commit 643e9f9fcbcd1cfb8f42af0ec8d5ab70a612bbb1 Author: wehub-resource-sync Date: Mon Jul 13 13:01:52 2026 +0800 chore: import upstream snapshot with attribution diff --git a/.agents/skills/translation-diff-export/SKILL.md b/.agents/skills/translation-diff-export/SKILL.md new file mode 100644 index 0000000..6268cff --- /dev/null +++ b/.agents/skills/translation-diff-export/SKILL.md @@ -0,0 +1,98 @@ +--- +name: translation-diff-export +description: Compares UniGetUI JSON locale files against English, identifies untranslated or source-changed keys, and generates patch, reference, and handoff files for a target language. Use when the user asks to export missing translations, untranslated strings, i18n diffs, or locale-file changes. +--- + +# translation diff export + +Use this skill when you need a small UniGetUI translation patch instead of sending a full language JSON file for review or translation. + +It exports only the active untranslated or source-changed strings, creates the translator handoff files, and prepares the patch set needed by `translation-diff-translate` and `translation-diff-import`. + +## Prerequisites + +- PowerShell 7 (`pwsh`). +- `git` available on `PATH`. +- `cirup` available on `PATH`. + +When source strings changed, run `translation-source-sync` first so `lang_en.json` reflects current source usage before exporting downstream translation patches. + +## Scripts + +- `scripts/export-translation-diff.ps1`: Exports JSON patch artifacts and generates a translation handoff prompt. +- `scripts/test-translation-diff.ps1`: Runs a local end-to-end smoke test against the checked-in UniGetUI language files. + +Use this skill's wrapper scripts first; the downstream translate and import steps are documented in [translation-diff-translate](../translation-diff-translate/SKILL.md) and [translation-diff-import](../translation-diff-import/SKILL.md). + +## Usage + +Export untranslated French strings only: + +```powershell +pwsh ./.agents/skills/translation-diff-export/scripts/export-translation-diff.ps1 \ + -NeutralJson ./src/Languages/lang_en.json \ + -TargetJson ./src/Languages/lang_fr.json \ + -Language fr +``` + +Export untranslated French strings plus English source values changed since `origin/main`: + +```powershell +pwsh ./.agents/skills/translation-diff-export/scripts/export-translation-diff.ps1 \ + -NeutralJson ./src/Languages/lang_en.json \ + -TargetJson ./src/Languages/lang_fr.json \ + -Language fr \ + -BaseRef origin/main +``` + +Optional parameters: + +- `-OutputDir` (default: `generated/translation-diff-export`) +- `-KeepIntermediate` + +Run the built-in smoke test: + +```powershell +pwsh ./.agents/skills/translation-diff-export/scripts/test-translation-diff.ps1 +``` + +## Output + +For `lang_en.json` and language `fr`, the script generates: + +- `generated/translation-diff-export/lang.diff.fr.source.json` +- `generated/translation-diff-export/lang.diff.fr.translated.json` +- `generated/translation-diff-export/lang.diff.fr.reference.json` +- `generated/translation-diff-export/lang.diff.fr.prompt.md` + +If `-KeepIntermediate` is used, git-baseline snapshots are kept under `generated/translation-diff-export/tmp/`. + +The smoke test writes its temporary artifacts under `generated/translation-diff-export-demo/`. + +## Validate The Export + +After export, confirm the patch is usable before handing it off: + +1. Check that `.source.json` is not empty unless you expected no work for that language. +2. Confirm `.translated.json` is sparse and does not contain copied English placeholders for unfinished keys. +3. If the patch should include recent English changes, rerun with `-BaseRef` and compare the resulting `.source.json`. +4. Run the smoke test if you changed the export workflow itself. + +## Hand Off To Translate + +After exporting the patch, use the generated `.prompt.md` file with [translation-diff-translate](../translation-diff-translate/SKILL.md) to update the sparse translated working copy. + +## Hand Off To Import + +After translating the patch, merge it back into the full language file with [translation-diff-import](../translation-diff-import/SKILL.md): + +```powershell +pwsh ./.agents/skills/translation-diff-import/scripts/import-translation-diff.ps1 \ + -TranslatedPatch ./generated/translation-diff-export/lang.diff.fr.translated.json \ + -SourcePatch ./generated/translation-diff-export/lang.diff.fr.source.json \ + -TargetJson ./src/Languages/lang_fr.json \ + -NeutralJson ./src/Languages/lang_en.json \ + -OutputJson ./src/Languages/lang_fr.merged.json +``` + +Keep the `.translated.json` file sparse. If a key is not translated yet, leave it out instead of copying the English source value into the working copy. \ No newline at end of file diff --git a/.agents/skills/translation-diff-export/scripts/TranslationDiff.JsonTools.ps1 b/.agents/skills/translation-diff-export/scripts/TranslationDiff.JsonTools.ps1 new file mode 100644 index 0000000..00f9d0f --- /dev/null +++ b/.agents/skills/translation-diff-export/scripts/TranslationDiff.JsonTools.ps1 @@ -0,0 +1,3 @@ +Set-StrictMode -Version Latest + +. (Join-Path $PSScriptRoot '..\..\..\..\scripts\translation\Languages\TranslationJsonTools.ps1') diff --git a/.agents/skills/translation-diff-export/scripts/export-translation-diff.ps1 b/.agents/skills/translation-diff-export/scripts/export-translation-diff.ps1 new file mode 100644 index 0000000..5f1134c --- /dev/null +++ b/.agents/skills/translation-diff-export/scripts/export-translation-diff.ps1 @@ -0,0 +1,508 @@ +param( + [Parameter(Mandatory = $true)] + [string]$NeutralJson, + + [Parameter(Mandatory = $true)] + [string]$TargetJson, + + [Parameter(Mandatory = $true)] + [string]$Language, + + [string]$BaseRef, + + [string]$OutputDir = 'generated/translation-diff-export', + + [switch]$ActiveOnly, + + [switch]$KeepIntermediate +) + +Set-StrictMode -Version Latest +$ErrorActionPreference = 'Stop' + +. (Join-Path $PSScriptRoot 'TranslationDiff.JsonTools.ps1') + +function Get-GitJsonMap { + param( + [Parameter(Mandatory = $true)] + [string]$RepositoryRoot, + + [Parameter(Mandatory = $true)] + [string]$BaseRef, + + [Parameter(Mandatory = $true)] + [string]$RepoRelativePath + ) + + $gitSpec = '{0}:{1}' -f $BaseRef, $RepoRelativePath + $rawContent = & git -C $RepositoryRoot show $gitSpec 2>$null + if ($LASTEXITCODE -ne 0) { + return $null + } + + $jsonText = [string]::Join([Environment]::NewLine, @($rawContent)) + if ([string]::IsNullOrWhiteSpace($jsonText)) { + return $null + } + + $tempPath = Join-Path $env:TEMP ('translation-diff-{0}.json' -f [System.Guid]::NewGuid().ToString('N')) + try { + New-Utf8File -Path $tempPath -Content $jsonText + return Read-OrderedJsonMap -Path $tempPath + } + finally { + Remove-Item -Path $tempPath -Force -ErrorAction SilentlyContinue + } +} + +function Get-CirupKeySet { + param( + [Parameter(Mandatory = $true)] + [string[]]$Arguments + ) + + $rows = Invoke-CirupJson -Arguments $Arguments + $keys = New-Object System.Collections.Generic.HashSet[string] ([System.StringComparer]::Ordinal) + foreach ($row in $rows) { + if (-not ($row -is [System.Collections.IDictionary]) -or -not $row.Contains('name')) { + throw 'cirup returned an unexpected JSON payload.' + } + + [void]$keys.Add([string]$row['name']) + } + + return $keys +} + +function Get-EmptyTargetKeys { + param( + [Parameter(Mandatory = $true)] + [System.Collections.IDictionary]$SourceMap, + + [Parameter(Mandatory = $true)] + [System.Collections.IDictionary]$TargetMap + ) + + $keys = New-Object System.Collections.Generic.HashSet[string] ([System.StringComparer]::Ordinal) + foreach ($entry in $SourceMap.GetEnumerator()) { + $key = [string]$entry.Key + if (-not $TargetMap.Contains($key)) { + continue + } + + if ([string]::IsNullOrWhiteSpace([string]$TargetMap[$key])) { + [void]$keys.Add($key) + } + } + + return $keys +} + +function Test-IntentionalSourceEqualValue { + param( + [Parameter(Mandatory = $true)] + [string]$LanguageCode, + + [Parameter(Mandatory = $true)] + [AllowEmptyString()] + [string]$SourceValue, + + [Parameter(Mandatory = $false)] + [AllowEmptyString()] + [string]$TargetValue = '' + ) + + if ($SourceValue -in @( + 'OK', + 'UniGetUI', + 'UniGetUI - {0} {1}' + )) { + return $true + } + + if ($LanguageCode -ceq 'it' -and $SourceValue -ceq 'No' -and $TargetValue -ceq 'No') { + return $true + } + + if ($LanguageCode -ceq 'ca' -and $SourceValue -ceq $TargetValue -and $SourceValue -in @( + '1 - Errors', + 'Error', + 'Global', + 'Local', + 'Manifest', + 'Manifests', + 'No', + 'Notes:', + 'Text' + )) { + return $true + } + + if ($LanguageCode -ceq 'pt_PT' -and $SourceValue -ceq $TargetValue -and $SourceValue -in @( + 'Global', + 'Local' + )) { + return $true + } + + if ($LanguageCode -ceq 'hr' -and $SourceValue -ceq $TargetValue -and $SourceValue -in @( + 'Manifest', + 'Status', + 'URL' + )) { + return $true + } + + if ($LanguageCode -ceq 'es' -and $SourceValue -ceq $TargetValue -and $SourceValue -in @( + 'Error', + 'Global', + 'Local', + 'No', + 'URL' + )) { + return $true + } + + if ($LanguageCode -ceq 'fr' -and $SourceValue -ceq $TargetValue -and $SourceValue -in @( + 'Ascendant', + 'Descendant', + 'Global', + 'Local', + 'Portable', + 'Source', + 'Sources', + 'Verbose', + 'Version', + 'installation', + 'option', + 'version {0}', + '{0} minutes' + )) { + return $true + } + + if ($LanguageCode -ceq 'nl' -and $SourceValue -ceq $TargetValue -and $SourceValue -in @( + '1 week', + 'Filters', + 'Manifest', + 'Status', + 'Updates', + 'URL', + 'update', + 'website', + '{0} status' + )) { + return $true + } + + if ($LanguageCode -ceq 'sk' -and $SourceValue -ceq $TargetValue -and $SourceValue -in @( + 'Manifest', + 'Text' + )) { + return $true + } + + if ($LanguageCode -ceq 'de' -and $SourceValue -ceq $TargetValue -and $SourceValue -in @( + 'Global', + 'Manifest', + 'Name', + 'Repository', + 'Start', + 'Status', + 'Text', + 'Updates', + 'URL', + 'Verbose', + 'Version', + 'Version:', + 'optional', + '{package} Installation', + '{package} Update' + )) { + return $true + } + + if ($LanguageCode -ceq 'sv' -and $SourceValue -ceq $TargetValue -and $SourceValue -in @( + 'Global', + 'Manifest', + 'Start', + 'Status', + 'Text', + 'Version', + 'Version:', + 'installation', + 'version {0}', + '{0} installation', + '{0} status', + '{pm} version:' + )) { + return $true + } + + if ($LanguageCode -ceq 'id' -and $SourceValue -ceq $TargetValue -and $SourceValue -in @( + 'Global', + 'Grid', + 'Manifest', + 'Status', + 'URL', + 'Verbose', + '{0} status' + )) { + return $true + } + + if ($LanguageCode -ceq 'fil' -and $SourceValue -ceq $TargetValue -and $SourceValue -in @( + 'Android Subsystem', + 'Default', + 'Error', + 'Global', + 'Grid', + 'Machine | Global', + 'Manifest', + 'OK', + 'Ok', + 'Package', + 'Password', + 'Portable', + 'Portable mode', + 'PreRelease', + 'Repository', + 'Source', + 'Source:', + 'Telemetry', + 'Text', + 'URL', + 'UniGetUI', + 'UniGetUI - {0} {1}', + 'User', + 'Username', + 'Verbose', + 'website', + 'library' + )) { + return $true + } + + return $false +} + +. ([System.IO.Path]::GetFullPath((Join-Path $PSScriptRoot '..\..\..\..\scripts\translation\Languages\IntentionalSourceEqualValues.ps1'))) + +function Sync-TranslatedWorkingCopy { + param( + [Parameter(Mandatory = $true)] + [string]$LanguageCode, + + [Parameter(Mandatory = $true)] + [System.Collections.IDictionary]$CurrentSourceMap, + + [Parameter(Mandatory = $true)] + [string]$TranslatedPatchPath, + + [System.Collections.IDictionary]$PreviousSourceMap + ) + + $translatedMap = Read-OrderedJsonMap -Path $TranslatedPatchPath + $syncedMap = New-OrderedStringMap + + foreach ($entry in $CurrentSourceMap.GetEnumerator()) { + $key = [string]$entry.Key + $sourceValue = [string]$entry.Value + if (-not $translatedMap.Contains($key)) { + continue + } + + $translatedValue = [string]$translatedMap[$key] + if ([string]::IsNullOrWhiteSpace($translatedValue)) { + continue + } + + if ($translatedValue -ceq $sourceValue) { + if (-not (Test-IntentionalSourceEqualValue -LanguageCode $LanguageCode -SourceValue $sourceValue -TargetValue $translatedValue)) { + continue + } + } + + if ($null -ne $PreviousSourceMap -and $PreviousSourceMap.Contains($key)) { + if ($translatedValue -ceq [string]$PreviousSourceMap[$key]) { + continue + } + } + + $syncedMap[$key] = $translatedValue + } + + Write-OrderedJsonMap -Path $TranslatedPatchPath -Map $syncedMap +} + +function Get-FilteredPatchMap { + param( + [Parameter(Mandatory = $true)] + [System.Collections.IDictionary]$Map, + + [Parameter(Mandatory = $true)] + [System.Collections.IDictionary]$NeutralMap, + + [Parameter(Mandatory = $true)] + [switch]$ActiveOnly + ) + + if (-not $ActiveOnly.IsPresent) { + return $Map + } + + $activeKeys = Split-TranslationMapAtBoundary -Map $NeutralMap + $filteredMap = New-OrderedStringMap + foreach ($entry in $activeKeys.ActiveMap.GetEnumerator()) { + $key = [string]$entry.Key + if ($Map.Contains($key)) { + $filteredMap[$key] = [string]$Map[$key] + } + } + + return $filteredMap +} + +Assert-Command -Name 'git' +Assert-Command -Name 'cirup' + +$neutralPath = Get-FullPath -Path $NeutralJson +$targetPath = Get-FullPath -Path $TargetJson +if (-not (Test-Path -Path $neutralPath -PathType Leaf)) { + throw "Neutral JSON file not found: $neutralPath" +} + +$languageCode = $Language.Trim() +if ([string]::IsNullOrWhiteSpace($languageCode)) { + throw 'Language must not be empty.' +} + +$languagesReferencePath = Get-LanguagesReferencePath -NeutralJsonPath $neutralPath +Assert-LanguageCodeKnown -LanguagesReferencePath $languagesReferencePath -LanguageCode $languageCode + +$outputRoot = Get-FullPath -Path $OutputDir +$tmpRoot = Join-Path $outputRoot 'tmp' +New-Item -Path $outputRoot -ItemType Directory -Force | Out-Null +New-Item -Path $tmpRoot -ItemType Directory -Force | Out-Null + +$cirupTargetPath = $targetPath +if (-not (Test-Path -Path $targetPath -PathType Leaf)) { + $cirupTargetPath = Join-Path $tmpRoot 'target.empty.json' + Write-OrderedJsonMap -Path $cirupTargetPath -Map (New-OrderedStringMap) +} + +$baseName = Get-PatchBaseName -NeutralJsonPath $neutralPath +$sourcePatchPath = Join-Path $outputRoot ('{0}.diff.{1}.source.json' -f $baseName, $languageCode) +$translatedPatchPath = Join-Path $outputRoot ('{0}.diff.{1}.translated.json' -f $baseName, $languageCode) +$referencePatchPath = Join-Path $outputRoot ('{0}.diff.{1}.reference.json' -f $baseName, $languageCode) +$promptPath = Join-Path $outputRoot ('{0}.diff.{1}.prompt.md' -f $baseName, $languageCode) + +$neutralMap = Read-OrderedJsonMap -Path $neutralPath +$targetMap = Read-OrderedJsonMap -Path $targetPath +$baseSummary = 'No git baseline was provided. The patch contains untranslated UniGetUI entries only.' +$changedSourceKeys = New-Object System.Collections.Generic.HashSet[string] ([System.StringComparer]::Ordinal) +$missingTargetKeys = Get-CirupKeySet -Arguments @('file-diff', $neutralPath, $cirupTargetPath) +$rawEqualEnglishKeys = Get-CirupKeySet -Arguments @('file-intersect', $neutralPath, $cirupTargetPath) +$equalEnglishKeys = New-Object System.Collections.Generic.HashSet[string] ([System.StringComparer]::Ordinal) +$rawEqualEnglishKeys | ForEach-Object { + $key = [string]$_ + if (-not (Test-IntentionalSourceEqualValue -LanguageCode $Language -SourceValue ([string]$neutralMap[$key]) -TargetValue ([string]$targetMap[$key]))) { + [void]$equalEnglishKeys.Add($key) + } +} +$emptyTargetKeys = Get-EmptyTargetKeys -SourceMap $neutralMap -TargetMap $targetMap + +if (-not [string]::IsNullOrWhiteSpace($BaseRef)) { + $repoRoot = Get-RepositoryRoot -WorkingDirectory (Split-Path -Path $neutralPath -Parent) + $repoRelativeNeutralPath = Get-RepoRelativePath -RepositoryRoot $repoRoot -FilePath $neutralPath + $baseSourceMap = Get-GitJsonMap -RepositoryRoot $repoRoot -BaseRef $BaseRef -RepoRelativePath $repoRelativeNeutralPath + $safeBaseRef = Get-SafeLabel -Value $BaseRef + $baseSnapshotPath = Join-Path $tmpRoot ('{0}.baseline.{1}.json' -f $baseName, $safeBaseRef) + + if ($null -ne $baseSourceMap) { + Write-OrderedJsonMap -Path $baseSnapshotPath -Map $baseSourceMap + $baseSummary = "Git baseline '$BaseRef' was used to include keys that are new or whose English value changed since that revision." + } + else { + Write-OrderedJsonMap -Path $baseSnapshotPath -Map (New-OrderedStringMap) + $baseSummary = "Git baseline '$BaseRef' did not contain the neutral JSON file, so all current English entries were treated as new for the changed-source delta." + } + + $changedSourceKeys = Get-CirupKeySet -Arguments @('diff-with-base', $baseSnapshotPath, $neutralPath, $neutralPath) +} + +$sourcePatchMap = New-OrderedStringMap +$referencePatchMap = New-OrderedStringMap + +$keysToTranslate = New-Object System.Collections.Generic.HashSet[string] ([System.StringComparer]::Ordinal) +foreach ($key in $missingTargetKeys) { + [void]$keysToTranslate.Add([string]$key) +} + +foreach ($key in $equalEnglishKeys) { + [void]$keysToTranslate.Add([string]$key) +} + +foreach ($key in $emptyTargetKeys) { + [void]$keysToTranslate.Add([string]$key) +} + +foreach ($key in $changedSourceKeys) { + [void]$keysToTranslate.Add([string]$key) +} + +foreach ($entry in $neutralMap.GetEnumerator()) { + $key = [string]$entry.Key + $sourceValue = [string]$entry.Value + + if ($keysToTranslate.Contains($key)) { + $sourcePatchMap[$key] = $sourceValue + continue + } + + if ($targetMap.Contains($key)) { + $targetValue = [string]$targetMap[$key] + if (-not [string]::IsNullOrWhiteSpace($targetValue) -and $targetValue -cne $sourceValue) { + $referencePatchMap[$key] = $targetValue + } + } +} + +$sourcePatchMap = Get-FilteredPatchMap -Map $sourcePatchMap -NeutralMap $neutralMap -ActiveOnly:$ActiveOnly +$referencePatchMap = Get-FilteredPatchMap -Map $referencePatchMap -NeutralMap $neutralMap -ActiveOnly:$ActiveOnly + +if (Test-Path -Path $sourcePatchPath -PathType Leaf) { + $previousSourceMap = Read-OrderedJsonMap -Path $sourcePatchPath +} +else { + $previousSourceMap = $null +} + +Write-OrderedJsonMap -Path $sourcePatchPath -Map $sourcePatchMap +Write-OrderedJsonMap -Path $referencePatchPath -Map $referencePatchMap +Sync-TranslatedWorkingCopy -LanguageCode $languageCode -CurrentSourceMap $sourcePatchMap -TranslatedPatchPath $translatedPatchPath -PreviousSourceMap $previousSourceMap + +$mergedTargetPath = Join-Path ([System.IO.Path]::GetDirectoryName($targetPath)) ('{0}.merged.json' -f [System.IO.Path]::GetFileNameWithoutExtension($targetPath)) +$skillsRoot = [System.IO.Path]::GetFullPath((Join-Path $PSScriptRoot '..\..')) +$translateHandoffScript = Join-Path $skillsRoot 'translation-diff-translate\scripts\write-translation-handoff.ps1' +$validationScript = Join-Path $skillsRoot 'translation-diff-import\scripts\validate-language-file.ps1' +if (-not (Test-Path -Path $translateHandoffScript -PathType Leaf)) { + throw "Translation handoff script not found: $translateHandoffScript" +} + +& $translateHandoffScript -BaseName $baseName -Language $languageCode -SourcePatch $sourcePatchPath -TranslatedPatch $translatedPatchPath -ReferencePatch $referencePatchPath -TargetJson $targetPath -NeutralJson $neutralPath -MergedTargetJson $mergedTargetPath -ValidationScript $validationScript -OutputPrompt $promptPath -BaseSummary $baseSummary + +if (-not $KeepIntermediate.IsPresent) { + Remove-Item -Path $tmpRoot -Recurse -Force -ErrorAction SilentlyContinue +} + +Write-Output "Created source patch: $sourcePatchPath" +Write-Output "Refreshed translated working copy: $translatedPatchPath" +Write-Output "Created reference patch: $referencePatchPath" +Write-Output "Created translation handoff prompt: $promptPath" +if ($ActiveOnly.IsPresent) { + Write-Output 'Patch scope: active translation keys only' +} +if ($KeepIntermediate.IsPresent) { + Write-Output "Kept intermediate files under: $tmpRoot" +} diff --git a/.agents/skills/translation-diff-export/scripts/test-translation-diff.ps1 b/.agents/skills/translation-diff-export/scripts/test-translation-diff.ps1 new file mode 100644 index 0000000..8d7dfdb --- /dev/null +++ b/.agents/skills/translation-diff-export/scripts/test-translation-diff.ps1 @@ -0,0 +1,44 @@ +param( + [string]$Language = 'fr', + + [string]$OutputRoot = 'generated/translation-diff-export-demo' +) + +Set-StrictMode -Version Latest +$ErrorActionPreference = 'Stop' + +. (Join-Path $PSScriptRoot 'TranslationDiff.JsonTools.ps1') + +$repoRoot = [System.IO.Path]::GetFullPath((Join-Path $PSScriptRoot '..\..\..\..')) +$neutralPath = Join-Path $repoRoot 'src\Languages\lang_en.json' +$targetPath = Join-Path $repoRoot ('src\Languages\lang_{0}.json' -f $Language) +$exportScript = Join-Path $PSScriptRoot 'export-translation-diff.ps1' +$importScript = Join-Path $repoRoot '.agents\skills\translation-diff-import\scripts\import-translation-diff.ps1' +$validateScript = Join-Path $repoRoot '.agents\skills\translation-diff-import\scripts\validate-language-file.ps1' + +if (-not (Test-Path -Path $neutralPath -PathType Leaf)) { + throw "Neutral language file not found: $neutralPath" +} + +& $exportScript -NeutralJson $neutralPath -TargetJson $targetPath -Language $Language -OutputDir $OutputRoot + +$baseName = Get-PatchBaseName -NeutralJsonPath $neutralPath +$sourcePatchPath = Join-Path (Get-FullPath -Path $OutputRoot) ('{0}.diff.{1}.source.json' -f $baseName, $Language) +$translatedPatchPath = Join-Path (Get-FullPath -Path $OutputRoot) ('{0}.diff.{1}.translated.json' -f $baseName, $Language) +$mergedTargetPath = Join-Path (Get-FullPath -Path $OutputRoot) ('lang_{0}.merged.smoke.json' -f $Language) + +$sourcePatchMap = Read-OrderedJsonMap -Path $sourcePatchPath +if ($sourcePatchMap.Count -eq 0) { + throw 'Smoke test patch is empty. Pick a target language with untranslated entries to exercise the workflow.' +} + +$translatedPatchMap = New-OrderedStringMap +$firstEntry = $sourcePatchMap.GetEnumerator() | Select-Object -First 1 +$translatedPatchMap[[string]$firstEntry.Key] = '[smoke {0}] {1}' -f $Language, [string]$firstEntry.Value +Write-OrderedJsonMap -Path $translatedPatchPath -Map $translatedPatchMap + +& $importScript -TranslatedPatch $translatedPatchPath -SourcePatch $sourcePatchPath -TargetJson $targetPath -NeutralJson $neutralPath -OutputJson $mergedTargetPath + +& $validateScript -NeutralJson $neutralPath -TargetJson $mergedTargetPath -PatchJson $sourcePatchPath + +Write-Output "Smoke test completed successfully. Merged output: $mergedTargetPath" \ No newline at end of file diff --git a/.agents/skills/translation-diff-import/SKILL.md b/.agents/skills/translation-diff-import/SKILL.md new file mode 100644 index 0000000..9aee2a8 --- /dev/null +++ b/.agents/skills/translation-diff-import/SKILL.md @@ -0,0 +1,64 @@ +--- +name: translation-diff-import +description: Merges translated key-value pairs from a UniGetUI JSON localization patch back into the full language file and validates the merged result. Use when the user asks to apply, merge, or import a translation patch. +--- + +# translation diff import + +Use this skill after the export skill produced a `.source.json`, `.translated.json`, and `.reference.json` set and you want to merge the translated working copy back into the full target-language JSON file. + +See [translation-diff-export](../translation-diff-export/SKILL.md) for the patch-generation step that produces the expected inputs. + +## Prerequisites + +- PowerShell 7 (`pwsh`). +- `cirup` available on `PATH`. + +## Scripts + +- `scripts/import-translation-diff.ps1`: Validates and merges a translated patch into the full language file. +- `scripts/validate-language-file.ps1`: Validates placeholder, token, HTML-fragment, and newline parity for either a full language file or just the active patch keys against `lang_en.json`. + +## Usage + +Import the translated French working copy from the export skill into the full French JSON file: + +```powershell +pwsh ./.agents/skills/translation-diff-import/scripts/import-translation-diff.ps1 \ + -TranslatedPatch ./generated/translation-diff-export/lang.diff.fr.translated.json \ + -SourcePatch ./generated/translation-diff-export/lang.diff.fr.source.json \ + -TargetJson ./src/Languages/lang_fr.json \ + -NeutralJson ./src/Languages/lang_en.json \ + -OutputJson ./src/Languages/lang_fr.merged.json +``` + +Validate the merged output: + +```powershell +pwsh ./.agents/skills/translation-diff-import/scripts/validate-language-file.ps1 \ + -NeutralJson ./src/Languages/lang_en.json \ + -TargetJson ./src/Languages/lang_fr.merged.json \ + -PatchJson ./generated/translation-diff-export/lang.diff.fr.source.json +``` + +Optional parameters: + +- `-OutputDir` (default: `generated/translation-diff-import`) +- `-AllowUnchangedValues` +- `-KeepIntermediate` + +Recommended input mapping from the export skill: + +- `-TranslatedPatch`: `generated/translation-diff-export/lang.diff.fr.translated.json` +- `-SourcePatch`: `generated/translation-diff-export/lang.diff.fr.source.json` + +## Output + +- A merged `.json` file that contains both the previously translated entries and the imported patch values. +- If `-KeepIntermediate` is used, patch snapshots are preserved under `generated/translation-diff-import/tmp/`. + +## Edge cases + +- If the target JSON file does not exist yet, the script can create an output from the translated patch alone. +- When `-SourcePatch` is provided, the script validates translated keys, placeholder tokens, HTML-like fragments, newline counts, and likely untranslated values before delegating the merge to `cirup` while allowing missing keys for partial progress. +- The import skill expects `.translated.json` to remain sparse. Untranslated keys should be omitted instead of copied in English unless you intentionally bypass that check with `-AllowUnchangedValues`. diff --git a/.agents/skills/translation-diff-import/scripts/import-translation-diff.ps1 b/.agents/skills/translation-diff-import/scripts/import-translation-diff.ps1 new file mode 100644 index 0000000..7a10994 --- /dev/null +++ b/.agents/skills/translation-diff-import/scripts/import-translation-diff.ps1 @@ -0,0 +1,168 @@ +param( + [Parameter(Mandatory = $true)] + [string]$TranslatedPatch, + + [string]$SourcePatch, + + [Parameter(Mandatory = $true)] + [string]$TargetJson, + + [string]$NeutralJson, + + [string]$OutputJson, + + [string]$OutputDir = 'generated/translation-diff-import', + + [switch]$AllowUnchangedValues, + + [switch]$KeepIntermediate +) + +Set-StrictMode -Version Latest +$ErrorActionPreference = 'Stop' + +. (Join-Path $PSScriptRoot '..\..\translation-diff-export\scripts\TranslationDiff.JsonTools.ps1') +. ([System.IO.Path]::GetFullPath((Join-Path $PSScriptRoot '..\..\..\..\scripts\translation\Languages\IntentionalSourceEqualValues.ps1'))) + +function Assert-PatchCompatibility { + param( + [Parameter(Mandatory = $true)] + [System.Collections.IDictionary]$SourceMap, + + [Parameter(Mandatory = $true)] + [System.Collections.IDictionary]$TranslatedMap, + + [Parameter(Mandatory = $true)] + [string]$LanguageCode, + + [Parameter(Mandatory = $true)] + [bool]$AllowUnchanged + ) + + foreach ($entry in $TranslatedMap.GetEnumerator()) { + $key = [string]$entry.Key + $translatedValue = [string]$entry.Value + if (-not $SourceMap.Contains($key)) { + throw "Translated patch contains unexpected key '$key'." + } + + if ([string]::IsNullOrWhiteSpace($translatedValue)) { + throw "Translated patch contains an empty value for key '$key'." + } + + $sourceValue = [string]$SourceMap[$key] + Assert-TranslationStructure -SourceValue $sourceValue -TranslatedValue $translatedValue -Key $key + + if (-not $AllowUnchanged -and $translatedValue -ceq $sourceValue -and -not (Test-IntentionalSourceEqualValue -LanguageCode $LanguageCode -SourceValue $sourceValue -TargetValue $translatedValue)) { + throw "Translated patch still contains the English source value for key '$key'. Use -AllowUnchangedValues only when that is intentional." + } + } +} + +function Merge-LanguageMaps { + param( + [Parameter(Mandatory = $true)] + [System.Collections.IDictionary]$NeutralMap, + + [Parameter(Mandatory = $true)] + [System.Collections.IDictionary]$TargetMap, + + [Parameter(Mandatory = $true)] + [System.Collections.IDictionary]$TranslatedPatchMap + ) + + $mergedMap = New-OrderedStringMap + + foreach ($entry in $NeutralMap.GetEnumerator()) { + $key = [string]$entry.Key + if ($TranslatedPatchMap.Contains($key)) { + $mergedMap[$key] = [string]$TranslatedPatchMap[$key] + continue + } + + if ($TargetMap.Contains($key)) { + $mergedMap[$key] = [string]$TargetMap[$key] + } + } + + foreach ($entry in $TargetMap.GetEnumerator()) { + $key = [string]$entry.Key + if (-not $NeutralMap.Contains($key) -and -not $mergedMap.Contains($key)) { + $mergedMap[$key] = [string]$entry.Value + } + } + + return $mergedMap +} + +$translatedPatchPath = Get-FullPath -Path $TranslatedPatch +if (-not (Test-Path -Path $translatedPatchPath -PathType Leaf)) { + throw "Translated patch file not found: $translatedPatchPath" +} + +$targetPath = Get-FullPath -Path $TargetJson +$targetMap = Read-OrderedJsonMap -Path $targetPath +$translatedPatchMap = Read-OrderedJsonMap -Path $translatedPatchPath +$targetBaseName = [System.IO.Path]::GetFileNameWithoutExtension($targetPath) +$languageCode = if ($targetBaseName.StartsWith('lang_', [System.StringComparison]::Ordinal)) { + $targetBaseName.Substring(5) +} +else { + '' +} + +if ([string]::IsNullOrWhiteSpace($NeutralJson)) { + $NeutralJson = Join-Path (Split-Path -Path $targetPath -Parent) 'lang_en.json' +} + +$neutralPath = Get-FullPath -Path $NeutralJson +if (-not (Test-Path -Path $neutralPath -PathType Leaf)) { + throw "Neutral JSON file not found: $neutralPath" +} + +$neutralMap = Read-OrderedJsonMap -Path $neutralPath +$sourceMap = $null +if (-not [string]::IsNullOrWhiteSpace($SourcePatch)) { + $sourcePatchPath = Get-FullPath -Path $SourcePatch + if (-not (Test-Path -Path $sourcePatchPath -PathType Leaf)) { + throw "Source patch file not found: $sourcePatchPath" + } + + $sourceMap = Read-OrderedJsonMap -Path $sourcePatchPath + Assert-PatchCompatibility -SourceMap $sourceMap -TranslatedMap $translatedPatchMap -LanguageCode $languageCode -AllowUnchanged:$AllowUnchangedValues.IsPresent +} + +foreach ($entry in $translatedPatchMap.GetEnumerator()) { + $key = [string]$entry.Key + if (-not $neutralMap.Contains($key)) { + throw "Translated patch key '$key' does not exist in the neutral language file." + } +} + +$outputRoot = Get-FullPath -Path $OutputDir +$tmpRoot = Join-Path $outputRoot 'tmp' +New-Item -Path $outputRoot -ItemType Directory -Force | Out-Null +New-Item -Path $tmpRoot -ItemType Directory -Force | Out-Null + +if ([string]::IsNullOrWhiteSpace($OutputJson)) { + if (Test-Path -Path $targetPath -PathType Leaf) { + $targetName = [System.IO.Path]::GetFileNameWithoutExtension($targetPath) + $OutputJson = Join-Path (Split-Path -Path $targetPath -Parent) ('{0}.merged.json' -f $targetName) + } + else { + $OutputJson = $targetPath + } +} + +$outputJsonPath = Get-FullPath -Path $OutputJson +$mergedMap = Merge-LanguageMaps -NeutralMap $neutralMap -TargetMap $targetMap -TranslatedPatchMap $translatedPatchMap +Write-OrderedJsonMap -Path $outputJsonPath -Map $mergedMap + +if (-not $KeepIntermediate.IsPresent) { + Remove-Item -Path $tmpRoot -Recurse -Force -ErrorAction SilentlyContinue +} + +Write-Output "Merged translated patch into: $outputJsonPath" +if ($null -ne $sourceMap) { + Write-Output "Validated translated patch against: $SourcePatch" +} diff --git a/.agents/skills/translation-diff-import/scripts/validate-language-file.ps1 b/.agents/skills/translation-diff-import/scripts/validate-language-file.ps1 new file mode 100644 index 0000000..37f2993 --- /dev/null +++ b/.agents/skills/translation-diff-import/scripts/validate-language-file.ps1 @@ -0,0 +1,63 @@ +param( + [Parameter(Mandatory = $true)] + [string]$NeutralJson, + + [Parameter(Mandatory = $true)] + [string]$TargetJson, + + [string]$PatchJson +) + +Set-StrictMode -Version Latest +$ErrorActionPreference = 'Stop' + +. (Join-Path $PSScriptRoot '..\..\translation-diff-export\scripts\TranslationDiff.JsonTools.ps1') + +$neutralPath = Get-FullPath -Path $NeutralJson +$targetPath = Get-FullPath -Path $TargetJson + +if (-not (Test-Path -Path $neutralPath -PathType Leaf)) { + throw "Neutral JSON file not found: $neutralPath" +} + +if (-not (Test-Path -Path $targetPath -PathType Leaf)) { + throw "Target JSON file not found: $targetPath" +} + +$neutralMap = Read-OrderedJsonMap -Path $neutralPath +$targetMap = Read-OrderedJsonMap -Path $targetPath + +$keysToValidate = New-Object System.Collections.Generic.List[string] +if (-not [string]::IsNullOrWhiteSpace($PatchJson)) { + $patchPath = Get-FullPath -Path $PatchJson + if (-not (Test-Path -Path $patchPath -PathType Leaf)) { + throw "Patch JSON file not found: $patchPath" + } + + $patchMap = Read-OrderedJsonMap -Path $patchPath + foreach ($entry in $patchMap.GetEnumerator()) { + $keysToValidate.Add([string]$entry.Key) + } +} +else { + foreach ($entry in $targetMap.GetEnumerator()) { + $keysToValidate.Add([string]$entry.Key) + } +} + +$validatedCount = 0 +foreach ($key in $keysToValidate) { + if (-not $neutralMap.Contains($key)) { + throw "Target file contains key '$key' that does not exist in the neutral language file." + } + + if (-not $targetMap.Contains($key)) { + throw "Target file does not contain required key '$key'." + } + + $targetValue = [string]$targetMap[$key] + Assert-TranslationStructure -SourceValue ([string]$neutralMap[$key]) -TranslatedValue $targetValue -Key $key + $validatedCount += 1 +} + +Write-Output "Validated $validatedCount translated entries against: $neutralPath" \ No newline at end of file diff --git a/.agents/skills/translation-diff-translate/SKILL.md b/.agents/skills/translation-diff-translate/SKILL.md new file mode 100644 index 0000000..7dd7162 --- /dev/null +++ b/.agents/skills/translation-diff-translate/SKILL.md @@ -0,0 +1,69 @@ +--- +name: translation-diff-translate +description: Translates a sparse UniGetUI JSON language patch, writes completed entries into the working copy, preserves placeholders and terminology, and prepares the patch for merge-back. Use when the user asks to translate or localize i18n strings, localization JSON, or language-file patches. +--- + +# translation diff translate + +Use this skill after `translation-diff-export` produced a `.source.json`, `.translated.json`, and `.reference.json` set and you want to update the sparse translated working copy. + +It translates only the active patch keys, keeps `.translated.json` as the sole writable file, preserves placeholders and formatting, and hands the completed working copy to `translation-diff-import` for merge-back. + +## Execution Expectations + +1. Edit `.translated.json` directly. Do not create helper scripts, temporary reports, or coverage probes. +2. Do not install packages or search for external translation services unless the user explicitly asks for automation. +3. If `.translated.json` is empty, that is expected. Translate from `.source.json` into `.translated.json`. +4. Use `.reference.json` only as terminology guidance, not as a reason to pause and analyze the rest of the repository. +5. If the patch is too large to finish reasonably in one pass, report that constraint to the user instead of creating automation on your own. + +## Script + +- `scripts/write-translation-handoff.ps1`: Writes a small `.prompt.md` file that points an agent at this skill with the concrete patch paths created by the export skill. + +## Usage + +Generate a handoff prompt for a translated French working copy: + +```powershell +pwsh ./.agents/skills/translation-diff-translate/scripts/write-translation-handoff.ps1 \ + -BaseName lang \ + -Language fr \ + -SourcePatch ./generated/translation-diff-export/lang.diff.fr.source.json \ + -TranslatedPatch ./generated/translation-diff-export/lang.diff.fr.translated.json \ + -ReferencePatch ./generated/translation-diff-export/lang.diff.fr.reference.json \ + -TargetJson ./src/Languages/lang_fr.json \ + -NeutralJson ./src/Languages/lang_en.json \ + -MergedTargetJson ./src/Languages/lang_fr.merged.json \ + -ValidationScript ./.agents/skills/translation-diff-import/scripts/validate-language-file.ps1 \ + -OutputPrompt ./generated/translation-diff-export/lang.diff.fr.prompt.md +``` + +## Translation Rules + +1. Do not edit `.source.json`. +2. Write completed translations only into `.translated.json`. +3. If a key is not translated yet, omit it from `.translated.json` instead of copying the English source value. +4. Preserve key names exactly as-is. +5. Preserve placeholders, named tokens, HTML-like fragments, escape sequences, and line breaks. +6. Keep translated entries in the same key order as `.source.json` when adding new entries. +7. Use `.reference.json` to match existing terminology and tone in the destination language. +8. Do not introduce keys that are not present in the source patch. + +## After Translation + +Merge the sparse working copy back into the full destination-language file: + +```powershell +pwsh ./.agents/skills/translation-diff-import/scripts/import-translation-diff.ps1 \ + -TranslatedPatch ./generated/translation-diff-export/lang.diff.fr.translated.json \ + -SourcePatch ./generated/translation-diff-export/lang.diff.fr.source.json \ + -TargetJson ./src/Languages/lang_fr.json \ + -NeutralJson ./src/Languages/lang_en.json \ + -OutputJson ./src/Languages/lang_fr.merged.json + +pwsh ./.agents/skills/translation-diff-import/scripts/validate-language-file.ps1 \ + -NeutralJson ./src/Languages/lang_en.json \ + -TargetJson ./src/Languages/lang_fr.merged.json \ + -PatchJson ./generated/translation-diff-export/lang.diff.fr.source.json +``` \ No newline at end of file diff --git a/.agents/skills/translation-diff-translate/scripts/write-translation-handoff.ps1 b/.agents/skills/translation-diff-translate/scripts/write-translation-handoff.ps1 new file mode 100644 index 0000000..4888a9c --- /dev/null +++ b/.agents/skills/translation-diff-translate/scripts/write-translation-handoff.ps1 @@ -0,0 +1,113 @@ +param( + [Parameter(Mandatory = $true)] + [string]$BaseName, + + [Parameter(Mandatory = $true)] + [string]$Language, + + [Parameter(Mandatory = $true)] + [string]$SourcePatch, + + [Parameter(Mandatory = $true)] + [string]$TranslatedPatch, + + [Parameter(Mandatory = $true)] + [string]$ReferencePatch, + + [Parameter(Mandatory = $true)] + [string]$TargetJson, + + [Parameter(Mandatory = $true)] + [string]$NeutralJson, + + [Parameter(Mandatory = $true)] + [string]$MergedTargetJson, + + [Parameter(Mandatory = $true)] + [string]$ValidationScript, + + [Parameter(Mandatory = $true)] + [string]$OutputPrompt, + + [string]$BaseSummary = 'No git baseline was provided. The patch contains untranslated UniGetUI entries only.' +) + +Set-StrictMode -Version Latest +$ErrorActionPreference = 'Stop' + +function New-Utf8File { + param( + [Parameter(Mandatory = $true)] + [string]$Path, + + [Parameter(Mandatory = $true)] + [AllowEmptyString()] + [string]$Content + ) + + $directory = Split-Path -Path $Path -Parent + if (-not [string]::IsNullOrWhiteSpace($directory)) { + New-Item -Path $directory -ItemType Directory -Force | Out-Null + } + + $encoding = [System.Text.UTF8Encoding]::new($false) + [System.IO.File]::WriteAllText($Path, $Content, $encoding) +} + +$promptPath = [System.IO.Path]::GetFullPath($OutputPrompt) +$promptDirectory = Split-Path -Path $promptPath -Parent +if (-not [string]::IsNullOrWhiteSpace($promptDirectory)) { + New-Item -Path $promptDirectory -ItemType Directory -Force | Out-Null +} + +$promptContent = @" +# Translate $BaseName to $Language + +## Use Skill + +Use the translation-diff-translate skill for the translation step. + +Detailed workflow and validation rules live in: + +- ./.agents/skills/translation-diff-translate/SKILL.md + +## Context + +- Source patch file: $SourcePatch +- Translated working copy: $TranslatedPatch +- Reference translations: $ReferencePatch +- Full target language file: $TargetJson +- Neutral language file: $NeutralJson +- $BaseSummary + +## Translation Task + +1. Update only the translated working copy. +2. If the translated working copy is empty, translate directly from the source patch into it. +3. Keep the translated working copy sparse by omitting keys that are not translated yet. +4. Use the reference translations file for terminology, style, and consistency. +5. Preserve placeholders, named tokens, HTML-like fragments, escape sequences, and line breaks. +6. Do not edit the source patch file. +7. Do not write helper scripts, temporary reports, coverage checks, or automation for this task. +8. Do not search for external translation tools or install packages unless the user explicitly asks for automation. +9. Start translating immediately instead of analyzing repo-wide translation coverage. + +## Expected Action + +- Read the source patch and reference file. +- Edit the translated patch file directly. +- Add translated JSON entries in source order. +- Leave untranslated keys out. +- When finished, use the import and validation commands below. + +## Import After Translation + +~~~powershell +pwsh ./.agents/skills/translation-diff-import/scripts/import-translation-diff.ps1 -TranslatedPatch "$TranslatedPatch" -SourcePatch "$SourcePatch" -TargetJson "$TargetJson" -NeutralJson "$NeutralJson" -OutputJson "$MergedTargetJson" +pwsh "$ValidationScript" -NeutralJson "$NeutralJson" -TargetJson "$MergedTargetJson" -PatchJson "$SourcePatch" +~~~ + +The import skill validates the translated working copy against the source patch, merges it into the full target file in English key order, and the validation script checks placeholders, HTML-like fragments, and line-break parity. +"@ + +New-Utf8File -Path $promptPath -Content $promptContent.TrimStart() \ No newline at end of file diff --git a/.agents/skills/translation-review/SKILL.md b/.agents/skills/translation-review/SKILL.md new file mode 100644 index 0000000..66fda04 --- /dev/null +++ b/.agents/skills/translation-review/SKILL.md @@ -0,0 +1,117 @@ +--- +name: translation-review +description: Reviews UniGetUI .json language files for localization quality, detects parity issues, English-equal entries, wrong-script content, and cross-language outliers, then generates a dataset for LLM-assisted linguistic review. Use when the user asks to review translations, audit localization, inspect i18n or l10n quality, or validate language files. +--- + +# translation review + +Use this skill when you need a quality review of an existing UniGetUI translation, not just coverage, but correctness, language integrity, and consistency against related languages. + +Typical triggers: review translations, check translation quality, mistranslations, wrong language in translation, untranslated strings, localization QA, translation audit, spot-check a language file. + +## Scope + +- Mechanically detect placeholder, HTML-fragment, and newline mismatches. +- Flag entries whose translation still equals the English source in a non-English language file. +- Detect wrong-script entries for non-Latin languages such as `ua`, `zh_CN`, `ar`, `ko`, `ja`, and `he`. +- Build a cross-language comparison table so the reviewing agent can identify outliers, suspicious wording, and wrong-language content. +- The agent performs the final linguistic review using the generated report. + +## Prerequisites + +- PowerShell 7 (`pwsh`). + +## Scripts + +- `scripts/review-translation-json.ps1`: Generate the review dataset for one UniGetUI language JSON file. + +## Workflow + +1. Generate the review dataset for the target language. +2. Confirm the output file exists and contains the expected flagged sections or JSON fields. +3. If the script fails or the output is empty, validate the target JSON with `pwsh ./scripts/translation/Verify-Translations.ps1` and rerun the review. +4. Read the flagged sections first: parity issues, English-equal entries, and wrong-script entries. +5. Spot-check the cross-language comparison table, focusing on labels, buttons, settings text, and error messages. +6. Report findings inline with the English source text, observed problem, and suggested correction. + +## Usage + +Generate a Markdown review report for French: + +```powershell +pwsh ./.agents/skills/translation-review/scripts/review-translation-json.ps1 \ + -TargetJson ./src/Languages/lang_fr.json \ + -Language fr +``` + +Generate a report for Ukrainian and include script-detection checks: + +```powershell +pwsh ./.agents/skills/translation-review/scripts/review-translation-json.ps1 \ + -TargetJson ./src/Languages/lang_ua.json \ + -Language ua +``` + +Generate a flagged-only JSON report with no cross-language table: + +```powershell +pwsh ./.agents/skills/translation-review/scripts/review-translation-json.ps1 \ + -TargetJson ./src/Languages/lang_de.json \ + -Language de \ + -OutputFormat Json \ + -FlaggedOnly +``` + +Optional parameters: + +- `-NeutralJson` — defaults to `src/Languages/lang_en.json` +- `-ComparisonLanguages` — languages to include in the comparison table; defaults to other checked-in `lang_*.json` files +- `-OutputPath` — defaults to `generated/translation-review/review..md` +- `-OutputFormat` — `Markdown` (default) or `Json` +- `-FlaggedOnly` — skip the full cross-language table and emit only mechanically flagged entries + +## Output + +The Markdown report is structured as: + +1. Summary +2. Parity Issues +3. English-Equal Entries +4. Wrong Script +5. Cross-Language Comparison + +Default output path: `generated/translation-review/review..md` + +## Agent Review Guidelines + +### Flagged sections + +- Parity issues: confirm whether the placeholder, tag, or newline mismatch is a genuine error or an acceptable localized variant. +- English-equal entries: decide whether the English value is an acceptable technical or brand string, or whether it should be translated. +- Wrong script: almost always an error for non-Latin languages. Verify against comparison languages and flag for re-translation when confirmed. + +### Cross-language comparison table + +- Sample at least 20–30 rows and prefer entries that look like UI labels, buttons, dialogs, settings descriptions, or error messages. +- Look for wrong language, suspiciously different meaning, missing words, or copied English that should probably be translated. +- Ignore obvious brand names and technical identifiers. + +### Output format for findings + +Report each issue in this format: + +```text +**Source**: `Some English source text` +**Problem**: [describe the issue] +**Current value**: [the problematic translation] +**Suggested correction**: [corrected value, if confident] +**Confidence**: High / Medium / Low +``` + +Group findings by type: parity, English-equal, wrong language, wrong script, or other. + +## Integration with Other Skills + +- Use [translation-status](../translation-status/SKILL.md) first if you need a coverage snapshot before reviewing quality. +- Use [translation-diff-export](../translation-diff-export/SKILL.md) to produce a sparse patch for entries that need re-translation after review. +- Use [translation-diff-import](../translation-diff-import/SKILL.md) to merge corrected entries back into the full language file. \ No newline at end of file diff --git a/.agents/skills/translation-review/scripts/review-translation-json.ps1 b/.agents/skills/translation-review/scripts/review-translation-json.ps1 new file mode 100644 index 0000000..d3f7956 --- /dev/null +++ b/.agents/skills/translation-review/scripts/review-translation-json.ps1 @@ -0,0 +1,435 @@ +[CmdletBinding()] +param( + [Parameter(Mandatory)] + [string]$TargetJson, + + [Parameter(Mandatory)] + [string]$Language, + + [string]$NeutralJson, + [string]$OutputPath, + [string[]]$ComparisonLanguages, + + [ValidateSet('Markdown', 'Json')] + [string]$OutputFormat = 'Markdown', + + [switch]$FlaggedOnly +) + +Set-StrictMode -Version Latest +$ErrorActionPreference = 'Stop' + +$repoRoot = [System.IO.Path]::GetFullPath((Join-Path $PSScriptRoot '..\..\..\..')) +. (Join-Path $repoRoot 'scripts\translation\Languages\TranslationJsonTools.ps1') + +function Get-TranslationReviewLanguageReferencePath { + return Join-Path $repoRoot 'src\Languages\Data\LanguagesReference.json' +} + +function Get-TranslationReviewLanguagesDirectory { + return Join-Path $repoRoot 'src\Languages' +} + +function Get-TranslationReviewLanguageReference { + return Read-OrderedJsonMap -Path (Get-TranslationReviewLanguageReferencePath) +} + +function Get-TranslationReviewDisplayLanguage { + param( + [Parameter(Mandatory = $true)] + [string]$LanguageCode, + + [Parameter(Mandatory = $true)] + [System.Collections.IDictionary]$LanguageReference + ) + + if ($LanguageReference.Contains($LanguageCode)) { + return [string]$LanguageReference[$LanguageCode] + } + + return $LanguageCode +} + +function Test-TranslationReviewTechnicalToken { + param( + [string]$Value + ) + + if ([string]::IsNullOrWhiteSpace($Value)) { return $false } + if ($Value -match '^\d[\d\s%:./-]*$') { return $true } + if ($Value -match '^[A-Z0-9]{1,12}$') { return $true } + if ($Value -match '^https?://') { return $true } + if ($Value -match '^[A-Z][a-zA-Z0-9]+$' -and $Value.Length -le 30) { return $true } + if ($Value.Length -le 2) { return $true } + + return $false +} + +function Get-TranslationReviewScriptInfo { + param( + [Parameter(Mandatory = $true)] + [string]$LanguageCode + ) + + switch ($LanguageCode) { + 'ar' { return @{ Name = 'Arabic'; Pattern = '[\u0600-\u06ff]' } } + 'be' { return @{ Name = 'Cyrillic'; Pattern = '[\u0400-\u04ff]' } } + 'bg' { return @{ Name = 'Cyrillic'; Pattern = '[\u0400-\u04ff]' } } + 'bn' { return @{ Name = 'Bengali'; Pattern = '[\u0980-\u09ff]' } } + 'el' { return @{ Name = 'Greek'; Pattern = '[\u0370-\u03ff]' } } + 'fa' { return @{ Name = 'Arabic'; Pattern = '[\u0600-\u06ff]' } } + 'he' { return @{ Name = 'Hebrew'; Pattern = '[\u0590-\u05ff]' } } + 'hi' { return @{ Name = 'Devanagari'; Pattern = '[\u0900-\u097f]' } } + 'ja' { return @{ Name = 'Japanese'; Pattern = '[\u3040-\u30ff\u4e00-\u9fff]' } } + 'ka' { return @{ Name = 'Georgian'; Pattern = '[\u10a0-\u10ff]' } } + 'kn' { return @{ Name = 'Kannada'; Pattern = '[\u0c80-\u0cff]' } } + 'ko' { return @{ Name = 'Korean'; Pattern = '[\uac00-\ud7a3]' } } + 'mk' { return @{ Name = 'Cyrillic'; Pattern = '[\u0400-\u04ff]' } } + 'mr' { return @{ Name = 'Devanagari'; Pattern = '[\u0900-\u097f]' } } + 'ru' { return @{ Name = 'Cyrillic'; Pattern = '[\u0400-\u04ff]' } } + 'sa' { return @{ Name = 'Devanagari'; Pattern = '[\u0900-\u097f]' } } + 'si' { return @{ Name = 'Sinhala'; Pattern = '[\u0d80-\u0dff]' } } + 'ta' { return @{ Name = 'Tamil'; Pattern = '[\u0b80-\u0bff]' } } + 'th' { return @{ Name = 'Thai'; Pattern = '[\u0e00-\u0e7f]' } } + 'ua' { return @{ Name = 'Cyrillic'; Pattern = '[\u0400-\u04ff]' } } + 'ur' { return @{ Name = 'Arabic'; Pattern = '[\u0600-\u06ff]' } } + 'zh_CN' { return @{ Name = 'CJK'; Pattern = '[\u4e00-\u9fff\u3400-\u4dbf\uf900-\ufaff]' } } + 'zh_TW' { return @{ Name = 'CJK'; Pattern = '[\u4e00-\u9fff\u3400-\u4dbf\uf900-\ufaff]' } } + default { return $null } + } +} + +function Test-TranslationReviewExpectedScript { + param( + [Parameter(Mandatory = $true)] + [string]$LanguageCode, + + [Parameter(Mandatory = $true)] + [string]$Value + ) + + $scriptInfo = Get-TranslationReviewScriptInfo -LanguageCode $LanguageCode + if ($null -eq $scriptInfo) { + return $null + } + + return [pscustomobject]@{ + ExpectedScript = $scriptInfo.Name + HasExpectedScript = [bool]($Value -match $scriptInfo.Pattern) + } +} + +function Get-TranslationReviewParityIssues { + param( + [Parameter(Mandatory = $true)] + [string]$SourceValue, + + [Parameter(Mandatory = $true)] + [string]$TranslatedValue + ) + + $issues = New-Object System.Collections.Generic.List[string] + + $sourcePlaceholderSignature = (Get-PlaceholderTokens -Value $SourceValue) -join "`n" + $translatedPlaceholderSignature = (Get-PlaceholderTokens -Value $TranslatedValue) -join "`n" + if ($sourcePlaceholderSignature -ne $translatedPlaceholderSignature) { + $issues.Add('Placeholder mismatch') + } + + $sourceHtmlSignature = (Get-HtmlTokens -Value $SourceValue) -join "`n" + $translatedHtmlSignature = (Get-HtmlTokens -Value $TranslatedValue) -join "`n" + if ($sourceHtmlSignature -ne $translatedHtmlSignature) { + $issues.Add('HTML fragment mismatch') + } + + if ((Get-NewlineCount -Value $SourceValue) -ne (Get-NewlineCount -Value $TranslatedValue)) { + $issues.Add('Line-break mismatch') + } + + return @($issues) +} + +function Format-TranslationReviewMarkdownCell { + param( + [AllowNull()] + [string]$Value + ) + + if ($null -eq $Value) { + return '_-_' + } + + $escapedValue = $Value -replace '\|', '\|' + if ($escapedValue.Length -gt 120) { + $escapedValue = $escapedValue.Substring(0, 117) + '...' + } + + return $escapedValue +} + +if (-not $NeutralJson) { + $NeutralJson = Join-Path (Get-TranslationReviewLanguagesDirectory) 'lang_en.json' +} + +$languageReference = Get-TranslationReviewLanguageReference +if (-not $languageReference.Contains($Language)) { + throw "Unknown language code '$Language'." +} + +if (-not $ComparisonLanguages) { + $ComparisonLanguages = @() + foreach ($entry in $languageReference.GetEnumerator()) { + $code = [string]$entry.Key + if ($code -in @('default', 'en', $Language)) { + continue + } + + $comparisonPath = Join-Path (Get-TranslationReviewLanguagesDirectory) ("lang_{0}.json" -f $code) + if (Test-Path -Path $comparisonPath -PathType Leaf) { + $ComparisonLanguages += $code + } + } +} + +if (-not $OutputPath) { + $extension = if ($OutputFormat -eq 'Json') { 'json' } else { 'md' } + $OutputPath = Join-Path $repoRoot ("generated\translation-review\review.{0}.{1}" -f $Language, $extension) +} + +$neutralMap = Read-OrderedJsonMap -Path $NeutralJson +$targetMap = Read-OrderedJsonMap -Path $TargetJson + +$comparisonMaps = [ordered]@{} +foreach ($code in $ComparisonLanguages) { + $comparisonPath = Join-Path (Get-TranslationReviewLanguagesDirectory) ("lang_{0}.json" -f $code) + if (Test-Path -Path $comparisonPath -PathType Leaf) { + $comparisonMaps[$code] = Read-OrderedJsonMap -Path $comparisonPath + } +} + +$parityIssues = [System.Collections.Generic.List[object]]::new() +$englishEqualEntries = [System.Collections.Generic.List[object]]::new() +$wrongScriptEntries = [System.Collections.Generic.List[object]]::new() +$crossLanguageEntries = [System.Collections.Generic.List[object]]::new() + +foreach ($entry in $neutralMap.GetEnumerator()) { + $sourceText = [string]$entry.Key + $englishValue = [string]$entry.Value + + if (-not $targetMap.Contains($sourceText)) { + continue + } + + $targetValue = [string]$targetMap[$sourceText] + if ([string]::IsNullOrWhiteSpace($targetValue)) { + continue + } + + $crossLanguage = [ordered]@{} + foreach ($code in $comparisonMaps.Keys) { + $crossLanguage[$code] = if ($comparisonMaps[$code].Contains($sourceText)) { + [string]$comparisonMaps[$code][$sourceText] + } + else { + $null + } + } + + if ($Language -ne 'en' -and $targetValue -ceq $englishValue -and -not (Test-TranslationReviewTechnicalToken -Value $englishValue)) { + $englishEqualEntries.Add([pscustomobject]@{ + SourceText = $sourceText + English = $englishValue + Translation = $targetValue + CrossLanguage = $crossLanguage + }) + } + else { + $issues = @(Get-TranslationReviewParityIssues -SourceValue $englishValue -TranslatedValue $targetValue) + if ($issues.Count -gt 0) { + $parityIssues.Add([pscustomobject]@{ + SourceText = $sourceText + English = $englishValue + Translation = $targetValue + Issues = $issues + CrossLanguage = $crossLanguage + }) + } + + $scriptCheck = Test-TranslationReviewExpectedScript -LanguageCode $Language -Value $targetValue + if ($null -ne $scriptCheck -and -not $scriptCheck.HasExpectedScript -and -not (Test-TranslationReviewTechnicalToken -Value $englishValue)) { + $wrongScriptEntries.Add([pscustomobject]@{ + SourceText = $sourceText + English = $englishValue + Translation = $targetValue + ExpectedScript = $scriptCheck.ExpectedScript + CrossLanguage = $crossLanguage + }) + } + } + + $crossLanguageEntries.Add([pscustomobject]@{ + SourceText = $sourceText + English = $englishValue + Translation = $targetValue + CrossLanguage = $crossLanguage + }) +} + +$displayName = Get-TranslationReviewDisplayLanguage -LanguageCode $Language -LanguageReference $languageReference + +$output = if ($OutputFormat -eq 'Json') { + [pscustomobject]@{ + Language = $Language + DisplayName = $displayName + GeneratedAt = (Get-Date -Format 'o') + TargetJson = $TargetJson + TotalReviewed = $crossLanguageEntries.Count + ParityIssueCount = $parityIssues.Count + EnglishEqualCount = $englishEqualEntries.Count + WrongScriptCount = $wrongScriptEntries.Count + ParityIssues = $parityIssues.ToArray() + EnglishEqual = $englishEqualEntries.ToArray() + WrongScript = $wrongScriptEntries.ToArray() + CrossLanguage = if (-not $FlaggedOnly) { $crossLanguageEntries.ToArray() } else { @() } + } | ConvertTo-Json -Depth 10 +} +else { + $builder = [System.Text.StringBuilder]::new() + [void]$builder.AppendLine("# Translation Review: $displayName ($Language)") + [void]$builder.AppendLine() + [void]$builder.AppendLine("**File**: ``$TargetJson``") + [void]$builder.AppendLine("**Generated**: $(Get-Date -Format 'yyyy-MM-dd HH:mm')") + [void]$builder.AppendLine("**Comparison languages**: $($comparisonMaps.Keys -join ', ')") + [void]$builder.AppendLine() + [void]$builder.AppendLine('## Summary') + [void]$builder.AppendLine() + [void]$builder.AppendLine('| Category | Count |') + [void]$builder.AppendLine('|---|---|') + [void]$builder.AppendLine("| Reviewed translated entries | $($crossLanguageEntries.Count) |") + [void]$builder.AppendLine("| Parity issues | $($parityIssues.Count) |") + [void]$builder.AppendLine("| English-equal entries | $($englishEqualEntries.Count) |") + [void]$builder.AppendLine("| Wrong script entries | $($wrongScriptEntries.Count) |") + [void]$builder.AppendLine() + + [void]$builder.AppendLine('## Parity Issues') + [void]$builder.AppendLine() + if ($parityIssues.Count -eq 0) { + [void]$builder.AppendLine('_No parity issues found._') + } + else { + foreach ($issue in $parityIssues) { + [void]$builder.AppendLine("### ``$($issue.SourceText)``") + [void]$builder.AppendLine() + [void]$builder.AppendLine("- **English**: $($issue.English)") + [void]$builder.AppendLine("- **$Language**: $($issue.Translation)") + foreach ($problem in $issue.Issues) { + [void]$builder.AppendLine("- **Issue**: $problem") + } + foreach ($code in $issue.CrossLanguage.Keys) { + $value = $issue.CrossLanguage[$code] + if (-not [string]::IsNullOrWhiteSpace($value) -and $value -ne $issue.English) { + [void]$builder.AppendLine("- **$code**: $value") + } + } + [void]$builder.AppendLine() + } + } + [void]$builder.AppendLine() + + [void]$builder.AppendLine('## English-Equal Entries') + [void]$builder.AppendLine() + if ($englishEqualEntries.Count -eq 0) { + [void]$builder.AppendLine('_No suspicious English-equal entries found._') + } + else { + foreach ($item in $englishEqualEntries) { + [void]$builder.AppendLine("### ``$($item.SourceText)``") + [void]$builder.AppendLine() + [void]$builder.AppendLine("- **English**: $($item.English)") + [void]$builder.AppendLine("- **$Language**: $($item.Translation)") + foreach ($code in $item.CrossLanguage.Keys) { + $value = $item.CrossLanguage[$code] + if (-not [string]::IsNullOrWhiteSpace($value) -and $value -ne $item.English) { + [void]$builder.AppendLine("- **$code**: $value") + } + } + [void]$builder.AppendLine() + } + } + [void]$builder.AppendLine() + + [void]$builder.AppendLine('## Wrong Script') + [void]$builder.AppendLine() + if ($wrongScriptEntries.Count -eq 0) { + $scriptInfo = Get-TranslationReviewScriptInfo -LanguageCode $Language + if ($null -eq $scriptInfo) { + [void]$builder.AppendLine('_Not applicable for Latin-script languages._') + } + else { + [void]$builder.AppendLine('_No wrong-script entries found._') + } + } + else { + foreach ($item in $wrongScriptEntries) { + [void]$builder.AppendLine("### ``$($item.SourceText)``") + [void]$builder.AppendLine() + [void]$builder.AppendLine("- **English**: $($item.English)") + [void]$builder.AppendLine("- **$Language**: $($item.Translation)") + [void]$builder.AppendLine("- **Expected script**: $($item.ExpectedScript)") + foreach ($code in $item.CrossLanguage.Keys) { + $value = $item.CrossLanguage[$code] + if (-not [string]::IsNullOrWhiteSpace($value) -and $value -ne $item.English) { + [void]$builder.AppendLine("- **$code**: $value") + } + } + [void]$builder.AppendLine() + } + } + [void]$builder.AppendLine() + + if (-not $FlaggedOnly) { + $comparisonCodes = @($comparisonMaps.Keys) + [void]$builder.AppendLine('## Cross-Language Comparison') + [void]$builder.AppendLine() + [void]$builder.AppendLine('Use this table for spot-checking suspicious wording, wrong language, and unusual differences against related languages.') + [void]$builder.AppendLine() + $header = '| Source | English | ' + $Language + ' | ' + ($comparisonCodes -join ' | ') + ' |' + $divider = '|---|---|' + ('---|' * ($comparisonCodes.Count + 1)) + [void]$builder.AppendLine($header) + [void]$builder.AppendLine($divider) + foreach ($row in $crossLanguageEntries) { + $cells = New-Object System.Collections.Generic.List[string] + $cells.Add((Format-TranslationReviewMarkdownCell -Value $row.SourceText)) + $cells.Add((Format-TranslationReviewMarkdownCell -Value $row.English)) + $cells.Add((Format-TranslationReviewMarkdownCell -Value $row.Translation)) + foreach ($code in $comparisonCodes) { + $cells.Add((Format-TranslationReviewMarkdownCell -Value $row.CrossLanguage[$code])) + } + + [void]$builder.AppendLine('| ' + ($cells -join ' | ') + ' |') + } + } + + $builder.ToString() +} + +$outputDirectory = Split-Path -Path $OutputPath -Parent +if (-not (Test-Path -Path $outputDirectory -PathType Container)) { + New-Item -Path $outputDirectory -ItemType Directory -Force | Out-Null +} + +[System.IO.File]::WriteAllText($OutputPath, [string]$output, [System.Text.UTF8Encoding]::new($false)) + +Write-Host "Review written to: $OutputPath" +Write-Host " Parity issues: $($parityIssues.Count)" +Write-Host " English-equal: $($englishEqualEntries.Count)" +Write-Host " Wrong script: $($wrongScriptEntries.Count)" +Write-Host " Entries reviewed: $($crossLanguageEntries.Count)" + +[pscustomobject]@{ + OutputPath = $OutputPath + ParityIssueCount = $parityIssues.Count + EnglishEqualCount = $englishEqualEntries.Count + WrongScriptCount = $wrongScriptEntries.Count + ReviewedEntryCount = $crossLanguageEntries.Count +} \ No newline at end of file diff --git a/.agents/skills/translation-source-sync/SKILL.md b/.agents/skills/translation-source-sync/SKILL.md new file mode 100644 index 0000000..0a8a3c9 --- /dev/null +++ b/.agents/skills/translation-source-sync/SKILL.md @@ -0,0 +1,91 @@ +--- +name: translation-source-sync +description: Synchronizes the UniGetUI English language file with source-code usage, identifies missing translation keys, removes unused entries, reports localization drift, and can reorder locale files to match the English key ordering. Use when the user asks to sync language files, missing translations, i18n drift, or align locale file ordering with English. +--- + +# translation source sync + +Use this skill when UniGetUI source code changed and you need to keep [src/Languages/lang_en.json](src/Languages/lang_en.json) aligned with the strings actually used by the application, or when you need downstream locale files reordered to match the English key ordering. + +It scans supported C#, WinUI XAML, and Avalonia AXAML patterns, finds missing English keys, removes unused entries, reports translation-source warnings that still need manual cleanup, and can align locale file ordering to the English layout. + +## Scope + +- Extract literal translation keys from supported UniGetUI source patterns. +- Add new English keys missing from `lang_en.json`. +- Remove English keys that are no longer used. +- Reorder non-English locale files to match the English key ordering. +- Warn about interpolated `CoreTools.Translate($"...")` calls that are not synchronized automatically. +- Leave downstream language propagation to the existing translation diff workflow. + +## Supported extraction sources + +- `CoreTools.Translate("...")` in C#. +- `CoreTools.AutoTranslated("...")` in C#. +- `widgets:TranslatedTextBlock Text="..."` in WinUI XAML. +- `settings:TranslatedTextBlock Text="..."` in Avalonia AXAML. +- `{t:Translate Some text}` and `{t:Translate Text='A, B, C'}` in Avalonia AXAML. + +## Out of scope for v1 + +- Interpolated translation calls such as `CoreTools.Translate($"Running {value}")`. +- Non-literal translation inputs passed through variables. +- CI enforcement. + +## Scripts + +- `scripts/sync-translation-sources.ps1`: Skill wrapper around the repository sync script. +- `scripts/set-translation-boundary-order.ps1`: Skill wrapper around the repository locale reordering script. +- `scripts/test-translation-source-sync.ps1`: Skill wrapper around the repository smoke test. +- `../../../../scripts/translation/Sync-TranslationSources.ps1`: Canonical repository implementation used by the wrapper. +- `../../../../scripts/translation/Set-TranslationBoundaryOrder.ps1`: Canonical repository implementation used by the wrapper. +- `../../../../scripts/translation/Test-TranslationSourceSync.ps1`: Canonical smoke test used by the wrapper. + +## Usage + +Synchronize the checked-in English language file in place: + +```powershell +pwsh ./.agents/skills/translation-source-sync/scripts/sync-translation-sources.ps1 +``` + +Check whether the English file is out of sync without writing changes: + +```powershell +pwsh ./.agents/skills/translation-source-sync/scripts/sync-translation-sources.ps1 -CheckOnly +``` + +Reorder locale files to match the English key ordering: + +```powershell +pwsh ./.agents/skills/translation-source-sync/scripts/set-translation-boundary-order.ps1 +``` + +Preview whether locale files need reordering without writing changes: + +```powershell +pwsh ./.agents/skills/translation-source-sync/scripts/set-translation-boundary-order.ps1 -CheckOnly +``` + +Run the smoke test: + +```powershell +pwsh ./.agents/skills/translation-source-sync/scripts/test-translation-source-sync.ps1 +``` + +## Recommended workflow + +1. Run translation source sync after changing any translatable source string. +2. If `-CheckOnly` reports drift, run the full sync to rewrite `lang_en.json`. +3. Review warnings for interpolated translation calls and convert them to stable literals or add the missing English keys manually when needed. +4. Run `pwsh ./.agents/skills/translation-source-sync/scripts/set-translation-boundary-order.ps1` to align locale ordering with English. +5. Run `pwsh ./scripts/translation/Verify-Translations.ps1` to confirm the language files still validate cleanly. +6. Run `pwsh ./.agents/skills/translation-source-sync/scripts/test-translation-source-sync.ps1` if you changed the sync workflow itself. +7. Export changed work for translators with [translation-diff-export](../translation-diff-export/SKILL.md). + +## Notes + +- Existing English values are preserved for retained keys; newly added English entries default to `key == value`. +- The sync script preserves current key order for retained entries and appends newly discovered keys deterministically. +- The locale reorder script follows English as the canonical order and appends unmapped locale-only keys at the end. +- The smoke test uses a temporary synthetic repo so it does not mutate the checked-in language files. diff --git a/.agents/skills/translation-source-sync/scripts/set-translation-boundary-order.ps1 b/.agents/skills/translation-source-sync/scripts/set-translation-boundary-order.ps1 new file mode 100644 index 0000000..19c122d --- /dev/null +++ b/.agents/skills/translation-source-sync/scripts/set-translation-boundary-order.ps1 @@ -0,0 +1,26 @@ +[CmdletBinding(SupportsShouldProcess = $true)] +param( + [string]$RepositoryRoot, + [string]$EnglishFilePath, + [string]$LanguagesDirectory, + [string]$InventoryOutputPath, + [switch]$IncludeEnglish, + [switch]$CheckOnly +) + +Set-StrictMode -Version Latest +$ErrorActionPreference = 'Stop' + +$repoRoot = [System.IO.Path]::GetFullPath((Join-Path $PSScriptRoot '..\..\..\..')) +$scriptPath = Join-Path $repoRoot 'scripts\translation\Set-TranslationBoundaryOrder.ps1' +if (-not (Test-Path -Path $scriptPath -PathType Leaf)) { + throw "Translation boundary reorder script not found: $scriptPath" +} + +& $scriptPath ` + -RepositoryRoot $RepositoryRoot ` + -EnglishFilePath $EnglishFilePath ` + -LanguagesDirectory $LanguagesDirectory ` + -InventoryOutputPath $InventoryOutputPath ` + -IncludeEnglish:$IncludeEnglish.IsPresent ` + -CheckOnly:$CheckOnly.IsPresent \ No newline at end of file diff --git a/.agents/skills/translation-source-sync/scripts/sync-translation-sources.ps1 b/.agents/skills/translation-source-sync/scripts/sync-translation-sources.ps1 new file mode 100644 index 0000000..b92d1cd --- /dev/null +++ b/.agents/skills/translation-source-sync/scripts/sync-translation-sources.ps1 @@ -0,0 +1,17 @@ +[CmdletBinding(SupportsShouldProcess = $true)] +param( + [string]$RepositoryRoot, + [string]$EnglishFilePath, + [switch]$CheckOnly +) + +Set-StrictMode -Version Latest +$ErrorActionPreference = 'Stop' + +$repoRoot = [System.IO.Path]::GetFullPath((Join-Path $PSScriptRoot '..\..\..\..')) +$scriptPath = Join-Path $repoRoot 'scripts\translation\Sync-TranslationSources.ps1' +if (-not (Test-Path -Path $scriptPath -PathType Leaf)) { + throw "Translation source sync script not found: $scriptPath" +} + +& $scriptPath -RepositoryRoot $RepositoryRoot -EnglishFilePath $EnglishFilePath -CheckOnly:$CheckOnly.IsPresent \ No newline at end of file diff --git a/.agents/skills/translation-source-sync/scripts/test-translation-source-sync.ps1 b/.agents/skills/translation-source-sync/scripts/test-translation-source-sync.ps1 new file mode 100644 index 0000000..8f2b255 --- /dev/null +++ b/.agents/skills/translation-source-sync/scripts/test-translation-source-sync.ps1 @@ -0,0 +1,10 @@ +Set-StrictMode -Version Latest +$ErrorActionPreference = 'Stop' + +$repoRoot = [System.IO.Path]::GetFullPath((Join-Path $PSScriptRoot '..\..\..\..')) +$scriptPath = Join-Path $repoRoot 'scripts\translation\Test-TranslationSourceSync.ps1' +if (-not (Test-Path -Path $scriptPath -PathType Leaf)) { + throw "Translation source sync smoke test script not found: $scriptPath" +} + +& $scriptPath \ No newline at end of file diff --git a/.agents/skills/translation-status/SKILL.md b/.agents/skills/translation-status/SKILL.md new file mode 100644 index 0000000..90b2714 --- /dev/null +++ b/.agents/skills/translation-status/SKILL.md @@ -0,0 +1,58 @@ +--- +name: translation-status +description: Analyzes checked-in UniGetUI language files to calculate translation percentages, surface untranslated coverage data, and generate localization status reports. +--- + +# translation status + +Use this skill when the user asks for UniGetUI translation progress, localization or i18n coverage, untranslated-language reports, or a language support status summary. + +## Prerequisites + +- PowerShell 7 (`pwsh`). + +## Scripts + +- `scripts/get-translation-status.ps1`: Skill wrapper you should invoke from the skill. +- `../../../../scripts/translation/Get-TranslationStatus.ps1`: Canonical repository implementation delegated to by the wrapper. + +## Usage + +Show the default table summary: + +```powershell +pwsh ./.agents/skills/translation-status/scripts/get-translation-status.ps1 +``` + +Show only incomplete languages as markdown: + +```powershell +pwsh ./.agents/skills/translation-status/scripts/get-translation-status.ps1 \ + -OutputFormat Markdown \ + -OnlyIncomplete +``` + +Write JSON output to a file: + +```powershell +pwsh ./.agents/skills/translation-status/scripts/get-translation-status.ps1 \ + -OutputFormat Json \ + -OutputPath ./generated/translation-status.json +``` + +## Output Fields + +- `Code`: language code +- `Language`: display name +- `Completion`: computed completion percentage using English active keys only +- `Translated`, `Missing`, `Empty`, `SourceEqual`, `Extra`: per-language entry counts +- `Stored` and `Delta`: stored percentage metadata and difference from the computed result + +## Notes + +- The script treats source-equal values as untranslated for non-English languages. +- Completion never reports `100%` unless every active English key is present and translated. +- `Extra` counts locale-only keys not present in the English file. +- Use `-IncludeEnglish` if you want the `en` row included in the report. +- Use `-OnlyIncomplete` to focus on languages that still need work. +- For the full parameter surface, inspect `../../../../scripts/translation/Get-TranslationStatus.ps1`. diff --git a/.agents/skills/translation-status/scripts/get-translation-status.ps1 b/.agents/skills/translation-status/scripts/get-translation-status.ps1 new file mode 100644 index 0000000..d12addf --- /dev/null +++ b/.agents/skills/translation-status/scripts/get-translation-status.ps1 @@ -0,0 +1,22 @@ +[CmdletBinding()] +param( + [ValidateSet('Table', 'Json', 'Markdown')] + [string]$OutputFormat = 'Table', + + [switch]$IncludeEnglish, + + [switch]$OnlyIncomplete, + + [string]$OutputPath +) + +Set-StrictMode -Version Latest +$ErrorActionPreference = 'Stop' + +$repoRoot = [System.IO.Path]::GetFullPath((Join-Path $PSScriptRoot '..\..\..\..')) +$scriptPath = Join-Path $repoRoot 'scripts\translation\Get-TranslationStatus.ps1' +if (-not (Test-Path -Path $scriptPath -PathType Leaf)) { + throw "Translation status script not found: $scriptPath" +} + +& $scriptPath -OutputFormat $OutputFormat -IncludeEnglish:$IncludeEnglish.IsPresent -OnlyIncomplete:$OnlyIncomplete.IsPresent -OutputPath $OutputPath \ No newline at end of file diff --git a/.claude/skills b/.claude/skills new file mode 120000 index 0000000..2b7a412 --- /dev/null +++ b/.claude/skills @@ -0,0 +1 @@ +../.agents/skills \ No newline at end of file diff --git a/.deepsource.toml b/.deepsource.toml new file mode 100644 index 0000000..227ede7 --- /dev/null +++ b/.deepsource.toml @@ -0,0 +1,65 @@ +version = 1 + +[[analyzers]] +name = "python" +enabled = true + + [analyzers.meta] + runtime_version = "3.x.x" + + [analyzers.pylint] + enabled = true + config = """ + [MESSAGES CONTROL] + disable = C0111 # Disables missing docstring warnings + """ + +[[analyzers]] +name = "javascript" +enabled = true + + [analyzers.meta] + plugins = [ + "react", + "vue", + "angular" + ] + environment = [ + "nodejs", + "mocha", + "mongo", + "browser", + "jasmine", + "cypress", + "vitest", + "jquery", + "jest" + ] + +[[transformers]] +name = "autopep8" +enabled = false # Disables autopep8 transformer + +[[transformers]] +name = "isort" +enabled = false # Disables isort transformer + +[[transformers]] +name = "black" +enabled = false # Disables black transformer + +[[transformers]] +name = "yapf" +enabled = false # Disables yapf transformer + +[[transformers]] +name = "ruff" +enabled = false # Disables ruff transformer + +[[transformers]] +name = "standardjs" +enabled = false # Disables standardjs transformer + +[[transformers]] +name = "prettier" +enabled = false # Disables prettier transformer \ No newline at end of file diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..1b8a169 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +src/UniGetUI.PackageEngine.Managers.Chocolatey/choco-cli/** linguist-vendored +.githooks/* text eol=lf \ No newline at end of file diff --git a/.githooks/pre-commit b/.githooks/pre-commit new file mode 100644 index 0000000..45f6cfe --- /dev/null +++ b/.githooks/pre-commit @@ -0,0 +1,38 @@ +#!/usr/bin/env sh + +set -eu + +repo_root=$(git rev-parse --show-toplevel) +cd "$repo_root" + +staged_files=$(git diff --cached --name-only --diff-filter=ACMR -- src | grep -E '\.(cs|csproj|props|targets|editorconfig|json|sln|slnx)$' || true) + +if [ -z "$staged_files" ]; then + exit 0 +fi + +unstaged_files=$(git diff --name-only -- $staged_files || true) +if [ -n "$unstaged_files" ]; then + echo "pre-commit: relevant files have unstaged changes." + echo "Stage or stash them before committing so dotnet format does not rewrite mixed content." + printf '%s\n' "$unstaged_files" + exit 1 +fi + +if ! command -v dotnet >/dev/null 2>&1; then + echo "pre-commit: dotnet CLI not found; skipping whitespace formatting." + exit 0 +fi + +echo "pre-commit: running dotnet format whitespace on staged src files" + +# shellcheck disable=SC2086 +dotnet format whitespace src --folder --verbosity minimal --include $staged_files + +if ! git diff --quiet -- $staged_files; then + git add -- $staged_files + echo "pre-commit: formatting updates were staged. Review them and run git commit again." + exit 1 +fi + +exit 0 \ No newline at end of file diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 0000000..8d0b931 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1,3 @@ +# File auto-generated and managed by Devops +/.github/ @devolutions/devops @devolutions/architecture-maintainers @GabrielDuf # Gabriel Dufresne +/.github/dependabot.yml @devolutions/security-managers diff --git a/.github/ISSUE_TEMPLATE/bug-issue.yml b/.github/ISSUE_TEMPLATE/bug-issue.yml new file mode 100644 index 0000000..47850e7 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug-issue.yml @@ -0,0 +1,68 @@ +name: '🐞 Report a bug or an issue' +description: Report issues or unexpected behaviors. +title: "[BUG] (Enter your description here)" +labels: ["bug"] +body: + - type: checkboxes + attributes: + label: Please confirm these before moving forward + description: Please confirm the following before posting your issue. + options: + - label: I have searched for my issue and have not found a work-in-progress/duplicate/resolved issue. + required: true + - label: I have tested that this issue has not been fixed in the latest [(beta or stable) release](https://github.com/Devolutions/UniGetUI/releases/). + required: true + - label: I have checked the [FAQ](https://github.com/Devolutions/UniGetUI#frequently-asked-questions) section for solutions. + required: true + - label: This issue is about a bug (if it is not, please use the [correct template](https://github.com/Devolutions/UniGetUI/issues/new/choose)). + required: true + - type: input + attributes: + label: UniGetUI Version + placeholder: 'x.y.z (e.g., 3.1.0)' + validations: + required: true + - type: input + attributes: + label: Windows version, edition, and architecture + placeholder: Windows 11 Pro 10.0.22000.0 x64 + validations: + required: true + - type: textarea + attributes: + label: Describe your issue + placeholder: Explain the issue you are experiencing, providing as many details as possible. + validations: + required: true + - type: textarea + attributes: + label: Steps to reproduce the issue + placeholder: How can this issue be reproduced? List here, if known, the steps followed before this issue appeared. + validations: + required: false + - type: textarea + attributes: + label: UniGetUI Log + render: "text" + placeholder: Paste your UniGetUI logs here. Click the button on the bottom-left corner of UniGetUI -> UniGetUI Log. + validations: + required: true + - type: textarea + attributes: + label: Package Managers Logs + render: "text" + placeholder: Paste your Package Manager logs here. Click the button on the bottom-left corner of UniGetUI -> Package Manager logs. + validations: + required: true + - type: textarea + attributes: + label: Relevant information + placeholder: Other relevant information about this issue. Perhaps you have some special settings enabled or any other detail that could be related. + validations: + required: false + - type: textarea + attributes: + label: Screenshots and videos + placeholder: If applicable, please post here a video or a screenshot of the issue. + validations: + required: false diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 0000000..927f333 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,12 @@ +blank_issues_enabled: false + +contact_links: + - name: 📦 ISSUES INSTALLING/UPDATING A PACKAGE + url: https://github.com/Devolutions/UniGetUI + about: PLEASE READ THIS BEFORE CREATING AN ISSUE RELATED TO A SPECIFIC PACKAGE + - name: 🔒 Security issue or vulnerability + url: https://devolutions.net/security/ + about: Found a security issue? Please report it via the Devolutions security page + - name: 📧 Contact us directly, in private + url: https://devolutions.net/contact/ + about: Please use only for private inquiries that should not be posted publicly diff --git a/.github/ISSUE_TEMPLATE/enhancement-improvement.yml b/.github/ISSUE_TEMPLATE/enhancement-improvement.yml new file mode 100644 index 0000000..5774b2f --- /dev/null +++ b/.github/ISSUE_TEMPLATE/enhancement-improvement.yml @@ -0,0 +1,28 @@ +name: '🚧 Suggest an improvement for an existing feature' +description: Propose an improvement to UniGetUI. +title: "[IMPROVEMENT] (Enter your description here)" +labels: ["enhancement"] +body: + - type: checkboxes + attributes: + label: Please confirm these before moving forward. + description: Please confirm the following before posting your issue. + options: + - label: I have searched for my feature proposal and have not found a work-in-progress/duplicate/resolved/discarded issue. + required: true + - label: This improvement refers to an existing feature. If you want to suggest a new feature, please use [this template](https://github.com/Devolutions/UniGetUI/issues/new?labels=new-feature&projects=&template=feature-request.yml&title=%5BFEATURE+REQUEST%5D+%28Enter+your+description+here%29). + required: true + - label: This improvement is not a bug. If you want to report a bug, please use [this template](https://github.com/Devolutions/UniGetUI/issues/new?labels=bug&projects=&template=bug-issue.yml&title=%5BBUG%5D+%28Enter+your+description+here%29). + required: true + - type: textarea + attributes: + label: Describe the improvement + placeholder: Explain how you see this enhancement, providing as many details as possible. + validations: + required: true + - type: textarea + attributes: + label: Describe how this improvement could help users + placeholder: For what would it be useful? + validations: + required: true diff --git a/.github/ISSUE_TEMPLATE/feature-request.yml b/.github/ISSUE_TEMPLATE/feature-request.yml new file mode 100644 index 0000000..52f7f6d --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature-request.yml @@ -0,0 +1,26 @@ +name: '💡 Propose a new feature' +description: Propose a new feature that could be useful in UniGetUI. +title: "[FEATURE REQUEST] (Enter your description here)" +labels: ["new-feature"] +body: + - type: checkboxes + attributes: + label: Please confirm these before moving forward. + description: Please confirm the following before posting your issue. + options: + - label: I have searched for my feature proposal and have not found a work-in-progress/duplicate/resolved/discarded issue. + required: true + - label: This proposal is a completely new feature. If you want to suggest an improvement or an enhancement, please use [this template](https://github.com/Devolutions/UniGetUI/issues/new?labels=enhancement&projects=&template=enhancement-improvement.yml&title=%5BENHANCEMENT%5D+%28Enter+your+description+here%29). + required: true + - type: textarea + attributes: + label: Describe the new feature + placeholder: Explain how you see this new feature, providing as many details as possible. + validations: + required: true + - type: textarea + attributes: + label: Describe how this new feature could help users + placeholder: For what would it be useful? + validations: + required: true diff --git a/.github/ISSUE_TEMPLATE/hard-crash.yml b/.github/ISSUE_TEMPLATE/hard-crash.yml new file mode 100644 index 0000000..7a1b446 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/hard-crash.yml @@ -0,0 +1,35 @@ +name: '🚑 Report a crash or a hang' +description: UniGetUI is not launching, is hard-crashing, or is hanging at some point. +title: "[CRASH] (Enter your description here)" +labels: ["bug", "important"] +body: + - type: checkboxes + attributes: + label: Please confirm these before moving forward. + description: Please confirm the following before posting your issue. + options: + - label: I have tried deleting a folder named `UniGetUI` under `%UserProfile%\AppData\Local\UniGetUI`. + required: true + - label: I have tried reinstalling UniGetUI. + required: true + - label: I have tested that this issue has not been fixed in the latest [(beta or stable) release](https://github.com/Devolutions/UniGetUI/releases/). + required: true + - type: textarea + attributes: + label: Describe your crash + placeholder: What were you doing when this happened? + validations: + required: true + - type: textarea + attributes: + label: Logs (if possible) + placeholder: If you get an error report or a message, please post it here. + render: "text" + validations: + required: false + - type: textarea + attributes: + label: More details + placeholder: Do you have any other valuable information about this issue? + validations: + required: false diff --git a/.github/ISSUE_TEMPLATE/widgets-issue.yml b/.github/ISSUE_TEMPLATE/widgets-issue.yml new file mode 100644 index 0000000..23fa40a --- /dev/null +++ b/.github/ISSUE_TEMPLATE/widgets-issue.yml @@ -0,0 +1,74 @@ +name: '🧩 Report an issue with Widgets for UniGetUI' +description: Report issues or unexpected behaviors with Widgets for UniGetUI. +title: "[WIDGETS BUG] (Enter your description here)" +labels: ["bug", "widgets-for-unigetui"] +body: + - type: checkboxes + attributes: + label: Please confirm these before moving forward + description: Please confirm the following before posting your issue. + options: + - label: I have searched for my issue and have not found a work-in-progress/duplicate/resolved issue. + required: true + - label: I have tested that this issue has not been fixed in the latest [(beta or stable) release](https://github.com/Devolutions/UniGetUI/releases/). + required: true + - label: I have checked the [FAQ](https://github.com/Devolutions/UniGetUI#frequently-asked-questions) section for solutions. + required: true + - label: This issue is about a bug (if it is not, please use the [correct template](https://github.com/Devolutions/UniGetUI/issues/new/choose)). + required: true + - type: input + attributes: + label: UniGetUI Version + placeholder: 'x.y.z (e.g., 3.1.0)' + validations: + required: true + - type: input + attributes: + label: Widgets for UniGetUI Version + placeholder: 'x.y.z.w (e.g., 0.6.1.0)' + validations: + required: true + - type: input + attributes: + label: Windows version, edition, and architecture + placeholder: Windows 11 Pro 10.0.22000.0 x64 + validations: + required: true + - type: textarea + attributes: + label: Describe your issue + placeholder: Explain the issue you are experiencing, providing as many details as possible. + validations: + required: true + - type: textarea + attributes: + label: Steps to reproduce the issue + placeholder: How can this issue be reproduced? List here, if known, the steps followed before this issue appeared. + validations: + required: false + - type: textarea + attributes: + label: UniGetUI Log + render: "text" + placeholder: Paste your UniGetUI logs here. Click the button on the bottom-left corner of UniGetUI -> UniGetUI Log. + validations: + required: true + - type: textarea + attributes: + label: Package Managers Logs + render: "text" + placeholder: Paste your Package Manager logs here. Click the button on the bottom-left corner of UniGetUI -> Package Manager logs. + validations: + required: true + - type: textarea + attributes: + label: Relevant information + placeholder: Other relevant information about this issue. Perhaps you have some special settings enabled or any other detail that could be related. + validations: + required: false + - type: textarea + attributes: + label: Screenshots and videos + placeholder: If applicable, please post a video or a screenshot of the issue here. + validations: + required: false diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..ce009de --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,14 @@ + +- [ ] **I have read the [contributing guidelines](https://github.com/Devolutions/UniGetUI/blob/main/CONTRIBUTING.md#coding), and I agree with the [Code of Conduct](https://github.com/Devolutions/UniGetUI/blob/main/CODE_OF_CONDUCT.md)**. +- [ ] **Have you checked that there aren't other open [pull requests](https://github.com/Devolutions/UniGetUI/pulls) for the same changes?** +- [ ] **Have you tested that the committed code can be executed without errors?** +- [ ] **Have you confirmed that this issue is caused by UniGetUI itself, and not by the package manager or the package involved?** +If the same issue can be reproduced outside UniGetUI with the relevant package manager or with the package itself, please report it there first. UniGetUI should only be used to track issues that are specific to UniGetUI's behavior or integration. +----- + + +----- + +Closes #XXXX + +Relates to #XXXX diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..14515b0 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,10 @@ +version: 2 +updates: + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" + groups: + actions-deps: + patterns: + - "*" diff --git a/.github/renovate.json b/.github/renovate.json new file mode 100644 index 0000000..7d03fb6 --- /dev/null +++ b/.github/renovate.json @@ -0,0 +1,10 @@ +{ + "$schema": "https://docs.renovatebot.com/renovate-schema.json", + "extends": [ + "config:recommended" + ], + "enabledManagers": [ + "nuget" + ], + "dependencyDashboard": true +} diff --git a/.github/workflows/build-release.yml b/.github/workflows/build-release.yml new file mode 100644 index 0000000..670ff29 --- /dev/null +++ b/.github/workflows/build-release.yml @@ -0,0 +1,896 @@ +name: Build and Release + +on: + workflow_dispatch: + inputs: + version: + description: 'Release version (required, e.g. 2026.1.0)' + required: true + draft-release: + description: 'Create the GitHub Release as a draft' + required: true + type: boolean + default: false + skip-publish: + description: 'Skip publishing to GitHub Releases' + required: true + type: boolean + default: false + dry-run: + description: 'Dry run (simulate without publishing)' + required: true + type: boolean + default: true + +jobs: + preflight: + name: Preflight + runs-on: ubuntu-latest + outputs: + package-env: ${{ steps.info.outputs.package-env }} + package-version: ${{ steps.info.outputs.package-version }} + onedrive-version: ${{ steps.info.outputs.onedrive-version }} + draft-release: ${{ steps.info.outputs.draft-release }} + skip-publish: ${{ steps.info.outputs.skip-publish }} + dry-run: ${{ steps.info.outputs.dry-run }} + + steps: + - name: Checkout + uses: actions/checkout@v7 + + - name: Resolve build parameters + id: info + shell: pwsh + run: | + $IsProductionBranch = @('main', 'master') -contains '${{ github.ref_name }}' + + try { $DraftRelease = [System.Boolean]::Parse('${{ inputs.draft-release }}') } catch { $DraftRelease = $false } + try { $SkipPublish = [System.Boolean]::Parse('${{ inputs.skip-publish }}') } catch { $SkipPublish = $false } + try { $DryRun = [System.Boolean]::Parse('${{ inputs.dry-run }}') } catch { $DryRun = $true } + + $PackageEnv = if ($IsProductionBranch) { + "publish-prod" + } else { + "publish-test" + } + + if (-Not $IsProductionBranch) { + $DryRun = $true # force dry run when not on main/master branch + } + + if (-Not $SkipPublish -And $PackageEnv -ne 'publish-prod') { + $DryRun = $true # force dry run when publishing outside production environment + } + + $PackageVersion = '${{ inputs.version }}' + if ([string]::IsNullOrWhiteSpace($PackageVersion)) { + throw "The workflow_dispatch version input is required." + } + + echo "package-env=$PackageEnv" >> $Env:GITHUB_OUTPUT + $OneDriveVersion = "$PackageVersion.0" + + echo "package-version=$PackageVersion" >> $Env:GITHUB_OUTPUT + echo "onedrive-version=$OneDriveVersion" >> $Env:GITHUB_OUTPUT + echo "draft-release=$($DraftRelease.ToString().ToLower())" >> $Env:GITHUB_OUTPUT + echo "skip-publish=$($SkipPublish.ToString().ToLower())" >> $Env:GITHUB_OUTPUT + echo "dry-run=$($DryRun.ToString().ToLower())" >> $Env:GITHUB_OUTPUT + + echo "::notice::Environment: $PackageEnv" + echo "::notice::Version: $PackageVersion" + echo "::notice::DraftRelease: $DraftRelease" + echo "::notice::DryRun: $DryRun" + + build: + name: Build & Sign (${{ matrix.platform }}) + runs-on: windows-latest + needs: [preflight] + environment: ${{ needs.preflight.outputs.package-env }} + permissions: + contents: read + env: + UNIGETUI_GITHUB_CLIENT_ID: ${{ secrets.UNIGETUI_GITHUB_CLIENT_ID }} + UNIGETUI_GITHUB_CLIENT_SECRET: ${{ secrets.UNIGETUI_GITHUB_CLIENT_SECRET }} + UNIGETUI_OPENSEARCH_USERNAME: ${{ secrets.UNIGETUI_OPENSEARCH_USERNAME }} + UNIGETUI_OPENSEARCH_PASSWORD: ${{ secrets.UNIGETUI_OPENSEARCH_PASSWORD }} + NUGET_PACKAGES: ${{ github.workspace }}\.nuget\packages + strategy: + fail-fast: false + matrix: + platform: [x64, arm64] + + steps: + - name: Checkout + uses: actions/checkout@v7 + + - name: Validate GitHub OAuth secrets + shell: pwsh + run: | + if ([string]::IsNullOrWhiteSpace($env:UNIGETUI_GITHUB_CLIENT_ID)) { + throw "UNIGETUI_GITHUB_CLIENT_ID is not configured for this build environment." + } + + if ([string]::IsNullOrWhiteSpace($env:UNIGETUI_GITHUB_CLIENT_SECRET)) { + throw "UNIGETUI_GITHUB_CLIENT_SECRET is not configured for this build environment." + } + + Write-Host "::notice::GitHub OAuth secrets are configured for this build." + + - name: Install .NET + uses: actions/setup-dotnet@v5 + with: + global-json-file: global.json + + - name: Cache NuGet packages + uses: actions/cache@v6 + with: + path: ${{ env.NUGET_PACKAGES }} + key: ${{ runner.os }}-nuget-${{ hashFiles('global.json', 'src/**/*.csproj', 'src/**/*.props', 'src/**/*.targets', 'src/**/*.sln', 'src/**/*.slnx') }} + restore-keys: | + ${{ runner.os }}-nuget- + + - name: Install Python + uses: actions/setup-python@v6 + with: + python-version: '3.x' + + - name: Install Inno Setup + shell: pwsh + run: | + choco install innosetup -y --no-progress + echo "C:\Program Files (x86)\Inno Setup 6" >> $Env:GITHUB_PATH + + - name: Install code-signing tools + shell: pwsh + run: | + dotnet tool install --global AzureSignTool + Install-Module -Name Devolutions.Authenticode -Force + + # Trust test code-signing CA + $TestCertsUrl = "https://raw.githubusercontent.com/Devolutions/devolutions-authenticode/master/data/certs" + Invoke-WebRequest -Uri "$TestCertsUrl/authenticode-test-ca.crt" -OutFile ".\authenticode-test-ca.crt" + Import-Certificate -FilePath ".\authenticode-test-ca.crt" -CertStoreLocation "cert:\LocalMachine\Root" + Remove-Item ".\authenticode-test-ca.crt" -ErrorAction SilentlyContinue | Out-Null + + - name: Set version + shell: pwsh + run: | + $PackageVersion = '${{ needs.preflight.outputs.package-version }}' + .\scripts\set-version.ps1 -Version $PackageVersion + + - name: Restore dependencies + working-directory: src + run: dotnet restore UniGetUI.Windows.slnx + + - name: Run tests + working-directory: src + shell: pwsh + run: | + dotnet build-server shutdown + # Retry once to handle flaky tests (e.g. TaskRecyclerTests uses Random) + dotnet test UniGetUI.Windows.slnx --no-restore --verbosity q --nologo /p:Platform=x64 /p:UseSharedCompilation=false /m:1 + if ($LASTEXITCODE -ne 0) { + Write-Host "::warning::First test run failed, retrying..." + dotnet build-server shutdown + dotnet test UniGetUI.Windows.slnx --no-restore --verbosity q --nologo /p:Platform=x64 /p:UseSharedCompilation=false /m:1 + if ($LASTEXITCODE -ne 0) { exit 1 } + } + + - name: Publish + shell: pwsh + run: | + $Platform = '${{ matrix.platform }}' + $TargetFramework = ( + dotnet msbuild src/UniGetUI.Avalonia/UniGetUI.Avalonia.csproj ` + /nologo ` + -getProperty:TargetFramework ` + /p:Configuration=Release ` + /p:Platform=$Platform ` + /p:RuntimeIdentifier=win-$Platform | + Select-Object -Last 1 + ).Trim() + + if ([string]::IsNullOrWhiteSpace($TargetFramework)) { + throw "Could not resolve the Avalonia target framework from MSBuild" + } + + dotnet publish src/UniGetUI.Avalonia/UniGetUI.Avalonia.csproj ` + /noLogo ` + /p:Configuration=Release ` + /p:Platform=$Platform ` + /p:RuntimeIdentifier=win-$Platform ` + /p:PublishProfile=Win-$Platform-NativeAot ` + /p:UseSharedCompilation=false ` + /p:BuildInParallel=false ` + /m:1 ` + -v m + if ($LASTEXITCODE -ne 0) { throw "dotnet publish Avalonia failed" } + + # Stage binaries + $PublishDir = "src/UniGetUI.Avalonia/bin/$Platform/Release/$TargetFramework/win-$Platform/publish" + if (Test-Path "unigetui_bin") { Remove-Item "unigetui_bin" -Recurse -Force } + New-Item "unigetui_bin" -ItemType Directory | Out-Null + Get-ChildItem $PublishDir | Move-Item -Destination "unigetui_bin" -Force + + if (-not (Test-Path "unigetui_bin/UniGetUI.exe")) { + throw "Windows app host was not produced at unigetui_bin/UniGetUI.exe" + } + + $MaxShippedPdbSizeBytes = 1MB + $PdbsToRemove = Get-ChildItem "unigetui_bin" -Filter "*.pdb" -File -Recurse | Where-Object { + $_.Length -gt $MaxShippedPdbSizeBytes + } + + if ($PdbsToRemove.Count -gt 0) { + $RemovedPdbBytes = ($PdbsToRemove | Measure-Object -Property Length -Sum).Sum + $PdbsToRemove | Remove-Item -Force + Write-Host ("Removed {0} oversized PDBs above {1:N2} MiB ({2:N2} MiB total)." -f $PdbsToRemove.Count, ($MaxShippedPdbSizeBytes / 1MB), ($RemovedPdbBytes / 1MB)) + } + + - name: Code-sign binaries + if: ${{ fromJSON(needs.preflight.outputs.dry-run) == false }} + shell: pwsh + run: | + $ListPath = Join-Path $PWD "signing-files.txt" + $files = Get-ChildItem "unigetui_bin" -Recurse -Include "*.exe", "*.dll" | Where-Object { + (Get-AuthenticodeSignature $_.FullName).Status -eq "NotSigned" + } + $files.FullName | Set-Content $ListPath + Write-Host "Signing list contains $($files.Count) files." + + .\scripts\sign.ps1 ` + -FileListPath $ListPath ` + -AzureTenantId '${{ secrets.AZURE_TENANT_ID }}' ` + -KeyVaultUrl '${{ secrets.CODE_SIGNING_KEYVAULT_URL }}' ` + -ClientId '${{ secrets.CODE_SIGNING_CLIENT_ID }}' ` + -ClientSecret '${{ secrets.CODE_SIGNING_CLIENT_SECRET }}' ` + -CertificateName '${{ secrets.CODE_SIGNING_CERTIFICATE_NAME }}' ` + -TimestampServer '${{ vars.CODE_SIGNING_TIMESTAMP_SERVER }}' + + - name: Build installer + shell: pwsh + run: | + $Platform = '${{ matrix.platform }}' + $OutputDir = Join-Path $PWD "output" + New-Item $OutputDir -ItemType Directory -ErrorAction SilentlyContinue | Out-Null + + .\scripts\refresh-integrity-tree.ps1 -Path $PWD/unigetui_bin -FailOnUnexpectedFiles + + # Configure Inno Setup to use AzureSignTool + $IssPath = "UniGetUI.iss" + + # Build the installer (signing of the installer itself happens in the next step) + # Temporarily remove SignTool line so ISCC doesn't try to sign during build + $issContent = Get-Content $IssPath -Raw + + try { + $issContentNoSign = $issContent -Replace '(?m)^SignTool=.*$', '; SignTool=azsign (disabled for CI, signed separately)' + $issContentNoSign = $issContentNoSign -Replace '(?m)^SignedUninstaller=yes', 'SignedUninstaller=no' + Set-Content $IssPath $issContentNoSign -NoNewline + + $InstallerBaseName = "UniGetUI.Installer.$Platform" + $IsccArgs = @($IssPath, "/F$InstallerBaseName", "/O$OutputDir") + if ([System.Boolean]::Parse('${{ needs.preflight.outputs.dry-run }}') -eq $false) { + Write-Host "Using lzma/ultra64 installer compression for release build." + $IsccArgs = @('/DInstallerCompression=lzma/ultra64') + $IsccArgs + } + + & ISCC.exe @IsccArgs + if ($LASTEXITCODE -ne 0) { throw "Inno Setup failed with exit code $LASTEXITCODE" } + } + finally { + Set-Content $IssPath $issContent -NoNewline + } + + - name: Stage output + shell: pwsh + run: | + $Platform = '${{ matrix.platform }}' + New-Item "output" -ItemType Directory -ErrorAction SilentlyContinue | Out-Null + + .\scripts\refresh-integrity-tree.ps1 -Path $PWD/unigetui_bin -FailOnUnexpectedFiles + + # Zip + Compress-Archive -Path "unigetui_bin/*" -DestinationPath "output/UniGetUI.$Platform.zip" -CompressionLevel Optimal + + # Installer is created in output during the previous step + + - name: Capture artifact sizes + shell: pwsh + run: | + $Platform = '${{ matrix.platform }}' + $SizesFile = "output/sizes.$Platform.json" + $UncompressedSize = (Get-ChildItem "unigetui_bin" -Recurse -File | Measure-Object -Property Length -Sum).Sum + $Artifacts = Get-ChildItem "output" -File | Where-Object { $_.Name -ne "sizes.$Platform.json" } | ForEach-Object { + @{ Name = $_.Name; SizeBytes = $_.Length } + } + $Report = @{ + Platform = $Platform + RuntimeIdentifier = "win-$Platform" + UncompressedSizeBytes = $UncompressedSize + Artifacts = $Artifacts + Timestamp = [DateTimeOffset]::UtcNow.ToString("o") + } + $Report | ConvertTo-Json -Depth 4 | Set-Content $SizesFile -Encoding UTF8 + Write-Host "Artifact sizes saved to $SizesFile" + Get-Content $SizesFile + + - name: Code-sign installer + if: ${{ fromJSON(needs.preflight.outputs.dry-run) == false }} + shell: pwsh + run: | + $Platform = '${{ matrix.platform }}' + .\scripts\sign.ps1 ` + -InstallerPath "output/UniGetUI.Installer.$Platform.exe" ` + -AzureTenantId '${{ secrets.AZURE_TENANT_ID }}' ` + -KeyVaultUrl '${{ secrets.CODE_SIGNING_KEYVAULT_URL }}' ` + -ClientId '${{ secrets.CODE_SIGNING_CLIENT_ID }}' ` + -ClientSecret '${{ secrets.CODE_SIGNING_CLIENT_SECRET }}' ` + -CertificateName '${{ secrets.CODE_SIGNING_CERTIFICATE_NAME }}' ` + -TimestampServer '${{ vars.CODE_SIGNING_TIMESTAMP_SERVER }}' + + - name: Upload artifacts + uses: actions/upload-artifact@v7 + with: + name: UniGetUI-release-${{ matrix.platform }} + path: output/* + + - name: Cleanup + if: always() + shell: pwsh + run: | + Remove-Item "unigetui_bin" -Recurse -Force -ErrorAction SilentlyContinue + + build-avalonia: + name: Build (${{ matrix.name }}) + runs-on: ${{ matrix.os }} + needs: [preflight] + environment: ${{ needs.preflight.outputs.package-env }} + permissions: + contents: read + env: + UNIGETUI_GITHUB_CLIENT_ID: ${{ secrets.UNIGETUI_GITHUB_CLIENT_ID }} + UNIGETUI_GITHUB_CLIENT_SECRET: ${{ secrets.UNIGETUI_GITHUB_CLIENT_SECRET }} + UNIGETUI_OPENSEARCH_USERNAME: ${{ secrets.UNIGETUI_OPENSEARCH_USERNAME }} + UNIGETUI_OPENSEARCH_PASSWORD: ${{ secrets.UNIGETUI_OPENSEARCH_PASSWORD }} + NUGET_PACKAGES: ${{ github.workspace }}/.nuget/packages + SIGNING_IDENTITY: 'Developer ID Application: Devolutions inc.' + strategy: + fail-fast: false + matrix: + include: + - os: macos-latest + name: macos-arm64 + runtime: osx-arm64 + publish_profile: osx-arm64-NativeAot + - os: macos-latest + name: macos-x64 + runtime: osx-x64 + publish_profile: osx-x64-NativeAot + - os: ubuntu-latest + name: linux-x64 + runtime: linux-x64 + publish_profile: linux-x64-NativeAot + - os: ubuntu-latest + name: linux-arm64 + runtime: linux-arm64 + publish_profile: linux-arm64-NativeAot + + steps: + - name: Checkout + uses: actions/checkout@v7 + + - name: Install .NET + uses: actions/setup-dotnet@v5 + with: + global-json-file: global.json + + - name: Cache NuGet packages + uses: actions/cache@v6 + with: + path: ${{ env.NUGET_PACKAGES }} + key: ${{ runner.os }}-nuget-${{ hashFiles('global.json', 'src/**/*.csproj', 'src/**/*.props', 'src/**/*.targets', 'src/**/*.sln', 'src/**/*.slnx') }} + restore-keys: | + ${{ runner.os }}-nuget- + + - name: Install Linux arm64 NativeAOT toolchain + if: matrix.runtime == 'linux-arm64' + shell: bash + run: | + set -euo pipefail + + . /etc/os-release + sudo dpkg --add-architecture arm64 + + # Keep the runner's default Ubuntu feeds bound to amd64, then add the + # Ubuntu Ports arm64 feed that provides the target CRT and zlib objects. + if compgen -G "/etc/apt/sources.list.d/*.sources" > /dev/null; then + for source in /etc/apt/sources.list.d/*.sources; do + if ! grep -q '^Architectures:' "$source"; then + sudo sed -i '/^Types: deb$/a Architectures: amd64' "$source" + fi + done + fi + + if [ -f /etc/apt/sources.list ]; then + sudo sed -i -E '/^deb /s/^deb /deb [arch=amd64] /' /etc/apt/sources.list + fi + + sudo tee /etc/apt/sources.list.d/ubuntu-arm64.sources >/dev/null < "${APP_BUNDLE}/Contents/Info.plist" + # Compile the appearance-aware app icon (Default/Dark/Tinted/Clear) from the Icon Composer + # .icon into the bundle: produces Assets.car + AppIcon.icns. Info.plist already declares + # CFBundleIconName=AppIcon, so macOS renders the appearance styles itself (incl. when closed). + xcrun actool scripts/macos/AppIcon.icon \ + --compile "${APP_BUNDLE}/Contents/Resources" \ + --app-icon AppIcon \ + --output-partial-info-plist "$(mktemp).plist" \ + --platform macosx \ + --minimum-deployment-target 12.0 \ + --errors --warnings + # Static .icns fallback for macOS < 26 (CFBundleIconFile) and the dmg volume icon. + cp scripts/macos/UniGetUI.icns "${APP_BUNDLE}/Contents/Resources/" + + if [ "$DRY_RUN" = "false" ]; then + ENTITLEMENTS="scripts/macos/Entitlements.plist" + find "${APP_BUNDLE}/Contents/MacOS" -type f \! -name "${APP_EXECUTABLE}" -print0 \ + | while IFS= read -r -d '' f; do + codesign --force --timestamp --options runtime \ + --entitlements "$ENTITLEMENTS" \ + --sign "$SIGNING_IDENTITY" "$f" + done + codesign --force --timestamp --options runtime \ + --entitlements "$ENTITLEMENTS" \ + --sign "$SIGNING_IDENTITY" "${APP_BUNDLE}" + codesign --verify --verbose=2 "${APP_BUNDLE}" + else + find "${APP_BUNDLE}/Contents/MacOS" -type f | while IFS= read -r f; do + codesign --force --sign - "$f" 2>/dev/null || true + done + codesign --force --sign - "${APP_BUNDLE}" + fi + + COPYFILE_DISABLE=1 tar -czf "output/UniGetUI.${{ matrix.name }}.tar.gz" "${APP_BUNDLE}" + + create-dmg \ + --volname "UniGetUI" \ + --volicon "scripts/macos/UniGetUI.icns" \ + --window-pos 200 120 \ + --window-size 600 400 \ + --icon-size 128 \ + --icon "UniGetUI.app" 150 185 \ + --hide-extension "UniGetUI.app" \ + --app-drop-link 450 185 \ + "output/UniGetUI.${{ matrix.name }}.dmg" \ + "${APP_BUNDLE}" + + test -f "output/UniGetUI.${{ matrix.name }}.tar.gz" + test -f "output/UniGetUI.${{ matrix.name }}.dmg" + + - name: Sign DMG + if: ${{ runner.os == 'macOS' && fromJSON(needs.preflight.outputs.dry-run) == false }} + run: | + set -euo pipefail + DMG="output/UniGetUI.${{ matrix.name }}.dmg" + codesign --force --timestamp --sign "$SIGNING_IDENTITY" "$DMG" + codesign --verify --verbose=2 "$DMG" + + - name: Notarize DMG + if: ${{ runner.os == 'macOS' && fromJSON(needs.preflight.outputs.dry-run) == false }} + uses: ./.github/workflows/macos-notarize + timeout-minutes: 15 + with: + apple_password: ${{ secrets.APPLE_BOT_PASSWORD }} + package_path: output/UniGetUI.${{ matrix.name }}.dmg + + - name: Install Linux packaging tools + if: runner.os == 'Linux' + run: | + sudo apt-get update + sudo apt-get install -y rpm + + - name: Package (Linux) + if: runner.os == 'Linux' + shell: pwsh + run: | + $Version = '${{ needs.preflight.outputs.package-version }}' + $Parts = $Version -split '-', 2 + $BaseVersion = $Parts[0] + $Prerelease = if ($Parts.Count -gt 1) { $Parts[1] } else { $null } + + # deb: use tilde notation for pre-releases (Ubuntu 18.04+ compatible) + $DebVersion = if ($Prerelease) { "${BaseVersion}~${Prerelease}" } else { $Version } + # rpm: pre-release encoded in Release/Iteration field (RHEL 8+ / RPM 4.14+) + $RpmVersion = $BaseVersion + $RpmIteration = if ($Prerelease) { "0.${Prerelease}" } else { '1' } + + # Map .NET RID -> package arch names + $DebArch, $RpmArch = switch ('${{ matrix.runtime }}') { + 'linux-arm64' { 'arm64', 'aarch64' } + default { 'amd64', 'x86_64' } + } + + New-Item -ItemType Directory -Force -Path output | Out-Null + + # .tar.gz + & tar -czf "output/UniGetUI.${{ matrix.name }}.tar.gz" -C "bin/${{ matrix.name }}" . + if ($LASTEXITCODE -ne 0) { exit 1 } + + # .deb — Ubuntu 18.04+ (glibc 2.27, Debian policy 3.9.6) + & ./scripts/package-linux.ps1 ` + -PackageType deb ` + -SourceDir "bin/${{ matrix.name }}" ` + -OutputPath "output/UniGetUI.${{ matrix.name }}.deb" ` + -Version $DebVersion ` + -Architecture $DebArch + + # .rpm — RHEL 8+ (RPM 4.14, glibc 2.28) + & ./scripts/package-linux.ps1 ` + -PackageType rpm ` + -SourceDir "bin/${{ matrix.name }}" ` + -OutputPath "output/UniGetUI.${{ matrix.name }}.rpm" ` + -Version $RpmVersion ` + -Iteration $RpmIteration ` + -Architecture $RpmArch + + - name: Capture artifact sizes + shell: pwsh + run: | + $Name = '${{ matrix.name }}' + $Runtime = '${{ matrix.runtime }}' + $SizesFile = "output/sizes.$Name.json" + $SourceDir = if ('${{ runner.os }}' -eq 'macOS') { "UniGetUI.app/Contents/MacOS" } else { "bin/$Name" } + $UncompressedSize = (Get-ChildItem $SourceDir -Recurse -File -ErrorAction SilentlyContinue | Measure-Object -Property Length -Sum).Sum + $Artifacts = Get-ChildItem "output" -File -ErrorAction SilentlyContinue | Where-Object { $_.Name -ne "sizes.$Name.json" } | ForEach-Object { + @{ Name = $_.Name; SizeBytes = $_.Length } + } + $Report = @{ + Platform = $Name + RuntimeIdentifier = $Runtime + UncompressedSizeBytes = $UncompressedSize + Artifacts = $Artifacts + Timestamp = [DateTimeOffset]::UtcNow.ToString("o") + } + $Report | ConvertTo-Json -Depth 4 | Set-Content $SizesFile -Encoding UTF8 + Write-Host "Artifact sizes saved to $SizesFile" + Get-Content $SizesFile + + - name: Upload artifacts + uses: actions/upload-artifact@v7 + with: + name: UniGetUI-${{ matrix.name }} + path: output/* + + publish: + name: Publish GitHub Release + runs-on: ubuntu-latest + needs: [preflight, build, build-avalonia] + if: ${{ fromJSON(needs.preflight.outputs.skip-publish) == false }} + environment: ${{ needs.preflight.outputs.package-env }} + permissions: + contents: write + + steps: + - name: Download artifacts + uses: actions/download-artifact@v8 + with: + path: output + + - name: Add legacy installer filename + shell: pwsh + working-directory: output + run: | + $InstallerFiles = Get-ChildItem -Path . -Recurse -File -Filter "UniGetUI.Installer.x64.exe" + if (-not $InstallerFiles) { + throw "Could not find UniGetUI.Installer.x64.exe in downloaded artifacts" + } + + $InstallerFiles | ForEach-Object { + $LegacyInstallerPath = Join-Path $_.DirectoryName "UniGetUI.Installer.exe" + Copy-Item -Path $_.FullName -Destination $LegacyInstallerPath -Force + Write-Host "Created legacy installer alias: $LegacyInstallerPath" + } + + - name: Generate consolidated checksums + shell: pwsh + working-directory: output + run: | + $ChecksumFile = Join-Path $PWD "checksums.txt" + $ChecksumLines = Get-ChildItem -Path . -Recurse -File | Where-Object { + $_.Name -notmatch '^checksums(\..+)?\.txt$' + } | Sort-Object Name | ForEach-Object { + $hash = (Get-FileHash $_.FullName -Algorithm SHA256).Hash + "$hash $($_.Name)" + } + + Set-Content -Path $ChecksumFile -Value $ChecksumLines -Encoding utf8NoBOM + + echo "::group::checksums" + Get-Content $ChecksumFile + echo "::endgroup::" + + - name: Generate consolidated size report + shell: pwsh + working-directory: output + run: | + $SizeFiles = Get-ChildItem -Path . -Recurse -File -Filter "sizes.*.json" | Sort-Object Name + if (-not $SizeFiles) { + Write-Host "No size files found." + return + } + + $Rows = foreach ($file in $SizeFiles) { + $data = Get-Content $file.FullName -Raw | ConvertFrom-Json + $uncompressedMiB = [math]::Round($data.UncompressedSizeBytes / 1MB, 2) + foreach ($artifact in $data.Artifacts) { + [PSCustomObject]@{ + Platform = $data.Platform + RID = $data.RuntimeIdentifier + Artifact = $artifact.Name + CompressedMiB = [math]::Round($artifact.SizeBytes / 1MB, 2) + UncompressedMiB = $uncompressedMiB + } + } + } + + $SizeReportFile = Join-Path $PWD "sizes.md" + $Lines = @("# UniGetUI Release Artifact Sizes", "") + $Lines += $Rows | Format-Table -AutoSize | Out-String -Stream | Where-Object { $_.Trim() -ne '' } + Set-Content -Path $SizeReportFile -Value $Lines -Encoding utf8NoBOM + + echo "::group::sizes" + Get-Content $SizeReportFile + echo "::endgroup::" + + - name: Create GitHub Release + shell: pwsh + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + working-directory: output + run: | + $PackageVersion = '${{ needs.preflight.outputs.package-version }}' + $DraftRelease = [System.Boolean]::Parse('${{ needs.preflight.outputs.draft-release }}') + $DryRun = [System.Boolean]::Parse('${{ needs.preflight.outputs.dry-run }}') + + echo "::group::checksums" + Get-Content "./checksums.txt" + echo "::endgroup::" + + $ReleaseTag = "v$PackageVersion" + $ReleaseTitle = "UniGetUI v${PackageVersion}" + $Repository = $Env:GITHUB_REPOSITORY + $DraftArg = if ($DraftRelease) { '--draft' } else { $null } + + $Files = Get-ChildItem -Path . -Recurse -File | Where-Object { + $_.Name -eq 'checksums.txt' -or $_.Name -notmatch '^checksums\..+\.txt$' + } + + if ($DryRun) { + Write-Host "Dry Run: skipping GitHub release creation!" + Write-Host "Would create release $ReleaseTag with title '$ReleaseTitle' (draft=$DraftRelease)" + $Files | ForEach-Object { Write-Host " - $($_.FullName)" } + } else { + if ($DraftArg) { + & gh release create $ReleaseTag --repo $Repository --title $ReleaseTitle $DraftArg $Files.FullName + } else { + & gh release create $ReleaseTag --repo $Repository --title $ReleaseTitle $Files.FullName + } + } + + - name: Check out Devolutions/actions + if: ${{ fromJSON(needs.preflight.outputs.dry-run) == false }} + uses: actions/checkout@v7 + with: + repository: Devolutions/actions + ref: v1 + token: ${{ secrets.DEVOLUTIONSBOT_TOKEN }} + path: ./.github/workflows + + - name: Install Devolutions Toolbox + if: ${{ fromJSON(needs.preflight.outputs.dry-run) == false }} + uses: ./.github/workflows/toolbox-install + with: + github_token: ${{ secrets.DEVOLUTIONSBOT_TOKEN }} + + - name: Stage files for OneDrive upload + if: ${{ fromJSON(needs.preflight.outputs.dry-run) == false }} + shell: pwsh + run: | + $PackageVersion = '${{ needs.preflight.outputs.package-version }}' + New-Item -Path "onedrive-staging" -ItemType Directory -Force | Out-Null + + $OneDriveVersion = '${{ needs.preflight.outputs.onedrive-version }}' + + $Mappings = @{ + "output/UniGetUI-release-x64/UniGetUI.Installer.x64.exe" = "Devolutions.UniGetUI.win-x64.$OneDriveVersion.exe" + "output/UniGetUI-release-arm64/UniGetUI.Installer.arm64.exe" = "Devolutions.UniGetUI.win-arm64.$OneDriveVersion.exe" + "output/UniGetUI-release-x64/UniGetUI.x64.zip" = "Devolutions.UniGetUI.win-x64.$OneDriveVersion.zip" + "output/UniGetUI-release-arm64/UniGetUI.arm64.zip" = "Devolutions.UniGetUI.win-arm64.$OneDriveVersion.zip" + "output/UniGetUI-macos-x64/UniGetUI.macos-x64.dmg" = "Devolutions.UniGetUI.macos-x64.$OneDriveVersion.dmg" + "output/UniGetUI-macos-arm64/UniGetUI.macos-arm64.dmg" = "Devolutions.UniGetUI.macos-arm64.$OneDriveVersion.dmg" + "output/UniGetUI-macos-x64/UniGetUI.macos-x64.tar.gz" = "Devolutions.UniGetUI.macos-x64.$OneDriveVersion.tar.gz" + "output/UniGetUI-macos-arm64/UniGetUI.macos-arm64.tar.gz" = "Devolutions.UniGetUI.macos-arm64.$OneDriveVersion.tar.gz" + "output/UniGetUI-linux-x64/UniGetUI.linux-x64.deb" = "Devolutions.UniGetUI.linux-x64.$OneDriveVersion.deb" + "output/UniGetUI-linux-arm64/UniGetUI.linux-arm64.deb" = "Devolutions.UniGetUI.linux-arm64.$OneDriveVersion.deb" + "output/UniGetUI-linux-x64/UniGetUI.linux-x64.rpm" = "Devolutions.UniGetUI.linux-x64.$OneDriveVersion.rpm" + "output/UniGetUI-linux-arm64/UniGetUI.linux-arm64.rpm" = "Devolutions.UniGetUI.linux-arm64.$OneDriveVersion.rpm" + "output/UniGetUI-linux-x64/UniGetUI.linux-x64.tar.gz" = "Devolutions.UniGetUI.linux-x64.$OneDriveVersion.tar.gz" + "output/UniGetUI-linux-arm64/UniGetUI.linux-arm64.tar.gz" = "Devolutions.UniGetUI.linux-arm64.$OneDriveVersion.tar.gz" + } + + foreach ($entry in $Mappings.GetEnumerator()) { + if (-not (Test-Path $entry.Key)) { + throw "File not found: $($entry.Key)" + } + Copy-Item -Path $entry.Key -Destination "onedrive-staging/$($entry.Value)" + Write-Host "Staged: $($entry.Key) -> $($entry.Value)" + } + + - name: Upload to OneDrive + if: ${{ fromJSON(needs.preflight.outputs.dry-run) == false }} + uses: ./.github/workflows/onedrive-upload + with: + azure_client_id: ${{ secrets.ONEDRIVE_AUTOMATION_CLIENT_ID }} + azure_client_secret: ${{ secrets.ONEDRIVE_AUTOMATION_CLIENT_SECRET }} + conflict_behavior: replace + destination_path: /UniGetUI/${{ needs.preflight.outputs.onedrive-version }} + remote: releases + source_path: Devolutions.UniGetUI.* + working_directory: onedrive-staging + + size-report: + name: Consolidated Size Report + runs-on: ubuntu-latest + needs: [preflight, build, build-avalonia] + if: always() && needs.build.result != 'cancelled' && needs.build-avalonia.result != 'cancelled' + + steps: + - name: Download artifacts + uses: actions/download-artifact@v8 + with: + path: output + + - name: Generate consolidated size report + shell: pwsh + working-directory: output + run: | + $SizeFiles = Get-ChildItem -Path . -Recurse -File -Filter "sizes.*.json" | Sort-Object Name + if (-not $SizeFiles) { + Write-Host "No size files found." + return + } + + $Rows = foreach ($file in $SizeFiles) { + $data = Get-Content $file.FullName -Raw | ConvertFrom-Json + $uncompressedMiB = [math]::Round($data.UncompressedSizeBytes / 1MB, 2) + foreach ($artifact in $data.Artifacts) { + [PSCustomObject]@{ + Platform = $data.Platform + RID = $data.RuntimeIdentifier + Artifact = $artifact.Name + CompressedMiB = [math]::Round($artifact.SizeBytes / 1MB, 2) + UncompressedMiB = $uncompressedMiB + } + } + } + + $SizeReportFile = Join-Path $PWD "sizes.md" + $Lines = @("# UniGetUI Release Artifact Sizes", "") + $Lines += $Rows | Format-Table -AutoSize | Out-String -Stream | Where-Object { $_.Trim() -ne '' } + Set-Content -Path $SizeReportFile -Value $Lines -Encoding utf8NoBOM + + echo "::group::sizes" + Get-Content $SizeReportFile + echo "::endgroup::" + + - name: Upload size report + uses: actions/upload-artifact@v7 + with: + name: UniGetUI-size-report + path: output/sizes.md diff --git a/.github/workflows/cli-headless-e2e.yml b/.github/workflows/cli-headless-e2e.yml new file mode 100644 index 0000000..8ac9959 --- /dev/null +++ b/.github/workflows/cli-headless-e2e.yml @@ -0,0 +1,179 @@ +name: CLI Headless E2E + +on: + pull_request: + branches: [ "main" ] + paths: + - 'src/**/*.cs' + - 'src/**/*.csproj' + - 'src/**/*.props' + - 'src/**/*.targets' + - 'src/**/*.sln' + - 'src/**/*.slnx' + - 'testing/automation/**' + - '.github/workflows/cli-headless-e2e.yml' + - 'global.json' + workflow_dispatch: + +jobs: + cli-headless-e2e: + strategy: + fail-fast: false + matrix: + include: + - name: Windows (Avalonia) + os: windows-latest + solution: UniGetUI.Windows.slnx + daemon_project: UniGetUI.Avalonia/UniGetUI.Avalonia.csproj + daemon_build_args: '-p:Platform=x64' + manifest: testing/automation/cli-e2e.manifest.windows.json + - name: Windows (NativeAOT) + os: windows-latest + solution: UniGetUI.Windows.slnx + daemon_project: UniGetUI.Avalonia/UniGetUI.Avalonia.csproj + daemon_publish_profile: Win-x64-NativeAot + daemon_build_args: '-p:Platform=x64' + manifest: testing/automation/cli-e2e.manifest.windows.json + - name: Linux (Avalonia) + os: ubuntu-latest + solution: UniGetUI.Avalonia.slnx + daemon_project: UniGetUI.Avalonia/UniGetUI.Avalonia.csproj + daemon_build_args: '' + manifest: testing/automation/cli-e2e.manifest.linux.json + - name: Linux (NativeAOT) + os: ubuntu-latest + solution: UniGetUI.Avalonia.slnx + daemon_project: UniGetUI.Avalonia/UniGetUI.Avalonia.csproj + daemon_publish_profile: linux-x64-NativeAot + daemon_build_args: '' + manifest: testing/automation/cli-e2e.manifest.linux-nativeaot.json + + name: ${{ matrix.name }} + runs-on: ${{ matrix.os }} + env: + CONFIGURATION: Release + NUGET_PACKAGES: ${{ github.workspace }}/.nuget/packages + + steps: + - name: Checkout repository + uses: actions/checkout@v7 + + - name: Setup .NET SDK + uses: actions/setup-dotnet@v5 + with: + global-json-file: global.json + + - name: Setup Python + uses: actions/setup-python@v6 + with: + python-version: '3.12' + + - name: Setup Node.js + uses: actions/setup-node@v6 + with: + node-version: '24' + + - name: Cache NuGet packages + uses: actions/cache@v6 + with: + path: ${{ env.NUGET_PACKAGES }} + key: ${{ runner.os }}-nuget-e2e-${{ hashFiles('global.json', 'src/**/*.csproj', 'src/**/*.props', 'src/**/*.targets', 'src/**/*.sln', 'src/**/*.slnx') }} + restore-keys: | + ${{ runner.os }}-nuget-e2e- + + - name: Restore solution + working-directory: src + shell: pwsh + run: dotnet restore ${{ matrix.solution }} + + - name: Build headless daemon + working-directory: src + shell: pwsh + run: | + $PublishProfile = '${{ matrix.daemon_publish_profile }}' + $BuildArgs = '${{ matrix.daemon_build_args }}' + + dotnet build-server shutdown + + if ($PublishProfile) { + $RuntimeIdentifier = $PublishProfile -replace '-NativeAot$', '' -replace '^Win-', 'win-' -replace '^linux-', 'linux-' -replace '^osx-', 'osx-' + $OutputPath = Join-Path (Resolve-Path '..') "artifacts/e2e-nativeaot/$RuntimeIdentifier" + New-Item -ItemType Directory -Force -Path $OutputPath | Out-Null + + $args = @( + 'publish', + '${{ matrix.daemon_project }}', + '--no-restore', + '--configuration', + '${{ env.CONFIGURATION }}', + '--runtime', + $RuntimeIdentifier, + '--self-contained', + 'true', + '--output', + $OutputPath, + '--verbosity', + 'minimal', + '/p:UseSharedCompilation=false', + '/m:1', + "/p:PublishProfile=$PublishProfile" + ) + if ($BuildArgs) { + $args += $BuildArgs + } + dotnet @args + + $exeName = if ('${{ runner.os }}' -eq 'Windows') { 'UniGetUI.exe' } else { 'UniGetUI' } + $daemonExe = Join-Path $OutputPath $exeName + if (-not (Test-Path $daemonExe)) { + throw "NativeAOT daemon executable was not produced at $daemonExe" + } + if ('${{ runner.os }}' -ne 'Windows') { + chmod +x $daemonExe + } + echo "UNIGETUI_DAEMON_EXE=$daemonExe" >> $Env:GITHUB_ENV + } + else { + $args = @( + 'build', + '${{ matrix.daemon_project }}', + '--no-restore', + '--configuration', + '${{ env.CONFIGURATION }}', + '--verbosity', + 'minimal', + '/p:UseSharedCompilation=false', + '/m:1' + ) + if ($BuildArgs) { + $args += $BuildArgs + } + dotnet @args + } + + - name: Upgrade pip tooling + shell: pwsh + run: python -m pip install --upgrade pip setuptools wheel + + - name: Show package-manager inventory + shell: pwsh + run: | + dotnet --version + python --version + python -m pip --version + npm --version + + - name: Run headless CLI E2E + shell: pwsh + env: + UNIGETUI_CLI_E2E_MANIFEST: ${{ matrix.manifest }} + UNIGETUI_CLI_E2E_ARTIFACTS: ${{ github.workspace }}/artifacts/cli-headless-e2e/${{ runner.os }} + run: ./testing/automation/run-cli-e2e.ps1 + + - name: Upload CLI E2E artifacts + if: always() + uses: actions/upload-artifact@v7 + with: + name: cli-headless-e2e-${{ matrix.name }} + path: artifacts/cli-headless-e2e/${{ runner.os }} + if-no-files-found: warn diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml new file mode 100644 index 0000000..7fcaf32 --- /dev/null +++ b/.github/workflows/codeql.yml @@ -0,0 +1,90 @@ +# For most projects, this workflow file will not need changing; you simply need +# to commit it to your repository. +# +# You may wish to alter this file to override the set of languages analyzed, +# or to provide custom queries or build logic. +# +# ******** NOTE ******** +# We have attempted to detect the languages in your repository. Please check +# the `language` matrix defined below to confirm you have the correct set of +# supported CodeQL languages. +# +name: "CodeQL" + +on: + schedule: + - cron: '0 0 * * 1' + workflow_dispatch: + +jobs: + analyze: + name: Analyze (${{ matrix.language }}) + # Runner size impacts CodeQL analysis time. To learn more, please see: + # - https://gh.io/recommended-hardware-resources-for-running-codeql + # - https://gh.io/supported-runners-and-hardware-resources + # - https://gh.io/using-larger-runners (GitHub.com only) + # Consider using larger runners or machines with greater resources for possible analysis time improvements. + runs-on: ${{ (matrix.language == 'swift' && 'macos-latest') || 'ubuntu-latest' }} + timeout-minutes: ${{ (matrix.language == 'swift' && 120) || 360 }} + permissions: + # required for all workflows + security-events: write + + # required to fetch internal or private CodeQL packs + packages: read + + # only required for workflows in private repositories + actions: read + contents: read + + strategy: + fail-fast: false + matrix: + include: + - language: csharp + build-mode: none + # CodeQL supports the following values keywords for 'language': 'c-cpp', 'csharp', 'go', 'java-kotlin', 'javascript-typescript', 'python', 'ruby', 'swift' + # Use `c-cpp` to analyze code written in C, C++ or both + # Use 'java-kotlin' to analyze code written in Java, Kotlin or both + # Use 'javascript-typescript' to analyze code written in JavaScript, TypeScript or both + # To learn more about changing the languages that are analyzed or customizing the build mode for your analysis, + # see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/customizing-your-advanced-setup-for-code-scanning. + # If you are analyzing a compiled language, you can modify the 'build-mode' for that language to customize how + # your codebase is analyzed, see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/codeql-code-scanning-for-compiled-languages + steps: + - name: Checkout repository + uses: actions/checkout@v7 + + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@v4 + with: + languages: ${{ matrix.language }} + build-mode: ${{ matrix.build-mode }} + # If you wish to specify custom queries, you can do so here or in a config file. + # By default, queries listed here will override any specified in a config file. + # Prefix the list here with "+" to use these queries and those in the config file. + + # For more details on CodeQL's query packs, refer to: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs + # queries: security-extended,security-and-quality + + # If the analyze step fails for one of the languages you are analyzing with + # "We were unable to automatically build your code", modify the matrix above + # to set the build mode to "manual" for that language. Then modify this step + # to build your code. + # ℹ️ Command-line programs to run using the OS shell. + # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun + - if: matrix.build-mode == 'manual' + shell: bash + run: | + echo 'If you are using a "manual" build mode for one or more of the' \ + 'languages you are analyzing, replace this with the commands to build' \ + 'your code, for example:' + echo ' make bootstrap' + echo ' make release' + exit 1 + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v4 + with: + category: "/language:${{matrix.language}}" diff --git a/.github/workflows/dotnet-test.yml b/.github/workflows/dotnet-test.yml new file mode 100644 index 0000000..58cea35 --- /dev/null +++ b/.github/workflows/dotnet-test.yml @@ -0,0 +1,115 @@ +name: .NET Tests +on: + push: + branches: [ "main" ] + paths: + - 'global.json' + - '**.cs' + - '**.axaml' + - '**.csproj' + - '**.props' + - '**.targets' + - '**.sln' + - '**.slnx' + - 'src/.editorconfig' + - '.github/workflows/dotnet-test.yml' + + pull_request: + branches: [ "main" ] + paths: + - 'global.json' + - '**.cs' + - '**.axaml' + - '**.csproj' + - '**.props' + - '**.targets' + - '**.sln' + - '**.slnx' + - 'src/.editorconfig' + - '.github/workflows/dotnet-test.yml' + + workflow_dispatch: + +jobs: + test-codebase: + runs-on: windows-latest + env: + NUGET_PACKAGES: ${{ github.workspace }}\.nuget\packages + + steps: + - name: Checkout the repository + uses: actions/checkout@v7 + with: + fetch-depth: 0 + + - name: Install .NET SDK + uses: actions/setup-dotnet@v5 + with: + global-json-file: global.json + + - name: Cache NuGet packages + uses: actions/cache@v6 + with: + path: ${{ env.NUGET_PACKAGES }} + key: ${{ runner.os }}-nuget-${{ hashFiles('global.json', 'src/**/*.csproj', 'src/**/*.props', 'src/**/*.targets', 'src/**/*.sln', 'src/**/*.slnx') }} + restore-keys: | + ${{ runner.os }}-nuget- + + - name: Install dependencies + working-directory: src + run: dotnet restore UniGetUI.Windows.slnx + + - name: Check whitespace formatting + run: dotnet format whitespace src --folder --verify-no-changes --verbosity minimal + + - name: Check code style formatting (Avalonia Windows solution) + working-directory: src + run: dotnet format style UniGetUI.Windows.slnx --no-restore --verify-no-changes --verbosity minimal + + - name: Build Avalonia Windows solution + working-directory: src + run: | + dotnet build-server shutdown + dotnet build UniGetUI.Windows.slnx --no-restore --verbosity minimal /p:Platform=x64 /p:UseSharedCompilation=false /m:1 + + - name: Run Tests + working-directory: src + env: + GITHUB_TOKEN: ${{ github.token }} + run: dotnet test UniGetUI.Windows.slnx --no-restore --verbosity q --nologo /p:Platform=x64 /p:UseSharedCompilation=false /m:1 + + - name: Report full-trim publish warnings + working-directory: src + shell: pwsh + continue-on-error: true + run: | + dotnet build-server shutdown + dotnet publish UniGetUI.Avalonia/UniGetUI.Avalonia.csproj ` + --no-restore ` + --configuration Release ` + --runtime win-x64 ` + --self-contained true ` + --output "${{ runner.temp }}\unigetui-full-trim-publish" ` + /p:Platform=x64 ` + /p:TrimMode=full ` + /p:TrimmerSingleWarn=false ` + /p:UseSharedCompilation=false ` + --verbosity minimal + + - name: Report NativeAOT publish warnings + working-directory: src + shell: pwsh + run: | + dotnet build-server shutdown + dotnet publish UniGetUI.Avalonia/UniGetUI.Avalonia.csproj ` + --no-restore ` + --configuration Release ` + --runtime win-x64 ` + --self-contained true ` + --output "${{ runner.temp }}\unigetui-nativeaot-publish" ` + /m:1 ` + /p:Platform=x64 ` + /p:PublishProfile=Win-x64-NativeAot ` + /p:TrimmerSingleWarn=false ` + /p:UseSharedCompilation=false ` + --verbosity minimal diff --git a/.github/workflows/translation-validation.yml b/.github/workflows/translation-validation.yml new file mode 100644 index 0000000..8bbf36e --- /dev/null +++ b/.github/workflows/translation-validation.yml @@ -0,0 +1,44 @@ +name: Translation Validation + +on: + push: + branches: [ "main" ] + paths: + - 'scripts/translation/**' + - '.agents/skills/translation-*/scripts/**' + - 'src/Languages/**' + - 'src/Languages/Data/LanguagesReference.json' + - 'src/Languages/Data/TranslatedPercentages.json' + - 'src/Languages/Data/Translators.json' + - 'src/UniGetUI.Core.Data/Assets/Data/Contributors.list' + - '.github/workflows/translation-validation.yml' + + pull_request: + branches: [ "main" ] + paths: + - 'scripts/translation/**' + - '.agents/skills/translation-*/scripts/**' + - 'src/Languages/**' + - 'src/Languages/Data/LanguagesReference.json' + - 'src/Languages/Data/TranslatedPercentages.json' + - 'src/Languages/Data/Translators.json' + - 'src/UniGetUI.Core.Data/Assets/Data/Contributors.list' + - '.github/workflows/translation-validation.yml' + + workflow_dispatch: + +jobs: + validate-translations: + runs-on: windows-latest + + steps: + - name: Checkout the repository + uses: actions/checkout@v7 + + - name: Validate translation file structure + shell: pwsh + run: pwsh ./scripts/translation/Verify-Translations.ps1 + + - name: Validate boundary alignment + shell: pwsh + run: pwsh ./scripts/translation/Set-TranslationBoundaryOrder.ps1 -CheckOnly diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ee7a943 --- /dev/null +++ b/.gitignore @@ -0,0 +1,99 @@ +/.vscode/ +src/.vscode/ +"UniGetUI Store.exe" +UniGetUI Store Installer.exe +UniGetUI Installer.exe +WingetUI Installer.exe +UniGetUI Store.exe +UniGetUI.exe +installer.iss +output/ +/artifacts/ +*.old +vcredist.exe +unigetui_bin/ +APIKEY.txt +*.pyc +WebBasedData/new_urls.txt +WebBasedData/screenshot-database.json.backup +pr_body.md +*.log +UniGetUI/wingettest.py +*.nupkg + +wui-1.7.0-console.zip +wui1.7.0-debug2.zip +env/ +.vs/* +dllexp.exe +sign.cmd.lnk +src/packages/ + +src/UniGetUI/bin +src/UniGetUI/obj + +src/WindowsPackageManager.Interop/bin +src/WindowsPackageManager.Interop/obj +src/WindowsPackageManager.Interop/out +src/WindowsPackageManager.Interop/outpublish + +src/UniGetU*/bin +src/UniGetU*/obj +src/UniGetU*/out +src/UniGetU*/outpublish + +src/UniGetUI.Pinget.Cli/bin +src/UniGetUI.Pinget.Cli/obj + +src/ExternalLibraries.*/bin +src/ExternalLibraries.*/obj +src/ExternalLibraries.*/out +src/ExternalLibraries.*/outpublish + +src/.vs +src/.vscode +new-names.docx + +src/UniGetUI/choco-cli/logs/ +src/UniGetUI/choco-cli/lib/ +src/UniGetUI/choco-cli/lib-bad/ +src/UniGetUI/choco-cli/.chocolatey/ +src/UniGetUI/choco-cli/lib/chocolatey-compatibility.extension/* +src/UniGetUI/choco-cli/extensions/chocolatey-core/* +src/UniGetUI/choco-cli/extensions/chocolatey-compatibility/* +src/UniGetUI/choco-cli/lib-bkp/ +src/UniGetUI/choco-cli/extensions/chocolatey-windowsupdate/* +src/UniGetUI/choco-cli/bin/chocolatey.exe +src/UniGetUI/choco-cli/redirects/chocolatey.exe +src/UniGetUI/choco-cli/redirects/chocolatey.exe.ignore +src/UniGetUI/choco-cli/redirects/cinst.exe +src/UniGetUI/choco-cli/redirects/cinst.exe.ignore +src/UniGetUI/choco-cli/redirects/clist.exe +src/UniGetUI/choco-cli/redirects/clist.exe.ignore +src/UniGetUI/choco-cli/redirects/cpush.exe +src/UniGetUI/choco-cli/redirects/cpush.exe.ignore +src/UniGetUI/choco-cli/redirects/cuninst.exe +src/UniGetUI/choco-cli/redirects/cuninst.exe.ignore +src/UniGetUI/choco-cli/redirects/cup.exe +src/UniGetUI/choco-cli/redirects/cup.exe.ignore +src/UniGetUI/choco-cli/bin/ssh-copy-id.exe +src/UniGetUI/choco-cli/extensions/chocolatey-visualstudio/ +src/UniGetUI/choco-cli/extensions/chocolatey-dotnetfx/ + +*.user +/src/UniGetUI/Generated Files +/src/UniGetUI.Avalonia/Infrastructure/Generated Files +/InstallerExtras/MsiCreator/.vs/MsiInstallerWrapper/CopilotIndices +/InstallerExtras/MsiCreator/.vs +InstallerExtras/MsiCreator/setup.exe +InstallerExtras/MsiCreator/UniGetUI Installer.msi +InstallerExtras/MsiCreator/UniGetUISetup.msi +UniGetUI.Installer.ms-store-test.exe +UniGetUI Installer_winget-fix-test.exe +InstallerExtras/uninst-*.e32 +src/.idea/ +src/UniGetUI.v3.ncrunchsolution + +# macOS Finder metadata +.DS_Store +/src/UniGetUI.Avalonia/Generated Files diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..70c5491 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,108 @@ +# UniGetUI - Copilot Instructions + +## Project Overview + +UniGetUI is an Avalonia desktop app (C#/.NET 10) providing a GUI for CLI package managers (WinGet, Scoop, Chocolatey, Pip, Npm, .NET Tool, PowerShell Gallery, Cargo, Vcpkg). + +Solution entry points: +- `src/UniGetUI.Windows.slnx` - official Windows solution; builds the Avalonia app and Windows-specific package-manager integrations +- `src/UniGetUI.Avalonia.slnx` - cross-platform Avalonia solution + +## Architecture + +The codebase follows a **layered, modular structure** with ~40 projects: + +- **`UniGetUI.Avalonia/`** - Avalonia entry point, AXAML pages, controls, and app shell (`Program.cs`, `Views/MainWindow.axaml`) +- **`SharedAssets/`** - shared app icons, symbols, splash images, and utility scripts used by packaging +- **`UniGetUI.Core.*`** - Shared infrastructure: `Logger`, `Settings`, `Tools` (includes `CoreTools.Translate()`), `IconEngine`, `LanguageEngine` +- **`UniGetUI.PackageEngine.Interfaces`** - Contracts: `IPackageManager`, `IPackage`, `IManagerSource`, `IPackageDetails` +- **`UniGetUI.PackageEngine.PackageManagerClasses`** - Base implementations: `PackageManager` (abstract), `Package`, helpers (`BasePkgDetailsHelper`, `BasePkgOperationHelper`, `BaseSourceHelper`) +- **`UniGetUI.PackageEngine.Managers.*`** - Concrete manager implementations (one project per manager: `WinGet`, `Scoop`, `Chocolatey`, `Pip`, `npm`, etc.) +- **`UniGetUI.PackageEngine.Operations`** - Install/update/uninstall operation orchestration +- **`UniGetUI.Interface.*`** - Enums, telemetry, background API + +## Adding a New Package Manager + +Each manager extends `PackageManager` and must override three abstract methods: + +```csharp +protected override IReadOnlyList FindPackages_UnSafe(string query); +protected override IReadOnlyList GetAvailableUpdates_UnSafe(); +protected override IReadOnlyList GetInstalledPackages_UnSafe(); +``` + +Each manager also provides three helper classes (in a `Helpers/` subfolder): +- `*PkgDetailsHelper` extends `BasePkgDetailsHelper` - overrides `GetDetails_UnSafe`, `GetInstallableVersions_UnSafe`, `GetIcon_UnSafe`, etc. +- `*PkgOperationHelper` extends `BasePkgOperationHelper` - overrides `_getOperationParameters`, `_getOperationResult` +- `*SourceHelper` extends `BaseSourceHelper` - overrides `GetSources_UnSafe`, `GetAddSourceParameters`, etc. + +The constructor sets `Capabilities`, `Properties`, and wires the helpers. See `src/UniGetUI.PackageEngine.Managers.Scoop/Scoop.cs` as a clean reference implementation. + +## Build & Test + +```shell +# Restore & test (from src/) +dotnet restore UniGetUI.Windows.slnx +dotnet test UniGetUI.Windows.slnx --verbosity q --nologo /p:Platform=x64 + +# Publish release build +dotnet publish src/UniGetUI.Avalonia/UniGetUI.Avalonia.csproj /p:Configuration=Release /p:Platform=x64 -p:RuntimeIdentifier=win-x64 +``` + +- Target framework: `net10.0-windows10.0.26100.0` (min `10.0.19041`) +- Build generates secrets via `src/UniGetUI.Avalonia/Infrastructure/generate-secrets.ps1` and integrity tree via `scripts/generate-integrity-tree.ps1` +- Self-contained, publish-trimmed (partial), Windows App SDK self-contained +- Tests use **xUnit** (`[Fact]`, `Assert.*`) + +## Avalonia DevTools (Developer-Only) + +Use these rules when changing Avalonia diagnostics/devtools behavior: + +- Build-time switch is `EnableAvaloniaDiagnostics` in `src/Directory.Build.props`. +- Default policy: enabled in `Debug`, disabled in `Release`. +- `src/UniGetUI.Avalonia/UniGetUI.Avalonia.csproj` must condition `AvaloniaUI.DiagnosticsSupport` on `$(EnableAvaloniaDiagnostics)`. +- Compile-time diagnostics code in `src/UniGetUI.Avalonia/Program.cs` must be gated by `#if AVALONIA_DIAGNOSTICS_ENABLED` (not `#if DEBUG`). +- Runtime controls are developer-only and intentionally not listed in `docs/CLI.md`. +- Runtime precedence in `Program.cs`: CLI flags > `UNIGETUI_AVALONIA_DEVTOOLS` environment variable > `Auto` default. +- Accepted runtime env/CLI values for mode parsing: `auto`, `enabled`, `disabled`, `on`, `off`, `true`, `false`, `1`, `0`. +- `Auto` mode must remain WSL-safe (DevTools disabled by default on WSL). +- If diagnostics were excluded at build time, runtime toggle requests should log a no-op warning. + +## Key Patterns & Conventions + +### Settings +File-based settings via `Settings.Get(Settings.K.*)` / `Settings.Set(Settings.K.*, value)` and `Settings.GetValue(Settings.K.*)` / `Settings.SetValue(Settings.K.*, value)`. Setting keys are defined in the `Settings.K` enum in `SettingsEngine_Names.cs`. Boolean settings are stored as file existence; string settings as file content. + +### Logging +Use `Logger.Info()`, `Logger.Warn()`, `Logger.Error()`, `Logger.Debug()`, `Logger.ImportantInfo()` from `UniGetUI.Core.Logging`. Accepts both `string` and `Exception` parameters. + +### Localization +Use `CoreTools.Translate("text")` for all user-facing strings. Parameterized: `CoreTools.Translate("{0} packages found", count)`. In XAML, use the `TranslatedTextBlock` control. Translation assets live under `src/Languages/`; do not assume Tolgee-based automation exists in this repository. + +### Naming +- Types, methods, properties: **PascalCase** +- Private fields: `__doubleUnderscore` or `_singleUnderscore` prefix +- Internal unsafe methods: suffix `_UnSafe` (e.g., `FindPackages_UnSafe`) +- Nullable enabled globally; `LangVersion` is `latest` +- Code style enforced in build (`EnforceCodeStyleInBuild=true`) + +### Manager conventions +- `FALSE_PACKAGE_NAMES`, `FALSE_PACKAGE_IDS`, `FALSE_PACKAGE_VERSIONS` static arrays filter CLI parsing noise +- Manager initialization flows through `Initialize()` -> `_loadManagerExecutableFile()` -> `_loadManagerVersion()` -> `_performExtraLoadingSteps()` +- Operations that may fail return `OperationVeredict` (note: intentional misspelling used throughout codebase) + +## Key Files + +| Purpose | Path | +|---|---| +| Windows solution | `src/UniGetUI.Windows.slnx` | +| Cross-platform solution | `src/UniGetUI.Avalonia.slnx` | +| Shared build props | `src/Directory.Build.props` | +| Version info | `src/SharedAssemblyInfo.cs` | +| Manager interface | `src/UniGetUI.PackageEngine.Interfaces/IPackageManager.cs` | +| Base manager class | `src/UniGetUI.PackageEngine.PackageManagerClasses/Manager/PackageManager.cs` | +| Package class | `src/UniGetUI.PackageEngine.PackageManagerClasses/Packages/Package.cs` | +| Settings engine | `src/UniGetUI.Core.Settings/SettingsEngine.cs` | +| Setting keys | `src/UniGetUI.Core.Settings/SettingsEngine_Names.cs` | +| Logger | `src/UniGetUI.Core.Logger/Logger.cs` | +| CI test workflow | `.github/workflows/dotnet-test.yml` | diff --git a/CLAUDE.md b/CLAUDE.md new file mode 120000 index 0000000..47dc3e3 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1 @@ +AGENTS.md \ No newline at end of file diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..ff6cc26 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,13 @@ +# Code of Conduct + +UniGetUI follows the [Contributor Covenant Code of Conduct, version 2.1](https://www.contributor-covenant.org/version/2/1/code_of_conduct/). + +## Providing feedback + +We are happy to receive constructive feedback, including criticism, and we value the time people take to help improve UniGetUI. The most helpful feedback is specific, respectful, and actionable: describe what changed, where it happens, what you expected instead, and any details that would help reproduce or evaluate the issue. + +Feedback about design, performance, usability, or project direction is welcome, especially when it focuses on concrete observations and possible improvements. Personal attacks, insults, repeated off-topic comments, pile-ons across unrelated issues or pull requests, and broad demands that cannot be acted on do not help the project and may be moderated. + +Instances of abusive, harassing, or otherwise unacceptable behavior may be reported privately through the [Devolutions contact page](https://devolutions.net/contact/). + +Security vulnerabilities should be reported through the [Devolutions security page](https://devolutions.net/security/). diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..bc8d503 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,64 @@ +# Contributing to UniGetUI + +Thank you for helping improve UniGetUI. Please follow the [Code of Conduct](CODE_OF_CONDUCT.md) in all project spaces. + +## Issues and feature requests + +Use the GitHub issue forms and choose the template that best matches your request: + +- **Bug or issue:** use the bug template, include the UniGetUI version, platform details, logs, and reproduction steps when available. +- **Hard crash:** use the hard-crash template. +- **New feature:** use the feature request template. +- **Improvement to an existing feature:** use the enhancement/improvement template. + +Before opening an issue, search for duplicates and check whether the problem is specific to UniGetUI. If the same behavior can be reproduced directly with the underlying package manager or package, report it to that project first. + +Do not include secrets, tokens, personal data, or private logs in public issues. Security vulnerabilities should be reported through the [Devolutions security page](https://devolutions.net/security/). Private non-security inquiries can be sent through the [Devolutions contact page](https://devolutions.net/contact/). + +Feature requests and improvements are reviewed by the maintainers and prioritized based on scope, impact, maintainability, and the project roadmap. + +## Pull requests + +- Use the pull request template and describe the user-visible change. +- Keep pull requests focused on one feature, bug fix, or documentation update. +- Link related issues when applicable, but do not create placeholder issues just to justify a pull request. +- Mark unfinished work as a draft pull request. +- Make sure the project builds and the affected behavior is tested before requesting review. +- Spam, unrelated, non-building, or low-effort pull requests may be closed without review. + +## Development setup and validation + +Run the pre-commit hook setup once after cloning: + +```powershell +pwsh ./scripts/install-git-hooks.ps1 +``` + +The hook runs whitespace formatting on staged files under `src` when the `dotnet` CLI is available. If it rewrites files, review the changes and commit again. + +Useful local validation commands from the repository root: + +```powershell +dotnet format whitespace src --folder --verify-no-changes +dotnet restore src/UniGetUI.Windows.slnx +dotnet format style src/UniGetUI.Windows.slnx --no-restore --verify-no-changes +dotnet test src/UniGetUI.Windows.slnx --no-restore --verbosity q --nologo /p:Platform=x64 +``` + +## Coding guidelines + +UniGetUI is primarily a C#/.NET Avalonia application. Follow the existing codebase style and patterns: + +- Use PascalCase for types, methods, and properties. +- Follow existing private field conventions, including `_singleUnderscore` and `__doubleUnderscore` prefixes. +- Keep nullable reference types and type safety intact; avoid unnecessary casts and broad catch blocks. +- Use the `_UnSafe` suffix for internal unsafe package-manager methods when matching existing package-engine patterns. +- Localize user-facing strings with `CoreTools.Translate(...)`. +- Use the existing logging APIs from `UniGetUI.Core.Logging`. +- Keep changes focused and avoid unrelated refactors. + +## Commits + +- Keep each commit focused on a single logical change. +- Do not leave the project in a broken or non-buildable state between commits. +- Use clear commit messages and reference related issues when applicable. diff --git a/InstallerExtras/CodeDependencies.iss b/InstallerExtras/CodeDependencies.iss new file mode 100644 index 0000000..306dfb1 --- /dev/null +++ b/InstallerExtras/CodeDependencies.iss @@ -0,0 +1,314 @@ +; Modified from https://github.com/DomGries/InnoDependencyInstaller + + + +[Code] +// types and variables +type + TDependency_Entry = record + Filename: String; + Parameters: String; + Title: String; + URL: String; + Checksum: String; + ForceSuccess: Boolean; + RestartAfter: Boolean; + end; + +var + Dependency_Memo: String; + Dependency_List: array of TDependency_Entry; + Dependency_NeedRestart, Dependency_ForceX86: Boolean; + Dependency_DownloadPage: TDownloadWizardPage; + +procedure Dependency_Add(const Filename, Parameters, Title, URL, Checksum: String; const ForceSuccess, RestartAfter: Boolean); +var + Dependency: TDependency_Entry; + DependencyCount: Integer; +begin + Dependency_Memo := Dependency_Memo + #13#10 + '%1' + Title; + + Dependency.Filename := Filename; + Dependency.Parameters := Parameters; + Dependency.Title := Title; + + if FileExists(ExpandConstant('{tmp}{\}') + Filename) then begin + Dependency.URL := ''; + end else begin + Dependency.URL := URL; + end; + + Dependency.Checksum := Checksum; + Dependency.ForceSuccess := ForceSuccess; + Dependency.RestartAfter := RestartAfter; + + DependencyCount := GetArrayLength(Dependency_List); + SetArrayLength(Dependency_List, DependencyCount + 1); + Dependency_List[DependencyCount] := Dependency; +end; + + +procedure Dependency_Internal1; +begin + Dependency_DownloadPage := CreateDownloadPage(SetupMessage(msgWizardPreparing), SetupMessage(msgPreparingDesc), nil); +end; + + +function Dependency_Internal2(var NeedsRestart: Boolean): String; +var + DependencyCount, DependencyIndex, ResultCode: Integer; + Retry: Boolean; + TempValue: String; +begin + DependencyCount := GetArrayLength(Dependency_List); + + if DependencyCount > 0 then begin + Dependency_DownloadPage.Show; + + for DependencyIndex := 0 to DependencyCount - 1 do begin + if Dependency_List[DependencyIndex].URL <> '' then begin + Dependency_DownloadPage.Clear; + Dependency_DownloadPage.Add(Dependency_List[DependencyIndex].URL, Dependency_List[DependencyIndex].Filename, Dependency_List[DependencyIndex].Checksum); + + Retry := True; + while Retry do begin + Retry := False; + + try + Dependency_DownloadPage.Download; + except + if Dependency_DownloadPage.AbortedByUser then begin + Result := Dependency_List[DependencyIndex].Title; + DependencyIndex := DependencyCount; + end else begin + case SuppressibleMsgBox(AddPeriod(GetExceptionMessage), mbError, MB_ABORTRETRYIGNORE, IDIGNORE) of + IDABORT: begin + Result := Dependency_List[DependencyIndex].Title; + DependencyIndex := DependencyCount; + end; + IDRETRY: begin + Retry := True; + end; + end; + end; + end; + end; + end; + end; + + if Result = '' then begin + for DependencyIndex := 0 to DependencyCount - 1 do begin + Dependency_DownloadPage.SetText(Dependency_List[DependencyIndex].Title, ''); + Dependency_DownloadPage.SetProgress(DependencyIndex + 1, DependencyCount + 1); + + while True do begin + ResultCode := 0; + if ShellExec('', ExpandConstant('{tmp}{\}') + Dependency_List[DependencyIndex].Filename, Dependency_List[DependencyIndex].Parameters, '', SW_SHOWNORMAL, ewWaitUntilTerminated, ResultCode) then begin + if Dependency_List[DependencyIndex].RestartAfter then begin + if DependencyIndex = DependencyCount - 1 then begin + Dependency_NeedRestart := True; + end else begin + NeedsRestart := True; + Result := Dependency_List[DependencyIndex].Title; + end; + break; + end else if (ResultCode = 0) or Dependency_List[DependencyIndex].ForceSuccess then begin // ERROR_SUCCESS (0) + break; + end else if ResultCode = 1641 then begin // ERROR_SUCCESS_REBOOT_INITIATED (1641) + NeedsRestart := True; + Result := Dependency_List[DependencyIndex].Title; + break; + end else if ResultCode = 3010 then begin // ERROR_SUCCESS_REBOOT_REQUIRED (3010) + Dependency_NeedRestart := True; + break; + end; + end; + + case SuppressibleMsgBox(FmtMessage(SetupMessage(msgErrorFunctionFailed), [Dependency_List[DependencyIndex].Title, IntToStr(ResultCode)]), mbError, MB_ABORTRETRYIGNORE, IDIGNORE) of + IDABORT: begin + Result := Dependency_List[DependencyIndex].Title; + break; + end; + IDIGNORE: begin + break; + end; + end; + end; + + if Result <> '' then begin + break; + end; + end; + + if NeedsRestart then begin + TempValue := '"' + ExpandConstant('{srcexe}') + '" /restart=1 /LANG="' + ExpandConstant('{language}') + '" /DIR="' + WizardDirValue + '" /GROUP="' + WizardGroupValue + '" /TYPE="' + WizardSetupType(False) + '" /COMPONENTS="' + WizardSelectedComponents(False) + '" /TASKS="' + WizardSelectedTasks(False) + '"'; + if WizardNoIcons then begin + TempValue := TempValue + ' /NOICONS'; + end; + RegWriteStringValue(HKA, 'SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce', '{#SetupSetting("AppName")}', TempValue); + end; + end; + + Dependency_DownloadPage.Hide; + end; +end; + + +function Dependency_Internal3(const Space, NewLine, MemoUserInfoInfo, MemoDirInfo, MemoTypeInfo, MemoComponentsInfo, MemoGroupInfo, MemoTasksInfo: String): String; +begin + Result := ''; + if MemoUserInfoInfo <> '' then begin + Result := Result + MemoUserInfoInfo + Newline + NewLine; + end; + if MemoDirInfo <> '' then begin + Result := Result + MemoDirInfo + Newline + NewLine; + end; + if MemoTypeInfo <> '' then begin + Result := Result + MemoTypeInfo + Newline + NewLine; + end; + if MemoComponentsInfo <> '' then begin + Result := Result + MemoComponentsInfo + Newline + NewLine; + end; + if MemoGroupInfo <> '' then begin + Result := Result + MemoGroupInfo + Newline + NewLine; + end; + if MemoTasksInfo <> '' then begin + Result := Result + MemoTasksInfo; + end; + + if Dependency_Memo <> '' then begin + if MemoTasksInfo = '' then begin + Result := Result + SetupMessage(msgReadyMemoTasks); + end; + Result := Result + FmtMessage(Dependency_Memo, [Space]); + end; +end; + + +function Dependency_Internal4: Boolean; +begin + Result := Dependency_NeedRestart; +end; + +function Dependency_IsX64: Boolean; +begin + Result := not Dependency_ForceX86 and Is64BitInstallMode; +end; + +function Dependency_String(const x86, x64: String): String; +begin + if Dependency_IsX64 then begin + Result := x64; + end else begin + Result := x86; + end; +end; + +function Dependency_ArchSuffix: String; +begin + Result := Dependency_String('_x64', '_x64'); +end; + +function Dependency_ArchTitle: String; +begin + Result := Dependency_String(' (x86)', ' (x64)'); +end; + +function Dependency_IsNetCoreInstalled(const Version: String): Boolean; +var + ResultCode: Integer; +begin + // source code: https://github.com/dotnet/deployment-tools/tree/main/src/clickonce/native/projects/NetCoreCheck + if not FileExists(ExpandConstant('{tmp}{\}') + 'netcorecheck' + Dependency_ArchSuffix + '.exe') then begin + ExtractTemporaryFile('netcorecheck' + Dependency_ArchSuffix + '.exe'); + end; + Result := ShellExec('', ExpandConstant('{tmp}{\}') + 'netcorecheck' + Dependency_ArchSuffix + '.exe', Version, '', SW_HIDE, ewWaitUntilTerminated, ResultCode) and (ResultCode = 0); +end; + +function Dependency_IsVCRuntimeInstalled(const Arch: String; const Major, Minor, Bld: Cardinal): Boolean; +var + InstalledFlag, InstMajor, InstMinor, InstBld: Cardinal; + Key: String; +begin + // Canonical VC++ runtime detection per Microsoft docs: + // https://learn.microsoft.com/en-us/cpp/windows/redistributing-visual-cpp-files + // The redistributable installer writes these values to both registry views, + // so a plain HKLM read is correct from Inno Setup's 32-bit process. + Key := 'SOFTWARE\Microsoft\VisualStudio\14.0\VC\Runtimes\' + Arch; + Result := + RegQueryDWordValue(HKLM, Key, 'Installed', InstalledFlag) and (InstalledFlag = 1) and + RegQueryDWordValue(HKLM, Key, 'Major', InstMajor) and + RegQueryDWordValue(HKLM, Key, 'Minor', InstMinor) and + RegQueryDWordValue(HKLM, Key, 'Bld', InstBld) and + ((InstMajor > Major) or + ((InstMajor = Major) and (InstMinor > Minor)) or + ((InstMajor = Major) and (InstMinor = Minor) and (InstBld >= Bld))); +end; + +procedure Dependency_AddVC2015To2022; +var + Arch, Url: String; + MinMajor, MinMinor, MinBld: Cardinal; +begin + // https://docs.microsoft.com/en-us/cpp/windows/latest-supported-vc-redist + MinMajor := 14; + MinMinor := 30; + MinBld := 30704; + + if IsARM64 then begin + Arch := 'arm64'; + Url := 'https://aka.ms/vc14/vc_redist.arm64.exe'; + end else begin + Arch := 'x64'; + Url := 'https://aka.ms/vc14/vc_redist.x64.exe'; + end; + + // Primary: registry-based detection (Microsoft's documented method, stable + // across installer builds). Fallback: MSI UpgradeCode lookup for x64 only + // (the x64 UpgradeCode {36F68A90-...} is verified; keeping a fallback helps + // on unusual install states). See issue #4596 for the regression this + // replaces, where a ProductCode was mistakenly used with IsMsiProductInstalled. + if Dependency_IsVCRuntimeInstalled(Arch, MinMajor, MinMinor, MinBld) then Exit; + if (Arch = 'x64') and IsMsiProductInstalled('{36F68A90-239C-34DF-B58C-64B30153CE35}', + PackVersionComponents(MinMajor, MinMinor, MinBld, 0)) then Exit; + + Dependency_Add('vcredist2022_' + Arch + '.exe', + '/passive /norestart', + 'Visual C++ 2015-2022 Redistributable (' + Arch + ')', + Url, + '', False, False); +end; + + +procedure Dependency_AddWebView2; +var + WebView2URL, WebView2Title: String; +begin + // https://developer.microsoft.com/en-us/microsoft-edge/webview2 + if not RegValueExists(HKLM, Dependency_String('SOFTWARE', 'SOFTWARE\WOW6432Node') + '\Microsoft\EdgeUpdate\Clients\{F3017226-FE2A-4295-8BDF-00C3A9A7E4C5}', 'pv') then begin + if IsARM64 then begin + WebView2URL := 'https://go.microsoft.com/fwlink/?linkid=2099616'; + WebView2Title := 'WebView2 Runtime (ARM64)'; + end else begin + WebView2URL := 'https://go.microsoft.com/fwlink/?linkid=2124701'; + WebView2Title := 'WebView2 Runtime (x64)'; + end; + Dependency_Add('MicrosoftEdgeWebview2Setup.exe', + '/silent /install', + WebView2Title, + WebView2URL, + '', False, False); + end; +end; + + + +[Files] +#ifdef Dependency_Path_NetCoreCheck +; download netcorecheck_x64.exe: https://www.nuget.org/packages/Microsoft.NET.Tools.NETCoreCheck.x64 +Source: "{#Dependency_Path_NetCoreCheck}netcorecheck_x64.exe"; Flags: dontcopy noencryption +#endif + +#ifdef Dependency_Path_DirectX +Source: "{#Dependency_Path_DirectX}dxwebsetup.exe"; Flags: dontcopy noencryption +#endif diff --git a/InstallerExtras/CustomMessages.iss b/InstallerExtras/CustomMessages.iss new file mode 100644 index 0000000..9112660 --- /dev/null +++ b/InstallerExtras/CustomMessages.iss @@ -0,0 +1,218 @@ +[CustomMessages] +; Armenian, Brazilian Portuguese, Catalan, Corsican, Czech, Danish, Dutch, Finnish, French, German, Hebrew, Icelandic, Italian, Japanese, Korean, Norwegian, Polish, Portuguese, Russian, Slovenian, Spanish, Turkish, Ukrainian + +; English +InstallType=Installation type +ShCuts=Shortcuts +PortInst=Perform a portable installation +RegInst=Perform a regular installation +RegStartMmenuIcon=Create a shortcut on the Start menu +RegDesktopIcon=Create a shortcut on the Desktop +PackageBundleName=UniGetUI package bundle + +; Armenian +Armenian.InstallType=Տեղադրման տեսակը +Armenian.ShCuts=Դյուրանցումներ +Armenian.PortInst=Կատարել շարժական տեղադրում +Armenian.RegInst=Կատարել սովորական տեղադրում +Armenian.RegStartMmenuIcon=Ստեղծեք դյուրանցում Start ընտրացանկում +Armenian.RegDesktopIcon=Ստեղծեք դյուրանցում աշխատասեղանի վրա +Armenian.PackageBundleName=UniGetUI փաթեթի փաթեթ + +; BrazilianPortuguese +BrazilianPortuguese.InstallType=Tipo de instalação +BrazilianPortuguese.ShCuts=Atalhos +BrazilianPortuguese.PortInst=Realizar uma instalação portátil +BrazilianPortuguese.RegInst=Realizar uma instalação regular +BrazilianPortuguese.RegStartMmenuIcon=Criar um atalho no menu Iniciar +BrazilianPortuguese.RegDesktopIcon=Criar um atalho na área de trabalh +BrazilianPortuguese.PackageBundleName=Coleção de pacotes UniGetUI + +; Catalan +Catalan.InstallType=Tipus d'instal·lació +Catalan.ShCuts=Dreceres +Catalan.PortInst=Feu una instal·lació portàtil +Catalan.RegInst=Feu una instal·lació regular +Catalan.RegStartMmenuIcon=Creeu una drecera al menú Inici +Catalan.RegDesktopIcon=Creeu una drecera a l'Escriptori +Catalan.PackageBundleName=Col·lecció de paquets de l'UniGetUI + +; Corsican +Corsican.InstallType=Tipu d'installazione +Corsican.ShCuts=Scorciatoie +Corsican.PortInst=Eseguite una installazione portable +Corsican.RegInst=Eseguite una installazione regulare +Corsican.RegStartMmenuIcon=Create una scorciatoia nant'à u menu Start +Corsican.RegDesktopIcon=Create una scorciatoia nant'à u Desktop +Corsican.PackageBundleName=Raccolta di pacchetti UniGetUI + +; Czech +Czech.InstallType=Typ instalace +Czech.ShCuts=Zkratky +Czech.PortInst=Proveďte přenosnou instalaci +Czech.RegInst=Proveďte běžnou instalaci +Czech.RegStartMmenuIcon=Vytvořte zástupce v nabídce Start +Czech.RegDesktopIcon=Vytvořte zástupce na ploše +Czech.PackageBundleName=Kolekce balíčků UniGetUI + +; Danish +Danish.InstallType=Installationstype +Danish.ShCuts=Genveje +Danish.PortInst=Udfør en bærbar installation +Danish.RegInst=Udfør en almindelig installation +Danish.RegStartMmenuIcon=Opret en genvej på Start-menuen +Danish.RegDesktopIcon=Opret en genvej på skrivebordet +Danish.PackageBundleName=Samling af UniGetUI-pakker + +; Dutch +Dutch.InstallType=Installatietype +Dutch.ShCuts=Snelkoppelingen +Dutch.PortInst=Voer een draagbare installatie uit +Dutch.RegInst=Voer een normale installatie uit +Dutch.RegStartMmenuIcon=Maak een snelkoppeling in het Startmenu +Dutch.RegDesktopIcon=Maak een snelkoppeling op het bureaublad +Dutch.PackageBundleName=Verzameling UniGetUI-pakketten + +; Finnish +Finnish.InstallType=Asennustyyppi +Finnish.ShCuts=Oikopolut +Finnish.PortInst=Suorita kannettava asennus +Finnish.RegInst=Suorita tavallinen asennus +Finnish.RegStartMmenuIcon=Luo pikakuvake Käynnistä-valikkoon +Finnish.RegDesktopIcon=Luo pikakuvake työpöydälle +Finnish.PackageBundleName=Kokoelma UniGetUI-paketteja + +; French +French.InstallType=Type d'installation +French.ShCuts=Raccourcis +French.PortInst=Effectuer une installation portable +French.RegInst=Effectuer une installation normale +French.RegStartMmenuIcon=Créer un raccourci dans le menu Démarrer +French.RegDesktopIcon=Créer un raccourci sur le bureau +French.PackageBundleName=Collection de packages UniGetUI + +; German +German.InstallType=Installationstyp +German.ShCuts=Verknüpfungen +German.PortInst=Führe eine portable Installation durch +German.RegInst=Führe eine normale Installation durch +German.RegStartMmenuIcon=Erstelle eine Verknüpfung im Startmenü +German.RegDesktopIcon=Erstelle eine Verknüpfung auf dem Desktop +German.PackageBundleName=Sammlung von UniGetUI-Paketen + +; Hebrew +Hebrew.InstallType=סוג התקנה +Hebrew.ShCuts=קיצורי דרך +Hebrew.PortInst=בצע התקנה ניידת +Hebrew.RegInst=בצע התקנה רגילה +Hebrew.RegStartMmenuIcon=צור קיצור דרך בתפריט התחל +Hebrew.RegDesktopIcon=צור קיצור דרך בשולחן העבודה +Hebrew.PackageBundleName=אוסף חבילות UniGetUI + +; Icelandic +;Icelandic.InstallType=Uppsetningargerð +;Icelandic.ShCuts=Flýtivísar +;Icelandic.PortInst=Framkvæma færanlega uppsetningu +;Icelandic.RegInst=Framkvæma reglulega uppsetningu +;Icelandic.RegStartMmenuIcon=Búa til flýtileið á Start valmyndinni +;Icelandic.RegDesktopIcon=Búa til flýtileið á skjáborðinu +;Icelandic.PackageBundleName=Safn af UniGetUI pakka + +; Italian +Italian.InstallType=Tipo di installazione +Italian.ShCuts=Collegamenti +Italian.PortInst=Esegui installazione portatile +Italian.RegInst=Esegui installazione normale +Italian.RegStartMmenuIcon=Crea una scorciatoia nel menu Start +Italian.RegDesktopIcon=Crea una scorciatoia sul Desktop +Italian.PackageBundleName=Raccolta di pacchetti UniGetUI + +; Japanese +Japanese.InstallType=インストールの種類 +Japanese.ShCuts=ショートカット +Japanese.PortInst=ポータブル インストールを実行する +Japanese.RegInst=通常のインストールを実行します +Japanese.RegStartMmenuIcon=スタート メニューにショートカットを作成する +Japanese.RegDesktopIcon=デスクトップにショートカットを作成する +Japanese.PackageBundleName=UniGetUI パッケージのコレクション + +; Korean +Korean.InstallType=설치 유형 +Korean.ShCuts=바로가기 +Korean.PortInst=이동식 설치 수행 +Korean.RegInst=일반 설치 수행 +Korean.RegStartMmenuIcon=시작 메뉴에 바로가기 만들기 +Korean.RegDesktopIcon=바탕화면에 바로가기 생성 +Korean.PackageBundleName=UniGetUI 패키지 컬렉션 + +; Norwegian +Norwegian.InstallType=Installasjonstype +Norwegian.ShCuts=Snarveier +Norwegian.PortInst=Utfør en bærbar installasjon +Norwegian.RegInst=Utfør en vanlig installasjon +Norwegian.RegStartMmenuIcon=Lag en snarvei på Start-menyen +Norwegian.RegDesktopIcon=Lag en snarvei på skrivebordet +Norwegian.PackageBundleName=Samling av UniGetUI-pakker + +; Polish +Polish.InstallType=Typ instalacji +Polish.ShCuts=Skróty +Polish.PortInst=Przeprowadź instalację przenośną +Polish.RegInst=Przeprowadź zwykłą instalację +Polish.RegStartMmenuIcon=Utwórz skrót w menu Start +Polish.RegDesktopIcon=Utwórz skrót na pulpicie +Polish.PackageBundleName=Kolekcja pakietów UniGetUI + +; Portuguese +Portuguese.InstallType=Tipo de instalação +Portuguese.ShCuts=Atalhos +Portuguese.PortInst=Execute uma instalação portátil +Portuguese.RegInst=Execute uma instalação regular +Portuguese.RegStartMmenuIcon=Criar um atalho no menu Iniciar +Portuguese.RegDesktopIcon=Criar um atalho na área de trabalho +Portuguese.PackageBundleName=Coleção de pacotes UniGetUI + +; Russian +Russian.InstallType=Тип установки +Russian.ShCuts=Ярлыки +Russian.PortInst=Выполнить переносную установку +Russian.RegInst=Выполнить обычную установку +Russian.RegStartMmenuIcon=Создать ярлык в меню «Пуск» +Russian.RegDesktopIcon=Создать ярлык на рабочем столе +Russian.PackageBundleName= + +; Slovenian +Slovenian.InstallType=Vrsta namestitve +Slovenian.ShCuts=Bližnjice +Slovenian.PortInst=Izvedite prenosno namestitev +Slovenian.RegInst=Izvedite običajno namestitev +Slovenian.RegStartMmenuIcon=Ustvarite bližnjico v meniju Start +Slovenian.RegDesktopIcon=Ustvarite bližnjico na namizju +Slovenian.PackageBundleName=Коллекция пакетов UniGetUI + +; Spanish +Spanish.InstallType=Tipo de instalación +Spanish.ShCuts=Atajos +Spanish.PortInst=Realizar una instalación portátil +Spanish.RegInst=Realizar una instalación regular +Spanish.RegStartMmenuIcon=Crear un acceso directo en el menú Inicio +Spanish.RegDesktopIcon=Crear un atajo en el escritorio +Spanish.PackageBundleName=Coleción de paquetes del UniGetUI + +; Turkish +Turkish.InstallType=Yükleme türü +Turkish.ShCuts=Kısayollar +Turkish.PortInst=Taşınabilir bir kurulum gerçekleştirin +Turkish.RegInst=Normal bir kurulum gerçekleştir +Turkish.RegStartMmenuIcon=Başlat menüsünde bir kısayol oluştur +Turkish.RegDesktopIcon=Masaüstünde bir kısayol oluştur +Turkish.PackageBundleName=UniGetUI paketlerinin toplanması + +; Ukrainian +Ukrainian.InstallType=Тип інсталяції +Ukrainian.ShCuts=Ярлики +Ukrainian.PortInst=Виконати переносне встановлення +Ukrainian.RegInst=Виконайте звичайну установку +Ukrainian.RegStartMmenuIcon=Створити ярлик у меню «Пуск». +Ukrainian.RegDesktopIcon=Створити ярлик на робочому столі +Ukrainian.PackageBundleName=Колекція пакетів UniGetUI diff --git a/InstallerExtras/ForceUniGetUIPortable b/InstallerExtras/ForceUniGetUIPortable new file mode 100644 index 0000000..e69de29 diff --git a/InstallerExtras/MsiCreator/MsiInstallerWrapper.sln b/InstallerExtras/MsiCreator/MsiInstallerWrapper.sln new file mode 100644 index 0000000..1f75c98 --- /dev/null +++ b/InstallerExtras/MsiCreator/MsiInstallerWrapper.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.11.35303.130 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{54435603-DBB4-11D2-8724-00A0C9A8B90C}") = "MsiInstallerWrapper", "MsiInstallerWrapper.vdproj", "{EE7E4697-83BE-454A-8188-714D27776721}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Default = Debug|Default + Release|Default = Release|Default + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {EE7E4697-83BE-454A-8188-714D27776721}.Debug|Default.ActiveCfg = Debug + {EE7E4697-83BE-454A-8188-714D27776721}.Debug|Default.Build.0 = Debug + {EE7E4697-83BE-454A-8188-714D27776721}.Release|Default.ActiveCfg = Release + {EE7E4697-83BE-454A-8188-714D27776721}.Release|Default.Build.0 = Release + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {FD6F7794-50E5-477C-90BC-D877BB2CDDED} + EndGlobalSection +EndGlobal diff --git a/InstallerExtras/MsiCreator/MsiInstallerWrapper.vdproj b/InstallerExtras/MsiCreator/MsiInstallerWrapper.vdproj new file mode 100644 index 0000000..df9bc84 --- /dev/null +++ b/InstallerExtras/MsiCreator/MsiInstallerWrapper.vdproj @@ -0,0 +1,712 @@ +"DeployProject" +{ +"VSVersion" = "3:800" +"ProjectType" = "8:{978C614F-708E-4E1A-B201-565925725DBA}" +"IsWebType" = "8:FALSE" +"ProjectName" = "8:MsiInstallerWrapper" +"LanguageId" = "3:1033" +"CodePage" = "3:1252" +"UILanguageId" = "3:1033" +"SccProjectName" = "8:" +"SccLocalPath" = "8:" +"SccAuxPath" = "8:" +"SccProvider" = "8:" + "Hierarchy" + { + "Entry" + { + "MsmKey" = "8:_A22A7552D1EC4801A0A4D984FCF18331" + "OwnerKey" = "8:_UNDEFINED" + "MsmSig" = "8:_UNDEFINED" + } + } + "Configurations" + { + "Debug" + { + "DisplayName" = "8:Debug" + "IsDebugOnly" = "11:TRUE" + "IsReleaseOnly" = "11:FALSE" + "OutputFilename" = "8:UniGetUISetup.msi" + "PackageFilesAs" = "3:2" + "PackageFileSize" = "3:-2147483648" + "CabType" = "3:1" + "Compression" = "3:2" + "SignOutput" = "11:FALSE" + "CertificateFile" = "8:" + "PrivateKeyFile" = "8:" + "TimeStampServer" = "8:" + "InstallerBootstrapper" = "3:2" + "BootstrapperCfg:{63ACBE69-63AA-4F98-B2B6-99F9E24495F2}" + { + "Enabled" = "11:TRUE" + "PromptEnabled" = "11:TRUE" + "PrerequisitesLocation" = "2:1" + "Url" = "8:" + "ComponentsUrl" = "8:" + "Items" + { + "{EDC2488A-8267-493A-A98E-7D9C3B36CDF3}:.NETFramework,Version=v4.7.2" + { + "Name" = "8:Microsoft .NET Framework 4.7.2 (x86 and x64)" + "ProductCode" = "8:.NETFramework,Version=v4.7.2" + } + "{EDC2488A-8267-493A-A98E-7D9C3B36CDF3}:Microsoft.EdgeRuntime" + { + "Name" = "8:Edge WebView runtime" + "ProductCode" = "8:Microsoft.EdgeRuntime" + } + "{EDC2488A-8267-493A-A98E-7D9C3B36CDF3}:Microsoft.Visual.C++.14.0.x64" + { + "Name" = "8:Visual C++ \"14\" Runtime Libraries (x64)" + "ProductCode" = "8:Microsoft.Visual.C++.14.0.x64" + } + } + } + } + "Release" + { + "DisplayName" = "8:Release" + "IsDebugOnly" = "11:FALSE" + "IsReleaseOnly" = "11:TRUE" + "OutputFilename" = "8:UniGetUISetup.msi" + "PackageFilesAs" = "3:2" + "PackageFileSize" = "3:-2147483648" + "CabType" = "3:1" + "Compression" = "3:2" + "SignOutput" = "11:FALSE" + "CertificateFile" = "8:" + "PrivateKeyFile" = "8:" + "TimeStampServer" = "8:" + "InstallerBootstrapper" = "3:2" + "BootstrapperCfg:{63ACBE69-63AA-4F98-B2B6-99F9E24495F2}" + { + "Enabled" = "11:TRUE" + "PromptEnabled" = "11:TRUE" + "PrerequisitesLocation" = "2:1" + "Url" = "8:" + "ComponentsUrl" = "8:" + "Items" + { + "{EDC2488A-8267-493A-A98E-7D9C3B36CDF3}:.NETFramework,Version=v4.7.2" + { + "Name" = "8:Microsoft .NET Framework 4.7.2 (x86 and x64)" + "ProductCode" = "8:.NETFramework,Version=v4.7.2" + } + "{EDC2488A-8267-493A-A98E-7D9C3B36CDF3}:Microsoft.EdgeRuntime" + { + "Name" = "8:Edge WebView runtime" + "ProductCode" = "8:Microsoft.EdgeRuntime" + } + "{EDC2488A-8267-493A-A98E-7D9C3B36CDF3}:Microsoft.Visual.C++.14.0.x64" + { + "Name" = "8:Visual C++ \"14\" Runtime Libraries (x64)" + "ProductCode" = "8:Microsoft.Visual.C++.14.0.x64" + } + } + } + } + } + "Deployable" + { + "CustomAction" + { + "{4AA51A2D-7D85-4A59-BA75-B0809FC8B380}:_BF756C7619CC4B4BBFD0B9E127183C43" + { + "Name" = "8:%ProgramFiles%\\UniGetUI\\unins000.exe" + "Condition" = "8:" + "Object" = "8:_A22A7552D1EC4801A0A4D984FCF18331" + "FileType" = "3:2" + "InstallAction" = "3:4" + "Arguments" = "8:" + "EntryPoint" = "8:" + "Sequence" = "3:1" + "Identifier" = "8:_F4F70591_F141_4E92_8171_63B1F09EEAE9" + "InstallerClass" = "11:FALSE" + "CustomActionData" = "8:" + } + "{4AA51A2D-7D85-4A59-BA75-B0809FC8B380}:_D68AA58489F8420F9DFCC894A884B2A9" + { + "Name" = "8:UniGetUI Installer.exe" + "Condition" = "8: " + "Object" = "8:_A22A7552D1EC4801A0A4D984FCF18331" + "FileType" = "3:2" + "InstallAction" = "3:1" + "Arguments" = "8:/NoAutoStart /ALLUSERS /silent /unattended /NoVCRedist /NoEdgeWebView /NoRestart" + "EntryPoint" = "8:" + "Sequence" = "3:1" + "Identifier" = "8:_AB502465_2086_4B1B_B987_3CD03317278A" + "InstallerClass" = "11:FALSE" + "CustomActionData" = "8:" + "Run64Bit" = "11:FALSE" + } + } + "DefaultFeature" + { + "Name" = "8:DefaultFeature" + "Title" = "8:" + "Description" = "8:" + } + "ExternalPersistence" + { + "LaunchCondition" + { + } + } + "File" + { + "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_A22A7552D1EC4801A0A4D984FCF18331" + { + "SourcePath" = "8:UniGetUI Installer.exe" + "TargetName" = "8:UniGetUI Installer.exe" + "Tag" = "8:" + "Folder" = "8:_B08F8663334547FDBF4D0DC7F957E164" + "Condition" = "8:" + "Transitive" = "11:FALSE" + "Vital" = "11:TRUE" + "ReadOnly" = "11:FALSE" + "Hidden" = "11:FALSE" + "System" = "11:FALSE" + "Permanent" = "11:FALSE" + "SharedLegacy" = "11:FALSE" + "PackageAs" = "3:1" + "Register" = "3:1" + "Exclude" = "11:FALSE" + "IsDependency" = "11:FALSE" + "IsolateTo" = "8:" + } + } + "FileType" + { + } + "Folder" + { + "{1525181F-901A-416C-8A58-119130FE478E}:_545FB00BD1854FA8BAF4F057F086F631" + { + "Name" = "8:#1919" + "AlwaysCreate" = "11:FALSE" + "Condition" = "8:" + "Transitive" = "11:FALSE" + "Property" = "8:ProgramMenuFolder" + "Folders" + { + } + } + "{3C67513D-01DD-4637-8A68-80971EB9504F}:_A6825CAB25F84B15A64AE00EFD72194C" + { + "DefaultLocation" = "8:[ProgramFiles64Folder][Manufacturer]\\[ProductName]" + "Name" = "8:#1925" + "AlwaysCreate" = "11:FALSE" + "Condition" = "8:" + "Transitive" = "11:FALSE" + "Property" = "8:TARGETDIR" + "Folders" + { + } + } + "{1525181F-901A-416C-8A58-119130FE478E}:_AA2E6321A69F4A7F974C661BCDEE307F" + { + "Name" = "8:#1916" + "AlwaysCreate" = "11:FALSE" + "Condition" = "8:" + "Transitive" = "11:FALSE" + "Property" = "8:DesktopFolder" + "Folders" + { + } + } + "{994432C3-9487-495D-8656-3E829A8DBDDE}:_B08F8663334547FDBF4D0DC7F957E164" + { + "DefaultLocation" = "8:[WindowsFolder]\\Temp" + "Name" = "8:Temp" + "AlwaysCreate" = "11:FALSE" + "Condition" = "8:" + "Transitive" = "11:FALSE" + "Property" = "8:NEWPROPERTY1" + "Folders" + { + } + } + } + "LaunchCondition" + { + } + "Locator" + { + } + "MsiBootstrapper" + { + "LangId" = "3:1033" + "RequiresElevation" = "11:FALSE" + } + "Product" + { + "Name" = "8:Microsoft Visual Studio" + "ProductName" = "8:UniGetUI" + "ProductCode" = "8:{4896DCDD-E250-45EE-814B-0A6591D1AC00}" + "PackageCode" = "8:{03CA204E-D817-4486-B0C3-C2A31BD2EBA1}" + "UpgradeCode" = "8:{AA73EEF1-B0C1-4CDD-AA20-97C49E1085DA}" + "AspNetVersion" = "8:2.0.50727.0" + "RestartWWWService" = "11:FALSE" + "RemovePreviousVersions" = "11:FALSE" + "DetectNewerInstalledVersion" = "11:FALSE" + "InstallAllUsers" = "11:TRUE" + "ProductVersion" = "8:0.0.0" + "Manufacturer" = "8:Martí Climent" + "ARPHELPTELEPHONE" = "8:" + "ARPHELPLINK" = "8:" + "Title" = "8:UniGetUI" + "Subject" = "8:" + "ARPCONTACT" = "8:Martí Climent" + "Keywords" = "8:" + "ARPCOMMENTS" = "8:" + "ARPURLINFOABOUT" = "8:" + "ARPPRODUCTICON" = "8:" + "ARPIconIndex" = "3:0" + "SearchPath" = "8:" + "UseSystemSearchPath" = "11:TRUE" + "TargetPlatform" = "3:1" + "PreBuildEvent" = "8:" + "PostBuildEvent" = "8:" + "RunPostBuildEvent" = "3:0" + } + "Registry" + { + "HKLM" + { + "Keys" + { + } + } + "HKCU" + { + "Keys" + { + } + } + "HKCR" + { + "Keys" + { + } + } + "HKU" + { + "Keys" + { + } + } + "HKPU" + { + "Keys" + { + } + } + } + "Sequences" + { + } + "Shortcut" + { + } + "UserInterface" + { + "{2479F3F5-0309-486D-8047-8187E2CE5BA0}:_3A17EDF809CC4B78986B2FE6EA70BE3E" + { + "UseDynamicProperties" = "11:FALSE" + "IsDependency" = "11:FALSE" + "SourcePath" = "8:\\VsdUserInterface.wim" + } + "{2479F3F5-0309-486D-8047-8187E2CE5BA0}:_3D5999E6267F4C0298B4BCDE7D5F60A6" + { + "UseDynamicProperties" = "11:FALSE" + "IsDependency" = "11:FALSE" + "SourcePath" = "8:\\VsdBasicDialogs.wim" + } + "{DF760B10-853B-4699-99F2-AFF7185B4A62}:_4DFD809C69BF4C59A6FD3BA01B0D95DA" + { + "Name" = "8:#1900" + "Sequence" = "3:2" + "Attributes" = "3:1" + "Dialogs" + { + "{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_1647D66DC7EA4BC4BE95CB839077FD2B" + { + "Sequence" = "3:200" + "DisplayName" = "8:Installation Folder" + "UseDynamicProperties" = "11:TRUE" + "IsDependency" = "11:FALSE" + "SourcePath" = "8:\\VsdAdminFolderDlg.wid" + "Properties" + { + "BannerBitmap" + { + "Name" = "8:BannerBitmap" + "DisplayName" = "8:#1001" + "Description" = "8:#1101" + "Type" = "3:8" + "ContextData" = "8:Bitmap" + "Attributes" = "3:4" + "Setting" = "3:0" + "UsePlugInResources" = "11:TRUE" + } + } + } + "{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_4452C40CD596425EAB25E35D2B22C4CF" + { + "Sequence" = "3:100" + "DisplayName" = "8:Welcome" + "UseDynamicProperties" = "11:TRUE" + "IsDependency" = "11:FALSE" + "SourcePath" = "8:\\VsdAdminWelcomeDlg.wid" + "Properties" + { + "BannerBitmap" + { + "Name" = "8:BannerBitmap" + "DisplayName" = "8:#1001" + "Description" = "8:#1101" + "Type" = "3:8" + "ContextData" = "8:Bitmap" + "Attributes" = "3:4" + "Setting" = "3:0" + "UsePlugInResources" = "11:TRUE" + } + "CopyrightWarning" + { + "Name" = "8:CopyrightWarning" + "DisplayName" = "8:#1002" + "Description" = "8:#1102" + "Type" = "3:3" + "ContextData" = "8:" + "Attributes" = "3:0" + "Setting" = "3:1" + "Value" = "8:#1202" + "DefaultValue" = "8:#1202" + "UsePlugInResources" = "11:TRUE" + } + "Welcome" + { + "Name" = "8:Welcome" + "DisplayName" = "8:#1003" + "Description" = "8:#1103" + "Type" = "3:3" + "ContextData" = "8:" + "Attributes" = "3:0" + "Setting" = "3:1" + "Value" = "8:#1203" + "DefaultValue" = "8:#1203" + "UsePlugInResources" = "11:TRUE" + } + } + } + "{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_56CAF5E0DFAE4764ACD49E3FD559D429" + { + "Sequence" = "3:300" + "DisplayName" = "8:Confirm Installation" + "UseDynamicProperties" = "11:TRUE" + "IsDependency" = "11:FALSE" + "SourcePath" = "8:\\VsdAdminConfirmDlg.wid" + "Properties" + { + "BannerBitmap" + { + "Name" = "8:BannerBitmap" + "DisplayName" = "8:#1001" + "Description" = "8:#1101" + "Type" = "3:8" + "ContextData" = "8:Bitmap" + "Attributes" = "3:4" + "Setting" = "3:0" + "UsePlugInResources" = "11:TRUE" + } + } + } + } + } + "{DF760B10-853B-4699-99F2-AFF7185B4A62}:_5D2ED95DF08B4D95A7EB3239A89BF4C6" + { + "Name" = "8:#1902" + "Sequence" = "3:2" + "Attributes" = "3:3" + "Dialogs" + { + "{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_D56A5E75F9834D60948B9D0DD86D2299" + { + "Sequence" = "3:100" + "DisplayName" = "8:Finished" + "UseDynamicProperties" = "11:TRUE" + "IsDependency" = "11:FALSE" + "SourcePath" = "8:\\VsdAdminFinishedDlg.wid" + "Properties" + { + "BannerBitmap" + { + "Name" = "8:BannerBitmap" + "DisplayName" = "8:#1001" + "Description" = "8:#1101" + "Type" = "3:8" + "ContextData" = "8:Bitmap" + "Attributes" = "3:4" + "Setting" = "3:0" + "UsePlugInResources" = "11:TRUE" + } + } + } + } + } + "{DF760B10-853B-4699-99F2-AFF7185B4A62}:_6EF9716EF936459ABC8F22F995A5CF35" + { + "Name" = "8:#1901" + "Sequence" = "3:1" + "Attributes" = "3:2" + "Dialogs" + { + "{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_2C4A093A2457487DBD623967D4706C28" + { + "Sequence" = "3:100" + "DisplayName" = "8:Progress" + "UseDynamicProperties" = "11:TRUE" + "IsDependency" = "11:FALSE" + "SourcePath" = "8:\\VsdProgressDlg.wid" + "Properties" + { + "BannerBitmap" + { + "Name" = "8:BannerBitmap" + "DisplayName" = "8:#1001" + "Description" = "8:#1101" + "Type" = "3:8" + "ContextData" = "8:Bitmap" + "Attributes" = "3:4" + "Setting" = "3:0" + "UsePlugInResources" = "11:TRUE" + } + "ShowProgress" + { + "Name" = "8:ShowProgress" + "DisplayName" = "8:#1009" + "Description" = "8:#1109" + "Type" = "3:5" + "ContextData" = "8:1;True=1;False=0" + "Attributes" = "3:0" + "Setting" = "3:0" + "Value" = "3:1" + "DefaultValue" = "3:1" + "UsePlugInResources" = "11:TRUE" + } + } + } + } + } + "{DF760B10-853B-4699-99F2-AFF7185B4A62}:_DAA1A949544C4A96986254FF87C0D0D7" + { + "Name" = "8:#1901" + "Sequence" = "3:2" + "Attributes" = "3:2" + "Dialogs" + { + "{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_597DC589900D4E32B4D7BCB6B9B64387" + { + "Sequence" = "3:100" + "DisplayName" = "8:Progress" + "UseDynamicProperties" = "11:TRUE" + "IsDependency" = "11:FALSE" + "SourcePath" = "8:\\VsdAdminProgressDlg.wid" + "Properties" + { + "BannerBitmap" + { + "Name" = "8:BannerBitmap" + "DisplayName" = "8:#1001" + "Description" = "8:#1101" + "Type" = "3:8" + "ContextData" = "8:Bitmap" + "Attributes" = "3:4" + "Setting" = "3:0" + "UsePlugInResources" = "11:TRUE" + } + "ShowProgress" + { + "Name" = "8:ShowProgress" + "DisplayName" = "8:#1009" + "Description" = "8:#1109" + "Type" = "3:5" + "ContextData" = "8:1;True=1;False=0" + "Attributes" = "3:0" + "Setting" = "3:0" + "Value" = "3:1" + "DefaultValue" = "3:1" + "UsePlugInResources" = "11:TRUE" + } + } + } + } + } + "{DF760B10-853B-4699-99F2-AFF7185B4A62}:_F8B322222EFF4C19B40AB77367AC4879" + { + "Name" = "8:#1902" + "Sequence" = "3:1" + "Attributes" = "3:3" + "Dialogs" + { + "{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_6BB46602C9BA410C932C78D7334D7518" + { + "Sequence" = "3:100" + "DisplayName" = "8:Finished" + "UseDynamicProperties" = "11:TRUE" + "IsDependency" = "11:FALSE" + "SourcePath" = "8:\\VsdFinishedDlg.wid" + "Properties" + { + "BannerBitmap" + { + "Name" = "8:BannerBitmap" + "DisplayName" = "8:#1001" + "Description" = "8:#1101" + "Type" = "3:8" + "ContextData" = "8:Bitmap" + "Attributes" = "3:4" + "Setting" = "3:0" + "UsePlugInResources" = "11:TRUE" + } + "UpdateText" + { + "Name" = "8:UpdateText" + "DisplayName" = "8:#1058" + "Description" = "8:#1158" + "Type" = "3:15" + "ContextData" = "8:" + "Attributes" = "3:0" + "Setting" = "3:1" + "Value" = "8:#1258" + "DefaultValue" = "8:#1258" + "UsePlugInResources" = "11:TRUE" + } + } + } + } + } + "{DF760B10-853B-4699-99F2-AFF7185B4A62}:_F90FA3407D9843D38E8B11EAEC8F1DF9" + { + "Name" = "8:#1900" + "Sequence" = "3:1" + "Attributes" = "3:1" + "Dialogs" + { + "{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_23F910A18BC2402DAFED0320959F69C5" + { + "Sequence" = "3:100" + "DisplayName" = "8:Welcome" + "UseDynamicProperties" = "11:TRUE" + "IsDependency" = "11:FALSE" + "SourcePath" = "8:\\VsdWelcomeDlg.wid" + "Properties" + { + "BannerBitmap" + { + "Name" = "8:BannerBitmap" + "DisplayName" = "8:#1001" + "Description" = "8:#1101" + "Type" = "3:8" + "ContextData" = "8:Bitmap" + "Attributes" = "3:4" + "Setting" = "3:0" + "UsePlugInResources" = "11:TRUE" + } + "CopyrightWarning" + { + "Name" = "8:CopyrightWarning" + "DisplayName" = "8:#1002" + "Description" = "8:#1102" + "Type" = "3:3" + "ContextData" = "8:" + "Attributes" = "3:0" + "Setting" = "3:1" + "Value" = "8:#1202" + "DefaultValue" = "8:#1202" + "UsePlugInResources" = "11:TRUE" + } + "Welcome" + { + "Name" = "8:Welcome" + "DisplayName" = "8:#1003" + "Description" = "8:#1103" + "Type" = "3:3" + "ContextData" = "8:" + "Attributes" = "3:0" + "Setting" = "3:1" + "Value" = "8:#1203" + "DefaultValue" = "8:#1203" + "UsePlugInResources" = "11:TRUE" + } + } + } + "{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_285DD2DB675346BEA1981B59FCF526E7" + { + "Sequence" = "3:300" + "DisplayName" = "8:Confirm Installation" + "UseDynamicProperties" = "11:TRUE" + "IsDependency" = "11:FALSE" + "SourcePath" = "8:\\VsdConfirmDlg.wid" + "Properties" + { + "BannerBitmap" + { + "Name" = "8:BannerBitmap" + "DisplayName" = "8:#1001" + "Description" = "8:#1101" + "Type" = "3:8" + "ContextData" = "8:Bitmap" + "Attributes" = "3:4" + "Setting" = "3:0" + "UsePlugInResources" = "11:TRUE" + } + } + } + "{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_9E00460782B64434AB9AE5C2FDF5F039" + { + "Sequence" = "3:200" + "DisplayName" = "8:Installation Folder" + "UseDynamicProperties" = "11:TRUE" + "IsDependency" = "11:FALSE" + "SourcePath" = "8:\\VsdFolderDlg.wid" + "Properties" + { + "BannerBitmap" + { + "Name" = "8:BannerBitmap" + "DisplayName" = "8:#1001" + "Description" = "8:#1101" + "Type" = "3:8" + "ContextData" = "8:Bitmap" + "Attributes" = "3:4" + "Setting" = "3:0" + "UsePlugInResources" = "11:TRUE" + } + "InstallAllUsersVisible" + { + "Name" = "8:InstallAllUsersVisible" + "DisplayName" = "8:#1059" + "Description" = "8:#1159" + "Type" = "3:5" + "ContextData" = "8:1;True=1;False=0" + "Attributes" = "3:0" + "Setting" = "3:0" + "Value" = "3:1" + "DefaultValue" = "3:1" + "UsePlugInResources" = "11:TRUE" + } + } + } + } + } + } + "MergeModule" + { + } + "ProjectOutput" + { + } + } +} diff --git a/InstallerExtras/MsiCreator/README.md b/InstallerExtras/MsiCreator/README.md new file mode 100644 index 0000000..138e040 --- /dev/null +++ b/InstallerExtras/MsiCreator/README.md @@ -0,0 +1,20 @@ +# How to create a MSI Installer for UniGetUI +Sometimes, when deploying software through GPO, msi installers are required. However, UniGetUI does not offer such installers by default. +In order to obtain a .msi installer, the following guide must be followed. + + +> [!Warning] +> When using MSI Installers, required dependencies will not be installed automatically. The deployer will need to ensure that the following requirements are met on target machines: +> - Microsoft Visual C++ Redistriutable 2015-2022 (x64) +> - Microsoft Edge WebView Runtime (x64) + +## Creating a MSI wrapper for the installer +1. Install [Visual Studio 2022](https://visualstudio.microsoft.com/es/downloads/) and the [Microsoft Visual Studio Installer Projects 2022 extension](https://marketplace.visualstudio.com/items?itemName=VisualStudioClient.MicrosoftVisualStudio2022InstallerProjects). +2. Clone this repository: +``` +git clone https://github.com/Devolutions/UniGetUI +``` +3. Download from [GitHub](https://github.com/Devolutions/UniGetUI/releases/) the installer version you wish to package as MSI. +4. Move the downloaded exe installer into `InstallerExtras/MsiCreator`. Ensure that the downloaded installer name is **exactly** `UniGetUI Installer.exe` +5. Open the Solution (`MsiInstallerWrapper.sln`) with Visual Studio and build the solution. The files `UniGetUISetup.msi` and `setup.exe` will be created. You may want to delete `setup.exe`, since it will not be used. +6. (Optional) Test that the file `UniGetUISetup.msi` installs UniGetUI properly. You should be now ready to go diff --git a/InstallerExtras/appsdk.exe b/InstallerExtras/appsdk.exe new file mode 100644 index 0000000..2465d7e Binary files /dev/null and b/InstallerExtras/appsdk.exe differ diff --git a/InstallerExtras/installer-banner.png b/InstallerExtras/installer-banner.png new file mode 100644 index 0000000..7c7450e Binary files /dev/null and b/InstallerExtras/installer-banner.png differ diff --git a/InstallerExtras/netcorecheck_x64.exe b/InstallerExtras/netcorecheck_x64.exe new file mode 100644 index 0000000..73ba728 Binary files /dev/null and b/InstallerExtras/netcorecheck_x64.exe differ diff --git a/InstallerExtras/unigetui-256.png b/InstallerExtras/unigetui-256.png new file mode 100644 index 0000000..003fe7e Binary files /dev/null and b/InstallerExtras/unigetui-256.png differ diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..0a19014 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2025 Martí Climent + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..d60f21c --- /dev/null +++ b/README.md @@ -0,0 +1,240 @@ +# WARNING: **wingetuicom** and **unigetuicom** are fake websites hosted by a third-party. please do NOT trust them +
+ +## Devolutions UniGetUI + +> [!IMPORTANT] +> **Major announcement:** UniGetUI has entered its next chapter with Devolutions. +> Read the [blog post](https://devolutions.net/blog/2026/03/unigetui-enters-its-next-chapter-with-devolutions/) and the [official press release](https://www.globenewswire.com/news-release/2026/03/10/3253012/0/en/Devolutions-Acquires-UniGetUI-Strengthening-Security-and-Enterprise-Readiness.html). + +[![Downloads](https://img.shields.io/github/downloads/Devolutions/UniGetUI/total?style=for-the-badge)](https://github.com/Devolutions/UniGetUI/releases/latest) +[![Release Version Badge](https://img.shields.io/github/v/release/Devolutions/UniGetUI?style=for-the-badge)](https://github.com/Devolutions/UniGetUI/releases) +[![Issues Badge](https://img.shields.io/github/issues/Devolutions/UniGetUI?style=for-the-badge)](https://github.com/Devolutions/UniGetUI/issues) +[![Closed Issues Badge](https://img.shields.io/github/issues-closed/Devolutions/UniGetUI?color=%238256d0&style=for-the-badge)](https://github.com/Devolutions/UniGetUI/issues?q=is%3Aissue+is%3Aclosed)
+UniGetUI is a Windows-first, intuitive GUI for the most common CLI package managers on Windows 10 and 11. Cross-platform builds are also available for macOS and Linux, with support for package managers including [WinGet](https://learn.microsoft.com/en-us/windows/package-manager/), [Scoop](https://scoop.sh/), [Chocolatey](https://chocolatey.org/), [Homebrew](https://brew.sh/), [APT](https://wiki.debian.org/Apt), [DNF](https://dnf.readthedocs.io/), [Pacman](https://wiki.archlinux.org/title/Pacman), [Flatpak](https://flatpak.org/), [Snap](https://snapcraft.io/), [pip](https://pypi.org/), [npm](https://www.npmjs.com/), [Bun](https://bun.sh/), [.NET Tool](https://learn.microsoft.com/en-us/dotnet/core/tools/dotnet-tool-install), [PowerShell Gallery](https://www.powershellgallery.com/), and more. +With UniGetUI, you can discover, install, update, and uninstall software from multiple package managers through one interface. + +![image](media/UniGetUI-Image.png) +View more screenshots [here](#screenshots) + +Check out the [Package Managers](#package-managers) section for more details! + +**Disclaimer:** UniGetUI is not affiliated with the package managers it integrates with. Packages are provided by third parties, so review sources and publishers before installation. + +![GitHub Actions Workflow Status](https://img.shields.io/github/actions/workflow/status/Devolutions/UniGetUI/dotnet-test.yml?branch=main&style=for-the-badge&label=Tests)
+ + +> [!CAUTION] +> **The official website for UniGetUI is [https://devolutions.net/unigetui/](https://devolutions.net/unigetui/).**
+> **The official source repository is [https://github.com/Devolutions/UniGetUI](https://github.com/Devolutions/UniGetUI).**
+> **Any other website should be considered unofficial, despite what they may say.** + +🔒 Found a security issue? Please report it via the [Devolutions security page](https://devolutions.net/security/) + +## Project stewardship + +UniGetUI was created by Martí Climent and is now maintained by Devolutions. The project remains free, open source, and MIT-licensed. Devolutions' stewardship brings long-term investment, structured governance, stronger security processes, and a roadmap for broader enterprise readiness while keeping UniGetUI standalone and community-driven. + +Read more in the [Devolutions announcement](https://devolutions.net/blog/2026/03/unigetui-enters-its-next-chapter-with-devolutions/) and the [official press release](https://www.globenewswire.com/news-release/2026/03/10/3253012/0/en/Devolutions-Acquires-UniGetUI-Strengthening-Security-and-Enterprise-Readiness.html). + +## Table of contents + - **[UniGetUI Homepage](https://devolutions.net/unigetui/)** + - [Table of contents](#table-of-contents) + - [Installation](#installation) + - [Update UniGetUI](#update-unigetui) + - [Project stewardship](#project-stewardship) + - [Features](#features) + - [Package Managers](#package-managers) + - [Translations](TRANSLATION.md) + - [Contributions](#contributions) + - [Screenshots](#screenshots) + - [Frequently Asked Questions](#frequently-asked-questions) + - [CLI reference](docs/CLI.md) + - [IPC reference](docs/IPC.md) + +## Installation +

There are multiple ways to install UniGetUI — choose whichever one you prefer!

+ +### Windows + +UniGetUI is primarily built for Windows. The Microsoft Store is the recommended installation method, but direct installer and package-manager options are also available. + +#### Microsoft Store installation (recommended) +alt_text + +#### Download the Windows installer: +![GitHub Release](https://img.shields.io/github/v/release/Devolutions/UniGetUI?style=for-the-badge) +Use the installer for the best Windows experience. `UniGetUI.Installer.exe` is the legacy/default x64 installer alias; use the explicit architecture downloads if needed. + +| Architecture | Installer | Portable `.zip` | +|---|---|---| +| x64 | [UniGetUI.Installer.x64.exe](https://github.com/Devolutions/UniGetUI/releases/latest/download/UniGetUI.Installer.x64.exe) ([default x64 alias](https://github.com/Devolutions/UniGetUI/releases/latest/download/UniGetUI.Installer.exe)) | [UniGetUI.x64.zip](https://github.com/Devolutions/UniGetUI/releases/latest/download/UniGetUI.x64.zip) | +| arm64 | [UniGetUI.Installer.arm64.exe](https://github.com/Devolutions/UniGetUI/releases/latest/download/UniGetUI.Installer.arm64.exe) | [UniGetUI.arm64.zip](https://github.com/Devolutions/UniGetUI/releases/latest/download/UniGetUI.arm64.zip) | + +#### Install via WinGet: +![WinGet Package Version](https://img.shields.io/winget/v/Devolutions.UniGetUI?style=for-the-badge) +```cmd +winget install --exact --id Devolutions.UniGetUI --source winget +``` + + +#### Install via Scoop: +![Scoop version](https://img.shields.io/scoop/v/unigetui?bucket=extras&style=for-the-badge) +```cmd +scoop bucket add extras +scoop install extras/unigetui +``` + +#### Install via Chocolatey: +![Chocolatey Version](https://img.shields.io/chocolatey/v/unigetui?style=for-the-badge) +```cmd +choco install unigetui +``` + +### NativeAOT builds + +Release packages are compiled with NativeAOT on all supported platforms (Windows, macOS, and Linux) for improved startup performance and a reduced attack surface. If you want to build the same configuration locally, the repository includes helper publish profiles and a script: + +```powershell +pwsh ./scripts/publish-nativeaot.ps1 -Platform x64 # or arm64 +``` + +This publishes `src/UniGetUI.Avalonia/UniGetUI.Avalonia.csproj` as a self-contained NativeAOT build into `artifacts/nativeaot/win-/`. + +### macOS + +macOS builds are available from GitHub Releases. Use the `.dmg` for the standard installer experience, or the `.tar.gz` archive for a portable app bundle. + +| Architecture | `.dmg` | `.tar.gz` | +|---|---|---| +| Apple silicon (arm64) | [UniGetUI.macos-arm64.dmg](https://github.com/Devolutions/UniGetUI/releases/latest/download/UniGetUI.macos-arm64.dmg) | [UniGetUI.macos-arm64.tar.gz](https://github.com/Devolutions/UniGetUI/releases/latest/download/UniGetUI.macos-arm64.tar.gz) | +| Intel (x64) | [UniGetUI.macos-x64.dmg](https://github.com/Devolutions/UniGetUI/releases/latest/download/UniGetUI.macos-x64.dmg) | [UniGetUI.macos-x64.tar.gz](https://github.com/Devolutions/UniGetUI/releases/latest/download/UniGetUI.macos-x64.tar.gz) | + +### Linux + +Linux builds are available from GitHub Releases. Use the `.deb` package for Debian/Ubuntu-based distributions, the `.rpm` package for Fedora/RHEL-based distributions, or the `.tar.gz` archive for a portable build. + +| Architecture | `.deb` | `.rpm` | `.tar.gz` | +|---|---|---|---| +| x64 | [Download](https://github.com/Devolutions/UniGetUI/releases/latest/download/UniGetUI.linux-x64.deb) | [Download](https://github.com/Devolutions/UniGetUI/releases/latest/download/UniGetUI.linux-x64.rpm) | [Download](https://github.com/Devolutions/UniGetUI/releases/latest/download/UniGetUI.linux-x64.tar.gz) | +| arm64 | [Download](https://github.com/Devolutions/UniGetUI/releases/latest/download/UniGetUI.linux-arm64.deb) | [Download](https://github.com/Devolutions/UniGetUI/releases/latest/download/UniGetUI.linux-arm64.rpm) | [Download](https://github.com/Devolutions/UniGetUI/releases/latest/download/UniGetUI.linux-arm64.tar.gz) | + +Install the package that matches your distribution and architecture: + +```bash +# Debian/Ubuntu-based distributions +sudo apt install ./UniGetUI.linux-x64.deb + +# Fedora/RHEL-based distributions +sudo dnf install ./UniGetUI.linux-x64.rpm + +# Portable archive +tar -xzf UniGetUI.linux-x64.tar.gz +./UniGetUI +``` + +Replace `x64` with `arm64` in the file name when using the arm64 build. + + +## Update UniGetUI + +UniGetUI has a built-in autoupdater. On Windows, it can also be updated like any other package within UniGetUI when installed through WinGet, Scoop, or Chocolatey. + + +## Features + + - Install, update, and remove software from your system easily at one click: UniGetUI combines packages from the most used package managers for your platform, including WinGet, Chocolatey, Scoop, Homebrew, APT, DNF, Pacman, Flatpak, Snap, Pip, npm, Bun, and .NET Tool. + - Discover new packages and filter them to easily find the package you want. + - View detailed metadata about any package before installing it. Get the direct download URL or the name of the publisher, as well as the size of the download. + - Easily bulk-install, update, or uninstall multiple packages at once selecting multiple packages before performing an operation + - Automatically update packages, or be notified when updates become available. Skip versions or completely ignore updates on a per-package basis. + - The system tray icon will also show the available updates and installed packages where supported, to efficiently update a program or remove a package from your system. + - Easily customize how and where packages are installed. Select different installation options and switches for each package. Install an older version or force a specific architecture where supported. \[But don't worry, those options will be saved for future updates for this package*] + - Share packages with your friends using generated package links. + - Export custom lists of packages to then import them to another machine and install those packages with previously specified, custom installation parameters. Setting up machines or configuring a specific software setup has never been easier. + - Backup your packages to a local file to easily recover your setup in a matter of seconds when migrating to a new machine* + +## Package Managers + +**NOTE:** All package managers do support basic install, update, and uninstall processes, as well as checking for updates, finding new packages, and retrieving details from a package. + +UniGetUI loads package managers based on the current platform. Windows builds include WinGet, Scoop, Chocolatey, Windows PowerShell, PowerShell 7, npm, Bun, pip, Cargo, .NET Tool, and vcpkg. macOS and Linux builds include Homebrew, PowerShell 7, npm, Bun, pip, Cargo, .NET Tool, and vcpkg; Linux builds also include distro-aware support for APT, DNF, Pacman, Snap, and Flatpak where applicable. + +![image](media/supported-managers.svg) + +✅: Supported on UniGetUI
+☑️: Not directly supported but can be easily achieved
+⚠️: May not work in some cases
+❌: Not supported by the Package Manager
+
+ +## Translations + +UniGetUI translations are maintained directly in this repository. For the current language list, completion status, and per-language contributor attributions, see [TRANSLATION.md](TRANSLATION.md). If you spot a translation issue or want to improve a locale, please open an issue or submit a pull request. + +## Screenshots + +![image](media/UniGetUI_1.png) + +![image](media/UniGetUI_2.png) + +![image](media/UniGetUI_3.png) + +![image](media/UniGetUI_4.png) + +![image](media/UniGetUI_5.png) + +![image](media/UniGetUI_6.png) + +![image](media/UniGetUI_7.png) + +![image](media/UniGetUI_8.png) + +![image](media/UniGetUI_9.png) + + +## Contributions +UniGetUI continues to grow thanks to its community of contributors. Devolutions is grateful to everyone who contributes code, translations, documentation, testing, and feedback to the project.

+ +[![Contributors](https://contrib.rocks/image?repo=Devolutions/UniGetUI)](https://github.com/Devolutions/UniGetUI/graphs/contributors)

+ + +## Frequently asked questions + +**Q: I am unable to install or upgrade a specific Winget package! What should I do?**
+ +A: This is likely an issue with Winget rather than UniGetUI. + +Please check if it's possible to install/upgrade the package through PowerShell or the Command Prompt by using the commands `winget upgrade` or `winget install`, depending on the situation (for example: `winget upgrade --id Microsoft.PowerToys`). + +If this doesn't work, consider asking for help at [Winget's project page](https://github.com/microsoft/winget-cli).
+ +# + +**Q: The name of a package is trimmed with ellipsis — how do I see its full name/id?**
+ +A: This is a known limitation of Winget. + +For more details, see this issue: https://github.com/microsoft/winget-cli/issues/2603.
+ +# + +**Q: My antivirus is telling me that UniGetUI is a virus! / My browser is blocking the download of UniGetUI!**
+ +A: A common reason apps (i.e., executables) get blocked and/or detected as a virus — even when there's nothing malicious about them, like in the case of UniGetUI — is because a relatively large amount of people are not using them. + +Combine that with the fact that you might be downloading something recently released, and blocking unknown apps is in many cases a good precaution to take to prevent actual malware. + +Since UniGetUI is open source and safe to use, whitelist the app in the settings of your antivirus/browser.
+ +# + +**Q: Are packages from third-party package managers safe?**
+ +A: UniGetUI and the package-manager maintainers aren't responsible for every package available for download. Packages are provided by third parties and can theoretically be compromised, regardless of whether they come from WinGet, Scoop, Chocolatey, Homebrew, APT, DNF, Pacman, Flatpak, Snap, or another source. + +Some package managers and repositories implement checks to mitigate the risks of downloading malware. Even so, it's recommended that you only download software from trusted publishers. + +## Command-line interface: + +Check out the CLI reference [here](docs/CLI.md) and the IPC reference [here](docs/IPC.md). diff --git a/README.wehub.md b/README.wehub.md new file mode 100644 index 0000000..5570be8 --- /dev/null +++ b/README.wehub.md @@ -0,0 +1,7 @@ +# WeHub 来源说明 + +- 原始项目:`Devolutions/UniGetUI` +- 原始仓库:https://github.com/Devolutions/UniGetUI +- 导入方式:上游默认分支的最新快照 +- 原作者、版权和许可证信息以原始仓库及本仓库 LICENSE 为准 +- 本文件仅用于记录来源,不代表 WeHub 是原项目作者 diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..43f97b7 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,5 @@ +# Security Policy + +## Reporting a Vulnerability + +Found a security issue? Please report it via the [Devolutions security page](https://devolutions.net/security/). diff --git a/TRANSLATION.md b/TRANSLATION.md new file mode 100644 index 0000000..a5299f3 --- /dev/null +++ b/TRANSLATION.md @@ -0,0 +1,156 @@ +# Translations + +UniGetUI includes translations for the languages listed below. + +This page lists the supported languages, each locale file, current completion status, and the credited contributors for each translation. + +If you would like to help improve a translation or report an issue, please open an issue or submit a pull request. + +Translation discussion and coordination also happens in [GitHub discussion #4510](https://github.com/Devolutions/UniGetUI/discussions/4510). + +## Language Coverage + +| Language | Code | Translated | File | +| :-- | :-- | :-- | :-- | +|   Afrikaans - Afrikaans | `af` | 100% | [lang_af.json](src/Languages/lang_af.json) | +|   Arabic - عربي‎ | `ar` | 100% | [lang_ar.json](src/Languages/lang_ar.json) | +|   Belarusian - беларуская | `be` | 100% | [lang_be.json](src/Languages/lang_be.json) | +|   Bulgarian - български | `bg` | 100% | [lang_bg.json](src/Languages/lang_bg.json) | +|   Bangla - বাংলা | `bn` | 100% | [lang_bn.json](src/Languages/lang_bn.json) | +|   Catalan - Català | `ca` | 100% | [lang_ca.json](src/Languages/lang_ca.json) | +|   Czech - Čeština | `cs` | 100% | [lang_cs.json](src/Languages/lang_cs.json) | +|   Danish - Dansk | `da` | 99% | [lang_da.json](src/Languages/lang_da.json) | +|   German - Deutsch | `de` | 100% | [lang_de.json](src/Languages/lang_de.json) | +|   Greek - Ελληνικά | `el` | 100% | [lang_el.json](src/Languages/lang_el.json) | +|   Estonian - Eesti | `et` | 100% | [lang_et.json](src/Languages/lang_et.json) | +|   English - English | `en` | 100% | [lang_en.json](src/Languages/lang_en.json) | +|   Esperanto - Esperanto | `eo` | 99% | [lang_eo.json](src/Languages/lang_eo.json) | +|   Spanish - Castellano | `es` | 100% | [lang_es.json](src/Languages/lang_es.json) | +|   Spanish (Mexico) | `es-MX` | 100% | [lang_es-MX.json](src/Languages/lang_es-MX.json) | +|   Persian - فارسی‎ | `fa` | 100% | [lang_fa.json](src/Languages/lang_fa.json) | +|   Finnish - Suomi | `fi` | 100% | [lang_fi.json](src/Languages/lang_fi.json) | +|   Filipino - Filipino | `fil` | 99% | [lang_fil.json](src/Languages/lang_fil.json) | +|   French - Français | `fr` | 100% | [lang_fr.json](src/Languages/lang_fr.json) | +|   Galician - Galego | `gl` | 99% | [lang_gl.json](src/Languages/lang_gl.json) | +|   Gujarati - ગુજરાતી | `gu` | 100% | [lang_gu.json](src/Languages/lang_gu.json) | +|   Hindi - हिंदी | `hi` | 100% | [lang_hi.json](src/Languages/lang_hi.json) | +|   Croatian - Hrvatski | `hr` | 100% | [lang_hr.json](src/Languages/lang_hr.json) | +|   Hebrew - עִבְרִית‎ | `he` | 100% | [lang_he.json](src/Languages/lang_he.json) | +|   Hungarian - Magyar | `hu` | 100% | [lang_hu.json](src/Languages/lang_hu.json) | +|   Italian - Italiano | `it` | 100% | [lang_it.json](src/Languages/lang_it.json) | +|   Indonesian - Bahasa Indonesia | `id` | 100% | [lang_id.json](src/Languages/lang_id.json) | +|   Japanese - 日本語 | `ja` | 100% | [lang_ja.json](src/Languages/lang_ja.json) | +|   Georgian - ქართული | `ka` | 100% | [lang_ka.json](src/Languages/lang_ka.json) | +|   Kannada - ಕನ್ನಡ | `kn` | 100% | [lang_kn.json](src/Languages/lang_kn.json) | +|   Korean - 한국어 | `ko` | 100% | [lang_ko.json](src/Languages/lang_ko.json) | +|   Kurdish - کوردی | `ku` | 100% | [lang_ku.json](src/Languages/lang_ku.json) | +|   Lithuanian - Lietuvių | `lt` | 100% | [lang_lt.json](src/Languages/lang_lt.json) | +|   Macedonian - Македонски | `mk` | 100% | [lang_mk.json](src/Languages/lang_mk.json) | +|   Marathi - मराठी | `mr` | 100% | [lang_mr.json](src/Languages/lang_mr.json) | +|   Norwegian (bokmål) | `nb` | 100% | [lang_nb.json](src/Languages/lang_nb.json) | +|   Norwegian (nynorsk) | `nn` | 100% | [lang_nn.json](src/Languages/lang_nn.json) | +|   Dutch - Nederlands | `nl` | 100% | [lang_nl.json](src/Languages/lang_nl.json) | +|   Polish - Polski | `pl` | 100% | [lang_pl.json](src/Languages/lang_pl.json) | +|   Portuguese (Brazil) | `pt_BR` | 100% | [lang_pt_BR.json](src/Languages/lang_pt_BR.json) | +|   Portuguese (Portugal) | `pt_PT` | 100% | [lang_pt_PT.json](src/Languages/lang_pt_PT.json) | +|   Romanian - Română | `ro` | 100% | [lang_ro.json](src/Languages/lang_ro.json) | +|   Russian - Русский | `ru` | 100% | [lang_ru.json](src/Languages/lang_ru.json) | +|   Sanskrit - संस्कृत भाषा | `sa` | 100% | [lang_sa.json](src/Languages/lang_sa.json) | +|   Slovak - Slovenčina | `sk` | 100% | [lang_sk.json](src/Languages/lang_sk.json) | +|   Serbian - Srpski | `sr` | 100% | [lang_sr.json](src/Languages/lang_sr.json) | +|   Albanian - Shqip | `sq` | 100% | [lang_sq.json](src/Languages/lang_sq.json) | +|   Sinhala - සිංහල | `si` | 100% | [lang_si.json](src/Languages/lang_si.json) | +|   Slovene - Slovenščina | `sl` | 100% | [lang_sl.json](src/Languages/lang_sl.json) | +|   Swedish - Svenska | `sv` | 100% | [lang_sv.json](src/Languages/lang_sv.json) | +|   Tamil - தமிழ் | `ta` | 100% | [lang_ta.json](src/Languages/lang_ta.json) | +|   Tagalog - Tagalog | `tl` | 100% | [lang_tl.json](src/Languages/lang_tl.json) | +|   Thai - ภาษาไทย | `th` | 100% | [lang_th.json](src/Languages/lang_th.json) | +|   Turkish - Türkçe | `tr` | 100% | [lang_tr.json](src/Languages/lang_tr.json) | +|   Ukrainian - Українська | `uk` | 100% | [lang_uk.json](src/Languages/lang_uk.json) | +|   Urdu - اردو | `ur` | 100% | [lang_ur.json](src/Languages/lang_ur.json) | +|   Vietnamese - Tiếng Việt | `vi` | 100% | [lang_vi.json](src/Languages/lang_vi.json) | +|   Simplified Chinese (China) | `zh_CN` | 100% | [lang_zh_CN.json](src/Languages/lang_zh_CN.json) | +|   Traditional Chinese (Taiwan) | `zh_TW` | 100% | [lang_zh_TW.json](src/Languages/lang_zh_TW.json) | + +## Contributors + +We are grateful to everyone who contributes translations to UniGetUI. Contributor credits are sourced from [Translators.json](src/Languages/Data/Translators.json). If you would like to be added to or removed from the list for a particular language, please open a pull request. + +| Language | Code | Contributor(s) | +| :-- | :-- | --- | +|   Afrikaans - Afrikaans | `af` | Hendrik Bezuidenhout | +|   Arabic - عربي‎ | `ar` | [Abdu11ahAS](https://github.com/Abdu11ahAS), [Abdullah-Dev115](https://github.com/Abdullah-Dev115), [AbdullahAlousi](https://github.com/AbdullahAlousi), [bassuny3003](https://github.com/bassuny3003), [DaRandomCube](https://github.com/DaRandomCube), [FancyCookin](https://github.com/FancyCookin), [IFrxo](https://github.com/IFrxo), [mo9a7i](https://github.com/mo9a7i) | +|   Belarusian - беларуская | `be` | [bthos](https://github.com/bthos) | +|   Bulgarian - български | `bg` | Nikolay Naydenov, Vasil Kolev | +|   Bangla - বাংলা | `bn` | [fluentmoheshwar](https://github.com/fluentmoheshwar), [itz-rj-here](https://github.com/itz-rj-here), Mushfiq Iqbal Rayon, Nilavra Bhattacharya, [samiulislamsharan](https://github.com/samiulislamsharan) | +|   Catalan - Català | `ca` | [marticliment](https://github.com/marticliment) | +|   Czech - Čeština | `cs` | [mlisko](https://github.com/mlisko), [panther7](https://github.com/panther7), [xtorlukas](https://github.com/xtorlukas) | +|   Danish - Dansk | `da` | [AAUCrisp](https://github.com/AAUCrisp), [bstordrup](https://github.com/bstordrup), [mikkolukas](https://github.com/mikkolukas), [siewers](https://github.com/siewers), [yrjarv](https://github.com/yrjarv) | +|   German - Deutsch | `de` | [1270o1](https://github.com/1270o1), [AbsolutLeon](https://github.com/AbsolutLeon), [alxhu-dev](https://github.com/alxhu-dev), [Araxxas](https://github.com/Araxxas), [arnowelzel](https://github.com/arnowelzel), [CanePlayz](https://github.com/CanePlayz), [Datacra5H](https://github.com/Datacra5H), [ebnater](https://github.com/ebnater), [lucadsign](https://github.com/lucadsign), [martinwilco](https://github.com/martinwilco), [michaelmairegger](https://github.com/michaelmairegger), [Seeloewen](https://github.com/Seeloewen), [TheScarfix](https://github.com/TheScarfix), [tkohlmeier](https://github.com/tkohlmeier), [VfBFan](https://github.com/VfBFan), [Xeraox3335](https://github.com/Xeraox3335), [yrjarv](https://github.com/yrjarv) | +|   Greek - Ελληνικά | `el` | [antwnhsx](https://github.com/antwnhsx), [panos78](https://github.com/panos78), [seijind](https://github.com/seijind), [thunderstrike116](https://github.com/thunderstrike116), [wobblerrrgg](https://github.com/wobblerrrgg) | +|   Estonian - Eesti | `et` | [artjom3729](https://github.com/artjom3729) | +|   English - English | `en` | [lucadsign](https://github.com/lucadsign), [marticliment](https://github.com/marticliment), [ppvnf](https://github.com/ppvnf) | +|   Esperanto - Esperanto | `eo` | | +|   Spanish - Castellano | `es` | [apazga](https://github.com/apazga), [dalbitresb12](https://github.com/dalbitresb12), [evaneliasyoung](https://github.com/evaneliasyoung), [guplem](https://github.com/guplem), [JMoreno97](https://github.com/JMoreno97), [marticliment](https://github.com/marticliment), [P10Designs](https://github.com/P10Designs), [rubnium](https://github.com/rubnium), [uKER](https://github.com/uKER) | +|   Spanish (Mexico) | `es-MX` | [apazga](https://github.com/apazga), [dalbitresb12](https://github.com/dalbitresb12), [evaneliasyoung](https://github.com/evaneliasyoung), [guplem](https://github.com/guplem), [JMoreno97](https://github.com/JMoreno97), [marticliment](https://github.com/marticliment), [P10Designs](https://github.com/P10Designs), [rubnium](https://github.com/rubnium), [uKER](https://github.com/uKER) | +|   Persian - فارسی‎ | `fa` | [ehinium](https://github.com/ehinium), [MobinMardi](https://github.com/MobinMardi) | +|   Finnish - Suomi | `fi` | [simakuutio](https://github.com/simakuutio) | +|   Filipino - Filipino | `fil` | [infyProductions](https://github.com/infyProductions) | +|   French - Français | `fr` | BreatFR, [Entropiness](https://github.com/Entropiness), Evans Costa, [PikPakPik](https://github.com/PikPakPik), Rémi Guerrero, [W1L7dev](https://github.com/W1L7dev) | +|   Galician - Galego | `gl` | | +|   Gujarati - ગુજરાતી | `gu` | | +|   Hindi - हिंदी | `hi` | [Ashu-r](https://github.com/Ashu-r), [atharva_xoxo](https://github.com/atharva_xoxo), [satanarious](https://github.com/satanarious) | +|   Croatian - Hrvatski | `hr` | [AndrejFeher](https://github.com/AndrejFeher), Ivan Nuić, Stjepan Treger | +|   Hebrew - עִבְרִית‎ | `he` | [maximunited](https://github.com/maximunited), Oryan Hassidim | +|   Hungarian - Magyar | `hu` | [gidano](https://github.com/gidano) | +|   Italian - Italiano | `it` | David Senoner, [giacobot](https://github.com/giacobot), [maicol07](https://github.com/maicol07), [mapi68](https://github.com/mapi68), [mrfranza](https://github.com/mrfranza), Rosario Di Mauro | +|   Indonesian - Bahasa Indonesia | `id` | [agrinfauzi](https://github.com/agrinfauzi), [arthackrc](https://github.com/arthackrc), [joenior](https://github.com/joenior), [nrarfn](https://github.com/nrarfn) | +|   Japanese - 日本語 | `ja` | [anmoti](https://github.com/anmoti), [BHCrusher1](https://github.com/BHCrusher1), [nob-swik](https://github.com/nob-swik), Nobuhiro Shintaku, sho9029, [tacostea](https://github.com/tacostea), Yuki Takase | +|   Georgian - ქართული | `ka` | [marticliment](https://github.com/marticliment), [ppvnf](https://github.com/ppvnf) | +|   Kannada - ಕನ್ನಡ | `kn` | [skanda890](https://github.com/skanda890) | +|   Korean - 한국어 | `ko` | [VenusGirl](https://github.com/VenusGirl) | +|   Kurdish - کوردی | `ku` | | +|   Lithuanian - Lietuvių | `lt` | Džiugas Januševičius, [dziugas1959](https://github.com/dziugas1959), [martyn3z](https://github.com/martyn3z) | +|   Macedonian - Македонски | `mk` | LordDeatHunter | +|   Marathi - मराठी | `mr` | | +|   Norwegian (bokmål) | `nb` | [DandelionSprout](https://github.com/DandelionSprout), [mikaelkw](https://github.com/mikaelkw), [yrjarv](https://github.com/yrjarv) | +|   Norwegian (nynorsk) | `nn` | [yrjarv](https://github.com/yrjarv) | +|   Dutch - Nederlands | `nl` | [abbydiode](https://github.com/abbydiode), [CateyeNL](https://github.com/CateyeNL), [mia-riezebos](https://github.com/mia-riezebos), [Stephan-P](https://github.com/Stephan-P) | +|   Polish - Polski | `pl` | [AdiMajsterek](https://github.com/AdiMajsterek), [GrzegorzKi](https://github.com/GrzegorzKi), [H4qu3r](https://github.com/H4qu3r), [ikarmus2001](https://github.com/ikarmus2001), [juliazero](https://github.com/juliazero), [KamilZielinski](https://github.com/KamilZielinski), [kwiateusz](https://github.com/kwiateusz), [RegularGvy13](https://github.com/RegularGvy13), [szumsky](https://github.com/szumsky), [ThePhaseless](https://github.com/ThePhaseless) | +|   Portuguese (Brazil) | `pt_BR` | [maisondasilva](https://github.com/maisondasilva), [ppvnf](https://github.com/ppvnf), [renanalencar](https://github.com/renanalencar), [Rodrigo-Matsuura](https://github.com/Rodrigo-Matsuura), [thiagojramos](https://github.com/thiagojramos), [wanderleihuttel](https://github.com/wanderleihuttel) | +|   Portuguese (Portugal) | `pt_PT` | [100Nome](https://github.com/100Nome), [NimiGames68](https://github.com/NimiGames68), [PoetaGA](https://github.com/PoetaGA), [Putocoroa](https://github.com/Putocoroa), [Tiago_Ferreira](https://github.com/Tiago_Ferreira) | +|   Romanian - Română | `ro` | [David735453](https://github.com/David735453), [lucadsign](https://github.com/lucadsign), [SilverGreen93](https://github.com/SilverGreen93), TZACANEL | +|   Russian - Русский | `ru` | Alexander, [bropines](https://github.com/bropines), [Denisskas](https://github.com/Denisskas), [DvladikD](https://github.com/DvladikD), [flatron4eg](https://github.com/flatron4eg), Gleb Saygin, [katrovsky](https://github.com/katrovsky), Sergey, [sklart](https://github.com/sklart), [solarscream](https://github.com/solarscream), [tapnisu](https://github.com/tapnisu), [Vertuhai](https://github.com/Vertuhai) | +|   Sanskrit - संस्कृत भाषा | `sa` | [skanda890](https://github.com/skanda890) | +|   Slovak - Slovenčina | `sk` | [david-kucera](https://github.com/david-kucera), [Luk164](https://github.com/Luk164) | +|   Serbian - Srpski | `sr` | [daVinci13](https://github.com/daVinci13), [igorskyflyer](https://github.com/igorskyflyer), [momcilovicluka](https://github.com/momcilovicluka) | +|   Albanian - Shqip | `sq` | [RDN000](https://github.com/RDN000) | +|   Sinhala - සිංහල | `si` | [SashikaSandeepa](https://github.com/SashikaSandeepa), [Savithu-s3](https://github.com/Savithu-s3), [ttheek](https://github.com/ttheek) | +|   Slovene - Slovenščina | `sl` | [rumplin](https://github.com/rumplin) | +|   Swedish - Svenska | `sv` | [curudel](https://github.com/curudel), [Hi-there-how-are-u](https://github.com/Hi-there-how-are-u), [kakmonster](https://github.com/kakmonster), [umeaboy](https://github.com/umeaboy) | +|   Tamil - தமிழ் | `ta` | [nochilli](https://github.com/nochilli) | +|   Tagalog - Tagalog | `tl` | lasersPew, [znarfm](https://github.com/znarfm) | +|   Thai - ภาษาไทย | `th` | [apaeisara](https://github.com/apaeisara), [dulapahv](https://github.com/dulapahv), [hanchain](https://github.com/hanchain), [rikoprushka](https://github.com/rikoprushka), [vestearth](https://github.com/vestearth) | +|   Turkish - Türkçe | `tr` | [ahmetozmtn](https://github.com/ahmetozmtn), [anzeralp](https://github.com/anzeralp), [BerkeA111](https://github.com/BerkeA111), [dogancanyr](https://github.com/dogancanyr), [gokberkgs](https://github.com/gokberkgs) | +|   Ukrainian - Українська | `uk` | Alex Logvin, Artem Moldovanenko, Operator404, [Taron-art](https://github.com/Taron-art), [Vertuhai](https://github.com/Vertuhai) | +|   Urdu - اردو | `ur` | [digitio](https://github.com/digitio), [digitpk](https://github.com/digitpk), [hamzaharoon1314](https://github.com/hamzaharoon1314) | +|   Vietnamese - Tiếng Việt | `vi` | [aethervn2309](https://github.com/aethervn2309), [legendsjoon](https://github.com/legendsjoon), [txavlog](https://github.com/txavlog), [vanlongluuly](https://github.com/vanlongluuly) | +|   Simplified Chinese (China) | `zh_CN` | Aaron Liu, [adfnekc](https://github.com/adfnekc), [Ardenet](https://github.com/Ardenet), [arthurfsy2](https://github.com/arthurfsy2), [bai0012](https://github.com/bai0012), BUGP Association, ciaran, CnYeSheng, Cololi, [dongfengweixiao](https://github.com/dongfengweixiao), [enKl03B](https://github.com/enKl03B), [seanyu0](https://github.com/seanyu0), [Sigechaishijie](https://github.com/Sigechaishijie), [SpaceTimee](https://github.com/SpaceTimee), [xiaopangju](https://github.com/xiaopangju), Yisme | +|   Traditional Chinese (Taiwan) | `zh_TW` | Aaron Liu, [CnYeSheng](https://github.com/CnYeSheng), Cololi, [enKl03B](https://github.com/enKl03B), [Henryliu880922](https://github.com/Henryliu880922), [MINAX2U](https://github.com/MINAX2U), [StarsShine11904](https://github.com/StarsShine11904), [yrctw](https://github.com/yrctw) | + +## Maintaining Translation Data + +The tables in this document are generated from the checked-in translation metadata. Completion is computed against the active English keys in `lang_en.json`; keys below the legacy boundary marker are excluded from the percentage. + +To refresh translated percentages, contributor metadata, and this document after locale changes, run: + +```powershell +pwsh ./scripts/translation/Sync-TranslationMetadata.ps1 -AllLanguages -UpdateTranslationDoc +``` + +To inspect the current status without modifying files, run: + +```powershell +pwsh ./scripts/translation/Get-TranslationStatus.ps1 -OutputFormat Markdown -OnlyIncomplete +``` + diff --git a/UniGetUI.iss b/UniGetUI.iss new file mode 100644 index 0000000..b29b83f --- /dev/null +++ b/UniGetUI.iss @@ -0,0 +1,352 @@ +; Script generated by the Inno Setup Script Wizard. +; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES! + +#define MyAppVersion "3.3.7" +#define MyAppName "UniGetUI" +#define MyAppPublisher "Devolutions Inc." +#define MyAppURL "https://github.com/Devolutions/UniGetUI" +#define MyAppExeName "UniGetUI.exe" +#ifndef InstallerCompression +#define InstallerCompression "lzma" +#endif + +#define public Dependency_Path_NetCoreCheck "InstallerExtras\" +#include "InstallerExtras\CodeDependencies.iss" + + +[Setup] +; NOTE: The value of AppId uniquely identifies this application. Do not use the same AppId value in installers for other applications. +; (To generate a new GUID, click Tools | Generate GUID inside the IDE.) +UninstallDisplayName="UniGetUI" +AppId={{889610CC-4337-4BDB-AC3B-4F21806C0BDE} +AppName={#MyAppName} +AppVersion={#MyAppVersion} +AppVerName={#MyAppName} {#MyAppVersion} +AppPublisher={#MyAppPublisher} +AppPublisherURL="https://devolutions.net/unigetui/" +AppSupportURL={#MyAppURL} +AppUpdatesURL={#MyAppURL} +VersionInfoVersion=3.3.7.0 +VersionInfoProductVersion=3.3.7.0 +DefaultDirName="{autopf64}\UniGetUI" +DisableProgramGroupPage=yes +DisableDirPage=no +DirExistsWarning=no +; Force-close any process holding files we overwrite (backstop for the kill in PrepareToInstall). +CloseApplications=force +CloseApplicationsFilter=*.exe,*.dll +RestartApplications=no +; Default to per-user install mode and let the dialog opt into all-users installs when needed. +PrivilegesRequired=lowest +PrivilegesRequiredOverridesAllowed=dialog +OutputBaseFilename=UniGetUI Installer +OutputDir=. +; Comment line below to disable digital signature of installer +SignTool=azsign + +SignedUninstaller=yes +SignedUninstallerDir=InstallerExtras\ +MinVersion=10.0 +SetupIconFile=src\SharedAssets\Assets\Images\icon.ico +UninstallDisplayIcon={app}\UniGetUI.exe +Compression={#InstallerCompression} +SolidCompression=yes +WizardStyle=modern dynamic +WizardImageFile=InstallerExtras\installer-banner.png +WizardImageFileDynamicDark=InstallerExtras\installer-banner.png +WizardSmallImageFile=InstallerExtras\unigetui-256.png +WizardSmallImageFileDynamicDark=InstallerExtras\unigetui-256.png +DisableWelcomePage=no +AllowUNCPath=no +UsePreviousTasks=yes +UsePreviousPrivileges=yes +UsePreviousAppDir=yes +ChangesEnvironment=yes +RestartIfNeededByRun=no +Uninstallable=WizardIsTaskSelected('regularinstall') +AppModifyPath="{app}\UniGetUI.Installer.exe" /silent /NoDeployInstaller + + +[Languages] +Name: "English"; MessagesFile: "compiler:Default.isl" +Name: "Armenian"; MessagesFile: "compiler:Languages\Armenian.isl" +Name: "BrazilianPortuguese"; MessagesFile: "compiler:Languages\BrazilianPortuguese.isl" +Name: "Catalan"; MessagesFile: "compiler:Languages\Catalan.isl" +Name: "Corsican"; MessagesFile: "compiler:Languages\Corsican.isl" +Name: "Czech"; MessagesFile: "compiler:Languages\Czech.isl" +Name: "Danish"; MessagesFile: "compiler:Languages\Danish.isl" +Name: "Dutch"; MessagesFile: "compiler:Languages\Dutch.isl" +Name: "Finnish"; MessagesFile: "compiler:Languages\Finnish.isl" +Name: "French"; MessagesFile: "compiler:Languages\French.isl" +Name: "German"; MessagesFile: "compiler:Languages\German.isl" +Name: "Hebrew"; MessagesFile: "compiler:Languages\Hebrew.isl" +;Name: "Icelandic"; MessagesFile: "compiler:Languages\Icelandic.isl" +Name: "Italian"; MessagesFile: "compiler:Languages\Italian.isl" +Name: "Japanese"; MessagesFile: "compiler:Languages\Japanese.isl" +Name: "Korean"; MessagesFile: "compiler:Languages\Korean.isl" +Name: "Norwegian"; MessagesFile: "compiler:Languages\Norwegian.isl" +Name: "Polish"; MessagesFile: "compiler:Languages\Polish.isl" +Name: "Portuguese"; MessagesFile: "compiler:Languages\Portuguese.isl" +Name: "Russian"; MessagesFile: "compiler:Languages\Russian.isl" +Name: "Slovenian"; MessagesFile: "compiler:Languages\Slovenian.isl" +Name: "Spanish"; MessagesFile: "compiler:Languages\Spanish.isl" +Name: "Turkish"; MessagesFile: "compiler:Languages\Turkish.isl" +Name: "Ukrainian"; MessagesFile: "compiler:Languages\Ukrainian.isl" + +; Include installer's messages +#include "InstallerExtras\CustomMessages.iss" + +[Code] +var + PreserveAutostartDisabled: Boolean; + +// StartupApproved stores the on/off state in the first byte's low bit (03 = off). +function IsAutostartDisabledByUser: Boolean; +var + Data: AnsiString; +begin + Result := False; + if RegQueryBinaryValue(HKEY_CURRENT_USER, + 'Software\Microsoft\Windows\CurrentVersion\Explorer\StartupApproved\Run', + 'WingetUI', Data) then + Result := (Length(Data) >= 1) and ((Ord(Data[1]) and 1) = 1); +end; + +procedure InitializeWizard; +begin + WizardForm.Bevel.Visible := False; + WizardForm.Bevel1.Visible := True; +end; + +// Kills all instances of an image and loops until none remain (taskkill returns 0 while killing, 128 when none left). +procedure TaskKillWait(FileName: String); +var + ResultCode, Attempts: Integer; +begin + Attempts := 0; + repeat + if not Exec('taskkill.exe', '/f /im "' + FileName + '"', '', SW_HIDE, + ewWaitUntilTerminated, ResultCode) then + Break; + if ResultCode <> 0 then + Break; + Sleep(500); + Attempts := Attempts + 1; + until Attempts >= 10; +end; + +procedure KillRunningApps; +begin + TaskKillWait('WingetUI.exe'); + TaskKillWait('UniGetUI.exe'); + TaskKillWait('UniGetUI.Avalonia.exe'); + // Elevator (gsudo cache) and pinget live in {app} and lock their own files. + TaskKillWait('UniGetUI Elevator.exe'); + TaskKillWait('pinget.exe'); + Sleep(1000); // let the OS release file handles before copying + +end; + +function GetCurrentProcessId: Cardinal; external 'GetCurrentProcessId@kernel32.dll stdcall'; + +function UpdateMarkerPath(): String; +begin + Result := ExpandConstant('{app}\.unigetui-update-in-progress'); +end; + +// Marker holds our PID; the app blocks only while this installer runs. Name MUST match UpdateInProgressGuard.MarkerFileName. +procedure WriteUpdateMarker; +var + Pid: Int64; +begin + ForceDirectories(ExpandConstant('{app}')); + Pid := GetCurrentProcessId; + SaveStringToFile(UpdateMarkerPath(), IntToStr(Pid), False); +end; + +procedure RemoveUpdateMarker; +begin + DeleteFile(UpdateMarkerPath()); +end; + +// Runs before any file is copied: shut everything down, then mark the copy window. +function PrepareToInstall(var NeedsRestart: Boolean): String; +begin + // Capture before [Registry] rewrites the Run key, so updates keep the user's choice. + PreserveAutostartDisabled := IsAutostartDisabledByUser; + KillRunningApps; + WriteUpdateMarker; + Result := ''; +end; + +// Clear the marker once the copy is done, before the post-install launch. +procedure CurStepChanged(CurStep: TSetupStep); +begin + if CurStep = ssPostInstall then + RemoveUpdateMarker; +end; + +function CmdLineParamExists(const Value: string): Boolean; +var + I: Integer; +begin + Result := False; + for I := 1 to ParamCount do + if CompareText(ParamStr(I), Value) = 0 then + begin + Result := True; + Exit; + end; +end; + +function IsMSStoreInstall: Boolean; +begin + Result := CmdLineParamExists('/MSStore'); +end; + +function ShouldInstallVCRedist: Boolean; +begin + Result := not (CmdLineParamExists('/NoVCRedist') or IsMSStoreInstall); +end; + +function ShouldInstallEdgeWebView: Boolean; +begin + Result := not (CmdLineParamExists('/NoEdgeWebView') or IsMSStoreInstall); +end; + +function ShouldLaunchAfterInstall: Boolean; +begin + Result := not (CmdLineParamExists('/NoAutoStart') or IsMSStoreInstall); +end; + +function ShouldSuppressRunOnStartup: Boolean; +begin + Result := CmdLineParamExists('/NoRunOnStartup') or IsMSStoreInstall or PreserveAutostartDisabled; +end; + +var CustomExitCode: integer; + +procedure ExitProcess(exitCode:integer); + external 'ExitProcess@kernel32.dll stdcall'; + +procedure DeinitializeSetup(); +begin + RemoveUpdateMarker; // also clear on abort, before ssPostInstall + + if (CustomExitCode <> 0) then + begin + DelTree(ExpandConstant('{tmp}'), True, True, True); + ExitProcess(0); + end; +end; + +function IsCharValid(Value: Char): Boolean; +begin + Result := Ord(Value) <= $007F; +end; + +function IsDirNameValid(const Value: string): Boolean; +var + I: Integer; +begin + Result := False; + for I := 1 to Length(Value) do + if not IsCharValid(Value[I]) then + Exit; + Result := True; +end; + +function NextButtonClick(CurPageID: Integer): Boolean; +begin + Result := True; + + if (CurPageID = wpSelectDir) and + not IsDirNameValid(WizardForm.DirEdit.Text) then + begin + Result := False; + MsgBox('There is an invalid character in the selected install location. ' + + 'Install location cannot contain special characters. ' + + 'Please input a valid path to continue, such as '+ExpandConstant('{commonpf64}')+'\UniGetUI', mbError, MB_OK); + end; +end; + +function InitializeSetup: Boolean; +begin + try + if ShouldInstallVCRedist then + begin + Dependency_AddVC2015To2022; + end; + if ShouldInstallEdgeWebView then + begin + Dependency_AddWebView2; + end; + Result := True; + except + Result := True; + end; +end; + + +[Tasks] +Name: "portableinstall"; Description: "{cm:PortInst}"; GroupDescription: "{cm:InstallType}"; Flags: unchecked exclusive +Name: "regularinstall"; Description: "{cm:RegInst}"; GroupDescription: "{cm:InstallType}"; Flags: exclusive +Name: "regularinstall\startmenuicon"; Description: "{cm:RegStartMmenuIcon}"; GroupDescription: "{cm:ShCuts}"; +Name: "regularinstall\desktopicon"; Description: "{cm:RegDesktopIcon}"; GroupDescription: "{cm:ShCuts}"; + +[Registry] +Root: HKCU; Subkey: "SOFTWARE\Microsoft\Windows\CurrentVersion\Run"; ValueType: string; ValueName: "WingetUI"; ValueData: """{app}\UniGetUI.exe"" --daemon"; Flags: uninsdeletevalue noerror; Tasks: regularinstall; +Root: HKCU; Subkey: "Software\Microsoft\Windows\CurrentVersion\Explorer\StartupApproved\Run"; ValueType: binary; ValueName: "WingetUI"; ValueData: "03"; Flags: uninsdeletevalue; Tasks: regularinstall; Check: ShouldSuppressRunOnStartup; + +// Register the unigetui:// deep link +Root: HKA; Subkey: "Software\Classes\unigetui"; ValueType: "string"; ValueData: "URL:UniGetUI Protocol"; Flags: uninsdeletekey; Tasks: regularinstall; +Root: HKA; Subkey: "Software\Classes\unigetui"; ValueType: "string"; ValueName: "URL Protocol"; ValueData: ""; Tasks: regularinstall; +Root: HKA; Subkey: "Software\Classes\unigetui\DefaultIcon"; ValueType: "string"; ValueData: "{app}\{#MyAppExeName},0"; Tasks: regularinstall; +Root: HKA; Subkey: "Software\Classes\unigetui\shell\open\command"; ValueType: "string"; ValueData: """{app}\{#MyAppExeName}"" ""%1"""; Tasks: regularinstall; + +// Register the .ubundle file type +Root: HKA; Subkey: "Software\Classes\.ubundle"; ValueType: string; ValueData: "UniGetUI.PackageBundle"; Flags: uninsdeletekey; Tasks: regularinstall; +Root: HKA; Subkey: "Software\Classes\UniGetUI.PackageBundle"; ValueType: string; ValueData: {cm:PackageBundleName}; Flags: uninsdeletekey; Tasks: regularinstall; +Root: HKA; Subkey: "Software\Classes\UniGetUI.PackageBundle\DefaultIcon"; ValueType: string; ValueData: "{app}\{#MyAppExeName},0"; Flags: uninsdeletekey; Tasks: regularinstall; +Root: HKA; Subkey: "Software\Classes\UniGetUI.PackageBundle\shell\open\command"; ValueType: string; ValueData: """{app}\{#MyAppExeName}"" ""%1"""; Flags: uninsdeletekey; Tasks: regularinstall; + + +[InstallDelete] +Type: filesandordirs; Name: "{app}\Avalonia" +Type: filesandordirs; Name: "{app}\Assets" +Type: files; Name: "{app}\WingetUI.exe" +Type: files; Name: "{app}\UniGetUI.Avalonia.exe" +Type: files; Name: "{app}\*.dll" +Type: files; Name: "{app}\*.pdb" +Type: files; Name: "{app}\*.pri" +Type: files; Name: "{app}\*.xbf" +Type: files; Name: "{app}\*.json" + +[Files] +; Deploy installer for autorepair jobs (unless disabled) +Source: "{srcexe}"; DestDir: "{app}"; DestName: "UniGetUI.Installer.exe"; Flags: external ignoreversion; Tasks: regularinstall; Check: not CmdLineParamExists('/NoDeployInstaller'); +; Deploy integrity tree +Source: "unigetui_bin\IntegrityTree.json"; DestDir: "{app}"; Flags: createallsubdirs ignoreversion recursesubdirs; +; Deploy executable files (running instances already killed in PrepareToInstall). +Source: "unigetui_bin\{#MyAppExeName}"; DestDir: "{app}"; Flags: ignoreversion; +Source: "unigetui_bin\*"; DestDir: "{app}"; Flags: createallsubdirs ignoreversion recursesubdirs; +; Make installation portable (if required) +Source: "InstallerExtras\ForceUniGetUIPortable"; DestDir: "{app}"; Tasks: portableinstall + + +[Icons] +Name: "{autostartmenu}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: regularinstall\startmenuicon +Name: "{autodesktop}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: regularinstall\desktopicon + +[Run] +; Filename: "powershell.exe"; Parameters: "-ExecutionPolicy Bypass -File -NonInteractive ""{tmp}\EnsureWinGet.ps1"""; StatusMsg: "Ensuring WinGet is properly installed... (this may take a while)"; WorkingDir: {app}; Check: not CmdLineParamExists('/NoWinGet'); Flags: runhidden +Filename: "{app}\{#MyAppExeName}"; Description: "{cm:LaunchProgram,{#StringChange(MyAppName, '&', '&&')}}"; Flags: runasoriginaluser nowait postinstall; Check: ShouldLaunchAfterInstall; +Filename: "{app}\{#MyAppExeName}"; Parameters: "--migrate-wingetui-to-unigetui"; StatusMsg: "Removing old icons..."; + + +[UninstallRun] +; Remove WingetUI Notification registries +; Filename: "{app}\{#MyAppExeName}"; Parameters: "--uninstall-unigetui"; Flags: skipifdoesntexist runhidden; +Filename: {sys}\taskkill.exe; Parameters: "/f /im WingetUI.exe"; Flags: skipifdoesntexist runhidden; RunOnceId: "KillWingetUI" +Filename: {sys}\taskkill.exe; Parameters: "/f /im UniGetUI.exe"; Flags: skipifdoesntexist runhidden; RunOnceId: "KillUniGetUI" +Filename: {sys}\taskkill.exe; Parameters: "/f /im UniGetUI.Avalonia.exe"; Flags: skipifdoesntexist runhidden; RunOnceId: "KillUniGetUIAvalonia" diff --git a/WebBasedData/icons/devolutions-agent-icon.png b/WebBasedData/icons/devolutions-agent-icon.png new file mode 100644 index 0000000..2c61aa3 Binary files /dev/null and b/WebBasedData/icons/devolutions-agent-icon.png differ diff --git a/WebBasedData/icons/gateway-icon.png b/WebBasedData/icons/gateway-icon.png new file mode 100644 index 0000000..53f2c88 Binary files /dev/null and b/WebBasedData/icons/gateway-icon.png differ diff --git a/WebBasedData/icons/launcher-icon.png b/WebBasedData/icons/launcher-icon.png new file mode 100644 index 0000000..55bb4d1 Binary files /dev/null and b/WebBasedData/icons/launcher-icon.png differ diff --git a/WebBasedData/icons/msrdpex-icon.png b/WebBasedData/icons/msrdpex-icon.png new file mode 100644 index 0000000..3bcde49 Binary files /dev/null and b/WebBasedData/icons/msrdpex-icon.png differ diff --git a/WebBasedData/icons/remote-desktop-manager-agent-icon.png b/WebBasedData/icons/remote-desktop-manager-agent-icon.png new file mode 100644 index 0000000..1554648 Binary files /dev/null and b/WebBasedData/icons/remote-desktop-manager-agent-icon.png differ diff --git a/WebBasedData/icons/remote-desktop-manager-icon.png b/WebBasedData/icons/remote-desktop-manager-icon.png new file mode 100644 index 0000000..7e114cd Binary files /dev/null and b/WebBasedData/icons/remote-desktop-manager-icon.png differ diff --git a/WebBasedData/icons/server-icon.png b/WebBasedData/icons/server-icon.png new file mode 100644 index 0000000..bdc6a8b Binary files /dev/null and b/WebBasedData/icons/server-icon.png differ diff --git a/WebBasedData/icons/workspace-icon.png b/WebBasedData/icons/workspace-icon.png new file mode 100644 index 0000000..7ebeb02 Binary files /dev/null and b/WebBasedData/icons/workspace-icon.png differ diff --git a/WebBasedData/screenshot-database-v2.json b/WebBasedData/screenshot-database-v2.json new file mode 100644 index 0000000..77308f9 --- /dev/null +++ b/WebBasedData/screenshot-database-v2.json @@ -0,0 +1,55176 @@ +{ + "package_count": { + "total": 12411, + "done": 5933, + "packages_with_icon": 5933, + "packages_with_screenshot": 1368, + "total_screenshots": 4140 + }, + "icons_and_screenshots": { + "__test_entry_DO_NOT_EDIT_PLEASE": { + "icon": "https://this.is.a.test/url/used_for/automated_unit_testing.png", + "images": [ + "https://image_number.com/1.png", + "https://image_number.com/2.png", + "https://image_number.com/3.png" + ] + }, + "010editor": { + "icon": "https://i.postimg.cc/YqC1p8yC/010editor.png", + "images": [ + "https://i.postimg.cc/mkNV0DDp/image.png", + "https://i.postimg.cc/6p1zsFWK/image.png", + "https://i.postimg.cc/1znByMXq/image.png", + "https://i.postimg.cc/L5TBxbCr/image.png", + "https://i.postimg.cc/XNc8NrjQ/image.png" + ] + }, + "010memorizer": { + "icon": "https://i.postimg.cc/vBYJpNFC/727716.png", + "images": [ + "https://i.postimg.cc/43QC2TMz/010-Mem-Screen1.png", + "https://i.postimg.cc/vB0JMtGT/010-Mem-Screen2.png" + ] + }, + "0ad": { + "icon": "https://i.postimg.cc/k4SjQd9L/0ad.png", + "images": [ + "https://play0ad.com/wp-content/gallery/carousel/thumbs/thumbs_Kushcitycenter.jpg", + "https://play0ad.com/wp-content/gallery/carousel/thumbs/thumbs_EgyptianPyramids.jpg", + "https://play0ad.com/wp-content/gallery/carousel/thumbs/thumbs_CarthaginianTown.jpg", + "https://play0ad.com/wp-content/gallery/carousel/thumbs/thumbs_MacedonPort.jpg", + "https://play0ad.com/wp-content/gallery/carousel/thumbs/thumbs_water-rubble.jpg", + "https://play0ad.com/wp-content/gallery/carousel/thumbs/thumbs_PersianTradeRoute.jpg", + "https://play0ad.com/wp-content/gallery/carousel/thumbs/thumbs_Treasure.jpg", + "https://play0ad.com/wp-content/gallery/carousel/thumbs/thumbs_Pericles.jpeg", + "https://play0ad.com/wp-content/gallery/carousel/thumbs/thumbs_%20Iberian%20Town.jpeg", + "https://play0ad.com/wp-content/gallery/carousel/thumbs/thumbs_SpartanTown.jpg", + "https://play0ad.com/wp-content/gallery/carousel/thumbs/thumbs_mauryan-structures.jpg", + "https://play0ad.com/wp-content/gallery/carousel/thumbs/thumbs_BabylonParadise.jpg", + "https://play0ad.com/wp-content/gallery/carousel/thumbs/thumbs_MauryanColony.jpg", + "https://play0ad.com/wp-content/gallery/carousel/thumbs/thumbs_BritsAbroad.jpg", + "https://play0ad.com/wp-content/gallery/carousel/thumbs/thumbs_tilt-shift-filter.jpeg", + "https://play0ad.com/wp-content/gallery/carousel/thumbs/thumbs_water-specular.jpg", + "https://play0ad.com/wp-content/gallery/carousel/thumbs/thumbs_athenian_gymnasion.jpg", + "https://play0ad.com/wp-content/gallery/carousel/thumbs/thumbs_elapuba.jpg", + "https://play0ad.com/wp-content/gallery/carousel/thumbs/thumbs_celtbroch.jpg" + ] + }, + "0install": { + "icon": "https://i.postimg.cc/TPqFDC19/zero.png", + "images": [ + "https://i.postimg.cc/3N7wZLFx/image.png", + "https://i.postimg.cc/CLxhLnvX/image.png", + "https://i.postimg.cc/HLXHPwxc/image.png", + "https://i.postimg.cc/y6vK5YVP/image.png" + ] + }, + "0patch": { + "icon": "https://imgur.com/YHwGP6l.png", + "images": [ + "https://0patch.com/img/0patch-rac1.png", + "https://0patch.com/img/extra/0patchCentral.jpg", + "https://0patch.com/img/extra/Windows_7_adopted.png" + ] + }, + "115chrome": { + "icon": "https://i.imgur.com/5fSfmJl.png", + "images": [ + "https://pc.115.com/static/pc/images/pc_banner@2x.png", + "https://pc.115.com/static/tv/images/tv_clinet_pic@2x.png", + "https://pc.115.com/static/tv/images/web_mvpage@2x.png", + "https://pc.115.com/static/tv/images/web_albumpage@2x.png", + "https://pc.115.com/static/tv/images/web_audiopage@2x.png" + ] + }, + "12306-electron": { + "icon": "https://raw.githubusercontent.com/woo-long/12306-electron/dev/build/icons/256x256.png", + "images": [ + "https://raw.githubusercontent.com/woo-long/12306-electron/dev/app_snapshot.png" + ] + }, + "1c-barcode-printing": { + "icon": "https://community.chocolatey.org/content/packageimages/1c-barcode-printing.8.0.14.2.png", + "images": [] + }, + "1c-barcode-scanner": { + "icon": "https://community.chocolatey.org/content/packageimages/1c-barcode-scanner.8.0.8.4.png", + "images": [] + }, + "1c-its": { + "icon": "https://community.chocolatey.org/content/packageimages/1c-its.8.3.png", + "images": [] + }, + "1cfresh-client": { + "icon": "https://community.chocolatey.org/content/packageimages/1cfresh-client.8.3.22.1886.png", + "images": [] + }, + "1clipboard": { + "icon": "https://i.postimg.cc/Y01y0NHQ/1clip-icon.png", + "images": [ + "https://i.postimg.cc/d3MxJHzq/1clip-1.png" + ] + }, + "1history": { + "icon": "https://i.postimg.cc/k4w2mzVS/98217212.png", + "images": [ + "https://i.postimg.cc/Vv6dLgMV/top10-domain.png", + "https://i.postimg.cc/nrPMsmGc/top10-title.png" + ] + }, + "1password": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/5/5b/1Password_icon.png", + "images": [ + "https://i.postimg.cc/nc6SCCj5/image.png", + "https://i.postimg.cc/yxDnNHVs/image.png", + "https://i.postimg.cc/hvNsz5jx/image.png", + "https://i.postimg.cc/yYSv4sQT/image.png", + "https://i.postimg.cc/vDR7Hxqt/image.png" + ] + }, + "1password-beta": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/5/5b/1Password_icon.png", + "images": [] + }, + "1password-cli": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/5/5b/1Password_icon.png", + "images": [] + }, + "1password4": { + "icon": "https://community.chocolatey.org/content/packageimages/1password4.4.6.2.626.png", + "images": [] + }, + "2fast": { + "icon": "https://community.chocolatey.org/content/packageimages/2fast.1.2.2.png", + "images": [] + }, + "360chrome-x": { + "icon": "https://1.bp.blogspot.com/-3IeAb5s0t7Q/Xk-ESZ9EU3I/AAAAAAAACuY/MxkpFzOGH1crDT0Q7UnqM51TV3gkK2K3QCNcBGAsYHQ/s310-c/360chrome-11.png", + "images": [ + "https://images.sftcdn.net/images/t_app-cover-l,f_auto/p/4e860d5b-18bd-4216-bd39-e703553c49a1/3838871850/360-browser-images%20(8).jpg", + "https://cdn.lo4d.com/t/screenshot/360-browser-3.png" + ] + }, + "360cleanmaster": { + "icon": "https://imgur.com/zFifzGq.png", + "images": [ + "https://p0.ssl.qhmsg.com/dr/510__100/t0162c6333044e14f4f.png" + ] + }, + "360gt": { + "icon": "https://imgur.com/arldkgB.png", + "images": [ + "https://se3.360simg.com/dr/996__80/t01c084e8fb0a69b9d3.jpg", + "https://se3.360simg.com/dr/996__80/t01eac9e03abf4b71d0.jpg", + "https://se2.360simg.com/dr/996__80/t01ddb19fa70197ec64.jpg", + "https://se3.360simg.com/dr/996__80/t014a6a9851a4356e84.jpg" + ] + }, + "360se": { + "icon": "https://i.imgur.com/OTgnwGn.png", + "images": [ + "https://se1.360simg.com/t01556df2aa6ab462bc.jpg", + "https://se2.360simg.com/t01bc71221790eac009.jpg", + "https://se2.360simg.com/t01f6f305ac16a617ce.jpg", + "https://se2.360simg.com/t01000f2ee1d3caf0a0.jpg" + ] + }, + "360ts": { + "icon": "https://community.chocolatey.org/content/packageimages/360ts.10.8.0.1529.png", + "images": [] + }, + "360tse": { + "icon": "https://community.chocolatey.org/content/packageimages/360tse.8.8.0.1119.png", + "images": [] + }, + "360zip": { + "icon": "https://static.360totalsecurity.com/home/images/zip/box-112dab92.png", + "images": [ + "https://i0.wp.com/crast.net/img/2022/05/1652364831_571_Save-disk-space-with-this-360-Total-Security-program.jpg", + "https://www.xiaoyi.vc/wp-content/uploads/2020/01/360zip.png" + ] + }, + "3cx": { + "icon": "https://community.chocolatey.org/content/packageimages/3cx.16.3.0.264.png", + "images": [] + }, + "3d-fix-manager": { + "icon": "", + "images": [] + }, + "3dduke-shareware": { + "icon": "https://community.chocolatey.org/content/packageimages/3dduke-shareware.1.3.0.png", + "images": [] + }, + "3dmark": { + "icon": "https://i.ibb.co/zrwxXrq/download.png", + "images": [ + "https://cooltown2.hattara.fuma.fi/static/images/screenshots/ul-procyon-ai-inference-windows-result-part-1.png" + ] + }, + "3dxware-10": { + "icon": "", + "images": [] + }, + "3rvx": { + "icon": "https://community.chocolatey.org/content/packageimages/3rvx.2.9.2.10.png", + "images": [] + }, + "4297127d64ec6": { + "icon": "https://cdn2.steamgriddb.com/icon/b7a782741f667201b54880c925faec4b.png", + "images": [] + }, + "4gb-patch": { + "icon": "", + "images": [] + }, + "4k-slideshow-maker": { + "icon": "https://community.chocolatey.org/content/packageimages/4k-slideshow-maker.2.0.1.png", + "images": [] + }, + "4k-video-downloader": { + "icon": "https://i.postimg.cc/ZKVs8Jf2/4k-video-downloader-icon.png", + "images": [ + "https://i.postimg.cc/ncHw9X1q/4k-video-downloader-1.png" + ] + }, + "4k-video-to-mp3": { + "icon": "https://community.chocolatey.org/content/packageimages/4k-video-to-mp3.3.0.1.png", + "images": [] + }, + "4k-youtube-to-mp3": { + "icon": "", + "images": [] + }, + "4kcaptureutility": { + "icon": "https://img.informer.com/icons/png/128/6862/6862311.png", + "images": [ + "https://help.elgato.com/hc/article_attachments/4405457555597/Interface_Main_2_copy.png", + "https://help.elgato.com/hc/article_attachments/4405465427085/Interface_Main_1_copy.png" + ] + }, + "4kslideshowmaker": { + "icon": "https://img.informer.com/icons_mac/png/128/546/546469.png", + "images": [ + "https://static.4kdownload.com/main/img/redesign-v2/products-page/slideshowmaker/promo-main.png", + "https://static.4kdownload.com/main/img/redesign/product-screenshots/cards/new-cards/slideshowmaker-card@1x.webp", + "https://static.4kdownload.com/main/img/redesign-v2/products-page/slideshowmaker/quality@1x.png" + ] + }, + "4kstogram": { + "icon": "", + "images": [ + "https://static.4kdownload.com/main/img/redesign/product-screenshots/cards/new-cards/stogram-card@1x.png", + "https://static.4kdownload.com/main/img/redesign-v2/products-page/stogram/download@1x.png" + ] + }, + "4ktokkit": { + "icon": "", + "images": [ + "https://static.4kdownload.com/main/img/redesign/product-screenshots/cards/new-cards/tokkit-card@1x.png", + "https://static.4kdownload.com/main/img/redesign-v2/products-page/tokkit/download-tiktok-hashtag.07a06cb13a1b.png" + ] + }, + "4kvideodownloader": { + "icon": "https://static.4kdownload.com/main/img/logo/videodownloader-512.7395df698c5e.png", + "images": [ + "https://static.4kdownload.com/main/img/redesign/product-screenshots/cards/new-cards/videodownloader-card@1x.png", + "https://static.4kdownload.com/main/img/redesign/product-screenshots/windows/videodownloader/playlist.png" + ] + }, + "4kvideotomp3": { + "icon": "https://i.postimg.cc/DZF6srGL/4-K-Video-to-MP3.png", + "images": [ + "https://static.4kdownload.com/main/img/redesign/product-screenshots/cards/new-cards/videotomp3-card@1x.png", + "https://static.4kdownload.com/main/img/redesign-v2/products-page/videotomp3/import@1x.png" + ] + }, + "4kyoutubetomp3": { + "icon": "https://dl2.macupdate.com/images/icons256/45833.png?time=1662981249", + "images": [ + "https://static.4kdownload.com/main/img/redesign/product-screenshots/cards/new-cards/youtubetomp3-card@1x.png", + "https://static.4kdownload.com/main/img/redesign-v2/products-page/youtubetomp3/playlist@1x.png" + ] + }, + "4t-tray-minimizer": { + "icon": "https://community.chocolatey.org/content/packageimages/4t-tray-minimizer.6.07.png", + "images": [] + }, + "4ttrayminimizer": { + "icon": "https://imgur.com/QSc6fq3.png", + "images": [ + "https://www.4t-niagara.com/images/tray_screen_small.png", + "https://windows-cdn.softpedia.com/screenshots/4t-Tray-Minimizer-Free_1.png" + ] + }, + "4zur3": { + "icon": "https://i.postimg.cc/7L9wKgH3/4zur3.png", + "images": [] + }, + "5eclient": { + "icon": "https://i.postimg.cc/FRmZMcSv/5eclient.png", + "images": [] + }, + "64gram": { + "icon": "https://imgur.com/cvfaDrq.png", + "images": [ + "https://raw.githubusercontent.com/TDesktop-x64/tdesktop/dev/docs/assets/preview.png" + ] + }, + "7-taskbar-tweaker": { + "icon": "https://community.chocolatey.org/content/packageimages/7-taskbar-tweaker.5.8.png", + "images": [] + }, + "7+taskbartweaker": { + "icon": "https://community.chocolatey.org/content/packageimages/7-taskbar-tweaker.5.8.png", + "images": [] + }, + "7kaa": { + "icon": "", + "images": [] + }, + "7tsp": { + "icon": "https://img.informer.com/icons/png/128/3964/3964022.png", + "images": [] + }, + "7tt": { + "icon": "https://community.chocolatey.org/content/packageimages/7tt.5.14.1.png", + "images": [] + }, + "7zip": { + "icon": "https://i.postimg.cc/CLMvJ2Fp/image.png", + "images": [ + "https://i.postimg.cc/fyxLGHPS/7-Zip-1.png", + "https://cdn.mos.cms.futurecdn.net/0c3ce5fdf135bb76208e0558845eb98c.jpg" + ] + }, + "7zip-alpha-exe": { + "icon": "https://i.postimg.cc/Wprhq34p/7-Zip-icon.png", + "images": [ + "https://i.postimg.cc/fyxLGHPS/7-Zip-1.png" + ] + }, + "7zip-alpha-msi": { + "icon": "https://i.postimg.cc/Wprhq34p/7-Zip-icon.png", + "images": [ + "https://i.postimg.cc/fyxLGHPS/7-Zip-1.png" + ] + }, + "7zip-commandline": { + "icon": "https://i.postimg.cc/Wprhq34p/7-Zip-icon.png", + "images": [] + }, + "7zip-zstd": { + "icon": "https://i.postimg.cc/Wprhq34p/7-Zip-icon.png", + "images": [ + "https://i.postimg.cc/qvcFN2Pc/7zip-zstd-1.png", + "https://i.postimg.cc/d3THwCRy/7zip-zstd-2.png", + "https://i.postimg.cc/1tX772fM/7zip-zstd-3.png", + "https://i.postimg.cc/SsPTBd94/7zip-zstd-4.png", + "https://i.postimg.cc/9fJNpCFr/7zip-zstd-5.png" + ] + }, + "7zip19-00-helper": { + "icon": "", + "images": [] + }, + "7ztm": { + "icon": "", + "images": [] + }, + "8gadgetpack": { + "icon": "https://cdn.lo4d.com/t/icon/128/8gadgetpack.png", + "images": [ + "https://i.postimg.cc/hhWcSRbp/image.png", + "https://i.postimg.cc/7PCzY1n2/image.png", + "https://i.postimg.cc/KcdMKK0s/image.png", + "https://i.postimg.cc/dtrTGqXQ/image.png" + ] + }, + "8x8virtualoffice": { + "icon": "", + "images": [] + }, + "9kw-client": { + "icon": "https://community.chocolatey.org/content/packageimages/9kw-client.1.2.1.png", + "images": [] + }, + "a0toolkit": { + "icon": "", + "images": [] + }, + "a3launcher": { + "icon": "https://i.imgur.com/lYZJfK3.png", + "images": [ + "https://a3launcher.com/images/7171b67d-5c3f-43af-81d1-790fae989dea.png", + "https://i.ytimg.com/vi/F2eT-7k2aMc/sddefault.jpg", + "https://4.bp.blogspot.com/-fpsyiZfmSy0/VLnyNUw4VfI/AAAAAAAAd-0/bRQhZMEI7VI/s1600/arma3_a3_launcher2.png" + ] + }, + "aaaaxy": { + "icon": "https://i.postimg.cc/ZnnB2RgZ/aaaaxy.png", + "images": [ + "https://i.postimg.cc/CxkZW9vZ/shot1.png", + "https://i.postimg.cc/x8ZJ2QDm/shot2.png", + "https://i.postimg.cc/BQdL7JC9/shot3.png", + "https://i.postimg.cc/TYy5cKgJ/shot4.png", + "https://i.postimg.cc/T2NWmVLP/shot5.png" + ] + }, + "aacgain": { + "icon": "https://community.chocolatey.org/content/packageimages/aacgain.1.9.0.2.png", + "images": [] + }, + "aaclr": { + "icon": "https://community.chocolatey.org/content/packageimages/aaclr.1.0.2.png", + "images": [] + }, + "aadhaarcardpasswordremover": { + "icon": "https://i.postimg.cc/qM32FGtH/adhaar.png", + "images": [ + "https://i.postimg.cc/Gtz6n1g9/aadharpassword1.png", + "https://i.postimg.cc/W1c0cJrF/aadharpassword2.png", + "https://i.postimg.cc/y8hc1YXf/aadharpassword3.png" + ] + }, + "abaclient": { + "icon": "https://i.imgur.com/zXixk8q.png", + "images": [ + "https://docplayer.org/docs-images/109/187115837/images/7-0.jpg", + "https://i.imgur.com/mEWcJzg.png" + ] + }, + "abastart": { + "icon": "https://community.chocolatey.org/content/packageimages/abastart.3.3.0.png", + "images": [] + }, + "abc": { + "icon": "", + "images": [] + }, + "abc-update": { + "icon": "https://community.chocolatey.org/content/packageimages/ABC-Update.3.0.1.png", + "images": [] + }, + "abdownloadmanager": { + "icon": "https://i.postimg.cc/Px4yR0tL/abdownloadmanager.png", + "images": [ + "https://raw.githubusercontent.com/amir1376/ab-download-manager/master/assets/banners/app_banner.png", + "https://raw.githubusercontent.com/amir1376/ab-download-manager/master/assets/screenshots/app-home_dark.png", + "https://raw.githubusercontent.com/amir1376/ab-download-manager/master/assets/screenshots/app-home_light.png", + "https://raw.githubusercontent.com/amir1376/ab-download-manager/master/assets/screenshots/app-download_dark.png", + "https://raw.githubusercontent.com/amir1376/ab-download-manager/master/assets/screenshots/app-download_light.png" + ] + }, + "abilityoffice": { + "icon": "https://i.postimg.cc/fbz5STZb/Ability-icon.png", + "images": [] + }, + "abilityoffice-10-professional": { + "icon": "https://i.postimg.cc/fbz5STZb/Ability-icon.png", + "images": [ + "https://i.postimg.cc/RZzg9LDK/Ability-1.png", + "https://i.postimg.cc/vBDzXq4F/Ability-2.png" + ] + }, + "abilityoffice-10-standard": { + "icon": "https://i.postimg.cc/fbz5STZb/Ability-icon.png", + "images": [ + "https://i.postimg.cc/RZzg9LDK/Ability-1.png", + "https://i.postimg.cc/vBDzXq4F/Ability-2.png" + ] + }, + "abilityoffice-8-professional": { + "icon": "https://i.postimg.cc/fbz5STZb/Ability-icon.png", + "images": [ + "https://i.postimg.cc/RZzg9LDK/Ability-1.png", + "https://i.postimg.cc/vBDzXq4F/Ability-2.png" + ] + }, + "abilityoffice-8-standard": { + "icon": "https://i.postimg.cc/fbz5STZb/Ability-icon.png", + "images": [ + "https://i.postimg.cc/RZzg9LDK/Ability-1.png", + "https://i.postimg.cc/vBDzXq4F/Ability-2.png" + ] + }, + "abiword": { + "icon": "https://i.imgur.com/qnBf8D1.png", + "images": [ + "https://www.abisource.com/screenshots/abi-win32.thumb.jpg", + "https://www.abisource.com/screenshots/abi-yiddish.thumb.jpg" + ] + }, + "abricotine": { + "icon": "https://raw.githubusercontent.com/brrd/abricotine/develop/icons/abricotine-64.png", + "images": [ + "https://raw.githubusercontent.com/brrd/abricotine/develop/screenshot.jpg" + ] + }, + "absolute-uninstaller": { + "icon": "https://i.postimg.cc/qML9RYYM/Absolute-Uninstaller.png", + "images": [ + "https://i.postimg.cc/GmvTGFF2/Absolute-Uninstaller-2.png" + ] + }, + "abyssoverlay": { + "icon": "https://user-images.githubusercontent.com/61895718/111565782-5ced2900-8772-11eb-9c43-c8801fc2a1a8.png", + "images": [ + "https://i.imgur.com/92gMTyo.png", + "https://i.imgur.com/KENrNHj.png" + ] + }, + "acardaoutboundagent": { + "icon": "", + "images": [] + }, + "access-data-registry-viewer": { + "icon": "", + "images": [] + }, + "access-to-mysql": { + "icon": "https://community.chocolatey.org/content/packageimages/access-to-mysql.5.2.0.252.png", + "images": [] + }, + "access2016runtime": { + "icon": "", + "images": [] + }, + "accesschk": { + "icon": "https://community.chocolatey.org/content/packageimages/accesschk.6.15.png", + "images": [] + }, + "accessenum": { + "icon": "https://community.chocolatey.org/content/packageimages/accessenum.1.32.png", + "images": [] + }, + "accesser": { + "icon": "", + "images": [] + }, + "accesspv": { + "icon": "https://community.chocolatey.org/content/packageimages/accesspv.1.12.png", + "images": [] + }, + "acddokannet": { + "icon": "", + "images": [] + }, + "ace": { + "icon": "https://community.chocolatey.org/content/packageimages/ace.1.3.png", + "images": [] + }, + "acemovi": { + "icon": "https://acemovi.tuneskit.com/images/acemovi.svg", + "images": [ + "https://techbullion.com/wp-content/uploads/2021/07/TunesKit-AceMovi-Video-Editor-1000x600.jpg", + "https://acemovi.tuneskit.com/images/product/edit-video-v4.jpg", + "https://static.filehorse.com/screenshots/video-software/tuneskit-acemovi-screenshot-05.png", + "https://acemovi.tuneskit.com/images/video-editor/interface-mac.png", + "https://screenshots.macupdate.com/JPG/63486/63486_1633616496_scr_uc2.jpg" + ] + }, + "acestream": { + "icon": "", + "images": [] + }, + "acfunvirtualtool": { + "icon": "https://i.imgur.com/JWlDMfh.png", + "images": [ + "https://i.imgur.com/qD3qwQ3.png", + "https://i.imgur.com/gs0jRFj.png", + "https://i.imgur.com/TN1ZFJQ.png", + "https://i.imgur.com/clFQlOC.png", + "https://i.imgur.com/CwZwk9H.png" + ] + }, + "achievement-watcher": { + "icon": "https://community.chocolatey.org/content/packageimages/achievement-watcher.1.6.8.png", + "images": [] + }, + "achievementwatcher": { + "icon": "https://xan105.github.io/Achievement-Watcher/resources/img/logo.png", + "images": [ + "https://raw.githubusercontent.com/xan105/Achievement-Watcher/master/screenshot/home.png", + "https://raw.githubusercontent.com/xan105/Achievement-Watcher/master/screenshot/ach_view.png", + "https://xan105.github.io/Achievement-Watcher/resources/img/unified.png", + "https://xan105.github.io/Achievement-Watcher/resources/img/loading.png" + ] + }, + "ack": { + "icon": "https://community.chocolatey.org/content/packageimages/ack.3.4.0.png", + "images": [] + }, + "acm": { + "icon": "https://community.chocolatey.org/content/packageimages/acm.1.00.png", + "images": [] + }, + "acme-sh": { + "icon": "https://community.chocolatey.org/content/packageimages/acme-sh.3.0.5.png", + "images": [] + }, + "acmesharp": { + "icon": "", + "images": [] + }, + "acmesharp-posh-all": { + "icon": "https://community.chocolatey.org/content/packageimages/acmesharp-posh-all.0.8.1.0.png", + "images": [] + }, + "acorn": { + "icon": "", + "images": [] + }, + "acr": { + "icon": "https://community.chocolatey.org/content/packageimages/acr.2.18.2.png", + "images": [] + }, + "acrobat-reader-32-bit": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/e/ea/Adobe_Acrobat_DC_icon.png", + "images": [ + "https://img-19.ccm.net/fheSH8Cl0detgNX2J1v2QAgMrR4=/450x/smart/4b36b6809e574683aa645cf6023a7c52/ccmcms-enccm/35559148.png", + "https://cdn.mos.cms.futurecdn.net/bKeFKKwEaBtyJwwCDWhsu5-1200-80.jpg", + "https://gdm-catalog-fmapi-prod.imgix.net/ProductScreenshot/02aadd42-87e9-45a6-9b74-09224415adf0.jpeg", + "https://imag.malavida.com/mvimgbig/download-fs/adobe-reader-293-1.jpg", + "https://imag.malavida.com/mvimgbig/download-fs/adobe-reader-293-3.jpg" + ] + }, + "acrobat-reader-64-bit": { + "icon": "https://i.postimg.cc/wvbKJzmr/acrobat.png", + "images": [ + "https://img-19.ccm.net/fheSH8Cl0detgNX2J1v2QAgMrR4=/450x/smart/4b36b6809e574683aa645cf6023a7c52/ccmcms-enccm/35559148.png", + "https://cdn.mos.cms.futurecdn.net/bKeFKKwEaBtyJwwCDWhsu5-1200-80.jpg", + "https://gdm-catalog-fmapi-prod.imgix.net/ProductScreenshot/02aadd42-87e9-45a6-9b74-09224415adf0.jpeg", + "https://imag.malavida.com/mvimgbig/download-fs/adobe-reader-293-1.jpg", + "https://imag.malavida.com/mvimgbig/download-fs/adobe-reader-293-3.jpg" + ] + }, + "acrylic-dns-proxy": { + "icon": "", + "images": [] + }, + "acrylicdns": { + "icon": "https://i.imgur.com/gEsxO7g.png", + "images": [] + }, + "acs": { + "icon": "https://i.imgur.com/cne3Hul.png", + "images": [ + "https://user-images.githubusercontent.com/95648640/156843519-5825eec1-3f6c-484e-882d-f3a2b18fefd2.jpg" + ] + }, + "acs-engine": { + "icon": "https://community.chocolatey.org/content/packageimages/acs-engine.0.26.3.png", + "images": [] + }, + "act": { + "icon": "", + "images": [] + }, + "act-cli": { + "icon": "https://community.chocolatey.org/content/packageimages/act-cli.0.2.42.png", + "images": [] + }, + "actifileagent": { + "icon": "https://i.imgur.com/WoPZ1HB.png", + "images": [ + "https://static.wixstatic.com/media/10e96b_df7e3b0f52234ec9940b60815cd0a8f1~mv2.png/v1/fill/w_560,h_330,al_c,q_85,usm_0.66_1.00_0.01,enc_auto/Actifile%20-%20Introduction%20May%202022%20-1.png", + "https://www.bitcyber.com.sg/wp-content/uploads/2021/07/Actifile-Risk-Assessment-600x305-1.jpg" + ] + }, + "action": { + "icon": "https://mirillis.com/res/images/icons/favicon32.png", + "images": [ + "https://mirillis.com/res/old/media/images/product/action/16-ui_for_users.png", + "https://mirillis.com/res/old/media/images/product/action/new-green_screen.jpg", + "https://mirillis.com/res/old/media/images/product/action/action-device-recording-mode.jpg", + "https://mirillis.com/res/old/media/images/product/action/new-app_record.jpg", + "https://mirillis.com/res/old/media/images/product/action/1-record_gameplay.jpg", + "https://mirillis.com/res/old/media/images/product/action/4-stream_gameplay.jpg", + "https://mirillis.com/res/old/media/images/product/action/11-record_with_4k.jpg", + "https://mirillis.com/res/old/media/images/product/action/7-upload_to_facebok.jpg", + "https://mirillis.com/res/old/media/images/product/action/20-video_playback.jpg" + ] + }, + "actiona": { + "icon": "https://community.chocolatey.org/content/packageimages/actiona.install.3.10.0.png", + "images": [] + }, + "actionlint": { + "icon": "", + "images": [] + }, + "activate-linux": { + "icon": "https://community.chocolatey.org/content/packageimages/activate-linux.1.1.0.png", + "images": [] + }, + "active-directory-photos": { + "icon": "https://community.chocolatey.org/content/packageimages/active-directory-photos.1.3.2.0.png", + "images": [] + }, + "activebootdisk": { + "icon": "https://www.lsoft.net/images/icons/boot-disk.png", + "images": [ + "https://www.lsoft.net/images/screenshots/bootdisk1.png", + "https://www.lsoft.net/images/screenshots/bootdisk2.png", + "https://www.lsoft.net/images/screenshots/bootdisk3.png", + "https://www.lsoft.net/images/screenshots/bootdisk5.png", + "https://www.lsoft.net/images/screenshots/bootdisk6.png", + "https://www.lsoft.net/images/screenshots/bootdisk7.png", + "https://www.lsoft.net/images/screenshots/bootdisk8.png", + "https://www.lsoft.net/images/screenshots/bootdisk9.png", + "https://www.lsoft.net/images/screenshots/bootdisk10.png" + ] + }, + "activechart": { + "icon": "https://activechart.futureglobe.de/images/appLogo.png", + "images": [ + "https://activechart.futureglobe.de/images/screenshots/Screenshot01.PNG", + "https://activechart.futureglobe.de/images/screenshots/Screenshot02.PNG", + "https://activechart.futureglobe.de/images/screenshots/Screenshot03.PNG" + ] + }, + "activedataburner": { + "icon": "https://www.lsoft.net/images/icons/data-burner.png", + "images": [ + "https://www.lsoft.net/images/screenshots/cd_data_burner.gif" + ] + }, + "activedatastudio": { + "icon": "https://www.lsoft.net/images/icons/data-studio.png", + "images": [ + "https://www.lsoft.net/images/icons/data-studio.png", + "https://www.lsoft.net/images/screenshots/disk-image-new.gif", + "https://www.lsoft.net/images/screenshots/main-screen4-big.gif", + "https://www.lsoft.net/images/screenshots/workspace.png", + "https://www.lsoft.net/images/screenshots/partition-manager-workspace.png", + "https://www.lsoft.net/images/screenshots/disk-monitor-screenshot.gif", + "https://www.lsoft.net/images/screenshots/disk-editor-new.gif", + "https://www.lsoft.net/images/screenshots/password-changer.jpg", + "https://www.lsoft.net/images/screenshots/killdisk.png", + "https://www.lsoft.net/images/screenshots/data-burner.gif" + ] + }, + "activediskeditor": { + "icon": "https://www.lsoft.net/images/icons/disk-editor.png", + "images": [ + "https://www.lsoft.net/images/screenshots/HexEditor2.gif", + "https://www.lsoft.net/images/screenshots/HexEditor5.gif", + "https://www.lsoft.net/images/screenshots/HexEditor12.gif", + "https://www.lsoft.net/images/screenshots/HexEditor8.gif", + "https://www.lsoft.net/images/screenshots/HexEditor9.gif", + "https://www.lsoft.net/images/screenshots/HexEditor10.gif", + "https://www.lsoft.net/images/screenshots/HexEditor11.gif", + "https://www.lsoft.net/images/screenshots/HexEditor7.gif" + ] + }, + "activediskimage": { + "icon": "https://www.lsoft.net/images/icons/disk-image.png", + "images": [ + "https://www.lsoft.net/images/screenshots/diskimage1.png", + "https://www.lsoft.net/images/screenshots/diskimage2.png", + "https://www.lsoft.net/images/screenshots/diskimage3.png", + "https://www.lsoft.net/images/screenshots/diskimage4.png", + "https://www.lsoft.net/images/screenshots/diskimage5.gif", + "https://www.lsoft.net/images/screenshots/diskimage6.png" + ] + }, + "activediskmonitor": { + "icon": "https://www.lsoft.net/images/icons/disk-monitor.png", + "images": [ + "https://www.lsoft.net/images/screenshots/1-disk-monitor.gif", + "https://www.lsoft.net/images/screenshots/disk-monitor-smart.gif", + "https://www.lsoft.net/images/screenshots/disk-monitor-scan.gif", + "https://www.lsoft.net/images/screenshots/disk-monitor-temperature.gif", + "https://www.lsoft.net/images/screenshots/sc_diskinfo.jpg", + "https://www.lsoft.net/images/screenshots/sc_disksametime.gif", + "https://www.lsoft.net/images/screenshots/sc_hoststatus.jpg", + "https://www.lsoft.net/images/screenshots/sc_temphist.jpg", + "https://www.lsoft.net/images/screenshots/screen_badblock_big.gif" + ] + }, + "activedvderaser": { + "icon": "https://www.lsoft.net/images/icons/dvd-eraser.png", + "images": [ + "https://www.lsoft.net/images/screenshots/dvd_eraser_main.gif" + ] + }, + "activeexit": { + "icon": "", + "images": [] + }, + "activefilerecovery": { + "icon": "https://i.postimg.cc/FzjtTs6L/fr-icon.png", + "images": [ + "https://i.postimg.cc/4NQydJ3y/fr1.png", + "https://i.postimg.cc/ZnFbCc42/fr2.png", + "https://i.postimg.cc/dQ8tHqr6/fr3.png" + ] + }, + "activeisoburner": { + "icon": "https://www.lsoft.net/images/icons/data-burner.png", + "images": [ + "https://www.lsoft.net/images/screenshots/ISO-Burner.jpg", + "https://www.lsoft.net/images/screenshots/iso_burner_beta_options.gif" + ] + }, + "activeisomanager": { + "icon": "https://www.lsoft.net/images/icons/iso-manager.png", + "images": [ + "https://www.lsoft.net/images/screenshots/edit-iso-manager.gif", + "https://www.lsoft.net/images/screenshots/burn-iso-manager.gif" + ] + }, + "activekilldisk": { + "icon": "https://www.lsoft.net/images/icons/killdisk.png", + "images": [ + "https://www.lsoft.net/images/screenshots/Certificate-killdisk1.png", + "https://www.lsoft.net/images/screenshots/sanitizing-hard-disk-killdisk2.png", + "https://www.lsoft.net/images/screenshots/parallel-disk-erasing-killdisk3.png", + "https://www.lsoft.net/images/screenshots/erase-options-killdisk4.png", + "https://www.lsoft.net/images/screenshots/sectors-display-hex-data-killdisk5.png", + "https://www.lsoft.net/images/screenshots/detected-physical-disks-killdisk6.gif", + "https://www.lsoft.net/images/screenshots/file-system-display-killdisk7.png", + "https://www.lsoft.net/images/screenshots/sanitizing-unused-disk-space-killdisk8.png", + "https://www.lsoft.net/images/screenshots/settings-dialog-killdisk9.png" + ] + }, + "activelivecd": { + "icon": "https://www.lsoft.net/images/icons/live-cd.png", + "images": [ + "https://www.lsoft.net/images/screenshots/livecd-desktop.jpg", + "https://www.lsoft.net/images/screenshots/livecd-configure-decktop.png", + "https://www.lsoft.net/images/screenshots/livecd-disk-backup.jpg", + "https://www.lsoft.net/images/screenshots/livecd-main.gif", + "https://www.lsoft.net/images/screenshots/livecd-undelete.jpg", + "https://www.lsoft.net/images/screenshots/livecd-disk.gif" + ] + }, + "activemq": { + "icon": "", + "images": [] + }, + "activemq-artemis": { + "icon": "", + "images": [] + }, + "activeperl": { + "icon": "https://community.chocolatey.org/content/packageimages/ActivePerl.5.28.png", + "images": [] + }, + "activeperl-eqemu-x86": { + "icon": "", + "images": [] + }, + "activepresenter": { + "icon": "", + "images": [] + }, + "activetcl": { + "icon": "https://community.chocolatey.org/content/packageimages/ActiveTcl.8.6.4.1.png", + "images": [] + }, + "activeundelete": { + "icon": "https://www.lsoft.net/images/icons/undelete.png", + "images": [ + "https://www.lsoft.net/images/screenshots/main-screen-recovery-view-undelete1.png", + "https://www.lsoft.net/images/screenshots/disk-scan-screen-undelete2.png", + "https://www.lsoft.net/images/screenshots/data-recovery-screen-undelete3.png", + "https://www.lsoft.net/images/screenshots/file-preview-screen-undelete4.png", + "https://www.lsoft.net/images/screenshots/disk-editor-screen-undelete5.png", + "https://www.lsoft.net/images/screenshots/partman-screen-undelete6.png" + ] + }, + "activeuneraser": { + "icon": "https://www.lsoft.net/images/icons/uneraser.png", + "images": [ + "https://www.lsoft.net/images/icons/uneraser.png", + "https://www.lsoft.net/images/screenshots/uneraser-superscan.png", + "https://www.lsoft.net/images/screenshots/uneraser-restored-file.png" + ] + }, + "activezdelete": { + "icon": "https://www.lsoft.net/images/icons/zdelete.png", + "images": [ + "https://www.lsoft.net/images/screenshots/zdelete-menu.jpg", + "https://www.lsoft.net/images/screenshots/zdelete-erase-method.jpg", + "https://www.lsoft.net/images/screenshots/zdelete-selecting-file-for-erasure.jpg" + ] + }, + "activitywatch": { + "icon": "https://i.imgur.com/0fNCI9J.png", + "images": [ + "https://activitywatch.net/img/screenshots/screenshot-v0.9.3-activity.png", + "https://activitywatch.net/img/screenshots/screenshot-v0.8.0b9-timeline.png", + "https://activitywatch.net/img/screenshots/BelKed/screenshot-v0.12.0b2-activity.png" + ] + }, + "actualupdater": { + "icon": "https://i.imgur.com/3KtDZX9.png", + "images": [ + "https://www.actualinstaller.com/images/screen/installer_1s.png", + "https://www.actualinstaller.com/images/screen/installer_2s.png", + "https://www.actualinstaller.com/images/screen/installer_3s.png", + "https://www.actualinstaller.com/images/screen/installer_4s.png", + "https://www.actualinstaller.com/images/screen/installer_6s.png", + "https://www.actualinstaller.com/images/screen/installer_7s.png", + "https://www.actualinstaller.com/images/screen/installer_8s.png", + "https://www.actualinstaller.com/images/screen/installer_9s.png", + "https://www.actualinstaller.com/images/screen/installer_10s.png", + "https://www.actualinstaller.com/images/screen/installer_11s.png", + "https://www.actualinstaller.com/images/screen/installer_12s.png", + "https://www.actualinstaller.com/images/screen/installer_13s.png", + "https://www.actualinstaller.com/images/screen/installer_14s.png", + "https://www.actualinstaller.com/images/screen/installer_15s.png", + "https://www.actualinstaller.com/images/screen/installer_16s.png", + "https://www.actualinstaller.com/images/screen/installer_17s.png", + "https://www.actualinstaller.com/images/screen/wizard_welcome_small.png", + "https://www.actualinstaller.com/images/screen/wizard_license_small.png", + "https://www.actualinstaller.com/images/screen/wizard_tasks_small.png", + "https://www.actualinstaller.com/images/screen/wizard_install_small.png" + ] + }, + "acunetix-free": { + "icon": "https://community.chocolatey.org/content/packageimages/acunetix-free.1.0.0.20180331.png", + "images": [] + }, + "ad-acl-scanner": { + "icon": "", + "images": [] + }, + "ad-photo-edit-free": { + "icon": "https://community.chocolatey.org/content/packageimages/ad-photo-edit-free.2.6.1.20161008.png", + "images": [] + }, + "ad-tidy-free": { + "icon": "https://community.chocolatey.org/content/packageimages/ad-tidy-free.2.1.7.0.png", + "images": [] + }, + "adafruit-pi-finder": { + "icon": "", + "images": [] + }, + "adb": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/6/64/Android_logo_2019_%28stacked%29.svg/275px-Android_logo_2019_%28stacked%29.svg.png", + "images": [] + }, + "adbappcontrol": { + "icon": "https://adbappcontrol.com/assets/img/logo_blue.png", + "images": [ + "https://adbappcontrol.com/assets/img/scr-main.jpg", + "https://adbappcontrol.com/assets/img/scr-extended.jpg", + "https://adbappcontrol.com/assets/img/scr-wizard.jpg", + "https://adbappcontrol.com/assets/img/scr-tools.jpg" + ] + }, + "adblockpluschrome": { + "icon": "", + "images": [] + }, + "adblockplusfirefox": { + "icon": "https://community.chocolatey.org/content/packageimages/adblockplusfirefox.0.0.0.2.png", + "images": [] + }, + "adblockplusie": { + "icon": "https://community.chocolatey.org/content/packageimages/adblockplusie.1.4.png", + "images": [] + }, + "addcurrentpath": { + "icon": "", + "images": [] + }, + "additionaltools": { + "icon": "", + "images": [] + }, + "addnewfile": { + "icon": "", + "images": [] + }, + "addo": { + "icon": "", + "images": [] + }, + "addons": { + "icon": "", + "images": [] + }, + "address-tagging-exchange": { + "icon": "https://community.chocolatey.org/content/packageimages/address-tagging-exchange.1.0.1.png", + "images": [] + }, + "addtoany-chrome": { + "icon": "", + "images": [] + }, + "adexplorer": { + "icon": "https://community.chocolatey.org/content/packageimages/adexplorer.1.52.png", + "images": [] + }, + "adguard": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/4/48/AdGuard_Logo.png", + "images": [ + "https://cdn.adguard.com/content/release_notes/ad_blocker/windows/v7.14/main_light_en.png", + "https://cdn.adguard.com/content/release_notes/ad_blocker/windows/v7.14/general_light_en.png" + ] + }, + "adguard-beta": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/4/48/AdGuard_Logo.png", + "images": [ + "https://cdn.adguard.com/content/release_notes/ad_blocker/windows/v7.14/main_light_en.png", + "https://cdn.adguard.com/content/release_notes/ad_blocker/windows/v7.14/general_light_en.png" + ] + }, + "adguard-chrome": { + "icon": "https://community.chocolatey.org/content/packageimages/adguard-chrome.3.0.13.png", + "images": [ + "https://cdn.adguard.com/public/Adguard/Common/adguard_extension_4_settings.png" + ] + }, + "adguardhome": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/4/48/AdGuard_Logo.png", + "images": [ + "https://dashboard.snapcraft.io/site_media/appmedia/2020/04/agh1_Y8qX5Jf.png", + "https://dashboard.snapcraft.io/site_media/appmedia/2020/04/agh2_BF6Xfj2.png", + "https://dashboard.snapcraft.io/site_media/appmedia/2020/04/agh3_2Zqhv3A.png" + ] + }, + "adguardhome-beta": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/4/48/AdGuard_Logo.png", + "images": [ + "https://dashboard.snapcraft.io/site_media/appmedia/2020/04/agh1_Y8qX5Jf.png", + "https://dashboard.snapcraft.io/site_media/appmedia/2020/04/agh2_BF6Xfj2.png", + "https://dashboard.snapcraft.io/site_media/appmedia/2020/04/agh3_2Zqhv3A.png" + ] + }, + "adguardvpn": { + "icon": "https://i.imgur.com/tvlrfxJ.png", + "images": [ + "https://cdn.adtidy.org/content/release_notes/vpn/windows/v2.0/main_screen_light_en.png" + ] + }, + "adif-master": { + "icon": "", + "images": [] + }, + "adiirc": { + "icon": "https://www.irchelp.org/clients/windows/adiirc_logo_256p.png", + "images": [ + "https://www.adiirc.com/images/xss.png.pagespeed.ic.goVp15eGFq.png", + "https://i.imgur.com/R7PYXze.png", + "https://www.irchelp.org/clients/windows/adiirc_screenshot_hackergreen.png", + "https://dev.adiirc.com/attachments/download/790/Monitoring_Panels_02.gif" + ] + }, + "adinsight": { + "icon": "https://community.chocolatey.org/content/packageimages/adinsight.1.20.png", + "images": [] + }, + "adkpeaddon": { + "icon": "", + "images": [] + }, + "admbridge-signagelive": { + "icon": "", + "images": [] + }, + "admincenter": { + "icon": "", + "images": [] + }, + "adminservice": { + "icon": "", + "images": [] + }, + "admobilize-demo-app": { + "icon": "https://community.chocolatey.org/content/packageimages/admobilize-demo-app.1.0.1.png", + "images": [] + }, + "admobilize-desktop-ui": { + "icon": "https://community.chocolatey.org/content/packageimages/admobilize-desktop-ui.2.1.2.png", + "images": [] + }, + "admobilize-desktopui": { + "icon": "https://i.imgur.com/db7YcHx.png", + "images": [ + "https://venturebeat.com/wp-content/uploads/2015/07/AdMobilize.png", + "https://www.helloooh.com/wp-content/uploads/2016/06/proof-of-engagement-website.gif" + ] + }, + "admobilize-malosvision": { + "icon": "", + "images": [] + }, + "admobilize-vision-service": { + "icon": "", + "images": [] + }, + "admobilize-visionservice": { + "icon": "https://i.imgur.com/db7YcHx.png", + "images": [] + }, + "admprovider": { + "icon": "https://i.imgur.com/db7YcHx.png", + "images": [] + }, + "adobe-connect": { + "icon": "https://community.chocolatey.org/content/packageimages/adobe-connect.2020.1.5.png", + "images": [] + }, + "adobe-dnc": { + "icon": "https://community.chocolatey.org/content/packageimages/adobe-dnc.15.2.png", + "images": [] + }, + "adobe-source-sans": { + "icon": "", + "images": [] + }, + "adobeair": { + "icon": "https://community.chocolatey.org/content/packageimages/AdobeAIR.50.1.1.2.png", + "images": [] + }, + "adobeconnect": { + "icon": "https://cdn.iconscout.com/icon/free/png-256/adobe-connect-2521767-2132659.png", + "images": [ + "https://i.imgur.com/RG7wdZ0.jpg", + "https://i.imgur.com/Jg0q7UW.jpg", + "https://i.imgur.com/twirlCd.jpg", + "https://i.imgur.com/v28qeiM.jpg", + "https://i.imgur.com/kvcw9n1.jpg", + "https://i.imgur.com/z0bh5vW.jpg", + "https://i.imgur.com/yCDdBnJ.jpg" + ] + }, + "adobedigitaleditions": { + "icon": "https://community.chocolatey.org/content/packageimages/adobedigitaleditions.4.5.11.20200510.png", + "images": [] + }, + "adobereader": { + "icon": "https://community.chocolatey.org/content/packageimages/adobereader.2022.003.20322.png", + "images": [] + }, + "adobereader-update": { + "icon": "", + "images": [] + }, + "adoptopenjdk": { + "icon": "", + "images": [] + }, + "adoptopenjdk11": { + "icon": "", + "images": [] + }, + "adoptopenjdk11jre": { + "icon": "", + "images": [] + }, + "adoptopenjdk11openj9": { + "icon": "", + "images": [] + }, + "adoptopenjdk13": { + "icon": "", + "images": [] + }, + "adoptopenjdk13openj9": { + "icon": "", + "images": [] + }, + "adoptopenjdk14": { + "icon": "", + "images": [] + }, + "adoptopenjdk14openj9": { + "icon": "", + "images": [] + }, + "adoptopenjdk14openj9jre": { + "icon": "", + "images": [] + }, + "adoptopenjdk15": { + "icon": "", + "images": [] + }, + "adoptopenjdk15jre": { + "icon": "", + "images": [] + }, + "adoptopenjdk15openj9": { + "icon": "", + "images": [] + }, + "adoptopenjdk15openj9jre": { + "icon": "", + "images": [] + }, + "adoptopenjdk8": { + "icon": "", + "images": [] + }, + "adoptopenjdk8jre": { + "icon": "", + "images": [] + }, + "adoptopenjdkjre": { + "icon": "", + "images": [] + }, + "adoptopenjdkopenj9": { + "icon": "", + "images": [] + }, + "adoptopenjdkopenj9jdk": { + "icon": "", + "images": [] + }, + "adoptopenjdkopenj9jre": { + "icon": "", + "images": [] + }, + "adreports": { + "icon": "", + "images": [] + }, + "adrestore": { + "icon": "", + "images": [] + }, + "adrive": { + "icon": "", + "images": [] + }, + "advanced-bat-to-exe-converter": { + "icon": "", + "images": [] + }, + "advanced-codecs": { + "icon": "", + "images": [] + }, + "advanced-file-finder": { + "icon": "https://community.chocolatey.org/content/packageimages/advanced-file-finder.5.0.0.png", + "images": [] + }, + "advanced-installer": { + "icon": "https://community.chocolatey.org/content/packageimages/advanced-installer.20.3.2.png", + "images": [] + }, + "advanced-ip-scanner": { + "icon": "https://community.chocolatey.org/content/packageimages/advanced-ip-scanner.2.5.4594.1.png", + "images": [] + }, + "advanced-ipscanner": { + "icon": "", + "images": [] + }, + "advanced-port-scanner": { + "icon": "", + "images": [] + }, + "advanced-renamer": { + "icon": "https://community.chocolatey.org/content/packageimages/advanced-renamer.portable.3.88.1.png", + "images": [] + }, + "advancedcombattracker": { + "icon": "https://advancedcombattracker.com/act_data/act_banner1.png", + "images": [] + }, + "advancedfilefinder": { + "icon": "https://i.imgur.com/CEW3vDw.png", + "images": [ + "https://www.binarymark.com/img/screens/p23_main.png", + "https://www.binarymark.com/assets/batch-files-processor/screenshots/v3/manualmode.png", + "https://www.binarymark.com/assets/batch-files-processor/screenshots/v3/manualproc.png", + "https://www.binarymark.com/assets/batch-files-processor/screenshots/v3/automode1.png", + "https://www.binarymark.com/assets/batch-files-processor/screenshots/v3/automode5.png" + ] + }, + "advancedinstaller": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/2/22/Advanced-Installer-logo-new.png", + "images": [ + "https://www.advancedinstaller.com/img/index/imgStart.png", + "https://cdn.advancedinstaller.com/img/features/imgMSIAuthoring.png", + "https://cdn.advancedinstaller.com/img/ui/main-screen-shot.png", + "https://origin2.cdn.componentsource.com/sites/default/files/styles/image_large/public/images/product_description/advancedinstaller/advanced-installer-enterprise/img_670536.png", + "https://origin2.cdn.componentsource.com/sites/default/files/styles/carousel_main/public/images/product_description/advancedinstaller/advanced-installer-enterprise/img_670536.png" + ] + }, + "advancedipscanner": { + "icon": "https://i.imgur.com/BDtf1F4.png", + "images": [ + "https://www.advanced-ip-scanner.com/images/aips/screenshots/25/en/main.png", + "https://www.advanced-ip-scanner.com/images/aips/screenshots/24/en/11_tracert.png", + "https://www.advanced-ip-scanner.com/images/aips/screenshots/24/en/07_radmin_control.png", + "https://images.sftcdn.net/images/t_app-cover-l,f_auto/p/8f6d6c3c-96d1-11e6-af95-00163ec9f5fa/3327930924/advanced-ip-scanner-eng%202.jpg", + "https://images.sftcdn.net/images/t_app-cover-l,f_auto/p/8f6d6c3c-96d1-11e6-af95-00163ec9f5fa/3155941051/advanced-ip-scanner-eng%203.jpg" + ] + }, + "advancedlogviewer": { + "icon": "https://windows-cdn.softpedia.com/screenshots/ico/ALV-Advanced-Log-Viewer.gif", + "images": [ + "https://windows-cdn.softpedia.com/screenshots/ALV-Advanced-Log-Viewer_1.png", + "https://windows-cdn.softpedia.com/screenshots/ALV-Advanced-Log-Viewer_2.png", + "https://windows-cdn.softpedia.com/screenshots/ALV-Advanced-Log-Viewer_3.png", + "https://windows-cdn.softpedia.com/screenshots/ALV-Advanced-Log-Viewer_4.png", + "https://windows-cdn.softpedia.com/screenshots/ALV-Advanced-Log-Viewer_5.png", + "https://windows-cdn.softpedia.com/screenshots/ALV-Advanced-Log-Viewer_6.png" + ] + }, + "advancedofficepasswordrecovery": { + "icon": "https://i.postimg.cc/4yhBwPkG/aopr.png", + "images": [ + "https://i.postimg.cc/YS9VY19r/image.png" + ] + }, + "advancedrenamer": { + "icon": "https://i.postimg.cc/kXb269CH/image.png", + "images": [ + "https://i.postimg.cc/k42bTSr9/image.png", + "https://i.postimg.cc/h47mxVb7/image.png", + "https://i.postimg.cc/kGtgbNkH/image.png" + ] + }, + "advancedrestclient": { + "icon": "https://i.imgur.com/wi1FDBh.png", + "images": [ + "https://img.thinstallsoft.com/2020/10/Advanced-REST-Client-Portable.png", + "https://www.geckoandfly.com/wp-content/uploads/2019/05/advance-rest.jpg" + ] + }, + "advancedrun": { + "icon": "https://community.chocolatey.org/content/packageimages/advancedrun.1.51.png", + "images": [ + "https://i.postimg.cc/4xG4MGTv/image.png" + ] + }, + "advancedsystemcare": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/8/89/Advanced_SystemCare_9_logo.png", + "images": [ + "https://i0.wp.com/cracktube.net/wp-content/uploads/2018/08/Advanced-SystemCare-Key-Crack-Free-Download-Updated.png", + "https://www.iobit.com/tpl/images/products/ascfreew/ai_pc.png", + "https://www.iobit.com/tpl/images/products/ascfreew/sp_pc.png", + "https://www.iobit.com/tpl/images/products/ascfreew/pr_pc.png", + "https://www.iobit.com/tpl/images/products/ascfreew/bs_pc.png", + "https://thesweetbits.com/wp-content/uploads/2021/10/advanced-systemcare-pro-15.jpg", + "https://img.creativemark.co.uk/uploads/images/816/15816/img3File.png", + "https://2.bp.blogspot.com/-fGHCoVsY_tQ/XeVEQ2X-quI/AAAAAAAAUm8/bsyDwm4jAooPp2yg84NHU5xvVVj7lfGAgCLcBGAsYHQ/s1600/Advanced%2BSystemCare%2B13%2BPRO%2BFull%2Bversion%2B%2Bspeed%2Bup.png", + "https://www.iobit.com/product-manuals/asc-help/images/mainfeatures/browser-protection.jpg" + ] + }, + "advancedsystemtweaker": { + "icon": "https://community.chocolatey.org/content/packageimages/advancedsystemtweaker.2.0.0.20141128.png", + "images": [] + }, + "adventuregamestudio": { + "icon": "https://i.imgur.com/mmvoQoN.png", + "images": [ + "https://startupstash.com/wp-content/uploads/2022/07/adventure-game-studio.jpg", + "https://upload.wikimedia.org/wikipedia/commons/thumb/1/1b/AGS_SCI_template_Room_1.png/1200px-AGS_SCI_template_Room_1.png" + ] + }, + "advisor": { + "icon": "", + "images": [] + }, + "advor": { + "icon": "https://community.chocolatey.org/content/packageimages/advor.0.3.1.2.png", + "images": [] + }, + "advtor": { + "icon": "https://community.chocolatey.org/content/packageimages/advtor.0.3.1.2.png", + "images": [] + }, + "adwcleaner": { + "icon": "", + "images": [] + }, + "aegisub": { + "icon": "https://icons.iconarchive.com/icons/papirus-team/papirus-apps/512/aegisub-icon.png", + "images": [ + "https://i0.wp.com/www.l10nsoftware.com/wp-content/uploads/2019/07/Aegisub-1.jpg", + "https://static.filehorse.com/screenshots/video-software/aegisub-screenshot-03.png", + "https://upload.wikimedia.org/wikipedia/commons/4/44/Aegisub_screenshot.png", + "https://upload.wikimedia.org/wikipedia/commons/a/a0/Aegisub_2_screenshot.png", + "https://cdn.afterdawn.fi/screenshots/normal/4448.jpg" + ] + }, + "aegisub-dev": { + "icon": "https://icons.iconarchive.com/icons/papirus-team/papirus-apps/512/aegisub-icon.png", + "images": [ + "https://i0.wp.com/www.l10nsoftware.com/wp-content/uploads/2019/07/Aegisub-1.jpg", + "https://static.filehorse.com/screenshots/video-software/aegisub-screenshot-03.png", + "https://upload.wikimedia.org/wikipedia/commons/4/44/Aegisub_screenshot.png", + "https://upload.wikimedia.org/wikipedia/commons/a/a0/Aegisub_2_screenshot.png", + "https://cdn.afterdawn.fi/screenshots/normal/4448.jpg" + ] + }, + "aegisubdc": { + "icon": "", + "images": [] + }, + "aemulusmodmanager": { + "icon": "", + "images": [] + }, + "aeon": { + "icon": "https://i.imgur.com/vslysV8.png", + "images": [ + "https://raw.githubusercontent.com/leinelissen/aeon/master/docs/.gitbook/assets/aeon-demo.gif", + "https://raw.githubusercontent.com/leinelissen/aeon/master/docs/.gitbook/assets/graph.png", + "https://raw.githubusercontent.com/leinelissen/aeon/master/docs/.gitbook/assets/erasure.png", + "https://raw.githubusercontent.com/leinelissen/aeon/master/docs/.gitbook/assets/timeline.png" + ] + }, + "aepctl": { + "icon": "", + "images": [] + }, + "aeroadmin": { + "icon": "https://community.chocolatey.org/content/packageimages/aeroadmin.portable.3.0.2037.png", + "images": [] + }, + "aerozoom": { + "icon": "https://files.softicons.com/download/system-icons/atrous-windows-7-icons-by-iconleak/png/128x128/3.png", + "images": [ + "https://1.bp.blogspot.com/-05uPDrjnQUY/YNiKZT5BWoI/AAAAAAAACzs/pr9bRpTToYAdFvS8UdBoJRzCm9xQiaLMwCLcBGAsYHQ/s0/5583194454_3a71e20ed9_o.png", + "https://1.bp.blogspot.com/-_NeTJC2TBD8/YNiKvj52v1I/AAAAAAAACz0/3BiOYcvyb3ITeyD5Ka7VA3HYbSBgfGgagCLcBGAsYHQ/s0/aerozoom-v1-gui_1.png", + "https://i.imgur.com/DTQGB13.png", + "https://farm8.staticflickr.com/7880/47203430182_17c98b2bee_o.gif" + ] + }, + "aescrypt": { + "icon": "https://community.chocolatey.org/content/packageimages/AESCrypt.3.10.png", + "images": [] + }, + "aether": { + "icon": "https://i.imgur.com/LwEIsPC.png", + "images": [ + "https://getaether.net/images/product-images-v2/pi-1.png", + "https://getaether.net/images/product-images-v2/pi-2.png", + "https://getaether.net/images/product-images-v2/pi-3.png", + "https://getaether.net/images/product-images-v2/pi-4.png", + "https://getaether.net/images/product-images-v2/pi-5.png" + ] + }, + "affine-client": { + "icon": "https://community.chocolatey.org/content/packageimages/affine-client.0.2.0.png", + "images": [] + }, + "afformationrequester": { + "icon": "", + "images": [] + }, + "afterlife": { + "icon": "https://raw.githubusercontent.com/ad3rito/AfterLife/master/src/icon/rocket.png", + "images": [ + "https://raw.githubusercontent.com/AderitoNeto/AfterLife/Master/src/images/Readme/1.PNG", + "https://raw.githubusercontent.com/AderitoNeto/AfterLife/Master/src/images/Readme/2.PNG", + "https://raw.githubusercontent.com/AderitoNeto/AfterLife/Master/src/images/Readme/3.PNG", + "https://raw.githubusercontent.com/AderitoNeto/AfterLife/Master/src/images/Readme/4.PNG", + "https://raw.githubusercontent.com/AderitoNeto/AfterLife/Master/src/images/Readme/5.PNG", + "https://raw.githubusercontent.com/AderitoNeto/AfterLife/Master/src/images/Readme/6.PNG", + "https://raw.githubusercontent.com/AderitoNeto/AfterLife/Master/src/images/Readme/7.PNG" + ] + }, + "ag": { + "icon": "", + "images": [] + }, + "agantty": { + "icon": "https://pbs.twimg.com/profile_images/606166025663574016/7nwzHu5w_400x400.png", + "images": [ + "https://upload.wikimedia.org/wikipedia/commons/thumb/0/05/Gantt-chart-agantty.jpg/640px-Gantt-chart-agantty.jpg", + "https://img.youtube.com/vi/x7eLMIf0UyU/sddefault.jpg", + "https://www.agantty.com/wp-content/themes/planbar-wp/images/agantty-project-management-ganttchart.jpg", + "https://www.agantty.com/wp-content/themes/planbar-wp/images/agantty-project-management-dashboard.jpg", + "https://windows-cdn.softpedia.com/screenshots/Agantty_6.png" + ] + }, + "age": { + "icon": "", + "images": [] + }, + "agen": { + "icon": "", + "images": [] + }, + "agent": { + "icon": "", + "images": [] + }, + "agentgit": { + "icon": "", + "images": [] + }, + "agentransack": { + "icon": "", + "images": [] + }, + "agentsvn": { + "icon": "https://www.zeusedit.com/agent/images/agent_icon.png", + "images": [] + }, + "agfeodashboard": { + "icon": "https://agfeo.de/wp-content/uploads/2020/03/6_Icon_APP_3.png", + "images": [ + "https://i.ytimg.com/vi/4TXgtD4NEVg/maxresdefault.jpg", + "https://www.plenom.com/wp-content/uploads/2019/06/Screenshot-af-AGFEO-1024x539.jpg", + "https://www.agfeo-service.de/media/images/dashboard1.jpg", + "https://docplayer.org/docs-images/111/198726594/images/45-1.jpg", + "https://docplayer.org/docs-images/111/198726594/images/9-1.jpg" + ] + }, + "agg": { + "icon": "", + "images": [] + }, + "ags": { + "icon": "https://community.chocolatey.org/content/packageimages/ags.3.5.1.21.png", + "images": [] + }, + "agwchateaux": { + "icon": "https://community.chocolatey.org/content/packageimages/agwchateaux.portable.1.8.0.png", + "images": [] + }, + "agwmultiactivites": { + "icon": "https://community.chocolatey.org/content/packageimages/agwmultiactivites.portable.1.2.7.png", + "images": [] + }, + "ahmsystemmanager": { + "icon": "", + "images": [ + "https://portalnaglosnieniowy.eu/images/stories/2020/Prezentacje-sprzetu/Allen-Heath-AHM64-Matrix-64x64/Allen-Heath-AHM64-stageboxes-Application-Diagram.jpg", + "https://portalnaglosnieniowy.eu/images/stories/2020/Prezentacje-sprzetu/Allen-Heath-AHM64-Matrix-64x64/Allen-Heath-AHM64-AHM-System-Manager-Channels-Input-Ducker.jpg", + "https://portalnaglosnieniowy.eu/images/stories/2020/Prezentacje-sprzetu/Allen-Heath-AHM64-Matrix-64x64/Allen-Heath-AHM64-AHM-System-Manager-Channels-Out-Zones-Crossovers-Filters.jpg", + "https://portalnaglosnieniowy.eu/images/stories/2020/Prezentacje-sprzetu/Allen-Heath-AHM64-Matrix-64x64/Allen-Heath-AHM64-AHM-System-Manager-Channels-Out-Zones-ANC-Sampling-Noise-Cancellation.jpg" + ] + }, + "ahoy": { + "icon": "", + "images": [] + }, + "ai-chess": { + "icon": "", + "images": [] + }, + "ai-web-originalip": { + "icon": "", + "images": [] + }, + "aida64-business": { + "icon": "", + "images": [ + "https://i.postimg.cc/NfRGBTKw/image.png" + ] + }, + "aida64-engineer": { + "icon": "", + "images": [ + "https://i.postimg.cc/bvhzZv22/image.png" + ] + }, + "aida64-extreme": { + "icon": "", + "images": [ + "https://i.postimg.cc/VsMDRLSN/image.png" + ] + }, + "aida64-networkaudit": { + "icon": "", + "images": [ + "https://i.postimg.cc/gjP5Dwmv/image.png" + ] + }, + "aida64extreme": { + "icon": "", + "images": [ + "https://i.postimg.cc/bvhzZv22/image.png" + ] + }, + "aie": { + "icon": "", + "images": [] + }, + "aimp": { + "icon": "https://cdn2.iconfinder.com/data/icons/flurry-for-audio/512/aimp2.png", + "images": [ + "https://windows-cdn.softpedia.com/screenshots/Portable-AIMP_3.jpg", + "https://www.aimp.ru/v2/pages/features/afw_main-6.png", + "https://upload.wikimedia.org/wikipedia/en/6/6a/AIMP_4_screenshot.png", + "https://www.ghacks.net/wp-content/uploads/2017/10/aimp4-5.png", + "https://www.ghacks.net/wp-content/uploads/2012/11/aimp3.20.jpg", + "https://www.lightbook.org/wp-content/uploads/2018/02/AIMP-2018-1-2.jpg" + ] + }, + "aircrack-ng": { + "icon": "", + "images": [] + }, + "airdroid": { + "icon": "https://i.imgur.com/fJP42G4.png", + "images": [ + "https://i.imgur.com/zkSlJYh.png", + "https://i.imgur.com/x7oZtJr.png", + "https://img-5-cdn.airdroid.com/assets/img/home/lg/pic_biz_personal-b66cf87561.png", + "https://help.airdroid.com/hc/article_attachments/360048877974/How_to_record_phone_screen_in_AirMirror_p1.JPG" + ] + }, + "airexplorer": { + "icon": "https://www.airexplorer.net/en/wp-content/uploads/sites/2/2019/10/cropped-cloud512.png", + "images": [ + "https://www.airexplorer.net/en/wp-content/uploads/sites/2/2019/11/motivoIndex_windows-2.png", + "https://www.airexplorer.net/en/wp-content/uploads/sites/2/2020/09/screenshot_sharelink_black.png", + "https://www.airexplorer.net/en/wp-content/uploads/sites/2/2019/10/cropped-motivo_ayuda_03_en.png" + ] + }, + "airgameplay": { + "icon": "", + "images": [] + }, + "airgameserver": { + "icon": "", + "images": [] + }, + "airparrot-2": { + "icon": "", + "images": [] + }, + "airparrot-3": { + "icon": "", + "images": [ + "https://i.postimg.cc/5tb9BDxc/airparrot-bringt-grafische-bedienoberflaeche-welcher-euch-intuitiv-zurecht-finden-284446.png" + ] + }, + "airserver": { + "icon": "", + "images": [] + }, + "airship": { + "icon": "https://community.chocolatey.org/content/packageimages/airship.2.6.3.20210417.png", + "images": [] + }, + "airshipper": { + "icon": "https://i.imgur.com/I6HBlap.jpg", + "images": [ + "https://linuxmasterclub.com/wp-content/uploads/2021/06/Veloren.-Airshipper-Launcher.png", + "https://upload.wikimedia.org/wikipedia/commons/thumb/d/df/Airshipper.png/580px-Airshipper.png" + ] + }, + "airstream-futuropolis-regular-font": { + "icon": "https://community.chocolatey.org/content/packageimages/airstream-futuropolis-regular-font.1.0.png", + "images": [] + }, + "airtable": { + "icon": "https://cdn.iconscout.com/icon/free/png-256/airtable-1482122-1254387.png", + "images": [ + "https://static.airtable.com/images/homescreen/homepage-sync.jpg", + "https://static.airtable.com/images/homescreen/Homepage_Poster_05_SeeValueFast_FINAL.png", + "https://static.airtable.com/images/homescreen/homepage-apps-dashboard.jpg" + ] + }, + "airtame": { + "icon": "https://community.chocolatey.org/content/packageimages/airtame.4.3.3.png", + "images": [] + }, + "ajour": { + "icon": "https://community.chocolatey.org/content/packageimages/ajour.1.3.2.20211105.png", + "images": [] + }, + "ajour-opengl": { + "icon": "https://community.chocolatey.org/content/packageimages/ajour-opengl.1.3.2.20211105.png", + "images": [] + }, + "akelpad": { + "icon": "https://static.wikia.nocookie.net/logopedia/images/c/c4/Notepad_Vista_10.png", + "images": [ + "https://akelpad.sourceforge.net/files/screen_basic.png", + "https://akelpad.sourceforge.net/files/screen_plugins.png" + ] + }, + "aks-engine": { + "icon": "https://community.chocolatey.org/content/packageimages/aks-engine.0.71.0.png", + "images": [] + }, + "aksctl": { + "icon": "", + "images": [] + }, + "alacritty": { + "icon": "https://raw.githubusercontent.com/alacritty/alacritty/master/extra/logo/compat/alacritty-term%2Bscanlines.png", + "images": [ + "https://i.ytimg.com/vi/S5ra0DUDZww/maxresdefault.jpg", + "https://user-images.githubusercontent.com/8886672/103264352-5ab0d500-49a2-11eb-8961-02f7da66c855.png", + "https://windows-cdn.softpedia.com/screenshots/Alacritty_1.png" + ] + }, + "aladindesktop": { + "icon": "https://i.imgur.com/iATlqUP.png", + "images": [ + "https://aladin.u-strasbg.fr/AladinDesktop/AladinBanner.jpg", + "https://i.ytimg.com/vi/IG_6Eh9EKKk/maxresdefault.jpg", + "https://i.ytimg.com/vi/0iIby3XXvp0/maxresdefault.jpg" + ] + }, + "alanstevens-utils": { + "icon": "", + "images": [] + }, + "alanstevens-utils-vm": { + "icon": "", + "images": [] + }, + "alanstevens-vs2012extensions": { + "icon": "", + "images": [] + }, + "alanstevens-vsextensions": { + "icon": "", + "images": [] + }, + "alarm-cron": { + "icon": "https://raw.githubusercontent.com/bl00mber/alarm-cron/master/screens/logo.png", + "images": [ + "https://raw.githubusercontent.com/bl00mber/alarm-cron/master/screens/interface.png" + ] + }, + "alass": { + "icon": "", + "images": [] + }, + "album-art-downloader": { + "icon": "", + "images": [] + }, + "albumartdownloader": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/0/02/CD_icon_test.svg/1024px-CD_icon_test.svg.png", + "images": [ + "https://www.snapfiles.com/screenfiles/aadownloader.png", + "https://freewaregenius.com/wp-content/uploads/2008/06/album-art-downloader-screenshot3.jpg", + "https://www.chip.de/ii/5/8/4/1/1/0/9/eaf373a13b0756b4.jpg", + "https://www.snapfiles.com/screenfiles/aadownloader2.png" + ] + }, + "albumstomp": { + "icon": "https://community.chocolatey.org/content/packageimages/albumstomp.2.14.png", + "images": [] + }, + "alcohol52-free": { + "icon": "https://community.chocolatey.org/content/packageimages/alcohol52-free.2.0.3.9326.png", + "images": [] + }, + "aleapp": { + "icon": "", + "images": [] + }, + "aleph": { + "icon": "https://i.imgur.com/Vh15Yr6.png", + "images": [ + "https://aleph.chezhe.dev/screenshot.png" + ] + }, + "algernon": { + "icon": "", + "images": [] + }, + "algodoo": { + "icon": "https://www.algodoo.com/mainpage/wp-content/uploads/2013/03/algodoo_logo_algoryx_web.png", + "images": [ + "https://www.algodoo.com/mainpage/wp-content/uploads/2013/03/algodoo_for_education_pyramid-300x187.png", + "https://www.algodoo.com/mainpage/wp-content/uploads/2013/03/algodoo_for_education_start-300x187.png", + "https://www.algodoo.com/mainpage/wp-content/uploads/2013/03/800px-New_algodoo.png" + ] + }, + "aliae": { + "icon": "https://github.githubassets.com/images/icons/emoji/unicode/1f331.png", + "images": [] + }, + "alibabacloudcli": { + "icon": "", + "images": [] + }, + "alice3": { + "icon": "", + "images": [] + }, + "aliceandbob": { + "icon": "https://i.imgur.com/VCbOVS8.png", + "images": [ + "https://raw.githubusercontent.com/aliceandbob-io/files/main/features_generate_v2.png", + "https://raw.githubusercontent.com/aliceandbob-io/files/main/features_encrypt_v2.png", + "https://raw.githubusercontent.com/aliceandbob-io/files/main/features_decrypt_v2.png" + ] + }, + "aliengame": { + "icon": "https://community.chocolatey.org/content/packageimages/aliengame.0.2.31.png", + "images": [] + }, + "aliim": { + "icon": "", + "images": [] + }, + "alipaykeytool": { + "icon": "", + "images": [] + }, + "alist": { + "icon": "", + "images": [] + }, + "aliworkbench": { + "icon": "", + "images": [] + }, + "aliyun": { + "icon": "", + "images": [] + }, + "aliyun-cli": { + "icon": "", + "images": [] + }, + "all-to-mp3": { + "icon": "https://community.chocolatey.org/content/packageimages/all-to-mp3.0.3.3.png", + "images": [] + }, + "alldup": { + "icon": "", + "images": [] + }, + "allow-block-remove-firewall": { + "icon": "", + "images": [] + }, + "allpairs": { + "icon": "", + "images": [] + }, + "allure": { + "icon": "", + "images": [] + }, + "allway-sync": { + "icon": "https://community.chocolatey.org/content/packageimages/allway-sync.20.2.1.png", + "images": [] + }, + "allwaysync": { + "icon": "https://allwaysync.com/themes/allwaysync/img/logo.png", + "images": [ + "https://allwaysync.com/content/img/screenshots/sync-rules.png", + "https://allwaysync.com/content/img/screenshots/auto-sync.png", + "https://allwaysync.com/content/img/screenshots/filters.png", + "https://allwaysync.com/content/img/screenshots/file-versioning.png", + "https://allwaysync.com/content/img/screenshots/error-handling.png" + ] + }, + "allwemo": { + "icon": "", + "images": [] + }, + "alphabiz": { + "icon": "https://i.imgur.com/O9hDfyE.png", + "images": [ + "https://alpha.biz/media/app_img_dark.jpg", + "https://windows-cdn.softpedia.com/screenshots/Alphabiz_1.png", + "https://windows-cdn.softpedia.com/screenshots/Alphabiz_2.png", + "https://windows-cdn.softpedia.com/screenshots/Alphabiz_3.png", + "https://windows-cdn.softpedia.com/screenshots/Alphabiz_4.png", + "https://windows-cdn.softpedia.com/screenshots/Alphabiz_5.png", + "https://windows-cdn.softpedia.com/screenshots/Alphabiz_6.png", + "https://windows-cdn.softpedia.com/screenshots/Alphabiz_7.png", + "https://windows-cdn.softpedia.com/screenshots/Alphabiz_8.png" + ] + }, + "alpinewsl": { + "icon": "", + "images": [] + }, + "alreader2": { + "icon": "https://community.chocolatey.org/content/packageimages/Alreader2.2.5.png", + "images": [] + }, + "alt-tab-terminator": { + "icon": "https://community.chocolatey.org/content/packageimages/alt-tab-terminator.5.6.png", + "images": [] + }, + "altair": { + "icon": "https://raw.githubusercontent.com/altair-graphql/altair/master/icons/android-icon-192x192.png", + "images": [ + "https://altairgraphql.dev/assets/img/app-shot.png", + "https://i.stack.imgur.com/veyfM.png", + "https://i.imgur.com/5zrqWb6.png" + ] + }, + "altap-salamander": { + "icon": "https://community.chocolatey.org/content/packageimages/altap-salamander.4.0.png", + "images": [] + }, + "altcopy": { + "icon": "https://community.chocolatey.org/content/packageimages/altcopy.1.0.7.png", + "images": [] + }, + "altdrag": { + "icon": "https://stefansundin.github.io/altdrag/img/icon128.png", + "images": [ + "https://stefansundin.github.io/altdrag/img/resize.png", + "https://stefansundin.github.io/altdrag/img/configuration_window.png" + ] + }, + "alterego": { + "icon": "", + "images": [] + }, + "alternatestreamview": { + "icon": "https://community.chocolatey.org/content/packageimages/alternatestreamview.1.58.png", + "images": [ + "https://i.postimg.cc/QtFj5xpK/image.png" + ] + }, + "altium-designer": { + "icon": "https://community.chocolatey.org/content/packageimages/altium-designer.21.1.0.24.png", + "images": [] + }, + "altools": { + "icon": "https://community.chocolatey.org/content/packageimages/altools.1.0.0.20191219.png", + "images": [] + }, + "altserver": { + "icon": "https://tweak-box.com/wp-content/uploads/emus4u/2019/10/altstore-app-200px-120x120.png", + "images": [ + "https://ijunkie.com/wp-content/uploads/2020/04/altstore-sideload.jpeg", + "https://images.sftcdn.net/images/t_app-cover-m,f_auto/p/2ee76aed-e3c3-440c-87e2-cf8b1a1fe627/2455918045/altstore-altstore-io-page.png" + ] + }, + "altsnap": { + "icon": "https://stefansundin.github.io/altdrag/img/icon128.png", + "images": [ + "https://raw.githubusercontent.com/RamonUnch/AltSnap/main/HelpImages/TestWindow.png", + "https://raw.githubusercontent.com/RamonUnch/AltSnap/main/HelpImages/GeneralDiag.png", + "https://raw.githubusercontent.com/RamonUnch/AltSnap/main/HelpImages/SnpaLayoutEg.png", + "https://raw.githubusercontent.com/RamonUnch/AltSnap/main/HelpImages/unikeymenu.png", + "https://raw.githubusercontent.com/RamonUnch/AltSnap/main/HelpImages/BlacklistDiag.png" + ] + }, + "altstreamdump": { + "icon": "", + "images": [] + }, + "altus": { + "icon": "", + "images": [] + }, + "alvr": { + "icon": "https://i.imgur.com/rByv98Y.png", + "images": [ + "https://i.imgur.com/0Jxph0u.png", + "https://cdn.mos.cms.futurecdn.net/9PNC57923LTrS76dbHWu2D-1200-80.jpg", + "https://mk0uploadvrcom4bcwhj.kinstacdn.com/wp-content/uploads/2019/06/sidequest-apps.png" + ] + }, + "amarok": { + "icon": "https://i.postimg.cc/ydrZZ6pN/Amarok-icon.png", + "images": [ + "https://i.postimg.cc/4dMY3Ln7/amarok.png" + ] + }, + "amass": { + "icon": "", + "images": [] + }, + "amaya": { + "icon": "", + "images": [] + }, + "amazingmarvin": { + "icon": "", + "images": [] + }, + "amazon-appstream": { + "icon": "https://community.chocolatey.org/content/packageimages/amazon-appstream.1.1.294.png", + "images": [] + }, + "amazon-appstream-usb": { + "icon": "https://community.chocolatey.org/content/packageimages/amazon-appstream-usb.1.1.294.png", + "images": [] + }, + "amazon-assistant-chrome": { + "icon": "", + "images": [] + }, + "amazon-chime": { + "icon": "https://community.chocolatey.org/content/packageimages/amazon-chime.4.39.20018.1.png", + "images": [] + }, + "amazon-ecr-credential-helper": { + "icon": "https://community.chocolatey.org/content/packageimages/amazon-ecr-credential-helper.0.6.0.png", + "images": [] + }, + "amazon-music": { + "icon": "", + "images": [] + }, + "amazon-photos": { + "icon": "", + "images": [] + }, + "amazon-workspaces": { + "icon": "https://community.chocolatey.org/content/packageimages/amazon-workspaces.5.6.4.3457.png", + "images": [] + }, + "ambie": { + "icon": "https://raw.githubusercontent.com/jenius-apps/ambie/main/images/logo_transparent.png", + "images": [ + "https://i.postimg.cc/4NyXvSRF/image.png", + "https://i.postimg.cc/B6NGHxY0/image.png", + "https://i.postimg.cc/Bb6fgXk1/image.png" + ] + }, + "amcacheparser": { + "icon": "", + "images": [] + }, + "amd-ryzen-chipset": { + "icon": "https://community.chocolatey.org/content/packageimages/amd-ryzen-chipset.2022.11.21.png", + "images": [] + }, + "amethyst": { + "icon": "https://i.imgur.com/bbjCj4v.png", + "images": [ + "https://i.postimg.cc/0QkpmCBB/image.png", + "https://i.postimg.cc/gc5ZkdGF/image.png", + "https://i.postimg.cc/DwQJgXLL/image.png", + "https://i.postimg.cc/rmsDMZbz/image.png" + ] + }, + "amfora": { + "icon": "", + "images": [] + }, + "amidst": { + "icon": "https://community.chocolatey.org/content/packageimages/amidst.4.7.png", + "images": [] + }, + "amiduos": { + "icon": "", + "images": [] + }, + "ammonite": { + "icon": "", + "images": [] + }, + "amongus-extraroles": { + "icon": "", + "images": [] + }, + "amp-winoff": { + "icon": "https://community.chocolatey.org/content/packageimages/amp-winoff.install.5.0.1.png", + "images": [] + }, + "ampinstancemanager": { + "icon": "https://i.postimg.cc/fRRC2XL0/amp.png", + "images": [ + "https://i.postimg.cc/wBJm0Thm/Setup.png" + ] + }, + "amsexplorer": { + "icon": "https://community.chocolatey.org/content/packageimages/amsexplorer.5.4.4.0.png", + "images": [] + }, + "amt": { + "icon": "https://community.chocolatey.org/content/packageimages/amt.11.0.png", + "images": [] + }, + "amule": { + "icon": "https://community.chocolatey.org/content/packageimages/amule.install.2.3.1.png", + "images": [] + }, + "amulet": { + "icon": "https://community.chocolatey.org/content/packageimages/amulet.0.10.8.png", + "images": [] + }, + "anaconda2": { + "icon": "https://community.chocolatey.org/content/packageimages/anaconda2.2019.10.png", + "images": [] + }, + "anaconda3": { + "icon": "https://i.imgur.com/Yfn6Mec.png", + "images": [ + "https://assets.anaconda.com/production/Products/Distro01.png?w=700&q=80&auto=format&fit=crop&crop=focalpoint&fp-x=0.5&fp-y=0.5&dm=1647546929&s=7a22f8ac8ef3c673d6522750d19073e5", + "https://assets.anaconda.com/production/Products/distro02-a.png?w=700&q=80&auto=format&fit=crop&crop=focalpoint&fp-x=0.5&fp-y=0.5&dm=1648141889&s=cf0f76189199988679e3b8195489ba18", + "https://assets.anaconda.com/production/Products/Distro03.png?w=700&q=80&auto=format&fit=crop&crop=focalpoint&fp-x=0.5&fp-y=0.5&dm=1647546960&s=71ec759bbe7909f56d95b96c38718b73", + "https://assets.anaconda.com/production/Products/Distro04-new.png?w=700&q=80&auto=format&fit=crop&crop=focalpoint&fp-x=0.5&fp-y=0.5&dm=1647548959&s=2061f01602dc7917a72a1cf73da9f3a7" + ] + }, + "analyzer2go": { + "icon": "https://community.chocolatey.org/content/packageimages/analyzer2go.2.2.png", + "images": [] + }, + "android-clt": { + "icon": "", + "images": [] + }, + "android-line-transfer": { + "icon": "", + "images": [] + }, + "android-log-viewer": { + "icon": "", + "images": [] + }, + "android-messages": { + "icon": "", + "images": [] + }, + "android-messages-desktop": { + "icon": "https://community.chocolatey.org/content/packageimages/android-messages-desktop.3.1.0.png", + "images": [] + }, + "android-ndk": { + "icon": "https://community.chocolatey.org/content/packageimages/android-ndk.25.2.png", + "images": [] + }, + "android-payload-dumper": { + "icon": "", + "images": [] + }, + "android-sdk": { + "icon": "", + "images": [] + }, + "android-sms-backup-and-restore": { + "icon": "", + "images": [] + }, + "android-studio": { + "icon": "https://i.imgur.com/FfKcF2R.png", + "images": [] + }, + "android11react": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/a/a7/React-icon.svg/2300px-React-icon.svg.png", + "images": [ + "https://raw.githubusercontent.com/blueedgetechno/androidInReact/master/public/gall1.png", + "https://raw.githubusercontent.com/blueedgetechno/androidInReact/master/public/gall2.png" + ] + }, + "androidstudio": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/e/e3/Android_Studio_Icon_%282014-2019%29.svg/1200px-Android_Studio_Icon_%282014-2019%29.svg.png", + "images": [ + "https://www.aceinfoway.com/blog/wp-content/uploads/2020/12/android-studio_plugins.jpg", + "https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiC2X0sIY_AGvgi6jD8Eh_u8rOdZXKA6PP18tnJdA6jQxR-n4bF6vsIVI2D4FTOnHAlqSY5hJShEjHcRQr7P8QM-YyP3sM3Su_KxFRdBXhg8WUIoXr74luWfFvtgYGJHWdDe_gPnwpCsLR4YhE0U88QcSqrYs3LLjp7dGqQul_pRoerJr__-mD8lUPA/s1600/Android-IO22AndroidDevRecap_Social.png", + "https://1.bp.blogspot.com/-b1_n6tOHvWU/YKMssWEjo-I/AAAAAAAAQjk/vIJQsAPUpRQKxR44GoCbm3CtRgr8tVBKACLcBGAsYHQ/s0/Android_NewForDevelopers_1024x512_updated.png", + "https://pbs.twimg.com/media/EeL1D6cWkAEWgTC.png", + "https://developer.android.com/static/studio/images/releases/compose-multipreview-annotations.png", + "https://i.ytimg.com/vi/kMI2jy-WlGM/maxresdefault.jpg" + ] + }, + "androidstudio-beta": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/e/e3/Android_Studio_Icon_%282014-2019%29.svg/1200px-Android_Studio_Icon_%282014-2019%29.svg.png", + "images": [ + "https://www.aceinfoway.com/blog/wp-content/uploads/2020/12/android-studio_plugins.jpg", + "https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiC2X0sIY_AGvgi6jD8Eh_u8rOdZXKA6PP18tnJdA6jQxR-n4bF6vsIVI2D4FTOnHAlqSY5hJShEjHcRQr7P8QM-YyP3sM3Su_KxFRdBXhg8WUIoXr74luWfFvtgYGJHWdDe_gPnwpCsLR4YhE0U88QcSqrYs3LLjp7dGqQul_pRoerJr__-mD8lUPA/s1600/Android-IO22AndroidDevRecap_Social.png", + "https://1.bp.blogspot.com/-b1_n6tOHvWU/YKMssWEjo-I/AAAAAAAAQjk/vIJQsAPUpRQKxR44GoCbm3CtRgr8tVBKACLcBGAsYHQ/s0/Android_NewForDevelopers_1024x512_updated.png", + "https://pbs.twimg.com/media/EeL1D6cWkAEWgTC.png", + "https://developer.android.com/static/studio/images/releases/compose-multipreview-annotations.png", + "https://i.ytimg.com/vi/kMI2jy-WlGM/maxresdefault.jpg" + ] + }, + "androidstudio-canary": { + "icon": "https://i.imgur.com/GAcvIsP.png", + "images": [ + "https://i.imgur.com/YjOIZFc.jpg", + "https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiC2X0sIY_AGvgi6jD8Eh_u8rOdZXKA6PP18tnJdA6jQxR-n4bF6vsIVI2D4FTOnHAlqSY5hJShEjHcRQr7P8QM-YyP3sM3Su_KxFRdBXhg8WUIoXr74luWfFvtgYGJHWdDe_gPnwpCsLR4YhE0U88QcSqrYs3LLjp7dGqQul_pRoerJr__-mD8lUPA/s1600/Android-IO22AndroidDevRecap_Social.png", + "https://1.bp.blogspot.com/-b1_n6tOHvWU/YKMssWEjo-I/AAAAAAAAQjk/vIJQsAPUpRQKxR44GoCbm3CtRgr8tVBKACLcBGAsYHQ/s0/Android_NewForDevelopers_1024x512_updated.png", + "https://pbs.twimg.com/media/EeL1D6cWkAEWgTC.png", + "https://developer.android.com/static/studio/images/releases/compose-multipreview-annotations.png", + "https://i.ytimg.com/vi/kMI2jy-WlGM/maxresdefault.jpg" + ] + }, + "angband": { + "icon": "https://community.chocolatey.org/content/packageimages/angband.4.2.4.png", + "images": [] + }, + "angry-birds-star-wars": { + "icon": "", + "images": [] + }, + "angryip": { + "icon": "", + "images": [] + }, + "angryipscanner": { + "icon": "https://angryip.org/images/icon.png", + "images": [ + "https://angryip.org/screenshots/ipscan-win10.png" + ] + }, + "ani-cli": { + "icon": "", + "images": [] + }, + "anime-library": { + "icon": "https://i.imgur.com/uYEi0F6.png", + "images": [ + "https://user-images.githubusercontent.com/1662812/138271729-b6004bd9-f8cb-4d92-a0ef-784c7694108d.png", + "https://user-images.githubusercontent.com/1662812/138271791-7d1b32ec-c989-4f9c-bddf-86a89177b075.png", + "https://user-images.githubusercontent.com/1662812/138271883-dbf360fd-244d-4bf3-a546-21554337ce18.png", + "https://user-images.githubusercontent.com/1662812/138271926-4f0b2bc8-8acc-44bc-9c15-0f3c501363ef.png", + "https://user-images.githubusercontent.com/1662812/138272119-40405411-20fd-4c4d-b81f-c0aa80d4c903.png", + "https://user-images.githubusercontent.com/1662812/138272147-a7b2a25f-f9d7-4752-a4c1-cb17dc3b8c29.png" + ] + }, + "animeback": { + "icon": "https://i.imgur.com/ih7APQ2.png", + "images": [ + "https://raw.githubusercontent.com/LeGitHubDeTai/AnimeBack/main/assets/images/options.png", + "https://raw.githubusercontent.com/LeGitHubDeTai/AnimeBack/main/assets/images/tray%20options.png", + "https://raw.githubusercontent.com/LeGitHubDeTai/AnimeBack/main/assets/images/options%20window.png", + "https://raw.githubusercontent.com/LeGitHubDeTai/AnimeBack/main/assets/images/changelog%20window.png", + "https://raw.githubusercontent.com/LeGitHubDeTai/AnimeBack/main/assets/images/add%20extensions.png", + "https://raw.githubusercontent.com/LeGitHubDeTai/AnimeBack/main/assets/images/add%20custom.png" + ] + }, + "anireel": { + "icon": "", + "images": [] + }, + "ankhsvn": { + "icon": "https://community.chocolatey.org/content/packageimages/AnkhSvn.2.5.12703.png", + "images": [] + }, + "anki": { + "icon": "https://i.redd.it/cruevyf68dt31.png", + "images": [ + "https://images.squarespace-cdn.com/content/v1/58eada9abe659458e85c3f68/1532751018464-0U0KMM5L0XH731KAZ27K/01.png", + "https://remembereverything.org/wp-content/uploads/2016/10/Vocabulary-card-Anki-2.jpg", + "https://uploads-ssl.webflow.com/5dc6cc5bc19d438a53fbbaa9/607c90200e3c5babc5c380c0_German%20Noun%20Flashcards%20by%20Visual%20German.png", + "https://www.kenhub.com/thumbor/nBD7DFKLXiTizFxC7zjVEJea9qU=/fit-in/800x1600/filters:watermark(/images/logo_url.png,-10,-10,0):background_color(FFFFFF):format(jpeg)/images/article/en/how-to-learn-anatomy-with-anki/ZCM4XlKl0rGO6bWuw9d7FA_anki3.png" + ] + }, + "annatar": { + "icon": "", + "images": [] + }, + "another-redis-desktop-manager": { + "icon": "https://community.chocolatey.org/content/packageimages/another-redis-desktop-manager.1.5.9.png", + "images": [] + }, + "anotherredisdesktopmanager": { + "icon": "https://i.imgur.com/XEqwRMy.png", + "images": [ + "https://i.imgur.com/j8X8erw.png", + "https://i.imgur.com/NJr39pR.png", + "https://i.imgur.com/JRDNdYT.png", + "https://i.imgur.com/pirCiFg.png" + ] + }, + "ansiblevaultcmd": { + "icon": "", + "images": [] + }, + "ansicon": { + "icon": "", + "images": [] + }, + "ansifilter": { + "icon": "https://community.chocolatey.org/content/packageimages/ansifilter.2.18.png", + "images": [] + }, + "ant": { + "icon": "", + "images": [] + }, + "ant-renamer": { + "icon": "https://community.chocolatey.org/content/packageimages/ant-renamer.2.12.0.20170526.png", + "images": [] + }, + "antares": { + "icon": "https://antares-sql.app/_nuxt/logo.3ded7749.png", + "images": [ + "https://raw.githubusercontent.com/Fabio286/antares/master/docs/gh-logo.png", + "https://antares-sql.app/images/screen1c.png", + "https://antares-sql.app/images/screen4.png", + "https://res.cloudinary.com/canonical/image/fetch/f_auto,q_auto,fl_sanitize,w_819,h_569/https://dashboard.snapcraft.io/site_media/appmedia/2022/09/Immagine_2022-09-22_101124.png", + "https://pbs.twimg.com/media/FMWoNXpXMAM7avj.jpg" + ] + }, + "antidupl": { + "icon": "https://community.chocolatey.org/content/packageimages/antidupl.2.3.9.png", + "images": [] + }, + "antidupl-net": { + "icon": "", + "images": [] + }, + "antimicro": { + "icon": "https://i.imgur.com/i5LJvyI.png", + "images": [ + "https://sc.filehippo.net/images/t_app-cover-m,f_auto/p/6eb28e07-8d98-497d-9784-43c30fd0d31b/133226868/antimicro-1.png", + "https://windows-cdn.softpedia.com/screenshots/antimicro-Portable_1.png", + "https://windows-cdn.softpedia.com/screenshots/antimicro-Portable_2.png", + "https://www.filecroco.com/wp-content/uploads/2018/07/antimicro-3.jpg" + ] + }, + "antimicrox": { + "icon": "", + "images": [] + }, + "antimicroxportable": { + "icon": "", + "images": [] + }, + "antrenamer": { + "icon": "https://antp.be/img/softico_renamer.png", + "images": [ + "https://www.howtoanswer.com/articles/windows/Rename_multiple_files_and_folders_at_once_in_Windows/sshot-5.png", + "https://www.howtoanswer.com/articles/windows/Rename_multiple_files_and_folders_at_once_in_Windows/sshot-6.png", + "https://www.howtoanswer.com/articles/windows/Rename_multiple_files_and_folders_at_once_in_Windows/sshot-7.png", + "https://www.howtoanswer.com/articles/windows/Rename_multiple_files_and_folders_at_once_in_Windows/sshot-8.png" + ] + }, + "antutubenchmark": { + "icon": "", + "images": [] + }, + "anvide-seal-folder": { + "icon": "https://community.chocolatey.org/content/packageimages/anvide-seal-folder.5.30.png", + "images": [] + }, + "anvilstudio": { + "icon": "https://anvilstudio.com/s/logo175_163.jpg", + "images": [ + "https://imag.malavida.com/mvimgbig/download-fs/anvil-studio-15716-3.jpg", + "https://cdn.afterdawn.fi/screenshots/normal/19840.jpg", + "https://img.informer.com/screenshots/2963/2963166_1.jpg", + "https://img.informer.com/screenshots/2963/2963166_2.jpg", + "https://img.informer.com/screenshots/2963/2963166_3.jpg", + "https://img.informer.com/screenshots/2963/2963166_4.jpg" + ] + }, + "any2ico": { + "icon": "https://community.chocolatey.org/content/packageimages/any2ico.2.4.0.0.png", + "images": [] + }, + "anyburn": { + "icon": "", + "images": [ + "https://kubadownload.com/site/assets/files/1732/anyburn-1.png", + "https://cdn.neow.in/news/images/uploaded/2016/03/freeanyburn.jpg" + ] + }, + "anydesk": { + "icon": "https://img.icons8.com/fluency/512/anydesk.png", + "images": [ + "https://cdn.mos.cms.futurecdn.net/rGU2S5Jz22yFy28i5shEFL.jpg", + "https://cdn.afterdawn.fi/screenshots/normal/20813.jpg", + "https://static.sitejabber.com/img/urls/1323983/picture_374006.1626670964.jpg" + ] + }, + "anydo": { + "icon": "https://i.postimg.cc/43QGKq9x/image.png", + "images": [ + "https://www.any.do/v4/images/pc/calendar@2x.png", + "https://gdm-catalog-fmapi-prod.imgix.net/ProductScreenshot/869cbc09-bd48-47df-b65e-00eed3b27217.jpg", + "https://images.saasworthy.com/anydo_7454_screenshot_1591679649_adivu.jpg", + "https://pbs.twimg.com/media/Ek13rtrXEAAqVOe.jpg" + ] + }, + "anydvd": { + "icon": "https://community.chocolatey.org/content/packageimages/anydvd.8.6.3.0.png", + "images": [] + }, + "anylogic-personal": { + "icon": "https://i.imgur.com/82aJSKc.png", + "images": [ + "https://www.anylogic.com/upload/medialibrary/566/566c613f09bb7819a2aa4aa6bd3470f9.jpg", + "https://www.anylogic.com/upload/medialibrary/806/806cefb15119b22d3619843573dad71b.jpg", + "https://www.anylogic.com/upload/medialibrary/3f5/3f59466cdff47b9e1438c2a5ac2f8d71.jpg", + "https://www.anylogic.com/upload/medialibrary/1gf/10.png", + "https://www.anylogic.com/upload/medialibrary/1gf/13.png", + "https://www.anylogic.com/upload/medialibrary/1gf/15.png", + "https://www.anylogic.com/upload/medialibrary/1gf/16.png", + "https://www.anylogic.com/upload/medialibrary/1gf/17.png", + "https://www.anylogic.com/upload/medialibrary/1gf/18.png" + ] + }, + "anylogic-professional": { + "icon": "https://i.imgur.com/IL1dloo.png", + "images": [ + "https://www.anylogic.com/upload/medialibrary/566/566c613f09bb7819a2aa4aa6bd3470f9.jpg", + "https://www.anylogic.com/upload/medialibrary/806/806cefb15119b22d3619843573dad71b.jpg", + "https://www.anylogic.com/upload/medialibrary/3f5/3f59466cdff47b9e1438c2a5ac2f8d71.jpg", + "https://www.anylogic.com/upload/medialibrary/1gf/10.png", + "https://www.anylogic.com/upload/medialibrary/1gf/13.png", + "https://www.anylogic.com/upload/medialibrary/1gf/15.png", + "https://www.anylogic.com/upload/medialibrary/1gf/16.png", + "https://www.anylogic.com/upload/medialibrary/1gf/17.png", + "https://www.anylogic.com/upload/medialibrary/1gf/18.png" + ] + }, + "anylogic-university": { + "icon": "https://i.imgur.com/IL1dloo.png", + "images": [ + "https://www.anylogic.com/upload/medialibrary/566/566c613f09bb7819a2aa4aa6bd3470f9.jpg", + "https://www.anylogic.com/upload/medialibrary/806/806cefb15119b22d3619843573dad71b.jpg", + "https://www.anylogic.com/upload/medialibrary/3f5/3f59466cdff47b9e1438c2a5ac2f8d71.jpg", + "https://www.anylogic.com/upload/medialibrary/1gf/10.png", + "https://www.anylogic.com/upload/medialibrary/1gf/13.png", + "https://www.anylogic.com/upload/medialibrary/1gf/15.png", + "https://www.anylogic.com/upload/medialibrary/1gf/16.png", + "https://www.anylogic.com/upload/medialibrary/1gf/17.png", + "https://www.anylogic.com/upload/medialibrary/1gf/18.png" + ] + }, + "anyrail6": { + "icon": "https://community.chocolatey.org/content/packageimages/AnyRail6.6.50.2.png", + "images": [] + }, + "anystream": { + "icon": "https://community.chocolatey.org/content/packageimages/anystream.1.5.1.0.png", + "images": [] + }, + "anytoiso": { + "icon": "https://crystalidea.com/assets/images/anytoiso/icon_32.png", + "images": [ + "https://crystalidea.com/assets/images/anytoiso/carousel1.png", + "https://crystalidea.com/assets/images/anytoiso/carousel2.png", + "https://crystalidea.com/assets/images/anytoiso/carousel3.png" + ] + }, + "anytxtsearcher": { + "icon": "https://anytxt.net/wp-content/uploads/2019/11/Anytxt-searcher-logo.png", + "images": [ + "https://anytxt.net/wp-content/uploads/2022/03/Anytxt-web-full-text-search-1024x594-1.png", + "https://anytxt.net/wp-content/uploads/2022/10/20221007014339.png", + "https://anytxt.net/wp-content/uploads/2021/05/2021-5-29-2-768x461.png", + "https://a.fsdn.com/con/app/proj/anytxt/screenshots/eg5.jpg", + "https://anytxt.net/wp-content/uploads/2021/05/20210529192946-768x449.png", + "https://anytxt.net/wp-content/uploads/2021/05/20210529193138-768x449.png", + "https://anytxt.net/wp-content/uploads/2021/05/20210529193239-1-768x449.png", + "https://anytxt.net/wp-content/uploads/2021/05/20210529193408-768x451.png" + ] + }, + "anytype": { + "icon": "https://community-static.anytype.io/optimized/2X/1/1b350d4c2b5d324e5bdfd837ba7ec4057c5ee3e6_2_499x500.png", + "images": [] + }, + "anyvideoconverter": { + "icon": "https://community.chocolatey.org/content/packageimages/anyvideoconverter.6.0.0.png", + "images": [] + }, + "anyvizcloudadapter": { + "icon": "https://us.store.codesys.com/media/catalog/product/cache/adefa4dac3229abc7b8dba2f1e919681/i/c/icon_000089_AnyVisz_Cloud_Adapter.png", + "images": [ + "https://www.anyviz.io/wp-content/uploads/2021/09/Cloud-Adapter-News-1024x536.png", + "https://us.store.codesys.com/media/catalog/product/cache/3bdc815eb46cb7b9d94251c144719462/s/c/screen_0_000089_anyvisz_cloud_adapter.png", + "https://res.cloudinary.com/canonical/image/fetch/f_auto,q_auto,fl_sanitize,w_819,h_464/https://dashboard.snapcraft.io/site_media/appmedia/2020/06/UniversalCloudAdapter.PNG", + "https://www.anyviz.io/wp-content/uploads/2019/07/Universal-Cloud-Adapter_UI.png", + "https://res.cloudinary.com/canonical/image/fetch/f_auto,q_auto,fl_sanitize,w_819,h_487/https://dashboard.snapcraft.io/site_media/appmedia/2020/06/Desktop_01.PNG" + ] + }, + "ao": { + "icon": "https://raw.githubusercontent.com/klaussinani/ao/master/docs/media/logo.png", + "images": [ + "https://raw.githubusercontent.com/klaussinani/ao/master/docs/media/list-navigation.gif" + ] + }, + "aoc-cli": { + "icon": "", + "images": [] + }, + "aorus-engine": { + "icon": "https://pics.computerbase.de/7/7/8/1/6/logo-256.png", + "images": [ + "https://i.ytimg.com/vi/dpZHSmUwpvI/maxresdefault.jpg", + "https://www.nikktech.com/main/images/pics/reviews/gigabyte/gv_n207saorus_8gc/aorus_engine_1.jpg", + "https://www.servethehome.com/wp-content/uploads/2019/05/Gigabyte-GTX1650-OC-4GB-AORUS-Engine.jpg", + "https://www.theoverclocker.com/wp-content/uploads/2018/12/AORUS-Utility.jpg" + ] + }, + "apache": { + "icon": "", + "images": [] + }, + "apache-cassandra": { + "icon": "https://community.chocolatey.org/content/packageimages/apache-cassandra.3.7.png", + "images": [] + }, + "apache-directory-studio": { + "icon": "", + "images": [] + }, + "apache-fop": { + "icon": "https://community.chocolatey.org/content/packageimages/apache-fop.2.6.png", + "images": [] + }, + "apache-httpd": { + "icon": "https://community.chocolatey.org/content/packageimages/apache-httpd.2.4.55.png", + "images": [] + }, + "apache-ivy": { + "icon": "", + "images": [] + }, + "apache-netbeans": { + "icon": "", + "images": [] + }, + "apache-tinkerpop-gremlin-console": { + "icon": "", + "images": [] + }, + "apache-tinkerpop-gremlin-server": { + "icon": "", + "images": [] + }, + "apache-zookeeper": { + "icon": "https://community.chocolatey.org/content/packageimages/apache-zookeeper.3.4.9.png", + "images": [] + }, + "apachecommonsdaemon": { + "icon": "", + "images": [] + }, + "apacheds": { + "icon": "https://community.chocolatey.org/content/packageimages/apacheds.2.0.0.19.png", + "images": [] + }, + "ape": { + "icon": "https://community.chocolatey.org/content/packageimages/ape.3.1.256.png", + "images": [] + }, + "apfs": { + "icon": "https://i.imgur.com/zd6eSy1.png", + "images": [ + "https://www.paragon-software.com/wp-content/uploads/2018/06/Volumes_sample1.png", + "https://www.paragon-software.com/wp-content/uploads/2018/06/File_transfer_sample.png" + ] + }, + "aphemo": { + "icon": "", + "images": [] + }, + "apifox": { + "icon": "https://i.imgur.com/SSjFNQ6.png", + "images": [ + "https://cdn.apifox.cn/www/screenshot/dark-apifox-api-case-1.png", + "https://cdn.apifox.cn/www/screenshot/dark-apifox-schema-1.png", + "https://cdn.apifox.cn/www/screenshot/dark-apifox-api-definition-2.png", + "https://cdn.apifox.cn/www/screenshot/dark-apifox-test-case-1.png", + "https://cdn.apifox.cn/www/screenshot/dark-apifox-test-case-2.png", + "https://cdn.apifox.cn/www/screenshot/dark-apifox-test-case-3.png", + "https://cdn.apifox.cn/www/screenshot/dark-apifox-mock-1.png", + "https://cdn.apifox.cn/www/screenshot/dark-apifox-mock-2.png", + "https://cdn.apifox.cn/www/screenshot/dark-apifox-mock-3.png", + "https://cdn.apifox.cn/www/screenshot/dark-apifox-codegen-1.png", + "https://cdn.apifox.cn/www/screenshot/dark-apifox-codegen-2.png", + "https://cdn.apifox.cn/www/screenshot/dark-apifox-setting-import-1.png", + "https://cdn.apifox.cn/www/screenshot/light-apifox-theme-1.png" + ] + }, + "apimonitor": { + "icon": "https://community.chocolatey.org/content/packageimages/apimonitor.2.13.0.20210213.png", + "images": [] + }, + "apimtemplate": { + "icon": "", + "images": [] + }, + "apincorepywr-vsix": { + "icon": "https://community.chocolatey.org/content/packageimages/apincorepywr-vsix.1.2.png", + "images": [] + }, + "apkeep": { + "icon": "", + "images": [] + }, + "apkinstaller-classic": { + "icon": "https://raw.githubusercontent.com/Paving-Base/APK-Installer-Classic/main/logo.png", + "images": [ + "https://raw.githubusercontent.com/Paving-Base/APK-Installer-Classic/main/Images/Guides/Snipaste_2019-10-12_22-46-37.png", + "https://raw.githubusercontent.com/Paving-Base/APK-Installer-Classic/main/Images/Guides/Snipaste_2019-10-19_15-28-58.png", + "https://raw.githubusercontent.com/Paving-Base/APK-Installer-Classic/main/Images/Guides/Snipaste_2019-10-20_23-36-44.png", + "https://raw.githubusercontent.com/Paving-Base/APK-Installer-Classic/main/Images/Guides/Snipaste_2019-10-13_12-42-40.png", + "https://raw.githubusercontent.com/Paving-Base/APK-Installer-Classic/main/Images/Screenshots/Snipaste_2022-01-03_01-07-53.png" + ] + }, + "apkrepatcher": { + "icon": "https://community.chocolatey.org/content/packageimages/apkrepatcher.1.1.0.png", + "images": [] + }, + "apktool": { + "icon": "https://community.chocolatey.org/content/packageimages/apktool.2.7.0.png", + "images": [] + }, + "apngasm": { + "icon": "", + "images": [] + }, + "apo-ok": { + "icon": "https://community.chocolatey.org/content/packageimages/apo-ok.5.22.png", + "images": [] + }, + "app-shop": { + "icon": "https://community.chocolatey.org/content/packageimages/app-shop.1.0.31.png", + "images": [] + }, + "appbuster": { + "icon": "", + "images": [] + }, + "appcharger": { + "icon": "https://community.chocolatey.org/content/packageimages/appcharger.1.0.6.png", + "images": [] + }, + "appcheck": { + "icon": "https://i.imgur.com/WKl5ATc.png", + "images": [ + "https://www.checkmal.com/_res/img/view/product/en/img-appcheck-screenshot-1.png", + "https://www.checkmal.com/_res/img/view/product/en/img-appcheck-screenshot-11.png", + "https://www.checkmal.com/_res/img/view/product/en/img-appcheck-screenshot-2.png", + "https://www.checkmal.com/_res/img/view/product/en/img-appcheck-screenshot-4.png", + "https://www.checkmal.com/_res/img/view/product/en/img-appcheck-screenshot-5.png", + "https://www.checkmal.com/_res/img/view/product/en/img-appcheck-screenshot-6.png", + "https://www.checkmal.com/_res/img/view/product/en/img-appcheck-screenshot-7.png", + "https://www.checkmal.com/_res/img/view/product/en/img-appcheck-screenshot-8.png", + "https://www.checkmal.com/_res/img/view/product/en/img-appcheck-screenshot-9.png" + ] + }, + "appcompat-cacheparser": { + "icon": "", + "images": [] + }, + "appcrashview": { + "icon": "", + "images": [ + "https://i.postimg.cc/ryt8wsVv/image.png" + ] + }, + "appease-client-powershell": { + "icon": "https://community.chocolatey.org/content/packageimages/appease.client.powershell.0.0.88.png", + "images": [] + }, + "appengine-go": { + "icon": "", + "images": [] + }, + "appfabric-caching": { + "icon": "", + "images": [] + }, + "appflowy": { + "icon": "https://raw.githubusercontent.com/AppFlowy-IO/AppFlowy/main/frontend/appflowy_flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset/256.png", + "images": [ + "https://raw.githubusercontent.com/AppFlowy-IO/AppFlowy-Website/main/assets/images/hero-section/desktop.png", + "https://raw.githubusercontent.com/AppFlowy-IO/AppFlowy/main/doc/imgs/welcome.png" + ] + }, + "appgallery": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/f/f6/Huawei_AppGallery.svg/2048px-Huawei_AppGallery.svg.png", + "images": [ + "https://www.huaweicentral.com/wp-content/uploads/2020/02/appgallery-ftrd-img-2.jpg", + "https://drscmedia.eu/wp-content/uploads/2019/10/HwAppGalleryBanner-678x381.jpg", + "https://www.huaweinewos.com/wp-content/uploads/2020/12/AppGallery-Market-PC-version-download-01-600x301.jpg", + "https://www.huaweinewos.com/wp-content/uploads/2020/12/AppGallery-Application-Market-PC-006-600x362.jpg", + "https://www.huaweinewos.com/wp-content/uploads/2020/12/AppGallery-Application-Market-PC-003-600x277.jpg" + ] + }, + "appharborcli": { + "icon": "https://community.chocolatey.org/content/packageimages/appharborcli.install.1.2.png", + "images": [] + }, + "appinstaller": { + "icon": "https://i.postimg.cc/76k6y060/image.png", + "images": [ + "https://i.postimg.cc/qMCGmH9Y/image.png" + ] + }, + "appinstallerfilebuilder": { + "icon": "", + "images": [] + }, + "appinstallrecorder": { + "icon": "", + "images": [] + }, + "appium": { + "icon": "https://static-00.iconduck.com/assets.00/appium-icon-255x256-5yix6ocd.png", + "images": [ + "https://www.automationtestinghub.com/images/appium/appium-desktop-latest.png", + "https://user-images.githubusercontent.com/26970971/35574693-69fbf0ce-05d2-11e8-861f-c9bb37f2b75a.png", + "https://static1.smartbear.co/smartbearbrand/media/images/blog/blogimages/use-appium-desktop-3.png", + "https://www.einfochips.com/blog/wp-content/uploads/2018/02/004-appium-inspector.png" + ] + }, + "appium-desktop": { + "icon": "https://community.chocolatey.org/content/packageimages/appium-desktop.1.20.2.png", + "images": [] + }, + "applicationcompatibilitytoolkit": { + "icon": "https://community.chocolatey.org/content/packageimages/applicationcompatibilitytoolkit.5.6.png", + "images": [] + }, + "appverifier": { + "icon": "https://community.chocolatey.org/content/packageimages/appverifier.4.0.665.png", + "images": [] + }, + "appveyor-server": { + "icon": "https://community.chocolatey.org/content/packageimages/appveyor-server.7.0.3212.png", + "images": [] + }, + "appveyorbyoc-powershell": { + "icon": "https://community.chocolatey.org/content/packageimages/appveyorbyoc.powershell.1.0.182.png", + "images": [] + }, + "appvmanage": { + "icon": "", + "images": [] + }, + "appvprovider": { + "icon": "https://community.chocolatey.org/content/packageimages/appvprovider.0.6.0.4.png", + "images": [] + }, + "aptana-studio": { + "icon": "https://community.chocolatey.org/content/packageimages/aptana-studio.3.7.2.png", + "images": [] + }, + "aqt": { + "icon": "", + "images": [] + }, + "aqtinstall": { + "icon": "", + "images": [] + }, + "aqua-eap": { + "icon": "", + "images": [] + }, + "aquasnap": { + "icon": "https://static.techspot.com/images2/downloads/topdownload/2014/11/aquasnap.png", + "images": [ + "https://i.ytimg.com/vi/bOVOEebpiWc/maxresdefault.jpg", + "https://i.ytimg.com/vi/_x2fj7JIuzE/maxresdefault.jpg", + "https://getintopc.today/wp-content/uploads/2021/10/Aquasnap.jpg", + "https://www.nurgo-software.com/images/AquaSnap/Docking.gif", + "https://www.nurgo-software.com/images/AquaSnap/AquaShake.gif" + ] + }, + "aquila-wakeonlan": { + "icon": "https://community.chocolatey.org/content/packageimages/Aquila-WakeOnLAN.2.12.4.png", + "images": [] + }, + "arc": { + "icon": "https://i.postimg.cc/rpdm7tmJ/icon-arc.png", + "images": [ + "https://i.postimg.cc/9fHtfV7y/arc.png" + ] + }, + "arc-prerelease": { + "icon": "", + "images": [] + }, + "arcanist": { + "icon": "", + "images": [] + }, + "arccommander": { + "icon": "", + "images": [] + }, + "arcfacilitiessync": { + "icon": "https://community.chocolatey.org/content/packageimages/ARCFacilitiesSync.3.0.0.png", + "images": [] + }, + "archi": { + "icon": "https://community.chocolatey.org/content/packageimages/Archi.4.10.0.png", + "images": [] + }, + "archisteamfarm": { + "icon": "https://raw.githubusercontent.com/JustArchiNET/ArchiSteamFarm/main/resources/ASF_512x512.png", + "images": [ + "https://raw.githubusercontent.com/JustArchiNET/ASF-ui/main/.github/previews/bots.png" + ] + }, + "archive": { + "icon": "", + "images": [] + }, + "archivepassword": { + "icon": "https://i.postimg.cc/SQPYg2yy/ARCHPR.png", + "images": [ + "https://i.postimg.cc/8zmM3pwy/image.png", + "https://i.postimg.cc/0jSJCPb0/image.png", + "https://i.postimg.cc/FsjLdFt9/image.png" + ] + }, + "archiver": { + "icon": "", + "images": [] + }, + "archivo-narrow-font": { + "icon": "", + "images": [] + }, + "archwsl": { + "icon": "", + "images": [] + }, + "arctype": { + "icon": "https://i.imgur.com/gXqvZDe.png", + "images": [ + "https://arctype.com/home/images/overview.svg" + ] + }, + "arcwelder": { + "icon": "", + "images": [] + }, + "ardev": { + "icon": "", + "images": [] + }, + "arduino": { + "icon": "https://community.chocolatey.org/content/packageimages/arduino.2.0.4.png", + "images": [] + }, + "arduino-cli": { + "icon": "https://community.chocolatey.org/content/packageimages/arduino-cli.0.31.0.png", + "images": [] + }, + "arduinoide": { + "icon": "", + "images": [] + }, + "arduinoidegalileo": { + "icon": "", + "images": [] + }, + "arecabackup": { + "icon": "https://community.chocolatey.org/content/packageimages/ArecaBackup.7.5.png", + "images": [] + }, + "ares": { + "icon": "https://images.sftcdn.net/images/t_app-icon-m/p/b618c802-96bf-11e6-a849-00163ec9f5fa/2084765831/ares-download.png", + "images": [] + }, + "arescommander-2022": { + "icon": "https://cad.com.au/wp-content/uploads/2020/11/ares-logo-red.png", + "images": [ + "https://www.graebert.com/wp-content/uploads/2021/02/ARES-Commander-2020-tower-transparent-with-logo-1.jpg", + "https://www.graebert.com/wp-content/uploads/2021/08/ARES_Kudo2.jpg", + "https://windows-cdn.softpedia.com/screenshots/ARES-Commander-Edition_3.png", + "https://www.graebert.com/wp-content/uploads/2022/03/sheet_list_2023_2.jpg" + ] + }, + "arescommander-2023": { + "icon": "https://cad.com.au/wp-content/uploads/2020/11/ares-logo-red.png", + "images": [ + "https://www.graebert.com/wp-content/uploads/2021/02/ARES-Commander-2020-tower-transparent-with-logo-1.jpg", + "https://www.graebert.com/wp-content/uploads/2021/08/ARES_Kudo2.jpg", + "https://windows-cdn.softpedia.com/screenshots/ARES-Commander-Edition_3.png", + "https://www.graebert.com/wp-content/uploads/2022/03/sheet_list_2023_2.jpg" + ] + }, + "arescommander-2024": { + "icon": "https://cad.com.au/wp-content/uploads/2020/11/ares-logo-red.png", + "images": [ + "https://www.graebert.com/wp-content/uploads/2021/02/ARES-Commander-2020-tower-transparent-with-logo-1.jpg", + "https://www.graebert.com/wp-content/uploads/2021/08/ARES_Kudo2.jpg", + "https://windows-cdn.softpedia.com/screenshots/ARES-Commander-Edition_3.png", + "https://www.graebert.com/wp-content/uploads/2022/03/sheet_list_2023_2.jpg" + ] + }, + "arescommander-2025": { + "icon": "https://cad.com.au/wp-content/uploads/2020/11/ares-logo-red.png", + "images": [ + "https://www.graebert.com/wp-content/uploads/2021/02/ARES-Commander-2020-tower-transparent-with-logo-1.jpg", + "https://www.graebert.com/wp-content/uploads/2021/08/ARES_Kudo2.jpg", + "https://windows-cdn.softpedia.com/screenshots/ARES-Commander-Edition_3.png", + "https://www.graebert.com/wp-content/uploads/2022/03/sheet_list_2023_2.jpg" + ] + }, + "arescommander-2026": { + "icon": "https://cad.com.au/wp-content/uploads/2020/11/ares-logo-red.png", + "images": [ + "https://www.graebert.com/wp-content/uploads/2021/02/ARES-Commander-2020-tower-transparent-with-logo-1.jpg", + "https://www.graebert.com/wp-content/uploads/2021/08/ARES_Kudo2.jpg", + "https://windows-cdn.softpedia.com/screenshots/ARES-Commander-Edition_3.png", + "https://www.graebert.com/wp-content/uploads/2022/03/sheet_list_2023_2.jpg" + ] + }, + "aresmap-2022": { + "icon": "https://www.graebert.com/wp-content/uploads/2022/03/New_Prod_ARES_Map_256x256_183w_2x.png", + "images": [ + "https://www.graebert.com/wp-content/uploads/2018/04/01_map.jpg", + "https://www.graebert.com/wp-content/uploads/2018/04/02_map.jpg", + "https://www.graebert.com/wp-content/uploads/2017/11/aresmap_screen-1_2017.png" + ] + }, + "aresmap-2023": { + "icon": "https://www.graebert.com/wp-content/uploads/2022/03/New_Prod_ARES_Map_256x256_183w_2x.png", + "images": [ + "https://www.graebert.com/wp-content/uploads/2018/04/01_map.jpg", + "https://www.graebert.com/wp-content/uploads/2018/04/02_map.jpg", + "https://www.graebert.com/wp-content/uploads/2017/11/aresmap_screen-1_2017.png" + ] + }, + "aresmechanical-2022": { + "icon": "https://www.graebert.com/wp-content/uploads/2022/03/New_Prod_ARES_Mechanical_256x256_183w_2x.png", + "images": [ + "https://img.youtube.com/vi/yk15tlH2YoQ/0.jpg", + "https://www.graebert.com/wp-content/uploads/2022/02/ARES-Mechanical-woman-work-on-mechanical-piece_cut_kl.jpg", + "https://www.graebert.com/wp-content/uploads/2018/06/02_ares_mech_n.jpg", + "https://www.graebert.com/wp-content/uploads/2017/11/aresmech_screen-1_2017.png" + ] + }, + "aresmechanical-2023": { + "icon": "https://www.graebert.com/wp-content/uploads/2022/03/New_Prod_ARES_Mechanical_256x256_183w_2x.png", + "images": [ + "https://img.youtube.com/vi/yk15tlH2YoQ/0.jpg", + "https://www.graebert.com/wp-content/uploads/2022/02/ARES-Mechanical-woman-work-on-mechanical-piece_cut_kl.jpg", + "https://www.graebert.com/wp-content/uploads/2018/06/02_ares_mech_n.jpg", + "https://www.graebert.com/wp-content/uploads/2017/11/aresmech_screen-1_2017.png" + ] + }, + "aresmechanical-2024": { + "icon": "", + "images": [] + }, + "aresmechanical-2025": { + "icon": "", + "images": [] + }, + "aresmechanical-2026": { + "icon": "https://i.postimg.cc/xdj0j7hc/aresm2026.png", + "images": [] + }, + "areselectrical-2026": { + "icon": "", + "images": [] + }, + "argo": { + "icon": "", + "images": [] + }, + "argo-workflows": { + "icon": "https://community.chocolatey.org/content/packageimages/argo-workflows.3.4.2.png", + "images": [] + }, + "argocd": { + "icon": "", + "images": [] + }, + "argocd-autopilot": { + "icon": "https://community.chocolatey.org/content/packageimages/argocd-autopilot.0.2.28.png", + "images": [] + }, + "argocd-cli": { + "icon": "https://community.chocolatey.org/content/packageimages/argocd-cli.2.6.3.png", + "images": [] + }, + "argouml": { + "icon": "https://community.chocolatey.org/content/packageimages/argouml.0.34.1.png", + "images": [] + }, + "argusmonitor": { + "icon": "", + "images": [ + "https://cdn.argusmonitor.com/assets/en/fan_control_with_argus_monitor.png", + "https://cdn.argusmonitor.com/assets/en/screen01.png", + "https://cdn.argusmonitor.com/assets/en/screen02.png", + "https://cdn.argusmonitor.com/assets/en/screen03.png", + "https://cdn.argusmonitor.com/assets/en/screen04.png", + "https://cdn.argusmonitor.com/assets/en/screen05.png" + ] + }, + "argyllcms": { + "icon": "", + "images": [] + }, + "aria-ng-gui": { + "icon": "", + "images": [] + }, + "aria2": { + "icon": "https://community.chocolatey.org/content/packageimages/aria2.1.36.0.png", + "images": [] + }, + "ariang-native": { + "icon": "", + "images": [] + }, + "arkade": { + "icon": "https://community.chocolatey.org/content/packageimages/arkade.0.8.44.png", + "images": [] + }, + "arkana": { + "icon": "", + "images": [] + }, + "arliveforacfunlive": { + "icon": "", + "images": [ + "https://img.81857.net/2020/0817/20200817013305783.jpg" + ] + }, + "arma3sync": { + "icon": "https://i.imgur.com/WxxNlan.png", + "images": [ + "https://i.imgur.com/Pq8nK5T.png" + ] + }, + "armagetronad": { + "icon": "https://community.chocolatey.org/content/packageimages/armagetronad.0.2.9.01.png", + "images": [] + }, + "armclient": { + "icon": "", + "images": [] + }, + "armcord": { + "icon": "https://i.imgur.com/YWEmrzv.png", + "images": [ + "https://i.imgur.com/oIWacW1.jpg", + "https://windows-cdn.softpedia.com/screenshots/ArmCord_1.png", + "https://windows-cdn.softpedia.com/screenshots/ArmCord_2.png", + "https://windows-cdn.softpedia.com/screenshots/ArmCord_3.png", + "https://windows-cdn.softpedia.com/screenshots/ArmCord_4.png", + "https://res.cloudinary.com/canonical/image/fetch/f_auto,q_auto,fl_sanitize,w_819,h_623/https://dashboard.snapcraft.io/site_media/appmedia/2022/05/1_1.png" + ] + }, + "armips": { + "icon": "", + "images": [] + }, + "armor": { + "icon": "", + "images": [] + }, + "armory": { + "icon": "https://community.chocolatey.org/content/packageimages/armory.0.96.png", + "images": [] + }, + "armps": { + "icon": "", + "images": [] + }, + "arq": { + "icon": "https://i.postimg.cc/fTvDvfwm/arq.png", + "images": [ + "https://i.postimg.cc/xdXQnrL3/image.png", + "https://i.postimg.cc/pT8t5DG9/image.png" + ] + }, + "artha": { + "icon": "", + "images": [ + "https://artha.sourceforge.net/wiki/images/thumb/7/75/Mode_detailed.png/180px-Mode_detailed.png", + "https://artha.sourceforge.net/wiki/images/thumb/7/76/Regex_wildcard.png/180px-Regex_wildcard.png", + "https://artha.sourceforge.net/wiki/images/thumb/c/cf/Screen_antonyms.png/180px-Screen_antonyms.png", + "https://artha.sourceforge.net/wiki/images/thumb/a/ab/Screen_attribute.png/180px-Screen_attribute.png" + ] + }, + "arthas": { + "icon": "", + "images": [] + }, + "arthub": { + "icon": "", + "images": [] + }, + "artifactory-pro": { + "icon": "", + "images": [] + }, + "artmoney": { + "icon": "", + "images": [] + }, + "artools": { + "icon": "", + "images": [] + }, + "aruba-networks-virtual-intranet-access-client": { + "icon": "https://community.chocolatey.org/content/packageimages/aruba-networks-virtual-intranet-access-client.4.0.2004212.png", + "images": [] + }, + "arvis": { + "icon": "", + "images": [ + "https://user-images.githubusercontent.com/18283033/131144965-97a5b380-afcd-46c4-8298-55ac6b75bcce.gif" + ] + }, + "arxiv-collector": { + "icon": "", + "images": [] + }, + "as-ssd": { + "icon": "https://community.chocolatey.org/content/packageimages/as-ssd.2.0.7316.34247.png", + "images": [] + }, + "asana": { + "icon": "https://seeklogo.com/images/A/asana-logo-7F172ED8E6-seeklogo.com.png", + "images": [ + "https://luna1.co/179c58.png", + "https://blog.asana.com/wp-content/post-images/11_04_boards_hero.png", + "https://luna1.co/7c29c0.png", + "https://luna1.co/5eafef.png", + "https://luna1.co/9b651d.png", + "https://luna1.co/3e4fc7.png", + "https://luna1.co/5fae66.png" + ] + }, + "asar7z": { + "icon": "", + "images": [] + }, + "ascensionlauncher": { + "icon": "", + "images": [ + "https://i.imgur.com/120dtq9.jpg", + "https://i.imgur.com/4uec4Ve.jpg" + ] + }, + "ascii-image-converter": { + "icon": "", + "images": [] + }, + "asciidocfx": { + "icon": "https://community.chocolatey.org/content/packageimages/asciidocfx.portable.1.8.4.png", + "images": [] + }, + "asciidoctorj": { + "icon": "", + "images": [] + }, + "asciiengine": { + "icon": "", + "images": [] + }, + "asgardex": { + "icon": "", + "images": [ + "https://www.cryptoninjas.net/wp-content/uploads/asgardex-thorchain-cryptoninjas.jpg", + "https://i.imgur.com/dEQBzCj.png", + "https://user-images.githubusercontent.com/61792675/175036489-f9bac515-b74a-44bf-b294-b65489c17bd8.png", + "https://user-images.githubusercontent.com/61792675/170678309-d6046218-8490-4efc-9274-14cdbcc57d9f.png", + "https://raw.githubusercontent.com/thorchain/asgardex-electron/develop/internals/img/asgardex-splash.png" + ] + }, + "asio4all": { + "icon": "https://cybersoft.ru/uploads/posts/2021-03/1614682798_asio4all.png", + "images": [ + "https://www.asio4all.org/wp-content/uploads/2021/04/PanelSimple.jpg", + "https://www.asio4all.org/wp-content/uploads/2021/04/PanelAdvanced.jpg", + "https://www.asio4all.org/wp-content/uploads/2021/03/USBTreeview.jpg" + ] + }, + "asn1editor": { + "icon": "https://community.chocolatey.org/content/packageimages/asn1editor.1.4.1.png", + "images": [] + }, + "asp-net-mvc-boilerplate": { + "icon": "https://community.chocolatey.org/content/packageimages/asp-net-mvc-boilerplate.6.2.0.28901.png", + "images": [] + }, + "aspeed-graphics-driver": { + "icon": "", + "images": [] + }, + "aspell": { + "icon": "", + "images": [] + }, + "aspnetcore-runtimepackagestore": { + "icon": "https://community.chocolatey.org/content/packageimages/aspnetcore-runtimepackagestore.3.1.32.png", + "images": [] + }, + "aspnetmvc": { + "icon": "", + "images": [] + }, + "aspnetmvc2": { + "icon": "", + "images": [] + }, + "aspnetmvc4": { + "icon": "", + "images": [] + }, + "asrock-3tb-plus-unlocker": { + "icon": "https://community.chocolatey.org/content/packageimages/asrock-3tb-plus-unlocker.1.1.1.png", + "images": [] + }, + "assaultcube": { + "icon": "https://www.fileeagle.com/data/2016/02/AssaultCube.jpg", + "images": [ + "https://assault.cubers.net/screenshots/screenshots-large/ac_complex_DM_gren_large00.jpg", + "https://assault.cubers.net/screenshots/screenshots-large/ac_complex_DM_pist_large00.jpg", + "https://assault.cubers.net/screenshots/screenshots-large/ac_complex_DM_SG_large00.jpg", + "https://assault.cubers.net/screenshots/screenshots-large/ac_complex_DM_SR_large00.jpg", + "https://assault.cubers.net/screenshots/screenshots-large/ac_mines_CTF_SMG_large00.jpg", + "https://assault.cubers.net/screenshots/screenshots-large/ac_mines_CTF_SMG_large01.jpg", + "https://assault.cubers.net/screenshots/screenshots-large/ac_shine_CTF_unknown_large00.jpg", + "https://assault.cubers.net/screenshots/screenshot-table.jpg" + ] + }, + "assessment-disaggregation": { + "icon": "", + "images": [ + "https://windows-cdn.softpedia.com/screenshots/Assessment-Disaggregation_1.jpg" + ] + }, + "assetizr": { + "icon": "https://dist.assetizr.com/logo_written_200.png", + "images": [ + "https://i.gzn.jp/img/2019/01/22/assetizr/00.png", + "https://ph-files.imgix.net/793bbc97-8ae2-4a3a-8f12-a09afa6f71c7.png", + "https://i.imgur.com/tWMcwuk.jpg", + "https://d4.alternativeto.net/8i_Ph_1eCCOKNXd9uHsEpExDSXwcB1zKOoW0ynrInGM/rs:fit:1200:1200:0/g:ce:0:0/YWJzOi8vZGlzdC9zL2Fzc2V0aXpyXzI0OTk4NF9mdWxsLmpwZw.jpg" + ] + }, + "assfiltermod": { + "icon": "", + "images": [] + }, + "assistant-computer-control": { + "icon": "https://community.chocolatey.org/content/packageimages/assistant-computer-control.1.4.4.png", + "images": [] + }, + "Winget.ares-emulator.ares": { + "icon": "https://raw.githubusercontent.com/ares-emulator/ares/master/desktop-ui/resource/ares.png", + "images": [] + }, + "astah": { + "icon": "https://community.chocolatey.org/content/packageimages/astah.6.6.4.png", + "images": [] + }, + "astral-sh.ruff": { + "icon": "https://i.postimg.cc/NfT3zPTq/astral-sh-ruff.png", + "images": [] + }, + "astral-sh.ty": { + "icon": "https://i.postimg.cc/7PpvXyCY/astral-sh-ty.png", + "images": [] + }, + "astral-sh.uv": { + "icon": "https://i.postimg.cc/PrZgRFZG/astral-sh-uv.png", + "images": [] + }, + "asterie": { + "icon": "https://community.chocolatey.org/content/packageimages/asterie.1.03.png", + "images": [] + }, + "asteroids": { + "icon": "", + "images": [] + }, + "astiga": { + "icon": "https://dashboard.snapcraft.io/site_media/appmedia/2020/01/Logo_Dropbox.png", + "images": [ + "https://res.cloudinary.com/canonical/image/fetch/f_auto,q_auto,fl_sanitize,w_819,h_436/https://dashboard.snapcraft.io/site_media/appmedia/2020/01/Screenshot_from_2020-01-10_01-16-33.png", + "https://preview.redd.it/3ouoq4atpdq91.png?auto=webp&s=b1c7e76401629916ac71743e6cb7e8b7420b0628" + ] + }, + "astro": { + "icon": "", + "images": [] + }, + "astrogrep": { + "icon": "https://astrogrep.sourceforge.net/pics/AstroGrep_256x256.png", + "images": [ + "https://a.fsdn.com/con/app/proj/astrogrep/screenshots/ss_main_new.png", + "https://www.portablefreeware.com/screenshots/scrLEgvyw.png", + "https://windows-cdn.softpedia.com/screenshots/X-AstroGrep_1.png" + ] + }, + "astromenace": { + "icon": "https://community.chocolatey.org/content/packageimages/astromenace.1.3.2.png", + "images": [] + }, + "astyle": { + "icon": "", + "images": [] + }, + "asuite": { + "icon": "", + "images": [] + }, + "asymptote": { + "icon": "https://community.chocolatey.org/content/packageimages/asymptote.2.85.png", + "images": [] + }, + "at-term": { + "icon": "", + "images": [] + }, + "athens": { + "icon": "https://community.chocolatey.org/content/packageimages/athens.2.1.0.png", + "images": [] + }, + "atkinson-hyperlegible": { + "icon": "", + "images": [] + }, + "atlassian-companion": { + "icon": "https://community.chocolatey.org/content/packageimages/atlassian-companion.1.4.4.png", + "images": [] + }, + "atlassian-plugin-sdk": { + "icon": "https://community.chocolatey.org/content/packageimages/atlassian-plugin-sdk.5.0.13.png", + "images": [] + }, + "atlassianconnector-for-visualstudio": { + "icon": "", + "images": [] + }, + "atlauncher": { + "icon": "https://atlauncher.com/assets/images/logo-named.png", + "images": [ + "https://i.imgur.com/W06uViG.png", + "https://i.imgur.com/fTnYjus.png" + ] + }, + "atnow": { + "icon": "https://community.chocolatey.org/content/packageimages/atnow.1.1.png", + "images": [] + }, + "atol-dto": { + "icon": "", + "images": [] + }, + "atom": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/e/e2/Atom_1.0_icon.png", + "images": [ + "https://i.imgur.com/MK7Ww1T.png", + "https://i.ytimg.com/vi/hPC6keUUiTA/maxresdefault.jpg", + "https://upload.wikimedia.org/wikipedia/commons/5/5f/Atom_screenshot_v1.41.0.png", + "https://media.wired.com/photos/590951b376f462691f0126fc/master/w_1600%2Cc_limit/screenshot-dark.png", + "https://upload.wikimedia.org/wikipedia/commons/7/7c/Screenshot_of_Atom_editor.png" + ] + }, + "atom-beta": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/e/e2/Atom_1.0_icon.png", + "images": [ + "https://i.imgur.com/MK7Ww1T.png", + "https://i.ytimg.com/vi/hPC6keUUiTA/maxresdefault.jpg", + "https://upload.wikimedia.org/wikipedia/commons/5/5f/Atom_screenshot_v1.41.0.png", + "https://media.wired.com/photos/590951b376f462691f0126fc/master/w_1600%2Cc_limit/screenshot-dark.png", + "https://upload.wikimedia.org/wikipedia/commons/7/7c/Screenshot_of_Atom_editor.png" + ] + }, + "atomicparsley": { + "icon": "", + "images": [] + }, + "atraci": { + "icon": "", + "images": [] + }, + "atrixlauncher": { + "icon": "", + "images": [] + }, + "attractmode": { + "icon": "https://community.chocolatey.org/content/packageimages/attractmode.portable.2.3.0.png", + "images": [] + }, + "attributechanger": { + "icon": "https://community.chocolatey.org/content/packageimages/attributechanger.11.10.png", + "images": [] + }, + "atubecatcher": { + "icon": "https://community.chocolatey.org/content/packageimages/atubecatcher.3.8.9622.png", + "images": [] + }, + "auburn": { + "icon": "https://the-sz.com/products/auburn/auburn_icon.png", + "images": [ + "https://the-sz.com/products/auburn/auburn.png", + "https://i.imgur.com/NomYphG.jpg" + ] + }, + "audacious": { + "icon": "https://community.chocolatey.org/content/packageimages/audacious.4.2.png", + "images": [] + }, + "audacity": { + "icon": "https://forum.audacityteam.org/uploads/default/original/1X/81a69b20bcd548215067cfaceccc8a10bfa2d176.png", + "images": [ + "https://i.postimg.cc/h4rWHTWb/image.png", + "https://i.postimg.cc/zf3bxXFw/audacity-1.png", + "https://i.postimg.cc/63v7NjSy/audacity-2.png", + "https://i.postimg.cc/28w1mBHF/audacity-3.png" + ] + }, + "audacium": { + "icon": "https://user-images.githubusercontent.com/34075088/128607939-19908854-923a-4447-b134-40632d233510.png", + "images": [ + "https://user-images.githubusercontent.com/34075088/128556907-8cb6a1a8-d4e9-461a-9f84-3759085583dd.png", + "https://i.imgur.com/YGdq58x.png" + ] + }, + "audioanalyser": { + "icon": "", + "images": [ + "https://sedutec.de/images/audioanalyser201012_1.jpg" + ] + }, + "audiobookconverter": { + "icon": "https://community.chocolatey.org/content/packageimages/audiobookconverter.6.1.2.png", + "images": [ + "https://lh5.googleusercontent.com/fi8XFyiFP6malV-MGC5Sv49KNqOYuwSxoP3YL6VzBxVmKuvGbOERT0SXRuVJyO2BswbZRnwAPVJq7R0zojT8_IyzIzfSmcRnlytR6Vhz0r7VNVf7=w1280", + "https://cdn.cloudflare.steamstatic.com/steam/apps/1529240/ss_6baa06b1609afe4ef2e82d265bc8c25a0b69dda5.1920x1080.jpg?t=1640257305" + ] + }, + "audioconverter": { + "icon": "https://community.chocolatey.org/content/packageimages/AudioConverter.3.1.png", + "images": [] + }, + "audiojam": { + "icon": "https://i.imgur.com/twEVCV0.png", + "images": [ + "https://audiojam.cn/assets/audioJam1_en.b03649e6.png" + ] + }, + "audiomoth-config": { + "icon": "https://community.chocolatey.org/content/packageimages/audiomoth-config.1.9.0.png", + "images": [] + }, + "audioranger": { + "icon": "https://www.audioranger.com/images/logo_20221013.png", + "images": [] + }, + "audiorelay": { + "icon": "", + "images": [ + "https://2594558889-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MEh8vFAB2fHUbGzyi0U%2Fuploads%2FHrduy2Wx5s0ZSnvdIlyW%2FCleanShot%202022-02-20%20at%2014.04.27.png?alt=media&token=d7622501-22e4-4b42-87d3-cdafa06cc644", + "https://geekflare.com/wp-content/uploads/2021/08/audiorelay-pc-client.jpg" + ] + }, + "audioshell": { + "icon": "https://community.chocolatey.org/content/packageimages/audioshell.2.3.6.png", + "images": [] + }, + "audioswitch": { + "icon": "https://raw.githubusercontent.com/sirWest/AudioSwitch/master/gh-pages/AudioSwitchLogoSmall.png", + "images": [ + "https://raw.githubusercontent.com/sirWest/AudioSwitch/master/gh-pages/output.png", + "https://raw.githubusercontent.com/sirWest/AudioSwitch/master/gh-pages/input.png" + ] + }, + "audioswitcher": { + "icon": "https://community.chocolatey.org/content/packageimages/audioswitcher.1.8.0.142.png", + "images": [] + }, + "audius": { + "icon": "", + "images": [] + }, + "audmes": { + "icon": "", + "images": [] + }, + "aurora": { + "icon": "", + "images": [] + }, + "austin": { + "icon": "", + "images": [] + }, + "ausweisapp": { + "icon": "https://i.imgur.com/nPb3wTl.png", + "images": [ + "https://res.cloudinary.com/canonical/image/fetch/f_auto,q_auto,fl_sanitize,w_819,h_549/https://dashboard.snapcraft.io/site_media/appmedia/2019/01/ausweisapp2.png", + "https://www.ausweisapp.bund.de/fileadmin/user_upload/Bilder/Mock-ups/startseite-smartphone-und-desktop-englisch.jpg" + ] + }, + "authenticator": { + "icon": "https://i.postimg.cc/DyndH0xK/image.png", + "images": [ + "https://i.postimg.cc/mZQymCNw/image.png", + "https://i.postimg.cc/X7LcbWPB/image.png", + "https://i.postimg.cc/fRb7WF42/image.png", + "https://i.postimg.cc/L80tJT2H/image.png" + ] + }, + "authenticator-beta": { + "icon": "", + "images": [] + }, + "authme": { + "icon": "https://dashboard.snapcraft.io/site_media/appmedia/2022/06/icon_QqnPS4R.png", + "images": [ + "https://raw.githubusercontent.com/Levminer/authme/dev/screenshots/edit.png", + "https://raw.githubusercontent.com/Levminer/authme/dev/screenshots/export.png", + "https://raw.githubusercontent.com/Levminer/authme/dev/screenshots/import.png", + "https://raw.githubusercontent.com/Levminer/authme/dev/screenshots/settings.png" + ] + }, + "authpass": { + "icon": "https://i.imgur.com/d1BGeGd.png", + "images": [ + "https://raw.githubusercontent.com/authpass/authpass/main/_docs/authpass-platform-composition.png", + "https://store-images.s-microsoft.com/image/apps.61539.14570429597835811.0743ca73-dd36-4d11-a26c-40a9785f67ba.a57b906c-47b5-4ee0-9308-6aba5c8d668b", + "https://store-images.s-microsoft.com/image/apps.30753.14570429597835811.0743ca73-dd36-4d11-a26c-40a9785f67ba.402e49a6-2437-4016-b398-edd7124e493e" + ] + }, + "authy": { + "icon": "https://i.imgur.com/MoOmCvE.png", + "images": [ + "https://i.postimg.cc/MTpwRF4x/1.png", + "https://i.postimg.cc/R0R9WBgX/2.png", + "https://i.postimg.cc/50KVmmdz/3.png" + ] + }, + "authy-desktop": { + "icon": "https://community.chocolatey.org/content/packageimages/authy-desktop.2.2.3.png", + "images": [] + }, + "auth-desktop": { + "icon": "https://raw.githubusercontent.com/ente-io/ente/main/mobile/apps/auth/assets/icons/auth-icon.png", + "images": [] + }, + "autoactions": { + "icon": "", + "images": [] + }, + "autobootdisk": { + "icon": "https://community.chocolatey.org/content/packageimages/autobootdisk.5.7.png", + "images": [] + }, + "autocad": { + "icon": "https://community.chocolatey.org/content/packageimages/autocad.2023.242530.png", + "images": [] + }, + "autocadlt": { + "icon": "https://community.chocolatey.org/content/packageimages/autocadlt.2023.242530.png", + "images": [] + }, + "autoclicker": { + "icon": "https://community.chocolatey.org/content/packageimages/autoclicker.3.0.png", + "images": [] + }, + "autocomplete": { + "icon": "https://community.chocolatey.org/content/packageimages/autocomplete.1.3.png", + "images": [] + }, + "autodesk-fusion360": { + "icon": "https://community.chocolatey.org/content/packageimages/autodesk-fusion360.2.0.15509.png", + "images": [] + }, + "autofirma": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/b/b2/Icono_AutoFirma.png", + "images": [] + }, + "autofixture-automoqprig": { + "icon": "", + "images": [] + }, + "autoflac": { + "icon": "", + "images": [ + "https://www.legroom.net/files/software/autoflac_gui_thumb.png", + "https://www.legroom.net/files/software/autoflac_convert.png" + ] + }, + "autohotkey": { + "icon": "https://raw.githubusercontent.com/Ixiko/AHK-Forum/master/images/AHK%20main%20icon.png", + "images": [ + "https://i.ytimg.com/vi/n_9-QkD-zJ4/maxresdefault.jpg", + "https://s8.postimg.cc/je3mkkwzp/Auto_GUI_v2.0.1.png", + "https://images.sftcdn.net/images/t_app-cover-l,f_auto/p/a5edca32-96d7-11e6-98e0-00163ec9f5fa/4013272943/autohotkey-Untitled.png" + ] + }, + "autohotkey-compiler": { + "icon": "", + "images": [] + }, + "autohotkey-l": { + "icon": "", + "images": [] + }, + "autoit": { + "icon": "https://i.imgur.com/lETjQsY.png", + "images": [] + }, + "autoit-commandline": { + "icon": "https://community.chocolatey.org/content/packageimages/autoit.commandline.3.3.14.2.png", + "images": [] + }, + "autoit-script-editor": { + "icon": "", + "images": [] + }, + "autojump": { + "icon": "", + "images": [] + }, + "autokeyboard": { + "icon": "", + "images": [ + "https://www.murgee.com/auto-keyboard/images/auto-keyboard.png" + ] + }, + "autologon": { + "icon": "", + "images": [] + }, + "automatedlab": { + "icon": "https://imgur.com/a/0P9TpTo.png", + "images": [ + "https://i.ytimg.com/vi/lrPlRvFR5fA/sddefault.jpg" + ] + }, + "automation-spy": { + "icon": "", + "images": [] + }, + "automise": { + "icon": "https://community.chocolatey.org/content/packageimages/automise.5.0.0.1475.png", + "images": [] + }, + "automiserunner": { + "icon": "https://community.chocolatey.org/content/packageimages/automiserunner.5.0.0.1475.png", + "images": [] + }, + "automiseruntime": { + "icon": "https://community.chocolatey.org/content/packageimages/automiseruntime.5.0.0.1475.png", + "images": [] + }, + "automouseclick": { + "icon": "https://community.chocolatey.org/content/packageimages/automouseclick.99.1.4.20230228.png", + "images": [] + }, + "autopsy": { + "icon": "https://i.imgur.com/MNqvAXk.png", + "images": [ + "https://sleuthkit.org/autopsy/docs/user-docs/4.15.0/portable_case_original_version.png", + "https://media.geeksforgeeks.org/wp-content/uploads/20200830111540/Screenshot8.png" + ] + }, + "autorunner": { + "icon": "", + "images": [] + }, + "autoruns": { + "icon": "https://i.ibb.co/hF170wpM/2021-12-16-ts3-thumbs-dfe-p-256.png", + "images": [ + "https://i.ibb.co/x9YyC59/image.png", + "https://i.ibb.co/KptqgZ3r/image.png" + ] + }, + "autoscreenrecorder": { + "icon": "", + "images": [ + "https://windows-cdn.softpedia.com/screenshots/AutoScreenRecorder-Pro_10.png", + "https://windows-cdn.softpedia.com/screenshots/AutoScreenRecorder-Pro_11.png", + "https://windows-cdn.softpedia.com/screenshots/AutoScreenRecorder-Pro_12.png", + "https://windows-cdn.softpedia.com/screenshots/AutoScreenRecorder-Pro_13.png" + ] + }, + "autossh": { + "icon": "", + "images": [] + }, + "autostartconfirm": { + "icon": "", + "images": [] + }, + "avantisdirector": { + "icon": "", + "images": [ + "https://www.prosoundweb.com/wp-content/uploads/2021/03/AH-Avantis-v11.jpg", + "https://www.allen-heath.com/media/AV-Touch768.jpg" + ] + }, + "avast-is-trial": { + "icon": "https://community.chocolatey.org/content/packageimages/avast-is-trial.12.3.2279.png", + "images": [] + }, + "avast-premier-trial": { + "icon": "https://community.chocolatey.org/content/packageimages/avast-premier-trial.12.3.2279.png", + "images": [] + }, + "avast-pro-trial": { + "icon": "https://community.chocolatey.org/content/packageimages/avast-pro-trial.12.3.2279.png", + "images": [] + }, + "avastbrowsercleanup": { + "icon": "", + "images": [] + }, + "avastfreeantivirus": { + "icon": "https://community.chocolatey.org/content/packageimages/avastfreeantivirus.23.1.7883.0.png", + "images": [] + }, + "avd-nativeapp": { + "icon": "", + "images": [] + }, + "aventurasdequintal": { + "icon": "", + "images": [] + }, + "avgantivirusbusiness": { + "icon": "", + "images": [] + }, + "avgantivirusfree": { + "icon": "https://community.chocolatey.org/content/packageimages/avgantivirusfree.18.1817.103.png", + "images": [] + }, + "avginternetsecurity": { + "icon": "https://community.chocolatey.org/content/packageimages/avginternetsecurity.15.0.6125.png", + "images": [] + }, + "avgpctuneup": { + "icon": "", + "images": [] + }, + "avidemux": { + "icon": "", + "images": [] + }, + "avinaptic": { + "icon": "https://community.chocolatey.org/content/packageimages/avinaptic.2011.12.18.png", + "images": [] + }, + "avirafreeantivirus": { + "icon": "", + "images": [] + }, + "avisynth": { + "icon": "https://www.avisynth.org/images/avisynth-logo-gears-mod.png", + "images": [ + "https://www.svp-team.com/w/images/3/3c/Mpchc-avsf.png", + "https://imag.malavida.com/mvimgbig/download-fs/avisynth-11914-1.jpg" + ] + }, + "avisynthplus": { + "icon": "https://www.avisynth.org/images/avisynth-logo-gears-mod.png", + "images": [ + "https://www.svp-team.com/w/images/3/3c/Mpchc-avsf.png", + "https://imag.malavida.com/mvimgbig/download-fs/avisynth-11914-1.jpg" + ] + }, + "avocode": { + "icon": "", + "images": [ + "https://avocode.com/static/og/facebook/avocode-og-download.png", + "https://miro.medium.com/max/1400/0*wKuC9gfMG2BG_KCL.png", + "https://miro.medium.com/max/1400/1*PGcWow7rw0fppvtOsZGoLg.png" + ] + }, + "avogadro": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/c/c1/Avogadro.png", + "images": [ + "https://a.fsdn.com/con/app/proj/avogadro/screenshots/205209.jpg", + "https://a.fsdn.com/con/app/proj/avogadro/screenshots/205205.jpg", + "https://a.fsdn.com/con/app/proj/avogadro/screenshots/205207.jpg" + ] + }, + "avr-gcc": { + "icon": "", + "images": [] + }, + "avrdude": { + "icon": "", + "images": [] + }, + "avrdudess": { + "icon": "", + "images": [] + }, + "avro": { + "icon": "https://okkhor52.com/img/designer/001.png", + "images": [ + "https://www.omicronlab.com/assets/images/landing/avro_600x337.jpg", + "https://linux.omicronlab.com/images/screenshot.png", + "https://imag.malavida.com/mvimgbig/download-fs/avro-keyboard-22346-1.jpg" + ] + }, + "avro-keyboard": { + "icon": "https://community.chocolatey.org/content/packageimages/avro-keyboard.5.6.0.png", + "images": [] + }, + "avro-tools": { + "icon": "", + "images": [] + }, + "avspmod": { + "icon": "", + "images": [] + }, + "awake": { + "icon": "", + "images": [] + }, + "awareness": { + "icon": "", + "images": [] + }, + "awboxcontroller": { + "icon": "", + "images": [] + }, + "awesomealexdev": { + "icon": "", + "images": [] + }, + "awesomebump": { + "icon": "https://community.chocolatey.org/content/packageimages/awesomebump.5.1.png", + "images": [] + }, + "awk": { + "icon": "", + "images": [] + }, + "aws": { + "icon": "", + "images": [] + }, + "aws-amplify": { + "icon": "", + "images": [] + }, + "aws-copilot": { + "icon": "", + "images": [] + }, + "aws-ecs": { + "icon": "", + "images": [] + }, + "aws-iam-authenticator": { + "icon": "https://community.chocolatey.org/content/packageimages/aws-iam-authenticator.0.5.9.png", + "images": [] + }, + "aws-monitor-diskusage": { + "icon": "", + "images": [] + }, + "aws-nosql-workbench": { + "icon": "", + "images": [] + }, + "aws-nuke": { + "icon": "", + "images": [] + }, + "aws-sam-cli": { + "icon": "", + "images": [] + }, + "aws-sdk-net": { + "icon": "", + "images": [] + }, + "aws-session-manager-plugin": { + "icon": "", + "images": [] + }, + "aws-vault": { + "icon": "https://community.chocolatey.org/content/packageimages/aws-vault.6.6.0.png", + "images": [] + }, + "awscli": { + "icon": "https://discover.strongdm.com/hs-fs/hubfs/Technology%20Images/603c5ee70b9e8acb4229b654_603c218977575b8d6b27fabe_AWS_CLI.png?width=300&height=300&name=603c5ee70b9e8acb4229b654_603c218977575b8d6b27fabe_AWS_CLI.png", + "images": [ + "https://i.imgur.com/WhbXwYQ.png" + ] + }, + "awscli-session-manager": { + "icon": "", + "images": [] + }, + "awsqueue": { + "icon": "", + "images": [] + }, + "awssamcli": { + "icon": "", + "images": [] + }, + "awssts": { + "icon": "", + "images": [] + }, + "awstools-powershell": { + "icon": "https://community.chocolatey.org/content/packageimages/AWSTools.Powershell.1.1.1120.20130916.png", + "images": [] + }, + "awsvpnclient": { + "icon": "https://img.informer.com/icons_mac/png/128/577/577519.png", + "images": [ + "https://d2908q01vomqb2.cloudfront.net/5b384ce32d8cdef02bc3a139d4cac0a22bb029e8/2020/05/12/Slide2.png", + "https://docs.aws.amazon.com/vpn/latest/clientvpn-admin/images/architecture.png", + "https://docs.aws.amazon.com/whitepapers/latest/aws-vpc-connectivity-options/images/image21.png", + "https://docs.aws.amazon.com/vpn/latest/clientvpn-admin/images/client-vpn-scenario-igw.png" + ] + }, + "axcrypt": { + "icon": "https://axcrypt.net/img/axcrypt_white.05643fb0.png", + "images": [ + "https://i.ytimg.com/vi/jyixJ03qmkg/maxresdefault.jpg", + "https://i.pcmag.com/imagery/reviews/01jciGTh8bUT5wFvORiELjy-14..v1627508527.png", + "https://i.pcmag.com/imagery/reviews/01jciGTh8bUT5wFvORiELjy-11..v1627508527.png" + ] + }, + "axel": { + "icon": "https://community.chocolatey.org/content/packageimages/axel.2.4.1.png", + "images": [] + }, + "axiom": { + "icon": "", + "images": [] + }, + "axis": { + "icon": "", + "images": [] + }, + "axtraxng": { + "icon": "https://community.chocolatey.org/content/packageimages/axtraxng.27.7.1.19.png", + "images": [] + }, + "axurerp-10": { + "icon": "https://i.imgur.com/6VJTDPC.png", + "images": [ + "https://i.ytimg.com/vi/bFtXrsvdA1U/maxresdefault.jpg", + "https://uploads-ssl.webflow.com/60ac286928965092f733e140/60ac35cb7bfd6e9c8168e517_Axure%2BRP%2B10%2BOne%402x.png" + ] + }, + "axway-apim-cli": { + "icon": "https://community.chocolatey.org/content/packageimages/axway-apim-cli.1.13.3.png", + "images": [] + }, + "aya": { + "icon": "https://user-images.githubusercontent.com/2874236/75116104-fcc2ab00-5675-11ea-91af-0e8e04df8a46.png", + "images": [ + "https://user-images.githubusercontent.com/2874236/75115994-0dbeec80-5675-11ea-93a1-33f4e5fb9e70.png" + ] + }, + "az-powershell": { + "icon": "https://community.chocolatey.org/content/packageimages/az.powershell.9.4.0.png", + "images": [] + }, + "azclient": { + "icon": "https://community.chocolatey.org/content/packageimages/azclient.0.5.png", + "images": [] + }, + "azcopy": { + "icon": "", + "images": [] + }, + "azcopy10": { + "icon": "https://community.chocolatey.org/content/packageimages/azcopy10.10.17.0.png", + "images": [] + }, + "azd": { + "icon": "", + "images": [] + }, + "azdata-cli": { + "icon": "", + "images": [] + }, + "azkar": { + "icon": "https://i.imgur.com/iY6QivM.png", + "images": [ + "https://user-images.githubusercontent.com/48678280/174669335-b9cdf440-4ba4-48a6-a218-addb0c749db6.png", + "https://user-images.githubusercontent.com/48678280/141684574-ad164c5a-ac22-4c27-8774-6847e10cde3b.jpg", + "https://user-images.githubusercontent.com/48678280/141684402-51d9a132-2dad-4648-ad4f-d6cf814a9c93.png" + ] + }, + "azpazeta": { + "icon": "", + "images": [] + }, + "aztfy": { + "icon": "", + "images": [] + }, + "aztoolkit": { + "icon": "", + "images": [] + }, + "azure-ad-connect": { + "icon": "", + "images": [] + }, + "azure-azcopy-10": { + "icon": "", + "images": [] + }, + "azure-aztfy": { + "icon": "", + "images": [] + }, + "azure-cli": { + "icon": "https://community.chocolatey.org/content/packageimages/azure-cli.2.45.0.png", + "images": [] + }, + "azure-cosmosemulator": { + "icon": "", + "images": [] + }, + "azure-data-studio-sql-server-admin-pack": { + "icon": "https://community.chocolatey.org/content/packageimages/azure-data-studio-sql-server-admin-pack.0.0.1.png", + "images": [] + }, + "azure-datacli": { + "icon": "", + "images": [] + }, + "azure-devops-policy-configurator": { + "icon": "", + "images": [] + }, + "azure-documentdb-emulator": { + "icon": "", + "images": [] + }, + "azure-functions-core-tools": { + "icon": "https://community.chocolatey.org/content/packageimages/azure-functions-core-tools.4.0.5030.png", + "images": [] + }, + "azure-functions-core-tools-3": { + "icon": "https://community.chocolatey.org/content/packageimages/azure-functions-core-tools-3.3.0.3785.png", + "images": [] + }, + "azure-functionscoretools": { + "icon": "", + "images": [] + }, + "azure-information-protection-unified-labeling-client": { + "icon": "https://community.chocolatey.org/content/packageimages/azure-information-protection-unified-labeling-client.2.14.90.0.png", + "images": [] + }, + "azure-iot-explorer": { + "icon": "", + "images": [] + }, + "azure-iotexplorer": { + "icon": "", + "images": [] + }, + "azure-kubelogin": { + "icon": "", + "images": [] + }, + "azure-pipelines-agent": { + "icon": "https://community.chocolatey.org/content/packageimages/azure-pipelines-agent.2.217.2.png", + "images": [] + }, + "azure-ps": { + "icon": "", + "images": [] + }, + "azure-storageemulator": { + "icon": "", + "images": [] + }, + "azure-storageexplorer": { + "icon": "", + "images": [] + }, + "azurebuildsdkvs2012": { + "icon": "https://community.chocolatey.org/content/packageimages/AzureBuildSDKvs2012.2.4.0.png", + "images": [] + }, + "azurebuildsdkvs2013": { + "icon": "", + "images": [] + }, + "azurecli": { + "icon": "", + "images": [] + }, + "azuredatafactorytools15": { + "icon": "https://community.chocolatey.org/content/packageimages/azuredatafactorytools15.0.9.3527.2.png", + "images": [] + }, + "azuredatastudio": { + "icon": "https://i.imgur.com/rpaxRmk.png", + "images": [ + "https://i.imgur.com/IVuHK5O.png", + "https://i.imgur.com/VidjK8M.png" + ] + }, + "azuredatastudio-insiders": { + "icon": "https://i.imgur.com/rpaxRmk.png", + "images": [ + "https://i.imgur.com/IVuHK5O.png", + "https://i.imgur.com/VidjK8M.png" + ] + }, + "azuredatastudio-powershell": { + "icon": "https://community.chocolatey.org/content/packageimages/azuredatastudio-powershell.2022.8.5.png", + "images": [] + }, + "azurefunctions-vscode": { + "icon": "", + "images": [] + }, + "azurepowershell": { + "icon": "https://community.chocolatey.org/content/packageimages/AzurePowerShell.6.9.0.20211025.png", + "images": [] + }, + "azurestorageemulator": { + "icon": "", + "images": [] + }, + "azurestorageexplorer": { + "icon": "", + "images": [] + }, + "b1": { + "icon": "", + "images": [] + }, + "b2": { + "icon": "", + "images": [] + }, + "b2bclient": { + "icon": "", + "images": [] + }, + "b2sum": { + "icon": "", + "images": [] + }, + "b3sum": { + "icon": "", + "images": [] + }, + "b4j": { + "icon": "https://community.chocolatey.org/content/packageimages/B4J.8.50.png", + "images": [] + }, + "babelmap": { + "icon": "https://community.chocolatey.org/content/packageimages/babelmap.15.0.0.5.png", + "images": [] + }, + "babelpad": { + "icon": "https://community.chocolatey.org/content/packageimages/babelpad.15.0.0.4.png", + "images": [] + }, + "babyftp": { + "icon": "https://community.chocolatey.org/content/packageimages/babyftp.1.24.png", + "images": [] + }, + "babysmash": { + "icon": "", + "images": [] + }, + "back-to-backspace-chrome": { + "icon": "", + "images": [] + }, + "backup-restore": { + "icon": "", + "images": [] + }, + "backup-start-menu-layout": { + "icon": "", + "images": [] + }, + "backupandsync": { + "icon": "https://i.imgur.com/OAW2RMk.png", + "images": [ + "https://1.bp.blogspot.com/-kyT1WzImsDQ/YOxgOPE941I/AAAAAAAAKBw/kjvRhMgsdj4_lrhzmreFQBbABELLlv4-wCLcBGAsYHQ/s1375/drive%2Bfor%2Bdesktop.png", + "https://i.imgur.com/djKiC3T.jpg", + "https://i.imgur.com/bgvMCpb.png" + ] + }, + "backupper": { + "icon": "https://www.megaleechers.com/storage/AOMEI-Backupper-Icon.png", + "images": [ + "https://images.idgesg.net/images/article/2021/07/aomei-backupper-6-tools-100895761-large.jpg", + "https://images.idgesg.net/images/article/2021/07/aomei-backupper-6-sync-tab-100895760-large.jpg", + "https://www.lifewire.com/thmb/-PFAciaszPLMbis0tGJz4b5CC5s=/1010x674/filters:fill(auto,1)/aomei-backupper-standard-6-3083ab1eadff4d369c4f89f096a25fd6.png", + "https://www.ubackup.com/screenshot/en/std/restore/system-restore-using-bootable-media/preview-restore.png", + "https://www.ubackup.com/screenshot/en/std/restore/system-restore-using-bootable-media/select-destination.png" + ] + }, + "backupper-server": { + "icon": "https://community.chocolatey.org/content/packageimages/backupper-server.5.3.0.png", + "images": [] + }, + "backupper-standard": { + "icon": "https://community.chocolatey.org/content/packageimages/backupper-standard.7.1.2.png", + "images": [] + }, + "backupvault": { + "icon": "https://community.chocolatey.org/content/packageimages/backupvault.3.2.2018.15.png", + "images": [] + }, + "badaboom-media-converter": { + "icon": "https://community.chocolatey.org/content/packageimages/badaboom-media-converter.2.0.0.128.png", + "images": [] + }, + "badger": { + "icon": "", + "images": [] + }, + "badlionclient": { + "icon": "https://i.imgur.com/vMTzw0v.png", + "images": [ + "https://assets.badlion.net/site/assets/client.png", + "https://i.imgur.com/1UkRg5e.jpg", + "https://i.imgur.com/lrJUZx7.jpg" + ] + }, + "baidunetdisk": { + "icon": "", + "images": [] + }, + "baidupcs-go": { + "icon": "", + "images": [] + }, + "baidupinyin": { + "icon": "", + "images": [] + }, + "baidusiassistant": { + "icon": "", + "images": [] + }, + "baidusimeeting": { + "icon": "", + "images": [] + }, + "baidutranslate": { + "icon": "", + "images": [] + }, + "baiduwenku": { + "icon": "", + "images": [] + }, + "baka-mplayer": { + "icon": "", + "images": [] + }, + "balabolka": { + "icon": "", + "images": [] + }, + "balena-cli": { + "icon": "", + "images": [] + }, + "balenacli": { + "icon": "https://www.balena.io/docs/img/logo.svg", + "images": [ + "https://i.imgur.com/y2qAdKD.png", + "https://i.imgur.com/lSrugml.png", + "https://i.imgur.com/wcfZcGB.png" + ] + }, + "balsamiqmockups3": { + "icon": "https://community.chocolatey.org/content/packageimages/balsamiqmockups3.3.4.4.png", + "images": [] + }, + "balsamiqwireframes": { + "icon": "https://community.chocolatey.org/content/packageimages/balsamiqwireframes.4.5.4.png", + "images": [] + }, + "bamboo-tray": { + "icon": "", + "images": [] + }, + "bambustudio": { + "icon": "https://unigeticons.meowcat285.com/BambuStudio.png", + "images": [] + }, + "banana-buchhaltung": { + "icon": "https://community.chocolatey.org/content/packageimages/banana-buchhaltung.10.0.12.png", + "images": [] + }, + "banana-cake-pop": { + "icon": "", + "images": [] + }, + "bananacakepop": { + "icon": "https://i.imgur.com/BLAMFGT.png", + "images": [ + "https://chillicream.com/static/235c2468b1b6a9b5e818516b74e55e84/e2f49/bcp-operations.png", + "https://chillicream.com/static/6fb492dfe4f20527624dcb562abe875a/e2f49/bcp-start-screen.png", + "https://chillicream.com/static/daf2e87c9c32e15cd16d34e051937d06/e2f49/bcp-endpoint-entry.png", + "https://chillicream.com/static/96a1180f1c43149cfdcb7b3da53284b1/e2f49/bcp-sessionsbyid-query.png", + "https://chillicream.com/static/5fb9d581f93b8bd6ccde495964363edf/e2f49/bcp-editor-dropdown.png", + "https://chillicream.com/static/13f73550b3648db5c6e8010eb3b6be42/e2f49/bcp-schema-reference-query-type.png" + ] + }, + "bandicam": { + "icon": "https://i.imgur.com/E9S91RK.png", + "images": [ + "https://static.bandicam.com/img/screenshot/bandicam-start.jpg", + "https://static.bandicam.com/img/screenshot/bandicam-select.jpg", + "https://static.bandicam.com/img/screenshot/bandicam-screen-recording.jpg", + "https://static.bandicam.com/img/screenshot/bandicam-game-recording.jpg", + "https://static.bandicam.com/img/screenshot/bandicam-device-recording.jpg", + "https://static.bandicam.com/img/screenshot/bandicam-folder.jpg" + ] + }, + "bandicut": { + "icon": "https://i.imgur.com/u0qdAsn.png", + "images": [ + "https://static.bandicam.com/bandicut-video-cutter/screenshot/3_bandicut_screenshot_base.jpg", + "https://static.bandicam.com/bandicut-video-cutter/screenshot/3_bandicut_screenshot_cutter.jpg", + "https://static.bandicam.com/bandicut-video-cutter/screenshot/3_bandicut_screenshot_spliter.jpg", + "https://static.bandicam.com/bandicut-video-cutter/screenshot/3_bandicut_screenshot_joiner.jpg", + "https://static.bandicam.com/bandicut-video-cutter/screenshot/3_bandicut_screenshot_process.jpg" + ] + }, + "bandizip": { + "icon": "https://i.imgur.com/qqhrrET.png", + "images": [ + "https://www.bandisoft.com/bandizip/screenshots/imgs.en/08_pm.png", + "https://www.bandisoft.com/bandizip/screenshots/imgs.en/09_repair.png", + "https://www.bandisoft.com/bandizip/screenshots/imgs.en/10_pr.png", + "https://www.bandisoft.com/bandizip/screenshots/imgs.en/11_preview.png", + "https://www.bandisoft.com/bandizip/screenshots/imgs.en/12_amsi.png" + ] + }, + "bandiview": { + "icon": "", + "images": [ + "https://en.bandisoft.com/bandiview/screenshots/imgs.en/01.png" + ] + }, + "banks": { + "icon": "https://community.chocolatey.org/content/packageimages/banks.portable.1.02.png", + "images": [] + }, + "barcode-to-pc-server": { + "icon": "https://community.chocolatey.org/content/packageimages/barcode-to-pc-server.4.3.1.png", + "images": [] + }, + "baregrep": { + "icon": "https://community.chocolatey.org/content/packageimages/baregrep.3.50.0.20120225.png", + "images": [] + }, + "baretail": { + "icon": "https://community.chocolatey.org/content/packageimages/baretail.3.50.0.20120226.png", + "images": [] + }, + "barrier": { + "icon": "https://i.postimg.cc/jjtTJ58S/barrier-icon.png", + "images": [ + "https://i.postimg.cc/0QNqc41g/barrier1.png", + "https://i.postimg.cc/HLzg0gK4/barrier2.png" + ] + }, + "barryschiffer-netscaler-script": { + "icon": "", + "images": [] + }, + "bas21": { + "icon": "https://bas21.no/wp-content/uploads/2018/05/bascore-100.png", + "images": [ + "https://bas21.no/wp-content/uploads/2018/05/bas21ordre-1024x496.jpg" + ] + }, + "base64": { + "icon": "https://community.chocolatey.org/content/packageimages/base64.1.0.0.png", + "images": [] + }, + "basecamp": { + "icon": "", + "images": [] + }, + "basilisk": { + "icon": "https://community.chocolatey.org/content/packageimages/basilisk.install.2022.01.27.png", + "images": [] + }, + "bat": { + "icon": "", + "images": [] + }, + "bat2exe": { + "icon": "", + "images": [] + }, + "batch-docs": { + "icon": "https://community.chocolatey.org/content/packageimages/batch-docs.5.6.0.png", + "images": [] + }, + "batch-encoding-converter": { + "icon": "https://community.chocolatey.org/content/packageimages/batch-encoding-converter.5.0.0.png", + "images": [] + }, + "batch-file-encrypt": { + "icon": "https://community.chocolatey.org/content/packageimages/batch-file-encrypt.5.0.0.png", + "images": [] + }, + "batch-file-manager": { + "icon": "https://community.chocolatey.org/content/packageimages/batch-file-manager.5.0.0.png", + "images": [] + }, + "batch-file-rename": { + "icon": "https://community.chocolatey.org/content/packageimages/batch-file-rename.5.0.0.png", + "images": [] + }, + "batch-files": { + "icon": "https://community.chocolatey.org/content/packageimages/batch-files.5.0.0.png", + "images": [] + }, + "batch-hex-editor": { + "icon": "https://community.chocolatey.org/content/packageimages/batch-hex-editor.5.0.0.png", + "images": [] + }, + "batch-image-converter": { + "icon": "https://community.chocolatey.org/content/packageimages/batch-image-converter.5.6.0.png", + "images": [] + }, + "batch-image-enhancer": { + "icon": "https://community.chocolatey.org/content/packageimages/batch-image-enhancer.5.6.0.png", + "images": [] + }, + "batch-image-splitter": { + "icon": "https://community.chocolatey.org/content/packageimages/batch-image-splitter.5.6.0.png", + "images": [] + }, + "batch-image-watermarker": { + "icon": "https://community.chocolatey.org/content/packageimages/batch-image-watermarker.5.6.0.png", + "images": [] + }, + "batch-install-vsix": { + "icon": "", + "images": [] + }, + "batch-photo-face": { + "icon": "https://community.chocolatey.org/content/packageimages/batch-photo-face.5.6.0.png", + "images": [] + }, + "batch-regex": { + "icon": "https://community.chocolatey.org/content/packageimages/batch-regex.5.0.0.png", + "images": [] + }, + "batch-word-replace": { + "icon": "https://community.chocolatey.org/content/packageimages/batch-word-replace.5.6.0.png", + "images": [] + }, + "batchdocs": { + "icon": "https://i.imgur.com/REcnsis.png", + "images": [ + "https://www.binarymark.com/assets/batch/screens/bd/bd-1.gif", + "https://www.binarymark.com/assets/batch/screens/bd/bd-2.gif", + "https://www.binarymark.com/assets/batch/screens/bd/bd-3.gif", + "https://www.binarymark.com/assets/batch/screens/bd/replaceregex.png", + "https://www.binarymark.com/assets/batch/screens/bd/delete1.png" + ] + }, + "batchencodingconverter": { + "icon": "https://i.imgur.com/LulTz8S.png", + "images": [ + "https://www.binarymark.com/assets/batch-files-processor/screenshots/v3/findfiles1.png", + "https://www.binarymark.com/img/screens/p18_main.png", + "https://www.binarymark.com/assets/batch-files-processor/screenshots/v3/manualproc.png", + "https://www.binarymark.com/assets/batch-files-processor/screenshots/v3/schedule1.png", + "https://www.binarymark.com/assets/batch-files-processor/screenshots/v3/actionsequence2.png" + ] + }, + "batchfileencrypt": { + "icon": "https://i.imgur.com/bp6zJ2f.png", + "images": [ + "https://www.binarymark.com/img/screens/p31_main.png", + "https://www.binarymark.com/assets/batch-files-processor/screenshots/v3/manualproc.png", + "https://www.binarymark.com/assets/batch-files-processor/screenshots/actions/act_encrypt.png", + "https://www.binarymark.com/assets/batch-files-processor/screenshots/v3/p31_welcome.png", + "https://www.binarymark.com/assets/batch-files-processor/screenshots/v3/manualmode.png" + ] + }, + "batchfilemanager": { + "icon": "https://i.imgur.com/REcnsis.png", + "images": [ + "https://www.binarymark.com/assets/batch-files-processor/screenshots/v3/manualmode.png", + "https://www.binarymark.com/assets/batch-files-processor/screenshots/v3/commontasks4.png", + "https://www.binarymark.com/assets/batch-files-processor/screenshots/v3/filehelper_copy.png", + "https://www.binarymark.com/assets/batch-files-processor/screenshots/v3/rename1.png", + "https://www.binarymark.com/assets/batch-files-processor/screenshots/v3/findfiles1.png" + ] + }, + "batchfilerename": { + "icon": "https://i.imgur.com/kCHWyKz.png", + "images": [ + "https://www.binarymark.com/img/screens/p25_main.png", + "https://www.binarymark.com/assets/batch-files-processor/screenshots/v3/manualmode.png", + "https://www.binarymark.com/assets/batch-files-processor/screenshots/v3/rename1.png", + "https://www.binarymark.com/assets/batch-files-processor/screenshots/v3/findfiles1.png" + ] + }, + "batchfilereplace": { + "icon": "https://i.imgur.com/VJhsHSY.png", + "images": [ + "https://www.binarymark.com/img/screens/p19_main.png", + "https://www.binarymark.com/assets/batch-files-processor/screenshots/v3/findfiles1.png", + "https://www.binarymark.com/assets/batch-files-processor/screenshots/v3/manualproc.png", + "https://www.binarymark.com/assets/batch-files-processor/screenshots/v3/automode1.png", + "https://www.binarymark.com/assets/batch-files-processor/screenshots/v3/schedule1.png" + ] + }, + "batchfiles": { + "icon": "https://i.imgur.com/REcnsis.png", + "images": [ + "https://www.binarymark.com/assets/batch-files-processor/screenshots/v3/findfiles1.png", + "https://www.binarymark.com/img/screens/p17_main.png", + "https://www.binarymark.com/assets/batch-files-processor/screenshots/v3/manualproc.png", + "https://www.binarymark.com/assets/batch-files-processor/screenshots/actions/act_textreplace.png", + "https://www.binarymark.com/assets/batch-files-processor/screenshots/actions/act_format2.png" + ] + }, + "batchfilesplitjoin": { + "icon": "https://i.imgur.com/5TGCLm9.png", + "images": [ + "https://www.binarymark.com/assets/batch-files-processor/screenshots/v3/manualmode.png", + "https://www.binarymark.com/img/screens/p24_main.png", + "https://www.binarymark.com/assets/batch-files-processor/screenshots/v3/filehelper_copy.png", + "https://www.binarymark.com/assets/batch-files-processor/screenshots/v3/p24_welcome.png" + ] + }, + "batchhexeditor": { + "icon": "https://i.imgur.com/GzvYCVM.png", + "images": [ + "https://www.binarymark.com/assets/batch-files-processor/screenshots/v3/findfiles1.png", + "https://www.binarymark.com/img/screens/p21_main.png", + "https://www.binarymark.com/assets/batch-files-processor/screenshots/v3/manualproc.png", + "https://www.binarymark.com/assets/batch-files-processor/screenshots/actions/act_binreplace.png", + "https://www.binarymark.com/assets/batch-files-processor/screenshots/actions/act_insertbin.png" + ] + }, + "batchimageconverter": { + "icon": "https://i2.wp.com/filecr.com/wp-content/uploads/2022/04/batch-image-converter-logo.png", + "images": [ + "https://vovsoft.com/screenshots/batch-image-converter.png" + ] + }, + "batchimageenhancer": { + "icon": "https://i.imgur.com/REcnsis.png", + "images": [ + "https://www.binarymark.com/img/screens/p4_main.png", + "https://www.binarymark.com/assets/batch-image-processor/screenshots/tour/act11.png", + "https://www.binarymark.com/assets/batch-image-processor/screenshots/tour/scr_manualmode2.jpg", + "https://www.binarymark.com/assets/batch-image-processor/screenshots/tour/fitto_resize.jpg", + "https://www.binarymark.com/assets/batch-image-processor/screenshots/tour/resize_percent.jpg" + ] + }, + "batchimageresizer": { + "icon": "https://i.imgur.com/REcnsis.png", + "images": [ + "https://i.postimg.cc/d1LxnhHH/image.png", + "https://i.postimg.cc/ZKrDftcX/image.png", + "https://i.postimg.cc/LsqtbjSP/image.png", + "https://i.postimg.cc/MZBsT2hQ/image.png", + "https://i.postimg.cc/6pMcS9vq/image.png", + "https://i.postimg.cc/N0V4spDV/image.png", + "https://i.postimg.cc/3r2Bhjvj/image.png" + ] + }, + "batchimages": { + "icon": "https://i.imgur.com/REcnsis.png", + "images": [ + "https://www.binarymark.com/img/screens/p16_main.png", + "https://www.binarymark.com/assets/batch-image-processor/screenshots/tour/act1.png", + "https://www.binarymark.com/assets/batch-image-processor/screenshots/tour/scr_manualmode2.jpg", + "https://www.binarymark.com/assets/batch-image-processor/screenshots/tour/fitto_resize.jpg", + "https://www.binarymark.com/assets/batch-image-processor/screenshots/tour/resize_percent.jpg" + ] + }, + "batchimagesplitter": { + "icon": "https://i.imgur.com/REcnsis.png", + "images": [ + "https://www.binarymark.com/img/screens/p15_main.png", + "https://www.binarymark.com/assets/batch-image-processor/screenshots/tour/act5.png", + "https://www.binarymark.com/assets/batch-image-processor/screenshots/tour/scr_manualmode2.jpg", + "https://www.binarymark.com/assets/batch-image-processor/v3/cbi_split4.png", + "https://www.binarymark.com/assets/batch-image-processor/screenshots/tour/fitto_resize.jpg" + ] + }, + "batchimagewatermarker": { + "icon": "https://i.imgur.com/REcnsis.png", + "images": [ + "https://www.binarymark.com/img/screens/p3_main.png", + "https://www.binarymark.com/assets/batch-image-processor/screenshots/tour/act7.png", + "https://www.binarymark.com/assets/batch-image-processor/screenshots/tour/scr_manualmode2.jpg", + "https://www.binarymark.com/assets/batch-image-processor/screenshots/tour/watermarks.jpg", + "https://www.binarymark.com/assets/batch-image-processor/screenshots/tour/watermark_text.jpg" + ] + }, + "batchphotoface": { + "icon": "https://i.imgur.com/REcnsis.png", + "images": [ + "https://www.binarymark.com/img/screens/p14_main.png", + "https://www.binarymark.com/assets/batch-image-processor/v3/bi_actions_new56_1.png", + "https://www.binarymark.com/assets/batch-image-processor/screenshots/tour/scr_manualmode2.jpg", + "https://www.binarymark.com/assets/batch-image-processor/v3/cbi_face_helper.png", + "https://www.binarymark.com/assets/batch-image-processor/v3/cbi_face_search.png" + ] + }, + "batchregex": { + "icon": "https://i.imgur.com/BbSGkkF.png", + "images": [ + "https://www.binarymark.com/assets/batch-files-processor/screenshots/v3/findfiles1.png", + "https://www.binarymark.com/img/screens/p20_main.png", + "https://www.binarymark.com/assets/batch-files-processor/screenshots/v3/manualproc.png", + "https://www.binarymark.com/assets/batch-files-processor/screenshots/actions/act_regexreplace.png", + "https://www.binarymark.com/assets/batch-files-processor/screenshots/actions/act_format2.png" + ] + }, + "batchtextfileeditor": { + "icon": "https://i.imgur.com/1Vgpt5Q.png", + "images": [ + "https://www.binarymark.com/assets/batch-files-processor/screenshots/v3/findfiles1.png", + "https://www.binarymark.com/img/screens/p30_main.png", + "https://www.binarymark.com/assets/batch-files-processor/screenshots/v3/manualproc.png", + "https://www.binarymark.com/assets/batch-files-processor/screenshots/actions/act_textreplace.png", + "https://www.binarymark.com/assets/batch-files-processor/screenshots/actions/act_inserttext.png" + ] + }, + "batchwordreplace": { + "icon": "https://i.imgur.com/REcnsis.png", + "images": [ + "https://www.binarymark.com/assets/batch/screens/bd/bd-1.gif", + "https://www.binarymark.com/assets/batch/screens/bd/bd-2.gif", + "https://www.binarymark.com/assets/batch/screens/bd/bd-3.gif", + "https://www.binarymark.com/assets/batch/screens/bd/replace1.png", + "https://www.binarymark.com/assets/batch/screens/bd/replaceformat.png" + ] + }, + "batcodecheck": { + "icon": "", + "images": [] + }, + "batexpert": { + "icon": "", + "images": [] + }, + "batik": { + "icon": "https://community.chocolatey.org/content/packageimages/Batik.1.7.png", + "images": [] + }, + "batte-loadouts-dev": { + "icon": "", + "images": [] + }, + "battecode-cmder-dev": { + "icon": "https://community.chocolatey.org/content/packageimages/battecode.cmder.dev.1.1.3.1.png", + "images": [] + }, + "battery-care": { + "icon": "", + "images": [] + }, + "batterybar": { + "icon": "https://i.imgur.com/3swIrxK.png", + "images": [ + "https://batterybarpro.com/images/splash1.png", + "https://batterybarpro.com/images/features.png", + "https://batterybarpro.com/images/features1.png" + ] + }, + "batteryinfoview": { + "icon": "https://community.chocolatey.org/content/packageimages/batteryinfoview.1.23.png", + "images": [] + }, + "batterymon": { + "icon": "https://i.postimg.cc/bwFSNhS6/batterymon.png", + "images": [ + "https://i.postimg.cc/TPLLK4rT/image.png", + "https://i.postimg.cc/50GNxG46/image.png", + "https://i.postimg.cc/7brHz2T4/image.png", + "https://i.postimg.cc/3x7p5yfz/image.png" + ] + }, + "battleforwesnoth": { + "icon": "https://i.imgur.com/sn1MXX5.png", + "images": [ + "https://www.wesnoth.org/images/sshots/wesnoth-1.16.0-1.jpg", + "https://www.wesnoth.org/images/sshots/wesnoth-1.16.0-2.jpg", + "https://www.wesnoth.org/images/sshots/wesnoth-1.16.0-3.jpg", + "https://www.wesnoth.org/images/sshots/wesnoth-1.16.0-4.jpg", + "https://www.wesnoth.org/images/sshots/wesnoth-1.16.0-5.jpg" + ] + }, + "battlepainters": { + "icon": "https://www.saitogames.com/_images/painters_logo.gif", + "images": [ + "https://www.saitogames.com/_images/painters_screen01.gif", + "https://www.saitogames.com/_images/painters_screen02.gif", + "https://www.saitogames.com/_images/painters_screen03.gif", + "https://www.saitogames.com/_images/painters_screen04.gif" + ] + }, + "battoexeconverter": { + "icon": "", + "images": [] + }, + "batzendev-tools": { + "icon": "", + "images": [] + }, + "baulk": { + "icon": "https://i.imgur.com/3k2phcY.png", + "images": [ + "https://raw.githubusercontent.com/baulk/baulk/master/docs/images/getstarted.png", + "https://raw.githubusercontent.com/baulk/baulk/master/docs/images/baulksearch.png", + "https://raw.githubusercontent.com/baulk/baulk/master/docs/images/onterminal.png", + "https://raw.githubusercontent.com/baulk/baulk/master/docs/images/barrels.png" + ] + }, + "bazecor": { + "icon": "https://i.imgur.com/sblG8Td.png", + "images": [ + "https://raw.githubusercontent.com/Dygmalab/Bazecor/development/data/screenshot.png", + "https://i.imgur.com/glj06fJ.png" + ] + }, + "bazel": { + "icon": "", + "images": [] + }, + "bazel-buildtools": { + "icon": "", + "images": [] + }, + "bazelisk": { + "icon": "", + "images": [] + }, + "bbhouse": { + "icon": "https://i.imgur.com/c1Ne2d2.png", + "images": [ + "https://raw.githubusercontent.com/endcloud/bbhouse-tauri/master/doc/1660423610.png", + "https://raw.githubusercontent.com/endcloud/bbhouse-tauri/master/doc/Xnip2022-08-14_18-37-21.jpg" + ] + }, + "bbk-cli": { + "icon": "", + "images": [] + }, + "bbwin": { + "icon": "https://community.chocolatey.org/content/packageimages/bbwin.0.13.20160427.png", + "images": [] + }, + "bc": { + "icon": "", + "images": [] + }, + "bca-dac": { + "icon": "https://community.chocolatey.org/content/packageimages/bca-dac.0.1.0.png", + "images": [] + }, + "bca-docker": { + "icon": "https://community.chocolatey.org/content/packageimages/bca-docker.0.3.0.png", + "images": [] + }, + "bca-savemarkdowncommanddocumentation": { + "icon": "https://community.chocolatey.org/content/packageimages/bca-savemarkdowncommanddocumentation.0.0.2.png", + "images": [] + }, + "bcc-msbuildlog": { + "icon": "", + "images": [] + }, + "bcc-submission": { + "icon": "", + "images": [] + }, + "bdash": { + "icon": "", + "images": [ + "https://raw.githubusercontent.com/bdash-app/bdash/1.2.2/assets/capture1.png", + "https://raw.githubusercontent.com/bdash-app/bdash/1.2.2/assets/capture2.png" + ] + }, + "beaker": { + "icon": "https://community.chocolatey.org/content/packageimages/beaker.1.1.0.png", + "images": [] + }, + "beakerbrowser": { + "icon": "https://raw.githubusercontent.com/beakerbrowser/beaker/master/build/icons/256x256.png", + "images": [] + }, + "bear": { + "icon": "https://the-sz.com/products/bear/bear_icon.png", + "images": [ + "https://the-sz.com/products/bear/delta_small.jpg", + "https://the-sz.com/products/bear/details_small.jpg", + "https://the-sz.com/products/bear/logging_small.jpg", + "https://the-sz.com/products/bear/bear7.jpg", + "https://the-sz.com/products/bear/bear.jpg" + ] + }, + "beatdrop": { + "icon": "", + "images": [] + }, + "bedford": { + "icon": "https://the-sz.com/products/bedford/bedford_icon.png", + "images": [ + "https://the-sz.com/products/bedford/bedford.png" + ] + }, + "beebeep": { + "icon": "https://i.imgur.com/lZXq4xt.png", + "images": [ + "https://www.beebeep.net/images/shots/beebeep_in_action_macosx.png", + "https://www.beebeep.net/images/shots/beebeep_in_action_windows.png", + "https://www.beebeep.net/images/shots/beebeep_in_action_darkstyle.png" + ] + }, + "beef": { + "icon": "", + "images": [] + }, + "beeftext": { + "icon": "https://beeftext.org/images/BeeftextLogo75.png", + "images": [ + "https://beeftext.org/images/Demo01.png", + "https://beeftext.org/images/Demo02.gif" + ] + }, + "beehive": { + "icon": "", + "images": [] + }, + "beekeeper-studio": { + "icon": "https://i.ibb.co/TMZj4pS3/Image.png", + "images": [ + "https://i.postimg.cc/xCfs8tb3/image.png", + "https://i.postimg.cc/C5dmH57K/image.png", + "https://i.postimg.cc/BZwhZ5Zg/image.png", + "https://i.postimg.cc/pLKkBgfm/image.png", + "https://i.postimg.cc/W3Y73jvQ/image.png", + "https://i.postimg.cc/KjdrPN46/image.png", + "https://i.postimg.cc/0N8G0r54/image.png" + ] + }, + "beeper": { + "icon": "https://i.postimg.cc/j5JbY4KV/beeper_512.png", + "images": [] + }, + "beersmith": { + "icon": "", + "images": [] + }, + "beets": { + "icon": "https://community.chocolatey.org/content/packageimages/beets.1.6.0.png", + "images": [] + }, + "before-dawn": { + "icon": "", + "images": [] + }, + "behindyou": { + "icon": "", + "images": [] + }, + "belarcadvisor": { + "icon": "", + "images": [] + }, + "believerssword": { + "icon": "", + "images": [] + }, + "bellavista": { + "icon": "https://community.chocolatey.org/content/packageimages/bellavista.1.1.0.75.png", + "images": [] + }, + "belvedere": { + "icon": "https://community.chocolatey.org/content/packageimages/belvedere.0.7.1.png", + "images": [] + }, + "bencode-editor": { + "icon": "", + "images": [] + }, + "bennett": { + "icon": "https://community.chocolatey.org/content/packageimages/bennett.portable.1.26.png", + "images": [] + }, + "beqdesigner": { + "icon": "", + "images": [] + }, + "berrybrew": { + "icon": "", + "images": [] + }, + "bes": { + "icon": "", + "images": [] + }, + "bespoke": { + "icon": "https://community.chocolatey.org/content/packageimages/bespoke.1.1.0.png", + "images": [] + }, + "bespokesynth": { + "icon": "", + "images": [] + }, + "bestnotes": { + "icon": "", + "images": [] + }, + "besttrace": { + "icon": "", + "images": [] + }, + "beta": { + "icon": "", + "images": [] + }, + "betaflight-blackbox-explorer": { + "icon": "", + "images": [] + }, + "betaflight-configurator": { + "icon": "https://community.chocolatey.org/content/packageimages/betaflight-configurator.10.9.0.png", + "images": [] + }, + "better-joy": { + "icon": "", + "images": [] + }, + "betterbird": { + "icon": "https://avatars.githubusercontent.com/u/86832723", + "images": [] + }, + "bettercrewlink": { + "icon": "https://community.chocolatey.org/content/packageimages/bettercrewlink.3.1.1.png", + "images": [] + }, + "betterobs": { + "icon": "", + "images": [] + }, + "bettertls-psmodule": { + "icon": "https://community.chocolatey.org/content/packageimages/bettertls-psmodule.0.1.0.0.png", + "images": [] + }, + "beyondcompare": { + "icon": "https://i.postimg.cc/HLscGbLj/Beyond-Compare5.png", + "images": [ + "https://www.scootersoftware.com/shot_FolderCompare_Dark.png", + "https://www.scootersoftware.com/shot_TextCompare_Dark.png", + "https://www.scootersoftware.com/shot_FolderMerge_Dark.png", + "https://www.scootersoftware.com/shot_TextMerge_Dark.png" + ] + }, + "beyondcompare-integration": { + "icon": "https://community.chocolatey.org/content/packageimages/beyondcompare-integration.2.0.0.png", + "images": [] + }, + "beyondcompare-5": { + "icon": "https://i.postimg.cc/HLscGbLj/Beyond-Compare5.png", + "images": [ + "https://www.scootersoftware.com/shot_FolderCompare_Dark.png", + "https://www.scootersoftware.com/shot_TextCompare_Dark.png", + "https://www.scootersoftware.com/shot_FolderMerge_Dark.png", + "https://www.scootersoftware.com/shot_TextMerge_Dark.png" + ] + }, + "beyondcompare-4": { + "icon": "https://i.postimg.cc/HLscGbLj/Beyond-Compare5.png", + "images": [] + }, + "bfg": { + "icon": "", + "images": [] + }, + "bfg-repo-cleaner": { + "icon": "", + "images": [] + }, + "bginfo": { + "icon": "https://community.chocolatey.org/content/packageimages/bginfo.4.32.png", + "images": [] + }, + "bgpkiller": { + "icon": "", + "images": [] + }, + "biber": { + "icon": "https://community.chocolatey.org/content/packageimages/biber.portable.1.9.png", + "images": [] + }, + "bibletime": { + "icon": "", + "images": [] + }, + "biblioteq": { + "icon": "https://community.chocolatey.org/content/packageimages/biblioteq.2022.05.30.png", + "images": [] + }, + "bicep": { + "icon": "", + "images": [] + }, + "big-stretch-reminder": { + "icon": "", + "images": [] + }, + "biggit": { + "icon": "", + "images": [] + }, + "biglybt": { + "icon": "", + "images": [] + }, + "biglybt-no-java": { + "icon": "https://community.chocolatey.org/content/packageimages/biglybt-no-java.3.3.0.0.png", + "images": [] + }, + "bigrats": { + "icon": "", + "images": [] + }, + "bigstash": { + "icon": "", + "images": [] + }, + "biicode": { + "icon": "https://community.chocolatey.org/content/packageimages/biicode.2.8.png", + "images": [] + }, + "bilibili": { + "icon": "", + "images": [] + }, + "bilibilivideodownload": { + "icon": "", + "images": [] + }, + "bililiverecorder": { + "icon": "", + "images": [] + }, + "biliup-app": { + "icon": "", + "images": [] + }, + "bilive-electron": { + "icon": "", + "images": [] + }, + "billfish": { + "icon": "", + "images": [] + }, + "binance": { + "icon": "https://community.chocolatey.org/content/packageimages/binance.1.43.2.png", + "images": [] + }, + "binaryen": { + "icon": "", + "images": [] + }, + "bind": { + "icon": "", + "images": [] + }, + "bind-toolsonly": { + "icon": "", + "images": [] + }, + "bing": { + "icon": "https://registry.npmmirror.com/@lobehub/icons-static-png/latest/files/dark/bing-color.png", + "images": [] + }, + "bingbar": { + "icon": "", + "images": [] + }, + "bingdesktop": { + "icon": "https://registry.npmmirror.com/@lobehub/icons-static-png/latest/files/dark/bing-color.png", + "images": [] + }, + "binggpt": { + "icon": "https://images2.imgbox.com/9a/db/4veBjoAH_o.png", + "images": [] + }, + "bingwallpaper": { + "icon": "https://registry.npmmirror.com/@lobehub/icons-static-png/latest/files/dark/bing-color.png", + "images": [] + }, + "binutils": { + "icon": "", + "images": [] + }, + "biodiff": { + "icon": "", + "images": [] + }, + "bioedit": { + "icon": "", + "images": [] + }, + "biome": { + "icon": "", + "images": [] + }, + "biorhythms-calculator": { + "icon": "https://community.chocolatey.org/content/packageimages/biorhythms-calculator.2.0.0.png", + "images": [] + }, + "biorhythmscalculator": { + "icon": "", + "images": [] + }, + "bioviadraw-ae": { + "icon": "https://community.chocolatey.org/content/packageimages/bioviadraw-ae.2018.0.0.20180925.png", + "images": [] + }, + "birdskitchen": { + "icon": "", + "images": [] + }, + "birdtray": { + "icon": "", + "images": [] + }, + "bis-f": { + "icon": "https://community.chocolatey.org/content/packageimages/bis-f.7.1912.7.png", + "images": [] + }, + "biscuit": { + "icon": "", + "images": [] + }, + "bison": { + "icon": "", + "images": [] + }, + "bisq": { + "icon": "https://community.chocolatey.org/content/packageimages/bisq.1.9.9.png", + "images": [] + }, + "bistudio": { + "icon": "https://community.chocolatey.org/content/packageimages/bistudio.8.3.9.png", + "images": [] + }, + "bit": { + "icon": "", + "images": [] + }, + "bit-git": { + "icon": "", + "images": [] + }, + "bitboxapp": { + "icon": "", + "images": [] + }, + "bitcoin": { + "icon": "", + "images": [] + }, + "bitcoin-unlimited": { + "icon": "https://community.chocolatey.org/content/packageimages/bitcoin-unlimited.1.0.2.0.png", + "images": [] + }, + "bitcoincore": { + "icon": "", + "images": [] + }, + "bitcoinxt": { + "icon": "https://community.chocolatey.org/content/packageimages/bitcoinxt.install.0.11.04.png", + "images": [] + }, + "bitcomet": { + "icon": "https://community.chocolatey.org/content/packageimages/bitcomet.1.98.png", + "images": [] + }, + "bitcrypt": { + "icon": "https://community.chocolatey.org/content/packageimages/bitcrypt.0.0.3.png", + "images": [] + }, + "bitdefender": { + "icon": "https://unigeticons.meowcat285.com/bitdefendericon.png", + "images": [] + }, + "bitdefender-usb-immunizer": { + "icon": "https://community.chocolatey.org/content/packageimages/bitdefender-usb-immunizer.2.0.1.901.png", + "images": [] + }, + "bitdefenderavfree": { + "icon": "", + "images": [] + }, + "bitdiffer": { + "icon": "", + "images": [] + }, + "bitdriverupdater": { + "icon": "", + "images": [] + }, + "bitgamebooster": { + "icon": "", + "images": [] + }, + "bitkinex": { + "icon": "https://community.chocolatey.org/content/packageimages/bitkinex.3.2.3.20130823.png", + "images": [] + }, + "bitmessage": { + "icon": "", + "images": [] + }, + "bitmeteros": { + "icon": "https://community.chocolatey.org/content/packageimages/bitmeteros.0.7.6.png", + "images": [] + }, + "bitnami-xampp": { + "icon": "", + "images": [] + }, + "bitsmanager": { + "icon": "", + "images": [] + }, + "bitstreamverafonts": { + "icon": "", + "images": [] + }, + "bitvise-ssh-server": { + "icon": "https://community.chocolatey.org/content/packageimages/bitvise-ssh-server.9.27.png", + "images": [] + }, + "bitwarden": { + "icon": "https://raw.githubusercontent.com/bitwarden/brand/main/icons/256x256.png", + "images": [ + "https://tweakers.net/ext/i/2003879068.png" + ] + }, + "bitwarden-chrome": { + "icon": "", + "images": [] + }, + "bitwarden-cli": { + "icon": "https://community.chocolatey.org/content/packageimages/bitwarden-cli.2023.2.0.png", + "images": [] + }, + "bitwarden-edge": { + "icon": "", + "images": [] + }, + "bitwig": { + "icon": "https://community.chocolatey.org/content/packageimages/Bitwig.4.4.8.png", + "images": [] + }, + "biyi": { + "icon": "", + "images": [] + }, + "bizhawk": { + "icon": "", + "images": [] + }, + "biztalkfactorypowershellprovider": { + "icon": "", + "images": [] + }, + "biztalkmigrator-cli": { + "icon": "", + "images": [] + }, + "bkchem": { + "icon": "", + "images": [] + }, + "black": { + "icon": "https://i.postimg.cc/52qwxW0H/black.png", + "images": [] + }, + "blackbird": { + "icon": "https://community.chocolatey.org/content/packageimages/blackbird.1.0.85.320230119.png", + "images": [] + }, + "blat": { + "icon": "", + "images": [] + }, + "bleachbit": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/a/a9/Bleachbit_logo.svg/1200px-Bleachbit_logo.svg.png", + "images": [ + "https://cdn.neowin.com/news/images/uploaded/2020/02/1580983501_bleachbit_2020.jpg", + "https://software.opensuse.org/package/thumbnail/bleachbit.png" + ] + }, + "blender": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/0/0c/Blender_logo_no_text.svg/293px-Blender_logo_no_text.svg.png", + "images": [ + "https://i.ibb.co/0Xk37y3/Blender-4.jpg", + "https://i.ibb.co/6Rj232m/Blender-2.jpg", + "https://i.ibb.co/tK7KKBQ/Blender-3.jpg", + "https://i.ibb.co/35K0LQ5/Blender-1.jpg" + ] + }, + "blender-launcher": { + "icon": "", + "images": [] + }, + "bless": { + "icon": "https://community.chocolatey.org/content/packageimages/bless.0.6.0.png", + "images": [] + }, + "blink": { + "icon": "https://community.chocolatey.org/content/packageimages/blink.3.2.0.png", + "images": [] + }, + "blink1-tool": { + "icon": "", + "images": [] + }, + "blink1control2": { + "icon": "", + "images": [] + }, + "blinkmind": { + "icon": "", + "images": [] + }, + "blinkys-scary-school": { + "icon": "", + "images": [] + }, + "blisk": { + "icon": "", + "images": [] + }, + "blitz": { + "icon": "https://i.postimg.cc/HnLLYxHw/icon.png", + "images": [ + "https://i.postimg.cc/HW3JqGH0/1.png", + "https://i.postimg.cc/j5c5YNVq/2.png", + "https://i.postimg.cc/cLtrtr3T/3.png", + "https://i.postimg.cc/jd5WK8dp/4.png", + "https://i.postimg.cc/jjz2vmZ7/5.png", + "https://i.postimg.cc/JnMnFx2d/6.png", + "https://i.postimg.cc/CLQRKjRz/7.png", + "https://i.postimg.cc/mrxhYBN4/8.png", + "https://i.postimg.cc/rsYwKkFv/9.png", + "https://i.postimg.cc/CMv1vjHm/10.png", + "https://i.postimg.cc/15fzbfvP/11.png", + "https://i.postimg.cc/65gQKtPZ/12.png" + ] + }, + "blitz-gg": { + "icon": "https://community.chocolatey.org/content/packageimages/blitz.gg.2.1.184.png", + "images": [] + }, + "blobby2": { + "icon": "", + "images": [] + }, + "blobsaver": { + "icon": "", + "images": [] + }, + "blockbench": { + "icon": "https://offlinesetups.com/wp-content/uploads/2022/06/Blockbench.png", + "images": [ + "https://learn.microsoft.com/en-us/minecraft/creator/documents/media/entitymodeling/animation.png" + ] + }, + "blockcheck": { + "icon": "https://community.chocolatey.org/content/packageimages/blockcheck.0.0.9.7.png", + "images": [] + }, + "blockjsvbs-winconfig": { + "icon": "https://community.chocolatey.org/content/packageimages/blockjsvbs-winconfig.0.0.1.png", + "images": [] + }, + "blocknet": { + "icon": "", + "images": [] + }, + "blogspot-image-downloader": { + "icon": "https://community.chocolatey.org/content/packageimages/blogspot-image-downloader.1.1.0.png", + "images": [] + }, + "bloomrpc": { + "icon": "https://community.chocolatey.org/content/packageimages/bloomrpc.1.5.3.png", + "images": [] + }, + "bloxstrap": { + "icon": "https://raw.githubusercontent.com/pizzaboxer/bloxstrap/main/Images/Bloxstrap.png", + "images": [ + "https://i.postimg.cc/yNKgjgKs/image.png", + "https://i.postimg.cc/JndsW-TZ4/image.png", + "https://i.postimg.cc/wvB1ZKtG/image.png" + ] + }, + "blu-rayplayer": { + "icon": "", + "images": [] + }, + "bluebrick": { + "icon": "https://community.chocolatey.org/content/packageimages/bluebrick.1.9.1.png", + "images": [] + }, + "bluebubbles": { + "icon": "https://community.chocolatey.org/content/packageimages/bluebubbles.1.10.1.png", + "images": [] + }, + "bluecfd": { + "icon": "", + "images": [] + }, + "bluedis": { + "icon": "https://community.chocolatey.org/content/packageimages/bluedis.0.1.0.png", + "images": [] + }, + "bluefish": { + "icon": "", + "images": [] + }, + "bluej": { + "icon": "https://community.chocolatey.org/content/packageimages/bluej.5.1.0.png", + "images": [] + }, + "bluej-bundled": { + "icon": "https://community.chocolatey.org/content/packageimages/bluej-bundled.3.1.7.png", + "images": [] + }, + "bluejeans": { + "icon": "", + "images": [] + }, + "bluejeansapp": { + "icon": "https://community.chocolatey.org/content/packageimages/BlueJeansApp.2.23.193.png", + "images": [] + }, + "bluescreenview": { + "icon": "https://community.chocolatey.org/content/packageimages/bluescreenview.portable.1.55.png", + "images": [ + "https://i.postimg.cc/vmjpJ76p/image.png", + "https://i.postimg.cc/4d9rsK6m/image.png" + ] + }, + "bluesherpa": { + "icon": "", + "images": [] + }, + "bluestacks": { + "icon": "https://raw.githubusercontent.com/Fileover/Assets/main/Others/WingetUI/Bluestacks/bluestacks-icon.png", + "images": [ + "https://raw.githubusercontent.com/Fileover/Assets/main/Others/WingetUI/Bluestacks/bluestacks-screen01.png" + ] + }, + "bluetoothcl": { + "icon": "https://community.chocolatey.org/content/packageimages/bluetoothcl.1.07.png", + "images": [] + }, + "bluetoothlogview": { + "icon": "https://community.chocolatey.org/content/packageimages/bluetoothlogview.1.12.png", + "images": [] + }, + "bluetracker-cli": { + "icon": "https://community.chocolatey.org/content/packageimages/bluetracker-cli.2.3.0.png", + "images": [] + }, + "bluoscontroller": { + "icon": "", + "images": [] + }, + "blur-ie": { + "icon": "https://community.chocolatey.org/content/packageimages/Blur-IE.5.5.1930.png", + "images": [] + }, + "blush": { + "icon": "", + "images": [] + }, + "bmfont": { + "icon": "", + "images": [] + }, + "boardmix": { + "icon": "", + "images": [] + }, + "bobthehamstervga": { + "icon": "", + "images": [] + }, + "bochs": { + "icon": "", + "images": [] + }, + "boinc": { + "icon": "https://community.chocolatey.org/content/packageimages/boinc.7.20.2.png", + "images": [] + }, + "boinctasks": { + "icon": "", + "images": [] + }, + "bombardier": { + "icon": "https://community.chocolatey.org/content/packageimages/bombardier.1.2.5.png", + "images": [] + }, + "bomi": { + "icon": "", + "images": [] + }, + "bomist": { + "icon": "", + "images": [] + }, + "bonjour": { + "icon": "https://developer.apple.com/assets/elements/icons/bonjour/bonjour-256x256.png", + "images": [] + }, + "bonobo-git-server": { + "icon": "", + "images": [] + }, + "book-collector": { + "icon": "", + "images": [] + }, + "bookhunter": { + "icon": "", + "images": [] + }, + "boomeranggmail-chrome": { + "icon": "https://community.chocolatey.org/content/packageimages/boomeranggmail-chrome.1.2.7.png", + "images": [] + }, + "boost-msvc-12": { + "icon": "", + "images": [] + }, + "boost-msvc-14-2": { + "icon": "", + "images": [] + }, + "boost-msvc-14-3": { + "icon": "https://community.chocolatey.org/content/packageimages/boost-msvc-14.3.1.81.0.png", + "images": [] + }, + "boostnote": { + "icon": "https://community.chocolatey.org/content/packageimages/boostnote.0.16.1.20220307.png", + "images": [] + }, + "boostnote-local": { + "icon": "", + "images": [] + }, + "boot-clj": { + "icon": "", + "images": [] + }, + "boot-no-hyperv": { + "icon": "https://community.chocolatey.org/content/packageimages/boot-no-hyperv.0.1.0.png", + "images": [] + }, + "boot2docker": { + "icon": "", + "images": [] + }, + "bootstrap-studio": { + "icon": "https://community.chocolatey.org/content/packageimages/bootstrap-studio.install.6.3.1.png", + "images": [] + }, + "borderlessgaming": { + "icon": "https://community.chocolatey.org/content/packageimages/borderlessgaming.9.5.6.png", + "images": [] + }, + "borderlessminecraft": { + "icon": "https://community.chocolatey.org/content/packageimages/borderlessminecraft.1.3.2.png", + "images": [] + }, + "boringproxy": { + "icon": "", + "images": [] + }, + "borna-fonts": { + "icon": "https://community.chocolatey.org/content/packageimages/borna-fonts.2.1.png", + "images": [] + }, + "botframeworkcomposer": { + "icon": "", + "images": [] + }, + "botframeworkemulator": { + "icon": "", + "images": [] + }, + "botpress": { + "icon": "https://community.chocolatey.org/content/packageimages/botpress.12.30.7.png", + "images": [] + }, + "bottom": { + "icon": "", + "images": [] + }, + "bouml": { + "icon": "https://community.chocolatey.org/content/packageimages/bouml.7.9.1.png", + "images": [] + }, + "boundary": { + "icon": "", + "images": [] + }, + "boundingboxeditor": { + "icon": "https://community.chocolatey.org/content/packageimages/boundingboxeditor.2.5.0.png", + "images": [] + }, + "boutdutunnel-client": { + "icon": "", + "images": [] + }, + "boutdutunnel-server": { + "icon": "https://community.chocolatey.org/content/packageimages/boutdutunnel.server.1.5.3369.20120225.png", + "images": [] + }, + "bower": { + "icon": "https://community.chocolatey.org/content/packageimages/bower.1.8.12.png", + "images": [] + }, + "bowery-agent": { + "icon": "", + "images": [] + }, + "bowpad": { + "icon": "https://community.chocolatey.org/content/packageimages/bowpad.2.8.7.png", + "images": [] + }, + "box": { + "icon": "", + "images": [] + }, + "box-drive": { + "icon": "https://community.chocolatey.org/content/packageimages/box-drive.2.30.87.png", + "images": [] + }, + "boxcryptor": { + "icon": "https://community.chocolatey.org/content/packageimages/boxcryptor.2.52.2484.png", + "images": [] + }, + "boxcryptorclassic": { + "icon": "https://community.chocolatey.org/content/packageimages/BoxCryptorClassic.1.7.409.20180501.png", + "images": [] + }, + "boxes": { + "icon": "", + "images": [] + }, + "boxhero": { + "icon": "", + "images": [] + }, + "boxstarter": { + "icon": "https://community.chocolatey.org/content/packageimages/boxstarter.3.0.0.png", + "images": [] + }, + "boxstarter-azure": { + "icon": "https://community.chocolatey.org/content/packageimages/Boxstarter.Azure.3.0.0.png", + "images": [] + }, + "boxstarter-bootstrapper": { + "icon": "https://community.chocolatey.org/content/packageimages/boxstarter.bootstrapper.3.0.0.png", + "images": [] + }, + "boxstarter-chocolatey": { + "icon": "https://community.chocolatey.org/content/packageimages/boxstarter.chocolatey.3.0.0.png", + "images": [] + }, + "boxstarter-common": { + "icon": "https://community.chocolatey.org/content/packageimages/BoxStarter.Common.3.0.0.png", + "images": [] + }, + "boxstarter-hyperv": { + "icon": "https://community.chocolatey.org/content/packageimages/Boxstarter.HyperV.3.0.0.png", + "images": [] + }, + "boxstarter-testrunner": { + "icon": "https://community.chocolatey.org/content/packageimages/Boxstarter.TestRunner.3.0.0.png", + "images": [] + }, + "boxstarter-winconfig": { + "icon": "https://community.chocolatey.org/content/packageimages/BoxStarter.WinConfig.3.0.0.png", + "images": [] + }, + "boxstarter-windowsupdate": { + "icon": "", + "images": [] + }, + "boxsync": { + "icon": "https://community.chocolatey.org/content/packageimages/boxsync.4.0.8088.0.png", + "images": [] + }, + "boxtools": { + "icon": "", + "images": [] + }, + "bpbible": { + "icon": "", + "images": [] + }, + "bpgconv": { + "icon": "", + "images": [] + }, + "bpmn-rpastudio": { + "icon": "", + "images": [] + }, + "bpo": { + "icon": "", + "images": [] + }, + "bq": { + "icon": "https://community.chocolatey.org/content/packageimages/bq.portable.0.101.png", + "images": [] + }, + "br-adobereaderfr": { + "icon": "", + "images": [] + }, + "brackets": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/4/4c/Brackets_Icon.svg/2048px-Brackets_Icon.svg.png", + "images": [] + }, + "brackets-theseus": { + "icon": "https://community.chocolatey.org/content/packageimages/Brackets.Theseus.0.2.8.png", + "images": [] + }, + "brainsimulator": { + "icon": "https://community.chocolatey.org/content/packageimages/brainsimulator.0.6.0.png", + "images": [] + }, + "brave": { + "icon": "https://images2.imgbox.com/ba/f3/TN24YrQw_o.png", + "images": [ + "https://i.postimg.cc/RZBLqdDV/Brave-headpic.png", + "https://i.postimg.cc/tg9nGmmW/image.png" + ] + }, + "brave-beta": { + "icon": "https://images2.imgbox.com/ba/f3/TN24YrQw_o.png", + "images": [ + "https://i.postimg.cc/RZBLqdDV/Brave-headpic.png", + "https://i.postimg.cc/tg9nGmmW/image.png" + ] + }, + "brave-dev": { + "icon": "https://images2.imgbox.com/ba/f3/TN24YrQw_o.png", + "images": [ + "https://i.postimg.cc/RZBLqdDV/Brave-headpic.png", + "https://i.postimg.cc/tg9nGmmW/image.png" + ] + }, + "brave-nightly": { + "icon": "https://images2.imgbox.com/ba/f3/TN24YrQw_o.png", + "images": [ + "https://i.postimg.cc/RZBLqdDV/Brave-headpic.png", + "https://i.postimg.cc/tg9nGmmW/image.png" + ] + }, + "breaktimer": { + "icon": "", + "images": [] + }, + "breitbandmessung": { + "icon": "", + "images": [] + }, + "brename": { + "icon": "", + "images": [] + }, + "brightauthorconnected": { + "icon": "", + "images": [] + }, + "brim": { + "icon": "https://community.chocolatey.org/content/packageimages/brim.0.31.0.png", + "images": [] + }, + "briss": { + "icon": "", + "images": [] + }, + "brl-cad": { + "icon": "", + "images": [] + }, + "broadcast": { + "icon": "", + "images": [] + }, + "broadcaster": { + "icon": "", + "images": [] + }, + "broadcaster-ptr": { + "icon": "", + "images": [] + }, + "brogue": { + "icon": "", + "images": [] + }, + "broot": { + "icon": "", + "images": [] + }, + "brotli": { + "icon": "", + "images": [] + }, + "browser": { + "icon": "", + "images": [] + }, + "browser-select": { + "icon": "https://community.chocolatey.org/content/packageimages/browser-select.1.4.1.png", + "images": [] + }, + "browsermanager": { + "icon": "https://community.chocolatey.org/content/packageimages/browsermanager.1.3.0.3.png", + "images": [] + }, + "browserselect": { + "icon": "", + "images": [] + }, + "browsertamer": { + "icon": "", + "images": [] + }, + "browsinghistoryview": { + "icon": "https://community.chocolatey.org/content/packageimages/browsinghistoryview.2.21.png", + "images": [] + }, + "brutalchess": { + "icon": "", + "images": [] + }, + "brutaldoom": { + "icon": "https://community.chocolatey.org/content/packageimages/brutaldoom.21.0.0.png", + "images": [] + }, + "brutaldoom-d2reload": { + "icon": "https://community.chocolatey.org/content/packageimages/brutaldoom-d2reload.1.0.0.png", + "images": [] + }, + "brutaldoom-dtwid": { + "icon": "", + "images": [] + }, + "brutaldoom-epic2": { + "icon": "https://community.chocolatey.org/content/packageimages/brutaldoom-epic2.1.0.0.png", + "images": [] + }, + "brutaldoom-goingdown": { + "icon": "https://community.chocolatey.org/content/packageimages/brutaldoom-goingdown.1.0.0.png", + "images": [] + }, + "brutaldoom-hellbound": { + "icon": "", + "images": [] + }, + "brutaldoom-scythe2": { + "icon": "https://community.chocolatey.org/content/packageimages/brutaldoom-scythe2.2.0.0.png", + "images": [] + }, + "bruteshark": { + "icon": "https://community.chocolatey.org/content/packageimages/bruteshark.1.2.5.png", + "images": [] + }, + "bs1770gain": { + "icon": "", + "images": [] + }, + "bsnes": { + "icon": "https://community.chocolatey.org/content/packageimages/bsnes.1.15.png", + "images": [] + }, + "bsnes-hd": { + "icon": "", + "images": [] + }, + "bst": { + "icon": "https://community.chocolatey.org/content/packageimages/bst.1.0.png", + "images": [] + }, + "bstrings": { + "icon": "", + "images": [] + }, + "bt": { + "icon": "", + "images": [] + }, + "bt2qbt": { + "icon": "", + "images": [] + }, + "btop": { + "icon": "", + "images": [] + }, + "btop-lhm": { + "icon": "", + "images": [] + }, + "btopdf": { + "icon": "https://community.chocolatey.org/content/packageimages/btopdf.0.85.png", + "images": [] + }, + "btsync": { + "icon": "", + "images": [] + }, + "btyacc": { + "icon": "", + "images": [] + }, + "buck": { + "icon": "", + "images": [] + }, + "buckaroo": { + "icon": "https://community.chocolatey.org/content/packageimages/buckaroo.2.2.0.png", + "images": [] + }, + "buckets": { + "icon": "https://community.chocolatey.org/content/packageimages/buckets.portable.0.69.0.png", + "images": [] + }, + "bud": { + "icon": "", + "images": [] + }, + "buf": { + "icon": "", + "images": [] + }, + "buffalo": { + "icon": "", + "images": [] + }, + "bugn": { + "icon": "", + "images": [] + }, + "bugs": { + "icon": "", + "images": [] + }, + "build-them-all": { + "icon": "", + "images": [] + }, + "buildifier": { + "icon": "", + "images": [] + }, + "buildkite": { + "icon": "", + "images": [] + }, + "buildozer": { + "icon": "", + "images": [] + }, + "buildpacks": { + "icon": "", + "images": [] + }, + "buildtools2015": { + "icon": "https://i.postimg.cc/g2xkmBx5/image.png", + "images": [] + }, + "bulk-crap-uninstaller": { + "icon": "https://community.chocolatey.org/content/packageimages/bulk-crap-uninstaller.5.4.png", + "images": [] + }, + "bulk-extractor": { + "icon": "", + "images": [] + }, + "bulk-rename-command": { + "icon": "", + "images": [] + }, + "bulk-rename-utility": { + "icon": "", + "images": [] + }, + "bulkcrapuninstaller": { + "icon": "https://www.techspot.com/images2/downloads/topdownload/2022/02/2022-02-07-ts3_thumbs-067.png", + "images": [ + "https://www.bcuninstaller.com/assets/1.png", + "https://www.bcuninstaller.com/assets/3.png", + "https://www.bcuninstaller.com/assets/4.png", + "https://www.bcuninstaller.com/assets/2.png" + ] + }, + "bulkrenamecommand": { + "icon": "", + "images": [] + }, + "bulkrenameutility": { + "icon": "https://i.postimg.cc/d3kQmLP3/bulk-rename-utility.png", + "images": [ + "https://www.bulkrenameutility.co.uk/assets/img-bru/mainscr.png", + "https://www.bulkrenameutility.co.uk/assets/img-bru/bru_main1.png", + "https://www.bulkrenameutility.co.uk/assets/img-bru/bru_main2.png", + "https://www.bulkrenameutility.co.uk/assets/img-bru/bru_main3.png", + "https://www.bulkrenameutility.co.uk/assets/img-bru/bru_main4.png" + ] + }, + "bulletspassview": { + "icon": "https://community.chocolatey.org/content/packageimages/bulletspassview.portable.1.32.png", + "images": [] + }, + "bullzippdfstudio": { + "icon": "", + "images": [] + }, + "bumptop": { + "icon": "", + "images": [] + }, + "bumpy": { + "icon": "", + "images": [] + }, + "bun": { + "icon": "https://bun.com/icons/icon-512x512.png", + "images": [] + }, + "bundlerminifier": { + "icon": "", + "images": [] + }, + "bunqdesktop": { + "icon": "https://community.chocolatey.org/content/packageimages/bunqdesktop.0.9.10.png", + "images": [] + }, + "burgertime": { + "icon": "", + "images": [] + }, + "burnawarefree": { + "icon": "https://community.chocolatey.org/content/packageimages/burnawarefree.15.8.png", + "images": [] + }, + "burnawarepremium": { + "icon": "https://community.chocolatey.org/content/packageimages/burnawarepremium.15.8.png", + "images": [] + }, + "burnawarepro": { + "icon": "https://community.chocolatey.org/content/packageimages/burnawarepro.15.8.png", + "images": [] + }, + "burneremails-chrome": { + "icon": "https://community.chocolatey.org/content/packageimages/burneremails-chrome.0.1.7.png", + "images": [] + }, + "burnttoast-psmodule": { + "icon": "", + "images": [] + }, + "burp-suite-free-edition": { + "icon": "https://community.chocolatey.org/content/packageimages/burp-suite-free-edition.2022.12.4.png", + "images": [] + }, + "burp-suite-pro-edition": { + "icon": "https://community.chocolatey.org/content/packageimages/burp-suite-pro-edition.2022.3.3.png", + "images": [] + }, + "burpsuite-community": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/e/e7/BurpSuite_Comunity_Edition.svg/512px-BurpSuite_Comunity_Edition.svg.png", + "images": [] + }, + "burpsuite-professional": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/e/e7/BurpSuite_Comunity_Edition.svg/512px-BurpSuite_Comunity_Edition.svg.png", + "images": [] + }, + "businesscardmaker": { + "icon": "", + "images": [] + }, + "busybox": { + "icon": "https://community.chocolatey.org/content/packageimages/busybox.4882.0.png", + "images": [] + }, + "busybox-lean": { + "icon": "", + "images": [] + }, + "busylight-microsoft-teams": { + "icon": "", + "images": [] + }, + "butane": { + "icon": "", + "images": [] + }, + "butler": { + "icon": "https://community.chocolatey.org/content/packageimages/butler.15.21.0.png", + "images": [] + }, + "buttercup": { + "icon": "https://community.chocolatey.org/content/packageimages/buttercup.2.18.2.png", + "images": [] + }, + "butterflow": { + "icon": "", + "images": [] + }, + "butterflow-ui": { + "icon": "", + "images": [] + }, + "butterfly": { + "icon": "https://raw.githubusercontent.com/LinwoodDev/Butterfly/develop/app/web/ios/128.png", + "images": [] + }, + "butterfly-nightly": { + "icon": "", + "images": [] + }, + "buzz": { + "icon": "", + "images": [] + }, + "byacc": { + "icon": "", + "images": [] + }, + "byenow": { + "icon": "", + "images": [] + }, + "byond": { + "icon": "", + "images": [] + }, + "byteball": { + "icon": "https://community.chocolatey.org/content/packageimages/byteball.2.7.2.png", + "images": [] + }, + "bytecoin": { + "icon": "https://community.chocolatey.org/content/packageimages/bytecoin.1.1.8.png", + "images": [] + }, + "bytedanceminiappide": { + "icon": "", + "images": [] + }, + "bytemark": { + "icon": "", + "images": [] + }, + "bzeditor": { + "icon": "", + "images": [] + }, + "bzflag": { + "icon": "", + "images": [] + }, + "bzip2": { + "icon": "", + "images": [] + }, + "bzr": { + "icon": "https://community.chocolatey.org/content/packageimages/bzr.2.5.1.2.png", + "images": [] + }, + "c99toc89": { + "icon": "", + "images": [] + }, + "cabal": { + "icon": "https://community.chocolatey.org/content/packageimages/cabal.3.8.1.0.png", + "images": [] + }, + "cabal-mini": { + "icon": "", + "images": [] + }, + "cacert": { + "icon": "", + "images": [] + }, + "cachemonkey": { + "icon": "", + "images": [] + }, + "cacher": { + "icon": "https://community.chocolatey.org/content/packageimages/cacher.2.46.0.png", + "images": [] + }, + "cacheset": { + "icon": "https://community.chocolatey.org/content/packageimages/cacheset.1.0.png", + "images": [] + }, + "cactusblockchaingui": { + "icon": "", + "images": [] + }, + "cadconverter": { + "icon": "https://community.chocolatey.org/content/packageimages/CADConverter.3.1.png", + "images": [] + }, + "caddy": { + "icon": "https://community.chocolatey.org/content/packageimages/caddy.2.6.4.png", + "images": [] + }, + "cadreader": { + "icon": "https://i.postimg.cc/DZRr4bcc/image.png", + "images": [ + "https://i.postimg.cc/g0TR161P/image.png", + "https://i.postimg.cc/rsYvrjPP/image.png", + "https://i.postimg.cc/sX5YSg0d/image.png", + "https://i.postimg.cc/vBw9Qd8P/image.png" + ] + }, + "cadreader-cn": { + "icon": "https://i.postimg.cc/DZRr4bcc/image.png", + "images": [ + "https://i.postimg.cc/g0TR161P/image.png", + "https://i.postimg.cc/rsYvrjPP/image.png", + "https://i.postimg.cc/sX5YSg0d/image.png", + "https://i.postimg.cc/vBw9Qd8P/image.png" + ] + }, + "caesium": { + "icon": "https://community.chocolatey.org/content/packageimages/caesium.install.2.3.1.png", + "images": [] + }, + "caesium-image-compressor": { + "icon": "", + "images": [] + }, + "caesiumimagecompressor": { + "icon": "", + "images": [] + }, + "caesiumph": { + "icon": "", + "images": [] + }, + "caffeine": { + "icon": "https://community.chocolatey.org/content/packageimages/caffeine.1.97.0.20210517.png", + "images": [ + "https://i.postimg.cc/k5nPsNjK/image.png" + ] + }, + "cairo": { + "icon": "https://cairoshell.com/img/favicon.png", + "images": [ + "https://cairoshell.com/img/ss_dynDesk.jpg", + "https://cairoshell.com/img/ss_progs.png", + "https://cairoshell.com/img/ss_taskbar.png", + "https://cairoshell.com/img/ss_stacks.png" + ] + }, + "cairo-desktop": { + "icon": "https://cairoshell.com/img/favicon.png", + "images": [ + "https://cairoshell.com/img/ss_dynDesk.jpg", + "https://cairoshell.com/img/ss_progs.png", + "https://cairoshell.com/img/ss_taskbar.png", + "https://cairoshell.com/img/ss_stacks.png" + ] + }, + "cairoshell": { + "icon": "https://cairoshell.com/img/favicon.png", + "images": [ + "https://cairoshell.com/img/ss_dynDesk.jpg", + "https://cairoshell.com/img/ss_progs.png", + "https://cairoshell.com/img/ss_taskbar.png", + "https://cairoshell.com/img/ss_stacks.png" + ] + }, + "cajviewer": { + "icon": "", + "images": [] + }, + "cajviewer-simple": { + "icon": "", + "images": [] + }, + "cake": { + "icon": "https://community.chocolatey.org/content/packageimages/cake.portable.1.3.0.png", + "images": [] + }, + "cakerecipe-vscode": { + "icon": "https://community.chocolatey.org/content/packageimages/cakerecipe-vscode.0.5.0.png", + "images": [] + }, + "calcheck": { + "icon": "", + "images": [] + }, + "calculator": { + "icon": "", + "images": [] + }, + "calculator-net": { + "icon": "https://community.chocolatey.org/content/packageimages/Calculator.Net.1.2.0.42.png", + "images": [] + }, + "calculatorsuite": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/5/57/Geogebra.svg/240px-Geogebra.svg.png", + "images": [] + }, + "calibre": { + "icon": "https://i.postimg.cc/ZKZnJMkP/cal.png", + "images": [ + "https://i.postimg.cc/5N7XpSGw/Calibre-Linux-2-38.png", + "https://i.postimg.cc/k4zjxSC9/edit-book.png", + "https://i.postimg.cc/pdV1xxkN/calibre-323.png" + ] + }, + "calibre-dedrm": { + "icon": "https://community.chocolatey.org/content/packageimages/calibre-dedrm.10.0.3.png", + "images": [] + }, + "calibre-normal": { + "icon": "", + "images": [] + }, + "calibre-portable": { + "icon": "https://i.postimg.cc/ZKZnJMkP/cal.png", + "images": [ + "https://i.postimg.cc/5N7XpSGw/Calibre-Linux-2-38.png", + "https://i.postimg.cc/k4zjxSC9/edit-book.png", + "https://i.postimg.cc/pdV1xxkN/calibre-323.png" + ] + }, + "callbar": { + "icon": "", + "images": [] + }, + "callflowdesigner": { + "icon": "https://www.carierista.com/storage/companies/150/2d05df55a3399d793cfbd01657052b4d.png", + "images": [ + "https://www.3cx.com/wp-content/uploads/2017/05/screenshot_1.png", + "https://www.3cx.com/wp-content/uploads/2021/08/cfd.png", + "https://i.ytimg.com/vi/wBRFPCBQjLE/maxresdefault.jpg", + "https://aatroxcommunications.com.au/wp-content/uploads/2019/05/create-project.jpg" + ] + }, + "calliper": { + "icon": "", + "images": [] + }, + "cam": { + "icon": "", + "images": [] + }, + "cameochemicals": { + "icon": "", + "images": [] + }, + "camerahub": { + "icon": "https://i.postimg.cc/fTj3gLXs/camerahub_202512_128.png", + "images": [] + }, + "camerasettings": { + "icon": "", + "images": [] + }, + "cameyo": { + "icon": "", + "images": [] + }, + "camlviewer": { + "icon": "", + "images": [] + }, + "camo-studio": { + "icon": "", + "images": [] + }, + "camstudio": { + "icon": "", + "images": [] + }, + "camtasia": { + "icon": "https://i.postimg.cc/wvZkFLt4/camtasia-icon.png", + "images": [ + "https://i.postimg.cc/L4kScTT7/image.png" + ] + }, + "audiate": { + "icon": "https://i.postimg.cc/yNrhYcTg/audiate-icon.png", + "images": [] + }, + "camunda-bpm-tomcat": { + "icon": "", + "images": [] + }, + "camunda-modeler": { + "icon": "", + "images": [ + "https://i.postimg.cc/sDv8b82G/image.png" + ] + }, + "modeler": { + "icon": "", + "images": [ + "https://i.postimg.cc/sDv8b82G/image.png" + ] + }, + "camunda-operate": { + "icon": "", + "images": [] + }, + "canopy": { + "icon": "", + "images": [] + }, + "cantact": { + "icon": "", + "images": [] + }, + "cantara": { + "icon": "", + "images": [] + }, + "cantata": { + "icon": "https://community.chocolatey.org/content/packageimages/cantata.2.3.2.png", + "images": [] + }, + "canva": { + "icon": "https://i.imgur.com/lkKNh5X.png", + "images": [ + "https://i.imgur.com/9BlUW6o.png" + ] + }, + "capa": { + "icon": "https://i.postimg.cc/26HZSjRY/logo.png", + "images": [] + }, + "capcut": { + "icon": "https://i.imgur.com/KKlYzyU.png", + "images": [ + "https://i.imgur.com/HEcgy42.png" + ] + }, + "capframex": { + "icon": "", + "images": [] + }, + "caprine": { + "icon": "https://raw.githubusercontent.com/sindresorhus/caprine/main/media/AppIcon-readme.png", + "images": [] + }, + "capslockx": { + "icon": "https://community.chocolatey.org/content/packageimages/CapsLockX.1.30.3.png", + "images": [] + }, + "capstone": { + "icon": "", + "images": [] + }, + "captfencoder": { + "icon": "", + "images": [] + }, + "caption": { + "icon": "", + "images": [] + }, + "captionocrtool": { + "icon": "", + "images": [] + }, + "captura": { + "icon": "", + "images": [] + }, + "capture": { + "icon": "https://i.postimg.cc/SRWPM8L5/faststone-capture.png", + "images": [ + "https://screenrecorderpro.files.wordpress.com/2018/03/capture.png", + "https://screenrecorderpro.files.wordpress.com/2018/03/fscapture-auto-save-settings.png", + "https://screenrecorderpro.files.wordpress.com/2018/03/fscapture-editor.png", + "https://screenrecorderpro.files.wordpress.com/2018/03/fscapture-file-name-format.png", + "https://screenrecorderpro.files.wordpress.com/2018/03/fscapture-miscellaneous-settings.png" + ] + }, + "capture2text": { + "icon": "https://community.chocolatey.org/content/packageimages/capture2text.4.6.1.png", + "images": [] + }, + "captureflux": { + "icon": "https://community.chocolatey.org/content/packageimages/captureflux.6.0.5.png", + "images": [] + }, + "carbon": { + "icon": "https://community.chocolatey.org/content/packageimages/carbon.2.10.2.png", + "images": [] + }, + "caret": { + "icon": "https://community.chocolatey.org/content/packageimages/caret.3.4.6.png", + "images": [] + }, + "caretbeta": { + "icon": "", + "images": [] + }, + "carina": { + "icon": "https://community.chocolatey.org/content/packageimages/carina.2.1.3.png", + "images": [] + }, + "carlwebster-adds-script": { + "icon": "", + "images": [] + }, + "carlwebster-dhcp-script": { + "icon": "", + "images": [] + }, + "carlwebster-pvs-script": { + "icon": "", + "images": [] + }, + "carlwebster-xa6-script": { + "icon": "", + "images": [] + }, + "carlwebster-xa65-script": { + "icon": "", + "images": [] + }, + "carlwebster-xd5-script": { + "icon": "", + "images": [] + }, + "carnac": { + "icon": "https://community.chocolatey.org/content/packageimages/carnac.2.3.13.png", + "images": [] + }, + "carotdav": { + "icon": "", + "images": [] + }, + "carroll": { + "icon": "", + "images": [] + }, + "carvel-vendir": { + "icon": "", + "images": [] + }, + "cascadeur": { + "icon": "https://i.postimg.cc/Bb23WKb5/cascadeur.png", + "images": [ + "https://i.postimg.cc/7ZXbfp9v/cascadeur-ss0.png", + "https://i.postimg.cc/k54G8fY2/cascadeur-ss1.png", + "https://i.postimg.cc/pT5dcyHx/cascadeur-ss2.png", + "https://i.postimg.cc/tJ04Kyq6/cascadeur-ss3.png", + "https://i.postimg.cc/zvnG5Mvc/cascadeur-ss4.png", + "https://i.postimg.cc/15QzM9Yh/cascadeur-ss5.png", + "https://i.postimg.cc/vmNBvfC3/cascadeur-ss6.png" + ] + }, + "cascadiacodeitalic": { + "icon": "", + "images": [] + }, + "cascadiacodepl-italic": { + "icon": "", + "images": [] + }, + "cascadiafonts": { + "icon": "", + "images": [] + }, + "cascadiamono": { + "icon": "", + "images": [] + }, + "cascadiamonoitalic": { + "icon": "", + "images": [] + }, + "cascadiamonopl": { + "icon": "", + "images": [] + }, + "cascadiamonopl-italic": { + "icon": "", + "images": [] + }, + "cascalculator": { + "icon": "", + "images": [] + }, + "casecurebrowser": { + "icon": "", + "images": [] + }, + "cashcash": { + "icon": "", + "images": [] + }, + "cask": { + "icon": "", + "images": [] + }, + "casperjs": { + "icon": "", + "images": [] + }, + "cass": { + "icon": "https://community.chocolatey.org/content/packageimages/cass.4.0.0.png", + "images": [] + }, + "cassinidev": { + "icon": "", + "images": [] + }, + "castle-view-image": { + "icon": "", + "images": [] + }, + "castxml": { + "icon": "", + "images": [] + }, + "catalyst": { + "icon": "", + "images": [] + }, + "catalyst3": { + "icon": "", + "images": [] + }, + "catsxp": { + "icon": "", + "images": [] + }, + "cavesofqud": { + "icon": "https://community.chocolatey.org/content/packageimages/cavesofqud.1.0.4646.16699.png", + "images": [] + }, + "cbackup": { + "icon": "", + "images": [] + }, + "cbetar2": { + "icon": "", + "images": [] + }, + "cbox": { + "icon": "", + "images": [] + }, + "cc65-compiler": { + "icon": "", + "images": [] + }, + "ccache": { + "icon": "", + "images": [] + }, + "ccat": { + "icon": "", + "images": [] + }, + "cccp": { + "icon": "https://community.chocolatey.org/content/packageimages/cccp.2015.10.18.png", + "images": [] + }, + "ccenhancer": { + "icon": "https://community.chocolatey.org/content/packageimages/ccenhancer.portable.4.5.7.png", + "images": [] + }, + "ccextractor": { + "icon": "", + "images": [] + }, + "ccl": { + "icon": "", + "images": [] + }, + "ccleaner": { + "icon": "https://upload.wikimedia.org/wikipedia/en/4/4a/CCleaner_logo_2013.png", + "images": [] + }, + "ccleaner-protrial": { + "icon": "https://upload.wikimedia.org/wikipedia/en/4/4a/CCleaner_logo_2013.png", + "images": [] + }, + "ccls": { + "icon": "", + "images": [] + }, + "ccom": { + "icon": "", + "images": [] + }, + "cdburnerxp": { + "icon": "https://www.gezginler.net/indir/resim-grafik/cdburnerxp-1351609602.png", + "images": [] + }, + "cdex": { + "icon": "https://community.chocolatey.org/content/packageimages/cdex.2.24.png", + "images": [] + }, + "cdinfo": { + "icon": "", + "images": [] + }, + "cdn": { + "icon": "https://community.chocolatey.org/content/packageimages/cdn.1.3.png", + "images": [] + }, + "cdogssdl": { + "icon": "", + "images": [] + }, + "cdrtfe": { + "icon": "https://community.chocolatey.org/content/packageimages/cdrtfe.1.5.9.png", + "images": [] + }, + "cdrtools": { + "icon": "", + "images": [] + }, + "ceed": { + "icon": "https://community.chocolatey.org/content/packageimages/ceed.0.8.0.png", + "images": [] + }, + "celestia": { + "icon": "", + "images": [] + }, + "cellprofiler": { + "icon": "", + "images": [] + }, + "cellprofiler-analyst": { + "icon": "https://community.chocolatey.org/content/packageimages/cellprofiler-analyst.3.0.4.png", + "images": [] + }, + "cells": { + "icon": "", + "images": [] + }, + "cellssync": { + "icon": "https://community.chocolatey.org/content/packageimages/cellssync.0.9.2.png", + "images": [] + }, + "cemu": { + "icon": "https://community.chocolatey.org/content/packageimages/cemu.2.0.20220910.png", + "images": [] + }, + "cemui": { + "icon": "https://community.chocolatey.org/content/packageimages/cemu.2.0.20220910.png", + "images": [] + }, + "centbrowser": { + "icon": "https://community.chocolatey.org/content/packageimages/CentBrowser.4.3.9.248.png", + "images": [] + }, + "center": { + "icon": "", + "images": [] + }, + "centertaskbar": { + "icon": "", + "images": [] + }, + "centipede": { + "icon": "", + "images": [] + }, + "centrifugo": { + "icon": "", + "images": [] + }, + "cerebro": { + "icon": "", + "images": [] + }, + "cerebro-es": { + "icon": "https://community.chocolatey.org/content/packageimages/cerebro-es.0.9.2.png", + "images": [] + }, + "certaid": { + "icon": "", + "images": [] + }, + "certbot": { + "icon": "", + "images": [] + }, + "certdump": { + "icon": "", + "images": [] + }, + "certifysslmanager": { + "icon": "", + "images": [] + }, + "certifytheweb": { + "icon": "https://community.chocolatey.org/content/packageimages/certifytheweb.5.6.8.png", + "images": [] + }, + "certoniuchacz": { + "icon": "", + "images": [] + }, + "certstrap": { + "icon": "", + "images": [] + }, + "cevio": { + "icon": "https://community.chocolatey.org/content/packageimages/cevio.1.2.4.2.png", + "images": [] + }, + "cfbeta": { + "icon": "", + "images": [] + }, + "cfgcam": { + "icon": "", + "images": [] + }, + "cfiler": { + "icon": "https://community.chocolatey.org/content/packageimages/cfiler.2.49.png", + "images": [] + }, + "cfr": { + "icon": "", + "images": [] + }, + "cfsec": { + "icon": "", + "images": [] + }, + "cfssl": { + "icon": "", + "images": [] + }, + "cgithubinst": { + "icon": "", + "images": [] + }, + "chafa": { + "icon": "", + "images": [] + }, + "chainlp": { + "icon": "", + "images": [] + }, + "champ-r": { + "icon": "", + "images": [] + }, + "championify": { + "icon": "", + "images": [] + }, + "change-dns-servers": { + "icon": "", + "images": [] + }, + "change-screen-resolution": { + "icon": "", + "images": [] + }, + "changelog": { + "icon": "", + "images": [] + }, + "charissil": { + "icon": "https://community.chocolatey.org/content/packageimages/charissil.5.0.png", + "images": [] + }, + "charles": { + "icon": "https://community.chocolatey.org/content/packageimages/Charles.3.12.3.png", + "images": [ + "https://i.postimg.cc/hjWL10jV/image.png", + "https://i.postimg.cc/DZrqjbJH/image.png", + "https://i.postimg.cc/ydHRZYQP/image.png" + ] + }, + "charles4": { + "icon": "https://community.chocolatey.org/content/packageimages/charles4.4.6.3.png", + "images": [] + }, + "charm-gum": { + "icon": "", + "images": [] + }, + "charmtimetracker": { + "icon": "https://community.chocolatey.org/content/packageimages/charmtimetracker.1.12.0.png", + "images": [] + }, + "chars": { + "icon": "", + "images": [] + }, + "chaskis": { + "icon": "https://community.chocolatey.org/content/packageimages/chaskis.0.31.0.png", + "images": [] + }, + "chat": { + "icon": "", + "images": [] + }, + "chatclient": { + "icon": "", + "images": [] + }, + "chatgpt": { + "icon": "https://community.chocolatey.org/content/packageimages/chatgpt.0.10.3.png", + "images": [] + }, + "chatterino": { + "icon": "https://community.chocolatey.org/content/packageimages/chatterino.2.4.0.png", + "images": [] + }, + "chatty": { + "icon": "", + "images": [] + }, + "chatzilla": { + "icon": "", + "images": [] + }, + "cheat": { + "icon": "", + "images": [] + }, + "cheat-engine": { + "icon": "https://i.postimg.cc/653Bf1f3/image.png", + "images": [] + }, + "check-mk": { + "icon": "", + "images": [] + }, + "check-mk-agent": { + "icon": "", + "images": [] + }, + "checkerplusforgmail-chrome": { + "icon": "", + "images": [] + }, + "checkip": { + "icon": "", + "images": [] + }, + "checkstyle": { + "icon": "https://community.chocolatey.org/content/packageimages/checkstyle.6.18.png", + "images": [] + }, + "checksum": { + "icon": "", + "images": [] + }, + "checksum-compare": { + "icon": "", + "images": [] + }, + "chef-client": { + "icon": "https://community.chocolatey.org/content/packageimages/chef-client.18.1.0.png", + "images": [] + }, + "chef-development": { + "icon": "", + "images": [] + }, + "chef-workstation": { + "icon": "https://community.chocolatey.org/content/packageimages/chef-workstation.23.2.1028.png", + "images": [] + }, + "chefdk": { + "icon": "", + "images": [] + }, + "cherrytree": { + "icon": "https://community.chocolatey.org/content/packageimages/cherrytree.0.99.49.png", + "images": [] + }, + "chessx": { + "icon": "https://community.chocolatey.org/content/packageimages/chessx.1.5.0.png", + "images": [] + }, + "chezmoi": { + "icon": "", + "images": [] + }, + "chgkey": { + "icon": "", + "images": [] + }, + "chia-network": { + "icon": "https://community.chocolatey.org/content/packageimages/chia-network.1.7.0.png", + "images": [] + }, + "chicken": { + "icon": "https://community.chocolatey.org/content/packageimages/chicken.5.2.0.6.png", + "images": [] + }, + "chime": { + "icon": "https://seeklogo.com/images/A/amazon-chime-logo-EE2754CC2C-seeklogo.com.png", + "images": [ + "https://d15shllkswkct0.cloudfront.net/wp-content/blogs.dir/1/files/2017/02/Amazon-Chime.jpg", + "https://media.amazonwebservices.com/blog/2017/chime_main_1.png", + "https://answers.chime.aws/storage/attachments/97-41-resize-media-panes.png", + "https://media.amazonwebservices.com/blog/2017/chime_meeting_2.png", + "https://d2908q01vomqb2.cloudfront.net/ca3512f4dfa95a03169c5a670a4c91a19b3077b4/2020/06/29/thier-fig4.png" + ] + }, + "chimera": { + "icon": "https://community.chocolatey.org/content/packageimages/chimera.1.16.png", + "images": [] + }, + "chipmunk": { + "icon": "", + "images": [] + }, + "chipspeech": { + "icon": "", + "images": [] + }, + "chirp": { + "icon": "https://community.chocolatey.org/content/packageimages/chirp.install.2023.02.24.png", + "images": [] + }, + "chisel": { + "icon": "", + "images": [] + }, + "chk": { + "icon": "", + "images": [] + }, + "chkcpu": { + "icon": "", + "images": [] + }, + "chmac": { + "icon": "https://community.chocolatey.org/content/packageimages/ChMac.2.0.0.5.png", + "images": [] + }, + "choco-cleaner": { + "icon": "", + "images": [] + }, + "choco-install-packages-from-web-winconfig": { + "icon": "https://community.chocolatey.org/content/packageimages/choco-install-packages-from-web-winconfig.0.0.1.png", + "images": [] + }, + "choco-nuspec-checker": { + "icon": "", + "images": [] + }, + "choco-optimize-at": { + "icon": "https://community.chocolatey.org/content/packageimages/choco-optimize-at.0.0.1.1.png", + "images": [] + }, + "choco-package-deprecater": { + "icon": "", + "images": [] + }, + "choco-package-list-backup": { + "icon": "", + "images": [] + }, + "choco-persistent-packages": { + "icon": "https://community.chocolatey.org/content/packageimages/choco-persistent-packages.2018.05.06.png", + "images": [] + }, + "choco-protocol-support": { + "icon": "", + "images": [] + }, + "choco-update-notifier": { + "icon": "https://community.chocolatey.org/content/packageimages/choco-update-notifier.1.2.1.png", + "images": [] + }, + "choco-upgrade-all-at": { + "icon": "", + "images": [] + }, + "choco-upgrade-all-at-startup": { + "icon": "", + "images": [] + }, + "chocobutler": { + "icon": "https://community.chocolatey.org/content/packageimages/chocobutler.1.0.0.png", + "images": [] + }, + "chocolatey": { + "icon": "https://raw.githubusercontent.com/chocolatey/choco/develop/docs/logo/chocolateyicon.png", + "images": [ + "https://i.postimg.cc/kgYGgPdD/image.png", + "https://i.postimg.cc/d0FdGKx6/image.png" + ] + }, + "chocolatey-appstore-chrome": { + "icon": "https://raw.githubusercontent.com/chocolatey/choco/develop/docs/logo/chocolateyicon.png", + "images": [] + }, + "chocolatey-autoupdater": { + "icon": "https://raw.githubusercontent.com/chocolatey/choco/develop/docs/logo/chocolateyicon.png", + "images": [] + }, + "chocolatey-azuredatastudio-extension": { + "icon": "https://raw.githubusercontent.com/chocolatey/choco/develop/docs/logo/chocolateyicon.png", + "images": [] + }, + "chocolatey-compatibility-extension": { + "icon": "https://raw.githubusercontent.com/chocolatey/choco/develop/docs/logo/chocolateyicon.png", + "images": [] + }, + "chocolatey-core-extension": { + "icon": "https://raw.githubusercontent.com/chocolatey/choco/develop/docs/logo/chocolateyicon.png", + "images": [] + }, + "chocolatey-dotnetfx-extension": { + "icon": "https://raw.githubusercontent.com/chocolatey/choco/develop/docs/logo/chocolateyicon.png", + "images": [] + }, + "chocolatey-fastanswers-extension": { + "icon": "https://raw.githubusercontent.com/chocolatey/choco/develop/docs/logo/chocolateyicon.png", + "images": [] + }, + "chocolatey-font-helpers-extension": { + "icon": "https://raw.githubusercontent.com/chocolatey/choco/develop/docs/logo/chocolateyicon.png", + "images": [] + }, + "chocolatey-fosshub-extension": { + "icon": "https://raw.githubusercontent.com/chocolatey/choco/develop/docs/logo/chocolateyicon.png", + "images": [] + }, + "chocolatey-isomount-extension": { + "icon": "https://raw.githubusercontent.com/chocolatey/choco/develop/docs/logo/chocolateyicon.png", + "images": [] + }, + "chocolatey-mandelbulber2": { + "icon": "https://community.chocolatey.org/content/packageimages/chocolatey-mandelbulber2.2.27.png", + "images": [] + }, + "chocolatey-misc-helpers-extension": { + "icon": "", + "images": [] + }, + "chocolatey-nexus-repo": { + "icon": "https://community.chocolatey.org/content/packageimages/chocolatey-nexus-repo.1.0.1.png", + "images": [] + }, + "chocolatey-npm-extension": { + "icon": "", + "images": [] + }, + "chocolatey-os-dependency-extension": { + "icon": "", + "images": [] + }, + "chocolatey-preinstaller-checks-extension": { + "icon": "", + "images": [] + }, + "chocolatey-server": { + "icon": "https://raw.githubusercontent.com/chocolatey/choco/develop/docs/logo/chocolateyicon.png", + "images": [] + }, + "chocolatey-toast-notifications-extension": { + "icon": "", + "images": [] + }, + "chocolatey-uninstall-extension": { + "icon": "", + "images": [] + }, + "chocolatey-visualstudio-extension": { + "icon": "", + "images": [] + }, + "chocolatey-vscode": { + "icon": "https://community.chocolatey.org/content/packageimages/chocolatey-vscode.0.7.2.png", + "images": [] + }, + "chocolatey-vscode-extension": { + "icon": "", + "images": [] + }, + "chocolatey-windowsupdate-extension": { + "icon": "https://raw.githubusercontent.com/chocolatey/choco/develop/docs/logo/chocolateyicon.png", + "images": [] + }, + "chocolateydeploymentutils": { + "icon": "", + "images": [] + }, + "chocolateyexplorer": { + "icon": "", + "images": [] + }, + "chocolateygui": { + "icon": "https://i.postimg.cc/Dw17KsLV/icon.png", + "images": [ + "https://i.postimg.cc/zf58DBFy/1.png" + ] + }, + "chocolateypackageupdater": { + "icon": "", + "images": [] + }, + "chocolateypowershell": { + "icon": "", + "images": [] + }, + "chocomaint": { + "icon": "https://community.chocolatey.org/content/packageimages/chocomaint.1.0.3.7.png", + "images": [] + }, + "chocomon": { + "icon": "https://community.chocolatey.org/content/packageimages/chocomon.1.0.1.1.png", + "images": [] + }, + "chocoshortcuts": { + "icon": "https://community.chocolatey.org/content/packageimages/ChocoShortcuts.0.4.1.png", + "images": [] + }, + "choeazycopy": { + "icon": "https://unigeticons.meowcat285.com/ChoEazyCopy.png", + "images": [ + "https://unigeticons.meowcat285.com/Screenshots/ChoEazyCopy/EazyCopyMain.PNG", + "https://unigeticons.meowcat285.com/Screenshots/ChoEazyCopy/EazyCopyMain1.PNG" + ] + }, + "choosenim": { + "icon": "", + "images": [] + }, + "chordpro": { + "icon": "", + "images": [] + }, + "chow-tape-model": { + "icon": "https://community.chocolatey.org/content/packageimages/chow-tape-model.2.9.0.png", + "images": [] + }, + "chrlauncher": { + "icon": "https://community.chocolatey.org/content/packageimages/chrlauncher.portable.2.6.png", + "images": [] + }, + "chroma": { + "icon": "", + "images": [] + }, + "chromaprint": { + "icon": "", + "images": [] + }, + "chromas": { + "icon": "https://community.chocolatey.org/content/packageimages/chromas.2.6.6.png", + "images": [] + }, + "chrome": { + "icon": "https://i.postimg.cc/yd2gGCZY/chrome-icon.png", + "images": [ + "https://i.postimg.cc/5tNCY3J1/chrome-1.png", + "https://i.postimg.cc/nVQQDrys/chrome-2.png", + "https://i.postimg.cc/Y0gGKD6N/chrome-3.png" + ] + }, + "chrome-beta": { + "icon": "https://i.postimg.cc/BnRrthHP/chrome-beta-icon.png", + "images": [ + "https://i.postimg.cc/5tNCY3J1/chrome-1.png", + "https://i.postimg.cc/nVQQDrys/chrome-2.png", + "https://i.postimg.cc/Y0gGKD6N/chrome-3.png" + ] + }, + "chrome-beta-exe": { + "icon": "https://i.postimg.cc/BnRrthHP/chrome-beta-icon.png", + "images": [ + "https://i.postimg.cc/5tNCY3J1/chrome-1.png", + "https://i.postimg.cc/nVQQDrys/chrome-2.png", + "https://i.postimg.cc/Y0gGKD6N/chrome-3.png" + ] + }, + "chrome-canary": { + "icon": "https://i.postimg.cc/9f8qG7X9/chrome-canary-icon.png", + "images": [ + "https://i.postimg.cc/5tNCY3J1/chrome-1.png", + "https://i.postimg.cc/nVQQDrys/chrome-2.png", + "https://i.postimg.cc/Y0gGKD6N/chrome-3.png" + ] + }, + "chrome-dev": { + "icon": "https://i.postimg.cc/tgPL6hNS/chrome-dev-icon.png", + "images": [ + "https://i.postimg.cc/5tNCY3J1/chrome-1.png", + "https://i.postimg.cc/nVQQDrys/chrome-2.png", + "https://i.postimg.cc/Y0gGKD6N/chrome-3.png" + ] + }, + "chrome-dev-exe": { + "icon": "https://i.postimg.cc/tgPL6hNS/chrome-dev-icon.png", + "images": [ + "https://i.postimg.cc/5tNCY3J1/chrome-1.png", + "https://i.postimg.cc/nVQQDrys/chrome-2.png", + "https://i.postimg.cc/Y0gGKD6N/chrome-3.png" + ] + }, + "chrome-exe": { + "icon": "https://i.postimg.cc/yd2gGCZY/chrome-icon.png", + "images": [ + "https://i.postimg.cc/5tNCY3J1/chrome-1.png", + "https://i.postimg.cc/nVQQDrys/chrome-2.png", + "https://i.postimg.cc/Y0gGKD6N/chrome-3.png" + ] + }, + "chromecacheview": { + "icon": "https://community.chocolatey.org/content/packageimages/chromecacheview.2.41.png", + "images": [ + "https://i.postimg.cc/28mPNSVk/image.png" + ] + }, + "chromecookiebackup": { + "icon": "https://community.chocolatey.org/content/packageimages/chromecookiebackup.1.0.0.png", + "images": [] + }, + "chromedriver": { + "icon": "https://community.chocolatey.org/content/packageimages/chromedriver.110.0.5481.772.png", + "images": [] + }, + "chromedriver2": { + "icon": "", + "images": [] + }, + "chromehue-chrome": { + "icon": "", + "images": [] + }, + "chromelpass-chrome": { + "icon": "https://community.chocolatey.org/content/packageimages/chromelpass-chrome.2.8.1.png", + "images": [] + }, + "chromeremotedesktophost": { + "icon": "https://i.postimg.cc/PJZQkFwv/cds.png", + "images": [ + "https://i.postimg.cc/xTDPPYwv/srd1.png" + ] + }, + "chrometana-chrome": { + "icon": "https://community.chocolatey.org/content/packageimages/chrometana-chrome.2.0.1.png", + "images": [] + }, + "chromium": { + "icon": "https://i.postimg.cc/FzjDb7vy/chromium-icon.png", + "images": [] + }, + "chromium-gost": { + "icon": "", + "images": [] + }, + "chromium-stable": { + "icon": "https://i.postimg.cc/FzjDb7vy/chromium-icon.png", + "images": [] + }, + "chromiumbsu": { + "icon": "https://community.chocolatey.org/content/packageimages/chromiumbsu.0.9.16.1.png", + "images": [] + }, + "chrono-chrome": { + "icon": "https://community.chocolatey.org/content/packageimages/chrono-chrome.0.10.0.png", + "images": [] + }, + "chronograf": { + "icon": "", + "images": [] + }, + "cht": { + "icon": "", + "images": [] + }, + "chuck": { + "icon": "", + "images": [] + }, + "chucknorris": { + "icon": "https://community.chocolatey.org/content/packageimages/chucknorris.0.6.png", + "images": [] + }, + "chutzpah": { + "icon": "https://community.chocolatey.org/content/packageimages/Chutzpah.4.4.8.png", + "images": [] + }, + "ci-cd-assets-vscode": { + "icon": "https://community.chocolatey.org/content/packageimages/ci-cd-assets-vscode.0.5.0.png", + "images": [] + }, + "cica": { + "icon": "", + "images": [] + }, + "cider": { + "icon": "https://community.chocolatey.org/content/packageimages/cider.1.6.0.png", + "images": [] + }, + "cider-nightly": { + "icon": "", + "images": [] + }, + "cinny": { + "icon": "", + "images": [] + }, + "circleci-cli": { + "icon": "", + "images": [] + }, + "circuitdiagram": { + "icon": "", + "images": [] + }, + "cisco-proximity": { + "icon": "https://community.chocolatey.org/content/packageimages/cisco-proximity.3.0.8.png", + "images": [] + }, + "ciscowebexmeetings": { + "icon": "https://community.chocolatey.org/content/packageimages/webex-meetings.44.4.0.159.png", + "images": [] + }, + "citrix-receiver": { + "icon": "https://community.chocolatey.org/content/packageimages/citrix-receiver.4.12.png", + "images": [] + }, + "citrix-sharefile-outlook": { + "icon": "", + "images": [] + }, + "citrix-sharefile-sync": { + "icon": "https://community.chocolatey.org/content/packageimages/citrix-sharefile-sync.3.24.106.0.png", + "images": [] + }, + "citrix-workspace": { + "icon": "https://imgur.com/a/rrJMWst", + "images": [] + }, + "citrix-workspace-ltsr": { + "icon": "https://community.chocolatey.org/content/packageimages/citrix-workspace-ltsr.22.3.2000.2105.png", + "images": [] + }, + "citrix-xenserver-sdk": { + "icon": "https://community.chocolatey.org/content/packageimages/citrix-xenserver-sdk.6.2.0.png", + "images": [] + }, + "citycraftlauncher": { + "icon": "", + "images": [] + }, + "civet": { + "icon": "", + "images": [] + }, + "civo": { + "icon": "", + "images": [] + }, + "civo-cli": { + "icon": "https://community.chocolatey.org/content/packageimages/civo-cli.1.0.48.png", + "images": [] + }, + "cksdev11": { + "icon": "", + "images": [] + }, + "cksdevserver": { + "icon": "", + "images": [] + }, + "clamav": { + "icon": "https://upload.wikimedia.org/wikipedia/en/thumb/6/60/New_ClamAV_Logo.svg/1200px-New_ClamAV_Logo.svg.png", + "images": [] + }, + "clamsentinel": { + "icon": "https://community.chocolatey.org/content/packageimages/clamsentinel.1.22.png", + "images": [] + }, + "clamwin": { + "icon": "https://community.chocolatey.org/content/packageimages/clamwin.0.103.2.1.png", + "images": [] + }, + "clan": { + "icon": "", + "images": [] + }, + "clangd": { + "icon": "", + "images": [] + }, + "clarinet": { + "icon": "", + "images": [] + }, + "clash": { + "icon": "", + "images": [] + }, + "clash-for-windows": { + "icon": "https://community.chocolatey.org/content/packageimages/clash-for-windows.0.20.2.png", + "images": [] + }, + "clash-meta": { + "icon": "", + "images": [] + }, + "clash-mini": { + "icon": "", + "images": [] + }, + "clash-of-clans": { + "icon": "", + "images": [] + }, + "clash-royale": { + "icon": "", + "images": [] + }, + "clashforwindows": { + "icon": "https://community.chocolatey.org/content/packageimages/clash-for-windows.0.20.2.png", + "images": [] + }, + "clashverge": { + "icon": "", + "images": [] + }, + "clashy": { + "icon": "", + "images": [] + }, + "classic": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/5/57/Geogebra.svg/240px-Geogebra.svg.png", + "images": [] + }, + "classic-5": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/5/57/Geogebra.svg/240px-Geogebra.svg.png", + "images": [] + }, + "classic-shell": { + "icon": "https://community.chocolatey.org/content/packageimages/classic-shell.4.3.1.20180405.png", + "images": [] + }, + "classiccontext": { + "icon": "", + "images": [] + }, + "classicftp": { + "icon": "", + "images": [] + }, + "classicgenerator": { + "icon": "", + "images": [] + }, + "classicshell": { + "icon": "", + "images": [ + "https://i.postimg.cc/mZCMz7yz/startmenu3.png" + ] + }, + "classified-ads": { + "icon": "https://community.chocolatey.org/content/packageimages/classified-ads.0.13.png", + "images": [] + }, + "classin": { + "icon": "", + "images": [] + }, + "classroomassistant": { + "icon": "", + "images": [] + }, + "classyshark": { + "icon": "https://community.chocolatey.org/content/packageimages/classyshark.8.2.png", + "images": [] + }, + "clavier-plus": { + "icon": "", + "images": [] + }, + "clawpdf": { + "icon": "", + "images": [] + }, + "claws-mail": { + "icon": "", + "images": [] + }, + "clawsmail": { + "icon": "", + "images": [] + }, + "clcl": { + "icon": "https://community.chocolatey.org/content/packageimages/clcl.portable.2.0.3.png", + "images": [] + }, + "cleanmgr-plus": { + "icon": "https://community.chocolatey.org/content/packageimages/cleanmgr-plus.1.50.1300.png", + "images": [] + }, + "cleanmgrplus": { + "icon": "", + "images": [] + }, + "cleanup": { + "icon": "https://community.chocolatey.org/content/packageimages/cleanup.4.5.2.20190522.png", + "images": [] + }, + "clearcomponentcache": { + "icon": "", + "images": [] + }, + "clementine": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/d/d3/Clementine_logo.svg/1200px-Clementine_logo.svg.png", + "images": [] + }, + "clever-tools": { + "icon": "", + "images": [] + }, + "cli": { + "icon": "", + "images": [] + }, + "cli-preview": { + "icon": "", + "images": [] + }, + "click-pcl": { + "icon": "https://community.chocolatey.org/content/packageimages/click-pcl.2.40.0000.png", + "images": [] + }, + "clickshare-desktop": { + "icon": "https://community.chocolatey.org/content/packageimages/clickshare-desktop.4.27.2.4.png", + "images": [] + }, + "clickup": { + "icon": "https://clickup.com/landing/images/for-se-page/clickup.png", + "images": [ + "https://clickup.com/assets/home-test/projects.png", + "https://clickup.com/assets/home-test/collaborate.png" + ] + }, + "client": { + "icon": "", + "images": [] + }, + "clingo": { + "icon": "", + "images": [] + }, + "clink": { + "icon": "https://community.chocolatey.org/content/packageimages/clink.0.4.9.png", + "images": [] + }, + "clink-completions": { + "icon": "", + "images": [] + }, + "clink-flex-prompt": { + "icon": "", + "images": [] + }, + "clink-maintained": { + "icon": "", + "images": [] + }, + "clion": { + "icon": "https://resources.jetbrains.com/storage/products/clion/img/meta/clion_logo_300x300.png", + "images": [] + }, + "clion-eap": { + "icon": "https://resources.jetbrains.com/storage/products/clion/img/meta/clion_logo_300x300.png", + "images": [] + }, + "clion-ide": { + "icon": "https://community.chocolatey.org/content/packageimages/clion-ide.2022.3.2.png", + "images": [] + }, + "clipboard": { + "icon": "", + "images": [] + }, + "clipboardfusion": { + "icon": "", + "images": [ + "https://i.postimg.cc/Jnyh9s0B/image.png", + "https://i.postimg.cc/Vvnkk2jf/image.png", + "https://i.postimg.cc/fW9LCS1G/image.png", + "https://i.postimg.cc/m2Wr52st/image.png", + "https://i.postimg.cc/kXN533Jw/image.png", + "https://i.postimg.cc/vZQZGqDy/image.png" + ] + }, + "clipboardic": { + "icon": "https://community.chocolatey.org/content/packageimages/clipboardic.1.15.png", + "images": [ + "https://i.postimg.cc/Vvz4p5Dz/image.png" + ] + }, + "clipboardsync": { + "icon": "", + "images": [] + }, + "clipcache": { + "icon": "", + "images": [] + }, + "clipcc": { + "icon": "", + "images": [] + }, + "clipcc-beta": { + "icon": "", + "images": [] + }, + "clipclip": { + "icon": "", + "images": [] + }, + "clipgrab": { + "icon": "https://community.chocolatey.org/content/packageimages/clipgrab.3.9.7.png", + "images": [] + }, + "clipify": { + "icon": "", + "images": [] + }, + "clipjump": { + "icon": "https://community.chocolatey.org/content/packageimages/clipjump.12.5.png", + "images": [] + }, + "clipnest": { + "icon": "", + "images": [] + }, + "clippo": { + "icon": "", + "images": [] + }, + "clips": { + "icon": "", + "images": [] + }, + "clipstudio-modeler": { + "icon": "https://community.chocolatey.org/content/packageimages/clipstudio-modeler.1.10.13.png", + "images": [] + }, + "clipstudio-paint": { + "icon": "https://community.chocolatey.org/content/packageimages/clipstudio-paint.1.13.2.png", + "images": [] + }, + "clipto": { + "icon": "https://community.chocolatey.org/content/packageimages/clipto.install.7.2.17.png", + "images": [] + }, + "clipto-pro": { + "icon": "", + "images": [] + }, + "clipx": { + "icon": "", + "images": [] + }, + "clipx-beta": { + "icon": "", + "images": [] + }, + "clisp": { + "icon": "https://community.chocolatey.org/content/packageimages/clisp.2.49.png", + "images": [] + }, + "cloak": { + "icon": "", + "images": [] + }, + "cloc": { + "icon": "https://community.chocolatey.org/content/packageimages/CLOC.1.96.png", + "images": [] + }, + "clockify": { + "icon": "https://community.chocolatey.org/content/packageimages/clockify.2.0.2.png", + "images": [] + }, + "clockres": { + "icon": "", + "images": [] + }, + "clojure-clr": { + "icon": "", + "images": [] + }, + "clonespy": { + "icon": "https://community.chocolatey.org/content/packageimages/clonespy.3.43.png", + "images": [] + }, + "closethedoor": { + "icon": "https://community.chocolatey.org/content/packageimages/CloseTheDoor.0.2.1.1.png", + "images": [] + }, + "cloud-nuke": { + "icon": "", + "images": [] + }, + "cloud-sql-proxy": { + "icon": "", + "images": [] + }, + "cloudapp": { + "icon": "", + "images": [] + }, + "cloudbaseinit": { + "icon": "", + "images": [] + }, + "cloudberrydrive": { + "icon": "https://community.chocolatey.org/content/packageimages/cloudberrydrive.3.2.0.2.png", + "images": [] + }, + "cloudberrydrive-desktop": { + "icon": "", + "images": [] + }, + "cloudberryexplorer-azurestorage": { + "icon": "https://community.chocolatey.org/content/packageimages/CloudBerryExplorer.AzureStorage.3.1.0.17.png", + "images": [] + }, + "cloudberryexplorer-googlestorage": { + "icon": "https://community.chocolatey.org/content/packageimages/CloudBerryExplorer.GoogleStorage.3.6.0.3.png", + "images": [] + }, + "cloudberryexplorer-s3": { + "icon": "https://community.chocolatey.org/content/packageimages/CloudBerryExplorer.S3.5.0.0.29.png", + "images": [] + }, + "cloudcompare": { + "icon": "", + "images": [] + }, + "cloudcontinuityagent": { + "icon": "", + "images": [] + }, + "cloudflared": { + "icon": "", + "images": [] + }, + "cloudflarespeedtest": { + "icon": "", + "images": [] + }, + "cloudformation-guard": { + "icon": "", + "images": [] + }, + "cloudfoundry-cli": { + "icon": "https://community.chocolatey.org/content/packageimages/cloudfoundry-cli.8.6.0.png", + "images": [] + }, + "cloudmusic": { + "icon": "", + "images": [] + }, + "cloudoman-snapshottercmd": { + "icon": "", + "images": [] + }, + "cloudsdk": { + "icon": "", + "images": [] + }, + "cloudshow": { + "icon": "", + "images": [] + }, + "cloudstation": { + "icon": "https://community.chocolatey.org/content/packageimages/cloudstation.4.3.3.4469.png", + "images": [] + }, + "clover": { + "icon": "https://community.chocolatey.org/content/packageimages/Clover.3.2.3.png", + "images": [] + }, + "clownfishvoicechanger": { + "icon": "", + "images": [] + }, + "clrtypessqlserver-2019": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/2/25/Microsoft_icon.svg/250px-Microsoft_icon.svg.png", + "images": [] + }, + "clumsy": { + "icon": "", + "images": [] + }, + "clustal-omega": { + "icon": "", + "images": [] + }, + "clustalw": { + "icon": "", + "images": [] + }, + "clustalx": { + "icon": "", + "images": [] + }, + "cmail": { + "icon": "", + "images": [] + }, + "cmake": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/e/ef/CMake_logo.svg/1200px-CMake_logo.svg.png", + "images": [] + }, + "cmaptools": { + "icon": "https://community.chocolatey.org/content/packageimages/cmaptools.6.03.01.1.png", + "images": [] + }, + "cmcollctr": { + "icon": "https://community.chocolatey.org/content/packageimages/cmcollctr.1.0.0.12.png", + "images": [] + }, + "cmdaliases": { + "icon": "", + "images": [] + }, + "cmder": { + "icon": "", + "images": [] + }, + "cmder-full": { + "icon": "", + "images": [] + }, + "cmdermini": { + "icon": "", + "images": [] + }, + "cmdhere": { + "icon": "https://community.chocolatey.org/content/packageimages/cmdhere.0.0.1.png", + "images": [] + }, + "cmdow": { + "icon": "", + "images": [] + }, + "cmdutils": { + "icon": "https://community.chocolatey.org/content/packageimages/cmdutils.1.5.png", + "images": [] + }, + "cmsupportcenter": { + "icon": "https://community.chocolatey.org/content/packageimages/CMSupportCenter.5.0.7958.20190201.png", + "images": [] + }, + "cnconline": { + "icon": "", + "images": [] + }, + "cnkiexpress": { + "icon": "", + "images": [] + }, + "cnote": { + "icon": "", + "images": [] + }, + "cntlm": { + "icon": "https://community.chocolatey.org/content/packageimages/Cntlm.0.92.3.2.png", + "images": [] + }, + "coapcli": { + "icon": "", + "images": [] + }, + "coapp": { + "icon": "", + "images": [] + }, + "cobalt": { + "icon": "", + "images": [] + }, + "cobian-backup": { + "icon": "", + "images": [] + }, + "cockatrice": { + "icon": "https://community.chocolatey.org/content/packageimages/cockatrice.2016.05.06.png", + "images": [] + }, + "cockroachdb": { + "icon": "", + "images": [] + }, + "cocosdashboard": { + "icon": "", + "images": [] + }, + "cocuun": { + "icon": "https://community.chocolatey.org/content/packageimages/cocuun.2.23.2.0.png", + "images": [] + }, + "codac": { + "icon": "", + "images": [] + }, + "code-minimap": { + "icon": "", + "images": [] + }, + "code-notes": { + "icon": "", + "images": [] + }, + "code-radio-cli": { + "icon": "", + "images": [] + }, + "codeauditor": { + "icon": "", + "images": [] + }, + "codeblocks": { + "icon": "https://www.codeblocks.org/images/logo160.png", + "images": [ + "https://windows-cdn.softpedia.com/screenshots/Code-Blocks_4.png", + "https://www.hellocodies.com/wp-content/uploads/2018/11/Build-and-Run.png" + ] + }, + "codeblocks-mingw": { + "icon": "", + "images": [] + }, + "codecontracts": { + "icon": "https://community.chocolatey.org/content/packageimages/codecontracts.1.9.10714.2.png", + "images": [] + }, + "codecov": { + "icon": "https://community.chocolatey.org/content/packageimages/codecov.1.13.0.png", + "images": [] + }, + "codelite": { + "icon": "", + "images": [] + }, + "codemaid": { + "icon": "https://community.chocolatey.org/content/packageimages/codemaid.12.0.300.png", + "images": [] + }, + "codeowners-validator": { + "icon": "", + "images": [] + }, + "codeql": { + "icon": "https://community.chocolatey.org/content/packageimages/codeql.2.11.1.png", + "images": [] + }, + "coder": { + "icon": "", + "images": [] + }, + "codetrack": { + "icon": "", + "images": [] + }, + "codex": { + "icon": "", + "images": [] + }, + "coffee": { + "icon": "", + "images": [] + }, + "coffeebean": { + "icon": "", + "images": [] + }, + "coffeescript": { + "icon": "", + "images": [] + }, + "colemak": { + "icon": "", + "images": [] + }, + "colibri": { + "icon": "", + "images": [] + }, + "collapsesolution": { + "icon": "", + "images": [] + }, + "collision": { + "icon": "", + "images": [] + }, + "colobot": { + "icon": "", + "images": [] + }, + "colon": { + "icon": "", + "images": [] + }, + "color-cop": { + "icon": "", + "images": [] + }, + "color-quantizer": { + "icon": "https://community.chocolatey.org/content/packageimages/color-quantizer.0.7.4.4.png", + "images": [] + }, + "color-sustainer": { + "icon": "", + "images": [] + }, + "colorcat": { + "icon": "", + "images": [] + }, + "colorconsole": { + "icon": "https://community.chocolatey.org/content/packageimages/colorconsole.2.51.png", + "images": [] + }, + "colorcontrol": { + "icon": "", + "images": [] + }, + "colorcop": { + "icon": "https://community.chocolatey.org/content/packageimages/colorcop.5.4.3.20130420.png", + "images": [] + }, + "colorkraken": { + "icon": "", + "images": [] + }, + "colormania": { + "icon": "https://community.chocolatey.org/content/packageimages/colormania.12.1.png", + "images": [] + }, + "colorpaletteeditor": { + "icon": "", + "images": [] + }, + "colorpic": { + "icon": "https://community.chocolatey.org/content/packageimages/ColorPic.4.1.png", + "images": [] + }, + "colorpicker": { + "icon": "", + "images": [] + }, + "colors": { + "icon": "", + "images": [] + }, + "colortool": { + "icon": "", + "images": [] + }, + "colour-contrast-analyser": { + "icon": "https://community.chocolatey.org/content/packageimages/colour-contrast-analyser.3.2.0.png", + "images": [] + }, + "com0com": { + "icon": "https://community.chocolatey.org/content/packageimages/com0com.3.0.0.png", + "images": [] + }, + "com2tcp": { + "icon": "", + "images": [] + }, + "combofix": { + "icon": "https://community.chocolatey.org/content/packageimages/combofix.19.11.04.01.png", + "images": [] + }, + "comfortclipboardpro": { + "icon": "https://community.chocolatey.org/content/packageimages/comfortclipboardpro.9.5.0.png", + "images": [] + }, + "comic-collector": { + "icon": "https://community.chocolatey.org/content/packageimages/comic-collector.23.3.2.png", + "images": [] + }, + "comic-dl": { + "icon": "https://community.chocolatey.org/content/packageimages/comic-dl.2023.01.08.2.png", + "images": [] + }, + "comicrack": { + "icon": "", + "images": [] + }, + "comicrackce-nightly": { + "icon": "https://raw.githubusercontent.com/maforget/ComicRackCE/master/ComicRack/Resources/ComicRackApp256.png", + "images": [] + }, + "comicrack-community-edition": { + "icon": "https://images.freeimages.com/fic/images/icons/2804/plex/512/comicrack.png", + "images": [] + }, + "comicreader-plex": { + "icon": "", + "images": [] + }, + "commandbox": { + "icon": "https://community.chocolatey.org/content/packageimages/commandbox.1.0.0.png", + "images": [] + }, + "commandconfigure": { + "icon": "", + "images": [] + }, + "commander": { + "icon": "", + "images": [] + }, + "commandtaskrunner": { + "icon": "", + "images": [] + }, + "commandupdate": { + "icon": "", + "images": [] + }, + "commandupdate-universal": { + "icon": "", + "images": [] + }, + "commandwindowhere": { + "icon": "", + "images": [] + }, + "commentremover": { + "icon": "", + "images": [] + }, + "commit": { + "icon": "", + "images": [] + }, + "commitmonitor": { + "icon": "https://community.chocolatey.org/content/packageimages/commitmonitor.1.11.2.1123.png", + "images": [] + }, + "communicator": { + "icon": "", + "images": [] + }, + "community": { + "icon": "", + "images": [] + }, + "comodo-cocc": { + "icon": "https://community.chocolatey.org/content/packageimages/comodo-cocc.6.17.11191.18031.png", + "images": [] + }, + "comodo-remote": { + "icon": "https://community.chocolatey.org/content/packageimages/comodo-remote.6.17.11326.18031.png", + "images": [] + }, + "compact-timer": { + "icon": "", + "images": [] + }, + "compactgui": { + "icon": "https://i.imgur.com/NHhZtxp.png", + "images": [ + "https://i.imgur.com/VsswHJ2.png", + "https://i.imgur.com/9CcHxub.png", + "https://i.imgur.com/HavsEnA.png", + "https://i.imgur.com/a5epFFP.png" + ] + }, + "compactor": { + "icon": "https://community.chocolatey.org/content/packageimages/compactor.0.10.1.png", + "images": [] + }, + "companion": { + "icon": "", + "images": [] + }, + "compareit": { + "icon": "https://community.chocolatey.org/content/packageimages/compareit.4.2.0.png", + "images": [] + }, + "compass": { + "icon": "", + "images": [] + }, + "compass-community": { + "icon": "", + "images": [] + }, + "compass-full": { + "icon": "https://unigeticons.meowcat285.com/mongodb-compass-logo-stable.png", + "images": [ + "https://raw.githubusercontent.com/mongodb-js/compass/main/packages/compass/compass-screenshot.png" + ] + }, + "compass-isolated": { + "icon": "", + "images": [] + }, + "compass-readonly": { + "icon": "", + "images": [] + }, + "compassion": { + "icon": "https://community.chocolatey.org/content/packageimages/compassion.1.26.20221112.png", + "images": [] + }, + "compatibility-manager": { + "icon": "", + "images": [] + }, + "compdf-console": { + "icon": "https://community.chocolatey.org/content/packageimages/compdf-console.1.07.png", + "images": [] + }, + "composegenerator": { + "icon": "", + "images": [] + }, + "composer": { + "icon": "https://community.chocolatey.org/content/packageimages/composer.6.3.0.png", + "images": [] + }, + "compton": { + "icon": "https://community.chocolatey.org/content/packageimages/compton.portable.1.51.png", + "images": [] + }, + "compute-a-fan": { + "icon": "", + "images": [] + }, + "conan": { + "icon": "", + "images": [] + }, + "concert-env": { + "icon": "", + "images": [] + }, + "concfg": { + "icon": "", + "images": [] + }, + "concourse": { + "icon": "https://community.chocolatey.org/content/packageimages/concourse.5.8.0.png", + "images": [] + }, + "concourse-fly": { + "icon": "", + "images": [] + }, + "conemu": { + "icon": "https://community.chocolatey.org/content/packageimages/ConEmu.22.12.18.0.png", + "images": [] + }, + "conemu-color-themes": { + "icon": "", + "images": [] + }, + "confd": { + "icon": "", + "images": [] + }, + "confide": { + "icon": "https://community.chocolatey.org/content/packageimages/confide.1.10.2.0.png", + "images": [] + }, + "config-disablebeep": { + "icon": "", + "images": [] + }, + "configcat": { + "icon": "https://community.chocolatey.org/content/packageimages/configcat.1.7.1.png", + "images": [] + }, + "configuration-powershell": { + "icon": "https://community.chocolatey.org/content/packageimages/configuration.powershell.1.5.1.png", + "images": [] + }, + "conftest": { + "icon": "", + "images": [] + }, + "confuser": { + "icon": "https://community.chocolatey.org/content/packageimages/confuser.1.9.png", + "images": [] + }, + "confuser-ex": { + "icon": "", + "images": [] + }, + "confuserex": { + "icon": "https://community.chocolatey.org/content/packageimages/confuserex.portable.1.6.0.png", + "images": [] + }, + "connect": { + "icon": "https://play-lh.googleusercontent.com/f868E2XQBpfl677hykMnZ4_HlKqrOs0fUhuwy0TC9ZI_PQLn99RtBV2kQ7Z50OtQkw", + "images": [ + "https://i.postimg.cc/y8dkPRcT/14621efe-9306-44f5-ade6-b0eebe217a5f.png" + ] + }, + "connecttunnel": { + "icon": "", + "images": [] + }, + "connexion": { + "icon": "https://community.chocolatey.org/content/packageimages/connexion.3.1.8196.png", + "images": [] + }, + "conroe": { + "icon": "https://community.chocolatey.org/content/packageimages/conroe.install.1.13.png", + "images": [] + }, + "console-devel": { + "icon": "https://community.chocolatey.org/content/packageimages/console-devel.2.00.148.png", + "images": [] + }, + "console2": { + "icon": "", + "images": [] + }, + "consoleclassix": { + "icon": "https://community.chocolatey.org/content/packageimages/consoleclassix.4.30.0.png", + "images": [] + }, + "consolez": { + "icon": "https://community.chocolatey.org/content/packageimages/ConsoleZ.1.19.0.19104.png", + "images": [] + }, + "consolez-settings": { + "icon": "https://community.chocolatey.org/content/packageimages/ConsoleZ.Settings.1.0.0.20141027.png", + "images": [] + }, + "consolez-withpin": { + "icon": "https://community.chocolatey.org/content/packageimages/ConsoleZ.WithPin.1.12.0.14282.png", + "images": [] + }, + "consul": { + "icon": "", + "images": [] + }, + "consul-template": { + "icon": "", + "images": [] + }, + "containerd": { + "icon": "", + "images": [] + }, + "contasimple-desktop": { + "icon": "", + "images": [] + }, + "contasimpledesktop": { + "icon": "", + "images": [] + }, + "contentsync": { + "icon": "", + "images": [] + }, + "context-menu-manager": { + "icon": "", + "images": [] + }, + "contextconsole": { + "icon": "", + "images": [] + }, + "contextmenumanager": { + "icon": "", + "images": [] + }, + "contig": { + "icon": "", + "images": [] + }, + "continuainit": { + "icon": "", + "images": [] + }, + "contosocookbook": { + "icon": "", + "images": [] + }, + "contour": { + "icon": "", + "images": [] + }, + "controlcenter": { + "icon": "https://i.postimg.cc/CLHZ61DY/controlcenter_202512_128.png", + "images": [] + }, + "controller": { + "icon": "", + "images": [] + }, + "controlmymonitor": { + "icon": "https://community.chocolatey.org/content/packageimages/controlmymonitor.1.36.png", + "images": [] + }, + "converse": { + "icon": "", + "images": [] + }, + "converseen": { + "icon": "https://images.sftcdn.net/images/t_app-icon-m/p/2bb1d08a-9a63-11e6-b1e0-00163ec9f5fa/2428479783/converseen-icon.png", + "images": [] + }, + "convert-net": { + "icon": "", + "images": [] + }, + "convertall": { + "icon": "", + "images": [] + }, + "conveyor": { + "icon": "", + "images": [] + }, + "cookiecutter": { + "icon": "", + "images": [] + }, + "coolterm": { + "icon": "https://community.chocolatey.org/content/packageimages/coolterm.2.0.1.png", + "images": [] + }, + "copay": { + "icon": "", + "images": [] + }, + "copilot": { + "icon": "https://i.postimg.cc/5yPpc3Sd/copilot-cli.png", + "images": [ + "https://i.postimg.cc/fW0xMMW3/Header-Image.png", + "https://i.postimg.cc/59Fwff9Q/1-Get-Started-0.png", + "https://i.postimg.cc/ZYyrJJYy/2-MCPsearch-Issues-0.png", + "https://i.postimg.cc/xjbK99jz/3-Change-Color-0.png" + ] + }, + "coppeliasim": { + "icon": "", + "images": [] + }, + "copy-dialog-lunar-lander": { + "icon": "https://community.chocolatey.org/content/packageimages/copy-dialog-lunar-lander.1.1.png", + "images": [] + }, + "copyfilename": { + "icon": "https://community.chocolatey.org/content/packageimages/copyfilename.2.2.022.20160824.png", + "images": [] + }, + "copyq": { + "icon": "https://community.chocolatey.org/content/packageimages/copyq.6.4.0.png", + "images": [] + }, + "copytools": { + "icon": "", + "images": [] + }, + "copytranslator": { + "icon": "", + "images": [] + }, + "coq": { + "icon": "https://community.chocolatey.org/content/packageimages/Coq.8.13.1.png", + "images": [] + }, + "coqplatform": { + "icon": "", + "images": [] + }, + "coqplatform-beta": { + "icon": "", + "images": [] + }, + "core": { + "icon": "", + "images": [] + }, + "coredns": { + "icon": "", + "images": [] + }, + "coreftp": { + "icon": "", + "images": [] + }, + "coreinfo": { + "icon": "https://community.chocolatey.org/content/packageimages/coreinfo.3.53.png", + "images": [] + }, + "coreos-butane": { + "icon": "", + "images": [] + }, + "coreprio": { + "icon": "", + "images": [] + }, + "coretemp": { + "icon": "https://community.chocolatey.org/content/packageimages/coretemp.1.18.png", + "images": [] + }, + "coreutils": { + "icon": "", + "images": [] + }, + "corkscrew": { + "icon": "", + "images": [] + }, + "cormanlisp": { + "icon": "", + "images": [] + }, + "corretto-11": { + "icon": "", + "images": [ + "https://d2908q01vomqb2.cloudfront.net/ca3512f4dfa95a03169c5a670a4c91a19b3077b4/2018/11/14/Corretto_E-800x400.jpg", + "https://pbs.twimg.com/media/D07IwAyU8AAwhZ_.jpg" + ] + }, + "corretto-17": { + "icon": "", + "images": [ + "https://d2908q01vomqb2.cloudfront.net/ca3512f4dfa95a03169c5a670a4c91a19b3077b4/2018/11/14/Corretto_E-800x400.jpg", + "https://pbs.twimg.com/media/D07IwAyU8AAwhZ_.jpg" + ] + }, + "corretto-18": { + "icon": "", + "images": [ + "https://d2908q01vomqb2.cloudfront.net/ca3512f4dfa95a03169c5a670a4c91a19b3077b4/2018/11/14/Corretto_E-800x400.jpg", + "https://pbs.twimg.com/media/D07IwAyU8AAwhZ_.jpg" + ] + }, + "corretto-19": { + "icon": "", + "images": [ + "https://d2908q01vomqb2.cloudfront.net/ca3512f4dfa95a03169c5a670a4c91a19b3077b4/2018/11/14/Corretto_E-800x400.jpg", + "https://pbs.twimg.com/media/D07IwAyU8AAwhZ_.jpg" + ] + }, + "corretto-8": { + "icon": "", + "images": [ + "https://d2908q01vomqb2.cloudfront.net/ca3512f4dfa95a03169c5a670a4c91a19b3077b4/2018/11/14/Corretto_E-800x400.jpg", + "https://pbs.twimg.com/media/D07IwAyU8AAwhZ_.jpg" + ] + }, + "corretto11jdk": { + "icon": "", + "images": [] + }, + "corretto8jdk": { + "icon": "", + "images": [] + }, + "corretto8jre": { + "icon": "", + "images": [] + }, + "correttojdk": { + "icon": "", + "images": [] + }, + "corsixth": { + "icon": "", + "images": [ + "https://i.postimg.cc/fTF6Vt4w/image.png", + "https://i.postimg.cc/C526ntQv/image.png", + "https://i.postimg.cc/9FVBJcGG/image.png", + "https://i.postimg.cc/HxXQ9NnZ/image.png", + "https://i.postimg.cc/tJbFSzVX/image.png", + "https://i.postimg.cc/d1w0gNnS/image.png", + "https://i.postimg.cc/yx5s6LXK/image.png", + "https://i.postimg.cc/XNDVgvMP/image.png", + "https://i.postimg.cc/Y2VHWyYK/image.png" + ] + }, + "corvusskk": { + "icon": "", + "images": [] + }, + "cosbrowser": { + "icon": "", + "images": [] + }, + "coscli": { + "icon": "", + "images": [] + }, + "cosign": { + "icon": "https://community.chocolatey.org/content/packageimages/Cosign.1.3.1.png", + "images": [] + }, + "cosmosdbexplorer": { + "icon": "https://community.chocolatey.org/content/packageimages/cosmosdbexplorer.0.9.5.0.png", + "images": [] + }, + "couchdb": { + "icon": "", + "images": [] + }, + "couchpotato": { + "icon": "https://community.chocolatey.org/content/packageimages/CouchPotato.2012.11.04.1.png", + "images": [] + }, + "countrytraceroute": { + "icon": "https://community.chocolatey.org/content/packageimages/countrytraceroute.1.33.png", + "images": [] + }, + "coursehunt": { + "icon": "", + "images": [] + }, + "coursier": { + "icon": "", + "images": [] + }, + "covenanteyes": { + "icon": "https://community.chocolatey.org/content/packageimages/CovenantEyes.4.5.3.2302.png", + "images": [] + }, + "coverage41c": { + "icon": "", + "images": [] + }, + "covid-19-cases-overview": { + "icon": "", + "images": [] + }, + "cowsay": { + "icon": "", + "images": [] + }, + "coyim": { + "icon": "https://community.chocolatey.org/content/packageimages/coyim.0.4.1.png", + "images": [] + }, + "cozydrive": { + "icon": "", + "images": [] + }, + "cozydrive-beta": { + "icon": "", + "images": [] + }, + "cp210x-vcp-drivers": { + "icon": "https://community.chocolatey.org/content/packageimages/cp210x-vcp-drivers.6.7.6.2130.png", + "images": [] + }, + "cp210x-vcp-drivers-win10": { + "icon": "https://community.chocolatey.org/content/packageimages/cp210x-vcp-drivers-win10.10.1.3.png", + "images": [] + }, + "cpfixit": { + "icon": "https://community.chocolatey.org/content/packageimages/cpfixit.5.0.16772.0.png", + "images": [] + }, + "cpfox": { + "icon": "https://community.chocolatey.org/content/packageimages/cpfox.45.1.2.png", + "images": [] + }, + "cpkeeper": { + "icon": "", + "images": [] + }, + "cpntools": { + "icon": "https://community.chocolatey.org/content/packageimages/cpntools.4.0.1.png", + "images": [] + }, + "cpod": { + "icon": "", + "images": [] + }, + "cpolar": { + "icon": "https://community.chocolatey.org/content/packageimages/cpolar.3.2.82.png", + "images": [] + }, + "cports": { + "icon": "https://community.chocolatey.org/content/packageimages/cports.2.66.png", + "images": [] + }, + "cppcheck": { + "icon": "https://community.chocolatey.org/content/packageimages/cppcheck.2.10.png", + "images": [] + }, + "cprocess": { + "icon": "https://community.chocolatey.org/content/packageimages/cprocess.1.13.png", + "images": [] + }, + "cpu-v": { + "icon": "", + "images": [] + }, + "cpu-z": { + "icon": "https://i.postimg.cc/fWjrdd4c/cpu-z.png", + "images": [ + "https://i.postimg.cc/DwkvZGry/image.png", + "https://i.postimg.cc/TPTTjXNz/image.png", + "https://i.postimg.cc/s2Ksw0tv/image.png", + "https://i.postimg.cc/xCCY732g/image.png", + "https://i.postimg.cc/hj5gqQ4n/image.png", + "https://i.postimg.cc/kGRCMMDb/image.png", + "https://i.postimg.cc/NLhcKhrP/image.png" + ] + }, + "cpu-z-aorus": { + "icon": "https://i.postimg.cc/5NcQhssJ/aorus.png", + "images": [ + "https://i.postimg.cc/3JgR29JD/image.png", + "https://i.postimg.cc/MpqG5Rv3/image.png", + "https://i.postimg.cc/hGGtWB89/image.png", + "https://i.postimg.cc/hjz4v15v/image.png", + "https://i.postimg.cc/mDvLH1vw/image.png", + "https://i.postimg.cc/v8nHdXnS/image.png", + "https://i.postimg.cc/wTdxxJcx/image.png" + ] + }, + "cpu-z-asr": { + "icon": "https://i.postimg.cc/2Srb6VpX/asr.png", + "images": [ + "https://i.postimg.cc/fTFK0zyb/image.png", + "https://i.postimg.cc/9Q7Bd6wY/image.png", + "https://i.postimg.cc/W326PtW5/image.png", + "https://i.postimg.cc/cHX71ZP0/image.png", + "https://i.postimg.cc/J7Y39rbQ/image.png", + "https://i.postimg.cc/YqJ6CdDG/image.png", + "https://i.postimg.cc/Hxs5hRnK/image.png" + ] + }, + "cpu-z-cm": { + "icon": "https://i.postimg.cc/xTKNnLZz/cm.png", + "images": [ + "https://i.postimg.cc/L6Hd0V3P/image.png", + "https://i.postimg.cc/dV1bJtXt/image.png", + "https://i.postimg.cc/8z0qcgQd/image.png", + "https://i.postimg.cc/0QgFGGNb/image.png", + "https://i.postimg.cc/WzTyC2gV/image.png", + "https://i.postimg.cc/BbpzGdBK/image.png", + "https://i.postimg.cc/mZyJMHWg/image.png" + ] + }, + "cpu-z-gbt": { + "icon": "https://i.postimg.cc/6pc7Gtt6/gbt.png", + "images": [ + "https://i.postimg.cc/mZyJMHWg/image.png", + "https://i.postimg.cc/vTYPX0wH/image.png", + "https://i.postimg.cc/1XvvdDy0/image.png", + "https://i.postimg.cc/jqc3CYyW/image.png", + "https://i.postimg.cc/9Ff87gBL/image.png", + "https://i.postimg.cc/Z5GVXbzQ/image.png", + "https://i.postimg.cc/jjyZbpsS/image.png" + ] + }, + "cpu-z-msi": { + "icon": "https://i.postimg.cc/FKKYy8Hy/msi.png", + "images": [ + "https://i.postimg.cc/L8xmVWdh/image.png", + "https://i.postimg.cc/cJ60kcZh/image.png", + "https://i.postimg.cc/wBPHCsjp/image.png", + "https://i.postimg.cc/bJt8pNZ2/image.png", + "https://i.postimg.cc/bNTPz5wL/image.png", + "https://i.postimg.cc/qvDdKCn3/image.png", + "https://i.postimg.cc/cJKGB4M5/image.png" + ] + }, + "cpu-z-phantom": { + "icon": "https://i.postimg.cc/MTMX4BRX/phantom.png", + "images": [ + "https://i.postimg.cc/FzwL1Kp5/image.png", + "https://i.postimg.cc/qvVKTzg2/image.png", + "https://i.postimg.cc/d0nZr669/image.png", + "https://i.postimg.cc/1ttnHFY1/image.png", + "https://i.postimg.cc/yx3JqHHf/image.png", + "https://i.postimg.cc/JtwsM27R/image.png", + "https://i.postimg.cc/mZPVZ1Zn/image.png" + ] + }, + "cpu-z-rog": { + "icon": "https://i.postimg.cc/hG3fpsXH/rog.png", + "images": [ + "https://i.postimg.cc/L4gBFdNK/image.png", + "https://i.postimg.cc/CLjGdj3c/image.png", + "https://i.postimg.cc/GmKvxbhY/image.png", + "https://i.postimg.cc/bvvk64s5/image.png", + "https://i.postimg.cc/tTZPbPdt/image.png", + "https://i.postimg.cc/90y7RhnD/image.png", + "https://i.postimg.cc/65NRs88n/image.png" + ] + }, + "cpu-z-taichi": { + "icon": "https://i.postimg.cc/SsBjpK7d/taichi.png", + "images": [ + "https://i.postimg.cc/0yyzxDPM/image.png", + "https://i.postimg.cc/DzWm4hW7/image.png", + "https://i.postimg.cc/bvKrQ5bk/image.png", + "https://i.postimg.cc/XJdJxgch/image.png", + "https://i.postimg.cc/qqG7HMFx/image.png", + "https://i.postimg.cc/y8x82Ky0/image.png", + "https://i.postimg.cc/t4c4jcBw/image.png" + ] + }, + "cpufetch": { + "icon": "https://res.cloudinary.com/canonical/image/fetch/f_auto,q_auto,fl_sanitize,w_120/https%3A%2F%2Fdashboard.snapcraft.io%2Fsite_media%2Fappmedia%2F2021%2F04%2Ficon_YRxn9Gn.png", + "images": [ + "https://i.postimg.cc/cC1SY7Df/image.png", + "https://i.postimg.cc/rwRLSw9Z/image.png", + "https://i.postimg.cc/prLwyWTZ/image.png" + ] + }, + "cpugrabex": { + "icon": "", + "images": [] + }, + "craft": { + "icon": "", + "images": [] + }, + "crane": { + "icon": "https://community.chocolatey.org/content/packageimages/crane.0.2.0.15.png", + "images": [] + }, + "crankshaft": { + "icon": "", + "images": [] + }, + "crashplan": { + "icon": "https://community.chocolatey.org/content/packageimages/CrashPlan.4.8.3.png", + "images": [] + }, + "crashplanpro": { + "icon": "https://community.chocolatey.org/content/packageimages/CrashPlanPRO.4.6.0.png", + "images": [] + }, + "crawl": { + "icon": "https://community.chocolatey.org/content/packageimages/crawl.0.22.1.png", + "images": [] + }, + "crazybump": { + "icon": "", + "images": [] + }, + "crc": { + "icon": "", + "images": [] + }, + "crd2pulumi": { + "icon": "", + "images": [] + }, + "crealogix-paymaker-office": { + "icon": "https://community.chocolatey.org/content/packageimages/crealogix-paymaker-office.5.0.8.1.png", + "images": [] + }, + "create-synchronicity": { + "icon": "https://community.chocolatey.org/content/packageimages/create-synchronicity.install.6.0.png", + "images": [] + }, + "create-tauri-app": { + "icon": "", + "images": [] + }, + "createstructure": { + "icon": "", + "images": [] + }, + "creativeapp": { + "icon": "https://d287ku8w5owj51.cloudfront.net/inline/products/23968/6_app_logo.png", + "images": [] + }, + "creativecenter": { + "icon": "", + "images": [] + }, + "creatorstudio": { + "icon": "", + "images": [] + }, + "crescendo": { + "icon": "", + "images": [] + }, + "crewlink": { + "icon": "https://community.chocolatey.org/content/packageimages/crewlink.2.0.1.png", + "images": [] + }, + "cricutdesignspace": { + "icon": "https://community.chocolatey.org/content/packageimages/cricutdesignspace.6.6.121.png", + "images": [] + }, + "croc": { + "icon": "https://community.chocolatey.org/content/packageimages/croc.9.6.3.png", + "images": [] + }, + "cropper": { + "icon": "https://community.chocolatey.org/content/packageimages/cropper.1.9.4.20141123.png", + "images": [] + }, + "cropro": { + "icon": "", + "images": [] + }, + "croscorefonts-font": { + "icon": "https://community.chocolatey.org/content/packageimages/croscorefonts-font.1.31.0.png", + "images": [] + }, + "crossout": { + "icon": "", + "images": [] + }, + "crossover": { + "icon": "", + "images": [] + }, + "crossworks": { + "icon": "", + "images": [] + }, + "crowdinspect": { + "icon": "https://community.chocolatey.org/content/packageimages/crowdinspect.1.5.0.png", + "images": [] + }, + "crowdsec": { + "icon": "https://community.chocolatey.org/content/packageimages/crowdsec.1.4.2.png", + "images": [] + }, + "crowdsec-windows-firewall-bouncer": { + "icon": "https://community.chocolatey.org/content/packageimages/crowdsec-windows-firewall-bouncer.0.0.3.png", + "images": [] + }, + "crowleer": { + "icon": "https://community.chocolatey.org/content/packageimages/crowleer.2.0.png", + "images": [] + }, + "crowtranslate": { + "icon": "https://i.postimg.cc/cJSMxJPy/45773185.png", + "images": [ + "https://i.postimg.cc/28twVd7M/main-1.png" + ] + }, + "crsed": { + "icon": "", + "images": [] + }, + "cru": { + "icon": "", + "images": [] + }, + "crucial-storage-executive": { + "icon": "https://community.chocolatey.org/content/packageimages/crucial-storage-executive.8.07.png", + "images": [] + }, + "cruft": { + "icon": "", + "images": [] + }, + "cruisecontrol-net": { + "icon": "https://community.chocolatey.org/content/packageimages/cruisecontrol.net.1.8.5.0.png", + "images": [] + }, + "crunchy-cli": { + "icon": "", + "images": [] + }, + "crushee": { + "icon": "https://community.chocolatey.org/content/packageimages/crushee.install.2.4.5.png", + "images": [] + }, + "cryptcp": { + "icon": "https://community.chocolatey.org/content/packageimages/cryptcp.5.0.10804.png", + "images": [] + }, + "crypter": { + "icon": "", + "images": [] + }, + "crypto-notepad": { + "icon": "https://community.chocolatey.org/content/packageimages/crypto-notepad.1.7.3.png", + "images": [] + }, + "cryptoarm": { + "icon": "https://community.chocolatey.org/content/packageimages/cryptoarm.5.3.0.8941.png", + "images": [] + }, + "cryptoarmgost": { + "icon": "", + "images": [] + }, + "cryptomator": { + "icon": "https://cryptomator.org/presskit/cryptomator-logo.png", + "images": [ + "https://cryptomator.org/presskit/win-screenshot-1.png", + "https://cryptomator.org/presskit/win-screenshot-2.png" + ] + }, + "cryptool1": { + "icon": "", + "images": [] + }, + "cryptopro-pdf": { + "icon": "https://community.chocolatey.org/content/packageimages/cryptopro-pdf.2.0.0811.png", + "images": [] + }, + "cryptopro-ssf": { + "icon": "https://community.chocolatey.org/content/packageimages/cryptopro-ssf.1.0.10908.0.png", + "images": [] + }, + "cryptopro-stunnel": { + "icon": "https://community.chocolatey.org/content/packageimages/cryptopro-stunnel.3.06.3773.0000.png", + "images": [] + }, + "cryptr": { + "icon": "", + "images": [ + "https://i.imgur.com/xXKaOEm.png" + ] + }, + "cryptsync": { + "icon": "https://community.chocolatey.org/content/packageimages/cryptsync.1.4.4.png", + "images": [] + }, + "crystaldiskinfo": { + "icon": "https://tweakers.net/ext/i/2004637378.png", + "images": [ + "https://tweakers.net/ext/i/2004681610.png" + ] + }, + "crystaldiskinfo-kureikeiedition": { + "icon": "https://i.postimg.cc/Cxr9krCK/kureikei.png", + "images": [] + }, + "crystaldiskinfo-shizukuedition": { + "icon": "https://i.postimg.cc/N0yS48bk/shizuku.png", + "images": [] + }, + "crystaldiskmark": { + "icon": "https://i.postimg.cc/NMsCG9zH/cmark-icon.png", + "images": [ + "https://upload.wikimedia.org/wikipedia/commons/5/5b/CrystalDiskMark_8.0.4_x64.png" + ] + }, + "crystaldiskmark-shizukuedition": { + "icon": "https://i.postimg.cc/NMsCG9zH/cmark-icon.png", + "images": [] + }, + "crystalexplorer": { + "icon": "https://community.chocolatey.org/content/packageimages/crystalexplorer.21.5.png", + "images": [] + }, + "crystalreports-for-visualstudio": { + "icon": "https://community.chocolatey.org/content/packageimages/crystalreports-for-visualstudio.13.0.25.3158.png", + "images": [] + }, + "crystalreports2008runtime": { + "icon": "", + "images": [] + }, + "cs-script": { + "icon": "https://community.chocolatey.org/content/packageimages/cs-script.4.6.4.0.png", + "images": [] + }, + "cs-script-core": { + "icon": "https://community.chocolatey.org/content/packageimages/cs-script.core.2.0.0.0.png", + "images": [] + }, + "cs-syntaxer": { + "icon": "https://community.chocolatey.org/content/packageimages/cs-syntaxer.3.1.2.0.png", + "images": [] + }, + "cscope": { + "icon": "", + "images": [] + }, + "csgoaccountchecker": { + "icon": "", + "images": [] + }, + "csound": { + "icon": "", + "images": [] + }, + "cspclean": { + "icon": "", + "images": [] + }, + "csvconverter": { + "icon": "https://community.chocolatey.org/content/packageimages/CSVConverter.3.1.png", + "images": [] + }, + "csved": { + "icon": "", + "images": [] + }, + "csvfileview": { + "icon": "https://community.chocolatey.org/content/packageimages/csvfileview.2.63.png", + "images": [ + "https://i.postimg.cc/yYQnp194/image.png" + ] + }, + "csview": { + "icon": "", + "images": [] + }, + "csvtk": { + "icon": "", + "images": [] + }, + "csvtosql": { + "icon": "", + "images": [] + }, + "ctags": { + "icon": "https://community.chocolatey.org/content/packageimages/ctags.5.8.1.png", + "images": [] + }, + "ctemplar": { + "icon": "https://community.chocolatey.org/content/packageimages/ctemplar.2.5.75.20220817.png", + "images": [] + }, + "ctools": { + "icon": "", + "images": [] + }, + "ctop": { + "icon": "https://community.chocolatey.org/content/packageimages/ctop.0.7.7.png", + "images": [] + }, + "ctre-phoenixframework": { + "icon": "https://community.chocolatey.org/content/packageimages/ctre-phoenixframework.5.21.3.0.png", + "images": [] + }, + "ctrlr": { + "icon": "", + "images": [] + }, + "ctype": { + "icon": "", + "images": [] + }, + "ctypes": { + "icon": "", + "images": [] + }, + "cube": { + "icon": "https://i.imgur.com/bWnk6NQ.png", + "images": [] + }, + "cubeice": { + "icon": "", + "images": [] + }, + "cubepdf": { + "icon": "", + "images": [] + }, + "cubepdfutility": { + "icon": "", + "images": [] + }, + "cubeplatform": { + "icon": "", + "images": [] + }, + "cubicsdr": { + "icon": "", + "images": [] + }, + "cubiomes-viewer": { + "icon": "", + "images": [] + }, + "cuda": { + "icon": "https://community.chocolatey.org/content/packageimages/cuda.12.0.1.52833.png", + "images": [] + }, + "cudatext": { + "icon": "https://community.chocolatey.org/content/packageimages/cudatext.1.178.0.0.png", + "images": [] + }, + "cudatext-beta": { + "icon": "", + "images": [] + }, + "cue": { + "icon": "https://community.chocolatey.org/content/packageimages/cue.3.13.94.png", + "images": [] + }, + "cuemounter": { + "icon": "", + "images": [] + }, + "cuetools": { + "icon": "https://community.chocolatey.org/content/packageimages/cuetools.2.2.3.png", + "images": [] + }, + "cupboard": { + "icon": "", + "images": [] + }, + "cupscale": { + "icon": "", + "images": [] + }, + "cura": { + "icon": "https://raw.githubusercontent.com/bq/Ultimaker-Cura/master/icons/cura-128.png", + "images": [] + }, + "cura-lulzbot": { + "icon": "https://community.chocolatey.org/content/packageimages/cura-lulzbot.3.6.37.png", + "images": [] + }, + "curl": { + "icon": "https://i.postimg.cc/bJW9nGtV/curl-symbol-transparent.png", + "images": [] + }, + "curlie": { + "icon": "", + "images": [] + }, + "currencyconverterpowertoys": { + "icon": "https://i.postimg.cc/v1FNdgnN/icon-white.png", + "images": [ + "https://raw.githubusercontent.com/Advaith3600/PowerToys-Run-Currency-Converter/main/screenshots/screenshot1.png", + "https://raw.githubusercontent.com/Advaith3600/PowerToys-Run-Currency-Converter/main/screenshots/screenshot2.png", + "https://raw.githubusercontent.com/Advaith3600/PowerToys-Run-Currency-Converter/6a630ebc3d44ac482fa823362ab5729be4b2fa92/screenshots/screenshot3.png", + "https://raw.githubusercontent.com/Advaith3600/PowerToys-Run-Currency-Converter/6a630ebc3d44ac482fa823362ab5729be4b2fa92/screenshots/screenshot4.png", + "https://raw.githubusercontent.com/Advaith3600/PowerToys-Run-Currency-Converter/6a630ebc3d44ac482fa823362ab5729be4b2fa92/screenshots/screenshot5.png", + "https://raw.githubusercontent.com/Advaith3600/PowerToys-Run-Currency-Converter/6a630ebc3d44ac482fa823362ab5729be4b2fa92/screenshots/screenshot6.png" + ] + }, + "curse-voice": { + "icon": "", + "images": [] + }, + "curseforge": { + "icon": "https://console-apps.overwolf.com/prod/apps/cchhcaiapeikjbdbpfplgmpobbcdkdaphclbmkbj/assets/c2738f03-c55f-4baa-aa13-9c670b76c3b3.png", + "images": [ + "https://i.imgur.com/81rahEC.png", + "https://i.imgur.com/1JV8HPN.png", + "https://i.imgur.com/WHKHrax.png", + "https://i.imgur.com/90Q2KLk.png" + ] + }, + "cursor-commander": { + "icon": "https://community.chocolatey.org/content/packageimages/cursor-commander.1.0.0.0.png", + "images": [] + }, + "curtains": { + "icon": "https://community.chocolatey.org/content/packageimages/curtains.1.19.1.png", + "images": [] + }, + "customcontroleditor": { + "icon": "", + "images": [] + }, + "customrp": { + "icon": "", + "images": [] + }, + "cutemarked": { + "icon": "https://community.chocolatey.org/content/packageimages/cutemarked.0.11.3.png", + "images": [] + }, + "cutepdf": { + "icon": "https://community.chocolatey.org/content/packageimages/CutePDF.4.0.1.201.png", + "images": [] + }, + "cutepdfwriter": { + "icon": "", + "images": [] + }, + "cutter": { + "icon": "", + "images": [] + }, + "cv4pve-pepper": { + "icon": "", + "images": [] + }, + "cvs": { + "icon": "", + "images": [] + }, + "cvtvt": { + "icon": "", + "images": [] + }, + "cw": { + "icon": "", + "images": [] + }, + "cwcli": { + "icon": "https://community.chocolatey.org/content/packageimages/cwcli.0.2.0.png", + "images": [] + }, + "cwrsync": { + "icon": "", + "images": [] + }, + "cyberchef": { + "icon": "https://community.chocolatey.org/content/packageimages/cyberchef.9.55.0.png", + "images": [] + }, + "cyberduck": { + "icon": "https://community.chocolatey.org/content/packageimages/cyberduck.install.6.4.6.27773.png", + "images": [] + }, + "cyberfox": { + "icon": "https://community.chocolatey.org/content/packageimages/cyberfox.52.9.1.png", + "images": [] + }, + "cyberprotecthomeoffice": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/8/86/Acronis_True_Image_2015_icon.png", + "images": [ + "https://staticfiles.acronis.com/images/content/f086c44f7bcffdc3be4da4d39d4bf28b.jpg", + "https://kb.acronis.com/system/files/content/2021/09/69472/69472_01.png", + "https://i.pcmag.com/imagery/reviews/04JiWbx5aUrJ5O6dTdfkFaH-23.fit_lim.size_1050x.png", + "https://kb.acronis.com/system/files/content/2021/09/69477/69477_01.png" + ] + }, + "cygwin": { + "icon": "https://community.chocolatey.org/content/packageimages/Cygwin.3.4.6.png", + "images": [] + }, + "cyohash": { + "icon": "", + "images": [] + }, + "cypress": { + "icon": "https://community.chocolatey.org/content/packageimages/cypress.12.6.0.png", + "images": [] + }, + "czkawka": { + "icon": "", + "images": [] + }, + "czkawka-gui": { + "icon": "", + "images": [] + }, + "d-link-network-assistant": { + "icon": "https://community.chocolatey.org/content/packageimages/d-link-network-assistant.2.0.2.4.png", + "images": [] + }, + "d2": { + "icon": "", + "images": [] + }, + "d2codingfont": { + "icon": "https://community.chocolatey.org/content/packageimages/d2codingfont.1.3.2.png", + "images": [] + }, + "d4t-addons-accurate-music": { + "icon": "", + "images": [] + }, + "dacfx-18": { + "icon": "", + "images": [] + }, + "dacia-media-nav-toolbox": { + "icon": "https://community.chocolatey.org/content/packageimages/dacia-media-nav-toolbox.3.18.5.740218.png", + "images": [] + }, + "dadroitjsonviewer": { + "icon": "", + "images": [] + }, + "dafny": { + "icon": "", + "images": [] + }, + "dagger": { + "icon": "https://community.chocolatey.org/content/packageimages/dagger.0.3.13.png", + "images": [] + }, + "dagger-cue": { + "icon": "https://community.chocolatey.org/content/packageimages/dagger-cue.0.2.232.png", + "images": [] + }, + "dahua-web-plugin": { + "icon": "https://community.chocolatey.org/content/packageimages/dahua-web-plugin.3.1.0.486876.png", + "images": [] + }, + "dangerzone": { + "icon": "", + "images": [] + }, + "dankerino": { + "icon": "https://community.chocolatey.org/content/packageimages/dankerino.2.3.6.20221201.png", + "images": [] + }, + "danser-go": { + "icon": "", + "images": [] + }, + "dapr": { + "icon": "", + "images": [] + }, + "dapr-cli": { + "icon": "", + "images": [] + }, + "dar": { + "icon": "https://community.chocolatey.org/content/packageimages/dar.2.6.5.png", + "images": [] + }, + "dark": { + "icon": "", + "images": [] + }, + "darkoberon": { + "icon": "https://community.chocolatey.org/content/packageimages/DarkOberon.1.0.2.png", + "images": [] + }, + "darksoulsmapviewer": { + "icon": "", + "images": [] + }, + "darkswitcher": { + "icon": "", + "images": [] + }, + "darktable": { + "icon": "https://github.com/darktable-org/darktable/blob/master/data/pixmaps/256x256/darktable.png", + "images": [] + }, + "dart": { + "icon": "", + "images": [] + }, + "dart-sass-embedded": { + "icon": "", + "images": [] + }, + "dart-sdk": { + "icon": "https://community.chocolatey.org/content/packageimages/dart-sdk.2.19.2.png", + "images": [] + }, + "darteditor": { + "icon": "", + "images": [] + }, + "dartium": { + "icon": "", + "images": [] + }, + "dartium-content-shell": { + "icon": "", + "images": [] + }, + "dasel": { + "icon": "", + "images": [] + }, + "dashboard-beta": { + "icon": "", + "images": [] + }, + "dashlane": { + "icon": "https://d38muu3h4xeqr1.cloudfront.net/website/static/DG-8114/images/icon_og_400x400.png", + "images": [] + }, + "dashlane-chrome": { + "icon": "https://community.chocolatey.org/content/packageimages/dashlane-chrome.1.0.0.png", + "images": [] + }, + "dashy": { + "icon": "", + "images": [] + }, + "daskeyboard": { + "icon": "", + "images": [] + }, + "data-lifeguard-diagnostic": { + "icon": "", + "images": [] + }, + "data-saver-chrome": { + "icon": "https://community.chocolatey.org/content/packageimages/data-saver-chrome.2.0.2.png", + "images": [] + }, + "database-net": { + "icon": "", + "images": [] + }, + "database-searcher": { + "icon": "https://community.chocolatey.org/content/packageimages/database-searcher.1.04.0.png", + "images": [] + }, + "databasemaster": { + "icon": "https://community.chocolatey.org/content/packageimages/databasemaster.8.3.9.png", + "images": [] + }, + "databasetools": { + "icon": "", + "images": [] + }, + "datacrow": { + "icon": "https://community.chocolatey.org/content/packageimages/datacrow.4.1.1.png", + "images": [] + }, + "datadog-agent": { + "icon": "https://community.chocolatey.org/content/packageimages/datadog-agent.7.43.0.png", + "images": [] + }, + "datagrip": { + "icon": "https://iconape.com/wp-content/png_logo_vector/dotpeek-logo.png", + "images": [] + }, + "datagrip-earlyaccess": { + "icon": "https://iconape.com/wp-content/png_logo_vector/dotpeek-logo.png", + "images": [] + }, + "datahelix": { + "icon": "https://community.chocolatey.org/content/packageimages/datahelix.2.2.2.png", + "images": [] + }, + "datamash": { + "icon": "", + "images": [] + }, + "datapixels": { + "icon": "https://community.chocolatey.org/content/packageimages/datapixels.1.1.0.png", + "images": [] + }, + "dataram-ramdisk": { + "icon": "", + "images": [] + }, + "datarecovery": { + "icon": "https://i.postimg.cc/TY0YBDxK/drw.png", + "images": [ + "https://i.postimg.cc/SxQjKGdL/image.png", + "https://i.postimg.cc/7ZBhJTtF/image.png", + "https://i.postimg.cc/JhGnN49G/image.png", + "https://i.postimg.cc/4yTxRvn9/image.png", + "https://i.postimg.cc/G3kpJfSJ/image.png" + ] + }, + "datarescue": { + "icon": "", + "images": [] + }, + "dataspell": { + "icon": "", + "images": [] + }, + "dataspell-earlypreview": { + "icon": "https://seeklogo.com/images/D/dataspell-logo-06435B9CF3-seeklogo.com.png", + "images": [] + }, + "datastar": { + "icon": "", + "images": [] + }, + "datastax-community": { + "icon": "", + "images": [] + }, + "date-reminder": { + "icon": "https://community.chocolatey.org/content/packageimages/date-reminder.3.38.png", + "images": [] + }, + "datomic-free": { + "icon": "", + "images": [] + }, + "dattodrive": { + "icon": "", + "images": [] + }, + "davegnukem": { + "icon": "", + "images": [] + }, + "davmail": { + "icon": "https://community.chocolatey.org/content/packageimages/davmail.6.0.1.3390.png", + "images": [] + }, + "dawg": { + "icon": "", + "images": [] + }, + "daxstudio": { + "icon": "https://community.chocolatey.org/content/packageimages/daxstudio.3.0.4.png", + "images": [] + }, + "db-visualizer": { + "icon": "https://community.chocolatey.org/content/packageimages/db-visualizer.14.0.3.png", + "images": [] + }, + "dbachecks": { + "icon": "https://community.chocolatey.org/content/packageimages/dbachecks.2.0.18.png", + "images": [] + }, + "dbbrowserforsqlite": { + "icon": "https://unigeticons.meowcat285.com/DBBrowser.png", + "images": [] + }, + "dbeaver": { + "icon": "https://unigeticons.meowcat285.com/DBeaver.png", + "images": [] + }, + "dbeaver-ee": { + "icon": "https://community.chocolatey.org/content/packageimages/dbeaver-ee.7.3.0.png", + "images": [] + }, + "dbforge-mysql-cb": { + "icon": "https://community.chocolatey.org/content/packageimages/dbforge-mysql-cb.9.1.2.20221005.png", + "images": [] + }, + "dbforge-mysql-dc": { + "icon": "https://community.chocolatey.org/content/packageimages/dbforge-mysql-dc.5.8.19.20220830.png", + "images": [] + }, + "dbforge-mysql-doc-std": { + "icon": "", + "images": [] + }, + "dbforge-mysql-qb": { + "icon": "https://community.chocolatey.org/content/packageimages/dbforge-mysql-qb.5.1.15.20220830.png", + "images": [] + }, + "dbforge-mysql-sc": { + "icon": "https://community.chocolatey.org/content/packageimages/dbforge-mysql-sc.5.1.16.20220830.png", + "images": [] + }, + "dbforge-mysql-studio": { + "icon": "https://community.chocolatey.org/content/packageimages/dbforge-mysql-studio.9.1.21.20221005.png", + "images": [] + }, + "dbforge-ora-cb": { + "icon": "https://community.chocolatey.org/content/packageimages/dbforge-ora-cb.4.4.6.20220719.png", + "images": [] + }, + "dbforge-ora-dc": { + "icon": "https://community.chocolatey.org/content/packageimages/dbforge-ora-dc.5.4.22.20220719.png", + "images": [] + }, + "dbforge-ora-dg": { + "icon": "", + "images": [] + }, + "dbforge-ora-doc-std": { + "icon": "", + "images": [] + }, + "dbforge-ora-sc": { + "icon": "https://community.chocolatey.org/content/packageimages/dbforge-ora-sc.4.4.26.20220719.png", + "images": [] + }, + "dbforge-ora-studio": { + "icon": "", + "images": [] + }, + "dbforge-ora-studio-x86": { + "icon": "", + "images": [] + }, + "dbforge-pg-dc": { + "icon": "https://community.chocolatey.org/content/packageimages/dbforge-pg-dc.4.0.472.20230130.png", + "images": [] + }, + "dbforge-postgre-studio": { + "icon": "", + "images": [] + }, + "dbforge-sql-cb-pro": { + "icon": "", + "images": [] + }, + "dbforge-sql-cmpl": { + "icon": "", + "images": [] + }, + "dbforge-sql-dc": { + "icon": "", + "images": [] + }, + "dbforge-sql-decrypt": { + "icon": "", + "images": [] + }, + "dbforge-sql-devops": { + "icon": "", + "images": [] + }, + "dbforge-sql-dg": { + "icon": "", + "images": [] + }, + "dbforge-sql-doc": { + "icon": "", + "images": [] + }, + "dbforge-sql-dp": { + "icon": "", + "images": [] + }, + "dbforge-sql-ep": { + "icon": "", + "images": [] + }, + "dbforge-sql-fus": { + "icon": "", + "images": [] + }, + "dbforge-sql-im": { + "icon": "", + "images": [] + }, + "dbforge-sql-mon": { + "icon": "", + "images": [] + }, + "dbforge-sql-qb": { + "icon": "", + "images": [] + }, + "dbforge-sql-sc": { + "icon": "", + "images": [] + }, + "dbforge-sql-schcmpr": { + "icon": "", + "images": [] + }, + "dbforge-sql-search": { + "icon": "", + "images": [] + }, + "dbforge-sql-studio": { + "icon": "", + "images": [] + }, + "dbforge-sql-tools": { + "icon": "https://community.chocolatey.org/content/packageimages/dbforge-sql-tools.6.4.2.20230222.png", + "images": [] + }, + "dbforge-sql-ut": { + "icon": "", + "images": [] + }, + "dbforgesqlru": { + "icon": "", + "images": [] + }, + "dbgate": { + "icon": "https://community.chocolatey.org/content/packageimages/dbgate.install.5.2.3.png", + "images": [] + }, + "dbgl": { + "icon": "https://community.chocolatey.org/content/packageimages/dbgl.0.96.0.png", + "images": [] + }, + "dbgview": { + "icon": "https://community.chocolatey.org/content/packageimages/dbgview.4.90.png", + "images": [] + }, + "dbmate": { + "icon": "", + "images": [] + }, + "dbmigration": { + "icon": "https://community.chocolatey.org/content/packageimages/dbmigration.16.0.8447.1.png", + "images": [] + }, + "dbr": { + "icon": "https://community.chocolatey.org/content/packageimages/dbr.5.2.0.png", + "images": [] + }, + "dbsync": { + "icon": "", + "images": [] + }, + "dbvis": { + "icon": "", + "images": [] + }, + "dcc-unlit": { + "icon": "", + "images": [] + }, + "dcforoffice": { + "icon": "https://community.chocolatey.org/content/packageimages/dcforoffice.1.2.png", + "images": [] + }, + "dcmtk": { + "icon": "", + "images": [] + }, + "dcode": { + "icon": "https://community.chocolatey.org/content/packageimages/dcode.5.5.21194.40.png", + "images": [] + }, + "dcplusplus": { + "icon": "https://community.chocolatey.org/content/packageimages/dcplusplus.0.870.png", + "images": [] + }, + "dcsworld": { + "icon": "", + "images": [] + }, + "dd": { + "icon": "", + "images": [] + }, + "dd-trace-dotnet": { + "icon": "", + "images": [] + }, + "ddc-toolbox": { + "icon": "", + "images": [] + }, + "ddcpuid": { + "icon": "", + "images": [] + }, + "ddecmd": { + "icon": "", + "images": [] + }, + "ddev": { + "icon": "", + "images": [] + }, + "ddh": { + "icon": "", + "images": [] + }, + "ddosify": { + "icon": "", + "images": [] + }, + "dds-thumbnail-viewer": { + "icon": "https://community.chocolatey.org/content/packageimages/dds-thumbnail-viewer.1.0.1.001.png", + "images": [] + }, + "ddu": { + "icon": "https://community.chocolatey.org/content/packageimages/ddu.18.0.6.2023012901.png", + "images": [] + }, + "Devolutions.Agent": { + "icon": "https://raw.githubusercontent.com/Devolutions/UniGetUI/main/WebBasedData/icons/devolutions-agent-icon.png", + "images": [] + }, + "Devolutions.Gateway": { + "icon": "https://raw.githubusercontent.com/Devolutions/UniGetUI/main/WebBasedData/icons/gateway-icon.png", + "images": [] + }, + "Devolutions.Jetsocat": { + "icon": "https://raw.githubusercontent.com/Devolutions/UniGetUI/main/WebBasedData/icons/gateway-icon.png", + "images": [] + }, + "Devolutions.Launcher": { + "icon": "https://raw.githubusercontent.com/Devolutions/UniGetUI/main/WebBasedData/icons/launcher-icon.png", + "images": [] + }, + "Devolutions.MsRdpEx": { + "icon": "https://raw.githubusercontent.com/Devolutions/UniGetUI/main/WebBasedData/icons/msrdpex-icon.png", + "images": [ + "https://raw.githubusercontent.com/Devolutions/MsRdpEx/master/images/MsRdpEx_installed.png" + ] + }, + "Devolutions.RemoteDesktopManager": { + "icon": "https://raw.githubusercontent.com/Devolutions/UniGetUI/main/WebBasedData/icons/remote-desktop-manager-icon.png", + "images": [] + }, + "Devolutions.RemoteDesktopManagerAgent": { + "icon": "https://raw.githubusercontent.com/Devolutions/UniGetUI/main/WebBasedData/icons/remote-desktop-manager-agent-icon.png", + "images": [] + }, + "Devolutions.ServerConsole": { + "icon": "https://raw.githubusercontent.com/Devolutions/UniGetUI/main/WebBasedData/icons/server-icon.png", + "images": [] + }, + "Devolutions.UniGetUI": { + "icon": "https://raw.githubusercontent.com/Devolutions/UniGetUI/main/media/icon.png", + "images": [ + "https://raw.githubusercontent.com/Devolutions/UniGetUI/main/media/UniGetUI_1.png", + "https://raw.githubusercontent.com/Devolutions/UniGetUI/main/media/UniGetUI_3.png", + "https://raw.githubusercontent.com/Devolutions/UniGetUI/main/media/UniGetUI_6.png" + ] + }, + "Devolutions.Workspace": { + "icon": "https://raw.githubusercontent.com/Devolutions/UniGetUI/main/WebBasedData/icons/workspace-icon.png", + "images": [] + }, + "de4dot": { + "icon": "", + "images": [] + }, + "deadbeef": { + "icon": "https://community.chocolatey.org/content/packageimages/deadbeef.install.1.9.5.png", + "images": [] + }, + "deadlock": { + "icon": "https://cdn2.steamgriddb.com/icon_thumb/497a029d45e44c8f9cfb18713bc133b4.png", + "images": [] + }, + "debian": { + "icon": "https://i.ibb.co/WfRYYFs/debian-512x512.png", + "images": [ + "https://i.postimg.cc/KckNLQYg/Debian-12.png", + "https://i.postimg.cc/MTXY9mbN/debian-12book.png", + "https://i.postimg.cc/k4ZvzRT4/Debian12-Inst.png", + "https://i.postimg.cc/J0k5L7FQ/debian-12b.png" + ] + }, + "debotnet": { + "icon": "https://community.chocolatey.org/content/packageimages/debotnet.0.7.800.png", + "images": [] + }, + "debugtron": { + "icon": "", + "images": [] + }, + "debugviewpp": { + "icon": "", + "images": [] + }, + "deck": { + "icon": "", + "images": [] + }, + "deckboard": { + "icon": "", + "images": [] + }, + "deckmaster": { + "icon": "", + "images": [] + }, + "deemix-gui": { + "icon": "", + "images": [] + }, + "deepgit": { + "icon": "https://community.chocolatey.org/content/packageimages/deepgit.4.3.png", + "images": [] + }, + "deepl": { + "icon": "https://i.postimg.cc/FFkmhyn6/deepl-icon.png", + "images": [ + "https://i.postimg.cc/nrmtTxDx/deepl-1.png" + ] + }, + "deepstream": { + "icon": "", + "images": [] + }, + "deepview": { + "icon": "https://community.chocolatey.org/content/packageimages/deepview.4.10.0.20161116.png", + "images": [] + }, + "deepvocal": { + "icon": "", + "images": [] + }, + "deepvocal-hitsuboku-kumi-chn": { + "icon": "", + "images": [] + }, + "deezer": { + "icon": "https://community.chocolatey.org/content/packageimages/deezer.5.30.520.155.png", + "images": [] + }, + "default-template": { + "icon": "https://community.chocolatey.org/content/packageimages/default.template.1.0.0.png", + "images": [] + }, + "defaultaudio": { + "icon": "", + "images": [] + }, + "defender-injector": { + "icon": "https://community.chocolatey.org/content/packageimages/defender-injector.1.1.png", + "images": [] + }, + "defenderui": { + "icon": "https://i.postimg.cc/8Pyn1b94/defui-icon.png", + "images": [ + "https://i.postimg.cc/76gWwrrJ/defui1.png", + "https://i.postimg.cc/KcDHWb5d/defui2.png", + "https://i.postimg.cc/PJTFqVd3/defui3.png", + "https://i.postimg.cc/2yG9Ld6z/defui4.png", + "https://i.postimg.cc/fTWrnP2k/defui5.png", + "https://i.postimg.cc/mgtphHGs/defui6.png" + ] + }, + "defi": { + "icon": "", + "images": [] + }, + "defiwallet": { + "icon": "https://community.chocolatey.org/content/packageimages/defiwallet.3.2.1.png", + "images": [] + }, + "deflopt": { + "icon": "", + "images": [] + }, + "defprof": { + "icon": "https://community.chocolatey.org/content/packageimages/defprof.1.10.png", + "images": [] + }, + "defraggler": { + "icon": "https://community.chocolatey.org/content/packageimages/defraggler.2.22.995.20200817.png", + "images": [] + }, + "deletefiles": { + "icon": "https://community.chocolatey.org/content/packageimages/DeleteFiles.1.14.png", + "images": [] + }, + "dell-command-configure": { + "icon": "https://community.chocolatey.org/content/packageimages/dell-command-configure.4.7.0.433.png", + "images": [] + }, + "dell-command-monitor": { + "icon": "https://community.chocolatey.org/content/packageimages/dell-command-monitor.10.7.0.232.png", + "images": [] + }, + "dell-commandupdate-universal": { + "icon": "https://community.chocolatey.org/content/packageimages/dellcommandupdate-uwp.4.8.0.png", + "images": [] + }, + "dell-platform-tags-utility": { + "icon": "https://community.chocolatey.org/content/packageimages/dell-platform-tags-utility.4.0.30.0.png", + "images": [] + }, + "dell-system-update": { + "icon": "", + "images": [] + }, + "dell-update": { + "icon": "", + "images": [] + }, + "dellcommandupdate-uwp": { + "icon": "https://community.chocolatey.org/content/packageimages/dellcommandupdate-uwp.4.8.0.png", + "images": [] + }, + "delta": { + "icon": "", + "images": [] + }, + "deltachat": { + "icon": "https://raw.githubusercontent.com/deltachat/deltachat-desktop/main/images/deltachat.png", + "images": [] + }, + "deltarune": { + "icon": "https://user-images.githubusercontent.com/35242550/147987895-053c724c-eefd-4cc0-ae20-a1502ab0120d.png", + "images": [] + }, + "deluge": { + "icon": "https://i.postimg.cc/FzR3fcmq/image.png", + "images": [ + "https://i.postimg.cc/bJdQ6MFr/image.png", + "https://i.postimg.cc/W1j0RtfQ/image.png", + "https://i.postimg.cc/6p0nBwkT/image.png" + ] + }, + "delugebeta": { + "icon": "https://i.postimg.cc/FzR3fcmq/image.png", + "images": [ + "https://i.postimg.cc/bJdQ6MFr/image.png", + "https://i.postimg.cc/W1j0RtfQ/image.png", + "https://i.postimg.cc/6p0nBwkT/image.png" + ] + }, + "demo-rest-service": { + "icon": "", + "images": [] + }, + "democreator": { + "icon": "", + "images": [] + }, + "democreator-cn": { + "icon": "", + "images": [] + }, + "deno": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/c/c3/Deno_Logo_2024.svg/250px-Deno_Logo_2024.svg.png", + "images": [] + }, + "dep": { + "icon": "", + "images": [] + }, + "dependencies": { + "icon": "https://community.chocolatey.org/content/packageimages/dependencies.1.11.1.png", + "images": [ + "https://i.postimg.cc/BZc8QVt8/image.png", + "https://i.postimg.cc/QdRNqQHG/image.png", + "https://i.postimg.cc/L5C2gfrW/image.png" + ] + }, + "dependency-check": { + "icon": "", + "images": [] + }, + "dependency-scanner": { + "icon": "https://community.chocolatey.org/content/packageimages/dependency-scanner.0.2.0.1.png", + "images": [] + }, + "dependency-server2016": { + "icon": "https://community.chocolatey.org/content/packageimages/dependency-server2016.2016.1803.png", + "images": [] + }, + "dependency-server2019": { + "icon": "https://community.chocolatey.org/content/packageimages/dependency-server2019.2019.0.png", + "images": [] + }, + "dependency-windows10": { + "icon": "", + "images": [] + }, + "dependencywalker": { + "icon": "https://community.chocolatey.org/content/packageimages/dependencywalker.2.2.6000.9.png", + "images": [] + }, + "depends": { + "icon": "", + "images": [] + }, + "deploymenttoolkit": { + "icon": "", + "images": [] + }, + "depressurizer": { + "icon": "https://community.chocolatey.org/content/packageimages/depressurizer.5.2.0.png", + "images": [] + }, + "designsparkpcb": { + "icon": "", + "images": [] + }, + "desk-drive": { + "icon": "https://community.chocolatey.org/content/packageimages/desk-drive.2.1.1.png", + "images": [] + }, + "deskfiler": { + "icon": "", + "images": [] + }, + "deskflow": { + "icon": "https://dl.flathub.org/media/org/deskflow/deskflow/d93533995feb3af980d1ee1ffc0bf6d6/icons/128x128/org.deskflow.deskflow.png", + "images": [ + "https://i.ibb.co/WvkQ1Drx/image.png", + "https://i.ibb.co/wNXm9YWh/image.png" + ] + }, + "deskgo": { + "icon": "", + "images": [] + }, + "deskpins": { + "icon": "https://community.chocolatey.org/content/packageimages/deskpins.1.32.2.png", + "images": [] + }, + "deskreen": { + "icon": "", + "images": [] + }, + "deskspace": { + "icon": "", + "images": [] + }, + "desktop": { + "icon": "", + "images": [] + }, + "desktop-audio-streamer": { + "icon": "https://community.chocolatey.org/content/packageimages/desktop-audio-streamer.5.1.png", + "images": [] + }, + "desktop-dimmer": { + "icon": "", + "images": [] + }, + "desktop-ini-editor": { + "icon": "", + "images": [] + }, + "desktop-restore": { + "icon": "", + "images": [] + }, + "desktopapp": { + "icon": "https://i.postimg.cc/ydcHyB9H/desktopapp-icon.png", + "images": [ + "https://i.postimg.cc/FK2vS1Yp/desktopapp-1.png", + "https://i.postimg.cc/QCqZvb0Y/desktopapp-2.png", + "https://i.postimg.cc/wMzdWPcs/desktopapp-3.png" + ] + }, + "desktopeditors": { + "icon": "https://i.imgur.com/LZh4v4l.png", + "images": [] + }, + "desktopicons-winconfig": { + "icon": "https://community.chocolatey.org/content/packageimages/desktopicons-winconfig.0.0.1.png", + "images": [] + }, + "desktopicontoggle": { + "icon": "https://community.chocolatey.org/content/packageimages/desktopicontoggle.1.3.0.png", + "images": [] + }, + "desktopinfo": { + "icon": "https://community.chocolatey.org/content/packageimages/desktopinfo.3.10.0.png", + "images": [] + }, + "desktopok": { + "icon": "https://i.postimg.cc/DyPVnPcT/Desktop-OK.png", + "images": [ + "https://i.postimg.cc/rpz7GX2V/Desktop-OK-1.png" + ] + }, + "desktops": { + "icon": "", + "images": [] + }, + "desura": { + "icon": "https://community.chocolatey.org/content/packageimages/desura.100.53.20141201.png", + "images": [] + }, + "deta": { + "icon": "", + "images": [] + }, + "detect-it-easy": { + "icon": "", + "images": [] + }, + "detekt": { + "icon": "", + "images": [] + }, + "dev-c++": { + "icon": "https://www.bloodshed.net/data/_uploaded/image/blddevcpp.png", + "images": [ + "https://raw.githubusercontent.com/Embarcadero/Dev-Cpp/master/Source/Images/screenshot800x600.png" + ] + }, + "dev-sidecar": { + "icon": "", + "images": [] + }, + "devaudit": { + "icon": "", + "images": [] + }, + "devbook": { + "icon": "", + "images": [] + }, + "devbox-common": { + "icon": "https://community.chocolatey.org/content/packageimages/Devbox-Common.1.0.2.png", + "images": [] + }, + "devbox-common-extension": { + "icon": "https://community.chocolatey.org/content/packageimages/Devbox-Common.extension.1.0.1.png", + "images": [] + }, + "devbox-conemu": { + "icon": "https://community.chocolatey.org/content/packageimages/Devbox-ConEmu.0.0.0.20130422.png", + "images": [] + }, + "devbox-git": { + "icon": "https://community.chocolatey.org/content/packageimages/Devbox-Git.1.8.1.20130422.png", + "images": [] + }, + "devbox-gitflow": { + "icon": "https://community.chocolatey.org/content/packageimages/Devbox-GitFlow.0.0.0.png", + "images": [] + }, + "devbox-gitsettings": { + "icon": "https://community.chocolatey.org/content/packageimages/Devbox-GitSettings.1.0.1.png", + "images": [] + }, + "devbox-nano": { + "icon": "https://community.chocolatey.org/content/packageimages/Devbox-Nano.2.2.6.20130417.png", + "images": [] + }, + "devbox-notepad2": { + "icon": "https://community.chocolatey.org/content/packageimages/Devbox-Notepad2.4.2.25.png", + "images": [] + }, + "devbox-p4merge": { + "icon": "https://community.chocolatey.org/content/packageimages/Devbox-P4Merge.2022.3.0.2022112301.png", + "images": [] + }, + "devbox-sed": { + "icon": "https://community.chocolatey.org/content/packageimages/Devbox-Sed.4.2.1.png", + "images": [] + }, + "devbox-unzip": { + "icon": "https://community.chocolatey.org/content/packageimages/Devbox-UnZip.5.52.png", + "images": [] + }, + "devbox-vcredist2010": { + "icon": "https://community.chocolatey.org/content/packageimages/Devbox-VCRedist2010.10.0.40219.20130422.png", + "images": [] + }, + "devbox-wget": { + "icon": "https://community.chocolatey.org/content/packageimages/Devbox-Wget.1.11.4.1.png", + "images": [] + }, + "devcon": { + "icon": "", + "images": [] + }, + "devd": { + "icon": "https://community.chocolatey.org/content/packageimages/devd.0.9.png", + "images": [] + }, + "devdocs": { + "icon": "", + "images": [] + }, + "devdocs-app": { + "icon": "https://community.chocolatey.org/content/packageimages/devdocs-app.0.7.2.png", + "images": [] + }, + "devdocs-desktop": { + "icon": "", + "images": [] + }, + "deveunitylicenseactivator": { + "icon": "https://community.chocolatey.org/content/packageimages/deveunitylicenseactivator.1.0.20.png", + "images": [] + }, + "devhome": { + "icon": "https://unigeticons.meowcat285.com/DevHome.png", + "images": [ + "https://github.com/microsoft/devhome/blob/main/src/Assets/Preview/StoreDisplay-150.png", + "https://i.postimg.cc/6qBmSkFB/devhome-machine-config.png", + "https://i.postimg.cc/tJDMHrHW/devhome-widgets.png", + "https://i.postimg.cc/PfMcZq8J/devhome-environment-manage.png" + ] + }, + "devhub": { + "icon": "", + "images": [] + }, + "deviceioview": { + "icon": "https://community.chocolatey.org/content/packageimages/deviceioview.1.05.png", + "images": [] + }, + "devrantron": { + "icon": "", + "images": [] + }, + "dewey": { + "icon": "", + "images": [] + }, + "dex": { + "icon": "https://i.postimg.cc/pVsYggXd/Samsung-De-X.png", + "images": [ + "https://i.postimg.cc/dVHBx2Rt/image.png" + ] + }, + "dex2jar": { + "icon": "", + "images": [] + }, + "dexed": { + "icon": "", + "images": [] + }, + "dexpot": { + "icon": "https://community.chocolatey.org/content/packageimages/dexpot.1.6.14.1.png", + "images": [] + }, + "dfu-util": { + "icon": "", + "images": [] + }, + "dhall": { + "icon": "", + "images": [] + }, + "dhcp-server": { + "icon": "", + "images": [] + }, + "dia": { + "icon": "", + "images": [] + }, + "diagram-designer": { + "icon": "", + "images": [] + }, + "dialang": { + "icon": "", + "images": [] + }, + "dialpad": { + "icon": "", + "images": [] + }, + "dialupass": { + "icon": "https://community.chocolatey.org/content/packageimages/dialupass.3.60.png", + "images": [] + }, + "dicomproxy": { + "icon": "", + "images": [] + }, + "dictpw": { + "icon": "", + "images": [] + }, + "dida": { + "icon": "", + "images": [] + }, + "die": { + "icon": "", + "images": [] + }, + "die-engine": { + "icon": "https://community.chocolatey.org/content/packageimages/die.3.07.png", + "images": [ + "https://i.postimg.cc/VsbkrHtD/image.png", + "https://i.postimg.cc/PxDnx97D/image.png", + "https://i.postimg.cc/YS1xCx39/image.png" + ] + }, + "diff-pdf": { + "icon": "", + "images": [] + }, + "diff-so-fancy": { + "icon": "", + "images": [] + }, + "diffinity": { + "icon": "", + "images": [] + }, + "diffmerge": { + "icon": "https://community.chocolatey.org/content/packageimages/diffmerge.4.2.0.20170602.png", + "images": [] + }, + "diffpdf": { + "icon": "", + "images": [] + }, + "diffsitter": { + "icon": "", + "images": [] + }, + "difftastic": { + "icon": "", + "images": [] + }, + "diffuse": { + "icon": "https://community.chocolatey.org/content/packageimages/diffuse.0.4.8.1.png", + "images": [] + }, + "diffutils": { + "icon": "", + "images": [] + }, + "digdag": { + "icon": "", + "images": [] + }, + "digidoc4": { + "icon": "", + "images": [] + }, + "digikam": { + "icon": "", + "images": [] + }, + "digime": { + "icon": "", + "images": [] + }, + "digimizer": { + "icon": "https://community.chocolatey.org/content/packageimages/digimizer.6.1.1.png", + "images": [] + }, + "digital": { + "icon": "", + "images": [] + }, + "digsby": { + "icon": "https://community.chocolatey.org/content/packageimages/digsby.0.91.30192.png", + "images": [] + }, + "dilay": { + "icon": "https://community.chocolatey.org/content/packageimages/dilay.1.9.0.png", + "images": [] + }, + "dimension4": { + "icon": "", + "images": [] + }, + "dingtalk": { + "icon": "", + "images": [] + }, + "dingtalk-lite": { + "icon": "", + "images": [] + }, + "dip": { + "icon": "https://community.chocolatey.org/content/packageimages/dip.4.1.0.png", + "images": [] + }, + "dipiscan": { + "icon": "https://community.chocolatey.org/content/packageimages/dipiscan.2.6.1.png", + "images": [] + }, + "direct": { + "icon": "", + "images": [] + }, + "directorymonitor": { + "icon": "https://community.chocolatey.org/content/packageimages/directorymonitor.2.15.0.6.png", + "images": [] + }, + "directoryopus": { + "icon": "https://s3-ap-southeast-2.amazonaws.com/images.imagescience.com.au/_201904_imager-transforms/s3images/Knowledge-Base/Miscellaneous/Directory-Opus/310128/Opus-Logo_8a39ff8a6b9c4355b296f93fc26068cc.png", + "images": [ + "https://i.postimg.cc/15VYgs8r/image.png", + "https://i.postimg.cc/DZzx7TVs/image.png", + "https://i.postimg.cc/vTJh7x4L/image.png", + "https://i.postimg.cc/pV3Mc08k/image.png", + "https://i.postimg.cc/4NtkDzQG/image.png", + "https://i.postimg.cc/g2WFmngZ/image.png", + "https://i.postimg.cc/Gmx02dfS/image.png", + "https://i.postimg.cc/q7JP6WVB/image.png" + ] + }, + "directorystudio": { + "icon": "https://i.imgur.com/KeJwBYO.png", + "images": [ + "https://directory.apache.org/studio/static/images/screen_ldif_editor.jpg", + "https://directory.apache.org/apacheds/basic-ug/images/schema-browser-person.png", + "https://d4.alternativeto.net/WnNm-4s905qEOrZiYuG-mAZBmC5GlPWDiAxYQopTYUU/rs:fit:1200:1200:0/g:ce:0:0/YWJzOi8vZGlzdC9zLzE5NTQ0YjI2LWQ0YTAtZTExMS05NDU2LTAwMjU5MDJjN2U3M18yX2Z1bGwucG5n.jpg", + "https://blog.dzhuvinov.com/wp-content/uploads/2010/02/apache-directory-studio.jpg" + ] + }, + "directx": { + "icon": "", + "images": [] + }, + "directx-sdk": { + "icon": "https://community.chocolatey.org/content/packageimages/directx-sdk.9.29.1962.02.png", + "images": [] + }, + "direnv": { + "icon": "https://avatars.githubusercontent.com/u/13077327", + "images": [] + }, + "direvents": { + "icon": "", + "images": [] + }, + "dirhash": { + "icon": "", + "images": [] + }, + "dirprintok": { + "icon": "https://i.postimg.cc/pLWwT50n/Dir-Print-OK.png", + "images": [ + "https://i.postimg.cc/hGw6pyK9/Dir-Print-OK-1.png" + ] + }, + "dirsyncpro": { + "icon": "https://community.chocolatey.org/content/packageimages/dirsyncpro.1.53.png", + "images": [] + }, + "disable-hiberboot": { + "icon": "https://community.chocolatey.org/content/packageimages/disable-hiberboot.1.0.1.png", + "images": [] + }, + "disable-logon-blur": { + "icon": "", + "images": [] + }, + "disable-ms-msdt": { + "icon": "https://community.chocolatey.org/content/packageimages/disable-ms-msdt.1.0.0.png", + "images": [] + }, + "disable-nvidia-telemetry": { + "icon": "https://community.chocolatey.org/content/packageimages/disable-nvidia-telemetry.1.1.0.20190306.png", + "images": [] + }, + "disable-smb-v1": { + "icon": "", + "images": [] + }, + "disable-windows10-upgrade": { + "icon": "https://community.chocolatey.org/content/packageimages/disable-windows10-upgrade.1.2.0.png", + "images": [] + }, + "disableofficemacros-winconfig": { + "icon": "https://community.chocolatey.org/content/packageimages/disableofficemacros-winconfig.0.0.1.png", + "images": [] + }, + "disableofficenag-winconfig": { + "icon": "https://community.chocolatey.org/content/packageimages/disableofficenag-winconfig.0.0.1.png", + "images": [] + }, + "disableuac": { + "icon": "", + "images": [] + }, + "disablewintracking": { + "icon": "https://community.chocolatey.org/content/packageimages/disablewintracking.3.2.3.png", + "images": [] + }, + "discord": { + "icon": "https://i.ibb.co/VJN801L/release-and-ptb.png", + "images": [ + "https://i.ibb.co/5M0bd2N/discord-1.png", + "https://i.ibb.co/hcBnn6x/discord-2.png", + "https://i.ibb.co/GFdRfcy/discord-3.png" + ] + }, + "discord-canary": { + "icon": "https://i.ibb.co/9qxY46z/canary.png", + "images": [ + "https://i.ibb.co/5M0bd2N/discord-1.png", + "https://i.ibb.co/hcBnn6x/discord-2.png", + "https://i.ibb.co/GFdRfcy/discord-3.png" + ] + }, + "discord-development": { + "icon": "https://i.ibb.co/bX00g4q/development.png", + "images": [ + "https://i.ibb.co/5M0bd2N/discord-1.png", + "https://i.ibb.co/hcBnn6x/discord-2.png", + "https://i.ibb.co/GFdRfcy/discord-3.png" + ] + }, + "discord-history-tracker": { + "icon": "https://community.chocolatey.org/content/packageimages/discord-history-tracker.37.2.png", + "images": [] + }, + "discord-ptb": { + "icon": "https://i.ibb.co/VJN801L/release-and-ptb.png", + "images": [ + "https://i.ibb.co/5M0bd2N/discord-1.png", + "https://i.ibb.co/hcBnn6x/discord-2.png", + "https://i.ibb.co/GFdRfcy/discord-3.png" + ] + }, + "discord-rpc-extension": { + "icon": "", + "images": [] + }, + "discord-py": { + "icon": "", + "images": [ + "https://raw.githubusercontent.com/Rapptz/discord.py/master/docs/images/commands/positional3.png" + ] + }, + "discordchatexporter": { + "icon": "", + "images": [] + }, + "discordmedialoader": { + "icon": "", + "images": [] + }, + "discordrpcmaker": { + "icon": "", + "images": [] + }, + "discoverj": { + "icon": "", + "images": [] + }, + "discrakt": { + "icon": "", + "images": [] + }, + "disk-wipe": { + "icon": "https://community.chocolatey.org/content/packageimages/disk-wipe.1.7.png", + "images": [] + }, + "diskcheckup": { + "icon": "", + "images": [] + }, + "diskcountersview": { + "icon": "https://community.chocolatey.org/content/packageimages/diskcountersview.1.27.png", + "images": [ + "https://i.postimg.cc/Qdq7YSvk/image.png" + ] + }, + "diskdefrag": { + "icon": "https://www.auslogics.com/includes/software/disk-defrag/i/logo.png", + "images": [ + "https://i.postimg.cc/0y2TJ5bp/image.png", + "https://i.postimg.cc/Bn6znhVp/image.png", + "https://i.postimg.cc/SKYtWnqz/image.png", + "https://i.postimg.cc/Pxm3R0CX/image.png" + ] + }, + "diskdefragtouch": { + "icon": "https://community.chocolatey.org/content/packageimages/diskdefragtouch.8.0.12.0.png", + "images": [] + }, + "diskdump": { + "icon": "https://community.chocolatey.org/content/packageimages/diskdump.0.1.0.png", + "images": [] + }, + "diskgenius": { + "icon": "https://community.chocolatey.org/content/packageimages/diskgenius.5.4.2.1239.png", + "images": [] + }, + "diskled": { + "icon": "", + "images": [] + }, + "diskmarkstream": { + "icon": "https://community.chocolatey.org/content/packageimages/diskmarkstream.1.1.2.png", + "images": [] + }, + "diskmon": { + "icon": "https://community.chocolatey.org/content/packageimages/diskmon.2.01.png", + "images": [] + }, + "disksmartview": { + "icon": "https://community.chocolatey.org/content/packageimages/disksmartview.1.21.png", + "images": [] + }, + "diskspd": { + "icon": "", + "images": [] + }, + "diskus": { + "icon": "", + "images": [] + }, + "diskview": { + "icon": "https://community.chocolatey.org/content/packageimages/diskview.2.41.png", + "images": [] + }, + "dismplusplus": { + "icon": "https://community.chocolatey.org/content/packageimages/dismplusplus.10.1.1002.1.png", + "images": [] + }, + "dispcalgui": { + "icon": "https://community.chocolatey.org/content/packageimages/dispcalgui.3.8.9.3.png", + "images": [] + }, + "display-changer": { + "icon": "", + "images": [] + }, + "displaycal": { + "icon": "https://community.chocolatey.org/content/packageimages/displaycal.portable.3.8.9.3.png", + "images": [] + }, + "displaydriveruninstaller": { + "icon": "https://kr.new-version.app/wp-content/uploads/2022/11/DDU-Display-Driver-Uninstaller.png", + "images": [ + "https://i.ibb.co/9HwQZpwt/image.png" + ] + }, + "displayfusion": { + "icon": "https://tweakers.net/ext/i/2004839352.png", + "images": [ + "https://i.postimg.cc/bwNp7ZFN/image.png", + "https://i.postimg.cc/Bvjsvd0r/image.png", + "https://i.postimg.cc/s2bzGwfv/image.png", + "https://i.postimg.cc/PxZjWYNK/image.png", + "https://i.postimg.cc/HngCBnym/image.png", + "https://i.postimg.cc/2y7NJYQZ/image.png", + "https://i.postimg.cc/2jQY3QsS/image.png", + "https://i.postimg.cc/T34MBCDC/image.png", + "https://i.postimg.cc/QMKGD1gs/image.png", + "https://i.postimg.cc/QtLLdCS7/image.png" + ] + }, + "displaylink": { + "icon": "", + "images": [] + }, + "displaymanager": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/8/85/Deluge-Logo.svg/1200px-Deluge-Logo.svg.png", + "images": [ + "https://tweakers.net/ext/i/1391463333.png" + ] + }, + "displayz": { + "icon": "https://community.chocolatey.org/content/packageimages/displayz.0.1.0.png", + "images": [] + }, + "ditto": { + "icon": "https://store-images.s-microsoft.com/image/apps.21473.13510798887950305.d9b285e1-1829-480b-a018-980604fa17cc.df6c59c8-9b0e-4195-a06e-84b9bc76ccc0", + "images": [ + "https://store-images.s-microsoft.com/image/apps.56934.13510798887950305.b0cc4771-9cd2-41d2-b700-51139aed9a69.5c34cd8a-7747-4299-92b6-bc9204e92bf7" + ] + }, + "ditto++": { + "icon": "", + "images": [] + }, + "diun": { + "icon": "", + "images": [] + }, + "dive": { + "icon": "https://community.chocolatey.org/content/packageimages/dive.0.10.0.png", + "images": [] + }, + "divoom-cli": { + "icon": "", + "images": [] + }, + "divoom-gateway": { + "icon": "", + "images": [] + }, + "divoomcli": { + "icon": "", + "images": [] + }, + "divoomgateway": { + "icon": "", + "images": [] + }, + "divvy": { + "icon": "https://community.chocolatey.org/content/packageimages/divvy.1.4.4.png", + "images": [] + }, + "dixa": { + "icon": "", + "images": [] + }, + "djiassistant2": { + "icon": "", + "images": [] + }, + "djiassistant2-consumerseries": { + "icon": "", + "images": [] + }, + "djiassistant2-enterpriseseries": { + "icon": "", + "images": [] + }, + "djiassistant2-forautopilot": { + "icon": "", + "images": [] + }, + "djiassistant2-forbatterystation": { + "icon": "", + "images": [] + }, + "djiassistant2-formatrice": { + "icon": "", + "images": [] + }, + "djiassistant2-formavic": { + "icon": "", + "images": [] + }, + "djiassistant2-formg": { + "icon": "", + "images": [] + }, + "djiassistant2-forphantom": { + "icon": "", + "images": [] + }, + "djiassistant2-fpv": { + "icon": "", + "images": [] + }, + "djv": { + "icon": "https://community.chocolatey.org/content/packageimages/djv.2.0.8.png", + "images": [] + }, + "djv2": { + "icon": "", + "images": [] + }, + "djview": { + "icon": "", + "images": [] + }, + "djvu-libre": { + "icon": "https://community.chocolatey.org/content/packageimages/djvu-libre.3.5.28.412.png", + "images": [] + }, + "djvulibre": { + "icon": "", + "images": [] + }, + "dlivedirector": { + "icon": "", + "images": [] + }, + "dllexp": { + "icon": "https://community.chocolatey.org/content/packageimages/dllexp.1.66.png", + "images": [] + }, + "dmd": { + "icon": "https://community.chocolatey.org/content/packageimages/dmd.2.100.2.png", + "images": [] + }, + "dmde": { + "icon": "https://community.chocolatey.org/content/packageimages/dmde.4.0.2.804.png", + "images": [] + }, + "dmg2img": { + "icon": "", + "images": [] + }, + "dmidiplayer": { + "icon": "", + "images": [] + }, + "dn-tool-container": { + "icon": "", + "images": [] + }, + "dngconverter": { + "icon": "https://i.imgur.com/IHM1AHJ.png", + "images": [ + "https://thumb.tildacdn.com/tild3862-6566-4331-a138-376239646663/-/resize/824x/-/format/webp/tilda-page-adobe-dng.png", + "https://codecpack.co/images/Adobe-DNG-Converter.png", + "https://helpx.adobe.com/content/dam/help/en/photoshop/using/adobe-dng-converter/jcr_content/main-pars/image_0/DNGConverter.jpg.img.jpg", + "https://helpx.adobe.com/content/dam/help/en/photoshop/using/adobe-dng-converter/jcr_content/main-pars/image/DNGPrefs.jpg.img.jpg" + ] + }, + "dngrep": { + "icon": "https://community.chocolatey.org/content/packageimages/dngrep.3.0.154.0.png", + "images": [] + }, + "dnncmd": { + "icon": "https://community.chocolatey.org/content/packageimages/dnncmd.3.7.523.0.png", + "images": [] + }, + "dns-benchmark": { + "icon": "", + "images": [] + }, + "dnsagent": { + "icon": "", + "images": [] + }, + "dnscontrol": { + "icon": "", + "images": [] + }, + "dnscrypt-proxy": { + "icon": "https://community.chocolatey.org/content/packageimages/dnscrypt-proxy.2.1.4.png", + "images": [] + }, + "dnsdataview": { + "icon": "https://community.chocolatey.org/content/packageimages/dnsdataview.1.56.png", + "images": [] + }, + "dnsjumper": { + "icon": "https://i.postimg.cc/T1HzqkRh/dnsjmp.png", + "images": [ + "https://i.postimg.cc/N0WkXr0Z/image.png", + "https://i.postimg.cc/XJdck7Gq/image.png", + "https://i.postimg.cc/8kdmFcgn/image.png", + "https://i.postimg.cc/xT0yLQ0j/image.png" + ] + }, + "dnslookup": { + "icon": "", + "images": [] + }, + "dnsproxy": { + "icon": "", + "images": [] + }, + "dnspy": { + "icon": "https://community.chocolatey.org/content/packageimages/dnspy.6.1.8.png", + "images": [] + }, + "dnspy-netfx": { + "icon": "https://community.chocolatey.org/content/packageimages/dnspy-netfx.6.1.8.png", + "images": [] + }, + "dnspyex": { + "icon": "https://community.chocolatey.org/content/packageimages/dnspyex.6.3.0.png", + "images": [] + }, + "dobi": { + "icon": "", + "images": [] + }, + "docash-vega-driver": { + "icon": "", + "images": [] + }, + "docash-vega-firmware": { + "icon": "", + "images": [] + }, + "docconverter": { + "icon": "https://community.chocolatey.org/content/packageimages/DocConverter.3.1.png", + "images": [] + }, + "docear": { + "icon": "https://community.chocolatey.org/content/packageimages/docear.install.1.2.png", + "images": [] + }, + "docear4word": { + "icon": "https://community.chocolatey.org/content/packageimages/docear4word.1.30.00.png", + "images": [] + }, + "docfetcher": { + "icon": "https://community.chocolatey.org/content/packageimages/docfetcher.1.1.25.20230104.png", + "images": [] + }, + "docfx": { + "icon": "", + "images": [] + }, + "docfx-companion-tools": { + "icon": "", + "images": [] + }, + "docker": { + "icon": "https://www.docker.com/wp-content/uploads/2022/03/Docker-Logo-White-RGB_Vertical.png", + "images": [ + "https://i.postimg.cc/6qqkjsDF/Docker-Desktop.png" + ] + }, + "docker-cli": { + "icon": "https://community.chocolatey.org/content/packageimages/docker-cli.23.0.1.png", + "images": [] + }, + "docker-compose": { + "icon": "https://raw.githubusercontent.com/docker/compose/main/logo.png", + "images": [ + "https://i.postimg.cc/R0pF1kxh/Simple-example-of-Docker-compose-file.png" + ] + }, + "docker-desktop": { + "icon": "https://www.docker.com/wp-content/uploads/2022/03/Docker-Logo-White-RGB_Vertical.png", + "images": [] + }, + "docker-dockerdesktop": { + "icon": "https://www.docker.com/wp-content/uploads/2022/03/Docker-Logo-White-RGB_Vertical.png", + "images": [ + "https://i.postimg.cc/6qqkjsDF/Docker-Desktop.png" + ] + }, + "docker-engine": { + "icon": "https://community.chocolatey.org/content/packageimages/docker-engine.23.0.1.png", + "images": [] + }, + "docker-for-windows": { + "icon": "https://www.docker.com/wp-content/uploads/2022/03/Docker-Logo-White-RGB_Vertical.png", + "images": [] + }, + "docker-kitematic": { + "icon": "https://community.chocolatey.org/content/packageimages/docker-kitematic.0.17.13.png", + "images": [] + }, + "docker-machine": { + "icon": "", + "images": [] + }, + "docker-machine-sakuracloud": { + "icon": "", + "images": [] + }, + "docker-machine-vmwareworkstation": { + "icon": "", + "images": [] + }, + "docker-pushrm": { + "icon": "", + "images": [] + }, + "docker-toolbox": { + "icon": "https://community.chocolatey.org/content/packageimages/docker-toolbox.19.03.1.png", + "images": [] + }, + "docker-watch-forwarder": { + "icon": "", + "images": [] + }, + "dockercompletion": { + "icon": "", + "images": [] + }, + "dockerdesktop": { + "icon": "https://i.imgur.com/sOiXSfX.png", + "images": [ + "https://i.imgur.com/c36rCBs.png" + ] + }, + "dockerdesktopedge": { + "icon": "https://i.imgur.com/sOiXSfX.png", + "images": [ + "https://i.imgur.com/c36rCBs.png" + ] + }, + "dockmanager": { + "icon": "", + "images": [] + }, + "dockstation": { + "icon": "", + "images": [] + }, + "doctl": { + "icon": "", + "images": [] + }, + "docto": { + "icon": "", + "images": [] + }, + "dog": { + "icon": "", + "images": [] + }, + "dogecoin": { + "icon": "https://community.chocolatey.org/content/packageimages/dogecoin.1.14.6.png", + "images": [] + }, + "dogecoincore": { + "icon": "", + "images": [] + }, + "doggo": { + "icon": "", + "images": [] + }, + "dogtail-azuresdk": { + "icon": "", + "images": [] + }, + "dogtail-azuresdk-2-1-visualstudio2102": { + "icon": "", + "images": [] + }, + "dogtail-devenv": { + "icon": "", + "images": [] + }, + "dogtail-dotnet3-5sp1": { + "icon": "", + "images": [] + }, + "dogtail-visualstudio2012ultimate": { + "icon": "", + "images": [] + }, + "dogtail-visualstudio2013ultimatepreview": { + "icon": "", + "images": [] + }, + "dogtail-visualstudiotoolsforgit": { + "icon": "", + "images": [] + }, + "dogtail-vs2012-1": { + "icon": "", + "images": [] + }, + "dogtail-vs2012-2": { + "icon": "", + "images": [] + }, + "dogtail-vs2012-2-ctp": { + "icon": "", + "images": [] + }, + "dogtail-vs2012-3": { + "icon": "", + "images": [] + }, + "dokany": { + "icon": "https://community.chocolatey.org/content/packageimages/dokany.1.3.0.1000.png", + "images": [] + }, + "dokka": { + "icon": "", + "images": [] + }, + "dolphin": { + "icon": "https://community.chocolatey.org/content/packageimages/dolphin.5.0.0.20201120.png", + "images": [] + }, + "dolt": { + "icon": "", + "images": [] + }, + "domainhostingview": { + "icon": "https://community.chocolatey.org/content/packageimages/domainhostingview.1.82.png", + "images": [] + }, + "domo": { + "icon": "https://community.chocolatey.org/content/packageimages/domo.4.2.6.png", + "images": [] + }, + "donkey": { + "icon": "", + "images": [] + }, + "donkeykong": { + "icon": "", + "images": [] + }, + "dont-sleep": { + "icon": "", + "images": [] + }, + "dontsleep": { + "icon": "https://community.chocolatey.org/content/packageimages/dontsleep.9.29.png", + "images": [] + }, + "doom-d64rtr": { + "icon": "https://community.chocolatey.org/content/packageimages/doom-d64rtr.1.5.0.png", + "images": [] + }, + "doom1-maps-dtwid": { + "icon": "https://community.chocolatey.org/content/packageimages/doom1-maps-dtwid.1.1.0.20200628.png", + "images": [] + }, + "doom2-maps-btsx-e1": { + "icon": "https://community.chocolatey.org/content/packageimages/doom2-maps-btsx-e1.1.1.5.png", + "images": [] + }, + "doom2-maps-btsx-e2": { + "icon": "https://community.chocolatey.org/content/packageimages/doom2-maps-btsx-e2.1.0.1.png", + "images": [] + }, + "doom2-maps-d2reload": { + "icon": "https://community.chocolatey.org/content/packageimages/doom2-maps-d2reload.11.10.09.20200628.png", + "images": [] + }, + "doom2-maps-epic2": { + "icon": "https://community.chocolatey.org/content/packageimages/doom2-maps-epic2.25.11.10.20200628.png", + "images": [] + }, + "doom2-maps-goingdown": { + "icon": "https://community.chocolatey.org/content/packageimages/doom2-maps-goingdown.11.02.14.20200823.png", + "images": [] + }, + "doom2-maps-nova3": { + "icon": "https://community.chocolatey.org/content/packageimages/doom2-maps-nova3.02.12.2019.20200628.png", + "images": [] + }, + "doom2-maps-scyte2": { + "icon": "", + "images": [] + }, + "doom2-maps-scythe2": { + "icon": "https://community.chocolatey.org/content/packageimages/doom2-maps-scythe2.25.03.2005.png", + "images": [] + }, + "doom4-death-foretold": { + "icon": "https://community.chocolatey.org/content/packageimages/doom4-death-foretold.2.5.0.20200628.png", + "images": [] + }, + "doomsday": { + "icon": "https://community.chocolatey.org/content/packageimages/doomsday.2.3.1.png", + "images": [] + }, + "doomseeker": { + "icon": "https://community.chocolatey.org/content/packageimages/doomseeker.1.3.2.png", + "images": [] + }, + "dooray!drive": { + "icon": "", + "images": [] + }, + "dooray!messenger": { + "icon": "", + "images": [] + }, + "dopamine": { + "icon": "https://community.chocolatey.org/content/packageimages/dopamine.2.0.8.png", + "images": [] + }, + "dopamine-2": { + "icon": "https://cdn.neowin.com/news/images/uploaded/2016/12/1483030869_dopamine_story.jpg", + "images": [] + }, + "dopamine-3": { + "icon": "https://cdn.neowin.com/news/images/uploaded/2016/12/1483030869_dopamine_story.jpg", + "images": [] + }, + "dopdf": { + "icon": "https://community.chocolatey.org/content/packageimages/doPDF.11.7.371.png", + "images": [] + }, + "dorion": { + "icon": "https://raw.githubusercontent.com/SpikeHD/Dorion/main/src-tauri/icons/icon.png", + "images": [ + "https://spikehd.github.io/projects/dorion/images/theme_full.png", + "https://spikehd.github.io/projects/dorion/images/settings_full.png", + "https://spikehd.github.io/projects/dorion/images/performancesettings.png", + "https://spikehd.github.io/projects/dorion/images/settings.png", + "https://spikehd.github.io/projects/dorion/images/shelter.png" + ] + }, + "doro": { + "icon": "https://community.chocolatey.org/content/packageimages/doro.install.2.20.png", + "images": [] + }, + "dos2unix": { + "icon": "", + "images": [] + }, + "dosbox": { + "icon": "https://community.chocolatey.org/content/packageimages/dosbox.0.74.3.0.png", + "images": [] + }, + "dosbox-staging": { + "icon": "", + "images": [] + }, + "dosbox-x": { + "icon": "", + "images": [] + }, + "dot11expert": { + "icon": "", + "images": [] + }, + "dotcover": { + "icon": "https://community.chocolatey.org/content/packageimages/dotCover.2022.3.2.png", + "images": [] + }, + "dotcover-cli": { + "icon": "https://community.chocolatey.org/content/packageimages/dotcover-cli.2022.3.png", + "images": [] + }, + "dotcover-clt": { + "icon": "", + "images": [] + }, + "dotdotgoose": { + "icon": "", + "images": [] + }, + "dotlocal": { + "icon": "", + "images": [] + }, + "dotmemory": { + "icon": "https://community.chocolatey.org/content/packageimages/dotMemory.2022.3.2.png", + "images": [] + }, + "dotmemory-clt": { + "icon": "", + "images": [] + }, + "dotmemory-console": { + "icon": "https://community.chocolatey.org/content/packageimages/dotmemory-console.portable.2022.1.2.png", + "images": [] + }, + "dotmemory-unit": { + "icon": "https://community.chocolatey.org/content/packageimages/dotmemory-unit.3.2.20220510.png", + "images": [] + }, + "dotmemoryunit": { + "icon": "", + "images": [] + }, + "dotnet": { + "icon": "https://community.chocolatey.org/content/packageimages/dotnet.7.0.3.png", + "images": [] + }, + "dotnet-4-6-2": { + "icon": "", + "images": [] + }, + "dotnet-5-0-aspnetruntime": { + "icon": "https://community.chocolatey.org/content/packageimages/dotnet-5.0-aspnetruntime.5.0.17.png", + "images": [] + }, + "dotnet-5-0-desktopruntime": { + "icon": "https://community.chocolatey.org/content/packageimages/dotnet-5.0-desktopruntime.5.0.17.png", + "images": [] + }, + "dotnet-5-0-runtime": { + "icon": "https://community.chocolatey.org/content/packageimages/dotnet-5.0-runtime.5.0.17.png", + "images": [] + }, + "dotnet-5-0-sdk": { + "icon": "https://community.chocolatey.org/content/packageimages/dotnet-5.0-sdk.5.0.408.png", + "images": [] + }, + "dotnet-5-0-sdk-1xx": { + "icon": "https://community.chocolatey.org/content/packageimages/dotnet-5.0-sdk-1xx.5.0.104.png", + "images": [] + }, + "dotnet-5-0-sdk-4xx": { + "icon": "https://community.chocolatey.org/content/packageimages/dotnet-5.0-sdk-4xx.5.0.408.png", + "images": [] + }, + "dotnet-5-0-windowshosting": { + "icon": "https://community.chocolatey.org/content/packageimages/dotnet-5.0-windowshosting.5.0.17.png", + "images": [] + }, + "dotnet-6-0-aspnetruntime": { + "icon": "https://community.chocolatey.org/content/packageimages/dotnet-6.0-aspnetruntime.6.0.14.png", + "images": [] + }, + "dotnet-6-0-desktopruntime": { + "icon": "https://community.chocolatey.org/content/packageimages/dotnet-6.0-desktopruntime.6.0.14.png", + "images": [] + }, + "dotnet-6-0-runtime": { + "icon": "https://community.chocolatey.org/content/packageimages/dotnet-6.0-runtime.6.0.14.png", + "images": [] + }, + "dotnet-6-0-sdk": { + "icon": "https://community.chocolatey.org/content/packageimages/dotnet-6.0-sdk.6.0.406.png", + "images": [] + }, + "dotnet-6-0-sdk-1xx": { + "icon": "https://community.chocolatey.org/content/packageimages/dotnet-6.0-sdk-1xx.6.0.114.png", + "images": [] + }, + "dotnet-6-0-sdk-3xx": { + "icon": "https://community.chocolatey.org/content/packageimages/dotnet-6.0-sdk-3xx.6.0.309.png", + "images": [] + }, + "dotnet-6-0-sdk-4xx": { + "icon": "https://community.chocolatey.org/content/packageimages/dotnet-6.0-sdk-4xx.6.0.406.png", + "images": [] + }, + "dotnet-6-0-windowshosting": { + "icon": "https://community.chocolatey.org/content/packageimages/dotnet-6.0-windowshosting.6.0.14.png", + "images": [] + }, + "dotnet-7-0-aspnetruntime": { + "icon": "https://community.chocolatey.org/content/packageimages/dotnet-7.0-aspnetruntime.7.0.3.png", + "images": [] + }, + "dotnet-7-0-desktopruntime": { + "icon": "https://community.chocolatey.org/content/packageimages/dotnet-7.0-desktopruntime.7.0.3.png", + "images": [] + }, + "dotnet-7-0-runtime": { + "icon": "https://community.chocolatey.org/content/packageimages/dotnet-7.0-runtime.7.0.3.png", + "images": [] + }, + "dotnet-7-0-sdk": { + "icon": "https://community.chocolatey.org/content/packageimages/dotnet-7.0-sdk.7.0.201.png", + "images": [] + }, + "dotnet-7-0-sdk-1xx": { + "icon": "https://community.chocolatey.org/content/packageimages/dotnet-7.0-sdk-1xx.7.0.103.png", + "images": [] + }, + "dotnet-7-0-sdk-2xx": { + "icon": "https://community.chocolatey.org/content/packageimages/dotnet-7.0-sdk-2xx.7.0.201.png", + "images": [] + }, + "dotnet-7-0-windowshosting": { + "icon": "https://community.chocolatey.org/content/packageimages/dotnet-7.0-windowshosting.7.0.3.png", + "images": [] + }, + "dotnet-aspnetcore-3-1": { + "icon": "https://raw.githubusercontent.com/dotnetcore-chocolatey/dotnetcore-chocolateypackages/master/icons/dotnetcore.png", + "images": [] + }, + "dotnet-aspnetcore-5": { + "icon": "https://raw.githubusercontent.com/dotnetcore-chocolatey/dotnetcore-chocolateypackages/master/icons/dotnetcore.png", + "images": [] + }, + "dotnet-aspnetcore-6": { + "icon": "https://raw.githubusercontent.com/dotnetcore-chocolatey/dotnetcore-chocolateypackages/master/icons/dotnetcore.png", + "images": [] + }, + "dotnet-aspnetcore-7": { + "icon": "https://raw.githubusercontent.com/dotnetcore-chocolatey/dotnetcore-chocolateypackages/master/icons/dotnetcore.png", + "images": [] + }, + "dotnet-aspnetcore-8": { + "icon": "https://raw.githubusercontent.com/dotnetcore-chocolatey/dotnetcore-chocolateypackages/master/icons/dotnetcore.png", + "images": [] + }, + "dotnet-aspnetcore-preview": { + "icon": "", + "images": [] + }, + "dotnet-aspnetcoremodule-v2": { + "icon": "https://community.chocolatey.org/content/packageimages/dotnet-aspnetcoremodule-v2.17.0.23030.png", + "images": [] + }, + "dotnet-aspnetruntime": { + "icon": "https://community.chocolatey.org/content/packageimages/dotnet-aspnetruntime.7.0.3.png", + "images": [] + }, + "dotnet-desktopruntime": { + "icon": "https://raw.githubusercontent.com/dotnetcore-chocolatey/dotnetcore-chocolateypackages/master/icons/dotnetcore.png", + "images": [] + }, + "dotnet-desktopruntime-10": { + "icon": "https://i.ibb.co/sdzNm4Dp/image.png", + "images": [] + }, + "dotnet-desktopruntime-3_1": { + "icon": "https://raw.githubusercontent.com/dotnetcore-chocolatey/dotnetcore-chocolateypackages/master/icons/dotnetcore.png", + "images": [] + }, + "dotnet-desktopruntime-5": { + "icon": "https://raw.githubusercontent.com/dotnetcore-chocolatey/dotnetcore-chocolateypackages/master/icons/dotnetcore.png", + "images": [] + }, + "dotnet-desktopruntime-6": { + "icon": "https://raw.githubusercontent.com/dotnetcore-chocolatey/dotnetcore-chocolateypackages/master/icons/dotnetcore.png", + "images": [] + }, + "dotnet-desktopruntime-7": { + "icon": "https://raw.githubusercontent.com/dotnetcore-chocolatey/dotnetcore-chocolateypackages/master/icons/dotnetcore.png", + "images": [] + }, + "dotnet-desktopruntime-8": { + "icon": "https://i.ibb.co/sdzNm4Dp/image.png", + "images": [] + }, + "dotnet-desktopruntime-9": { + "icon": "https://i.ibb.co/sdzNm4Dp/image.png", + "images": [] + }, + "dotnet-generic-unpacker": { + "icon": "", + "images": [] + }, + "dotnet-hostingbundle-3-1": { + "icon": "", + "images": [] + }, + "dotnet-hostingbundle-5": { + "icon": "", + "images": [] + }, + "dotnet-hostingbundle-6": { + "icon": "", + "images": [] + }, + "dotnet-hostingbundle-7": { + "icon": "", + "images": [] + }, + "dotnet-runtime-3-1": { + "icon": "https://community.chocolatey.org/content/packageimages/dotnetcore-3.1-runtime.3.1.32.png", + "images": [] + }, + "dotnet-runtime-5": { + "icon": "https://community.chocolatey.org/content/packageimages/dotnet-5.0-runtime.5.0.17.png", + "images": [] + }, + "dotnet-runtime-6": { + "icon": "https://community.chocolatey.org/content/packageimages/dotnet-6.0-runtime.6.0.24.png", + "images": [] + }, + "dotnet-runtime-7": { + "icon": "https://community.chocolatey.org/content/packageimages/dotnet-7.0-runtime.7.0.13.png", + "images": [] + }, + "dotnet-runtime-preview": { + "icon": "", + "images": [] + }, + "dotnet-script": { + "icon": "https://community.chocolatey.org/content/packageimages/dotnet.script.1.3.1.png", + "images": [] + }, + "dotnet-sdk": { + "icon": "https://community.chocolatey.org/content/packageimages/dotnet-sdk.7.0.201.png", + "images": [] + }, + "dotnet-sdk-3-1": { + "icon": "https://community.chocolatey.org/content/packageimages/dotnetcore-3.1-sdk.3.1.426.png", + "images": [] + }, + "dotnet-sdk-5": { + "icon": "https://community.chocolatey.org/content/packageimages/dotnet-5.0-sdk.5.0.408.png", + "images": [] + }, + "dotnet-sdk-6": { + "icon": "https://community.chocolatey.org/content/packageimages/dotnet-6.0-sdk.6.0.416.png", + "images": [] + }, + "dotnet-sdk-7": { + "icon": "https://community.chocolatey.org/content/packageimages/dotnet-7.0-sdk.7.0.403.png", + "images": [] + }, + "dotnet-sdk-preview": { + "icon": "", + "images": [] + }, + "dotnet-verification-tool": { + "icon": "", + "images": [] + }, + "dotnet1-1": { + "icon": "https://community.chocolatey.org/content/packageimages/dotnet1.1.1.1.png", + "images": [] + }, + "dotnet3-5": { + "icon": "https://community.chocolatey.org/content/packageimages/DotNet3.5.3.5.20160716.png", + "images": [] + }, + "dotnet4-0": { + "icon": "https://community.chocolatey.org/content/packageimages/DotNet4.0.4.0.30319.20141222.png", + "images": [] + }, + "dotnet4-5": { + "icon": "https://community.chocolatey.org/content/packageimages/DotNet4.5.4.5.20120822.png", + "images": [] + }, + "dotnet4-5-2": { + "icon": "https://community.chocolatey.org/content/packageimages/DotNet4.5.2.4.5.2.20140902.png", + "images": [] + }, + "dotnet4-6": { + "icon": "https://community.chocolatey.org/content/packageimages/DotNet4.6.4.6.00081.20150925.png", + "images": [] + }, + "dotnet4-6-1": { + "icon": "https://community.chocolatey.org/content/packageimages/DotNet4.6.1.4.6.01055.20170308.png", + "images": [] + }, + "dotnet4-6-1-devpack": { + "icon": "https://community.chocolatey.org/content/packageimages/DotNet4.6.1-DevPack.4.6.01055.0.png", + "images": [] + }, + "dotnet4-6-2": { + "icon": "https://community.chocolatey.org/content/packageimages/dotnet4.6.2.4.6.01590.20190822.png", + "images": [] + }, + "dotnet4-6-targetpack": { + "icon": "https://community.chocolatey.org/content/packageimages/DotNet4.6-TargetPack.4.6.00081.20150925.png", + "images": [] + }, + "dotnet4-7": { + "icon": "https://community.chocolatey.org/content/packageimages/dotnet4.7.4.7.2053.20190226.png", + "images": [] + }, + "dotnet4-7-1": { + "icon": "https://community.chocolatey.org/content/packageimages/dotnet4.7.1.4.7.2558.20190226.png", + "images": [] + }, + "dotnet4-7-2": { + "icon": "https://community.chocolatey.org/content/packageimages/dotnet4.7.2.4.7.2.20210903.png", + "images": [] + }, + "dotnet5-desktop-runtime": { + "icon": "", + "images": [] + }, + "dotnetcore-2-0-runtime": { + "icon": "https://community.chocolatey.org/content/packageimages/dotnetcore-2.0-runtime.2.0.9.png", + "images": [] + }, + "dotnetcore-2-1-runtime": { + "icon": "https://community.chocolatey.org/content/packageimages/dotnetcore-2.1-runtime.2.1.30.png", + "images": [] + }, + "dotnetcore-2-1-sdk": { + "icon": "https://community.chocolatey.org/content/packageimages/dotnetcore-2.1-sdk.2.1.818.png", + "images": [] + }, + "dotnetcore-2-1-sdk-6xx": { + "icon": "https://community.chocolatey.org/content/packageimages/dotnetcore-2.1-sdk-6xx.2.1.617.png", + "images": [] + }, + "dotnetcore-2-1-sdk-8xx": { + "icon": "https://community.chocolatey.org/content/packageimages/dotnetcore-2.1-sdk-8xx.2.1.818.png", + "images": [] + }, + "dotnetcore-2-1-windowshosting": { + "icon": "https://community.chocolatey.org/content/packageimages/dotnetcore-2.1-windowshosting.2.1.30.png", + "images": [] + }, + "dotnetcore-2-2-aspnetruntime": { + "icon": "https://community.chocolatey.org/content/packageimages/dotnetcore-2.2-aspnetruntime.2.2.8.png", + "images": [] + }, + "dotnetcore-2-2-runtime": { + "icon": "https://community.chocolatey.org/content/packageimages/dotnetcore-2.2-runtime.2.2.8.png", + "images": [] + }, + "dotnetcore-2-2-sdk": { + "icon": "https://community.chocolatey.org/content/packageimages/dotnetcore-2.2-sdk.2.2.402.png", + "images": [] + }, + "dotnetcore-2-2-sdk-1xx": { + "icon": "https://community.chocolatey.org/content/packageimages/dotnetcore-2.2-sdk-1xx.2.2.110.png", + "images": [] + }, + "dotnetcore-2-2-sdk-2xx": { + "icon": "https://community.chocolatey.org/content/packageimages/dotnetcore-2.2-sdk-2xx.2.2.207.png", + "images": [] + }, + "dotnetcore-2-2-sdk-4xx": { + "icon": "https://community.chocolatey.org/content/packageimages/dotnetcore-2.2-sdk-4xx.2.2.402.png", + "images": [] + }, + "dotnetcore-2-2-windowshosting": { + "icon": "https://community.chocolatey.org/content/packageimages/dotnetcore-2.2-windowshosting.2.2.8.png", + "images": [] + }, + "dotnetcore-3-0-desktopruntime": { + "icon": "https://community.chocolatey.org/content/packageimages/dotnetcore-3.0-desktopruntime.3.0.3.png", + "images": [] + }, + "dotnetcore-3-0-runtime": { + "icon": "https://community.chocolatey.org/content/packageimages/dotnetcore-3.0-runtime.3.0.3.png", + "images": [] + }, + "dotnetcore-3-0-sdk": { + "icon": "https://community.chocolatey.org/content/packageimages/dotnetcore-3.0-sdk.3.0.103.png", + "images": [] + }, + "dotnetcore-3-0-sdk-1xx": { + "icon": "https://community.chocolatey.org/content/packageimages/dotnetcore-3.0-sdk-1xx.3.0.103.png", + "images": [] + }, + "dotnetcore-3-1-aspnetruntime": { + "icon": "https://community.chocolatey.org/content/packageimages/dotnetcore-3.1-aspnetruntime.3.1.32.png", + "images": [] + }, + "dotnetcore-3-1-runtime": { + "icon": "https://community.chocolatey.org/content/packageimages/dotnetcore-3.1-runtime.3.1.32.png", + "images": [] + }, + "dotnetcore-3-1-sdk": { + "icon": "https://community.chocolatey.org/content/packageimages/dotnetcore-3.1-sdk.3.1.426.png", + "images": [] + }, + "dotnetcore-3-1-sdk-1xx": { + "icon": "https://community.chocolatey.org/content/packageimages/dotnetcore-3.1-sdk-1xx.3.1.120.png", + "images": [] + }, + "dotnetcore-3-1-sdk-4xx": { + "icon": "https://community.chocolatey.org/content/packageimages/dotnetcore-3.1-sdk-4xx.3.1.426.png", + "images": [] + }, + "dotnetcore-3-1-windowshosting": { + "icon": "https://community.chocolatey.org/content/packageimages/dotnetcore-3.1-windowshosting.3.1.32.png", + "images": [] + }, + "dotnetcore-aspnetruntime": { + "icon": "https://community.chocolatey.org/content/packageimages/dotnetcore-aspnetruntime.3.1.32.png", + "images": [] + }, + "dotnetcore-desktopruntime": { + "icon": "https://community.chocolatey.org/content/packageimages/dotnetcore-desktopruntime.3.1.32.png", + "images": [] + }, + "dotnetcore-runtime": { + "icon": "https://community.chocolatey.org/content/packageimages/dotnetcore-runtime.portable.3.1.32.png", + "images": [] + }, + "dotnetcore-sdk": { + "icon": "https://community.chocolatey.org/content/packageimages/dotnetcore-sdk.3.1.426.png", + "images": [] + }, + "dotnetcoresdk": { + "icon": "https://community.chocolatey.org/content/packageimages/dotnetcoresdk.1.0.1.png", + "images": [] + }, + "dotnetinstaller": { + "icon": "https://community.chocolatey.org/content/packageimages/dotnetinstaller.2.4.png", + "images": [] + }, + "dotnetreactor": { + "icon": "", + "images": [ + "https://www.eziriz.com/images/screenshot_r_files_m.jpg", + "https://www.eziriz.com/images/screenshot_r_settings1_m.jpg", + "https://www.eziriz.com/images/screenshot_r_settings2_m.jpg", + "https://www.eziriz.com/images/screenshot_r_settings3_m.jpg", + "https://www.eziriz.com/images/screenshot_r_lm_m.jpg", + "https://www.eziriz.com/images/screenshot_r_inspector_m.jpg", + "https://www.eziriz.com/images/screenshot_r_presets_m.jpg", + "https://www.eziriz.com/images/screenshot_r_protect_m.jpg", + "https://www.eziriz.com/images/screenshot_r_rules_m.jpg", + "https://www.eziriz.com/images/screenshot_deobfuscator_m.jpg", + "https://www.eziriz.com/images/screenshot_nr_dark_m.jpg", + "https://www.eziriz.com/images/screenshot_nr_green_m.jpg", + "https://www.eziriz.com/images/screenshot_nr_classic_m.jpg" + ] + }, + "dotnetresourcesextract": { + "icon": "https://community.chocolatey.org/content/packageimages/dotnetresourcesextract.1.01.png", + "images": [] + }, + "dotnetsmoketest2": { + "icon": "https://community.chocolatey.org/content/packageimages/dotnetsmoketest2.2.3.16.1.png", + "images": [] + }, + "dotnetsmoketest4": { + "icon": "https://community.chocolatey.org/content/packageimages/dotnetsmoketest4.4.1.16.1.png", + "images": [] + }, + "dotnetuninstalltool": { + "icon": "", + "images": [] + }, + "dotnetversiondetector": { + "icon": "https://community.chocolatey.org/content/packageimages/dotnetversiondetector.21.1.0.png", + "images": [] + }, + "dotpeek": { + "icon": "https://community.chocolatey.org/content/packageimages/dotpeek.portable.10.0.2.1.png", + "images": [] + }, + "dotter": { + "icon": "", + "images": [] + }, + "dottorrent-gui": { + "icon": "", + "images": [] + }, + "dottrace": { + "icon": "https://community.chocolatey.org/content/packageimages/dotTrace.2022.3.2.png", + "images": [] + }, + "dottrace-api": { + "icon": "", + "images": [] + }, + "dottrace-clt": { + "icon": "", + "images": [] + }, + "dottrace-memory": { + "icon": "", + "images": [] + }, + "dotultimate": { + "icon": "https://computermalaysia.com.my/media/catalog/product/cache/1/thumbnail/500x500/9df78eab33525d08d6e5fb8d27136e95/d/o/dotultimate.png", + "images": [] + }, + "doublecadxt": { + "icon": "https://community.chocolatey.org/content/packageimages/doublecadxt.5.0.30.2.png", + "images": [] + }, + "doublecmd": { + "icon": "https://community.chocolatey.org/content/packageimages/doublecmd.1.0.10.png", + "images": [] + }, + "doublecommander": { + "icon": "https://w7.pngwing.com/pngs/493/1012/png-transparent-double-commander-file-manager-computer-icons-manager-miscellaneous-rectangle-orange.png", + "images": [] + }, + "doubledriver": { + "icon": "https://community.chocolatey.org/content/packageimages/doubledriver.4.1.png", + "images": [] + }, + "doublemousedownloader": { + "icon": "", + "images": [] + }, + "doulossil": { + "icon": "https://community.chocolatey.org/content/packageimages/doulossil.5.0.png", + "images": [] + }, + "douyin": { + "icon": "", + "images": [] + }, + "douyinide": { + "icon": "", + "images": [] + }, + "douyinim": { + "icon": "", + "images": [] + }, + "douyulive": { + "icon": "", + "images": [] + }, + "downloadapp": { + "icon": "", + "images": [] + }, + "downloader": { + "icon": "", + "images": [] + }, + "downloadmanager": { + "icon": "", + "images": [ + "https://raw.githubusercontent.com/Download-Manager-Community/Download-Manager/master/.github/images/UniGetUI/DownloadManagerMain.png", + "https://raw.githubusercontent.com/Download-Manager-Community/Download-Manager/master/.github/images/UniGetUI/DownloadManagerSettings.png", + "https://raw.githubusercontent.com/Download-Manager-Community/Download-Manager/master/.github/images/UniGetUI/DownloadManagerDownload.png", + "https://raw.githubusercontent.com/Download-Manager-Community/Download-Manager/master/.github/images/UniGetUI/DownloadManagerExt.png" + ] + }, + "downtester": { + "icon": "https://i.postimg.cc/P5FDkNrP/image.png", + "images": [ + "https://i.postimg.cc/90jTNSXc/image.png" + ] + }, + "downzemall": { + "icon": "https://community.chocolatey.org/content/packageimages/downzemall.3.0.2.png", + "images": [] + }, + "doxie": { + "icon": "https://community.chocolatey.org/content/packageimages/doxie.3.1.png", + "images": [] + }, + "doxygen": { + "icon": "https://static.macupdate.com/products/51038/l/doxygen-logo.png", + "images": [] + }, + "dprint": { + "icon": "", + "images": [] + }, + "draft": { + "icon": "", + "images": [] + }, + "draftsight": { + "icon": "https://community.chocolatey.org/content/packageimages/draftsight.2022.1.0055.png", + "images": [] + }, + "drasyl": { + "icon": "", + "images": [] + }, + "draw": { + "icon": "", + "images": [] + }, + "draw-io": { + "icon": "https://raw.githubusercontent.com/jgraph/drawio-desktop/dev/build/1024x1024.png", + "images": [] + }, + "drawio": { + "icon": "https://community.chocolatey.org/content/packageimages/drawio.20.8.16.png", + "images": [] + }, + "drawpile": { + "icon": "https://community.chocolatey.org/content/packageimages/drawpile.2.1.20.png", + "images": [] + }, + "dreampie": { + "icon": "https://community.chocolatey.org/content/packageimages/dreampie.1.2.1.png", + "images": [] + }, + "dreamset": { + "icon": "", + "images": [] + }, + "drexplain": { + "icon": "", + "images": [] + }, + "dripcap": { + "icon": "", + "images": [] + }, + "drive": { + "icon": "https://i.imgur.com/LowtJVt.png", + "images": [] + }, + "drive-letter-changer": { + "icon": "", + "images": [] + }, + "driveclient": { + "icon": "", + "images": [] + }, + "driveletterview": { + "icon": "", + "images": [] + }, + "driver-officegate": { + "icon": "https://community.chocolatey.org/content/packageimages/driver-officegate.1.0.0.0.png", + "images": [] + }, + "driverbooster": { + "icon": "https://community.chocolatey.org/content/packageimages/driverbooster.11.5.0.85.png", + "images": [] + }, + "drivereasy": { + "icon": "https://community.chocolatey.org/content/packageimages/drivereasyfree.6.0.0.png", + "images": [ + "https://i.postimg.cc/KYP7xy8c/image.png", + "https://i.postimg.cc/x8CLvJyq/image.png", + "https://i.postimg.cc/pTkD5Yjg/image.png" + ] + }, + "drivereasyfree": { + "icon": "https://community.chocolatey.org/content/packageimages/drivereasyfree.5.7.4.png", + "images": [] + }, + "driverfusion": { + "icon": "https://community.chocolatey.org/content/packageimages/driverfusion.10.1.png", + "images": [] + }, + "drivergenius": { + "icon": "https://community.chocolatey.org/content/packageimages/drivergenius.19.0.0.145.png", + "images": [] + }, + "driverpacksolution": { + "icon": "https://community.chocolatey.org/content/packageimages/driverpacksolution.17.2017.2.22.png", + "images": [] + }, + "driverscloud": { + "icon": "", + "images": [] + }, + "driverstoreexplorer": { + "icon": "https://i.ibb.co/dwC17cP4/icon2-upscayl-5x-ultramix-balanced-4x.png", + "images": [] + }, + "driverview": { + "icon": "https://community.chocolatey.org/content/packageimages/driverview.1.47.png", + "images": [] + }, + "drivesnapshot": { + "icon": "https://community.chocolatey.org/content/packageimages/drivesnapshot.1.50.1094.png", + "images": [] + }, + "drkspider": { + "icon": "", + "images": [] + }, + "drmemory": { + "icon": "", + "images": [] + }, + "drmips": { + "icon": "", + "images": [] + }, + "droidcam": { + "icon": "", + "images": [] + }, + "droidcam-obs-plugin": { + "icon": "https://community.chocolatey.org/content/packageimages/droidcam-obs-plugin.2.0.1.png", + "images": [] + }, + "droidcamclient": { + "icon": "https://community.chocolatey.org/content/packageimages/droidcamclient.6.5.2.png", + "images": [] + }, + "drone": { + "icon": "", + "images": [] + }, + "dropbox": { + "icon": "https://i.postimg.cc/kgM4jKJ1/Dropbox-icon-icons-com-66767.png", + "images": [ + "https://i.postimg.cc/7L8v9knn/drop1.png", + "https://i.postimg.cc/P5QWQRZ2/dropp.png" + ] + }, + "dropboxifier": { + "icon": "https://community.chocolatey.org/content/packageimages/dropboxifier.0.1.8.png", + "images": [] + }, + "dropit": { + "icon": "https://community.chocolatey.org/content/packageimages/dropit.portable.8.5.1.png", + "images": [] + }, + "dropkick": { + "icon": "", + "images": [] + }, + "droppoint": { + "icon": "", + "images": [] + }, + "drovio": { + "icon": "", + "images": [] + }, + "drupal": { + "icon": "https://i.postimg.cc/9fG6Nnx5/druplicon-small.png", + "images": [] + }, + "drush-commandline": { + "icon": "", + "images": [] + }, + "ds4windows": { + "icon": "https://community.chocolatey.org/content/packageimages/ds4windows.3.2.8.png", + "images": [] + }, + "dsc-computermanagement": { + "icon": "", + "images": [] + }, + "dsc-dscresourcedesigner": { + "icon": "", + "images": [] + }, + "dsc-hyperv": { + "icon": "", + "images": [] + }, + "dsc-networking": { + "icon": "", + "images": [] + }, + "dsc-powershellcommunity": { + "icon": "", + "images": [] + }, + "dsc-psdesiredstateconfiguration": { + "icon": "", + "images": [] + }, + "dsc-webadministration": { + "icon": "", + "images": [] + }, + "dsclock": { + "icon": "", + "images": [] + }, + "dsinternals-psmodule": { + "icon": "https://community.chocolatey.org/content/packageimages/dsinternals-psmodule.4.9.png", + "images": [] + }, + "dspeech": { + "icon": "https://community.chocolatey.org/content/packageimages/dspeech.1.73.1.png", + "images": [] + }, + "dsynchronize": { + "icon": "https://community.chocolatey.org/content/packageimages/dsynchronize.2.48.png", + "images": [] + }, + "dt-agent": { + "icon": "", + "images": [] + }, + "dt-clientextension": { + "icon": "", + "images": [] + }, + "dt-console": { + "icon": "", + "images": [] + }, + "dtc-msys2": { + "icon": "https://community.chocolatey.org/content/packageimages/dtc-msys2.1.5.1.png", + "images": [] + }, + "dtksneak": { + "icon": "https://community.chocolatey.org/content/packageimages/dtksneak.1.0.0.20150826.png", + "images": [] + }, + "du": { + "icon": "https://community.chocolatey.org/content/packageimages/du.1.62.png", + "images": [] + }, + "dua": { + "icon": "", + "images": [] + }, + "dual-monitor-tools": { + "icon": "", + "images": [] + }, + "dualism": { + "icon": "https://community.chocolatey.org/content/packageimages/dualism.1.16.20221112.png", + "images": [] + }, + "dualiza": { + "icon": "", + "images": [] + }, + "dualmonitortaskbar": { + "icon": "", + "images": [] + }, + "dualmonitortools": { + "icon": "https://i.postimg.cc/hj7BR1nL/dual-monitor-tools-176.png", + "images": [] + }, + "dualsensefwupdater": { + "icon": "", + "images": [] + }, + "dualuniverse": { + "icon": "", + "images": [] + }, + "duan-tre-command": { + "icon": "", + "images": [] + }, + "dub": { + "icon": "https://community.chocolatey.org/content/packageimages/dub.1.11.0.png", + "images": [] + }, + "duc": { + "icon": "", + "images": [] + }, + "ducible": { + "icon": "", + "images": [] + }, + "duck": { + "icon": "https://community.chocolatey.org/content/packageimages/duck.8.5.6.39394.png", + "images": [] + }, + "duckdb": { + "icon": "", + "images": [] + }, + "duckdns": { + "icon": "", + "images": [] + }, + "duckietv": { + "icon": "https://community.chocolatey.org/content/packageimages/duckietv.1.1.5.png", + "images": [] + }, + "duetdisplay": { + "icon": "", + "images": [] + }, + "duf": { + "icon": "https://community.chocolatey.org/content/packageimages/duf.0.8.1.png", + "images": [] + }, + "dufs": { + "icon": "", + "images": [] + }, + "dug": { + "icon": "", + "images": [] + }, + "dukto": { + "icon": "https://community.chocolatey.org/content/packageimages/dukto.6.0.0.20192215.png", + "images": [] + }, + "dum": { + "icon": "", + "images": [] + }, + "dumeter": { + "icon": "https://community.chocolatey.org/content/packageimages/dumeter.6.40.20141201.png", + "images": [ + "https://i.postimg.cc/3W5RwdTK/image.png", + "https://i.postimg.cc/SKNW4td8/image.png", + "https://i.postimg.cc/htMd21nJ/image.png", + "https://i.postimg.cc/LsbZp4np/image.png", + "https://i.postimg.cc/D0qWLq6D/image.png" + ] + }, + "dumo": { + "icon": "https://community.chocolatey.org/content/packageimages/dumo.2.25.2.122.png", + "images": [] + }, + "dumpedid": { + "icon": "", + "images": [] + }, + "dungeoncrawlstonesoup": { + "icon": "", + "images": [] + }, + "dupeguru": { + "icon": "https://community.chocolatey.org/content/packageimages/dupeguru.4.3.1.png", + "images": [] + }, + "dupeguru-me": { + "icon": "https://community.chocolatey.org/content/packageimages/dupeguru-me.6.8.1.png", + "images": [] + }, + "dupeguru-pe": { + "icon": "https://community.chocolatey.org/content/packageimages/dupeguru-pe.2.10.1.png", + "images": [] + }, + "dupemerge": { + "icon": "https://community.chocolatey.org/content/packageimages/dupemerge.1.104.png", + "images": [] + }, + "duplicacy": { + "icon": "https://community.chocolatey.org/content/packageimages/duplicacy.3.1.0.png", + "images": [] + }, + "duplicacyweb": { + "icon": "", + "images": [] + }, + "duplicatefilefinder": { + "icon": "", + "images": [ + "https://i.postimg.cc/s2K14gcs/image.png", + "https://i.postimg.cc/B66bYfYD/image.png", + "https://i.postimg.cc/Tw4wBNFs/image.png", + "https://i.postimg.cc/D04ZhdKw/image.png" + ] + }, + "duplicatemusicfixer": { + "icon": "", + "images": [] + }, + "duplicati": { + "icon": "https://community.chocolatey.org/content/packageimages/duplicati.portable.2.0.3.3.png", + "images": [] + }, + "durandal-extensions-vs2013": { + "icon": "", + "images": [] + }, + "duskplayer": { + "icon": "", + "images": [] + }, + "dust": { + "icon": "", + "images": [] + }, + "dvassist": { + "icon": "", + "images": [] + }, + "dvc": { + "icon": "https://community.chocolatey.org/content/packageimages/dvc.2.45.1.png", + "images": [] + }, + "dvdcreator": { + "icon": "", + "images": [] + }, + "dvdflick": { + "icon": "", + "images": [] + }, + "dvdstyler": { + "icon": "https://linuxmasterclub.com/wp-content/uploads/2020/12/DVDStyler-logo.png", + "images": [ + "https://upload.wikimedia.org/wikipedia/commons/b/b4/DVDStyler_Screenshot_1.png" + ] + }, + "dwarf-fortress": { + "icon": "https://community.chocolatey.org/content/packageimages/dwarf-fortress.0.47.05.png", + "images": [] + }, + "dwgtrueview": { + "icon": "https://community.chocolatey.org/content/packageimages/dwgtrueview.2023.24.2.72.png", + "images": [] + }, + "dwords2": { + "icon": "", + "images": [] + }, + "dws": { + "icon": "https://community.chocolatey.org/content/packageimages/dws.portable.2.2.2.2.png", + "images": [] + }, + "dxenterprise": { + "icon": "", + "images": [] + }, + "dxftoqet": { + "icon": "", + "images": [] + }, + "dxirc": { + "icon": "", + "images": [] + }, + "dxwnd": { + "icon": "", + "images": [] + }, + "dymo-connect": { + "icon": "https://community.chocolatey.org/content/packageimages/dymo-connect.1.3.1.png", + "images": [] + }, + "dymoconnect": { + "icon": "", + "images": [] + }, + "dymolabel": { + "icon": "", + "images": [] + }, + "dynalist": { + "icon": "", + "images": [] + }, + "dynamorio": { + "icon": "", + "images": [] + }, + "dynare": { + "icon": "", + "images": [] + }, + "dynatraceagent": { + "icon": "", + "images": [] + }, + "dynatraceclient": { + "icon": "", + "images": [] + }, + "dzlauncher": { + "icon": "", + "images": [] + }, + "e-haushaltsbuch": { + "icon": "https://community.chocolatey.org/content/packageimages/e-Haushaltsbuch.1.9.5.png", + "images": [] + }, + "ea-app": { + "icon": "https://community.chocolatey.org/content/packageimages/ea-app.13.218.0.5731.png", + "images": [ + "https://i.postimg.cc/8cPmZnDp/image.png", + "https://i.postimg.cc/Vk34zR9g/image.png", + "https://i.postimg.cc/8PcbW3tw/image.png" + ] + }, + "eac": { + "icon": "", + "images": [] + }, + "eac3to": { + "icon": "", + "images": [] + }, + "eadesktop": { + "icon": "https://community.chocolatey.org/content/packageimages/ea-app.13.218.0.5731.png", + "images": [ + "https://i.postimg.cc/8cPmZnDp/image.png", + "https://i.postimg.cc/Vk34zR9g/image.png", + "https://i.postimg.cc/8PcbW3tw/image.png" + ] + }, + "eagle": { + "icon": "https://i.postimg.cc/PrVFhCy0/Eagle.png", + "images": [ + "https://i.postimg.cc/yY2Xvcv6/image.png" + ] + }, + "eagleget": { + "icon": "", + "images": [] + }, + "eagluet": { + "icon": "", + "images": [] + }, + "earth-alerts": { + "icon": "", + "images": [] + }, + "earthly": { + "icon": "", + "images": [] + }, + "earthpro": { + "icon": "https://images.icon-icons.com/188/PNG/256/Google_Earth_22883.png", + "images": [] + }, + "earthview": { + "icon": "", + "images": [] + }, + "earthview-chrome": { + "icon": "https://community.chocolatey.org/content/packageimages/earthview-chrome.2.18.5.png", + "images": [] + }, + "eartrumpet": { + "icon": "https://raw.githubusercontent.com/File-New-Project/EarTrumpet/master/EarTrumpet/Assets/Logo-Light.png", + "images": [] + }, + "easinote": { + "icon": "", + "images": [] + }, + "eassosrecovery": { + "icon": "", + "images": [] + }, + "easy-context-menu": { + "icon": "", + "images": [] + }, + "easy7zip": { + "icon": "", + "images": [] + }, + "easyboot": { + "icon": "", + "images": [] + }, + "easyconnect": { + "icon": "https://community.chocolatey.org/content/packageimages/easyconnect.3.0.0.82.png", + "images": [] + }, + "easyeda": { + "icon": "", + "images": [] + }, + "easylogusb": { + "icon": "https://community.chocolatey.org/content/packageimages/easylogusb.7.7.0.png", + "images": [] + }, + "easyrsa": { + "icon": "", + "images": [] + }, + "easyserviceoptimizer": { + "icon": "", + "images": [] + }, + "easytag": { + "icon": "https://community.chocolatey.org/content/packageimages/easytag.2.4.3.png", + "images": [] + }, + "easytune6": { + "icon": "https://community.chocolatey.org/content/packageimages/easytune6.15.0210.1.2.png", + "images": [] + }, + "easyuefi": { + "icon": "https://community.chocolatey.org/content/packageimages/easyuefi.4.9.png", + "images": [] + }, + "easyworship": { + "icon": "", + "images": [] + }, + "eazfuscator-net": { + "icon": "", + "images": [] + }, + "ebay-chrome": { + "icon": "", + "images": [] + }, + "ebbflow": { + "icon": "https://community.chocolatey.org/content/packageimages/ebbflow.1.1.0.png", + "images": [] + }, + "ec2-api-tools": { + "icon": "", + "images": [] + }, + "ec2clitools": { + "icon": "https://community.chocolatey.org/content/packageimages/ec2clitools.1.7.5.1.png", + "images": [] + }, + "echess": { + "icon": "", + "images": [] + }, + "echo": { + "icon": "", + "images": [ + "https://i.imgur.com/HRpmT0v.png" + ] + }, + "echoargs": { + "icon": "", + "images": [] + }, + "echosync": { + "icon": "", + "images": [] + }, + "echotool": { + "icon": "", + "images": [] + }, + "eclipse": { + "icon": "https://community.chocolatey.org/content/packageimages/eclipse.4.26.png", + "images": [] + }, + "eclipse-android": { + "icon": "", + "images": [] + }, + "eclipse-automotive": { + "icon": "", + "images": [] + }, + "eclipse-classic-juno": { + "icon": "", + "images": [] + }, + "eclipse-committers": { + "icon": "", + "images": [] + }, + "eclipse-cpp": { + "icon": "https://community.chocolatey.org/content/packageimages/eclipse-cpp.2022.12.png", + "images": [] + }, + "eclipse-cpp-oxygen": { + "icon": "", + "images": [] + }, + "eclipse-dsl": { + "icon": "", + "images": [] + }, + "eclipse-embedcpp": { + "icon": "", + "images": [] + }, + "eclipse-java": { + "icon": "", + "images": [] + }, + "eclipse-java-juno": { + "icon": "https://community.chocolatey.org/content/packageimages/eclipse-java-juno.4.2.20121004.png", + "images": [] + }, + "eclipse-java-kepler": { + "icon": "https://community.chocolatey.org/content/packageimages/eclipse-java-kepler.4.3.1.png", + "images": [] + }, + "eclipse-java-luna": { + "icon": "https://community.chocolatey.org/content/packageimages/eclipse-java-luna.4.4.png", + "images": [] + }, + "eclipse-java-oxygen": { + "icon": "https://community.chocolatey.org/content/packageimages/eclipse-java-oxygen.2022.12.png", + "images": [] + }, + "eclipse-javaee-juno": { + "icon": "", + "images": [] + }, + "eclipse-javascript": { + "icon": "", + "images": [] + }, + "eclipse-jee": { + "icon": "", + "images": [] + }, + "eclipse-jee-luna": { + "icon": "https://community.chocolatey.org/content/packageimages/eclipse-jee-luna.4.4.png", + "images": [] + }, + "eclipse-mat": { + "icon": "", + "images": [] + }, + "eclipse-modeling": { + "icon": "", + "images": [] + }, + "eclipse-parallel": { + "icon": "", + "images": [] + }, + "eclipse-php": { + "icon": "", + "images": [] + }, + "eclipse-platform": { + "icon": "", + "images": [] + }, + "eclipse-rcp": { + "icon": "", + "images": [] + }, + "eclipse-reporting": { + "icon": "", + "images": [] + }, + "eclipse-rust": { + "icon": "", + "images": [] + }, + "eclipse-scout": { + "icon": "", + "images": [] + }, + "eclipse-sdk": { + "icon": "", + "images": [] + }, + "eclipse-standard-kepler": { + "icon": "https://community.chocolatey.org/content/packageimages/eclipse-standard-kepler.4.3.20130917.png", + "images": [] + }, + "eclipse-standard-luna": { + "icon": "https://community.chocolatey.org/content/packageimages/eclipse-standard-luna.4.4.png", + "images": [] + }, + "eclipse-sumo": { + "icon": "", + "images": [] + }, + "eclipse-testing": { + "icon": "", + "images": [] + }, + "eclipseclp-7-0": { + "icon": "", + "images": [] + }, + "eclipseclp-7-1": { + "icon": "", + "images": [] + }, + "ecs-cli": { + "icon": "", + "images": [] + }, + "ect": { + "icon": "", + "images": [] + }, + "eddie": { + "icon": "https://community.chocolatey.org/content/packageimages/eddie.portable.2.21.8.png", + "images": [] + }, + "edecoder": { + "icon": "", + "images": [] + }, + "edex-ui": { + "icon": "", + "images": [] + }, + "edge": { + "icon": "https://i.postimg.cc/pd256kHk/logo.png", + "images": [ + "https://i.postimg.cc/L56h1HsP/edge.png" + ] + }, + "edge-beta": { + "icon": "", + "images": [] + }, + "edge-dev": { + "icon": "", + "images": [] + }, + "edgeandbingdeflector": { + "icon": "", + "images": [] + }, + "edgedb": { + "icon": "", + "images": [] + }, + "edgedeflector": { + "icon": "", + "images": [] + }, + "edgedriver": { + "icon": "", + "images": [] + }, + "edgewebview2runtime": { + "icon": "https://i.postimg.cc/pd256kHk/logo.png", + "images": [ + "https://i.postimg.cc/4yLyvrKS/webview.png" + ] + }, + "edison": { + "icon": "https://community.chocolatey.org/content/packageimages/edison.1.5.0.12.png", + "images": [] + }, + "editor": { + "icon": "", + "images": [] + }, + "editor-services-command-suite": { + "icon": "https://community.chocolatey.org/content/packageimages/editor-services-command-suite.0.4.0.png", + "images": [] + }, + "editorconfig": { + "icon": "", + "images": [] + }, + "editorconfig-core": { + "icon": "https://community.chocolatey.org/content/packageimages/editorconfig.core.0.12.1.png", + "images": [] + }, + "editorconfig-vs": { + "icon": "https://community.chocolatey.org/content/packageimages/editorconfig.vs.0.2.6.png", + "images": [] + }, + "editplus": { + "icon": "", + "images": [] + }, + "editthiscookie-chrome": { + "icon": "https://community.chocolatey.org/content/packageimages/editthiscookie-chrome.1.5.0.png", + "images": [] + }, + "edrawinfo": { + "icon": "", + "images": [] + }, + "edrawinfo-cn": { + "icon": "", + "images": [] + }, + "edrawings-viewer": { + "icon": "https://community.chocolatey.org/content/packageimages/edrawings-viewer.30.00.5017.png", + "images": [] + }, + "edrawmax": { + "icon": "", + "images": [] + }, + "edrawmax-cn": { + "icon": "", + "images": [] + }, + "edrawmind": { + "icon": "", + "images": [] + }, + "edrawproj": { + "icon": "", + "images": [] + }, + "edrawproj-cn": { + "icon": "", + "images": [] + }, + "edu": { + "icon": "", + "images": [] + }, + "eduactiv8": { + "icon": "https://community.chocolatey.org/content/packageimages/eduactiv8.3.80.411.png", + "images": [] + }, + "eduke32": { + "icon": "https://community.chocolatey.org/content/packageimages/eduke32.2022.02.19.9962.png", + "images": [] + }, + "edulite": { + "icon": "", + "images": [] + }, + "edumips64": { + "icon": "", + "images": [] + }, + "eduvpnclient": { + "icon": "https://postimg.cc/DSG2WZg2", + "images": [] + }, + "effie": { + "icon": "", + "images": [] + }, + "effie-cn": { + "icon": "", + "images": [] + }, + "efsdump": { + "icon": "", + "images": [] + }, + "eget": { + "icon": "", + "images": [] + }, + "egnytedesktopapp": { + "icon": "", + "images": [] + }, + "eid-belgium": { + "icon": "https://community.chocolatey.org/content/packageimages/eid-belgium.5.0.17.5498.png", + "images": [] + }, + "eid-belgium-viewer": { + "icon": "https://community.chocolatey.org/content/packageimages/eid-belgium-viewer.5.1.2.5886.png", + "images": [] + }, + "eid-estonia": { + "icon": "https://community.chocolatey.org/content/packageimages/eid-estonia.22.11.0.1934.png", + "images": [] + }, + "eidviewer": { + "icon": "https://eid.belgium.be/themes/custom/eid/logo.svg", + "images": [] + }, + "eiskaltdcpp": { + "icon": "", + "images": [] + }, + "ekeyfinder": { + "icon": "https://community.chocolatey.org/content/packageimages/ekeyfinder.0.1.7.png", + "images": [] + }, + "ekiga": { + "icon": "", + "images": [] + }, + "eksctl": { + "icon": "", + "images": [] + }, + "ekz": { + "icon": "", + "images": [] + }, + "elasticsearch": { + "icon": "", + "images": [] + }, + "elasticsearch-service": { + "icon": "", + "images": [] + }, + "electerm": { + "icon": "", + "images": [] + }, + "electorrent": { + "icon": "", + "images": [] + }, + "electron": { + "icon": "https://community.chocolatey.org/content/packageimages/electron.23.1.1.png", + "images": [] + }, + "electron-app-store": { + "icon": "", + "images": [] + }, + "electron-cash": { + "icon": "https://community.chocolatey.org/content/packageimages/electron-cash.install.4.2.14.png", + "images": [] + }, + "electron-fiddle": { + "icon": "", + "images": [] + }, + "electron-igot": { + "icon": "", + "images": [] + }, + "electron-mail": { + "icon": "https://community.chocolatey.org/content/packageimages/electron-mail.5.1.3.png", + "images": [] + }, + "electron-office-365": { + "icon": "", + "images": [] + }, + "electron-office-consumer": { + "icon": "", + "images": [] + }, + "electron-office-tools": { + "icon": "", + "images": [] + }, + "electron-outlook-365": { + "icon": "", + "images": [] + }, + "electron-outlook-com": { + "icon": "", + "images": [] + }, + "electron-vue-cloud-music": { + "icon": "", + "images": [] + }, + "electroncash": { + "icon": "", + "images": [] + }, + "electroncashslp": { + "icon": "", + "images": [] + }, + "electronfiddle": { + "icon": "", + "images": [] + }, + "electronic-gmail": { + "icon": "", + "images": [] + }, + "electronics-assistant": { + "icon": "", + "images": [] + }, + "electronim": { + "icon": "", + "images": [] + }, + "electronmail": { + "icon": "https://i.postimg.cc/zB1h53ds/image.png", + "images": [ + "https://i.postimg.cc/jdRhP34p/image.png", + "https://i.postimg.cc/BZHhxK9K/image.png", + "https://i.postimg.cc/VkG4Y9M3/image.png" + ] + }, + "electrum": { + "icon": "https://community.chocolatey.org/content/packageimages/electrum.portable.4.3.4.png", + "images": [] + }, + "electrum-ltc": { + "icon": "https://community.chocolatey.org/content/packageimages/electrum-ltc.portable.4.2.2.1.png", + "images": [] + }, + "electrum-mona": { + "icon": "https://community.chocolatey.org/content/packageimages/electrum-mona.install.4.1.4.png", + "images": [] + }, + "electrum-nmc": { + "icon": "", + "images": [] + }, + "element": { + "icon": "", + "images": [] + }, + "element-desktop": { + "icon": "", + "images": [] + }, + "elements": { + "icon": "https://community.chocolatey.org/content/packageimages/elements.1.2.1.png", + "images": [] + }, + "elephicon": { + "icon": "", + "images": [] + }, + "elevate": { + "icon": "", + "images": [] + }, + "elevate-native": { + "icon": "", + "images": [] + }, + "elevenclock": { + "icon": "https://raw.githubusercontent.com/martinet101/ElevenClock/main/media/icon.png", + "images": [ + "https://raw.githubusercontent.com/martinet101/ElevenClock/main/media/img1.png", + "https://raw.githubusercontent.com/martinet101/ElevenClock/main/media/img2.png", + "https://raw.githubusercontent.com/martinet101/ElevenClock/main/media/img3.png", + "https://raw.githubusercontent.com/martinet101/ElevenClock/main/media/img4.png", + "https://raw.githubusercontent.com/martinet101/ElevenClock/main/media/img5.png", + "https://raw.githubusercontent.com/martinet101/ElevenClock/main/media/img6.png", + "https://raw.githubusercontent.com/martinet101/ElevenClock/main/media/img7.png", + "https://raw.githubusercontent.com/martinet101/ElevenClock/main/media/img8.png" + ] + }, + "elexelauncher": { + "icon": "", + "images": [] + }, + "elgato-game-capture": { + "icon": "", + "images": [] + }, + "elinks": { + "icon": "https://community.chocolatey.org/content/packageimages/elinks.0.12.3.2.png", + "images": [] + }, + "elisa": { + "icon": "https://community.chocolatey.org/content/packageimages/elisa.22.08.1.png", + "images": [] + }, + "elitedangerousmarketconnector": { + "icon": "", + "images": [] + }, + "elixir": { + "icon": "https://community.chocolatey.org/content/packageimages/Elixir.1.14.3.png", + "images": [] + }, + "elk": { + "icon": "", + "images": [] + }, + "elm": { + "icon": "", + "images": [] + }, + "elm-new": { + "icon": "", + "images": [] + }, + "elm-platform": { + "icon": "https://community.chocolatey.org/content/packageimages/elm-platform.0.19.1.png", + "images": [] + }, + "elmer": { + "icon": "https://community.chocolatey.org/content/packageimages/elmer.8.4.png", + "images": [] + }, + "elmer-mpi": { + "icon": "https://community.chocolatey.org/content/packageimages/elmer-mpi.8.4.png", + "images": [] + }, + "elsie": { + "icon": "https://community.chocolatey.org/content/packageimages/elsie.2.85.png", + "images": [] + }, + "elsterformular": { + "icon": "https://community.chocolatey.org/content/packageimages/elsterformular.21.5.020221020.png", + "images": [] + }, + "elsword": { + "icon": "", + "images": [] + }, + "elsworld-en": { + "icon": "", + "images": [] + }, + "elsworld-es": { + "icon": "", + "images": [] + }, + "elvish": { + "icon": "", + "images": [] + }, + "em-client": { + "icon": "https://i.postimg.cc/xdQ8sMDS/emclient.png", + "images": [ + "https://i.postimg.cc/9M6Q77BS/image.png", + "https://i.postimg.cc/nL1zNrp9/image.png", + "https://i.postimg.cc/nhbhzBLQ/image.png", + "https://i.postimg.cc/sfL2ktdm/image.png", + "https://i.postimg.cc/rmFmTTwn/image.png", + "https://i.postimg.cc/tTSgCc1X/image.png", + "https://i.postimg.cc/d3gtGTmp/image.png" + ] + }, + "em-n-en": { + "icon": "https://community.chocolatey.org/content/packageimages/em-n-en.1.0.0.png", + "images": [] + }, + "emacs": { + "icon": "https://community.chocolatey.org/content/packageimages/emacs.install.28.2.0.png", + "images": [] + }, + "emacs-full": { + "icon": "", + "images": [] + }, + "emax64-pdumper": { + "icon": "", + "images": [] + }, + "embeddedstudioarm": { + "icon": "", + "images": [] + }, + "ember-media-manager": { + "icon": "https://community.chocolatey.org/content/packageimages/ember-media-manager.1.11.1.png", + "images": [] + }, + "embestide": { + "icon": "", + "images": [] + }, + "embree": { + "icon": "", + "images": [] + }, + "emclient": { + "icon": "https://i.postimg.cc/xdQ8sMDS/emclient.png", + "images": [ + "https://i.postimg.cc/9M6Q77BS/image.png", + "https://i.postimg.cc/nL1zNrp9/image.png", + "https://i.postimg.cc/nhbhzBLQ/image.png", + "https://i.postimg.cc/sfL2ktdm/image.png", + "https://i.postimg.cc/rmFmTTwn/image.png", + "https://i.postimg.cc/tTSgCc1X/image.png", + "https://i.postimg.cc/d3gtGTmp/image.png" + ] + }, + "emdb": { + "icon": "https://community.chocolatey.org/content/packageimages/EMDB.5.17.png", + "images": [] + }, + "emeditor": { + "icon": "https://i.postimg.cc/5055hhLW/image.png", + "images": [ + "https://i.postimg.cc/zfs0ZwQK/image.png", + "https://i.postimg.cc/26nTzbpJ/image.png", + "https://i.postimg.cc/NF44H3jk/image.png", + "https://i.postimg.cc/h4bM6d1Q/image.png", + "https://i.postimg.cc/tCqDj4BS/image.png", + "https://i.postimg.cc/YqdRqBVp/image.png", + "https://i.postimg.cc/fRFvmjDp/image.png" + ] + }, + "emet": { + "icon": "https://community.chocolatey.org/content/packageimages/emet.5.52.png", + "images": [] + }, + "emitter": { + "icon": "", + "images": [] + }, + "emplace": { + "icon": "", + "images": [] + }, + "empoche": { + "icon": "https://community.chocolatey.org/content/packageimages/empoche.0.2.1.png", + "images": [] + }, + "empty-recycle-bin": { + "icon": "", + "images": [] + }, + "emscripten": { + "icon": "https://community.chocolatey.org/content/packageimages/emscripten.3.1.28.png", + "images": [] + }, + "emsisoft-anti-malware": { + "icon": "https://community.chocolatey.org/content/packageimages/emsisoft-anti-malware.11.0.0.5958.png", + "images": [] + }, + "emsisoft-emergency-kit": { + "icon": "https://community.chocolatey.org/content/packageimages/emsisoft-emergency-kit.2022.12.0.11730.png", + "images": [] + }, + "emulationstation": { + "icon": "https://community.chocolatey.org/content/packageimages/emulationstation.portable.2.0.1.01.png", + "images": [] + }, + "emule": { + "icon": "https://community.chocolatey.org/content/packageimages/emule.0.50.01.png", + "images": [] + }, + "emule-community": { + "icon": "", + "images": [] + }, + "emulsion": { + "icon": "", + "images": [] + }, + "enarx": { + "icon": "", + "images": [] + }, + "encrypto": { + "icon": "https://community.chocolatey.org/content/packageimages/encrypto.1.0.1.0.png", + "images": [] + }, + "encryptpad": { + "icon": "", + "images": [] + }, + "encryptr": { + "icon": "", + "images": [] + }, + "endpointantivirus": { + "icon": "", + "images": [] + }, + "endpointsecurity": { + "icon": "", + "images": [] + }, + "energia": { + "icon": "https://community.chocolatey.org/content/packageimages/energia.1.8.1023.png", + "images": [] + }, + "engauge-digitizer": { + "icon": "", + "images": [] + }, + "englishizecmd": { + "icon": "https://community.chocolatey.org/content/packageimages/englishizecmd.2.0.0.0.png", + "images": [] + }, + "enigmavirtualbox": { + "icon": "", + "images": [] + }, + "enlisted": { + "icon": "https://cdn2.steamgriddb.com/logo/64608f951c2e26fcddeb4dca75459470.png", + "images": [ + "https://cdn2.steamgriddb.com/grid/a9d43cc09feae3b311d88ccb52827849.png", + "https://cdn2.steamgriddb.com/grid/6a474493748e16188f5723d881c2338a.png", + "https://cdn2.steamgriddb.com/hero/95c14ff9ca2c5d8ead4a18b1e830d504.png", + "https://cdn2.steamgriddb.com/hero/ccb946faf2ff655ccffee7f306a81888.png" + ] + }, + "enonic": { + "icon": "", + "images": [] + }, + "enowork": { + "icon": "", + "images": [] + }, + "enpass": { + "icon": "https://community.chocolatey.org/content/packageimages/enpass.install.6.8.5.1239.png", + "images": [] + }, + "enso": { + "icon": "", + "images": [] + }, + "ente": { + "icon": "", + "images": [] + }, + "entityframeworkpowertools-vs2013": { + "icon": "", + "images": [] + }, + "envsubst": { + "icon": "", + "images": [] + }, + "envyupdate": { + "icon": "", + "images": [] + }, + "epanet": { + "icon": "https://community.chocolatey.org/content/packageimages/epanet.2.2.png", + "images": [] + }, + "epicgameslauncher": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/3/31/Epic_Games_logo.svg/207px-Epic_Games_logo.svg.png", + "images": [ + "https://i.postimg.cc/QtBQnP70/egs-social-home-medium-1710x942-c0e4ff4c149e.jpg" + ] + }, + "epidata": { + "icon": "https://community.chocolatey.org/content/packageimages/epidata.4.6.0.6.png", + "images": [] + }, + "epilogueoperator": { + "icon": "", + "images": [] + }, + "epoccam": { + "icon": "", + "images": [] + }, + "epos-connect": { + "icon": "https://community.chocolatey.org/content/packageimages/epos-connect.7.4.0.37648.png", + "images": [] + }, + "epr": { + "icon": "", + "images": [] + }, + "epsdevtools-web": { + "icon": "https://community.chocolatey.org/content/packageimages/EpsDevTools.Web.0.4.1.png", + "images": [] + }, + "epson-perfection-v33-scanner": { + "icon": "https://community.chocolatey.org/content/packageimages/epson-perfection-v33-scanner.3.9.2.2.png", + "images": [] + }, + "epsviewer": { + "icon": "https://community.chocolatey.org/content/packageimages/epsviewer.3.2.png", + "images": [] + }, + "epub-checker": { + "icon": "https://community.chocolatey.org/content/packageimages/epub-checker.2.0.8.png", + "images": [] + }, + "epubcheck": { + "icon": "", + "images": [] + }, + "equality": { + "icon": "https://community.chocolatey.org/content/packageimages/equality.1.40.20221112.png", + "images": [] + }, + "equick": { + "icon": "https://community.chocolatey.org/content/packageimages/equick.1.23.png", + "images": [] + }, + "equilibrium": { + "icon": "https://community.chocolatey.org/content/packageimages/equilibrium.1.65.20221112.png", + "images": [] + }, + "eraser": { + "icon": "https://community.chocolatey.org/content/packageimages/eraser.6.2.0.2993.png", + "images": [] + }, + "ergofakt-v5": { + "icon": "", + "images": [] + }, + "ericzimmermantools": { + "icon": "", + "images": [] + }, + "erin": { + "icon": "", + "images": [] + }, + "erlang": { + "icon": "", + "images": [] + }, + "erlang16": { + "icon": "https://community.chocolatey.org/content/packageimages/Erlang16.16.03.4.png", + "images": [] + }, + "erlangotp": { + "icon": "", + "images": [] + }, + "erpxe": { + "icon": "https://community.chocolatey.org/content/packageimages/erpxe.1.2.png", + "images": [] + }, + "err": { + "icon": "", + "images": [] + }, + "errorcatcher": { + "icon": "", + "images": [] + }, + "errorlookup": { + "icon": "", + "images": [] + }, + "es": { + "icon": "https://community.chocolatey.org/content/packageimages/es.1.1.0.26.png", + "images": [] + }, + "esearch": { + "icon": "", + "images": [] + }, + "eset-antivirus": { + "icon": "https://community.chocolatey.org/content/packageimages/eset-antivirus.8.0.2028.png", + "images": [] + }, + "eset-nod32-antivirus": { + "icon": "https://community.chocolatey.org/content/packageimages/eset-nod32-antivirus.16.0.22.0.png", + "images": [] + }, + "esp-idf-tools": { + "icon": "", + "images": [] + }, + "espanso": { + "icon": "https://community.chocolatey.org/content/packageimages/espanso.2.1.8.png", + "images": [] + }, + "espeak": { + "icon": "", + "images": [] + }, + "essence": { + "icon": "https://community.chocolatey.org/content/packageimages/essence.1.14.20221112.png", + "images": [] + }, + "esteem": { + "icon": "", + "images": [] + }, + "etcd": { + "icon": "", + "images": [] + }, + "etcder": { + "icon": "", + "images": [] + }, + "etcdmanager": { + "icon": "", + "images": [] + }, + "etcher": { + "icon": "https://i.imgur.com/e31olQa.png", + "images": [ + "https://i.imgur.com/111ORhl.png", + "https://www.how2shout.com/linux/wp-content/uploads/2021/11/BalenaEtcher-installation-on-Debian-11-Bullseye.png", + "https://i.ytimg.com/vi/K8TFa-ufE2s/maxresdefault.jpg" + ] + }, + "etcher-cli": { + "icon": "", + "images": [] + }, + "ethanbrown-chromecanarydevextensions": { + "icon": "https://community.chocolatey.org/content/packageimages/EthanBrown.ChromeCanaryDevExtensions.0.0.2.png", + "images": [] + }, + "ethanbrown-chromedevextensions": { + "icon": "https://community.chocolatey.org/content/packageimages/EthanBrown.ChromeDevExtensions.0.0.2.png", + "images": [] + }, + "ethanbrown-conemuconfig": { + "icon": "https://community.chocolatey.org/content/packageimages/EthanBrown.ConEmuConfig.0.0.5.png", + "images": [] + }, + "ethanbrown-devtools-web": { + "icon": "", + "images": [] + }, + "ethanbrown-gitaliases": { + "icon": "https://community.chocolatey.org/content/packageimages/EthanBrown.GitAliases.0.0.5.png", + "images": [] + }, + "ethanbrown-gitconfiguration": { + "icon": "https://community.chocolatey.org/content/packageimages/EthanBrown.GitConfiguration.0.0.4.png", + "images": [] + }, + "ethanbrown-gitextensionsconfiguration": { + "icon": "https://community.chocolatey.org/content/packageimages/EthanBrown.GitExtensionsConfiguration.0.0.1.png", + "images": [] + }, + "ethanbrown-sublimetext2-editorpackages": { + "icon": "https://community.chocolatey.org/content/packageimages/EthanBrown.SublimeText2.EditorPackages.0.2.2.png", + "images": [] + }, + "ethanbrown-sublimetext2-gitpackages": { + "icon": "https://community.chocolatey.org/content/packageimages/EthanBrown.SublimeText2.GitPackages.0.2.2.png", + "images": [] + }, + "ethanbrown-sublimetext2-utilpackages": { + "icon": "https://community.chocolatey.org/content/packageimages/EthanBrown.SublimeText2.UtilPackages.0.2.2.png", + "images": [] + }, + "ethanbrown-sublimetext2-webpackages": { + "icon": "https://community.chocolatey.org/content/packageimages/EthanBrown.SublimeText2.WebPackages.0.3.0.png", + "images": [] + }, + "ethereum-wallet": { + "icon": "", + "images": [] + }, + "ethminer": { + "icon": "", + "images": [] + }, + "ethr": { + "icon": "", + "images": [] + }, + "etl2pcapng": { + "icon": "", + "images": [] + }, + "etlas": { + "icon": "", + "images": [] + }, + "etternagame": { + "icon": "", + "images": [] + }, + "eudic": { + "icon": "", + "images": [] + }, + "euler": { + "icon": "", + "images": [] + }, + "euroscope": { + "icon": "", + "images": [] + }, + "evacuationz": { + "icon": "", + "images": [] + }, + "evans": { + "icon": "", + "images": [] + }, + "evemon": { + "icon": "", + "images": [] + }, + "eventghost": { + "icon": "https://community.chocolatey.org/content/packageimages/eventghost.0.4.1.1723.png", + "images": [] + }, + "eventstore": { + "icon": "", + "images": [] + }, + "eventstore-oss": { + "icon": "", + "images": [] + }, + "eventstore-servicehost": { + "icon": "", + "images": [] + }, + "eveonline": { + "icon": "", + "images": [] + }, + "everedit": { + "icon": "", + "images": [] + }, + "evernote": { + "icon": "https://community.chocolatey.org/content/packageimages/evernote.10.53.2.png", + "images": [] + }, + "evernote-chrome": { + "icon": "", + "images": [] + }, + "evernote2onenote": { + "icon": "https://community.chocolatey.org/content/packageimages/evernote2onenote.1.2.2.png", + "images": [] + }, + "everything": { + "icon": "https://i.postimg.cc/rpwsh2hZ/everything-icon.png", + "images": [ + "https://i.postimg.cc/RZRL3w9Q/Everything-Search-Window.png" + ] + }, + "everything-alpha": { + "icon": "https://unigeticons.meowcat285.com/EverythingAlpha.png", + "images": [ + "https://i.postimg.cc/wvL9Cbp6/image.png" + ] + }, + "everything-beta": { + "icon": "https://community.chocolatey.org/content/packageimages/everything.beta.portable.1.3.3.658.png", + "images": [ + "https://i.postimg.cc/wvL9Cbp6/image.png" + ] + }, + "everything-cli": { + "icon": "", + "images": [] + }, + "everything-lite": { + "icon": "", + "images": [] + }, + "everythingpowertoys": { + "icon": "https://community.chocolatey.org/content/packageimages/everythingpowertoys.0.66.0.png", + "images": [] + }, + "everythingtoolbar": { + "icon": "https://lecrabeinfo.net/app/uploads/2024/02/everything-toolbar-65ccd9736a92e.png", + "images": [ + "https://i.postimg.cc/P5hMrSG5/IfpkHAX.png" + ] + }, + "everythingtoolbar-beta": { + "icon": "", + "images": [] + }, + "evga-eleet": { + "icon": "https://community.chocolatey.org/content/packageimages/evga-eleet.1.10.4.png", + "images": [] + }, + "evga-flow-control": { + "icon": "https://community.chocolatey.org/content/packageimages/evga-flow-control.2.1.0.png", + "images": [] + }, + "evga-precision-x1": { + "icon": "https://community.chocolatey.org/content/packageimages/evga-precision-x1.1.3.6.0.png", + "images": [] + }, + "evga-precision-xoc": { + "icon": "https://community.chocolatey.org/content/packageimages/evga-precision-xoc.6.2.7.png", + "images": [] + }, + "eviacam": { + "icon": "https://community.chocolatey.org/content/packageimages/eviacam.2.1.0.20210123.png", + "images": [] + }, + "evimsync": { + "icon": "https://community.chocolatey.org/content/packageimages/evimsync.1.0.0.118.png", + "images": [] + }, + "evince": { + "icon": "https://community.chocolatey.org/content/packageimages/evince.2.32.0.145001.png", + "images": [] + }, + "evo": { + "icon": "", + "images": [] + }, + "evoluentmousemanager": { + "icon": "", + "images": [] + }, + "evope": { + "icon": "", + "images": [] + }, + "ewseditor": { + "icon": "", + "images": [] + }, + "exactaudiocopy": { + "icon": "", + "images": [] + }, + "exaile": { + "icon": "", + "images": [] + }, + "examdiff": { + "icon": "https://i.postimg.cc/dVJr6css/examdif.png", + "images": [ + "https://i.postimg.cc/T1hnrVfr/image.png" + ] + }, + "examdiff-pro": { + "icon": "https://i.postimg.cc/dVJr6css/examdif.png", + "images": [ + "https://i.postimg.cc/pV1fP6Jk/image.png", + "https://i.postimg.cc/X7Gwqk2W/image.png", + "https://i.postimg.cc/G2f4nZny/image.png", + "https://i.postimg.cc/W42FGG7h/image.png", + "https://i.postimg.cc/252q21HT/image.png", + "https://i.postimg.cc/9Q2tkqpj/image.png" + ] + }, + "excel-parser-processor": { + "icon": "", + "images": [] + }, + "excel-viewer": { + "icon": "", + "images": [] + }, + "excelconverter": { + "icon": "https://community.chocolatey.org/content/packageimages/ExcelConverter.3.2.2.png", + "images": [] + }, + "exceptionless": { + "icon": "https://community.chocolatey.org/content/packageimages/exceptionless.3.2.2128.2.png", + "images": [] + }, + "exceptionless-elasticsearch": { + "icon": "", + "images": [] + }, + "exchange-edb-viewer": { + "icon": "https://community.chocolatey.org/content/packageimages/exchange-edb-viewer.15.9.png", + "images": [] + }, + "exe-explorer": { + "icon": "", + "images": [] + }, + "execs": { + "icon": "", + "images": [] + }, + "executedprogramslist": { + "icon": "https://community.chocolatey.org/content/packageimages/executedprogramslist.1.11.png", + "images": [] + }, + "executor": { + "icon": "https://i.postimg.cc/qRnQRS1X/image.png", + "images": [ + "https://i.postimg.cc/x1TsRsdf/image.png", + "https://i.postimg.cc/wxX0dKyH/image.png", + "https://i.postimg.cc/sDKmvp40/image.png", + "https://i.postimg.cc/B6WcdNJx/image.png", + "https://i.postimg.cc/02tG898M/image.png" + ] + }, + "exeinfo": { + "icon": "https://community.chocolatey.org/content/packageimages/exeinfo.1.01.png", + "images": [] + }, + "exeinfo-pe": { + "icon": "", + "images": [] + }, + "exercism": { + "icon": "", + "images": [] + }, + "exercism-io-cli": { + "icon": "https://community.chocolatey.org/content/packageimages/exercism-io-cli.3.1.0.png", + "images": [] + }, + "exifcleaner": { + "icon": "", + "images": [] + }, + "exifdataview": { + "icon": "https://community.chocolatey.org/content/packageimages/exifdataview.1.15.png", + "images": [] + }, + "exiftool": { + "icon": "https://community.chocolatey.org/content/packageimages/exiftool.12.57.png", + "images": [] + }, + "exiftoolgui": { + "icon": "https://community.chocolatey.org/content/packageimages/exiftoolgui.5.16.20211222.png", + "images": [] + }, + "exodus": { + "icon": "", + "images": [] + }, + "exoduswallet": { + "icon": "https://community.chocolatey.org/content/packageimages/exoduswallet.23.2.27.png", + "images": [] + }, + "expandrive": { + "icon": "https://community.chocolatey.org/content/packageimages/expandrive.2021.08.03.png", + "images": [] + }, + "explorer-expand-to-current-folder": { + "icon": "", + "images": [] + }, + "explorer-suite": { + "icon": "", + "images": [] + }, + "explorer-winconfig": { + "icon": "https://community.chocolatey.org/content/packageimages/explorer-winconfig.0.0.1.png", + "images": [] + }, + "explorergenie": { + "icon": "https://community.chocolatey.org/content/packageimages/explorergenie.2.0.1.png", + "images": [] + }, + "explorerpatcher": { + "icon": "", + "images": [] + }, + "explorerpatcher-prerelease": { + "icon": "", + "images": [] + }, + "explorerplusplus": { + "icon": "https://community.chocolatey.org/content/packageimages/Explorerplusplus.1.3.5.png", + "images": [] + }, + "explorersuite": { + "icon": "", + "images": [] + }, + "express": { + "icon": "https://i.postimg.cc/y6pDCFC4/grminexp.png", + "images": [ + "https://i.postimg.cc/HxFgvsq2/image.png" + ] + }, + "expressionblend": { + "icon": "https://community.chocolatey.org/content/packageimages/expressionblend.2.0.20525.png", + "images": [] + }, + "expressionblend3": { + "icon": "", + "images": [] + }, + "expresslrs-configurator": { + "icon": "https://i.postimg.cc/5tkH4rTL/Express-LRS.png", + "images": [ + "https://i.postimg.cc/gj3rK2JH/image.png", + "https://i.postimg.cc/QN7BD0bK/image.png" + ] + }, + "expresso": { + "icon": "https://community.chocolatey.org/content/packageimages/expresso.3.0.4750.png", + "images": [] + }, + "expressvpn": { + "icon": "https://community.chocolatey.org/content/packageimages/expressvpn.12.37.0.85.png", + "images": [] + }, + "expurgate": { + "icon": "https://community.chocolatey.org/content/packageimages/expurgate.1.12.20221112.png", + "images": [] + }, + "ext2explore": { + "icon": "https://community.chocolatey.org/content/packageimages/ext2explore.2.2.71.20100623.png", + "images": [] + }, + "ext2ifs": { + "icon": "", + "images": [] + }, + "extensibilitytools": { + "icon": "", + "images": [] + }, + "externalraidmanager": { + "icon": "", + "images": [ + "https://i.postimg.cc/DyHyRCmr/image.png" + ] + }, + "extractnow": { + "icon": "", + "images": [] + }, + "extraterm": { + "icon": "", + "images": [] + }, + "extremetuxracer": { + "icon": "", + "images": [] + }, + "eyesguard": { + "icon": "https://raw.githubusercontent.com/avestura/EyesGuard/master/UWPAssets/150x150.png", + "images": [ + "https://raw.githubusercontent.com/avestura/EyesGuard/master/Screenshots/Store/Settings.PNG", + "https://raw.githubusercontent.com/avestura/EyesGuard/master/Screenshots/Store/ContextMenu.png" + ] + }, + "eyesrelax": { + "icon": "", + "images": [] + }, + "ezssh": { + "icon": "https://community.chocolatey.org/content/packageimages/ezssh.1.0.4.png", + "images": [] + }, + "ezunlock": { + "icon": "", + "images": [] + }, + "f-lux": { + "icon": "https://justgetflux.com/press/flux-icon-transparent.png", + "images": [] + }, + "f2": { + "icon": "", + "images": [] + }, + "f3d": { + "icon": "", + "images": [] + }, + "faas-cli": { + "icon": "https://community.chocolatey.org/content/packageimages/faas-cli.0.16.0.png", + "images": [] + }, + "fab": { + "icon": "https://community.chocolatey.org/content/packageimages/fab.1.7.png", + "images": [] + }, + "fabric-installer": { + "icon": "https://community.chocolatey.org/content/packageimages/fabric-installer.0.11.1.png", + "images": [] + }, + "faceitac": { + "icon": "", + "images": [] + }, + "faceitclient": { + "icon": "", + "images": [] + }, + "factor": { + "icon": "https://community.chocolatey.org/content/packageimages/factor.0.97.png", + "images": [] + }, + "fadein": { + "icon": "", + "images": [] + }, + "fadetop": { + "icon": "", + "images": [] + }, + "fah": { + "icon": "https://community.chocolatey.org/content/packageimages/fah.7.6.21.png", + "images": [] + }, + "fairshare": { + "icon": "", + "images": [] + }, + "fake": { + "icon": "", + "images": [] + }, + "fakenet": { + "icon": "", + "images": [] + }, + "falcon-sql-client": { + "icon": "", + "images": [] + }, + "falconx": { + "icon": "", + "images": [] + }, + "falkon": { + "icon": "https://community.chocolatey.org/content/packageimages/falkon.3.1.0.20220620.png", + "images": [ + "https://falkon.org//images/screenshot.png" + ] + }, + "famisafe": { + "icon": "", + "images": [] + }, + "famistudio": { + "icon": "", + "images": [] + }, + "fanalab": { + "icon": "https://community.chocolatey.org/content/packageimages/fanalab.1.64.5.png", + "images": [] + }, + "fanatec-driver": { + "icon": "https://community.chocolatey.org/content/packageimages/fanatec-driver.1.0.447.png", + "images": [] + }, + "fancontrol": { + "icon": "https://unigeticons.meowcat285.com/FanControl.png", + "images": [ + "https://unigeticons.meowcat285.com/Screenshots/FanControl/MainUI.png" + ] + }, + "far": { + "icon": "", + "images": [] + }, + "far-2": { + "icon": "https://community.chocolatey.org/content/packageimages/Far-2.2.0.1807.png", + "images": [] + }, + "far-3": { + "icon": "", + "images": [] + }, + "farmanager": { + "icon": "https://avatars.githubusercontent.com/u/3636093?s=200&v=4", + "images": [ + "https://www.farmanager.com/img/screen/ctrll.png", + "https://www.farmanager.com/img/screen/colors.png", + "https://www.farmanager.com/img/screen/viewer.png", + "https://www.farmanager.com/img/screen/elevation.png", + "https://www.farmanager.com/img/screen/altf7.png" + ] + }, + "fastcopy": { + "icon": "", + "images": [ + "https://i.postimg.cc/59HZpDLn/image.png" + ] + }, + "fastest-mouse-clicker": { + "icon": "https://community.chocolatey.org/content/packageimages/fastest-mouse-clicker.2.6.1.0.png", + "images": [] + }, + "fastfetch": { + "icon": "", + "images": [] + }, + "fastfinder": { + "icon": "https://community.chocolatey.org/content/packageimages/fastfinder.2.0.0.png", + "images": [] + }, + "fastglacier": { + "icon": "https://community.chocolatey.org/content/packageimages/fastglacier.3.4.7.png", + "images": [] + }, + "fastimageresizer": { + "icon": "https://community.chocolatey.org/content/packageimages/fastimageresizer.0.98.20181007.png", + "images": [] + }, + "fastresolver": { + "icon": "https://community.chocolatey.org/content/packageimages/fastresolver.portable.1.26.png", + "images": [] + }, + "fat32format": { + "icon": "", + "images": [] + }, + "fat32format-gui": { + "icon": "", + "images": [] + }, + "fatty": { + "icon": "", + "images": [] + }, + "favbinedit": { + "icon": "https://community.chocolatey.org/content/packageimages/favbinedit.1.2.4.png", + "images": [] + }, + "faviconizer": { + "icon": "https://community.chocolatey.org/content/packageimages/faviconizer.1.4.png", + "images": [] + }, + "fawkes": { + "icon": "", + "images": [] + }, + "fbcacheview": { + "icon": "https://community.chocolatey.org/content/packageimages/fbcacheview.1.22.png", + "images": [] + }, + "fbexport": { + "icon": "", + "images": [] + }, + "fbflipper": { + "icon": "", + "images": [] + }, + "fbide": { + "icon": "", + "images": [] + }, + "fbp-vst-plugins": { + "icon": "", + "images": [] + }, + "fbvlc": { + "icon": "", + "images": [] + }, + "fbx": { + "icon": "https://community.chocolatey.org/content/packageimages/fbx.3.18.png", + "images": [] + }, + "fciv": { + "icon": "", + "images": [] + }, + "fclones": { + "icon": "", + "images": [] + }, + "fd": { + "icon": "", + "images": [] + }, + "feathercoin": { + "icon": "https://community.chocolatey.org/content/packageimages/feathercoin.0.19.1.png", + "images": [] + }, + "featherwallet": { + "icon": "", + "images": [] + }, + "fedoramediawriter": { + "icon": "", + "images": [] + }, + "feeddemon": { + "icon": "", + "images": [] + }, + "feeder": { + "icon": "", + "images": [] + }, + "feedly-chrome": { + "icon": "", + "images": [] + }, + "feednotifier": { + "icon": "", + "images": [] + }, + "feem": { + "icon": "", + "images": [] + }, + "feem-beta": { + "icon": "", + "images": [] + }, + "feishu": { + "icon": "", + "images": [] + }, + "felloe": { + "icon": "", + "images": [] + }, + "femm": { + "icon": "https://community.chocolatey.org/content/packageimages/femm.4.2.20190421.png", + "images": [] + }, + "fences": { + "icon": "", + "images": [] + }, + "fend": { + "icon": "https://community.chocolatey.org/content/packageimages/fend.portable.1.1.5.png", + "images": [] + }, + "fenix-web-server": { + "icon": "", + "images": [] + }, + "fenophoto": { + "icon": "", + "images": [] + }, + "ferdi": { + "icon": "", + "images": [ + "https://i.postimg.cc/05wGYTPN/workspaces.png" + ] + }, + "ferdium": { + "icon": "https://ferdium.org/_next/static/media/logo.9fc5c374.png", + "images": [ + "https://i.postimg.cc/05wGYTPN/workspaces.png" + ] + }, + "ferdium-beta": { + "icon": "", + "images": [] + }, + "ferdium-nightly": { + "icon": "", + "images": [] + }, + "ferraricreator": { + "icon": "", + "images": [] + }, + "ffdec": { + "icon": "", + "images": [] + }, + "ffdshow": { + "icon": "", + "images": [] + }, + "ffdshow-x86-32": { + "icon": "", + "images": [] + }, + "ffe": { + "icon": "https://community.chocolatey.org/content/packageimages/ffe.1.1.png", + "images": [] + }, + "ffftp": { + "icon": "https://community.chocolatey.org/content/packageimages/ffftp.4.8.png", + "images": [] + }, + "ffmpeg": { + "icon": "https://ia803205.us.archive.org/19/items/banner_20240106/FFmpeg_Logo_new.png", + "images": [] + }, + "ffmpeg-batch": { + "icon": "https://community.chocolatey.org/content/packageimages/ffmpeg-batch.install.2.8.4.png", + "images": [] + }, + "ffmpeg-full": { + "icon": "", + "images": [] + }, + "ffmpeg-shared": { + "icon": "", + "images": [] + }, + "ffmpegbatchavconverter": { + "icon": "", + "images": [] + }, + "ffqueue": { + "icon": "", + "images": [] + }, + "ffsend": { + "icon": "", + "images": [] + }, + "ffsj": { + "icon": "", + "images": [] + }, + "fheroes2enh": { + "icon": "https://community.chocolatey.org/content/packageimages/fheroes2enh.1.1.0.png", + "images": [] + }, + "fiddler": { + "icon": "https://community.chocolatey.org/content/packageimages/fiddler.5.0.20211.51073.png", + "images": [ + "https://i.postimg.cc/zvS7tnBp/image.png" + ] + }, + "fiddler-classic": { + "icon": "https://community.chocolatey.org/content/packageimages/fiddler.5.0.20211.51073.png", + "images": [ + "https://i.postimg.cc/zvS7tnBp/image.png" + ] + }, + "fiddler-everywhere": { + "icon": "https://i.postimg.cc/sgvn63Yy/fiddler-e.png", + "images": [ + "https://i.postimg.cc/rp4fTgZP/image.png", + "https://i.postimg.cc/ydXngxHh/image.png", + "https://i.postimg.cc/j2MXc1CL/image.png" + ] + }, + "fiddler-everywhere-insiders": { + "icon": "", + "images": [] + }, + "fifo": { + "icon": "", + "images": [] + }, + "figlet": { + "icon": "", + "images": [] + }, + "figlet-go": { + "icon": "", + "images": [] + }, + "figma": { + "icon": "https://i.imgur.com/4N8g5vs.png", + "images": [ + "https://help.figma.com/hc/article_attachments/4411511018135/Select_page_as_a_viewer.png", + "https://help.figma.com/hc/article_attachments/4402389760919/mask-with-stroke.png" + ] + }, + "figurine": { + "icon": "", + "images": [] + }, + "fiji": { + "icon": "", + "images": [] + }, + "file": { + "icon": "", + "images": [] + }, + "file-hash-generator": { + "icon": "https://community.chocolatey.org/content/packageimages/file-hash-generator.5.0.0.png", + "images": [] + }, + "filealyzer": { + "icon": "https://community.chocolatey.org/content/packageimages/filealyzer.2.0.5.57.png", + "images": [] + }, + "fileassassin": { + "icon": "https://community.chocolatey.org/content/packageimages/fileassassin.1.06.png", + "images": [] + }, + "filebeat": { + "icon": "https://community.chocolatey.org/content/packageimages/filebeat.7.15.1.png", + "images": [] + }, + "filebeat-oss": { + "icon": "https://community.chocolatey.org/content/packageimages/filebeat-oss.8.4.1.png", + "images": [] + }, + "filebot": { + "icon": "", + "images": [] + }, + "fileconverter": { + "icon": "https://file-converter.io/images/application-icon.png", + "images": [ + "https://i.postimg.cc/CK1Yn290/ss2.png", + "https://file-converter.org/images/screenshot3.png" + ] + }, + "fileformatconverters": { + "icon": "", + "images": [] + }, + "filehashgenerator": { + "icon": "", + "images": [] + }, + "filelight": { + "icon": "https://invent.kde.org/utilities/filelight/-/raw/master/logo.png", + "images": [] + }, + "filelist": { + "icon": "https://i.postimg.cc/vDwTRXkX/filelist.png", + "images": [ + "https://i.postimg.cc/gJrn3x3y/image.png", + "https://i.postimg.cc/MT4X5zYC/image.png", + "https://i.postimg.cc/kGbGhL1B/image.png" + ] + }, + "filemenutools": { + "icon": "https://i.postimg.cc/52FyrzJ3/File-Menu-Tools.png", + "images": [ + "https://i.postimg.cc/Y9ywkXfy/image.png", + "https://i.postimg.cc/jqmrFFjj/image.png", + "https://i.postimg.cc/ThMFYByw/image.png", + "https://i.postimg.cc/QMd83WZ3/image.png", + "https://i.postimg.cc/4yVZ56VQ/image.png", + "https://i.postimg.cc/t4Xy3VTT/image.png" + ] + }, + "filen": { + "icon": "https://community.chocolatey.org/content/packageimages/filen.2.0.16.png", + "images": [] + }, + "filen-sync": { + "icon": "https://community.chocolatey.org/content/packageimages/filen-sync.2.0.16.png", + "images": [] + }, + "filenesting": { + "icon": "", + "images": [] + }, + "filensync": { + "icon": "", + "images": [] + }, + "fileoptimizer": { + "icon": "https://community.chocolatey.org/content/packageimages/FileOptimizer.16.20.2771.png", + "images": [] + }, + "filerecoveryfree": { + "icon": "", + "images": [] + }, + "files": { + "icon": "https://community.chocolatey.org/content/packageimages/files.2.4.40.png", + "images": [] + }, + "fileseek": { + "icon": "https://community.chocolatey.org/content/packageimages/fileseek.6.7.0.png", + "images": [ + "https://i.postimg.cc/Ls17wRR8/image.png", + "https://i.postimg.cc/SsVGttXK/image.png", + "https://i.postimg.cc/1tWpKnTn/image.png", + "https://i.postimg.cc/SKg200GH/image.png", + "https://i.postimg.cc/2jbTCYKQ/image.png" + ] + }, + "fileshredder": { + "icon": "https://community.chocolatey.org/content/packageimages/fileshredder.2.5.1.png", + "images": [] + }, + "filesing": { + "icon": "", + "images": [] + }, + "filespy": { + "icon": "https://community.chocolatey.org/content/packageimages/filespy.4.1.0.522.png", + "images": [] + }, + "filetool": { + "icon": "https://community.chocolatey.org/content/packageimages/filetool.1.0.0.814.png", + "images": [] + }, + "filetypeeditor": { + "icon": "https://community.chocolatey.org/content/packageimages/filetypeeditor.3.1.4.20170309.png", + "images": [] + }, + "filetypesman": { + "icon": "https://community.chocolatey.org/content/packageimages/FileTypesMan.1.97.png", + "images": [] + }, + "filevoyager": { + "icon": "", + "images": [] + }, + "filezilla": { + "icon": "https://community.chocolatey.org/content/packageimages/filezilla.server.1.6.7.png", + "images": [] + }, + "filezilla-server": { + "icon": "https://community.chocolatey.org/content/packageimages/filezilla.server.1.6.7.png", + "images": [] + }, + "filius": { + "icon": "", + "images": [] + }, + "film-info-organizer": { + "icon": "https://community.chocolatey.org/content/packageimages/film-info-organizer.0.6.1.3.png", + "images": [] + }, + "filmii": { + "icon": "", + "images": [] + }, + "filmora": { + "icon": "", + "images": [] + }, + "filmora-cn": { + "icon": "", + "images": [] + }, + "filmora-pro": { + "icon": "", + "images": [] + }, + "final-fantasy-xiv": { + "icon": "", + "images": [] + }, + "finalbuilder": { + "icon": "https://community.chocolatey.org/content/packageimages/finalbuilder.8.0.0.3237.png", + "images": [] + }, + "find-and-run-robot": { + "icon": "https://community.chocolatey.org/content/packageimages/find-and-run-robot.install.2.239.01.png", + "images": [] + }, + "find-java": { + "icon": "", + "images": [] + }, + "findaes": { + "icon": "", + "images": [] + }, + "findandmount": { + "icon": "", + "images": [] + }, + "findandreplace": { + "icon": "https://community.chocolatey.org/content/packageimages/findandreplace.2.0.png", + "images": [] + }, + "findandrunrobot": { + "icon": "", + "images": [] + }, + "finddupe": { + "icon": "", + "images": [] + }, + "findlinks": { + "icon": "", + "images": [] + }, + "findthatfont": { + "icon": "https://community.chocolatey.org/content/packageimages/findthatfont.1.0.0.png", + "images": [] + }, + "findutils": { + "icon": "", + "images": [] + }, + "fing": { + "icon": "https://community.chocolatey.org/content/packageimages/fing.3.2.0.608.png", + "images": [] + }, + "fintender-installer": { + "icon": "https://community.chocolatey.org/content/packageimages/fintender-installer.2.5.48.png", + "images": [] + }, + "fio": { + "icon": "", + "images": [] + }, + "fira": { + "icon": "https://community.chocolatey.org/content/packageimages/fira.4.202.png", + "images": [] + }, + "firacode": { + "icon": "https://community.chocolatey.org/content/packageimages/FiraCode.6.2.png", + "images": [] + }, + "firacode-ttf": { + "icon": "https://community.chocolatey.org/content/packageimages/FiraCode-ttf.5.2.png", + "images": [] + }, + "firacodenf": { + "icon": "https://community.chocolatey.org/content/packageimages/firacodenf.6.002.png", + "images": [] + }, + "firealpaca": { + "icon": "https://community.chocolatey.org/content/packageimages/firealpaca.2.9.1.png", + "images": [] + }, + "firebase": { + "icon": "https://firebase.google.com/_pwa/firebase/icons/icon-512x512.png", + "images": [ + "https://firebase.google.com/images/social.png" + ] + }, + "firebasecli": { + "icon": "", + "images": [] + }, + "firebird": { + "icon": "https://community.chocolatey.org/content/packageimages/firebird.4.0.2.png", + "images": [] + }, + "firebird-emu": { + "icon": "", + "images": [] + }, + "firedm": { + "icon": "", + "images": [] + }, + "firefly": { + "icon": "", + "images": [] + }, + "firefox": { + "icon": "https://i.postimg.cc/RCLmpNTX/Firefox-icon.png", + "images": [ + "https://i.postimg.cc/3Jr4Jyrc/ff1.png", + "https://i.postimg.cc/Wb9DD2hb/ff2.png", + "https://i.postimg.cc/526XLZC5/ff3.png" + ] + }, + "firefox-beta": { + "icon": "https://i.postimg.cc/B6tFYdrC/firefox-beta.png", + "images": [ + "https://i.postimg.cc/3Jr4Jyrc/ff1.png", + "https://i.postimg.cc/Wb9DD2hb/ff2.png", + "https://i.postimg.cc/526XLZC5/ff3.png" + ] + }, + "firefox-developeredition": { + "icon": "https://i.postimg.cc/d19f6TKC/Firefox-Developer-Edition.png", + "images": [ + "https://i.postimg.cc/3Jr4Jyrc/ff1.png", + "https://i.postimg.cc/Wb9DD2hb/ff2.png", + "https://i.postimg.cc/526XLZC5/ff3.png" + ] + }, + "firefox-eme-free": { + "icon": "https://i.postimg.cc/RCLmpNTX/Firefox-icon.png", + "images": [ + "https://i.postimg.cc/3Jr4Jyrc/ff1.png", + "https://i.postimg.cc/Wb9DD2hb/ff2.png", + "https://i.postimg.cc/526XLZC5/ff3.png" + ] + }, + "firefox-esr": { + "icon": "https://i.postimg.cc/RCLmpNTX/Firefox-icon.png", + "images": [ + "https://i.postimg.cc/3Jr4Jyrc/ff1.png", + "https://i.postimg.cc/Wb9DD2hb/ff2.png", + "https://i.postimg.cc/526XLZC5/ff3.png" + ] + }, + "firefox-nightly": { + "icon": "https://i.postimg.cc/k5T8ynp4/Firefox-nightly-logo.png", + "images": [ + "https://i.postimg.cc/3Jr4Jyrc/ff1.png", + "https://i.postimg.cc/Wb9DD2hb/ff2.png", + "https://i.postimg.cc/526XLZC5/ff3.png" + ] + }, + "firefoxdownloadsview": { + "icon": "https://community.chocolatey.org/content/packageimages/firefoxdownloadsview.1.40.png", + "images": [] + }, + "firefoxesr": { + "icon": "", + "images": [] + }, + "firefoxpwa": { + "icon": "https://community.chocolatey.org/content/packageimages/firefoxpwa.2.4.1.png", + "images": [] + }, + "firemin": { + "icon": "", + "images": [] + }, + "fireshot-chrome": { + "icon": "https://community.chocolatey.org/content/packageimages/fireshot-chrome.0.98.93.2.png", + "images": [] + }, + "firestorm-opensim": { + "icon": "https://community.chocolatey.org/content/packageimages/firestorm-opensim.6.6.3.png", + "images": [] + }, + "firestorm-secondlife": { + "icon": "https://community.chocolatey.org/content/packageimages/firestorm-secondlife.6.6.8.png", + "images": [] + }, + "firewallappblocker": { + "icon": "", + "images": [] + }, + "firework": { + "icon": "", + "images": [] + }, + "firmwaretablesview": { + "icon": "https://community.chocolatey.org/content/packageimages/firmwaretablesview.1.01.png", + "images": [] + }, + "firowallet": { + "icon": "https://community.chocolatey.org/content/packageimages/firowallet.0.14.12.0.png", + "images": [] + }, + "fishingfunds": { + "icon": "", + "images": [] + }, + "fission-cli": { + "icon": "", + "images": [] + }, + "fitbit-ultra": { + "icon": "", + "images": [] + }, + "fix-print-spooler": { + "icon": "", + "images": [] + }, + "fl2k-win": { + "icon": "", + "images": [] + }, + "flac": { + "icon": "https://community.chocolatey.org/content/packageimages/flac.1.3.4.png", + "images": [] + }, + "flacsquisher": { + "icon": "https://community.chocolatey.org/content/packageimages/flacsquisher.1.3.8.png", + "images": [] + }, + "flameshot": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/f/f6/Flameshot_logo.svg/1024px-Flameshot_logo.svg.png", + "images": [] + }, + "flare": { + "icon": "https://community.chocolatey.org/content/packageimages/flare.0.19.20141201.png", + "images": [] + }, + "flarectl": { + "icon": "", + "images": [] + }, + "flaresolverr": { + "icon": "", + "images": [] + }, + "flash-decompiler-trillix": { + "icon": "https://community.chocolatey.org/content/packageimages/flash-decompiler-trillix.5.3.1400.png", + "images": [] + }, + "flashbackexpress": { + "icon": "", + "images": [] + }, + "flashbackpro": { + "icon": "", + "images": [] + }, + "flashboot": { + "icon": "", + "images": [] + }, + "flashbuilder": { + "icon": "https://community.chocolatey.org/content/packageimages/flashbuilder.install.1.44.png", + "images": [] + }, + "flashfxp": { + "icon": "", + "images": [ + "https://i.postimg.cc/SsdYFhH6/image.png", + "https://i.postimg.cc/MHrcHY6X/image.png", + "https://i.postimg.cc/rFK0b7j4/image.png", + "https://i.postimg.cc/7Ly55hk1/image.png", + "https://i.postimg.cc/1X4tkNGS/image.png", + "https://i.postimg.cc/9F6Mk0r3/image.png", + "https://i.postimg.cc/Gmv2nRy4/image.png" + ] + }, + "flashplayer-sa": { + "icon": "", + "images": [] + }, + "flashplayer-sa-debug": { + "icon": "", + "images": [] + }, + "flashplayeractivex": { + "icon": "https://community.chocolatey.org/content/packageimages/flashplayeractivex.32.0.0.465.png", + "images": [] + }, + "flashplayerplugin": { + "icon": "https://community.chocolatey.org/content/packageimages/flashplayerplugin.32.0.0.465.png", + "images": [] + }, + "flashplayerplugin-disable-updates-winconfig": { + "icon": "https://community.chocolatey.org/content/packageimages/flashplayerplugin-disable-updates-winconfig.0.0.1.png", + "images": [] + }, + "flashplayerppapi": { + "icon": "https://community.chocolatey.org/content/packageimages/flashplayerppapi.32.0.0.465.png", + "images": [] + }, + "flashpoint": { + "icon": "https://community.chocolatey.org/content/packageimages/flashpoint.1.0.png", + "images": [] + }, + "flashpoint-core": { + "icon": "https://community.chocolatey.org/content/packageimages/flashpoint-core.11.0.png", + "images": [] + }, + "flashpoint-infinity": { + "icon": "https://community.chocolatey.org/content/packageimages/flashpoint-infinity.10.0.png", + "images": [] + }, + "flat": { + "icon": "", + "images": [] + }, + "flat-assembler": { + "icon": "", + "images": [] + }, + "flatc": { + "icon": "https://community.chocolatey.org/content/packageimages/flatc.1.12.0.png", + "images": [] + }, + "flattenpackages": { + "icon": "", + "images": [] + }, + "flauinspect": { + "icon": "https://community.chocolatey.org/content/packageimages/flauinspect.1.3.0.png", + "images": [] + }, + "flawesome": { + "icon": "", + "images": [] + }, + "flbmusic": { + "icon": "", + "images": [] + }, + "fleet": { + "icon": "https://community.chocolatey.org/content/packageimages/fleet.0.5.1.png", + "images": [] + }, + "fleetlauncher-eap": { + "icon": "https://www.jetbrains.com/_assets/www/fleet/inc/overview-content/img/fleet-logo.65f4a04c59fc3ba93bb5e181050891c5.png", + "images": [] + }, + "fleetlauncher-preview": { + "icon": "https://www.jetbrains.com/_assets/www/fleet/inc/overview-content/img/fleet-logo.65f4a04c59fc3ba93bb5e181050891c5.png", + "images": [] + }, + "flexasio": { + "icon": "", + "images": [] + }, + "flexhex": { + "icon": "", + "images": [] + }, + "flexihub": { + "icon": "", + "images": [] + }, + "flexipdf-2022": { + "icon": "", + "images": [] + }, + "flicflac": { + "icon": "", + "images": [] + }, + "flickerlist": { + "icon": "", + "images": [] + }, + "flightgear": { + "icon": "", + "images": [] + }, + "flip": { + "icon": "", + "images": [] + }, + "flipflip": { + "icon": "https://community.chocolatey.org/content/packageimages/flipflip.3.2.1.png", + "images": [] + }, + "flo": { + "icon": "", + "images": [] + }, + "flock": { + "icon": "", + "images": [] + }, + "floorp": { + "icon": "https://styles.redditmedia.com/t5_6c1hrv/styles/communityIcon_c6dw6btea2y81.png", + "images": [ + "https://floorp.app/_next/static/chunks/images/hero_1920_75.png", + "https://upload.wikimedia.org/wikipedia/commons/d/d0/Floorp_Browser_11.1.2_Screenshot.png" + ] + }, + "floss": { + "icon": "", + "images": [] + }, + "flot": { + "icon": "", + "images": [] + }, + "flow": { + "icon": "", + "images": [] + }, + "flow-launcher": { + "icon": "https://i.postimg.cc/PrS6Pjtt/flow-ico.png", + "images": [ + "https://i.postimg.cc/SK21Bvbm/flow1.png", + "https://i.postimg.cc/25s9r7Ch/flow2.png", + "https://i.postimg.cc/kG9jtM65/flow3.png", + "https://i.postimg.cc/Y03dNcYz/flow4.png", + "https://i.postimg.cc/DZ1jZ4zD/flow5.png", + "https://i.postimg.cc/T2qNvbF5/flow6.png", + "https://i.postimg.cc/5N4740W7/flow7.png" + ] + }, + "flowdock": { + "icon": "", + "images": [] + }, + "flowus": { + "icon": "", + "images": [] + }, + "flstudio": { + "icon": "", + "images": [] + }, + "fluent-reader": { + "icon": "", + "images": [] + }, + "fluent-search": { + "icon": "", + "images": [] + }, + "fluent-terminal": { + "icon": "https://community.chocolatey.org/content/packageimages/fluent-terminal.0.7.7.0.png", + "images": [] + }, + "fluentautomation-repl": { + "icon": "", + "images": [] + }, + "fluentsearch": { + "icon": "", + "images": [] + }, + "fluidsynth": { + "icon": "https://community.chocolatey.org/content/packageimages/fluidsynth.2.3.1.png", + "images": [] + }, + "flutter": { + "icon": "", + "images": [] + }, + "flux": { + "icon": "https://community.chocolatey.org/content/packageimages/flux.0.40.1.png", + "images": [] + }, + "fluxfonts": { + "icon": "", + "images": [] + }, + "flyctl": { + "icon": "https://community.chocolatey.org/content/packageimages/flyctl.0.0.472.png", + "images": [] + }, + "flyingcarpet": { + "icon": "https://community.chocolatey.org/content/packageimages/flyingcarpet.install.6.0.png", + "images": [] + }, + "flyingcube": { + "icon": "", + "images": [] + }, + "flyspeed-sql-query": { + "icon": "", + "images": [] + }, + "flyway": { + "icon": "", + "images": [] + }, + "flyway-commandline": { + "icon": "https://community.chocolatey.org/content/packageimages/flyway.commandline.9.11.0.png", + "images": [] + }, + "flyway-commandline-withjre": { + "icon": "https://community.chocolatey.org/content/packageimages/flyway.commandline.withjre.9.11.0.png", + "images": [] + }, + "fmedia": { + "icon": "", + "images": [] + }, + "fmodel": { + "icon": "https://community.chocolatey.org/content/packageimages/fmodel.4.4.1.1.png", + "images": [] + }, + "fnaticop": { + "icon": "", + "images": [] + }, + "fnlock": { + "icon": "", + "images": [] + }, + "fnm": { + "icon": "", + "images": [] + }, + "fnproject": { + "icon": "", + "images": [] + }, + "fnr": { + "icon": "", + "images": [] + }, + "foca": { + "icon": "https://community.chocolatey.org/content/packageimages/foca.3.4.7.1.png", + "images": [] + }, + "focus": { + "icon": "", + "images": [] + }, + "focusnote": { + "icon": "", + "images": [] + }, + "focuswriter": { + "icon": "", + "images": [] + }, + "fogg": { + "icon": "https://community.chocolatey.org/content/packageimages/fogg.0.7.0.png", + "images": [] + }, + "folder-marker": { + "icon": "https://community.chocolatey.org/content/packageimages/folder-marker.4.4.png", + "images": [] + }, + "folder-painter": { + "icon": "", + "images": [] + }, + "folder-size": { + "icon": "https://community.chocolatey.org/content/packageimages/Folder_Size.5.3.0.2.png", + "images": [] + }, + "foldercolorizer": { + "icon": "", + "images": [] + }, + "foldermenu3": { + "icon": "", + "images": [] + }, + "foldersize": { + "icon": "", + "images": [] + }, + "foldersizes": { + "icon": "https://community.chocolatey.org/content/packageimages/foldersizes.9.0.252.png", + "images": [] + }, + "foldertimeupdate": { + "icon": "https://community.chocolatey.org/content/packageimages/foldertimeupdate.1.55.png", + "images": [] + }, + "folding-at-home": { + "icon": "", + "images": [] + }, + "foldingathome": { + "icon": "", + "images": [] + }, + "foldit": { + "icon": "https://community.chocolatey.org/content/packageimages/foldit.0.0.20190903.png", + "images": [] + }, + "font-awesome-font": { + "icon": "", + "images": [] + }, + "font-firge": { + "icon": "", + "images": [] + }, + "font-gost2-304-81": { + "icon": "", + "images": [] + }, + "fontbase": { + "icon": "https://community.chocolatey.org/content/packageimages/fontbase.2.18.1.png", + "images": [ + "https://i.postimg.cc/rpvHTb1z/image.png", + "https://i.postimg.cc/dt1jW6Cf/image.png" + ] + }, + "fontcreator": { + "icon": "", + "images": [ + "https://i.postimg.cc/zBB8V333/image.png", + "https://i.postimg.cc/V5y8GRgb/image.png", + "https://i.postimg.cc/2yLY7JQD/image.png", + "https://i.postimg.cc/66F4xx1C/image.png", + "https://i.postimg.cc/vH9gQ2pk/image.png", + "https://i.postimg.cc/9Qh4zt2M/image.png", + "https://i.postimg.cc/XYkr5GNg/image.png", + "https://i.postimg.cc/8Ckjmpjg/image.png", + "https://i.postimg.cc/k5jDj0b6/image.png" + ] + }, + "fontforge": { + "icon": "https://i.postimg.cc/kXyktPsr/fontforge.png", + "images": [ + "https://i.postimg.cc/VvKWmgqh/image.png", + "https://i.postimg.cc/T209Vdzc/image.png", + "https://i.postimg.cc/YqSxbckB/image.png" + ] + }, + "fonthelper": { + "icon": "", + "images": [] + }, + "fontreg": { + "icon": "", + "images": [] + }, + "fonts-poppins": { + "icon": "https://community.chocolatey.org/content/packageimages/fonts-poppins.1.1.png", + "images": [] + }, + "fontviewok": { + "icon": "https://i.postimg.cc/5NSK9JZ4/Font-View-OK-ico.png", + "images": [ + "https://i.postimg.cc/SNf1Q4wx/Font-View-OK.png" + ] + }, + "foobar2000": { + "icon": "https://i.postimg.cc/3NV8dpy4/foobar2000-ico.png", + "images": [ + "https://i.postimg.cc/PJ9XPZLC/foobar2000-1.png", + "https://i.postimg.cc/0jFkbm6d/foobar2000-3.png" + ] + }, + "foobar2000-encoders": { + "icon": "", + "images": [] + }, + "force": { + "icon": "", + "images": [] + }, + "force-cli": { + "icon": "https://community.chocolatey.org/content/packageimages/force-cli.0.31.0.png", + "images": [] + }, + "forcebindip": { + "icon": "", + "images": [] + }, + "forceps": { + "icon": "https://community.chocolatey.org/content/packageimages/forceps.1.0.0.1.png", + "images": [] + }, + "forensic7z": { + "icon": "", + "images": [] + }, + "forge": { + "icon": "", + "images": [] + }, + "fork": { + "icon": "https://i.postimg.cc/bryY17ng/fork-logo.png", + "images": [] + }, + "forkgram": { + "icon": "", + "images": [] + }, + "format-factory": { + "icon": "", + "images": [] + }, + "formatfactory": { + "icon": "", + "images": [] + }, + "forseti": { + "icon": "https://community.chocolatey.org/content/packageimages/forseti.portable.1.0.0.0.png", + "images": [] + }, + "forticlientvpn": { + "icon": "", + "images": [] + }, + "fossa": { + "icon": "", + "images": [] + }, + "fossamail": { + "icon": "https://community.chocolatey.org/content/packageimages/fossamail.38.2.0.png", + "images": [] + }, + "fossil": { + "icon": "https://community.chocolatey.org/content/packageimages/fossil.2.21.png", + "images": [] + }, + "foto-mosaik-edda": { + "icon": "", + "images": [] + }, + "fotophire-focus": { + "icon": "", + "images": [] + }, + "fotophire-maximizer": { + "icon": "", + "images": [] + }, + "fotophire-toolkit": { + "icon": "", + "images": [] + }, + "fotor": { + "icon": "", + "images": [] + }, + "fotosketcher": { + "icon": "", + "images": [] + }, + "fotoxplorer": { + "icon": "", + "images": [] + }, + "foxe": { + "icon": "https://community.chocolatey.org/content/packageimages/foxe.portable.2.4.2.2.png", + "images": [] + }, + "foxit-pdf-reader": { + "icon": "https://www.foxit.com/static/company/images/icons/foxit-pdf-reader-logo-500x500.png", + "images": [ + "https://i.ibb.co/WtYDb60/NJ1-E9-Pf7d-T.png" + ] + }, + "foxit-reader": { + "icon": "https://images2.imgbox.com/20/60/DRe5tHGN_o.png", + "images": [ + "https://i.ibb.co/WtYDb60/NJ1-E9-Pf7d-T.png" + ] + }, + "foxitreader": { + "icon": "https://img.utdstc.com/icon/aab/566/aab566ff80c739e8a4d06f1fee8f87fb93c845c92d05751d2e372bde3eb26480:200", + "images": [] + }, + "foxmail": { + "icon": "", + "images": [] + }, + "foxtelgo": { + "icon": "https://community.chocolatey.org/content/packageimages/foxtelgo.1.6.png", + "images": [] + }, + "fpm": { + "icon": "", + "images": [] + }, + "fpt": { + "icon": "https://community.chocolatey.org/content/packageimages/fpt.1.4.0.png", + "images": [] + }, + "fq": { + "icon": "", + "images": [] + }, + "fragger": { + "icon": "", + "images": [] + }, + "fragstats": { + "icon": "https://community.chocolatey.org/content/packageimages/fragstats.4.2.0.20171213.png", + "images": [] + }, + "frame": { + "icon": "", + "images": [] + }, + "franz": { + "icon": "https://community.chocolatey.org/content/packageimages/franz.5.9.2.png", + "images": [] + }, + "frc-radioconfigurationutility": { + "icon": "", + "images": [] + }, + "freac": { + "icon": "https://images.sftcdn.net/images/t_app-icon-s/p/59daf2d0-96d4-11e6-a53e-00163ec9f5fa/379161326/freac-logo.png", + "images": [ + "https://images.sftcdn.net/images/t_app-cover-l,f_auto/p/59daf2d0-96d4-11e6-a53e-00163ec9f5fa/748648210/freac-screenshot.png" + ] + }, + "free-download-manager": { + "icon": "", + "images": [] + }, + "free-manga-downloader": { + "icon": "", + "images": [] + }, + "free-manga-downloader2": { + "icon": "", + "images": [] + }, + "free-ost-reader": { + "icon": "https://community.chocolatey.org/content/packageimages/free-ost-reader.4.1.png", + "images": [] + }, + "free-pst-reader": { + "icon": "https://community.chocolatey.org/content/packageimages/free-pst-reader.4.1.png", + "images": [] + }, + "free-shooter": { + "icon": "", + "images": [] + }, + "free-virtual-keyboard": { + "icon": "https://community.chocolatey.org/content/packageimages/free-virtual-keyboard.5.0.png", + "images": [] + }, + "free42": { + "icon": "", + "images": [] + }, + "freearc": { + "icon": "https://community.chocolatey.org/content/packageimages/freearc.install.0.666.png", + "images": [] + }, + "freebasic": { + "icon": "", + "images": [] + }, + "freecad": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/f/f7/FreeCAD-logo.svg/1200px-FreeCAD-logo.svg.png", + "images": [] + }, + "freeciv": { + "icon": "https://play-lh.googleusercontent.com/pk9708v9vyijJWO__sDAfBkqH-m0jbVo6doXWTQsCoKE9IGb15dT0BgDHyRNwc2oKlI=w480-h960", + "images": [] + }, + "freeclipboardviewer": { + "icon": "", + "images": [] + }, + "freecommander": { + "icon": "", + "images": [] + }, + "freecommander-xe": { + "icon": "https://community.chocolatey.org/content/packageimages/freecommander-xe.portable.2016.715.png", + "images": [] + }, + "freecommanderxe": { + "icon": "", + "images": [] + }, + "freedome": { + "icon": "", + "images": [] + }, + "freedoom": { + "icon": "", + "images": [] + }, + "freedownloadmanager": { + "icon": "https://www.freedownloadmanager.org/public/img/v2/FDM6_logo.png", + "images": [ + "https://www.freedownloadmanager.org/public/img/v2/FDM6_windows_screenshot.png", + "https://www.freedownloadmanager.org/public/img/v2/FDM6_mac_screenshot.png" + ] + }, + "freeencoderpack": { + "icon": "", + "images": [] + }, + "freefem": { + "icon": "", + "images": [] + }, + "freefemplusplus": { + "icon": "https://community.chocolatey.org/content/packageimages/freefemplusplus.4.11.png", + "images": [] + }, + "freefilesync": { + "icon": "https://community.chocolatey.org/content/packageimages/freefilesync.10.2.0.20180914.png", + "images": [] + }, + "freehexeditorneo": { + "icon": "", + "images": [] + }, + "freemake-audio-converter": { + "icon": "https://community.chocolatey.org/content/packageimages/freemake-audio-converter.1.1.8.1000201030.png", + "images": [] + }, + "freemake-video-converter": { + "icon": "https://community.chocolatey.org/content/packageimages/freemake-video-converter.4.1.9.450201030.png", + "images": [] + }, + "freemat": { + "icon": "", + "images": [] + }, + "freemediaplayer": { + "icon": "", + "images": [] + }, + "freemind": { + "icon": "https://community.chocolatey.org/content/packageimages/freemind.1.0.1.png", + "images": [] + }, + "freemove": { + "icon": "", + "images": [] + }, + "freenet": { + "icon": "https://community.chocolatey.org/content/packageimages/freenet.0.7.5.1496.png", + "images": [] + }, + "freeoffice": { + "icon": "https://community.chocolatey.org/content/packageimages/freeoffice.2021.1060.png", + "images": [] + }, + "freeoffice-2021": { + "icon": "", + "images": [] + }, + "freepascal": { + "icon": "https://community.chocolatey.org/content/packageimages/freepascal.3.0.4.png", + "images": [] + }, + "freepascalcompiler": { + "icon": "", + "images": [] + }, + "freepdf": { + "icon": "", + "images": [] + }, + "freepdf-2022": { + "icon": "", + "images": [] + }, + "freeplane": { + "icon": "", + "images": [] + }, + "freerapid": { + "icon": "", + "images": [] + }, + "freerdp": { + "icon": "https://community.chocolatey.org/content/packageimages/freerdp.portable.2.10.0.png", + "images": [] + }, + "freeshooter": { + "icon": "", + "images": [] + }, + "freesnap": { + "icon": "", + "images": [] + }, + "freesshd": { + "icon": "https://community.chocolatey.org/content/packageimages/freeSSHD.1.3.1.png", + "images": [] + }, + "freeswitch": { + "icon": "https://community.chocolatey.org/content/packageimages/freeswitch.1.8.5.png", + "images": [] + }, + "freeter": { + "icon": "https://community.chocolatey.org/content/packageimages/freeter.1.2.1.png", + "images": [] + }, + "freetube": { + "icon": "https://dashboard.snapcraft.io/site_media/appmedia/2023/04/freetube.svg.png", + "images": [ + "https://dl.flathub.org/repo/screenshots/io.freetubeapp.FreeTube-stable/1504x846/io.freetubeapp.FreeTube-907f16599bf6e4ccc54af956f74c9c82.png", + "https://dl.flathub.org/repo/screenshots/io.freetubeapp.FreeTube-stable/1504x846/io.freetubeapp.FreeTube-fb4cac2c93e0714c0f1e1bc9586120ec.png", + "https://dl.flathub.org/repo/screenshots/io.freetubeapp.FreeTube-stable/1504x846/io.freetubeapp.FreeTube-d19954df5ca9968a21c782ab4417c124.png", + "https://dl.flathub.org/repo/screenshots/io.freetubeapp.FreeTube-stable/1504x846/io.freetubeapp.FreeTube-867034d7732ac2bf68406732fbf06487.png" + ] + }, + "freevideoeditor": { + "icon": "https://community.chocolatey.org/content/packageimages/freevideoeditor.8.1.png", + "images": [] + }, + "frescobaldi": { + "icon": "https://community.chocolatey.org/content/packageimages/frescobaldi.3.2.0.png", + "images": [ + "https://www.frescobaldi.org/images/frescobaldi1-en.png", + "https://www.frescobaldi.org/images/magnifier1-en.png", + "https://www.frescobaldi.org/images/scorewiz1-en.png", + "https://www.frescobaldi.org/images/scorewiz2-en.png", + "https://www.frescobaldi.org/images/scorewiz3-en.png" + ] + }, + "freshbing": { + "icon": "", + "images": [] + }, + "frhed": { + "icon": "https://community.chocolatey.org/content/packageimages/frhed.1.6.0.png", + "images": [] + }, + "friture": { + "icon": "https://community.chocolatey.org/content/packageimages/friture.0.49.png", + "images": [] + }, + "fritzing": { + "icon": "", + "images": [] + }, + "frogger": { + "icon": "", + "images": [] + }, + "frogsay": { + "icon": "", + "images": [] + }, + "fromscratch": { + "icon": "", + "images": [] + }, + "frost": { + "icon": "https://community.chocolatey.org/content/packageimages/frost.2011.03.05.png", + "images": [] + }, + "frostwire": { + "icon": "", + "images": [] + }, + "frozenbytes-baseline-dev": { + "icon": "https://community.chocolatey.org/content/packageimages/frozenbytes.baseline.dev.1.0.2.png", + "images": [] + }, + "frozenbytes-dev-essentials": { + "icon": "https://community.chocolatey.org/content/packageimages/frozenbytes.dev.essentials.1.01.png", + "images": [] + }, + "frozenbytes-extras": { + "icon": "https://community.chocolatey.org/content/packageimages/frozenbytes.extras.1.03.png", + "images": [] + }, + "frozenbytes-vs2012-extensions": { + "icon": "https://community.chocolatey.org/content/packageimages/frozenbytes.vs2012.extensions.1.03.png", + "images": [] + }, + "frozenfruits": { + "icon": "https://community.chocolatey.org/content/packageimages/frozenfruits.1.4.0.1.png", + "images": [] + }, + "frozenfruits2": { + "icon": "https://community.chocolatey.org/content/packageimages/frozenfruits2.1.4.0.1.png", + "images": [] + }, + "frp": { + "icon": "", + "images": [] + }, + "fruin-cloudstorage": { + "icon": "", + "images": [] + }, + "fs-uae": { + "icon": "https://community.chocolatey.org/content/packageimages/fs-uae.3.1.66.png", + "images": [] + }, + "fs2020-livery-manager": { + "icon": "", + "images": [] + }, + "fscapture": { + "icon": "https://i.postimg.cc/SRWPM8L5/faststone-capture.png", + "images": [ + "https://screenrecorderpro.files.wordpress.com/2018/03/capture.png", + "https://screenrecorderpro.files.wordpress.com/2018/03/fscapture-auto-save-settings.png", + "https://screenrecorderpro.files.wordpress.com/2018/03/fscapture-editor.png", + "https://screenrecorderpro.files.wordpress.com/2018/03/fscapture-file-name-format.png", + "https://screenrecorderpro.files.wordpress.com/2018/03/fscapture-miscellaneous-settings.png" + ] + }, + "fselect": { + "icon": "", + "images": [] + }, + "fslogix": { + "icon": "https://community.chocolatey.org/content/packageimages/fslogix.2.9.8361.52326.png", + "images": [] + }, + "fslogix-java": { + "icon": "https://community.chocolatey.org/content/packageimages/fslogix-java.2.9.8361.52326.png", + "images": [] + }, + "fspy": { + "icon": "", + "images": [] + }, + "fsresizer": { + "icon": "", + "images": [] + }, + "fsum": { + "icon": "", + "images": [] + }, + "fsumfrontend": { + "icon": "https://community.chocolatey.org/content/packageimages/fsumfrontend.1.5.5.1.png", + "images": [] + }, + "fsviewer": { + "icon": "", + "images": [] + }, + "ftdi-drivers": { + "icon": "https://community.chocolatey.org/content/packageimages/ftdi-drivers.2.12.28.1.png", + "images": [] + }, + "ftester": { + "icon": "https://community.chocolatey.org/content/packageimages/ftester.2016.01.14.png", + "images": [] + }, + "ftpuse": { + "icon": "", + "images": [] + }, + "fu": { + "icon": "", + "images": [] + }, + "fudge": { + "icon": "https://community.chocolatey.org/content/packageimages/fudge.1.3.0.png", + "images": [] + }, + "fuelscm": { + "icon": "https://community.chocolatey.org/content/packageimages/fuelscm.portable.1.0.0.png", + "images": [] + }, + "fun": { + "icon": "", + "images": [] + }, + "func-e": { + "icon": "", + "images": [] + }, + "fundels": { + "icon": "", + "images": [] + }, + "furmark": { + "icon": "https://community.chocolatey.org/content/packageimages/furmark.1.33.0.0.png", + "images": [ + "https://i.postimg.cc/nzFVC0GK/image.png", + "https://i.postimg.cc/4Nmd62kB/image.png" + ] + }, + "furmark-1": { + "icon": "https://community.chocolatey.org/content/packageimages/furmark.1.33.0.0.png", + "images": [ + "https://i.postimg.cc/nzFVC0GK/image.png", + "https://i.postimg.cc/4Nmd62kB/image.png" + ] + }, + "furmark-2": { + "icon": "https://community.chocolatey.org/content/packageimages/furmark.1.33.0.0.png", + "images": [ + "https://i.postimg.cc/pXJHnDyq/image.png", + "https://i.postimg.cc/wxJH9KzK/image.png" + ] + }, + "fuse-nfs": { + "icon": "https://community.chocolatey.org/content/packageimages/fuse-nfs.5.0.2.png", + "images": [] + }, + "fusion-ldv": { + "icon": "https://community.chocolatey.org/content/packageimages/fusion-ldv.4.40.png", + "images": [] + }, + "fusioninventory-agent": { + "icon": "https://community.chocolatey.org/content/packageimages/fusioninventory-agent.2.6.png", + "images": [] + }, + "futurerestore-gui": { + "icon": "", + "images": [] + }, + "fuze": { + "icon": "", + "images": [] + }, + "fv": { + "icon": "https://community.chocolatey.org/content/packageimages/fv.install.0.6.3.5830.png", + "images": [] + }, + "fvie": { + "icon": "", + "images": [] + }, + "fvim": { + "icon": "https://community.chocolatey.org/content/packageimages/fvim.0.3.531.png", + "images": [] + }, + "fvm": { + "icon": "", + "images": [] + }, + "fvpn": { + "icon": "", + "images": [] + }, + "fx": { + "icon": "", + "images": [] + }, + "fx-win": { + "icon": "", + "images": [] + }, + "fxgqlc": { + "icon": "", + "images": [] + }, + "fxsound": { + "icon": "https://i.ibb.co/0Rx00jW6/image.png", + "images": [] + }, + "fysty": { + "icon": "", + "images": [] + }, + "fzf": { + "icon": "", + "images": [] + }, + "g-assist": { + "icon": "", + "images": [] + }, + "g-desktop-suite": { + "icon": "", + "images": [] + }, + "g-helper": { + "icon": "https://i.ibb.co/PvLShmHH/ghelper.png", + "images": [ + "https://i.postimg.cc/7ZLhgWHV/image.png", + "https://i.postimg.cc/BbsQth7T/image.png", + "https://i.postimg.cc/0yr56KnL/image.png" + ] + }, + "g14controlv2": { + "icon": "", + "images": [] + }, + "gae-sdk": { + "icon": "", + "images": [] + }, + "gajim": { + "icon": "", + "images": [] + }, + "galaxian": { + "icon": "", + "images": [] + }, + "galaxy": { + "icon": "", + "images": [] + }, + "galaxybudsclient": { + "icon": "", + "images": [] + }, + "gallery-dl": { + "icon": "", + "images": [] + }, + "galliobundle": { + "icon": "", + "images": [] + }, + "gam": { + "icon": "", + "images": [] + }, + "gambit": { + "icon": "", + "images": [] + }, + "game-collector": { + "icon": "https://community.chocolatey.org/content/packageimages/game-collector.23.1.1.png", + "images": [] + }, + "game-key-revealer": { + "icon": "", + "images": [] + }, + "gamebooster": { + "icon": "https://community.chocolatey.org/content/packageimages/gamebooster.5.1.38.0.png", + "images": [] + }, + "gameboosthd": { + "icon": "", + "images": [] + }, + "gamecapture-4k60promk2": { + "icon": "", + "images": [] + }, + "gamecapture-hd": { + "icon": "", + "images": [] + }, + "gamecapture-hd60s": { + "icon": "", + "images": [] + }, + "gamecaster": { + "icon": "https://community.chocolatey.org/content/packageimages/gamecaster.4.0.2109.2802.png", + "images": [] + }, + "gamecenter": { + "icon": "", + "images": [] + }, + "gamedownloader": { + "icon": "https://community.chocolatey.org/content/packageimages/gamedownloader.4.0.20150329.png", + "images": [] + }, + "gamemaker-studio-1": { + "icon": "", + "images": [] + }, + "gameplay-time-tracker": { + "icon": "https://community.chocolatey.org/content/packageimages/gameplay-time-tracker.3.1.0.0.png", + "images": [] + }, + "gameplayer": { + "icon": "", + "images": [] + }, + "games": { + "icon": "https://seeklogo.com/images/A/amazon-games-logo-BE9EB714E4-seeklogo.com.png", + "images": [ + "https://m.media-amazon.com/images/G/01/sm/shared/166979982420469/social_image._CB409110150_.jpg", + "https://theculturednerd.org/wp-content/uploads/2020/10/Crucible-Featured.png", + "https://www.howtogeek.com/wp-content/uploads/2020/06/0-amazon-games-header.jpg", + "https://www.androidheadlines.com/wp-content/uploads/2021/01/Prime-Gaming-Amazon-Games-Launcher.jpg" + ] + }, + "gamesavemanager": { + "icon": "https://community.chocolatey.org/content/packageimages/gamesavemanager.3.1.517.0.png", + "images": [] + }, + "gamevox": { + "icon": "", + "images": [] + }, + "gammy": { + "icon": "", + "images": [] + }, + "ganache": { + "icon": "", + "images": [] + }, + "ganttproject": { + "icon": "https://community.chocolatey.org/content/packageimages/ganttproject.3.1.3100.png", + "images": [] + }, + "gaoding": { + "icon": "", + "images": [] + }, + "garam-editor": { + "icon": "https://community.chocolatey.org/content/packageimages/Garam-Editor.1.0.0.4.png", + "images": [] + }, + "gardenlogin": { + "icon": "https://community.chocolatey.org/content/packageimages/gardenlogin.0.3.0.png", + "images": [] + }, + "garena": { + "icon": "https://community.chocolatey.org/content/packageimages/garena.2.0.png", + "images": [] + }, + "gateway": { + "icon": "", + "images": [] + }, + "gather": { + "icon": "https://community.chocolatey.org/content/packageimages/gather.0.3.23.png", + "images": [] + }, + "gatling": { + "icon": "", + "images": [] + }, + "gauche": { + "icon": "", + "images": [] + }, + "gauge": { + "icon": "https://community.chocolatey.org/content/packageimages/gauge.1.4.3.png", + "images": [] + }, + "gawk": { + "icon": "", + "images": [] + }, + "gax2012": { + "icon": "", + "images": [] + }, + "gazel-cli": { + "icon": "https://community.chocolatey.org/content/packageimages/gazel-cli.1.2.2.png", + "images": [] + }, + "gb-mongodb": { + "icon": "https://community.chocolatey.org/content/packageimages/gb.MongoDB.2.4.7.0.png", + "images": [] + }, + "gb-studio": { + "icon": "", + "images": [] + }, + "gbm": { + "icon": "https://community.chocolatey.org/content/packageimages/gbm.1.3.4.png", + "images": [] + }, + "gbstudio": { + "icon": "https://community.chocolatey.org/content/packageimages/gbstudio.1.2.1.png", + "images": [] + }, + "gbt": { + "icon": "", + "images": [] + }, + "gc-menu": { + "icon": "", + "images": [] + }, + "gcc": { + "icon": "", + "images": [] + }, + "gcc-arm-none-eabi": { + "icon": "", + "images": [] + }, + "gcfscape": { + "icon": "", + "images": [] + }, + "gcloud": { + "icon": "", + "images": [] + }, + "gcompris": { + "icon": "https://community.chocolatey.org/content/packageimages/gcompris.1.0.png", + "images": [] + }, + "gcsa": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/a/a5/Google_Calendar_icon_%282020%29.svg/512px-Google_Calendar_icon_%282020%29.svg.png", + "images": [] + }, + "gcstar": { + "icon": "https://community.chocolatey.org/content/packageimages/gcstar.1.6.1.png", + "images": [] + }, + "gdb": { + "icon": "", + "images": [] + }, + "gdevelop": { + "icon": "https://community.chocolatey.org/content/packageimages/gdevelop.4.0.94.png", + "images": [] + }, + "gdiview": { + "icon": "https://community.chocolatey.org/content/packageimages/gdiview.1.26.png", + "images": [] + }, + "gdlauncher": { + "icon": "", + "images": [] + }, + "gdu": { + "icon": "", + "images": [] + }, + "geany": { + "icon": "https://community.chocolatey.org/content/packageimages/geany.1.38.0.png", + "images": [] + }, + "geany-nogtk": { + "icon": "https://community.chocolatey.org/content/packageimages/geany-nogtk.1.27.png", + "images": [] + }, + "geany-plugins": { + "icon": "https://community.chocolatey.org/content/packageimages/geany-plugins.1.38.png", + "images": [] + }, + "geckodriver": { + "icon": "", + "images": [] + }, + "gedit": { + "icon": "", + "images": [] + }, + "gedkeeper": { + "icon": "https://i.postimg.cc/T3VXdqJ9/GEDKeeper-48.png", + "images": [ + "https://i.postimg.cc/XJtq0YQy/image.png", + "https://i.postimg.cc/j5HmR8hQ/image.png", + "https://i.postimg.cc/bv3S4P7Q/image.png", + "https://i.postimg.cc/JzX9T4B2/image.png" + ] + }, + "geekbench": { + "icon": "", + "images": [] + }, + "geekbench-4": { + "icon": "https://i.postimg.cc/BnRGNY1Y/Geekbench6.png", + "images": [] + }, + "geekbench-5": { + "icon": "https://i.postimg.cc/BnRGNY1Y/Geekbench6.png", + "images": [] + }, + "geekbench-6": { + "icon": "https://i.postimg.cc/BnRGNY1Y/Geekbench6.png", + "images": [ + "https://i.postimg.cc/FK0wp9vz/image.png" + ] + }, + "geekbench2": { + "icon": "https://community.chocolatey.org/content/packageimages/geekbench2.2.4.3.png", + "images": [] + }, + "geekbench3": { + "icon": "https://community.chocolatey.org/content/packageimages/geekbench3.3.4.4.png", + "images": [] + }, + "geekbench4": { + "icon": "https://community.chocolatey.org/content/packageimages/geekbench4.4.4.4.png", + "images": [] + }, + "geekbench5": { + "icon": "https://community.chocolatey.org/content/packageimages/geekbench5.5.5.1.png", + "images": [] + }, + "geekbench6": { + "icon": "https://i.postimg.cc/BnRGNY1Y/Geekbench6.png", + "images": [] + }, + "geekuninstaller": { + "icon": "", + "images": [] + }, + "geforce-experience": { + "icon": "https://community.chocolatey.org/content/packageimages/geforce-experience.3.27.0.112.png", + "images": [] + }, + "geforce-game-ready-driver": { + "icon": "https://community.chocolatey.org/content/packageimages/geforce-game-ready-driver.528.49.png", + "images": [] + }, + "geforce-game-ready-driver-win10": { + "icon": "", + "images": [] + }, + "geforceexperience": { + "icon": "https://styles.redditmedia.com/t5_2rlgy/styles/communityIcon_vjvyn29wsuj51.png", + "images": [] + }, + "geforcenow": { + "icon": "", + "images": [ + "https://i.postimg.cc/g20x2SPP/image.png", + "https://i.postimg.cc/tgZ7hsTS/image.png" + ] + }, + "gejigeji": { + "icon": "", + "images": [] + }, + "genact": { + "icon": "", + "images": [] + }, + "genius-chrome": { + "icon": "https://community.chocolatey.org/content/packageimages/genius-chrome.0.1.2.png", + "images": [] + }, + "genuinetools": { + "icon": "https://community.chocolatey.org/content/packageimages/genuinetools.0.0.1.png", + "images": [] + }, + "genymotion": { + "icon": "https://community.chocolatey.org/content/packageimages/genymotion.3.3.2.png", + "images": [] + }, + "geoda": { + "icon": "https://community.chocolatey.org/content/packageimages/geoda.1.20.0.8.png", + "images": [] + }, + "geogebra": { + "icon": "", + "images": [] + }, + "geogebra-classic": { + "icon": "https://community.chocolatey.org/content/packageimages/geogebra-classic.install.6.0.752.0.png", + "images": [] + }, + "geogebra-geometry": { + "icon": "https://community.chocolatey.org/content/packageimages/geogebra-geometry.6.0.760.0.png", + "images": [] + }, + "geogebra6": { + "icon": "https://community.chocolatey.org/content/packageimages/geogebra6.6.0.760.0.png", + "images": [] + }, + "geoipupdate": { + "icon": "", + "images": [] + }, + "geometry": { + "icon": "", + "images": [] + }, + "geoscene3d": { + "icon": "", + "images": [] + }, + "geoserver": { + "icon": "https://community.chocolatey.org/content/packageimages/geoserver.2.22.2.png", + "images": [] + }, + "geosetter": { + "icon": "", + "images": [] + }, + "geostudio": { + "icon": "", + "images": [] + }, + "gephi": { + "icon": "https://community.chocolatey.org/content/packageimages/gephi.0.10.1.png", + "images": [] + }, + "geppetto": { + "icon": "", + "images": [] + }, + "get-childitemcolor": { + "icon": "https://community.chocolatey.org/content/packageimages/get-childitemcolor.3.4.0.png", + "images": [] + }, + "get-iplayer": { + "icon": "", + "images": [] + }, + "getdataback-simple": { + "icon": "", + "images": [] + }, + "getdiz": { + "icon": "", + "images": [] + }, + "geteventstore": { + "icon": "", + "images": [] + }, + "geth": { + "icon": "", + "images": [] + }, + "getiplayer": { + "icon": "https://community.chocolatey.org/content/packageimages/getiplayer.3.31.png", + "images": [] + }, + "getopt": { + "icon": "https://community.chocolatey.org/content/packageimages/getopt.2.14.1.png", + "images": [] + }, + "getter1": { + "icon": "", + "images": [] + }, + "getuserinfo": { + "icon": "https://community.chocolatey.org/content/packageimages/getuserinfo.2.07.00.png", + "images": [] + }, + "geupd": { + "icon": "https://community.chocolatey.org/content/packageimages/geupd.3.9.303.0.png", + "images": [] + }, + "geupd4": { + "icon": "https://community.chocolatey.org/content/packageimages/geupd4.2.1.0.1.png", + "images": [] + }, + "gevent": { + "icon": "", + "images": [] + }, + "gforth": { + "icon": "", + "images": [] + }, + "gfxbench": { + "icon": "", + "images": [] + }, + "gg": { + "icon": "https://i.imgur.com/KS6qrz8.png", + "images": [] + }, + "ggu-software": { + "icon": "https://community.chocolatey.org/content/packageimages/ggu-software.20.23.004.png", + "images": [] + }, + "ggu-software-international": { + "icon": "https://community.chocolatey.org/content/packageimages/ggu-software-international.20.23.004.png", + "images": [] + }, + "gh": { + "icon": "https://community.chocolatey.org/content/packageimages/gh.2.23.0.png", + "images": [] + }, + "gh-api-cli": { + "icon": "", + "images": [] + }, + "ghb0t": { + "icon": "https://community.chocolatey.org/content/packageimages/ghb0t.0.4.0.png", + "images": [] + }, + "ghc": { + "icon": "", + "images": [] + }, + "ghidra": { + "icon": "https://community.chocolatey.org/content/packageimages/ghidra.10.2.3.png", + "images": [] + }, + "ghorg": { + "icon": "", + "images": [] + }, + "ghost": { + "icon": "", + "images": [] + }, + "ghost-desktop": { + "icon": "https://community.chocolatey.org/content/packageimages/ghost-desktop.1.7.0.png", + "images": [] + }, + "ghostdoc-enterprise": { + "icon": "https://community.chocolatey.org/content/packageimages/ghostdoc-enterprise.2022.2.22190.png", + "images": [] + }, + "ghostdoc-pro": { + "icon": "https://community.chocolatey.org/content/packageimages/ghostdoc-pro.2022.2.22190.png", + "images": [] + }, + "ghostscript": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/d/dd/Ghostscript_logo.svg/853px-Ghostscript_logo.svg.png", + "images": [] + }, + "ghostscript-app": { + "icon": "", + "images": [] + }, + "ghostwriter": { + "icon": "", + "images": [] + }, + "ghq": { + "icon": "", + "images": [] + }, + "ghub": { + "icon": "https://i.imgur.com/xkIS90o.png", + "images": [] + }, + "gibo": { + "icon": "", + "images": [] + }, + "gibu": { + "icon": "", + "images": [] + }, + "giddh": { + "icon": "", + "images": [] + }, + "gifcam": { + "icon": "https://community.chocolatey.org/content/packageimages/gifcam.6.5.0.0.png", + "images": [] + }, + "gifsicle": { + "icon": "", + "images": [] + }, + "gifski": { + "icon": "", + "images": [] + }, + "gifyourgame": { + "icon": "", + "images": [] + }, + "gimagereader": { + "icon": "https://community.chocolatey.org/content/packageimages/gimagereader.3.4.1.png", + "images": [] + }, + "gimagex": { + "icon": "", + "images": [] + }, + "gimmieaguid": { + "icon": "", + "images": [] + }, + "gimp": { + "icon": "https://gitlab.gnome.org/GNOME/gimp/-/raw/f73c4ed397d797ec1b5175f27b5c0f3538a87714/data/images/gimp-logo.png", + "images": [ + "https://docs.gimp.org/2.10/en/images/using/multi-window.png", + "https://i.sooftcdn.com/screen/en/windows/gimp-1.png", + "https://www.ionos.it/digitalguide/fileadmin/DigitalGuide/Screenshots_2021/screenshot-funktion-von-gimp.png" + ] + }, + "gimp-nightly": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/4/45/The_GIMP_icon_-_gnome.svg/316px-The_GIMP_icon_-_gnome.svg.png", + "images": [ + "https://docs.gimp.org/2.10/en/images/using/multi-window.png", + "https://i.sooftcdn.com/screen/en/windows/gimp-1.png", + "https://www.ionos.it/digitalguide/fileadmin/DigitalGuide/Screenshots_2021/screenshot-funktion-von-gimp.png" + ] + }, + "gingerchrome": { + "icon": "", + "images": [] + }, + "gingerwriter": { + "icon": "https://community.chocolatey.org/content/packageimages/gingerwriter.1.0.0.png", + "images": [] + }, + "gink": { + "icon": "", + "images": [] + }, + "git": { + "icon": "https://unigeticons.meowcat285.com/git.2.46.2.png", + "images": [ + "https://i.postimg.cc/QMmHqPP9/git1.png", + "https://i.postimg.cc/cHJ6khyD/git2.png", + "https://i.postimg.cc/j5k2pfRR/git3.png" + ] + }, + "git-aliases": { + "icon": "", + "images": [] + }, + "git-annex": { + "icon": "", + "images": [] + }, + "git-branchless": { + "icon": "", + "images": [] + }, + "git-bug": { + "icon": "", + "images": [] + }, + "git-chglog": { + "icon": "", + "images": [] + }, + "git-cliff": { + "icon": "", + "images": [] + }, + "git-cola": { + "icon": "https://community.chocolatey.org/content/packageimages/git-cola.4.1.0.png", + "images": [] + }, + "git-commandline": { + "icon": "", + "images": [] + }, + "git-credential-manager": { + "icon": "", + "images": [] + }, + "git-credential-manager-core": { + "icon": "", + "images": [] + }, + "git-credential-manager-for-windows": { + "icon": "https://community.chocolatey.org/content/packageimages/Git-Credential-Manager-for-Windows.1.20.0.png", + "images": [] + }, + "git-credential-winstore": { + "icon": "", + "images": [] + }, + "git-crypt": { + "icon": "", + "images": [] + }, + "git-filter-repo": { + "icon": "", + "images": [] + }, + "git-flow-dependencies": { + "icon": "", + "images": [] + }, + "git-flow-hooks": { + "icon": "https://community.chocolatey.org/content/packageimages/git-flow-hooks.1.0.4.png", + "images": [] + }, + "git-fork": { + "icon": "https://community.chocolatey.org/content/packageimages/git-fork.1.82.1.png", + "images": [] + }, + "git-helper": { + "icon": "", + "images": [] + }, + "git-interactive-rebase-tool": { + "icon": "", + "images": [] + }, + "git-istage": { + "icon": "", + "images": [] + }, + "git-it": { + "icon": "https://community.chocolatey.org/content/packageimages/git-it.4.4.0.png", + "images": [] + }, + "git-lfs": { + "icon": "https://community.chocolatey.org/content/packageimages/git-lfs.install.3.3.0.png", + "images": [] + }, + "git-lfx": { + "icon": "https://community.chocolatey.org/content/packageimages/git-lfx.0.1.0.png", + "images": [] + }, + "git-phlow": { + "icon": "", + "images": [] + }, + "git-quick-stats": { + "icon": "", + "images": [] + }, + "git-sizer": { + "icon": "", + "images": [] + }, + "git-status-cache-posh-client": { + "icon": "", + "images": [] + }, + "git-tf": { + "icon": "", + "images": [] + }, + "git-tfs": { + "icon": "", + "images": [] + }, + "git-tower": { + "icon": "", + "images": [] + }, + "git-town": { + "icon": "", + "images": [] + }, + "git-up": { + "icon": "", + "images": [] + }, + "git-with-openssh": { + "icon": "", + "images": [] + }, + "git-xargs": { + "icon": "", + "images": [] + }, + "gitahead": { + "icon": "https://community.chocolatey.org/content/packageimages/gitahead.2.6.3.png", + "images": [] + }, + "gitb": { + "icon": "", + "images": [] + }, + "gitblade": { + "icon": "", + "images": [] + }, + "gitblit": { + "icon": "", + "images": [] + }, + "gitbutler": { + "icon": "https://gitbutler.com/favicon/favicon-64x64.png", + "images": [ + "https://docs.gitbutler.com/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Finitial-workspace.8084a3ae.png&w=3840&q=75" + ] + }, + "gitcredentialmanagercore": { + "icon": "", + "images": [] + }, + "gitdiffmargin": { + "icon": "", + "images": [] + }, + "gitdiffmargin-vs2012": { + "icon": "https://community.chocolatey.org/content/packageimages/GitDiffMargin.vs2012.1.0.png", + "images": [] + }, + "gitdiffmargin-vs2013": { + "icon": "https://community.chocolatey.org/content/packageimages/GitDiffMargin.vs2013.2.0.0.png", + "images": [] + }, + "gitea": { + "icon": "https://community.chocolatey.org/content/packageimages/gitea.1.18.5.png", + "images": [] + }, + "gitextensions": { + "icon": "https://community.chocolatey.org/content/packageimages/gitextensions.portable.4.0.2.png", + "images": [] + }, + "giteye": { + "icon": "", + "images": [] + }, + "gitfiend": { + "icon": "", + "images": [] + }, + "gitflow-avh": { + "icon": "https://community.chocolatey.org/content/packageimages/gitflow-avh.0.0.0.20200718.png", + "images": [] + }, + "gitflow-hooks": { + "icon": "https://community.chocolatey.org/content/packageimages/gitflow-hooks.1.0.1.png", + "images": [] + }, + "gitg": { + "icon": "", + "images": [] + }, + "github": { + "icon": "", + "images": [] + }, + "github-build-from-label": { + "icon": "", + "images": [] + }, + "github-desktop": { + "icon": "https://community.chocolatey.org/content/packageimages/github-desktop.3.1.8.png", + "images": [] + }, + "github-hovercard-chrome": { + "icon": "https://community.chocolatey.org/content/packageimages/github-hovercard-chrome.1.4.4.png", + "images": [] + }, + "githubdesktop": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/a/ae/Github-desktop-logo-symbol.svg/128px-Github-desktop-logo-symbol.svg.png", + "images": [ + "https://desktop.github.com/images/screenshot-windows-light.png", + "https://docs.github.com/assets/cb-23214/images/help/desktop/windows-choose-options.png", + "https://user-images.githubusercontent.com/634063/202742985-bb3b3b94-8aca-404a-8d8a-fd6a6f030672.png" + ] + }, + "githubdesktop-beta": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/a/ae/Github-desktop-logo-symbol.svg/128px-Github-desktop-logo-symbol.svg.png", + "images": [ + "https://desktop.github.com/images/screenshot-windows-light.png", + "https://docs.github.com/assets/cb-23214/images/help/desktop/windows-choose-options.png", + "https://user-images.githubusercontent.com/634063/202742985-bb3b3b94-8aca-404a-8d8a-fd6a6f030672.png" + ] + }, + "githubforwindows": { + "icon": "", + "images": [] + }, + "githublink": { + "icon": "https://community.chocolatey.org/content/packageimages/githublink.2.3.0.png", + "images": [] + }, + "githubreleasemanager": { + "icon": "", + "images": [] + }, + "githubreleasenotes": { + "icon": "https://community.chocolatey.org/content/packageimages/githubreleasenotes.1.0.7.1.png", + "images": [] + }, + "giti": { + "icon": "", + "images": [] + }, + "gitify": { + "icon": "", + "images": [] + }, + "gitignore": { + "icon": "", + "images": [] + }, + "gitkraken": { + "icon": "https://dashboard.snapcraft.io/site_media/appmedia/2018/01/1.png", + "images": [ + "https://i.postimg.cc/nLn0ndMK/image.png", + "https://i.postimg.cc/RZKDS6dm/image.png", + "https://i.ibb.co/TDShJbTM/Image.pn" + ] + }, + "gitkube": { + "icon": "", + "images": [] + }, + "gitlab-runner": { + "icon": "https://community.chocolatey.org/content/packageimages/gitlab-runner.15.8.0.png", + "images": [] + }, + "gitleaks": { + "icon": "https://community.chocolatey.org/content/packageimages/gitleaks.8.16.0.png", + "images": [] + }, + "gitlfs": { + "icon": "", + "images": [] + }, + "gitnote": { + "icon": "", + "images": [] + }, + "gitnuro": { + "icon": "", + "images": [] + }, + "gitomatic": { + "icon": "", + "images": [] + }, + "gitpad": { + "icon": "", + "images": [] + }, + "gitreleasemanager": { + "icon": "", + "images": [] + }, + "gitreleasenotes": { + "icon": "", + "images": [] + }, + "gitreleasenotes-portable": { + "icon": "", + "images": [] + }, + "gitsh": { + "icon": "", + "images": [] + }, + "gitsign": { + "icon": "", + "images": [] + }, + "gitsvnexternals": { + "icon": "", + "images": [] + }, + "gitter": { + "icon": "https://community.chocolatey.org/content/packageimages/gitter.5.0.1.20200714.png", + "images": [] + }, + "gittfs": { + "icon": "https://community.chocolatey.org/content/packageimages/gittfs.0.32.0.png", + "images": [] + }, + "gittyup": { + "icon": "", + "images": [] + }, + "gitui": { + "icon": "", + "images": [] + }, + "gitversion": { + "icon": "", + "images": [] + }, + "gitversion-portable": { + "icon": "https://community.chocolatey.org/content/packageimages/GitVersion.Portable.5.12.0.png", + "images": [] + }, + "gitversioner": { + "icon": "", + "images": [] + }, + "gitviz": { + "icon": "", + "images": [] + }, + "glab": { + "icon": "https://community.chocolatey.org/content/packageimages/glab.portable.1.24.1.png", + "images": [] + }, + "glary-utilities": { + "icon": "", + "images": [] + }, + "glaryutilities": { + "icon": "https://tweakers.net/ext/i/2004642056.jpeg", + "images": [ + "https://www.glarysoft.com/images/screenshots/glary-utilities/galry-utilities3.png", + "https://www.glarysoft.com/images/screenshots/glary-utilities/galry-utilities2.png" + ] + }, + "glaryutilities-free": { + "icon": "https://community.chocolatey.org/content/packageimages/glaryutilities-free.5.148.0.174.png", + "images": [] + }, + "glaryutilities-pro": { + "icon": "https://community.chocolatey.org/content/packageimages/glaryutilities-pro.5.121.0.146.png", + "images": [] + }, + "glasscannon": { + "icon": "", + "images": [] + }, + "glassfish": { + "icon": "", + "images": [] + }, + "glasswire": { + "icon": "https://i.postimg.cc/c1XvgWkK/image.png", + "images": [ + "https://i.postimg.cc/k4j74JMq/image.png", + "https://i.postimg.cc/dQpKSSLH/image.png", + "https://i.postimg.cc/T3XvTLjn/image.png", + "https://i.postimg.cc/DzvVb9MZ/image.png" + ] + }, + "glasswire-lite": { + "icon": "", + "images": [] + }, + "glazewm": { + "icon": "", + "images": [] + }, + "gleam": { + "icon": "", + "images": [] + }, + "glfw3": { + "icon": "", + "images": [] + }, + "glimpse": { + "icon": "https://community.chocolatey.org/content/packageimages/glimpse.0.2.0.png", + "images": [] + }, + "glitter": { + "icon": "", + "images": [] + }, + "global": { + "icon": "https://community.chocolatey.org/content/packageimages/global.6.5.2.png", + "images": [] + }, + "globalmapper": { + "icon": "", + "images": [] + }, + "globalplatformpro": { + "icon": "", + "images": [] + }, + "globalvpn": { + "icon": "", + "images": [] + }, + "glogg": { + "icon": "https://community.chocolatey.org/content/packageimages/glogg.1.1.4.png", + "images": [] + }, + "glossi": { + "icon": "https://community.chocolatey.org/content/packageimages/glossi.0.0.8.1.png", + "images": [] + }, + "glouton": { + "icon": "https://community.chocolatey.org/content/packageimages/glouton.23.01.04.103523.png", + "images": [] + }, + "glow": { + "icon": "", + "images": [] + }, + "glpi-agent": { + "icon": "https://i.postimg.cc/JhrM5cBw/glpi-agent.png", + "images": [] + }, + "glpk": { + "icon": "https://community.chocolatey.org/content/packageimages/glpk.4.65.20210830.png", + "images": [] + }, + "glslang": { + "icon": "", + "images": [] + }, + "glslviewer": { + "icon": "", + "images": [] + }, + "glyph-launcher": { + "icon": "", + "images": [] + }, + "glyphexporter": { + "icon": "", + "images": [] + }, + "glyphr-studio-desktop": { + "icon": "https://community.chocolatey.org/content/packageimages/glyphr-studio-desktop.0.5.6.png", + "images": [] + }, + "gm8x-fix": { + "icon": "", + "images": [] + }, + "gmac-teamcity": { + "icon": "", + "images": [] + }, + "gmail-desktop": { + "icon": "", + "images": [] + }, + "gmail-growl": { + "icon": "https://community.chocolatey.org/content/packageimages/gmail-growl.2.4.0.png", + "images": [] + }, + "gmailnotifier": { + "icon": "https://community.chocolatey.org/content/packageimages/gmailnotifier.1.2.1.png", + "images": [] + }, + "gmer": { + "icon": "https://community.chocolatey.org/content/packageimages/gmer.2.2.19882.20161107.png", + "images": [] + }, + "gmkvextractgui": { + "icon": "https://community.chocolatey.org/content/packageimages/gmkvextractgui.2.6.2.png", + "images": [] + }, + "gms": { + "icon": "https://community.chocolatey.org/content/packageimages/gms.10.5.12.png", + "images": [] + }, + "gmsh": { + "icon": "https://community.chocolatey.org/content/packageimages/gmsh.4.10.5.png", + "images": [] + }, + "gmt": { + "icon": "", + "images": [] + }, + "gmvault": { + "icon": "", + "images": [] + }, + "gnat-gpl": { + "icon": "https://community.chocolatey.org/content/packageimages/gnat-gpl.2021.0.png", + "images": [] + }, + "gnatsd": { + "icon": "https://community.chocolatey.org/content/packageimages/gnatsd.1.0.2.20170727.png", + "images": [] + }, + "gnirehtet": { + "icon": "", + "images": [] + }, + "gnuarmembeddedtoolchain": { + "icon": "", + "images": [] + }, + "gnucash": { + "icon": "https://tweakers.net/ext/i/2004646972.png", + "images": [ + "https://tweakers.net/ext/i/2005189022.jpeg" + ] + }, + "gnucobol": { + "icon": "", + "images": [] + }, + "gnumeric": { + "icon": "https://community.chocolatey.org/content/packageimages/gnumeric.1.12.17.20200531.png", + "images": [] + }, + "gnupg": { + "icon": "https://gnupg.org/share/logo-gnupg-light-purple-bg.png", + "images": [] + }, + "gnupg-modern": { + "icon": "", + "images": [] + }, + "gnupg1": { + "icon": "", + "images": [] + }, + "gnuplot": { + "icon": "https://community.chocolatey.org/content/packageimages/gnuplot.portable.5.0.1.png", + "images": [] + }, + "gnuradio": { + "icon": "https://community.chocolatey.org/content/packageimages/gnuradio.3.8.2.1.png", + "images": [] + }, + "gnuwin32-coreutils": { + "icon": "https://community.chocolatey.org/content/packageimages/gnuwin32-coreutils.portable.5.3.0.png", + "images": [] + }, + "gnvm": { + "icon": "https://community.chocolatey.org/content/packageimages/gnvm.0.2.0.png", + "images": [] + }, + "go": { + "icon": "https://unigeticons.meowcat285.com/Go-Logo_Blue.png", + "images": [] + }, + "go-contact-sync-mod": { + "icon": "", + "images": [] + }, + "go-containerregistry": { + "icon": "", + "images": [] + }, + "go-fmt-fail": { + "icon": "", + "images": [] + }, + "go-fonts": { + "icon": "https://community.chocolatey.org/content/packageimages/go-fonts.2.008.png", + "images": [] + }, + "go-jsonnet": { + "icon": "", + "images": [] + }, + "go-msi": { + "icon": "", + "images": [] + }, + "go-swagger": { + "icon": "", + "images": [] + }, + "go-unstable": { + "icon": "", + "images": [] + }, + "goagent": { + "icon": "", + "images": [] + }, + "goauthing": { + "icon": "", + "images": [] + }, + "goawayedge": { + "icon": "https://dl.exploitox.de/goawayedge/GoAwayEdge_Logo.png", + "images": [ + "https://dl.exploitox.de/goawayedge/GoAwayEdge_Screenshot2.png" + ] + }, + "gobang": { + "icon": "", + "images": [] + }, + "gobby": { + "icon": "https://community.chocolatey.org/content/packageimages/gobby.0.6.0.png", + "images": [] + }, + "gobuster": { + "icon": "", + "images": [] + }, + "gocdagent": { + "icon": "", + "images": [] + }, + "gocdserver": { + "icon": "", + "images": [] + }, + "gociagent": { + "icon": "", + "images": [] + }, + "godot": { + "icon": "https://community.chocolatey.org/content/packageimages/godot.3.5.1.png", + "images": [] + }, + "godot-manager": { + "icon": "", + "images": [] + }, + "godot-mono": { + "icon": "https://community.chocolatey.org/content/packageimages/godot-mono.3.5.1.png", + "images": [] + }, + "gof": { + "icon": "", + "images": [] + }, + "gog-galaxy-plugin-downloader": { + "icon": "", + "images": [] + }, + "goggalaxy": { + "icon": "https://community.chocolatey.org/content/packageimages/goggalaxy.2.0.58.4.png", + "images": [] + }, + "gogs": { + "icon": "", + "images": [] + }, + "goland": { + "icon": "https://resources.jetbrains.com/storage/products/goland/img/meta/goland_logo_300x300.png", + "images": [] + }, + "goland-earlyaccess": { + "icon": "https://resources.jetbrains.com/storage/products/goland/img/meta/goland_logo_300x300.png", + "images": [] + }, + "golang": { + "icon": "https://go.dev/images/favicon-gopher.png", + "images": [] + }, + "golangci-lint": { + "icon": "", + "images": [] + }, + "goldendict": { + "icon": "https://community.chocolatey.org/content/packageimages/goldendict.install.1.0.1.png", + "images": [] + }, + "goldendict-en-ru-en": { + "icon": "https://community.chocolatey.org/content/packageimages/goldendict-en-ru-en.install.1.0.1.png", + "images": [] + }, + "goldwave": { + "icon": "", + "images": [] + }, + "golly": { + "icon": "https://community.chocolatey.org/content/packageimages/golly.4.2.png", + "images": [] + }, + "gom-player": { + "icon": "https://community.chocolatey.org/content/packageimages/gom-player.2.3.83.5350.png", + "images": [] + }, + "gomodrun": { + "icon": "", + "images": [] + }, + "gomplate": { + "icon": "https://community.chocolatey.org/content/packageimages/gomplate.3.9.0.png", + "images": [] + }, + "gomplayer": { + "icon": "https://upload.wikimedia.org/wikipedia/uk/a/a0/GOM_Player_Logo.png", + "images": [] + }, + "gomuks": { + "icon": "", + "images": [] + }, + "goneovim": { + "icon": "", + "images": [] + }, + "gongwen": { + "icon": "", + "images": [] + }, + "goodbyedpi": { + "icon": "https://community.chocolatey.org/content/packageimages/goodbyedpi.0.2.2.png", + "images": [] + }, + "goodjobb": { + "icon": "", + "images": [] + }, + "goodsync": { + "icon": "https://i.postimg.cc/mDJwHMts/Good-Sync-256-256.png", + "images": [ + "https://www.goodsync.com/images/logos/GoodSync-sync-progress.png", + "https://www.goodsync.com/images/logos/GoodSync-sync-completed.png", + "https://www.goodsync.com/images/logos/GoodSync-sync-analysis.png" + ] + }, + "google-api-core": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/c/c1/Google_%22G%22_logo.svg/1200px-Google_%22G%22_logo.svg.png", + "images": [] + }, + "google-api-python-client": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/c/c1/Google_%22G%22_logo.svg/1200px-Google_%22G%22_logo.svg.png", + "images": [] + }, + "google-assistant": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/c/cb/Google_Assistant_logo.svg/768px-Google_Assistant_logo.svg.png", + "images": [] + }, + "google-auth": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/c/c1/Google_%22G%22_logo.svg/1200px-Google_%22G%22_logo.svg.png", + "images": [] + }, + "google-auth-httplib2": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/c/c1/Google_%22G%22_logo.svg/1200px-Google_%22G%22_logo.svg.png", + "images": [] + }, + "google-auth-oauthlib": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/c/c1/Google_%22G%22_logo.svg/1200px-Google_%22G%22_logo.svg.png", + "images": [] + }, + "google-books-downloader": { + "icon": "https://community.chocolatey.org/content/packageimages/google-books-downloader.2.7.png", + "images": [] + }, + "google-calendar-chrome": { + "icon": "https://community.chocolatey.org/content/packageimages/google-calendar-chrome.2.8.png", + "images": [] + }, + "google-calendar-desktop": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/a/a5/Google_Calendar_icon_%282020%29.svg/2048px-Google_Calendar_icon_%282020%29.svg.png", + "images": [] + }, + "google-cast-chrome": { + "icon": "", + "images": [] + }, + "google-chat-linux": { + "icon": "https://dashboard.snapcraft.io/site_media/appmedia/2021/01/scalable.svg.png", + "images": [] + }, + "google-chrome-for-enterprise": { + "icon": "", + "images": [] + }, + "google-chrome-x64": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/e/e1/Google_Chrome_icon_%28February_2022%29.svg/32px-Google_Chrome_icon_%28February_2022%29.svg.png", + "images": [] + }, + "google-dictionary-chrome": { + "icon": "https://community.chocolatey.org/content/packageimages/google-dictionary-chrome.4.0.8.png", + "images": [] + }, + "google-drive-add-to-explorer": { + "icon": "", + "images": [] + }, + "google-drive-file-stream": { + "icon": "https://community.chocolatey.org/content/packageimages/google-drive-file-stream.56.0.11.2022.png", + "images": [] + }, + "google-earth-pro": { + "icon": "https://images.icon-icons.com/188/PNG/256/Google_Earth_22883.png", + "images": [] + }, + "google-hangouts-chrome": { + "icon": "", + "images": [] + }, + "google-java-format": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/c/c1/Google_%22G%22_logo.svg/1200px-Google_%22G%22_logo.svg.png", + "images": [] + }, + "google-meet-desktop": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/9/9b/Google_Meet_icon_%282020%29.svg/512px-Google_Meet_icon_%282020%29.svg.png", + "images": [] + }, + "google-pinyin": { + "icon": "", + "images": [] + }, + "google-play-games-beta": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/5/59/Google_Play_Games.png", + "images": [ + "https://www.gstatic.com/play/games/pc/googleplaygames-beta-opengraph-7ab5c9b4.png" + ] + }, + "google-quickshare": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/d/dc/Quickshare.svg/1200px-Quickshare.svg.png", + "images": [ + "https://i.postimg.cc/KYG1sNtZ/zen-ra5ql49-DU7.png" + ] + }, + "google-translate-chrome": { + "icon": "https://community.chocolatey.org/content/packageimages/google-translate-chrome.2.0.7.png", + "images": [] + }, + "google-voice-chrome": { + "icon": "", + "images": [] + }, + "google-voice-desktop": { + "icon": "https://community.chocolatey.org/content/packageimages/google-voice-desktop.1.2.8.png", + "images": [] + }, + "google-web-designer": { + "icon": "", + "images": [] + }, + "google-workspace-sync": { + "icon": "https://community.chocolatey.org/content/packageimages/google-workspace-sync.4.3.53.0.png", + "images": [] + }, + "google2srt": { + "icon": "https://community.chocolatey.org/content/packageimages/google2srt.install.0.7.10.png", + "images": [] + }, + "googleapis-common-protos": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/c/c1/Google_%22G%22_logo.svg/1200px-Google_%22G%22_logo.svg.png", + "images": [] + }, + "googlechatelectron": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/d/de/Google_Chat_icon_%282020%29.svg/1200px-Google_Chat_icon_%282020%29.svg.png", + "images": [] + }, + "googlechrome": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/e/e1/Google_Chrome_icon_%28February_2022%29.svg/32px-Google_Chrome_icon_%28February_2022%29.svg.png", + "images": [] + }, + "googlechrome-allusers": { + "icon": "https://community.chocolatey.org/content/packageimages/GoogleChrome-AllUsers.26.0.1410.64.png", + "images": [] + }, + "googlechrome-authy": { + "icon": "https://community.chocolatey.org/content/packageimages/googlechrome-authy.2.3.0.png", + "images": [] + }, + "googlechrome-dev": { + "icon": "https://community.chocolatey.org/content/packageimages/GoogleChrome.Dev.27.0.1453.12.png", + "images": [] + }, + "googlechrome-github-expandinizr": { + "icon": "", + "images": [] + }, + "googledocs": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/6/66/Google_Docs_2020_Logo.svg/1489px-Google_Docs_2020_Logo.svg.png", + "images": [ + "https://cdn.ablebits.com/-img22lp-google-docs/styles/add-new-element.png" + ] + }, + "googledrive": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/1/12/Google_Drive_icon_%282020%29.svg/1200px-Google_Drive_icon_%282020%29.svg.png", + "images": [ + "https://lh3.googleusercontent.com/0-LdzZVF15tdJN0nBgDsQ8XmvRbx7p-qvKpA8qNhhjcNI1vFDPJOwqFq_zJFACDoV0qXUta1zCnNb9PSlKiJ627-gdtCm66-PcV-yBv6po1ozXvcLtls=s0", + "https://i.postimg.cc/Kvy003sY/Rs5-Sqif-Imgur.png", + "https://i.postimg.cc/4NZ16km7/image.png" + ] + }, + "googleearth": { + "icon": "https://community.chocolatey.org/content/packageimages/googleearth.7.1.8.30360001.png", + "images": [] + }, + "googleearthpro": { + "icon": "https://community.chocolatey.org/content/packageimages/googleearthpro.7.3.6.20230128.png", + "images": [] + }, + "googlejapaneseinput": { + "icon": "", + "images": [] + }, + "googlephotos": { + "icon": "", + "images": [] + }, + "gopass": { + "icon": "", + "images": [] + }, + "gopass-jsonapi": { + "icon": "", + "images": [] + }, + "gopeed": { + "icon": "", + "images": [] + }, + "gopher360": { + "icon": "", + "images": [] + }, + "gopro-quik": { + "icon": "https://community.chocolatey.org/content/packageimages/gopro-quik.2.7.0.94501.png", + "images": [] + }, + "goreleaser": { + "icon": "", + "images": [] + }, + "goreman": { + "icon": "", + "images": [] + }, + "gosec": { + "icon": "", + "images": [] + }, + "gossamer3": { + "icon": "", + "images": [] + }, + "gossm": { + "icon": "", + "images": [] + }, + "gosuslugi-plugin": { + "icon": "https://community.chocolatey.org/content/packageimages/gosuslugi-plugin.3.1.1.0.png", + "images": [] + }, + "gotify-cli": { + "icon": "", + "images": [] + }, + "gotify-server": { + "icon": "", + "images": [] + }, + "gotiny": { + "icon": "", + "images": [] + }, + "gotomeeting": { + "icon": "https://i.postimg.cc/zXwPYfcy/gotomeeting.png", + "images": [] + }, + "gotoopener": { + "icon": "https://community.chocolatey.org/content/packageimages/gotoopener.1.0.564.png", + "images": [] + }, + "gotop": { + "icon": "https://dashboard.snapcraft.io/site_media/appmedia/2019/03/icon.png", + "images": [] + }, + "gotowindow": { + "icon": "", + "images": [] + }, + "gource": { + "icon": "", + "images": [] + }, + "govc": { + "icon": "", + "images": [] + }, + "gow": { + "icon": "", + "images": [] + }, + "goxlr": { + "icon": "", + "images": [] + }, + "goxlr-driver": { + "icon": "", + "images": [] + }, + "gpac": { + "icon": "https://community.chocolatey.org/content/packageimages/gpac.2.2.0.png", + "images": [] + }, + "gperf": { + "icon": "", + "images": [] + }, + "gpg": { + "icon": "", + "images": [] + }, + "gpg4win": { + "icon": "https://www.gpg4win.org/img/logo_gpg4win_for_microblogs.png", + "images": [ + "https://www.gpg4win.org/img/screenshots/sc-inst-welcome_en.png", + "https://www.gpg4win.org/img/screenshots/h250.sc-inst-welcome_en.png", + "https://www.gpg4win.org/img/screenshots/h250.sc-kleopatra-configureCertificateserver_en.png" + ] + }, + "gpg4win-light": { + "icon": "https://community.chocolatey.org/content/packageimages/gpg4win-light.2.3.4.20191021.png", + "images": [] + }, + "gpg4win-vanilla": { + "icon": "https://community.chocolatey.org/content/packageimages/gpg4win-vanilla.2.3.4.20191021.png", + "images": [] + }, + "gpgfrontend": { + "icon": "", + "images": [] + }, + "gping": { + "icon": "", + "images": [] + }, + "gpodder": { + "icon": "", + "images": [] + }, + "gpower": { + "icon": "https://community.chocolatey.org/content/packageimages/gpower.3.1.9.7.png", + "images": [] + }, + "gprolog-mingw": { + "icon": "https://community.chocolatey.org/content/packageimages/gprolog-mingw.1.5.0.png", + "images": [] + }, + "gprolog-msvc": { + "icon": "https://community.chocolatey.org/content/packageimages/gprolog-msvc.1.5.0.png", + "images": [] + }, + "gps-sdr-sim": { + "icon": "https://community.chocolatey.org/content/packageimages/gps-sdr-sim.1.0.png", + "images": [] + }, + "gpt4all": { + "icon": "https://gpt4all.io/gpt4all-128.png", + "images": [ + "https://gpt4all.io/robot_poem_gpt4all_still.png", + "https://gpt4all.io/baroque_gpt4all_still.png", + "https://gpt4all.io/web_request_gpt4all_still.png" + ] + }, + "gptgen": { + "icon": "", + "images": [] + }, + "gpu-z": { + "icon": "https://tpucdn.com/images/news/tpu-v1669381101081.png", + "images": [ + "https://i.postimg.cc/SRLwChQJ/image.png", + "https://i.postimg.cc/ZRv9Tfbf/image.png", + "https://i.postimg.cc/SRw3BxZT/image.png", + "https://i.postimg.cc/RFmDQYW8/image.png" + ] + }, + "gpxeditor": { + "icon": "https://community.chocolatey.org/content/packageimages/gpxeditor.1.7.12.1731.png", + "images": [] + }, + "gpxsee": { + "icon": "https://i.postimg.cc/FKsmkfLh/image.png", + "images": [ + "https://i.postimg.cc/brbjfkK9/image.png" + ] + }, + "graalvm": { + "icon": "", + "images": [] + }, + "graalvm-java11": { + "icon": "", + "images": [] + }, + "graalvm-java17": { + "icon": "", + "images": [] + }, + "graalvm-java8": { + "icon": "", + "images": [] + }, + "gradle": { + "icon": "", + "images": [] + }, + "gradle-bin": { + "icon": "", + "images": [] + }, + "grafana": { + "icon": "https://i.postimg.cc/HLcqgzgz/grafana-icon.png", + "images": [ + "https://i.postimg.cc/65BxvCr6/Grafana-Dashboard.png" + ] + }, + "grafana-agent": { + "icon": "https://i.postimg.cc/nzn6NDHc/grafana-agent.png", + "images": [] + }, + "grafana-enterprise": { + "icon": "", + "images": [] + }, + "grafana-oss": { + "icon": "", + "images": [] + }, + "grails": { + "icon": "https://community.chocolatey.org/content/packageimages/Grails.5.2.4.png", + "images": [] + }, + "gramblr": { + "icon": "https://community.chocolatey.org/content/packageimages/gramblr.2.8.1.png", + "images": [] + }, + "grammarly": { + "icon": "https://i.postimg.cc/dtrmQxRt/grammarly-for-windows-1-2-122-1565.png", + "images": [] + }, + "grammarly-chrome": { + "icon": "", + "images": [] + }, + "grammarly-edge": { + "icon": "", + "images": [] + }, + "grammarly-office": { + "icon": "", + "images": [] + }, + "gramps": { + "icon": "", + "images": [] + }, + "grand": { + "icon": "https://community.chocolatey.org/content/packageimages/grand.portable.1.07.png", + "images": [] + }, + "granit": { + "icon": "", + "images": [] + }, + "grap": { + "icon": "", + "images": [] + }, + "graph": { + "icon": "https://community.chocolatey.org/content/packageimages/graph.4.4.2.20170413.png", + "images": [] + }, + "graphdigitizer": { + "icon": "", + "images": [] + }, + "graphicsdriver": { + "icon": "", + "images": [] + }, + "graphicsgale": { + "icon": "", + "images": [] + }, + "graphicsmagick": { + "icon": "https://community.chocolatey.org/content/packageimages/graphicsmagick.1.3.36.png", + "images": [] + }, + "graphicsmagick-q16": { + "icon": "https://community.chocolatey.org/content/packageimages/graphicsmagick-q16.1.3.35.png", + "images": [] + }, + "graphingcalculator": { + "icon": "https://community.chocolatey.org/content/packageimages/graphingcalculator.6.0.535.001.png", + "images": [] + }, + "graphiql": { + "icon": "", + "images": [] + }, + "graphite-powershell": { + "icon": "", + "images": [] + }, + "graphql-playground": { + "icon": "", + "images": [] + }, + "graphqlplayground": { + "icon": "", + "images": [] + }, + "graphviz": { + "icon": "https://upload.wikimedia.org/wikipedia/en/4/48/GraphvizLogo.png", + "images": [] + }, + "grasshopper": { + "icon": "", + "images": [] + }, + "grate": { + "icon": "", + "images": [] + }, + "gravitdesigner": { + "icon": "https://community.chocolatey.org/content/packageimages/gravitdesigner.portable.2019.2.png", + "images": [] + }, + "gravitoneditor": { + "icon": "", + "images": [] + }, + "grayboxsimulator": { + "icon": "", + "images": [] + }, + "graylog-sidecar": { + "icon": "", + "images": [] + }, + "green-tunnel": { + "icon": "", + "images": [] + }, + "greenfoot": { + "icon": "", + "images": [] + }, + "greenshot": { + "icon": "https://secure.gravatar.com/avatar/a39fbcebe12b5f384ec729e86139ec39.png", + "images": [] + }, + "grep": { + "icon": "", + "images": [] + }, + "grepwin": { + "icon": "https://raw.githubusercontent.com/stefankueng/grepWin/main/src/Resources/grepwin_256.png", + "images": [ + "https://i.postimg.cc/BnWJLR2M/image.png", + "https://i.postimg.cc/ht9c9Mrg/image.png", + "https://i.postimg.cc/q740QnbK/image.png" + ] + }, + "gretl": { + "icon": "https://community.chocolatey.org/content/packageimages/gretl.2022.221101.png", + "images": [] + }, + "grex": { + "icon": "", + "images": [] + }, + "greyhound-crm": { + "icon": "", + "images": [] + }, + "grib-tools": { + "icon": "https://community.chocolatey.org/content/packageimages/grib-tools.1.14.5.1.png", + "images": [] + }, + "grid": { + "icon": "", + "images": [] + }, + "gridcoinwallet": { + "icon": "https://community.chocolatey.org/content/packageimages/gridcoinwallet.5.4.1.0.png", + "images": [] + }, + "gridea": { + "icon": "", + "images": [] + }, + "gridtracker": { + "icon": "https://community.chocolatey.org/content/packageimages/gridtracker.1.23.0206.png", + "images": [] + }, + "grisbi": { + "icon": "https://community.chocolatey.org/content/packageimages/grisbi.2.0.5.png", + "images": [] + }, + "grit7z": { + "icon": "", + "images": [] + }, + "grocery-checklist-shell": { + "icon": "", + "images": [] + }, + "groff": { + "icon": "https://community.chocolatey.org/content/packageimages/groff.1.22.4.png", + "images": [] + }, + "gron": { + "icon": "", + "images": [] + }, + "groovy": { + "icon": "https://community.chocolatey.org/content/packageimages/groovy.3.0.14.png", + "images": [] + }, + "groovy-2-5": { + "icon": "", + "images": [] + }, + "groovy-3": { + "icon": "", + "images": [] + }, + "groovy-4": { + "icon": "", + "images": [] + }, + "groovyserv": { + "icon": "", + "images": [] + }, + "growl": { + "icon": "https://community.chocolatey.org/content/packageimages/Growl.2.0.9.20191130.png", + "images": [] + }, + "grpc-tools": { + "icon": "", + "images": [] + }, + "grpcurl": { + "icon": "", + "images": [] + }, + "grub2win": { + "icon": "https://community.chocolatey.org/content/packageimages/grub2win.1.0.5.8.png", + "images": [] + }, + "grubinst": { + "icon": "", + "images": [] + }, + "gruntsnippetpack": { + "icon": "", + "images": [] + }, + "grype": { + "icon": "", + "images": [] + }, + "gsak": { + "icon": "", + "images": [] + }, + "gsl-shell": { + "icon": "", + "images": [] + }, + "gsmartcontrol": { + "icon": "https://community.chocolatey.org/content/packageimages/gsmartcontrol.1.1.4.png", + "images": [] + }, + "gstreamer": { + "icon": "https://community.chocolatey.org/content/packageimages/gstreamer.1.20.4.png", + "images": [] + }, + "gstreamer-devel": { + "icon": "https://community.chocolatey.org/content/packageimages/gstreamer-devel.1.20.4.png", + "images": [] + }, + "gstreamer-mingw": { + "icon": "https://community.chocolatey.org/content/packageimages/gstreamer-mingw.1.20.4.png", + "images": [] + }, + "gstreamer-mingw-devel": { + "icon": "https://community.chocolatey.org/content/packageimages/gstreamer-mingw-devel.1.20.4.png", + "images": [] + }, + "gsubs": { + "icon": "https://community.chocolatey.org/content/packageimages/gsubs.1.0.3.png", + "images": [] + }, + "gsudo": { + "icon": "", + "images": [] + }, + "gsuite-migration-exchange": { + "icon": "https://community.chocolatey.org/content/packageimages/gsuite-migration-exchange.5.1.20.0.png", + "images": [] + }, + "gsuite-migration-outlook": { + "icon": "https://community.chocolatey.org/content/packageimages/gsuite-migration-outlook.4.0.117.10.png", + "images": [] + }, + "gsuite-sync-outlook": { + "icon": "https://community.chocolatey.org/content/packageimages/gsuite-sync-outlook.4.1.25.0.png", + "images": [] + }, + "gsutil": { + "icon": "", + "images": [] + }, + "gsview": { + "icon": "", + "images": [] + }, + "gt4t": { + "icon": "", + "images": [] + }, + "gtk-runtime": { + "icon": "https://community.chocolatey.org/content/packageimages/gtk-runtime.2.24.10.20121010.png", + "images": [] + }, + "gtk-sharp": { + "icon": "", + "images": [] + }, + "gtksharp": { + "icon": "https://community.chocolatey.org/content/packageimages/gtksharp.2.12.45.png", + "images": [] + }, + "gtkwave": { + "icon": "https://community.chocolatey.org/content/packageimages/gtkwave.3.3.100.png", + "images": [] + }, + "gtmhub-codegen": { + "icon": "", + "images": [] + }, + "gtools": { + "icon": "", + "images": [] + }, + "gtypist": { + "icon": "", + "images": [] + }, + "guetzli": { + "icon": "", + "images": [] + }, + "guidgen-console": { + "icon": "https://community.chocolatey.org/content/packageimages/guidgen-console.2.0.0.8.png", + "images": [] + }, + "guiforchiablockchain": { + "icon": "", + "images": [] + }, + "guiformat": { + "icon": "", + "images": [] + }, + "guild-wars": { + "icon": "", + "images": [] + }, + "guilded": { + "icon": "", + "images": [] + }, + "guinget": { + "icon": "", + "images": [] + }, + "guiscrcpy": { + "icon": "", + "images": [] + }, + "guitar-pro": { + "icon": "https://community.chocolatey.org/content/packageimages/guitar-pro.7.6.0.2089.png", + "images": [] + }, + "guitarhub": { + "icon": "https://community.chocolatey.org/content/packageimages/guitarhub.1.1.15.png", + "images": [] + }, + "guitarpro-7": { + "icon": "https://i.imgur.com/ntePXqZ.png", + "images": [ + "https://www.guitar-pro.com/themes/gp_child_classic/assets/img/guitar-pro-7-features/guitar-pro-7-feature-screen-notation-en.jpg", + "https://www.guitar-pro.com/themes/gp_child_classic/assets/img/guitar-pro-7-features/guitar-pro-7-sheet-music-setup.jpg", + "https://www.guitar-pro.com/themes/gp_child_classic/assets/img/guitar-pro-7-features/guitar-pro-7-chords.jpg", + "https://www.guitar-pro.com/themes/gp_child_classic/assets/img/guitar-pro-7-features/guitar-pro-7-scales.jpg", + "https://www.guitar-pro.com/themes/gp_child_classic/assets/img/guitar-pro-7-features/guitar-pro-7-lyrics.jpg", + "https://www.guitar-pro.com/themes/gp_child_classic/assets/img/guitar-pro-7-features/guitar-pro-7-tuner.jpg" + ] + }, + "gulp-cli": { + "icon": "https://community.chocolatey.org/content/packageimages/gulp-cli.2.3.0.20201126.png", + "images": [] + }, + "gulpsnippetpack": { + "icon": "", + "images": [] + }, + "gum": { + "icon": "", + "images": [] + }, + "gump": { + "icon": "", + "images": [] + }, + "gunk": { + "icon": "", + "images": [] + }, + "gurtle": { + "icon": "https://community.chocolatey.org/content/packageimages/gurtle.0.6.0.236.png", + "images": [] + }, + "gyazo": { + "icon": "", + "images": [] + }, + "gyroflow": { + "icon": "", + "images": [] + }, + "gzdoom": { + "icon": "https://community.chocolatey.org/content/packageimages/gzdoom.4.8.2.png", + "images": [] + }, + "gzip": { + "icon": "", + "images": [] + }, + "h-opc-cli": { + "icon": "https://community.chocolatey.org/content/packageimages/h-opc-cli.0.9.0.png", + "images": [] + }, + "h264tscutter": { + "icon": "", + "images": [] + }, + "h2testw": { + "icon": "https://community.chocolatey.org/content/packageimages/h2testw.1.4.20180717.png", + "images": [] + }, + "haali-media-splitter": { + "icon": "", + "images": [] + }, + "hack-font": { + "icon": "", + "images": [] + }, + "hackaru": { + "icon": "", + "images": [] + }, + "hacker-scoper": { + "icon": "", + "images": [] + }, + "hackfont-windows": { + "icon": "https://community.chocolatey.org/content/packageimages/hackfont-windows.1.6.0.png", + "images": [] + }, + "hackfonts": { + "icon": "", + "images": [] + }, + "hadolint": { + "icon": "", + "images": [] + }, + "hadoop": { + "icon": "https://community.chocolatey.org/content/packageimages/hadoop.3.3.4.png", + "images": [] + }, + "hadoop-winutils": { + "icon": "", + "images": [] + }, + "hadouken": { + "icon": "", + "images": [] + }, + "hain": { + "icon": "https://community.chocolatey.org/content/packageimages/Hain.0.6.6.png", + "images": [] + }, + "hakchi2": { + "icon": "", + "images": [] + }, + "hakchi2-ce": { + "icon": "https://community.chocolatey.org/content/packageimages/hakchi2-ce.3.9.3.png", + "images": [] + }, + "haku-neko": { + "icon": "https://community.chocolatey.org/content/packageimages/haku-neko.6.1.7.png", + "images": [] + }, + "hakuneko": { + "icon": "", + "images": [] + }, + "hakuneko-nightly": { + "icon": "", + "images": [] + }, + "hakunekonightly": { + "icon": "https://community.chocolatey.org/content/packageimages/hakunekonightly.8.3.4.png", + "images": [] + }, + "halestudio": { + "icon": "", + "images": [] + }, + "halite": { + "icon": "https://community.chocolatey.org/content/packageimages/Halite.0.4.0.4.png", + "images": [] + }, + "halo": { + "icon": "", + "images": [] + }, + "hamachi": { + "icon": "https://community.chocolatey.org/content/packageimages/hamachi.2.3.0.78.png", + "images": [] + }, + "hamic": { + "icon": "", + "images": [] + }, + "hammerpdf": { + "icon": "", + "images": [] + }, + "hammultiplayer": { + "icon": "", + "images": [] + }, + "hamsket": { + "icon": "", + "images": [] + }, + "hamsterbase": { + "icon": "", + "images": [] + }, + "handbrake": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/d/d9/HandBrake_Icon.png", + "images": [ + "https://handbrake.fr/img/slides/slide1_win.jpg", + "https://handbrake.fr/img/slides/slide2_win.jpg", + "https://handbrake.fr/img/slides/slide3_win.jpg" + ] + }, + "handbrake-cli": { + "icon": "https://community.chocolatey.org/content/packageimages/handbrake-cli.1.6.1.png", + "images": [] + }, + "handle": { + "icon": "", + "images": [] + }, + "handscream": { + "icon": "", + "images": [] + }, + "handyimagemapper": { + "icon": "https://community.chocolatey.org/content/packageimages/handyimagemapper.2.0.0.0.png", + "images": [] + }, + "handywinget-gui": { + "icon": "", + "images": [] + }, + "hardcopy": { + "icon": "", + "images": [] + }, + "harddriveindicator": { + "icon": "https://community.chocolatey.org/content/packageimages/harddriveindicator.1.3.0.0.png", + "images": [] + }, + "hardentools": { + "icon": "https://community.chocolatey.org/content/packageimages/hardentools.2.4.png", + "images": [] + }, + "hardware-identify": { + "icon": "", + "images": [] + }, + "hardwipe": { + "icon": "", + "images": [] + }, + "harfbuzz": { + "icon": "", + "images": [] + }, + "harmonoid": { + "icon": "https://avatars.githubusercontent.com/u/75374037?s=200&v=4", + "images": [ + "https://i.postimg.cc/QNTdQNjK/harmonoidscreenshot.png" + ] + }, + "harmony": { + "icon": "", + "images": [] + }, + "haroopad": { + "icon": "", + "images": [] + }, + "hash-r": { + "icon": "", + "images": [] + }, + "hashcat": { + "icon": "", + "images": [] + }, + "hashcheck": { + "icon": "https://community.chocolatey.org/content/packageimages/hashcheck.2.5.0.png", + "images": [] + }, + "hashcheckshellextension": { + "icon": "", + "images": [] + }, + "hashdeep": { + "icon": "", + "images": [] + }, + "hasher": { + "icon": "", + "images": [] + }, + "hasher-erz": { + "icon": "", + "images": [] + }, + "hashhash": { + "icon": "", + "images": [] + }, + "hashicorp-sentinel": { + "icon": "https://community.chocolatey.org/content/packageimages/hashicorp-sentinel.0.20.0.png", + "images": [] + }, + "hashlink": { + "icon": "", + "images": [] + }, + "hashmyfiles": { + "icon": "https://community.chocolatey.org/content/packageimages/hashmyfiles.2.43.png", + "images": [ + "https://i.postimg.cc/kMxgyG0B/image.png", + "https://i.postimg.cc/WbTbYjVm/image.png" + ] + }, + "hashtab": { + "icon": "https://community.chocolatey.org/content/packageimages/hashtab.6.0.0.3402.png", + "images": [] + }, + "hashtools": { + "icon": "https://community.chocolatey.org/content/packageimages/hashtools.4.6.png", + "images": [ + "https://i.postimg.cc/sxdWVkMm/image.png" + ] + }, + "haskell": { + "icon": "", + "images": [] + }, + "haskell-cabal": { + "icon": "", + "images": [] + }, + "haskell-dev": { + "icon": "https://community.chocolatey.org/content/packageimages/haskell-dev.0.0.1.png", + "images": [] + }, + "haskell-language-server": { + "icon": "https://community.chocolatey.org/content/packageimages/haskell-language-server.1.5.1.png", + "images": [] + }, + "haskell-stack": { + "icon": "https://community.chocolatey.org/content/packageimages/haskell-stack.2.9.3.png", + "images": [] + }, + "hasklig": { + "icon": "", + "images": [] + }, + "hasleobackupsuite": { + "icon": "https://community.chocolatey.org/content/packageimages/hasleobackupsuite.3.4.0.png", + "images": [] + }, + "hasura-cli": { + "icon": "", + "images": [] + }, + "havdetectiontool": { + "icon": "https://community.chocolatey.org/content/packageimages/havdetectiontool.1.0.png", + "images": [] + }, + "haveibeenpwned": { + "icon": "", + "images": [] + }, + "haxe": { + "icon": "", + "images": [] + }, + "haxm": { + "icon": "https://community.chocolatey.org/content/packageimages/haxm.7.7.0.png", + "images": [] + }, + "hazelcast": { + "icon": "", + "images": [] + }, + "hbbatchbeast": { + "icon": "", + "images": [] + }, + "hcloud": { + "icon": "https://community.chocolatey.org/content/packageimages/hcloud.portable.1.31.1.png", + "images": [] + }, + "hdcleaner": { + "icon": "https://i.postimg.cc/T2FY9Szj/HDCleaner.png", + "images": [] + }, + "hddexpert": { + "icon": "", + "images": [] + }, + "hddguardian": { + "icon": "https://community.chocolatey.org/content/packageimages/hddguardian.0.7.1.png", + "images": [] + }, + "hddllftool": { + "icon": "", + "images": [] + }, + "hddrawcopytool": { + "icon": "", + "images": [] + }, + "hdgrandslam-plex": { + "icon": "", + "images": [] + }, + "hdguard": { + "icon": "https://community.chocolatey.org/content/packageimages/hdguard.10.0.0.4.png", + "images": [] + }, + "hdhomerun": { + "icon": "", + "images": [] + }, + "hdhomerun-view": { + "icon": "https://community.chocolatey.org/content/packageimages/hdhomerun-view.2022.03.03.png", + "images": [] + }, + "hdhomeruntech": { + "icon": "", + "images": [] + }, + "hdhomerunviewer-plex": { + "icon": "", + "images": [] + }, + "hdoslauncher": { + "icon": "", + "images": [] + }, + "hdparm": { + "icon": "https://community.chocolatey.org/content/packageimages/hdparm.6.9.2.png", + "images": [] + }, + "hdrmerge": { + "icon": "https://community.chocolatey.org/content/packageimages/hdrmerge.0.5.0.png", + "images": [] + }, + "hdsentinel": { + "icon": "https://community.chocolatey.org/content/packageimages/hdsentinel.5.70.png", + "images": [] + }, + "hdtune": { + "icon": "https://community.chocolatey.org/content/packageimages/hdtune.2.55.0.1.png", + "images": [] + }, + "hdtunepro": { + "icon": "", + "images": [] + }, + "he3": { + "icon": "", + "images": [] + }, + "headlamp": { + "icon": "https://community.chocolatey.org/content/packageimages/headlamp.0.15.0.png", + "images": [] + }, + "heads-tails": { + "icon": "", + "images": [] + }, + "headset": { + "icon": "https://community.chocolatey.org/content/packageimages/headset.4.2.1.png", + "images": [] + }, + "headsetcontrol-gui": { + "icon": "https://raw.githubusercontent.com/LeoKlaus/HeadsetControl-GUI/main/src/Resources/icons/light/png/headphones.png", + "images": [] + }, + "heapmemview": { + "icon": "https://community.chocolatey.org/content/packageimages/heapmemview.1.05.png", + "images": [] + }, + "heartbeat-oss": { + "icon": "https://community.chocolatey.org/content/packageimages/heartbeat-oss.8.4.1.png", + "images": [] + }, + "hearthstone-deck-tracker-arena-helper": { + "icon": "", + "images": [] + }, + "hearthstonedecktracker": { + "icon": "https://hsdecktracker.net/static/images/logo.png", + "images": [] + }, + "heaven-benchmark": { + "icon": "https://community.chocolatey.org/content/packageimages/heaven-benchmark.4.0.0.20200922.png", + "images": [] + }, + "heavenbenchmark": { + "icon": "https://i.postimg.cc/sx9rvdBX/heaven.png", + "images": [ + "https://i.postimg.cc/pL1t9BdD/image.png", + "https://i.postimg.cc/8CJsscTz/image.png", + "https://i.postimg.cc/XJPZQ5xF/image.png", + "https://i.postimg.cc/wBvL29HC/image.png", + "https://i.postimg.cc/jSq7qRWD/image.png" + ] + }, + "heavyload": { + "icon": "https://i.postimg.cc/BvmgB7wr/Heavy-Load.png", + "images": [ + "https://i.postimg.cc/7h2nDHY4/image.png", + "https://i.postimg.cc/7PFN92mZ/image.png", + "https://i.postimg.cc/9FyYnQnt/image.png", + "https://i.postimg.cc/RZ9L5zrr/image.png" + ] + }, + "hec-efm": { + "icon": "", + "images": [] + }, + "hec-fda": { + "icon": "", + "images": [] + }, + "hec-hms": { + "icon": "", + "images": [] + }, + "hec-ras": { + "icon": "", + "images": [] + }, + "hec-rpt": { + "icon": "", + "images": [] + }, + "hec-ssp": { + "icon": "", + "images": [] + }, + "hedgewars": { + "icon": "https://community.chocolatey.org/content/packageimages/hedgewars.1.0.0.png", + "images": [] + }, + "heidisql": { + "icon": "https://community.chocolatey.org/content/packageimages/HeidiSQL.12.3.0.6589.png", + "images": [] + }, + "heimdall": { + "icon": "https://community.chocolatey.org/content/packageimages/heimdall.1.4.2.png", + "images": [] + }, + "heiziflashtools": { + "icon": "", + "images": [] + }, + "hekasoft-backup-restore": { + "icon": "", + "images": [] + }, + "helio-workstation": { + "icon": "https://community.chocolatey.org/content/packageimages/helio-workstation.install.3.10.png", + "images": [] + }, + "helioslauncher": { + "icon": "", + "images": [] + }, + "helioworkstation": { + "icon": "", + "images": [] + }, + "helium": { + "icon": "https://raw.githubusercontent.com/imputnet/helium/main/resources/branding/app_icon/raw.png", + "images": [ + "https://i.ibb.co/whfhQY9H/lead.png", + "https://i.ibb.co/SX023htv/split-view.png", + "https://i.ibb.co/849XG3C3/bangs.png" + ] + }, + "helium-pre": { + "icon": "https://raw.githubusercontent.com/imputnet/helium/main/resources/branding/app_icon/raw.png", + "images": [ + "https://i.ibb.co/whfhQY9H/lead.png", + "https://i.ibb.co/SX023htv/split-view.png", + "https://i.ibb.co/849XG3C3/bangs.png" + ] + }, + "helix": { + "icon": "", + "images": [] + }, + "helix-alm-client": { + "icon": "https://community.chocolatey.org/content/packageimages/helix-alm-client.2022.3.0.20230115.png", + "images": [] + }, + "hellofont": { + "icon": "", + "images": [] + }, + "hellominecraftlauncher": { + "icon": "", + "images": [] + }, + "helm": { + "icon": "", + "images": [] + }, + "helm-chart-releaser": { + "icon": "", + "images": [] + }, + "helm-chart-testing": { + "icon": "", + "images": [] + }, + "helm-docs": { + "icon": "", + "images": [] + }, + "helmfile": { + "icon": "", + "images": [] + }, + "help-workshop": { + "icon": "https://community.chocolatey.org/content/packageimages/help-workshop.4.0.3.200.png", + "images": [] + }, + "helpndoc": { + "icon": "", + "images": [] + }, + "hercules": { + "icon": "https://community.chocolatey.org/content/packageimages/Hercules.3.2.8.3.png", + "images": [] + }, + "heroesofnewerth": { + "icon": "https://community.chocolatey.org/content/packageimages/heroesofnewerth.3.5.8.png", + "images": [] + }, + "heroku-cli": { + "icon": "https://community.chocolatey.org/content/packageimages/heroku-cli.7.53.0.20220328.png", + "images": [] + }, + "heroku-toolbelt": { + "icon": "", + "images": [] + }, + "herokucli": { + "icon": "", + "images": [] + }, + "hex-editor-neo": { + "icon": "", + "images": [] + }, + "hex2dec": { + "icon": "", + "images": [] + }, + "hexamail-pop3-downloader": { + "icon": "", + "images": [] + }, + "hexchat": { + "icon": "", + "images": [] + }, + "hexed": { + "icon": "", + "images": [] + }, + "hexo-blog-client": { + "icon": "", + "images": [] + }, + "hexo-client": { + "icon": "", + "images": [] + }, + "hexoclient": { + "icon": "", + "images": [] + }, + "hexter-octopus": { + "icon": "", + "images": [] + }, + "hexter-teamcity": { + "icon": "", + "images": [] + }, + "hexter-webserver": { + "icon": "", + "images": [] + }, + "hexyl": { + "icon": "", + "images": [] + }, + "heyboxaccelerator": { + "icon": "", + "images": [] + }, + "heyboxwow": { + "icon": "", + "images": [] + }, + "hfs": { + "icon": "https://community.chocolatey.org/content/packageimages/hfs.2.3.12.png", + "images": [] + }, + "hfs+": { + "icon": "", + "images": [] + }, + "hfsexplorer": { + "icon": "", + "images": [] + }, + "hhkbcng": { + "icon": "", + "images": [] + }, + "hibit-startup-manager": { + "icon": "https://www.hibitsoft.ir/images/Startup-Manager-icon.png", + "images": [] + }, + "hibit-system-information": { + "icon": "https://www.hibitsoft.ir/images/System-Information-icon.png", + "images": [] + }, + "hibit-uninstaller": { + "icon": "https://www.hibitsoft.ir/images/Uninstaller-icon.png", + "images": [ + "https://i.postimg.cc/dVc81hWz/Screenshot-1.png", + "https://i.postimg.cc/zGwTRq63/Screenshot-2.png", + "https://i.postimg.cc/ZqV3VVTS/Screenshot-3.png", + "https://i.postimg.cc/0Q4SqjMX/Screenshot-4.png", + "https://i.postimg.cc/rp8x1v2j/Screenshot-5.png", + "https://i.postimg.cc/xC8m7MCb/Screenshot-6.png" + ] + }, + "hibituninstaller": { + "icon": "https://www.hibitsoft.ir/images/Uninstaller-icon.png", + "images": [ + "https://i.postimg.cc/dVc81hWz/Screenshot-1.png", + "https://i.postimg.cc/zGwTRq63/Screenshot-2.png", + "https://i.postimg.cc/ZqV3VVTS/Screenshot-3.png", + "https://i.postimg.cc/0Q4SqjMX/Screenshot-4.png", + "https://i.postimg.cc/rp8x1v2j/Screenshot-5.png", + "https://i.postimg.cc/xC8m7MCb/Screenshot-6.png" + ] + }, + "hidemaru-editor": { + "icon": "https://community.chocolatey.org/content/packageimages/hidemaru-editor.8.95.png", + "images": [] + }, + "hideme": { + "icon": "", + "images": [] + }, + "hideuser": { + "icon": "", + "images": [] + }, + "hidevolumeosd": { + "icon": "https://community.chocolatey.org/content/packageimages/hidevolumeosd.1.3.png", + "images": [] + }, + "hidhide": { + "icon": "", + "images": [] + }, + "higan": { + "icon": "https://community.chocolatey.org/content/packageimages/higan.1.0.096.png", + "images": [] + }, + "highlight": { + "icon": "", + "images": [] + }, + "highs": { + "icon": "", + "images": [] + }, + "hightailexpress": { + "icon": "", + "images": [] + }, + "hijackthis": { + "icon": "https://community.chocolatey.org/content/packageimages/hijackthis.2.10.0.14.png", + "images": [] + }, + "hikvision-sadp": { + "icon": "", + "images": [] + }, + "himalaya": { + "icon": "", + "images": [] + }, + "hindsight": { + "icon": "https://community.chocolatey.org/content/packageimages/hindsight.2021.12.png", + "images": [] + }, + "hipchat": { + "icon": "https://community.chocolatey.org/content/packageimages/HipChat.4.30.3.1665.png", + "images": [] + }, + "hipdf": { + "icon": "", + "images": [] + }, + "hiphop": { + "icon": "", + "images": [] + }, + "hipposcan": { + "icon": "", + "images": [] + }, + "hisuite": { + "icon": "", + "images": [] + }, + "hitfilmexpress": { + "icon": "", + "images": [] + }, + "hjson": { + "icon": "", + "images": [] + }, + "hl7inspector": { + "icon": "https://community.chocolatey.org/content/packageimages/hl7inspector.install.2.7.4.png", + "images": [] + }, + "hlae": { + "icon": "", + "images": [] + }, + "hledger": { + "icon": "", + "images": [] + }, + "hmailserver": { + "icon": "", + "images": [] + }, + "hmne": { + "icon": "https://community.chocolatey.org/content/packageimages/hmne.2.0.3.png", + "images": [] + }, + "hmnisedit": { + "icon": "", + "images": [] + }, + "hobocopy": { + "icon": "", + "images": [] + }, + "hokus": { + "icon": "", + "images": [] + }, + "hollows-hunter": { + "icon": "", + "images": [] + }, + "holzshots": { + "icon": "", + "images": [] + }, + "homeassistant": { + "icon": "", + "images": [] + }, + "homebank": { + "icon": "https://postimg.cc/Lnf7LZr0", + "images": [ + "https://www.gethomebank.org/screenshots/5.8/image1.png", + "https://www.gethomebank.org/screenshots/5.8/image2.png", + "https://www.gethomebank.org/screenshots/5.8/image3.png", + "https://www.gethomebank.org/screenshots/5.8/image4.png", + "https://www.gethomebank.org/screenshots/5.8/image5.png", + "https://www.gethomebank.org/screenshots/5.8/image6.png" + ] + }, + "homedale": { + "icon": "", + "images": [] + }, + "homepages-winconfig": { + "icon": "https://community.chocolatey.org/content/packageimages/homepages-winconfig.0.0.1.png", + "images": [] + }, + "honeybee-devops-packaging": { + "icon": "", + "images": [] + }, + "honeybee-devops-selfdeployment": { + "icon": "", + "images": [] + }, + "honeyview": { + "icon": "https://tweakers.net/ext/i/2000553432.jpeg", + "images": [ + "https://tweakers.net/ext/i/2001549423.jpeg" + ] + }, + "hopmon": { + "icon": "", + "images": [] + }, + "hopp-cli": { + "icon": "", + "images": [] + }, + "hopsan": { + "icon": "https://community.chocolatey.org/content/packageimages/hopsan.2.20.0.png", + "images": [] + }, + "horcrux": { + "icon": "", + "images": [] + }, + "horizon": { + "icon": "", + "images": [] + }, + "horizon-eda": { + "icon": "", + "images": [] + }, + "horizonclient": { + "icon": "", + "images": [] + }, + "host-editor": { + "icon": "", + "images": [] + }, + "hostctl": { + "icon": "", + "images": [] + }, + "hostinfo": { + "icon": "", + "images": [] + }, + "hosts": { + "icon": "", + "images": [] + }, + "hosts-editor": { + "icon": "https://community.chocolatey.org/content/packageimages/hosts.editor.1.2.0.png", + "images": [] + }, + "hosts-file-editor": { + "icon": "", + "images": [] + }, + "hostsman": { + "icon": "", + "images": [] + }, + "hot-chocolatey": { + "icon": "https://community.chocolatey.org/content/packageimages/hot-chocolatey.7.0.1.0.png", + "images": [] + }, + "hotpotato": { + "icon": "", + "images": [] + }, + "hotswap": { + "icon": "", + "images": [] + }, + "houdoku": { + "icon": "", + "images": [] + }, + "hourglass": { + "icon": "https://community.chocolatey.org/content/packageimages/hourglass.install.1.15.png", + "images": [] + }, + "housecall": { + "icon": "https://community.chocolatey.org/content/packageimages/housecall.portable.1.62.0.1252.png", + "images": [] + }, + "hover": { + "icon": "", + "images": [ + "https://i.postimg.cc/MTT2n9rQ/image.png", + "https://i.postimg.cc/Dz7KTvr5/image.png" + ] + }, + "howard": { + "icon": "", + "images": [] + }, + "hp-coolsense-technology": { + "icon": "", + "images": [] + }, + "hp-ilo-cmdlets": { + "icon": "", + "images": [] + }, + "hp-oa-cmdlets": { + "icon": "", + "images": [] + }, + "hp-universal-print-driver-pcl": { + "icon": "https://community.chocolatey.org/content/packageimages/hp-universal-print-driver-pcl.7.0.1.24923.png", + "images": [] + }, + "hp-universal-print-driver-ps": { + "icon": "https://community.chocolatey.org/content/packageimages/hp-universal-print-driver-ps.7.0.0.24832.png", + "images": [] + }, + "hpbcu": { + "icon": "https://community.chocolatey.org/content/packageimages/hpbcu.4.0.30.1.png", + "images": [] + }, + "hpcloudrecoverytool": { + "icon": "", + "images": [] + }, + "hpcmsl": { + "icon": "", + "images": [] + }, + "hpdiagnostics": { + "icon": "https://community.chocolatey.org/content/packageimages/hpdiagnostics.2.1.0.0.png", + "images": [] + }, + "hpglviewer": { + "icon": "", + "images": [] + }, + "hppark": { + "icon": "https://community.chocolatey.org/content/packageimages/hppark.1.8.7.png", + "images": [] + }, + "hpsupportassistant": { + "icon": "https://community.chocolatey.org/content/packageimages/hpsupportassistant.9.19.52.0.png", + "images": [] + }, + "hpusbdisk": { + "icon": "", + "images": [] + }, + "hsm-usb-serial-driver": { + "icon": "", + "images": [] + }, + "hst": { + "icon": "", + "images": [] + }, + "hte": { + "icon": "", + "images": [] + }, + "html-help-workshop": { + "icon": "https://community.chocolatey.org/content/packageimages/html-help-workshop.1.32.1.png", + "images": [] + }, + "html-tidy": { + "icon": "", + "images": [] + }, + "htmlclip": { + "icon": "", + "images": [] + }, + "htmlconverter": { + "icon": "https://community.chocolatey.org/content/packageimages/HTMLConverter.3.1.png", + "images": [] + }, + "htmlpackager": { + "icon": "", + "images": [] + }, + "htmlq": { + "icon": "", + "images": [] + }, + "http-downloader": { + "icon": "", + "images": [] + }, + "httpdownloader": { + "icon": "https://i.postimg.cc/d3CWK7DB/httpd.png", + "images": [ + "https://i.postimg.cc/G22Jb4gD/image.png", + "https://i.postimg.cc/Prkyw5Pg/image.png", + "https://i.postimg.cc/Ls7B6Hc0/image.png", + "https://i.postimg.cc/j576DpKq/image.png", + "https://i.postimg.cc/Y0B6Ydq6/image.png" + ] + }, + "httpie": { + "icon": "https://community.chocolatey.org/content/packageimages/httpie.3.2.1.png", + "images": [] + }, + "httpie-desktop": { + "icon": "https://community.chocolatey.org/content/packageimages/httpie-desktop.2023.1.2.png", + "images": [] + }, + "httping": { + "icon": "", + "images": [] + }, + "httpmaster-express": { + "icon": "https://community.chocolatey.org/content/packageimages/httpmaster-express.5.7.0.png", + "images": [] + }, + "httpmaster-professional": { + "icon": "https://community.chocolatey.org/content/packageimages/httpmaster-professional.5.7.0.png", + "images": [] + }, + "httpmasterexpress": { + "icon": "", + "images": [] + }, + "httpmasterprofessional": { + "icon": "", + "images": [] + }, + "httpnetworksniffer": { + "icon": "https://community.chocolatey.org/content/packageimages/httpnetworksniffer.1.63.png", + "images": [] + }, + "httpplatformhandler": { + "icon": "", + "images": [] + }, + "httprest": { + "icon": "", + "images": [] + }, + "https-everywhere-chrome": { + "icon": "", + "images": [] + }, + "httpstat": { + "icon": "", + "images": [] + }, + "httptoolkit": { + "icon": "", + "images": [] + }, + "httrack": { + "icon": "", + "images": [] + }, + "httrack-app": { + "icon": "", + "images": [] + }, + "huaweibrowser": { + "icon": "", + "images": [] + }, + "huaweicloudmeeting": { + "icon": "", + "images": [] + }, + "huayupy": { + "icon": "", + "images": [] + }, + "hub": { + "icon": "https://resources.jetbrains.com/storage/products/hub/img/meta/hub_logo_300x300.png", + "images": [] + }, + "huesync": { + "icon": "", + "images": [] + }, + "huggle": { + "icon": "", + "images": [] + }, + "hugin": { + "icon": "https://community.chocolatey.org/content/packageimages/hugin.portable.2015.0.0.png", + "images": [] + }, + "hugo": { + "icon": "https://i.postimg.cc/zf0bKK5p/image.png", + "images": [] + }, + "hugo-extended": { + "icon": "https://i.postimg.cc/zf0bKK5p/image.png", + "images": [] + }, + "hugo-hugo-extended": { + "icon": "https://i.postimg.cc/zf0bKK5p/image.png", + "images": [] + }, + "hulu-desktop": { + "icon": "", + "images": [] + }, + "humble-app": { + "icon": "", + "images": [] + }, + "humbleapp": { + "icon": "", + "images": [] + }, + "hunspell": { + "icon": "", + "images": [] + }, + "hurl": { + "icon": "https://community.chocolatey.org/content/packageimages/hurl.2.0.1.png", + "images": [] + }, + "hvmanager": { + "icon": "", + "images": [] + }, + "hwinfo": { + "icon": "https://i.postimg.cc/MKfynM2J/HWiNFO64.png", + "images": [ + "https://i.postimg.cc/6Qrcy7Zp/image.png", + "https://i.postimg.cc/3R3BpKjC/image.png", + "https://i.postimg.cc/D0ZPjBMS/image.png", + "https://i.postimg.cc/KjHrdB6J/image.png", + "https://i.postimg.cc/MGm0zCkc/image.png", + "https://i.postimg.cc/TPfmNtyT/image.png" + ] + }, + "hwinfo32": { + "icon": "https://i.postimg.cc/MKfynM2J/HWiNFO64.png", + "images": [ + "https://i.postimg.cc/6Qrcy7Zp/image.png", + "https://i.postimg.cc/3R3BpKjC/image.png", + "https://i.postimg.cc/D0ZPjBMS/image.png", + "https://i.postimg.cc/KjHrdB6J/image.png", + "https://i.postimg.cc/MGm0zCkc/image.png", + "https://i.postimg.cc/TPfmNtyT/image.png" + ] + }, + "hwmonitor": { + "icon": "https://i.postimg.cc/65W1fQwD/hwmonitor.png", + "images": [] + }, + "hwp-converter": { + "icon": "", + "images": [] + }, + "hxd": { + "icon": "https://community.chocolatey.org/content/packageimages/HxD.2.5.0.0.png", + "images": [] + }, + "hybridsaas": { + "icon": "", + "images": [] + }, + "hydrairc": { + "icon": "https://community.chocolatey.org/content/packageimages/hydrairc.0.3.165.1.png", + "images": [] + }, + "hydrogen": { + "icon": "", + "images": [] + }, + "hydrus-network": { + "icon": "https://community.chocolatey.org/content/packageimages/hydrus-network.518.0.png", + "images": [] + }, + "hydrusnetwork": { + "icon": "", + "images": [ + "https://raw.githubusercontent.com/hydrusnetwork/hydrus/master/static/hydrus.png", + "https://hydrusnetwork.github.io/hydrus/images/screenshot_empty.png", + "https://hydrusnetwork.github.io/hydrus/images/screenshot_thread_watcher.png" + ] + }, + "hygen": { + "icon": "", + "images": [] + }, + "hyper": { + "icon": "https://community.chocolatey.org/content/packageimages/hyper.3.4.1.png", + "images": [] + }, + "hyper-v-switch": { + "icon": "", + "images": [] + }, + "hyperamp": { + "icon": "", + "images": [] + }, + "hyperfine": { + "icon": "", + "images": [] + }, + "hyperspace": { + "icon": "https://community.chocolatey.org/content/packageimages/hyperspace.1.1.4.png", + "images": [] + }, + "hyperspace-desktop": { + "icon": "https://community.chocolatey.org/content/packageimages/hyperspace-desktop.1.1.2.png", + "images": [] + }, + "hyperspacedesktop": { + "icon": "", + "images": [] + }, + "hysteria": { + "icon": "", + "images": [] + }, + "hytale": { + "icon": "https://i.ibb.co/84gk48zK/hytale.png", + "images": [] + }, + "i-am": { + "icon": "", + "images": [] + }, + "i18nmanager": { + "icon": "", + "images": [] + }, + "i2p": { + "icon": "https://community.chocolatey.org/content/packageimages/i2p.2.1.0.png", + "images": [] + }, + "i2p-zero": { + "icon": "", + "images": [] + }, + "i2p-zero-gui": { + "icon": "", + "images": [] + }, + "i2pd": { + "icon": "", + "images": [] + }, + "iapdesktop": { + "icon": "", + "images": [] + }, + "iasl": { + "icon": "https://community.chocolatey.org/content/packageimages/iasl.2022.03.31.png", + "images": [] + }, + "iawriter": { + "icon": "", + "images": [] + }, + "ibackupbot": { + "icon": "", + "images": [] + }, + "ibex": { + "icon": "https://community.chocolatey.org/content/packageimages/ibex.2.8.9.20220812.png", + "images": [] + }, + "ibmcloud-cli": { + "icon": "", + "images": [] + }, + "icaros": { + "icon": "https://community.chocolatey.org/content/packageimages/Icaros.3.2.1.png", + "images": [] + }, + "icaros-beta": { + "icon": "", + "images": [] + }, + "icbcchromeextension": { + "icon": "", + "images": [] + }, + "icbcebankassist": { + "icon": "", + "images": [] + }, + "icc-profile-inspector": { + "icon": "", + "images": [] + }, + "icecast": { + "icon": "https://community.chocolatey.org/content/packageimages/icecast.2.4.4.png", + "images": [] + }, + "icecat": { + "icon": "https://community.chocolatey.org/content/packageimages/icecat.91.9.1.png", + "images": [] + }, + "icechat": { + "icon": "", + "images": [] + }, + "icedtea-web": { + "icon": "https://community.chocolatey.org/content/packageimages/icedtea-web.1.8.8.png", + "images": [] + }, + "iceweasel": { + "icon": "", + "images": [] + }, + "icinga2": { + "icon": "https://community.chocolatey.org/content/packageimages/icinga2.2.13.7.png", + "images": [] + }, + "icloud": { + "icon": "https://developer.apple.com/assets/elements/icons/icloud/icloud-256x256.png", + "images": [] + }, + "icnsify": { + "icon": "", + "images": [] + }, + "iconedit2": { + "icon": "", + "images": [] + }, + "iconizer": { + "icon": "https://community.chocolatey.org/content/packageimages/iconizer.2013.06.25.png", + "images": [] + }, + "iconscout": { + "icon": "", + "images": [] + }, + "iconsext": { + "icon": "https://community.chocolatey.org/content/packageimages/iconsext.1.47.0.20150708.png", + "images": [] + }, + "iconsextract": { + "icon": "", + "images": [] + }, + "iconv": { + "icon": "", + "images": [] + }, + "iconviewer": { + "icon": "", + "images": [ + "https://i.postimg.cc/dtGBYzxf/iv3.png" + ] + }, + "iconworkshop": { + "icon": "", + "images": [ + "https://i.postimg.cc/NMrF1Pt9/image.png", + "https://i.postimg.cc/fycbPtJz/image.png" + ] + }, + "icopy": { + "icon": "https://community.chocolatey.org/content/packageimages/icopy.install.1.7.0.png", + "images": [ + "https://i.postimg.cc/15qVBMSf/icopy-ss.png" + ] + }, + "icqnew": { + "icon": "", + "images": [] + }, + "icsharp": { + "icon": "", + "images": [] + }, + "icue": { + "icon": "https://community.chocolatey.org/content/packageimages/icue.4.33.138.png", + "images": [] + }, + "icue-3": { + "icon": "", + "images": [] + }, + "icue-4": { + "icon": "", + "images": [] + }, + "ida-free": { + "icon": "https://community.chocolatey.org/content/packageimages/ida-free.8.2.png", + "images": [] + }, + "ide-beta": { + "icon": "https://i.postimg.cc/VLBfqzyt/arduino.png", + "images": [ + "https://i.imgur.com/Wt5xlSf.png", + "https://andprof.com/wp-content/uploads/2021/10/What-is-arduino-software-IDE-and-how-use-it.png", + "https://static.javatpoint.com/tutorial/arduino/images/arduino-ide.png", + "https://www.digikey.my/-/media/MakerIO/Images/blogs/2018/Introduction%20to%20the%20Arduino%20IDE/Fig-1.jpg" + ] + }, + "ide-rc": { + "icon": "https://i.postimg.cc/VLBfqzyt/arduino.png", + "images": [ + "https://i.imgur.com/Wt5xlSf.png", + "https://andprof.com/wp-content/uploads/2021/10/What-is-arduino-software-IDE-and-how-use-it.png", + "https://static.javatpoint.com/tutorial/arduino/images/arduino-ide.png", + "https://www.digikey.my/-/media/MakerIO/Images/blogs/2018/Introduction%20to%20the%20Arduino%20IDE/Fig-1.jpg" + ] + }, + "ide-stable": { + "icon": "https://i.postimg.cc/VLBfqzyt/arduino.png", + "images": [ + "https://i.imgur.com/Wt5xlSf.png", + "https://andprof.com/wp-content/uploads/2021/10/What-is-arduino-software-IDE-and-how-use-it.png", + "https://static.javatpoint.com/tutorial/arduino/images/arduino-ide.png", + "https://www.digikey.my/-/media/MakerIO/Images/blogs/2018/Introduction%20to%20the%20Arduino%20IDE/Fig-1.jpg" + ] + }, + "idea": { + "icon": "", + "images": [] + }, + "idea-ultimate": { + "icon": "", + "images": [] + }, + "ideamaker": { + "icon": "https://community.chocolatey.org/content/packageimages/ideamaker.4.3.1.6452.png", + "images": [] + }, + "ideashare": { + "icon": "", + "images": [] + }, + "ideashareproject": { + "icon": "", + "images": [] + }, + "identityv": { + "icon": "", + "images": [] + }, + "identityv-cn": { + "icon": "", + "images": [] + }, + "idle-logoff": { + "icon": "", + "images": [] + }, + "idle-master-extended": { + "icon": "https://community.chocolatey.org/content/packageimages/idle-master-extended.1.2.png", + "images": [] + }, + "idleeucalytus": { + "icon": "", + "images": [] + }, + "idphotostudio": { + "icon": "", + "images": [] + }, + "idris": { + "icon": "https://community.chocolatey.org/content/packageimages/idris.1.1.1.png", + "images": [] + }, + "idrive": { + "icon": "https://community.chocolatey.org/content/packageimages/idrive.6.7.4.41.png", + "images": [] + }, + "ie": { + "icon": "", + "images": [] + }, + "ie-box2d-api-sample1": { + "icon": "", + "images": [] + }, + "ie-zadig": { + "icon": "https://i.postimg.cc/TPg0gR9T/zadig.png", + "images": [ + "https://i.postimg.cc/C5PsSdFs/image.png" + ] + }, + "ie10": { + "icon": "", + "images": [] + }, + "ie11": { + "icon": "", + "images": [] + }, + "ie11webdriver": { + "icon": "", + "images": [] + }, + "ie9": { + "icon": "", + "images": [] + }, + "iecacheview": { + "icon": "https://community.chocolatey.org/content/packageimages/iecacheview.1.58.png", + "images": [] + }, + "iedriverserver": { + "icon": "", + "images": [] + }, + "iepv": { + "icon": "https://community.chocolatey.org/content/packageimages/iepv.1.35.png", + "images": [] + }, + "ietab-chrome": { + "icon": "", + "images": [] + }, + "ietester": { + "icon": "https://community.chocolatey.org/content/packageimages/ietester.0.5.4.20170203.png", + "images": [] + }, + "iflyime": { + "icon": "", + "images": [] + }, + "iforgot": { + "icon": "", + "images": [] + }, + "ifunscreenrecorder": { + "icon": "", + "images": [] + }, + "ifunscreenshot": { + "icon": "", + "images": [] + }, + "igclient": { + "icon": "https://i.postimg.cc/5Nct9sXC/Indie-Gala.png", + "images": [] + }, + "igdm": { + "icon": "https://community.chocolatey.org/content/packageimages/igdm.2.6.5.png", + "images": [] + }, + "igetter": { + "icon": "https://community.chocolatey.org/content/packageimages/igetter.3.0.0.png", + "images": [] + }, + "ignition": { + "icon": "", + "images": [] + }, + "ignorefiles": { + "icon": "", + "images": [] + }, + "ignoreit": { + "icon": "", + "images": [] + }, + "iguana": { + "icon": "https://community.chocolatey.org/content/packageimages/iguana.install.6.1.5.png", + "images": [] + }, + "ihavenotomatoes": { + "icon": "", + "images": [] + }, + "iis": { + "icon": "https://community.chocolatey.org/content/packageimages/iis.2.0.0.png", + "images": [] + }, + "iis-administration": { + "icon": "", + "images": [] + }, + "iis-arr": { + "icon": "https://community.chocolatey.org/content/packageimages/iis-arr.3.0.20210521.png", + "images": [] + }, + "iis-compression": { + "icon": "https://community.chocolatey.org/content/packageimages/iis-compression.1.0.6502.png", + "images": [] + }, + "iis-cors-module": { + "icon": "https://community.chocolatey.org/content/packageimages/iis-cors-module.1.0.png", + "images": [] + }, + "iis-externalcache": { + "icon": "", + "images": [] + }, + "iis75-express": { + "icon": "", + "images": [] + }, + "iiscryptocli": { + "icon": "", + "images": [] + }, + "iiscryptogui": { + "icon": "", + "images": [] + }, + "iisgeolocate": { + "icon": "", + "images": [] + }, + "iishosts": { + "icon": "", + "images": [] + }, + "iissecurity-psmodule": { + "icon": "https://community.chocolatey.org/content/packageimages/iissecurity-psmodule.1.3.0.png", + "images": [] + }, + "iiumschedule": { + "icon": "", + "images": [] + }, + "ike-scan": { + "icon": "", + "images": [] + }, + "ikvm": { + "icon": "", + "images": [] + }, + "ilastik": { + "icon": "https://community.chocolatey.org/content/packageimages/ilastik.1.4.0.8.png", + "images": [] + }, + "ileapp": { + "icon": "", + "images": [] + }, + "ilmerge": { + "icon": "", + "images": [] + }, + "ilovepdfdesktop": { + "icon": "", + "images": [] + }, + "ilspy": { + "icon": "https://community.chocolatey.org/content/packageimages/ilspy.7.2.1.png", + "images": [] + }, + "ilspy-getprigindirectionstubsetting-plugin": { + "icon": "", + "images": [] + }, + "imaconverter": { + "icon": "", + "images": [] + }, + "imageanalyzer": { + "icon": "https://community.chocolatey.org/content/packageimages/imageanalyzer.1.38.4.png", + "images": [] + }, + "imagecacheviewer": { + "icon": "https://community.chocolatey.org/content/packageimages/imagecacheviewer.1.20.png", + "images": [] + }, + "imageconverter": { + "icon": "", + "images": [] + }, + "imageglass": { + "icon": "https://i.postimg.cc/ncpmLSDW/imageglass.png", + "images": [ + "https://i.postimg.cc/PrXM752N/imageglassscreenshot.png" + ] + }, + "imagej": { + "icon": "https://community.chocolatey.org/content/packageimages/imagej.1.53.png", + "images": [] + }, + "imagemagick": { + "icon": "https://community.chocolatey.org/content/packageimages/imagemagick.7.1.0.6100.png", + "images": [] + }, + "imagemagick-app": { + "icon": "https://community.chocolatey.org/content/packageimages/imagemagick.app.7.1.0.6200.png", + "images": [] + }, + "imagemagick-lean": { + "icon": "", + "images": [] + }, + "imagemanager": { + "icon": "https://community.chocolatey.org/content/packageimages/ImageManager.7.7.0.png", + "images": [] + }, + "imageoptimizer": { + "icon": "", + "images": [] + }, + "imageslicer": { + "icon": "", + "images": [] + }, + "imagesprites": { + "icon": "", + "images": [] + }, + "imageusb": { + "icon": "https://community.chocolatey.org/content/packageimages/imageusb.1.5.1003.png", + "images": [] + }, + "imageview": { + "icon": "", + "images": [] + }, + "imagine": { + "icon": "", + "images": [ + "https://i.postimg.cc/MpQLn0hB/image.png", + "https://i.postimg.cc/s2P0cjfD/image.png", + "https://i.postimg.cc/DzcBGx5S/image.png", + "https://i.postimg.cc/3w3Z3g7Y/image.png", + "https://i.postimg.cc/SxfvLQxQ/image.png" + ] + }, + "imazing": { + "icon": "", + "images": [] + }, + "imazingheicconverter": { + "icon": "", + "images": [] + }, + "imazingprofileeditor": { + "icon": "", + "images": [] + }, + "imdisk": { + "icon": "https://community.chocolatey.org/content/packageimages/imdisk.2.1.1.png", + "images": [] + }, + "imdone": { + "icon": "", + "images": [] + }, + "imgburn": { + "icon": "https://i.ibb.co/XsmMybM/962a091e98eaabdcdd98e4807565fab2b290848df3391684930e210056617433-200.png", + "images": [ + "https://upload.wikimedia.org/wikipedia/en/0/0a/ImgBurn_screenshot.png" + ] + }, + "imhex": { + "icon": "https://community.chocolatey.org/content/packageimages/imhex.1.26.2.png", + "images": [] + }, + "immunet": { + "icon": "https://community.chocolatey.org/content/packageimages/immunet.7.5.8.21178.png", + "images": [] + }, + "imo-messenger": { + "icon": "", + "images": [] + }, + "implay": { + "icon": "", + "images": [] + }, + "importexcel-powershell": { + "icon": "https://community.chocolatey.org/content/packageimages/importexcel.powershell.7.8.4.png", + "images": [] + }, + "impregnate": { + "icon": "", + "images": [] + }, + "inadyn-mt": { + "icon": "", + "images": [] + }, + "inbox-chrome": { + "icon": "https://community.chocolatey.org/content/packageimages/inbox-chrome.1.0.0.1929.png", + "images": [] + }, + "inboxer": { + "icon": "", + "images": [] + }, + "inbucket": { + "icon": "", + "images": [] + }, + "inclowdz": { + "icon": "", + "images": [] + }, + "inconsolata": { + "icon": "", + "images": [] + }, + "indentex": { + "icon": "https://community.chocolatey.org/content/packageimages/indentex.0.5.0.png", + "images": [] + }, + "infekt": { + "icon": "https://community.chocolatey.org/content/packageimages/infekt.1.0.1.png", + "images": [] + }, + "infektnfoviewer": { + "icon": "", + "images": [] + }, + "infinitex": { + "icon": "https://community.chocolatey.org/content/packageimages/infinitex.portable.0.9.16.png", + "images": [] + }, + "influx": { + "icon": "", + "images": [] + }, + "influxdb": { + "icon": "https://community.chocolatey.org/content/packageimages/influxdb.1.8.10.png", + "images": [] + }, + "influxdb1": { + "icon": "https://community.chocolatey.org/content/packageimages/influxdb1.1.8.10.png", + "images": [] + }, + "infoqube": { + "icon": "", + "images": [] + }, + "informado": { + "icon": "", + "images": [] + }, + "infracost": { + "icon": "https://community.chocolatey.org/content/packageimages/infracost.0.10.17.png", + "images": [] + }, + "infrarecorder": { + "icon": "https://community.chocolatey.org/content/packageimages/InfraRecorder.0.53.0.1.png", + "images": [] + }, + "inimanager": { + "icon": "https://unigeticons.meowcat285.com/iniManager.png", + "images": [] + }, + "inireloc": { + "icon": "", + "images": [] + }, + "initool": { + "icon": "", + "images": [] + }, + "initranslator": { + "icon": "", + "images": [] + }, + "injecteddll": { + "icon": "https://community.chocolatey.org/content/packageimages/injecteddll.1.00.png", + "images": [] + }, + "inkscape": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/0/0d/Inkscape_Logo.svg/240px-Inkscape_Logo.svg.png", + "images": [ + "https://upload.wikimedia.org/wikipedia/commons/e/e5/Inkscape_1.2_screenshot.png", + "https://media.inkscape.org/media/resources/render/Screenshot_Freedom_Machine_Inkscape_master_spEBt2Y.png" + ] + }, + "inkscape-extension-sozi": { + "icon": "", + "images": [] + }, + "inky": { + "icon": "", + "images": [] + }, + "inno-download-plugin": { + "icon": "", + "images": [] + }, + "inno-script-studio": { + "icon": "", + "images": [] + }, + "inno-setup": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/c/cc/Inno_Setup_icon.png", + "images": [ + "https://jazzteam.org/en/wp-content/uploads/2020/09/image1.png", + "https://i.stack.imgur.com/IXyKs.png" + ] + }, + "innoextract": { + "icon": "https://community.chocolatey.org/content/packageimages/innoextract.1.9.png", + "images": [] + }, + "innoscriptstudio": { + "icon": "", + "images": [] + }, + "innosetup": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/c/cc/Inno_Setup_icon.png", + "images": [ + "https://jazzteam.org/en/wp-content/uploads/2020/09/image1.png", + "https://i.stack.imgur.com/IXyKs.png" + ] + }, + "innounp": { + "icon": "https://cdn2.portableapps.com/InnoUnpackerPortable_128.png", + "images": [] + }, + "inpixiophotostudio": { + "icon": "", + "images": [] + }, + "input-overlay": { + "icon": "", + "images": [] + }, + "inputdirector": { + "icon": "https://community.chocolatey.org/content/packageimages/InputDirector.2.1.png", + "images": [] + }, + "insd": { + "icon": "https://community.chocolatey.org/content/packageimages/insd.2022.1.0.0.png", + "images": [] + }, + "insect": { + "icon": "https://community.chocolatey.org/content/packageimages/insect.5.7.0.png", + "images": [] + }, + "insideclipboard": { + "icon": "https://community.chocolatey.org/content/packageimages/insideclipboard.1.15.png", + "images": [ + "https://i.postimg.cc/TPLR53jf/image.png" + ] + }, + "insomnia": { + "icon": "https://community.chocolatey.org/content/packageimages/insomnia-rest-api-client.2023.9.2.png", + "images": [ + "https://i.postimg.cc/yNCXgPp8/image.png", + "https://i.postimg.cc/B6qTNv0W/image.png", + "https://i.postimg.cc/Bbbx9wbM/image.png", + "https://i.postimg.cc/Qt0pzr8F/image.png" + ] + }, + "insomnia-designer": { + "icon": "https://community.chocolatey.org/content/packageimages/insomnia-designer.2020.5.2.png", + "images": [] + }, + "insomnia-dotnet": { + "icon": "https://community.chocolatey.org/content/packageimages/insomnia-dotnet.1.0.0.0.png", + "images": [] + }, + "insomnia-rest-api-client": { + "icon": "https://community.chocolatey.org/content/packageimages/insomnia-rest-api-client.2022.7.4.png", + "images": [] + }, + "inspec": { + "icon": "https://community.chocolatey.org/content/packageimages/inspec.4.46.13.png", + "images": [] + }, + "inssider": { + "icon": "", + "images": [] + }, + "inssider-lite": { + "icon": "https://community.chocolatey.org/content/packageimages/inssider-lite.1.11.1.png", + "images": [] + }, + "inssist": { + "icon": "", + "images": [] + }, + "install4j": { + "icon": "https://community.chocolatey.org/content/packageimages/install4j.install.7.0.11.png", + "images": [] + }, + "installpackcomplete": { + "icon": "https://keygensofts.com/wp-content/uploads/2021/06/AVS4YOU.jpg", + "images": [ + "https://i.imgur.com/RH6wO99.jpg", + "https://i.imgur.com/z8oFnzY.png" + ] + }, + "installroot": { + "icon": "https://community.chocolatey.org/content/packageimages/installroot.5.5.png", + "images": [] + }, + "instant-eyedropper": { + "icon": "", + "images": [] + }, + "instanteyedropper": { + "icon": "https://community.chocolatey.org/content/packageimages/instanteyedropper.1.75.png", + "images": [] + }, + "instanteyedropper-app": { + "icon": "https://community.chocolatey.org/content/packageimages/instanteyedropper.app.1.75.png", + "images": [] + }, + "instanteyedropper-tool": { + "icon": "https://community.chocolatey.org/content/packageimages/instanteyedropper.tool.1.75.png", + "images": [] + }, + "instanthousecall": { + "icon": "", + "images": [] + }, + "instantjchem": { + "icon": "", + "images": [] + }, + "instantwordpress": { + "icon": "", + "images": [] + }, + "insted": { + "icon": "https://community.chocolatey.org/content/packageimages/InstEd.1.5.15.27.png", + "images": [] + }, + "instigator": { + "icon": "", + "images": [] + }, + "insync": { + "icon": "https://images2.imgbox.com/d4/d8/0gMfRUTK_o.png", + "images": [ + "https://i.ibb.co/8D4W4Lv/Insync-Vy-QWYJC469.png" + ] + }, + "integerscaler": { + "icon": "", + "images": [] + }, + "intel-arc-graphics-driver": { + "icon": "", + "images": [] + }, + "intel-bluetooth-drivers": { + "icon": "", + "images": [] + }, + "intel-chipset-device-software": { + "icon": "https://community.chocolatey.org/content/packageimages/intel-chipset-device-software.10.1.18793.8276.png", + "images": [] + }, + "intel-dsa": { + "icon": "", + "images": [] + }, + "intel-graphics-driver": { + "icon": "", + "images": [] + }, + "intel-ipdt": { + "icon": "", + "images": [] + }, + "intel-killer-performance-suite": { + "icon": "", + "images": [] + }, + "intel-mas": { + "icon": "https://community.chocolatey.org/content/packageimages/intel-mas.2.2.png", + "images": [] + }, + "intel-me-drivers": { + "icon": "", + "images": [] + }, + "intel-network-drivers-win10": { + "icon": "", + "images": [] + }, + "intel-processor-identification-utility": { + "icon": "", + "images": [] + }, + "intel-proset-drivers": { + "icon": "", + "images": [] + }, + "intel-redist-cpp": { + "icon": "https://community.chocolatey.org/content/packageimages/intel-redist-cpp.2019.5.281.png", + "images": [] + }, + "intel-rst-driver": { + "icon": "", + "images": [] + }, + "intel-xtu": { + "icon": "", + "images": [] + }, + "intelligenthub": { + "icon": "", + "images": [] + }, + "intellijidea": { + "icon": "https://resources.jetbrains.com/storage/products/company/brand/logos/IntelliJ_IDEA_icon.png", + "images": [] + }, + "intellijidea-community": { + "icon": "https://resources.jetbrains.com/storage/products/intellij-idea/img/meta/intellij-idea_logo_300x300.png", + "images": [] + }, + "intellijidea-edu": { + "icon": "https://resources.jetbrains.com/storage/products/intellij-idea/img/meta/intellij-idea_logo_300x300.png", + "images": [] + }, + "intellijidea-ultimate": { + "icon": "https://resources.jetbrains.com/storage/products/company/brand/logos/IntelliJ_IDEA_icon.png", + "images": [] + }, + "intellijidea-ultimate-eap": { + "icon": "https://resources.jetbrains.com/storage/products/intellij-idea/img/meta/intellij-idea_logo_300x300.png", + "images": [] + }, + "IntelliJIDEA-Ultimate": { + "icon": "https://resources.jetbrains.com/storage/products/company/brand/logos/IntelliJ_IDEA_icon.png", + "images": [ + "https://www.jetbrains.com/idea/img/overview-heading-screenshot.png" + ] + }, + "intellitype": { + "icon": "https://community.chocolatey.org/content/packageimages/intellitype.8.20.469.0.png", + "images": [] + }, + "intelpowergadget": { + "icon": "https://community.chocolatey.org/content/packageimages/intelpowergadget.3.5.9.png", + "images": [] + }, + "interactivedataeditor": { + "icon": "", + "images": [] + }, + "interiordesign3d": { + "icon": "", + "images": [] + }, + "interlink": { + "icon": "", + "images": [] + }, + "intermodal": { + "icon": "", + "images": [] + }, + "internet-download-manager": { + "icon": "https://community.chocolatey.org/content/packageimages/internet-download-manager.6.41.7.png", + "images": [ + "https://www.internetdownloadmanager.com/images/idm_screenshot_6_35.png", + "https://www.internetdownloadmanager.com/images/queue.png" + ] + }, + "internetdownloadmanager": { + "icon": "https://i.postimg.cc/Vk37BG4z/internet-download-manager.png", + "images": [ + "https://www.internetdownloadmanager.com/images/idm_screenshot_6_35.png", + "https://www.internetdownloadmanager.com/images/queue.png" + ] + }, + "internetoff": { + "icon": "", + "images": [] + }, + "internxt-drive": { + "icon": "", + "images": [] + }, + "interopformsredist": { + "icon": "https://community.chocolatey.org/content/packageimages/interopformsredist.2.0.1.png", + "images": [] + }, + "intuiter": { + "icon": "", + "images": [] + }, + "intunewinapputil": { + "icon": "", + "images": [] + }, + "invantive-bridge-connectors-power-bi": { + "icon": "https://community.chocolatey.org/content/packageimages/invantive-bridge-connectors-power-bi.20.2.172.png", + "images": [] + }, + "invantive-bridge-developers": { + "icon": "https://community.chocolatey.org/content/packageimages/invantive-bridge-developers.20.0.154.png", + "images": [] + }, + "invantive-business-for-outlook": { + "icon": "https://community.chocolatey.org/content/packageimages/invantive-business-for-outlook.22.0.186.png", + "images": [] + }, + "invantive-business-for-windows": { + "icon": "https://community.chocolatey.org/content/packageimages/invantive-business-for-windows.22.0.187.png", + "images": [] + }, + "invantive-composition-for-word": { + "icon": "https://community.chocolatey.org/content/packageimages/invantive-composition-for-word.22.0.187.png", + "images": [] + }, + "invantive-control-for-excel": { + "icon": "https://community.chocolatey.org/content/packageimages/invantive-control-for-excel.22.0.187.png", + "images": [] + }, + "invantive-data-hub": { + "icon": "https://community.chocolatey.org/content/packageimages/invantive-data-hub.22.0.187.png", + "images": [] + }, + "invantive-estate-for-outlook": { + "icon": "https://community.chocolatey.org/content/packageimages/invantive-estate-for-outlook.22.0.187.png", + "images": [] + }, + "invantive-query-tool": { + "icon": "https://community.chocolatey.org/content/packageimages/invantive-query-tool.22.0.187.png", + "images": [] + }, + "invantive-studio": { + "icon": "https://community.chocolatey.org/content/packageimages/invantive-studio.22.0.187.png", + "images": [] + }, + "inventorview": { + "icon": "https://community.chocolatey.org/content/packageimages/inventorview.2023.270158.png", + "images": [] + }, + "invisiwind": { + "icon": "", + "images": [] + }, + "invizi": { + "icon": "", + "images": [] + }, + "invoke-build": { + "icon": "", + "images": [] + }, + "invokebuild": { + "icon": "https://community.chocolatey.org/content/packageimages/invokebuild.5.10.2.png", + "images": [] + }, + "invokemsbuild": { + "icon": "", + "images": [] + }, + "invoncify": { + "icon": "", + "images": [] + }, + "io-js": { + "icon": "", + "images": [] + }, + "io-ninja": { + "icon": "https://community.chocolatey.org/content/packageimages/io-ninja.5.3.0.png", + "images": [] + }, + "io-unlocker": { + "icon": "https://community.chocolatey.org/content/packageimages/io-unlocker.1.3.0.png", + "images": [] + }, + "iobit-malware-fighter": { + "icon": "https://community.chocolatey.org/content/packageimages/iobit-malware-fighter.8.9.5.889.png", + "images": [] + }, + "iobit-uninstaller": { + "icon": "https://community.chocolatey.org/content/packageimages/iobit-uninstaller.12.3.0.9.png", + "images": [] + }, + "iobitsysinfo": { + "icon": "", + "images": [] + }, + "iographica": { + "icon": "", + "images": [] + }, + "iometer": { + "icon": "https://community.chocolatey.org/content/packageimages/iometer.1.1.0.20161009.png", + "images": [] + }, + "ioninja": { + "icon": "", + "images": [] + }, + "ioquake3": { + "icon": "https://community.chocolatey.org/content/packageimages/ioquake3.install.1.36.png", + "images": [] + }, + "ioquake3-data": { + "icon": "https://community.chocolatey.org/content/packageimages/ioquake3-data.1.36.png", + "images": [] + }, + "ios-webkit-debug-proxy": { + "icon": "", + "images": [] + }, + "ipe": { + "icon": "https://community.chocolatey.org/content/packageimages/Ipe.7.2.26.png", + "images": [] + }, + "iperf2": { + "icon": "", + "images": [] + }, + "iperf3": { + "icon": "", + "images": [] + }, + "ipevo-presenter": { + "icon": "https://community.chocolatey.org/content/packageimages/ipevo-presenter.6.8.1.1.png", + "images": [] + }, + "ipevo-visualizer": { + "icon": "", + "images": [] + }, + "ipfilter-updater": { + "icon": "https://community.chocolatey.org/content/packageimages/ipfilter-updater.2.2.2.0.png", + "images": [] + }, + "ipfilterupdater": { + "icon": "", + "images": [] + }, + "ipfs-desktop": { + "icon": "https://community.chocolatey.org/content/packageimages/ipfs-desktop.0.26.1.png", + "images": [] + }, + "ipfs-mount": { + "icon": "https://community.chocolatey.org/content/packageimages/ipfs-mount.0.3.3.png", + "images": [] + }, + "iphone-sms-backup-and-restore": { + "icon": "", + "images": [] + }, + "ipinfo": { + "icon": "", + "images": [] + }, + "ipinfo-cli": { + "icon": "", + "images": [] + }, + "iplayer": { + "icon": "https://i.imgur.com/gfpg8io.png", + "images": [ + "https://iplayer-web.files.bbci.co.uk/iplayer-web-app-features/1.0.0-667/install/screenshot.png", + "https://i.imgur.com/nTis8Uz.png", + "https://broadbandtvnews-broadbandtvnews.netdna-ssl.com/wp-content/uploads/2010/09/bbc-iplayer-new-Sept-20101.jpg", + "https://www.ispreview.co.uk/ispnews/data/upimages/subfolders/2009%20Misc/iplayer.jpg" + ] + }, + "ipmicfg": { + "icon": "https://community.chocolatey.org/content/packageimages/ipmicfg.1.27.1.170901.png", + "images": [] + }, + "ipmsg": { + "icon": "", + "images": [] + }, + "ipnetinfo": { + "icon": "https://community.chocolatey.org/content/packageimages/ipnetinfo.install.1.95.png", + "images": [ + "https://i.postimg.cc/VvRSZkHG/image.png" + ] + }, + "ipopt": { + "icon": "", + "images": [] + }, + "ipscan": { + "icon": "", + "images": [] + }, + "iptvnator": { + "icon": "https://i.imgur.com/GFJ1R73.png", + "images": [] + }, + "ipvanish": { + "icon": "https://community.chocolatey.org/content/packageimages/ipvanish.3.4.4.420190621.png", + "images": [] + }, + "ipvtest": { + "icon": "", + "images": [] + }, + "ipwhoisflags-chrome": { + "icon": "", + "images": [] + }, + "iqedge": { + "icon": "", + "images": [] + }, + "iqiyi": { + "icon": "", + "images": [] + }, + "irccloud": { + "icon": "", + "images": [] + }, + "ireboot": { + "icon": "https://community.chocolatey.org/content/packageimages/ireboot.1.1.1.20141201.png", + "images": [] + }, + "ireport": { + "icon": "https://community.chocolatey.org/content/packageimages/ireport.4.5.1.png", + "images": [] + }, + "irfanview": { + "icon": "", + "images": [ + "https://i.postimg.cc/k5fm1vB7/image.png", + "https://i.postimg.cc/zBv19HgK/image.png", + "https://i.postimg.cc/v814ncN4/image.png", + "https://i.postimg.cc/HkmnF3sM/image.png" + ] + }, + "irfanview-languages": { + "icon": "", + "images": [] + }, + "irfanview-lean": { + "icon": "", + "images": [] + }, + "irfanviewplugins": { + "icon": "", + "images": [] + }, + "iris": { + "icon": "https://community.chocolatey.org/content/packageimages/iris.1.2.0.png", + "images": [] + }, + "iriunvr": { + "icon": "", + "images": [] + }, + "iriunwebcam": { + "icon": "", + "images": [] + }, + "ironpython": { + "icon": "", + "images": [] + }, + "ironpython-2": { + "icon": "", + "images": [] + }, + "ironpython-3": { + "icon": "", + "images": [] + }, + "ironruby": { + "icon": "https://community.chocolatey.org/content/packageimages/ironruby.1.1.3.png", + "images": [] + }, + "irscrutinizer": { + "icon": "https://community.chocolatey.org/content/packageimages/IrScrutinizer.2.4.0.png", + "images": [] + }, + "isapirewrite": { + "icon": "https://community.chocolatey.org/content/packageimages/ISAPIRewrite.3.1.0068.png", + "images": [] + }, + "iscommandlineapp": { + "icon": "", + "images": [] + }, + "isepester": { + "icon": "", + "images": [] + }, + "islc": { + "icon": "", + "images": [] + }, + "islide": { + "icon": "", + "images": [] + }, + "isnautoitstudio": { + "icon": "", + "images": [] + }, + "iso7z": { + "icon": "", + "images": [] + }, + "isobuster": { + "icon": "", + "images": [] + }, + "isocreator": { + "icon": "", + "images": [] + }, + "isoplex": { + "icon": "https://community.chocolatey.org/content/packageimages/isoplex.1.0.4.png", + "images": [] + }, + "isorecorder": { + "icon": "https://community.chocolatey.org/content/packageimages/isorecorder.3.1.3.20210129.png", + "images": [] + }, + "isowriter": { + "icon": "https://community.chocolatey.org/content/packageimages/isowriter.0.6.1.20200129.png", + "images": [] + }, + "ispc": { + "icon": "", + "images": [] + }, + "ispy": { + "icon": "", + "images": [] + }, + "istioctl": { + "icon": "", + "images": [] + }, + "iswix": { + "icon": "", + "images": [] + }, + "isx": { + "icon": "", + "images": [] + }, + "italc": { + "icon": "https://community.chocolatey.org/content/packageimages/italc.3.0.1.png", + "images": [] + }, + "itch": { + "icon": "https://raw.githubusercontent.com/itchio/itch/master/src/static/images/tray/itch.png", + "images": [ + "https://static.itch.io/images/app/collections@1x.png", + "https://static.itch.io/images/app/gamepage@1x.png", + "https://static.itch.io/images/app/install@1x.png", + "https://static.itch.io/images/app/html5@1x.png" + ] + }, + "itopdatarecovery": { + "icon": "", + "images": [] + }, + "itopscreenrecorder": { + "icon": "", + "images": [] + }, + "itsclient": { + "icon": "", + "images": [] + }, + "itunes": { + "icon": "https://developer.apple.com/assets/elements/icons/itunes/itunes-256x256.png", + "images": [ + "https://i.postimg.cc/J7B3hnyY/image.png", + "https://i.postimg.cc/fR3DG6qd/image.png", + "https://i.postimg.cc/2SBNcn3F/image.png" + ] + }, + "itunesfusion": { + "icon": "https://community.chocolatey.org/content/packageimages/itunesfusion.3.3.0.20200624.png", + "images": [] + }, + "ivcam": { + "icon": "", + "images": [] + }, + "iverilog": { + "icon": "https://community.chocolatey.org/content/packageimages/iverilog.11.0.png", + "images": [] + }, + "ivideon-client": { + "icon": "", + "images": [] + }, + "ivideon-server": { + "icon": "", + "images": [] + }, + "ivpn": { + "icon": "", + "images": [] + }, + "ivy": { + "icon": "https://community.chocolatey.org/content/packageimages/ivy.2.5.0.png", + "images": [] + }, + "izarc": { + "icon": "https://i.postimg.cc/wMf77mR3/IZArc.png", + "images": [ + "https://i.postimg.cc/52v2MGgX/image.png", + "https://i.postimg.cc/NMNg4wsz/image.png", + "https://i.postimg.cc/9XnmwVN4/image.png" + ] + }, + "izpack": { + "icon": "https://community.chocolatey.org/content/packageimages/izpack.5.1.0.png", + "images": [] + }, + "j-9-03": { + "icon": "", + "images": [] + }, + "j-kinopoisk2imdb": { + "icon": "https://community.chocolatey.org/content/packageimages/j-kinopoisk2imdb.1.2.png", + "images": [] + }, + "jabba": { + "icon": "", + "images": [] + }, + "jabber": { + "icon": "https://community.chocolatey.org/content/packageimages/jabber.14.1.4.57561.png", + "images": [] + }, + "jabra-direct": { + "icon": "https://community.chocolatey.org/content/packageimages/jabra-direct.6.6.03101.png", + "images": [ + "https://www.jabra.com/-/media/Images/Products/Jabra-Direct/v2/direct_screens_v2.png" + ] + }, + "jabref": { + "icon": "https://community.chocolatey.org/content/packageimages/jabref.portable.5.8.png", + "images": [] + }, + "jack": { + "icon": "https://community.chocolatey.org/content/packageimages/jack.1.9.21.20221111.png", + "images": [] + }, + "jack2": { + "icon": "", + "images": [] + }, + "jackett": { + "icon": "https://community.chocolatey.org/content/packageimages/jackett.0.20.3403.png", + "images": [] + }, + "jacksum": { + "icon": "https://community.chocolatey.org/content/packageimages/jacksum.1.7.0.png", + "images": [] + }, + "jacobrutski-vcenter-script": { + "icon": "", + "images": [] + }, + "jadx": { + "icon": "", + "images": [] + }, + "jaguar": { + "icon": "", + "images": [] + }, + "jaime": { + "icon": "https://community.chocolatey.org/content/packageimages/Jaime.2.0.2.png", + "images": [] + }, + "jameica": { + "icon": "https://community.chocolatey.org/content/packageimages/jameica.2.10.3.png", + "images": [] + }, + "james": { + "icon": "", + "images": [] + }, + "jami": { + "icon": "https://community.chocolatey.org/content/packageimages/jami.2023.02.23.png", + "images": [] + }, + "jami-beta": { + "icon": "", + "images": [] + }, + "jamovi": { + "icon": "https://community.chocolatey.org/content/packageimages/jamovi.install.2.3.21.0.png", + "images": [] + }, + "jamtaba": { + "icon": "", + "images": [] + }, + "jamulus": { + "icon": "", + "images": [] + }, + "jana2006": { + "icon": "https://community.chocolatey.org/content/packageimages/jana2006.5.193.png", + "images": [] + }, + "jandi": { + "icon": "", + "images": [] + }, + "janet": { + "icon": "", + "images": [] + }, + "japaneseime": { + "icon": "https://www.google.co.jp/ime/images/product-icon.png", + "images": [] + }, + "jarfix": { + "icon": "https://community.chocolatey.org/content/packageimages/jarfix.3.0.0.png", + "images": [] + }, + "jasp": { + "icon": "https://community.chocolatey.org/content/packageimages/jasp.0.14.1.png", + "images": [] + }, + "jasper": { + "icon": "", + "images": [] + }, + "jaspersoft-studio": { + "icon": "", + "images": [] + }, + "java7u13x64": { + "icon": "", + "images": [] + }, + "javaruntime": { + "icon": "", + "images": [] + }, + "javaruntime-platformspecific": { + "icon": "", + "images": [] + }, + "javaruntime-preventasktoolbar": { + "icon": "", + "images": [] + }, + "javaruntime-tiger": { + "icon": "", + "images": [] + }, + "javaruntimeenvironment": { + "icon": "https://cdn-icons-png.flaticon.com/256/226/226777.png", + "images": [ + "https://i.postimg.cc/BQz4ZDNX/image.png", + "https://i.postimg.cc/YS6HxP7W/image.png" + ] + }, + "javascriptsnippetpack": { + "icon": "", + "images": [] + }, + "javauninstalltool": { + "icon": "", + "images": [] + }, + "jaws": { + "icon": "https://community.chocolatey.org/content/packageimages/JAWS.2023.2302.15.png", + "images": [] + }, + "jawsforwindows": { + "icon": "", + "images": [] + }, + "jbang": { + "icon": "", + "images": [] + }, + "jbmail": { + "icon": "https://community.chocolatey.org/content/packageimages/jbmail.portable.3.3.png", + "images": [] + }, + "jbs": { + "icon": "https://community.chocolatey.org/content/packageimages/jbs.5.5.0.18.png", + "images": [] + }, + "jchemdotnetapi": { + "icon": "", + "images": [] + }, + "jcli": { + "icon": "", + "images": [] + }, + "jcliff": { + "icon": "", + "images": [] + }, + "jcpicker": { + "icon": "https://community.chocolatey.org/content/packageimages/jcpicker.5.7.png", + "images": [] + }, + "jcplayer": { + "icon": "", + "images": [] + }, + "jd": { + "icon": "", + "images": [] + }, + "jd-cli": { + "icon": "", + "images": [] + }, + "jd-gui": { + "icon": "", + "images": [] + }, + "jdk-17": { + "icon": "https://cdn-icons-png.flaticon.com/256/226/226777.png", + "images": [ + "https://www.oracle.com/a/pr/img/rc24-java-17.jpg" + ] + }, + "jdk-18": { + "icon": "https://cdn-icons-png.flaticon.com/256/226/226777.png", + "images": [ + "https://www.oracle.com/a/pr/img/rc24-java-18.jpg" + ] + }, + "jdk-19": { + "icon": "https://cdn-icons-png.flaticon.com/256/226/226777.png", + "images": [ + "https://www.oracle.com/a/pr/img/rc24-java-19.jpg" + ] + }, + "jdk-20": { + "icon": "https://cdn-icons-png.flaticon.com/256/226/226777.png", + "images": [ + "https://www.oracle.com/a/pr/img/rc24-java20.jpg" + ] + }, + "jdk-21": { + "icon": "https://cdn-icons-png.flaticon.com/256/226/226777.png", + "images": [ + "https://www.oracle.com/a/pr/img/rc24-java21.jpg" + ] + }, + "jdk-22": { + "icon": "https://cdn-icons-png.flaticon.com/256/226/226777.png", + "images": [ + "https://www.oracle.com/a/pr/img/rc24-java22.jpg" + ] + }, + "jdk-23": { + "icon": "https://cdn-icons-png.flaticon.com/256/226/226777.png", + "images": [ + "https://www.oracle.com/a/pr/img/rc24-java23.jpg" + ] + }, + "jdk-24": { + "icon": "https://cdn-icons-png.flaticon.com/256/226/226777.png", + "images": [ + "https://www.oracle.com/a/pr/img/rc24-java24.jpg" + ] + }, + "jdk-25": { + "icon": "https://cdn-icons-png.flaticon.com/256/226/226777.png", + "images": [ + "https://www.oracle.com/a/pr/img/rc24-java-25-release.jpg" + ] + }, + "jdminecraftlauncher": { + "icon": "", + "images": [] + }, + "jdnbtexplorer": { + "icon": "", + "images": [] + }, + "jdownloader": { + "icon": "https://jdownloader.org/_media/knowledge/wiki/jdownloader.png", + "images": [ + "https://i.postimg.cc/RCpz4nQY/IMG-20201015-161652.png", + "https://i.postimg.cc/8PWF8wdw/jdwonloader-4.png", + "https://i.postimg.cc/43Dchdgb/IMG-20201015-162417.png" + ] + }, + "jdtextedit": { + "icon": "", + "images": [] + }, + "jdtls": { + "icon": "", + "images": [] + }, + "jdupes": { + "icon": "", + "images": [] + }, + "jedit": { + "icon": "https://community.chocolatey.org/content/packageimages/jEdit.5.5.0.png", + "images": [] + }, + "jellyamp": { + "icon": "", + "images": [] + }, + "jellyfin-media-player": { + "icon": "", + "images": [] + }, + "jellyfin-mpv-shim": { + "icon": "", + "images": [] + }, + "jellyfin-server": { + "icon": "https://community.chocolatey.org/content/packageimages/jellyfin.10.7.7.png", + "images": [] + }, + "jellyfinmediaplayer": { + "icon": "", + "images": [] + }, + "jellyfinmpvshim": { + "icon": "", + "images": [] + }, + "jenkins": { + "icon": "https://community.chocolatey.org/content/packageimages/jenkins.2.222.4.png", + "images": [] + }, + "jenkins-lts": { + "icon": "", + "images": [] + }, + "jenkins-tray": { + "icon": "https://community.chocolatey.org/content/packageimages/jenkins-tray.1.0.5.0.png", + "images": [] + }, + "jenv": { + "icon": "", + "images": [] + }, + "jerrychess": { + "icon": "", + "images": [] + }, + "jetaudio": { + "icon": "", + "images": [] + }, + "jetaudio-basic": { + "icon": "", + "images": [] + }, + "jetbrains-hub": { + "icon": "", + "images": [] + }, + "jetbrains-license-server": { + "icon": "", + "images": [] + }, + "jetbrains-rider": { + "icon": "https://community.chocolatey.org/content/packageimages/jetbrains-rider.2022.3.2.png", + "images": [] + }, + "jetbrains-toolbox": { + "icon": "", + "images": [] + }, + "jetbrainsmono": { + "icon": "", + "images": [] + }, + "jetbrainstoolbox": { + "icon": "https://community.chocolatey.org/content/packageimages/jetbrainstoolbox.1.27.2.13801.png", + "images": [] + }, + "jetty": { + "icon": "https://community.chocolatey.org/content/packageimages/jetty.11.0.7.png", + "images": [] + }, + "jexiftoolgui": { + "icon": "", + "images": [] + }, + "jfrog": { + "icon": "", + "images": [] + }, + "jfrog-cli": { + "icon": "", + "images": [] + }, + "jfrog-cli-v2-jf": { + "icon": "", + "images": [] + }, + "jhead": { + "icon": "", + "images": [] + }, + "jhipster": { + "icon": "https://community.chocolatey.org/content/packageimages/jhipster.5.8.2.png", + "images": [] + }, + "jianyingpro": { + "icon": "", + "images": [] + }, + "jid": { + "icon": "", + "images": [] + }, + "jigdo": { + "icon": "https://community.chocolatey.org/content/packageimages/jigdo.0.8.0.png", + "images": [] + }, + "jigsaw": { + "icon": "", + "images": [] + }, + "jira": { + "icon": "", + "images": [] + }, + "jira-cli": { + "icon": "", + "images": [] + }, + "jiracli": { + "icon": "https://community.chocolatey.org/content/packageimages/JiraCli.1.1.0.png", + "images": [] + }, + "jirastopwatch": { + "icon": "", + "images": [] + }, + "jiratimers": { + "icon": "https://community.chocolatey.org/content/packageimages/jiratimers.0.9.4.png", + "images": [] + }, + "jisupdf": { + "icon": "", + "images": [] + }, + "jisupdfeditor": { + "icon": "", + "images": [] + }, + "jisupdftoword": { + "icon": "", + "images": [] + }, + "jisutodo": { + "icon": "", + "images": [] + }, + "jitsi": { + "icon": "", + "images": [] + }, + "jitsi-meet": { + "icon": "", + "images": [] + }, + "jivkok-autohotkey": { + "icon": "https://community.chocolatey.org/content/packageimages/jivkok.AutoHotKey.1.0.0.1.png", + "images": [] + }, + "jivkok-boxstarter1": { + "icon": "", + "images": [] + }, + "jivkok-dev1": { + "icon": "", + "images": [] + }, + "jivkok-gitconfig": { + "icon": "https://community.chocolatey.org/content/packageimages/jivkok.GitConfig.1.0.1.0.png", + "images": [] + }, + "jivkok-shell1": { + "icon": "", + "images": [] + }, + "jivkok-sublimetext3-packages": { + "icon": "https://community.chocolatey.org/content/packageimages/jivkok.SublimeText3.Packages.1.0.0.12.png", + "images": [] + }, + "jivkok-tools": { + "icon": "", + "images": [] + }, + "jivkok-vsextensions-2013": { + "icon": "", + "images": [] + }, + "jkrypto": { + "icon": "", + "images": [] + }, + "jmc": { + "icon": "", + "images": [] + }, + "jmeter": { + "icon": "", + "images": [] + }, + "jmeter-pm": { + "icon": "", + "images": [] + }, + "jmfb-com-import": { + "icon": "", + "images": [] + }, + "jmkvpropedit": { + "icon": "", + "images": [] + }, + "jmol": { + "icon": "https://community.chocolatey.org/content/packageimages/jmol.16.1.5.png", + "images": [] + }, + "jo": { + "icon": "", + "images": [] + }, + "joal-desktop": { + "icon": "https://community.chocolatey.org/content/packageimages/joal-desktop.2.0.16.png", + "images": [] + }, + "joe": { + "icon": "", + "images": [] + }, + "join-me": { + "icon": "https://community.chocolatey.org/content/packageimages/join.me.3.2.1.523301.png", + "images": [] + }, + "jojodiff": { + "icon": "", + "images": [] + }, + "jom": { + "icon": "", + "images": [] + }, + "joomla": { + "icon": "https://tweakers.net/ext/i/2004739054.png", + "images": [ + "https://tweakers.net/ext/i/1294820259.png" + ] + }, + "joplin": { + "icon": "https://community.chocolatey.org/content/packageimages/joplin.2.9.17.png", + "images": [] + }, + "joplin-pre-release": { + "icon": "", + "images": [] + }, + "jormungandr": { + "icon": "", + "images": [] + }, + "josm": { + "icon": "https://community.chocolatey.org/content/packageimages/josm.18646.0.png", + "images": [] + }, + "joystickgremlin": { + "icon": "", + "images": [] + }, + "joytokey": { + "icon": "https://community.chocolatey.org/content/packageimages/joytokey.6.9.1.png", + "images": [ + "https://i.postimg.cc/cLf5TDHR/image.png", + "https://i.postimg.cc/CLXWcB4g/image.png", + "https://i.postimg.cc/25fgfsJ9/image.png", + "https://i.postimg.cc/BvckZhfS/image.png", + "https://i.postimg.cc/4yMF2qV5/image.png" + ] + }, + "jp": { + "icon": "https://community.chocolatey.org/content/packageimages/jp.1.1.11.png", + "images": [] + }, + "jpass": { + "icon": "", + "images": [] + }, + "jpegoptim": { + "icon": "https://community.chocolatey.org/content/packageimages/jpegoptim.1.5.1.1.png", + "images": [] + }, + "jpegtran": { + "icon": "", + "images": [] + }, + "jpegview": { + "icon": "https://community.chocolatey.org/content/packageimages/jpegview.1.1.43.png", + "images": [ + "https://i.postimg.cc/MTLhgn8V/image.png", + "https://i.postimg.cc/VLPYNV3M/image.png", + "https://i.postimg.cc/vZ3M3HDL/image.png" + ] + }, + "jq": { + "icon": "https://community.chocolatey.org/content/packageimages/jq.1.6.png", + "images": [] + }, + "jqp": { + "icon": "", + "images": [] + }, + "jre8": { + "icon": "", + "images": [] + }, + "jregexanalyser": { + "icon": "https://community.chocolatey.org/content/packageimages/jregexanalyser.1.4.0.png", + "images": [] + }, + "jreleaser": { + "icon": "https://community.chocolatey.org/content/packageimages/jreleaser.1.5.0.png", + "images": [] + }, + "jruby": { + "icon": "https://community.chocolatey.org/content/packageimages/jruby.9.4.1.0.png", + "images": [] + }, + "jsdesign": { + "icon": "", + "images": [] + }, + "jsonprettyprint": { + "icon": "https://community.chocolatey.org/content/packageimages/JSONPrettyPrint.1.0.3.0.png", + "images": [] + }, + "jsshell": { + "icon": "https://community.chocolatey.org/content/packageimages/jsshell.86.0.png", + "images": [] + }, + "jstock": { + "icon": "https://community.chocolatey.org/content/packageimages/jstock.1.0.7.32.png", + "images": [] + }, + "jtalert": { + "icon": "https://community.chocolatey.org/content/packageimages/jtalert.2.60.5.png", + "images": [] + }, + "jtdx": { + "icon": "https://community.chocolatey.org/content/packageimages/jtdx.18.0.0.133.png", + "images": [] + }, + "jtdx-multimode": { + "icon": "https://community.chocolatey.org/content/packageimages/jtdx-multimode.2.2.159.png", + "images": [] + }, + "jtl-wawi": { + "icon": "", + "images": [] + }, + "jtrim": { + "icon": "", + "images": [] + }, + "jubler": { + "icon": "https://community.chocolatey.org/content/packageimages/jubler.7.0.0.png", + "images": [] + }, + "juce": { + "icon": "", + "images": [] + }, + "juffed": { + "icon": "https://community.chocolatey.org/content/packageimages/juffed.0.8.1.png", + "images": [] + }, + "juggernaut": { + "icon": "", + "images": [] + }, + "juice": { + "icon": "", + "images": [] + }, + "juju": { + "icon": "", + "images": [] + }, + "julia": { + "icon": "https://community.chocolatey.org/content/packageimages/Julia.1.8.5.png", + "images": [ + "https://i.imgur.com/d80DTBP.png" + ] + }, + "julia-lts": { + "icon": "", + "images": [] + }, + "jump-location": { + "icon": "", + "images": [] + }, + "jumpgobrowser-legacy": { + "icon": "", + "images": [] + }, + "jumplistexplorer": { + "icon": "", + "images": [] + }, + "jumplistlauncher": { + "icon": "", + "images": [] + }, + "jumpshare": { + "icon": "https://community.chocolatey.org/content/packageimages/jumpshare.2.0.10.png", + "images": [] + }, + "junction": { + "icon": "", + "images": [] + }, + "jupyterlab": { + "icon": "", + "images": [] + }, + "just": { + "icon": "https://community.chocolatey.org/content/packageimages/just.1.13.0.png", + "images": [] + }, + "just-install": { + "icon": "", + "images": [] + }, + "justread-chrome": { + "icon": "https://community.chocolatey.org/content/packageimages/justread-chrome.1.1.12.png", + "images": [] + }, + "jw-cad": { + "icon": "", + "images": [] + }, + "jwt-cli": { + "icon": "", + "images": [] + }, + "jwtdecode": { + "icon": "", + "images": [] + }, + "jwtinfo": { + "icon": "", + "images": [] + }, + "jx": { + "icon": "", + "images": [] + }, + "jxplorer": { + "icon": "https://community.chocolatey.org/content/packageimages/jxplorer.3.3.1.2.png", + "images": [] + }, + "k-litecodecpack-basic": { + "icon": "", + "images": [ + "https://www.leawo.org/entips/wp-content/uploads/2020/09/Windows-Media-Player-codec-04.png" + ] + }, + "k-litecodecpack-full": { + "icon": "", + "images": [ + "https://www.leawo.org/entips/wp-content/uploads/2020/09/Windows-Media-Player-codec-04.png" + ] + }, + "k-litecodecpack-mega": { + "icon": "", + "images": [ + "https://www.leawo.org/entips/wp-content/uploads/2020/09/Windows-Media-Player-codec-04.png" + ] + }, + "k-litecodecpack-standard": { + "icon": "", + "images": [ + "https://www.leawo.org/entips/wp-content/uploads/2020/09/Windows-Media-Player-codec-04.png" + ] + }, + "k-litecodecpackbasic": { + "icon": "https://community.chocolatey.org/content/packageimages/k-litecodecpackbasic.17.4.5.png", + "images": [] + }, + "k-litecodecpackfull": { + "icon": "https://community.chocolatey.org/content/packageimages/k-litecodecpackfull.17.4.5.png", + "images": [] + }, + "k-litecodecpackmega": { + "icon": "https://community.chocolatey.org/content/packageimages/k-litecodecpackmega.17.4.5.png", + "images": [] + }, + "k-meleon": { + "icon": "https://community.chocolatey.org/content/packageimages/k-meleon.portable.75.1.png", + "images": [] + }, + "k0s": { + "icon": "", + "images": [] + }, + "k0sctl": { + "icon": "", + "images": [] + }, + "k2tf": { + "icon": "", + "images": [] + }, + "k3d": { + "icon": "", + "images": [] + }, + "k3sup": { + "icon": "https://community.chocolatey.org/content/packageimages/k3sup.0.12.3.png", + "images": [] + }, + "k6": { + "icon": "https://community.chocolatey.org/content/packageimages/k6.0.43.1.png", + "images": [] + }, + "k9s": { + "icon": "https://community.chocolatey.org/content/packageimages/k9s.0.26.7.png", + "images": [] + }, + "kaf": { + "icon": "", + "images": [] + }, + "kaf-cli": { + "icon": "", + "images": [] + }, + "kaf-wifi": { + "icon": "", + "images": [] + }, + "kafaninput": { + "icon": "", + "images": [] + }, + "kafka": { + "icon": "", + "images": [] + }, + "kafka-exporter": { + "icon": "", + "images": [] + }, + "kafkaexplorer": { + "icon": "https://community.chocolatey.org/content/packageimages/kafkaexplorer.1.2.png", + "images": [] + }, + "kahla": { + "icon": "", + "images": [] + }, + "kakaotalk": { + "icon": "https://community.chocolatey.org/content/packageimages/kakaotalk.3.4.7.3369.png", + "images": [ + "https://t1.kakaocdn.net/kakaocorp/kakaocorp/admin/service/e9d4e476018e00001.png" + ] + }, + "kakaowork": { + "icon": "", + "images": [] + }, + "kaku": { + "icon": "", + "images": [] + }, + "kalilinux": { + "icon": "https://unigeticons.meowcat285.com/KaliLinux.png", + "images": [] + }, + "kalk": { + "icon": "", + "images": [] + }, + "kalker": { + "icon": "https://github.com/PaddiM8/kalker/blob/master/logo.png", + "images": [ + "https://github.com/PaddiM8/kalker/blob/master/preview.png" + ] + }, + "kamban": { + "icon": "", + "images": [] + }, + "kamel": { + "icon": "", + "images": [] + }, + "kanban-desktop": { + "icon": "", + "images": [] + }, + "kangaroo": { + "icon": "", + "images": [] + }, + "kantu-xmodules": { + "icon": "", + "images": [] + }, + "kapacitor": { + "icon": "", + "images": [] + }, + "kapow-punch-clock": { + "icon": "", + "images": [] + }, + "kapp": { + "icon": "https://community.chocolatey.org/content/packageimages/kapp.0.52.0.png", + "images": [] + }, + "kappo": { + "icon": "", + "images": [] + }, + "karaf": { + "icon": "", + "images": [] + }, + "karate": { + "icon": "", + "images": [] + }, + "kareemsultan-developer-toolkit-dotnet": { + "icon": "", + "images": [] + }, + "karensreplicator": { + "icon": "", + "images": [] + }, + "kate": { + "icon": "https://community.chocolatey.org/content/packageimages/kate.22.12.1.png", + "images": [ + "https://i.postimg.cc/sDCYwTg4/konsole.png" + ] + }, + "katmouse": { + "icon": "https://community.chocolatey.org/content/packageimages/KatMouse.1.7.png", + "images": [] + }, + "kav": { + "icon": "https://community.chocolatey.org/content/packageimages/kav.15.0.2.361.png", + "images": [] + }, + "kavita": { + "icon": "", + "images": [] + }, + "kawaii-player": { + "icon": "", + "images": [ + "https://zv915ylvcs.ufs.sh/f/fYIgEizARqiSG47vnNlXuI0GKjDFqPw9kgdCraEfzZe1lLOt", + "https://zv915ylvcs.ufs.sh/f/fYIgEizARqiSFQrW9cVtiaGEPnZIjVfXlJQO9vd1k64UbFDe" + ] + }, + "kawanime": { + "icon": "https://community.chocolatey.org/content/packageimages/kawanime.0.4.3.png", + "images": [] + }, + "kb2454826": { + "icon": "https://community.chocolatey.org/content/packageimages/KB2454826.1.0.4.png", + "images": [] + }, + "kb2519277": { + "icon": "https://community.chocolatey.org/content/packageimages/KB2519277.1.0.0.png", + "images": [] + }, + "kb2533552": { + "icon": "https://community.chocolatey.org/content/packageimages/KB2533552.1.0.4.png", + "images": [] + }, + "kb2670838": { + "icon": "https://community.chocolatey.org/content/packageimages/KB2670838.1.0.20181019.png", + "images": [] + }, + "kb2842230": { + "icon": "", + "images": [] + }, + "kb2882822": { + "icon": "https://community.chocolatey.org/content/packageimages/KB2882822.1.0.3.png", + "images": [] + }, + "kb2999226": { + "icon": "https://community.chocolatey.org/content/packageimages/KB2999226.1.0.20181019.png", + "images": [] + }, + "kb4019990": { + "icon": "https://community.chocolatey.org/content/packageimages/KB4019990.1.0.2.png", + "images": [] + }, + "kb4480955": { + "icon": "https://community.chocolatey.org/content/packageimages/kb4480955.1.0.png", + "images": [] + }, + "kb4554364": { + "icon": "https://community.chocolatey.org/content/packageimages/KB4554364.1.0.0.png", + "images": [] + }, + "kb4567512": { + "icon": "https://community.chocolatey.org/content/packageimages/KB4567512.1.0.0.png", + "images": [] + }, + "kb5001567": { + "icon": "https://community.chocolatey.org/content/packageimages/KB5001567.1.0.0.png", + "images": [] + }, + "kb5001649": { + "icon": "https://community.chocolatey.org/content/packageimages/KB5001649.1.0.0.png", + "images": [] + }, + "kb976932": { + "icon": "https://community.chocolatey.org/content/packageimages/KB976932.1.0.0.png", + "images": [] + }, + "kbld": { + "icon": "https://community.chocolatey.org/content/packageimages/kbld.0.35.0.png", + "images": [] + }, + "kcast": { + "icon": "https://community.chocolatey.org/content/packageimages/kcast.3.2.0.0.png", + "images": [] + }, + "kcc": { + "icon": "", + "images": [] + }, + "kcleaner": { + "icon": "https://community.chocolatey.org/content/packageimages/kcleaner.3.6.3.102.png", + "images": [] + }, + "kcptun": { + "icon": "", + "images": [] + }, + "kde-mover-sizer": { + "icon": "https://community.chocolatey.org/content/packageimages/kde-mover-sizer.2.9.png", + "images": [] + }, + "kdeconnect": { + "icon": "https://kdeconnect.kde.org/assets/img/KDE_Logo.png", + "images": [ + "https://cdn.kde.org/screenshots/kdeconnect/plasmoid.png", + "https://cdn.kde.org/screenshots/kdeconnect/kcm.png", + "https://cdn.kde.org/screenshots/kdeconnect/gnome3.png" + ] + }, + "kdeconnect-kde": { + "icon": "https://kdeconnect.kde.org/assets/img/KDE_Logo.png", + "images": [ + "https://cdn.kde.org/screenshots/kdeconnect/plasmoid.png", + "https://cdn.kde.org/screenshots/kdeconnect/kcm.png", + "https://cdn.kde.org/screenshots/kdeconnect/gnome3.png" + ] + }, + "kdenlive": { + "icon": "https://invent.kde.org/multimedia/kdenlive/-/raw/master/data/icons/256-apps-kdenlive.png", + "images": [ + "https://kdenlive.org/wp-content/uploads/2022/01/271174170_1089343691850009_6872343577648842521_n.png", + "https://kdenlive.org/wp-content/uploads/2022/01/photo_2021-12-13_15-36-56.jpg", + "https://kdenlive.org/wp-content/uploads/2022/05/photo_2022-05-28_01-11-01.jpg" + ] + }, + "kdevelop": { + "icon": "https://community.chocolatey.org/content/packageimages/kdevelop.install.5.5.0.png", + "images": [ + "https://cdn.kde.org/screenshots/kdevelop/kdevelop.png", + "https://kdevelop.org/images/kdevelop-code.png", + "https://kdevelop.org/images/kdevelop-documentation.png" + ] + }, + "kdiff3": { + "icon": "https://community.chocolatey.org/content/packageimages/kdiff3.0.9.98.20220330.png", + "images": [ + "https://cdn.kde.org/screenshots/kdiff3/diffscreen_two_way.png", + "https://cdn.kde.org/screenshots/kdiff3/ManualMerdge.png" + ] + }, + "kdoc-formatter": { + "icon": "", + "images": [] + }, + "kdocs": { + "icon": "", + "images": [] + }, + "keaasz": { + "icon": "", + "images": [] + }, + "kebler": { + "icon": "", + "images": [] + }, + "keboola-cli": { + "icon": "https://community.chocolatey.org/content/packageimages/keboola-cli.2.13.0.png", + "images": [] + }, + "keboolacli": { + "icon": "", + "images": [] + }, + "keenwrite": { + "icon": "", + "images": [] + }, + "keep-chrome": { + "icon": "https://community.chocolatey.org/content/packageimages/keep-chrome.3.1.16302.1110.png", + "images": [] + }, + "keepass": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/0/04/KeePass_icon.svg/2048px-KeePass_icon.svg.png", + "images": [ + "https://keepass.info/screenshots/keepass_2x/main_big.png" + ] + }, + "keepass-browser-importer": { + "icon": "https://community.chocolatey.org/content/packageimages/keepass-browser-importer.1.0.9.0.png", + "images": [] + }, + "keepass-classic": { + "icon": "", + "images": [] + }, + "keepass-classic-langfiles": { + "icon": "", + "images": [] + }, + "keepass-early-update-check": { + "icon": "https://community.chocolatey.org/content/packageimages/keepass-early-update-check.3.5.0.png", + "images": [] + }, + "keepass-exe-icon-picker": { + "icon": "https://community.chocolatey.org/content/packageimages/keepass-exe-icon-picker.1.2.0.0.png", + "images": [] + }, + "keepass-keepasshttp": { + "icon": "https://community.chocolatey.org/content/packageimages/keepass-keepasshttp.1.8.4.220170629.png", + "images": [] + }, + "keepass-kp-simple-database-backup": { + "icon": "https://community.chocolatey.org/content/packageimages/keepass-kp-simple-database-backup.1.4.0.0.png", + "images": [] + }, + "keepass-kpentrytemplates": { + "icon": "", + "images": [] + }, + "keepass-plugin-1p2kp": { + "icon": "https://community.chocolatey.org/content/packageimages/keepass-plugin-1p2kp.0.2.1.png", + "images": [] + }, + "keepass-plugin-autotypecustomfieldpicker": { + "icon": "", + "images": [] + }, + "keepass-plugin-autotypesearch": { + "icon": "", + "images": [] + }, + "keepass-plugin-autotypesplitter": { + "icon": "", + "images": [] + }, + "keepass-plugin-certkeyprovider": { + "icon": "https://community.chocolatey.org/content/packageimages/keepass-plugin-certkeyprovider.1.0.0.png", + "images": [] + }, + "keepass-plugin-cw3import": { + "icon": "https://community.chocolatey.org/content/packageimages/keepass-plugin-cw3import.2.10.png", + "images": [] + }, + "keepass-plugin-enhancedentryview": { + "icon": "", + "images": [] + }, + "keepass-plugin-favicon": { + "icon": "", + "images": [] + }, + "keepass-plugin-fieldsadminconsole": { + "icon": "", + "images": [] + }, + "keepass-plugin-gost": { + "icon": "", + "images": [] + }, + "keepass-plugin-haveibeenpwned": { + "icon": "", + "images": [] + }, + "keepass-plugin-hibpofflinecheck": { + "icon": "https://community.chocolatey.org/content/packageimages/keepass-plugin-hibpofflinecheck.1.7.9.png", + "images": [] + }, + "keepass-plugin-ioprotocolext": { + "icon": "", + "images": [] + }, + "keepass-plugin-itanmaster": { + "icon": "", + "images": [] + }, + "keepass-plugin-keeagent": { + "icon": "https://community.chocolatey.org/content/packageimages/keepass-plugin-keeagent.0.13.4.png", + "images": [] + }, + "keepass-plugin-keeanywhere": { + "icon": "https://community.chocolatey.org/content/packageimages/keepass-plugin-keeanywhere.2.0.3.png", + "images": [] + }, + "keepass-plugin-keechallenge": { + "icon": "", + "images": [] + }, + "keepass-plugin-keecloud": { + "icon": "https://community.chocolatey.org/content/packageimages/keepass-plugin-keecloud.1.2.0.3.png", + "images": [] + }, + "keepass-plugin-keeotp": { + "icon": "https://community.chocolatey.org/content/packageimages/keepass-plugin-keeotp.1.3.9.png", + "images": [] + }, + "keepass-plugin-keeotp2": { + "icon": "", + "images": [] + }, + "keepass-plugin-keepasshttp": { + "icon": "https://community.chocolatey.org/content/packageimages/keepass-plugin-keepasshttp.1.8.4.2.png", + "images": [] + }, + "keepass-plugin-keepassnatmsg": { + "icon": "", + "images": [] + }, + "keepass-plugin-keepassqrcodeview": { + "icon": "https://community.chocolatey.org/content/packageimages/keepass-plugin-keepassqrcodeview.1.1.0.png", + "images": [] + }, + "keepass-plugin-keepassrpc": { + "icon": "", + "images": [] + }, + "keepass-plugin-keetheme": { + "icon": "https://community.chocolatey.org/content/packageimages/keepass-plugin-keetheme.0.10.2.png", + "images": [] + }, + "keepass-plugin-keetraytotp": { + "icon": "", + "images": [] + }, + "keepass-plugin-kp2fachecker": { + "icon": "", + "images": [] + }, + "keepass-plugin-kpenhentryview": { + "icon": "", + "images": [] + }, + "keepass-plugin-kpfloatingpanel": { + "icon": "https://community.chocolatey.org/content/packageimages/keepass-plugin-kpfloatingpanel.7.5.png", + "images": [] + }, + "keepass-plugin-kpscript": { + "icon": "", + "images": [] + }, + "keepass-plugin-mskeyimporter": { + "icon": "", + "images": [] + }, + "keepass-plugin-osk": { + "icon": "", + "images": [] + }, + "keepass-plugin-otpkeyprov": { + "icon": "https://community.chocolatey.org/content/packageimages/keepass-plugin-otpkeyprov.2.6.png", + "images": [] + }, + "keepass-plugin-passwordchangereminder": { + "icon": "", + "images": [] + }, + "keepass-plugin-passwordcounter": { + "icon": "", + "images": [] + }, + "keepass-plugin-pickcharsdeferred": { + "icon": "", + "images": [] + }, + "keepass-plugin-qrcodegen": { + "icon": "https://community.chocolatey.org/content/packageimages/keepass-plugin-qrcodegen.2.0.12.png", + "images": [] + }, + "keepass-plugin-qualitycolumn": { + "icon": "", + "images": [] + }, + "keepass-plugin-qualityhighlighter": { + "icon": "", + "images": [] + }, + "keepass-plugin-quickunlock": { + "icon": "https://community.chocolatey.org/content/packageimages/keepass-plugin-quickunlock.2.4.png", + "images": [] + }, + "keepass-plugin-rdp": { + "icon": "", + "images": [] + }, + "keepass-plugin-readable-passphrase": { + "icon": "", + "images": [] + }, + "keepass-plugin-readablepassphrasegen": { + "icon": "", + "images": [] + }, + "keepass-plugin-rulebuilder": { + "icon": "", + "images": [] + }, + "keepass-plugin-sequencer": { + "icon": "", + "images": [] + }, + "keepass-plugin-spmimport": { + "icon": "", + "images": [] + }, + "keepass-plugin-trayrecent": { + "icon": "", + "images": [] + }, + "keepass-plugin-traytotp": { + "icon": "https://community.chocolatey.org/content/packageimages/keepass-plugin-traytotp.2.0.0.5.png", + "images": [] + }, + "keepass-plugin-truecryptmount": { + "icon": "https://community.chocolatey.org/content/packageimages/keepass-plugin-truecryptmount.2.3.png", + "images": [] + }, + "keepass-plugin-twofishcipher": { + "icon": "", + "images": [] + }, + "keepass-plugin-webautotype": { + "icon": "", + "images": [] + }, + "keepass-plugin-winkee": { + "icon": "", + "images": [] + }, + "keepass-plugin-yafd": { + "icon": "", + "images": [] + }, + "keepass-yet-another-favicon-downloader": { + "icon": "https://community.chocolatey.org/content/packageimages/keepass-yet-another-favicon-downloader.1.2.5.20230114.png", + "images": [] + }, + "keepassx": { + "icon": "https://community.chocolatey.org/content/packageimages/keepassx.2.0.3.png", + "images": [] + }, + "keepassx-langfiles": { + "icon": "", + "images": [] + }, + "keepassxc": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/c/c1/KeePassXC.svg/480px-KeePassXC.svg.png", + "images": [ + "https://upload.wikimedia.org/wikipedia/commons/1/1e/KeePassXC_main_men%C3%BA.png", + "https://keepassxc.org/images/screenshots/database_view.png", + "https://keepassxc.org/images/screenshots/edit_entry.png", + "https://keepassxc.org/images/screenshots/password_generator_advanced.png" + ] + }, + "keepassxc-legacy": { + "icon": "", + "images": [] + }, + "keeper": { + "icon": "https://community.chocolatey.org/content/packageimages/keeper.16.8.9.png", + "images": [] + }, + "keeperdesktop": { + "icon": "", + "images": [] + }, + "keesbaggerman-nutanix-script": { + "icon": "", + "images": [] + }, + "keeweb": { + "icon": "https://community.chocolatey.org/content/packageimages/keeweb.1.18.6.png", + "images": [] + }, + "kega-fusion": { + "icon": "https://community.chocolatey.org/content/packageimages/kega-fusion.3.64.png", + "images": [] + }, + "kekiri-tools": { + "icon": "", + "images": [] + }, + "kellyelton-devenvironment": { + "icon": "https://community.chocolatey.org/content/packageimages/kellyelton.devenvironment.1.0.0.11.png", + "images": [] + }, + "kellyelton-vsextensions": { + "icon": "https://community.chocolatey.org/content/packageimages/kellyelton.vsextensions.1.0.0.8.png", + "images": [] + }, + "kenku-fm": { + "icon": "", + "images": [] + }, + "kensingtonworks": { + "icon": "", + "images": [] + }, + "keptn-cli": { + "icon": "", + "images": [] + }, + "kernel-simulator-coreclr": { + "icon": "https://community.chocolatey.org/content/packageimages/kernel-simulator-coreclr.0.0.22.0.png", + "images": [] + }, + "ketarin": { + "icon": "https://community.chocolatey.org/content/packageimages/ketarin.1.8.11.png", + "images": [] + }, + "kexi": { + "icon": "", + "images": [] + }, + "key-n-stroke": { + "icon": "https://community.chocolatey.org/content/packageimages/key-n-stroke.1.1.0.1.png", + "images": [] + }, + "keybase": { + "icon": "", + "images": [] + }, + "keyboard-chatter-blocker": { + "icon": "", + "images": [] + }, + "keyboard-layout-creator": { + "icon": "https://community.chocolatey.org/content/packageimages/keyboard-layout-creator.1.4.png", + "images": [] + }, + "keyboardunchatter": { + "icon": "", + "images": [] + }, + "keybridge": { + "icon": "", + "images": [] + }, + "keycastow": { + "icon": "https://community.chocolatey.org/content/packageimages/keycastow.2.0.2.4.png", + "images": [] + }, + "keyferret": { + "icon": "https://community.chocolatey.org/content/packageimages/keyferret.install.2.6.png", + "images": [] + }, + "keyhub-cli": { + "icon": "https://community.chocolatey.org/content/packageimages/keyhub-cli.24.0.png", + "images": [] + }, + "keymanager": { + "icon": "", + "images": [] + }, + "keypirinha": { + "icon": "https://community.chocolatey.org/content/packageimages/keypirinha.2.26.png", + "images": [] + }, + "keypose": { + "icon": "", + "images": [] + }, + "keyprank": { + "icon": "", + "images": [] + }, + "keyremapper": { + "icon": "", + "images": [ + "https://i.postimg.cc/k4bvjz3q/keyremapper-remap-and-block.png" + ] + }, + "keystore-explorer": { + "icon": "", + "images": [] + }, + "keystoreexplorer": { + "icon": "https://i.postimg.cc/R0bXNPCp/image.png", + "images": [ + "https://i.postimg.cc/NfLSDrSH/image.png", + "https://i.postimg.cc/rFbbPw2Y/image.png", + "https://i.postimg.cc/sxx6Tt6r/image.png", + "https://i.postimg.cc/bY4W6vhV/image.png", + "https://i.postimg.cc/KvLVCycG/image.png" + ] + }, + "keytweak": { + "icon": "https://community.chocolatey.org/content/packageimages/keytweak.2.3.0.20200614.png", + "images": [] + }, + "keyviz": { + "icon": "", + "images": [] + }, + "kgmusic": { + "icon": "", + "images": [] + }, + "khoa-loadouts-dev": { + "icon": "", + "images": [] + }, + "kibana": { + "icon": "", + "images": [] + }, + "kicad": { + "icon": "https://community.chocolatey.org/content/packageimages/kicad.6.0.11.png", + "images": [] + }, + "kicad-lite": { + "icon": "", + "images": [] + }, + "kickassconsole": { + "icon": "https://community.chocolatey.org/content/packageimages/kickassconsole.0.1.9.png", + "images": [] + }, + "kickassvim": { + "icon": "https://community.chocolatey.org/content/packageimages/KickAssVim.7.4.0.00.png", + "images": [] + }, + "kid3": { + "icon": "https://community.chocolatey.org/content/packageimages/kid3.3.9.3.png", + "images": [] + }, + "kiki-re": { + "icon": "", + "images": [] + }, + "kile": { + "icon": "https://community.chocolatey.org/content/packageimages/Kile.2.9.93.png", + "images": [] + }, + "kill-frozen-programs": { + "icon": "", + "images": [] + }, + "killprocess": { + "icon": "", + "images": [] + }, + "kim": { + "icon": "", + "images": [] + }, + "kind": { + "icon": "https://community.chocolatey.org/content/packageimages/kind.0.17.0.png", + "images": [] + }, + "kindle": { + "icon": "https://hips.hearstapps.com/hmg-prod.s3.amazonaws.com/images/kindle-logo-1571758206.png", + "images": [ + "https://m.media-amazon.com/images/G/01/kindle/journeys/37DxD9LI0o5SlfZ3/ODFhOGNkZjYt-w1200._CB608601343_.jpg", + "https://www.online-tech-tips.com/wp-content/uploads/2020/04/Kindle-Desktop-Book-Collection.png", + "https://cdn.mos.cms.futurecdn.net/Kc9Y7v9vqdt2k237jfQHnD.jpg", + "https://www.thewindowsclub.com/wp-content/uploads/2018/03/Download-600x369.png", + "https://i.pcmag.com/imagery/articles/00cjVMgipjFlAHptWfw1bmm-6.fit_lim.size_1050x.png" + ] + }, + "kindlepreviewer": { + "icon": "https://community.chocolatey.org/content/packageimages/kindlepreviewer.3.52.png", + "images": [] + }, + "kingdraw": { + "icon": "", + "images": [] + }, + "kingsoft-office-free": { + "icon": "https://community.chocolatey.org/content/packageimages/kingsoft-office-free.9.1.0.20140820.png", + "images": [] + }, + "kingsoftpdf": { + "icon": "", + "images": [] + }, + "kingston-ssd-manager": { + "icon": "", + "images": [] + }, + "kino-rendezvous-service": { + "icon": "https://community.chocolatey.org/content/packageimages/kino-rendezvous-service.0.0.1.27.png", + "images": [] + }, + "kinovea": { + "icon": "https://community.chocolatey.org/content/packageimages/kinovea.0.9.5.png", + "images": [] + }, + "kirkajs": { + "icon": "https://client.kirka.io/images/icon.png", + "images": [] + }, + "kis": { + "icon": "https://community.chocolatey.org/content/packageimages/kis.22.8.4.0.png", + "images": [] + }, + "kitematic": { + "icon": "", + "images": [] + }, + "kitty": { + "icon": "https://i.postimg.cc/NjSwt9n8/kitty-icon.png", + "images": [ + "https://i.postimg.cc/bvnfwYX7/kitty-1.png" + ] + }, + "kiwi-for-gmail": { + "icon": "", + "images": [] + }, + "kiwix": { + "icon": "", + "images": [] + }, + "kiwixjs": { + "icon": "", + "images": [] + }, + "kiwixjs-electron": { + "icon": "", + "images": [] + }, + "kkbox": { + "icon": "https://community.chocolatey.org/content/packageimages/KKBOX.7.2.52.png", + "images": [] + }, + "kkrieger": { + "icon": "https://community.chocolatey.org/content/packageimages/kkrieger.2004.04.png", + "images": [] + }, + "klatexformula": { + "icon": "https://community.chocolatey.org/content/packageimages/klatexformula.4.1.0.20210227.png", + "images": [] + }, + "klavaro": { + "icon": "https://i.postimg.cc/2yp3v5nk/image.png", + "images": [ + "https://i.postimg.cc/NFyL2Hyc/image.png", + "https://i.postimg.cc/15qf9DhB/image.png", + "https://i.postimg.cc/xCZ1Q16N/image.png", + "https://i.postimg.cc/h4J9dzRv/image.png", + "https://i.postimg.cc/fbTdTkfp/image.png", + "https://i.postimg.cc/W3xqn8cv/image.png" + ] + }, + "klayout": { + "icon": "https://community.chocolatey.org/content/packageimages/klayout.0.28.5.png", + "images": [] + }, + "klog": { + "icon": "https://community.chocolatey.org/content/packageimages/klog.2.3.png", + "images": [] + }, + "klogg": { + "icon": "https://community.chocolatey.org/content/packageimages/klogg.22.06.0.1289.png", + "images": [] + }, + "kmdf": { + "icon": "https://community.chocolatey.org/content/packageimages/KMDF.1.11.png", + "images": [] + }, + "kmt": { + "icon": "https://community.chocolatey.org/content/packageimages/kmt.9.2.4.png", + "images": [] + }, + "kmttg": { + "icon": "", + "images": [] + }, + "kmupd": { + "icon": "https://community.chocolatey.org/content/packageimages/kmupd.3.9.303.0.png", + "images": [] + }, + "kmymoney": { + "icon": "https://i.postimg.cc/BQbVh7Vt/kmymoney-icon.png", + "images": [ + "https://i.postimg.cc/gk7B1yCs/kmymoney.png", + "https://i.postimg.cc/rm9PHBTR/kmm2.png", + "https://i.postimg.cc/44B0QRwr/kmm3.png" + ] + }, + "knative": { + "icon": "", + "images": [] + }, + "knime": { + "icon": "https://community.chocolatey.org/content/packageimages/knime.install.4.6.0.png", + "images": [] + }, + "knotes": { + "icon": "", + "images": [] + }, + "knowte": { + "icon": "", + "images": [] + }, + "kobito": { + "icon": "", + "images": [] + }, + "kobo": { + "icon": "https://play-lh.googleusercontent.com/gWAccZO7a9JX1u7jzeu4LpxuOlVlpdzt4Z6vkqwpp4ankRCqQZgt7WEfD4czLXVvtzk=w240-h480", + "images": [] + }, + "kodi": { + "icon": "https://i.postimg.cc/2yyqfsLK/icon.png", + "images": [ + "https://i.postimg.cc/Y94cdr5z/1.png", + "https://i.postimg.cc/gcZFR0qY/2.png", + "https://i.postimg.cc/Z5j1ZvZL/3.png", + "https://i.postimg.cc/wTYKkd0D/4.png", + "https://i.postimg.cc/0y9LL0gQ/5.png", + "https://i.postimg.cc/RhfkzPV3/6.png", + "https://i.postimg.cc/CK19KMxp/7.png", + "https://i.postimg.cc/BQTrYwVk/8.png" + ] + }, + "kodos": { + "icon": "https://community.chocolatey.org/content/packageimages/kodos.2.4.9.png", + "images": [] + }, + "kodugamelab": { + "icon": "", + "images": [] + }, + "koffee": { + "icon": "", + "images": [] + }, + "komac": { + "icon": "https://i.postimg.cc/9fS786Qr/komac-logo.png", + "images": [] + }, + "kombustor-2": { + "icon": "", + "images": [ + "https://i.postimg.cc/nLT0thRF/image.png" + ] + }, + "kombustor-3": { + "icon": "", + "images": [ + "https://i.postimg.cc/nLT0thRF/image.png", + "https://i.postimg.cc/x8NRHy08/image.png", + "https://i.postimg.cc/056RZTjM/image.png", + "https://i.postimg.cc/52Vh4j3L/image.png", + "https://i.postimg.cc/8Ckxv3xC/image.png", + "https://i.postimg.cc/0Qb3WSkR/image.png" + ] + }, + "kombustor-4": { + "icon": "", + "images": [ + "https://i.postimg.cc/nLT0thRF/image.png", + "https://i.postimg.cc/x8NRHy08/image.png", + "https://i.postimg.cc/056RZTjM/image.png", + "https://i.postimg.cc/52Vh4j3L/image.png", + "https://i.postimg.cc/8Ckxv3xC/image.png", + "https://i.postimg.cc/0Qb3WSkR/image.png" + ] + }, + "komga": { + "icon": "", + "images": [] + }, + "komodo-edit": { + "icon": "https://community.chocolatey.org/content/packageimages/komodo-edit.12.0.1.png", + "images": [] + }, + "komodo-ide": { + "icon": "https://community.chocolatey.org/content/packageimages/komodo-ide.12.0.1.png", + "images": [] + }, + "komodoedit": { + "icon": "https://cdn.activestate.com/wp-content/uploads/2018/10/komodo-ide-icon-512x512.png", + "images": [ + "https://cdn.activestate.com/wp-content/uploads/2018/10/edit-vs-ide.png" + ] + }, + "komodoide": { + "icon": "https://cdn.activestate.com/wp-content/uploads/2018/10/komodo-ide-icon-512x512.png", + "images": [ + "https://cdn.activestate.com/wp-content/uploads/2020/01/komodo-activestate-platform-integration-500x250.png", + "https://cdn.activestate.com/wp-content/uploads/2018/09/codeintel-500x250.png", + "https://cdn.activestate.com/wp-content/uploads/2018/09/devdocs-500x250.png", + "https://cdn.activestate.com/wp-content/uploads/2018/09/preview.gif" + ] + }, + "komokana": { + "icon": "", + "images": [] + }, + "komorebi": { + "icon": "", + "images": [] + }, + "kompose": { + "icon": "", + "images": [] + }, + "kondo": { + "icon": "", + "images": [] + }, + "kontur-addtotrusted": { + "icon": "", + "images": [] + }, + "kontur-certificates": { + "icon": "", + "images": [] + }, + "kontur-diag": { + "icon": "", + "images": [] + }, + "kontur-plugin": { + "icon": "", + "images": [] + }, + "koodo-reader": { + "icon": "https://community.chocolatey.org/content/packageimages/koodo-reader.1.5.2.png", + "images": [] + }, + "koodoreader": { + "icon": "", + "images": [] + }, + "kook": { + "icon": "https://saas.bk-cdn.com/1666170194529-KOOKLOGO.png", + "images": [ + "https://saas.bk-cdn.com/t/901342ff-5949-41f1-b992-6101f871f04e/u/97b9cb94-fb1b-40f1-96fb-4d81eb1097e5/1656493066531/image.png" + ] + }, + "kopano-ads-nightly": { + "icon": "https://community.chocolatey.org/content/packageimages/kopano-ads-nightly.1.1.88.png", + "images": [] + }, + "kopia": { + "icon": "", + "images": [] + }, + "kopiaui": { + "icon": "", + "images": [] + }, + "kops": { + "icon": "", + "images": [] + }, + "koruri": { + "icon": "https://community.chocolatey.org/content/packageimages/koruri.2014.09.04.png", + "images": [] + }, + "kotatogram": { + "icon": "", + "images": [] + }, + "kotlin": { + "icon": "", + "images": [] + }, + "kotlin-native": { + "icon": "", + "images": [] + }, + "kptransfer": { + "icon": "https://community.chocolatey.org/content/packageimages/kptransfer.3.0.0.png", + "images": [] + }, + "krew": { + "icon": "", + "images": [] + }, + "krisp": { + "icon": "", + "images": [] + }, + "krita": { + "icon": "https://i.imgur.com/ZIpIzyq.png", + "images": [ + "https://i.postimg.cc/52xMNS7V/Krita.png" + ] + }, + "kritashellextension": { + "icon": "", + "images": [] + }, + "krunkerclient": { + "icon": "", + "images": [] + }, + "krypton-cli": { + "icon": "", + "images": [] + }, + "kryptor": { + "icon": "https://community.chocolatey.org/content/packageimages/kryptor.4.0.1.png", + "images": [] + }, + "ks": { + "icon": "https://community.chocolatey.org/content/packageimages/KS.0.0.24.4.png", + "images": [] + }, + "ks-net": { + "icon": "https://community.chocolatey.org/content/packageimages/KS.NET.0.0.22.0.png", + "images": [] + }, + "kscript": { + "icon": "", + "images": [] + }, + "ksnip": { + "icon": "https://community.chocolatey.org/content/packageimages/ksnip.install.1.10.0.png", + "images": [] + }, + "ksp-ckan": { + "icon": "https://community.chocolatey.org/content/packageimages/ksp-ckan.1.31.2.png", + "images": [] + }, + "ksp-client": { + "icon": "https://community.chocolatey.org/content/packageimages/ksp-client.7.9.0.4.png", + "images": [] + }, + "kstars": { + "icon": "", + "images": [] + }, + "ktlint": { + "icon": "", + "images": [] + }, + "ktunnel": { + "icon": "", + "images": [] + }, + "ktx-software": { + "icon": "", + "images": [] + }, + "kube-forwarder": { + "icon": "", + "images": [] + }, + "kube-linter": { + "icon": "", + "images": [] + }, + "kube2pulumi": { + "icon": "", + "images": [] + }, + "kubeadm": { + "icon": "", + "images": [] + }, + "kubebox": { + "icon": "", + "images": [] + }, + "kubeconform": { + "icon": "", + "images": [] + }, + "kubectl": { + "icon": "", + "images": [] + }, + "kubectx": { + "icon": "", + "images": [] + }, + "kubedevdashboard": { + "icon": "", + "images": [] + }, + "kubefwd": { + "icon": "", + "images": [] + }, + "kubeless": { + "icon": "https://community.chocolatey.org/content/packageimages/kubeless.1.0.8.png", + "images": [] + }, + "kubelet": { + "icon": "", + "images": [] + }, + "kubelogin": { + "icon": "", + "images": [] + }, + "kubens": { + "icon": "", + "images": [] + }, + "kubent": { + "icon": "", + "images": [] + }, + "kubernetes-cli": { + "icon": "https://community.chocolatey.org/content/packageimages/kubernetes-cli.1.26.1.png", + "images": [] + }, + "kubernetes-helm": { + "icon": "https://community.chocolatey.org/content/packageimages/kubernetes-helm.3.11.1.png", + "images": [] + }, + "kubernetes-helmfile": { + "icon": "", + "images": [] + }, + "kubernetes-kompose": { + "icon": "https://community.chocolatey.org/content/packageimages/kubernetes-kompose.1.28.0.png", + "images": [] + }, + "kubescape": { + "icon": "", + "images": [] + }, + "kubeseal": { + "icon": "", + "images": [] + }, + "kubeval": { + "icon": "", + "images": [] + }, + "kubo": { + "icon": "", + "images": [] + }, + "kui": { + "icon": "https://community.chocolatey.org/content/packageimages/kui.13.1.1.png", + "images": [] + }, + "kurvenprofi": { + "icon": "", + "images": [] + }, + "kustomize": { + "icon": "https://community.chocolatey.org/content/packageimages/kustomize.4.5.5.png", + "images": [] + }, + "kyma-cli": { + "icon": "https://community.chocolatey.org/content/packageimages/kyma-cli.2.11.0.png", + "images": [] + }, + "kyverno-cli": { + "icon": "", + "images": [] + }, + "kzip": { + "icon": "", + "images": [] + }, + "l0phtcrack": { + "icon": "", + "images": [] + }, + "lab": { + "icon": "", + "images": [] + }, + "labadvisor": { + "icon": "https://img.informer.com/icons/png/128/3924/3924343.png", + "images": [ + "https://www.agilent.com/cs/publishingimages/LabAdvisor_Main_Screen_zoomtb.jpg", + "https://www.agilent.com/cs/publishingimages/LabAdvisor_Apps_Screen_zoomtb.jpg", + "https://www.agilent.com/cs/publishingimages/LabAdvisor_Configuration_Screen_zoomtb.jpg", + "https://www.agilent.com/cs/publishingimages/LabAdvisor_Data_Sharing_Screen_zoomtb.jpg", + "https://www.agilent.com/cs/publishingimages/LabAdvisor_Instrument_Control_Screen_zoomtb.jpg", + "https://www.agilent.com/cs/publishingimages/LabAdvisor_Logs_and_Results_Screen_zoomtb.jpg" + ] + }, + "labplot": { + "icon": "", + "images": [] + }, + "lacework-cli": { + "icon": "https://community.chocolatey.org/content/packageimages/lacework-cli.1.11.1.png", + "images": [] + }, + "lacey": { + "icon": "https://community.chocolatey.org/content/packageimages/lacey.portable.2.82.png", + "images": [] + }, + "lagrange": { + "icon": "", + "images": [] + }, + "laihuavideo": { + "icon": "", + "images": [] + }, + "lame": { + "icon": "https://community.chocolatey.org/content/packageimages/lame.3.100.20200409.png", + "images": [] + }, + "lamexp": { + "icon": "https://community.chocolatey.org/content/packageimages/lamexp.4.19.png", + "images": [] + }, + "lammercontextmenu": { + "icon": "https://community.chocolatey.org/content/packageimages/lammercontextmenu.1.0.3.1901.png", + "images": [] + }, + "lammps": { + "icon": "", + "images": [] + }, + "lammps-ml-pace": { + "icon": "", + "images": [] + }, + "lammps-user-aeam": { + "icon": "", + "images": [] + }, + "lammps-user-rebomos": { + "icon": "", + "images": [] + }, + "lammps-user-vcsgc": { + "icon": "", + "images": [] + }, + "lan-messenger": { + "icon": "https://community.chocolatey.org/content/packageimages/lan-messenger.portable.1.2.37.png", + "images": [] + }, + "lan-speed-test": { + "icon": "", + "images": [] + }, + "lan-speed-test-lite": { + "icon": "", + "images": [] + }, + "lan-speed-test-registered": { + "icon": "", + "images": [] + }, + "lanbench": { + "icon": "https://community.chocolatey.org/content/packageimages/lanbench.1.1.0.20180725.png", + "images": [] + }, + "lanconfig": { + "icon": "https://community.chocolatey.org/content/packageimages/lanconfig.10.72.12.png", + "images": [] + }, + "landrop": { + "icon": "", + "images": [ + "https://i.postimg.cc/QxPB4C8d/image.png" + ] + }, + "languagetool": { + "icon": "https://community.chocolatey.org/content/packageimages/languagetool.6.0.png", + "images": [] + }, + "languagetool-java": { + "icon": "", + "images": [] + }, + "lanhu-photoshop": { + "icon": "", + "images": [] + }, + "lanmessenger": { + "icon": "", + "images": [] + }, + "lanmonitor": { + "icon": "https://community.chocolatey.org/content/packageimages/lanmonitor.10.72.7.png", + "images": [] + }, + "lanservice": { + "icon": "", + "images": [] + }, + "lansweeper": { + "icon": "https://community.chocolatey.org/content/packageimages/lansweeper.10.4.0.2.png", + "images": [] + }, + "lantern-client": { + "icon": "", + "images": [] + }, + "lanxchange": { + "icon": "https://community.chocolatey.org/content/packageimages/lanxchange.1.41.png", + "images": [] + }, + "lapce": { + "icon": "https://community.chocolatey.org/content/packageimages/lapce.0.2.5.png", + "images": [] + }, + "laps": { + "icon": "https://community.chocolatey.org/content/packageimages/laps.6.2.0.20210510.png", + "images": [] + }, + "laragon": { + "icon": "https://community.chocolatey.org/content/packageimages/laragon.portable.4.0.15.png", + "images": [] + }, + "largh": { + "icon": "https://community.chocolatey.org/content/packageimages/largh.0.1.png", + "images": [] + }, + "lark": { + "icon": "", + "images": [] + }, + "laserbox": { + "icon": "", + "images": [] + }, + "laserbox-basic": { + "icon": "", + "images": [] + }, + "laserbox-mcreate": { + "icon": "", + "images": [] + }, + "last-hit": { + "icon": "", + "images": [] + }, + "lastactivityview": { + "icon": "https://i.postimg.cc/QMLzSNLy/image.png", + "images": [ + "https://i.postimg.cc/vBbNFPZz/image.png" + ] + }, + "lastfmdesktopscrobbler": { + "icon": "", + "images": [] + }, + "lastpass": { + "icon": "", + "images": [] + }, + "lastpass-chrome": { + "icon": "https://community.chocolatey.org/content/packageimages/lastpass-chrome.4.3.0.png", + "images": [] + }, + "latencymon": { + "icon": "https://community.chocolatey.org/content/packageimages/latencymon.7.20.png", + "images": [] + }, + "latex": { + "icon": "", + "images": [] + }, + "latexdaemon": { + "icon": "", + "images": [] + }, + "latexdraw": { + "icon": "https://community.chocolatey.org/content/packageimages/latexdraw.4.0.3.png", + "images": [] + }, + "latexindent": { + "icon": "", + "images": [] + }, + "latexml": { + "icon": "https://community.chocolatey.org/content/packageimages/latexml.0.8.5.png", + "images": [] + }, + "latin-modern-fonts": { + "icon": "", + "images": [] + }, + "lato": { + "icon": "", + "images": [] + }, + "launch": { + "icon": "https://community.chocolatey.org/content/packageimages/launch.1.15.png", + "images": [] + }, + "launch4j": { + "icon": "", + "images": [] + }, + "launchbox": { + "icon": "https://community.chocolatey.org/content/packageimages/launchbox.4.1.png", + "images": [] + }, + "launcher": { + "icon": "https://i.ibb.co/PZ4CGyXW/rockstar-games-1536-433540335.png", + "images": [] + }, + "launchy": { + "icon": "https://community.chocolatey.org/content/packageimages/launchy.2.5.0.20220923.png", + "images": [] + }, + "lavape": { + "icon": "", + "images": [] + }, + "lavfilters": { + "icon": "https://community.chocolatey.org/content/packageimages/lavfilters.0.77.1.png", + "images": [] + }, + "layer0": { + "icon": "", + "images": [] + }, + "lazarus": { + "icon": "https://community.chocolatey.org/content/packageimages/lazarus.2.2.2.png", + "images": [] + }, + "lazesoftrecovery": { + "icon": "", + "images": [] + }, + "lazpaint": { + "icon": "", + "images": [] + }, + "lazy-posh-git": { + "icon": "", + "images": [] + }, + "lazydocker": { + "icon": "", + "images": [] + }, + "lazygit": { + "icon": "https://community.chocolatey.org/content/packageimages/lazygit.0.37.0.png", + "images": [] + }, + "lazytype": { + "icon": "", + "images": [] + }, + "lbry": { + "icon": "https://community.chocolatey.org/content/packageimages/lbry.0.53.9.png", + "images": [] + }, + "lceda": { + "icon": "", + "images": [] + }, + "lcov": { + "icon": "", + "images": [] + }, + "ldap-admin": { + "icon": "", + "images": [] + }, + "ldapadmin": { + "icon": "https://community.chocolatey.org/content/packageimages/ldapadmin.1.8.3.png", + "images": [] + }, + "ldapbrowser": { + "icon": "", + "images": [] + }, + "ldc": { + "icon": "https://community.chocolatey.org/content/packageimages/ldc.1.31.0.png", + "images": [] + }, + "ldmdump": { + "icon": "", + "images": [] + }, + "ldplayer": { + "icon": "", + "images": [] + }, + "ldtk": { + "icon": "https://community.chocolatey.org/content/packageimages/ldtk.1.2.4.png", + "images": [] + }, + "leafview": { + "icon": "", + "images": [] + }, + "leafview-tauri": { + "icon": "", + "images": [] + }, + "leagueoflegends": { + "icon": "", + "images": [] + }, + "leagueoflegends-br": { + "icon": "", + "images": [] + }, + "leagueoflegends-eune": { + "icon": "", + "images": [] + }, + "leagueoflegends-euw": { + "icon": "", + "images": [] + }, + "leagueoflegends-la1": { + "icon": "", + "images": [] + }, + "leagueoflegends-la2": { + "icon": "", + "images": [] + }, + "leagueoflegends-na": { + "icon": "", + "images": [] + }, + "leagueoflegends-oc1": { + "icon": "", + "images": [] + }, + "leagueoflegends-pbe": { + "icon": "", + "images": [] + }, + "leagueoflegendseune": { + "icon": "", + "images": [] + }, + "leagueoflegendseuw": { + "icon": "https://community.chocolatey.org/content/packageimages/leagueoflegendseuw.1.0.1.0.png", + "images": [] + }, + "lean": { + "icon": "", + "images": [] + }, + "lean-cli": { + "icon": "", + "images": [] + }, + "leanify": { + "icon": "", + "images": [] + }, + "leappstore": { + "icon": "", + "images": [] + }, + "lecloud": { + "icon": "", + "images": [] + }, + "lecmd": { + "icon": "", + "images": [] + }, + "lector": { + "icon": "", + "images": [] + }, + "ledger-live": { + "icon": "https://community.chocolatey.org/content/packageimages/ledger-live.2.51.0.png", + "images": [] + }, + "ledgerlive": { + "icon": "", + "images": [] + }, + "leechcraft": { + "icon": "", + "images": [] + }, + "leet": { + "icon": "", + "images": [] + }, + "legendary": { + "icon": "", + "images": [] + }, + "legionaccessorycentral": { + "icon": "", + "images": [] + }, + "legit": { + "icon": "", + "images": [] + }, + "legitest": { + "icon": "", + "images": [] + }, + "lego": { + "icon": "", + "images": [] + }, + "lein": { + "icon": "https://community.chocolatey.org/content/packageimages/Lein.2.10.0.png", + "images": [] + }, + "leiningen": { + "icon": "", + "images": [] + }, + "lektor": { + "icon": "https://community.chocolatey.org/content/packageimages/lektor.3.2.0.png", + "images": [] + }, + "lemminx": { + "icon": "", + "images": [] + }, + "lenovo-s145-touchpad-fix": { + "icon": "", + "images": [] + }, + "lenovolegiontoolkit": { + "icon": "", + "images": [] + }, + "lens": { + "icon": "https://community.chocolatey.org/content/packageimages/lens.2023.1.110749.png", + "images": [] + }, + "leocad": { + "icon": "", + "images": [] + }, + "leonflix": { + "icon": "https://community.chocolatey.org/content/packageimages/leonflix.0.7.0.png", + "images": [] + }, + "lepton": { + "icon": "https://community.chocolatey.org/content/packageimages/lepton.1.10.0.png", + "images": [] + }, + "less": { + "icon": "", + "images": [] + }, + "lessmsi": { + "icon": "https://community.chocolatey.org/content/packageimages/lessmsi.1.10.0.png", + "images": [] + }, + "letsconnectclient": { + "icon": "", + "images": [] + }, + "lettura": { + "icon": "", + "images": [] + }, + "leveret": { + "icon": "", + "images": [] + }, + "lexibar-el": { + "icon": "", + "images": [] + }, + "lexibar-es": { + "icon": "", + "images": [] + }, + "lexibar-fr": { + "icon": "", + "images": [] + }, + "lexibar-ru": { + "icon": "", + "images": [] + }, + "lf": { + "icon": "", + "images": [] + }, + "lftp": { + "icon": "https://community.chocolatey.org/content/packageimages/lftp.4.9.2.20210924.png", + "images": [] + }, + "lgs": { + "icon": "", + "images": [] + }, + "lha": { + "icon": "", + "images": [] + }, + "lhaplus": { + "icon": "", + "images": [] + }, + "libavif": { + "icon": "", + "images": [] + }, + "libdvdcss-2": { + "icon": "", + "images": [] + }, + "liberationfonts": { + "icon": "https://community.chocolatey.org/content/packageimages/liberationfonts.2.1.5.20211119.png", + "images": [] + }, + "liberica11jdk": { + "icon": "", + "images": [] + }, + "liberica11jdkfull": { + "icon": "", + "images": [] + }, + "liberica11jre": { + "icon": "", + "images": [] + }, + "liberica11jrefull": { + "icon": "", + "images": [] + }, + "liberica17jdkfull": { + "icon": "", + "images": [] + }, + "liberica8jdk": { + "icon": "", + "images": [] + }, + "liberica8jre": { + "icon": "", + "images": [] + }, + "libericajdk": { + "icon": "", + "images": [] + }, + "libericajdk-11": { + "icon": "https://www.sokrat.ru/upload/medialibrary/9b5/Bellsoft_logo.png", + "images": [] + }, + "libericajdk-11-full": { + "icon": "https://www.sokrat.ru/upload/medialibrary/9b5/Bellsoft_logo.png", + "images": [] + }, + "libericajdk-14": { + "icon": "https://www.sokrat.ru/upload/medialibrary/9b5/Bellsoft_logo.png", + "images": [] + }, + "libericajdk-14-full": { + "icon": "https://www.sokrat.ru/upload/medialibrary/9b5/Bellsoft_logo.png", + "images": [] + }, + "libericajdk-15": { + "icon": "https://www.sokrat.ru/upload/medialibrary/9b5/Bellsoft_logo.png", + "images": [] + }, + "libericajdk-15-full": { + "icon": "https://www.sokrat.ru/upload/medialibrary/9b5/Bellsoft_logo.png", + "images": [] + }, + "libericajdk-16": { + "icon": "https://www.sokrat.ru/upload/medialibrary/9b5/Bellsoft_logo.png", + "images": [] + }, + "libericajdk-16-full": { + "icon": "https://www.sokrat.ru/upload/medialibrary/9b5/Bellsoft_logo.png", + "images": [] + }, + "libericajdk-17": { + "icon": "https://www.sokrat.ru/upload/medialibrary/9b5/Bellsoft_logo.png", + "images": [] + }, + "libericajdk-17-full": { + "icon": "https://www.sokrat.ru/upload/medialibrary/9b5/Bellsoft_logo.png", + "images": [] + }, + "libericajdk-18": { + "icon": "https://www.sokrat.ru/upload/medialibrary/9b5/Bellsoft_logo.png", + "images": [] + }, + "libericajdk-18-full": { + "icon": "https://www.sokrat.ru/upload/medialibrary/9b5/Bellsoft_logo.png", + "images": [] + }, + "libericajdk-19": { + "icon": "https://www.sokrat.ru/upload/medialibrary/9b5/Bellsoft_logo.png", + "images": [] + }, + "libericajdk-19-full": { + "icon": "https://www.sokrat.ru/upload/medialibrary/9b5/Bellsoft_logo.png", + "images": [] + }, + "libericajdk-8": { + "icon": "https://www.sokrat.ru/upload/medialibrary/9b5/Bellsoft_logo.png", + "images": [] + }, + "libericajdk-8-full": { + "icon": "https://www.sokrat.ru/upload/medialibrary/9b5/Bellsoft_logo.png", + "images": [] + }, + "libericajdkfull": { + "icon": "", + "images": [] + }, + "libericajdklite": { + "icon": "", + "images": [] + }, + "libericajre": { + "icon": "", + "images": [] + }, + "libericajrefull": { + "icon": "", + "images": [] + }, + "libgen-desktop": { + "icon": "", + "images": [] + }, + "libgendesktop": { + "icon": "", + "images": [] + }, + "libjpeg-turbo": { + "icon": "https://avatars.githubusercontent.com/u/13406820", + "images": [] + }, + "libjpeg-turbo-gcc": { + "icon": "https://avatars.githubusercontent.com/u/13406820", + "images": [] + }, + "libjpeg-turbo-vc": { + "icon": "https://avatars.githubusercontent.com/u/13406820", + "images": [] + }, + "libjxl": { + "icon": "", + "images": [] + }, + "libopencv-dev": { + "icon": "https://community.chocolatey.org/content/packageimages/libopencv-dev.4.5.4.png", + "images": [] + }, + "librebarcode-font": { + "icon": "https://community.chocolatey.org/content/packageimages/librebarcode.font.1.008.png", + "images": [] + }, + "librecad": { + "icon": "", + "images": [] + }, + "librehardwaremonitor": { + "icon": "https://community.chocolatey.org/content/packageimages/librehardwaremonitor.0.9.1.png", + "images": [] + }, + "libreoffice": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/4/48/LibreOffice_7.5_Main_Icon.svg/250px-LibreOffice_7.5_Main_Icon.svg.png", + "images": [ + "https://www.libreoffice.org/assets/Uploads/writer-2020.png", + "https://www.libreoffice.org/assets/Uploads/calc-2020.png", + "https://www.libreoffice.org/assets/Uploads/impress-2020.png", + "https://www.libreoffice.org/assets/Uploads/draw-2020.png" + ] + }, + "libreoffice-fresh": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/4/48/LibreOffice_7.5_Main_Icon.svg/250px-LibreOffice_7.5_Main_Icon.svg.png", + "images": [] + }, + "libreoffice-help": { + "icon": "", + "images": [] + }, + "libreoffice-oldstable": { + "icon": "", + "images": [] + }, + "libreoffice-still": { + "icon": "", + "images": [] + }, + "librespeed-cli": { + "icon": "https://community.chocolatey.org/content/packageimages/librespeed-cli.1.0.10.png", + "images": [] + }, + "libresprite": { + "icon": "https://community.chocolatey.org/content/packageimages/libresprite.1.0.png", + "images": [] + }, + "librevault": { + "icon": "", + "images": [] + }, + "librewolf": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/d/d0/LibreWolf_icon.svg/480px-LibreWolf_icon.svg.png", + "images": [] + }, + "libsndfile": { + "icon": "", + "images": [] + }, + "libusbdotnet": { + "icon": "https://community.chocolatey.org/content/packageimages/libusbdotnet.2.2.8.png", + "images": [] + }, + "libvips": { + "icon": "", + "images": [] + }, + "libwebp": { + "icon": "", + "images": [] + }, + "libxml2": { + "icon": "", + "images": [] + }, + "licecap": { + "icon": "", + "images": [] + }, + "liclipse": { + "icon": "", + "images": [] + }, + "lidarr": { + "icon": "https://community.chocolatey.org/content/packageimages/lidarr.1.1.3.2982.png", + "images": [] + }, + "lifesize-cloud": { + "icon": "", + "images": [] + }, + "light": { + "icon": "https://community.chocolatey.org/content/packageimages/light.34.0.png", + "images": [] + }, + "lightalloy": { + "icon": "https://community.chocolatey.org/content/packageimages/lightalloy.4.10.2.png", + "images": [] + }, + "lightbulb": { + "icon": "https://community.chocolatey.org/content/packageimages/lightbulb.2.0.png", + "images": [ + "https://i.imgur.com/BT0Gejw.png" + ] + }, + "lightburn": { + "icon": "https://i.postimg.cc/6pNTh6p3/Lightburn.png", + "images": [ + "https://i.postimg.cc/662SNnd8/image.png" + ] + }, + "lightcord": { + "icon": "", + "images": [] + }, + "lightformcreator": { + "icon": "", + "images": [] + }, + "lighthouse": { + "icon": "", + "images": [] + }, + "lightproxy": { + "icon": "", + "images": [] + }, + "lightscreen": { + "icon": "https://i.postimg.cc/nVszPXRx/icon.png", + "images": [ + "https://i.postimg.cc/DftZk7HX/1.png" + ] + }, + "lightshot": { + "icon": "https://community.chocolatey.org/content/packageimages/lightshot.install.5.5.0.720221014.png", + "images": [] + }, + "lightspark": { + "icon": "", + "images": [] + }, + "lighttable": { + "icon": "", + "images": [] + }, + "lighttpd": { + "icon": "", + "images": [] + }, + "lightworks": { + "icon": "https://community.chocolatey.org/content/packageimages/lightworks.2021.2.png", + "images": [] + }, + "lightyearvpn": { + "icon": "", + "images": [] + }, + "lightzone": { + "icon": "", + "images": [] + }, + "likefont": { + "icon": "", + "images": [] + }, + "lili": { + "icon": "https://community.chocolatey.org/content/packageimages/lili.portable.2.9.4.png", + "images": [] + }, + "lilypond": { + "icon": "https://i.postimg.cc/NFKh9R5j/lilypond-icon.png", + "images": [ + "https://i.postimg.cc/3NVsgWvC/lilypond-large.png" + ] + }, + "lilypond-unstable": { + "icon": "https://i.postimg.cc/NFKh9R5j/lilypond-icon.png", + "images": [ + "https://i.postimg.cc/3NVsgWvC/lilypond-large.png" + ] + }, + "limechat": { + "icon": "", + "images": [] + }, + "limitless": { + "icon": "https://community.chocolatey.org/content/packageimages/limitless.1.16.20221112.png", + "images": [] + }, + "line": { + "icon": "", + "images": [] + }, + "linepodlauncher": { + "icon": "", + "images": [] + }, + "lingdys4": { + "icon": "", + "images": [] + }, + "linkage": { + "icon": "", + "images": [] + }, + "linked": { + "icon": "", + "images": [] + }, + "linkednotes": { + "icon": "", + "images": [] + }, + "linkerd": { + "icon": "", + "images": [] + }, + "linkerd2": { + "icon": "", + "images": [] + }, + "links": { + "icon": "", + "images": [] + }, + "linkshellextension": { + "icon": "https://community.chocolatey.org/content/packageimages/LinkShellExtension.3.9.3.5.png", + "images": [] + }, + "linotte": { + "icon": "https://community.chocolatey.org/content/packageimages/linotte.3.14.00.png", + "images": [] + }, + "linphone": { + "icon": "", + "images": [] + }, + "linqpad": { + "icon": "https://i.postimg.cc/90NzY8b4/LINQPad8.png", + "images": [ + "https://i.postimg.cc/43bdSNwR/image.png", + "https://i.postimg.cc/D0mw0Qh7/image.png" + ] + }, + "linqpad-5": { + "icon": "https://i.postimg.cc/xCnQJvKW/LINQPad5.png", + "images": [ + "https://i.postimg.cc/t46GBSkK/image.png", + "https://i.postimg.cc/ZqFtSW1j/image.png" + ] + }, + "linqpad-6": { + "icon": "https://i.postimg.cc/CKJP7byy/LINQPad6.png", + "images": [ + "https://i.postimg.cc/Y2FVKGYF/image.png", + "https://i.postimg.cc/sD9NxknD/image.png" + ] + }, + "linqpad-7": { + "icon": "https://i.postimg.cc/ncZ3ydH8/LINQPad7.png", + "images": [ + "https://i.postimg.cc/CMCNsjbc/image.png", + "https://i.postimg.cc/FR5yjRzt/image.png" + ] + }, + "linqpad-8": { + "icon": "https://i.postimg.cc/90NzY8b4/LINQPad8.png", + "images": [ + "https://i.postimg.cc/43bdSNwR/image.png", + "https://i.postimg.cc/D0mw0Qh7/image.png" + ] + }, + "linqpad2": { + "icon": "", + "images": [] + }, + "linqpad4": { + "icon": "https://community.chocolatey.org/content/packageimages/linqpad4.4.59.png", + "images": [] + }, + "linqpad5": { + "icon": "https://i.postimg.cc/xCnQJvKW/LINQPad5.png", + "images": [ + "https://i.postimg.cc/t46GBSkK/image.png", + "https://i.postimg.cc/ZqFtSW1j/image.png" + ] + }, + "linqpad5-anycpu": { + "icon": "https://community.chocolatey.org/content/packageimages/linqpad5.AnyCPU.portable.5.46.0.png", + "images": [] + }, + "linqpad6": { + "icon": "https://i.postimg.cc/CKJP7byy/LINQPad6.png", + "images": [ + "https://i.postimg.cc/Y2FVKGYF/image.png", + "https://i.postimg.cc/sD9NxknD/image.png" + ] + }, + "linqpad7": { + "icon": "https://i.postimg.cc/ncZ3ydH8/LINQPad7.png", + "images": [ + "https://i.postimg.cc/CMCNsjbc/image.png", + "https://i.postimg.cc/FR5yjRzt/image.png" + ] + }, + "linqpad8": { + "icon": "https://i.postimg.cc/90NzY8b4/LINQPad8.png", + "images": [ + "https://i.postimg.cc/43bdSNwR/image.png", + "https://i.postimg.cc/D0mw0Qh7/image.png" + ] + }, + "linqpadless": { + "icon": "", + "images": [] + }, + "linrad": { + "icon": "", + "images": [] + }, + "linux-reader": { + "icon": "https://community.chocolatey.org/content/packageimages/linux-reader.4.15.2.png", + "images": [] + }, + "linuxfilesystems": { + "icon": "", + "images": [] + }, + "linuxreader": { + "icon": "", + "images": [] + }, + "liquibase": { + "icon": "https://community.chocolatey.org/content/packageimages/liquibase.4.15.0.png", + "images": [] + }, + "liquidsoap": { + "icon": "", + "images": [] + }, + "liskhub": { + "icon": "", + "images": [] + }, + "listary": { + "icon": "https://i.postimg.cc/2SxZ7C2m/Listary.png", + "images": [ + "https://i.postimg.cc/L8vJZN88/image.png", + "https://i.postimg.cc/NfcFJWy0/image.png", + "https://i.postimg.cc/C1CTz6wv/image.png" + ] + }, + "listdlls": { + "icon": "", + "images": [] + }, + "listen1": { + "icon": "", + "images": [] + }, + "listen1-fluent": { + "icon": "", + "images": [] + }, + "listen1desktop": { + "icon": "", + "images": [] + }, + "listenmoeclient": { + "icon": "", + "images": [] + }, + "listmonk": { + "icon": "", + "images": [] + }, + "lite": { + "icon": "", + "images": [] + }, + "lite-xl": { + "icon": "", + "images": [] + }, + "litebrowser": { + "icon": "", + "images": [] + }, + "litecoin": { + "icon": "", + "images": [] + }, + "liteide": { + "icon": "", + "images": [] + }, + "litemanager-server": { + "icon": "https://community.chocolatey.org/content/packageimages/litemanager-server.4.8.4886.png", + "images": [] + }, + "litemanager-viewer": { + "icon": "https://community.chocolatey.org/content/packageimages/litemanager-viewer.4.8.4886.png", + "images": [] + }, + "littlebigmouse": { + "icon": "", + "images": [] + }, + "littlenavmap": { + "icon": "https://community.chocolatey.org/content/packageimages/littlenavmap.2.8.8.png", + "images": [] + }, + "littleregistrycleaner": { + "icon": "https://community.chocolatey.org/content/packageimages/littleregistrycleaner.1.6.0.20141201.png", + "images": [] + }, + "littletips": { + "icon": "", + "images": [] + }, + "livecode": { + "icon": "", + "images": [] + }, + "liveconnect": { + "icon": "", + "images": [] + }, + "livehime": { + "icon": "", + "images": [] + }, + "livekd": { + "icon": "https://community.chocolatey.org/content/packageimages/livekd.5.63.png", + "images": [] + }, + "lively": { + "icon": "https://store-images.s-microsoft.com/image/apps.4720.14416131676512756.84314783-1c86-4403-b991-2e1da8525703.bf78340f-7059-4641-8d3f-8a7f740be8c0?w=120", + "images": [ + "https://store-images.s-microsoft.com/image/apps.21268.14416131676512756.d5cc43b8-16cc-4bdc-9f26-072d160ee792.51d0b915-43ec-4085-90a3-8cb687b4c488?h=768", + "https://store-images.s-microsoft.com/image/apps.21640.14416131676512756.8f975657-3f20-4265-8782-90e4e981cac8.157bc225-7b38-424a-8a73-84cec651d367?h=768", + "https://store-images.s-microsoft.com/image/apps.22016.14416131676512756.8f975657-3f20-4265-8782-90e4e981cac8.87797727-2732-4a94-8405-c7f4d9492e1b?h=768" + ] + }, + "livelywallpaper": { + "icon": "", + "images": [] + }, + "livereloadwebserver": { + "icon": "https://community.chocolatey.org/content/packageimages/LiveReloadWebServer.1.2.1.png", + "images": [] + }, + "livesplit": { + "icon": "https://community.chocolatey.org/content/packageimages/LiveSplit.1.8.25.png", + "images": [] + }, + "livestreamer": { + "icon": "", + "images": [] + }, + "livestreamer-twitch-gui": { + "icon": "", + "images": [] + }, + "llftool": { + "icon": "https://community.chocolatey.org/content/packageimages/llftool.4.40.20141201.png", + "images": [] + }, + "llvm": { + "icon": "https://unigeticons.meowcat285.com/LLVM-Logo-Derivative-4.png", + "images": [] + }, + "lmath": { + "icon": "", + "images": [] + }, + "lmms": { + "icon": "https://i.postimg.cc/T1NtbsBz/lmms-icon.png", + "images": [ + "https://i.postimg.cc/RhZPNmp1/LMMS-1.png" + ] + }, + "ln": { + "icon": "", + "images": [] + }, + "loadem": { + "icon": "", + "images": [] + }, + "local": { + "icon": "", + "images": [] + }, + "local-browser": { + "icon": "", + "images": [] + }, + "local-mock-server": { + "icon": "", + "images": [] + }, + "localadminwmi": { + "icon": "", + "images": [] + }, + "locale-emulator": { + "icon": "https://community.chocolatey.org/content/packageimages/locale-emulator.2.5.0.11.png", + "images": [] + }, + "localegraph": { + "icon": "", + "images": [] + }, + "localsend": { + "icon": "https://i.imgur.com/JZiGU2w.png", + "images": [ + "https://i.imgur.com/ZUmvRlJ.png", + "https://i.imgur.com/tzapdEs.png" + ] + }, + "lockhunter": { + "icon": "https://lockhunter.com/assets/images/lockhunter_icon_large_128_sh.png", + "images": [ + "https://lockhunter.com/assets/screenshots/mainScreenshotFull.png" + ] + }, + "lode": { + "icon": "", + "images": [] + }, + "loft": { + "icon": "", + "images": [] + }, + "log2console": { + "icon": "https://community.chocolatey.org/content/packageimages/log2console.1.6.0.220190214.png", + "images": [] + }, + "log4om": { + "icon": "https://community.chocolatey.org/content/packageimages/log4om.2.26.0.0.png", + "images": [] + }, + "log4view": { + "icon": "https://community.chocolatey.org/content/packageimages/log4view.1.5.3.1583.png", + "images": [] + }, + "logbert": { + "icon": "", + "images": [] + }, + "logdna": { + "icon": "", + "images": [] + }, + "logexpert": { + "icon": "", + "images": [] + }, + "logfileparser": { + "icon": "", + "images": [] + }, + "logfusion": { + "icon": "", + "images": [ + "https://i.postimg.cc/ZnxWJCtY/image.png", + "https://i.postimg.cc/9XdRdNR3/image.png", + "https://i.postimg.cc/CLJRtBsm/image.png", + "https://i.postimg.cc/g2TnzC5h/image.png", + "https://i.postimg.cc/3w0WdL5c/image.png", + "https://i.postimg.cc/y6yxggts/image.png" + ] + }, + "logibolt": { + "icon": "", + "images": [] + }, + "logiccards-chrome": { + "icon": "", + "images": [] + }, + "logicoolgaming5": { + "icon": "https://community.chocolatey.org/content/packageimages/logicoolgaming5.5.10.127.png", + "images": [] + }, + "loginator": { + "icon": "", + "images": [] + }, + "logintimer": { + "icon": "https://community.chocolatey.org/content/packageimages/loginTimer.108.11.4.7.png", + "images": [] + }, + "logisim-evolution": { + "icon": "https://community.chocolatey.org/content/packageimages/logisim-evolution.3.8.0.png", + "images": [] + }, + "logitech-camera-settings": { + "icon": "https://community.chocolatey.org/content/packageimages/logitech-camera-settings.2.12.8.png", + "images": [] + }, + "logitech-media-server": { + "icon": "", + "images": [] + }, + "logitech-omm": { + "icon": "", + "images": [] + }, + "logitech-options": { + "icon": "", + "images": [] + }, + "logitech-webcam-software": { + "icon": "", + "images": [] + }, + "logitechgaming5": { + "icon": "https://community.chocolatey.org/content/packageimages/logitechgaming5.5.10.127.png", + "images": [] + }, + "logitune": { + "icon": "https://imgs.search.brave.com/ASjRKcLSMy8TMcfmAKV4Hte2F6IJZNgqHnCwlZv_jJw/rs:fit:860:0:0:0/g:ce/aHR0cHM6Ly93d3cu/bG9naXRlY2guY29t/L2Fzc2V0cy82NTY4/Ni8yL2xvZ2ktdHVu/ZS1hcHAucG5n", + "images": [] + }, + "logmein-client": { + "icon": "https://community.chocolatey.org/content/packageimages/Logmein.Client.4.1.0.32682.png", + "images": [] + }, + "logmein-rescue-console-desktop": { + "icon": "", + "images": [] + }, + "logonsessions": { + "icon": "https://community.chocolatey.org/content/packageimages/logonsessions.1.41.png", + "images": [] + }, + "logos": { + "icon": "", + "images": [] + }, + "logparser": { + "icon": "", + "images": [] + }, + "logparser-lizardgui": { + "icon": "", + "images": [] + }, + "logparserstudio": { + "icon": "", + "images": [] + }, + "logreader": { + "icon": "", + "images": [] + }, + "logrotate": { + "icon": "https://community.chocolatey.org/content/packageimages/LogRotate.0.0.0.17.png", + "images": [] + }, + "logseq": { + "icon": "https://community.chocolatey.org/content/packageimages/logseq.0.8.17.png", + "images": [] + }, + "logstalgia": { + "icon": "", + "images": [] + }, + "logstash": { + "icon": "", + "images": [] + }, + "logstash-contrib": { + "icon": "", + "images": [] + }, + "logstash-forwarder": { + "icon": "", + "images": [] + }, + "logstitcher": { + "icon": "", + "images": [] + }, + "logtalk": { + "icon": "https://community.chocolatey.org/content/packageimages/logtalk.3.63.0.png", + "images": [] + }, + "lokalise-cli-2": { + "icon": "https://community.chocolatey.org/content/packageimages/lokalise-cli-2.2.6.8.png", + "images": [] + }, + "lokalise": { + "icon": "https://i.postimg.cc/NMvVwYk5/icon.png", + "images": [ + "https://i.postimg.cc/505r4Gsp/lokalize.png" + ] + }, + "loki": { + "icon": "", + "images": [] + }, + "loki-logcli": { + "icon": "", + "images": [] + }, + "loki-scanner": { + "icon": "https://community.chocolatey.org/content/packageimages/loki-scanner.0.45.0.png", + "images": [] + }, + "looking-glass": { + "icon": "", + "images": [] + }, + "loom": { + "icon": "", + "images": [] + }, + "loopdrop": { + "icon": "", + "images": [] + }, + "loopemail": { + "icon": "", + "images": [] + }, + "loopemail-beta": { + "icon": "", + "images": [] + }, + "loot": { + "icon": "", + "images": [] + }, + "lossless-audio-checker": { + "icon": "https://community.chocolatey.org/content/packageimages/lossless-audio-checker.2.0.7.png", + "images": [] + }, + "lossless-cut": { + "icon": "https://community.chocolatey.org/content/packageimages/lossless-cut.3.52.0.png", + "images": [] + }, + "losslesscut": { + "icon": "https://i.postimg.cc/zGkCwpwT/losslesscut-icon.png", + "images": [ + "https://github.com/mifi/lossless-cut/blob/59f117af2fe8ce03140ab8237cccbd073e09c0bc/main_screenshot.jpg" + ] + }, + "lot": { + "icon": "", + "images": [] + }, + "love": { + "icon": "https://community.chocolatey.org/content/packageimages/love.portable.11.4.png", + "images": [] + }, + "love2d": { + "icon": "", + "images": [] + }, + "lowkeygg": { + "icon": "", + "images": [] + }, + "lpsolve-ide": { + "icon": "https://community.chocolatey.org/content/packageimages/lpsolve-ide.5.5.2.11.png", + "images": [] + }, + "lrtimelapse": { + "icon": "https://community.chocolatey.org/content/packageimages/LRTimelapse.6.1.2.png", + "images": [] + }, + "lsagent": { + "icon": "https://community.chocolatey.org/content/packageimages/lsagent.10.0.1.100.png", + "images": [] + }, + "lsasecretsdump": { + "icon": "", + "images": [] + }, + "lsasecretsview": { + "icon": "https://community.chocolatey.org/content/packageimages/lsasecretsview.1.25.png", + "images": [] + }, + "lsd": { + "icon": "", + "images": [] + }, + "lsdeer": { + "icon": "", + "images": [] + }, + "lua": { + "icon": "https://i.postimg.cc/jjhXJWkv/lua.png", + "images": [] + }, + "lua-for-windows": { + "icon": "https://i.postimg.cc/jjhXJWkv/lua.png", + "images": [] + }, + "lua-language-server": { + "icon": "", + "images": [] + }, + "lua51": { + "icon": "https://i.postimg.cc/jjhXJWkv/lua.png", + "images": [] + }, + "lua52": { + "icon": "https://i.postimg.cc/jjhXJWkv/lua.png", + "images": [] + }, + "luabuglight": { + "icon": "https://community.chocolatey.org/content/packageimages/luabuglight.2.3.20161105.png", + "images": [] + }, + "luacheck": { + "icon": "", + "images": [] + }, + "luaforwindows": { + "icon": "", + "images": [] + }, + "luajit": { + "icon": "", + "images": [] + }, + "luarocks": { + "icon": "https://community.chocolatey.org/content/packageimages/luarocks.2.4.4.png", + "images": [] + }, + "luau": { + "icon": "", + "images": [] + }, + "lucaschess": { + "icon": "", + "images": [] + }, + "luckybackup": { + "icon": "https://community.chocolatey.org/content/packageimages/luckybackup.0.4.7.20140107.png", + "images": [] + }, + "ludusavi": { + "icon": "https://raw.githubusercontent.com/mtkennerly/ludusavi/master/assets/icon.svg", + "images": [ + "https://imgur.com/AJS547V" + ] + }, + "luminance": { + "icon": "https://community.chocolatey.org/content/packageimages/luminance.2.6.0.png", + "images": [] + }, + "luminancehdr": { + "icon": "", + "images": [] + }, + "luminearemote": { + "icon": "", + "images": [] + }, + "lunacy": { + "icon": "https://community.chocolatey.org/content/packageimages/lunacy.8.7.2.png", + "images": [] + }, + "lunaorm": { + "icon": "https://community.chocolatey.org/content/packageimages/LunaORM.4.0.0.1.png", + "images": [] + }, + "lunar-ips": { + "icon": "https://community.chocolatey.org/content/packageimages/lunar-ips.1.03.png", + "images": [] + }, + "lunarclient": { + "icon": "", + "images": [] + }, + "lunarlander": { + "icon": "", + "images": [] + }, + "lusun": { + "icon": "", + "images": [] + }, + "lux": { + "icon": "", + "images": [] + }, + "luxcorerender": { + "icon": "https://community.chocolatey.org/content/packageimages/luxcorerender.2.6.png", + "images": [] + }, + "lwc": { + "icon": "", + "images": [] + }, + "lx-music-desktop": { + "icon": "", + "images": [] + }, + "lxc": { + "icon": "https://community.chocolatey.org/content/packageimages/lxc.5.11.png", + "images": [] + }, + "lxrunoffline": { + "icon": "", + "images": [] + }, + "lychee": { + "icon": "", + "images": [] + }, + "lycheeslicer": { + "icon": "https://community.chocolatey.org/content/packageimages/lycheeslicer.3.6.6.png", + "images": [] + }, + "lyncbasic2013x86": { + "icon": "", + "images": [] + }, + "lynx": { + "icon": "", + "images": [] + }, + "lyricsfinder": { + "icon": "https://community.chocolatey.org/content/packageimages/lyricsfinder.1.5.2.png", + "images": [] + }, + "lyx": { + "icon": "https://community.chocolatey.org/content/packageimages/lyx.2.3.7.1.png", + "images": [] + }, + "lz4": { + "icon": "", + "images": [] + }, + "lzip": { + "icon": "", + "images": [] + }, + "lzip7z": { + "icon": "", + "images": [] + }, + "m4": { + "icon": "", + "images": [] + }, + "m4a-to-mp3-converter": { + "icon": "", + "images": [] + }, + "mac-precision-touchpad": { + "icon": "", + "images": [] + }, + "macaddressview": { + "icon": "https://community.chocolatey.org/content/packageimages/macaddressview.1.42.png", + "images": [] + }, + "macast": { + "icon": "", + "images": [] + }, + "macast-debug": { + "icon": "", + "images": [] + }, + "macchina": { + "icon": "", + "images": [] + }, + "mach-composer": { + "icon": "https://community.chocolatey.org/content/packageimages/mach-composer.2.5.0.png", + "images": [] + }, + "mach2": { + "icon": "", + "images": [] + }, + "macintosh-js": { + "icon": "", + "images": [] + }, + "macintoshjs": { + "icon": "", + "images": [] + }, + "macrocreator": { + "icon": "", + "images": [] + }, + "mactype": { + "icon": "https://community.chocolatey.org/content/packageimages/mactype.2017.628.0.png", + "images": [] + }, + "made-2016": { + "icon": "https://community.chocolatey.org/content/packageimages/made-2016.2022.08.23.png", + "images": [] + }, + "made2010": { + "icon": "https://community.chocolatey.org/content/packageimages/made2010.2021.02.08.png", + "images": [] + }, + "madvr": { + "icon": "https://community.chocolatey.org/content/packageimages/madvr.0.92.17.png", + "images": [] + }, + "mage": { + "icon": "", + "images": [] + }, + "magebros": { + "icon": "", + "images": [] + }, + "magic-wormhole": { + "icon": "", + "images": [] + }, + "magic-wormhole-rs": { + "icon": "", + "images": [] + }, + "magicavoxel": { + "icon": "https://community.chocolatey.org/content/packageimages/magicavoxel.0.99.6.4.png", + "images": [] + }, + "magicavoxelviewer": { + "icon": "https://community.chocolatey.org/content/packageimages/magicavoxelviewer.0.41.0.20170719.png", + "images": [] + }, + "magicsplat-tcl-tk": { + "icon": "", + "images": [] + }, + "magicut": { + "icon": "", + "images": [] + }, + "magpie": { + "icon": "", + "images": [] + }, + "mailbird": { + "icon": "", + "images": [] + }, + "mailconverter": { + "icon": "https://community.chocolatey.org/content/packageimages/MailConverter.3.1.png", + "images": [] + }, + "mailer": { + "icon": "https://community.chocolatey.org/content/packageimages/mailer.1.6.png", + "images": [] + }, + "mailhog": { + "icon": "", + "images": [] + }, + "maille-edupython": { + "icon": "", + "images": [] + }, + "mailmaster": { + "icon": "", + "images": [] + }, + "mailnoter": { + "icon": "https://community.chocolatey.org/content/packageimages/mailnoter.1.0.1.png", + "images": [] + }, + "mailpv": { + "icon": "https://community.chocolatey.org/content/packageimages/mailpv.1.86.png", + "images": [] + }, + "mailsend": { + "icon": "", + "images": [] + }, + "mailsend-go": { + "icon": "", + "images": [] + }, + "mailslurper": { + "icon": "https://community.chocolatey.org/content/packageimages/mailslurper.1.14.1.png", + "images": [] + }, + "mailspring": { + "icon": "https://images2.imgbox.com/19/20/xmpBFPrl_o.png", + "images": [ + "https://i.postimg.cc/W1X0pj65/hero-graphic-win32-2x.png" + ] + }, + "mailviewer": { + "icon": "", + "images": [] + }, + "mailwasher-free": { + "icon": "https://davescomputertips.com/wp-content/uploads/2020/08/MailWasher-Logo.png", + "images": [] + }, + "mailwasher-pro": { + "icon": "https://davescomputertips.com/wp-content/uploads/2020/08/MailWasher-Logo.png", + "images": [] + }, + "mainca": { + "icon": "", + "images": [] + }, + "mairix": { + "icon": "https://i.postimg.cc/qBNbxzgn/mairix.png", + "images": [] + }, + "majsoul-plus": { + "icon": "", + "images": [] + }, + "make": { + "icon": "https://i.postimg.cc/PJjZN2sh/png-clipart-gnu-compiler-collection-gnu-make-gnu-project-tor-mammal-sheep-thumbnail-Photoroom.png", + "images": [] + }, + "makehuman": { + "icon": "", + "images": [] + }, + "makemeadmin": { + "icon": "https://community.chocolatey.org/content/packageimages/makemeadmin.2.3.png", + "images": [ + "https://raw.githubusercontent.com/wiki/pseymour/MakeMeAdmin/images/makemeadminui-230.png" + ] + }, + "makemkv": { + "icon": "https://community.chocolatey.org/content/packageimages/MakeMKV.1.17.3.png", + "images": [] + }, + "makerlapse": { + "icon": "", + "images": [] + }, + "malden": { + "icon": "", + "images": [] + }, + "malwarebytes": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/2/27/Malwarebytes_Logo_%282016%29.svg/270px-Malwarebytes_Logo_%282016%29.svg.png", + "images": [ + "https://nl.malwarebytes.com/images/website-refresh/premium/take-a-look.png", + "https://nl.malwarebytes.com/images/website-refresh/premium/take-a-look2.png" + ] + }, + "malwarefighter": { + "icon": "", + "images": [] + }, + "mambaforge": { + "icon": "https://community.chocolatey.org/content/packageimages/mambaforge.22.11.1.400.png", + "images": [] + }, + "mame": { + "icon": "", + "images": [] + }, + "mamp": { + "icon": "https://community.chocolatey.org/content/packageimages/mamp.5.0.5.png", + "images": [] + }, + "mamp3": { + "icon": "https://community.chocolatey.org/content/packageimages/mamp3.3.3.1.png", + "images": [] + }, + "manaplus": { + "icon": "https://community.chocolatey.org/content/packageimages/manaplus.1.8.4.14.png", + "images": [] + }, + "mancy": { + "icon": "", + "images": [] + }, + "mandelbulber": { + "icon": "", + "images": [] + }, + "mandoc": { + "icon": "", + "images": [] + }, + "manga-py": { + "icon": "https://community.chocolatey.org/content/packageimages/manga-py.1.33.3.png", + "images": [] + }, + "mangal": { + "icon": "", + "images": [] + }, + "mangu": { + "icon": "", + "images": [] + }, + "manictime": { + "icon": "https://manictime.com/images/logo.png", + "images": [] + }, + "manifest-tool": { + "icon": "https://community.chocolatey.org/content/packageimages/manifest-tool.1.0.3.png", + "images": [] + }, + "manifold": { + "icon": "", + "images": [] + }, + "manifold-8": { + "icon": "", + "images": [] + }, + "manifold-9": { + "icon": "", + "images": [] + }, + "manifold-viewer": { + "icon": "", + "images": [] + }, + "manifoldviewer-9": { + "icon": "", + "images": [] + }, + "manim": { + "icon": "", + "images": [] + }, + "manim-latex": { + "icon": "https://community.chocolatey.org/content/packageimages/manim-latex.2023.01.png", + "images": [] + }, + "manta": { + "icon": "", + "images": [] + }, + "mantle": { + "icon": "", + "images": [] + }, + "manuskript": { + "icon": "https://community.chocolatey.org/content/packageimages/manuskript.0.14.0.png", + "images": [] + }, + "manycam": { + "icon": "https://community.chocolatey.org/content/packageimages/manycam.7.7.0.33.png", + "images": [] + }, + "maple": { + "icon": "", + "images": [] + }, + "mapmap": { + "icon": "", + "images": [] + }, + "mapper": { + "icon": "", + "images": [] + }, + "maptilerdesktop": { + "icon": "", + "images": [] + }, + "maptool": { + "icon": "https://community.chocolatey.org/content/packageimages/maptool.1.12.2.png", + "images": [] + }, + "marble": { + "icon": "https://community.chocolatey.org/content/packageimages/marble.2.2.0.png", + "images": [] + }, + "marcedit": { + "icon": "https://community.chocolatey.org/content/packageimages/marcedit.7.3.15.png", + "images": [] + }, + "mariadb": { + "icon": "https://community.chocolatey.org/content/packageimages/mariadb.portable.11.0.1.png", + "images": [] + }, + "markdown-edit": { + "icon": "https://community.chocolatey.org/content/packageimages/markdown-edit.1.35.0.20210920.png", + "images": [] + }, + "markdown-generator": { + "icon": "https://community.chocolatey.org/content/packageimages/Markdown-Generator.1.0.2.png", + "images": [] + }, + "markdown-monster": { + "icon": "", + "images": [] + }, + "markdowneditor": { + "icon": "", + "images": [] + }, + "markdownlint-cli": { + "icon": "https://community.chocolatey.org/content/packageimages/markdownlint-cli.0.32.2.png", + "images": [] + }, + "markdownmode": { + "icon": "", + "images": [] + }, + "markdownmonster": { + "icon": "https://markdownmonster.west-wind.com/Images/MarkdownMonster_Icon_256.png", + "images": [ + "https://i.postimg.cc/dQ8ZNrLw/image.png", + "https://i.postimg.cc/fWKT0KVt/image.png", + "https://i.postimg.cc/pL924Mqz/image.png", + "https://i.postimg.cc/PqYdfzGq/image.png", + "https://i.postimg.cc/jSJbvQSh/image.png" + ] + }, + "markdownmonster-portable": { + "icon": "https://community.chocolatey.org/content/packageimages/MarkdownMonster.Portable.2.8.6.png", + "images": [] + }, + "markdownoutlook": { + "icon": "", + "images": [] + }, + "markdownpad": { + "icon": "https://community.chocolatey.org/content/packageimages/markdownpad.portable.2.5.0.27920.png", + "images": [] + }, + "markdownpad2": { + "icon": "https://community.chocolatey.org/content/packageimages/markdownpad2.2.3.png", + "images": [] + }, + "markdownwin": { + "icon": "https://community.chocolatey.org/content/packageimages/markdownwin.1.0.png", + "images": [] + }, + "marker": { + "icon": "", + "images": [] + }, + "markn": { + "icon": "", + "images": [] + }, + "markpad": { + "icon": "https://community.chocolatey.org/content/packageimages/markpad.1.0.5.png", + "images": [] + }, + "markright": { + "icon": "", + "images": [] + }, + "marksman": { + "icon": "", + "images": [] + }, + "marktext": { + "icon": "https://community.chocolatey.org/content/packageimages/marktext.portable.0.17.1.png", + "images": [] + }, + "marp": { + "icon": "", + "images": [] + }, + "marp-cli": { + "icon": "https://community.chocolatey.org/content/packageimages/marp-cli.2.4.0.png", + "images": [] + }, + "marv": { + "icon": "", + "images": [] + }, + "marvin": { + "icon": "", + "images": [] + }, + "masgau": { + "icon": "https://community.chocolatey.org/content/packageimages/masgau.1.0.6.png", + "images": [] + }, + "masscert": { + "icon": "", + "images": [] + }, + "masscode": { + "icon": "", + "images": [] + }, + "massigra": { + "icon": "https://community.chocolatey.org/content/packageimages/massigra.0.45.0.1.png", + "images": [] + }, + "masteragent": { + "icon": "", + "images": [] + }, + "mastergo": { + "icon": "", + "images": [] + }, + "masterpackager": { + "icon": "https://community.chocolatey.org/content/packageimages/masterpackager.23.1.8444.0.png", + "images": [] + }, + "masterpdfeditor": { + "icon": "", + "images": [] + }, + "mastervolumesync": { + "icon": "", + "images": [] + }, + "masvis": { + "icon": "", + "images": [] + }, + "matchanagrams": { + "icon": "https://community.chocolatey.org/content/packageimages/matchanagrams.1.0.png", + "images": [] + }, + "matchmaking-server-picker": { + "icon": "https://community.chocolatey.org/content/packageimages/matchmaking-server-picker.4.5.png", + "images": [] + }, + "material-maker": { + "icon": "https://community.chocolatey.org/content/packageimages/material-maker.portable.1.2.png", + "images": [] + }, + "materialize": { + "icon": "", + "images": [] + }, + "materialproducticons-vscode": { + "icon": "https://community.chocolatey.org/content/packageimages/materialproducticons-vscode.1.5.0.png", + "images": [] + }, + "math": { + "icon": "", + "images": [] + }, + "mathpix": { + "icon": "", + "images": [] + }, + "mathpixsnippingtool": { + "icon": "", + "images": [] + }, + "mathtype7": { + "icon": "https://i.postimg.cc/Jh6hrqYz/mathtype-icon.png", + "images": [ + "https://i.postimg.cc/BQQwDBm0/mathtype-screenshot.png", + "https://i.postimg.cc/QCS4wFxw/mathtype-screenshot.png" + ] + }, + "matlabdrive": { + "icon": "", + "images": [] + }, + "matrikon-explorer": { + "icon": "", + "images": [] + }, + "matrix-io-malos-vision": { + "icon": "", + "images": [] + }, + "matterbridge": { + "icon": "", + "images": [] + }, + "matterircd": { + "icon": "", + "images": [] + }, + "mattermost": { + "icon": "https://mattermost.com/wp-content/themes/mattermost-2021/frontend/dist/img/favicon/v2/apple-touch-icon.png", + "images": [ + "https://mattermost.com/wp-content/uploads/2022/07/mattermost-channels-collaborate.png" + ] + }, + "mattermost-desktop": { + "icon": "https://raw.githubusercontent.com/mattermost/desktop/master/src/assets/linux/app_icon.png", + "images": [ + "https://mattermost.com/wp-content/uploads/2022/07/mattermost-channels-collaborate.png" + ] + }, + "mattermostdesktop": { + "icon": "https://raw.githubusercontent.com/mattermost/desktop/master/src/assets/linux/app_icon.png", + "images": [ + "https://mattermost.com/wp-content/uploads/2022/07/mattermost-channels-collaborate.png" + ] + }, + "maven": { + "icon": "", + "images": [] + }, + "maven-snapshot": { + "icon": "", + "images": [] + }, + "mavishub": { + "icon": "", + "images": [] + }, + "maxima": { + "icon": "", + "images": [] + }, + "maxmind-geoip-dat": { + "icon": "", + "images": [] + }, + "maxthon": { + "icon": "https://community.chocolatey.org/content/packageimages/maxthon.install.4.9.4.1000.png", + "images": [] + }, + "maxthon-5": { + "icon": "", + "images": [] + }, + "maxthon-6": { + "icon": "", + "images": [] + }, + "maxthon-commandline": { + "icon": "https://community.chocolatey.org/content/packageimages/maxthon.commandline.6.1.3.3000.png", + "images": [] + }, + "maxto": { + "icon": "", + "images": [] + }, + "mazerator": { + "icon": "", + "images": [] + }, + "mazeratorold": { + "icon": "", + "images": [] + }, + "mbca": { + "icon": "", + "images": [] + }, + "mbcord": { + "icon": "", + "images": [] + }, + "mblock": { + "icon": "https://community.chocolatey.org/content/packageimages/mblock.5.3.5.png", + "images": [] + }, + "mboxviewer": { + "icon": "https://community.chocolatey.org/content/packageimages/mboxviewer.1.0.3.37.png", + "images": [] + }, + "mbruler": { + "icon": "https://community.chocolatey.org/content/packageimages/mbruler.5.4.png", + "images": [] + }, + "mbsa": { + "icon": "https://community.chocolatey.org/content/packageimages/mbsa.2.3.2211.png", + "images": [] + }, + "mc": { + "icon": "https://community.chocolatey.org/content/packageimages/mc.4.17.0.214.png", + "images": [] + }, + "mclauncher": { + "icon": "", + "images": [] + }, + "mcomix": { + "icon": "", + "images": [] + }, + "mcr-r2014b": { + "icon": "https://community.chocolatey.org/content/packageimages/mcr-r2014b.8.4.0.20190708.png", + "images": [] + }, + "mcr-r2015a": { + "icon": "https://community.chocolatey.org/content/packageimages/mcr-r2015a.8.5.0.20190708.png", + "images": [] + }, + "mcr-r2015b": { + "icon": "https://community.chocolatey.org/content/packageimages/mcr-r2015b.9.0.png", + "images": [] + }, + "mcr-r2016b": { + "icon": "https://community.chocolatey.org/content/packageimages/mcr-r2016b.9.1.png", + "images": [] + }, + "mcr-r2019a": { + "icon": "https://community.chocolatey.org/content/packageimages/mcr-r2019a.9.6.0.1150989.png", + "images": [] + }, + "mcr-r2020b": { + "icon": "https://community.chocolatey.org/content/packageimages/mcr-r2020b.9.9.0.2037887.png", + "images": [] + }, + "mcr-r2021b": { + "icon": "https://community.chocolatey.org/content/packageimages/mcr-r2021b.9.11.0.2022996.png", + "images": [] + }, + "mcr-r2022b": { + "icon": "https://community.chocolatey.org/content/packageimages/mcr-r2022b.9.13.0.2166757.png", + "images": [] + }, + "mcreator": { + "icon": "https://mcreator.net/favicon/apple-touch-icon.png", + "images": [ + "https://mcreator.net/sites/default/files/wiki/%5B1%5D%20Main%20Menu.png", + "https://i.imgur.com/5ymmOCS.png" + ] + }, + "mcs": { + "icon": "", + "images": [] + }, + "mcserv": { + "icon": "", + "images": [] + }, + "mcxstudio": { + "icon": "", + "images": [] + }, + "md5": { + "icon": "https://community.chocolatey.org/content/packageimages/md5.2.2.png", + "images": [] + }, + "md5deep": { + "icon": "", + "images": [] + }, + "md5sums": { + "icon": "", + "images": [] + }, + "mdaemon": { + "icon": "", + "images": [] + }, + "mdbook": { + "icon": "", + "images": [] + }, + "mdbviewerplus": { + "icon": "", + "images": [] + }, + "mdcat": { + "icon": "", + "images": [] + }, + "mdftoiso": { + "icon": "", + "images": [] + }, + "mdloader": { + "icon": "", + "images": [] + }, + "mdt": { + "icon": "https://community.chocolatey.org/content/packageimages/MDT.6.3.8456.2.png", + "images": [] + }, + "mdview": { + "icon": "", + "images": [] + }, + "mdyna": { + "icon": "", + "images": [] + }, + "meatplay": { + "icon": "", + "images": [] + }, + "meazure": { + "icon": "https://community.chocolatey.org/content/packageimages/meazure.4.0.0.png", + "images": [] + }, + "medford": { + "icon": "", + "images": [] + }, + "mediacenter": { + "icon": "", + "images": [] + }, + "mediachips": { + "icon": "", + "images": [] + }, + "mediacreationtool": { + "icon": "", + "images": [] + }, + "mediafire-dl": { + "icon": "", + "images": [] + }, + "mediainfo": { + "icon": "", + "images": [] + }, + "mediainfo-cli": { + "icon": "", + "images": [] + }, + "mediainfo-gui": { + "icon": "", + "images": [ + "https://i.postimg.cc/s2x7v8Ts/814eedf-84591aa.jpg" + ] + }, + "mediainfo-net": { + "icon": "", + "images": [] + }, + "mediamonkey": { + "icon": "", + "images": [] + }, + "mediaplayer": { + "icon": "https://avatars.githubusercontent.com/u/1249822?s=280&v=4", + "images": [ + "https://audacious-media-player.org/images/audacious-4.0.2.png", + "https://www.fossmint.com/wp-content/uploads/2017/06/Audacious-Media-Player.png" + ] + }, + "mediathekview": { + "icon": "https://community.chocolatey.org/content/packageimages/MediathekView.13.9.0.png", + "images": [] + }, + "mednafen": { + "icon": "", + "images": [] + }, + "meet": { + "icon": "", + "images": [] + }, + "mega-chrome": { + "icon": "https://community.chocolatey.org/content/packageimages/mega-chrome.3.119.0.png", + "images": [] + }, + "mega-edge": { + "icon": "https://community.chocolatey.org/content/packageimages/mega-edge.3.119.0.png", + "images": [] + }, + "megabasterd": { + "icon": "", + "images": [] + }, + "megacmd": { + "icon": "https://community.chocolatey.org/content/packageimages/megacmd.1.4.1.0.png", + "images": [] + }, + "megadownloader": { + "icon": "https://community.chocolatey.org/content/packageimages/megadownloader.1.8.png", + "images": [] + }, + "megasync": { + "icon": "https://community.chocolatey.org/content/packageimages/megasync.4.8.7.0.png", + "images": [] + }, + "megatools": { + "icon": "", + "images": [] + }, + "megui": { + "icon": "https://community.chocolatey.org/content/packageimages/megui.1.0.2913.png", + "images": [] + }, + "meinplatz": { + "icon": "", + "images": [] + }, + "meld": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/e/ea/Meld_Logo.svg/128px-Meld_Logo.svg.png", + "images": [ + "https://upload.wikimedia.org/wikipedia/commons/thumb/3/30/Meld_file1.png/640px-Meld_file1.png" + ] + }, + "mellow": { + "icon": "", + "images": [] + }, + "mellowplayer": { + "icon": "https://community.chocolatey.org/content/packageimages/mellowplayer.3.5.90.png", + "images": [] + }, + "melodics": { + "icon": "", + "images": [] + }, + "melodie": { + "icon": "", + "images": [] + }, + "melonplayer": { + "icon": "", + "images": [] + }, + "memcached": { + "icon": "https://community.chocolatey.org/content/packageimages/memcached.1.4.4.png", + "images": [] + }, + "memento": { + "icon": "https://community.chocolatey.org/content/packageimages/memento.install.1.0.0.png", + "images": [] + }, + "mementodatabasedesktop": { + "icon": "", + "images": [] + }, + "memreduct": { + "icon": "https://community.chocolatey.org/content/packageimages/memreduct.3.4.png", + "images": [] + }, + "memurai-developer": { + "icon": "https://community.chocolatey.org/content/packageimages/memurai-developer.2.0.7.png", + "images": [] + }, + "memuraideveloper": { + "icon": "", + "images": [] + }, + "mendeley": { + "icon": "https://community.chocolatey.org/content/packageimages/mendeley.1.19.8.png", + "images": [] + }, + "mental-omega": { + "icon": "https://community.chocolatey.org/content/packageimages/mental-omega.3.3.4.png", + "images": [] + }, + "menutools": { + "icon": "https://community.chocolatey.org/content/packageimages/menutools.1.0.2.20210222.png", + "images": [] + }, + "meow": { + "icon": "", + "images": [] + }, + "mercurial": { + "icon": "", + "images": [] + }, + "mery": { + "icon": "", + "images": [] + }, + "mery-beta": { + "icon": "", + "images": [] + }, + "meshcommander": { + "icon": "https://community.chocolatey.org/content/packageimages/meshcommander.0.9.6.png", + "images": [] + }, + "meshhouse": { + "icon": "", + "images": [] + }, + "meshlab": { + "icon": "https://community.chocolatey.org/content/packageimages/MeshLab.2022.02.png", + "images": [] + }, + "meshmixer": { + "icon": "https://community.chocolatey.org/content/packageimages/meshmixer.3.5.0.20210303.png", + "images": [] + }, + "meshroom": { + "icon": "", + "images": [] + }, + "meson": { + "icon": "", + "images": [] + }, + "messenger": { + "icon": "https://i.imgur.com/PZmD7cN.png", + "images": [ + "https://i.imgur.com/9PCvI22.png", + "https://i.imgur.com/7mPy8kQ.png", + "https://i.imgur.com/zVq5B1X.jpg" + ] + }, + "metadataplusplus": { + "icon": "https://community.chocolatey.org/content/packageimages/metadataplusplus.2.02.3.png", + "images": [] + }, + "metafox": { + "icon": "", + "images": [] + }, + "metastore": { + "icon": "", + "images": [] + }, + "metax": { + "icon": "https://community.chocolatey.org/content/packageimages/MetaX.2.85.png", + "images": [] + }, + "meteor": { + "icon": "https://community.chocolatey.org/content/packageimages/meteor.0.0.5.png", + "images": [] + }, + "metricbeat-oss": { + "icon": "https://community.chocolatey.org/content/packageimages/metricbeat-oss.8.4.1.png", + "images": [] + }, + "metrogit": { + "icon": "", + "images": [] + }, + "metronome": { + "icon": "", + "images": [ + "https://i.imgur.com/bDHGwjV.png", + "https://i.imgur.com/N9k3j4n.png", + "https://i.imgur.com/gh4c7L2.png" + ] + }, + "metronomewallet": { + "icon": "", + "images": [] + }, + "metropolislauncher": { + "icon": "https://community.chocolatey.org/content/packageimages/metropolislauncher.1.2.0.png", + "images": [] + }, + "mfaws": { + "icon": "", + "images": [] + }, + "mfilter": { + "icon": "", + "images": [] + }, + "mft2csv": { + "icon": "", + "images": [] + }, + "mgba": { + "icon": "https://community.chocolatey.org/content/packageimages/mgba.0.10.1.png", + "images": [] + }, + "micaforeveryone": { + "icon": "https://raw.githubusercontent.com/MicaForEveryone/MicaForEveryone/reset-winui3/MicaForEveryone.App/Assets/Square44x44Logo.altform-lightunplated_targetsize-256.png", + "images": [] + }, + "micmonitor": { + "icon": "https://community.chocolatey.org/content/packageimages/micmonitor.1.1.0.png", + "images": [] + }, + "micmute": { + "icon": "", + "images": [] + }, + "micro": { + "icon": "", + "images": [] + }, + "micron-storage-executive": { + "icon": "https://community.chocolatey.org/content/packageimages/micron-storage-executive.8.07.072022.04.png", + "images": [] + }, + "micronaut": { + "icon": "https://community.chocolatey.org/content/packageimages/micronaut.3.8.3.png", + "images": [] + }, + "microsip": { + "icon": "https://community.chocolatey.org/content/packageimages/microsip.3.21.3.png", + "images": [] + }, + "microsip-lite": { + "icon": "https://community.chocolatey.org/content/packageimages/microsip-lite.3.21.3.png", + "images": [] + }, + "microsoft-band-sync": { + "icon": "https://community.chocolatey.org/content/packageimages/Microsoft-Band-Sync.1.3.1021.3.png", + "images": [] + }, + "microsoft-build-tools": { + "icon": "", + "images": [] + }, + "microsoft-build-tools-2013": { + "icon": "https://community.chocolatey.org/content/packageimages/microsoft-build-tools-2013.2013.1.png", + "images": [] + }, + "microsoft-edge": { + "icon": "https://community.chocolatey.org/content/packageimages/microsoft-edge.110.0.1587.57.png", + "images": [] + }, + "microsoft-edge-insider": { + "icon": "https://community.chocolatey.org/content/packageimages/microsoft-edge-insider.111.0.1661.24.png", + "images": [] + }, + "microsoft-edge-insider-dev": { + "icon": "https://community.chocolatey.org/content/packageimages/microsoft-edge-insider-dev.111.0.1660.14.png", + "images": [] + }, + "microsoft-monitoring-agent": { + "icon": "https://community.chocolatey.org/content/packageimages/microsoft-monitoring-agent.10.20.18067.0.png", + "images": [] + }, + "microsoft-office-deployment": { + "icon": "https://community.chocolatey.org/content/packageimages/microsoft-office-deployment.16.0.15726.20202.png", + "images": [] + }, + "microsoft-openjdk11": { + "icon": "", + "images": [] + }, + "microsoft-openjdk17": { + "icon": "", + "images": [] + }, + "microsoft-powerapps-cli": { + "icon": "", + "images": [] + }, + "microsoft-sql-server-migration-assistant-for-access": { + "icon": "https://community.chocolatey.org/content/packageimages/microsoft-sql-server-migration-assistant-for-access.9.0.0.png", + "images": [] + }, + "microsoft-teams": { + "icon": "https://community.chocolatey.org/content/packageimages/microsoft-teams.install.1.6.00.1381.png", + "images": [] + }, + "microsoft-teams-free": { + "icon": "https://community.chocolatey.org/content/packageimages/microsoft-teams.install.1.6.00.1381.png", + "images": [] + }, + "microsoft-visual-cpp-build-tools": { + "icon": "https://community.chocolatey.org/content/packageimages/microsoft-visual-cpp-build-tools.14.0.25420.1.png", + "images": [] + }, + "microsoft-vsteam-psmodule": { + "icon": "https://community.chocolatey.org/content/packageimages/microsoft-vsteam-psmodule.7.9.0.png", + "images": [] + }, + "microsoftazurestorageexplorer": { + "icon": "", + "images": [] + }, + "microsoftbandtools": { + "icon": "", + "images": [] + }, + "microsoftmathematics": { + "icon": "https://community.chocolatey.org/content/packageimages/microsoftmathematics.4.0.1108.0000.png", + "images": [] + }, + "microsoftofficehub": { + "icon": "https://i.postimg.cc/T31K2tXf/Brand-Logo-org-Microsoft-Copilot-Logo.png", + "images": [] + }, + "microsoftsecurityessentials": { + "icon": "", + "images": [] + }, + "microsoftwebdriver": { + "icon": "https://community.chocolatey.org/content/packageimages/microsoftwebdriver.1.0.0.png", + "images": [] + }, + "microsoftwse": { + "icon": "", + "images": [] + }, + "micswitch": { + "icon": "", + "images": [] + }, + "midi-ox": { + "icon": "", + "images": [] + }, + "midi2lr": { + "icon": "", + "images": [] + }, + "midicsv": { + "icon": "", + "images": [] + }, + "midnightcommander": { + "icon": "https://developer.asustor.com/uploadIcons/0020_999_1596445716_Midnight-Commander_256.png", + "images": [] + }, + "midori-browser": { + "icon": "https://community.chocolatey.org/content/packageimages/midori-browser.0.5.9.20141201.png", + "images": [] + }, + "midterm": { + "icon": "", + "images": [] + }, + "mightymoose": { + "icon": "https://community.chocolatey.org/content/packageimages/mightymoose.1.47.0.png", + "images": [] + }, + "mightytext-chrome": { + "icon": "", + "images": [] + }, + "migi": { + "icon": "", + "images": [] + }, + "migrate": { + "icon": "", + "images": [] + }, + "migrationassistant": { + "icon": "", + "images": [] + }, + "miktex": { + "icon": "https://community.chocolatey.org/content/packageimages/miktex.install.22.10.png", + "images": [] + }, + "mileswilford-defaultinstall": { + "icon": "", + "images": [] + }, + "milkman": { + "icon": "https://community.chocolatey.org/content/packageimages/milkman.5.5.0.png", + "images": [] + }, + "milkman-cassandra": { + "icon": "https://community.chocolatey.org/content/packageimages/milkman-cassandra.5.5.0.png", + "images": [] + }, + "milkman-explore": { + "icon": "https://community.chocolatey.org/content/packageimages/milkman-explore.5.5.0.png", + "images": [] + }, + "milkman-graphql": { + "icon": "https://community.chocolatey.org/content/packageimages/milkman-graphql.5.5.0.png", + "images": [] + }, + "milkman-grpc": { + "icon": "https://community.chocolatey.org/content/packageimages/milkman-grpc.5.5.0.png", + "images": [] + }, + "milkman-jdbc": { + "icon": "", + "images": [] + }, + "milkman-note": { + "icon": "https://community.chocolatey.org/content/packageimages/milkman-note.5.5.0.png", + "images": [] + }, + "milkman-plugins": { + "icon": "https://community.chocolatey.org/content/packageimages/milkman-plugins.5.5.0.png", + "images": [] + }, + "milkman-privatebin": { + "icon": "https://community.chocolatey.org/content/packageimages/milkman-privatebin.5.5.0.png", + "images": [] + }, + "milkman-scripting": { + "icon": "https://community.chocolatey.org/content/packageimages/milkman-scripting.5.5.0.png", + "images": [] + }, + "milkman-sync-git": { + "icon": "https://community.chocolatey.org/content/packageimages/milkman-sync-git.5.5.0.png", + "images": [] + }, + "mill": { + "icon": "", + "images": [] + }, + "miller": { + "icon": "", + "images": [] + }, + "millipede": { + "icon": "", + "images": [] + }, + "milton": { + "icon": "https://community.chocolatey.org/content/packageimages/milton.1.9.1.png", + "images": [] + }, + "min": { + "icon": "https://community.chocolatey.org/content/packageimages/min.portable.1.27.0.png", + "images": [] + }, + "mind+": { + "icon": "", + "images": [] + }, + "mindforger": { + "icon": "", + "images": [] + }, + "mindmaster": { + "icon": "", + "images": [] + }, + "mindstormseduev3classroom": { + "icon": "", + "images": [] + }, + "mine-imator": { + "icon": "", + "images": [] + }, + "minecraft-education": { + "icon": "https://edusupport.minecraft.net/hc/article_attachments/12443930919700", + "images": [] + }, + "minecraftlauncher": { + "icon": "https://cdn2.steamgriddb.com/icon/b7a782741f667201b54880c925faec4b.png", + "images": [ + "https://www.minecraft.net/content/dam/games/minecraft/key-art/MC_The-Wild-Update_540x300.jpg", + "https://pics.computerbase.de/1/0/3/7/5/9-e76e0679e4fd11ea/article-1280x720.2cad9186.jpg" + ] + }, + "minecraftuwp": { + "icon": "https://cdn2.steamgriddb.com/icon/b7a782741f667201b54880c925faec4b.png", + "images": [] + }, + "minermanager": { + "icon": "", + "images": [] + }, + "minerva": { + "icon": "", + "images": [] + }, + "minetest": { + "icon": "https://community.chocolatey.org/content/packageimages/minetest.5.6.1.20221118.png", + "images": [] + }, + "mingit": { + "icon": "", + "images": [] + }, + "mingit-busybox": { + "icon": "", + "images": [] + }, + "mingo": { + "icon": "", + "images": [] + }, + "mingw": { + "icon": "", + "images": [] + }, + "mingw-get": { + "icon": "", + "images": [] + }, + "mingw-nuwen": { + "icon": "", + "images": [] + }, + "mingw-winlibs": { + "icon": "", + "images": [] + }, + "mini-sftp-server": { + "icon": "", + "images": [] + }, + "mini-squeezebox-control-chrome": { + "icon": "", + "images": [] + }, + "minibin": { + "icon": "https://community.chocolatey.org/content/packageimages/minibin.6.6.0.004.png", + "images": [] + }, + "miniconda": { + "icon": "https://community.chocolatey.org/content/packageimages/Miniconda.4.3.21.png", + "images": [] + }, + "miniconda3": { + "icon": "https://community.chocolatey.org/content/packageimages/miniconda3.4.12.0.png", + "images": [] + }, + "miniforge3": { + "icon": "https://i.postimg.cc/pLM4CMmw/Miniforge3-256-256.png", + "images": [] + }, + "minify": { + "icon": "", + "images": [] + }, + "minikube": { + "icon": "https://community.chocolatey.org/content/packageimages/Minikube.1.29.0.png", + "images": [] + }, + "minilyrics": { + "icon": "", + "images": [] + }, + "minio": { + "icon": "", + "images": [] + }, + "minio-client": { + "icon": "https://community.chocolatey.org/content/packageimages/minio-client.2020.12.10.png", + "images": [] + }, + "minio-server": { + "icon": "https://community.chocolatey.org/content/packageimages/minio-server.2021.11.09.png", + "images": [] + }, + "minipacman": { + "icon": "", + "images": [] + }, + "miniprogramstudio": { + "icon": "", + "images": [] + }, + "miniserve": { + "icon": "", + "images": [] + }, + "minishift": { + "icon": "https://community.chocolatey.org/content/packageimages/minishift.1.34.3.png", + "images": [] + }, + "minisign": { + "icon": "", + "images": [] + }, + "mipony": { + "icon": "", + "images": [] + }, + "miranda": { + "icon": "", + "images": [] + }, + "miranda-ng": { + "icon": "https://community.chocolatey.org/content/packageimages/miranda-ng.0.95.9.1.png", + "images": [] + }, + "mirandaim": { + "icon": "", + "images": [] + }, + "mirandang": { + "icon": "", + "images": [] + }, + "mirc": { + "icon": "https://community.chocolatey.org/content/packageimages/mirc.7.72.png", + "images": [] + }, + "miro": { + "icon": "https://i.postimg.cc/vmpfwKmf/miro-logo-250.png", + "images": [] + }, + "mirrorgo": { + "icon": "", + "images": [] + }, + "mirrorop": { + "icon": "", + "images": [] + }, + "mirth": { + "icon": "https://community.chocolatey.org/content/packageimages/mirth.install.3.10.1.png", + "images": [] + }, + "mirth-administrator-launcher": { + "icon": "https://community.chocolatey.org/content/packageimages/mirth-administrator-launcher.1.1.0.png", + "images": [] + }, + "miru": { + "icon": "", + "images": [] + }, + "mise-en-place": { + "icon": "https://raw.githubusercontent.com/jdx/mise/main/docs/public/favicon-32x32.png", + "images": [] + }, + "miservice": { + "icon": "", + "images": [] + }, + "misfitmodel3d": { + "icon": "", + "images": [] + }, + "misfitmodel3d-dev": { + "icon": "", + "images": [] + }, + "missionplanner": { + "icon": "https://community.chocolatey.org/content/packageimages/missionplanner.1.3.77.png", + "images": [] + }, + "mist": { + "icon": "", + "images": [] + }, + "mitelconnect": { + "icon": "https://community.chocolatey.org/content/packageimages/MitelConnect.213.100.4571.0.png", + "images": [] + }, + "mitkerberos": { + "icon": "https://community.chocolatey.org/content/packageimages/mitkerberos.4.1.png", + "images": [] + }, + "mitmproxy": { + "icon": "https://community.chocolatey.org/content/packageimages/mitmproxy.8.1.1.png", + "images": [] + }, + "miui+": { + "icon": "", + "images": [] + }, + "miunlock": { + "icon": "https://community.chocolatey.org/content/packageimages/miunlock.6.5.224.28.png", + "images": [] + }, + "mixxx": { + "icon": "https://community.chocolatey.org/content/packageimages/mixxx.2.3.3.png", + "images": [] + }, + "mizu-cli": { + "icon": "", + "images": [] + }, + "mkcert": { + "icon": "", + "images": [] + }, + "mkdocs": { + "icon": "https://community.chocolatey.org/content/packageimages/mkdocs.1.4.2.png", + "images": [] + }, + "mkdocs-material": { + "icon": "https://community.chocolatey.org/content/packageimages/mkdocs-material.9.0.15.png", + "images": [] + }, + "mkey": { + "icon": "", + "images": [] + }, + "mkv-muxing-batch-gui": { + "icon": "https://community.chocolatey.org/content/packageimages/mkv-muxing-batch-gui.2.1.png", + "images": [] + }, + "mkvmergebatcher": { + "icon": "", + "images": [] + }, + "mkvtoolnix": { + "icon": "https://i.postimg.cc/DzrFp15v/mkvtoolnix-icon.png", + "images": [ + "https://i.postimg.cc/TPMfctVN/mkvtoolnix-gui-official-screenshot.png" + ] + }, + "Winget.mlocati.GetText": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/2/22/Heckert_GNU_white.svg/960px-Heckert_GNU_white.svg.png", + "images": [ + "https://i.imgur.com/KnVZQsT.png" + ] + }, + "mls-software-openssh": { + "icon": "", + "images": [] + }, + "mm-choco-extension": { + "icon": "", + "images": [] + }, + "mmbot": { + "icon": "", + "images": [] + }, + "mmctl": { + "icon": "", + "images": [] + }, + "mmdb-websitebeaterupper": { + "icon": "https://community.chocolatey.org/content/packageimages/MMDB.WebsiteBeaterUpper.1.0.0.2.png", + "images": [] + }, + "mnemosyne": { + "icon": "https://community.chocolatey.org/content/packageimages/mnemosyne.2.10.1.png", + "images": [] + }, + "mo2": { + "icon": "https://community.chocolatey.org/content/packageimages/mo2.2.4.4.png", + "images": [] + }, + "moar": { + "icon": "", + "images": [] + }, + "mob": { + "icon": "", + "images": [] + }, + "mobalivecd": { + "icon": "", + "images": [] + }, + "mobaxterm": { + "icon": "https://i.postimg.cc/1XxHfxyp/xterm-logo.png", + "images": [ + "https://i.postimg.cc/ZK48gxnK/image.png", + "https://i.postimg.cc/KjrnjRq2/Cool-features.png" + ] + }, + "mobilecloud": { + "icon": "", + "images": [] + }, + "mobiletrans": { + "icon": "", + "images": [] + }, + "mobilityprint": { + "icon": "", + "images": [] + }, + "mobipocket-reader": { + "icon": "", + "images": [] + }, + "mobirise": { + "icon": "", + "images": [] + }, + "mobster": { + "icon": "", + "images": [] + }, + "mobswitcher": { + "icon": "https://community.chocolatey.org/content/packageimages/mobswitcher.1.3.4.png", + "images": [] + }, + "mochi": { + "icon": "https://community.chocolatey.org/content/packageimages/mochi.1.3.10.png", + "images": [] + }, + "mockery": { + "icon": "", + "images": [] + }, + "mockitt-cn": { + "icon": "", + "images": [] + }, + "mockoon": { + "icon": "https://community.chocolatey.org/content/packageimages/mockoon.1.22.0.png", + "images": [] + }, + "modd": { + "icon": "", + "images": [] + }, + "moddb-extension": { + "icon": "https://community.chocolatey.org/content/packageimages/moddb.extension.0.1.3.png", + "images": [] + }, + "modelio": { + "icon": "https://community.chocolatey.org/content/packageimages/modelio.4.1.0.png", + "images": [] + }, + "modern7z": { + "icon": "", + "images": [] + }, + "moderncsv": { + "icon": "https://community.chocolatey.org/content/packageimages/moderncsv.1.3.36.png", + "images": [] + }, + "moderndeck": { + "icon": "", + "images": [] + }, + "modernflyouts": { + "icon": "https://i.imgur.com/prW4uEK.png", + "images": [] + }, + "modorganizer": { + "icon": "", + "images": [] + }, + "modrealmslauncher": { + "icon": "https://community.chocolatey.org/content/packageimages/modrealmslauncher.2.5.4.0000.png", + "images": [] + }, + "modrinthapp": { + "icon": "https://raw.githubusercontent.com/modrinth/code/main/apps/app/icons/icon.png", + "images": [] + }, + "modsecurity": { + "icon": "", + "images": [] + }, + "modv": { + "icon": "", + "images": [] + }, + "moebius": { + "icon": "", + "images": [] + }, + "mogan": { + "icon": "", + "images": [] + }, + "moldflowc": { + "icon": "https://community.chocolatey.org/content/packageimages/moldflowc.2023.0.png", + "images": [] + }, + "moligeek": { + "icon": "", + "images": [] + }, + "molotov": { + "icon": "https://community.chocolatey.org/content/packageimages/molotov.4.4.4.png", + "images": [] + }, + "momentum-chrome": { + "icon": "", + "images": [] + }, + "monaco": { + "icon": "", + "images": [] + }, + "monaminote": { + "icon": "", + "images": [] + }, + "monday": { + "icon": "", + "images": [] + }, + "monero": { + "icon": "https://community.chocolatey.org/content/packageimages/monero.0.18.1.2.png", + "images": [] + }, + "monero-cli": { + "icon": "", + "images": [] + }, + "money-manager-ex": { + "icon": "https://community.chocolatey.org/content/packageimages/money-manager-ex.1.5.16.0.png", + "images": [] + }, + "moneydance": { + "icon": "", + "images": [] + }, + "moneyguru": { + "icon": "https://community.chocolatey.org/content/packageimages/moneyguru.2.10.1.png", + "images": [] + }, + "moneymanagerex": { + "icon": "", + "images": [] + }, + "mongoclient": { + "icon": "https://community.chocolatey.org/content/packageimages/mongoclient.1.5.0.png", + "images": [] + }, + "mongodb": { + "icon": "https://community.chocolatey.org/content/packageimages/mongodb.install.6.2.0.png", + "images": [] + }, + "mongodb-3": { + "icon": "", + "images": [] + }, + "mongodb-cli": { + "icon": "https://community.chocolatey.org/content/packageimages/mongodb-cli.1.27.0.png", + "images": [] + }, + "mongodb-compass": { + "icon": "https://community.chocolatey.org/content/packageimages/mongodb-compass.1.35.0.png", + "images": [] + }, + "mongodb-compass-isolated": { + "icon": "https://community.chocolatey.org/content/packageimages/mongodb-compass-isolated.1.35.0.png", + "images": [] + }, + "mongodb-compass-readonly": { + "icon": "https://community.chocolatey.org/content/packageimages/mongodb-compass-readonly.1.35.0.png", + "images": [] + }, + "mongodb-core": { + "icon": "https://community.chocolatey.org/content/packageimages/mongodb.core.2.4.9.2014021902.png", + "images": [] + }, + "mongodb-core-2-2": { + "icon": "https://community.chocolatey.org/content/packageimages/mongodb.core.2.2.2.2.7.2014021906.png", + "images": [] + }, + "mongodb-core-2-4": { + "icon": "https://community.chocolatey.org/content/packageimages/mongodb.core.2.4.2.4.9.2014021905.png", + "images": [] + }, + "mongodb-core-2-6": { + "icon": "https://community.chocolatey.org/content/packageimages/mongodb.core.2.6.2.6.1.2014061320.png", + "images": [] + }, + "mongodb-database-tools": { + "icon": "https://community.chocolatey.org/content/packageimages/mongodb-database-tools.100.6.1.png", + "images": [] + }, + "mongodb-shell": { + "icon": "https://community.chocolatey.org/content/packageimages/mongodb-shell.1.7.1.png", + "images": [] + }, + "mongodbatlascli": { + "icon": "", + "images": [] + }, + "mongodbcli": { + "icon": "", + "images": [] + }, + "mongodbfortango": { + "icon": "https://community.chocolatey.org/content/packageimages/MongoDBForTango.1.0.png", + "images": [] + }, + "mongoose-tiny": { + "icon": "", + "images": [] + }, + "mongosh": { + "icon": "", + "images": [] + }, + "mongovue": { + "icon": "", + "images": [] + }, + "monika": { + "icon": "", + "images": [] + }, + "monit": { + "icon": "", + "images": [] + }, + "monitordetails": { + "icon": "", + "images": [] + }, + "monitorian": { + "icon": "https://community.chocolatey.org/content/packageimages/monitorian.4.0.1.png", + "images": [] + }, + "monitorinfoview": { + "icon": "https://community.chocolatey.org/content/packageimages/monitorinfoview.1.22.png", + "images": [] + }, + "monitorswitcher": { + "icon": "https://community.chocolatey.org/content/packageimages/monitorswitcher.0.7.0.0.png", + "images": [] + }, + "monkeyacademy": { + "icon": "", + "images": [] + }, + "monkeysaudio": { + "icon": "https://www.instalki.pl/wp-content/uploads/program/icons/Monkey_Audio.png", + "images": [ + "https://monkeysaudio.com/images/screenshot.png" + ] + }, + "mono": { + "icon": "https://community.chocolatey.org/content/packageimages/mono.6.12.0.182.png", + "images": [] + }, + "mono3": { + "icon": "", + "images": [] + }, + "monodevelop": { + "icon": "https://community.chocolatey.org/content/packageimages/monodevelop.5.10.1.6.png", + "images": [] + }, + "monogame": { + "icon": "", + "images": [] + }, + "monokle": { + "icon": "", + "images": [] + }, + "monolith": { + "icon": "https://community.chocolatey.org/content/packageimages/monolith.2.7.0.png", + "images": [] + }, + "monosnap": { + "icon": "https://community.chocolatey.org/content/packageimages/Monosnap.4.1.16.png", + "images": [] + }, + "montserrat-font": { + "icon": "", + "images": [] + }, + "mooncoin": { + "icon": "", + "images": [] + }, + "moonitor": { + "icon": "", + "images": [] + }, + "moonlight": { + "icon": "https://community.chocolatey.org/content/packageimages/moonlight.install.1.0.0.png", + "images": [] + }, + "moonlight-qt": { + "icon": "https://community.chocolatey.org/content/packageimages/moonlight-qt.install.4.3.1.png", + "images": [] + }, + "moonscript": { + "icon": "", + "images": [] + }, + "moose": { + "icon": "", + "images": [] + }, + "moosync": { + "icon": "https://raw.githubusercontent.com/Moosync/Moosync/main/extras/banner_logo.png", + "images": [ + "https://raw.githubusercontent.com/Moosync/Moosync/main/extras/screenshot_song_view.png", + "https://raw.githubusercontent.com/Moosync/Moosync/main/extras/screenshot_musicinfo_view.png" + ] + }, + "moq-prig": { + "icon": "", + "images": [] + }, + "morsetest": { + "icon": "https://community.chocolatey.org/content/packageimages/morsetest.4.6.png", + "images": [] + }, + "mosh-client": { + "icon": "", + "images": [] + }, + "mosquitto": { + "icon": "", + "images": [] + }, + "mossawir-lan-messenger": { + "icon": "", + "images": [] + }, + "motiongif": { + "icon": "", + "images": [] + }, + "motionstudio": { + "icon": "", + "images": [] + }, + "motrix": { + "icon": "", + "images": [] + }, + "mountain-duck": { + "icon": "https://unigeticons.meowcat285.com/MountainDuck.png", + "images": [] + }, + "mountainduck": { + "icon": "https://unigeticons.meowcat285.com/MountainDuck.png", + "images": [] + }, + "mouse-jiggler": { + "icon": "https://community.chocolatey.org/content/packageimages/mouse-jiggler.2.0.14.png", + "images": [] + }, + "mouseandkeyboardcenter": { + "icon": "https://cdn.lo4d.com/t/icon/128/microsoft-mouse-and-keyboard-center.png", + "images": [] + }, + "mousecontroller": { + "icon": "https://community.chocolatey.org/content/packageimages/mousecontroller.1.7.1.20141201.png", + "images": [] + }, + "mousejiggler": { + "icon": "", + "images": [] + }, + "mousewithoutborders": { + "icon": "https://community.chocolatey.org/content/packageimages/mousewithoutborders.2.2.1.327.png", + "images": [] + }, + "movaviscreenrecorder": { + "icon": "https://community.chocolatey.org/content/packageimages/movaviscreenrecorder.22.0.0.png", + "images": [] + }, + "movavislideshowmaker": { + "icon": "https://community.chocolatey.org/content/packageimages/movavislideshowmaker.8.0.0.png", + "images": [] + }, + "movavivideoconverter": { + "icon": "https://community.chocolatey.org/content/packageimages/movavivideoconverter.22.1.0.png", + "images": [] + }, + "movefile": { + "icon": "", + "images": [] + }, + "movie-collector": { + "icon": "https://community.chocolatey.org/content/packageimages/movie-collector.23.1.1.png", + "images": [] + }, + "movieconverter": { + "icon": "https://community.chocolatey.org/content/packageimages/MovieConverter.3.1.png", + "images": [] + }, + "mozbackup": { + "icon": "https://community.chocolatey.org/content/packageimages/mozbackup.1.5.1.20141130.png", + "images": [] + }, + "mozilla-vpn": { + "icon": "", + "images": [] + }, + "mozillacacheview": { + "icon": "https://community.chocolatey.org/content/packageimages/mozillacacheview.1.81.png", + "images": [] + }, + "mozillahistoryview": { + "icon": "https://community.chocolatey.org/content/packageimages/mozillahistoryview.1.65.png", + "images": [] + }, + "mozillamaintenanceservice": { + "icon": "https://i.postimg.cc/RCLmpNTX/Firefox-icon.png", + "images": [] + }, + "mozjpeg": { + "icon": "", + "images": [] + }, + "mozregression-gui": { + "icon": "", + "images": [] + }, + "mp3directcut": { + "icon": "https://community.chocolatey.org/content/packageimages/mp3directcut.2.36.png", + "images": [] + }, + "mp3gain": { + "icon": "https://community.chocolatey.org/content/packageimages/mp3gain.1.5.2.png", + "images": [] + }, + "mp3gain-gui": { + "icon": "https://community.chocolatey.org/content/packageimages/mp3gain-gui.1.2.5.20190112.png", + "images": [] + }, + "mp3infpu": { + "icon": "", + "images": [] + }, + "mp3tag": { + "icon": "https://www.mp3tag.de/images/logo.png", + "images": [ + "https://www.mp3tag.de/images/sht_main.png", + "https://www.mp3tag.de/images/sht_optgen1.png", + "https://www.mp3tag.de/images/sht_optcon1.png", + "https://www.mp3tag.de/images/sht_export.png", + "https://www.mp3tag.de/images/sht_optfreedb1.png" + ] + }, + "mpack": { + "icon": "", + "images": [] + }, + "mpc": { + "icon": "", + "images": [] + }, + "mpc-be": { + "icon": "https://i.postimg.cc/k4TTW6J4/mpc-be-1-6-6.png", + "images": [ + "https://cdn2.portableapps.com/MPC-BEPortable.png" + ] + }, + "mpc-be-nightly": { + "icon": "https://community.chocolatey.org/content/packageimages/mpc-be-nightly.1.5.6.5943.png", + "images": [] + }, + "mpc-hc": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/7/76/Media_Player_Classic_logo.png", + "images": [ + "https://user-images.githubusercontent.com/73800734/200967040-8c06e7be-4937-4e98-b5b6-cc9960d8d12c.png" + ] + }, + "mpc-hc-fork": { + "icon": "", + "images": [] + }, + "mpc-qt": { + "icon": "https://community.chocolatey.org/content/packageimages/mpc-qt.23.02.png", + "images": [] + }, + "mpd": { + "icon": "", + "images": [] + }, + "mpg123": { + "icon": "", + "images": [] + }, + "mplayer": { + "icon": "", + "images": [] + }, + "mpos": { + "icon": "https://community.chocolatey.org/content/packageimages/mpos.0.5.0.png", + "images": [] + }, + "mpress": { + "icon": "", + "images": [] + }, + "mprocs": { + "icon": "", + "images": [] + }, + "mps": { + "icon": "", + "images": [] + }, + "mps-eap": { + "icon": "", + "images": [] + }, + "mpv": { + "icon": "https://raw.githubusercontent.com/mpv-player/mpv.io/master/source/images/mpv-logo-128.png", + "images": [] + }, + "mpv-easy-player": { + "icon": "https://raw.githubusercontent.com/mpv-player/mpv.io/master/source/images/mpv-logo-128.png", + "images": [] + }, + "mpv-git": { + "icon": "https://raw.githubusercontent.com/mpv-player/mpv.io/master/source/images/mpv-logo-128.png", + "images": [] + }, + "mpv-net": { + "icon": "https://raw.githubusercontent.com/mpv-player/mpv.io/master/source/images/mpv-logo-128.png", + "images": [ + "https://i.postimg.cc/cJNqRHQH/Main.png", + "https://i.postimg.cc/jdmYjv2y/Menu.png", + "https://i.postimg.cc/0ySRKmKF/Conf-Editor.png", + "https://i.postimg.cc/ncCtZNFH/Terminal.png" + ] + }, + "mpvio": { + "icon": "https://community.chocolatey.org/content/packageimages/mpvio.0.35.0.png", + "images": [] + }, + "mpvnet": { + "icon": "https://raw.githubusercontent.com/mpv-player/mpv.io/master/source/images/mpv-logo-128.png", + "images": [ + "https://i.postimg.cc/cJNqRHQH/Main.png", + "https://i.postimg.cc/jdmYjv2y/Menu.png", + "https://i.postimg.cc/0ySRKmKF/Conf-Editor.png", + "https://i.postimg.cc/ncCtZNFH/Terminal.png" + ] + }, + "mpw": { + "icon": "https://community.chocolatey.org/content/packageimages/mpw.portable.2.7.12.png", + "images": [] + }, + "mpxplay": { + "icon": "", + "images": [] + }, + "mqtt-explorer": { + "icon": "", + "images": [] + }, + "mqtt-explorer-beta": { + "icon": "", + "images": [] + }, + "mqtt-spy": { + "icon": "", + "images": [] + }, + "mqttfx": { + "icon": "https://community.chocolatey.org/content/packageimages/mqttfx.1.7.1.png", + "images": [] + }, + "mqttx": { + "icon": "", + "images": [] + }, + "mrboom": { + "icon": "", + "images": [] + }, + "mrcode": { + "icon": "", + "images": [] + }, + "mrdclutterer": { + "icon": "", + "images": [] + }, + "mremoteng": { + "icon": "https://community.chocolatey.org/content/packageimages/mRemoteNG.1.76.20.24615.png", + "images": [] + }, + "mro": { + "icon": "https://community.chocolatey.org/content/packageimages/mro.1.12.20141201.png", + "images": [] + }, + "mro-launcher": { + "icon": "https://community.chocolatey.org/content/packageimages/mro-launcher.0.2.1.20141201.png", + "images": [] + }, + "mrswatson": { + "icon": "", + "images": [] + }, + "ms-reportviewer2015": { + "icon": "", + "images": [] + }, + "msaccess2010-redist": { + "icon": "", + "images": [] + }, + "msaccess2010-redist-x86": { + "icon": "https://community.chocolatey.org/content/packageimages/MSAccess2010-redist-x86.1.2.png", + "images": [] + }, + "msbuild-awstasks": { + "icon": "", + "images": [] + }, + "msbuild-communitytasks": { + "icon": "", + "images": [] + }, + "msbuild-extensionpack": { + "icon": "https://community.chocolatey.org/content/packageimages/msbuild.extensionpack.4.0.15.0.png", + "images": [] + }, + "msbuild-sonarqube-runner": { + "icon": "", + "images": [] + }, + "msbuild-structured-log-viewer": { + "icon": "https://community.chocolatey.org/content/packageimages/msbuild-structured-log-viewer.2.1.758.png", + "images": [] + }, + "msbuild-xslt": { + "icon": "", + "images": [] + }, + "msbuildcommunitytasks": { + "icon": "", + "images": [] + }, + "msbuilddumper": { + "icon": "", + "images": [] + }, + "msdeploy": { + "icon": "", + "images": [] + }, + "msedgeredirect": { + "icon": "https://unigeticons.meowcat285.com/msedgeredirect.0.7.5.3.png", + "images": [] + }, + "mseries": { + "icon": "", + "images": [] + }, + "msfilterpack2-redist-x64": { + "icon": "https://community.chocolatey.org/content/packageimages/MSFilterPack2-redist-x64.1.1.png", + "images": [] + }, + "msfsclient": { + "icon": "", + "images": [] + }, + "msi-template": { + "icon": "https://community.chocolatey.org/content/packageimages/msi.template.1.0.2.png", + "images": [] + }, + "msi2xml": { + "icon": "", + "images": [] + }, + "msiafterburner": { + "icon": "https://community.chocolatey.org/content/packageimages/msiafterburner.4.6.5.png", + "images": [] + }, + "msigna": { + "icon": "https://community.chocolatey.org/content/packageimages/msigna.0.10.5.png", + "images": [] + }, + "msikombustor": { + "icon": "", + "images": [] + }, + "msival2": { + "icon": "", + "images": [] + }, + "msixcommander": { + "icon": "", + "images": [] + }, + "msixcore": { + "icon": "", + "images": [] + }, + "msixhero": { + "icon": "", + "images": [] + }, + "msklc": { + "icon": "", + "images": [] + }, + "msmpi": { + "icon": "", + "images": [] + }, + "msmpisdk": { + "icon": "", + "images": [] + }, + "msmtp": { + "icon": "", + "images": [] + }, + "msoidcli": { + "icon": "", + "images": [] + }, + "msoledbsql": { + "icon": "", + "images": [] + }, + "mspacman": { + "icon": "", + "images": [] + }, + "mspacmannes": { + "icon": "", + "images": [] + }, + "mspass": { + "icon": "https://community.chocolatey.org/content/packageimages/mspass.1.43.png", + "images": [] + }, + "msspeech-sr-tele-en-us": { + "icon": "", + "images": [] + }, + "mssql2014express-defaultinstance": { + "icon": "", + "images": [] + }, + "mssqlexpress2014sp1wt": { + "icon": "", + "images": [] + }, + "mssqlserver-compact3-5": { + "icon": "https://community.chocolatey.org/content/packageimages/mssqlserver-compact3.5.3.5.8080.0.png", + "images": [] + }, + "mssqlserver-compact4-0": { + "icon": "https://community.chocolatey.org/content/packageimages/mssqlserver-compact4.0.4.0.8876.1.png", + "images": [] + }, + "mssqlserver2012express": { + "icon": "https://community.chocolatey.org/content/packageimages/MsSqlServer2012Express.11.00.3000.20140928.png", + "images": [] + }, + "mssqlserver2012expressadv": { + "icon": "https://community.chocolatey.org/content/packageimages/MsSqlServer2012ExpressAdv.11.0.2100.60.png", + "images": [] + }, + "mssqlserver2012expresswithreporting": { + "icon": "https://community.chocolatey.org/content/packageimages/MsSqlServer2012ExpressWithReporting.11.00.3000.20140928.png", + "images": [] + }, + "mssqlserver2014-sqllocaldb": { + "icon": "", + "images": [] + }, + "mssqlserver2014express": { + "icon": "", + "images": [] + }, + "mssqlservermanagementstudio2014express": { + "icon": "", + "images": [] + }, + "mssqlserverschoolsampledatabase": { + "icon": "", + "images": [] + }, + "mssyncframework21-corecomponents-x64": { + "icon": "https://community.chocolatey.org/content/packageimages/mssyncframework21-corecomponents-x64.2.1.1648.0.png", + "images": [] + }, + "mssyncframework21-sdk-x86": { + "icon": "https://community.chocolatey.org/content/packageimages/MSSyncFramework21-sdk-x86.1.1.png", + "images": [] + }, + "mstream": { + "icon": "https://community.chocolatey.org/content/packageimages/mstream.install.5.11.4.png", + "images": [] + }, + "mstreamserver": { + "icon": "", + "images": [] + }, + "msvisualcplusplus2012-redist": { + "icon": "", + "images": [] + }, + "msvisualcplusplus2013-redist": { + "icon": "https://community.chocolatey.org/content/packageimages/MSVisualCplusplus2013-redist.1.1.png", + "images": [] + }, + "msxml4": { + "icon": "", + "images": [] + }, + "msxml4-sp3": { + "icon": "", + "images": [] + }, + "msxml6-sp1": { + "icon": "", + "images": [] + }, + "msys": { + "icon": "", + "images": [] + }, + "msys2": { + "icon": "https://i.postimg.cc/pd1rJ06Q/mingw64.png", + "images": [ + "https://i.postimg.cc/MTCGhnxv/winterm.png" + ] + }, + "msysgit": { + "icon": "https://community.chocolatey.org/content/packageimages/msysgit.1.7.10.20120526.png", + "images": [] + }, + "mtgalauncher": { + "icon": "", + "images": [] + }, + "mtn": { + "icon": "https://community.chocolatey.org/content/packageimages/mtn.1.1.png", + "images": [] + }, + "mtpcopy": { + "icon": "", + "images": [] + }, + "mtputty": { + "icon": "", + "images": [] + }, + "mtuner": { + "icon": "https://community.chocolatey.org/content/packageimages/mtuner.4.2.9.png", + "images": [] + }, + "mu": { + "icon": "", + "images": [] + }, + "mu-editor": { + "icon": "", + "images": [] + }, + "mubu": { + "icon": "", + "images": [] + }, + "mucommander": { + "icon": "https://community.chocolatey.org/content/packageimages/mucommander.1.1.0.png", + "images": [] + }, + "mudlet": { + "icon": "https://community.chocolatey.org/content/packageimages/mudlet.4.16.0.png", + "images": [] + }, + "muffon": { + "icon": "", + "images": [] + }, + "muleesb": { + "icon": "https://community.chocolatey.org/content/packageimages/muleesb.3.8.1.png", + "images": [] + }, + "mullvad-app": { + "icon": "https://community.chocolatey.org/content/packageimages/mullvad-app.2023.1.png", + "images": [] + }, + "mullvadbrowser": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/7/70/Mullvad_Browser_logo.svg/128px-Mullvad_Browser_logo.svg.png", + "images": [] + }, + "mullvadvpn": { + "icon": "https://i.postimg.cc/0jX6jk4D/mullvad-VPN.png", + "images": [] + }, + "multi-gitter": { + "icon": "https://community.chocolatey.org/content/packageimages/multi-gitter.0.42.3.png", + "images": [] + }, + "multiavchd": { + "icon": "", + "images": [] + }, + "multibit": { + "icon": "https://community.chocolatey.org/content/packageimages/multibit.0.5.19.png", + "images": [] + }, + "multibit-hd": { + "icon": "https://community.chocolatey.org/content/packageimages/multibit-hd.0.5.1.png", + "images": [] + }, + "multibootusb": { + "icon": "", + "images": [] + }, + "multibrowse": { + "icon": "", + "images": [] + }, + "multiclip": { + "icon": "https://community.chocolatey.org/content/packageimages/Multiclip.1.4.2.0.png", + "images": [] + }, + "multicommander": { + "icon": "https://community.chocolatey.org/content/packageimages/MultiCommander.12.8.2929.20230224.png", + "images": [] + }, + "multihasher": { + "icon": "https://community.chocolatey.org/content/packageimages/multihasher.2.8.2.png", + "images": [] + }, + "multilingualapptoolkit": { + "icon": "https://community.chocolatey.org/content/packageimages/MultilingualAppToolkit.4.0.1915.png", + "images": [] + }, + "multimc": { + "icon": "https://community.chocolatey.org/content/packageimages/multimc.0.6.16.png", + "images": [ + "https://i.postimg.cc/65rZjmpj/image.png", + "https://i.postimg.cc/Hk3yH85b/image.png", + "https://i.postimg.cc/rpmtpyC3/image.png", + "https://i.postimg.cc/25KLLp06/image.png", + "https://i.postimg.cc/0jmVH0zY/image.png" + ] + }, + "multimon": { + "icon": "", + "images": [] + }, + "multimonitortool": { + "icon": "https://community.chocolatey.org/content/packageimages/multimonitortool.2.05.png", + "images": [] + }, + "multipar": { + "icon": "https://community.chocolatey.org/content/packageimages/multipar.portable.1.3.2.7.png", + "images": [] + }, + "multipar-beta": { + "icon": "", + "images": [] + }, + "multipass": { + "icon": "", + "images": [] + }, + "multiplicity": { + "icon": "https://community.chocolatey.org/content/packageimages/multiplicity.1.10.20221112.png", + "images": [] + }, + "multisine": { + "icon": "", + "images": [] + }, + "multrin": { + "icon": "https://community.chocolatey.org/content/packageimages/multrin.1.2.2.png", + "images": [] + }, + "mumble": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/8/8f/Icons_mumble.svg/256px-Icons_mumble.svg.png", + "images": [] + }, + "mumble-client": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/8/8f/Icons_mumble.svg/256px-Icons_mumble.svg.png", + "images": [] + }, + "mumble-server": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/8/8f/Icons_mumble.svg/256px-Icons_mumble.svg.png", + "images": [] + }, + "munixo-client": { + "icon": "", + "images": [] + }, + "mupdf": { + "icon": "https://community.chocolatey.org/content/packageimages/mupdf.1.21.0.png", + "images": [] + }, + "mupen64": { + "icon": "", + "images": [] + }, + "mupen64plus-qt": { + "icon": "https://community.chocolatey.org/content/packageimages/mupen64plus-qt.1.10.png", + "images": [] + }, + "museeks": { + "icon": "", + "images": [] + }, + "musescore": { + "icon": "https://i.imgur.com/gvC46W4.png", + "images": [ + "https://i.imgur.com/zdv4ouw.png", + "https://i.imgur.com/Onb2nRv.png", + "https://i.postimg.cc/wMqbcrRS/1.png", + "https://i.postimg.cc/y6jGY7wB/2.png", + "https://i.postimg.cc/5ysKPmwj/3.png" + ] + }, + "music": { + "icon": "https://m.media-amazon.com/images/I/610LDzZhsUL.png", + "images": [ + "https://www.dolby.com/siteassets/passions/music/amazonmusic_1920x1080.jpg", + "https://i.pcmag.com/imagery/reviews/01vJVJPhC1L36eDVDp2Mlsb-15..v1621319677.jpg", + "https://i.imgur.com/OeVCtFA.jpg", + "https://www.windowslatest.com/wp-content/uploads/2018/02/amazon-music.png" + ] + }, + "music-collector": { + "icon": "https://community.chocolatey.org/content/packageimages/music-collector.22.0.6.png", + "images": [] + }, + "musicbee": { + "icon": "", + "images": [] + }, + "musiccaster": { + "icon": "", + "images": [] + }, + "musicplayer": { + "icon": "", + "images": [] + }, + "musicplayer2": { + "icon": "", + "images": [] + }, + "music-presence": { + "icon": "https://i.imgur.com/mg9JXrI.png", + "images": [ + "https://i.imgur.com/a/0bmcVo6.png", + "https://repository-images.githubusercontent.com/754190568/8726b1de-8ffc-4184-9ad6-a0a8f7a7b896", + "https://musicpresence.app/opengraph/index.png" + ] + }, + "musikcube": { + "icon": "", + "images": [] + }, + "musique": { + "icon": "", + "images": [] + }, + "mutagen": { + "icon": "", + "images": [] + }, + "mvc": { + "icon": "https://community.chocolatey.org/content/packageimages/mvc.3.0.2.png", + "images": [] + }, + "mvndaemon": { + "icon": "", + "images": [] + }, + "mweather": { + "icon": "https://community.chocolatey.org/content/packageimages/mweather.1.73.png", + "images": [] + }, + "mybox": { + "icon": "", + "images": [] + }, + "mybrowserpage-chrome": { + "icon": "https://community.chocolatey.org/content/packageimages/mybrowserpage-chrome.1.0.png", + "images": [] + }, + "myeventviewer": { + "icon": "https://community.chocolatey.org/content/packageimages/myeventviewer.2.25.png", + "images": [] + }, + "myfamilytree": { + "icon": "https://i.servimg.com/u/f56/09/00/58/71/myfami10.png", + "images": [ + "https://chronoplexsoftware.com/myfamilytree/screenshots/screenshot_1a.webp", + "https://chronoplexsoftware.com/myfamilytree/screenshots/screenshot_2a.webp", + "https://chronoplexsoftware.com/myfamilytree/screenshots/screenshot_3a.webp", + "https://chronoplexsoftware.com/myfamilytree/screenshots/screenshot_4a.webp", + "https://chronoplexsoftware.com/myfamilytree/screenshots/screenshot_5a.webp", + "https://chronoplexsoftware.com/myfamilytree/screenshots/screenshot_6a.webp", + "https://chronoplexsoftware.com/myfamilytree/screenshots/screenshot_7a.webp", + "https://chronoplexsoftware.com/myfamilytree/screenshots/screenshot_9a.webp", + "https://chronoplexsoftware.com/myfamilytree/screenshots/screenshot_10a.webp", + "https://chronoplexsoftware.com/myfamilytree/screenshots/screenshot_11a.webp", + "https://chronoplexsoftware.com/myfamilytree/screenshots/screenshot_12a.webp", + "https://chronoplexsoftware.com/myfamilytree/screenshots/screenshot_3h.webp" + ] + }, + "myharmony": { + "icon": "", + "images": [] + }, + "myhomelib": { + "icon": "", + "images": [] + }, + "myhotkey": { + "icon": "https://community.chocolatey.org/content/packageimages/myhotkey.4.0.0.20170311.png", + "images": [] + }, + "myjdownloader-chrome": { + "icon": "", + "images": [] + }, + "myki": { + "icon": "", + "images": [] + }, + "mylifeorganized": { + "icon": "https://community.chocolatey.org/content/packageimages/mylifeorganized.5.0.4.png", + "images": [] + }, + "mymonero": { + "icon": "https://community.chocolatey.org/content/packageimages/mymonero.1.3.3.png", + "images": [] + }, + "mymoney-net": { + "icon": "", + "images": [] + }, + "myopenlab": { + "icon": "https://community.chocolatey.org/content/packageimages/myopenlab.3.11.0.png", + "images": [] + }, + "mypaint": { + "icon": "https://community.chocolatey.org/content/packageimages/mypaint.2.0.1.20220704.png", + "images": [] + }, + "mypal": { + "icon": "", + "images": [] + }, + "myphoneexplorer": { + "icon": "", + "images": [] + }, + "myrulib": { + "icon": "https://community.chocolatey.org/content/packageimages/myrulib.0.29.16.png", + "images": [] + }, + "myrulib-cr": { + "icon": "https://community.chocolatey.org/content/packageimages/myrulib-cr.0.29.16.png", + "images": [] + }, + "mysql": { + "icon": "https://community.chocolatey.org/content/packageimages/mysql.8.0.31.png", + "images": [] + }, + "mysql-32bit": { + "icon": "https://community.chocolatey.org/content/packageimages/mysql-32bit.5.6.15.png", + "images": [] + }, + "mysql-cli": { + "icon": "", + "images": [] + }, + "mysql-connector": { + "icon": "https://community.chocolatey.org/content/packageimages/mysql-connector.8.0.31.png", + "images": [] + }, + "mysql-connector-java": { + "icon": "", + "images": [] + }, + "mysql-installer": { + "icon": "", + "images": [] + }, + "mysql-odbc": { + "icon": "https://community.chocolatey.org/content/packageimages/mysql.odbc.8.0.32.png", + "images": [] + }, + "mysql-python": { + "icon": "https://community.chocolatey.org/content/packageimages/mysql-python.8.0.31.png", + "images": [] + }, + "mysql-utilities": { + "icon": "", + "images": [] + }, + "mysql-workbench": { + "icon": "https://unigeticons.meowcat285.com/MySQLWorkbench.png", + "images": [] + }, + "mysqlnotifier": { + "icon": "", + "images": [] + }, + "mysqlworkbench": { + "icon": "https://unigeticons.meowcat285.com/MySQLWorkbench.png", + "images": [ + "https://i.postimg.cc/wTDYzPtb/image.png", + "https://i.postimg.cc/43NDzxWr/image.png", + "https://i.postimg.cc/5t7ZpWGj/image.png" + ] + }, + "mysterium": { + "icon": "", + "images": [] + }, + "mysteriumvpn": { + "icon": "https://community.chocolatey.org/content/packageimages/mysteriumvpn.10.14.4.png", + "images": [] + }, + "myviewboard-display": { + "icon": "", + "images": [] + }, + "myviewboard-whiteboard": { + "icon": "", + "images": [] + }, + "mzcv": { + "icon": "https://community.chocolatey.org/content/packageimages/mzcv.1.56.png", + "images": [] + }, + "n-m3u8dl-cli": { + "icon": "", + "images": [] + }, + "n3dr": { + "icon": "https://community.chocolatey.org/content/packageimages/n3dr.6.7.3.png", + "images": [] + }, + "nagstamon": { + "icon": "https://community.chocolatey.org/content/packageimages/nagstamon.install.3.10.1.png", + "images": [] + }, + "naiveproxy": { + "icon": "", + "images": [] + }, + "nalgaeset": { + "icon": "", + "images": [] + }, + "nali": { + "icon": "", + "images": [] + }, + "namebench": { + "icon": "", + "images": [] + }, + "namecoin": { + "icon": "", + "images": [] + }, + "namecoincore": { + "icon": "", + "images": [] + }, + "namemytvseries": { + "icon": "", + "images": [] + }, + "nanazip": { + "icon": "https://i.postimg.cc/QCMrRPpR/nana.png", + "images": [ + "https://raw.githubusercontent.com/M2Team/NanaZip/main/Documents/ContextMenu.png" + ] + }, + "nanazip-preview": { + "icon": "https://i.postimg.cc/m25bGbpV/nana-pre.png", + "images": [ + "https://raw.githubusercontent.com/M2Team/NanaZip/main/Documents/ContextMenu.png" + ] + }, + "nancy": { + "icon": "", + "images": [] + }, + "nancy-blog": { + "icon": "https://community.chocolatey.org/content/packageimages/Nancy.Blog.0.1.0.0.png", + "images": [] + }, + "nano": { + "icon": "", + "images": [] + }, + "nano-win": { + "icon": "", + "images": [] + }, + "nanoleaf": { + "icon": "https://community.chocolatey.org/content/packageimages/nanoleaf.1.3.4.png", + "images": [] + }, + "nant": { + "icon": "https://community.chocolatey.org/content/packageimages/NAnt.0.92.2.png", + "images": [] + }, + "nanum-gothic-coding-font": { + "icon": "https://community.chocolatey.org/content/packageimages/nanum-gothic-coding-font.2.5.1.20180701.png", + "images": [] + }, + "naps2": { + "icon": "", + "images": [ + "https://i.postimg.cc/25B0gqTv/1.png", + "https://i.postimg.cc/JnVp81dF/2.png", + "https://i.postimg.cc/FzGp00st/3.png", + "https://i.postimg.cc/gJVNkfC2/4.png", + "https://i.postimg.cc/brqLGmPH/5.png", + "https://i.postimg.cc/Wp75Rcm9/6.png", + "https://i.postimg.cc/wTT0g409/7.png" + ] + }, + "naps2-prerelease": { + "icon": "", + "images": [] + }, + "narrange": { + "icon": "", + "images": [] + }, + "nasm": { + "icon": "https://community.chocolatey.org/content/packageimages/nasm.2.16.01.20221231.png", + "images": [] + }, + "nassau": { + "icon": "https://community.chocolatey.org/content/packageimages/nassau.portable.1.09.png", + "images": [] + }, + "nateon": { + "icon": "", + "images": [] + }, + "nativeaccess": { + "icon": "", + "images": [] + }, + "nativescript": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/8/86/NativeScript_Logo.png", + "images": [ + "https://preview.nativescript.org/assets/sb_screenshot-e3262412.png", + "https://docs.nativescript.org/assets/WebView.ee7d2fc5.png", + "https://docs.nativescript.org/assets/Image.c71ebc7e.png" + ] + }, + "natron": { + "icon": "https://community.chocolatey.org/content/packageimages/natron.portable.2.5.0.png", + "images": [] + }, + "nats-server": { + "icon": "", + "images": [] + }, + "nats-streaming-server": { + "icon": "https://community.chocolatey.org/content/packageimages/nats-streaming-server.0.3.8.20170209.png", + "images": [] + }, + "natscli": { + "icon": "", + "images": [] + }, + "natural-docs": { + "icon": "", + "images": [] + }, + "naturalreader16": { + "icon": "", + "images": [] + }, + "nautilus": { + "icon": "", + "images": [] + }, + "naverworks": { + "icon": "", + "images": [] + }, + "navfree": { + "icon": "https://community.chocolatey.org/content/packageimages/navfree.2023.200138263.png", + "images": [] + }, + "navi": { + "icon": "", + "images": [] + }, + "navicatpremium": { + "icon": "https://i.postimg.cc/ZqwHmRrC/navicat.png", + "images": [ + "https://i.postimg.cc/7LK5Qyw1/image.png", + "https://i.postimg.cc/DZD8ndW8/image.png", + "https://i.postimg.cc/c6GC8xBW/image.png", + "https://i.postimg.cc/02SVS9qB/image.png" + ] + }, + "navicatpremiumlite": { + "icon": "https://i.postimg.cc/1RprsTC3/navicatlite.png", + "images": [ + "https://i.postimg.cc/25snfFnf/image.png", + "https://i.postimg.cc/Hn2M5qRr/image.png", + "https://i.postimg.cc/JztXDdqw/image.png", + "https://i.postimg.cc/Ls1ZvYw7/image.png" + ] + }, + "navicatmysql": { + "icon": "https://i.postimg.cc/7Y26p28r/navsql.png", + "images": [ + "https://i.postimg.cc/Nj7008hK/image.png", + "https://i.postimg.cc/76bPXp5g/image.png", + "https://i.postimg.cc/nVjBhW3J/image.png", + "https://i.postimg.cc/J7fJDQF6/image.png", + "https://i.postimg.cc/DwFX5wnn/image.png", + "https://i.postimg.cc/kgctHPgy/image.png" + ] + }, + "navicatmongodb": { + "icon": "https://i.postimg.cc/KYJ2gJvs/navicatmongo.png", + "images": [ + "https://i.postimg.cc/JnyDtycf/image.png", + "https://i.postimg.cc/tJWstLcs/image.png", + "https://i.postimg.cc/wT5ttYL6/image.png", + "https://i.postimg.cc/DwB8gQx9/image.png", + "https://i.postimg.cc/zBRv8sqY/image.png", + "https://i.postimg.cc/tCbJGvf3/image.png" + ] + }, + "navicatpostgresql": { + "icon": "https://i.postimg.cc/QtmwztWv/navicatpost.png", + "images": [ + "https://i.postimg.cc/x1m72gzN/image.png", + "https://i.postimg.cc/mDmpw50p/image.png", + "https://i.postimg.cc/vTjqR680/image.png", + "https://i.postimg.cc/xTJpvggp/image.png", + "https://i.postimg.cc/k5cTJHX4/image.png" + ] + }, + "navicatoracle": { + "icon": "https://i.postimg.cc/PqPCJpdy/navicatora.png", + "images": [ + "https://i.postimg.cc/gcq2Yq35/image.png", + "https://i.postimg.cc/MpX6bCN4/image.png", + "https://i.postimg.cc/Ssbm4Jsw/image.png", + "https://i.postimg.cc/Y23tc2wX/image.png", + "https://i.postimg.cc/QxdhjL8W/image.png", + "https://i.postimg.cc/SxX4zWzy/image.png", + "https://i.postimg.cc/3RhQ6VfG/image.png" + ] + }, + "navicatredis": { + "icon": "https://i.postimg.cc/W4X7LJXT/navicatredis.png", + "images": [ + "https://i.postimg.cc/15w2xJ6N/image.png", + "https://i.postimg.cc/PqrRwH7d/image.png", + "https://i.postimg.cc/7LsQ1c8w/image.png", + "https://i.postimg.cc/Y9TnZWCF/image.png", + "https://i.postimg.cc/2jBXv20t/image.png", + "https://i.postimg.cc/vHrq2DFQ/image.png" + ] + }, + "navicatmariadb": { + "icon": "", + "images": [ + "https://i.postimg.cc/sgXV3kJc/image.png", + "https://i.postimg.cc/8CfN6L94/image.png", + "https://i.postimg.cc/DwFX5wnn/image.png", + "https://i.postimg.cc/T2JGgd7B/image.png", + "https://i.postimg.cc/2yzs2WcB/image.png" + ] + }, + "navicatsnowflake": { + "icon": "", + "images": [ + "https://i.postimg.cc/ZnKQrSnF/image.png", + "https://i.postimg.cc/BZMkJX7r/image.png", + "https://i.postimg.cc/13Nj0MRP/image.png", + "https://i.postimg.cc/qqRmNxZq/image.png", + "fv" + ] + }, + "navicatsqlite": { + "icon": "https://i.postimg.cc/C1456jNJ/navicatsqlite.png", + "images": [ + "https://i.postimg.cc/Y982xt2q/image.png", + "https://i.postimg.cc/rFDyS6vf/image.png", + "https://i.postimg.cc/DzT2kS80/image.png", + "https://i.postimg.cc/0Q5PjhGs/image.png" + ] + }, + "navicatmonitor": { + "icon": "https://i.postimg.cc/NGPRxcPP/navicatmon.png", + "images": [ + "https://i.postimg.cc/tgPBKg8q/image.png", + "https://i.postimg.cc/c4HXshVs/image.png", + "https://i.postimg.cc/DzVgPTmn/image.png", + "https://i.postimg.cc/bJp949x8/image.png", + "https://i.postimg.cc/KjYr8csh/image.png", + "https://i.postimg.cc/Yqhzc9WW/image.png" + ] + }, + "navicatdatamodeler": { + "icon": "https://i.postimg.cc/vHhVPnWM/navdatamod.png", + "images": [ + "https://i.postimg.cc/FsjwLDTC/image.png", + "https://i.postimg.cc/C1BQLNZj/image.png", + "https://i.postimg.cc/wTdGgD98/image.png", + "https://i.postimg.cc/RZSpn932/image.png" + ] + }, + "navicatdatamodelerlite": { + "icon": "https://i.postimg.cc/qMx4TJHd/modelerlite.png", + "images": [ + "https://i.postimg.cc/FsjwLDTC/image.png", + "https://i.postimg.cc/C1BQLNZj/image.png", + "https://i.postimg.cc/wTdGgD98/image.png", + "https://i.postimg.cc/RZSpn932/image.png" + ] + }, + "navicatonpremserver": { + "icon": "", + "images": [ + "https://i.postimg.cc/d3nrMMq0/image.png", + "https://i.postimg.cc/Y02LzX17/image.png", + "https://i.postimg.cc/9MCDcxg4/image.png", + "https://i.postimg.cc/mkh2rKYy/image.png" + ] + }, + "navicatsqlserver": { + "icon": "", + "images": [ + "https://i.postimg.cc/d3b8J2bx/image.png", + "https://i.postimg.cc/PrDW27D0/image.png", + "https://i.postimg.cc/HLYbWshB/image.png", + "https://i.postimg.cc/G29YYgrN/image.png", + "https://i.postimg.cc/2jVgGnxK/image.png" + ] + }, + "nbfc": { + "icon": "", + "images": [] + }, + "nbtexplorer": { + "icon": "https://i.postimg.cc/BZFQ1C1R/NBTExplorer.png", + "images": [] + }, + "ncalayer": { + "icon": "", + "images": [] + }, + "ncftp": { + "icon": "", + "images": [] + }, + "ncftpclient": { + "icon": "", + "images": [] + }, + "ncmpc": { + "icon": "", + "images": [] + }, + "ncollector-studio-lite": { + "icon": "https://community.chocolatey.org/content/packageimages/ncollector-studio-lite.4.0.0.png", + "images": [] + }, + "nconvert": { + "icon": "", + "images": [] + }, + "ncrunch-console": { + "icon": "https://community.chocolatey.org/content/packageimages/ncrunch-console.4.16.4.png", + "images": [] + }, + "ncrunch-gridnodeserver": { + "icon": "https://community.chocolatey.org/content/packageimages/ncrunch-gridnodeserver.4.16.4.png", + "images": [] + }, + "ncrunch-vs2008": { + "icon": "https://community.chocolatey.org/content/packageimages/ncrunch-vs2008.4.8.3.png", + "images": [] + }, + "ncrunch-vs2010": { + "icon": "", + "images": [] + }, + "ncrunch-vs2012": { + "icon": "https://community.chocolatey.org/content/packageimages/ncrunch-vs2012.4.16.4.png", + "images": [] + }, + "ncrunch-vs2013": { + "icon": "https://community.chocolatey.org/content/packageimages/ncrunch.vs2013.0.0.0.0.png", + "images": [] + }, + "ncrunch-vs2015": { + "icon": "https://community.chocolatey.org/content/packageimages/ncrunch-vs2015.4.16.4.png", + "images": [] + }, + "ncrunch-vs2017": { + "icon": "https://community.chocolatey.org/content/packageimages/ncrunch-vs2017.4.16.4.png", + "images": [] + }, + "ncrunch-vs2019": { + "icon": "https://community.chocolatey.org/content/packageimages/ncrunch-vs2019.4.16.4.png", + "images": [] + }, + "ncrunch-vs2022": { + "icon": "https://community.chocolatey.org/content/packageimages/ncrunch-vs2022.4.16.4.png", + "images": [] + }, + "ncspot": { + "icon": "", + "images": [] + }, + "ndi5runtime": { + "icon": "", + "images": [] + }, + "ndi5tools": { + "icon": "", + "images": [] + }, + "nditools": { + "icon": "https://i.postimg.cc/t4nMK0N7/nditools.png", + "images": [ + "https://i.postimg.cc/RZpD8SHp/ndi-tools.png" + ] + }, + "ndm": { + "icon": "https://i.imgur.com/Q3bnbu1.png", + "images": [] + }, + "neat": { + "icon": "", + "images": [] + }, + "neatconverter": { + "icon": "", + "images": [] + }, + "neatdownloadmanager": { + "icon": "", + "images": [] + }, + "neatify": { + "icon": "", + "images": [] + }, + "neatreader": { + "icon": "", + "images": [] + }, + "neck-diagrams": { + "icon": "https://community.chocolatey.org/content/packageimages/neck-diagrams.2.3.4.png", + "images": [] + }, + "nefcon": { + "icon": "", + "images": [] + }, + "neftest-consolerunner": { + "icon": "https://community.chocolatey.org/content/packageimages/NefTest.ConsoleRunner.1.0.0.png", + "images": [] + }, + "negativeencoder": { + "icon": "", + "images": [] + }, + "neko": { + "icon": "https://community.chocolatey.org/content/packageimages/neko.2.3.0.png", + "images": [] + }, + "nekoray": { + "icon": "", + "images": [] + }, + "nelson": { + "icon": "https://community.chocolatey.org/content/packageimages/nelson.0.7.1.2683.png", + "images": [] + }, + "neo-cowsay": { + "icon": "", + "images": [] + }, + "neo4j-community": { + "icon": "https://community.chocolatey.org/content/packageimages/neo4j-community.3.5.1.png", + "images": [] + }, + "neofetch": { + "icon": "", + "images": [ + "https://zv915ylvcs.ufs.sh/f/fYIgEizARqiSu7FpAit2c9F5IJV04zYrBXaySm7AGhM1vkEU" + ] + }, + "neoload": { + "icon": "", + "images": [] + }, + "neovide": { + "icon": "", + "images": [] + }, + "neoviewer": { + "icon": "", + "images": [] + }, + "neovim": { + "icon": "https://community.chocolatey.org/content/packageimages/neovim.0.8.3.png", + "images": [] + }, + "neovim-nightly": { + "icon": "", + "images": [] + }, + "neovim-qt": { + "icon": "", + "images": [] + }, + "nerd-fonts-3270": { + "icon": "", + "images": [] + }, + "nerd-fonts-agave": { + "icon": "", + "images": [] + }, + "nerd-fonts-bitstreamverasansmono": { + "icon": "", + "images": [] + }, + "nerd-fonts-cascadiacode": { + "icon": "", + "images": [] + }, + "nerd-fonts-delugiabook": { + "icon": "", + "images": [] + }, + "nerd-fonts-delugiacomplete": { + "icon": "", + "images": [] + }, + "nerd-fonts-delugiamono-complete": { + "icon": "", + "images": [] + }, + "nerd-fonts-delugiamono-powerline": { + "icon": "", + "images": [] + }, + "nerd-fonts-delugiapowerline": { + "icon": "", + "images": [] + }, + "nerd-fonts-firacode": { + "icon": "", + "images": [] + }, + "nerd-fonts-hack": { + "icon": "", + "images": [] + }, + "nerd-fonts-hermit": { + "icon": "", + "images": [] + }, + "nerd-fonts-iosevka": { + "icon": "", + "images": [] + }, + "nerd-fonts-jetbrainsmono": { + "icon": "", + "images": [] + }, + "nerd-fonts-lekton": { + "icon": "", + "images": [] + }, + "nerd-fonts-monofur": { + "icon": "", + "images": [] + }, + "nerd-fonts-mononoki": { + "icon": "", + "images": [] + }, + "nerd-fonts-mplus": { + "icon": "", + "images": [] + }, + "nerd-fonts-opendyslexic": { + "icon": "", + "images": [] + }, + "nerd-fonts-overpass": { + "icon": "", + "images": [] + }, + "nerd-fonts-profont": { + "icon": "", + "images": [] + }, + "nerd-fonts-sourcecodepro": { + "icon": "", + "images": [] + }, + "nerd-fonts-terminus": { + "icon": "", + "images": [] + }, + "nerd-fonts-ubuntu": { + "icon": "", + "images": [] + }, + "nerd-fonts-victormono": { + "icon": "", + "images": [] + }, + "nerdctl": { + "icon": "", + "images": [] + }, + "nerdfont-hack": { + "icon": "https://community.chocolatey.org/content/packageimages/nerdfont-hack.2.1.0.png", + "images": [] + }, + "nero-aac": { + "icon": "https://community.chocolatey.org/content/packageimages/nero-aac.1.5.4.png", + "images": [] + }, + "nertivia": { + "icon": "", + "images": [] + }, + "nervatura": { + "icon": "", + "images": [] + }, + "nessus": { + "icon": "", + "images": [] + }, + "nessus-agent": { + "icon": "https://community.chocolatey.org/content/packageimages/nessus-agent.10.3.1.png", + "images": [] + }, + "nestopia": { + "icon": "https://community.chocolatey.org/content/packageimages/Nestopia.1.40.20191010.png", + "images": [] + }, + "net-check": { + "icon": "", + "images": [] + }, + "net-reactor-slayer": { + "icon": "https://community.chocolatey.org/content/packageimages/net-reactor-slayer.6.4.0.0.png", + "images": [] + }, + "netbakreplicator": { + "icon": "", + "images": [ + "https://i.postimg.cc/B66rS0VX/image.png", + "https://i.postimg.cc/ZRM10MGj/image.png", + "https://i.postimg.cc/zGq5s98R/image.png", + "https://i.postimg.cc/W1YK5K3V/image.png" + ] + }, + "netbalancer": { + "icon": "https://community.chocolatey.org/content/packageimages/netbalancer.9.5.2.png", + "images": [] + }, + "netbeans": { + "icon": "https://community.chocolatey.org/content/packageimages/NetBeans.8.2.20171030.png", + "images": [] + }, + "netbeans-jee": { + "icon": "https://community.chocolatey.org/content/packageimages/netbeans-jee.8.1.png", + "images": [] + }, + "netbeans-php": { + "icon": "https://community.chocolatey.org/content/packageimages/netbeans-php.8.2.png", + "images": [] + }, + "netbird": { + "icon": "https://netbird.io/icon.png", + "images": [] + }, + "netbscanner": { + "icon": "https://community.chocolatey.org/content/packageimages/netbscanner.1.11.png", + "images": [ + "https://i.postimg.cc/GmnP542f/image.png" + ] + }, + "netcat": { + "icon": "", + "images": [] + }, + "netcfpowertoys": { + "icon": "https://community.chocolatey.org/content/packageimages/NetCFPowerToys.3.5.0.png", + "images": [] + }, + "netcfsvcutil": { + "icon": "", + "images": [] + }, + "netch": { + "icon": "https://community.chocolatey.org/content/packageimages/netch.1.8.7.png", + "images": [] + }, + "netchat": { + "icon": "", + "images": [] + }, + "netconnectchoose": { + "icon": "https://community.chocolatey.org/content/packageimages/netconnectchoose.1.07.png", + "images": [] + }, + "netcoredbg": { + "icon": "", + "images": [] + }, + "netdrive": { + "icon": "", + "images": [] + }, + "netextender": { + "icon": "", + "images": [] + }, + "netfoxdetective": { + "icon": "", + "images": [] + }, + "netfx-4-0-1-devpack": { + "icon": "https://community.chocolatey.org/content/packageimages/netfx-4.0.1-devpack.4.0.447.20180614.png", + "images": [] + }, + "netfx-4-0-2-devpack": { + "icon": "", + "images": [] + }, + "netfx-4-0-3-devpack": { + "icon": "https://community.chocolatey.org/content/packageimages/netfx-4.0.3-devpack.4.0.551.20180614.png", + "images": [] + }, + "netfx-4-5-2-devpack": { + "icon": "https://community.chocolatey.org/content/packageimages/netfx-4.5.2-devpack.4.5.5165101.20180721.png", + "images": [] + }, + "netfx-4-6-1-devpack": { + "icon": "https://community.chocolatey.org/content/packageimages/netfx-4.6.1-devpack.4.6.01055.00.png", + "images": [] + }, + "netfx-4-6-2": { + "icon": "https://community.chocolatey.org/content/packageimages/netfx-4.6.2.4.6.2.20210905.png", + "images": [] + }, + "netfx-4-6-2-devpack": { + "icon": "https://community.chocolatey.org/content/packageimages/netfx-4.6.2-devpack.4.6.01590.20210905.png", + "images": [] + }, + "netfx-4-7-2": { + "icon": "https://community.chocolatey.org/content/packageimages/netfx-4.7.2.4.7.2.0.png", + "images": [] + }, + "netfx-4-7-2-devpack": { + "icon": "https://community.chocolatey.org/content/packageimages/netfx-4.7.2-devpack.4.7.2.20210903.png", + "images": [] + }, + "netfx-4-8": { + "icon": "https://community.chocolatey.org/content/packageimages/netfx-4.8.4.8.0.20220524.png", + "images": [] + }, + "netfx-4-8-1": { + "icon": "https://community.chocolatey.org/content/packageimages/netfx-4.8.1.4.8.1.0.png", + "images": [] + }, + "netfx-4-8-devpack": { + "icon": "https://community.chocolatey.org/content/packageimages/netfx-4.8-devpack.4.8.0.20190930.png", + "images": [] + }, + "netfx-pcl-reference-assemblies-4-6": { + "icon": "https://community.chocolatey.org/content/packageimages/netfx-pcl-reference-assemblies-4.6.4.6.20150820.png", + "images": [] + }, + "nethack": { + "icon": "https://community.chocolatey.org/content/packageimages/nethack.3.6.7.png", + "images": [] + }, + "nethermind": { + "icon": "", + "images": [] + }, + "netlifyctl": { + "icon": "", + "images": [] + }, + "netlimiter": { + "icon": "https://static.techspot.com/images2/downloads/topdownload/2023/01/2023-01-13-ts3_thumbs-264.png", + "images": [ + "https://www.netlimiter.com/img/hero.png", + "https://www.netlimiter.com/img/features/feature-monitoring.png", + "https://www.netlimiter.com/img/features/feature-bw-control.png", + "https://www.netlimiter.com/img/features/feature-blocker.png", + "https://www.netlimiter.com/img/features/feature-stats.png", + "https://www.netlimiter.com/img/features/feature-cnnhist.png" + ] + }, + "netlimiter-infobar": { + "icon": "https://community.chocolatey.org/content/packageimages/netlimiter-infobar.1.42.0.png", + "images": [] + }, + "netlogo": { + "icon": "https://community.chocolatey.org/content/packageimages/NetLogo.6.3.0.png", + "images": [] + }, + "netmagic": { + "icon": "", + "images": [] + }, + "netmon": { + "icon": "", + "images": [] + }, + "netpass": { + "icon": "https://community.chocolatey.org/content/packageimages/netpass.portable.1.40.png", + "images": [] + }, + "netresview": { + "icon": "https://community.chocolatey.org/content/packageimages/netresview.1.27.png", + "images": [] + }, + "netron": { + "icon": "", + "images": [] + }, + "netrouteview": { + "icon": "https://community.chocolatey.org/content/packageimages/netrouteview.1.30.png", + "images": [ + "https://i.postimg.cc/jjsHRByM/image.png" + ] + }, + "netscan": { + "icon": "https://community.chocolatey.org/content/packageimages/netscan.6.2.1.20161101.png", + "images": [] + }, + "netscan32": { + "icon": "", + "images": [] + }, + "netscan64": { + "icon": "", + "images": [] + }, + "netsend": { + "icon": "", + "images": [] + }, + "netsetman": { + "icon": "", + "images": [] + }, + "netsix": { + "icon": "", + "images": [] + }, + "netspeakerphone": { + "icon": "", + "images": [] + }, + "netstat-agent": { + "icon": "https://community.chocolatey.org/content/packageimages/netstat-agent.3.6.png", + "images": [] + }, + "netstat-viewer": { + "icon": "https://community.chocolatey.org/content/packageimages/netstat-viewer.1.0.20180725.png", + "images": [] + }, + "netstress": { + "icon": "https://community.chocolatey.org/content/packageimages/netstress.2.0.9686.png", + "images": [] + }, + "netstumbler": { + "icon": "", + "images": [] + }, + "netsurf": { + "icon": "https://community.chocolatey.org/content/packageimages/netsurf.3.6.png", + "images": [] + }, + "nettime": { + "icon": "https://community.chocolatey.org/content/packageimages/nettime.3.14.20161102.png", + "images": [] + }, + "nettraffic": { + "icon": "https://community.chocolatey.org/content/packageimages/nettraffic.1.66.2.png", + "images": [] + }, + "network-inventory-advisor": { + "icon": "https://community.chocolatey.org/content/packageimages/network-inventory-advisor.5.0.155.png", + "images": [] + }, + "network-miner": { + "icon": "https://community.chocolatey.org/content/packageimages/network-miner.2.5.png", + "images": [] + }, + "network-profile-name-changer": { + "icon": "", + "images": [] + }, + "networkmanager": { + "icon": "", + "images": [] + }, + "networkminer": { + "icon": "", + "images": [] + }, + "networkmonitor": { + "icon": "", + "images": [] + }, + "networx": { + "icon": "https://community.chocolatey.org/content/packageimages/networx.6.2.5.png", + "images": [ + "https://i.postimg.cc/sxWybn53/image.png", + "https://i.postimg.cc/X7Mn9b0F/image.png", + "https://i.postimg.cc/MGGwzZ1P/image.png", + "https://i.postimg.cc/j5pY6zmP/image.png" + ] + }, + "newfield": { + "icon": "https://community.chocolatey.org/content/packageimages/newfield.install.1.03.png", + "images": [] + }, + "newfiletime": { + "icon": "https://community.chocolatey.org/content/packageimages/newfiletime.6.88.png", + "images": [] + }, + "newrelic": { + "icon": "", + "images": [] + }, + "newrelic-cli": { + "icon": "", + "images": [] + }, + "newrelic-infra": { + "icon": "https://community.chocolatey.org/content/packageimages/newrelic-infra.1.37.2.png", + "images": [] + }, + "newrelic-mssql": { + "icon": "https://community.chocolatey.org/content/packageimages/newrelic-mssql.2.8.7.png", + "images": [] + }, + "newrelicserver": { + "icon": "", + "images": [] + }, + "news-feed-eradicator-for-facebook-chrome": { + "icon": "", + "images": [] + }, + "newsbin": { + "icon": "https://community.chocolatey.org/content/packageimages/newsbin.6.72.png", + "images": [] + }, + "newsleecher": { + "icon": "https://i.postimg.cc/hvDFRpkW/News-Leecher-icon.png", + "images": [ + "https://i.postimg.cc/KzrXWdsD/News-Leecher-1.png" + ] + }, + "newt": { + "icon": "https://community.chocolatey.org/content/packageimages/newt.1.0.0.1.png", + "images": [] + }, + "newzenlauncher": { + "icon": "", + "images": [] + }, + "nextcloud": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/e/ed/Nextcloud-svgrepo-com.svg/512px-Nextcloud-svgrepo-com.svg.png", + "images": [] + }, + "nextcloud-client": { + "icon": "https://community.chocolatey.org/content/packageimages/nextcloud-client.3.7.3.png", + "images": [] + }, + "nextcloud-talk": { + "icon": "https://raw.githubusercontent.com/nextcloud/talk-desktop/main/img/icons/icon.png", + "images": [] + }, + "nextclouddesktop": { + "icon": "https://raw.githubusercontent.com/nextcloud/desktop/master/theme/colored/wizard-nextcloud.png", + "images": [] + }, + "nextdns": { + "icon": "", + "images": [] + }, + "nextdns-cli": { + "icon": "https://community.chocolatey.org/content/packageimages/nextdns-cli.1.37.11.png", + "images": [] + }, + "nextdns-prerelease": { + "icon": "", + "images": [] + }, + "nextiva": { + "icon": "", + "images": [] + }, + "nextivaone": { + "icon": "", + "images": [] + }, + "nexttrace": { + "icon": "", + "images": [] + }, + "nexus-oss": { + "icon": "https://community.chocolatey.org/content/packageimages/nexus-oss.2.15.1.02.png", + "images": [] + }, + "nexus-repository": { + "icon": "https://community.chocolatey.org/content/packageimages/nexus-repository.3.43.0.01.png", + "images": [] + }, + "nexus-repository-oss": { + "icon": "", + "images": [] + }, + "nexus-root-toolkit": { + "icon": "", + "images": [] + }, + "nexusfile": { + "icon": "https://community.chocolatey.org/content/packageimages/nexusfile.portable.5.3.3.5532.png", + "images": [] + }, + "nexusfont": { + "icon": "https://community.chocolatey.org/content/packageimages/nexusfont.portable.2.6.2.png", + "images": [ + "https://i.postimg.cc/GpYkD0gB/image.png" + ] + }, + "nexushell": { + "icon": "", + "images": [] + }, + "nexusimage": { + "icon": "https://community.chocolatey.org/content/packageimages/nexusimage.1.1.3.992.png", + "images": [] + }, + "nfopad": { + "icon": "https://community.chocolatey.org/content/packageimages/nfopad.portable.1.75.png", + "images": [] + }, + "ng": { + "icon": "", + "images": [] + }, + "nginx": { + "icon": "", + "images": [] + }, + "nginx-service": { + "icon": "https://community.chocolatey.org/content/packageimages/nginx-service.1.22.1.png", + "images": [] + }, + "nglide": { + "icon": "", + "images": [] + }, + "ngrok": { + "icon": "", + "images": [] + }, + "ngspice": { + "icon": "https://community.chocolatey.org/content/packageimages/ngspice.38.0.png", + "images": [] + }, + "nheko": { + "icon": "", + "images": [] + }, + "nheko-reborn": { + "icon": "https://community.chocolatey.org/content/packageimages/nheko-reborn.0.11.3.png", + "images": [] + }, + "ni-frcgametools": { + "icon": "https://community.chocolatey.org/content/packageimages/ni-frcgametools.23.0.0.png", + "images": [] + }, + "nice-dcv-client": { + "icon": "https://community.chocolatey.org/content/packageimages/nice-dcv-client.2021.3.7801.png", + "images": [] + }, + "nicepage": { + "icon": "https://community.chocolatey.org/content/packageimages/nicepage.4.14.1.png", + "images": [] + }, + "nicotine-plus": { + "icon": "", + "images": [] + }, + "nift": { + "icon": "https://community.chocolatey.org/content/packageimages/nift.2.4.9.png", + "images": [] + }, + "nightcode": { + "icon": "https://community.chocolatey.org/content/packageimages/nightcode.2.6.0.png", + "images": [] + }, + "nighthawk": { + "icon": "", + "images": [] + }, + "nightingale": { + "icon": "", + "images": [] + }, + "Winget.Nilesoft.Shell": { + "icon": "https://nilesoft.org/images/favicon.png", + "images": [ + "https://nilesoft.org/images/screenshots/light/ss2.png", + "https://nilesoft.org/images/screenshots/light/goto.png", + "https://nilesoft.org/images/screenshots/light/ss1.png", + "https://nilesoft.org/images/screenshots/light/file-manage.png" + ] + }, + "nilesoft-shell": { + "icon": "https://nilesoft.org/images/favicon.png", + "images": [ + "https://nilesoft.org/images/screenshots/light/ss2.png", + "https://nilesoft.org/images/screenshots/light/goto.png", + "https://nilesoft.org/images/screenshots/light/ss1.png", + "https://nilesoft.org/images/screenshots/light/file-manage.png" + ] + }, + "nim": { + "icon": "", + "images": [] + }, + "nimblenote": { + "icon": "https://community.chocolatey.org/content/packageimages/nimblenote.3.2.2.png", + "images": [] + }, + "nimbleset": { + "icon": "", + "images": [] + }, + "nimbletext": { + "icon": "", + "images": [] + }, + "nimbusnote": { + "icon": "", + "images": [] + }, + "nina": { + "icon": "", + "images": [] + }, + "ninja": { + "icon": "", + "images": [] + }, + "ninja-kitware": { + "icon": "", + "images": [] + }, + "nircmd": { + "icon": "", + "images": [] + }, + "nirext": { + "icon": "https://community.chocolatey.org/content/packageimages/nirext.1.01.png", + "images": [] + }, + "nirlauncher": { + "icon": "https://community.chocolatey.org/content/packageimages/nirlauncher.1.23.66.png", + "images": [] + }, + "nitronicrush": { + "icon": "", + "images": [] + }, + "nitropro": { + "icon": "", + "images": [] + }, + "nitroreader": { + "icon": "https://community.chocolatey.org/content/packageimages/nitroreader.install.5.5.9.2.png", + "images": [] + }, + "nitroshare": { + "icon": "https://community.chocolatey.org/content/packageimages/nitroshare.0.3.4.png", + "images": [] + }, + "nixpacks": { + "icon": "", + "images": [] + }, + "nk2edit": { + "icon": "https://community.chocolatey.org/content/packageimages/nk2edit.portable.3.40.png", + "images": [ + "https://i.postimg.cc/PxbNNqhp/image.png", + "https://i.postimg.cc/d341mSLH/image.png" + ] + }, + "nmap": { + "icon": "", + "images": [] + }, + "no-cash-psx": { + "icon": "", + "images": [] + }, + "no-ip-duc": { + "icon": "https://community.chocolatey.org/content/packageimages/no-ip-duc.4.1.1.20170207.png", + "images": [] + }, + "noctrlz": { + "icon": "", + "images": [] + }, + "nod32": { + "icon": "", + "images": [] + }, + "node-compiler": { + "icon": "", + "images": [] + }, + "node-explorer": { + "icon": "", + "images": [] + }, + "node-webkit": { + "icon": "", + "images": [] + }, + "node-webkit-0-9-2": { + "icon": "", + "images": [] + }, + "nodejs": { + "icon": "https://raw.githubusercontent.com/nodejs/nodejs.org/main/apps/site/public/static/images/favicons/android-chrome-192x192.png", + "images": [ + "https://i.postimg.cc/02RhVftG/Node-js-logo.png" + ] + }, + "nodejs-lts": { + "icon": "https://raw.githubusercontent.com/nodejs/nodejs.org/main/apps/site/public/static/images/favicons/android-chrome-192x192.png", + "images": [ + "https://i.postimg.cc/02RhVftG/Node-js-logo.png" + ] + }, + "nodejs-nightly": { + "icon": "", + "images": [] + }, + "nodemailer": { + "icon": "", + "images": [] + }, + "nodist": { + "icon": "", + "images": [] + }, + "nohboard": { + "icon": "", + "images": [] + }, + "nomachine": { + "icon": "", + "images": [] + }, + "nomachineclient": { + "icon": "", + "images": [] + }, + "nomacs": { + "icon": "", + "images": [] + }, + "nomad": { + "icon": "https://community.chocolatey.org/content/packageimages/nomad.1.4.4.png", + "images": [] + }, + "nomino": { + "icon": "", + "images": [] + }, + "nordlocker": { + "icon": "https://community.chocolatey.org/content/packageimages/nordlocker.5.1.2.png", + "images": [] + }, + "nordpass": { + "icon": "https://i.postimg.cc/L5mb7DVN/nordpass-logo.png", + "images": [] + }, + "nordvpn": { + "icon": "https://community.chocolatey.org/content/packageimages/nordvpn.6.40.5.png", + "images": [] + }, + "nordvpn-teams": { + "icon": "https://community.chocolatey.org/content/packageimages/nordvpn-teams.2.6.3.png", + "images": [] + }, + "norman": { + "icon": "", + "images": [] + }, + "normcap": { + "icon": "", + "images": [] + }, + "northreader": { + "icon": "", + "images": [] + }, + "norwood": { + "icon": "https://community.chocolatey.org/content/packageimages/norwood.portable.1.03.png", + "images": [] + }, + "noscript": { + "icon": "https://community.chocolatey.org/content/packageimages/noscript.2.9.0.2.png", + "images": [] + }, + "nosql-workbench": { + "icon": "https://community.chocolatey.org/content/packageimages/nosql-workbench.3.3.0.png", + "images": [] + }, + "nosqlbooster": { + "icon": "", + "images": [] + }, + "nosqlworkbench": { + "icon": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAOEAAADhCAMAAAAJbSJIAAABIFBMVEUAHDL///8JvvfiHFmZR5n6ZgUAHDDlHFoAHC4AGS/sHFsJwvzoHFuUHEgAABkGkr8JKkAbHDMbxfzV8/6DHETdHFnBHFIpHDR5PYH/awAAFyYAEjV2HEIAAAAAvPhaHD1jHD4AGDMADyaQRJIAABtSHDtuHEAJHy98HEPMHFXnYQsAABTRWREAAA4AFTTv+/8Ju/AFbpEaIS9JHDkIqNc0HDeCQCOJQYxj1/6I4f4EXXxAHDjo+v8GiLAizP0IsuWz6/4GfaKwHE6i5v4CNEwEX38DQ17F8P5P0/4Fc5WiHEvpYQpZMmaKQyLHVRVILVvJVxQDS2csIzBpN3NwOCc0J0yqTRy4URhQLyt2OiZkNCkuJEYDMU2YRx86Jy0HncxNn4YeAAAQZ0lEQVR4nO2dC1vayBrHadgGQhB0FBWttKaxq0uRsNJTb0BRRHG7bmnPtns5Z/n+3+LkQi5zSTKTzATs8f/0eeojksyPdzLzzj9h3tyz7125LE/Wvj07vTs9u769zPCkmRFeXp/2gdRo2P9UcPqhndGJMyK8vVNNsoAaDfU0m0hmQnjblwhqgEwYMyBcv4PDF1AWcRROaPKF4NlxFM8omHD9VI3gc/rqmVhGoYSXpyoSQFVVgapijCLHVYGE6yifCoxZr9MZzgygZscojBCLn6pWp0pF1zS9otx0Ucb+taiGCCJsnwKke4LealPJOVK01rTbR+MoiFEI4eUZ1j+ruYrL50DuTbE4imEUQHh5BlC+2SrMZ0lr4owi+ip3wjbG15+Nmhifw3g+QDpzo/+Bd4M4E+J8YDZqEflsxj3xjFwJSXxjvH9CjJUbwYw8CQn9cxweP49RvzFEMnIjJMSvO96L5XP6qsg4ciJsX+N80+j+Ccexg8fxlk/T+BBe95H8sz+YtjRaPptRQxkb0h0XRh6EaPwkMDjfY+KzGVsTLI48GNMTfkDjZ/LpzHxOHIcGuti6W180Ic5ndJLxWdKVIZrmqGkZ0xHeEvjY+2dAiq6jjJJ6mooxDeHtHdKlVGOipeFz4ij3cMYUNkBywvU7CZ0ghoqels+KY2UVZWyop4mXyEkJMYPJXADqOvUEGMPYzFUxxqR2TjLC9TtsAdhb5RE/j7EymqF9NaHVkYSQYMD0CAvAlIyt8QyzAc4yISTwVYu8+VxGDjYAKyFuMIHqSASfzVgZp7cB2Ahxvn41ZAHPidGyrCSEkW3ZwUJIiN9sNX4BmE7a3jTd0oqekGQwxSzgOTHqqawOWsL2GZpnUC3gOTESrI47WkY6wjZugHYz47MZk9sANIQkg2IqcnwhMmqondOQqGwACkKUT+p3GRfwnBhxq0OiiGMcIRY/c4E7TbVASsO4h9sAsXGMIcQMmMQLeE6MygSzAWIYIwlxPqPTXCBfzloi4zZAtGUVQYgbTEZnEdcfxqj1sNvIEYyhhFj8uCzg+UjHlsgRllUIIWYwmQt4jecCMJ2U5qiKLq3CGImEmMGkSiZfxhNgtJTmKmoDSA2iZUUgvMUMGGMoL0/8XCmVEW51ECwrjJBsMC1V/FxZfTWeMYfxwQLGpKItJZ8lpSnHWlYQIb4ANCbKkoyfISL1VdiyChLiCfayjS8kmX0Vs6yCVodPiA6gj4PPktIa4XbOOkrYPpUQvt4Sjp9hUrAnVxrgA0x4CQfQNngfRfxcaS3U6micBQkvoSsQf4LpMQh7cmWO6BAGI2g9AfP4+CyhS+TGtUd4FgAE3XHWBgU/afokeDmCyznhpQ+uGud0T4gsq7TgHdbG3ZzQDyEYVpZ7gqeQvtr1IqauO4TeL8BNa9Ht4yClWXWjaA02JuGtBzhpLrp1fLQ3cBH7NqHXSQd7jEeSZTm3JlzmaRjbpYzdbqleWoTuvR21w3gNyodXR7V8QbRqR/dbjIytrhvEDyZh2+NdZRtFTwqlQiGfgQrl0gobotYB3oWYe3bp4g4qTEfJ1TLBc1R6ydQ0v5uemoTrbghnbOPMy1J2gPnyFVMQlVU3hn2LcD7QqFW2GB5mSVg4KiYilEByQvn7J9x4HITttISFUi1fsoecUr5Gp1KCEWpxhOXNi5xyYI2qtQPad77bLD8iwpp1YnmrlC+9Yxjsao+HsHxvcxWPmFogbzL304UT1r5bwnze7qUXZi89oe6lco6Vb5GEhdqrrXeHVkjKG++26PTyiH0wTUcopYlhoVQuOxNj2fyJStnPFup3PeM/S0z4mPLSJ8L/W8IDa8AoFMoFa/AQrqsFEFoHsp0iewp4Z+vC0ompA0gvIb1CBL0YeJd1HPNw9oG32AwWboRLqyfCx68nwsevJ8LHLz6Eyok9tb0J6kW43oSIOCtaE6MzG9oy58O17AnNtUVmMpOmhJ53SsLvPC/9ngiP9yEdK4skLAYlF0O42Qg/f/rlp4B++emfBRIWv7yG9HEnPeHuQ/05pPq/94OEhdLcdylQjxspCHde/wDrd+IIxEb403OE8F9BwvLVxsam9VNpc2WDSof3KZyonfcI4cf0hPt1lPDXAGHpoijLRfPH0ob5A52KB+z9OzSGX4jdlInwxyjCgrP0LtbyBYaxrpjc88YIt9MT/owRBnqpf9+ilo2rnzlhYdOJYTlfYsg5iuym98II86UX5nUlX5XNESdnTU80SjLPLI4wX6ptbuat8b+c36RULcFEukBCy1B0W0Epdr4FE2aiJ0JBhJR303ioJJCwWK/XSYS5rcOV7LRx4rRm5wf+hPtfvz18+vTW1aeHhz8cwhxtlsZF7uf98cv29vZ7V9vbv6XPS3PHx7uQjveJf5aR5B1Y5ETjyWt7/HoifPx6IoSFDKW7x+4L1It6Dip60wX/sfT461tYD/MXDtifMEyetBXmD+sXP26/f/36vS8OTtRxHfXa5jN+ts9ibIY5UURvga2XYnnpX4sgzNSJ+nOZCAWuLRZDWBRA+PmJ8NETfv+9tMg40hQKZee2rf2dM/tHDt9wcx1nESMNft9iPlu8wAlNovzR1cqbky13eay8O3ixcnWULyV5MJhEiM6HHAh3n9cDPob18x9EwnKpfHT/4kIJLMgdWb9YOzm8qqWhDCX8kn7G3//127eHT76J8e3r/IUgYaFUvnqzhbJBnEX5YuMoOeSc0MzaLA/jtZ25bW9/+fI38WxsOc0+bGMcu5m3T2jivZQp7szIxTUTMskNUo8QdTG43OUOk0tYqq2s0X/XQr64LydhZLm3xZewVDtk/Kp1ce0+QRwXQfimZH0j77DI+lVyK5D3zNfjYggLpfscxqegzytrOr6TlnyxyZgvLIawdoHwKVqrKf8H/l1z0rsZtZooZfGwzBRGkYTHiCXsjqUnK/BJFb05HnalvgGxaJ2+CvrSrLPagiFlhSmMLqEAF2P/v98Ctv4nc0L87LYRItFHwwEAqgRugjszKJpzKhWAbgfZuKi4wXA1evOhOQs6clwMDq7+j2F3ZoIH1PWOiWcfpQttrtHythmxIKtjaPda+aRW9hLZmPxVYNaGr/ExQk0ZAu+Io2CctBto5ya1PziHNsApbpq53tXK4ZuDg1fz/DXk8syU8E+YUGl2/I1vwTC4BZoyQncZVcHgPLhJk/xyzU1k7f/fvVrZJCWwIjPvsCeGXAW39JGkAbQ9yl4XJZTsjaii9vkxE9iTFSy3E7l6io6h0oS2nuqPg4R6B2B8dl+txmxmayawK/DX9rMl/Oy/qOWCATQPEYyOfxqM0ZjGzb2y/OoowCjSa0MJ6189Wz9XmcJbTxtQQtOahdcCBr3YLcVk+eVRCSUU4WIghPW3PmBrAgcJngo1ch91/7aLpXe4im9q5exj6LerMoQR1Bl0AMWc/33hPXWw6n0emm5JI+SvuatSxjF0LQxTLQRQAsguTOOOp0mVgGi4iNp5rzqr9obno2YLTdOLr+wJ0r1vkYzQPSMFYf3XXff3zQkKOEF2A1U0T3tD0iVpzD8SvepEG/RBtzdV4Cxdzh2V0hJG7zgAEfoXoX6DAKqD8O1OK+in4b7FuRaVqZ/aqUCancM7M8tmT82KsP7Z7aPaFG0zGIfOceiI5CPOk1gF/i0wetDut8WVUmH+nRnBhPWvu9gRvGb1QvfRwvpz4GPp2edsovOKCnq5wAdmrkLuxRHKgRj+7P6yNUCvKyO0j4ZkNvMGTC0QwsSigk4gjMWVTAj9uV5Hh1EJnIf1Uf08alqUDOt9eIZuHbLrTyfeWlQw4Wfs/d4nPgtLpmMA571bH5BeAudYi9gJ4/c28Qkf3BA2sdkNnQo94SMSFirrrTphvrReG6IXdyLCW8oYundkCCE0r5kQwHEcoLPVn0acL80DV5HtONmzNgbC5+5AqmPNAbriKwg4igV0XIHQHBZU4SiKJKw/uIQtA2vHzcjWeDwejQKAocunoKzzamj+4B8anoUSEVJeh549o0z7eDvMLBs46g/dEVCRsbI+ZJn5XSghsmBJRHgZnXl7hP/MfxEyKngtcucNJUcJCDpaBCE8ilH7NO6pQWCHVrVLzEpcwl/ckVTDOims+eekaFhWECK124oiVLuBYYyW0Bvh+sFddg3ipD0nrH87Rt9Mbs/EOYqik1wosoAWuVoGgd1/5d+3aQi9T6xh7dD6zK2KoI5Jk5pDWH/rZmxhAzv8MbEAmpdacxL110ZgOSXv7Py2HUvoJbqNa4vw2h1Me6QL0SKsv/1rF3szubHzELYYAM0RYK8X9efqEOpd8k7ut/eRhErOe++tReimbRLIEYIo1+tv/9j1DURiguVpHsJWlWae8DQgGqsBoTmhvPP3dgRhs+cPNNCe7OY1jSPufwvymZ9BpL/kXDKMgJI6ih694BnD0c7adhih7s1n8z3Z/S3L1RnBqoW/XxEz0DSTAJrnjQ4h4nG5jL+/JhEqTT/Zd/fVv/RNBCOu9qZ2HtEY5yrELCoKxLjXc7pl9yAGpLzzESfUNf/zbfQJ9S36s+j6vlrUqGckBIyVWh0Oh5Ob6WoFtqmKCnL/UNOCtQOtEM5rlAQKpaugGlFjW9uLyGjsqzDCs0iDaHtxKjBmnVXo/hx8m1brBPMopwyLQ9iGy7D0yGWQFL3ZiUpUrBBWIrITHjIxu+fkKqFovVm7fodXKwhCtI0gjFGprPo3QkmyQiga0G5dH74HOedDawbPAQP1npBySGi5PB2vxofIaMZ6FrwEuiO4dVjdZ7/SvF+zCynKCYxhoCSn1kKrf2JSzSVCrGfBSyqYBG5eYYWQzAB65eUCddfaSF05VfLKcqK30Ugy9OwAJSuM7qiqNc8H8JIVKvcM1c5bv1OROHYsRkXvxTcddFpjhlw0veY3r/C65H4HxQnx+odg0Gm1RjQrPUOn8iw4SjVWFQWrLY/VeMRqWKI1OoEUN8I4f9bJGtBC1KZdpH+qWC1SijqkVH3PoDVleEo1kA9fJdSTpaslG3+u6gIAETXIdY9D6gHf3jXYIBfPF1a7OrSmM1bzeLkVXrc6oi73B7Qu9/IqqoY8W231pVQDmuDZCJ+10fKyS6hovjhCc/1/pi41YxxfPCGhDPISKZ6PhtBizDxdoRINHx3hcsaRjo+WcPmuR1o+ekKLcXnG1Qa4jm8wM+Hy9FUWPjbC5WCECqdzJzSXyAtmNBfwbbYWsxJaNgDjsmOhfEkI7SXyYvhUdr5khNYSWco+jurZZXzLeBFmv3zEDCbhhNkyJudLQ5ghI26gZUSYEWODYKBlRijeBmiQDMJMCQUzpubjQYjdtVoqPj6EYuKYvn864kP4rM07jqEGL7M4EfK25aIMUEZxIzTFjZF+AU8hnoSc4siVjzMhDzuHdYEbK86E+NMAC+YTQJjG6hDAJ4QwqdWBPGHAS0IIk8RREJ8wQvzJlVi+BAYFlYQR2nfKafkSGTCUEkhI+zSAUD7BhDRxTGNQUEkwYdyTK42GYL4MCG3GEEjh8bOUAWGYnUN4QkuEMiG0GJG5oyGBTPgyIzTnx7M+MC+7hnXtNdT+6QeR42dQmRGaat9en52aOrsVf/X5ypJwMfof6xdjrO2Nee8AAAAASUVORK5CYII=", + "images": [ + "https://miro.medium.com/max/1400/1*rDjQMV1_Qa8CZr2lP2nkIw.png" + ] + }, + "notable": { + "icon": "https://community.chocolatey.org/content/packageimages/notable.1.8.4.png", + "images": [] + }, + "notary": { + "icon": "https://community.chocolatey.org/content/packageimages/notary.0.6.1.png", + "images": [] + }, + "notcl": { + "icon": "", + "images": [] + }, + "notebar": { + "icon": "", + "images": [] + }, + "notebookfancontrol": { + "icon": "https://i.postimg.cc/Sxm3hKbJ/fan.png", + "images": [ + "https://i.postimg.cc/fR5FThM5/image.png" + ] + }, + "noteexplorer": { + "icon": "", + "images": [] + }, + "notehighlight2016": { + "icon": "", + "images": [] + }, + "notejoy": { + "icon": "", + "images": [] + }, + "notepad--": { + "icon": "", + "images": [] + }, + "notepad-dot-qt": { + "icon": "", + "images": [] + }, + "notepad++": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/f/f5/Notepad_plus_plus.png", + "images": [ + "https://notepad-plus-plus.org/assets/images/notepad4ever.png", + "https://i.postimg.cc/k5TCdJV4/image.png", + "https://i.postimg.cc/KjMhLt0k/image.png" + ] + }, + "notepad2": { + "icon": "", + "images": [] + }, + "notepad2-mod": { + "icon": "https://community.chocolatey.org/content/packageimages/notepad2-mod.4.2.25.99800.png", + "images": [] + }, + "notepad2-zufuliu": { + "icon": "", + "images": [] + }, + "notepad2mod": { + "icon": "", + "images": [] + }, + "notepad3": { + "icon": "https://community.chocolatey.org/content/packageimages/notepad3.install.6.23.203.2.png", + "images": [] + }, + "notepadnext": { + "icon": "", + "images": [] + }, + "notepadplusplus": { + "icon": "https://i.postimg.cc/j5vJ5ys8/notepadplusplus.png", + "images": [ + "https://www.portablefreeware.com/screenshots/scrmICQF3.png", + "https://www.cathrinewilhelmsen.net/images/notepad/CathrineWilhelmsenNotepadPlusPlusMultiEditing01.png", + "https://mojeprogramy.com/notepad/pliki/images/screenshots/preferences.png" + ] + }, + "notepadplusplus-commandline": { + "icon": "https://community.chocolatey.org/content/packageimages/notepadplusplus.commandline.8.4.9.png", + "images": [] + }, + "notepadplusplus-plugin-template": { + "icon": "https://community.chocolatey.org/content/packageimages/notepadplusplus-plugin.template.1.0.3.png", + "images": [] + }, + "notepadplusplus-settings": { + "icon": "https://community.chocolatey.org/content/packageimages/Notepadplusplus.Settings.1.0.0.20141029.png", + "images": [] + }, + "notepadreplacer": { + "icon": "https://community.chocolatey.org/content/packageimages/notepadreplacer.1.6.0.20230113.png", + "images": [] + }, + "notepadsapp": { + "icon": "https://store-images.s-microsoft.com/image/apps.50935.13628411695448126.aaaa4dcd-6a65-403d-a558-9a51a7efcd04.f8723b56-2380-4980-91da-41d0bb46fa05", + "images": [ + "https://static.wixstatic.com/media/0fcd80_f13c96da960d491fa8862087ad614ce4~mv2.png/v1/fill/w_972,h_745,al_c,q_90,usm_0.66_1.00_0.01,enc_auto/1.png", + "https://static.wixstatic.com/media/0fcd80_282f2d7627c94d86b22f90c4e0b3448d~mv2.png/v1/fill/w_956,h_744,al_c,q_90,usm_0.66_1.00_0.01,enc_auto/2.png" + ] + }, + "notepanda": { + "icon": "", + "images": [] + }, + "notes": { + "icon": "", + "images": [] + }, + "notesnook": { + "icon": "", + "images": [] + }, + "notestationclient": { + "icon": "", + "images": [] + }, + "notetablight": { + "icon": "", + "images": [] + }, + "noti": { + "icon": "", + "images": [] + }, + "notify-me-ci": { + "icon": "https://community.chocolatey.org/content/packageimages/notify-me-ci.1.3.3.13.png", + "images": [] + }, + "notifycli": { + "icon": "", + "images": [] + }, + "notion": { + "icon": "https://i.imgur.com/J4xCzCy.png", + "images": [] + }, + "notion-enhanced": { + "icon": "", + "images": [] + }, + "notion-repackaged": { + "icon": "https://community.chocolatey.org/content/packageimages/notion-repackaged.2.0.18.1.png", + "images": [] + }, + "notionenhanced": { + "icon": "", + "images": [] + }, + "noto": { + "icon": "https://community.chocolatey.org/content/packageimages/Noto.0.20171025.png", + "images": [] + }, + "noty": { + "icon": "", + "images": [] + }, + "nova": { + "icon": "", + "images": [] + }, + "now-cli": { + "icon": "", + "images": [] + }, + "nowtvplayer": { + "icon": "", + "images": [] + }, + "nozbepersonal": { + "icon": "", + "images": [] + }, + "npackd": { + "icon": "https://community.chocolatey.org/content/packageimages/npackd.1.20.5.png", + "images": [] + }, + "npackd-cli": { + "icon": "https://community.chocolatey.org/content/packageimages/npackd-cli.1.20.5.png", + "images": [] + }, + "npiperelay": { + "icon": "", + "images": [] + }, + "npmtaskrunner": { + "icon": "", + "images": [] + }, + "npppluginmanager": { + "icon": "https://community.chocolatey.org/content/packageimages/npppluginmanager.1.4.12.png", + "images": [] + }, + "nrf-connect": { + "icon": "", + "images": [] + }, + "nrf-sdk": { + "icon": "", + "images": [] + }, + "nrfjprog": { + "icon": "https://community.chocolatey.org/content/packageimages/nrfjprog.10.16.0.png", + "images": [] + }, + "nsbuilder": { + "icon": "https://community.chocolatey.org/content/packageimages/nsbuilder.2018.9.11.png", + "images": [] + }, + "nservicebus": { + "icon": "", + "images": [] + }, + "nsis": { + "icon": "https://community.chocolatey.org/content/packageimages/nsis.install.3.08.png", + "images": [] + }, + "nsis-advancedlogging": { + "icon": "https://community.chocolatey.org/content/packageimages/nsis-advancedlogging.3.04.0.20190220.png", + "images": [] + }, + "nsis-unicode": { + "icon": "", + "images": [] + }, + "nsolid-console": { + "icon": "https://community.chocolatey.org/content/packageimages/nsolid-console.4.6.3.png", + "images": [] + }, + "nsolid-dubnium": { + "icon": "https://community.chocolatey.org/content/packageimages/nsolid-dubnium.4.5.3.png", + "images": [] + }, + "nsolid-erbium": { + "icon": "https://community.chocolatey.org/content/packageimages/nsolid-erbium.4.6.2.png", + "images": [] + }, + "nsolid-fermium": { + "icon": "https://community.chocolatey.org/content/packageimages/nsolid-fermium.4.6.3.png", + "images": [] + }, + "nsolid-gallium": { + "icon": "https://community.chocolatey.org/content/packageimages/nsolid-gallium.4.6.3.png", + "images": [] + }, + "nssm": { + "icon": "https://community.chocolatey.org/content/packageimages/NSSM.2.24.101.20180116.png", + "images": [] + }, + "nsudo": { + "icon": "https://community.chocolatey.org/content/packageimages/nsudo.8.0.1.png", + "images": [] + }, + "nswagstudio": { + "icon": "https://community.chocolatey.org/content/packageimages/NSwagStudio.13.18.2.png", + "images": [] + }, + "ntag": { + "icon": "", + "images": [] + }, + "nteract": { + "icon": "https://community.chocolatey.org/content/packageimages/nteract.install.0.28.0.png", + "images": [] + }, + "ntfs2btrfs": { + "icon": "", + "images": [] + }, + "ntfsdatarecovery": { + "icon": "", + "images": [] + }, + "ntfsinfo": { + "icon": "", + "images": [] + }, + "ntfssecurity-psmodule": { + "icon": "https://community.chocolatey.org/content/packageimages/ntfssecurity-psmodule.4.2.4.png", + "images": [] + }, + "ntfy": { + "icon": "", + "images": [] + }, + "ntlite": { + "icon": "https://i.ibb.co/Zc7n1r1/ntliteicon.png", + "images": [ + "https://i.ibb.co/GWqgwFL/ntlite1.png", + "https://i.ibb.co/2ytYrb8/ntlite2.png", + "https://i.ibb.co/rb5Lkvp/ntlite3.png", + "https://i.ibb.co/jWBRgm4/ntlite4.png", + "https://i.ibb.co/hc8Hsrv/ntlite5.png", + "https://i.ibb.co/4jzfN9J/ntlite6.png", + "https://i.ibb.co/8d49hZ9/ntlite7.png" + ] + }, + "ntlite-free": { + "icon": "", + "images": [] + }, + "ntop": { + "icon": "", + "images": [] + }, + "ntop-portable": { + "icon": "", + "images": [] + }, + "ntstrace": { + "icon": "https://community.chocolatey.org/content/packageimages/ntstrace.1.0.1.1.png", + "images": [] + }, + "ntttcp": { + "icon": "https://community.chocolatey.org/content/packageimages/ntttcp.5.33.png", + "images": [] + }, + "nu": { + "icon": "", + "images": [] + }, + "nubasic": { + "icon": "", + "images": [] + }, + "nuclear": { + "icon": "https://community.chocolatey.org/content/packageimages/nuclear.0.6.17.png", + "images": [] + }, + "nuget": { + "icon": "", + "images": [] + }, + "nuget-commandline": { + "icon": "https://community.chocolatey.org/content/packageimages/NuGet.CommandLine.6.5.0.png", + "images": [] + }, + "nuget-contextmenu": { + "icon": "https://community.chocolatey.org/content/packageimages/NuGet.ContextMenu.1.0.0.20141024.png", + "images": [] + }, + "nuget-credentialprovider-vss": { + "icon": "https://community.chocolatey.org/content/packageimages/nuget-credentialprovider-vss.0.37.0.png", + "images": [] + }, + "nuget-package-explorer": { + "icon": "", + "images": [] + }, + "nugetdefense": { + "icon": "", + "images": [] + }, + "nugetpackageexplorer": { + "icon": "https://community.chocolatey.org/content/packageimages/NugetPackageExplorer.6.0.64.png", + "images": [] + }, + "nugetpackagemanager": { + "icon": "", + "images": [] + }, + "nugetupload": { + "icon": "", + "images": [] + }, + "nullpomino": { + "icon": "", + "images": [] + }, + "numara": { + "icon": "", + "images": [] + }, + "numere": { + "icon": "https://raw.githubusercontent.com/numere-org/Resources/refs/heads/main/icons/app/folder.png", + "images": [ + "https://a.fsdn.com/con/app/proj/numere/screenshots/numere-session-screen.png", + "https://a.fsdn.com/con/app/proj/numere/screenshots/promotion_1.png", + "https://a.fsdn.com/con/app/proj/numere/screenshots/promotion_2.png" + ] + }, + "numpy": { + "icon": "https://images.seeklogo.com/logo-png/39/1/numpy-logo-png_seeklogo-398690.png", + "images": [] + }, + "nunit": { + "icon": "", + "images": [] + }, + "nunit-console": { + "icon": "", + "images": [] + }, + "nunit-console-runner": { + "icon": "https://community.chocolatey.org/content/packageimages/nunit-console-runner.3.16.3.png", + "images": [] + }, + "nunit-extension-net20-pluggable-agent": { + "icon": "https://community.chocolatey.org/content/packageimages/nunit-extension-net20-pluggable-agent.2.0.0.png", + "images": [] + }, + "nunit-extension-nunit-project-loader": { + "icon": "", + "images": [] + }, + "nunit-extension-nunit-v2-driver": { + "icon": "https://community.chocolatey.org/content/packageimages/nunit-extension-nunit-v2-driver.3.9.0.png", + "images": [] + }, + "nunit-extension-nunit-v2-result-writer": { + "icon": "", + "images": [] + }, + "nunit-extension-teamcity-event-listener": { + "icon": "https://community.chocolatey.org/content/packageimages/nunit-extension-teamcity-event-listener.1.0.7.png", + "images": [] + }, + "nunit-extension-vs-project-loader": { + "icon": "", + "images": [] + }, + "nunit-gui": { + "icon": "", + "images": [] + }, + "nunit-project-editor": { + "icon": "https://community.chocolatey.org/content/packageimages/nunit-project-editor.1.0.png", + "images": [] + }, + "nunustudio": { + "icon": "", + "images": [] + }, + "nushell": { + "icon": "https://community.chocolatey.org/content/packageimages/nushell.install.0.74.0.png", + "images": [] + }, + "nutstore": { + "icon": "", + "images": [] + }, + "nutstorelightapp": { + "icon": "", + "images": [] + }, + "nvcleanstall": { + "icon": "https://tpucdn.com/download/images/133_icon-v1669381101081.png", + "images": [ + "https://tpucdn.com/nvcleanstall/screen-2-v1669381101081.png" + ] + }, + "nvda": { + "icon": "https://community.chocolatey.org/content/packageimages/nvda.2022.4.png", + "images": [] + }, + "nvidia-broadcast": { + "icon": "https://community.chocolatey.org/content/packageimages/nvidia-broadcast.1.4.0.29.png", + "images": [] + }, + "nvidia-display-driver": { + "icon": "https://community.chocolatey.org/content/packageimages/nvidia-display-driver.528.49.png", + "images": [] + }, + "nvidia-geforce-now": { + "icon": "https://community.chocolatey.org/content/packageimages/nvidia-geforce-now.2.0.49.102.png", + "images": [] + }, + "nvidia-inspector": { + "icon": "https://community.chocolatey.org/content/packageimages/nvidia-inspector.2.3.0.20200706.png", + "images": [] + }, + "nvidia-profile-inspector": { + "icon": "https://community.chocolatey.org/content/packageimages/nvidia-profile-inspector.2.4.0.3.png", + "images": [] + }, + "nvim-ui": { + "icon": "", + "images": [] + }, + "nvm": { + "icon": "https://raw.githubusercontent.com/nodejs/nodejs.org/main/apps/site/public/static/images/favicons/android-chrome-192x192.png", + "images": [] + }, + "nvmforwindows": { + "icon": "https://raw.githubusercontent.com/nodejs/nodejs.org/main/apps/site/public/static/images/favicons/android-chrome-192x192.png", + "images": [] + }, + "nvquicksite": { + "icon": "", + "images": [] + }, + "nvs": { + "icon": "", + "images": [] + }, + "nvui": { + "icon": "", + "images": [] + }, + "nvy": { + "icon": "", + "images": [] + }, + "nwjs": { + "icon": "", + "images": [] + }, + "nwjs-sdk": { + "icon": "", + "images": [] + }, + "nxlog": { + "icon": "https://community.chocolatey.org/content/packageimages/nxlog.3.1.2319.png", + "images": [] + }, + "nxshell": { + "icon": "", + "images": [] + }, + "nxt": { + "icon": "https://community.chocolatey.org/content/packageimages/nxt.1.11.5.png", + "images": [] + }, + "nyagos": { + "icon": "https://community.chocolatey.org/content/packageimages/nyagos.4.4.13.1.png", + "images": [] + }, + "nyanfi": { + "icon": "https://community.chocolatey.org/content/packageimages/nyanfi.14.31.png", + "images": [] + }, + "nyrna": { + "icon": "", + "images": [] + }, + "nytdl": { + "icon": "https://community.chocolatey.org/content/packageimages/nytdl.1.1.25.png", + "images": [] + }, + "nzbget": { + "icon": "", + "images": [] + }, + "nzxt": { + "icon": "", + "images": [] + }, + "nzxt-cam": { + "icon": "https://community.chocolatey.org/content/packageimages/nzxt-cam.3.7.7.png", + "images": [] + }, + "o2": { + "icon": "", + "images": [] + }, + "obdautodoctor": { + "icon": "", + "images": [] + }, + "ober": { + "icon": "", + "images": [] + }, + "obinskit": { + "icon": "", + "images": [] + }, + "objconv": { + "icon": "", + "images": [] + }, + "obs-amd-encoder": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/d/d3/OBS_Studio_Logo.svg/768px-OBS_Studio_Logo.svg.png", + "images": [ + "https://i.imgur.com/Fferqsd.png" + ] + }, + "obs-asio": { + "icon": "", + "images": [] + }, + "obs-move-transition": { + "icon": "https://community.chocolatey.org/content/packageimages/obs-move-transition.2.5.8.png", + "images": [] + }, + "obs-mp": { + "icon": "", + "images": [] + }, + "obs-ndi": { + "icon": "https://community.chocolatey.org/content/packageimages/obs-ndi.4.10.0.png", + "images": [] + }, + "obs-plugin-droidcam": { + "icon": "", + "images": [] + }, + "obs-rtspserver": { + "icon": "", + "images": [] + }, + "obs-studio": { + "icon": "https://community.chocolatey.org/content/packageimages/obs-studio.install.29.0.2.png", + "images": [] + }, + "obs-studio-small": { + "icon": "", + "images": [] + }, + "obs-virtual-cam": { + "icon": "", + "images": [] + }, + "obs-virtualcam": { + "icon": "https://community.chocolatey.org/content/packageimages/obs-virtualcam.2.0.5.png", + "images": [] + }, + "obsidian": { + "icon": "https://raw.githubusercontent.com/Fileover/Assets/main/Others/WingetUI/Obsidian/obsidian-icon.png", + "images": [ + "https://raw.githubusercontent.com/Fileover/Assets/main/Others/WingetUI/Obsidian/obsidian-screen01.png", + "https://raw.githubusercontent.com/Fileover/Assets/main/Others/WingetUI/Obsidian/obsidian-screen02.png" + ] + }, + "obsstudio": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/d/d3/OBS_Studio_Logo.svg/512px-OBS_Studio_Logo.svg.png", + "images": [ + "https://obsproject.com/assets/images/features-new/hero.png" + ] + }, + "obsstudio-pre-release": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/d/d3/OBS_Studio_Logo.svg/512px-OBS_Studio_Logo.svg.png", + "images": [] + }, + "ocaml": { + "icon": "", + "images": [] + }, + "ocaml-ocpwin64": { + "icon": "", + "images": [] + }, + "ocat": { + "icon": "", + "images": [] + }, + "ocenaudio": { + "icon": "https://community.chocolatey.org/content/packageimages/ocenaudio.install.3.11.22.png", + "images": [] + }, + "ocpwin": { + "icon": "", + "images": [] + }, + "ocrtools": { + "icon": "", + "images": [] + }, + "octant": { + "icon": "", + "images": [] + }, + "octave": { + "icon": "https://community.chocolatey.org/content/packageimages/octave.portable.7.3.0.png", + "images": [] + }, + "octobuild": { + "icon": "", + "images": [] + }, + "octofarm": { + "icon": "https://community.chocolatey.org/content/packageimages/octofarm.1.7.3.png", + "images": [] + }, + "octonautscli": { + "icon": "", + "images": [] + }, + "octopi-init": { + "icon": "", + "images": [] + }, + "octopus-cli": { + "icon": "", + "images": [] + }, + "octopusdeploy": { + "icon": "https://community.chocolatey.org/content/packageimages/OctopusDeploy.2022.3.11098.png", + "images": [] + }, + "octopusdeploy-tentacle": { + "icon": "https://community.chocolatey.org/content/packageimages/OctopusDeploy.Tentacle.6.2.277.png", + "images": [] + }, + "octopustools": { + "icon": "", + "images": [] + }, + "octosql": { + "icon": "", + "images": [] + }, + "oculante": { + "icon": "", + "images": [] + }, + "oda-file-converter": { + "icon": "https://community.chocolatey.org/content/packageimages/oda-file-converter.19.12.0.0.png", + "images": [] + }, + "odafileconverter": { + "icon": "", + "images": [] + }, + "odassey": { + "icon": "", + "images": [] + }, + "odo": { + "icon": "", + "images": [] + }, + "odrive": { + "icon": "https://community.chocolatey.org/content/packageimages/odrive.install.1.0.6590.png", + "images": [] + }, + "offcat": { + "icon": "", + "images": [] + }, + "office": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/0/0c/Microsoft_Office_logo_%282013%E2%80%932019%29.svg/250px-Microsoft_Office_logo_%282013%E2%80%932019%29.svg.png", + "images": [] + }, + "office-2010-filterpack": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/0/0c/Microsoft_Office_logo_%282013%E2%80%932019%29.svg/250px-Microsoft_Office_logo_%282013%E2%80%932019%29.svg.png", + "images": [] + }, + "office-2021": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/4/49/Office_2021.png", + "images": [] + }, + "office-online-chrome": { + "icon": "", + "images": [] + }, + "office-readiness-toolkit": { + "icon": "", + "images": [] + }, + "office-to-pdf": { + "icon": "", + "images": [] + }, + "office-tool": { + "icon": "https://community.chocolatey.org/content/packageimages/office-tool.9.0.3.7.png", + "images": [] + }, + "office-tool-plus": { + "icon": "", + "images": [] + }, + "office2013-proofingtools-nl": { + "icon": "https://community.chocolatey.org/content/packageimages/office2013-proofingtools-nl.15.0.4420.1017.png", + "images": [] + }, + "office2019proplus": { + "icon": "https://community.chocolatey.org/content/packageimages/office2019proplus.2019.1808.png", + "images": [] + }, + "office365-2016-deployment-tool": { + "icon": "", + "images": [] + }, + "office365business": { + "icon": "https://community.chocolatey.org/content/packageimages/Office365Business.16026.20170.png", + "images": [] + }, + "office365homepremium": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/0/0e/Microsoft_365_%282022%29.svg/931px-Microsoft_365_%282022%29.svg.png", + "images": [] + }, + "office365proplus": { + "icon": "https://community.chocolatey.org/content/packageimages/Office365ProPlus.15330.20231.png", + "images": [] + }, + "officecustomuieditor": { + "icon": "https://community.chocolatey.org/content/packageimages/officecustomuieditor.1.1.png", + "images": [] + }, + "officedeploymenttool": { + "icon": "", + "images": [] + }, + "officedevtools": { + "icon": "", + "images": [] + }, + "officegate-configuration-tool": { + "icon": "https://community.chocolatey.org/content/packageimages/officegate-configuration-tool.1.2.8.png", + "images": [] + }, + "officeproplus2013": { + "icon": "https://community.chocolatey.org/content/packageimages/OfficeProPlus2013.15.0.4827.png", + "images": [] + }, + "officeribboneditor": { + "icon": "", + "images": [] + }, + "officetab": { + "icon": "", + "images": [] + }, + "officetab-enterprise": { + "icon": "", + "images": [] + }, + "officetabenterprise": { + "icon": "", + "images": [] + }, + "officialapp": { + "icon": "", + "images": [] + }, + "offlineinsiderenroll": { + "icon": "", + "images": [] + }, + "offset-explorer": { + "icon": "https://community.chocolatey.org/content/packageimages/offset-explorer.2.3.2.png", + "images": [] + }, + "ofview": { + "icon": "", + "images": [] + }, + "ogdesigneagle": { + "icon": "https://community.chocolatey.org/content/packageimages/ogdesigneagle.3.0.0.png", + "images": [] + }, + "oh-my-posh": { + "icon": "https://community.chocolatey.org/content/packageimages/oh-my-posh.14.9.1.png", + "images": [] + }, + "oha": { + "icon": "", + "images": [] + }, + "ohhaibrowser": { + "icon": "", + "images": [] + }, + "ohmyposh": { + "icon": "https://i.postimg.cc/x1gnCQxg/icon.png", + "images": [ + "https://i.postimg.cc/PrstV2vb/1.png", + "https://i.postimg.cc/7ZqqwhVf/2.png", + "https://i.postimg.cc/tC39KWFK/3.png" + ] + }, + "ohrrpgce": { + "icon": "", + "images": [] + }, + "ojdkbuild": { + "icon": "", + "images": [] + }, + "ojdkbuild11": { + "icon": "", + "images": [] + }, + "okapi": { + "icon": "", + "images": [] + }, + "okta": { + "icon": "https://community.chocolatey.org/content/packageimages/okta.0.10.0.png", + "images": [] + }, + "okta-core-automation": { + "icon": "https://community.chocolatey.org/content/packageimages/Okta.Core.Automation.0.2.0.0.png", + "images": [] + }, + "okteto": { + "icon": "", + "images": [] + }, + "okular": { + "icon": "https://community.chocolatey.org/content/packageimages/okular.22.08.1.png", + "images": [ + "https://i.postimg.cc/XY7yzmSd/Okular-21-12-1-screenshot.png" + ] + }, + "okular-nightly": { + "icon": "https://community.chocolatey.org/content/packageimages/okular.22.08.1.png", + "images": [] + }, + "oldcalc": { + "icon": "https://community.chocolatey.org/content/packageimages/oldcalc.1.1.20200529.png", + "images": [] + }, + "oldschoolrunescape": { + "icon": "", + "images": [] + }, + "olex2": { + "icon": "https://community.chocolatey.org/content/packageimages/olex2.1.3.0.6408.png", + "images": [] + }, + "olive-editor": { + "icon": "", + "images": [] + }, + "olivevideoeditor": { + "icon": "", + "images": [] + }, + "ollydbg": { + "icon": "https://community.chocolatey.org/content/packageimages/ollydbg.1.10.png", + "images": [] + }, + "olpcli": { + "icon": "", + "images": [] + }, + "omaprevitplugin": { + "icon": "", + "images": [] + }, + "omega-data-logger": { + "icon": "https://community.chocolatey.org/content/packageimages/omega-data-logger.1.3.1.png", + "images": [] + }, + "omegaailink": { + "icon": "", + "images": [] + }, + "omegat": { + "icon": "https://community.chocolatey.org/content/packageimages/omegat.4.3.3.png", + "images": [] + }, + "omnidb-app": { + "icon": "https://community.chocolatey.org/content/packageimages/omnidb-app.2.17.0.png", + "images": [] + }, + "omnidb-server": { + "icon": "https://community.chocolatey.org/content/packageimages/omnidb-server.2.17.0.png", + "images": [] + }, + "omnifyhotspot": { + "icon": "https://community.chocolatey.org/content/packageimages/omnifyhotspot.4.1.png", + "images": [] + }, + "omnisharp": { + "icon": "", + "images": [] + }, + "omnisharp-http": { + "icon": "", + "images": [] + }, + "omsilauncher": { + "icon": "", + "images": [] + }, + "onchrome": { + "icon": "", + "images": [] + }, + "onecommander": { + "icon": "https://onecommander.com/images/apple-touch-icon-114x114.png", + "images": [ + "https://onecommander.com/images/OneCommander-Hero.png" + ] + }, + "onecopy": { + "icon": "", + "images": [] + }, + "onedarkpro-vscode": { + "icon": "https://community.chocolatey.org/content/packageimages/onedarkpro-vscode.3.15.6.png", + "images": [] + }, + "onedrive": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/e/e7/Microsoft_OneDrive_Icon_%282025_-_present%29.svg/512px-Microsoft_OneDrive_Icon_%282025_-_present%29.svg.png", + "images": [ + "https://i.postimg.cc/T3TKcYTW/365.png", + "https://i.postimg.cc/mrDh0XzL/offic.png", + "https://i.postimg.cc/BnNX79v7/OneD.png" + ] + }, + "onedrive-enterprise": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/e/e7/Microsoft_OneDrive_Icon_%282025_-_present%29.svg/512px-Microsoft_OneDrive_Icon_%282025_-_present%29.svg.png", + "images": [] + }, + "onedrive-insiders": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/e/e7/Microsoft_OneDrive_Icon_%282025_-_present%29.svg/512px-Microsoft_OneDrive_Icon_%282025_-_present%29.svg.png", + "images": [] + }, + "onedrive-internal-fast": { + "icon": "", + "images": [] + }, + "onedrive-internal-slow": { + "icon": "", + "images": [] + }, + "onefetch": { + "icon": "", + "images": [] + }, + "onekey": { + "icon": "", + "images": [] + }, + "oneleft": { + "icon": "", + "images": [] + }, + "onemark": { + "icon": "", + "images": [] + }, + "onemore": { + "icon": "", + "images": [] + }, + "onenote": { + "icon": "https://community.chocolatey.org/content/packageimages/onenote.16.0.15330.20246.png", + "images": [] + }, + "onenote-taggingkit-addin": { + "icon": "https://community.chocolatey.org/content/packageimages/onenote-taggingkit-addin.install.5.1.8437.png", + "images": [] + }, + "onenotetaggingkit": { + "icon": "", + "images": [] + }, + "onescript": { + "icon": "https://community.chocolatey.org/content/packageimages/onescript.1.7.0.png", + "images": [] + }, + "onescript-cli": { + "icon": "https://community.chocolatey.org/content/packageimages/onescript-cli.1.2.0.png", + "images": [] + }, + "onetagger": { + "icon": "", + "images": [] + }, + "onetastic": { + "icon": "https://community.chocolatey.org/content/packageimages/onetastic.5.9.0.png", + "images": [] + }, + "oni": { + "icon": "", + "images": [] + }, + "onionshare": { + "icon": "https://community.chocolatey.org/content/packageimages/onionshare.2.6.png", + "images": [] + }, + "onionshare-dev": { + "icon": "", + "images": [] + }, + "online": { + "icon": "https://i.imgur.com/rCxdO5J.png", + "images": [ + "https://i.ytimg.com/vi/YM3c90leQFU/maxresdefault.jpg", + "https://assets.albiononline.com/assets/images/header/header-faye.jpg", + "https://assets.albiononline.com/uploads/media/default/media/f5a6e6b6d986ee3e61ed5ee7b305f792b2bd7bf4.jpeg", + "https://assets.albiononline.com/uploads/media/default/media/thumb_/media/62eb9dceb4de8_default_big.jpeg?cb=2.94.7", + "https://assets.albiononline.com/uploads/media/default/media/1a335a4d9e38600c1b64b7641e28a89c84e5bb75.jpeg" + ] + }, + "onlykeyapp": { + "icon": "https://community.chocolatey.org/content/packageimages/onlykeyapp.5.3.6.png", + "images": [] + }, + "onlym": { + "icon": "", + "images": [] + }, + "onlyoffice": { + "icon": "https://community.chocolatey.org/content/packageimages/onlyoffice.7.3.0.png", + "images": [] + }, + "onlyoffice-desktopeditors": { + "icon": "", + "images": [] + }, + "onlyt": { + "icon": "", + "images": [] + }, + "onscreen-control": { + "icon": "", + "images": [] + }, + "ontopreplica": { + "icon": "", + "images": [] + }, + "ooniprobe-cli": { + "icon": "https://community.chocolatey.org/content/packageimages/ooniprobe-cli.3.8.0.png", + "images": [] + }, + "op": { + "icon": "https://community.chocolatey.org/content/packageimages/op.2.14.0.png", + "images": [] + }, + "opa": { + "icon": "", + "images": [] + }, + "opam": { + "icon": "", + "images": [] + }, + "opautoclicker": { + "icon": "https://i.postimg.cc/1XDdYBp5/image.png", + "images": [ + "https://i.postimg.cc/xTShbr2k/image.png" + ] + }, + "opc-components": { + "icon": "https://community.chocolatey.org/content/packageimages/opc-components.106.0.201.2.png", + "images": [] + }, + "open-dvd-producer": { + "icon": "https://community.chocolatey.org/content/packageimages/open-dvd-producer.16.11.png", + "images": [] + }, + "open-log-viewer": { + "icon": "", + "images": [] + }, + "open-mahjong-java": { + "icon": "", + "images": [] + }, + "open-screenshot-chrome": { + "icon": "", + "images": [] + }, + "open-shell": { + "icon": "", + "images": [] + }, + "open-shell-menu": { + "icon": "", + "images": [ + "https://i.postimg.cc/mZCMz7yz/startmenu3.png" + ] + }, + "open-stage-control": { + "icon": "https://community.chocolatey.org/content/packageimages/open-stage-control.1.21.0.png", + "images": [] + }, + "open-video-downloader": { + "icon": "https://community.chocolatey.org/content/packageimages/open-video-downloader.2.4.0.png", + "images": [] + }, + "open-visual-traceroute": { + "icon": "https://community.chocolatey.org/content/packageimages/open-visual-traceroute.1.7.1.png", + "images": [] + }, + "openal": { + "icon": "", + "images": [] + }, + "openalsdk": { + "icon": "", + "images": [] + }, + "openapi-generator-cli": { + "icon": "", + "images": [] + }, + "openark": { + "icon": "", + "images": [] + }, + "openaudible": { + "icon": "https://community.chocolatey.org/content/packageimages/openaudible.3.6.3.png", + "images": [] + }, + "openbbterminal": { + "icon": "", + "images": [] + }, + "openboard": { + "icon": "", + "images": [] + }, + "openbve": { + "icon": "", + "images": [] + }, + "openchrom": { + "icon": "https://community.chocolatey.org/content/packageimages/openchrom.1.5.0.20230224.png", + "images": [] + }, + "opencl-intel-cpu-runtime": { + "icon": "", + "images": [] + }, + "openclosedriveeject": { + "icon": "", + "images": [] + }, + "opencomic": { + "icon": "", + "images": [] + }, + "opencommandline": { + "icon": "", + "images": [] + }, + "openconnect-gui": { + "icon": "https://community.chocolatey.org/content/packageimages/openconnect-gui.1.5.3.20191209.png", + "images": [] + }, + "opencover": { + "icon": "https://community.chocolatey.org/content/packageimages/opencover.portable.4.7.1221.png", + "images": [] + }, + "opencppcoverage": { + "icon": "", + "images": [] + }, + "opencv": { + "icon": "https://community.chocolatey.org/content/packageimages/OpenCV.4.6.0.png", + "images": [] + }, + "openface": { + "icon": "", + "images": [] + }, + "openfire": { + "icon": "https://community.chocolatey.org/content/packageimages/openfire.4.7.4.png", + "images": [] + }, + "openflexure-ev": { + "icon": "", + "images": [] + }, + "openhab": { + "icon": "", + "images": [] + }, + "openhardwaremonitor": { + "icon": "https://community.chocolatey.org/content/packageimages/OpenHardwareMonitor.0.9.6.20210201.png", + "images": [] + }, + "openhashtab": { + "icon": "https://community.chocolatey.org/content/packageimages/openhashtab.3.0.2.png", + "images": [] + }, + "openhv": { + "icon": "https://community.chocolatey.org/content/packageimages/openhv.2023.02.12.png", + "images": [] + }, + "openinvscode": { + "icon": "", + "images": [] + }, + "openinwsl": { + "icon": "", + "images": [] + }, + "openjdk": { + "icon": "", + "images": [] + }, + "openjdk-11": { + "icon": "https://projects.eclipse.org/sites/default/files/Logo_Adoptium_2021_03_08_JRR_RGB-V3C%20%281%29.png", + "images": [ + "https://adoptopenjdk.net/dist/assets/social-image.png", + "https://www.somkiat.cc/wp-content/uploads/2021/10/adoptium.jpg" + ] + }, + "openjdk-11-jdk": { + "icon": "https://www.basis-europe.eu/wp-content/uploads/openjdk_Icon_logo.png", + "images": [] + }, + "openjdk-11-jre": { + "icon": "https://www.basis-europe.eu/wp-content/uploads/openjdk_Icon_logo.png", + "images": [] + }, + "openjdk-13-jdk": { + "icon": "https://www.basis-europe.eu/wp-content/uploads/openjdk_Icon_logo.png", + "images": [] + }, + "openjdk-14": { + "icon": "https://projects.eclipse.org/sites/default/files/Logo_Adoptium_2021_03_08_JRR_RGB-V3C%20%281%29.png", + "images": [ + "https://adoptopenjdk.net/dist/assets/social-image.png", + "https://www.somkiat.cc/wp-content/uploads/2021/10/adoptium.jpg" + ] + }, + "openjdk-14-jdk": { + "icon": "https://www.basis-europe.eu/wp-content/uploads/openjdk_Icon_logo.png", + "images": [] + }, + "openjdk-15": { + "icon": "https://projects.eclipse.org/sites/default/files/Logo_Adoptium_2021_03_08_JRR_RGB-V3C%20%281%29.png", + "images": [ + "https://adoptopenjdk.net/dist/assets/social-image.png", + "https://www.somkiat.cc/wp-content/uploads/2021/10/adoptium.jpg" + ] + }, + "openjdk-16": { + "icon": "https://projects.eclipse.org/sites/default/files/Logo_Adoptium_2021_03_08_JRR_RGB-V3C%20%281%29.png", + "images": [ + "https://adoptopenjdk.net/dist/assets/social-image.png", + "https://www.somkiat.cc/wp-content/uploads/2021/10/adoptium.jpg" + ] + }, + "openjdk-17": { + "icon": "https://projects.eclipse.org/sites/default/files/Logo_Adoptium_2021_03_08_JRR_RGB-V3C%20%281%29.png", + "images": [ + "https://adoptopenjdk.net/dist/assets/social-image.png", + "https://www.somkiat.cc/wp-content/uploads/2021/10/adoptium.jpg" + ] + }, + "openjdk-17-jdk": { + "icon": "https://www.basis-europe.eu/wp-content/uploads/openjdk_Icon_logo.png", + "images": [] + }, + "openjdk-17-jre": { + "icon": "https://www.basis-europe.eu/wp-content/uploads/openjdk_Icon_logo.png", + "images": [] + }, + "openjdk-8": { + "icon": "https://projects.eclipse.org/sites/default/files/Logo_Adoptium_2021_03_08_JRR_RGB-V3C%20%281%29.png", + "images": [ + "https://adoptopenjdk.net/dist/assets/social-image.png", + "https://www.somkiat.cc/wp-content/uploads/2021/10/adoptium.jpg" + ] + }, + "openjdk11": { + "icon": "", + "images": [] + }, + "openjdk11redhatbuild": { + "icon": "", + "images": [] + }, + "openjdk12": { + "icon": "", + "images": [] + }, + "openjdk13": { + "icon": "", + "images": [] + }, + "openjdk14": { + "icon": "", + "images": [] + }, + "openjdk8redhatbuild": { + "icon": "", + "images": [] + }, + "openkneeboard": { + "icon": "", + "images": [] + }, + "openldap": { + "icon": "https://community.chocolatey.org/content/packageimages/openldap.2.4.39.png", + "images": [] + }, + "openlens": { + "icon": "https://community.chocolatey.org/content/packageimages/openlens.6.3.0.png", + "images": [] + }, + "openliberty": { + "icon": "", + "images": [] + }, + "openlivewriter": { + "icon": "https://community.chocolatey.org/content/packageimages/openlivewriter.0.6.0.0.png", + "images": [] + }, + "openlp": { + "icon": "", + "images": [] + }, + "openmpt": { + "icon": "https://community.chocolatey.org/content/packageimages/openmpt.1.30.10.0.png", + "images": [] + }, + "opennbs": { + "icon": "", + "images": [] + }, + "opennetmeter": { + "icon": "", + "images": [] + }, + "openni-x64": { + "icon": "https://community.chocolatey.org/content/packageimages/openni-x64.2.2.0.33.png", + "images": [] + }, + "openni-x86": { + "icon": "https://community.chocolatey.org/content/packageimages/openni-x86.2.2.0.33.png", + "images": [] + }, + "openocd": { + "icon": "https://community.chocolatey.org/content/packageimages/openocd.0.11.0.20211118.png", + "images": [] + }, + "openocd-xpack": { + "icon": "", + "images": [] + }, + "openoffice": { + "icon": "https://tweakers.net/ext/i/2004673270.png", + "images": [ + "https://tweakers.net/ext/i/1394718028.png" + ] + }, + "openorienteering-mapper": { + "icon": "https://community.chocolatey.org/content/packageimages/openorienteering-mapper.0.9.5.png", + "images": [] + }, + "openosrslauncher": { + "icon": "", + "images": [] + }, + "openpht": { + "icon": "https://community.chocolatey.org/content/packageimages/openpht.1.8.0.png", + "images": [] + }, + "openproject": { + "icon": "https://community.chocolatey.org/content/packageimages/openproject.12.4.5.png", + "images": [] + }, + "openra": { + "icon": "https://community.chocolatey.org/content/packageimages/openra.2023.02.25.png", + "images": [] + }, + "openrct2": { + "icon": "https://community.chocolatey.org/content/packageimages/openrct2.0.4.1.png", + "images": [] + }, + "openresty": { + "icon": "", + "images": [] + }, + "openrgb": { + "icon": "https://community.chocolatey.org/content/packageimages/openrgb.0.8.png", + "images": [] + }, + "openrpa": { + "icon": "", + "images": [] + }, + "opensans": { + "icon": "https://community.chocolatey.org/content/packageimages/OpenSans.2.010.png", + "images": [] + }, + "opensavefilesview": { + "icon": "https://community.chocolatey.org/content/packageimages/opensavefilesview.1.15.png", + "images": [] + }, + "openscad": { + "icon": "https://community.chocolatey.org/content/packageimages/openscad.install.2021.01.png", + "images": [] + }, + "openscap": { + "icon": "", + "images": [] + }, + "opensearch-odbc": { + "icon": "", + "images": [] + }, + "openshark": { + "icon": "", + "images": [] + }, + "openshift-cli": { + "icon": "https://community.chocolatey.org/content/packageimages/openshift-cli.4.12.4.png", + "images": [] + }, + "openshift-okd-client": { + "icon": "", + "images": [] + }, + "openshift-origin-client": { + "icon": "", + "images": [] + }, + "openshot": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/1/17/OpenShot_logo_%282016%29.svg/1200px-OpenShot_logo_%282016%29.svg.png", + "images": [ + "https://i.postimg.cc/0jXvXsrd/image.png", + "https://i.postimg.cc/6q2bwJYh/image.png", + "https://i.postimg.cc/8cM3MgMz/image.png" + ] + }, + "openssh": { + "icon": "https://community.chocolatey.org/content/packageimages/openssh.8.0.0.1.png", + "images": [] + }, + "openssh-beta": { + "icon": "", + "images": [] + }, + "openssh-preview": { + "icon": "https://i.ibb.co/nqFFVBcw/image.png", + "images": [] + }, + "openssl": { + "icon": "", + "images": [] + }, + "openssl-light": { + "icon": "https://community.chocolatey.org/content/packageimages/OpenSSL.Light.3.0.8.png", + "images": [] + }, + "openssl-mingw": { + "icon": "", + "images": [] + }, + "openssl-wizard": { + "icon": "https://community.chocolatey.org/content/packageimages/openssl-wizard.1.3.png", + "images": [] + }, + "opensslkey": { + "icon": "", + "images": [] + }, + "openstego": { + "icon": "", + "images": [] + }, + "openstoreinstaller": { + "icon": "", + "images": [] + }, + "opentabletdriver": { + "icon": "", + "images": [] + }, + "opentelemetry-collector-contrib": { + "icon": "", + "images": [] + }, + "opentoonz": { + "icon": "", + "images": [] + }, + "opentrack": { + "icon": "https://community.chocolatey.org/content/packageimages/opentrack.2022.3.2.png", + "images": [] + }, + "opentracker": { + "icon": "", + "images": [] + }, + "openttd": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/c/c5/Openttdlogo.svg/1200px-Openttdlogo.svg.png", + "images": [ + "https://i.postimg.cc/bvjbJHrf/image.png", + "https://i.postimg.cc/qvghvD4F/image.png", + "https://i.postimg.cc/xd0ZmmpB/image.png", + "https://i.postimg.cc/Hns54Y1Y/image.png", + "https://i.postimg.cc/9Fwz3Rb3/image.png" + ] + }, + "opentyrian": { + "icon": "", + "images": [] + }, + "openutau": { + "icon": "", + "images": [] + }, + "openvpn": { + "icon": "https://postimg.cc/2LQGvMgm", + "images": [] + }, + "openvpn-community": { + "icon": "", + "images": [] + }, + "openvpn-connect": { + "icon": "https://community.chocolatey.org/content/packageimages/openvpn-connect.3.3.7.png", + "images": [] + }, + "openvpnconnect": { + "icon": "https://community.chocolatey.org/content/packageimages/openvpn-connect.3.4.4.png", + "images": [] + }, + "openvr-advancedsettings": { + "icon": "", + "images": [] + }, + "openwebstart": { + "icon": "", + "images": [] + }, + "openwithplusplus": { + "icon": "", + "images": [] + }, + "openwithview": { + "icon": "https://community.chocolatey.org/content/packageimages/openwithview.1.11.png", + "images": [] + }, + "opera": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/4/49/Opera_2015_icon.svg/512px-Opera_2015_icon.svg.png", + "images": [ + "https://i.postimg.cc/T1B5Hqjn/opera.png" + ] + }, + "opera-beta": { + "icon": "", + "images": [] + }, + "opera-developer": { + "icon": "https://community.chocolatey.org/content/packageimages/opera-developer.97.0.4718.0.png", + "images": [] + }, + "opera-gx": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/e/e7/Opera_GX_Icon.svg/512px-Opera_GX_Icon.svg.png", + "images": [] + }, + "operacacheview": { + "icon": "https://community.chocolatey.org/content/packageimages/operacacheview.1.40.png", + "images": [] + }, + "operacrypto": { + "icon": "", + "images": [] + }, + "operagx": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/e/e7/Opera_GX_Icon.svg/512px-Opera_GX_Icon.svg.png", + "images": [] + }, + "opos-cco": { + "icon": "", + "images": [] + }, + "opsview-agent-x32": { + "icon": "", + "images": [] + }, + "opswatsecurityscore": { + "icon": "https://community.chocolatey.org/content/packageimages/opswatsecurityscore.7.0.137.10.png", + "images": [] + }, + "optgeo": { + "icon": "", + "images": [] + }, + "options": { + "icon": "", + "images": [] + }, + "optionsplus": { + "icon": "https://www.logitech.com/assets/66208/optionsplusicon.png", + "images": [] + }, + "optipng": { + "icon": "", + "images": [] + }, + "opus-tools": { + "icon": "", + "images": [] + }, + "oracle-instant-client": { + "icon": "", + "images": [] + }, + "oracle-instant-client-odbc": { + "icon": "", + "images": [] + }, + "oracle-instant-client-sdk": { + "icon": "", + "images": [] + }, + "oracle-sql-developer": { + "icon": "https://community.chocolatey.org/content/packageimages/oracle-sql-developer.20.4.1.20210328.png", + "images": [] + }, + "oracle17jdk": { + "icon": "", + "images": [] + }, + "orange": { + "icon": "", + "images": [] + }, + "orangeplayer": { + "icon": "", + "images": [] + }, + "oras": { + "icon": "", + "images": [] + }, + "orbitron": { + "icon": "", + "images": [] + }, + "orbxcentral": { + "icon": "", + "images": [] + }, + "orca": { + "icon": "https://community.chocolatey.org/content/packageimages/orca.10.0.22621.png", + "images": [] + }, + "orcaslicer": { + "icon": "https://unigeticons.meowcat285.com/OrcaSlicer.png", + "images": [] + }, + "orchardcms": { + "icon": "", + "images": [] + }, + "orfeo-toolbox": { + "icon": "https://community.chocolatey.org/content/packageimages/orfeo-toolbox.8.1.1.png", + "images": [] + }, + "org-ajupdatewatcher": { + "icon": "", + "images": [] + }, + "orgcharting": { + "icon": "", + "images": [] + }, + "orgcharting-cn": { + "icon": "", + "images": [] + }, + "orientdb": { + "icon": "", + "images": [] + }, + "origin": { + "icon": "https://community.chocolatey.org/content/packageimages/origin.10.5.119.52718.png", + "images": [] + }, + "orion": { + "icon": "https://community.chocolatey.org/content/packageimages/orion.1.1.3.png", + "images": [] + }, + "orionsdk": { + "icon": "https://community.chocolatey.org/content/packageimages/orionsdk.3.1.343.png", + "images": [] + }, + "oripa": { + "icon": "", + "images": [] + }, + "ormcore": { + "icon": "", + "images": [] + }, + "ortep3": { + "icon": "https://community.chocolatey.org/content/packageimages/ortep3.2014.1.png", + "images": [] + }, + "orvibos20cli": { + "icon": "", + "images": [] + }, + "orwelldevcpp": { + "icon": "https://community.chocolatey.org/content/packageimages/orwelldevcpp.5.11.png", + "images": [] + }, + "osara": { + "icon": "", + "images": [] + }, + "oscar": { + "icon": "", + "images": [] + }, + "oscar-mouse-editor": { + "icon": "", + "images": [] + }, + "osfmount": { + "icon": "", + "images": [] + }, + "osmc-installer": { + "icon": "", + "images": [] + }, + "ospray": { + "icon": "", + "images": [] + }, + "osquery": { + "icon": "https://community.chocolatey.org/content/packageimages/osquery.5.5.1.png", + "images": [] + }, + "oss-browser": { + "icon": "", + "images": [] + }, + "ossec-client": { + "icon": "https://community.chocolatey.org/content/packageimages/ossec-client.3.7.0.png", + "images": [] + }, + "ossecagent": { + "icon": "", + "images": [] + }, + "ossgadget": { + "icon": "", + "images": [] + }, + "osslsigncode": { + "icon": "", + "images": [] + }, + "ossutil": { + "icon": "", + "images": [] + }, + "ost2": { + "icon": "https://community.chocolatey.org/content/packageimages/ost2.2.13.0.28.png", + "images": [] + }, + "ost2pst-wizard": { + "icon": "https://community.chocolatey.org/content/packageimages/ost2pst-wizard.4.2.png", + "images": [] + }, + "osu!": { + "icon": "https://raw.githubusercontent.com/ppy/osu/master/assets/lazer.png", + "images": [ + "https://i.vgy.me/owQn6h.png", + "https://i.vgy.me/k9A3Pi.png", + "https://i.vgy.me/o7pUyS.png", + "https://i.vgy.me/QnbCFt.png", + "https://i.vgy.me/B5EeB8.png", + "https://i.vgy.me/8KZSAa.png", + "https://i.vgy.me/JEZvI4.png", + "https://i.vgy.me/Bxs34D.png", + "https://i.vgy.me/VDdABh.png" + ] + }, + "osuhelper": { + "icon": "", + "images": [] + }, + "osv-scanner": { + "icon": "https://community.chocolatey.org/content/packageimages/osv-scanner.1.2.0.png", + "images": [] + }, + "otterbrowser": { + "icon": "", + "images": [] + }, + "ouch": { + "icon": "", + "images": [] + }, + "out": { + "icon": "", + "images": [] + }, + "outlinemanager": { + "icon": "", + "images": [] + }, + "outlook-google-calendar-sync": { + "icon": "", + "images": [] + }, + "outlook-photos": { + "icon": "https://community.chocolatey.org/content/packageimages/outlook-photos.2.1.2.0.png", + "images": [] + }, + "outlookcaldav": { + "icon": "https://community.chocolatey.org/content/packageimages/Outlookcaldav.4.3.0.png", + "images": [] + }, + "outlookcaldavsynchronizer": { + "icon": "", + "images": [] + }, + "outlookconverter": { + "icon": "https://community.chocolatey.org/content/packageimages/OutlookConverter.3.1.png", + "images": [] + }, + "outlookstatview": { + "icon": "https://community.chocolatey.org/content/packageimages/outlookstatview.2.17.png", + "images": [] + }, + "outlookviewer": { + "icon": "", + "images": [] + }, + "outlyer-agent": { + "icon": "", + "images": [] + }, + "outwit": { + "icon": "", + "images": [] + }, + "overlaytimer": { + "icon": "", + "images": [] + }, + "overwolf": { + "icon": "https://community.chocolatey.org/content/packageimages/overwolf.2.156.0.2.png", + "images": [] + }, + "ovito-basic": { + "icon": "", + "images": [] + }, + "ovito-pro": { + "icon": "", + "images": [] + }, + "owinhost": { + "icon": "", + "images": [] + }, + "owlplug": { + "icon": "", + "images": [] + }, + "owncloud-client": { + "icon": "https://community.chocolatey.org/content/packageimages/owncloud-client.3.2.0.10193.png", + "images": [] + }, + "ownclouddesktop": { + "icon": "", + "images": [] + }, + "oxipng": { + "icon": "", + "images": [] + }, + "ozcode": { + "icon": "https://community.chocolatey.org/content/packageimages/ozcode.3.0.0.3893.png", + "images": [] + }, + "ozcode-vs2017": { + "icon": "https://community.chocolatey.org/content/packageimages/ozcode-vs2017.4.0.0.19540.png", + "images": [] + }, + "ozcode-vs2022": { + "icon": "https://community.chocolatey.org/content/packageimages/ozcode-vs2022.4.0.0.22253.png", + "images": [] + }, + "p3xredisui": { + "icon": "", + "images": [] + }, + "p4": { + "icon": "https://community.chocolatey.org/content/packageimages/p4.2022.2.png", + "images": [] + }, + "p4d": { + "icon": "https://community.chocolatey.org/content/packageimages/p4d.2018.1.png", + "images": [] + }, + "p4merge": { + "icon": "https://community.chocolatey.org/content/packageimages/P4Merge.2022.3.0.2022112301.png", + "images": [] + }, + "p4v": { + "icon": "https://community.chocolatey.org/content/packageimages/p4v.2022.3.png", + "images": [] + }, + "pacaptr": { + "icon": "", + "images": [] + }, + "pack": { + "icon": "", + "images": [] + }, + "packageinstaller": { + "icon": "", + "images": [] + }, + "packageintellisense": { + "icon": "", + "images": [] + }, + "packer": { + "icon": "https://community.chocolatey.org/content/packageimages/packer.1.8.5.png", + "images": [] + }, + "packer-post-processor-vagrant-vmware-ovf": { + "icon": "", + "images": [] + }, + "packer-windows-plugins": { + "icon": "", + "images": [] + }, + "packetsender": { + "icon": "https://packetsender.com/pslogo64.png", + "images": [] + }, + "packetstream": { + "icon": "https://community.chocolatey.org/content/packageimages/packetstream.20.202.1548.png", + "images": [] + }, + "pacman": { + "icon": "", + "images": [] + }, + "pacman-revenge": { + "icon": "", + "images": [] + }, + "pacparser": { + "icon": "", + "images": [] + }, + "padgen": { + "icon": "https://community.chocolatey.org/content/packageimages/padgen.3.1.1.51.png", + "images": [] + }, + "padmanager": { + "icon": "https://community.chocolatey.org/content/packageimages/padmanager.2.0.0.76.png", + "images": [] + }, + "pageedit": { + "icon": "", + "images": [] + }, + "paint-net": { + "icon": "https://community.chocolatey.org/content/packageimages/paint.net.5.0.2.png", + "images": [] + }, + "paint-net-plugin-boltbait": { + "icon": "", + "images": [] + }, + "paint-net-plugin-pyrochild": { + "icon": "", + "images": [] + }, + "paintaid": { + "icon": "", + "images": [] + }, + "paintdotnet": { + "icon": "https://i.postimg.cc/fRpJr36f/paintdotnet.png", + "images": [ + "https://i.postimg.cc/j21bSf68/image.png", + "https://i.postimg.cc/Pf7sZmZy/image.png" + ] + }, + "painter": { + "icon": "", + "images": [] + }, + "painttoolsai": { + "icon": "https://community.chocolatey.org/content/packageimages/painttoolsai.1.2.5.png", + "images": [] + }, + "paket": { + "icon": "https://community.chocolatey.org/content/packageimages/Paket.7.2.0.png", + "images": [] + }, + "paketinit": { + "icon": "", + "images": [] + }, + "palamedes": { + "icon": "", + "images": [] + }, + "palemoon": { + "icon": "https://community.chocolatey.org/content/packageimages/palemoon.32.0.1.png", + "images": [] + }, + "palminput": { + "icon": "", + "images": [] + }, + "pandabank": { + "icon": "https://community.chocolatey.org/content/packageimages/pandabank.3.0.2.0.png", + "images": [] + }, + "pandafreeantivirus": { + "icon": "https://community.chocolatey.org/content/packageimages/PandaFreeAntivirus.18.07.04.20200620.png", + "images": [] + }, + "pandas": { + "icon": "", + "images": [] + }, + "pandoc": { + "icon": "", + "images": [] + }, + "pandoc-crossref": { + "icon": "", + "images": [] + }, + "pandoc-plot": { + "icon": "", + "images": [] + }, + "pandocgui": { + "icon": "", + "images": [] + }, + "pandownload": { + "icon": "", + "images": [] + }, + "panwriter": { + "icon": "", + "images": [] + }, + "papagayo-ng": { + "icon": "https://community.chocolatey.org/content/packageimages/papagayo-ng.1.4.2.png", + "images": [] + }, + "papercut": { + "icon": "https://community.chocolatey.org/content/packageimages/papercut.6.0.0.png", + "images": [] + }, + "paperlib": { + "icon": "", + "images": [] + }, + "paperwork": { + "icon": "", + "images": [] + }, + "paprika-1": { + "icon": "", + "images": [] + }, + "paprika-3": { + "icon": "", + "images": [] + }, + "papyrus": { + "icon": "https://community.chocolatey.org/content/packageimages/papyrus.1.0.3.png", + "images": [] + }, + "paquet-builder": { + "icon": "", + "images": [] + }, + "par2cmdline": { + "icon": "", + "images": [] + }, + "paradoxlauncher": { + "icon": "https://vectorified.com/images/paradox-icon-21.png", + "images": [] + }, + "paragon-hfs": { + "icon": "", + "images": [] + }, + "paragon-linux": { + "icon": "", + "images": [] + }, + "paragonbackuprecoveryce": { + "icon": "", + "images": [] + }, + "parallels": { + "icon": "", + "images": [] + }, + "paraview": { + "icon": "", + "images": [] + }, + "parkcontrol": { + "icon": "", + "images": [] + }, + "parkdale": { + "icon": "https://community.chocolatey.org/content/packageimages/parkdale.portable.3.06.png", + "images": [] + }, + "parkdale-commandline": { + "icon": "https://community.chocolatey.org/content/packageimages/parkdale.commandline.1.01.png", + "images": [] + }, + "parse-cloudcode": { + "icon": "https://community.chocolatey.org/content/packageimages/Parse.CloudCode.1.0.6.0.png", + "images": [] + }, + "parsec": { + "icon": "https://community.chocolatey.org/content/packageimages/parsec.20221220.00.png", + "images": [] + }, + "parsec-cloud": { + "icon": "", + "images": [] + }, + "parsifydesktop": { + "icon": "", + "images": [] + }, + "partition-assistant-standard": { + "icon": "https://community.chocolatey.org/content/packageimages/partition-assistant-standard.9.4.png", + "images": [] + }, + "partition-manager": { + "icon": "https://community.chocolatey.org/content/packageimages/partition-manager.17.9.1.png", + "images": [] + }, + "partitionassistant": { + "icon": "https://www.megaleechers.com/storage/AOMEI-Partition-Assistant-Icon.png", + "images": [ + "https://www.lifewire.com/thmb/XSZctBtKj3Cc4sfaSY8E_hse3kk=/1280x691/filters:fill(auto,1)/aomei-partition-assistant-standard-edition-9-3f6f3e578f4c4109984e88bd8750d55d.png", + "https://sc.filehippo.net/images/t_app-cover-m,f_auto/p/20ef5252-a4d2-11e6-8f31-00163ed833e7/493431249/aomei-partition-assistant-standard-edition-1.png", + "https://windows-cdn.softpedia.com/screenshots/Partition-Assistant-Home-Edition_10.png", + "https://www.diskpart.com/screenshot/en/std/register/register.png" + ] + }, + "partitionexpert": { + "icon": "https://community.chocolatey.org/content/packageimages/partitionexpert.7.3.3.png", + "images": [] + }, + "partitionmaster": { + "icon": "https://i.postimg.cc/prZRNggw/pm.png", + "images": [] + }, + "partitionmasterfree": { + "icon": "https://i.postimg.cc/prZRNggw/pm.png", + "images": [] + }, + "partitionwizard": { + "icon": "https://community.chocolatey.org/content/packageimages/partitionwizard.12.7.png", + "images": [] + }, + "partitionwizard-free": { + "icon": "", + "images": [] + }, + "pass": { + "icon": "", + "images": [] + }, + "pass-winmenu-nogpg": { + "icon": "", + "images": [] + }, + "pass4win": { + "icon": "", + "images": [] + }, + "passbolt-cli": { + "icon": "", + "images": [] + }, + "passcovery": { + "icon": "https://community.chocolatey.org/content/packageimages/passcovery.3.1.png", + "images": [] + }, + "passcoverysuite": { + "icon": "", + "images": [] + }, + "passkey": { + "icon": "https://community.chocolatey.org/content/packageimages/passkey.8.2.7.9.png", + "images": [] + }, + "passky": { + "icon": "", + "images": [] + }, + "passportphotomaker": { + "icon": "", + "images": [] + }, + "passprotect-chrome": { + "icon": "https://community.chocolatey.org/content/packageimages/passprotect-chrome.0.1.8.png", + "images": [] + }, + "password-checkup-chrome": { + "icon": "", + "images": [] + }, + "password-control": { + "icon": "https://community.chocolatey.org/content/packageimages/password-control.2.4.3061.39299.png", + "images": [] + }, + "password-generator": { + "icon": "https://community.chocolatey.org/content/packageimages/password-generator.3.0.0.png", + "images": [] + }, + "password-hub": { + "icon": "", + "images": [] + }, + "passwordchecker": { + "icon": "", + "images": [] + }, + "passwordfox": { + "icon": "https://community.chocolatey.org/content/packageimages/passwordfox.1.56.png", + "images": [] + }, + "passwordgenerator": { + "icon": "https://vovsoft.com/icons64/password-generator.png", + "images": [ + "https://i.postimg.cc/ncvwMjzD/image.png" + ] + }, + "passwordsafe": { + "icon": "", + "images": [] + }, + "passwordscan": { + "icon": "https://community.chocolatey.org/content/packageimages/passwordscan.1.42.png", + "images": [] + }, + "passwork-chrome": { + "icon": "https://community.chocolatey.org/content/packageimages/passwork-chrome.0.6.0.png", + "images": [] + }, + "pasteboard": { + "icon": "https://community.chocolatey.org/content/packageimages/pasteboard.1.1.0.png", + "images": [] + }, + "pasteintofile": { + "icon": "https://community.chocolatey.org/content/packageimages/pasteintofile.1.5.0.png", + "images": [] + }, + "pastel": { + "icon": "", + "images": [ + "https://i.postimg.cc/Jnv1gC2r/image.png", + "https://i.postimg.cc/T1bRvNzW/image.png", + "https://i.postimg.cc/xjNjmqXd/image.png" + ] + }, + "patch": { + "icon": "", + "images": [] + }, + "patch-my-pc": { + "icon": "https://community.chocolatey.org/content/packageimages/patch-my-pc.4.5.0.0.png", + "images": [] + }, + "patchcleaner": { + "icon": "https://community.chocolatey.org/content/packageimages/patchcleaner.1.4.2.0.png", + "images": [] + }, + "patchmypc": { + "icon": "https://community.chocolatey.org/content/packageimages/patch-my-pc.4.5.0.0.png", + "images": [] + }, + "patchwork": { + "icon": "", + "images": [] + }, + "path-copy-copy": { + "icon": "https://community.chocolatey.org/content/packageimages/path-copy-copy.20.0.png", + "images": [] + }, + "path-manager": { + "icon": "https://community.chocolatey.org/content/packageimages/path-manager.2.3.png", + "images": [] + }, + "pathcopycopy": { + "icon": "", + "images": [] + }, + "pathed": { + "icon": "https://community.chocolatey.org/content/packageimages/pathed.4.2.png", + "images": [] + }, + "patheditor": { + "icon": "", + "images": [] + }, + "pathlengthchecker": { + "icon": "", + "images": [] + }, + "pathmanager": { + "icon": "", + "images": [] + }, + "pathod": { + "icon": "", + "images": [] + }, + "pathwavelicensemanager": { + "icon": "", + "images": [] + }, + "pavement-dev": { + "icon": "", + "images": [] + }, + "pavement-standard": { + "icon": "", + "images": [] + }, + "pawns": { + "icon": "https://community.chocolatey.org/content/packageimages/pawns.1.19.6.png", + "images": [] + }, + "pb-for-desktop": { + "icon": "", + "images": [] + }, + "pc-decrapifier": { + "icon": "", + "images": [] + }, + "pc-dimmer": { + "icon": "", + "images": [] + }, + "pcanypass": { + "icon": "https://community.chocolatey.org/content/packageimages/pcanypass.1.12.png", + "images": [] + }, + "pcanyscan": { + "icon": "https://community.chocolatey.org/content/packageimages/pcanyscan.1.0.png", + "images": [] + }, + "pcem": { + "icon": "", + "images": [] + }, + "pcgen": { + "icon": "", + "images": [] + }, + "pci-z": { + "icon": "https://community.chocolatey.org/content/packageimages/pci-z.2.0.png", + "images": [ + "https://betanews.com/wp-content/uploads/2014/01/PCI-Z.jpg" + ] + }, + "pciutils": { + "icon": "", + "images": [] + }, + "pclouddrive": { + "icon": "", + "images": [] + }, + "pcmanager": { + "icon": "https://store-images.s-microsoft.com/image/apps.5035.14298090620665013.cb25e253-e091-4d54-8b38-83056d549887.6cb80d38-5f06-461c-800f-34ac2c478fec?h=170", + "images": [] + }, + "pcmanager-cn": { + "icon": "", + "images": [] + }, + "pcmark8": { + "icon": "https://community.chocolatey.org/content/packageimages/pcmark8.2.10.901.png", + "images": [] + }, + "pcmeter": { + "icon": "", + "images": [] + }, + "pcon-plannerstd": { + "icon": "", + "images": [] + }, + "pcre2grep": { + "icon": "", + "images": [] + }, + "pcregrep": { + "icon": "", + "images": [] + }, + "pcsx2": { + "icon": "", + "images": [] + }, + "pctransfree": { + "icon": "https://community.chocolatey.org/content/packageimages/pctransfree.9.10.png", + "images": [] + }, + "pcwrunas": { + "icon": "", + "images": [] + }, + "pdanet": { + "icon": "", + "images": [] + }, + "pdbgit": { + "icon": "", + "images": [] + }, + "pdbproject-vs2013": { + "icon": "", + "images": [] + }, + "pdbproject-vs2015": { + "icon": "", + "images": [] + }, + "pdd": { + "icon": "", + "images": [] + }, + "pdf-ifilter-64": { + "icon": "https://community.chocolatey.org/content/packageimages/pdf-ifilter-64.11.0.01.20180614.png", + "images": [] + }, + "pdf-over": { + "icon": "", + "images": [] + }, + "pdf-tools": { + "icon": "", + "images": [] + }, + "pdf-xchange-editor": { + "icon": "https://pdf-xchange.eu/_images/pdf-xchange-editor/box-version-6.png", + "images": [] + }, + "pdf-xchangeeditor": { + "icon": "https://pdf-xchange.eu/_images/pdf-xchange-editor/box-version-6.png", + "images": [] + }, + "pdf-xchangepro": { + "icon": "https://pdf-xchange.eu/_images/pdf-xchange/box-pdf-xchange-pro-6.png", + "images": [] + }, + "pdf-xchangestandard": { + "icon": "https://pdf-xchange.eu/_images/pdf-xchange/box-pdf-xchange-standard-6.png", + "images": [] + }, + "pdf-xchangeviewer": { + "icon": "https://pdf-xchange.eu/_images/pdf-xchange-editor/box-version-6.png", + "images": [] + }, + "pdf24": { + "icon": "https://i.postimg.cc/DfP15pB1/icon.png", + "images": [ + "https://i.postimg.cc/BbpD6tXm/1.png" + ] + }, + "pdf24creator": { + "icon": "https://i.postimg.cc/DfP15pB1/icon.png", + "images": [ + "https://i.postimg.cc/BbpD6tXm/1.png", + "https://i.postimg.cc/9QK9z6QH/ui-assistant-1.png", + "https://i.postimg.cc/43c9cWY7/ui-compress-1.png", + "https://i.postimg.cc/SNZCb20s/ui-extract-1.png", + "https://i.postimg.cc/j5QngCQR/ui-file-tools-1.png", + "https://i.postimg.cc/tTHVNF6r/ui-ocr-1.png", + "https://i.postimg.cc/MpvR66xY/ui-reader-1.png" + ] + }, + "pdf2djvu": { + "icon": "", + "images": [] + }, + "pdf2json": { + "icon": "", + "images": [] + }, + "pdf2svg": { + "icon": "", + "images": [] + }, + "pdf2svg-win": { + "icon": "", + "images": [] + }, + "pdf417": { + "icon": "", + "images": [] + }, + "pdfarranger": { + "icon": "https://i.postimg.cc/fRcKnWvg/icon.png", + "images": [ + "https://i.postimg.cc/VNzFYyGs/screenshot.png" + ] + }, + "pdfbox": { + "icon": "", + "images": [] + }, + "pdfcandy": { + "icon": "", + "images": [] + }, + "pdfcombine": { + "icon": "https://community.chocolatey.org/content/packageimages/PDFCombine.3.1.png", + "images": [] + }, + "pdfconverter": { + "icon": "https://community.chocolatey.org/content/packageimages/PDFConverter.3.1.png", + "images": [] + }, + "pdfconverter-pro": { + "icon": "", + "images": [] + }, + "pdfcpu": { + "icon": "", + "images": [] + }, + "pdfcrack": { + "icon": "", + "images": [] + }, + "pdfcreator": { + "icon": "https://community.chocolatey.org/content/packageimages/PDFCreator.5.0.3.png", + "images": [] + }, + "pdfdesktop": { + "icon": "", + "images": [] + }, + "pdfedit": { + "icon": "https://community.chocolatey.org/content/packageimages/pdfedit.2014.0526.1531.png", + "images": [] + }, + "pdfelement-6": { + "icon": "", + "images": [] + }, + "pdfelement-6-pro": { + "icon": "", + "images": [] + }, + "pdfelement-7": { + "icon": "", + "images": [] + }, + "pdfelement-8": { + "icon": "", + "images": [] + }, + "pdfelement-9": { + "icon": "", + "images": [] + }, + "pdfelement-cn": { + "icon": "", + "images": [] + }, + "pdfill": { + "icon": "https://community.chocolatey.org/content/packageimages/pdfill.11.0.png", + "images": [] + }, + "pdfkeeper": { + "icon": "", + "images": [] + }, + "pdflux": { + "icon": "", + "images": [] + }, + "pdfpasswordremover": { + "icon": "", + "images": [] + }, + "pdfprinter": { + "icon": "", + "images": [] + }, + "pdfreader": { + "icon": "https://vovsoft.com/icons128/pdf-reader.png", + "images": [ + "https://vovsoft.com/screenshots/pdf-reader.png", + "https://vovsoft.com/screenshots/pdf-reader-2.png", + "https://vovsoft.com/screenshots/pdf-reader-3.png", + "https://vovsoft.com/screenshots/pdf-reader-4.png", + "https://vovsoft.com/screenshots/pdf-reader-5.png", + "https://vovsoft.com/screenshots/pdf-reader-6.png" + ] + }, + "pdfreader-cn": { + "icon": "", + "images": [] + }, + "pdfredirect": { + "icon": "", + "images": [] + }, + "pdfsam": { + "icon": "https://community.chocolatey.org/content/packageimages/pdfsam.install.5.0.3.png", + "images": [] + }, + "pdfsam-visual": { + "icon": "", + "images": [] + }, + "pdfshaperfree": { + "icon": "https://community.chocolatey.org/content/packageimages/pdfshaperfree.12.5.png", + "images": [] + }, + "pdfshaperpremium": { + "icon": "https://community.chocolatey.org/content/packageimages/pdfshaperpremium.12.5.png", + "images": [] + }, + "pdfshaperpro": { + "icon": "https://community.chocolatey.org/content/packageimages/pdfshaperpro.12.5.png", + "images": [] + }, + "pdfshow": { + "icon": "", + "images": [] + }, + "pdfsplitter": { + "icon": "https://community.chocolatey.org/content/packageimages/PDFSplitter.3.1.png", + "images": [] + }, + "pdfstudio": { + "icon": "https://community.chocolatey.org/content/packageimages/pdfstudio.2020.4.0.png", + "images": [] + }, + "pdftk": { + "icon": "https://i.postimg.cc/WzPQgWrH/Pdftk.png", + "images": [ + "https://i.postimg.cc/N0KqcrBp/image.png" + ] + }, + "pdftk-builder": { + "icon": "", + "images": [] + }, + "pdftk-free": { + "icon": "https://i.postimg.cc/WzPQgWrH/Pdftk.png", + "images": [ + "https://i.postimg.cc/N0KqcrBp/image.png" + ] + }, + "pdftk-java": { + "icon": "", + "images": [] + }, + "pdftk-server": { + "icon": "", + "images": [] + }, + "pdftkbuilder": { + "icon": "", + "images": [] + }, + "pdfxchangeeditor": { + "icon": "https://community.chocolatey.org/content/packageimages/PDFXchangeEditor.9.5.366.0.png", + "images": [ + "https://i.imgur.com/VajKqLl.png" + ] + }, + "pdfxchangelite": { + "icon": "https://community.chocolatey.org/content/packageimages/pdfxchangelite.6.0.322.5.png", + "images": [] + }, + "pdfxchangepro": { + "icon": "https://community.chocolatey.org/content/packageimages/PDFXchangePro.9.5.366.0.png", + "images": [] + }, + "pdfxchangeviewer": { + "icon": "https://community.chocolatey.org/content/packageimages/PDFXChangeViewer.2.5.317.20161116.png", + "images": [] + }, + "pdk": { + "icon": "https://community.chocolatey.org/content/packageimages/pdk.2.5.0.0.png", + "images": [] + }, + "pdqdeploy": { + "icon": "https://community.chocolatey.org/content/packageimages/pdq-deploy.19.3.360.0.png", + "images": [] + }, + "pdqinventory": { + "icon": "https://i.postimg.cc/prhSk68Z/PDQInventory.png", + "images": [] + }, + "pdraw32": { + "icon": "", + "images": [] + }, + "pe-bear": { + "icon": "", + "images": [] + }, + "pe-client-tools": { + "icon": "https://community.chocolatey.org/content/packageimages/pe-client-tools.21.7.0.png", + "images": [] + }, + "pe-sieve": { + "icon": "", + "images": [] + }, + "peazip": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/f/fe/Peazip_ico.svg/256px-Peazip_ico.svg.png", + "images": [ + "https://i.postimg.cc/Qxybz51V/image.png", + "https://i.postimg.cc/DyXJ2bRS/image.png", + "https://i.postimg.cc/qvHtgvdj/image.png", + "https://i.postimg.cc/VND5790V/image.png", + "https://i.postimg.cc/SsY2J2j1/image.png" + ] + }, + "pebear": { + "icon": "https://community.chocolatey.org/content/packageimages/pebear.0.6.5.png", + "images": [] + }, + "pecmd": { + "icon": "", + "images": [] + }, + "peco": { + "icon": "https://community.chocolatey.org/content/packageimages/peco.0.5.8.png", + "images": [] + }, + "pedeps": { + "icon": "", + "images": [] + }, + "peerblock": { + "icon": "", + "images": [] + }, + "peerunity": { + "icon": "", + "images": [] + }, + "peexplorer": { + "icon": "", + "images": [] + }, + "peid": { + "icon": "", + "images": [] + }, + "pelles-c": { + "icon": "", + "images": [] + }, + "pelles-c-sdk": { + "icon": "", + "images": [] + }, + "pelook": { + "icon": "", + "images": [] + }, + "pencil": { + "icon": "https://community.chocolatey.org/content/packageimages/Pencil.3.1.0.png", + "images": [] + }, + "pencil2d": { + "icon": "", + "images": [] + }, + "pendingreboot-psmodule": { + "icon": "https://community.chocolatey.org/content/packageimages/pendingreboot-psmodule.0.9.0.6.png", + "images": [] + }, + "pendmoves": { + "icon": "", + "images": [] + }, + "pendulums": { + "icon": "https://community.chocolatey.org/content/packageimages/pendulums.1.1.10.png", + "images": [] + }, + "pennywise": { + "icon": "", + "images": [] + }, + "pentaho-data-integration": { + "icon": "", + "images": [] + }, + "pepys": { + "icon": "", + "images": [] + }, + "perfect-privacy": { + "icon": "", + "images": [] + }, + "perfectworldarena": { + "icon": "https://i.postimg.cc/VkHP3g5P/perfectworldarena.png", + "images": [] + }, + "perfectxl-compare": { + "icon": "", + "images": [] + }, + "perfetto": { + "icon": "", + "images": [] + }, + "perfoo": { + "icon": "", + "images": [] + }, + "performance-monitor": { + "icon": "https://community.chocolatey.org/content/packageimages/performance-monitor.4.1.3.20170523.png", + "images": [] + }, + "performancetest": { + "icon": "https://community.chocolatey.org/content/packageimages/performancetest.10.2.1006.0.png", + "images": [] + }, + "perfview": { + "icon": "https://community.chocolatey.org/content/packageimages/perfview.3.0.7.png", + "images": [] + }, + "perimeter81ltd": { + "icon": "", + "images": [] + }, + "perl": { + "icon": "", + "images": [] + }, + "permain": { + "icon": "https://community.chocolatey.org/content/packageimages/permain.0.7.0.20220406.png", + "images": [] + }, + "permido-addin": { + "icon": "https://community.chocolatey.org/content/packageimages/permido-addin.1.3.39.png", + "images": [] + }, + "persepolis": { + "icon": "https://community.chocolatey.org/content/packageimages/persepolis.3.2.0.png", + "images": [] + }, + "personalbackup": { + "icon": "https://community.chocolatey.org/content/packageimages/PersonalBackup.6.3.0003.png", + "images": [] + }, + "personligsentralbord": { + "icon": "", + "images": [] + }, + "perspective": { + "icon": "", + "images": [] + }, + "pesecurity": { + "icon": "", + "images": [] + }, + "pesieve": { + "icon": "https://community.chocolatey.org/content/packageimages/pesieve.0.3.5.png", + "images": [] + }, + "pester": { + "icon": "https://community.chocolatey.org/content/packageimages/pester.5.4.0.png", + "images": [] + }, + "pestudio": { + "icon": "https://community.chocolatey.org/content/packageimages/PeStudio.9.47.0.0.png", + "images": [] + }, + "pet": { + "icon": "https://community.chocolatey.org/content/packageimages/pet.0.4.0.png", + "images": [] + }, + "petabridge-cmd": { + "icon": "https://community.chocolatey.org/content/packageimages/petabridge-cmd.1.2.2.png", + "images": [] + }, + "petal": { + "icon": "", + "images": [] + }, + "petools": { + "icon": "", + "images": [] + }, + "petwings": { + "icon": "", + "images": [] + }, + "pext": { + "icon": "", + "images": [] + }, + "pgadmin": { + "icon": "", + "images": [] + }, + "pgadmin3": { + "icon": "https://community.chocolatey.org/content/packageimages/pgadmin3.1.22.2.20170504.png", + "images": [] + }, + "pgadmin4": { + "icon": "https://community.chocolatey.org/content/packageimages/pgadmin4.6.13.png", + "images": [] + }, + "pgcli": { + "icon": "https://community.chocolatey.org/content/packageimages/pgcli.3.3.6.20180604.png", + "images": [] + }, + "pget": { + "icon": "", + "images": [] + }, + "pgina": { + "icon": "https://community.chocolatey.org/content/packageimages/pgina.3.1.8.004.png", + "images": [] + }, + "pginafork": { + "icon": "https://community.chocolatey.org/content/packageimages/pginafork.3.9.9.12.png", + "images": [] + }, + "pgmetrics": { + "icon": "", + "images": [] + }, + "pgptool": { + "icon": "https://community.chocolatey.org/content/packageimages/pgptool.0.5.9.2.png", + "images": [] + }, + "ph-ukl-buhdqrty": { + "icon": "", + "images": [] + }, + "ph-ukl-hanoqrty": { + "icon": "", + "images": [] + }, + "ph-ukl-tagbqrty": { + "icon": "", + "images": [] + }, + "ph-ukl-tglgqrty": { + "icon": "", + "images": [] + }, + "phalanger-4-0-tools": { + "icon": "", + "images": [] + }, + "phantombot": { + "icon": "https://community.chocolatey.org/content/packageimages/phantombot.3.7.4.2.png", + "images": [] + }, + "phantomjs": { + "icon": "https://community.chocolatey.org/content/packageimages/PhantomJS.2.1.1.png", + "images": [] + }, + "phantompdf": { + "icon": "", + "images": [] + }, + "phatgit": { + "icon": "https://community.chocolatey.org/content/packageimages/phatgit.1.2.0.33.png", + "images": [] + }, + "philea": { + "icon": "", + "images": [] + }, + "phoenix-protector": { + "icon": "", + "images": [] + }, + "phoenixfilerescue": { + "icon": "", + "images": [] + }, + "phonepresenter": { + "icon": "", + "images": [] + }, + "phonerlite": { + "icon": "https://community.chocolatey.org/content/packageimages/phonerlite.portable.3.15.png", + "images": [] + }, + "photocalendarcreator": { + "icon": "", + "images": [] + }, + "photodemon": { + "icon": "", + "images": [] + }, + "photodiva": { + "icon": "", + "images": [] + }, + "photofiltre-studio-x": { + "icon": "https://community.chocolatey.org/content/packageimages/photofiltre-studio-x.10.14.1.png", + "images": [] + }, + "photofiltre7-en": { + "icon": "", + "images": [] + }, + "photoflare": { + "icon": "https://community.chocolatey.org/content/packageimages/photoflare.install.1.6.5.png", + "images": [] + }, + "photoflow": { + "icon": "https://community.chocolatey.org/content/packageimages/photoflow.0.2.8.png", + "images": [] + }, + "photogimp": { + "icon": "https://community.chocolatey.org/content/packageimages/photogimp.1.0.2020.png", + "images": [] + }, + "photoglory": { + "icon": "", + "images": [] + }, + "photoguru": { + "icon": "", + "images": [] + }, + "photoresizerok": { + "icon": "https://community.chocolatey.org/content/packageimages/photoresizerok.2.77.png", + "images": [] + }, + "photosync": { + "icon": "", + "images": [] + }, + "phototofilm": { + "icon": "", + "images": [] + }, + "photoviewer": { + "icon": "", + "images": [] + }, + "photoworks": { + "icon": "", + "images": [] + }, + "phoxosee": { + "icon": "https://i.postimg.cc/yN3GL0q7/phoxosee.png", + "images": [ + "https://i.postimg.cc/ncdwZ3pH/image.png" + ] + }, + "php": { + "icon": "", + "images": [] + }, + "php-nts": { + "icon": "", + "images": [] + }, + "php-nts-xdebug": { + "icon": "", + "images": [] + }, + "php-service": { + "icon": "https://community.chocolatey.org/content/packageimages/php-service.8.1.10.png", + "images": [] + }, + "php-xdebug": { + "icon": "", + "images": [] + }, + "phpbb": { + "icon": "", + "images": [] + }, + "phpmyadmin": { + "icon": "https://community.chocolatey.org/content/packageimages/phpmyadmin.5.1.3.png", + "images": [] + }, + "phpstorm": { + "icon": "https://resources.jetbrains.com/storage/products/phpstorm/img/meta/phpstorm_logo_300x300.png", + "images": [] + }, + "phpstorm-earlyaccess": { + "icon": "https://resources.jetbrains.com/storage/products/phpstorm/img/meta/phpstorm_logo_300x300.png", + "images": [] + }, + "phraseapp": { + "icon": "https://community.chocolatey.org/content/packageimages/phraseapp.1.17.1.png", + "images": [] + }, + "phraseexpress": { + "icon": "", + "images": [] + }, + "physx": { + "icon": "", + "images": [] + }, + "physx-legacy": { + "icon": "https://community.chocolatey.org/content/packageimages/Physx.Legacy.9.13.0604.png", + "images": [] + }, + "physxlegacy": { + "icon": "", + "images": [] + }, + "pia": { + "icon": "https://community.chocolatey.org/content/packageimages/pia.290.3.3.1.png", + "images": [] + }, + "pia-desktop": { + "icon": "", + "images": [] + }, + "pibakery": { + "icon": "https://community.chocolatey.org/content/packageimages/pibakery.0.3.4.png", + "images": [] + }, + "picard": { + "icon": "", + "images": [] + }, + "picaso": { + "icon": "https://1000logos.net/wp-content/uploads/2020/08/Picasa-Logo.jpg", + "images": [] + }, + "picassio": { + "icon": "https://community.chocolatey.org/content/packageimages/picassio.0.12.0.png", + "images": [] + }, + "picgo": { + "icon": "https://community.chocolatey.org/content/packageimages/picgo.2.3.0.png", + "images": [] + }, + "picgo-beta": { + "icon": "", + "images": [] + }, + "pickles": { + "icon": "https://community.chocolatey.org/content/packageimages/pickles.2.21.1.png", + "images": [] + }, + "picklesui": { + "icon": "https://community.chocolatey.org/content/packageimages/picklesui.2.21.1.png", + "images": [] + }, + "picocrypt": { + "icon": "", + "images": [] + }, + "picoscope": { + "icon": "https://community.chocolatey.org/content/packageimages/picoscope.6.14.44.png", + "images": [] + }, + "picotorrent": { + "icon": "https://community.chocolatey.org/content/packageimages/picotorrent.portable.0.25.0.png", + "images": [] + }, + "picpick": { + "icon": "", + "images": [ + "https://i.postimg.cc/ZYHQDcfg/image.png", + "https://i.postimg.cc/Qts6f9ch/image.png", + "https://i.postimg.cc/yxpv6Lt8/image.png", + "https://i.postimg.cc/CxqmYHNw/image.png", + "https://i.postimg.cc/j5Zhv8s4/image.png", + "https://i.postimg.cc/D0NP384W/image.png", + "https://i.postimg.cc/nVSkDwSH/image.png", + "https://i.postimg.cc/rFvNhRL3/image.png" + ] + }, + "pictoselector": { + "icon": "", + "images": [] + }, + "picturama": { + "icon": "", + "images": [] + }, + "pictus": { + "icon": "https://community.chocolatey.org/content/packageimages/pictus.1.7.0.png", + "images": [] + }, + "picview": { + "icon": "", + "images": [] + }, + "pidgin": { + "icon": "", + "images": [] + }, + "pidgin-otr": { + "icon": "", + "images": [] + }, + "pidginotrplugin": { + "icon": "", + "images": [] + }, + "pietty": { + "icon": "", + "images": [] + }, + "pik": { + "icon": "", + "images": [] + }, + "pikpak": { + "icon": "", + "images": [] + }, + "pine64-updater": { + "icon": "", + "images": [] + }, + "pinetwork": { + "icon": "", + "images": [] + }, + "pinginfoview": { + "icon": "https://community.chocolatey.org/content/packageimages/pinginfoview.2.30.png", + "images": [] + }, + "pingmonitorfree": { + "icon": "https://community.chocolatey.org/content/packageimages/pingmonitorfree.9.0.5.png", + "images": [] + }, + "pingplotter": { + "icon": "https://community.chocolatey.org/content/packageimages/pingplotter.5.23.3.png", + "images": [ + "https://i.postimg.cc/QC2wcB03/image.png" + ] + }, + "pingtracer": { + "icon": "https://community.chocolatey.org/content/packageimages/pingtracer.1.13.png", + "images": [] + }, + "pingus": { + "icon": "", + "images": [] + }, + "pinta": { + "icon": "https://community.chocolatey.org/content/packageimages/Pinta.2.1.png", + "images": [] + }, + "pioneer": { + "icon": "", + "images": [] + }, + "pip": { + "icon": "https://cdn.iconscout.com/icon/free/png-256/free-python-logo-icon-download-in-svg-png-gif-file-formats--brand-development-tools-pack-logos-icons-226051.png", + "images": [] + }, + "pip-tool": { + "icon": "", + "images": [] + }, + "pipes-rs": { + "icon": "", + "images": [] + }, + "pipp": { + "icon": "", + "images": [] + }, + "pitchfunk": { + "icon": "https://community.chocolatey.org/content/packageimages/pitchfunk.1.21.20221112.png", + "images": [] + }, + "pitv": { + "icon": "", + "images": [] + }, + "pix": { + "icon": "", + "images": [] + }, + "pixelorama": { + "icon": "https://community.chocolatey.org/content/packageimages/pixelorama.0.10.3.png", + "images": [] + }, + "pixelshop": { + "icon": "https://community.chocolatey.org/content/packageimages/pixelshop.1.0.0.20180711.png", + "images": [] + }, + "pixie": { + "icon": "https://community.chocolatey.org/content/packageimages/pixie.4.1.png", + "images": [] + }, + "pixitracker": { + "icon": "", + "images": [] + }, + "pixitracker-1bit": { + "icon": "", + "images": [] + }, + "pixivutil2": { + "icon": "https://community.chocolatey.org/content/packageimages/pixivutil2.2021.11.04.png", + "images": [] + }, + "pixpin": { + "icon": "https://pixpin.cn/images/logo/1024.png", + "images": [ + "https://pixpin.cn/docs/main.png", + "https://pixpin.cn/docs/images/member-features/image-2.png" + ] + }, + "pixso": { + "icon": "", + "images": [] + }, + "pixsolocalfont": { + "icon": "", + "images": [] + }, + "pjw-autopackages": { + "icon": "", + "images": [] + }, + "pkg-config": { + "icon": "", + "images": [] + }, + "pkgconfiglite": { + "icon": "", + "images": [] + }, + "pl-sqlitestudio": { + "icon": "https://raw.githubusercontent.com/pawelsalawa/sqlitestudio/master/SQLiteStudio3/guiSQLiteStudio/img/sqlitestudio_256.png", + "images": [ + "https://sqlitestudio.pl/img/uploaded/full_22.png", + "https://sqlitestudio.pl/img/uploaded/1613941917961410_3.3.0.png" + ] + }, + "planetblupi": { + "icon": "", + "images": [] + }, + "planetmule": { + "icon": "https://community.chocolatey.org/content/packageimages/planetmule.1.3.6.png", + "images": [] + }, + "planexplorerssmsaddin": { + "icon": "", + "images": [] + }, + "planningforexcel": { + "icon": "", + "images": [] + }, + "plantronicshub": { + "icon": "https://community.chocolatey.org/content/packageimages/plantronicshub.3.25.53800.37131.png", + "images": [] + }, + "plantuml": { + "icon": "https://community.chocolatey.org/content/packageimages/plantuml.1.2023.2.png", + "images": [] + }, + "plasticscm-cloudedition": { + "icon": "", + "images": [] + }, + "platformtools": { + "icon": "https://i.postimg.cc/L5VT8t0r/platform-tools.png", + "images": [] + }, + "platonnetwork": { + "icon": "", + "images": [] + }, + "platonnetwork-all": { + "icon": "", + "images": [] + }, + "platonnetwork-mpclib": { + "icon": "", + "images": [] + }, + "platyps": { + "icon": "https://community.chocolatey.org/content/packageimages/platyps.0.14.2.png", + "images": [] + }, + "play": { + "icon": "https://community.chocolatey.org/content/packageimages/Play.2.3.6.png", + "images": [] + }, + "playdatesdk": { + "icon": "https://nikee.dev/imgr/playdate4.png", + "images": [ + "https://nikee.dev/imgr/playdatesdk_screenshot.png", + "https://nikee.dev/imgr/playdatesdk_screenshot2.png" + ] + }, + "playgames-beta": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/9/95/Google_Play_Games_logo_%282023%29.svg/512px-Google_Play_Games_logo_%282023%29.svg.png", + "images": [] + }, + "playlist-creator": { + "icon": "https://community.chocolatey.org/content/packageimages/playlist-creator.install.3.6.2.png", + "images": [] + }, + "playnite": { + "icon": "https://playnite.link/applogo.png", + "images": [ + "https://playnite.link/screen1.jpg", + "https://playnite.link/screen2.jpg", + "https://playnite.link/screen3.jpg", + "https://playnite.link/screen4.jpg", + "https://playnite.link/screen5.jpg" + ] + }, + "playparkdownloader": { + "icon": "", + "images": [] + }, + "plentymarkets-client": { + "icon": "", + "images": [] + }, + "plex": { + "icon": "https://community.chocolatey.org/content/packageimages/plex.1.64.2.3546.png", + "images": [] + }, + "plex-chrome": { + "icon": "", + "images": [] + }, + "plex-desktop": { + "icon": "", + "images": [] + }, + "plex-home-theater": { + "icon": "https://community.chocolatey.org/content/packageimages/plex-home-theater.1.4.1.469001.png", + "images": [] + }, + "plex-mpv-shim": { + "icon": "", + "images": [] + }, + "plex-player": { + "icon": "", + "images": [] + }, + "plex-server": { + "icon": "", + "images": [] + }, + "plexamp": { + "icon": "", + "images": [] + }, + "plexmediaplayer": { + "icon": "https://community.chocolatey.org/content/packageimages/plexmediaplayer.2.58.0.1078.png", + "images": [] + }, + "plexmediaserver": { + "icon": "https://community.chocolatey.org/content/packageimages/plexmediaserver.1.31.1.6733.png", + "images": [] + }, + "plexpy": { + "icon": "", + "images": [] + }, + "plexrichpresence": { + "icon": "", + "images": [] + }, + "plitch": { + "icon": "https://www.plitch.com/images/icons/favicons/favicon-96x96.png?v=cL97JBBJkExlzzI5_WaT0XL8To54lbHldXos1yA2WCA", + "images": [] + }, + "plottr": { + "icon": "", + "images": [] + }, + "plover": { + "icon": "", + "images": [] + }, + "plsqldeveloper": { + "icon": "", + "images": [] + }, + "pluginval": { + "icon": "", + "images": [] + }, + "pluralsight-transcripter": { + "icon": "https://community.chocolatey.org/content/packageimages/pluralsight-transcripter.1.0.0.png", + "images": [] + }, + "plus": { + "icon": "", + "images": [] + }, + "pluto": { + "icon": "", + "images": [] + }, + "pluto-tv": { + "icon": "", + "images": [] + }, + "pmd": { + "icon": "https://community.chocolatey.org/content/packageimages/pmd.6.55.0.png", + "images": [] + }, + "pmetro": { + "icon": "https://community.chocolatey.org/content/packageimages/pmetro.2022.06.10.png", + "images": [] + }, + "pneumatictube": { + "icon": "https://community.chocolatey.org/content/packageimages/pneumatictube.portable.1.7.0.0.png", + "images": [] + }, + "png2html": { + "icon": "", + "images": [] + }, + "png2jpeg": { + "icon": "", + "images": [] + }, + "pngcheck": { + "icon": "", + "images": [] + }, + "pngcrush": { + "icon": "", + "images": [] + }, + "pnggauntlet": { + "icon": "https://community.chocolatey.org/content/packageimages/pnggauntlet.install.3.1.2.20171027.png", + "images": [] + }, + "pngoo": { + "icon": "", + "images": [] + }, + "pngoptimizer": { + "icon": "https://community.chocolatey.org/content/packageimages/pngoptimizer.2.7.png", + "images": [] + }, + "pngoptimizer-commandline": { + "icon": "https://community.chocolatey.org/content/packageimages/pngoptimizer.commandline.2.5.png", + "images": [] + }, + "pngquant": { + "icon": "https://community.chocolatey.org/content/packageimages/pngquant.2.18.0.png", + "images": [] + }, + "pngyu": { + "icon": "https://community.chocolatey.org/content/packageimages/pngyu.1.0.1.20221128.png", + "images": [] + }, + "pnpm": { + "icon": "https://community.chocolatey.org/content/packageimages/pnpm.7.28.0.png", + "images": [] + }, + "pocketsphinx": { + "icon": "", + "images": [] + }, + "podcastutilities": { + "icon": "", + "images": [] + }, + "podcastutilities-core": { + "icon": "", + "images": [] + }, + "pode": { + "icon": "https://community.chocolatey.org/content/packageimages/pode.2.8.0.png", + "images": [] + }, + "poderosa-terminal-net35": { + "icon": "", + "images": [] + }, + "poderosa-terminal-net40": { + "icon": "", + "images": [] + }, + "podman": { + "icon": "", + "images": [] + }, + "podman-cli": { + "icon": "https://community.chocolatey.org/content/packageimages/podman-cli.1.8.0.png", + "images": [] + }, + "podman-desktop": { + "icon": "https://community.chocolatey.org/content/packageimages/podman-desktop.0.12.0.png", + "images": [] + }, + "podman-machine": { + "icon": "https://community.chocolatey.org/content/packageimages/podman-machine.0.17.png", + "images": [] + }, + "poe-writer": { + "icon": "", + "images": [] + }, + "poedit": { + "icon": "https://poedit.net/images/icons/poedit/icon_128x128@2x.png", + "images": [ + "https://i.postimg.cc/NGJJKCNf/image.png" + ] + }, + "poetry": { + "icon": "", + "images": [] + }, + "poi": { + "icon": "https://community.chocolatey.org/content/packageimages/poi.10.8.0.png", + "images": [] + }, + "pokemonshowdown": { + "icon": "https://play.pokemonshowdown.com/favicon-256.png", + "images": [] + }, + "pokemontcgonline": { + "icon": "", + "images": [] + }, + "pokerth": { + "icon": "", + "images": [] + }, + "polar": { + "icon": "https://community.chocolatey.org/content/packageimages/polar.2.0.108.png", + "images": [] + }, + "polaris": { + "icon": "", + "images": [] + }, + "polipo": { + "icon": "", + "images": [] + }, + "pollapo": { + "icon": "", + "images": [] + }, + "polleverywhere": { + "icon": "https://community.chocolatey.org/content/packageimages/polleverywhere.3.0.8.png", + "images": [] + }, + "polsedit": { + "icon": "", + "images": [] + }, + "polypane": { + "icon": "", + "images": [] + }, + "pomodoneapp": { + "icon": "", + "images": [] + }, + "pomodoro": { + "icon": "", + "images": [] + }, + "pomodorologger": { + "icon": "", + "images": [] + }, + "pomolectron": { + "icon": "https://community.chocolatey.org/content/packageimages/pomolectron.1.1.0.png", + "images": [] + }, + "pomotime": { + "icon": "https://community.chocolatey.org/content/packageimages/PomoTime.1.8.png", + "images": [] + }, + "pomotodo": { + "icon": "", + "images": [] + }, + "pomotroid": { + "icon": "", + "images": [] + }, + "poni": { + "icon": "", + "images": [] + }, + "popcorn-time": { + "icon": "https://community.chocolatey.org/content/packageimages/popcorn-time.0.3.10.png", + "images": [] + }, + "popcorn-time-ru": { + "icon": "", + "images": [] + }, + "poppler": { + "icon": "", + "images": [] + }, + "port": { + "icon": "", + "images": [] + }, + "portable-library-tools-2": { + "icon": "https://community.chocolatey.org/content/packageimages/portable-library-tools-2.10.0.50828.20180323.png", + "images": [] + }, + "portable-virtualbox": { + "icon": "", + "images": [] + }, + "portainer": { + "icon": "", + "images": [] + }, + "portalstillalive": { + "icon": "", + "images": [] + }, + "portexpert": { + "icon": "https://community.chocolatey.org/content/packageimages/portexpert.1.8.3.22.png", + "images": [] + }, + "portfolio": { + "icon": "", + "images": [] + }, + "portfolio-performance": { + "icon": "", + "images": [] + }, + "portforward": { + "icon": "", + "images": [] + }, + "portmaster": { + "icon": "https://i.postimg.cc/bwPx1D4Y/image.png", + "images": [ + "https://i.postimg.cc/02Ym55jT/image.png", + "https://raw.githubusercontent.com/kamack38/chocopkgs/94fb372e1be6e893d51714e565ea9413cd97e6bc/assets/portmaster.png", + "https://safing.io/assets/img/page-specific/portmaster/block-trackers-system-wide.png", + "https://safing.io/assets/img/page-specific/portmaster/set-global-and-per-app-configuration.png", + "https://safing.io/assets/img/page-specific/portmaster/monitor-network-activity.png" + ] + }, + "portmon": { + "icon": "https://community.chocolatey.org/content/packageimages/portmon.3.03.0.20151228.png", + "images": [] + }, + "portscan": { + "icon": "https://community.chocolatey.org/content/packageimages/portscan.portable.1.91.png", + "images": [] + }, + "portwarden": { + "icon": "", + "images": [] + }, + "portx": { + "icon": "https://community.chocolatey.org/content/packageimages/portx.2.1.10.png", + "images": [] + }, + "posfordotnet": { + "icon": "", + "images": [] + }, + "posh-cde": { + "icon": "", + "images": [] + }, + "posh-ci-git": { + "icon": "", + "images": [] + }, + "posh-docker": { + "icon": "", + "images": [] + }, + "posh-git": { + "icon": "", + "images": [] + }, + "posh-git-hg": { + "icon": "", + "images": [] + }, + "posh-github": { + "icon": "https://community.chocolatey.org/content/packageimages/Posh-GitHub.0.0.2.png", + "images": [] + }, + "posh-hg": { + "icon": "", + "images": [] + }, + "posh-vsvars": { + "icon": "https://community.chocolatey.org/content/packageimages/Posh-VsVars.0.0.3.png", + "images": [] + }, + "poshadmin": { + "icon": "https://community.chocolatey.org/content/packageimages/poshadmin.1.1.0.0.png", + "images": [] + }, + "poshcode": { + "icon": "", + "images": [] + }, + "poshdevops": { + "icon": "", + "images": [] + }, + "poshdynargs": { + "icon": "", + "images": [] + }, + "poshgit": { + "icon": "", + "images": [] + }, + "poshhosts": { + "icon": "", + "images": [] + }, + "poshpuppetreports": { + "icon": "https://community.chocolatey.org/content/packageimages/poshpuppetreports.0.9.55.png", + "images": [] + }, + "poshtools-visualstudio2012": { + "icon": "https://community.chocolatey.org/content/packageimages/poshtools-visualstudio2012.1.0.5.png", + "images": [] + }, + "poshtools-visualstudio2013": { + "icon": "https://community.chocolatey.org/content/packageimages/poshtools-visualstudio2013.3.0.299.png", + "images": [] + }, + "postbox": { + "icon": "https://community.chocolatey.org/content/packageimages/postbox.7.0.59.png", + "images": [] + }, + "posterazor": { + "icon": "https://community.chocolatey.org/content/packageimages/posterazor.portable.1.5.2.20190317.png", + "images": [] + }, + "postgis-9-3": { + "icon": "", + "images": [] + }, + "postgresql": { + "icon": "https://community.chocolatey.org/content/packageimages/postgresql.15.2.png", + "images": [] + }, + "postgresql-9-3": { + "icon": "https://community.chocolatey.org/content/packageimages/postgresql-9.3.9.3.5.3.png", + "images": [] + }, + "postgresql10": { + "icon": "https://community.chocolatey.org/content/packageimages/postgresql10.10.23.1.png", + "images": [] + }, + "postgresql13": { + "icon": "https://community.chocolatey.org/content/packageimages/postgresql13.13.10.png", + "images": [] + }, + "postgresql14": { + "icon": "https://community.chocolatey.org/content/packageimages/postgresql14.14.5.1.png", + "images": [] + }, + "postgresql15": { + "icon": "https://community.chocolatey.org/content/packageimages/postgresql15.15.0.1.png", + "images": [] + }, + "postgresql93": { + "icon": "", + "images": [] + }, + "postgrest": { + "icon": "https://community.chocolatey.org/content/packageimages/postgrest.10.1.2.png", + "images": [] + }, + "postimage": { + "icon": "https://i.postimg.cc/rwzVQQKG/image.png", + "images": [ + "https://postimgs.org/img/app_2.png", + "https://postimgs.org/img/app_1.png", + "https://postimgs.org/img/app_3.png", + "https://postimgs.org/img/app_5.png" + ] + }, + "postman": { + "icon": "https://assets.getpostman.com/common-share/postman-logo.png", + "images": [] + }, + "postman-canary": { + "icon": "https://assets.getpostman.com/common-share/postman-logo.png", + "images": [] + }, + "postman-cli": { + "icon": "https://community.chocolatey.org/content/packageimages/postman-cli.1.0.1.png", + "images": [] + }, + "postman-desktopagent": { + "icon": "https://assets.getpostman.com/common-share/postman-logo.png", + "images": [] + }, + "postybirb": { + "icon": "", + "images": [] + }, + "potatowall": { + "icon": "", + "images": [] + }, + "potplayer": { + "icon": "https://tweakers.net/ext/i/2004649714.png", + "images": [ + "https://tweakers.net/ext/i/2000615049.jpeg" + ] + }, + "potrace": { + "icon": "", + "images": [] + }, + "pov-ray": { + "icon": "https://community.chocolatey.org/content/packageimages/pov-ray.3.7.0.20161121.png", + "images": [] + }, + "povray": { + "icon": "", + "images": [] + }, + "powder-toy": { + "icon": "https://community.chocolatey.org/content/packageimages/powder-toy.97.0.png", + "images": [] + }, + "powerappscli": { + "icon": "", + "images": [] + }, + "powerarchiver-2022": { + "icon": "https://tweakers.net/ext/i/1302267349.jpeg", + "images": [] + }, + "powerarchiver2016": { + "icon": "https://community.chocolatey.org/content/packageimages/powerarchiver2016.16.10.24.20181017.png", + "images": [] + }, + "powerautomatedesktop": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/4/4d/Microsoft_Power_Automate.svg/64px-Microsoft_Power_Automate.svg.png", + "images": [] + }, + "powerbi": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/c/cf/New_Power_BI_Logo.svg/512px-New_Power_BI_Logo.svg.png", + "images": [] + }, + "powerbi-reportbuilder": { + "icon": "https://community.chocolatey.org/content/packageimages/powerbi-reportbuilder.15.7.1801.18.png", + "images": [] + }, + "powerchute-personal": { + "icon": "https://community.chocolatey.org/content/packageimages/powerchute-personal.3.1.0.png", + "images": [] + }, + "powerdelivery": { + "icon": "", + "images": [] + }, + "powerdelivery-vsextension-2010": { + "icon": "", + "images": [] + }, + "powerdelivery-vsextension-2013": { + "icon": "", + "images": [] + }, + "powerdelivery3": { + "icon": "", + "images": [] + }, + "powerdelivery3node": { + "icon": "", + "images": [] + }, + "powergist": { + "icon": "", + "images": [] + }, + "powergui": { + "icon": "", + "images": [] + }, + "powerguivsx": { + "icon": "", + "images": [] + }, + "poweriast": { + "icon": "", + "images": [] + }, + "poweriso": { + "icon": "https://www.gezginler.net/indir/resim-grafik/poweriso-1383913611.png", + "images": [ + "https://i.ibb.co/HfkMcLwT/Image.png", + "https://i.postimg.cc/8kwRvZfX/image.png", + "https://i.postimg.cc/QMk93MpY/image.png", + "https://i.postimg.cc/x8qcMyBB/image.png" + ] + }, + "powerline-go": { + "icon": "", + "images": [] + }, + "powermanager": { + "icon": "", + "images": [] + }, + "powermax": { + "icon": "", + "images": [] + }, + "powerpanel-personal": { + "icon": "https://community.chocolatey.org/content/packageimages/powerpanel-personal.2.4.6.png", + "images": [] + }, + "powerping": { + "icon": "", + "images": [] + }, + "powerpoint-viewer": { + "icon": "", + "images": [] + }, + "powerpointviewer": { + "icon": "", + "images": [] + }, + "powerquery": { + "icon": "", + "images": [] + }, + "powerresizer": { + "icon": "https://community.chocolatey.org/content/packageimages/powerresizer.0.0.1.png", + "images": [] + }, + "powersession": { + "icon": "", + "images": [] + }, + "powersession-rs": { + "icon": "", + "images": [] + }, + "powershell": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/a/af/PowerShell_Core_6.0_icon.png", + "images": [ + "https://i.postimg.cc/3rBP8N2d/powershell.png" + ] + }, + "powershell-core": { + "icon": "https://community.chocolatey.org/content/packageimages/powershell-core.7.3.3.png", + "images": [] + }, + "powershell-packagemanagement": { + "icon": "https://community.chocolatey.org/content/packageimages/powershell-packagemanagement.10.0.10586.200.png", + "images": [] + }, + "powershell-preview": { + "icon": "https://community.chocolatey.org/content/packageimages/powershell-preview.7.2.4.20210411.png", + "images": [] + }, + "powershellbuild-powershell": { + "icon": "https://community.chocolatey.org/content/packageimages/powershellbuild.powershell.0.6.1.png", + "images": [] + }, + "powershellextension-sql2012": { + "icon": "", + "images": [] + }, + "powershellgac": { + "icon": "", + "images": [] + }, + "powershellplus": { + "icon": "https://community.chocolatey.org/content/packageimages/powershellplus.11.50.0.42619.png", + "images": [] + }, + "powershelluniversal": { + "icon": "", + "images": [] + }, + "powertab": { + "icon": "", + "images": [] + }, + "powertoys": { + "icon": "https://i.postimg.cc/DfmW7XGy/pticon.png", + "images": [ + "https://i.postimg.cc/KjdjH0cp/pt1.png", + "https://i.postimg.cc/KYZzwkFb/pt2.png", + "https://i.postimg.cc/x1VqGp4c/pt3.png", + "https://i.postimg.cc/XYKqsKRx/pt4.png", + "https://i.postimg.cc/fLPRV8dW/pt5.png", + "https://i.postimg.cc/SsRKQBJt/pt6.png", + "https://i.postimg.cc/br2Nk10x/pt7.png", + "https://i.postimg.cc/jqWzZ9ZX/pt8.png" + ] + }, + "ppdgr2": { + "icon": "https://community.chocolatey.org/content/packageimages/ppdgr2.2.4.2.png", + "images": [] + }, + "ppee": { + "icon": "", + "images": [] + }, + "pplink": { + "icon": "", + "images": [] + }, + "pprovost-desktoputils": { + "icon": "", + "images": [] + }, + "pprovost-devtools": { + "icon": "", + "images": [] + }, + "ppsspp": { + "icon": "https://community.chocolatey.org/content/packageimages/PPSSPP.1.14.4.png", + "images": [] + }, + "praat": { + "icon": "https://community.chocolatey.org/content/packageimages/praat.6.3.08.png", + "images": [] + }, + "pragmaticworksworkbench": { + "icon": "", + "images": [] + }, + "pragmaticworksworkbenchserver": { + "icon": "", + "images": [] + }, + "precode-wlw": { + "icon": "", + "images": [] + }, + "prefix": { + "icon": "https://community.chocolatey.org/content/packageimages/prefix.2.0.130.png", + "images": [] + }, + "premake": { + "icon": "https://community.chocolatey.org/content/packageimages/premake.portable.4.3.png", + "images": [] + }, + "premake-5-beta": { + "icon": "", + "images": [] + }, + "premotem": { + "icon": "https://community.chocolatey.org/content/packageimages/premotem.0.7.2.2.png", + "images": [] + }, + "presencelight": { + "icon": "https://community.chocolatey.org/content/packageimages/PresenceLight.5.5.18.0.png", + "images": [] + }, + "presenter": { + "icon": "", + "images": [] + }, + "presenter-express": { + "icon": "", + "images": [] + }, + "presenter-personal": { + "icon": "", + "images": [] + }, + "presenter-premium": { + "icon": "", + "images": [] + }, + "presenter-standard": { + "icon": "", + "images": [] + }, + "presentmon": { + "icon": "", + "images": [] + }, + "presonusuniversalcontrol": { + "icon": "", + "images": [] + }, + "prestashop": { + "icon": "", + "images": [] + }, + "pretixscan": { + "icon": "", + "images": [] + }, + "prettypaste": { + "icon": "", + "images": [] + }, + "pretzel": { + "icon": "https://community.chocolatey.org/content/packageimages/pretzel.0.7.1.png", + "images": [] + }, + "pretzel-scriptcs": { + "icon": "https://community.chocolatey.org/content/packageimages/pretzel.scriptcs.0.7.0.png", + "images": [] + }, + "previewconfig": { + "icon": "https://community.chocolatey.org/content/packageimages/previewconfig.1.2.0.0.png", + "images": [] + }, + "previewhandlerpack": { + "icon": "", + "images": [] + }, + "previousfilesrecovery": { + "icon": "https://community.chocolatey.org/content/packageimages/previousfilesrecovery.1.10.png", + "images": [] + }, + "prey": { + "icon": "https://community.chocolatey.org/content/packageimages/prey.1.10.10.png", + "images": [] + }, + "preziclassic": { + "icon": "", + "images": [] + }, + "prig": { + "icon": "https://community.chocolatey.org/content/packageimages/Prig.2.3.2.png", + "images": [] + }, + "prime95": { + "icon": "https://community.chocolatey.org/content/packageimages/prime95.portable.30.3.6.png", + "images": [] + }, + "primecoin": { + "icon": "https://community.chocolatey.org/content/packageimages/primecoin.0.1.2.png", + "images": [] + }, + "primecount": { + "icon": "", + "images": [] + }, + "primesieve": { + "icon": "", + "images": [] + }, + "primevirtualcalculator": { + "icon": "", + "images": [] + }, + "prince": { + "icon": "", + "images": [] + }, + "printmaestro": { + "icon": "", + "images": [] + }, + "printrun": { + "icon": "", + "images": [] + }, + "prism": { + "icon": "", + "images": [] + }, + "prismatikunofficial": { + "icon": "", + "images": [] + }, + "prismlauncher": { + "icon": "https://unigeticons.meowcat285.com/prismlauncher.8.4.20240820.png", + "images": [ + "https://i.postimg.cc/FHLWvyfy/q7pf-R-Cbs-L-824.png" + ] + }, + "prismlauncher-git": { + "icon": "https://cdn2.steamgriddb.com/file/sgdb-cdn/logo_thumb/d89950b4a87c48fdba628160f5217844.png", + "images": [ + "https://images.opencollective.com/prismlauncher/29f649e/background.png", + "https://i.ibb.co/wZSn327s/image.png", + "https://i.ibb.co/G4zyDM4R/image.png" + ] + }, + "pritunl-client": { + "icon": "https://community.chocolatey.org/content/packageimages/pritunl-client.1.3.3343.50.png", + "images": [] + }, + "privacy": { + "icon": "", + "images": [] + }, + "privacy-sexy": { + "icon": "", + "images": [] + }, + "privacywall": { + "icon": "https://community.chocolatey.org/content/packageimages/privacywall.1.0.0.0.png", + "images": [] + }, + "privadovpn": { + "icon": "", + "images": [] + }, + "privateinternetaccess": { + "icon": "https://www.droidviews.com/wp-content/uploads/2021/05/Private-Internet-Access.png", + "images": [ + "https://i.pcmag.com/imagery/reviews/01gzf2i73u7uAk08rsioA8v-43.fit_lim.size_1050x.jpg" + ] + }, + "privatezilla": { + "icon": "", + "images": [] + }, + "privazer": { + "icon": "https://community.chocolatey.org/content/packageimages/privazer.portable.4.0.66.png", + "images": [] + }, + "privoxy": { + "icon": "https://community.chocolatey.org/content/packageimages/privoxy.3.0.34.png", + "images": [] + }, + "prm": { + "icon": "", + "images": [] + }, + "processhacker": { + "icon": "https://community.chocolatey.org/content/packageimages/processhacker.portable.2.39.png", + "images": [] + }, + "processing": { + "icon": "https://community.chocolatey.org/content/packageimages/Processing.3.5.4.png", + "images": [] + }, + "processing2": { + "icon": "", + "images": [] + }, + "processlasso": { + "icon": "", + "images": [] + }, + "processlasso-beta": { + "icon": "", + "images": [] + }, + "processordiagnostictool": { + "icon": "", + "images": [] + }, + "processthreadsview": { + "icon": "https://community.chocolatey.org/content/packageimages/processthreadsview.1.29.png", + "images": [] + }, + "procgov": { + "icon": "", + "images": [] + }, + "procs": { + "icon": "", + "images": [] + }, + "procyon": { + "icon": "", + "images": [] + }, + "product666": { + "icon": "", + "images": [] + }, + "productportal": { + "icon": "", + "images": [] + }, + "produkey": { + "icon": "https://community.chocolatey.org/content/packageimages/produkey.portable.1.97.png", + "images": [] + }, + "proficad": { + "icon": "https://community.chocolatey.org/content/packageimages/proficad.12.2.1.png", + "images": [] + }, + "profileswitcherforfirefox": { + "icon": "", + "images": [] + }, + "program-install-and-uninstall-troubleshooter": { + "icon": "https://community.chocolatey.org/content/packageimages/program-install-and-uninstall-troubleshooter.1.0.0.20201116.png", + "images": [] + }, + "programmer-dvorak": { + "icon": "", + "images": [] + }, + "programmersnotepad": { + "icon": "https://community.chocolatey.org/content/packageimages/programmersnotepad.install.2.4.2.png", + "images": [] + }, + "project-2010-sdk": { + "icon": "https://community.chocolatey.org/content/packageimages/project.2010.sdk.12.0.0.1.png", + "images": [] + }, + "project64": { + "icon": "", + "images": [] + }, + "project64-dev": { + "icon": "", + "images": [] + }, + "projectenvcli": { + "icon": "", + "images": [] + }, + "projectlibre": { + "icon": "https://community.chocolatey.org/content/packageimages/projectlibre.1.9.3.png", + "images": [] + }, + "projectmyscreen": { + "icon": "", + "images": [] + }, + "projecttaskrunner": { + "icon": "", + "images": [] + }, + "projectwise-client": { + "icon": "", + "images": [] + }, + "projectwise-deliverables-management": { + "icon": "", + "images": [] + }, + "projectwise-webapi-for-iis-prereqs": { + "icon": "https://community.chocolatey.org/content/packageimages/projectwise-webapi-for-iis-prereqs.1.0.0.png", + "images": [] + }, + "projectwise-webapi-message-monitor-service": { + "icon": "https://community.chocolatey.org/content/packageimages/projectwise-webapi-message-monitor-service.1.0.1.png", + "images": [] + }, + "projectwise-webapi-service": { + "icon": "https://community.chocolatey.org/content/packageimages/projectwise-webapi-service.1.0.1.png", + "images": [] + }, + "prometheus": { + "icon": "https://community.chocolatey.org/content/packageimages/prometheus.2.2.1.png", + "images": [] + }, + "prometheus-blackbox-exporter": { + "icon": "https://community.chocolatey.org/content/packageimages/prometheus-blackbox-exporter.0.12.0.png", + "images": [] + }, + "prometheus-grok-exporter": { + "icon": "", + "images": [] + }, + "prometheus-pushgateway": { + "icon": "", + "images": [] + }, + "prometheus-windows-exporter": { + "icon": "https://community.chocolatey.org/content/packageimages/prometheus-windows-exporter.install.0.20.0.png", + "images": [] + }, + "prometheus-wmi-exporter": { + "icon": "https://community.chocolatey.org/content/packageimages/prometheus-wmi-exporter.install.0.12.0.png", + "images": [] + }, + "promtail": { + "icon": "", + "images": [] + }, + "propertree": { + "icon": "", + "images": [] + }, + "propresenter": { + "icon": "", + "images": [] + }, + "prospect-mail": { + "icon": "", + "images": [] + }, + "prospectmail": { + "icon": "", + "images": [] + }, + "protectedfolder": { + "icon": "", + "images": [] + }, + "protectmychoices-chrome": { + "icon": "https://community.chocolatey.org/content/packageimages/protectmychoices-chrome.1.2.4.png", + "images": [] + }, + "protobuf": { + "icon": "", + "images": [] + }, + "protoc": { + "icon": "", + "images": [] + }, + "protoc-gen-grpc-web": { + "icon": "", + "images": [] + }, + "protolint": { + "icon": "", + "images": [] + }, + "protoman": { + "icon": "", + "images": [] + }, + "proton": { + "icon": "https://i.postimg.cc/Wp5VcCz8/image.png", + "images": [ + "https://i.postimg.cc/KzFbmytq/image.png" + ] + }, + "protonclient": { + "icon": "https://i.postimg.cc/0yQbq79M/image.png", + "images": [ + "https://i.postimg.cc/gcVwyYMJ/image.png" + ] + }, + "protondrive": { + "icon": "https://i.postimg.cc/RZpFXq57/Proton-Drive.png", + "images": [ + "https://i.postimg.cc/MGtwZFtz/image.png", + "https://i.postimg.cc/HxBPyG7k/image.png", + "https://i.postimg.cc/W3b5j9fL/image.png" + ] + }, + "protonmail": { + "icon": "https://i.postimg.cc/zGYnzbHJ/protonmail.png", + "images": [ + "https://i.postimg.cc/zB6G5QXV/image.png", + "https://i.postimg.cc/SN3gWxX5/mail.png", + "https://i.postimg.cc/P51QYznp/image.png", + "https://i.postimg.cc/XvFmZyQQ/image.png" + ] + }, + "protonmail-bridge": { + "icon": "https://raw.githubusercontent.com/ProtonMail/proton-bridge/master/dist/raw/win%2Blin_icon_256x256.png", + "images": [ + "https://i.postimg.cc/QC1c11Fx/image.png", + "https://i.postimg.cc/fTQcZ2P3/image.png", + "https://i.postimg.cc/XvP5PQFY/image.png" + ] + }, + "protonmailbridge": { + "icon": "https://raw.githubusercontent.com/ProtonMail/proton-bridge/master/dist/raw/win%2Blin_icon_256x256.png", + "images": [ + "https://i.postimg.cc/QC1c11Fx/image.png", + "https://i.postimg.cc/fTQcZ2P3/image.png", + "https://i.postimg.cc/XvP5PQFY/image.png" + ] + }, + "protonpass": { + "icon": "https://i.postimg.cc/8PvZmf2v/protonpass.png", + "images": [ + "https://i.postimg.cc/cLh16CLq/image.png", + "https://i.postimg.cc/sDrN8Xfh/image.png", + "https://i.postimg.cc/htCZf1LL/image.png", + "https://i.postimg.cc/y8qY20gT/image.png", + "https://i.postimg.cc/sDb98H40/image.png", + "https://i.postimg.cc/nLG4XFb6/image.png" + ] + }, + "protonvpn": { + "icon": "https://raw.githubusercontent.com/ProtonVPN/proton-vpn-browser-extension/main/source/img/icon-256.png", + "images": [ + "https://i.postimg.cc/GphzR864/image.png", + "https://i.postimg.cc/x8Sz0Bq6/image.png", + "https://i.postimg.cc/2yQBsfSF/windows-ovpn-9-1024x616.png" + ] + }, + "protonauthenticator": { + "icon": "https://i.postimg.cc/BnByYH70/proton-auth.png", + "images": [ + "https://i.postimg.cc/8zZJmnGg/image.png", + "https://i.postimg.cc/26Z1mkZC/image.png", + "https://i.postimg.cc/L88h5B1C/image.png" + ] + }, + "protopie": { + "icon": "https://i.imgur.com/bsk6EpG.png", + "images": [] + }, + "prowessiq": { + "icon": "", + "images": [] + }, + "prowisepresenter": { + "icon": "", + "images": [] + }, + "prowiz": { + "icon": "", + "images": [] + }, + "prowlarr": { + "icon": "https://community.chocolatey.org/content/packageimages/prowlarr.1.3.1.2796.png", + "images": [] + }, + "proxallium": { + "icon": "https://community.chocolatey.org/content/packageimages/proxallium.0.4.3.png", + "images": [] + }, + "proxifier": { + "icon": "https://community.chocolatey.org/content/packageimages/proxifier.4.11.png", + "images": [] + }, + "proxinject": { + "icon": "", + "images": [] + }, + "proxychains": { + "icon": "", + "images": [] + }, + "proxyman": { + "icon": "", + "images": [] + }, + "prs": { + "icon": "", + "images": [] + }, + "prtgdesktop": { + "icon": "https://community.chocolatey.org/content/packageimages/prtgdesktop.23.0.0.png", + "images": [] + }, + "prusaslicer": { + "icon": "https://community.chocolatey.org/content/packageimages/prusaslicer.2.5.0.png", + "images": [] + }, + "ps3-system-software": { + "icon": "https://i.ibb.co/219fc7pc/playstation-logo-rounded-playstation-logo-free-png-507847634.png", + "images": [] + }, + "ps-remote-play": { + "icon": "", + "images": [] + }, + "ps3mediaserver": { + "icon": "https://community.chocolatey.org/content/packageimages/ps3mediaserver.1.90.1.png", + "images": [] + }, + "psake": { + "icon": "", + "images": [] + }, + "pscodehealth": { + "icon": "https://community.chocolatey.org/content/packageimages/pscodehealth.0.2.26.png", + "images": [] + }, + "pscolor": { + "icon": "", + "images": [] + }, + "pseps": { + "icon": "", + "images": [] + }, + "psframework": { + "icon": "https://community.chocolatey.org/content/packageimages/psframework.1.7.270.png", + "images": [] + }, + "psfzf": { + "icon": "", + "images": [] + }, + "psget": { + "icon": "https://community.chocolatey.org/content/packageimages/PsGet.1.0.4.407.png", + "images": [] + }, + "psgithub": { + "icon": "", + "images": [] + }, + "pshazz": { + "icon": "", + "images": [] + }, + "pshtml-powershell": { + "icon": "https://community.chocolatey.org/content/packageimages/pshtml.powershell.0.8.2.png", + "images": [] + }, + "psi": { + "icon": "https://community.chocolatey.org/content/packageimages/psi.1.3.png", + "images": [] + }, + "psievm": { + "icon": "https://community.chocolatey.org/content/packageimages/psievm.0.2.7.29815.png", + "images": [] + }, + "psinfo": { + "icon": "", + "images": [] + }, + "psiphon": { + "icon": "https://community.chocolatey.org/content/packageimages/psiphon.3.0.0.20150720.png", + "images": [] + }, + "psiphon3": { + "icon": "", + "images": [] + }, + "pskubectlcompletion": { + "icon": "", + "images": [] + }, + "psloggedon": { + "icon": "", + "images": [] + }, + "psloglist": { + "icon": "", + "images": [] + }, + "psmsi": { + "icon": "", + "images": [] + }, + "pspad": { + "icon": "https://upload.wikimedia.org/wikipedia/en/d/df/Pspad_256x256.png", + "images": [] + }, + "psping": { + "icon": "", + "images": [] + }, + "psplus": { + "icon": "", + "images": [] + }, + "psql": { + "icon": "https://community.chocolatey.org/content/packageimages/psql.15.0.png", + "images": [] + }, + "psqlodbc": { + "icon": "https://community.chocolatey.org/content/packageimages/psqlodbc.13.02.0000.png", + "images": [] + }, + "psreadline": { + "icon": "", + "images": [] + }, + "psremoteplay": { + "icon": "", + "images": [] + }, + "psscriptanalyzer": { + "icon": "https://community.chocolatey.org/content/packageimages/PSScriptAnalyzer.1.21.0.png", + "images": [] + }, + "psshutdown": { + "icon": "", + "images": [] + }, + "psstringtemplate": { + "icon": "https://community.chocolatey.org/content/packageimages/psstringtemplate.0.2.0.png", + "images": [] + }, + "pst-merger": { + "icon": "https://community.chocolatey.org/content/packageimages/pst-merger.1.03.5016.png", + "images": [] + }, + "pstpassword": { + "icon": "https://community.chocolatey.org/content/packageimages/pstpassword.install.1.20.png", + "images": [] + }, + "psubst": { + "icon": "", + "images": [] + }, + "psutils": { + "icon": "", + "images": [] + }, + "psvso": { + "icon": "", + "images": [] + }, + "psvsts": { + "icon": "", + "images": [] + }, + "pswindowsupdate": { + "icon": "https://community.chocolatey.org/content/packageimages/PSWindowsUpdate.2.2.0.3.png", + "images": [] + }, + "pt": { + "icon": "", + "images": [] + }, + "ptags": { + "icon": "", + "images": [] + }, + "pterm": { + "icon": "", + "images": [] + }, + "ptimer": { + "icon": "", + "images": [] + }, + "public": { + "icon": "", + "images": [] + }, + "publii": { + "icon": "", + "images": [] + }, + "publishedapplications": { + "icon": "", + "images": [] + }, + "publishorperish": { + "icon": "", + "images": [] + }, + "pueue": { + "icon": "", + "images": [] + }, + "pullp": { + "icon": "", + "images": [] + }, + "pulse": { + "icon": "https://community.chocolatey.org/content/packageimages/pulse.0.1.4.png", + "images": [] + }, + "pulseaudio": { + "icon": "https://community.chocolatey.org/content/packageimages/pulseaudio.1.1.png", + "images": [] + }, + "pulsesms": { + "icon": "", + "images": [] + }, + "pulseview": { + "icon": "https://community.chocolatey.org/content/packageimages/pulseview.0.4.2.png", + "images": [ + "https://i.postimg.cc/Nj0DD2w7/image.png", + "https://i.postimg.cc/VNrRQyvJ/image.png", + "https://i.postimg.cc/6qwLvy0Z/image.png" + ] + }, + "pulseview-nightly": { + "icon": "https://community.chocolatey.org/content/packageimages/pulseview.0.4.2.png", + "images": [ + "https://i.postimg.cc/Nj0DD2w7/image.png", + "https://i.postimg.cc/VNrRQyvJ/image.png", + "https://i.postimg.cc/6qwLvy0Z/image.png" + ] + }, + "pulseway": { + "icon": "https://community.chocolatey.org/content/packageimages/pulseway.4.7.0.png", + "images": [] + }, + "pulumi": { + "icon": "", + "images": [] + }, + "pulumictl": { + "icon": "https://community.chocolatey.org/content/packageimages/pulumictl.0.0.42.png", + "images": [] + }, + "punktf": { + "icon": "https://community.chocolatey.org/content/packageimages/punktf.3.0.0.png", + "images": [] + }, + "puntoswitcher": { + "icon": "", + "images": [] + }, + "pup": { + "icon": "", + "images": [] + }, + "pupafm": { + "icon": "", + "images": [] + }, + "puppet": { + "icon": "", + "images": [] + }, + "puppet-agent": { + "icon": "https://community.chocolatey.org/content/packageimages/puppet-agent.7.21.0.png", + "images": [] + }, + "puppet-bolt": { + "icon": "https://community.chocolatey.org/content/packageimages/puppet-bolt.3.26.2.png", + "images": [] + }, + "puppetry": { + "icon": "", + "images": [] + }, + "puranfilerecovery": { + "icon": "", + "images": [] + }, + "pure-data": { + "icon": "", + "images": [] + }, + "purecodec": { + "icon": "", + "images": [] + }, + "puredata": { + "icon": "https://community.chocolatey.org/content/packageimages/puredata.0.53.1.png", + "images": [] + }, + "pureref": { + "icon": "", + "images": [] + }, + "purescript": { + "icon": "https://community.chocolatey.org/content/packageimages/purescript.0.15.7.png", + "images": [] + }, + "puretext": { + "icon": "https://community.chocolatey.org/content/packageimages/puretext.6.2.png", + "images": [] + }, + "puretextplus": { + "icon": "https://community.chocolatey.org/content/packageimages/PureTextPlus.3.0.6.2.png", + "images": [] + }, + "purewriter": { + "icon": "", + "images": [] + }, + "purple-facebook": { + "icon": "", + "images": [] + }, + "purplepen": { + "icon": "https://community.chocolatey.org/content/packageimages/purplepen.3.4.1.png", + "images": [] + }, + "pushbullet": { + "icon": "", + "images": [] + }, + "pushbullet-chrome": { + "icon": "", + "images": [] + }, + "pushcsv": { + "icon": "", + "images": [] + }, + "puttie": { + "icon": "", + "images": [] + }, + "putty": { + "icon": "https://i.postimg.cc/WzjtrBVC/putty-icon.png", + "images": [ + "https://i.ibb.co/JWq9ZZMp/Image.png", + "https://i.postimg.cc/yNZqgJfn/image.png", + "https://i.postimg.cc/qR2zNkP2/putty.png" + ] + }, + "putty-cac": { + "icon": "https://community.chocolatey.org/content/packageimages/putty-cac.0.78.0.1.png", + "images": [] + }, + "putty-d2ddw": { + "icon": "", + "images": [] + }, + "putty-nd": { + "icon": "https://community.chocolatey.org/content/packageimages/putty-nd.7.9.0.png", + "images": [] + }, + "puttytel": { + "icon": "", + "images": [] + }, + "puush": { + "icon": "https://community.chocolatey.org/content/packageimages/puush.1.0.0.png", + "images": [] + }, + "pvc": { + "icon": "https://community.chocolatey.org/content/packageimages/Pvc.0.0.2.2.png", + "images": [] + }, + "pviewer": { + "icon": "", + "images": [] + }, + "pvplounge": { + "icon": "", + "images": [] + }, + "pvs-studio": { + "icon": "https://community.chocolatey.org/content/packageimages/pvs-studio.7.23.68542.86.png", + "images": [ + "https://i.postimg.cc/rwz0mx25/image.png", + "https://i.postimg.cc/bwGr8P1v/image.png", + "https://i.postimg.cc/3RZJ9xHk/image.png", + "https://i.postimg.cc/9XJQ70pz/image.png" + ] + }, + "pwgen": { + "icon": "https://community.chocolatey.org/content/packageimages/pwgen.install.3.4.5.png", + "images": [] + }, + "pwsafe": { + "icon": "", + "images": [] + }, + "pwsh": { + "icon": "", + "images": [] + }, + "pwtech": { + "icon": "", + "images": [] + }, + "px": { + "icon": "", + "images": [] + }, + "pxcook": { + "icon": "", + "images": [] + }, + "pyaudio": { + "icon": "", + "images": [] + }, + "pycharm": { + "icon": "https://community.chocolatey.org/content/packageimages/Pycharm.2022.3.2.png", + "images": [] + }, + "pycharm-community": { + "icon": "https://resources.jetbrains.com/storage/products/pycharm/img/meta/pycharm_logo_300x300.png", + "images": [ + "https://origin2.cdn.componentsource.com/sites/default/files/styles/image_large/public/images/product_description/jetbrains/pycharm/img_484761.png" + ] + }, + "pycharm-community-eap": { + "icon": "https://resources.jetbrains.com/storage/products/pycharm/img/meta/pycharm_logo_300x300.png", + "images": [ + "https://origin2.cdn.componentsource.com/sites/default/files/styles/image_large/public/images/product_description/jetbrains/pycharm/img_484761.png" + ] + }, + "pycharm-edu": { + "icon": "https://community.chocolatey.org/content/packageimages/pycharm-edu.2022.2.2.png", + "images": [] + }, + "pycharm-professional": { + "icon": "https://resources.jetbrains.com/storage/products/pycharm/img/meta/pycharm_logo_300x300.png", + "images": [ + "https://origin2.cdn.componentsource.com/sites/default/files/styles/image_large/public/images/product_description/jetbrains/pycharm/img_484761.png" + ] + }, + "pycharm-professional-eap": { + "icon": "https://resources.jetbrains.com/storage/products/pycharm/img/meta/pycharm_logo_300x300.png", + "images": [ + "https://origin2.cdn.componentsource.com/sites/default/files/styles/image_large/public/images/product_description/jetbrains/pycharm/img_484761.png" + ] + }, + "pydebloatx": { + "icon": "", + "images": [] + }, + "pydev": { + "icon": "https://community.chocolatey.org/content/packageimages/pydev.10.1.3.png", + "images": [] + }, + "pydiosync": { + "icon": "https://community.chocolatey.org/content/packageimages/pydiosync.1.2.5.png", + "images": [] + }, + "pyenv": { + "icon": "", + "images": [] + }, + "pyexiftoolgui": { + "icon": "https://community.chocolatey.org/content/packageimages/pyexiftoolgui.0.5.png", + "images": [] + }, + "pyfa": { + "icon": "", + "images": [] + }, + "pyflow": { + "icon": "", + "images": [] + }, + "pyftpsync": { + "icon": "", + "images": [] + }, + "pygtk-all-in-one-win32-py2-7": { + "icon": "", + "images": [] + }, + "pyhoca-gui": { + "icon": "", + "images": [] + }, + "Pylogmon-pot": { + "icon": "https://cdn.staticaly.com/gh/Pylogmon/pot/master/public/icon.png", + "images": [ + "https://cdn.staticaly.com/gh/Pylogmon/pot/master/asset/dark.png", + "https://cdn.staticaly.com/gh/Pylogmon/pot/master/asset/example.png", + "https://cdn.staticaly.com/gh/Pylogmon/pot/master/asset/light.png" + ] + }, + "pymca": { + "icon": "https://community.chocolatey.org/content/packageimages/pymca.5.8.0.png", + "images": [] + }, + "pymoda": { + "icon": "", + "images": [] + }, + "pymol": { + "icon": "", + "images": [] + }, + "pympress": { + "icon": "", + "images": [] + }, + "pyprime": { + "icon": "", + "images": [] + }, + "pypy2": { + "icon": "", + "images": [] + }, + "pypy3": { + "icon": "https://community.chocolatey.org/content/packageimages/pypy3.7.3.4.20210425.png", + "images": [] + }, + "pyqt4": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/e/e6/Python_and_Qt.svg/1200px-Python_and_Qt.svg.png", + "images": [] + }, + "pyqt5": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/e/e6/Python_and_Qt.svg/1200px-Python_and_Qt.svg.png", + "images": [] + }, + "pyqt5_sip": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/e/e6/Python_and_Qt.svg/1200px-Python_and_Qt.svg.png", + "images": [] + }, + "pyqt5-qt5": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/e/e6/Python_and_Qt.svg/1200px-Python_and_Qt.svg.png", + "images": [] + }, + "pyqt6": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/e/e6/Python_and_Qt.svg/1200px-Python_and_Qt.svg.png", + "images": [] + }, + "pyqt6_sip": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/e/e6/Python_and_Qt.svg/1200px-Python_and_Qt.svg.png", + "images": [] + }, + "pyqt6-qt6": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/e/e6/Python_and_Qt.svg/1200px-Python_and_Qt.svg.png", + "images": [] + }, + "pyqtwebengine": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/e/e6/Python_and_Qt.svg/1200px-Python_and_Qt.svg.png", + "images": [] + }, + "pyqtwebengine-qt5": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/e/e6/Python_and_Qt.svg/1200px-Python_and_Qt.svg.png", + "images": [] + }, + "pyqtwebengine-qt6": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/e/e6/Python_and_Qt.svg/1200px-Python_and_Qt.svg.png", + "images": [] + }, + "pyrevit-cli": { + "icon": "https://community.chocolatey.org/content/packageimages/pyrevit-cli.4.8.12.22247.png", + "images": [] + }, + "pytest": { + "icon": "https://raw.githubusercontent.com/pytest-dev/pytest/main/doc/en/_static/pytest1.png", + "images": [] + }, + "python": { + "icon": "https://s3.dualstack.us-east-2.amazonaws.com/pythondotorg-assets/media/community/logos/python-logo-only.png", + "images": [] + }, + "python-2": { + "icon": "https://cdn4.iconfinder.com/data/icons/logos-and-brands/512/267_Python_logo-1024.png", + "images": [] + }, + "python-3-0": { + "icon": "https://cdn4.iconfinder.com/data/icons/logos-and-brands/512/267_Python_logo-1024.png", + "images": [] + }, + "python-3-1": { + "icon": "https://cdn4.iconfinder.com/data/icons/logos-and-brands/512/267_Python_logo-1024.png", + "images": [] + }, + "python-3-10": { + "icon": "https://cdn4.iconfinder.com/data/icons/logos-and-brands/512/267_Python_logo-1024.png", + "images": [ + "https://i.postimg.cc/NFqHC0Bj/Python-IDLE.png" + ] + }, + "python-3-11": { + "icon": "https://cdn4.iconfinder.com/data/icons/logos-and-brands/512/267_Python_logo-1024.png", + "images": [] + }, + "python-3-12": { + "icon": "https://cdn4.iconfinder.com/data/icons/logos-and-brands/512/267_Python_logo-1024.png", + "images": [] + }, + "python-3-13": { + "icon": "https://cdn4.iconfinder.com/data/icons/logos-and-brands/512/267_Python_logo-1024.png", + "images": [] + }, + "python-3-2": { + "icon": "https://cdn4.iconfinder.com/data/icons/logos-and-brands/512/267_Python_logo-1024.png", + "images": [] + }, + "python-3-3": { + "icon": "https://cdn4.iconfinder.com/data/icons/logos-and-brands/512/267_Python_logo-1024.png", + "images": [] + }, + "python-3-4": { + "icon": "https://cdn4.iconfinder.com/data/icons/logos-and-brands/512/267_Python_logo-1024.png", + "images": [] + }, + "python-3-5": { + "icon": "https://cdn4.iconfinder.com/data/icons/logos-and-brands/512/267_Python_logo-1024.png", + "images": [] + }, + "python-3-6": { + "icon": "https://cdn4.iconfinder.com/data/icons/logos-and-brands/512/267_Python_logo-1024.png", + "images": [] + }, + "python-3-7": { + "icon": "https://cdn4.iconfinder.com/data/icons/logos-and-brands/512/267_Python_logo-1024.png", + "images": [] + }, + "python-3-8": { + "icon": "https://cdn4.iconfinder.com/data/icons/logos-and-brands/512/267_Python_logo-1024.png", + "images": [] + }, + "python-3-9": { + "icon": "https://cdn4.iconfinder.com/data/icons/logos-and-brands/512/267_Python_logo-1024.png", + "images": [] + }, + "python-cheetah": { + "icon": "https://community.chocolatey.org/content/packageimages/Python.Cheetah.2.4.4.png", + "images": [] + }, + "python-pypy": { + "icon": "https://community.chocolatey.org/content/packageimages/python.pypy.7.3.4.20210425.png", + "images": [] + }, + "python-wxwidgets": { + "icon": "", + "images": [] + }, + "python-x86": { + "icon": "", + "images": [] + }, + "python2": { + "icon": "", + "images": [] + }, + "python2-x86-32": { + "icon": "", + "images": [] + }, + "python3-virtualenv": { + "icon": "", + "images": [] + }, + "python3-x86-32": { + "icon": "", + "images": [] + }, + "python310": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/7/7f/Python_Windows_setup_icon_2016.svg/512px-Python_Windows_setup_icon_2016.svg.png", + "images": [] + }, + "python311": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/7/7f/Python_Windows_setup_icon_2016.svg/512px-Python_Windows_setup_icon_2016.svg.png", + "images": [] + }, + "python35": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/7/7f/Python_Windows_setup_icon_2016.svg/512px-Python_Windows_setup_icon_2016.svg.png", + "images": [] + }, + "python36": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/7/7f/Python_Windows_setup_icon_2016.svg/512px-Python_Windows_setup_icon_2016.svg.png", + "images": [] + }, + "python37": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/7/7f/Python_Windows_setup_icon_2016.svg/512px-Python_Windows_setup_icon_2016.svg.png", + "images": [] + }, + "python38": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/7/7f/Python_Windows_setup_icon_2016.svg/512px-Python_Windows_setup_icon_2016.svg.png", + "images": [] + }, + "pythonlauncher": { + "icon": "https://cdn4.iconfinder.com/data/icons/logos-and-brands/512/267_Python_logo-1024.png", + "images": [] + }, + "pythontkguibuilder": { + "icon": "", + "images": [] + }, + "pytigon": { + "icon": "", + "images": [] + }, + "pytivo-desktop": { + "icon": "https://community.chocolatey.org/content/packageimages/pytivo-desktop.1.6.16.0020180601.png", + "images": [] + }, + "pytivo-lucasnz": { + "icon": "", + "images": [] + }, + "pytivo-wmcbrine": { + "icon": "https://community.chocolatey.org/content/packageimages/pytivo-wmcbrine.2018.05.09.png", + "images": [] + }, + "pywin32": { + "icon": "https://cdn.iconscout.com/icon/free/png-256/free-python-logo-icon-download-in-svg-png-gif-file-formats--technology-social-media-vol-5-pack-logos-icons-2945099.png?f=webp&w=256", + "images": [] + }, + "pyzo": { + "icon": "https://community.chocolatey.org/content/packageimages/pyzo.portable.4.12.7.png", + "images": [] + }, + "q": { + "icon": "", + "images": [] + }, + "q-dir": { + "icon": "https://i.postimg.cc/QdfRWNPY/Q-Dir.png", + "images": [ + "https://i.postimg.cc/tJdcR9W5/Q-Dir-1.png" + ] + }, + "q-dns": { + "icon": "", + "images": [] + }, + "q10": { + "icon": "https://community.chocolatey.org/content/packageimages/q10.portable.1.2.21.png", + "images": [] + }, + "qaac": { + "icon": "", + "images": [] + }, + "qalculate": { + "icon": "https://community.chocolatey.org/content/packageimages/qalculate.4.5.1.png", + "images": [] + }, + "qawl": { + "icon": "", + "images": [] + }, + "qbittorrent": { + "icon": "https://i.ibb.co/9mQ0y0MX/Image.png", + "images": [ + "https://i.postimg.cc/gkCHcnZG/image.png", + "https://i.postimg.cc/k4sdpppV/image.png", + "https://i.postimg.cc/s2bQ12B4/QBittorrent-4-3-9-screenshot.png" + ] + }, + "qbittorrent-enhanced": { + "icon": "https://i.ibb.co/9mQ0y0MX/Image.png", + "images": [ + "https://i.postimg.cc/gkCHcnZG/image.png" + ] + }, + "qbs": { + "icon": "https://community.chocolatey.org/content/packageimages/qbs.1.23.1.png", + "images": [] + }, + "qc-doom-edition": { + "icon": "https://community.chocolatey.org/content/packageimages/qc-doom-edition.2.7.0.png", + "images": [] + }, + "qcad": { + "icon": "https://community.chocolatey.org/content/packageimages/qcad.3.27.9.png", + "images": [] + }, + "qdir": { + "icon": "https://community.chocolatey.org/content/packageimages/qdir.11.19.png", + "images": [] + }, + "qemu": { + "icon": "", + "images": [] + }, + "qemu-guest-agent": { + "icon": "", + "images": [] + }, + "qemu-img": { + "icon": "", + "images": [] + }, + "qencdecrypter": { + "icon": "", + "images": [ + "https://i.postimg.cc/5tM926Bj/image.png", + "https://i.postimg.cc/rszMPWkZ/image.png" + ] + }, + "qet": { + "icon": "https://community.chocolatey.org/content/packageimages/qet.0.90.7758.png", + "images": [] + }, + "qfinderpro": { + "icon": "https://community.chocolatey.org/content/packageimages/qfinderpro.7.8.3.1309.png", + "images": [ + "https://i.postimg.cc/SRGCDBmf/image.png", + "https://i.postimg.cc/tRd3qxFn/image.png", + "https://i.postimg.cc/KvJtLhqZ/image.png" + ] + }, + "qflipper": { + "icon": "https://community.chocolatey.org/content/packageimages/qflipper.1.1.2.png", + "images": [] + }, + "qgis": { + "icon": "https://community.chocolatey.org/content/packageimages/QGIS.3.28.3.png", + "images": [] + }, + "qgis-ltr": { + "icon": "https://community.chocolatey.org/content/packageimages/QGIS-LTR.3.22.16.png", + "images": [] + }, + "qgroundcontrol": { + "icon": "", + "images": [] + }, + "qianji": { + "icon": "", + "images": [] + }, + "qidian": { + "icon": "", + "images": [] + }, + "qikqr": { + "icon": "", + "images": [] + }, + "qimgv": { + "icon": "https://community.chocolatey.org/content/packageimages/qimgv.1.0.2.png", + "images": [] + }, + "qimgv-video": { + "icon": "", + "images": [] + }, + "qiniuclient": { + "icon": "", + "images": [] + }, + "qip2012": { + "icon": "https://community.chocolatey.org/content/packageimages/qip2012.4.0.9380.png", + "images": [] + }, + "qiyu": { + "icon": "", + "images": [] + }, + "qlcplus": { + "icon": "", + "images": [] + }, + "qmk-toolbox": { + "icon": "", + "images": [] + }, + "qmktoolbox": { + "icon": "", + "images": [] + }, + "qmmp": { + "icon": "https://community.chocolatey.org/content/packageimages/qmmp.2.1.2.png", + "images": [] + }, + "qmplay2": { + "icon": "https://community.chocolatey.org/content/packageimages/qmplay2.22.10.23.png", + "images": [] + }, + "qnapi": { + "icon": "https://community.chocolatey.org/content/packageimages/qnapi.0.2.3.png", + "images": [] + }, + "qownnotes": { + "icon": "", + "images": [] + }, + "qpdf": { + "icon": "", + "images": [] + }, + "qpmx": { + "icon": "", + "images": [] + }, + "qq": { + "icon": "https://sqimg.qq.com/qq_product_operations/im/mac/5.0/images/share-img.png", + "images": [ + "https://im.qq.com/pcqq/images/new/big-chat-desk.png", + "https://im.qq.com/pcqq/images/new/login.png" + ] + }, + "qq-devtool": { + "icon": "", + "images": [] + }, + "qq-nt": { + "icon": "https://qzonestyle.gtimg.cn/qzone/qzact/act/external/tiqq/logo.png", + "images": [] + }, + "qqbrowser": { + "icon": "https://logos.fandom.com/wiki/QQ_Browser?file=QQ_Browser_2014.png", + "images": [] + }, + "qqimage": { + "icon": "", + "images": [] + }, + "qqmusic": { + "icon": "https://i.postimg.cc/VLdpMRY5/QQMusic.png", + "images": [] + }, + "qqpinyin": { + "icon": "", + "images": [] + }, + "qqplayer": { + "icon": "", + "images": [] + }, + "qqwubi": { + "icon": "", + "images": [] + }, + "qr": { + "icon": "", + "images": [] + }, + "qr-code-studio": { + "icon": "https://community.chocolatey.org/content/packageimages/qr-code-studio.2.0.1.png", + "images": [] + }, + "qr-codereader": { + "icon": "https://raw.githubusercontent.com/ottozumkeller/QR-Code-Reader/main/Images/logo_dark.png", + "images": [ + "https://raw.githubusercontent.com/ottozumkeller/QR-Code-Reader/main/Images/screenshot_1_dark.png" + ] + }, + "qrcp": { + "icon": "", + "images": [] + }, + "qrencode": { + "icon": "", + "images": [] + }, + "qrscan": { + "icon": "", + "images": [] + }, + "qsirch": { + "icon": "", + "images": [ + "https://i.postimg.cc/C1kQLx4M/image.png" + ] + }, + "qsync": { + "icon": "https://community.chocolatey.org/content/packageimages/qsync.5.0.7.1122.png", + "images": [ + "https://i.postimg.cc/Y9HvZdnn/image.png", + "https://i.postimg.cc/HnWVsVCb/image.png", + "https://i.postimg.cc/gkJnCXsW/image.png", + "https://i.postimg.cc/Gh5HdLgs/image.png" + ] + }, + "qt-creator": { + "icon": "", + "images": [] + }, + "qt-creator-cdb-ext": { + "icon": "", + "images": [] + }, + "qt-creator-wininterrupt": { + "icon": "", + "images": [] + }, + "qt-creator-x64": { + "icon": "", + "images": [] + }, + "qt-creator-x86": { + "icon": "", + "images": [] + }, + "qt-installer-framework": { + "icon": "", + "images": [] + }, + "qt-sdk": { + "icon": "", + "images": [] + }, + "qt-sdk-android-x86": { + "icon": "", + "images": [] + }, + "qt-sdk-windows-x64-mingw-opengl-seh": { + "icon": "", + "images": [] + }, + "qt-sdk-windows-x64-mingw-opengl-sjlj": { + "icon": "", + "images": [] + }, + "qt-sdk-windows-x64-mingw-seh": { + "icon": "", + "images": [] + }, + "qt-sdk-windows-x64-mingw-sjlj": { + "icon": "", + "images": [] + }, + "qt-sdk-windows-x64-msvc2010": { + "icon": "", + "images": [] + }, + "qt-sdk-windows-x64-msvc2010-opengl": { + "icon": "", + "images": [] + }, + "qt-sdk-windows-x64-msvc2012": { + "icon": "", + "images": [] + }, + "qt-sdk-windows-x64-msvc2012-opengl": { + "icon": "", + "images": [] + }, + "qt-sdk-windows-x86-mingw-opengl": { + "icon": "", + "images": [] + }, + "qt-sdk-windows-x86-msvc2010-opengl": { + "icon": "", + "images": [] + }, + "qt-sdk-windows-x86-msvc2013": { + "icon": "", + "images": [] + }, + "qt-sdk-windows-x86-msvc2013-opengl": { + "icon": "", + "images": [] + }, + "qt-sdk-windowsrt-x86": { + "icon": "", + "images": [] + }, + "qt-vs-addin5": { + "icon": "", + "images": [] + }, + "qt5-default": { + "icon": "https://community.chocolatey.org/content/packageimages/qt5-default.5.15.2.20220508.png", + "images": [] + }, + "qtbinpatcher-x64": { + "icon": "", + "images": [] + }, + "qtbinpatcher-x86": { + "icon": "", + "images": [] + }, + "qtcreator": { + "icon": "https://community.chocolatey.org/content/packageimages/qtcreator.9.0.2.png", + "images": [] + }, + "qtcreator-cdbext": { + "icon": "https://community.chocolatey.org/content/packageimages/qtcreator-cdbext.9.0.2.png", + "images": [] + }, + "qtdesigner": { + "icon": "", + "images": [] + }, + "qtdsync": { + "icon": "https://community.chocolatey.org/content/packageimages/qtdsync.0.6.20.png", + "images": [] + }, + "qtemu": { + "icon": "", + "images": [] + }, + "qtextpad": { + "icon": "", + "images": [] + }, + "qtodotxt": { + "icon": "", + "images": [] + }, + "qtox": { + "icon": "", + "images": [] + }, + "qtpass": { + "icon": "", + "images": [] + }, + "qtranslate": { + "icon": "https://community.chocolatey.org/content/packageimages/qtranslate.6.8.0.1.png", + "images": [] + }, + "qtscrcpy": { + "icon": "", + "images": [] + }, + "qttabbar": { + "icon": "https://community.chocolatey.org/content/packageimages/QTTabBar.1043.0.png", + "images": [] + }, + "quadriga": { + "icon": "", + "images": [] + }, + "quamotion": { + "icon": "", + "images": [] + }, + "quantumdreams": { + "icon": "https://community.chocolatey.org/content/packageimages/quantumdreams.0.1.20160513.png", + "images": [] + }, + "quantumgis": { + "icon": "", + "images": [] + }, + "quantumkit": { + "icon": "", + "images": [] + }, + "quantumshooter": { + "icon": "https://community.chocolatey.org/content/packageimages/quantumshooter.0.1.20160513.png", + "images": [] + }, + "quark": { + "icon": "", + "images": [] + }, + "quarkclouddrive": { + "icon": "", + "images": [] + }, + "quarkus": { + "icon": "https://community.chocolatey.org/content/packageimages/quarkus.2.16.3.png", + "images": [] + }, + "quarkus-cli": { + "icon": "", + "images": [] + }, + "quarto": { + "icon": "https://community.chocolatey.org/content/packageimages/quarto.1.2.335.png", + "images": [] + }, + "quartz": { + "icon": "", + "images": [] + }, + "quassel": { + "icon": "", + "images": [] + }, + "quasselirc": { + "icon": "", + "images": [] + }, + "qudedupextracttool": { + "icon": "", + "images": [ + "https://i.postimg.cc/HsBPLKbM/image.png", + "https://i.postimg.cc/J46P8XWc/image.png", + "https://i.postimg.cc/rpWJ5YRQ/image.png" + ] + }, + "queryexplus": { + "icon": "", + "images": [] + }, + "questdb": { + "icon": "", + "images": [] + }, + "questpatcher": { + "icon": "", + "images": [] + }, + "queueexplorer-professional": { + "icon": "https://i.postimg.cc/BQd3nbmP/qe.png", + "images": [ + "https://i.postimg.cc/xdQSL7D0/image.png", + "https://i.postimg.cc/sxWrYRXg/image.png" + ] + }, + "queueexplorer": { + "icon": "https://i.postimg.cc/BQd3nbmP/qe.png", + "images": [ + "https://i.postimg.cc/xdQSL7D0/image.png", + "https://i.postimg.cc/sxWrYRXg/image.png" + ] + }, + "queuemonitor-pro": { + "icon": "https://i.postimg.cc/XqSh0Bjn/qm.png", + "images": [ + "https://i.postimg.cc/sXqtT0QH/image.png", + "https://i.postimg.cc/fW04VZpG/image.png", + "https://i.postimg.cc/fTx6vCw5/image.png" + ] + }, + "queuemonitor-std": { + "icon": "https://i.postimg.cc/XqSh0Bjn/qm.png", + "images": [ + "https://i.postimg.cc/sXqtT0QH/image.png", + "https://i.postimg.cc/fW04VZpG/image.png", + "https://i.postimg.cc/fTx6vCw5/image.png" + ] + }, + "quick-javascript-switcher-chrome": { + "icon": "", + "images": [] + }, + "quick-lint-js": { + "icon": "https://community.chocolatey.org/content/packageimages/quick-lint-js.2.11.0.png", + "images": [] + }, + "quick-picture-viewer": { + "icon": "", + "images": [] + }, + "quickappide": { + "icon": "", + "images": [] + }, + "quickapppcassistant": { + "icon": "", + "images": [] + }, + "quickclean": { + "icon": "", + "images": [] + }, + "quickcpu": { + "icon": "https://i.postimg.cc/vB6bVmBG/QuickCPU.png", + "images": [] + }, + "quicken": { + "icon": "", + "images": [] + }, + "quicker": { + "icon": "", + "images": [] + }, + "quickfixmypic": { + "icon": "https://community.chocolatey.org/content/packageimages/quickfixmypic.1.0.1.png", + "images": [] + }, + "quicklook": { + "icon": "https://i.postimg.cc/ZR64Y5Yv/quick-ico.png", + "images": [ + "https://i.postimg.cc/y8G1ScgX/ql1.png" + ] + }, + "quickpar": { + "icon": "https://community.chocolatey.org/content/packageimages/QuickPar.0.9.1.20181112.png", + "images": [] + }, + "quickpictureviewer": { + "icon": "", + "images": [] + }, + "quickredis": { + "icon": "", + "images": [] + }, + "quickroute": { + "icon": "https://community.chocolatey.org/content/packageimages/quickroute.2.4.0.png", + "images": [] + }, + "quicksecs": { + "icon": "", + "images": [] + }, + "quicksfv": { + "icon": "", + "images": [] + }, + "quickshare": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/d/dc/Quickshare.svg/1200px-Quickshare.svg.png", + "images": [] + }, + "quickstart-defaultinstall": { + "icon": "", + "images": [] + }, + "quickstart2": { + "icon": "", + "images": [] + }, + "quicktextpaste": { + "icon": "", + "images": [] + }, + "quicktime": { + "icon": "https://community.chocolatey.org/content/packageimages/Quicktime.7.7.9.20161124.png", + "images": [] + }, + "quickviewer": { + "icon": "https://community.chocolatey.org/content/packageimages/quickviewer.1.1.8.png", + "images": [] + }, + "quicreach": { + "icon": "", + "images": [] + }, + "quiet": { + "icon": "https://community.chocolatey.org/content/packageimages/quiet.1.01.00.20211221.png", + "images": [] + }, + "quikpak": { + "icon": "", + "images": [] + }, + "quiterss": { + "icon": "https://community.chocolatey.org/content/packageimages/quiterss.0.19.4.png", + "images": [] + }, + "quixelbridge": { + "icon": "https://community.chocolatey.org/content/packageimages/quixelbridge.2020.3.2.png", + "images": [] + }, + "quodlibet": { + "icon": "https://community.chocolatey.org/content/packageimages/quodlibet.install.4.5.0.png", + "images": [] + }, + "quollwriter": { + "icon": "https://community.chocolatey.org/content/packageimages/quollwriter.3.0.1.png", + "images": [] + }, + "qupath": { + "icon": "", + "images": [] + }, + "qutebrowser": { + "icon": "https://community.chocolatey.org/content/packageimages/qutebrowser.install.2.5.2.png", + "images": [] + }, + "qutemol": { + "icon": "", + "images": [] + }, + "qv2ray": { + "icon": "https://community.chocolatey.org/content/packageimages/qv2ray.portable.3.0.0.png", + "images": [] + }, + "qv2ray-dev": { + "icon": "", + "images": [] + }, + "qview": { + "icon": "https://community.chocolatey.org/content/packageimages/qview.portable.5.0.png", + "images": [] + }, + "qvrproclient": { + "icon": "", + "images": [ + "https://i.postimg.cc/C5MsThPQ/image.png", + "https://i.postimg.cc/X7mdxkbh/image.png", + "https://i.postimg.cc/fRdXPSWb/image.png", + "https://i.postimg.cc/bvjbfYd9/image.png", + "https://i.postimg.cc/5yjQS6kb/image.png" + ] + }, + "qws": { + "icon": "", + "images": [] + }, + "r": { + "icon": "https://www.r-project.org/logo/Rlogo.png", + "images": [] + }, + "r-latest": { + "icon": "", + "images": [] + }, + "r-project": { + "icon": "", + "images": [] + }, + "r-studio": { + "icon": "https://i.postimg.cc/XJpRzw46/R-Studio-icon.png", + "images": [ + "https://i.postimg.cc/vmqRhPRv/R-Studio-1.png", + "https://i.postimg.cc/d1pbPLVk/R-Studio-2.png" + ] + }, + "r128gain": { + "icon": "", + "images": [] + }, + "r6rc": { + "icon": "", + "images": [] + }, + "rabbitmq": { + "icon": "https://community.chocolatey.org/content/packageimages/rabbitmq.3.11.9.png", + "images": [] + }, + "rabbitmqadmin": { + "icon": "", + "images": [] + }, + "raccine": { + "icon": "", + "images": [] + }, + "rack": { + "icon": "https://community.chocolatey.org/content/packageimages/rack.1.2.2016072901.png", + "images": [] + }, + "racket": { + "icon": "", + "images": [] + }, + "racket-minimal": { + "icon": "", + "images": [] + }, + "radare2": { + "icon": "", + "images": [] + }, + "radarr": { + "icon": "", + "images": [] + }, + "radiant": { + "icon": "https://community.chocolatey.org/content/packageimages/radiant.2022.1.1.png", + "images": [] + }, + "radmin-server": { + "icon": "", + "images": [] + }, + "radmin-viewer": { + "icon": "", + "images": [] + }, + "rage": { + "icon": "", + "images": [] + }, + "ragel": { + "icon": "", + "images": [] + }, + "raidar": { + "icon": "", + "images": [] + }, + "raidcall": { + "icon": "", + "images": [] + }, + "raidrive": { + "icon": "https://community.chocolatey.org/content/packageimages/raidrive.2022.6.92.png", + "images": [ + "https://i.postimg.cc/hvSqbrV1/image.png", + "https://i.postimg.cc/K8KhN43w/image.png", + "https://i.postimg.cc/7YKq9psG/image.png", + "https://i.postimg.cc/C5YwrYpD/image.png" + ] + }, + "railsinstaller": { + "icon": "", + "images": [] + }, + "railway": { + "icon": "", + "images": [] + }, + "rainbow": { + "icon": "", + "images": [] + }, + "rainbowboard": { + "icon": "", + "images": [] + }, + "raindrop": { + "icon": "", + "images": [] + }, + "raindrop-io": { + "icon": "", + "images": [] + }, + "rainmeter": { + "icon": "https://community.chocolatey.org/content/packageimages/rainmeter.4.3.0.3321.png", + "images": [] + }, + "rakudo-moar": { + "icon": "", + "images": [] + }, + "rakudo-star": { + "icon": "", + "images": [] + }, + "rakudostar": { + "icon": "https://community.chocolatey.org/content/packageimages/rakudostar.2022.07.png", + "images": [] + }, + "rambox": { + "icon": "", + "images": [] + }, + "rambox-community": { + "icon": "", + "images": [] + }, + "ramexpert": { + "icon": "", + "images": [] + }, + "rammap": { + "icon": "https://community.chocolatey.org/content/packageimages/rammap.1.61.png", + "images": [] + }, + "ramme": { + "icon": "https://community.chocolatey.org/content/packageimages/ramme.3.2.5.png", + "images": [] + }, + "rancher-cli": { + "icon": "", + "images": [] + }, + "rancher-compose": { + "icon": "", + "images": [] + }, + "rancher-desktop": { + "icon": "https://community.chocolatey.org/content/packageimages/rancher-desktop.1.7.0.png", + "images": [] + }, + "rancherdesktop": { + "icon": "", + "images": [] + }, + "rand-beer": { + "icon": "https://community.chocolatey.org/content/packageimages/rand-beer.0.0.2.png", + "images": [] + }, + "random-number-generator": { + "icon": "https://community.chocolatey.org/content/packageimages/random-number-generator.3.0.0.png", + "images": [] + }, + "randomnumbergenerator": { + "icon": "", + "images": [] + }, + "randpass": { + "icon": "", + "images": [] + }, + "ransomfree": { + "icon": "", + "images": [] + }, + "rapidcrc": { + "icon": "", + "images": [] + }, + "rapidcrc-unicode": { + "icon": "https://community.chocolatey.org/content/packageimages/rapidcrc-unicode.0.3.16.png", + "images": [] + }, + "rapidcrcunicode": { + "icon": "", + "images": [] + }, + "rapidee": { + "icon": "https://community.chocolatey.org/content/packageimages/RapidEE.9.2.937.png", + "images": [] + }, + "rapidenvironmenteditor": { + "icon": "", + "images": [] + }, + "rapidminer": { + "icon": "https://community.chocolatey.org/content/packageimages/rapidminer.10.1.png", + "images": [] + }, + "rapr": { + "icon": "https://community.chocolatey.org/content/packageimages/rapr.0.11.79.png", + "images": [] + }, + "rare": { + "icon": "", + "images": [] + }, + "raspberrypiimager": { + "icon": "https://i.postimg.cc/mknNsXFJ/raspberry-pi-imager.png", + "images": [ + "https://i.postimg.cc/DZwKB0Zm/rasp1.png", + "https://i.postimg.cc/269NJYbG/rasp2.png", + "https://i.postimg.cc/Zn9zzQ6S/rasp3.png", + "https://i.postimg.cc/QCRG8qqW/rasp4.png", + "https://i.postimg.cc/SQ5pfypN/rasp5.png" + ] + }, + "rath": { + "icon": "", + "images": [] + }, + "rathole": { + "icon": "", + "images": [] + }, + "ratiomaster": { + "icon": "", + "images": [] + }, + "raven-reader": { + "icon": "", + "images": [] + }, + "ravencore": { + "icon": "", + "images": [] + }, + "ravendb": { + "icon": "https://community.chocolatey.org/content/packageimages/RavenDB.5.4.101.png", + "images": [] + }, + "ravendb3": { + "icon": "", + "images": [] + }, + "ravensburgertiptoimanager": { + "icon": "https://community.chocolatey.org/content/packageimages/ravensburgertiptoimanager.3.0.8.png", + "images": [] + }, + "rawcap": { + "icon": "", + "images": [] + }, + "rawcooked": { + "icon": "", + "images": [] + }, + "rawcopy": { + "icon": "", + "images": [] + }, + "rawrite32": { + "icon": "", + "images": [] + }, + "rawtherapee": { + "icon": "https://i.postimg.cc/P5L5D1yp/image.png", + "images": [ + "https://i.postimg.cc/sggCGWPF/image.png", + "https://i.postimg.cc/Y0j37XNq/image.png", + "https://i.postimg.cc/tRPd3Vrc/image.png", + "https://i.postimg.cc/BnZxf7qW/image.png", + "https://i.postimg.cc/JhGZGyDP/image.png" + ] + }, + "rawtherapee-dev": { + "icon": "https://i.postimg.cc/P5L5D1yp/image.png", + "images": [ + "https://i.postimg.cc/5tDYjbCz/image.png", + "https://i.postimg.cc/Y0j37XNq/image.png", + "https://i.postimg.cc/tRPd3Vrc/image.png", + "https://i.postimg.cc/BnZxf7qW/image.png", + "https://i.postimg.cc/JhGZGyDP/image.png" + ] + }, + "rawwrite": { + "icon": "", + "images": [] + }, + "ray": { + "icon": "", + "images": [] + }, + "raycho": { + "icon": "", + "images": [] + }, + "raylib": { + "icon": "", + "images": [] + }, + "raylib-mingw": { + "icon": "", + "images": [] + }, + "rayman-controlpanel": { + "icon": "https://community.chocolatey.org/content/packageimages/rayman-controlpanel.10.3.1.png", + "images": [] + }, + "razer-synapse-2": { + "icon": "", + "images": [] + }, + "razer-synapse-3": { + "icon": "", + "images": [] + }, + "razorsql": { + "icon": "", + "images": [] + }, + "rbac-lookup": { + "icon": "", + "images": [] + }, + "rbatchfiles": { + "icon": "", + "images": [] + }, + "rbcmd": { + "icon": "", + "images": [] + }, + "rbiblia": { + "icon": "", + "images": [] + }, + "rbtray": { + "icon": "https://community.chocolatey.org/content/packageimages/rbtray.4.14.png", + "images": [] + }, + "rcc": { + "icon": "", + "images": [] + }, + "rcedit": { + "icon": "", + "images": [] + }, + "rclone": { + "icon": "https://cdn.icon-icons.com/icons2/2699/PNG/512/rclone_logo_icon_168876.png", + "images": [] + }, + "rclone-browser": { + "icon": "", + "images": [] + }, + "rclonebrowser": { + "icon": "", + "images": [] + }, + "rdcman": { + "icon": "https://community.chocolatey.org/content/packageimages/rdcman.2.92.1430.png", + "images": [] + }, + "rdiff-backup": { + "icon": "https://community.chocolatey.org/content/packageimages/rdiff-backup.2.0.5.png", + "images": [] + }, + "rdm": { + "icon": "https://community.chocolatey.org/content/packageimages/rdm.2022.3.33.0.png", + "images": [] + }, + "rdmagent": { + "icon": "", + "images": [] + }, + "rdmfree": { + "icon": "https://community.chocolatey.org/content/packageimages/rdmfree.2022.2.26.0.png", + "images": [] + }, + "rdpguard": { + "icon": "", + "images": [] + }, + "rdpv": { + "icon": "https://community.chocolatey.org/content/packageimages/rdpv.1.02.png", + "images": [] + }, + "react-explorer": { + "icon": "", + "images": [] + }, + "react-native-debugger": { + "icon": "", + "images": [] + }, + "reactnativedebugger": { + "icon": "", + "images": [] + }, + "reactos-apps": { + "icon": "https://community.chocolatey.org/content/packageimages/reactos-apps.0.4.15.png", + "images": [] + }, + "reactotron": { + "icon": "https://community.chocolatey.org/content/packageimages/reactotron.2.17.1.png", + "images": [] + }, + "reactotron-pre-release": { + "icon": "", + "images": [] + }, + "reactsnippetpack": { + "icon": "", + "images": [] + }, + "reactype": { + "icon": "", + "images": [] + }, + "reader": { + "icon": "", + "images": [] + }, + "readpaper": { + "icon": "", + "images": [] + }, + "readycloud": { + "icon": "https://community.chocolatey.org/content/packageimages/readycloud.1.17.1301.560.png", + "images": [] + }, + "readyshare-vault": { + "icon": "https://community.chocolatey.org/content/packageimages/readyshare-vault.1.0.50.500.png", + "images": [] + }, + "real": { + "icon": "", + "images": [] + }, + "real-netstat": { + "icon": "https://community.chocolatey.org/content/packageimages/real-netstat.3.1.png", + "images": [] + }, + "realcugan-ncnn-vulkan": { + "icon": "", + "images": [] + }, + "realesrgan-ncnn-vulkan": { + "icon": "", + "images": [] + }, + "realpopup": { + "icon": "https://community.chocolatey.org/content/packageimages/realpopup.11.1.png", + "images": [] + }, + "realsense-sdk2": { + "icon": "https://community.chocolatey.org/content/packageimages/realsense-sdk2.2.29.0.png", + "images": [] + }, + "realtek-hd-audio-driver": { + "icon": "https://i.postimg.cc/DzJZq4Hm/Realtek-icon.png", + "images": [ + "https://i.postimg.cc/021P4H3k/Realtek-1.png" + ] + }, + "realtemp": { + "icon": "https://community.chocolatey.org/content/packageimages/realtemp.3.7.0.png", + "images": [] + }, + "realterm": { + "icon": "https://community.chocolatey.org/content/packageimages/realterm.2.0.0.7000.png", + "images": [] + }, + "reaper": { + "icon": "https://i.postimg.cc/TY8SLvxj/icon.png", + "images": [ + "https://i.postimg.cc/L6zWjQ4c/reaper.png" + ] + }, + "reaper-sws-extension": { + "icon": "https://community.chocolatey.org/content/packageimages/reaper-sws-extension.2.12.1.3.png", + "images": [] + }, + "rebar3": { + "icon": "https://community.chocolatey.org/content/packageimages/rebar3.3.20.0.png", + "images": [] + }, + "rebootblocker": { + "icon": "", + "images": [] + }, + "rebus-snoop": { + "icon": "", + "images": [] + }, + "recaps": { + "icon": "", + "images": [] + }, + "recentfilesview": { + "icon": "https://community.chocolatey.org/content/packageimages/recentfilesview.1.33.png", + "images": [] + }, + "recentx": { + "icon": "", + "images": [] + }, + "recime-cli": { + "icon": "", + "images": [] + }, + "recmd": { + "icon": "", + "images": [] + }, + "recode-converter": { + "icon": "", + "images": [] + }, + "recoverit": { + "icon": "", + "images": [] + }, + "recoverit-cn": { + "icon": "", + "images": [] + }, + "recuva": { + "icon": "https://community.chocolatey.org/content/packageimages/Recuva.1.54.120.png", + "images": [] + }, + "recycle": { + "icon": "", + "images": [] + }, + "recycle-bin": { + "icon": "", + "images": [] + }, + "recyclenow": { + "icon": "https://community.chocolatey.org/content/packageimages/recyclenow.1.0.0.png", + "images": [] + }, + "red": { + "icon": "https://community.chocolatey.org/content/packageimages/red.0.6.4.png", + "images": [] + }, + "redasm": { + "icon": "", + "images": [] + }, + "reddit-wallpaper-changer": { + "icon": "https://community.chocolatey.org/content/packageimages/reddit-wallpaper-changer.1.0.13.png", + "images": [] + }, + "redeclipse": { + "icon": "https://community.chocolatey.org/content/packageimages/redeclipse.1.4.20141130.png", + "images": [] + }, + "redis": { + "icon": "", + "images": [] + }, + "redis-64": { + "icon": "", + "images": [] + }, + "redis-desktop-manager": { + "icon": "", + "images": [] + }, + "redis-gui": { + "icon": "", + "images": [] + }, + "redis-tui": { + "icon": "", + "images": [] + }, + "rednotebook": { + "icon": "", + "images": [] + }, + "redpanda-c++": { + "icon": "", + "images": [] + }, + "redpen": { + "icon": "", + "images": [] + }, + "redragon-m913": { + "icon": "", + "images": [] + }, + "redshift": { + "icon": "", + "images": [] + }, + "redshift-tray": { + "icon": "", + "images": [] + }, + "reduce-memory": { + "icon": "", + "images": [] + }, + "redwood": { + "icon": "https://community.chocolatey.org/content/packageimages/redwood.portable.1.10.png", + "images": [] + }, + "reeeplayer": { + "icon": "https://community.chocolatey.org/content/packageimages/reeeplayer.0.4.png", + "images": [] + }, + "reflect-free": { + "icon": "https://community.chocolatey.org/content/packageimages/reflect-free.8.0.7175.png", + "images": [] + }, + "reflector-2": { + "icon": "", + "images": [] + }, + "reflector-3": { + "icon": "", + "images": [] + }, + "reflector-4": { + "icon": "", + "images": [] + }, + "refreshenv": { + "icon": "", + "images": [] + }, + "regalyzer": { + "icon": "https://community.chocolatey.org/content/packageimages/RegAlyzer.1.6.2.161.png", + "images": [] + }, + "regard3d": { + "icon": "https://community.chocolatey.org/content/packageimages/regard3d.1.0.0.png", + "images": [] + }, + "regcleanpro": { + "icon": "", + "images": [] + }, + "regcool": { + "icon": "https://i.postimg.cc/6QX9bvvX/regcool-icon.png", + "images": [ + "https://i.postimg.cc/Vvd1093j/regcool-e1.png", + "https://i.postimg.cc/W3psTc8Y/regcool-e2.png", + "https://i.postimg.cc/d1Ww0NSs/regcool-e3.png", + "https://i.postimg.cc/KYDm68Pg/regcool-e4.png", + "https://i.postimg.cc/nrgx4jJN/regcool-e5.png", + "https://i.postimg.cc/dQxJPXyn/regcool-e6.png", + "https://i.postimg.cc/5NQbx35J/regcool-e7.png" + ] + }, + "regdelnull": { + "icon": "", + "images": [] + }, + "regdllview": { + "icon": "", + "images": [] + }, + "regeditor": { + "icon": "", + "images": [] + }, + "regexcoach": { + "icon": "https://community.chocolatey.org/content/packageimages/regexcoach.0.9.2.png", + "images": [] + }, + "regexp": { + "icon": "", + "images": [] + }, + "regexpixie": { + "icon": "", + "images": [] + }, + "regextester": { + "icon": "https://community.chocolatey.org/content/packageimages/regextester.3.2.0.0.png", + "images": [] + }, + "regfileexport": { + "icon": "", + "images": [] + }, + "reginald": { + "icon": "", + "images": [] + }, + "registry-backup": { + "icon": "https://community.chocolatey.org/content/packageimages/registry-backup.3.5.3.png", + "images": [] + }, + "registry-explorer": { + "icon": "", + "images": [] + }, + "registry-finder": { + "icon": "", + "images": [] + }, + "registry-key-jumper": { + "icon": "", + "images": [] + }, + "registrychangesview": { + "icon": "https://i.postimg.cc/cHC5Lvfg/image.png", + "images": [ + "https://i.postimg.cc/zvRtT4tf/image.png" + ] + }, + "registrymanager": { + "icon": "https://community.chocolatey.org/content/packageimages/registrymanager.8.02.png", + "images": [] + }, + "registryworkshop": { + "icon": "https://community.chocolatey.org/content/packageimages/registryworkshop.5.1.0.png", + "images": [] + }, + "regjump": { + "icon": "", + "images": [] + }, + "regolith": { + "icon": "", + "images": [] + }, + "regressi": { + "icon": "", + "images": [] + }, + "regripper": { + "icon": "", + "images": [] + }, + "regscanner": { + "icon": "https://community.chocolatey.org/content/packageimages/RegScanner.2.71.png", + "images": [] + }, + "regshot": { + "icon": "", + "images": [] + }, + "regula": { + "icon": "", + "images": [] + }, + "regulator": { + "icon": "https://community.chocolatey.org/content/packageimages/regulator.2.0.3.png", + "images": [] + }, + "rehash": { + "icon": "", + "images": [] + }, + "rehex": { + "icon": "", + "images": [] + }, + "reicon": { + "icon": "https://i.postimg.cc/PqnFnC2f/reicon.png", + "images": [ + "https://i.postimg.cc/BvSC429S/image.png", + "https://i.postimg.cc/PfgzNgnN/image.png", + "https://i.postimg.cc/CKrb0t4Y/image.png", + "https://i.postimg.cc/sfh5FTQH/image.png", + "https://i.postimg.cc/3wq0VGKQ/image.png" + ] + }, + "reko": { + "icon": "", + "images": [] + }, + "rekor-cli": { + "icon": "https://community.chocolatey.org/content/packageimages/rekor-cli.0.3.0.png", + "images": [] + }, + "reloaded-ii-tools": { + "icon": "https://community.chocolatey.org/content/packageimages/reloaded-ii-tools.1.1.2.png", + "images": [] + }, + "remarkablecompanionapp": { + "icon": "", + "images": [] + }, + "rember": { + "icon": "", + "images": [] + }, + "remindr": { + "icon": "", + "images": [] + }, + "remixide": { + "icon": "", + "images": [] + }, + "remnote": { + "icon": "", + "images": [] + }, + "remote-desktop-client": { + "icon": "https://community.chocolatey.org/content/packageimages/remote-desktop-client.1.2.3918.png", + "images": [] + }, + "remote-desktop-ip-monitor-and-blocker": { + "icon": "", + "images": [] + }, + "remote-syslog2": { + "icon": "https://community.chocolatey.org/content/packageimages/remote-syslog2.0.21.png", + "images": [] + }, + "remoteapp": { + "icon": "", + "images": [] + }, + "remoteapptool": { + "icon": "", + "images": [] + }, + "remotedesktopclient": { + "icon": "", + "images": [] + }, + "remotedesktopmanager": { + "icon": "https://i.postimg.cc/gjFS5psy/RDM.png", + "images": [] + }, + "remotedesktopplus": { + "icon": "", + "images": [] + }, + "remotehelp": { + "icon": "", + "images": [] + }, + "remoteit": { + "icon": "", + "images": [] + }, + "remotemouse": { + "icon": "", + "images": [] + }, + "remotetestkit": { + "icon": "", + "images": [] + }, + "remotix": { + "icon": "", + "images": [] + }, + "remove-empty-directories": { + "icon": "", + "images": [] + }, + "removeemptydirectories": { + "icon": "", + "images": [] + }, + "rename-cli": { + "icon": "", + "images": [] + }, + "renamemaster": { + "icon": "https://www.joejoesoft.com/update2-48-fix.png", + "images": [] + }, + "renamemytvseries": { + "icon": "", + "images": [] + }, + "renamemytvseries2": { + "icon": "https://community.chocolatey.org/content/packageimages/renamemytvseries2.2.0.10.png", + "images": [] + }, + "renamer": { + "icon": "https://community.chocolatey.org/content/packageimages/renamer.install.7.3.png", + "images": [] + }, + "renderdoc": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/9/93/RenderDoc_logo.svg/900px-RenderDoc_logo.svg.png?20210730051731", + "images": [] + }, + "renode": { + "icon": "", + "images": [] + }, + "renoise": { + "icon": "", + "images": [] + }, + "renpy": { + "icon": "", + "images": [] + }, + "reolink": { + "icon": "", + "images": [] + }, + "repairit": { + "icon": "", + "images": [] + }, + "repairit-cn": { + "icon": "", + "images": [] + }, + "replayweb-page": { + "icon": "", + "images": [] + }, + "reportbuilder": { + "icon": "", + "images": [] + }, + "reportservercommunity": { + "icon": "", + "images": [] + }, + "reportviewer2008": { + "icon": "", + "images": [] + }, + "reportviewer2008sp1kb971119": { + "icon": "", + "images": [] + }, + "reportviewer2010sp1": { + "icon": "", + "images": [] + }, + "reportviewer2010sp1kb2549864": { + "icon": "", + "images": [] + }, + "reportviewer2012": { + "icon": "", + "images": [] + }, + "repositorycleaner": { + "icon": "https://community.chocolatey.org/content/packageimages/repositorycleaner.1.1.0.png", + "images": [] + }, + "repoz": { + "icon": "", + "images": [] + }, + "reprofiler": { + "icon": "", + "images": [] + }, + "republicanywhere": { + "icon": "", + "images": [] + }, + "repulicanywhere": { + "icon": "", + "images": [] + }, + "reqrypt": { + "icon": "", + "images": [] + }, + "rescuetime": { + "icon": "", + "images": [] + }, + "resedit": { + "icon": "", + "images": [] + }, + "reshack": { + "icon": "https://community.chocolatey.org/content/packageimages/reshack.5.1.8.png", + "images": [] + }, + "reshade": { + "icon": "https://community.chocolatey.org/content/packageimages/reshade.5.7.0.png", + "images": [] + }, + "resharper": { + "icon": "https://resources.jetbrains.com/storage/products/resharper/img/meta/resharper_logo_300x300.png", + "images": [] + }, + "resharper-clt": { + "icon": "https://community.chocolatey.org/content/packageimages/resharper-clt.portable.2022.3.2.png", + "images": [] + }, + "resharper-earlyaccess": { + "icon": "https://resources.jetbrains.com/storage/products/resharper/img/meta/resharper_logo_300x300.png", + "images": [] + }, + "resharper-platform": { + "icon": "https://community.chocolatey.org/content/packageimages/resharper-platform.223.0.20230125.120904.png", + "images": [] + }, + "resharper-ultimate-all": { + "icon": "https://community.chocolatey.org/content/packageimages/resharper-ultimate-all.2022.3.2.png", + "images": [] + }, + "resharpercpp": { + "icon": "https://community.chocolatey.org/content/packageimages/ReSharperCpp.2022.3.2.png", + "images": [] + }, + "resharpersdk-7": { + "icon": "https://community.chocolatey.org/content/packageimages/ReSharperSDK-7.7.1.96.png", + "images": [] + }, + "resharpersdk-7-app": { + "icon": "https://community.chocolatey.org/content/packageimages/ReSharperSDK-7.app.7.1.96.png", + "images": [] + }, + "resharpersdk-7-tool": { + "icon": "https://community.chocolatey.org/content/packageimages/ReSharperSDK-7.tool.7.1.96.png", + "images": [] + }, + "resharpersdk-app": { + "icon": "https://community.chocolatey.org/content/packageimages/ReSharperSDK.app.8.0.1086.png", + "images": [] + }, + "resharpersdk-tool": { + "icon": "https://community.chocolatey.org/content/packageimages/ReSharperSDK.tool.8.0.1086.png", + "images": [] + }, + "residualvm": { + "icon": "", + "images": [] + }, + "resilio-sync-home": { + "icon": "", + "images": [] + }, + "resiliosync": { + "icon": "", + "images": [] + }, + "resizer": { + "icon": "", + "images": [] + }, + "resolvealias": { + "icon": "", + "images": [] + }, + "resonic": { + "icon": "https://community.chocolatey.org/content/packageimages/resonic.0.9.1.1690.png", + "images": [] + }, + "resophnotes": { + "icon": "https://community.chocolatey.org/content/packageimages/ResophNotes.1.7.0.png", + "images": [] + }, + "resource-hacker": { + "icon": "", + "images": [] + }, + "resource-tuner": { + "icon": "", + "images": [] + }, + "resource-tuner-console": { + "icon": "", + "images": [] + }, + "resourcehacker": { + "icon": "https://community.chocolatey.org/content/packageimages/resourcehacker.portable.5.1.8.png", + "images": [ + "https://i.postimg.cc/2y55NVxC/image.png", + "https://i.postimg.cc/mDrqq449/image.png", + "https://i.postimg.cc/23pTGRTn/image.png", + "https://i.postimg.cc/T2QyNXcR/image.png", + "https://i.postimg.cc/xCnCgsJJ/image.png", + "https://i.postimg.cc/FsdvcXYd/image.png" + ] + }, + "resourcetuner": { + "icon": "https://i.postimg.cc/nh3g2tjg/restuner.png", + "images": [ + "https://i.postimg.cc/B66zk7Db/image.png", + "https://i.postimg.cc/Jn2FL3cq/image.png", + "https://i.postimg.cc/XXMDZVPB/image.png", + "https://i.postimg.cc/mZ0b37fC/image.png", + "https://i.postimg.cc/5NLfsjbG/image.png", + "https://i.postimg.cc/Z5L4hg9x/image.png" + ] + }, + "resourcetunerconsole": { + "icon": "https://i.postimg.cc/rpvhZy8n/rtc.png", + "images": [ + "https://i.postimg.cc/N0fYG4mq/image.png" + ] + }, + "responsively": { + "icon": "", + "images": [] + }, + "responsivelyapp": { + "icon": "", + "images": [] + }, + "restart-explorer": { + "icon": "", + "images": [] + }, + "restart-to-uefi": { + "icon": "https://community.chocolatey.org/content/packageimages/restart-to-uefi.1.0.5.png", + "images": [] + }, + "restic": { + "icon": "https://github.com/restic/restic/blob/master/doc/logo/logo.png", + "images": [] + }, + "restish": { + "icon": "", + "images": [] + }, + "restler": { + "icon": "https://community.chocolatey.org/content/packageimages/restler.0.1.0.png", + "images": [] + }, + "restreamchat": { + "icon": "", + "images": [] + }, + "resvg": { + "icon": "", + "images": [] + }, + "retdec": { + "icon": "", + "images": [] + }, + "rethinkdb": { + "icon": "", + "images": [] + }, + "retoolkit": { + "icon": "", + "images": [] + }, + "retroarch": { + "icon": "https://i.postimg.cc/G2q7QrKh/retroarch-300.png", + "images": [] + }, + "retroshare": { + "icon": "https://community.chocolatey.org/content/packageimages/retroshare.0.6.6.png", + "images": [] + }, + "reveye-chrome": { + "icon": "https://community.chocolatey.org/content/packageimages/reveye-chrome.1.4.4.png", + "images": [] + }, + "reviewdog": { + "icon": "", + "images": [] + }, + "revo-scan": { + "icon": "", + "images": [] + }, + "revo-studio": { + "icon": "", + "images": [] + }, + "revo-uninstaller": { + "icon": "https://i.postimg.cc/PqFKpK5s/Revouninstallerpro-512.png", + "images": [] + }, + "revoltdesktop": { + "icon": "", + "images": [] + }, + "revosleep": { + "icon": "https://community.chocolatey.org/content/packageimages/revosleep.0.4.0.png", + "images": [] + }, + "revouninstaller": { + "icon": "https://i.postimg.cc/PqFKpK5s/Revouninstallerpro-512.png", + "images": [] + }, + "revouninstallerpro": { + "icon": "https://i.postimg.cc/PqFKpK5s/Revouninstallerpro-512.png", + "images": [] + }, + "revrobotics-hardwareclient": { + "icon": "https://community.chocolatey.org/content/packageimages/revrobotics-hardwareclient.1.4.3.png", + "images": [] + }, + "revu-21": { + "icon": "", + "images": [] + }, + "rfortango": { + "icon": "", + "images": [] + }, + "rga": { + "icon": "", + "images": [] + }, + "rgbds": { + "icon": "https://community.chocolatey.org/content/packageimages/rgbds.0.5.2.png", + "images": [] + }, + "rgss-rtpstandard": { + "icon": "", + "images": [] + }, + "rgsupervision": { + "icon": "", + "images": [] + }, + "rhash": { + "icon": "https://community.chocolatey.org/content/packageimages/rhash.1.3.8.png", + "images": [] + }, + "richcopy": { + "icon": "", + "images": [] + }, + "richmond": { + "icon": "", + "images": [] + }, + "rickrack": { + "icon": "", + "images": [] + }, + "ricochet": { + "icon": "", + "images": [] + }, + "rider": { + "icon": "https://resources.jetbrains.com/storage/products/rider/img/meta/rider_logo_300x300.png", + "images": [] + }, + "rider-eap": { + "icon": "https://resources.jetbrains.com/storage/products/rider/img/meta/rider_logo_300x300.png", + "images": [] + }, + "ridibooks": { + "icon": "", + "images": [] + }, + "ridnacs": { + "icon": "", + "images": [] + }, + "riecoin": { + "icon": "https://community.chocolatey.org/content/packageimages/riecoin.0.10.2.png", + "images": [] + }, + "rife-ncnn-vulkan": { + "icon": "", + "images": [] + }, + "rig": { + "icon": "", + "images": [] + }, + "rightnote": { + "icon": "https://i.postimg.cc/mZj8kSNm/Right-Note.png", + "images": [ + "https://i.postimg.cc/Jhs9c2K7/image.png", + "https://i.postimg.cc/52sVmvVg/image.png", + "https://i.postimg.cc/QdyztqD2/image.png", + "https://i.postimg.cc/9MGgL592/image.png", + "https://i.postimg.cc/4N42Q0xC/image.png", + "https://i.postimg.cc/g0hg0FNh/image.png" + ] + }, + "rigsofrods": { + "icon": "", + "images": [] + }, + "rim": { + "icon": "", + "images": [] + }, + "rimhill": { + "icon": "", + "images": [] + }, + "ring": { + "icon": "https://community.chocolatey.org/content/packageimages/ring.2018.04.14.png", + "images": [] + }, + "ringcentral": { + "icon": "https://www.ringcentral.com/content/dam/rc-www/en_us/images/favicon/ringcentral_2.0_icon_favicon.ico", + "images": [] + }, + "rink": { + "icon": "", + "images": [] + }, + "rio": { + "icon": "", + "images": [] + }, + "riot": { + "icon": "https://community.chocolatey.org/content/packageimages/riot.1.0.1.png", + "images": [] + }, + "riot-web": { + "icon": "https://community.chocolatey.org/content/packageimages/riot-web.1.5.15.20200728.png", + "images": [] + }, + "ripcord": { + "icon": "https://community.chocolatey.org/content/packageimages/ripcord.0.4.29.png", + "images": [] + }, + "ripgrep": { + "icon": "", + "images": [] + }, + "ripgrep-gnu": { + "icon": "", + "images": [] + }, + "ripgrep-msvc": { + "icon": "", + "images": [] + }, + "ripme": { + "icon": "", + "images": [] + }, + "ripple": { + "icon": "", + "images": [] + }, + "ripshout": { + "icon": "", + "images": [] + }, + "risoheditor": { + "icon": "", + "images": [] + }, + "rivet": { + "icon": "", + "images": [] + }, + "rizin": { + "icon": "", + "images": [] + }, + "rke": { + "icon": "", + "images": [] + }, + "rktools-2003": { + "icon": "https://community.chocolatey.org/content/packageimages/rktools.2003.5.2.121102.png", + "images": [] + }, + "rktools2k3": { + "icon": "", + "images": [] + }, + "rkward": { + "icon": "", + "images": [] + }, + "rlogin": { + "icon": "https://community.chocolatey.org/content/packageimages/rlogin.2.27.7.png", + "images": [] + }, + "rm-glob": { + "icon": "", + "images": [] + }, + "rmprepusb": { + "icon": "", + "images": [] + }, + "rmstale": { + "icon": "", + "images": [] + }, + "rnp": { + "icon": "", + "images": [] + }, + "rnp-cli": { + "icon": "https://community.chocolatey.org/content/packageimages/rnp-cli.0.1.146.png", + "images": [] + }, + "rnr": { + "icon": "", + "images": [] + }, + "roadgeek-font": { + "icon": "https://community.chocolatey.org/content/packageimages/roadgeek.font.2005.2.png", + "images": [] + }, + "roamresearch": { + "icon": "", + "images": [] + }, + "roblox": { + "icon": "https://i.ibb.co/ddqFLQ9/roblox.png", + "images": [ + "https://i.postimg.cc/Dy4vWSLD/image.png", + "https://i.postimg.cc/mrLWSk1T/image.png" + ] + }, + "robo3t": { + "icon": "https://i.imgur.com/XSYqe6j.png", + "images": [] + }, + "robocode": { + "icon": "", + "images": [] + }, + "robocopy-gui": { + "icon": "", + "images": [] + }, + "roboform": { + "icon": "https://community.chocolatey.org/content/packageimages/RoboForm.9.2.1.png", + "images": [ + "https://i.postimg.cc/T2ks4fx6/image.png" + ] + }, + "robomirror": { + "icon": "https://community.chocolatey.org/content/packageimages/robomirror.2.0.20161009.png", + "images": [] + }, + "robomongo": { + "icon": "", + "images": [] + }, + "robopro": { + "icon": "", + "images": [] + }, + "roboto-font": { + "icon": "", + "images": [] + }, + "robotofonts": { + "icon": "", + "images": [] + }, + "roccatswarm": { + "icon": "https://community.chocolatey.org/content/packageimages/roccatswarm.1.9414.png", + "images": [] + }, + "rockbox": { + "icon": "https://community.chocolatey.org/content/packageimages/rockbox.1.4.0.png", + "images": [] + }, + "rocketchat": { + "icon": "", + "images": [] + }, + "rocketchat-client": { + "icon": "", + "images": [] + }, + "rocketdock": { + "icon": "", + "images": [] + }, + "rockpaperscissorscli": { + "icon": "", + "images": [] + }, + "rocksndiamonds": { + "icon": "", + "images": [] + }, + "rockstar-launcher": { + "icon": "https://i.ibb.co/PZ4CGyXW/rockstar-games-1536-433540335.png", + "images": [] + }, + "rocolatey": { + "icon": "https://community.chocolatey.org/content/packageimages/rocolatey.0.6.1.png", + "images": [] + }, + "rocrail": { + "icon": "https://community.chocolatey.org/content/packageimages/rocrail.1.696.png", + "images": [] + }, + "rode-central": { + "icon": "https://help.rode.com/hc/article_attachments/12943376530063", + "images": [] + }, + "rokkr": { + "icon": "", + "images": [] + }, + "rollbackrx": { + "icon": "", + "images": [] + }, + "romcenter": { + "icon": "", + "images": [] + }, + "rommanager": { + "icon": "https://i.postimg.cc/qRCTHxrb/steamrommanager_256.png", + "images": [] + }, + "romp": { + "icon": "", + "images": [] + }, + "roo": { + "icon": "", + "images": [] + }, + "roomarranger": { + "icon": "https://community.chocolatey.org/content/packageimages/roomarranger.9.7.2.png", + "images": [] + }, + "roomeqwizard": { + "icon": "https://community.chocolatey.org/content/packageimages/roomeqwizard.5.18.png", + "images": [] + }, + "roon": { + "icon": "", + "images": [] + }, + "roonbridge": { + "icon": "", + "images": [] + }, + "roonserver": { + "icon": "", + "images": [] + }, + "roost-desktop-notifier-for-nest": { + "icon": "https://community.chocolatey.org/content/packageimages/roost-desktop-notifier-for-nest.0.9.8.212.png", + "images": [] + }, + "rootbeer": { + "icon": "", + "images": [] + }, + "ropen": { + "icon": "", + "images": [] + }, + "ropresence": { + "icon": "", + "images": [] + }, + "rosaimagewriter": { + "icon": "https://community.chocolatey.org/content/packageimages/rosaimagewriter.2.6.2.png", + "images": [] + }, + "rosi": { + "icon": "", + "images": [] + }, + "roslynpad": { + "icon": "", + "images": [] + }, + "roswell": { + "icon": "", + "images": [] + }, + "rotpdf": { + "icon": "https://community.chocolatey.org/content/packageimages/rotpdf.0.80.png", + "images": [] + }, + "roughgrep": { + "icon": "", + "images": [] + }, + "roundedcorners": { + "icon": "", + "images": [] + }, + "roundedtb": { + "icon": "", + "images": [] + }, + "roundhouse": { + "icon": "https://community.chocolatey.org/content/packageimages/roundhouse.1.3.1.png", + "images": [] + }, + "routerpassview": { + "icon": "https://community.chocolatey.org/content/packageimages/routerpassview.1.81.png", + "images": [] + }, + "royal": { + "icon": "", + "images": [] + }, + "royalserver": { + "icon": "https://community.chocolatey.org/content/packageimages/royalserver.4.01.60216.0.png", + "images": [] + }, + "royalts": { + "icon": "", + "images": [] + }, + "royalts-v5": { + "icon": "https://community.chocolatey.org/content/packageimages/royalts-v5.5.04.60415.0.png", + "images": [] + }, + "royalts-v6": { + "icon": "https://community.chocolatey.org/content/packageimages/royalts-v6.6.01.60209.png", + "images": [] + }, + "rpc": { + "icon": "https://community.chocolatey.org/content/packageimages/rpc.6.1.png", + "images": [] + }, + "rpcs3": { + "icon": "https://i.ibb.co/0RZzzr7y/8070735.png", + "images": [ + "https://i.ibb.co/wF17cTdm/image.png" + ] + }, + "rpgmakermv-free-trial": { + "icon": "", + "images": [] + }, + "rpgtkoolvx-rtp": { + "icon": "https://community.chocolatey.org/content/packageimages/rpgtkoolvx-rtp.202.0.png", + "images": [] + }, + "rpgtkoolvxace-rtp": { + "icon": "https://community.chocolatey.org/content/packageimages/rpgtkoolvxace-rtp.100.0.png", + "images": [] + }, + "rpi-imager": { + "icon": "https://community.chocolatey.org/content/packageimages/rpi-imager.1.7.3.png", + "images": [] + }, + "rs-deploy-ceta": { + "icon": "", + "images": [] + }, + "rs-deploy-raj": { + "icon": "", + "images": [] + }, + "rs-deploy-web": { + "icon": "", + "images": [] + }, + "rs-ssms-extension": { + "icon": "", + "images": [] + }, + "rs-status": { + "icon": "", + "images": [] + }, + "rsat": { + "icon": "https://community.chocolatey.org/content/packageimages/RSAT.2.1809.0.20210815.png", + "images": [] + }, + "rsat-featurepack": { + "icon": "", + "images": [] + }, + "rsc": { + "icon": "https://community.chocolatey.org/content/packageimages/rsc.9.0.0.png", + "images": [] + }, + "rsilauncher": { + "icon": "https://i.imgur.com/AoIT18N.png", + "images": [ + "https://i.imgur.com/7P1Z9pQ.png" + ] + }, + "rss-builder": { + "icon": "https://community.chocolatey.org/content/packageimages/rss-builder.2.1.8.png", + "images": [] + }, + "rssguard": { + "icon": "https://community.chocolatey.org/content/packageimages/rssguard.4.3.2.png", + "images": [] + }, + "rssowlnix": { + "icon": "https://community.chocolatey.org/content/packageimages/rssowlnix.2.9.0.png", + "images": [] + }, + "rstray": { + "icon": "https://community.chocolatey.org/content/packageimages/rstray.2.2.3.png", + "images": [] + }, + "rstudio": { + "icon": "", + "images": [] + }, + "rstudio-opensource": { + "icon": "https://www.rstudio.com/wp-content/uploads/2018/10/RStudio-Logo-Flat.png", + "images": [] + }, + "rstudio-professional": { + "icon": "https://www.rstudio.com/wp-content/uploads/2018/10/RStudio-Logo-Flat.png", + "images": [] + }, + "rsync": { + "icon": "https://community.chocolatey.org/content/packageimages/rsync.6.2.8.png", + "images": [] + }, + "rtl-utility": { + "icon": "https://community.chocolatey.org/content/packageimages/rtl-utility.1.0.6.png", + "images": [] + }, + "rtlsdr-scanner": { + "icon": "https://community.chocolatey.org/content/packageimages/rtlsdr-scanner.1.3.2.png", + "images": [] + }, + "rtlutility": { + "icon": "", + "images": [] + }, + "rtmpdump": { + "icon": "", + "images": [] + }, + "rtmpdumphelper": { + "icon": "https://community.chocolatey.org/content/packageimages/rtmpdumphelper.1.22.png", + "images": [] + }, + "rtools": { + "icon": "https://www.r-project.org/logo/Rlogo.png", + "images": [] + }, + "rtss": { + "icon": "https://i.ibb.co/vMjBYpp/image.png", + "images": [ + "https://i.ibb.co/bMTYq6bG/2024-02-07-19-19-30-guru3d.png" + ] + }, + "rtxvoice": { + "icon": "", + "images": [] + }, + "ru": { + "icon": "", + "images": [] + }, + "rubberduck": { + "icon": "https://community.chocolatey.org/content/packageimages/rubberduck.2.5.1.5621.png", + "images": [] + }, + "rubick": { + "icon": "", + "images": [] + }, + "ruby": { + "icon": "", + "images": [] + }, + "ruby-2-6": { + "icon": "", + "images": [] + }, + "ruby-2-7": { + "icon": "", + "images": [] + }, + "ruby-3-0": { + "icon": "", + "images": [] + }, + "ruby-3-1": { + "icon": "", + "images": [] + }, + "ruby-devkit-ruby193": { + "icon": "", + "images": [] + }, + "ruby1-9": { + "icon": "https://community.chocolatey.org/content/packageimages/ruby1.9.1.9.3.54500.png", + "images": [] + }, + "rubymine": { + "icon": "https://resources.jetbrains.com/storage/products/rubymine/img/meta/rubymine_logo_300x300.png", + "images": [] + }, + "rubymine-earlyaccess": { + "icon": "https://resources.jetbrains.com/storage/products/rubymine/img/meta/rubymine_logo_300x300.png", + "images": [] + }, + "ruff": { + "icon": "", + "images": [] + }, + "rufus": { + "icon": "https://i.postimg.cc/VsS0dxJn/Rufus.png", + "images": [ + "https://i.postimg.cc/02D6C7dN/Rufus1.png" + ] + }, + "run-in-genie": { + "icon": "", + "images": [] + }, + "run00-teamcitychocolatey": { + "icon": "https://community.chocolatey.org/content/packageimages/Run00.TeamCityChocolatey.0.0.0.12.png", + "images": [] + }, + "run00-teamcityversioning": { + "icon": "https://community.chocolatey.org/content/packageimages/Run00.TeamCityVersioning.0.0.0.4.png", + "images": [] + }, + "runasdate": { + "icon": "", + "images": [] + }, + "runassystem": { + "icon": "https://community.chocolatey.org/content/packageimages/runassystem.1.1.png", + "images": [] + }, + "runasti": { + "icon": "", + "images": [] + }, + "runastool": { + "icon": "", + "images": [] + }, + "runat": { + "icon": "", + "images": [] + }, + "runcat": { + "icon": "", + "images": [] + }, + "rundeck": { + "icon": "https://community.chocolatey.org/content/packageimages/rundeck.4.2.0.png", + "images": [] + }, + "runebook": { + "icon": "", + "images": [] + }, + "runelite": { + "icon": "https://community.chocolatey.org/content/packageimages/runelite.2.6.2.png", + "images": [] + }, + "runinbash": { + "icon": "https://community.chocolatey.org/content/packageimages/runinbash.0.1.1.png", + "images": [] + }, + "runjs": { + "icon": "", + "images": [] + }, + "runlet": { + "icon": "https://community.chocolatey.org/content/packageimages/runlet.1.0.8.png", + "images": [] + }, + "runner": { + "icon": "", + "images": [] + }, + "ruqola": { + "icon": "", + "images": [] + }, + "russian-grammatical-dictionary": { + "icon": "", + "images": [] + }, + "rust": { + "icon": "https://www.rust-lang.org/logos/rust-logo-512x512.png", + "images": [] + }, + "rust-analyzer": { + "icon": "https://community.chocolatey.org/content/packageimages/rust-analyzer.2023.02.06.png", + "images": [] + }, + "rust-gnu": { + "icon": "https://www.rust-lang.org/logos/rust-logo-512x512.png", + "images": [] + }, + "rust-ms": { + "icon": "https://www.rust-lang.org/logos/rust-logo-512x512.png", + "images": [] + }, + "rust-msvc": { + "icon": "https://www.rust-lang.org/logos/rust-logo-512x512.png", + "images": [] + }, + "rustdesk": { + "icon": "https://raw.githubusercontent.com/rustdesk/rustdesk/master/res/icon.png", + "images": [] + }, + "rustup": { + "icon": "https://www.rust-lang.org/logos/rust-logo-512x512.png", + "images": [] + }, + "rustup-gnu": { + "icon": "https://www.rust-lang.org/logos/rust-logo-512x512.png", + "images": [] + }, + "rustup-msvc": { + "icon": "https://www.rust-lang.org/logos/rust-logo-512x512.png", + "images": [] + }, + "rutoken-driver-repair-tool": { + "icon": "", + "images": [] + }, + "rutoken-drivers-removal-tool": { + "icon": "", + "images": [] + }, + "rutoken-egais-drivers": { + "icon": "", + "images": [] + }, + "rutoken-magistra-drivers": { + "icon": "", + "images": [] + }, + "rutoken-plugin": { + "icon": "", + "images": [] + }, + "rutoken-web-plugin": { + "icon": "", + "images": [] + }, + "rutoken-web-tool": { + "icon": "", + "images": [] + }, + "rutracker-proxy": { + "icon": "https://community.chocolatey.org/content/packageimages/rutracker-proxy.0.2.3.png", + "images": [] + }, + "rvtools": { + "icon": "https://community.chocolatey.org/content/packageimages/rvtools.4.4.1.png", + "images": [] + }, + "rweverything": { + "icon": "https://community.chocolatey.org/content/packageimages/rweverything.install.1.7.0.20220602.png", + "images": [] + }, + "rxrepl": { + "icon": "", + "images": [] + }, + "ryujinx": { + "icon": "https://community.chocolatey.org/content/packageimages/ryujinx.1.1.645.png", + "images": [] + }, + "ryujinx-canary": { + "icon": "https://raw.githubusercontent.com/Ryubing/Assets/main/RyujinxApp_1024.png", + "images": [ + "https://i.ibb.co/Pv7N8rky/shell.png" + ] + }, + "ryzen-controller": { + "icon": "", + "images": [] + }, + "ryzenadj": { + "icon": "", + "images": [] + }, + "ryzencontroller": { + "icon": "", + "images": [] + }, + "s": { + "icon": "", + "images": [] + }, + "s1controller": { + "icon": "", + "images": [] + }, + "s2": { + "icon": "", + "images": [] + }, + "s3deploy": { + "icon": "", + "images": [] + }, + "sabaki": { + "icon": "", + "images": [] + }, + "saber": { + "icon": "", + "images": [] + }, + "sabnzbd": { + "icon": "https://community.chocolatey.org/content/packageimages/SABnzbd.3.7.2.png", + "images": [] + }, + "sacad": { + "icon": "", + "images": [] + }, + "sackerel": { + "icon": "https://community.chocolatey.org/content/packageimages/sackerel.0.0.3.png", + "images": [] + }, + "sad": { + "icon": "", + "images": [] + }, + "safaricacheview": { + "icon": "https://community.chocolatey.org/content/packageimages/safaricacheview.1.11.png", + "images": [] + }, + "safarihistoryview": { + "icon": "https://community.chocolatey.org/content/packageimages/safarihistoryview.1.01.png", + "images": [] + }, + "safebrowser": { + "icon": "", + "images": [] + }, + "safeexambrowser": { + "icon": "https://i.postimg.cc/Pq0yjtmD/Safe-icon.png", + "images": [ + "https://i.postimg.cc/rsk9DQZF/SEB-Preferences-10-Security.png", + "https://i.postimg.cc/Y0zzYYTN/SEB-Preferences-04-Browser.png" + ] + }, + "safemonk": { + "icon": "", + "images": [] + }, + "safenet-authentication-client": { + "icon": "https://community.chocolatey.org/content/packageimages/safenet-authentication-client.10.8.png", + "images": [] + }, + "sagagis": { + "icon": "", + "images": [] + }, + "sagemath": { + "icon": "", + "images": [] + }, + "sagepassword": { + "icon": "https://i.postimg.cc/pdBnCsd7/asapr.png", + "images": [ + "https://i.postimg.cc/hv2NpW6h/image.png" + ] + }, + "sagethumbs": { + "icon": "https://community.chocolatey.org/content/packageimages/sagethumbs.2.0.0.23.png", + "images": [] + }, + "sakuraeditor": { + "icon": "https://community.chocolatey.org/content/packageimages/SakuraEditor.2.4.1.png", + "images": [] + }, + "salad": { + "icon": "", + "images": [] + }, + "salamander": { + "icon": "https://i.imgur.com/WvxLM42.png", + "images": [ + "https://www.altap.cz/images/teaser.1562049971.png" + ] + }, + "salome": { + "icon": "", + "images": [] + }, + "salt-minion": { + "icon": "", + "images": [] + }, + "saltminion": { + "icon": "https://community.chocolatey.org/content/packageimages/saltminion.3005.1.1.png", + "images": [] + }, + "sam-cli": { + "icon": "https://i.imgur.com/JTHKvy1.png", + "images": [ + "https://s33046.pcdn.co/wp-content/uploads/2020/08/aws-sam-workflow-e1597653903262.png", + "https://d2908q01vomqb2.cloudfront.net/1b6453892473a467d07372d45eb05abc2031647a/2020/12/16/poster-1024x629.png" + ] + }, + "sameboy": { + "icon": "", + "images": [] + }, + "saml2aws": { + "icon": "", + "images": [] + }, + "sample": { + "icon": "", + "images": [] + }, + "sampler": { + "icon": "", + "images": [] + }, + "samsung-magician": { + "icon": "https://community.chocolatey.org/content/packageimages/samsung-magician.7.2.1.980.png", + "images": [ + "https://images.samsung.com/is/image/samsung/assets/de/memory-storage/magician-software/Magician-8.0_Online_feature_02_Drive_information_pc_health-check.jpg?$FB_TYPE_A_PNG$", + "https://images.samsung.com/is/image/samsung/assets/de/memory-storage/magician-software/Magician-8.0_Online_feature_03_Drive_management_pc_dark.jpg?$FB_TYPE_A_PNG$", + "https://images.samsung.com/is/image/samsung/assets/de/memory-storage/magician-software/Magician-8.0_Online_feature_05_information_pc.jpg?$FB_TYPE_A_PNG$" + ] + }, + "samsung-nvme-driver": { + "icon": "https://community.chocolatey.org/content/packageimages/samsung-nvme-driver.3.3.png", + "images": [] + }, + "sandboxie": { + "icon": "https://community.chocolatey.org/content/packageimages/sandboxie.install.5.62.2.png", + "images": [] + }, + "sandboxie-plus": { + "icon": "https://community.chocolatey.org/content/packageimages/sandboxie-plus.install.1.14.9.png", + "images": [] + }, + "sandman": { + "icon": "", + "images": [] + }, + "sanerpersonal": { + "icon": "", + "images": [] + }, + "sanetwain": { + "icon": "", + "images": [] + }, + "sanitycheck": { + "icon": "", + "images": [] + }, + "saoutils-2": { + "icon": "", + "images": [] + }, + "saoutils-exp": { + "icon": "", + "images": [] + }, + "sapiclient": { + "icon": "", + "images": [] + }, + "sapling": { + "icon": "", + "images": [] + }, + "sapmachine": { + "icon": "", + "images": [] + }, + "sapmachine11": { + "icon": "", + "images": [] + }, + "sapmachine11jre": { + "icon": "", + "images": [] + }, + "sapmachine13": { + "icon": "", + "images": [] + }, + "sapmachine17": { + "icon": "", + "images": [] + }, + "saram-tools": { + "icon": "https://community.chocolatey.org/content/packageimages/saram.tools.0.2.png", + "images": [] + }, + "sass": { + "icon": "https://community.chocolatey.org/content/packageimages/sass.1.58.2.png", + "images": [] + }, + "sass-migrator": { + "icon": "https://community.chocolatey.org/content/packageimages/sass-migrator.1.0.1.png", + "images": [] + }, + "sastarterkitvs2012": { + "icon": "", + "images": [] + }, + "saucedacity": { + "icon": "", + "images": [] + }, + "sauerbraten": { + "icon": "https://community.chocolatey.org/content/packageimages/sauerbraten.2013.02.03.20161112.png", + "images": [] + }, + "save-to-google-drive-chrome": { + "icon": "https://community.chocolatey.org/content/packageimages/save-to-google-drive-chrome.2.1.1.png", + "images": [] + }, + "save-to-pocket-chrome": { + "icon": "", + "images": [] + }, + "save-to-tonido-chrome": { + "icon": "", + "images": [] + }, + "saxonhe": { + "icon": "https://community.chocolatey.org/content/packageimages/SaxonHE.9.9.1.7.png", + "images": [] + }, + "say": { + "icon": "", + "images": [] + }, + "sayit": { + "icon": "", + "images": [] + }, + "sbcl": { + "icon": "https://community.chocolatey.org/content/packageimages/sbcl.2.3.1.png", + "images": [] + }, + "sbis-plugin": { + "icon": "", + "images": [] + }, + "sbom-tool": { + "icon": "", + "images": [] + }, + "sbt": { + "icon": "", + "images": [] + }, + "sbz-switcher": { + "icon": "", + "images": [] + }, + "sc1": { + "icon": "", + "images": [] + }, + "sc3plugins": { + "icon": "https://community.chocolatey.org/content/packageimages/sc3plugins.3.11.1.png", + "images": [] + }, + "scala": { + "icon": "", + "images": [] + }, + "scala-2": { + "icon": "", + "images": [] + }, + "scala-cli": { + "icon": "https://community.chocolatey.org/content/packageimages/scala-cli.0.2.0.png", + "images": [] + }, + "scalaide": { + "icon": "https://community.chocolatey.org/content/packageimages/scalaide.4.0.0.0.png", + "images": [] + }, + "scale-serial-reader": { + "icon": "", + "images": [] + }, + "scaleway-cli": { + "icon": "https://community.chocolatey.org/content/packageimages/scaleway-cli.2.11.1.png", + "images": [] + }, + "scallion": { + "icon": "", + "images": [] + }, + "scanner": { + "icon": "", + "images": [] + }, + "scanscan": { + "icon": "", + "images": [] + }, + "scantailor-advanced": { + "icon": "https://community.chocolatey.org/content/packageimages/scantailor-advanced.2019.8.16.png", + "images": [] + }, + "scap-compliance-checker": { + "icon": "", + "images": [] + }, + "scarm": { + "icon": "https://community.chocolatey.org/content/packageimages/scarm.1.9.2.png", + "images": [] + }, + "scavenger": { + "icon": "", + "images": [] + }, + "scc": { + "icon": "https://community.chocolatey.org/content/packageimages/scc.3.1.0.20221202.png", + "images": [] + }, + "sccache": { + "icon": "", + "images": [] + }, + "sccmtoolkit": { + "icon": "", + "images": [] + }, + "scene-builder": { + "icon": "", + "images": [] + }, + "scenebuilder": { + "icon": "", + "images": [] + }, + "scenebuilder-18": { + "icon": "", + "images": [] + }, + "scenebuilder8": { + "icon": "https://community.chocolatey.org/content/packageimages/scenebuilder8.8.4.1.png", + "images": [] + }, + "scenebuilder9": { + "icon": "https://community.chocolatey.org/content/packageimages/scenebuilder9.9.0.1.png", + "images": [] + }, + "scheduled-shutdown": { + "icon": "", + "images": [] + }, + "schemacrawler": { + "icon": "https://community.chocolatey.org/content/packageimages/schemacrawler.16.19.7.png", + "images": [] + }, + "schild-report": { + "icon": "", + "images": [] + }, + "schildichat": { + "icon": "", + "images": [] + }, + "schismtracker": { + "icon": "", + "images": [] + }, + "scholdoc": { + "icon": "", + "images": [] + }, + "scicoslab": { + "icon": "https://community.chocolatey.org/content/packageimages/scicoslab.4.4.2.png", + "images": [] + }, + "scidavis": { + "icon": "", + "images": [] + }, + "sciencefair": { + "icon": "https://community.chocolatey.org/content/packageimages/sciencefair.1.0.6.png", + "images": [] + }, + "scientificword": { + "icon": "https://community.chocolatey.org/content/packageimages/scientificword.6.1.2.png", + "images": [] + }, + "scilab": { + "icon": "", + "images": [] + }, + "scite": { + "icon": "", + "images": [] + }, + "scite4autohotkey": { + "icon": "https://community.chocolatey.org/content/packageimages/scite4autohotkey.3.0.06.20170428.png", + "images": [] + }, + "sciteco": { + "icon": "", + "images": [] + }, + "scla": { + "icon": "https://community.chocolatey.org/content/packageimages/scla.2.0.0.2.png", + "images": [] + }, + "sco": { + "icon": "", + "images": [] + }, + "scons": { + "icon": "", + "images": [] + }, + "scoop-completion": { + "icon": "", + "images": [] + }, + "scoop-sd": { + "icon": "", + "images": [] + }, + "scoop-search": { + "icon": "", + "images": [] + }, + "scoop-shim": { + "icon": "", + "images": [] + }, + "scoop-validator": { + "icon": "", + "images": [] + }, + "scopy": { + "icon": "", + "images": [] + }, + "score": { + "icon": "", + "images": [] + }, + "scov": { + "icon": "", + "images": [] + }, + "scp": { + "icon": "https://community.chocolatey.org/content/packageimages/scp.5.0.2.png", + "images": [] + }, + "scpterminal": { + "icon": "", + "images": [] + }, + "scrab": { + "icon": "", + "images": [] + }, + "scratch": { + "icon": "", + "images": [] + }, + "scratch-3": { + "icon": "", + "images": [] + }, + "scratchfordiscord": { + "icon": "", + "images": [] + }, + "scrcpy": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/5/54/Scrcpy_logo.svg/1200px-Scrcpy_logo.svg.png", + "images": [ + "https://images.airdroid.com/2022/02/scrcpy.png", + "https://2.bp.blogspot.com/-2dg32r9hSj0/XIk7727kPcI/AAAAAAAACi8/92xT85-g1M0bpdVFZXrw6lpCXEGvsKqgQCLcBGAs/s1600/scrcpy-linux-ubuntu.png" + ] + }, + "scrcpy+": { + "icon": "", + "images": [] + }, + "scrcpy2": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/5/54/Scrcpy_logo.svg/1200px-Scrcpy_logo.svg.png", + "images": [] + }, + "screamer": { + "icon": "https://community.chocolatey.org/content/packageimages/Screamer.2022.07.26.png", + "images": [] + }, + "screen-resolution": { + "icon": "https://community.chocolatey.org/content/packageimages/screen-resolution.1.0.1.png", + "images": [] + }, + "screen-saver-control": { + "icon": "", + "images": [] + }, + "screencast": { + "icon": "", + "images": [] + }, + "screencloud": { + "icon": "", + "images": [] + }, + "screencloudplayer": { + "icon": "", + "images": [] + }, + "screenhunter": { + "icon": "", + "images": [] + }, + "screeninstyle": { + "icon": "https://community.chocolatey.org/content/packageimages/screeninstyle.1.1.10.png", + "images": [] + }, + "screenlogic-connect": { + "icon": "", + "images": [] + }, + "screenoff": { + "icon": "", + "images": [] + }, + "screenpresso": { + "icon": "https://community.chocolatey.org/content/packageimages/screenpresso.2.1.8.png", + "images": [] + }, + "screenrecorder": { + "icon": "", + "images": [] + }, + "screenruler": { + "icon": "https://community.chocolatey.org/content/packageimages/screenruler.0.10.0.png", + "images": [] + }, + "screenshotcaptor": { + "icon": "", + "images": [] + }, + "screensketch": { + "icon": "https://static.wikia.nocookie.net/logopedia/images/a/a3/Win-SnippingTool.png/revision/latest?cb=20211201013441", + "images": [] + }, + "screentogif": { + "icon": "https://community.chocolatey.org/content/packageimages/screentogif.2.41.0.png", + "images": [ + "https://www.screentogif.com/img/Startup.81fa6bd3.png", + "https://camo.githubusercontent.com/192d4a63fa660bdeaee93bf4d0832cd2d8b01c7edad9c0f625a652c464a6e4f8/68747470733a2f2f7777772e73637265656e746f6769662e636f6d2f6d656469612f5265636f726465722e706e67" + ] + }, + "screenview": { + "icon": "", + "images": [] + }, + "scriber": { + "icon": "", + "images": [] + }, + "scribus": { + "icon": "https://wiki.scribus.net/wiki/images/thumb/f/f1/Scribusicon-blue.png/200px-Scribusicon-blue.png", + "images": [] + }, + "scriptcs": { + "icon": "", + "images": [] + }, + "scrivener": { + "icon": "", + "images": [] + }, + "scrivener1": { + "icon": "https://community.chocolatey.org/content/packageimages/scrivener1.1.9.17.png", + "images": [] + }, + "scsetup": { + "icon": "https://community.chocolatey.org/content/packageimages/SCSetup.3.8.21.64.png", + "images": [] + }, + "scummvm": { + "icon": "", + "images": [] + }, + "sd": { + "icon": "", + "images": [] + }, + "sd-card-formatter": { + "icon": "https://community.chocolatey.org/content/packageimages/sd-card-formatter.5.0.2.png", + "images": [] + }, + "sd-cli": { + "icon": "https://community.chocolatey.org/content/packageimages/sd-cli.0.7.5.png", + "images": [] + }, + "sdbexplorer": { + "icon": "", + "images": [] + }, + "sdc-ietdviewautark": { + "icon": "", + "images": [] + }, + "sdc-ietdviewautarkbw": { + "icon": "", + "images": [] + }, + "sdc-ietdviewpublish": { + "icon": "", + "images": [] + }, + "sdcc": { + "icon": "", + "images": [] + }, + "sdfcli": { + "icon": "", + "images": [] + }, + "sdio": { + "icon": "https://community.chocolatey.org/content/packageimages/sdio.1.12.9.749.png", + "images": [] + }, + "sdir": { + "icon": "", + "images": [] + }, + "sdl2": { + "icon": "https://d4.alternativeto.net/osEBVed0H1ZZ3RYFt2TsXDDONZvrQIbw2bW19lTmNe4/rs:fit:280:280:0/g:ce:0:0/exar:1/YWJzOi8vZGlzdC9pY29ucy9zZGxfOTczNDgucG5n.png", + "images": [] + }, + "sdl2-image": { + "icon": "https://d4.alternativeto.net/osEBVed0H1ZZ3RYFt2TsXDDONZvrQIbw2bW19lTmNe4/rs:fit:280:280:0/g:ce:0:0/exar:1/YWJzOi8vZGlzdC9pY29ucy9zZGxfOTczNDgucG5n.png", + "images": [] + }, + "sdl2-mixer": { + "icon": "https://d4.alternativeto.net/osEBVed0H1ZZ3RYFt2TsXDDONZvrQIbw2bW19lTmNe4/rs:fit:280:280:0/g:ce:0:0/exar:1/YWJzOi8vZGlzdC9pY29ucy9zZGxfOTczNDgucG5n.png", + "images": [] + }, + "sdl2-ttf": { + "icon": "https://d4.alternativeto.net/osEBVed0H1ZZ3RYFt2TsXDDONZvrQIbw2bW19lTmNe4/rs:fit:280:280:0/g:ce:0:0/exar:1/YWJzOi8vZGlzdC9pY29ucy9zZGxfOTczNDgucG5n.png", + "images": [] + }, + "sdrsharp": { + "icon": "https://community.chocolatey.org/content/packageimages/sdrsharp.1.0.0.1909.png", + "images": [] + }, + "seafile": { + "icon": "", + "images": [] + }, + "seamonkey": { + "icon": "", + "images": [] + }, + "search-by-image-chrome": { + "icon": "https://community.chocolatey.org/content/packageimages/search-by-image-chrome.1.5.2.png", + "images": [] + }, + "search-deflector": { + "icon": "", + "images": [] + }, + "search-sql-server-database": { + "icon": "https://community.chocolatey.org/content/packageimages/search-sql-server-database.2.11.0.0.png", + "images": [] + }, + "searchdeflector": { + "icon": "", + "images": [] + }, + "searchfilterview": { + "icon": "https://community.chocolatey.org/content/packageimages/searchfilterview.1.00.png", + "images": [] + }, + "searchquerytool": { + "icon": "https://community.chocolatey.org/content/packageimages/SearchQueryTool.2.9.0.png", + "images": [] + }, + "searchwithmybrowser": { + "icon": "", + "images": [] + }, + "seaside": { + "icon": "https://community.chocolatey.org/content/packageimages/seaside.install.1.38.png", + "images": [] + }, + "seatools": { + "icon": "", + "images": [] + }, + "seatools-legacy": { + "icon": "", + "images": [] + }, + "seatsmart": { + "icon": "", + "images": [] + }, + "secondstrategy-baseline-utilities": { + "icon": "", + "images": [] + }, + "secret-maryo-chronicles": { + "icon": "", + "images": [] + }, + "secunia-psi": { + "icon": "https://community.chocolatey.org/content/packageimages/Secunia.PSI.3.0.0.9016.png", + "images": [] + }, + "secure-file": { + "icon": "https://community.chocolatey.org/content/packageimages/secure-file.1.0.0.png", + "images": [] + }, + "secureanywhere": { + "icon": "", + "images": [] + }, + "securedns-terminal": { + "icon": "", + "images": [] + }, + "securefs": { + "icon": "", + "images": [] + }, + "securepointsslvpn": { + "icon": "https://community.chocolatey.org/content/packageimages/securepointsslvpn.2.0.36.png", + "images": [] + }, + "secureshell-chrome": { + "icon": "https://community.chocolatey.org/content/packageimages/secureshell-chrome.0.8.43.png", + "images": [] + }, + "secureuxtheme": { + "icon": "", + "images": [] + }, + "security": { + "icon": "", + "images": [] + }, + "securitygateway": { + "icon": "", + "images": [] + }, + "securityplus": { + "icon": "", + "images": [] + }, + "sed": { + "icon": "", + "images": [] + }, + "seek-dsc": { + "icon": "", + "images": [] + }, + "seek-dsc-appfabric-hosting": { + "icon": "", + "images": [] + }, + "seek-dsc-database": { + "icon": "", + "images": [] + }, + "seek-dsc-harddisk": { + "icon": "", + "images": [] + }, + "seek-dsc-networking": { + "icon": "", + "images": [] + }, + "seek-dsc-nservicebus": { + "icon": "", + "images": [] + }, + "seek-dsc-software": { + "icon": "", + "images": [] + }, + "seek-dsc-topshelf": { + "icon": "", + "images": [] + }, + "sejda": { + "icon": "https://community.chocolatey.org/content/packageimages/sejda.3.2.85.png", + "images": [] + }, + "sejda-pdf": { + "icon": "", + "images": [] + }, + "selene": { + "icon": "", + "images": [] + }, + "selenium": { + "icon": "https://community.chocolatey.org/content/packageimages/selenium.3.141.59.png", + "images": [] + }, + "selenium-all-drivers": { + "icon": "https://community.chocolatey.org/content/packageimages/selenium-all-drivers.4.0.png", + "images": [] + }, + "selenium-chrome-driver": { + "icon": "", + "images": [] + }, + "selenium-chromium-edge-driver": { + "icon": "https://community.chocolatey.org/content/packageimages/selenium-chromium-edge-driver.110.0.1587.57.png", + "images": [] + }, + "selenium-edge-driver": { + "icon": "https://community.chocolatey.org/content/packageimages/selenium-edge-driver.6.17134.20180630.png", + "images": [] + }, + "selenium-gecko-driver": { + "icon": "https://community.chocolatey.org/content/packageimages/selenium-gecko-driver.0.32.2.png", + "images": [] + }, + "selenium-ie-driver": { + "icon": "", + "images": [] + }, + "selenium-opera-driver": { + "icon": "", + "images": [] + }, + "selfssl7": { + "icon": "", + "images": [] + }, + "semantamodeler": { + "icon": "", + "images": [] + }, + "semanticmerge": { + "icon": "https://community.chocolatey.org/content/packageimages/SemanticMerge.0.9.17.0.png", + "images": [] + }, + "semanticreleasenotes-parser": { + "icon": "https://community.chocolatey.org/content/packageimages/semanticreleasenotes-parser.0.1.0.png", + "images": [] + }, + "sematadatastore": { + "icon": "", + "images": [] + }, + "semeruruntimeopenedition-jdk": { + "icon": "", + "images": [] + }, + "semeruruntimeopenedition-jre": { + "icon": "", + "images": [] + }, + "sendmail": { + "icon": "", + "images": [] + }, + "sendmessage": { + "icon": "https://community.chocolatey.org/content/packageimages/sendmessage.1.1.2.png", + "images": [] + }, + "sendsx": { + "icon": "", + "images": [] + }, + "sendto-menu-editor": { + "icon": "", + "images": [] + }, + "sendtokindle": { + "icon": "https://i.imgur.com/ZadUYa5.png", + "images": [ + "https://m.media-amazon.com/images/G/01/pdocs-client/send-to-kindle/s2k-family-pc-rcm.PNG", + "https://m.media-amazon.com/images/G/01/pdocs-client/send-to-kindle/s2k-family-pc-dnd.png" + ] + }, + "sengi": { + "icon": "https://raw.githubusercontent.com/NicolasConstant/wingetui-illustration/master/pkgs/n/NicolasConstant/sengi/icon.png", + "images": [ + "https://raw.githubusercontent.com/NicolasConstant/wingetui-illustration/master/pkgs/n/NicolasConstant/sengi/screen-1.png", + "https://raw.githubusercontent.com/NicolasConstant/wingetui-illustration/master/pkgs/n/NicolasConstant/sengi/screen-2.png" + ] + }, + "sensu-agent": { + "icon": "", + "images": [] + }, + "sensu-cli": { + "icon": "", + "images": [] + }, + "sentinel": { + "icon": "", + "images": [] + }, + "sentry-cli": { + "icon": "", + "images": [] + }, + "seppdf": { + "icon": "https://community.chocolatey.org/content/packageimages/seppdf.3.64.png", + "images": [] + }, + "seq": { + "icon": "https://community.chocolatey.org/content/packageimages/seq.2023.1.8991.png", + "images": [] + }, + "seq-import": { + "icon": "https://community.chocolatey.org/content/packageimages/seq-import.0.1.16.png", + "images": [] + }, + "seqcli": { + "icon": "", + "images": [] + }, + "seqdownload": { + "icon": "https://community.chocolatey.org/content/packageimages/seqdownload.portable.1.26.png", + "images": [] + }, + "serf": { + "icon": "", + "images": [] + }, + "serial-cloner": { + "icon": "", + "images": [] + }, + "seriallab": { + "icon": "", + "images": [] + }, + "serilink": { + "icon": "", + "images": [] + }, + "serilog-generator": { + "icon": "https://community.chocolatey.org/content/packageimages/serilog-generator.1.0.10.png", + "images": [] + }, + "serizawa": { + "icon": "", + "images": [] + }, + "serva": { + "icon": "", + "images": [] + }, + "serve": { + "icon": "", + "images": [] + }, + "server": { + "icon": "", + "images": [] + }, + "server-jre": { + "icon": "", + "images": [] + }, + "server-jre10": { + "icon": "", + "images": [] + }, + "server-jre8": { + "icon": "", + "images": [] + }, + "server-jre9": { + "icon": "", + "images": [] + }, + "servercommunity": { + "icon": "", + "images": [] + }, + "serverenterprise": { + "icon": "", + "images": [] + }, + "serverless": { + "icon": "https://community.chocolatey.org/content/packageimages/serverless.3.28.0.png", + "images": [] + }, + "servermanager": { + "icon": "", + "images": [] + }, + "service-fabric": { + "icon": "https://community.chocolatey.org/content/packageimages/service-fabric.9.1.1390.png", + "images": [] + }, + "service-fabric-explorer": { + "icon": "", + "images": [] + }, + "service-fabric-sdk": { + "icon": "https://community.chocolatey.org/content/packageimages/service-fabric-sdk.6.1.1390.png", + "images": [] + }, + "service-fabric-tools": { + "icon": "https://community.chocolatey.org/content/packageimages/service-fabric-tools.2.5.20615.png", + "images": [] + }, + "servicebridge": { + "icon": "https://i.postimg.cc/yNNzCHDC/LSB.png", + "images": [] + }, + "servicebusexplorer": { + "icon": "https://community.chocolatey.org/content/packageimages/ServiceBusExplorer.6.0.3.png", + "images": [ + "https://raw.githubusercontent.com/paolosalvatori/ServiceBusExplorer/main/media/service-bus-explorer.png" + ] + }, + "servicebusmqmanager": { + "icon": "", + "images": [] + }, + "servicefabricexplorer": { + "icon": "", + "images": [] + }, + "servicefabricruntime": { + "icon": "", + "images": [] + }, + "servicepulse": { + "icon": "", + "images": [] + }, + "servicetriggereditor": { + "icon": "https://community.chocolatey.org/content/packageimages/servicetriggereditor.3.0.8.57.png", + "images": [] + }, + "serviio": { + "icon": "https://community.chocolatey.org/content/packageimages/serviio.2.3.png", + "images": [] + }, + "serviwin": { + "icon": "https://community.chocolatey.org/content/packageimages/serviwin.portable.1.71.png", + "images": [] + }, + "session": { + "icon": "https://getsession.org/apple-touch-icon.png", + "images": [] + }, + "sessionmanagerplugin": { + "icon": "", + "images": [] + }, + "setacl": { + "icon": "", + "images": [] + }, + "setacl-studio": { + "icon": "https://community.chocolatey.org/content/packageimages/setacl-studio.1.2.4.png", + "images": [] + }, + "setaffinity2": { + "icon": "", + "images": [] + }, + "setdefaultbrowser": { + "icon": "", + "images": [] + }, + "setdefaultprinter": { + "icon": "", + "images": [] + }, + "setpoint": { + "icon": "", + "images": [] + }, + "settingsmanager": { + "icon": "", + "images": [] + }, + "setup-assistant": { + "icon": "", + "images": [] + }, + "sfdx-cli": { + "icon": "https://community.chocolatey.org/content/packageimages/sfdx-cli.6.0.16.png", + "images": [] + }, + "sfk": { + "icon": "", + "images": [] + }, + "sforzando": { + "icon": "", + "images": [] + }, + "sfsu": { + "icon": "", + "images": [] + }, + "sftpgo": { + "icon": "https://community.chocolatey.org/content/packageimages/sftpgo.2.4.4.png", + "images": [] + }, + "sget": { + "icon": "https://community.chocolatey.org/content/packageimages/sget.1.3.1.png", + "images": [] + }, + "sgt-puzzles": { + "icon": "https://community.chocolatey.org/content/packageimages/sgt-puzzles.2023.02.24.png", + "images": [] + }, + "shadered": { + "icon": "", + "images": [] + }, + "shaderglass": { + "icon": "", + "images": [] + }, + "shadow": { + "icon": "", + "images": [] + }, + "shadowcopyview": { + "icon": "https://community.chocolatey.org/content/packageimages/shadowcopyview.1.15.png", + "images": [] + }, + "shadowexplorer": { + "icon": "https://community.chocolatey.org/content/packageimages/shadowexplorer.portable.0.9.462.png", + "images": [] + }, + "shadowsocks": { + "icon": "https://community.chocolatey.org/content/packageimages/shadowsocks.4.4.1.0.png", + "images": [] + }, + "shadowsocks-qt5": { + "icon": "https://community.chocolatey.org/content/packageimages/shadowsocks-qt5.2.9.0.20190623.png", + "images": [] + }, + "shadowsocks-qtun-plugin": { + "icon": "", + "images": [] + }, + "shadowsocks-rust": { + "icon": "", + "images": [] + }, + "shadowsocks-v2ray-plugin": { + "icon": "", + "images": [] + }, + "shadowsockselectron": { + "icon": "", + "images": [] + }, + "shadowsocksr-csharp": { + "icon": "", + "images": [] + }, + "shadowsocksr-hmbsbige": { + "icon": "", + "images": [] + }, + "shadowsocksr-windows": { + "icon": "", + "images": [] + }, + "shadowspawn": { + "icon": "", + "images": [] + }, + "shamela": { + "icon": "", + "images": [] + }, + "shapr3d": { + "icon": "", + "images": [] + }, + "shareaza": { + "icon": "", + "images": [] + }, + "sharebylink": { + "icon": "", + "images": [] + }, + "sharecoin": { + "icon": "", + "images": [] + }, + "shareenum": { + "icon": "https://community.chocolatey.org/content/packageimages/shareenum.1.60.png", + "images": [] + }, + "sharegate-desktop": { + "icon": "", + "images": [] + }, + "sharepoint-2010-sdk": { + "icon": "", + "images": [] + }, + "sharepoint-2013-sdk": { + "icon": "", + "images": [] + }, + "sharepoint-hiveshortcut-desktop": { + "icon": "", + "images": [] + }, + "sharepoint-hiveshortcut-explorer": { + "icon": "", + "images": [] + }, + "sharepoint-online-management-shell": { + "icon": "", + "images": [] + }, + "sharepointdesigner2010x64": { + "icon": "", + "images": [] + }, + "sharepointdesigner2013x32": { + "icon": "", + "images": [] + }, + "sharepointdesigner2013x64": { + "icon": "", + "images": [] + }, + "sharepointlogviewer": { + "icon": "", + "images": [] + }, + "sharepointmanager2010": { + "icon": "", + "images": [] + }, + "sharepointmanager2013": { + "icon": "", + "images": [] + }, + "sharex": { + "icon": "https://community.chocolatey.org/content/packageimages/sharex.16.1.0.png", + "images": [ + "https://getsharex.com/img/ShareX_Screenshot.png", + "https://getsharex.com/img/screenshots/MainWindowListView.png", + "https://getsharex.com/img/screenshots/MainWindowCaptureMenu.png", + "https://getsharex.com/img/screenshots/MainWindowUploadMenu.png", + "https://getsharex.com/img/screenshots/ClipboardUpload.png", + "https://getsharex.com/img/screenshots/MainWindowToolsMenu.png", + "https://getsharex.com/img/screenshots/ColorPicker.png", + "https://getsharex.com/img/screenshots/ScreenColorPicker.png", + "https://getsharex.com/img/screenshots/VideoConverter.png", + "https://getsharex.com/img/screenshots/ImageEditor.png", + "https://getsharex.com/img/screenshots/ImageEffects.png", + "https://i.vgy.me/a9hTwL.png", + "https://i.vgy.me/JPxq19.png" + ] + }, + "sharik": { + "icon": "", + "images": [] + }, + "sharpapp": { + "icon": "", + "images": [] + }, + "sharpdevelop": { + "icon": "", + "images": [] + }, + "sharperlight": { + "icon": "", + "images": [] + }, + "sharpkeys": { + "icon": "", + "images": [] + }, + "shasum": { + "icon": "", + "images": [] + }, + "shawl": { + "icon": "", + "images": [] + }, + "sheepit-client": { + "icon": "https://community.chocolatey.org/content/packageimages/sheepit-client.6.22092.0.png", + "images": [] + }, + "shell": { + "icon": "", + "images": [] + }, + "shell-x": { + "icon": "", + "images": [] + }, + "shellbagsexplorer": { + "icon": "", + "images": [] + }, + "shellbagsview": { + "icon": "", + "images": [] + }, + "shellcheck": { + "icon": "", + "images": [ + "https://miro.medium.com/v2/resize:fit:1400/0*DsAh-A5WQ9zc1ffA.png", + "https://www.tecmint.com/wp-content/uploads/2017/04/Shell-Script-Code-Analyzer-Tool.png", + "https://www.tecmint.com/wp-content/uploads/2017/04/ShellCheck-Check-Shell-Script.png" + ] + }, + "shellexview": { + "icon": "https://i.postimg.cc/sgBX7myK/image.png", + "images": [ + "https://i.postimg.cc/qv97LKvG/image.png" + ] + }, + "shellmenunew": { + "icon": "https://community.chocolatey.org/content/packageimages/shellmenunew.1.02.png", + "images": [] + }, + "shellrunas": { + "icon": "https://community.chocolatey.org/content/packageimages/shellrunas.1.01.0.20160210.png", + "images": [] + }, + "shelltools": { + "icon": "", + "images": [] + }, + "shellz": { + "icon": "", + "images": [] + }, + "sherwood": { + "icon": "https://community.chocolatey.org/content/packageimages/sherwood.portable.1.09.png", + "images": [] + }, + "shexview": { + "icon": "https://community.chocolatey.org/content/packageimages/shexview.2.01.png", + "images": [] + }, + "shfmt": { + "icon": "", + "images": [] + }, + "shiba": { + "icon": "", + "images": [] + }, + "shim": { + "icon": "", + "images": [] + }, + "shimo": { + "icon": "", + "images": [] + }, + "shipyard": { + "icon": "https://community.chocolatey.org/content/packageimages/shipyard.0.4.14.png", + "images": [] + }, + "shman": { + "icon": "https://community.chocolatey.org/content/packageimages/shman.1.10.png", + "images": [] + }, + "shmnview": { + "icon": "https://community.chocolatey.org/content/packageimages/shmnview.1.41.png", + "images": [] + }, + "shogigui": { + "icon": "", + "images": [] + }, + "shortcut": { + "icon": "", + "images": [] + }, + "shortcutexporter": { + "icon": "", + "images": [] + }, + "shotcut": { + "icon": "https://community.chocolatey.org/content/packageimages/shotcut.portable.22.12.21.png", + "images": [ + "https://i.postimg.cc/2SRBQGSD/shotcut.png" + ] + }, + "shotty": { + "icon": "", + "images": [] + }, + "show-disk-partition-style": { + "icon": "", + "images": [] + }, + "showwhatprocesslocksfile": { + "icon": "", + "images": [] + }, + "shplayer": { + "icon": "", + "images": [] + }, + "shureplusmotiv": { + "icon": "", + "images": [] + }, + "shutdowncountdown": { + "icon": "", + "images": [] + }, + "shutter": { + "icon": "", + "images": [] + }, + "shutter-encoder": { + "icon": "", + "images": [] + }, + "shuttle": { + "icon": "", + "images": [] + }, + "shutup10": { + "icon": "", + "images": [] + }, + "sia-ui": { + "icon": "", + "images": [] + }, + "sickbeard": { + "icon": "https://community.chocolatey.org/content/packageimages/SickBeard.2012.11.04.1.png", + "images": [] + }, + "sidebar-diagnostics": { + "icon": "https://community.chocolatey.org/content/packageimages/sidebar-diagnostics.3.6.3.png", + "images": [] + }, + "sidebardiagnostics": { + "icon": "", + "images": [] + }, + "sidekick": { + "icon": "", + "images": [] + }, + "sidekick-browser": { + "icon": "", + "images": [] + }, + "sideloadly": { + "icon": "", + "images": [] + }, + "sidequest": { + "icon": "https://sidequestvr.com/assets/icons/apple-icon-180x180.png", + "images": [] + }, + "sidesync": { + "icon": "https://community.chocolatey.org/content/packageimages/sidesync.4.7.5.203.png", + "images": [] + }, + "siera": { + "icon": "", + "images": [] + }, + "sifon": { + "icon": "https://community.chocolatey.org/content/packageimages/sifon.1.3.3.png", + "images": [] + }, + "sift": { + "icon": "", + "images": [] + }, + "sigcheck": { + "icon": "https://community.chocolatey.org/content/packageimages/sigcheck.2.90.png", + "images": [] + }, + "sigil": { + "icon": "https://sigil-ebook.com/assets/images/sigil-512.png", + "images": [ + "https://raw.githubusercontent.com/Sigil-Ebook/Sigil/master/docs/screencaps/sigil.png", + "https://raw.githubusercontent.com/Sigil-Ebook/Sigil/master/docs/screencaps/sigil_dark.png", + "https://raw.githubusercontent.com/Sigil-Ebook/Sigil/master/docs/screencaps/pageedit.png" + ] + }, + "sigma-file-manager": { + "icon": "https://i.imgur.com/YA5meL1.png", + "images": [ + "https://i.imgur.com/CpJu3Co.png", + "https://i.imgur.com/GezgekX.png", + "https://i.imgur.com/rgSbFdi.png", + "https://i.imgur.com/cXCLIyo.png", + "https://i.imgur.com/86f2gwh.png", + "https://i.imgur.com/oO7XnNc.png", + "https://i.imgur.com/zNqNVtz.png", + "https://i.imgur.com/fpF8vik.png", + "https://i.imgur.com/CmZAbLo.png", + "https://i.imgur.com/S04JAkm.png" + ] + }, + "signal": { + "icon": "https://raw.githubusercontent.com/signalapp/Signal-Desktop/main/images/tray-icons/base/signal-tray-icon-256x256-base.png", + "images": [] + }, + "signal-beta": { + "icon": "", + "images": [] + }, + "signal-cli": { + "icon": "", + "images": [] + }, + "signalbackup-tools": { + "icon": "", + "images": [] + }, + "signalfx-agent": { + "icon": "https://community.chocolatey.org/content/packageimages/signalfx-agent.5.27.3.png", + "images": [] + }, + "signalrgb": { + "icon": "", + "images": [] + }, + "signcode": { + "icon": "", + "images": [] + }, + "sigrok": { + "icon": "", + "images": [] + }, + "sigrok-cli": { + "icon": "https://community.chocolatey.org/content/packageimages/sigrok-cli.0.7.2.png", + "images": [] + }, + "silentcmd": { + "icon": "", + "images": [] + }, + "silentinstallbuilder": { + "icon": "https://i.postimg.cc/HnX6mXZD/sib5.png", + "images": [ + "https://i.postimg.cc/GtwjX9cM/image.png" + ] + }, + "silentinstallbuilder-beta": { + "icon": "https://i.postimg.cc/Kv70s73t/sib6.png", + "images": [ + "https://i.postimg.cc/FKkcwmCw/image.png" + ] + }, + "silex-desktop": { + "icon": "", + "images": [] + }, + "silicon": { + "icon": "", + "images": [] + }, + "silk": { + "icon": "", + "images": [] + }, + "sim": { + "icon": "https://community.chocolatey.org/content/packageimages/sim.1.5.0.202.png", + "images": [] + }, + "simairclient": { + "icon": "", + "images": [] + }, + "simh": { + "icon": "https://community.chocolatey.org/content/packageimages/simh.3.9.0.png", + "images": [] + }, + "simnetsa-adobereader-fr": { + "icon": "https://community.chocolatey.org/content/packageimages/simnetsa-adobereader-fr.11.0.7.png", + "images": [] + }, + "simple-assembly-explorer": { + "icon": "", + "images": [] + }, + "simple-dnscrypt": { + "icon": "", + "images": [] + }, + "simple-docker-ui": { + "icon": "", + "images": [] + }, + "simple-http-server": { + "icon": "", + "images": [] + }, + "simple-software-restriction-policy": { + "icon": "", + "images": [] + }, + "simple-sticky-notes": { + "icon": "", + "images": [] + }, + "simplecom": { + "icon": "", + "images": [] + }, + "simplednscrypt": { + "icon": "https://community.chocolatey.org/content/packageimages/simplednscrypt.0.6.6.png", + "images": [] + }, + "simpleipconfig": { + "icon": "", + "images": [] + }, + "simplenote": { + "icon": "https://community.chocolatey.org/content/packageimages/simplenote.2.21.0.png", + "images": [] + }, + "simpleprogramdebugger": { + "icon": "https://community.chocolatey.org/content/packageimages/simpleprogramdebugger.1.05.png", + "images": [ + "https://i.postimg.cc/fyKK7Z7M/image.png" + ] + }, + "simplestfilerenamer": { + "icon": "", + "images": [] + }, + "simplesystemtweaker": { + "icon": "https://community.chocolatey.org/content/packageimages/simplesystemtweaker.2.0.0.20141201.png", + "images": [] + }, + "simpletransfer": { + "icon": "", + "images": [] + }, + "simplewall": { + "icon": "https://community.chocolatey.org/content/packageimages/simplewall.install.3.6.7.png", + "images": [ + "https://i.postimg.cc/Qxwdpt9F/image.png", + "https://i.postimg.cc/4xcNwgVB/image.png" + ] + }, + "simplewavsplitter-avalonia": { + "icon": "", + "images": [] + }, + "simplex-chat": { + "icon": "", + "images": [] + }, + "simplifi": { + "icon": "https://community.chocolatey.org/content/packageimages/Simplifi.0.0.3.1.png", + "images": [] + }, + "simply-weather": { + "icon": "", + "images": [] + }, + "simplyfortran": { + "icon": "", + "images": [] + }, + "simutrans": { + "icon": "", + "images": [] + }, + "simutrans-pak128": { + "icon": "", + "images": [] + }, + "simutrans-pak64": { + "icon": "", + "images": [] + }, + "sing-box": { + "icon": "https://i.postimg.cc/kghFK6Yy/sing-box.png", + "images": [] + }, + "sinon": { + "icon": "https://community.chocolatey.org/content/packageimages/Sinon.1.3.0.png", + "images": [] + }, + "sioyek": { + "icon": "", + "images": [] + }, + "sipgatesoftphone": { + "icon": "", + "images": [] + }, + "sirikali": { + "icon": "", + "images": [] + }, + "siril": { + "icon": "", + "images": [] + }, + "sitdownmw": { + "icon": "", + "images": [] + }, + "site24x7-apminsight-dotnet": { + "icon": "", + "images": [] + }, + "sitecore-courier": { + "icon": "", + "images": [] + }, + "sitecoreshipfunctions": { + "icon": "", + "images": [] + }, + "sitemapcreator": { + "icon": "", + "images": [] + }, + "siteshoter": { + "icon": "https://community.chocolatey.org/content/packageimages/siteshoter.1.42.png", + "images": [] + }, + "sithealthy": { + "icon": "", + "images": [] + }, + "siv": { + "icon": "", + "images": [] + }, + "siw": { + "icon": "https://community.chocolatey.org/content/packageimages/siw.13.2.11.20230204.png", + "images": [] + }, + "siyuan": { + "icon": "https://i.postimg.cc/DfCR8D3t/SiYuan.png", + "images": [] + }, + "siyuan-note": { + "icon": "", + "images": [] + }, + "sizeexplorer": { + "icon": "", + "images": [] + }, + "sizer": { + "icon": "https://community.chocolatey.org/content/packageimages/sizer.4.0.640.png", + "images": [] + }, + "sizer-dev": { + "icon": "", + "images": [] + }, + "skaarhojupdater": { + "icon": "", + "images": [] + }, + "skaffold": { + "icon": "https://community.chocolatey.org/content/packageimages/skaffold.2.1.0.png", + "images": [] + }, + "sketchbook": { + "icon": "https://www.logolynx.com/images/logolynx/38/384353c7d320c8c409fd75fd9200037d.png", + "images": [] + }, + "sketchup-2022": { + "icon": "https://i.postimg.cc/259Fnnxn/sketchup.png", + "images": [] + }, + "sketchup-2023": { + "icon": "https://i.postimg.cc/259Fnnxn/sketchup.png", + "images": [] + }, + "sketchup-2025": { + "icon": "https://i.postimg.cc/259Fnnxn/sketchup.png", + "images": [ + "https://i.postimg.cc/yxZwM1Nr/image.png" + ] + }, + "sketchup-pro-2022": { + "icon": "", + "images": [] + }, + "sketchuppro": { + "icon": "", + "images": [] + }, + "sketchupviewer": { + "icon": "https://community.chocolatey.org/content/packageimages/sketchupviewer.17.0.18899.png", + "images": [] + }, + "skia4delphi": { + "icon": "https://community.chocolatey.org/content/packageimages/skia4delphi.4.0.2.png", + "images": [] + }, + "skifree": { + "icon": "", + "images": [] + }, + "skillpipereader": { + "icon": "https://community.chocolatey.org/content/packageimages/skillpipereader.2.1.143.20160112.png", + "images": [] + }, + "skqw": { + "icon": "", + "images": [] + }, + "sktimestamp": { + "icon": "https://community.chocolatey.org/content/packageimages/sktimestamp.1.3.6.png", + "images": [] + }, + "skydrive": { + "icon": "", + "images": [] + }, + "skyfonts": { + "icon": "https://community.chocolatey.org/content/packageimages/skyfonts.5.9.5.1.png", + "images": [] + }, + "skygo": { + "icon": "", + "images": [] + }, + "skylight": { + "icon": "", + "images": [] + }, + "skympc": { + "icon": "https://community.chocolatey.org/content/packageimages/skympc.1.6.4.20190511.png", + "images": [] + }, + "skype": { + "icon": "https://community.chocolatey.org/content/packageimages/skype.8.94.0.426.png", + "images": [] + }, + "skype-chrome": { + "icon": "", + "images": [] + }, + "skype-disable-updates-winconfig": { + "icon": "https://community.chocolatey.org/content/packageimages/skype-disable-updates-winconfig.0.0.1.png", + "images": [] + }, + "skype-insiders": { + "icon": "", + "images": [] + }, + "skype-utility-project": { + "icon": "", + "images": [] + }, + "skypecontactsview": { + "icon": "https://community.chocolatey.org/content/packageimages/skypecontactsview.1.05.png", + "images": [] + }, + "skypefocusfix": { + "icon": "", + "images": [] + }, + "skypeforbusiness": { + "icon": "https://community.chocolatey.org/content/packageimages/SkypeForBusiness.12130.20272.png", + "images": [] + }, + "skypeforbusinessbasic": { + "icon": "https://community.chocolatey.org/content/packageimages/SkypeForBusinessBasic.11107.33602.png", + "images": [] + }, + "skypelogview": { + "icon": "https://community.chocolatey.org/content/packageimages/skypelogview.1.55.png", + "images": [] + }, + "skysitefacilities": { + "icon": "https://community.chocolatey.org/content/packageimages/SkySiteFacilities.4.2.0.png", + "images": [] + }, + "skywalking-cli": { + "icon": "", + "images": [] + }, + "slack": { + "icon": "https://i.imgur.com/PHteKLC.png", + "images": [ + "https://i.imgur.com/EyA9fI3.png", + "https://i.imgur.com/EX4lDVS.png", + "https://i.imgur.com/V8d0HAH.png" + ] + }, + "slack-beta": { + "icon": "", + "images": [] + }, + "slade": { + "icon": "https://community.chocolatey.org/content/packageimages/slade.3.2.1.png", + "images": [] + }, + "sleek": { + "icon": "", + "images": [] + }, + "sleep-timer": { + "icon": "", + "images": [] + }, + "sleeponlan": { + "icon": "", + "images": [] + }, + "sleuthkit": { + "icon": "", + "images": [] + }, + "slic3r": { + "icon": "https://community.chocolatey.org/content/packageimages/slic3r.1.3.0.png", + "images": [] + }, + "slickrss-chrome": { + "icon": "", + "images": [] + }, + "slickrun": { + "icon": "", + "images": [] + }, + "slidy": { + "icon": "", + "images": [] + }, + "slik-svn": { + "icon": "", + "images": [] + }, + "sliksvn": { + "icon": "https://community.chocolatey.org/content/packageimages/sliksvn.1.14.2.png", + "images": [] + }, + "slm": { + "icon": "https://community.chocolatey.org/content/packageimages/slm.11.1.png", + "images": [] + }, + "slntools": { + "icon": "", + "images": [] + }, + "slooh-explorer": { + "icon": "", + "images": [] + }, + "slpolicy": { + "icon": "", + "images": [] + }, + "slskd": { + "icon": "", + "images": [] + }, + "smallpdf": { + "icon": "", + "images": [] + }, + "smart-console-utility": { + "icon": "https://community.chocolatey.org/content/packageimages/smart-console-utility.3.00.10.png", + "images": [] + }, + "smart-control-center": { + "icon": "https://community.chocolatey.org/content/packageimages/smart-control-center.1.1.3.4.png", + "images": [] + }, + "smart7z": { + "icon": "", + "images": [] + }, + "smartftp": { + "icon": "https://i.postimg.cc/pr4jMkZ6/smartftp.png", + "images": [ + "https://i.postimg.cc/Gt5Fhbcz/image.png", + "https://i.postimg.cc/BZYcCBxD/image.png", + "https://i.postimg.cc/8PxR2kXz/image.png", + "https://i.postimg.cc/Z5384kXF/image.png" + ] + }, + "smartgamebooster": { + "icon": "", + "images": [] + }, + "smartgit": { + "icon": "https://community.chocolatey.org/content/packageimages/SmartGit.21.1.1.png", + "images": [] + }, + "smartgit-with-jre": { + "icon": "", + "images": [] + }, + "smartmontools": { + "icon": "https://community.chocolatey.org/content/packageimages/smartmontools.7.3.png", + "images": [] + }, + "smartpss": { + "icon": "https://community.chocolatey.org/content/packageimages/smartpss.2.00.1.20170225.png", + "images": [] + }, + "smartrename": { + "icon": "https://community.chocolatey.org/content/packageimages/smartrename.1.1.2.png", + "images": [] + }, + "smartsvn": { + "icon": "", + "images": [] + }, + "smartswitch": { + "icon": "https://i.postimg.cc/CKcNST5S/samsungsmartswitch.png", + "images": [] + }, + "smartsynchronize": { + "icon": "", + "images": [] + }, + "smartsystemmenu": { + "icon": "https://community.chocolatey.org/content/packageimages/smartsystemmenu.2.21.2.png", + "images": [] + }, + "smarttaskbar": { + "icon": "", + "images": [] + }, + "smartty": { + "icon": "", + "images": [] + }, + "smf-player": { + "icon": "", + "images": [] + }, + "smimesign": { + "icon": "", + "images": [] + }, + "sming-core": { + "icon": "", + "images": [] + }, + "smlnj": { + "icon": "", + "images": [] + }, + "smmdb-client": { + "icon": "", + "images": [] + }, + "smplayer": { + "icon": "https://i.postimg.cc/X7mhgCJL/SMPlayer.png", + "images": [] + }, + "sms": { + "icon": "https://community.chocolatey.org/content/packageimages/sms.13.1.15.png", + "images": [] + }, + "smsniff": { + "icon": "https://community.chocolatey.org/content/packageimages/smsniff.2.27.png", + "images": [] + }, + "smtube": { + "icon": "https://community.chocolatey.org/content/packageimages/smtube.21.10.0.png", + "images": [] + }, + "smuxi": { + "icon": "", + "images": [] + }, + "smz32v50": { + "icon": "", + "images": [] + }, + "snagit": { + "icon": "https://i.postimg.cc/Pr6L1hBP/snagit-icon.png", + "images": [] + }, + "snagit-2020": { + "icon": "https://i.postimg.cc/Pr6L1hBP/snagit-icon.png", + "images": [] + }, + "snagit-2021": { + "icon": "https://i.postimg.cc/Pr6L1hBP/snagit-icon.png", + "images": [] + }, + "snagit-2022": { + "icon": "https://i.postimg.cc/Pr6L1hBP/snagit-icon.png", + "images": [] + }, + "snagit-2023": { + "icon": "https://i.postimg.cc/Pr6L1hBP/snagit-icon.png", + "images": [] + }, + "snagit-2024": { + "icon": "https://i.postimg.cc/Pr6L1hBP/snagit-icon.png", + "images": [] + }, + "snagit-2025": { + "icon": "https://i.postimg.cc/Pr6L1hBP/snagit-icon.png", + "images": [ + "https://i.postimg.cc/6513ycvf/image.png" + ] + }, + "snailfm": { + "icon": "", + "images": [] + }, + "snake": { + "icon": "", + "images": [] + }, + "snake-java": { + "icon": "https://community.chocolatey.org/content/packageimages/snake-java.1.7.0.png", + "images": [] + }, + "snaketail": { + "icon": "https://community.chocolatey.org/content/packageimages/snaketail.portable.1.9.4.png", + "images": [] + }, + "snapgene-viewer": { + "icon": "https://community.chocolatey.org/content/packageimages/snapgene-viewer.5.2.4.png", + "images": [] + }, + "snaplr": { + "icon": "https://community.chocolatey.org/content/packageimages/snaplr.0.1.png", + "images": [] + }, + "snapmakerluban": { + "icon": "", + "images": [] + }, + "snappy-driver-installer": { + "icon": "https://community.chocolatey.org/content/packageimages/snappy-driver-installer.1.0.539.20170422.png", + "images": [] + }, + "snappy-driver-installer-origin": { + "icon": "https://i.ibb.co/C50n1dRK/image.png", + "images": [] + }, + "snapraid": { + "icon": "", + "images": [] + }, + "snaptimer": { + "icon": "", + "images": [] + }, + "snarl": { + "icon": "", + "images": [] + }, + "snaz": { + "icon": "", + "images": [] + }, + "sndcpy": { + "icon": "", + "images": [] + }, + "snes9x": { + "icon": "https://community.chocolatey.org/content/packageimages/snes9x.1.61.png", + "images": [] + }, + "sniffpass": { + "icon": "https://community.chocolatey.org/content/packageimages/sniffpass.1.13.png", + "images": [] + }, + "snipaste": { + "icon": "", + "images": [] + }, + "snipcommand": { + "icon": "", + "images": [] + }, + "snipe": { + "icon": "", + "images": [] + }, + "snippingtoolplusplus": { + "icon": "", + "images": [] + }, + "snips": { + "icon": "https://community.chocolatey.org/content/packageimages/snips.1.2.png", + "images": [] + }, + "snmpb": { + "icon": "https://community.chocolatey.org/content/packageimages/snmpb.0.8.png", + "images": [] + }, + "snoop": { + "icon": "https://community.chocolatey.org/content/packageimages/snoop.5.0.0.png", + "images": [] + }, + "snyk": { + "icon": "https://community.chocolatey.org/content/packageimages/snyk.1.797.0.png", + "images": [] + }, + "so": { + "icon": "", + "images": [] + }, + "soapui": { + "icon": "https://community.chocolatey.org/content/packageimages/soapui.5.7.0.20220316.png", + "images": [] + }, + "socialamnesia": { + "icon": "", + "images": [] + }, + "socially": { + "icon": "", + "images": [] + }, + "socket-io-tester": { + "icon": "https://community.chocolatey.org/content/packageimages/socket-io-tester.1.2.3.png", + "images": [] + }, + "socketsniff": { + "icon": "https://community.chocolatey.org/content/packageimages/socketsniff.1.11.png", + "images": [] + }, + "soda-for-sparc": { + "icon": "", + "images": [] + }, + "sofia": { + "icon": "", + "images": [] + }, + "softerraldapbrowser": { + "icon": "https://community.chocolatey.org/content/packageimages/softerraldapbrowser.4.5.19808.0.png", + "images": [] + }, + "softether-vpn-client": { + "icon": "", + "images": [] + }, + "softhsm": { + "icon": "", + "images": [] + }, + "softkey-revealer": { + "icon": "", + "images": [] + }, + "softphone": { + "icon": "https://imgur.com/YJszAke.png", + "images": [ + "https://www.3cx.com/wp-content/uploads/2013/07/beta-release-3-1-opt.png", + "https://www.3cx.com/wp-content/uploads/2013/10/sp-2-image-1-opt.png", + "https://eteletech.com/wp-content/uploads/2015/12/3cx.jpg" + ] + }, + "software-ideas-modeler": { + "icon": "https://community.chocolatey.org/content/packageimages/software-ideas-modeler.portable.12.71.png", + "images": [] + }, + "softwarecreations-devbox": { + "icon": "https://community.chocolatey.org/content/packageimages/SoftwareCreations.devbox.0.04.png", + "images": [] + }, + "softwarecreations-devset": { + "icon": "https://community.chocolatey.org/content/packageimages/SoftwareCreations.devset.0.07.png", + "images": [] + }, + "softwareinformer": { + "icon": "https://community.chocolatey.org/content/packageimages/softwareinformer.1.5.1346.png", + "images": [] + }, + "sogeti-windowsazure-plugins-endpoint-acl": { + "icon": "", + "images": [] + }, + "sogouinput": { + "icon": "https://i.postimg.cc/vBjg3mgd/sogou.png", + "images": [ + "https://i.postimg.cc/NFRv6q83/sogou1.png", + "https://i.postimg.cc/xTj6yVPL/sogou2.png", + "https://i.postimg.cc/9f2RZCdh/sogou3.png" + ] + }, + "sogouinputskineditor": { + "icon": "", + "images": [] + }, + "sogouwbinput": { + "icon": "", + "images": [] + }, + "solar": { + "icon": "", + "images": [] + }, + "solarwinds-advanced-monitoring-agent": { + "icon": "", + "images": [] + }, + "solarwinds-automation-manager": { + "icon": "", + "images": [] + }, + "solarwinds-backup-manager": { + "icon": "", + "images": [] + }, + "solarwinds-take-control-teamviewer": { + "icon": "", + "images": [] + }, + "solarwinds-take-control-viewer": { + "icon": "", + "images": [] + }, + "solarwinds-tftp-server": { + "icon": "https://community.chocolatey.org/content/packageimages/solarwinds-tftp-server.11.2.0.50028.png", + "images": [] + }, + "solfege": { + "icon": "", + "images": [] + }, + "solidity": { + "icon": "", + "images": [] + }, + "solr": { + "icon": "https://community.chocolatey.org/content/packageimages/Solr.9.1.0.png", + "images": [] + }, + "soluto": { + "icon": "https://community.chocolatey.org/content/packageimages/soluto.1.3.1497.1.png", + "images": [] + }, + "solvespace": { + "icon": "https://community.chocolatey.org/content/packageimages/solvespace.2.3.png", + "images": [] + }, + "sonar-runner": { + "icon": "", + "images": [] + }, + "sonar-scanner": { + "icon": "", + "images": [] + }, + "sonarlint-vs2015": { + "icon": "https://community.chocolatey.org/content/packageimages/sonarlint-vs2015.4.38.0.36876.png", + "images": [] + }, + "sonarlint-vs2017": { + "icon": "https://community.chocolatey.org/content/packageimages/sonarlint-vs2017.5.5.0.43817.png", + "images": [] + }, + "sonarlint-vs2022": { + "icon": "https://community.chocolatey.org/content/packageimages/sonarlint-vs2022.6.13.0.62767.png", + "images": [] + }, + "sonarqube": { + "icon": "", + "images": [] + }, + "sonarqube-scanner": { + "icon": "", + "images": [] + }, + "sonarr": { + "icon": "https://community.chocolatey.org/content/packageimages/sonarr.3.0.9.1549.png", + "images": [] + }, + "sonarscanner-msbuild-net46": { + "icon": "https://community.chocolatey.org/content/packageimages/sonarscanner-msbuild-net46.5.11.0.60783.png", + "images": [] + }, + "sonarscanner-msbuild-net50": { + "icon": "https://community.chocolatey.org/content/packageimages/sonarscanner-msbuild-net50.5.11.0.60783.png", + "images": [] + }, + "sonarscanner-msbuild-netcoreapp2-0": { + "icon": "https://community.chocolatey.org/content/packageimages/sonarscanner-msbuild-netcoreapp2.0.5.11.0.60783.png", + "images": [] + }, + "sonarscanner-msbuild-netcoreapp30": { + "icon": "https://community.chocolatey.org/content/packageimages/sonarscanner-msbuild-netcoreapp30.5.11.0.60783.png", + "images": [] + }, + "songr": { + "icon": "", + "images": [] + }, + "sonicpi": { + "icon": "https://community.chocolatey.org/content/packageimages/sonicpi.3.1.0.png", + "images": [] + }, + "sonicroboblast2": { + "icon": "", + "images": [] + }, + "sonicroboblast2kart": { + "icon": "", + "images": [] + }, + "sonicvisualiser": { + "icon": "https://community.chocolatey.org/content/packageimages/sonicvisualiser.4.5.1.png", + "images": [] + }, + "sonicwall-netextender": { + "icon": "https://paulstsmith.github.io/images/netextender-icon.png", + "images": [ + "https://paulstsmith.github.io/images/netextender-screenshot-connected.png", + "https://paulstsmith.github.io/images/netextender-screenShot-disconnected.png" + ] + }, + "sonixd": { + "icon": "", + "images": [] + }, + "sono": { + "icon": "", + "images": [] + }, + "sonobuoy": { + "icon": "", + "images": [] + }, + "sonobus": { + "icon": "", + "images": [] + }, + "sonos-controller": { + "icon": "https://community.chocolatey.org/content/packageimages/sonos-controller.14.20.0.png", + "images": [] + }, + "sonos-s1-controller": { + "icon": "https://community.chocolatey.org/content/packageimages/sonos-s1-controller.57.3.77280.png", + "images": [] + }, + "sony-imaging-edge-webcam": { + "icon": "https://community.chocolatey.org/content/packageimages/sony-imaging-edge-webcam.1.1.01.08108.png", + "images": [] + }, + "sonyvegaspro": { + "icon": "https://community.chocolatey.org/content/packageimages/sonyvegaspro.13.0.428.png", + "images": [] + }, + "sophia": { + "icon": "https://community.chocolatey.org/content/packageimages/sophia.6.3.2.png", + "images": [] + }, + "sophiapp": { + "icon": "", + "images": [] + }, + "sops": { + "icon": "", + "images": [] + }, + "sorayomi": { + "icon": "", + "images": [] + }, + "soroush+": { + "icon": "", + "images": [] + }, + "sort-uniq-wc": { + "icon": "", + "images": [] + }, + "sos": { + "icon": "", + "images": [] + }, + "soulseekqt": { + "icon": "", + "images": [] + }, + "soundblastercommand": { + "icon": "https://d287ku8w5owj51.cloudfront.net/inline/products/23431/sbcommand_app_icon.png", + "images": [] + }, + "soundboard": { + "icon": "", + "images": [] + }, + "soundcheck": { + "icon": "https://i.postimg.cc/3NFW2Vtp/sndchk.png", + "images": [ + "https://i.postimg.cc/bNqZqYvR/image.png", + "https://i.postimg.cc/rwmzthx0/image.png", + "https://i.postimg.cc/x148GK3s/image.png", + "https://i.postimg.cc/Xq4YNxnv/image.png", + "https://i.postimg.cc/j2cdDNj4/image.png" + ] + }, + "soundly": { + "icon": "", + "images": [] + }, + "soundnode": { + "icon": "", + "images": [] + }, + "soundnode-app": { + "icon": "https://community.chocolatey.org/content/packageimages/soundnode-app.0.6.5.20200509.png", + "images": [] + }, + "soundswitch": { + "icon": "https://community.chocolatey.org/content/packageimages/soundswitch.6.5.4.png", + "images": [] + }, + "soundtrack": { + "icon": "", + "images": [] + }, + "source-han-sans-cn": { + "icon": "", + "images": [] + }, + "source-han-sans-sc": { + "icon": "", + "images": [] + }, + "source-han-serif-cn": { + "icon": "", + "images": [] + }, + "source-han-serif-sc": { + "icon": "", + "images": [] + }, + "sourcecodepro": { + "icon": "", + "images": [] + }, + "sourcegraph-cli": { + "icon": "", + "images": [] + }, + "sourceinsight": { + "icon": "", + "images": [] + }, + "sourcelink": { + "icon": "", + "images": [] + }, + "sourcemonitor": { + "icon": "https://community.chocolatey.org/content/packageimages/sourcemonitor.3.5.16.62.png", + "images": [] + }, + "sourcetrail": { + "icon": "https://community.chocolatey.org/content/packageimages/sourcetrail.2021.4.19.png", + "images": [] + }, + "sourcetree": { + "icon": "", + "images": [] + }, + "sourcetree-disableautoupdate": { + "icon": "https://community.chocolatey.org/content/packageimages/sourcetree-disableautoupdate.1.0.0.png", + "images": [] + }, + "sovranti": { + "icon": "", + "images": [] + }, + "sox": { + "icon": "", + "images": [] + }, + "sozi": { + "icon": "", + "images": [] + }, + "sp2013prereqs": { + "icon": "", + "images": [] + }, + "space": { + "icon": "https://resources.jetbrains.com/storage/products/space/img/meta/logo.png", + "images": [] + }, + "space-radar": { + "icon": "", + "images": [] + }, + "spacedesk-server": { + "icon": "https://community.chocolatey.org/content/packageimages/spacedesk-server.1.0.60.png", + "images": [] + }, + "spacedeskdriver-client": { + "icon": "", + "images": [] + }, + "spacedeskdriver-server": { + "icon": "https://i.ibb.co/tCBfBrV/img.png", + "images": [] + }, + "spaceengine": { + "icon": "", + "images": [] + }, + "spaceeye": { + "icon": "", + "images": [] + }, + "spaceinvaders": { + "icon": "", + "images": [] + }, + "spacemacs": { + "icon": "https://community.chocolatey.org/content/packageimages/spacemacs.0.200.13.20210130.png", + "images": [] + }, + "spacemesh": { + "icon": "", + "images": [] + }, + "spacemonger": { + "icon": "https://community.chocolatey.org/content/packageimages/spacemonger.portable.1.4.0.20220808.png", + "images": [] + }, + "spaceradar": { + "icon": "https://community.chocolatey.org/content/packageimages/spaceradar.5.1.0.20200525.png", + "images": [] + }, + "spacescape": { + "icon": "", + "images": [] + }, + "spacesniffer": { + "icon": "", + "images": [] + }, + "spacethumbnails": { + "icon": "", + "images": [] + }, + "spacious-start-menu": { + "icon": "https://community.chocolatey.org/content/packageimages/spacious-start-menu.1.3.0.0.png", + "images": [] + }, + "spark": { + "icon": "https://community.chocolatey.org/content/packageimages/Spark.3.0.1.png", + "images": [] + }, + "sparkleshare": { + "icon": "https://community.chocolatey.org/content/packageimages/sparkleshare.1.5.0.20161115.png", + "images": [] + }, + "spatial": { + "icon": "", + "images": [] + }, + "spawner": { + "icon": "https://community.chocolatey.org/content/packageimages/spawner.0.2.4.png", + "images": [] + }, + "spcomp": { + "icon": "https://community.chocolatey.org/content/packageimages/spcomp.1.9.6282.png", + "images": [] + }, + "spdx-sbom-generator": { + "icon": "", + "images": [] + }, + "speccy": { + "icon": "https://community.chocolatey.org/content/packageimages/speccy.1.32.774.png", + "images": [ + "https://upload.wikimedia.org/wikipedia/commons/thumb/4/44/Speccy-Screenshot.png/240px-Speccy-Screenshot.png", + "https://cdn.lo4d.com/t/screenshot/800/speccy-7.png" + ] + }, + "specflow": { + "icon": "", + "images": [] + }, + "specialfoldersview": { + "icon": "https://community.chocolatey.org/content/packageimages/specialfoldersview.1.26.png", + "images": [] + }, + "specialk": { + "icon": "https://wiki.special-k.info/misc/sk_logo.png", + "images": [ + "https://wiki.special-k.info/tools/skif_2022.png" + ] + }, + "spectcl": { + "icon": "", + "images": [] + }, + "spectral": { + "icon": "", + "images": [] + }, + "speedcrunch": { + "icon": "https://community.chocolatey.org/content/packageimages/speedcrunch.portable.0.12.png", + "images": [] + }, + "speedfan": { + "icon": "https://community.chocolatey.org/content/packageimages/speedfan.4.52.0.20200321.png", + "images": [] + }, + "speedtest": { + "icon": "", + "images": [] + }, + "speedtest-by-ookla": { + "icon": "https://community.chocolatey.org/content/packageimages/speedtest-by-ookla.1.10.163.001.png", + "images": [] + }, + "speedtest-chrome": { + "icon": "", + "images": [] + }, + "speedtest-cli": { + "icon": "", + "images": [] + }, + "speedyfox": { + "icon": "https://community.chocolatey.org/content/packageimages/speedyfox.2.0.30.png", + "images": [] + }, + "speex": { + "icon": "https://community.chocolatey.org/content/packageimages/speex.1.0.4.png", + "images": [] + }, + "spek": { + "icon": "https://github.com/alexkay/spek/blob/master/data/icons/48x48/spek.png", + "images": [] + }, + "spencer": { + "icon": "https://community.chocolatey.org/content/packageimages/spencer.portable.1.28.png", + "images": [] + }, + "sph": { + "icon": "", + "images": [] + }, + "sphinx": { + "icon": "https://community.chocolatey.org/content/packageimages/sphinx.6.1.3.png", + "images": [] + }, + "sphinxbase": { + "icon": "", + "images": [] + }, + "sphinxtrain": { + "icon": "", + "images": [] + }, + "spice": { + "icon": "", + "images": [] + }, + "spicetify": { + "icon": "https://spicetify.app/images/spicetify.png", + "images": [] + }, + "spicetify-cli": { + "icon": "https://community.chocolatey.org/content/packageimages/spicetify-cli.2.16.2.png", + "images": [] + }, + "spicetify-marketplace": { + "icon": "", + "images": [] + }, + "spicetify-themes": { + "icon": "", + "images": [] + }, + "spicewebdavd": { + "icon": "", + "images": [] + }, + "spiceworks": { + "icon": "", + "images": [] + }, + "spiceworks-agent-shell": { + "icon": "", + "images": [] + }, + "spiceworksnetmon": { + "icon": "", + "images": [] + }, + "spideroak": { + "icon": "", + "images": [] + }, + "spideroakgroups": { + "icon": "", + "images": [] + }, + "spideroakone": { + "icon": "https://community.chocolatey.org/content/packageimages/spideroakone.7.5.1.png", + "images": [] + }, + "spike": { + "icon": "https://community.chocolatey.org/content/packageimages/spike.3.0.11.png", + "images": [] + }, + "spim": { + "icon": "", + "images": [] + }, + "spin": { + "icon": "https://community.chocolatey.org/content/packageimages/spin.6.5.1.png", + "images": [] + }, + "spineomatic": { + "icon": "https://community.chocolatey.org/content/packageimages/spineomatic.8.1.2.20220919.png", + "images": [] + }, + "splashtop-business-access": { + "icon": "", + "images": [] + }, + "splashtopbusiness": { + "icon": "", + "images": [] + }, + "splashtoppersonal": { + "icon": "", + "images": [] + }, + "splashtopstreamer": { + "icon": "", + "images": [] + }, + "splashtopwiredxdisplay": { + "icon": "", + "images": [] + }, + "splashultimate": { + "icon": "", + "images": [] + }, + "splayer": { + "icon": "", + "images": [] + }, + "splayerx": { + "icon": "", + "images": [] + }, + "spleeter-msvc-exe": { + "icon": "", + "images": [] + }, + "spleetergui": { + "icon": "", + "images": [] + }, + "splint": { + "icon": "https://community.chocolatey.org/content/packageimages/splint.3.1.2.png", + "images": [] + }, + "split": { + "icon": "", + "images": [] + }, + "splitcam": { + "icon": "", + "images": [] + }, + "splunk-otel-collector": { + "icon": "https://community.chocolatey.org/content/packageimages/splunk-otel-collector.0.70.0.png", + "images": [] + }, + "splunk-server": { + "icon": "", + "images": [] + }, + "splunkforwarder": { + "icon": "https://community.chocolatey.org/content/packageimages/splunkforwarder.6.2.3.png", + "images": [] + }, + "sponsorblock-for-youtube-chrome": { + "icon": "https://community.chocolatey.org/content/packageimages/sponsorblock-for-youtube-chrome.4.0.4.png", + "images": [] + }, + "spookyview": { + "icon": "", + "images": [] + }, + "spotbugs": { + "icon": "", + "images": [] + }, + "spotiflyer": { + "icon": "", + "images": [] + }, + "spotify": { + "icon": "https://cdn-icons-png.flaticon.com/512/174/174872.png", + "images": [ + "https://i.ibb.co/q5x5C1b/spotify-1.png", + "https://i.ibb.co/XFF0Xp5/spotify-2.png", + "https://i.ibb.co/fx3NjzD/spotify-3.png", + "https://i.ibb.co/p10nvWp/spotify-4.png", + "https://i.ibb.co/hKRcB2B/spotify-5.png", + "https://i.ibb.co/kgzyKdP/spotify-6.png", + "https://i.ibb.co/FHrbs1w/spotify-7.png" + ] + }, + "spotify-qt": { + "icon": "", + "images": [] + }, + "spotify-tui": { + "icon": "https://community.chocolatey.org/content/packageimages/spotify-tui.0.25.0.png", + "images": [] + }, + "spotlight-desktop": { + "icon": "https://community.chocolatey.org/content/packageimages/spotlight-desktop.2.0.1.png", + "images": [] + }, + "spotube": { + "icon": "https://spotube.krtirtho.dev/images/spotube-logo.png", + "images": [] + }, + "spring-boot-cli": { + "icon": "https://community.chocolatey.org/content/packageimages/spring-boot-cli.2.7.3.png", + "images": [] + }, + "springboot": { + "icon": "", + "images": [] + }, + "springtoolsuite": { + "icon": "", + "images": [] + }, + "sprintplusviewer": { + "icon": "", + "images": [] + }, + "sprut-sms-client": { + "icon": "", + "images": [] + }, + "sprut-universal-sprutconfig": { + "icon": "https://community.chocolatey.org/content/packageimages/sprut-universal-sprutconfig.2.04.4000.png", + "images": [] + }, + "sprut-universal-update": { + "icon": "https://community.chocolatey.org/content/packageimages/sprut-universal-update.2.72.60.png", + "images": [] + }, + "spsf": { + "icon": "", + "images": [] + }, + "spx": { + "icon": "https://community.chocolatey.org/content/packageimages/spx.6.8.4.png", + "images": [] + }, + "spybot": { + "icon": "https://community.chocolatey.org/content/packageimages/spybot.2.9.82.0.png", + "images": [] + }, + "spybotantibeacon": { + "icon": "", + "images": [] + }, + "spyder": { + "icon": "", + "images": [] + }, + "spyex": { + "icon": "", + "images": [] + }, + "spyglass": { + "icon": "", + "images": [] + }, + "spytify": { + "icon": "", + "images": [] + }, + "spywareblaster": { + "icon": "https://community.chocolatey.org/content/packageimages/SpywareBlaster.5.6.png", + "images": [] + }, + "sql-server-2016-developer-edition": { + "icon": "", + "images": [] + }, + "sql-server-2017": { + "icon": "", + "images": [] + }, + "sql-server-2017-cumulative-update": { + "icon": "", + "images": [] + }, + "sql-server-2019": { + "icon": "", + "images": [] + }, + "sql-server-2019-cumulative-update": { + "icon": "", + "images": [] + }, + "sql-server-2022": { + "icon": "", + "images": [] + }, + "sql-server-express": { + "icon": "", + "images": [] + }, + "sql-server-express-adv": { + "icon": "", + "images": [] + }, + "sql-server-management-studio": { + "icon": "https://community.chocolatey.org/content/packageimages/sql-server-management-studio.19.0.20200.0.png", + "images": [] + }, + "sql-workbench": { + "icon": "https://community.chocolatey.org/content/packageimages/sql-workbench.127.0.0.png", + "images": [] + }, + "sql2008-clrtypes": { + "icon": "https://community.chocolatey.org/content/packageimages/SQL2008.ClrTypes.10.00.2531.00.png", + "images": [] + }, + "sql2008-cmdline": { + "icon": "https://community.chocolatey.org/content/packageimages/SQL2008.CmdLine.10.00.2531.00.png", + "images": [] + }, + "sql2008-powershell": { + "icon": "https://community.chocolatey.org/content/packageimages/SQL2008.Powershell.10.00.2531.00.png", + "images": [] + }, + "sql2008-smo": { + "icon": "https://community.chocolatey.org/content/packageimages/SQL2008.SMO.10.00.2531.01.png", + "images": [] + }, + "sql2008r2-clrtypes": { + "icon": "https://community.chocolatey.org/content/packageimages/SQL2008R2.ClrTypes.10.50.1600.1.png", + "images": [] + }, + "sql2008r2-powershell": { + "icon": "https://community.chocolatey.org/content/packageimages/SQL2008R2.PowerShell.10.50.1600.1.png", + "images": [] + }, + "sql2008r2-smo": { + "icon": "https://community.chocolatey.org/content/packageimages/SQL2008R2.SMO.10.50.1600.1.png", + "images": [] + }, + "sql2012-cmdline": { + "icon": "", + "images": [] + }, + "sql2012-dac": { + "icon": "", + "images": [] + }, + "sql2012-dacframework": { + "icon": "https://community.chocolatey.org/content/packageimages/SQL2012.DACFramework.11.1.2861.0.png", + "images": [] + }, + "sql2012-localdb": { + "icon": "", + "images": [] + }, + "sql2012-nativeclient": { + "icon": "https://community.chocolatey.org/content/packageimages/SQL2012.NativeClient.9911.0.7001.0.png", + "images": [] + }, + "sql2012-powershell": { + "icon": "https://community.chocolatey.org/content/packageimages/SQL2012.PowerShell.11.0.2100.61.png", + "images": [] + }, + "sql2012-smo": { + "icon": "https://community.chocolatey.org/content/packageimages/SQL2012.SMO.11.0.2100.61.png", + "images": [] + }, + "sql2012-sqldom": { + "icon": "https://community.chocolatey.org/content/packageimages/SQL2012.SQLDom.11.1.2825.1.png", + "images": [] + }, + "sql2012asamo": { + "icon": "", + "images": [] + }, + "sql2012t-sql-scriptdom": { + "icon": "", + "images": [] + }, + "sql2014-clrtypes": { + "icon": "https://community.chocolatey.org/content/packageimages/SQL2014.ClrTypes.12.2.5000.0.png", + "images": [] + }, + "sql2014-dacframework": { + "icon": "", + "images": [] + }, + "sql2014-powershell": { + "icon": "https://community.chocolatey.org/content/packageimages/SQL2014-powershell.12.0.2000.8.png", + "images": [] + }, + "sql2014-smo": { + "icon": "https://community.chocolatey.org/content/packageimages/SQL2014.SMO.12.2.5000.0.png", + "images": [] + }, + "sql2014-sqldom": { + "icon": "", + "images": [] + }, + "sql2016-clrtypes": { + "icon": "", + "images": [] + }, + "sql2016-smo": { + "icon": "", + "images": [] + }, + "sql2017-dacframework": { + "icon": "", + "images": [] + }, + "sqlanywhereclient": { + "icon": "https://community.chocolatey.org/content/packageimages/sqlanywhereclient.12.0.1.png", + "images": [] + }, + "sqlbench": { + "icon": "", + "images": [] + }, + "sqlbpa-2008": { + "icon": "", + "images": [] + }, + "sqlbpa-2012": { + "icon": "https://community.chocolatey.org/content/packageimages/sqlbpa.2012.12.0.0.1.png", + "images": [] + }, + "sqlcl": { + "icon": "", + "images": [] + }, + "sqlcmd": { + "icon": "", + "images": [] + }, + "sqldef": { + "icon": "", + "images": [] + }, + "sqldiagmanager": { + "icon": "", + "images": [] + }, + "sqlectron-gui": { + "icon": "", + "images": [] + }, + "sqlgrep": { + "icon": "", + "images": [] + }, + "sqlio": { + "icon": "https://community.chocolatey.org/content/packageimages/sqlio.1.0.png", + "images": [] + }, + "sqlite": { + "icon": "", + "images": [] + }, + "sqlite-analyzer": { + "icon": "https://community.chocolatey.org/content/packageimages/sqlite.analyzer.3.41.0.png", + "images": [] + }, + "sqlite-shell": { + "icon": "https://community.chocolatey.org/content/packageimages/sqlite.shell.3.41.0.png", + "images": [] + }, + "sqlite-studio": { + "icon": "https://community.chocolatey.org/content/packageimages/sqlite-studio.portable.3.4.3.png", + "images": [] + }, + "sqliteadmin": { + "icon": "", + "images": [] + }, + "sqlitebrowser": { + "icon": "", + "images": [] + }, + "sqlitepsprovider": { + "icon": "", + "images": [] + }, + "sqlitespy": { + "icon": "", + "images": [] + }, + "sqlitestudio": { + "icon": "https://community.chocolatey.org/content/packageimages/sqlitestudio.3.4.3.png", + "images": [] + }, + "sqljdbc": { + "icon": "https://community.chocolatey.org/content/packageimages/sqljdbc.11.2.0.0.png", + "images": [] + }, + "sqlkerberosconfigmgr": { + "icon": "https://community.chocolatey.org/content/packageimages/SqlKerberosConfigMgr.3.0.0.png", + "images": [] + }, + "sqllocaldb": { + "icon": "", + "images": [] + }, + "sqllocaldb2016": { + "icon": "", + "images": [] + }, + "sqlmaintenancesolution": { + "icon": "", + "images": [] + }, + "sqlnexus": { + "icon": "", + "images": [] + }, + "sqlnotebook": { + "icon": "https://community.chocolatey.org/content/packageimages/sqlnotebook.1.2.1.png", + "images": [] + }, + "sqlpackage": { + "icon": "", + "images": [] + }, + "sqlsearch": { + "icon": "https://community.chocolatey.org/content/packageimages/SqlSearch.2019.12.19.png", + "images": [] + }, + "sqlsentryplanexplorer": { + "icon": "https://community.chocolatey.org/content/packageimages/SQLSentryPlanExplorer.2.0.0.2.png", + "images": [] + }, + "sqlserver-2019-developer": { + "icon": "", + "images": [] + }, + "sqlserver-2019-express": { + "icon": "", + "images": [] + }, + "sqlserver-odbcdriver": { + "icon": "", + "images": [] + }, + "sqlserver2012express": { + "icon": "", + "images": [] + }, + "sqlserver2012nativeclient": { + "icon": "", + "images": [] + }, + "sqlserver2014express": { + "icon": "", + "images": [] + }, + "sqlserverdatatools-2012": { + "icon": "", + "images": [] + }, + "sqlserverdatatools2012": { + "icon": "", + "images": [] + }, + "sqlserverexpress": { + "icon": "https://community.chocolatey.org/content/packageimages/SqlServerExpress.10.0.0.20130503.png", + "images": [] + }, + "sqlservermanagementstudio": { + "icon": "", + "images": [] + }, + "sqltoolbelt": { + "icon": "https://community.chocolatey.org/content/packageimages/SqlToolbelt.2023.02.22.png", + "images": [] + }, + "sqlyog": { + "icon": "https://community.chocolatey.org/content/packageimages/sqlyog.13.1.6.20200807.png", + "images": [] + }, + "sqlyog-community": { + "icon": "", + "images": [] + }, + "sqlyogcommunity": { + "icon": "", + "images": [] + }, + "sqmixpad": { + "icon": "", + "images": [] + }, + "squalr": { + "icon": "", + "images": [] + }, + "squashfs": { + "icon": "", + "images": [] + }, + "squashfs-tools": { + "icon": "", + "images": [] + }, + "squid": { + "icon": "https://community.chocolatey.org/content/packageimages/squid.4.14.png", + "images": [] + }, + "squiggle": { + "icon": "https://community.chocolatey.org/content/packageimages/squiggle.3.4.4.0020180331.png", + "images": [] + }, + "squirrel-sql": { + "icon": "", + "images": [] + }, + "srcclr": { + "icon": "https://community.chocolatey.org/content/packageimages/srcclr.3.8.21.png", + "images": [] + }, + "srcdemo2": { + "icon": "https://community.chocolatey.org/content/packageimages/srcdemo2.2012.04.07.png", + "images": [] + }, + "srecord": { + "icon": "", + "images": [] + }, + "srlua": { + "icon": "", + "images": [] + }, + "srtalign": { + "icon": "", + "images": [] + }, + "srvany-ng": { + "icon": "", + "images": [] + }, + "srvman": { + "icon": "", + "images": [] + }, + "srwareiron": { + "icon": "https://community.chocolatey.org/content/packageimages/srwareiron.portable.109.0.5550.000.png", + "images": [] + }, + "ssd-z": { + "icon": "https://community.chocolatey.org/content/packageimages/ssd-z.portable.16.09.09.png", + "images": [] + }, + "ssdt12": { + "icon": "https://community.chocolatey.org/content/packageimages/ssdt12.12.0.50512.0.png", + "images": [] + }, + "ssdtbi-vs2012": { + "icon": "", + "images": [] + }, + "ssh-agent-wsl": { + "icon": "", + "images": [] + }, + "ssh-chat": { + "icon": "", + "images": [] + }, + "ssh-client": { + "icon": "https://i.postimg.cc/28K8Xzkv/Icon.png", + "images": [ + "https://i.postimg.cc/fRcjfgsG/image.png", + "https://i.postimg.cc/Sxht49xp/image.png", + "https://i.postimg.cc/g2Ht20xL/image.png", + "https://i.postimg.cc/FzSD5FtR/image.png" + ] + }, + "ssh-copy-id": { + "icon": "", + "images": [] + }, + "ssh-server": { + "icon": "", + "images": [ + "https://i.ibb.co/9M8JH3X/Image.png", + "https://i.ibb.co/bjH7g8mr/Image.png", + "https://i.ibb.co/xtpk799R/Image.png" + ] + }, + "sshfs-win": { + "icon": "", + "images": [] + }, + "sshfs-win-manager": { + "icon": "", + "images": [] + }, + "sshrunas": { + "icon": "https://community.chocolatey.org/content/packageimages/sshrunas.3.0.0.png", + "images": [] + }, + "sshs": { + "icon": "", + "images": [] + }, + "ssis-vs2019": { + "icon": "https://community.chocolatey.org/content/packageimages/ssis-vs2019.4.4.2.png", + "images": [] + }, + "sslscan": { + "icon": "", + "images": [] + }, + "sslverifier": { + "icon": "", + "images": [] + }, + "ssms": { + "icon": "", + "images": [] + }, + "ssoperations": { + "icon": "https://community.chocolatey.org/content/packageimages/ssoperations.1.5.4.png", + "images": [] + }, + "ssrs": { + "icon": "https://community.chocolatey.org/content/packageimages/ssrs.14.0.600.1669.png", + "images": [] + }, + "ssrs-2019": { + "icon": "https://community.chocolatey.org/content/packageimages/ssrs-2019.15.0.7765.17516.png", + "images": [] + }, + "stack": { + "icon": "", + "images": [] + }, + "stackexchange-dnscontrol": { + "icon": "", + "images": [] + }, + "stackless": { + "icon": "", + "images": [] + }, + "stacks": { + "icon": "", + "images": [] + }, + "stakecubecoinwallet": { + "icon": "https://community.chocolatey.org/content/packageimages/stakecubecoinwallet.3.3.1.png", + "images": [] + }, + "stakecubecoinwallet-bootstrap": { + "icon": "https://community.chocolatey.org/content/packageimages/stakecubecoinwallet-bootstrap.3.1.0.20211012.png", + "images": [] + }, + "standardnotes": { + "icon": "", + "images": [] + }, + "stanlys-terminal": { + "icon": "", + "images": [] + }, + "starborne": { + "icon": "", + "images": [] + }, + "starconflict": { + "icon": "", + "images": [] + }, + "stardock-fences": { + "icon": "https://community.chocolatey.org/content/packageimages/stardock-fences.4.03.png", + "images": [] + }, + "starfaceapp": { + "icon": "", + "images": [] + }, + "starfaceucc": { + "icon": "", + "images": [] + }, + "starfaceucc-beta": { + "icon": "", + "images": [] + }, + "starleaf": { + "icon": "https://community.chocolatey.org/content/packageimages/starleaf.4.4.26.0.png", + "images": [] + }, + "starship": { + "icon": "https://raw.githubusercontent.com/starship/starship/master/media/icon.png", + "images": [] + }, + "start": { + "icon": "", + "images": [] + }, + "start10": { + "icon": "https://community.chocolatey.org/content/packageimages/start10.1.97.png", + "images": [] + }, + "start11": { + "icon": "https://i.postimg.cc/prC8r9DL/Start-All-Back.png", + "images": [] + }, + "startallback": { + "icon": "https://i.postimg.cc/prC8r9DL/Start-All-Back.png", + "images": [ + "https://i.postimg.cc/Vv8BdQpD/image.png", + "https://i.postimg.cc/MHm0B38x/image.png", + "https://i.postimg.cc/J7N5S0Hg/image.png", + "https://i.postimg.cc/0290vvpN/image.png" + ] + }, + "startbluescreen": { + "icon": "https://community.chocolatey.org/content/packageimages/startbluescreen.1.00.png", + "images": [] + }, + "startisback": { + "icon": "https://www.megaleechers.com/storage/StartIsBack-Icon.png", + "images": [] + }, + "startisbackplus": { + "icon": "", + "images": [] + }, + "startmenu8": { + "icon": "https://community.chocolatey.org/content/packageimages/startmenu8.1.6.0.20141130.png", + "images": [] + }, + "startmenureviver": { + "icon": "https://community.chocolatey.org/content/packageimages/startmenureviver.2.5.0.18.png", + "images": [] + }, + "startrekfleetcommand": { + "icon": "", + "images": [] + }, + "startuplist": { + "icon": "", + "images": [] + }, + "startupmanager": { + "icon": "https://i.postimg.cc/QdTZ5skM/Startup-Manager-icon.png", + "images": [ + "https://i.postimg.cc/TPDhNZV7/Screenshot-1.png", + "https://i.postimg.cc/RhMFFhjy/Screenshot-2.png", + "https://i.postimg.cc/63Vqtn1C/Screenshot-3.png", + "https://i.postimg.cc/BZgbz5F0/Screenshot-4.png", + "https://i.postimg.cc/76rhFmXx/Screenshot-5.png", + "https://i.postimg.cc/prqdnxvT/Screenshot-6.png" + ] + }, + "staruml": { + "icon": "https://i.postimg.cc/DyQGRZNr/image.png", + "images": [ + "https://i.postimg.cc/ZKmBPmqC/image.png", + "https://i.postimg.cc/FHWYQJVL/image.png" + ] + }, + "staruml2": { + "icon": "https://i.postimg.cc/DyQGRZNr/image.png", + "images": [ + "https://i.postimg.cc/ZKmBPmqC/image.png", + "https://i.postimg.cc/FHWYQJVL/image.png" + ] + }, + "staruml3": { + "icon": "https://i.postimg.cc/DyQGRZNr/image.png", + "images": [ + "https://i.postimg.cc/ZKmBPmqC/image.png", + "https://i.postimg.cc/FHWYQJVL/image.png" + ] + }, + "stash": { + "icon": "", + "images": [] + }, + "static-web-server": { + "icon": "", + "images": [] + }, + "staticcheck": { + "icon": "", + "images": [] + }, + "station": { + "icon": "", + "images": [] + }, + "statlookserver": { + "icon": "", + "images": [] + }, + "statping": { + "icon": "", + "images": [] + }, + "status": { + "icon": "", + "images": [] + }, + "staxrip": { + "icon": "https://community.chocolatey.org/content/packageimages/staxrip.2.13.0.png", + "images": [] + }, + "stay-hydrated": { + "icon": "", + "images": [] + }, + "stc": { + "icon": "", + "images": [] + }, + "stdiscosrv": { + "icon": "", + "images": [] + }, + "stduviewer": { + "icon": "", + "images": [] + }, + "steam": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/8/83/Steam_icon_logo.svg/512px-Steam_icon_logo.svg.png", + "images": [ + "https://i.postimg.cc/dV3DDVx5/steam.png", + "https://i.postimg.cc/7ZRhzyvw/image.png" + ] + }, + "steam-322170": { + "icon": "https://upload.wikimedia.org/wikipedia/en/thumb/4/4d/Logo_of_Geometry_Dash.svg/1200px-Logo_of_Geometry_Dash.svg.png", + "images": [] + }, + "steam-32440": { + "icon": "https://cdn2.steamgriddb.com/icon/0b70b95deb2dfeeb11aa462c44169894.png", + "images": [] + }, + "steam-32510": { + "icon": "https://cdn2.steamgriddb.com/icon/013d407166ec4fa56eb1e1f8cbe183b9/8/32x32.png", + "images": [] + }, + "steam-920210": { + "icon": "https://cdn2.steamgriddb.com/icon/b156769842d5235767f769b5c8617399/32/32x32.png", + "images": [] + }, + "steam-cleaner": { + "icon": "https://community.chocolatey.org/content/packageimages/steam-cleaner.2.4.png", + "images": [] + }, + "steam-client": { + "icon": "https://community.chocolatey.org/content/packageimages/steam-client.2.10.91.91.png", + "images": [] + }, + "steam-library-manager": { + "icon": "", + "images": [] + }, + "steam-rom-manager": { + "icon": "https://i.postimg.cc/qRCTHxrb/steamrommanager_256.png", + "images": [] + }, + "steamachievementmanager": { + "icon": "https://community.chocolatey.org/content/packageimages/steamachievementmanager.7.0.25.png", + "images": [] + }, + "steamchina": { + "icon": "", + "images": [] + }, + "steamcmd": { + "icon": "", + "images": [] + }, + "steascree": { + "icon": "https://community.chocolatey.org/content/packageimages/steascree.1.5.4.png", + "images": [] + }, + "steelseries-engine": { + "icon": "https://community.chocolatey.org/content/packageimages/steelseries-engine.26.0.0.png", + "images": [] + }, + "steelseriesengine": { + "icon": "", + "images": [] + }, + "steghide": { + "icon": "", + "images": [] + }, + "stele": { + "icon": "", + "images": [] + }, + "stellar": { + "icon": "https://community.chocolatey.org/content/packageimages/stellar.3.6.png", + "images": [] + }, + "stellarium": { + "icon": "https://img.icons8.com/color/480/stellarium-logo.png", + "images": [] + }, + "stellarplayer": { + "icon": "", + "images": [] + }, + "step": { + "icon": "", + "images": [] + }, + "step-ca": { + "icon": "", + "images": [] + }, + "stepmania": { + "icon": "", + "images": [] + }, + "stern": { + "icon": "https://community.chocolatey.org/content/packageimages/stern.1.21.0.png", + "images": [] + }, + "stevedore": { + "icon": "https://community.chocolatey.org/content/packageimages/stevedore.0.11.0.png", + "images": [] + }, + "stexbar": { + "icon": "", + "images": [] + }, + "stickies": { + "icon": "https://community.chocolatey.org/content/packageimages/Stickies.10.1.3.png", + "images": [] + }, + "stigviewer": { + "icon": "", + "images": [] + }, + "stinker": { + "icon": "", + "images": [] + }, + "stirling-jp": { + "icon": "https://community.chocolatey.org/content/packageimages/stirling-jp.1.31.png", + "images": [] + }, + "stl-thumb": { + "icon": "", + "images": [] + }, + "stlink": { + "icon": "", + "images": [] + }, + "stone-soup": { + "icon": "", + "images": [] + }, + "stone-soup-tiles": { + "icon": "", + "images": [] + }, + "stools": { + "icon": "", + "images": [] + }, + "stopawu": { + "icon": "", + "images": [] + }, + "stoplight-prism": { + "icon": "", + "images": [] + }, + "stoplight-studio": { + "icon": "", + "images": [] + }, + "storj": { + "icon": "", + "images": [] + }, + "storjshare": { + "icon": "https://community.chocolatey.org/content/packageimages/storjshare.7.3.4.png", + "images": [] + }, + "stracent": { + "icon": "https://community.chocolatey.org/content/packageimages/StraceNT.0.8.png", + "images": [] + }, + "stratos": { + "icon": "", + "images": [] + }, + "strawberry": { + "icon": "", + "images": [] + }, + "strawberrymusicplayer": { + "icon": "https://community.chocolatey.org/content/packageimages/strawberrymusicplayer.1.0.14.png", + "images": [] + }, + "strawberryperl": { + "icon": "https://community.chocolatey.org/content/packageimages/StrawberryPerl.5.32.1.1.png", + "images": [] + }, + "streambaby": { + "icon": "", + "images": [] + }, + "streambop": { + "icon": "", + "images": [] + }, + "streamdeck": { + "icon": "https://i.postimg.cc/4NbKFdts/streamdeck_202512_128.png", + "images": [] + }, + "streamer": { + "icon": "https://unigeticons.meowcat285.com/VirtualDesktop.png", + "images": [] + }, + "streaming-video-downloader": { + "icon": "https://community.chocolatey.org/content/packageimages/streaming-video-downloader.7.0.0.png", + "images": [] + }, + "streamingtool": { + "icon": "", + "images": [] + }, + "streamingvideodownloader": { + "icon": "", + "images": [] + }, + "streamlabs": { + "icon": "", + "images": [] + }, + "streamlabs-chatbot": { + "icon": "", + "images": [] + }, + "streamlabs-obs": { + "icon": "https://community.chocolatey.org/content/packageimages/streamlabs-obs.1.12.5.png", + "images": [] + }, + "streamlabsobs": { + "icon": "", + "images": [] + }, + "streamlink": { + "icon": "", + "images": [] + }, + "streamlink-twitch-gui": { + "icon": "https://community.chocolatey.org/content/packageimages/streamlink-twitch-gui.2.2.0.png", + "images": [] + }, + "streamlink-twitchgui": { + "icon": "", + "images": [] + }, + "streams": { + "icon": "", + "images": [] + }, + "streamwhatyouhear": { + "icon": "https://community.chocolatey.org/content/packageimages/streamwhatyouhear.1.5.0.png", + "images": [] + }, + "streamwriter": { + "icon": "https://community.chocolatey.org/content/packageimages/streamwriter.5.5.1.1.png", + "images": [] + }, + "stremio": { + "icon": "https://community.chocolatey.org/content/packageimages/stremio.4.4.159.png", + "images": [] + }, + "stressor": { + "icon": "", + "images": [] + }, + "stretchly": { + "icon": "https://community.chocolatey.org/content/packageimages/stretchly.1.13.1.png", + "images": [] + }, + "striata-reader": { + "icon": "https://community.chocolatey.org/content/packageimages/striata-reader.2.31.2.0.png", + "images": [] + }, + "stride": { + "icon": "", + "images": [] + }, + "strimio": { + "icon": "", + "images": [] + }, + "string-replicator": { + "icon": "https://community.chocolatey.org/content/packageimages/string-replicator.1.0.0.0.png", + "images": [] + }, + "strings": { + "icon": "", + "images": [] + }, + "stripe-cli": { + "icon": "", + "images": [] + }, + "strokesplus": { + "icon": "https://community.chocolatey.org/content/packageimages/strokesplus.install.2.8.6.401.png", + "images": [] + }, + "strokesplus-net": { + "icon": "", + "images": [] + }, + "structcompiler": { + "icon": "", + "images": [] + }, + "structurizr-cli": { + "icon": "", + "images": [] + }, + "sts": { + "icon": "", + "images": [] + }, + "stubby": { + "icon": "https://community.chocolatey.org/content/packageimages/stubby.0.4.0.0.png", + "images": [] + }, + "stubby4net": { + "icon": "", + "images": [] + }, + "stuctured-storage-explorer": { + "icon": "https://community.chocolatey.org/content/packageimages/stuctured-storage-explorer.2.2.1.9.png", + "images": [] + }, + "studio": { + "icon": "https://community.chocolatey.org/content/packageimages/studio.2.23.2.1.png", + "images": [] + }, + "studio3t": { + "icon": "https://community.chocolatey.org/content/packageimages/studio3t.2023.1.1.png", + "images": [ + "https://i.ibb.co/TnGC4QP/Image.png", + "https://i.ibb.co/CpvbCrLC/image.png" + ] + }, + "studiorack": { + "icon": "", + "images": [] + }, + "studiotrans": { + "icon": "", + "images": [] + }, + "stunnel": { + "icon": "https://community.chocolatey.org/content/packageimages/stunnel.5.68.png", + "images": [] + }, + "stunnel-beta": { + "icon": "", + "images": [] + }, + "stunnel-msspi": { + "icon": "https://community.chocolatey.org/content/packageimages/stunnel-msspi.5.56.0.155.png", + "images": [] + }, + "stylecop": { + "icon": "https://community.chocolatey.org/content/packageimages/stylecop.4.7.55.0.png", + "images": [] + }, + "stylecop-vsix": { + "icon": "https://community.chocolatey.org/content/packageimages/stylecop-vsix.5.0.6419.20180518.png", + "images": [] + }, + "stylua": { + "icon": "", + "images": [] + }, + "suanpan": { + "icon": "", + "images": [] + }, + "sublime-merge": { + "icon": "https://www.sublimehq.com/images/sublime_merge.png", + "images": [ + "https://www.sublimemerge.com/images/contents_view.png", + "https://www.sublimetext.com/screenshots/merge/staging.png" + ] + }, + "sublime-text": { + "icon": "https://www.sublimehq.com/images/sublime_text.png", + "images": [ + "https://www.sublimetext.com/screenshots/sublime_text_4.png", + "https://forum.sublimetext.com/uploads/default/original/3X/b/8/b85894e3b2489204f53733ec5952176749b3481d.png" + ] + }, + "sublimemerge": { + "icon": "https://www.sublimehq.com/images/sublime_merge.png", + "images": [ + "https://www.sublimemerge.com/images/contents_view.png", + "https://www.sublimetext.com/screenshots/merge/staging.png" + ] + }, + "sublimemerge-dev": { + "icon": "", + "images": [] + }, + "sublimetext": { + "icon": "https://www.sublimehq.com/images/sublime_text.png", + "images": [ + "https://www.sublimetext.com/screenshots/sublime_text_4.png", + "https://forum.sublimetext.com/uploads/default/original/3X/b/8/b85894e3b2489204f53733ec5952176749b3481d.png" + ] + }, + "sublimetext-3": { + "icon": "https://www.sublimehq.com/images/sublime_text.png", + "images": [ + "https://www.sublimetext.com/screenshots/3.0/windows.png", + "https://www.sublimetext.com/screenshots/3.0/linux@2x.png", + "https://www.sublimetext.com/screenshots/3.0/osx.png" + ] + }, + "sublimetext-4": { + "icon": "https://www.sublimehq.com/images/sublime_text.png", + "images": [ + "https://www.sublimetext.com/screenshots/sublime_text_4.png", + "https://forum.sublimetext.com/uploads/default/original/3X/b/8/b85894e3b2489204f53733ec5952176749b3481d.png" + ] + }, + "sublimetext2": { + "icon": "https://community.chocolatey.org/content/packageimages/sublimetext2.2.0.2.2224.png", + "images": [ + "https://www.sublimetext.com/screenshots/alpha_goto_anything2_large.png", + "https://www.sublimetext.com/screenshots/new_theme_large.png" + ] + }, + "sublimetext2-packagecontrol": { + "icon": "https://community.chocolatey.org/content/packageimages/SublimeText2.PackageControl.1.6.3.png", + "images": [] + }, + "sublimetext2-powershellalias": { + "icon": "https://community.chocolatey.org/content/packageimages/SublimeText2.PowershellAlias.0.1.0.png", + "images": [] + }, + "sublimetext3": { + "icon": "https://community.chocolatey.org/content/packageimages/SublimeText3.3.2.2.png", + "images": [ + "https://www.sublimetext.com/screenshots/3.0/windows.png", + "https://www.sublimetext.com/screenshots/3.0/linux@2x.png", + "https://www.sublimetext.com/screenshots/3.0/osx.png" + ] + }, + "sublimetext3-app": { + "icon": "https://community.chocolatey.org/content/packageimages/SublimeText3.app.3.0.0.3065.png", + "images": [] + }, + "sublimetext3-packagecontrol": { + "icon": "https://community.chocolatey.org/content/packageimages/SublimeText3.PackageControl.2.0.0.20140915.png", + "images": [] + }, + "sublimetext3-powershellalias": { + "icon": "https://community.chocolatey.org/content/packageimages/SublimeText3.PowershellAlias.0.1.0.png", + "images": [] + }, + "subordination": { + "icon": "", + "images": [] + }, + "substanceplayer": { + "icon": "", + "images": [] + }, + "subsurface": { + "icon": "", + "images": [] + }, + "subsync": { + "icon": "", + "images": [] + }, + "subtitleedit": { + "icon": "https://community.chocolatey.org/content/packageimages/subtitleedit.3.6.11.20230215.png", + "images": [] + }, + "subtitler": { + "icon": "", + "images": [] + }, + "subtitleworkshop": { + "icon": "https://community.chocolatey.org/content/packageimages/subtitleworkshop.6.0.131121.png", + "images": [] + }, + "subversion": { + "icon": "", + "images": [] + }, + "sudo": { + "icon": "", + "images": [] + }, + "sugarsync": { + "icon": "https://community.chocolatey.org/content/packageimages/sugarsync.1.9.71.1.png", + "images": [] + }, + "suggestedextensions": { + "icon": "", + "images": [] + }, + "sumatrapdf": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/7/7b/Sumatra_PDF_logo.png", + "images": [ + "https://i.postimg.cc/0yfnDCYt/pdf.png" + ] + }, + "sumatrapdf-commandline": { + "icon": "", + "images": [] + }, + "sumerics": { + "icon": "https://community.chocolatey.org/content/packageimages/Sumerics.2.0.0.0.png", + "images": [] + }, + "summerfun": { + "icon": "", + "images": [] + }, + "sumo": { + "icon": "https://www.kcsoftwares.com/images/SUMo_icon.png", + "images": [ + "https://www.kcsoftwares.com/images/SUMo_screen.png" + ] + }, + "sundance": { + "icon": "", + "images": [] + }, + "sundial": { + "icon": "", + "images": [] + }, + "sunset-screen": { + "icon": "https://community.chocolatey.org/content/packageimages/sunset-screen.1.50.png", + "images": [] + }, + "sunsetscreen": { + "icon": "", + "images": [] + }, + "sunshine": { + "icon": "https://community.chocolatey.org/content/packageimages/sunshine.0.18.3.png", + "images": [] + }, + "sunshine-pre": { + "icon": "https://raw.githubusercontent.com/LizardByte/Sunshine/master/sunshine.png", + "images": [] + }, + "supd2": { + "icon": "https://community.chocolatey.org/content/packageimages/supd2.2.0.0.png", + "images": [] + }, + "super-mario-bros-java": { + "icon": "https://community.chocolatey.org/content/packageimages/super-mario-bros-java.2017.05.06.png", + "images": [] + }, + "super-productivity": { + "icon": "https://i.imgur.com/UnvhxDl.png", + "images": [ + "https://i.imgur.com/YUDVM3V.png", + "https://i.imgur.com/RMIK4fd.png" + ] + }, + "superantispyware": { + "icon": "https://community.chocolatey.org/content/packageimages/superantispyware.10.0.1246.png", + "images": [] + }, + "superburgertime": { + "icon": "", + "images": [] + }, + "supercollider": { + "icon": "", + "images": [] + }, + "supercopier": { + "icon": "", + "images": [] + }, + "superdelete": { + "icon": "", + "images": [] + }, + "superf4": { + "icon": "https://community.chocolatey.org/content/packageimages/superf4.1.4.0.png", + "images": [] + }, + "superfamiconv": { + "icon": "https://community.chocolatey.org/content/packageimages/superfamiconv.0.9.2.png", + "images": [] + }, + "supernovaplayer": { + "icon": "", + "images": [] + }, + "superposition-benchmark": { + "icon": "https://community.chocolatey.org/content/packageimages/superposition-benchmark.1.1.png", + "images": [] + }, + "superpositionbenchmark": { + "icon": "", + "images": [] + }, + "superpowers-app": { + "icon": "", + "images": [] + }, + "superproductivity": { + "icon": "https://i.imgur.com/UnvhxDl.png", + "images": [ + "https://i.imgur.com/YUDVM3V.png", + "https://i.imgur.com/RMIK4fd.png" + ] + }, + "superputty": { + "icon": "https://community.chocolatey.org/content/packageimages/superputty.portable.1.5.0.0.png", + "images": [] + }, + "superscript": { + "icon": "", + "images": [] + }, + "superslicer": { + "icon": "https://community.chocolatey.org/content/packageimages/superslicer.2.4.58.5.png", + "images": [] + }, + "supertux": { + "icon": "", + "images": [] + }, + "supertuxkart": { + "icon": "https://community.chocolatey.org/content/packageimages/supertuxkart.1.4.png", + "images": [] + }, + "supportassist": { + "icon": "https://community.chocolatey.org/content/packageimages/supportassist.3.13.0.236.png", + "images": [] + }, + "supraball": { + "icon": "https://community.chocolatey.org/content/packageimages/supraball.0.2.10.1.png", + "images": [] + }, + "surfshark": { + "icon": "https://asset.brandfetch.io/idInXa2Zcj/idM5I-Fk7d.png", + "images": [ + "https://surfshark.com/website/_next/public/press/assets/images/downloads/product-screenshots/pc/win-app.png", + "https://surfshark.com/website/_next/public/press/assets/images/downloads/product-screenshots/others/multiple-devices.png" + ] + }, + "surge": { + "icon": "", + "images": [] + }, + "surgext": { + "icon": "", + "images": [] + }, + "suricata": { + "icon": "https://community.chocolatey.org/content/packageimages/suricata.2.0.2.20140625.png", + "images": [] + }, + "surrealdb": { + "icon": "", + "images": [] + }, + "sushi": { + "icon": "", + "images": [] + }, + "suside": { + "icon": "", + "images": [] + }, + "suwatchapp": { + "icon": "", + "images": [] + }, + "svcat": { + "icon": "", + "images": [] + }, + "svchost-lookup-tool": { + "icon": "", + "images": [] + }, + "svchost-process-analyzer": { + "icon": "https://community.chocolatey.org/content/packageimages/svchost-process-analyzer.portable.1.0.20161106.png", + "images": [] + }, + "svg-explorer-extension": { + "icon": "", + "images": [] + }, + "svgcleaner": { + "icon": "https://community.chocolatey.org/content/packageimages/svgcleaner.0.9.5.png", + "images": [] + }, + "svgo-gui": { + "icon": "", + "images": [] + }, + "svn": { + "icon": "", + "images": [] + }, + "svtplay-dl": { + "icon": "", + "images": [] + }, + "swanide": { + "icon": "", + "images": [] + }, + "sweet-home-3d": { + "icon": "https://community.chocolatey.org/content/packageimages/sweet-home-3d.7.0.2.png", + "images": [] + }, + "sweethome3d": { + "icon": "", + "images": [] + }, + "swftools": { + "icon": "https://community.chocolatey.org/content/packageimages/swftools.0.9.0.20220414.png", + "images": [] + }, + "swi-prolog": { + "icon": "https://community.chocolatey.org/content/packageimages/SWI-Prolog.9.0.4.1.png", + "images": [] + }, + "swift": { + "icon": "", + "images": [] + }, + "swift-im": { + "icon": "https://community.chocolatey.org/content/packageimages/swift-im.4.0.2.20190627.png", + "images": [] + }, + "swifty": { + "icon": "", + "images": [] + }, + "swig": { + "icon": "", + "images": [] + }, + "swipl": { + "icon": "", + "images": [] + }, + "swish": { + "icon": "", + "images": [] + }, + "swissfileknife": { + "icon": "https://community.chocolatey.org/content/packageimages/SwissFileKnife.1.9.8.2.png", + "images": [] + }, + "switch": { + "icon": "", + "images": [] + }, + "switcheroo": { + "icon": "https://community.chocolatey.org/content/packageimages/switcheroo.install.0.9.2.111.png", + "images": [] + }, + "switchhosts": { + "icon": "", + "images": [] + }, + "switchoff": { + "icon": "https://www.softwarecrew.com/wp-content/uploads/2013/03/AiryTecSwitchOffLogo200-175.png", + "images": [ + "https://www.airytec.com/images/en/screenshots/schedule.png", + "https://www.airytec.com/images/en/screenshots/one-click.png", + "https://www.airytec.com/images/en/screenshots/web-interface.png", + "https://www.airytec.com/images/en/screenshots/notifyicon.png" + ] + }, + "swmm": { + "icon": "https://community.chocolatey.org/content/packageimages/swmm.5.2.2.png", + "images": [] + }, + "swyh": { + "icon": "https://community.chocolatey.org/content/packageimages/swyh.1.5.0.png", + "images": [] + }, + "syft": { + "icon": "", + "images": [] + }, + "sylpheed": { + "icon": "https://community.chocolatey.org/content/packageimages/sylpheed.portable.3.7.0.png", + "images": [] + }, + "symbolsource-demoapplication": { + "icon": "", + "images": [] + }, + "symbolsource-integration-nuget-commandline": { + "icon": "", + "images": [] + }, + "symflowercli": { + "icon": "", + "images": [] + }, + "symfony-cli": { + "icon": "", + "images": [] + }, + "symphytum": { + "icon": "", + "images": [] + }, + "sync": { + "icon": "", + "images": [] + }, + "syncany-cli": { + "icon": "", + "images": [] + }, + "syncback": { + "icon": "", + "images": [] + }, + "syncbackfree": { + "icon": "https://www.2brightsparks.com/assets/logo-blue-288x288-trans.png", + "images": [] + }, + "syncbackpro": { + "icon": "https://www.2brightsparks.com/assets/logo-blue-288x288-trans.png", + "images": [] + }, + "syncbackse": { + "icon": "https://www.2brightsparks.com/assets/logo-blue-288x288-trans.png", + "images": [] + }, + "synchrofeed-console": { + "icon": "https://community.chocolatey.org/content/packageimages/SynchroFeed.Console.1.0.1.png", + "images": [] + }, + "syncless": { + "icon": "https://community.chocolatey.org/content/packageimages/syncless.2.1.png", + "images": [] + }, + "syncovery": { + "icon": "https://community.chocolatey.org/content/packageimages/syncovery.7.87.101.png", + "images": [] + }, + "syncplay": { + "icon": "https://community.chocolatey.org/content/packageimages/syncplay.1.6.9.png", + "images": [] + }, + "syncplay-beta": { + "icon": "", + "images": [] + }, + "synctex": { + "icon": "https://community.chocolatey.org/content/packageimages/synctex.58783.0.png", + "images": [] + }, + "syncthing": { + "icon": "https://community.chocolatey.org/content/packageimages/syncthing.1.23.1.png", + "images": [] + }, + "syncthing-gtk": { + "icon": "https://community.chocolatey.org/content/packageimages/syncthing-gtk.0.9.4.4.png", + "images": [] + }, + "syncthingtray": { + "icon": "https://community.chocolatey.org/content/packageimages/syncthingtray.1.3.2.png", + "images": [] + }, + "synctoday": { + "icon": "", + "images": [] + }, + "synctoy": { + "icon": "", + "images": [] + }, + "synctrayzor": { + "icon": "https://community.chocolatey.org/content/packageimages/synctrayzor.1.1.29.png", + "images": [] + }, + "synfig": { + "icon": "https://community.chocolatey.org/content/packageimages/synfig.1.5.1.png", + "images": [] + }, + "synfig-studio": { + "icon": "", + "images": [] + }, + "synkron": { + "icon": "https://community.chocolatey.org/content/packageimages/synkron.1.6.2.20140909.png", + "images": [] + }, + "synology-activebackup-for-business-agent": { + "icon": "https://community.chocolatey.org/content/packageimages/synology-activebackup-for-business-agent.2.5.1.2634.png", + "images": [] + }, + "synology-note-station-client": { + "icon": "https://community.chocolatey.org/content/packageimages/synology-note-station-client.2.2.2.609.png", + "images": [] + }, + "synology-surveillance-station": { + "icon": "", + "images": [] + }, + "synologychat": { + "icon": "", + "images": [] + }, + "synth": { + "icon": "https://community.chocolatey.org/content/packageimages/synth.1.0.3.png", + "images": [] + }, + "synthesia": { + "icon": "", + "images": [] + }, + "syrem": { + "icon": "https://community.chocolatey.org/content/packageimages/syrem.3.0.0.png", + "images": [] + }, + "sysexp": { + "icon": "https://community.chocolatey.org/content/packageimages/sysexp.portable.1.76.png", + "images": [] + }, + "sysgauge": { + "icon": "", + "images": [] + }, + "sysinternals": { + "icon": "https://community.chocolatey.org/content/packageimages/sysinternals.2023.1.25.png", + "images": [] + }, + "sysinternals-autoruns": { + "icon": "https://learn.microsoft.com/en-us/sysinternals/media/index/sysinternals.png", + "images": [ + "https://learn.microsoft.com/en-us/sysinternals/downloads/media/autoruns/autoruns_v13.png", + "https://www.bleepstatic.com/download/screenshots/a/autoruns/everything-tab.jpg" + ] + }, + "sysinternals-bginfo": { + "icon": "https://learn.microsoft.com/en-us/sysinternals/media/index/sysinternals.png", + "images": [] + }, + "sysinternals-desktops": { + "icon": "https://learn.microsoft.com/en-us/sysinternals/media/index/sysinternals.png", + "images": [] + }, + "sysinternals-rdcman": { + "icon": "https://learn.microsoft.com/en-us/sysinternals/media/index/sysinternals.png", + "images": [] + }, + "sysinternals-tcpview": { + "icon": "https://learn.microsoft.com/en-us/sysinternals/media/index/sysinternals.png", + "images": [] + }, + "sysinternals-zoomIt": { + "icon": "https://i.postimg.cc/hjPX2PL9/ZoomIt.png", + "images": [] + }, + "syspin": { + "icon": "https://community.chocolatey.org/content/packageimages/syspin.0.99.9.20210303.png", + "images": [] + }, + "systemexplorer": { + "icon": "https://community.chocolatey.org/content/packageimages/systemexplorer.7.0.0.20160118.png", + "images": [] + }, + "systeminformer-nightlybuilds": { + "icon": "https://community.chocolatey.org/content/packageimages/systeminformer-nightlybuilds.3.0.5727.png", + "images": [ + "https://i.postimg.cc/fyYvYt64/image.png", + "https://i.postimg.cc/vmP2mndg/image.png", + "https://i.postimg.cc/V6p7qcvS/image.png", + "https://i.postimg.cc/44H2Jn2P/image.png", + "https://i.postimg.cc/NjBd7DsK/image.png", + "https://i.postimg.cc/HLL3FL7V/image.png", + "https://i.postimg.cc/xCJ5TF5f/image.png" + ] + }, + "systeminformer": { + "icon": "https://community.chocolatey.org/content/packageimages/systeminformer-nightlybuilds.3.0.5727.png", + "images": [ + "https://i.postimg.cc/fyYvYt64/image.png", + "https://i.postimg.cc/vmP2mndg/image.png", + "https://i.postimg.cc/V6p7qcvS/image.png", + "https://i.postimg.cc/44H2Jn2P/image.png", + "https://i.postimg.cc/NjBd7DsK/image.png", + "https://i.postimg.cc/HLL3FL7V/image.png", + "https://i.postimg.cc/xCJ5TF5f/image.png" + ] + }, + "systeminformer-canary": { + "icon": "https://community.chocolatey.org/content/packageimages/systeminformer-nightlybuilds.3.0.5727.png", + "images": [ + "https://i.postimg.cc/fyYvYt64/image.png", + "https://i.postimg.cc/vmP2mndg/image.png", + "https://i.postimg.cc/V6p7qcvS/image.png", + "https://i.postimg.cc/44H2Jn2P/image.png", + "https://i.postimg.cc/NjBd7DsK/image.png", + "https://i.postimg.cc/HLL3FL7V/image.png", + "https://i.postimg.cc/xCJ5TF5f/image.png" + ] + }, + "systemmonitor": { + "icon": "", + "images": [] + }, + "systemninja": { + "icon": "https://community.chocolatey.org/content/packageimages/systemninja.3.1.6.png", + "images": [] + }, + "systemtraymenu": { + "icon": "https://community.chocolatey.org/content/packageimages/systemtraymenu.1.3.2.0.png", + "images": [] + }, + "systemupdate": { + "icon": "https://download.lenovo.com/km/media/images/HT003029/LSU2_20200824181525152.png", + "images": [] + }, + "t-clock": { + "icon": "https://community.chocolatey.org/content/packageimages/t-clock.2.4.4.492.png", + "images": [] + }, + "t-rex": { + "icon": "https://community.chocolatey.org/content/packageimages/t-rex.0.26.8.png", + "images": [] + }, + "tabby": { + "icon": "https://i.postimg.cc/dtxVX0r1/icon.png", + "images": [ + "https://i.postimg.cc/q78BzXYh/sc1.png", + "https://i.postimg.cc/5tcN4kPW/sc2.png", + "https://i.postimg.cc/3x0xHHFZ/sc3.png" + ] + }, + "tablacus": { + "icon": "https://community.chocolatey.org/content/packageimages/tablacus.23.1.31.png", + "images": [] + }, + "tableau-desktop": { + "icon": "", + "images": [] + }, + "tableau-imager": { + "icon": "https://community.chocolatey.org/content/packageimages/tableau-imager.20.3.png", + "images": [] + }, + "tableau-server": { + "icon": "", + "images": [] + }, + "tablecloth": { + "icon": "", + "images": [] + }, + "tableplus": { + "icon": "https://i.postimg.cc/sDw9zDvT/image.png", + "images": [ + "https://i.postimg.cc/HxRRB9C7/image.png", + "https://i.postimg.cc/BvwVnBbw/image.png", + "https://i.postimg.cc/GpNXC3gW/image.png" + ] + }, + "tabspace": { + "icon": "", + "images": [] + }, + "tabula": { + "icon": "", + "images": [] + }, + "tabular-editor": { + "icon": "https://community.chocolatey.org/content/packageimages/tabular-editor.2.17.2.png", + "images": [] + }, + "tac": { + "icon": "", + "images": [] + }, + "tachidesk-jui": { + "icon": "", + "images": [] + }, + "tachidesk-server": { + "icon": "", + "images": [] + }, + "tachidesk-sorayomi": { + "icon": "", + "images": [] + }, + "tad": { + "icon": "https://community.chocolatey.org/content/packageimages/tad.0.11.0.png", + "images": [] + }, + "tag&rename": { + "icon": "", + "images": [] + }, + "tagainijisho": { + "icon": "https://community.chocolatey.org/content/packageimages/TagainiJisho.1.0.3.png", + "images": [] + }, + "tageditor": { + "icon": "", + "images": [] + }, + "tagflow": { + "icon": "https://community.chocolatey.org/content/packageimages/tagflow.0.5.1.png", + "images": [] + }, + "taglyst": { + "icon": "", + "images": [] + }, + "tagscanner": { + "icon": "https://community.chocolatey.org/content/packageimages/tagscanner.portable.6.1.14.png", + "images": [] + }, + "tagspaces": { + "icon": "https://community.chocolatey.org/content/packageimages/tagspaces.5.2.5.png", + "images": [] + }, + "tagsrep": { + "icon": "https://community.chocolatey.org/content/packageimages/tagsrep.1.00.png", + "images": [] + }, + "taiga": { + "icon": "https://imgur.com/a/MTPLaUL", + "images": [ + "https://imgur.com/a/Jp9TlKP", + "https://imgur.com/a/LMBhzM4", + "https://imgur.com/a/Zx98DaQ" + ] + }, + "tailblazer": { + "icon": "https://community.chocolatey.org/content/packageimages/tailblazer.0.9.0.536.png", + "images": [] + }, + "tailscale": { + "icon": "https://tailscale.com/favicon.png", + "images": [] + }, + "tailwindcss": { + "icon": "", + "images": [] + }, + "taisei": { + "icon": "", + "images": [] + }, + "tajpi": { + "icon": "", + "images": [] + }, + "tak": { + "icon": "", + "images": [] + }, + "take-command": { + "icon": "", + "images": [] + }, + "talkdesk": { + "icon": "", + "images": [] + }, + "talosctl": { + "icon": "", + "images": [] + }, + "tangible-t4-vs2013": { + "icon": "", + "images": [] + }, + "tangible-t4-vs2017": { + "icon": "https://community.chocolatey.org/content/packageimages/tangible-t4-vs2017.2.4.0.png", + "images": [] + }, + "tanoshi": { + "icon": "", + "images": [] + }, + "tanzu-community-edition-unstable": { + "icon": "", + "images": [] + }, + "tapwindows": { + "icon": "https://community.chocolatey.org/content/packageimages/tapwindows.9.24.2.png", + "images": [] + }, + "tar": { + "icon": "", + "images": [] + }, + "tartool": { + "icon": "", + "images": [] + }, + "tartube": { + "icon": "https://community.chocolatey.org/content/packageimages/tartube.2.4.221.png", + "images": [] + }, + "task": { + "icon": "", + "images": [] + }, + "task-coach": { + "icon": "", + "images": [] + }, + "taskade": { + "icon": "", + "images": [] + }, + "taskbar-winconfig": { + "icon": "https://community.chocolatey.org/content/packageimages/taskbar-winconfig.0.0.3.png", + "images": [] + }, + "taskbarhider": { + "icon": "", + "images": [] + }, + "taskbarx": { + "icon": "https://community.chocolatey.org/content/packageimages/taskbarx.1.7.8.0.png", + "images": [] + }, + "taskboard": { + "icon": "", + "images": [] + }, + "taskschedulerview": { + "icon": "", + "images": [] + }, + "tasmotizer": { + "icon": "https://community.chocolatey.org/content/packageimages/tasmotizer.1.2.png", + "images": [] + }, + "tastyworks": { + "icon": "", + "images": [] + }, + "tauonmusicbox": { + "icon": "", + "images": [] + }, + "tautulli": { + "icon": "", + "images": [] + }, + "tb-vol-scroll": { + "icon": "https://community.chocolatey.org/content/packageimages/tb-vol-scroll.4.1.2.png", + "images": [] + }, + "tbb": { + "icon": "", + "images": [] + }, + "tcc": { + "icon": "", + "images": [] + }, + "tcc-unlit": { + "icon": "", + "images": [] + }, + "tclocklight-kt": { + "icon": "https://community.chocolatey.org/content/packageimages/tclocklight-kt.18.09.04.png", + "images": [] + }, + "tcno-acc-switcher": { + "icon": "https://community.chocolatey.org/content/packageimages/tcno-acc-switcher.2022.05.26.01.png", + "images": [] + }, + "tcp-copytree": { + "icon": "", + "images": [] + }, + "tcp-diskdirextended": { + "icon": "", + "images": [] + }, + "tcp-envvars": { + "icon": "https://community.chocolatey.org/content/packageimages/tcp-envvars.1.0.png", + "images": [] + }, + "tcp-fileinfo": { + "icon": "", + "images": [] + }, + "tcp-linkinfo": { + "icon": "", + "images": [] + }, + "tcp-mediainfo": { + "icon": "", + "images": [] + }, + "tcp-peviewer": { + "icon": "https://community.chocolatey.org/content/packageimages/tcp-peviewer.2.0.png", + "images": [] + }, + "tcp-qse": { + "icon": "https://community.chocolatey.org/content/packageimages/tcp-qse.2.2.6.png", + "images": [] + }, + "tcp-registry": { + "icon": "", + "images": [] + }, + "tcp-services2": { + "icon": "", + "images": [] + }, + "tcp-shelldetails": { + "icon": "", + "images": [] + }, + "tcp-sqlite": { + "icon": "", + "images": [] + }, + "tcp-startups": { + "icon": "", + "images": [] + }, + "tcp-uninstaller": { + "icon": "https://community.chocolatey.org/content/packageimages/tcp-uninstaller.1.0.1.20191007.png", + "images": [] + }, + "tcp-virtualpanel": { + "icon": "", + "images": [] + }, + "tcp-webdav": { + "icon": "", + "images": [] + }, + "tcping": { + "icon": "", + "images": [] + }, + "tcpipmanager": { + "icon": "", + "images": [] + }, + "tcpoptimizer": { + "icon": "", + "images": [] + }, + "tcps": { + "icon": "https://community.chocolatey.org/content/packageimages/tcps.0.3.2.png", + "images": [] + }, + "tcptunnel": { + "icon": "https://community.chocolatey.org/content/packageimages/tcptunnel.0.8.0.20180614.png", + "images": [] + }, + "tcpvcon": { + "icon": "https://community.chocolatey.org/content/packageimages/tcpvcon.3.05.png", + "images": [] + }, + "tcpview": { + "icon": "", + "images": [] + }, + "tdagent": { + "icon": "", + "images": [] + }, + "tdesktop": { + "icon": "", + "images": [] + }, + "tdict": { + "icon": "", + "images": [] + }, + "tea": { + "icon": "https://community.chocolatey.org/content/packageimages/tea.0.9.0.png", + "images": [] + }, + "teaclient": { + "icon": "", + "images": [] + }, + "tealdeer": { + "icon": "", + "images": [] + }, + "teambition": { + "icon": "", + "images": [] + }, + "teamcity": { + "icon": "https://resources.jetbrains.com/storage/products/teamcity/img/meta/teamcity_logo_300x300.png", + "images": [] + }, + "teamcity-openjdk8": { + "icon": "https://community.chocolatey.org/content/packageimages/teamcity-openjdk8.2022.10.2.png", + "images": [] + }, + "teamcity-preinstalledjre": { + "icon": "https://community.chocolatey.org/content/packageimages/teamcity-preinstalledjre.2022.10.2.png", + "images": [] + }, + "teamcity-vstest-customlogger": { + "icon": "https://community.chocolatey.org/content/packageimages/teamcity-vstest-customlogger.9.1.7.png", + "images": [] + }, + "teamdrive": { + "icon": "", + "images": [] + }, + "teammate": { + "icon": "", + "images": [] + }, + "teams": { + "icon": "https://i.ibb.co/1YT66G0j/teams.png", + "images": [ + "https://i.ibb.co/qYCjdVSp/71-E48-C78-1-F38-47-AD-B28-D-047-A1175-DAAD.png", + "https://i.ibb.co/QvYT1bKf/F17-F108-C-65-E1-4-FD4-AA9-D-E7539-B61-A6-EA.png" + ] + }, + "teams-free": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/c/c9/Microsoft_Office_Teams_(2018%E2%80%93present).svg/258px-Microsoft_Office_Teams_(2018%E2%80%93present).svg.png", + "images": [ + "https://upload.wikimedia.org/wikipedia/en/f/f1/Microsoft_Teams_Desktop_Application_Screenshot.png" + ] + }, + "teams-exploration": { + "icon": "", + "images": [] + }, + "teams-preview": { + "icon": "", + "images": [] + }, + "teamspeak": { + "icon": "https://community.chocolatey.org/content/packageimages/teamspeak.3.5.6.png", + "images": [] + }, + "teamspeak3": { + "icon": "", + "images": [] + }, + "teamspeakclient": { + "icon": "https://img001.prntscr.com/file/img001/aG60yNoTRDq_hlSMrV4e1A.png", + "images": [ + "https://discourse-forums-images.s3.dualstack.us-east-2.amazonaws.com/original/3X/0/5/05c2a7459eb5d5b5e25c09ca695d4497808cb91a.png", + "https://img001.prntscr.com/file/img001/aG60yNoTRDq_hlSMrV4e1A.png", + "https://img001.prntscr.com/file/img001/BPXQQa1DSQGtNMZOEMAR3A.png" + ] + }, + "teamviewer": { + "icon": "https://i.imgur.com/2UWkAjM.png", + "images": [ + "https://upload.wikimedia.org/wikipedia/commons/0/07/TeamViewer_15_Desktop_Win_English.png" + ] + }, + "teamviewer-chrome": { + "icon": "https://community.chocolatey.org/content/packageimages/teamviewer-chrome.13.0.281.png", + "images": [] + }, + "teamviewer-host": { + "icon": "https://i.imgur.com/2UWkAjM.png", + "images": [] + }, + "teamviewer-qs": { + "icon": "https://community.chocolatey.org/content/packageimages/teamviewer-qs.15.39.5.0.png", + "images": [] + }, + "teamviewer7": { + "icon": "https://community.chocolatey.org/content/packageimages/teamviewer7.7.0.17271.png", + "images": [] + }, + "teamviewer8": { + "icon": "https://community.chocolatey.org/content/packageimages/teamviewer8.8.0.26038.png", + "images": [] + }, + "technicians-toolbox": { + "icon": "https://community.chocolatey.org/content/packageimages/technicians-toolbox.1.2.0.png", + "images": [] + }, + "techsmithsnagit": { + "icon": "", + "images": [] + }, + "tectonic": { + "icon": "https://community.chocolatey.org/content/packageimages/tectonic.0.3.2.png", + "images": [] + }, + "tedit": { + "icon": "", + "images": [] + }, + "tednotepad": { + "icon": "", + "images": [] + }, + "teeworlds": { + "icon": "https://community.chocolatey.org/content/packageimages/teeworlds.0.7.5.png", + "images": [] + }, + "tegrarcmgui": { + "icon": "", + "images": [] + }, + "tektoncd-cli": { + "icon": "", + "images": [] + }, + "telegraf": { + "icon": "https://community.chocolatey.org/content/packageimages/telegraf.1.25.3.png", + "images": [] + }, + "telegram": { + "icon": "https://community.chocolatey.org/content/packageimages/telegram.install.4.6.5.png", + "images": [] + }, + "telegram-downloader": { + "icon": "", + "images": [] + }, + "telegramdesktop": { + "icon": "https://i.imgur.com/at0VmW2.png", + "images": [] + }, + "telegramdesktop-beta": { + "icon": "", + "images": [] + }, + "teleport": { + "icon": "", + "images": [] + }, + "teleport-tsh": { + "icon": "https://community.chocolatey.org/content/packageimages/teleport-tsh.11.2.2.png", + "images": [] + }, + "telerikcontrolpanel": { + "icon": "https://community.chocolatey.org/content/packageimages/TelerikControlPanel.2014.3.1017.png", + "images": [] + }, + "telnet": { + "icon": "", + "images": [] + }, + "tempfilecleaner-app": { + "icon": "https://community.chocolatey.org/content/packageimages/TempFileCleaner.app.4.5.0.0.png", + "images": [] + }, + "tempfilecleaner-tool": { + "icon": "https://community.chocolatey.org/content/packageimages/TempFileCleaner.tool.4.3.0.0.png", + "images": [] + }, + "temple": { + "icon": "https://community.chocolatey.org/content/packageimages/temple.portable.1.21.png", + "images": [] + }, + "temurin": { + "icon": "https://community.chocolatey.org/content/packageimages/Temurin.19.0.2.700.png", + "images": [] + }, + "temurin-11-jdk": { + "icon": "https://projects.eclipse.org/sites/default/files/Logo_Temurin_2021_08_17_JRR_RGB-V1A_0.png", + "images": [] + }, + "temurin-11-jre": { + "icon": "https://projects.eclipse.org/sites/default/files/Logo_Temurin_2021_08_17_JRR_RGB-V1A_0.png", + "images": [] + }, + "temurin-16-jdk": { + "icon": "https://projects.eclipse.org/sites/default/files/Logo_Temurin_2021_08_17_JRR_RGB-V1A_0.png", + "images": [] + }, + "temurin-17-jdk": { + "icon": "https://projects.eclipse.org/sites/default/files/Logo_Temurin_2021_08_17_JRR_RGB-V1A_0.png", + "images": [] + }, + "temurin-17-jre": { + "icon": "https://projects.eclipse.org/sites/default/files/Logo_Temurin_2021_08_17_JRR_RGB-V1A_0.png", + "images": [] + }, + "temurin-18-jdk": { + "icon": "https://projects.eclipse.org/sites/default/files/Logo_Temurin_2021_08_17_JRR_RGB-V1A_0.png", + "images": [] + }, + "temurin-18-jre": { + "icon": "https://projects.eclipse.org/sites/default/files/Logo_Temurin_2021_08_17_JRR_RGB-V1A_0.png", + "images": [] + }, + "temurin-19-jdk": { + "icon": "https://projects.eclipse.org/sites/default/files/Logo_Temurin_2021_08_17_JRR_RGB-V1A_0.png", + "images": [] + }, + "temurin-19-jre": { + "icon": "https://projects.eclipse.org/sites/default/files/Logo_Temurin_2021_08_17_JRR_RGB-V1A_0.png", + "images": [] + }, + "temurin-20-jdk": { + "icon": "https://projects.eclipse.org/sites/default/files/Logo_Temurin_2021_08_17_JRR_RGB-V1A_0.png", + "images": [] + }, + "temurin-20-jre": { + "icon": "https://projects.eclipse.org/sites/default/files/Logo_Temurin_2021_08_17_JRR_RGB-V1A_0.png", + "images": [] + }, + "temurin-21-jdk": { + "icon": "https://projects.eclipse.org/sites/default/files/Logo_Temurin_2021_08_17_JRR_RGB-V1A_0.png", + "images": [] + }, + "temurin-8-jdk": { + "icon": "https://projects.eclipse.org/sites/default/files/Logo_Temurin_2021_08_17_JRR_RGB-V1A_0.png", + "images": [] + }, + "temurin-8-jre": { + "icon": "https://projects.eclipse.org/sites/default/files/Logo_Temurin_2021_08_17_JRR_RGB-V1A_0.png", + "images": [] + }, + "temurin11": { + "icon": "https://community.chocolatey.org/content/packageimages/Temurin11.11.0.18.1000.png", + "images": [] + }, + "temurin11jre": { + "icon": "https://community.chocolatey.org/content/packageimages/Temurin11jre.11.0.18.1000.png", + "images": [] + }, + "temurin17": { + "icon": "https://community.chocolatey.org/content/packageimages/Temurin17.17.0.6.1000.png", + "images": [] + }, + "temurin17jre": { + "icon": "https://community.chocolatey.org/content/packageimages/Temurin17jre.17.0.6.1000.png", + "images": [] + }, + "temurin19": { + "icon": "https://community.chocolatey.org/content/packageimages/Temurin19.19.0.2.700.png", + "images": [] + }, + "temurin8": { + "icon": "https://community.chocolatey.org/content/packageimages/Temurin8.8.362.9.png", + "images": [] + }, + "temurin8jre": { + "icon": "https://community.chocolatey.org/content/packageimages/Temurin8jre.8.362.9.png", + "images": [] + }, + "temurinjre": { + "icon": "https://community.chocolatey.org/content/packageimages/Temurinjre.19.0.2.700.png", + "images": [] + }, + "tenacity": { + "icon": "", + "images": [] + }, + "Chocolatey.tenacity": { + "icon": "https://community.chocolatey.org/content/packageimages/tenacity.1.3.4.20250612.png", + "images": [] + }, + "Winget.TenacityTeam.Tenacity": { + "icon": "https://community.chocolatey.org/content/packageimages/tenacity.1.3.4.20250612.png", + "images": [] + }, + "tencentdocs": { + "icon": "", + "images": [] + }, + "tencentmeeting": { + "icon": "https://cdn.meeting.tencent.com/assets/next-website/logo512.png", + "images": [] + }, + "tencentmeetingrooms": { + "icon": "", + "images": [] + }, + "tencentqq": { + "icon": "", + "images": [] + }, + "tencentvideo": { + "icon": "", + "images": [] + }, + "tenhands": { + "icon": "", + "images": [] + }, + "tenhou": { + "icon": "", + "images": [] + }, + "tentacle": { + "icon": "", + "images": [] + }, + "teracopy": { + "icon": "https://i.ibb.co/VWMLqzbN/icon.png", + "images": [ + "https://i.ibb.co/XZgvrZDt/s1.png", + "https://i.ibb.co/RT4Qpvpj/s2.png", + "https://i.ibb.co/S40DxfM4/s3.png" + ] + }, + "teraterm": { + "icon": "https://community.chocolatey.org/content/packageimages/teraterm.4.106.png", + "images": [] + }, + "tere": { + "icon": "", + "images": [] + }, + "terminal-icons": { + "icon": "", + "images": [ + "https://raw.githubusercontent.com/devblackops/Terminal-Icons/main/media/screenshot.png" + ] + }, + "terminal-icons-powershell": { + "icon": "https://community.chocolatey.org/content/packageimages/terminal-icons.powershell.0.10.0.png", + "images": [ + "https://raw.githubusercontent.com/devblackops/Terminal-Icons/main/media/screenshot.png" + ] + }, + "terminalpp": { + "icon": "", + "images": [] + }, + "terminals": { + "icon": "", + "images": [] + }, + "terminals-app": { + "icon": "", + "images": [] + }, + "terminus": { + "icon": "", + "images": [] + }, + "termite": { + "icon": "", + "images": [] + }, + "termius": { + "icon": "https://community.chocolatey.org/content/packageimages/termius.7.56.4.png", + "images": [] + }, + "termscp": { + "icon": "", + "images": [] + }, + "termshark": { + "icon": "", + "images": [] + }, + "tern-subtitle-file-translator": { + "icon": "", + "images": [] + }, + "terracreds": { + "icon": "https://community.chocolatey.org/content/packageimages/terracreds.2.1.4.png", + "images": [] + }, + "terraform": { + "icon": "https://community.chocolatey.org/content/packageimages/terraform.1.3.9.png", + "images": [] + }, + "terraform-docs": { + "icon": "https://community.chocolatey.org/content/packageimages/Terraform-Docs.0.16.0.png", + "images": [] + }, + "terraform-provider-fincloud": { + "icon": "https://community.chocolatey.org/content/packageimages/terraform-provider-fincloud.1.0.1.png", + "images": [] + }, + "terraform-provider-ibm": { + "icon": "", + "images": [] + }, + "terraform-provider-sakuracloud": { + "icon": "", + "images": [] + }, + "terraform-switcher": { + "icon": "", + "images": [] + }, + "terraformer": { + "icon": "", + "images": [] + }, + "terragrunt": { + "icon": "https://community.chocolatey.org/content/packageimages/terragrunt.0.44.0.png", + "images": [] + }, + "teslacamviewer": { + "icon": "https://community.chocolatey.org/content/packageimages/teslacamviewer.2020.18.0.0.png", + "images": [] + }, + "teslamap": { + "icon": "https://community.chocolatey.org/content/packageimages/teslamap.9.0.4.png", + "images": [] + }, + "tess": { + "icon": "https://community.chocolatey.org/content/packageimages/tess.0.6.3.png", + "images": [] + }, + "tesseract": { + "icon": "", + "images": [] + }, + "tesseract-languages": { + "icon": "", + "images": [] + }, + "tesseract-ocr": { + "icon": "", + "images": [] + }, + "tesseractocr": { + "icon": "", + "images": [] + }, + "testcentric": { + "icon": "", + "images": [] + }, + "testcentric-gui": { + "icon": "https://community.chocolatey.org/content/packageimages/testcentric-gui.1.6.4.png", + "images": [] + }, + "testdisk": { + "icon": "https://www.cgsecurity.org/mw/images/thumb/Testdisklogo_clear_100.png/75px-Testdisklogo_clear_100.png", + "images": [] + }, + "testdisk-photorec": { + "icon": "", + "images": [] + }, + "testmace": { + "icon": "", + "images": [] + }, + "testnav": { + "icon": "https://community.chocolatey.org/content/packageimages/testnav.1.10.2.png", + "images": [] + }, + "testonegetcs": { + "icon": "", + "images": [] + }, + "tetr": { + "icon": "", + "images": [] + }, + "tetr-io": { + "icon": "https://community.chocolatey.org/content/packageimages/tetr-io.1.0.0.png", + "images": [] + }, + "tetris-java": { + "icon": "https://community.chocolatey.org/content/packageimages/tetris-java.1.13.0.png", + "images": [] + }, + "texlab": { + "icon": "", + "images": [] + }, + "texlive": { + "icon": "", + "images": [] + }, + "texmacs": { + "icon": "https://community.chocolatey.org/content/packageimages/texmacs.2.1.1.png", + "images": [] + }, + "texmaker": { + "icon": "", + "images": [] + }, + "texniccenter": { + "icon": "https://community.chocolatey.org/content/packageimages/texniccenter.2.02.png", + "images": [] + }, + "texpaste": { + "icon": "", + "images": [] + }, + "texstudio": { + "icon": "https://community.chocolatey.org/content/packageimages/texstudio.portable.4.5.1.png", + "images": [] + }, + "text-grab": { + "icon": "", + "images": [] + }, + "text-to-mp3-converter": { + "icon": "https://community.chocolatey.org/content/packageimages/text-to-mp3-converter.2.0.0.png", + "images": [] + }, + "textadept": { + "icon": "", + "images": [] + }, + "textecode": { + "icon": "https://community.chocolatey.org/content/packageimages/textecode.0.1.0.png", + "images": [] + }, + "texteditoranywhere": { + "icon": "", + "images": [] + }, + "texteditorpro": { + "icon": "", + "images": [] + }, + "textexpander": { + "icon": "", + "images": [] + }, + "textfilter": { + "icon": "https://community.chocolatey.org/content/packageimages/textfilter.0.7.0.009.png", + "images": [] + }, + "textgenerator": { + "icon": "", + "images": [] + }, + "textify": { + "icon": "https://community.chocolatey.org/content/packageimages/textify.1.10.3.png", + "images": [] + }, + "textpad": { + "icon": "", + "images": [] + }, + "textpaster": { + "icon": "", + "images": [] + }, + "texts": { + "icon": "https://community.chocolatey.org/content/packageimages/Texts.1.5.20190524.png", + "images": [] + }, + "texttomp3converter": { + "icon": "https://vovsoft.com/icons128/text-to-mp3-converter.png", + "images": [ + "https://vovsoft.com/screenshots/text-to-mp3-converter.png", + "https://vovsoft.com/screenshots/text-to-mp3-converter-2.png", + "https://vovsoft.com/screenshots/text-to-mp3-converter-3.png", + "https://vovsoft.com/screenshots/text-to-mp3-converter-4.png", + "https://vovsoft.com/screenshots/text-to-mp3-converter-5.png", + "https://vovsoft.com/screenshots/text-to-mp3-converter-6.png" + ] + }, + "texworks": { + "icon": "", + "images": [] + }, + "tf2pulumi": { + "icon": "", + "images": [] + }, + "tflash": { + "icon": "https://community.chocolatey.org/content/packageimages/tflash.2.10.png", + "images": [] + }, + "tflint": { + "icon": "", + "images": [] + }, + "tfs2010objectmodel": { + "icon": "https://community.chocolatey.org/content/packageimages/tfs2010objectmodel.10.0.0.1.png", + "images": [] + }, + "tfs2013objectmodel": { + "icon": "https://community.chocolatey.org/content/packageimages/tfs2013objectmodel.12.0.31101.1.png", + "images": [] + }, + "tfs2013powertools": { + "icon": "", + "images": [] + }, + "tfscmdlets": { + "icon": "https://community.chocolatey.org/content/packageimages/TfsCmdlets.2.6.0.png", + "images": [] + }, + "tfsdropdownloader": { + "icon": "", + "images": [] + }, + "tfsec": { + "icon": "", + "images": [] + }, + "tfsexpress-build": { + "icon": "", + "images": [] + }, + "tfsexpress-standard": { + "icon": "", + "images": [] + }, + "tfspowertools2012": { + "icon": "", + "images": [] + }, + "tfssidekicks": { + "icon": "https://community.chocolatey.org/content/packageimages/tfsSidekicks.2.4.0.png", + "images": [] + }, + "tfssidekicks2010": { + "icon": "https://community.chocolatey.org/content/packageimages/tfsSidekicks2010.3.1.1.png", + "images": [] + }, + "tfssidekicks2012": { + "icon": "https://community.chocolatey.org/content/packageimages/tfsSidekicks2012.4.5.png", + "images": [] + }, + "tfssidekicks2013": { + "icon": "", + "images": [] + }, + "tftpd": { + "icon": "", + "images": [] + }, + "tftputil-gui": { + "icon": "", + "images": [] + }, + "thebat": { + "icon": "https://community.chocolatey.org/content/packageimages/TheBat.6.8.8.png", + "images": [] + }, + "thebat!": { + "icon": "", + "images": [] + }, + "thebrain": { + "icon": "https://community.chocolatey.org/content/packageimages/thebrain.9.000.png", + "images": [] + }, + "thecenter": { + "icon": "", + "images": [] + }, + "thedesk": { + "icon": "https://community.chocolatey.org/content/packageimages/thedesk.portable.24.0.8.png", + "images": [] + }, + "thedude": { + "icon": "", + "images": [] + }, + "thefreezingkoala": { + "icon": "", + "images": [] + }, + "thegiant-cleanup": { + "icon": "", + "images": [] + }, + "thegiant-fonts": { + "icon": "", + "images": [] + }, + "thegiant-freshinstall": { + "icon": "", + "images": [] + }, + "thegiant-tools": { + "icon": "", + "images": [] + }, + "theiablueprint": { + "icon": "", + "images": [] + }, + "thematrix": { + "icon": "https://community.chocolatey.org/content/packageimages/thematrix.1.15.png", + "images": [] + }, + "thermal": { + "icon": "", + "images": [] + }, + "theseus2000": { + "icon": "", + "images": [] + }, + "theworld": { + "icon": "", + "images": [] + }, + "thininstaller": { + "icon": "", + "images": [] + }, + "thinupdate": { + "icon": "https://community.chocolatey.org/content/packageimages/thinupdate.2.06.22.png", + "images": [] + }, + "thisismyfile": { + "icon": "https://i.postimg.cc/g2mDwxmL/This-Is-My-File.png", + "images": [ + "https://i.postimg.cc/fTLd1YzK/This-Is-My-File-1.png" + ] + }, + "thonny": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/e/e2/Thonny_logo.png", + "images": [ + "https://thonny.org/img/screenshot.png" + ] + }, + "thorium": { + "icon": "", + "images": [] + }, + "thorium-reader": { + "icon": "", + "images": [] + }, + "thosefunnyfunguloids": { + "icon": "", + "images": [] + }, + "thoughtworks-go-server": { + "icon": "", + "images": [] + }, + "threema": { + "icon": "https://tweakers.net/ext/i/2005024022.png", + "images": [] + }, + "threema-desktop": { + "icon": "", + "images": [] + }, + "thrift": { + "icon": "", + "images": [] + }, + "throttlestop": { + "icon": "https://community.chocolatey.org/content/packageimages/throttlestop.9.5.png", + "images": [] + }, + "ths-hevo": { + "icon": "", + "images": [] + }, + "thumbico": { + "icon": "https://community.chocolatey.org/content/packageimages/thumbico.1.5.0.25.png", + "images": [] + }, + "thumbnail-database-viewer": { + "icon": "", + "images": [] + }, + "thumbs-viewer": { + "icon": "https://community.chocolatey.org/content/packageimages/thumbs-viewer.1.0.3.0.png", + "images": [] + }, + "thumbs7z": { + "icon": "", + "images": [] + }, + "thumbsremover": { + "icon": "", + "images": [] + }, + "thunder": { + "icon": "", + "images": [] + }, + "thunder-speed": { + "icon": "", + "images": [] + }, + "thunderbird": { + "icon": "https://i.ibb.co/NgwCjhjJ/image.png", + "images": [ + "https://upload.wikimedia.org/wikipedia/commons/thumb/3/39/Thunderbird_102_screenshot.png/1024px-Thunderbird_102_screenshot.png" + ] + }, + "thunderbird-beta": { + "icon": "", + "images": [] + }, + "thunderbird-esr": { + "icon": "https://www.thunderbird.net/media/img/thunderbird/thunderbird-256.png", + "images": [] + }, + "thymiosuite": { + "icon": "https://community.chocolatey.org/content/packageimages/thymiosuite.2.4.0.png", + "images": [] + }, + "ti-cgt-tms470": { + "icon": "", + "images": [] + }, + "ti-smartview-ti-83": { + "icon": "", + "images": [] + }, + "ticker": { + "icon": "", + "images": [] + }, + "ticktick": { + "icon": "https://i.postimg.cc/L63mjjjB/99774274-e1ee6b80-2b0d-11eb-9f17-95ad67dd878c.png", + "images": [ + "https://i.postimg.cc/SRGHY7Hn/platform.png" + ] + }, + "ticonnect": { + "icon": "", + "images": [] + }, + "tidal": { + "icon": "https://community.chocolatey.org/content/packageimages/tidal.2.34.2.0.png", + "images": [] + }, + "tidalcycles": { + "icon": "https://community.chocolatey.org/content/packageimages/TidalCycles.1.9.3.png", + "images": [] + }, + "tidewaysdaemon": { + "icon": "", + "images": [] + }, + "tidy": { + "icon": "", + "images": [] + }, + "tidyjson": { + "icon": "", + "images": [] + }, + "tidystart-powershell": { + "icon": "", + "images": [] + }, + "tidytabs": { + "icon": "https://community.chocolatey.org/content/packageimages/tidytabs.1.3.5.png", + "images": [] + }, + "tigervnc": { + "icon": "https://community.chocolatey.org/content/packageimages/tigervnc.1.11.0.png", + "images": [] + }, + "tigervnc-nightly": { + "icon": "", + "images": [] + }, + "tigervnc-viewer": { + "icon": "https://community.chocolatey.org/content/packageimages/tigervnc-viewer.1.11.0.png", + "images": [] + }, + "tightvnc": { + "icon": "https://tweakers.net/ext/i/1278099200.png", + "images": [ + "https://i.postimg.cc/VNX6YrVt/image.png", + "https://i.postimg.cc/zvGXSdXw/image.png", + "https://i.postimg.cc/3R4HKPRc/image.png" + ] + }, + "tikzedtbeta": { + "icon": "", + "images": [] + }, + "tikzit": { + "icon": "", + "images": [] + }, + "tilde": { + "icon": "", + "images": [] + }, + "tiled": { + "icon": "", + "images": [] + }, + "tileiconifier": { + "icon": "", + "images": [] + }, + "tilt": { + "icon": "https://community.chocolatey.org/content/packageimages/tilt.0.31.2.png", + "images": [] + }, + "tim": { + "icon": "", + "images": [] + }, + "timberwinr": { + "icon": "https://community.chocolatey.org/content/packageimages/TimberWinR.1.4.17.0.png", + "images": [] + }, + "time": { + "icon": "", + "images": [] + }, + "time-to-leave": { + "icon": "", + "images": [] + }, + "time-txt": { + "icon": "", + "images": [] + }, + "time4popcorn": { + "icon": "https://community.chocolatey.org/content/packageimages/time4popcorn.0.5.0.png", + "images": [] + }, + "timeapp": { + "icon": "", + "images": [] + }, + "timeclockwizard": { + "icon": "", + "images": [] + }, + "timeit": { + "icon": "", + "images": [] + }, + "timelineexplorer": { + "icon": "", + "images": [] + }, + "timerle": { + "icon": "", + "images": [] + }, + "timeseriesadmin": { + "icon": "", + "images": [] + }, + "timeslottracker": { + "icon": "", + "images": [] + }, + "timespent": { + "icon": "", + "images": [] + }, + "timestamp": { + "icon": "", + "images": [] + }, + "timetable": { + "icon": "", + "images": [] + }, + "timevertor": { + "icon": "https://community.chocolatey.org/content/packageimages/timevertor.1.4.3.png", + "images": [] + }, + "timrayburn-gitaliases": { + "icon": "https://community.chocolatey.org/content/packageimages/TimRayburn.GitAliases.1.2.0.png", + "images": [] + }, + "tineye-chrome": { + "icon": "", + "images": [] + }, + "tinn-r": { + "icon": "https://community.chocolatey.org/content/packageimages/tinn-r.8.2.2.1.png", + "images": [] + }, + "tinode-mysql": { + "icon": "", + "images": [] + }, + "tiny-pxe-server": { + "icon": "", + "images": [] + }, + "tinycad": { + "icon": "https://community.chocolatey.org/content/packageimages/tinycad.3.00.00.png", + "images": [] + }, + "tinycc": { + "icon": "https://community.chocolatey.org/content/packageimages/tinycc.0.9.26.png", + "images": [] + }, + "tinycodes": { + "icon": "", + "images": [] + }, + "tinygo": { + "icon": "", + "images": [] + }, + "tinymediamanager": { + "icon": "", + "images": [] + }, + "tinynvidiaupdatechecker": { + "icon": "", + "images": [] + }, + "tinytask": { + "icon": "https://community.chocolatey.org/content/packageimages/tinytask.1.50.20141130.png", + "images": [] + }, + "tinytex": { + "icon": "https://community.chocolatey.org/content/packageimages/tinytex.2023.02.png", + "images": [] + }, + "tinyvid": { + "icon": "", + "images": [] + }, + "tipp10": { + "icon": "", + "images": [] + }, + "tiptoimanager": { + "icon": "https://community.chocolatey.org/content/packageimages/tiptoimanager.5.0.2.png", + "images": [] + }, + "titanium-studio": { + "icon": "", + "images": [] + }, + "titik": { + "icon": "", + "images": [] + }, + "titulkycom": { + "icon": "", + "images": [] + }, + "tivo-desktop": { + "icon": "", + "images": [] + }, + "tivo-desktop-patch": { + "icon": "", + "images": [] + }, + "tivotogo-plex": { + "icon": "", + "images": [] + }, + "tixati": { + "icon": "https://community.chocolatey.org/content/packageimages/tixati.portable.3.16.png", + "images": [] + }, + "tjs": { + "icon": "https://community.chocolatey.org/content/packageimages/tjs.portable.6.20.0.png", + "images": [] + }, + "tlaplus-toolbox": { + "icon": "", + "images": [] + }, + "tldr": { + "icon": "https://community.chocolatey.org/content/packageimages/tldr.1.0.png", + "images": [] + }, + "tldr-plusplus": { + "icon": "https://community.chocolatey.org/content/packageimages/tldr-plusplus.0.6.1.png", + "images": [] + }, + "tlfdadidw": { + "icon": "", + "images": [] + }, + "tmpgenc-karma": { + "icon": "https://community.chocolatey.org/content/packageimages/tmpgenc-karma.0.0.7.72.png", + "images": [] + }, + "toastify": { + "icon": "", + "images": [] + }, + "toby-chrome": { + "icon": "https://community.chocolatey.org/content/packageimages/toby-chrome.0.5.2.png", + "images": [] + }, + "tockler": { + "icon": "", + "images": [] + }, + "todesk": { + "icon": "https://todeskcdnspeed.todesk.com/20250513164524635007419258d4.png", + "images": [ + "https://todeskcdnspeed.todesk.com/202302231103335f555421c56974.png" + ] + }, + "todo": { + "icon": "", + "images": [] + }, + "todobackup": { + "icon": "https://community.chocolatey.org/content/packageimages/todobackup.2022.20211220.png", + "images": [] + }, + "todoist": { + "icon": "", + "images": [] + }, + "todoist-desktop": { + "icon": "https://community.chocolatey.org/content/packageimages/todoist-desktop.1.0.7.png", + "images": [] + }, + "todoist-outlook": { + "icon": "", + "images": [] + }, + "todolist": { + "icon": "", + "images": [] + }, + "todopctrans": { + "icon": "https://i.postimg.cc/R0G2gsRp/pct.png", + "images": [ + "https://i.postimg.cc/JzSsGxJg/image.png", + "https://i.postimg.cc/9QwM59SB/image.png", + "https://i.postimg.cc/R0Qv4LTw/image.png", + "https://i.postimg.cc/Kv6bTHqn/image.png", + "https://i.postimg.cc/Gpr17s1t/image.png", + "https://i.postimg.cc/6Q0xD590/image.png", + "https://i.postimg.cc/XJY63Sq0/image.png" + ] + }, + "todotxt-net": { + "icon": "", + "images": [] + }, + "toggl": { + "icon": "https://community.chocolatey.org/content/packageimages/toggl.7.5.454.png", + "images": [] + }, + "toggltrack": { + "icon": "https://community.chocolatey.org/content/packageimages/toggl.7.5.454.png", + "images": [] + }, + "tokei": { + "icon": "", + "images": [] + }, + "tokumei-player-plus": { + "icon": "", + "images": [] + }, + "tokumei-player-pp": { + "icon": "", + "images": [] + }, + "tom": { + "icon": "", + "images": [] + }, + "tomatoad": { + "icon": "", + "images": [] + }, + "tomboy": { + "icon": "https://community.chocolatey.org/content/packageimages/tomboy.1.15.7.png", + "images": [] + }, + "tomcat": { + "icon": "https://community.chocolatey.org/content/packageimages/Tomcat.9.0.70.png", + "images": [] + }, + "tome-editor": { + "icon": "https://community.chocolatey.org/content/packageimages/tome-editor.1.0.png", + "images": [] + }, + "tomtom-mydrive-connect": { + "icon": "https://community.chocolatey.org/content/packageimages/tomtom-mydrive-connect.4.2.13.4365.png", + "images": [] + }, + "tonelib": { + "icon": "", + "images": [] + }, + "tonelib-gfx": { + "icon": "https://community.chocolatey.org/content/packageimages/tonelib-gfx.4.6.5.png", + "images": [] + }, + "tonido-drive": { + "icon": "", + "images": [] + }, + "tonido-server": { + "icon": "", + "images": [] + }, + "tonido-sync": { + "icon": "", + "images": [] + }, + "toolbox": { + "icon": "https://resources.jetbrains.com/storage/products/toolbox/img/meta/toolbox_logo_300x300.png", + "images": [] + }, + "toolchain": { + "icon": "", + "images": [] + }, + "toolkit": { + "icon": "", + "images": [] + }, + "toolsroot": { + "icon": "", + "images": [] + }, + "toolwiz-time-freeze": { + "icon": "https://community.chocolatey.org/content/packageimages/toolwiz-time-freeze.4.3.1.5000.png", + "images": [] + }, + "toontownrewritten": { + "icon": "https://i.postimg.cc/XJzHGLmW/Toontown-Logo-Icon.png", + "images": [] + }, + "topazdenoiseai": { + "icon": "", + "images": [] + }, + "topazgigapixelai": { + "icon": "https://www.pngfind.com/pngs/m/675-6751343_topaz-gigapixel-ai-logo-hd-png-download.png", + "images": [] + }, + "topazphotoai": { + "icon": "", + "images": [] + }, + "topazsharpenai": { + "icon": "", + "images": [] + }, + "topazvideoenhanceai": { + "icon": "", + "images": [] + }, + "topbeat": { + "icon": "https://community.chocolatey.org/content/packageimages/topbeat.1.3.1.png", + "images": [] + }, + "topgrade": { + "icon": "", + "images": [] + }, + "tor": { + "icon": "https://community.chocolatey.org/content/packageimages/tor.0.4.7.11.png", + "images": [] + }, + "tor-browser": { + "icon": "", + "images": [] + }, + "torbrowser": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/c/c9/Tor_Browser_icon.svg/800px-Tor_Browser_icon.svg.png", + "images": [] + }, + "torchat": { + "icon": "https://community.chocolatey.org/content/packageimages/torchat.0.9.9.553201803.png", + "images": [] + }, + "torguard": { + "icon": "", + "images": [] + }, + "torguard-client": { + "icon": "https://community.chocolatey.org/content/packageimages/torguard-client.4.8.15.20230218.png", + "images": [] + }, + "torifier": { + "icon": "https://community.chocolatey.org/content/packageimages/torifier.1.04.png", + "images": [] + }, + "torpar": { + "icon": "", + "images": [] + }, + "torrent-file-editor": { + "icon": "", + "images": [] + }, + "torrenttools": { + "icon": "", + "images": [] + }, + "torrid": { + "icon": "", + "images": [] + }, + "tortoisegit": { + "icon": "https://unigeticons.meowcat285.com/tortoisegit.png", + "images": [ + "https://i.imgur.com/r43Qy8M.png", + "https://i.imgur.com/yJlUype.png", + "https://i.imgur.com/xSqb72j.png" + ] + }, + "tortoisegit-latest": { + "icon": "https://community.chocolatey.org/content/packageimages/TortoiseGit.latest.1.7.15.png", + "images": [] + }, + "tortoisehg": { + "icon": "", + "images": [] + }, + "tortoisemerge": { + "icon": "", + "images": [] + }, + "tortoisesvn": { + "icon": "https://community.chocolatey.org/content/packageimages/tortoisesvn.1.14.5.29465.png", + "images": [] + }, + "tortoisesvn-ipv6": { + "icon": "https://community.chocolatey.org/content/packageimages/tortoisesvn-ipv6.1.10.1.28295.png", + "images": [] + }, + "total-registry": { + "icon": "", + "images": [] + }, + "totalcommander": { + "icon": "https://tweakers.net/ext/i/2005046262.png", + "images": [ + "https://iforum-sg.c.huawei.com/dddd/images/2021/5/13/e8aa6d53-9e98-414e-a8cb-fe5d5e55bdb4.png" + ] + }, + "totalcommanderpowerpack": { + "icon": "https://community.chocolatey.org/content/packageimages/totalcommanderpowerpack.2.0.png", + "images": [] + }, + "totalregistry": { + "icon": "", + "images": [] + }, + "totypescriptd": { + "icon": "", + "images": [] + }, + "touch": { + "icon": "", + "images": [] + }, + "touchcursor": { + "icon": "", + "images": [] + }, + "touchdesigner": { + "icon": "https://community.chocolatey.org/content/packageimages/touchdesigner.88.62160.png", + "images": [] + }, + "touchportal": { + "icon": "https://community.chocolatey.org/content/packageimages/touchportal.3.1.11.png", + "images": [] + }, + "touchvpn": { + "icon": "", + "images": [] + }, + "toughcookies": { + "icon": "", + "images": [] + }, + "tower": { + "icon": "", + "images": [] + }, + "toweroffantasy": { + "icon": "", + "images": [] + }, + "toxiproxy": { + "icon": "https://community.chocolatey.org/content/packageimages/toxiproxy.2.5.0.png", + "images": [] + }, + "toxiproxy-cli": { + "icon": "https://community.chocolatey.org/content/packageimages/toxiproxy-cli.2.5.0.png", + "images": [] + }, + "toxiproxy-server": { + "icon": "https://community.chocolatey.org/content/packageimages/toxiproxy-server.2.5.0.png", + "images": [] + }, + "tproxy": { + "icon": "", + "images": [] + }, + "tpx": { + "icon": "", + "images": [] + }, + "trace3dplus": { + "icon": "", + "images": [] + }, + "trackchecker": { + "icon": "", + "images": [] + }, + "trackcomp": { + "icon": "https://community.chocolatey.org/content/packageimages/trackcomp.2.06.20221112.png", + "images": [] + }, + "trackcontrol": { + "icon": "", + "images": [] + }, + "trackds": { + "icon": "https://community.chocolatey.org/content/packageimages/trackds.1.10.20221112.png", + "images": [] + }, + "tracker": { + "icon": "", + "images": [] + }, + "trackgate": { + "icon": "https://community.chocolatey.org/content/packageimages/trackgate.1.10.20221112.png", + "images": [] + }, + "tracklimit": { + "icon": "https://community.chocolatey.org/content/packageimages/tracklimit.1.10.20221112.png", + "images": [] + }, + "trackmanianationsforever": { + "icon": "", + "images": [] + }, + "trackmeter": { + "icon": "https://community.chocolatey.org/content/packageimages/trackmeter.1.10.20221112.png", + "images": [] + }, + "tradingpaints": { + "icon": "", + "images": [] + }, + "tradingviewdesktop": { + "icon": "", + "images": [] + }, + "tradingviewdesktop-beta": { + "icon": "", + "images": [] + }, + "tradosstudio-2021": { + "icon": "", + "images": [] + }, + "tradosstudio-2022": { + "icon": "", + "images": [] + }, + "traefik": { + "icon": "https://community.chocolatey.org/content/packageimages/traefik.1.7.34.png", + "images": [] + }, + "trafficlight-chrome": { + "icon": "https://community.chocolatey.org/content/packageimages/trafficlight-chrome.1.1.0.9.png", + "images": [] + }, + "trafficlight-firefox": { + "icon": "https://community.chocolatey.org/content/packageimages/trafficlight-firefox.2.0.1.png", + "images": [] + }, + "trafficmonitor": { + "icon": "", + "images": [] + }, + "trafficmonitor-lite": { + "icon": "", + "images": [] + }, + "trafficwatcher": { + "icon": "https://community.chocolatey.org/content/packageimages/trafficwatcher.2.0.1.png", + "images": [] + }, + "trailingwhitespace": { + "icon": "", + "images": [] + }, + "transcribe": { + "icon": "", + "images": [] + }, + "transfer": { + "icon": "https://community.chocolatey.org/content/packageimages/transfer.1.1.0.png", + "images": [] + }, + "transgui": { + "icon": "https://community.chocolatey.org/content/packageimages/transgui.5.18.0.png", + "images": [] + }, + "transifex-client": { + "icon": "https://community.chocolatey.org/content/packageimages/transifex-client.0.14.4.png", + "images": [] + }, + "translucenttb": { + "icon": "https://community.chocolatey.org/content/packageimages/translucenttb.2022.1.png", + "images": [] + }, + "transmart": { + "icon": "", + "images": [] + }, + "transmission": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/4/46/Transmission_Icon.svg/1200px-Transmission_Icon.svg.png", + "images": [ + "https://i.postimg.cc/G2Pv3qPn/image.png", + "https://i.postimg.cc/HnpXrX3c/image.png" + ] + }, + "transmission-cli": { + "icon": "", + "images": [] + }, + "transmission-qt": { + "icon": "", + "images": [] + }, + "transwiz": { + "icon": "https://community.chocolatey.org/content/packageimages/Transwiz.1.19.png", + "images": [] + }, + "travis": { + "icon": "https://community.chocolatey.org/content/packageimages/travis.1.11.1.png", + "images": [] + }, + "trayit": { + "icon": "https://community.chocolatey.org/content/packageimages/trayit.4.6.5.5.png", + "images": [] + }, + "traymond": { + "icon": "", + "images": [] + }, + "traystatus": { + "icon": "", + "images": [ + "https://i.postimg.cc/gjgGMRbh/image.png", + "https://i.postimg.cc/L6s9Jyj3/image.png", + "https://i.postimg.cc/MpMzDvPc/image.png", + "https://i.postimg.cc/T3zfHfFt/image.png", + "https://i.postimg.cc/XJ334xVF/image.png" + ] + }, + "trayweather": { + "icon": "", + "images": [] + }, + "tree": { + "icon": "https://community.chocolatey.org/content/packageimages/tree.1.5.2.2.png", + "images": [] + }, + "tree-sitter": { + "icon": "", + "images": [] + }, + "treesheets": { + "icon": "https://community.chocolatey.org/content/packageimages/treesheets.2015.9.13.png", + "images": [] + }, + "treesize": { + "icon": "https://i.postimg.cc/wvC9YRHB/TreeSize.png", + "images": [ + "https://www.jam-software.com/sites/default/files/treesize/online_manual/EN/TreeSize-MainWindow_Options_Display.png", + "https://www.jam-software.com/sites/default/files/treesize/online_manual/EN/TreeSize-Mainwindow_Quickstart_raw.png", + "https://www.jam-software.com/sites/default/files/treesize/online_manual/EN/TreeSize-MainWindow_Chart.png", + "https://www.jam-software.com/sites/default/files/treesize/online_manual/EN/TreeSize-MainWindow_TreeMap.png", + "https://www.jam-software.com/sites/default/files/treesize/online_manual/EN/TreeSize-MainWindow_Details.png", + "https://www.jam-software.com/sites/default/files/treesize/online_manual/EN/TreeSize-MainWindow_Options_Age_of_Files.png", + "https://www.jam-software.com/sites/default/files/treesize/online_manual/EN/TreeSize-MainWindow_Top_Files.png", + "https://www.jam-software.com/sites/default/files/treesize/online_manual/EN/TreeSize-FileSearch_Custom.png" + ] + }, + "treesize-free": { + "icon": "https://i.postimg.cc/qq24JBMx/Tree-Size-Free.png", + "images": [ + "https://www.jam-software.com/sites/default/files/treesize_free/online_manual/EN/TreeSizeFree-Classic-MainForm-Touch.png", + "https://www.jam-software.com/sites/default/files/treesize_free/online_manual/EN/TreeSizeFree-DirectoryTree-Pure.png", + "https://www.jam-software.com/sites/default/files/treesize_free/online_manual/EN/TreeSizeFree_3.png", + "https://www.jam-software.com/sites/default/files/treesize_free/online_manual/EN/TreeSizeFree-Treemap-Chart-3D.png", + "https://www.jam-software.com/sites/default/files/treesize_free/online_manual/EN/TreeSizeFree-DarkMode.png" + ] + }, + "treesizefree": { + "icon": "https://i.postimg.cc/qq24JBMx/Tree-Size-Free.png", + "images": [ + "https://www.jam-software.com/sites/default/files/treesize_free/online_manual/EN/TreeSizeFree-Classic-MainForm-Touch.png", + "https://www.jam-software.com/sites/default/files/treesize_free/online_manual/EN/TreeSizeFree-DirectoryTree-Pure.png", + "https://www.jam-software.com/sites/default/files/treesize_free/online_manual/EN/TreeSizeFree_3.png", + "https://www.jam-software.com/sites/default/files/treesize_free/online_manual/EN/TreeSizeFree-Treemap-Chart-3D.png", + "https://www.jam-software.com/sites/default/files/treesize_free/online_manual/EN/TreeSizeFree-DarkMode.png" + ] + }, + "treetrim": { + "icon": "", + "images": [] + }, + "trelby": { + "icon": "", + "images": [] + }, + "trello-chrome": { + "icon": "", + "images": [] + }, + "tremulous": { + "icon": "", + "images": [] + }, + "tresorit": { + "icon": "https://community.chocolatey.org/content/packageimages/tresorit.3.5.4214.3460.png", + "images": [] + }, + "trezor-suite": { + "icon": "", + "images": [] + }, + "trezorbridge": { + "icon": "", + "images": [] + }, + "tribler": { + "icon": "https://www.techforpc.com/wp-content/uploads/2015/11/tribler-for-pc-windows-7810mac-free-download.png", + "images": [] + }, + "trico": { + "icon": "", + "images": [] + }, + "trid": { + "icon": "https://community.chocolatey.org/content/packageimages/trid.2.24.20230228.png", + "images": [] + }, + "trilium": { + "icon": "", + "images": [] + }, + "trilium-notes": { + "icon": "https://community.chocolatey.org/content/packageimages/trilium-notes.0.58.7.png", + "images": [] + }, + "trillian": { + "icon": "https://i.imgur.com/QPPJo3s.png", + "images": [] + }, + "trim": { + "icon": "", + "images": [] + }, + "trion": { + "icon": "https://community.chocolatey.org/content/packageimages/trion.portable.1.15.png", + "images": [] + }, + "triplea": { + "icon": "https://community.chocolatey.org/content/packageimages/triplea.2.5.22294.png", + "images": [] + }, + "trivia-desktop": { + "icon": "", + "images": [] + }, + "trivy": { + "icon": "https://community.chocolatey.org/content/packageimages/trivy.0.1.7.png", + "images": [] + }, + "trojan": { + "icon": "", + "images": [] + }, + "trojita": { + "icon": "", + "images": [] + }, + "tropy": { + "icon": "", + "images": [] + }, + "troy2000": { + "icon": "", + "images": [] + }, + "truecrypt": { + "icon": "https://community.chocolatey.org/content/packageimages/truecrypt.7.1.20150620.png", + "images": [] + }, + "truecrypt-langfiles": { + "icon": "", + "images": [] + }, + "trufflehog": { + "icon": "https://community.chocolatey.org/content/packageimages/trufflehog.3.28.2.png", + "images": [] + }, + "trustedqsl": { + "icon": "https://community.chocolatey.org/content/packageimages/trustedqsl.2.6.5.png", + "images": [] + }, + "trzsz": { + "icon": "", + "images": [] + }, + "tsip": { + "icon": "", + "images": [] + }, + "tsprintclient": { + "icon": "https://community.chocolatey.org/content/packageimages/tsprintclient.3.2.2.8.png", + "images": [] + }, + "tta": { + "icon": "", + "images": [] + }, + "ttl": { + "icon": "", + "images": [] + }, + "ttsnow": { + "icon": "", + "images": [] + }, + "ttth": { + "icon": "", + "images": [] + }, + "ttyd": { + "icon": "", + "images": [] + }, + "ttyper": { + "icon": "", + "images": [] + }, + "tuifeed": { + "icon": "https://community.chocolatey.org/content/packageimages/tuifeed.0.3.2.png", + "images": [] + }, + "tukui": { + "icon": "", + "images": [] + }, + "tumblthree": { + "icon": "", + "images": [] + }, + "tuna": { + "icon": "", + "images": [] + }, + "tunein": { + "icon": "https://community.chocolatey.org/content/packageimages/tunein-radio.1.24.0.png", + "images": [] + }, + "tunein-radio": { + "icon": "https://community.chocolatey.org/content/packageimages/tunein-radio.1.24.0.png", + "images": [] + }, + "tunepack": { + "icon": "", + "images": [] + }, + "tuneuputilities": { + "icon": "", + "images": [] + }, + "tunnel": { + "icon": "", + "images": [] + }, + "tunnelbear": { + "icon": "", + "images": [] + }, + "tunnelier": { + "icon": "", + "images": [] + }, + "tunsafe": { + "icon": "https://community.chocolatey.org/content/packageimages/tunsafe.1.4.png", + "images": [] + }, + "tup": { + "icon": "", + "images": [] + }, + "turbotop": { + "icon": "", + "images": [] + }, + "turbovnc": { + "icon": "", + "images": [] + }, + "turbowarp": { + "icon": "", + "images": [] + }, + "turnflash": { + "icon": "https://community.chocolatey.org/content/packageimages/turnflash.1.00.png", + "images": [] + }, + "turnoffxboxcontroller": { + "icon": "https://community.chocolatey.org/content/packageimages/turnoffxboxcontroller.1.2.0.png", + "images": [] + }, + "turtl": { + "icon": "", + "images": [] + }, + "tusk": { + "icon": "https://community.chocolatey.org/content/packageimages/tusk.install.0.23.0.png", + "images": [] + }, + "tutanota": { + "icon": "https://community.chocolatey.org/content/packageimages/tutanota.3.109.5.png", + "images": [] + }, + "tutoolbox": { + "icon": "", + "images": [] + }, + "tux-of-math-command": { + "icon": "https://community.chocolatey.org/content/packageimages/tux-of-math-command.2.0.2.png", + "images": [] + }, + "tux-paint-stamps": { + "icon": "", + "images": [] + }, + "tux-typing": { + "icon": "https://community.chocolatey.org/content/packageimages/tux-typing.1.8.1.png", + "images": [] + }, + "tuxboot": { + "icon": "https://community.chocolatey.org/content/packageimages/tuxboot.0.8.3.png", + "images": [] + }, + "tuxguitar": { + "icon": "https://community.chocolatey.org/content/packageimages/tuxguitar.1.5.6.png", + "images": [] + }, + "tuxpaint": { + "icon": "", + "images": [] + }, + "tv-browser": { + "icon": "", + "images": [] + }, + "tviewer": { + "icon": "", + "images": [] + }, + "tvrename": { + "icon": "https://community.chocolatey.org/content/packageimages/tvrename.4.8.6.png", + "images": [] + }, + "tweakpower": { + "icon": "", + "images": [] + }, + "tweakstyle": { + "icon": "", + "images": [] + }, + "tweetduck": { + "icon": "https://community.chocolatey.org/content/packageimages/tweetduck.install.1.25.2.png", + "images": [] + }, + "tweeten": { + "icon": "", + "images": [] + }, + "tweetz-desktop": { + "icon": "https://community.chocolatey.org/content/packageimages/tweetz-desktop.0.8.23.png", + "images": [] + }, + "twemoji": { + "icon": "", + "images": [] + }, + "twilio-cli": { + "icon": "", + "images": [] + }, + "twine": { + "icon": "", + "images": [] + }, + "twingate": { + "icon": "https://community.chocolatey.org/content/packageimages/twingate.1.0.25.17984.png", + "images": [] + }, + "twingate-connector": { + "icon": "https://community.chocolatey.org/content/packageimages/twingate-connector.1.41.0.png", + "images": [] + }, + "twinkle-tray": { + "icon": "https://community.chocolatey.org/content/packageimages/twinkle-tray.1.15.2.png", + "images": [] + }, + "twinkletray": { + "icon": "", + "images": [] + }, + "twinkstarbrowser": { + "icon": "", + "images": [] + }, + "twisted": { + "icon": "", + "images": [] + }, + "twister-webkit": { + "icon": "https://community.chocolatey.org/content/packageimages/twister-webkit.0.9.28.0.png", + "images": [] + }, + "twitch": { + "icon": "https://community.chocolatey.org/content/packageimages/twitch.8.0.0.20201028.png", + "images": [] + }, + "twitch-channel-points-aut-chrome": { + "icon": "https://community.chocolatey.org/content/packageimages/twitch-channel-points-aut-chrome.0.0.11.png", + "images": [] + }, + "twitchdownloader": { + "icon": "", + "images": [] + }, + "twitchdownloader-cli": { + "icon": "", + "images": [] + }, + "twitchstudio": { + "icon": "", + "images": [] + }, + "twitchtest": { + "icon": "", + "images": [] + }, + "twittertron": { + "icon": "", + "images": [] + }, + "typecode": { + "icon": "", + "images": [] + }, + "typeeasy": { + "icon": "", + "images": [] + }, + "typefaster": { + "icon": "", + "images": [] + }, + "typegen": { + "icon": "https://community.chocolatey.org/content/packageimages/TypeGen.1.6.3.png", + "images": [] + }, + "typemockisolator-net": { + "icon": "", + "images": [] + }, + "typerefhasher": { + "icon": "", + "images": [] + }, + "typerspeedsepia": { + "icon": "", + "images": [] + }, + "typescript": { + "icon": "https://community.chocolatey.org/content/packageimages/typescript.4.9.5.png", + "images": [] + }, + "typescript-vs2013": { + "icon": "https://community.chocolatey.org/content/packageimages/typescript.vs2013.1.8.5.png", + "images": [] + }, + "typescript-vs2015": { + "icon": "https://community.chocolatey.org/content/packageimages/typescript-vs2015.3.2.2.0.png", + "images": [] + }, + "typinglearner": { + "icon": "", + "images": [] + }, + "typingmaster": { + "icon": "", + "images": [] + }, + "typingtest": { + "icon": "", + "images": [] + }, + "typioca": { + "icon": "", + "images": [] + }, + "typora": { + "icon": "https://community.chocolatey.org/content/packageimages/typora.1.5.8.png", + "images": [] + }, + "ù": { + "icon": "", + "images": [] + }, + "uadevelopers-utils": { + "icon": "", + "images": [] + }, + "uas-plex": { + "icon": "", + "images": [] + }, + "ubackit": { + "icon": "", + "images": [] + }, + "uber-apk-signer": { + "icon": "", + "images": [] + }, + "ubiquiti-unifi-controller": { + "icon": "https://community.chocolatey.org/content/packageimages/ubiquiti-unifi-controller.7.3.83.png", + "images": [] + }, + "ubisoft-connect": { + "icon": "https://community.chocolatey.org/content/packageimages/ubisoft-connect.138.3.0.10824.png", + "images": [ + "https://ubistatic-a.ubisoft.com/0123/PROD/_next/static/images/pc-launcher-a6cf12a5845261259bd87299a19446e7.png", + "https://ubistatic-a.ubisoft.com/0123/PROD/_next/static/images/devices-composition-d29dbea55ec3e0f0e5c2d7250be061d4.png" + ] + }, + "ubooquity": { + "icon": "https://community.chocolatey.org/content/packageimages/ubooquity.2.1.2.png", + "images": [] + }, + "ubports-installer": { + "icon": "", + "images": [] + }, + "ubuntu-1604": { + "icon": "https://www.clipartmax.com/png/small/180-1805592_ubuntu-logo-clipart-ubuntu-transparent.png", + "images": [] + }, + "ubuntu-1804": { + "icon": "https://www.clipartmax.com/png/small/180-1805592_ubuntu-logo-clipart-ubuntu-transparent.png", + "images": [] + }, + "ubuntu-2004": { + "icon": "https://www.clipartmax.com/png/small/180-1805592_ubuntu-logo-clipart-ubuntu-transparent.png", + "images": [] + }, + "ubuntu-2204": { + "icon": "https://www.clipartmax.com/png/small/180-1805592_ubuntu-logo-clipart-ubuntu-transparent.png", + "images": [] + }, + "ubuntu-font": { + "icon": "", + "images": [] + }, + "ubuntuhere": { + "icon": "https://community.chocolatey.org/content/packageimages/ubuntuhere.0.0.5.20200501.png", + "images": [] + }, + "ucma4": { + "icon": "", + "images": [] + }, + "ucon64": { + "icon": "", + "images": [] + }, + "udemycouponfetcher": { + "icon": "", + "images": [] + }, + "ueexplorer": { + "icon": "", + "images": [] + }, + "uefitool": { + "icon": "https://community.chocolatey.org/content/packageimages/uefitool.0.28.0.png", + "images": [] + }, + "ueli": { + "icon": "https://community.chocolatey.org/content/packageimages/ueli.8.23.1.png", + "images": [] + }, + "uestudio": { + "icon": "", + "images": [] + }, + "ufraw": { + "icon": "", + "images": [] + }, + "ugene": { + "icon": "", + "images": [] + }, + "uget": { + "icon": "https://community.chocolatey.org/content/packageimages/uget.2.2.3.png", + "images": [] + }, + "uget-integrator": { + "icon": "", + "images": [] + }, + "ugrep": { + "icon": "", + "images": [] + }, + "uhe-ace": { + "icon": "https://community.chocolatey.org/content/packageimages/uhe-ace.1.4.2.png", + "images": [] + }, + "uhe-bazille": { + "icon": "https://community.chocolatey.org/content/packageimages/uhe-bazille.1.1.2.png", + "images": [] + }, + "uhe-colourcopy": { + "icon": "https://community.chocolatey.org/content/packageimages/uhe-colourcopy.1.0.12092.png", + "images": [] + }, + "uhe-diva": { + "icon": "https://community.chocolatey.org/content/packageimages/uhe-diva.1.4.5.png", + "images": [] + }, + "uhe-hive": { + "icon": "https://community.chocolatey.org/content/packageimages/uhe-hive.2.1.1.png", + "images": [] + }, + "uhe-mfm2": { + "icon": "https://community.chocolatey.org/content/packageimages/uhe-mfm2.2.5.0.png", + "images": [] + }, + "uhe-presswerk": { + "icon": "https://community.chocolatey.org/content/packageimages/uhe-presswerk.1.1.5.png", + "images": [] + }, + "uhe-repro": { + "icon": "https://community.chocolatey.org/content/packageimages/uhe-repro.1.1.12092.png", + "images": [] + }, + "uhe-satin": { + "icon": "https://community.chocolatey.org/content/packageimages/uhe-satin.1.3.2.png", + "images": [] + }, + "uhe-twangstrom": { + "icon": "https://community.chocolatey.org/content/packageimages/uhe-twangstrom.1.0.12092.png", + "images": [] + }, + "uhe-uhbik": { + "icon": "https://community.chocolatey.org/content/packageimages/uhe-uhbik.1.3.1.20200127.png", + "images": [] + }, + "uhe-zebra2": { + "icon": "https://community.chocolatey.org/content/packageimages/uhe-zebra2.2.9.12092.png", + "images": [] + }, + "uhexen2": { + "icon": "https://community.chocolatey.org/content/packageimages/uhexen2.1.5.9.png", + "images": [] + }, + "ui": { + "icon": "https://i.imgur.com/kTVX1t5.png", + "images": [] + }, + "ui-xaml-2-6": { + "icon": "https://user-images.githubusercontent.com/7389110/64734952-8a06ae80-d4df-11e9-830a-2c451a6c0694.png", + "images": [] + }, + "ui-xaml-2-7": { + "icon": "https://user-images.githubusercontent.com/7389110/64734952-8a06ae80-d4df-11e9-830a-2c451a6c0694.png", + "images": [] + }, + "ui-xaml-2-8": { + "icon": "https://user-images.githubusercontent.com/7389110/64734952-8a06ae80-d4df-11e9-830a-2c451a6c0694.png", + "images": [] + }, + "uiforetw": { + "icon": "", + "images": [] + }, + "uivonim": { + "icon": "", + "images": [] + }, + "ukinternationalkeyboard": { + "icon": "https://community.chocolatey.org/content/packageimages/ukinternationalkeyboard.2.0.0.png", + "images": [] + }, + "ulsviewer": { + "icon": "", + "images": [] + }, + "ultimate-cube": { + "icon": "", + "images": [] + }, + "ultimate-settings-panel-lite": { + "icon": "", + "images": [] + }, + "ultimatevocalremover": { + "icon": "", + "images": [] + }, + "ultra": { + "icon": "", + "images": [] + }, + "ultracopier": { + "icon": "https://community.chocolatey.org/content/packageimages/ultracopier.2.2.6.0.png", + "images": [] + }, + "ultradefrag": { + "icon": "https://static.techspot.com/images2/downloads/topdownload/2014/10/UltraDefrag.png", + "images": [ + "https://www.intowindows.com/wp-content/uploads/2012/01/UltraDefrag-for-Windows-10-64-bit.png" + ] + }, + "ultradmm": { + "icon": "https://community.chocolatey.org/content/packageimages/ultradmm.1.0.5.37035.png", + "images": [] + }, + "ultraedit": { + "icon": "", + "images": [] + }, + "ultraiso": { + "icon": "https://community.chocolatey.org/content/packageimages/ultraiso.9.7.6.3829.png", + "images": [] + }, + "ultramon": { + "icon": "https://community.chocolatey.org/content/packageimages/ultramon.3.4.1.png", + "images": [] + }, + "ultraschall": { + "icon": "https://community.chocolatey.org/content/packageimages/ultraschall.5.0.3.png", + "images": [] + }, + "ultrasearch": { + "icon": "https://community.chocolatey.org/content/packageimages/ultrasearch.4.8.4.png", + "images": [] + }, + "ultraviewer": { + "icon": "https://community.chocolatey.org/content/packageimages/ultraviewer.install.6.6.png", + "images": [] + }, + "ultravnc": { + "icon": "", + "images": [] + }, + "umbrello": { + "icon": "https://community.chocolatey.org/content/packageimages/umbrello.install.2.32.0.png", + "images": [] + }, + "umlet": { + "icon": "https://community.chocolatey.org/content/packageimages/umlet.15.0.0.20220711.png", + "images": [] + }, + "umple": { + "icon": "https://community.chocolatey.org/content/packageimages/umple.1.31.1.png", + "images": [] + }, + "ums": { + "icon": "https://community.chocolatey.org/content/packageimages/ums.13.2.0.png", + "images": [] + }, + "unar": { + "icon": "https://community.chocolatey.org/content/packageimages/unar.1.8.1.png", + "images": [] + }, + "unbound": { + "icon": "https://i.imgur.com/tM3e83k.png", + "images": [] + }, + "uncap": { + "icon": "", + "images": [] + }, + "unchecky": { + "icon": "https://unchecky.com/assets/img/fb-unchecky-logo.png", + "images": [ + "https://rammichael.com/wp-content/uploads/2014/01/unchecky_0_2.png" + ] + }, + "uncolored": { + "icon": "", + "images": [] + }, + "uncrustify": { + "icon": "", + "images": [] + }, + "undark": { + "icon": "", + "images": [] + }, + "undeluxe": { + "icon": "", + "images": [] + }, + "undercover10": { + "icon": "https://community.chocolatey.org/content/packageimages/undercover10.3.00.png", + "images": [] + }, + "undo-winrmconfig-during-shutdown": { + "icon": "https://community.chocolatey.org/content/packageimages/undo-winrmconfig-during-shutdown.1.2.0.20191031.png", + "images": [] + }, + "unetbootin": { + "icon": "https://community.chocolatey.org/content/packageimages/unetbootin.7.0.2.png", + "images": [] + }, + "unformat": { + "icon": "", + "images": [] + }, + "unfreez": { + "icon": "https://community.chocolatey.org/content/packageimages/unfreez.2.1.20171104.png", + "images": [] + }, + "unfx-proxy-checker": { + "icon": "", + "images": [] + }, + "ungit": { + "icon": "https://community.chocolatey.org/content/packageimages/ungit.0.10.1.png", + "images": [] + }, + "ungoogled-chromium": { + "icon": "https://community.chocolatey.org/content/packageimages/ungoogled-chromium.110.0.5481.781.png", + "images": [] + }, + "uni": { + "icon": "https://community.chocolatey.org/content/packageimages/uni.2.4.0.png", + "images": [] + }, + "uniconverter": { + "icon": "", + "images": [] + }, + "uniconverter-13": { + "icon": "", + "images": [] + }, + "uniconverter-cn": { + "icon": "", + "images": [] + }, + "unicornhttps": { + "icon": "", + "images": [] + }, + "unicornify": { + "icon": "", + "images": [] + }, + "uniextract": { + "icon": "https://community.chocolatey.org/content/packageimages/uniextract.install.1.6.1.png", + "images": [] + }, + "uniextract2": { + "icon": "", + "images": [] + }, + "unifiedremote": { + "icon": "https://community.chocolatey.org/content/packageimages/unifiedremote.3.13.0.2501.png", + "images": [] + }, + "uniflash": { + "icon": "", + "images": [] + }, + "unifying": { + "icon": "", + "images": [] + }, + "unifyingsoftware": { + "icon": "", + "images": [] + }, + "unigetui": { + "icon": "https://raw.githubusercontent.com/Devolutions/UniGetUI/main/media/icon.png", + "images": [ + "https://raw.githubusercontent.com/Devolutions/UniGetUI/main/media/UniGetUI_1.png", + "https://raw.githubusercontent.com/Devolutions/UniGetUI/main/media/UniGetUI_3.png", + "https://raw.githubusercontent.com/Devolutions/UniGetUI/main/media/UniGetUI_6.png" + ] + }, + "unihex": { + "icon": "", + "images": [] + }, + "unikey": { + "icon": "", + "images": [] + }, + "uninstaller": { + "icon": "https://www.iobit.com/tpl/images/product-icons/icon_96_199.png", + "images": [ + "https://www.iobit.com/tpl/images/screenshot/iu/software_uninstal_655.png", + "https://www.iobit.com/tpl/images/screenshot/iu/uninstalling_24.png", + "https://www.iobit.com/tpl/images/screenshot/iu/install_monitor_42.png", + "https://www.iobit.com/tpl/images/screenshot/iu/software_health_516.png" + ] + }, + "uninstalltool": { + "icon": "https://community.chocolatey.org/content/packageimages/uninstalltool.portable.3.7.2.png", + "images": [ + "https://i.postimg.cc/3J6sG5dT/image.png", + "https://i.postimg.cc/bJ3MN4K4/image.png", + "https://i.postimg.cc/J0F2jZ7q/image.png", + "https://i.postimg.cc/PfV9Gsbw/image.png", + "https://i.postimg.cc/Tww0Q14H/image.png" + ] + }, + "uninstallview": { + "icon": "https://i.postimg.cc/jjHJnc4d/image.png", + "images": [ + "https://i.postimg.cc/HxT8wM6w/image.png" + ] + }, + "unison": { + "icon": "https://community.chocolatey.org/content/packageimages/unison.2.53.0.png", + "images": [] + }, + "unit-test-boilerplate-generator": { + "icon": "https://community.chocolatey.org/content/packageimages/unit-test-boilerplate-generator.2.7.3.png", + "images": [] + }, + "units": { + "icon": "", + "images": [] + }, + "unity": { + "icon": "https://community.chocolatey.org/content/packageimages/unity.2022.2.8.png", + "images": [] + }, + "unity-2020": { + "icon": "https://companieslogo.com/img/orig/U-ea48bc1d.png", + "images": [] + }, + "unity-2021": { + "icon": "https://companieslogo.com/img/orig/U-ea48bc1d.png", + "images": [] + }, + "unity-2022": { + "icon": "https://companieslogo.com/img/orig/U-ea48bc1d.png", + "images": [] + }, + "unity-android": { + "icon": "https://community.chocolatey.org/content/packageimages/unity-android.2022.2.8.png", + "images": [] + }, + "unity-appletv": { + "icon": "https://community.chocolatey.org/content/packageimages/unity-appletv.2022.2.8.png", + "images": [] + }, + "unity-docs": { + "icon": "https://community.chocolatey.org/content/packageimages/unity-docs.2022.2.8.png", + "images": [] + }, + "unity-example-project": { + "icon": "https://community.chocolatey.org/content/packageimages/unity-example-project.2018.1.7.png", + "images": [] + }, + "unity-facebook": { + "icon": "https://community.chocolatey.org/content/packageimages/unity-facebook.2019.2.18.png", + "images": [] + }, + "unity-hub": { + "icon": "https://community.chocolatey.org/content/packageimages/unity-hub.3.9.1.png", + "images": [] + }, + "unity-il2cpp": { + "icon": "https://community.chocolatey.org/content/packageimages/unity-il2cpp.2020.1.16.20201208.png", + "images": [] + }, + "unity-ios": { + "icon": "https://community.chocolatey.org/content/packageimages/unity-ios.2022.2.8.png", + "images": [] + }, + "unity-linux": { + "icon": "https://community.chocolatey.org/content/packageimages/unity-linux.2021.2.16.1.png", + "images": [] + }, + "unity-linux-il2cpp": { + "icon": "https://community.chocolatey.org/content/packageimages/unity-linux-il2cpp.2022.2.8.png", + "images": [] + }, + "unity-linux-mono": { + "icon": "https://community.chocolatey.org/content/packageimages/unity-linux-mono.2022.2.8.png", + "images": [] + }, + "unity-linux-server": { + "icon": "https://community.chocolatey.org/content/packageimages/unity-linux-server.2022.2.8.png", + "images": [] + }, + "unity-lumin": { + "icon": "https://community.chocolatey.org/content/packageimages/unity-lumin.2021.2.10.1.png", + "images": [] + }, + "unity-mac": { + "icon": "https://community.chocolatey.org/content/packageimages/unity-mac.2022.2.8.png", + "images": [] + }, + "unity-mac-server": { + "icon": "https://community.chocolatey.org/content/packageimages/unity-mac-server.2022.2.8.png", + "images": [] + }, + "unity-samsungtv": { + "icon": "https://community.chocolatey.org/content/packageimages/unity-samsungtv.2017.2.1.20180517.png", + "images": [] + }, + "unity-standard-assets": { + "icon": "https://community.chocolatey.org/content/packageimages/unity-standard-assets.2018.1.7.png", + "images": [] + }, + "unity-tizen": { + "icon": "https://community.chocolatey.org/content/packageimages/unity-tizen.2017.2.1.20180517.png", + "images": [] + }, + "unity-vuforia": { + "icon": "https://community.chocolatey.org/content/packageimages/unity-vuforia.2019.1.12.20190801.png", + "images": [] + }, + "unity-webgl": { + "icon": "https://community.chocolatey.org/content/packageimages/unity-webgl.2022.2.8.png", + "images": [] + }, + "unity-win-il2cpp": { + "icon": "https://community.chocolatey.org/content/packageimages/unity-win-il2cpp.2022.2.8.png", + "images": [] + }, + "unity-windows-server": { + "icon": "https://community.chocolatey.org/content/packageimages/unity-windows-server.2022.2.8.png", + "images": [] + }, + "unity-windows-store": { + "icon": "https://community.chocolatey.org/content/packageimages/unity-windows-store.2022.2.8.png", + "images": [] + }, + "unity4": { + "icon": "https://community.chocolatey.org/content/packageimages/unity4.4.6.0.png", + "images": [] + }, + "unityhub": { + "icon": "", + "images": [] + }, + "unitywebplayer": { + "icon": "https://community.chocolatey.org/content/packageimages/unitywebplayer.4.6.0.png", + "images": [] + }, + "universal-ctags": { + "icon": "", + "images": [] + }, + "universal-extractor": { + "icon": "https://community.chocolatey.org/content/packageimages/universal-extractor.1.6.1.20161126.png", + "images": [] + }, + "universal-firmware-updater": { + "icon": "", + "images": [] + }, + "universal-gcode-sender": { + "icon": "", + "images": [] + }, + "universal-mediacreationtool": { + "icon": "", + "images": [] + }, + "universal-usb-installer": { + "icon": "https://community.chocolatey.org/content/packageimages/universal-usb-installer.2.0.1.400.png", + "images": [] + }, + "universaladbdriver": { + "icon": "", + "images": [] + }, + "universalforwarder": { + "icon": "", + "images": [] + }, + "universalpausebutton": { + "icon": "", + "images": [] + }, + "uniws": { + "icon": "https://community.chocolatey.org/content/packageimages/uniws.1.03.png", + "images": [] + }, + "unknownhorizons": { + "icon": "", + "images": [] + }, + "unlocker": { + "icon": "", + "images": [] + }, + "unofficial-google-chat-electron": { + "icon": "https://community.chocolatey.org/content/packageimages/unofficial-Google-Chat-Electron.2.20.0.png", + "images": [] + }, + "unofficial-google-docs-client": { + "icon": "https://community.chocolatey.org/content/packageimages/unofficial-google-docs-client.2022.6.1.20220727.png", + "images": [] + }, + "unofficial-google-meet": { + "icon": "", + "images": [] + }, + "unpaper": { + "icon": "", + "images": [] + }, + "unrar": { + "icon": "https://community.chocolatey.org/content/packageimages/unrar.5.30.png", + "images": [] + }, + "unreal-commander": { + "icon": "https://community.chocolatey.org/content/packageimages/unreal-commander.4.21.1560.png", + "images": [] + }, + "unreal-linux-toolchain": { + "icon": "https://community.chocolatey.org/content/packageimages/unreal-linux-toolchain.20.13.0.1.png", + "images": [] + }, + "unreal-speccy": { + "icon": "https://community.chocolatey.org/content/packageimages/unreal-speccy.0.0.57.png", + "images": [] + }, + "unrealcommander": { + "icon": "", + "images": [] + }, + "unreleasedgithubhistory-portable": { + "icon": "", + "images": [] + }, + "unshield": { + "icon": "", + "images": [] + }, + "unsplashwallpapers": { + "icon": "", + "images": [] + }, + "unsubscan": { + "icon": "", + "images": [] + }, + "unxutils": { + "icon": "", + "images": [] + }, + "unzip": { + "icon": "", + "images": [] + }, + "up": { + "icon": "", + "images": [] + }, + "up2date": { + "icon": "https://community.chocolatey.org/content/packageimages/up2date.2.3.0.png", + "images": [] + }, + "upack": { + "icon": "", + "images": [] + }, + "upackx": { + "icon": "", + "images": [] + }, + "upbound-cli": { + "icon": "", + "images": [] + }, + "upcount": { + "icon": "", + "images": [] + }, + "updateassistant": { + "icon": "", + "images": [] + }, + "updateretriever": { + "icon": "", + "images": [] + }, + "updateutility": { + "icon": "", + "images": [] + }, + "upgit": { + "icon": "", + "images": [] + }, + "uplay": { + "icon": "", + "images": [] + }, + "uploader": { + "icon": "", + "images": [] + }, + "upm": { + "icon": "", + "images": [] + }, + "upscayl": { + "icon": "https://community.chocolatey.org/content/packageimages/upscayl.2.0.1.png", + "images": [] + }, + "upsource": { + "icon": "https://community.chocolatey.org/content/packageimages/upsource.2020.1.1802.png", + "images": [] + }, + "uptodatedownloader": { + "icon": "https://community.chocolatey.org/content/packageimages/uptodatedownloader.portable.1.4.0.1201.png", + "images": [] + }, + "upx": { + "icon": "", + "images": [] + }, + "uranossoftphone": { + "icon": "", + "images": [] + }, + "urbackup-client": { + "icon": "", + "images": [] + }, + "urbackup-server": { + "icon": "", + "images": [] + }, + "urllib3": { + "icon": "https://i.postimg.cc/90Nw8MnZ/urllib3.png", + "images": [] + }, + "urlprotocolview": { + "icon": "https://community.chocolatey.org/content/packageimages/urlprotocolview.1.15.png", + "images": [] + }, + "urlstringgrabber": { + "icon": "https://community.chocolatey.org/content/packageimages/urlstringgrabber.1.11.png", + "images": [] + }, + "usagestats": { + "icon": "", + "images": [] + }, + "usamimi-hurricane": { + "icon": "https://community.chocolatey.org/content/packageimages/usamimi-hurricane.0.30.png", + "images": [] + }, + "usbclient": { + "icon": "", + "images": [] + }, + "usbdeview": { + "icon": "https://community.chocolatey.org/content/packageimages/usbdeview.3.06.png", + "images": [] + }, + "usbdlm": { + "icon": "https://static.techspot.com/images2/downloads/topdownload/2016/05/pendrive.png", + "images": [] + }, + "usbimager": { + "icon": "", + "images": [] + }, + "usbimagetool": { + "icon": "", + "images": [] + }, + "usbip": { + "icon": "", + "images": [] + }, + "usbipd-win": { + "icon": "", + "images": [] + }, + "usbit": { + "icon": "https://community.chocolatey.org/content/packageimages/usbit.1.90.png", + "images": [] + }, + "usblogon": { + "icon": "https://community.chocolatey.org/content/packageimages/usblogon.1.8.1.2.png", + "images": [] + }, + "usbmididriver": { + "icon": "", + "images": [] + }, + "usbnetworkgate": { + "icon": "", + "images": [] + }, + "usbpcap": { + "icon": "", + "images": [] + }, + "usbsafelyremove": { + "icon": "", + "images": [ + "https://i.postimg.cc/d3X6TQB5/image.png", + "https://i.postimg.cc/yNBPRbmC/image.png", + "https://i.postimg.cc/Px5Q3vV6/image.png", + "https://i.postimg.cc/gkZqTW4P/image.png", + "https://i.postimg.cc/1300yrLC/image.png", + "https://i.postimg.cc/9Q1pGBJ4/image.png" + ] + }, + "usbserver": { + "icon": "", + "images": [] + }, + "userassistview": { + "icon": "https://community.chocolatey.org/content/packageimages/userassistview.1.02.png", + "images": [] + }, + "userdiag": { + "icon": "", + "images": [] + }, + "usnjrnl2csv": { + "icon": "", + "images": [] + }, + "usql": { + "icon": "", + "images": [] + }, + "ussf": { + "icon": "", + "images": [] + }, + "ut-launcher": { + "icon": "", + "images": [] + }, + "utaformatix": { + "icon": "", + "images": [] + }, + "util-linux-ng": { + "icon": "", + "images": [] + }, + "util-linux-ng-getopt": { + "icon": "", + "images": [] + }, + "util-linux-ng-libintl3": { + "icon": "", + "images": [] + }, + "utility": { + "icon": "", + "images": [] + }, + "utilso": { + "icon": "", + "images": [] + }, + "utools": { + "icon": "https://i.postimg.cc/7hGyPTRQ/utools.png", + "images": [] + }, + "utorrent-easy-client-chrome": { + "icon": "", + "images": [] + }, + "utorrent-link-sender-chrome": { + "icon": "https://community.chocolatey.org/content/packageimages/utorrent-link-sender-chrome.0.0.9.png", + "images": [] + }, + "utorrent-webui": { + "icon": "", + "images": [] + }, + "utsu": { + "icon": "", + "images": [] + }, + "utvideo": { + "icon": "", + "images": [] + }, + "utvideocodecsuite": { + "icon": "", + "images": [] + }, + "uupmediacreator": { + "icon": "", + "images": [] + }, + "uutils-coreutils": { + "icon": "", + "images": [] + }, + "uutils-coreutils-lean": { + "icon": "", + "images": [] + }, + "uvtools": { + "icon": "https://raw.githubusercontent.com/sn4k3/UVtools/master/UVtools.CAD/UVtools.png", + "images": [ + "https://raw.githubusercontent.com/sn4k3/UVtools/master/wiki/UI1.png", + "https://raw.githubusercontent.com/sn4k3/UVtools/master/wiki/UI2.png" + ] + }, + "uwamp": { + "icon": "", + "images": [] + }, + "uwphook": { + "icon": "", + "images": [] + }, + "uws": { + "icon": "https://community.chocolatey.org/content/packageimages/UWS.2.0.21.png", + "images": [] + }, + "uxl-launcher": { + "icon": "", + "images": [] + }, + "v": { + "icon": "", + "images": [] + }, + "v-medal": { + "icon": "", + "images": [] + }, + "v-prowisereflect": { + "icon": "", + "images": [] + }, + "v2ray": { + "icon": "", + "images": [] + }, + "v2ray-electron": { + "icon": "", + "images": [] + }, + "v2raya": { + "icon": "", + "images": [] + }, + "v2rayn": { + "icon": "https://community.chocolatey.org/content/packageimages/v2rayn.6.13.png", + "images": [] + }, + "vaccine": { + "icon": "", + "images": [] + }, + "vacuum-im": { + "icon": "https://community.chocolatey.org/content/packageimages/vacuum-im.1.2.5.png", + "images": [] + }, + "vagrant": { + "icon": "https://community.chocolatey.org/content/packageimages/vagrant.2.3.4.png", + "images": [] + }, + "vagrant-manager": { + "icon": "", + "images": [] + }, + "vagrant-plugins": { + "icon": "", + "images": [] + }, + "vagrant-vmware-utility": { + "icon": "https://community.chocolatey.org/content/packageimages/vagrant-vmware-utility.1.0.21.png", + "images": [] + }, + "vagrant-winrm-config": { + "icon": "", + "images": [] + }, + "vajehdan": { + "icon": "", + "images": [] + }, + "vale": { + "icon": "https://community.chocolatey.org/content/packageimages/vale.2.22.0.png", + "images": [] + }, + "valgrindparsetools": { + "icon": "", + "images": [] + }, + "valleybenchmark": { + "icon": "", + "images": [] + }, + "valorant": { + "icon": "https://zv915ylvcs.ufs.sh/f/fYIgEizARqiSm9QzvKbv3WNIoXHVpASdBFORtzZ6JCYTeDnh", + "images": [] + }, + "valorant-ap": { + "icon": "", + "images": [] + }, + "valorant-br": { + "icon": "", + "images": [] + }, + "valorant-eu": { + "icon": "", + "images": [] + }, + "valorant-na": { + "icon": "", + "images": [] + }, + "valorantrandomizer": { + "icon": "", + "images": [] + }, + "vals": { + "icon": "", + "images": [] + }, + "vanillarenewed": { + "icon": "", + "images": [] + }, + "vapoursynth": { + "icon": "", + "images": [] + }, + "vapoursyntheditor": { + "icon": "", + "images": [] + }, + "varpanel": { + "icon": "https://community.chocolatey.org/content/packageimages/varpanel.1.1.0.png", + "images": [] + }, + "vassal": { + "icon": "", + "images": [] + }, + "vatis": { + "icon": "", + "images": [] + }, + "vatspy": { + "icon": "", + "images": [] + }, + "vault": { + "icon": "", + "images": [] + }, + "vazir-code-font": { + "icon": "https://community.chocolatey.org/content/packageimages/vazir-code-font.1.1.2.png", + "images": [] + }, + "vb-cable": { + "icon": "", + "images": [] + }, + "vb5runtime": { + "icon": "", + "images": [] + }, + "vbindiff": { + "icon": "", + "images": [] + }, + "vboxguestadditions": { + "icon": "", + "images": [] + }, + "vboxheadlesstray": { + "icon": "", + "images": [] + }, + "vboxvmservice": { + "icon": "", + "images": [] + }, + "vcam": { + "icon": "", + "images": [] + }, + "vcbuildtools": { + "icon": "https://community.chocolatey.org/content/packageimages/vcbuildtools.2015.4.png", + "images": [] + }, + "vcexpress2010": { + "icon": "https://community.chocolatey.org/content/packageimages/VCExpress2010.0.1.0.20140915.png", + "images": [] + }, + "vclibs": { + "icon": "https://i.postimg.cc/rwGzh5vf/Visual-Studio-Icon-2022.png", + "images": [] + }, + "vclibs-desktop-14": { + "icon": "https://i.postimg.cc/rwGzh5vf/Visual-Studio-Icon-2022.png", + "images": [] + }, + "vclip": { + "icon": "https://community.chocolatey.org/content/packageimages/vclip.2.0.0.1.png", + "images": [] + }, + "vcpkg": { + "icon": "https://devblogs.microsoft.com/cppblog/wp-content/uploads/sites/9/2021/05/vcpkg-product-mark.png", + "images": [] + }, + "vcpkg-cmake": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/e/ef/CMake_logo.svg/1200px-CMake_logo.svg.png", + "images": [] + }, + "vcpkg-cmake-config": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/e/ef/CMake_logo.svg/1200px-CMake_logo.svg.png", + "images": [] + }, + "vcpkg-cmake-get-vars": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/e/ef/CMake_logo.svg/1200px-CMake_logo.svg.png", + "images": [] + }, + "vcpkg-tool-meson": { + "icon": "https://static-00.iconduck.com/assets.00/file-type-meson-icon-256x256-ias65td0.png", + "images": [] + }, + "vcredist": { + "icon": "https://i.postimg.cc/rwGzh5vf/Visual-Studio-Icon-2022.png", + "images": [] + }, + "vcredist-2005-x64": { + "icon": "https://i.postimg.cc/rwGzh5vf/Visual-Studio-Icon-2022.png", + "images": [] + }, + "vcredist-2005-x86": { + "icon": "https://i.postimg.cc/rwGzh5vf/Visual-Studio-Icon-2022.png", + "images": [] + }, + "vcredist-2008-x64": { + "icon": "https://i.postimg.cc/rwGzh5vf/Visual-Studio-Icon-2022.png", + "images": [] + }, + "vcredist-2008-x86": { + "icon": "https://i.postimg.cc/rwGzh5vf/Visual-Studio-Icon-2022.png", + "images": [] + }, + "vcredist-2010-x64": { + "icon": "https://i.postimg.cc/rwGzh5vf/Visual-Studio-Icon-2022.png", + "images": [] + }, + "vcredist-2010-x86": { + "icon": "https://i.postimg.cc/rwGzh5vf/Visual-Studio-Icon-2022.png", + "images": [] + }, + "vcredist-2012-x64": { + "icon": "https://i.postimg.cc/rwGzh5vf/Visual-Studio-Icon-2022.png", + "images": [] + }, + "vcredist-2012-x86": { + "icon": "https://i.postimg.cc/rwGzh5vf/Visual-Studio-Icon-2022.png", + "images": [] + }, + "vcredist-2013-x64": { + "icon": "https://i.postimg.cc/rwGzh5vf/Visual-Studio-Icon-2022.png", + "images": [] + }, + "vcredist-2013-x86": { + "icon": "https://i.postimg.cc/rwGzh5vf/Visual-Studio-Icon-2022.png", + "images": [] + }, + "vcredist-2015+-x64": { + "icon": "https://i.postimg.cc/rwGzh5vf/Visual-Studio-Icon-2022.png", + "images": [] + }, + "vcredist-2015+-x86": { + "icon": "https://i.postimg.cc/rwGzh5vf/Visual-Studio-Icon-2022.png", + "images": [] + }, + "vcredist-2019-arm64": { + "icon": "https://i.postimg.cc/rwGzh5vf/Visual-Studio-Icon-2022.png", + "images": [] + }, + "vcredist-2022-arm64": { + "icon": "https://i.postimg.cc/rwGzh5vf/Visual-Studio-Icon-2022.png", + "images": [] + }, + "vcredist-all": { + "icon": "https://community.chocolatey.org/content/packageimages/vcredist-all.1.0.1.png", + "images": [] + }, + "vcredist-2015-x64": { + "icon": "https://i.postimg.cc/rwGzh5vf/Visual-Studio-Icon-2022.png", + "images": [] + }, + "vcredist-2015-x86": { + "icon": "https://i.postimg.cc/rwGzh5vf/Visual-Studio-Icon-2022.png", + "images": [] + }, + "vcredist140": { + "icon": "https://community.chocolatey.org/content/packageimages/vcredist140.14.34.31938.png", + "images": [] + }, + "vcredist2005": { + "icon": "https://i.postimg.cc/rwGzh5vf/Visual-Studio-Icon-2022.png", + "images": [] + }, + "vcredist2008": { + "icon": "https://i.postimg.cc/rwGzh5vf/Visual-Studio-Icon-2022.png", + "images": [] + }, + "vcredist2010": { + "icon": "https://i.postimg.cc/rwGzh5vf/Visual-Studio-Icon-2022.png", + "images": [] + }, + "vcredist2012": { + "icon": "https://i.postimg.cc/rwGzh5vf/Visual-Studio-Icon-2022.png", + "images": [] + }, + "vcredist2013": { + "icon": "https://i.postimg.cc/rwGzh5vf/Visual-Studio-Icon-2022.png", + "images": [] + }, + "vcredist2015": { + "icon": "https://i.postimg.cc/rwGzh5vf/Visual-Studio-Icon-2022.png", + "images": [] + }, + "vcredist2017": { + "icon": "https://i.postimg.cc/rwGzh5vf/Visual-Studio-Icon-2022.png", + "images": [] + }, + "vcredist2019": { + "icon": "https://i.postimg.cc/rwGzh5vf/Visual-Studio-Icon-2022.png", + "images": [] + }, + "vcredist2022": { + "icon": "https://i.postimg.cc/rwGzh5vf/Visual-Studio-Icon-2022.png", + "images": [] + }, + "vcvrack": { + "icon": "https://community.chocolatey.org/content/packageimages/vcvrack.2.1.2.png", + "images": [] + }, + "vcxsrv": { + "icon": "https://community.chocolatey.org/content/packageimages/vcxsrv.1.20.14.0.png", + "images": [] + }, + "vdagent": { + "icon": "", + "images": [] + }, + "vdesk": { + "icon": "", + "images": [] + }, + "vdhcoapp": { + "icon": "", + "images": [] + }, + "vector": { + "icon": "", + "images": [] + }, + "veeam-agent": { + "icon": "https://community.chocolatey.org/content/packageimages/veeam-agent.6.0.0.960.png", + "images": [] + }, + "veeam-backup-and-replication-catalog": { + "icon": "https://community.chocolatey.org/content/packageimages/veeam-backup-and-replication-catalog.11.0.1.1261.png", + "images": [] + }, + "veeam-backup-and-replication-console": { + "icon": "https://community.chocolatey.org/content/packageimages/veeam-backup-and-replication-console.11.0.1.1261.png", + "images": [] + }, + "veeam-backup-and-replication-iso": { + "icon": "https://community.chocolatey.org/content/packageimages/veeam-backup-and-replication-iso.11.0.1.1261.png", + "images": [] + }, + "veeam-backup-and-replication-management": { + "icon": "https://community.chocolatey.org/content/packageimages/veeam-backup-and-replication-management.11.0.1.1261.png", + "images": [] + }, + "veeam-backup-and-replication-server": { + "icon": "https://community.chocolatey.org/content/packageimages/veeam-backup-and-replication-server.11.0.1.1261.png", + "images": [] + }, + "veeam-backup-for-microsoft-365": { + "icon": "https://community.chocolatey.org/content/packageimages/veeam-backup-for-microsoft-365.7.0.0.2911.png", + "images": [] + }, + "veeam-backup-for-microsoft-365-console": { + "icon": "https://community.chocolatey.org/content/packageimages/veeam-backup-for-microsoft-365-console.7.0.0.2911.png", + "images": [] + }, + "veeam-backup-for-microsoft-365-iso": { + "icon": "https://community.chocolatey.org/content/packageimages/veeam-backup-for-microsoft-365-iso.7.0.0.2911.png", + "images": [] + }, + "veeam-backup-for-microsoft-365-management": { + "icon": "https://community.chocolatey.org/content/packageimages/veeam-backup-for-microsoft-365-management.7.0.0.2911.png", + "images": [] + }, + "veeam-backup-for-microsoft-365-rest-api": { + "icon": "", + "images": [] + }, + "veeam-backup-for-microsoft-365-server": { + "icon": "", + "images": [] + }, + "veeam-backup-for-microsoft-office-365": { + "icon": "https://community.chocolatey.org/content/packageimages/veeam-backup-for-microsoft-office-365.6.0.0.png", + "images": [] + }, + "veeam-backup-for-microsoft-office-365-console": { + "icon": "https://community.chocolatey.org/content/packageimages/veeam-backup-for-microsoft-office-365-console.6.0.0.png", + "images": [] + }, + "veeam-backup-for-microsoft-office-365-management": { + "icon": "https://community.chocolatey.org/content/packageimages/veeam-backup-for-microsoft-office-365-management.6.0.0.png", + "images": [] + }, + "veeam-endpoint-backup-free": { + "icon": "https://community.chocolatey.org/content/packageimages/veeam-endpoint-backup-free.1.5.png", + "images": [] + }, + "veeam-explorer-for-microsoft-active-directory": { + "icon": "https://community.chocolatey.org/content/packageimages/veeam-explorer-for-microsoft-active-directory.11.0.1.1261.png", + "images": [] + }, + "veeam-explorer-for-microsoft-exchange": { + "icon": "https://community.chocolatey.org/content/packageimages/veeam-explorer-for-microsoft-exchange.11.0.1.1261.png", + "images": [] + }, + "veeam-explorer-for-microsoft-exchange-o365": { + "icon": "https://community.chocolatey.org/content/packageimages/veeam-explorer-for-microsoft-exchange-o365.6.0.0.png", + "images": [] + }, + "veeam-explorer-for-microsoft-sharepoint": { + "icon": "https://community.chocolatey.org/content/packageimages/veeam-explorer-for-microsoft-sharepoint.11.0.1.1261.png", + "images": [] + }, + "veeam-explorer-for-microsoft-sharepoint-o365": { + "icon": "https://community.chocolatey.org/content/packageimages/veeam-explorer-for-microsoft-sharepoint-o365.6.0.0.png", + "images": [] + }, + "veeam-explorer-for-microsoft-sql-server": { + "icon": "https://community.chocolatey.org/content/packageimages/veeam-explorer-for-microsoft-sql-server.11.0.1.1261.png", + "images": [] + }, + "veeam-explorer-for-microsoft-teams": { + "icon": "https://community.chocolatey.org/content/packageimages/veeam-explorer-for-microsoft-teams.11.0.1.1261.png", + "images": [] + }, + "veeam-explorer-for-microsoft-teams-m365": { + "icon": "https://community.chocolatey.org/content/packageimages/veeam-explorer-for-microsoft-teams-m365.7.0.0.2911.png", + "images": [] + }, + "veeam-explorer-for-microsoft-teams-o365": { + "icon": "https://community.chocolatey.org/content/packageimages/veeam-explorer-for-microsoft-teams-o365.6.0.0.png", + "images": [] + }, + "veeam-explorer-for-oracle": { + "icon": "https://community.chocolatey.org/content/packageimages/veeam-explorer-for-oracle.11.0.1.1261.png", + "images": [] + }, + "veeam-one-agent": { + "icon": "https://community.chocolatey.org/content/packageimages/veeam-one-agent.11.0.1.1880.png", + "images": [] + }, + "veeam-one-iso": { + "icon": "https://community.chocolatey.org/content/packageimages/veeam-one-iso.11.0.1.1880.png", + "images": [] + }, + "veeam-one-monitor-client": { + "icon": "https://community.chocolatey.org/content/packageimages/veeam-one-monitor-client.11.0.1.1880.png", + "images": [] + }, + "veeam-one-monitor-server": { + "icon": "https://community.chocolatey.org/content/packageimages/veeam-one-monitor-server.11.0.1.1880.png", + "images": [] + }, + "veeam-one-reporter-server": { + "icon": "https://community.chocolatey.org/content/packageimages/veeam-one-reporter-server.11.0.1.1880.png", + "images": [] + }, + "veeam-one-reporter-web": { + "icon": "https://community.chocolatey.org/content/packageimages/veeam-one-reporter-web.11.0.1.1880.png", + "images": [] + }, + "veeam-service-provider-console-connectwise-automate-plugin": { + "icon": "", + "images": [] + }, + "veeam-service-provider-console-connectwise-manage-service": { + "icon": "", + "images": [] + }, + "veeam-service-provider-console-connectwise-manage-webui": { + "icon": "", + "images": [] + }, + "veeam-service-provider-console-server": { + "icon": "https://community.chocolatey.org/content/packageimages/veeam-service-provider-console-server.7.0.0.12777.png", + "images": [] + }, + "veeam-service-provider-console-ssp-agent-service": { + "icon": "https://community.chocolatey.org/content/packageimages/veeam-service-provider-console-ssp-agent-service.7.0.0.12777.png", + "images": [] + }, + "veeam-service-provider-console-ssp-agent-webui": { + "icon": "", + "images": [] + }, + "veeam-service-provider-console-webui": { + "icon": "https://community.chocolatey.org/content/packageimages/veeam-service-provider-console-webui.7.0.0.12777.png", + "images": [] + }, + "velero": { + "icon": "https://community.chocolatey.org/content/packageimages/velero.1.10.0.png", + "images": [] + }, + "velociraptor": { + "icon": "", + "images": [] + }, + "velocity": { + "icon": "", + "images": [] + }, + "vencord-installer": { + "icon": "https://i.ibb.co/60R4PZVv/113042587.png", + "images": [ + "https://user-images.githubusercontent.com/45497981/226734476-5fb42420-844d-4e27-ae06-4799118e086e.png" + ] + }, + "vendir": { + "icon": "https://community.chocolatey.org/content/packageimages/vendir.0.32.0.png", + "images": [] + }, + "ventoy": { + "icon": "https://pics.computerbase.de/9/3/5/0/1/logo-256.png", + "images": [ + "https://i.postimg.cc/ryJT5j1y/image.png", + "https://i.postimg.cc/dQTHYV0b/image.png", + "https://i.postimg.cc/fTNKQ7pd/image.png", + "https://i.postimg.cc/2S5nC0w1/image.png", + "https://i.postimg.cc/59qzvhKH/image.png", + "https://i.postimg.cc/BQ7XB4Tv/image.png" + ] + }, + "veracity": { + "icon": "", + "images": [] + }, + "veracrypt": { + "icon": "https://i.postimg.cc/PxGjtFmh/image.png", + "images": [ + "https://i.postimg.cc/pLg785yJ/image.png", + "https://i.postimg.cc/L8fDcC6j/image.png", + "https://i.postimg.cc/s2mYztFG/image.png", + "https://i.postimg.cc/BbLHxbj2/image.png", + "https://i.postimg.cc/dtCG37PY/image.png", + "https://i.postimg.cc/CxHDCWxr/image.png", + "https://i.postimg.cc/nMfjBkbt/image.png", + "https://i.postimg.cc/fRhg5txz/image.png" + ] + }, + "vercel": { + "icon": "https://zv915ylvcs.ufs.sh/f/fYIgEizARqiSKv03FUtUaGqDZpvIXcO2YTyfjCHRkoFNAmxn", + "images": [] + }, + "verysleepy": { + "icon": "", + "images": [] + }, + "vesta": { + "icon": "", + "images": [] + }, + "vesktop": { + "icon": "https://i.ibb.co/vGXwKRp/image.png", + "images": [ + "https://i.ibb.co/qMnD6bVM/image.png" + ] + }, + "vet": { + "icon": "https://community.chocolatey.org/content/packageimages/vet.1.4.png", + "images": [] + }, + "veusz": { + "icon": "https://community.chocolatey.org/content/packageimages/veusz.3.6.2.png", + "images": [] + }, + "vexcode": { + "icon": "https://community.chocolatey.org/content/packageimages/vexcode.2.4.0.png", + "images": [] + }, + "vexcodepro": { + "icon": "https://community.chocolatey.org/content/packageimages/vexcodepro.2.5.0.png", + "images": [] + }, + "veyon": { + "icon": "https://community.chocolatey.org/content/packageimages/veyon.4.7.5.png", + "images": [] + }, + "vfsforgit": { + "icon": "", + "images": [] + }, + "vhs": { + "icon": "", + "images": [] + }, + "via": { + "icon": "", + "images": [] + }, + "vial": { + "icon": "", + "images": [] + }, + "viana": { + "icon": "", + "images": [] + }, + "viber": { + "icon": "https://i.imgur.com/NNuAkJi.png", + "images": [] + }, + "vibrance-gui": { + "icon": "", + "images": [] + }, + "vibrancegui": { + "icon": "https://community.chocolatey.org/content/packageimages/vibrancegui.2.0.0.0.png", + "images": [] + }, + "victoria": { + "icon": "https://i.postimg.cc/1zLrVmLp/image.png", + "images": [ + "https://i.postimg.cc/gkChKSMW/image.png", + "https://i.postimg.cc/DzbYMMhP/image.png", + "https://i.postimg.cc/bYRVWn7W/image.png", + "https://i.postimg.cc/L5VWVgSd/image.png", + "https://i.postimg.cc/P55g2yNS/image.png", + "https://i.postimg.cc/4NSPRQBL/image.png" + ] + }, + "victormononf": { + "icon": "https://community.chocolatey.org/content/packageimages/victormononf.2.1.0.png", + "images": [] + }, + "vidcoder": { + "icon": "https://raw.githubusercontent.com/RandomEngy/VidCoder/master/VidCoder/Icons/VidCoder.png", + "images": [ + "https://vidcoder.net/images/main.png", + "https://vidcoder.net/images/preview.png", + "https://vidcoder.net/images/encoding_settings.png" + ] + }, + "vidcoder-beta": { + "icon": "https://raw.githubusercontent.com/RandomEngy/VidCoder/master/VidCoder/Icons/VidCoder.png", + "images": [] + }, + "vidcutter": { + "icon": "https://community.chocolatey.org/content/packageimages/vidcutter.6.0.5.1.png", + "images": [] + }, + "viddy": { + "icon": "", + "images": [] + }, + "video-ad-block-for-twitch-chrome": { + "icon": "https://community.chocolatey.org/content/packageimages/video-ad-block-for-twitch-chrome.5.2.3.png", + "images": [] + }, + "video-card-stability-test": { + "icon": "https://community.chocolatey.org/content/packageimages/video-card-stability-test.1.0.0.320161103.png", + "images": [] + }, + "video-compare": { + "icon": "", + "images": [] + }, + "video-hub-app-demo": { + "icon": "", + "images": [] + }, + "video-repair-software": { + "icon": "https://community.chocolatey.org/content/packageimages/video-repair-software.4.0.0.1.png", + "images": [] + }, + "video-thumbnails-maker": { + "icon": "", + "images": [] + }, + "videocacheview": { + "icon": "https://i.postimg.cc/0jWkJM42/image.png", + "images": [ + "https://i.postimg.cc/05c24FNx/image.png" + ] + }, + "videoder": { + "icon": "https://community.chocolatey.org/content/packageimages/videoder.1.0.9.png", + "images": [] + }, + "videoeffectssdk-20xx-turing": { + "icon": "", + "images": [] + }, + "videoinspector": { + "icon": "", + "images": [] + }, + "videomass": { + "icon": "", + "images": [] + }, + "videomeld": { + "icon": "", + "images": [] + }, + "videoplayer": { + "icon": "", + "images": [] + }, + "videostream": { + "icon": "https://community.chocolatey.org/content/packageimages/videostream.0.5.1.png", + "images": [] + }, + "vidi": { + "icon": "", + "images": [] + }, + "vidi-dc": { + "icon": "https://community.chocolatey.org/content/packageimages/vidi-dc.1.0.0.png", + "images": [] + }, + "vidiot": { + "icon": "", + "images": [] + }, + "vieas": { + "icon": "", + "images": [] + }, + "vieb": { + "icon": "https://community.chocolatey.org/content/packageimages/vieb.9.2.1.png", + "images": [] + }, + "viemu-visualstudio2010": { + "icon": "", + "images": [] + }, + "viemu-visualstudio2012": { + "icon": "", + "images": [] + }, + "viemu-visualstudio2013": { + "icon": "", + "images": [] + }, + "vietex": { + "icon": "", + "images": [] + }, + "viewer": { + "icon": "", + "images": [] + }, + "viewercomponent-diagram": { + "icon": "", + "images": [] + }, + "viewercomponent-excel": { + "icon": "", + "images": [] + }, + "viewercomponent-office": { + "icon": "", + "images": [] + }, + "viewercomponent-pdf": { + "icon": "", + "images": [] + }, + "viewercomponent-word": { + "icon": "", + "images": [] + }, + "viewmate-viewer": { + "icon": "https://community.chocolatey.org/content/packageimages/viewmate-viewer.11.18.40.png", + "images": [] + }, + "vifm": { + "icon": "https://community.chocolatey.org/content/packageimages/vifm.0.11.png", + "images": [] + }, + "vigembus": { + "icon": "", + "images": [] + }, + "vigoon": { + "icon": "", + "images": [] + }, + "vikunja-desktop": { + "icon": "", + "images": [] + }, + "villagersandheroes": { + "icon": "", + "images": [] + }, + "vim": { + "icon": "", + "images": [] + }, + "vim-console": { + "icon": "", + "images": [] + }, + "vim-tux": { + "icon": "https://1.bp.blogspot.com/-hAugYyJ2NAg/X9EREuqFVxI/AAAAAAAAH8Y/l29y_XcmVBU8YrqN51HFni5eJLtpaoB0gCLcBGAsYHQ/s320/vim-editor.png", + "images": [] + }, + "vim-x64": { + "icon": "https://1.bp.blogspot.com/-hAugYyJ2NAg/X9EREuqFVxI/AAAAAAAAH8Y/l29y_XcmVBU8YrqN51HFni5eJLtpaoB0gCLcBGAsYHQ/s320/vim-editor.png", + "images": [] + }, + "vim-x86": { + "icon": "https://1.bp.blogspot.com/-hAugYyJ2NAg/X9EREuqFVxI/AAAAAAAAH8Y/l29y_XcmVBU8YrqN51HFni5eJLtpaoB0gCLcBGAsYHQ/s320/vim-editor.png", + "images": [] + }, + "vimtutor": { + "icon": "", + "images": [] + }, + "violin": { + "icon": "", + "images": [] + }, + "viper": { + "icon": "", + "images": [] + }, + "viper4windows": { + "icon": "https://community.chocolatey.org/content/packageimages/viper4windows.1.0.5.1.png", + "images": [] + }, + "virt-dimension": { + "icon": "https://community.chocolatey.org/content/packageimages/virt-dimension.0.94.png", + "images": [] + }, + "virt-viewer": { + "icon": "https://community.chocolatey.org/content/packageimages/virt-viewer.11.0.256.1.png", + "images": [] + }, + "virtio-drivers": { + "icon": "", + "images": [] + }, + "virtualbox": { + "icon": "https://kids.kiddle.co/images/thumb/f/ff/VirtualBox_2024_Logo.svg/512px-VirtualBox_2024_Logo.svg.png", + "images": [ + "https://i.postimg.cc/LXTH6F2f/image.png", + "https://i.postimg.cc/wTg7YHY6/image.png" + ] + }, + "virtualbox-guest-additions-guest": { + "icon": "https://community.chocolatey.org/content/packageimages/virtualbox-guest-additions-guest.install.7.0.6.png", + "images": [] + }, + "virtualclonedrive": { + "icon": "https://community.chocolatey.org/content/packageimages/VirtualCloneDrive.5.5.2.0.png", + "images": [] + }, + "virtualdj": { + "icon": "https://scontent.fmaa1-2.fna.fbcdn.net/v/t39.30808-1/326397625_2321958784636526_5229108248126755436_n.png?stp=dst-png_s200x200&_nc_cat=108&ccb=1-7&_nc_sid=2d3e12&_nc_ohc=IwpWVndkdlIQ7kNvgFMuZJa&_nc_zt=24&_nc_ht=scontent.fmaa1-2.fna&_nc_gid=Art3x9PHjThDjELVp-bkW9V&oh=00_AYBRslXr3VpgSFuFbK5g9mNj34G8r6t1UEg7atLBCocBzA&oe=678FA7B9", + "images": [] + }, + "virtualdub": { + "icon": "https://community.chocolatey.org/content/packageimages/virtualdub.1.10.4.3549101.png", + "images": [] + }, + "virtualdub2": { + "icon": "https://community.chocolatey.org/content/packageimages/virtualdub2.0.0.44282.png", + "images": [] + }, + "virtualengine-compression": { + "icon": "https://community.chocolatey.org/content/packageimages/VirtualEngine-Compression.1.1.0.18.png", + "images": [] + }, + "virtualgl": { + "icon": "", + "images": [] + }, + "virtualhere-client": { + "icon": "https://community.chocolatey.org/content/packageimages/virtualhere-client.5.4.4.png", + "images": [] + }, + "virtualhere-server": { + "icon": "https://community.chocolatey.org/content/packageimages/virtualhere-server.4.5.1.png", + "images": [] + }, + "virtualmachineconverter": { + "icon": "https://community.chocolatey.org/content/packageimages/virtualmachineconverter.3.1.0.20180613.png", + "images": [] + }, + "virtualmidisynth": { + "icon": "https://community.chocolatey.org/content/packageimages/virtualmidisynth.2.13.5.png", + "images": [] + }, + "virtualofficedesktop": { + "icon": "https://store-images.s-microsoft.com/image/apps.48237.19d1bd6a-9d62-497a-9418-a5027e36aa13.674cc665-b0fd-4782-ba73-36706eddee01.6e1155d9-6a72-4301-a674-5a08f355ac26.png", + "images": [ + "https://ik.imagekit.io/8x8/36BRYSitRR2mUasBs39Pr4.jpg", + "https://ik.imagekit.io/8x8/gd26UTUHjE8KQyCXtPQgQx.jpg", + "https://docs.8x8.com/8x8WebHelp/8x8analytics-virtual-office/Content/Resources/Images/VO%20Analytics%20-Overview/company-summary-new.png" + ] + }, + "virtuawin": { + "icon": "https://community.chocolatey.org/content/packageimages/virtuawin.4.4.png", + "images": [] + }, + "virtviewer": { + "icon": "", + "images": [] + }, + "virustotaluploader": { + "icon": "", + "images": [] + }, + "viscosity": { + "icon": "", + "images": [] + }, + "visionapp": { + "icon": "https://community.chocolatey.org/content/packageimages/visionapp.9.0.5222.png", + "images": [] + }, + "visioviewer": { + "icon": "https://community.chocolatey.org/content/packageimages/visioviewer.16.0.png", + "images": [] + }, + "visioviewer2016": { + "icon": "https://community.chocolatey.org/content/packageimages/visioviewer2016.16.0.png", + "images": [] + }, + "visual-arm-emulator": { + "icon": "", + "images": [] + }, + "visualbasic6-kb896559": { + "icon": "", + "images": [] + }, + "visualbcd": { + "icon": "", + "images": [] + }, + "visualboyadvance": { + "icon": "https://community.chocolatey.org/content/packageimages/VisualBoyAdvance.1.7.2.png", + "images": [] + }, + "visualc": { + "icon": "", + "images": [] + }, + "visualcplusplusexpress2008": { + "icon": "", + "images": [] + }, + "visualcpp-build-tools": { + "icon": "", + "images": [] + }, + "visualcppbuildtools": { + "icon": "https://community.chocolatey.org/content/packageimages/VisualCppBuildTools.14.0.25420.1.png", + "images": [] + }, + "visualcsharpexpress2008": { + "icon": "", + "images": [] + }, + "visuald": { + "icon": "", + "images": [] + }, + "visualfamilytree": { + "icon": "", + "images": [] + }, + "visualgdb": { + "icon": "https://community.chocolatey.org/content/packageimages/visualgdb.5.6.9.png", + "images": [] + }, + "visualhg": { + "icon": "", + "images": [] + }, + "visualkernel": { + "icon": "https://community.chocolatey.org/content/packageimages/visualkernel.3.1.9.png", + "images": [] + }, + "visualleakdetector": { + "icon": "https://community.chocolatey.org/content/packageimages/visualleakdetector.2.5.7.png", + "images": [] + }, + "visualparadigm-ce": { + "icon": "https://community.chocolatey.org/content/packageimages/visualparadigm-ce.17.0.png", + "images": [] + }, + "visualstudio-buildtools": { + "icon": "https://raw.githubusercontent.com/jberezanski/ChocolateyPackages/master/icons/vs2026.png", + "images": [] + }, + "visualstudio-community": { + "icon": "https://raw.githubusercontent.com/jberezanski/ChocolateyPackages/master/icons/vs2026.png", + "images": [ + "https://learn.microsoft.com/en-us/visualstudio/ide/media/visualstudio/create-new-project-dark-theme.png?view=vs-2017", + "https://learn.microsoft.com/zh-cn/visualstudio/releases/2026/media/18.0/pr-comment-in-file.png" + ] + }, + "visualstudio-enterprise": { + "icon": "https://raw.githubusercontent.com/jberezanski/ChocolateyPackages/master/icons/vs2026.png", + "images": [ + "https://learn.microsoft.com/en-us/visualstudio/ide/media/visualstudio/create-new-project-dark-theme.png?view=vs-2018", + "https://learn.microsoft.com/zh-cn/visualstudio/releases/2026/media/18.0/pr-comment-in-file.png" + ] + }, + "visualstudio-professional": { + "icon": "https://raw.githubusercontent.com/jberezanski/ChocolateyPackages/master/icons/vs2026.png", + "images": [ + "https://learn.microsoft.com/en-us/visualstudio/ide/media/visualstudio/create-new-project-dark-theme.png?view=vs-2019", + "https://learn.microsoft.com/zh-cn/visualstudio/releases/2026/media/18.0/pr-comment-in-file.png" + ] + }, + "visualstudio-remotetools": { + "icon": "https://raw.githubusercontent.com/jberezanski/ChocolateyPackages/master/icons/vs2026.png", + "images": [] + }, + "visualstudio-2019-buildtools": { + "icon": "https://raw.githubusercontent.com/jberezanski/ChocolateyPackages/master/icons/vs2019.png", + "images": [ + "https://learn.microsoft.com/zh-cn/visualstudio/releases/2019/media/16.9/16.9_p2_vsinstallerdarktheme.png" + ] + }, + "visualstudio-2019-community": { + "icon": "https://raw.githubusercontent.com/jberezanski/ChocolateyPackages/master/icons/vs2019.png", + "images": [ + "https://devblogs.microsoft.com/visualstudio/wp-content/uploads/sites/4/2019/05/Visual-Studio-2019-Start-Window.png", + "https://devblogs.microsoft.com/visualstudio/wp-content/uploads/sites/4/2019/08/16.3preview2x1-1024x671.png", + "https://learn.microsoft.com/zh-tw/visualstudio/releases/2019/media/16.8/16_8_ga_xamlbindfailwindow.png" + ] + }, + "visualstudio-2019-enterprise": { + "icon": "https://raw.githubusercontent.com/jberezanski/ChocolateyPackages/master/icons/vs2019.png", + "images": [ + "https://devblogs.microsoft.com/visualstudio/wp-content/uploads/sites/4/2019/05/Visual-Studio-2019-Start-Window.png", + "https://devblogs.microsoft.com/visualstudio/wp-content/uploads/sites/4/2019/08/16.3preview2x1-1024x671.png", + "https://learn.microsoft.com/zh-tw/visualstudio/releases/2019/media/16.8/16_8_ga_xamlbindfailwindow.png" + ] + }, + "visualstudio-2019-professional": { + "icon": "https://raw.githubusercontent.com/jberezanski/ChocolateyPackages/master/icons/vs2019.png", + "images": [ + "https://devblogs.microsoft.com/visualstudio/wp-content/uploads/sites/4/2019/05/Visual-Studio-2019-Start-Window.png", + "https://devblogs.microsoft.com/visualstudio/wp-content/uploads/sites/4/2019/08/16.3preview2x1-1024x671.png", + "https://learn.microsoft.com/zh-tw/visualstudio/releases/2019/media/16.8/16_8_ga_xamlbindfailwindow.png" + ] + }, + "visualstudio-2019-remotetools": { + "icon": "https://raw.githubusercontent.com/jberezanski/ChocolateyPackages/master/icons/vs2019.png", + "images": [ + "https://devblogs.microsoft.com/visualstudio/wp-content/uploads/sites/4/2019/05/Visual-Studio-2019-Start-Window.png" + ] + }, + "visualstudio-2022-buildtools": { + "icon": "https://raw.githubusercontent.com/jberezanski/ChocolateyPackages/master/icons/vs2022.png", + "images": [ + "https://learn.microsoft.com/zh-cn/visualstudio/install/media/vs-2022/update-ready-install-visual-studio-community-from-ide.png?view=vs-2017" + ] + }, + "visualstudio-2022-community": { + "icon": "https://raw.githubusercontent.com/jberezanski/ChocolateyPackages/master/icons/vs2022.png", + "images": [ + "https://learn.microsoft.com/en-us/visualstudio/ide/media/vs-2022/start-window-create-new-project.png?view=vs-2017", + "https://devblogs.microsoft.com/visualstudio/wp-content/uploads/sites/4/2022/02/word-image-3.png", + "https://devblogs.microsoft.com/visualstudio/wp-content/uploads/sites/4/2022/05/git-linestaging.png" + ] + }, + "visualstudio-2022-enterprise": { + "icon": "https://raw.githubusercontent.com/jberezanski/ChocolateyPackages/master/icons/vs2022.png", + "images": [ + "https://learn.microsoft.com/en-us/visualstudio/ide/media/vs-2022/start-window-create-new-project.png?view=vs-2018", + "https://devblogs.microsoft.com/visualstudio/wp-content/uploads/sites/4/2022/02/word-image-3.png", + "https://devblogs.microsoft.com/visualstudio/wp-content/uploads/sites/4/2022/05/git-linestaging.png" + ] + }, + "visualstudio-2022-professional": { + "icon": "https://raw.githubusercontent.com/jberezanski/ChocolateyPackages/master/icons/vs2022.png", + "images": [ + "https://learn.microsoft.com/en-us/visualstudio/ide/media/vs-2022/start-window-create-new-project.png?view=vs-2019", + "https://devblogs.microsoft.com/visualstudio/wp-content/uploads/sites/4/2022/02/word-image-3.png", + "https://devblogs.microsoft.com/visualstudio/wp-content/uploads/sites/4/2022/05/git-linestaging.png" + ] + }, + "visualstudio-codealignment": { + "icon": "https://community.chocolatey.org/content/packageimages/visualstudio-codealignment.12.0.png", + "images": [] + }, + "visualstudio-github": { + "icon": "", + "images": [] + }, + "visualstudio-linepastefix": { + "icon": "https://community.chocolatey.org/content/packageimages/visualstudio-linepastefix.7.0.png", + "images": [] + }, + "visualstudio-locator": { + "icon": "", + "images": [] + }, + "visualstudio2012premium": { + "icon": "https://community.chocolatey.org/content/packageimages/VisualStudio2012Premium.11.0.1.20151219.png", + "images": [] + }, + "visualstudio2012premwithwebtools": { + "icon": "", + "images": [] + }, + "visualstudio2012professional": { + "icon": "https://community.chocolatey.org/content/packageimages/VisualStudio2012Professional.11.0.1.20151219.png", + "images": [] + }, + "visualstudio2012ultimate": { + "icon": "https://community.chocolatey.org/content/packageimages/VisualStudio2012Ultimate.11.0.1.png", + "images": [] + }, + "visualstudio2012wdx": { + "icon": "https://community.chocolatey.org/content/packageimages/VisualStudio2012WDX.11.0.png", + "images": [] + }, + "visualstudio2013-update1": { + "icon": "https://community.chocolatey.org/content/packageimages/visualstudio2013-update1.1.0.4.png", + "images": [] + }, + "visualstudio2013-update2": { + "icon": "https://community.chocolatey.org/content/packageimages/visualstudio2013-update2.1.0.5.png", + "images": [] + }, + "visualstudio2013-update3": { + "icon": "https://community.chocolatey.org/content/packageimages/visualstudio2013-update3.1.0.2.png", + "images": [] + }, + "visualstudio2013-webessentials-vsix": { + "icon": "https://community.chocolatey.org/content/packageimages/visualstudio2013-webessentials.vsix.1.0.1.png", + "images": [] + }, + "visualstudio2013expressweb": { + "icon": "https://community.chocolatey.org/content/packageimages/VisualStudio2013ExpressWeb.12.0.21005.20150920.png", + "images": [] + }, + "visualstudio2013premium": { + "icon": "", + "images": [] + }, + "visualstudio2013professional": { + "icon": "https://community.chocolatey.org/content/packageimages/VisualStudio2013Professional.12.0.40629.20150920.png", + "images": [] + }, + "visualstudio2013teamexplorer": { + "icon": "https://community.chocolatey.org/content/packageimages/VisualStudio2013TeamExplorer.12.0.21005.1.png", + "images": [] + }, + "visualstudio2013testagents": { + "icon": "https://community.chocolatey.org/content/packageimages/visualstudio2013testagents.12.0.21005.20160105.png", + "images": [] + }, + "visualstudio2013testprofessional": { + "icon": "https://community.chocolatey.org/content/packageimages/VisualStudio2013TestProfessional.12.0.21005.20150920.png", + "images": [] + }, + "visualstudio2015-nugetpackagemanager": { + "icon": "https://community.chocolatey.org/content/packageimages/visualstudio2015-nugetpackagemanager.3.5.0.png", + "images": [] + }, + "visualstudio2015-powershelltools": { + "icon": "https://community.chocolatey.org/content/packageimages/visualstudio2015-powershelltools.3.0.539.png", + "images": [] + }, + "visualstudio2015-update": { + "icon": "https://community.chocolatey.org/content/packageimages/visualstudio2015-update.3.0.0.0.png", + "images": [] + }, + "visualstudio2015community": { + "icon": "https://community.chocolatey.org/content/packageimages/VisualStudio2015Community.2015.03.03.png", + "images": [] + }, + "visualstudio2015enterprise": { + "icon": "https://community.chocolatey.org/content/packageimages/VisualStudio2015Enterprise.2015.03.03.png", + "images": [] + }, + "visualstudio2015professional": { + "icon": "https://community.chocolatey.org/content/packageimages/VisualStudio2015Professional.2015.03.03.png", + "images": [] + }, + "visualstudio2015testagents": { + "icon": "https://community.chocolatey.org/content/packageimages/visualstudio2015testagents.14.0.25420.1.png", + "images": [] + }, + "visualstudio2017-installer": { + "icon": "https://community.chocolatey.org/content/packageimages/visualstudio2017-installer.2.0.2.png", + "images": [] + }, + "visualstudio2017-performancetools": { + "icon": "https://community.chocolatey.org/content/packageimages/visualstudio2017-performancetools.15.0.28010.0.png", + "images": [] + }, + "visualstudio2017-workload-azure": { + "icon": "https://community.chocolatey.org/content/packageimages/visualstudio2017-workload-azure.1.2.3.png", + "images": [] + }, + "visualstudio2017-workload-azurebuildtools": { + "icon": "https://community.chocolatey.org/content/packageimages/visualstudio2017-workload-azurebuildtools.1.0.2.png", + "images": [] + }, + "visualstudio2017-workload-databuildtools": { + "icon": "https://community.chocolatey.org/content/packageimages/visualstudio2017-workload-databuildtools.1.0.2.png", + "images": [] + }, + "visualstudio2017-workload-datascience": { + "icon": "https://community.chocolatey.org/content/packageimages/visualstudio2017-workload-datascience.1.0.2.png", + "images": [] + }, + "visualstudio2017-workload-manageddesktopbuildtools": { + "icon": "https://community.chocolatey.org/content/packageimages/visualstudio2017-workload-manageddesktopbuildtools.1.0.2.png", + "images": [] + }, + "visualstudio2017-workload-managedgame": { + "icon": "https://community.chocolatey.org/content/packageimages/visualstudio2017-workload-managedgame.1.2.3.png", + "images": [] + }, + "visualstudio2017-workload-nativecrossplat": { + "icon": "https://community.chocolatey.org/content/packageimages/visualstudio2017-workload-nativecrossplat.1.2.3.png", + "images": [] + }, + "visualstudio2017-workload-nativegame": { + "icon": "https://community.chocolatey.org/content/packageimages/visualstudio2017-workload-nativegame.1.2.3.png", + "images": [] + }, + "visualstudio2017-workload-netcorebuildtools": { + "icon": "https://community.chocolatey.org/content/packageimages/visualstudio2017-workload-netcorebuildtools.1.1.3.png", + "images": [] + }, + "visualstudio2017-workload-netcrossplat": { + "icon": "https://community.chocolatey.org/content/packageimages/visualstudio2017-workload-netcrossplat.1.2.3.png", + "images": [] + }, + "visualstudio2017-workload-netweb": { + "icon": "https://community.chocolatey.org/content/packageimages/visualstudio2017-workload-netweb.1.2.3.png", + "images": [] + }, + "visualstudio2017-workload-nodebuildtools": { + "icon": "https://community.chocolatey.org/content/packageimages/visualstudio2017-workload-nodebuildtools.1.0.2.png", + "images": [] + }, + "visualstudio2017-workload-office": { + "icon": "https://community.chocolatey.org/content/packageimages/visualstudio2017-workload-office.1.2.3.png", + "images": [] + }, + "visualstudio2017-workload-officebuildtools": { + "icon": "https://community.chocolatey.org/content/packageimages/visualstudio2017-workload-officebuildtools.1.0.2.png", + "images": [] + }, + "visualstudio2017-workload-python": { + "icon": "https://community.chocolatey.org/content/packageimages/visualstudio2017-workload-python.1.0.2.png", + "images": [] + }, + "visualstudio2017-workload-universal": { + "icon": "https://community.chocolatey.org/content/packageimages/visualstudio2017-workload-universal.1.2.3.png", + "images": [] + }, + "visualstudio2017-workload-universalbuildtools": { + "icon": "https://community.chocolatey.org/content/packageimages/visualstudio2017-workload-universalbuildtools.1.0.2.png", + "images": [] + }, + "visualstudio2017-workload-visualstudioextension": { + "icon": "https://community.chocolatey.org/content/packageimages/visualstudio2017-workload-visualstudioextension.1.2.3.png", + "images": [] + }, + "visualstudio2017-workload-visualstudioextensionbuildtools": { + "icon": "https://community.chocolatey.org/content/packageimages/visualstudio2017-workload-visualstudioextensionbuildtools.1.0.2.png", + "images": [] + }, + "visualstudio2017-workload-webbuildtools": { + "icon": "https://community.chocolatey.org/content/packageimages/visualstudio2017-workload-webbuildtools.1.3.3.png", + "images": [] + }, + "visualstudio2017-workload-webcrossplat": { + "icon": "https://community.chocolatey.org/content/packageimages/visualstudio2017-workload-webcrossplat.1.2.3.png", + "images": [] + }, + "visualstudio2017-workload-xamarinbuildtools": { + "icon": "https://community.chocolatey.org/content/packageimages/visualstudio2017-workload-xamarinbuildtools.1.0.2.png", + "images": [] + }, + "visualstudio2017buildtools": { + "icon": "https://community.chocolatey.org/content/packageimages/visualstudio2017buildtools.15.9.52.0.png", + "images": [] + }, + "visualstudio2017community": { + "icon": "https://community.chocolatey.org/content/packageimages/VisualStudio2017Community.15.9.52.0.png", + "images": [] + }, + "visualstudio2017enterprise": { + "icon": "https://community.chocolatey.org/content/packageimages/visualstudio2017enterprise.15.9.52.0.png", + "images": [] + }, + "visualstudio2017feedbackclient": { + "icon": "https://community.chocolatey.org/content/packageimages/visualstudio2017feedbackclient.15.9.52.0.png", + "images": [] + }, + "visualstudio2017professional": { + "icon": "https://community.chocolatey.org/content/packageimages/VisualStudio2017Professional.15.9.52.0.png", + "images": [] + }, + "visualstudio2017sql": { + "icon": "https://community.chocolatey.org/content/packageimages/visualstudio2017sql.15.9.52.0.png", + "images": [] + }, + "visualstudio2017teamexplorer": { + "icon": "https://community.chocolatey.org/content/packageimages/visualstudio2017teamexplorer.15.9.52.0.png", + "images": [] + }, + "visualstudio2017testcontroller": { + "icon": "https://community.chocolatey.org/content/packageimages/visualstudio2017testcontroller.15.9.52.0.png", + "images": [] + }, + "visualstudio2017testprofessional": { + "icon": "https://community.chocolatey.org/content/packageimages/visualstudio2017testprofessional.15.9.52.0.png", + "images": [] + }, + "visualstudio2019-remotetools": { + "icon": "https://community.chocolatey.org/content/packageimages/visualstudio2019-remotetools.16.0.29905.13400.png", + "images": [] + }, + "visualstudio2019-workload-azurebuildtools": { + "icon": "https://community.chocolatey.org/content/packageimages/visualstudio2019-workload-azurebuildtools.1.0.1.png", + "images": [] + }, + "visualstudio2019-workload-datascience": { + "icon": "https://community.chocolatey.org/content/packageimages/visualstudio2019-workload-datascience.1.0.1.png", + "images": [] + }, + "visualstudio2019-workload-manageddesktopbuildtools": { + "icon": "https://community.chocolatey.org/content/packageimages/visualstudio2019-workload-manageddesktopbuildtools.1.0.2.png", + "images": [] + }, + "visualstudio2019-workload-managedgame": { + "icon": "https://community.chocolatey.org/content/packageimages/visualstudio2019-workload-managedgame.1.0.1.png", + "images": [] + }, + "visualstudio2019-workload-nativedesktop": { + "icon": "https://community.chocolatey.org/content/packageimages/visualstudio2019-workload-nativedesktop.1.0.1.png", + "images": [] + }, + "visualstudio2019-workload-nativegame": { + "icon": "https://community.chocolatey.org/content/packageimages/visualstudio2019-workload-nativegame.1.0.1.png", + "images": [] + }, + "visualstudio2019-workload-nativemobile": { + "icon": "https://community.chocolatey.org/content/packageimages/visualstudio2019-workload-nativemobile.1.0.1.png", + "images": [] + }, + "visualstudio2019-workload-netweb": { + "icon": "https://community.chocolatey.org/content/packageimages/visualstudio2019-workload-netweb.1.0.1.png", + "images": [] + }, + "visualstudio2019-workload-node": { + "icon": "https://community.chocolatey.org/content/packageimages/visualstudio2019-workload-node.1.0.1.png", + "images": [] + }, + "visualstudio2019-workload-office": { + "icon": "https://community.chocolatey.org/content/packageimages/visualstudio2019-workload-office.1.0.1.png", + "images": [] + }, + "visualstudio2019-workload-officebuildtools": { + "icon": "https://community.chocolatey.org/content/packageimages/visualstudio2019-workload-officebuildtools.1.0.1.png", + "images": [] + }, + "visualstudio2019-workload-python": { + "icon": "https://community.chocolatey.org/content/packageimages/visualstudio2019-workload-python.1.0.1.png", + "images": [] + }, + "visualstudio2019-workload-visualstudioextension": { + "icon": "https://community.chocolatey.org/content/packageimages/visualstudio2019-workload-visualstudioextension.1.0.1.png", + "images": [] + }, + "visualstudio2019-workload-visualstudioextensionbuildtools": { + "icon": "https://community.chocolatey.org/content/packageimages/visualstudio2019-workload-visualstudioextensionbuildtools.1.0.1.png", + "images": [] + }, + "visualstudio2019-workload-webbuildtools": { + "icon": "https://community.chocolatey.org/content/packageimages/visualstudio2019-workload-webbuildtools.1.0.1.png", + "images": [] + }, + "visualstudio2019-workload-xamarinbuildtools": { + "icon": "https://community.chocolatey.org/content/packageimages/visualstudio2019-workload-xamarinbuildtools.1.0.1.png", + "images": [] + }, + "visualstudio2019buildtools": { + "icon": "https://community.chocolatey.org/content/packageimages/visualstudio2019buildtools.16.11.24.0.png", + "images": [] + }, + "visualstudio2019community": { + "icon": "https://community.chocolatey.org/content/packageimages/visualstudio2019community.16.11.24.0.png", + "images": [] + }, + "visualstudio2019enterprise": { + "icon": "https://community.chocolatey.org/content/packageimages/visualstudio2019enterprise.16.11.24.0.png", + "images": [] + }, + "visualstudio2019professional": { + "icon": "https://community.chocolatey.org/content/packageimages/visualstudio2019professional.16.11.24.0.png", + "images": [] + }, + "visualstudio2019teamexplorer": { + "icon": "https://community.chocolatey.org/content/packageimages/visualstudio2019teamexplorer.16.11.24.0.png", + "images": [] + }, + "visualstudio2019testagent": { + "icon": "https://community.chocolatey.org/content/packageimages/visualstudio2019testagent.16.11.24.0.png", + "images": [] + }, + "visualstudio2019testcontroller": { + "icon": "https://community.chocolatey.org/content/packageimages/visualstudio2019testcontroller.16.11.24.0.png", + "images": [] + }, + "visualstudio2022-remotetools": { + "icon": "https://community.chocolatey.org/content/packageimages/visualstudio2022-remotetools.17.0.33103.184.png", + "images": [] + }, + "visualstudio2022-workload-azure": { + "icon": "https://community.chocolatey.org/content/packageimages/visualstudio2022-workload-azure.1.0.0.png", + "images": [] + }, + "visualstudio2022-workload-azurebuildtools": { + "icon": "https://community.chocolatey.org/content/packageimages/visualstudio2022-workload-azurebuildtools.1.0.0.png", + "images": [] + }, + "visualstudio2022-workload-data": { + "icon": "https://community.chocolatey.org/content/packageimages/visualstudio2022-workload-data.1.0.0.png", + "images": [] + }, + "visualstudio2022-workload-databuildtools": { + "icon": "https://community.chocolatey.org/content/packageimages/visualstudio2022-workload-databuildtools.1.0.0.png", + "images": [] + }, + "visualstudio2022-workload-datascience": { + "icon": "https://community.chocolatey.org/content/packageimages/visualstudio2022-workload-datascience.1.0.1.png", + "images": [] + }, + "visualstudio2022-workload-manageddesktop": { + "icon": "https://community.chocolatey.org/content/packageimages/visualstudio2022-workload-manageddesktop.1.0.1.png", + "images": [] + }, + "visualstudio2022-workload-manageddesktopbuildtools": { + "icon": "https://community.chocolatey.org/content/packageimages/visualstudio2022-workload-manageddesktopbuildtools.1.0.0.png", + "images": [] + }, + "visualstudio2022-workload-managedgame": { + "icon": "https://community.chocolatey.org/content/packageimages/visualstudio2022-workload-managedgame.1.0.0.png", + "images": [] + }, + "visualstudio2022-workload-nativecrossplat": { + "icon": "https://community.chocolatey.org/content/packageimages/visualstudio2022-workload-nativecrossplat.1.0.0.png", + "images": [] + }, + "visualstudio2022-workload-nativedesktop": { + "icon": "https://community.chocolatey.org/content/packageimages/visualstudio2022-workload-nativedesktop.1.0.0.png", + "images": [] + }, + "visualstudio2022-workload-nativegame": { + "icon": "https://community.chocolatey.org/content/packageimages/visualstudio2022-workload-nativegame.1.0.0.png", + "images": [] + }, + "visualstudio2022-workload-nativemobile": { + "icon": "https://community.chocolatey.org/content/packageimages/visualstudio2022-workload-nativemobile.1.0.0.png", + "images": [] + }, + "visualstudio2022-workload-netcrossplat": { + "icon": "https://community.chocolatey.org/content/packageimages/visualstudio2022-workload-netcrossplat.1.0.0.png", + "images": [] + }, + "visualstudio2022-workload-netweb": { + "icon": "https://community.chocolatey.org/content/packageimages/visualstudio2022-workload-netweb.1.0.0.png", + "images": [] + }, + "visualstudio2022-workload-node": { + "icon": "https://community.chocolatey.org/content/packageimages/visualstudio2022-workload-node.1.0.0.png", + "images": [] + }, + "visualstudio2022-workload-nodebuildtools": { + "icon": "https://community.chocolatey.org/content/packageimages/visualstudio2022-workload-nodebuildtools.1.0.0.png", + "images": [] + }, + "visualstudio2022-workload-office": { + "icon": "https://community.chocolatey.org/content/packageimages/visualstudio2022-workload-office.1.0.0.png", + "images": [] + }, + "visualstudio2022-workload-officebuildtools": { + "icon": "https://community.chocolatey.org/content/packageimages/visualstudio2022-workload-officebuildtools.1.0.0.png", + "images": [] + }, + "visualstudio2022-workload-python": { + "icon": "https://community.chocolatey.org/content/packageimages/visualstudio2022-workload-python.1.0.0.png", + "images": [] + }, + "visualstudio2022-workload-universal": { + "icon": "https://community.chocolatey.org/content/packageimages/visualstudio2022-workload-universal.1.0.0.png", + "images": [] + }, + "visualstudio2022-workload-universalbuildtools": { + "icon": "https://community.chocolatey.org/content/packageimages/visualstudio2022-workload-universalbuildtools.1.0.0.png", + "images": [] + }, + "visualstudio2022-workload-vctools": { + "icon": "https://community.chocolatey.org/content/packageimages/visualstudio2022-workload-vctools.1.0.0.png", + "images": [] + }, + "visualstudio2022-workload-visualstudioextension": { + "icon": "https://community.chocolatey.org/content/packageimages/visualstudio2022-workload-visualstudioextension.1.0.0.png", + "images": [] + }, + "visualstudio2022-workload-visualstudioextensionbuildtools": { + "icon": "https://community.chocolatey.org/content/packageimages/visualstudio2022-workload-visualstudioextensionbuildtools.1.0.0.png", + "images": [] + }, + "visualstudio2022-workload-webbuildtools": { + "icon": "https://community.chocolatey.org/content/packageimages/visualstudio2022-workload-webbuildtools.1.0.0.png", + "images": [] + }, + "visualstudio2022-workload-xamarinbuildtools": { + "icon": "https://community.chocolatey.org/content/packageimages/visualstudio2022-workload-xamarinbuildtools.1.0.0.png", + "images": [] + }, + "visualstudio2022buildtools": { + "icon": "https://community.chocolatey.org/content/packageimages/visualstudio2022buildtools.117.5.0.0.png", + "images": [] + }, + "visualstudio2022community": { + "icon": "https://community.chocolatey.org/content/packageimages/visualstudio2022community.117.5.0.0.png", + "images": [] + }, + "visualstudio2022enterprise": { + "icon": "https://community.chocolatey.org/content/packageimages/visualstudio2022enterprise.117.5.0.0.png", + "images": [] + }, + "visualstudio2022professional": { + "icon": "https://community.chocolatey.org/content/packageimages/visualstudio2022professional.117.5.0.0.png", + "images": [] + }, + "visualstudio2022teamexplorer": { + "icon": "https://community.chocolatey.org/content/packageimages/visualstudio2022teamexplorer.117.5.0.0.png", + "images": [] + }, + "visualstudio2022testagent": { + "icon": "https://community.chocolatey.org/content/packageimages/visualstudio2022testagent.117.5.0.0.png", + "images": [] + }, + "visualstudio2022testcontroller": { + "icon": "https://community.chocolatey.org/content/packageimages/visualstudio2022testcontroller.117.5.0.0.png", + "images": [] + }, + "visualstudiocode": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/9/9a/Visual_Studio_Code_1.35_icon.svg/langfr-800px-Visual_Studio_Code_1.35_icon.svg.png", + "images": [ + "https://upload.wikimedia.org/wikipedia/commons/thumb/8/80/Visual_Studio_Code_0.10.1_on_Windows_7%2C_with_search.png/1024px-Visual_Studio_Code_0.10.1_on_Windows_7%2C_with_search.png", + "https://upload.wikimedia.org/wikipedia/commons/thumb/e/e9/VS_Code_%28Insiders%29.png/800px-VS_Code_%28Insiders%29.png?20210728074118" + ] + }, + "visualstudiocode-disableautoupdate": { + "icon": "https://community.chocolatey.org/content/packageimages/visualstudiocode-disableautoupdate.1.0.0.20180620.png", + "images": [] + }, + "visualstudiocode-insiders": { + "icon": "https://images2.imgbox.com/6f/c2/Rqjtunak_o.png", + "images": [ + "https://upload.wikimedia.org/wikipedia/commons/thumb/e/e9/VS_Code_%28Insiders%29.png/800px-VS_Code_%28Insiders%29.png?20210728074118" + ] + }, + "visualstudiocommunity2013": { + "icon": "https://community.chocolatey.org/content/packageimages/VisualStudioCommunity2013.12.0.21005.1.png", + "images": [] + }, + "visualstudioexpress2008": { + "icon": "", + "images": [] + }, + "visualstudioexpress2012teamexplorer": { + "icon": "https://community.chocolatey.org/content/packageimages/VisualStudioExpress2012TeamExplorer.11.0.0.1.png", + "images": [] + }, + "visualstudioexpress2012tfs": { + "icon": "https://community.chocolatey.org/content/packageimages/VisualStudioExpress2012TFS.11.0.0.1.png", + "images": [] + }, + "visualstudioexpress2012web": { + "icon": "https://community.chocolatey.org/content/packageimages/VisualStudioExpress2012Web.11.0.1.png", + "images": [] + }, + "visualstudioexpress2012windows8": { + "icon": "https://community.chocolatey.org/content/packageimages/VisualStudioExpress2012Windows8.11.0.0.1.png", + "images": [] + }, + "visualstudioexpress2012windowsphone": { + "icon": "https://community.chocolatey.org/content/packageimages/VisualStudioExpress2012WindowsPhone.11.0.0.1.png", + "images": [] + }, + "visualstudioteamfoundationserverexpress2013": { + "icon": "https://community.chocolatey.org/content/packageimages/VisualStudioTeamFoundationServerExpress2013.12.0.21005.1.png", + "images": [] + }, + "visualstudiotfsexpress2012": { + "icon": "", + "images": [] + }, + "visualsubst": { + "icon": "https://community.chocolatey.org/content/packageimages/visualsubst.1.0.6.png", + "images": [] + }, + "visualsvnserver": { + "icon": "https://community.chocolatey.org/content/packageimages/visualsvnserver.5.1.3.png", + "images": [] + }, + "visualsyslog": { + "icon": "https://community.chocolatey.org/content/packageimages/visualsyslog.1.6.4.19.png", + "images": [] + }, + "vitomu": { + "icon": "", + "images": [] + }, + "vitrite": { + "icon": "", + "images": [] + }, + "vivaldi": { + "icon": "https://vivaldi.com/wp-content/uploads/cropped-viv_icon-500px.png", + "images": [] + }, + "vivetool": { + "icon": "", + "images": [] + }, + "vivetool-gui": { + "icon": "", + "images": [] + }, + "vivi": { + "icon": "", + "images": [] + }, + "vjredist": { + "icon": "https://community.chocolatey.org/content/packageimages/vjredist.2.0.1.png", + "images": [] + }, + "vkmessenger": { + "icon": "", + "images": [] + }, + "vkquake": { + "icon": "https://community.chocolatey.org/content/packageimages/vkQuake.1.20.3.png", + "images": [] + }, + "vlc": { + "icon": "https://i.imgur.com/k4W1Nm1.png", + "images": [ + "https://i.imgur.com/3AOZ20t.png" + ] + }, + "vlc-nightly": { + "icon": "https://community.chocolatey.org/content/packageimages/vlc-nightly.4.0.0.20230228.png", + "images": [ + "https://i.vgy.me/JtHcSz.png" + ] + }, + "vlc-skin-editor": { + "icon": "https://community.chocolatey.org/content/packageimages/vlc-skin-editor.0.8.5.png", + "images": [] + }, + "vlc-skins": { + "icon": "https://community.chocolatey.org/content/packageimages/vlc-skins.2017.01.13.png", + "images": [] + }, + "vmaf": { + "icon": "", + "images": [] + }, + "vmmap": { + "icon": "https://community.chocolatey.org/content/packageimages/vmmap.3.32.png", + "images": [] + }, + "vmpk": { + "icon": "", + "images": [] + }, + "vmware-converter": { + "icon": "https://community.chocolatey.org/content/packageimages/vmware-converter.6.2.0.101.png", + "images": [] + }, + "vmware-horizon-client": { + "icon": "https://community.chocolatey.org/content/packageimages/vmware-horizon-client.8.8.1.21249081.png", + "images": [] + }, + "vmware-tools": { + "icon": "https://community.chocolatey.org/content/packageimages/vmware-tools.12.1.5.20735119.png", + "images": [] + }, + "vmware-workloadmanagement": { + "icon": "https://community.chocolatey.org/content/packageimages/vmware-workloadmanagement.1.0.14.png", + "images": [] + }, + "vmware-workstation-player": { + "icon": "https://community.chocolatey.org/content/packageimages/vmware-workstation-player.17.0.1.21139696.png", + "images": [] + }, + "vmwareplayer": { + "icon": "", + "images": [] + }, + "vmwarevsphereclient": { + "icon": "", + "images": [] + }, + "vmwareworkstation": { + "icon": "https://community.chocolatey.org/content/packageimages/vmwareworkstation.17.0.1.21139696.png", + "images": [] + }, + "vnc-viewer-chrome": { + "icon": "", + "images": [] + }, + "vnc-viewer-plus": { + "icon": "", + "images": [] + }, + "vncpassview": { + "icon": "https://community.chocolatey.org/content/packageimages/vncpassview.1.05.png", + "images": [] + }, + "vncserver": { + "icon": "https://www.pacisoft.vn/wp-content/uploads/2018/10/vnc-viewer-logo.png", + "images": [] + }, + "vncviewer": { + "icon": "https://www.pacisoft.vn/wp-content/uploads/2018/10/vnc-viewer-logo.png", + "images": [] + }, + "vnote": { + "icon": "", + "images": [] + }, + "vocalsharp": { + "icon": "", + "images": [] + }, + "voice-control": { + "icon": "https://community.chocolatey.org/content/packageimages/voice_control.1.0.0.png", + "images": [] + }, + "voiceattack": { + "icon": "https://i.postimg.cc/7LXf5rRG/Voice-Attack.png", + "images": [ + "https://i.postimg.cc/wTy3YfBS/image.png", + "https://i.postimg.cc/zf5fWqkr/image.png", + "https://i.postimg.cc/RFZVsG8p/image.png", + "https://i.postimg.cc/rsdycsqS/image.png", + "https://i.postimg.cc/vHV8N4qy/image.png", + "https://i.postimg.cc/Bn5SJdfw/image.png" + ] + }, + "voicebot": { + "icon": "", + "images": [ + "https://i.postimg.cc/FR9t2RZV/image.png", + "https://i.postimg.cc/HxBGHgvD/image.png", + "https://i.postimg.cc/SRsBxvHX/image.png", + "https://i.postimg.cc/ryZ6Pqt5/image.png", + "https://i.postimg.cc/BQ8WWRxk/image.png", + "https://i.postimg.cc/HsFqT3zx/image.png", + "https://i.postimg.cc/RZfjhfpT/image.png", + "https://i.postimg.cc/hGBNdjHR/image.png", + "https://i.postimg.cc/6QfgLKX2/image.png" + ] + }, + "voicecommands": { + "icon": "", + "images": [] + }, + "voicemacro": { + "icon": "", + "images": [] + }, + "voicemeeter": { + "icon": "", + "images": [] + }, + "voicemeeter-banana": { + "icon": "https://community.chocolatey.org/content/packageimages/voicemeeter-banana.install.2.0.6.200.png", + "images": [] + }, + "voicemeeter-potato": { + "icon": "https://community.chocolatey.org/content/packageimages/voicemeeter-potato.portable.3.0.2.1000.png", + "images": [] + }, + "voicemod": { + "icon": "", + "images": [] + }, + "volanta": { + "icon": "", + "images": [] + }, + "volatility": { + "icon": "https://community.chocolatey.org/content/packageimages/volatility.2.6.0.20190425.png", + "images": [] + }, + "volatility3": { + "icon": "https://community.chocolatey.org/content/packageimages/volatility3.2.4.0.png", + "images": [] + }, + "volley": { + "icon": "", + "images": [] + }, + "volta": { + "icon": "", + "images": [] + }, + "volume2": { + "icon": "", + "images": [] + }, + "volume2portable": { + "icon": "", + "images": [] + }, + "volumeid": { + "icon": "", + "images": [] + }, + "volumouse": { + "icon": "https://community.chocolatey.org/content/packageimages/volumouse.install.2.03.png", + "images": [ + "https://i.postimg.cc/cHd09Byx/image.png" + ] + }, + "voodooshield": { + "icon": "", + "images": [] + }, + "voovmeeting": { + "icon": "", + "images": [] + }, + "vortex": { + "icon": "https://community.chocolatey.org/content/packageimages/vortex.1.7.8.png", + "images": [] + }, + "vortexdm": { + "icon": "", + "images": [] + }, + "vosviewer": { + "icon": "https://community.chocolatey.org/content/packageimages/vosviewer.1.6.19.png", + "images": [] + }, + "vott": { + "icon": "", + "images": [] + }, + "voxengo-anspec": { + "icon": "", + "images": [] + }, + "voxengo-beeper": { + "icon": "https://community.chocolatey.org/content/packageimages/voxengo-beeper.2.11.png", + "images": [] + }, + "voxengo-bms": { + "icon": "https://community.chocolatey.org/content/packageimages/voxengo-bms.2.5.png", + "images": [] + }, + "voxengo-boogex": { + "icon": "https://community.chocolatey.org/content/packageimages/voxengo-boogex.3.6.png", + "images": [] + }, + "voxengo-correlometer": { + "icon": "https://community.chocolatey.org/content/packageimages/voxengo-correlometer.1.6.png", + "images": [] + }, + "voxengo-crtiv-chorus": { + "icon": "", + "images": [] + }, + "voxengo-crtiv-reverb-2": { + "icon": "", + "images": [] + }, + "voxengo-crtiv-shumovick": { + "icon": "", + "images": [] + }, + "voxengo-crtiv-tape-bus": { + "icon": "https://community.chocolatey.org/content/packageimages/voxengo-crtiv-tape-bus.1.6.png", + "images": [] + }, + "voxengo-crunchessor": { + "icon": "", + "images": [] + }, + "voxengo-curveeq": { + "icon": "https://community.chocolatey.org/content/packageimages/voxengo-curveeq.3.12.png", + "images": [] + }, + "voxengo-deftcompressor": { + "icon": "https://community.chocolatey.org/content/packageimages/voxengo-deftcompressor.1.12.png", + "images": [] + }, + "voxengo-drumformer": { + "icon": "https://community.chocolatey.org/content/packageimages/voxengo-drumformer.1.10.png", + "images": [] + }, + "voxengo-ebuslim": { + "icon": "https://community.chocolatey.org/content/packageimages/voxengo-ebuslim.1.8.png", + "images": [] + }, + "voxengo-elephant": { + "icon": "https://community.chocolatey.org/content/packageimages/voxengo-elephant.5.2.png", + "images": [] + }, + "voxengo-glisseq": { + "icon": "https://community.chocolatey.org/content/packageimages/voxengo-glisseq.3.17.png", + "images": [] + }, + "voxengo-harmonieq": { + "icon": "https://community.chocolatey.org/content/packageimages/voxengo-harmonieq.2.9.png", + "images": [] + }, + "voxengo-latency-delay": { + "icon": "https://community.chocolatey.org/content/packageimages/voxengo-latency-delay.2.9.png", + "images": [] + }, + "voxengo-lf-max-punch": { + "icon": "https://community.chocolatey.org/content/packageimages/voxengo-lf-max-punch.1.14.png", + "images": [] + }, + "voxengo-marquis-compressor": { + "icon": "https://community.chocolatey.org/content/packageimages/voxengo-marquis-compressor.2.6.png", + "images": [] + }, + "voxengo-marvel-geq": { + "icon": "https://community.chocolatey.org/content/packageimages/voxengo-marvel-geq.1.13.png", + "images": [] + }, + "voxengo-msed": { + "icon": "", + "images": [] + }, + "voxengo-oldskoolverb": { + "icon": "https://community.chocolatey.org/content/packageimages/voxengo-oldskoolverb.2.10.png", + "images": [] + }, + "voxengo-oldskoolverb-plus": { + "icon": "", + "images": [] + }, + "voxengo-oldskoolverbplus": { + "icon": "https://community.chocolatey.org/content/packageimages/voxengo-oldskoolverbplus.1.2.png", + "images": [] + }, + "voxengo-ovc-128": { + "icon": "https://community.chocolatey.org/content/packageimages/voxengo-ovc-128.1.11.png", + "images": [] + }, + "voxengo-overtone-geq": { + "icon": "https://community.chocolatey.org/content/packageimages/voxengo-overtone-geq.1.16.png", + "images": [] + }, + "voxengo-peakbuster": { + "icon": "https://community.chocolatey.org/content/packageimages/voxengo-peakbuster.1.5.png", + "images": [] + }, + "voxengo-pha-979": { + "icon": "", + "images": [] + }, + "voxengo-polysquasher3": { + "icon": "", + "images": [] + }, + "voxengo-powershaper": { + "icon": "https://community.chocolatey.org/content/packageimages/voxengo-powershaper.1.4.png", + "images": [] + }, + "voxengo-primeeq": { + "icon": "https://community.chocolatey.org/content/packageimages/voxengo-primeeq.1.7.png", + "images": [] + }, + "voxengo-r8brain-pro": { + "icon": "", + "images": [] + }, + "voxengo-shinechilla": { + "icon": "https://community.chocolatey.org/content/packageimages/voxengo-shinechilla.1.4.png", + "images": [] + }, + "voxengo-sobor": { + "icon": "", + "images": [] + }, + "voxengo-soniformer": { + "icon": "", + "images": [] + }, + "voxengo-sound-delay": { + "icon": "", + "images": [] + }, + "voxengo-span": { + "icon": "https://community.chocolatey.org/content/packageimages/voxengo-span.3.15.png", + "images": [] + }, + "voxengo-span-plus": { + "icon": "https://community.chocolatey.org/content/packageimages/voxengo-span-plus.1.22.png", + "images": [] + }, + "voxengo-spatifier": { + "icon": "https://community.chocolatey.org/content/packageimages/voxengo-spatifier.1.9.png", + "images": [] + }, + "voxengo-stereo-touch": { + "icon": "", + "images": [] + }, + "voxengo-stereotouch": { + "icon": "https://community.chocolatey.org/content/packageimages/voxengo-stereotouch.2.11.png", + "images": [] + }, + "voxengo-tempo-delay": { + "icon": "https://community.chocolatey.org/content/packageimages/voxengo-tempo-delay.2.6.png", + "images": [] + }, + "voxengo-tempodelay": { + "icon": "https://community.chocolatey.org/content/packageimages/voxengo-tempodelay.2.3.png", + "images": [] + }, + "voxengo-teote": { + "icon": "https://community.chocolatey.org/content/packageimages/voxengo-teote.1.12.png", + "images": [] + }, + "voxengo-teq-421": { + "icon": "https://community.chocolatey.org/content/packageimages/voxengo-teq-421.1.1.png", + "images": [] + }, + "voxengo-transgainer": { + "icon": "", + "images": [] + }, + "voxengo-tube-amp": { + "icon": "", + "images": [] + }, + "voxengo-varisaturator": { + "icon": "https://community.chocolatey.org/content/packageimages/voxengo-varisaturator.2.5.png", + "images": [] + }, + "voxengo-voxformer": { + "icon": "https://community.chocolatey.org/content/packageimages/voxengo-voxformer.2.21.png", + "images": [] + }, + "voxengo-warmifier": { + "icon": "https://community.chocolatey.org/content/packageimages/voxengo-warmifier.2.7.png", + "images": [] + }, + "vp8-vfw": { + "icon": "", + "images": [] + }, + "vpb-banking": { + "icon": "https://community.chocolatey.org/content/packageimages/vpb-banking.5.6.1.png", + "images": [] + }, + "vpilot": { + "icon": "", + "images": [] + }, + "vplayer-next": { + "icon": "", + "images": [] + }, + "vpn": { + "icon": "", + "images": [] + }, + "vpnac": { + "icon": "", + "images": [] + }, + "vpnarea": { + "icon": "https://community.chocolatey.org/content/packageimages/vpnarea.2.2.0.0.png", + "images": [] + }, + "vrew": { + "icon": "", + "images": [] + }, + "vroid-studio": { + "icon": "", + "images": [] + }, + "vs2010-shellintegratedredist": { + "icon": "https://community.chocolatey.org/content/packageimages/VS2010.ShellIntegratedRedist.10.0.30319.2.png", + "images": [] + }, + "vs2012-4": { + "icon": "", + "images": [] + }, + "vs2012-5": { + "icon": "https://community.chocolatey.org/content/packageimages/vs2012.5.11.0.61219.0.png", + "images": [] + }, + "vs2012-shellintegratedredist": { + "icon": "", + "images": [] + }, + "vs2012-shellisolatedredist": { + "icon": "", + "images": [] + }, + "vs2012remotetools": { + "icon": "", + "images": [] + }, + "vs2012sdk": { + "icon": "", + "images": [] + }, + "vs2013-1": { + "icon": "", + "images": [] + }, + "vs2013-2": { + "icon": "", + "images": [] + }, + "vs2013-3": { + "icon": "", + "images": [] + }, + "vs2013-5": { + "icon": "", + "images": [] + }, + "vs2013-powertools": { + "icon": "", + "images": [] + }, + "vs2013-remotetools-update1": { + "icon": "", + "images": [] + }, + "vs2013-shellintegratedredist": { + "icon": "", + "images": [] + }, + "vs2013-shellisolatedredist": { + "icon": "", + "images": [] + }, + "vs2013agents": { + "icon": "", + "images": [] + }, + "vs2013remotetools": { + "icon": "", + "images": [] + }, + "vs2013sdk": { + "icon": "", + "images": [] + }, + "vs2015-1": { + "icon": "https://community.chocolatey.org/content/packageimages/vs2015.1.1.0.0.0.png", + "images": [] + }, + "vs2015-2": { + "icon": "https://community.chocolatey.org/content/packageimages/vs2015.2.2.0.0.0.png", + "images": [] + }, + "vs2015-3": { + "icon": "https://community.chocolatey.org/content/packageimages/vs2015.3.3.0.0.0.png", + "images": [] + }, + "vs2015-roaming-extension-manager": { + "icon": "https://community.chocolatey.org/content/packageimages/vs2015-roaming-extension-manager.2.0.0.0.png", + "images": [] + }, + "vs2015remotetools": { + "icon": "", + "images": [] + }, + "vs2019-codemaid": { + "icon": "https://community.chocolatey.org/content/packageimages/vs2019-codemaid.12.0.300.png", + "images": [] + }, + "vsae": { + "icon": "https://community.chocolatey.org/content/packageimages/vsae.1.4.1.0.png", + "images": [] + }, + "vsautoupdater": { + "icon": "", + "images": [] + }, + "vscmount": { + "icon": "", + "images": [] + }, + "vscode": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/9/9a/Visual_Studio_Code_1.35_icon.svg/langfr-800px-Visual_Studio_Code_1.35_icon.svg.png", + "images": [ + "https://upload.wikimedia.org/wikipedia/commons/thumb/8/80/Visual_Studio_Code_0.10.1_on_Windows_7%2C_with_search.png/1024px-Visual_Studio_Code_0.10.1_on_Windows_7%2C_with_search.png", + "https://upload.wikimedia.org/wikipedia/commons/thumb/e/e9/VS_Code_%28Insiders%29.png/800px-VS_Code_%28Insiders%29.png?20210728074118" + ] + }, + "vscode-ansible": { + "icon": "https://community.chocolatey.org/content/packageimages/vscode-ansible.1.2.44.png", + "images": [] + }, + "vscode-appveyor": { + "icon": "", + "images": [] + }, + "vscode-arduino": { + "icon": "https://community.chocolatey.org/content/packageimages/vscode-arduino.0.4.11.png", + "images": [] + }, + "vscode-autofilename": { + "icon": "https://community.chocolatey.org/content/packageimages/vscode-autofilename.1.0.0.20181011.png", + "images": [] + }, + "vscode-autohotkey": { + "icon": "https://community.chocolatey.org/content/packageimages/vscode-autohotkey.0.2.2.png", + "images": [] + }, + "vscode-azure-deploy": { + "icon": "https://community.chocolatey.org/content/packageimages/vscode-azure-deploy.1.2.4.png", + "images": [] + }, + "vscode-azurerepos": { + "icon": "https://community.chocolatey.org/content/packageimages/vscode-azurerepos.1.161.1.png", + "images": [] + }, + "vscode-azurerm-tools": { + "icon": "https://community.chocolatey.org/content/packageimages/vscode-azurerm-tools.1.0.0.20180620.png", + "images": [] + }, + "vscode-beautify": { + "icon": "https://community.chocolatey.org/content/packageimages/vscode-beautify.1.5.0.png", + "images": [] + }, + "vscode-cake": { + "icon": "https://community.chocolatey.org/content/packageimages/vscode-cake.1.0.0.20191026.png", + "images": [] + }, + "vscode-chrome-debug": { + "icon": "https://community.chocolatey.org/content/packageimages/vscode-chrome-debug.4.13.0.png", + "images": [] + }, + "vscode-code-runner": { + "icon": "https://community.chocolatey.org/content/packageimages/vscode-code-runner.0.12.0.png", + "images": [] + }, + "vscode-codespellchecker": { + "icon": "https://community.chocolatey.org/content/packageimages/vscode-codespellchecker.1.0.0.20181011.png", + "images": [] + }, + "vscode-codespellchecker-german": { + "icon": "https://community.chocolatey.org/content/packageimages/vscode-codespellchecker-german.1.0.0.20181011.png", + "images": [] + }, + "vscode-commitizen": { + "icon": "", + "images": [] + }, + "vscode-cortex-debug": { + "icon": "https://community.chocolatey.org/content/packageimages/vscode-cortex-debug.0.3.1.png", + "images": [] + }, + "vscode-cpptools": { + "icon": "https://community.chocolatey.org/content/packageimages/vscode-cpptools.0.24.1.png", + "images": [] + }, + "vscode-csharp": { + "icon": "https://community.chocolatey.org/content/packageimages/vscode-csharp.1.23.16.png", + "images": [] + }, + "vscode-csharpextensions": { + "icon": "https://community.chocolatey.org/content/packageimages/vscode-csharpextensions.1.0.0.20180620.png", + "images": [] + }, + "vscode-docker": { + "icon": "https://community.chocolatey.org/content/packageimages/vscode-docker.1.0.0.20190907.png", + "images": [] + }, + "vscode-drawio": { + "icon": "https://community.chocolatey.org/content/packageimages/vscode-drawio.1.6.6.png", + "images": [] + }, + "vscode-edge-debug": { + "icon": "https://community.chocolatey.org/content/packageimages/vscode-edge-debug.1.0.15.png", + "images": [] + }, + "vscode-editorconfig": { + "icon": "https://community.chocolatey.org/content/packageimages/vscode-editorconfig.1.0.0.20181011.png", + "images": [] + }, + "vscode-ember-cli": { + "icon": "", + "images": [] + }, + "vscode-ember-frost": { + "icon": "", + "images": [] + }, + "vscode-eslint": { + "icon": "https://community.chocolatey.org/content/packageimages/vscode-eslint.1.0.0.20181011.png", + "images": [] + }, + "vscode-firefox-debug": { + "icon": "https://community.chocolatey.org/content/packageimages/vscode-firefox-debug.2.9.8.png", + "images": [] + }, + "vscode-gitattributes": { + "icon": "https://community.chocolatey.org/content/packageimages/vscode-gitattributes.0.4.1.20190310.png", + "images": [] + }, + "vscode-gitignore": { + "icon": "https://community.chocolatey.org/content/packageimages/vscode-gitignore.0.9.0.png", + "images": [] + }, + "vscode-gitlens": { + "icon": "https://community.chocolatey.org/content/packageimages/vscode-gitlens.1.0.0.20181011.png", + "images": [] + }, + "vscode-go": { + "icon": "https://community.chocolatey.org/content/packageimages/vscode-go.0.37.1.png", + "images": [] + }, + "vscode-go-nightly": { + "icon": "https://community.chocolatey.org/content/packageimages/vscode-go-nightly.2023.2.2621.png", + "images": [] + }, + "vscode-go-test-adapter": { + "icon": "https://community.chocolatey.org/content/packageimages/vscode-go-test-adapter.0.1.6.png", + "images": [] + }, + "vscode-haskell": { + "icon": "https://community.chocolatey.org/content/packageimages/vscode-haskell.2.2.2.png", + "images": [] + }, + "vscode-icons": { + "icon": "https://community.chocolatey.org/content/packageimages/vscode-icons.1.0.0.20190314.png", + "images": [] + }, + "vscode-insiders": { + "icon": "https://community.chocolatey.org/content/packageimages/vscode-insiders.1.76.0.20230227.png", + "images": [] + }, + "vscode-intellicode": { + "icon": "https://community.chocolatey.org/content/packageimages/vscode-intellicode.1.2.30.png", + "images": [] + }, + "vscode-java": { + "icon": "https://community.chocolatey.org/content/packageimages/vscode-java.1.16.2023022403.png", + "images": [] + }, + "vscode-java-debug": { + "icon": "https://community.chocolatey.org/content/packageimages/vscode-java-debug.0.48.2023021407.png", + "images": [] + }, + "vscode-java-dependency": { + "icon": "https://community.chocolatey.org/content/packageimages/vscode-java-dependency.0.21.2023021500.png", + "images": [] + }, + "vscode-jscslinting": { + "icon": "https://community.chocolatey.org/content/packageimages/vscode-jscslinting.1.0.0.20181011.png", + "images": [] + }, + "vscode-jshint": { + "icon": "https://community.chocolatey.org/content/packageimages/vscode-jshint.1.0.0.20181011.png", + "images": [] + }, + "vscode-jupyter": { + "icon": "https://community.chocolatey.org/content/packageimages/vscode-jupyter.2023.2.1000561009.png", + "images": [] + }, + "vscode-kubernetes-tools": { + "icon": "https://community.chocolatey.org/content/packageimages/vscode-kubernetes-tools.1.3.11.png", + "images": [] + }, + "vscode-live-share": { + "icon": "", + "images": [] + }, + "vscode-live-share-audio": { + "icon": "https://community.chocolatey.org/content/packageimages/vscode-live-share-audio.0.1.93.png", + "images": [] + }, + "vscode-markdown-all-in-one": { + "icon": "https://community.chocolatey.org/content/packageimages/vscode-markdown-all-in-one.3.4.0.png", + "images": [] + }, + "vscode-markdownlint": { + "icon": "https://community.chocolatey.org/content/packageimages/vscode-markdownlint.1.0.0.20181011.png", + "images": [] + }, + "vscode-maven": { + "icon": "https://community.chocolatey.org/content/packageimages/vscode-maven.0.38.2022090603.png", + "images": [] + }, + "vscode-mongodb": { + "icon": "https://community.chocolatey.org/content/packageimages/vscode-mongodb.0.10.0.png", + "images": [] + }, + "vscode-mssql": { + "icon": "https://community.chocolatey.org/content/packageimages/vscode-mssql.1.6.0.png", + "images": [] + }, + "vscode-oracle-devtools": { + "icon": "https://community.chocolatey.org/content/packageimages/vscode-oracle-devtools.21.5.0.png", + "images": [] + }, + "vscode-powershell": { + "icon": "https://community.chocolatey.org/content/packageimages/vscode-powershell.2022.8.5.png", + "images": [] + }, + "vscode-prettier": { + "icon": "https://community.chocolatey.org/content/packageimages/vscode-prettier.9.10.4.png", + "images": [] + }, + "vscode-pull-request-github": { + "icon": "https://community.chocolatey.org/content/packageimages/vscode-pull-request-github.0.59.2023022411.png", + "images": [] + }, + "vscode-pylance": { + "icon": "https://community.chocolatey.org/content/packageimages/vscode-pylance.2023.2.43.png", + "images": [] + }, + "vscode-python": { + "icon": "https://community.chocolatey.org/content/packageimages/vscode-python.2022.19.13071014.png", + "images": [] + }, + "vscode-python-test-adapter": { + "icon": "", + "images": [] + }, + "vscode-react-native": { + "icon": "https://community.chocolatey.org/content/packageimages/vscode-react-native.1.10.0.png", + "images": [] + }, + "vscode-ruby": { + "icon": "https://community.chocolatey.org/content/packageimages/vscode-ruby.0.28.1.png", + "images": [] + }, + "vscode-rust-test-adapter": { + "icon": "https://community.chocolatey.org/content/packageimages/vscode-rust-test-adapter.0.11.0.png", + "images": [] + }, + "vscode-settingssync": { + "icon": "https://community.chocolatey.org/content/packageimages/vscode-settingssync.1.0.0.0.png", + "images": [] + }, + "vscode-spring-boot": { + "icon": "https://community.chocolatey.org/content/packageimages/vscode-spring-boot.1.31.0.png", + "images": [] + }, + "vscode-spring-boot-dashboard": { + "icon": "https://community.chocolatey.org/content/packageimages/vscode-spring-boot-dashboard.0.11.2023022800.png", + "images": [] + }, + "vscode-spring-initializr": { + "icon": "", + "images": [] + }, + "vscode-terraform": { + "icon": "https://community.chocolatey.org/content/packageimages/vscode-terraform.2.25.4.png", + "images": [] + }, + "vscode-test-explorer": { + "icon": "https://community.chocolatey.org/content/packageimages/vscode-test-explorer.2.21.1.png", + "images": [] + }, + "vscode-test-explorer-diagnostics": { + "icon": "https://community.chocolatey.org/content/packageimages/vscode-test-explorer-diagnostics.0.1.1.png", + "images": [] + }, + "vscode-test-explorer-liveshare": { + "icon": "https://community.chocolatey.org/content/packageimages/vscode-test-explorer-liveshare.1.0.5.png", + "images": [] + }, + "vscode-test-explorer-status-bar": { + "icon": "https://community.chocolatey.org/content/packageimages/vscode-test-explorer-status-bar.1.2.0.png", + "images": [] + }, + "vscode-todo-tree": { + "icon": "https://community.chocolatey.org/content/packageimages/vscode-todo-tree.0.0.224.png", + "images": [] + }, + "vscode-tslint": { + "icon": "https://community.chocolatey.org/content/packageimages/vscode-tslint.1.0.0.20190730.png", + "images": [] + }, + "vscode-vsonline": { + "icon": "https://community.chocolatey.org/content/packageimages/vscode-vsonline.1.0.3076.png", + "images": [] + }, + "vscode-xmltools": { + "icon": "https://community.chocolatey.org/content/packageimages/vscode-xmltools.2.5.1.png", + "images": [] + }, + "vscodium": { + "icon": "https://dl.flathub.org/media/com/vscodium/codium/6efa4be7fea2ee9f93db27a85f515cc3/icons/128x128/com.vscodium.codium.png", + "images": [ + "https://upload.wikimedia.org/wikipedia/commons/thumb/e/e9/VS_Code_%28Insiders%29.png/800px-VS_Code_%28Insiders%29.png?20210728074118" + ] + }, + "vscodium-insiders": { + "icon": "https://dl.flathub.org/media/com/vscodium/codium-insiders/8b559d12716a7f31e2aafc6193c1edb8/icons/128x128/com.vscodium.codium-insiders.png", + "images": [] + }, + "vspatialremotedesktop": { + "icon": "", + "images": [] + }, + "vstor2010": { + "icon": "", + "images": [] + }, + "vsts-admin-tools": { + "icon": "https://community.chocolatey.org/content/packageimages/vsts-admin-tools.1.0.12.png", + "images": [] + }, + "vsts-cli": { + "icon": "https://community.chocolatey.org/content/packageimages/vsts-cli.0.1.4.20190126.png", + "images": [] + }, + "vsvim": { + "icon": "", + "images": [] + }, + "vswhere": { + "icon": "", + "images": [] + }, + "vt-cli": { + "icon": "https://community.chocolatey.org/content/packageimages/vt-cli.0.11.1.png", + "images": [] + }, + "vt-uploader": { + "icon": "", + "images": [] + }, + "vtfedit": { + "icon": "", + "images": [] + }, + "vtools": { + "icon": "https://community.chocolatey.org/content/packageimages/vtools.01.05.png", + "images": [] + }, + "vuescan": { + "icon": "https://community.chocolatey.org/content/packageimages/vuescan.9.7.97.png", + "images": [] + }, + "vulkan": { + "icon": "", + "images": [] + }, + "vulkansdk": { + "icon": "", + "images": [] + }, + "vultr": { + "icon": "", + "images": [] + }, + "vultr-cli": { + "icon": "https://community.chocolatey.org/content/packageimages/vultr-cli.portable.2.15.0.png", + "images": [] + }, + "vuplayer": { + "icon": "", + "images": [] + }, + "vuzeclient": { + "icon": "https://community.chocolatey.org/content/packageimages/vuzeclient.1.11.1.png", + "images": [] + }, + "vvvv-addonpack": { + "icon": "https://community.chocolatey.org/content/packageimages/vvvv-addonpack.36.1.png", + "images": [] + }, + "vvvv-addonpack-x64": { + "icon": "https://community.chocolatey.org/content/packageimages/vvvv-addonpack.x64.29.2.png", + "images": [] + }, + "vvvv-addonpack-x86": { + "icon": "https://community.chocolatey.org/content/packageimages/vvvv-addonpack.x86.29.2.png", + "images": [] + }, + "vvvv-x64": { + "icon": "https://community.chocolatey.org/content/packageimages/vvvv.x64.29.2.1.png", + "images": [] + }, + "vvvv-x86": { + "icon": "https://community.chocolatey.org/content/packageimages/vvvv.x86.29.2.1.png", + "images": [] + }, + "vym": { + "icon": "", + "images": [] + }, + "vyprvpn": { + "icon": "", + "images": [] + }, + "vysor": { + "icon": "", + "images": [] + }, + "w10privacy": { + "icon": "https://community.chocolatey.org/content/packageimages/w10privacy.4.1.2.1.png", + "images": [] + }, + "w2klockdesktop": { + "icon": "", + "images": [] + }, + "w64devkit": { + "icon": "", + "images": [] + }, + "wabt": { + "icon": "", + "images": [] + }, + "wacom-drivers": { + "icon": "https://community.chocolatey.org/content/packageimages/wacom-drivers.6.4.1.3.png", + "images": [] + }, + "wacomtabletdriver": { + "icon": "https://upload.wikimedia.org/wikipedia/en/thumb/7/7e/Wacom_Logo_WhiteType.svg/254px-Wacom_Logo_WhiteType.svg.png", + "images": [] + }, + "waifu2x-caffe": { + "icon": "", + "images": [] + }, + "waifu2x-converter-cpp": { + "icon": "", + "images": [] + }, + "waifu2x-extension-gui": { + "icon": "", + "images": [] + }, + "waifu2x-ncnn-vulkan": { + "icon": "", + "images": [] + }, + "waifu2x-snowshell": { + "icon": "", + "images": [] + }, + "waifu2xgui": { + "icon": "", + "images": [] + }, + "waiua": { + "icon": "", + "images": [] + }, + "wakatime-cli": { + "icon": "", + "images": [] + }, + "wakemeonlan": { + "icon": "https://i.postimg.cc/vZWm0BgX/image.png", + "images": [ + "https://i.postimg.cc/SsZRcvXw/image.png" + ] + }, + "wallcat": { + "icon": "https://community.chocolatey.org/content/packageimages/wallcat.1.0.4.png", + "images": [] + }, + "wallhaven-electron": { + "icon": "", + "images": [] + }, + "wamp": { + "icon": "", + "images": [] + }, + "wapm-cli": { + "icon": "", + "images": [] + }, + "warframe": { + "icon": "", + "images": [] + }, + "warmup": { + "icon": "", + "images": [] + }, + "Winget.Cloudflare.Warp": { + "icon": "https://i.postimg.cc/wT15bYsJ/cloudwarp.png", + "images": [ + "https://i.postimg.cc/GhhW9QSz/image.png", + "https://i.postimg.cc/KjY0c9vM/image.png", + "https://i.postimg.cc/KvDtp7GX/image.png" + ] + }, + "Winget.Warp.Warp": { + "icon": "https://i.postimg.cc/kGK1RH4Y/warp-icon.png", + "images": [ + "https://i.postimg.cc/SNL1yHHJ/warp-banner.png", + "https://i.postimg.cc/xTVFV9xw/warp-screenshot.png" + ] + }, + "warthunder": { + "icon": "https://cdn2.steamgriddb.com/icon_thumb/3fdc6213681ba98cb5a95150380e0e04.png", + "images": [ + "https://cdn2.steamgriddb.com/logo/54d22f8632eb479849f7bad14f024ce5.png", + "https://i.postimg.cc/x8sJFJZb/image.png", + "https://i.postimg.cc/rsyRJCfk/image.png", + "https://cdn2.steamgriddb.com/hero/632e3ccec223290601ef00e26aa62bd0.png", + "https://cdn2.steamgriddb.com/hero/1a551b7323fefa14d9b4ac09bd73ee49.png", + "https://cdn2.steamgriddb.com/hero/460c9b5698f98c052062fd25e2b2f6de.png", + "https://cdn2.steamgriddb.com/hero/a8c5a73459631beb2cbe6af3c74628e8.png", + "https://cdn2.steamgriddb.com/hero/dc19fa59fb460f069c2e609348abfc77.png", + "https://cdn2.steamgriddb.com/hero/d5e7a42f848de89069733d940881fa90.png", + "https://cdn2.steamgriddb.com/hero/e38b7566fe907e0d2fec9a0f9af72d9f.png", + "https://i.postimg.cc/zBzTtrf6/image.png", + "https://i.postimg.cc/yxWcKycT/image.png", + "https://i.postimg.cc/PJcZ5vMn/image.png", + "https://i.postimg.cc/Bn2DJ6LR/image.png", + "https://i.postimg.cc/1zPFXQDX/image.png", + "https://i.postimg.cc/7LV2TWNV/image.png" + ] + }, + "warzone2100": { + "icon": "", + "images": [] + }, + "was-liberty-java-ee7-full-platform": { + "icon": "https://community.chocolatey.org/content/packageimages/was-liberty-java-ee7-full-platform.19.0.0.9.png", + "images": [] + }, + "was-liberty-java-ee8-web-profile": { + "icon": "https://community.chocolatey.org/content/packageimages/was-liberty-java-ee8-web-profile.19.0.0.9.png", + "images": [] + }, + "wash": { + "icon": "", + "images": [] + }, + "wasm4": { + "icon": "", + "images": [] + }, + "wasmedge": { + "icon": "", + "images": [] + }, + "wasmer": { + "icon": "", + "images": [] + }, + "wasmtime": { + "icon": "", + "images": [] + }, + "wassapp": { + "icon": "https://community.chocolatey.org/content/packageimages/wassapp.1.1.1.1.png", + "images": [] + }, + "watchexec": { + "icon": "", + "images": [] + }, + "watchman": { + "icon": "https://community.chocolatey.org/content/packageimages/watchman.2022.09.19.00.png", + "images": [] + }, + "waterfox": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/2/2a/Waterfox_logo_2019.png", + "images": [] + }, + "waterfox-classic": { + "icon": "https://temosoft.com/wp-content/uploads/2018/09/waterfox-logo.png", + "images": [] + }, + "watlow-composer": { + "icon": "", + "images": [] + }, + "wav2bar": { + "icon": "", + "images": [] + }, + "wave-engine": { + "icon": "https://community.chocolatey.org/content/packageimages/wave-engine.2.5.0.20190125.png", + "images": [] + }, + "wavebox": { + "icon": "https://community.chocolatey.org/content/packageimages/wavebox.10.110.26.png", + "images": [] + }, + "wavebox-classic": { + "icon": "", + "images": [] + }, + "wavebox-unstable": { + "icon": "https://community.chocolatey.org/content/packageimages/wavebox-unstable.10.110.29.3.png", + "images": [] + }, + "wavelink": { + "icon": "https://windows-cdn.softpedia.com/screenshots/ico/Elgato-Wave-Link.png", + "images": [] + }, + "wavescentral": { + "icon": "", + "images": [] + }, + "wavesurfer": { + "icon": "https://community.chocolatey.org/content/packageimages/wavesurfer.1.8.84.20160822.png", + "images": [] + }, + "wavosaur": { + "icon": "https://community.chocolatey.org/content/packageimages/wavosaur.1.7.0.0.png", + "images": [] + }, + "wavpack": { + "icon": "https://community.chocolatey.org/content/packageimages/wavpack.4.80.0.png", + "images": [] + }, + "wavpack7z": { + "icon": "", + "images": [] + }, + "wawi": { + "icon": "", + "images": [] + }, + "waypoint": { + "icon": "", + "images": [] + }, + "wazuh-agent": { + "icon": "", + "images": [] + }, + "wazuhagent": { + "icon": "", + "images": [] + }, + "wc3270": { + "icon": "https://community.chocolatey.org/content/packageimages/WC3270.4.2.8.png", + "images": [] + }, + "wcat": { + "icon": "", + "images": [] + }, + "wcfservice": { + "icon": "", + "images": [] + }, + "wcfservice1": { + "icon": "", + "images": [] + }, + "wd-backup": { + "icon": "https://community.chocolatey.org/content/packageimages/wd-backup.1.9.7435.38388.png", + "images": [] + }, + "wd-dashboard": { + "icon": "https://community.chocolatey.org/content/packageimages/wd-dashboard.3.8.2.9.png", + "images": [] + }, + "wd-security": { + "icon": "https://community.chocolatey.org/content/packageimages/wd-security.2.1.0.130.png", + "images": [] + }, + "weakaurascompanion": { + "icon": "", + "images": [] + }, + "weasel": { + "icon": "https://community.chocolatey.org/content/packageimages/weasel.0.14.3.20220220.png", + "images": [] + }, + "weasel-pageant": { + "icon": "", + "images": [] + }, + "weasis": { + "icon": "https://community.chocolatey.org/content/packageimages/weasis.4.0.3.png", + "images": [] + }, + "weather-chrome": { + "icon": "https://community.chocolatey.org/content/packageimages/weather-chrome.4.2.97.png", + "images": [] + }, + "webbrowserpassview": { + "icon": "https://community.chocolatey.org/content/packageimages/webbrowserpassview.portable.1.85.png", + "images": [] + }, + "webcacheimageinfo": { + "icon": "https://community.chocolatey.org/content/packageimages/webcacheimageinfo.1.30.png", + "images": [] + }, + "webcam-on-off": { + "icon": "", + "images": [] + }, + "webcamimagesave": { + "icon": "https://community.chocolatey.org/content/packageimages/webcamimagesave.1.11.png", + "images": [] + }, + "webcamoid": { + "icon": "", + "images": [] + }, + "webcompiler": { + "icon": "", + "images": [] + }, + "webcookiessniffer": { + "icon": "https://community.chocolatey.org/content/packageimages/webcookiessniffer.1.30.png", + "images": [] + }, + "webcopy": { + "icon": "", + "images": [] + }, + "webcord": { + "icon": "", + "images": [] + }, + "webdeploy": { + "icon": "", + "images": [] + }, + "webdesigner": { + "icon": "", + "images": [] + }, + "webdl": { + "icon": "", + "images": [] + }, + "webdrive": { + "icon": "https://i.postimg.cc/5NcLdbWb/WebDrive.png", + "images": [ + "https://i.postimg.cc/NfgGrz1R/image.png", + "https://southrivertech.com/wp-content/uploads/2023/07/WD_Various_Servers_Connected.png" + ] + }, + "webessentials2015": { + "icon": "", + "images": [] + }, + "webex": { + "icon": "https://community.chocolatey.org/content/packageimages/webex.43.1.0.24716.png", + "images": [] + }, + "webex-meetings": { + "icon": "https://community.chocolatey.org/content/packageimages/webex-meetings.43.3.2.9.png", + "images": [] + }, + "webex-outlook-plugin": { + "icon": "", + "images": [] + }, + "webex-teams": { + "icon": "", + "images": [] + }, + "webexie": { + "icon": "https://community.chocolatey.org/content/packageimages/webexie.29.7.1.6.png", + "images": [] + }, + "webexteams": { + "icon": "https://help.webex.com/images/favicon.png", + "images": [] + }, + "webflipscreensaver": { + "icon": "", + "images": [] + }, + "webhook": { + "icon": "", + "images": [] + }, + "webkiosk-wrapper": { + "icon": "", + "images": [] + }, + "webkitty": { + "icon": "", + "images": [] + }, + "webmailconverter": { + "icon": "https://community.chocolatey.org/content/packageimages/WebMailConverter.3.1.png", + "images": [] + }, + "webmcam": { + "icon": "https://community.chocolatey.org/content/packageimages/webmcam.2.4.1.png", + "images": [] + }, + "webmforpremiere": { + "icon": "", + "images": [] + }, + "webos-dev-manager": { + "icon": "https://community.chocolatey.org/content/packageimages/webos-dev-manager.1.10.0.png", + "images": [] + }, + "webp": { + "icon": "https://community.chocolatey.org/content/packageimages/webp.1.0.0.png", + "images": [] + }, + "webpacktaskrunner": { + "icon": "", + "images": [] + }, + "webpconverter": { + "icon": "https://vovsoft.com/icons128/webp-converter.png", + "images": [ + "https://vovsoft.com/screenshots/webp-converter.png", + "https://vovsoft.com/screenshots/webp-converter-2.png", + "https://vovsoft.com/screenshots/webp-converter-3.png" + ] + }, + "webpicmd": { + "icon": "", + "images": [] + }, + "webpicommandline": { + "icon": "", + "images": [] + }, + "webproxy": { + "icon": "https://community.chocolatey.org/content/packageimages/webproxy.2.7.0.png", + "images": [] + }, + "webqueries": { + "icon": "", + "images": [] + }, + "websitesniffer": { + "icon": "https://community.chocolatey.org/content/packageimages/websitesniffer.1.50.png", + "images": [] + }, + "webstorm": { + "icon": "https://resources.jetbrains.com/storage/products/webstorm/img/meta/webstorm_logo_300x300.png", + "images": [] + }, + "webstorm-eap": { + "icon": "https://resources.jetbrains.com/storage/products/webstorm/img/meta/webstorm_logo_300x300.png", + "images": [] + }, + "webswing": { + "icon": "https://community.chocolatey.org/content/packageimages/webswing.2.5.10.png", + "images": [] + }, + "webtorrent": { + "icon": "https://community.chocolatey.org/content/packageimages/webtorrent-desktop.0.24.0.png", + "images": [] + }, + "webtorrent-desktop": { + "icon": "https://community.chocolatey.org/content/packageimages/webtorrent-desktop.0.24.0.png", + "images": [ + "https://webtorrent.io/img/screenshot-main.png", + "https://webtorrent.io/img/screenshot-player.png", + "https://webtorrent.io/img/network.png" + ] + }, + "webvideocap": { + "icon": "https://community.chocolatey.org/content/packageimages/webvideocap.1.41.png", + "images": [] + }, + "webview2-runtime": { + "icon": "https://community.chocolatey.org/content/packageimages/webview2-runtime.110.0.1587.56.png", + "images": [] + }, + "wechat": { + "icon": "https://pp.myapp.com/ma_icon/0/icon_10910_1753099072/256.png", + "images": [ + "https://res.wx.qq.com/t/wx_fed/base/weixin_portal/res/static/img/3iay9ly.png", + "https://res.wx.qq.com/t/wx_fed/base/weixin_portal/res/static/img/v6Q8nnL.png" + ] + }, + "wechat-universal": { + "icon": "https://pp.myapp.com/ma_icon/0/icon_10910_1753099072/256.png", + "images": [ + "https://res.wx.qq.com/t/fed_upload/7d5aac613b423c3b246a5a2827b8ab1b/1.png", + "https://res.wx.qq.com/t/fed_upload/56a84421870dd0a5700bf2585e403e5d/darkmode.png" + ] + }, + "wechat-work": { + "icon": "https://dldir1.qq.com/foxmail/icon/work_logo.png", + "images": [] + }, + "wechatdevtools": { + "icon": "https://raw.githubusercontent.com/msojocs/wechat-web-devtools-linux/master/res/icons/512x512.png", + "images": [ + "https://res.wx.qq.com/wxdoc/dist/assets/img/main.9b443fbd.png", + "https://res.wx.qq.com/wxdoc/dist/assets/img/projectlist.41fad5cf.png" + ] + }, + "wecom": { + "icon": "https://dldir1.qq.com/foxmail/icon/work_logo.png", + "images": [ + "https://res.wx.qq.com/wxdoc/dist/assets/img/application2.803df32d.png", + "https://wwcdn.weixin.qq.com/node/wework/images/wecom-temp-f9247fc9ed69949f3e3cd39480410738.4145f338c0.png" + ] + }, + "weebp": { + "icon": "", + "images": [] + }, + "weixin-dev-tools": { + "icon": "https://file.service.qq.com/user-files/uploads/201612/0ce9ee10d3099f9989a81308811be588.png", + "images": [ + "https://res.wx.qq.com/wxdoc/dist/assets/img/main.9b443fbd.png", + "https://res.wx.qq.com/wxdoc/dist/assets/img/projectlist.41fad5cf.png" + ] + }, + "weixindevtools": { + "icon": "", + "images": [] + }, + "weiyun": { + "icon": "", + "images": [] + }, + "weiyunsync": { + "icon": "", + "images": [] + }, + "weka": { + "icon": "https://community.chocolatey.org/content/packageimages/Weka.3.8.6.png", + "images": [] + }, + "welink": { + "icon": "", + "images": [] + }, + "wemeetoutlookplugin": { + "icon": "", + "images": [] + }, + "wemod": { + "icon": "https://i.imgur.com/7Mstj5O.png", + "images": [ + "https://i.imgur.com/qo57Usj.png" + ] + }, + "wemod-beta": { + "icon": "https://i.imgur.com/7Mstj5O.png", + "images": [ + "https://i.imgur.com/qo57Usj.png" + ] + }, + "wesing": { + "icon": "", + "images": [] + }, + "wesingliveassistant": { + "icon": "", + "images": [] + }, + "wesnoth": { + "icon": "https://community.chocolatey.org/content/packageimages/wesnoth.1.16.8.png", + "images": [] + }, + "westwindhtmlhelpbuilder": { + "icon": "https://community.chocolatey.org/content/packageimages/WestwindHtmlHelpBuilder.5.33.png", + "images": [] + }, + "westwindwebmonitor": { + "icon": "https://community.chocolatey.org/content/packageimages/WestwindWebMonitor.3.50.png", + "images": [] + }, + "westwindwebsurge": { + "icon": "https://community.chocolatey.org/content/packageimages/WestwindWebSurge.2.2.4.png", + "images": [] + }, + "wevpn": { + "icon": "", + "images": [] + }, + "wewechat": { + "icon": "", + "images": [] + }, + "wexond": { + "icon": "", + "images": [] + }, + "weylus": { + "icon": "", + "images": [] + }, + "wezterm": { + "icon": "https://community.chocolatey.org/content/packageimages/wezterm.portable.20221119.145034.png", + "images": [] + }, + "wfilecheck": { + "icon": "https://community.chocolatey.org/content/packageimages/wfilecheck.0.4.png", + "images": [] + }, + "wgcf": { + "icon": "", + "images": [] + }, + "wget": { + "icon": "https://community.chocolatey.org/content/packageimages/Wget.1.21.3.png", + "images": [] + }, + "wget2": { + "icon": "", + "images": [] + }, + "whale": { + "icon": "https://community.chocolatey.org/content/packageimages/whale.2.4.0.png", + "images": [] + }, + "whalebird-desktop": { + "icon": "", + "images": [] + }, + "whatinstartup": { + "icon": "https://community.chocolatey.org/content/packageimages/whatinstartup.1.35.png", + "images": [] + }, + "whatishang": { + "icon": "https://community.chocolatey.org/content/packageimages/whatishang.1.27.png", + "images": [ + "https://i.postimg.cc/bwjyShCR/image.png" + ] + }, + "whatpulse": { + "icon": "", + "images": [] + }, + "whatsapp": { + "icon": "https://i.postimg.cc/jjzdZ4GZ/WhatsApp.png", + "images": [] + }, + "whatsapp-beta": { + "icon": "https://i.postimg.cc/jjzdZ4GZ/WhatsApp.png", + "images": [] + }, + "whatsappdesktop": { + "icon": "https://i.postimg.cc/jjzdZ4GZ/WhatsApp.png", + "images": [] + }, + "whatsapptray": { + "icon": "https://community.chocolatey.org/content/packageimages/whatsapptray.1.9.0.png", + "images": [] + }, + "which": { + "icon": "", + "images": [] + }, + "whitebox": { + "icon": "https://community.chocolatey.org/content/packageimages/whitebox.portable.3.4.0.20180608.png", + "images": [] + }, + "whkd": { + "icon": "", + "images": [] + }, + "whocrashed": { + "icon": "", + "images": [] + }, + "whois": { + "icon": "https://community.chocolatey.org/content/packageimages/whois.1.21.png", + "images": [] + }, + "whoiscl": { + "icon": "", + "images": [] + }, + "whoisconnectedsniffer": { + "icon": "", + "images": [] + }, + "whoistd": { + "icon": "https://community.chocolatey.org/content/packageimages/whoistd.2.36.png", + "images": [] + }, + "whoisthisdomain": { + "icon": "https://i.postimg.cc/V67Q7yW7/image.png", + "images": [ + "https://i.postimg.cc/DzPKX4Jn/image.png" + ] + }, + "whosip": { + "icon": "", + "images": [] + }, + "whynotwin11": { + "icon": "", + "images": [] + }, + "whysoslow": { + "icon": "https://community.chocolatey.org/content/packageimages/whysoslow.1.00.png", + "images": [] + }, + "wia-loader": { + "icon": "", + "images": [] + }, + "widelands": { + "icon": "https://community.chocolatey.org/content/packageimages/widelands.18.0.png", + "images": [] + }, + "wifi-manager": { + "icon": "https://community.chocolatey.org/content/packageimages/wifi-manager.0.2.png", + "images": [] + }, + "wifichannelmonitor": { + "icon": "https://community.chocolatey.org/content/packageimages/wifichannelmonitor.1.59.png", + "images": [] + }, + "wifidiagnosticsview": { + "icon": "https://i.postimg.cc/YCqpz377/image.png", + "images": [ + "https://i.postimg.cc/htyKyd4y/image.png" + ] + }, + "wifiguard": { + "icon": "https://community.chocolatey.org/content/packageimages/wifiguard.2.2.0.png", + "images": [] + }, + "wifimouseserver": { + "icon": "", + "images": [] + }, + "wigui": { + "icon": "", + "images": [] + }, + "wikidpad": { + "icon": "", + "images": [] + }, + "wikidpad-alpha": { + "icon": "", + "images": [] + }, + "wikimed": { + "icon": "", + "images": [] + }, + "wikimed-electron": { + "icon": "", + "images": [] + }, + "wikivoyage": { + "icon": "", + "images": [] + }, + "wikivoyage-electron": { + "icon": "", + "images": [] + }, + "wimlib": { + "icon": "https://community.chocolatey.org/content/packageimages/wimlib.1.13.6.png", + "images": [] + }, + "win-acme": { + "icon": "", + "images": [] + }, + "win-caffeinate": { + "icon": "https://community.chocolatey.org/content/packageimages/caffeine.1.97.0.20210517.png", + "images": [ + "https://i.postimg.cc/k5nPsNjK/image.png" + ] + }, + "win-dynamic-desktop": { + "icon": "", + "images": [] + }, + "win-gpg-agent": { + "icon": "https://community.chocolatey.org/content/packageimages/win-gpg-agent.1.6.3.png", + "images": [] + }, + "win-no-annoy": { + "icon": "", + "images": [] + }, + "win-portacle": { + "icon": "", + "images": [] + }, + "win-rdm": { + "icon": "https://community.chocolatey.org/content/packageimages/win-rdm.2021.7.png", + "images": [] + }, + "win-sshfs": { + "icon": "", + "images": [] + }, + "win-vind": { + "icon": "", + "images": [] + }, + "win-xkill": { + "icon": "", + "images": [] + }, + "win-youtube-dl": { + "icon": "https://community.chocolatey.org/content/packageimages/win-youtube-dl.1.1.0.png", + "images": [] + }, + "win10-brightnessslider": { + "icon": "", + "images": [] + }, + "win10mct": { + "icon": "https://community.chocolatey.org/content/packageimages/win10mct.10.0.19041.572.png", + "images": [] + }, + "win10pcap": { + "icon": "", + "images": [] + }, + "win11dragdroptaskbarfix": { + "icon": "", + "images": [] + }, + "win11react": { + "icon": "", + "images": [] + }, + "win2003-mklink": { + "icon": "", + "images": [] + }, + "win32-disk-imager": { + "icon": "", + "images": [] + }, + "win32-openssh": { + "icon": "https://community.chocolatey.org/content/packageimages/win32-openssh.2016.05.30.20160922.png", + "images": [] + }, + "win32diskimager": { + "icon": "https://community.chocolatey.org/content/packageimages/win32diskimager.portable.1.0.0.20181220.png", + "images": [] + }, + "win32yank": { + "icon": "", + "images": [] + }, + "win9xpv": { + "icon": "https://community.chocolatey.org/content/packageimages/win9xpv.1.1.png", + "images": [] + }, + "winaero-tweaker": { + "icon": "https://community.chocolatey.org/content/packageimages/winaero-tweaker.install.1.40.0.0.png", + "images": [] + }, + "winamp": { + "icon": "https://i.imgur.com/gSQ2mle.png", + "images": [ + "https://i.imgur.com/WASmcBJ.png" + ] + }, + "winappdriver": { + "icon": "", + "images": [] + }, + "winaudit": { + "icon": "https://community.chocolatey.org/content/packageimages/winaudit.3.0.11.0.png", + "images": [] + }, + "winauth": { + "icon": "", + "images": [] + }, + "winbareos": { + "icon": "https://community.chocolatey.org/content/packageimages/winbareos.install.15.2.2.png", + "images": [] + }, + "winbolt": { + "icon": "https://community.chocolatey.org/content/packageimages/WinBOLT.3.2.png", + "images": [] + }, + "winbox": { + "icon": "https://i.postimg.cc/8CKZvh7N/winbox.png", + "images": [ + "https://i.postimg.cc/DZPRRWZs/image.png", + "https://i.postimg.cc/gjc1pYLp/image.png", + "https://i.postimg.cc/D0CHyt1B/image.png", + "https://i.postimg.cc/YqsTcBpb/image.png", + "https://i.postimg.cc/nLtRZH6F/image.png", + "https://i.postimg.cc/dtk4ykYm/image.png" + ] + }, + "winbtrfs": { + "icon": "", + "images": [] + }, + "wincam": { + "icon": "", + "images": [] + }, + "wincaptureaudio-beta": { + "icon": "", + "images": [] + }, + "wincdemu": { + "icon": "https://community.chocolatey.org/content/packageimages/wincdemu.4.1.0.20171221.png", + "images": [] + }, + "wincompose": { + "icon": "https://community.chocolatey.org/content/packageimages/wincompose.install.0.9.11.png", + "images": [] + }, + "wincontig": { + "icon": "https://community.chocolatey.org/content/packageimages/wincontig.1.35.03.png", + "images": [] + }, + "wincrashreport": { + "icon": "https://community.chocolatey.org/content/packageimages/wincrashreport.1.25.png", + "images": [] + }, + "wincrypt-sshagent": { + "icon": "", + "images": [] + }, + "wincrypthashers": { + "icon": "", + "images": [] + }, + "wincvt": { + "icon": "", + "images": [] + }, + "wincy": { + "icon": "", + "images": [] + }, + "wincyapk": { + "icon": "", + "images": [] + }, + "windhawk": { + "icon": "https://community.chocolatey.org/content/packageimages/windhawk.1.7.2.png", + "images": [ + "https://i.imgur.com/fszFq44.png", + "https://i.imgur.com/PlkUIje.png" + ] + }, + "windiff": { + "icon": "", + "images": [] + }, + "windirstat": { + "icon": "https://i.postimg.cc/hGB1VDfg/windirstat-1-1-2-20161210.png", + "images": [ + "https://i.postimg.cc/gjnVGrBy/image.png" + ] + }, + "windjview": { + "icon": "https://i.imgur.com/8x1CTVD.png", + "images": [ + "https://windjview.sourceforge.io/screenshot.png" + ] + }, + "windowblinds": { + "icon": "https://community.chocolatey.org/content/packageimages/windowblinds.10.89.png", + "images": [] + }, + "windowclippings": { + "icon": "", + "images": [] + }, + "windowdetective": { + "icon": "https://community.chocolatey.org/content/packageimages/windowdetective.3.2.1.png", + "images": [] + }, + "windowfx": { + "icon": "https://community.chocolatey.org/content/packageimages/windowfx.6.13.png", + "images": [] + }, + "windowgrid": { + "icon": "https://community.chocolatey.org/content/packageimages/windowgrid.1.3.1.1.png", + "images": [] + }, + "windowinspector": { + "icon": "", + "images": [ + "https://i.postimg.cc/6qyPXGGn/image.png", + "https://i.postimg.cc/PfRcMKB4/image.png" + ] + }, + "windows-11-installation-assistant": { + "icon": "https://community.chocolatey.org/content/packageimages/windows-11-installation-assistant.1.4.19041.1285.png", + "images": [] + }, + "windows-adk": { + "icon": "https://community.chocolatey.org/content/packageimages/windows-adk.10.1.22621.1.png", + "images": [] + }, + "windows-adk-all": { + "icon": "https://community.chocolatey.org/content/packageimages/windows-adk-all.10.1.22621.1.png", + "images": [] + }, + "windows-adk-deploy": { + "icon": "", + "images": [] + }, + "windows-adk-oscdimg": { + "icon": "https://community.chocolatey.org/content/packageimages/windows-adk-oscdimg.10.1.png", + "images": [] + }, + "windows-adk-winpe": { + "icon": "https://community.chocolatey.org/content/packageimages/windows-adk-winpe.10.1.22621.1.png", + "images": [] + }, + "windows-admin-center": { + "icon": "https://community.chocolatey.org/content/packageimages/windows-admin-center.1.4.61699.0.png", + "images": [] + }, + "windows-application-driver": { + "icon": "", + "images": [] + }, + "windows-cryptographic-provider-development-kit": { + "icon": "", + "images": [] + }, + "windows-defender-browser-protection-chrome": { + "icon": "https://community.chocolatey.org/content/packageimages/windows-defender-browser-protection-chrome.1.62.png", + "images": [] + }, + "windows-iso-downloader": { + "icon": "", + "images": [] + }, + "windows-kill": { + "icon": "https://community.chocolatey.org/content/packageimages/windows-kill.1.1.4.png", + "images": [] + }, + "windows-performance-toolkit": { + "icon": "", + "images": [] + }, + "windows-repair-toolbox": { + "icon": "https://community.chocolatey.org/content/packageimages/windows-repair-toolbox.3.0.2.5.png", + "images": [] + }, + "windows-sandbox": { + "icon": "https://community.chocolatey.org/content/packageimages/windows-sandbox.0.0.1.png", + "images": [] + }, + "windows-sdk-10-1": { + "icon": "https://community.chocolatey.org/content/packageimages/windows-sdk-10.1.10.1.18362.1.png", + "images": [] + }, + "windows-sdk-10-version-1803-windbg": { + "icon": "", + "images": [] + }, + "windows-sdk-10-version-1809-all": { + "icon": "", + "images": [] + }, + "windows-sdk-10-version-2004-all": { + "icon": "", + "images": [] + }, + "windows-sdk-10-version-2004-windbg": { + "icon": "", + "images": [] + }, + "windows-sdk-11-version-22h2-all": { + "icon": "", + "images": [] + }, + "windows-sdk-6-0": { + "icon": "https://community.chocolatey.org/content/packageimages/windows-sdk-6.0.6.1.6000.20220204.png", + "images": [] + }, + "windows-sdk-8-1": { + "icon": "https://community.chocolatey.org/content/packageimages/windows-sdk-8.1.8.100.26654.0.png", + "images": [] + }, + "windows-spotlight": { + "icon": "", + "images": [] + }, + "windows-terminal": { + "icon": "https://winaero.com/blog/wp-content/uploads/2019/06/WIndows-Terminal-icon.png", + "images": [] + }, + "windows-tweaker": { + "icon": "https://community.chocolatey.org/content/packageimages/windows-tweaker.5.3.1.20210210.png", + "images": [] + }, + "windows10-media-creation-tool": { + "icon": "https://community.chocolatey.org/content/packageimages/windows10-media-creation-tool.10.0.19041.572.png", + "images": [] + }, + "windows11-classic-context-menu": { + "icon": "", + "images": [] + }, + "windows95": { + "icon": "https://betanews.com/wp-content/uploads/media/52/5251.png", + "images": [] + }, + "windowsadk": { + "icon": "https://community.chocolatey.org/content/packageimages/WindowsADK.2.0.png", + "images": [] + }, + "windowsadmincenter": { + "icon": "", + "images": [] + }, + "windowsagent": { + "icon": "", + "images": [] + }, + "windowsalarms": { + "icon": "https://i.postimg.cc/wMgJpBs7/Windows-Clock-App-Icon.png", + "images": [] + }, + "windowsapplicationdriver": { + "icon": "", + "images": [] + }, + "windowsappruntime-1-0": { + "icon": "", + "images": [] + }, + "windowsappruntime-1-1": { + "icon": "", + "images": [] + }, + "windowsappruntime-1-2": { + "icon": "", + "images": [] + }, + "windowsautonightmode": { + "icon": "", + "images": [] + }, + "windowsazurelibrariesfornet": { + "icon": "https://community.chocolatey.org/content/packageimages/WindowsAzureLibrariesForNet.2.2.20140119.png", + "images": [] + }, + "windowsazurelibsfornet": { + "icon": "https://community.chocolatey.org/content/packageimages/WindowsAzureLibsForNet.2.9.png", + "images": [] + }, + "windowsazurepowershell": { + "icon": "", + "images": [] + }, + "windowscalculator": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/5/55/Windows_Calculator_icon.png", + "images": [] + }, + "windowscamera": { + "icon": "https://winaero.com/blog/wp-content/uploads/2020/04/Windows-10-Camera-Icon-Fluent-Colorful-2020-1.png", + "images": [] + }, + "windowsdesktop-runtime": { + "icon": "", + "images": [] + }, + "windowsdesktop-runtime-lts": { + "icon": "", + "images": [] + }, + "windowsdriverkit11": { + "icon": "", + "images": [] + }, + "windowserrorlookuptool": { + "icon": "https://community.chocolatey.org/content/packageimages/windowserrorlookuptool.3.0.7.png", + "images": [] + }, + "windowsfirewallcontrol": { + "icon": "https://community.chocolatey.org/content/packageimages/windowsfirewallcontrol.6.9.0.0.png", + "images": [] + }, + "windowsjournal": { + "icon": "", + "images": [] + }, + "windowsliveinstaller": { + "icon": "", + "images": [] + }, + "windowslivemailconverter": { + "icon": "", + "images": [] + }, + "windowslivemesh": { + "icon": "https://community.chocolatey.org/content/packageimages/WindowsLiveMesh.2011.0.0.png", + "images": [] + }, + "windowsmigrationassistant": { + "icon": "https://i.postimg.cc/zBJPcC6V/Migration-Assistant.png", + "images": [ + "https://i.postimg.cc/cHw4FSqs/image.png", + "https://i.postimg.cc/RhTCzLVy/image.png", + "https://i.postimg.cc/BbJsNPcg/image.png" + ] + }, + "windowsnotepad": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/c/c9/Windows_Notepad_icon.png", + "images": [] + }, + "windowspchealthcheck": { + "icon": "", + "images": [] + }, + "windowsphone8sdk": { + "icon": "", + "images": [] + }, + "windowsrepair": { + "icon": "https://community.chocolatey.org/content/packageimages/windowsrepair.4.13.1.png", + "images": [] + }, + "windowssdk": { + "icon": "", + "images": [] + }, + "windowssdk-10-0-19041": { + "icon": "https://i.postimg.cc/rwGzh5vf/Visual-Studio-Icon-2022.png", + "images": [] + }, + "windowsspyblocker": { + "icon": "https://community.chocolatey.org/content/packageimages/windowsspyblocker.4.39.0.png", + "images": [] + }, + "windowsstore": { + "icon": "https://apps.microsoft.com/assets/icons/logo-256x256.png", + "images": [] + }, + "windowstelnet": { + "icon": "", + "images": [] + }, + "windowsterminal": { + "icon": "https://i.ibb.co/TBjm1bMR/terminal.png", + "images": [ + "https://i.ibb.co/pv1Fg0m2/image.png", + "https://i.ibb.co/wZmf8Wzh/image.png" + ] + }, + "windowsterminal-preview": { + "icon": "https://store-images.s-microsoft.com/image/apps.38612.14050269303149694.7e11f917-1bec-40ee-862c-2c5c3983ffb4.c7fa762a-1448-4ba9-93fb-3b4af6a64c4f", + "images": [] + }, + "windowsupdate-disableautorestart": { + "icon": "https://community.chocolatey.org/content/packageimages/WindowsUpdate.DisableAutoRestart.0.0.1.png", + "images": [] + }, + "windowswdk": { + "icon": "", + "images": [] + }, + "windowsxappremover": { + "icon": "https://community.chocolatey.org/content/packageimages/windowsxappremover.1.02.png", + "images": [] + }, + "windowtextextractor": { + "icon": "https://community.chocolatey.org/content/packageimages/windowtextextractor.1.15.0.png", + "images": [] + }, + "windowtop": { + "icon": "", + "images": [] + }, + "windscribe": { + "icon": "https://community.chocolatey.org/content/packageimages/windscribe.2.5.18.png", + "images": [] + }, + "windterm": { + "icon": "", + "images": [] + }, + "windv": { + "icon": "https://community.chocolatey.org/content/packageimages/windv.1.2.3.png", + "images": [] + }, + "windynamicdesktop": { + "icon": "https://community.chocolatey.org/content/packageimages/windynamicdesktop.5.2.1.png", + "images": [ + "https://i.imgur.com/p0zCEdQ.png" + ] + }, + "winedt": { + "icon": "https://community.chocolatey.org/content/packageimages/winedt.10.3.png", + "images": [] + }, + "winexp": { + "icon": "https://community.chocolatey.org/content/packageimages/winexp.1.30.png", + "images": [] + }, + "winfbe": { + "icon": "", + "images": [] + }, + "winfetch": { + "icon": "https://community.chocolatey.org/content/packageimages/winfetch.2.5.0.png", + "images": [] + }, + "winfile": { + "icon": "", + "images": [] + }, + "winfile-original": { + "icon": "", + "images": [] + }, + "winflashtool": { + "icon": "https://community.chocolatey.org/content/packageimages/winflashtool.3.0.png", + "images": [] + }, + "winflector": { + "icon": "https://community.chocolatey.org/content/packageimages/winflector.3.9.6.5.png", + "images": [] + }, + "winflector-client": { + "icon": "https://community.chocolatey.org/content/packageimages/winflector-client.3.9.6.2.png", + "images": [] + }, + "winflexbison": { + "icon": "", + "images": [] + }, + "winflexbison3": { + "icon": "", + "images": [] + }, + "winfontsview": { + "icon": "https://community.chocolatey.org/content/packageimages/winfontsview.1.10.png", + "images": [] + }, + "winfsp": { + "icon": "https://raw.githubusercontent.com/winfsp/winfsp/master/art/winfsp-glow.png", + "images": [] + }, + "wingide": { + "icon": "https://i.postimg.cc/1X55zmcm/wing.png", + "images": [ + "https://i.postimg.cc/Kjzx29x4/image.png", + "https://i.postimg.cc/0NRkwddH/image.png", + "https://i.postimg.cc/436Jb7W4/image.png", + "https://i.postimg.cc/sX33njLY/image.png" + ] + }, + "wingidepersonal": { + "icon": "https://i.postimg.cc/1X55zmcm/wing.png", + "images": [ + "https://i.postimg.cc/Kjzx29x4/image.png", + "https://i.postimg.cc/0NRkwddH/image.png", + "https://i.postimg.cc/436Jb7W4/image.png", + "https://i.postimg.cc/sX33njLY/image.png" + ] + }, + "wingide101": { + "icon": "https://i.postimg.cc/1X55zmcm/wing.png", + "images": [ + "https://i.postimg.cc/Kjzx29x4/image.png", + "https://i.postimg.cc/0NRkwddH/image.png", + "https://i.postimg.cc/436Jb7W4/image.png", + "https://i.postimg.cc/sX33njLY/image.png" + ] + }, + "wing-101": { + "icon": "https://i.postimg.cc/1X55zmcm/wing.png", + "images": [ + "https://i.postimg.cc/Kjzx29x4/image.png", + "https://i.postimg.cc/0NRkwddH/image.png", + "https://i.postimg.cc/436Jb7W4/image.png", + "https://i.postimg.cc/sX33njLY/image.png" + ] + }, + "wing-pro": { + "icon": "https://i.postimg.cc/1X55zmcm/wing.png", + "images": [ + "https://i.postimg.cc/Kjzx29x4/image.png", + "https://i.postimg.cc/0NRkwddH/image.png", + "https://i.postimg.cc/436Jb7W4/image.png", + "https://i.postimg.cc/sX33njLY/image.png" + ] + }, + "wing-personal": { + "icon": "https://i.postimg.cc/1X55zmcm/wing.png", + "images": [ + "https://i.postimg.cc/Kjzx29x4/image.png", + "https://i.postimg.cc/0NRkwddH/image.png", + "https://i.postimg.cc/436Jb7W4/image.png", + "https://i.postimg.cc/sX33njLY/image.png" + ] + }, + "winget": { + "icon": "https://i.postimg.cc/bJfdcw0g/winget-cli.png", + "images": [] + }, + "winget-ps": { + "icon": "", + "images": [] + }, + "wingetcreate": { + "icon": "", + "images": [ + "https://i.postimg.cc/g0n2QSQR/image.png" + ] + }, + "wingetui": { + "icon": "https://raw.githubusercontent.com/Devolutions/UniGetUI/main/media/icon.png", + "images": [ + "https://raw.githubusercontent.com/Devolutions/UniGetUI/main/media/UniGetUI_1.png", + "https://raw.githubusercontent.com/Devolutions/UniGetUI/main/media/UniGetUI_2.png", + "https://raw.githubusercontent.com/Devolutions/UniGetUI/main/media/UniGetUI_3.png", + "https://raw.githubusercontent.com/Devolutions/UniGetUI/main/media/UniGetUI_4.png", + "https://raw.githubusercontent.com/Devolutions/UniGetUI/main/media/UniGetUI_5.png", + "https://raw.githubusercontent.com/Devolutions/UniGetUI/main/media/UniGetUI_6.png", + "https://raw.githubusercontent.com/Devolutions/UniGetUI/main/media/UniGetUI_7.png", + "https://raw.githubusercontent.com/Devolutions/UniGetUI/main/media/UniGetUI_8.png", + "https://raw.githubusercontent.com/Devolutions/UniGetUI/main/media/UniGetUI_9.png", + "https://raw.githubusercontent.com/Devolutions/UniGetUI/main/media/UniGetUI_10.png" + ] + }, + "wingetuistore": { + "icon": "https://raw.githubusercontent.com/Devolutions/UniGetUI/main/media/icon.png", + "images": [ + "https://raw.githubusercontent.com/Devolutions/UniGetUI/main/media/UniGetUI_1.png", + "https://raw.githubusercontent.com/Devolutions/UniGetUI/main/media/UniGetUI_2.png", + "https://raw.githubusercontent.com/Devolutions/UniGetUI/main/media/UniGetUI_3.png", + "https://raw.githubusercontent.com/Devolutions/UniGetUI/main/media/UniGetUI_4.png", + "https://raw.githubusercontent.com/Devolutions/UniGetUI/main/media/UniGetUI_5.png", + "https://raw.githubusercontent.com/Devolutions/UniGetUI/main/media/UniGetUI_6.png", + "https://raw.githubusercontent.com/Devolutions/UniGetUI/main/media/UniGetUI_7.png", + "https://raw.githubusercontent.com/Devolutions/UniGetUI/main/media/UniGetUI_8.png", + "https://raw.githubusercontent.com/Devolutions/UniGetUI/main/media/UniGetUI_9.png", + "https://raw.githubusercontent.com/Devolutions/UniGetUI/main/media/UniGetUI_10.png" + ] + }, + "winginx": { + "icon": "https://community.chocolatey.org/content/packageimages/winginx.0.6.2.png", + "images": [] + }, + "wingrub": { + "icon": "", + "images": [] + }, + "wings3d": { + "icon": "https://community.chocolatey.org/content/packageimages/wings3d.2.2.6.1.png", + "images": [ + "https://i.postimg.cc/nVv7xtcs/image.png", + "https://i.postimg.cc/bvDDF7Bw/image.png", + "https://i.postimg.cc/rpB06fBC/image.png", + "https://i.postimg.cc/4yZYymNY/image.png" + ] + }, + "winhotkey": { + "icon": "https://community.chocolatey.org/content/packageimages/winhotkey.0.70.0.1.png", + "images": [] + }, + "winhttpcertcfg": { + "icon": "", + "images": [] + }, + "winhue": { + "icon": "https://community.chocolatey.org/content/packageimages/winhue.3.0.3028.0.png", + "images": [] + }, + "winja": { + "icon": "https://community.chocolatey.org/content/packageimages/winja.install.7.1.0.20201205.png", + "images": [] + }, + "wink": { + "icon": "", + "images": [] + }, + "winlame": { + "icon": "", + "images": [] + }, + "winlibs": { + "icon": "", + "images": [] + }, + "winlibs-llvm-free": { + "icon": "", + "images": [] + }, + "winlister": { + "icon": "https://community.chocolatey.org/content/packageimages/winlister.1.22.png", + "images": [] + }, + "winlockless": { + "icon": "https://community.chocolatey.org/content/packageimages/winlockless.0.3.20141129.png", + "images": [] + }, + "winlog32": { + "icon": "https://community.chocolatey.org/content/packageimages/winlog32.7.3.46.png", + "images": [] + }, + "winlogbeat": { + "icon": "https://i.imgur.com/gaZ7moS.png", + "images": [ + "https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt6c4cbb4f3ca4258c/5ca67d82154fe31d3366f9f6/logging-winlogbeat-windows.jpg", + "https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltf5db944ddd48764f/5bbcae7b0e6edaf014d23be8/winlogbeat-account-usage-dashboard.jpg", + "https://www.tutorials24x7.com/uploads/2020-01-04/files/12-tutorials24x7-winlogbeat-kibana-dashboard.png" + ] + }, + "winlogbeat-oss": { + "icon": "https://community.chocolatey.org/content/packageimages/winlogbeat-oss.8.4.1.png", + "images": [] + }, + "winlogonview": { + "icon": "https://community.chocolatey.org/content/packageimages/winlogonview.1.32.png", + "images": [] + }, + "winmerge": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/7/79/WinMergeLogo.png", + "images": [ + "https://winmerge.org/screenshots/filecmp.png" + ] + }, + "winmerge-7z": { + "icon": "", + "images": [] + }, + "winmerge-beta": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/7/79/WinMergeLogo.png", + "images": [ + "https://winmerge.org/screenshots/filecmp.png" + ] + }, + "winmerge-jp": { + "icon": "https://community.chocolatey.org/content/packageimages/winmerge-jp.2.14.0.77.png", + "images": [] + }, + "winmerge2011": { + "icon": "https://community.chocolatey.org/content/packageimages/winmerge2011.portable.0.2011.007.44401.png", + "images": [] + }, + "winmoji": { + "icon": "", + "images": [] + }, + "winmtr": { + "icon": "", + "images": [] + }, + "winmtr-live": { + "icon": "", + "images": [] + }, + "winmtr-redux": { + "icon": "https://community.chocolatey.org/content/packageimages/winmtr-redux.1.00.png", + "images": [] + }, + "winmute": { + "icon": "https://community.chocolatey.org/content/packageimages/winmute.2.2.0.20221128.png", + "images": [] + }, + "winnfsd": { + "icon": "", + "images": [] + }, + "winobj": { + "icon": "https://community.chocolatey.org/content/packageimages/winobj.3.14.png", + "images": [] + }, + "winobjc-tools": { + "icon": "https://community.chocolatey.org/content/packageimages/winobjc-tools.0.2.180220.png", + "images": [] + }, + "winobjex64": { + "icon": "", + "images": [] + }, + "winpatrol": { + "icon": "https://community.chocolatey.org/content/packageimages/winpatrol.35.5.2017.800.png", + "images": [] + }, + "winpinator": { + "icon": "", + "images": [] + }, + "winpower": { + "icon": "", + "images": [] + }, + "winprefetchview": { + "icon": "https://community.chocolatey.org/content/packageimages/winprefetchview.1.35.png", + "images": [] + }, + "winpty": { + "icon": "", + "images": [] + }, + "winpython": { + "icon": "", + "images": [] + }, + "winpython-dot": { + "icon": "", + "images": [] + }, + "winpython-dot-pypy": { + "icon": "", + "images": [] + }, + "winpython-pypy": { + "icon": "", + "images": [] + }, + "winquicklook": { + "icon": "https://community.chocolatey.org/content/packageimages/winquicklook.1.1.31.png", + "images": [] + }, + "winrar": { + "icon": "https://i.postimg.cc/mrqHDZxJ/winrar.png", + "images": [ + "https://i.postimg.cc/Dfsbkzxv/image.png", + "https://i.postimg.cc/PJrG4JxW/image.png", + "https://i.postimg.cc/hjQMqq5k/image.png", + "https://i.postimg.cc/7ZL3kkCK/image.png" + ] + }, + "winrar-helper": { + "icon": "", + "images": [] + }, + "winscan2pdf": { + "icon": "https://i.postimg.cc/B6KyyTvR/Win-Scan2-PDF.png", + "images": [ + "https://i.postimg.cc/PJnckCpJ/Win-Scan2-PDF-1.png" + ] + }, + "winscp": { + "icon": "https://i.postimg.cc/3xtGsCtK/icon.png", + "images": [ + "https://i.postimg.cc/j2yNmpF9/1.png", + "https://i.postimg.cc/ncYBkt79/2.png", + "https://i.postimg.cc/7Pzg5zZV/3.png", + "https://i.postimg.cc/zX1TKfL1/4.png", + "https://i.postimg.cc/y819prXQ/5.png" + ] + }, + "winscp-rc": { + "icon": "", + "images": [] + }, + "winscreenfetch": { + "icon": "https://community.chocolatey.org/content/packageimages/WinScreenfetch.0.5.1.png", + "images": [] + }, + "winscript": { + "icon": "https://i.ibb.co/5WvDZdDb/winscript-upscayl-4x-upscayl-standard-4x.png", + "images": [ + "https://i.ibb.co/PvhGcy8S/image.png" + ] + }, + "winsecuritybaseline": { + "icon": "https://community.chocolatey.org/content/packageimages/WinSecurityBaseline.19.03.02.png", + "images": [] + }, + "winsetupfromusb": { + "icon": "", + "images": [] + }, + "winsize2": { + "icon": "https://community.chocolatey.org/content/packageimages/winsize2.2.38.04.png", + "images": [] + }, + "winsockservicesview": { + "icon": "https://community.chocolatey.org/content/packageimages/winsockservicesview.1.00.png", + "images": [] + }, + "winspector": { + "icon": "https://community.chocolatey.org/content/packageimages/winspector.1.0.37.png", + "images": [] + }, + "winspy": { + "icon": "https://community.chocolatey.org/content/packageimages/winspy.1.7.202103022.png", + "images": [] + }, + "winssh-pageant": { + "icon": "", + "images": [] + }, + "winsshd": { + "icon": "", + "images": [] + }, + "winsshterm": { + "icon": "https://community.chocolatey.org/content/packageimages/winsshterm.2.24.0.png", + "images": [] + }, + "winsw": { + "icon": "", + "images": [] + }, + "wintail": { + "icon": "", + "images": [] + }, + "winthruster": { + "icon": "", + "images": [] + }, + "winthumbspreloader": { + "icon": "https://community.chocolatey.org/content/packageimages/WinThumbsPreloader.1.0.1.png", + "images": [] + }, + "wintpic": { + "icon": "", + "images": [] + }, + "winvdig": { + "icon": "", + "images": [] + }, + "winvice": { + "icon": "https://community.chocolatey.org/content/packageimages/winvice.3.1.png", + "images": [] + }, + "winvice-nightly": { + "icon": "https://community.chocolatey.org/content/packageimages/winvice-nightly.3.6.1.png", + "images": [] + }, + "winxcorners": { + "icon": "https://community.chocolatey.org/content/packageimages/winxcorners.1.1.0.320190708.png", + "images": [] + }, + "winyl": { + "icon": "", + "images": [] + }, + "winzip": { + "icon": "https://i.postimg.cc/hGB7GRhF/WinZip.png", + "images": [ + "https://i.postimg.cc/ZnCWQTsN/image.png", + "https://i.postimg.cc/fbVTZHf4/image.png" + ] + }, + "wire": { + "icon": "https://community.chocolatey.org/content/packageimages/wire.3.30.4368.png", + "images": [] + }, + "wireedit": { + "icon": "https://community.chocolatey.org/content/packageimages/wireedit.3.10.357.png", + "images": [] + }, + "wireframes": { + "icon": "", + "images": [] + }, + "wireframesketcher": { + "icon": "https://community.chocolatey.org/content/packageimages/wireframesketcher.6.6.0.png", + "images": [] + }, + "wireguard": { + "icon": "https://community.chocolatey.org/content/packageimages/wireguard.0.5.3.png", + "images": [ + "https://i.postimg.cc/wvRXQFBR/wire1.png" + ] + }, + "wirelessconnectioninfo": { + "icon": "https://community.chocolatey.org/content/packageimages/wirelessconnectioninfo.1.12.png", + "images": [] + }, + "wirelessnetconsole": { + "icon": "https://community.chocolatey.org/content/packageimages/wirelessnetconsole.1.00.png", + "images": [] + }, + "wirelessnetview": { + "icon": "https://community.chocolatey.org/content/packageimages/wirelessnetview.portable.1.75.0.20181224.png", + "images": [] + }, + "wirelessnetworkwatcher": { + "icon": "https://i.postimg.cc/44SRVgdp/image.png", + "images": [ + "https://i.postimg.cc/L8jccgVg/image.png" + ] + }, + "wirelessworkbench": { + "icon": "", + "images": [] + }, + "wireproxy": { + "icon": "", + "images": [] + }, + "wireshark": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/d/df/Wireshark_icon.svg/1200px-Wireshark_icon.svg.png", + "images": [ + "https://www.wireshark.org/docs/wsug_html_chunked/images/ws-main.png" + ] + }, + "wiseadcleaner": { + "icon": "https://i.postimg.cc/qRvrKxcG/adclr.png", + "images": [ + "https://i.postimg.cc/8cqgq82y/image.png", + "https://i.postimg.cc/HWKmJ5rQ/image.png" + ] + }, + "wisecare365": { + "icon": "https://i.postimg.cc/wjpdV2xp/wc.png", + "images": [ + "https://i.postimg.cc/brVsnMfp/image.png", + "https://i.postimg.cc/kXhbRV7K/image.png", + "https://i.postimg.cc/qMgtrk2R/image.png", + "https://i.postimg.cc/VN9vg5P7/image.png", + "https://i.postimg.cc/FR9RBm9h/image.png", + "https://i.postimg.cc/Wzy1zk04/image.png" + ] + }, + "wisedatarecovery": { + "icon": "https://i.postimg.cc/rFMW2CzV/wdr.png", + "images": [ + "https://i.postimg.cc/tCz6qrMS/image.png" + ] + }, + "wisediskcleaner": { + "icon": "https://i.postimg.cc/hG7TBVQp/dskclr.png", + "images": [ + "https://i.postimg.cc/d12C7vBC/image.png", + "https://i.postimg.cc/5yfCLG7R/image.png", + "https://i.postimg.cc/T1QW99BY/image.png", + "https://i.postimg.cc/2y3Cs7V5/image.png" + ] + }, + "wiseduplicatefinder": { + "icon": "https://i.postimg.cc/pXZBGQKj/filedup.png", + "images": [ + "https://i.postimg.cc/PJbMkYcB/image.png", + "https://i.postimg.cc/J4mq5YHm/image.png" + ] + }, + "wisefolderhider": { + "icon": "https://i.postimg.cc/bvJRbXtF/wff.png", + "images": [ + "https://i.postimg.cc/P5dyXvrH/image.png" + ] + }, + "wisegamebooster": { + "icon": "https://i.postimg.cc/DfDPXYvx/gbuster.png", + "images": [ + "https://i.postimg.cc/0yGYhkp4/image.png", + "https://i.postimg.cc/QMXQ32md/image.png", + "https://i.postimg.cc/hGp9P2Zb/image.png", + "https://i.postimg.cc/vBT515pR/image.png" + ] + }, + "wisehotkey": { + "icon": "https://i.postimg.cc/pTsk4Wtv/hotkey.png", + "images": [ + "https://i.postimg.cc/nhmRrfqK/image.png" + ] + }, + "wisememoryoptimizer": { + "icon": "https://i.postimg.cc/jdSYD2jH/memo.png", + "images": [ + "https://i.postimg.cc/dVZXCycy/image.png", + "https://i.postimg.cc/hvGZtJ0h/image.png", + "https://i.postimg.cc/JzywQFZt/image.png" + ] + }, + "wisevideoconverter": { + "icon": "https://i.postimg.cc/m2qKXwbD/wvc.png", + "images": [ + "https://i.postimg.cc/76sKCHh6/image.png", + "https://i.postimg.cc/vTCXz0Ww/image.png" + ] + }, + "wiseimagex": { + "icon": "https://i.postimg.cc/HkvnPFrM/ix.png", + "images": [ + "https://i.postimg.cc/bY0JjZGp/image.png", + "https://i.postimg.cc/SNDxJH7P/image.png", + "https://i.postimg.cc/FHzscGTH/image.png", + "https://i.postimg.cc/FRy9m6HD/image.png" + ] + }, + "wisenote": { + "icon": "https://i.postimg.cc/MZYWFg4G/wnote.png", + "images": [ + "https://i.postimg.cc/4y4TGNMx/image.png", + "https://i.postimg.cc/d08MTyc0/image.png" + ] + }, + "wisex": { + "icon": "https://i.postimg.cc/50C3nZm9/wisex.png", + "images": [ + "https://i.postimg.cc/DwnMmyPr/image.png", + "https://i.postimg.cc/ZRBfX9JS/image.png", + "https://i.postimg.cc/7YyBQYcF/image.png", + "https://i.postimg.cc/K8G0xpmQ/image.png" + ] + }, + "wisemo": { + "icon": "https://community.chocolatey.org/content/packageimages/wisemo.3.51.png", + "images": [] + }, + "wiseprogramuninstaller": { + "icon": "https://i.postimg.cc/Jn61Yk6Q/wpu.png", + "images": [ + "https://i.postimg.cc/CxkxMd5F/image.png" + ] + }, + "wiser": { + "icon": "", + "images": [] + }, + "wiseregistrycleaner": { + "icon": "https://i.postimg.cc/bN72RsBn/wisereg.png", + "images": [ + "https://i.postimg.cc/Y2yFhXNb/image.png", + "https://i.postimg.cc/gJgZysCc/image.png", + "https://i.postimg.cc/pryns8vf/image.png", + "https://i.postimg.cc/J0gHvn79/image.png" + ] + }, + "wisetoys": { + "icon": "https://www.wisecleaner.com/static/img/product/products_icon/wisetoys-100.png", + "images": [ + "https://toys.wisecleaner.com/help/assets/wisetoys-main-search.png" + ] + }, + "wit": { + "icon": "https://community.chocolatey.org/content/packageimages/wit.3.04.8427.png", + "images": [] + }, + "wix35": { + "icon": "", + "images": [] + }, + "wixedit": { + "icon": "https://community.chocolatey.org/content/packageimages/wixedit.0.7.5.png", + "images": [] + }, + "wixtoolset": { + "icon": "https://i.postimg.cc/KcVKZ1FW/image.png", + "images": [ + "https://raw.githubusercontent.com/wixtoolset/.github/master/profile/images/readme-header.png" + ] + }, + "wizemo": { + "icon": "", + "images": [] + }, + "wizfile": { + "icon": "https://antibodysoftware-17031.kxcdn.com/wizfile/images/wizfile445x.png", + "images": [] + }, + "wizkey": { + "icon": "", + "images": [] + }, + "wizmouse": { + "icon": "https://i.postimg.cc/J4BKRzYN/3453520687.png", + "images": [] + }, + "wiznote": { + "icon": "", + "images": [] + }, + "wiznotelite": { + "icon": "", + "images": [] + }, + "wiztools-rest-client-ui": { + "icon": "https://community.chocolatey.org/content/packageimages/wiztools-rest-client-ui.3.7.1.png", + "images": [] + }, + "wiztree": { + "icon": "https://antibodysoftware-17031.kxcdn.com/images/wiztree445x.png", + "images": [ + "https://i.imgur.com/Sf1hKhj.png" + ] + }, + "wkhtmltopdf": { + "icon": "", + "images": [] + }, + "wkhtmltox": { + "icon": "", + "images": [] + }, + "wmiexplorer": { + "icon": "", + "images": [] + }, + "wmiexporter": { + "icon": "", + "images": [] + }, + "wmisecurity": { + "icon": "", + "images": [] + }, + "wms": { + "icon": "https://community.chocolatey.org/content/packageimages/wms.11.1.4.png", + "images": [] + }, + "wnetwatcher": { + "icon": "https://community.chocolatey.org/content/packageimages/wnetwatcher.2.30.png", + "images": [] + }, + "wnr": { + "icon": "", + "images": [] + }, + "wol": { + "icon": "", + "images": [] + }, + "wolai": { + "icon": "", + "images": [] + }, + "wolframengine": { + "icon": "", + "images": [] + }, + "wolvenkit-nightly": { + "icon": "", + "images": [] + }, + "wonderpen": { + "icon": "", + "images": [] + }, + "wonton": { + "icon": "https://community.chocolatey.org/content/packageimages/wonton.1.1.1.png", + "images": [] + }, + "word-viewer": { + "icon": "https://community.chocolatey.org/content/packageimages/Word.Viewer.12.0.6219.1000.png", + "images": [] + }, + "wordcontentcontroltoolkit": { + "icon": "https://community.chocolatey.org/content/packageimages/wordcontentcontroltoolkit.1.3.png", + "images": [] + }, + "wordmark": { + "icon": "", + "images": [] + }, + "wordpress": { + "icon": "https://tweakers.net/ext/i/2004779290.png", + "images": [ + "https://tweakers.net/ext/i/2002139227.png" + ] + }, + "wordviewer": { + "icon": "", + "images": [] + }, + "wordweb-free": { + "icon": "", + "images": [] + }, + "workcad": { + "icon": "", + "images": [] + }, + "workflowy": { + "icon": "", + "images": [] + }, + "workman": { + "icon": "", + "images": [] + }, + "workoffice": { + "icon": "", + "images": [] + }, + "workrave": { + "icon": "https://community.chocolatey.org/content/packageimages/workrave.1.10.50.png", + "images": [] + }, + "workspace": { + "icon": "", + "images": [] + }, + "workspace-agent": { + "icon": "", + "images": [] + }, + "workspacer": { + "icon": "https://community.chocolatey.org/content/packageimages/workspacer.install.0.9.11.png", + "images": [] + }, + "workspacer-beta": { + "icon": "", + "images": [] + }, + "workspacesclient": { + "icon": "https://i.imgur.com/1xJawrC.png", + "images": [ + "https://images-na.ssl-images-amazon.com/images/I/41AdvBLniPL.png", + "https://www.sufle.io/img/blog/amazon-workspaces.jpg", + "https://docs.aws.amazon.com/workspaces/latest/adminguide/images/architectural-diagram-new-2.png", + "https://research-it.wharton.upenn.edu/wp-content/uploads/2020/05/WorkSpaces_Login.png" + ] + }, + "workspaceutilities": { + "icon": "", + "images": [] + }, + "workstation": { + "icon": "", + "images": [] + }, + "workstationplayer": { + "icon": "https://community.chocolatey.org/content/packageimages/vmware-workstation-player.17.0.1.21139696.png", + "images": [ + "https://i.postimg.cc/BZTLQ4J2/Captura-de-pantalla-28.png" + ] + }, + "workstationpro": { + "icon": "https://community.chocolatey.org/content/packageimages/vmwareworkstation.17.0.1.21139696.png", + "images": [] + }, + "worldofwarshipsmodstation": { + "icon": "", + "images": [] + }, + "worldolio": { + "icon": "", + "images": [] + }, + "worldwide-telescope": { + "icon": "https://community.chocolatey.org/content/packageimages/worldwide-telescope.5.5.0.3.png", + "images": [] + }, + "worldwidetelescope": { + "icon": "https://i.imgur.com/b8UUC9y.png", + "images": [ + "https://windows-cdn.softpedia.com/screenshots/WorldWide-Telescope_17.png", + "https://windows-cdn.softpedia.com/screenshots/WorldWide-Telescope_18.png", + "https://www.thewindowsclub.com/wp-content/uploads/2015/08/WorldWide-Telescope.jpg" + ] + }, + "wormhole-william": { + "icon": "", + "images": [] + }, + "wormies-au-helpers": { + "icon": "", + "images": [] + }, + "wot": { + "icon": "", + "images": [] + }, + "wot-chrome": { + "icon": "", + "images": [] + }, + "wow-stat": { + "icon": "https://community.chocolatey.org/content/packageimages/wow-stat.3.0.5.png", + "images": [] + }, + "wowup": { + "icon": "", + "images": [] + }, + "wox": { + "icon": "https://community.chocolatey.org/content/packageimages/wox.1.3.524.20180714.png", + "images": [] + }, + "wp-cli": { + "icon": "", + "images": [] + }, + "wpd": { + "icon": "https://community.chocolatey.org/content/packageimages/wpd.1.5.2042.png", + "images": [] + }, + "wpfinspector": { + "icon": "", + "images": [] + }, + "wps-office-free": { + "icon": "https://community.chocolatey.org/content/packageimages/wps-office-free.11.2.0.10223.png", + "images": [] + }, + "wpsoffice": { + "icon": "", + "images": [] + }, + "wpsoffice-cn": { + "icon": "", + "images": [] + }, + "wput": { + "icon": "", + "images": [] + }, + "wrangler": { + "icon": "", + "images": [] + }, + "writage": { + "icon": "https://community.chocolatey.org/content/packageimages/writage.2.10.png", + "images": [] + }, + "write": { + "icon": "", + "images": [] + }, + "wsa-pacman": { + "icon": "", + "images": [] + }, + "wsasideloader": { + "icon": "https://i.imgur.com/pVsN9qp.png", + "images": [ + "https://user-images.githubusercontent.com/44692189/246669862-ede49229-4667-47b1-ac2d-84f2d71b954f.png" + ] + }, + "wsasystemcontrol": { + "icon": "https://i.imgur.com/lwsJObd.png", + "images": [ + "https://user-images.githubusercontent.com/44692189/247650724-304fdbd8-ffd7-4127-96d2-23adf672724c.png" + ] + }, + "wsatools": { + "icon": "", + "images": [] + }, + "wsgidav": { + "icon": "", + "images": [] + }, + "wsjtx": { + "icon": "https://community.chocolatey.org/content/packageimages/wsjtx.2.5.4.png", + "images": [] + }, + "wsl": { + "icon": "https://i.postimg.cc/c4TB1sTf/wsl-icon.png", + "images": [] + }, + "wsl-alpine": { + "icon": "", + "images": [] + }, + "wsl-archlinux": { + "icon": "https://community.chocolatey.org/content/packageimages/wsl-archlinux.1.0.3.0.png", + "images": [] + }, + "wsl-debiangnulinux": { + "icon": "https://community.chocolatey.org/content/packageimages/wsl-debiangnulinux.9.0.0.020180923.png", + "images": [] + }, + "wsl-distrod": { + "icon": "", + "images": [] + }, + "wsl-fedoraremix": { + "icon": "", + "images": [] + }, + "wsl-kalilinux": { + "icon": "", + "images": [] + }, + "wsl-manjaro": { + "icon": "", + "images": [] + }, + "wsl-opensuse": { + "icon": "https://community.chocolatey.org/content/packageimages/wsl-opensuse.42.2.0.020181002.png", + "images": [] + }, + "wsl-ssh-agent": { + "icon": "", + "images": [] + }, + "wsl-ssh-pageant": { + "icon": "", + "images": [] + }, + "wsl-ssh-pageant-gui": { + "icon": "https://community.chocolatey.org/content/packageimages/wsl-ssh-pageant-gui.20201121.2.png", + "images": [] + }, + "wsl-terminal": { + "icon": "", + "images": [] + }, + "wsl-ubuntu-1604": { + "icon": "https://community.chocolatey.org/content/packageimages/wsl-ubuntu-1604.16.04.3.020181002.png", + "images": [] + }, + "wsl-ubuntu-1804": { + "icon": "https://community.chocolatey.org/content/packageimages/wsl-ubuntu-1804.18.04.1.020181923.png", + "images": [] + }, + "wsl-ubuntu-2004": { + "icon": "https://community.chocolatey.org/content/packageimages/wsl-ubuntu-2004.20.4.0.20220127.png", + "images": [] + }, + "wsl-ubuntu-2204": { + "icon": "https://community.chocolatey.org/content/packageimages/wsl-ubuntu-2204.22.4.0.20220819.png", + "images": [] + }, + "wsl2": { + "icon": "https://community.chocolatey.org/content/packageimages/wsl2.2.0.0.20210721.png", + "images": [] + }, + "wsl2-distro-manager": { + "icon": "", + "images": [] + }, + "wsldiskshrinker": { + "icon": "", + "images": [] + }, + "wslgit": { + "icon": "", + "images": [] + }, + "wslmanager": { + "icon": "", + "images": [] + }, + "wsltoolbox": { + "icon": "", + "images": [] + }, + "wsltty": { + "icon": "https://community.chocolatey.org/content/packageimages/wsltty.3.6.1.2.png", + "images": [] + }, + "wstunnel": { + "icon": "", + "images": [] + }, + "wsus-offline-update": { + "icon": "https://community.chocolatey.org/content/packageimages/wsus-offline-update.12.0.png", + "images": [] + }, + "wsus-offline-update-community": { + "icon": "https://community.chocolatey.org/content/packageimages/wsus-offline-update-community.12.6.1.png", + "images": [] + }, + "wszst": { + "icon": "https://community.chocolatey.org/content/packageimages/wszst.1.58.7503.png", + "images": [] + }, + "wtfast": { + "icon": "", + "images": [] + }, + "wtile": { + "icon": "", + "images": [] + }, + "wtils": { + "icon": "", + "images": [] + }, + "wttop": { + "icon": "", + "images": [] + }, + "wtw": { + "icon": "https://community.chocolatey.org/content/packageimages/wtw.1.2.0.4424.png", + "images": [] + }, + "wu10man": { + "icon": "", + "images": [] + }, + "wubi": { + "icon": "https://community.chocolatey.org/content/packageimages/wubi.12.04.20120921.png", + "images": [] + }, + "wudt": { + "icon": "https://community.chocolatey.org/content/packageimages/wudt.1.0.30.20180515.png", + "images": [] + }, + "wuinstall-run": { + "icon": "", + "images": [] + }, + "wul": { + "icon": "https://community.chocolatey.org/content/packageimages/wul.portable.1.32.png", + "images": [] + }, + "wumgr": { + "icon": "", + "images": [] + }, + "wumt": { + "icon": "https://community.chocolatey.org/content/packageimages/wumt.2016.12.20.png", + "images": [] + }, + "wunderlist": { + "icon": "", + "images": [] + }, + "wurl": { + "icon": "", + "images": [] + }, + "wuzz": { + "icon": "", + "images": [] + }, + "wvd-agent": { + "icon": "", + "images": [] + }, + "wvd-boot-loader": { + "icon": "", + "images": [] + }, + "wwphone": { + "icon": "https://community.chocolatey.org/content/packageimages/wwphone.4.0.26.png", + "images": [] + }, + "wwphone-cti": { + "icon": "https://community.chocolatey.org/content/packageimages/wwphone-cti.4.0.26.png", + "images": [] + }, + "wxdfast": { + "icon": "", + "images": [] + }, + "wxhexeditor": { + "icon": "", + "images": [] + }, + "wxmacmolplt": { + "icon": "https://community.chocolatey.org/content/packageimages/wxmacmolplt.7.7.png", + "images": [] + }, + "wxmp3gain": { + "icon": "https://community.chocolatey.org/content/packageimages/wxmp3gain.4.0.0.20190427.png", + "images": [] + }, + "wxmun": { + "icon": "", + "images": [] + }, + "wxpython": { + "icon": "", + "images": [] + }, + "wxrecovery": { + "icon": "", + "images": [] + }, + "wxtcmd": { + "icon": "", + "images": [] + }, + "wxwidgets": { + "icon": "https://community.chocolatey.org/content/packageimages/wxwidgets.3.1.2.png", + "images": [] + }, + "wyam": { + "icon": "https://community.chocolatey.org/content/packageimages/wyam.2.2.9.png", + "images": [] + }, + "wyam2": { + "icon": "https://community.chocolatey.org/content/packageimages/wyam2.3.0.0.png", + "images": [] + }, + "x-air-edit": { + "icon": "https://community.chocolatey.org/content/packageimages/x-air-edit.1.7.1.0.png", + "images": [] + }, + "x-lite": { + "icon": "", + "images": [] + }, + "x-moto": { + "icon": "https://community.chocolatey.org/content/packageimages/x-moto.0.5.11.20170430.png", + "images": [] + }, + "x-mousebuttoncontrol": { + "icon": "https://i.postimg.cc/q7GZk7Y4/xmousebuttoncontrol.png", + "images": [ + "https://i.postimg.cc/tJcMLmc6/xmouse1.png", + "https://i.postimg.cc/hPHYs6TW/xmouse2.png", + "https://i.postimg.cc/CLZtjSZs/xmouse3.png", + "https://i.postimg.cc/9QZnnbY4/xmouse4.png", + "https://i.postimg.cc/7L4W8zKK/xmouse5.png" + ] + }, + "x-vpn": { + "icon": "https://img.icons8.com/color/512/x-vpn.png", + "images": [] + }, + "x264": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/6/6f/X264.png", + "images": [] + }, + "x264vfw": { + "icon": "https://community.chocolatey.org/content/packageimages/x264vfw.2017.07.30.png", + "images": [] + }, + "x265": { + "icon": "https://en.wikipedia.org/wiki/X265#/media/File:X265_HEVC_Encoder_Logo.png", + "images": [] + }, + "x2go": { + "icon": "https://community.chocolatey.org/content/packageimages/x2go.4.1.2.2.png", + "images": [] + }, + "x2goclient": { + "icon": "", + "images": [] + }, + "x32-edit": { + "icon": "https://community.chocolatey.org/content/packageimages/x32-edit.4.3.png", + "images": [] + }, + "x64dbg": { + "icon": "https://community.chocolatey.org/content/packageimages/x64dbg.portable.20230115.1529.png", + "images": [] + }, + "xairedit": { + "icon": "", + "images": [] + }, + "xamarin-interactive-aka-workbooks-inspector": { + "icon": "https://community.chocolatey.org/content/packageimages/xamarin-interactive-aka-workbooks-inspector.1.0.0.0.png", + "images": [] + }, + "xamarin-ios-simulator": { + "icon": "https://community.chocolatey.org/content/packageimages/xamarin-ios-simulator.0.10.1.1.png", + "images": [] + }, + "xamarin-profiler": { + "icon": "https://community.chocolatey.org/content/packageimages/xamarin-profiler.0.38.0.png", + "images": [] + }, + "xamarin-studio": { + "icon": "https://community.chocolatey.org/content/packageimages/xamarin-studio.5.5.2.2014102200.png", + "images": [] + }, + "xamarin-visualstudio": { + "icon": "https://community.chocolatey.org/content/packageimages/xamarin-visualstudio.4.0.3.214.png", + "images": [] + }, + "xampp": { + "icon": "https://i.postimg.cc/zfGvzr9f/xampp.png", + "images": [] + }, + "xampp-7-4": { + "icon": "https://assets.stickpng.com/images/58482973cef1014c0b5e49fd.png", + "images": [] + }, + "xampp-72": { + "icon": "", + "images": [] + }, + "xampp-73": { + "icon": "", + "images": [] + }, + "xampp-74": { + "icon": "", + "images": [] + }, + "xampp-8-0": { + "icon": "https://assets.stickpng.com/images/58482973cef1014c0b5e49fd.png", + "images": [] + }, + "xampp-8-1": { + "icon": "https://assets.stickpng.com/images/58482973cef1014c0b5e49fd.png", + "images": [] + }, + "xampp-8-2": { + "icon": "https://assets.stickpng.com/images/58482973cef1014c0b5e49fd.png", + "images": [] + }, + "xampp-80": { + "icon": "", + "images": [] + }, + "xampp-81": { + "icon": "", + "images": [] + }, + "xampp-app": { + "icon": "", + "images": [] + }, + "xampp-tool": { + "icon": "", + "images": [] + }, + "xb1cbi": { + "icon": "", + "images": [] + }, + "xbar": { + "icon": "", + "images": [] + }, + "xbian-installer": { + "icon": "https://community.chocolatey.org/content/packageimages/xbian-installer.1.4.png", + "images": [] + }, + "xbmc": { + "icon": "", + "images": [] + }, + "xboot": { + "icon": "", + "images": [] + }, + "xca": { + "icon": "https://community.chocolatey.org/content/packageimages/xca.2.4.0.png", + "images": [] + }, + "xcas": { + "icon": "", + "images": [] + }, + "xcmd": { + "icon": "https://community.chocolatey.org/content/packageimages/xCmd.1.12.0.png", + "images": [] + }, + "xdelta": { + "icon": "", + "images": [] + }, + "xdelta3-cross-gui": { + "icon": "", + "images": [] + }, + "xdman": { + "icon": "", + "images": [] + }, + "xdoc2txt": { + "icon": "", + "images": [] + }, + "xencenter": { + "icon": "https://community.chocolatey.org/content/packageimages/xencenter.7.2.0.png", + "images": [] + }, + "xenko": { + "icon": "", + "images": [] + }, + "xenserver-backup": { + "icon": "https://community.chocolatey.org/content/packageimages/xenserver-backup.2.0.1.5.png", + "images": [] + }, + "xenu": { + "icon": "", + "images": [] + }, + "xeroxupd": { + "icon": "https://community.chocolatey.org/content/packageimages/xeroxupd.5.887.3.0.png", + "images": [] + }, + "xh": { + "icon": "", + "images": [] + }, + "xhyper-v": { + "icon": "", + "images": [] + }, + "xiaoetong": { + "icon": "", + "images": [] + }, + "xiaomicloud": { + "icon": "", + "images": [] + }, + "xiboplayer": { + "icon": "", + "images": [] + }, + "xidel": { + "icon": "", + "images": [] + }, + "xiguavideo": { + "icon": "", + "images": [] + }, + "ximalaya": { + "icon": "", + "images": [] + }, + "ximalayalive": { + "icon": "", + "images": [] + }, + "ximple": { + "icon": "https://community.chocolatey.org/content/packageimages/ximple.1.6.2302.11085.png", + "images": [] + }, + "xivlauncher": { + "icon": "", + "images": [] + }, + "xjoy": { + "icon": "", + "images": [] + }, + "xkill": { + "icon": "", + "images": [] + }, + "xmake": { + "icon": "https://raw.githubusercontent.com/xmake-io/xmake-docs/master/docs/public/assets/img/xmake-logo-large.png", + "images": [ + "https://xmake.io/assets/img/index/package_manage.png" + ] + }, + "xmedia-recode": { + "icon": "", + "images": [] + }, + "xmind": { + "icon": "https://community.chocolatey.org/content/packageimages/xmind.8.9.png", + "images": [] + }, + "xmind-2020": { + "icon": "https://community.chocolatey.org/content/packageimages/xmind-2020.12.0.3.png", + "images": [] + }, + "xmind-8": { + "icon": "", + "images": [] + }, + "xminecraftlauncher": { + "icon": "", + "images": [] + }, + "xming": { + "icon": "", + "images": [] + }, + "xml-copy-editor": { + "icon": "https://community.chocolatey.org/content/packageimages/xml-copy-editor.1.3.0.0.png", + "images": [] + }, + "xml-notepad": { + "icon": "https://community.chocolatey.org/content/packageimages/xml-notepad.2.8.0.7.png", + "images": [] + }, + "xmlconverter": { + "icon": "https://community.chocolatey.org/content/packageimages/XMLConverter.3.1.png", + "images": [] + }, + "xmlexplorer": { + "icon": "", + "images": [] + }, + "xmlformatter": { + "icon": "", + "images": [] + }, + "xmllint": { + "icon": "", + "images": [] + }, + "xmlnotepad": { + "icon": "", + "images": [] + }, + "xmlspy": { + "icon": "https://community.chocolatey.org/content/packageimages/xmlspy.2023.1.png", + "images": [] + }, + "xmlstarlet": { + "icon": "https://community.chocolatey.org/content/packageimages/xmlstarlet.portable.1.6.1.png", + "images": [] + }, + "xmoto": { + "icon": "", + "images": [] + }, + "xmp": { + "icon": "", + "images": [] + }, + "xmplay": { + "icon": "", + "images": [] + }, + "xmrig": { + "icon": "", + "images": [] + }, + "xnaredist": { + "icon": "https://community.chocolatey.org/content/packageimages/xna31.3.1.0.20160105.png", + "images": [] + }, + "xnconvert": { + "icon": "https://www.xnview.com/img/app-xnconvert-512.png", + "images": [ + "https://i.postimg.cc/W1jwJr8d/image.png", + "https://i.postimg.cc/QMdgf3Rs/image.png" + ] + }, + "xnresize": { + "icon": "https://www.xnview.com/img/app-resizeme-512.png", + "images": [ + "https://i.postimg.cc/7LzP8GvN/image.png", + "https://i.postimg.cc/Hn6d4b5T/image.png", + "https://i.postimg.cc/xdLQpwHx/image.png", + "https://i.postimg.cc/pVsHSYhH/image.png" + ] + }, + "xnshell": { + "icon": "https://www.xnview.com/img/app-xnview-512.png", + "images": [] + }, + "xnview": { + "icon": "https://www.xnview.com/img/app-xnview-512.png", + "images": [] + }, + "xnview-classic": { + "icon": "https://www.xnview.com/img/app-xnview-512.png", + "images": [ + "https://i.postimg.cc/SNLWqR4k/image.png", + "https://i.postimg.cc/rpH4gt1C/image.png", + "https://i.postimg.cc/ZqWB9KG9/image.png" + ] + }, + "xnviewmp": { + "icon": "https://www.xnview.com/img/app-xnviewmp-512.png", + "images": [ + "https://i.postimg.cc/ZnwYJxhm/xnviewmp-win-01.png", + "https://i.postimg.cc/C1qBmtD2/xnviewmp-win-02.png", + "https://i.postimg.cc/QCgBrTfk/xnviewmp-win-03.png" + ] + }, + "xolidosigndesktop": { + "icon": "https://community.chocolatey.org/content/packageimages/xolidosigndesktop.2.2.1.56.png", + "images": [] + }, + "xonotic": { + "icon": "https://community.chocolatey.org/content/packageimages/xonotic.0.8.2.png", + "images": [] + }, + "xournal++": { + "icon": "https://raw.githubusercontent.com/xournalpp/xournalpp/master/ui/pixmaps/com.github.xournalpp.xournalpp.png", + "images": [] + }, + "xournalplusplus": { + "icon": "https://raw.githubusercontent.com/xournalpp/xournalpp/master/ui/pixmaps/com.github.xournalpp.xournalpp.png", + "images": [] + }, + "xournalpp": { + "icon": "https://raw.githubusercontent.com/xournalpp/xournalpp/master/ui/pixmaps/com.github.xournalpp.xournalpp.png", + "images": [] + }, + "xpdf-tools": { + "icon": "", + "images": [] + }, + "xpdf-tools-lsp": { + "icon": "", + "images": [] + }, + "xpdf-utils": { + "icon": "https://community.chocolatey.org/content/packageimages/xpdf-utils.3.4.0.20170430.png", + "images": [] + }, + "XPFFTQ032PTPHF": { + "icon": "https://raw.githubusercontent.com/Devolutions/UniGetUI/main/media/icon.png", + "images": [ + "https://raw.githubusercontent.com/Devolutions/UniGetUI/main/media/UniGetUI_1.png", + "https://raw.githubusercontent.com/Devolutions/UniGetUI/main/media/UniGetUI_3.png", + "https://raw.githubusercontent.com/Devolutions/UniGetUI/main/media/UniGetUI_6.png" + ] + }, + "xpipe": { + "icon": "", + "images": [ + "https://raw.githubusercontent.com/xpipe-io/.github/main/img/banner.png", + "https://raw.githubusercontent.com/xpipe-io/.github/main/img/hub_shadow.png", + "https://raw.githubusercontent.com/xpipe-io/.github/main/img/terminal_shadow.png", + "https://raw.githubusercontent.com/xpipe-io/.github/main/img/browser_shadow.png" + ] + }, + "xplorer": { + "icon": "", + "images": [] + }, + "xplorer2": { + "icon": "https://community.chocolatey.org/content/packageimages/xplorer2.5.2.0.2.png", + "images": [] + }, + "xplorer2pro": { + "icon": "https://community.chocolatey.org/content/packageimages/xplorer2pro.5.2.0.1.png", + "images": [] + }, + "xplorer2ultimate": { + "icon": "https://community.chocolatey.org/content/packageimages/xplorer2ultimate.5.3.0.1.png", + "images": [] + }, + "xplotter": { + "icon": "", + "images": [] + }, + "xqilla": { + "icon": "", + "images": [] + }, + "xray": { + "icon": "", + "images": [] + }, + "xrecode3": { + "icon": "https://community.chocolatey.org/content/packageimages/xrecode3.1.54.png", + "images": [] + }, + "xrmtoolbox": { + "icon": "https://community.chocolatey.org/content/packageimages/xrmtoolbox.1.2021.9.52.png", + "images": [] + }, + "xsd2code": { + "icon": "", + "images": [] + }, + "xsltproc": { + "icon": "", + "images": [] + }, + "xsockets-performancecounters": { + "icon": "", + "images": [] + }, + "xsockets-windows-service": { + "icon": "", + "images": [] + }, + "xsplit-vcam": { + "icon": "", + "images": [] + }, + "xstudio": { + "icon": "", + "images": [] + }, + "xsv": { + "icon": "", + "images": [] + }, + "xtensa-esp32-elf": { + "icon": "", + "images": [] + }, + "xtensa-esp32-toolchain": { + "icon": "", + "images": [] + }, + "xtranslator": { + "icon": "", + "images": [] + }, + "xtremedownloadmanager": { + "icon": "", + "images": [] + }, + "xtremedownloadmanager-beta": { + "icon": "", + "images": [] + }, + "xtrmruntime": { + "icon": "", + "images": [] + }, + "xunit-visualstudio": { + "icon": "", + "images": [] + }, + "xunit-vs2012": { + "icon": "https://community.chocolatey.org/content/packageimages/xUnit.vs2012.0.9.5.png", + "images": [] + }, + "xvid": { + "icon": "https://community.chocolatey.org/content/packageimages/xvid.1.3.5.png", + "images": [] + }, + "xvst": { + "icon": "https://community.chocolatey.org/content/packageimages/xvst.2.5.2.20141130.png", + "images": [] + }, + "xwfim": { + "icon": "", + "images": [] + }, + "xx-net": { + "icon": "", + "images": [] + }, + "xxcopy": { + "icon": "", + "images": [] + }, + "xxd": { + "icon": "", + "images": [] + }, + "xyplorer": { + "icon": "https://community.chocolatey.org/content/packageimages/xyplorer.22.70.0100.png", + "images": [] + }, + "xyzzy": { + "icon": "https://community.chocolatey.org/content/packageimages/xyzzy.0.22.251.png", + "images": [] + }, + "xz": { + "icon": "", + "images": [] + }, + "xzaid": { + "icon": "", + "images": [] + }, + "y-cruncher": { + "icon": "", + "images": [] + }, + "y2mp3": { + "icon": "", + "images": [] + }, + "yabause": { + "icon": "https://community.chocolatey.org/content/packageimages/yabause.2.3.1.png", + "images": [] + }, + "yacreader": { + "icon": "", + "images": [] + }, + "yacy": { + "icon": "https://community.chocolatey.org/content/packageimages/yacy.1.90.png", + "images": [] + }, + "yaffplayer": { + "icon": "", + "images": [] + }, + "yakyak": { + "icon": "", + "images": [] + }, + "yale": { + "icon": "https://community.chocolatey.org/content/packageimages/yale.portable.1.25.png", + "images": [] + }, + "yammer": { + "icon": "https://community.chocolatey.org/content/packageimages/yammer.3.4.9.png", + "images": [] + }, + "yana": { + "icon": "", + "images": [] + }, + "yandex-music": { + "icon": "https://yastatic.net/s3/doc-binary/src/mediaservices/yandex_music_icon_ru_darkbg.png", + "images": [ + "https://i.postimg.cc/SKqXqtWD/i-RF5-Jgd-Z1-Q.png", + "https://i.postimg.cc/rsb0kVJr/Mo-Tmun1zjd.png", + "https://i.postimg.cc/L40ZfDp8/nl-Rywj-YEux.png", + "https://i.postimg.cc/6Q08QLcw/Scfmnn-Mo48.png", + "https://i.postimg.cc/HxkV8cvM/u-ARCBXBW1-L.png" + ] + }, + "yanknote": { + "icon": "", + "images": [] + }, + "yapa": { + "icon": "", + "images": [] + }, + "yara": { + "icon": "", + "images": [] + }, + "yarn": { + "icon": "", + "images": [] + }, + "yasm": { + "icon": "", + "images": [] + }, + "yatqa": { + "icon": "", + "images": [] + }, + "ydl-ui": { + "icon": "", + "images": [] + }, + "yed": { + "icon": "https://community.chocolatey.org/content/packageimages/yed.3.22.png", + "images": [] + }, + "yedit": { + "icon": "", + "images": [] + }, + "yeoman": { + "icon": "", + "images": [] + }, + "yesplaymusic": { + "icon": "", + "images": [] + }, + "yggdrasil": { + "icon": "", + "images": [] + }, + "yingyongbao": { + "icon": "", + "images": [] + }, + "yinxiang": { + "icon": "", + "images": [] + }, + "yo": { + "icon": "https://community.chocolatey.org/content/packageimages/yo.4.3.1.png", + "images": [] + }, + "yogadns": { + "icon": "", + "images": [] + }, + "yomail": { + "icon": "", + "images": [] + }, + "yori": { + "icon": "", + "images": [] + }, + "york": { + "icon": "", + "images": [] + }, + "yosys": { + "icon": "", + "images": [] + }, + "you-get": { + "icon": "https://community.chocolatey.org/content/packageimages/you-get.0.4.915.png", + "images": [] + }, + "youdaodict": { + "icon": "", + "images": [] + }, + "youdaonote": { + "icon": "", + "images": [] + }, + "youku": { + "icon": "", + "images": [] + }, + "yourphone": { + "icon": "https://i.postimg.cc/qMSQHJqG/Your-Phone-app-icon-2-Photoroom.png", + "images": [] + }, + "youtrack": { + "icon": "https://resources.jetbrains.com/storage/products/youtrack/img/meta/youtrack_logo_300x300.png", + "images": [] + }, + "youtube-dl": { + "icon": "", + "images": [] + }, + "youtube-dl-gui": { + "icon": "https://community.chocolatey.org/content/packageimages/youtube-dl-gui.portable.0.4.png", + "images": [] + }, + "youtube-dlc": { + "icon": "https://community.chocolatey.org/content/packageimages/youtube-dlc.2020.11.11.3.png", + "images": [] + }, + "youtube-downloader": { + "icon": "https://community.chocolatey.org/content/packageimages/youtube-downloader.1.3.1.png", + "images": [] + }, + "youtube-music": { + "icon": "", + "images": [] + }, + "youtubedownloader": { + "icon": "", + "images": [] + }, + "youtubemusic": { + "icon": "", + "images": [] + }, + "youtubetomp3": { + "icon": "", + "images": [] + }, + "yq": { + "icon": "", + "images": [] + }, + "yregedit": { + "icon": "", + "images": [] + }, + "yt-dlg": { + "icon": "https://community.chocolatey.org/content/packageimages/yt-dlg.install.1.8.4.png", + "images": [ + "https://user-images.githubusercontent.com/73800734/200966245-8fff1730-9a02-4e35-b660-f9e30a37d342.png" + ] + }, + "yt-dlp": { + "icon": "https://i.postimg.cc/dQdRHr2P/yt-dlp-icon.png", + "images": [] + }, + "ytcast": { + "icon": "", + "images": [] + }, + "ytdlp-interface": { + "icon": "", + "images": [] + }, + "ytdownloader": { + "icon": "https://community.chocolatey.org/content/packageimages/ytdownloader.3.11.0.png", + "images": [] + }, + "ytmdesktop": { + "icon": "https://i.imgur.com/YigQor4.png", + "images": [ + "https://i.imgur.com/BUrjOd1.png", + "https://i.imgur.com/lsgvfHR.png", + "https://i.imgur.com/yGGs3uL.png" + ] + }, + "ytsubconverter": { + "icon": "", + "images": [] + }, + "ytt": { + "icon": "https://community.chocolatey.org/content/packageimages/ytt.0.43.0.png", + "images": [] + }, + "yubico-authenticator": { + "icon": "", + "images": [] + }, + "yubico-piv-tool": { + "icon": "", + "images": [] + }, + "yubikey-manager": { + "icon": "https://community.chocolatey.org/content/packageimages/yubikey-manager.1.2.5.png", + "images": [] + }, + "yubikey-manager-qt": { + "icon": "", + "images": [] + }, + "yubikey-neo-manager": { + "icon": "", + "images": [] + }, + "yubikey-personalization": { + "icon": "", + "images": [] + }, + "yubikey-personalization-gui": { + "icon": "", + "images": [] + }, + "yubikey-personalization-tool": { + "icon": "https://community.chocolatey.org/content/packageimages/yubikey-personalization-tool.3.1.25.png", + "images": [] + }, + "yubikey-piv-manager": { + "icon": "https://community.chocolatey.org/content/packageimages/yubikey-piv-manager.1.4.2.103.png", + "images": [] + }, + "yubikeymanager": { + "icon": "", + "images": [] + }, + "yubikeypersonalizationtool": { + "icon": "", + "images": [] + }, + "yubioath": { + "icon": "", + "images": [] + }, + "yumi": { + "icon": "https://community.chocolatey.org/content/packageimages/yumi.2.0.9.4.png", + "images": [] + }, + "yumi-exfat": { + "icon": "", + "images": [] + }, + "yumi-uefi": { + "icon": "https://community.chocolatey.org/content/packageimages/yumi-uefi.0.0.4.6.png", + "images": [] + }, + "yuniql": { + "icon": "https://community.chocolatey.org/content/packageimages/yuniql.1.3.15.png", + "images": [] + }, + "yuqing-monitor-electron": { + "icon": "", + "images": [] + }, + "yuque": { + "icon": "", + "images": [] + }, + "yxcalendar": { + "icon": "", + "images": [] + }, + "yxfile": { + "icon": "", + "images": [] + }, + "yy": { + "icon": "", + "images": [] + }, + "yyanchor": { + "icon": "", + "images": [] + }, + "yynote": { + "icon": "", + "images": [] + }, + "z": { + "icon": "", + "images": [] + }, + "z-lua": { + "icon": "", + "images": [] + }, + "z3": { + "icon": "https://community.chocolatey.org/content/packageimages/z3.4.12.1.png", + "images": [] + }, + "zabbix-agent": { + "icon": "https://community.chocolatey.org/content/packageimages/zabbix-agent.install.6.2.7.png", + "images": [] + }, + "zabbix-agent2": { + "icon": "https://community.chocolatey.org/content/packageimages/zabbix-agent2.6.2.7.png", + "images": [] + }, + "zalo": { + "icon": "", + "images": [] + }, + "zalopc": { + "icon": "https://community.chocolatey.org/content/packageimages/zalopc.23.2.1.png", + "images": [] + }, + "zandronum": { + "icon": "", + "images": [] + }, + "zap": { + "icon": "https://community.chocolatey.org/content/packageimages/zap.2.12.0.20221127.png", + "images": [] + }, + "zaproxy": { + "icon": "", + "images": [] + }, + "zazu": { + "icon": "https://community.chocolatey.org/content/packageimages/zazu.0.6.0.png", + "images": [] + }, + "zbar": { + "icon": "https://community.chocolatey.org/content/packageimages/zbar.0.10.png", + "images": [] + }, + "zeal": { + "icon": "https://community.chocolatey.org/content/packageimages/zeal.portable.0.6.1.png", + "images": [] + }, + "zecwallet": { + "icon": "https://community.chocolatey.org/content/packageimages/zecwallet.1.8.5.png", + "images": [] + }, + "zecwallet-lite": { + "icon": "https://community.chocolatey.org/content/packageimages/zecwallet-lite.1.17.20.png", + "images": [] + }, + "zeebe": { + "icon": "", + "images": [] + }, + "zeebe-modeler": { + "icon": "", + "images": [] + }, + "zello": { + "icon": "", + "images": [] + }, + "zen-browser": { + "icon": "https://raw.githubusercontent.com/zen-browser/desktop/dev/configs/branding/release/logo1024.png", + "images": [ + "https://i.postimg.cc/MTFqp5N4/browsers-i-Ox7z-S8-P-Z2u-WYk9.png", + "https://i.postimg.cc/9XDqtnmD/browser-workspaces-Cb-JPkzf-E-Ha2-Q.png", + "https://i.postimg.cc/yY9g23SB/browser-splitview-Cf6r-Lqf4-Zn7p-D.png", + "https://i.postimg.cc/qMCMzfkG/browser-sidebar-dj-YBVG-Z-rtpa-P.png", + "https://i.postimg.cc/7PjJBnhm/browser-compactmode-U4-Ir-AYin-26y.png" + ] + }, + "zen-browser-twilight": { + "icon": "https://i.ibb.co/LDSjdjNP/Image.png", + "images": [] + }, + "zenhan": { + "icon": "", + "images": [] + }, + "zentimings": { + "icon": "https://community.chocolatey.org/content/packageimages/zentimings.1.2.9.png", + "images": [] + }, + "zentimo": { + "icon": "", + "images": [] + }, + "zephyr-crosstool-xtensa-intel-apl-adsp": { + "icon": "https://community.chocolatey.org/content/packageimages/zephyr-crosstool-xtensa-intel-apl-adsp.1.24.0.4.png", + "images": [] + }, + "zephyr-gnuarmemb": { + "icon": "https://community.chocolatey.org/content/packageimages/zephyr-gnuarmemb.10.2.1.png", + "images": [] + }, + "zephyr-ide": { + "icon": "https://community.chocolatey.org/content/packageimages/zephyr-ide.1.14.0.png", + "images": [] + }, + "zeplin": { + "icon": "", + "images": [] + }, + "zeppelin": { + "icon": "", + "images": [] + }, + "zerabase": { + "icon": "", + "images": [] + }, + "zerobrane-studio": { + "icon": "", + "images": [] + }, + "zerofill": { + "icon": "", + "images": [] + }, + "zeroinstall": { + "icon": "https://i.postimg.cc/TPqFDC19/zero.png", + "images": [ + "https://i.postimg.cc/3N7wZLFx/image.png", + "https://i.postimg.cc/CLxhLnvX/image.png", + "https://i.postimg.cc/HLXHPwxc/image.png", + "https://i.postimg.cc/y6vK5YVP/image.png" + ] + }, + "zeronet": { + "icon": "https://community.chocolatey.org/content/packageimages/zeronet.0.7.1.png", + "images": [] + }, + "zerotierone": { + "icon": "", + "images": [] + }, + "zeta-test-management": { + "icon": "https://community.chocolatey.org/content/packageimages/zeta-test-management.3.6.17.0.png", + "images": [] + }, + "zettlr": { + "icon": "https://www.zettlr.com/themes/zettlr/assets/img/256x256.png", + "images": [] + }, + "zeuside": { + "icon": "", + "images": [] + }, + "zeuslite": { + "icon": "", + "images": [] + }, + "zg-ipchat": { + "icon": "", + "images": [] + }, + "zg-mdm": { + "icon": "", + "images": [] + }, + "zg-pkg": { + "icon": "", + "images": [] + }, + "zg-print": { + "icon": "", + "images": [] + }, + "zg-upload": { + "icon": "", + "images": [] + }, + "zg-zsso": { + "icon": "", + "images": [] + }, + "zhiyuntranslator": { + "icon": "", + "images": [] + }, + "zig": { + "icon": "https://community.chocolatey.org/content/packageimages/zig.0.10.1.png", + "images": [] + }, + "zim": { + "icon": "https://community.chocolatey.org/content/packageimages/zim.0.68.png", + "images": [] + }, + "zint": { + "icon": "https://github.com/zint/zint/blob/master/docs/images/zint-qt.png", + "images": [] + }, + "zip": { + "icon": "", + "images": [] + }, + "zip-template": { + "icon": "https://community.chocolatey.org/content/packageimages/zip.template.1.0.0.png", + "images": [] + }, + "zipinst": { + "icon": "https://community.chocolatey.org/content/packageimages/zipinst.1.21.png", + "images": [] + }, + "zipmanager": { + "icon": "", + "images": [] + }, + "zitidesktopedge": { + "icon": "", + "images": [] + }, + "zkanji": { + "icon": "https://community.chocolatey.org/content/packageimages/zkanji.0.731.png", + "images": [] + }, + "zlib": { + "icon": "", + "images": [] + }, + "zlocation": { + "icon": "", + "images": [] + }, + "zmc": { + "icon": "", + "images": [] + }, + "znote": { + "icon": "", + "images": [] + }, + "zoe": { + "icon": "https://community.chocolatey.org/content/packageimages/zoe.0.28.0.png", + "images": [] + }, + "zohomail-desktop": { + "icon": "", + "images": [] + }, + "zoiper": { + "icon": "https://community.chocolatey.org/content/packageimages/Zoiper.5.5.10.png", + "images": [] + }, + "zola": { + "icon": "https://community.chocolatey.org/content/packageimages/zola.0.16.1.png", + "images": [] + }, + "zona": { + "icon": "https://community.chocolatey.org/content/packageimages/zona.2.0.3.3.png", + "images": [] + }, + "zookeeper": { + "icon": "", + "images": [] + }, + "zoom": { + "icon": "https://i.postimg.cc/NFd1Qg5d/zoom-logo.png", + "images": [ + "https://i.postimg.cc/HW0dsF59/Zoom1.png", + "https://i.postimg.cc/pXqvK8s9/Zoom2.png", + "https://i.postimg.cc/52yVg0rs/Zoom3.png" + ] + }, + "zoom-client": { + "icon": "", + "images": [] + }, + "zoom-outlook": { + "icon": "", + "images": [] + }, + "zoomit": { + "icon": "https://community.chocolatey.org/content/packageimages/zoomit.6.12.png", + "images": [] + }, + "zoomoutlookplugin": { + "icon": "", + "images": [] + }, + "zoomrooms": { + "icon": "", + "images": [] + }, + "zotero": { + "icon": "https://www.zotero.org/static/images/icons/zotero-app-icon-256.png", + "images": [] + }, + "zotero-standalone": { + "icon": "", + "images": [] + }, + "zoxide": { + "icon": "", + "images": [] + }, + "zpaq": { + "icon": "", + "images": [] + }, + "zsnes": { + "icon": "https://community.chocolatey.org/content/packageimages/zsnes.1.51.png", + "images": [] + }, + "zstandard": { + "icon": "https://community.chocolatey.org/content/packageimages/zstandard.1.5.0.png", + "images": [] + }, + "zstd": { + "icon": "", + "images": [] + }, + "zulip": { + "icon": "", + "images": [] + }, + "zulu": { + "icon": "https://i.postimg.cc/bwR9h2mZ/zulu-icon.png", + "images": [] + }, + "zulu-10-jdk": { + "icon": "https://i.postimg.cc/bwR9h2mZ/zulu-icon.png", + "images": [] + }, + "zulu-10-jre": { + "icon": "https://i.postimg.cc/bwR9h2mZ/zulu-icon.png", + "images": [] + }, + "zulu-11-jdk": { + "icon": "https://i.postimg.cc/bwR9h2mZ/zulu-icon.png", + "images": [] + }, + "zulu-11-jre": { + "icon": "https://i.postimg.cc/bwR9h2mZ/zulu-icon.png", + "images": [] + }, + "zulu-12-jdk": { + "icon": "https://i.postimg.cc/bwR9h2mZ/zulu-icon.png", + "images": [] + }, + "zulu-12-jre": { + "icon": "https://i.postimg.cc/bwR9h2mZ/zulu-icon.png", + "images": [] + }, + "zulu-13-jdk": { + "icon": "https://i.postimg.cc/bwR9h2mZ/zulu-icon.png", + "images": [] + }, + "zulu-13-jre": { + "icon": "https://i.postimg.cc/bwR9h2mZ/zulu-icon.png", + "images": [] + }, + "zulu-14-jdk": { + "icon": "https://i.postimg.cc/bwR9h2mZ/zulu-icon.png", + "images": [] + }, + "zulu-14-jre": { + "icon": "https://i.postimg.cc/bwR9h2mZ/zulu-icon.png", + "images": [] + }, + "zulu-15-jdk": { + "icon": "https://i.postimg.cc/bwR9h2mZ/zulu-icon.png", + "images": [] + }, + "zulu-15-jre": { + "icon": "https://i.postimg.cc/bwR9h2mZ/zulu-icon.png", + "images": [] + }, + "zulu-16-jdk": { + "icon": "https://i.postimg.cc/bwR9h2mZ/zulu-icon.png", + "images": [] + }, + "zulu-16-jre": { + "icon": "https://i.postimg.cc/bwR9h2mZ/zulu-icon.png", + "images": [] + }, + "zulu-17-jdk": { + "icon": "https://i.postimg.cc/bwR9h2mZ/zulu-icon.png", + "images": [] + }, + "zulu-17-jre": { + "icon": "https://i.postimg.cc/bwR9h2mZ/zulu-icon.png", + "images": [] + }, + "zulu-18-jdk": { + "icon": "https://i.postimg.cc/bwR9h2mZ/zulu-icon.png", + "images": [] + }, + "zulu-18-jre": { + "icon": "https://i.postimg.cc/bwR9h2mZ/zulu-icon.png", + "images": [] + }, + "zulu-19-jdk": { + "icon": "https://i.postimg.cc/bwR9h2mZ/zulu-icon.png", + "images": [] + }, + "zulu-19-jre": { + "icon": "https://i.postimg.cc/bwR9h2mZ/zulu-icon.png", + "images": [] + }, + "zulu-20-jdk": { + "icon": "https://i.postimg.cc/bwR9h2mZ/zulu-icon.png", + "images": [] + }, + "zulu-20-jre": { + "icon": "https://i.postimg.cc/bwR9h2mZ/zulu-icon.png", + "images": [] + }, + "zulu-21-jdk": { + "icon": "https://i.postimg.cc/bwR9h2mZ/zulu-icon.png", + "images": [] + }, + "zulu-21-jre": { + "icon": "https://i.postimg.cc/bwR9h2mZ/zulu-icon.png", + "images": [] + }, + "zulu-22-jdk": { + "icon": "https://i.postimg.cc/bwR9h2mZ/zulu-icon.png", + "images": [] + }, + "zulu-22-jre": { + "icon": "https://i.postimg.cc/bwR9h2mZ/zulu-icon.png", + "images": [] + }, + "zulu-23-jdk": { + "icon": "https://i.postimg.cc/bwR9h2mZ/zulu-icon.png", + "images": [] + }, + "zulu-23-jre": { + "icon": "https://i.postimg.cc/bwR9h2mZ/zulu-icon.png", + "images": [] + }, + "zulu-24-jdk": { + "icon": "https://i.postimg.cc/bwR9h2mZ/zulu-icon.png", + "images": [] + }, + "zulu-24-jre": { + "icon": "https://i.postimg.cc/bwR9h2mZ/zulu-icon.png", + "images": [] + }, + "zulu-25-jdk": { + "icon": "https://i.postimg.cc/bwR9h2mZ/zulu-icon.png", + "images": [] + }, + "zulu-25-jre": { + "icon": "https://i.postimg.cc/bwR9h2mZ/zulu-icon.png", + "images": [] + }, + "zulu-6-jre": { + "icon": "https://i.postimg.cc/bwR9h2mZ/zulu-icon.png", + "images": [] + }, + "zulu-6-jdk": { + "icon": "https://i.postimg.cc/bwR9h2mZ/zulu-icon.png", + "images": [] + }, + "zulu-7-jdk": { + "icon": "https://i.postimg.cc/bwR9h2mZ/zulu-icon.png", + "images": [] + }, + "zulu-7-jre": { + "icon": "https://i.postimg.cc/bwR9h2mZ/zulu-icon.png", + "images": [] + }, + "zulu-8-jdk": { + "icon": "https://i.postimg.cc/bwR9h2mZ/zulu-icon.png", + "images": [] + }, + "zulu-8-jre": { + "icon": "https://i.postimg.cc/bwR9h2mZ/zulu-icon.png", + "images": [] + }, + "zulu-9-jdk": { + "icon": "https://i.postimg.cc/bwR9h2mZ/zulu-icon.png", + "images": [] + }, + "zulu-9-jre": { + "icon": "https://i.postimg.cc/bwR9h2mZ/zulu-icon.png", + "images": [] + }, + "zulu11": { + "icon": "https://i.postimg.cc/bwR9h2mZ/zulu-icon.png", + "images": [] + }, + "zulu12": { + "icon": "https://i.postimg.cc/bwR9h2mZ/zulu-icon.png", + "images": [] + }, + "zulu13": { + "icon": "https://i.postimg.cc/bwR9h2mZ/zulu-icon.png", + "images": [] + }, + "zulu14": { + "icon": "https://i.postimg.cc/bwR9h2mZ/zulu-icon.png", + "images": [] + }, + "zulu15": { + "icon": "https://i.postimg.cc/bwR9h2mZ/zulu-icon.png", + "images": [] + }, + "zulu16": { + "icon": "https://i.postimg.cc/bwR9h2mZ/zulu-icon.png", + "images": [] + }, + "zulu7": { + "icon": "https://i.postimg.cc/bwR9h2mZ/zulu-icon.png", + "images": [] + }, + "zulufx-17-jdk": { + "icon": "https://i.postimg.cc/bwR9h2mZ/zulu-icon.png", + "images": [] + }, + "zulufx-17-jre": { + "icon": "https://i.postimg.cc/bwR9h2mZ/zulu-icon.png", + "images": [] + }, + "zulufx-18-jdk": { + "icon": "https://i.postimg.cc/bwR9h2mZ/zulu-icon.png", + "images": [] + }, + "zulufx-18-jre": { + "icon": "https://i.postimg.cc/bwR9h2mZ/zulu-icon.png", + "images": [] + }, + "zulufx-19-jdk": { + "icon": "https://i.postimg.cc/bwR9h2mZ/zulu-icon.png", + "images": [] + }, + "zulufx-19-jre": { + "icon": "https://i.postimg.cc/bwR9h2mZ/zulu-icon.png", + "images": [] + }, + "zulufx-20-jdk": { + "icon": "https://i.postimg.cc/bwR9h2mZ/zulu-icon.png", + "images": [] + }, + "zulufx-20-jre": { + "icon": "https://i.postimg.cc/bwR9h2mZ/zulu-icon.png", + "images": [] + }, + "zulufx-21-jdk": { + "icon": "https://i.postimg.cc/bwR9h2mZ/zulu-icon.png", + "images": [] + }, + "zulufx-21-jre": { + "icon": "https://i.postimg.cc/bwR9h2mZ/zulu-icon.png", + "images": [] + }, + "zulufx-22-jdk": { + "icon": "https://i.postimg.cc/bwR9h2mZ/zulu-icon.png", + "images": [] + }, + "zulufx-22-jre": { + "icon": "https://i.postimg.cc/bwR9h2mZ/zulu-icon.png", + "images": [] + }, + "zulufx-23-jdk": { + "icon": "https://i.postimg.cc/bwR9h2mZ/zulu-icon.png", + "images": [] + }, + "zulufx-23-jre": { + "icon": "https://i.postimg.cc/bwR9h2mZ/zulu-icon.png", + "images": [] + }, + "zulufx-24-jdk": { + "icon": "https://i.postimg.cc/bwR9h2mZ/zulu-icon.png", + "images": [] + }, + "zulufx-24-jre": { + "icon": "https://i.postimg.cc/bwR9h2mZ/zulu-icon.png", + "images": [] + }, + "zulufx-25-jdk": { + "icon": "https://i.postimg.cc/bwR9h2mZ/zulu-icon.png", + "images": [] + }, + "zulufx-25-jre": { + "icon": "https://i.postimg.cc/bwR9h2mZ/zulu-icon.png", + "images": [] + }, + "zunemusic": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/5/51/Media_Player_Windows_11_logo.svg/2048px-Media_Player_Windows_11_logo.svg.png", + "images": [] + }, + "zwift": { + "icon": "", + "images": [] + }, + "zxpinstaller": { + "icon": "https://i.postimg.cc/Qt0c5n6C/ZXPInstaller.png", + "images": [ + "https://i.postimg.cc/Yq3jSms2/image.png" + ] + }, + "wordaizer": { + "icon": "https://i.postimg.cc/J0BR3tZQ/Wordaizer.png", + "images": [ + "https://i.postimg.cc/XqFpjsH3/image.png", + "https://i.postimg.cc/g0JjXzSg/image.png", + "https://i.postimg.cc/RhrZDcMY/image.png" + ] + }, + "cherrystudio": { + "icon": "https://i.postimg.cc/dV1zPvj5/image.png", + "images": [ + "https://i.postimg.cc/9fPPLwwK/image.png", + "https://i.postimg.cc/XJVfmNwJ/image.png", + "https://i.postimg.cc/4yyz482R/image.png", + "https://i.postimg.cc/xTWKY3KB/image.png" + ] + }, + "javelinpdfreader-3": { + "icon": "https://i.postimg.cc/mkzGyz6P/Javelin3.png", + "images": [ + "https://i.postimg.cc/bYWPNgsk/image.png", + "https://i.postimg.cc/CL8gZ8qt/image.png", + "https://i.postimg.cc/mrLf665f/image.png" + ] + }, + "fastpictureviewer-professional": { + "icon": "https://i.ibb.co/FLLTZ91c/Fast-Picture-Viewer.png", + "images": [ + "https://i.postimg.cc/RVfwPv88/image.png", + "https://i.postimg.cc/kgmKzkP5/image.png" + ] + }, + "artweaver-7-plus": { + "icon": "", + "images": [ + "https://i.postimg.cc/T2HKzy83/art7plus.png", + "https://i.postimg.cc/gkZ21Nqg/image.png" + ] + }, + "artweaver-8-plus": { + "icon": "", + "images": [ + "https://i.postimg.cc/5N6CyB5z/art8plus.png", + "https://i.postimg.cc/k4vxN7Dt/image.png" + ] + }, + "artweaver-7-free": { + "icon": "", + "images": [ + "https://i.postimg.cc/rsdwVJ6F/art7free.png", + "https://i.postimg.cc/yd8N5KvR/image.png" + ] + }, + "artweaver-8-free": { + "icon": "", + "images": [ + "https://i.postimg.cc/yNzgL2Mh/art8free.png", + "https://i.postimg.cc/k4vxN7Dt/image.png" + ] + }, + "passwordrecovery": { + "icon": "https://i.postimg.cc/SKJS7dsL/edpr.png", + "images": [ + "https://i.postimg.cc/PrTdFTJ5/image.png", + "https://i.postimg.cc/RVd4kyJQ/image.png", + "https://i.postimg.cc/Bnv44pxW/image.png" + ] + }, + "forensicdiskdecryptor": { + "icon": "https://i.postimg.cc/GhXn7D6X/efdd.png", + "images": [ + "https://i.postimg.cc/0NwgyBj4/image.png", + "https://i.postimg.cc/26Rsb7BS/image.png", + "https://i.postimg.cc/NM6W1217/image.png", + "https://i.postimg.cc/Fss2LR13/image.png" + ] + }, + "wirelesssecurityauditor": { + "icon": "https://i.postimg.cc/L8gQtZSY/ewsa.png", + "images": [ + "https://i.postimg.cc/SQVPkhVs/image.png", + "https://i.postimg.cc/VL6VNVHF/image.png", + "https://i.postimg.cc/dtxSZjbc/image.png" + ] + }, + "geekbenchai": { + "icon": "", + "images": [ + "https://i.postimg.cc/KzG5H165/image.png", + "https://i.postimg.cc/1XYM6yYr/image.png" + ] + }, + "familytreebuilder": { + "icon": "https://i.postimg.cc/HxvP00rM/My-Heritage.png", + "images": [ + "https://i.ibb.co/5x84kGkK/Image.png" + ] + }, + "quickcpux64": { + "icon": "https://i.postimg.cc/vB6bVmBG/QuickCPU.png", + "images": [ + "https://i.ibb.co/XrMJW7hd/Image.png", + "https://i.ibb.co/chqQb4yy/Image.png", + "https://i.ibb.co/S774Zksk/Image.png" + ] + }, + "radiantdicomviewer": { + "icon": "https://i.postimg.cc/Ls5qXnZd/radiant.png", + "images": [ + "https://i.postimg.cc/C1Dzb0Lp/image.png", + "https://i.postimg.cc/zXYTtd9k/image.png", + "https://i.postimg.cc/X7KdTfW6/image.png" + ] + }, + "reqview": { + "icon": "https://i.postimg.cc/RFcvVBG5/reqview.png", + "images": [ + "https://i.postimg.cc/rmYQRSmP/image.png", + "https://i.postimg.cc/tCGm3NkK/image.png", + "https://i.postimg.cc/J43YPHdG/image.png" + ] + }, + "unraidusbcreator": { + "icon": "https://i.postimg.cc/h4TXfFhG/unraid.png", + "images": [ + "https://i.postimg.cc/g2QhhNqR/image.png", + "https://i.postimg.cc/26fBcytS/image.png", + "https://i.postimg.cc/FzTdHZHY/image.png" + ] + }, + "viceversapro": { + "icon": "https://i.postimg.cc/VsFydCfY/Vice-Versa.png", + "images": [ + "https://i.postimg.cc/MKZCRpH1/Bitmap-665.png", + "https://i.postimg.cc/2yrxsyMG/image.png", + "https://i.postimg.cc/nV2KsH68/image.png", + "https://i.postimg.cc/kXhxcTJf/image.png", + "https://i.postimg.cc/L8cjdhZP/image.png", + "https://i.postimg.cc/W40gsjMH/image.png" + ] + }, + "autorunorganizer": { + "icon": "", + "images": [ + "https://i.postimg.cc/XqYSYZbs/image.png" + ] + }, + "asctimetables": { + "icon": "https://i.postimg.cc/bYt4vB3k/asa.png", + "images": [ + "https://i.postimg.cc/zB6mQmpX/splash.jpg", + "https://i.postimg.cc/NFXhqNP8/image.png", + "https://i.postimg.cc/2jLNZ68q/image.png", + "https://i.postimg.cc/x1Ywh3GH/image.png", + "https://i.postimg.cc/VNk3LsVk/image.png", + "https://i.postimg.cc/g0t1w9Cq/image.png" + ] + }, + "winuae": { + "icon": "https://i.postimg.cc/15Rk8qtF/winuae.png", + "images": [ + "https://i.postimg.cc/Pf1XWYTF/image.png", + "https://i.postimg.cc/kgTXVCqJ/image.png", + "https://i.postimg.cc/LsqRnZxD/image.png", + "https://i.postimg.cc/ZYPmBmxG/image.png", + "https://i.postimg.cc/VkhPQkzC/image.png" + ] + }, + "modbusslave": { + "icon": "https://i.postimg.cc/KcgxbyR0/slave.png", + "images": [ + "https://i.postimg.cc/YCLSymQC/image.png", + "https://i.postimg.cc/BZhQSCgv/image.png", + "https://i.postimg.cc/8P9pWPxQ/image.png", + "https://i.postimg.cc/mg9bSWGc/image.png" + ] + }, + "modbuspoll": { + "icon": "https://i.postimg.cc/3x3T249q/poll.png", + "images": [ + "https://i.postimg.cc/Jh9Z2Ls9/image.png", + "https://i.postimg.cc/prv8PJYC/image.png", + "https://i.postimg.cc/13XFRt6k/image.png", + "https://i.postimg.cc/t4cxsjNY/image.png" + ] + }, + "modbusmasteremulator": { + "icon": "https://i.postimg.cc/Jz1dxSvr/mme.png", + "images": [ + "https://i.postimg.cc/LsbZXhgY/image.png", + "https://i.postimg.cc/fy4tcFKM/image.png", + "https://i.postimg.cc/d3874BHr/image.png", + "https://i.postimg.cc/SQ8zSSSR/image.png", + "https://i.postimg.cc/pXJhjsnt/image.png", + "https://i.postimg.cc/K8cKDtn3/image.png" + ] + }, + "modbustool": { + "icon": "https://i.postimg.cc/7ZFJwy4D/image.png", + "images": [ + "https://i.postimg.cc/q72h7ZBK/image.png", + "https://i.postimg.cc/TwGy5qh4/image.png" + ] + }, + "modbusslaveemulator": { + "icon": "https://i.postimg.cc/wBPpS6Yc/mse.png", + "images": [ + "https://i.postimg.cc/PrB58zRQ/image.png" + ] + }, + "gs-base": { + "icon": "https://i.postimg.cc/hvFwcvjg/gsbase.png", + "images": [ + "https://i.postimg.cc/NMyqQZk8/image.png", + "https://i.postimg.cc/SQMF3Fsk/image.png", + "https://i.postimg.cc/WbmRpGgy/image.png", + "https://i.postimg.cc/KYzC5CwX/image.png" + ] + }, + "gs-calc": { + "icon": "", + "images": [ + "https://i.postimg.cc/SRWPs429/image.png", + "https://i.postimg.cc/gcRQ4VS0/image.png", + "https://i.postimg.cc/J4LgFsv5/image.png", + "https://i.postimg.cc/4dcLLG10/image.png", + "https://i.postimg.cc/0jqth4Wy/image.png" + ] + }, + "wavepad": { + "icon": "", + "images": [ + "https://i.postimg.cc/DzNLMYf4/image.png", + "https://i.postimg.cc/BQCD0vQ0/image.png" + ] + }, + "xftp": { + "icon": "https://i.postimg.cc/y8s02ZmB/Xftp.png", + "images": [ + "https://i.postimg.cc/TwYmhMks/image.png", + "https://i.postimg.cc/w3K7XSVg/image.png", + "https://i.postimg.cc/tRskzW5M/image.png", + "https://i.postimg.cc/FFwZCzCs/image.png" + ] + }, + "xshell": { + "icon": "https://i.postimg.cc/Jz55hqrG/Xshell.png", + "images": [ + "https://i.postimg.cc/bJCntCWw/image.png", + "https://i.postimg.cc/j55wt620/image.png", + "https://i.postimg.cc/mD5cDc1c/image.png", + "https://i.postimg.cc/NF2KrgRd/image.png" + ] + }, + "xlightftp": { + "icon": "https://i.postimg.cc/zvBRg18V/image.png", + "images": [ + "https://i.postimg.cc/wvzvhYc9/image.png", + "https://i.postimg.cc/K8Ys8162/image.png", + "https://i.postimg.cc/6p1b29KG/image.png", + "https://i.postimg.cc/W4FW0QpY/image.png" + ] + }, + "talktype": { + "icon": "https://i.postimg.cc/g0fRtjdP/image.png", + "images": [ + "https://i.postimg.cc/28zWKPp3/image.png", + "https://i.postimg.cc/L5vJS8d5/image.png" + ] + }, + "zetaresourceeditor": { + "icon": "https://i.postimg.cc/T1mFZpZM/paint-brush.png", + "images": [ + "https://i.postimg.cc/15rYwhSH/image.png", + "https://i.postimg.cc/L8yCQtng/image.png", + "https://i.postimg.cc/bvW6pq0z/image.png", + "https://i.postimg.cc/Y0wbL8yZ/image.png" + ] + }, + "ultrastarworldparty": { + "icon": "https://i.postimg.cc/1t4ZYRms/World-Party.png", + "images": [ + "https://i.postimg.cc/fyLkCQF9/image.png", + "https://i.postimg.cc/y8qYgRV9/image.png", + "https://i.postimg.cc/BZkJkFPy/image.png" + ] + }, + "onewarestudio": { + "icon": "", + "images": [ + "https://i.postimg.cc/pT0KRCMK/image.png", + "https://i.postimg.cc/JnRQ1tDC/image.png", + "https://i.postimg.cc/wTnc1wyV/image.png", + "https://i.postimg.cc/SKfWtqZT/image.png" + ] + }, + "profiler": { + "icon": "", + "images": [ + "https://i.postimg.cc/HsKg7VyQ/image.png" + ] + }, + "i1profiler": { + "icon": "https://i.postimg.cc/D01LJF1r/i1-Profiler.png", + "images": [] + }, + "zepra": { + "icon": "https://i.postimg.cc/GtLSzMzs/zepra.png", + "images": [] + }, + "hexworkshop": { + "icon": "https://i.postimg.cc/fbdFbSJk/hexworkshop.png", + "images": [ + "https://i.postimg.cc/sXhZqy6k/image.png" + ] + }, + "gerbview": { + "icon": "https://i.postimg.cc/ZnL1DDWz/gerbview.png", + "images": [ + "https://i.postimg.cc/52svFsQR/gerbview.png" + ] + }, + "jprofiler-14": { + "icon": "https://i.postimg.cc/C54dpKjQ/jprofiler.png", + "images": [ + "https://i.postimg.cc/DzqTMMQC/image.png", + "https://i.postimg.cc/nzbLsm2W/image.png", + "https://i.postimg.cc/8kyV9WWV/image.png", + "https://i.postimg.cc/28MN8D2c/image.png", + "https://i.postimg.cc/2SWR1Ktz/image.png", + "https://i.postimg.cc/zf1mKkmT/image.png", + "https://i.postimg.cc/CKC3NfYX/image.png" + ] + }, + "jprofiler-15": { + "icon": "https://i.postimg.cc/C54dpKjQ/jprofiler.png", + "images": [ + "https://i.postimg.cc/DzqTMMQC/image.png", + "https://i.postimg.cc/nzbLsm2W/image.png", + "https://i.postimg.cc/8kyV9WWV/image.png", + "https://i.postimg.cc/28MN8D2c/image.png", + "https://i.postimg.cc/2SWR1Ktz/image.png", + "https://i.postimg.cc/zf1mKkmT/image.png", + "https://i.postimg.cc/CKC3NfYX/image.png" + ] + }, + "jprofiler-13": { + "icon": "https://i.postimg.cc/9XgvJ25m/jprofiler13.png", + "images": [ + "https://i.postimg.cc/qqKSNtm1/jprofiler-box.png", + "https://i.postimg.cc/nzbLsm2W/image.png", + "https://i.postimg.cc/8kyV9WWV/image.png", + "https://i.postimg.cc/28MN8D2c/image.png", + "https://i.postimg.cc/2SWR1Ktz/image.png", + "https://i.postimg.cc/zf1mKkmT/image.png", + "https://i.postimg.cc/CKC3NfYX/image.png" + ] + }, + "perfino-4": { + "icon": "", + "images": [ + "https://i.postimg.cc/QN7ykTbb/image.png", + "https://i.postimg.cc/m2G6dgpG/image.png", + "https://i.postimg.cc/pLWcH1tG/image.png" + ] + }, + "eclipseideforjavadevelopers": { + "icon": "https://i.postimg.cc/pLsbYd7V/eclipse.png", + "images": [] + }, + "photovariants": { + "icon": "https://i.postimg.cc/VkxWdxBf/pv.png", + "images": [ + "https://i.postimg.cc/s2KxtS2k/image.png", + "https://i.postimg.cc/W33zj3Fh/image.png", + "https://i.postimg.cc/RqrZcLPH/image.png", + "https://i.postimg.cc/13QpSG9X/image.png", + "https://i.postimg.cc/bvYkDqSj/image.png" + ] + }, + "stratoshark": { + "icon": "https://i.postimg.cc/Hnmh5YC1/image.png", + "images": [ + "https://i.postimg.cc/C1gNrcrj/image.png", + "https://i.postimg.cc/rwgMwHxp/image.png" + ] + }, + "soluling": { + "icon": "https://i.postimg.cc/htKPrCwR/Soluling.png", + "images": [ + "https://i.postimg.cc/Wp9njKGX/image.png", + "https://i.postimg.cc/B6TVMCkR/image.png", + "https://i.postimg.cc/ncC1LkTZ/image.png", + "https://i.postimg.cc/DyHP4XYG/image.png" + ] + }, + "msiwrapper": { + "icon": "https://i.postimg.cc/BQBSzFCk/wrap.png", + "images": [ + "https://i.postimg.cc/8zd1q6Bx/image.png", + "https://i.postimg.cc/T2WhthFv/image.png", + "https://i.postimg.cc/5NdyTbWY/image.png", + "https://i.postimg.cc/rwqmyjmq/image.png", + "https://i.postimg.cc/8C5zMCM3/image.png", + "https://i.postimg.cc/43SN5T13/image.png", + "https://i.postimg.cc/MTfZ3rsm/image.png", + "https://i.postimg.cc/6qdWt4x7/image.png" + ] + }, + "recexperts": { + "icon": "", + "images": [ + "https://i.postimg.cc/K8mf2MTV/image.png", + "https://i.postimg.cc/j5nQXQVW/image.png", + "https://i.postimg.cc/W3dSycZ1/image.png", + "https://i.postimg.cc/sfkywVW1/image.png", + "https://i.postimg.cc/T2mB2nyY/image.png", + "https://i.postimg.cc/hPNJ8WD0/image.png", + "https://i.postimg.cc/fkQVNmgr/image.png" + ] + }, + "filelocator": { + "icon": "https://i.postimg.cc/MHkfsnx8/fileloc.png", + "images": [ + "https://i.postimg.cc/7YfLsxm2/image.png", + "https://i.postimg.cc/Pqkr51hW/image.png", + "https://i.postimg.cc/KzGGnF14/image.png", + "https://i.postimg.cc/3N635vnD/image.png", + "https://i.postimg.cc/mZ6LFvB2/image.png", + "https://i.postimg.cc/Qx2jfcF2/image.png" + ] + }, + "fileviewerplus": { + "icon": "https://i.postimg.cc/bwcZ1nPJ/fvp.png", + "images": [ + "https://i.postimg.cc/GtGMtYrD/image.png", + "https://i.postimg.cc/hvBLCYWJ/image.png", + "https://i.postimg.cc/7hwz1T00/image.png", + "https://i.postimg.cc/dVLy9FkH/image.png" + ] + }, + "k8studio": { + "icon": "https://i.postimg.cc/507Hzk9d/k8.png", + "images": [ + "https://i.postimg.cc/5NG0bCyg/image.png", + "https://i.postimg.cc/J00rWrWS/image.png", + "https://i.postimg.cc/J0F1rfr0/image.png", + "https://i.postimg.cc/QxB84dmT/image.png" + ] + }, + "puresync-personal": { + "icon": "https://i.postimg.cc/JhCj7g0p/ps.png", + "images": [ + "https://i.postimg.cc/tJ6XgrYz/image.png", + "https://i.postimg.cc/hGGcm4Xv/image.png", + "https://i.postimg.cc/tgmyN065/image.png" + ] + }, + "binaryninja": { + "icon": "https://i.postimg.cc/SNKrHwY8/bn.png", + "images": [ + "https://i.postimg.cc/SQcFJYgV/image.png", + "https://i.postimg.cc/6qJkMBpd/image.png", + "https://i.postimg.cc/6p5Djjt1/image.png", + "https://i.postimg.cc/Z57X18qY/image.png", + "https://i.postimg.cc/0Qm3Mh0r/image.png", + "https://i.postimg.cc/j24FvN9b/image.png" + ] + }, + "winget-autoupdate": { + "icon": "https://i.postimg.cc/gcRqwQxF/wau.png", + "images": [ + "https://i.postimg.cc/2yP4tdct/image.png", + "https://i.postimg.cc/PfczNhXM/image.png", + "https://i.postimg.cc/XY6fc8yG/image.png" + ] + }, + "chattrans": { + "icon": "", + "images": [ + "https://i.postimg.cc/jq1JM3dh/image.png", + "https://i.postimg.cc/7LBgwHDF/image.png", + "https://i.postimg.cc/SsJcKBxJ/image.png", + "https://i.postimg.cc/xChMN6Xg/image.png" + ] + }, + "webcatalog": { + "icon": "", + "images": [ + "https://i.postimg.cc/SQM27D49/image.png" + ] + }, + "iconset": { + "icon": "https://i.postimg.cc/BZmZdz0k/iconset.png", + "images": [ + "https://i.postimg.cc/pyMPqfDY/image.png", + "https://i.postimg.cc/X7953xDW/image.png" + ] + }, + "merge": { + "icon": "https://i.postimg.cc/qqqw0MLL/amerge.png", + "images": [ + "https://i.postimg.cc/43FkWDtQ/image.png", + "https://i.postimg.cc/d1bMYG57/image.png", + "https://i.postimg.cc/C5k3Ld2c/image.png", + "https://i.postimg.cc/9X95BNfy/image.png", + "https://i.postimg.cc/g2Nf0CMb/image.png", + "https://i.postimg.cc/8CcxfZ3J/image.png", + "https://i.postimg.cc/50FGn6ff/image.png" + ] + }, + "desktopbrowser": { + "icon": "https://i.postimg.cc/sf9t34WF/icons8-duckduckgo-480.png", + "images": [ + "https://i.postimg.cc/WzbSNgRj/1.png", + "https://i.postimg.cc/mZ88dXMr/2.png", + "https://i.postimg.cc/65bbQj5P/3.jpg", + "https://i.postimg.cc/yxQjkxBR/4.jpg", + "https://i.postimg.cc/2SBGSCtq/5.png", + "https://i.postimg.cc/NfFbZ67k/6.png", + "https://i.postimg.cc/xCPtVg4t/7.jpg", + "https://i.postimg.cc/QM1f0jkL/8.jpg", + "https://i.postimg.cc/52ZPBXzq/9.jpg", + "https://i.postimg.cc/wjtfRX1j/10.jpg" + ] + }, + "primoramdisk": { + "icon": "https://i.postimg.cc/MK9V2cy1/ramd.png", + "images": [ + "https://i.postimg.cc/QdkLd3dg/image.png", + "https://i.postimg.cc/wMCK7xN2/image.png", + "https://i.postimg.cc/hGtSFj1Q/image.png", + "https://i.postimg.cc/3RP7DZ52/image.png" + ] + }, + "primocache": { + "icon": "https://i.postimg.cc/XJqr4x4W/ramdsk.png", + "images": [] + }, + "acdseephotostudio-ultimate": { + "icon": "https://i.postimg.cc/LXLxnYq5/acdsee-u.png", + "images": [] + }, + "acdseephotostudio-professional": { + "icon": "https://i.postimg.cc/QNT6zdfq/acdpro.png", + "images": [] + }, + "acdseephotostudio-home": { + "icon": "https://i.postimg.cc/50MJFRyc/acdhome.png", + "images": [] + }, + "acdsee-free": { + "icon": "https://i.postimg.cc/4NSpR4dS/acdsee-f.png", + "images": [] + }, + "simplestickynotes": { + "icon": "https://i.postimg.cc/QxjSZFnb/ssn.png", + "images": [ + "https://i.postimg.cc/65HVsYZW/image.png", + "https://i.postimg.cc/kgzxGGwL/image.png", + "https://i.postimg.cc/gk0RK8Tf/image.png", + "https://i.postimg.cc/BnrKsyn0/image.png", + "https://i.postimg.cc/Y93G6Cfr/image.png" + ] + }, + "bitreplica": { + "icon": "", + "images": [ + "https://i.postimg.cc/SQf17F0V/image.png", + "https://i.postimg.cc/t4Yrjssm/image.png", + "https://i.postimg.cc/HxC3X3Bf/image.png", + "https://i.postimg.cc/wvc2VJr3/image.png", + "https://i.postimg.cc/zvxjmN8r/image.png", + "https://i.postimg.cc/Y2R8L6gs/image.png", + "https://i.postimg.cc/CLK7GRsL/image.png" + ] + }, + "boostspeed": { + "icon": "", + "images": [ + "https://i.postimg.cc/rw09H7HB/image.png", + "https://i.postimg.cc/NfL8yWQK/image.png", + "https://i.postimg.cc/vZVWhfgM/image.png", + "https://i.postimg.cc/xdVL48Mm/image.png" + ] + }, + "driverupdater": { + "icon": "", + "images": [ + "https://i.postimg.cc/t4WxWbw4/image.png", + "https://i.postimg.cc/XvWygh6c/image.png", + "https://i.postimg.cc/s2JGHcVF/image.png", + "https://i.postimg.cc/85PJ2657/image.png", + "https://i.postimg.cc/SRHnY1G9/image.png" + ] + }, + "registrycleaner": { + "icon": "", + "images": [ + "https://i.postimg.cc/0Qbm6SqL/image.png", + "https://i.postimg.cc/KzwTtYG4/image.png", + "https://i.postimg.cc/wMNm2dM2/image.png" + ] + }, + "registrydefrag": { + "icon": "", + "images": [ + "https://i.postimg.cc/PJ1CZzVF/image.png", + "https://i.postimg.cc/1RFnLsRc/image.png", + "https://i.postimg.cc/X70GWmpM/image.png" + ] + }, + "ssdoptimizer": { + "icon": "", + "images": [ + "https://i.postimg.cc/8PBFz467/image.png", + "https://i.postimg.cc/K8G1kTPJ/image.png", + "https://i.postimg.cc/9fzz1jN9/image.png" + ] + }, + "videograbber": { + "icon": "", + "images": [ + "https://i.postimg.cc/RFHh5LmV/image.png", + "https://i.postimg.cc/RhxFMJC1/image.png", + "https://i.postimg.cc/6qVQT6Tk/image.png" + ] + }, + "windowsslimmer": { + "icon": "", + "images": [ + "https://i.postimg.cc/15Pt2Fjs/image.png", + "https://i.postimg.cc/28w6D5sv/image.png", + "https://i.postimg.cc/Njj0fctn/image.png" + ] + }, + "sqliteexpert-personal": { + "icon": "https://i.postimg.cc/KzGKLMhZ/SQLite-Exp.png", + "images": [ + "https://i.postimg.cc/02BpscR7/image.png", + "https://i.postimg.cc/rp6xdspm/image.png", + "https://i.postimg.cc/KzxTNWBh/image.png", + "https://i.postimg.cc/65yvYn2q/image.png" + ] + }, + "sqliteexpert-professional": { + "icon": "https://i.postimg.cc/KzGKLMhZ/SQLite-Exp.png", + "images": [ + "https://i.postimg.cc/02BpscR7/image.png", + "https://i.postimg.cc/rp6xdspm/image.png", + "https://i.postimg.cc/KzxTNWBh/image.png", + "https://i.postimg.cc/65yvYn2q/image.png" + ] + }, + "usbtrace": { + "icon": "https://i.postimg.cc/W3Px2rF7/usbt.png", + "images": [ + "https://i.postimg.cc/4dq77fGw/image.png", + "https://i.postimg.cc/nV9Q8DKW/image.png", + "https://i.postimg.cc/pXDhrM6Y/image.png", + "https://i.postimg.cc/W18dm6jd/image.png", + "https://i.postimg.cc/bvvsmDN3/image.png", + "https://i.postimg.cc/XJGX0R55/image.png" + ] + }, + "videopad": { + "icon": "", + "images": [ + "https://i.postimg.cc/vBs938kB/image.png" + ] + }, + "acdseegemstone": { + "icon": "https://i.postimg.cc/13tCz35b/gemstone.png", + "images": [] + }, + "darkthumbs": { + "icon": "https://i.postimg.cc/9Mmw1yHg/Dark-Thumbs-Icon.png", + "images": [ + "https://i.postimg.cc/m2tM03z0/image.png", + "https://i.postimg.cc/1526PgD4/image.png" + ] + }, + "vectorstyler": { + "icon": "https://i.postimg.cc/4yLJZhMd/vector.png", + "images": [ + "https://i.postimg.cc/vBvYqKt5/image.png", + "https://i.postimg.cc/pX407LTJ/image.png", + "https://i.postimg.cc/mkhwXvWn/image.png", + "https://i.postimg.cc/tJfzLBX4/image.png", + "https://i.postimg.cc/Jz8TmdNs/image.png", + "https://i.postimg.cc/2Sx05FG2/image.png", + "https://i.postimg.cc/FHhxwkvc/image.png" + ] + }, + "sysinternals-suite": { + "icon": "https://i.postimg.cc/FFWmY3WF/image.png", + "images": [ + "https://i.postimg.cc/NFMcNjMw/image.png" + ] + }, + "diffractor": { + "icon": "https://i.postimg.cc/0yFXFdkQ/diffractor.png", + "images": [ + "https://i.postimg.cc/sgXbtg5n/image.png" + ] + }, + "ritt": { + "icon": "https://i.postimg.cc/hPbQNKhh/ritt.png", + "images": [ + "https://i.postimg.cc/BZzK2mkQ/image.png", + "https://i.postimg.cc/Lss9CpZd/image.png", + "https://i.postimg.cc/nLNy4b4G/image.png", + "https://i.postimg.cc/W3MH0Dbs/image.png", + "https://i.postimg.cc/85BZjqt5/image.png", + "https://i.postimg.cc/fyqjdZXw/image.png", + "https://i.postimg.cc/3x1rFRNC/image.png" + ] + }, + "greatis-unhackme-stable": { + "icon": "", + "images": [ + "https://i.postimg.cc/0N0QG2MY/image.png", + "https://i.postimg.cc/FRPHqWx1/image.png" + ] + }, + "greatis-unhackme-beta": { + "icon": "", + "images": [ + "https://i.postimg.cc/0N0QG2MY/image.png", + "https://i.postimg.cc/FRPHqWx1/image.png" + ] + }, + "invisibleman-invisiblemanxray": { + "icon": "", + "images": [ + "https://i.postimg.cc/QMjxjYH3/image.png", + "https://i.postimg.cc/Dz5f0QXb/image.png" + ] + }, + "icofx": { + "icon": "", + "images": [ + "https://i.postimg.cc/B6drntMK/image.png", + "https://i.postimg.cc/66Zs1LpL/image.png", + "https://i.postimg.cc/hPGLtMQV/image.png", + "https://i.postimg.cc/G2qB0wQV/image.png", + "https://i.postimg.cc/Cxkzhf7j/image.png", + "https://i.postimg.cc/Z585tzYH/image.png" + ] + }, + "rapidraw": { + "icon": "https://i.postimg.cc/B6sDqSHn/rapidraw.png", + "images": [ + "https://i.postimg.cc/mgRm5s6B/image.png", + "https://i.postimg.cc/vTrWr1y9/image.png", + "https://i.postimg.cc/LXffSqn7/image.png", + "https://i.postimg.cc/j2tWrMVw/image.png", + "https://i.postimg.cc/NfLs23xG/image.png", + "https://i.postimg.cc/brnj3hV1/image.png" + ] + }, + "malcatlite": { + "icon": "https://i.postimg.cc/prh9r2bn/malcat-1.png", + "images": [ + "https://i.postimg.cc/9QtDr8S1/image.png", + "https://i.postimg.cc/3RWNfKwb/image.png", + "https://i.postimg.cc/Y0W9kbY6/image.png", + "https://i.postimg.cc/T2pt8SNz/image.png", + "https://i.postimg.cc/kMzf7ckB/image.png", + "https://i.postimg.cc/XY0LCvNW/image.png", + "https://i.postimg.cc/pdWBs1n1/image.png", + "https://i.postimg.cc/1zvr2cGR/image.png", + "https://i.postimg.cc/TwSqYdNZ/image.png" + ] + }, + "futuremarksysteminfo": { + "icon": "https://i.postimg.cc/q7FSWxjc/System-Info.png", + "images": [ + "https://i.postimg.cc/Y0HnwngF/image.png", + "https://i.postimg.cc/tJNrR3tM/image.png", + "https://i.postimg.cc/76V7fmd0/image.png" + ] + }, + "smartsdr": { + "icon": "", + "images": [ + "https://i.postimg.cc/NFCrXdnF/image.png", + "https://i.postimg.cc/7PtCmQBY/image.png", + "https://i.postimg.cc/jSPLqqRL/image.png", + "https://i.postimg.cc/Gpz39HVh/image.png", + "https://i.postimg.cc/nr9ndTzC/image.png", + "https://i.postimg.cc/J7sJVLHB/image.png", + "https://i.postimg.cc/NGZXQzRC/image.png", + "https://i.postimg.cc/zXWgvFjz/image.png" + ] + }, + "undertalemodtool": { + "icon": "https://i.postimg.cc/5txxVVtW/umt.png", + "images": [ + "https://i.postimg.cc/44zsmyhR/image.png", + "https://i.postimg.cc/nhLJR1Sn/image.png", + "https://i.postimg.cc/0Q7RMXj0/image.png", + "https://i.postimg.cc/TYdM196n/image.png", + "https://i.postimg.cc/PxW9rLV6/image.png" + ] + }, + "gimp-3": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/4/45/The_GIMP_icon_-_gnome.svg/316px-The_GIMP_icon_-_gnome.svg.png", + "images": [ + "https://docs.gimp.org/2.10/en/images/using/multi-window.png", + "https://i.sooftcdn.com/screen/en/windows/gimp-1.png", + "https://www.ionos.it/digitalguide/fileadmin/DigitalGuide/Screenshots_2021/screenshot-funktion-von-gimp.png" + ] + }, + "santedicomeditor": { + "icon": "", + "images": [ + "https://i.postimg.cc/1zKsSp7F/image.png", + "https://i.postimg.cc/mgYG3Ysn/image.png", + "https://i.postimg.cc/4y7DYtPB/image.png", + "https://i.postimg.cc/7P5h3WQQ/image.png", + "https://i.postimg.cc/k5h9Dn9M/image.png", + "https://i.postimg.cc/Dwx3Y2SQ/image.png" + ] + }, + "santedicomviewerlite": { + "icon": "", + "images": [ + "https://i.postimg.cc/J001PGqk/image.png" + ] + }, + "santedicomviewerpro": { + "icon": "", + "images": [] + }, + "santepacsserver": { + "icon": "", + "images": [] + }, + "santepacsserverpg": { + "icon": "", + "images": [] + }, + "smartalbums": { + "icon": "", + "images": [] + }, + "xreveal": { + "icon": "https://i.postimg.cc/3wBZCYSb/xreveal.png", + "images": [ + "https://i.postimg.cc/N0Sjnrzy/xreveal-status.png", + "https://i.postimg.cc/nzqpwSm5/xreveal-bd.png", + "https://i.postimg.cc/ZqBT655J/xreveal-general.png", + "https://i.postimg.cc/rpBqj2Dx/xreveal-hotkeys.png", + "https://i.postimg.cc/fTCTNPPQ/xreveal-mydiscs.png", + "https://i.postimg.cc/mgrZ2wxz/xreveal-mydrives.png", + "https://i.postimg.cc/0jxPgGdN/xreveal-rip2iso.png", + "https://i.postimg.cc/WznjsDXw/xreveal-ripping.png" + ] + }, + "ciemiddleware": { + "icon": "https://i.postimg.cc/52GCc4FP/cieid.png", + "images": [ + "https://i.postimg.cc/7YH70QkN/image.png" + ] + }, + "innounpacker": { + "icon": "https://i.postimg.cc/wMZfsXRL/innoun.png", + "images": [ + "https://i.postimg.cc/503WvRfv/image.png", + "https://i.postimg.cc/xT7DKHVs/image.png", + "https://i.postimg.cc/7L8FRk60/image.png", + "https://i.postimg.cc/4ydqc4Lk/image.png" + ] + }, + "xmlviewer": { + "icon": "https://i.postimg.cc/PxBVCbwZ/xmlv.png", + "images": [ + "https://i.postimg.cc/1RGr0Zxb/image.png", + "https://i.postimg.cc/kgpQMJ8R/image.png", + "https://i.postimg.cc/XJM9FssV/image.png" + ] + }, + "windowsfileanalyzer": { + "icon": "", + "images": [] + }, + "networkscanner": { + "icon": "https://i.postimg.cc/WbZTHyRJ/netscan.png", + "images": [ + "https://i.postimg.cc/QNKgSVZm/image.png", + "https://i.postimg.cc/50SZHp97/image.png", + "https://i.postimg.cc/NMWSzMGX/image.png", + "https://i.postimg.cc/DyysWcPS/image.png" + ] + }, + "innoextractor": { + "icon": "", + "images": [ + "https://i.postimg.cc/k5YWCpws/image.png", + "https://i.postimg.cc/gcZ394hy/image.png", + "https://i.postimg.cc/kMKRYGrf/image.png", + "https://i.postimg.cc/7ZWLZr85/image.png" + ] + }, + "dwgseecad": { + "icon": "https://i.postimg.cc/VNNmMGw3/dwgseecad.png", + "images": [] + }, + "dwgseepro": { + "icon": "https://i.postimg.cc/MH2CsdkZ/dwgseepro.png", + "images": [] + }, + "smbiosexplorer": { + "icon": "https://i.postimg.cc/SRRMv7c5/smbe.png", + "images": [ + "https://i.postimg.cc/tCRS9LzQ/image.png", + "https://i.postimg.cc/GpvJFQjx/image.png", + "https://i.postimg.cc/qR0cj3bV/image.png" + ] + }, + "netoptimizer": { + "icon": "https://i.postimg.cc/MKvWvrWN/Net-Optimizer.png", + "images": [ + "https://i.postimg.cc/sfPWTx7s/image.png", + "https://i.postimg.cc/bNztWP9b/image.png", + "https://i.postimg.cc/FsDLQ6T6/image.png", + "https://i.postimg.cc/dVfZhyPm/image.png", + "https://i.postimg.cc/nzbskfLX/image.png", + "https://i.postimg.cc/1Xyfk0wP/image.png" + ] + }, + "wise-registry-cleaner": { + "icon": "https://i.ibb.co/VYZ84Rt5/image.png", + "images": [] + }, + "wiseforcedeleter": { + "icon": "https://i.postimg.cc/T2rt6RM3/image.png", + "images": [ + "https://i.postimg.cc/15sJRLsc/image.png", + "https://i.postimg.cc/FHBXdwb8/image.png" + ] + }, + "wisejetsearch": { + "icon": "https://i.postimg.cc/VN2wT2dn/image.png", + "images": [ + "https://i.postimg.cc/jqHTggKn/image.png", + "https://i.postimg.cc/8PTSqRPK/image.png", + "https://i.postimg.cc/Yq8Hkvvp/image.png" + ] + }, + "netbakpcagent": { + "icon": "", + "images": [ + "https://i.postimg.cc/25mmfgYZ/image.png", + "https://i.postimg.cc/Qtd3F5HN/image.png", + "https://i.postimg.cc/HxvCXxyw/image.png", + "https://i.postimg.cc/qqtHLTs9/image.png", + "https://i.postimg.cc/PJBsVRKN/image.png", + "https://i.postimg.cc/tRfjgsyy/image.png" + ] + }, + "qvpnclient": { + "icon": "", + "images": [ + "https://i.postimg.cc/1td3PMJ1/image.png", + "https://i.postimg.cc/4dYhzY0Z/image.png", + "https://i.postimg.cc/cHPtTsq3/image.png", + "https://i.postimg.cc/C5DBQWYQ/image.png", + "https://i.postimg.cc/vHF6VHtF/image.png" + ] + }, + "winsecretplus": { + "icon": "", + "images": [] + }, + "exeexplorer": { + "icon": "https://i.postimg.cc/rmwhGyzS/exe.png", + "images": [ + "https://i.postimg.cc/d3Mys4ML/image.png", + "https://i.postimg.cc/GpH8vZd4/image.png", + "https://i.postimg.cc/pVD9QQbJ/image.png", + "https://i.postimg.cc/g0CJ8jg7/image.png", + "https://i.postimg.cc/fT8R5BHm/image.png", + "https://i.postimg.cc/QtgX7b9B/image.png", + "https://i.postimg.cc/3Jf32WRZ/image.png", + "https://i.postimg.cc/x8TSzSV7/image.png" + ] + }, + "hexedit": { + "icon": "https://i.postimg.cc/85fZXKB5/hexedit.png", + "images": [ + "https://i.postimg.cc/VNdg5GhR/image.png", + "https://i.postimg.cc/nLgkmKbt/image.png", + "https://i.postimg.cc/G2DjxBdT/image.png", + "https://i.postimg.cc/2j4wqB0P/image.png" + ] + }, + "iconexplorer": { + "icon": "https://i.postimg.cc/jSkQV6jJ/Icon-Explorer.png", + "images": [ + "https://i.postimg.cc/yxPcLc5x/image.png" + ] + }, + "infobar": { + "icon": "", + "images": [ + "https://i.postimg.cc/V69CNXzg/image.png", + "https://i.postimg.cc/C5Ffnd1g/image.png", + "https://i.postimg.cc/tJ2n3yZV/image.png", + "https://i.postimg.cc/2jwWRdc8/image.png", + "https://i.postimg.cc/Pr5wtL9b/image.png", + "https://i.postimg.cc/qMDCgJHP/image.png" + ] + }, + "jsonviewer": { + "icon": "", + "images": [] + }, + "networkmeter": { + "icon": "https://i.postimg.cc/1tYZwjR3/netmeter.png", + "images": [ + "https://i.postimg.cc/pdCvXdg8/image.png" + ] + }, + "harddisksentinel-professional": { + "icon": "", + "images": [ + "https://i.postimg.cc/76Zj3634/image.png", + "https://i.postimg.cc/zv9MYF9D/image.png", + "https://i.postimg.cc/Dy3kD2Fr/image.png", + "https://i.postimg.cc/7640dGsv/image.png", + "https://i.postimg.cc/k5m2grxK/image.png" + ] + }, + "harddisksentinel-standard": { + "icon": "", + "images": [ + "https://i.postimg.cc/76Zj3634/image.png", + "https://i.postimg.cc/zv9MYF9D/image.png", + "https://i.postimg.cc/Dy3kD2Fr/image.png", + "https://i.postimg.cc/7640dGsv/image.png", + "https://i.postimg.cc/k5m2grxK/image.png" + ] + }, + "antcommander-personal": { + "icon": "", + "images": [ + "https://i.postimg.cc/kXKNYSTQ/image.png", + "https://i.postimg.cc/CKFRNB2x/image.png", + "https://i.postimg.cc/50rjbP2X/image.png", + "https://i.postimg.cc/t7QTVYPy/image.png", + "https://i.postimg.cc/mk0cNmvv/image.png" + ] + }, + "antcommander-pro": { + "icon": "", + "images": [ + "https://i.postimg.cc/Gp7vTxpC/image.png", + "https://i.postimg.cc/C1RkGnZf/image.png", + "https://i.postimg.cc/FFJ01c5M/image.png", + "https://i.postimg.cc/yY4cRd7k/image.png", + "https://i.postimg.cc/XvJCWBkD/image.png", + "https://i.postimg.cc/fbr0RWHW/image.png" + ] + }, + "dnakitstudio": { + "icon": "https://i.postimg.cc/137CWYMW/dna.png", + "images": [ + "https://i.postimg.cc/76jrpZVW/image.png", + "https://i.postimg.cc/RCnBwwC5/image.png", + "https://i.postimg.cc/FHhXtqyN/image.png", + "https://i.postimg.cc/vBJC0S8R/image.png", + "https://i.postimg.cc/RVzjf8bK/image.png", + "https://i.postimg.cc/Prz0M4Bc/image.png" + ] + }, + "pinga": { + "icon": "https://i.postimg.cc/52T9Cz66/pinga.png", + "images": [ + "https://i.postimg.cc/qRnNRLwJ/image.png", + "https://i.postimg.cc/76MqdQX2/image.png", + "https://i.postimg.cc/Y0dMqG52/image.png" + ] + }, + "pingo": { + "icon": "", + "images": [ + "https://i.postimg.cc/yNDgqBSS/image.png" + ] + }, + "cterm": { + "icon": "", + "images": [ + "https://i.postimg.cc/vZJgdk7q/image.png", + "https://i.postimg.cc/FFTYK7gJ/image.png" + ] + }, + "hoppscotch": { + "icon": "https://raw.githubusercontent.com/hoppscotch/hoppscotch/main/packages/hoppscotch-common/public/icons/pwa-192x192.png", + "images": [ + "https://raw.githubusercontent.com/hoppscotch/hoppscotch/main/packages/hoppscotch-common/public/images/banner-dark.png" + ] + }, + "cryptostuff": { + "icon": "https://i.postimg.cc/xjwGFCh0/Crypto-Stuff.png", + "images": [ + "https://i.postimg.cc/W1jGTysC/image.png", + "https://i.postimg.cc/JhzjBBDQ/image.png", + "https://i.postimg.cc/76TGg1xS/image.png", + "https://i.postimg.cc/hvLXYSQj/image.png", + "https://i.postimg.cc/BQ3LK1R1/image.png", + "https://i.postimg.cc/Kv5Kr8yp/image.png" + ] + }, + "servy": { + "icon": "https://i.postimg.cc/25PF22gT/image.png", + "images": [ + "https://i.postimg.cc/d3FRKDsy/image.png" + ] + }, + "gesturesign": { + "icon": "https://i.postimg.cc/tCbHVPYs/image.png", + "images": [ + "https://i.postimg.cc/Jhx81h1s/image.png", + "https://i.postimg.cc/h45SzhVx/image.png", + "https://i.postimg.cc/dVvtvp8S/image.png", + "https://i.postimg.cc/gj8mbHrW/image.png", + "https://i.postimg.cc/L8HRGfpc/image.png" + ] + }, + "websitewatcher": { + "icon": "https://i.postimg.cc/rsRYp50F/wsw.png", + "images": [ + "https://i.postimg.cc/15cbVc7f/image.png", + "https://i.postimg.cc/gJgPhy2V/image.png", + "https://i.postimg.cc/ZYDSKLgZ/image.png", + "https://i.postimg.cc/BQLG8K9F/image.png", + "https://i.postimg.cc/0y7Rn1N2/image.png", + "https://i.postimg.cc/J0sSB9g8/image.png" + ] + }, + "websitewatcherfree": { + "icon": "https://i.postimg.cc/rsRYp50F/wsw.png", + "images": [ + "https://i.postimg.cc/MTCgVs8j/image.png", + "https://i.postimg.cc/gJgPhy2V/image.png", + "https://i.postimg.cc/ZYDSKLgZ/image.png", + "https://i.postimg.cc/BQLG8K9F/image.png", + "https://i.postimg.cc/0y7Rn1N2/image.png", + "https://i.postimg.cc/J0sSB9g8/image.png" + ] + }, + "nfsserver": { + "icon": "https://i.postimg.cc/Rh6wfGxf/nfsico.png", + "images": [ + "https://i.postimg.cc/g2q8vnQM/image.png", + "https://i.postimg.cc/FR1S5GRq/image.png", + "https://i.postimg.cc/76c2x7JL/image.png", + "https://i.postimg.cc/zDV6DRcY/image.png", + "https://i.postimg.cc/9XKSDF6R/image.png" + ] + }, + "dnsserver": { + "icon": "https://i.postimg.cc/wvdMxp9S/dnsico.png", + "images": [ + "https://i.postimg.cc/fW9Cg7Py/image.png", + "https://i.postimg.cc/zXNCtsW2/image.png", + "https://i.postimg.cc/Bb0KzF8P/image.png", + "https://i.postimg.cc/NM1yR0Ns/image.png" + ] + }, + "lldpagent": { + "icon": "https://i.postimg.cc/VLy83RLV/image.png", + "images": [ + "https://i.postimg.cc/Prctrj42/image.png", + "https://i.postimg.cc/1RdxDKqz/image.png", + "https://i.postimg.cc/V6HhBY5h/image.png", + "https://i.postimg.cc/1569tdjS/image.png" + ] + }, + "atlantiswordprocessorlite": { + "icon": "https://i.postimg.cc/zXV2wVqK/awp.png", + "images": [ + "https://i.postimg.cc/85fsBRXx/image.png" + ] + }, + "atlantiswordprocessor": { + "icon": "https://i.postimg.cc/zXV2wVqK/awp.png", + "images": [ + "https://i.postimg.cc/15rXH5MR/image.png", + "https://i.postimg.cc/Gm32SwSF/image.png", + "https://i.postimg.cc/52DhQ8vX/image.png" + ] + }, + "elcomsoftupdater": { + "icon": "https://i.postimg.cc/d0pGYtbP/UPD.png", + "images": [ + "https://i.postimg.cc/pTmkfSHx/image.png" + ] + }, + "jetscreenshot": { + "icon": "", + "images": [ + "https://i.postimg.cc/FKLKd3Pz/image.png", + "https://i.postimg.cc/zBYGnvMj/image.png", + "https://i.postimg.cc/15XsVDXS/image.png", + "https://i.postimg.cc/Kv1h8Fpv/image.png", + "https://i.postimg.cc/15bhgTb0/image.png" + ] + }, + "rcloneui": { + "icon": "https://i.postimg.cc/pXHmqzQj/image.png", + "images": [ + "https://i.postimg.cc/dtPypzFL/image.png", + "https://i.postimg.cc/xTvz2tjg/image.png", + "https://i.postimg.cc/XYny7dpW/image.png" + ] + }, + "alterphoto": { + "icon": "", + "images": [ + "https://i.postimg.cc/BZcSZyD8/image.png", + "https://i.postimg.cc/7YHx5VMK/image.png", + "https://i.postimg.cc/X7sndCs4/image.png", + "https://i.postimg.cc/YCjM3CPg/image.png", + "https://i.postimg.cc/cHGW0MLM/image.png", + "https://i.postimg.cc/J01WBrJs/image.png", + "https://i.postimg.cc/GtqnFWJq/image.png", + "https://i.postimg.cc/Qt86QH4Z/image.png" + ] + }, + "wondershare-filmora": { + "icon": "https://i.postimg.cc/dt1TdfW7/wondershare-1746013641.png", + "images": [ + "https://i.postimg.cc/xd49wsvM/step2-pic.png" + ] + }, + "xp89dcgq3k6vld": { + "icon": "https://i.postimg.cc/yYZ3vRzc/image.png", + "images": [ + "https://i.postimg.cc/KjdjH0cp/pt1.png", + "https://i.postimg.cc/KYZzwkFb/pt2.png", + "https://i.postimg.cc/x1VqGp4c/pt3.png", + "https://i.postimg.cc/XYKqsKRx/pt4.png" + ] + }, + "guru3d-afterburner": { + "icon": "https://i.postimg.cc/nzfnVXWr/images.jpg", + "images": [ + "https://i.postimg.cc/43bStnd5/msi-afterburner.png" + ] + }, + "guru3d-rtss": { + "icon": "https://i.postimg.cc/mD9NM5V0/rivatuner-thumb-megaupp.png", + "images": [ + "https://i.postimg.cc/2jFnDvtB/2021-02-18-ts3-thumbs-831.png" + ] + }, + "wargaming-gamecenter": { + "icon": "https://i.postimg.cc/tgkHbBFv/Wargaming-Game-Cente2.png", + "images": [ + "https://i.postimg.cc/nhVykvyB/809-07.png", + "https://i.postimg.cc/X7Lhprrr/808-2.png" + ] + }, + "sandisk-dashboard": { + "icon": "https://i.postimg.cc/MG5XLbHW/sandisk-dashboard-icon.png", + "images": [ + "https://i.postimg.cc/J062YgV0/78-BA0-CB7-1-B00-4-F4-B-91-D3-36392-FC6572-B.png" + ] + }, + "ubuntu": { + "icon": "https://i.postimg.cc/T3kT1MCf/image.png", + "images": [] + }, + "cursorworkshop": { + "icon": "https://i.postimg.cc/pXkWntjc/curwork.png", + "images": [ + "https://i.postimg.cc/sX37KrnB/image.png" + ] + }, + "icongenerator": { + "icon": "", + "images": [ + "https://i.postimg.cc/NMPFTqZw/image.png" + ] + }, + "iconvectors": { + "icon": "", + "images": [ + "https://i.postimg.cc/t7GXtXkP/image.png", + "https://i.postimg.cc/k5JgpgmM/image.png", + "https://i.postimg.cc/SsjNm1jy/image.png", + "https://i.postimg.cc/fL63pQ5h/image.png" + ] + }, + "screensaverproducer": { + "icon": "https://i.postimg.cc/LsLGLz7x/scrnprod.png", + "images": [ + "https://i.postimg.cc/3N1TpgkV/image.png", + "https://i.postimg.cc/tCrb4NQP/image.png", + "https://i.postimg.cc/PqDnKGLQ/image.png", + "https://i.postimg.cc/sX9ddp4C/image.png", + "https://i.postimg.cc/sxjFVvTw/image.png" + ] + }, + "kyno": { + "icon": "https://i.postimg.cc/FR3Z7svR/kyno.png", + "images": [] + }, + "dnslookupview": { + "icon": "https://i.postimg.cc/2SjdDPQy/image.png", + "images": [ + "https://i.postimg.cc/T3j7Mm4s/image.png" + ] + }, + "pellesc": { + "icon": "https://i.postimg.cc/dV1TgSZ1/pelles.png", + "images": [ + "https://i.postimg.cc/ZKqRqvb8/image.png", + "https://i.postimg.cc/vZJHXPrF/image.png", + "https://i.postimg.cc/sxH3WKjG/image.png", + "https://i.postimg.cc/DyD2yCpM/image.png", + "https://i.postimg.cc/25dmGCjR/image.png", + "https://i.postimg.cc/FRDvtGJ6/image.png", + "https://i.postimg.cc/NGCtpJtF/image.png", + "https://i.postimg.cc/9QZjXc7w/image.png" + ] + }, + "gifmoviegear": { + "icon": "https://i.postimg.cc/MTcC4xqv/movgear.png", + "images": [ + "https://i.postimg.cc/k4dNrvdN/image.png", + "https://i.postimg.cc/90gqfGvm/image.png", + "https://i.postimg.cc/T3gp8M2c/image.png" + ] + }, + "navicatbiviewer": { + "icon": "https://i.postimg.cc/MH1KC1qc/navicatbiv.png", + "images": [ + "https://i.postimg.cc/76WmFTmr/image.png", + "https://i.postimg.cc/sftRSBsr/image.png", + "https://i.postimg.cc/5tNc1LqL/image.png" + ] + }, + "navicatbi": { + "icon": "https://i.postimg.cc/BQZr9xqR/navicatbi.png", + "images": [ + "https://i.postimg.cc/pTqBD5gT/image.png", + "https://i.postimg.cc/y6pPx9hq/image.png", + "https://i.postimg.cc/d0FRp9FL/image.png", + "https://i.postimg.cc/W3bGbbhj/image.png", + "https://i.postimg.cc/8c7LMKdG/image.png" + ] + }, + "pixplant": { + "icon": "https://i.postimg.cc/hjP8sbWs/PixPlant.png", + "images": [ + "https://i.postimg.cc/VvZKnZJC/image.png", + "https://i.postimg.cc/T2t7z1tn/image.png", + "https://i.postimg.cc/vHjPmjRS/image.png", + "https://i.postimg.cc/VLT7NTQC/image.png", + "https://i.postimg.cc/7Z2KJVws/image.png", + "https://i.postimg.cc/1z0MJ3g1/image.png" + ] + }, + "softroslanmessenger": { + "icon": "https://i.postimg.cc/DwPBcz4T/smm.png", + "images": [ + "https://i.postimg.cc/gk9sFhvw/image.png", + "https://i.postimg.cc/XY4gX0HT/image.png", + "https://i.postimg.cc/g00qqHP6/image.png", + "https://i.postimg.cc/Bvw5hPSZ/image.png", + "https://i.postimg.cc/HxqwmG8B/image.png", + "https://i.postimg.cc/9FjdNhhV/image.png" + ] + }, + "dbschema": { + "icon": "https://i.postimg.cc/wT7pPSQ3/DbSchema.png", + "images": [ + "https://i.postimg.cc/QCCR2T5v/image.png", + "https://i.postimg.cc/c4VVz6Jn/image.png", + "https://i.postimg.cc/vmyCQjf6/image.png", + "https://i.postimg.cc/DZyDGXCZ/image.png", + "https://i.postimg.cc/90Dn8j5L/image.png", + "https://i.postimg.cc/L4W7qhLQ/image.png", + "https://i.postimg.cc/k57hrSPV/image.png" + ] + }, + "fasm": { + "icon": "https://i.postimg.cc/gkHr44mX/fasm.png", + "images": [ + "https://i.postimg.cc/sDmD5X40/image.png", + "https://i.postimg.cc/DwDhcbJm/image.png" + ] + }, + "axisdevicecompatibilitytool": { + "icon": "", + "images": [ + "https://i.postimg.cc/sDx7Btpj/image.png" + ] + }, + "hotalarmclock": { + "icon": "", + "images": [ + "https://i.postimg.cc/mrkgVsgw/image.png", + "https://i.postimg.cc/Y0K2pLf4/image.png", + "https://i.postimg.cc/fRTzTNX5/image.png", + "https://i.postimg.cc/Y9gkyqKj/image.png" + ] + }, + "httpanalyzer": { + "icon": "https://i.postimg.cc/mgvH5jt1/httpanal.png", + "images": [ + "https://i.postimg.cc/tT27pNC3/image.png", + "https://i.postimg.cc/wTSMqvgH/image.png", + "https://i.postimg.cc/gc7ksJw0/image.png", + "https://i.postimg.cc/dtTQxYrK/image.png", + "https://i.postimg.cc/1zy9XVTS/image.png", + "https://i.postimg.cc/XJJ4cS4P/image.png" + ] + }, + "connectionqualitymonitor": { + "icon": "https://i.postimg.cc/Jh3rzYFm/image.png", + "images": [ + "https://i.postimg.cc/Px2dmpTH/image.png", + "https://i.postimg.cc/QCzsy2Fp/image.png" + ] + }, + "netgenius": { + "icon": "https://i.postimg.cc/yNTKHgJS/image.png", + "images": [ + "https://i.postimg.cc/Sx6F62fW/image.png", + "https://i.postimg.cc/XqGtppvD/image.png", + "https://i.postimg.cc/v84mWhgK/image.png" + ] + }, + "bandwidthmanager": { + "icon": "https://i.postimg.cc/XY7mCHXZ/image.png", + "images": [ + "https://i.postimg.cc/7L5RB53Z/image.png", + "https://i.postimg.cc/XJFzbt1c/image.png", + "https://i.postimg.cc/Hn9vJXgy/image.png", + "https://i.postimg.cc/15MYsGMh/image.png", + "https://i.postimg.cc/cJtDRVSz/image.png" + ] + }, + "connectionemulator": { + "icon": "https://i.postimg.cc/tJkDRb3S/image.png", + "images": [ + "https://i.postimg.cc/NM7kbtzt/image.png" + ] + }, + "ramdisk": { + "icon": "https://i.postimg.cc/zvGKjghB/image.png", + "images": [ + "https://i.postimg.cc/3Nq4Fb7s/image.png", + "https://i.postimg.cc/SNXzxqfN/image.png", + "https://i.postimg.cc/Z5pB6cgZ/image.png" + ] + }, + "switchportmapper": { + "icon": "https://i.postimg.cc/13GX8znf/image.png", + "images": [ + "https://i.postimg.cc/XvxvgDks/image.png", + "https://i.postimg.cc/G25hW8Nx/image.png" + ] + }, + "Winget.SoftPerfect.WiFiGuard": { + "icon": "https://i.postimg.cc/5Nxbsm6W/image.png", + "images": [ + "https://i.postimg.cc/43hgYLFm/image.png" + ] + }, + "Winget.SoftPerfect.NetworkScanner": { + "icon": "https://i.postimg.cc/brmMCkF7/image.png", + "images": [ + "https://i.postimg.cc/Fsn80bS3/image.png", + "https://i.postimg.cc/2SbJGqFS/image.png", + "https://i.postimg.cc/5t8rcZRh/image.png", + "https://i.postimg.cc/B6sVJmW8/image.png" + ] + }, + "cacherelocator": { + "icon": "https://i.postimg.cc/jS8RBnBZ/image.png", + "images": [ + "https://i.postimg.cc/Pq9T5sXY/image.png" + ] + }, + "zed": { + "icon": "https://i.postimg.cc/qgVTHhyZ/zed.png", + "images": [ + "https://i.postimg.cc/cLWvQ62b/image.png", + "https://i.postimg.cc/Zq70tHnz/image.png", + "https://i.postimg.cc/Y2m0Z1wb/image.png", + "https://i.postimg.cc/3R0rMHzK/image.png" + ] + }, + "zed-preview": { + "icon": "https://i.postimg.cc/8zd1DHyx/zed-prev.png", + "images": [ + "https://i.postimg.cc/cLWvQ62b/image.png", + "https://i.postimg.cc/Zq70tHnz/image.png", + "https://i.postimg.cc/Y2m0Z1wb/image.png", + "https://i.postimg.cc/3R0rMHzK/image.png" + ] + }, + "worldmap": { + "icon": "", + "images": [ + "https://i.postimg.cc/c4yGFzZd/image.png", + "https://i.postimg.cc/05C04M1f/image.png", + "https://i.postimg.cc/rwVbbXHc/image.png", + "https://i.postimg.cc/CLFmMCsj/image.png", + "https://i.postimg.cc/Df51g91G/image.png" + ] + }, + "bluelifehostseditor": { + "icon": "https://i.postimg.cc/pdzPVtP0/hostedit.png", + "images": [ + "https://i.postimg.cc/cCjRc3P6/image.png", + "https://i.postimg.cc/htYk7Z2Y/image.png", + "https://i.postimg.cc/8Crqdd3w/image.png", + "https://i.postimg.cc/0jZ35V6C/image.png", + "https://i.postimg.cc/hPywH3RP/image.png", + "https://i.postimg.cc/6pFPQ235/image.png" + ] + }, + "hibernateenableordisable": { + "icon": "https://i.postimg.cc/BvrtNgvf/hibernate.png", + "images": [ + "https://i.postimg.cc/V6fWsmXp/image.png", + "https://i.postimg.cc/4yh7sS2D/image.png", + "https://i.postimg.cc/ZY9VWYGF/image.png", + "https://i.postimg.cc/Njxx3KHp/image.png", + "https://i.postimg.cc/50XqQpkS/image.png" + ] + }, + "folderpainter": { + "icon": "https://i.postimg.cc/7YTVPxCL/Folder-Painter.png", + "images": [ + "https://i.postimg.cc/htL1xp1n/image.png", + "https://i.postimg.cc/jjv63217/image.png", + "https://i.postimg.cc/qRRsP0Vp/image.png", + "https://i.postimg.cc/2yL45wSJ/image.png", + "https://i.postimg.cc/59DrSKvT/image.png" + ] + }, + "logonexpert": { + "icon": "https://i.postimg.cc/bwwjxDYk/logonexpert.png", + "images": [ + "https://i.postimg.cc/htdXq5xN/image.png", + "https://i.postimg.cc/50xyL9rs/image.png", + "https://i.postimg.cc/85t5HQQc/image.png", + "https://i.postimg.cc/nrWhy4hg/image.png", + "https://i.postimg.cc/L4Q5gp3c/image.png", + "https://i.postimg.cc/mgCgnFfY/image.png" + ] + }, + "logonexpert-server": { + "icon": "https://i.postimg.cc/bwwjxDYk/logonexpert.png", + "images": [ + "https://i.postimg.cc/1tc61Ykk/image.png", + "https://i.postimg.cc/6qMvy45c/image.png", + "https://i.postimg.cc/bNvn4g3Q/image.png", + "https://i.postimg.cc/3JbGhGqd/image.png", + "https://i.postimg.cc/8z2rJSDx/image.png", + "https://i.postimg.cc/bJ8Dg9Zm/image.png", + "https://i.postimg.cc/Kjp1ZXJP/image.png" + ] + }, + "networktimesystem-server": { + "icon": "https://i.postimg.cc/XYjns1L9/ntsclient.png", + "images": [] + }, + "networktimesystem-client": { + "icon": "https://i.postimg.cc/XYjns1L9/ntsclient.png", + "images": [] + }, + "transparentlockscreen": { + "icon": "", + "images": [] + }, + "airequester": { + "icon": "https://vovsoft.com/icons128/ai-requester.png", + "images": [ + "https://vovsoft.com/screenshots/ai-requester.png", + "https://vovsoft.com/screenshots/ai-requester-2.png", + "https://vovsoft.com/screenshots/ai-requester-3.png", + "https://vovsoft.com/screenshots/ai-requester-4.png", + "https://vovsoft.com/screenshots/ai-requester-5.png", + "https://vovsoft.com/screenshots/ai-requester-6.png" + ] + }, + "autochangescreensavers": { + "icon": "https://vovsoft.com/icons128/auto-change-screensavers.png", + "images": [ + "https://vovsoft.com/screenshots/auto-change-screensavers.png" + ] + }, + "automouseclicker": { + "icon": "https://vovsoft.com/icons64/auto-mouse-clicker.png", + "images": [ + "https://i.postimg.cc/v8W83Tjm/image.png" + ] + }, + "batchaudioconverter": { + "icon": "https://vovsoft.com/icons128/batch-audio-converter.png", + "images": [ + "https://vovsoft.com/screenshots/batch-audio-converter.png" + ] + }, + "Winget.VovSoft.BatchImageResizer": { + "icon": "https://vovsoft.com/icons64/batch-image-resizer.png", + "images": [ + "https://vovsoft.com/screenshots/batch-image-resizer.png", + "https://vovsoft.com/screenshots/batch-image-resizer-2.png", + "https://vovsoft.com/screenshots/batch-image-resizer-3.png", + "https://vovsoft.com/screenshots/batch-image-resizer-4.png" + ] + }, + "batchimageupscaler": { + "icon": "https://vovsoft.com/icons128/batch-image-upscaler.png", + "images": [ + "https://i.postimg.cc/XJt8JQ3S/image.png" + ] + }, + "batchtranslator": { + "icon": "https://vovsoft.com/icons64/batch-translator.png", + "images": [ + "https://vovsoft.com/screenshots/batch-translator.png", + "https://vovsoft.com/screenshots/batch-translator-2.png", + "https://vovsoft.com/screenshots/batch-translator-3.png", + "https://vovsoft.com/screenshots/batch-translator-4.png" + ] + }, + "batchurldownloader": { + "icon": "https://vovsoft.com/icons64/batch-url-downloader.png", + "images": [ + "https://vovsoft.com/screenshots/batch-url-downloader.png", + "https://vovsoft.com/screenshots/batch-url-downloader-2.png", + "https://vovsoft.com/screenshots/batch-url-downloader-3.png", + "https://vovsoft.com/screenshots/batch-url-downloader-4.png", + "https://vovsoft.com/screenshots/batch-url-downloader-5.png", + "https://vovsoft.com/screenshots/batch-url-downloader-6.png" + ] + }, + "batchvideoupscaler": { + "icon": "https://vovsoft.com/icons128/batch-video-upscaler.png", + "images": [ + "https://vovsoft.com/screenshots/batch-video-upscaler.png" + ] + }, + "brokenlinkdetector": { + "icon": "https://vovsoft.com/icons128/broken-link-detector.png", + "images": [ + "https://i.postimg.cc/mkDsLZLT/image.png" + ] + }, + "bulkbarcodegenerator": { + "icon": "https://vovsoft.com/icons128/bulk-barcode-generator.png", + "images": [ + "https://vovsoft.com/screenshots/bulk-barcode-generator.png" + ] + }, + "bulkdomainappraisal": { + "icon": "https://vovsoft.com/icons64/bulk-domain-appraisal.png", + "images": [ + "https://vovsoft.com/screenshots/bulk-domain-appraisal.png", + "https://vovsoft.com/screenshots/bulk-domain-appraisal-2.png", + "https://vovsoft.com/screenshots/bulk-domain-appraisal-3.png", + "https://vovsoft.com/screenshots/bulk-domain-appraisal-4.png" + ] + }, + "bulkqrcodegenerator": { + "icon": "https://vovsoft.com/icons128/bulk-qr-code-generator.png", + "images": [ + "https://vovsoft.com/screenshots/bulk-qr-code-generator.png", + "https://vovsoft.com/screenshots/bulk-qr-code-generator-2.png", + "https://vovsoft.com/screenshots/bulk-qr-code-generator-3.png", + "https://vovsoft.com/screenshots/bulk-qr-code-generator-4.png", + "https://vovsoft.com/screenshots/bulk-qr-code-generator-5.png" + ] + }, + "cpubenchmark": { + "icon": "https://vovsoft.com/icons128/cpu-benchmark.png", + "images": [ + "https://vovsoft.com/screenshots/cpu-benchmark.png" + ] + }, + "csvsplitter": { + "icon": "https://vovsoft.com/icons64/csv-splitter.png", + "images": [ + "https://i.postimg.cc/kGdTsfHZ/image.png" + ] + }, + "csvtojsonconverter": { + "icon": "https://vovsoft.com/icons128/csv-to-json-converter.png", + "images": [ + "https://i.postimg.cc/pTKZmKdJ/image.png" + ] + }, + "csvtovcfconverter": { + "icon": "https://vovsoft.com/icons64/csv-to-vcf-converter.png", + "images": [ + "https://vovsoft.com/screenshots/csv-to-vcf-converter.png", + "https://vovsoft.com/screenshots/csv-to-vcf-converter-2.png", + "https://vovsoft.com/screenshots/csv-to-vcf-converter-3.png" + ] + }, + "clipboardreader": { + "icon": "https://vovsoft.com/icons128/clipboard-reader.png", + "images": [ + "https://i.postimg.cc/jqXHBxnb/image.png" + ] + }, + "collecturl": { + "icon": "https://vovsoft.com/icons64/collect-url.png", + "images": [ + "https://vovsoft.com/screenshots/collect-url.png" + ] + }, + "comparetwotexts": { + "icon": "https://vovsoft.com/icons128/compare-two-texts.png", + "images": [ + "https://vovsoft.com/screenshots/compare-two-texts.png", + "https://vovsoft.com/screenshots/compare-two-texts-2.png" + ] + }, + "contactmanager": { + "icon": "https://vovsoft.com/icons128/contact-manager.png", + "images": [ + "https://i.postimg.cc/gjTndTPv/image.png" + ] + }, + "containerloadingcalculator": { + "icon": "https://vovsoft.com/icons64/container-loading-calculator.png", + "images": [ + "https://vovsoft.com/screenshots/container-loading-calculator.png" + ] + }, + "convertvideotoaudio": { + "icon": "https://vovsoft.com/icons128/convert-video-to-audio.png", + "images": [ + "https://i.postimg.cc/mZJLLMHv/image.png" + ] + }, + "copyfilesintomultiplefolders": { + "icon": "https://vovsoft.com/icons64/copy-files-into-multiple-folders.png", + "images": [ + "https://i.postimg.cc/y8PW8xB4/image.png", + "https://vovsoft.com/screenshots/copy-files-into-multiple-folders-2.png", + "https://vovsoft.com/screenshots/copy-files-into-multiple-folders-3.png", + "https://vovsoft.com/screenshots/copy-files-into-multiple-folders-4.png", + "https://vovsoft.com/screenshots/copy-files-into-multiple-folders-5.png" + ] + }, + "createimagegallery": { + "icon": "https://vovsoft.com/icons64/create-image-gallery.png", + "images": [ + "https://vovsoft.com/screenshots/create-image-gallery.png", + "https://vovsoft.com/screenshots/create-image-gallery-2.png" + ] + }, + "cryptocurrencytracker": { + "icon": "https://vovsoft.com/icons64/cryptocurrency-tracker.png", + "images": [ + "https://vovsoft.com/screenshots/cryptocurrency-tracker.png", + "https://vovsoft.com/screenshots/cryptocurrency-tracker-2.png", + "https://vovsoft.com/screenshots/cryptocurrency-tracker-3.png", + "https://vovsoft.com/screenshots/cryptocurrency-tracker-4.png", + "https://vovsoft.com/screenshots/cryptocurrency-tracker-5.png" + ] + }, + "desktopdiary": { + "icon": "https://vovsoft.com/icons64/desktop-diary.png", + "images": [ + "https://vovsoft.com/screenshots/desktop-diary.png", + "https://vovsoft.com/screenshots/desktop-diary-2.png", + "https://vovsoft.com/screenshots/desktop-diary-3.png", + "https://vovsoft.com/screenshots/desktop-diary-4.png", + "https://vovsoft.com/screenshots/desktop-diary-5.png" + ] + }, + "Winget.VovSoft.DirectoryMonitor": { + "icon": "https://vovsoft.com/icons128/directory-monitor.png", + "images": [ + "https://vovsoft.com/screenshots/directory-monitor.png", + "https://vovsoft.com/screenshots/directory-monitor-2.png", + "https://vovsoft.com/screenshots/directory-monitor-3.png", + "https://vovsoft.com/screenshots/directory-monitor-4.png" + ] + }, + "diskmonitorgadget": { + "icon": "https://vovsoft.com/icons64/disk-monitor-gadget.png", + "images": [ + "https://vovsoft.com/screenshots/disk-monitor-gadget.png" + ] + }, + "documentmanager": { + "icon": "https://vovsoft.com/icons64/document-manager.png", + "images": [ + "https://vovsoft.com/screenshots/document-manager.png", + "https://vovsoft.com/screenshots/document-manager-2.png", + "https://vovsoft.com/screenshots/document-manager-3.png", + "https://vovsoft.com/screenshots/document-manager-4.png" + ] + }, + "domainchecker": { + "icon": "https://vovsoft.com/icons64/domain-checker.png", + "images": [ + "https://vovsoft.com/screenshots/domain-checker.png", + "https://vovsoft.com/screenshots/domain-checker-2.png", + "https://vovsoft.com/screenshots/domain-checker-3.png", + "https://vovsoft.com/screenshots/domain-checker-4.png", + "https://vovsoft.com/screenshots/domain-checker-5.png", + "https://vovsoft.com/screenshots/domain-checker-6.png" + ] + }, + "downloadmailboxemails": { + "icon": "https://vovsoft.com/icons64/download-mailbox-emails.png", + "images": [ + "https://vovsoft.com/screenshots/download-mailbox-emails.png", + "https://vovsoft.com/screenshots/download-mailbox-emails-2.png", + "https://vovsoft.com/screenshots/download-mailbox-emails-3.png", + "https://vovsoft.com/screenshots/download-mailbox-emails-4.png" + ] + }, + "Winget.VovSoft.DuplicateFileFinder": { + "icon": "https://vovsoft.com/icons64/duplicate-file-finder.png", + "images": [ + "https://vovsoft.com/screenshots/duplicate-file-finder.png" + ] + }, + "emlconverter": { + "icon": "https://vovsoft.com/icons128/eml-converter.png", + "images": [ + "https://vovsoft.com/screenshots/eml-converter.png" + ] + }, + "executablebitscanner": { + "icon": "https://vovsoft.com/icons128/executable-bit-scanner.png", + "images": [ + "https://vovsoft.com/screenshots/executable-bit-scanner.png" + ] + }, + "externallinkdetector": { + "icon": "https://vovsoft.com/icons128/external-link-detector.png", + "images": [ + "https://vovsoft.com/screenshots/external-link-detector.png" + ] + }, + "facedetector": { + "icon": "https://vovsoft.com/icons128/face-detector.png", + "images": [ + "https://vovsoft.com/screenshots/face-detector.png", + "https://vovsoft.com/screenshots/face-detector-2.png", + "https://vovsoft.com/screenshots/face-detector-3.png" + ] + }, + "filechecksumcalculator": { + "icon": "https://vovsoft.com/icons64/file-checksum-calculator.png", + "images": [ + "https://vovsoft.com/screenshots/file-checksum-calculator.png", + "https://vovsoft.com/screenshots/file-checksum-calculator-2.png", + "https://vovsoft.com/screenshots/file-checksum-calculator-3.png" + ] + }, + "filesplitterandjoiner": { + "icon": "https://vovsoft.com/icons64/file-splitter-and-joiner.png", + "images": [ + "https://vovsoft.com/screenshots/file-splitter-and-joiner.png" + ] + }, + "filenamelister": { + "icon": "https://vovsoft.com/icons64/filename-lister.png", + "images": [ + "https://vovsoft.com/screenshots/filename-lister.png" + ] + }, + "findandreplacemultiplefiles": { + "icon": "https://vovsoft.com/icons64/find-and-replace-multiple-files.png", + "images": [ + "https://i.postimg.cc/pXv0FW3X/image.png" + ] + }, + "foldersplitter": { + "icon": "https://vovsoft.com/icons128/folder-splitter.png", + "images": [ + "https://i.postimg.cc/rwmN1Kjy/image.png" + ] + }, + "htmlstripper": { + "icon": "https://vovsoft.com/icons128/html-stripper.png", + "images": [ + "https://vovsoft.com/screenshots/html-stripper.png", + "https://vovsoft.com/screenshots/html-stripper-2.png", + "https://vovsoft.com/screenshots/html-stripper-3.png" + ] + }, + "httprequester": { + "icon": "https://vovsoft.com/icons128/http-requester.png", + "images": [ + "https://vovsoft.com/screenshots/http-requester.png", + "https://vovsoft.com/screenshots/http-requester-2.png", + "https://vovsoft.com/screenshots/http-requester-3.png", + "https://vovsoft.com/screenshots/http-requester-4.png" + ] + }, + "healthbreakreminder": { + "icon": "https://vovsoft.com/icons128/health-break-reminder.png", + "images": [ + "https://vovsoft.com/screenshots/health-break-reminder.png" + ] + }, + "hexviewer": { + "icon": "https://vovsoft.com/icons128/hex-viewer.png", + "images": [ + "https://vovsoft.com/screenshots/hex-viewer.png" + ] + }, + "hidefiles": { + "icon": "https://vovsoft.com/icons128/hide-files.png", + "images": [ + "https://vovsoft.com/screenshots/hide-files.png", + "https://vovsoft.com/screenshots/hide-files-2.png", + "https://vovsoft.com/screenshots/hide-files-3.png", + "https://vovsoft.com/screenshots/hide-files-4.png", + "https://vovsoft.com/screenshots/hide-files-5.png" + ] + }, + "hierarchicalfilemanager": { + "icon": "https://vovsoft.com/icons128/hierarchical-file-manager.png", + "images": [ + "https://vovsoft.com/screenshots/hierarchical-file-manager.png" + ] + }, + "imagecombiner": { + "icon": "https://vovsoft.com/icons64/image-combiner.png", + "images": [ + "https://vovsoft.com/screenshots/image-combiner.png", + "https://vovsoft.com/screenshots/image-combiner-2.png", + "https://vovsoft.com/screenshots/image-combiner-3.png" + ] + }, + "imagepixelator": { + "icon": "https://vovsoft.com/icons128/image-pixelator.png", + "images": [ + "https://vovsoft.com/screenshots/image-pixelator.png" + ] + }, + "imagesplitter": { + "icon": "https://vovsoft.com/icons128/image-splitter.png", + "images": [ + "https://vovsoft.com/screenshots/image-splitter.png", + "https://vovsoft.com/screenshots/image-splitter-2.png", + "https://vovsoft.com/screenshots/image-splitter-3.png", + "https://vovsoft.com/screenshots/image-splitter-4.png" + ] + }, + "imagetocartoonconverter": { + "icon": "https://vovsoft.com/icons128/image-to-cartoon-converter.png", + "images": [ + "https://vovsoft.com/screenshots/image-to-cartoon-converter.png" + ] + }, + "jsonbeautifier": { + "icon": "https://vovsoft.com/icons128/json-beautifier.png", + "images": [ + "https://vovsoft.com/screenshots/json-beautifier.png" + ] + }, + "jsontocsvconverter": { + "icon": "https://vovsoft.com/icons128/json-to-csv-converter.png", + "images": [ + "https://i.postimg.cc/7ZWd0vgF/image.png" + ] + }, + "keepsoftwarealive": { + "icon": "https://vovsoft.com/icons64/keep-software-alive.png", + "images": [ + "https://vovsoft.com/screenshots/keep-software-alive.png" + ] + }, + "keyboardlights": { + "icon": "https://vovsoft.com/icons128/keyboard-lights.png", + "images": [ + "https://vovsoft.com/screenshots/keyboard-lights.png", + "https://vovsoft.com/screenshots/keyboard-lights-2.png", + "https://vovsoft.com/screenshots/keyboard-lights-3.png", + "https://vovsoft.com/screenshots/keyboard-lights-4.png" + ] + }, + "keyboardsoundboard": { + "icon": "https://vovsoft.com/icons128/keyboard-soundboard.png", + "images": [ + "https://vovsoft.com/screenshots/keyboard-soundboard.png", + "https://vovsoft.com/screenshots/keyboard-soundboard-2.png", + "https://vovsoft.com/screenshots/keyboard-soundboard-3.png", + "https://vovsoft.com/screenshots/keyboard-soundboard-4.png" + ] + }, + "keystrokevisualizer": { + "icon": "https://vovsoft.com/icons64/keystroke-visualizer.png", + "images": [ + "https://vovsoft.com/screenshots/keystroke-visualizer.png", + "https://vovsoft.com/screenshots/keystroke-visualizer-2.png", + "https://vovsoft.com/screenshots/keystroke-visualizer-3.png", + "https://vovsoft.com/screenshots/keystroke-visualizer-4.png" + ] + }, + "keywordcombiner": { + "icon": "https://vovsoft.com/icons128/keyword-combiner.png", + "images": [ + "https://vovsoft.com/screenshots/keyword-combiner.png" + ] + }, + "machinelearningrequester": { + "icon": "https://vovsoft.com/icons128/machine-learning-requester.png", + "images": [ + "https://vovsoft.com/screenshots/machine-learning-requester.png" + ] + }, + "markdownconverter": { + "icon": "https://vovsoft.com/icons128/markdown-converter.png", + "images": [ + "https://vovsoft.com/screenshots/markdown-converter.png" + ] + }, + "mergemultiplefolders": { + "icon": "https://vovsoft.com/icons128/merge-multiple-folders.png", + "images": [ + "https://i.postimg.cc/d3cL0SH6/image.png" + ] + }, + "mergexmlfiles": { + "icon": "https://vovsoft.com/icons64/merge-xml-files.png", + "images": [ + "https://vovsoft.com/screenshots/merge-xml-files.png" + ] + }, + "networkalarmer": { + "icon": "https://vovsoft.com/icons128/network-alarmer.png", + "images": [ + "https://vovsoft.com/screenshots/network-alarmer.png" + ] + }, + "noisedetector": { + "icon": "https://vovsoft.com/icons128/noise-detector.png", + "images": [ + "https://vovsoft.com/screenshots/noise-detector.png", + "https://vovsoft.com/screenshots/noise-detector-2.png", + "https://vovsoft.com/screenshots/noise-detector-3.png" + ] + }, + "ocrreader": { + "icon": "https://vovsoft.com/icons128/ocr-reader.png?v=3.3", + "images": [ + "https://vovsoft.com/screenshots/ocr-reader.png", + "https://vovsoft.com/screenshots/ocr-reader-2.png", + "https://vovsoft.com/screenshots/ocr-reader-3.png", + "https://vovsoft.com/screenshots/ocr-reader-4.png", + "https://vovsoft.com/screenshots/ocr-reader-5.png" + ] + }, + "pdftoimageconverter": { + "icon": "https://vovsoft.com/icons64/pdf-to-image-converter.png", + "images": [ + "https://i.postimg.cc/1zRdkmyW/image.png" + ] + }, + "photostovideo": { + "icon": "https://vovsoft.com/icons64/photos-to-video.png", + "images": [ + "https://vovsoft.com/screenshots/photos-to-video.png", + "https://vovsoft.com/screenshots/photos-to-video-2.png", + "https://vovsoft.com/screenshots/photos-to-video-3.png" + ] + }, + "picturedownloader": { + "icon": "https://vovsoft.com/icons64/picture-downloader.png", + "images": [ + "https://vovsoft.com/screenshots/picture-downloader.png", + "https://vovsoft.com/screenshots/picture-downloader-2.png", + "https://vovsoft.com/screenshots/picture-downloader-3.png" + ] + }, + "podcastdownloader": { + "icon": "https://vovsoft.com/icons64/podcast-downloader.png", + "images": [ + "https://vovsoft.com/screenshots/podcast-downloader.png", + "https://vovsoft.com/screenshots/podcast-downloader-2.png", + "https://vovsoft.com/screenshots/podcast-downloader-3.png" + ] + }, + "preventcomputersleep": { + "icon": "https://vovsoft.com/icons128/prevent-computer-sleep.png", + "images": [ + "https://i.postimg.cc/1zMXqZBK/image.png" + ] + }, + "preventdisksleep": { + "icon": "https://vovsoft.com/icons64/prevent-disk-sleep.png", + "images": [ + "https://i.postimg.cc/x8mbH4c1/image.png" + ] + }, + "proxychecker": { + "icon": "https://vovsoft.com/icons128/proxy-checker.png", + "images": [ + "https://vovsoft.com/screenshots/proxy-checker.png" + ] + }, + "proxyserver": { + "icon": "https://vovsoft.com/icons128/proxy-server.png", + "images": [ + "https://vovsoft.com/screenshots/proxy-server.png" + ] + }, + "proxyswitcher": { + "icon": "https://vovsoft.com/icons128/proxy-switcher.png", + "images": [ + "https://vovsoft.com/screenshots/proxy-switcher.png" + ] + }, + "qrcodeandbarcodereader": { + "icon": "https://vovsoft.com/icons128/qr-code-and-barcode-reader.png", + "images": [ + "https://vovsoft.com/screenshots/qr-code-and-barcode-reader.png", + "https://vovsoft.com/screenshots/qr-code-and-barcode-reader-2.png", + "https://vovsoft.com/screenshots/qr-code-and-barcode-reader-3.png" + ] + }, + "rambenchmark": { + "icon": "https://vovsoft.com/icons64/ram-benchmark.png", + "images": [ + "https://i.postimg.cc/Gm6wgg29/image.png" + ] + }, + "rammonitorgadget": { + "icon": "https://vovsoft.com/icons128/ram-monitor-gadget.png", + "images": [ + "https://vovsoft.com/screenshots/ram-monitor-gadget.png" + ] + }, + "randomwordlistgenerator": { + "icon": "https://vovsoft.com/icons128/random-wordlist-generator.png", + "images": [ + "https://vovsoft.com/screenshots/random-wordlist-generator.png", + "https://vovsoft.com/screenshots/random-wordlist-generator-2.png", + "https://vovsoft.com/screenshots/random-wordlist-generator-3.png" + ] + }, + "readmode": { + "icon": "https://vovsoft.com/icons64/read-mode.png", + "images": [ + "https://vovsoft.com/screenshots/read-mode.png" + ] + }, + "regexextractor": { + "icon": "https://vovsoft.com/icons64/regex-extractor.png", + "images": [ + "https://vovsoft.com/screenshots/regex-extractor.png", + "https://vovsoft.com/screenshots/regex-extractor-2.png", + "https://vovsoft.com/screenshots/regex-extractor-3.png", + "https://vovsoft.com/screenshots/regex-extractor-4.png" + ] + }, + "resourceextractor": { + "icon": "https://vovsoft.com/icons128/resource-extractor.png", + "images": [ + "https://vovsoft.com/screenshots/resource-extractor.png" + ] + }, + "seochecker": { + "icon": "https://vovsoft.com/icons64/seo-checker.png", + "images": [ + "https://vovsoft.com/screenshots/seo-checker.png", + "https://vovsoft.com/screenshots/seo-checker-2.png", + "https://vovsoft.com/screenshots/seo-checker-3.png", + "https://vovsoft.com/screenshots/seo-checker-4.png", + "https://vovsoft.com/screenshots/seo-checker-5.png", + "https://vovsoft.com/screenshots/seo-checker-6.png", + "https://vovsoft.com/screenshots/seo-checker-7.png" + ] + }, + "searchtextinfiles": { + "icon": "https://vovsoft.com/icons128/search-text-in-files.png", + "images": [ + "https://vovsoft.com/screenshots/search-text-in-files.png", + "https://vovsoft.com/screenshots/search-text-in-files-2.png", + "https://vovsoft.com/screenshots/search-text-in-files-3.png", + "https://vovsoft.com/screenshots/search-text-in-files-4.png", + "https://vovsoft.com/screenshots/search-text-in-files-5.png", + "https://vovsoft.com/screenshots/search-text-in-files-6.png" + ] + }, + "serialportmonitor": { + "icon": "https://vovsoft.com/icons64/serial-port-monitor.png", + "images": [ + "https://vovsoft.com/screenshots/serial-port-monitor.png", + "https://vovsoft.com/screenshots/serial-port-monitor-2.png", + "https://vovsoft.com/screenshots/serial-port-monitor-3.png", + "https://vovsoft.com/screenshots/serial-port-monitor-4.png", + "https://vovsoft.com/screenshots/serial-port-monitor-5.png" + ] + }, + "silenceremover": { + "icon": "https://vovsoft.com/icons128/silence-remover.png", + "images": [ + "https://vovsoft.com/screenshots/silence-remover.png" + ] + }, + "sitemapgenerator": { + "icon": "https://vovsoft.com/icons64/sitemap-generator.png", + "images": [ + "https://vovsoft.com/screenshots/sitemap-generator.png" + ] + }, + "soundrecorder": { + "icon": "https://vovsoft.com/icons64/sound-recorder.png", + "images": [ + "https://i.postimg.cc/2jqzGWTH/image.png" + ] + }, + "speechtosubtitleconverter": { + "icon": "https://vovsoft.com/icons128/speech-to-subtitle-converter.png", + "images": [ + "https://vovsoft.com/screenshots/speech-to-subtitle-converter.png", + "https://vovsoft.com/screenshots/speech-to-subtitle-converter-2.png", + "https://vovsoft.com/screenshots/speech-to-subtitle-converter-3.png", + "https://vovsoft.com/screenshots/speech-to-subtitle-converter-4.png" + ] + }, + "spreadsheetcombiner": { + "icon": "https://vovsoft.com/icons128/spreadsheet-combiner.png", + "images": [ + "https://vovsoft.com/screenshots/spreadsheet-combiner.png" + ] + }, + "textdecoderandencoder": { + "icon": "https://vovsoft.com/icons64/text-decoder-and-encoder.png", + "images": [ + "https://vovsoft.com/screenshots/text-decoder-and-encoder.png", + "https://vovsoft.com/screenshots/text-decoder-and-encoder-2.png", + "https://vovsoft.com/screenshots/text-decoder-and-encoder-3.png" + ] + }, + "texteditplus": { + "icon": "https://vovsoft.com/icons128/text-edit-plus.png", + "images": [ + "https://i.postimg.cc/sx34jznX/image.png", + "https://vovsoft.com/screenshots/text-edit-plus.png", + "https://vovsoft.com/screenshots/text-edit-plus-2.png", + "https://vovsoft.com/screenshots/text-edit-plus-3.png", + "https://vovsoft.com/screenshots/text-edit-plus-4.png", + "https://vovsoft.com/screenshots/text-edit-plus-5.png", + "https://vovsoft.com/screenshots/text-edit-plus-6.png" + ] + }, + "Winget.VovSoft.TextFilter": { + "icon": "https://vovsoft.com/icons128/text-filter.png", + "images": [ + "https://vovsoft.com/screenshots/text-filter.png" + ] + }, + "timesync": { + "icon": "https://vovsoft.com/icons64/time-sync.png", + "images": [ + "https://vovsoft.com/screenshots/time-sync.png" + ] + }, + "treenotes": { + "icon": "https://vovsoft.com/icons128/tree-notes.png", + "images": [ + "https://vovsoft.com/screenshots/tree-notes.png" + ] + }, + "urlextractor": { + "icon": "https://vovsoft.com/icons64/url-extractor.png", + "images": [ + "https://vovsoft.com/screenshots/url-extractor.png", + "https://vovsoft.com/screenshots/url-extractor-2.png", + "https://vovsoft.com/screenshots/url-extractor-3.png", + "https://vovsoft.com/screenshots/url-extractor-4.png", + "https://vovsoft.com/screenshots/url-extractor-6.png" + ] + }, + "vcfeditor": { + "icon": "https://vovsoft.com/icons128/vcf-editor.png", + "images": [ + "https://vovsoft.com/screenshots/vcf-editor.png" + ] + }, + "vcfmerger": { + "icon": "https://vovsoft.com/icons128/vcf-merger.png", + "images": [ + "https://vovsoft.com/screenshots/vcf-merger.png" + ] + }, + "vcfsplitter": { + "icon": "https://vovsoft.com/icons128/vcf-splitter.png", + "images": [ + "https://vovsoft.com/screenshots/vcf-splitter.png" + ] + }, + "vcftocsvconverter": { + "icon": "https://vovsoft.com/icons128/vcf-to-csv-converter.png", + "images": [ + "https://vovsoft.com/screenshots/vcf-to-csv-converter-2.png", + "https://vovsoft.com/screenshots/vcf-to-csv-converter-3.png", + "https://vovsoft.com/screenshots/vcf-to-csv-converter-4.png" + ] + }, + "videotophotos": { + "icon": "https://vovsoft.com/icons64/video-to-photos.png", + "images": [ + "https://vovsoft.com/screenshots/video-to-photos.png" + ] + }, + "voicechanger": { + "icon": "https://vovsoft.com/icons64/voice-changer.png", + "images": [ + "https://vovsoft.com/screenshots/voice-changer.png", + "https://vovsoft.com/screenshots/voice-changer-2.png", + "https://vovsoft.com/screenshots/voice-changer-3.png" + ] + }, + "vovalphablend": { + "icon": "https://vovsoft.com/icons64/vov-alpha-blend.png", + "images": [ + "https://vovsoft.com/screenshots/vov-alpha-blend.png" + ] + }, + "vovmusicplayer": { + "icon": "https://vovsoft.com/icons128/vov-music-player.png", + "images": [ + "https://vovsoft.com/screenshots/vov-music-player.png", + "https://vovsoft.com/screenshots/vov-music-player-2.png", + "https://vovsoft.com/screenshots/vov-music-player-3.png", + "https://vovsoft.com/screenshots/vov-music-player-4.png", + "https://vovsoft.com/screenshots/vov-music-player-5.png" + ] + }, + "vovscreenrecorder": { + "icon": "https://vovsoft.com/icons64/vov-screen-recorder.png", + "images": [ + "https://vovsoft.com/screenshots/vov-screen-recorder.png", + "https://vovsoft.com/screenshots/vov-screen-recorder-2.png", + "https://vovsoft.com/screenshots/vov-screen-recorder-3.png", + "https://vovsoft.com/screenshots/vov-screen-recorder-4.png" + ] + }, + "vovstickynotes": { + "icon": "https://vovsoft.com/icons128/vov-sticky-notes.png", + "images": [ + "https://vovsoft.com/screenshots/vov-sticky-notes.png", + "https://vovsoft.com/screenshots/vov-sticky-notes-2.png", + "https://vovsoft.com/screenshots/vov-sticky-notes-3.png", + "https://vovsoft.com/screenshots/vov-sticky-notes-4.png", + "https://vovsoft.com/screenshots/vov-sticky-notes-5.png", + "https://vovsoft.com/screenshots/vov-sticky-notes-6.png", + "https://vovsoft.com/screenshots/vov-sticky-notes-7.png" + ] + }, + "vovstopstart": { + "icon": "https://vovsoft.com/icons128/vov-stop-start.png", + "images": [ + "https://vovsoft.com/screenshots/vov-stop-start.png" + ] + }, + "watermarkvideo": { + "icon": "https://vovsoft.com/icons64/watermark-video.png", + "images": [ + "https://i.postimg.cc/CxFjCWdn/image.png" + ] + }, + "webplatformidentifier": { + "icon": "https://vovsoft.com/icons128/web-platform-identifier.png", + "images": [ + "https://vovsoft.com/screenshots/web-platform-identifier.png" + ] + }, + "webcamcapture": { + "icon": "https://vovsoft.com/icons64/webcam-capture.png", + "images": [ + "https://vovsoft.com/screenshots/webcam-capture.png" + ] + }, + "websitefilecollector": { + "icon": "https://vovsoft.com/icons128/website-file-collector.png", + "images": [ + "https://vovsoft.com/screenshots/website-file-collector.png" + ] + }, + "websitescreenshotgenerator": { + "icon": "https://vovsoft.com/icons128/website-screenshot-generator.png", + "images": [ + "https://vovsoft.com/screenshots/website-screenshot-generator.png" + ] + }, + "websitespellchecker": { + "icon": "https://vovsoft.com/icons128/website-spell-checker.png", + "images": [ + "https://vovsoft.com/screenshots/website-spell-checker.png" + ] + }, + "Winget.VovSoft.WebsiteWatcher": { + "icon": "https://vovsoft.com/icons128/website-watcher.png", + "images": [ + "https://vovsoft.com/screenshots/website-watcher.png", + "https://vovsoft.com/screenshots/website-watcher-2.png", + "https://vovsoft.com/screenshots/website-watcher-3.png" + ] + }, + "windowresizer": { + "icon": "https://vovsoft.com/icons128/window-resizer.png", + "images": [ + "https://vovsoft.com/screenshots/window-resizer.png" + ] + }, + "vovsystemuptime": { + "icon": "https://vovsoft.com/icons64/vov-system-uptime.png", + "images": [ + "https://vovsoft.com/screenshots/vov-system-uptime.png" + ] + }, + "xlstocsvconverter": { + "icon": "https://vovsoft.com/icons64/xls-to-csv-converter.png", + "images": [ + "https://vovsoft.com/screenshots/xls-to-csv-converter.png" + ] + }, + "vcftotxtconverter": { + "icon": "https://vovsoft.com/icons128/vcf-to-txt-converter.png", + "images": [ + "https://vovsoft.com/screenshots/vcf-to-txt-converter.png?v=3.1" + ] + }, + "subtitletranslator": { + "icon": "https://vovsoft.com/icons64/subtitle-translator.png", + "images": [ + "https://vovsoft.com/screenshots/subtitle-translator.png" + ] + }, + "speechtotextconverter": { + "icon": "https://vovsoft.com/icons64/speech-to-text-converter.png", + "images": [ + "https://vovsoft.com/screenshots/speech-to-text-converter.png", + "https://vovsoft.com/screenshots/speech-to-text-converter-2.png", + "https://vovsoft.com/screenshots/speech-to-text-converter-3.png", + "https://vovsoft.com/screenshots/speech-to-text-converter-4.png", + "https://vovsoft.com/screenshots/speech-to-text-converter-5.png", + "https://vovsoft.com/screenshots/speech-to-text-converter-6.png" + ] + }, + "textstatisticsanalyzer": { + "icon": "https://vovsoft.com/icons128/text-statistics-analyzer.png", + "images": [ + "https://vovsoft.com/screenshots/text-statistics-analyzer.png", + "https://vovsoft.com/screenshots/text-statistics-analyzer-2.png", + "https://vovsoft.com/screenshots/text-statistics-analyzer-3.png", + "https://vovsoft.com/screenshots/text-statistics-analyzer-4.png", + "https://vovsoft.com/screenshots/text-statistics-analyzer-5.png", + "https://vovsoft.com/screenshots/text-statistics-analyzer-6.png" + ] + }, + "3dboxmaker": { + "icon": "https://vovsoft.com/icons64/3d-box-maker.png", + "images": [ + "https://vovsoft.com/screenshots/3d-box-maker.png" + ] + }, + "picturepuzzle": { + "icon": "https://vovsoft.com/icons128/picture-puzzle.png", + "images": [ + "https://vovsoft.com/screenshots/picture-puzzle.png" + ] + }, + "syslogserver": { + "icon": "https://vovsoft.com/icons128/syslog-server.png", + "images": [ + "https://vovsoft.com/screenshots/syslog-server.png" + ] + }, + "vcftoxlsconverter": { + "icon": "https://vovsoft.com/icons128/vcf-to-xls-converter.png", + "images": [ + "https://vovsoft.com/screenshots/vcf-to-xls-converter.png" + ] + }, + "appreadwritecounter": { + "icon": "https://i.postimg.cc/0201zJLD/App-Read-Write-Counter.png", + "images": [ + "https://i.postimg.cc/7L648Yth/image.png" + ] + }, + "dhcplogview": { + "icon": "https://i.postimg.cc/nzWcwQHF/DHCPLog-View.png", + "images": [ + "https://i.postimg.cc/LX33t2Rc/image.png" + ] + }, + "fulleventlogview": { + "icon": "https://i.postimg.cc/50Q6JmKG/image.png", + "images": [ + "https://i.postimg.cc/KvP34JG7/image.png" + ] + }, + "guipropview": { + "icon": "https://i.postimg.cc/MpsTjLhB/image.png", + "images": [ + "https://i.postimg.cc/XYNqqWDv/image.png" + ] + }, + "installeddriverslist": { + "icon": "https://i.postimg.cc/GtrrfPW8/image.png", + "images": [ + "https://i.postimg.cc/Xq836GWg/image.png" + ] + }, + "installedpackagesview": { + "icon": "https://i.postimg.cc/hthnNt5m/image.png", + "images": [ + "https://i.postimg.cc/13TSS1kv/image.png" + ] + }, + "lanipscanner": { + "icon": "https://i.postimg.cc/6QRkN2Lq/image.png", + "images": [ + "https://i.postimg.cc/y8JqvrDZ/image.png" + ] + }, + "managewirelessnetworks": { + "icon": "https://i.postimg.cc/pV1qqVKR/image.png", + "images": [ + "https://i.postimg.cc/zXspYddW/image.png" + ] + }, + "mobilefilesearch": { + "icon": "https://i.postimg.cc/76Znnj6h/image.png", + "images": [ + "https://i.postimg.cc/Fzfb2c3n/image.png", + "https://i.postimg.cc/fy67ZLvh/image.png" + ] + }, + "networkcounterswatch": { + "icon": "https://i.postimg.cc/jqWFVJsp/image.png", + "images": [ + "https://i.postimg.cc/NGWPQfFF/image.png" + ] + }, + "networkinterfacesview": { + "icon": "https://i.postimg.cc/43LBqXjJ/image.png", + "images": [ + "https://i.postimg.cc/gJxNPfPf/image.png" + ] + }, + "networkopenedfiles": { + "icon": "https://i.postimg.cc/X7fx3fTY/image.png", + "images": [ + "https://i.postimg.cc/y87jNJHP/image.png" + ] + }, + "networkusageview": { + "icon": "https://i.postimg.cc/C1nH2kGY/image.png", + "images": [ + "https://i.postimg.cc/NFh7vFD6/image.png" + ] + }, + "openedfilesview": { + "icon": "https://i.postimg.cc/Tw3B57vN/image.png", + "images": [ + "https://i.postimg.cc/76td33qj/image.png", + "https://i.postimg.cc/C5ZtmR1f/image.png" + ] + }, + "resourcesextract": { + "icon": "https://i.postimg.cc/ZqszHtcc/image.png", + "images": [ + "https://i.postimg.cc/0Q6RHWX9/image.png" + ] + }, + "searchmyfiles": { + "icon": "https://i.postimg.cc/Gp56YPLP/image.png", + "images": [ + "https://i.postimg.cc/Y9LZx4jp/image.png" + ] + }, + "shellmenuview": { + "icon": "https://i.postimg.cc/TYJSQv2r/image.png", + "images": [ + "https://i.postimg.cc/W19yLmJB/image.png" + ] + }, + "simplecodegenerator": { + "icon": "https://i.postimg.cc/RFtpHjb7/image.png", + "images": [ + "https://i.postimg.cc/bYQFNfnf/image.png" + ] + }, + "soundvolumeview": { + "icon": "https://i.postimg.cc/MHW0pNkT/image.png", + "images": [ + "https://i.postimg.cc/sxwYQmym/image.png" + ] + }, + "tcplogview": { + "icon": "https://i.postimg.cc/1zwDcssz/image.png", + "images": [ + "https://i.postimg.cc/fLsm8pRK/image.png" + ] + }, + "turnedontimesview": { + "icon": "https://i.postimg.cc/MZdVYs2Z/image.png", + "images": [ + "https://i.postimg.cc/FszcCjNp/image.png" + ] + }, + "usblogview": { + "icon": "https://i.postimg.cc/2jcLWVhb/image.png", + "images": [ + "https://i.postimg.cc/qMNhx4xZ/image.png" + ] + }, + "wifiinfoview": { + "icon": "https://i.postimg.cc/T39KR1dg/image.png", + "images": [ + "https://i.postimg.cc/xdpqzZb2/image.png" + ] + }, + "browserdownloadsview": { + "icon": "https://i.postimg.cc/zvFrnLPV/image.png", + "images": [ + "https://i.postimg.cc/VsqmyTLy/image.png" + ] + }, + "winhex": { + "icon": "https://i.postimg.cc/v8zktdZ0/winhex.png", + "images": [ + "https://i.postimg.cc/8cPy0jzM/image.png" + ] + }, + "Winget.DiskInternals.AccessRecovery": { + "icon": "", + "images": [ + "https://i.postimg.cc/5yCH1m0h/image.png", + "https://i.postimg.cc/05bBgXGv/image.png", + "https://i.postimg.cc/1R2Yy0Mw/image.png", + "https://i.postimg.cc/wTN4MtGy/image.png", + "https://i.postimg.cc/zGSdwsNS/image.png" + ] + }, + "Winget.DiskInternals.BootableRecoveryCD": { + "icon": "", + "images": [ + "https://i.postimg.cc/VNkFq5DS/image.png", + "https://i.postimg.cc/3RyCq6sq/image.png", + "https://i.postimg.cc/Hxf41zHk/image.png", + "https://i.postimg.cc/zB9SY75t/image.png" + ] + }, + "Winget.DiskInternals.CD-DVDRecovery": { + "icon": "", + "images": [ + "https://i.postimg.cc/9QWP2r52/image.png", + "https://i.postimg.cc/Zqnr925n/image.png", + "https://i.postimg.cc/YS014ZC3/image.png" + ] + }, + "Winget.DiskInternals.DVRRecovery": { + "icon": "", + "images": [ + "https://i.postimg.cc/7LjT5Lcv/image.png", + "https://i.postimg.cc/j5NnPb04/image.png" + ] + }, + "Winget.DiskInternals.EFSRecovery": { + "icon": "", + "images": [ + "https://i.postimg.cc/Bn68ND9k/image.png", + "https://i.postimg.cc/XJwXXkd1/image.png", + "https://i.postimg.cc/CLMdLD1b/image.png", + "https://i.postimg.cc/t4wg5Mzv/image.png", + "https://i.postimg.cc/cHNLqt2B/image.png", + "https://i.postimg.cc/BQvQG0YN/image.png" + ] + }, + "Winget.DiskInternals.ExcelRecovery": { + "icon": "", + "images": [ + "https://i.postimg.cc/VkCwYLjf/image.png", + "https://i.postimg.cc/Dz17cyZp/image.png", + "https://i.postimg.cc/W3jTYLq9/image.png", + "https://i.postimg.cc/zv2NfytF/image.png", + "https://i.postimg.cc/9FzVnB09/image.png" + ] + }, + "ramtempfolderpro": { + "icon": "https://i.postimg.cc/ZRR4zPjy/image.png", + "images": [ + "https://i.postimg.cc/637ghMYH/image.png" + ] + }, + "ramtempfolder": { + "icon": "https://i.postimg.cc/ZRR4zPjy/image.png", + "images": [] + }, + "diskboss": { + "icon": "", + "images": [] + }, + "diskbossenterprise": { + "icon": "", + "images": [] + }, + "diskbosspro": { + "icon": "", + "images": [] + }, + "diskbossserver": { + "icon": "", + "images": [] + }, + "diskbossultimate": { + "icon": "", + "images": [ + "https://i.postimg.cc/6qxK4st9/image.png", + "https://i.postimg.cc/rwZLCRMh/image.png" + ] + }, + "diskpulse": { + "icon": "", + "images": [] + }, + "diskpulseenterprise": { + "icon": "", + "images": [] + }, + "diskpulsepro": { + "icon": "", + "images": [] + }, + "diskpulseserver": { + "icon": "", + "images": [] + }, + "disksavvy": { + "icon": "", + "images": [] + }, + "disksavvyenterprise": { + "icon": "", + "images": [] + }, + "disksavvypro": { + "icon": "", + "images": [] + }, + "disksavvyserver": { + "icon": "", + "images": [] + }, + "disksavvyultimate": { + "icon": "", + "images": [] + }, + "disksorter": { + "icon": "https://i.postimg.cc/rFDPg9rn/disksorter.png", + "images": [] + }, + "disksorterenterprise": { + "icon": "https://i.postimg.cc/rFDPg9rn/disksorter.png", + "images": [] + }, + "disksorterpro": { + "icon": "https://i.postimg.cc/rFDPg9rn/disksorter.png", + "images": [] + }, + "disksorterserver": { + "icon": "https://i.postimg.cc/rFDPg9rn/disksorter.png", + "images": [] + }, + "disksorterultimate": { + "icon": "https://i.postimg.cc/rFDPg9rn/disksorter.png", + "images": [] + }, + "dupscout": { + "icon": "", + "images": [] + }, + "dupscoutenterprise": { + "icon": "", + "images": [] + }, + "dupscoutpro": { + "icon": "", + "images": [] + }, + "dupscoutserver": { + "icon": "", + "images": [] + }, + "dupscoutultimate": { + "icon": "", + "images": [] + }, + "syncbreeze": { + "icon": "", + "images": [] + }, + "syncbreezeenterprise": { + "icon": "", + "images": [] + }, + "syncbreezepro": { + "icon": "", + "images": [] + }, + "syncbreezeserver": { + "icon": "", + "images": [] + }, + "syncbreezeultimate": { + "icon": "", + "images": [] + }, + "sysgaugepro": { + "icon": "", + "images": [] + }, + "sysgaugeserver": { + "icon": "", + "images": [] + }, + "sysgaugeultimate": { + "icon": "", + "images": [] + }, + "vxsearch": { + "icon": "", + "images": [] + }, + "vxsearchenterprise": { + "icon": "", + "images": [] + }, + "vxsearchpro": { + "icon": "", + "images": [] + }, + "vxsearchserver": { + "icon": "", + "images": [] + }, + "vxsearchultimate": { + "icon": "", + "images": [] + }, + "autologout": { + "icon": "https://autologout.yiays.com/img/icon-colour.png", + "images": [ + "https://autologout.yiays.com/img/client.png", + "https://autologout.yiays.com/img/client-controlpanel.png" + ] + }, + "habbolauncher": { + "icon": "https://i.imgur.com/yzNr9nN.png", + "images": [] + }, + "iobitunlocker": { + "icon": "https://i.imgur.com/nq6FMyG.png", + "images": [] + }, + "calendartask": { + "icon": "https://i.postimg.cc/Qt5rXMNW/caltask.png", + "images": [ + "https://i.postimg.cc/L6mMpRcZ/image.png", + "https://i.postimg.cc/QdVw8M0J/image.png", + "https://i.postimg.cc/MHd3xkBg/image.png", + "https://i.postimg.cc/T3Z7TJKs/image.png", + "https://i.postimg.cc/nzx3DVYw/image.png", + "https://i.postimg.cc/QCxSf6zJ/image.png", + "https://i.postimg.cc/sDxwSNS8/image.png" + ] + }, + "websiteoptimizer": { + "icon": "", + "images": [ + "https://i.postimg.cc/s2YbYdpf/image.png", + "https://i.postimg.cc/zvBMYy4V/image.png" + ] + }, + "appletrunnerpro": { + "icon": "", + "images": [ + "https://i.postimg.cc/59hGR2n5/image.png", + "https://i.postimg.cc/vZzNTLMx/image.png", + "https://i.postimg.cc/ZnpfS6Vy/image.png", + "https://i.postimg.cc/h4dZTqc4/image.png", + "https://i.postimg.cc/021WCHyn/image.png" + ] + }, + "controldashboard": { + "icon": "", + "images": [ + "https://i.postimg.cc/1XQGD2r8/image.png", + "https://i.postimg.cc/sfY93f33/image.png", + "https://i.postimg.cc/xT9G8rdy/image.png", + "https://i.postimg.cc/KvQPg9kZ/image.png", + "https://i.postimg.cc/NjM181mk/image.png", + "https://i.postimg.cc/0NKDFPV3/image.png" + ] + }, + "controldashboard-pro": { + "icon": "", + "images": [ + "https://i.postimg.cc/1XQGD2r8/image.png", + "https://i.postimg.cc/sfY93f33/image.png", + "https://i.postimg.cc/xT9G8rdy/image.png", + "https://i.postimg.cc/KvQPg9kZ/image.png", + "https://i.postimg.cc/NjM181mk/image.png", + "https://i.postimg.cc/0NKDFPV3/image.png" + ] + }, + "decoration": { + "icon": "", + "images": [ + "https://i.postimg.cc/xTjHYKxQ/image.png", + "https://i.postimg.cc/HkVy8T14/image.png", + "https://i.postimg.cc/ZRhBQ3BV/image.png", + "https://i.postimg.cc/rsVdVk9y/image.png", + "https://i.postimg.cc/L5xJhbyy/image.png", + "https://i.postimg.cc/h4szCXSm/image.png" + ] + }, + "dictaphone": { + "icon": "", + "images": [ + "https://i.postimg.cc/Bv2t26Y5/image.png", + "https://i.postimg.cc/d1v36Ypb/image.png", + "https://i.postimg.cc/LXTX0WMh/image.png" + ] + }, + "discotheek": { + "icon": "", + "images": [ + "https://i.postimg.cc/SQPqN4Vb/image.png" + ] + }, + "clipboardhistory": { + "icon": "", + "images": [ + "https://i.postimg.cc/LsmF084f/image.png", + "https://i.postimg.cc/YS8BcBhc/image.png", + "https://i.postimg.cc/QttGhYTp/image.png", + "https://i.postimg.cc/k4pr4NQZ/image.png", + "https://i.postimg.cc/QC92WBSr/image.png", + "https://i.postimg.cc/nry6KHwQ/image.png" + ] + }, + "clipboardhistory-pro": { + "icon": "", + "images": [ + "https://i.postimg.cc/MKRGCXwr/image.png", + "https://i.postimg.cc/JzLhMm4r/image.png", + "https://i.postimg.cc/y8y8N5kJ/image.png", + "https://i.postimg.cc/rpyFRJrf/image.png" + ] + }, + "Winget.Japplis.Toolbox": { + "icon": "", + "images": [ + "https://i.postimg.cc/zDh5BMQq/image.png", + "https://i.postimg.cc/YCrwdSCr/image.png", + "https://i.postimg.cc/XYs6m0r2/image.png", + "https://i.postimg.cc/W4KLp66J/image.png", + "https://i.postimg.cc/XqSRdjPW/image.png", + "https://i.postimg.cc/90dvp33v/image.png", + "https://i.postimg.cc/hPgFGGTF/image.png" + ] + }, + "Winget.Japplis.Toolbox.Pro": { + "icon": "", + "images": [ + "https://i.postimg.cc/R0JpdrKZ/image.png", + "https://i.postimg.cc/26pcXHxC/image.png", + "https://i.postimg.cc/C57c5wpT/image.png", + "https://i.postimg.cc/sDfn8G5s/image.png", + "https://i.postimg.cc/XqSRdjPW/image.png", + "https://i.postimg.cc/90dvp33v/image.png" + ] + }, + "Winget.Japplis.Watch": { + "icon": "", + "images": [ + "https://i.postimg.cc/htDfVcFw/image.png", + "https://i.postimg.cc/P5SN49TP/image.png", + "https://i.postimg.cc/BvybWFjB/image.png", + "https://i.postimg.cc/hjdjKGxh/image.png", + "https://i.postimg.cc/QCZMCrkf/image.png", + "https://i.postimg.cc/0jGyJHVN/image.png" + ] + }, + "Winget.Japplis.Watch.Pro": { + "icon": "", + "images": [ + "https://i.postimg.cc/4N53fqKn/image.png", + "https://i.postimg.cc/8zXPWvmp/image.png", + "https://i.postimg.cc/d07Q905C/image.png", + "https://i.postimg.cc/TPZdNXsz/image.png" + ] + }, + "lopeedit": { + "icon": "", + "images": [ + "https://i.postimg.cc/XqGX0B5m/image.png" + ] + }, + "Winget.Hetman.PhotoRecovery": { + "icon": "", + "images": [ + "https://i.postimg.cc/XJQnqfdm/image.png", + "https://i.postimg.cc/htTgTWVX/image.png", + "https://i.postimg.cc/nzRtpHt8/image.png" + ] + }, + "Winget.Hetman.OfficeRecovery": { + "icon": "", + "images": [ + "https://i.postimg.cc/cCF6qqF0/image.png", + "https://i.postimg.cc/HsLVwxLx/image.png", + "https://i.postimg.cc/XYGqPzFx/image.png", + "https://i.postimg.cc/4dZ3m4Mk/image.png", + "https://i.postimg.cc/C5rMPGx9/image.png" + ] + }, + "Winget.Hetman.DataRecoveryPack": { + "icon": "", + "images": [ + "https://i.postimg.cc/d32mG0Q2/image.png", + "https://i.postimg.cc/wvZgD64R/image.png", + "https://i.postimg.cc/76GyHFHt/image.png", + "https://i.postimg.cc/HsLVwxLx/image.png", + "https://i.postimg.cc/htTgTWVX/image.png" + ] + }, + "Winget.Hetman.PartitionRecovery": { + "icon": "", + "images": [ + "https://i.postimg.cc/dVHR2pv0/image.png", + "https://i.postimg.cc/dtnGFphF/image.png", + "https://i.postimg.cc/25LW4520/image.png", + "https://i.postimg.cc/3NYD5F7S/image.png", + "https://i.postimg.cc/VLsbKgDT/image.png" + ] + }, + "Winget.Hetman.FileRepair": { + "icon": "", + "images": [ + "https://i.postimg.cc/tg659D0N/image.png" + ] + }, + "Winget.Hetman.RAIDRecovery": { + "icon": "", + "images": [ + "https://i.postimg.cc/nhR5X3PC/image.png", + "https://i.postimg.cc/yN2bPkKt/image.png", + "https://i.postimg.cc/1t6YYs50/image.png", + "https://i.postimg.cc/5ySKbgzb/image.png", + "https://i.postimg.cc/7YqQmvv4/image.png", + "https://i.postimg.cc/GhzgfMrX/image.png" + ] + }, + "Winget.Hetman.InternetSpy": { + "icon": "", + "images": [ + "https://i.postimg.cc/jScTZ63G/image.png", + "https://i.postimg.cc/76GyHFHt/image.png", + "https://i.postimg.cc/NM3v5dLs/image.png", + "https://i.postimg.cc/mZ9G0W6Q/image.png", + "https://i.postimg.cc/QxkZdkDC/image.png", + "https://i.postimg.cc/SxSF22Qt/image.png" + ] + }, + "Winget.Hetman.Uneraser": { + "icon": "", + "images": [ + "https://i.postimg.cc/76fqCCVj/image.png", + "https://i.postimg.cc/wvZgD64R/image.png", + "https://i.postimg.cc/zvh5j949/image.png", + "https://i.postimg.cc/5Ncf02Fk/image.png" + ] + }, + "multiping": { + "icon": "https://i.postimg.cc/fTgJQMkh/multiping-icon.png", + "images": [ + "https://i.postimg.cc/NGSW3VBF/image.png", + "https://i.postimg.cc/2SFMBSv5/image.png" + ] + }, + "musehub": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/4/4b/MuseHub_Logo.svg/512px-MuseHub_Logo.svg.png", + "images": [] + }, + "antigravity": { + "icon": "https://unigeticons.meowcat285.com/Antigravity.png", + "images": [ + "https://cdn.thenewstack.io/media/2025/11/9fa23e7d-googleantigravitylogo-whitebackground.png", + "https://antigravity.google/assets/image/docs/editor-open-agent-manager.png", + "https://antigravity.google/assets/image/docs/default-allowlist-urls.png", + "https://antigravity.google/assets/image/docs/editor/editor.png" + ] + }, + "aviutl2-catalog": { + "icon": "https://raw.githubusercontent.com/Neosku/aviutl2-catalog/main/src-tauri/icons/icon.png", + "images": [ + "https://raw.githubusercontent.com/Neosku/aviutl2-catalog/main/docs/info1.png", + "https://raw.githubusercontent.com/Neosku/aviutl2-catalog/main/docs/info2.png", + "https://raw.githubusercontent.com/Neosku/aviutl2-catalog/main/docs/info3.png", + "https://raw.githubusercontent.com/Neosku/aviutl2-catalog/main/docs/info4.png" + ] + }, + "r2modman": { + "icon": "https://unigeticons.meowcat285.com/r2modman.png", + "images": [ + "https://unigeticons.meowcat285.com/Screenshots/r2modman/r2modman-screenshot1.png", + "https://unigeticons.meowcat285.com/Screenshots/r2modman/r2modman-screenshot2.png", + "https://unigeticons.meowcat285.com/Screenshots/r2modman/r2modman-screenshot3.png", + "https://unigeticons.meowcat285.com/Screenshots/r2modman/r2modman-screenshot4.png", + "https://unigeticons.meowcat285.com/Screenshots/r2modman/r2modman-screenshot5.png" + ] + }, + "robotframework": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/e/e4/Robot-framework-logo.png", + "images": [] + }, + "Logitech.LogiTune": { + "icon": "https://imgs.search.brave.com/ASjRKcLSMy8TMcfmAKV4Hte2F6IJZNgqHnCwlZv_jJw/rs:fit:860:0:0:0/g:ce/aHR0cHM6Ly93d3cu/bG9naXRlY2guY29t/L2Fzc2V0cy82NTY4/Ni8yL2xvZ2ktdHVu/ZS1hcHAucG5n", + "images": [] + }, + "OpenVPNTechnologies.OpenVPN": { + "icon": "https://postimg.cc/2LQGvMgm", + "images": [] + }, + "Winget.Zoom.Zoom.EXE": { + "icon": "https://i.postimg.cc/NFd1Qg5d/zoom-logo.png", + "images": [ + "https://i.postimg.cc/HW0dsF59/Zoom1.png", + "https://i.postimg.cc/pXqvK8s9/Zoom2.png", + "https://i.postimg.cc/52yVg0rs/Zoom3.png" + ] + }, + "Winget.winaero.tweaker": { + "icon": "https://winaerotweaker.com/images/tweaker-app-icon.png", + "images": [ + "https://winaerotweaker.com/images/tweaker-app.png", + "https://winaerotweaker.com/images/tweaker-app-unblock-cm.png", + "https://winaerotweaker.com/images/tweaker-app-drag-drop.png", + "https://winaerotweaker.com/images/tweaker-app-taskbar-thumbnails.png", + "https://winaerotweaker.com/images/tweaker-app-this-pc.png", + "https://winaerotweaker.com/images/tweaker-app-remove-cm.png", + "https://winaerotweaker.com/images/tweaker-app-reset-gp.png", + "https://winaerotweaker.com/images/tweaker-app-shares-uac.png" + ] + }, + "Winget.Microsoft.DotNet.DesktopRuntime.8": { + "icon": "https://community.chocolatey.org/content/packageimages/dotnet-8.0-desktopruntime.8.0.22.png", + "images": [] + }, + "google/gemini-cli": { + "icon": "https://geminicli.com/icon.png", + "images": [ + "https://raw.githubusercontent.com/google-gemini/gemini-cli/HEAD/docs/assets/gemini-screenshot.png" + ] + }, + "codesector-teraCopy": { + "icon": "https://i.ibb.co/VWMLqzbN/icon.png", + "images": [ + "https://i.ibb.co/XZgvrZDt/s1.png", + "https://i.ibb.co/RT4Qpvpj/s2.png", + "https://i.ibb.co/S40DxfM4/s3.png" + ] + }, + "XPFFCG7M673D4F": { + "icon": "https://images-eds-ssl.xboxlive.com/image?url=4rt9.lXDC4H_93laV1_eHHFT949fUipzkiFOBH3fAiZZUCdYojwUyX2aTonS1aIwMrx6NUIsHfUHSLzjGJFxxs6rpBN2unaNv5PNdhlS_qHGRhvdm1TQsZPByVJpM1zdYJW4EEWuEzJfMSAN6k7OiP4f5vDN5Z3B5cnmDdboFpA-&format=source&h=115", + "images": [] + }, + "setuptools": { + "icon": "https://i.ibb.co/67ZyXb6J/logo-over-white.png", + "images": [] + }, + "requests": { + "icon": "https://requests.readthedocs.io/en/latest/_static/requests-sidebar.png", + "images": [] + }, + "psutil": { + "icon": "", + "images": [] + }, + "attrs": { + "icon": "https://i.ibb.co/Tx99nQCc/attrs-logo.png", + "images": [] + }, + "starlette": { + "icon": "https://raw.githubusercontent.com/encode/starlette/master/docs/img/starlette.svg", + "images": [] + }, + "trio": { + "icon": "https://i.postimg.cc/sg60JLtz/68747470733a2f2f7261772e67697468756275736572636f6e74656e742e636f6d2f707974686f6e2d7472696f2f7472696f.png", + "images": [] + }, + "affinity": { + "icon": "https://i.postimg.cc/ZqQSQDGP/affinity_canva_256.png", + "images": [] + }, + "akiflow": { + "icon": "https://i.postimg.cc/MTjSJmwB/akiflow_256.png", + "images": [] + }, + "fullstackaimemegenerator": { + "icon": "https://i.postimg.cc/nzQJfGxG/thiojoe_96.png", + "images": [] + }, + "svgthumbnailextension": { + "icon": "https://i.postimg.cc/nzQJfGxG/thiojoe_96.png", + "images": [] + }, + "ytspammerpurge": { + "icon": "https://i.postimg.cc/nzQJfGxG/thiojoe_96.png", + "images": [] + }, + "tweaker": { + "icon": "https://i.postimg.cc/C1fgps0W/winaero_109.png", + "images": [] + }, + "uvicorn": { + "icon": "https://uvicorn.dev/uvicorn.png", + "images": [] + }, + "Winget.XMediaRecode.XMediaRecode": { + "icon": "", + "images": [] + }, + "mirrorforphotoshopserver": { + "icon": "https://raw.githubusercontent.com/hex/mirror-for-photoshop-server/main/assets/icon.png", + "images": [ + "https://raw.githubusercontent.com/hex/mirror-for-photoshop-server/main/assets/screenshot.png" + ] + }, + "jarkviewer": { + "icon": "https://i.postimg.cc/4x7jNZ9r/ico.png", + "images": [ + "https://i.postimg.cc/fW8PckjQ/preview.png" + ] + }, + "fastapi": { + "icon": "https://avatars.githubusercontent.com/u/156354296?s=200&v=4", + "images": [] + }, + "applocate": { + "icon": "https://i.postimg.cc/gkpYhzw7/applocate.png", + "images": [ + "https://i.postimg.cc/fLHDFw0J/applocate-unigetui-sample.png", + "https://i.postimg.cc/jqFR4STS/applocate-unigetui-sample-advanced.png", + "https://i.postimg.cc/pXLnpTZM/applocate-unigetui-sample-json-fromat.png" + ] + }, + "click": { + "icon": "https://i.ibb.co/9H19kg1F/click-logo-1.png", + "images": [] + }, + "lin-ycv.EverythingCmdPal3": { + "icon": "https://store-images.s-microsoft.com/image/apps.25263.13565088367537471.1afd4527-e5f2-4286-ae89-167b4ff891b1.6b1f6c28-e687-4873-982a-ddf8c246ba6e?h=115", + "images": [] + }, + "Python.Launcher": { + "icon": "https://s3.dualstack.us-east-2.amazonaws.com/pythondotorg-assets/media/community/logos/python-logo-only.png", + "images": [] + }, + "pkhex": { + "icon": "https://raw.githubusercontent.com/kwsch/PKHeX/master/icon.png", + "images": [ + "https://camo.githubusercontent.com/691f9203db46580d9f02406a7fd4574a3f0d70ec196bb948b8453469af30f217/68747470733a2f2f692e696d6775722e636f6d2f704948646f54702e706e67" + ] + }, + "nikke": { + "icon": "https://cdn.brandfetch.io/idQEkAXA-z/w/400/h/400/theme/dark/icon.jpeg?c=1bxid64Mup7aczewSAYMX&t=1769771355360", + "images": [ + "https://i.vgy.me/SlaOsN.png" + ] + }, + "Ollama": { + "icon": "https://cdn.brandfetch.io/idrRDmZ2_F/w/400/h/400/theme/dark/icon.jpeg?c=1bxid64Mup7aczewSAYMX&t=1771678337826", + "images": [ + "https://i.vgy.me/Q7ouok.png" + ] + }, + "google-genai": { + "icon": "https://community.chocolatey.org/content/packageimages/google-workspace-sync.4.3.53.0.png", + "images": [ + "https://upload.wikimedia.org/wikipedia/commons/0/01/Google_AI.png" + ] + }, + "langchain-core": { + "icon": "https://images.seeklogo.com/logo-png/61/3/langchain-icon-logo-png_seeklogo-611655.png", + "images": [ + "https://saraceni.me/wp-content/uploads/2025/08/langchain.png" + ] + }, + "npm": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/d/db/Npm-logo.svg/960px-Npm-logo.svg.png", + "images": [ + "https://blog.risingstack.com/wp-content/uploads/2021/07/npm-1466683907227.png" + ] + }, + "ElementLabs.LMStudio": { + "icon": "https://ignos.blog/wp-content/uploads/2024/01/lm-studio-logo.png", + "images": [ + "https://lmstudio.ai/assets/docs/chat.png", + "https://lmstudio.ai/assets/docs/mcp-editor.png", + "https://lmstudio.ai/assets/docs/speculative-decoding-setting.png" + ] + }, + "openclaw": { + "icon": "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/png/openclaw.png", + "images": [ + "https://openclaw.ai/og-image.png" + ] + }, + "opencode-ai": { + "icon": "https://pbs.twimg.com/profile_images/1973794620233433088/nBn75BTm.png", + "images": [ + "https://opencode.ai/social-share.png", + "https://miro.medium.com/v2/resize:fit:1400/1*-hGiynLuhdOZPwsMrqnUuQ.png" + ] + }, + "pydantic_core": { + "icon": "https://opensource.muenchen.de/logo/pydantic.png", + "images": [] + }, + "winget-cli": { + "icon": "https://postimg.cc/LqxRtqj8", + "images": [] + }, + "dotnetfx": { + "icon": "https://community.chocolatey.org/content/packageimages/netfx-4.7.2.4.7.2.0.png", + "images": [] + }, + "dotnetcore": { + "icon": "https://community.chocolatey.org/content/packageimages/dotnetcore.3.1.32.png", + "images": [] + }, + "KB2919442": { + "icon": "https://community.chocolatey.org/content/packageimages/KB2919442.1.0.20160915.png", + "images": [] + }, + "KB2919355": { + "icon": "https://community.chocolatey.org/content/packageimages/KB2919442.1.0.20160915.png", + "images": [] + }, + "KB3033929": { + "icon": "https://community.chocolatey.org/content/packageimages/KB2919442.1.0.20160915.png", + "images": [] + }, + "KB3035131": { + "icon": "https://community.chocolatey.org/content/packageimages/KB2919442.1.0.20160915.png", + "images": [] + }, + "KB3063858": { + "icon": "https://community.chocolatey.org/content/packageimages/KB2919442.1.0.20160915.png", + "images": [] + }, + "microsoft-ui-xaml-2-7": { + "icon": "https://community.chocolatey.org/content/packageimages/microsoft-ui-xaml-2-7.2.7.3.png", + "images": [] + }, + "microsoft-vclibs-140-00": { + "icon": "https://community.chocolatey.org/content/packageimages/KB2919442.1.0.20160915.png", + "images": [] + }, + "activepartitionmanager": { + "icon": "", + "images": [] + }, + "activepartitionrecovery": { + "icon": "", + "images": [] + }, + "activepasswordchanger": { + "icon": "", + "images": [] + }, + "advanceddiskrecovery": { + "icon": "", + "images": [] + }, + "advanceddriverupdater": { + "icon": "", + "images": [] + }, + "advancedsystemoptimizer": { + "icon": "", + "images": [] + }, + "androidmessages-desktop": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/6/67/Google_Messages_icon_%282022%29.svg/128px-Google_Messages_icon_%282022%29.svg.png", + "images": [] + }, + "armagetronadvanced": { + "icon": "", + "images": [] + }, + "avsdisccreator": { + "icon": "", + "images": [] + }, + "axiscamerastation": { + "icon": "", + "images": [] + }, + "azuremediaservicesexplorer": { + "icon": "", + "images": [] + }, + "belgium-eidmiddleware": { + "icon": "https://eid.belgium.be/themes/custom/eid/logo.svg", + "images": [] + }, + "bluegriffon": { + "icon": "", + "images": [] + }, + "bulkimagedownloader": { + "icon": "", + "images": [] + }, + "cambridgereader": { + "icon": "", + "images": [] + }, + "clipboard-manager-electron": { + "icon": "", + "images": [] + }, + "cloudsignatureupdateagent": { + "icon": "", + "images": [] + }, + "coldturkeyblocker": { + "icon": "", + "images": [] + }, + "connectwisemanageclient64-bit": { + "icon": "", + "images": [] + }, + "copytranscontrolcenter": { + "icon": "", + "images": [] + }, + "crowdsecwindowsfirewallbouncer": { + "icon": "", + "images": [] + }, + "deskupdate": { + "icon": "", + "images": [] + }, + "devicemanagementassistant": { + "icon": "", + "images": [] + }, + "dotnet-desktopruntime-preview": { + "icon": "https://raw.githubusercontent.com/dotnetcore-chocolatey/dotnetcore-chocolateypackages/master/icons/dotnetcore.png", + "images": [] + }, + "dotnet-framework-developerpack": { + "icon": "", + "images": [] + }, + "dotnet-hostingbundle-preview": { + "icon": "", + "images": [] + }, + "duo2faauthenticationforwindows": { + "icon": "", + "images": [] + }, + "duplicatecleaner": { + "icon": "", + "images": [] + }, + "duplicatefilesfixer": { + "icon": "", + "images": [] + }, + "duplicatephotosfixer": { + "icon": "", + "images": [] + }, + "electron-markdown-editor": { + "icon": "", + "images": [] + }, + "electron-screen-recorder": { + "icon": "", + "images": [] + }, + "fedora-remix-for-wsl": { + "icon": "", + "images": [] + }, + "flawlesswidescreen": { + "icon": "", + "images": [] + }, + "flybywiresimulatorinstaller": { + "icon": "", + "images": [] + }, + "fotophire-slideshowmaker": { + "icon": "", + "images": [] + }, + "google-assistant-preview": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/c/cb/Google_Assistant_logo.svg/768px-Google_Assistant_logo.svg.png", + "images": [] + }, + "googleplaymusicdesktopplayer": { + "icon": "https://cdn.wccftech.com/wp-content/uploads/2018/01/Youtube-music.png", + "images": [] + }, + "handtrackedcockpitclicking": { + "icon": "", + "images": [] + }, + "hec-dssvue": { + "icon": "", + "images": [] + }, + "hec-metvue": { + "icon": "", + "images": [] + }, + "hec-ressim": { + "icon": "", + "images": [] + }, + "heroicgameslauncher": { + "icon": "", + "images": [] + }, + "inteldriverandsupportassistant": { + "icon": "", + "images": [] + }, + "intellijidea-community-eap": { + "icon": "https://resources.jetbrains.com/storage/products/intellij-idea/img/meta/intellij-idea_logo_300x300.png", + "images": [] + }, + "microsoftvirtualearthsatellitemaps": { + "icon": "", + "images": [] + }, + "minecraftnoteblockstudio": { + "icon": "", + "images": [] + }, + "moonmodeler": { + "icon": "", + "images": [] + }, + "msbuildstructuredlogviewer": { + "icon": "", + "images": [] + }, + "music-pattern-generator": { + "icon": "https://community.chocolatey.org/content/packageimages/music-collector.22.0.6.png", + "images": [] + }, + "openvpn-configuration-generator": { + "icon": "", + "images": [] + }, + "oxfordlearnersbookshelf": { + "icon": "", + "images": [] + }, + "pathofbuilding": { + "icon": "", + "images": [] + }, + "powerpanelpersonal": { + "icon": "", + "images": [] + }, + "prowritingaid": { + "icon": "", + "images": [] + }, + "puloversmacrocreator": { + "icon": "", + "images": [] + }, + "qbittorrent-enhanced-edition": { + "icon": "", + "images": [] + }, + "qemuguestagent": { + "icon": "", + "images": [] + }, + "registrarregistrymanager": { + "icon": "", + "images": [] + }, + "remotedesktopmanagerfree": { + "icon": "", + "images": [] + }, + "rubywithdevkit-2-7": { + "icon": "", + "images": [] + }, + "rubywithdevkit-3-2": { + "icon": "", + "images": [] + }, + "satisfactorymodmanager": { + "icon": "", + "images": [] + }, + "softperfectnetworkscanner": { + "icon": "", + "images": [] + }, + "splashtopstreamer-deployment": { + "icon": "", + "images": [] + }, + "stellarextractor": { + "icon": "", + "images": [] + }, + "surfaceduoemulator-android11": { + "icon": "", + "images": [] + }, + "svgexplorerextension": { + "icon": "", + "images": [] + }, + "syncoutlookandgooglecalendar": { + "icon": "", + "images": [] + }, + "sysinternals-processexplorer": { + "icon": "https://learn.microsoft.com/en-us/sysinternals/media/index/sysinternals.png", + "images": [] + }, + "sysinternals-processmonitor": { + "icon": "https://learn.microsoft.com/en-us/sysinternals/media/index/sysinternals.png", + "images": [] + }, + "systweaksoftwareupdater": { + "icon": "", + "images": [] + }, + "teams-continuousdeployment": { + "icon": "", + "images": [] + }, + "ti-nspire-computerlink": { + "icon": "", + "images": [] + }, + "ti-nspire-cxcasstudent": { + "icon": "", + "images": [] + }, + "ti-nspire-cxpremiumteacher": { + "icon": "", + "images": [] + }, + "ti-nspire-cxstudent": { + "icon": "", + "images": [] + }, + "ti-smartview-mathprint": { + "icon": "", + "images": [] + }, + "ti-smartview-ti-cx": { + "icon": "", + "images": [] + }, + "toontowncorporateclash": { + "icon": "", + "images": [] + }, + "torpedoremote": { + "icon": "", + "images": [] + }, + "transmissionremotegui": { + "icon": "", + "images": [] + }, + "tweakshotscreencapture": { + "icon": "", + "images": [] + }, + "universalmediaserver": { + "icon": "https://www.universalmediaserver.com/assets/img/logo.png", + "images": [] + }, + "unlimited-clipboard": { + "icon": "", + "images": [] + }, + "usefultoolsforwindows": { + "icon": "", + "images": [] + }, + "virtualmagnifyingglass": { + "icon": "", + "images": [] + }, + "virtualserialporttools": { + "icon": "", + "images": [] + }, + "visualsvnrepositoryconfigurator": { + "icon": "", + "images": [] + }, + "vivaldi-snapshot": { + "icon": "https://vivaldi.com/wp-content/uploads/cropped-viv_icon-500px.png", + "images": [] + }, + "watchguardsystemmanager": { + "icon": "", + "images": [] + }, + "windowcenteringhelper": { + "icon": "", + "images": [] + }, + "windowsinstallationassistant": { + "icon": "", + "images": [] + }, + "windowssubsystemforlinux": { + "icon": "https://i.postimg.cc/c4TB1sTf/wsl-icon.png", + "images": [ + "https://i.postimg.cc/9QnPTJ6M/wsl1.png" + ] + }, + "windowsvirtualdesktopagent": { + "icon": "", + "images": [] + }, + "windowsvirtualdesktopbootloader": { + "icon": "", + "images": [] + }, + "youtubemusicfordesktop": { + "icon": "", + "images": [] + }, + "youtubevideodownloader": { + "icon": "", + "images": [] + }, + "activebackupforbusinessagent": { + "icon": "", + "images": [] + } + } +} diff --git a/WebBasedData/screenshot-database.json b/WebBasedData/screenshot-database.json new file mode 100644 index 0000000..813a3b8 --- /dev/null +++ b/WebBasedData/screenshot-database.json @@ -0,0 +1,21582 @@ +{ + "package_count": { + "winget": 3863, + "scoop": 1092, + "total": 4955, + "done": 473 + }, + "winget": { + "115.115Chrome": { + "icon": "https://i.imgur.com/5fSfmJl.png", + "images": [ + "https://pc.115.com/static/pc/images/pc_banner@2x.png", + "https://pc.115.com/static/tv/images/tv_clinet_pic@2x.png", + "https://pc.115.com/static/tv/images/web_mvpage@2x.png", + "https://pc.115.com/static/tv/images/web_albumpage@2x.png", + "https://pc.115.com/static/tv/images/web_audiopage@2x.png" + ] + }, + "1ic.BPMN-RPAstudio": { + "icon": "", + "images": [] + }, + "1MHz.Knotes": { + "icon": "", + "images": [] + }, + "1zilc.FishingFunds": { + "icon": "", + "images": [] + }, + "2BrightSparks.SyncBackFree": { + "icon": "https://www.2brightsparks.com/assets/logo-blue-288x288-trans.png", + "images": [] + }, + "2BrightSparks.SyncBackPro": { + "icon": "https://www.2brightsparks.com/assets/logo-blue-288x288-trans.png", + "images": [] + }, + "2BrightSparks.SyncBackSE": { + "icon": "https://www.2brightsparks.com/assets/logo-blue-288x288-trans.png", + "images": [] + }, + "360.360Chrome": { + "icon": "https://1.bp.blogspot.com/-3IeAb5s0t7Q/Xk-ESZ9EU3I/AAAAAAAACuY/MxkpFzOGH1crDT0Q7UnqM51TV3gkK2K3QCNcBGAsYHQ/s310-c/360chrome-11.png", + "images": [ + "https://images.sftcdn.net/images/t_app-cover-l,f_auto/p/4e860d5b-18bd-4216-bd39-e703553c49a1/3838871850/360-browser-images%20(8).jpg", + "https://cdn.lo4d.com/t/screenshot/360-browser-3.png" + ] + }, + "360.360Chrome.X": { + "icon": "https://1.bp.blogspot.com/-3IeAb5s0t7Q/Xk-ESZ9EU3I/AAAAAAAACuY/MxkpFzOGH1crDT0Q7UnqM51TV3gkK2K3QCNcBGAsYHQ/s310-c/360chrome-11.png", + "images": [ + "https://images.sftcdn.net/images/t_app-cover-l,f_auto/p/4e860d5b-18bd-4216-bd39-e703553c49a1/3838871850/360-browser-images%20(8).jpg", + "https://cdn.lo4d.com/t/screenshot/360-browser-3.png" + ] + }, + "360.360CleanMaster": { + "icon": "https://imgur.com/zFifzGq.png", + "images": [ + "https://p0.ssl.qhmsg.com/dr/510__100/t0162c6333044e14f4f.png" + ] + }, + "360.360GT": { + "icon": "https://imgur.com/arldkgB.png", + "images": [ + "https://se3.360simg.com/dr/996__80/t01c084e8fb0a69b9d3.jpg", + "https://se3.360simg.com/dr/996__80/t01eac9e03abf4b71d0.jpg", + "https://se2.360simg.com/dr/996__80/t01ddb19fa70197ec64.jpg", + "https://se3.360simg.com/dr/996__80/t014a6a9851a4356e84.jpg" + ] + }, + "360.360SE": { + "icon": "https://i.imgur.com/OTgnwGn.png", + "images": [ + "https://se1.360simg.com/t01556df2aa6ab462bc.jpg", + "https://se2.360simg.com/t01bc71221790eac009.jpg", + "https://se2.360simg.com/t01f6f305ac16a617ce.jpg", + "https://se2.360simg.com/t01000f2ee1d3caf0a0.jpg" + ] + }, + "360.360Zip": { + "icon": "https://static.360totalsecurity.com/home/images/zip/box-112dab92.png", + "images": [ + "https://i0.wp.com/crast.net/img/2022/05/1652364831_571_Save-disk-space-with-this-360-Total-Security-program.jpg", + "https://www.xiaoyi.vc/wp-content/uploads/2020/01/360zip.png" + ] + }, + "360.PalmInput": { + "icon": "", + "images": [] + }, + "3CX.CallFlowDesigner": { + "icon": "https://www.carierista.com/storage/companies/150/2d05df55a3399d793cfbd01657052b4d.png", + "images": [ + "https://www.3cx.com/wp-content/uploads/2017/05/screenshot_1.png", + "https://www.3cx.com/wp-content/uploads/2021/08/cfd.png", + "https://i.ytimg.com/vi/wBRFPCBQjLE/maxresdefault.jpg", + "https://aatroxcommunications.com.au/wp-content/uploads/2019/05/create-project.jpg" + ] + }, + "3CX.Softphone": { + "icon": "https://imgur.com/YJszAke.png", + "images": [ + "https://www.3cx.com/wp-content/uploads/2013/07/beta-release-3-1-opt.png", + "https://www.3cx.com/wp-content/uploads/2013/10/sp-2-image-1-opt.png", + "https://eteletech.com/wp-content/uploads/2015/12/3cx.jpg" + ] + }, + "3ll3d00d.beqdesigner": { + "icon": "", + "images": [] + }, + "3T.Robo3T": { + "icon": "https://i.imgur.com/XSYqe6j.png", + "images": [] + }, + "4gray.iptvnator": { + "icon": "https://i.imgur.com/GFJ1R73.png", + "images": [] + }, + "4tNiagaraSoftware.4tTrayMinimizer": { + "icon": "https://imgur.com/QSc6fq3.png", + "images": [ + "https://www.4t-niagara.com/images/tray_screen_small.png", + "https://windows-cdn.softpedia.com/screenshots/4t-Tray-Minimizer-Free_1.png" + ] + }, + "64Gram.64Gram": { + "icon": "https://imgur.com/cvfaDrq.png", + "images": [ + "https://raw.githubusercontent.com/TDesktop-x64/tdesktop/dev/docs/assets/preview.png" + ] + }, + "720kb.ndm": { + "icon": "", + "images": [] + }, + "7room.Aya": { + "icon": "https://user-images.githubusercontent.com/2874236/75116104-fcc2ab00-5675-11ea-91af-0e8e04df8a46.png", + "images": [ + "https://user-images.githubusercontent.com/2874236/75115994-0dbeec80-5675-11ea-93a1-33f4e5fb9e70.png" + ] + }, + "7S2P.Effie": { + "icon": "", + "images": [] + }, + "7S2P.Effie.CN": { + "icon": "", + "images": [] + }, + "7zip.7zip": { + "icon": "https://findicons.com/files/icons/1008/quiet/256/7zip.png", + "images": [ + "https://a.fsdn.com/con/app/proj/sevenzip/screenshots/534500_4.png", + "https://cdn.mos.cms.futurecdn.net/0c3ce5fdf135bb76208e0558845eb98c-1200-80.jpg", + "https://www.wikihow.com/images/thumb/e/e2/Highly-Compress-Files-with-7zip-Step-3.jpg/v4-460px-Highly-Compress-Files-with-7zip-Step-3.jpg" + ] + }, + "7zip.7zip.Alpha.exe": { + "icon": "https://findicons.com/files/icons/1008/quiet/256/7zip.png", + "images": [ + "https://a.fsdn.com/con/app/proj/sevenzip/screenshots/534500_4.png", + "https://cdn.mos.cms.futurecdn.net/0c3ce5fdf135bb76208e0558845eb98c-1200-80.jpg", + "https://www.wikihow.com/images/thumb/e/e2/Highly-Compress-Files-with-7zip-Step-3.jpg/v4-460px-Highly-Compress-Files-with-7zip-Step-3.jpg" + ] + }, + "7zip.7zip.Alpha.msi": { + "icon": "https://findicons.com/files/icons/1008/quiet/256/7zip.png", + "images": [ + "https://a.fsdn.com/con/app/proj/sevenzip/screenshots/534500_4.png", + "https://cdn.mos.cms.futurecdn.net/0c3ce5fdf135bb76208e0558845eb98c-1200-80.jpg", + "https://www.wikihow.com/images/thumb/e/e2/Highly-Compress-Files-with-7zip-Step-3.jpg/v4-460px-Highly-Compress-Files-with-7zip-Step-3.jpg" + ] + }, + "8x8.VirtualOfficeDesktop": { + "icon": "https://store-images.s-microsoft.com/image/apps.48237.19d1bd6a-9d62-497a-9418-a5027e36aa13.674cc665-b0fd-4782-ba73-36706eddee01.6e1155d9-6a72-4301-a674-5a08f355ac26.png", + "images": [ + "https://ik.imagekit.io/8x8/36BRYSitRR2mUasBs39Pr4.jpg", + "https://ik.imagekit.io/8x8/gd26UTUHjE8KQyCXtPQgQx.jpg", + "https://docs.8x8.com/8x8WebHelp/8x8analytics-virtual-office/Content/Resources/Images/VO%20Analytics%20-Overview/company-summary-new.png" + ] + }, + "A-SIT.PDF-Over": { + "icon": "", + "images": [] + }, + "AAAInternetPublishing.WTFast": { + "icon": "", + "images": [] + }, + "Aardappel.Cube": { + "icon": "https://i.imgur.com/bWnk6NQ.png", + "images": [] + }, + "AAS.WorldWideTelescope": { + "icon": "https://i.imgur.com/b8UUC9y.png", + "images": [ + "https://windows-cdn.softpedia.com/screenshots/WorldWide-Telescope_17.png", + "https://windows-cdn.softpedia.com/screenshots/WorldWide-Telescope_18.png", + "https://www.thewindowsclub.com/wp-content/uploads/2015/08/WorldWide-Telescope.jpg" + ] + }, + "Abacus.AbaClient": { + "icon": "https://i.imgur.com/zXixk8q.png", + "images": [ + "https://docplayer.org/docs-images/109/187115837/images/7-0.jpg", + "https://i.imgur.com/mEWcJzg.png", + "https://www.obt.ch/resources/folders/18/20181205-abacus-start-neu-mit-abaclient.jpg" + ] + }, + "AbdelrahmanBayoumi.Azkar": { + "icon": "https://i.imgur.com/iY6QivM.png", + "images": [ + "https://user-images.githubusercontent.com/48678280/174669335-b9cdf440-4ba4-48a6-a218-addb0c749db6.png", + "https://user-images.githubusercontent.com/48678280/141684574-ad164c5a-ac22-4c27-8774-6847e10cde3b.jpg", + "https://user-images.githubusercontent.com/48678280/141684402-51d9a132-2dad-4648-ad4f-d6cf814a9c93.png" + ] + }, + "Ability.AbilityOffice.10.Professio\u2026": { + "icon": "", + "images": [] + }, + "Ability.AbilityOffice.10.Standard": { + "icon": "https://i.imgur.com/M2EY1us.png", + "images": [ + "https://www.ability.com/images/standard_box.png", + "https://getintopc.today/wp-content/uploads/2021/12/Ability-Office.png", + "https://windows-cdn.softpedia.com/screenshots/Ability-Office_1.png", + "https://img.creativemark.co.uk/uploads/images/670/22670/img5File.jpg" + ] + }, + "Ability.AbilityOffice.8.Profession\u2026": { + "icon": "", + "images": [] + }, + "Ability.AbilityOffice.8.Standard": { + "icon": "https://i.imgur.com/M2EY1us.png", + "images": [ + "https://winningpc.com/wp-content/uploads/2020/08/Ability-Office-Standard-Boxshot.jpg", + "https://thesoftwareshop.b-cdn.net/wp-content/uploads/2019/09/Ability-Office-8-Standard-Presentation.png", + "https://m.media-amazon.com/images/I/812bFV2A7yL._AC_SL1281_.jpg", + "https://m.media-amazon.com/images/I/71kyNjr3gmL._AC_SL1279_.jpg" + ] + }, + "AbiSource.AbiWord": { + "icon": "https://i.imgur.com/qnBf8D1.png", + "images": [ + "http://www.abisource.com/screenshots/abi-win32.thumb.jpg", + "http://www.abisource.com/screenshots/abi-yiddish.thumb.jpg" + ] + }, + "Abyss.AbyssOverlay": { + "icon": "https://user-images.githubusercontent.com/61895718/111565782-5ced2900-8772-11eb-9c43-c8801fc2a1a8.png", + "images": [ + "https://i.imgur.com/92gMTyo.png", + "https://i.imgur.com/KENrNHj.png" + ] + }, + "acaudwell.Gource": { + "icon": "", + "images": [] + }, + "AcFun.AcFunVirtualTool": { + "icon": "https://i.imgur.com/JWlDMfh.png", + "images": [ + "https://i.imgur.com/qD3qwQ3.png", + "https://i.imgur.com/gs0jRFj.png", + "https://i.imgur.com/TN1ZFJQ.png", + "https://i.imgur.com/clFQlOC.png", + "https://i.imgur.com/CwZwk9H.png" + ] + }, + "AcFun.ARLiveForAcfunLive": { + "icon": "", + "images": [ + "https://img.81857.net/2020/0817/20200817013305783.jpg", + "https://img.8xia.com/uploadfile/2020/0805/20200805024353291.png" + ] + }, + "Acronis.CyberProtectHomeOffice": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/8/86/Acronis_True_Image_2015_icon.png", + "images": [ + "https://staticfiles.acronis.com/images/content/f086c44f7bcffdc3be4da4d39d4bf28b.jpg", + "https://kb.acronis.com/system/files/content/2021/09/69472/69472_01.png", + "https://i.pcmag.com/imagery/reviews/04JiWbx5aUrJ5O6dTdfkFaH-23.fit_lim.size_1050x.png", + "https://kb.acronis.com/system/files/content/2021/09/69477/69477_01.png" + ] + }, + "AcroSoftware.CutePDFWriter": { + "icon": "", + "images": [] + }, + "ACROSSecurity.0patch": { + "icon": "https://imgur.com/YHwGP6l.png", + "images": [ + "https://0patch.com/img/0patch-rac1.png", + "https://0patch.com/img/extra/0patchCentral.jpg", + "https://0patch.com/img/extra/Windows_7_adopted.png" + ] + }, + "Actifile.ActifileAgent": { + "icon": "https://i.imgur.com/WoPZ1HB.png", + "images": [ + "https://static.wixstatic.com/media/10e96b_df7e3b0f52234ec9940b60815cd0a8f1~mv2.png/v1/fill/w_560,h_330,al_c,q_85,usm_0.66_1.00_0.01,enc_auto/Actifile%20-%20Introduction%20May%202022%20-1.png", + "https://www.bitcyber.com.sg/wp-content/uploads/2021/07/Actifile-Risk-Assessment-600x305-1.jpg" + ] + }, + "ActiveState.KomodoEdit": { + "icon": "https://cdn.activestate.com/wp-content/uploads/2018/10/komodo-ide-icon-512x512.png", + "images": [ + "https://cdn.activestate.com/wp-content/uploads/2018/10/edit-vs-ide.png" + ] + }, + "ActiveState.KomodoIDE": { + "icon": "https://cdn.activestate.com/wp-content/uploads/2018/10/komodo-ide-icon-512x512.png", + "images": [ + "https://cdn.activestate.com/wp-content/uploads/2020/01/komodo-activestate-platform-integration-500x250.png", + "https://cdn.activestate.com/wp-content/uploads/2018/09/codeintel-500x250.png", + "https://cdn.activestate.com/wp-content/uploads/2018/09/devdocs-500x250.png", + "https://cdn.activestate.com/wp-content/uploads/2018/09/preview.gif" + ] + }, + "ActivityWatch.ActivityWatch": { + "icon": "https://i.imgur.com/0fNCI9J.png", + "images": [ + "https://activitywatch.net/img/screenshots/screenshot-v0.9.3-activity.png", + "https://activitywatch.net/img/screenshots/screenshot-v0.8.0b9-timeline.png", + "https://activitywatch.net/img/screenshots/BelKed/screenshot-v0.12.0b2-activity.png" + ] + }, + "Adamant.Messenger": { + "icon": "https://i.imgur.com/PZmD7cN.png", + "images": [ + "https://i.imgur.com/9PCvI22.png", + "https://i.imgur.com/7mPy8kQ.png", + "https://i.imgur.com/zVq5B1X.jpg" + ] + }, + "AdamMiskiewicz.GraphiQL": { + "icon": "", + "images": [] + }, + "AderitoNeto.AfterLife": { + "icon": "https://github.com/ad3rito/AfterLife/blob/master/src/icon/rocket.png?raw=true", + "images": [ + "https://raw.githubusercontent.com/AderitoNeto/AfterLife/Master/src/images/Readme/1.PNG", + "https://raw.githubusercontent.com/AderitoNeto/AfterLife/Master/src/images/Readme/2.PNG", + "https://raw.githubusercontent.com/AderitoNeto/AfterLife/Master/src/images/Readme/3.PNG", + "https://raw.githubusercontent.com/AderitoNeto/AfterLife/Master/src/images/Readme/4.PNG", + "https://raw.githubusercontent.com/AderitoNeto/AfterLife/Master/src/images/Readme/5.PNG", + "https://raw.githubusercontent.com/AderitoNeto/AfterLife/Master/src/images/Readme/6.PNG", + "https://raw.githubusercontent.com/AderitoNeto/AfterLife/Master/src/images/Readme/7.PNG" + ] + }, + "AdGuard.AdGuard": { + "icon": "https://cdn.adtidy.org/website/adguard.com/favicons/favicon.svg", + "images": [ + "https://adguard.com/img/social/og-main.png", + "https://cdn.adguard.com/public/Adguard/Common/adguard_home.gif", + "https://static.filehorse.com/screenshots/firewalls-and-security/adguard-screenshot-01.png", + "https://static.filehorse.com/screenshots/firewalls-and-security/adguard-screenshot-02.png" + ] + }, + "AdGuard.AdGuardVPN": { + "icon": "https://i.imgur.com/tvlrfxJ.png", + "images": [ + "https://ph-files.imgix.net/1d1c0f41-8752-4bcc-b469-93a569909b31.png", + "https://cdn.adguardvpn.com/website/adguard-vpn.com/products/win-mac.png", + "https://windows-cdn.softpedia.com/screenshots/AdGuard-VPN_1.png" + ] + }, + "Admobilize.AdMobilize.DesktopUI": { + "icon": "https://i.imgur.com/db7YcHx.png", + "images": [ + "https://venturebeat.com/wp-content/uploads/2015/07/AdMobilize.png", + "https://www.helloooh.com/wp-content/uploads/2016/06/proof-of-engagement-website.gif" + ] + }, + "Admobilize.AdMobilize.MalosVision": { + "icon": "", + "images": [] + }, + "Admobilize.AdMobilize.VisionService": { + "icon": "https://i.imgur.com/db7YcHx.png", + "images": [] + }, + "Admobilize.admprovider": { + "icon": "https://i.imgur.com/db7YcHx.png", + "images": [] + }, + "Adobe.Acrobat.Reader.32-bit": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/e/ea/Adobe_Acrobat_DC_icon.png", + "images": [ + "https://img-19.ccm.net/fheSH8Cl0detgNX2J1v2QAgMrR4=/450x/smart/4b36b6809e574683aa645cf6023a7c52/ccmcms-enccm/35559148.png", + "https://cdn.mos.cms.futurecdn.net/bKeFKKwEaBtyJwwCDWhsu5-1200-80.jpg", + "https://gdm-catalog-fmapi-prod.imgix.net/ProductScreenshot/02aadd42-87e9-45a6-9b74-09224415adf0.jpeg", + "https://imag.malavida.com/mvimgbig/download-fs/adobe-reader-293-1.jpg", + "https://imag.malavida.com/mvimgbig/download-fs/adobe-reader-293-3.jpg" + ] + }, + "Adobe.Acrobat.Reader.64-bit": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/e/ea/Adobe_Acrobat_DC_icon.png", + "images": [ + "https://img-19.ccm.net/fheSH8Cl0detgNX2J1v2QAgMrR4=/450x/smart/4b36b6809e574683aa645cf6023a7c52/ccmcms-enccm/35559148.png", + "https://cdn.mos.cms.futurecdn.net/bKeFKKwEaBtyJwwCDWhsu5-1200-80.jpg", + "https://gdm-catalog-fmapi-prod.imgix.net/ProductScreenshot/02aadd42-87e9-45a6-9b74-09224415adf0.jpeg", + "https://imag.malavida.com/mvimgbig/download-fs/adobe-reader-293-1.jpg", + "https://imag.malavida.com/mvimgbig/download-fs/adobe-reader-293-3.jpg" + ] + }, + "Adobe.AdobeConnect": { + "icon": "https://cdn.iconscout.com/icon/free/png-256/adobe-connect-2521767-2132659.png", + "images": [ + "https://i.imgur.com/RG7wdZ0.jpg", + "https://i.imgur.com/Jg0q7UW.jpg", + "https://i.imgur.com/twirlCd.jpg", + "https://i.imgur.com/v28qeiM.jpg", + "https://i.imgur.com/kvcw9n1.jpg", + "https://i.imgur.com/z0bh5vW.jpg", + "https://i.imgur.com/yCDdBnJ.jpg" + ] + }, + "Adobe.Brackets": { + "icon": "", + "images": [] + }, + "Adobe.Cryptr": { + "icon": "", + "images": [ + "https://i.imgur.com/xXKaOEm.png" + ] + }, + "Adobe.DNGConverter": { + "icon": "https://i.imgur.com/IHM1AHJ.png", + "images": [ + "https://thumb.tildacdn.com/tild3862-6566-4331-a138-376239646663/-/resize/824x/-/format/webp/tilda-page-adobe-dng.png", + "https://codecpack.co/images/Adobe-DNG-Converter.png", + "https://helpx.adobe.com/content/dam/help/en/photoshop/using/adobe-dng-converter/jcr_content/main-pars/image_0/DNGConverter.jpg.img.jpg", + "https://helpx.adobe.com/content/dam/help/en/photoshop/using/adobe-dng-converter/jcr_content/main-pars/image/DNGPrefs.jpg.img.jpg" + ] + }, + "AdoptOpenJDK.OpenJDK.11": { + "icon": "https://projects.eclipse.org/sites/default/files/Logo_Adoptium_2021_03_08_JRR_RGB-V3C%20%281%29.png", + "images": [ + "https://adoptopenjdk.net/dist/assets/social-image.png", + "https://www.somkiat.cc/wp-content/uploads/2021/10/adoptium.jpg" + ] + }, + "AdoptOpenJDK.OpenJDK.14": { + "icon": "https://projects.eclipse.org/sites/default/files/Logo_Adoptium_2021_03_08_JRR_RGB-V3C%20%281%29.png", + "images": [ + "https://adoptopenjdk.net/dist/assets/social-image.png", + "https://www.somkiat.cc/wp-content/uploads/2021/10/adoptium.jpg" + ] + }, + "AdoptOpenJDK.OpenJDK.15": { + "icon": "https://projects.eclipse.org/sites/default/files/Logo_Adoptium_2021_03_08_JRR_RGB-V3C%20%281%29.png", + "images": [ + "https://adoptopenjdk.net/dist/assets/social-image.png", + "https://www.somkiat.cc/wp-content/uploads/2021/10/adoptium.jpg" + ] + }, + "AdoptOpenJDK.OpenJDK.16": { + "icon": "https://projects.eclipse.org/sites/default/files/Logo_Adoptium_2021_03_08_JRR_RGB-V3C%20%281%29.png", + "images": [ + "https://adoptopenjdk.net/dist/assets/social-image.png", + "https://www.somkiat.cc/wp-content/uploads/2021/10/adoptium.jpg" + ] + }, + "AdoptOpenJDK.OpenJDK.17": { + "icon": "https://projects.eclipse.org/sites/default/files/Logo_Adoptium_2021_03_08_JRR_RGB-V3C%20%281%29.png", + "images": [ + "https://adoptopenjdk.net/dist/assets/social-image.png", + "https://www.somkiat.cc/wp-content/uploads/2021/10/adoptium.jpg" + ] + }, + "AdoptOpenJDK.OpenJDK.8": { + "icon": "https://projects.eclipse.org/sites/default/files/Logo_Adoptium_2021_03_08_JRR_RGB-V3C%20%281%29.png", + "images": [ + "https://adoptopenjdk.net/dist/assets/social-image.png", + "https://www.somkiat.cc/wp-content/uploads/2021/10/adoptium.jpg" + ] + }, + "AdrienAllard.FileConverter": { + "icon": "https://file-converter.org/images/application-icon.png", + "images": [ + "https://i.postimg.cc/CK1Yn290/ss2.png", + "https://file-converter.org/images/screenshot3.png" + ] + }, + "advancedfx.HLAE": { + "icon": "", + "images": [] + }, + "Aegisub.Aegisub": { + "icon": "https://icons.iconarchive.com/icons/papirus-team/papirus-apps/512/aegisub-icon.png", + "images": [ + "https://i0.wp.com/www.l10nsoftware.com/wp-content/uploads/2019/07/Aegisub-1.jpg", + "https://static.filehorse.com/screenshots/video-software/aegisub-screenshot-03.png", + "https://upload.wikimedia.org/wikipedia/commons/4/44/Aegisub_screenshot.png", + "https://upload.wikimedia.org/wikipedia/commons/a/a0/Aegisub_2_screenshot.png", + "https://cdn.afterdawn.fi/screenshots/normal/4448.jpg" + ] + }, + "Aegisub.Aegisub.Dev": { + "icon": "https://icons.iconarchive.com/icons/papirus-team/papirus-apps/512/aegisub-icon.png", + "images": [ + "https://i0.wp.com/www.l10nsoftware.com/wp-content/uploads/2019/07/Aegisub-1.jpg", + "https://static.filehorse.com/screenshots/video-software/aegisub-screenshot-03.png", + "https://upload.wikimedia.org/wikipedia/commons/4/44/Aegisub_screenshot.png", + "https://upload.wikimedia.org/wikipedia/commons/a/a0/Aegisub_2_screenshot.png", + "https://cdn.afterdawn.fi/screenshots/normal/4448.jpg" + ] + }, + "Aether.Aether": { + "icon": "https://i.imgur.com/LwEIsPC.png", + "images": [ + "https://getaether.net/images/product-images-v2/pi-1.png", + "https://getaether.net/images/product-images-v2/pi-2.png", + "https://getaether.net/images/product-images-v2/pi-3.png", + "https://getaether.net/images/product-images-v2/pi-4.png", + "https://getaether.net/images/product-images-v2/pi-5.png" + ] + }, + "afractal.Echo": { + "icon": "", + "images": [ + "https://i.imgur.com/HRpmT0v.png" + ] + }, + "afractal.Metronome": { + "icon": "", + "images": [ + "https://i.imgur.com/bDHGwjV.png", + "https://i.imgur.com/N9k3j4n.png", + "https://i.imgur.com/gh4c7L2.png" + ] + }, + "afractal.TwitterTron": { + "icon": "", + "images": [] + }, + "agalwood.Motrix": { + "icon": "", + "images": [] + }, + "AGFEO.AGFEODashboard": { + "icon": "https://agfeo.de/wp-content/uploads/2020/03/6_Icon_APP_3.png", + "images": [ + "https://i.ytimg.com/vi/4TXgtD4NEVg/maxresdefault.jpg", + "https://www.plenom.com/wp-content/uploads/2019/06/Screenshot-af-AGFEO-1024x539.jpg", + "https://www.agfeo-service.de/media/images/dashboard1.jpg", + "https://docplayer.org/docs-images/111/198726594/images/45-1.jpg", + "https://docplayer.org/docs-images/111/198726594/images/9-1.jpg" + ] + }, + "AgileBits.1Password": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/5/5b/1Password_icon.png", + "images": [ + "https://developer.1password.com/img/meta-og-image.png", + "https://1password.com/img/tour/storage.6b7de1841abbfabf58300e55c8832b8b.png", + "https://1password.com/img/tour/security.a8d93c2a861e79fe51636df1ecf5fa9d.png", + "https://1password.com/img/tour/watchtower.5279b033f16276640b046442f41e8c9a.png" + ] + }, + "Agilent.LabAdvisor": { + "icon": "https://img.informer.com/icons/png/128/3924/3924343.png", + "images": [ + "https://www.agilent.com/cs/publishingimages/LabAdvisor_Main_Screen_zoomtb.jpg", + "https://www.agilent.com/cs/publishingimages/LabAdvisor_Apps_Screen_zoomtb.jpg", + "https://www.agilent.com/cs/publishingimages/LabAdvisor_Configuration_Screen_zoomtb.jpg", + "https://www.agilent.com/cs/publishingimages/LabAdvisor_Data_Sharing_Screen_zoomtb.jpg", + "https://www.agilent.com/cs/publishingimages/LabAdvisor_Instrument_Control_Screen_zoomtb.jpg", + "https://www.agilent.com/cs/publishingimages/LabAdvisor_Logs_and_Results_Screen_zoomtb.jpg" + ] + }, + "AGSProjectTeam.AdventureGameStudio": { + "icon": "https://i.imgur.com/mmvoQoN.png", + "images": [ + "https://startupstash.com/wp-content/uploads/2022/07/adventure-game-studio.jpg", + "https://upload.wikimedia.org/wikipedia/commons/thumb/1/1b/AGS_SCI_template_Room_1.png/1200px-AGS_SCI_template_Room_1.png", + "https://www.adventuregamestudio.co.uk/images/editorscreen1large.png", + "https://www.adventuregamestudio.co.uk/images/editorscreen2large.png", + "https://www.adventuregamestudio.co.uk/images/editorscreen3large.png", + "https://www.adventuregamestudio.co.uk/images/editorscreen4large.png" + ] + }, + "ahkohd.switch": { + "icon": "", + "images": [] + }, + "Ahlyab.PasswordChecker": { + "icon": "", + "images": [] + }, + "Ahlyab.UdemyCouponFetcher": { + "icon": "", + "images": [] + }, + "AIMP.AIMP": { + "icon": "https://cdn2.iconfinder.com/data/icons/flurry-for-audio/512/aimp2.png", + "images": [ + "https://windows-cdn.softpedia.com/screenshots/Portable-AIMP_3.jpg", + "https://www.aimp.ru/v2/pages/features/afw_main-6.png", + "https://upload.wikimedia.org/wikipedia/en/6/6a/AIMP_4_screenshot.png", + "https://www.ghacks.net/wp-content/uploads/2017/10/aimp4-5.png", + "https://www.ghacks.net/wp-content/uploads/2012/11/aimp3.20.jpg", + "https://www.lightbook.org/wp-content/uploads/2018/02/AIMP-2018-1-2.jpg" + ] + }, + "AirDroid.AirDroid": { + "icon": "https://i.imgur.com/fJP42G4.png", + "images": [ + "https://i.imgur.com/zkSlJYh.png", + "https://i.imgur.com/x7oZtJr.png", + "https://img-5-cdn.airdroid.com/assets/img/home/lg/pic_biz_personal-b66cf87561.png", + "https://help.airdroid.com/hc/article_attachments/360048877974/How_to_record_phone_screen_in_AirMirror_p1.JPG" + ] + }, + "AirExplorer.AirExplorer": { + "icon": "https://www.airexplorer.net/en/wp-content/uploads/sites/2/2019/10/cropped-cloud512.png", + "images": [ + "https://www.airexplorer.net/en/wp-content/uploads/sites/2/2019/11/motivoIndex_windows-2.png", + "https://www.airexplorer.net/en/wp-content/uploads/sites/2/2020/09/screenshot_sharelink_black.png", + "https://www.airexplorer.net/en/wp-content/uploads/sites/2/2019/10/cropped-motivo_ayuda_03_en.png" + ] + }, + "Airsquared.Blobsaver": { + "icon": "", + "images": [] + }, + "AirVPN.Eddie": { + "icon": "", + "images": [] + }, + "Airytec.SwitchOff": { + "icon": "https://www.softwarecrew.com/wp-content/uploads/2013/03/AiryTecSwitchOffLogo200-175.png", + "images": [ + "http://www.airytec.com/images/en/screenshots/schedule.png", + "http://www.airytec.com/images/en/screenshots/one-click.png", + "http://www.airytec.com/images/en/screenshots/web-interface.png", + "http://www.airytec.com/images/en/screenshots/notifyicon.png" + ] + }, + "Aiursoft.Kahla": { + "icon": "", + "images": [] + }, + "AivarAnnamaa.Thonny": { + "icon": "", + "images": [] + }, + "AkelPad.AkelPad": { + "icon": "https://static.wikia.nocookie.net/logopedia/images/c/c4/Notepad_Vista_10.png", + "images": [ + "https://akelpad.sourceforge.net/files/screen_basic.png", + "https://akelpad.sourceforge.net/files/screen_plugins.png" + ] + }, + "Alacritty.Alacritty": { + "icon": "https://raw.githubusercontent.com/alacritty/alacritty/master/extra/logo/compat/alacritty-term%2Bscanlines.png", + "images": [ + "https://i.ytimg.com/vi/S5ra0DUDZww/maxresdefault.jpg", + "https://user-images.githubusercontent.com/8886672/103264352-5ab0d500-49a2-11eb-8961-02f7da66c855.png", + "https://windows-cdn.softpedia.com/screenshots/Alacritty_1.png" + ] + }, + "alagrede.znote": { + "icon": "", + "images": [] + }, + "Albion.Online": { + "icon": "https://i.imgur.com/rCxdO5J.png", + "images": [ + "https://i.ytimg.com/vi/YM3c90leQFU/maxresdefault.jpg", + "https://assets.albiononline.com/assets/images/header/header-faye.jpg", + "https://assets.albiononline.com/uploads/media/default/media/f5a6e6b6d986ee3e61ed5ee7b305f792b2bd7bf4.jpeg", + "https://assets.albiononline.com/uploads/media/default/media/thumb_/media/62eb9dceb4de8_default_big.jpeg?cb=2.94.7", + "https://assets.albiononline.com/uploads/media/default/media/1a335a4d9e38600c1b64b7641e28a89c84e5bb75.jpeg" + ] + }, + "ALCPU.CoreTemp": { + "icon": "", + "images": [] + }, + "Aleab.Toastify": { + "icon": "", + "images": [] + }, + "AlekseyHoffman.Sigma-File-Manager": { + "icon": "", + "images": [] + }, + "alesimula.wsa_pacman": { + "icon": "", + "images": [] + }, + "AlexanderKojevnikov.Spek": { + "icon": "", + "images": [] + }, + "AlexanderPershin.lsdeer": { + "icon": "", + "images": [] + }, + "AlexandrSubbotin.Cerebro": { + "icon": "", + "images": [] + }, + "AlexKaul.Freeter": { + "icon": "", + "images": [] + }, + "alexkim205.g-desktop-suite": { + "icon": "", + "images": [] + }, + "AlexRedden.G14ControlV2": { + "icon": "", + "images": [] + }, + "AlexThuering.DVDStyler": { + "icon": "", + "images": [] + }, + "alexvallat.AlbumArtDownloader": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/0/02/CD_icon_test.svg/1024px-CD_icon_test.svg.png", + "images": [ + "https://www.snapfiles.com/screenfiles/aadownloader.png", + "http://freewaregenius.com/wp-content/uploads/2008/06/album-art-downloader-screenshot3.jpg", + "https://www.chip.de/ii/5/8/4/1/1/0/9/eaf373a13b0756b4.jpg", + "https://www.snapfiles.com/screenfiles/aadownloader2.png" + ] + }, + "alexx2000.DoubleCommander": { + "icon": "", + "images": [] + }, + "Algoryx.Algodoo": { + "icon": "http://www.algodoo.com/mainpage/wp-content/uploads/2013/03/algodoo_logo_algoryx_web.png", + "images": [ + "http://www.algodoo.com/mainpage/wp-content/uploads/2013/03/algodoo_for_education_pyramid-300x187.png", + "http://www.algodoo.com/mainpage/wp-content/uploads/2013/03/algodoo_for_education_start-300x187.png", + "http://www.algodoo.com/mainpage/wp-content/uploads/2013/03/800px-New_algodoo.png" + ] + }, + "ali50m.AddCurrentPath": { + "icon": "", + "images": [] + }, + "Alibaba.aDrive": { + "icon": "", + "images": [] + }, + "Alibaba.AliIM": { + "icon": "", + "images": [] + }, + "Alibaba.AlipayDevelopmentAssistant": { + "icon": "", + "images": [] + }, + "Alibaba.DingTalk": { + "icon": "", + "images": [] + }, + "Alibaba.DingTalk.Lite": { + "icon": "", + "images": [] + }, + "Alibaba.LightProxy": { + "icon": "", + "images": [] + }, + "Alibaba.MiniProgramStudio": { + "icon": "", + "images": [] + }, + "Alibaba.Teambition": { + "icon": "", + "images": [] + }, + "Alibaba.Yuque": { + "icon": "", + "images": [] + }, + "aliceandbob-io.aliceandbob": { + "icon": "https://i.imgur.com/VCbOVS8.png", + "images": [ + "https://raw.githubusercontent.com/aliceandbob-io/files/main/features_generate_v2.png", + "https://raw.githubusercontent.com/aliceandbob-io/files/main/features_encrypt_v2.png", + "https://raw.githubusercontent.com/aliceandbob-io/files/main/features_decrypt_v2.png" + ] + }, + "Allen&Heath.AHMSystemManager": { + "icon": "", + "images": [ + "https://portalnaglosnieniowy.eu/images/stories/2020/Prezentacje-sprzetu/Allen-Heath-AHM64-Matrix-64x64/Allen-Heath-AHM64-stageboxes-Application-Diagram.jpg", + "https://portalnaglosnieniowy.eu/media/k2/galleries/1451/Allen-Heath-AHM64-AHM-System-Manager-Channels-Input-AMM-Automaic-Mixer-1-8channels.jpg", + "https://portalnaglosnieniowy.eu/images/stories/2020/Prezentacje-sprzetu/Allen-Heath-AHM64-Matrix-64x64/Allen-Heath-AHM64-AHM-System-Manager-Channels-Input-Ducker.jpg", + "https://portalnaglosnieniowy.eu/images/stories/2020/Prezentacje-sprzetu/Allen-Heath-AHM64-Matrix-64x64/Allen-Heath-AHM64-AHM-System-Manager-Channels-Out-Zones-Crossovers-Filters.jpg", + "https://portalnaglosnieniowy.eu/images/stories/2020/Prezentacje-sprzetu/Allen-Heath-AHM64-Matrix-64x64/Allen-Heath-AHM64-AHM-System-Manager-Channels-Out-Zones-ANC-Sampling-Noise-Cancellation.jpg" + ] + }, + "Allen&Heath.AvantisDirector": { + "icon": "https://www.allen-heath.com/media/Avantis-Solo-In-Place.png", + "images": [ + "https://www.prosoundweb.com/wp-content/uploads/2021/03/AH-Avantis-v11.jpg", + "https://www.allen-heath.com/media/AV-Touch768.jpg" + ] + }, + "Allen&Heath.CustomControlEditor": { + "icon": "", + "images": [] + }, + "Allen&Heath.dLiveDirector": { + "icon": "", + "images": [] + }, + "Allen&Heath.SQMixPad": { + "icon": "", + "images": [] + }, + "AllMapSoft.MicrosoftVirtualEarthSa\u2026": { + "icon": "", + "images": [] + }, + "Almico.SpeedFan": { + "icon": "", + "images": [] + }, + "Alphayama.PowerIAST": { + "icon": "", + "images": [] + }, + "altair-graphql.altair": { + "icon": "https://github.com/altair-graphql/altair/raw/master/icons/android-icon-192x192.png", + "images": [ + "https://altairgraphql.dev/assets/img/app-shot.png", + "https://res.cloudinary.com/practicaldev/image/fetch/s--aSbALnX7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/b3xkbj0kjapx2blphb44.png", + "https://i.stack.imgur.com/veyfM.png", + "https://i.imgur.com/5zrqWb6.png" + ] + }, + "Altap.Salamander": { + "icon": "https://i.imgur.com/WvxLM42.png", + "images": [ + "https://www.altap.cz/images/teaser.1562049971.png" + ] + }, + "AltDrag.AltDrag": { + "icon": "https://stefansundin.github.io/altdrag/img/icon128.png", + "images": [ + "https://stefansundin.github.io/altdrag/img/resize.png", + "https://stefansundin.github.io/altdrag/img/configuration_window.png" + ] + }, + "AltSnap.AltSnap": { + "icon": "https://stefansundin.github.io/altdrag/img/icon128.png", + "images": [ + "https://github.com/RamonUnch/AltSnap/raw/main/HelpImages/TestWindow.png", + "https://github.com/RamonUnch/AltSnap/raw/main/HelpImages/GeneralDiag.png", + "https://github.com/RamonUnch/AltSnap/raw/main/HelpImages/SnpaLayoutEg.png", + "https://github.com/RamonUnch/AltSnap/raw/main/HelpImages/unikeymenu.png", + "https://raw.githubusercontent.com/RamonUnch/AltSnap/main/HelpImages/BlacklistDiag.png" + ] + }, + "ALVR.ALVR": { + "icon": "https://i.imgur.com/rByv98Y.png", + "images": [ + "https://i.imgur.com/0Jxph0u.png", + "https://cdn.mos.cms.futurecdn.net/9PNC57923LTrS76dbHWu2D-1200-80.jpg", + "https://mk0uploadvrcom4bcwhj.kinstacdn.com/wp-content/uploads/2019/06/sidequest-apps.png" + ] + }, + "AmanHarwara.Altus": { + "icon": "https://github.com/amanharwara/altus/blob/master/public/icon.png?raw=true", + "images": [ + "https://github.com/amanharwara/altus/raw/master/img/Altus-First-Start.png", + "https://github.com/amanharwara/altus/raw/master/img/Altus-Default-Theme.png", + "https://github.com/amanharwara/altus/raw/master/img/Altus-Dark-Theme.png" + ] + }, + "Amazon.AWSCLI": { + "icon": "https://discover.strongdm.com/hs-fs/hubfs/Technology%20Images/603c5ee70b9e8acb4229b654_603c218977575b8d6b27fabe_AWS_CLI.png?width=300&height=300&name=603c5ee70b9e8acb4229b654_603c218977575b8d6b27fabe_AWS_CLI.png", + "images": [ + "https://i.imgur.com/WhbXwYQ.png" + ] + }, + "Amazon.AWSVPNClient": { + "icon": "https://img.informer.com/icons_mac/png/128/577/577519.png", + "images": [ + "https://d2908q01vomqb2.cloudfront.net/5b384ce32d8cdef02bc3a139d4cac0a22bb029e8/2020/05/12/Slide2.png", + "https://docs.aws.amazon.com/vpn/latest/clientvpn-admin/images/architecture.png", + "https://docs.aws.amazon.com/whitepapers/latest/aws-vpc-connectivity-options/images/image21.png", + "https://docs.aws.amazon.com/vpn/latest/clientvpn-admin/images/client-vpn-scenario-igw.png" + ] + }, + "Amazon.Chime": { + "icon": "https://seeklogo.com/images/A/amazon-chime-logo-EE2754CC2C-seeklogo.com.png", + "images": [ + "https://d15shllkswkct0.cloudfront.net/wp-content/blogs.dir/1/files/2017/02/Amazon-Chime.jpg", + "https://media.amazonwebservices.com/blog/2017/chime_main_1.png", + "https://answers.chime.aws/storage/attachments/97-41-resize-media-panes.png", + "https://media.amazonwebservices.com/blog/2017/chime_meeting_2.png", + "https://d2908q01vomqb2.cloudfront.net/ca3512f4dfa95a03169c5a670a4c91a19b3077b4/2020/06/29/thier-fig4.png" + ] + }, + "Amazon.Corretto.11": { + "icon": "https://www.pulseway.com/Images/features/patch/3pp-logos/Amazon_Corretto_8.png", + "images": [ + "https://d2908q01vomqb2.cloudfront.net/ca3512f4dfa95a03169c5a670a4c91a19b3077b4/2018/11/14/Corretto_E-800x400.jpg", + "https://pbs.twimg.com/media/D07IwAyU8AAwhZ_.jpg" + ] + }, + "Amazon.Corretto.17": { + "icon": "https://www.pulseway.com/Images/features/patch/3pp-logos/Amazon_Corretto_8.png", + "images": [ + "https://d2908q01vomqb2.cloudfront.net/ca3512f4dfa95a03169c5a670a4c91a19b3077b4/2018/11/14/Corretto_E-800x400.jpg", + "https://pbs.twimg.com/media/D07IwAyU8AAwhZ_.jpg" + ] + }, + "Amazon.Corretto.18": { + "icon": "https://www.pulseway.com/Images/features/patch/3pp-logos/Amazon_Corretto_8.png", + "images": [ + "https://d2908q01vomqb2.cloudfront.net/ca3512f4dfa95a03169c5a670a4c91a19b3077b4/2018/11/14/Corretto_E-800x400.jpg", + "https://pbs.twimg.com/media/D07IwAyU8AAwhZ_.jpg" + ] + }, + "Amazon.Corretto.19": { + "icon": "https://www.pulseway.com/Images/features/patch/3pp-logos/Amazon_Corretto_8.png", + "images": [ + "https://d2908q01vomqb2.cloudfront.net/ca3512f4dfa95a03169c5a670a4c91a19b3077b4/2018/11/14/Corretto_E-800x400.jpg", + "https://pbs.twimg.com/media/D07IwAyU8AAwhZ_.jpg" + ] + }, + "Amazon.Corretto.8": { + "icon": "https://www.pulseway.com/Images/features/patch/3pp-logos/Amazon_Corretto_8.png", + "images": [ + "https://d2908q01vomqb2.cloudfront.net/ca3512f4dfa95a03169c5a670a4c91a19b3077b4/2018/11/14/Corretto_E-800x400.jpg", + "https://pbs.twimg.com/media/D07IwAyU8AAwhZ_.jpg" + ] + }, + "Amazon.Games": { + "icon": "https://seeklogo.com/images/A/amazon-games-logo-BE9EB714E4-seeklogo.com.png", + "images": [ + "https://m.media-amazon.com/images/G/01/sm/shared/166979982420469/social_image._CB409110150_.jpg", + "https://theculturednerd.org/wp-content/uploads/2020/10/Crucible-Featured.png", + "https://www.allcitycanvas.com/wp-content/uploads/2021/07/new-world-amazon-games-h-1280x720.jpg", + "https://www.howtogeek.com/wp-content/uploads/2020/06/0-amazon-games-header.jpg", + "https://www.androidheadlines.com/wp-content/uploads/2021/01/Prime-Gaming-Amazon-Games-Launcher.jpg" + ] + }, + "Amazon.Kindle": { + "icon": "https://hips.hearstapps.com/hmg-prod.s3.amazonaws.com/images/kindle-logo-1571758206.png", + "images": [ + "https://m.media-amazon.com/images/G/01/kindle/journeys/37DxD9LI0o5SlfZ3/ODFhOGNkZjYt-w1200._CB608601343_.jpg", + "https://www.online-tech-tips.com/wp-content/uploads/2020/04/Kindle-Desktop-Book-Collection.png", + "https://cdn.mos.cms.futurecdn.net/Kc9Y7v9vqdt2k237jfQHnD.jpg", + "https://www.thewindowsclub.com/wp-content/uploads/2018/03/Download-600x369.png", + "https://i.pcmag.com/imagery/articles/00cjVMgipjFlAHptWfw1bmm-6.fit_lim.size_1050x.png" + ] + }, + "Amazon.Music": { + "icon": "https://m.media-amazon.com/images/I/610LDzZhsUL.png", + "images": [ + "https://www.dolby.com/siteassets/passions/music/amazonmusic_1920x1080.jpg", + "https://i.pcmag.com/imagery/reviews/01vJVJPhC1L36eDVDp2Mlsb-15..v1621319677.jpg", + "https://i.imgur.com/OeVCtFA.jpg", + "https://www.windowslatest.com/wp-content/uploads/2018/02/amazon-music.png" + ] + }, + "Amazon.NoSQLWorkbench": { + "icon": "", + "images": [] + }, + "Amazon.OpenSearch.ODBC": { + "icon": "", + "images": [] + }, + "Amazon.SAM-CLI": { + "icon": "https://i.imgur.com/JTHKvy1.png", + "images": [ + "https://s33046.pcdn.co/wp-content/uploads/2020/08/aws-sam-workflow-e1597653903262.png", + "https://d2908q01vomqb2.cloudfront.net/1b6453892473a467d07372d45eb05abc2031647a/2020/12/16/poster-1024x629.png" + ] + }, + "Amazon.SendToKindle": { + "icon": "https://i.imgur.com/ZadUYa5.png", + "images": [ + "https://m.media-amazon.com/images/G/01/pdocs-client/send-to-kindle/s2k-family-pc-rcm.PNG", + "https://m.media-amazon.com/images/G/01/pdocs-client/send-to-kindle/s2k-family-pc-dnd.png" + ] + }, + "Amazon.SessionManagerPlugin": { + "icon": "", + "images": [] + }, + "Amazon.WorkspacesClient": { + "icon": "https://i.imgur.com/1xJawrC.png", + "images": [ + "https://images-na.ssl-images-amazon.com/images/I/41AdvBLniPL.png", + "https://www.sufle.io/img/blog/amazon-workspaces.jpg", + "https://docs.aws.amazon.com/workspaces/latest/adminguide/images/architectural-diagram-new-2.png", + "https://research-it.wharton.upenn.edu/wp-content/uploads/2020/05/WorkSpaces_Login.png" + ] + }, + "AMD.OCAT": { + "icon": "", + "images": [] + }, + "AmineMouafik.Ferdi": { + "icon": "", + "images": [ + "https://i.postimg.cc/05wGYTPN/workspaces.png" + ] + }, + "amitmerchant1990.electron-markdown\u2026": { + "icon": "", + "images": [] + }, + "Anaconda.Anaconda3": { + "icon": "https://i.imgur.com/Yfn6Mec.png", + "images": [ + "https://assets.anaconda.com/production/Products/Distro01.png?w=700&q=80&auto=format&fit=crop&crop=focalpoint&fp-x=0.5&fp-y=0.5&dm=1647546929&s=7a22f8ac8ef3c673d6522750d19073e5", + "https://assets.anaconda.com/production/Products/distro02-a.png?w=700&q=80&auto=format&fit=crop&crop=focalpoint&fp-x=0.5&fp-y=0.5&dm=1648141889&s=cf0f76189199988679e3b8195489ba18", + "https://assets.anaconda.com/production/Products/Distro03.png?w=700&q=80&auto=format&fit=crop&crop=focalpoint&fp-x=0.5&fp-y=0.5&dm=1647546960&s=71ec759bbe7909f56d95b96c38718b73", + "https://assets.anaconda.com/production/Products/Distro04-new.png?w=700&q=80&auto=format&fit=crop&crop=focalpoint&fp-x=0.5&fp-y=0.5&dm=1647548959&s=2061f01602dc7917a72a1cf73da9f3a7" + ] + }, + "Anaconda.Miniconda3": { + "icon": "", + "images": [] + }, + "AnchorFree.TouchVPN": { + "icon": "", + "images": [] + }, + "Andersama.obs-asio": { + "icon": "", + "images": [] + }, + "AndreasWascher.RepoZ": { + "icon": "", + "images": [] + }, + "AndresMorelos.Invoncify": { + "icon": "", + "images": [] + }, + "andrewbrey.flot": { + "icon": "", + "images": [] + }, + "AndreWiethoff.ExactAudioCopy": { + "icon": "", + "images": [] + }, + "AndrewZhezherun.WinDjView": { + "icon": "", + "images": [] + }, + "androidWG.Corkscrew": { + "icon": "", + "images": [] + }, + "angryziber.AngryIPScanner": { + "icon": "https://angryip.org/images/icon.png", + "images": [ + "https://angryip.org/screenshots/ipscan-win10.png" + ] + }, + "AngusJohnson.PDFTKBuilder": { + "icon": "", + "images": [] + }, + "AngusJohnson.ResourceHacker": { + "icon": "", + "images": [] + }, + "Anjok07.UltimateVocalRemover": { + "icon": "", + "images": [] + }, + "Anki.Anki": { + "icon": "https://i.redd.it/cruevyf68dt31.png", + "images": [ + "https://arihoresh.com/wp-content/uploads/2021/09/Laptop2-1-1024x458-1.jpg", + "https://images.squarespace-cdn.com/content/v1/58eada9abe659458e85c3f68/1532751018464-0U0KMM5L0XH731KAZ27K/01.png", + "https://remembereverything.org/wp-content/uploads/2016/10/Vocabulary-card-Anki-2.jpg", + "https://uploads-ssl.webflow.com/5dc6cc5bc19d438a53fbbaa9/607c90200e3c5babc5c380c0_German%20Noun%20Flashcards%20by%20Visual%20German.png", + "https://www.kenhub.com/thumbor/nBD7DFKLXiTizFxC7zjVEJea9qU=/fit-in/800x1600/filters:watermark(/images/logo_url.png,-10,-10,0):background_color(FFFFFF):format(jpeg)/images/article/en/how-to-learn-anatomy-with-anki/ZCM4XlKl0rGO6bWuw9d7FA_anki3.png" + ] + }, + "ankurk91.GoogleChatElectron": { + "icon": "", + "images": [] + }, + "AnthonyBeaumont.AchievementWatcher": { + "icon": "https://xan105.github.io/Achievement-Watcher/resources/img/logo.png", + "images": [ + "https://github.com/xan105/Achievement-Watcher/raw/master/screenshot/home.png", + "https://github.com/xan105/Achievement-Watcher/raw/master/screenshot/ach_view.png", + "https://xan105.github.io/Achievement-Watcher/resources/img/unified.png", + "https://xan105.github.io/Achievement-Watcher/resources/img/loading.png" + ] + }, + "AntibodySoftware.BulkImageDownload\u2026": { + "icon": "", + "images": [] + }, + "AntibodySoftware.WizFile": { + "icon": "", + "images": [] + }, + "AntibodySoftware.WizKey": { + "icon": "", + "images": [] + }, + "AntibodySoftware.WizMouse": { + "icon": "", + "images": [] + }, + "AntibodySoftware.WizTree": { + "icon": "", + "images": [] + }, + "AntiMicro.AntiMicro": { + "icon": "https://i.imgur.com/i5LJvyI.png", + "images": [ + "https://sc.filehippo.net/images/t_app-cover-m,f_auto/p/6eb28e07-8d98-497d-9784-43c30fd0d31b/133226868/antimicro-1.png", + "https://windows-cdn.softpedia.com/screenshots/antimicro-Portable_1.png", + "https://windows-cdn.softpedia.com/screenshots/antimicro-Portable_2.png", + "https://www.filecroco.com/wp-content/uploads/2018/07/antimicro-3.jpg" + ] + }, + "AntoineAflalo.SoundSwitch": { + "icon": "", + "images": [] + }, + "AntoniKepinski.ParsifyDesktop": { + "icon": "", + "images": [] + }, + "antonreshetov.massCode": { + "icon": "", + "images": [] + }, + "AntonyCourtney.Tad": { + "icon": "", + "images": [] + }, + "ANTOrg-Inc.ASCIIEngine": { + "icon": "", + "images": [] + }, + "AntSoftware.AntRenamer": { + "icon": "https://antp.be/img/softico_renamer.png", + "images": [ + "https://www.howtoanswer.com/articles/windows/Rename_multiple_files_and_folders_at_once_in_Windows/sshot-5.png", + "https://www.howtoanswer.com/articles/windows/Rename_multiple_files_and_folders_at_once_in_Windows/sshot-6.png", + "https://www.howtoanswer.com/articles/windows/Rename_multiple_files_and_folders_at_once_in_Windows/sshot-7.png", + "https://www.howtoanswer.com/articles/windows/Rename_multiple_files_and_folders_at_once_in_Windows/sshot-8.png" + ] + }, + "AnyDeskSoftwareGmbH.AnyDesk": { + "icon": "https://img.icons8.com/fluency/512/anydesk.png", + "images": [ + "https://cdn.mos.cms.futurecdn.net/rGU2S5Jz22yFy28i5shEFL.jpg", + "https://blog.anydesk.com/wp-content/uploads/2019/04/anydesk-software-version-5.png", + "https://cdn.afterdawn.fi/screenshots/normal/20813.jpg", + "https://static.sitejabber.com/img/urls/1323983/picture_374006.1626670964.jpg", + "https://support.anydesk.com/hs-fs/hubfs/Help%20Center/Connecting%20to%20a%20Remote%20Client/VirtualBoxVM_bao5gPJz7u.png?width=475&name=VirtualBoxVM_bao5gPJz7u.png" + ] + }, + "Anydo.Anydo": { + "icon": "https://www.any.do/v4/images/logo_blue.svg", + "images": [ + "https://dk2dyle8k4h9a.cloudfront.net/newPages/app_review/anydo.png", + "https://www.any.do/v4/images/pc/calendar@2x.png", + "https://gdm-catalog-fmapi-prod.imgix.net/ProductScreenshot/869cbc09-bd48-47df-b65e-00eed3b27217.jpg", + "https://images.saasworthy.com/anydo_7454_screenshot_1591679649_adivu.jpg", + "https://pbs.twimg.com/media/Ek13rtrXEAAqVOe.jpg" + ] + }, + "AnyLogic.AnyLogic.Personal": { + "icon": "https://i.imgur.com/82aJSKc.png", + "images": [ + "https://www.anylogic.com/upload/medialibrary/566/566c613f09bb7819a2aa4aa6bd3470f9.jpg", + "https://www.anylogic.com/upload/medialibrary/806/806cefb15119b22d3619843573dad71b.jpg", + "https://www.anylogic.com/upload/medialibrary/3f5/3f59466cdff47b9e1438c2a5ac2f8d71.jpg", + "https://www.anylogic.com/upload/medialibrary/1gf/10.png", + "https://www.anylogic.com/upload/medialibrary/1gf/13.png", + "https://www.anylogic.com/upload/medialibrary/1gf/15.png", + "https://www.anylogic.com/upload/medialibrary/1gf/16.png", + "https://www.anylogic.com/upload/medialibrary/1gf/17.png", + "https://www.anylogic.com/upload/medialibrary/1gf/18.png" + ] + }, + "AnyLogic.AnyLogic.Professional": { + "icon": "https://i.imgur.com/IL1dloo.png", + "images": [ + "https://www.anylogic.com/upload/medialibrary/566/566c613f09bb7819a2aa4aa6bd3470f9.jpg", + "https://www.anylogic.com/upload/medialibrary/806/806cefb15119b22d3619843573dad71b.jpg", + "https://www.anylogic.com/upload/medialibrary/3f5/3f59466cdff47b9e1438c2a5ac2f8d71.jpg", + "https://www.anylogic.com/upload/medialibrary/1gf/10.png", + "https://www.anylogic.com/upload/medialibrary/1gf/13.png", + "https://www.anylogic.com/upload/medialibrary/1gf/15.png", + "https://www.anylogic.com/upload/medialibrary/1gf/16.png", + "https://www.anylogic.com/upload/medialibrary/1gf/17.png", + "https://www.anylogic.com/upload/medialibrary/1gf/18.png" + ] + }, + "AnyLogic.AnyLogic.University": { + "icon": "https://i.imgur.com/IL1dloo.png", + "images": [ + "https://www.anylogic.com/upload/medialibrary/566/566c613f09bb7819a2aa4aa6bd3470f9.jpg", + "https://www.anylogic.com/upload/medialibrary/806/806cefb15119b22d3619843573dad71b.jpg", + "https://www.anylogic.com/upload/medialibrary/3f5/3f59466cdff47b9e1438c2a5ac2f8d71.jpg", + "https://www.anylogic.com/upload/medialibrary/1gf/10.png", + "https://www.anylogic.com/upload/medialibrary/1gf/13.png", + "https://www.anylogic.com/upload/medialibrary/1gf/15.png", + "https://www.anylogic.com/upload/medialibrary/1gf/16.png", + "https://www.anylogic.com/upload/medialibrary/1gf/17.png", + "https://www.anylogic.com/upload/medialibrary/1gf/18.png" + ] + }, + "AnyTXT.AnyTXTSearcher": { + "icon": "https://anytxt.net/wp-content/uploads/2019/11/Anytxt-searcher-logo.png", + "images": [ + "https://anytxt.net/wp-content/uploads/2022/03/Anytxt-web-full-text-search-1024x594-1.png", + "https://anytxt.net/wp-content/uploads/2022/10/20221007014339.png", + "https://anytxt.net/wp-content/uploads/2021/05/2021-5-29-2-768x461.png", + "https://a.fsdn.com/con/app/proj/anytxt/screenshots/eg5.jpg", + "https://anytxt.net/wp-content/uploads/2021/05/20210529192946-768x449.png", + "https://anytxt.net/wp-content/uploads/2021/05/20210529193138-768x449.png", + "https://anytxt.net/wp-content/uploads/2021/05/20210529193239-1-768x449.png", + "https://anytxt.net/wp-content/uploads/2021/05/20210529193408-768x451.png" + ] + }, + "AOMEI.Backupper": { + "icon": "https://www.megaleechers.com/storage/AOMEI-Backupper-Icon.png", + "images": [ + "https://images.idgesg.net/images/article/2021/07/aomei-backupper-6-tools-100895761-large.jpg", + "https://images.idgesg.net/images/article/2021/07/aomei-backupper-6-sync-tab-100895760-large.jpg", + "https://www.lifewire.com/thmb/-PFAciaszPLMbis0tGJz4b5CC5s=/1010x674/filters:fill(auto,1)/aomei-backupper-standard-6-3083ab1eadff4d369c4f89f096a25fd6.png", + "https://www.ubackup.com/screenshot/en/std/restore/system-restore-using-bootable-media/preview-restore.png", + "https://www.ubackup.com/screenshot/en/std/restore/system-restore-using-bootable-media/select-destination.png" + ] + }, + "AOMEI.PartitionAssistant": { + "icon": "https://www.megaleechers.com/storage/AOMEI-Partition-Assistant-Icon.png", + "images": [ + "https://www.lifewire.com/thmb/XSZctBtKj3Cc4sfaSY8E_hse3kk=/1280x691/filters:fill(auto,1)/aomei-partition-assistant-standard-edition-9-3f6f3e578f4c4109984e88bd8750d55d.png", + "https://sc.filehippo.net/images/t_app-cover-m,f_auto/p/20ef5252-a4d2-11e6-8f31-00163ed833e7/493431249/aomei-partition-assistant-standard-edition-1.png", + "https://windows-cdn.softpedia.com/screenshots/Partition-Assistant-Home-Edition_10.png", + "https://www.diskpart.com/screenshot/en/std/register/register.png" + ] + }, + "Apache.DirectoryStudio": { + "icon": "https://i.imgur.com/KeJwBYO.png", + "images": [ + "https://directory.apache.org/studio/static/images/screen_ldif_editor.jpg", + "https://directory.apache.org/apacheds/basic-ug/images/schema-browser-person.png", + "https://d4.alternativeto.net/WnNm-4s905qEOrZiYuG-mAZBmC5GlPWDiAxYQopTYUU/rs:fit:1200:1200:0/g:ce:0:0/YWJzOi8vZGlzdC9zLzE5NTQ0YjI2LWQ0YTAtZTExMS05NDU2LTAwMjU5MDJjN2U3M18yX2Z1bGwucG5n.jpg", + "https://blog.dzhuvinov.com/wp-content/uploads/2010/02/apache-directory-studio.jpg" + ] + }, + "Apache.Groovy.2.5": { + "icon": "", + "images": [] + }, + "Apache.Groovy.3": { + "icon": "", + "images": [] + }, + "Apache.Groovy.4": { + "icon": "", + "images": [] + }, + "Apache.OpenOffice": { + "icon": "", + "images": [] + }, + "ApacheFriends.Xampp.7.4": { + "icon": "", + "images": [] + }, + "ApacheFriends.Xampp.8.0": { + "icon": "", + "images": [] + }, + "ApacheFriends.Xampp.8.1": { + "icon": "", + "images": [] + }, + "Apifox.Apifox": { + "icon": "https://i.imgur.com/SSjFNQ6.png", + "images": [ + "https://cdn.apifox.cn/www/screenshot/dark-apifox-api-case-1.png", + "https://cdn.apifox.cn/www/screenshot/dark-apifox-schema-1.png", + "https://cdn.apifox.cn/www/screenshot/dark-apifox-api-definition-2.png", + "https://cdn.apifox.cn/www/screenshot/dark-apifox-test-case-1.png", + "https://cdn.apifox.cn/www/screenshot/dark-apifox-test-case-2.png", + "https://cdn.apifox.cn/www/screenshot/dark-apifox-test-case-3.png", + "https://cdn.apifox.cn/www/screenshot/dark-apifox-mock-1.png", + "https://cdn.apifox.cn/www/screenshot/dark-apifox-mock-2.png", + "https://cdn.apifox.cn/www/screenshot/dark-apifox-mock-3.png", + "https://cdn.apifox.cn/www/screenshot/dark-apifox-codegen-1.png", + "https://cdn.apifox.cn/www/screenshot/dark-apifox-codegen-2.png", + "https://cdn.apifox.cn/www/screenshot/dark-apifox-codegen-3.png", + "https://cdn.apifox.cn/www/screenshot/dark-apifox-setting-import-1.png", + "https://cdn.apifox.cn/www/screenshot/light-apifox-theme-1.png" + ] + }, + "AppbyTroye.KoodoReader": { + "icon": "", + "images": [] + }, + "Appest.Dida": { + "icon": "", + "images": [] + }, + "Appest.TickTick": { + "icon": "", + "images": [] + }, + "Apple.iTunes": { + "icon": "https://www.apple.com/v/itunes/home/k/images/overview/itunes_logo__dwjkvx332d0m_large.png", + "images": [] + }, + "appmakes.Typora": { + "icon": "", + "images": [] + }, + "Approximatrix.SimplyFortran": { + "icon": "", + "images": [] + }, + "AppWork.JDownloader": { + "icon": "", + "images": [] + }, + "AprelTech.HVManager": { + "icon": "", + "images": [] + }, + "AprelTech.PowerManager": { + "icon": "", + "images": [] + }, + "AprelTech.SilentInstallBuilder": { + "icon": "", + "images": [] + }, + "ArcadeRenegade.SidebarDiagnostics": { + "icon": "", + "images": [] + }, + "Arctype.Arctype": { + "icon": "https://i.imgur.com/gXqvZDe.png", + "images": [ + "https://arctype.com/home/images/overview.svg" + ] + }, + "arcusmaximus.YTSubConverter": { + "icon": "", + "images": [] + }, + "ArduinoSA.IDE.beta": { + "icon": "https://www.arduino.cc/wiki/370832ed4114dd35d498f2f449b4781e/arduino.svg", + "images": [ + "https://i.imgur.com/Wt5xlSf.png", + "https://andprof.com/wp-content/uploads/2021/10/What-is-arduino-software-IDE-and-how-use-it.png", + "https://static.javatpoint.com/tutorial/arduino/images/arduino-ide.png", + "https://www.digikey.my/-/media/MakerIO/Images/blogs/2018/Introduction%20to%20the%20Arduino%20IDE/Fig-1.jpg" + ] + }, + "ArduinoSA.IDE.rc": { + "icon": "", + "images": [ + "https://i.imgur.com/Wt5xlSf.png", + "https://andprof.com/wp-content/uploads/2021/10/What-is-arduino-software-IDE-and-how-use-it.png", + "https://static.javatpoint.com/tutorial/arduino/images/arduino-ide.png", + "https://www.digikey.my/-/media/MakerIO/Images/blogs/2018/Introduction%20to%20the%20Arduino%20IDE/Fig-1.jpg" + ] + }, + "ArduinoSA.IDE.stable": { + "icon": "https://www.arduino.cc/wiki/370832ed4114dd35d498f2f449b4781e/arduino.svg", + "images": [ + "https://i.imgur.com/Wt5xlSf.png", + "https://andprof.com/wp-content/uploads/2021/10/What-is-arduino-software-IDE-and-how-use-it.png", + "https://static.javatpoint.com/tutorial/arduino/images/arduino-ide.png", + "https://www.digikey.my/-/media/MakerIO/Images/blogs/2018/Introduction%20to%20the%20Arduino%20IDE/Fig-1.jpg" + ] + }, + "Argotronic.ArgusMonitor": { + "icon": "https://www.softlay.com/wp-content/uploads/Argus-Monitor-Free-Fan-Controller.png", + "images": [ + "https://cdn.argusmonitor.com/assets/en/fan_control_with_argus_monitor.png", + "https://cdn.argusmonitor.com/assets/en/screen01.png", + "https://cdn.argusmonitor.com/assets/en/screen02.png", + "https://cdn.argusmonitor.com/assets/en/screen03.png", + "https://cdn.argusmonitor.com/assets/en/screen04.png", + "https://cdn.argusmonitor.com/assets/en/screen05.png" + ] + }, + "Aries-Sciences-LLC.AI-Chess": { + "icon": "", + "images": [] + }, + "arjun-g.google-meet-desktop": { + "icon": "", + "images": [] + }, + "Arm.GnuArmEmbeddedToolchain": { + "icon": "", + "images": [] + }, + "ArmagetronAdvanced.ArmagetronAdvan\u2026": { + "icon": "", + "images": [] + }, + "ArmCord.ArmCord": { + "icon": "https://i.imgur.com/YWEmrzv.png", + "images": [ + "https://i.imgur.com/oIWacW1.jpg", + "https://windows-cdn.softpedia.com/screenshots/ArmCord_1.png", + "https://windows-cdn.softpedia.com/screenshots/ArmCord_2.png", + "https://windows-cdn.softpedia.com/screenshots/ArmCord_3.png", + "https://windows-cdn.softpedia.com/screenshots/ArmCord_4.png", + "https://res.cloudinary.com/canonical/image/fetch/f_auto,q_auto,fl_sanitize,w_819,h_623/https://dashboard.snapcraft.io/site_media/appmedia/2022/05/1_1.png" + ] + }, + "Armin2208.WindowsAutoNightMode": { + "icon": "https://raw.githubusercontent.com/AutoDarkMode/Windows-Auto-Night-Mode/master/Readme/logo.png", + "images": [ + "https://github.com/Armin2208/Windows-Auto-Night-Mode/raw/master/Readme/screenshot1.png", + "https://github.com/Armin2208/Windows-Auto-Night-Mode/raw/master/Readme/screenshot2.png", + "https://github.com/Armin2208/Windows-Auto-Night-Mode/raw/master/Readme/screenshot3.png", + "https://github.com/AutoDarkMode/Windows-Auto-Night-Mode/raw/master/Readme/screenshot4.png" + ] + }, + "ArobasMusic.GuitarPro.7": { + "icon": "https://i.imgur.com/ntePXqZ.png", + "images": [ + "https://www.guitar-pro.com/themes/gp_child_classic/assets/img/guitar-pro-7-features/guitar-pro-7-feature-screen-notation-en.jpg", + "https://www.guitar-pro.com/themes/gp_child_classic/assets/img/guitar-pro-7-features/guitar-pro-7-sheet-music-setup.jpg", + "https://www.guitar-pro.com/themes/gp_child_classic/assets/img/guitar-pro-7-features/guitar-pro-7-chords.jpg", + "https://www.guitar-pro.com/themes/gp_child_classic/assets/img/guitar-pro-7-features/guitar-pro-7-scales.jpg", + "https://www.guitar-pro.com/themes/gp_child_classic/assets/img/guitar-pro-7-features/guitar-pro-7-lyrics.jpg", + "https://www.guitar-pro.com/themes/gp_child_classic/assets/img/guitar-pro-7-features/guitar-pro-7-tuner.jpg" + ] + }, + "arrow2nd.serizawa": { + "icon": "", + "images": [] + }, + "arrow2nd.tokumei-player-plus": { + "icon": "", + "images": [] + }, + "arrow2nd.tokumei-player-pp": { + "icon": "", + "images": [] + }, + "Artha.Artha": { + "icon": "https://artha.sourceforge.net/wiki/skins/common/images/logo.png", + "images": [ + "https://artha.sourceforge.net/wiki/images/thumb/7/75/Mode_detailed.png/180px-Mode_detailed.png", + "https://artha.sourceforge.net/wiki/images/thumb/7/76/Regex_wildcard.png/180px-Regex_wildcard.png", + "https://artha.sourceforge.net/wiki/images/thumb/c/cf/Screen_antonyms.png/180px-Screen_antonyms.png", + "https://artha.sourceforge.net/wiki/images/thumb/a/ab/Screen_attribute.png/180px-Screen_attribute.png" + ] + }, + "ArtifexSoftware.GhostScript": { + "icon": "", + "images": [] + }, + "ArtisteerLimited.Nicepage": { + "icon": "", + "images": [] + }, + "Artsoft.RocksNDiamonds": { + "icon": "", + "images": [] + }, + "Asana.Asana": { + "icon": "https://seeklogo.com/images/A/asana-logo-7F172ED8E6-seeklogo.com.png", + "images": [ + "https://luna1.co/179c58.png", + "https://blog.asana.com/wp-content/post-images/11_04_boards_hero.png", + "https://luna1.co/7c29c0.png", + "https://luna1.co/5eafef.png", + "https://luna1.co/9b651d.png", + "https://luna1.co/3e4fc7.png", + "https://luna1.co/5fae66.png" + ] + }, + "AsaphaHalifa.AudioRelay": { + "icon": "https://audiorelay.net/assets/images/icon-512.png", + "images": [ + "https://2594558889-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MEh8vFAB2fHUbGzyi0U%2Fuploads%2FHrduy2Wx5s0ZSnvdIlyW%2FCleanShot%202022-02-20%20at%2014.04.27.png?alt=media&token=d7622501-22e4-4b42-87d3-cdafa06cc644", + "https://geekflare.com/wp-content/uploads/2021/08/audiorelay-pc-client.jpg" + ] + }, + "Ascension.AscensionLauncher": { + "icon": "https://api.ascension.gg/assets/91339ee87802eea59874.png", + "images": [ + "https://i.imgur.com/120dtq9.jpg", + "https://i.imgur.com/4uec4Ve.jpg" + ] + }, + "asdfjkl.JerryChess": { + "icon": "", + "images": [] + }, + "ASGARDEXMaintainers.ASGARDEX": { + "icon": "https://gitlab.com/uploads/-/system/project/avatar/19201149/LOGO-ROUND.png", + "images": [ + "https://www.cryptoninjas.net/wp-content/uploads/asgardex-thorchain-cryptoninjas.jpg", + "https://i.imgur.com/dEQBzCj.png", + "https://user-images.githubusercontent.com/61792675/175036489-f9bac515-b74a-44bf-b294-b65489c17bd8.png", + "https://user-images.githubusercontent.com/61792675/170678309-d6046218-8490-4efc-9274-14cdbcc57d9f.png", + "https://github.com/thorchain/asgardex-electron/raw/develop/internals/img/asgardex-splash.png" + ] + }, + "AshishBharadwajJ.Flawesome": { + "icon": "", + "images": [] + }, + "AshleyStone.DefaultAudio": { + "icon": "", + "images": [] + }, + "AshleyStone.SitdownMW": { + "icon": "", + "images": [] + }, + "assetizr.assetizr": { + "icon": "https://dist.assetizr.com/logo_written_200.png", + "images": [ + "https://i.gzn.jp/img/2019/01/22/assetizr/00.png", + "https://ph-files.imgix.net/793bbc97-8ae2-4a3a-8f12-a09afa6f71c7.png", + "https://i.imgur.com/tWMcwuk.jpg", + "https://d4.alternativeto.net/8i_Ph_1eCCOKNXd9uHsEpExDSXwcB1zKOoW0ynrInGM/rs:fit:1200:1200:0/g:ce:0:0/YWJzOi8vZGlzdC9zL2Fzc2V0aXpyXzI0OTk4NF9mdWxsLmpwZw.jpg" + ] + }, + "assnctr.unfx-proxy-checker": { + "icon": "", + "images": [] + }, + "AstroComma.AstroGrep": { + "icon": "http://astrogrep.sourceforge.net/pics/AstroGrep_256x256.png", + "images": [ + "https://a.fsdn.com/con/app/proj/astrogrep/screenshots/ss_main_new.png", + "https://www.portablefreeware.com/screenshots/scrLEgvyw.png", + "https://windows-cdn.softpedia.com/screenshots/X-AstroGrep_1.png" + ] + }, + "Astronomer.Astro": { + "icon": "", + "images": [] + }, + "athlabs.Spyglass": { + "icon": "", + "images": [] + }, + "Atlassian.Sourcetree": { + "icon": "", + "images": [] + }, + "ATLauncher.ATLauncher": { + "icon": "", + "images": [] + }, + "ATNSOFT.KeyManager": { + "icon": "", + "images": [] + }, + "ATNSOFT.KeyRemapper": { + "icon": "", + "images": [ + "https://i.postimg.cc/k4bvjz3q/keyremapper-remap-and-block.png" + ] + }, + "ATNSOFT.TextPaster": { + "icon": "", + "images": [] + }, + "Atola.FindandMount": { + "icon": "", + "images": [] + }, + "AtomixProductions.VirtualDJ": { + "icon": "", + "images": [] + }, + "Atrix.AtrixLauncher": { + "icon": "", + "images": [] + }, + "Audacious.MediaPlayer": { + "icon": "https://avatars.githubusercontent.com/u/1249822?s=280&v=4", + "images": [ + "https://audacious-media-player.org/images/audacious-4.0.2.png", + "https://www.fossmint.com/wp-content/uploads/2017/06/Audacious-Media-Player.png" + ] + }, + "Audacity.Audacity": { + "icon": "https://www.audacityteam.org/wp-content/themes/wp_audacity/img/logo.png", + "images": [ + "https://www.audacityteam.org/wp-content/uploads/2017/12/Theme_Dark.png", + "https://www.audacityteam.org/wp-content/uploads/2020/10/01-Audacity-Rhythm-Track-and-mono-vocal-track-waveform-view-768x586.png", + "https://www.audacityteam.org/wp-content/uploads/2020/10/02-Recording-with-Audacity-in-Dark-theme-768x586.png", + "https://www.audacityteam.org/wp-content/uploads/2020/10/03-Audacity-in-Multi-view-with-a-spectral-selection-768x586.png", + "https://www.audacityteam.org/wp-content/uploads/2020/10/04-Note-track-playing-in-Audacity-768x586.png", + "https://www.audacityteam.org/wp-content/uploads/2020/10/05-Audio-and-MIDI-on-Linux-768x567.png" + ] + }, + "Audient.EVO": { + "icon": "", + "images": [] + }, + "Audient.Sono": { + "icon": "", + "images": [] + }, + "AudioRangerIT.AudioRanger": { + "icon": "https://www.audioranger.com/images/logo_20221013.png", + "images": [ + "https://www.audioranger.com/images/audioranger.png", + "https://www.audioranger.com/images/features/automatically_fix_your_songs_1.png", + "https://www.audioranger.com/images/features/automatically_fix_your_songs_2.png", + "https://www.audioranger.com/images/features/automatically_fix_your_songs_3.png" + ] + }, + "AuraSide.Mantle": { + "icon": "", + "images": [] + }, + "Auslogics.DiskDefrag": { + "icon": "https://www.auslogics.com/includes/software/disk-defrag/i/logo.png", + "images": [ + "https://i0.wp.com/filecr.com/wp-content/uploads/2021/06/Auslogics-Disk-Defrag-professional-Free-Download.jpg", + "https://sc.filehippo.net/images/t_app-cover-m,f_auto/p/df5582de-96d1-11e6-b25d-00163ec9f5fa/1089620818/auslogics-disk-defrag-1089620818.png", + "https://windows-cdn.softpedia.com/screenshots/Portable-Auslogics-Disk-Defrag_12.png" + ] + }, + "AustinLeath.R6RC": { + "icon": "", + "images": [] + }, + "Authpass.Authpass": { + "icon": "https://i.imgur.com/d1BGeGd.png", + "images": [ + "https://github.com/authpass/authpass/raw/main/_docs/authpass-platform-composition.png", + "https://store-images.s-microsoft.com/image/apps.61539.14570429597835811.0743ca73-dd36-4d11-a26c-40a9785f67ba.a57b906c-47b5-4ee0-9308-6aba5c8d668b", + "https://store-images.s-microsoft.com/image/apps.30753.14570429597835811.0743ca73-dd36-4d11-a26c-40a9785f67ba.402e49a6-2437-4016-b398-edd7124e493e" + ] + }, + "Autodesk.DesktopApp": { + "icon": "https://www.logolynx.com/images/logolynx/38/384353c7d320c8c409fd75fd9200037d.png", + "images": [ + "https://i0.wp.com/blogs.autodesk.com/autocad/wp-content/uploads/sites/35/2020/04/DesktopApp-1_zfu9dz.png?resize=800%2C388&ssl=1", + "https://knowledge.autodesk.com/akn-aknsite-ckeditor-image-uploads/c3f89b07-9104-4b90-81a0-99df550dd393.PNG", + "https://www.mgfx.co.za/wp-content/uploads/2019/09/Autodesk-Desktop-App-1.Screenshot.jpg" + ] + }, + "Autodesk.EAGLE": { + "icon": "https://www.logolynx.com/images/logolynx/38/384353c7d320c8c409fd75fd9200037d.png", + "images": [] + }, + "Autodesk.sketchbook": { + "icon": "https://www.logolynx.com/images/logolynx/38/384353c7d320c8c409fd75fd9200037d.png", + "images": [] + }, + "AutoIt.AutoIt": { + "icon": "https://i.imgur.com/lETjQsY.png", + "images": [] + }, + "AutomatedLab.AutomatedLab": { + "icon": "https://imgur.com/a/0P9TpTo.png", + "images": [ + "https://i.ytimg.com/vi/lrPlRvFR5fA/sddefault.jpg" + ] + }, + "Automattic.Simplenote": { + "icon": "", + "images": [] + }, + "Automattic.Wordpress": { + "icon": "", + "images": [] + }, + "AutonomousSoftware.MetronomeWallet": { + "icon": "", + "images": [] + }, + "AveekSaha.DuskPlayer": { + "icon": "", + "images": [] + }, + "Avidemux.Avidemux": { + "icon": "", + "images": [] + }, + "AviSynth.AviSynth": { + "icon": "http://www.avisynth.org/images/avisynth-logo-gears-mod.png", + "images": [ + "https://www.svp-team.com/w/images/3/3c/Mpchc-avsf.png", + "https://imag.malavida.com/mvimgbig/download-fs/avisynth-11914-1.jpg" + ] + }, + "AviSynth.AviSynthPlus": { + "icon": "http://www.avisynth.org/images/avisynth-logo-gears-mod.png", + "images": [ + "https://www.svp-team.com/w/images/3/3c/Mpchc-avsf.png", + "https://imag.malavida.com/mvimgbig/download-fs/avisynth-11914-1.jpg" + ] + }, + "Avocode.Avocode": { + "icon": "https://www.macupdate.com/images/icons512/58650.png", + "images": [ + "https://avocode.com/static/og/facebook/avocode-og-download.png", + "https://miro.medium.com/max/1400/0*wKuC9gfMG2BG_KCL.png", + "https://miro.medium.com/max/1400/1*PGcWow7rw0fppvtOsZGoLg.png" + ] + }, + "Avogadro.Avogadro": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/c/c1/Avogadro.png", + "images": [ + "https://a.fsdn.com/con/app/proj/avogadro/screenshots/205209.jpg", + "https://a.fsdn.com/con/app/proj/avogadro/screenshots/205205.jpg", + "https://a.fsdn.com/con/app/proj/avogadro/screenshots/205207.jpg" + ] + }, + "avosskuehler.viana": { + "icon": "", + "images": [] + }, + "AVS.InstallPackComplete": { + "icon": "https://keygensofts.com/wp-content/uploads/2021/06/AVS4YOU.jpg", + "images": [ + "https://i.imgur.com/RH6wO99.jpg", + "https://i.imgur.com/z8oFnzY.png" + ] + }, + "awehook.BlinkMind": { + "icon": "", + "images": [] + }, + "AwthWathje.SteaScree": { + "icon": "", + "images": [] + }, + "AxCrypt.AxCrypt": { + "icon": "https://axcrypt.net/img/axcrypt_white.05643fb0.png", + "images": [ + "https://i.ytimg.com/vi/jyixJ03qmkg/maxresdefault.jpg", + "https://i.pcmag.com/imagery/reviews/01jciGTh8bUT5wFvORiELjy-14..v1627508527.png", + "https://i.pcmag.com/imagery/reviews/01jciGTh8bUT5wFvORiELjy-11..v1627508527.png" + ] + }, + "AxisCommunications.AxisCameraStati\u2026": { + "icon": "", + "images": [] + }, + "Axosoft.GitKraken": { + "icon": "", + "images": [] + }, + "Axure.AxureRP.10": { + "icon": "https://i.imgur.com/6VJTDPC.png", + "images": [ + "https://www.axure.com/wp-content/uploads/2021/04/og-image@2x.png", + "https://i.ytimg.com/vi/bFtXrsvdA1U/maxresdefault.jpg", + "https://uploads-ssl.webflow.com/60ac286928965092f733e140/60ac35cb7bfd6e9c8168e517_Axure%2BRP%2B10%2BOne%402x.png" + ] + }, + "AyibatariIbaba.Stopawu": { + "icon": "", + "images": [] + }, + "Azul.Zulu.11.JDK": { + "icon": "https://i.imgur.com/HZVJwPC.png", + "images": [ + "https://www.azul.com/wp-content/uploads/Java_Setup_macOS_1-1.jpeg", + "https://www.azul.com/wp-content/uploads/step3.png" + ] + }, + "Azul.Zulu.11.JRE": { + "icon": "https://i.imgur.com/HZVJwPC.png", + "images": [ + "https://www.azul.com/wp-content/uploads/Java_Setup_macOS_1-1.jpeg", + "https://www.azul.com/wp-content/uploads/step3.png" + ] + }, + "Azul.Zulu.13.JDK": { + "icon": "https://i.imgur.com/HZVJwPC.png", + "images": [ + "https://www.azul.com/wp-content/uploads/Java_Setup_macOS_1-1.jpeg", + "https://www.azul.com/wp-content/uploads/step3.png" + ] + }, + "Azul.Zulu.13.JRE": { + "icon": "https://i.imgur.com/HZVJwPC.png", + "images": [ + "https://www.azul.com/wp-content/uploads/Java_Setup_macOS_1-1.jpeg", + "https://www.azul.com/wp-content/uploads/step3.png" + ] + }, + "Azul.Zulu.15.JDK": { + "icon": "https://i.imgur.com/HZVJwPC.png", + "images": [ + "https://www.azul.com/wp-content/uploads/Java_Setup_macOS_1-1.jpeg", + "https://www.azul.com/wp-content/uploads/step3.png" + ] + }, + "Azul.Zulu.15.JRE": { + "icon": "https://i.imgur.com/HZVJwPC.png", + "images": [ + "https://www.azul.com/wp-content/uploads/Java_Setup_macOS_1-1.jpeg", + "https://www.azul.com/wp-content/uploads/step3.png" + ] + }, + "Azul.Zulu.16.JDK": { + "icon": "https://i.imgur.com/HZVJwPC.png", + "images": [ + "https://www.azul.com/wp-content/uploads/Java_Setup_macOS_1-1.jpeg", + "https://www.azul.com/wp-content/uploads/step3.png" + ] + }, + "Azul.Zulu.16.JRE": { + "icon": "https://i.imgur.com/HZVJwPC.png", + "images": [ + "https://www.azul.com/wp-content/uploads/Java_Setup_macOS_1-1.jpeg", + "https://www.azul.com/wp-content/uploads/step3.png" + ] + }, + "Azul.Zulu.17.JDK": { + "icon": "https://i.imgur.com/HZVJwPC.png", + "images": [ + "https://www.azul.com/wp-content/uploads/Java_Setup_macOS_1-1.jpeg", + "https://www.azul.com/wp-content/uploads/step3.png" + ] + }, + "Azul.Zulu.17.JRE": { + "icon": "https://i.imgur.com/HZVJwPC.png", + "images": [ + "https://www.azul.com/wp-content/uploads/Java_Setup_macOS_1-1.jpeg", + "https://www.azul.com/wp-content/uploads/step3.png" + ] + }, + "Azul.Zulu.18.JDK": { + "icon": "https://i.imgur.com/HZVJwPC.png", + "images": [ + "https://www.azul.com/wp-content/uploads/Java_Setup_macOS_1-1.jpeg", + "https://www.azul.com/wp-content/uploads/step3.png" + ] + }, + "Azul.Zulu.18.JRE": { + "icon": "https://i.imgur.com/HZVJwPC.png", + "images": [ + "https://www.azul.com/wp-content/uploads/Java_Setup_macOS_1-1.jpeg", + "https://www.azul.com/wp-content/uploads/step3.png" + ] + }, + "Azul.Zulu.6.JDK": { + "icon": "https://i.imgur.com/HZVJwPC.png", + "images": [ + "https://www.azul.com/wp-content/uploads/Java_Setup_macOS_1-1.jpeg", + "https://www.azul.com/wp-content/uploads/step3.png" + ] + }, + "Azul.Zulu.7.JDK": { + "icon": "https://i.imgur.com/HZVJwPC.png", + "images": [ + "https://www.azul.com/wp-content/uploads/Java_Setup_macOS_1-1.jpeg", + "https://www.azul.com/wp-content/uploads/step3.png" + ] + }, + "Azul.Zulu.7.JRE": { + "icon": "https://i.imgur.com/HZVJwPC.png", + "images": [ + "https://www.azul.com/wp-content/uploads/Java_Setup_macOS_1-1.jpeg", + "https://www.azul.com/wp-content/uploads/step3.png" + ] + }, + "Azul.Zulu.8.JDK": { + "icon": "https://i.imgur.com/HZVJwPC.png", + "images": [ + "https://www.azul.com/wp-content/uploads/Java_Setup_macOS_1-1.jpeg", + "https://www.azul.com/wp-content/uploads/step3.png" + ] + }, + "Azul.Zulu.8.JRE": { + "icon": "https://i.imgur.com/HZVJwPC.png", + "images": [ + "https://www.azul.com/wp-content/uploads/Java_Setup_macOS_1-1.jpeg", + "https://www.azul.com/wp-content/uploads/step3.png" + ] + }, + "Azul.Zulu.9.JDK": { + "icon": "https://i.imgur.com/HZVJwPC.png", + "images": [ + "https://www.azul.com/wp-content/uploads/Java_Setup_macOS_1-1.jpeg", + "https://www.azul.com/wp-content/uploads/step3.png" + ] + }, + "Azul.Zulu.9.JRE": { + "icon": "https://i.imgur.com/HZVJwPC.png", + "images": [ + "https://www.azul.com/wp-content/uploads/Java_Setup_macOS_1-1.jpeg", + "https://www.azul.com/wp-content/uploads/step3.png" + ] + }, + "Azul.ZuluFX.17.JDK": { + "icon": "https://i.imgur.com/HZVJwPC.png", + "images": [ + "https://www.azul.com/wp-content/uploads/Java_Setup_macOS_1-1.jpeg", + "https://www.azul.com/wp-content/uploads/step3.png" + ] + }, + "Azul.ZuluFX.18.JDK": { + "icon": "https://i.imgur.com/HZVJwPC.png", + "images": [ + "https://www.azul.com/wp-content/uploads/Java_Setup_macOS_1-1.jpeg", + "https://www.azul.com/wp-content/uploads/step3.png" + ] + }, + "azure06.clips": { + "icon": "", + "images": [] + }, + "B3log.SiYuan": { + "icon": "https://i.postimg.cc/DfCR8D3t/SiYuan.png", + "images": [] + }, + "Badlion.BadlionClient": { + "icon": "https://i.imgur.com/vMTzw0v.png", + "images": [ + "https://assets.badlion.net/site/assets/client.png", + "https://i.imgur.com/1UkRg5e.jpg", + "https://i.imgur.com/lrJUZx7.jpg" + ] + }, + "badpanda.GifYourGame": { + "icon": "", + "images": [] + }, + "Baidu.BaiduNetdisk": { + "icon": "", + "images": [] + }, + "Baidu.BaiduPinyin": { + "icon": "", + "images": [] + }, + "Baidu.BaiduSIAssistant": { + "icon": "", + "images": [] + }, + "Baidu.BaiduSIMeeting": { + "icon": "", + "images": [] + }, + "Baidu.BaiduTranslate": { + "icon": "", + "images": [] + }, + "Baidu.BaiduWenku": { + "icon": "", + "images": [] + }, + "Baidu.SwanIDE": { + "icon": "", + "images": [] + }, + "BaldurKarlsson.RenderDoc": { + "icon": "", + "images": [] + }, + "Balena.BalenaCLI": { + "icon": "https://www.balena.io/docs/img/logo.svg", + "images": [ + "https://i.imgur.com/y2qAdKD.png", + "https://i.imgur.com/lSrugml.png", + "https://i.imgur.com/wcfZcGB.png" + ] + }, + "Balena.Etcher": { + "icon": "https://i.imgur.com/e31olQa.png", + "images": [ + "https://i.imgur.com/111ORhl.png", + "https://www.how2shout.com/linux/wp-content/uploads/2021/11/BalenaEtcher-installation-on-Debian-11-Bullseye.png", + "https://i.ytimg.com/vi/K8TFa-ufE2s/maxresdefault.jpg" + ] + }, + "Balsamiq.Wireframes": { + "icon": "", + "images": [] + }, + "BandicamCompany.Bandicam": { + "icon": "https://i.imgur.com/E9S91RK.png", + "images": [ + "https://static.bandicam.com/img/screenshot/bandicam-start.jpg", + "https://static.bandicam.com/img/screenshot/bandicam-select.jpg", + "https://static.bandicam.com/img/screenshot/bandicam-screen-recording.jpg", + "https://static.bandicam.com/img/screenshot/bandicam-game-recording.jpg", + "https://static.bandicam.com/img/screenshot/bandicam-device-recording.jpg", + "https://static.bandicam.com/img/screenshot/bandicam-folder.jpg" + ] + }, + "BandicamCompany.Bandicut": { + "icon": "https://i.imgur.com/u0qdAsn.png", + "images": [ + "https://static.bandicam.com/bandicut-video-cutter/screenshot/3_bandicut_screenshot_base.jpg", + "https://static.bandicam.com/bandicut-video-cutter/screenshot/3_bandicut_screenshot_cutter.jpg", + "https://static.bandicam.com/bandicut-video-cutter/screenshot/3_bandicut_screenshot_spliter.jpg", + "https://static.bandicam.com/bandicut-video-cutter/screenshot/3_bandicut_screenshot_joiner.jpg", + "https://static.bandicam.com/bandicut-video-cutter/screenshot/3_bandicut_screenshot_process.jpg" + ] + }, + "Bandisoft.Bandizip": { + "icon": "https://i.imgur.com/qqhrrET.png", + "images": [ + "https://www.bandisoft.com/bandizip/screenshots/imgs.en/08_pm.png", + "https://www.bandisoft.com/bandizip/screenshots/imgs.en/09_repair.png", + "https://www.bandisoft.com/bandizip/screenshots/imgs.en/10_pr.png", + "https://www.bandisoft.com/bandizip/screenshots/imgs.en/11_preview.png", + "https://www.bandisoft.com/bandizip/screenshots/imgs.en/12_amsi.png" + ] + }, + "Bandisoft.Honeyview": { + "icon": "", + "images": [] + }, + "BarcoNV.MirrorOp": { + "icon": "", + "images": [] + }, + "BartoszCichecki.LenovoLegionToolkit": { + "icon": "", + "images": [] + }, + "Baulk.Baulk": { + "icon": "https://i.imgur.com/3k2phcY.png", + "images": [ + "https://github.com/baulk/baulk/raw/master/docs/images/getstarted.png", + "https://github.com/baulk/baulk/raw/master/docs/images/baulksearch.png", + "https://github.com/baulk/baulk/raw/master/docs/images/onterminal.png", + "https://github.com/baulk/baulk/raw/master/docs/images/barrels.png" + ] + }, + "Bazel.Bazelisk": { + "icon": "", + "images": [] + }, + "BBC.iPlayer": { + "icon": "https://i.imgur.com/gfpg8io.png", + "images": [ + "https://iplayer-web.files.bbci.co.uk/iplayer-web-app-features/1.0.0-667/install/screenshot.png", + "https://i.imgur.com/nTis8Uz.png", + "https://broadbandtvnews-broadbandtvnews.netdna-ssl.com/wp-content/uploads/2010/09/bbc-iplayer-new-Sept-20101.jpg", + "https://www.ispreview.co.uk/ispnews/data/upimages/subfolders/2009%20Misc/iplayer.jpg" + ] + }, + "bdash-app.bdash": { + "icon": "", + "images": [ + "https://raw.githubusercontent.com/bdash-app/bdash/1.2.2/assets/capture1.png", + "https://raw.githubusercontent.com/bdash-app/bdash/1.2.2/assets/capture2.png" + ] + }, + "BedaKosata.BKChem": { + "icon": "", + "images": [] + }, + "BeeBEEP.BeeBEEP": { + "icon": "https://i.imgur.com/lZXq4xt.png", + "images": [ + "https://www.beebeep.net/images/shots/beebeep_in_action_macosx.png", + "https://www.beebeep.net/images/shots/beebeep_in_action_windows.png", + "https://www.beebeep.net/images/shots/beebeep_in_action_darkstyle.png" + ] + }, + "Beeftext.Beeftext": { + "icon": "https://beeftext.org/images/BeeftextLogo75.png", + "images": [ + "https://beeftext.org/images/Demo01.png", + "https://beeftext.org/images/Demo02.gif" + ] + }, + "beekeeper-studio.beekeeper-studio": { + "icon": "https://www.beekeeperstudio.io/assets/img/logos/bk-logo-yellow-icon-3761c77d1abf26d329e20e3b5cf05cabfa00fb9225054be62707b0693991d380.svg", + "images": [ + "https://www.beekeeperstudio.io/assets/img/blog/33/solarized-725bccb89ac412416ad89bad5424238aa85e57e0562f97ab430535021b94ccad.png", + "https://www.beekeeperstudio.io/assets/img/features/magics-6c2eb6f3466201c7ecb9a43e85caae7ce5a202859b88b7a056010899bbd3f64e.png" + ] + }, + "Belarc.Advisor": { + "icon": "", + "images": [] + }, + "BelgianGovernment.Belgium-eIDmiddl\u2026": { + "icon": "https://eid.belgium.be/themes/custom/eid/logo.svg", + "images": [] + }, + "BelgianGovernment.eIDViewer": { + "icon": "https://eid.belgium.be/themes/custom/eid/logo.svg", + "images": [] + }, + "BelledonneCommunications.Linphone": { + "icon": "", + "images": [] + }, + "BellSoft.LibericaJDK.11": { + "icon": "https://www.sokrat.ru/upload/medialibrary/9b5/Bellsoft_logo.png", + "images": [] + }, + "BellSoft.LibericaJDK.11.Full": { + "icon": "https://www.sokrat.ru/upload/medialibrary/9b5/Bellsoft_logo.png", + "images": [] + }, + "BellSoft.LibericaJDK.14": { + "icon": "https://www.sokrat.ru/upload/medialibrary/9b5/Bellsoft_logo.png", + "images": [] + }, + "BellSoft.LibericaJDK.14.Full": { + "icon": "https://www.sokrat.ru/upload/medialibrary/9b5/Bellsoft_logo.png", + "images": [] + }, + "BellSoft.LibericaJDK.15": { + "icon": "https://www.sokrat.ru/upload/medialibrary/9b5/Bellsoft_logo.png", + "images": [] + }, + "BellSoft.LibericaJDK.15.Full": { + "icon": "https://www.sokrat.ru/upload/medialibrary/9b5/Bellsoft_logo.png", + "images": [] + }, + "BellSoft.LibericaJDK.16": { + "icon": "https://www.sokrat.ru/upload/medialibrary/9b5/Bellsoft_logo.png", + "images": [] + }, + "BellSoft.LibericaJDK.16.Full": { + "icon": "https://www.sokrat.ru/upload/medialibrary/9b5/Bellsoft_logo.png", + "images": [] + }, + "BellSoft.LibericaJDK.17": { + "icon": "https://www.sokrat.ru/upload/medialibrary/9b5/Bellsoft_logo.png", + "images": [] + }, + "BellSoft.LibericaJDK.17.Full": { + "icon": "https://www.sokrat.ru/upload/medialibrary/9b5/Bellsoft_logo.png", + "images": [] + }, + "BellSoft.LibericaJDK.18": { + "icon": "https://www.sokrat.ru/upload/medialibrary/9b5/Bellsoft_logo.png", + "images": [] + }, + "BellSoft.LibericaJDK.18.Full": { + "icon": "https://www.sokrat.ru/upload/medialibrary/9b5/Bellsoft_logo.png", + "images": [] + }, + "BellSoft.LibericaJDK.19": { + "icon": "https://www.sokrat.ru/upload/medialibrary/9b5/Bellsoft_logo.png", + "images": [] + }, + "BellSoft.LibericaJDK.19.Full": { + "icon": "https://www.sokrat.ru/upload/medialibrary/9b5/Bellsoft_logo.png", + "images": [] + }, + "BellSoft.LibericaJDK.8": { + "icon": "https://www.sokrat.ru/upload/medialibrary/9b5/Bellsoft_logo.png", + "images": [] + }, + "BellSoft.LibericaJDK.8.Full": { + "icon": "https://www.sokrat.ru/upload/medialibrary/9b5/Bellsoft_logo.png", + "images": [] + }, + "BenHollis.PNGGauntlet": { + "icon": "", + "images": [] + }, + "BespokeSynth.BespokeSynth": { + "icon": "", + "images": [] + }, + "Betaflight.Betaflight-Configurator": { + "icon": "", + "images": [] + }, + "Bethesda.Launcher": { + "icon": "", + "images": [] + }, + "BetterCrewLink.BetterCrewLink": { + "icon": "", + "images": [] + }, + "BiglySoftware.BiglyBT": { + "icon": "", + "images": [] + }, + "Bilibili.Bilibili": { + "icon": "", + "images": [] + }, + "Bilibili.Livehime": { + "icon": "", + "images": [] + }, + "Bililive.BililiveRecorder": { + "icon": "", + "images": [] + }, + "Billfish.Billfish": { + "icon": "", + "images": [] + }, + "BinanceTech.Binance": { + "icon": "", + "images": [] + }, + "BinaryFortress.ClipboardFusion": { + "icon": "", + "images": [] + }, + "BinaryFortress.CloudShow": { + "icon": "", + "images": [] + }, + "BinaryFortress.DisplayFusion": { + "icon": "", + "images": [] + }, + "BinaryFortress.FileSeek": { + "icon": "", + "images": [] + }, + "BinaryFortress.HashTools": { + "icon": "", + "images": [] + }, + "BinaryFortress.LogFusion": { + "icon": "", + "images": [] + }, + "BinaryFortress.TrayStatus": { + "icon": "", + "images": [] + }, + "BinaryFortress.VoiceBot": { + "icon": "", + "images": [] + }, + "BinaryFortress.WindowInspector": { + "icon": "", + "images": [] + }, + "BinaryMark.AdvancedFileFinder": { + "icon": "https://i.imgur.com/CEW3vDw.png", + "images": [ + "https://www.binarymark.com/img/screens/p23_main.png", + "https://www.binarymark.com/assets/batch-files-processor/screenshots/v3/manualmode.png", + "https://www.binarymark.com/assets/batch-files-processor/screenshots/v3/manualproc.png", + "https://www.binarymark.com/assets/batch-files-processor/screenshots/v3/automode1.png", + "https://www.binarymark.com/assets/batch-files-processor/screenshots/v3/automode5.png" + ] + }, + "BinaryMark.BatchDocs": { + "icon": "https://i.imgur.com/REcnsis.png", + "images": [ + "https://www.binarymark.com/assets/batch/screens/bd/bd-1.gif", + "https://www.binarymark.com/assets/batch/screens/bd/bd-2.gif", + "https://www.binarymark.com/assets/batch/screens/bd/bd-3.gif", + "https://www.binarymark.com/assets/batch/screens/bd/replaceregex.png", + "https://www.binarymark.com/assets/batch/screens/bd/delete1.png" + ] + }, + "BinaryMark.BatchEncodingConverter": { + "icon": "https://i.imgur.com/LulTz8S.png", + "images": [ + "https://www.binarymark.com/assets/batch-files-processor/screenshots/v3/findfiles1.png", + "https://www.binarymark.com/img/screens/p18_main.png", + "https://www.binarymark.com/assets/batch-files-processor/screenshots/v3/manualproc.png", + "https://www.binarymark.com/assets/batch-files-processor/screenshots/v3/schedule1.png", + "https://www.binarymark.com/assets/batch-files-processor/screenshots/v3/actionsequence2.png" + ] + }, + "BinaryMark.BatchFileEncrypt": { + "icon": "https://i.imgur.com/bp6zJ2f.png", + "images": [ + "https://www.binarymark.com/img/screens/p31_main.png", + "https://www.binarymark.com/assets/batch-files-processor/screenshots/v3/manualproc.png", + "https://www.binarymark.com/assets/batch-files-processor/screenshots/actions/act_encrypt.png", + "https://www.binarymark.com/assets/batch-files-processor/screenshots/v3/p31_welcome.png", + "https://www.binarymark.com/assets/batch-files-processor/screenshots/v3/manualmode.png" + ] + }, + "BinaryMark.BatchFileManager": { + "icon": "https://i.imgur.com/REcnsis.png", + "images": [ + "https://www.binarymark.com/assets/batch-files-processor/screenshots/v3/manualmode.png", + "https://www.binarymark.com/assets/batch-files-processor/screenshots/v3/commontasks4.png", + "https://www.binarymark.com/assets/batch-files-processor/screenshots/v3/filehelper_copy.png", + "https://www.binarymark.com/assets/batch-files-processor/screenshots/v3/rename1.png", + "https://www.binarymark.com/assets/batch-files-processor/screenshots/v3/findfiles1.png" + ] + }, + "BinaryMark.BatchFileRename": { + "icon": "https://i.imgur.com/kCHWyKz.png", + "images": [ + "https://www.binarymark.com/img/screens/p25_main.png", + "https://www.binarymark.com/assets/batch-files-processor/screenshots/v3/manualmode.png", + "https://www.binarymark.com/assets/batch-files-processor/screenshots/v3/rename1.png", + "https://www.binarymark.com/assets/batch-files-processor/screenshots/v3/findfiles1.png" + ] + }, + "BinaryMark.BatchFileReplace": { + "icon": "https://i.imgur.com/VJhsHSY.png", + "images": [ + "https://www.binarymark.com/img/screens/p19_main.png", + "https://www.binarymark.com/assets/batch-files-processor/screenshots/v3/findfiles1.png", + "https://www.binarymark.com/assets/batch-files-processor/screenshots/v3/manualproc.png", + "https://www.binarymark.com/assets/batch-files-processor/screenshots/v3/automode1.png", + "https://www.binarymark.com/assets/batch-files-processor/screenshots/v3/schedule1.png" + ] + }, + "BinaryMark.BatchFiles": { + "icon": "https://i.imgur.com/REcnsis.png", + "images": [ + "https://www.binarymark.com/assets/batch-files-processor/screenshots/v3/findfiles1.png", + "https://www.binarymark.com/img/screens/p17_main.png", + "https://www.binarymark.com/assets/batch-files-processor/screenshots/v3/manualproc.png", + "https://www.binarymark.com/assets/batch-files-processor/screenshots/actions/act_textreplace.png", + "https://www.binarymark.com/assets/batch-files-processor/screenshots/actions/act_format2.png" + ] + }, + "BinaryMark.BatchFileSplitJoin": { + "icon": "https://i.imgur.com/5TGCLm9.png", + "images": [ + "https://www.binarymark.com/assets/batch-files-processor/screenshots/v3/manualmode.png", + "https://www.binarymark.com/img/screens/p24_main.png", + "https://www.binarymark.com/assets/batch-files-processor/screenshots/v3/filehelper_copy.png", + "https://www.binarymark.com/assets/batch-files-processor/screenshots/v3/p24_welcome.png", + "https://www.binarymark.com/assets/batch-files-processor/screenshots/v3/manualmode.png" + ] + }, + "BinaryMark.BatchHexEditor": { + "icon": "https://i.imgur.com/GzvYCVM.png", + "images": [ + "https://www.binarymark.com/assets/batch-files-processor/screenshots/v3/findfiles1.png", + "https://www.binarymark.com/img/screens/p21_main.png", + "https://www.binarymark.com/assets/batch-files-processor/screenshots/v3/manualproc.png", + "https://www.binarymark.com/assets/batch-files-processor/screenshots/actions/act_binreplace.png", + "https://www.binarymark.com/assets/batch-files-processor/screenshots/actions/act_insertbin.png" + ] + }, + "BinaryMark.BatchImageConverter": { + "icon": "", + "images": [] + }, + "BinaryMark.BatchImageEnhancer": { + "icon": "https://i.imgur.com/REcnsis.png", + "images": [ + "https://www.binarymark.com/img/screens/p4_main.png", + "https://www.binarymark.com/assets/batch-image-processor/screenshots/tour/act11.png", + "https://www.binarymark.com/assets/batch-image-processor/screenshots/tour/scr_manualmode2.jpg", + "https://www.binarymark.com/assets/batch-image-processor/screenshots/tour/fitto_resize.jpg", + "https://www.binarymark.com/assets/batch-image-processor/screenshots/tour/resize_percent.jpg" + ] + }, + "BinaryMark.BatchImageResizer": { + "icon": "https://i.imgur.com/REcnsis.png", + "images": [ + "https://www.binarymark.com/img/screens/p2_main.png", + "https://www.binarymark.com/assets/batch-image-processor/screenshots/tour/act5.png", + "https://www.binarymark.com/assets/batch-image-processor/screenshots/tour/scr_manualmode2.jpg", + "https://www.binarymark.com/assets/batch-image-processor/screenshots/tour/fitto_resize.jpg", + "https://www.binarymark.com/assets/batch-image-processor/crop/scr_crop_ratio.jpg" + ] + }, + "BinaryMark.BatchImages": { + "icon": "https://i.imgur.com/REcnsis.png", + "images": [ + "https://www.binarymark.com/img/screens/p16_main.png", + "https://www.binarymark.com/assets/batch-image-processor/screenshots/tour/act1.png", + "https://www.binarymark.com/assets/batch-image-processor/screenshots/tour/scr_manualmode2.jpg", + "https://www.binarymark.com/assets/batch-image-processor/screenshots/tour/fitto_resize.jpg", + "https://www.binarymark.com/assets/batch-image-processor/screenshots/tour/resize_percent.jpg" + ] + }, + "BinaryMark.BatchImageSplitter": { + "icon": "https://i.imgur.com/REcnsis.png", + "images": [ + "https://www.binarymark.com/img/screens/p15_main.png", + "https://www.binarymark.com/assets/batch-image-processor/screenshots/tour/act5.png", + "https://www.binarymark.com/assets/batch-image-processor/screenshots/tour/scr_manualmode2.jpg", + "https://www.binarymark.com/assets/batch-image-processor/v3/cbi_split4.png", + "https://www.binarymark.com/assets/batch-image-processor/screenshots/tour/fitto_resize.jpg" + ] + }, + "BinaryMark.BatchImageWatermarker": { + "icon": "https://i.imgur.com/REcnsis.png", + "images": [ + "https://www.binarymark.com/img/screens/p3_main.png", + "https://www.binarymark.com/assets/batch-image-processor/screenshots/tour/act7.png", + "https://www.binarymark.com/assets/batch-image-processor/screenshots/tour/scr_manualmode2.jpg", + "https://www.binarymark.com/assets/batch-image-processor/screenshots/tour/watermarks.jpg", + "https://www.binarymark.com/assets/batch-image-processor/screenshots/tour/watermark_text.jpg" + ] + }, + "BinaryMark.BatchPhotoFace": { + "icon": "https://i.imgur.com/REcnsis.png", + "images": [ + "https://www.binarymark.com/img/screens/p14_main.png", + "https://www.binarymark.com/assets/batch-image-processor/v3/bi_actions_new56_1.png", + "https://www.binarymark.com/assets/batch-image-processor/screenshots/tour/scr_manualmode2.jpg", + "https://www.binarymark.com/assets/batch-image-processor/v3/cbi_face_helper.png", + "https://www.binarymark.com/assets/batch-image-processor/v3/cbi_face_search.png" + ] + }, + "BinaryMark.BatchRegEx": { + "icon": "https://i.imgur.com/BbSGkkF.png", + "images": [ + "https://www.binarymark.com/assets/batch-files-processor/screenshots/v3/findfiles1.png", + "https://www.binarymark.com/img/screens/p20_main.png", + "https://www.binarymark.com/assets/batch-files-processor/screenshots/v3/manualproc.png", + "https://www.binarymark.com/assets/batch-files-processor/screenshots/actions/act_regexreplace.png", + "https://www.binarymark.com/assets/batch-files-processor/screenshots/actions/act_format2.png" + ] + }, + "BinaryMark.BatchTextFileEditor": { + "icon": "https://i.imgur.com/1Vgpt5Q.png", + "images": [ + "https://www.binarymark.com/assets/batch-files-processor/screenshots/v3/findfiles1.png", + "https://www.binarymark.com/img/screens/p30_main.png", + "https://www.binarymark.com/assets/batch-files-processor/screenshots/v3/manualproc.png", + "https://www.binarymark.com/assets/batch-files-processor/screenshots/actions/act_textreplace.png", + "https://www.binarymark.com/assets/batch-files-processor/screenshots/actions/act_inserttext.png" + ] + }, + "BinaryMark.BatchWordReplace": { + "icon": "https://i.imgur.com/REcnsis.png", + "images": [ + "https://www.binarymark.com/assets/batch/screens/bd/bd-1.gif", + "https://www.binarymark.com/assets/batch/screens/bd/bd-2.gif", + "https://www.binarymark.com/assets/batch/screens/bd/bd-3.gif", + "https://www.binarymark.com/assets/batch/screens/bd/replace1.png", + "https://www.binarymark.com/assets/batch/screens/bd/replaceformat.png" + ] + }, + "BinaryMark.BiorhythmsCalculator": { + "icon": "", + "images": [] + }, + "BinaryMark.FileHashGenerator": { + "icon": "", + "images": [] + }, + "BinaryMark.PasswordGenerator": { + "icon": "", + "images": [] + }, + "BinaryMark.RandomNumberGenerator": { + "icon": "", + "images": [] + }, + "BinaryMark.StreamingVideoDownloader": { + "icon": "", + "images": [] + }, + "BinaryMark.TextToMp3Converter": { + "icon": "", + "images": [] + }, + "BiniSoft.WindowsFirewallControl": { + "icon": "", + "images": [] + }, + "Biscuit.Biscuit": { + "icon": "", + "images": [] + }, + "Bisq.Bisq": { + "icon": "", + "images": [] + }, + "BiSS.WSLDiskShrinker": { + "icon": "", + "images": [] + }, + "bitbeans.SimpleDNSCrypt": { + "icon": "", + "images": [] + }, + "BitcoinCoreProject.BitcoinCore": { + "icon": "", + "images": [] + }, + "Bitdefender.Bitdefender": { + "icon": "", + "images": [] + }, + "BitGuardian.BitDriverUpdater": { + "icon": "", + "images": [] + }, + "bitmediae-SolutionsGmbH.ITSClient": { + "icon": "", + "images": [] + }, + "Bitnami.Drupal": { + "icon": "", + "images": [] + }, + "Bitnami.Joomla": { + "icon": "", + "images": [] + }, + "Bitnami.phpBB": { + "icon": "", + "images": [] + }, + "Bitnami.PrestaShop": { + "icon": "", + "images": [] + }, + "Bitnami.ReportServerCommunity": { + "icon": "", + "images": [] + }, + "Bitnami.WAMP": { + "icon": "", + "images": [] + }, + "Bitnami.WordPress": { + "icon": "", + "images": [] + }, + "BitRecover.AadhaarCardPasswordRemo\u2026": { + "icon": "", + "images": [] + }, + "BitRecover.WindowsLiveMailConverter": { + "icon": "", + "images": [] + }, + "BitSum.Coreprio": { + "icon": "", + "images": [] + }, + "BitSum.ParkControl": { + "icon": "", + "images": [] + }, + "BitSum.ProcessLasso": { + "icon": "", + "images": [] + }, + "BitSum.ProcessLasso.Beta": { + "icon": "", + "images": [] + }, + "Bitvise.SSH.Client": { + "icon": "", + "images": [] + }, + "Bitvise.SSH.Server": { + "icon": "", + "images": [] + }, + "Bitwarden.Bitwarden": { + "icon": "", + "images": [] + }, + "bitwig.bitwig": { + "icon": "", + "images": [] + }, + "Biyi.Biyi": { + "icon": "", + "images": [] + }, + "BJLive!.LumineaRemote": { + "icon": "", + "images": [] + }, + "bl00mber.alarm-cron": { + "icon": "https://github.com/bl00mber/alarm-cron/raw/master/screens/logo.png", + "images": [ + "https://github.com/bl00mber/alarm-cron/raw/master/screens/interface.png" + ] + }, + "blaadje.Todolist": { + "icon": "", + "images": [] + }, + "Blade.Shadow": { + "icon": "", + "images": [] + }, + "BlastApps.FluentSearch": { + "icon": "", + "images": [] + }, + "BleachBit.BleachBit": { + "icon": "", + "images": [] + }, + "BlenderFoundation.Blender": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/0/0c/Blender_logo_no_text.svg/293px-Blender_logo_no_text.svg.png", + "images": [ + "https://i.ibb.co/0Xk37y3/Blender-4.jpg", + "https://i.ibb.co/6Rj232m/Blender-2.jpg", + "https://i.ibb.co/tK7KKBQ/Blender-3.jpg", + "https://i.ibb.co/35K0LQ5/Blender-1.jpg" + ] + }, + "Blitz.Blitz": { + "icon": "https://i.postimg.cc/HnLLYxHw/icon.png", + "images": [ + "https://i.postimg.cc/HW3JqGH0/1.png", + "https://i.postimg.cc/j5c5YNVq/2.png", + "https://i.postimg.cc/cLtrtr3T/3.png", + "https://i.postimg.cc/jd5WK8dp/4.png", + "https://i.postimg.cc/jjz2vmZ7/5.png", + "https://i.postimg.cc/JnMnFx2d/6.png\n", + "https://i.postimg.cc/CLQRKjRz/7.png", + "https://i.postimg.cc/mrxhYBN4/8.png", + "https://i.postimg.cc/rsYwKkFv/9.png", + "https://i.postimg.cc/CMv1vjHm/10.png", + "https://i.postimg.cc/15fzbfvP/11.png", + "https://i.postimg.cc/65gQKtPZ/12.png" + ] + }, + "Blocknetproject.Blocknet": { + "icon": "", + "images": [] + }, + "Blueberry.FlashbackExpress": { + "icon": "", + "images": [] + }, + "Blueberry.FlashBackPro": { + "icon": "", + "images": [] + }, + "BlueBubbles.BlueBubbles": { + "icon": "", + "images": [] + }, + "bluecfd.bluecfd": { + "icon": "", + "images": [] + }, + "blueedge.android11react": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/a/a7/React-icon.svg/2300px-React-icon.svg.png", + "images": [ + "https://github.com/blueedgetechno/androidInReact/raw/master/public/gall1.png", + "https://github.com/blueedgetechno/androidInReact/raw/master/public/gall2.png" + ] + }, + "blueedge.win11react": { + "icon": "", + "images": [] + }, + "Bluefish.Bluefish": { + "icon": "", + "images": [] + }, + "BlueJeans.BlueJeans": { + "icon": "", + "images": [] + }, + "BlueJTeam.BlueJ": { + "icon": "", + "images": [] + }, + "BlueMarbleGeographics.GlobalMapper": { + "icon": "", + "images": [] + }, + "bluemars.ClipX": { + "icon": "", + "images": [] + }, + "bluemars.ClipX.Beta": { + "icon": "", + "images": [] + }, + "BlueMicrophones.BlueSherpa": { + "icon": "", + "images": [] + }, + "Bluesound.BluOSController": { + "icon": "", + "images": [] + }, + "BlueStack.BlueStacks": { + "icon": "https://i.imgur.com/mOS8BWh.png", + "images": [] + }, + "bmatzelle.Gow": { + "icon": "", + "images": [] + }, + "Bome.SendSX": { + "icon": "", + "images": [] + }, + "boostio.boostnote": { + "icon": "", + "images": [] + }, + "Bopsoft.Listary": { + "icon": "", + "images": [] + }, + "BorisYakubchik.SimplestFileRenamer": { + "icon": "", + "images": [] + }, + "bornova.numara": { + "icon": "", + "images": [] + }, + "BornToBeRoot.NETworkManager": { + "icon": "", + "images": [] + }, + "Borvid.HttpMasterExpress": { + "icon": "", + "images": [] + }, + "Borvid.HttpMasterProfessional": { + "icon": "", + "images": [] + }, + "Bostrot.WSLManager": { + "icon": "", + "images": [] + }, + "Bosyun.BoardMix": { + "icon": "", + "images": [] + }, + "Bosyun.Pixso": { + "icon": "", + "images": [] + }, + "Bosyun.PixsoLocalFont": { + "icon": "", + "images": [] + }, + "Botkind.AllwaySync": { + "icon": "https://allwaysync.com/themes/allwaysync/img/logo.png", + "images": [ + "https://allwaysync.com/content/img/screenshots/sync-rules.png", + "https://allwaysync.com/content/img/screenshots/auto-sync.png", + "https://allwaysync.com/content/img/screenshots/filters.png", + "https://allwaysync.com/content/img/screenshots/file-versioning.png", + "https://allwaysync.com/content/img/screenshots/error-handling.png" + ] + }, + "BotProductions.IconViewer": { + "icon": "", + "images": [ + "https://i.postimg.cc/dtGBYzxf/iv3.png" + ] + }, + "Box.Box": { + "icon": "", + "images": [] + }, + "BoxHero.BoxHero": { + "icon": "", + "images": [] + }, + "boy1dr.SpleeterGui": { + "icon": "", + "images": [] + }, + "bozbez.WinCaptureAudio.beta": { + "icon": "", + "images": [] + }, + "BPBible.BPBible": { + "icon": "", + "images": [] + }, + "brackets-cont.brackets": { + "icon": "", + "images": [] + }, + "Brave.Brave": { + "icon": "https://img.icons8.com/color/48/null/brave-web-browser.png", + "images": [] + }, + "Brave.Brave.Beta": { + "icon": "", + "images": [] + }, + "Brave.Brave.Dev": { + "icon": "", + "images": [] + }, + "Brave.Brave.Nightly": { + "icon": "", + "images": [] + }, + "BrianApps.Sizer": { + "icon": "", + "images": [] + }, + "BrianApps.Sizer.Dev": { + "icon": "", + "images": [] + }, + "brianlima.uwphook": { + "icon": "", + "images": [] + }, + "BrickLink.Studio": { + "icon": "", + "images": [] + }, + "brimdata.brim": { + "icon": "", + "images": [] + }, + "Brio.FolderSize": { + "icon": "", + "images": [] + }, + "brrd.abricotine": { + "icon": "https://github.com/brrd/abricotine/blob/develop/icons/abricotine-64.png?raw=true", + "images": [ + "https://raw.githubusercontent.com/brrd/abricotine/develop/screenshot.jpg" + ] + }, + "BrunoBanelli.PCI-Z": { + "icon": "", + "images": [] + }, + "BrunoNova.Collision": { + "icon": "", + "images": [] + }, + "BrunoNova.DrMIPS": { + "icon": "", + "images": [] + }, + "brunurd.companion": { + "icon": "", + "images": [] + }, + "BrutalChess.BrutalChess": { + "icon": "", + "images": [] + }, + "btargac.excel-parser-processor": { + "icon": "", + "images": [] + }, + "buchen.portfolio": { + "icon": "", + "images": [] + }, + "Bullzip.BullzipPDFStudio": { + "icon": "", + "images": [] + }, + "Bullzip.PDFPrinter": { + "icon": "", + "images": [] + }, + "BumpTechnologies.BumpTop": { + "icon": "", + "images": [] + }, + "Buttercup.Buttercup": { + "icon": "", + "images": [] + }, + "BYOND.BYOND": { + "icon": "", + "images": [] + }, + "ByteDance.BytedanceMiniappIDE": { + "icon": "", + "images": [] + }, + "ByteDance.CapCut": { + "icon": "", + "images": [] + }, + "ByteDance.Debugtron": { + "icon": "", + "images": [] + }, + "ByteDance.Douyin": { + "icon": "", + "images": [] + }, + "ByteDance.Feishu": { + "icon": "", + "images": [] + }, + "ByteDance.JianyingPro": { + "icon": "", + "images": [] + }, + "ByteDance.Lark": { + "icon": "", + "images": [] + }, + "ByteDance.StreamingTool": { + "icon": "", + "images": [] + }, + "BZFlag.BZFlag": { + "icon": "", + "images": [] + }, + "c-egg.tenhou": { + "icon": "", + "images": [] + }, + "c0re100.qBittorrent-Enhanced-Editi\u2026": { + "icon": "", + "images": [] + }, + "c3er.mdview": { + "icon": "", + "images": [] + }, + "ca.duan.tre-command": { + "icon": "", + "images": [] + }, + "CactusNetwork.CactusBlockchainGUI": { + "icon": "", + "images": [] + }, + "CaffeineInc.Caffeine": { + "icon": "", + "images": [] + }, + "CAI.CASecureBrowser": { + "icon": "", + "images": [] + }, + "Cairo.Cairo": { + "icon": "", + "images": [] + }, + "calibre.calibre": { + "icon": "", + "images": [] + }, + "calibre.calibre.portable": { + "icon": "", + "images": [] + }, + "CambridgeUniversityPress.Cambridge\u2026": { + "icon": "", + "images": [] + }, + "CameronSutter.Plottr": { + "icon": "", + "images": [] + }, + "cangzhang.champ-r": { + "icon": "", + "images": [] + }, + "Canneverbe.CDBurnerXP": { + "icon": "", + "images": [] + }, + "Canonical.Juju": { + "icon": "", + "images": [] + }, + "Canonical.Multipass": { + "icon": "", + "images": [] + }, + "Canonical.Ubuntu": { + "icon": "", + "images": [] + }, + "Canonical.Ubuntu.1604": { + "icon": "", + "images": [] + }, + "Canonical.Ubuntu.1804": { + "icon": "", + "images": [] + }, + "Canonical.Ubuntu.2004": { + "icon": "", + "images": [] + }, + "Canonical.Ubuntu.2204": { + "icon": "", + "images": [] + }, + "Canva.Canva": { + "icon": "", + "images": [] + }, + "caobinrg.electron-office-tools": { + "icon": "", + "images": [] + }, + "Caphyon.AdvancedInstaller": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/2/22/Advanced-Installer-logo-new.png", + "images": [ + "https://www.advancedinstaller.com/img/index/imgStart.png", + "https://cdn.advancedinstaller.com/img/features/imgMSIAuthoring.png", + "https://cdn.advancedinstaller.com/img/ui/main-screen-shot.png", + "https://origin2.cdn.componentsource.com/sites/default/files/styles/image_large/public/images/product_description/advancedinstaller/advanced-installer-enterprise/img_670536.png", + "https://origin2.cdn.componentsource.com/sites/default/files/styles/carousel_main/public/images/product_description/advancedinstaller/advanced-installer-enterprise/img_670536.png" + ] + }, + "Caphyon.Hover": { + "icon": "", + "images": [] + }, + "CapricornConsultingGmbH.Vigoon": { + "icon": "", + "images": [] + }, + "Caprine.Caprine": { + "icon": "", + "images": [] + }, + "Caret.Caret": { + "icon": "", + "images": [] + }, + "Caret.CaretBeta": { + "icon": "", + "images": [] + }, + "CarlWenrich.PythonTkGuiBuilder": { + "icon": "", + "images": [] + }, + "CarstenGehling.JiraStopWatch": { + "icon": "", + "images": [] + }, + "CartamundiDigital.Fundels": { + "icon": "", + "images": [] + }, + "Catacombae.HFSExplorer": { + "icon": "", + "images": [] + }, + "CatalystDevelopment.SocketTools10.\u2026": { + "icon": "", + "images": [] + }, + "Catsxp.Catsxp": { + "icon": "", + "images": [] + }, + "cawa-93.anime-library": { + "icon": "https://i.imgur.com/uYEi0F6.png", + "images": [ + "https://user-images.githubusercontent.com/1662812/138271729-b6004bd9-f8cb-4d92-a0ef-784c7694108d.png", + "https://user-images.githubusercontent.com/1662812/138271791-7d1b32ec-c989-4f9c-bddf-86a89177b075.png", + "https://user-images.githubusercontent.com/1662812/138271883-dbf360fd-244d-4bf3-a546-21554337ce18.png", + "https://user-images.githubusercontent.com/1662812/138271926-4f0b2bc8-8acc-44bc-9c15-0f3c501363ef.png", + "https://user-images.githubusercontent.com/1662812/138272119-40405411-20fd-4c4d-b81f-c0aa80d4c903.png", + "https://user-images.githubusercontent.com/1662812/138272147-a7b2a25f-f9d7-4752-a4c1-cb17dc3b8c29.png" + ] + }, + "CBackup.CBackup": { + "icon": "", + "images": [] + }, + "CCL.NetLogo": { + "icon": "", + "images": [] + }, + "CCTV.CBox": { + "icon": "", + "images": [] + }, + "CDS.AladinDesktop": { + "icon": "https://i.imgur.com/iATlqUP.png", + "images": [ + "https://aladin.u-strasbg.fr/AladinDesktop/AladinBanner.jpg", + "https://i.ytimg.com/vi/IG_6Eh9EKKk/maxresdefault.jpg", + "https://i.ytimg.com/vi/0iIby3XXvp0/maxresdefault.jpg" + ] + }, + "Celestia.Celestia": { + "icon": "", + "images": [] + }, + "Cencit.BAS21": { + "icon": "https://bas21.no/wp-content/uploads/2018/05/bascore-100.png", + "images": [ + "https://bas21.no/wp-content/uploads/2018/05/bas21ordre-1024x496.jpg" + ] + }, + "CentStudio.CentBrowser": { + "icon": "", + "images": [] + }, + "CertifyTheWeb.CertifySSLManager": { + "icon": "", + "images": [] + }, + "Chadsoft.CTools": { + "icon": "", + "images": [] + }, + "chanplecai.smarttaskbar": { + "icon": "", + "images": [] + }, + "Chatflow.Spike": { + "icon": "", + "images": [] + }, + "Chatty.Chatty": { + "icon": "", + "images": [] + }, + "ChatZilla.ChatZilla": { + "icon": "", + "images": [] + }, + "CheckMAL.AppCheck": { + "icon": "https://i.imgur.com/WKl5ATc.png", + "images": [ + "https://www.checkmal.com/_res/img/view/product/en/img-appcheck-screenshot-1.png", + "https://www.checkmal.com/_res/img/view/product/en/img-appcheck-screenshot-11.png", + "https://www.checkmal.com/_res/img/view/product/en/img-appcheck-screenshot-2.png", + "https://www.checkmal.com/_res/img/view/product/en/img-appcheck-screenshot-4.png", + "https://www.checkmal.com/_res/img/view/product/en/img-appcheck-screenshot-5.png", + "https://www.checkmal.com/_res/img/view/product/en/img-appcheck-screenshot-6.png", + "https://www.checkmal.com/_res/img/view/product/en/img-appcheck-screenshot-7.png", + "https://www.checkmal.com/_res/img/view/product/en/img-appcheck-screenshot-8.png", + "https://www.checkmal.com/_res/img/view/product/en/img-appcheck-screenshot-9.png" + ] + }, + "ChefSoftware.ChefDK": { + "icon": "", + "images": [] + }, + "ChefSoftware.Inspec": { + "icon": "", + "images": [] + }, + "ChefSoftware.Workstation": { + "icon": "", + "images": [] + }, + "ChemAxon.instantjchem": { + "icon": "", + "images": [] + }, + "ChemAxon.jchemdotnetapi": { + "icon": "", + "images": [] + }, + "ChemAxon.Marvin": { + "icon": "", + "images": [] + }, + "CherubicSoftware.SageThumbs": { + "icon": "", + "images": [] + }, + "chezhe.Aleph": { + "icon": "https://i.imgur.com/Vh15Yr6.png", + "images": [ + "https://aleph.chezhe.dev/screenshot.png" + ] + }, + "Chia-Lung.Kaku": { + "icon": "", + "images": [] + }, + "ChiaNetwork.GUIforChiaBlockchain": { + "icon": "", + "images": [] + }, + "ChilliBits.CCom": { + "icon": "", + "images": [] + }, + "ChilliBits.ComposeGenerator": { + "icon": "", + "images": [] + }, + "ChilliBits.Spice": { + "icon": "", + "images": [] + }, + "ChilliCream.BananaCakePop": { + "icon": "https://i.imgur.com/BLAMFGT.png", + "images": [ + "https://chillicream.com/static/235c2468b1b6a9b5e818516b74e55e84/e2f49/bcp-operations.png", + "https://chillicream.com/static/6fb492dfe4f20527624dcb562abe875a/e2f49/bcp-start-screen.png", + "https://chillicream.com/static/daf2e87c9c32e15cd16d34e051937d06/e2f49/bcp-endpoint-entry.png", + "https://chillicream.com/static/96a1180f1c43149cfdcb7b3da53284b1/e2f49/bcp-sessionsbyid-query.png", + "https://chillicream.com/static/5fb9d581f93b8bd6ccde495964363edf/e2f49/bcp-editor-dropdown.png", + "https://chillicream.com/static/13f73550b3648db5c6e8010eb3b6be42/e2f49/bcp-schema-reference-query-type.png" + ] + }, + "CHIRP.CHIRP": { + "icon": "", + "images": [] + }, + "CHMS.Behindyou": { + "icon": "", + "images": [] + }, + "Chocolatey.ChocolateyGUI": { + "icon": "https://i.postimg.cc/Dw17KsLV/icon.png", + "images": [ + "https://i.postimg.cc/zf58DBFy/1.png" + ] + }, + "chrdavis.smartrename": { + "icon": "", + "images": [] + }, + "chrisant996.Clink": { + "icon": "", + "images": [] + }, + "ChrisBagwell.SoX": { + "icon": "", + "images": [] + }, + "ChrisKlimas.Twine": { + "icon": "", + "images": [] + }, + "ChristianAviBulan.GlassCannon": { + "icon": "", + "images": [] + }, + "ChristianHohnstadt.xca": { + "icon": "", + "images": [] + }, + "ChristianKaiser.Lightscreen": { + "icon": "https://i.postimg.cc/nVszPXRx/icon.png", + "images": [ + "https://i.postimg.cc/DftZk7HX/1.png" + ] + }, + "ChristianKindahl.InfraRecorder": { + "icon": "", + "images": [] + }, + "ChristianSchenk.MiKTeX": { + "icon": "", + "images": [] + }, + "ChronoplexSoftware.MyFamilyTree": { + "icon": "", + "images": [] + }, + "ChungZH.notepanda": { + "icon": "", + "images": [] + }, + "CI010.XMinecraftLauncher": { + "icon": "", + "images": [] + }, + "CiderCollective.Cider": { + "icon": "", + "images": [] + }, + "CiderCollective.Cider.Nightly": { + "icon": "", + "images": [] + }, + "CircuitDiagram.CircuitDiagram": { + "icon": "", + "images": [] + }, + "Cisco.CiscoWebexMeetings": { + "icon": "", + "images": [] + }, + "Cisco.ClamAV": { + "icon": "", + "images": [] + }, + "Cisco.Jabber": { + "icon": "", + "images": [] + }, + "Cisco.webex-outlook-plugin": { + "icon": "", + "images": [] + }, + "Cisco.WebexTeams": { + "icon": "", + "images": [] + }, + "Citrix.Workspace": { + "icon": "", + "images": [] + }, + "cjerrington.net-check": { + "icon": "", + "images": [] + }, + "CKingX.haveibeenpwned": { + "icon": "", + "images": [] + }, + "ClamWin.ClamWin": { + "icon": "", + "images": [] + }, + "ClawsMail.ClawsMail": { + "icon": "", + "images": [] + }, + "clawSoft.clawPDF": { + "icon": "", + "images": [] + }, + "CLechasseur.PathCopyCopy": { + "icon": "", + "images": [] + }, + "Clement.bottom": { + "icon": "", + "images": [] + }, + "Clementine.Clementine": { + "icon": "", + "images": [] + }, + "ClickUp.ClickUp": { + "icon": "", + "images": [] + }, + "ClipTeam.ClipCC": { + "icon": "", + "images": [] + }, + "ClipTeam.ClipCC.Beta": { + "icon": "", + "images": [] + }, + "CliptoTeam.Clipto": { + "icon": "", + "images": [] + }, + "Clockify.Clockify": { + "icon": "", + "images": [] + }, + "ClockworkMod.UniversalADBDriver": { + "icon": "", + "images": [] + }, + "CloneSpy.CloneSpy": { + "icon": "", + "images": [] + }, + "CloudApp.CloudApp": { + "icon": "", + "images": [] + }, + "CloudCall.Communicator": { + "icon": "", + "images": [] + }, + "Cloudflare.cloudflared": { + "icon": "", + "images": [] + }, + "Cloudflare.Warp": { + "icon": "", + "images": [] + }, + "CloudImperiumGames.RSILauncher": { + "icon": "", + "images": [] + }, + "clouDr-f2e.rubick": { + "icon": "", + "images": [] + }, + "clsid2.mpc-hc": { + "icon": "", + "images": [ + "https://user-images.githubusercontent.com/73800734/200967040-8c06e7be-4937-4e98-b5b6-cc9960d8d12c.png" + ] + }, + "ClusterM.hakchi2": { + "icon": "", + "images": [] + }, + "CMIE.ProwessIQ": { + "icon": "", + "images": [] + }, + "CNRISTI.MeshLab": { + "icon": "", + "images": [] + }, + "CNRISTI.QuteMol": { + "icon": "", + "images": [] + }, + "COAS.Donkey": { + "icon": "", + "images": [] + }, + "COAS.SemantaModeler": { + "icon": "", + "images": [] + }, + "Cockatrice.Cockatrice": { + "icon": "", + "images": [] + }, + "Cockos.LICEcap": { + "icon": "", + "images": [] + }, + "Cockos.REAPER": { + "icon": "", + "images": [] + }, + "Cocos.CocosDashboard": { + "icon": "", + "images": [] + }, + "code52.Carnac": { + "icon": "", + "images": [] + }, + "Codeblocks.Codeblocks": { + "icon": "https://www.codeblocks.org/images/logo160.png", + "images": [ + "https://windows-cdn.softpedia.com/screenshots/Code-Blocks_4.png", + "https://www.hellocodies.com/wp-content/uploads/2018/11/Build-and-Run.png" + ] + }, + "CodecGuide.K-LiteCodecPack.Basic": { + "icon": "", + "images": [] + }, + "CodecGuide.K-LiteCodecPack.Full": { + "icon": "", + "images": [ + "https://user-images.githubusercontent.com/73800734/200967040-8c06e7be-4937-4e98-b5b6-cc9960d8d12c.png" + ] + }, + "CodecGuide.K-LiteCodecPack.Mega": { + "icon": "", + "images": [] + }, + "CodecGuide.K-LiteCodecPack.Standard": { + "icon": "", + "images": [] + }, + "CodeF0x.violin": { + "icon": "", + "images": [] + }, + "CodeforScience.ScienceFair": { + "icon": "", + "images": [] + }, + "CodeIndustry.MasterPdfEditor": { + "icon": "", + "images": [] + }, + "CodeJelly.Launchy": { + "icon": "", + "images": [] + }, + "CodeLite.CodeLite": { + "icon": "", + "images": [] + }, + "Coder.Coder": { + "icon": "", + "images": [] + }, + "codersnotes.VerySleepy": { + "icon": "", + "images": [] + }, + "CodeSector.TeraCopy": { + "icon": "", + "images": [] + }, + "Codeusa.BorderlessGaming": { + "icon": "", + "images": [] + }, + "Codice.PlasticSCM.CloudEdition": { + "icon": "", + "images": [] + }, + "Coldlake.StellarPlayer": { + "icon": "", + "images": [] + }, + "ColdTurkeySoftware.ColdTurkeyBlock\u2026": { + "icon": "", + "images": [] + }, + "CometNetwork.BitComet": { + "icon": "", + "images": [] + }, + "commercialhaskell.stack": { + "icon": "", + "images": [] + }, + "CompLabs.GoogleDocs": { + "icon": "", + "images": [] + }, + "CompuBench.GFXBench": { + "icon": "", + "images": [] + }, + "Compuphase.Termite": { + "icon": "", + "images": [] + }, + "Concept2.Utility": { + "icon": "", + "images": [] + }, + "ConceptworldCorporation.RecentX": { + "icon": "", + "images": [] + }, + "CondaForge.Mambaforge": { + "icon": "", + "images": [] + }, + "CondaForge.Miniforge3": { + "icon": "", + "images": [] + }, + "ConeXware.PowerArchiver2022": { + "icon": "", + "images": [] + }, + "CongusBongus.CDogsSDL": { + "icon": "", + "images": [] + }, + "Coninfer.ECLiPSeCLP.7.0": { + "icon": "", + "images": [] + }, + "Contasimple.ContasimpleDesktop": { + "icon": "", + "images": [] + }, + "converse.converse": { + "icon": "", + "images": [] + }, + "CoocooFroggy.FutureRestore-GUI": { + "icon": "", + "images": [] + }, + "CoolPlayLin.MOliGeek": { + "icon": "", + "images": [] + }, + "CopyTranslator.CopyTranslator": { + "icon": "", + "images": [] + }, + "Coq.CoqPlatform": { + "icon": "", + "images": [] + }, + "Coq.CoqPlatform.Beta": { + "icon": "", + "images": [] + }, + "corda.node-explorer": { + "icon": "", + "images": [] + }, + "Corel.WinZip": { + "icon": "", + "images": [] + }, + "CoreyButler.NVMforWindows": { + "icon": "", + "images": [] + }, + "CorporateClashCrew.ToontownCorpora\u2026": { + "icon": "", + "images": [] + }, + "Corsair.iCUE.3": { + "icon": "", + "images": [] + }, + "Corsair.iCUE.4": { + "icon": "", + "images": [] + }, + "CorsixTH.CorsixTH": { + "icon": "", + "images": [] + }, + "CosmoX.Lepton": { + "icon": "", + "images": [] + }, + "coti.mcxstudio": { + "icon": "", + "images": [] + }, + "Couchbase.ServerCommunity": { + "icon": "", + "images": [] + }, + "Couchbase.ServerEnterprise": { + "icon": "", + "images": [] + }, + "Couchcoding.Logbert": { + "icon": "", + "images": [] + }, + "COWON.jetAudio": { + "icon": "", + "images": [] + }, + "CozyCloud.CozyDrive": { + "icon": "", + "images": [] + }, + "CozyCloud.CozyDrive.Beta": { + "icon": "", + "images": [] + }, + "Cppcheck.Cppcheck": { + "icon": "", + "images": [] + }, + "CPUID.CPU-Z": { + "icon": "", + "images": [] + }, + "CPUID.CPU-Z.AORUS": { + "icon": "", + "images": [] + }, + "CPUID.CPU-Z.ASR": { + "icon": "", + "images": [] + }, + "CPUID.CPU-Z.CM": { + "icon": "", + "images": [] + }, + "CPUID.CPU-Z.GBT": { + "icon": "", + "images": [] + }, + "CPUID.CPU-Z.MSI": { + "icon": "", + "images": [] + }, + "CPUID.CPU-Z.PHANTOM": { + "icon": "", + "images": [] + }, + "CPUID.CPU-Z.ROG": { + "icon": "", + "images": [] + }, + "CPUID.CPU-Z.TAICHI": { + "icon": "", + "images": [] + }, + "CPUID.HWMonitor": { + "icon": "", + "images": [] + }, + "CPUID.powerMAX": { + "icon": "", + "images": [] + }, + "Crazybump.Crazybump": { + "icon": "", + "images": [] + }, + "CreativeTechnology.CreativeApp": { + "icon": "", + "images": [] + }, + "CreativeTechnology.SoundBlasterCom\u2026": { + "icon": "", + "images": [] + }, + "Creosys.OBDAutoDoctor": { + "icon": "", + "images": [] + }, + "Crintsoft.MiniLyrics": { + "icon": "", + "images": [] + }, + "CrowdSecurity.CrowdSec": { + "icon": "", + "images": [] + }, + "CrowdSecurity.CrowdSecWindowsFirew\u2026": { + "icon": "", + "images": [] + }, + "CrowTranslate.CrowTranslate": { + "icon": "", + "images": [] + }, + "Cryptomator.Cryptomator": { + "icon": "", + "images": [] + }, + "CrystalArtSoftware.NewsLeecher": { + "icon": "", + "images": [] + }, + "CrystalDewWorld.CrystalDiskInfo": { + "icon": "", + "images": [] + }, + "CrystalDewWorld.CrystalDiskInfo.Ku\u2026": { + "icon": "", + "images": [] + }, + "CrystalDewWorld.CrystalDiskInfo.Sh\u2026": { + "icon": "", + "images": [] + }, + "CrystalDewWorld.CrystalDiskMark": { + "icon": "", + "images": [] + }, + "CrystalDewWorld.CrystalDiskMark.Sh\u2026": { + "icon": "", + "images": [] + }, + "CrystalIDEASoftware.AnyToISO": { + "icon": "https://crystalidea.com/assets/images/anytoiso/icon_32.png", + "images": [ + "https://crystalidea.com/assets/images/anytoiso/carousel1.png", + "https://crystalidea.com/assets/images/anytoiso/carousel2.png", + "https://crystalidea.com/assets/images/anytoiso/carousel3.png" + ] + }, + "CrystalIDEASoftware.UninstallTool": { + "icon": "", + "images": [] + }, + "CrystalRich.InternetOff": { + "icon": "", + "images": [] + }, + "CrystalRich.LockHunter": { + "icon": "", + "images": [] + }, + "CrystalRich.USBSafelyRemove": { + "icon": "", + "images": [] + }, + "CrystalRich.Zentimo": { + "icon": "", + "images": [] + }, + "CThingSoftware.Meazure": { + "icon": "", + "images": [] + }, + "ctrl-f.userdiag": { + "icon": "", + "images": [] + }, + "Cube.CubePlatform": { + "icon": "", + "images": [] + }, + "CubeCodersLimited.AMPInstanceManag\u2026": { + "icon": "", + "images": [] + }, + "CubeSoft.CubeICE": { + "icon": "", + "images": [] + }, + "CubeSoft.CubePDF": { + "icon": "", + "images": [] + }, + "CubeSoft.CubePDFUtility": { + "icon": "", + "images": [] + }, + "CubicSDR.CubicSDR": { + "icon": "", + "images": [] + }, + "cuiliang.quicker": { + "icon": "", + "images": [] + }, + "cuiocean.zyplayer": { + "icon": "", + "images": [] + }, + "CWEcomputerservices.GSAK": { + "icon": "", + "images": [] + }, + "Cyanfish.NAPS2": { + "icon": "", + "images": [] + }, + "Cybelsoft.DriversCloud": { + "icon": "", + "images": [] + }, + "CyberCat.ADBAppControl": { + "icon": "https://adbappcontrol.com/assets/img/logo_blue.png", + "images": [ + "https://adbappcontrol.com/assets/img/scr-main.jpg", + "https://adbappcontrol.com/assets/img/scr-extended.jpg", + "https://adbappcontrol.com/assets/img/scr-wizard.jpg", + "https://adbappcontrol.com/assets/img/scr-tools.jpg" + ] + }, + "CyberPowerSystemsInc.PowerPanelPer\u2026": { + "icon": "", + "images": [] + }, + "Cygwin.Cygwin": { + "icon": "", + "images": [] + }, + "Cyotek.ColorPaletteEditor": { + "icon": "", + "images": [] + }, + "Cyotek.CopyTools": { + "icon": "", + "images": [] + }, + "Cyotek.SitemapCreator": { + "icon": "", + "images": [] + }, + "Cyotek.WebCopy": { + "icon": "", + "images": [] + }, + "D4koon.WhatsappTray": { + "icon": "", + "images": [] + }, + "DaanavSoftwares.AutoKeyboard": { + "icon": "", + "images": [ + "https://www.murgee.com/auto-keyboard/images/auto-keyboard.png" + ] + }, + "dail8859.NotepadNext": { + "icon": "", + "images": [] + }, + "DaiyuuNobori.Win10Pcap": { + "icon": "", + "images": [] + }, + "daltonmenezes.electron-screen-reco\u2026": { + "icon": "", + "images": [] + }, + "DaMtech.PasswordGenerator": { + "icon": "", + "images": [] + }, + "dangeredwolf.ModernDeck": { + "icon": "", + "images": [] + }, + "DanTheMan827.ClassicContext": { + "icon": "", + "images": [] + }, + "Dapr.CLI": { + "icon": "", + "images": [] + }, + "Dapr.CLI.Preview": { + "icon": "", + "images": [] + }, + "DaringDevelopmentInc.Horizon": { + "icon": "", + "images": [] + }, + "DarkfullDante.srtAlign": { + "icon": "", + "images": [] + }, + "DarkfullDante.wol": { + "icon": "", + "images": [] + }, + "darktable.darktable": { + "icon": "", + "images": [] + }, + "Dashlane.Dashlane": { + "icon": "", + "images": [] + }, + "DasKeyboard.DasKeyboard": { + "icon": "", + "images": [] + }, + "Datadog.Agent": { + "icon": "", + "images": [] + }, + "Datadog.dd-trace-dotnet": { + "icon": "", + "images": [] + }, + "Datalust.Seq": { + "icon": "", + "images": [] + }, + "DataPLANT.ArcCommander": { + "icon": "", + "images": [] + }, + "Datronicsoft.SpacedeskDriver.Client": { + "icon": "", + "images": [] + }, + "Datronicsoft.SpacedeskDriver.Server": { + "icon": "", + "images": [] + }, + "Datto.WindowsAgent": { + "icon": "", + "images": [] + }, + "Daum.PotPlayer": { + "icon": "", + "images": [] + }, + "DavidJoffe.DaveGnukem": { + "icon": "", + "images": [] + }, + "DavidMoore.IPFilterUpdater": { + "icon": "", + "images": [] + }, + "DavidNorgren.Mine-imator": { + "icon": "", + "images": [] + }, + "DavidRector.Linkage": { + "icon": "", + "images": [] + }, + "DavidRios.Remindr": { + "icon": "", + "images": [] + }, + "DavidTHOIRON.FotoSketcher": { + "icon": "", + "images": [] + }, + "DavidWheatley.fs2020-livery-manager": { + "icon": "", + "images": [] + }, + "dawg.dawg": { + "icon": "", + "images": [] + }, + "DaxStudio.DaxStudio": { + "icon": "", + "images": [] + }, + "DBBrowserForSQLite.DBBrowserForSQL\u2026": { + "icon": "", + "images": [] + }, + "dbeaver.dbeaver": { + "icon": "", + "images": [] + }, + "DCSS.DungeonCrawlStoneSoup": { + "icon": "", + "images": [] + }, + "DeaDBeeF.DeaDBeeF": { + "icon": "", + "images": [] + }, + "DebaucheeOpenSourceGroup.Barrier": { + "icon": "", + "images": [] + }, + "Debian.Debian": { + "icon": "", + "images": [] + }, + "dechamps.FlexASIO": { + "icon": "", + "images": [] + }, + "deep5050.MrDclutterer": { + "icon": "", + "images": [] + }, + "deep5050.qikQR": { + "icon": "", + "images": [] + }, + "DeepL.DeepL": { + "icon": "", + "images": [] + }, + "deepnight.LDtk": { + "icon": "", + "images": [] + }, + "Deezer.Deezer": { + "icon": "", + "images": [] + }, + "defi.defi": { + "icon": "", + "images": [] + }, + "Dell.CommandConfigure": { + "icon": "", + "images": [] + }, + "Dell.CommandUpdate": { + "icon": "", + "images": [] + }, + "Dell.CommandUpdate.Universal": { + "icon": "", + "images": [] + }, + "Dell.DisplayManager": { + "icon": "", + "images": [] + }, + "deltachat.deltachat": { + "icon": "", + "images": [] + }, + "DelugeTeam.Deluge": { + "icon": "", + "images": [] + }, + "DelugeTeam.DelugeBeta": { + "icon": "", + "images": [] + }, + "den4b.Colors": { + "icon": "", + "images": [] + }, + "den4b.Hasher": { + "icon": "", + "images": [] + }, + "den4b.RandPass": { + "icon": "", + "images": [] + }, + "den4b.ReNamer": { + "icon": "", + "images": [] + }, + "den4b.Resizer": { + "icon": "", + "images": [] + }, + "den4b.Shutter": { + "icon": "", + "images": [] + }, + "deskfiler.deskfiler": { + "icon": "", + "images": [] + }, + "DeskRelief.SitHealthy": { + "icon": "", + "images": [] + }, + "DeskSoft.EarthView": { + "icon": "", + "images": [] + }, + "dev47apps.DroidCam": { + "icon": "", + "images": [] + }, + "DevHub.DevHub": { + "icon": "", + "images": [] + }, + "Devolutions.RemoteDesktopManager": { + "icon": "", + "images": [] + }, + "Devolutions.RemoteDesktopManagerFr\u2026": { + "icon": "", + "images": [] + }, + "DFRobot.Mind+": { + "icon": "", + "images": [] + }, + "DH2iCompany.DxEnterprise": { + "icon": "", + "images": [] + }, + "Dialpad.Dialpad": { + "icon": "", + "images": [] + }, + "Dicarne.TheCenter": { + "icon": "", + "images": [] + }, + "Dichromate.Browser": { + "icon": "", + "images": [] + }, + "DiegoFernandes.jsdesign": { + "icon": "", + "images": [] + }, + "DigiDNA.iMazing": { + "icon": "", + "images": [] + }, + "DigiDNA.iMazingHEICConverter": { + "icon": "", + "images": [] + }, + "DigiDNA.iMazingProfileEditor": { + "icon": "", + "images": [] + }, + "Digimezzo.Dopamine.2": { + "icon": "", + "images": [] + }, + "Digimezzo.Dopamine.3": { + "icon": "", + "images": [] + }, + "Digimezzo.Knowte": { + "icon": "", + "images": [] + }, + "DigiPen.NitronicRush": { + "icon": "", + "images": [] + }, + "DigitalCreations.MaxTo": { + "icon": "", + "images": [] + }, + "DigitalExtremes.Warframe": { + "icon": "", + "images": [] + }, + "DigitalVolcanoSoftware.DuplicateCl\u2026": { + "icon": "", + "images": [] + }, + "Diladele.WebProxy": { + "icon": "", + "images": [] + }, + "dillonkearns.mobster": { + "icon": "", + "images": [] + }, + "DimitriVanHeesch.Doxygen": { + "icon": "", + "images": [] + }, + "Dio.PureCodec": { + "icon": "", + "images": [] + }, + "Discord.Discord": { + "icon": "https://i.ibb.co/VJN801L/release-and-ptb.png", + "images": [ + "https://i.ibb.co/5M0bd2N/discord-1.png", + "https://i.ibb.co/hcBnn6x/discord-2.png", + "https://i.ibb.co/GFdRfcy/discord-3.png" + ] + }, + "Discord.Discord.Canary": { + "icon": "https://i.ibb.co/9qxY46z/canary.png", + "images": [ + "https://i.ibb.co/5M0bd2N/discord-1.png", + "https://i.ibb.co/hcBnn6x/discord-2.png", + "https://i.ibb.co/GFdRfcy/discord-3.png" + ] + }, + "Discord.Discord.Development": { + "icon": "", + "images": [ + "https://i.ibb.co/5M0bd2N/discord-1.png", + "https://i.ibb.co/hcBnn6x/discord-2.png", + "https://i.ibb.co/GFdRfcy/discord-3.png" + ] + }, + "Discord.Discord.PTB": { + "icon": "https://i.ibb.co/VJN801L/release-and-ptb.png", + "images": [ + "https://i.ibb.co/5M0bd2N/discord-1.png", + "https://i.ibb.co/hcBnn6x/discord-2.png", + "https://i.ibb.co/GFdRfcy/discord-3.png" + ] + }, + "DiskInternals.LinuxReader": { + "icon": "", + "images": [] + }, + "DisplayLink.GraphicsDriver": { + "icon": "", + "images": [] + }, + "DisruptiveInnovationsSAS.BlueGriff\u2026": { + "icon": "", + "images": [] + }, + "Ditto.Ditto": { + "icon": "", + "images": [] + }, + "Dixa.Dixa": { + "icon": "", + "images": [] + }, + "DJI.DJIAssistant2": { + "icon": "", + "images": [] + }, + "DJI.DJIAssistant2.ConsumerSeries": { + "icon": "", + "images": [] + }, + "DJI.DJIAssistant2.EnterpriseSeries": { + "icon": "", + "images": [] + }, + "DJI.DJIAssistant2.ForAutopilot": { + "icon": "", + "images": [] + }, + "DJI.DJIAssistant2.ForBatteryStation": { + "icon": "", + "images": [] + }, + "DJI.DJIAssistant2.ForMatrice": { + "icon": "", + "images": [] + }, + "DJI.DJIAssistant2.ForMavic": { + "icon": "", + "images": [] + }, + "DJI.DJIAssistant2.ForMG": { + "icon": "", + "images": [] + }, + "DJI.DJIAssistant2.ForPhantom": { + "icon": "", + "images": [] + }, + "DJI.DJIAssistant2.FPV": { + "icon": "", + "images": [] + }, + "DjVuLibre.DjView": { + "icon": "", + "images": [] + }, + "Dlang.DMD": { + "icon": "", + "images": [] + }, + "Dlang.VisualD": { + "icon": "", + "images": [] + }, + "Dmitry-Farafonov.MicSwitch": { + "icon": "", + "images": [] + }, + "DmitryKozhinov.IconEdit2": { + "icon": "", + "images": [] + }, + "DMM.GamePlayer": { + "icon": "", + "images": [] + }, + "dnGrep.dnGrep": { + "icon": "", + "images": [] + }, + "Docker.DockerDesktop": { + "icon": "", + "images": [] + }, + "Docker.DockerDesktopEdge": { + "icon": "", + "images": [] + }, + "DockStation.DockStation": { + "icon": "", + "images": [] + }, + "docmirror.dev-sidecar": { + "icon": "", + "images": [] + }, + "DocumizeInc.Zerabase": { + "icon": "", + "images": [] + }, + "DoDPKE.InstallRoot": { + "icon": "", + "images": [] + }, + "DogecoinCoreproject.DogecoinCore": { + "icon": "", + "images": [] + }, + "Dogramming.Imaconverter": { + "icon": "", + "images": [] + }, + "Doist.Todoist": { + "icon": "", + "images": [] + }, + "dokan-dev.Dokany": { + "icon": "", + "images": [] + }, + "DolphinEmulator.Dolphin": { + "icon": "", + "images": [] + }, + "DoltHub.Dolt": { + "icon": "", + "images": [] + }, + "DominikReichl.KeePass": { + "icon": "", + "images": [] + }, + "DonationCoder.FindandRunRobot": { + "icon": "", + "images": [] + }, + "DonationCoder.ScreenshotCaptor": { + "icon": "", + "images": [] + }, + "Donkz.RemoteDesktopPlus": { + "icon": "", + "images": [] + }, + "dorssel.usbipd-win": { + "icon": "", + "images": [] + }, + "DOSBox.DOSBox": { + "icon": "", + "images": [] + }, + "dotenorio.clipboard-manager-electr\u2026": { + "icon": "", + "images": [] + }, + "Douyu.DouyuLive": { + "icon": "", + "images": [] + }, + "DownloadHelper.VdhCoApp": { + "icon": "", + "images": [] + }, + "Doxie.Doxie": { + "icon": "", + "images": [] + }, + "DrakeetXu.PureWriter": { + "icon": "", + "images": [] + }, + "drakkan.SFTPGo": { + "icon": "", + "images": [] + }, + "Drawpile.Drawpile": { + "icon": "", + "images": [] + }, + "dreamus.flo": { + "icon": "", + "images": [] + }, + "DrewNaylor.guinget": { + "icon": "", + "images": [] + }, + "DrewNaylor.UXL-Launcher": { + "icon": "", + "images": [] + }, + "Dropbox.Dropbox": { + "icon": "", + "images": [] + }, + "Drovio.Drovio": { + "icon": "", + "images": [] + }, + "drscaon.OneLeft": { + "icon": "", + "images": [] + }, + "Drumstick.dmidiplayer": { + "icon": "", + "images": [] + }, + "dscalzi.HeliosLauncher": { + "icon": "", + "images": [] + }, + "dsheiko.puppetry": { + "icon": "", + "images": [] + }, + "DucFabulous.UltraViewer": { + "icon": "", + "images": [] + }, + "dumbasPL.CSGOAccountChecker": { + "icon": "", + "images": [] + }, + "Dummerle.Rare": { + "icon": "", + "images": [] + }, + "DuongDieuPhap.ImageGlass": { + "icon": "", + "images": [] + }, + "DuoSecurity.Duo2FAAuthenticationfo\u2026": { + "icon": "", + "images": [] + }, + "Duowan.YY": { + "icon": "", + "images": [] + }, + "DupeGuru.DupeGuru": { + "icon": "", + "images": [] + }, + "Duplicati.Duplicati": { + "icon": "", + "images": [] + }, + "dvcrn.markright": { + "icon": "", + "images": [] + }, + "DVDFlick.DVDFlick": { + "icon": "", + "images": [] + }, + "DygmaLabs.Bazecor": { + "icon": "https://i.imgur.com/sblG8Td.png", + "images": [ + "https://github.com/Dygmalab/Bazecor/raw/development/data/screenshot.png", + "https://i.imgur.com/glj06fJ.png" + ] + }, + "Dynalist.Dynalist": { + "icon": "", + "images": [] + }, + "dynobo.NormCap": { + "icon": "", + "images": [] + }, + "dziemborowicz.hourglass": { + "icon": "", + "images": [] + }, + "e2eSoft.iVCam": { + "icon": "", + "images": [] + }, + "EagleDynamics.DCSWorld": { + "icon": "", + "images": [] + }, + "EaseUS.DataRecovery": { + "icon": "", + "images": [] + }, + "EaseUS.PartitionMaster": { + "icon": "", + "images": [] + }, + "EaseUS.TodoBackup": { + "icon": "", + "images": [] + }, + "Easeware.DriverEasy": { + "icon": "", + "images": [] + }, + "Eassos.DiskGenius": { + "icon": "", + "images": [] + }, + "Eassos.EassosRecovery": { + "icon": "", + "images": [] + }, + "EasternGraphics.pCon.plannerSTD": { + "icon": "", + "images": [] + }, + "EasyEDAinc.EasyEDA": { + "icon": "", + "images": [] + }, + "easymodo.qimgv": { + "icon": "", + "images": [] + }, + "Ebbflow.Ebbflow": { + "icon": "", + "images": [] + }, + "EclipseAdoptium.Temurin.11.JDK": { + "icon": "", + "images": [] + }, + "EclipseAdoptium.Temurin.11.JRE": { + "icon": "", + "images": [] + }, + "EclipseAdoptium.Temurin.16.JDK": { + "icon": "", + "images": [] + }, + "EclipseAdoptium.Temurin.17.JDK": { + "icon": "", + "images": [] + }, + "EclipseAdoptium.Temurin.17.JRE": { + "icon": "", + "images": [] + }, + "EclipseAdoptium.Temurin.18.JDK": { + "icon": "", + "images": [] + }, + "EclipseAdoptium.Temurin.18.JRE": { + "icon": "", + "images": [] + }, + "EclipseAdoptium.Temurin.19.JDK": { + "icon": "", + "images": [] + }, + "EclipseAdoptium.Temurin.19.JRE": { + "icon": "", + "images": [] + }, + "EclipseAdoptium.Temurin.20.JDK": { + "icon": "", + "images": [] + }, + "EclipseAdoptium.Temurin.20.JRE": { + "icon": "", + "images": [] + }, + "EclipseAdoptium.Temurin.8.JDK": { + "icon": "", + "images": [] + }, + "EclipseAdoptium.Temurin.8.JRE": { + "icon": "", + "images": [] + }, + "EclipseFoundation.Mosquitto": { + "icon": "", + "images": [] + }, + "EclipseFoundation.SUMO": { + "icon": "", + "images": [] + }, + "EclipseFoundation.TheiaBlueprint": { + "icon": "", + "images": [] + }, + "EDCD.EliteDangerousMarketConnector": { + "icon": "", + "images": [] + }, + "EddieWang.Sia-UI": { + "icon": "", + "images": [] + }, + "EdrawSoft.EdrawInfo": { + "icon": "", + "images": [] + }, + "EdrawSoft.EdrawInfo.CN": { + "icon": "", + "images": [] + }, + "EdrawSoft.EdrawMax": { + "icon": "", + "images": [] + }, + "EdrawSoft.EdrawMax.CN": { + "icon": "", + "images": [] + }, + "EdrawSoft.EdrawMind": { + "icon": "", + "images": [] + }, + "EdrawSoft.EdrawProj": { + "icon": "", + "images": [] + }, + "EdrawSoft.EdrawProj.CN": { + "icon": "", + "images": [] + }, + "EdrawSoft.MindMaster": { + "icon": "", + "images": [] + }, + "EdrawSoft.OrgCharting": { + "icon": "", + "images": [] + }, + "EdrawSoft.OrgCharting.CN": { + "icon": "", + "images": [] + }, + "EdrawSoft.ViewerComponent.Diagram": { + "icon": "", + "images": [] + }, + "EdrawSoft.ViewerComponent.Excel": { + "icon": "", + "images": [] + }, + "EdrawSoft.ViewerComponent.Office": { + "icon": "", + "images": [] + }, + "EdrawSoft.ViewerComponent.PDF": { + "icon": "", + "images": [] + }, + "EdrawSoft.ViewerComponent.Word": { + "icon": "", + "images": [] + }, + "EDRLab.Thorium": { + "icon": "", + "images": [] + }, + "EduMIPS64.EduMIPS64": { + "icon": "", + "images": [] + }, + "eeo.classin": { + "icon": "", + "images": [] + }, + "EFF.Certbot": { + "icon": "", + "images": [] + }, + "eFMer.BoincTasks": { + "icon": "", + "images": [] + }, + "Egnyte.EgnyteDesktopApp": { + "icon": "", + "images": [] + }, + "egoist.devdocs-desktop": { + "icon": "", + "images": [] + }, + "Eigenmiao.Rickrack": { + "icon": "", + "images": [] + }, + "ekvedaras.redis-gui": { + "icon": "", + "images": [] + }, + "ElaborateBytes.VirtualCloneDrive": { + "icon": "", + "images": [] + }, + "Elastic.Elasticsearch": { + "icon": "", + "images": [] + }, + "Elastic.Winlogbeat": { + "icon": "https://i.imgur.com/gaZ7moS.png", + "images": [ + "https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt6c4cbb4f3ca4258c/5ca67d82154fe31d3366f9f6/logging-winlogbeat-windows.jpg", + "https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltf5db944ddd48764f/5bbcae7b0e6edaf014d23be8/winlogbeat-account-usage-dashboard.jpg", + "https://www.tutorials24x7.com/uploads/2020-01-04/files/12-tutorials24x7-winlogbeat-kibana-dashboard.png" + ] + }, + "electerm.electerm": { + "icon": "", + "images": [] + }, + "Electron-Store.electron-app-store": { + "icon": "", + "images": [] + }, + "ElectronCash.ElectronCash": { + "icon": "", + "images": [] + }, + "ElectronCommunity.ElectronFiddle": { + "icon": "", + "images": [] + }, + "ElectronicArts.EADesktop": { + "icon": "", + "images": [] + }, + "ElectronicTeam.Flexihub": { + "icon": "", + "images": [] + }, + "ElectronicTeam.USBNetworkGate": { + "icon": "", + "images": [] + }, + "Electrum.Electrum": { + "icon": "", + "images": [] + }, + "Element.Element": { + "icon": "", + "images": [] + }, + "Elexe.ElexeLauncher": { + "icon": "", + "images": [] + }, + "Elgato.4KCaptureUtility": { + "icon": "https://img.informer.com/icons/png/128/6862/6862311.png", + "images": [ + "https://help.elgato.com/hc/article_attachments/4405457555597/Interface_Main_2_copy.png", + "https://help.elgato.com/hc/article_attachments/4405465427085/Interface_Main_1_copy.png" + ] + }, + "Elgato.CameraHub": { + "icon": "", + "images": [] + }, + "Elgato.ControlCenter": { + "icon": "", + "images": [] + }, + "Elgato.EpocCam": { + "icon": "", + "images": [] + }, + "Elgato.GameCapture.4K60ProMK2": { + "icon": "", + "images": [] + }, + "Elgato.GameCapture.HD": { + "icon": "", + "images": [] + }, + "Elgato.GameCapture.HD60S": { + "icon": "", + "images": [] + }, + "Elgato.StreamDeck": { + "icon": "", + "images": [] + }, + "Elgato.WaveLink": { + "icon": "", + "images": [] + }, + "EliasFotinis.DeskPins": { + "icon": "", + "images": [] + }, + "eliboa.TegraRcmGUI": { + "icon": "", + "images": [] + }, + "elieserdejesus.JamTaba": { + "icon": "", + "images": [] + }, + "ElijahLopez.MusicCaster": { + "icon": "", + "images": [] + }, + "eloston.ungoogled-chromium": { + "icon": "", + "images": [] + }, + "ElstenSoftware.Astiga": { + "icon": "https://dashboard.snapcraft.io/site_media/appmedia/2020/01/Logo_Dropbox.png", + "images": [ + "https://d4.alternativeto.net/j2WRZ3ufq9KpRm9sRo-dNl_y9Xe_T16Q8rr6CcVeUsM/rs:fit:1200:1200:0/g:ce:0:0/YWJzOi8vZGlzdC9zL2FzdGlnYV8yMzI0NzNfZnVsbC5wbmc.jpg", + "https://res.cloudinary.com/canonical/image/fetch/f_auto,q_auto,fl_sanitize,w_819,h_436/https://dashboard.snapcraft.io/site_media/appmedia/2020/01/Screenshot_from_2020-01-10_01-16-33.png", + "https://preview.redd.it/3ouoq4atpdq91.png?auto=webp&s=b1c7e76401629916ac71743e6cb7e8b7420b0628" + ] + }, + "elvirbrk.notehighlight2016": { + "icon": "", + "images": [] + }, + "Embarcadero.Dev-C++": { + "icon": "", + "images": [] + }, + "eMClient.eMClient": { + "icon": "", + "images": [] + }, + "EmoteInteractive.RemoteMouse": { + "icon": "", + "images": [] + }, + "Empoche.Empoche": { + "icon": "", + "images": [] + }, + "emqx.mqttx": { + "icon": "", + "images": [] + }, + "Emulationstation.Emulationstation": { + "icon": "", + "images": [] + }, + "eMule.eMule": { + "icon": "", + "images": [] + }, + "eMule.eMule.community": { + "icon": "", + "images": [] + }, + "Emurasoft.EmEditor": { + "icon": "", + "images": [] + }, + "EnarxProject.enarx": { + "icon": "", + "images": [] + }, + "endcloud.BBHouse": { + "icon": "https://i.imgur.com/c1Ne2d2.png", + "images": [ + "https://github.com/endcloud/bbhouse-tauri/raw/master/doc/1660423610.png", + "https://github.com/endcloud/bbhouse-tauri/raw/master/doc/Xnip2022-08-14_18-37-21.jpg" + ] + }, + "ente-io.ente": { + "icon": "", + "images": [] + }, + "Enterbrain.RGSS-RTPStandard": { + "icon": "", + "images": [] + }, + "EpicGames.EpicGamesLauncher": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/3/31/Epic_Games_logo.svg/207px-Epic_Games_logo.svg.png", + "images": [ + "https://i.postimg.cc/QtBQnP70/egs-social-home-medium-1710x942-c0e4ff4c149e.jpg" + ] + }, + "Epilogue.EpilogueOperator": { + "icon": "", + "images": [] + }, + "Epsitec.Colobot": { + "icon": "", + "images": [] + }, + "Epsitec.PlanetBlupi": { + "icon": "", + "images": [] + }, + "EQAditu.AdvancedCombatTracker": { + "icon": "https://advancedcombattracker.com/act_data/act_banner1.png", + "images": [ + "https://advancedcombattracker.com/screenshots/2_1037-StartupWizard.png", + "https://advancedcombattracker.com/screenshots/2_1105-EncounterContext.png", + "https://advancedcombattracker.com/screenshots/2_1109-Combatant.png", + "https://advancedcombattracker.com/screenshots/2_1130-AttackType.png", + "https://advancedcombattracker.com/screenshots/2_1113-DamageType.png", + "https://advancedcombattracker.com/screenshots/2_1131-ViewLogs.png", + "https://advancedcombattracker.com/screenshots/2_1137-SpellTimers-Calc.png", + "https://advancedcombattracker.com/screenshots/2_1138-TimerOptions.png", + "https://advancedcombattracker.com/screenshots/2_1140-ZoneAvoidReport.png", + "https://advancedcombattracker.com/screenshots/2_1142-PlayerAvoidance.png", + "https://advancedcombattracker.com/screenshots/2_1145-SpecialsReport.png", + "https://advancedcombattracker.com/screenshots/2_1150-DeathReport.png", + "https://advancedcombattracker.com/screenshots/2_1157-EncounterVcr.png", + "https://advancedcombattracker.com/screenshots/2_1201-Timeline.png", + "https://advancedcombattracker.com/screenshots/2_1206-BreakdownCombatant.png", + "https://advancedcombattracker.com/screenshots/2_1234-OpMisc.png", + "https://advancedcombattracker.com/screenshots/2_1235-OpXmlShare.png", + "https://advancedcombattracker.com/screenshots/2_1238-OpXmlConfig.png", + "https://advancedcombattracker.com/screenshots/2_1240-OpG19.png", + "https://advancedcombattracker.com/screenshots/2_1241-OpEncTable.png", + "https://advancedcombattracker.com/screenshots/2_1256-OpMini.png" + ] + }, + "Eraser.Eraser": { + "icon": "", + "images": [] + }, + "erengy.Taiga": { + "icon": "", + "images": [] + }, + "Ergosoft.ErgoFAKT_V5": { + "icon": "", + "images": [] + }, + "erikbra.grate": { + "icon": "", + "images": [] + }, + "Erlang.ErlangOTP": { + "icon": "", + "images": [] + }, + "ErykRakowski.Multrin": { + "icon": "", + "images": [] + }, + "EryouHao.Gridea": { + "icon": "", + "images": [] + }, + "ES-Computing.EditPlus": { + "icon": "", + "images": [] + }, + "ESET.EndpointAntivirus": { + "icon": "", + "images": [] + }, + "ESET.EndpointSecurity": { + "icon": "", + "images": [] + }, + "ESET.Nod32": { + "icon": "", + "images": [] + }, + "ESET.Security": { + "icon": "", + "images": [] + }, + "Espanso.Espanso": { + "icon": "", + "images": [] + }, + "espeak.espeak": { + "icon": "", + "images": [] + }, + "Esteem.Esteem": { + "icon": "", + "images": [] + }, + "eTeks.SweetHome3D": { + "icon": "", + "images": [] + }, + "Ethereum.geth": { + "icon": "", + "images": [] + }, + "Ethereum.grid": { + "icon": "", + "images": [] + }, + "ETHZurich.SafeExamBrowser": { + "icon": "", + "images": [] + }, + "EtternaProject.EtternaGame": { + "icon": "", + "images": [] + }, + "ETXSoftwareInc.DuckDns": { + "icon": "", + "images": [] + }, + "Eugeny.Tabby": { + "icon": "", + "images": [] + }, + "EuSoft.Eudic": { + "icon": "", + "images": [] + }, + "EvanCzaplicki.Elm": { + "icon": "", + "images": [] + }, + "EVEMonDevelopmentTeam.EVEMon": { + "icon": "", + "images": [] + }, + "eVenture.HideMe": { + "icon": "", + "images": [] + }, + "EverEdit.EverEdit": { + "icon": "", + "images": [] + }, + "evernote.evernote": { + "icon": "", + "images": [] + }, + "evernote.yinxiang": { + "icon": "", + "images": [] + }, + "Evoluent.EvoluentMouseManager": { + "icon": "", + "images": [] + }, + "Evolus.Pencil": { + "icon": "", + "images": [] + }, + "evsar3.sshfs-win-manager": { + "icon": "", + "images": [] + }, + "ExclaimerLtd.CloudSignatureUpdateA\u2026": { + "icon": "", + "images": [] + }, + "ExodusMovement.Exodus": { + "icon": "", + "images": [] + }, + "Exploitox.CheckIP": { + "icon": "", + "images": [] + }, + "ExpressLRS.ExpressLRS-Configurator": { + "icon": "", + "images": [] + }, + "ExpressVPN.ExpressVPN": { + "icon": "", + "images": [] + }, + "EXPSystems.PDFreDirect": { + "icon": "", + "images": [] + }, + "ExtendOffice.OfficeTab": { + "icon": "", + "images": [] + }, + "ExtendOffice.OfficeTab.Enterprise": { + "icon": "", + "images": [] + }, + "ExtremeTuxRacer.ExtremeTuxRacer": { + "icon": "", + "images": [] + }, + "EYHN.SpaceThumbnails": { + "icon": "", + "images": [] + }, + "EZBSystems.EasyBoot": { + "icon": "", + "images": [] + }, + "EZBSystems.UltraISO": { + "icon": "", + "images": [] + }, + "Eziriz.DotNetReactor": { + "icon": "https://i0.wp.com/filecr.com/wp-content/uploads/2021/03/net-reactor-logo.png", + "images": [ + "https://www.eziriz.com/images/screenshot_r_files_m.jpg", + "https://www.eziriz.com/images/screenshot_r_settings1_m.jpg", + "https://www.eziriz.com/images/screenshot_r_settings2_m.jpg", + "https://www.eziriz.com/images/screenshot_r_settings3_m.jpg", + "https://www.eziriz.com/images/screenshot_r_lm_m.jpg", + "https://www.eziriz.com/images/screenshot_r_inspector_m.jpg", + "https://www.eziriz.com/images/screenshot_r_presets_m.jpg", + "https://www.eziriz.com/images/screenshot_r_protect_m.jpg", + "https://www.eziriz.com/images/screenshot_r_rules_m.jpg", + "https://www.eziriz.com/images/screenshot_deobfuscator_m.jpg", + "https://www.eziriz.com/images/screenshot_nr_dark_m.jpg", + "https://www.eziriz.com/images/screenshot_nr_green_m.jpg", + "https://www.eziriz.com/images/screenshot_nr_classic_m.jpg" + ] + }, + "F-Secure.Freedome": { + "icon": "", + "images": [] + }, + "Fabio286.antares": { + "icon": "https://antares-sql.app/_nuxt/logo.3ded7749.png", + "images": [ + "https://raw.githubusercontent.com/Fabio286/antares/master/docs/gh-logo.png", + "https://antares-sql.app/images/screen1c.png", + "https://antares-sql.app/images/screen4.png", + "https://res.cloudinary.com/canonical/image/fetch/f_auto,q_auto,fl_sanitize,w_819,h_569/https://dashboard.snapcraft.io/site_media/appmedia/2022/09/Immagine_2022-09-22_101124.png", + "https://pbs.twimg.com/media/FMWoNXpXMAM7avj.jpg" + ] + }, + "Facebook.Messenger": { + "icon": "", + "images": [] + }, + "FACEITLTD.FACEITAC": { + "icon": "", + "images": [] + }, + "FACEITLTD.FACEITClient": { + "icon": "", + "images": [] + }, + "FadeIn.FadeIn": { + "icon": "", + "images": [] + }, + "fairdataihub.FAIRshare": { + "icon": "", + "images": [] + }, + "fairdataihub.SODA-for-SPARC": { + "icon": "", + "images": [] + }, + "Faithlife.Logos": { + "icon": "", + "images": [] + }, + "FalconNL93.WSLToolbox": { + "icon": "", + "images": [] + }, + "Famatech.AdvancedIPScanner": { + "icon": "https://i.imgur.com/BDtf1F4.png", + "images": [ + "https://www.advanced-ip-scanner.com/images/aips/screenshots/25/en/main.png", + "https://www.advanced-ip-scanner.com/images/aips/screenshots/24/en/11_tracert.png", + "https://www.advanced-ip-scanner.com/images/aips/screenshots/24/en/07_radmin_control.png", + "https://images.sftcdn.net/images/t_app-cover-l,f_auto/p/8f6d6c3c-96d1-11e6-af95-00163ec9f5fa/3327930924/advanced-ip-scanner-eng%202.jpg", + "https://images.sftcdn.net/images/t_app-cover-l,f_auto/p/8f6d6c3c-96d1-11e6-af95-00163ec9f5fa/3155941051/advanced-ip-scanner-eng%203.jpg" + ] + }, + "FancyNode.PxCook": { + "icon": "", + "images": [] + }, + "Fangamer.Deltarune": { + "icon": "", + "images": [] + }, + "FarManager.FarManager": { + "icon": "", + "images": [] + }, + "FastCopy.FastCopy": { + "icon": "", + "images": [] + }, + "FastCopy.IPMsg": { + "icon": "", + "images": [] + }, + "FastStone.Capture": { + "icon": "", + "images": [] + }, + "FastStone.Viewer": { + "icon": "", + "images": [] + }, + "FedericoTerzi.espanso": { + "icon": "", + "images": [] + }, + "Fedora.CoreOS.butane": { + "icon": "", + "images": [] + }, + "Fedora.FedoraMediaWriter": { + "icon": "", + "images": [] + }, + "FelipeEFdeCastro.Klavaro": { + "icon": "", + "images": [] + }, + "FelipeSantos.ClipboardSync": { + "icon": "", + "images": [] + }, + "feliskio.sleep-timer": { + "icon": "", + "images": [] + }, + "felixgborrego.simple-docker-ui": { + "icon": "", + "images": [] + }, + "FelixRieseberg.MacintoshJS": { + "icon": "", + "images": [] + }, + "FelixRieseberg.Windows95": { + "icon": "", + "images": [] + }, + "FengHe.FocusNote": { + "icon": "", + "images": [] + }, + "FengHe.Migi": { + "icon": "", + "images": [] + }, + "FenoPhoto.FenoPhoto": { + "icon": "", + "images": [] + }, + "Fenrirthviti.obs-virtual-cam": { + "icon": "", + "images": [] + }, + "Feodor2.Mypal": { + "icon": "", + "images": [] + }, + "Ferdium.Ferdium": { + "icon": "", + "images": [ + "https://i.postimg.cc/05wGYTPN/workspaces.png" + ] + }, + "Ferdium.Ferdium.Beta": { + "icon": "", + "images": [] + }, + "Ferdium.Ferdium.Nightly": { + "icon": "", + "images": [] + }, + "fetacore.InfiniTex": { + "icon": "", + "images": [] + }, + "feugy.melodie": { + "icon": "", + "images": [] + }, + "Figma.Figma": { + "icon": "", + "images": [] + }, + "Figma.fonthelper": { + "icon": "", + "images": [] + }, + "File-New-Project.EarTrumpet": { + "icon": "", + "images": [] + }, + "FilenCloud.FilenSync": { + "icon": "", + "images": [] + }, + "FileVoyager.FileVoyager": { + "icon": "", + "images": [] + }, + "filips.FirefoxPWA": { + "icon": "", + "images": [] + }, + "FiloSottile.mkcert": { + "icon": "", + "images": [] + }, + "FinalWire.AIDA64.Engineer": { + "icon": "https://www.apkmirror.com/wp-content/uploads/2022/09/04/633599d2228a3-384x384.png", + "images": [ + "https://www.aida64.com/sites/default/files/ee_shot_02.png", + "https://www.aida64.com/sites/default/files/ee_shot_17.png", + "https://www.aida64.com/sites/default/files/styles/screen_shot_thumbnail_400/public/ee_shot_12.png", + "https://www.aida64.com/sites/default/files/xe_shot_03.png", + "https://www.aida64.com/sites/default/files/styles/screen_shot_thumbnail_400/public/xe_shot_04.png", + "https://www.aida64.com/sites/default/files/styles/screen_shot_thumbnail_400/public/xe_shot_05.png", + "https://www.aida64.com/sites/default/files/styles/screen_shot_thumbnail_400/public/xe_shot_18.png", + "https://www.aida64.com/sites/default/files/xe_shot_06.png" + ] + }, + "FinalWire.AIDA64.Extreme": { + "icon": "https://www.apkmirror.com/wp-content/uploads/2022/09/04/633599d2228a3-384x384.png", + "images": [ + "https://www.aida64.com/sites/default/files/styles/screen_shot_thumbnail_400/public/xe_shot_01.png", + "https://www.aida64.com/sites/default/files/styles/screen_shot_thumbnail_400/public/xe_shot_02.png", + "https://www.aida64.com/sites/default/files/styles/screen_shot_thumbnail_400/public/xe_shot_03.png", + "https://www.aida64.com/sites/default/files/styles/screen_shot_thumbnail_400/public/xe_shot_04.png", + "https://www.aida64.com/sites/default/files/styles/screen_shot_thumbnail_400/public/xe_shot_05.png", + "https://www.aida64.com/sites/default/files/styles/screen_shot_thumbnail_400/public/xe_shot_06.png", + "https://www.aida64.com/sites/default/files/styles/screen_shot_thumbnail_400/public/xe_shot_07.png", + "https://www.aida64.com/sites/default/files/styles/screen_shot_thumbnail_400/public/xe_shot_08.png", + "https://www.aida64.com/sites/default/files/styles/screen_shot_thumbnail_400/public/xe_shot_09.png", + "https://www.aida64.com/sites/default/files/styles/screen_shot_thumbnail_400/public/xe_shot_10.png" + ] + }, + "FireAlpaca.FireAlpaca": { + "icon": "", + "images": [] + }, + "Firetrust.MailWasher.Free": { + "icon": "", + "images": [] + }, + "Firetrust.MailWasher.Pro": { + "icon": "", + "images": [] + }, + "Firstversionist.Polypane": { + "icon": "", + "images": [] + }, + "FischertechnikGMBH.ROBOPro": { + "icon": "", + "images": [] + }, + "fjsoft.MyPhoneExplorer": { + "icon": "", + "images": [] + }, + "Flameshot.Flameshot": { + "icon": "", + "images": [] + }, + "FlawlessWidescreen.FlawlessWidescr\u2026": { + "icon": "", + "images": [] + }, + "FleetingClarityStudios.QuickFixMyP\u2026": { + "icon": "", + "images": [] + }, + "FleetingClarityStudios.RipShout": { + "icon": "", + "images": [] + }, + "FlightGear.FlightGear": { + "icon": "", + "images": [] + }, + "floating.frame": { + "icon": "", + "images": [] + }, + "FlockFZ.Flock": { + "icon": "", + "images": [] + }, + "FlorianFechner.Cells": { + "icon": "", + "images": [] + }, + "FlorianHoech.DisplayCAL": { + "icon": "", + "images": [] + }, + "Flow-Launcher.Flow-Launcher": { + "icon": "https://imgur.com/ofCO4cO", + "images": [ + "https://imgur.com/R34RBgy", + "https://imgur.com/Z0MNbw5", + "https://imgur.com/uAr1VZf", + "https://imgur.com/CNPjvsg", + "https://imgur.com/e9qOZpy", + "https://imgur.com/Kuialsw", + "https://imgur.com/N5QrhaY" + ] + }, + "flux.flux": { + "icon": "", + "images": [] + }, + "FLVCD.Bigrats": { + "icon": "", + "images": [] + }, + "FlyByWireSimulations.FlyByWireSimu\u2026": { + "icon": "", + "images": [] + }, + "Flywheel.Local": { + "icon": "", + "images": [] + }, + "Fnatic.FnaticOP": { + "icon": "", + "images": [] + }, + "Fndroid.ClashForWindows": { + "icon": "", + "images": [] + }, + "fnordsoftware.WebMforPremiere": { + "icon": "", + "images": [] + }, + "FoldingAtHome.FoldingAtHome": { + "icon": "", + "images": [] + }, + "FontForge.FontForge": { + "icon": "", + "images": [] + }, + "Fontke.LikeFont": { + "icon": "", + "images": [] + }, + "FookesHolding.NoteTabLight": { + "icon": "", + "images": [] + }, + "ForceBindIP.ForceBindIP": { + "icon": "", + "images": [] + }, + "ForecasterCyber.Picaso": { + "icon": "", + "images": [] + }, + "ForgQi.Biliup": { + "icon": "", + "images": [] + }, + "Fork.Fork": { + "icon": "", + "images": [] + }, + "Formagrid.Airtable": { + "icon": "https://cdn.iconscout.com/icon/free/png-256/airtable-1482122-1254387.png", + "images": [ + "https://static.airtable.com/images/homescreen/homepage-sync.jpg", + "https://static.airtable.com/images/homescreen/Homepage_Poster_05_SeeValueFast_FINAL.png", + "https://static.airtable.com/images/homescreen/homepage-apps-dashboard.jpg" + ] + }, + "Fortinet.FortiClientVPN": { + "icon": "", + "images": [] + }, + "FortranLang.fpm": { + "icon": "", + "images": [] + }, + "fotor.fotor": { + "icon": "", + "images": [] + }, + "Foundry376.Mailspring": { + "icon": "", + "images": [ + "https://i.postimg.cc/W1X0pj65/hero-graphic-win32-2x.png" + ] + }, + "FoundryLabs.Devbook": { + "icon": "", + "images": [] + }, + "foxglove.studio": { + "icon": "", + "images": [] + }, + "Foxit.FoxitReader": { + "icon": "", + "images": [] + }, + "Foxit.PhantomPDF": { + "icon": "", + "images": [] + }, + "FrancescoSorge.WinPower": { + "icon": "", + "images": [] + }, + "FrancisBanyikwa.SiriKali": { + "icon": "", + "images": [] + }, + "fredserva.birdskitchen": { + "icon": "", + "images": [] + }, + "FreeCAD.FreeCAD": { + "icon": "", + "images": [] + }, + "FreeCiv.FreeCiv": { + "icon": "", + "images": [] + }, + "FreeFem.FreeFem": { + "icon": "", + "images": [] + }, + "Freelancer.Desktop": { + "icon": "", + "images": [] + }, + "FreeMat.FreeMat": { + "icon": "", + "images": [] + }, + "FreePascal.FreePascalCompiler": { + "icon": "", + "images": [] + }, + "Freeplane.Freeplane": { + "icon": "", + "images": [] + }, + "Front.scrcpy+": { + "icon": "", + "images": [] + }, + "FrostWire.FrostWire": { + "icon": "", + "images": [] + }, + "FSC-SOFT.VoiceMacro": { + "icon": "", + "images": [] + }, + "FSN.TyperspeedSepia": { + "icon": "", + "images": [] + }, + "FujitsuClientComputingLimited.Desk\u2026": { + "icon": "", + "images": [] + }, + "funnyzak.TTSNow": { + "icon": "", + "images": [] + }, + "fupdec.mediaChips": { + "icon": "", + "images": [] + }, + "Futureglobe.ActiveChart": { + "icon": "https://activechart.futureglobe.de/images/appLogo.png", + "images": [ + "https://activechart.futureglobe.de/images/screenshots/Screenshot01.PNG", + "https://activechart.futureglobe.de/images/screenshots/Screenshot02.PNG", + "https://activechart.futureglobe.de/images/screenshots/Screenshot03.PNG" + ] + }, + "Futureglobe.Dashy": { + "icon": "", + "images": [] + }, + "Futureglobe.Gibu": { + "icon": "", + "images": [] + }, + "Futureglobe.NorthReader": { + "icon": "", + "images": [] + }, + "Fuze.Fuze": { + "icon": "", + "images": [] + }, + "FXHOME.HitFilmExpress": { + "icon": "", + "images": [] + }, + "FxSoundLLC.FxSound": { + "icon": "", + "images": [] + }, + "fzf404.Monit": { + "icon": "", + "images": [] + }, + "g07cha.pomodoro": { + "icon": "", + "images": [] + }, + "G3G4X5X6.ultimate-cube": { + "icon": "", + "images": [] + }, + "GaijinNetwork.Crossout": { + "icon": "", + "images": [] + }, + "GaijinNetwork.CRSED": { + "icon": "", + "images": [] + }, + "GaijinNetwork.Enlisted": { + "icon": "", + "images": [] + }, + "GaijinNetwork.StarConflict": { + "icon": "", + "images": [] + }, + "GaijinNetwork.WarThunder": { + "icon": "", + "images": [] + }, + "Gajim.Gajim": { + "icon": "", + "images": [] + }, + "Gamecaster.Gamecaster": { + "icon": "", + "images": [] + }, + "GameGodS3.DropPoint": { + "icon": "", + "images": [] + }, + "GanttProject.GanttProject": { + "icon": "", + "images": [] + }, + "GaoYoubo.HexoClient": { + "icon": "", + "images": [] + }, + "GarboMuffin.TurboWarp": { + "icon": "", + "images": [] + }, + "Garena.Garena": { + "icon": "", + "images": [] + }, + "Garmin.BaseCamp": { + "icon": "", + "images": [] + }, + "Garmin.Express": { + "icon": "", + "images": [] + }, + "GaryBentley.QuollWriter": { + "icon": "", + "images": [] + }, + "Gather.Gather": { + "icon": "", + "images": [] + }, + "gaubert.gmvault": { + "icon": "", + "images": [] + }, + "Gauge.Gauge": { + "icon": "", + "images": [] + }, + "GauzyTech.NeatConverter": { + "icon": "", + "images": [] + }, + "GauzyTech.NeatReader": { + "icon": "", + "images": [] + }, + "GDATA.TypeRefHasher": { + "icon": "", + "images": [] + }, + "GDevelop.GDevelop": { + "icon": "", + "images": [] + }, + "gdiObjects.fotoXplorer": { + "icon": "", + "images": [] + }, + "gdiObjects.Perspective": { + "icon": "", + "images": [] + }, + "gdiObjects.xBar": { + "icon": "", + "images": [] + }, + "Geany.Geany": { + "icon": "", + "images": [] + }, + "GeekCorner.threema": { + "icon": "", + "images": [] + }, + "geeksoftwareGmbH.PDF24Creator": { + "icon": "", + "images": [] + }, + "Geert-JanBesjes.wxMUN": { + "icon": "", + "images": [] + }, + "Gekorm.Dart": { + "icon": "", + "images": [] + }, + "GenericMappingTools.gmt": { + "icon": "", + "images": [] + }, + "Genymobile.Genymotion": { + "icon": "", + "images": [] + }, + "GeoffreyChen.Paperlib": { + "icon": "", + "images": [] + }, + "GeoGebra.CalculatorSuite": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/5/57/Geogebra.svg/240px-Geogebra.svg.png", + "images": [] + }, + "GeoGebra.CASCalculator": { + "icon": "", + "images": [] + }, + "GeoGebra.Classic": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/5/57/Geogebra.svg/240px-Geogebra.svg.png", + "images": [] + }, + "GeoGebra.Classic.5": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/5/57/Geogebra.svg/240px-Geogebra.svg.png", + "images": [] + }, + "GeoGebra.Geometry": { + "icon": "", + "images": [] + }, + "GeoGebra.GraphingCalculator": { + "icon": "", + "images": [] + }, + "GEOSLOPE.GeoStudio": { + "icon": "", + "images": [] + }, + "Geoxor.Amethyst": { + "icon": "https://i.imgur.com/bbjCj4v.png", + "images": [ + "https://user-images.githubusercontent.com/34042825/193412269-fa665a95-bc3a-43bc-b730-b6734bc22765.png" + ] + }, + "Gephi.Gephi": { + "icon": "", + "images": [] + }, + "gerardog.gsudo": { + "icon": "", + "images": [] + }, + "gergelycsernak.euroscope": { + "icon": "", + "images": [] + }, + "GetData.GraphDigitizer": { + "icon": "", + "images": [] + }, + "Ghisler.TotalCommander": { + "icon": "", + "images": [] + }, + "Ghostgum.GSview": { + "icon": "", + "images": [] + }, + "GianlucaPernigotto.Videomass": { + "icon": "", + "images": [] + }, + "GielCobben.Caption": { + "icon": "", + "images": [] + }, + "GIGABYTE.AORUS-ENGINE": { + "icon": "https://pics.computerbase.de/7/7/8/1/6/logo-256.png", + "images": [ + "https://i.ytimg.com/vi/dpZHSmUwpvI/maxresdefault.jpg", + "https://www.nikktech.com/main/images/pics/reviews/gigabyte/gv_n207saorus_8gc/aorus_engine_1.jpg", + "https://www.servethehome.com/wp-content/uploads/2019/05/Gigabyte-GTX1650-OC-4GB-AORUS-Engine.jpg", + "https://www.theoverclocker.com/wp-content/uploads/2018/12/AORUS-Utility.jpg" + ] + }, + "gileli121.windowtop": { + "icon": "", + "images": [] + }, + "GilmarQuinelato.i18nManager": { + "icon": "", + "images": [] + }, + "Gimanh.handscream": { + "icon": "", + "images": [] + }, + "GIMP.GIMP": { + "icon": "", + "images": [] + }, + "GIMP.GIMP.Nightly": { + "icon": "", + "images": [] + }, + "Giorgiotani.Peazip": { + "icon": "", + "images": [] + }, + "Git.Git": { + "icon": "", + "images": [] + }, + "GitAhead.GitAhead": { + "icon": "", + "images": [] + }, + "GitExtensionsTeam.GitExtensions": { + "icon": "", + "images": [] + }, + "GitHub.Atom": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/e/e2/Atom_1.0_icon.png", + "images": [ + "https://i.imgur.com/MK7Ww1T.png", + "https://i.ytimg.com/vi/hPC6keUUiTA/maxresdefault.jpg", + "https://upload.wikimedia.org/wikipedia/commons/5/5f/Atom_screenshot_v1.41.0.png", + "https://media.wired.com/photos/590951b376f462691f0126fc/master/w_1600%2Cc_limit/screenshot-dark.png", + "https://upload.wikimedia.org/wikipedia/commons/7/7c/Screenshot_of_Atom_editor.png" + ] + }, + "GitHub.Atom.Beta": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/e/e2/Atom_1.0_icon.png", + "images": [ + "https://i.imgur.com/MK7Ww1T.png", + "https://i.ytimg.com/vi/hPC6keUUiTA/maxresdefault.jpg", + "https://upload.wikimedia.org/wikipedia/commons/5/5f/Atom_screenshot_v1.41.0.png", + "https://media.wired.com/photos/590951b376f462691f0126fc/master/w_1600%2Cc_limit/screenshot-dark.png", + "https://upload.wikimedia.org/wikipedia/commons/7/7c/Screenshot_of_Atom_editor.png" + ] + }, + "GitHub.ClassroomAssistant": { + "icon": "", + "images": [] + }, + "GitHub.cli": { + "icon": "", + "images": [] + }, + "GitHub.GitHubDesktop": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/a/ae/Github-desktop-logo-symbol.svg/128px-Github-desktop-logo-symbol.svg.png", + "images": [ + "https://desktop.github.com/images/github-desktop-screenshot-windows.png", + "https://docs.github.com/assets/cb-23214/images/help/desktop/windows-choose-options.png", + "https://docs.github.com/assets/cb-62319/images/help/desktop/commit-revert-win.png" + ] + }, + "GitHub.GitHubDesktop.Beta": { + "icon": "", + "images": [] + }, + "GitHub.GitLFS": { + "icon": "", + "images": [] + }, + "Gitlab.Gitter": { + "icon": "", + "images": [] + }, + "Gitlab.Runner": { + "icon": "", + "images": [] + }, + "gitthermal.thermal": { + "icon": "", + "images": [] + }, + "Giuspen.Cherrytree": { + "icon": "", + "images": [] + }, + "gjthompson1.glue": { + "icon": "", + "images": [] + }, + "GLab.GLab": { + "icon": "", + "images": [] + }, + "Glarysoft.FileRecoveryFree": { + "icon": "", + "images": [] + }, + "Glarysoft.GlaryUtilities": { + "icon": "", + "images": [] + }, + "GlassWire.GlassWire": { + "icon": "", + "images": [] + }, + "GlassWire.GlassWire.Lite": { + "icon": "", + "images": [] + }, + "GlavSoft.TightVNC": { + "icon": "", + "images": [] + }, + "Glecun.soundboard": { + "icon": "", + "images": [] + }, + "GlenSawyer.MP3Gain": { + "icon": "", + "images": [] + }, + "Glimpse.Glimpse": { + "icon": "", + "images": [] + }, + "Glodon.CADReader": { + "icon": "", + "images": [] + }, + "Glodon.CADReader.CN": { + "icon": "", + "images": [] + }, + "Gluon.SceneBuilder": { + "icon": "", + "images": [] + }, + "Gluon.SceneBuilder.18": { + "icon": "", + "images": [] + }, + "GlyphrStudio.Desktop": { + "icon": "", + "images": [] + }, + "GNE.DualMonitorTools": { + "icon": "", + "images": [] + }, + "gnome.Dia": { + "icon": "", + "images": [] + }, + "gnome.gedit": { + "icon": "", + "images": [] + }, + "gnome.gitg": { + "icon": "", + "images": [] + }, + "GNU.Emacs": { + "icon": "", + "images": [] + }, + "GNU.Gforth": { + "icon": "", + "images": [] + }, + "GNU.MidnightCommander": { + "icon": "", + "images": [] + }, + "GNU.Nano": { + "icon": "", + "images": [] + }, + "GNU.Octave": { + "icon": "", + "images": [] + }, + "GNU.Solfege": { + "icon": "", + "images": [] + }, + "GNU.TeXmacs": { + "icon": "", + "images": [] + }, + "GnuCash.GnuCash": { + "icon": "", + "images": [] + }, + "GnuPG.GnuPG": { + "icon": "https://www.tech-faq.com/wp-content/uploads/gnupg-shell.png", + "images": [ + "https://www.tech-faq.com/gnupg-shell/keyring_editor.png", + "https://www.tech-faq.com/gnupg-shell/create_new_keyring.png", + "https://www.tech-faq.com/gnupg-shell/file_manager.png" + ] + }, + "GnuPG.Gpg4win": { + "icon": "https://www.gpg4win.org/img/logo_gpg4win_for_microblogs.png", + "images": [ + "https://www.gpg4win.org/img/screenshots/sc-inst-welcome_en.png", + "https://www.gpg4win.org/img/screenshots/h250.sc-inst-welcome_en.png", + "https://www.gpg4win.org/img/screenshots/h250.sc-kleopatra-configureCertificateserver_en.png" + ] + }, + "gnuplot.gnuplot": { + "icon": "", + "images": [] + }, + "GnuWin32.Grep": { + "icon": "", + "images": [] + }, + "GnuWin32.Make": { + "icon": "", + "images": [] + }, + "GnuWin32.Tar": { + "icon": "", + "images": [] + }, + "GnuWin32.Tree": { + "icon": "", + "images": [] + }, + "GnuWin32.UnZip": { + "icon": "", + "images": [] + }, + "GnuWin32.Zip": { + "icon": "", + "images": [] + }, + "goatcorp.XIVLauncher": { + "icon": "", + "images": [] + }, + "GoCD.Agent": { + "icon": "", + "images": [] + }, + "GoCD.Server": { + "icon": "", + "images": [] + }, + "GOG.Galaxy": { + "icon": "", + "images": [] + }, + "GoLang.Go.1.17": { + "icon": "", + "images": [] + }, + "GoLang.Go.1.18": { + "icon": "", + "images": [] + }, + "GoLang.Go.1.19": { + "icon": "", + "images": [] + }, + "GoLang.Go.Unstable": { + "icon": "", + "images": [] + }, + "GoldenDict.GoldenDict": { + "icon": "", + "images": [] + }, + "GoldWave.GoldWave": { + "icon": "", + "images": [] + }, + "GoldWave.VideoMeld": { + "icon": "", + "images": [] + }, + "GOMLab.GOMPlayer": { + "icon": "", + "images": [] + }, + "Google.AndroidStudio": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/e/e3/Android_Studio_Icon_%282014-2019%29.svg/1200px-Android_Studio_Icon_%282014-2019%29.svg.png", + "images": [ + "https://www.aceinfoway.com/blog/wp-content/uploads/2020/12/android-studio_plugins.jpg", + "https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiC2X0sIY_AGvgi6jD8Eh_u8rOdZXKA6PP18tnJdA6jQxR-n4bF6vsIVI2D4FTOnHAlqSY5hJShEjHcRQr7P8QM-YyP3sM3Su_KxFRdBXhg8WUIoXr74luWfFvtgYGJHWdDe_gPnwpCsLR4YhE0U88QcSqrYs3LLjp7dGqQul_pRoerJr__-mD8lUPA/s1600/Android-IO22AndroidDevRecap_Social.png", + "https://1.bp.blogspot.com/-b1_n6tOHvWU/YKMssWEjo-I/AAAAAAAAQjk/vIJQsAPUpRQKxR44GoCbm3CtRgr8tVBKACLcBGAsYHQ/s0/Android_NewForDevelopers_1024x512_updated.png", + "https://pbs.twimg.com/media/EeL1D6cWkAEWgTC.png", + "https://developer.android.com/static/studio/images/releases/compose-multipreview-annotations.png", + "https://developer.android.com/static/studio/images/studio-homepage-hero.jpg", + "https://i.ytimg.com/vi/kMI2jy-WlGM/maxresdefault.jpg" + ] + }, + "Google.AndroidStudio.Beta": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/e/e3/Android_Studio_Icon_%282014-2019%29.svg/1200px-Android_Studio_Icon_%282014-2019%29.svg.png", + "images": [ + "https://www.aceinfoway.com/blog/wp-content/uploads/2020/12/android-studio_plugins.jpg", + "https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiC2X0sIY_AGvgi6jD8Eh_u8rOdZXKA6PP18tnJdA6jQxR-n4bF6vsIVI2D4FTOnHAlqSY5hJShEjHcRQr7P8QM-YyP3sM3Su_KxFRdBXhg8WUIoXr74luWfFvtgYGJHWdDe_gPnwpCsLR4YhE0U88QcSqrYs3LLjp7dGqQul_pRoerJr__-mD8lUPA/s1600/Android-IO22AndroidDevRecap_Social.png", + "https://1.bp.blogspot.com/-b1_n6tOHvWU/YKMssWEjo-I/AAAAAAAAQjk/vIJQsAPUpRQKxR44GoCbm3CtRgr8tVBKACLcBGAsYHQ/s0/Android_NewForDevelopers_1024x512_updated.png", + "https://pbs.twimg.com/media/EeL1D6cWkAEWgTC.png", + "https://developer.android.com/static/studio/images/releases/compose-multipreview-annotations.png", + "https://developer.android.com/static/studio/images/studio-homepage-hero.jpg", + "https://i.ytimg.com/vi/kMI2jy-WlGM/maxresdefault.jpg" + ] + }, + "Google.AndroidStudio.Canary": { + "icon": "http://i.imgur.com/GAcvIsP.png", + "images": [ + "https://i.imgur.com/YjOIZFc.jpg", + "https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiC2X0sIY_AGvgi6jD8Eh_u8rOdZXKA6PP18tnJdA6jQxR-n4bF6vsIVI2D4FTOnHAlqSY5hJShEjHcRQr7P8QM-YyP3sM3Su_KxFRdBXhg8WUIoXr74luWfFvtgYGJHWdDe_gPnwpCsLR4YhE0U88QcSqrYs3LLjp7dGqQul_pRoerJr__-mD8lUPA/s1600/Android-IO22AndroidDevRecap_Social.png", + "https://1.bp.blogspot.com/-b1_n6tOHvWU/YKMssWEjo-I/AAAAAAAAQjk/vIJQsAPUpRQKxR44GoCbm3CtRgr8tVBKACLcBGAsYHQ/s0/Android_NewForDevelopers_1024x512_updated.png", + "https://pbs.twimg.com/media/EeL1D6cWkAEWgTC.png", + "https://developer.android.com/static/studio/images/releases/compose-multipreview-annotations.png", + "https://developer.android.com/static/studio/images/studio-homepage-hero.jpg", + "https://i.ytimg.com/vi/kMI2jy-WlGM/maxresdefault.jpg" + ] + }, + "Google.BackupAndSync": { + "icon": "https://i.imgur.com/OAW2RMk.png", + "images": [ + "https://1.bp.blogspot.com/-kyT1WzImsDQ/YOxgOPE941I/AAAAAAAAKBw/kjvRhMgsdj4_lrhzmreFQBbABELLlv4-wCLcBGAsYHQ/s1375/drive%2Bfor%2Bdesktop.png", + "https://i.imgur.com/djKiC3T.jpg", + "https://i.imgur.com/bgvMCpb.png" + ] + }, + "Google.Chrome": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/e/e1/Google_Chrome_icon_%28February_2022%29.svg/2048px-Google_Chrome_icon_%28February_2022%29.svg.png", + "images": [ + "https://upload.wikimedia.org/wikipedia/commons/thumb/8/87/Google_Chrome_75_screenshot.png/800px-Google_Chrome_75_screenshot.png" + ] + }, + "Google.Chrome.Beta": { + "icon": "https://image.winudf.com/v2/image1/Y29tLmNocm9tZS5kZXZfaWNvbl8xNTYzNDkxNzUyXzA3Ng/icon.png?w=&fakeurl=1", + "images": [ + "https://upload.wikimedia.org/wikipedia/commons/thumb/8/87/Google_Chrome_75_screenshot.png/800px-Google_Chrome_75_screenshot.png" + ] + }, + "Google.Chrome.Canary": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/c/c6/Chrome-canary-logo.svg/512px-Chrome-canary-logo.svg.png", + "images": [ + "https://upload.wikimedia.org/wikipedia/commons/thumb/8/87/Google_Chrome_75_screenshot.png/800px-Google_Chrome_75_screenshot.png" + ] + }, + "Google.Chrome.Dev": { + "icon": "", + "images": [ + "https://upload.wikimedia.org/wikipedia/commons/thumb/8/87/Google_Chrome_75_screenshot.png/800px-Google_Chrome_75_screenshot.png" + ] + }, + "Google.ChromeRemoteDesktop": { + "icon": "https://play-lh.googleusercontent.com/I4DRWoABrUQsaAIQFVSKha98q1u2ilEdrwPJBaf9Mb8KdGZnXzs5DObrwcwUZovgOA", + "images": [] + }, + "Google.CloudSDK": { + "icon": "", + "images": [] + }, + "Google.Drive": { + "icon": "https://i.imgur.com/LowtJVt.png", + "images": [] + }, + "Google.EarthPro": { + "icon": "", + "images": [] + }, + "Google.FirebaseCLI": { + "icon": "", + "images": [] + }, + "Google.IAPDesktop": { + "icon": "", + "images": [] + }, + "Google.JapaneseIME": { + "icon": "", + "images": [] + }, + "Google.WebDesigner": { + "icon": "", + "images": [] + }, + "GorillaDevs.GDLauncher": { + "icon": "", + "images": [] + }, + "GottCode.FocusWriter": { + "icon": "", + "images": [] + }, + "Governikus.AusweisApp2": { + "icon": "https://i.imgur.com/nPb3wTl.png", + "images": [ + "https://res.cloudinary.com/canonical/image/fetch/f_auto,q_auto,fl_sanitize,w_819,h_549/https://dashboard.snapcraft.io/site_media/appmedia/2019/01/ausweisapp2.png", + "https://www.ausweisapp.bund.de/fileadmin/user_upload/Bilder/Mock-ups/startseite-smartphone-und-desktop-englisch.jpg", + "https://www.ausweisapp.bund.de/fileadmin/user_upload/Bilder/Mock-ups/startseite-smartphone-und-desktop-englisch.jpg" + ] + }, + "GPBeta.SAOUtils.Exp": { + "icon": "", + "images": [] + }, + "gpodder.gpodder": { + "icon": "", + "images": [] + }, + "GPSoftware.DirectoryOpus": { + "icon": "", + "images": [] + }, + "Graebert.AresCommander.2022": { + "icon": "https://cad.com.au/wp-content/uploads/2020/11/ares-logo-red.png", + "images": [ + "https://www.graebert.com/wp-content/uploads/2021/02/ARES-Commander-2020-tower-transparent-with-logo-1.jpg", + "https://www.graebert.com/wp-content/uploads/2021/08/ARES_Kudo2.jpg", + "https://windows-cdn.softpedia.com/screenshots/ARES-Commander-Edition_3.png", + "https://www.graebert.com/wp-content/uploads/2022/03/sheet_list_2023_2.jpg" + ] + }, + "Graebert.AresCommander.2023": { + "icon": "https://cad.com.au/wp-content/uploads/2020/11/ares-logo-red.png", + "images": [ + "https://www.graebert.com/wp-content/uploads/2021/02/ARES-Commander-2020-tower-transparent-with-logo-1.jpg", + "https://www.graebert.com/wp-content/uploads/2021/08/ARES_Kudo2.jpg", + "https://windows-cdn.softpedia.com/screenshots/ARES-Commander-Edition_3.png", + "https://www.graebert.com/wp-content/uploads/2022/03/sheet_list_2023_2.jpg" + ] + }, + "Graebert.AresMap.2022": { + "icon": "https://www.graebert.com/wp-content/uploads/2022/03/New_Prod_ARES_Map_256x256_183w_2x.png", + "images": [ + "https://www.graebert.com/wp-content/uploads/2018/04/01_map.jpg", + "https://www.graebert.com/wp-content/uploads/2018/04/02_map.jpg", + "https://www.graebert.com/wp-content/uploads/2017/11/aresmap_screen-1_2017.png" + ] + }, + "Graebert.AresMap.2023": { + "icon": "https://www.graebert.com/wp-content/uploads/2022/03/New_Prod_ARES_Map_256x256_183w_2x.png", + "images": [ + "https://www.graebert.com/wp-content/uploads/2018/04/01_map.jpg", + "https://www.graebert.com/wp-content/uploads/2018/04/02_map.jpg", + "https://www.graebert.com/wp-content/uploads/2017/11/aresmap_screen-1_2017.png" + ] + }, + "Graebert.AresMechanical.2022": { + "icon": "https://www.graebert.com/wp-content/uploads/2022/03/New_Prod_ARES_Mechanical_256x256_183w_2x.png", + "images": [ + "https://img.youtube.com/vi/yk15tlH2YoQ/0.jpg", + "https://www.graebert.com/wp-content/uploads/2022/02/ARES-Mechanical-woman-work-on-mechanical-piece_cut_kl.jpg", + "https://www.graebert.com/wp-content/uploads/2018/06/02_ares_mech_n.jpg", + "https://www.graebert.com/wp-content/uploads/2017/11/aresmech_screen-1_2017.png" + ] + }, + "Graebert.AresMechanical.2023": { + "icon": "https://www.graebert.com/wp-content/uploads/2022/03/New_Prod_ARES_Mechanical_256x256_183w_2x.png", + "images": [ + "https://img.youtube.com/vi/yk15tlH2YoQ/0.jpg", + "https://www.graebert.com/wp-content/uploads/2022/02/ARES-Mechanical-woman-work-on-mechanical-piece_cut_kl.jpg", + "https://www.graebert.com/wp-content/uploads/2018/06/02_ares_mech_n.jpg", + "https://www.graebert.com/wp-content/uploads/2017/11/aresmech_screen-1_2017.png" + ] + }, + "GrafanaLabs.Grafana.Enterprise": { + "icon": "", + "images": [] + }, + "GrafanaLabs.Grafana.OSS": { + "icon": "", + "images": [] + }, + "Grammarly.Grammarly": { + "icon": "", + "images": [] + }, + "Grammarly.Grammarly.Office": { + "icon": "", + "images": [] + }, + "Gramps.Gramps": { + "icon": "", + "images": [] + }, + "Graphcool.GraphQLPlayground": { + "icon": "", + "images": [] + }, + "Graphviz.Graphviz": { + "icon": "", + "images": [] + }, + "GreenfootTeam.Greenfoot": { + "icon": "", + "images": [] + }, + "Greenshot.Greenshot": { + "icon": "", + "images": [] + }, + "Gridcoin.Client": { + "icon": "", + "images": [] + }, + "GruberQuentin.stay-hydrated": { + "icon": "", + "images": [] + }, + "gsass1.NTop": { + "icon": "", + "images": [] + }, + "GSmartControl.GSmartControl": { + "icon": "", + "images": [] + }, + "gstreamerproject.gstreamer": { + "icon": "", + "images": [] + }, + "gtamas.etcdmanager": { + "icon": "", + "images": [] + }, + "guideguide.ZXPInstaller": { + "icon": "", + "images": [] + }, + "Guilded.Guilded": { + "icon": "", + "images": [] + }, + "GuinpinSoft.MakeMKV": { + "icon": "", + "images": [] + }, + "gumengyu.vplayer-next": { + "icon": "", + "images": [] + }, + "gurayyarar.SnipCommand": { + "icon": "", + "images": [] + }, + "gurnec.HashCheckShellExtension": { + "icon": "", + "images": [] + }, + "GyDi.ClashVerge": { + "icon": "", + "images": [] + }, + "H2IK.JoystickGremlin": { + "icon": "", + "images": [] + }, + "h3poteto.whalebird-desktop": { + "icon": "", + "images": [] + }, + "HagelTechnologiesLtd.DUMeter": { + "icon": "", + "images": [] + }, + "HakuNeko.HakuNeko": { + "icon": "", + "images": [] + }, + "HakuNeko.HakuNeko.Nightly": { + "icon": "", + "images": [] + }, + "HamsterBase.HamsterBase": { + "icon": "", + "images": [] + }, + "HamsterRepublic.BobTheHamsterVGA": { + "icon": "", + "images": [] + }, + "HamsterRepublic.OHRRPGCE": { + "icon": "", + "images": [] + }, + "HandBrake.HandBrake": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/d/d9/HandBrake_Icon.png", + "images": [ + "https://handbrake.fr/img/slides/slide1_win.jpg", + "https://handbrake.fr/img/slides/slide2_win.jpg", + "https://handbrake.fr/img/slides/slide3_win.jpg" + ] + }, + "HandyOrg.HandyWinget-GUI": { + "icon": "", + "images": [] + }, + "Harmonoid.Harmonoid": { + "icon": "", + "images": [] + }, + "HarshKhandeparkar.RainbowBoard": { + "icon": "", + "images": [] + }, + "Hashicorp.Vagrant": { + "icon": "", + "images": [] + }, + "HaxeFoundation.Haxe": { + "icon": "", + "images": [] + }, + "HDDGURU.HDDLLFTool": { + "icon": "", + "images": [] + }, + "HDDGURU.HDDRawCopyTool": { + "icon": "", + "images": [] + }, + "HDOS.HDOSLauncher": { + "icon": "", + "images": [] + }, + "Headsetapp.Headset": { + "icon": "", + "images": [] + }, + "HearthSim.HearthstoneDeckTracker": { + "icon": "", + "images": [] + }, + "Heaventools.FlexHex": { + "icon": "", + "images": [] + }, + "Heaventools.PEexplorer": { + "icon": "", + "images": [] + }, + "Heaventools.ResourceTuner": { + "icon": "", + "images": [] + }, + "Heaventools.ResourceTunerConsole": { + "icon": "", + "images": [] + }, + "Hedgewars.Hedgewars": { + "icon": "", + "images": [] + }, + "HeidiSQL.HeidiSQL": { + "icon": "", + "images": [] + }, + "Hekasoft.Backup-Restore": { + "icon": "", + "images": [] + }, + "Helio.HelioWorkstation": { + "icon": "", + "images": [] + }, + "hello-efficiency-inc.raven-reader": { + "icon": "", + "images": [] + }, + "Hellofont.Hellofont": { + "icon": "", + "images": [] + }, + "HelmutBuhler.8GadgetPack": { + "icon": "https://cdn.lo4d.com/t/icon/128/8gadgetpack.png", + "images": [ + "https://8gadgetpack.net/Screen8GP.jpg", + "https://8gadgetpack.net/tut/tut1.jpg", + "https://8gadgetpack.net/tut/tut4.jpg", + "https://8gadgetpack.net/tut/tut6.jpg", + "https://8gadgetpack.net/tut/tut18.jpg", + "https://8gadgetpack.net/tut/tut20.jpg" + ] + }, + "HenriWahl.Nagstamon": { + "icon": "", + "images": [] + }, + "Henry++.ErrorLookup": { + "icon": "", + "images": [] + }, + "Henry++.freeshooter": { + "icon": "", + "images": [] + }, + "Henry++.MemReduct": { + "icon": "", + "images": [] + }, + "Henry++.simplewall": { + "icon": "", + "images": [] + }, + "HERE.OLPCLI": { + "icon": "", + "images": [] + }, + "HermannSchinagl.LinkShellExtension": { + "icon": "", + "images": [] + }, + "HeroicGamesLauncher.HeroicGamesLau\u2026": { + "icon": "", + "images": [] + }, + "Heroku.HerokuCLI": { + "icon": "", + "images": [] + }, + "herrlichmedia.Agantty": { + "icon": "https://pbs.twimg.com/profile_images/606166025663574016/7nwzHu5w_400x400.png", + "images": [ + "https://upload.wikimedia.org/wikipedia/commons/thumb/0/05/Gantt-chart-agantty.jpg/640px-Gantt-chart-agantty.jpg", + "https://img.youtube.com/vi/x7eLMIf0UyU/sddefault.jpg", + "https://www.agantty.com/wp-content/themes/planbar-wp/images/agantty-project-management-ganttchart.jpg", + "https://www.agantty.com/wp-content/themes/planbar-wp/images/agantty-project-management-dashboard.jpg", + "https://static.filehorse.com/screenshots/office-and-business-tools/agantty-screenshot-01.png", + "https://windows-cdn.softpedia.com/screenshots/Agantty_6.png" + ] + }, + "Hex-Rays.IDA.Free": { + "icon": "", + "images": [] + }, + "Hexandcube.DesktopIconToggle": { + "icon": "", + "images": [] + }, + "HexChat.HexChat": { + "icon": "", + "images": [] + }, + "HHDSoftware.FreeHexEditorNeo": { + "icon": "", + "images": [] + }, + "HHDSoftwareLtd.VirtualSerialPortTo\u2026": { + "icon": "", + "images": [] + }, + "Hibbiki.Chromium": { + "icon": "", + "images": [] + }, + "HiBitSoftware.HiBitUninstaller": { + "icon": "", + "images": [] + }, + "HiBitSoftware.StartUpManager": { + "icon": "", + "images": [] + }, + "HighPerformanceCoders.SciDAVis": { + "icon": "", + "images": [] + }, + "Highresolution.X-MouseButtonControl": { + "icon": "", + "images": [] + }, + "HiroshiFuu.onecopy": { + "icon": "", + "images": [] + }, + "HiroSystems.Clarinet": { + "icon": "", + "images": [] + }, + "Hirschmann.NotebookFanControl": { + "icon": "", + "images": [] + }, + "hisschemoller.music-pattern-genera\u2026": { + "icon": "", + "images": [] + }, + "Hitencent.JisuPDF": { + "icon": "", + "images": [] + }, + "Hitencent.JisuPDFEditor": { + "icon": "", + "images": [] + }, + "Hitencent.JisuPDFToWord": { + "icon": "", + "images": [] + }, + "Hitencent.JisuTodo": { + "icon": "", + "images": [] + }, + "hluk.CopyQ": { + "icon": "", + "images": [] + }, + "HMSoft.HMNISEdit": { + "icon": "", + "images": [] + }, + "HomeBank.HomeBank": { + "icon": "", + "images": [] + }, + "HottaStudio.TowerofFantasy": { + "icon": "", + "images": [] + }, + "HP.HPCloudRecoveryTool": { + "icon": "", + "images": [] + }, + "HP.HPCMSL": { + "icon": "", + "images": [] + }, + "HP.PrimeVirtualCalculator": { + "icon": "", + "images": [] + }, + "hql287.manta": { + "icon": "", + "images": [] + }, + "HR.Crypter": { + "icon": "", + "images": [] + }, + "https://www.ocenaudio.com/imgs/sc6058.win.en.png": { + "icon": "https://www.ocenaudio.com/imgs/ocenaudio164.png", + "images": [ + "https://www.ocenaudio.com/imgs/sc6058.win.en.png" + ] + }, + "HTTPToolKit.HTTPToolKit": { + "icon": "", + "images": [] + }, + "Huawei.appgallery": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/f/f6/Huawei_AppGallery.svg/2048px-Huawei_AppGallery.svg.png", + "images": [ + "https://www.huaweicentral.com/wp-content/uploads/2020/02/appgallery-ftrd-img-2.jpg", + "https://drscmedia.eu/wp-content/uploads/2019/10/HwAppGalleryBanner-678x381.jpg", + "https://www.huaweinewos.com/wp-content/uploads/2020/12/AppGallery-Market-PC-version-download-01-600x301.jpg", + "https://www.huaweinewos.com/wp-content/uploads/2020/12/AppGallery-Application-Market-PC-006-600x362.jpg", + "https://www.huaweinewos.com/wp-content/uploads/2020/12/AppGallery-Application-Market-PC-003-600x277.jpg" + ] + }, + "Huawei.HiSuite": { + "icon": "", + "images": [] + }, + "Huawei.HuaweiBrowser": { + "icon": "", + "images": [] + }, + "Huawei.HuaweiCloudMeeting": { + "icon": "", + "images": [] + }, + "Huawei.IdeaShare": { + "icon": "", + "images": [] + }, + "Huawei.IdeaShareProject": { + "icon": "", + "images": [] + }, + "Huawei.mobilecloud": { + "icon": "", + "images": [] + }, + "Huawei.QuickAppIde": { + "icon": "", + "images": [] + }, + "Huawei.QuickAppPCAssistant": { + "icon": "", + "images": [] + }, + "Huawei.Welink": { + "icon": "", + "images": [] + }, + "Hugin.Hugin": { + "icon": "", + "images": [] + }, + "HulubuluSoftware.AdvancedRenamer": { + "icon": "https://i.imgur.com/glf2Hgy.jpg", + "images": [ + "https://www.advancedrenamer.com/pic/screen_aren_3_87_002.png", + "https://static.filehorse.com/screenshots/file-transfer-and-networking/advanced-renamer-screenshot-01.png", + "https://www.portablefreeware.com/screenshots/scrUiOEc2.png", + "https://www.thewindowsclub.com/wp-content/uploads/2013/04/advanced-renamer-2.png" + ] + }, + "Humanity.DJV2": { + "icon": "", + "images": [] + }, + "HumbleBundle.HumbleApp": { + "icon": "", + "images": [] + }, + "HybridSaaS.HybridSaaS": { + "icon": "", + "images": [] + }, + "HydrologicEngineeringCenter.HEC-DS\u2026": { + "icon": "", + "images": [] + }, + "HydrologicEngineeringCenter.HEC-EF\u2026": { + "icon": "", + "images": [] + }, + "HydrologicEngineeringCenter.HEC-EFM": { + "icon": "", + "images": [] + }, + "HydrologicEngineeringCenter.HEC-FDA": { + "icon": "", + "images": [] + }, + "HydrologicEngineeringCenter.HEC-HMS": { + "icon": "", + "images": [] + }, + "HydrologicEngineeringCenter.HEC-Me\u2026": { + "icon": "", + "images": [] + }, + "HydrologicEngineeringCenter.HEC-RAS": { + "icon": "", + "images": [] + }, + "HydrologicEngineeringCenter.HEC-Re\u2026": { + "icon": "", + "images": [] + }, + "HydrologicEngineeringCenter.HEC-RPT": { + "icon": "", + "images": [] + }, + "HydrologicEngineeringCenter.HEC-SSP": { + "icon": "", + "images": [] + }, + "HydrusNetwork.HydrusNetwork": { + "icon": "", + "images": [ + "https://raw.githubusercontent.com/hydrusnetwork/hydrus/master/static/hydrus.png", + "https://hydrusnetwork.github.io/hydrus/images/screenshot_empty.png", + "https://hydrusnetwork.github.io/hydrus/images/screenshot_thread_watcher.png" + ] + }, + "Hypermodules.Hyperamp": { + "icon": "", + "images": [] + }, + "HyperspaceDev.HyperspaceDesktop": { + "icon": "", + "images": [] + }, + "I-GIS.GeoScene3D": { + "icon": "", + "images": [] + }, + "iA.Writer": { + "icon": "", + "images": [] + }, + "iamscottxu.obs-rtspserver": { + "icon": "", + "images": [] + }, + "IanWalton.JellyfinMPVShim": { + "icon": "", + "images": [] + }, + "IBESoftware.HelpNDoc": { + "icon": "", + "images": [] + }, + "IBM.SemeruRuntimeOpenEdition.JDK": { + "icon": "", + "images": [] + }, + "IBM.SemeruRuntimeOpenEdition.JRE": { + "icon": "", + "images": [] + }, + "ICBC.ICBCChromeExtension": { + "icon": "", + "images": [] + }, + "ICBC.ICBCEBankAssist": { + "icon": "", + "images": [] + }, + "IceChat.IceChat": { + "icon": "", + "images": [] + }, + "IcecreamApps.PDFCandy": { + "icon": "", + "images": [] + }, + "Icons8.Lunacy": { + "icon": "", + "images": [] + }, + "Iconscout.Iconscout": { + "icon": "", + "images": [] + }, + "icsharpcode.ILSpy": { + "icon": "", + "images": [] + }, + "IDRIX.VeraCrypt": { + "icon": "", + "images": [] + }, + "ifedapoolarewaju.IGdm": { + "icon": "", + "images": [] + }, + "iFlytek.iFlyIME": { + "icon": "", + "images": [] + }, + "Igoravl.TfsCmdlets": { + "icon": "", + "images": [] + }, + "IHMC.CmapTools": { + "icon": "", + "images": [] + }, + "IJHack.QtPass": { + "icon": "", + "images": [] + }, + "IliasHad.makerlapse": { + "icon": "", + "images": [] + }, + "ilime.petal": { + "icon": "", + "images": [] + }, + "iLovePDF.iLovePDFDesktop": { + "icon": "", + "images": [] + }, + "ImageLine.FLStudio": { + "icon": "", + "images": [] + }, + "ImageMagick.ImageMagick": { + "icon": "", + "images": [] + }, + "Iminetsoft.DarkSwitcher": { + "icon": "", + "images": [] + }, + "IndigoByte.DrExplain": { + "icon": "", + "images": [] + }, + "InfiniteInstant.KoduGameLab": { + "icon": "", + "images": [] + }, + "infinitepower18.WSASideloader": { + "icon": "", + "images": [] + }, + "InfiniteRed.Reactotron": { + "icon": "", + "images": [] + }, + "InfiniteRed.Reactotron.Pre-release": { + "icon": "", + "images": [] + }, + "IngoRuhnke.Pingus": { + "icon": "", + "images": [] + }, + "Initex.Proxifier": { + "icon": "", + "images": [] + }, + "Initex.YogaDNS": { + "icon": "", + "images": [] + }, + "IniTranslator.IniTranslator": { + "icon": "", + "images": [] + }, + "Inkscape.Inkscape": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/0/0d/Inkscape_Logo.svg/240px-Inkscape_Logo.svg.png", + "images": [ + "https://upload.wikimedia.org/wikipedia/commons/e/e5/Inkscape_1.2_screenshot.png", + "https://media.inkscape.org/media/resources/render/Screenshot_Freedom_Machine_Inkscape_master_spEBt2Y.png" + ] + }, + "inPixio.inPixioPhotoStudio": { + "icon": "", + "images": [] + }, + "Insecure.Nmap": { + "icon": "", + "images": [] + }, + "Insomnia.Insomnia": { + "icon": "", + "images": [] + }, + "InstantHousecall.InstantHousecall": { + "icon": "", + "images": [] + }, + "Instatus.Out": { + "icon": "", + "images": [] + }, + "InstEd.InstEd": { + "icon": "", + "images": [] + }, + "Insynchq.Insync": { + "icon": "", + "images": [] + }, + "Intel.IntelDriverAndSupportAssista\u2026": { + "icon": "", + "images": [] + }, + "Intel.Iometer": { + "icon": "", + "images": [] + }, + "Intel.ProcessorDiagnosticTool": { + "icon": "", + "images": [] + }, + "Internxt.Drive": { + "icon": "", + "images": [] + }, + "InTheLoop.LoopEmail": { + "icon": "", + "images": [] + }, + "InTheLoop.LoopEmail.Beta": { + "icon": "", + "images": [] + }, + "intxcc.pyaudio": { + "icon": "", + "images": [] + }, + "Invizi.Invizi": { + "icon": "", + "images": [] + }, + "IObit.AdvancedSystemCare": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/8/89/Advanced_SystemCare_9_logo.png", + "images": [ + "https://i0.wp.com/cracktube.net/wp-content/uploads/2018/08/Advanced-SystemCare-Key-Crack-Free-Download-Updated.png", + "https://i1.wp.com/filecr.com/wp-content/uploads/2020/09/advanced-systemcare-ultimate-free-download.jpg", + "https://www.iobit.com/tpl/images/products/ascfreew/ai_pc.png", + "https://www.iobit.com/tpl/images/products/ascfreew/sp_pc.png", + "https://www.iobit.com/tpl/images/products/ascfreew/pr_pc.png", + "https://www.iobit.com/tpl/images/products/ascfreew/bs_pc.png", + "https://thesweetbits.com/wp-content/uploads/2021/10/advanced-systemcare-pro-15.jpg", + "https://img.creativemark.co.uk/uploads/images/816/15816/img3File.png", + "https://2.bp.blogspot.com/-fGHCoVsY_tQ/XeVEQ2X-quI/AAAAAAAAUm8/bsyDwm4jAooPp2yg84NHU5xvVVj7lfGAgCLcBGAsYHQ/s1600/Advanced%2BSystemCare%2B13%2BPRO%2BFull%2Bversion%2B%2Bspeed%2Bup.png", + "https://www.iobit.com/product-manuals/asc-help/images/mainfeatures/browser-protection.jpg" + ] + }, + "IObit.DriverBooster": { + "icon": "", + "images": [] + }, + "IObit.iFunScreenRecorder": { + "icon": "", + "images": [] + }, + "IObit.iFunScreenshot": { + "icon": "", + "images": [] + }, + "IObit.IObitSysInfo": { + "icon": "", + "images": [] + }, + "IObit.MalwareFighter": { + "icon": "", + "images": [] + }, + "IObit.ProtectedFolder": { + "icon": "", + "images": [] + }, + "IObit.Uninstaller": { + "icon": "", + "images": [] + }, + "iOSGods.Sideloadly": { + "icon": "", + "images": [] + }, + "IPFS.IPFS-Desktop": { + "icon": "", + "images": [] + }, + "IPIP.BestTrace": { + "icon": "", + "images": [] + }, + "iQIYI.iQIYI": { + "icon": "", + "images": [] + }, + "IRCCloud.IRCCloud": { + "icon": "", + "images": [] + }, + "IrfanSkiljan.IrfanView": { + "icon": "", + "images": [] + }, + "Iriun.IriunVR": { + "icon": "", + "images": [] + }, + "Iriun.IriunWebcam": { + "icon": "", + "images": [] + }, + "IronmanSoftware.PowerShellUniversa\u2026": { + "icon": "", + "images": [] + }, + "IronmanSoftware.PowerShellUniversal": { + "icon": "", + "images": [] + }, + "isaaclevin.presencelight": { + "icon": "", + "images": [] + }, + "IsaqueS.AventurasDeQuintal": { + "icon": "", + "images": [] + }, + "iSlide.iSlide": { + "icon": "", + "images": [] + }, + "isnetwork.ISNAutoItStudio": { + "icon": "", + "images": [] + }, + "IsWiX.IsWiX": { + "icon": "", + "images": [] + }, + "ItchIo.Itch": { + "icon": "", + "images": [] + }, + "ITDevTeam.UUPMediaCreator": { + "icon": "", + "images": [] + }, + "Iterate.Cyberduck": { + "icon": "", + "images": [] + }, + "Iterate.MountainDuck": { + "icon": "", + "images": [] + }, + "iTop.iTopDataRecovery": { + "icon": "", + "images": [] + }, + "iTop.iTopScreenRecorder": { + "icon": "", + "images": [] + }, + "ITRI.QuickSECS": { + "icon": "", + "images": [] + }, + "IvanG.BrowserTamer": { + "icon": "", + "images": [] + }, + "IvoSoft.ClassicShell": { + "icon": "", + "images": [ + "https://i.postimg.cc/mZCMz7yz/startmenu3.png" + ] + }, + "IVPN.IVPN": { + "icon": "", + "images": [] + }, + "IZArc.IZArc": { + "icon": "", + "images": [] + }, + "iZotope.ProductPortal": { + "icon": "", + "images": [] + }, + "Jabra.Direct": { + "icon": "", + "images": [] + }, + "JabRef.JabRef": { + "icon": "", + "images": [] + }, + "JackDevey.Lux": { + "icon": "", + "images": [] + }, + "Jackett.Jackett": { + "icon": "", + "images": [] + }, + "JackHumphries.Socially": { + "icon": "", + "images": [] + }, + "JackieLiu.NotepadsApp": { + "icon": "https://store-images.s-microsoft.com/image/apps.50935.13628411695448126.aaaa4dcd-6a65-403d-a558-9a51a7efcd04.f8723b56-2380-4980-91da-41d0bb46fa05", + "images": [ + "https://static.wixstatic.com/media/0fcd80_f13c96da960d491fa8862087ad614ce4~mv2.png/v1/fill/w_972,h_745,al_c,q_90,usm_0.66_1.00_0.01,enc_auto/1.png", + "https://static.wixstatic.com/media/0fcd80_282f2d7627c94d86b22f90c4e0b3448d~mv2.png/v1/fill/w_956,h_744,al_c,q_90,usm_0.66_1.00_0.01,enc_auto/2.png" + ] + }, + "Jacksta.Instigator": { + "icon": "", + "images": [] + }, + "Jagex.OldSchoolRunescape": { + "icon": "", + "images": [] + }, + "jamaljsr.Polar": { + "icon": "", + "images": [] + }, + "james.james": { + "icon": "", + "images": [] + }, + "jamesbowden.qws": { + "icon": "", + "images": [] + }, + "JamesLarus.SPIM": { + "icon": "", + "images": [] + }, + "JamieOConnell.MIDI-OX": { + "icon": "", + "images": [] + }, + "JamiePine.CacheMonkey": { + "icon": "", + "images": [] + }, + "jamoviStats.jamovi": { + "icon": "", + "images": [] + }, + "JAMSoftware.HeavyLoad": { + "icon": "", + "images": [] + }, + "JAMSoftware.TreeSize": { + "icon": "", + "images": [] + }, + "JAMSoftware.TreeSize.Free": { + "icon": "", + "images": [] + }, + "JAMSoftware.Ultrasearch": { + "icon": "", + "images": [] + }, + "JanDeDobbeleer.OhMyPosh": { + "icon": "https://i.postimg.cc/x1gnCQxg/icon.png\n", + "images": [ + "https://i.postimg.cc/PrstV2vb/1.png", + "https://i.postimg.cc/7ZqqwhVf/2.png", + "https://i.postimg.cc/tC39KWFK/3.png" + ] + }, + "JanFiala.PSpad": { + "icon": "https://upload.wikimedia.org/wikipedia/en/d/df/Pspad_256x256.png", + "images": [] + }, + "JanGrzegorowski.TimeSeriesAdmin": { + "icon": "", + "images": [] + }, + "JannisX11.Blockbench": { + "icon": "", + "images": [] + }, + "JanProchazka.dbgate": { + "icon": "", + "images": [] + }, + "Jaquadro.NBTExplorer": { + "icon": "", + "images": [] + }, + "JasnaPaka.MozBackup": { + "icon": "", + "images": [] + }, + "jasongin.nvs": { + "icon": "", + "images": [] + }, + "jasperapp.jasper": { + "icon": "", + "images": [] + }, + "JavadMotallebi.NeatDownloadManager": { + "icon": "", + "images": [] + }, + "jayakumarreddy.Local-Mock-Server": { + "icon": "", + "images": [] + }, + "JaydenDev.Catalyst": { + "icon": "", + "images": [] + }, + "JaydenDev.Catalyst3": { + "icon": "", + "images": [] + }, + "JayPrall.ColorCop": { + "icon": "", + "images": [] + }, + "jbreland.autoflac": { + "icon": "", + "images": [ + "https://www.legroom.net/files/software/autoflac_gui_thumb.png", + "https://www.legroom.net/files/software/autoflac_convert.png" + ] + }, + "jbreland.uniextract": { + "icon": "", + "images": [] + }, + "jcoon97.LAClient": { + "icon": "", + "images": [] + }, + "jcv8000.Codex": { + "icon": "", + "images": [] + }, + "JeffreyPfau.mGBA": { + "icon": "", + "images": [] + }, + "jeffvli.Sonixd": { + "icon": "", + "images": [] + }, + "Jellyfin.JellyfinMediaPlayer": { + "icon": "", + "images": [] + }, + "Jellyfin.Server": { + "icon": "", + "images": [] + }, + "Jelmerro.Vieb": { + "icon": "", + "images": [] + }, + "jely2002.youtube-dl-gui": { + "icon": "", + "images": [] + }, + "jenius-apps.ambie": { + "icon": "https://github.com/jenius-apps/ambie/raw/main/images/logo_transparent.png", + "images": [ + "https://raw.githubusercontent.com/jenius-apps/ambie/main/images/ambie_hero_v3.png", + "https://github.com/jenius-apps/ambie/raw/main/images/toolkit-translate.png" + ] + }, + "JenuelOrasGanawed.BelieversSword": { + "icon": "", + "images": [] + }, + "JernejSimoncic.Wget": { + "icon": "", + "images": [] + }, + "jerrod-lankford.google-voice-deskt\u2026": { + "icon": "", + "images": [] + }, + "Jeskola.Buzz": { + "icon": "", + "images": [] + }, + "JetBrains.CLion": { + "icon": "https://resources.jetbrains.com/storage/products/clion/img/meta/clion_logo_300x300.png", + "images": [] + }, + "JetBrains.CLion.EAP": { + "icon": "https://resources.jetbrains.com/storage/products/clion/img/meta/clion_logo_300x300.png", + "images": [] + }, + "JetBrains.DataGrip": { + "icon": "https://iconape.com/wp-content/png_logo_vector/dotpeek-logo.png", + "images": [] + }, + "JetBrains.DataGrip.EarlyAccess": { + "icon": "https://iconape.com/wp-content/png_logo_vector/dotpeek-logo.png", + "images": [] + }, + "JetBrains.DataSpell.EarlyPreview": { + "icon": "https://seeklogo.com/images/D/dataspell-logo-06435B9CF3-seeklogo.com.png", + "images": [] + }, + "JetBrains.dotUltimate": { + "icon": "https://computermalaysia.com.my/media/catalog/product/cache/1/thumbnail/500x500/9df78eab33525d08d6e5fb8d27136e95/d/o/dotultimate.png", + "images": [] + }, + "JetBrains.FleetLauncher.EAP": { + "icon": "https://www.jetbrains.com/_assets/www/fleet/inc/overview-content/img/fleet-logo.65f4a04c59fc3ba93bb5e181050891c5.png", + "images": [] + }, + "JetBrains.FleetLauncher.Preview": { + "icon": "https://www.jetbrains.com/_assets/www/fleet/inc/overview-content/img/fleet-logo.65f4a04c59fc3ba93bb5e181050891c5.png", + "images": [] + }, + "JetBrains.Gateway": { + "icon": "", + "images": [] + }, + "JetBrains.GoLand": { + "icon": "https://resources.jetbrains.com/storage/products/goland/img/meta/goland_logo_300x300.png", + "images": [] + }, + "JetBrains.GoLand.EarlyAccess": { + "icon": "https://resources.jetbrains.com/storage/products/goland/img/meta/goland_logo_300x300.png", + "images": [] + }, + "JetBrains.Hub": { + "icon": "https://resources.jetbrains.com/storage/products/hub/img/meta/hub_logo_300x300.png", + "images": [] + }, + "JetBrains.IntelliJIDEA.Community": { + "icon": "https://resources.jetbrains.com/storage/products/intellij-idea/img/meta/intellij-idea_logo_300x300.png", + "images": [] + }, + "JetBrains.IntelliJIDEA.Community.E\u2026": { + "icon": "https://resources.jetbrains.com/storage/products/intellij-idea/img/meta/intellij-idea_logo_300x300.png", + "images": [] + }, + "JetBrains.IntelliJIDEA.Edu": { + "icon": "https://resources.jetbrains.com/storage/products/intellij-idea/img/meta/intellij-idea_logo_300x300.png", + "images": [] + }, + "JetBrains.IntelliJIDEA.Ultimate": { + "icon": "https://resources.jetbrains.com/storage/products/intellij-idea/img/meta/intellij-idea_logo_300x300.png", + "images": [] + }, + "JetBrains.IntelliJIDEA.Ultimate.EAP": { + "icon": "https://resources.jetbrains.com/storage/products/intellij-idea/img/meta/intellij-idea_logo_300x300.png", + "images": [] + }, + "JetBrains.MPS": { + "icon": "", + "images": [] + }, + "JetBrains.MPS.EAP": { + "icon": "", + "images": [] + }, + "JetBrains.PHPStorm": { + "icon": "https://resources.jetbrains.com/storage/products/phpstorm/img/meta/phpstorm_logo_300x300.png", + "images": [] + }, + "JetBrains.PHPStorm.EarlyAccess": { + "icon": "https://resources.jetbrains.com/storage/products/phpstorm/img/meta/phpstorm_logo_300x300.png", + "images": [] + }, + "JetBrains.PyCharm.Community": { + "icon": "https://resources.jetbrains.com/storage/products/pycharm/img/meta/pycharm_logo_300x300.png", + "images": [ + "https://origin2.cdn.componentsource.com/sites/default/files/styles/image_large/public/images/product_description/jetbrains/pycharm/img_484761.png" + ] + }, + "JetBrains.PyCharm.Community.EAP": { + "icon": "https://resources.jetbrains.com/storage/products/pycharm/img/meta/pycharm_logo_300x300.png", + "images": [ + "https://origin2.cdn.componentsource.com/sites/default/files/styles/image_large/public/images/product_description/jetbrains/pycharm/img_484761.png" + ] + }, + "JetBrains.PyCharm.Professional": { + "icon": "https://resources.jetbrains.com/storage/products/pycharm/img/meta/pycharm_logo_300x300.png", + "images": [ + "https://origin2.cdn.componentsource.com/sites/default/files/styles/image_large/public/images/product_description/jetbrains/pycharm/img_484761.png" + ] + }, + "JetBrains.PyCharm.Professional.EAP": { + "icon": "https://resources.jetbrains.com/storage/products/pycharm/img/meta/pycharm_logo_300x300.png", + "images": [ + "https://origin2.cdn.componentsource.com/sites/default/files/styles/image_large/public/images/product_description/jetbrains/pycharm/img_484761.png" + ] + }, + "JetBrains.ReSharper": { + "icon": "https://resources.jetbrains.com/storage/products/resharper/img/meta/resharper_logo_300x300.png", + "images": [] + }, + "JetBrains.ReSharper.EarlyAccess": { + "icon": "https://resources.jetbrains.com/storage/products/resharper/img/meta/resharper_logo_300x300.png", + "images": [] + }, + "JetBrains.Rider": { + "icon": "https://resources.jetbrains.com/storage/products/rider/img/meta/rider_logo_300x300.png", + "images": [] + }, + "JetBrains.Rider.EAP": { + "icon": "https://resources.jetbrains.com/storage/products/rider/img/meta/rider_logo_300x300.png", + "images": [] + }, + "JetBrains.RubyMine": { + "icon": "https://resources.jetbrains.com/storage/products/rubymine/img/meta/rubymine_logo_300x300.png", + "images": [] + }, + "JetBrains.RubyMine.EarlyAccess": { + "icon": "https://resources.jetbrains.com/storage/products/rubymine/img/meta/rubymine_logo_300x300.png", + "images": [] + }, + "JetBrains.Space": { + "icon": "https://resources.jetbrains.com/storage/products/space/img/meta/logo.png", + "images": [] + }, + "JetBrains.TeamCity": { + "icon": "https://resources.jetbrains.com/storage/products/teamcity/img/meta/teamcity_logo_300x300.png", + "images": [] + }, + "JetBrains.Toolbox": { + "icon": "https://resources.jetbrains.com/storage/products/toolbox/img/meta/toolbox_logo_300x300.png", + "images": [] + }, + "JetBrains.WebStorm": { + "icon": "https://resources.jetbrains.com/storage/products/webstorm/img/meta/webstorm_logo_300x300.png", + "images": [] + }, + "JetBrains.WebStorm.EAP": { + "icon": "https://resources.jetbrains.com/storage/products/webstorm/img/meta/webstorm_logo_300x300.png", + "images": [] + }, + "JetBrains.YouTrack": { + "icon": "https://resources.jetbrains.com/storage/products/youtrack/img/meta/youtrack_logo_300x300.png", + "images": [] + }, + "JFLarvoire.Ag": { + "icon": "", + "images": [] + }, + "JFrog.Conan": { + "icon": "", + "images": [] + }, + "JGraph.Draw": { + "icon": "", + "images": [] + }, + "jhen0409.ReactNativeDebugger": { + "icon": "", + "images": [] + }, + "JIACHENG135.JCPlayer": { + "icon": "", + "images": [] + }, + "Jidifudi.GT4T": { + "icon": "", + "images": [] + }, + "jie17.electronic-gmail": { + "icon": "", + "images": [] + }, + "jie17.v2ray-electron": { + "icon": "", + "images": [] + }, + "Jigsaw.OutlineManager": { + "icon": "", + "images": [] + }, + "JimHan.Kanban-Desktop": { + "icon": "", + "images": [] + }, + "jingang.vocalsharp": { + "icon": "", + "images": [] + }, + "JinweiZhiguang.Lanhu.Photoshop": { + "icon": "", + "images": [] + }, + "JinweiZhiguang.MasterAgent": { + "icon": "", + "images": [] + }, + "JinweiZhiguang.MasterGo": { + "icon": "", + "images": [] + }, + "JiroShimizu.Jw_cad": { + "icon": "", + "images": [] + }, + "Jisco.LoT": { + "icon": "", + "images": [] + }, + "Jisco.VisualFamilyTree": { + "icon": "", + "images": [] + }, + "Jitsi.Meet": { + "icon": "", + "images": [] + }, + "JiveOff.roPresence": { + "icon": "", + "images": [] + }, + "JoachimEibl.KDiff3": { + "icon": "", + "images": [] + }, + "joe.joe": { + "icon": "", + "images": [] + }, + "JoeIpson.Jellyamp": { + "icon": "", + "images": [] + }, + "JohannesMillan.superProductivity": { + "icon": "", + "images": [] + }, + "JohnCantrell.Juggernaut": { + "icon": "", + "images": [] + }, + "JohnMacFarlane.Pandoc": { + "icon": "", + "images": [] + }, + "JohnTaylor.less": { + "icon": "", + "images": [] + }, + "JohnTaylor.lesskey": { + "icon": "", + "images": [] + }, + "JonasJohn.RemoveEmptyDirectories": { + "icon": "", + "images": [] + }, + "jonasmusall.texpaste": { + "icon": "", + "images": [] + }, + "joncampbell123.DOSBox-X": { + "icon": "", + "images": [] + }, + "jopemachine.Arvis": { + "icon": "", + "images": [ + "https://user-images.githubusercontent.com/18283033/131144965-97a5b380-afcd-46c4-8298-55ac6b75bcce.gif" + ] + }, + "Joplin.Joplin": { + "icon": "", + "images": [] + }, + "Joplin.Joplin.Pre-release": { + "icon": "", + "images": [] + }, + "JosephFinney.Text-Grab": { + "icon": "", + "images": [] + }, + "JRiver.MediaCenter": { + "icon": "", + "images": [] + }, + "JRSoftware.InnoSetup": { + "icon": "", + "images": [] + }, + "JSFoundation.Appium": { + "icon": "https://static-00.iconduck.com/assets.00/appium-icon-255x256-5yix6ocd.png", + "images": [ + "https://www.automationtestinghub.com/images/appium/appium-desktop-latest.png", + "https://user-images.githubusercontent.com/26970971/35574693-69fbf0ce-05d2-11e8-861f-c9bb37f2b75a.png", + "https://static1.smartbear.co/smartbearbrand/media/images/blog/blogimages/use-appium-desktop-3.png", + "https://www.einfochips.com/blog/wp-content/uploads/2018/02/004-appium-inspector.png", + "https://digital.ai/sites/default/files/pictures/experitest/2020/05/image12.png" + ] + }, + "jsimlo.tednotepad": { + "icon": "", + "images": [] + }, + "JTechMe.JumpGoBrowser.Legacy": { + "icon": "", + "images": [] + }, + "JTL.Wawi": { + "icon": "", + "images": [] + }, + "Julialang.Julia": { + "icon": "", + "images": [] + }, + "Julialang.Julia.LTS": { + "icon": "", + "images": [] + }, + "JulianAlarcon.ProspectMail": { + "icon": "", + "images": [] + }, + "JuneFabrics.PdaNet": { + "icon": "", + "images": [] + }, + "jurplel.qView": { + "icon": "", + "images": [] + }, + "just-install.just-install": { + "icon": "", + "images": [] + }, + "JustinMaximillianKimlim.Xplorer": { + "icon": "", + "images": [] + }, + "JustinPaulSilva.Superscript": { + "icon": "", + "images": [] + }, + "k6.k6": { + "icon": "", + "images": [] + }, + "Kafan.KafanInput": { + "icon": "", + "images": [] + }, + "KaiKramer.KeyStoreExplorer": { + "icon": "", + "images": [] + }, + "Kaitai.StructCompiler": { + "icon": "", + "images": [] + }, + "Kakao.KakaoTalk": { + "icon": "", + "images": [] + }, + "KakaoEnterprise.KakaoWork": { + "icon": "", + "images": [] + }, + "KakaoEntertainmentCorp.MelonPlayer": { + "icon": "", + "images": [] + }, + "kalilinux.kalilinux": { + "icon": "", + "images": [] + }, + "KamilSzymborski.WindowCenteringHel\u2026": { + "icon": "", + "images": [] + }, + "kamranahmedse.pennywise": { + "icon": "", + "images": [] + }, + "Kamua.TinyVid": { + "icon": "", + "images": [] + }, + "kapitainsky.RcloneBrowser": { + "icon": "", + "images": [] + }, + "karakun.OpenWebStart": { + "icon": "", + "images": [] + }, + "KarenWare.KarensReplicator": { + "icon": "", + "images": [] + }, + "KarimHossenbux.moonitor": { + "icon": "", + "images": [] + }, + "katahiromz.RisohEditor": { + "icon": "", + "images": [] + }, + "KatjaHoffmann.TViewer": { + "icon": "", + "images": [] + }, + "KCSoftwares.ApHeMo": { + "icon": "", + "images": [] + }, + "KCSoftwares.BATExpert": { + "icon": "", + "images": [] + }, + "KCSoftwares.dot11Expert": { + "icon": "", + "images": [] + }, + "KCSoftwares.DUMo": { + "icon": "", + "images": [] + }, + "KCSoftwares.HDDExpert": { + "icon": "", + "images": [] + }, + "KCSoftwares.IDPhotoStudio": { + "icon": "", + "images": [] + }, + "KCSoftwares.KCleaner": { + "icon": "", + "images": [] + }, + "KCSoftwares.MassCert": { + "icon": "", + "images": [] + }, + "KCSoftwares.PhotoToFilm": { + "icon": "", + "images": [] + }, + "KCSoftwares.PortExpert": { + "icon": "", + "images": [] + }, + "KCSoftwares.RAMExpert": { + "icon": "", + "images": [] + }, + "KCSoftwares.SUMo": { + "icon": "https://www.kcsoftwares.com/images/SUMo_icon.png", + "images": [ + "https://www.kcsoftwares.com/images/SUMo_screen.png" + ] + }, + "KCSoftwares.VideoInspector": { + "icon": "", + "images": [] + }, + "KDani-99.timetable": { + "icon": "", + "images": [] + }, + "KDE.Amarok": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/f/f4/Breezeicons-apps-48-amarok.svg/1200px-Breezeicons-apps-48-amarok.svg.png", + "images": [ + "https://cdn.kde.org/screenshots/amarok/amarok.png", + "http://amarok.kde.org/files/Amarok-2_0_0-Magnatune.png", + "https://userbase.kde.org/images.userbase/thumb/8/8b/Amarok_2.8_Beta.png/600px-Amarok_2.8_Beta.png" + ] + }, + "KDE.digikam": { + "icon": "", + "images": [] + }, + "KDE.Dolphin": { + "icon": "", + "images": [] + }, + "KDE.Falkon": { + "icon": "", + "images": [] + }, + "KDE.Kate": { + "icon": "", + "images": [ + "https://i.postimg.cc/sDCYwTg4/konsole.png" + ] + }, + "KDE.KDEConnect": { + "icon": "", + "images": [] + }, + "KDE.Kdenlive": { + "icon": "https://kdenlive.org/wp-content/uploads/2022/01/kdenlive-logo-blank-500px.png", + "images": [] + }, + "KDE.kdevelop": { + "icon": "", + "images": [] + }, + "KDE.KDiff3": { + "icon": "", + "images": [] + }, + "KDE.kexi": { + "icon": "", + "images": [] + }, + "KDE.kile": { + "icon": "", + "images": [] + }, + "KDE.kmymoney": { + "icon": "", + "images": [] + }, + "KDE.Krita": { + "icon": "https://i.imgur.com/ZIpIzyq.png", + "images": [] + }, + "KDE.KritaShellExtension": { + "icon": "", + "images": [] + }, + "KDE.kstars": { + "icon": "", + "images": [] + }, + "KDE.LabPlot": { + "icon": "", + "images": [] + }, + "KDE.Marble": { + "icon": "", + "images": [] + }, + "KDE.Okular": { + "icon": "", + "images": [ + "https://i.postimg.cc/XY7yzmSd/Okular-21-12-1-screenshot.png" + ] + }, + "KDE.Okular.Nightly": { + "icon": "", + "images": [] + }, + "KDE.rkward": { + "icon": "", + "images": [] + }, + "KDE.ruqola": { + "icon": "", + "images": [] + }, + "KDE.umbrello": { + "icon": "", + "images": [] + }, + "Kebler.Kebler": { + "icon": "", + "images": [] + }, + "Keboola.KeboolaCLI": { + "icon": "", + "images": [] + }, + "KeePassXCTeam.KeePassXC": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/c/c1/KeePassXC.svg/480px-KeePassXC.svg.png", + "images": [ + "https://upload.wikimedia.org/wikipedia/commons/1/1e/KeePassXC_main_men%C3%BA.png", + "https://keepassxc.org/images/screenshots/database_view.png", + "https://keepassxc.org/images/screenshots/edit_entry.png", + "https://keepassxc.org/images/screenshots/password_generator_advanced.png" + ] + }, + "Keeper.KeeperDesktop": { + "icon": "", + "images": [] + }, + "KeeWeb.KeeWeb": { + "icon": "", + "images": [] + }, + "Kensington.KensingtonWorks": { + "icon": "", + "images": [] + }, + "kerinlin.OrangePlayer": { + "icon": "", + "images": [] + }, + "Keybase.Keybase": { + "icon": "", + "images": [] + }, + "Keysight.PathWaveLicenseManager": { + "icon": "", + "images": [] + }, + "KhronosGroup.VulkanSDK": { + "icon": "", + "images": [] + }, + "KiCad.KiCad": { + "icon": "", + "images": [] + }, + "KiCad.KiCad.Lite": { + "icon": "", + "images": [] + }, + "kilian.fromscratch": { + "icon": "", + "images": [] + }, + "kimhwan.ScreenRecorder": { + "icon": "", + "images": [] + }, + "KimKnight.RemoteAppTool": { + "icon": "", + "images": [] + }, + "Kingsoft.KDocs": { + "icon": "", + "images": [] + }, + "Kingsoft.KingsoftPDF": { + "icon": "", + "images": [] + }, + "Kingsoft.TypeEasy": { + "icon": "", + "images": [] + }, + "Kingsoft.WPSOffice": { + "icon": "", + "images": [] + }, + "Kingsoft.WPSOffice.CN": { + "icon": "", + "images": [] + }, + "Kiraku.AudioJam": { + "icon": "https://i.imgur.com/twEVCV0.png", + "images": [ + "https://audiojam.cn/assets/audioJam1_en.b03649e6.png" + ] + }, + "KirillOsenkov.MSBuildStructuredLog\u2026": { + "icon": "", + "images": [] + }, + "KirraEnterprises.Presenter.Express": { + "icon": "", + "images": [] + }, + "KirraEnterprises.Presenter.Personal": { + "icon": "", + "images": [] + }, + "KirraEnterprises.Presenter.Premium": { + "icon": "", + "images": [] + }, + "KirraEnterprises.Presenter.Standard": { + "icon": "", + "images": [] + }, + "Kitware.CMake": { + "icon": "", + "images": [] + }, + "Kitware.ParaView": { + "icon": "", + "images": [] + }, + "Kiwix.KiwixJS": { + "icon": "", + "images": [] + }, + "Kiwix.KiwixJS.Electron": { + "icon": "", + "images": [] + }, + "Kiwix.WikiMed": { + "icon": "", + "images": [] + }, + "Kiwix.WikiMed.Electron": { + "icon": "", + "images": [] + }, + "Kiwix.Wikivoyage": { + "icon": "", + "images": [] + }, + "Kiwix.Wikivoyage.Electron": { + "icon": "", + "images": [] + }, + "klaussinani.ao": { + "icon": "https://github.com/klaussinani/ao/raw/master/docs/media/logo.png", + "images": [ + "https://github.com/klaussinani/ao/raw/master/docs/media/list-navigation.gif" + ] + }, + "klaussinani.tusk": { + "icon": "", + "images": [] + }, + "klinker24.google-calendar-desktop": { + "icon": "", + "images": [] + }, + "Klocman.BulkCrapUninstaller": { + "icon": "https://i.imgur.com/tVYTWHz.png", + "images": [ + "https://www.bcuninstaller.com/assets/1.png", + "https://www.bcuninstaller.com/assets/3.png", + "https://www.bcuninstaller.com/assets/4.png", + "https://www.bcuninstaller.com/assets/2.png" + ] + }, + "kmeleonbrowser.K-Meleon": { + "icon": "", + "images": [] + }, + "knoopx.feeder": { + "icon": "", + "images": [] + }, + "Kobo.Kobo": { + "icon": "", + "images": [] + }, + "KOGGames.Elsword": { + "icon": "", + "images": [] + }, + "KOOK.KOOK": { + "icon": "", + "images": [] + }, + "Kopia.KopiaUI": { + "icon": "", + "images": [] + }, + "KorigamiK.mangu": { + "icon": "", + "images": [] + }, + "Kotatogram.Kotatogram": { + "icon": "", + "images": [] + }, + "KoushikNaskar.InteractiveDataEditor": { + "icon": "", + "images": [] + }, + "KraXen72.crankshaft": { + "icon": "", + "images": [] + }, + "Krisp.Krisp": { + "icon": "", + "images": [] + }, + "KristenMcWilliam.Nyrna": { + "icon": "", + "images": [] + }, + "KRTirtho.Spotube": { + "icon": "", + "images": [] + }, + "ksnip.ksnip": { + "icon": "", + "images": [] + }, + "ktmouk.Hackaru": { + "icon": "", + "images": [] + }, + "Kubernetes.kubectl": { + "icon": "", + "images": [] + }, + "Kubernetes.minikube": { + "icon": "", + "images": [] + }, + "KuGou.gejigeji": { + "icon": "", + "images": [] + }, + "KuGou.KGMusic": { + "icon": "", + "images": [] + }, + "Kuro.Mery": { + "icon": "", + "images": [] + }, + "Kuro.Mery.Beta": { + "icon": "", + "images": [] + }, + "KurtisLiggett.SimpleIPConfig": { + "icon": "", + "images": [] + }, + "KuRuimeng.PalmInput": { + "icon": "", + "images": [] + }, + "kvakulo.switcheroo": { + "icon": "", + "images": [] + }, + "KYDronePilot.SpaceEye": { + "icon": "", + "images": [] + }, + "kymoto.InnoScriptStudio": { + "icon": "", + "images": [] + }, + "L0phtHoldings.L0phtCrack": { + "icon": "", + "images": [] + }, + "LacyMorrow.CrossOver": { + "icon": "", + "images": [] + }, + "LAIPIC.LaiHuaVideo": { + "icon": "", + "images": [] + }, + "LAIPIC.Perfoo": { + "icon": "", + "images": [] + }, + "Lakes.SCREENView": { + "icon": "", + "images": [] + }, + "LAMMPS.LAMMPS": { + "icon": "", + "images": [] + }, + "LAMMPS.LAMMPS-ML-PACE": { + "icon": "", + "images": [] + }, + "LAMMPS.LAMMPS-USER-AEAM": { + "icon": "", + "images": [] + }, + "LAMMPS.LAMMPS-USER-REBOMOS": { + "icon": "", + "images": [] + }, + "LAMMPS.LAMMPS-USER-VCSGC": { + "icon": "", + "images": [] + }, + "LanguageTool.LanguageTool": { + "icon": "", + "images": [] + }, + "Lapce.Lapce": { + "icon": "", + "images": [] + }, + "last-hit-team.last-hit": { + "icon": "", + "images": [] + }, + "LastFM.LastFMDesktopScrobbler": { + "icon": "", + "images": [] + }, + "launch4j.launch4j": { + "icon": "", + "images": [] + }, + "LaurentPRenedeCotret.pandoc-plot": { + "icon": "", + "images": [] + }, + "Lauriethefish.QuestPatcher": { + "icon": "", + "images": [] + }, + "lauthieb.code-notes": { + "icon": "", + "images": [] + }, + "Lazarus.Lazarus": { + "icon": "", + "images": [] + }, + "Lazesoft.LazesoftRecovery": { + "icon": "", + "images": [] + }, + "LBRY.LBRY": { + "icon": "", + "images": [] + }, + "Learnpulse.Screenpresso": { + "icon": "", + "images": [] + }, + "LedgerHQ.LedgerLive": { + "icon": "", + "images": [] + }, + "leezer3.OpenBVE": { + "icon": "", + "images": [] + }, + "LeGitHubDeTai.AnimeBack": { + "icon": "https://i.imgur.com/ih7APQ2.png", + "images": [ + "https://raw.githubusercontent.com/LeGitHubDeTai/AnimeBack/main/assets/images/options.png", + "https://github.com/LeGitHubDeTai/AnimeBack/raw/main/assets/images/tray%20options.png?raw=true", + "https://github.com/LeGitHubDeTai/AnimeBack/raw/main/assets/images/options%20window.png?raw=true", + "https://github.com/LeGitHubDeTai/AnimeBack/raw/main/assets/images/changelog%20window.png?raw=true", + "https://github.com/LeGitHubDeTai/AnimeBack/raw/main/assets/images/add%20extensions.png?raw=true", + "https://github.com/LeGitHubDeTai/AnimeBack/raw/main/assets/images/add%20custom.png?raw=true" + ] + }, + "LEGO.MindstormsEduEV3Classroom": { + "icon": "", + "images": [] + }, + "leinelissen.aeon": { + "icon": "https://i.imgur.com/vslysV8.png", + "images": [ + "https://github.com/leinelissen/aeon/blob/master/docs/.gitbook/assets/aeon-demo.gif?raw=true", + "https://github.com/leinelissen/aeon/blob/master/docs/.gitbook/assets/graph.png?raw=true", + "https://github.com/leinelissen/aeon/blob/master/docs/.gitbook/assets/erasure.png?raw=true", + "https://github.com/leinelissen/aeon/blob/master/docs/.gitbook/assets/timeline.png?raw=true" + ] + }, + "LelanceFlamer.TLFDADIDW": { + "icon": "", + "images": [] + }, + "LeNgocKhoa.Laragon": { + "icon": "", + "images": [] + }, + "Lenovo.DockManager": { + "icon": "", + "images": [] + }, + "Lenovo.LeAppStore": { + "icon": "", + "images": [] + }, + "Lenovo.LeCloud": { + "icon": "", + "images": [] + }, + "Lenovo.LegionAccessoryCentral": { + "icon": "", + "images": [] + }, + "Lenovo.MigrationAssistant": { + "icon": "", + "images": [] + }, + "Lenovo.QuickClean": { + "icon": "", + "images": [] + }, + "Lenovo.SystemUpdate": { + "icon": "", + "images": [] + }, + "Lenovo.ThinInstaller": { + "icon": "", + "images": [] + }, + "Lenovo.UpdateRetriever": { + "icon": "", + "images": [] + }, + "LeonardoZide.LeoCAD": { + "icon": "", + "images": [] + }, + "Leonflix.Leonflix": { + "icon": "", + "images": [] + }, + "Levitsky.FontBase": { + "icon": "", + "images": [] + }, + "Levminer.Authme": { + "icon": "https://dashboard.snapcraft.io/site_media/appmedia/2022/06/icon_QqnPS4R.png", + "images": [ + "https://github.com/Levminer/authme/raw/dev/screenshots/application.png", + "https://github.com/Levminer/authme/raw/dev/screenshots/edit.png", + "https://github.com/Levminer/authme/raw/dev/screenshots/export.png", + "https://github.com/Levminer/authme/raw/dev/screenshots/import.png", + "https://github.com/Levminer/authme/raw/dev/screenshots/settings.png" + ] + }, + "Lexikos.AutoHotkey": { + "icon": "https://raw.githubusercontent.com/Ixiko/AHK-Forum/master/images/AHK%20main%20icon.png", + "images": [ + "https://i.ytimg.com/vi/n_9-QkD-zJ4/maxresdefault.jpg", + "https://s8.postimg.cc/je3mkkwzp/Auto_GUI_v2.0.1.png", + "https://images.sftcdn.net/images/t_app-cover-l,f_auto/p/a5edca32-96d7-11e6-98e0-00163ec9f5fa/4013272943/autohotkey-Untitled.png" + ] + }, + "lexoyo.silex-desktop": { + "icon": "", + "images": [] + }, + "LGUG2Z.komorebi": { + "icon": "", + "images": [] + }, + "liberodark.ODrive": { + "icon": "", + "images": [] + }, + "LibgenApps.LibgenDesktop": { + "icon": "", + "images": [] + }, + "libjpeg-turbo.libjpeg-turbo.GCC": { + "icon": "", + "images": [] + }, + "libjpeg-turbo.libjpeg-turbo.VC": { + "icon": "", + "images": [] + }, + "LibreCAD.LibreCAD": { + "icon": "", + "images": [] + }, + "Libretro.RetroArch": { + "icon": "", + "images": [] + }, + "LibrevaultTeam.Librevault": { + "icon": "", + "images": [] + }, + "LibreWolf.LibreWolf": { + "icon": "", + "images": [] + }, + "LightBurnSoftware.LightBurn": { + "icon": "", + "images": [] + }, + "Lightform.LightformCreator": { + "icon": "", + "images": [] + }, + "LIGHTNINGUK.ImgBurn": { + "icon": "https://i.ibb.co/XsmMybM/962a091e98eaabdcdd98e4807565fab2b290848df3391684930e210056617433-200.png", + "images": [ + "https://upload.wikimedia.org/wikipedia/en/0/0a/ImgBurn_screenshot.png" + ] + }, + "lightspark.lightspark": { + "icon": "", + "images": [] + }, + "LightyearVPN.LightyearVPN": { + "icon": "", + "images": [] + }, + "LilyPond.LilyPond": { + "icon": "", + "images": [] + }, + "LilyPond.LilyPond.Unstable": { + "icon": "", + "images": [] + }, + "LINE.LINE": { + "icon": "", + "images": [] + }, + "linepod.linepodlauncher": { + "icon": "", + "images": [] + }, + "LingitAS.Lingdys4": { + "icon": "", + "images": [] + }, + "LINQPad.LINQPad.5": { + "icon": "", + "images": [] + }, + "LINQPad.LINQPad.6": { + "icon": "", + "images": [] + }, + "LINQPad.LINQPad.7": { + "icon": "", + "images": [] + }, + "LinuxSuRen.HTTPdownloader": { + "icon": "", + "images": [] + }, + "LinwoodCloud.Butterfly": { + "icon": "", + "images": [] + }, + "LinwoodCloud.Butterfly.Nightly": { + "icon": "", + "images": [] + }, + "LionelJouin.PiP-Tool": { + "icon": "", + "images": [] + }, + "Liquit.Workspace.Agent": { + "icon": "", + "images": [] + }, + "LiskFoundation.LiskHub": { + "icon": "", + "images": [] + }, + "listen1.listen1": { + "icon": "", + "images": [] + }, + "listen1.listen1.fluent": { + "icon": "", + "images": [] + }, + "LiTang.QianJi": { + "icon": "", + "images": [] + }, + "LiteratureandLatte.Scrivener": { + "icon": "", + "images": [] + }, + "LittleTijn.SpookyView": { + "icon": "", + "images": [] + }, + "LizardByte.Sunshine": { + "icon": "", + "images": [] + }, + "LLVM.LLVM": { + "icon": "", + "images": [] + }, + "LMMS.LMMS": { + "icon": "", + "images": [] + }, + "LN-Zap.zap": { + "icon": "", + "images": [] + }, + "lode.lode": { + "icon": "", + "images": [] + }, + "logisim-evolution.logisim-evolution": { + "icon": "", + "images": [] + }, + "Logitech.CameraSettings": { + "icon": "", + "images": [] + }, + "Logitech.GHUB": { + "icon": "https://i.imgur.com/xkIS90o.png", + "images": [] + }, + "Logitech.LGS": { + "icon": "", + "images": [] + }, + "Logitech.LogiBolt": { + "icon": "", + "images": [] + }, + "Logitech.LogiTune": { + "icon": "", + "images": [] + }, + "Logitech.MyHarmony": { + "icon": "", + "images": [] + }, + "Logitech.Options": { + "icon": "", + "images": [] + }, + "Logitech.OptionsPlus": { + "icon": "", + "images": [] + }, + "Logitech.SetPoint": { + "icon": "", + "images": [] + }, + "Logitech.Solar": { + "icon": "", + "images": [] + }, + "Logitech.Sync": { + "icon": "", + "images": [] + }, + "Logitech.UnifyingSoftware": { + "icon": "", + "images": [] + }, + "LogMeIn.GoToMeeting": { + "icon": "", + "images": [] + }, + "LogMeIn.Hamachi": { + "icon": "", + "images": [] + }, + "LogMeIn.LastPass": { + "icon": "", + "images": [] + }, + "Logseq.Logseq": { + "icon": "", + "images": [] + }, + "Logtalk.Logtalk": { + "icon": "", + "images": [] + }, + "long-woo.12306-electron": { + "icon": "https://raw.githubusercontent.com/woo-long/12306-electron/dev/build/icons/256x256.png", + "images": [ + "https://raw.githubusercontent.com/woo-long/12306-electron/dev/app_snapshot.png" + ] + }, + "Loom.Loom": { + "icon": "", + "images": [] + }, + "LOOT.LOOT": { + "icon": "", + "images": [] + }, + "losbiw.erin": { + "icon": "", + "images": [] + }, + "lostdesign.linked": { + "icon": "", + "images": [] + }, + "Love2d.Love2d": { + "icon": "", + "images": [] + }, + "LovettSoftware.MyMoney.Net": { + "icon": "", + "images": [] + }, + "Lowkey.LowkeyGG": { + "icon": "", + "images": [] + }, + "LSoftTechnologies.ActiveBootDisk": { + "icon": "https://www.lsoft.net/images/icons/boot-disk.png", + "images": [ + "https://www.lsoft.net/images/screenshots/bootdisk1.png", + "https://www.lsoft.net/images/screenshots/bootdisk2.png", + "https://www.lsoft.net/images/screenshots/bootdisk3.png", + "https://www.lsoft.net/images/screenshots/bootdisk5.png", + "https://www.lsoft.net/images/screenshots/bootdisk6.png", + "https://www.lsoft.net/images/screenshots/bootdisk7.png", + "https://www.lsoft.net/images/screenshots/bootdisk8.png", + "https://www.lsoft.net/images/screenshots/bootdisk9.png", + "https://www.lsoft.net/images/screenshots/bootdisk10.png" + ] + }, + "LSoftTechnologies.ActiveDataBurner": { + "icon": "https://www.lsoft.net/images/icons/data-burner.png", + "images": [ + "https://www.lsoft.net/images/screenshots/cd_data_burner.gif" + ] + }, + "LSoftTechnologies.ActiveDataStudio": { + "icon": "https://www.lsoft.net/images/icons/data-studio.png", + "images": [ + "https://www.lsoft.net/images/icons/data-studio.png", + "https://www.lsoft.net/images/screenshots/disk-image-new.gif", + "https://www.lsoft.net/images/screenshots/main-screen4-big.gif", + "https://www.lsoft.net/images/screenshots/workspace.png", + "https://www.lsoft.net/images/screenshots/partition-manager-workspace.png", + "https://www.lsoft.net/images/screenshots/disk-monitor-screenshot.gif", + "https://www.lsoft.net/images/screenshots/disk-editor-new.gif", + "https://www.lsoft.net/images/screenshots/password-changer.jpg", + "https://www.lsoft.net/images/screenshots/killdisk.png", + "https://www.lsoft.net/images/screenshots/data-burner.gif" + ] + }, + "LSoftTechnologies.ActiveDiskEditor": { + "icon": "https://www.lsoft.net/images/icons/disk-editor.png", + "images": [ + "https://www.lsoft.net/images/screenshots/HexEditor2.gif", + "https://www.lsoft.net/images/screenshots/HexEditor5.gif", + "https://www.lsoft.net/images/screenshots/HexEditor12.gif", + "https://www.lsoft.net/images/screenshots/HexEditor8.gif", + "https://www.lsoft.net/images/screenshots/HexEditor9.gif", + "https://www.lsoft.net/images/screenshots/HexEditor10.gif", + "https://www.lsoft.net/images/screenshots/HexEditor11.gif", + "https://www.lsoft.net/images/screenshots/HexEditor7.gif" + ] + }, + "LSoftTechnologies.ActiveDiskImage": { + "icon": "https://www.lsoft.net/images/icons/disk-image.png", + "images": [ + "https://www.lsoft.net/images/screenshots/diskimage1.png", + "https://www.lsoft.net/images/screenshots/diskimage2.png", + "https://www.lsoft.net/images/screenshots/diskimage3.png", + "https://www.lsoft.net/images/screenshots/diskimage4.png", + "https://www.lsoft.net/images/screenshots/diskimage5.gif", + "https://www.lsoft.net/images/screenshots/diskimage6.png" + ] + }, + "LSoftTechnologies.ActiveDiskMonitor": { + "icon": "https://www.lsoft.net/images/icons/disk-monitor.png", + "images": [ + "https://www.lsoft.net/images/screenshots/1-disk-monitor.gif", + "https://www.lsoft.net/images/screenshots/disk-monitor-smart.gif", + "https://www.lsoft.net/images/screenshots/disk-monitor-scan.gif", + "https://www.lsoft.net/images/screenshots/disk-monitor-temperature.gif", + "https://www.lsoft.net/images/screenshots/sc_diskinfo.jpg", + "https://www.lsoft.net/images/screenshots/sc_disksametime.gif", + "https://www.lsoft.net/images/screenshots/sc_hoststatus.jpg", + "https://www.lsoft.net/images/screenshots/sc_temphist.jpg", + "https://www.lsoft.net/images/screenshots/screen_badblock_big.gif" + ] + }, + "LSoftTechnologies.ActiveDVDEraser": { + "icon": "https://www.lsoft.net/images/icons/dvd-eraser.png", + "images": [ + "https://www.lsoft.net/images/screenshots/dvd_eraser_main.gif" + ] + }, + "LSoftTechnologies.ActiveFileRecove\u2026": { + "icon": "", + "images": [] + }, + "LSoftTechnologies.ActiveISOBurner": { + "icon": "https://www.lsoft.net/images/icons/data-burner.png", + "images": [ + "https://www.lsoft.net/images/screenshots/ISO-Burner.jpg", + "https://www.lsoft.net/images/screenshots/iso_burner_beta_options.gif" + ] + }, + "LSoftTechnologies.ActiveISOManager": { + "icon": "https://www.lsoft.net/images/icons/iso-manager.png", + "images": [ + "https://www.lsoft.net/images/screenshots/edit-iso-manager.gif", + "https://www.lsoft.net/images/screenshots/burn-iso-manager.gif" + ] + }, + "LSoftTechnologies.ActiveKillDisk": { + "icon": "https://www.lsoft.net/images/icons/killdisk.png", + "images": [ + "https://www.lsoft.net/images/screenshots/Certificate-killdisk1.png", + "https://www.lsoft.net/images/screenshots/sanitizing-hard-disk-killdisk2.png", + "https://www.lsoft.net/images/screenshots/parallel-disk-erasing-killdisk3.png", + "https://www.lsoft.net/images/screenshots/erase-options-killdisk4.png", + "https://www.lsoft.net/images/screenshots/sectors-display-hex-data-killdisk5.png", + "https://www.lsoft.net/images/screenshots/detected-physical-disks-killdisk6.gif", + "https://www.lsoft.net/images/screenshots/file-system-display-killdisk7.png", + "https://www.lsoft.net/images/screenshots/sanitizing-unused-disk-space-killdisk8.png", + "https://www.lsoft.net/images/screenshots/settings-dialog-killdisk9.png" + ] + }, + "LSoftTechnologies.ActiveLiveCD": { + "icon": "https://www.lsoft.net/images/icons/live-cd.png", + "images": [ + "https://www.lsoft.net/images/screenshots/livecd-desktop.jpg", + "https://www.lsoft.net/images/screenshots/livecd-configure-decktop.png", + "https://www.lsoft.net/images/screenshots/livecd-disk-backup.jpg", + "https://www.lsoft.net/images/screenshots/livecd-main.gif", + "https://www.lsoft.net/images/screenshots/livecd-undelete.jpg", + "https://www.lsoft.net/images/screenshots/livecd-disk.gif" + ] + }, + "LSoftTechnologies.ActivePartitionM\u2026": { + "icon": "", + "images": [] + }, + "LSoftTechnologies.ActivePartitionR\u2026": { + "icon": "", + "images": [] + }, + "LSoftTechnologies.ActivePasswordCh\u2026": { + "icon": "", + "images": [] + }, + "LSoftTechnologies.ActiveUNDELETE": { + "icon": "https://www.lsoft.net/images/icons/undelete.png", + "images": [ + "https://www.lsoft.net/images/screenshots/main-screen-recovery-view-undelete1.png", + "https://www.lsoft.net/images/screenshots/disk-scan-screen-undelete2.png", + "https://www.lsoft.net/images/screenshots/data-recovery-screen-undelete3.png", + "https://www.lsoft.net/images/screenshots/file-preview-screen-undelete4.png", + "https://www.lsoft.net/images/screenshots/disk-editor-screen-undelete5.png", + "https://www.lsoft.net/images/screenshots/partman-screen-undelete6.png" + ] + }, + "LSoftTechnologies.ActiveUNERASER": { + "icon": "https://www.lsoft.net/images/icons/uneraser.png", + "images": [ + "https://www.lsoft.net/images/icons/uneraser.png", + "https://www.lsoft.net/images/screenshots/uneraser-superscan.png", + "https://www.lsoft.net/images/screenshots/uneraser-restored-file.png" + ] + }, + "LSoftTechnologies.ActiveZDelete": { + "icon": "https://www.lsoft.net/images/icons/zdelete.png", + "images": [ + "https://www.lsoft.net/images/screenshots/zdelete-menu.jpg", + "https://www.lsoft.net/images/screenshots/zdelete-erase-method.jpg", + "https://www.lsoft.net/images/screenshots/zdelete-selecting-file-for-erasure.jpg" + ] + }, + "LSoftTechnologies.NTFSDataRecovery": { + "icon": "", + "images": [] + }, + "LSoftTechnologies.UNFORMAT": { + "icon": "", + "images": [] + }, + "lstratman.easyconnect": { + "icon": "", + "images": [] + }, + "LuanRoger.WorkOffice": { + "icon": "", + "images": [] + }, + "luapp.Covid-19-cases-overview": { + "icon": "", + "images": [] + }, + "luapp.ToDo": { + "icon": "", + "images": [] + }, + "LucasReade.OhHaiBrowser": { + "icon": "", + "images": [] + }, + "LukasBach.Yana": { + "icon": "", + "images": [] + }, + "lukasmonk.lucaschess": { + "icon": "", + "images": [] + }, + "LukeBriggs.Pepys": { + "icon": "", + "images": [] + }, + "lukehaas.RunJS": { + "icon": "", + "images": [] + }, + "LuminanceHDR.LuminanceHDR": { + "icon": "", + "images": [] + }, + "LUPhysics.PyMODA": { + "icon": "", + "images": [] + }, + "LupoPenSuite.DropIt": { + "icon": "", + "images": [] + }, + "LutzRoeder.Netron": { + "icon": "", + "images": [] + }, + "luyuhuang.DWords2": { + "icon": "", + "images": [] + }, + "LWKS.lightworks": { + "icon": "", + "images": [] + }, + "LX-Systems.WinMute": { + "icon": "", + "images": [] + }, + "LyonBros.Turtl": { + "icon": "", + "images": [] + }, + "lyswhut.lx-music-desktop": { + "icon": "", + "images": [] + }, + "LyX.LyX": { + "icon": "", + "images": [] + }, + "M2Team.NanaZip": { + "icon": "https://github.com/M2Team/NanaZip/blob/main/Assets/NanaZip.png?raw=true", + "images": [ + "https://github.com/M2Team/NanaZip/blob/main/Documents/ContextMenu.png?raw=true", + "https://github.com/M2Team/NanaZip/blob/main/Documents/MainWindow.png?raw=true" + ] + }, + "M2Team.NanaZip.Preview": { + "icon": "https://store-images.s-microsoft.com/image/apps.50792.14474509061719709.17da0911-dc1c-48b2-9bcb-e41dc2e0e38e.862b41b7-470d-46f3-801f-8b701239fbab", + "images": [ + "https://github.com/M2Team/NanaZip/blob/main/Documents/ContextMenu.png?raw=true", + "https://github.com/M2Team/NanaZip/blob/main/Documents/MainWindow.png?raw=true" + ] + }, + "Maca134.A3Launcher": { + "icon": "https://i.imgur.com/lYZJfK3.png", + "images": [ + "https://a3launcher.com/images/7171b67d-5c3f-43af-81d1-790fae989dea.png", + "https://i.ytimg.com/vi/F2eT-7k2aMc/sddefault.jpg", + "https://4.bp.blogspot.com/-fpsyiZfmSy0/VLnyNUw4VfI/AAAAAAAAd-0/bRQhZMEI7VI/s1600/arma3_a3_launcher2.png" + ] + }, + "Maca134.DZLauncher": { + "icon": "", + "images": [] + }, + "MacPaw.Encrypto": { + "icon": "", + "images": [] + }, + "MacType.MacType": { + "icon": "", + "images": [] + }, + "madisvain.upcount": { + "icon": "", + "images": [] + }, + "MadOtterGames.VillagersandHeroes": { + "icon": "", + "images": [] + }, + "MadrasCheck.flow": { + "icon": "", + "images": [] + }, + "magic-wormhole.magic-wormhole": { + "icon": "", + "images": [] + }, + "Mailbird.Mailbird": { + "icon": "", + "images": [] + }, + "MailRu.ICQNew": { + "icon": "", + "images": [] + }, + "majsoulplus.majsoul-plus": { + "icon": "", + "images": [] + }, + "Makeblock.LaserBox": { + "icon": "", + "images": [] + }, + "Makeblock.LaserBox.Basic": { + "icon": "", + "images": [] + }, + "Makeblock.LaserBox.mCreate": { + "icon": "", + "images": [] + }, + "makeblockteam.mBlock": { + "icon": "", + "images": [] + }, + "MaLuns.wallhaven-electron": { + "icon": "", + "images": [] + }, + "Malwarebytes.Malwarebytes": { + "icon": "", + "images": [] + }, + "Malwarebytes.Privacy": { + "icon": "", + "images": [] + }, + "MAMP.MAMP": { + "icon": "", + "images": [] + }, + "ManaManaIoT.DeviceManagementAssist\u2026": { + "icon": "", + "images": [] + }, + "Mandelbulber.Mandelbulber": { + "icon": "", + "images": [] + }, + "ManicTime.ManicTime": { + "icon": "", + "images": [] + }, + "ManifoldSoftware.Manifold.8": { + "icon": "", + "images": [] + }, + "ManifoldSoftware.Manifold.9": { + "icon": "", + "images": [] + }, + "ManifoldSoftware.ManifoldViewer.9": { + "icon": "", + "images": [] + }, + "manosim.gitify": { + "icon": "", + "images": [] + }, + "ManticoreGames.Core": { + "icon": "", + "images": [] + }, + "maojindao55.Etcder": { + "icon": "", + "images": [] + }, + "MapleMedia.PulseSMS": { + "icon": "", + "images": [] + }, + "MapMapTeam.MapMap": { + "icon": "", + "images": [] + }, + "MapTiler.MapTilerDesktop": { + "icon": "", + "images": [] + }, + "mar10.pyftpsync": { + "icon": "", + "images": [] + }, + "mar10.stressor": { + "icon": "", + "images": [] + }, + "mar10.wsgidav": { + "icon": "", + "images": [] + }, + "MarcEspinSanz.GravitonEditor": { + "icon": "", + "images": [] + }, + "marchellodev.Sharik": { + "icon": "", + "images": [] + }, + "MarcinOtorowski.MSIXHero": { + "icon": "", + "images": [] + }, + "MarekJasinski.FreeCommanderXE": { + "icon": "", + "images": [] + }, + "marha.VcXsrv": { + "icon": "", + "images": [] + }, + "MariaDB.Server": { + "icon": "", + "images": [] + }, + "MarkoBL.Rosi": { + "icon": "", + "images": [] + }, + "MarkText.MarkText": { + "icon": "", + "images": [] + }, + "Martevax.TitulkyCom": { + "icon": "", + "images": [] + }, + "martinchrzan.ColorPicker": { + "icon": "", + "images": [] + }, + "MartinFinnerup.YouTubeMusicforDesk\u2026": { + "icon": "", + "images": [] + }, + "MartinKinkelin.RoboMirror": { + "icon": "", + "images": [] + }, + "MasterPackager.MasterPackager": { + "icon": "", + "images": [] + }, + "MathiasSvensson.MultiCommander": { + "icon": "", + "images": [] + }, + "Mathpix.MathpixSnippingTool": { + "icon": "", + "images": [] + }, + "mathworks.matlabdrive": { + "icon": "", + "images": [] + }, + "Mattermost.MattermostDesktop": { + "icon": "", + "images": [] + }, + "MatthijsGroen.Geppetto": { + "icon": "", + "images": [] + }, + "MattTytel.Helm": { + "icon": "", + "images": [] + }, + "matvelloso.electron-office-365": { + "icon": "", + "images": [] + }, + "matvelloso.electron-office-consumer": { + "icon": "", + "images": [] + }, + "maurizuki.O2": { + "icon": "", + "images": [] + }, + "MaxDiesel.UnrealCommander": { + "icon": "", + "images": [] + }, + "MaximaTeam.Maxima": { + "icon": "", + "images": [] + }, + "maximmax42.CustomRP": { + "icon": "", + "images": [] + }, + "Maximus5.ConEmu": { + "icon": "", + "images": [] + }, + "Maxthon.Maxthon.5": { + "icon": "", + "images": [] + }, + "Maxthon.Maxthon.6": { + "icon": "", + "images": [] + }, + "Mayakron.AcrylicDNS": { + "icon": "https://i.imgur.com/gEsxO7g.png", + "images": [] + }, + "maygo.tockler": { + "icon": "", + "images": [] + }, + "mb21.panwriter": { + "icon": "", + "images": [] + }, + "mcmilk.7zip-zstd": { + "icon": "https://findicons.com/files/icons/1008/quiet/256/7zip.png", + "images": [ + "https://mcmilk.de/projects/7-Zip-zstd/Fileman.png", + "https://mcmilk.de/projects/7-Zip-zstd/Methods.png", + "https://mcmilk.de/projects/7-Zip-zstd/Add-To-Archive.png", + "https://mcmilk.de/projects/7-Zip-zstd/dl/compr-v120.png" + ] + }, + "MCreator.MCreator": { + "icon": "", + "images": [] + }, + "McServ.McServ": { + "icon": "", + "images": [] + }, + "MCvanderKooij.PictoSelector": { + "icon": "", + "images": [] + }, + "mdyna.mdyna": { + "icon": "", + "images": [] + }, + "MedalB.V.Medal": { + "icon": "", + "images": [] + }, + "MediaArea.MediaInfo": { + "icon": "", + "images": [] + }, + "MediaArea.MediaInfo.GUI": { + "icon": "", + "images": [ + "https://i.postimg.cc/s2x7v8Ts/814eedf-84591aa.jpg" + ] + }, + "MediaHuman.LyricsFinder": { + "icon": "", + "images": [] + }, + "MediathekViewTeam.MediathekView": { + "icon": "", + "images": [] + }, + "MedZed.youtubetomp3": { + "icon": "", + "images": [] + }, + "Mega.MEGASync": { + "icon": "", + "images": [] + }, + "MehediHassan.Tweeten": { + "icon": "", + "images": [] + }, + "Meld.Meld": { + "icon": "", + "images": [] + }, + "mellobacon.scpterminal": { + "icon": "", + "images": [] + }, + "Melodics.Melodics": { + "icon": "", + "images": [] + }, + "Meltytech.Shotcut": { + "icon": "", + "images": [] + }, + "Melvin-Abraham.Google-Assistant": { + "icon": "", + "images": [] + }, + "Melvin-Abraham.Google-Assistant.Pr\u2026": { + "icon": "", + "images": [] + }, + "MementoDB.MementoDatabaseDesktop": { + "icon": "", + "images": [] + }, + "Memurai.MemuraiDeveloper": { + "icon": "", + "images": [] + }, + "mentebinaria.retoolkit": { + "icon": "", + "images": [] + }, + "Mercurial.Mercurial": { + "icon": "", + "images": [] + }, + "MeshHouse.MeshHouse": { + "icon": "", + "images": [] + }, + "mesonbuild.meson": { + "icon": "", + "images": [] + }, + "MetaGeek.inSSIDer": { + "icon": "", + "images": [] + }, + "mguessan.davmail": { + "icon": "", + "images": [] + }, + "MHGames.IHaveNoTomatoes": { + "icon": "", + "images": [] + }, + "MHGames.ThoseFunnyFunguloids": { + "icon": "", + "images": [] + }, + "MicaForEveryone.MicaForEveryone": { + "icon": "", + "images": [] + }, + "MichaelBromley.SKQW": { + "icon": "", + "images": [] + }, + "MichaelTippach.ASIO4ALL": { + "icon": "https://cybersoft.ru/uploads/posts/2021-03/1614682798_asio4all.png", + "images": [ + "https://www.asio4all.org/wp-content/uploads/2021/04/PanelSimple.jpg", + "https://www.asio4all.org/wp-content/uploads/2021/04/PanelAdvanced.jpg", + "https://www.asio4all.org/wp-content/uploads/2021/03/USBTreeview.jpg" + ] + }, + "MicroSIP.MicroSIP": { + "icon": "", + "images": [] + }, + "MicroSIP.MicroSIP.Lite": { + "icon": "", + "images": [] + }, + "Microsoft.ADKPEAddon": { + "icon": "", + "images": [] + }, + "Microsoft.AppInstallerFileBuilder": { + "icon": "", + "images": [] + }, + "Microsoft.azure-iot-explorer": { + "icon": "https://i.imgur.com/zqAMm9X.png", + "images": [ + "https://github.com/Azure/azure-iot-explorer/raw/main/doc/screenRecords/login.gif", + "https://github.com/Azure/azure-iot-explorer/raw/main/doc/screenRecords/create_device.gif", + "https://github.com/Azure/azure-iot-explorer/raw/main/doc/screenRecords/device_features.gif", + "https://github.com/Azure/azure-iot-explorer/raw/main/doc/screenRecords/pnp_discovery.gif", + "https://github.com/Azure/azure-iot-explorer/raw/main/doc/screenRecords/pnp_interaction_property.gif", + "https://github.com/Azure/azure-iot-explorer/raw/main/doc/screenRecords/pnp_interaction_telemetry.gif" + ] + }, + "Microsoft.AzureAztfy": { + "icon": "https://archive.org/download/github.com-Azure-aztfy_-_2022-04-15_03-45-05/cover.jpg", + "images": [ + "https://asciinema.org/a/475516.svg" + ] + }, + "Microsoft.AzureCLI": { + "icon": "", + "images": [] + }, + "Microsoft.AzureCosmosEmulator": { + "icon": "https://i.imgur.com/udtoNcP.png", + "images": [ + "https://mountainss.files.wordpress.com/2018/02/cosmosdb-emu-1.png", + "https://learn.microsoft.com/en-us/azure/cosmos-db/media/local-emulator/mac-trust-certificate.png" + ] + }, + "Microsoft.AzureDataCLI": { + "icon": "https://i.imgur.com/2hR51ld.png", + "images": [ + "https://azurelessons.com/wp-content/uploads/2020/12/Install-Azure-CLI-On-Windows.jpg", + "https://s33046.pcdn.co/wp-content/uploads/2020/05/azure-cloud-shell.png" + ] + }, + "Microsoft.AzureDataStudio": { + "icon": "https://i.imgur.com/rpaxRmk.png", + "images": [ + "https://i.imgur.com/IVuHK5O.png", + "https://cloudblogs.microsoft.com/uploads/prod/sites/32/2018/09/Azure-data-studio-for-sql-server-screenshot.png", + "https://i.imgur.com/VidjK8M.png" + ] + }, + "Microsoft.AzureDataStudio.Insiders": { + "icon": "https://i.imgur.com/rpaxRmk.png", + "images": [ + "https://i.imgur.com/IVuHK5O.png", + "https://cloudblogs.microsoft.com/uploads/prod/sites/32/2018/09/Azure-data-studio-for-sql-server-screenshot.png", + "https://i.imgur.com/VidjK8M.png" + ] + }, + "Microsoft.AzureFunctionsCoreTools": { + "icon": "https://raw.githubusercontent.com/Azure/azure-functions-cli/master/src/Azure.Functions.Cli/npm/assets/azure-functions-logo-color-raster.png", + "images": [ + "https://learn.microsoft.com/training/achievements/develop-test-deploy-azure-functions-core-tools-social.png", + "https://azure.github.io/AppService/media/2017/08/cli-screenshot.png", + "https://i.imgur.com/EKthsZP.png" + ] + }, + "Microsoft.AzureMediaServicesExplor\u2026": { + "icon": "", + "images": [] + }, + "Microsoft.AzureStorageEmulator": { + "icon": "", + "images": [] + }, + "Microsoft.AzureStorageExplorer": { + "icon": "", + "images": [] + }, + "Microsoft.Bicep": { + "icon": "", + "images": [] + }, + "Microsoft.BingWallpaper": { + "icon": "", + "images": [] + }, + "Microsoft.bitsmanager": { + "icon": "", + "images": [] + }, + "Microsoft.BotFrameworkComposer": { + "icon": "", + "images": [] + }, + "Microsoft.BotFrameworkEmulator": { + "icon": "", + "images": [] + }, + "Microsoft.CLRTypesSQLServer.2019": { + "icon": "", + "images": [] + }, + "Microsoft.DeploymentToolkit": { + "icon": "", + "images": [] + }, + "Microsoft.DirectX": { + "icon": "", + "images": [] + }, + "Microsoft.DotNet.AspNetCore.3_1": { + "icon": "", + "images": [] + }, + "Microsoft.DotNet.AspNetCore.5": { + "icon": "", + "images": [] + }, + "Microsoft.DotNet.AspNetCore.6": { + "icon": "", + "images": [] + }, + "Microsoft.DotNet.AspNetCore.Preview": { + "icon": "", + "images": [] + }, + "Microsoft.DotNet.DesktopRuntime.3_1": { + "icon": "", + "images": [] + }, + "Microsoft.DotNet.DesktopRuntime.5": { + "icon": "", + "images": [] + }, + "Microsoft.DotNet.DesktopRuntime.6": { + "icon": "", + "images": [] + }, + "Microsoft.DotNet.DesktopRuntime.Pr\u2026": { + "icon": "", + "images": [] + }, + "Microsoft.DotNet.HostingBundle.3_1": { + "icon": "", + "images": [] + }, + "Microsoft.DotNet.HostingBundle.5": { + "icon": "", + "images": [] + }, + "Microsoft.DotNet.HostingBundle.6": { + "icon": "", + "images": [] + }, + "Microsoft.DotNet.HostingBundle.Pre\u2026": { + "icon": "", + "images": [] + }, + "Microsoft.DotNet.Runtime.3_1": { + "icon": "", + "images": [] + }, + "Microsoft.DotNet.Runtime.5": { + "icon": "", + "images": [] + }, + "Microsoft.DotNet.Runtime.6": { + "icon": "", + "images": [] + }, + "Microsoft.DotNet.Runtime.Preview": { + "icon": "", + "images": [] + }, + "Microsoft.DotNet.SDK.3_1": { + "icon": "", + "images": [] + }, + "Microsoft.DotNet.SDK.5": { + "icon": "", + "images": [] + }, + "Microsoft.DotNet.SDK.6": { + "icon": "", + "images": [] + }, + "Microsoft.DotNet.SDK.Preview": { + "icon": "", + "images": [] + }, + "Microsoft.dotNetFramework": { + "icon": "https://www.itsolutionworld.com/common/img/customise/dotnet_logo.png", + "images": [ + "http://neosmart.net/blog/wp-content/uploads/2019/06/dot-net-framework.png", + "https://sc.filehippo.net/images/t_app-cover-m,f_auto/p/b79eab0e-96d0-11e6-aa5e-00163ed833e7/2916409783/microsoft-net-framework-Installing-.NET-Framework-4.7.jpg" + ] + }, + "Microsoft.dotnetUninstallTool": { + "icon": "", + "images": [] + }, + "Microsoft.Edge": { + "icon": "", + "images": [] + }, + "Microsoft.Edge.Beta": { + "icon": "", + "images": [] + }, + "Microsoft.Edge.Dev": { + "icon": "", + "images": [] + }, + "Microsoft.EdgeWebView2Runtime": { + "icon": "", + "images": [] + }, + "Microsoft.Git": { + "icon": "", + "images": [] + }, + "Microsoft.GitCredentialManagerCore": { + "icon": "", + "images": [] + }, + "Microsoft.IronPython.2": { + "icon": "", + "images": [] + }, + "Microsoft.IronPython.3": { + "icon": "", + "images": [] + }, + "Microsoft.LAPS": { + "icon": "", + "images": [] + }, + "Microsoft.MouseandKeyboardCenter": { + "icon": "", + "images": [] + }, + "Microsoft.MouseWithoutBorders": { + "icon": "", + "images": [] + }, + "Microsoft.MSIXCore": { + "icon": "", + "images": [] + }, + "Microsoft.msmpi": { + "icon": "", + "images": [] + }, + "Microsoft.msmpisdk": { + "icon": "", + "images": [] + }, + "Microsoft.MultilingualAppToolkit": { + "icon": "", + "images": [] + }, + "Microsoft.NuGet": { + "icon": "", + "images": [] + }, + "Microsoft.Office": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/5/5f/Microsoft_Office_logo_%282019%E2%80%93present%29.svg/640px-Microsoft_Office_logo_%282019%E2%80%93present%29.svg.png", + "images": [] + }, + "Microsoft.OfficeDeploymentTool": { + "icon": "", + "images": [] + }, + "Microsoft.OneDrive": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/3/3c/Microsoft_Office_OneDrive_%282019%E2%80%93present%29.svg/320px-Microsoft_Office_OneDrive_%282019%E2%80%93present%29.svg.png", + "images": [] + }, + "Microsoft.OneDrive.Enterprise": { + "icon": "", + "images": [] + }, + "Microsoft.OneDrive.Insiders": { + "icon": "", + "images": [] + }, + "Microsoft.OneDrive.Internal.Fast": { + "icon": "", + "images": [] + }, + "Microsoft.OneDrive.Internal.Slow": { + "icon": "", + "images": [] + }, + "Microsoft.OpenJDK.11": { + "icon": "", + "images": [] + }, + "Microsoft.OpenJDK.16": { + "icon": "", + "images": [] + }, + "Microsoft.OpenJDK.17": { + "icon": "", + "images": [] + }, + "Microsoft.OpenSSH.Beta": { + "icon": "", + "images": [] + }, + "Microsoft.PIX": { + "icon": "", + "images": [] + }, + "Microsoft.PowerAppsCLI": { + "icon": "", + "images": [] + }, + "Microsoft.PowerAutomateDesktop": { + "icon": "", + "images": [] + }, + "Microsoft.PowerBI": { + "icon": "", + "images": [] + }, + "Microsoft.PowerShell": { + "icon": "", + "images": [] + }, + "Microsoft.PowerShell.Preview": { + "icon": "", + "images": [] + }, + "Microsoft.PowerToys": { + "icon": "https://i.imgur.com/SW1jH0O.png", + "images": [ + "https://i.postimg.cc/28YW430H/XP89-DCGQ3-K6-VLD-9bd9e1a9-22c3-4789-99c5-46a7f7a46378.png", + "https://i.postimg.cc/TYcDQGST/XP89-DCGQ3-K6-VLD-e95dd209-0ff1-4fa1-9621-e7d7449238d6.png" + ] + }, + "Microsoft.ProjectMyScreen": { + "icon": "", + "images": [] + }, + "Microsoft.RemoteDesktopClient": { + "icon": "", + "images": [] + }, + "Microsoft.RemoteHelp": { + "icon": "", + "images": [] + }, + "Microsoft.ReportBuilder": { + "icon": "", + "images": [] + }, + "Microsoft.ROpen": { + "icon": "", + "images": [] + }, + "Microsoft.ServiceFabricExplorer": { + "icon": "", + "images": [] + }, + "Microsoft.ServiceFabricRuntime": { + "icon": "", + "images": [] + }, + "Microsoft.Skype": { + "icon": "", + "images": [] + }, + "Microsoft.Skype.Insiders": { + "icon": "", + "images": [] + }, + "Microsoft.Sqlcmd": { + "icon": "", + "images": [] + }, + "Microsoft.SQLServer.2019.Developer": { + "icon": "", + "images": [] + }, + "Microsoft.SQLServer.2019.Express": { + "icon": "", + "images": [] + }, + "Microsoft.SQLServer2012NativeClient": { + "icon": "", + "images": [] + }, + "Microsoft.SQLServerManagementStudio": { + "icon": "", + "images": [] + }, + "Microsoft.SurfaceDuoEmulator.Andro\u2026": { + "icon": "", + "images": [] + }, + "Microsoft.Sysinternals.Autoruns": { + "icon": "", + "images": [ + "https://learn.microsoft.com/en-us/sysinternals/downloads/media/autoruns/autoruns_v13.png", + "https://www.bleepstatic.com/download/screenshots/a/autoruns/everything-tab.jpg" + ] + }, + "Microsoft.Sysinternals.ProcessExpl\u2026": { + "icon": "", + "images": [] + }, + "Microsoft.Sysinternals.ProcessMoni\u2026": { + "icon": "", + "images": [] + }, + "Microsoft.TeamMate": { + "icon": "", + "images": [] + }, + "Microsoft.Teams": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/c/c9/Microsoft_Office_Teams_(2018%E2%80%93present).svg/258px-Microsoft_Office_Teams_(2018%E2%80%93present).svg.png", + "images": [ + "https://upload.wikimedia.org/wikipedia/en/f/f1/Microsoft_Teams_Desktop_Application_Screenshot.png" + ] + }, + "Microsoft.Teams.ContinuousDeployme\u2026": { + "icon": "", + "images": [] + }, + "Microsoft.Teams.Exploration": { + "icon": "", + "images": [] + }, + "Microsoft.Teams.Preview": { + "icon": "", + "images": [] + }, + "Microsoft.UpdateAssistant": { + "icon": "", + "images": [] + }, + "Microsoft.VC++2008Redist-x64": { + "icon": "", + "images": [] + }, + "Microsoft.VC++2008Redist-x86": { + "icon": "", + "images": [] + }, + "Microsoft.VCRedist.2005.x64": { + "icon": "", + "images": [] + }, + "Microsoft.VCRedist.2005.x86": { + "icon": "", + "images": [] + }, + "Microsoft.VCRedist.2008.x64": { + "icon": "", + "images": [] + }, + "Microsoft.VCRedist.2008.x86": { + "icon": "", + "images": [] + }, + "Microsoft.VCRedist.2010.x64": { + "icon": "", + "images": [] + }, + "Microsoft.VCRedist.2010.x86": { + "icon": "", + "images": [] + }, + "Microsoft.VCRedist.2012.x64": { + "icon": "", + "images": [] + }, + "Microsoft.VCRedist.2012.x86": { + "icon": "", + "images": [] + }, + "Microsoft.VCRedist.2013.x64": { + "icon": "", + "images": [] + }, + "Microsoft.VCRedist.2013.x86": { + "icon": "", + "images": [] + }, + "Microsoft.VCRedist.2015+.x64": { + "icon": "", + "images": [] + }, + "Microsoft.VCRedist.2015+.x86": { + "icon": "", + "images": [] + }, + "Microsoft.VCRedist.2019.arm64": { + "icon": "", + "images": [] + }, + "Microsoft.VCRedist.2022.arm64": { + "icon": "", + "images": [] + }, + "Microsoft.VFSforGit": { + "icon": "", + "images": [] + }, + "Microsoft.VisioViewer": { + "icon": "", + "images": [] + }, + "Microsoft.VisualStudio.2019.BuildT\u2026": { + "icon": "", + "images": [] + }, + "Microsoft.VisualStudio.2019.Commun\u2026": { + "icon": "", + "images": [] + }, + "Microsoft.VisualStudio.2019.Enterp\u2026": { + "icon": "", + "images": [] + }, + "Microsoft.VisualStudio.2019.Profes\u2026": { + "icon": "", + "images": [] + }, + "Microsoft.VisualStudio.2019.Remote\u2026": { + "icon": "", + "images": [] + }, + "Microsoft.VisualStudio.2019.Standa\u2026": { + "icon": "", + "images": [] + }, + "Microsoft.VisualStudio.2019.TeamEx\u2026": { + "icon": "", + "images": [] + }, + "Microsoft.VisualStudio.2019.TestAg\u2026": { + "icon": "", + "images": [] + }, + "Microsoft.VisualStudio.2019.TestCo\u2026": { + "icon": "", + "images": [] + }, + "Microsoft.VisualStudio.2022.BuildT\u2026": { + "icon": "", + "images": [] + }, + "Microsoft.VisualStudio.2022.Commun\u2026": { + "icon": "", + "images": [] + }, + "Microsoft.VisualStudio.2022.Enterp\u2026": { + "icon": "", + "images": [] + }, + "Microsoft.VisualStudio.2022.Profes\u2026": { + "icon": "", + "images": [] + }, + "Microsoft.VisualStudio.2022.Remote\u2026": { + "icon": "", + "images": [] + }, + "Microsoft.VisualStudio.2022.TeamEx\u2026": { + "icon": "", + "images": [] + }, + "Microsoft.VisualStudio.2022.TestAg\u2026": { + "icon": "", + "images": [] + }, + "Microsoft.VisualStudio.2022.TestCo\u2026": { + "icon": "", + "images": [] + }, + "Microsoft.VisualStudio.Locator": { + "icon": "", + "images": [] + }, + "Microsoft.VisualStudioCode": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/9/9a/Visual_Studio_Code_1.35_icon.svg/langfr-800px-Visual_Studio_Code_1.35_icon.svg.png", + "images": [ + "https://upload.wikimedia.org/wikipedia/commons/thumb/8/80/Visual_Studio_Code_0.10.1_on_Windows_7%2C_with_search.png/1024px-Visual_Studio_Code_0.10.1_on_Windows_7%2C_with_search.png", + "https://upload.wikimedia.org/wikipedia/commons/thumb/e/e9/VS_Code_%28Insiders%29.png/800px-VS_Code_%28Insiders%29.png?20210728074118" + ] + }, + "Microsoft.VisualStudioCode.Insiders": { + "icon": "", + "images": [ + "https://upload.wikimedia.org/wikipedia/commons/thumb/e/e9/VS_Code_%28Insiders%29.png/800px-VS_Code_%28Insiders%29.png?20210728074118" + ] + }, + "Microsoft.vott": { + "icon": "", + "images": [] + }, + "Microsoft.WebDeploy": { + "icon": "", + "images": [] + }, + "Microsoft.webpicmd": { + "icon": "", + "images": [] + }, + "Microsoft.WindowsADK": { + "icon": "", + "images": [] + }, + "Microsoft.WindowsAdminCenter": { + "icon": "", + "images": [] + }, + "Microsoft.WindowsApplicationDriver": { + "icon": "", + "images": [] + }, + "Microsoft.WindowsInstallationAssis\u2026": { + "icon": "", + "images": [] + }, + "Microsoft.WindowsJournal": { + "icon": "", + "images": [] + }, + "Microsoft.WindowsPCHealthCheck": { + "icon": "", + "images": [] + }, + "Microsoft.WindowsSDK": { + "icon": "", + "images": [] + }, + "Microsoft.WindowsTerminal": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/5/51/Windows_Terminal_logo.svg/320px-Windows_Terminal_logo.svg.png", + "images": [ + "https://store-images.s-microsoft.com/image/apps.64156.13926773940052066.16e93a5b-b25f-4aaf-8a38-77375e237879.00013886-8351-473f-9acd-7fcce9ee7388", + "https://store-images.s-microsoft.com/image/apps.28865.13926773940052066.16e93a5b-b25f-4aaf-8a38-77375e237879.78e2aeac-6ede-4855-acb1-79a854b5556d" + ] + }, + "Microsoft.WindowsTerminal.Preview": { + "icon": "", + "images": [] + }, + "Microsoft.WindowsVirtualDesktopAge\u2026": { + "icon": "", + "images": [] + }, + "Microsoft.WindowsVirtualDesktopBoo\u2026": { + "icon": "", + "images": [] + }, + "Microsoft.WindowsWDK": { + "icon": "", + "images": [] + }, + "Microsoft.WingetCreate": { + "icon": "", + "images": [] + }, + "Microsoft.XMLNotepad": { + "icon": "", + "images": [] + }, + "Microsoft.XNARedist": { + "icon": "", + "images": [] + }, + "Microstockr.Desktopapp": { + "icon": "", + "images": [] + }, + "MikeFarah.yq": { + "icon": "", + "images": [] + }, + "mikefra.ContosoCookbook": { + "icon": "", + "images": [] + }, + "Mikrotik.TheDude": { + "icon": "", + "images": [] + }, + "MillerPuckette.PureData": { + "icon": "", + "images": [] + }, + "Min.Min": { + "icon": "", + "images": [] + }, + "MindsetInnovationInc.Enowork": { + "icon": "", + "images": [] + }, + "Minecodes.4zur3": { + "icon": "", + "images": [] + }, + "Mingo.Mingo": { + "icon": "", + "images": [] + }, + "MinhLoi.Midterm": { + "icon": "", + "images": [] + }, + "MiniTool.PartitionWizard.Free": { + "icon": "", + "images": [] + }, + "Mintty.WSLtty": { + "icon": "", + "images": [] + }, + "MirandaIM.MirandaIM": { + "icon": "", + "images": [] + }, + "MirandaNG.MirandaNG": { + "icon": "", + "images": [] + }, + "Mirantis.Lens": { + "icon": "", + "images": [] + }, + "Mirasoft.AnyVizCloudAdapter": { + "icon": "https://us.store.codesys.com/media/catalog/product/cache/adefa4dac3229abc7b8dba2f1e919681/i/c/icon_000089_AnyVisz_Cloud_Adapter.png", + "images": [ + "https://www.anyviz.io/wp-content/uploads/2021/09/Cloud-Adapter-News-1024x536.png", + "https://us.store.codesys.com/media/catalog/product/cache/3bdc815eb46cb7b9d94251c144719462/s/c/screen_0_000089_anyvisz_cloud_adapter.png", + "https://res.cloudinary.com/canonical/image/fetch/f_auto,q_auto,fl_sanitize,w_819,h_464/https://dashboard.snapcraft.io/site_media/appmedia/2020/06/UniversalCloudAdapter.PNG", + "https://www.anyviz.io/wp-content/uploads/2019/07/Universal-Cloud-Adapter_UI.png", + "https://res.cloudinary.com/canonical/image/fetch/f_auto,q_auto,fl_sanitize,w_819,h_487/https://dashboard.snapcraft.io/site_media/appmedia/2020/06/Desktop_01.PNG" + ] + }, + "mIRC.mIRC": { + "icon": "", + "images": [] + }, + "Mirillis.Action": { + "icon": "https://mirillis.com/res/images/icons/favicon32.png", + "images": [ + "https://mirillis.com/res/old/media/images/product/action/16-ui_for_users.png", + "https://mirillis.com/res/old/media/images/product/action/new-green_screen.jpg", + "https://mirillis.com/res/old/media/images/product/action/action-device-recording-mode.jpg", + "https://mirillis.com/res/old/media/images/product/action/new-app_record.jpg", + "https://mirillis.com/res/old/media/images/product/action/1-record_gameplay.jpg", + "https://mirillis.com/res/old/media/images/product/action/4-stream_gameplay.jpg", + "https://mirillis.com/res/old/media/images/product/action/11-record_with_4k.jpg", + "https://mirillis.com/res/old/media/images/product/action/7-upload_to_facebok.jpg", + "https://mirillis.com/res/old/media/images/product/action/20-video_playback.jpg" + ] + }, + "Mirillis.SplashUltimate": { + "icon": "", + "images": [] + }, + "Miro.Miro": { + "icon": "", + "images": [] + }, + "MisfitCode.MisfitModel3D": { + "icon": "", + "images": [] + }, + "MisfitCode.MisfitModel3D.dev": { + "icon": "", + "images": [] + }, + "MIT.CertAid": { + "icon": "", + "images": [] + }, + "MITMediaLab.Scratch.3": { + "icon": "", + "images": [] + }, + "mitmproxy.mitmproxy": { + "icon": "", + "images": [] + }, + "MiXXX.MiXXX": { + "icon": "", + "images": [] + }, + "MKLabs.StarUML": { + "icon": "", + "images": [] + }, + "MKProj.Minerva": { + "icon": "", + "images": [] + }, + "mmanela.markdownoutlook": { + "icon": "", + "images": [] + }, + "mmckegg.loopdrop": { + "icon": "", + "images": [] + }, + "MMSOFTDesign.Pulseway": { + "icon": "", + "images": [] + }, + "Mobirise.Mobirise": { + "icon": "", + "images": [] + }, + "Modeliosoft.Modelio": { + "icon": "", + "images": [] + }, + "ModernFlyouts.ModernFlyouts": { + "icon": "https://i.imgur.com/prW4uEK.png", + "images": [] + }, + "ModOrganizer2.modorganizer": { + "icon": "", + "images": [] + }, + "ModuleArt.QuickPictureViewer": { + "icon": "", + "images": [] + }, + "MoheshwarAmarnathBiswas.UsefulTool\u2026": { + "icon": "", + "images": [] + }, + "MoheshwarAmarnathBiswas.YouTubeVid\u2026": { + "icon": "", + "images": [] + }, + "Mojang.MinecraftLauncher": { + "icon": "https://www.minecraft.net/content/dam/games/minecraft/key-art/MC_The-Wild-Update_540x300.jpg", + "images": [ + "https://pics.computerbase.de/1/0/3/7/5/9-e76e0679e4fd11ea/article-1280x720.2cad9186.jpg" + ] + }, + "MolotovTV.Molotov": { + "icon": "", + "images": [] + }, + "MongoDB.Compass.Community": { + "icon": "", + "images": [] + }, + "MongoDB.Compass.Full": { + "icon": "", + "images": [] + }, + "MongoDB.Compass.Isolated": { + "icon": "", + "images": [] + }, + "MongoDB.Compass.Readonly": { + "icon": "", + "images": [] + }, + "MongoDB.DatabaseTools": { + "icon": "", + "images": [] + }, + "MongoDB.MongoDBCLI": { + "icon": "", + "images": [] + }, + "MongoDB.Server": { + "icon": "", + "images": [] + }, + "MongoDB.Shell": { + "icon": "", + "images": [] + }, + "MonkeysAudio.MonkeysAudio": { + "icon": "", + "images": [] + }, + "MonkiLabs.Notejoy": { + "icon": "", + "images": [] + }, + "Mono.gtksharp": { + "icon": "", + "images": [] + }, + "Mono.Mono": { + "icon": "", + "images": [] + }, + "MonoGame.MonoGame": { + "icon": "", + "images": [] + }, + "monsterkodi.clippo": { + "icon": "", + "images": [] + }, + "monsterkodi.kalk": { + "icon": "", + "images": [] + }, + "monsterkodi.kappo": { + "icon": "", + "images": [] + }, + "MoonchildProductions.PaleMoon": { + "icon": "", + "images": [] + }, + "MoonlightGameStreamingProject.Moon\u2026": { + "icon": "", + "images": [] + }, + "Moonsworth.LunarClient": { + "icon": "", + "images": [] + }, + "MoritzBunkus.MKVToolNix": { + "icon": "", + "images": [] + }, + "moshfeu.y2mp3": { + "icon": "", + "images": [] + }, + "MOTU.MSeries": { + "icon": "", + "images": [] + }, + "MoyuScript.DoubleMouseDownloader": { + "icon": "", + "images": [] + }, + "Mozilla.Firefox": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/a/a0/Firefox_logo%2C_2019.svg/800px-Firefox_logo%2C_2019.svg.png", + "images": [ + "https://i.postimg.cc/zBRhkhmQ/Firefox-96-screenshot.png", + "https://upload.wikimedia.org/wikipedia/commons/thumb/1/1f/Capture_d%27%C3%A9cran_de_Mozilla_Firefox_version_100.0.png/1024px-Capture_d%27%C3%A9cran_de_Mozilla_Firefox_version_100.0.png" + ] + }, + "Mozilla.Firefox.Beta": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/8/8c/Firefox_beta_logo.png", + "images": [ + "https://upload.wikimedia.org/wikipedia/commons/thumb/1/1f/Capture_d%27%C3%A9cran_de_Mozilla_Firefox_version_100.0.png/1024px-Capture_d%27%C3%A9cran_de_Mozilla_Firefox_version_100.0.png" + ] + }, + "Mozilla.Firefox.DeveloperEdition": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/3/30/Firefox_Developer_Edition_logo%2C_2019.svg/800px-Firefox_Developer_Edition_logo%2C_2019.svg.png", + "images": [ + "https://upload.wikimedia.org/wikipedia/commons/thumb/1/1f/Capture_d%27%C3%A9cran_de_Mozilla_Firefox_version_100.0.png/1024px-Capture_d%27%C3%A9cran_de_Mozilla_Firefox_version_100.0.pngg" + ] + }, + "Mozilla.Firefox.ESR": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/a/a0/Firefox_logo%2C_2019.svg/800px-Firefox_logo%2C_2019.svg.png", + "images": [ + "https://upload.wikimedia.org/wikipedia/commons/thumb/1/1f/Capture_d%27%C3%A9cran_de_Mozilla_Firefox_version_100.0.png/1024px-Capture_d%27%C3%A9cran_de_Mozilla_Firefox_version_100.0.png" + ] + }, + "Mozilla.Firefox.Nightly": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/b/b4/Firefox_Nightly_logo%2C_2019.svg/800px-Firefox_Nightly_logo%2C_2019.svg.png", + "images": [ + "https://upload.wikimedia.org/wikipedia/commons/thumb/1/1f/Capture_d%27%C3%A9cran_de_Mozilla_Firefox_version_100.0.png/1024px-Capture_d%27%C3%A9cran_de_Mozilla_Firefox_version_100.0.png" + ] + }, + "Mozilla.SeaMonkey": { + "icon": "", + "images": [] + }, + "Mozilla.Thunderbird": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/e/e1/Thunderbird_Logo%2C_2018.svg/langfr-800px-Thunderbird_Logo%2C_2018.svg.png", + "images": [ + "https://upload.wikimedia.org/wikipedia/commons/thumb/3/39/Thunderbird_102_screenshot.png/1024px-Thunderbird_102_screenshot.png" + ] + }, + "Mozilla.Thunderbird.Beta": { + "icon": "", + "images": [] + }, + "Mozilla.VPN": { + "icon": "", + "images": [] + }, + "Mp3tag.Mp3tag": { + "icon": "", + "images": [] + }, + "mRemoteNG.mRemoteNG": { + "icon": "", + "images": [] + }, + "MrMYHuang.cbetar2": { + "icon": "", + "images": [] + }, + "msaltnet.TViewer": { + "icon": "", + "images": [] + }, + "MSI.Kombustor.2": { + "icon": "", + "images": [] + }, + "MSI.Kombustor.3": { + "icon": "", + "images": [] + }, + "MSI.Kombustor.4": { + "icon": "", + "images": [] + }, + "mspearpoint.Evacuationz": { + "icon": "", + "images": [] + }, + "MSYS2.MSYS2": { + "icon": "", + "images": [] + }, + "Mu.Mu": { + "icon": "", + "images": [] + }, + "Mubu.Mubu": { + "icon": "", + "images": [] + }, + "muCommander.muCommander": { + "icon": "", + "images": [] + }, + "muffinista.before-dawn": { + "icon": "", + "images": [] + }, + "MuhammadFareezIqmal.IIUMSchedule": { + "icon": "", + "images": [] + }, + "MuhammedKalkan.OpenLens": { + "icon": "", + "images": [] + }, + "MullvadVPN.MullvadVPN": { + "icon": "", + "images": [] + }, + "Mumble.Mumble.Client": { + "icon": "", + "images": [] + }, + "Mumble.Mumble.Server": { + "icon": "", + "images": [] + }, + "Mupen64.Mupen64": { + "icon": "", + "images": [] + }, + "murgatt.recode-converter": { + "icon": "", + "images": [] + }, + "Musescore.Musescore": { + "icon": "", + "images": [] + }, + "MusicBrainz.Picard": { + "icon": "", + "images": [] + }, + "MyCloudGame.AirGamePlay": { + "icon": "", + "images": [] + }, + "MyCloudGame.AirGameServer": { + "icon": "", + "images": [] + }, + "MyGames.GameCenter": { + "icon": "", + "images": [] + }, + "MyPaint.MyPaint": { + "icon": "", + "images": [] + }, + "MysteriumNetwork.Mysterium": { + "icon": "", + "images": [] + }, + "Mythicsoft.AgentRansack": { + "icon": "", + "images": [] + }, + "n457.uncolored": { + "icon": "", + "images": [] + }, + "naaive.Orange": { + "icon": "", + "images": [] + }, + "Nadeo.TrackManiaNationsForever": { + "icon": "", + "images": [] + }, + "NagleCode.PacketSender": { + "icon": "", + "images": [] + }, + "namazso.OpenHashTab": { + "icon": "", + "images": [] + }, + "NamecoinProject.Electrum-NMC": { + "icon": "", + "images": [] + }, + "NamecoinProject.NamecoinCore": { + "icon": "", + "images": [] + }, + "NartacSoftwareInc.IISCryptoCLI": { + "icon": "", + "images": [] + }, + "NartacSoftwareInc.IISCryptoGUI": { + "icon": "", + "images": [] + }, + "nashaofu.dingtalk": { + "icon": "", + "images": [] + }, + "NASM.NASM": { + "icon": "", + "images": [] + }, + "NathanBeals.WinSSH-Pageant": { + "icon": "", + "images": [] + }, + "nathancorvussolis.corvusskk": { + "icon": "", + "images": [] + }, + "NathanielJohns.Beatdrop": { + "icon": "", + "images": [] + }, + "NathanMoinvaziri.ExtractNow": { + "icon": "", + "images": [] + }, + "NathanOsman.NitroShare": { + "icon": "", + "images": [] + }, + "NativeInstruments.NativeAccess": { + "icon": "", + "images": [] + }, + "Naturalsoft.NaturalReader16": { + "icon": "", + "images": [] + }, + "NAVER.MYBOX": { + "icon": "", + "images": [] + }, + "NAVER.Vaccine": { + "icon": "", + "images": [] + }, + "NCHSoftware.ClassicFTP": { + "icon": "", + "images": [] + }, + "NCHSoftware.Crescendo": { + "icon": "", + "images": [] + }, + "ncyxie.Notepad-DOT-Qt": { + "icon": "", + "images": [] + }, + "NelsonNumericalSoftware.Nelson": { + "icon": "", + "images": [] + }, + "Neotys.NeoLoad": { + "icon": "", + "images": [] + }, + "Neovim.Neovim": { + "icon": "", + "images": [] + }, + "Neovim.Neovim.Nightly": { + "icon": "", + "images": [] + }, + "Nervatura.Nervatura": { + "icon": "", + "images": [] + }, + "netbsd.rawrite32": { + "icon": "", + "images": [] + }, + "NetEase.CloudMusic": { + "icon": "", + "images": [] + }, + "NetEase.IdentityV": { + "icon": "", + "images": [] + }, + "NetEase.IdentityV.CN": { + "icon": "", + "images": [] + }, + "NetEase.MailMaster": { + "icon": "", + "images": [] + }, + "NetEase.MCLauncher": { + "icon": "", + "images": [] + }, + "netless-io.flat": { + "icon": "", + "images": [] + }, + "NetSarangComputer.PortX": { + "icon": "", + "images": [] + }, + "Netstumbler.Netstumbler": { + "icon": "", + "images": [] + }, + "NetSurf.NetSurf": { + "icon": "", + "images": [] + }, + "Neux.OneMark": { + "icon": "", + "images": [] + }, + "Nevcairiel.LAVFilters": { + "icon": "", + "images": [] + }, + "NewBreedSoftware.TuxPaint": { + "icon": "", + "images": [] + }, + "NewsGator.FeedDemon": { + "icon": "", + "images": [] + }, + "NewTek.NDI5Tools": { + "icon": "", + "images": [] + }, + "NewzenMC.NewzenLauncher": { + "icon": "", + "images": [] + }, + "Nextcloud.NextcloudDesktop": { + "icon": "", + "images": [] + }, + "NextDNS.NextDNS.Prerelease": { + "icon": "", + "images": [] + }, + "NexusMods.Vortex": { + "icon": "", + "images": [] + }, + "ngudbhav.lazyType": { + "icon": "", + "images": [] + }, + "ngudbhav.TriCo": { + "icon": "", + "images": [] + }, + "ngudbhav.Webkiosk-Wrapper": { + "icon": "", + "images": [] + }, + "NGWIN.PicPick": { + "icon": "https://picpick.app/static/logo-32ef3f284ce5058bd11263e9796a5606.png", + "images": [ + "https://picpick.app/static/screenshot_6-5e1b3ae39deaa0e864db567987191881.png", + "https://picpick.app/static/screenshot_5-ce960495e0e30e97d983172f9e9b0e7a.png", + "https://picpick.app/static/screenshot_2-fa50c1e8d5b5bdcafdd5e647d467cfac.png" + ] + }, + "NhekoReborn.Nheko": { + "icon": "", + "images": [] + }, + "NHNCorporation.Dooray!Drive": { + "icon": "", + "images": [] + }, + "NHNCorporation.Dooray!Messenger": { + "icon": "", + "images": [] + }, + "NickeManarin.ScreenToGif": { + "icon": "", + "images": [] + }, + "NickGottschlich.SocialAmnesia": { + "icon": "", + "images": [] + }, + "NicolasConstant.sengi": { + "icon": "", + "images": [] + }, + "NicolasRamz.React-Explorer": { + "icon": "", + "images": [] + }, + "Nikkho.FileOptimizer": { + "icon": "", + "images": [] + }, + "nikpapa.palamedes": { + "icon": "", + "images": [] + }, + "Nikse.SubtitleEdit": { + "icon": "", + "images": [] + }, + "Nilesoft.Shell": { + "icon": "", + "images": [] + }, + "nimblenote.nimblenote": { + "icon": "", + "images": [] + }, + "NimbusWeb.NimbusNote": { + "icon": "", + "images": [] + }, + "NIOSH.ARMPS": { + "icon": "", + "images": [] + }, + "NirSoft.BlueScreenView": { + "icon": "", + "images": [] + }, + "NirSoft.DownTester": { + "icon": "", + "images": [] + }, + "NirSoft.IPNetInfo": { + "icon": "", + "images": [] + }, + "NirSoft.NK2Edit": { + "icon": "", + "images": [] + }, + "NirSoft.ShellExView": { + "icon": "", + "images": [] + }, + "NirSoft.VideoCacheView": { + "icon": "", + "images": [] + }, + "NirSoft.Volumouse": { + "icon": "", + "images": [] + }, + "NirSoft.WhoisThisDomain": { + "icon": "", + "images": [] + }, + "NirSoft.WirelessNetworkWatcher": { + "icon": "", + "images": [] + }, + "NishkalKashyap.Quark": { + "icon": "", + "images": [] + }, + "NISZ.KEAASZ": { + "icon": "", + "images": [] + }, + "NitroSoftware.NitroPro": { + "icon": "", + "images": [] + }, + "Nlitesoft.NTLite": { + "icon": "", + "images": [] + }, + "NLM.Wiser": { + "icon": "", + "images": [] + }, + "NLnetLabs.Unbound": { + "icon": "https://i.imgur.com/tM3e83k.png", + "images": [] + }, + "NOAA.CAMEOChemicals": { + "icon": "", + "images": [] + }, + "nodemailer.nodemailer": { + "icon": "", + "images": [] + }, + "Nodist.Nodist": { + "icon": "", + "images": [] + }, + "NoIP.DUC": { + "icon": "", + "images": [] + }, + "nojsja.ShadowsocksElectron": { + "icon": "", + "images": [] + }, + "NoMachine.NoMachine": { + "icon": "", + "images": [] + }, + "NoMachine.NoMachineClient": { + "icon": "", + "images": [] + }, + "nomacs.nomacs": { + "icon": "", + "images": [] + }, + "NoMoreFood.PuTTY-CAC": { + "icon": "", + "images": [] + }, + "Nord.NordLocker": { + "icon": "", + "images": [] + }, + "NordPassTeam.NordPass": { + "icon": "", + "images": [] + }, + "NordVPN.NordVPN": { + "icon": "", + "images": [] + }, + "NoSQLBooster.NoSQLBooster": { + "icon": "", + "images": [] + }, + "Nota.Gyazo": { + "icon": "", + "images": [] + }, + "notable.notable": { + "icon": "", + "images": [] + }, + "Notepad++.Notepad++": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/f/f5/Notepad_plus_plus.png", + "images": [ + "https://notepadplusapp.com/images/uploads/2021-05-18/m0St1R0-r0qya.png", + "https://notepadplusapp.com/images/uploads/2021-05-18/notepad-screenshot-dt5y5.png", + "https://notepadplusapp.com/images/uploads/2021-05-18/screenshot02-0xo1j.jpg" + ] + }, + "Notepad2mod.Notepad2mod": { + "icon": "", + "images": [] + }, + "Notion.Notion": { + "icon": "https://i.imgur.com/J4xCzCy.png", + "images": [] + }, + "NotionRepackaged.NotionEnhanced": { + "icon": "", + "images": [] + }, + "Novaquark.DualUniverse": { + "icon": "", + "images": [] + }, + "NovaTechnology.Beeper": { + "icon": "", + "images": [] + }, + "Novicon.Munixo.Client": { + "icon": "", + "images": [] + }, + "NOWTV.NOWTVPlayer": { + "icon": "", + "images": [] + }, + "Nozbe.NozbePersonal": { + "icon": "", + "images": [] + }, + "nrittsti.NTag": { + "icon": "", + "images": [] + }, + "NSIS.NSIS": { + "icon": "", + "images": [] + }, + "nteract.nteract": { + "icon": "", + "images": [] + }, + "NTWindSoftware.VisualSubst": { + "icon": "", + "images": [] + }, + "NTWindSoftware.WinCam": { + "icon": "", + "images": [] + }, + "nukeop.nuclear": { + "icon": "", + "images": [] + }, + "Nulana.Remotix": { + "icon": "", + "images": [] + }, + "nulldev.ProfileSwitcherforFirefox": { + "icon": "", + "images": [] + }, + "Nullpomino.Nullpomino": { + "icon": "", + "images": [] + }, + "NumeRe.NumeRe": { + "icon": "", + "images": [] + }, + "NurgoSoftware.AquaSnap": { + "icon": "https://static.techspot.com/images2/downloads/topdownload/2014/11/aquasnap.png", + "images": [ + "https://i.ytimg.com/vi/bOVOEebpiWc/maxresdefault.jpg", + "https://i.ytimg.com/vi/_x2fj7JIuzE/maxresdefault.jpg", + "https://getintopc.today/wp-content/uploads/2021/10/Aquasnap.jpg", + "https://www.nurgo-software.com/images/AquaSnap/Docking.gif", + "https://www.nurgo-software.com/images/AquaSnap/AquaShake.gif" + ] + }, + "Nushell.Nushell": { + "icon": "", + "images": [] + }, + "Nutstore.Nutstore": { + "icon": "", + "images": [] + }, + "Nutstore.NutstoreLightApp": { + "icon": "", + "images": [] + }, + "nuttyartist.notes": { + "icon": "", + "images": [] + }, + "NVAccess.NVDA": { + "icon": "", + "images": [] + }, + "Nvidia.Broadcast": { + "icon": "", + "images": [] + }, + "Nvidia.CUDA": { + "icon": "", + "images": [] + }, + "Nvidia.GeForceExperience": { + "icon": "", + "images": [] + }, + "Nvidia.GeForceNow": { + "icon": "", + "images": [] + }, + "Nvidia.PhysX": { + "icon": "", + "images": [] + }, + "Nvidia.PhysXLegacy": { + "icon": "", + "images": [] + }, + "Nvidia.RTXVoice": { + "icon": "", + "images": [] + }, + "Nvidia.VideoEffectsSDK.20xx-Turing": { + "icon": "", + "images": [] + }, + "nvisionative.nvQuickSite": { + "icon": "", + "images": [] + }, + "NxShellTeam.NxShell": { + "icon": "", + "images": [] + }, + "nzbget.nzbget": { + "icon": "", + "images": [] + }, + "NZXT.CAM": { + "icon": "", + "images": [] + }, + "o2sh.onefetch": { + "icon": "", + "images": [] + }, + "ObinsKit.ObinsKit": { + "icon": "", + "images": [] + }, + "Obsidian.Obsidian": { + "icon": "", + "images": [] + }, + "OBSProject.obs-amd-encoder": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/d/d3/OBS_Studio_Logo.svg/768px-OBS_Studio_Logo.svg.png", + "images": [ + "http://i.imgur.com/Fferqsd.png" + ] + }, + "OBSProject.OBSStudio": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/d/d3/OBS_Studio_Logo.svg/512px-OBS_Studio_Logo.svg.png", + "images": [ + "https://obsproject.com/assets/images/features-new/hero.png" + ] + }, + "OBSProject.OBSStudio.Pre-release": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/d/d3/OBS_Studio_Logo.svg/512px-OBS_Studio_Logo.svg.png", + "images": [] + }, + "OctopusDeploy.Server": { + "icon": "", + "images": [] + }, + "OctopusDeploy.Tentacle": { + "icon": "", + "images": [] + }, + "ogdesign.Eagle": { + "icon": "", + "images": [] + }, + "OISF.Suricata": { + "icon": "", + "images": [] + }, + "ojdkbuild.ojdkbuild": { + "icon": "", + "images": [] + }, + "ojdkbuild.openjdk.11.jdk": { + "icon": "", + "images": [] + }, + "ojdkbuild.openjdk.11.jre": { + "icon": "", + "images": [] + }, + "ojdkbuild.openjdk.13.jdk": { + "icon": "", + "images": [] + }, + "ojdkbuild.openjdk.14.jdk": { + "icon": "", + "images": [] + }, + "ojdkbuild.openjdk.17.jdk": { + "icon": "", + "images": [] + }, + "ojdkbuild.openjdk.17.jre": { + "icon": "", + "images": [] + }, + "OlavSortlandThoresen.ScreenCloud": { + "icon": "", + "images": [] + }, + "oldj.switchhosts": { + "icon": "", + "images": [] + }, + "OlegDanilov.RapidEnvironmentEditor": { + "icon": "", + "images": [] + }, + "OlegShparber.Zeal": { + "icon": "", + "images": [] + }, + "OleguerLlopart.OpenComic": { + "icon": "", + "images": [] + }, + "OliverBetz.ExifTool": { + "icon": "", + "images": [] + }, + "OliverSchwendener.ueli": { + "icon": "", + "images": [] + }, + "OliveTeam.OliveVideoEditor": { + "icon": "", + "images": [] + }, + "Olivia.VIA": { + "icon": "", + "images": [] + }, + "Ombrelin.PandocGui": { + "icon": "", + "images": [] + }, + "Ombrelin.PlexRichPresence": { + "icon": "", + "images": [] + }, + "OmicronLab.Avro": { + "icon": "https://okkhor52.com/img/designer/001.png", + "images": [ + "https://www.omicronlab.com/assets/images/landing/avro_600x337.jpg", + "http://linux.omicronlab.com/images/screenshot.png", + "https://imag.malavida.com/mvimgbig/download-fs/avro-keyboard-22346-1.jpg" + ] + }, + "OmsiLauncher.OmsiLauncher": { + "icon": "", + "images": [] + }, + "OndrejSalplachta.AdvancedLogViewer": { + "icon": "https://windows-cdn.softpedia.com/screenshots/ico/ALV-Advanced-Log-Viewer.gif", + "images": [ + "https://windows-cdn.softpedia.com/screenshots/ALV-Advanced-Log-Viewer_1.png", + "https://windows-cdn.softpedia.com/screenshots/ALV-Advanced-Log-Viewer_2.png", + "https://windows-cdn.softpedia.com/screenshots/ALV-Advanced-Log-Viewer_3.png", + "https://windows-cdn.softpedia.com/screenshots/ALV-Advanced-Log-Viewer_4.png", + "https://windows-cdn.softpedia.com/screenshots/ALV-Advanced-Log-Viewer_5.png", + "https://windows-cdn.softpedia.com/screenshots/ALV-Advanced-Log-Viewer_6.png" + ] + }, + "OneGal.Viper": { + "icon": "", + "images": [] + }, + "OneKey.OneKey": { + "icon": "", + "images": [] + }, + "OneScript.OneScript": { + "icon": "", + "images": [] + }, + "OnionShare.OnionShare": { + "icon": "", + "images": [] + }, + "OnionShare.OnionShare.Dev": { + "icon": "", + "images": [] + }, + "OnlineMediaTechnologiesLtd.AVSDisc\u2026": { + "icon": "", + "images": [] + }, + "ONLYOFFICE.DesktopEditors": { + "icon": "https://i.imgur.com/LZh4v4l.png", + "images": [] + }, + "OO-Software.ShutUp10": { + "icon": "", + "images": [] + }, + "Ookla.Speedtest": { + "icon": "", + "images": [] + }, + "OPAutoClicker.OPAutoClicker": { + "icon": "", + "images": [] + }, + "Open-Shell.Open-Shell-Menu": { + "icon": "", + "images": [ + "https://i.postimg.cc/mZCMz7yz/startmenu3.png" + ] + }, + "open-source-labs.ReacType": { + "icon": "", + "images": [] + }, + "OpenDesignAlliance.ODAFileConverter": { + "icon": "", + "images": [] + }, + "OpenEducationFoundation.OpenBoard": { + "icon": "", + "images": [] + }, + "OpenJS.NodeJS": { + "icon": "", + "images": [] + }, + "OpenJS.NodeJS.LTS": { + "icon": "", + "images": [] + }, + "OpenJS.NodeJS.Nightly": { + "icon": "", + "images": [] + }, + "OpenLiveWriter.OpenLiveWriter": { + "icon": "", + "images": [] + }, + "OpenLPDevelopers.OpenLP": { + "icon": "", + "images": [] + }, + "OpenMedia.4KSlideshowMaker": { + "icon": "https://img.informer.com/icons_mac/png/128/546/546469.png", + "images": [ + "https://static.4kdownload.com/main/img/redesign-v2/products-page/slideshowmaker/promo-main.png", + "https://static.4kdownload.com/main/img/redesign/product-screenshots/cards/new-cards/slideshowmaker-card@1x.webp", + "https://static.4kdownload.com/main/img/redesign-v2/products-page/slideshowmaker/quality@1x.png" + ] + }, + "OpenMedia.4KStogram": { + "icon": "http://static.4kdownload.com/main/img/logo/stogram-256.732811102182.png", + "images": [ + "https://static.4kdownload.com/main/img/redesign/product-screenshots/cards/new-cards/stogram-card@1x.png", + "https://static.4kdownload.com/main/img/redesign-v2/products-page/stogram/download@1x.png" + ] + }, + "OpenMedia.4KTokkit": { + "icon": "http://static.4kdownload.com/main/img/logo/tokkit-512.c09c7b19c607.png", + "images": [ + "https://static.4kdownload.com/main/img/redesign/product-screenshots/cards/new-cards/tokkit-card@1x.png", + "https://static.4kdownload.com/main/img/redesign-v2/products-page/tokkit/download-tiktok-hashtag.07a06cb13a1b.png" + ] + }, + "OpenMedia.4KVideoDownloader": { + "icon": "http://static.4kdownload.com/main/img/logo/videodownloader-512.7395df698c5e.png", + "images": [ + "https://static.4kdownload.com/main/img/redesign/product-screenshots/cards/new-cards/videodownloader-card@1x.png", + "https://static.4kdownload.com/main/img/redesign/product-screenshots/windows/videodownloader/playlist.png" + ] + }, + "OpenMedia.4KVideoToMP3": { + "icon": "", + "images": [ + "https://static.4kdownload.com/main/img/redesign/product-screenshots/cards/new-cards/videotomp3-card@1x.png", + "https://static.4kdownload.com/main/img/redesign-v2/products-page/videotomp3/import@1x.png" + ] + }, + "OpenMedia.4KYoutubetoMP3": { + "icon": "https://dl2.macupdate.com/images/icons256/45833.png?time=1662981249", + "images": [ + "https://static.4kdownload.com/main/img/redesign/product-screenshots/cards/new-cards/youtubetomp3-card@1x.png", + "https://static.4kdownload.com/main/img/redesign-v2/products-page/youtubetomp3/playlist@1x.png" + ] + }, + "OpenMPT.OpenMPT": { + "icon": "", + "images": [] + }, + "OpenNoteBlockStudio.MinecraftNoteB\u2026": { + "icon": "", + "images": [] + }, + "OpenOrienteering.Mapper": { + "icon": "", + "images": [] + }, + "OpenOSRS.OpenOSRSLauncher": { + "icon": "", + "images": [] + }, + "OpenRA.OpenRA": { + "icon": "", + "images": [] + }, + "OpenRCT2.OpenRCT2": { + "icon": "", + "images": [] + }, + "OpenRPAApS.OpenRPA": { + "icon": "", + "images": [] + }, + "OpenSCAD.OpenSCAD": { + "icon": "", + "images": [] + }, + "OpenShopChannel.Downloader": { + "icon": "", + "images": [] + }, + "OpenShot.OpenShot": { + "icon": "", + "images": [] + }, + "OpenSight.FlashFXP": { + "icon": "", + "images": [] + }, + "OpenSource.Grisbi": { + "icon": "", + "images": [] + }, + "OpenSourcePhysics.Tracker": { + "icon": "", + "images": [] + }, + "OpenStenoProject.Plover": { + "icon": "", + "images": [] + }, + "OpenStreetMap.Josm": { + "icon": "", + "images": [] + }, + "OpenTTD.OpenTTD": { + "icon": "", + "images": [] + }, + "OpenVPNTechnologies.OpenVPN": { + "icon": "", + "images": [] + }, + "OpenVPNTechnologies.OpenVPNConnect": { + "icon": "", + "images": [] + }, + "OpenWhisperSystems.Signal": { + "icon": "", + "images": [] + }, + "OpenWhisperSystems.Signal.Beta": { + "icon": "", + "images": [] + }, + "Opera.Opera": { + "icon": "", + "images": [] + }, + "Opera.Opera.Beta": { + "icon": "", + "images": [] + }, + "Opera.OperaGX": { + "icon": "", + "images": [] + }, + "opticos.gwsl": { + "icon": "", + "images": [] + }, + "opticos.openinwsl": { + "icon": "", + "images": [] + }, + "Oracle.JavaRuntimeEnvironment": { + "icon": "https://www.eclipse.org/xtend/images/java8_logo.png", + "images": [] + }, + "Oracle.JDK.17": { + "icon": "", + "images": [] + }, + "Oracle.JDK.18": { + "icon": "", + "images": [] + }, + "Oracle.JDK.19": { + "icon": "", + "images": [] + }, + "Oracle.MySQL": { + "icon": "", + "images": [] + }, + "Oracle.MySQLNotifier": { + "icon": "", + "images": [] + }, + "Oracle.VirtualBox": { + "icon": "", + "images": [] + }, + "Orange-OpenSource.Hurl": { + "icon": "", + "images": [] + }, + "OrangeDrangon.AndroidMessages.Desk\u2026": { + "icon": "", + "images": [] + }, + "OrangeNote.RuneBook": { + "icon": "", + "images": [] + }, + "OrbxSimulationSystems.OrbxCentral": { + "icon": "", + "images": [] + }, + "OrbxSimulationSystems.Volanta": { + "icon": "", + "images": [] + }, + "Orwell.Dev-C++": { + "icon": "", + "images": [] + }, + "osara.osara": { + "icon": "", + "images": [] + }, + "OSGeo.GeoServer": { + "icon": "", + "images": [] + }, + "OSGeo.QGIS": { + "icon": "", + "images": [] + }, + "OSGeo.QGIS_LTR": { + "icon": "", + "images": [] + }, + "OsirisDevelopment.BatteryBar": { + "icon": "https://i.imgur.com/3swIrxK.png", + "images": [ + "https://batterybarpro.com/images/splash1.png", + "https://batterybarpro.com/images/features.png", + "https://batterybarpro.com/images/features1.png" + ] + }, + "osk.tetr": { + "icon": "", + "images": [] + }, + "OSSEC.OSSECAgent": { + "icon": "", + "images": [] + }, + "OtterBrowserTeam.OtterBrowser": { + "icon": "", + "images": [] + }, + "Ottomated.CrewLink": { + "icon": "", + "images": [] + }, + "Outertech.GetDiz": { + "icon": "", + "images": [] + }, + "OutsourcedGuru.octopi-init": { + "icon": "", + "images": [] + }, + "OV2.RapidCRCUnicode": { + "icon": "", + "images": [] + }, + "Ovenoboyo.Moosync": { + "icon": "", + "images": [] + }, + "Overwolf.CurseForge": { + "icon": "", + "images": [] + }, + "ovital.OmapRevitPlugin": { + "icon": "", + "images": [] + }, + "ovito.ovito-basic": { + "icon": "", + "images": [] + }, + "ovito.ovito-pro": { + "icon": "", + "images": [] + }, + "OVRASTeam.OpenVR-AdvancedSettings": { + "icon": "", + "images": [] + }, + "OwlPlug.OwlPlug": { + "icon": "", + "images": [] + }, + "ownCloud.ownCloudDesktop": { + "icon": "", + "images": [] + }, + "Oxen.Session": { + "icon": "", + "images": [] + }, + "OxfordUniversityPressELT.OxfordLea\u2026": { + "icon": "", + "images": [] + }, + "OxygenCloud.odrive": { + "icon": "", + "images": [] + }, + "oxygendioxide.Deepvocal-Hitsuboku-\u2026": { + "icon": "", + "images": [] + }, + "oxygendioxide.utaformatix": { + "icon": "", + "images": [] + }, + "ozankaraali.PiTV": { + "icon": "", + "images": [] + }, + "OzMartian.VidCutter": { + "icon": "", + "images": [] + }, + "PacketStreamTeam.PacketStream": { + "icon": "", + "images": [] + }, + "PaddiM8.kalker": { + "icon": "", + "images": [] + }, + "Paessler.PRTGDesktop": { + "icon": "", + "images": [] + }, + "Panic.PlaydateSDK": { + "icon": "", + "images": [] + }, + "PaodingAI.Calliper": { + "icon": "", + "images": [] + }, + "PaodingAI.PDFlux": { + "icon": "", + "images": [] + }, + "PaodingAI.Scriber": { + "icon": "", + "images": [] + }, + "paologiuaa.Tilde": { + "icon": "", + "images": [] + }, + "PaperCutSoftware.MobilityPrint": { + "icon": "", + "images": [] + }, + "PaperCutSoftware.NG": { + "icon": "", + "images": [] + }, + "PaprikaApp.Paprika.1": { + "icon": "", + "images": [] + }, + "PaprikaApp.Paprika.3": { + "icon": "", + "images": [] + }, + "ParadoxInteractive.ParadoxLauncher": { + "icon": "", + "images": [] + }, + "Paragon.APFS": { + "icon": "https://i.imgur.com/zd6eSy1.png", + "images": [ + "https://filecr.com/wp-content/uploads/2019/06/Paragon-APFS-for-Windows-Free-Download.jpg", + "https://www.paragon-software.com/wp-content/uploads/2018/06/Volumes_sample1.png", + "https://www.paragon-software.com/wp-content/uploads/2018/06/File_transfer_sample.png", + "https://techsviewer.com/wp-content/uploads/2019/08/Read-and-Write-Mac-Drive-on-Windows.jpg", + "https://techsviewer.com/wp-content/uploads/2019/08/APFS-for-Windows-by-Paragon.jpg" + ] + }, + "Paragon.HFS+": { + "icon": "", + "images": [] + }, + "Paragon.LinuxFileSystems": { + "icon": "", + "images": [] + }, + "Paragon.ParagonBackupRecoveryCE": { + "icon": "", + "images": [] + }, + "Parallels.Parallels": { + "icon": "", + "images": [] + }, + "Parsec.Parsec": { + "icon": "", + "images": [] + }, + "PascalBerger.MSIXCommander": { + "icon": "", + "images": [] + }, + "Passcovery.PasscoverySuite": { + "icon": "", + "images": [] + }, + "PassMark.BatteryMon": { + "icon": "", + "images": [] + }, + "PassMark.DiskCheckup": { + "icon": "", + "images": [] + }, + "PassmarkSoftware.Fragger": { + "icon": "", + "images": [] + }, + "PassmarkSoftware.OSFMount": { + "icon": "", + "images": [] + }, + "PassmarkSoftware.SoundCheck": { + "icon": "", + "images": [] + }, + "PatchMyPC.PatchMyPC": { + "icon": "", + "images": [] + }, + "PatentLobster.stinker": { + "icon": "", + "images": [] + }, + "PathofBuildingCommunity.PathofBuil\u2026": { + "icon": "", + "images": [] + }, + "PatrickMortara.WIA-Loader": { + "icon": "", + "images": [] + }, + "PatrickSiegler.PrismatikUnofficial": { + "icon": "", + "images": [] + }, + "PatrickWaweru.FLBMusic": { + "icon": "", + "images": [] + }, + "PatrikLaszlo.P3XRedisUI": { + "icon": "", + "images": [] + }, + "PaulFrazee.BeakerBrowser": { + "icon": "https://github.com/beakerbrowser/beaker/raw/master/build/icons/256x256.png", + "images": [ + "https://itsfoss.com/wp-content/uploads/2020/04/beaker-browser.jpg", + "https://itsfoss.com/wp-content/uploads/2020/04/beaker-bowser-setting.jpg", + "https://itsfoss.com/wp-content/uploads/2020/04/beaker-bowser-seedding.jpg", + "https://itsfoss.com/wp-content/uploads/2020/04/beaker-browser-menu.jpg", + "https://itsfoss.com/wp-content/uploads/2020/04/beaker-browser-website-template.jpg" + ] + }, + "PaulSori.mStreamServer": { + "icon": "", + "images": [] + }, + "PaulWoolcock.SyncOutlookandGooglec\u2026": { + "icon": "", + "images": [] + }, + "pavlobu.deskreen": { + "icon": "", + "images": [] + }, + "PawelPsztyc.AdvancedRestClient": { + "icon": "https://i.imgur.com/wi1FDBh.png", + "images": [ + "https://img.thinstallsoft.com/2020/10/Advanced-REST-Client-Portable.png", + "https://www.geckoandfly.com/wp-content/uploads/2019/05/advance-rest.jpg" + ] + }, + "PCGen.PCGen": { + "icon": "", + "images": [] + }, + "PDFArranger.PDFArranger": { + "icon": "", + "images": [] + }, + "pdfforge.PDFCreator": { + "icon": "", + "images": [] + }, + "PDFLabs.PDFtk.Free": { + "icon": "", + "images": [] + }, + "PDFLabs.PDFtk.Server": { + "icon": "", + "images": [] + }, + "PDFsam.PDFsam": { + "icon": "", + "images": [] + }, + "PenguinLabs.Cacher": { + "icon": "", + "images": [] + }, + "PeppermindSystemse.K.PioneerDesk-N\u2026": { + "icon": "", + "images": [] + }, + "Peppy.Osu!": { + "icon": "", + "images": [] + }, + "PerAmundsen.AdiIRC": { + "icon": "https://www.irchelp.org/clients/windows/adiirc_logo_256p.png", + "images": [ + "https://www.adiirc.com/images/xss.png.pagespeed.ic.goVp15eGFq.png", + "http://i.imgur.com/R7PYXze.png", + "https://www.irchelp.org/clients/windows/adiirc_screenshot_hackergreen.png", + "https://dev.adiirc.com/attachments/download/790/Monitoring_Panels_02.gif" + ] + }, + "PerfectWorld.SteamChina": { + "icon": "", + "images": [] + }, + "Perforce.P4Merge": { + "icon": "", + "images": [] + }, + "Perforce.P4V": { + "icon": "", + "images": [] + }, + "PersepolisDownloadManager.Persepol\u2026": { + "icon": "", + "images": [] + }, + "PersistenceOfVisionRaytracer.POVRay": { + "icon": "", + "images": [] + }, + "PeterBClements.QuickPar": { + "icon": "", + "images": [] + }, + "PeterBienstman.Mnemosyne": { + "icon": "", + "images": [] + }, + "PeterDaveHello.TransmissionRemoteG\u2026": { + "icon": "", + "images": [] + }, + "PeterPawlowski.foobar2000": { + "icon": "", + "images": [] + }, + "PeterStrick.ViVeTool-GUI": { + "icon": "", + "images": [] + }, + "Pext.Pext": { + "icon": "", + "images": [] + }, + "PFOJEnterprisesLLC.ModernCSV": { + "icon": "", + "images": [] + }, + "PhilipGerke.Odassey": { + "icon": "", + "images": [] + }, + "Philips.HueSync": { + "icon": "", + "images": [] + }, + "Phoenix.TheWorld": { + "icon": "", + "images": [] + }, + "PHOENIXstudios.PC_DIMMER": { + "icon": "", + "images": [] + }, + "PhonePresenter.PhonePresenter": { + "icon": "", + "images": [] + }, + "Phoner.PhonerLite": { + "icon": "", + "images": [] + }, + "Phonero.PersonligSentralbord": { + "icon": "", + "images": [] + }, + "PhraseExpress.PhraseExpress": { + "icon": "", + "images": [] + }, + "PicGo.PicGo": { + "icon": "", + "images": [] + }, + "PicGo.PicGo.Beta": { + "icon": "", + "images": [] + }, + "Picorims.wav2bar": { + "icon": "", + "images": [] + }, + "PicoTorrent.PicoTorrent": { + "icon": "", + "images": [] + }, + "picturama.picturama": { + "icon": "", + "images": [] + }, + "Pidgin.Pidgin": { + "icon": "", + "images": [] + }, + "Pierre.Museeks": { + "icon": "", + "images": [] + }, + "PilotEdge.MSFSclient": { + "icon": "", + "images": [] + }, + "Pinta.Pinta": { + "icon": "", + "images": [] + }, + "PioneerDevelopers.Pioneer": { + "icon": "", + "images": [] + }, + "Piriform.CCleaner": { + "icon": "https://upload.wikimedia.org/wikipedia/en/4/4a/CCleaner_logo_2013.png", + "images": [] + }, + "Piriform.CCleaner.ProTrial": { + "icon": "https://upload.wikimedia.org/wikipedia/en/4/4a/CCleaner_logo_2013.png", + "images": [] + }, + "Piriform.Defraggler": { + "icon": "", + "images": [] + }, + "Piriform.Recuva": { + "icon": "", + "images": [] + }, + "Piriform.Speccy": { + "icon": "", + "images": [] + }, + "PirinelLtd.GitBlade": { + "icon": "", + "images": [] + }, + "pit-ray.win-vind": { + "icon": "", + "images": [] + }, + "pixel-point.kube-forwarder": { + "icon": "", + "images": [] + }, + "PKI.NCALayer": { + "icon": "", + "images": [] + }, + "pku.gateway": { + "icon": "", + "images": [] + }, + "Playnite.Playnite": { + "icon": "", + "images": [] + }, + "PlayStation.DualSenseFWUpdater": { + "icon": "", + "images": [] + }, + "PlayStation.PSPlus": { + "icon": "", + "images": [] + }, + "PlayStation.PSRemotePlay": { + "icon": "", + "images": [] + }, + "Plex.Plex": { + "icon": "", + "images": [] + }, + "Plex.Plexamp": { + "icon": "", + "images": [] + }, + "Plex.PlexMediaPlayer": { + "icon": "", + "images": [] + }, + "Plex.PlexMediaServer": { + "icon": "", + "images": [] + }, + "plogue.alterego": { + "icon": "", + "images": [] + }, + "plogue.chipspeech": { + "icon": "", + "images": [] + }, + "PlotSoft.PDFill": { + "icon": "", + "images": [] + }, + "pnpm.pnpm": { + "icon": "", + "images": [] + }, + "poetries.yuqing-monitor-electron": { + "icon": "", + "images": [] + }, + "PointPlanck.FileBot": { + "icon": "", + "images": [] + }, + "PokerTH.PokerTH": { + "icon": "", + "images": [] + }, + "Polar.Polar": { + "icon": "", + "images": [] + }, + "PolarGoose.CoffeeBean": { + "icon": "", + "images": [] + }, + "Poly.PlantronicsHub": { + "icon": "", + "images": [] + }, + "poooi.poi": { + "icon": "", + "images": [] + }, + "PopcornTime.Popcorn-Time": { + "icon": "", + "images": [] + }, + "PopcornTime.Popcorn-Time-Ru": { + "icon": "", + "images": [] + }, + "POQDavid.PotatoWall": { + "icon": "", + "images": [] + }, + "PortSwigger.BurpSuite.Community": { + "icon": "", + "images": [] + }, + "PortSwigger.BurpSuite.Professional": { + "icon": "", + "images": [] + }, + "Postbox.Postbox": { + "icon": "", + "images": [] + }, + "PostgreSQL.pgAdmin": { + "icon": "", + "images": [] + }, + "PostgreSQL.PostgreSQL": { + "icon": "", + "images": [] + }, + "Postimage.Postimage": { + "icon": "", + "images": [] + }, + "Postman.Postman": { + "icon": "", + "images": [] + }, + "Postman.Postman.Canary": { + "icon": "", + "images": [] + }, + "Postman.Postman.DesktopAgent": { + "icon": "", + "images": [] + }, + "PowerClouds.CertoNiuchacz": { + "icon": "", + "images": [] + }, + "PowerSoftware.AnyBurn": { + "icon": "https://1.bp.blogspot.com/-U3q46Zq8h-w/XyhkYlQ8j_I/AAAAAAAAB9U/cJDXuo1SSFw3EUlEr0kVvQiOoEj-EqjygCLcBGAsYHQ/s750/anyburn.png", + "images": [ + "https://kubadownload.com/site/assets/files/1732/anyburn-1.png", + "https://cdn.neow.in/news/images/uploaded/2016/03/freeanyburn.jpg" + ] + }, + "PowerSoftware.PowerISO": { + "icon": "", + "images": [] + }, + "PowTools.FileShredder": { + "icon": "", + "images": [] + }, + "PPSSPPTeam.PPSSPP": { + "icon": "", + "images": [] + }, + "PragmaTwice.proxinject": { + "icon": "", + "images": [] + }, + "PremiumSoft.NavicatPremium": { + "icon": "", + "images": [] + }, + "PrestonN.FreeTube": { + "icon": "", + "images": [] + }, + "PrestoSoft.ExamDiff": { + "icon": "", + "images": [] + }, + "Pretix.PretixSCAN": { + "icon": "", + "images": [] + }, + "Prey.Prey": { + "icon": "", + "images": [] + }, + "Prezi.PreziClassic": { + "icon": "", + "images": [] + }, + "PrimateLabs.Geekbench.4": { + "icon": "", + "images": [] + }, + "PrimateLabs.Geekbench.5": { + "icon": "", + "images": [] + }, + "Primecount.Primecount": { + "icon": "", + "images": [] + }, + "Primesieve.Primesieve": { + "icon": "", + "images": [] + }, + "Principle.Lusun": { + "icon": "", + "images": [] + }, + "printfn.fend": { + "icon": "", + "images": [] + }, + "PrismLauncher.PrismLauncher": { + "icon": "", + "images": [] + }, + "PrivadoNetworksAG.PrivadoVPN": { + "icon": "", + "images": [] + }, + "PrivateInternetAccess.PrivateInter\u2026": { + "icon": "", + "images": [] + }, + "ProaData.B2BClient": { + "icon": "", + "images": [] + }, + "Project64.Project64": { + "icon": "", + "images": [] + }, + "Project64.Project64.Dev": { + "icon": "", + "images": [] + }, + "Prometheus.WMIExporter": { + "icon": "", + "images": [] + }, + "ProsoftEngineering.DataRescue": { + "icon": "", + "images": [] + }, + "ProtonTechnologies.ProtonMailBridge": { + "icon": "", + "images": [] + }, + "ProtonTechnologies.ProtonVPN": { + "icon": "", + "images": [ + "https://i.postimg.cc/2yQBsfSF/windows-ovpn-9-1024x616.png" + ] + }, + "Prowise.ProwisePresenter": { + "icon": "", + "images": [] + }, + "ProwiseB.V.ProwiseReflect": { + "icon": "", + "images": [] + }, + "Prusa3D.PrusaSlicer": { + "icon": "", + "images": [] + }, + "PS.KubeDevDashboard": { + "icon": "", + "images": [] + }, + "Psenix.OverlayTimer": { + "icon": "", + "images": [] + }, + "PTRTECH.UVtools": { + "icon": "", + "images": [] + }, + "PuloversMacroCreator.PuloversMacro\u2026": { + "icon": "", + "images": [] + }, + "pulsardev.netsix": { + "icon": "", + "images": [] + }, + "pulsejet.edgeandbingdeflector": { + "icon": "", + "images": [] + }, + "Pulumi.Pulumi": { + "icon": "", + "images": [] + }, + "PunkLabs.RocketDock": { + "icon": "", + "images": [] + }, + "Puppet.pdk": { + "icon": "", + "images": [] + }, + "Puppet.puppet-agent": { + "icon": "", + "images": [] + }, + "Puppet.puppet-bolt": { + "icon": "", + "images": [] + }, + "PuranSoftware.PuranFileRecovery": { + "icon": "", + "images": [] + }, + "purocean.YankNote": { + "icon": "", + "images": [] + }, + "PurpleI2P.i2pd": { + "icon": "", + "images": [] + }, + "Pushbullet.Pushbullet": { + "icon": "", + "images": [] + }, + "PushPlayLabs.Sidekick": { + "icon": "", + "images": [] + }, + "PuTTY.PuTTY": { + "icon": "", + "images": [] + }, + "PvPLounge.PvPLounge": { + "icon": "", + "images": [] + }, + "pyfa.pyfa": { + "icon": "", + "images": [] + }, + "PYPrime.PYPrime": { + "icon": "", + "images": [] + }, + "Python.Python.2": { + "icon": "", + "images": [] + }, + "Python.Python.3.0": { + "icon": "", + "images": [] + }, + "Python.Python.3.1": { + "icon": "", + "images": [] + }, + "Python.Python.3.10": { + "icon": "", + "images": [ + "https://i.postimg.cc/NFqHC0Bj/Python-IDLE.png" + ] + }, + "Python.Python.3.11": { + "icon": "", + "images": [] + }, + "Python.Python.3.2": { + "icon": "", + "images": [] + }, + "Python.Python.3.3": { + "icon": "", + "images": [] + }, + "Python.Python.3.4": { + "icon": "", + "images": [] + }, + "Python.Python.3.5": { + "icon": "", + "images": [] + }, + "Python.Python.3.6": { + "icon": "", + "images": [] + }, + "Python.Python.3.7": { + "icon": "", + "images": [] + }, + "Python.Python.3.8": { + "icon": "", + "images": [] + }, + "Python.Python.3.9": { + "icon": "", + "images": [] + }, + "Qalculate.Qalculate": { + "icon": "", + "images": [] + }, + "qBittorrent.qBittorrent": { + "icon": "https://i.imgur.com/k5VTeab.png", + "images": [ + "https://i.postimg.cc/s2bQ12B4/QBittorrent-4-3-9-screenshot.png" + ] + }, + "qier222.yesplaymusic": { + "icon": "", + "images": [] + }, + "Qingfeng.HeyboxAccelerator": { + "icon": "", + "images": [] + }, + "Qingfeng.HeyboxWow": { + "icon": "", + "images": [] + }, + "qishibo.AnotherRedisDesktopManager": { + "icon": "https://i.imgur.com/XEqwRMy.png", + "images": [ + "https://i.imgur.com/j8X8erw.png", + "https://i.imgur.com/NJr39pR.png", + "https://i.imgur.com/JRDNdYT.png", + "https://i.imgur.com/pirCiFg.png" + ] + }, + "QL-Win.QuickLook": { + "icon": "", + "images": [] + }, + "QMK.QMKToolbox": { + "icon": "", + "images": [] + }, + "QmmpDevelopmentTeam.qmmp": { + "icon": "", + "images": [] + }, + "QMPlay2.QMPlay2": { + "icon": "", + "images": [] + }, + "QNAP.ExternalRAIDManager": { + "icon": "", + "images": [] + }, + "QNAP.NetBakReplicator": { + "icon": "", + "images": [] + }, + "QNAP.QENCDecrypter": { + "icon": "", + "images": [] + }, + "QNAP.QfinderPro": { + "icon": "", + "images": [] + }, + "QNAP.Qsirch": { + "icon": "", + "images": [] + }, + "QNAP.Qsync": { + "icon": "", + "images": [] + }, + "QNAP.QuDedupExtractTool": { + "icon": "", + "images": [] + }, + "QNAP.QVRProClient": { + "icon": "", + "images": [] + }, + "Qoppa.PDFStudio": { + "icon": "", + "images": [] + }, + "qotop.SpaceEngine": { + "icon": "", + "images": [] + }, + "Qt.QtDesigner": { + "icon": "", + "images": [] + }, + "QTextPad.QTextPad": { + "icon": "", + "images": [] + }, + "QTodoTxt.QTodoTxt": { + "icon": "", + "images": [] + }, + "QTTabBar.QTTabBar": { + "icon": "", + "images": [] + }, + "Questrade.IQEdge": { + "icon": "", + "images": [] + }, + "QuestSoft.QTranslate": { + "icon": "", + "images": [] + }, + "quick-lint.quick-lint-js": { + "icon": "", + "images": [] + }, + "quick123.quickredis": { + "icon": "", + "images": [] + }, + "Quicken.Quicken": { + "icon": "", + "images": [] + }, + "QuintonReeves.RedEclipse": { + "icon": "", + "images": [] + }, + "QuiteRSS.QuiteRSS": { + "icon": "", + "images": [] + }, + "QuodLibet.QuodLibet": { + "icon": "", + "images": [] + }, + "qutebrowser.qutebrowser": { + "icon": "", + "images": [] + }, + "Qv2ray.Qv2ray": { + "icon": "", + "images": [] + }, + "r12f.DivoomCli": { + "icon": "", + "images": [] + }, + "r12f.DivoomGateway": { + "icon": "", + "images": [] + }, + "r12f.Rnp": { + "icon": "", + "images": [] + }, + "Rabbit-Company.Passky": { + "icon": "", + "images": [] + }, + "RabidViperProductions.AssaultCube": { + "icon": "https://www.fileeagle.com/data/2016/02/AssaultCube.jpg", + "images": [ + "https://assault.cubers.net/screenshots/screenshots-large/ac_complex_DM_gren_large00.jpg", + "https://assault.cubers.net/screenshots/screenshots-large/ac_complex_DM_pist_large00.jpg", + "https://assault.cubers.net/screenshots/screenshots-large/ac_complex_DM_SG_large00.jpg", + "https://assault.cubers.net/screenshots/screenshots-large/ac_complex_DM_SR_large00.jpg", + "https://assault.cubers.net/screenshots/screenshots-large/ac_mines_CTF_SMG_large00.jpg", + "https://assault.cubers.net/screenshots/screenshots-large/ac_mines_CTF_SMG_large01.jpg", + "https://assault.cubers.net/screenshots/screenshots-large/ac_shine_CTF_unknown_large00.jpg", + "https://assault.cubers.net/screenshots/screenshot-table.jpg" + ] + }, + "RaceCore24.Ignition": { + "icon": "", + "images": [] + }, + "Racket.Racket": { + "icon": "", + "images": [] + }, + "Radiantly.Invisiwind": { + "icon": "", + "images": [] + }, + "Radmin.VPN": { + "icon": "", + "images": [] + }, + "raimo.Smallpdf": { + "icon": "", + "images": [] + }, + "Rainmeter.Rainmeter": { + "icon": "", + "images": [] + }, + "Rambax.SimpleTransfer": { + "icon": "", + "images": [] + }, + "Rambox.Rambox": { + "icon": "", + "images": [] + }, + "Rambox.Rambox.Community": { + "icon": "", + "images": [] + }, + "rammichael.7+TaskbarTweaker": { + "icon": "https://imgur.com/tr7rArh.png", + "images": [ + "https://tweaker.ramensoftware.com/images/7-taskbar-tweaker.png", + "https://tweaker.ramensoftware.com/images/screenshot-1-settings.png", + "https://tweaker.ramensoftware.com/images/screenshot-2-inspector-1.png", + "https://tweaker.ramensoftware.com/images/screenshot-3-inspector-2.png", + "https://tweaker.ramensoftware.com/images/screenshot-4-advanced.png" + ] + }, + "rammichael.7+TaskbarTweaker.Beta": { + "icon": "https://imgur.com/tr7rArh.png", + "images": [ + "https://tweaker.ramensoftware.com/images/7-taskbar-tweaker.png", + "https://tweaker.ramensoftware.com/images/screenshot-1-settings.png", + "https://tweaker.ramensoftware.com/images/screenshot-2-inspector-1.png", + "https://tweaker.ramensoftware.com/images/screenshot-3-inspector-2.png", + "https://tweaker.ramensoftware.com/images/screenshot-4-advanced.png" + ] + }, + "rammichael.Textify": { + "icon": "", + "images": [] + }, + "RamSoft.DicomProxy": { + "icon": "", + "images": [] + }, + "RamSoft.OmegaAILink": { + "icon": "", + "images": [] + }, + "RandomEngy.VidCoder": { + "icon": "https://vidcoder.net/images/BannerLarge.png", + "images": [ + "https://vidcoder.net/images/main.png", + "https://vidcoder.net/images/preview.png", + "https://vidcoder.net/images/encoding_settings.png" + ] + }, + "RandomEngy.VidCoder.Beta": { + "icon": "", + "images": [] + }, + "RandyRants.SharpKeys": { + "icon": "", + "images": [] + }, + "ransome1.sleek": { + "icon": "", + "images": [] + }, + "RARLab.WinRAR": { + "icon": "", + "images": [] + }, + "RaspberryPiFoundation.RaspberryPiI\u2026": { + "icon": "", + "images": [] + }, + "Rawns.Reddit-Wallpaper-Changer": { + "icon": "", + "images": [] + }, + "RawTherapee.RawTherapee": { + "icon": "", + "images": [] + }, + "RawTherapee.RawTherapee-Dev": { + "icon": "", + "images": [] + }, + "raycho.raycho": { + "icon": "", + "images": [] + }, + "RaynerSec.Hyper-V-Switch": { + "icon": "", + "images": [] + }, + "rcmaehl.MSEdgeRedirect": { + "icon": "", + "images": [] + }, + "rcmaehl.WhyNotWin11": { + "icon": "", + "images": [] + }, + "Readdle.Spark": { + "icon": "", + "images": [] + }, + "REALiX.HWiNFO": { + "icon": "", + "images": [] + }, + "realsast.FlyingCube": { + "icon": "", + "images": [] + }, + "RealtimeSoft.UltraMon": { + "icon": "", + "images": [] + }, + "RealVNC.VNCServer": { + "icon": "", + "images": [] + }, + "RealVNC.VNCViewer": { + "icon": "", + "images": [] + }, + "Recoupler.AudioBookConverter": { + "icon": "", + "images": [ + "https://lh5.googleusercontent.com/fi8XFyiFP6malV-MGC5Sv49KNqOYuwSxoP3YL6VzBxVmKuvGbOERT0SXRuVJyO2BswbZRnwAPVJq7R0zojT8_IyzIzfSmcRnlytR6Vhz0r7VNVf7=w1280", + "https://cdn.cloudflare.steamstatic.com/steam/apps/1529240/ss_6baa06b1609afe4ef2e82d265bc8c25a0b69dda5.1920x1080.jpg?t=1640257305" + ] + }, + "REDAbierta.URANOSSoftphone": { + "icon": "", + "images": [] + }, + "RedDucks.CemUI": { + "icon": "", + "images": [] + }, + "RedHat.Podman": { + "icon": "", + "images": [] + }, + "RedHat.Podman-Desktop": { + "icon": "", + "images": [] + }, + "RedHat.VirtViewer": { + "icon": "", + "images": [] + }, + "Redisant.LittleTips": { + "icon": "", + "images": [] + }, + "Reginald.Reginald": { + "icon": "", + "images": [] + }, + "RejminetGroupInc.PDFShow": { + "icon": "", + "images": [] + }, + "RemixTeam.RemixIDE": { + "icon": "", + "images": [] + }, + "RemNote.RemNote": { + "icon": "", + "images": [] + }, + "remoteit.remoteit": { + "icon": "", + "images": [] + }, + "RenewedVision.ProPresenter": { + "icon": "", + "images": [] + }, + "Renode.Renode": { + "icon": "", + "images": [] + }, + "Renoise.Renoise": { + "icon": "", + "images": [] + }, + "Reolink.Reolink": { + "icon": "", + "images": [] + }, + "Reptarsrage.looking-glass": { + "icon": "", + "images": [] + }, + "RescueTime.DesktopApp": { + "icon": "", + "images": [] + }, + "Resilio.ResilioSync": { + "icon": "", + "images": [] + }, + "Resplendence.LatencyMon": { + "icon": "", + "images": [] + }, + "Resplendence.MultiMon": { + "icon": "", + "images": [] + }, + "Resplendence.RegistrarRegistryMana\u2026": { + "icon": "", + "images": [] + }, + "Resplendence.SanityCheck": { + "icon": "", + "images": [] + }, + "Resplendence.Undeluxe": { + "icon": "", + "images": [] + }, + "Resplendence.WhoCrashed": { + "icon": "", + "images": [] + }, + "Resplendence.WhySoSlow": { + "icon": "", + "images": [] + }, + "ResponsivelyApp.ResponsivelyApp": { + "icon": "", + "images": [] + }, + "Restream.RestreamChat": { + "icon": "", + "images": [] + }, + "Retroshare.Retroshare": { + "icon": "", + "images": [] + }, + "Revolt.RevoltDesktop": { + "icon": "", + "images": [] + }, + "Revora.CNCOnline": { + "icon": "", + "images": [] + }, + "RevoUninstaller.RevoUninstaller": { + "icon": "", + "images": [] + }, + "RevoUninstaller.RevoUninstallerPro": { + "icon": "", + "images": [] + }, + "Rhinode.TradingPaints": { + "icon": "", + "images": [] + }, + "RIA.DigiDoc4": { + "icon": "", + "images": [] + }, + "RichardsonSoftware.RazorSQL": { + "icon": "", + "images": [] + }, + "rickbutton.workspacer": { + "icon": "", + "images": [] + }, + "rickbutton.workspacer.beta": { + "icon": "", + "images": [] + }, + "RickClark.Pullp": { + "icon": "", + "images": [] + }, + "RicochetIM.Ricochet": { + "icon": "", + "images": [] + }, + "RicoSuter.NSwagStudio": { + "icon": "", + "images": [] + }, + "RIDI.Ridibooks": { + "icon": "", + "images": [] + }, + "RigsofRods.RigsofRods": { + "icon": "", + "images": [] + }, + "Riiid.pollapo": { + "icon": "", + "images": [] + }, + "RileyTestut.AltServer": { + "icon": "https://tweak-box.com/wp-content/uploads/emus4u/2019/10/altstore-app-200px-120x120.png", + "images": [ + "https://ijunkie.com/wp-content/uploads/2020/04/altstore-sideload.jpeg", + "https://images.sftcdn.net/images/t_app-cover-m,f_auto/p/2ee76aed-e3c3-440c-87e2-cf8b1a1fe627/2455918045/altstore-altstore-io-page.png", + "https://altstore.io/install-altstore.png" + ] + }, + "Rils.TouchPortal": { + "icon": "", + "images": [] + }, + "Rime.Weasel": { + "icon": "", + "images": [] + }, + "RingCentral.RingCentral": { + "icon": "", + "images": [] + }, + "RiotGames.LeagueOfLegends.BR": { + "icon": "", + "images": [] + }, + "RiotGames.LeagueOfLegends.EUNE": { + "icon": "", + "images": [] + }, + "RiotGames.LeagueOfLegends.EUW": { + "icon": "", + "images": [] + }, + "RiotGames.LeagueOfLegends.LA1": { + "icon": "", + "images": [] + }, + "RiotGames.LeagueOfLegends.LA2": { + "icon": "", + "images": [] + }, + "RiotGames.LeagueOfLegends.NA": { + "icon": "", + "images": [] + }, + "RiotGames.LeagueOfLegends.OC1": { + "icon": "", + "images": [] + }, + "RiotGames.LeagueOfLegends.PBE": { + "icon": "", + "images": [] + }, + "RiotGames.Valorant.AP": { + "icon": "", + "images": [] + }, + "RiotGames.Valorant.BR": { + "icon": "", + "images": [] + }, + "RiotGames.Valorant.EU": { + "icon": "", + "images": [] + }, + "RiotGames.Valorant.NA": { + "icon": "", + "images": [] + }, + "Ripose.Memento": { + "icon": "", + "images": [] + }, + "Ritlabs.TheBat!": { + "icon": "", + "images": [] + }, + "RivaFarabi.Deckboard": { + "icon": "", + "images": [] + }, + "Rizonesoft.Firemin": { + "icon": "", + "images": [] + }, + "Rizonesoft.Notepad3": { + "icon": "", + "images": [] + }, + "rjpcomputing.luaforwindows": { + "icon": "", + "images": [] + }, + "RKibria.frhed": { + "icon": "", + "images": [] + }, + "RoamResearch.RoamResearch": { + "icon": "", + "images": [] + }, + "RobertFFrasca.PDFKeeper": { + "icon": "", + "images": [] + }, + "RobinJullian.Shuttle": { + "icon": "", + "images": [] + }, + "Robware.RVTools": { + "icon": "", + "images": [] + }, + "RocketChat.RocketChat": { + "icon": "", + "images": [] + }, + "rocksdanister.LivelyWallpaper": { + "icon": "", + "images": [] + }, + "RoderickQiu.wnr": { + "icon": "", + "images": [] + }, + "Rohde&Schwarz.SDC.IETDViewAutark": { + "icon": "", + "images": [] + }, + "Rohde&Schwarz.SDC.IETDViewAutarkBw": { + "icon": "", + "images": [] + }, + "Rohde&Schwarz.SDC.IETDViewPublish": { + "icon": "", + "images": [] + }, + "Rokkr.Rokkr": { + "icon": "", + "images": [] + }, + "Romanitho.WiGUI": { + "icon": "", + "images": [] + }, + "RomanKubiak.Ctrlr": { + "icon": "", + "images": [] + }, + "Romcenter.Romcenter": { + "icon": "", + "images": [] + }, + "RoniLehto.LMath": { + "icon": "", + "images": [] + }, + "RonyShapiro.PasswordSafe": { + "icon": "", + "images": [] + }, + "RoonLabs.Roon": { + "icon": "", + "images": [] + }, + "RoonLabs.RoonBridge": { + "icon": "", + "images": [] + }, + "RoonLabs.RoonServer": { + "icon": "", + "images": [] + }, + "roryok.poe-writer": { + "icon": "", + "images": [] + }, + "RossCarlson.VATSpy": { + "icon": "", + "images": [] + }, + "RossCarlson.vPilot": { + "icon": "", + "images": [] + }, + "Rowley.CrossWorks": { + "icon": "", + "images": [] + }, + "RoyalApps.RoyalTS": { + "icon": "", + "images": [] + }, + "RoyQu.RedPanda-C++": { + "icon": "", + "images": [] + }, + "RProject.R": { + "icon": "https://www.r-project.org/logo/Rlogo.png", + "images": [] + }, + "RProject.Rtools": { + "icon": "https://www.r-project.org/logo/Rlogo.png", + "images": [] + }, + "rsjaffe.MIDI2LR": { + "icon": "", + "images": [] + }, + "RStudio.quarto": { + "icon": "", + "images": [] + }, + "RStudio.RStudio.OpenSource": { + "icon": "https://www.rstudio.com/wp-content/uploads/2018/10/RStudio-Logo-Flat.png", + "images": [] + }, + "RStudio.RStudio.Professional": { + "icon": "https://www.rstudio.com/wp-content/uploads/2018/10/RStudio-Logo-Flat.png", + "images": [] + }, + "Ruanmei.Qiyu": { + "icon": "", + "images": [] + }, + "Rubberduck.Rubberduck": { + "icon": "", + "images": [] + }, + "Ruben2776.PicView": { + "icon": "", + "images": [] + }, + "RubinderSingh.Ditto++": { + "icon": "", + "images": [] + }, + "RubyInstallerTeam.Ruby.2.6": { + "icon": "", + "images": [] + }, + "RubyInstallerTeam.Ruby.2.7": { + "icon": "", + "images": [] + }, + "RubyInstallerTeam.Ruby.3.0": { + "icon": "", + "images": [] + }, + "RubyInstallerTeam.Ruby.3.1": { + "icon": "", + "images": [] + }, + "RubyInstallerTeam.RubyWithDevKit.2\u2026": { + "icon": "", + "images": [] + }, + "RubyInstallerTeam.RubyWithDevKit.3\u2026": { + "icon": "", + "images": [] + }, + "Rufus.Rufus": { + "icon": "", + "images": [] + }, + "RuneLite.RuneLite": { + "icon": "", + "images": [] + }, + "runlet.runlet": { + "icon": "", + "images": [] + }, + "RussellBanks.HashHash": { + "icon": "", + "images": [] + }, + "RustDesk.RustDesk": { + "icon": "", + "images": [] + }, + "RustemMussabekov.Raindrop": { + "icon": "", + "images": [] + }, + "Rustlang.Rust.GNU": { + "icon": "", + "images": [] + }, + "Rustlang.Rust.MSVC": { + "icon": "", + "images": [] + }, + "Rustlang.Rustup": { + "icon": "", + "images": [] + }, + "RyanGregg.GCFScape": { + "icon": "", + "images": [] + }, + "RyanGregg.VTFEdit": { + "icon": "", + "images": [] + }, + "ryanSn.winMoji": { + "icon": "", + "images": [] + }, + "RyzenControllerTeam.RyzenController": { + "icon": "", + "images": [] + }, + "s8sachin.subtitler": { + "icon": "", + "images": [] + }, + "SaaSGroup.Tower": { + "icon": "", + "images": [] + }, + "SabakiHQ.Sabaki": { + "icon": "", + "images": [] + }, + "SABnzbdTeam.SABnzbd": { + "icon": "", + "images": [] + }, + "SachaBruttin.CosmosDBExplorer": { + "icon": "", + "images": [] + }, + "SaeraSoft.CaesiumImageCompressor": { + "icon": "", + "images": [] + }, + "SaeraSoft.CaesiumPH": { + "icon": "", + "images": [] + }, + "SaferNetworking.SpybotAntiBeacon": { + "icon": "", + "images": [] + }, + "Safing.Portmaster": { + "icon": "", + "images": [] + }, + "SagarGurtu.Lector": { + "icon": "", + "images": [] + }, + "SAGAUserGroupAssociation.SAGAGIS": { + "icon": "", + "images": [] + }, + "SageMath.SageMath": { + "icon": "", + "images": [] + }, + "SagMeinenNamen.eChess": { + "icon": "", + "images": [] + }, + "SagMeinenNamen.OpenStoreInstaller": { + "icon": "", + "images": [] + }, + "SagMeinenNamen.TypingTest": { + "icon": "", + "images": [] + }, + "SaiSandeepVaddi.TenHands": { + "icon": "", + "images": [] + }, + "SaitoGames.BattlePainters": { + "icon": "http://www.saitogames.com/_images/painters_logo.gif", + "images": [ + "http://www.saitogames.com/_images/painters_screen01.gif", + "http://www.saitogames.com/_images/painters_screen02.gif", + "http://www.saitogames.com/_images/painters_screen03.gif", + "http://www.saitogames.com/_images/painters_screen04.gif" + ] + }, + "SaitoGames.Hopmon": { + "icon": "", + "images": [] + }, + "SaitoGames.MageBros": { + "icon": "", + "images": [] + }, + "SaitoGames.PetWings": { + "icon": "", + "images": [] + }, + "SaitoGames.Troy2000": { + "icon": "", + "images": [] + }, + "SaladTechnologies.Salad": { + "icon": "", + "images": [] + }, + "SaltStack.SaltMinion": { + "icon": "", + "images": [] + }, + "SamHocevar.WinCompose": { + "icon": "", + "images": [] + }, + "Samsung.DeX": { + "icon": "", + "images": [] + }, + "Samsung.SmartSwitch": { + "icon": "", + "images": [] + }, + "SamuelAttard.GooglePlayMusicDeskto\u2026": { + "icon": "", + "images": [] + }, + "Sandboxie.Classic": { + "icon": "", + "images": [] + }, + "Sandboxie.Plus": { + "icon": "", + "images": [] + }, + "SandroMani.gImageReader": { + "icon": "", + "images": [] + }, + "SandwichFox.mbcord": { + "icon": "", + "images": [] + }, + "SanfordLP.DYMOConnect": { + "icon": "", + "images": [] + }, + "SanfordLP.DYMOLabel": { + "icon": "", + "images": [] + }, + "Sangoma.Zulu": { + "icon": "", + "images": [] + }, + "SartoxOnlyGNU.Audacium": { + "icon": "https://user-images.githubusercontent.com/34075088/128607939-19908854-923a-4447-b134-40632d233510.png", + "images": [ + "https://user-images.githubusercontent.com/34075088/128556907-8cb6a1a8-d4e9-461a-9f84-3759085583dd.png", + "https://i.imgur.com/YGdq58x.png" + ] + }, + "SatisfactoryModding.SatisfactoryMo\u2026": { + "icon": "", + "images": [] + }, + "SatoshiLabs.trezor-suite": { + "icon": "", + "images": [] + }, + "SatoshiLabs.TrezorBridge": { + "icon": "", + "images": [] + }, + "Saturneric.GpgFrontend": { + "icon": "", + "images": [] + }, + "SavardSoftware.TurboTop": { + "icon": "", + "images": [] + }, + "Saxo_Broko.GingerChrome": { + "icon": "", + "images": [] + }, + "Saxo_Broko.Officialapp": { + "icon": "", + "images": [] + }, + "Sayuri.FFFTP": { + "icon": "", + "images": [] + }, + "SBCL.SBCL": { + "icon": "", + "images": [] + }, + "sbt.sbt": { + "icon": "", + "images": [] + }, + "sc0ty.SubSync": { + "icon": "", + "images": [] + }, + "Scala.Scala.2": { + "icon": "", + "images": [] + }, + "schemacrawler.schemacrawler": { + "icon": "", + "images": [] + }, + "Schezo.Lhaplus": { + "icon": "", + "images": [] + }, + "schild-report.schild-report": { + "icon": "", + "images": [] + }, + "SchildiChat.SchildiChat": { + "icon": "", + "images": [] + }, + "Schrodinger.Pymol": { + "icon": "", + "images": [] + }, + "Scilab.Scilab": { + "icon": "", + "images": [] + }, + "scimusmn.stele": { + "icon": "", + "images": [] + }, + "Scintilla.SciTE": { + "icon": "", + "images": [] + }, + "ScooterSoftware.BeyondCompare4": { + "icon": "", + "images": [] + }, + "Scopely.StarTrekFleetCommand": { + "icon": "", + "images": [] + }, + "Scorpio.sco": { + "icon": "", + "images": [] + }, + "Scorpio.scov": { + "icon": "", + "images": [] + }, + "Scorpio.stools": { + "icon": "", + "images": [] + }, + "scottlerch.hosts-file-editor": { + "icon": "", + "images": [] + }, + "ScratchForDiscord.ScratchForDiscor\u2026": { + "icon": "", + "images": [] + }, + "ScratchForDiscord.ScratchForDiscord": { + "icon": "", + "images": [] + }, + "ScreenCloud.ScreenCloudPlayer": { + "icon": "", + "images": [] + }, + "Scribus.Scribus": { + "icon": "https://wiki.scribus.net/wiki/images/thumb/f/f1/Scribusicon-blue.png/200px-Scribusicon-blue.png", + "images": [] + }, + "ScummVM.ScummVM": { + "icon": "", + "images": [] + }, + "Seafile.Seafile": { + "icon": "", + "images": [] + }, + "Seagate.SeaTools": { + "icon": "", + "images": [] + }, + "Seagate.SeaTools.Legacy": { + "icon": "", + "images": [] + }, + "SearchDeflector.SearchDeflector": { + "icon": "", + "images": [] + }, + "SebastianEwert.RapidCRC": { + "icon": "", + "images": [] + }, + "SebastianFelling.ToughCookies": { + "icon": "", + "images": [] + }, + "sebastianstoff.orbitron": { + "icon": "", + "images": [] + }, + "secana.CertDump": { + "icon": "", + "images": [] + }, + "SecombaGmbH.Boxcryptor": { + "icon": "", + "images": [] + }, + "Secret.Chat": { + "icon": "", + "images": [] + }, + "SeDuTec.AudioAnalyser": { + "icon": "", + "images": [ + "https://sedutec.de/images/audioanalyser201012_1.jpg" + ] + }, + "SeDuTec.Multisine": { + "icon": "", + "images": [] + }, + "sedwards2009.extraterm": { + "icon": "", + "images": [] + }, + "Seedy-Threepio.Theseus2000": { + "icon": "", + "images": [] + }, + "Segger.EmbeddedStudioARM": { + "icon": "", + "images": [] + }, + "Sejda.PDFDesktop": { + "icon": "", + "images": [] + }, + "Seonglae.Intuiter": { + "icon": "", + "images": [] + }, + "Seonglae.Screencast": { + "icon": "", + "images": [] + }, + "SergeySerkov.TagScanner": { + "icon": "", + "images": [] + }, + "SerhiiSlieptsov.Utilso": { + "icon": "", + "images": [] + }, + "SerialLab.SerialLab": { + "icon": "", + "images": [] + }, + "Serraniel.DiscordMediaLoader": { + "icon": "", + "images": [] + }, + "Serverless.Serverless": { + "icon": "", + "images": [] + }, + "ServerManager.ServerManager": { + "icon": "", + "images": [] + }, + "SeventhString.Transcribe": { + "icon": "", + "images": [] + }, + "SFLinux.Jami": { + "icon": "", + "images": [] + }, + "SFLinux.Jami.Beta": { + "icon": "", + "images": [] + }, + "sfx101.deck": { + "icon": "", + "images": [] + }, + "Shabinder.SpotiFlyer": { + "icon": "", + "images": [] + }, + "shagrath.PS3MediaServer": { + "icon": "", + "images": [] + }, + "Shapr3D.Shapr3D": { + "icon": "", + "images": [] + }, + "ShareX.ShareX": { + "icon": "", + "images": [] + }, + "SharkLabs.ClownfishVoiceChanger": { + "icon": "", + "images": [] + }, + "ShiftCryptoAG.BitBoxApp": { + "icon": "", + "images": [] + }, + "shimo.shimo": { + "icon": "", + "images": [] + }, + "ShiningLight.OpenSSL": { + "icon": "", + "images": [] + }, + "ShiningLight.OpenSSL.Light": { + "icon": "", + "images": [] + }, + "shogixyz.ShogiGUI": { + "icon": "", + "images": [] + }, + "Shooter.SPlayer": { + "icon": "", + "images": [] + }, + "Shooter.SPlayerX": { + "icon": "", + "images": [] + }, + "Shure.ShurePlusMOTIV": { + "icon": "", + "images": [] + }, + "Shure.UpdateUtility": { + "icon": "", + "images": [] + }, + "Shure.WirelessWorkbench": { + "icon": "", + "images": [] + }, + "SiberSystems.GoodSync": { + "icon": "", + "images": [] + }, + "SideQuestVR.SideQuest": { + "icon": "https://sidequestvr.com/assets/icons/apple-icon-180x180.png", + "images": [] + }, + "sidneys.desktop-dimmer": { + "icon": "", + "images": [] + }, + "sidneys.pb-for-desktop": { + "icon": "", + "images": [] + }, + "Sigil-Ebook.Sigil": { + "icon": "", + "images": [] + }, + "Sigrok.PulseView": { + "icon": "", + "images": [] + }, + "Silicondust.HDHomeRun": { + "icon": "", + "images": [] + }, + "Silicondust.HDHomeRunTECH": { + "icon": "", + "images": [] + }, + "SilverlakeSoftware.Velocity": { + "icon": "", + "images": [] + }, + "SimAirIo.SimAirClient": { + "icon": "", + "images": [] + }, + "SimBustSoftware.MonAmiNote": { + "icon": "", + "images": [] + }, + "Simon511000.CitycraftLauncher": { + "icon": "", + "images": [] + }, + "SimpleLedger.ElectronCashSLP": { + "icon": "", + "images": [] + }, + "Sinew.Enpass": { + "icon": "", + "images": [] + }, + "SingularLabs.CCEnhancer": { + "icon": "", + "images": [] + }, + "sipgate.sipgatesoftphone": { + "icon": "", + "images": [] + }, + "sirWest.AudioSwitch": { + "icon": "https://raw.githubusercontent.com/sirWest/AudioSwitch/master/gh-pages/AudioSwitchLogoSmall.png", + "images": [ + "https://github.com/sirWest/AudioSwitch/raw/master/gh-pages/output.png", + "https://github.com/sirWest/AudioSwitch/raw/master/gh-pages/input.png" + ] + }, + "Skaarhoj.KeyBridge": { + "icon": "", + "images": [] + }, + "SKAARHOJApS.SKAARHOJUpdater": { + "icon": "", + "images": [] + }, + "SKCommunications.NateOn": { + "icon": "", + "images": [] + }, + "SKDataAS.ORMCore": { + "icon": "", + "images": [] + }, + "Skillbrains.Lightshot": { + "icon": "", + "images": [] + }, + "Sky.SkyGo": { + "icon": "", + "images": [] + }, + "skyjake.Lagrange": { + "icon": "", + "images": [] + }, + "SlackedLime.TimeSpent": { + "icon": "", + "images": [] + }, + "SlackTechnologies.Slack": { + "icon": "", + "images": [] + }, + "SlackTechnologies.Slack.Beta": { + "icon": "", + "images": [] + }, + "SlashedIo.Inssist": { + "icon": "", + "images": [] + }, + "SleuthKit.Autopsy": { + "icon": "https://i.imgur.com/MNqvAXk.png", + "images": [ + "http://sleuthkit.org/autopsy/docs/user-docs/4.15.0/portable_case_original_version.png", + "https://media.geeksforgeeks.org/wp-content/uploads/20200830111540/Screenshot8.png" + ] + }, + "Slik.Subversion": { + "icon": "", + "images": [] + }, + "Slonopotamus.Stevedore": { + "icon": "", + "images": [] + }, + "SM5BSZ.Linrad": { + "icon": "", + "images": [] + }, + "SmartBear.SoapUI": { + "icon": "", + "images": [] + }, + "SmartGameBooster.SmartGameBooster": { + "icon": "", + "images": [] + }, + "SmartHoldemDAPPs.heads-tails": { + "icon": "", + "images": [] + }, + "smartmontools.smartmontools": { + "icon": "", + "images": [] + }, + "SmartOldFish.OCRTools": { + "icon": "", + "images": [] + }, + "SmartProjects.IsoBuster": { + "icon": "", + "images": [] + }, + "SmartSoft.SmartFTP": { + "icon": "", + "images": [] + }, + "Smile.TextExpander": { + "icon": "", + "images": [] + }, + "Smogon.PokemonShowdown": { + "icon": "", + "images": [] + }, + "SMPlayer.SMPlayer": { + "icon": "https://i.postimg.cc/X7mhgCJL/SMPlayer.png", + "images": [] + }, + "SnailDOS.Fifo": { + "icon": "", + "images": [] + }, + "SnailDOS.SnailFM": { + "icon": "", + "images": [] + }, + "SnailDOS.StreamBop": { + "icon": "", + "images": [] + }, + "snakefoot.snaketail": { + "icon": "", + "images": [] + }, + "SnapmakerDevTeam.SnapmakerLuban": { + "icon": "", + "images": [] + }, + "Snaz.Snaz": { + "icon": "", + "images": [] + }, + "SnoopWpf.Snoop": { + "icon": "", + "images": [] + }, + "Snyk.Snyk": { + "icon": "", + "images": [] + }, + "SocialchainInc.PiNetwork": { + "icon": "", + "images": [] + }, + "SoftDeluxe.FreeDownloadManager": { + "icon": "", + "images": [] + }, + "Softerra.LDAPBrowser": { + "icon": "", + "images": [] + }, + "SoftezaDevelopment.ActualUpdater": { + "icon": "https://i.imgur.com/3KtDZX9.png", + "images": [ + "https://www.actualinstaller.com/images/screen/installer_1s.png", + "https://www.actualinstaller.com/images/screen/installer_2s.png", + "https://www.actualinstaller.com/images/screen/installer_3s.png", + "https://www.actualinstaller.com/images/screen/installer_4s.png", + "https://www.actualinstaller.com/images/screen/installer_6s.png", + "https://www.actualinstaller.com/images/screen/installer_7s.png", + "https://www.actualinstaller.com/images/screen/installer_8s.png", + "https://www.actualinstaller.com/images/screen/installer_9s.png", + "https://www.actualinstaller.com/images/screen/installer_10s.png", + "https://www.actualinstaller.com/images/screen/installer_11s.png", + "https://www.actualinstaller.com/images/screen/installer_12s.png", + "https://www.actualinstaller.com/images/screen/installer_13s.png", + "https://www.actualinstaller.com/images/screen/installer_14s.png", + "https://www.actualinstaller.com/images/screen/installer_15s.png", + "https://www.actualinstaller.com/images/screen/installer_16s.png", + "https://www.actualinstaller.com/images/screen/installer_17s.png", + "https://www.actualinstaller.com/images/screen/wizard_welcome_small.png", + "https://www.actualinstaller.com/images/screen/wizard_license_small.png", + "https://www.actualinstaller.com/images/screen/wizard_tasks_small.png", + "https://www.actualinstaller.com/images/screen/wizard_install_small.png", + "https://www.actualinstaller.com/images/screen/wizard_finish_small.png" + ] + }, + "SoftMaker.FreeOffice.2021": { + "icon": "", + "images": [] + }, + "SoftMaker.Office.2021": { + "icon": "", + "images": [] + }, + "SoftouchDevelopment.EasyWorship": { + "icon": "", + "images": [] + }, + "SoftPerfect.SoftPerfectNetworkScan\u2026": { + "icon": "", + "images": [] + }, + "SoftpointerInc.Tag&Rename": { + "icon": "", + "images": [] + }, + "SoftwareFreedomConservancy.QEMU": { + "icon": "", + "images": [] + }, + "SoftwareFreedomConservancy.QEMUGue\u2026": { + "icon": "", + "images": [] + }, + "Sogou.SogouInput": { + "icon": "", + "images": [] + }, + "Sogou.SogouWBInput": { + "icon": "", + "images": [] + }, + "Sohu.SHPlayer": { + "icon": "", + "images": [] + }, + "SolidClouds.Starborne": { + "icon": "", + "images": [] + }, + "Solvusoft.WinThruster": { + "icon": "", + "images": [] + }, + "SomePythonThings.ElevenClock": { + "icon": "https://github.com/martinet101/ElevenClock/blob/main/media/icon.png?raw=true", + "images": [ + "https://github.com/martinet101/ElevenClock/blob/main/media/img1.png?raw=true", + "https://github.com/martinet101/ElevenClock/blob/main/media/img2.png?raw=true", + "https://github.com/martinet101/ElevenClock/blob/main/media/img3.png?raw=true", + "https://github.com/martinet101/ElevenClock/blob/main/media/img4.png?raw=true", + "https://github.com/martinet101/ElevenClock/blob/main/media/img5.png?raw=true", + "https://github.com/martinet101/ElevenClock/blob/main/media/img6.png?raw=true", + "https://github.com/martinet101/ElevenClock/blob/main/media/img7.png?raw=true", + "https://github.com/martinet101/ElevenClock/blob/main/media/img8.png?raw=true" + ] + }, + "SomePythonThings.WingetUIStore": { + "icon": "https://github.com/martinet101/WingetUI/blob/main/wingetui/resources/icon.png?raw=true", + "images": [ + "https://github.com/martinet101/WingetUI/blob/main/media/winget_1.png?raw=true", + "https://github.com/martinet101/WingetUI/blob/main/media/winget_2.png?raw=true", + "https://github.com/martinet101/WingetUI/blob/main/media/winget_3.png?raw=true", + "https://github.com/martinet101/WingetUI/blob/main/media/winget_4.png?raw=true", + "https://github.com/martinet101/WingetUI/blob/main/media/winget_5.png?raw=true", + "https://github.com/martinet101/WingetUI/blob/main/media/winget_6.png?raw=true", + "https://github.com/martinet101/WingetUI/blob/main/media/winget_7.png", + "https://github.com/martinet101/WingetUI/blob/main/media/winget_8.png" + ] + }, + "SomePythonThings.ZipManager": { + "icon": "", + "images": [] + }, + "Soneliem.WAIUA": { + "icon": "", + "images": [] + }, + "SonicPi.SonicPi": { + "icon": "", + "images": [] + }, + "SonicTeamJr.SonicRoboBlast2": { + "icon": "", + "images": [] + }, + "SonicTeamJr.SonicRoboBlast2Kart": { + "icon": "", + "images": [] + }, + "SonicVisualiser.SonicVisualiser": { + "icon": "", + "images": [] + }, + "SonicWALL.ConnectTunnel": { + "icon": "", + "images": [] + }, + "SonicWALL.GlobalVPN": { + "icon": "", + "images": [] + }, + "SonicWALL.NetExtender": { + "icon": "", + "images": [] + }, + "Sonos.Controller": { + "icon": "", + "images": [] + }, + "Sonos.S1Controller": { + "icon": "", + "images": [] + }, + "Sonosaurus.SonoBus": { + "icon": "", + "images": [] + }, + "SonsofExiled.Arma3Sync": { + "icon": "https://i.imgur.com/WxxNlan.png", + "images": [ + "http://i.imgur.com/Pq8nK5T.png", + "https://wiki.tacticalteam.de/technik/armasync/armasync_repository_checkupdates.png", + "https://wiki.tacticalteam.de/technik/armasync/armasync_verzeichnis-repoauswahl.png", + "https://sasclan.org/sites/default/files/public/images/downloading-a3-modset-a3sync-3.png" + ] + }, + "Soroush.Soroush+": { + "icon": "", + "images": [] + }, + "SoroushChehresa.UnsplashWallpapers": { + "icon": "", + "images": [] + }, + "Soulseek.SoulseekQt": { + "icon": "", + "images": [] + }, + "Soundly.Soundly": { + "icon": "", + "images": [] + }, + "SourceFoundry.HackFonts": { + "icon": "", + "images": [] + }, + "SourceGear.DiffMerge": { + "icon": "", + "images": [] + }, + "Sovranti.Sovranti": { + "icon": "", + "images": [] + }, + "Spacemesh.Spacemesh": { + "icon": "", + "images": [] + }, + "SparkLabs.openvpn-configuration-ge\u2026": { + "icon": "", + "images": [] + }, + "SparkLabs.Viscosity": { + "icon": "", + "images": [] + }, + "SparkleShare.SparkleShare": { + "icon": "", + "images": [] + }, + "Spatie.Ray": { + "icon": "", + "images": [] + }, + "SpeedCrunch.SpeedCrunch": { + "icon": "", + "images": [] + }, + "Spice.SpiceWebDAVd": { + "icon": "", + "images": [] + }, + "Spice.VDAgent": { + "icon": "", + "images": [] + }, + "Spicebrains.Instant-Eyedropper": { + "icon": "", + "images": [] + }, + "Splashtop.SOS": { + "icon": "", + "images": [] + }, + "Splashtop.SplashtopBusiness": { + "icon": "", + "images": [] + }, + "Splashtop.SplashtopPersonal": { + "icon": "", + "images": [] + }, + "Splashtop.SplashtopWiredXDisplay": { + "icon": "", + "images": [] + }, + "Splawik.pytigon": { + "icon": "", + "images": [] + }, + "splode.pomotroid": { + "icon": "", + "images": [] + }, + "Splunk.ACS": { + "icon": "https://i.imgur.com/cne3Hul.png", + "images": [ + "https://user-images.githubusercontent.com/95648640/156843519-5825eec1-3f6c-484e-882d-f3a2b18fefd2.jpg" + ] + }, + "Splunk.UniversalForwarder": { + "icon": "", + "images": [] + }, + "spluxx.Protoman": { + "icon": "", + "images": [] + }, + "SpongeNobody.Clashy": { + "icon": "", + "images": [] + }, + "Spotify.Spotify": { + "icon": "https://cdn-icons-png.flaticon.com/512/174/174872.png", + "images": [ + "https://i.ibb.co/q5x5C1b/spotify-1.png", + "https://i.ibb.co/XFF0Xp5/spotify-2.png", + "https://i.ibb.co/fx3NjzD/spotify-3.png", + "https://i.ibb.co/p10nvWp/spotify-4.png", + "https://i.ibb.co/hKRcB2B/spotify-5.png", + "https://i.ibb.co/kgzyKdP/spotify-6.png", + "https://i.ibb.co/FHrbs1w/spotify-7.png" + ] + }, + "sprout2000.Elephicon": { + "icon": "", + "images": [] + }, + "sprout2000.LeafView": { + "icon": "", + "images": [] + }, + "sprout2000.LeafView-Tauri": { + "icon": "", + "images": [] + }, + "Spyder.Spyder": { + "icon": "", + "images": [] + }, + "sqlectron.sqlectron-gui": { + "icon": "", + "images": [] + }, + "squalou.google-chat-linux": { + "icon": "", + "images": [] + }, + "Squitch.Tess": { + "icon": "", + "images": [] + }, + "srjuddington.slade": { + "icon": "", + "images": [] + }, + "SSBC.Patchwork": { + "icon": "", + "images": [] + }, + "SSHFS-Win.SSHFS-Win": { + "icon": "", + "images": [] + }, + "Stackers.Stack": { + "icon": "", + "images": [] + }, + "stackless.stackless": { + "icon": "", + "images": [] + }, + "stacks.stacks": { + "icon": "", + "images": [] + }, + "stakira.OpenUTAU": { + "icon": "", + "images": [] + }, + "StandardNotes.StandardNotes": { + "icon": "", + "images": [] + }, + "staniel359.muffon": { + "icon": "", + "images": [] + }, + "Stardock.Curtains": { + "icon": "", + "images": [] + }, + "Stardock.Fences": { + "icon": "", + "images": [] + }, + "Stardock.Start10": { + "icon": "", + "images": [] + }, + "Stardock.Start11": { + "icon": "", + "images": [] + }, + "StarfaceGmbH.StarfaceUCC": { + "icon": "", + "images": [] + }, + "StarfaceGmbH.StarfaceUCC.Beta": { + "icon": "", + "images": [] + }, + "starscape.creatorstudio": { + "icon": "", + "images": [] + }, + "Starship.Starship": { + "icon": "", + "images": [] + }, + "StartIsBack.StartAllBack": { + "icon": "", + "images": [] + }, + "StartIsBack.StartIsBack": { + "icon": "", + "images": [] + }, + "Startpack.Firework": { + "icon": "", + "images": [] + }, + "SteamGridDB.RomManager": { + "icon": "", + "images": [] + }, + "Steccas.ProtonClient": { + "icon": "", + "images": [] + }, + "stedolan.jq": { + "icon": "", + "images": [] + }, + "SteelSeries.GG": { + "icon": "", + "images": [] + }, + "SteelSeries.SteelSeriesEngine": { + "icon": "", + "images": [] + }, + "StefanMalzner.Franz": { + "icon": "", + "images": [] + }, + "StefansTools.BowPad": { + "icon": "", + "images": [] + }, + "StefansTools.grepWin": { + "icon": "", + "images": [] + }, + "StefanSundin.Superf4": { + "icon": "", + "images": [] + }, + "StefHeyenrath.GitHubReleaseNotes": { + "icon": "", + "images": [] + }, + "StellarDataRecovery.StellarExtract\u2026": { + "icon": "", + "images": [] + }, + "Stellarium.Stellarium": { + "icon": "", + "images": [] + }, + "StephanDilly.gitui": { + "icon": "", + "images": [] + }, + "StepMania.StepMania": { + "icon": "", + "images": [] + }, + "stevencohn.OneMore": { + "icon": "", + "images": [] + }, + "StevenCole.Coffee": { + "icon": "", + "images": [] + }, + "steventhanna.proton": { + "icon": "", + "images": [] + }, + "stnkl.EverythingToolbar": { + "icon": "", + "images": [ + "https://i.postimg.cc/P5hMrSG5/IfpkHAX.png" + ] + }, + "stnkl.EverythingToolbar.Beta": { + "icon": "", + "images": [] + }, + "Stoplight.Prism": { + "icon": "", + "images": [] + }, + "Stoplight.Spectral": { + "icon": "", + "images": [] + }, + "Stoplight.Studio": { + "icon": "", + "images": [] + }, + "StrawberryMusicPlayer.Strawberry": { + "icon": "", + "images": [] + }, + "StrawberryPerl.StrawberryPerl": { + "icon": "", + "images": [] + }, + "Stream-Pi.Client": { + "icon": "", + "images": [] + }, + "Stream-Pi.Server": { + "icon": "", + "images": [] + }, + "Streamlabs.Streamlabs": { + "icon": "", + "images": [] + }, + "Streamlabs.StreamlabsOBS": { + "icon": "", + "images": [] + }, + "Streamlink.Streamlink": { + "icon": "", + "images": [] + }, + "Streamlink.Streamlink.TwitchGui": { + "icon": "", + "images": [] + }, + "Streetwriters.Notesnook": { + "icon": "", + "images": [] + }, + "Stremio.Stremio": { + "icon": "", + "images": [] + }, + "Stretchly.Stretchly": { + "icon": "", + "images": [] + }, + "Stride.Stride": { + "icon": "", + "images": [] + }, + "strimio.strimio": { + "icon": "", + "images": [] + }, + "StudioRack.StudioRack": { + "icon": "", + "images": [] + }, + "StudioXID.ProtoPie": { + "icon": "https://i.imgur.com/bsk6EpG.png", + "images": [] + }, + "Stuffmatic.fSpy": { + "icon": "", + "images": [] + }, + "StylusLabs.Write": { + "icon": "", + "images": [] + }, + "subhra74.XtremeDownloadManager": { + "icon": "", + "images": [] + }, + "SublimeHQ.SublimeMerge": { + "icon": "", + "images": [] + }, + "SublimeHQ.SublimeMerge.Dev": { + "icon": "", + "images": [] + }, + "SublimeHQ.SublimeText.3": { + "icon": "", + "images": [] + }, + "SublimeHQ.SublimeText.4": { + "icon": "", + "images": [] + }, + "Subsurface.Subsurface": { + "icon": "", + "images": [] + }, + "sufone.qawl": { + "icon": "", + "images": [] + }, + "sum1re.CaptionOCRTool": { + "icon": "", + "images": [] + }, + "SumatraPDF.SumatraPDF": { + "icon": "", + "images": [] + }, + "sunabozu.subordination": { + "icon": "", + "images": [] + }, + "sunzongzheng.music": { + "icon": "", + "images": [] + }, + "SUPERAntiSpyware.SUPERAntiSpyware": { + "icon": "", + "images": [] + }, + "SuperCollider.SuperCollider": { + "icon": "", + "images": [] + }, + "Supernova.SupernovaPlayer": { + "icon": "", + "images": [] + }, + "supertiger1234.nertivia": { + "icon": "", + "images": [] + }, + "SuperTux.SuperTux": { + "icon": "", + "images": [] + }, + "SuperTuxKart.SuperTuxKart": { + "icon": "", + "images": [] + }, + "surajrathod.eagluet": { + "icon": "", + "images": [] + }, + "SURF.eduVPNClient": { + "icon": "", + "images": [] + }, + "SURF.LetsConnectClient": { + "icon": "", + "images": [] + }, + "SurgeSynth.Surge": { + "icon": "", + "images": [] + }, + "suse.RancherDesktop": { + "icon": "", + "images": [] + }, + "Suwayomi.Tachidesk-JUI": { + "icon": "", + "images": [] + }, + "Suwayomi.Tachidesk-Server": { + "icon": "", + "images": [] + }, + "Suwayomi.Tachidesk-Sorayomi": { + "icon": "", + "images": [] + }, + "SVGExplorerExtension.SVGExplorerEx\u2026": { + "icon": "", + "images": [] + }, + "SVZsoft.GEDKeeper": { + "icon": "", + "images": [] + }, + "sw4you.Hardcopy": { + "icon": "", + "images": [] + }, + "SweetScape.010Editor": { + "icon": "https://insmac.org/uploads/posts/2018-10/1539323096_010-editor.png", + "images": [ + "https://www.sweetscape.com/screenshots/TourS.GIF", + "https://www.sweetscape.com/screenshots/010EdCalculator.GIF", + "https://www.sweetscape.com/screenshots/010EdCompareS.GIF" + ] + }, + "SWI-Prolog.SWI-Prolog": { + "icon": "", + "images": [] + }, + "Swift.Toolchain": { + "icon": "", + "images": [] + }, + "swiftyapp.swifty": { + "icon": "", + "images": [] + }, + "SwingTeam.Pendulums": { + "icon": "", + "images": [] + }, + "sylikc.JPEGView": { + "icon": "", + "images": [] + }, + "Symflower.SymflowerCLI": { + "icon": "", + "images": [] + }, + "Syncplay.Syncplay.Beta": { + "icon": "", + "images": [] + }, + "Syncplify.Server": { + "icon": "", + "images": [] + }, + "SyncTrayzor.SyncTrayzor": { + "icon": "", + "images": [] + }, + "syndicode.iNFektNFOViewer": { + "icon": "", + "images": [] + }, + "Synology.ActiveBackupForBusinessAg\u2026": { + "icon": "", + "images": [] + }, + "Synology.ChatClient": { + "icon": "", + "images": [] + }, + "Synology.DriveClient": { + "icon": "", + "images": [] + }, + "Synology.NoteStationClient": { + "icon": "", + "images": [] + }, + "Synthesia.Synthesia": { + "icon": "", + "images": [] + }, + "Sysprogs.SmarTTY": { + "icon": "", + "images": [] + }, + "SystemExplorer.SystemExplorer": { + "icon": "", + "images": [] + }, + "Systweak.DuplicateMusicFixer": { + "icon": "", + "images": [] + }, + "SystweakSoftware.AdvancedDiskRecov\u2026": { + "icon": "", + "images": [] + }, + "SystweakSoftware.AdvancedDriverUpd\u2026": { + "icon": "", + "images": [] + }, + "SystweakSoftware.AdvancedSystemOpt\u2026": { + "icon": "", + "images": [] + }, + "SystweakSoftware.DuplicateFilesFix\u2026": { + "icon": "", + "images": [] + }, + "SystweakSoftware.DuplicatePhotosFi\u2026": { + "icon": "", + "images": [] + }, + "SystweakSoftware.RegCleanPro": { + "icon": "", + "images": [] + }, + "SystweakSoftware.SystweakSoftwareU\u2026": { + "icon": "", + "images": [] + }, + "syvaidya.openstego": { + "icon": "", + "images": [] + }, + "szTheory.exifcleaner": { + "icon": "", + "images": [] + }, + "t1m0thyj.WinDynamicDesktop": { + "icon": "", + "images": [ + "https://i.imgur.com/p0zCEdQ.png" + ] + }, + "Tableau.Desktop": { + "icon": "", + "images": [] + }, + "Tableau.Public": { + "icon": "", + "images": [] + }, + "Tableau.Reader": { + "icon": "", + "images": [] + }, + "TablePlus.TablePlus": { + "icon": "", + "images": [] + }, + "tagspaces.tagspaces": { + "icon": "", + "images": [] + }, + "Taiko2k.TauonMusicBox": { + "icon": "", + "images": [] + }, + "tailscale.tailscale": { + "icon": "", + "images": [] + }, + "TailwindLabs.TailwindCSS": { + "icon": "", + "images": [] + }, + "Taisei.Taisei": { + "icon": "", + "images": [] + }, + "TaiStudio.Sofia": { + "icon": "", + "images": [] + }, + "Talkdesk.Callbar": { + "icon": "", + "images": [] + }, + "Talkdesk.Talkdesk": { + "icon": "", + "images": [] + }, + "tangshimin.TypingLearner": { + "icon": "", + "images": [] + }, + "tanshuai.alphabiz": { + "icon": "https://i.imgur.com/O9hDfyE.png", + "images": [ + "https://alpha.biz/media/app_img_dark.jpg", + "https://windows-cdn.softpedia.com/screenshots/Alphabiz_1.png", + "https://windows-cdn.softpedia.com/screenshots/Alphabiz_2.png", + "https://windows-cdn.softpedia.com/screenshots/Alphabiz_3.png", + "https://windows-cdn.softpedia.com/screenshots/Alphabiz_4.png", + "https://windows-cdn.softpedia.com/screenshots/Alphabiz_5.png", + "https://windows-cdn.softpedia.com/screenshots/Alphabiz_6.png", + "https://windows-cdn.softpedia.com/screenshots/Alphabiz_7.png", + "https://windows-cdn.softpedia.com/screenshots/Alphabiz_8.png", + "https://windows-cdn.softpedia.com/screenshots/Alphabiz_8.png" + ] + }, + "Taozuhong.Kangaroo": { + "icon": "", + "images": [] + }, + "TarakSharma.Nighthawk": { + "icon": "", + "images": [] + }, + "TaskcadeInc.Taskade": { + "icon": "", + "images": [] + }, + "tastyworks.tastyworks": { + "icon": "", + "images": [] + }, + "Tautulli.Tautulli": { + "icon": "", + "images": [] + }, + "tazzben.Assessment-Disaggregation": { + "icon": "", + "images": [ + "https://windows-cdn.softpedia.com/screenshots/Assessment-Disaggregation_1.jpg" + ] + }, + "team-aie.aie": { + "icon": "", + "images": [] + }, + "TeamDriveSystems.TeamDrive": { + "icon": "", + "images": [] + }, + "TeamLidarr.Lidarr": { + "icon": "", + "images": [] + }, + "TeamProwlarr.Prowlarr": { + "icon": "", + "images": [] + }, + "TeamRadarr.Radarr": { + "icon": "", + "images": [] + }, + "TeamShinkansen.Hakchi2-CE": { + "icon": "", + "images": [] + }, + "TeamSonarr.Sonarr": { + "icon": "", + "images": [] + }, + "TeamSpeakSystems.TeamSpeakClient": { + "icon": "https://img001.prntscr.com/file/img001/aG60yNoTRDq_hlSMrV4e1A.png", + "images": [ + "https://discourse-forums-images.s3.dualstack.us-east-2.amazonaws.com/original/3X/0/5/05c2a7459eb5d5b5e25c09ca695d4497808cb91a.png", + "https://img001.prntscr.com/file/img001/aG60yNoTRDq_hlSMrV4e1A.png", + "https://img001.prntscr.com/file/img001/BPXQQa1DSQGtNMZOEMAR3A.png" + ] + }, + "TeamViewer.TeamViewer": { + "icon": "https://static.teamviewer.com/resources/2019/07/TeamViewer_Logo_512x512.png", + "images": [ + "https://static.teamviewer.com/resources/2018/09/BauhausHowItWorks-RemoteControl.png", + "https://static.teamviewer.com/resources/2021/01/online-meeting-with-teamviewer-meeting.png", + "https://static.teamviewer.com/resources/2018/05/android.png" + ] + }, + "TeamViewer.TeamViewer.Host": { + "icon": "https://static.teamviewer.com/resources/2019/07/TeamViewer_Logo_512x512.png", + "images": [] + }, + "TeaSpeak.TeaClient": { + "icon": "", + "images": [] + }, + "TechPowerUp.GPU-Z": { + "icon": "https://tpucdn.com/images/news/tpu-v1669381101081.png", + "images": [ + "https://www.techpowerup.com/img/11-03-21/126a.jpg" + ] + }, + "TechPowerUp.NVCleanstall": { + "icon": "https://tpucdn.com/download/images/133_icon-v1669381101081.png", + "images": [ + "https://tpucdn.com/nvcleanstall/screen-2-v1669381101081.png" + ] + }, + "TechSmith.Camtasia": { + "icon": "", + "images": [] + }, + "TechSmith.Snagit.2020": { + "icon": "", + "images": [] + }, + "TechSmith.Snagit.2021": { + "icon": "", + "images": [] + }, + "TechSmith.Snagit.2022": { + "icon": "", + "images": [] + }, + "Telegram.TelegramDesktop": { + "icon": "https://i.imgur.com/at0VmW2.png", + "images": [] + }, + "Telegram.TelegramDesktop.Beta": { + "icon": "", + "images": [] + }, + "Telerik.Fiddler.Classic": { + "icon": "", + "images": [] + }, + "Telerik.Fiddler.Everywhere": { + "icon": "", + "images": [] + }, + "Telerik.Fiddler.Everywhere.Insiders": { + "icon": "", + "images": [] + }, + "Tenable.Nessus": { + "icon": "", + "images": [] + }, + "Tencent.ArtHub": { + "icon": "", + "images": [] + }, + "Tencent.COSBrowser": { + "icon": "", + "images": [] + }, + "Tencent.COSCLI": { + "icon": "", + "images": [] + }, + "Tencent.DeskGo": { + "icon": "", + "images": [] + }, + "Tencent.EDU": { + "icon": "", + "images": [] + }, + "Tencent.EDULite": { + "icon": "", + "images": [] + }, + "Tencent.Foxmail": { + "icon": "", + "images": [] + }, + "Tencent.QiDian": { + "icon": "", + "images": [] + }, + "Tencent.QMProxyAccelerator": { + "icon": "", + "images": [] + }, + "Tencent.QQ": { + "icon": "https://qzonestyle.gtimg.cn/qzone/qzact/act/external/tiqq/logo.png", + "images": [] + }, + "Tencent.qq-devtool": { + "icon": "", + "images": [] + }, + "Tencent.QQBrowser": { + "icon": "", + "images": [] + }, + "Tencent.QQMusic": { + "icon": "https://i.postimg.cc/VLdpMRY5/QQMusic.png", + "images": [] + }, + "Tencent.QQPinyin": { + "icon": "", + "images": [] + }, + "Tencent.QQPlayer": { + "icon": "", + "images": [] + }, + "Tencent.QQWubi": { + "icon": "", + "images": [] + }, + "Tencent.START": { + "icon": "", + "images": [] + }, + "Tencent.TencentDocs": { + "icon": "", + "images": [] + }, + "Tencent.TencentMeeting": { + "icon": "", + "images": [] + }, + "Tencent.TencentMeetingRooms": { + "icon": "", + "images": [] + }, + "Tencent.TencentVideo": { + "icon": "", + "images": [] + }, + "Tencent.TIM": { + "icon": "", + "images": [] + }, + "Tencent.TranSmart": { + "icon": "", + "images": [] + }, + "Tencent.VooVMeeting": { + "icon": "", + "images": [] + }, + "Tencent.WeChat": { + "icon": "", + "images": [] + }, + "Tencent.wechat-work": { + "icon": "", + "images": [] + }, + "Tencent.WeixinDevTools": { + "icon": "", + "images": [] + }, + "Tencent.Weiyun": { + "icon": "", + "images": [] + }, + "Tencent.WeiyunSync": { + "icon": "", + "images": [] + }, + "Tencent.WemeetOutlookPlugin": { + "icon": "", + "images": [] + }, + "Tencent.WeSing": { + "icon": "", + "images": [] + }, + "Tencent.WeSingLiveAssistant": { + "icon": "", + "images": [] + }, + "Tencent.YingYongBao": { + "icon": "", + "images": [] + }, + "Tenpi.MusicPlayer": { + "icon": "", + "images": [] + }, + "Tenpi.PhotoViewer": { + "icon": "", + "images": [] + }, + "Tenpi.VideoPlayer": { + "icon": "", + "images": [] + }, + "Tenpi.Waifu2xGUI": { + "icon": "", + "images": [] + }, + "Teraskull.PyDebloatX": { + "icon": "", + "images": [] + }, + "TeraTermProject.teraterm": { + "icon": "", + "images": [] + }, + "terkelg.ramme": { + "icon": "", + "images": [] + }, + "Terminals.Terminals": { + "icon": "", + "images": [] + }, + "Termius.Termius": { + "icon": "", + "images": [] + }, + "testmace.testmace": { + "icon": "", + "images": [] + }, + "Tetrate.func-e": { + "icon": "", + "images": [] + }, + "TexasInstruments.TI-Nspire.Compute\u2026": { + "icon": "", + "images": [] + }, + "TexasInstruments.TI-Nspire.CXCASSt\u2026": { + "icon": "", + "images": [] + }, + "TexasInstruments.TI-Nspire.CXPremi\u2026": { + "icon": "", + "images": [] + }, + "TexasInstruments.TI-Nspire.CXStude\u2026": { + "icon": "", + "images": [] + }, + "TexasInstruments.TI-SmartView.Math\u2026": { + "icon": "", + "images": [] + }, + "TexasInstruments.TI-SmartView.TI-8\u2026": { + "icon": "", + "images": [] + }, + "TexasInstruments.TI-SmartView.TI-83": { + "icon": "", + "images": [] + }, + "TexasInstruments.TI-SmartView.TI-C\u2026": { + "icon": "", + "images": [] + }, + "TexasInstruments.TIConnect": { + "icon": "", + "images": [] + }, + "Texmaker.Texmaker": { + "icon": "", + "images": [] + }, + "Texnomic.SecureDNS-Terminal": { + "icon": "", + "images": [] + }, + "TeXstudio.TeXstudio": { + "icon": "", + "images": [] + }, + "TGRMNSoftware.BulkRenameUtility": { + "icon": "", + "images": [] + }, + "th-ch.YouTubeMusic": { + "icon": "", + "images": [] + }, + "ThaddeusMcCleary.Seatsmart": { + "icon": "", + "images": [] + }, + "thamara.time-to-leave": { + "icon": "", + "images": [] + }, + "ThatOneCalculator.DiscordRPCMaker": { + "icon": "", + "images": [] + }, + "ThaUnknown.Miru": { + "icon": "", + "images": [] + }, + "the-sz.Auburn": { + "icon": "https://the-sz.com/products/auburn/auburn_icon.png", + "images": [ + "https://the-sz.com/products/auburn/auburn.png", + "https://i.imgur.com/NomYphG.jpg" + ] + }, + "the-sz.Bear": { + "icon": "https://the-sz.com/products/bear/bear_icon.png", + "images": [ + "https://the-sz.com/products/bear/delta_small.jpg", + "https://the-sz.com/products/bear/details_small.jpg", + "https://the-sz.com/products/bear/logging_small.jpg", + "https://the-sz.com/products/bear/bear7.jpg", + "https://the-sz.com/products/bear/bear.jpg" + ] + }, + "the-sz.Bedford": { + "icon": "https://the-sz.com/products/bedford/bedford_icon.png", + "images": [ + "https://the-sz.com/products/bedford/bedford.png" + ] + }, + "the-sz.Bennett": { + "icon": "", + "images": [] + }, + "the-sz.Carroll": { + "icon": "", + "images": [] + }, + "the-sz.CDInfo": { + "icon": "", + "images": [] + }, + "the-sz.CheckSum": { + "icon": "", + "images": [] + }, + "the-sz.Compton": { + "icon": "", + "images": [] + }, + "the-sz.Conroe": { + "icon": "", + "images": [] + }, + "the-sz.CPUGrabEx": { + "icon": "", + "images": [] + }, + "the-sz.Doro": { + "icon": "", + "images": [] + }, + "the-sz.FlashBuilder": { + "icon": "", + "images": [] + }, + "the-sz.Grand": { + "icon": "", + "images": [] + }, + "the-sz.Homedale": { + "icon": "", + "images": [] + }, + "the-sz.Howard": { + "icon": "", + "images": [] + }, + "the-sz.Lacey": { + "icon": "", + "images": [] + }, + "the-sz.Malden": { + "icon": "", + "images": [] + }, + "the-sz.Medford": { + "icon": "", + "images": [] + }, + "the-sz.Nassau": { + "icon": "", + "images": [] + }, + "the-sz.NetChat": { + "icon": "", + "images": [] + }, + "the-sz.Newfield": { + "icon": "", + "images": [] + }, + "the-sz.Norwood": { + "icon": "", + "images": [] + }, + "the-sz.Parkdale": { + "icon": "", + "images": [] + }, + "the-sz.PortScan": { + "icon": "", + "images": [] + }, + "the-sz.Quartz": { + "icon": "", + "images": [] + }, + "the-sz.Redwood": { + "icon": "", + "images": [] + }, + "the-sz.Richmond": { + "icon": "", + "images": [] + }, + "the-sz.Rimhill": { + "icon": "", + "images": [] + }, + "the-sz.Royal": { + "icon": "", + "images": [] + }, + "the-sz.Seaside": { + "icon": "", + "images": [] + }, + "the-sz.Sherwood": { + "icon": "", + "images": [] + }, + "the-sz.SkypeFocusFix": { + "icon": "", + "images": [] + }, + "the-sz.Spencer": { + "icon": "", + "images": [] + }, + "the-sz.SpyEx": { + "icon": "", + "images": [] + }, + "the-sz.Temple": { + "icon": "", + "images": [] + }, + "the-sz.Trion": { + "icon": "", + "images": [] + }, + "the-sz.Yale": { + "icon": "", + "images": [] + }, + "the-sz.York": { + "icon": "", + "images": [] + }, + "TheDocumentFoundation.LibreOffice": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/9/97/LibreOffice_icon_3.3.1_48_px.svg/200px-LibreOffice_icon_3.3.1_48_px.svg.png", + "images": [ + "https://www.libreoffice.org/assets/Uploads/writer-2020.png", + "https://www.libreoffice.org/assets/Uploads/calc-2020.png", + "https://www.libreoffice.org/assets/Uploads/impress-2020.png", + "https://www.libreoffice.org/assets/Uploads/draw-2020.png" + ] + }, + "TheDocumentFoundation.LibreOffice.\u2026": { + "icon": "", + "images": [] + }, + "TheGoddessInari.Hamsket": { + "icon": "", + "images": [] + }, + "theIYD.coursehunt": { + "icon": "", + "images": [] + }, + "TheOSCARTeam.OSCAR": { + "icon": "", + "images": [] + }, + "TheOtterlord.DeckMaster": { + "icon": "", + "images": [] + }, + "ThePBone.GalaxyBudsClient": { + "icon": "", + "images": [] + }, + "ThePyzoteam.pyzo": { + "icon": "", + "images": [] + }, + "TheTTRTeam.ToontownRewritten": { + "icon": "https://i.postimg.cc/XJzHGLmW/Toontown-Logo-Icon.png", + "images": [] + }, + "ThielickeITSolutions.TIPP10": { + "icon": "", + "images": [] + }, + "ThinkingManSoftware.Dimension4": { + "icon": "", + "images": [] + }, + "ThomasJames.Tajpi": { + "icon": "", + "images": [] + }, + "thomasnordquist.MQTT-Explorer": { + "icon": "", + "images": [] + }, + "thomasnordquist.MQTT-Explorer.Beta": { + "icon": "", + "images": [] + }, + "Threema.Threema": { + "icon": "", + "images": [] + }, + "THS.THS.Hevo": { + "icon": "", + "images": [] + }, + "Thunder.Xmp": { + "icon": "", + "images": [] + }, + "Thunisoft.HuayuPY": { + "icon": "", + "images": [] + }, + "tibbo.ioninja": { + "icon": "", + "images": [] + }, + "TIDALMusicAS.TIDAL": { + "icon": "", + "images": [] + }, + "TidyCustoms.Publii": { + "icon": "", + "images": [] + }, + "TigerVNCproject.TigerVNC": { + "icon": "", + "images": [] + }, + "TigerVNCproject.TigerVNC.Nightly": { + "icon": "", + "images": [] + }, + "TikzEdt.TikzEdtBeta": { + "icon": "", + "images": [] + }, + "Tiled.Tiled": { + "icon": "", + "images": [] + }, + "Timber1900.WebDL": { + "icon": "", + "images": [] + }, + "timche.gmail-desktop": { + "icon": "", + "images": [] + }, + "timedomain.acestudio": { + "icon": "https://pbs.twimg.com/profile_images/1547177547330355200/7J8zlbZB_400x400.png", + "images": [ + "https://as-api.ws-cdn-1.timedomain.tech/resource/official/image/brochure1.webp", + "https://i.ytimg.com/vi/TpU9VZrtJdg/hqdefault.jpg", + "https://i0.hdslb.com/bfs/archive/6488ae88b2c585a838a7e878192c4c92740e0410.jpg", + "https://as-api.ws-cdn-1.timedomain.tech/resource/official/image/brochure2.webp" + ] + }, + "TimVisee.ffsend": { + "icon": "", + "images": [] + }, + "TinyCAD.TinyCAD": { + "icon": "", + "images": [] + }, + "titinko.utsu": { + "icon": "", + "images": [] + }, + "Toborek.rBiblia": { + "icon": "", + "images": [] + }, + "TobyAllen.DocTo": { + "icon": "", + "images": [] + }, + "TobySuggate.GitFiend": { + "icon": "", + "images": [] + }, + "Toggl.ToggleTrack": { + "icon": "", + "images": [] + }, + "Toinane.Colorpicker": { + "icon": "", + "images": [] + }, + "Toit.Jaguar": { + "icon": "", + "images": [] + }, + "TominLab.WonderPen": { + "icon": "", + "images": [] + }, + "tomlm.electron-outlook-365": { + "icon": "", + "images": [] + }, + "tomlm.electron-outlook-com": { + "icon": "", + "images": [] + }, + "TomWatson.BreakTimer": { + "icon": "", + "images": [] + }, + "Tonec.InternetDownloadManager": { + "icon": "", + "images": [] + }, + "TonyPottier.ImageView": { + "icon": "", + "images": [] + }, + "TopalaSoftwareSolutions.SIW": { + "icon": "", + "images": [] + }, + "TopazLabs.TopazDeNoiseAI": { + "icon": "", + "images": [] + }, + "TopazLabs.TopazGigapixelAI": { + "icon": "", + "images": [] + }, + "TopazLabs.TopazPhotoAI": { + "icon": "", + "images": [] + }, + "TopazLabs.TopazSharpenAI": { + "icon": "", + "images": [] + }, + "TopazLabs.TopazVideoEnhanceAI": { + "icon": "", + "images": [] + }, + "Torchsoft.RegistryWorkshop": { + "icon": "", + "images": [] + }, + "TorProject.TorBrowser": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/c/c9/Tor_Browser_icon.svg/800px-Tor_Browser_icon.svg.png", + "images": [] + }, + "TortoiseGit.TortoiseGit": { + "icon": "", + "images": [] + }, + "TortoiseHg.TortoiseHg": { + "icon": "", + "images": [] + }, + "TortoiseSVN.TortoiseSVN": { + "icon": "", + "images": [] + }, + "TossLab.JANDI": { + "icon": "", + "images": [] + }, + "TotallyUsefulSoftware.QuickSFV": { + "icon": "", + "images": [] + }, + "touchbyte.PhotoSync": { + "icon": "", + "images": [] + }, + "Tox.qTox": { + "icon": "", + "images": [] + }, + "TrackerSoftware.PDF-Tools": { + "icon": "", + "images": [] + }, + "TrackerSoftware.PDF-XChangeEditor": { + "icon": "", + "images": [] + }, + "TrackerSoftware.PDF-XChangePRO": { + "icon": "", + "images": [] + }, + "TrackerSoftware.PDF-XChangeStandard": { + "icon": "", + "images": [] + }, + "TrackerSoftware.PDF-XChangeViewer": { + "icon": "", + "images": [] + }, + "TradingView.TradingViewDesktop": { + "icon": "", + "images": [] + }, + "TradingView.TradingViewDesktop.Beta": { + "icon": "", + "images": [] + }, + "Trados.TradosStudio.2021": { + "icon": "", + "images": [] + }, + "Trados.TradosStudio.2022": { + "icon": "", + "images": [] + }, + "TransIP.STACK": { + "icon": "", + "images": [] + }, + "Transmission.Transmission": { + "icon": "", + "images": [] + }, + "trazyn.weweChat": { + "icon": "", + "images": [] + }, + "TreasureData.TDAgent": { + "icon": "", + "images": [] + }, + "Trelby.Trelby": { + "icon": "", + "images": [] + }, + "Tribler.Tribler": { + "icon": "", + "images": [] + }, + "Tricentis.NeoLoad": { + "icon": "", + "images": [] + }, + "Trigone.SystemMonitor": { + "icon": "", + "images": [] + }, + "Trillian.Trillian": { + "icon": "https://i.imgur.com/QPPJo3s.png", + "images": [] + }, + "Trimble.SketchUp.Pro.2022": { + "icon": "", + "images": [] + }, + "trinsic.cli": { + "icon": "", + "images": [] + }, + "trinsic.okapi": { + "icon": "", + "images": [] + }, + "Trivia-Bot-Apps.trivia-desktop": { + "icon": "", + "images": [] + }, + "tropy.tropy": { + "icon": "", + "images": [] + }, + "Trufflesuite.Ganache": { + "icon": "", + "images": [] + }, + "TrustedRu.CryptoARMGOST": { + "icon": "", + "images": [] + }, + "TTKN.CAJViewer": { + "icon": "", + "images": [] + }, + "TTKN.CAJViewer.Simple": { + "icon": "", + "images": [] + }, + "TTKN.CNKIExpress": { + "icon": "", + "images": [] + }, + "TTYPlus.MTPutty": { + "icon": "", + "images": [] + }, + "TUG.TeXworks": { + "icon": "", + "images": [] + }, + "TUitTUWien.TUtoolbox": { + "icon": "", + "images": [] + }, + "Tunepack.Tunepack": { + "icon": "", + "images": [] + }, + "TunesKit.AceMovi": { + "icon": "https://acemovi.tuneskit.com/images/acemovi.svg", + "images": [ + "https://techbullion.com/wp-content/uploads/2021/07/TunesKit-AceMovi-Video-Editor-1000x600.jpg", + "https://acemovi.tuneskit.com/images/product/edit-video-v4.jpg", + "https://static.filehorse.com/screenshots/video-software/tuneskit-acemovi-screenshot-05.png", + "https://acemovi.tuneskit.com/images/video-editor/interface-mac.png", + "https://screenshots.macupdate.com/JPG/63486/63486_1633616496_scr_uc2.jpg" + ] + }, + "TunnelBear.TunnelBear": { + "icon": "", + "images": [] + }, + "tushev.org.AJUpdateWatcher": { + "icon": "", + "images": [] + }, + "Tutanota.Tutanota": { + "icon": "", + "images": [] + }, + "TuxGuitar.TuxGuitar": { + "icon": "", + "images": [] + }, + "Tweaking4All.RenameMyTVSeries": { + "icon": "", + "images": [] + }, + "TweakingTechnologies.TweakShotScre\u2026": { + "icon": "", + "images": [] + }, + "TwibrightLabs.Links": { + "icon": "", + "images": [] + }, + "Twilio.Authy": { + "icon": "https://i.imgur.com/MoOmCvE.png", + "images": [ + "https://i.postimg.cc/MTpwRF4x/1.png", + "https://i.postimg.cc/R0R9WBgX/2.png", + "https://i.postimg.cc/50KVmmdz/3.png", + "https://authy.com/wp-content/uploads/tw1.png", + "https://authy.com/wp-content/uploads/2018-07-27_1440.png" + ] + }, + "twinkstar.browser": { + "icon": "", + "images": [] + }, + "Twistedst.scale-serial-reader": { + "icon": "", + "images": [] + }, + "Twitch.Soundtrack": { + "icon": "", + "images": [] + }, + "Twitch.TwitchStudio": { + "icon": "", + "images": [] + }, + "TwonotesAudioEngineering.TorpedoRe\u2026": { + "icon": "", + "images": [] + }, + "Tympanix.Electorrent": { + "icon": "", + "images": [] + }, + "TypeFaster.TypeFaster": { + "icon": "", + "images": [] + }, + "TypingInnovationGroup.TypingMaster": { + "icon": "", + "images": [] + }, + "Tyrrrz.LightBulb": { + "icon": "", + "images": [] + }, + "UB-Mannheim.TesseractOCR": { + "icon": "", + "images": [] + }, + "UbiquitiInc.UI": { + "icon": "https://i.imgur.com/kTVX1t5.png", + "images": [] + }, + "Ubisoft.Connect": { + "icon": "https://play-lh.googleusercontent.com/f868E2XQBpfl677hykMnZ4_HlKqrOs0fUhuwy0TC9ZI_PQLn99RtBV2kQ7Z50OtQkw", + "images": [ + "https://i.postimg.cc/y8dkPRcT/14621efe-9306-44f5-ade6-b0eebe217a5f.png" + ] + }, + "UCBerkeley.BOINC": { + "icon": "", + "images": [] + }, + "UdiFuchs.UFRaw": { + "icon": "", + "images": [] + }, + "uGetdm.uGet": { + "icon": "", + "images": [] + }, + "ULAB.PaintAid": { + "icon": "", + "images": [] + }, + "UlrichStrautz.Kurvenprofi": { + "icon": "", + "images": [] + }, + "Ultimaker.Cura": { + "icon": "", + "images": [] + }, + "Ultra.Ultra": { + "icon": "", + "images": [] + }, + "UltraDefrag.UltraDefrag": { + "icon": "", + "images": [] + }, + "ultrapico.expresso": { + "icon": "", + "images": [] + }, + "UMEZAWATakeshi.UtvideoCodecSuite": { + "icon": "", + "images": [] + }, + "Unchecky.Unchecky": { + "icon": "", + "images": [] + }, + "undergroundwires.privacy.sexy": { + "icon": "", + "images": [] + }, + "unetbootin.unetbootin": { + "icon": "", + "images": [] + }, + "UnicornSoft.UnicornHTTPS": { + "icon": "", + "images": [] + }, + "UnifiedIntents.UnifiedRemote": { + "icon": "", + "images": [] + }, + "Unigine.HeavenBenchmark": { + "icon": "", + "images": [] + }, + "Unigine.SuperpositionBenchmark": { + "icon": "", + "images": [] + }, + "Unigine.ValleyBenchmark": { + "icon": "", + "images": [] + }, + "Unity.Unity.2020": { + "icon": "", + "images": [] + }, + "Unity.Unity.2021": { + "icon": "", + "images": [] + }, + "Unity.Unity.2022": { + "icon": "", + "images": [] + }, + "Unity.UnityHub": { + "icon": "", + "images": [] + }, + "UniversalMediaServer.UniversalMedi\u2026": { + "icon": "https://www.universalmediaserver.com/assets/img/logo.png", + "images": [] + }, + "UniversityOfEdinburgh.QuPath": { + "icon": "", + "images": [] + }, + "UniversityofLjubljana.Orange": { + "icon": "", + "images": [] + }, + "UniversityOfWaikato.Weka": { + "icon": "", + "images": [] + }, + "UniversityOfWashington.Foldit": { + "icon": "", + "images": [] + }, + "univrsal.input-overlay": { + "icon": "", + "images": [] + }, + "univrsal.scrab": { + "icon": "", + "images": [] + }, + "univrsal.tuna": { + "icon": "", + "images": [] + }, + "unlimited-clipboard.unlimited-clip\u2026": { + "icon": "", + "images": [] + }, + "UnlimitedBacon.STL-Thumb": { + "icon": "", + "images": [] + }, + "USEPA.EPANET": { + "icon": "", + "images": [] + }, + "uvncbvba.UltraVnc": { + "icon": "", + "images": [] + }, + "uw-labs.BloomRPC": { + "icon": "", + "images": [] + }, + "UweDrechsel.vym": { + "icon": "", + "images": [] + }, + "uxmal.reko": { + "icon": "", + "images": [] + }, + "V.MAILLE.EduPython": { + "icon": "", + "images": [] + }, + "v2raya.win": { + "icon": "", + "images": [] + }, + "VaclavSlavik.Poedit": { + "icon": "", + "images": [] + }, + "Vajehdan.Vajehdan": { + "icon": "", + "images": [] + }, + "valinet.ExplorerPatcher": { + "icon": "", + "images": [] + }, + "valinet.ExplorerPatcher.Prerelease": { + "icon": "", + "images": [] + }, + "Valve.Steam": { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/8/83/Steam_icon_logo.svg/512px-Steam_icon_logo.svg.png", + "images": [ + "https://i.postimg.cc/wMp1cbQt/Steam-service.png" + ] + }, + "variar.klogg": { + "icon": "", + "images": [] + }, + "vassalengine.VASSAL": { + "icon": "", + "images": [] + }, + "VB-Audio.Voicemeeter": { + "icon": "", + "images": [] + }, + "VB-Audio.Voicemeeter.Banana": { + "icon": "", + "images": [] + }, + "VB-Audio.Voicemeeter.Potato": { + "icon": "", + "images": [] + }, + "VCVRack.VCVRack": { + "icon": "", + "images": [] + }, + "vcync.modV": { + "icon": "", + "images": [] + }, + "Vector000.bilive_electron": { + "icon": "", + "images": [] + }, + "Velocidex.Velociraptor": { + "icon": "", + "images": [] + }, + "Veloren.Airshipper": { + "icon": "https://i.imgur.com/I6HBlap.jpg", + "images": [ + "https://linuxmasterclub.com/wp-content/uploads/2021/06/Veloren.-Airshipper-Launcher.png", + "https://upload.wikimedia.org/wikipedia/commons/thumb/d/df/Airshipper.png/580px-Airshipper.png" + ] + }, + "venko.ClassicGenerator": { + "icon": "", + "images": [] + }, + "VentisMedia.MediaMonkey": { + "icon": "", + "images": [] + }, + "Vercel.Hyper": { + "icon": "", + "images": [] + }, + "Versa.MagiCut": { + "icon": "", + "images": [] + }, + "Vertexshare.WebpConverter": { + "icon": "", + "images": [] + }, + "VeyonSolutions.Veyon": { + "icon": "", + "images": [] + }, + "Viber.Viber": { + "icon": "https://i.imgur.com/NNuAkJi.png", + "images": [] + }, + "VideoLAN.VLC": { + "icon": "https://i.imgur.com/k4W1Nm1.png", + "images": [ + "https://i.imgur.com/3AOZ20t.png" + ] + }, + "VideoLAN.VLC.Nightly": { + "icon": "", + "images": [] + }, + "VideoLAN.x264": { + "icon": "", + "images": [] + }, + "ViewSonic.myViewBoard.Display": { + "icon": "", + "images": [] + }, + "ViewSonic.myViewBoard.Whiteboard": { + "icon": "", + "images": [] + }, + "ViGEm.HidHide": { + "icon": "", + "images": [] + }, + "ViGEm.ViGEmBus": { + "icon": "", + "images": [] + }, + "vim.vim": { + "icon": "", + "images": [] + }, + "VinaySajip.PythonLauncher": { + "icon": "", + "images": [] + }, + "VincentL.Harmony": { + "icon": "", + "images": [] + }, + "VirtualDesktop.Streamer": { + "icon": "", + "images": [] + }, + "VirtualGL.TurboVNC": { + "icon": "", + "images": [] + }, + "VirtualGL.VirtualGL": { + "icon": "", + "images": [] + }, + "VirtualHere.USBClient": { + "icon": "", + "images": [] + }, + "VirtualHere.USBServer": { + "icon": "", + "images": [] + }, + "VirtualMagnifyingGlass.VirtualMagn\u2026": { + "icon": "", + "images": [] + }, + "VirusTotal.VirusTotalUploader": { + "icon": "", + "images": [] + }, + "VisualParadigm.Community": { + "icon": "", + "images": [] + }, + "VisualSVNSoftwareLtd.VisualSVNRepo\u2026": { + "icon": "", + "images": [] + }, + "VisualSVNSoftwareLtd.VisualSVNServ\u2026": { + "icon": "", + "images": [] + }, + "Vitzo.ClipClip": { + "icon": "", + "images": [] + }, + "VivaldiTechnologies.Vivaldi": { + "icon": "", + "images": [] + }, + "VivaldiTechnologies.Vivaldi.Snapsh\u2026": { + "icon": "", + "images": [] + }, + "ViviCorporation.Vivi": { + "icon": "", + "images": [] + }, + "VividDesigns.WifiMouseServer": { + "icon": "", + "images": [] + }, + "vividos.winLAME": { + "icon": "", + "images": [] + }, + "VKontakte.VKMessenger": { + "icon": "", + "images": [] + }, + "VladimirYakovlev.ElectronMail": { + "icon": "", + "images": [] + }, + "VMPK.VMPK": { + "icon": "", + "images": [] + }, + "VMware.HorizonClient": { + "icon": "", + "images": [] + }, + "VMware.IntelligentHub": { + "icon": "", + "images": [] + }, + "VMware.WorkstationPlayer": { + "icon": "", + "images": [ + "https://i.postimg.cc/BZTLQ4J2/Captura-de-pantalla-28.png" + ] + }, + "VMware.WorkstationPro": { + "icon": "", + "images": [] + }, + "VNGCorp.Zalo": { + "icon": "", + "images": [] + }, + "Vogan.TinyCodes": { + "icon": "", + "images": [] + }, + "VoiceAttack.VoiceAttack": { + "icon": "", + "images": [] + }, + "Voicemod.Voicemod": { + "icon": "", + "images": [] + }, + "voidtools.Everything": { + "icon": "", + "images": [ + "https://i.postimg.cc/RZRL3w9Q/Everything-Search-Window.png" + ] + }, + "voidtools.Everything.Alpha": { + "icon": "", + "images": [] + }, + "voidtools.Everything.Lite": { + "icon": "", + "images": [] + }, + "VolkerFischer.Jamulus": { + "icon": "", + "images": [] + }, + "Volta.Volta": { + "icon": "", + "images": [] + }, + "VoodooSoft.VoodooShield": { + "icon": "", + "images": [] + }, + "VOWSoft.iBackupBot": { + "icon": "", + "images": [] + }, + "VoyagerX.Vrew": { + "icon": "", + "images": [] + }, + "VPNetwork.TorGuard": { + "icon": "", + "images": [] + }, + "Vromans.ChordPro": { + "icon": "", + "images": [] + }, + "VSCodium.VSCodium": { + "icon": "", + "images": [ + "https://upload.wikimedia.org/wikipedia/commons/thumb/e/e9/VS_Code_%28Insiders%29.png/800px-VS_Code_%28Insiders%29.png?20210728074118" + ] + }, + "VSCodium.VSCodium.Insiders": { + "icon": "", + "images": [] + }, + "VSDC.Editor": { + "icon": "", + "images": [] + }, + "VSDC.ScreenRecorder": { + "icon": "", + "images": [] + }, + "vSpatialInc.vSpatialRemoteDesktop": { + "icon": "", + "images": [] + }, + "Vysor.Vysor": { + "icon": "", + "images": [] + }, + "Wacom.WacomTabletDriver": { + "icon": "https://upload.wikimedia.org/wikipedia/en/thumb/7/7e/Wacom_Logo_WhiteType.svg/254px-Wacom_Logo_WhiteType.svg.png", + "images": [] + }, + "wagesj45.butterflow-ui": { + "icon": "", + "images": [] + }, + "Wago.Addons": { + "icon": "", + "images": [] + }, + "wahao.Electron-iGot": { + "icon": "", + "images": [] + }, + "WalkoverTechnologies.giddh": { + "icon": "", + "images": [] + }, + "wandersick.AeroZoom": { + "icon": "https://files.softicons.com/download/system-icons/atrous-windows-7-icons-by-iconleak/png/128x128/3.png", + "images": [ + "https://1.bp.blogspot.com/-05uPDrjnQUY/YNiKZT5BWoI/AAAAAAAACzs/pr9bRpTToYAdFvS8UdBoJRzCm9xQiaLMwCLcBGAsYHQ/s0/5583194454_3a71e20ed9_o.png", + "https://1.bp.blogspot.com/-_NeTJC2TBD8/YNiKvj52v1I/AAAAAAAACz0/3BiOYcvyb3ITeyD5Ka7VA3HYbSBgfGgagCLcBGAsYHQ/s0/aerozoom-v1-gui_1.png", + "https://i.imgur.com/DTQGB13.png", + "https://farm8.staticflickr.com/7880/47203430182_17c98b2bee_o.gif" + ] + }, + "wandersick.ChMac": { + "icon": "", + "images": [] + }, + "wandersick.EnglishizeCmd": { + "icon": "", + "images": [] + }, + "wangyu.BilibiliVideoDownload": { + "icon": "", + "images": [] + }, + "Wargaming.GameCenter": { + "icon": "", + "images": [] + }, + "Wargaming.WorldOfWarshipsModStation": { + "icon": "", + "images": [] + }, + "Warzone2100Project.Warzone2100": { + "icon": "", + "images": [] + }, + "WasmEdge.WasmEdge": { + "icon": "", + "images": [] + }, + "Wasmer.Wasmer": { + "icon": "", + "images": [] + }, + "WatchGuardTechnologies.WatchGuardS\u2026": { + "icon": "", + "images": [] + }, + "WaterbugStudios.Mazerator": { + "icon": "", + "images": [] + }, + "WaterbugStudios.MazeratorOld": { + "icon": "", + "images": [] + }, + "Waterfox.Waterfox": { + "icon": "", + "images": [] + }, + "Waterfox.Waterfox.Classic": { + "icon": "", + "images": [] + }, + "Watfaq.PowerSession": { + "icon": "", + "images": [] + }, + "WavesAudio.WavesCentral": { + "icon": "", + "images": [] + }, + "Wazuh.WazuhAgent": { + "icon": "", + "images": [] + }, + "WeakAuras.WeakAurasCompanion": { + "icon": "", + "images": [] + }, + "webberg.civet": { + "icon": "", + "images": [] + }, + "Webcamoid.Webcamoid": { + "icon": "", + "images": [] + }, + "webrecorder.replayweb-page": { + "icon": "", + "images": [] + }, + "Webroot.SecureAnywhere": { + "icon": "", + "images": [] + }, + "Webyog.SQLyogCommunity": { + "icon": "", + "images": [] + }, + "WeMod.WeMod": { + "icon": "", + "images": [] + }, + "WeMod.WeMod.Beta": { + "icon": "", + "images": [] + }, + "WereDev.Wu10Man": { + "icon": "", + "images": [] + }, + "WerWolv.ImHex": { + "icon": "", + "images": [] + }, + "Wesnoth.BattleForWesnoth": { + "icon": "https://i.imgur.com/sn1MXX5.png", + "images": [ + "https://www.wesnoth.org/images/sshots/wesnoth-1.16.0-1.jpg", + "https://www.wesnoth.org/images/sshots/wesnoth-1.16.0-2.jpg", + "https://www.wesnoth.org/images/sshots/wesnoth-1.16.0-3.jpg", + "https://www.wesnoth.org/images/sshots/wesnoth-1.16.0-4.jpg", + "https://www.wesnoth.org/images/sshots/wesnoth-1.16.0-5.jpg" + ] + }, + "WestWind.MarkdownMonster": { + "icon": "", + "images": [] + }, + "wethat.onenotetaggingkit": { + "icon": "", + "images": [] + }, + "Wetransform.HaleStudio": { + "icon": "", + "images": [] + }, + "WeVPN.WeVPN": { + "icon": "", + "images": [] + }, + "wexond.wexond": { + "icon": "", + "images": [] + }, + "wez.wezterm": { + "icon": "", + "images": [] + }, + "WhatPulse.WhatPulse": { + "icon": "", + "images": [] + }, + "WhatsApp.WhatsApp": { + "icon": "https://i.imgur.com/sGkly3m.png", + "images": [] + }, + "WhatsApp.WhatsApp.Beta": { + "icon": "", + "images": [] + }, + "wherewhere.APKInstaller.Classic": { + "icon": "https://github.com/Paving-Base/APK-Installer-Classic/raw/main/logo.png", + "images": [ + "https://github.com/Paving-Base/APK-Installer-Classic/raw/main/Images/Guides/Snipaste_2019-10-12_22-46-37.png", + "https://github.com/Paving-Base/APK-Installer-Classic/raw/main/Images/Guides/Snipaste_2019-10-19_15-28-58.png", + "https://github.com/Paving-Base/APK-Installer-Classic/raw/main/Images/Guides/Snipaste_2019-10-20_23-36-44.png", + "https://github.com/Paving-Base/APK-Installer-Classic/raw/main/Images/Guides/Snipaste_2019-10-13_12-42-40.png", + "https://github.com/Paving-Base/APK-Installer-Classic/raw/main/Images/Screenshots/Snipaste_2022-01-03_01-07-53.png" + ] + }, + "wherewhere.WSATools": { + "icon": "", + "images": [] + }, + "WhirlwindFX.SignalRgb": { + "icon": "", + "images": [] + }, + "whitewaterfoundry.fedora-remix-for\u2026": { + "icon": "", + "images": [] + }, + "whyboris.Video-Hub-App.Demo": { + "icon": "", + "images": [] + }, + "WidelandsDevelopmentTeam.Widelands": { + "icon": "", + "images": [] + }, + "WikidPad.WikidPad": { + "icon": "", + "images": [] + }, + "WikidPad.WikidPad.Alpha": { + "icon": "", + "images": [] + }, + "WikimediaProject.Huggle": { + "icon": "", + "images": [] + }, + "WilbertBerendsen.Frescobaldi": { + "icon": "", + "images": [] + }, + "WildfireGames.0AD": { + "icon": "https://cdn.icon-icons.com/icons2/1381/PNG/512/0ad_93511.png", + "images": [ + "https://play0ad.com/wp-content/gallery/carousel/thumbs/thumbs_Kushcitycenter.jpg", + "https://play0ad.com/wp-content/gallery/carousel/thumbs/thumbs_EgyptianPyramids.jpg", + "https://play0ad.com/wp-content/gallery/carousel/thumbs/thumbs_CarthaginianTown.jpg", + "https://play0ad.com/wp-content/gallery/carousel/thumbs/thumbs_MacedonPort.jpg", + "https://play0ad.com/wp-content/gallery/carousel/thumbs/thumbs_water-rubble.jpg", + "https://play0ad.com/wp-content/gallery/carousel/thumbs/thumbs_PersianTradeRoute.jpg", + "https://play0ad.com/wp-content/gallery/carousel/thumbs/thumbs_Treasure.jpg", + "https://play0ad.com/wp-content/gallery/carousel/thumbs/thumbs_Pericles.jpeg", + "https://play0ad.com/wp-content/gallery/carousel/thumbs/thumbs_%20Iberian%20Town.jpeg", + "https://play0ad.com/wp-content/gallery/carousel/thumbs/thumbs_SpartanTown.jpg", + "https://play0ad.com/wp-content/gallery/carousel/thumbs/thumbs_mauryan-structures.jpg", + "https://play0ad.com/wp-content/gallery/carousel/thumbs/thumbs_BabylonParadise.jpg", + "https://play0ad.com/wp-content/gallery/carousel/thumbs/thumbs_MauryanColony.jpg", + "https://play0ad.com/wp-content/gallery/carousel/thumbs/thumbs_BritsAbroad.jpg", + "https://play0ad.com/wp-content/gallery/carousel/thumbs/thumbs_tilt-shift-filter.jpeg", + "https://play0ad.com/wp-content/gallery/carousel/thumbs/thumbs_water-specular.jpg", + "https://play0ad.com/wp-content/gallery/carousel/thumbs/thumbs_athenian_gymnasion.jpg", + "https://play0ad.com/wp-content/gallery/carousel/thumbs/thumbs_elapuba.jpg", + "https://play0ad.com/wp-content/gallery/carousel/thumbs/thumbs_celtbroch.jpg" + ] + }, + "willnewii.qiniuClient": { + "icon": "", + "images": [] + }, + "WillowSoftware.AnvilStudio": { + "icon": "https://anvilstudio.com/s/logo175_163.jpg", + "images": [ + "https://imag.malavida.com/mvimgbig/download-fs/anvil-studio-15716-3.jpg", + "https://cdn.afterdawn.fi/screenshots/normal/19840.jpg", + "https://img.informer.com/screenshots/2963/2963166_1.jpg", + "https://img.informer.com/screenshots/2963/2963166_2.jpg", + "https://img.informer.com/screenshots/2963/2963166_3.jpg", + "https://img.informer.com/screenshots/2963/2963166_4.jpg" + ] + }, + "Win32diskimager.win32diskimager": { + "icon": "", + "images": [] + }, + "Winamp.Winamp": { + "icon": "https://i.imgur.com/gSQ2mle.png", + "images": [ + "https://i.imgur.com/WASmcBJ.png" + ] + }, + "Winbee.cashcash": { + "icon": "", + "images": [] + }, + "WinDirStat.WinDirStat": { + "icon": "", + "images": [] + }, + "Windows-Spotlight.Windows-Spotlight": { + "icon": "", + "images": [] + }, + "WindowsPostInstallWizard.Universal\u2026": { + "icon": "", + "images": [] + }, + "Windscribe.Windscribe": { + "icon": "", + "images": [] + }, + "WindSolutions.CopyTransControlCent\u2026": { + "icon": "", + "images": [] + }, + "WinFsp.WinFsp": { + "icon": "", + "images": [] + }, + "WinMerge.WinMerge": { + "icon": "https://en.wikipedia.org/wiki/WinMerge#/media/File:WinMergeLogo.png", + "images": [ + "https://winmerge.org/screenshots/filecmp.png" + ] + }, + "WinMerge.WinMerge.Beta": { + "icon": "https://en.wikipedia.org/wiki/WinMerge#/media/File:WinMergeLogo.png", + "images": [ + "https://winmerge.org/screenshots/filecmp.png" + ] + }, + "winpython.winpython": { + "icon": "", + "images": [] + }, + "winpython.winpython-dot": { + "icon": "", + "images": [] + }, + "winpython.winpython-dot-pypy": { + "icon": "", + "images": [] + }, + "winpython.winpython-pypy": { + "icon": "", + "images": [] + }, + "WinSCP.WinSCP": { + "icon": "https://en.wikipedia.org/wiki/WinSCP#/media/File:WinSCP_Logo.png", + "images": [ + "https://winscp-static-746341.c.cdn77.org/data/media/screenshots/commander.png?v=7006", + "https://winscp-static-746341.c.cdn77.org/data/media/screenshots/explorer.png?v=7006", + "https://winscp-static-746341.c.cdn77.org/data/media/screenshots/login.png?v=7006" + ] + }, + "WinSCP.WinSCP.RC": { + "icon": "", + "images": [] + }, + "wire.wire": { + "icon": "", + "images": [] + }, + "WireGuard.WireGuard": { + "icon": "", + "images": [] + }, + "WiresharkFoundation.Wireshark": { + "icon": "", + "images": [] + }, + "Wiris.MathType7": { + "icon": "", + "images": [] + }, + "WisdomSoftware.AutoScreenRecorder": { + "icon": "https://i0.wp.com/filecr.com/wp-content/uploads/2019/11/AutoScreenRecorder-Pro-icon.png", + "images": [ + "https://windows-cdn.softpedia.com/screenshots/AutoScreenRecorder-Pro_10.png", + "https://windows-cdn.softpedia.com/screenshots/AutoScreenRecorder-Pro_11.png", + "https://windows-cdn.softpedia.com/screenshots/AutoScreenRecorder-Pro_12.png", + "https://windows-cdn.softpedia.com/screenshots/AutoScreenRecorder-Pro_13.png" + ] + }, + "WisdomSoftware.FreeMediaPlayer": { + "icon": "", + "images": [] + }, + "WisdomSoftware.MotionGIF": { + "icon": "", + "images": [] + }, + "WisdomSoftware.MotionStudio": { + "icon": "", + "images": [] + }, + "WisdomSoftware.ScreenHunter": { + "icon": "", + "images": [] + }, + "WiseCleaner.WiseADCleaner": { + "icon": "", + "images": [] + }, + "WiseCleaner.WiseCare365": { + "icon": "", + "images": [] + }, + "WiseCleaner.WiseDataRecovery": { + "icon": "", + "images": [] + }, + "WiseCleaner.WiseDiskCleaner": { + "icon": "", + "images": [] + }, + "WiseCleaner.WiseDuplicateFinder": { + "icon": "", + "images": [] + }, + "WiseCleaner.WiseFolderHider": { + "icon": "", + "images": [] + }, + "WiseCleaner.WiseGameBooster": { + "icon": "", + "images": [] + }, + "WiseCleaner.WiseHotKey": { + "icon": "", + "images": [] + }, + "WiseCleaner.WiseMemoryOptimizer": { + "icon": "", + "images": [] + }, + "WiseCleaner.WiseProgramUninstaller": { + "icon": "", + "images": [] + }, + "WiseCleaner.WiseRegistryCleaner": { + "icon": "", + "images": [] + }, + "WiseCleaner.WiseToys": { + "icon": "", + "images": [] + }, + "WizardsoftheCoast.MTGALauncher": { + "icon": "", + "images": [] + }, + "wiznote.wiznote": { + "icon": "", + "images": [] + }, + "wiznote.wiznotelite": { + "icon": "", + "images": [] + }, + "wkhtmltopdf.wkhtmltox": { + "icon": "", + "images": [] + }, + "WolframResearch.WolframEngine": { + "icon": "", + "images": [] + }, + "Wondershare.Anireel": { + "icon": "", + "images": [] + }, + "Wondershare.CreativeCenter": { + "icon": "", + "images": [] + }, + "Wondershare.Cropro": { + "icon": "", + "images": [] + }, + "Wondershare.DemoCreator": { + "icon": "", + "images": [] + }, + "Wondershare.DemoCreator.CN": { + "icon": "", + "images": [] + }, + "Wondershare.DVDCreator": { + "icon": "", + "images": [] + }, + "Wondershare.FamiSafe": { + "icon": "", + "images": [] + }, + "Wondershare.Filmii": { + "icon": "", + "images": [] + }, + "Wondershare.Filmora": { + "icon": "", + "images": [] + }, + "Wondershare.Filmora.CN": { + "icon": "", + "images": [] + }, + "Wondershare.Filmora.Pro": { + "icon": "", + "images": [] + }, + "Wondershare.Fotophire.Focus": { + "icon": "", + "images": [] + }, + "Wondershare.Fotophire.Maximizer": { + "icon": "", + "images": [] + }, + "Wondershare.Fotophire.SlideshowMak\u2026": { + "icon": "", + "images": [] + }, + "Wondershare.Fotophire.Toolkit": { + "icon": "", + "images": [] + }, + "Wondershare.HiPDF": { + "icon": "", + "images": [] + }, + "Wondershare.InClowdz": { + "icon": "", + "images": [] + }, + "Wondershare.MirrorGo": { + "icon": "", + "images": [] + }, + "Wondershare.MobileTrans": { + "icon": "", + "images": [] + }, + "Wondershare.Mockitt.CN": { + "icon": "", + "images": [] + }, + "Wondershare.PDFConverter.Pro": { + "icon": "", + "images": [] + }, + "Wondershare.PDFelement.6": { + "icon": "", + "images": [] + }, + "Wondershare.PDFelement.6.Pro": { + "icon": "", + "images": [] + }, + "Wondershare.PDFelement.7": { + "icon": "", + "images": [] + }, + "Wondershare.PDFelement.8": { + "icon": "", + "images": [] + }, + "Wondershare.PDFelement.9": { + "icon": "", + "images": [] + }, + "Wondershare.PDFelement.CN": { + "icon": "", + "images": [] + }, + "Wondershare.PDFPasswordRemover": { + "icon": "", + "images": [] + }, + "Wondershare.PDFReader": { + "icon": "", + "images": [] + }, + "Wondershare.PDFReader.CN": { + "icon": "", + "images": [] + }, + "Wondershare.Recoverit": { + "icon": "", + "images": [] + }, + "Wondershare.Recoverit.CN": { + "icon": "", + "images": [] + }, + "Wondershare.Repairit": { + "icon": "", + "images": [] + }, + "Wondershare.Repairit.CN": { + "icon": "", + "images": [] + }, + "Wondershare.UBackit": { + "icon": "", + "images": [] + }, + "Wondershare.UniConverter": { + "icon": "", + "images": [] + }, + "Wondershare.UniConverter.13": { + "icon": "", + "images": [] + }, + "Wondershare.UniConverter.CN": { + "icon": "", + "images": [] + }, + "Wondershare.WXRecovery": { + "icon": "", + "images": [] + }, + "wordmark.wordmark": { + "icon": "", + "images": [] + }, + "WorkdayInc.PlanningforExcel": { + "icon": "", + "images": [] + }, + "workman-layout.workman": { + "icon": "", + "images": [] + }, + "Workrave.Workrave": { + "icon": "", + "images": [] + }, + "WorksMobile.NAVERWORKS": { + "icon": "", + "images": [] + }, + "WowUp.Beta": { + "icon": "", + "images": [] + }, + "WowUp.Wowup": { + "icon": "", + "images": [] + }, + "Wox.Wox": { + "icon": "", + "images": [] + }, + "Woyun.wolai": { + "icon": "", + "images": [] + }, + "writage.writage": { + "icon": "", + "images": [] + }, + "X2go.x2goclient": { + "icon": "", + "images": [] + }, + "xanderfrangos.crushee": { + "icon": "", + "images": [] + }, + "xanderfrangos.twinkletray": { + "icon": "", + "images": [] + }, + "Xanthus58.AfformationRequester": { + "icon": "", + "images": [] + }, + "Xanthus58.PortalStillAlive": { + "icon": "", + "images": [] + }, + "Xanthus58.RockPaperScissorsCLI": { + "icon": "", + "images": [] + }, + "Xanthus58.Stanlys_Terminal": { + "icon": "", + "images": [] + }, + "Xanthus58.ValorantRandomizer": { + "icon": "", + "images": [] + }, + "Xanthus58.VanillaRenewed": { + "icon": "", + "images": [] + }, + "XavierRoche.HTTrack": { + "icon": "", + "images": [] + }, + "XBMCFoundation.Kodi": { + "icon": "", + "images": [] + }, + "Xcas.Xcas": { + "icon": "", + "images": [] + }, + "XCP-ng.Center": { + "icon": "", + "images": [] + }, + "xgi.houdoku": { + "icon": "", + "images": [] + }, + "Xiaoe.Xiaoetong": { + "icon": "", + "images": [] + }, + "Xiaomi.MiService": { + "icon": "", + "images": [] + }, + "Xiaomi.MIUI+": { + "icon": "", + "images": [] + }, + "Xiaomi.XiaomiCloud": { + "icon": "", + "images": [] + }, + "xiaozhu188.electron-vue-cloud-music": { + "icon": "", + "images": [] + }, + "XiboSignage.XiboPlayer": { + "icon": "", + "images": [] + }, + "Xidicone.AgentGit": { + "icon": "", + "images": [] + }, + "Xidicone.AgentSVN": { + "icon": "https://www.zeusedit.com/agent/images/agent_icon.png", + "images": [] + }, + "Xidicone.ZeusIDE": { + "icon": "", + "images": [] + }, + "Xidicone.ZeusLite": { + "icon": "", + "images": [] + }, + "xiles.NexusFont": { + "icon": "", + "images": [] + }, + "Ximalaya.Ximalaya": { + "icon": "", + "images": [] + }, + "Ximalaya.XimalayaLive": { + "icon": "", + "images": [] + }, + "xinpianchang.StudioTrans": { + "icon": "", + "images": [] + }, + "XK72.Charles": { + "icon": "", + "images": [] + }, + "XmacsLabs.Mogan": { + "icon": "", + "images": [] + }, + "Xmake-io.Xmake": { + "icon": "", + "images": [] + }, + "Xmind.Xmind": { + "icon": "", + "images": [] + }, + "Xmind.Xmind.8": { + "icon": "", + "images": [] + }, + "Xming.Xming": { + "icon": "", + "images": [] + }, + "XMoto.XMoto": { + "icon": "", + "images": [] + }, + "XnSoft.XnConvert": { + "icon": "", + "images": [] + }, + "XnSoft.XnView.Classic": { + "icon": "", + "images": [] + }, + "XnSoft.XnViewMP": { + "icon": "", + "images": [ + "https://i.postimg.cc/wTF1L2yv/xnviewmp-win-01.jpg" + ] + }, + "XSplit.Broadcaster": { + "icon": "", + "images": [] + }, + "XSplit.Broadcaster.PTR": { + "icon": "", + "images": [] + }, + "XSplit.VCam": { + "icon": "", + "images": [] + }, + "XunLei.xunlei": { + "icon": "", + "images": [] + }, + "xushengfeng.eSearch": { + "icon": "", + "images": [] + }, + "xwartz.PupaFM": { + "icon": "", + "images": [] + }, + "YACReader.YACReader": { + "icon": "", + "images": [] + }, + "YaCy.YaCy": { + "icon": "", + "images": [] + }, + "yafp.ttth": { + "icon": "", + "images": [] + }, + "Yandex.PuntoSwitcher": { + "icon": "", + "images": [] + }, + "yang991178.fluent-reader": { + "icon": "", + "images": [] + }, + "Yarn.Yarn": { + "icon": "", + "images": [] + }, + "YaSuenag.SimpleCom": { + "icon": "", + "images": [] + }, + "Yemiao.Xtranslator": { + "icon": "", + "images": [] + }, + "Yemiao.ZhiyunTranslator": { + "icon": "", + "images": [] + }, + "YendisEntertainment.KrunkerClient": { + "icon": "", + "images": [] + }, + "YikuanSun.WebKitty": { + "icon": "", + "images": [] + }, + "YmSoft.Nalgaeset": { + "icon": "", + "images": [] + }, + "yomail.yomail": { + "icon": "", + "images": [] + }, + "Youdao.YoudaoDict": { + "icon": "", + "images": [] + }, + "Youdao.YoudaoNote": { + "icon": "", + "images": [] + }, + "Youku.Youku": { + "icon": "", + "images": [] + }, + "Youqu.ToDesk": { + "icon": "", + "images": [] + }, + "youtube-dl.youtube-dl": { + "icon": "", + "images": [] + }, + "YouXiao.YXCalendar": { + "icon": "", + "images": [] + }, + "YouXiao.YXFile": { + "icon": "", + "images": [] + }, + "YoYoGames.GameMaker.Studio.1": { + "icon": "", + "images": [] + }, + "yt-dlg.yt-dlg": { + "icon": "", + "images": [ + "https://user-images.githubusercontent.com/73800734/200966245-8fff1730-9a02-4e35-b660-f9e30a37d342.png" + ] + }, + "yt-dlp.yt-dlp": { + "icon": "", + "images": [] + }, + "Ytmdesktop.Ytmdesktop": { + "icon": "https://i.imgur.com/YigQor4.png", + "images": [ + "https://i.imgur.com/BUrjOd1.png", + "https://i.imgur.com/lsgvfHR.png", + "https://i.imgur.com/yGGs3uL.png" + ] + }, + "Yuanli.uTools": { + "icon": "", + "images": [] + }, + "Yubico.Authenticator": { + "icon": "", + "images": [] + }, + "Yubico.Authenticator.Beta": { + "icon": "", + "images": [] + }, + "Yubico.YubikeyManager": { + "icon": "", + "images": [] + }, + "Yubico.YubiKeyPersonalizationTool": { + "icon": "", + "images": [] + }, + "YutakaSawada.MultiPar": { + "icon": "", + "images": [] + }, + "zafaco.Breitbandmessung": { + "icon": "", + "images": [] + }, + "zeankundev.suside": { + "icon": "", + "images": [] + }, + "ZelloInc.Zello": { + "icon": "", + "images": [] + }, + "ZeroTier.ZeroTierOne": { + "icon": "", + "images": [] + }, + "Zettlr.Zettlr": { + "icon": "", + "images": [] + }, + "ZeusSoftware.nGlide": { + "icon": "", + "images": [] + }, + "zhaopengme.gitnote": { + "icon": "", + "images": [] + }, + "Zheguisoft.zg_mdm": { + "icon": "", + "images": [] + }, + "Zheguisoft.zg_pkg": { + "icon": "", + "images": [] + }, + "Zheguisoft.zg_print": { + "icon": "", + "images": [] + }, + "Zheguisoft.zg_upload": { + "icon": "", + "images": [] + }, + "Zheguisoft.zg-ipchat": { + "icon": "", + "images": [] + }, + "Zheguisoft.zg-zsso": { + "icon": "", + "images": [] + }, + "ZhornSoftware.Stickies": { + "icon": "", + "images": [] + }, + "Zimwiki.Zim": { + "icon": "", + "images": [] + }, + "Zint.Zint": { + "icon": "", + "images": [] + }, + "Zoho.ZohoMail.Desktop": { + "icon": "", + "images": [] + }, + "zokugun.MrCode": { + "icon": "", + "images": [] + }, + "Zoom.Zoom": { + "icon": "https://i.postimg.cc/SjtH36PD/ZoomIcon.png", + "images": [ + "https://i.postimg.cc/HW0dsF59/Zoom1.png", + "https://i.postimg.cc/pXqvK8s9/Zoom2.png", + "https://i.postimg.cc/52yVg0rs/Zoom3.png" + ] + }, + "Zoom.ZoomOutlookPlugin": { + "icon": "", + "images": [] + }, + "Zoom.ZoomRooms": { + "icon": "", + "images": [] + }, + "Zotero.Zotero": { + "icon": "", + "images": [] + }, + "Zulip.Zulip": { + "icon": "", + "images": [] + }, + "zumoshi.BrowserSelect": { + "icon": "", + "images": [] + }, + "Zwift.Zwift": { + "icon": "", + "images": [] + }, + "zxch3n.PomodoroLogger": { + "icon": "", + "images": [] + }, + "Zype.Compass": { + "icon": "", + "images": [] + } + }, + "scoop": { + "1password-cli": { + "icon": "", + "images": [] + }, + "7zip": { + "icon": "https://i.postimg.cc/tJmcw1zX/7zip.png", + "images": [] + }, + "7zip19.00-helper": { + "icon": "", + "images": [] + }, + "abc": { + "icon": "", + "images": [] + }, + "ack": { + "icon": "", + "images": [] + }, + "acmesharp": { + "icon": "", + "images": [] + }, + "acorn": { + "icon": "", + "images": [] + }, + "act": { + "icon": "", + "images": [] + }, + "actionlint": { + "icon": "", + "images": [] + }, + "adb": { + "icon": "", + "images": [] + }, + "ag": { + "icon": "", + "images": [] + }, + "ahoy": { + "icon": "", + "images": [] + }, + "aks-engine": { + "icon": "", + "images": [] + }, + "alass": { + "icon": "", + "images": [] + }, + "algernon": { + "icon": "", + "images": [] + }, + "aliyun": { + "icon": "", + "images": [] + }, + "allure": { + "icon": "", + "images": [] + }, + "amass": { + "icon": "", + "images": [] + }, + "ammonite": { + "icon": "", + "images": [] + }, + "amulet": { + "icon": "", + "images": [] + }, + "android-clt": { + "icon": "", + "images": [] + }, + "ansicon": { + "icon": "", + "images": [] + }, + "ant": { + "icon": "", + "images": [] + }, + "apache": { + "icon": "", + "images": [] + }, + "apimtemplate": { + "icon": "", + "images": [] + }, + "apktool": { + "icon": "", + "images": [] + }, + "apngasm": { + "icon": "", + "images": [] + }, + "aqtinstall": { + "icon": "", + "images": [] + }, + "arc": { + "icon": "", + "images": [] + }, + "arduino-cli": { + "icon": "", + "images": [] + }, + "argo": { + "icon": "", + "images": [] + }, + "argocd": { + "icon": "", + "images": [] + }, + "argocd-autopilot": { + "icon": "", + "images": [] + }, + "aria2": { + "icon": "", + "images": [] + }, + "armclient": { + "icon": "", + "images": [] + }, + "armor": { + "icon": "", + "images": [] + }, + "arthas": { + "icon": "", + "images": [] + }, + "asciidoctorj": { + "icon": "", + "images": [] + }, + "aspell": { + "icon": "", + "images": [] + }, + "astyle": { + "icon": "", + "images": [] + }, + "atomicparsley": { + "icon": "", + "images": [] + }, + "austin": { + "icon": "", + "images": [] + }, + "autoit": { + "icon": "", + "images": [] + }, + "autossh": { + "icon": "", + "images": [] + }, + "avr-gcc": { + "icon": "", + "images": [] + }, + "avrdude": { + "icon": "", + "images": [] + }, + "avro-tools": { + "icon": "", + "images": [] + }, + "aws": { + "icon": "", + "images": [] + }, + "aws-amplify": { + "icon": "", + "images": [] + }, + "aws-copilot": { + "icon": "", + "images": [] + }, + "aws-ecs": { + "icon": "", + "images": [] + }, + "aws-iam-authenticator": { + "icon": "", + "images": [] + }, + "aws-nuke": { + "icon": "", + "images": [] + }, + "aws-sam-cli": { + "icon": "", + "images": [] + }, + "aws-vault": { + "icon": "", + "images": [] + }, + "awsqueue": { + "icon": "", + "images": [] + }, + "awsSts": { + "icon": "", + "images": [] + }, + "axel": { + "icon": "", + "images": [] + }, + "azcopy": { + "icon": "", + "images": [] + }, + "aztfy": { + "icon": "", + "images": [] + }, + "azure-cli": { + "icon": "", + "images": [] + }, + "azure-functions-core-tools": { + "icon": "", + "images": [] + }, + "azure-kubelogin": { + "icon": "", + "images": [] + }, + "azure-ps": { + "icon": "", + "images": [] + }, + "b2": { + "icon": "", + "images": [] + }, + "b2sum": { + "icon": "", + "images": [] + }, + "b3sum": { + "icon": "", + "images": [] + }, + "balena-cli": { + "icon": "", + "images": [] + }, + "bat": { + "icon": "", + "images": [] + }, + "bazel": { + "icon": "", + "images": [] + }, + "bazel-buildtools": { + "icon": "", + "images": [] + }, + "bbk-cli": { + "icon": "", + "images": [] + }, + "bc": { + "icon": "", + "images": [] + }, + "beef": { + "icon": "", + "images": [] + }, + "beehive": { + "icon": "", + "images": [] + }, + "bfg": { + "icon": "", + "images": [] + }, + "bicep": { + "icon": "", + "images": [] + }, + "binaryen": { + "icon": "", + "images": [] + }, + "bind": { + "icon": "", + "images": [] + }, + "binutils": { + "icon": "", + "images": [] + }, + "biodiff": { + "icon": "", + "images": [] + }, + "bison": { + "icon": "", + "images": [] + }, + "bit": { + "icon": "", + "images": [] + }, + "bitwarden-cli": { + "icon": "", + "images": [] + }, + "blat": { + "icon": "", + "images": [] + }, + "blink1-tool": { + "icon": "", + "images": [] + }, + "bochs": { + "icon": "", + "images": [] + }, + "bombardier": { + "icon": "", + "images": [] + }, + "boringproxy": { + "icon": "", + "images": [] + }, + "bottom": { + "icon": "", + "images": [] + }, + "boundary": { + "icon": "", + "images": [] + }, + "boxes": { + "icon": "", + "images": [] + }, + "brename": { + "icon": "", + "images": [] + }, + "broot": { + "icon": "", + "images": [] + }, + "brotli": { + "icon": "", + "images": [] + }, + "bt2qbt": { + "icon": "", + "images": [] + }, + "btop": { + "icon": "", + "images": [] + }, + "btop-lhm": { + "icon": "", + "images": [] + }, + "btyacc": { + "icon": "", + "images": [] + }, + "buck": { + "icon": "", + "images": [] + }, + "buf": { + "icon": "", + "images": [] + }, + "buffalo": { + "icon": "", + "images": [] + }, + "bulk-rename-command": { + "icon": "", + "images": [] + }, + "busybox": { + "icon": "", + "images": [] + }, + "busybox-lean": { + "icon": "", + "images": [] + }, + "butterflow": { + "icon": "", + "images": [] + }, + "byacc": { + "icon": "", + "images": [] + }, + "byenow": { + "icon": "", + "images": [] + }, + "bzip2": { + "icon": "", + "images": [] + }, + "cacert": { + "icon": "", + "images": [] + }, + "caddy": { + "icon": "", + "images": [] + }, + "cake": { + "icon": "", + "images": [] + }, + "camunda-operate": { + "icon": "", + "images": [] + }, + "capstone": { + "icon": "", + "images": [] + }, + "carvel-vendir": { + "icon": "", + "images": [] + }, + "castxml": { + "icon": "", + "images": [] + }, + "ccache": { + "icon": "", + "images": [] + }, + "ccat": { + "icon": "", + "images": [] + }, + "ccl": { + "icon": "", + "images": [] + }, + "cdrtools": { + "icon": "", + "images": [] + }, + "centrifugo": { + "icon": "", + "images": [] + }, + "cfr": { + "icon": "", + "images": [] + }, + "cfsec": { + "icon": "", + "images": [] + }, + "cheat": { + "icon": "", + "images": [] + }, + "chezmoi": { + "icon": "", + "images": [] + }, + "chisel": { + "icon": "", + "images": [] + }, + "chkcpu": { + "icon": "", + "images": [] + }, + "chroma": { + "icon": "", + "images": [] + }, + "chromedriver": { + "icon": "", + "images": [] + }, + "chronograf": { + "icon": "", + "images": [] + }, + "cht": { + "icon": "", + "images": [] + }, + "chuck": { + "icon": "", + "images": [] + }, + "circleci-cli": { + "icon": "", + "images": [] + }, + "clangd": { + "icon": "", + "images": [] + }, + "clash": { + "icon": "", + "images": [] + }, + "clash.meta": { + "icon": "", + "images": [] + }, + "clink": { + "icon": "", + "images": [] + }, + "clink-completions": { + "icon": "", + "images": [] + }, + "clink-flex-prompt": { + "icon": "", + "images": [] + }, + "cloak": { + "icon": "", + "images": [] + }, + "cloc": { + "icon": "", + "images": [] + }, + "cloud-nuke": { + "icon": "", + "images": [] + }, + "cloud-sql-proxy": { + "icon": "", + "images": [] + }, + "cloudflared": { + "icon": "", + "images": [] + }, + "cmake": { + "icon": "", + "images": [] + }, + "cmder": { + "icon": "", + "images": [] + }, + "cmder-full": { + "icon": "", + "images": [] + }, + "cobalt": { + "icon": "", + "images": [] + }, + "cockroachdb": { + "icon": "", + "images": [] + }, + "codeowners-validator": { + "icon": "", + "images": [] + }, + "codeql": { + "icon": "", + "images": [] + }, + "coder": { + "icon": "", + "images": [] + }, + "colortool": { + "icon": "", + "images": [] + }, + "composer": { + "icon": "", + "images": [] + }, + "conan": { + "icon": "", + "images": [] + }, + "concfg": { + "icon": "", + "images": [] + }, + "concourse-fly": { + "icon": "", + "images": [] + }, + "conftest": { + "icon": "", + "images": [] + }, + "connect": { + "icon": "", + "images": [] + }, + "consul": { + "icon": "", + "images": [] + }, + "containerd": { + "icon": "", + "images": [] + }, + "coq": { + "icon": "", + "images": [] + }, + "coredns": { + "icon": "", + "images": [] + }, + "coreutils": { + "icon": "", + "images": [] + }, + "cormanlisp": { + "icon": "", + "images": [] + }, + "cosign": { + "icon": "", + "images": [] + }, + "coursier": { + "icon": "", + "images": [] + }, + "cowsay": { + "icon": "", + "images": [] + }, + "cppcheck": { + "icon": "", + "images": [] + }, + "cpufetch": { + "icon": "", + "images": [] + }, + "crc": { + "icon": "", + "images": [] + }, + "croc": { + "icon": "", + "images": [] + }, + "cscope": { + "icon": "", + "images": [] + }, + "csview": { + "icon": "", + "images": [] + }, + "csvtosql": { + "icon": "", + "images": [] + }, + "ctags": { + "icon": "", + "images": [] + }, + "ctop": { + "icon": "", + "images": [] + }, + "cuda": { + "icon": "", + "images": [] + }, + "cue": { + "icon": "", + "images": [] + }, + "curl": { + "icon": "", + "images": [] + }, + "curlie": { + "icon": "", + "images": [] + }, + "cvs": { + "icon": "", + "images": [] + }, + "cwrsync": { + "icon": "", + "images": [] + }, + "cygwin": { + "icon": "", + "images": [] + }, + "czkawka": { + "icon": "", + "images": [] + }, + "dafny": { + "icon": "", + "images": [] + }, + "dagger": { + "icon": "", + "images": [] + }, + "danser-go": { + "icon": "", + "images": [] + }, + "dapr-cli": { + "icon": "", + "images": [] + }, + "dark": { + "icon": "", + "images": [] + }, + "dart": { + "icon": "", + "images": [] + }, + "datamash": { + "icon": "", + "images": [] + }, + "dbmate": { + "icon": "", + "images": [] + }, + "dd": { + "icon": "", + "images": [] + }, + "ddev": { + "icon": "", + "images": [] + }, + "ddosify": { + "icon": "", + "images": [] + }, + "deepstream": { + "icon": "", + "images": [] + }, + "delta": { + "icon": "", + "images": [] + }, + "deno": { + "icon": "", + "images": [] + }, + "dep": { + "icon": "", + "images": [] + }, + "dependency-check": { + "icon": "", + "images": [] + }, + "deta": { + "icon": "", + "images": [] + }, + "detekt": { + "icon": "", + "images": [] + }, + "devd": { + "icon": "", + "images": [] + }, + "dhall": { + "icon": "", + "images": [] + }, + "diff-so-fancy": { + "icon": "", + "images": [] + }, + "diffsitter": { + "icon": "", + "images": [] + }, + "difftastic": { + "icon": "", + "images": [] + }, + "diffutils": { + "icon": "", + "images": [] + }, + "digdag": { + "icon": "", + "images": [] + }, + "direnv": { + "icon": "", + "images": [] + }, + "dirhash": { + "icon": "", + "images": [] + }, + "diun": { + "icon": "", + "images": [] + }, + "dive": { + "icon": "", + "images": [] + }, + "djvulibre": { + "icon": "", + "images": [] + }, + "dmd": { + "icon": "", + "images": [] + }, + "dmg2img": { + "icon": "", + "images": [] + }, + "dnscrypt-proxy": { + "icon": "", + "images": [] + }, + "dnslookup": { + "icon": "", + "images": [] + }, + "docfx": { + "icon": "", + "images": [] + }, + "docker": { + "icon": "", + "images": [] + }, + "docker-compose": { + "icon": "", + "images": [] + }, + "docker-pushrm": { + "icon": "", + "images": [] + }, + "doctl": { + "icon": "", + "images": [] + }, + "docto": { + "icon": "", + "images": [] + }, + "dog": { + "icon": "", + "images": [] + }, + "dokka": { + "icon": "", + "images": [] + }, + "dolt": { + "icon": "", + "images": [] + }, + "dos2unix": { + "icon": "", + "images": [] + }, + "dosbox": { + "icon": "", + "images": [] + }, + "dotcover-clt": { + "icon": "", + "images": [] + }, + "dotmemory-clt": { + "icon": "", + "images": [] + }, + "dotmemoryunit": { + "icon": "", + "images": [] + }, + "dotnet-script": { + "icon": "", + "images": [] + }, + "dotnet-sdk": { + "icon": "", + "images": [] + }, + "dotter": { + "icon": "", + "images": [] + }, + "dottrace-api": { + "icon": "", + "images": [] + }, + "dottrace-clt": { + "icon": "", + "images": [] + }, + "doxygen": { + "icon": "", + "images": [] + }, + "dprint": { + "icon": "", + "images": [] + }, + "draft": { + "icon": "", + "images": [] + }, + "drmemory": { + "icon": "", + "images": [] + }, + "drone": { + "icon": "", + "images": [] + }, + "dua": { + "icon": "", + "images": [] + }, + "duckdb": { + "icon": "", + "images": [] + }, + "duf": { + "icon": "", + "images": [] + }, + "dufs": { + "icon": "", + "images": [] + }, + "dum": { + "icon": "", + "images": [] + }, + "duplicacy": { + "icon": "", + "images": [] + }, + "dust": { + "icon": "", + "images": [] + }, + "dvc": { + "icon": "", + "images": [] + }, + "dynamorio": { + "icon": "", + "images": [] + }, + "eac3to": { + "icon": "", + "images": [] + }, + "ect": { + "icon": "", + "images": [] + }, + "edgedb": { + "icon": "", + "images": [] + }, + "edgedriver": { + "icon": "", + "images": [] + }, + "editorconfig": { + "icon": "", + "images": [] + }, + "eksctl": { + "icon": "", + "images": [] + }, + "elixir": { + "icon": "", + "images": [] + }, + "elm": { + "icon": "", + "images": [] + }, + "elvish": { + "icon": "", + "images": [] + }, + "emitter": { + "icon": "", + "images": [] + }, + "emplace": { + "icon": "", + "images": [] + }, + "empty-recycle-bin": { + "icon": "", + "images": [] + }, + "emscripten": { + "icon": "", + "images": [] + }, + "enonic": { + "icon": "", + "images": [] + }, + "envsubst": { + "icon": "", + "images": [] + }, + "erlang": { + "icon": "", + "images": [] + }, + "espanso": { + "icon": "", + "images": [] + }, + "etcd": { + "icon": "", + "images": [] + }, + "ethr": { + "icon": "", + "images": [] + }, + "etl2pcapng": { + "icon": "", + "images": [] + }, + "evans": { + "icon": "", + "images": [] + }, + "eventstore": { + "icon": "", + "images": [] + }, + "everything-cli": { + "icon": "", + "images": [] + }, + "exercism": { + "icon": "", + "images": [] + }, + "exiftool": { + "icon": "", + "images": [] + }, + "f2": { + "icon": "", + "images": [] + }, + "faas-cli": { + "icon": "", + "images": [] + }, + "fake": { + "icon": "", + "images": [] + }, + "far": { + "icon": "", + "images": [] + }, + "fat32format": { + "icon": "", + "images": [] + }, + "fciv": { + "icon": "", + "images": [] + }, + "fd": { + "icon": "", + "images": [] + }, + "ffmpeg": { + "icon": "", + "images": [] + }, + "ffmpeg-shared": { + "icon": "", + "images": [] + }, + "ffsend": { + "icon": "", + "images": [] + }, + "figlet": { + "icon": "", + "images": [] + }, + "figurine": { + "icon": "", + "images": [] + }, + "file": { + "icon": "", + "images": [] + }, + "findutils": { + "icon": "", + "images": [] + }, + "fio": { + "icon": "", + "images": [] + }, + "firebase": { + "icon": "", + "images": [] + }, + "flac": { + "icon": "", + "images": [] + }, + "flatc": { + "icon": "", + "images": [] + }, + "flow": { + "icon": "", + "images": [] + }, + "flux": { + "icon": "", + "images": [] + }, + "flyctl": { + "icon": "", + "images": [] + }, + "flyway": { + "icon": "", + "images": [] + }, + "fnm": { + "icon": "", + "images": [] + }, + "fnproject": { + "icon": "", + "images": [] + }, + "fontreg": { + "icon": "", + "images": [] + }, + "force": { + "icon": "", + "images": [] + }, + "forcebindip": { + "icon": "", + "images": [] + }, + "fossa": { + "icon": "", + "images": [] + }, + "fossil": { + "icon": "", + "images": [] + }, + "fq": { + "icon": "", + "images": [] + }, + "freebasic": { + "icon": "", + "images": [] + }, + "freepascal": { + "icon": "", + "images": [] + }, + "frp": { + "icon": "", + "images": [] + }, + "fselect": { + "icon": "", + "images": [] + }, + "fx": { + "icon": "", + "images": [] + }, + "fzf": { + "icon": "", + "images": [] + }, + "gallery-dl": { + "icon": "", + "images": [] + }, + "gameboosthd": { + "icon": "", + "images": [] + }, + "gauche": { + "icon": "", + "images": [] + }, + "gauge": { + "icon": "", + "images": [] + }, + "gawk": { + "icon": "", + "images": [] + }, + "gbt": { + "icon": "", + "images": [] + }, + "gcc": { + "icon": "", + "images": [] + }, + "gdb": { + "icon": "", + "images": [] + }, + "gdrive": { + "icon": "", + "images": [] + }, + "gdu": { + "icon": "", + "images": [] + }, + "geckodriver": { + "icon": "", + "images": [] + }, + "genact": { + "icon": "", + "images": [] + }, + "geoipupdate": { + "icon": "", + "images": [] + }, + "get-iplayer": { + "icon": "", + "images": [] + }, + "geth": { + "icon": "", + "images": [] + }, + "gettext": { + "icon": "", + "images": [] + }, + "gh": { + "icon": "", + "images": [] + }, + "ghorg": { + "icon": "", + "images": [] + }, + "ghostscript": { + "icon": "", + "images": [] + }, + "ghq": { + "icon": "", + "images": [] + }, + "gibo": { + "icon": "", + "images": [] + }, + "gifsicle": { + "icon": "", + "images": [] + }, + "gifski": { + "icon": "", + "images": [] + }, + "git": { + "icon": "", + "images": [] + }, + "git-annex": { + "icon": "", + "images": [] + }, + "git-bug": { + "icon": "", + "images": [] + }, + "git-chglog": { + "icon": "", + "images": [] + }, + "git-crypt": { + "icon": "", + "images": [] + }, + "git-filter-repo": { + "icon": "", + "images": [] + }, + "git-interactive-rebase-tool": { + "icon": "", + "images": [] + }, + "git-istage": { + "icon": "", + "images": [] + }, + "git-lfs": { + "icon": "", + "images": [] + }, + "git-sizer": { + "icon": "", + "images": [] + }, + "git-tfs": { + "icon": "", + "images": [] + }, + "git-town": { + "icon": "", + "images": [] + }, + "git-up": { + "icon": "", + "images": [] + }, + "git-with-openssh": { + "icon": "", + "images": [] + }, + "git-xargs": { + "icon": "", + "images": [] + }, + "gitea": { + "icon": "", + "images": [] + }, + "gitignore": { + "icon": "", + "images": [] + }, + "gitkube": { + "icon": "", + "images": [] + }, + "gitlab-runner": { + "icon": "", + "images": [] + }, + "gitleaks": { + "icon": "", + "images": [] + }, + "gitomatic": { + "icon": "", + "images": [] + }, + "gitsign": { + "icon": "", + "images": [] + }, + "gitui": { + "icon": "", + "images": [] + }, + "gitversion": { + "icon": "", + "images": [] + }, + "glab": { + "icon": "", + "images": [] + }, + "gleam": { + "icon": "", + "images": [] + }, + "glitter": { + "icon": "", + "images": [] + }, + "global": { + "icon": "", + "images": [] + }, + "glow": { + "icon": "", + "images": [] + }, + "glslang": { + "icon": "", + "images": [] + }, + "gnirehtet": { + "icon": "", + "images": [] + }, + "gnupg": { + "icon": "", + "images": [] + }, + "gnupg1": { + "icon": "", + "images": [] + }, + "gnuplot": { + "icon": "", + "images": [] + }, + "go": { + "icon": "", + "images": [] + }, + "go-containerregistry": { + "icon": "", + "images": [] + }, + "go-jsonnet": { + "icon": "", + "images": [] + }, + "go-swagger": { + "icon": "", + "images": [] + }, + "gobang": { + "icon": "", + "images": [] + }, + "gobuster": { + "icon": "", + "images": [] + }, + "gof": { + "icon": "", + "images": [] + }, + "gogs": { + "icon": "", + "images": [] + }, + "golangci-lint": { + "icon": "", + "images": [] + }, + "gomplate": { + "icon": "", + "images": [] + }, + "goodbyedpi": { + "icon": "", + "images": [] + }, + "gopass": { + "icon": "", + "images": [] + }, + "gopass-jsonapi": { + "icon": "", + "images": [] + }, + "goreleaser": { + "icon": "", + "images": [] + }, + "gosec": { + "icon": "", + "images": [] + }, + "gossm": { + "icon": "", + "images": [] + }, + "gotify-cli": { + "icon": "", + "images": [] + }, + "gotify-server": { + "icon": "", + "images": [] + }, + "gotop": { + "icon": "", + "images": [] + }, + "gource": { + "icon": "", + "images": [] + }, + "govc": { + "icon": "", + "images": [] + }, + "gow": { + "icon": "", + "images": [] + }, + "gpac": { + "icon": "", + "images": [] + }, + "gpg": { + "icon": "", + "images": [] + }, + "gping": { + "icon": "", + "images": [] + }, + "gradle": { + "icon": "", + "images": [] + }, + "gradle-bin": { + "icon": "", + "images": [] + }, + "grails": { + "icon": "", + "images": [] + }, + "graphicsmagick": { + "icon": "", + "images": [] + }, + "graphviz": { + "icon": "", + "images": [] + }, + "grep": { + "icon": "", + "images": [] + }, + "grex": { + "icon": "", + "images": [] + }, + "gron": { + "icon": "", + "images": [] + }, + "groovy": { + "icon": "", + "images": [] + }, + "groovyserv": { + "icon": "", + "images": [] + }, + "grpc-tools": { + "icon": "", + "images": [] + }, + "grpcurl": { + "icon": "", + "images": [] + }, + "grype": { + "icon": "", + "images": [] + }, + "gsl-shell": { + "icon": "", + "images": [] + }, + "gsudo": { + "icon": "", + "images": [] + }, + "gtypist": { + "icon": "", + "images": [] + }, + "guetzli": { + "icon": "", + "images": [] + }, + "gum": { + "icon": "", + "images": [] + }, + "gunk": { + "icon": "", + "images": [] + }, + "gzip": { + "icon": "", + "images": [] + }, + "hadolint": { + "icon": "", + "images": [] + }, + "halo": { + "icon": "", + "images": [] + }, + "handbrake-cli": { + "icon": "", + "images": [] + }, + "harfbuzz": { + "icon": "", + "images": [] + }, + "hashcat": { + "icon": "", + "images": [] + }, + "hashlink": { + "icon": "", + "images": [] + }, + "haskell": { + "icon": "", + "images": [] + }, + "haskell-cabal": { + "icon": "", + "images": [] + }, + "haxe": { + "icon": "", + "images": [] + }, + "hcloud": { + "icon": "", + "images": [] + }, + "helix": { + "icon": "", + "images": [] + }, + "helm": { + "icon": "", + "images": [] + }, + "helm-docs": { + "icon": "", + "images": [] + }, + "helmfile": { + "icon": "", + "images": [] + }, + "heroku-cli": { + "icon": "", + "images": [] + }, + "hexed": { + "icon": "", + "images": [] + }, + "hexyl": { + "icon": "", + "images": [] + }, + "highlight": { + "icon": "", + "images": [] + }, + "hjson": { + "icon": "", + "images": [] + }, + "hledger": { + "icon": "", + "images": [] + }, + "hollows-hunter": { + "icon": "", + "images": [] + }, + "hopp-cli": { + "icon": "", + "images": [] + }, + "hostctl": { + "icon": "", + "images": [] + }, + "htmlq": { + "icon": "", + "images": [] + }, + "httping": { + "icon": "", + "images": [] + }, + "httpstat": { + "icon": "", + "images": [] + }, + "hub": { + "icon": "", + "images": [] + }, + "hugo": { + "icon": "", + "images": [] + }, + "hugo-extended": { + "icon": "", + "images": [] + }, + "hurl": { + "icon": "", + "images": [] + }, + "hygen": { + "icon": "", + "images": [] + }, + "hyperfine": { + "icon": "", + "images": [] + }, + "i2p": { + "icon": "", + "images": [] + }, + "i2p-zero": { + "icon": "", + "images": [] + }, + "ibmcloud-cli": { + "icon": "", + "images": [] + }, + "iconv": { + "icon": "", + "images": [] + }, + "idris": { + "icon": "", + "images": [] + }, + "ie11webdriver": { + "icon": "", + "images": [] + }, + "imagemagick": { + "icon": "", + "images": [] + }, + "imagemagick-lean": { + "icon": "", + "images": [] + }, + "inadyn-mt": { + "icon": "", + "images": [] + }, + "influx": { + "icon": "", + "images": [] + }, + "influxdb": { + "icon": "", + "images": [] + }, + "innoextract": { + "icon": "", + "images": [] + }, + "innounp": { + "icon": "", + "images": [] + }, + "insect": { + "icon": "", + "images": [] + }, + "intermodal": { + "icon": "", + "images": [] + }, + "invoke-build": { + "icon": "", + "images": [] + }, + "iperf3": { + "icon": "", + "images": [] + }, + "ipopt": { + "icon": "", + "images": [] + }, + "ispc": { + "icon": "", + "images": [] + }, + "isx": { + "icon": "", + "images": [] + }, + "iverilog": { + "icon": "", + "images": [] + }, + "jabba": { + "icon": "", + "images": [] + }, + "janet": { + "icon": "", + "images": [] + }, + "jcli": { + "icon": "", + "images": [] + }, + "jd-cli": { + "icon": "", + "images": [] + }, + "jdtls": { + "icon": "", + "images": [] + }, + "jdupes": { + "icon": "", + "images": [] + }, + "jenkins": { + "icon": "", + "images": [] + }, + "jenkins-lts": { + "icon": "", + "images": [] + }, + "jfrog": { + "icon": "", + "images": [] + }, + "jhead": { + "icon": "", + "images": [] + }, + "jid": { + "icon": "", + "images": [] + }, + "jira": { + "icon": "", + "images": [] + }, + "jo": { + "icon": "", + "images": [] + }, + "jojodiff": { + "icon": "", + "images": [] + }, + "jom": { + "icon": "", + "images": [] + }, + "jp": { + "icon": "", + "images": [] + }, + "jq": { + "icon": "", + "images": [] + }, + "jruby": { + "icon": "", + "images": [] + }, + "julia": { + "icon": "", + "images": [] + }, + "just": { + "icon": "", + "images": [] + }, + "jx": { + "icon": "", + "images": [] + }, + "k0s": { + "icon": "", + "images": [] + }, + "k2tf": { + "icon": "", + "images": [] + }, + "k3d": { + "icon": "", + "images": [] + }, + "k3sup": { + "icon": "", + "images": [] + }, + "k6": { + "icon": "", + "images": [] + }, + "k9s": { + "icon": "", + "images": [] + }, + "kaf": { + "icon": "", + "images": [] + }, + "kafka": { + "icon": "", + "images": [] + }, + "kafka-exporter": { + "icon": "", + "images": [] + }, + "kalk": { + "icon": "", + "images": [] + }, + "kalker": { + "icon": "", + "images": [] + }, + "kapacitor": { + "icon": "", + "images": [] + }, + "kapp": { + "icon": "", + "images": [] + }, + "karate": { + "icon": "", + "images": [] + }, + "kcptun": { + "icon": "", + "images": [] + }, + "kim": { + "icon": "", + "images": [] + }, + "kind": { + "icon": "", + "images": [] + }, + "knative": { + "icon": "", + "images": [] + }, + "kompose": { + "icon": "", + "images": [] + }, + "kopia": { + "icon": "", + "images": [] + }, + "kops": { + "icon": "", + "images": [] + }, + "kotlin": { + "icon": "", + "images": [] + }, + "kotlin-native": { + "icon": "", + "images": [] + }, + "krew": { + "icon": "", + "images": [] + }, + "ktunnel": { + "icon": "", + "images": [] + }, + "ktx-software": { + "icon": "", + "images": [] + }, + "kubeadm": { + "icon": "", + "images": [] + }, + "kubectl": { + "icon": "", + "images": [] + }, + "kubectx": { + "icon": "", + "images": [] + }, + "kubefwd": { + "icon": "", + "images": [] + }, + "kubelet": { + "icon": "", + "images": [] + }, + "kubens": { + "icon": "", + "images": [] + }, + "kubescape": { + "icon": "", + "images": [] + }, + "kubeseal": { + "icon": "", + "images": [] + }, + "kubeval": { + "icon": "", + "images": [] + }, + "kubo": { + "icon": "", + "images": [] + }, + "kustomize": { + "icon": "", + "images": [] + }, + "lab": { + "icon": "", + "images": [] + }, + "lame": { + "icon": "", + "images": [] + }, + "latex": { + "icon": "", + "images": [] + }, + "latexindent": { + "icon": "", + "images": [] + }, + "lazydocker": { + "icon": "", + "images": [] + }, + "ldc": { + "icon": "", + "images": [] + }, + "lean-cli": { + "icon": "", + "images": [] + }, + "legit": { + "icon": "", + "images": [] + }, + "lego": { + "icon": "", + "images": [] + }, + "leiningen": { + "icon": "", + "images": [] + }, + "lemminx": { + "icon": "", + "images": [] + }, + "less": { + "icon": "", + "images": [] + }, + "lessmsi": { + "icon": "", + "images": [] + }, + "lf": { + "icon": "", + "images": [] + }, + "lftp": { + "icon": "", + "images": [] + }, + "libavif": { + "icon": "", + "images": [] + }, + "libvips": { + "icon": "", + "images": [] + }, + "libwebp": { + "icon": "", + "images": [] + }, + "libxml2": { + "icon": "", + "images": [] + }, + "lilypond": { + "icon": "", + "images": [] + }, + "links": { + "icon": "", + "images": [] + }, + "liquibase": { + "icon": "", + "images": [] + }, + "listmonk": { + "icon": "", + "images": [] + }, + "llvm": { + "icon": "", + "images": [] + }, + "ln": { + "icon": "", + "images": [] + }, + "loft": { + "icon": "", + "images": [] + }, + "lsd": { + "icon": "", + "images": [] + }, + "lua": { + "icon": "", + "images": [] + }, + "lua-for-windows": { + "icon": "", + "images": [] + }, + "luacheck": { + "icon": "", + "images": [] + }, + "luarocks": { + "icon": "", + "images": [] + }, + "lux": { + "icon": "", + "images": [] + }, + "lwc": { + "icon": "", + "images": [] + }, + "lxc": { + "icon": "", + "images": [] + }, + "lychee": { + "icon": "", + "images": [] + }, + "lynx": { + "icon": "", + "images": [] + }, + "lz4": { + "icon": "", + "images": [] + }, + "lzip": { + "icon": "", + "images": [] + }, + "m4": { + "icon": "", + "images": [] + }, + "macchina": { + "icon": "", + "images": [] + }, + "mach2": { + "icon": "", + "images": [] + }, + "mage": { + "icon": "", + "images": [] + }, + "magic-wormhole": { + "icon": "", + "images": [] + }, + "magic-wormhole-rs": { + "icon": "", + "images": [] + }, + "mailhog": { + "icon": "", + "images": [] + }, + "mailsend": { + "icon": "", + "images": [] + }, + "mailsend-go": { + "icon": "", + "images": [] + }, + "make": { + "icon": "", + "images": [] + }, + "mandoc": { + "icon": "", + "images": [] + }, + "mariadb": { + "icon": "", + "images": [] + }, + "marp": { + "icon": "", + "images": [] + }, + "maven": { + "icon": "", + "images": [] + }, + "mdbook": { + "icon": "", + "images": [] + }, + "mdcat": { + "icon": "", + "images": [] + }, + "mediainfo": { + "icon": "", + "images": [] + }, + "megacmd": { + "icon": "", + "images": [] + }, + "megatools": { + "icon": "", + "images": [] + }, + "memcached": { + "icon": "", + "images": [] + }, + "mercurial": { + "icon": "", + "images": [] + }, + "meson": { + "icon": "", + "images": [] + }, + "metastore": { + "icon": "", + "images": [] + }, + "micro": { + "icon": "", + "images": [] + }, + "micronaut": { + "icon": "", + "images": [] + }, + "migrate": { + "icon": "", + "images": [] + }, + "miktex": { + "icon": "", + "images": [] + }, + "mill": { + "icon": "", + "images": [] + }, + "miller": { + "icon": "", + "images": [] + }, + "mingit": { + "icon": "", + "images": [] + }, + "mingit-busybox": { + "icon": "", + "images": [] + }, + "mingw": { + "icon": "", + "images": [] + }, + "mingw-nuwen": { + "icon": "", + "images": [] + }, + "mingw-winlibs": { + "icon": "", + "images": [] + }, + "minikube": { + "icon": "", + "images": [] + }, + "minio": { + "icon": "", + "images": [] + }, + "minio-client": { + "icon": "", + "images": [] + }, + "miniserve": { + "icon": "", + "images": [] + }, + "minishift": { + "icon": "", + "images": [] + }, + "minisign": { + "icon": "", + "images": [] + }, + "mizu-cli": { + "icon": "", + "images": [] + }, + "mls-software-openssh": { + "icon": "", + "images": [] + }, + "mob": { + "icon": "", + "images": [] + }, + "mockery": { + "icon": "", + "images": [] + }, + "modd": { + "icon": "", + "images": [] + }, + "modern7z": { + "icon": "", + "images": [] + }, + "monero-cli": { + "icon": "", + "images": [] + }, + "mongodb": { + "icon": "", + "images": [] + }, + "mongodb-database-tools": { + "icon": "", + "images": [] + }, + "mono": { + "icon": "", + "images": [] + }, + "monolith": { + "icon": "", + "images": [] + }, + "mosh-client": { + "icon": "", + "images": [] + }, + "mosquitto": { + "icon": "", + "images": [] + }, + "mozjpeg": { + "icon": "", + "images": [] + }, + "mpd": { + "icon": "", + "images": [] + }, + "mpg123": { + "icon": "", + "images": [] + }, + "mprocs": { + "icon": "", + "images": [] + }, + "mpxplay": { + "icon": "", + "images": [] + }, + "mro": { + "icon": "", + "images": [] + }, + "msival2": { + "icon": "", + "images": [] + }, + "msmpi": { + "icon": "", + "images": [] + }, + "msys": { + "icon": "", + "images": [] + }, + "msys2": { + "icon": "", + "images": [] + }, + "mtn": { + "icon": "", + "images": [] + }, + "multipass": { + "icon": "", + "images": [] + }, + "mutagen": { + "icon": "", + "images": [] + }, + "mvndaemon": { + "icon": "", + "images": [] + }, + "mysql": { + "icon": "", + "images": [] + }, + "mysql-workbench": { + "icon": "", + "images": [] + }, + "n-m3u8dl-cli": { + "icon": "", + "images": [] + }, + "naiveproxy": { + "icon": "", + "images": [] + }, + "nali": { + "icon": "", + "images": [] + }, + "nancy": { + "icon": "", + "images": [] + }, + "nano": { + "icon": "", + "images": [] + }, + "nasm": { + "icon": "", + "images": [] + }, + "navi": { + "icon": "", + "images": [] + }, + "ncspot": { + "icon": "", + "images": [] + }, + "neko": { + "icon": "", + "images": [] + }, + "neo-cowsay": { + "icon": "", + "images": [] + }, + "neofetch": { + "icon": "", + "images": [] + }, + "neovim": { + "icon": "", + "images": [] + }, + "nerdctl": { + "icon": "", + "images": [] + }, + "nero-aac": { + "icon": "", + "images": [] + }, + "netcat": { + "icon": "", + "images": [] + }, + "netcoredbg": { + "icon": "", + "images": [] + }, + "nextdns": { + "icon": "", + "images": [] + }, + "nginx": { + "icon": "", + "images": [] + }, + "ngrok": { + "icon": "", + "images": [] + }, + "nim": { + "icon": "", + "images": [] + }, + "ninja": { + "icon": "", + "images": [] + }, + "ninja-kitware": { + "icon": "", + "images": [] + }, + "nircmd": { + "icon": "", + "images": [] + }, + "nixpacks": { + "icon": "", + "images": [] + }, + "nmap": { + "icon": "", + "images": [] + }, + "nodejs": { + "icon": "", + "images": [] + }, + "nodejs-lts": { + "icon": "", + "images": [] + }, + "nomad": { + "icon": "", + "images": [] + }, + "nomino": { + "icon": "", + "images": [] + }, + "noti": { + "icon": "", + "images": [] + }, + "nova": { + "icon": "", + "images": [] + }, + "nssm": { + "icon": "", + "images": [] + }, + "ntfs2btrfs": { + "icon": "", + "images": [] + }, + "ntfy": { + "icon": "", + "images": [] + }, + "ntop": { + "icon": "", + "images": [] + }, + "nu": { + "icon": "", + "images": [] + }, + "nuget": { + "icon": "", + "images": [] + }, + "nunit-console": { + "icon": "", + "images": [] + }, + "nunit-extension-nunit-project-loader": { + "icon": "", + "images": [] + }, + "nunit-extension-nunit-v2-driver": { + "icon": "", + "images": [] + }, + "nunit-extension-nunit-v2-result-writer": { + "icon": "", + "images": [] + }, + "nunit-extension-teamcity-event-listener": { + "icon": "", + "images": [] + }, + "nunit-extension-vs-project-loader": { + "icon": "", + "images": [] + }, + "nvm": { + "icon": "", + "images": [] + }, + "nvs": { + "icon": "", + "images": [] + }, + "nyagos": { + "icon": "", + "images": [] + }, + "objconv": { + "icon": "", + "images": [] + }, + "octave": { + "icon": "", + "images": [] + }, + "octopustools": { + "icon": "", + "images": [] + }, + "octosql": { + "icon": "", + "images": [] + }, + "odo": { + "icon": "", + "images": [] + }, + "offlineinsiderenroll": { + "icon": "", + "images": [] + }, + "oh-my-posh": { + "icon": "", + "images": [] + }, + "oha": { + "icon": "", + "images": [] + }, + "okteto": { + "icon": "", + "images": [] + }, + "omnisharp": { + "icon": "", + "images": [] + }, + "omnisharp-http": { + "icon": "", + "images": [] + }, + "opa": { + "icon": "", + "images": [] + }, + "openapi-generator-cli": { + "icon": "", + "images": [] + }, + "opencv": { + "icon": "", + "images": [] + }, + "openocd": { + "icon": "", + "images": [] + }, + "openresty": { + "icon": "", + "images": [] + }, + "openshift-okd-client": { + "icon": "", + "images": [] + }, + "openshift-origin-client": { + "icon": "", + "images": [] + }, + "openssh": { + "icon": "", + "images": [] + }, + "openssl": { + "icon": "", + "images": [] + }, + "openssl-mingw": { + "icon": "", + "images": [] + }, + "optipng": { + "icon": "", + "images": [] + }, + "opus-tools": { + "icon": "", + "images": [] + }, + "oracle-instant-client": { + "icon": "", + "images": [] + }, + "oracle-instant-client-odbc": { + "icon": "", + "images": [] + }, + "oracle-instant-client-sdk": { + "icon": "", + "images": [] + }, + "osquery": { + "icon": "", + "images": [] + }, + "ossgadget": { + "icon": "", + "images": [] + }, + "osslsigncode": { + "icon": "", + "images": [] + }, + "outwit": { + "icon": "", + "images": [] + }, + "oxipng": { + "icon": "", + "images": [] + }, + "p4": { + "icon": "", + "images": [] + }, + "pack": { + "icon": "", + "images": [] + }, + "packer": { + "icon": "", + "images": [] + }, + "pacparser": { + "icon": "", + "images": [] + }, + "paket": { + "icon": "", + "images": [] + }, + "pandoc": { + "icon": "", + "images": [] + }, + "pandoc-crossref": { + "icon": "", + "images": [] + }, + "par2cmdline": { + "icon": "", + "images": [] + }, + "pastel": { + "icon": "", + "images": [] + }, + "patch": { + "icon": "", + "images": [] + }, + "pciutils": { + "icon": "", + "images": [] + }, + "pcre2grep": { + "icon": "", + "images": [] + }, + "pcregrep": { + "icon": "", + "images": [] + }, + "pdf2djvu": { + "icon": "", + "images": [] + }, + "pdfbox": { + "icon": "", + "images": [] + }, + "pdfcpu": { + "icon": "", + "images": [] + }, + "pdftk": { + "icon": "", + "images": [] + }, + "pe-sieve": { + "icon": "", + "images": [] + }, + "peco": { + "icon": "", + "images": [] + }, + "pelook": { + "icon": "", + "images": [] + }, + "perl": { + "icon": "", + "images": [] + }, + "pester": { + "icon": "", + "images": [] + }, + "pget": { + "icon": "", + "images": [] + }, + "phantomjs": { + "icon": "", + "images": [] + }, + "php": { + "icon": "", + "images": [] + }, + "php-nts": { + "icon": "", + "images": [] + }, + "pkg-config": { + "icon": "", + "images": [] + }, + "plex-server": { + "icon": "", + "images": [] + }, + "pluto": { + "icon": "", + "images": [] + }, + "png2html": { + "icon": "", + "images": [] + }, + "png2jpeg": { + "icon": "", + "images": [] + }, + "pngcrush": { + "icon": "", + "images": [] + }, + "pngquant": { + "icon": "", + "images": [] + }, + "pnpm": { + "icon": "", + "images": [] + }, + "podman": { + "icon": "", + "images": [] + }, + "poetry": { + "icon": "", + "images": [] + }, + "polaris": { + "icon": "", + "images": [] + }, + "poppler": { + "icon": "", + "images": [] + }, + "portainer": { + "icon": "", + "images": [] + }, + "portwarden": { + "icon": "", + "images": [] + }, + "postgresql": { + "icon": "", + "images": [] + }, + "postgrest": { + "icon": "", + "images": [] + }, + "potrace": { + "icon": "", + "images": [] + }, + "powerline-go": { + "icon": "", + "images": [] + }, + "powerping": { + "icon": "", + "images": [] + }, + "powersession": { + "icon": "", + "images": [] + }, + "powersession-rs": { + "icon": "", + "images": [] + }, + "premake": { + "icon": "", + "images": [] + }, + "presentmon": { + "icon": "", + "images": [] + }, + "prince": { + "icon": "", + "images": [] + }, + "prm": { + "icon": "", + "images": [] + }, + "procs": { + "icon": "", + "images": [] + }, + "procyon": { + "icon": "", + "images": [] + }, + "prometheus": { + "icon": "", + "images": [] + }, + "prometheus-pushgateway": { + "icon": "", + "images": [] + }, + "promtail": { + "icon": "", + "images": [] + }, + "protoc-gen-grpc-web": { + "icon": "", + "images": [] + }, + "protolint": { + "icon": "", + "images": [] + }, + "prowiz": { + "icon": "", + "images": [] + }, + "proxychains": { + "icon": "", + "images": [] + }, + "prs": { + "icon": "", + "images": [] + }, + "psake": { + "icon": "", + "images": [] + }, + "psgithub": { + "icon": "", + "images": [] + }, + "pshazz": { + "icon": "", + "images": [] + }, + "psutils": { + "icon": "", + "images": [] + }, + "pt": { + "icon": "", + "images": [] + }, + "ptags": { + "icon": "", + "images": [] + }, + "pueue": { + "icon": "", + "images": [] + }, + "pulumi": { + "icon": "", + "images": [] + }, + "pup": { + "icon": "", + "images": [] + }, + "puppet": { + "icon": "", + "images": [] + }, + "puppet-bolt": { + "icon": "", + "images": [] + }, + "purescript": { + "icon": "", + "images": [] + }, + "pwsh": { + "icon": "", + "images": [] + }, + "px": { + "icon": "", + "images": [] + }, + "pyenv": { + "icon": "", + "images": [] + }, + "pyflow": { + "icon": "", + "images": [] + }, + "pypy2": { + "icon": "", + "images": [] + }, + "pypy3": { + "icon": "", + "images": [] + }, + "python": { + "icon": "", + "images": [] + }, + "q": { + "icon": "", + "images": [] + }, + "qaac": { + "icon": "", + "images": [] + }, + "qemu": { + "icon": "", + "images": [] + }, + "qpdf": { + "icon": "", + "images": [] + }, + "qr": { + "icon": "", + "images": [] + }, + "qrcp": { + "icon": "", + "images": [] + }, + "qrencode": { + "icon": "", + "images": [] + }, + "quarkus-cli": { + "icon": "", + "images": [] + }, + "questdb": { + "icon": "", + "images": [] + }, + "quick-lint-js": { + "icon": "", + "images": [] + }, + "r": { + "icon": "", + "images": [] + }, + "r128gain": { + "icon": "", + "images": [] + }, + "racket": { + "icon": "", + "images": [] + }, + "racket-minimal": { + "icon": "", + "images": [] + }, + "radare2": { + "icon": "", + "images": [] + }, + "railway": { + "icon": "", + "images": [] + }, + "rainbow": { + "icon": "", + "images": [] + }, + "rakudo-moar": { + "icon": "", + "images": [] + }, + "rakudo-star": { + "icon": "", + "images": [] + }, + "rancher-cli": { + "icon": "", + "images": [] + }, + "rancher-compose": { + "icon": "", + "images": [] + }, + "ravendb": { + "icon": "", + "images": [] + }, + "rcc": { + "icon": "", + "images": [] + }, + "rcedit": { + "icon": "", + "images": [] + }, + "rclone": { + "icon": "", + "images": [] + }, + "rdiff-backup": { + "icon": "", + "images": [] + }, + "recmd": { + "icon": "", + "images": [] + }, + "recycle-bin": { + "icon": "", + "images": [] + }, + "red": { + "icon": "", + "images": [] + }, + "redis": { + "icon": "", + "images": [] + }, + "redpen": { + "icon": "", + "images": [] + }, + "redshift": { + "icon": "", + "images": [] + }, + "refreshenv": { + "icon": "", + "images": [] + }, + "regula": { + "icon": "", + "images": [] + }, + "resharper-clt": { + "icon": "", + "images": [] + }, + "restic": { + "icon": "", + "images": [] + }, + "retdec": { + "icon": "", + "images": [] + }, + "rethinkdb": { + "icon": "", + "images": [] + }, + "reviewdog": { + "icon": "", + "images": [] + }, + "rga": { + "icon": "", + "images": [] + }, + "rink": { + "icon": "", + "images": [] + }, + "ripgrep": { + "icon": "", + "images": [] + }, + "rizin": { + "icon": "", + "images": [] + }, + "rke": { + "icon": "", + "images": [] + }, + "rktools2k3": { + "icon": "", + "images": [] + }, + "rnr": { + "icon": "", + "images": [] + }, + "roswell": { + "icon": "", + "images": [] + }, + "rtmpdump": { + "icon": "", + "images": [] + }, + "rtools": { + "icon": "", + "images": [] + }, + "ruby": { + "icon": "", + "images": [] + }, + "runasti": { + "icon": "", + "images": [] + }, + "runat": { + "icon": "", + "images": [] + }, + "rust": { + "icon": "", + "images": [] + }, + "rust-analyzer": { + "icon": "", + "images": [] + }, + "rust-msvc": { + "icon": "", + "images": [] + }, + "rustup": { + "icon": "", + "images": [] + }, + "rustup-msvc": { + "icon": "", + "images": [] + }, + "ryzenadj": { + "icon": "", + "images": [] + }, + "s": { + "icon": "", + "images": [] + }, + "s3deploy": { + "icon": "", + "images": [] + }, + "sacad": { + "icon": "", + "images": [] + }, + "saml2aws": { + "icon": "", + "images": [] + }, + "sampler": { + "icon": "", + "images": [] + }, + "sass": { + "icon": "", + "images": [] + }, + "say": { + "icon": "", + "images": [] + }, + "sayit": { + "icon": "", + "images": [] + }, + "sbcl": { + "icon": "", + "images": [] + }, + "sbt": { + "icon": "", + "images": [] + }, + "scala": { + "icon": "", + "images": [] + }, + "scaleway-cli": { + "icon": "", + "images": [] + }, + "scc": { + "icon": "", + "images": [] + }, + "sccache": { + "icon": "", + "images": [] + }, + "schemacrawler": { + "icon": "", + "images": [] + }, + "scholdoc": { + "icon": "", + "images": [] + }, + "scons": { + "icon": "", + "images": [] + }, + "scoop-search": { + "icon": "", + "images": [] + }, + "scoop-shim": { + "icon": "", + "images": [] + }, + "scoop-validator": { + "icon": "", + "images": [] + }, + "scrcpy": { + "icon": "", + "images": [] + }, + "scriptcs": { + "icon": "", + "images": [] + }, + "sd": { + "icon": "", + "images": [] + }, + "sdcc": { + "icon": "", + "images": [] + }, + "sed": { + "icon": "", + "images": [] + }, + "selenium": { + "icon": "", + "images": [] + }, + "sendmail": { + "icon": "", + "images": [] + }, + "sentinel": { + "icon": "", + "images": [] + }, + "sentry-cli": { + "icon": "", + "images": [] + }, + "seqcli": { + "icon": "", + "images": [] + }, + "serve": { + "icon": "", + "images": [] + }, + "serverless": { + "icon": "", + "images": [] + }, + "sftpgo": { + "icon": "", + "images": [] + }, + "sget": { + "icon": "", + "images": [] + }, + "shadowsocks-rust": { + "icon": "", + "images": [] + }, + "shasum": { + "icon": "", + "images": [] + }, + "shellcheck": { + "icon": "", + "images": [] + }, + "shfmt": { + "icon": "", + "images": [] + }, + "shim": { + "icon": "", + "images": [] + }, + "signal-cli": { + "icon": "", + "images": [] + }, + "sigrok": { + "icon": "", + "images": [] + }, + "simple-http-server": { + "icon": "", + "images": [] + }, + "simplex-chat": { + "icon": "", + "images": [] + }, + "skywalking-cli": { + "icon": "", + "images": [] + }, + "sliksvn": { + "icon": "", + "images": [] + }, + "smartmontools": { + "icon": "", + "images": [] + }, + "smimesign": { + "icon": "", + "images": [] + }, + "snapraid": { + "icon": "", + "images": [] + }, + "sndcpy": { + "icon": "", + "images": [] + }, + "solidity": { + "icon": "", + "images": [] + }, + "sonar-scanner": { + "icon": "", + "images": [] + }, + "sonarqube": { + "icon": "", + "images": [] + }, + "sops": { + "icon": "", + "images": [] + }, + "sort-uniq-wc": { + "icon": "", + "images": [] + }, + "sourcegraph-cli": { + "icon": "", + "images": [] + }, + "sox": { + "icon": "", + "images": [] + }, + "spark": { + "icon": "", + "images": [] + }, + "spdx-sbom-generator": { + "icon": "", + "images": [] + }, + "speedtest-cli": { + "icon": "", + "images": [] + }, + "spicetify-cli": { + "icon": "", + "images": [] + }, + "spotbugs": { + "icon": "", + "images": [] + }, + "spotify-tui": { + "icon": "", + "images": [] + }, + "sqlcl": { + "icon": "", + "images": [] + }, + "sqlite": { + "icon": "", + "images": [] + }, + "srecord": { + "icon": "", + "images": [] + }, + "srlua": { + "icon": "", + "images": [] + }, + "srvany-ng": { + "icon": "", + "images": [] + }, + "srvman": { + "icon": "", + "images": [] + }, + "sslscan": { + "icon": "", + "images": [] + }, + "stack": { + "icon": "", + "images": [] + }, + "starship": { + "icon": "", + "images": [] + }, + "static-web-server": { + "icon": "", + "images": [] + }, + "staticcheck": { + "icon": "", + "images": [] + }, + "stdiscosrv": { + "icon": "", + "images": [] + }, + "stern": { + "icon": "", + "images": [] + }, + "stlink": { + "icon": "", + "images": [] + }, + "stoplight-prism": { + "icon": "", + "images": [] + }, + "stylua": { + "icon": "", + "images": [] + }, + "suanpan": { + "icon": "", + "images": [] + }, + "sudo": { + "icon": "", + "images": [] + }, + "svtplay-dl": { + "icon": "", + "images": [] + }, + "swift": { + "icon": "", + "images": [] + }, + "swig": { + "icon": "", + "images": [] + }, + "syft": { + "icon": "", + "images": [] + }, + "symfony-cli": { + "icon": "", + "images": [] + }, + "syncany-cli": { + "icon": "", + "images": [] + }, + "syncthing": { + "icon": "", + "images": [] + }, + "tailwindcss": { + "icon": "", + "images": [] + }, + "tar": { + "icon": "", + "images": [] + }, + "task": { + "icon": "", + "images": [] + }, + "tcc": { + "icon": "", + "images": [] + }, + "tcping": { + "icon": "", + "images": [] + }, + "tea": { + "icon": "", + "images": [] + }, + "tealdeer": { + "icon": "", + "images": [] + }, + "tectonic": { + "icon": "", + "images": [] + }, + "tektoncd-cli": { + "icon": "", + "images": [] + }, + "telegraf": { + "icon": "", + "images": [] + }, + "teleport": { + "icon": "", + "images": [] + }, + "telnet": { + "icon": "", + "images": [] + }, + "termscp": { + "icon": "", + "images": [] + }, + "termshark": { + "icon": "", + "images": [] + }, + "terraform": { + "icon": "", + "images": [] + }, + "terraform-docs": { + "icon": "", + "images": [] + }, + "terraform-provider-ibm": { + "icon": "", + "images": [] + }, + "terraform-switcher": { + "icon": "", + "images": [] + }, + "terraformer": { + "icon": "", + "images": [] + }, + "terragrunt": { + "icon": "", + "images": [] + }, + "tesseract": { + "icon": "", + "images": [] + }, + "tesseract-languages": { + "icon": "", + "images": [] + }, + "texlab": { + "icon": "", + "images": [] + }, + "tflint": { + "icon": "", + "images": [] + }, + "tfsec": { + "icon": "", + "images": [] + }, + "thrift": { + "icon": "", + "images": [] + }, + "ticker": { + "icon": "", + "images": [] + }, + "tidy": { + "icon": "", + "images": [] + }, + "time": { + "icon": "", + "images": [] + }, + "tinygo": { + "icon": "", + "images": [] + }, + "tldr": { + "icon": "", + "images": [] + }, + "tokei": { + "icon": "", + "images": [] + }, + "topgrade": { + "icon": "", + "images": [] + }, + "tor": { + "icon": "", + "images": [] + }, + "torpar": { + "icon": "", + "images": [] + }, + "touch": { + "icon": "", + "images": [] + }, + "tproxy": { + "icon": "", + "images": [] + }, + "traefik": { + "icon": "", + "images": [] + }, + "transmission-cli": { + "icon": "", + "images": [] + }, + "tre-command": { + "icon": "", + "images": [] + }, + "tree-sitter": { + "icon": "", + "images": [] + }, + "trid": { + "icon": "", + "images": [] + }, + "trojan": { + "icon": "", + "images": [] + }, + "trufflehog": { + "icon": "", + "images": [] + }, + "tta": { + "icon": "", + "images": [] + }, + "tunnel": { + "icon": "", + "images": [] + }, + "tup": { + "icon": "", + "images": [] + }, + "uber-apk-signer": { + "icon": "", + "images": [] + }, + "ugrep": { + "icon": "", + "images": [] + }, + "unar": { + "icon": "", + "images": [] + }, + "uncap": { + "icon": "", + "images": [] + }, + "uncrustify": { + "icon": "", + "images": [] + }, + "unison": { + "icon": "", + "images": [] + }, + "units": { + "icon": "", + "images": [] + }, + "unrar": { + "icon": "", + "images": [] + }, + "unshield": { + "icon": "", + "images": [] + }, + "unxutils": { + "icon": "", + "images": [] + }, + "unzip": { + "icon": "", + "images": [] + }, + "up": { + "icon": "", + "images": [] + }, + "upbound-cli": { + "icon": "", + "images": [] + }, + "upm": { + "icon": "", + "images": [] + }, + "upx": { + "icon": "", + "images": [] + }, + "usql": { + "icon": "", + "images": [] + }, + "uutils-coreutils": { + "icon": "", + "images": [] + }, + "uutils-coreutils-lean": { + "icon": "", + "images": [] + }, + "v": { + "icon": "", + "images": [] + }, + "v2ray": { + "icon": "", + "images": [] + }, + "vagrant": { + "icon": "", + "images": [] + }, + "vale": { + "icon": "", + "images": [] + }, + "vals": { + "icon": "", + "images": [] + }, + "vapoursynth": { + "icon": "", + "images": [] + }, + "vault": { + "icon": "", + "images": [] + }, + "vbindiff": { + "icon": "", + "images": [] + }, + "vcpkg": { + "icon": "", + "images": [] + }, + "vdesk": { + "icon": "", + "images": [] + }, + "vector": { + "icon": "", + "images": [] + }, + "velero": { + "icon": "", + "images": [] + }, + "vim": { + "icon": "", + "images": [] + }, + "vimtutor": { + "icon": "", + "images": [] + }, + "vivetool": { + "icon": "", + "images": [] + }, + "vmaf": { + "icon": "", + "images": [] + }, + "volta": { + "icon": "", + "images": [] + }, + "vswhere": { + "icon": "", + "images": [] + }, + "vt-cli": { + "icon": "", + "images": [] + }, + "vulkan": { + "icon": "", + "images": [] + }, + "vultr": { + "icon": "", + "images": [] + }, + "waifu2x-converter-cpp": { + "icon": "", + "images": [] + }, + "waifu2x-ncnn-vulkan": { + "icon": "", + "images": [] + }, + "wapm-cli": { + "icon": "", + "images": [] + }, + "warp": { + "icon": "", + "images": [] + }, + "wasm4": { + "icon": "", + "images": [] + }, + "wasmer": { + "icon": "", + "images": [] + }, + "wasmtime": { + "icon": "", + "images": [] + }, + "watchexec": { + "icon": "", + "images": [] + }, + "watchman": { + "icon": "", + "images": [] + }, + "wavpack": { + "icon": "", + "images": [] + }, + "waypoint": { + "icon": "", + "images": [] + }, + "webhook": { + "icon": "", + "images": [] + }, + "wgcf": { + "icon": "", + "images": [] + }, + "wget": { + "icon": "", + "images": [] + }, + "which": { + "icon": "", + "images": [] + }, + "win-acme": { + "icon": "", + "images": [] + }, + "win32yank": { + "icon": "", + "images": [] + }, + "windows-application-driver": { + "icon": "", + "images": [] + }, + "winfetch": { + "icon": "", + "images": [] + }, + "winflexbison": { + "icon": "", + "images": [] + }, + "winget": { + "icon": "", + "images": [] + }, + "winnfsd": { + "icon": "", + "images": [] + }, + "winpython": { + "icon": "", + "images": [] + }, + "winsw": { + "icon": "", + "images": [] + }, + "wireproxy": { + "icon": "", + "images": [] + }, + "wixtoolset": { + "icon": "", + "images": [] + }, + "wkhtmltopdf": { + "icon": "", + "images": [] + }, + "wormhole-william": { + "icon": "", + "images": [] + }, + "wp-cli": { + "icon": "", + "images": [] + }, + "wrangler": { + "icon": "", + "images": [] + }, + "wstunnel": { + "icon": "", + "images": [] + }, + "wttop": { + "icon": "", + "images": [] + }, + "wuzz": { + "icon": "", + "images": [] + }, + "x264": { + "icon": "", + "images": [] + }, + "x265": { + "icon": "", + "images": [] + }, + "xdelta": { + "icon": "", + "images": [] + }, + "xh": { + "icon": "", + "images": [] + }, + "xidel": { + "icon": "", + "images": [] + }, + "xmake": { + "icon": "", + "images": [] + }, + "xming": { + "icon": "", + "images": [] + }, + "xmlstarlet": { + "icon": "", + "images": [] + }, + "xpdf-tools": { + "icon": "", + "images": [] + }, + "xpdf-tools-lsp": { + "icon": "", + "images": [] + }, + "xray": { + "icon": "", + "images": [] + }, + "xsv": { + "icon": "", + "images": [] + }, + "xtensa-esp32-elf": { + "icon": "", + "images": [] + }, + "xxcopy": { + "icon": "", + "images": [] + }, + "xz": { + "icon": "", + "images": [] + }, + "y-cruncher": { + "icon": "", + "images": [] + }, + "yara": { + "icon": "", + "images": [] + }, + "yarn": { + "icon": "", + "images": [] + }, + "yasm": { + "icon": "", + "images": [] + }, + "yedit": { + "icon": "", + "images": [] + }, + "yori": { + "icon": "", + "images": [] + }, + "yosys": { + "icon": "", + "images": [] + }, + "youtube-dl": { + "icon": "", + "images": [] + }, + "yq": { + "icon": "", + "images": [] + }, + "yt-dlp": { + "icon": "", + "images": [] + }, + "ytcast": { + "icon": "", + "images": [] + }, + "yubico-piv-tool": { + "icon": "", + "images": [] + }, + "yubikey-personalization": { + "icon": "", + "images": [] + }, + "z.lua": { + "icon": "", + "images": [] + }, + "z3": { + "icon": "", + "images": [] + }, + "zeebe": { + "icon": "", + "images": [] + }, + "zenhan": { + "icon": "", + "images": [] + }, + "zig": { + "icon": "", + "images": [] + }, + "zip": { + "icon": "", + "images": [] + }, + "zola": { + "icon": "", + "images": [] + }, + "zookeeper": { + "icon": "", + "images": [] + }, + "zoxide": { + "icon": "", + "images": [] + }, + "zstd": { + "icon": "", + "images": [] + } + } +} \ No newline at end of file diff --git a/configuration.winget/configurations.md b/configuration.winget/configurations.md new file mode 100644 index 0000000..57e1eb9 --- /dev/null +++ b/configuration.winget/configurations.md @@ -0,0 +1,10 @@ +# Available configurations + +### `unigetui-min.winget` +Installs UniGetUI and its dependencies. WinGet and PowerShell 5 will work out of the box, but other package managers will require manual installation. + +### `unigetui-full.winget` +Includes everything from `unigetui-min.winget` and also installs all supported package managers (except for vcpkg and Scoop, which must be installed manually). + +### `develop-unigetui.winget` +Includes everything from `unigetui-full.winget`, installs required development tools, and clones the repository to your user folder. diff --git a/configuration.winget/develop-unigetui.winget b/configuration.winget/develop-unigetui.winget new file mode 100644 index 0000000..84aa8db --- /dev/null +++ b/configuration.winget/develop-unigetui.winget @@ -0,0 +1,100 @@ +$schema: https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/2024/04/config/document.json + +metadata: + name: UniGetUI Development Environment + description: Sets up the development environment for UniGetUI + author: Martí Climent + +resources: +# Basic dependencies +- name: Install Microsoft Edge WebView2 + type: Microsoft.WinGet/Package + properties: + id: Microsoft.EdgeWebView2Runtime + source: winget + +- name: Install Microsoft Visual C++ 2015-2022 Redistributable + type: Microsoft.WinGet/Package + properties: + id: Microsoft.VCRedist.2015+.x64 + source: winget + +# Package Managers (for testing UniGetUI functionality) +- name: Install Chocolatey + type: Microsoft.WinGet/Package + properties: + id: Chocolatey.Chocolatey + source: winget + +- name: Install Python + type: Microsoft.WinGet/Package + properties: + id: Python.Python.3.13 + source: winget + +- name: Install PowerShell 7 + type: Microsoft.WinGet/Package + properties: + id: Microsoft.PowerShell + source: winget + +- name: Install NodeJS + type: Microsoft.WinGet/Package + properties: + id: OpenJS.NodeJS + source: winget + +- name: Install Rust (Cargo) + type: Microsoft.WinGet/Package + properties: + id: Rustlang.Rustup + source: winget + +# Build and deployment tools +- name: Install Git for version control + type: Microsoft.WinGet/Package + properties: + id: Git.Git + source: winget + +- name: Install Visual Studio 2022 Community + type: Microsoft.WinGet/Package + properties: + id: Microsoft.VisualStudio.2022.Community + source: winget + +- name: Install .NET 10 SDK + type: Microsoft.WinGet/Package + properties: + id: Microsoft.DotNet.SDK.10 + source: winget + +- name: Install Windows App SDK + type: Microsoft.WinGet/Package + properties: + id: Microsoft.WindowsAppRuntime.1.7 + source: winget + +- name: Install Windows SDK + type: Microsoft.WinGet/Package + properties: + id: Microsoft.WindowsSDK.10.0.19041 + source: winget + +- name: Install Inno Setup (for installer creation) + type: Microsoft.WinGet/Package + properties: + id: JRSoftware.InnoSetup + source: winget + +- name: Install 7-Zip (for archive handling) + type: Microsoft.WinGet/Package + properties: + id: 7zip.7zip + source: winget + +- name: Install gsudo (sudo for Windows) + type: Microsoft.WinGet/Package + properties: + id: gerardog.gsudo + source: winget diff --git a/configuration.winget/unigetui-all.winget b/configuration.winget/unigetui-all.winget new file mode 100644 index 0000000..f8f9e7c --- /dev/null +++ b/configuration.winget/unigetui-all.winget @@ -0,0 +1,65 @@ +$schema: https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/2024/04/config/document.json + +metadata: + name: UniGetUI Complete Environment + description: Installs all dependencies and tools for UniGetUI development and runtime + author: Martí Climent + +resources: +# Basic dependencies +- name: Install Microsoft Edge WebView2 + type: Microsoft.WinGet/Package + properties: + id: Microsoft.EdgeWebView2Runtime + source: winget + +- name: Install Microsoft Visual C++ 2015-2022 Redistributable + type: Microsoft.WinGet/Package + properties: + id: Microsoft.VCRedist.2015+.x64 + source: winget + +- name: Install UniGetUI + type: Microsoft.WinGet/Package + properties: + id: MartiCliment.UniGetUI + source: winget + +# Package Managers (for testing UniGetUI functionality) +- name: Install Chocolatey + type: Microsoft.WinGet/Package + properties: + id: Chocolatey.Chocolatey + source: winget + +- name: Install Python + type: Microsoft.WinGet/Package + properties: + id: Python.Python.3.13 + source: winget + +- name: Install PowerShell 7 + type: Microsoft.WinGet/Package + properties: + id: Microsoft.PowerShell + source: winget + +- name: Install NodeJS + type: Microsoft.WinGet/Package + properties: + id: OpenJS.NodeJS + source: winget + +- name: Install Rust (Cargo) + type: Microsoft.WinGet/Package + properties: + id: Rustlang.Rustup + source: winget + +- name: Install .NET 10 SDK + type: Microsoft.WinGet/Package + properties: + id: Microsoft.DotNet.SDK.10 + source: winget + +# vcpkg bootstrap is optional; run scripts\dev-setup-optional.ps1 if needed. diff --git a/configuration.winget/unigetui-min.winget b/configuration.winget/unigetui-min.winget new file mode 100644 index 0000000..8c6fca8 --- /dev/null +++ b/configuration.winget/unigetui-min.winget @@ -0,0 +1,26 @@ +$schema: https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/2024/04/config/document.json + +metadata: + name: UniGetUI Minimal Runtime Dependencies + description: Installs the minimal runtime dependencies required for UniGetUI + author: Martí Climent + +resources: +# Basic dependencies +- name: Install Microsoft Edge WebView2 + type: Microsoft.WinGet/Package + properties: + id: Microsoft.EdgeWebView2Runtime + source: winget + +- name: Install Microsoft Visual C++ 2015-2022 Redistributable + type: Microsoft.WinGet/Package + properties: + id: Microsoft.VCRedist.2015+.x64 + source: winget + +- name: Install UniGetUI + type: Microsoft.WinGet/Package + properties: + id: MartiCliment.UniGetUI + source: winget diff --git a/docs/CLI.md b/docs/CLI.md new file mode 100644 index 0000000..701af6b --- /dev/null +++ b/docs/CLI.md @@ -0,0 +1,262 @@ +# UniGetUI command-line interface + +This file documents the **public command-line surface** exposed by UniGetUI in the 2026 CLI redesign. + +- For the background IPC API that powers these commands, see [IPC.md](IPC.md). +- For developer-only Avalonia diagnostics toggles, see the project source and build props; they are intentionally not documented here as public CLI arguments. + +## Quick start + +```powershell +unigetui status +unigetui app status +unigetui package search --manager dotnet-tool --query dotnetsay +unigetui package install --manager dotnet-tool --id dotnetsay --version 2.1.4 --scope Global +unigetui operation wait --id 123 --timeout 300 +``` + +## Global transport options + +These options select how the CLI connects to the local UniGetUI automation session. + +| Option | Meaning | +| --- | --- | +| `--transport {named-pipe\|tcp}` | Client-side transport override. Default is `named-pipe`. | +| `--tcp-port ` | Client-side TCP port override. Used only with `tcp`. | +| `--pipe-name ` | Client-side named-pipe override. On Windows this is a pipe name. On non-Windows a relative name resolves under `/tmp`, while an absolute path uses that exact Unix socket path. | + +Related environment variables: + +| Variable | Meaning | +| --- | --- | +| `UNIGETUI_IPC_API_TRANSPORT` | Same as `--transport`. | +| `UNIGETUI_IPC_API_PORT` | Same as `--tcp-port`. | +| `UNIGETUI_IPC_API_PIPE_NAME` | Same as `--pipe-name`. | + +## Exit codes + +| Code | Meaning | +| --- | --- | +| `0` | Success | +| `1` | Command failed | +| `2` | Invalid parameter | +| `3` | IPC API unavailable | +| `4` | Unknown automation command | + +## Command grammar notes + +- Command nouns accept singular or plural forms: `operation`/`operations`, `package`/`packages`, `manager`/`managers`, and so on. +- Compatibility aliases are accepted for some flags: + - `--id` maps to `--package-id` or `--operation-id` where appropriate + - `--source` maps to `--package-source` +- Boolean options use explicit values such as `--enabled true` or `--wait false`. +- `--detach` is shorthand for asynchronous package operations (`--wait false`). +- `--manager` uses stable manager ids, not GUI labels. Current ids: `apt`, `bun`, `cargo`, `chocolatey`, `dnf`, `dotnet-tool`, `flatpak`, `homebrew`, `npm`, `pacman`, `pip`, `pwsh`, `scoop`, `snap`, `vcpkg`, `winget`, and `winps`. + +## Command reference + +### Core + +| Command | Required options | Optional options | Notes | +| --- | --- | --- | --- | +| `status` | None | None | Returns transport, endpoint, and build information for the selected automation session. | +| `version` | None | None | Returns the UniGetUI build number through the IPC API. | + +### App + +| Command | Required options | Optional options | Notes | +| --- | --- | --- | --- | +| `app status` | None | None | Returns app/session state such as headless mode, page, and supported UI actions. | +| `app show` | None | None | Shows and focuses the window when a GUI session exists. | +| `app navigate` | `--page ` | `--manager `, `--help-attachment ` | Valid pages include `discover`, `updates`, `installed`, `bundles`, `settings`, `managers`, `own-log`, `manager-log`, `operation-history`, `help`, `release-notes`, and `about`. | +| `app quit` | None | None | Gracefully shuts down the selected session, including headless daemons. | + +### Operations + +| Command | Required options | Optional options | Notes | +| --- | --- | --- | --- | +| `operation list` | None | None | Lists tracked live and completed operations. | +| `operation get` | `--id ` | None | Returns the full tracked payload for one operation. | +| `operation output` | `--id ` | `--tail ` | Reads captured output lines for one operation. | +| `operation wait` | `--id ` | `--timeout `, `--delay ` | Polls until the operation reaches a terminal state. | +| `operation cancel` | `--id ` | None | Cancels a queued or running operation. | +| `operation retry` | `--id ` | `--mode ` | Retry modes are defined by the operation payload. | +| `operation reorder` | `--id `, `--action ` | None | Reorders a queued operation. | +| `operation forget` | `--id ` | None | Removes a finished operation from the live tracked list. | + +### Managers + +| Command | Required options | Optional options | Notes | +| --- | --- | --- | --- | +| `manager list` | None | None | Lists managers and their automation-relevant capability flags. | +| `manager maintenance` | `--manager ` | None | Returns maintenance metadata for one manager. | +| `manager reload` | `--manager ` | None | Reloads one manager. | +| `manager set-executable` | `--manager `, `--path ` | None | Sets a custom executable override, then reloads the manager. | +| `manager clear-executable` | `--manager ` | None | Clears the custom executable override, then reloads the manager. | +| `manager action` | `--manager `, `--action ` | `--confirm` | Runs a manager-specific maintenance action. | +| `manager enable` | `--manager ` | None | Enables the manager. | +| `manager disable` | `--manager ` | None | Disables the manager. | +| `manager notifications enable` | `--manager ` | None | Enables update notifications for the manager. | +| `manager notifications disable` | `--manager ` | None | Disables update notifications for the manager. | + +### Sources + +| Command | Required options | Optional options | Notes | +| --- | --- | --- | --- | +| `source list` | None | `--manager ` | Lists sources, optionally filtered to one manager. | +| `source add` | `--manager `, `--name ` | `--url ` | Adds a source. | +| `source remove` | `--manager `, `--name ` | `--url ` | Removes a source. | + +### Settings + +| Command | Required options | Optional options | Notes | +| --- | --- | --- | --- | +| `settings list` | None | None | Lists non-secure settings. | +| `settings get` | `--key ` | None | Reads one non-secure setting. | +| `settings set` | `--key ` | `--enabled true\|false`, `--value ` | Sets either the boolean or string form of a setting. | +| `settings clear` | `--key ` | None | Clears a string-backed setting. | +| `settings reset` | None | None | Resets non-secure settings. | +| `settings secure list` | None | `--user ` | Lists secure settings for the current or specified user. | +| `settings secure get` | `--key ` | `--user ` | Reads one secure setting. | +| `settings secure set` | `--key `, `--enabled true\|false` | `--user ` | Enables or disables one secure setting. | + +Available keys live in: + +- [`src/UniGetUI.Core.Settings/SettingsEngine_Names.cs`](src/UniGetUI.Core.Settings/SettingsEngine_Names.cs) +- [`src/UniGetUI.Core.SecureSettings/SecureSettings.cs`](src/UniGetUI.Core.SecureSettings/SecureSettings.cs) + +### Shortcuts + +| Command | Required options | Optional options | Notes | +| --- | --- | --- | --- | +| `shortcut list` | None | None | Lists tracked desktop shortcuts and stored keep/delete verdicts. | +| `shortcut set` | `--path `, `--status ` | None | Marks a shortcut to keep or delete. | +| `shortcut reset` | `--path ` | None | Clears the stored verdict for one shortcut. | +| `shortcut reset-all` | None | None | Clears all stored shortcut verdicts. | + +### Logs + +| Command | Required options | Optional options | Notes | +| --- | --- | --- | --- | +| `log app` | None | `--level ` | Returns structured application log entries. | +| `log operations` | None | None | Returns persisted operation history. | +| `log manager` | None | `--manager `, `--verbose` | Returns manager task logs. | + +### Backups + +| Command | Required options | Optional options | Notes | +| --- | --- | --- | --- | +| `backup status` | None | None | Returns backup settings and cloud-auth state. | +| `backup local create` | None | None | Creates a local backup bundle. | +| `backup github login start` | None | `--launch-browser` | Starts the GitHub device flow. | +| `backup github login complete` | None | None | Completes the pending device flow. | +| `backup github logout` | None | None | Clears the stored GitHub auth token. | +| `backup cloud list` | None | None | Lists cloud backups in the authenticated GitHub backup store. | +| `backup cloud create` | None | None | Uploads the current backup to cloud storage. | +| `backup cloud download` | `--key ` | None | Downloads one cloud backup as bundle content. | +| `backup cloud restore` | `--key ` | `--append` | Imports one cloud backup into the current in-memory bundle. | + +### Bundles + +| Command | Required options | Optional options | Notes | +| --- | --- | --- | --- | +| `bundle get` | None | None | Returns the current in-memory bundle. | +| `bundle reset` | None | None | Clears the current in-memory bundle. | +| `bundle import` | None | `--path `, `--content `, `--format `, `--append` | Imports bundle content from a file or raw content. | +| `bundle export` | None | `--path ` | Exports the current bundle, optionally to disk. | +| `bundle add` | `--id ` | `--manager `, `--source `, `--version `, `--scope `, `--pre-release`, `--selection ` | Resolves a package and adds it to the bundle. | +| `bundle remove` | `--id ` | `--manager `, `--source `, `--version `, `--scope `, `--pre-release`, `--selection ` | Removes matching package entries from the bundle. | +| `bundle install` | None | `--include-installed true\|false`, `--elevated true\|false`, `--interactive true\|false`, `--skip-hash true\|false` | Installs the bundle through UniGetUI’s shared operation pipeline. | + +### Packages + +| Command | Required options | Optional options | Notes | +| --- | --- | --- | --- | +| `package search` | `--query ` | `--manager `, `--max-results ` | Searches packages. | +| `package details` | `--id ` | `--manager `, `--source ` | Returns the package details payload. | +| `package versions` | `--id ` | `--manager `, `--source ` | Returns installable versions when supported by the manager. | +| `package installed` | None | `--manager ` | Lists installed packages. | +| `package updates` | None | `--manager ` | Lists available updates. | +| `package install` | `--id ` | `--manager `, `--source `, `--version `, `--scope `, `--pre-release`, `--elevated true\|false`, `--interactive true\|false`, `--skip-hash true\|false`, `--architecture `, `--location `, `--wait true\|false`, `--detach` | Installs a package. Async mode returns an operation id immediately. | +| `package download` | `--id ` | `--manager `, `--source `, `--version `, `--scope `, `--wait true\|false`, `--detach`, `--output ` | Downloads a package artifact. | +| `package reinstall` | `--id ` | Same options as `package install` | Re-runs installation for an installed package. | +| `package repair` | `--id ` | Same options as `package install`, plus `--remove-data true\|false` | Uninstalls then reinstalls the package. | +| `package update` | `--id ` | Same options as `package install` | Updates one package. | +| `package uninstall` | `--id ` | `--manager `, `--source `, `--scope `, `--remove-data true\|false`, `--elevated true\|false`, `--interactive true\|false`, `--wait true\|false`, `--detach` | Uninstalls a package. | +| `package show` | `--id `, `--source ` | None | Opens the package details UI flow. | +| `package ignored list` | None | None | Lists ignored-update rules tracked by UniGetUI. | +| `package ignored add` | `--id ` | `--manager `, `--version `, `--source ` | Adds an ignored-update rule. | +| `package ignored remove` | `--id ` | `--manager `, `--version `, `--source ` | Removes an ignored-update rule. | +| `package update-all` | None | None | Queues updates for all currently upgradable packages. | +| `package update-manager` | `--manager ` | None | Queues updates for all upgradable packages handled by one manager. | + +## Headless behavior + +When UniGetUI is started with `--headless`, it exposes the same automation API without opening a window. + +| Command | Headless behavior | +| --- | --- | +| `status`, `app status`, `app quit` | Fully supported. | +| `app show` | Fails with “the current UniGetUI session is running headless and has no window to show.” | +| `app navigate` | Fails with “the current UniGetUI session is running headless and cannot navigate UI pages.” | +| `package show` | UI-oriented; may fail or be meaningless in pure headless sessions. | +| `package update-all`, `package update-manager` | Require GUI-side upgrade handlers. Headless sessions may return “cannot update all packages” or “cannot update manager packages.” | + +## Headless IPC options + +When UniGetUI is started with `--headless`, these options control the IPC listener: + +| Option | Meaning | +| --- | --- | +| `--ipc-api-transport {named-pipe\|tcp}` | Selects the server-side IPC transport. Default is `named-pipe`. | +| `--ipc-api-port ` | Overrides the TCP port when TCP transport is selected. | +| `--ipc-api-pipe-name ` | Overrides the server-side pipe name or Unix socket path. | + +## Other application startup parameters + +These parameters are accepted by the app executables in addition to the automation verb tree. + +| Parameter | Meaning | Notes | +| --- | --- | --- | +| `--daemon` | Starts UniGetUI minimized to the notification area. | Requires the corresponding startup setting. | +| `--welcome` | Opens the setup wizard. | Historical compatibility flag. | +| `--updateapps` | Forces automatic installation of available updates. | Historical compatibility flag. | +| `--report-all-errors` | Opens the error report page for any crash while loading. | Troubleshooting flag. | +| `--uninstall-unigetui` | Unregisters UniGetUI from the notification panel and quits. | Historical; only valid for specific old versions. | +| `--migrate-wingetui-to-unigetui` | Migrates legacy WingetUI data and shortcuts, then quits. | Migration helper. | +| `--help` / `-h` | Prints CLI help. | For the direct verb-based CLI. | +| `--import-settings ` | Imports settings from a JSON file. | Existing settings are replaced. | +| `--export-settings ` | Exports settings to a JSON file. | Creates or overwrites the file. | +| `--enable-setting ` / `--disable-setting ` | Toggles one boolean setting. | Legacy setting flags. | +| `--set-setting-value ` | Sets one string-backed setting. | Legacy setting flag. | +| `--no-corrupt-dialog` | Shows the verbose crash report instead of the simplified dialog. | Troubleshooting flag. | +| `--enable-secure-setting ` / `--disable-secure-setting ` | Toggles one secure setting for the current user. | May require elevation. | +| `--enable-secure-setting-for-user ` / `--disable-secure-setting-for-user ` | Toggles one secure setting for a specified user. | May require elevation. | +| `` | Loads a valid bundle file into the Package Bundles page. | Supported extensions include `.ubundle`, `.json`, `.yaml`, and `.xml`. | + +## Deep links + +UniGetUI also accepts the following `unigetui://` links: + +| Deep link | Meaning | +| --- | --- | +| `unigetui://showPackage?id={id}&managerName={manager}&sourceName={source}` | Opens package details for the specified package. | +| `unigetui://showUniGetUI` | Shows UniGetUI and brings the window to the front. | +| `unigetui://showDiscoverPage` | Opens the Discover page. | +| `unigetui://showUpdatesPage` | Opens the Updates page. | +| `unigetui://showInstalledPage` | Opens the Installed page. | + +## Installer parameters + +The installer is Inno Setup based. It supports the standard [Inno Setup command-line parameters](https://jrsoftware.org/ishelp/index.php?topic=setupcmdline) plus these UniGetUI-specific switches: + +| Parameter | Meaning | +| --- | --- | +| `/NoAutoStart` | Do not launch UniGetUI after installation. | +| `/NoRunOnStartup` | Do not register UniGetUI to start minimized at login. | +| `/NoVCRedist` | Skip installation of the MSVC x64 runtime. | +| `/NoEdgeWebView` | Skip installation of the Microsoft Edge WebView runtime. | +| `/NoChocolatey` | Deprecated no-op kept for compatibility. | +| `/EnableSystemChocolatey` | Deprecated no-op kept for compatibility. | +| `/NoWinGet` | Do not install WinGet and Microsoft.WinGet.Client if they are missing. | +| `/MSStore` | Microsoft Store install mode: skip the MSVC and WebView2 dependency installers, do not launch UniGetUI after installation, and disable startup at login. Use with `/CURRENTUSER` to select user-local scope. | diff --git a/docs/IPC.md b/docs/IPC.md new file mode 100644 index 0000000..f3056b6 --- /dev/null +++ b/docs/IPC.md @@ -0,0 +1,397 @@ +# UniGetUI background IPC API + +This file documents the **local automation API** used by the UniGetUI CLI. + +- For the public command-line interface built on top of this API, see [CLI.md](CLI.md). +- This API is designed for **local automation**, not for remote exposure. + +## Overview + +UniGetUI exposes a local HTTP API over one of two transports: + +- **Named-pipe transport** (default) + - Windows: Windows named pipe + - Non-Windows: Unix domain socket +- **TCP transport** (optional) + - Localhost only + +All endpoints live under `/uniget/v1/...`. + +## Transport defaults + +| Setting | Value | +| --- | --- | +| Default transport | `named-pipe` | +| Default TCP port | `7058` | +| Default pipe name | `UniGetUI.IPC` | +| Default Unix socket directory | `/tmp` | + +On non-Windows, a relative named-pipe name such as `UniGetUI.IPC` resolves to: + +```text +/tmp/UniGetUI.IPC +``` + +An absolute path may also be supplied on non-Windows. On Windows, absolute pipe paths are rejected and UniGetUI falls back to the default pipe name. + +## Server-side configuration + +These options are read when UniGetUI starts its IPC API server. + +| Argument | Environment variable | Meaning | +| --- | --- | --- | +| `--ipc-api-transport {named-pipe\|tcp}` | `UNIGETUI_IPC_API_TRANSPORT` | Selects the server transport. | +| `--ipc-api-port ` | `UNIGETUI_IPC_API_PORT` | Selects the TCP port when TCP is enabled. | +| `--ipc-api-pipe-name ` | `UNIGETUI_IPC_API_PIPE_NAME` | Selects the pipe name or Unix socket path when named-pipe transport is enabled. | + +## Client-side configuration + +These options are read by the CLI and `IpcClient`. + +| Argument | Environment variable | Meaning | +| --- | --- | --- | +| `--transport {named-pipe\|tcp}` | `UNIGETUI_IPC_API_TRANSPORT` | Explicit client-side transport override. | +| `--tcp-port ` | `UNIGETUI_IPC_API_PORT` | Explicit client-side TCP port override. | +| `--pipe-name ` | `UNIGETUI_IPC_API_PIPE_NAME` | Explicit client-side pipe name or Unix socket override. | + +## Session discovery + +When the client does **not** receive an explicit transport override: + +1. UniGetUI loads persisted endpoint registrations from the user configuration directory. +2. Registrations are ordered with this preference: + 1. headless sessions first + 2. newest persisted session first +3. The client probes for a live session and uses its persisted token automatically. + +When the client **does** receive an explicit override: + +- it connects to that transport choice instead of auto-selecting the newest session +- it waits up to 5 seconds for a matching persisted token to appear + +## Authentication + +| Endpoint | Auth | +| --- | --- | +| `GET /uniget/v1/status` | No token required | +| All other `/uniget/v1/*` endpoints | `token` query parameter required | + +Authentication details: + +- UniGetUI generates a per-session token at API startup. +- That token is persisted with the endpoint registration metadata. +- `IpcClient` automatically appends `token=` to authenticated requests. + +## Security notes + +- The default design is **local-only automation**. +- TCP mode binds to `localhost`, not all interfaces. +- On non-Windows named-pipe transport, UniGetUI applies Unix socket mode: + +```text +user-read + user-write +``` + +That is effectively `0600`-style same-user access on the socket file. + +- On Windows named-pipe transport, UniGetUI uses Kestrel named-pipe hosting and does not expose a filesystem socket path. + +## Error model + +| Condition | Result | +| --- | --- | +| Missing or invalid token | HTTP `401` | +| Invalid query/body arguments | HTTP `400` with plain-text error message | +| Success | JSON response with camelCase property names | + +Most successful command endpoints return either: + +- a domain object wrapped in a `status: "success"` envelope, or +- a command/result JSON envelope, or +- another typed JSON payload documented by its fields rather than its CLR type name + +## Request conventions + +### Query-string endpoints + +Most endpoints use query parameters, including: + +- operations +- app navigation +- sources +- settings +- secure settings +- shortcuts +- logs +- package search/details/versions/installed/updates +- package actions + +### JSON-body endpoints + +These endpoint families consume JSON bodies: + +| Endpoint family | Request shape | +| --- | --- | +| manager maintenance actions | manager maintenance request body | +| GitHub device-flow start | GitHub device-flow start request body | +| cloud backup download/restore | cloud backup request body | +| bundle import | bundle import request body | +| bundle export | bundle export request body | +| bundle add/remove | bundle package request body | +| bundle install | bundle install request body | + +### JSON body field reference + +All request bodies use **camelCase** JSON. + +#### Manager maintenance request body + +| Field | Type | Meaning | +| --- | --- | --- | +| `managerName` | string | Required stable manager id | +| `action` | string | Manager action name for `/action` | +| `path` | string | Custom executable path for `/executable/set` | +| `confirm` | boolean | Confirmation flag for destructive actions | + +#### GitHub device-flow start request body + +| Field | Type | Meaning | +| --- | --- | --- | +| `launchBrowser` | boolean | Whether UniGetUI should try to open the verification URL automatically | + +#### Cloud backup request body + +| Field | Type | Meaning | +| --- | --- | --- | +| `key` | string | Backup identifier | +| `append` | boolean | Append instead of replace when restoring/importing | + +#### Bundle import request body + +| Field | Type | Meaning | +| --- | --- | --- | +| `path` | string | Source file path | +| `content` | string | Raw bundle content | +| `format` | string | Bundle format such as `ubundle`, `json`, `yaml`, or `xml` | +| `append` | boolean | Append imported items to the current bundle | + +#### Bundle export request body + +| Field | Type | Meaning | +| --- | --- | --- | +| `path` | string | Optional output path | + +#### Bundle package request body + +| Field | Type | Meaning | +| --- | --- | --- | +| `packageId` | string | Package identifier | +| `managerName` | string | Stable manager id | +| `packageSource` | string | Source/feed name | +| `version` | string | Requested version | +| `scope` | string | Requested scope | +| `preRelease` | boolean | Include prerelease package metadata | +| `selection` | string | Bundle selection mode | + +#### Bundle install request body + +| Field | Type | Meaning | +| --- | --- | --- | +| `includeInstalled` | boolean | Whether already-installed packages should still be processed | +| `elevated` | boolean | Request elevated execution | +| `interactive` | boolean | Request interactive execution | +| `skipHash` | boolean | Skip hash validation when supported | + +## Shared parameter sets + +### Package action query parameters + +These keys are used by package-related endpoints such as install, update, uninstall, details, versions, ignored updates, and download. + +| Query key | Meaning | +| --- | --- | +| `packageId` | Package identifier | +| `manager` | Stable manager id | +| `packageSource` | Source/feed name | +| `version` | Requested version | +| `scope` | Install scope | +| `preRelease` | Boolean | +| `elevated` | Boolean | +| `interactive` | Boolean | +| `skipHash` | Boolean | +| `removeData` | Boolean | +| `wait` | Boolean | +| `architecture` | Architecture override | +| `location` | Install location override | +| `outputPath` | Download output path | + +### App navigation query parameters + +| Query key | Meaning | +| --- | --- | +| `page` | Target page name | +| `manager` | Optional manager context | +| `helpAttachment` | Optional help-page attachment | + +### Operation query parameters + +| Query key | Meaning | +| --- | --- | +| `tailLines` | Used by `GET /uniget/v1/operations/{operationId}/output` | +| `mode` | Retry mode for `POST /uniget/v1/operations/{operationId}/retry` | +| `action` | Queue action for `POST /uniget/v1/operations/{operationId}/reorder` | + +## Endpoint reference + +### Session and app + +| Method | Path | Auth | Parameters/body | CLI equivalent | Notes | +| --- | --- | --- | --- | --- | --- | +| `GET` | `/uniget/v1/status` | No | None | `status`, `version` | Returns `running`, `transport`, `tcpPort`, `namedPipeName`, `namedPipePath`, `baseAddress`, `version`, and `buildNumber`. | +| `GET` | `/uniget/v1/app` | Yes | None | `app status` | Returns app/headless/window state. | +| `POST` | `/uniget/v1/app/show` | Yes | None | `app show` | UI-only in practice. | +| `POST` | `/uniget/v1/app/navigate` | Yes | Query: `page`, optional `manager`, optional `helpAttachment` | `app navigate` | UI-only in practice. | +| `POST` | `/uniget/v1/app/quit` | Yes | None | `app quit` | Shuts down the selected session. | + +### Operations + +| Method | Path | Auth | Parameters/body | CLI equivalent | +| --- | --- | --- | --- | --- | +| `GET` | `/uniget/v1/operations` | Yes | None | `operation list` | +| `GET` | `/uniget/v1/operations/{operationId}` | Yes | Route: `operationId` | `operation get` | +| `GET` | `/uniget/v1/operations/{operationId}/output` | Yes | Route: `operationId`, optional query `tailLines` | `operation output` | +| `POST` | `/uniget/v1/operations/{operationId}/cancel` | Yes | Route: `operationId` | `operation cancel` | +| `POST` | `/uniget/v1/operations/{operationId}/retry` | Yes | Route: `operationId`, optional query `mode` | `operation retry` | +| `POST` | `/uniget/v1/operations/{operationId}/reorder` | Yes | Route: `operationId`, query `action` | `operation reorder` | +| `POST` | `/uniget/v1/operations/{operationId}/forget` | Yes | Route: `operationId` | `operation forget` | + +### Managers + +| Method | Path | Auth | Parameters/body | CLI equivalent | +| --- | --- | --- | --- | --- | +| `GET` | `/uniget/v1/managers` | Yes | None | `manager list` | +| `GET` | `/uniget/v1/managers/maintenance` | Yes | Query `manager` | `manager maintenance` | +| `POST` | `/uniget/v1/managers/maintenance/reload` | Yes | JSON body: manager maintenance request body | `manager reload` | +| `POST` | `/uniget/v1/managers/maintenance/executable/set` | Yes | JSON body: manager maintenance request body | `manager set-executable` | +| `POST` | `/uniget/v1/managers/maintenance/executable/clear` | Yes | JSON body: manager maintenance request body | `manager clear-executable` | +| `POST` | `/uniget/v1/managers/maintenance/action` | Yes | JSON body: manager maintenance request body | `manager action` | +| `POST` | `/uniget/v1/managers/set-enabled` | Yes | Query `manager`, `enabled` | `manager enable`, `manager disable` | +| `POST` | `/uniget/v1/managers/set-update-notifications` | Yes | Query `manager`, `enabled` | `manager notifications enable`, `manager notifications disable` | + +### Sources + +| Method | Path | Auth | Parameters/body | CLI equivalent | +| --- | --- | --- | --- | --- | +| `GET` | `/uniget/v1/sources` | Yes | Optional query `manager` | `source list` | +| `POST` | `/uniget/v1/sources/add` | Yes | Query `manager`, `name`, optional `url` | `source add` | +| `POST` | `/uniget/v1/sources/remove` | Yes | Query `manager`, `name`, optional `url` | `source remove` | + +### Settings + +| Method | Path | Auth | Parameters/body | CLI equivalent | +| --- | --- | --- | --- | --- | +| `GET` | `/uniget/v1/settings` | Yes | None | `settings list` | +| `GET` | `/uniget/v1/settings/item` | Yes | Query `key` | `settings get` | +| `POST` | `/uniget/v1/settings/set` | Yes | Query `key`, optional `enabled`, optional `value` | `settings set` | +| `POST` | `/uniget/v1/settings/clear` | Yes | Query `key` | `settings clear` | +| `POST` | `/uniget/v1/settings/reset` | Yes | None | `settings reset` | + +### Secure settings + +| Method | Path | Auth | Parameters/body | CLI equivalent | +| --- | --- | --- | --- | --- | +| `GET` | `/uniget/v1/secure-settings` | Yes | Optional query `user` | `settings secure list` | +| `GET` | `/uniget/v1/secure-settings/item` | Yes | Query `key`, optional `user` | `settings secure get` | +| `POST` | `/uniget/v1/secure-settings/set` | Yes | Query `key`, `enabled`, optional `user` | `settings secure set` | + +### Desktop shortcuts + +| Method | Path | Auth | Parameters/body | CLI equivalent | +| --- | --- | --- | --- | --- | +| `GET` | `/uniget/v1/desktop-shortcuts` | Yes | None | `shortcut list` | +| `POST` | `/uniget/v1/desktop-shortcuts/set` | Yes | Query `path`, `status` | `shortcut set` | +| `POST` | `/uniget/v1/desktop-shortcuts/reset` | Yes | Query `path` | `shortcut reset` | +| `POST` | `/uniget/v1/desktop-shortcuts/reset-all` | Yes | None | `shortcut reset-all` | + +### Logs + +| Method | Path | Auth | Parameters/body | CLI equivalent | +| --- | --- | --- | --- | --- | +| `GET` | `/uniget/v1/logs/app` | Yes | Optional query `level` | `log app` | +| `GET` | `/uniget/v1/logs/history` | Yes | None | `log operations` | +| `GET` | `/uniget/v1/logs/manager` | Yes | Optional query `manager`, optional query `verbose` | `log manager` | + +### Backups + +| Method | Path | Auth | Parameters/body | CLI equivalent | Notes | +| --- | --- | --- | --- | --- | --- | +| `GET` | `/uniget/v1/backups/status` | Yes | None | `backup status` | Includes local backup settings and GitHub auth state. | +| `POST` | `/uniget/v1/backups/local/create` | Yes | None | `backup local create` | Creates a local backup bundle. | +| `POST` | `/uniget/v1/backups/github/sign-in/start` | Yes | JSON body: GitHub device-flow start request body | `backup github login start` | Starts GitHub device flow. | +| `POST` | `/uniget/v1/backups/github/sign-in/complete` | Yes | None | `backup github login complete` | Completes device flow. | +| `POST` | `/uniget/v1/backups/github/sign-out` | Yes | None | `backup github logout` | Signs out of GitHub backup integration. | +| `GET` | `/uniget/v1/backups/cloud` | Yes | None | `backup cloud list` | Lists cloud backups. | +| `POST` | `/uniget/v1/backups/cloud/create` | Yes | None | `backup cloud create` | Uploads a cloud backup. | +| `POST` | `/uniget/v1/backups/cloud/download` | Yes | JSON body: cloud backup request body | `backup cloud download` | Downloads backup content. | +| `POST` | `/uniget/v1/backups/cloud/restore` | Yes | JSON body: cloud backup request body | `backup cloud restore` | Restores/imports a cloud backup. | + +### Bundles + +| Method | Path | Auth | Parameters/body | CLI equivalent | +| --- | --- | --- | --- | --- | +| `GET` | `/uniget/v1/bundles` | Yes | None | `bundle get` | +| `POST` | `/uniget/v1/bundles/reset` | Yes | None | `bundle reset` | +| `POST` | `/uniget/v1/bundles/import` | Yes | JSON body: bundle import request body | `bundle import` | +| `POST` | `/uniget/v1/bundles/export` | Yes | JSON body: bundle export request body | `bundle export` | +| `POST` | `/uniget/v1/bundles/add` | Yes | JSON body: bundle package request body | `bundle add` | +| `POST` | `/uniget/v1/bundles/remove` | Yes | JSON body: bundle package request body | `bundle remove` | +| `POST` | `/uniget/v1/bundles/install` | Yes | JSON body: bundle install request body | `bundle install` | + +### Packages + +| Method | Path | Auth | Parameters/body | CLI equivalent | Notes | +| --- | --- | --- | --- | --- | --- | +| `GET` | `/uniget/v1/packages/search` | Yes | Query `query`, optional `manager`, optional `maxResults` | `package search` | Search endpoint. | +| `GET` | `/uniget/v1/packages/installed` | Yes | Optional query `manager` | `package installed` | Installed packages. | +| `GET` | `/uniget/v1/packages/updates` | Yes | Optional query `manager` | `package updates` | Upgradable packages. | +| `GET` | `/uniget/v1/packages/details` | Yes | Package action query set | `package details` | Details payload. | +| `GET` | `/uniget/v1/packages/versions` | Yes | Package action query set | `package versions` | Installable versions. | +| `GET` | `/uniget/v1/packages/ignored` | Yes | None | `package ignored list` | Ignored-update rules. | +| `POST` | `/uniget/v1/packages/ignore` | Yes | Package action query set | `package ignored add` | Adds ignored-update rule. | +| `POST` | `/uniget/v1/packages/unignore` | Yes | Package action query set | `package ignored remove` | Removes ignored-update rule. | +| `POST` | `/uniget/v1/packages/download` | Yes | Package action query set | `package download` | Starts or performs download. | +| `POST` | `/uniget/v1/packages/install` | Yes | Package action query set | `package install` | Starts or performs install. | +| `POST` | `/uniget/v1/packages/reinstall` | Yes | Package action query set | `package reinstall` | Reinstalls package. | +| `POST` | `/uniget/v1/packages/update` | Yes | Package action query set | `package update` | Updates one package. | +| `POST` | `/uniget/v1/packages/uninstall` | Yes | Package action query set | `package uninstall` | Uninstalls package. | +| `POST` | `/uniget/v1/packages/uninstall-then-reinstall` | Yes | Package action query set | `package repair` | Repair flow. | +| `POST` | `/uniget/v1/packages/show` | Yes | Query `packageId`, `packageSource` | `package show` | UI-oriented package-details flow. | +| `POST` | `/uniget/v1/packages/update-all` | Yes | None | `package update-all` | Requires `OnUpgradeAll` handler to be wired. | +| `POST` | `/uniget/v1/packages/update-manager` | Yes | Query `manager` | `package update-manager` | Requires `OnUpgradeAllForManager` handler to be wired. | + +## Headless-specific limitations + +In headless sessions: + +- `POST /uniget/v1/app/show` fails because there is no window to show. +- `POST /uniget/v1/app/navigate` fails because there is no UI page stack to navigate. +- `POST /uniget/v1/packages/update-all` fails unless a host wires `OnUpgradeAll`. +- `POST /uniget/v1/packages/update-manager` fails unless a host wires `OnUpgradeAllForManager`. + +These failures are intentional and surfaced as HTTP `400` with a descriptive message. + +## Practical testing tip + +If you want to inspect the IPC API manually with generic tools such as `curl`, the easiest route is to start UniGetUI in **TCP mode**: + +```powershell +UniGetUI.exe --headless --ipc-api-transport tcp --ipc-api-port 7058 +``` + +Then: + +```powershell +curl http://localhost:7058/uniget/v1/status +``` + +For authenticated endpoints, you must also supply the session token as the `token` query parameter. The built-in CLI and `IpcClient` resolve that automatically. diff --git a/global.json b/global.json new file mode 100644 index 0000000..abe5820 --- /dev/null +++ b/global.json @@ -0,0 +1,6 @@ +{ + "sdk": { + "version": "10.0.103", + "rollForward": "latestFeature" + } +} diff --git a/media/Icon sizes/1024.png b/media/Icon sizes/1024.png new file mode 100644 index 0000000..3b52f4e Binary files /dev/null and b/media/Icon sizes/1024.png differ diff --git a/media/Icon sizes/128.png b/media/Icon sizes/128.png new file mode 100644 index 0000000..5aa2be8 Binary files /dev/null and b/media/Icon sizes/128.png differ diff --git a/media/Icon sizes/16.png b/media/Icon sizes/16.png new file mode 100644 index 0000000..800fe4c Binary files /dev/null and b/media/Icon sizes/16.png differ diff --git a/media/Icon sizes/2048.png b/media/Icon sizes/2048.png new file mode 100644 index 0000000..461ca1f Binary files /dev/null and b/media/Icon sizes/2048.png differ diff --git a/media/Icon sizes/256.png b/media/Icon sizes/256.png new file mode 100644 index 0000000..003fe7e Binary files /dev/null and b/media/Icon sizes/256.png differ diff --git a/media/Icon sizes/32.png b/media/Icon sizes/32.png new file mode 100644 index 0000000..9dd83b1 Binary files /dev/null and b/media/Icon sizes/32.png differ diff --git a/media/Icon sizes/4096.png b/media/Icon sizes/4096.png new file mode 100644 index 0000000..dcbc310 Binary files /dev/null and b/media/Icon sizes/4096.png differ diff --git a/media/Icon sizes/512.png b/media/Icon sizes/512.png new file mode 100644 index 0000000..8b9c6dd Binary files /dev/null and b/media/Icon sizes/512.png differ diff --git a/media/Icon sizes/64.png b/media/Icon sizes/64.png new file mode 100644 index 0000000..90392f6 Binary files /dev/null and b/media/Icon sizes/64.png differ diff --git a/media/Icon sizes/8.png b/media/Icon sizes/8.png new file mode 100644 index 0000000..6e4aafd Binary files /dev/null and b/media/Icon sizes/8.png differ diff --git a/media/UniGetUI Media.pptx b/media/UniGetUI Media.pptx new file mode 100644 index 0000000..bf69f6f Binary files /dev/null and b/media/UniGetUI Media.pptx differ diff --git a/media/UniGetUI-Image.png b/media/UniGetUI-Image.png new file mode 100644 index 0000000..efddfa5 Binary files /dev/null and b/media/UniGetUI-Image.png differ diff --git a/media/UniGetUI_1.png b/media/UniGetUI_1.png new file mode 100644 index 0000000..9928902 Binary files /dev/null and b/media/UniGetUI_1.png differ diff --git a/media/UniGetUI_2.png b/media/UniGetUI_2.png new file mode 100644 index 0000000..643f4ec Binary files /dev/null and b/media/UniGetUI_2.png differ diff --git a/media/UniGetUI_3.png b/media/UniGetUI_3.png new file mode 100644 index 0000000..13ba927 Binary files /dev/null and b/media/UniGetUI_3.png differ diff --git a/media/UniGetUI_4.png b/media/UniGetUI_4.png new file mode 100644 index 0000000..21560ee Binary files /dev/null and b/media/UniGetUI_4.png differ diff --git a/media/UniGetUI_5.png b/media/UniGetUI_5.png new file mode 100644 index 0000000..15935a5 Binary files /dev/null and b/media/UniGetUI_5.png differ diff --git a/media/UniGetUI_6.png b/media/UniGetUI_6.png new file mode 100644 index 0000000..db48a6d Binary files /dev/null and b/media/UniGetUI_6.png differ diff --git a/media/UniGetUI_7.png b/media/UniGetUI_7.png new file mode 100644 index 0000000..1e28659 Binary files /dev/null and b/media/UniGetUI_7.png differ diff --git a/media/UniGetUI_8.png b/media/UniGetUI_8.png new file mode 100644 index 0000000..dbb6998 Binary files /dev/null and b/media/UniGetUI_8.png differ diff --git a/media/UniGetUI_9.png b/media/UniGetUI_9.png new file mode 100644 index 0000000..535dc90 Binary files /dev/null and b/media/UniGetUI_9.png differ diff --git a/media/assets/devolutions-unigetui-color-shadow.svg b/media/assets/devolutions-unigetui-color-shadow.svg new file mode 100644 index 0000000..e791000 --- /dev/null +++ b/media/assets/devolutions-unigetui-color-shadow.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/media/assets/devolutions-unigetui-color.svg b/media/assets/devolutions-unigetui-color.svg new file mode 100644 index 0000000..e734367 --- /dev/null +++ b/media/assets/devolutions-unigetui-color.svg @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/media/assets/devolutions-unigetui-icon-halo.svg b/media/assets/devolutions-unigetui-icon-halo.svg new file mode 100644 index 0000000..553750a --- /dev/null +++ b/media/assets/devolutions-unigetui-icon-halo.svg @@ -0,0 +1,4 @@ + + + + diff --git a/media/assets/devolutions-unigetui-icon-shadow.svg b/media/assets/devolutions-unigetui-icon-shadow.svg new file mode 100644 index 0000000..b328f72 --- /dev/null +++ b/media/assets/devolutions-unigetui-icon-shadow.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/media/assets/devolutions-unigetui-icon-tray.svg b/media/assets/devolutions-unigetui-icon-tray.svg new file mode 100644 index 0000000..7f994d9 --- /dev/null +++ b/media/assets/devolutions-unigetui-icon-tray.svg @@ -0,0 +1,3 @@ + + + diff --git a/media/assets/devolutions-unigetui-icon.svg b/media/assets/devolutions-unigetui-icon.svg new file mode 100644 index 0000000..b1c408a --- /dev/null +++ b/media/assets/devolutions-unigetui-icon.svg @@ -0,0 +1,55 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/media/assets/devolutions-unigetui-white.svg b/media/assets/devolutions-unigetui-white.svg new file mode 100644 index 0000000..5f093e8 --- /dev/null +++ b/media/assets/devolutions-unigetui-white.svg @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/media/assets/devolutions-unigetui-wordmark.svg b/media/assets/devolutions-unigetui-wordmark.svg new file mode 100644 index 0000000..31fe8d1 --- /dev/null +++ b/media/assets/devolutions-unigetui-wordmark.svg @@ -0,0 +1,3 @@ + + + diff --git a/media/assets/devolutions-unigetui.ico b/media/assets/devolutions-unigetui.ico new file mode 100644 index 0000000..eda9c13 Binary files /dev/null and b/media/assets/devolutions-unigetui.ico differ diff --git a/media/assets/splash-dark.png b/media/assets/splash-dark.png new file mode 100644 index 0000000..f9dcf0e Binary files /dev/null and b/media/assets/splash-dark.png differ diff --git a/media/assets/splash-dark.svg b/media/assets/splash-dark.svg new file mode 100644 index 0000000..24e4435 --- /dev/null +++ b/media/assets/splash-dark.svg @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/media/assets/splash-dark@2x.png b/media/assets/splash-dark@2x.png new file mode 100644 index 0000000..46f3f0f Binary files /dev/null and b/media/assets/splash-dark@2x.png differ diff --git a/media/assets/splash-light.png b/media/assets/splash-light.png new file mode 100644 index 0000000..ed68ad3 Binary files /dev/null and b/media/assets/splash-light.png differ diff --git a/media/assets/splash-light.svg b/media/assets/splash-light.svg new file mode 100644 index 0000000..8d23250 --- /dev/null +++ b/media/assets/splash-light.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/media/assets/splash-light@2x.png b/media/assets/splash-light@2x.png new file mode 100644 index 0000000..7c2fa2e Binary files /dev/null and b/media/assets/splash-light@2x.png differ diff --git a/media/banner.png b/media/banner.png new file mode 100644 index 0000000..495eb22 Binary files /dev/null and b/media/banner.png differ diff --git a/media/customcolor_icon_old.ai b/media/customcolor_icon_old.ai new file mode 100644 index 0000000..87e191e --- /dev/null +++ b/media/customcolor_icon_old.ai @@ -0,0 +1,6198 @@ +%PDF-1.5 % +1 0 obj <>/OCGs[5 0 R 6 0 R 88 0 R 89 0 R 169 0 R 170 0 R 251 0 R 252 0 R]>>/Pages 3 0 R/Type/Catalog>> endobj 2 0 obj <>stream + + + + + application/pdf + + + Mobile + + + Adobe Illustrator CC 23.0 (Windows) + 2023-01-23T18:32:26+01:00 + 2023-01-23T18:33:56+01:00 + 2023-01-23T18:33:56+01:00 + + + + 200 + 256 + JPEG + /9j/4AAQSkZJRgABAgEASABIAAD/7QAsUGhvdG9zaG9wIDMuMAA4QklNA+0AAAAAABAASAAAAAEA AQBIAAAAAQAB/+4ADkFkb2JlAGTAAAAAAf/bAIQABgQEBAUEBgUFBgkGBQYJCwgGBggLDAoKCwoK DBAMDAwMDAwQDA4PEA8ODBMTFBQTExwbGxscHx8fHx8fHx8fHwEHBwcNDA0YEBAYGhURFRofHx8f Hx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8f/8AAEQgBAADIAwER AAIRAQMRAf/EAaIAAAAHAQEBAQEAAAAAAAAAAAQFAwIGAQAHCAkKCwEAAgIDAQEBAQEAAAAAAAAA AQACAwQFBgcICQoLEAACAQMDAgQCBgcDBAIGAnMBAgMRBAAFIRIxQVEGE2EicYEUMpGhBxWxQiPB UtHhMxZi8CRygvElQzRTkqKyY3PCNUQnk6OzNhdUZHTD0uIIJoMJChgZhJRFRqS0VtNVKBry4/PE 1OT0ZXWFlaW1xdXl9WZ2hpamtsbW5vY3R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo+Ck5SVlpeYmZ qbnJ2en5KjpKWmp6ipqqusra6voRAAICAQIDBQUEBQYECAMDbQEAAhEDBCESMUEFURNhIgZxgZEy obHwFMHR4SNCFVJicvEzJDRDghaSUyWiY7LCB3PSNeJEgxdUkwgJChgZJjZFGidkdFU38qOzwygp 0+PzhJSktMTU5PRldYWVpbXF1eX1RlZmdoaWprbG1ub2R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo +DlJWWl5iZmpucnZ6fkqOkpaanqKmqq6ytrq+v/aAAwDAQACEQMRAD8A9U4q7FXYq7FXYq7FXYq7 FXYq7FXYq6uKurirq4q7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq0TiqxpA MVWGYYq16wxVsTDFV6yA4qvBxVvFXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXHFVGR6V xVgnnT8w7fRJRbRq0ty2/BdqCtKknL8Onlk5cnV9o9rY9LQkCZHoGIn83r0/8e7f8H/ZmR+Ql3uq /wBFOP8AmS+YW/8AK3b7/lnb/g/7MfyEu9f9FOP+ZL5hUh/N+5Ei+pbtwr8VGBNPwx/IS70j2oxX vCX2PSfL3mC21azS5gfkrAHv/HMKUTE0XpMWWOSInE3Ep9G9RkWxWGKuxV2KuxV2KuxV2KuxV2Ku xV2KuxV2KuxV2KuxV2KtNiqEuWoDirwH8yST5omJNaoKf8E2bbQ/R8Xg/aYf4SP6g+8sWzNeedir sVeu/lTKRpFOwY/rOaTVf3hfSOxP8Uh7j95ek27VGY7tUYpxVvFXYq7FXYq7FXYq7FXYq7FXYqpy XEaCrGmKoOXWbRDQyDFVE+YLH/fo/HFWv8Q2X+/R+OKu/wAQ2X+/R+OKu/xDZf79H44qtbzDZU/v R+OKoO51+yIP70fjirxPz7dR3PmGSSM8l4gV/wBkxzbaD6D73hfaf/GI/wBQffJjuZrzjsVdir0r 8tdVt7fT2jdwCG6fSc0mq/vC+k9if4pD3H7y9DtvMFlT+8H45ju0Rq+YbL/fo/HFV3+IbL/fo/HF Xf4hsv8Afo/HFXf4hsv9+j8cVXLr9kf92D8cVRMOp20lOLg1xVFLIrCoOKrsVdirsVQd/fLbx8iR irzXzT+Yf1aR4IKPNWnEdt+5xVhF15z1mdy3NUHYAE/rOKoY+ZdXP+7fwxV3+JdW/wB+/hirv8S6 t/v38MVa/wATat/v38MVaPmXVqf3v4Yqh5vMmrEH97+GKpPFdz3TzSzNyf1CK+1Af45ttB9B97wv tP8A4xH+oPvkq5mvOOxV2Koex1m/tbu5jheihhQfRmk1X94X0jsT/FIe4/eU3i8zauB/ej7sx3ao geadY/36PuxV3+KdZ/36PuxV3+KtZ/36PuxVr/FWs/79H3Yq2PNutjpMPuxVNdM/MbVbaRfrCq6D utQafInFXqPlbzlBqMCurq1TQ4qzOKUOtRiq/FVkrhUJ8BirzL8xfMjW0HpxH969VT5+OKvJnZnY sxqzGpJ7k4q1irsVarirWKuriq09MVUJT1xVDaf9mb/jKf8AiIzbaD6D73hfaf8AxiP9QffJF5mv OOxV2KpRH/x0Lr/WH/ERmk1X94X0jsT/ABSHuP3lMIztmO7VWBxVvFWq4q1irVcVdiqYaHq82m3y Sqx9IkCVfbx+jFX0J5Z1VLuBSDWq1xVkQ6YqhdRcrbyH/JP6sVeDef7ppdWWMmvBSaf6xp/xrirG MVaxV1cVarirWKuriq09MVUJT1xVD6f9mb/jKf8AiIzbaD6D73hfaf8AxiP9QffJF5mvOOxV2KpQ n/HQuv8AWH/ERmk1X94X0nsT/FIe4/eUfGdsx3aKwOKuxV1cVaxVquKtYq6uKvaPyuvHexhVjWkY H3UGKvT0NVGKoLVf95ZP9U/qxV4B50P+5tv9Qf8AEmxVIa4q1irVcVdirVcVarirR6Yqh5T1xVQ0 4ms47ep/AZtdB9J97w/tQP38f6n6SjMznmnYq7FUliJN/dE/78p9wpmj1P8AeF9L7HFaWHuTGPpl DslYYq6uKtVxV2KtVxVrFWq4q9f/ACrP+ix/6n8cVesxfYGKoPVv95ZP9U/qxV8/+df+O23+oP8A iTYqkNcVaxVquKuxVquKtYq03TFUPKeuKqGnfauP+Mn8M2ug+k+94j2o/vo/1f0lG5nPMuxV2KpJ D/vdd/8AGQ5o9T/eF9L7I/xXH/VTGM7ZQ7JWGKurirWKtVxV1cVaxVquKvX/AMqv95Y/9T+OKvWo vsDFUHq3+8sn+qf1Yq+fvOv/AB22/wBQf8SbFUgrirsVarirWKtVxVqoxVotiqHlIxVS03rcf6/8 M2ug+k+94j2o/vo/1f0lG5nPMuxV2KpJH/vddf8AGQ5o9T/eF9M7I/xXH/VR8Z2yh2KsCMVdXFXV xVquKtVxV2KtVxV7B+VP+8sf+p/HFXrUX2BiqD1b/eWT/VP6sVfP3nb/AI7jf6g/4k2KsfrirWKu rirROKrGfFVIzKO+KrDOvjiqlJMu++KtaWwPrkf78/gM2ug+k+94j2o/vo/1f0lH5nPMuxV2KpCr gX93U/7sOaPU/wB4X0vsj/Fcf9VFpMvjlDslUTr44q2JgehxVeGxVdXFWsVarirq4q9g/Kn/AHkj /wBT+OKvW4vsDFUHq3+8sn+qf1Yq+ffO/wDx3G/1B/xJsVY/XFWsVariq1jiqEnIeWOMmiuaE/w+ nLcEBKYBcHtLUTw4JTh9QH4Pw5rjplkesf8Awzf1zbflcfc8J/Ler/nn5D9TX6KsP99f8M39cfyu PuX+WtX/ADz9n6mv0Tp5/wB1f8M39cfyuPuX+WtX/PP2fqVra0t7ZWWBOAY8m3JqeneuWwxxiKDh 6nV5M5vIeIhWybjuxV2KoN9J095XlaGsjmrtyYVP0HKZaeBNkOwxdq6nHERjOoj3fqd+iNO/31/w zf1yP5XH3Nn8tav+efkP1O/ROn/76/4Zv64/lcfcv8tav+efkP1KN5Y2kFs8sS+m6CoPImu/Tc98 pz6aAgSBTsOy+19TPURjKXFGRqqH42agcsgJ65qnuUQDireKtVxVrFXsX5Uf7yRf6n8cVetxfYGK oPVv95ZP9U/qxV8+eeP+O43+oP8AiTYqx+uKtYq1XFVj4qhLhA6kH6MUEAiiusbtn/czf3q9GP7Q 8fn45uNLqOMUfqeB7a7JOnlxw/uz9nl7u5GZluhdirsVdirsVdirsVdirTMqqWYgKBUk9ABgJTGJ Joc0juLpr242BFtH9gGo5H+Y/wAM0+p1HGaH0voHY3ZQ08eKX95L7PL9aJiFBmK7xXXFV2KtVxVr FXsf5Uf7yRf6n8cVetxfYGKoPVv95ZP9U/qxV89+ef8Ajut/xjH/ABJsVY9irsVariq074qoyDFU FcQsaMp4upqrDqDhjIg2GGXFHJExkLiUZZXizqVbaZKc1/iPbN1p84yDzfOe1ezZaXJXOB5H9HvR WZDq3Yq7FXYq7FXYq7FUj1G8N45t4W/0dDSRh+2R2HsM1er1N+mPJ7bsLsjwwM2Qes8h3efv+5uJ AAAMwHp0Si4qqjFXYq6uKtYq9j/Kf/eOL/U/jir1yL7AxVB6t/vLJ/qn9WKvnrzz/wAd1v8AjGP+ JNirHsVarirq4q1iqxhiqhImKoOVHjcTRbSr0Pj7HJ48hgbDj6rTQz4zCY2KZWlylxEHA4sNnTuD 4Zu8WUTjYfNtdop6bIYS+B7wr5a4bsVdirsVdiqUarfuzmztz7TyDsP5R7+Oa/V6mvTH4vU9g9kc ZGbIPT/CO/z93d3qEEKooVRQe2ax7RFItMVVQMVXVxVrFWq4q7FXsn5Tf7xxf6n8cVeuRfYGKoPV v95ZP9U/qxV89eev+O63/GMf8SbFWO4q1XFWsVdXFWjiqxhXFUPIoxVCEyW8wni7bOnZhluHMYSs OD2hoIanHwy59D3FN4J454hJGaqfvB7g5u4TEhYfNtRp54ZmExUgqZNpdirsVS3VNRMQ+rQH/SHG 5H7APf5+GYmq1HAKH1O+7F7JOolxz/ux9vl7u9AW8CooHU9yepzTvfAACgi0XFKsoAxVdirq4q1i rVcVaxV7N+Uv+8UX+p/HFXrkX2BiqD1b/eWT/VP6sVfPPns/7nW/4xj/AIk2KsdxVquKtYq1XFXY q0d8VU2GKoeROuKoeKZ7OYuPihY/vE/42HvmTp85xnydR2t2WNVCxtkjyP6CnKOjoHQhlYVBHcZu QQRYfO5wMJGMhRC7CxQWpagLWMKlGuJNo0/42PsMx9RnGMebtOyuzZarJXKA5n9HvSqCJ6l3PKRz V2PUnNLKRJsvo2LFHHERiKiEWiYGasoxVd0xV1cVarirsVarirWKvZvyl/3ii/1P44q9di+wMVQe rf7yyf6p/Vir548+H/c83/GMf8SbFWOYq6uKtYq1XFWsVdXFWjiqm61xVDSxgilMVUoprq1qIaNG dzG3QfLwzIw6mUNuYdT2h2Pi1J4j6Z94/SvfWLxhRLdUb+ZmLD7gFzIOvPQOqx+y0QfVMkeQr9JQ qxO8hmmPOVurH9QzBnMyNl6TT6eGGAhAVEIpEyLerKuKr8VaxV1cVaxVrFXVxVrFXs/5Sf7wxf6n 8cVeuxfYGKoPVv8AeWT/AFT+rFXzv58P+54/8Yx/xJsVY5irVcVdirVcVaxVquKuxVad8VWMoxVR aOuKrPTGKrljxVeoxVeBirq4q1irVcVdirVcVarirsVe0flJ/vDF/qH/AIlir12L7AxVB6t/vLJ/ qn9WKvnbz6f9zx/4xj/iTYqxzFWq4q1irq4q1irVcVdirVcVaOKrSK4qtpirqYq3irWKurirWKtV xV2KtVxVrFWq4q9p/KP/AHgh/wBQ/wDEsVevRfYGKoPVv95ZP9U/qxV87efv+O+f+MY/4k2KsbxV quKtYq1XFXYq1XFWsVarirsVarirVcVdirVcVaxVquKuxVquKtYq6uKtYq1XFXtX5Rf7wQ/6h/4l ir16L7AxVB6t/vLJ/qn9WKvnXz//AMd8/wDGMf8AEmxVjVcVdXFWsVarirWKurirWKtVxV2KtVxV rFWq4q6uKtYq1XFWsVdXFWsVarirsVarir2v8ov94If9Q/8AEsVevRfYGKoPVv8AeWT/AFT+rFXz p+YH/HfP/GMf8SbFWNVxVquKuxVquKtYq1XFXYq1XFWsVdXFWsVarirWKuxVquKtYq1XFXYq1XFW sVdXFXtn5Q/8c+H/AFD/AMSxV69F9gYqg9W/3lk/1T+rFXkt/wCRrTXrya8mupIXjb0QqKpBA+Ku /wDrYqhv+VSad/1cJv8AgFxVr/lUunf8t83/AAK4q1/yqXTv+W+b/gVxVr/lUunf8t83/ArirR/K bTv+W+b/AIFcVa/5VNp3/LfN/wACuKtH8ptO/wCW+b/gVxVr/lU+nf8ALfN/wK4q1/yqfTv+W+b/ AIFcVd/yqfTv+W+b/gVxVb/yqfTv+W+b/gVxVr/lVGn/APLfN/wK4q1/yqjTv+W+b/gVxVo/lRp/ /LfN/wACuKtf8qp0/wD5b5v+BXFXf8qo0/8A5b5v+BXFXf8AKqNP/wCW+b/gVxVr/lU+n/8ALfN/ wK4q7/lU+n/8t83/AAK4q7/lU2nf8t83/ArirX/KptO/5b5v+BXFWYeQNNTTLh7CNzIkHwh2FCeh 7fPFXp8X2BiqD1b/AHlk/wBU/qxVhWkn4bn/AIzt/wARXFUdXFVpOKtE4q0TirROKtE4qtrirVcV arirVcVariq0nFWicVaxV2KuxV2KuxV2KuxV2Ku8sf8AHau/n/AYq9Di+wMVQerf7yyf6p/VirCN KPw3P/Gdv+IriqNJxVonFWq4q1XFWq4q1XFVtcVaJxVonFWicVaJxVbXFXYq7FXYq7FXYq7FXYq7 FXYq7yx/x2rv5/wGKvQ4vsDFUJqo/wBFk/1T+rFWD6ZsLn/jMf8AiK4qi64q1XFWq4q0TirROKrS cVaJxVquKtVxVquKtYq7FXYq7FXYq7FXYq7FXYq7FXYq35YH+5q7+f8AAYq9Cj+wMVQ+oJyt3H+S f1YqwWAGK7uYW6lg6j57H9QxVEE4q0TirROKtVxVquKra4q1XFWq4q1irsVdirsVdirsVdirsVdi rsVdirsVdiqJ8pQmS+nnH2XY0PsCAP1YqztBRQMVakXkhHjirDPMWnzQXMd3AlStQ6igqppUYqhI 5UkQOhqDirdcVarirVcVWk4q0TirWKuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxVD3LyuPq9uOU0m 1R+yD3/pirMvL+mC1hUcQNsVTvFXYqhru0jnSjDFWJah5dlt5XmtGKljVk6qd+4xVLXlu4jSW3Y0 7oa/gaYqpm/P/LNN9y/81Yq19fP/ACzzfcv/ADVirX14/wDLPN9y/wDNWKtfXT/yzzfcv/NWKu+u n/lnm+5f+asVd9dP/LPN9y/81Yq766f+Web7l/5qxV310/8ALPN9y/8ANWKu+un/AJZ5vuX/AJqx V310/wDLPN9y/wDNWKu+un/lnm+5f+asVd9dP/LPN9y/81Yq766f+Web7l/5qxV310/8s833L/zV irvrp/5Z5vuX/mrFW/rp/wCWeb7l/wCasVcLtz0t5a+4UfxxVXhtdRuiFWP0VPVvtN9G1MVZDovl uG2HJqs7GrM25JxVkiIEFBiq7FXYq7FVrIrdcVUXsomO4GKqf6Nh/lGKu/RkPgMVd+jIfAYq79GQ +AxV36Mh8Birv0ZD4DFXfoyHwGKu/RkPgMVd+jIfAYq79GQ+AxV36Mh8Birv0ZD4DFXfoyHwGKu/ RkPgMVd+jIfAYq79GQ+AxVsadCP2RiqqltGnQDFVYADFXYq7FX//2Q== + + + + uuid:C1BCCE1871B8DB11993190FCD52B4E9F + xmp.did:ac8b3295-768d-154f-8a9d-693f27f836d3 + uuid:5e091acb-702f-4bd2-9277-4013f7bb6d5b + proof:pdf + + uuid:3bb36909-a733-4172-8ab7-6d277b4daa04 + xmp.did:4b2c66f6-4a34-184f-b228-8bd5c5cc3e9a + uuid:C1BCCE1871B8DB11993190FCD52B4E9F + proof:pdf + + + + + saved + xmp.iid:c8cea8c7-10c8-fd42-8ea2-52d6410202a3 + 2022-11-24T17:46:16+01:00 + Adobe Illustrator CC 23.0 (Windows) + / + + + saved + xmp.iid:ac8b3295-768d-154f-8a9d-693f27f836d3 + 2023-01-23T18:32:26+01:00 + Adobe Illustrator CC 23.0 (Windows) + / + + + + Mobile + Document + Adobe PDF library 15.00 + 1 + True + False + + 2400.000000 + 2400.000000 + Pixels + + + + Cyan + Magenta + Yellow + Black + + + + + + Default Swatch Group + 0 + + + + White + RGB + PROCESS + 255 + 255 + 255 + + + Black + RGB + PROCESS + 0 + 0 + 0 + + + RGB Red + RGB + PROCESS + 255 + 0 + 0 + + + RGB Yellow + RGB + PROCESS + 255 + 255 + 0 + + + RGB Green + RGB + PROCESS + 0 + 255 + 0 + + + RGB Cyan + RGB + PROCESS + 0 + 255 + 255 + + + RGB Blue + RGB + PROCESS + 0 + 0 + 255 + + + RGB Magenta + RGB + PROCESS + 255 + 0 + 255 + + + R=193 G=39 B=45 + RGB + PROCESS + 193 + 39 + 45 + + + R=237 G=28 B=36 + RGB + PROCESS + 237 + 28 + 36 + + + R=241 G=90 B=36 + RGB + PROCESS + 241 + 90 + 36 + + + R=247 G=147 B=30 + RGB + PROCESS + 247 + 147 + 30 + + + R=251 G=176 B=59 + RGB + PROCESS + 251 + 176 + 59 + + + R=252 G=238 B=33 + RGB + PROCESS + 252 + 238 + 33 + + + R=217 G=224 B=33 + RGB + PROCESS + 217 + 224 + 33 + + + R=140 G=198 B=63 + RGB + PROCESS + 140 + 198 + 63 + + + R=57 G=181 B=74 + RGB + PROCESS + 57 + 181 + 74 + + + R=0 G=146 B=69 + RGB + PROCESS + 0 + 146 + 69 + + + R=0 G=104 B=55 + RGB + PROCESS + 0 + 104 + 55 + + + R=34 G=181 B=115 + RGB + PROCESS + 34 + 181 + 115 + + + R=0 G=169 B=157 + RGB + PROCESS + 0 + 169 + 157 + + + R=41 G=171 B=226 + RGB + PROCESS + 41 + 171 + 226 + + + R=0 G=113 B=188 + RGB + PROCESS + 0 + 113 + 188 + + + R=46 G=49 B=146 + RGB + PROCESS + 46 + 49 + 146 + + + R=27 G=20 B=100 + RGB + PROCESS + 27 + 20 + 100 + + + R=102 G=45 B=145 + RGB + PROCESS + 102 + 45 + 145 + + + R=147 G=39 B=143 + RGB + PROCESS + 147 + 39 + 143 + + + R=158 G=0 B=93 + RGB + PROCESS + 158 + 0 + 93 + + + R=212 G=20 B=90 + RGB + PROCESS + 212 + 20 + 90 + + + R=237 G=30 B=121 + RGB + PROCESS + 237 + 30 + 121 + + + R=199 G=178 B=153 + RGB + PROCESS + 199 + 178 + 153 + + + R=153 G=134 B=117 + RGB + PROCESS + 153 + 134 + 117 + + + R=115 G=99 B=87 + RGB + PROCESS + 115 + 99 + 87 + + + R=83 G=71 B=65 + RGB + PROCESS + 83 + 71 + 65 + + + R=198 G=156 B=109 + RGB + PROCESS + 198 + 156 + 109 + + + R=166 G=124 B=82 + RGB + PROCESS + 166 + 124 + 82 + + + R=140 G=98 B=57 + RGB + PROCESS + 140 + 98 + 57 + + + R=117 G=76 B=36 + RGB + PROCESS + 117 + 76 + 36 + + + R=96 G=56 B=19 + RGB + PROCESS + 96 + 56 + 19 + + + R=66 G=33 B=11 + RGB + PROCESS + 66 + 33 + 11 + + + + + + Grays + 1 + + + + R=5 G=169 B=175 + RGB + PROCESS + 5 + 169 + 175 + + + R=26 G=26 B=26 + RGB + PROCESS + 26 + 26 + 26 + + + R=51 G=51 B=51 + RGB + PROCESS + 51 + 51 + 51 + + + R=77 G=77 B=77 + RGB + PROCESS + 77 + 77 + 77 + + + R=102 G=102 B=102 + RGB + PROCESS + 102 + 102 + 102 + + + R=128 G=128 B=128 + RGB + PROCESS + 128 + 128 + 128 + + + R=153 G=153 B=153 + RGB + PROCESS + 153 + 153 + 153 + + + R=179 G=179 B=179 + RGB + PROCESS + 179 + 179 + 179 + + + R=204 G=204 B=204 + RGB + PROCESS + 204 + 204 + 204 + + + R=230 G=230 B=230 + RGB + PROCESS + 230 + 230 + 230 + + + R=242 G=242 B=242 + RGB + PROCESS + 242 + 242 + 242 + + + + + + Mobile Color Group + 1 + + + + R=136 G=168 B=13 + RGB + PROCESS + 136 + 168 + 13 + + + R=127 G=71 B=221 + RGB + PROCESS + 127 + 71 + 221 + + + R=251 G=174 B=23 + RGB + PROCESS + 251 + 174 + 23 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +endstream endobj 3 0 obj <> endobj 8 0 obj <>/Resources<>/ExtGState<>/Properties<>/Shading<>/XObject<>>>/Thumb 267 0 R/TrimBox[0.0 0.0 2400.0 2400.0]/Type/Page>> endobj 254 0 obj <>stream +HTn0+q^A +4wivtd(P99Yѻ=k>}xu |rt{åx&4Qh 5"P d?> endobj 267 0 obj <>stream +8;Z]"lZ%S3%"t[#I\d.88/:F1rO:Kc`""dDk#!aB7(4O+ +n1/[E;n4BBf^e:VH-]i0<*HHr<%_?9bn9@)ZR.GAKpbe`Xd"Y&.h+N?kYR]m +JS8hY$1`=5Vf#RM@Tr[F=SB4rk%LKJ.4NKZc@JZBXpn243j]Jf0$+Uf0#;2%Qo`J< +k051^LcOH%^:QTT9$$?Z;M`[NE)R"0A=[P'@s0RM8,YU96mR#A''2.5>Z-ECSW:9V +SNK>=N^e7M.RteIQ6RnWcQ!P@Om((VoRCp-'1FO]'+$Z[CW`M,;=Z*lH1F6F,s,"K +n0k,pRW5BOB1T?RFX7Wd,7Dh5!gBe.d;.6RQ\_'F>*&5;Rs0[eE!^j/mg>LN>`.6U +AE,,Q+9@V/'2Q[mSu6G/,;=JJqr[oUJ&38%-TNI?GV/(jD7O5G:7dakZ,Jd-G4=)S +LcD,bVDr!6Etf4P%`&gXmCR7;b'8g$QH@T)7'KRE->nUNmnl)l0hlrm2s0>-@ +U$oS+Eh82gGVUR88km\C2t4FsX)*P)]-9`XQ--3@_&RI[BPq_LW2f91'L+VSc">;L +BHf'!]G&Y_6O:oQK05;FlZ;\6U+Ag3k6=6`+>W-$7/7+_E8R'S#gC.14K9`VJk&Io +]"%>qU@eqdl9/mXKLC4r$-h33Cj4?B\XNg5hd*eHkoSb[2g5t,3[3Y1d8l=rdQPC@ +\X,C8NqL[%G:Yc6Sa!^A][2JC]26sJdA"Oj<96fX +30^s1OCqY[i02<)]t^H= +endstream endobj 269 0 obj [/Indexed/DeviceRGB 255 270 0 R] endobj 270 0 obj <>stream +8;X]O>EqN@%''O_@%e@?J;%+8(9e>X=MR6S?i^YgA3=].HDXF.R$lIL@"pJ+EP(%0 +b]6ajmNZn*!='OQZeQ^Y*,=]?C.B+\Ulg9dhD*"iC[;*=3`oP1[!S^)?1)IZ4dup` +E1r!/,*0[*9.aFIR2&b-C#soRZ7Dl%MLY\.?d>Mn +6%Q2oYfNRF$$+ON<+]RUJmC0InDZ4OTs0S!saG>GGKUlQ*Q?45:CI&4J'_2j$XKrcYp0n+Xl_nU*O( +l[$6Nn+Z_Nq0]s7hs]`XX1nZ8&94a\~> +endstream endobj 264 0 obj <>/ExtGState<>/ProcSet[/PDF/ImageC/ImageI]/XObject<>>>/Subtype/Form>>stream +q +/GS0 gs +1899 0 0 2169 252 79 cm +/Im0 Do +Q + +endstream endobj 265 0 obj <>/ExtGState<>/ProcSet[/PDF/ImageC/ImageI]/XObject<>>>/Subtype/Form>>stream +q +/GS0 gs +1314 0 0 1692 563 856 cm +/Im0 Do +Q + +endstream endobj 266 0 obj <>/ExtGState<>/ProcSet[/PDF/ImageC/ImageI]/XObject<>>>/Subtype/Form>>stream +q +/GS0 gs +956 0 0 1331 723 1070 cm +/Im0 Do +Q + +endstream endobj 279 0 obj <> endobj 281 0 obj <>stream +Hۭ`NCޥa Y~\tvA^؟>1fdwwz>0CoN~@K߫WcՏȏV?z?_!G]ܡzרUg1\~U /_;U?Z<^V}~>W}Z|VܬmY]s:buxW>~?}^ת}^ת}^ת}^ת}^ת}^ת}^ת}^ת}^ת}^xblp]6u.:\lM.˦eSvblp]6u.:\lM.˦eSvblp]&ueRg˱]&ueRg˱]&ueRg˱]&ueRg˱]&ueRg˱]&ueRg˱]&ueRg˱]&ueRg˱]&ueRg˱]&ueRg˱]&ueRg˱]&ueRg˱]&ueRg˱]&ueRg˱]&ueRg˱]&ueRg˱]&ueRg˱]&ueRg˱]&ueRg˱]&ueRg˱]&ueRg˱]&ueRg˱]&ueRg˱]&ueRg˱]&ueRg˱]&ueRg˱]&ueRg˱]&ueRg˱]&ueRg˱]&ueRg˱]&ueRg˱]&ueSwvbln]6u.[lM-˦eSwvbln]6u.[lM-˦eSwvbln]6u.[lM-˦eSwvbln]6u.[lM-˦eSwvbln]6u.[LM.˦eSvblp]6u.:\lM.˦eSvblp]6u.:\lM.˦eSvblp]6u.:\lM.˦eSvblp]6u.:\lM.˦eSvblp]6u.:\lM.˦eSvblp]6u.:\lM.˦eSvblp]6u.:\lM.˦eSvblp]6u.:\lM.˦eSvblp]6u.:\lM.˦eSvblp]6u.:\lM.˦eSvblp]6u.:\lM.˦eSvblp]6u.:\lM.˦eSvblp]6u.:\lM.˦eSvblp]6u.\U].uܪ.nUK]˥.[Rr Vup\U].uܪ.nUK]˥.[Rr Vup\U].uܪ.nUK]˥.[Rr Vup\U].uܪ.nUK]˥.[Rr Vup\U].uܪ.nUK]˥.[Rr Vup\U].uܪ.nUK]˥.[Rr Vup\U].uܪ.nUK]˥.[Rr Vup\U].uܪ.nUK]˥.[Rr Vup\U].uܪ.>1 kDGA0V|#|Vt ]nbEX. Vt ]nbEXΣ<:hΣ<:hΣ<:hΣ<:hΣ<:hΣ<:hΣ<:hΣ<:hΣ<:hΣ<:hΣ<:hΣ<:hΣ<:hΣ<:hΣ<:hΣ<:hΣ<:hΣ<:hΣ<:hΣ<:hΣ<:hΣ<:hΣ<:hΣ<:hΣ<:hΣ<:hΣ<:hΣ<:hΣ<:hΣ<:hΣ<:hΣ<:hΣ<:hΣ<:hΣ<:hΣ<:hΣ<:hΣ:zx:zx:zx:zx:zx:zx:zx:zx:zx:zx:zx:zx:zx:zx:zx:zx:zx:zx:zx:zx:zx:zx:zx:zx:zx:zx:zx:zx:zx:zx:zx:zx:zx:zx:zx:zx:zx:zx:zx:zx:zx:zx:zx:zx:zx:zx:zx:zx:zx:zx:zx:zx:zx:zx:zx:zx펣8z8z8z8z8z8z8z8z8z8z8z8z8z8z8z8z8z8z8zn׏]6zn׏]6zn׏]6zn׏]6zn׏]6zn׏]6zn׏]6zn׏]6zn׏]6zn׏]6zn׏]6zn׏]6zn׏]6zn׏]6zn׏]6zn׏]6zn׏]6zn׏]6zn׏]6zn׏]6zn׏]6zn׏]6zn׏]6zn׏]6zn׏]6zn׏]6zn׏]6zn׏]6zn׏]6zn׏]6zn׏]6zn׏]6zn׏]6zn׏]6zn׏]6zn׏]6zn׏]6zn׏]6zn׏]6zn׏]6zn׏]6zn׏]6zn׏]6zn׏]6zn׏]6zn׏]6zn׏]6zn׏]6zn׏]6zn׏]6zn׏]6zn׏]6zn׏]6zn׏]6zn׏]6zn׏]6zn׏]6zn׏]6zn׏]6zn׏]6zn׏:zh. Rty +mNt2o%B?}Ă m^hVhVXUXUHUHUHUHTHTHTHTHT8THSHT8T8THSHSHS8T8T8SHS8T8S8T8S8T}F zH.?%`/u?O;{I} G]/s.VSP$GՕ~ +Y`uuk B}XY:QVU@']%`=u/|Y}(XK]SJR Q\wU->.dCAlP<>OOSAzЩ;>TN 'B%#|uu]>$Uw0W]܅SLuo Ե]>'Rv0G]Ia!xuegF +Ս Sƪ >-T5T}\k0Jpa uW37ꮦ ׫>3\njpSÕꞦ שk>7\nip5 +uGp^]Q>;U7u?p\]O>WG1u9 _G,~f]u3˨碑YH +xGJ_;^R?^Wײ𪺕ԥ,~ dIS{u%ߩYUNȲBVR9𹺎m,~|.c#u[C%]]&7&Q? +~VU𣺇ς5l~_vS Ve𧺃-OT U? X:d7W窷-?Np^/?Qs#O?TvWodzzV}^g_v?xU\!nCQ3`?fG=vS/S`/^A=vRk`'ZI=Qo_ԃ`RM= Pԣ`JP= WoO`uBL VW/O`m>B=VV/`]6F=VU/oaM.yA=VT3a=&yMSoCa5"yY=R7ca%yK=Qo7Ճay[=P՛a 9 +W!lz8rX=Z8z}RχN=ND^g R/ ѨwQW%1_9.RqzJU cbzm\^3kR,Ҹ\=)w^CԳbzc R1L=-ƪ8bz] Uϋqm1X=0Fp#czULQό՛bzg\CjתDظR&u-1Y=8R/qzGqzEqzE$q^!"8^zzSP=>ΨC!VPQrz7,!Gԫa y_QwՋayORwka)y]R[a1 yUSO;aA(yETϒaQ0NUO`]6ZV`i<\ W`yDX 6Pԫ` L] 6Q_Ջ`RUQO{`#XQRϕ[`3`z l,wz^-W"]KUOzV}ls՟ PAj$fvοD^U;xW,~=իwTo"GO8˨_y7,~kwRoZI5z,~];P̒A1{},~V^[.K{e,~u˲WU'_S*[|El~ԋS/6W_M'}-l~[Q/v_E#~ l~WPoȦǟ_ ۪_v~l~뱵gVoU/fUuwR?{DR0z1Na6^W\u37 Q/oẸ^ +ީEbJ:0W/]|cl:𹺎>/Filter/FlateDecode/Height 1331/Intent/RelativeColorimetric/Length 95307/Name/X/Subtype/Image/Type/XObject/Width 956>>stream +H _glv7j4Qh>來>CR@56ouUOwOI֡~zJ$I$I$I$I$/.鿕$9>yNA%)9-rO,I8IrN%S#r/IGℯ9r>ڿ}ΰ?$fOO"I -u?_WrI_wWb{NBd-ܽl}|C+zFխ!.e_NPd/\[{G\&W +5zԵR6ݻ|$Ie/Wkݣ:lW_+Urpuf&ݙ/laݯ蕂-&[EgwR3dN?t5^ھ`u"0[Zꕂ!rթlv^TNcE'}#W.efO"\cEkW+%o5YN:L3+ ؗWr0j2Z ,#N;S{93aL~|xG?KW?MrݲZK3FQn;6fV>z\{t.ry2\ݭR` Y*Z/ECG7(lX ~Mz@Ke\\niۂ-eK;'h0 f(z%KW_f8.ҶedVQC?h]p[J3!` ؿ̗t8uemUp[VKfE#uI+2ƽg0e2 LW55^_TRet媕[2xt a~5+x%Gk˴tV\n-ВX'$$kus$$$x&%eǏҡ~/l5[l[bfI7$;H20%^q_PK3V+xCʎv/Wnl]'5%%%55Kv+3 Γ;H2/իga揮zjKWɥkeI7YRIOgddiRB2_^zիӿgGW&+nS,yɥ ';,1&Uz͂W:-]:5XظȼMfk~~AAaaaUlt'YLcc‚ D8/bbW/^罘b\w.ɽ57r@ E*7sH1 ` ؾ Wޘ3z+}=U/3Q1xk7nӾ[-*e1 sHq .`||YoZ+W ]~b鞏My nmYyVҺ:Sݐ>, i0$¥%a*/|^͂Wr ;NtKK],76n~AQ1܂muM-ԦJYk|ki&\#UN1onvV&{Njt8fr5Kr1[Sett$еLrsnyEU5746Al+좺7F1|gGnm! o^NVfMV/^|7'|6tĪx]SSOl[;P{{~j`P3Oz{ `"ٷ3Ro(̈́7L"WtCB,tԍ1nrJ&6ْYxϡ4sIjQ=<<<4`˂ᷩ뷺0?3 1g+v@eZcB7JK7Vf[Y]SW{h,OLLZSA>}L=111>>6#dxwua`B/]t8wcW F2nzFVN?0Dj'&tzzffvvzh4y14< &=X-M ZҋYδz5'Ьk/]7SoefZ{w`pxlvz`t~~aaqqq =8G/-..,,σBc+ =^"5sLW?Z'whvo]ueVoNfzxO ^bW +H~.а?sVMNrqiEu]}Sk;ʝ K`:>W^~A13Frs0,C%-U%t7$]7^+Wty]Ѝ$1tx^.mli;0;Mp=[}f_ο_mƈ;;[[Mtu1>dݝmXxe{"YJv~B.ӽCrU-nGwٹ%]xb%nm뛷owww߽{+KRbwo߂4)a~l.?ޑ^΍&7w'#+W. 譫Ž?8269`ng/ؾy ?~7<}N=0}Kw]^Zމ=X|7x76F>yeJg톐]u1XЍ7⩋{Kw,bܟvlIدϯ(3 rn$kCD\EQQbA,PAPTPPD(Pffe A@(ꪛlL6亟=O% //V3cK_Kv5kwd1Ϟch`ђefVt{x^@F@n|b2HsdP[Xee +TJصtBQVP\W!JMNs+2"48aZ+`ˋZ(^!O.~OtWZXݰ:>~7#oA.*7K#'e +xT*kXju%Z]]UTrE73=591˙U%oOw-Xt1zjB +hN1Ō+W[lZ_](ݛ1qԹ+/[TVUVi`iԍp꺺: +XYYQW-! "Bz{qw9;m7^ejW$3;}kz&۝8/^B +܂2EE%֪@V[(#;Eqb+ӛ2jk\A|8Iwon!Լ;n\frjxB&,i3frͺ[w v#WzvbټnGO"މON˔AnU-"===CMhH7" ĝ|@oIQ՛p;qa7}y,IpȮf̛pl1t䄛W7EE[ Oh l__#c<Ѽәh(`ߦz0O&%z{z<~򮳲~Bb?xA)h$GAʷ +[ ]t,r+f!q&7R~7\VX;{╠p5]enCpKj ,DBX^Hkp&`yyùRQ\Kxcƒ.zq;qi-֎Wã7]!q'3ڵټn#నxnn;>Dp^@+  w[\$Az;QJE Ûv*Ob5xzh/D3df;}֨pمsɢ,--W7ut=yAtk" \>HsL2b||^[Kc]Ǜwf5 XGwl,(1Y +|j2v wcFĭؤLֺ6wtѹϞB-#寣)#L2 _'z:Z8rifZbltDH^n;1Woƴhf+dB<}&EW&fH%uQr[R1u&y _}{x dԄ;QaXN8tE̞9]k4 ^!Zy\#KWZYj 3/_ ϮD_`tu={E.Z8HsJFHv8'/z98@ՋN[('߾ygPĘF fz4 ^!dF_vpbeUt?xr ۟Zϣ)3A`_^/Uo_oYQ^vVZRltxpiW-֮2[d[a4 s_`bj&[;.~|E$fJs K+et zepI/ZA` yҨ(ŗ7#%!&2T]{l7Xahh?B +L9VYlnQqbY~Iy't߽gr?2Y?a~?Qv4V,JG?ޣNvmlcѼv,dmwɼq=Q Ŭmhn`wxrn3L~ûoޞw~}6UQqJ% (((D JA%HP ,9H 53-g}ι*v Իl.u9I1TJ%ø]hZ]Je606s RԘ;{F}+L."ePc~?"B6ww[S~0?7+-9.:"4阕&4pq`:xIdVZrrùKW\¢&{Al}8]pt\E +j0^ `ܹaA~.6ҕfE%Ya(s]DԘGƟ<那$|ePc|^pzq3O'džmoʥIqgC1fQX97KK^2+B7w*'O&f\kAu]ShcS3.~!R.1g(1HGЛ!޹ٙ 57 ozJBl@_g4k,fl𲐃 ò.+e +{VAe>uKW opٹyxua_7En1gP CP/]{6 [sG- ͼplԩ ?/4Wy?/1xIdݵ..*iWo߁k?1/z.<@..L_؜@6/;9/Xo߸f[KC=}%Yypk(su`]Q4w5Ys+sN͒{5N`[..2[#"`wvz +ޮ@i J,ڥkHdVosإ.~ADe.]V;1=,AGeR!"x߽} [3vx;Zk+`ifO;kscmM|nNhw=+ Kf"# fN`WXLjE5M-l\B"Sܭmh'*3qv؅ti䮶N/+qx߼ZKswGkCMŽk!ޮ6h)%%& pn޴qavאvɬ vAe!,.k~]CK[G7؄Ԍ<AOhƌbx /4 t5>,+hkib_M !O.*ͤ]2+rl.+"s^}ZzLut llxln՛wpTf*զǀ}tbdf匔/W{dWھKvd:[:yF$fM].e.-eyiޮey9) 1!ޮ6h*Hv0>߶ˉݵGQ ڵut MH/,_U NNϾXbs̿#TҌ}jP_W{S]Ԅo7[dWMq..'i . z]ahWIm x226Bn}CccN0{sX[-ZXE 4j%Q%ZQ+jܢnu aDAXň (EA@Ejrz{w +-.-+vuvU8k_U vebCz/Xd9}Ʉ?vvZ]d$vҭG~V /ͥvKT6ɬn K&]?w:h@]6^nkݟ.;%@ v]y.]I vn vݗU5߼mv)޾}󺶦Ba7j72<$w7=;@Ů0a5-uݮv50PإgWɮ2e*^rTy.jv +v-a$9mF؏&vgwOH[TRWnYIQaCnrB|\lt bw3؝A쎶ac=v;t8;n-kwQ[݋q12ICa>v]E +UMSحy`}wQn^VFnhbwl?"uvԴkuM̴Dj7 +v`{]:Ů?؝$uvkݯ*v +J[Ңݯt HvL9/{TE}Z(/[{ ,c3"%gw3/%ݔKϜvٝ:us h.c8.rjwc{Z +xa6#.Moc`%'O]=N<~HEFH}bw5"#ݫ)E-nh~vfzjz`ؽ~W[\ڭ,QZ,ؽ~v]`q2ZXlw2ݠn;K Elna/e vg.c8 v]Y"΂]`q2`1E.,e vg.c8 v]Y"΂]`q2`1E.,e vg.c8 v]Y"΂]`q2`1E.,e vg.c8 v]Y"΂]`q2`1E.,e vg1urxJn˶+"z؅]K"΂]`q2`1EĔLnQiYy.2i:W'} LqvW."nKJ0vi8 v]Y"2jwphD.2w"ޒ;@aw+.+e voI$awvaq^vc`v`[>v/&&."3nPᨘ8؅]dޚf7+aA!.2C v]."s]? % iOJ؅]OJv ^Um$F."J+cw)ݥnnB ؅]dصENwt{;#+va'f6؅]Ivmc!gwHF."s'mq ȬٝNm{.>! va1VԮ]]ojWݪZ؅]dm(E`ZzQ|]Efbva&=zCNv6ؽtvƽJ."S'ig]~ޣ/~5d> v? vOvݜ`1=۽u`Wn[6 .v(:w'zEFgs=VP>ݳ ȼmmaj#}QQ L6W]B vr؅]dn[\g5.2Y v?]nuK[Q^VZ$LOMI]ddRǏ>S/o`Kn^vf]E&I_=N^fivWvNHiFvvG;K.?YM?|ᒿR_ v ̜v͹lo."n/ߕLWۍ C.]dC."ݿ)ٽ +v]f(k'Od{vgva6#n]۩Ev;.2\?Y>5<-.]n "dwhw%v/ӳ"CDٰu84 aǘ6+<˂]dt v#v: +va%63g ~L첥ݕv.2pz۽t5Eڮڍkc=H. .[v3n$'vCvSKS& +vjw1C{vfeܖ8eo i iyhw ȸivUcMZyv۾C:]1vNGGȀ.[&%ğkuwȈ.[jvkk4vQV nv&}v }:z8~Za0-ʒi4ƒ-Kٲe*MTV*T&MZ$|?3sϽug><xvǎ:oc7/*إJ]Yc.yUv]m[6oXfEfeͳZv33,i%Wî, nϰݖ& gfԫ['=v%®2c.[TbWؕ%vO\j;v+K`wm7햗9vð++;mݹR5W.ve9kwLᐂnR K]Yhen;쒗aWVdvͰK^]Yb,=v[d7ڶ{v+˦s~Xb)aWc $v?}}kN۽\aWVCv<݋K]r1ʊOݥ?D}}qؕ%;zĻv.ve%;'K%®۩mSO>jؕ"^]$r}믛~N +QؕFGOvo.yve% +D_F.vE`-caWTvl{;vð+ +. +۵:]0k쒿aWvI]%m5cvO.vE ~%o®(7]r3슪݋?'l.vEaԅ]Q%uaWTJv_.vEEWl]RvE >S]RvEaԅ]Q%uaWvI]]RvEaԅ]Q%uaWvI]]RvEaԅ]Q%uaWvI]]RvEaԅ]Q%uaWvI]]RvEaԅ]Q%uaWvI]]RvEaԅ]Q%uaWvI]]RvEaԅ]Q%uaWvI]]RvEaԅ]Q%uaWvI]]RvEaԅ]Q%uaWvI]]RvEa%ۦ=.i*na76쒺R,vKZ®(쒺+ +.. Kꪸ _]RUʵ?o܌]R%(du-8݀]Rjm.^|E}%=Eص{y:]RbM`o +}}ߠlإJbFWXvom⢕k] +&W]RRyV݁݉.Z7i3] +4;e}a` 5v}.vɿb~؍ +2U3v8tXbO`7˲]쒮MKfdZvf57vs^evg[hŚu6oٶ%s[V:uedoIJ2le;إ=]/b{S] إm97o۝]RE٭Z\cwmw=.Z2 Jv5v{ )kwvK&ζݭa]-fndv]vϰ^,Enb4ݧJ~hf%Kj#] +vϽ lvt}};dcbq%v/c/Cv\Sݿ.vɟv4v_h`Sh] +awvK'im{]T2E}%-%{u7F}'/~ݺ%ٽŶݍ.P%.v)*`wDvbGݷ]Rm;b*J.vn/vK]I%}%{zyv?.v)mh/] +8vnd%}9=cv9"우K®$쒾+ 쾈]쒒\xvK]I%}nwQ.v%nmK]I=F5;aWRjv.v%a]I%}aWvI_ؕ]v%9ݽ._%î$'v׮Z$nOaWRv|õ%® +۽v ]Re®$쒾+ /J?joc<K® +Rg& K®Tj`X쒛aW$쒟aWR2g)']r7J؝d}Gؕ?]] +$Jkwg,wwhQؕlw~%®>m4aW8Gwvy]Rîv|7mA0v +ٽk=T+)5+;mV..yv%bc>aWD@Vv(vɕ+)>8nd"K]IΛ5cjݧ-wiؕe}Ƴ}nCc.v+Gy8vɵ+Ifwȡ1vح]tؕT9,waW۶lްn͊ ,5vg5ffXvӰK.]I",ݞa--M̨WNzZZ5Kn]Iev]n!vɿ+)MKN:nwaWn-/sN+쒧aWR=wvWsvkT]r'Jr+!ݮv`< +˶v%oîhv1va vXv{tp8+ZPQZhQ%ѴZPI+5()YRi(5fJT#||^.o/<ϣYcn%aW%n\/6ʳ;@UInz K~]T΍n׻{jQ5a*ݺi}yqʳ[iUnX5vCMK]NOh*vɇdw`R aW%vۭX,v㰫+v`| +*9ٻ{v[6m]-GZvo.vUJ`w#v)3}2v) v.vJnw`| +a4 +Etf,tUaUH{M{vO>r[WU gc ++/4jO.yv.iv.ivreYR aWXG] +;*]0*hwإ®B% Sҥ+vK:kX؍ a.vIvIðvIðvIðvIÒ4cufvah޸Ų{إ`SۤEknb)jhv.iv.iv.i }MO6إîB%K`J6)]+atn)=MC]Ҥ.v)=lJbB̕g &9s· ] +㳻a;vaBz:k}vbȭQvax^kbf[%]hwvKw7n9b+ƽa]uY.`zvooڬ ] +'ev_.vI +=XDv65.v)Idw,X]Rٽ= _dvK!nenvGƳۑ߱] +vO9  +cvO1K]9v{!vɇ+fw+.].vɋ+nֺV.1n+"vovO.WؕK`w󆬵Nv;ݰ{]K~]97v_0އ]?)ٝmk}:N.yvd|0{Dv`<rK/aNwa|r1v?[<#Mحkڭ]#ycN.yv=#_6있] %aa9vϰ+h}?o~ϛv{voj~afunr%îw c OEfؽU5_\ +)svtݿoγ;dv(ݘCO翟o1R ;q~la}O;މ]9ˡ-LU(~2vɫ+``QoM8fKv.v +#jw,K~]X%Ma,yK3VgfGvL|Ͱd5V.ki67n'Uvg] +$MZn"E6.WԮn `wnpnS;ڭQ Oؕ=ju݅حg4v+g{,nݡ^إraiwXIfbV.v$lvc**vۤtƮnv+/]>승;nvɿrӴ;Q9{wcwn˦K~9g^:8FAnE! rPw EM hDV4^p +6j4j6vjZh:6i{Y}y~߿`=y`ؽhULEΈ]vO`/`Vn#v?/>=vgw4.j]x}}vUbM.\ݬdk5$w"KQ~ qAv7jO|Hdv ^]ac TNkkݽ~ɯ{ v%vwSt펀]dv%s(_.vaY0vwnz.tpp4ew+@임]ƌ캻]ԭ)4e'".R5.(XFn=w㫰 HL vvS>~ vwZuvq]Yv>vie-vj>T n>2&"kf̮?MgNvݝZ^/|̓o."kh?0$4":6>؝-٭ v H:aEcMC]EV#v>wAc}؅]Bٝڭ힅]Egwv[6_؅]dXvP5-G vaY73vw(}('.ZfȦvXv."+fnh7-#{dw [x#v7j'v/^3n 1&m]Eg(nN^aQ:jZ{ +va!c=s^v :ow5Gn7ӷo؅]dLh@؅]z]f +.R1cv.[2.) r?]EĶ:%KnzvtYvgv_U{vaP~ԩvcvu+ ̳;/w .*e:m+*." ` #tvwv߅]E*Ǵhav`A1 `">]Vcv_]Emv{vaY/e:nͦ`v.+E|`첂]g +v.+E|`첂]g +v.+E|`첂]g +v.+E|`첂]g +v.+E|`첂]g +v.+E|`첂]g +v.+E|`첂]g +v.+E|`첂]g +v.+E|`첂]g +v.+E|`첂]g +v.+E|`첂]g +v.+E|`첂]g +v.+E|`첂]g +v.+E|`첂]g +v.+E|`첂]g +v.+E|`vu]7EݙD`wTXݱQކvu);efQ:Iv4]CG( 6ixQgӱkl7Inw;욶]n7Iٮ]U?;}+ v}5v]kmkzXd?Pj5j=K 5HmfY bSf7a}Ycb7Mfד$jR[bj?m6XJ%ed-9ZHvv ssfee%nv{4^Ve@W݉]'.=/ٿ'%cutrѱqɂgi箳n cOu{v'v vKٙёݡ^C<\ŃW aCԮaG9f\|Jz4bwiQI[ Ve%EKi)D0b.9xu(_؀Uk>پDW¹K )%enM]cQ5{-/+)^ONJI vé]_o^ީG_cp{S%v}|G0qs/+.-+0ֻح(/+-^`&&>28ׇm~ӫ'cW ]~\ ]2v:**f|n+vV7g_j޽gv)^]v[/?K4T(__bY;ybQ~>ृWj.f2_wkk?[QDW  + ;!1u3.,XbM;j=q>>ڽp-kvVlZfsg895qبАrW+jF!^pu+uucןaѱqISf]x56mUUp1jr7a뭗c6VںiÚ/;#kJjR\ltd9xLW;@lWU:H#r%ntҕc'ed͜hK+nؼmچC2fwnjݻk kWdѼYiodk +zJm5e2:|-׈v:fu@[΁Htӱ;l8Y鹛=+'w˫^߻o?{s/_]O~Sq?ߟ|oEWk֢DCkHSh$%ҾTBJEBP4I43gΙ}ޟ~ҹ xz +i;7D \0g֌笠ZHċzKWz,,*˺"'K6eІ3s-Z5%mon>-#v>aW*[G얡ܽi)[c"W-np4kkeÆIW9E|~i\[X?6L#>0J]xN9okb6%g8[v+*i/ݗ +[tD~nVzJҦ˗1u"Xa"^%Q +ݥ+Ⰵ\_Lor9piB/WNr Иڅ :w|, MHڙ}0ؽ\vknoݦʊe;b#‚.^(Ͱx֌#եFt.d0÷,?brp) Z_lF dBaFpZbeswŸVZKmyGN+\Nmhjovvu|; mmj_.:wH^vFq[⧅s}lij .LV/0/9<"¬_!_]ˁ+GWff UE䪨k ko뀕!^qK=9hBI;kvn(}vӚwn\@9{v%oٸ!`ˇKZ +;J~>@p?>a +(߾,]1B [,(QTT"rǨihj5׮+3A+#7}w澃GO\Eה??))hjIqeޞAxbiv50pWIQߜyiρ||h `.ߏ^P..͖6p(f G++\u -(@ +׮;˂Flں#mCNxڭncskhU{ks#}pֵ+ϟ>vh޴[7D ^FJ.^+ h͆c6ki^eѣեK ?>az?ZF]\.\tKKV5e:*Vu ԂK5;ڝ yq I;ӳr)Xv=yB??"v_47>{^,Y>(\^V%K¥D,SQ͌\o0Έе8ڝ㏕y S3>qR>&v;b{^*<{p3Κ5gz:<8yxizDe +~eRnU8^T¹.[-moK7uprBn̑ړw乢e+*nCnݖ`zs'ٵ=1~C$)dNqur x'`_m-o/aؑg?*!_^jr{s.]\ܲW*%ц!qF9xai]wt\ ^ ~ ũHfa) _|Yz髷xE +2,]99Z(nvI-*ja錕ɌF[mNܧ{zϙ`I`ȪR=Sxڭk64UM Okܽub~v_t_hJv߁W/[\@JsFjx. !xLtq^k+>573g_S QO#0 ~ _1XE{kKe.\bVf1 :> +r'}A]",?+=591>6zݚ`8y|fLsGNkoggko.sj*x +`+қr ]ҖQ.\.fxRkgc/A pttr?$霓M=,Y12#"K RR(K[. Zh)Z'xg*tNe8lq2/,sY-nhN?y^yBB\V4Mb( +՚ +lmݴ 0w?s}']:x?KJޞ-ZfB.T`Ho4 Y68x88-QDr$~mB"9rE/tIεK}]П5=ޡ^PhhhXXxxD$+*:&&ӄPjVg4c{g2ނ<17wɮs'? (ͷFG4=y0x-uV.d +@o<'6&:ƫ{/ "EFw_vzaxIofumLti_u2 U뻂LB܄G;uX(6& &$ONIKgeCaVojL m$v8%ZNҹ)u1ii4GIvw56jt Y /;6c=zي*B0KLOZ[yJc.e ."{RH~mb Gσ>łl'.<>+yBL]@>g_}}~=xwnߺj&rD)SߤD.7O_ &[rw9/֛8< {m:Ѕ}Cۄ\ܕA׬ OBL)t=<* 4A:% +եe]Иw;Dbwc옻?;c1xyƵ$x &/T]ϕ˲tAZ*~yd:kV%{3^'; v_ tqB_x %7 h7E2m]MJ ŒLX"sRRoM`^>zV1w_v[[i5z + 6 JPˑˤ(3#C.=Ӓy HI]@]F/f2z;}q캠 S2 ]e!\6`K%M/@σ2R(H,HRYvNnBYP.ՔWjuu 8zk7nBe: f'?<91&/,SǏس X,ה +ܜlT%"9=Q *c ! |hތw +mS3..t/%7,ÎORlIDף,IJ2,;[.lJUAQqMyh2[a"9~sCؽïelv탗~qKC>@c7* gYi>К/=w=۶͍-ZZWU=Ӕe TB׀RJ%tuبHޠ?_w޹^7WcwLt}B_ gŰI<>D8K&Wlբ:m}2kkM&ս޾}|$#/!$xANN߿K[3ؑzdhiMZom@U\,K %q1`;|>9y_q.1؝;oٺ]Qq 4a&DnNBUX\RJ!6K-GyQfPC6"G~}=EyqH.39h0O<6"(APE0`ARwX`TKA8fNjܝ{w,>}>2E%ejY}Gwpdyr"v߼Y]"xLM5 rxeՒ|7U@~Aϗ/K'wnMPk<=fgs}wm㥛wɢOՓy܍.)BcN.\lCX6;M^իW]v=>lE)73r + RZ#khjgyZy.ोwf:yޖYz r2n8>:MokNO!Es _ñG-<5kd@xn;vјchgЭ5kеwp\O/T,Q4I$&&%%'6 n3rr 9յͭr.]jTc=WԚqrx͍՜ܜLM`QrrRRb"6Xp/_uh ">^`o5k&]vϖ'ZkW +vc3w\ml"iB+2_@`ph8%(XyMrRSSӡlsrnɭk@_Vҥy]vg /SkV#@onczť7/7'!8==- ހ?ܮ'q!f@7<480z=N:@ZkSkbzpRkVyٝ-vYc^bɗ_m8hmcwǙ}96)hƧ'C/'&++;;;j +\IU 70?g;Z f%ޡޮVJAp8+=v#ly:¿'{9:*",$zϞp?x>Ư41^bߚy3c/@wf)Oo !ᑗbn="JxLMr1P e +r)tstq +?ZUK3S^5j\\\wVyv]oÖ e@ro̥ ޞ\m-y75 *f.5\ _o޲n]е?vyHD.&&R2ET>;bҲ2Jkncs ҥUl =v +^5e-ޖF[S]%%bqY=/9[x QLN%%/72,8ϙn'mnޭ[6a=Nޕ jY*|cƱͷ[0ŭKt]<AHnB(5^IUB )ϩ৲R"Jm| Bؽ 1y;[.d}fFjFj pT*WrM/=K~REI RDhͅ5ݱm߰fOiYUbWhwo7cu%9yHh㥴z9``VFjmk[{.Bw]֘|BkV;pыwKJ~H cwrتo鍉 +5cZJη4RUbWh!)t\ArVZyza@lN9En eS>yAWјY_&YRqw2Ԅ+[]aN;O!*e%Ō/q +Eo9oOkcu|Ϯqyf4Ϭ̚;wznPhdtDQ*-(܊JV4d[[۠n02wݩtƬ ֮JRk;x +>mxZ<0ԺZo$= ߢқ*JX.yG{6"{<Ћ|<][Z.^%vY̋!vMص!ьnVnaRZ#V~>#lㅹ3:Jf {%.;"w. :vՃw*z_{Iuuf>̷ BFZ).)bx#BΟpu:fku`?֛ x~xEUq?sD"%4LаBR,5+@R&.(ʠ)" &*&R߽yAb̙~35QY; +*aG%6fEK +YB&&ܬxG6D4*m*k[aИa Z. +蘃qiٹbd E;?Z;U82Dq"\|#K2HXFW7pȸ_w0nnMК=L ^;[_kS;*2 j1ޙBb[/h+VDtRgPEꩦSShkH64-3]ex9 $@p-*;`M߳zÞzm@_7xJR⅝7Bv +h>^ߒuqvθ1GXًi`b"etKe{T0[VsS-)>UT|4=;Ak^YӦLr?M4\xoPjnI+Sg̞nd,{cIJ!tO>SJut;?MZ<.R\}^ʗxX5}聳&~3O)IGw$ ^gLu~fKBi.etnnd٫Q_c\w-He~U,v7ls(>1 +s>咳2[[l^6O37Zd np\tŮ2T/x[Vwc0>'(?[9jsJb蝑7\J{4[YkbȰ7Ņ[7bW9^ݟ~؅uטmlXeg?0И20u/Kd5le+dZZ`K +r2 +z _zWFOCߚjYcf{`n0 ^`z[xqE<ݽ{Yb?]Ggn*kiIJM+ԭ\S r-{"Z.]ۯ %uC\w2{Be^~wa;[PDE6%`i\sn)ܶr? +x|_|oUp_K-*<~ w?7_J3. v-_yy] 2F} @#F// 0(TuǞy'N)-" D.mi' 7Sl-K2W^Ҝ9+?cM|iF6G3Neg`߳ck$4(0뛯` 1GXvnOflPso&<3\wmXc-.)Bat/!\t"|?lnrl-ZЕUK7v~1%.6fJB"\yֹtn-]exyȗ%ocT~ƚy5!&|[o3ŋozJb<-GXx̚6ZƝۣg/0ᣬml&LwuOuw_ʜn)num={m-]ܹûOmeGF!~cR`i>_[qcO{ss2zpa^={tn_cS!]GbʐM:[xcsC#pER'`ޕp3 +z){g{ #_^Z3̴䣇b`r;bfjbܷv{?<}%fw/Y"ضYX*0vp-;2wEs- W + +2Soˆ|Qﵫ65bVai΢ m@> Ξ1~<ҋ`zwS*; +DDFE%K?qL*;{K+sO<2-GA/?6{^ +jc qQUhw>)cv͑Q{%]Xw+eP.6|<{:4P>j>rxTo+ ޖ4*a)qFEnvvv',/*j.UB-+r{_h*txygE$yo\ + va-/-.]';v;ڍOL)vk2c춶tuDP0r +u3Ǘmm%/Zj '#51^m:w54Rfםw幋v+..kHW yv=+G>ΰv/K[3ؽ /حv]wev ;iШ`jVn{`P$ufjUf]BWG*v>F\sg xIΌn,؍/۵v124P/6R&D"bPz +"Ht"W9gݳgW0lܜ?5'{𜹕w@HDlbjfnaIeMCKG3%. |N\1y V59z)Ë w- 5%!NV Oj)Sv9AvQvD$PvM,mܽcR3TT74wvG^M .:l.#.[X=W(ᥰn_w{sCuEIԄ`ow'K3S]9i 1!]n:.ObW+%tXSG/8,:^ƃ]}l46]2߷ܷՠ;_eMO/:쾚#<2%Dy9Z[hV +|dv¢⒲N1x;QwSsʪ:{I㯦x3'SvYk|&}:k|LsSGICmMuUeE9)w`}4Te%Edv9W.wݯMpמ}2 +*z.\jrf`hd\RZVޣǵ=C xAe?@.\i- +/ 0w߀;4XQ^VZR\dh.W/_0: #o.m]^.DwnÖ_8pΞdep;"6153oMC ]\e/&j>c[ewqq4ԀLMlguSǏ9p`wǶ_w`wG B}մtO[8{ŀ /f@(g+vYgc]Pf@AvAer7&,𤮖wn˃۴gB"bRrJ5u L`!$`xi%if.(%e^XV>YRx$w`hVM|<0w.]u]n>¢2 Jsu}s{WyxQi~G;ıvn:..fn^V5ur󰨬p;LoMq{Lfw;C=uUeEsS2{;ZV./7PdK2 ^9eT,\oF'+,i eKGٝnCMeia^ f2+./8~<_ x9@Bv@WVQUH1f;g{`x˫Ꚑ;6zjzfvE2ı.@w5ٙדcvm*q/!&<$(1Pf UEY$wE"~"v.miqtu'*>9 ;äQ:k^ /_8VpHg̣a%GݹhcQfaAD"av/";0|5{OU6v?yΚh^hfwɘ'=HٍbE2@yXW4bpxUhkx/=6yS3dxfwdtg^O~/16240f}]#*pv>av1w3^A=K)jh?Efo;QqIhV2]dYcf]WWW:Z;; FzHu^a0ͮK$y)~8g{ w~ L޾ѱ 2eƻn!x@[LwBc1vScƒ^2wn޸vE^F9"K3w +:ϿH^VRU`f7oT9yۻzF$"'/rtwxҥ.NIѡzE'"؍YC]U鲬/?t攨w2*ͻ+KҌ֬ ZO@hdlRjFNA1Ҏ&ISs 5wܗrn37hk+Ņ)0߃ooit r2Rb#C| ]xi-`s<[M:ѝ' vw6Ubs3ӓÃ\m,^jh? ],ݚ=|Ē9ycR0YyX\EU]S[gw$ef{^8x?&HkFo1e}n~29162TWUeaRbcٓ1OW7ffyКo|gM^wHT"_onz %Sf!+^侠ݍ, }\_]+ƠQ!>5~y&h,,o}~ ^ 5K*\UQ&4y]<|BbR_e~S?4J O3ɋE]ttѡ憚7 _&FzCcWj*Wd%YDб5j' ,%1ym\=_E%eU4a$"ܗtK]`ʲ6cWN՘ 'X+I{`k>wQBZ=yX8yG'e-ށa45=H]^YmA"ǏKwg]mme07=E"z-nanfZr|txsؕx| حYXL2 +T/8<&>%=3[Z^U 'MxW9nr栻 +ӝ"Ct;ZKy)1~nN&zOcWAFb|Asce@k'{jZ9DИ<,mj!OBxu&ǟ ֌Eώ.d&m]NF{;[]6/ N@E;YiǮEnwrѝtڛ߼.~`mnlஆ ]A?jv[3{&v/,l\=_E%f5 oO(w//r|y<ŦƦKtj݂Ԥ6/>yx_+_)=1.[3sWRFʵ7ok>z/(,:.9-#%g [^ŠK]&`ʲœ ?/7G[ gOi޾yIx슱.1)v9L53'^)Y*j^m=CSK['7o\ocKg`@$MM-,RWh xۥ.mme07=E"z-0`?o7'[KSC=mUY)"̱ 3t?5{ +< &%)J*jodje--klxYxW^:69tt*8XWU^LOIvw25~|-5rR=}RTX=v( + +& rJwhY;{DИ<,mjdᅗ՚w'].3S M.A'"B}<̌uPWURp]Qct[3+(,&~a.D4&;WQ]7826>Ixu&} E"gǓ.EߤK.er|ldWA'"C|=\͍ taו%.?{F\I=]垼O+$"&_'lM]lV^DQ^H u)қ"E HQ:nvYM9Pt1yr|")sʪZFfVN8/yE m;=3x7ё.7s3ӀP[YZT}?59.*< doefxNV +#"r132@o?Hރ0yi'(AF8o䴌yemݽCS*w]]^\tG{;ۚk+ˊ d%G{͍5 ]9,FT0v~mnK&/  )(\606qpqNqqYU]cK;;04:]x ɋEltCn{Kc]UYG9iw#B]l̍ 5()a%D].v&.t$y)iG2s?y_HLBiXt p^& ; Σx}70B)ynBLĭ@6&:._<VZBL\LGh);H&/ +I xu M,lozގIx?yZ^]eī׳oVVwEGۢqՕ_M |T_]IC@71vhM[ C]إ%U.j&qĩ32.]QkhjiT$" E= E<ɱAHЭ(tSc#C|=]m-M u]tA^FR\X̩8X7RyO?!x)^z +".%ջaje[PTRQ𬵣opxW޿Ff/:)]hOݵe@wh}PSQRTdgezC++%.ecfdt]J>Rj{HɞSTVU32wyE%އxK+޶]=C#3soxǻA(^tdtż]7s3ӓ#C=]RH~jr\TXHOK]UYFD= b +\̀.žݑ?$/ / ;(+ǫodnm xU66#xGǧ ޅյ?wEm+vs}muyqҝE67V=tCqFxrX.; ..bc./IRR2sq)(\606vpv[wvl]ol]ڤ;Vf݉ vwv676ָ ?DKMIt!Q&Vv'^1 O;i9?-klGC#};0nKc]UǏr2$D +qwq06фtJK's2=Iw.=DKEMKwx9 ^a1I/^chba{'현2s꺦/&^ G/:ݏ,-}jblxj@7?'݄۷}<\oZh^|YiI1aHRSc~/%Kef8vaqIyWoPĻYTT7vD:{/:rn tE"A@IìC|=]m-M u2gN8ʌХt)ɻWJ*/#3WD\JF¥+jnZ9yF&g5ޞɽ揨]t2Rt'Fzg5nAnVzJRldh jW.]A132 ti(Fwbx)(~ = r|")sʪZz7̬ܼ"RgV42YCMEiQAnԤȰ`?/7';+zZʊd0"|.'{.B?SP| 8@H^OP%72wyG%yE m;=3x7ё˶.7s3ӀP[YZT&E{͌ tQA>^nN6]:.vt'ǻ)(\76vpyG'e<+,.mlnxWQtNvw57V=HK9;Xkk\UQRJ +C,LD$t$ݧcL8?< Ȳ,"(Hwtwwww7twH8(4ά3u>x]Y~ ׼~vxih^vN.n^qio`hT\rzVnAqyemckGO?EPC*Lwfrt6Vf'Ez[itEx8]Z@b7@w^R2r +J*jWPDBZ^QIYEMK7(,*>9#;୪klx1XG{t X XWeg$Gz8Xi(+)KK2Td$]⃣g{'(*!7qp +OxK8]:3t8ݿ f0st 0^!QIX:yG$fm]~xWW.FH٩!@--LMrs01QW{뺂LL4 x _Bx_|_HLRhZ:yD$>z4on}vQhGؾtO[k";=16:4𲷫G1!nN:ݾqUVRL gg.z5n.c3ۅ~X|?Ct[j*ʊݴȐow';+SC]0BKN@hCIx,/ܵw?52wv KJ}ZTVYwyemŋvݍeW}- eEOsҒ"C|ܝ̌t5޿s󚜔/HKJ@݉n/ -= ;'74WK704*.9=+ŌOxW^dxю}"c]Lcܬ丨@_{k3#=-/7'; =- KCK0yx$dT^V^A iyE%e5-=cskOߠ<`! K(^{t X XWeg$Gz8Xi(+)KKBt()HI{]=e`bpOPTBƫola>+y^Uد˧>3&Du btww7xDA@)9t! uwef_-"W7Ax! %Xh.QѝݦrBOI p23TSl(]&ͥ&_^0y!`8Axp0^u-=#skȸ|FVn~mm$Bx'9+r5cx=j]/yН;[ݚ +BQ~nV>%).24HOK+/- _6.-^::jxQ|G:+?;Z6~AQqɏ@xK淭]=C'>xbs邋t?M|jo} CtnCme낼gn|TX=0LBN #@xY^'N J(\|{:&n^R`eo˻+xgWڠ֠ +޵e0ݴ^n&:޺vG]V.j;6O?΅=U10ur i拗%eU0^R$3k[Ã}$ncmUYIOS$Ąvs45P螓CrݽuRM^ +](^}//WPDLJ+ojZ9{܏I|if[^U򾭳?826>95=KZ]K'uwoi*ts2>~q?PWC+JBty8}{! (]4t7.?xxNSxU4u̬=|C"bӟ*"W5x3"w Ë]B.3D@MS]u9Ut؈@g{+3#]M5@WQNJ\Dc]6@G7W37'.-|CEMK70426) VTRe.zDMݡ^bg;[_]fSb#C}=\͌Tn(+)IlL b:tċN^ﯿ~wB8 i޼glnIFVn~1mk{wx ] /ֺ&]`yНtz]ok*YO%Ez8Xi߹yyyi SǏAtۯ(]dn VQeFrxE%dP6~AaQqov^~qieMC38 (/jZ_Q7E~8 +@tj*K丨 ?OW c}m(JLEnMN*<…nݽm`ba,;uiemC]=}陹y /s3ၾj+K_e?KKM ru01оwֵd$E]~Nv +]F*;X=ia1IYpxtƒԴ/ ^U6=}Y^uk tg}=݀nKcmU낗/2R$D{9Zh te%ńN8zeYMwK5y)xwxw3ݷ =w۪:vNc>~ +Um$$k#t'!6@}aBLow';KSC ׯ\<'+%&߷y7#Jw MKw;-=^.NCjY9D$s^W5yM%/»'Nwyy`?ƺW9Ęwg;+3C]Mrq tݾE/=xoiY;{D&"Byu}HP]ٯoP?m.'Ȑ@g{+3#=M5J.ebߪt &/L^>N\Zƫgdn/"T^;G^x|ERf /?5].L@w<N@t{nM(?7+?'tx+(k ՎRPޛCgJzQ0Hf5Y3gp`XuBrz:Xhtİ]n@a0va?ފt!W3ˈpp?'StMYUC K[Lx[;#c^](^Mi=]p1@.Bwzr|l8!'E=q:.)IcxO taKG xi)2b8aB"0^M]C3K['>(,*}WPBk$$Bxgf?SE'/&m쮥yyiq~v;J$m"<t‚^8'[K3C]MLJ@AKŻs=^&/3sY~! iߺgdfi-x[_}׳wn(^Mmҝ[V@dgify%DϞ>2Ctݹ~>#̬^Q ]+;g7o{iO(,-kML~BmzK`?Lų'ibƒݜiAtd$DGAtmw{ Qpm5-}.1 )2<x+Ztt 01qfn +W/ڿݯTtf>NM|x?<񦵩}$AJBLD]c}-7\Pr@tn!xwŻex9M +z5] +NO}ݖ*Bq~^9Z"tE.#]U4[zxxY1</o52sy¢2[^}7H/x6]߽}XWE()y9Yj޹uyyi !~@J@Av]wzLfVvN JȐjY9yGKNxEAIyu]S+78L;"ŋ/ۀ.2v9@ų'iÃݜ̌Hte$DϞ>|eZOw疧K1yxw!x128xQpm5-=V1Rdoǻ~mot& =:B@7Aʽ`owg{zZjo\ #)* :xq=Bw-jjIxعx󪩾nBLD63'qc={,l$XW՛*&.>! YoQYEMC3h;K {@>QBAw;2 mn(+tSb#C|<\M Un^bIt9X{l? Q+jX8zF%?/*x;z $ŋCQ҅t]Zt'!]nmeYQ~nĸ_WG  V = .Lۋ.5^::jxxRrJ)jZ:t NOaݞ֦ܬĘ`o7'[K ] A^.΋8Xh]t0]ɋ{KNAIE}$ '(*!s*:vN!i꺦6w`/xѾ8bݶr@7qZblDHʃH +t 4'OPSQR#t%9x=v+|B8fVv>Im/_ co/.-olEZ졻8$3QqI9oEM}s{w;9]!R" +Lwf; +jots2ӓB}<̌4Uݾ! 0#t'L^/N^~!1)o`XT|rzӼҊopxt»oËQhDH w@ws} ]莏- 5EyO3ӓ}=\͍`RbB<]v@)0vaӏB/r5T^&._vjZ6~Aa)@x+kW}#cS3s#xE.?@.B»W݀nm%Dɣ ?OWsc}-ܼ&%&s,L]*.풑 tx xe`b +KxյM,l]ãgeU8S啵ͭ߈mOtX[YNMv6V?tÃ\m,La0]V&<] +HxK x9]WPTV10utIHȂ=C]x?xѾ>t?]ݥt`Y 1^n&:ʊ +r"\qt]t tKCKhZ:yD&fdW5vxӳs8(^oU8sXngkS]uyIAnvFjblD +DWFBD@GKѥQL^<#^r/#3OPTBT4t MݽB"cgMm=17oW׉xLwدϧ].3Sa@--JK vw45PSUQV13t)LtE&/_~=p5A i>xkhfeҊ7cYw +xшD.ug{s]tg0cÃozڛk*J^<lgef[%D]t{_~FcK˂AY;{F%e5 -} wg/W3/va?-ݾb@7=).*4H+#!eA%ߧ{{// ;/$*)pOͭ\<|âӳs_U6tt}?261=]]Bt6V! c#uw4VNO + pq67z +2B.; .$I Xٹ.^/$&) 76qp +O-xEE.2vu8X[UAnvFJ|tX6LWVRL\L ]t$]ɋ{KIu^,^a1)Yśw?R7qt NH|V5vC#ޥ/ݕ%XW=LIru0VtMEY)1a,]3hNQQ"tO%!xxxY9yxť`:&n^1 oaIyU]S[gəVon»=}wꗕf&G t5U 1^n&:0]9)qa>^nVf.-!]2^Ff6chjiV7uBx13Xkxxw o퟉.5,I DJMvs45PSUQVtE`ľ]jJA(ޟ^0y!`x9!"XVv!IiY9/J+QwxƋQG8|],?~t77eftxmo(-zlgej+/-."tρ?>]B xY8/\rMPDBZkY;{F%?}ix ML/~Z>o{d;L\ߠoy>@izR\dhwo]vN6. .%''y8'R2c +J(`j[ۻxE%/*kZ:aӳ յ}*DwavP[YVM + p67Uegaѥ£{{d{0^:/uU~!QI=|oln}?2w}(#]ߧ;>m?ۈ`mn7d$E^2@t=Nty&V"W][/(<:!%#;몺֎,鹅ťW/~@+LweiqanzK쌔 ?OW c}muBYGoDRBxOxY9 bR7m`ba,mj74:>93ʗM{(ޣw{t7W,}0739>: -){hkabRb]Vf@i.%B$] ^ +Sx4t L-mܼC"bS3s Kʫ:{^ E"tw5] ;T_]^Rdkij*I pX.AdGW3%5 +".-khji_T +6uãybxqWjhOKftjktKsc#Cݝ,M u5TUE`ľ0]jJp1=D"_m\σ{EL.QCEEEAcݝINQ;DJΜqFg-p<~ 59{"%OHTRVN^AIUS +MH+,.kjx޵ͭm`;..cÃ}=MuUŅy9 ؈ow'7;+3D(]d]#xIxPBb(^-=#skO@h$6/*.ojs K^Moīq1ÍE.-#ζ|@767B tPxtIv!{KKCr Iݹs5-}cs{gШĴ̗E%m?O@xW6x _X[YL |\_]QR23-16*4X_KGH p,t48dxtݟۋLECr-Naqo`XT\RZf7%5 ]wE'//v]tݩ!@̴@_O c}muXi.{#0x49Ź L0^^q?SV60up +K~V4CE"^.CtG{ݖR@7Er\tXJt . ?MF=.A{t?3^Zzo@jZ:zG +ޖV6;04:1=xF?~Cwkc}uOSC޵4V-xGy:Zh t%Dyn߼~{f?ݣFxOBR2 x^{(hZ9yGħgeUщi +ޯ_e~ţӝv6V)1^nv*Oޓt (S' xxKyer JxU5u ͬ0Nn!؄Ⲫ&o`x »o]D>|]kDwlxm*+.IOIF{9a u5Ua|]f@ +%0KB^/9OHTRVN^AIUSML̀W=}#cӳs K(^Dtż}(ݥɱN@ qwXi*)J +qs23СtaKBBtqxx%ᥡc Ixմͭ=|C#cޗE%m'[k+ݙqn[s}uEIQK@7624XOK +%&e%ã{{^^*ڍ[}_w"]_]8@Z@ 7Er|txJrAti (]!QIY9y%UM]#3+w@H6!5#'opxl]x7]"C߁t5@wНhm*/.HMFx;ǎt5Ud%E9X!ϟE"cH%GҡxPZzFgwHl"_T\^] xgǻ߈Wa 7vwo07 @t;ۚˋDldh3HO +&ďҥC%٥{{// # /,&uմm=|Cb2_TT7u?82>9]^/չq|ý"1FEQz(***(e,."]z_z mEP:fLsWԙpG24YwGkS]uyI쌔ksc=;_ #)*rs2Ғ݋݌/V/#37/,oln $fdW[;{^wE&/w׶ ]d0ݩي./-HM`=]l̍10]YI1!~>^n6fF@~+]*.(C?|(WXLJVQYEUMoba &e56o0 +[@}Dw0k*ݜ̴X\h D(+%&L =z0=AZ> +?]2{(q8u最W70,26 }TAWs oW6M}q ݍŷ s^NM?lknx\M rs41ЁI ;s' L%=(vĻ+*]zC]S7(,*.)=+୬mhnNL.@}t?]"ҝv77VYIqQaAnN:7^RtE`,L4Q; _^0y!`;rAxEĥxt Mݽ£ӳU6cyweu//jFBvt]_]t!cÃnKcmeYq ?owg;+SC]-"]yiqA.{D Jw⥦Ffu"._y[Kpxt|ʽު:io7^}O>yQtvo_NO >t Gp23պ} "Ϟ>ΊХ#%~(m۴KĻ /- /3+HDt;>9]\ZY[/:ywAtX_[YZLt;ZK + !>.FzD +2BD$dt"tF~9^x!/7/+o76vp $fd=^ 6.oŻچߛt7^<tt3Rbp!>.wn]rQAFRTeoKݶ/==̆Uj`-l\=ԌҊz|k'w׵#w0݅ٙQ"V|}MEia^NFjb,.4`caр*J!t٘Btt(C@xxY8!bR*j [G7/l`hdlRZfN^ۀoy7Hzjn*ޏ(Ot?R]]^|0(ayOg-LK z9Z`4TUeĄ l,]> +]>9!"^&ĩ3ť^uMSK['7oߠȸGE+kۺ$KwwDIBw]"tt57V>.zdkij*I ;sD{9=(/ix3xEĥ.]khji_ 66c%]Qot!Нtۛܬ丨 ?ow';KSC]MW/)ItYtЀmm_E$/\v󶖮]{U6w=xޕw.w-]` +;N >joi*+p^r|Tx]wg;+3C]7] /-!"x\c+B(ݯG>y!dx^Q ];ξ%~Ij~t1C.LY@wTWUVRGGp63CH"tYtdt7ݱ%KK J(\rm=csk%uM^ O@xVP/][YZL xTW]^R0;#%!&"XOέW.*H +$dtt!rT[ l<|Bb0^'6 WXZ^]ox #S0e(m"c]NݞV|}uyia^vFjb .$`cnJ ps132[RtOx!xih>rI+,&%7qtb2sފz|7@-xwO_0% m +@7'3-1ru0h(+J~8> p/E XUQiKtK/ҕ^""Ig6,,]@I 3a枧 +;yy~$`ݽ{v0bG\xi2#x9xE%zFx[GWOЈD7IiE E{gO<<619=3;*wNwuٙɉa2EkIA.h75C*IK + +rq t`t⥣gDqp#xq'04261-#-!4Ax$w +Eb}iTtW(tG$"DPSYfg%Fx:͌55T]B HO'mw' &/L}^>NZ^ƫolfe !@xޅwo#x׮f .do@w +;@tj+ˊ d%Ez9Ytqb]>@>0vamKK^/p2'ϜtUG-!Uﳗ]C#oޢxn6E龝z3>24[Uѽ79.*, }Ο9,/;~A>nN.Lvii1_G0xsx%eT` nXXt|'*}_T򴪮;84 +᝝[Xz+^lnt]~07 D4U=-)G ~u8L}.(1_%m@xY^CGK*:{&7=nGǧgx^w};-&tHw#ݾׯ0`7-L _|)YIqcG]tat »w?+;WJVWK?$<&!%=+ҊV/ipxt|rûE,AL񣜬oKC]- EY).;]o*;P{^.^.^52utILS7>o#&&gfbxFtW.LON I}=[k݂{1!ޞFZW.;}BQNJB ѥG|eB¢rJ'04"615#;IYe K\;.xW0[)j+(e@wn.}D,{Rd73tU%D]6.3K)]WjgD`FT54vNn^aIiyo-!G6ûv5bv(Bv7;B ẗ́Z@0/;#-)62,of$/Crs@2҃mޟ~ep2'ϜtUGoPXd\ ++k^vt)wa{`ûڔ.~; {:^57V=7).2,KϜT?z Dw/?E.F[^Z +L(^N-;Qqo~QqyU]C3o?;f-x?M?{obsm~]۩7n?DYKC]UyqQ>u' $JDA#1On˰UP9uk L,n 0iU]c˳W{F!s K-_]Z v~iIQ;~o:X[\vS* +".?'] +1%mYٹx9&".%54qpNHIyiu}csp;û%ڄ.:vy`iG9) .6&]EY)qcGptY6݆~»Kϰe^^.^54qt IHVT7}$4wwt'!N@ͺhciju'$`ݽ{v0bGPeFrp + + JH)!xL񶎮>1onҊBSΞ>yxlbrzfv~qiyU : tgg''ƆɤM'nbLDh-H$'-!*,$(ŁeK>jzfx['W/Ĵl%#09 ++TxiTtW(tG$"DPSYfg%Fx:͌55T]B HO ޝ/^0yx b8iyeo`Xد*>㳫? +t(yINQ;DJeYg 9zf7\Ĕ켂zw`; .>cn^(^ .d Btz;₼̔Ȑow'{k3#]MUE /;.L_#(ݽk'^""jxIԴ L,>AQI)i9EU-=#skgȸToI78<615=;> ɋ%v"tg&Ɔ;;݊njR\dh K +Ӆ]""e{/&^Jj:/'7WIMK704 +}_XZQЌ;26 ]X\^][nsCMEia~@7*4X_KM +& ӥܤKCBgx /KW8ĮݼsoPXT|rm ?Q.tܢEͫv@hcaĄ9ٮ\Ctv=ݳq4^~aq_Pxt|rzֳEe -0ޡɩ9,(^t?`LM t[j+ˊ?JOtu01VW ti(ϞG[?=%<RCxٹxůߺ@^YC_pxL\uWow3sV~ERt]YZx?7Po*@77+qBLx#;KS ewo]bPNBtvmx|({Kx*;+khje4EqyU]cKw`"%~AtݗuU/rf$D{9Yj("\W/_<RtOG{}/a񞣠 +Hܸ}OVAUS; $"61%#;୮kx{G'vûy5EFt!Нtݼ쌔؈ow'{+3C]MU{oHbti(a#3Jw/2y!/3 +OPTRJZFNQUS' $26)53;o`x xW?(^lWe@whm./)LM qw63TUp031@to]EOKKBi[;8{F9%5mAwjzvx76'_Lm_m ҝt!m5%9n\dhBWK%šKEg-C8xI6RR1lBbn޹PIM[70,*.9IN~aiEMCs۫7=}#cޅU/A7tW c#}=o^57TtcƒYh`r_|<=  |Pw%>ॠ7nߓUP54srILx˫Z!C0E_W/8taC֦b@7#%1&"PWSEA.K{(JjG^0y!`92@x900^EUM]#3k{'wĔ켂zw`; .>cn^(.].L'@wmeНvwyٙ)!NfF0]QA^ D=w]GPE;!W3K०e`bfa JJI)j[;8{F%BxK*޶᱉y/nN^j']p1o@.Bw~vzjblx Э(&Ex8;Xi*HKI +a8XYh0]%"BmمK'$UR76qp xV44cMBxW?E'i{~Kدϧ&=c"қb;"{͈HQPJhQBQ@鰳ά3~ + Lv<߿f!c#Cݦʲnr\TX>LWUQVJõB6fOxY!"RrZqx+;oPXt|r1Kx;{ȫxgW~2 ~^;J`9Č _O][KSCUQNJ\Qa!@˺V.^6v.^W'zG'dsjaѱ)2_w.#t&F(0ZRyi\bFJBtx+3Ѕ)Ity8 1 h (^&}/7WTBZ^IKWu Ḽny$f+xj^w)ãoML}K~;?;qja +u[sCm[{'35!&<햃KϨ)KKBtx}{!L(4t1?5[Żx>vRTBF^Yչahba}agUu -/3 Q]tgV/[*=)xx/;351&",/#!zჀ.'Lw[[0t;x̴ {+)~eF67ܽB"cӲ=*x7]bv5]t vuՀn{Yi!N7m,Ln\pV]YAFy \]F^tBx^CGUP9}kzF7}B#cn߽-:GIwn~qi2 Ks$;2Eu󧅏߽|HڕN(J:~ DwE.FQO^v*,(^"'04*.)/zES+w? V&L.W'E~|?@t[^T>Z'Ex8;YteP<(]*Wnҩon˼_STҾo#xE'sU7w Axg0 tf!c#C}=M5e%ErQa.;+um-M UE9)q@Wk.3m]Gwz/;/"rJ^ʞA{\\RFonxCY^]tѡ2\_K*+)~CH t%[q]%9iqGy8]tbt&;PL̻YXc +x%ΜtUgnm/8<:!%N.[ZNmxzݩ .6ԒK;) ~^qW/?$/-ʲ .f>BwWc'E%d&6ܼ#bRއOJ˫_%SG߾8=;W /=ZuݥSގSȽ]_67U>)x&D{r171D*HnN.]Ʒ_^0y!`? +Bx$eT`zF7ݽB"cҲ?*|?x?B\ޟ5].L?9@w;辨x쬴Ȑow盶Fz0]I1 {`?0ݾ^/#OI*>w5=#3K[Ggȸw!+W}#oO~@B'ɋ .Oз0~@_wǫV@9D@gG[K3#kW.; +)vC|<(].nߎehvaۨ2K*xͬ]<|âE%e5Mޡ14x[ciqanf;62m,+)&Ez8YtUea<\+tnCn2$j[erBGOK)jhji_.Aa/ mk!]K6y*]rOg{K3Â|=]vVxum-M UE9)qG].z[1 xwCx9xQrJj^]ڞA{\\ZNoRF'^]ݩ! +LT^Z8/J t!jJr(]^.v6nM4xwx {ܼ^Q iy%3c>0Ob^ (c,(ޱ{{G@@){(H=* $0sg#df{ed5t L-ܼC"bS3s꺦֎᱉ٹť5<(ޣj6ݵŅ鉱֦j@773=%16"@GCY^VF7D=wK=G=K/KxYX8Ĥ^9 ]CS+;gwԌ܂NwDnx6|[M@wy.lk()HM qw25PQtĄ9XY]J.K.J; j&>{_XLr +fV>qIyoM}3ۏ<ռ=pBv;96tkݼԤ@g{+3C]MUJ `QS^=M .f˯ ^# ,~'U5̬]<|C^|WXZQw32k]w ]`*;莏`zߵ57Tez".*4HOSUٓn p޼~2#D¯Ŏ] wBx q"xi"^5-=cskOߠx7';| _v&_|^/𷋥i ;moi,-t‚|=]͍"].)]¯tD~=d/ =+("qϕԴ-l\=£^U6704:>]Z^]GyCw}uy ;5>:4}{KcmeYQ~ ?OW c}m5Oݿ-!"2P%{{{b?^r"-=ӕk7عExյM,lݼc2߼-*klxF'xW^dx"c]ҝt;Zʊ޾LKN rs0VWbq +=-E@|?(xxO!xIΐ=w#-#+c`biW5=}޹.Atzݦb@7=%1&"@G]Y^VF7L{Yr3$SxtQ߻]xɰxiYX8İxU4t M-ܽB"bެ܂ή᱉ٹť}xQ.}t7Vf'Ɔ{:[ˋ r؈ow';KSC ,]1!~n6VfZj,]2|(c7FRRaRwvV* +rܕtyt)Pǹ %/,UT52w KJ}WXRQvcF X;W3P¥ م; +CtG0݀nCMEIa^Ԥ@g{k3#]MUE0?'Dнt]=KH\/)79yo{䙢o`XTJ]wO^;yQ~b}Og&Gzߵݗ/}=]͍T=yxW/3 tIaKH=} =d/ =W@Dƫoln /*ml.-olݱoKݩQ,ݖʲ׀ntXLWBD KOCCI(c.Cx)^+ns +Hܾs%um}c GW/4oCW+_=W+_}xVtӒÃ\m,Օ?}t /kW] +.~'PǴ{{"-OPT+m`bamqyU]c+wxtbjfn3&X s3S0ƺo2ӓb"m-L Օ!|]Z*!gP~{ +K ={०erp JޑW10srMLIxZ;z&gVnxYt训,-.NO tu6U)!nNv:2w$E9 Ԁ]b)<.^x^2/%/$&)hZ9D&fdTT7u&w {Bn;t1ng[S}uEIAnVFjbldH+%& Rt]t PǶoW3i,KtXǼ߯ѝuFLѡ|w'TW f%Gz9Zh(+ܾqUZ\De=O>f.^tBx9F eeȍWT14sr +OI-(*-oj}كxޅU`#]`wueyqНt=ZK +rSÂܝ,M u4Tde$Dq99Y!ǎB"cK +O^/^J/OPūkhfeV7Ax/|x35lg].Bwfjb5T ~vVf(]QA>.J._1Ļ//3'$*y;T5̬=#bR3ihn{opx ;;ݥY`_Om 5/ e&D{{8[i޻seIQ!>.@@.IDwVT :Ffgs !xմ̭\<D&f]m,L.;s{p;]]xG3!xqu L,lE%e˫Z!QOMJ~";Ct[ʟYiqQam-L tԕn߸* L(0xxK}erD$`*:vNn^AaiٹE˫ގnw +]X\xK1?1].L?@w +;t˟f%Gz9Yht%Dp]V@$50 KzmKF~/%"7NPDBFVN^QEC/(<:!%[ZABwxbxtǼ]@_Ogǫ6@lgej(/'+#!"Āҥg Krm؅!KAK jY;{x +_T44#x s K+oËMls~I奅Y BEqa#@7&!Qn޹gdfm?$"&15[ ~ջw~_nmНߠu;[ HMbomfzk%ExΟ=@tݍ% :F/WIMKA@HdlbjfΓ%e -0i**U`?L铜Ȑ.zZjJ])1!~.#͉]mxx!,KbRWߺola03'୪mli󮻷h鏳cxM.~~dݛ*@7?'aR\dh[ׯH ^0GCtQ{Jxw}w{K :s%^aqiWAY]o`hT\RZg˫[_x9w m ݗuUϟ?JK + hkabJ ^p)@{%]]+xL{ z㶂oPXT|rZVn[]vvFwK1ߎ.dwCN@-JK + rs41PV}㪴DO{|]o:ry'("!#+'chji[PTZ^]?0 N +.ڑ.NΎWME)aA~^Nv:*r2"8]cGt%'//%'(54sv Nx +J+j } >k0vೋНt m5EynBtxدϧ4å·]AqErRE9#***"9s9g$K9*D%ԌcXsOtp]qa.B.ݣ(C^xx)px^.^qi9yEeum [GW/𘄔܂꺦Ξy&+ၾζܬ`?/WG[ mueEy9iq^.@G.)Jd?^*WPDƫc`biWXZ^] bƧfak/2yQEE.ӝ]m奅yY1nN&:0] A^.Nv6fF:j@j?]^rSTgΞ` Jܺొw@HDlbڳlL@xQѝ 5n؈ow';KSC ޒe;{9B8]al1Ba,/_'$* 54sv Mx_ihizvp31=򧕵}xxn}t77V>-/7;=|UK@7)624PW+)*},0ӄtty{$ ޾PIUS'04*.)=3୬mhMLaJ+_bMOAt;Zj+ݜ@g{+3#=MUn0]&zZI(]b?`Bx=e Iai[;xE'g/.mlxF&!K0^׌%.dKݭu@w ;9626VLO + pq67Rҕ΃?txȐD20^r;=Q76qp +Oy[U[ /Żt:ݏKf&GuUOSÂ<]l̍Ԟ<禔0?ύkW.21 t)tg KD%KK+ ,.ūobaW5uxf!+[ۿE'v^mom@tg`mMu%nBtx:/.3.]RQ.d?^*/ + ".-'c`ba[ cvݵၾ^@K7+#5!&"@G]YQA^NZ\D ХRK%~5 #WPDB«c`jiWXZQSօ;15; Aߥ0?;5\_SQZdkijѕD2PBqGGCxϜxY |2>xkhje,;mhn};8}~qo(v~#iy ޮ@(/YZRldHwoH +qCtYݳg tQ]=x/^zOHTRUR52w KJyY5;û +n#xxGH+Bw]t_w4V*zloefJ +q_z"K{=1.Qk&? @K}o`XT\rzfN~1MN5CBӅ@wnzrldhits2ӓ}=\͌T޻-+)&e=I>f.1w^dBx^KWy'jZz.AaQO/.ml~?4:69.[۟]/Av?oomKPڪϟ&Gz8Xi=ytM)1a~׮\bEkKˀGjGǧ%eUuM=qwG/~M޿Яjc 7v`.L҇@wTWUVRGy:Xk#tŅ ]Jx꼍좸[P`]נSQnVF@@ FAC@uYf/#wݳ3xu}U5̬]<|C2ʚo/?]q}nKCMe)bomfݛrR0]VӧhNRRt%KF+ ".U36vp +xsJ+k[ڻ{qəťxww[Ks3x`_Ow{KcmeiQ~`mnЕ`eb@R%#n&'Pt ^AWֽG +Jj6~A)YoYUmckw?>]!MvoDDw +Lwj? hm*tSÃ<]l̍Քݻ% +"tP'(bC y '("!UV7ut IHI[P\VUBx޵M?_3f҅t\_t ÃnS]UYqA`?/WG[ }mue D =]D%'Gf +vҕk|2oLY]?8"&Koy5hdtbj'/txN^=H|_qvjbtd]'[]}"1&"@G]H +]r3#J + ]rr]Lg{/.^zF/,WEC; $"}WXRQ]܆.mlnFw~M͍eB05dgijӕ0ҥ${#w!#@xi^ I޸sM]CS+;gwؤ o n?1]ݣ Эf&F;Yj< YI1!~/]tb{{-=WXLJ«kdfemieMCs;?69=;Lmӓcxn{sCMe7ٙIqQ>VfF]9)1a.=3ݓ$"PS^&V/ͻ*j[;xE'ef -]=}8:ݧCDw}uyiq~nfrjoit3Ӓ}=\͍T>{SNJ\X>ѥ@#K=k^j/+ ".-*(i8zE'gU6ttûxW-6VFn+tڪ ?OWsc}-5%@W^Z\DХRǿKF|'"=RPR7qt NHI-x[~;س1Bwj|txmmt rSÃ\m,Օݻ%/-!"ef;=A>f]lv^tBx׳^ \~g&n^1 /^-(.kjx?4<:.k[]=.yks} ]t'F{u6Uz"!&<@[]H +]rD쯿E.."^rT(^F$WC?$"&+,.oj>!xewyckw~.BY@wT_]^\&D{9Zht%EP(]*{t$L_=Jr/=# ;/$&){΃'U4t MܽB"cS3^TT7u004261 ]^Y0޿ ѝ𾳭0uFjbldH'ܐtYwR=J9=GK~U~a1)O@hd\RjF%5 ]/ndl +sx]@w;96tڛj*J޾HM p23TEJ \|Ks]c(^ +ʓT4Nxťn}TQUS704*.9--ihxpx"y.74TiqQ.fFzO޽)'%.,e9}$%J]]/5W@D\glnV6w 3sK˫[`>ݝt6Wf&Ң@7>*,XOK +-."ĀХ&KF8 /3Wu_Pxt|Jz[VUƏOxWn"M@w;5v6VY)Ac.8Ϯ>YEQ *** +͡%EP;E)iQ֙e]׹#=skߏw] .= B i.ڡxO`Bx%x \~aq6,:>9-;k8;_3ŧ م~nѡn@ 7;-9>: hka pAt] +r0vaB%"BfKK΅SPV10urdžG'Cx˪ގށщE/tx'/AO|[E.LMvwuUepK +Ӆ.Jk{/^jZ/7WEC; 8<}WX\^UԊ;61 ]Z^]^{c{on./At'pt[ʋ 1Nv:*0] ^n.-]<'thxKx\+("qOU4u M}B"bS3`o}xWvs$B]+t޿ta1!>vV*O?{KBDƵ+̀.%Dl?(#O^DIM*jY;{D&f|URQ][|dg݅ɱn[S}uEɫ9!>VfF]IQA>.5奋ݳ(]ޓ^b / #OHTOṶ\<|C#㒞e5mzG'?|[v6ݣ}ҧ&G{u59ϒ"C}=\͍TuޝyPn~̇Нt[j݂ܬ0wĄ184T8gnjEC"ǟCxXXع02r +&n^ذ܂Ɩށ w]] 8C77Vy@wbth 7;=%>: hkab '+#-.,bgcea]E?y!DxxI^^pxtWXTVUxgfqxû3y%ycwgngGwq~vv6U nN:]^.-B.._QhKu*VvN1  +˫Z;޾.-<ޟ]_]^NO TWU^\<#5!&"8PWCwoIrs ;tI@ᅏ~d%Jj:+npp jY;{D&f|U\^] M%PE.;96<v5Wzloef+*qf:jK.~Qh{rI/1YR.Bxa<|B=|gdfm,-ox{G s ] %n泤Ȑ@_{k3#=MU'ݖ2Bt/^8OFz{].cᥡc|MN~!1^5-=cskOߠ8E뒊7zG'?|[6ݣҧ&G{޽ikn(yЍ tq67RyeF:sCC xhqx1ԝԴm\=¢ӲʚvwxGw;5>2moi,tҒ‚<]l̍Քݿ#bptigOt~!xO`Bx%x \~aq6,:>9-;k8;_3Aŧ م~nѡn@ 7;-9>: hka pAt] +r0vaBx%E3saťedu L,mܼ )޲*w`xtbjfv~ -Kxtv3S]nUD7=%!:dkib '+#-.,bgceaEtKDEAva'०e|:_8>"sEu EQQQQFSD@NESP]uf9_7 ?>\0^EUM=#3k{gwH7-3 ;26 ᝛_\^YOޭՕ9B 73 Ѝ qw63TU +rti(6=#\;Bx^F&fv.>AQ I)iYE5-=#skgȸdoӿwaCw6.llot+`ɉq>FzZjR|\,L .Dt'].Id(^n>!1o`XT\bJzV^aiEM}3whd|rjzvIw ;;=59>2m(-JOI + pq17RS qt)Οb_CAxOx) Bb>x,oba<%=୬ihn{?4:繅%<u!xucsP歏>O3AnkS]uyq~n&HWS+˅ҥB%ܤ+Fm{/^ +*ZOPTBRJZVQUK' 42619-3opdl;7|HDwrld 73-91624HOKUQVZJRBTeؠKC(Fk_%؉=OFAM'UR36qp KLN+(onxG /:y4]c]@莏 m5%yYɉqQ>.6zZjJ]!>nvf&FZj +.N] c(^"$Ϝx9n}XNIM[70,*y +[XZQvAxg Fwv;6T)}=]m,Ք?{KLK={4)Ib"1<]{)/%5Wr #xյ L,l]=¢Wٯ K+k߼az tW>Nx?>:MsCmeiWntX2BW)b=':%Ar=W10ur NHJx*k[ C0yU/95=];xН6Te$~N8> +aP XUQQTTTPz{((; +{I 3af\; 3?y>IqQ>VfF])1a.= S(]^B/1॥gr +`ĤddṶ\<|â2r꺦֎əťu<[G.-9=EnAIEu}S[';w@nt76!@ Efzr|tX+-`gctad.їttѾ_3I,sԴ X|"7nSPR7qt NHIxkn[GǼݩѡ^@LOIru0VWRw .-9,ݓcF}"/2x*7ĵw?TV60utIxYv^aiEMCsށ w][ =Bx ~.Cݯۚj*J =yhkab$D^x{_~Fb.J`N^/^R/_Hc`jiV6Cxw xy{uݏ>X@71&"@G+*ďХC%ء#J $xiY^N~aQ>xkhjeyN~QYemcK}c啵G + ѝ{(?Ȑow';+SC] G޺.)* 0l%{vpߋ=KECrNa1,^UM]C3+{gȸԧY/_U5vcX/2y}"c]ҝt;Zʊ^zloef+&,yFz.^Qh<^bS!L0^^o`hT\rZ[\^U @x8tʋ݌丨@_{k3#=MUEy9Y)1/L { 1B.j[{ //-=+; FWMK7(,*}[P\^]?82>937acޭÉwWf&G{:[ˋ r_QaA.zZjXA^.v6V&zZ,]2|PhxO"xix^)(i8zGǧg%mޡ) +MKEC*jY;{F%fd|U\^U +_t~',ɱnkc]UyYIqQ>VfF])1a.= S(]a?%DCx)(^Zz&/FLJFVN^QUK70,*>9-#+୮kj_\Z^]ûux£8?739>2TW fe%Gz8Xi*Hax L.%DKGvv/KxY9x1_PXt|rz܂Nwh +݃W ^5S"xO1#xqxiyE%5 O@(1&>9-3'୪mDmwk^=vV>M "tk̴bhACMEIQ^/C貳0BRmG3@xΜe)k L-m]<}CⲪƖ]=}#/>:vd@wdmKc]UYqa~NVzJ<hkij@TWU  ?e8~0J]rBx(ҡxYQb(^]CS+;GWOHR[PX\^] +x?"xcy _ky.B+y3mm./.,tHavV(]I1a.+J. +ݿ1XrkKrZFfV\E=JHx[𪤼=C#!SӳsNOAt? |xUAӌԄGQaA][jݽ}YIqaA>@y. }]-xޓlg/\BjY;yG&fd?񪤢 E5x7]@w;: 5Tz<;#516*ytXOޝ[7IIt9!';HCݿ.fmx!xY8Ox_HTBolas?$":}uiemCށO_&&M|[Xwi']ZGwaԷɉ/Fz;47V~ ЍvwocaЕ|iN6t`t=@MebaG^yE%5  gbL\rZ&[T@x`x<ލtRН At[ݲ"@73-9.`cab(,L(]Z]k`Bxe8rAxpx&' HON/,*kly7%k.K;iwic; !}]oZʊ +sҒIG[K&LW/r؅??]i=^**kxP\g +2 +הU5 vtoq9pd8+w~ax7 ..Ct? tumtˋ!) @_OWG;KSC5N.vV.L>TT]mi.w^e̬0^Aa1IYׇAaާJʫC#!S0^Xvk^-مNAt? !tK^>tE>t}`gefӕr2/ӥ7FkKĻw=^z/#}%>AaqI+o޾gdfe_Pxԣ o3sά][HM|큽7_t,7ѥ_Ow/Fk[ރ'P"Rr{zFNn^~ѱOx]ZQS x'AE.Bw6T~Bxݝ9]`wqaJŌ iTDQ H9g(QDE%3(&"ֶQ{REX|.󿿄`.(]M5e J.{1X5^ +,x^Ye#; $<&!53wxg_@xa:y / ]0v?g }1? m͍%9 1!DG[KsScC]M,+&,ȿJ.FkK/ˏUPk!xDwRDlb*9fs[WƟL}݊w+_N=t`_W[ͺrjbl)ǝHCjUd$%Ąq<.z]o ^&/3 +'7WƫgdbfaeGp $E&s /^w ݅.gnN5 30ݻC}]- siI@W"LWŒeڮeG +DSTUF;zF%_-xowCxG'_S}x7W݉Qnw{˭j@(BzR\dh=BW[]UQNaqB.Fk>(^>!nAQqYyEeW;FNLN-x,v[}}073591`d6{JYQ^Vzr\Th'J]!>~}]xx{ + +WRЁ88yE'gd5 oO0wzf7[mŻݿݷ0fa=nC [`PU ݟ0X;zeC + +:rLF^IMCĩ3l\{Gǧdd_zg`x;>|t*K si" +WAyy!]]L(^f/'+)kYX9z"cȹ/_7x>;wx_Jw +нwf]յ siI@_W';+ 3#=-uE9N2thbvv5tx0^>WQi9EUum}oPhd\R"B.lur70;tݢ IqAN]}muUE9飇]>.;.Fk/53GB*jh?y_PXT\rzV^Qٕn#xG'O/݊(BWʊғ‚<ݜϞ>y\_[CU +$w1X /2Jj:^g7/䌬boGwȃщm]t''F wwt2Âܜl :jJ2(DE.Fk7E9y!xPBWV18q9^)eWo4=09w]K9zTrL]*+";73 tjn\-+H:`s̩:j2ǎDQeBw/FkD/*^~Aa2^Sk_r JRIGwc_Qmm^*LI vwqjd!‚tY(2`tvUxxyx^1 I)Y-]V=%K{z[/ܵ>}0/c@O'[[ dg&Dx ƆZxY)I 1@XOC keG z"bS90{owm|?]}<L A + ]#=@Wt89XYQL4t1X;^:Z^O )261Smƻ]7opz/ՃG`Kt{;P9HRNNK>_QUkH+Q2ˤPXXXX8 "($$$$8`b@EDA3Af0d5kn]{}P9k[jRcRgWϾĝR/w7 ˘k)]i:=w$}{}}<]W祶@wl3c..3#W KL&5^[xRҥYWs x>{׿C;_eo~:_<{ʥ[\{5Ktc"ݺ}*Wg[+ DNa tDbnxUUjx'Lx $&3_daen xw O$x޻xv3իWNǷ\Ž,H.нN&DG t7oBt\,͟3DbtL@UUab#9xjjzF7m;wEF>^yz|ܽ tz{_BxLtdXHۀkW8YFzXݑp!.^> k +x/Ͼض3 ($<2:O,ۏ2T-O.Sd/~f݌ nltdxHPm_|F.K]S;ϧ"3d3qzF.V}xB#3eޚƦ֧ϞU_?w7|rrr߫>FF2{  +|Xht̝ejd7c;N+Fi2L(W8y*kL;-xwV/+_|fbrN]L]  %ކ5FtNjPv ǫx ^}Cc3kniiJo`p7|wW5~Ev3^^NrRr+W&.˯:_`4T޿çMhp SDwr6@PtGt w&ū/16=oR+_ccW`׀<ޒvzg9 _ +neJ29u[K_t?ް˝Z/7XKjjQUS{/:YVו_ ,[DV56KvsUK~e1prn@ 6UE@7{~t} ]Wkҝ.;wDb%ܓUU'/b Vή֬%7-{T]𸩹 {zI/\"e(mknzP[ **aݚUV KWE.3#w$Xd,\dJo~ѭ=({TU[؄^zp׋2~P\t.3NݦڪGe|(JB8YY,?gĀ;CwHWWw<ƫg`DZ^7?o4+;7[ZQUSHv3^tR2Lr˅~$nT.tQ钽X_SUQΒst݀5kdUQ S;;6"K]VS\)k7n޾{^ĜɁK䢵+ݖ'j*K߽}FLiz +/z k +tgLtDZtG)ʑëN<Κ`1»ݲ7obWxKӣTn^_3̼erv$JO%@0MJdn]u ]`,S#C;uDDWGwHWd@WkL#koܴ{(x̏wBx}#cSҳr +Jpnwt|rޗ^`#[ѭ ׯ^Ε;9>ʗne%y9Y) URX%ѕH>x7!;GW7O߀Șpb77 +;8tkdl|4}t_gˀ0#[r,fi-t-ttqL?hwJNWt7Kt,w%U=^sz*&>9^چv\4G&XOf|/r0ṡlѷp+E>yNM\ƥP[LnZr|̩ O7k{Lw%]!ѕ"+]&|~6v.<|N KJ/(.ÙީX31gy|Ab+eX~8 8t1zҭ,/.HM=y㘋t?.X+ͻx?b5χq!Qs/zZ: ^{p3}0!^go^o3K`\;w[t!rblTxH ǜlm,DJt,/+W)^7^u50653<`mk|_@0 Jzy8 z<#K~ 00!^%r3<\-)Lnp,L @Wnڸ^*2]:vY+CG ]x޽;{u.ùK3ʗ>b L7R,@Wfn pݡ,Վ\_˥w.+#%)>N]_OwW',]=Lw͂t%R>xE>FGoHLⲊ&Q[ãc_, aW +xFjg[[CDMueTi#Busuylg~{w P,6Uc.E&^é`w}{eD~"ѕ(xWE+:zݽh7GDšzdpv|;I~D @ &Ը#Ctrk*y.dAEE^rS j]w.JYdy?_oQۮCWd8z8n MI,Aӹ`g1`+=62 7i,w\NO tM uwhnWDWʒxW~]cNCvoUolB2gЋʗ^{O!m;S6MjܾkTm͍s!.X*_/^Spj讖JY۝:Vi`l*NG=zNEpfE{k/ +~IdJ }OLQۛCqB^ŝK &*xc.ڈkl{Y^UyDWʼxI(Z:zF&zXpz""|dQ_((*.AV``2(0KeKl+з%EqP&EGF\4P61ђU@WIQJt,̃W^EkW^mݝ\4\Y`ph8MdK~ KK \U H-U@ eE67Sr1CYe .]Ýb +JbJt,eWw[f{-[e޾A!TK훑=OKʑb hQ<6K93prC}GX0߃KwNO]%^^|DWȟWo^]죳WsK|1S~?EyaMqI8 + aQNB9 *" HayyZcؽM:>sώ}"Ϟ=K(Fϟ?]aD<©,perfg&\z|vNo%WPoBwoon;5]"ںtkkD]NOaq'r:\91vt~v Kzc[RjgOoӹV3whdtLM,o/,ZX-jM5ܱё!k&\SD˥%M+[wɚj\ˁ\\Nˤˊ3on6g/O\Wޑ GFF> Ce]َv L鿟ુKPv[y*\r18M]eE^޻NoBo9,/_ f~կ^(| ָm\x\UY.eLf3r8GB9u~ܙv^Օvʶɹʭ|ː[+7`mP/-Ԃmmk'7!ל˼~^s8ꭈ~0 kZ5_5 Z[6"\NImI֯/F1|-Ԃu]2zBリ^;!_3WX0j0 2 nNnL>M?Iw ׫kWaT%Ŭ{k?I1W^7̯_,aدFȞem &r2R~zZ8_ âX|Zaknͩ,pO.c)^=8u~~*aX:d>W ZQ+lq'[ 9\=)/7Ի7+k`1 R|*ֱ\n8*woT.2V=v{ `aA,'TԆl[7fsP.c.#~-`aE|@Goֲunp~K%JW`]`>~?լ-n=nr\epzZ_ +,VԂm6k&\e,Oz?;BX'Ԛ;ٸɥ\ޠ|zS_`8Ũz'4؛77k;ٟk+lCqI+~le~ujKVI|կ6p8~@u +r{25q2m0\e*^5aO_FZ۩_ϯ:m-2ˤPawK2ZPm6\eo7W"66pK!e ?p{Ły~}y~ [ep-`8l[e*-اwyi +~%ZeU> 7 cU!߻`H#[Ȗ:e콏`c1c1c1V0. +endstream endobj 257 0 obj [/ICCBased 284 0 R] endobj 283 0 obj <>stream + +endstream endobj 284 0 obj <>stream +HyTSwoɞc [5laQIBHADED2mtFOE.c}08׎8GNg9w߽'0 ֠Jb  + 2y.-;!KZ ^i"L0- @8(r;q7Ly&Qq4j|9 +V)gB0iW8#8wթ8_٥ʨQQj@&A)/g>'Kt;\ ӥ$պFZUn(4T%)뫔0C&Zi8bxEB;Pӓ̹A om?W= +x-[0}y)7ta>jT7@tܛ`q2ʀ&6ZLĄ?_yxg)˔zçLU*uSkSeO4?׸c. R ߁-25 S>ӣVd`rn~Y&+`;A4 A9=-tl`;~p Gp| [`L`< "A YA+Cb(R,*T2B- +ꇆnQt}MA0alSx k&^>0|>_',G!"F$H:R!zFQd?r 9\A&G rQ hE]a4zBgE#H *B=0HIpp0MxJ$D1D, VĭKĻYdE"EI2EBGt4MzNr!YK ?%_&#(0J:EAiQ(()ӔWT6U@P+!~mD eԴ!hӦh/']B/ҏӿ?a0nhF!X8܌kc&5S6lIa2cKMA!E#ƒdV(kel }}Cq9 +N')].uJr + wG xR^[oƜchg`>b$*~ :Eb~,m,-ݖ,Y¬*6X[ݱF=3뭷Y~dó ti zf6~`{v.Ng#{}}jc1X6fm;'_9 r:8q:˜O:ϸ8uJqnv=MmR 4 +n3ܣkGݯz=[==<=GTB(/S,]6*-W:#7*e^YDY}UjAyT`#D="b{ų+ʯ:!kJ4Gmt}uC%K7YVfFY .=b?SƕƩȺy چ k5%4m7lqlioZlG+Zz͹mzy]?uuw|"űNwW&e֥ﺱ*|j5kyݭǯg^ykEklD_p߶7Dmo꿻1ml{Mś nLl<9O[$h՛BdҞ@iءG&vVǥ8nRĩ7u\ЭD-u`ֲK³8%yhYѹJº;.! +zpg_XQKFAǿ=ȼ:ɹ8ʷ6˶5̵5͵6ζ7ϸ9к<Ѿ?DINU\dlvۀ܊ݖޢ)߯6DScs 2F[p(@Xr4Pm8Ww)Km +endstream endobj 280 0 obj <> endobj 285 0 obj <> endobj 286 0 obj [0.0 0.0 0.0] endobj 287 0 obj <>/ProcSet[/PDF/ImageB]/XObject<>>>/Subtype/Form>>stream +q +/GS0 gs +956 0 0 1331 723 1070 cm +/Im0 Do +Q + +endstream endobj 288 0 obj <> endobj 290 0 obj <>/Filter/FlateDecode/Height 1331/Intent/RelativeColorimetric/Length 95307/Name/X/Subtype/Image/Type/XObject/Width 956>>stream +H _glv7j4Qh>來>CR@56ouUOwOI֡~zJ$I$I$I$I$/.鿕$9>yNA%)9-rO,I8IrN%S#r/IGℯ9r>ڿ}ΰ?$fOO"I -u?_WrI_wWb{NBd-ܽl}|C+zFխ!.e_NPd/\[{G\&W +5zԵR6ݻ|$Ie/Wkݣ:lW_+Urpuf&ݙ/laݯ蕂-&[EgwR3dN?t5^ھ`u"0[Zꕂ!rթlv^TNcE'}#W.efO"\cEkW+%o5YN:L3+ ؗWr0j2Z ,#N;S{93aL~|xG?KW?MrݲZK3FQn;6fV>z\{t.ry2\ݭR` Y*Z/ECG7(lX ~Mz@Ke\\niۂ-eK;'h0 f(z%KW_f8.ҶedVQC?h]p[J3!` ؿ̗t8uemUp[VKfE#uI+2ƽg0e2 LW55^_TRet媕[2xt a~5+x%Gk˴tV\n-ВX'$$kus$$$x&%eǏҡ~/l5[l[bfI7$;H20%^q_PK3V+xCʎv/Wnl]'5%%%55Kv+3 Γ;H2/իga揮zjKWɥkeI7YRIOgddiRB2_^zիӿgGW&+nS,yɥ ';,1&Uz͂W:-]:5XظȼMfk~~AAaaaUlt'YLcc‚ D8/bbW/^罘b\w.ɽ57r@ E*7sH1 ` ؾ Wޘ3z+}=U/3Q1xk7nӾ[-*e1 sHq .`||YoZ+W ]~b鞏My nmYyVҺ:Sݐ>, i0$¥%a*/|^͂Wr ;NtKK],76n~AQ1܂muM-ԦJYk|ki&\#UN1onvV&{Njt8fr5Kr1[Sett$еLrsnyEU5746Al+좺7F1|gGnm! o^NVfMV/^|7'|6tĪx]SSOl[;P{{~j`P3Oz{ `"ٷ3Ro(̈́7L"WtCB,tԍ1nrJ&6ْYxϡ4sIjQ=<<<4`˂ᷩ뷺0?3 1g+v@eZcB7JK7Vf[Y]SW{h,OLLZSA>}L=111>>6#dxwua`B/]t8wcW F2nzFVN?0Dj'&tzzffvvzh4y14< &=X-M ZҋYδz5'Ьk/]7SoefZ{w`pxlvz`t~~aaqqq =8G/-..,,σBc+ =^"5sLW?Z'whvo]ueVoNfzxO ^bW +H~.а?sVMNrqiEu]}Sk;ʝ K`:>W^~A13Frs0,C%-U%t7$]7^+Wty]Ѝ$1tx^.mli;0;Mp=[}f_ο_mƈ;;[[Mtu1>dݝmXxe{"YJv~B.ӽCrU-nGwٹ%]xb%nm뛷owww߽{+KRbwo߂4)a~l.?ޑ^΍&7w'#+W. 譫Ž?8269`ng/ؾy ?~7<}N=0}Kw]^Zމ=X|7x76F>yeJg톐]u1XЍ7⩋{Kw,bܟvlIدϯ(3 rn$kCD\EQQbA,PAPTPPD(Pffe A@(ꪛlL6亟=O% //V3cK_Kv5kwd1Ϟch`ђefVt{x^@F@n|b2HsdP[Xee +TJصtBQVP\W!JMNs+2"48aZ+`ˋZ(^!O.~OtWZXݰ:>~7#oA.*7K#'e +xT*kXju%Z]]UTrE73=591˙U%oOw-Xt1zjB +hN1Ō+W[lZ_](ݛ1qԹ+/[TVUVi`iԍp꺺: +XYYQW-! "Bz{qw9;m7^ejW$3;}kz&۝8/^B +܂2EE%֪@V[(#;Eqb+ӛ2jk\A|8Iwon!Լ;n\frjxB&,i3frͺ[w v#WzvbټnGO"މON˔AnU-"===CMhH7" ĝ|@oIQ՛p;qa7}y,IpȮf̛pl1t䄛W7EE[ Oh l__#c<Ѽәh(`ߦz0O&%z{z<~򮳲~Bb?xA)h$GAʷ +[ ]t,r+f!q&7R~7\VX;{╠p5]enCpKj ,DBX^Hkp&`yyùRQ\Kxcƒ.zq;qi-֎Wã7]!q'3ڵټn#నxnn;>Dp^@+  w[\$Az;QJE Ûv*Ob5xzh/D3df;}֨pمsɢ,--W7ut=yAtk" \>HsL2b||^[Kc]Ǜwf5 XGwl,(1Y +|j2v wcFĭؤLֺ6wtѹϞB-#寣)#L2 _'z:Z8rifZbltDH^n;1Woƴhf+dB<}&EW&fH%uQr[R1u&y _}{x dԄ;QaXN8tE̞9]k4 ^!Zy\#KWZYj 3/_ ϮD_`tu={E.Z8HsJFHv8'/z98@ՋN[('߾ygPĘF fz4 ^!dF_vpbeUt?xr ۟Zϣ)3A`_^/Uo_oYQ^vVZRltxpiW-֮2[d[a4 s_`bj&[;.~|E$fJs K+et zepI/ZA` yҨ(ŗ7#%!&2T]{l7Xahh?B +L9VYlnQqbY~Iy't߽gr?2Y?a~?Qv4V,JG?ޣNvmlcѼv,dmwɼq=Q Ŭmhn`wxrn3L~ûoޞw~}6UQqJ% (((D JA%HP ,9H 53-g}ι*v Իl.u9I1TJ%ø]hZ]Je606s RԘ;{F}+L."ePc~?"B6ww[S~0?7+-9.:"4阕&4pq`:xIdVZrrùKW\¢&{Al}8]pt\E +j0^ `ܹaA~.6ҕfE%Ya(s]DԘGƟ<那$|ePc|^pzq3O'džmoʥIqgC1fQX97KK^2+B7w*'O&f\kAu]ShcS3.~!R.1g(1HGЛ!޹ٙ 57 ozJBl@_g4k,fl𲐃 ò.+e +{VAe>uKW opٹyxua_7En1gP CP/]{6 [sG- ͼplԩ ?/4Wy?/1xIdݵ..*iWo߁k?1/z.<@..L_؜@6/;9/Xo߸f[KC=}%Yypk(su`]Q4w5Ys+sN͒{5N`[..2[#"`wvz +ޮ@i J,ڥkHdVosإ.~ADe.]V;1=,AGeR!"x߽} [3vx;Zk+`ifO;kscmM|nNhw=+ Kf"# fN`WXLjE5M-l\B"Sܭmh'*3qv؅ti䮶N/+qx߼ZKswGkCMŽk!ޮ6h)%%& pn޴qavאvɬ vAe!,.k~]CK[G7؄Ԍ<AOhƌbx /4 t5>,+hkib_M !O.*ͤ]2+rl.+"s^}ZzLut llxln՛wpTf*զǀ}tbdf匔/W{dWھKvd:[:yF$fM].e.-eyiޮey9) 1!ޮ6h*Hv0>߶ˉݵGQ ڵut MH/,_U NNϾXbs̿#TҌ}jP_W{S]Ԅo7[dWMq..'i . z]ahWIm x226Bn}CccN0{sX[-ZXE 4j%Q%ZQ+jܢnu aDAXň (EA@Ejrz{w +-.-+vuvU8k_U vebCz/Xd9}Ʉ?vvZ]d$vҭG~V /ͥvKT6ɬn K&]?w:h@]6^nkݟ.;%@ v]y.]I vn vݗU5߼mv)޾}󺶦Ba7j72<$w7=;@Ů0a5-uݮv50PإgWɮ2e*^rTy.jv +v-a$9mF؏&vgwOH[TRWnYIQaCnrB|\lt bw3؝A쎶ac=v;t8;n-kwQ[݋q12ICa>v]E +UMSحy`}wQn^VFnhbwl?"uvԴkuM̴Dj7 +v`{]:Ů?؝$uvkݯ*v +J[Ңݯt HvL9/{TE}Z(/[{ ,c3"%gw3/%ݔKϜvٝ:us h.c8.rjwc{Z +xa6#.Moc`%'O]=N<~HEFH}bw5"#ݫ)E-nh~vfzjz`ؽ~W[\ڭ,QZ,ؽ~v]`q2ZXlw2ݠn;K Elna/e vg.c8 v]Y"΂]`q2`1E.,e vg.c8 v]Y"΂]`q2`1E.,e vg.c8 v]Y"΂]`q2`1E.,e vg.c8 v]Y"΂]`q2`1E.,e vg1urxJn˶+"z؅]K"΂]`q2`1EĔLnQiYy.2i:W'} LqvW."nKJ0vi8 v]Y"2jwphD.2w"ޒ;@aw+.+e voI$awvaq^vc`v`[>v/&&."3nPᨘ8؅]dޚf7+aA!.2C v]."s]? % iOJ؅]OJv ^Um$F."J+cw)ݥnnB ؅]dصENwt{;#+va'f6؅]Ivmc!gwHF."s'mq ȬٝNm{.>! va1VԮ]]ojWݪZ؅]dm(E`ZzQ|]Efbva&=zCNv6ؽtvƽJ."S'ig]~ޣ/~5d> v? vOvݜ`1=۽u`Wn[6 .v(:w'zEFgs=VP>ݳ ȼmmaj#}QQ L6W]B vr؅]dn[\g5.2Y v?]nuK[Q^VZ$LOMI]ddRǏ>S/o`Kn^vf]E&I_=N^fivWvNHiFvvG;K.?YM?|ᒿR_ v ̜v͹lo."n/ߕLWۍ C.]dC."ݿ)ٽ +v]f(k'Od{vgva6#n]۩Ev;.2\?Y>5<-.]n "dwhw%v/ӳ"CDٰu84 aǘ6+<˂]dt v#v: +va%63g ~L첥ݕv.2pz۽t5Eڮڍkc=H. .[v3n$'vCvSKS& +vjw1C{vfeܖ8eo i iyhw ȸivUcMZyv۾C:]1vNGGȀ.[&%ğkuwȈ.[jvkk4vQV nv&}v }:z8~Za0-ʒi4ƒ-Kٲe*MTV*T&MZ$|?3sϽug><xvǎ:oc7/*إJ]Yc.yUv]m[6oXfEfeͳZv33,i%Wî, nϰݖ& gfԫ['=v%®2c.[TbWؕ%vO\j;v+K`wm7햗9vð++;mݹR5W.ve9kwLᐂnR K]Yhen;쒗aWVdvͰK^]Yb,=v[d7ڶ{v+˦s~Xb)aWc $v?}}kN۽\aWVCv<݋K]r1ʊOݥ?D}}qؕ%;zĻv.ve%;'K%®۩mSO>jؕ"^]$r}믛~N +QؕFGOvo.yve% +D_F.vE`-caWTvl{;vð+ +. +۵:]0k쒿aWvI]%m5cvO.vE ~%o®(7]r3슪݋?'l.vEaԅ]Q%uaWTJv_.vEEWl]RvE >S]RvEaԅ]Q%uaWvI]]RvEaԅ]Q%uaWvI]]RvEaԅ]Q%uaWvI]]RvEaԅ]Q%uaWvI]]RvEaԅ]Q%uaWvI]]RvEaԅ]Q%uaWvI]]RvEaԅ]Q%uaWvI]]RvEaԅ]Q%uaWvI]]RvEaԅ]Q%uaWvI]]RvEa%ۦ=.i*na76쒺R,vKZ®(쒺+ +.. Kꪸ _]RUʵ?o܌]R%(du-8݀]Rjm.^|E}%=Eص{y:]RbM`o +}}ߠlإJbFWXvom⢕k] +&W]RRyV݁݉.Z7i3] +4;e}a` 5v}.vɿb~؍ +2U3v8tXbO`7˲]쒮MKfdZvf57vs^evg[hŚu6oٶ%s[V:uedoIJ2le;إ=]/b{S] إm97o۝]RE٭Z\cwmw=.Z2 Jv5v{ )kwvK&ζݭa]-fndv]vϰ^,Enb4ݧJ~hf%Kj#] +vϽ lvt}};dcbq%v/c/Cv\Sݿ.vɟv4v_h`Sh] +awvK'im{]T2E}%-%{u7F}'/~ݺ%ٽŶݍ.P%.v)*`wDvbGݷ]Rm;b*J.vn/vK]I%}%{zyv?.v)mh/] +8vnd%}9=cv9"우K®$쒾+ 쾈]쒒\xvK]I%}nwQ.v%nmK]I=F5;aWRjv.v%a]I%}aWvI_ؕ]v%9ݽ._%î$'v׮Z$nOaWRv|õ%® +۽v ]Re®$쒾+ /J?joc<K® +Rg& K®Tj`X쒛aW$쒟aWR2g)']r7J؝d}Gؕ?]] +$Jkwg,wwhQؕlw~%®>m4aW8Gwvy]Rîv|7mA0v +ٽk=T+)5+;mV..yv%bc>aWD@Vv(vɕ+)>8nd"K]IΛ5cjݧ-wiؕe}Ƴ}nCc.v+Gy8vɵ+Ifwȡ1vح]tؕT9,waW۶lްn͊ ,5vg5ffXvӰK.]I",ݞa--M̨WNzZZ5Kn]Iev]n!vɿ+)MKN:nwaWn-/sN+쒧aWR=wvWsvkT]r'Jr+!ݮv`< +˶v%oîhv1va vXv{tp8+ZPQZhQ%ѴZPI+5()YRi(5fJT#||^.o/<ϣYcn%aW%n\/6ʳ;@UInz K~]T΍n׻{jQ5a*ݺi}yqʳ[iUnX5vCMK]NOh*vɇdw`R aW%vۭX,v㰫+v`| +*9ٻ{v[6m]-GZvo.vUJ`w#v)3}2v) v.vJnw`| +a4 +Etf,tUaUH{M{vO>r[WU gc ++/4jO.yv.iv.ivreYR aWXG] +;*]0*hwإ®B% Sҥ+vK:kX؍ a.vIvIðvIðvIðvIÒ4cufvah޸Ų{إ`SۤEknb)jhv.iv.iv.i }MO6إîB%K`J6)]+atn)=MC]Ҥ.v)=lJbB̕g &9s· ] +㳻a;vaBz:k}vbȭQvax^kbf[%]hwvKw7n9b+ƽa]uY.`zvooڬ ] +'ev_.vI +=XDv65.v)Idw,X]Rٽ= _dvK!nenvGƳۑ߱] +vO9  +cvO1K]9v{!vɇ+fw+.].vɋ+nֺV.1n+"vovO.WؕK`w󆬵Nv;ݰ{]K~]97v_0އ]?)ٝmk}:N.yvd|0{Dv`<rK/aNwa|r1v?[<#Mحkڭ]#ycN.yv=#_6있] %aa9vϰ+h}?o~ϛv{voj~afunr%îw c OEfؽU5_\ +)svtݿoγ;dv(ݘCO翟o1R ;q~la}O;މ]9ˡ-LU(~2vɫ+``QoM8fKv.v +#jw,K~]X%Ma,yK3VgfGvL|Ͱd5V.ki67n'Uvg] +$MZn"E6.WԮn `wnpnS;ڭQ Oؕ=ju݅حg4v+g{,nݡ^إraiwXIfbV.v$lvc**vۤtƮnv+/]>승;nvɿrӴ;Q9{wcwn˦K~9g^:8FAnE! rPw EM hDV4^p +6j4j6vjZh:6i{Y}y~߿`=y`ؽhULEΈ]vO`/`Vn#v?/>=vgw4.j]x}}vUbM.\ݬdk5$w"KQ~ qAv7jO|Hdv ^]ac TNkkݽ~ɯ{ v%vwSt펀]dv%s(_.vaY0vwnz.tpp4ew+@임]ƌ캻]ԭ)4e'".R5.(XFn=w㫰 HL vvS>~ vwZuvq]Yv>vie-vj>T n>2&"kf̮?MgNvݝZ^/|̓o."kh?0$4":6>؝-٭ v H:aEcMC]EV#v>wAc}؅]Bٝڭ힅]Egwv[6_؅]dXvP5-G vaY73vw(}('.ZfȦvXv."+fnh7-#{dw [x#v7j'v/^3n 1&m]Eg(nN^aQ:jZ{ +va!c=s^v :ow5Gn7ӷo؅]dLh@؅]z]f +.R1cv.[2.) r?]EĶ:%KnzvtYvgv_U{vaP~ԩvcvu+ ̳;/w .*e:m+*." ` #tvwv߅]E*Ǵhav`A1 `">]Vcv_]Emv{vaY/e:nͦ`v.+E|`첂]g +v.+E|`첂]g +v.+E|`첂]g +v.+E|`첂]g +v.+E|`첂]g +v.+E|`첂]g +v.+E|`첂]g +v.+E|`첂]g +v.+E|`첂]g +v.+E|`첂]g +v.+E|`첂]g +v.+E|`첂]g +v.+E|`첂]g +v.+E|`첂]g +v.+E|`첂]g +v.+E|`vu]7EݙD`wTXݱQކvu);efQ:Iv4]CG( 6ixQgӱkl7Inw;욶]n7Iٮ]U?;}+ v}5v]kmkzXd?Pj5j=K 5HmfY bSf7a}Ycb7Mfד$jR[bj?m6XJ%ed-9ZHvv ssfee%nv{4^Ve@W݉]'.=/ٿ'%cutrѱqɂgi箳n cOu{v'v vKٙёݡ^C<\ŃW aCԮaG9f\|Jz4bwiQI[ Ve%EKi)D0b.9xu(_؀Uk>پDW¹K )%enM]cQ5{-/+)^ONJI vé]_o^ީG_cp{S%v}|G0qs/+.-+0ֻح(/+-^`&&>28ׇm~ӫ'cW ]~\ ]2v:**f|n+vV7g_j޽gv)^]v[/?K4T(__bY;ybQ~>ृWj.f2_wkk?[QDW  + ;!1u3.,XbM;j=q>>ڽp-kvVlZfsg895qبАrW+jF!^pu+uucןaѱqISf]x56mUUp1jr7a뭗c6VںiÚ/;#kJjR\ltd9xLW;@lWU:H#r%ntҕc'ed͜hK+nؼmچC2fwnjݻk kWdѼYiodk +zJm5e2:|-׈v:fu@[΁Htӱ;l8Y鹛=+'w˫^߻o?{s/_]O~Sq?ߟ|oEWk֢DCkHSh$%ҾTBJEBP4I43gΙ}ޟ~ҹ xz +i;7D \0g֌笠ZHċzKWz,,*˺"'K6eІ3s-Z5%mon>-#v>aW*[G얡ܽi)[c"W-np4kkeÆIW9E|~i\[X?6L#>0J]xN9okb6%g8[v+*i/ݗ +[tD~nVzJҦ˗1u"Xa"^%Q +ݥ+Ⰵ\_Lor9piB/WNr Иڅ :w|, MHڙ}0ؽ\vknoݦʊe;b#‚.^(Ͱx֌#եFt.d0÷,?brp) Z_lF dBaFpZbeswŸVZKmyGN+\Nmhjovvu|; mmj_.:wH^vFq[⧅s}lij .LV/0/9<"¬_!_]ˁ+GWff UE䪨k ko뀕!^qK=9hBI;kvn(}vӚwn\@9{v%oٸ!`ˇKZ +;J~>@p?>a +(߾,]1B [,(QTT"rǨihj5׮+3A+#7}w澃GO\Eה??))hjIqeޞAxbiv50pWIQߜyiρ||h `.ߏ^P..͖6p(f G++\u -(@ +׮;˂Flں#mCNxڭncskhU{ks#}pֵ+ϟ>vh޴[7D ^FJ.^+ h͆c6ki^eѣեK ?>az?ZF]\.\tKKV5e:*Vu ԂK5;ڝ yq I;ӳr)Xv=yB??"v_47>{^,Y>(\^V%K¥D,SQ͌\o0Έе8ڝ㏕y S3>qR>&v;b{^*<{p3Κ5gz:<8yxizDe +~eRnU8^T¹.[-moK7uprBn̑ړw乢e+*nCnݖ`zs'ٵ=1~C$)dNqur x'`_m-o/aؑg?*!_^jr{s.]\ܲW*%ц!qF9xai]wt\ ^ ~ ũHfa) _|Yz髷xE +2,]99Z(nvI-*ja錕ɌF[mNܧ{zϙ`I`ȪR=Sxڭk64UM Okܽub~v_t_hJv߁W/[\@JsFjx. !xLtq^k+>573g_S QO#0 ~ _1XE{kKe.\bVf1 :> +r'}A]",?+=591>6zݚ`8y|fLsGNkoggko.sj*x +`+қr ]ҖQ.\.fxRkgc/A pttr?$霓M=,Y12#"K RR(K[. Zh)Z'xg*tNe8lq2/,sY-nhN?y^yBB\V4Mb( +՚ +lmݴ 0w?s}']:x?KJޞ-ZfB.T`Ho4 Y68x88-QDr$~mB"9rE/tIεK}]П5=ޡ^PhhhXXxxD$+*:&&ӄPjVg4c{g2ނ<17wɮs'? (ͷFG4=y0x-uV.d +@o<'6&:ƫ{/ "EFw_vzaxIofumLti_u2 U뻂LB܄G;uX(6& &$ONIKgeCaVojL m$v8%ZNҹ)u1ii4GIvw56jt Y /;6c=zي*B0KLOZ[yJc.e ."{RH~mb Gσ>łl'.<>+yBL]@>g_}}~=xwnߺj&rD)SߤD.7O_ &[rw9/֛8< {m:Ѕ}Cۄ\ܕA׬ OBL)t=<* 4A:% +եe]Иw;Dbwc옻?;c1xyƵ$x &/T]ϕ˲tAZ*~yd:kV%{3^'; v_ tqB_x %7 h7E2m]MJ ŒLX"sRRoM`^>zV1w_v[[i5z + 6 JPˑˤ(3#C.=Ӓy HI]@]F/f2z;}q캠 S2 ]e!\6`K%M/@σ2R(H,HRYvNnBYP.ՔWjuu 8zk7nBe: f'?<91&/,SǏس X,ה +ܜlT%"9=Q *c ! |hތw +mS3..t/%7,ÎORlIDף,IJ2,;[.lJUAQqMyh2[a"9~sCؽïelv탗~qKC>@c7* gYi>К/=w=۶͍-ZZWU=Ӕe TB׀RJ%tuبHޠ?_w޹^7WcwLt}B_ gŰI<>D8K&Wlբ:m}2kkM&ս޾}|$#/!$xANN߿K[3ؑzdhiMZom@U\,K %q1`;|>9y_q.1؝;oٺ]Qq 4a&DnNBUX\RJ!6K-GyQfPC6"G~}=EyqH.39h0O<6"(APE0`ARwX`TKA8fNjܝ{w,>}>2E%ejY}Gwpdyr"v߼Y]"xLM5 rxeՒ|7U@~Aϗ/K'wnMPk<=fgs}wm㥛wɢOՓy܍.)BcN.\lCX6;M^իW]v=>lE)73r + RZ#khjgyZy.ोwf:yޖYz r2n8>:MokNO!Es _ñG-<5kd@xn;vјchgЭ5kеwp\O/T,Q4I$&&%%'6 n3rr 9յͭr.]jTc=WԚqrx͍՜ܜLM`QrrRRb"6Xp/_uh ">^`o5k&]vϖ'ZkW +vc3w\ml"iB+2_@`ph8%(XyMrRSSӡlsrnɭk@_Vҥy]vg /SkV#@onczť7/7'!8==- ހ?ܮ'q!f@7<480z=N:@ZkSkbzpRkVyٝ-vYc^bɗ_m8hmcwǙ}96)hƧ'C/'&++;;;j +\IU 70?g;Z f%ޡޮVJAp8+=v#ly:¿'{9:*",$zϞp?x>Ư41^bߚy3c/@wf)Oo !ᑗbn="JxLMr1P e +r)tstq +?ZUK3S^5j\\\wVyv]oÖ e@ro̥ ޞ\m-y75 *f.5\ _o޲n]е?vyHD.&&R2ET>;bҲ2Jkncs ҥUl =v +^5e-ޖF[S]%%bqY=/9[x QLN%%/72,8ϙn'mnޭ[6a=Nޕ jY*|cƱͷ[0ŭKt]<AHnB(5^IUB )ϩ৲R"Jm| Bؽ 1y;[.d}fFjFj pT*WrM/=K~REI RDhͅ5ݱm߰fOiYUbWhwo7cu%9yHh㥴z9``VFjmk[{.Bw]֘|BkV;pыwKJ~H cwrتo鍉 +5cZJη4RUbWh!)t\ArVZyza@lN9En eS>yAWјY_&YRqw2Ԅ+[]aN;O!*e%Ō/q +Eo9oOkcu|Ϯqyf4Ϭ̚;wznPhdtDQ*-(܊JV4d[[۠n02wݩtƬ ֮JRk;x +>mxZ<0ԺZo$= ߢқ*JX.yG{6"{<Ћ|<][Z.^%vY̋!vMص!ьnVnaRZ#V~>#lㅹ3:Jf {%.;"w. :vՃw*z_{Iuuf>̷ BFZ).)bx#BΟpu:fku`?֛ x~xEUq?sD"%4LаBR,5+@R&.(ʠ)" &*&R߽yAb̙~35QY; +*aG%6fEK +YB&&ܬxG6D4*m*k[aИa Z. +蘃qiٹbd E;?Z;U82Dq"\|#K2HXFW7pȸ_w0nnMК=L ^;[_kS;*2 j1ޙBb[/h+VDtRgPEꩦSShkH64-3]ex9 $@p-*;`M߳zÞzm@_7xJR⅝7Bv +h>^ߒuqvθ1GXًi`b"etKe{T0[VsS-)>UT|4=;Ak^YӦLr?M4\xoPjnI+Sg̞nd,{cIJ!tO>SJut;?MZ<.R\}^ʗxX5}聳&~3O)IGw$ ^gLu~fKBi.etnnd٫Q_c\w-He~U,v7ls(>1 +s>咳2[[l^6O37Zd np\tŮ2T/x[Vwc0>'(?[9jsJb蝑7\J{4[YkbȰ7Ņ[7bW9^ݟ~؅uטmlXeg?0И20u/Kd5le+dZZ`K +r2 +z _zWFOCߚjYcf{`n0 ^`z[xqE<ݽ{Yb?]Ggn*kiIJM+ԭ\S r-{"Z.]ۯ %uC\w2{Be^~wa;[PDE6%`i\sn)ܶr? +x|_|oUp_K-*<~ w?7_J3. v-_yy] 2F} @#F// 0(TuǞy'N)-" D.mi' 7Sl-K2W^Ҝ9+?cM|iF6G3Neg`߳ck$4(0뛯` 1GXvnOflPso&<3\wmXc-.)Bat/!\t"|?lnrl-ZЕUK7v~1%.6fJB"\yֹtn-]exyȗ%ocT~ƚy5!&|[o3ŋozJb<-GXx̚6ZƝۣg/0ᣬml&LwuOuw_ʜn)num={m-]ܹûOmeGF!~cR`i>_[qcO{ss2zpa^={tn_cS!]GbʐM:[xcsC#pER'`ޕp3 +z){g{ #_^Z3̴䣇b`r;bfjbܷv{?<}%fw/Y"ضYX*0vp-;2wEs- W + +2Soˆ|Qﵫ65bVai΢ m@> Ξ1~<ҋ`zwS*; +DDFE%K?qL*;{K+sO<2-GA/?6{^ +jc qQUhw>)cv͑Q{%]Xw+eP.6|<{:4P>j>rxTo+ ޖ4*a)qFEnvvv',/*j.UB-+r{_h*txygE$yo\ + va-/-.]';v;ڍOL)vk2c춶tuDP0r +u3Ǘmm%/Zj '#51^m:w54Rfםw幋v+..kHW yv=+G>ΰv/K[3ؽ /حv]wev ;iШ`jVn{`P$ufjUf]BWG*v>F\sg xIΌn,؍/۵v124P/6R&D"bPz +"Ht"W9gݳgW0lܜ?5'{𜹕w@HDlbjfnaIeMCKG3%. |N\1y V59z)Ë w- 5%!NV Oj)Sv9AvQvD$PvM,mܽcR3TT74wvG^M .:l.#.[X=W(ᥰn_w{sCuEIԄ`ow'K3S]9i 1!]n:.ObW+%tXSG/8,:^ƃ]}l46]2߷ܷՠ;_eMO/:쾚#<2%Dy9Z[hV +|dv¢⒲N1x;QwSsʪ:{I㯦x3'SvYk|&}:k|LsSGICmMuUeE9)w`}4Te%Edv9W.wݯMpמ}2 +*z.\jrf`hd\RZVޣǵ=C xAe?@.\i- +/ 0w߀;4XQ^VZR\dh.W/_0: #o.m]^.DwnÖ_8pΞdep;"6153oMC ]\e/&j>c[ewqq4ԀLMlguSǏ9p`wǶ_w`wG B}մtO[8{ŀ /f@(g+vYgc]Pf@AvAer7&,𤮖wn˃۴gB"bRrJ5u L`!$`xi%if.(%e^XV>YRx$w`hVM|<0w.]u]n>¢2 Jsu}s{WyxQi~G;ıvn:..fn^V5ur󰨬p;LoMq{Lfw;C=uUeEsS2{;ZV./7PdK2 ^9eT,\oF'+,i eKGٝnCMeia^ f2+./8~<_ x9@Bv@WVQUH1f;g{`x˫Ꚑ;6zjzfvE2ı.@w5ٙדcvm*q/!&<$(1Pf UEY$wE"~"v.miqtu'*>9 ;äQ:k^ /_8VpHg̣a%GݹhcQfaAD"av/";0|5{OU6v?yΚh^hfwɘ'=HٍbE2@yXW4bpxUhkx/=6yS3dxfwdtg^O~/16240f}]#*pv>av1w3^A=K)jh?Efo;QqIhV2]dYcf]WWW:Z;; FzHu^a0ͮK$y)~8g{ w~ L޾ѱ 2eƻn!x@[LwBc1vScƒ^2wn޸vE^F9"K3w +:ϿH^VRU`f7oT9yۻzF$"'/rtwxҥ.NIѡzE'"؍YC]U鲬/?t攨w2*ͻ+KҌ֬ ZO@hdlRjFNA1Ҏ&ISs 5wܗrn37hk+Ņ)0߃ooit r2Rb#C| ]xi-`s<[M:ѝ' vw6Ubs3ӓÃ\m,^jh? ],ݚ=|Ē9ycR0YyX\EU]S[gw$ef{^8x?&HkFo1e}n~29162TWUeaRbcٓ1OW7ffyКo|gM^wHT"_onz %Sf!+^侠ݍ, }\_]+ƠQ!>5~y&h,,o}~ ^ 5K*\UQ&4y]<|BbR_e~S?4J O3ɋE]ttѡ憚7 _&FzCcWj*Wd%YDб5j' ,%1ym\=_E%eU4a$"ܗtK]`ʲ6cWN՘ 'X+I{`k>wQBZ=yX8yG'e-ށa45=H]^YmA"ǏKwg]mme07=E"z-nanfZr|txsؕx| حYXL2 +T/8<&>%=3[Z^U 'MxW9nr栻 +ӝ"Ct;ZKy)1~nN&zOcWAFb|Asce@k'{jZ9DИ<,mj!OBxu&ǟ ֌Eώ.d&m]NF{;[]6/ N@E;YiǮEnwrѝtڛ߼.~`mnlஆ ]A?jv[3{&v/,l\=_E%f5 oO(w//r|y<ŦƦKtj݂Ԥ6/>yx_+_)=1.[3sWRFʵ7ok>z/(,:.9-#%g [^ŠK]&`ʲœ ?/7G[ gOi޾yIx슱.1)v9L53'^)Y*j^m=CSK['7o\ocKg`@$MM-,RWh xۥ.mme07=E"z-0`?o7'[KSC=mUY)"̱ 3t?5{ +< &%)J*jodje--klxYxW^:69tt*8XWU^LOIvw25~|-5rR=}RTX=v( + +& rJwhY;{DИ<,mjdᅗ՚w'].3S M.A'"B}<̌uPWURp]Qct[3+(,&~a.D4&;WQ]7826>Ixu&} E"gǓ.EߤK.er|ldWA'"C|=\͍ taו%.?{F\I=]垼O+$"&_'lM]lV^DQ^H u)қ"E HQ:nvYM9Pt1yr|")sʪZFfVN8/yE m;=3x7ё.7s3ӀP[YZT}?59.*< doefxNV +#"r132@o?Hރ0yi'(AF8o䴌yemݽCS*w]]^\tG{;ۚk+ˊ d%G{͍5 ]9,FT0v~mnK&/  )(\606qpqNqqYU]cK;;04:]x ɋEltCn{Kc]UYG9iw#B]l̍ 5()a%D].v&.t$y)iG2s?y_HLBiXt p^& ; Σx}70B)ynBLĭ@6&:._<VZBL\LGh);H&/ +I xu M,lozގIx?yZ^]eī׳oVVwEGۢqՕ_M |T_]IC@71vhM[ C]إ%U.j&qĩ32.]QkhjiT$" E= E<ɱAHЭ(tSc#C|=]m-M u]tA^FR\X̩8X7RyO?!x)^z +".%ջaje[PTRQ𬵣opxW޿Ff/:)]hOݵe@wh}PSQRTdgezC++%.ecfdt]J>Rj{HɞSTVU32wyE%އxK+޶]=C#3soxǻA(^tdtż]7s3ӓ#C=]RH~jr\TXHOK]UYFD= b +\̀.žݑ?$/ / ;(+ǫodnm xU66#xGǧ ޅյ?wEm+vs}muyqҝE67V=tCqFxrX.; ..bc./IRR2sq)(\606vpv[wvl]ol]ڤ;Vf݉ vwv676ָ ?DKMIt!Q&Vv'^1 O;i9?-klGC#};0nKc]UǏr2$D +qwq06фtJK's2=Iw.=DKEMKwx9 ^a1I/^chba{'현2s꺦/&^ G/:ݏ,-}jblxj@7?'݄۷}<\oZh^|YiI1aHRSc~/%Kef8vaqIyWoPĻYTT7vD:{/:rn tE"A@IìC|=]m-M u2gN8ʌХt)ɻWJ*/#3WD\JF¥+jnZ9yF&g5ޞɽ揨]t2Rt'Fzg5nAnVzJRldh jW.]A132 ti(Fwbx)(~ = r|")sʪZz7̬ܼ"RgV42YCMEiQAnԤȰ`?/7';+zZʊd0"|.'{.B?SP| 8@H^OP%72wyG%yE m;=3x7ё˶.7s3ӀP[YZT&E{͌ tQA>^nN6]:.vt'ǻ)(\76vpyG'e<+,.mlnxWQtNvw57V=HK9;Xkk\UQRJ +C,LD$t$ݧcL8?< Ȳ,"(Hwtwwww7twH8(4ά3u>x]Y~ ׼~vxih^vN.n^qio`hT\rzVnAqyemckGO?EPC*Lwfrt6Vf'Ez[itEx8]Z@b7@w^R2r +J*jWPDBZ^QIYEMK7(,*>9#;୪klx1XG{t X XWeg$Gz8Xi(+)KK2Td$]⃣g{'(*!7qp +OxK8]:3t8ݿ f0st 0^!QIX:yG$fm]~xWW.FH٩!@--LMrs01QW{뺂LL4 x _Bx_|_HLRhZ:yD$>z4on}vQhGؾtO[k";=16:4𲷫G1!nN:ݾqUVRL gg.z5n.c3ۅ~X|?Ct[j*ʊݴȐow';+SC]0BKN@hCIx,/ܵw?52wv KJ}ZTVYwyemŋvݍeW}- eEOsҒ"C|ܝ̌t5޿s󚜔/HKJ@݉n/ -= ;'74WK704*.9=+ŌOxW^dxю}"c]Lcܬ丨@_{k3#=-/7'; =- KCK0yx$dT^V^A iyE%e5-=cskOߠ<`! K(^{t X XWeg$Gz8Xi(+)KKBt()HI{]=e`bpOPTBƫola>+y^Uد˧>3&Du btww7xDA@)9t! uwef_-"W7Ax! %Xh.QѝݦrBOI p23TSl(]&ͥ&_^0y!`8Axp0^u-=#skȸ|FVn~mm$Bx'9+r5cx=j]/yН;[ݚ +BQ~nV>%).24HOK+/- _6.-^::jxQ|G:+?;Z6~AQqɏ@xK淭]=C'>xbs邋t?M|jo} CtnCme낼gn|TX=0LBN #@xY^'N J(\|{:&n^R`eo˻+xgWڠ֠ +޵e0ݴ^n&:޺vG]V.j;6O?΅=U10ur i拗%eU0^R$3k[Ã}$ncmUYIOS$Ąvs45P螓CrݽuRM^ +](^}//WPDLJ+ojZ9{܏I|if[^U򾭳?826>95=KZ]K'uwoi*ts2>~q?PWC+JBty8}{! (]4t7.?xxNSxU4u̬=|C"bӟ*"W5x3"w Ë]B.3D@MS]u9Ut؈@g{+3#]M5@WQNJ\Dc]6@G7W37'.-|CEMK70426) VTRe.zDMݡ^bg;[_]fSb#C}=\͌Tn(+)IlL b:tċN^ﯿ~wB8 i޼glnIFVn~1mk{wx ] /ֺ&]`yНtz]ok*YO%Ez8Xi߹yyyi SǏAtۯ(]dn VQeFrxE%dP6~AaQqov^~qieMC38 (/jZ_Q7E~8 +@tj*K丨 ?OW c}m(JLEnMN*<…nݽm`ba,;uiemC]=}陹y /s3ၾj+K_e?KKM ru01оwֵd$E]~Nv +]F*;X=ia1IYpxtƒԴ/ ^U6=}Y^uk tg}=݀nKcmU낗/2R$D{9Zh te%ńN8zeYMwK5y)xwxw3ݷ =w۪:vNc>~ +Um$$k#t'!6@}aBLow';KSC ׯ\<'+%&߷y7#Jw MKw;-=^.NCjY9D$s^W5yM%/»'Nwyy`?ƺW9Ęwg;+3C]Mrq tݾE/=xoiY;{D&"Byu}HP]ٯoP?m.'Ȑ@g{+3#=M5J.ebߪt &/L^>N\Zƫgdn/"T^;G^x|ERf /?5].L@w<N@t{nM(?7+?'tx+(k ՎRPޛCgJzQ0Hf5Y3gp`XuBrz:Xhtİ]n@a0va?ފt!W3ˈpp?'StMYUC K[Lx[;#c^](^Mi=]p1@.Bwzr|l8!'E=q:.)IcxO taKG xi)2b8aB"0^M]C3K['>(,*}WPBk$$Bxgf?SE'/&m쮥yyiq~v;J$m"<t‚^8'[K3C]MLJ@AKŻs=^&/3sY~! iߺgdfi-x[_}׳wn(^Mmҝ[V@dgify%DϞ>2Ctݹ~>#̬^Q ]+;g7o{iO(,-kML~BmzK`?Lų'ibƒݜiAtd$DGAtmw{ Qpm5-}.1 )2<x+Ztt 01qfn +W/ڿݯTtf>NM|x?<񦵩}$AJBLD]c}-7\Pr@tn!xwŻex9M +z5] +NO}ݖ*Bq~^9Z"tE.#]U4[zxxY1</o52sy¢2[^}7H/x6]߽}XWE()y9Yj޹uyyi !~@J@Av]wzLfVvN JȐjY9yGKNxEAIyu]S+78L;"ŋ/ۀ.2v9@ų'iÃݜ̌Hte$DϞ>|eZOw疧K1yxw!x128xQpm5-=V1Rdoǻ~mot& =:B@7Aʽ`owg{zZjo\ #)* :xq=Bw-jjIxعx󪩾nBLD63'qc={,l$XW՛*&.>! YoQYEMC3h;K {@>QBAw;2 mn(+tSb#C|<\M Un^bIt9X{l? Q+jX8zF%?/*x;z $ŋCQ҅t]Zt'!]nmeYQ~nĸ_WG  V = .Lۋ.5^::jxxRrJ)jZ:t NOaݞ֦ܬĘ`o7'[K ] A^.΋8Xh]t0]ɋ{KNAIE}$ '(*!s*:vN!i꺦6w`/xѾ8bݶr@7qZblDHʃH +t 4'OPSQR#t%9x=v+|B8fVv>Im/_ co/.-olEZ졻8$3QqI9oEM}s{w;9]!R" +Lwf; +jots2ӓB}<̌4Uݾ! 0#t'L^/N^~!1)o`XT|rzӼҊopxt»oËQhDH w@ws} ]莏- 5EyO3ӓ}=\͍`RbB<]v@)0vaӏB/r5T^&._vjZ6~Aa)@x+kW}#cS3s#xE.?@.B»W݀nm%Dɣ ?OWsc}-ܼ&%&s,L]*.풑 tx xe`b +KxյM,l]ãgeU8S啵ͭ߈mOtX[YNMv6V?tÃ\m,La0]V&<] +HxK x9]WPTV10utIHȂ=C]x?xѾ>t?]ݥt`Y 1^n&:ʊ +r"\qt]t tKCKhZ:yD&fdW5vxӳs8(^oU8sXngkS]uyIAnvFjblD +DWFBD@GKѥQL^<#^r/#3OPTBT4t MݽB"cgMm=17oW׉xLwدϧ].3Sa@--JK vw45PSUQV13t)LtE&/_~=p5A i>xkhfeҊ7cYw +xшD.ug{s]tg0cÃozڛk*J^<lgef[%D]t{_~FcK˂AY;{F%e5 -} wg/W3/va?-ݾb@7=).*4H+#!eA%ߧ{{// ;/$*)pOͭ\<|âӳs_U6tt}?261=]]Bt6V! c#uw4VNO + pq67z +2B.; .$I Xٹ.^/$&) 76qp +O-xEE.2vu8X[UAnvFJ|tX6LWVRL\L ]t$]ɋ{KIu^,^a1)Yśw?R7qt NH|V5vC#ޥ/ݕ%XW=LIru0VtMEY)1a,]3hNQQ"tO%!xxxY9yxť`:&n^1 oaIyU]S[gəVon»=}wꗕf&G t5U 1^n&:0]9)qa>^nVf.-!]2^Ff6chjiV7uBx13Xkxxw o퟉.5,I DJMvs45PSUQVtE`ľ]jJA(ޟ^0y!`x9!"XVv!IiY9/J+QwxƋQG8|],?~t77eftxmo(-zlgej+/-."tρ?>]B xY8/\rMPDBZkY;{F%?}ix ML/~Z>o{d;L\ߠoy>@izR\dhwo]vN6. .%''y8'R2c +J(`j[ۻxE%/*kZ:aӳ յ}*DwavP[YVM + p67Uegaѥ£{{d{0^:/uU~!QI=|oln}?2w}(#]ߧ;>m?ۈ`mn7d$E^2@t=Nty&V"W][/(<:!%#;몺֎,鹅ťW/~@+LweiqanzK쌔 ?OW c}muBYGoDRBxOxY9 bR7m`ba,mj74:>93ʗM{(ޣw{t7W,}0739>: -){hkabRb]Vf@i.%B$] ^ +Sx4t L-mܼC"bS3s Kʫ:{^ E"tw5] ;T_]^Rdkij*I pX.AdGW3%5 +".-khji_T +6uãybxqWjhOKftjktKsc#Cݝ,M u5TUE`ľ0]jJp1=D"_m\σ{EL.QCEEEAcݝINQ;DJΜqFg-p<~ 59{"%OHTRVN^AIUS +MH+,.kjx޵ͭm`;..cÃ}=MuUŅy9 ؈ow'7;+3D(]d]#xIxPBb(^-=#skO@h$6/*.ojs K^Moīq1ÍE.-#ζ|@767B tPxtIv!{KKCr Iݹs5-}cs{gШĴ̗E%m?O@xW6x _X[YL |\_]QR23-16*4X_KGH p,t48dxtݟۋLECr-Naqo`XT\RZf7%5 ]wE'//v]tݩ!@̴@_O c}muXi.{#0x49Ź L0^^q?SV60up +K~V4CE"^.CtG{ݖR@7Er\tXJt . ?MF=.A{t?3^Zzo@jZ:zG +ޖV6;04:1=xF?~Cwkc}uOSC޵4V-xGy:Zh t%Dyn߼~{f?ݣFxOBR2 x^{(hZ9yGħgeUщi +ޯ_e~ţӝv6V)1^nv*Oޓt (S' xxKyer JxU5u ͬ0Nn!؄Ⲫ&o`x »o]D>|]kDwlxm*+.IOIF{9a u5Ua|]f@ +%0KB^/9OHTRVN^AIUSML̀W=}#cӳs K(^Dtż}(ݥɱN@ qwXi*)J +qs23СtaKBBtqxx%ᥡc Ixմͭ=|C#cޗE%m'[k+ݙqn[s}uEIQK@7624XOK +%&e%ã{{^^*ڍ[}_w"]_]8@Z@ 7Er|txJrAti (]!QIY9y%UM]#3+w@H6!5#'opxl]x7]"C߁t5@wНhm*/.HMFx;ǎt5Ud%E9X!ϟE"cH%GҡxPZzFgwHl"_T\^] xgǻ߈Wa 7vwo07 @t;ۚˋDldh3HO +&ďҥC%٥{{// # /,&uմm=|Cb2_TT7u?82>9]^/չq|ý"1FEQz(***(e,."]z_z mEP:fLsWԙpG24YwGkS]uyI쌔ksc=;_ #)*rs2Ғ݋݌/V/#37/,oln $fdW[;{^wE&/w׶ ]d0ݩي./-HM`=]l̍10]YI1!~>^n6fF@~+]*.(C?|(WXLJVQYEUMoba &e56o0 +[@}Dw0k*ݜ̴X\h D(+%&L =z0=AZ> +?]2{(q8u最W70,26 }TAWs oW6M}q ݍŷ s^NM?lknx\M rs41ЁI ;s' L%=(vĻ+*]zC]S7(,*.)=+୬mhnNL.@}t?]"ҝv77VYIqQaAnN:7^RtE`,L4Q; _^0y!`;rAxEĥxt Mݽ£ӳU6cyweu//jFBvt]_]t!cÃnKcmeYq ?owg;+SC]-"]yiqA.{D Jw⥦Ffu"._y[Kpxt|ʽު:io7^}O>yQtvo_NO >t Gp23պ} "Ϟ>ΊХ#%~(m۴KĻ /- /3+HDt;>9]\ZY[/:ywAtX_[YZLt;ZK + !>.FzD +2BD$dt"tF~9^x!/7/+o76vp $fd=^ 6.oŻچߛt7^<tt3Rbp!>.wn]rQAFRTeoKݶ/==̆Uj`-l\=ԌҊz|k'w׵#w0݅ٙQ"V|}MEia^NFjb,.4`caр*J!t٘Btt(C@xxY8!bR*j [G7/l`hdlRZfN^ۀoy7Hzjn*ޏ(Ot?R]]^|0(ayOg-LK z9Z`4TUeĄ l,]> +]>9!"^&ĩ3ť^uMSK['7oߠȸGE+kۺ$KwwDIBw]"tt57V>.zdkij*I ;sD{9=(/ix3xEĥ.]khji_ 66c%]Qot!Нtۛܬ丨 ?ow';KSC]MW/)ItYtЀmm_E$/\v󶖮]{U6w=xޕw.w-]` +;N >joi*+p^r|Tx]wg;+3C]7] /-!"x\c+B(ݯG>y!dx^Q ];ξ%~Ij~t1C.LY@wTWUVRGGp63CH"tYtdt7ݱ%KK J(\rm=csk%uM^ O@xVP/][YZL xTW]^R0;#%!&"XOέW.*H +$dtt!rT[ l<|Bb0^'6 WXZ^]ox #S0e(m"c]NݞV|}uyia^vFjb .$`cnJ ps132[RtOx!xih>rI+,&%7qtb2sފz|7@-xwO_0% m +@7'3-1ru0h(+J~8> p/E XUQiKtK/ҕ^""Ig6,,]@I 3a枧 +;yy~$`ݽ{v0bG\xi2#x9xE%zFx[GWOЈD7IiE E{gO<<619=3;*wNwuٙɉa2EkIA.h75C*IK + +rq t`t⥣gDqp#xq'04261-#-!4Ax$w +Eb}iTtW(tG$"DPSYfg%Fx:͌55T]B HO'mw' &/L}^>NZ^ƫolfe !@xޅwo#x׮f .do@w +;@tj+ˊ d%Ez9Ytqb]>@>0vamKK^/p2'ϜtUG-!Uﳗ]C#oޢxn6E龝z3>24[Uѽ79.*, }Ο9,/;~A>nN.Lvii1_G0xsx%eT` nXXt|'*}_T򴪮;84 +᝝[Xz+^lnt]~07 D4U=-)G ~u8L}.(1_%m@xY^CGK*:{&7=nGǧgx^w};-&tHw#ݾׯ0`7-L _|)YIqcG]tat »w?+;WJVWK?$<&!%=+ҊV/ipxt|rûE,AL񣜬oKC]- EY).;]o*;P{^.^.^52utILS7>o#&&gfbxFtW.LON I}=[k݂{1!ޞFZW.;}BQNJB ѥG|eB¢rJ'04"615#;IYe K\;.xW0[)j+(e@wn.}D,{Rd73tU%D]6.3K)]WjgD`FT54vNn^aIiyo-!G6ûv5bv(Bv7;B ẗ́Z@0/;#-)62,of$/Crs@2҃mޟ~ep2'ϜtUGoPXd\ ++k^vt)wa{`ûڔ.~; {:^57V=7).2,KϜT?z Dw/?E.F[^Z +L(^N-;Qqo~QqyU]C3o?;f-x?M?{obsm~]۩7n?DYKC]UyqQ>u' $JDA#1On˰UP9uk L,n 0iU]c˳W{F!s K-_]Z v~iIQ;~o:X[\vS* +".?'] +1%mYٹx9&".%54qpNHIyiu}csp;û%ڄ.:vy`iG9) .6&]EY)qcGptY6݆~»Kϰe^^.^54qt IHVT7}$4wwt'!N@ͺhciju'$`ݽ{v0bGPeFrp + + JH)!xL񶎮>1onҊBSΞ>yxlbrzfv~qiyU : tgg''ƆɤM'nbLDh-H$'-!*,$(ŁeK>jzfx['W/Ĵl%#09 ++TxiTtW(tG$"DPSYfg%Fx:͌55T]B HO ޝ/^0yx b8iyeo`Xد*>㳫? +t(yINQ;DJeYg 9zf7\Ĕ켂zw`; .>cn^(^ .d Btz;₼̔Ȑow'{k3#]MUE /;.L_#(ݽk'^""jxIԴ L,>AQI)i9EU-=#skgȸToI78<615=;> ɋ%v"tg&Ɔ;;݊njR\dh K +Ӆ]""e{/&^Jj:/'7WIMK704 +}_XZQЌ;26 ]X\^][nsCMEia~@7*4X_KM +& ӥܤKCBgx /KW8ĮݼsoPXT|rm ?Q.tܢEͫv@hcaĄ9ٮ\Ctv=ݳq4^~aq_Pxt|rzֳEe -0ޡɩ9,(^t?`LM t[j+ˊ?JOtu01VW ti(ϞG[?=%<RCxٹxůߺ@^YC_pxL\uWow3sV~ERt]YZx?7Po*@77+qBLx#;KS ewo]bPNBtvmx|({Kx*;+khje4EqyU]cKw`"%~AtݗuU/rf$D{9Yj("\W/_<RtOG{}/a񞣠 +Hܸ}OVAUS; $"61%#;୮kx{G'vûy5EFt!Нtݼ쌔؈ow'{+3C]MU{oHbti(a#3Jw/2y!/3 +OPTRJZFNQUS' $26)53;o`x xW?(^lWe@whm./)LM qw63TUp031@to]EOKKBi[;8{F9%5mAwjzvx76'_Lm_m ҝt!m5%9n\dhBWK%šKEg-C8xI6RR1lBbn޹PIM[70,*.9IN~aiEMCs۫7=}#cޅU/A7tW c#}=o^57TtcƒYh`r_|<=  |Pw%>ॠ7nߓUP54srILx˫Z!C0E_W/8taC֦b@7#%1&"PWSEA.K{(JjG^0y!`92@x900^EUM]#3k{'wĔ켂zw`; .>cn^(.].L'@wmeНvwyٙ)!NfF0]QA^ D=w]GPE;!W3K०e`bfa JJI)j[;8{F%BxK*޶᱉y/nN^j']p1o@.Bw~vzjblx Э(&Ex8;Xi*HKI +a8XYh0]%"BmمK'$UR76qp xV44cMBxW?E'i{~Kدϧ&=c"қb;"{͈HQPJhQBQ@鰳ά3~ + Lv<߿f!c#Cݦʲnr\TX>LWUQVJõB6fOxY!"RrZqx+;oPXt|r1Kx;{ȫxgW~2 ~^;J`9Č _O][KSCUQNJ\Qa!@˺V.^6v.^W'zG'dsjaѱ)2_w.#t&F(0ZRyi\bFJBtx+3Ѕ)Ity8 1 h (^&}/7WTBZ^IKWu Ḽny$f+xj^w)ãoML}K~;?;qja +u[sCm[{'35!&<햃KϨ)KKBtx}{!L(4t1?5[Żx>vRTBF^Yչahba}agUu -/3 Q]tgV/[*=)xx/;351&",/#!zჀ.'Lw[[0t;x̴ {+)~eF67ܽB"cӲ=*x7]bv5]t vuՀn{Yi!N7m,Ln\pV]YAFy \]F^tBx^CGUP9}kzF7}B#cn߽-:GIwn~qi2 Ks$;2Eu󧅏߽|HڕN(J:~ DwE.FQO^v*,(^"'04*.)/zES+w? V&L.W'E~|?@t[^T>Z'Ex8;YteP<(]*Wnҩon˼_STҾo#xE'sU7w Axg0 tf!c#C}=M5e%ErQa.;+um-M UE9)q@Wk.3m]Gwz/;/"rJ^ʞA{\\RFonxCY^]tѡ2\_K*+)~CH t%[q]%9iqGy8]tbt&;PL̻YXc +x%ΜtUgnm/8<:!%N.[ZNmxzݩ .6ԒK;) ~^qW/?$/-ʲ .f>BwWc'E%d&6ܼ#bRއOJ˫_%SG߾8=;W /=ZuݥSގSȽ]_67U>)x&D{r171D*HnN.]Ʒ_^0y!`? +Bx$eT`zF7ݽB"cҲ?*|?x?B\ޟ5].L?9@w;辨x쬴Ȑow盶Fz0]I1 {`?0ݾ^/#OI*>w5=#3K[Ggȸw!+W}#oO~@B'ɋ .Oз0~@_wǫV@9D@gG[K3#kW.; +)vC|<(].nߎehvaۨ2K*xͬ]<|âE%e5Mޡ14x[ciqanf;62m,+)&Ez8YtUea<\+tnCn2$j[erBGOK)jhji_.Aa/ mk!]K6y*]rOg{K3Â|=]vVxum-M UE9)qG].z[1 xwCx9xQrJj^]ڞA{\\ZNoRF'^]ݩ! +LT^Z8/J t!jJr(]^.v6nM4xwx {ܼ^Q iy%3c>0Ob^ (c,(ޱ{{G@@){(H=* $0sg#df{ed5t L-ܼC"bS3s꺦֎᱉ٹť5<(ޣj6ݵŅ鉱֦j@773=%16"@GCY^VF7D=wK=G=K/KxYX8Ĥ^9 ]CS+;gwԌ܂NwDnx6|[M@wy.lk()HM qw25PQtĄ9XY]J.K.J; j&>{_XLr +fV>qIyoM}3ۏ<ռ=pBv;96tkݼԤ@g{+3C]MUJ `QS^=M .f˯ ^# ,~'U5̬]<|C^|WXZQw32k]w ]`*;莏`zߵ57Tez".*4HOSUٓn p޼~2#D¯Ŏ] wBx q"xi"^5-=cskOߠx7';| _v&_|^/𷋥i ;moi,-t‚|=]͍"].)]¯tD~=d/ =+("qϕԴ-l\=£^U6704:>]Z^]GyCw}uy ;5>:4}{KcmeYQ~ ?OW c}m5Oݿ-!"2P%{{{b?^r"-=ӕk7عExյM,lݼc2߼-*klxF'xW^dx"c]ҝt;Zʊ޾LKN rs0VWbq +=-E@|?(xxO!xIΐ=w#-#+c`biW5=}޹.Atzݦb@7=%1&"@G]Y^VF7L{Yr3$SxtQ߻]xɰxiYX8İxU4t M-ܽB"bެ܂ή᱉ٹť}xQ.}t7Vf'Ɔ{:[ˋ r؈ow';KSC ,]1!~n6VfZj,]2|(c7FRRaRwvV* +rܕtyt)Pǹ %/,UT52w KJ}WXRQvcF X;W3P¥ م; +CtG0݀nCMEIa^Ԥ@g{k3#]MUE0?'Dнt]=KH\/)79yo{䙢o`XTJ]wO^;yQ~b}Og&Gzߵݗ/}=]͍T=yxW/3 tIaKH=} =d/ =W@Dƫoln /*ml.-olݱoKݩQ,ݖʲ׀ntXLWBD KOCCI(c.Cx)^+ns +Hܾs%um}c GW/4oCW+_=W+_}xVtӒÃ\m,Օ?}t /kW] +.~'PǴ{{"-OPT+m`bamqyU]c+wxtbjfn3&X s3S0ƺo2ӓb"m-L Օ!|]Z*!gP~{ +K ={०erp JޑW10srMLIxZ;z&gVnxYt训,-.NO tu6U)!nNv:2w$E9 Ԁ]b)<.^x^2/%/$&)hZ9D&fdTT7u&w {Bn;t1ng[S}uEIAnVFjbldH+%& Rt]t PǶoW3i,KtXǼ߯ѝuFLѡ|w'TW f%Gz9Zh(+ܾqUZ\De=O>f.^tBx9F eeȍWT14sr +OI-(*-oj}كxޅU`#]`wueyqНt=ZK +rSÂܝ,M u4Tde$Dq99Y!ǎB"cK +O^/^J/OPūkhfeV7Ax/|x35lg].Bwfjb5T ~vVf(]QA>.J._1Ļ//3'$*y;T5̬=#bR3ihn{opx ;;ݥY`_Om 5/ e&D{{8[i޻seIQ!>.@@.IDwVT :Ffgs !xմ̭\<D&f]m,L.;s{p;]]xG3!xqu L,lE%e˫Z!QOMJ~";Ct[ʟYiqQam-L tԕn߸* L(0xxK}erD$`*:vNn^AaiٹE˫ގnw +]X\xK1?1].L?@w +;t˟f%Gz9Yht%Dp]V@$50 KzmKF~/%"7NPDBFVN^QEC/(<:!%[ZABwxbxtǼ]@_Ogǫ6@lgej(/'+#!"Āҥg Krm؅!KAK jY;{x +_T44#x s K+oËMls~I奅Y BEqa#@7&!Qn޹gdfm?$"&15[ ~ջw~_nmНߠu;[ HMbomfzk%ExΟ=@tݍ% :F/WIMKA@HdlbjfΓ%e -0i**U`?L铜Ȑ.zZjJ])1!~.#͉]mxx!,KbRWߺola03'୪mli󮻷h鏳cxM.~~dݛ*@7?'aR\dh[ׯH ^0GCtQ{Jxw}w{K :s%^aqiWAY]o`hT\RZg˫[_x9w m ݗuUϟ?JK + hkabJ ^p)@{%]]+xL{ z㶂oPXT|rZVn[]vvFwK1ߎ.dwCN@-JK + rs41PV}㪴DO{|]o:ry'("!#+'chji[PTZ^]?0 N +.ڑ.NΎWME)aA~^Nv:*r2"8]cGt%'//%'(54sv Nx +J+j } >k0vೋНt m5EynBtxدϧ4å·]AqErRE9#***"9s9g$K9*D%ԌcXsOtp]qa.B.ݣ(C^xx)px^.^qi9yEeum [GW/𘄔܂꺦Ξy&+ၾζܬ`?/WG[ mueEy9iq^.@G.)Jd?^*WPDƫc`biWXZ^] bƧfak/2yQEE.ӝ]m奅yY1nN&:0] A^.Nv6fF:j@j?]^rSTgΞ` Jܺొw@HDlbڳlL@xQѝ 5n؈ow';KSC ޒe;{9B8]al1Ba,/_'$* 54sv Mx_ihizvp31=򧕵}xxn}t77V>-/7;=|UK@7)624PW+)*},0ӄtty{$ ޾PIUS'04*.)=3୬mhMLaJ+_bMOAt;Zj+ݜ@g{+3#=MUn0]&zZI(]b?`Bx=e Iai[;xE'g/.mlxF&!K0^׌%.dKݭu@w ;9626VLO + pq67Rҕ΃?txȐD20^r;=Q76qp +Oy[U[ /Żt:ݏKf&GuUOSÂ<]l̍Ԟ<禔0?ύkW.21 t)tg KD%KK+ ,.ūobaW5uxf!+[ۿE'v^mom@tg`mMu%nBtx:/.3.]RQ.d?^*/ + ".-'c`ba[ cvݵၾ^@K7+#5!&"@G]YQA^NZ\D ХRK%~5 #WPDB«c`jiWXZQSօ;15; Aߥ0?;5\_SQZdkijѕD2PBqGGCxϜxY |2>xkhje,;mhn};8}~qo(v~#iy ޮ@(/YZRldHwoH +qCtYݳg tQ]=x/^zOHTRUR52w KJyY5;û +n#xxGH+Bw]t_w4V*zloefJ +q_z"K{=1.Qk&? @K}o`XT\rzfN~1MN5CBӅ@wnzrldhits2ӓ}=\͌T޻-+)&e=I>f.1w^dBx^KWy'jZz.AaQO/.ml~?4:69.[۟]/Av?oomKPڪϟ&Gz8Xi=ytM)1a~׮\bEkKˀGjGǧ%eUuM=qwG/~M޿Яjc 7v`.L҇@wTWUVRGy:Xk#tŅ ]Jx꼍좸[P`]נSQnVF@@ FAC@uYf/#wݳ3xu}U5̬]<|C2ʚo/?]q}nKCMe)bomfݛrR0]VӧhNRRt%KF+ ".U36vp +xsJ+k[ڻ{qəťxww[Ks3x`_Ow{KcmeiQ~`mnЕ`eb@R%#n&'Pt ^AWֽG +Jj6~A)YoYUmckw?>]!MvoDDw +Lwj? hm*tSÃ<]l̍Քݻ% +"tP'(bC y '("!UV7ut IHI[P\VUBx޵M?_3f҅t\_t ÃnS]UYqA`?/WG[ }mue D =]D%'Gf +vҕk|2oLY]?8"&Koy5hdtbj'/txN^=H|_qvjbtd]'[]}"1&"@G]H +]r3#J + ]rr]Lg{/.^zF/,WEC; $"}WXRQ]܆.mlnFw~M͍eB05dgijӕ0ҥ${#w!#@xi^ I޸sM]CS+;gwؤ o n?1]ݣ Эf&F;Yj< YI1!~/]tb{{-=WXLJ«kdfemieMCs;?69=;Lmӓcxn{sCMe7ٙIqQ>VfF]9)1a.=3ݓ$"PS^&V/ͻ*j[;xE'ef -]=}8:ݧCDw}uyiq~nfrjoit3Ӓ}=\͍T>{SNJ\X>ѥ@#K=k^j/+ ".-*(i8zE'gU6ttûxW-6VFn+tڪ ?OWsc}-5%@W^Z\DХRǿKF|'"=RPR7qt NHI-x[~;س1Bwj|txmmt rSÃ\m,Օݻ%/-!"ef;=A>f]lv^tBx׳^ \~g&n^1 /^-(.kjx?4<:.k[]=.yks} ]t'F{u6Uz"!&<@[]H +]rD쯿E.."^rT(^F$WC?$"&+,.oj>!xewyckw~.BY@wT_]^\&D{9Zht%EP(]*{t$L_=Jr/=# ;/$&){΃'U4t MܽB"cS3^TT7u004261 ]^Y0޿ ѝ𾳭0uFjbldH'ܐtYwR=J9=GK~U~a1)O@hd\RjF%5 ]/ndl +sx]@w;96tڛj*J޾HM p23TEJ \|Ks]c(^ +ʓT4Nxťn}TQUS704*.9--ihxpx"y.74TiqQ.fFzO޽)'%.,e9}$%J]]/5W@D\glnV6w 3sK˫[`>ݝt6Wf&Ң@7>*,XOK +-."ĀХ&KF8 /3Wu_Pxt|Jz[VUƏOxWn"M@w;5v6VY)Ac.8Ϯ>YEQ *** +͡%EP;E)iQ֙e]׹#=skߏw] .= B i.ڡxO`Bx%x \~aq6,:>9-;k8;_3ŧ م~nѡn@ 7;-9>: hka pAt] +r0vaB%"BfKK΅SPV10urdžG'Cx˪ގށщE/tx'/AO|[E.LMvwuUepK +Ӆ.Jk{/^jZ/7WEC; 8<}WX\^UԊ;61 ]Z^]^{c{on./At'pt[ʋ 1Nv:*0] ^n.-]<'thxKx\+("qOU4u M}B"bS3`o}xWvs$B]+t޿ta1!>vV*O?{KBDƵ+̀.%Dl?(#O^DIM*jY;{D&f|URQ][|dg݅ɱn[S}uEɫ9!>VfF]IQA>.5奋ݳ(]ޓ^b / #OHTOṶ\<|C#㒞e5mzG'?|[v6ݣ}ҧ&G{u59ϒ"C}=\͍TuޝyPn~̇Нt[j݂ܬ0wĄ184T8gnjEC"ǟCxXXع02r +&n^ذ܂Ɩށ w]] 8C77Vy@wbth 7;=%>: hkab '+#-.,bgcea]E?y!DxxI^^pxtWXTVUxgfqxû3y%ycwgngGwq~vv6U nN:]^.-B.._QhKu*VvN1  +˫Z;޾.-<ޟ]_]^NO TWU^\<#5!&"8PWCwoIrs ;tI@ᅏ~d%Jj:+npp jY;{D&f|U\^] M%PE.;96<v5Wzloef+*qf:jK.~Qh{rI/1YR.Bxa<|B=|gdfm,-ox{G s ] %n泤Ȑ@_{k3#=MU'ݖ2Bt/^8OFz{].cᥡc|MN~!1^5-=cskOߠ8E뒊7zG'?|[6ݣҧ&G{޽ikn(yЍ tq67RyeF:sCC xhqx1ԝԴm\=¢ӲʚvwxGw;5>2moi,tҒ‚<]l̍Քݿ#bptigOt~!xO`Bx%x \~aq6,:>9-;k8;_3Aŧ م~nѡn@ 7;-9>: hka pAt] +r0vaBx%E3saťedu L,mܼ )޲*w`xtbjfv~ -Kxtv3S]nUD7=%!:dkib '+#-.,bgceaEtKDEAva'०e|:_8>"sEu EQQQQFSD@NESP]uf9_7 ?>\0^EUM=#3k{gwH7-3 ;26 ᝛_\^YOޭՕ9B 73 Ѝ qw63TU +rti(6=#\;Bx^F&fv.>AQ I)iYE5-=#skgȸdoӿwaCw6.llot+`ɉq>FzZjR|\,L .Dt'].Id(^n>!1o`XT\bJzV^aiEM}3whd|rjzvIw ;;=59>2m(-JOI + pq17RS qt)Οb_CAxOx) Bb>x,oba<%=୬ihn{?4:繅%<u!xucsP歏>O3AnkS]uyq~n&HWS+˅ҥB%ܤ+Fm{/^ +*ZOPTBRJZVQUK' 42619-3opdl;7|HDwrld 73-91624HOKUQVZJRBTeؠKC(Fk_%؉=OFAM'UR36qp KLN+(onxG /:y4]c]@莏 m5%yYɉqQ>.6zZjJ]!>nvf&FZj +.N] c(^"$Ϝx9n}XNIM[70,*y +[XZQvAxg Fwv;6T)}=]m,Ք?{KLK={4)Ib"1<]{)/%5Wr #xյ L,l]=¢Wٯ K+k߼az tW>Nx?>:MsCmeiWntX2BW)b=':%Ar=W10ur NHJx*k[ C0yU/95=];xН6Te$~N8> +aP XUQQTTTPz{((; +{I 3af\; 3?y>IqQ>VfF])1a.= S(]^B/1॥gr +`ĤddṶ\<|â2r꺦֎əťu<[G.-9=EnAIEu}S[';w@nt76!@ Efzr|tX+-`gctad.їttѾ_3I,sԴ X|"7nSPR7qt NHIxkn[GǼݩѡ^@LOIru0VWRw .-9,ݓcF}"/2x*7ĵw?TV60utIxYv^aiEMCsށ w][ =Bx ~.Cݯۚj*J =yhkab$D^x{_~Fb.J`N^/^R/_Hc`jiV6Cxw xy{uݏ>X@71&"@G+*ďХC%ء#J $xiY^N~aQ>xkhjeyN~QYemcK}c啵G + ѝ{(?Ȑow';+SC] G޺.)* 0l%{vpߋ=KECrNa1,^UM]C3+{gȸԧY/_U5vcX/2y}"c]ҝt;Zʊ^zloef+&,yFz.^Qh<^bS!L0^^o`hT\rZ[\^U @x8tʋ݌丨@_{k3#=MUEy9Y)1/L { 1B.j[{ //-=+; FWMK7(,*}[P\^]?82>937acޭÉwWf&G{:[ˋ r_QaA.zZjXA^.v6V&zZ,]2|PhxO"xix^)(i8zGǧg%mޡ) +MKEC*jY;{F%fd|U\^U +_t~',ɱnkc]UyYIqQ>VfF])1a.= S(]a?%DCx)(^Zz&/FLJFVN^QUK70,*>9-#+୮kj_\Z^]ûux£8?739>2TW fe%Gz8Xi*Hax L.%DKGvv/KxY9x1_PXt|rz܂Nwh +݃W ^5S"xO1#xqxiyE%5 O@(1&>9-3'୪mDmwk^=vV>M "tk̴bhACMEIQ^/C貳0BRmG3@xΜe)k L-m]<}CⲪƖ]=}#/>:vd@wdmKc]UYqa~NVzJ<hkij@TWU  ?e8~0J]rBx(ҡxYQb(^]CS+;GWOHR[PX\^] +x?"xcy _ky.B+y3mm./.,tHavV(]I1a.+J. +ݿ1XrkKrZFfV\E=JHx[𪤼=C#!SӳsNOAt? |xUAӌԄGQaA][jݽ}YIqaA>@y. }]-xޓlg/\BjY;yG&fd?񪤢 E5x7]@w;: 5Tz<;#516*ytXOޝ[7IIt9!';HCݿ.fmx!xY8Ox_HTBolas?$":}uiemCށO_&&M|[Xwi']ZGwaԷɉ/Fz;47V~ ЍvwocaЕ|iN6t`t=@MebaG^yE%5  gbL\rZ&[T@x`x<ލtRН At[ݲ"@73-9.`cab(,L(]Z]k`Bxe8rAxpx&' HON/,*kly7%k.K;iwic; !}]oZʊ +sҒIG[K&LW/r؅??]i=^**kxP\g +2 +הU5 vtoq9pd8+w~ax7 ..Ct? tumtˋ!) @_OWG;KSC5N.vV.L>TT]mi.w^e̬0^Aa1IYׇAaާJʫC#!S0^Xvk^-مNAt? !tK^>tE>t}`gefӕr2/ӥ7FkKĻw=^z/#}%>AaqI+o޾gdfe_Pxԣ o3sά][HM|큽7_t,7ѥ_Ow/Fk[ރ'P"Rr{zFNn^~ѱOx]ZQS x'AE.Bw6T~Bxݝ9]`wqaJŌ iTDQ H9g(QDE%3(&"ֶQ{REX|.󿿄`.(]M5e J.{1X5^ +,x^Ye#; $<&!53wxg_@xa:y / ]0v?g }1? m͍%9 1!DG[KsScC]M,+&,ȿJ.FkK/ˏUPk!xDwRDlb*9fs[WƟL}݊w+_N=t`_W[ͺrjbl)ǝHCjUd$%Ąq<.z]o ^&/3 +'7WƫgdbfaeGp $E&s /^w ݅.gnN5 30ݻC}]- siI@W"LWŒeڮeG +DSTUF;zF%_-xowCxG'_S}x7W݉Qnw{˭j@(BzR\dh=BW[]UQNaqB.Fk>(^>!nAQqYyEeW;FNLN-x,v[}}073591`d6{JYQ^Vzr\Th'J]!>~}]xx{ + +WRЁ88yE'gd5 oO0wzf7[mŻݿݷ0fa=nC [`PU ݟ0X;zeC + +:rLF^IMCĩ3l\{Gǧdd_zg`x;>|t*K si" +WAyy!]]L(^f/'+)kYX9z"cȹ/_7x>;wx_Jw +нwf]յ siI@_W';+ 3#=-uE9N2thbvv5tx0^>WQi9EUum}oPhd\R"B.lur70;tݢ IqAN]}muUE9飇]>.;.Fk/53GB*jh?y_PXT\rzV^Qٕn#xG'O/݊(BWʊғ‚<ݜϞ>y\_[CU +$w1X /2Jj:^g7/䌬boGwȃщm]t''F wwt2Âܜl :jJ2(DE.Fk7E9y!xPBWV18q9^)eWo4=09w]K9zTrL]*+";73 tjn\-+H:`s̩:j2ǎDQeBw/FkD/*^~Aa2^Sk_r JRIGwc_Qmm^*LI vwqjd!‚tY(2`tvUxxyx^1 I)Y-]V=%K{z[/ܵ>}0/c@O'[[ dg&Dx ƆZxY)I 1@XOC keG z"bS90{owm|?]}<L A + ]#=@Wt89XYQL4t1X;^:Z^O )261Smƻ]7opz/ՃG`Kt{;P9HRNNK>_QUkH+Q2ˤPXXXX8 "($$$$8`b@EDA3Af0d5kn]{}P9k[jRcRgWϾĝR/w7 ˘k)]i:=w$}{}}<]W祶@wl3c..3#W KL&5^[xRҥYWs x>{׿C;_eo~:_<{ʥ[\{5Ktc"ݺ}*Wg[+ DNa tDbnxUUjx'Lx $&3_daen xw O$x޻xv3իWNǷ\Ž,H.нN&DG t7oBt\,͟3DbtL@UUab#9xjjzF7m;wEF>^yz|ܽ tz{_BxLtdXHۀkW8YFzXݑp!.^> k +x/Ͼض3 ($<2:O,ۏ2T-O.Sd/~f݌ nltdxHPm_|F.K]S;ϧ"3d3qzF.V}xB#3eޚƦ֧ϞU_?w7|rrr߫>FF2{  +|Xht̝ejd7c;N+Fi2L(W8y*kL;-xwV/+_|fbrN]L]  %ކ5FtNjPv ǫx ^}Cc3kniiJo`p7|wW5~Ev3^^NrRr+W&.˯:_`4T޿çMhp SDwr6@PtGt w&ū/16=oR+_ccW`׀<ޒvzg9 _ +neJ29u[K_t?ް˝Z/7XKjjQUS{/:YVו_ ,[DV56KvsUK~e1prn@ 6UE@7{~t} ]Wkҝ.;wDb%ܓUU'/b Vή֬%7-{T]𸩹 {zI/\"e(mknzP[ **aݚUV KWE.3#w$Xd,\dJo~ѭ=({TU[؄^zp׋2~P\t.3NݦڪGe|(JB8YY,?gĀ;CwHWWw<ƫg`DZ^7?o4+;7[ZQUSHv3^tR2Lr˅~$nT.tQ钽X_SUQΒst݀5kdUQ S;;6"K]VS\)k7n޾{^ĜɁK䢵+ݖ'j*K߽}FLiz +/z k +tgLtDZtG)ʑëN<Κ`1»ݲ7obWxKӣTn^_3̼erv$JO%@0MJdn]u ]`,S#C;uDDWGwHWd@WkL#koܴ{(x̏wBx}#cSҳr +Jpnwt|rޗ^`#[ѭ ׯ^Ε;9>ʗne%y9Y) URX%ѕH>x7!;GW7O߀Șpb77 +;8tkdl|4}t_gˀ0#[r,fi-t-ttqL?hwJNWt7Kt,w%U=^sz*&>9^چv\4G&XOf|/r0ṡlѷp+E>yNM\ƥP[LnZr|̩ O7k{Lw%]!ѕ"+]&|~6v.<|N KJ/(.ÙީX31gy|Ab+eX~8 8t1zҭ,/.HM=y㘋t?.X+ͻx?b5χq!Qs/zZ: ^{p3}0!^go^o3K`\;w[t!rblTxH ǜlm,DJt,/+W)^7^u50653<`mk|_@0 Jzy8 z<#K~ 00!^%r3<\-)Lnp,L @Wnڸ^*2]:vY+CG ]x޽;{u.ùK3ʗ>b L7R,@Wfn pݡ,Վ\_˥w.+#%)>N]_OwW',]=Lw͂t%R>xE>FGoHLⲊ&Q[ãc_, aW +xFjg[[CDMueTi#Busuylg~{w P,6Uc.E&^é`w}{eD~"ѕ(xWE+:zݽh7GDšzdpv|;I~D @ &Ը#Ctrk*y.dAEE^rS j]w.JYdy?_oQۮCWd8z8n MI,Aӹ`g1`+=62 7i,w\NO tM uwhnWDWʒxW~]cNCvoUolB2gЋʗ^{O!m;S6MjܾkTm͍s!.X*_/^Spj讖JY۝:Vi`l*NG=zNEpfE{k/ +~IdJ }OLQۛCqB^ŝK &*xc.ڈkl{Y^UyDWʼxI(Z:zF&zXpz""|dQ_((*.AV``2(0KeKl+з%EqP&EGF\4P61ђU@WIQJt,̃W^EkW^mݝ\4\Y`ph8MdK~ KK \U H-U@ eE67Sr1CYe .]Ýb +JbJt,eWw[f{-[e޾A!TK훑=OKʑb hQ<6K93prC}GX0߃KwNO]%^^|DWȟWo^]죳WsK|1S~?EyaMqI8 + aQNB9 *" HayyZcؽM:>sώ}"Ϟ=K(Fϟ?]aD<©,perfg&\z|vNo%WPoBwoon;5]"ںtkkD]NOaq'r:\91vt~v Kzc[RjgOoӹV3whdtLM,o/,ZX-jM5ܱё!k&\SD˥%M+[wɚj\ˁ\\Nˤˊ3on6g/O\Wޑ GFF> Ce]َv L鿟ુKPv[y*\r18M]eE^޻NoBo9,/_ f~կ^(| ָm\x\UY.eLf3r8GB9u~ܙv^Օvʶɹʭ|ː[+7`mP/-Ԃmmk'7!ל˼~^s8ꭈ~0 kZ5_5 Z[6"\NImI֯/F1|-Ԃu]2zBリ^;!_3WX0j0 2 nNnL>M?Iw ׫kWaT%Ŭ{k?I1W^7̯_,aدFȞem &r2R~zZ8_ âX|Zaknͩ,pO.c)^=8u~~*aX:d>W ZQ+lq'[ 9\=)/7Ի7+k`1 R|*ֱ\n8*woT.2V=v{ `aA,'TԆl[7fsP.c.#~-`aE|@Goֲunp~K%JW`]`>~?լ-n=nr\epzZ_ +,VԂm6k&\e,Oz?;BX'Ԛ;ٸɥ\ޠ|zS_`8Ũz'4؛77k;ٟk+lCqI+~le~ujKVI|կ6p8~@u +r{25q2m0\e*^5aO_FZ۩_ϯ:m-2ˤPawK2ZPm6\eo7W"66pK!e ?p{Ły~}y~ [ep-`8l[e*-اwyi +~%ZeU> 7 cU!߻`H#[Ȗ:e콏`c1c1c1V0. +endstream endobj 289 0 obj <> endobj 275 0 obj <> endobj 278 0 obj <>stream +H vJA5(Qdcv@/}=W9{| +Nғ՗oIhRW *n>YWW_ 0]KeZ B}y~+sKWߙ{_x,~FtYYKꃲQԇde'd]1GFј~oa~u~{C^/uz/7E?׀wճVOoz$0T>ٳA=.uQfKgz9rk zAnPTY%z9S&XL4' s Q"yzX:c^1OU n'U++E Bfdyzop+u\=9:V +&TÃ3So.T=?Pbu9 QazG cSj;lVG aF0L=xؤau/SOWWW`3u#LV>S7hcu! Wa:H <NH\H.n:\V|u! U!{.:xG|W/uSn~k?Mo୺]UoAuFP's?I/u : +RG?-*xG|W勉Kwa7u: OC|q!: BrYu@rauBr]uP7Vu:ƫy0]]|Cu Waz:Faz:&#az:#az:ƪ3az:Caz:Caz:FgSaz:FgSaz:Gcaz:7Թ0N=yؠ΅qu.SO6sazI ԃM`u0^MÜzMS7 s5O4̩>u0^MÜzMS7 s5O4̩>u0^MÜzMS7 s5O4̩>u0^MÜzMS7 s5O4̩>u0^MÜzMS7 s5O4̩>u0^MÜzMS7 s5O4̩>u0^MÜzMS7 s5O4̩>u0^MÜzMS7 s5O4̩>u0^MÜzMS7 s5O4̩>u0^MÜzMS7 s5O4̩>u0^MÜzMS7 s5O4̩>u0^MÜzMS7 s5O4̩>u0^MÜzMS7 s5O4̩>u0^MÜzMS7 s5O4̩>u0^MÜzMS7 s5O4̩>u0^MÜzMS7 s5O4̩>u0^MÜzMS7 s5O4̩>u0^MÜzMS7 s5O4̩>u0^MÜzMS7 s5O4̩>u0^MÜzMS7 s5O4̩>u0^MÜzMS7 s5O4̩>u0^MÜzMS7 s5O4̩>u0^MÜzMS7 s5O4̩>u0^MÜzMS7 s5O4̩>u0^MÜzMS7 s5O4̩>u0^MÜzMS7 s5O4̩>u0^MÜzMS7 s5O4̩>u0^MÜzMS7 s5O4̩:u0IäzOlS =M]4L6u0AèzP,S EK3̪*u09ôzSlR MH3̫Wu0^k)]D2^+Qm@1^W' GñqkupzcX/^U gwM9qKupzkP-^wS ǝԵquPՉB^ U QO+wIN.):;z n/G%3. +֩G͐:$ث^7_ROPϨ'Ա3mu#l6k?k^S_ǫV=xӁ |T}5hs_P"k ̨oFs{L,R%pP"p_ skm>5TpNas+gm$s '\^A@>AVPu?\A}*kt=R&]Iw*MPpUu?\Y}ZWRwR;p jԯE}W8p#:[7TcwS_/ P}R3pO:E]x wV_ [}U?.pw;N!;J-;D5;@=W?(I}ц RߴI[gmNFeR?#S}FԏlU_{6/V߸/خr_P?_}>~8 KIPߺO x}Bds>xV?$goއԏ~*ynCOT_w xSL3շ]G~P?\{S@ V7<[}~+wopY? ?[Qk7?=|~=//Q}R?-~V_O.~!^/gxM}_٩8?{:'GH$LU${Z  CH P  $@qHd!AH P $@qHd!CH P  9$@1H C$( $@rH C( $@rH C( 8$@1H!CH P$@rH!A$( P 8$@rH!A$( P$@qH!C( 8$@qH C( P8$@1H!C( P8$@1H!C( P8$@qHb!C( P8$@qH!C( P8$@1H!C$( P8$@qH!C( P8$@qH!C( nCgCZ$pb P8$@qH!C( P8$@qHA:$p^7"rH!C( P8$@} C( P8$@qHH8$@qH!}i i C( P k C( P 8$@qHឃH\8$@qHrCZ$p"wC'!ʽii} CEg!CG "spH1H 8$@y!-8 !sHqH8$@x -86( ;H!ʣia=| C"rHH< Г9$@x -8(;EA:$p0b +>d >f] >j >l >a >c >e >i >k >o]8nNr7Ym۬~܍3[fyvYvYv9v'v7N`mAW8NlK }%twk/ ޵էVSکck7d9ԋvBA;_}Q`]>)z.QXCe +^wVP/ewBi+v X}^`f]/0z.WW_7O ̪^[GToM33. u|ݺQ}j`6jݪ>60znVIX̣ޫQU>90zс9[̠^L}x`|NWT]RꍊFV/T~0zPUNCަAoFT/(?#i#Ի4hUJ `,& ~0zS?GG?ޣ/FQѐchP[K41@ޡկj + ~Ъ7hlwT=A^ Sz}P? h3M@^iԏWDWwWg&ի3Y͙L.NL~pzo&T K6SܣޚIoP/ͬwfZ;3uꕙZUO9>S/|T^~RU zMA z C|]|MA @P_7/ |:!Ἡ7o# ns:Fٜn6'+{i(zVs:LӜn4'+H:6s:S\N2ckE` +s:Z0\̮0sr:a0\̫n/7C-r:h0ܦ̧n-7;˝lr:n0ܬ̤+#J̢*:v0D Ꞓ[Jn):|0#I n'C˜f2:0 "%è[@0hN2:0 $#é# ȀP(.2:0 %n" #{ȰhBn! '2:PBë# +}L)T1:Ш$BӨ +[D1:pr̥+ܫn wt}1:pkL-ܣn w{ƴ1:peL/\S תÕ~1:p],1\Kc ר%b:pW,2n g;R8ùF:pO,4n C gĊTI*:pI,6˪ [pû:A,8o:;l9n{6qukHv8 [ԍa/uᐺ0N<QԑmaCuYuWR{xN6UQmчꖰ:HvV+ꆰlY0 e"U G]L n|Pw>[;? ?+ԥ.'Zwu3u/usu3u5@2PwP׃ /aouၺ"N?<. +{sOŽ결:p@]vS' ^AueIv8 ;եauumEtxI]P^TW٩H F-cOw'SV7awu-u[oxO VTW醷%b_uuUlD]$T.RWթeb?uBuMhR'vS'.UyՕb'uruGeA]+vQ'nQ=9bu6uX_aO.WgnT׋ [cmu~fuXY^]]2UgP׌UɅGEcMun!uXQZxL]6TSԙuc5ubQuXKWxX]9VRWuY@];VQ'uXCScuJ!SBP]? +VbuN'2WM!SɄ"2SK"թ122OI#ԉQB2KG$qiN2HFn%cQ^2DD.&39j2AB.':0X]OjuapuE)ҩ kJN,.*:w2:s6s:Q\l4W۩Ku,Zs:I\6C~:?⼣Nl.9WgPל望gηԱS]AUub(u:/p|A8Oz^U'T9CuJ\uT8Y>VWOǫGWgSչPOR^zY'$OuW$PsZ f az|^>VowXWKq8Pru^75f5un~4r2]z~1}~/zCvVx_# +\ޒ-OR~We/7իeCE. pzaWY=2 _<EoR͂g1գS@^5_*W( 4[V\g) 0GGf7i@0P^^`zJꝪwQK'IԻ_}a`iݩ-zPH=hת lwvUۻWGUS>*'1^FLg>f>c>e^b~wz +endstream endobj 291 0 obj <>/Filter/FlateDecode/Height 1692/Intent/RelativeColorimetric/Length 195315/Name/X/Subtype/Image/Type/XObject/Width 1314>>stream +HFaZ3MJmJvwT +@1soÝ< """""""""""""""""""""""""""""""""""""""""""""""""""'8DD=SDt-%n!kl|=~fDt[\P#ݧV6ϕ.ՂLDjִѹZ3h+ 3l5LADgjζ/ֶڠ h+"ZVs~iD4\vk/կ[j$VrA~D +<,@DZQb)$>H;7 yot([8W_u:b3 >V*4%:FLk`WJ>+0W6\}(DW!:FiQ|Q!H>j>gd2+b:^VSHm&΢&1 㽃,I$:Ƈ-ՁLb$4469d(' gx`#Ω#x PbT",./EA'#.;t㠦X١$F-m*]8a<}L# D QGhF$#C#ب$456& Ftac l/q%Ǎ\}oDը <6\q2 @#WWW&$!( >tl-I[Uҋ$Fnn81L.%\}{Dg_6jPzt!Dc]V= &CHb}lit:YSHH">6@ccϻ8H\Xi4 +ct:٦L#W_"6G-2v.KHb$QT|ljcIJI >#!c|txt8i)ـdr|c\>vh%OcDzWI$:|Tyl ѬCi("i II^5-}0A{Ѩ'}J:dЌ\}DxplsX;PL"9էIivң䘑Id1 ]>hb;t֠T"FO ~e6qs#^P֕"9b$3Hm~:Vh 0u&+Hv DhǴOzӂRfɉF>S5c; +&iC0i*mFB$QQQQgcjRRfI3r( > +QQbxoʹ,l0rtFVN=%lͧ5&)IIj >j<:60Z}Q*ԆdId-|lQ΢ϵFԥ4ԦddIT5 ;|TxupTlt +8Kʒ +ʐԍ|(iirhHG><8j2I""? +6ِ ohzm@ g)]SٔL2"ccLcE}յ,̔dHHZ|cc,ğGR`Vr tuiH|Lxu,ldl5HY:1ErH$*k= Mh(XQMmNɌIIIdHF>*Tfd#D5dFUE E&Υe#Cg3&S/ RGQGFEE/#)JY82)LQ#lj\}DSG?q_u7SpRRRmFD~D@~d650|Mɪʐ웑IW]q7wǪ)H)3i+#idߌH qƣccIƢ`aUŔLNO2$-#IW Lcc)c]os)QC)0BH{F"}Rq7w:&84.*&OJ&H~Ge9#iFB$]eSTcLnjFŜ_MRr2$;lIWX8ƀlQ1ӱ1Qt132,d:%]HG&mH{@ +>|x|1ӱ1Qt173,D=FB$)@2Gm>~X1ӱ1Qb1w3T;ɯ%$!3RY%!^6r@Rq7-3w8&60$~F:;&1MnHV|ygdmFB$oB642hqocJ<: "鐼53HmF6D.9ƀ||GGIFg +f&eeIoL7H;rObFnD>'rO4 Yv>Zon||woSs762J&- ̌mN&cREr_"o|陑I!@O><^ ǽmGnR@ۓ{%)yw7HnCiHFfH{^焬\|,x{7w6&4 +( *fJlN +JjHH$R I }7>N ǝ{kSȯd7FȜI@rg{ wU2 |Lcx1ñTѴ]no:8|aI7 +{/"B˒Dqt79Es̙.|3wԒ@$Vj-whF~D>/w@dy9"l֯X - #GG^ǀcb#QQvٛYf +,'9jF.0#Ԉ-!2Gdޠld9ƀ9R$.GBcʢ.╺gbV&N1I4\Fʌ`!-$ 1e 6>ZJ]<:E9F9EKc/u3S,IʤT bJ4ȉc1# "ȼo$doTrdCDŽG#1`*+iiaI N&$Ada#9F',d^(@6ҀLrd}G1Ht8F):f%28i+S#,B \sF:#@d0&2GdހVBVr,9A4rdq|||(y:t6R ?+kW T$a+S#C43RHIdK٦";!yyW'!}@\ c>#52R%'EdȼAZ{ EBv 9@. 1 H::R F"C}ׯ&ǒRɝdJ^%4$IH=#;'A7xCL> gH@.||> +AGcJ*e1b2(!B4r\C#EF΁3`dLd޷o ׁE ]@.>h#hYg`) N:&CK^ %=.$I0r'y992#aF*AMyye !ȑ@N)@\>>Q|T|xt8F&Y}"&H$Lr%U$]HcHJ#=}FÌ\ƌ"ky[9)7Y$r4x>x >2CM%;I$JdH<,3t D.T&F ry2Tl@.y E x> +I +}<Gfc(Idrr,1)I$E|HHhH +%r"^HyB@z!U '$ H3 wc@JC>**<(p 6F)BDN߯ϰkIdEI$JZHz#]H:##+ed"QHyn,r2 cGq6F Թ_ƞZCa EtL% HF$HSo2S"iDvAd2?V;! ;Հ\N$|_KxD8#E)"gɰ$R(iO"^I[DRd0 ,2@ddI& B6C#򦿆tLfHqt +$@|yXģh$2&&R~'{{kLfeRs+Y$CGR1I32-Adȼ^7 9*l%@D ]@nYxN}TQm Hdd, :Qw1ɕ$HIȧh 3r32 Fy7Du dπty YT1XHx,uLp6F +S{Lfe2@IJjHdF^`]-H09OAAd970aB6Ȼm|D e@>,QXcHm4S|dL(%+JdId$I !#eF`Fn`F"YDN"lUN@U\@n ;Cd 1x :FF#G(U]z$YɠAt- iyFY F"Wmϫ +!$rrOmro9%dGc1Ȫ1XT-kgSdZF)='.%I02EyF>#/HH$ َO$ٲD6!Bz [drV 1 >)y,q d.JU 2I@R$79y FbF#D>A"m""M;"sD:JH H) k Mr3ȏ>^ Ky,t8REt:M%2qR(#)#CF"w-$q[""D*y;Gd˄$@r  r^@n{{! ! ?HQhG1Hm 2R_BLj%8k)ITB +| FbF>yxxDՈW#R#2 &]B; wGG'', _@@>|<tDSEEiLSbP:'%TtFSČH"U"WT"Ȗ#2L"Vȼ_I,l!S &[}= WGDF.#S`?ɴT(IdZ$$okgg''GG@#r|T@y$ٯ+/h~6inZ &Ke6Ƙ4iIt_wΜ̌d }jNB* y@6 Y$8䣇G#H]pދs?wͤXRj($W2@ +IiHF" B"_H'"Fdww2":@  @ M@s,hQ1Qhh$0Z$2^>LK.%qbR*Iy0rfƗ@d_oo@d%2 +D6R"4BDޛ%$ +Yf ʀ3@%93|\>n>e>| g%2 @nnm| }%1Dce"_%&Hi9LʘJ~ J*$yH2# # +#yFnBFf3cH$D "D<TDꈬ,-"? DB{WXK'YLBVABBB6@B65Ecx"l@vJ $5 C?g>|<~jej}Ge-I`On|49.RI I=`e01#HH$>o)"_D&"ۑ<ܜiRD܊ɎȯFFd +R+;!7`Bn C%$ nkȷC@Hydyx}|ty4:Z8*5A%^N%gR)I-i!iB F^#/]y2H$r&]C䛊W6$2DbD66ˈVLLW)yr=K-2!%MHlĄ܉ @|}c HW {{kaQl42=?qpo&RK))t#:#OSF뢌D"1#CD~KWlE"H투)1"҈LWK/R>< Q] RR҂R:TJ%%2$0$>0GgY)#w8TD5AdY-@d#RDf sD.SI,H*GUR Q&6d3' ;HLH V@:M@샀94|Ce>]F#'~5#YiA2)T%BrC9(y2IH"3=NPDD9 lllĈtJLW }&&vM C 1!HJH9@9RF߱!%;;D65&#rc\iD%N/E%˘LBՋlƄcB +HHLO( /\$ e@^ [!Ge-&҂R:)TJRKZHʐ#0#")#H EW$Hd>ɈLաLLWY }$NՋLLLHL0'O) /]& {ȁA amhpT6-up˸9JIΤQ!)C2rySgd/e$IIDRFFB2"AHAdʈlݱËeOsKeD +J +Ÿ́LM-VJHR$R'd4( 2 o`@ +S#u8*5*m!5JI$G1r Oy[d$IYHk'Z@"['"S!, ȕ%'f;!UB)!;:EB + YB9$q}hxxqըeX4ozb2*'JI`-0rxeD$ed"QHMdg!LLD*! G$2DR?tnBF$䋥% 2!m"!Hɀ<AO@ʀ9>>N(gG;ZGF#c"﷥,&RC8)JzHRH#Q}HDH"ljJ5ȥ~.B_2E 'Ȅ$d3%dA$$4 G$8@9y.cG#Q٨eU}wywJ %s)1*i!)C7rl 3&ek"# BJ" y$ll,cD&2%2X W@N )$6LȜHȎNrph{sGGѵhh ɭR2'5LII{`q"#>QB2"QH"2ʈl(="=!m"W&2bR Y T r;%dLJ6d1@\@: '&3<(QhdX4!?: b2*5IäTRSSNF)Y4"5mDdˆ|IG YrD.I)*di  @&IH G ɩ)㣛G#] Kd ɭTJ4FN&#GEF +"EFDRD!DHd&SLLWrE„NH#$K-"!0!"!MBrh G䭱1 +{LJGG1@1ϋXLFc!i#nj%2R)2##2!(d\"%2]sNȍ[ Y @zB@<$(rvQcG#Ѧ}iPJ' $"DR$7r2 i)"̗k2t2 %z+!3>!9 >J NL耜s}tQud6j9!VBf2*m(-&$YH>ÐF΃茼+2 iL\6܈\D:Bj"S!U?@_HH%drD!nY$d+O0ȣ]@H 癏#ggYF"*#DBD*"UD!,EJHZ"+dJd/neJ5:7!7D%dN%$ Fpi\dOcK&b\#=295)32HHI$F RF&RY$"k\+#RŸ́  +2d\#'dBj !!H Ϝ-$8craQ3#ѦDSTN +&UK +$#?QF>#?69}_ddHH""RmE#rҎȢB\Gn,IB&r )د窮+P_^F[& 0{C$:ivۨz;ci&Qk}w;W*_f8׳^g,)@[@2 [2 ?QGGGI*-`ӒRqd-BR 922|#7oPFz(dDD"ՈtGdA$d8"M!w#3hTT4R2I[B + 1! ȲrdCd8 @޾sGݻ##9FUF/}iɥ)¤$"|"3-Ho"8HH RD$cD!rtiG/-F!s!R@!PJLH2//$ !!E ȊJdSHQ966>1!}QHH:J U~hTN*JdFN)Fˌ2FDBDHH$E$LKKMaE;,, + M!wB&(Bʄ LJȟXB + 1!didU55 d +$(TrtђAW%pRQ#Iّc2#CIDԉlDBD2"!"HH RFWt%"FDA"M!͈~6EJB& L1!SdI) $( hQڨhs_{ͺTNr&H*FNNIDD"";9uD$D$y8E$SDf iG,z!%ۍܭ$$ i$d:%d&~HLH|,+g@s ) *kGQTQ'CMJ d8%ɈFNLɈiWd''  DBD@ȟlӈ́̔IB#R _!wB&(B IBbBfh rd@bBdQ1YQɀlh$ ;9< >Ρf>τoRBDŽ O U & 955=3t60&~ڟԹ^R +( %%92‰9$&"!"HH "#E[2"_9RD>="SXD&%B&D.="m!#9Y NȀHTJH27%H y'$,( KȚZ>K@:Z@裞*auiƭͥ"p$S#a )9DRF9KD2"!"HȒNbD5_Dȃ,"s!"("S B#RcD{>}LH2%d8!(!T J|LLRHHlm# {! 3 '&x@> +7lIGIffjTJ'JZHzg$2$"loC"!"HȲR," G!jDfSDQD&i !"# օńͅLԄ !1!Մ<}B,„,D d/y#$ $>hdQﯱ)Fp3)H~!)\ZZ\X99IDDD1"!"HH ""#*"̡LO'!(d@2LBL/6.` !d8!_< y +,+D .RҒ\G +Ŀ> +Hze$2&2yB"!"HȪJSXD!#-$Ed Ԕf-6_Hq^ ,$OȔ42UB yD [Z3 s+@O0 ȹy +H!t82:Pε9sp@$GD2l"ȩ)F$HȫWgHH "" "#D L4%"7r'2ƈ\,v!wB&!$&$Bt +i$QLȓŐdUu-$$@vE Wd@ʀ\^^Y]uhQF{k}is@0遤 IH-# 7׈AF$D$َDBDBDV@Dƈ<uD|Ed.DdDd:E$ ЄLD! !="_|yRH%! $%'C!JH2;r_ Y Y @CB"dO/9H@^ 9rqxR(Q[l6O55*U& %9kk$hc 2ɡNw !DB@B6BB]d9t| ) IhQ(m4Y4gt"SReԐJA.2&=""#hlj,,yTC^yEdDd&DdZZjȗ܃DF'6_HqݖR +R2 LM„̓ +N|3! !!!3d9%{{9=À\\Tr}(щ߿ +jMJ2$&$-#?tC HH7gD^DBDBDvuBD4CDADVBD@DxF)$<,tH2 )"R + cD{e!w1!wK!H%d )99!ҔB y3! !!! ![!!ȳ=2y YH疏BGi޿cLI%&m$M#76"gD$"0" """"+"{G}P09D"2!_BfBFH_Hq" \=BH/!yBRB: !OCBV@BBB6ABCB y*- Hol(>y(uqeTcOz}ZR0HˌHHo1"]E"ȾޞM|EN!YDbDfRD0!HH{JDB{F%!wB&jB d BEJÔ +@^# o{\ D@>~lQ(mam6JLjH~+ g<#WVn"בHޞn "">E|"E + e:0܀ 9^t9R>E + PDo*.Tq`l8c|<9soMBƾ!"}ӼKH)d =!$K큐2B G&d9!'琐H6$$#At s'K6ǐf2Ð4c@iQҎe5#PFkfD~lotB+""$ȃ"2~LHq!c!ttR ՜BHq ! d* 4 )rN- Y4@^]rc@)rqQjģ c$ n{6,'U& gb{O?eDRFډDD2"Lj "M<""YȝFDڄzCB*)fB|D!6$B d2L醐xBfQB抄,7% $Y$dKKdOo9΁yy ȕqQQ?kMI*V#2#3F--W9 9݅lAD#Y,"ڈHGDI\H+!&6!O!{e!EB#!)!)龍 )rL]BBBojnEB!!dWW@@ F@>x>|hhw._,"&)mL*H|ΐF>"#WWA$q"oۉDDH9FDvwu""/!"yDY#GEdH""h1D2J;42 +r=^DBAt)%! )!EBSOH.$d?@7@~O@.-)||GGCGF +_D4RJ'V$\YـHHF  ޞ6Dd+SjDV,DDPDH!="3IHDd"ݮCMBn*"5m g?m*!_PxCHL&!~JH"!w''d%!xB#!{Hѱ 93ˁDB$+Zv5]f)iF0e$3DF.-9dD͂HD "yGKDV̧GIBRDj!">!dEm҉Hgoz,d +d r=2BLHCHrO2 Yʞ-BxBv#!Fcrj@_3DB r\kH6%f7m`YJɤ$ Iy E$' "A$"2@DvwvlFd H"$D˄L !Mi2ٻR?& H$B d2L#!3~'dJȽH\$dQIiY 93 $yǏe@}d(yTuTqhӐ[u+v+&U%%TT3BD.H"oHHD$BD!"]<"[Y/# "r/E$ I"ҟLFDnNm$dttAȰ UIHq$$%2BdHH#!!$%=Hl$dOl ?08GBȹ )u+"PRGF߆wtV*NJ4BlD于HHHDd FD?vCkk++Ky9Ʉd)"2GD!=L +i#k2V +ID25RiIHr'%>$dCGC&d y Fc-8(Qъ6;- +V%$U#CID~.|HD.ꉤȹ+cAx:*6Q_Y-'U%U$QD")"A$EUD"r,82#͈Ӻ,,EDBHD$ +IFB""^Ed%"cH)dB:Մ o郐$&!EBBH$HٹyHȒꚺ'O9$dOoO $ @ S H{@r|Txj0iR#HdUF䂕H "5D "rbl4#Edsl(/+).*@Df#"ILHH,"~? !uBF[]٦@nU2T#!].B&B2%$ܱ w_vNn^AaQIiYEeUMm]ÁZy:6F0?-*#|' BHD$"ÛsI}FD4x u5Ue%Ey}ɅGdz @B"""!LBnB +""B&d$d^H3{9yHJ lNHy$$q ! @~΁|\ Hǯ>*~(䱦Fw$9YIH^F>ŒD"ܿwCyCH$H #-NDD<#|.v:Vh@H  YO^"r/Dd[R mKB@n$Hf{Q.A !IB9 + Rk:dBh,LB 9F': y$$ #++b@>4E4VJ\%IW䍏D"1"^$È, l:ǢP]Hɨ!BbDvwu l&r;HYHyOr[#!wBlni%BPn"xBR BBB BBjb9."X"dR 9A'INBN71!$@BB2@~yrO"8ikIVZI$i#H4ǘH䊐GIE$I":F "$l&LĢP0z\Nj1ADj!"(!1"yBF!DVD! & )﩯MHZH%-~R($$$!uzlNÑX< DŽƄeAB^ @BB k Iy  %|dx( '!%I>Ff[,lD$"FEnD9}eȹٙ)aJQJFJH#bd0#yDa#$F +F'و*ų 1"cDNMW˥B>I'h$ aZLFN!AHHi!{QN&$RRmR&R޷|nB*8Bv$Ą|>R= Fjw8? +Gbd*Jrrzfn؉ KR .IdĄD utl1<&kJ5b"SD޺IDDFf''FGR˦Sx,^[-fA AȾ($DX(d#dRغB{jk  ʹm ^"d7 +yOH(rP҂&fw^? +Gcd*٭3NZx}m_Al!@!@^O<$d۶qxEܛt} 9GG6q:BD &d*= $$$&!!  H8:X-Ge$#FVK#(oI#ef)h8"sLFd<`D]u|(ߣD"^9"W19J&`DFq96etd84jTJL+|bikW!/]$," TȦP!WDDY]ނ($B@< +<yDH@@k]Tbsy|H++UjNo2F̖qt{|`(ONM'gҳ\~n\ ȪH6"n3R(JH,O !_Db"3$"?Fbq~.ΦgSh8&I%H*ݶ$I.H" ##rq8WgaDN'h$ nn3AVSeH(q9,&F!;mPH!#B* &BK*d5?M@c!!B!ہ*ds|P,PHVYmvBDlr*Lg3 @|VH$ 1H#۪,JYH2""7""DB!$ț̦S0"cp(z\N:f6 @R!JBa3t* +RF$*d)"!a ~tح +ӨrioX$8lNB^hzybYHlD! B->(䞲|g[!DYm/{BB644655B/ yT @H*dNf|qaiy$-4!?&dRB>^[@>@~ $Y@}$XmcmYN+G ɲČ,% r !Y!a"reyi8_9J&h$ nn3 zVSePH!et @*YDP#MM Pȃo.䮺B];r?**!ONΤ3\aZJȻ5$Hg !?$6 >bxƑ̿ok*JVdD>D>D#%wAD޺ycueyq8Wg3tb2>~tجPHqhPը +W" +\ɠS)@v dk ׿"y$I(ѲKBV"J +u!Q&B@bK&dccSsYS%!M!aBB!/!!)4:X+C!4[ƭvT"7oy$JB~^`B>}* TNbH"DD| +\C$D畈";o\^Z(L*Ǣp0]ubB: +)B|bn}6GuXaaxp +X00K{uUh{j&l$Ό >@ιwݽw%;8>C !1"BBF!!"v%.{ByMHjBBC!v!S3rrQȲʪV=42BD*W(`uN?M$<@B$Gg75#BD#|H$3F^Q+rD,yё!@? +P_[SUY^Bde&'%DGE|\!مF$ +yIȽrGH^)䎟"ABȣ.C !!dʣkUܖ4%7d0$t$r |DDB~%-"oADNCDZ&DZ$b` zQȖʊ"2;3L%dWAK 3.ƈ7 "'!"MFNQ)2D$s9C}]U%Ey(dzjJRb +I +BQ.!)9%-=\Rkuz 9 y"!| +  f]_=H'xZз.@6"_ ֵ r |D=zDȇDDޅ 9i6:Z$b` ftwv675TUBdeI(dtdD8+4! !O|L#|.{!EF$oy'NJ$7Cb?؈XZVg@sB>B޹9 i1 zFRȥPqF,)*F!Sb"X!A U +yƵG!PKr/k܏[ Yȣ<}B^!CXaQѱq I)餐E%Uյu -m]=졑Q. +)JZMIHw!!|fK/ r reȿRG:Ns;cvI#\"0"P"#F,D ɉqɨi*\&c<{27;+#Lh" +yڕG=Bz?K ARcB"BAȨ2+(,.)+ohjnm 9&2R Fe|bj:$; f]_x&$Hg-SISҥ4"mB"ϟo[׀e{!"OOM[F^Q)2) +rFك}=ݝmM 5Ue%Ņi)ɉ 1QaPRH? +yꤓH! !P=!={ "Qt!OB^!}A1(dZzfV?&IrR &ebrjz=!_ +IMU2!cBr3 1Ͻ|D Ĉ\uH { 7!"&',fAӨ +T" ?7'+LB!##Y!A / +yM㤐lBr7 +ӕ;19}}$٭+3ql3Mbll6sTb@ u B{k%jwڪƏL) $KxOqsrۮpg DB) $g@|d輋NXɅHdFIFmvD+ i4R!J"?6lokinl(/-)*̰BBz{zgPR<@ +MrYȭ !l*$ȗJ_9rYm4!w{B~f<~"?  + +H7:Ο&%RBh!! !M+센 yלp=9xt9%IN#ADCsDňŎHri2ZZ$"hkmnj,/+).,HOMIJC!î\ +BB!OI!!vRw.!]{(@n"AwI!B,$%! !B!ϻ{xYBGDBgdep?84LœR\Rktz$$27J !< - 9|dhDs$I֌dB$?pF$ +  BNO "*\& 'cRȮ֖j qQ(e2yvQ$ +i&%kƞOHHF +ǁG !OH!}Qˤq )iY9Eťe5uM-]ݽ}#(H,JFAHHȅEHHY>$ڣuOdt(%IԌD!mD>A"ۏHryi"4tZJI%bф?6:2<8K ?7'+3=-%"U2"Yȓ(QN!ByA!_s t|Wr?G!O  +A!Gr +YU][O +E\Tkzq +4 J$$ + @Br&FBR=`ґI'|Ȍo "I!!"AD$jJ\* QH@oOWg{[KscC]muUEyiIQa~YȤؘH +C +ylokinl(/-* +BB!OBiH.!BK! +sR׹|r+U4!Z$$)QBS 9RH_2CqPB*QHqjzv4 BBBV !޻GO^}|Q9HJE:(Iy:B΂VBJ'(odh&da~^NvfFZjrRB|lLT$ +y 4 yP= 䮝nn!ҵWo!V!v!8!)95-#3;'"dMm}CSsk[GgwO_ol\BJe +JՃ3  + B26w?, 9|tϱvd\FkD(Ura~nvfhk5jB&E5Ue%B!ڄ>>HHN"҈E{dD@Yon+ 2u( +c#Ã}]-Mu! r2SSb##PPse񙵢茊(,"BzBI(f]H#!3ά>9O99!* 9r?rrO|!WLH9B|$OiyB Ba4=B!\\=}C#I)3rr K**kA>YB !QB"!QB: K 'HAF>aD>&Dq+"WGAa$FTe}]m-"B&% +y<r7r;G DȵH5bB.&_X@ # +*$Z"ۉA,!'<2/B + 9BDBr_8!AiQz )~%dg9D +D-DH $ R dscC]muUEyiIQa~^NvfFZj9"Ȉ_/Ow7gG07CB!w!'y|IRڳ F!܇43!AHGg7wO/_а*乔Դlu dgWOo_\Rk(!B޺}'ф&sQhƔ400#)?"E#r +"rD7/!!J킨q1g<B %&Fu!ZIBJ@!_Wȕ+W%VF]\!'<y˕*   I %cg6;iHHi HHDkWAȋHH-R B675TUfgeBFE2B:;9 ikmeinv -䖏B!_,'.s -먐uBna BEB03 y%dHhxD|jzFVv.KVT(U$04HH,$93swv֔4tTRHQ"yyG D$X$ЀVR*e} d;H/drbB\^H?oO*q,!BB~B~FG B& )mmB!5R y8? +G!G,!oBN$; |4/$H}FrGHE1,!o~Bj5jB.![tBdeQ!" t<}y҂-"BMIHiKx5o|ߨ_ !:`faieckwy#dXxdT42-=3+'7%dcS O&W( %$#Tȱq4M9 R, <3XF4("!"'pDH" KHZmDꪊ)I T?_o/wW*,!DB~DP`!&B|$g" !&B::{xyS!SBWTU!;A~B !/(!$BNL338!CB>IH8F1M9# ɎH,䵫 E$VR= 䅖y9ٙTȘ3#H|yٻ3HHB y 94ը~Y_O7PY\XE9+"=igcmean+[HHiL/D@ !_z!S!@H{"?lL\|"2+;7!JF;0D w*rf'$xBFU7r|ȩIHHHFAHAFTAȮv*due^璉Q!B>y<rKmBn BEBBIHiKfBn'Bf43 y'dxD|j dhAHXH]B!'@ȻXȹ9?& W3HVFrGs8"8"$B^!/%B45a!K +ss qT@?oO7Wg'X!ܸ!IBJ[M\A\\K`(6XB&BvprvBP!9Eťe5uM- dWwoLND =D;HY&!Η@}\0Ƙ3Eш| B"!8"uB;,Q$šZmBfQ!"tB.c\.(jBna +qaDȤ*daQIiyEUum]Cc3%B`!QBrB޻wni )yBR#D$#]G$v+ԙMWj%Q*h46:"`Wb;-\ +vvgl[YWfg6s9=O0brDR!/rB61BV`!KK%BBld2rqxXhpP?9 1 9 9 +9b8'0!B +B 9 +9 +9 +9V, r"dde+1TD dEjNȺ&,$ZH"$$N+[HNHHHB)cyARdii4vul& iHB Πike dA^nvVFzj#T=vF9Ǚd"{$ jO?Fa =<}|Aav!oBGLIM!KO!:Bdن4Bڜ,俩to\=0RJቴ N&yLi5Xr,"I@m1[@U+ BN7rr<rC *Z?/9H($,$/Y!H\: + +t/dAaY^QYElDB6x!y!o!AHՅߔsHBZ&HFȫW8!#!g'9Yiv!R!7R!DF/ + +_B$BzBrY *ړK>r3!'Q!!,]N ? xI"F55 !sB +y6b  +,䯼.F'NJtc"DڅBr)2'9$dV`!Oc!K!N:B޹\FF!'"!) N7{"3jXn +B9 9 B. + ]ar#{^*drJZzfVNn~1tyFse@Bx!9!XH)=QQID:HHd4vuvb![TKg!+'dLBnB\L \r_o/OVȯ||K^ȗT!O^]re\A7B(׬^޾ #,Bn!cGS22s ASXN_['-$M Ea!م|`!cT Rq"wBvpBry*'d3i5UX2Y!A[c@+WH 9u@/]#RR !_ꍐߊ +fr .*!%X +F&$d '$ZHV[Y!f6N'>冑R"&>fZfH# +,*,HOMBBnB.䅜?'!!! 'Hw]EFT!՞HB>㖐 Tȯx!BNB(#j*v2>!QF2,dUuV7XHb!`!;F*d7 @trH&3"!;rB^BGB6juZMu@#;Av!B3\ 2B +֟뽐FHO/^ȟDBBƀ)YٹyE d9#d#򲜐XNBd +/)3&D8DBڬd"BQ!H*%,9'e<Bn!eㄜLKUH麐_rB~#/|^ȨTM *A3UB:XH)@I"N$#]F.$d;>DȋDzC^BB+LOKIB!V, 9 +9SoBsB~,w3Aav!׃;AI!O +l B^Bdb+򑂐B:ET&R2DHJ$'dj!$Bg,#d%HT F*^y tc#CB +2 +{r*r4rJt!kR + $uV!#!BB 9W2rm4r'q  ٹK7-!c!ʄܢ$R$I ҄B" &%49" 8"B yZ`B|(fBXșHHȡX^=ԡ9!kPH![R+rJ킐 !B^ 2dQHd2 6'-&!rBnS 9MKȮ-B!U!rr4r*r +1+$˄dQHY*IYhI B5rL1HB鈐OP +B6-d$.BcBP.d)>!mH7R[2IHD($" CBsBHB.d NSUB҆ϓB> BB ! Y ٌ&d$$$$,~!cb7Ѕ<'mR<bՄ4$##҈ X'B<@>f]ڈ5Vb!gӄ-g $N(d%SB֥ٖMșX儐E!B^T yKKHH%*!4I@OTAH~D?"܃DL&D$p߈B6]oB!@Hk}!kB6lԸ)!d{A^XȡH2!(  y/)}!ӑ>QH y $J!- #R%dy!eB^ [2r.!OH؄πP 5y!gJ) +!DZ^%ױ7!34,D@BB0!YFr!3<rXkV+l ל_B~#օ# #M ,d+!gc!WBnBBQ +yHl_%J!ݛZD*Db!6/My!BJLB&H$M!|[-k $2y@/iB 9Q&2[& L3)dvBB޵!>KdB ƚ/ 9+d !󰐿a!!K)B>tGHY./NJKdBngrPl!B~C=r8! $b;8!BU+Bv $䏄? +y!5tmBʉ BnP9Ռ TB!AHȫYm!_fBȯ$! +6z],rB3urr9! ,,e2C!$!/`!b!"!7BB!m r!ߣ : L! OsBntA%HȲ I#bD*, CGCBR# +,:BxH_[B +F#RO  +M&r +BEɚBn$d! =!шVyC!yB!' 3BP 4/%!u,U ЂL钐 !O"!5\I9"@B +DP3!t!y 䧒_I9EcGc#)#ҞiH$!pB!dk +< f\r|ʞeŢwY&eBa6 x +L1IGlB}d'RWc!3%!-  9r]!Pl!3 9#Y uB/d/QȶHf $v.ք릐j!9 R HSB*G$)}+B^  >f]Z{B!pB#\䘐9+6D򶾐'G9F!dw{BV S $м#dB<<圐eօHDŽiBMk؄ڹST!낐P8䢐|[cDžc2U.d)d($R&BiORw8!sr +!`]!B!μτ~ m RHg y$d(VBȕVl +BB7-r1zB^&Rl;Bڝ $ F&|I(BUH-".aC!g 0|HB6 dGB"yC[Ȼ.i$È iB.S 9%!+7CBH 9(dSk(dFt^[B!!Hl.* i l 崐$d +bC]9*u +AJHHE +!M y{BV!!/ 欐ց $&Ҧy!0)d BrY!끐PBtTH:gYxyXAHA!'2Q%5HCJ!cEӅgJ:5AH(-IHV #d9!7BF'd ^j $@H,d2!]@| 􄐗XH r42 ,?uq|iF D_"B,!Ω-Z٢Ѧ=-HRD(<'KRd:9}ݿ~~?]| WIB +! !ɵ2RZ rN!'r$B*dKDH$BHB$x!BGH DH,&Rȭ!HB"$BBHDH"QI$! $B"$B"$BBHDH"QI$* +9 rB"$B!HB"$BrGI)d{DH$CHYȢ$5DH$\Ȇ +Y{QVN {PXv 9*r,BjrP(d?$R dBv[ ! NyIjBHDH"Q& +!#Bk B/x$BH%$?S(d3]B.+dWF!!ĜrBrz!B6EH"DrBI-d@IVg!._![%rT! $B%K ! rBwY*8DH$!B.+#$$^!,|BnsUȕe5s)If!r+!9TrHr![ dBnDH"i#dW%B/Z\Wȅۅ|!rN% +!!DH2)kX#l,rBIRPkrrw$Y,fDHDHRB" !/DHr2(ddPBi $9B[JȫC!oBHB> +B+GDCH4@Ƚ"!O%DiO!rJy,!_FHDHRB"duBySBB^JCa!?^ȟ!CH!$BV z!$y B +yc}!/AHr5[!!)s!BH"qfyB'QB^~y yt "!{TTB!ɻL@5 WZ-䧉|!G$BZ VB$d'$2_ۋ|! +AHn!*!B!AHDH1DH$)[SI"$B"$9+B2 EclO +y1B"$Ba!$B&rp(d$/.iB>B!$BrEB/AIVd!tfQG]"|,!$9Bv$DH$U!$B*H$R%d@҅3AHlV!ddJ 9)Rȕ. +BTJ#r!g!$B"$b!LUȍ>-B-!rB*b!DH7)f/Lז$rHȅ ଐ8B"AC){!+1!(AɄ!Mr!4^ B*57#d!-q|2Bd}y!Bm$*>!O1G?!JeB> +y8BmIro4CHZI$ +!R]BL(dBV .IyG{ !dPvyw!EH$B"IT(!w@2W!=B;!$BrBo)@O S" +!.1<[$)ggܢJȱ4 +!Iwz<!srAB6AH2>MBXW p( Hݫ;B!$BfB!$Br^2!D!!HT*!C"n!3B܄ !ɚ={!z!W $Q +yh*!@HB*@$rFc] OT lW+d+$3HK yB*(!"$Bވ܆Iy嘐o!$B !Z!Gq(ddI! $iH!Yrt!fBeY B>I\[_J슐j&)sB~\ȭ^ !撐j!9FȉI)QInY(ӦNFH4 +y*B"$B!B~DU i"$9WB(7B^Gf 9!!Ic +?Z!|!y*!GH6EB$_ȑEBN>!U +8B!$BB,Kj<!ɁB>){DrBHDH"Q郐_k($CDN" ! !U_"$Qt yBmDH I!ɘE!AH"))B"doV-z# $~!Q(g)U[C!CH%BEkC!o#K)#$Qd ++B@$(>ۅx!DxB> +BiB> +d!?-D\m/ɉ !!HB.?XBdK<\!CH$*B"d/ $QBR nrl) B-I~IF yB"$BR!d&!K饐!$Bz,;VȞ=DBy4Bݹ#KB^jDΥSැ"$BrBb!o7NȢ߫{N\N Y|D(%< !ɱ PB!Ǫr B"$QA +lb!҇S},!WTmD*kIT2B-R +y:BK(dDH$#rQȥi#$B!3B"$B!$B&rBO9+ + :B(B-!gr BF9'+_![ +!!orBJy dS$KBHO\G1l! Raم  +"C -E> 2RIIn 1fN6!vd] ! \DeBH\ZuI9BvH+!g#d=!7$r!BXg8W1!'A' *bBT 99]}*CV[C;}t y6,GH5B>Iz T.dG\CH ɾG"$9;BCԄ!4rRGBB^!_GH5B^n"!o@Hr>$!B $Z.BM"IT 0B"$BR +!$B"$"dG\$'3Cs>B"$QF!DH$ BGXQ !)!2ozBD!B6Y$i +yHȉEBndz zڧ!# yZ"$Y.BN-h4H)m!ɎB$3f_+\!!D#d?DH$ 2J}!oBHDH$DHDH?UBv,\nvq싐d@ 9rUBINeo8.䗞&XBFH2)DO yB !GHM\P鴐O#$Qr2Bj&maB.@Hr 9N$Y[<.!d:B.BHr0 97g!Zȷ" y5B!dt!*rU"!FHi'BފɄ|U5I$.o!rPȫ!2 !!D!$Br'$R+dODH$ER/W!w)@Km!2'BHʅ썐 (B"+/Hȋ !ɐDHID!c +9nVIvKHHJ y@1I6} {lR'!AHr!1vvB"$B.*XBC |1/!7AH2(k|BBOo!CHDH>L$d QnIXBdNBIy"dBD%*;K y:Bf!ITUBEH$RYB^ yKZBABj B"$Q!H^B\;nnBi)r2BY ǵ +9{L$IȃH 9=XqLOG!I(NB"$^ +BAH<!r B"$BY+k@[}! +9!ɉ#DHh(CBcZ y|"$B"$eBޞ#$B)#$ [| !!Iyn +B"$D y B"$BRVlz!?GHB"YYɄF3.B.dBB$)>!EH$RTBEHDH"DH$THDH$3X;!!-\鞐w)dU䈤t >4^$-+iBCH#$D Y,`_& yO҆i] r@!{#AMGIYTLSȱNȟ]")ƅ 2Z&f,$DUN& # 9 !3;왂I B"!*MD")i@B"IBB$%K42'$B"dBVHIi$Ut!AB@H'dB!%HIR!YzD + 7d.MB 9!2IO*UB6B 7m!! Bv.4V1(dԄH^AN@,hB._ְ!rFJITnM@lkYxB +'d!:8.K{wfzfgoϽO{mzێ_qq8v;N\@$ H@@$@ xB%]WwUuUwLz~W,d4rF  C Y,dXEk8!&2p2v@yqO|&2B^HIVotȴ ʥ}pq@~R(d!< d" !"!OBfe@bJB&"!=$O̥r `R -Bb B5  +٬ 9m| 'rPHowKkB!ssruzB)!sBNHH0yT X}i&\ȂB@!+R򼳐B&+[BHJ:DȨ)%d!'d)*F/,2!g<  r /d%2O"drDzddW,R vB3B"! +9 +9 i B5 2a +KQHe"$}=DG[ gr>KR!l y_ Bդ߶r-d+ @\"]D*(Y:JR$d%$2Z ir9rP.$iF!3)= Y BD青~1siIH{!#H8\,d ً\墐B!#eB1B6!!kh!!A!!b!5+&bFWtQH.!@ i!KmQB$d !FB>l#仁 yIvVHQ- FH%#=po5f\|3em| +9G4-Ӆ,BVZBB.#B!rB[w"!O\'Q"d92N Y DnC3`n=UR'bQ8!yHB!KBnHUׁoB.7r%F$E! !B&KdHǤ߀d\ydq$!ZR$d+VȞ޾J͆{7!!@B>?wAX-P庐mPzP]XT"0r G$iKdtIڥ4_HG @!eHjZX]NJȕDmc'vLJYX!? @HC0B~?g +y y yrjrb|"dB*$H,(" 2$]aoKqFGGtB"!s(!QNȚZCEXfU!ɅtJrB!+wjB =Vȯ&*NV$RN*$d.d12 O )HB#SS2m&$˖ye:2>J2$u(!)!@r"|$䂅Pa ;!oCBo +y +b 'B>c4򈣐(!0BV#!˰Q-BQBa#25"IQɢeZG>r@ζiOK #B!+8!M@$d7ʄ|@:%D8!Y\ B`!SBH,BBRDgoYczx  I Y)Q,z"!%B>A Dȏ!|HԄ lB.2B!D0҈|@d$"m525'#[ttG; BB!#Pb]R(dB d] r!=gb!_ y7"}{ !7#!WZlBR BE5 bHHHG$w20ҏeGchd>X( +Ye +ن܊c +y3."䣜/B~` +@H,osBd +kjmPn](dPJ d)+d!d#d +D):*G d !@r(d5'd)rJD;vB|(R]?!QD,BB3B6LBǢQ-ABR/H;"F**<*^h&)diј.d  +Y 9(vB|'R,RNc!3BvB#!-BVA!t!D0'D::#ã#ȹ(!-BVB!kB.^lB.ӅBy\o ++B|]"Hۈ7\B!!8!XXTӀ!JH.""6+ӳ$r2ѢX.d)24 lrr#'a"$9g!N! {NȏBy. +yÁ[7o2BB.B"!BԅB0B#RHH9Nz\5tmhh $a"d\ +Y% +٩ 1ܲu oA")^| W /Y!8ӅQOB+rϮ;&!WB.B !DBԅBY\FH\,"Jd`Ǵmh H>!Mt!Kt!ˡV!X,Z"ݦ'B>e5$fU3qBD )]Hț%BB B6!͈B&zDD0%$HLd#V$T}$guӶъ#c@BBV@!kx!@n"J ljwB>n/\WJG7DB>jı!72BBvB!DBV!,#2jR"tVRI=wyGG$I SB!+P6 d.d!fN#!FB-"'vBl!"! !WBv@!BV!+$"CT#RN +M߹8iIpDӢXq\ B 0!@庐}D5Hmc۱2MHCR] + dHf d'gsT׉ NXu " IZ{5I@b0l66`$/8ĉ$~L<9{9g$9_Hy!/=(!詍<2> + !C@p2:F"&2L!3uzl 9 93;O y$mBޑ OC!G8![BB,fA!SAr Q("rFHaDk"'I0R[&;{$Wۤi^(Б* y BgP82`tBUTV76pB3BNNM +D*"HIyQZq +ȵ$'$ dI )LH2L!AHdA!sdd'gB~ +'b!9K҉BZ&#-d + +BnzF$$FddDd(Dd0O#L$H!$%=u$FjjFR$$-d Ir+ +BzlQ<=n\qep uBPr] dQA> +頄423@d2#%+""!" "7"R=<#EHt~^[:\F#G?f|O d +Cr +B:Fl%dsK[{'#.!ϣWB~Qw\BB yxta~vrld2BI(d,#$?"c1"!"Cd"&r"# )ˤڔFHP; GHq Ą!@Hr"!7mF!).!Mf ek 9ǖN| |K߭LHs)䟕ЭOd2[-fAB(VIGH|$Jjw;HTފ}m#9KH2'$ +B&:dY(dAȾ휐&|EQOy,==! QlJHA!SArfQatD"R5?omLzIUF<)r- $)!AȈLHq d +30B:Q⒲Jmݜ'J|򍗼/"!NȻoB% +E!m d +QtDˆ|HY$L8^ITVJxF, +@>)LH2Hrk,BBZ6 +YS[rdtϣ!_! k-B~?uBSI|kWe̲۬f!A8tDn"r=%"FJ$3Iv'H|\Gu6 +u(r $1!A( + B&i `4[vGV +YDr`-YT=FH*!B~HұGfO< [ dYI1 +rجBI(d,IHH:"CHDHR&58NI`yGU<đ`GNGGGu@G  CHHr + +Bb;sy(diYEeuM]}cSKk{GWw/'䞽LB?q7BBBJH_Fe!!_ "-"!N P_[SUI ̡4 z2 LD!!"BPQDrDTH<$J$;JIuHT=/虎בȟ@,d< +BfFFܼ¢!v< +yM[VH:!D! ! y9;GGv,-.*C!:2LFd+"Ø ˆT&`$I$&NPFZo+QM>*G|%<>RTBJ!AȌLY(d +Y.`pǰPK@7xB~ +!i }+$H /QB^F!\=|H(@_owWG;%d]Mue +YBf;6Bf) xQLDcD#H,T+@O$o+uTcGNGG. I &$CNH2Lԃ͑D!QȪں斶ήONM_8B{B/?,!S){( 2%$Y$24MA YPXTRZB76ؾchdt{yB[:A y%2-mVȻB~ -B~+N{wB^@!O:Irtxhp{_OwgG[ksSC= +YQVZ\Ti5z]fFZjJ٭;㯀IKd! Lr mծvV%E1%)m;񌓋LSv9{ٳBBFg>ńdȽEDxD$02$EIIN&Aɫ$fF+~{2>ȋc6RtHH\m;X)$$$2 )Kdr + 7p!KJcw!B^!O%homG# q9 QӪUJ$DD"drDd%HɄ4&r%! Rȃ0:R1/@ڝAI_&$`6R$ȐjVo0-6B ¤Uյu -m]=Cãc&&q!O2B-t!{څ!iB5.GIBޏ y.Y\#'B6בBE +Cv:Vhi5*B.9xDB2"2]ˆčd"IQ$:Ѣ񞘏 +7!HHTPZhXmp$ZL +Y?842:N +y"HȷBυd +.y y"$.ġᡁޞҒ(y.f5 zFBBJŢ<E$CHFDfD @$-#)FHƕ`I.&ARȍfm@ȍ#K8:Rx|$ wdfB +!(!sDbThub;n TB**kB…< B-,.B!&$rUB)8fA3 Bv675TUBF¡`b2uZJI%HLHΈGF "1#YdSR)\=3ܓ18 +GBGGj?]$PB&GB +ZLfp=>,*.-+'lim&:24ӝ"VVR +@HaZFNABʥ $$Ƚ$2@2YU9ɪd +$mۚ,} T:r3v8u#GN AHHLT:dN  …Ѣ-!#!q!o$D IAB/!BB~B~L6yreiqanv< 95y }aY&^Qr2?5"Ȭ=\DR34ɸT&:)XH +4$rMR<Ƒdi:b<>2n2sO IHȼ|D*S(U`4Y6P8B+jH!;zzGq!!Ϟ; +!LR hS@!Ɉ y*Es cGAȉ uUe%EpA0]Nj6:Zˤ$$H6!DD#`!`d"$ $J&LI6%yLadz\d%ꘞqI<|$$eOHHLP5ZhX +BhqIYohjnm&<41 ypqfn~aiy2:6&}bB~F3"䧸XDbBT!o !\ZY^\B!Btu45U12~tجѠjTJR,!"wov")4$$~Fnp2|#8), Y|%!{Ҳʪj/2R Fjw?m (9=37D,yYB~\ yAȫ)!!!Ono'\^\!'@ޞNLp](Bb2uZJ!I"˩(/+9"dH V"2d$IBI&&;$kJɢ|L) GvpdFG\4O`i, O܏'-$,-pyH")jVo0-6j!!MLKX< y2dB~ \B>!B^! V@irtxhkmnj~rحѠjTJL* %dF}#[:h#3|LLG _D@ I%H +\@(H +ZLfty@llj!{@ѱc J,X][DBDBÄD IZZXl%_| nFTDB@SkD<0?;3591>62<4P >,fAը +T" +x\%"1"_M$YFdP2dNҘ(Y,F>+rY<2# Gh$l$pHǴ?${BX"+TjNo4Y6kpph!x,&Bp I"2х|'%[B&yq$j"[Y^!AQlijkCrmVɠiJ\* |EdyΈ"_f%2YF2 }4'W,J2"hܻD(#㑪cA6Lj#cx>}$$; y%$O I2R Fjw? ՅȁcSӳs󋄐ǷgRB^$u&.;w߻Md8!ф|.&Iȹ驉cc#C}]-͍ p](XzNj1:ZˤbOC$! "HYH1wNR̥$YhF"ȜYyyHñi:\W }aZFNQ)2D"""GD@d*#B$$}t'iL2+$SIfd#2r@|>~#SovfzrbCLkDLN$=DO`#F2ĕ1I:J4&)J#H\? 2ǟ2}d呪#G6qHGGb 1 #3,+B bTP5:dN‘Xonfzjb|D&t!q"_d!H $JI%)+ #H֍\?>qG $y#UG:#iH##8؁D- _ȱɩY_ KdrJ&p=>0T&+˕jќow'g0!/ 9=!o"$rP!BBކ$'eLȳ@% bn5jT,T2Cv:lVɨi*\& q0 L뽉3D$WFd +Iar-NҘ(f$ȭLuqm|b#` Y|ā|Q@b *'gx|H,)*Vo0-6P2 rVo] q i 䅋`!B^#\^^Y]Dțą?!/aBBB.tFZ)cBfRD,>[-fAըrT,y3ӓGP wlDnD74$dIL(Y(X\/l}d lHq0}$$$$񅜞 bTP5:dNÑhHHR1I8>H&JBH2FrܢDn4ԁ#z r?3<@$JZ3Mt{|@(œtR56($\OH(!B~X RՕ徐0! +0!O!!;fV-\&Jcp0z\Nj6:ZK%b?7;3O0o&/,N$$!%Lr4'LJ2Dp#Dn>o#a#|"_e +BH$36'QLBJAr0OrȭG'@"}He# T8Hk@򯌅"T&WZhXmH,H3|TM dwaq iLȋ}!$#\ț@@ȻC.䰅|B~s7!ɉ$ rjkreD< >۬fQӨU +L" Y|":D҉|aΝC3v%I +JDH#$-FH#ǡ:RqDHcOG*1 {>r[ȽBN )He +Jfp=>0T:+KjtbB„ *U7B~;+VWVp!oCB&L$.䥋ǁ] d^K|.N%H8{=nnV&r1|"r`$I}&N %IHIJGfS,FlV%r#D $S}# CmFǁt>\ B +DbLP5:dN Ch,LgB\ցNwty|OH !} y y)$$B!!"B~=TȻ}!oM$$B^<~_G#f8Zn#o#+TGאGG2ą}[Z;:{}N‘Xp4O\BVC  y" +y +9==s ;""$7TӧPcGA +B +\&Jcp(yܮޞf"Wȿ"!E"W" |IIˡ40+ɯj"v$FY'Yk(iGE,[r߁Fm!}N‘Xx4Σ%4((+oQa W^SH\Hrt!;}NCh,L|BVA$Bj yrjjzƞ_RjS"}A;Aȫ(%FkB=CG!GAY.L:"P]}=D6'rf2u\vq##|}M*NZBi¤DI3$\i,?&sE@.dRQGG[q!?0.dk{G']H Ch,Le@butuv'o8$DBDn""dF]IMIIf'(eN("i2H sq"YǗt%(GGSnFJ#rQHr& +䖭$,X]B6k r{|@(t&/K 9vD!q!9!/\R_H"FGF!4w=!6T}kffzj +9 BN(B*I$B~z9@>QD'H RH3"7Q"F]IMIIf'(%C8i H0l#ZE'@#˦(hm48: +<}d}\> 7nq!;{`!n"X"ds"Y!G@HXH y JIBޝB +Li*5 + +I& 3Dc Y!K|.N%h$ D:'$iE$l o'73Iv%5%' Oy&5%MTFRjHBFD04Q@e} (hm4RuU>>B@M[";q!BTV˥b!ͤx4DzDvy&cq"o#iNoHȍFōF]I$aN +PJR$&H#YȺ9g% (?>*c} (hmdmqTux$}\>n @ +HXHrNrO 郅 Gcd*ɁeBB($YHFSrBNMMȄp y"eEHa"'OQ!r\,䳙t*0.:DL$iE$la#773Iv%"<ơ1)i>2#_0H[@J| +G~aU6r4mqTtdyTQq }@5$,nBÑ(,d*勥@ +B $YHQ W7T!oS!)B !*Bޗ 93=5E!'t"!a"AȱQV!K|.щDK&rN8TH 73RIzJ%&2(Cn=Wyv!BQ+kt:3 HXc[RKR +-ȾC–H`F-I*ĖP}/ȉ <ܯ'&?c"H=YHiSE#'b# #E$BII/BiuRfң(Iiw #6,h!+E @29f3=<:*]C4j6&G/G$9 @Q@*!PHr +ru@!B!A!OC!ϝBC!(UH. dsN-d/J2DŽLr!)$H&$$| !ϞDDD$r$r&rRL$)i9d,| i)"J*&uR6I2#iHO #"|QQIptd<}>}|}@ș\XH{PXr(F^PPP#PȓP3g5XK $+.\ޞL춅|Ԁ,T!{l!$d&D-\HH&$&zDB"AȪSȣ=ȝB rY I@.]@Z ]ȽPCPP*(,dB2!H)[lg!>Y!QBB" &$K)$$ljD!j1UÐ}v"7`"B"?\D"1!""SE#'a#5#)?E#9IdJI^$U$HF r`$o|2 N 8hphu4y}@@yA   E!<< +<<B66Q!QH\(d+LB.G\/ WB. +ّf34DH.$$D51!Dn,D^"1a"KHi*lIGI^I$3rcEFٿD>q"@i@3x#GG[GcF1G]GƣGd@ $ W~@[_0  +yB +&iB2 !dB>v|W]I!m.H&+(dC= <YB:XiF!ɕ4ԜtBCuR2)+SR"94rHT#FLd| > #ɣ:ͣ $Y@A@. $ ׬ BBBb!/7B +H.[Rv[{(d%dH! Bv +!SvHd"DH.$$DQ"ϊD1YQ"1!" H)BIII':Iv$ ##9jd,D7ȑ<}<:pT6hT6822< $ ׭G 7n B^B^Bn!ͷQV2Lәl6ׁBBZB݆wY)d+ I!DKjLd&-b"7`"HL 4\LDB#F()TJʕLjN:ԡ8)ԔTt90yGDr-d(Ȱ!m }6hT68r*[a $BnB~,d()L;- d)dW>!p!5 K1 !өd I!y"HYO<>"y Eo H($ D Egt ɄLBBvz! Ȁc +ȯA/H#f2$$$2 !) H@ H($u K<A3B޸IBBv/dBEȼD6BvY!$$yK$ +)BR"/:<FcCb(&*)H׻̽3/0?&DD6k"wh#&Id(IWId#c"g:D~pD֑Hrr@dG]VGgc +F1 +V$ +@B"*B-($ ށB)! ,d +yd! @r,EHHZ,JBDvvP".$$$%'DWHE$$DD#"p)td&7i; qR3@F〤k0r5 ٠9Dg"6RR|\>u|\>>z,RBvvJbT.C!Q# ,d +99 +D*!D*"!HHd"04r52fEWR2īu2EIId#\F.Ѝ$ +& +9r2D֍SW1X E *mCI:::6f8:J}CU w@ Ƚȃ1 c*$ + @B!_ +H +v,$9 Rȉ2#@#yrZ ˥b00Bv: &DE'gTDb"HHdD#@h䃍>%&q(C'E&%$e$׃!#F.F2צye"B S(dHYHHb2HF&1ʣQ11yHqut&y u8z6树m:z:<>r }ǁT4@B"PH +gYWHRBvu\Hrt  +2d!v%!m"Qj,(!!]s&^"_=%H$@$6e6rnodDIɤd +IͤA()ԑ 6\l\J,"g=UH  \J@ M r #>>&ؘA_sC5f;T wr I@B!HUH +@R!_lkG!{@RBS!#ZH2r|rBN!#ByA2X.:=6J7SN"DR">2aѣ+I4cGGd |< H($ @R!O +IB* ۰ d?rRB!AH $ +9-D] +)i$"QYBB"0:~#$&RDR"ӈF*"t#;[H}dDI$:J餯$#ԑE52UH ry]ȹD2 rGd yQ % +2!GPG11Fc1[#h}ܮ}ܹk +^'O d Q!3T,r!BB2u$D$Ld YD˥b0DS"O%RɉD"u"Ӊ|FFn'#-\I_IfdIIW(:P$$"u#Lb"Ayu>"gDi"3L +9% 2*teoGGmc"QGOG#Q , H*dop![ dP(JPJu< 9$ /!H_ A!$ى<lj|=FM$E$4Ril +4H6\I_Iä$AIE-1ah8J9Gq +!H ) :UBrD!GӄBF9%R )D de\F!M";0g9gH\D>EDB#F*#j#wIQId8)Ki0*]I$ȵn#e'm& 3@ +HgGGGG#hmp4:n:z<657kQ<s) +it +y +نօ,K%(d +9L4B^?r9 DT" ]VJىtBDB#ǸxF +$fWIfu2fR(CvBhYo$\P9IBj"/DNK!] e!] E xx(qdiǡm8Zǭq'H>@G @ +!L.Y,$r + 9$ +BNrr@rBVAHJdJd&y&#X"]"ǎF*#FFj$[t%$BKB82Jr%5wwd2FFƉ\MLEyIt!9 g l 8>nb;#}<e'DvEHHe$~$ F2f%Kq2I$*)+")FD#GY;2 'KCd.d/wz!~dyg&n rRd- d#>OZb1"#Ҩm~Gqqzy02B< H ٬D![AHdqںHDB +$,dIDM$D1;ȜD"a#"e##C#I^I$:RFNz&EI\Idj$1ddj#,D䀐`"…ZH y H@H<>axy:2|4i8Gq1ȹn ȥ ],B^,Zȫ^ȫBd!D6DocDBfV\DF6FZ#ɟf%YI$:@ (C'=F)AqA2edY6rm#N&+60<t8lG#8ut:<t Fցj#+a#F"sqyˁ,Xn!ȾȲ9  Á|1QGcjVFOH:<"c1ȅ25 L Bn!wG2I\ȏ`!e!- %% !s/jDD:!n"O'M.7H2HH 6rHkd=FҬ$(L'@J e8I$$ MdGȱ`$mdodl$9|8eE yc//d. '   +r, #0iG#lc.F1q*ͣQ8a~2 @k-q e! HY;h!e/MOBƅlB~^Xl![IHOdL9S<'L4DwQ"7+W9a޼s4i$ds8OA&EId1##F@DLd)YDj!fmƄ^ۢ @ +$@` @> +8G##Qh2zcJǧiG1 $n=BH\H܃ yB,lc ? GIDa"D"!5oEBDFL\ď-Fz$Jz%IpCH2p0JB9| 7rH ,"&O$Y`"&y @# Bf 9@1 0E}$q\4|G4G#8'1e@ 7/| @B܅ ?x!B6; ?l ٦ +y )Dىl ̜ȣn"D"Bd"d!"_@"a#׬V5!9tJZ&O2p3)J$su0m&r9w)"$2D~e G -d,$yW ++a n |,ȣ֑ph2ZF1#㳠|l> 7/eI @Bn߁ Pl!O^BF@26KOJBZ"/dLD";[c6/"kF&F.ZpF$ge222 r3)JD24r9Y[[S]]5jYDDDYFD=p"2S @900dUUuMMf Ǐ'>z-<#6fdt4G1Gˣq%4+e @"/g ,{9BtB2"B$"YD6&L$yN$]""N[$62!rl%HFr!VR1(I$$!Imd0rn$92 4D,%"{DvBގB~-$9yk#,@NL||21GţZGch'47p$<2ccHr JȷH\H\ȝv!Gd!?-d y)2D3bB"I&ll"D܇DD u$$6rHDOtJz&&cPR($dɸHLdMuU'rX +^4B2${N]2   G=92[cGGQhhhGGGzAGM0q ! q!ܳ ,B.dct!/Bz!/4!!;8d"ȽH"L䟈?X"@"_E"a#7F˽ HBүQR$(JwIIbėLIo0q67[7f"rDeE'r09OYFY]27N,dd+}䠬@ՍG@$>Qx t8j5Q8*qg6|@@F }@B!-Z!{#*o!G*p$ +i'0D@d D~DD"?WD͇:$yy7 #w$$E%钊IȡN*&m% IO$ #Kkh%"KH"DD1'rXJdtBF]H 2L +Br) @X di*Ѷ'&Fѣ#PGG< L@B!@!mPN(d +9 rDp"Gȯy"(@d D"o#_ !D^`D#Hh Y#-#"$E% %II%$SIb+˗+"_DΕDB$r*+D!_a"ǒO Xr*9-9B)i,r2/ORqc5QQh(i4eT46r5U9=}x-H<@ @s1BB!;ݢ^ |(|e!njV"5!!K"[Ȼ@d#Hh)ld-4o䡃o1#I##IIKJJII$$Y,+42" 9 L "z"9O7 Ɂ d@&D d&  W,**.))-+sQH886I#(lT8JUUǽZ :,y>,7$ +Q!v!#ǴSHH.䐉D-7&Y<iT$%M& J%Ĥ$!鈤0cjJhdnFbE"r$2ȉL$"W "'%2:!(8Br|Y@dr  3L Y@ Wrǭ裷ģ‘+aOMGʣGq?<iȋြ@B!H(dЅ[^HS!& !r+CҙX$"ۈ& K Hhih;Z#k>| 7r?i! 4*ɕLJ'TR:2ɔt"iY^qÆ֕FZ%\DfzID0"%H$K$IBN~9 !S,dF@ h@. |#J.=:5:d4iDmIGQGΣqGH Y@$G@FVGBOD><_a")]@dkkK3yG#Hhd=4 4jdx#9F%&IJKJ IbRS]҃$HO#C9$2 DN!"G'c@Ho!0D!, +B + P9dY@Y#~>>zy:874ڠєѤm8:<=>>9 $y|@^1yC@=}}$ +2l!-!~D )d;%^$"țDB#߇FF S<~њ#|F%I餂ҒҀR;i1ɔԐ4(HFb#@dćԔP(`"0S1SD"5"'H"|Nr@! 4d*Br%\dEEeUզ͛l}}Q=h#nʣq $y unsK - +y?B>d@,]H~e!Z"5!H}ޞnId  ȳoFZF"hSdy ?+t_O!5!'R +Y"9=7?҈Gdy cZ#u#s#%$E%-%5&IKJJIɤ$M҈BG#WD"_C"_q Df)DhHdH$H䄡Hh2d!\ȧOB1$+dJ2r*r:+ŦGԑpt(itȨhm7AGQG+ +.  +[|\$E$)q_ׯ_Cd3Po5HIDҨIPdD( +JII$*@#ɌF3# +x#7FFZG$r6D "bcbx"d"r"BN@'B&'d9\@@> \fd.d diiYyG/JGG4GKGGmG㑣u@n:+W^~]Á!m +9GCi'_$R''"Lio#q#H}F%%5&I.)NxI II2=,*~=\DB"idN$%L"YDFiDrȉ WȐ +KLJ Lr OZrFBȒԑpt$lp(y}|<}Ryn@ or o*#&0L$yysDzɍ|GFRTR)1N*(]RJ(-'-&<^#ʴFA#7l"ˈ%&șHd&ʈLbD "y"DND>hBFI!5 z! + @&d&9ǁ\r@n,YVV^YUU]S|}y$Hg!B~#BQ"S": -ϟkn"Fw]H IQI[I`R:JĤP/A#Ɍ%%#++E# "_D9̚DIx"r*'7O݉J!&2XHG!$!K!C21L H($ $ _V@@nD 7E"U,[muqm JQب(u|Ky}4>|4y>@FPo7Oty{Db#x#롑hqHVI$gpRA+II$4r׷1#kjF!L"W("_D.\@DΚDf)DFd\\l 9e'BHG"Y +L-wBZBBL`LBgd XHr ȒRȚqq/hw:.d4i6j8o+-=>O*η\hmmkoxR. { + BQ'%@&%җ";;Z[/ ȓ'׌<i!IJYSRcpRҒRBpTJHHjF$#n卬F@# @"_zQ99H" i$1Dzt9BԀԅB22 +d@fs u WH sȂBL$sGGGe_h GKǿ'z + ? <@~L@ޕ@BI"J}J]HȾ"?tIllFFFH$J:D'J[J/rBIBҊ!3#kkE#˰^"iD r\"2; L"#HD3BXH[HO)d/dJj*  $RdY^Qr񧺏fG#H8lKSG G=Z(Hr)H/D䧂H+l"FFC#FHZJzD'P*)%\I(;۶FȍKu"/DΙMDN"SSR2Qt 6B~O2BB&C!33fR!H* +@[ܵqh4*F GGƣ$H>@@ ;::/F(4 .2t"H‰D`Y22=iItRA\JĤP򗠤$FR7rϞݻ۷FVB#"7ɄD2!ȌtL$#2>ޕ f"t&1D +!r%VH)!'B&b!ӰYTHRtYRJ@Vȝ,{>b<8l4*]4 +~:GG)4( +D 8 dBB%$RDg`)H-I_%II)NL&2{HUHF$4cɄԉdBr"ȴTȸp|'R +9 9rGH#$dKH㩐O)d2 I y!%TH<dY]S#rޟţ4*|SGG_Gy dw~C@]"tkj7 +6}m4iڪi6<l0lZEiMKtӨ&!LdA&KZϹs=}^O/_''# mp#wFړ*ə$'%BJ9iJ"H2#[ZLlnР|Ut"!9Hd"5[Dև'r"Kԟy2B!K\!PȌ E-v\_2 Lg/#;wlnF[| FG}Si$A=>G6=W,7[$ +@`!Y'h"/H`{Ha%et)($S2IF  DFZ"$R iLD"?ͱ,lj!DƄ\ xA D.S|!]!AB f!H _ @JC؇>JFG##s/;Br~H"Mg"="A D^"/l#HH1ɷ RIä'eJg(JIɐ#留ܭ6|Y( $|f۶"&rM$ Y2!gT  [H#d,;Bl!#@XQԤUt8C2A2*Gq| y@^7@$ '@>BfHN$y+H$I5R" J:/)TN*(P +)PZ&7ȃi#4D8($=DZ!WdB.ۉ̲B!K"BB|.dH\H 䫿D  q [log>rG4hp:b: +>"g@ yMy[B#!3(cD4 Z"?F")(i$'P;i4JdFvwwuvlnVDF*"_ )D/Ȝ2 2&d`"!RB* K-sv! r}h ے| wFiGi>d@~f<W! ݅4@BΥEO!r""?C"/#`9Q#H$PIɤrRB\ʀĤRRIȎ`#"j"a#3Ʉ$"!wDn&,B$!K҅\z<GncF+ѱ'ZG1Gd#iV ow< -r2DLHA VV"?E"ȋ|#FHzHZ%L䤄2%s2_OR0+16il"rtD!DTWU++AH ,>2QGѥbF)ZG#ca d $dQ ,j"$"']"o"'Cd#i$$=%LI \JJeR)WR ۓIYm$ 9m"S&MdNLda!frֈ̲B!K+ILB~;Q! ٸGy i`@t8FA#Q#yR jv *r! ȹrF9M$YȫH02LcIDQϨ$gP4JJ$i$ȡmmHȆ84DDnL&rNdH+"$!K҄ˉ\ @̱ByHۋ> D}D GFWF6Fe#Ǒǂ>r @yR./dF!'$~ț#1R@R+`:)dKidN2% I1~ EMsz"7\CYYDFLrIF!W !ÅY@ > dKK q} t|ud65hp|(u4<}|1 $ YBαq"BNFDƌ|t4L͘N2(K %2ɔFVF &FFFt&!'r-N$!3 +\O4B0!KQ$ZHrt٦9<<2:j1zG{ӧeT46ud8j]}T>~h} d@q@fZG9Bl"PHN䝢 l$!鎤@R+ə3)D(QʥtLM%I1QHd+#r%N%2DYL:Ț*50VHEd)IBH!λ@Z2|r^ȍE/$,d3sx8z6id2Z%GQgnZ#d扜D"'cD^BdH> IWIɤ$2(Ĥz##z#{a#"a#="D2"DZ69o"KDB.Kr̲R!W !BB&BBn6 "$lD @J ȣyGcFec GQGct 3i> +r!,dV"D'"Df#2e#]#πH3IP2ʤrRB^J17/HF;rmd_"Rm$#AO$#&6DD垐eZHM +91Y\RXRr5 Ņ\or[4@B:@& [i|?z#hl dd4Z=2%vсS\Bf$RLd[Q"4Ҏ?VwIex) J$2/F36r62!#RM$#RO"2DnUt2듉\YU!sf"H!J!K+l!s|Uu"d][Mf!B Bj a!9 M=Аȱȣ(p ddhiT6:hQh13/23,a|"PD~!t62HFIŤs04Nj&QIɨǎ398L#RO$&KOd"DVyY', d +L )r%) f^ȧBnͲHXH $,$R-do2rcO }$GƔid4ZƑpd:<}<<b P )|0 "#_"ፌHvJNRdN2% Ɉ'O8~|XbȑE$ldHHE$NdB &r=Ndm2UUJ2* )d.|:.r]"d}=,$ +Yh!@ D Lr`P9q'#G#hp Ɉ4 +i Gcse# U3Ey -Ù-YD~BG!/C$m6ks[=Vg?#33sfdwaQpAVM6mm]+;̰hM4QJlDŦE&g}ϙafW.4 FP2¤$CPJ`R+!i,6Y"H$ DDi9S$٠Yˉd!'UB9bBB YBVBi!A,iBB.Ѕ$ $2_0?/qu8h d48Nۨq:pxd><Ɂ<>K @'ȑ/D^Y>#HwGER(ifwR4N*&Yɨ]][6o޴\sLDr"HN䲥*wn9=5_YT$!u,IR Y1t!4@ +!u!+RZ2@&籐BPH +@b!|ic|}D<2>BƀFGQQ(}<>>z$ % +9LOp787Rwe߬FII$CjʗQ +&YIBrd`i/@$62$IDR"HN"921!u"; < +B沙 +Y Yy(r+d 9I IՅ!A6PB!5($ $ +H(dgȵk@B]}i|ͣl pDMo&(J5 2JGLoG|<)h@^I:ryeD~yVFvH_ RIˤt2eDJIŤc$=_6r$rCHN" Db"WD.s9['&D0&Hd.dPZOj%"UT"GHHdU,$%d>@f,d -4UyQ!H($ @b!#@n$ 9;v u<ǡhm$=Syy,@^(KI@BHKeyAy^iTe tPNJR% ]]>O!*HJ$\y$3L"Br"6Hd3$G!k7% +YN" Bި *$ +Yl![P| B + + +I@B! XH &GrGɣsGi68"ec><%Bt ǒ)D!?,Ƞ(#F*$2dt(/;wFvw%*HJ$I|`9*,dr";;:PHHdK2ktYDJ!+!#}B󄬌 YBf2BrJgp!\I| +I@B!-doȈ>GK1Bo1Ǔ@^M"H6SHd`d +RedP'TIdh===%DoR"9S%2MHLd!lmE!r9 9 D] +GRBE 4u*rh!WS!BP@nj>g- +#:ZˣQ(p:<<*O @^@^"/2Ld!N%IɒPZ'5IHHCpHNObDeEHr\rި;㏚*7v0%M  x_33'jJMRIiX xQ>kTQHEM&*is=s>̈́Dz + \!g  cҝT!aB>˅L\b Ʉb!!$-$Bc!ʱ5Xzk!۬,$ iȳ/d>#&hhы0IEKIȕLȵBBXȼ|,dI YB6`!B/-$-@b u><::8&wFm=x|k % x BNDN/LD:c4$՗t3:ͤIHk#\ r$/ް'DJy@vLd و a"!dY0$!sIHL#:$[HLdFrKȹOO !gBS\HB2!Ce$*&:l!!$-dN. YBa!#Xȸi!<R, zHG27Q`#QGƣm?@~}G c/NHu# FVdHVRR3irR/n(U&%%-$ F6R#mH1 Ol"+مlD6c"15HY(D۶2!7r-rtҼsL\̈́|y]H$$-l,dA! Y a!1,d;Z}GB imo @|yut٘F#LGO}|DQޔ>'rR4n +J:/fR8 |*l$e#DK NYo MBη\B.gBfr!\Hk!XHB +B!dS يB[ y[B*@ JQѭFFo9hQȇrD~sDJi021&%9~NjP~fR(i#$iaH"!Қ&={01ݘ6LdـDV`"%E27ܼ I +&BNR9^Bz9ɄY.dJJjZZzrr#BH,$Bb!ʪP)`!;XȝB'Bl!9=#Q1i.<&1@@}|$DޕO9 @A+fR8 Ik$Ft,"Չ|DDDa";1qLdB d%,2{ FKHDLr%d + rYȧi q +9KR,kB[H<,BVb!CXHs4omBvc!c!X y\^Hs +##cc׮}ţFFoeyt?ot "LHHO#=sRRvҭHi#FGF"Ͻc R40{1;0=vLd,PTUVK%2ʄܰ[5LBȌ4[H">BLșOs]B.\JBB3 +$!7gAȜ\Y! +B걐ͱxk{G' ߼:p /WU @*|Txt(ۘF7zG 鵑F#Dҭ`줪5b#oFޠW('gDDDDb";-hYA`),9$MLgrr."s \eL\_d ɄHBn!!d ,5Hs مBBB|EZȟ I@^4yiţl/ +::<*2 ȉM$iHO#ՑdH()4; I0϶.mL 'HDDDDnDvwucfYTUV@,Hȗ.$M$ r12u 9/ !3Br!o !yBWTUԆ"ͱ8   y yGB@Bv47]hiFf GIGO?y >NS[#Bq#]F#iDҭƤTTt)m-H+$"ՉxTum|߼fe=y4h/ odj 9A"F~鹑H42;I?Iy ryYMDDDDDDtwu[bHSc}]8TS]!" !dm!dBf&!i")L Uȵf!_dBn !I¢@iBֆ h,׿c.,~,,IZӴ{ um 8zhhѭ'X<}id"}&򾉼cioHu$HLz9CfVRER3RF*D^eD^Љ:M4/c"b"`"wc"zn}5Y BـHp ^UۛUҮ-ɖ\p :Xe58LB.3 W\d&3&=9]Y-|7f5V!K +Ac Arr;rF%!| \%LB>|XYȧ!\r !׭܊B? BUZXYUmX5XzXȦfXn!O -$r@rTRGGIl$hdHȣ +>*\B.HH9$CI6JCdRPGi$C@G< $Odz"{<&&&2 +zNGj1WWU:ZBGA n$6N l!ߑ ' L!z +B>UHa!I!_|r-/$NQ#G偐%*Vg!Mf^t> BFcqXd + -dBh!CA! $}$xt٨"liyTQq %5O"YFmd$Jd;1I#IIm$Ad?G~+My~"DLD&`"0v9j6TUijUY\XB![9!ׯc 괐+%!|yRE!ߗ ^HH} a^Ȣ2Ijj;.jÑh,BBB8GXK2 ׇr죌G,Q###>*rHDfĐd(f2 _ĕđT0'r BJDJً&h!R01P]Nf5+V(Ä܉ v ){BrAB> D!_rGHȏ{AC B^HF7Mt{@2'a!`!;`!$$fAB/ +:)Og"ゐO\! * IH|!)!B,-+W5:lk.@h, lmD {_r @@ @ @#6J62qty1r#3H o)$JLNRC)cPR@48@0"r#ĈT3h"DD x, >! 󎃐@Ƚ BꗘPB|[B> $N +bBn. +yd5NCH4!S $, XS}!($ȴJ<2p̶":<1#@M!ʈ̾L#ɑđd)I2)9lNRJHJ#o$c@5 rILn"A.&&2Ն8!]b4u&ǜD!e)|1^G?Yϱ|SQ ېA QI +Z!N CuH,oL`!a!BןʁrU$,ؘ H_><:qre:RHBQl! +KJ+T`6i!kQ1 + y-䅋̅@ 9< yrbBH,)!m$qH#c&\ "628$FI4o$BhkmiN%X$\ +|^H Ņ<*;- + r$[l!BnEB!GXBZE!S d y4,$-g/ZQXqXȩA" F@J>ԑ1$,3cց\@{"s$2 IBI1I(!)5o$M4O89!DB^<{!A&>j l4tZ (,B!$d^~AQqIYyZU.j"X!jjimkꆅNJRHJq#"D^&rHN˗gπ dG{kKs*XG#PPnYB#Er /f$r/y%l GbDCcd'ك!䀼",Z1XIXٹ7@b>sDfHّTRd'eL2oț7fggI rlHIHH$ H^S!-r +BV:ZU^VZ\Twr(^ȵwA+)!Yc +8!+TjNot8]/ YИjjn\qq| 7<Aۿ`v8 IHBL5a(꽀$RfM*cMM&/&/Lf=sՕ{џ3/  Br (!((э6:< +'3!#PΤ+'y&%HJdlDDCD^"9C$q` YY^VZ\Tܹ=+st*իVʄN Xv!2B>'("Xrr)N5Y;!+*AH $IHKH.!PB67{^ G $HG +%6jput#8ŀ {H!#I&8)0AyH;~4#"tb o3> +<:QJGW<:( ًtO:#FB҅Z'%JHR#7E3RHDd ՗ DS'@ȽDҒ‚ܜlKMTȏdBNcS C$T+7}Bܕ_PT\RFEBց(!AH$@ ;|yTਵQz]d3D2Ron)#idV#"\D~cH, A*n^ۨS!.p]H ~B!B!+\B\Gܺ-#y D i42 ow-v(Q"yT{@0.BDR1)) y06H6HHiDrB~z y( YK,+).*E +r>2iVB|d' $"LFȅTUT͖yEťDVHDH&!LBlk)npGSG%|(ۅ DF:=%-%LjsRH##E"ہȖ` FUHHHC3GUYTȍTDBȗ@ 9Or23kNFJ"~$a$'!$ JH]RGd"CH&ꔌ2$#F~G3!7"KI< +YC,-.*J\G\!ZBB"҅#-dbRr%rG!!O!QB +B^IH ـ}hQoGSG5![@!FR$äIv#"ly2HK 牐'AHDJC];BNҥq=$d:2'7 y y B^B67ӄl )$$xO#c7pC@&Rv# i)-&Hʌg)#HfWqD +B y&d&+7+Qg!d9$M'!r-+^=g !$B^k!=^/I3!@|dyutQ=-r!%DB>m!_ Sȹr!3,!KJ+*w˅D y*ك IR#ϣDG9t')AAIELʙt4y_E$v#"8"$"(A$o 9J/|D4 ThBar]K\B!7 /Y< +BB^ YEBFBv @ޱQ1<Bd|эcB~RZB64b!}HȠ!"!|@J|y(QTG#c.2Rjk$Y%ULCʤ$HL=B]4"[[^,$H +b9r,rFȗ^)cO!B> B>JeBd +B<!/~m +f&w9 > +<#|d}q {P"R2$&H+#ӈ` !qDڅ< BEBօ$<|rȐ1!a c!N1 B\ B!׃[@ +!Ȅ$ i + B-Bځ|yQ +:ѥ~@R #HHHjT3)SRkH[Db!o׻:;%B^S y +Y YB!Aզ 4B +'(P, r@ +ٟr9hp\ܐ[_QO^$j7qqW\gaEEA@pc_fE}K4mҴ&(iOӞMz>޹s܁ +oPrLHDʄ\ I.d"LBe\ Bʀ (ѐHDH:+黒ތ6R$R{"{1!]#BvS!.gsSc}]m5%BCl!8b6EGF!CBΑ 9rTs|BN|W*{sKD!C&j; d +̆B@JY][WtDȳB~F!P!?y!Q! 㣊Ǿ(0|@D"BILj 4ɞHQg yB<.,BA #d0rRY!'H!䰁*0BN +9[!\*d0\ *2 Bf@<Y!!d9<"T+TY) +HBz_H9 "B>!?s*< )((/+-!wBȭ2BnV B.Bg 9C&d``8M!J|K ! j"J|Dj9. 0P.LBɅ !3!VB\NWy!o%dOϓ2!( }_tGHDHߐW-% )HDJ|R|O~ IR%)*d[P_ !B; dL X%r!BH!|B2M=!A$/ADITL!, ""dxdT9bs'@4!w@=<!k[6*)"y)3*g!]H@}d?<d?H%^VROI,#E"'HO!/B y B(?PB dLiBn$B!䢅<5,J!I!j!r:/H "B%BnBb,V^d!A]r?<!Ʌ< yB^)L$/] !# ߕq@_"Fd_қd )H=2!kE!OS!Z]ΖƆ:yXr/,2B&&bTur\L-$/4NȉT-!!˅|G2 +9rR>Tr\G!iOH2B@Ƚ Bu M-NWk[;([HL蓎}4 #UHz[I/J!0RBj"_ЉB> y_Gț78!/!!BVCʃeJ ḋ2B:q6l$Bn\ !P!Ȅ|w6r d'X9J"%H XN AȩTr!\!WJ6-V[!S3!d>,%BVK"B!B^ y}_pBW +Jȟ B~8`7}4J*BRnH\B䄼$r675C#BCB!3 d\P"dr 愜7W),*9BNSTBΛ!!*"d2T.dRrJ*ܒ! !d1,Gx!.w[{yB^B~JϽ ' H~Z>F 鋑}C'%;^|!BA!$YHN+!Y"dw׉nWKsSC}] r7!dgfBx=f1"#ˆ뉐!RIR-L*d^@^ +!GB3,x!G( !BNBd B.]F\M\O 2cX#>1i3̄[, !K!dohjnq[;BWx!oݖ _AȇDǂϩBzZH@}Gumx 4h$IJj#HA' + "=B>}I$ I +!ϟ#BY[S}BV@}rg[r dZjfkĘk 2- 9!i +).P@7RHc!{r"mb 2 B@rOUoh>yyB^ y#QHn"UB>y۫B2d>雑YID'RG!_ +BS*$ +y!OQ!ZΖFyC@}{v dLޜ 2<,t#r-rr"EZBN焜$r #^Hd)r'tAHHQrr-r#c!drjZzf֖ܭ .Bjj F!B|ዐBR!B!/]$B9M}۴e`t/D`MgLkHHIeF^[lP!!.Go3"!Cv1yoH B.-olB*x!,d4;y#%)ɄFnDoH!VW|Mh!s 9B~tmAd贝u[ RUI%bYL:J!oW !a!"&$(!}HB &E"!?+*2#+;$)Tbs<@X.KHHMݮ}~ej;n!1!a"& 8ox!I阀ǽqI䮔("LdXȷE 3qH{SHl! r|^Y,~WߍlW47u +y5BT.DBY :$炐 5$$,$0!OLOO;J$g!? + yHȣi!!OcB^H ߾!]!3sr +HdJ1`KRLT!VʪZe م4Mmty>px!gfąD M$&#$3rqiy9,䋰!"9"dBnrgX?#"=CdDUHl!#B,G ; Bޞ}^i XLHȞn]Wg^YUJ2)a3tj1T B^GB~P!< )dd! y8,q&DFBf"J1`K8R>R,Q7 !;:=~y`6dw?0<2:61yyBF&M!Wב/,/2d}L^D<ȽȄF&@2)%w42H‰%j"|U SL!a!AHXXɉё`]upl3{]f$d + Y^&#!YLZL!rAț7@˗p!cą<<2-"B +y ,䟉 X! $rs"BE y2~"1!/_!o! +T*pK + )GB[.Go3̖Ap=^ BS <&2NHl"?"?_\ZJA_c[|yL}dDnoFȄ-B#+$&RH'-$ y.,c v:6o贝u[KsAYW+UUJĢ2atB."倐@HXH$$BbBEB!aBAB~%'HȏBs!Ȱ#!?S$Lc I$YL瘐WY9"2J3YlEbJV#W)T-mvMV׭5͖mty@pxdl|b!?HM.U? p!=qO}@J.HI@dDF S#BE\@B>~ @}^Y,~W߭Դ[[U:ZV%Tʅ>[f1b +!!!"&$(!}XBBBMK}% $x!2Lu-2;2DJ&odD31B .h!AE&߅ZH-3c d]upl3{]m-M ZEMR* 6: aY-fWߣvj:mMZyMuUD\Q^&r9%,&F-& M2HL󘐧@a!B@n +rBDD&)dȈa"BASHs y*y / )Tbs<\$Hd5rEAҦntju^lچN G'&AșYLHh!|MQBn !_BF&2L2{{dD#F2 '2CBrc-$@.` /$ 9? 9= 9 n>d^}SӮnminT+jYT" |f14*\D*ʸB^Ņ$ZH$么ǎDBn.$H&$LɓHȳHDn&W@*$Sit] +e +RV-W*n}5Xaxf*Wloĕ;UBHHB&.ݻ"ɬ }ػf|3s~ֶWW`xxd4ohw:6d4J!I"尘 ZMuUY B;B R(ro2'dMSi"2&V2'ABi_QcA`8\@(KrRFS}cb:::{<^_ 80O B޺BBDȇDD>} +|'KBk2 >>G23#?dLHHELȅ/|@>$ $!!oހ yxdltd(}}nWgGbZM&^WQ+2V$lN(/-).܏B'"kE2D$ dTB& +B.ss33SLȟȄ\N%H됐.?7 yjb< + 9}^bY͍ &AըU +L" <.dk*JAHHH2uBB!QBaB@Ƅ\JOUȥHrgn^^.Ƚ{Q(TBBDB;~`\_(KrR鍦&joiuutvuxz|@(<49>1y"De($FddDHD*"0"0"Ɉ IBY!&rDfaLod6Vȟ$rr!>! #B 7!!\<7u $xdltx(}}nWgGbZMNV*dRIHq,&V Y^ZR\ B BÅ(dܵ,dbBP 'LD&$!9 BnG!sI!(da:!!"Q'!"+ "itZT&W4uZXlZm흮wo  Eg!"/@D^!!" !~9"((< +2eDf+@>xܴ>y !DdLIBC!ߐB%kLȗϞaB>"2)!Hې0!/F !C{\mjnnj7:J)Iŵ"atZ5YBD!1! !"Aȝ{!" +PtBBD'NUTVU  DbLTzlňlkpu=}^? OBDNAD^yoWD佸|JE ȗdD#MDSȌ@nrDfedZ$#2!Jd!|.!%'wdBńKȩ3OABFFGÃ`y].LHf5776 :mZ$Z尙 :Q"! !〤,<B{ܞ d +5I-[܊B$ˇ? +y2HJHH" +"dq H@!D`2[lvGqIiyEUuM"u޾ѱSG? |WDyA<=&RPR =KǗ&A%2\|.RHOB>s$B^%=CJȷ!'F)!{:;ۊlY_WS]YQ[-fAը9@ $$RXiX$(d<Rd d2bBPPR,<鵐$\Dr9)dJ)RH@$rk:r@daJ&pUTVl؅܋>G'D"<B1D FDzR/Yq+4H{o!%<r`O7r?iWcaY&^Qy9PH dVPH1Bb!S PX(B!B+d$UA! +FJ!eQrH,$ 2 ,(,RkzlՈ]m}C#c tDa9 HB$[R +p W-M#B$@|/BFK|BOyOȃ]HȽ{ZHȊR]TX dqBOB&A!㡐J2RH $-d"\@$l"BD*PH@d 2 RH,dzF"27/Hٲu"Po#"HAW "oBC0e d@)ZH? r0pB#d;rOsn$dmuU%iY&^U@mH- !B2 B(r$GH$^ +zRȵDBI D&"SRH!= ̂B`2[lvG1"JFD~#~r@1[F.HN *| !?Eȷ !O  F و(/-)FB=!d>r2#!$RXȔd(d22 :XH.!}r"Dz-XHA!eQr 2LDyG$+Dj:dADA 9;"_H߅\og!_BK9qB^c#C}(!QB,-v:lVhi5B d2!䦍.B + > B*1 +2Ru> fB7M$l"B"xTw!i"]Db!32!" 8tQD6/"-$M$)" M0#.#&" ]B~& MVJȺ*JHl2u +܎ܺ +)$)dj +2 +G +)#!ehan_IPBJȻH[_ + y!ƒ !7鍐Xd(d26V2UHZH!\ )D$-$B2T"c "inD 2 K&ՍZPH6PHL4G@䏞TȰqFJx!"䷮B~㍐ !$R0,RVQBnc%X!RIPxBH2B*G!Wrg!#H!DD* ")oJHRH@$_P@d5my1W HHL飐r^BJ$,!g7W)!/rCȃYtحѠjԄ ! ![@B@!qqr$HBY0R"!Ha!b +ILFDH,$ 2,,Ri8,-+ryɍHw"]D>DΊ#[+$2|\--I"R!ydB>BCBf(!/Bw= [#Ã>۬fE\$dCM LB&@!cI!"`OB.B +B2TD"XHW"i![DnDDb;KJ%!8 ("[H71w ! Dr%Z);B@=B>BBAB޼A  y!9$>!F d>rCȭ P$(d<RQ0BKȟq!x2ҝHH,$ 2Ro#`4Y68";9:r"=DYDybdy6$.$$r977 AG"@g!'KݠEIBB'3@@ȻH[ !τ0<4! 9nBnXH!!HHQB R)ZBI D&PD)($"r߈9?84<:6>yx3s "/"I +I DNC"ݣeԣȀ 0/H~!#37!g !SB @8.TP*Ʀ C_+MՕt'M4mf{yݝo} `} +)*|߻ y[U@ ,r +r"$ +$"$ +$rr"drmVɨϔR|Y ǎQ<%$lB _Hz=Bs}D&K%)Hȧ"#'Ζ)St(`4[v$DG5/G$NB$$r*B\ [W\#(dZ\ ABRB.!瀐($\B@!Q /B !}=@`!O?T< $)$!d!#B~];rRԈ!HB +#d?Aa"ȗCi" }!W0"?B$;7nDNDB"H"#h,_EdJ$F$+)Bn.L) +]d!q WX4\B!gn҄d B!Bt!>rmɠiԪY*ilL?9!B~lBAddƅz S2Ot"D0($<)"}&"$-2yR Fjs8]N?D"/ D^1F$JdT"oDNDA"iD + NdB2O"=1BbB@!@)D1BHHT (@DHd/2 .fVRve4!*+|;#BB> ,-Mx>DHToх\B徐|D\T!,d AQ@"_n"T!E"+kj%ֶvCb;\n 2 +w""1"~|DDDNDΓDЉ-Ȼ(YCd" =A_Crwz}`( Dɧ"ىBDNLB"gP" H4C*$Ht!"S\嫰2sB@ B@c1H <r9  $ B!Ptvl2uZJZ[B3#I&! I"d|F 3.d)ȴ +ȽT"B +F$"8K?D:Sv6&isK[LѡTkzlN]=}H@K׮cDD& I%N$rJ2#|D҉d"rQȇEvs,$2#B>drM{wI2 \B!p 1!Q BRB@^94x +N iVVv(dm-ҦƆښ*BS B%LMH(ѣSrw*B x2Ud"w D "?8u AdM]}CD&+*V7̀HȮ޾~@0B䕫H>"q"Q"!sEHJ$DENdFj!sݕҶb 俙 +x<@!瀐(H.!q (@H~ dW8Bz.f1 zFPۙ!|B )HD +"A"@ۀw "+"k%ֶvCb;nO!}H@KHHHt"oBDD.@"W"h,_Ed#'nkIdjDn2w~!Q56!BSHj<F"$@YIț@B!B@!!Ctwv:Vhk5j%!dTP_[S]I!]B7mK7Jȝ@ +r+)<^"wr)PTH6"؈,D$N$ ?È5ȷD&ol4"JZMft=^? +w"HHH."I"P"P" D;$ى`"d%2=Dn2V!r}Br'd2K@ȹ9)HDHH6!I 8# ]Pz.f1zVR*䲶Y]UYQ~ } ;o$J/eNHF!wSF!7ȯ1Uٯ;30{lML&{r P{zpIy-H4IMf9{v"#yy3N_JF7t{@0T:ӋBD;$" LDt"ry9 "gg\>_'YCD>"rYKĄ\G@޽3?_s, 4&rE 4HH9 + z{2T2FBq96d4R!JB$dgG{+4+! y݄IȏX@Lȟ+%"Ye)"#"ٌl!"R\Rkuzl.‘hˏȷBVFH|)S@rr +HH%@?;:2<8דN%h$ aY&^QHHHȧ y yI]$!/ |5@rnA"9#|!C/;"DtحѠjJ$D,ymgGIBn+&d-$䯗?!UY&[ȅ#򓊈^D~ȽC&Dd"'rJ&fw? +GD2ݝcHH:"t"r"sl./ϓ\'%"B>/ |"{@(Y @\6K9MIH$$ $@^#@vx4>,fAӨUJL*FB:ۑHHH}$!wP  nUB +Ed"r#HFȪ͂YMd)"܍<<e%$"e!] WDB@~5<ntdxh7ӝN%H8nnZLFNQ)2D,𻐐HHcHȃH=$!*&$+ޘ\,"9\ "7>6"ԈBGND>DaD䉓[Z;x|H,*F7t{@0T:70"ςHD$!D$M$;"D@N97BdeD|"U]CB63Y@V&$ d!e琐336:$$$K"HH +ȋȳr@d<v:Vhk5jB.E> ق<tحѠj*\&|^WG{[k @;z $:!܄rj'e"u݈Z@dELT:dH4H3 rDTDD"HU rDes|D$[Hȇ2RD.ȗVd-oBr$@>c-$ ) , Y_8 ώX4^,fAӪUJL* <$d >;wP@ YrBnL7BȺF_D-TD؉ܷyyTSs˙N_ ?yq|2vr0c0$uW{+m_z5`; w66HPCUh0/9gu )P4Zh2[mv]PMDȮnyD"ID2Dro.""G(cq9#rK!! g)< (#, $@ OƆH8 *iY&^ը +T  s3IBL܍ܹ҄C|g\jD̈Ƌy}\D&EG9ȼ|Dd "R +Zfp@? z";Ad)9@DD2D҈#ҏQJe4%FDn [I|$'d,OS9r@QH1@"!Y / ^ [d}m& *aZLF^Q+rD, +*d= 2IBd2)lB% [Kr"DD "ID&<,*.B)ɕ*F7tWU{}@(\S[W"{@d_?!r!Fd2"D^DAݻSS33|%2*2mMH@ $#<|93=5yyI2H$$0 ;d3 Nj1 zFReR1 Y\TX AȔ 1 RȤ TB.="HDe#29LD!BD!r'r+"7hk  _,ȇ,IqrI(HHȋT/-@S]r:Vh4jB.E@? 3 p@&Kȯӄ3'Mwr݅\ADڈE"rId#!Ddz"qDdA!"\ K2RFi;\ Ad-lBd?!rB9J$D#&955= |"!'u"q%Fl T qX g oGJ$ H$$9dy d$ +|^tmVhi5*B.EBA,.'dV&2r&n$Ν;> IlBn[DBOD?۱ȽlD$FdaDdf"DHDdR$ +fp@? DjZZAd!4!r,!D$G伐)D刼?/_JVDnV +hB. =Ȼ,7 (@rBݷȳC @Y ^O5tجѠj*\ +e@? 3 Hdr/Iy +͘ˌ/#"1p "w&I#HL@Dȼ|Y"JD*UjNo0-6> "@d3ȋQ""% +%:!K}B伐,OJ0C$"9J"A9B"-F/+$rK7'@rBQ  s< 'xQHq@"!Y )}ȓ @6 ۬ J\&dحϦ4U[bժED&ΌqTPIM&t7IM$(TyC30iVnu?sO4 WI@wHHu yB)!'䪥D +~D`<"5,"9LHG"EDHD$DD#"AD&H]Zz`"kq) D."bDRD*9̉pDv"K"W6W ] ny@d@ }q@6zYUQ^VZl-SnH]JrRb|\@F" ;w0 )!2$R@n& rRAEK_9F$#WDd HID""A$"D "c I) "͖Y"+k765imDd#r)y#yO9::6>>19)‰Wr".TH\lOf bBɅ ɉQ@# oq ځdBʁā {{dW'lM@VkQ!4dg2@&= ɁTIm,!~,!EB\fBޭ\ !?"WDM,"A""ՈH"18 "A1+;dʪ"[" HHH Il9p@Zdٔ 2 @&XA@G@A@RB*)rkKHcBnTH5K8!r6AiH_D$THI " !KHLJNեgliERY"Ad3l'"}ȡHND(ID!"p"OlD#%lD.)k3#M + c17_%dpHH??͛ H(!-iHNCDzoa "XDr"!3,"HD$DD("Ad:4Hْ"Ad $"{N%u"9#6"*|?#"?" J@L@>Sr9 +K d Zd#@@RSda ]; HJH% EBn @BK -r=OH ϒ (F,"Ad #2t R1"HD$DDHDdT6D&4i0fy +"Ad l- X|4">"m )ݬ| ,!@"!% ϝe@" OG fY d),ܜl SdB<& {v3 *@B g C@zEBr \BD8"QDn޴IHȈ DD$$"DdL "M DUZ" D]Dd/'r"҉+?r"o0"Ȉ|BD>Dڅ"?E]!r6G  9%) ɀ|.yyCyH$rǀm @JY )';˨Hץ$8I@' w@RB~BYB"!ҋr%:YB!!W9'NB~RșF$' G$'Ezȍ""9 E$ !]$" PƂ$" 2DZKJAd "[N"90ȉFOț6"DkDJB;r;BHIH@R6 or )!2rp! ; V kd,2@dLdr^rv H,! HoғiO?-L!"=("=EDlDd'oW%ID""ȃDd LH:9 2Y"BDv݌~NKDs"GȻ +D>s&%'gD"g܀| 3w : nl @H+9R u2@jn}6Ea1ΪV@1g`DfŜE09gXǜ-}c뺟>NkLW2+S2@"!큔LMaB& !np(A CI?~B~"%"# "Idj"B"D""I  "ǒ9Dȹ t r,$D"k',DBD^RD w@}Ed-"D~d|ow~@@HCH 'O( k@V2@.r.,SdG s dHr@ H $d2 i/!;LB6+"k!ˆaDd4#R"^@I"$ "G|9q, r\Xh&r=,'$D"7HMe" D C?+lll{!@^@z% +@Vr@KB9@"9 @9 +HHOBH&drR2@RHi$d2l0";_͈4t:]n"{ F$"D""Id6@B9D "Wu rܺ DE"+"j"%"D yD! |?& @>'OyS<$Ryy`?E Mr\ r6 D GezIH) L np(4++DdS_"R#D$2U !Ɉ$H"GAd9DAbDAC'D>#AU/"| MM>Dm18Ld|, Ȼ&W >@"! ( ȝr+ r1 gr +0@!Y! +m $dZ*21A%H(&dJH:!M ;Oo)dWΈ$>D&ȴtH +E$I" 2D$r "E r9\"7h" {CmSDj!D -#i EH ?٤B +Ɔ: 5'AB1L\H-d Cy @2<(@ fY We@%r*, c d9B8&!$2% 疄t8d@6+!DdȞ$RE"2D("HD9l8"ADYH"AD.@zY"+IdnYS@4Km)!iDj"+"{ 2YC_D +H!rdcǁ9 D@"\Dn!;}B#D yD! |?&U )-  țHIH+HH >rJ 7ȵrr r% +A m@ HHtٓ@RH d7%d6͌H?";YbiF$$$26r@db"#R[0"B$"D$r +"K@\Y\"7$rW<<sW[ED@mjy.9cyW  r \ ȹ@Nr,!#G( $@@ 2@F* - ٕB~ȶ!Gd;o!_B! Q$ҡI$2M"$2Dȉ$D9 r!\"W2MdGSDj! "(dD~B ?٤B + ,@" yZyP#@V @d) d4@Qa +~}큔LOcB&%&* ]&Q2H +HCH dLH!4";Z"HFArD&tH +G$#RDD +Y$r @" A 9[DId"w '퉼`%6"iȠDj!<"[[1(Z @ZRX@-N@ +M +z +@. 53d! ,r$2*!dsKB: +Ȟn&A i$=$2&L )$Wo)D""ȌL9D'S@t9D.K@JDmBdY<~B!ȋvD>'ezK 6hRyF&\@. ٭Ϧ4Uj-@gJ2t7I c0 0a9`N1ǙvsΒtw#:U[ez9>iw\9 '1r$9d i$$@RB&'k@1QBȎ dHKB%d+Ed(4DJ"NW""ݺ$"DBYLD ,'"+U p5yM)"W >ȆȗvDΞވ$/ ?y=,@ 6yRKH7gN3*@Vd9@@A - )DB).ӑ cHR&dkBB}$l2"DF01 2^DDt&GODRD2Y 27D""r"r\"@vDb"ORDԈIyJdMMm]]}W"_lkS@6X䄔@RB@b  rKd)N@ s%R$dF:22)I c :o%!HPH G$q pd"3̐DmK$E$r r r<9i29 D&"kȍ r"2'H"/,."x DA!'n!Dn@4B|e|fu HHȓ'{6\C@P@' gid9@ + K HH2Ct8df ;I ;2af C4 5!"2Bk "@d,LD&J"̮Hi&):L9 +DGDNSA,"rD.'"W@VD`"K")"툼(a"q|b"}wHkm l: 7$mQy\y * W r9K9 @G @ +$'$@v& @F1FB @ψ RFNd$1t2) 2MMgDJ")"#A9DN3ȹeD*E DD=&TBz'c5ȏ~7zB* + kȇ7ށ<'<@;frr) gS9F9B9ho $%d*%dR2@0"! d&d{%W +!Mq pd"3`"{J$E$- D("ˈrE:"DUjIHR# +yK'F/V" @@>@+BHȳg#;ȕ,# @<;"! t Hq2RlzB~.l&#H&2D&"u"3%#DD r2"KDYADUDn{SDiy|dCK;"_[|gO{oD~ +yw _3|  UH-!5 O3Շdr;Y  +d)N@d.R@kHH ;V ,@K 4 GB6Aȯ|G"2Ld 21t2)DdAdWE$ A$"D@$9 D&"+"Wk@&"r#S@h@@^W@^Ry< mrr9X9 'qc(rmB + $I +x@BHR$dLH򏗐DHKD~mHH 2ӥ.'LA9DN3e r+Ky@yLIiGEI D@-Hg-cH$r7 + 72r9@$ ȉ1rr ?@v@Tt8dV@ !C 8m\G"2Ld`"25LDvLd^^D"Ad!,3@\"r!D""׃-GyI'=mll ?"?#ȷ-y ?@c ]r \O@R@.$ 9A GH $V Ojkȇ7ށ<'<@;fJr),# @ +  +)]$.ӑ cH i d ցl62#HD+"$i "I"G r2"K PDV JY-"7X IHCȝ.kȅ +4r"M@d/ iil@y6Y +I@-iEMdL 2C̶, "-IDvd"{~@"r@\ "72;.^\JDB~%#2ȳL%L@"TY{@y iI _ 7:@. Y +xr@v;_H$$@6 YW̰L3 )@F'd'QDjDB Jdh" Ȇ a ")" n 9XD$"%Jz&rw?zFD޴" 2HW*"$ + Cy/ +ky}@  r\@$ qH9@e 1 _~$'$@RB +a:$H7!m _Sz*[DD "9",!o,M }G$E!m;&+D#ȱ r29C\ "W:Dne"(ǎ!yBDZa"c~fqTa |} oFy?ȽV@ yr9Y > dWg@rBȦ6 +d=2K4 dā|Ku"u|KdL"2SP8WL$!T"]@d/&r DN""ȹD"D[J@"O"GY\\Rj| DȲ2/L*䋄,s!H /A@;j#@n +r9 ȁ7مl' 9!f dY_ BQ@4/IH%2!EdDd"%2:"V '9DcȉJ%r9\ "73 M":yKiGdL"U`"_ʶX|zNH.Y,@^' @nr3\ r:H@ً@i闐ds%dAda fRL5 (w&R#2B֐"k+uAdNN(ͳlD 6Bd'ك"D9 "@i$@F\@NS Gȡ?@v [} dc <2@U k k 5 nBȷ(!LHK "MD +u,$"&B1";tݙ~ rDNU"(AF&ryKddD*ȋ *yÇG~D>̟AD"2% SqH o(vBZ@4@ l9 G!@v4@~U, +dCP ;@Q L + +܈L"zJd!D6"[~@$E!=ٍ "ȑ r<9D""ȥDn";DrDD~D%No( @^u<@rB:@RB:@/@nj@' g)HȾ;A@ [ X@+,2 @V|2iD:D֌ 2SP8W?|T"1]> r")3y r \"7mB>%M?"2,"o+@COl"Eh"]!L~ EH' { +m K Yr @nr&9@S 3}d7};|DB2MdY_ B2[ 2ULb Y/DjDB("3, "J?E$ECd[& Dt "'3 r%\" +{Dd<yT;,@BK"@$ 9@3@"!@~{\+@nJ gr@v :@~HNHld,2!S#2y@BK?BVҟHWH!. ùyٺ ٙ9"'A\"r\"ׁ-BCcADO_"ʢ5/ہ?0qSa m OyL#@n +r9 ȁ d/El闐dsd * n|w#!6i 2]Kdh" Ȇ.!"Dd"aJD%rD] GbyR<y],..)-s"Rw$U3,S UH{Xy^< #kEr9@N$ ar@v@n dH uH'!4/L6)Jdj YBd=%2"a,")"ȎLd&? +"G@4"r6\DqioLڗH^D@"r""gȹE rEDTD:IEE`"s%,"BF@(a@ H)$\c i K@` 2S89H@@vH$d}Y$%$—DVD`"*"% AdsIdo"ED*"{ r,Da"ȵȝDEI;yIyDD>D>f"h"͈%&]j}w!WfB2O, ]K>@:<@@Z\@@X9@@T@m$dcd db !@e kYȿڀ Y," 2ƃjDd0l!l;""{a r " "gȅe r "w%ODD^A3'/D~} ]B @ޔ@^TBڀJs 7@9,@ ف|@ޒ@^@ iyr@nl@! Ȏ܀DB-ddCd2 X@ꄌ@@ƄL&D% +v" &2`')LD +!mDDvD%"؉"3ARA*Dn#"J"j")"M"ϞSD^u%2;;'7JG9, 2HG%{ mr` '/fپ]0d*ljh k%VDzYFҍ*AD֒D3LD6D4GEdWId"r09 +DN`"g1K r+GyDD:d7H$R'2 d-? @VT@V@څJp,CDVvY 2oٌl]$ADH9DNDAJ;C""]/| D,6H|$DByX@nJr9@# AdokT@" @g 15m@ +!+CH \YMHO!݉*41DVD`"*"% Ads"/""%ȁD9DNa"2+@:D""2=hyǝD:oC/D'2| +@Dȋ^@9DfDY%t #dy&ȇ{yU iyv@K d2@NP d_2} )! * S@ +RȯKg)dJdUȚLd=&$lFDGEdWId"r09 +DN@|A +Dn@IM$"2sL5"Ad&IdI2Jd1 2R$?v)4 UHwb8~<9c`s0giw1g&L"Lb"Hp$c("%}D("'3ȕ 2Dn;%HDy[yO#1, 1"=E M!@BY y@ /+ 8r@ȕ%rr& (9Dٗd &)dYj@RBt]DgR#ȚH#"]LDiNDv*CDf#Ad&3sAb&rՈc"OyVy/oL%!.7+ +ȳ@:@; \\@#` d d.@v$ dKdF&u :.@V1Lx@E Ad2T +DD~NHIdo"r9 rD.+kA&"r_y+W,((,RD>DȒcD@Wd! ȧ +Ȣ‚ |yUy ~rrr.@f@fH {+ Nv Zlh@T@BVBd\@ʥ#~ E<ȯ]ED$"i r r!\n%r;OyJ?-DWD^7wGzDzBtDg_ $  #;ț:=<~L 7ȵr99  d/]DBȶ2%% "K ; Jd(YÉDq RD$ٓ9DNd"g3@Dn#"J"Չ4" B"؉|#2 +#y_ Q^r eȅrr @ dOw@ d 5 dTt+‰HDVs$Fd=&Fd3Ad LJHDdI09DNS@&r5"{$5")"D^D^w|DKo|FNJKd$@~t3om@@> @>y.@ZRa r+ W3 ȩr $=L 6HJH=ZBL1Y/$\*\"׃-DnI!HHӿ)"/9YXX0F' +ȇE&L /1-@4<$M@nȥrrb9@% K k@$ ̈́ԁlلYL2 @U Dd+-D֔D!"D6*li1݈Ⱦ! rAd9S9D.a"s@f"ry yFy| "mDЉBi +#2hQ + b|yDB)<(er\@d Ǜ@! I Y$$ Ȁ d]d"Y +drYNdpDV"2HDI";y)"#lD`"ȕV"wyLHG"*"DDދH="H #Yg O1$;f Wyrr2d_ dz@v$ dKd*!dMUddXB~"dll"J"r'RD$$2 "3Ad r:D@d.ADg"OyNyD;ԑȒH|#o( ߇M0%y ȓ'y 2@+ȹ d6# /^@vٔL ?5#2>|"kZ6"DH" ""$ rDAZ Dn'")" |0w$EEiD:D;$JGdy@BO䣇EE;W%=<@# Mr-@@N89D@'7 -l%l.L  l@ +!k@p@Gd3 DV Dq RD$S9"ǂȉ r\"7mD^EQ RH k "H="C+Dv#2Fd44i +d1|my<䯧.r3+K<r2d_ dz@v$ dKd*!c@jLd|Dr#29'"*"[ȶDd'/"EDJ"DH "A A\\"s5"ȓ.D='BD旉7e&ۑ?1!72<I2I@u brr$v9 +daATI D%!齋.zoQDU$l־Mф- d$Y{syOyD zOodn^@ـ k|,Wt2"#YՙȚ:q"۵w#RD"?9LAtDՂ rFDVDfdyQKdnn^"$TDA ,.D`| H|2Ky a2@)E2 +d9@v +d; d D 1iRYB@F:R[ B'_"YDq )lHH&HD9D.D.V"V"B%Iu-+a" "$t']hD~jB]h@ROHP2[ +C 2\  ȉd?ΝDBȖ~@!!$Ȋ^DF9YÉxAd#VȎ)" /9EDNӘL*Dnȃȓt" Gv" x#9:%L YHS'% r+\ W  49@@! @ HJHȦ +x : d jQ.@Vr|4TBVBVQ!o-D֫W_#H)" w"r09"ق r)DnȿD^D|D o|F/`|[g ؀|!|f)|dyCy& r 1Kr* GI }4 LH d+Fd= ս"Y1 !\DفHLdm+ -D։#$$rF89Db"ȕȵ r3IDD7ԉ"1&i#"*yS#D>\'R +K)d%4)4|n |@>ЀI@^U@"!}r@n@+yrX9B9m߅ +d_ +dȪ 7"2 D${IIp9J\&r9\c%r/yHyE5;Gd 6ȏ`/cyMyȟȣGȽV r.9rrGwO ځl@B,28"#"AdLLl$2ADDs'RD$$rI$9C "1AFDLW"/("@-+ǒH)AdQQD!"b@( o@^pt&yLF\@r[Ww I [& d\lLdMg Zt2" ]Ԋ}Gdy"+%h?DDLHEd?IP"2 DNәȅ 2E +"7m ryHAE_"J"sBN.4"?zAc$ I@>yȻYȋ@f0=r S)r2@Nd9TُȖ~J.@DVԉ,DF9Ylj!""ȾD"r4"9 rDnȃS"$Ad"2N? "m"C',zBڀQ@fKRHS +ȃn@g 1s49@& %} ;$2^YCd@rғȯ,DrDFAH"[Edu FH!H}$CQ r< +"g3KA*&rII䉓zDD^&g6"8֍_"[g ߸#o /@ yRyr  +@.@.@" H @d+Fd= ս"4 d@ +"ٌlm&%ȑV"gLJ r/ }|S< =my@ʄd EB@8. w@+ T9I@@ր )4Rٚlf2H@~4 +a ]nDF. Ads"?"{D""G@&r\"\"ׂ r''V"o"2 D$RD$r 9 "'șLb&r "wȽȣLH"ϝyGyߗ'Dr#Y@B:'w@sȣ;&F@.f gr,9(# k@6` Z@ +!2" GdR#AdLLl$2ADDs'RD"r9"' r r\.\ "7GnD^D^#"o%&[ϞH?!y_y<i 72"\9@Ncadn^@% [&&q115j22 ˇtAY/,DFFd{"ED2ȡDd"d&2"iDaEdF;%YDǒHRYTT! &@KY@cd~^n/Y + @ff( i6r5La @&C d.n@"!-@&8$@,EdEʒ*Ld#5:Ȧ "CG"EDD#"V"ȅe 2JD!")"ӭDK 2[yWc'RHO"YHw"߅F6s!HH=!B2GyWy t!r@.sDr4H@3 +Ȗ2^YCdu +2$dDݺ2]8[VGf +X1 2!:kk:_ֿ5MDʈ !`Ad#!Dd8'2BU٧," "ȑD"r:#D&DEd +ʉLЉTYj"YJ2 +3' or ( :T2@2 +@I # ([DB]@6rdRˆJLdG""B*"YDD$"D4"2"cAd<#r "@d2yI)$2y DcD>!-DYDdA ,k; _y@@fJ Ɓ) rsrl*#"r"3#44t|y +; UyLr7 7J WH Yr +9΁8V [I [f6@2!AH +zDd D6UD8mAdgNdOg"YD +"c r&"0"5 r+"q"J"8yI'N|[n"D@-wȋ@@% V @3dr 9L.@@vm9aPdS@Y1+AnDV׉Gd]EdMJGd/"YDJ"I r "K"WK"ȝGN;yyCD>DJ!>"K8$ y ,@J! ܜl o /9y 0 7f ' ȡȟ~tWlR tA&!iYǝƒ@dAdoldBD""'\"1"WD^" H&+ț H="]B:lDV+3]B'1e7 O + {@@.s r"9{[ { -$5 ( J p ހtu$$!99F&"CpNd"$O_?"YDDF# Dt9G'L"2iDd|f%2 %S79WJHȌtd* wD\ $st ȑdw-@"! Ȯ +g  9FBY5d9V"y%RD$ g&#M !," "GDx"r  2DnI 2<ĉL3DyVɉ"1"Ҏ" ,r"D ,kd ȗ6@>d@8HsBj@q 2 @n@XB  h2R߷"!5 ;j@|!!~@6d@~"|H"0"9iDF Nȩ r6\ \)"=DA" I$EsWDfeez*8`1L@႘P /έ&L00a&0yyV1\71TUk'^\@ g}DV(wM!%1@nd@ W + s$r 9|>!9 {3 {h"s Hbu@ A@d 2\"2@"2L"$ 2LeD, 2E""ϛyYD%:"+*{"IH=$ Ym +@>,F 9z /@% sl2K!L  2di d LdM%"rDFh;"YDDd<9MKd 2dDn"w!9Hd 9s" 8E"K)GJT4 K% +Es -d:2 L@&@!@F G ]!d9Z % |@zEd;"[ԄΦD9ȒHDD@F r#r AK~$ %W87;Z"9OH!$'c"y"^#Yw=/L|j+V@=#<@ w[ lr9́k dO2L d&> YDɅlIB"IDvDv5!ٟ)," HT r9_\D"!9NyU&.#>YD>V#R%?<QYK 9H! +rwYy_&y>r'\π\@.g@. ȩr,L@d;Vd˚i)dCɭfD6LH#͉Έe o DTIDG"3y@bF2 r r3܋DDɅTFDޒ|XK" "mB)'ȇȻ-$ )y$@n@@. 3)xr? هًȎ@]f@6Yƶ7lCDG"; qu9@!jd9DN"gsEU@:F& r; =D6"Az"{0"{Hd'"cc$r:9G +DdDfDG"!"uD^D"@djH#|$Y@ + /ȣd.@n 3+TBr9L@ 4@ )B # u dSޘD"2Xn$2ږHDdD&I@d 2M Df@d/diBNdBd # TlDzHUH-$Udd)e3 ϟ@K@fYd2M @&d<G@ 2d2 2 B@}MlQ3""]0"'#2GD&E$'2DN"g F + 2 +D"yHD^z"5*+u ΁@q ,<+C s]Vd:@. gȉd,rȯ6@"  ȞdX˥H?u=gȖ:"[+DlA$HAh$r9D""";%"p"Oyy,+sW<"BHWN|hp' 9R@>@@@^ir?€@@. +@NE ' lv +lad]͈lfF*$*ٝωk"YD*DB"#SD."3"W;}Ha") LH ׈[@]NC#rD)&}͈l@aȇ Ȼ2W5@W )arjrrr9@RGS @ p K@v@v-B6A,JD!6Dd{NdG !Hd7"BA7d9b$9D" " """2jDD^'55-z[5H%!e O !{frrr9Sr9R @BB" {YّٞlÁTdVD6wJ$HAdNdȾH@HR!EJp"r,9 D"1"kM@v ry="[s |I@> |y. LH Ar$\@.e@. 3Xrw )W[Xh+$Dd?ټ6@4D6K"{0"{[FD0"rDt rPRDF" G"1"5D^dM#$’ϔH'@~k +nS o /jd y<@ kȕȅr:9@&OH@ Z @~Y[ H-@d["`AdDd$ȡ1DdD&I@d2ʈL"3Y@d6D+D7#2',"KtDVUDz"U! $ Ym +@>,F 9z /@% sl2K!L  2di d LH> f^"1 +.WhJd#E$KD")t 2܅D yȳ̉,Di,uBH/ +ik'@2 K 8@;ˁC s@f 42EO@C G ]!d9@}MlQ";SG K"YDr"GU"g "ݺj*K8~60t\C'qwݝ=3Wh@ǰ; +zYϻֻga$$:XoAbA +Jd +y'C#HH=!m@>R@ft dd  Dr99@Nr/?;dsddCg k8@ sLžk$U%ՈDFEE$A)"$$r9DNSAl&r\#"=DI䉓zDD^Df"X| +"_X|)|c#39EK;Of'&5rr!mr49D@RBJ [Y +:YMY/dXH?eIiYǙDdHkDjDD&"GY""LV/րC@` /ڀo$n@nK|,9@' G$,@ @% [ȦF d0"FdE+U@nDc"؉lIHI@"r9DN3@&r="wȽȣL9G"/]VD4'|wnDBc" HSH+RHW6 '@޳y ȣȽr 3Kșr2G@ J { d=YH!dYQ|ȢWYʋrY 2::&VX DDw'RD"r9 "'LbRDn;Ad +y"Y7"Df!u K w~| o* /y<@nf Wyr   +_{^ +@6@6@DG@ + r^@ +YXA@de 5.Dd"Èx"ȹL +&r"CLi"J"oDޗDfeegHR'"?#['2ȹ|>&RH2[ ++@9ȷzB2yd2SX<a k@! o( @v<&G@[U |9r)( ȶdKW k;)Y1 dq[Y7 "cbM"VDd;/"EDJ"Éȱ3@<&r%D$"Gȳ眉IDf("!] #4t  + @T@^vy +zR@c 'c d_=lgLـWOY*@Yw974 2Oq N@@.@3 D29dHJH2Z d +!`H-!ȀODyKPH("2F%BDԈD#"$,LDfL"Ad'dF$E U"o YdAdoMD~Hwyc[v@~ +3/l,@@R2K@f,)Li T $ q#C@FI@FF\f [1 D֭J"0"EDpNX"r29D)ȥ r r3"JDPy=%eODj'h2"dM$%$KHȓr/ 73 3*d + gXp HCB΀2T_nڰ*  ; "ۃȎNȾn:9DDNs@BAJ Dn{CDqA$"L[D=@sDkH.de-ovBm|J@K@# o / !r.\'\ + @N9c8ٗe d{ & OD6v* 7ωHDD"r "%ȵm r7y<&v@v@l\ل٨r@ +YӆW9"yDd3k"[[ٙDMDTADs"ș r\Ĉ\"W3"׃- r'GDD:#RR#'.|LDeK?iiO ; H9!O] LHgN+@& ȝrrr g)xȟX9PdOd7dgk [[dC+ Mwl̉ !"[ w""%"@dJ$R&EFd9"@d2LD "3Ad&"s9y2rDDs" l|a&Hs K U2 s5 d:rL2 @&8 @RBr @FF\aa [!` ȦUd@ȪODyK$EFd1%"r"@ 9D4F*!"9ȓ/ "ojD2"82VD5#"Lol:  =E BY@* I@Ԁ;Ɂ*2C S@&8@Q@@* A k$lo$ #;EDuGDNd9]%r!\*\"73"kDDDRD,?WUq|aluF 3T b9`Ƅ &L0a&`N=˙մ f{1#jG;ؽzު:=%wg]w_.ODU*HRrg +^K o )!U YBj@@v @e@K$4r99T =dWdnȚ +"Bdc#A !3юD$"c9q:$I 2"S5"3@d&'2[yޒ9ț"b%*\*'R +2_2@^dd S%rJ@#9:m2B YɄ *@֕:ND6`H',Ɉ=91DDD'"AdLDDni 2D'"f "Ϟ#J]ȟYUB $4 o + s<NE@f2M W0 d"Lx2V91Ȟ2Ɂ x4 ]ٰT IsȇȦ- D-^~6DDD#"ș r\̈\"H"] ryDyƁȫ[Dx /8\H׾D"g"("m +H]H+ Ȼ-g%G .@@.4 o_ـlkdS' EzVD~ę6 +T"?ĂHaȱDd9D$AFS' iLH8A=FCFISR'mm @R +I@O + ȇ@^uir r5r9\$I@N& 5 +H$$ @v@vR l d&; mn5HM$ ɉlƉl)lm 2ȉ[|d99d$r!\ƈ\" " "ODk+ [H5!M@>@9  O {N@@.@3IrI I@րH@l-lɁl& z kEd}DDDNDш$!%,"u"p"G r$r$r "w= +ODRDJ"$:'$f"_9)D  ϝ&C@n@K 9]r49tgׁ ɁC@v7f/U +d@ȪK"V&]"R!r0'r9"g% r$r"wc"/^DЉiD"K"- +6_ȗ@>b@wHH:9 r;Ā\ WJ rȁŁ铐f 2 ;lW@YV D66"[DH"#"{}K!r NH"2 +"gd +" "y˂\"2O!2_̚k"$" {o,*z  \ %V6 Z 9_r*ɁT} @ !U Ⱥ k*Ȇ ֈxu"@dO"2ډHX"r<"@d"LDH"@d:IDfI"ϝ&2GyS##/D%U@V KL@g>@>0y + %L + S2I9qX@F@F #HOhH25 @ޕ:ND6ȶDFώHD8"r r#r h$r?yTy֖+*w!RH"?T9e#\HW@>@% o + sl@UN-ȇȂo ' Yv">"+|!,=gG.U@.g@.L9ǁ.+k $m [h@6@6@6H[![?#^Dʈ4ڞ.|j"EF0"rB 9W DfD[@N<,D>5IkV!T.ԅT| k R)Y| U2yȝr r\-\ r299L/@RB@vc@va@v5#+ ]$'%ʇPOXXxGF"*,"u"9@t9D.DDn;@"'IH5"5"5"[DHVRMHOm5 H-! @@& \ W1 ȅF 'c8Cu ?$%$/<>@" [r @Ҁ Y}+IHdg}" 9ʼn" r\ʈ\ "I"DANqHH.J"ow@}F##Dr"$j|nu LRB*@8N@" r3\'\*  ! +@! [^R$ sId +$]Ad"oiDLDDNS5"%ȵ rcH"/9iDtGOCd W _@z9u oH /d y qH䠁@F@v@2! +d:ND6`H',Ɉ=91DDD'"AdLDDni 2DDfI"#ؗb%D6"w\4 o + s<NE@f2M"L2@ X@p {(d$2<р v dRlCdS"ۖBd/Nd?"YD +"s"S@L9D.fD.k$[A.v/+bE#Y4Q &6`ņ ^`Ê쀺{D)Qח)F/|眙3<<@P|o.Df "slDBBVY@q }d +d-ylr r5r\`r"9&dc @' k;Y2߈ "Ndg"C$ +тX=-d)D&I 2DTI*ƈL +Y'"/ˉ,..)D>u$rRKH/,yd w-2M@2 gidH@Հ +H$$ @ +  C%!@6@jBVȪ?Un"IHNd#Nd 2@dʼnшD~w,"5"p" F"%F"G8NDJ!u"/q"[G +RHAJ#ҕV$| + Ȼ [ +T !#> z*D  x޽@RBq1(2d2H'~ ?啋Zn)l!0ٞ)$":9DT9KDdDA<̉<iH^FNkȷ>Y.#=ȷf _J ,f T'$% !urr1 g)r<r$r)!ٖȿJ Ȇ 3 "ȖV +"r@N"r,9Ds%AZFF D&"ǎK"f"D^"Fs/["=i}n|au H ϛd yy@р J ȹ8@O@v! ;X@6 B@Ț~ ?Uu\L#2<<"R'HDvu"E$'r89"9 r$r$r+ED "jD$7ANd$q9|#Fڜ@>,-)).*RI@^@"!yN ȍrrXp䀯N**22"<\k NDȦD1٭,"ÈDD# @2FjH~"2[wƆ k"|Vȟ@+K"qI[#m{_,|e 3 k @=#< @nk2 9@N" p od7dG dK dm' k."BBr"5"+DH"C" %,"%CD"2"gK"J"@DfY\{" " +Iۧ*ȟ<y_Yo d2O@[$R9@N ȡ~}DBNv@J C k@J p Ue! D'E"YDjD + 2D2"Ut"Gs D~ȋf"r"KJDH#ϪE ssYd&!L$2@&$2٧= @2 c@[W3u Y]f@dDdXXxDDdBd{#R!EN"r'r +"gȕ r=#r3ܡyXyJ%RHK $|7e՚H}4g 7| + =,--).@e@9T IHG}rr orK#83Qaa& AF:4 B~+IHdkFd[*jD*D&"Gr"ǃ)@bF +H^yyN$E ш%RHAKAUCdy@* y$0@:JX9 @N% 8 &$3*"!YdK"kV m@DvDADN89)\$\ "7 r<ȉ<IyI"͈g$ 'RȊ&g#?T/@HH:'8=r;$\! g)8r$rG d[d +"Bd}# AgvDD*KdWG"YD9cu"gȹȅ r$r#"w+Dӈ75DHKKJ oWH2@;+<Ɓ<`r#\#\ r9.+ q ;v 6Ȉp f]Dz$@"z ' ,"C9ȉ r "H"WK"ȝD~"2[gGA5;&"{Or|[K _x k 6@@@VA @.09M@@gdwljd z*ӟoDXYW'3!PhAdJdDDs"$# r)#rL3IDf "srDBA}3*HF/+g}d +d-yld& 4jT9@NSL$ j@c$ c +g @ֵ2H[!Zgg+7$$''2Hl 2DhDI"F"YDjDD&dˆ"H"׃t"GD~ȋ UyH{}/@p /:#RUr 2@dāL u {2I I@i@p 0 d#~ +)"RBa$=Y' ID""u"s"Gȩ r$r1\) "wȽDaNS*ZDD^D^w9g0_ @F$Ҫ ; DU"z"袃}\Ŧ$1N1}̜=3jM ߔ> ED鑑?KKJȻ /@6 b w[ %rr + Ga dd׏ 9!vd+;, ̈́ *AN"SAdA +Ld&9 r$2D.D@dYD)DRDDȋD>D>OCdFzUH@>% okN T<@" @%3d9$ {+@:p[ "ki";xٽADf r3sA" ;&*ߞD^""E$ N"=?}[@^@rB@,b @r2r@( dxR !U c"@ "&IϗD6DȎDd"ȑv"K" r- "w0M"Ojr @@.s$9@$ 3} Ȏ dk dS- dU/ +E|\DziYd"kDV/l %lcYKHId"rB9Q9D.D"J"y b"?D H7#=FO^@>zXZZR\y=M @. $D9@ 1}$ ۸XY_ d du28 ]|O}dA|DV.H5 dMH&;L"DvЏH&Lp9DNS%ARA*FD1H"=tANJv )!U ~r'@%st 8r$b @vȎ dkBٔLJL Ȫ^@V.,j"kDV/lFd& "" "0v"9 r\"7L>IH -$iDgN%5|*O@@޶dyZ&&F@Α@Nc- 3}%_|dl` d "@F:"?Ed==M-U";w)"RٛHD'"ǀȉْȥ r5ܨWy̅3FM"]3Rg}TWcEy&{ v ir" G>&}ddc d}o [@~'B<2$$YCDu@D&;l+/"EDDb"È r*"K"W D6"rA䑣D5"uY^#]} 7T Ϻymr#\ r* G@'$ ۚ@6c  05 , "D""ۙDBHȞLd"r(9 +DS$@;[<$Y\\RjDBj|DFBdF.H U&,Ғb G 0[ +@.@S@# 0 ~ I@# [فL4ldi&d0@V ȈIdT8LD6iDd{FD*D3 +9 2DN3%AJDn!"w1ىDg"țN""@" eh K/܁|yO b w+@+%L x9J@g {@:p}Z "ki";xٽDv"g|I +DLdHey_G3=i7ZC*W5@v 2-v | d s!d&ޣ, i: dH!d,TsDdtD64Ȧ 5уHLd?&2"r̓D$k-"w2")"H!IܓtA򵷏,5@!yRIH", +H9@q2" 3 wd Ȕ䤤Da@FGEd 6"Fd'7"EDDe"#AX9 DND Ar r"WWTDQP6X`Æ {lsΞ5NIV|߹w3ù="97@]{2??s"I&&/_ q & y@@RB@j iy܏@ 7K2Sh@ 2 ;*l ]D: ِt"2%DDRE$#2A" ,aD@dY)yEK5M:d +IO%3Á_\@dL&HDd9"  +" gϩbKWH5DHHQ--W@?ǀq o@^,6r#ρ@N& !"o'$@& < \Y7")|SAd;[" 9DND"y@"Fj r%yD"?щD:)#PR>>L Cg ЁD=gN@B w#[ "lIXrH9!u !]NjȺjD6WٖE"Dv6LD$r99\D.cD"D$"O:y(("2"H3pGe@v@~D@^wAr jrr9 @N$ ٞ @S l$қuYljF&2ȈJDp RH"r49DΔ\ +D܉D "OD8"9#TG3U ȧ HR @ W1 sșTr96dWdG2ˁl:]D%!ٌ٘R 2eGd +ӎH-"u"G!939@FJ r܁D'"DY}"LHH>H, c+ 5 ?5R +Jr Y"@ A@ҁL t  @66|Cd#Bg56M "[HdȘX/.Ld*#[f"DfHd.ω,"K2F&ȽDQH-"%"dUIG1 @>e } >Y@ "E V !!Td"@H@@-t ЪEd=DbDDFLF"8 ADd9 \DDnH0 VnW =!_͹$nmA#&)DA䈑D8$r9 DgD."mH+$y[&kG"ID:dHH_@~@~)y[G=6r#@  qHHKB@q ;i@vpuu V D6lD ͈l:cȉH4 r9\$ r7yyVMe["#H##dH$l| ț j 2 @. )D@% Gv + 5!"< "k"r"cc}qDdG@dW$#CDA"' Se"ˀ՜ȭ@."N3vD^щɉ+DvDVDioJIXd= ?y; Ϝց<$@ 1 iDr 9|3ݭ@G cc ȶl"lƉl)& "{ENh$r<9 DeD."W-u"O9y58""i2RFAiy?ĀtU O@D w![*Br.9@N G@d+Y#'& ;Yқt$R! Dd#2J 2A'2 L!"{RE$#r#9D.`D"ȝHȓyL}D>A"U6Ҋ3f @> k O@@ w*\ +@.@ Q I@ŀlɁlƀlL@r!i+˾jyHlADDȉLՉJL$2" " \ r_'$"Ιȧ~WRxC@yM=3'$ wuJr rdC@fr P i2\ dӀ CJ#2DdLL/,d"4UY +D@dY)y\&#|$N3NlIOUɀ|"2 d9Yƀ, 2& 3 هʁL$ |ؘad(I ZDsOdkH8iL'"Hd>YDKD"7 D#"DbD"R zD>fD3drQH#5"}dR,  tȾo @RBidHH=!?+PT@LIDA@˟jTBakIl'{h٘bLbIuq|2w7d>:~. v@dHd$9DAd%9HdO"KHd5YD6M@d3"y G s8 u  $d8d77sDd'FԈ"s vDNF,C"+$lD#L&"HB#Hb3sF*R;/.Bȣ + d=Y@V E,@ s,dZjJd@鍟IB@hXDD$RHJd)9#r +\Dn> \ց4CTg$g$.t$hQ +'; с)g9 +\ @ " ȹșoRr51ȡ( +$K>ϵ qK$F$#r8%2U$r 9N'RR RHF B$r\D"7ۀ=@!$@GVDH=#JikJG[y  @@ {mFr \99k2Xi)4 _r d7sIdp_9R#rH1"9""g#@r r5 +DfD'DțoGYITF2$ULr|WGȇȭ +   9 _}$$r9F pȗ2қz0pH r 2I'2#2Idq !F"<.% R0' +$-'F@2 &@ )r@@ 3  +%|4y 9"@ Y@YȴԔx 2қEd DdF@{"cu"9"3(@d!r%ZDR"K Hd #QA~3myK'ʌ1GR< Ύ@< @n d=Y@V K)SY8hȁHCHw@Z +So/l}F$ +I"DDX9J&rD%ZDD"DC"!ˀU@: r3yT b@Dv"M4RBR$x}Ȁ|H63yQ(r\@ q@#@ҁ|kdMLԁr# y@zs7g"CF0Դ2cu"'" r&!r.GRK"qD. H9##TOG9 @ޱR i}@.   g@ +ȉȱ#d +PdrP gK"%ej" t"AHH-"3s +ȵ@& r;€<'y@ @ d:bv@y@zs6wiK$ra-B;"$D"8"TD$Elu%ȳ-d3ĀE e:Sdd,dȁ * y@zOĈ"DDD&##d"'LTEN,Jd%YD8"S":$wȶ 4eH$yd}4y-c s@l Yjd 5!<22F2F!n9*99L3)EH2Fz sTU $CЄE$tB$ aSgʪ,* +[5lAJ${'qʥfj';9΀Uyw{T_+D62"DdS"{H{FZ iqRh<|)$IJ㱨d;_q P@yyHKr-T9g qʊ +_y0-Kܾ$Z!TD)\L\cyPyL"sJ)ٍm!HII}w||tH d +d0% b k%Ё )9HH-e|"L` 2Ld!AFD"Jj r3!rFAND~yy$2&&"yFƈF! Hr%u'ݻf>*>$s <ˁ<Nfr5XrHd=Y +HHHo}q#2/3"K8>BdU&D.D"7"w"b""ߔy:E"[1ȠDd&阑 +d||m]D< +dcR ?|Sy \@.R@b@a K,r2[_,DЈ,t X%DN$DNIFJJ rDAaA{NDUnDxy[!RHHI*thك쒀 " ;0N@@R|OyXGr#\)Zdeǁ, <7 s< eT4g#ȁ&C$"G0"G9՝ +oHD~J<"-vDdJd7idlIwMAG- {p@v%X4 ;y1)J@!/nr|w c@+@@2 \t^DH rJp;c(1i.DΝ[J +DDFR"D‘H4'HlL#e$K9 + +dѕr aȇ,98"">"R\ D># 5B;D"IFjDD* H2LII~ : +Mmٍ2F#p(hyy>  !@&|,r-Tr,H@|@z@zβDd3ENDb"4"k0uN$R"R"rg/D~l%D^1 BH$a"Ռ!ɔL*c6x4}T@$ ;~ M@5 _J'f@BBddH$dR@2[_/%"s܈ˌNYH)"e"S"['!J$dId&.阑*TI$R~u$<*> >م2D¡Pَl@^< Kg &@*|\C\'$Y'Yŀ,; s< vE+T $YȉYY DEDb"'"$'r%r5 !UByy2 ed  aN$6t3 *:)hTuda>j H@6YD>" (@@~dyr3(9S +Yy)(~ˌ~)#܉ȅU +; zI%Fd$FviIC4J +&Kב Qd$2@! [075 Q@>NUȅ)99 +dd!r Ʌԁ/k"D"R"ۉCDNs'rF&"D~@uLd3"DvC!LnF +$Ia| Hx|d, t@^ȣȃ4 $r;# @zBzK^?]"BDӈ,'D"DNw!r|FJ r#yP"tD^DlE`II1#IdL*N + >G@6c ){ ;ȍJyn@N 'a # ! ؁N +@v,M"s{K2#)*0)3DɈ\]D^lcD)TC4TG/AGG5i@C`g юlE@@^ /f$@@}dѕr H$Ot-*EYYO|Q("9)G%g$& +! Dv:;14#Hb#(QQ Ȉd*y yLrr;\ԓV qB + 'x@z.%"s܈˔RLdFd"R^!rA1DD^&DlF )3#IdLPCt<>:$@@^@~ )$ 6$ I@ u K-@"!2K/"Hd 'G#D6"gH.DnKȓ6"qF"/"QFD +aɍ-)!IdL +'5e|td3h 9)s 9 HHHY'Yŀ, K22 Ho]fDIB! +*@XDd rD$"R!r)%rBnBdD2<Ljl$DlBDv`"iFF)Hr&5hQ  6+&:[+'r+Tr HHHZde'Yd̀t^s~Os5,"mD`Dr rH*K4"Dv!J$HB$HDUJ$HddgdXHbd5RC*)TJ?_ܱ|LȦ&Ƌsߘ@\uqID @t%:Hĕn n3%f\cb$vԯ*d1I^ HUe!@ @N@weEd^D Eb7DG hD~ɉLr"!#{HWF)D%s(qaF:4D%%JSF#hH}D Wy-@vr -H#@ + 8 kB< dtdQz@y sM4J,AdAd5:]g Re$ l"YF^ue"a$ER(I%ԑ|}yW} k nl@2ȯL#62"@΢@PoGh9 +U5QDTD>-| ȫ +d{). V@r5Y @Ve DXJD"rlDs,")"W"׆}GD~Ed=Dfy 3~HHIv5|a>++ { V!+ #/ R@ +$$$B9$r2X x nEd,,"C,D%D.5\&E&)A M"k"? %2 yeU7!#@F)4yD1$ d . +ȏ@ rr933 z Fl"r&rRB&."WJ"o"2ñD~$3ĉb٣2H{`dI$2Rxtx|Ā @6#/q@>/|ЃA !!ȕȥ&r BdrLP!G+._7k"HdMd$rIFb r'r"r&HO +"wyR6!?DdDBF$!#;̌S4R$ i)iJIe8JG=#} >d@vdS#|tI8CO@>p $OHrr1rA%^H̗yY$,΄[4,"M"ȈϿ DDs"!#F(IT$PG H-#Hd d>@~)|f@WH&B,@!H!o-M"s#r*#rEd$r r YCܺ d1DZDBF66AFBFv&IBR"ITNZQx}Gokd$Y_d> Y@ ߎ9 6FB* k@ r:rj@y FnC@("Q"g "J$rEdAK"D<|7H IWFݸF[Fj$ȤҚ8(u<|>>AɁ|IIr(E K ʊD E-9H]JD%r\8)Čllyg$76# F:D%Q({G`@@@r /~; +ȓ$ %L <~e96S"Km" "j$ru +D>OiMaDdDBF6Yɍ5#D$PHr%Ie`O#GcdV$1 +wd5Ydicp-!S$R9D"CDα\d& "DSDD~"#H3#{ #{! Hr%Icx:"<|4|}Āl)d>{S߇h,kl 1  BXJ$27}" "g"s KȵqD>g ^0ɉYH&Iă{:Gǫ=f@6@2@~@<~ + W@@+ gZ@* %H% do$7tDr!Ȓ\9DDA$#9!#IFJ# #yH"I#:|ĀlcYR >R Y@ +9KM +L gˡ 7Xˊȼ,Dk"gD.`D..ȽMHNȋui IRRA>0t^GH HY ( D>bdYEyHѱ4ɎȩJ~CjDWDTD DAHF$ddHbdi I$gRAޥwu=| فI" c|#g5Á \Ł\d` FDI"E1=1DL<BHF3#;::$$oI$2)t * "kc7e$17 q+ ȍ@Γ@Y@ +!=~?٥D("9Id"QQD.dD.D("7eN+H62#"#/6DR*LJ(g#"Dn!r7!YM!BHH3%4$"IL*(wHi@~)m Y@ _N. 7ceFdH!̏ 4"k3&0!5H##HN#$AIͤҞ8 )"WmdK_@ +H H ++ȃ@nEYi9!3 CoA'"r&99_YDVDnq+#OF)23M-dka +IR3֯lAG#G, /D H^%@-   sș +| $ xHѳ̋" J Bd9'r."r&rkDD:BHF$fא˱F$I 9qm(yt H} zr9YNN! 74KȜ,@"%6"WK~D9k2ig$3E!t Jj&dpK:>@n O@\ E <~qKTNd&rȥ5D<`;Hg88_H$$Q% B5عKONĦTP`I !昔<3<3;[Ԙ~bd$#3r#UHJ$IB%Qh(xhǏX@ĀD &ȿ@ }_ ׸\@Vedo,KD"KJrF̈كIi2} rrd%R'o.!iY$r~*"ON"YFF2+Ȼ`XH$*əD( -q_BG##Gi@^Hɀ܆@n  1,@MM$Uy%DnD"D0H$#ڍ#0#P$I%epx8xd ߻'|7Cd( by +ȪL@M"2/%ńȒp"9sD644.DdD>H"?GDedWF2#OmDLr'5_:r||B! @nNR\ˁ7,"]D%$r%ra8oH063r``ph=eI$gTT;:ZHI%R(iT82%v>>쇀ud2 r YBFYP!'{&E$ +""w22HMFF}~HIҞ8|8 +)Gƣ# F@而 _ +ryf@*!m <~a9"TYId-YG\1*#)VF^dfd'Hf f-{IT3P***9JGΣ]G.# %c" oudm$eeDda +"6kHgFVF#{7HZIᤔRR/K y Ȅ@IEUHg`"EdMdIUE|1M"dD:3p HFr$ITXGEɣ6xS* oe@* @ Y<YDˀDd ReY##[ #~a$/IpR@R{h$8y> +6Hcj wE6%@2TF,pBDA0"EHEȯ͌#.H7$0)PJ*ƴFQSAr ,@MRYHZH"iFH0 lu HR#I$g;)Z'q:8*-7# ȫ̀B@1H$ _Mdl>KDGY "yF*"eFJ"UF~gDF~3,d$3234 4%JIRk Huy;]>~ >B@~m$ >R Go8ʁ@OȊ%bߌZ&&$DnDKTɈ2$H0\`LIŤrRQIh#t >]U>~|dy4/E@@Hr> +IȢ@ +9ٟ\DL D!DD"UF2"eFH04yy1 )$L( EQ8JGcG㕠_~D#Fd%I%oj%:<9+ HQ >j ui  dYty"!G]@@}*"O\/1"R٠$")#HwUFˌD#` 0.$=J"JczC:zyD?~rc}Ā\ +I> dgq{ y61'-vݒ"2#}"O"L$e$IDrFg$FnFzD%䤀ťmD^}>B@&H|T@@1 d|2g?"H"2"uD&Ed`"M$e$Iy{De+#%4r|`ohIVR0IN2J1?a#:y r rrS Рg + X2@w<H%΀L(~삖TD&AIS:D +"kfE$e$yk3rܕ)#e4r |f|͛ޡ>$ȤqRIhi>lDģ'{N)|\A1 Ȁ$ Grc + EsJ@~a;KLAt<-y@d!2ND0ML$e$98Dyg3rJd$\Ih$#$$YIŤqTKGO>{: rrS@vu2 dd@^ 3 +iw^y<)"h"D Dd5HDRF@$e hF>HRI:J"I%䫰pd)ǷW/_y {CN@615d|@@~giE) Έl "[HH 2g9H0rQ.|F$IRS)Fđux<}>#C y +) +qa +Hld  KB2igR$ȣn"!g"\DHdYED-D$e$I9hC01r|F +$)%%I㤒|U8j%@! 0 a@r@ r/]y aߍ+DdYID!@dIy2rXd$9 FC#\F?}s4)J*&Rߥ#H}xG9o@ަ$ :f" 4H;-)"3sIC"+Z$Č")#(#(#8 F΁}Fn.$)%YIͤqRIhi>*ldYG/ǧq|ǀ- +~ +HlB Jd2+@H Xj4'" 2DE@d)'"k"A9H4r# iTL' JMKG ǧkkOL?*! g1 '1 ǜ쥀$ ZF@ c~ sr^'  +߿};TD@"z$32:edh8f$9 Fc#khIf8t4|62GqC#' oR@P@-dYC@Rg C^ /$䷟H+AA ,A"ˑ*$ČlFH0rb #W>$I$AiFQ}\x|! dd7$ٌ@#Ձ@F@^-vvId o#Cd!2OYDV"Hd#I`]0rc#j#'k>$I㤒p|U8GW>>Y rr< oP@vQ@MdY@#%d)t i;D WP8D@d @"kHfv#I0r F4J*&ҙz~/lDT|\Y^r8>B@N@@b@:$҂ @"d2o %$ O_[ R&yyMdCdF"!#0#0#2#'ȩ #2$FIͤqRI0 +G֑QhqG Yr rrd;ٌ@5d 2d 7yiwxD~MD)@dYB"!#!#[0#;2#FCJTL' Jc3F؈8zu<|$rdY@V#qQU +G֑Qq}gu@ r, }@^6@O/@Md0.ܚ/Ǔ%_YH4/,"KHȊ +$22 23ӕ`yy!IHRJTL'Jc~})lDG9$8>udH@P(7gL(~R]RGDDb#222#"#[ #] FQhINIVR3INJ)l48j%*3 q}dH +2d^^4R@ m voNWIylb"sCp$u,/G"H0d#G|F΢H[I$9IPK؈8)<)8>$@Udd+_,vvo<'y -"uތ#{țli4r I)J +&IoτGGqVxWx}b! {t@ kJ, h4r-vv' YRD "#k`dFD#gHRI$9IPJFmD~i68>B@v$Y @Vel%g-vvi-M"3wj"/"9P8118gd dd;#n093rB#}H +%IU$CLքG1GqR8}>]"  d,VZ@2H8j <'<&̴@}n"s^"DAFBFsFVn}y\aeƫ1 ٜgvč㤇լMozg3|B 2|Wx/ #4x.a'g@R$+)$(IJVQ˨hБy$G#=xq~ȓF@6r/ zZZ@N0< ) #qq+yDv4"_Q&P,&JJD62r2r9 #BF~? $35)d*ӯl#(x$J|6>6(k f@N K dB9d2ӀKLy#|995]odeku #ӐHBJj&uO +.c.F8 -"?}>~>8?'CJHI@V@ȗȧ}5!ow]1";Is"rDȉBX,W*Z\3rgwaqs#!Jd&Jc?(aQQh#÷߸>9=9!G+ )r|[2 +$K&"_| e5d7g玑H Ɇ$#S,Ҟl#htTH>~g|cǣÃF@lD@֪dϏy }e @]/M BT,+jm2DʌF #߲aIR284V/F8*<|L ȹYF@* 9kn&D rDʌs^Fnlnmm%0F~CF&,/K{6:8!`_)d# d\\[ 4D199]iA#&#Hd%5IR4FQx {c]d@֪Jyr)|d\vDʌDAdX*M˕j6Ck| #!H.'YʟC#l86tT1"Jz@* '@- ms&"adID6HeNTH:JI夅bi4F#|Txq~O{ǔ@J kJˈ|"{,/4c rP,2TF##FH Ά@R*L' J'8ШmFGIsq{ks>&RYU+2$  swȸA"a"2"UF 2WV=7ddI`R9$) v^}$mdaӰٙz "r U@z@f-=m^(dUt}H2g"UF\BF*#7`k1 $IGI0i$(Iʿ/ő"lḍGx>p@* 2O@]@ƄkȴlH2#2#Dqdd"UFN9\^Y y@Fh#CHZ%$Kiq4:y>>nu>Y)ON" <$}@E ڷ#LdwHDA2gdkdں0r<$#ӑd%%Ix)i8cG % "r@)D ڷ\HGF67R$)2P+6 +u<]U>&}\q>&@@HH@d\\[q"Dj#H9,ʌ⌜CF向@)BtIdGQѨm8P>!_8 C2g@#qq%+&GٯLf(eD8#g0502I$4N*(IJό1P2=W%8gcZ@H2n>M@HOddH 4 y$YIɤr$). }i48U<2i>n}u(@9 H_@6} F ⮾ԟ}|bh"sHi dd YGFKA#!) %5Iҝ~34j#x9YqȾt :d2yFd&2k3r,Ud42\F$är$).E+Q(p$][q|!9hi 3'2&d]kBL}G!"HdFVSȠ!)I夀XaƑt'@JrLZ' JRj)T42*Gp>>Αc( _5|t@ #qq؍iTDȌ&2l%*24 I!)iNC#l8R #n@Q@2 1E2.ά5"h/ '"9#5HY I<PR3Pj*-̟aQcG!GYJ H 2׶u["GD4O%^FH!!S2PZ+WC#t @S + +Hd/@ur$a"{@d #MF65҄.# % $AIR:\=FGG}49DLBݝ\iDDd8#aM4!!HBI0i$(YJ2!QQ8+|> d2Ӂ>d\\:N#C022G93r8dIV0$(YJy:4j#HgO) ( M@c2.C)"'DfA"dtC2U0INJKquhe$5FG};>Z )@z@>@>@]LdD-ednHH:J*&%KiLLQ(}Z@f) 36 -#qqڍe4F*"mFB4!#UHHJ*&IZ*Fe#pdǵ032]I52LHO)# t I$+IN,%S)7BF8Z xX|lc0 E@^G+ש]{d"'a͌!_v9p$w#BhcaX;bl##Gu.ߒ_fe-̺Qף RId2Z/qec#w\>>ƀ|E_@6R<#b|532$CPrŤsA$,i+GO*QQ H 䂀 >ˀ6r2q_8@F%fZ\&Df3|Q232AR+[rŤ2R7Ҹ11GǗG ++gV@.) #{ !_y;D."Ō|e633! IsC$,!#^GG.Ri@H $ID<3ߜo +&Jf%ӒH0 8JS)?|\Vicȋb@z ֵܵ|i332E2Q22P2+3l 8v:Rj H hfDTD."匼Y03#)R)tN)9G)#_=|YcG< 4r? 1lm4#OyF^,32VrŤs2Jɱ?`txt<~*_p{C@e. oH DnUɍ\g+O:";#vF4TJdNKf"(p :R<:?{C>V cr/ 1lJdsF>YedIId9ɭddQw3to;_w>>^d@, 1lAne$23댑:#YHHr%%J9:i13X|L^ ȻG< $ayGF. g347FR+) P*-ءߣ+_B%xF>>J ws@nH f#HgyY07FҧdTtNz(.d +GG:>^c! d@2$M5Y Hd02"$$YJj&練Fg#u1(GI@%9& r;!1 H$@b،Ȧ227JIƤwCITN~b6AG U>z E> @Z>H IDD28fdH +IJIΤw2@ITl$)>|,8,  1l$&w'1#F^E#}H2$_QIƤw2@ɭ4G>2 GcGGG +HXr 1lEdCFH +I$c;VZs1qǢ$ k@b؜GENȜ IdRXiνg6:}>^|l16AD6#ϣ'Ic;VZsﴍԎZGΣǫ'\@1[f^ D&yyFF#E#3HJ%Ja5:Hu2c$ $İi7;DdeFFE#RIΤw2@)F8 G1ǣGiG6z"oYD#W1%dRXiν6:9}>;| +HaD0332 yi )S))$(`pT:x#İ #v$#ȣ`HINIϤw2B)GGe1#LJGǻ@bȺy4BR )S)TN*+s:Q1xZ"c$acl@"/4)L*'qұ`y@>H [& F)L*'11G$İHތ32rINIϤrRYY]8*#|l16K5(#sDY$S3Tr4͏ Qcqŀܮ@brFdVR2TZ`o^xQ(y4ǃ1 1l %vBmFs#S$M%%Re|pt:g&u> ?cȑbd ,NIdtK|al8vx<|xcO@H [&$7#He$!yR@dtK)wmt4x㨀6& Fʐ4tJ +&FoQH>FmvV|ôm#uFJ#GP20IN +)EGc:G$İuo,fd<9%I!eK} S5S +dۦXsl0idP20dPZXf\d4=}~MMd"$K DIdJey}Qc;S$İ6Ɍ!)JF&ʌ֙e%"'@b ZWFJ$TH% &9+ .J#A +|=@na?FYE#H&JZLRVL\?tlqH ik%r6y%Ieٓ㨣Gq> Ha-lFV"dLr'M*7-u<*U>Kֲ2HD$gR9<Ɵu|Mf0Z3UY0TI, :V6$sD6~$IepLuLxGa7~c3rIHF$ %sLPN>eal>H [Fg#KH2%9Z+[ Gұ|D@bM\oUodISuG$0O0# $M%j+kG6 1n-F#ɕLPVO=ⱜs 1lBd=!IHJ +&-VW38uǢH 1DYPR2iB4[z@bئNo$Wd;r82m@bADPR2iB2V=t?c?~A2f(٭Kq .u,)[6|ΙceHcqQ.c,H~D򣒛L:e88G{ | F%2l࿱:VxG?v#TrVWhq,(p9eȏH*d-#vKG븠~ FodGrm% ea펿󸮏 CD򠒥LIJn_<>Q BX#7lJ2eȣ>k7rmIڑUɹPm۬cHxЇmя6J3ݶtQ&h.J6;9Qwy\G[}FD,$ﰺHF*Ydw*vݍ> +$HD!#YdNVxP;Ld-NU6(ˣ>R$er5#f-j kG\F&õ<\sqȮ<#<9,GR@'+OW>tn,dKCؤ2VgbA#+UɩR׭MSG}8He2*)js/}GxFQ`&g468ddgue}5yGxElD]u<ܦ1bdosNelh<#^O#Q0{Wi>MdE,])d&g>>V6wp݇@u6(1Ǖ<%]G +}7 aiB\V3#PJŲoȴ7&݅d7lέoӟ`%'3ynhd4?L#'~K@btDNv2t7dFg%d~;@xFrQ)Gv=a.a4!C&G~'u d8Te"'WipAsL%'Kz&~G&'+ξ{V˝%ށX/Onee~fȾk~E-:J~:˾a~SIx쒝!NZٷ > endobj 292 0 obj <> endobj 293 0 obj [0.0 0.0 0.0] endobj 294 0 obj <>/ProcSet[/PDF/ImageB]/XObject<>>>/Subtype/Form>>stream +q +/GS0 gs +1314 0 0 1692 563 856 cm +/Im0 Do +Q + +endstream endobj 295 0 obj <> endobj 296 0 obj <>/Filter/FlateDecode/Height 1692/Intent/RelativeColorimetric/Length 195315/Name/X/Subtype/Image/Type/XObject/Width 1314>>stream +HFaZ3MJmJvwT +@1soÝ< """""""""""""""""""""""""""""""""""""""""""""""""""'8DD=SDt-%n!kl|=~fDt[\P#ݧV6ϕ.ՂLDjִѹZ3h+ 3l5LADgjζ/ֶڠ h+"ZVs~iD4\vk/կ[j$VrA~D +<,@DZQb)$>H;7 yot([8W_u:b3 >V*4%:FLk`WJ>+0W6\}(DW!:FiQ|Q!H>j>gd2+b:^VSHm&΢&1 㽃,I$:Ƈ-ՁLb$4469d(' gx`#Ω#x PbT",./EA'#.;t㠦X١$F-m*]8a<}L# D QGhF$#C#ب$456& Ftac l/q%Ǎ\}oDը <6\q2 @#WWW&$!( >tl-I[Uҋ$Fnn81L.%\}{Dg_6jPzt!Dc]V= &CHb}lit:YSHH">6@ccϻ8H\Xi4 +ct:٦L#W_"6G-2v.KHb$QT|ljcIJI >#!c|txt8i)ـdr|c\>vh%OcDzWI$:|Tyl ѬCi("i II^5-}0A{Ѩ'}J:dЌ\}DxplsX;PL"9էIivң䘑Id1 ]>hb;t֠T"FO ~e6qs#^P֕"9b$3Hm~:Vh 0u&+Hv DhǴOzӂRfɉF>S5c; +&iC0i*mFB$QQQQgcjRRfI3r( > +QQbxoʹ,l0rtFVN=%lͧ5&)IIj >j<:60Z}Q*ԆdId-|lQ΢ϵFԥ4ԦddIT5 ;|TxupTlt +8Kʒ +ʐԍ|(iirhHG><8j2I""? +6ِ ohzm@ g)]SٔL2"ccLcE}յ,̔dHHZ|cc,ğGR`Vr tuiH|Lxu,ldl5HY:1ErH$*k= Mh(XQMmNɌIIIdHF>*Tfd#D5dFUE E&Υe#Cg3&S/ RGQGFEE/#)JY82)LQ#lj\}DSG?q_u7SpRRRmFD~D@~d650|Mɪʐ웑IW]q7wǪ)H)3i+#idߌH qƣccIƢ`aUŔLNO2$-#IW Lcc)c]os)QC)0BH{F"}Rq7w:&84.*&OJ&H~Ge9#iFB$]eSTcLnjFŜ_MRr2$;lIWX8ƀlQ1ӱ1Qt132,d:%]HG&mH{@ +>|x|1ӱ1Qt173,D=FB$)@2Gm>~X1ӱ1Qb1w3T;ɯ%$!3RY%!^6r@Rq7-3w8&60$~F:;&1MnHV|ygdmFB$oB642hqocJ<: "鐼53HmF6D.9ƀ||GGIFg +f&eeIoL7H;rObFnD>'rO4 Yv>Zon||woSs762J&- ̌mN&cREr_"o|陑I!@O><^ ǽmGnR@ۓ{%)yw7HnCiHFfH{^焬\|,x{7w6&4 +( *fJlN +JjHH$R I }7>N ǝ{kSȯd7FȜI@rg{ wU2 |Lcx1ñTѴ]no:8|aI7 +{/"B˒Dqt79Es̙.|3wԒ@$Vj-whF~D>/w@dy9"l֯X - #GG^ǀcb#QQvٛYf +,'9jF.0#Ԉ-!2Gdޠld9ƀ9R$.GBcʢ.╺gbV&N1I4\Fʌ`!-$ 1e 6>ZJ]<:E9F9EKc/u3S,IʤT bJ4ȉc1# "ȼo$doTrdCDŽG#1`*+iiaI N&$Ada#9F',d^(@6ҀLrd}G1Ht8F):f%28i+S#,B \sF:#@d0&2GdހVBVr,9A4rdq|||(y:t6R ?+kW T$a+S#C43RHIdK٦";!yyW'!}@\ c>#52R%'EdȼAZ{ EBv 9@. 1 H::R F"C}ׯ&ǒRɝdJ^%4$IH=#;'A7xCL> gH@.||> +AGcJ*e1b2(!B4r\C#EF΁3`dLd޷o ׁE ]@.>h#hYg`) N:&CK^ %=.$I0r'y992#aF*AMyye !ȑ@N)@\>>Q|T|xt8F&Y}"&H$Lr%U$]HcHJ#=}FÌ\ƌ"ky[9)7Y$r4x>x >2CM%;I$JdH<,3t D.T&F ry2Tl@.y E x> +I +}<Gfc(Idrr,1)I$E|HHhH +%r"^HyB@z!U '$ H3 wc@JC>**<(p 6F)BDN߯ϰkIdEI$JZHz#]H:##+ed"QHyn,r2 cGq6F Թ_ƞZCa EtL% HF$HSo2S"iDvAd2?V;! ;Հ\N$|_KxD8#E)"gɰ$R(iO"^I[DRd0 ,2@ddI& B6C#򦿆tLfHqt +$@|yXģh$2&&R~'{{kLfeRs+Y$CGR1I32-Adȼ^7 9*l%@D ]@nYxN}TQm Hdd, :Qw1ɕ$HIȧh 3r32 Fy7Du dπty YT1XHx,uLp6F +S{Lfe2@IJjHdF^`]-H09OAAd970aB6Ȼm|D e@>,QXcHm4S|dL(%+JdId$I !#eF`Fn`F"YDN"lUN@U\@n ;Cd 1x :FF#G(U]z$YɠAt- iyFY F"Wmϫ +!$rrOmro9%dGc1Ȫ1XT-kgSdZF)='.%I02EyF>#/HH$ َO$ٲD6!Bz [drV 1 >)y,q d.JU 2I@R$79y FbF#D>A"m""M;"sD:JH H) k Mr3ȏ>^ Ky,t8REt:M%2qR(#)#CF"w-$q[""D*y;Gd˄$@r  r^@n{{! ! ?HQhG1Hm 2R_BLj%8k)ITB +| FbF>yxxDՈW#R#2 &]B; wGG'', _@@>|<tDSEEiLSbP:'%TtFSČH"U"WT"Ȗ#2L"Vȼ_I,l!S &[}= WGDF.#S`?ɴT(IdZ$$okgg''GG@#r|T@y$ٯ+/h~6inZ &Ke6Ƙ4iIt_wΜ̌d }jNB* y@6 Y$8䣇G#H]pދs?wͤXRj($W2@ +IiHF" B"_H'"Fdww2":@  @ M@s,hQ1Qhh$0Z$2^>LK.%qbR*Iy0rfƗ@d_oo@d%2 +D6R"4BDޛ%$ +Yf ʀ3@%93|\>n>e>| g%2 @nnm| }%1Dce"_%&Hi9LʘJ~ J*$yH2# # +#yFnBFf3cH$D "D<TDꈬ,-"? DB{WXK'YLBVABBB6@B65Ecx"l@vJ $5 C?g>|<~jej}Ge-I`On|49.RI I=`e01#HH$>o)"_D&"ۑ<ܜiRD܊ɎȯFFd +R+;!7`Bn C%$ nkȷC@Hydyx}|ty4:Z8*5A%^N%gR)I-i!iB F^#/]y2H$r&]C䛊W6$2DbD66ˈVLLW)yr=K-2!%MHlĄ܉ @|}c HW {{kaQl42=?qpo&RK))t#:#OSF뢌D"1#CD~KWlE"H투)1"҈LWK/R>< Q] RR҂R:TJ%%2$0$>0GgY)#w8TD5AdY-@d#RDf sD.SI,H*GUR Q&6d3' ;HLH V@:M@샀94|Ce>]F#'~5#YiA2)T%BrC9(y2IH"3=NPDD9 lllĈtJLW }&&vM C 1!HJH9@9RF߱!%;;D65&#rc\iD%N/E%˘LBՋlƄcB +HHLO( /\$ e@^ [!Ge-&҂R:)TJRKZHʐ#0#")#H EW$Hd>ɈLաLLWY }$NՋLLLHL0'O) /]& {ȁA amhpT6-up˸9JIΤQ!)C2rySgd/e$IIDRFFB2"AHAdʈlݱËeOsKeD +J +Ÿ́LM-VJHR$R'd4( 2 o`@ +S#u8*5*m!5JI$G1r Oy[d$IYHk'Z@"['"S!, ȕ%'f;!UB)!;:EB + YB9$q}hxxqըeX4ozb2*'JI`-0rxeD$ed"QHMdg!LLD*! G$2DR?tnBF$䋥% 2!m"!Hɀ<AO@ʀ9>>N(gG;ZGF#c"﷥,&RC8)JzHRH#Q}HDH"ljJ5ȥ~.B_2E 'Ȅ$d3%dA$$4 G$8@9y.cG#Q٨eU}wywJ %s)1*i!)C7rl 3&ek"# BJ" y$ll,cD&2%2X W@N )$6LȜHȎNrph{sGGѵhh ɭR2'5LII{`q"#>QB2"QH"2ʈl(="=!m"W&2bR Y T r;%dLJ6d1@\@: '&3<(QhdX4!?: b2*5IäTRSSNF)Y4"5mDdˆ|IG YrD.I)*di  @&IH G ɩ)㣛G#] Kd ɭTJ4FN&#GEF +"EFDRD!DHd&SLLWrE„NH#$K-"!0!"!MBrh G䭱1 +{LJGG1@1ϋXLFc!i#nj%2R)2##2!(d\"%2]sNȍ[ Y @zB@<$(rvQcG#Ѧ}iPJ' $"DR$7r2 i)"̗k2t2 %z+!3>!9 >J NL耜s}tQud6j9!VBf2*m(-&$YH>ÐF΃茼+2 iL\6܈\D:Bj"S!U?@_HH%drD!nY$d+O0ȣ]@H 癏#ggYF"*#DBD*"UD!,EJHZ"+dJd/neJ5:7!7D%dN%$ Fpi\dOcK&b\#=295)32HHI$F RF&RY$"k\+#RŸ́  +2d\#'dBj !!H Ϝ-$8craQ3#ѦDSTN +&UK +$#?QF>#?69}_ddHH""RmE#rҎȢB\Gn,IB&r )د窮+P_^F[& 0{C$:ivۨz;ci&Qk}w;W*_f8׳^g,)@[@2 [2 ?QGGGI*-`ӒRqd-BR 922|#7oPFz(dDD"ՈtGdA$d8"M!w#3hTT4R2I[B + 1! ȲrdCd8 @޾sGݻ##9FUF/}iɥ)¤$"|"3-Ho"8HH RD$cD!rtiG/-F!s!R@!PJLH2//$ !!E ȊJdSHQ966>1!}QHH:J U~hTN*JdFN)Fˌ2FDBDHH$E$LKKMaE;,, + M!wB&(Bʄ LJȟXB + 1!didU55 d +$(TrtђAW%pRQ#Iّc2#CIDԉlDBD2"!"HH RFWt%"FDA"M!͈~6EJB& L1!SdI) $( hQڨhs_{ͺTNr&H*FNNIDD"";9uD$D$y8E$SDf iG,z!%ۍܭ$$ i$d:%d&~HLH|,+g@s ) *kGQTQ'CMJ d8%ɈFNLɈiWd''  DBD@ȟlӈ́̔IB#R _!wB&(B IBbBfh rd@bBdQ1YQɀlh$ ;9< >Ρf>τoRBDŽ O U & 955=3t60&~ڟԹ^R +( %%92‰9$&"!"HH "#E[2"_9RD>="SXD&%B&D.="m!#9Y NȀHTJH27%H y'$,( KȚZ>K@:Z@裞*auiƭͥ"p$S#a )9DRF9KD2"!"HȒNbD5_Dȃ,"s!"("S B#RcD{>}LH2%d8!(!T J|LLRHHlm# {! 3 '&x@> +7lIGIffjTJ'JZHzg$2$"loC"!"HȲR," G!jDfSDQD&i !"# օńͅLԄ !1!Մ<}B,„,D d/y#$ $>hdQﯱ)Fp3)H~!)\ZZ\X99IDDD1"!"HH ""#*"̡LO'!(d@2LBL/6.` !d8!_< y +,+D .RҒ\G +Ŀ> +Hze$2&2yB"!"HȪJSXD!#-$Ed Ԕf-6_Hq^ ,$OȔ42UB yD [Z3 s+@O0 ȹy +H!t82:Pε9sp@$GD2l"ȩ)F$HȫWgHH "" "#D L4%"7r'2ƈ\,v!wB&!$&$Bt +i$QLȓŐdUu-$$@vE Wd@ʀ\^^Y]uhQF{k}is@0遤 IH-# 7׈AF$D$َDBDBDV@Dƈ<uD|Ed.DdDd:E$ ЄLD! !="_|yRH%! $%'C!JH2;r_ Y Y @CB"dO/9H@^ 9rqxR(Q[l6O55*U& %9kk$hc 2ɡNw !DB@B6BB]d9t| ) IhQ(m4Y4gt"SReԐJA.2&=""#hlj,,yTC^yEdDd&DdZZjȗ܃DF'6_HqݖR +R2 LM„̓ +N|3! !!!3d9%{{9=À\\Tr}(щ߿ +jMJ2$&$-#?tC HH7gD^DBDBDvuBD4CDADVBD@DxF)$<,tH2 )"R + cD{e!w1!wK!H%d )99!ҔB y3! !!! ![!!ȳ=2y YH疏BGi޿cLI%&m$M#76"gD$"0" """"+"{G}P09D"2!_BfBFH_Hq" \=BH/!yBRB: !OCBV@BBB6ABCB y*- Hol(>y(uqeTcOz}ZR0HˌHHo1"]E"ȾޞM|EN!YDbDfRD0!HH{JDB{F%!wB&jB d BEJÔ +@^# o{\ D@>~lQ(mam6JLjH~+ g<#WVn"בHޞn "">E|"E + e:0܀ 9^t9R>E + PDo*.Tq`l8c|<9soMBƾ!"}ӼKH)d =!$K큐2B G&d9!'琐H6$$#At s'K6ǐf2Ð4c@iQҎe5#PFkfD~lotB+""$ȃ"2~LHq!c!ttR ՜BHq ! d* 4 )rN- Y4@^]rc@)rqQjģ c$ n{6,'U& gb{O?eDRFډDD2"Lj "M<""YȝFDڄzCB*)fB|D!6$B d2L醐xBfQB抄,7% $Y$dKKdOo9΁yy ȕqQQ?kMI*V#2#3F--W9 9݅lAD#Y,"ڈHGDI\H+!&6!O!{e!EB#!)!)龍 )rL]BBBojnEB!!dWW@@ F@>x>|hhw._,"&)mL*H|ΐF>"#WWA$q"oۉDDH9FDvwu""/!"yDY#GEdH""h1D2J;42 +r=^DBAt)%! )!EBSOH.$d?@7@~O@.-)||GGCGF +_D4RJ'V$\YـHHF  ޞ6Dd+SjDV,DDPDH!="3IHDd"ݮCMBn*"5m g?m*!_PxCHL&!~JH"!w''d%!xB#!{Hѱ 93ˁDB$+Zv5]f)iF0e$3DF.-9dD͂HD "yGKDV̧GIBRDj!">!dEm҉Hgoz,d +d r=2BLHCHrO2 Yʞ-BxBv#!Fcrj@_3DB r\kH6%f7m`YJɤ$ Iy E$' "A$"2@DvwvlFd H"$D˄L !Mi2ٻR?& H$B d2L#!3~'dJȽH\$dQIiY 93 $yǏe@}d(yTuTqhӐ[u+v+&U%%TT3BD.H"oHHD$BD!"]<"[Y/# "r/E$ I"ҟLFDnNm$dttAȰ UIHq$$%2BdHH#!!$%=Hl$dOl ?08GBȹ )u+"PRGF߆wtV*NJ4BlD于HHHDd FD?vCkk++Ky9Ʉd)"2GD!=L +i#k2V +ID25RiIHr'%>$dCGC&d y Fc-8(Qъ6;- +V%$U#CID~.|HD.ꉤȹ+cAx:*6Q_Y-'U%U$QD")"A$EUD"r,82#͈Ӻ,,EDBHD$ +IFB""^Ed%"cH)dB:Մ o郐$&!EBBH$HٹyHȒꚺ'O9$dOoO $ @ S H{@r|Txj0iR#HdUF䂕H "5D "rbl4#Edsl(/+).*@Df#"ILHH,"~? !uBF[]٦@nU2T#!].B&B2%$ܱ w_vNn^AaQIiYEeUMm]ÁZy:6F0?-*#|' BHD$"ÛsI}FD4x u5Ue%Ey}ɅGdz @B"""!LBnB +""B&d$d^H3{9yHJ lNHy$$q ! @~΁|\ Hǯ>*~(䱦Fw$9YIH^F>ŒD"ܿwCyCH$H #-NDD<#|.v:Vh@H  YO^"r/Dd[R mKB@n$Hf{Q.A !IB9 + Rk:dBh,LB 9F': y$$ #++b@>4E4VJ\%IW䍏D"1"^$È, l:ǢP]Hɨ!BbDvwu l&r;HYHyOr[#!wBlni%BPn"xBR BBB BBjb9."X"dR 9A'INBN71!$@BB2@~yrO"8ikIVZI$i#H4ǘH䊐GIE$I":F "$l&LĢP0z\Nj1ADj!"(!1"yBF!DVD! & )﩯MHZH%-~R($$$!uzlNÑX< DŽƄeAB^ @BB k Iy  %|dx( '!%I>Ff[,lD$"FEnD9}eȹٙ)aJQJFJH#bd0#yDa#$F +F'و*ų 1"cDNMW˥B>I'h$ aZLFN!AHHi!{QN&$RRmR&R޷|nB*8Bv$Ą|>R= Fjw8? +Gbd*Jrrzfn؉ KR .IdĄD utl1<&kJ5b"SD޺IDDFf''FGR˦Sx,^[-fA AȾ($DX(d#dRغB{jk  ʹm ^"d7 +yOH(rP҂&fw^? +Gcd*٭3NZx}m_Al!@!@^O<$d۶qxEܛt} 9GG6q:BD &d*= $$$&!!  H8:X-Ge$#FVK#(oI#ef)h8"sLFd<`D]u|(ߣD"^9"W19J&`DFq96etd84jTJL+|bikW!/]$," TȦP!WDDY]ނ($B@< +<yDH@@k]Tbsy|H++UjNo2F̖qt{|`(ONM'gҳ\~n\ ȪH6"n3R(JH,O !_Db"3$"?Fbq~.ΦgSh8&I%H*ݶ$I.H" ##rq8WgaDN'h$ nn3AVSeH(q9,&F!;mPH!#B* &BK*d5?M@c!!B!ہ*ds|P,PHVYmvBDlr*Lg3 @|VH$ 1H#۪,JYH2""7""DB!$ț̦S0"cp(z\N:f6 @R!JBa3t* +RF$*d)"!a ~tح +ӨrioX$8lNB^hzybYHlD! B->(䞲|g[!DYm/{BB644655B/ yT @H*dNf|qaiy$-4!?&dRB>^[@>@~ $Y@}$XmcmYN+G ɲČ,% r !Y!a"reyi8_9J&h$ nn3 zVSePH!et @*YDP#MM Pȃo.䮺B];r?**!ONΤ3\aZJȻ5$Hg !?$6 >bxƑ̿ok*JVdD>D>D#%wAD޺ycueyq8Wg3tb2>~tجPHqhPը +W" +\ɠS)@v dk ׿"y$I(ѲKBV"J +u!Q&B@bK&dccSsYS%!M!aBB!/!!)4:X+C!4[ƭvT"7oy$JB~^`B>}* TNbH"DD| +\C$D畈";o\^Z(L*Ǣp0]ubB: +)B|bn}6GuXaaxp +X00K{uUh{j&l$Ό >@ιwݽw%;8>C !1"BBF!!"v%.{ByMHjBBC!v!S3rrQȲʪV=42BD*W(`uN?M$<@B$Gg75#BD#|H$3F^Q+rD,yё!@? +P_[SUY^Bde&'%DGE|\!مF$ +yIȽrGH^)䎟"ABȣ.C !!dʣkUܖ4%7d0$t$r |DDB~%-"oADNCDZ&DZ$b` zQȖʊ"2;3L%dWAK 3.ƈ7 "'!"MFNQ)2D$s9C}]U%Ey(dzjJRb +I +BQ.!)9%-=\Rkuz 9 y"!| +  f]_=H'xZз.@6"_ ֵ r |D=zDȇDDޅ 9i6:Z$b` ftwv675TUBdeI(dtdD8+4! !O|L#|.{!EF$oy'NJ$7Cb?؈XZVg@sB>B޹9 i1 zFRȥPqF,)*F!Sb"X!A U +yƵG!PKr/k܏[ Yȣ<}B^!CXaQѱq I)餐E%Uյu -m]=졑Q. +)JZMIHw!!|fK/ r reȿRG:Ns;cvI#\"0"P"#F,D ɉqɨi*\&c<{27;+#Lh" +yڕG=Bz?K ARcB"BAȨ2+(,.)+ohjnm 9&2R Fe|bj:$; f]_x&$Hg-SISҥ4"mB"ϟo[׀e{!"OOM[F^Q)2) +rFك}=ݝmM 5Ue%Ņi)ɉ 1QaPRH? +yꤓH! !P=!={ "Qt!OB^!}A1(dZzfV?&IrR &ebrjz=!_ +IMU2!cBr3 1Ͻ|D Ĉ\uH { 7!"&',fAӨ +T" ?7'+LB!##Y!A / +yM㤐lBr7 +ӕ;19}}$٭+3ql3Mbll6sTb@ u B{k%jwڪƏL) $KxOqsrۮpg DB) $g@|d輋NXɅHdFIFmvD+ i4R!J"?6lokinl(/-)*̰BBz{zgPR<@ +MrYȭ !l*$ȗJ_9rYm4!w{B~f<~"?  + +H7:Ο&%RBh!! !M+센 yלp=9xt9%IN#ADCsDňŎHri2ZZ$"hkmnj,/+).,HOMIJC!î\ +BB!OI!!vRw.!]{(@n"AwI!B,$%! !B!ϻ{xYBGDBgdep?84LœR\Rktz$$27J !< - 9|dhDs$I֌dB$?pF$ +  BNO "*\& 'cRȮ֖j qQ(e2yvQ$ +i&%kƞOHHF +ǁG !OH!}Qˤq )iY9Eťe5uM-]ݽ}#(H,JFAHHȅEHHY>$ڣuOdt(%IԌD!mD>A"ۏHryi"4tZJI%bф?6:2<8K ?7'+3=-%"U2"Yȓ(QN!ByA!_s t|Wr?G!O  +A!Gr +YU][O +E\Tkzq +4 J$$ + @Br&FBR=`ґI'|Ȍo "I!!"AD$jJ\* QH@oOWg{[KscC]muUEyiIQa~YȤؘH +C +ylokinl(/-* +BB!OBiH.!BK! +sR׹|r+U4!Z$$)QBS 9RH_2CqPB*QHqjzv4 BBBV !޻GO^}|Q9HJE:(Iy:B΂VBJ'(odh&da~^NvfFZjrRB|lLT$ +y 4 yP= 䮝nn!ҵWo!V!v!8!)95-#3;'"dMm}CSsk[GgwO_ol\BJe +JՃ3  + B26w?, 9|tϱvd\FkD(Ura~nvfhk5jB&E5Ue%B!ڄ>>HHN"҈E{dD@Yon+ 2u( +c#Ã}]-Mu! r2SSb##PPse񙵢茊(,"BzBI(f]H#!3ά>9O99!* 9r?rrO|!WLH9B|$OiyB Ba4=B!\\=}C#I)3rr K**kA>YB !QB"!QB: K 'HAF>aD>&Dq+"WGAa$FTe}]m-"B&% +y<r7r;G DȵH5bB.&_X@ # +*$Z"ۉA,!'<2/B + 9BDBr_8!AiQz )~%dg9D +D-DH $ R dscC]muUEyiIQa~^NvfFZj9"Ȉ_/Ow7gG07CB!w!'y|IRڳ F!܇43!AHGg7wO/_а*乔Դlu dgWOo_\Rk(!B޺}'ф&sQhƔ400#)?"E#r +"rD7/!!J킨q1g<B %&Fu!ZIBJ@!_Wȕ+W%VF]\!'<y˕*   I %cg6;iHHi HHDkWAȋHH-R B675TUfgeBFE2B:;9 ikmeinv -䖏B!_,'.s -먐uBna BEB03 y%dHhxD|jzFVv.KVT(U$04HH,$93swv֔4tTRHQ"yyG D$X$ЀVR*e} d;H/drbB\^H?oO*q,!BB~B~FG B& )mmB!5R y8? +G!G,!oBN$; |4/$H}FrGHE1,!o~Bj5jB.![tBdeQ!" t<}y҂-"BMIHiKx5o|ߨ_ !:`faieckwy#dXxdT42-=3+'7%dcS O&W( %$#Tȱq4M9 R, <3XF4("!"'pDH" KHZmDꪊ)I T?_o/wW*,!DB~DP`!&B|$g" !&B::{xyS!SBWTU!;A~B !/(!$BNL338!CB>IH8F1M9# ɎH,䵫 E$VR= 䅖y9ٙTȘ3#H|yٻ3HHB y 94ը~Y_O7PY\XE9+"=igcmean+[HHiL/D@ !_z!S!@H{"?lL\|"2+;7!JF;0D w*rf'$xBFU7r|ȩIHHHFAHAFTAȮv*due^璉Q!B>y<rKmBn BEBBIHiKfBn'Bf43 y'dxD|j dhAHXH]B!'@ȻXȹ9?& W3HVFrGs8"8"$B^!/%B45a!K +ss qT@?oO7Wg'X!ܸ!IBJ[M\A\\K`(6XB&BvprvBP!9Eťe5uM- dWwoLND =D;HY&!Η@}\0Ƙ3Eш| B"!8"uB;,Q$šZmBfQ!"tB.c\.(jBna +qaDȤ*daQIiyEUum]Cc3%B`!QBrB޻wni )yBR#D$#]G$v+ԙMWj%Q*h46:"`Wb;-\ +vvgl[YWfg6s9=O0brDR!/rB61BV`!KK%BBld2rqxXhpP?9 1 9 9 +9b8'0!B +B 9 +9 +9 +9V, r"dde+1TD dEjNȺ&,$ZH"$$N+[HNHHHB)cyARdii4vul& iHB Πike dA^nvVFzj#T=vF9Ǚd"{$ jO?Fa =<}|Aav!oBGLIM!KO!:Bdن4Bڜ,俩to\=0RJቴ N&yLi5Xr,"I@m1[@U+ BN7rr<rC *Z?/9H($,$/Y!H\: + +t/dAaY^QYElDB6x!y!o!AHՅߔsHBZ&HFȫW8!#!g'9Yiv!R!7R!DF/ + +_B$BzBrY *ړK>r3!'Q!!,]N ? xI"F55 !sB +y6b  +,䯼.F'NJtc"DڅBr)2'9$dV`!Oc!K!N:B޹\FF!'"!) N7{"3jXn +B9 9 B. + ]ar#{^*drJZzfVNn~1tyFse@Bx!9!XH)=QQID:HHd4vuvb![TKg!+'dLBnB\L \r_o/OVȯ||K^ȗT!O^]re\A7B(׬^޾ #,Bn!cGS22s ASXN_['-$M Ea!م|`!cT Rq"wBvpBry*'d3i5UX2Y!A[c@+WH 9u@/]#RR !_ꍐߊ +fr .*!%X +F&$d '$ZHV[Y!f6N'>冑R"&>fZfH# +,*,HOMBBnB.䅜?'!!! 'Hw]EFT!՞HB>㖐 Tȯx!BNB(#j*v2>!QF2,dUuV7XHb!`!;F*d7 @trH&3"!;rB^BGB6juZMu@#;Av!B3\ 2B +֟뽐FHO/^ȟDBBƀ)YٹyE d9#d#򲜐XNBd +/)3&D8DBڬd"BQ!H*%,9'e<Bn!eㄜLKUH麐_rB~#/|^ȨTM *A3UB:XH)@I"N$#]F.$d;>DȋDzC^BB+LOKIB!V, 9 +9SoBsB~,w3Aav!׃;AI!O +l B^Bdb+򑂐B:ET&R2DHJ$'dj!$Bg,#d%HT F*^y tc#CB +2 +{r*r4rJt!kR + $uV!#!BB 9W2rm4r'q  ٹK7-!c!ʄܢ$R$I ҄B" &%49" 8"B yZ`B|(fBXșHHȡX^=ԡ9!kPH![R+rJ킐 !B^ 2dQHd2 6'-&!rBnS 9MKȮ-B!U!rr4r*r +1+$˄dQHY*IYhI B5rL1HB鈐OP +B6-d$.BcBP.d)>!mH7R[2IHD($" CBsBHB.d NSUB҆ϓB> BB ! Y ٌ&d$$$$,~!cb7Ѕ<'mR<bՄ4$##҈ X'B<@>f]ڈ5Vb!gӄ-g $N(d%SB֥ٖMșX儐E!B^T yKKHH%*!4I@OTAH~D?"܃DL&D$p߈B6]oB!@Hk}!kB6lԸ)!d{A^XȡH2!(  y/)}!ӑ>QH y $J!- #R%dy!eB^ [2r.!OH؄πP 5y!gJ) +!DZ^%ױ7!34,D@BB0!YFr!3<rXkV+l ל_B~#օ# #M ,d+!gc!WBnBBQ +yHl_%J!ݛZD*Db!6/My!BJLB&H$M!|[-k $2y@/iB 9Q&2[& L3)dvBB޵!>KdB ƚ/ 9+d !󰐿a!!K)B>tGHY./NJKdBngrPl!B~C=r8! $b;8!BU+Bv $䏄? +y!5tmBʉ BnP9Ռ TB!AHȫYm!_fBȯ$! +6z],rB3urr9! ,,e2C!$!/`!b!"!7BB!m r!ߣ : L! OsBntA%HȲ I#bD*, CGCBR# +,:BxH_[B +F#RO  +M&r +BEɚBn$d! =!шVyC!yB!' 3BP 4/%!u,U ЂL钐 !O"!5\I9"@B +DP3!t!y 䧒_I9EcGc#)#ҞiH$!pB!dk +< f\r|ʞeŢwY&eBa6 x +L1IGlB}d'RWc!3%!-  9r]!Pl!3 9#Y uB/d/QȶHf $v.ք릐j!9 R HSB*G$)}+B^  >f]Z{B!pB#\䘐9+6D򶾐'G9F!dw{BV S $м#dB<<圐eօHDŽiBMk؄ڹST!낐P8䢐|[cDžc2U.d)d($R&BiORw8!sr +!`]!B!μτ~ m RHg y$d(VBȕVl +BB7-r1zB^&Rl;Bڝ $ F&|I(BUH-".aC!g 0|HB6 dGB"yC[Ȼ.i$È iB.S 9%!+7CBH 9(dSk(dFt^[B!!Hl.* i l 崐$d +bC]9*u +AJHHE +!M y{BV!!/ 欐ց $&Ҧy!0)d BrY!끐PBtTH:gYxyXAHA!'2Q%5HCJ!cEӅgJ:5AH(-IHV #d9!7BF'd ^j $@H,d2!]@| 􄐗XH r42 ,?uq|iF D_"B,!Ω-Z٢Ѧ=-HRD(<'KRd:9}ݿ~~?]| WIB +! !ɵ2RZ rN!'r$B*dKDH$BHB$x!BGH DH,&Rȭ!HB"$BBHDH"QI$! $B"$B"$BBHDH"QI$* +9 rB"$B!HB"$BrGI)d{DH$CHYȢ$5DH$\Ȇ +Y{QVN {PXv 9*r,BjrP(d?$R dBv[ ! NyIjBHDH"Q& +!#Bk B/x$BH%$?S(d3]B.+dWF!!ĜrBrz!B6EH"DrBI-d@IVg!._![%rT! $B%K ! rBwY*8DH$!B.+#$$^!,|BnsUȕe5s)If!r+!9TrHr![ dBnDH"i#dW%B/Z\Wȅۅ|!rN% +!!DH2)kX#l,rBIRPkrrw$Y,fDHDHRB" !/DHr2(ddPBi $9B[JȫC!oBHB> +B+GDCH4@Ƚ"!O%DiO!rJy,!_FHDHRB"duBySBB^JCa!?^ȟ!CH!$BV z!$y B +yc}!/AHr5[!!)s!BH"qfyB'QB^~y yt "!{TTB!ɻL@5 WZ-䧉|!G$BZ VB$d'$2_ۋ|! +AHn!*!B!AHDH1DH$)[SI"$B"$9+B2 EclO +y1B"$Ba!$B&rp(d$/.iB>B!$BrEB/AIVd!tfQG]"|,!$9Bv$DH$U!$B*H$R%d@҅3AHlV!ddJ 9)Rȕ. +BTJ#r!g!$B"$b!LUȍ>-B-!rB*b!DH7)f/Lז$rHȅ ଐ8B"AC){!+1!(AɄ!Mr!4^ B*57#d!-q|2Bd}y!Bm$*>!O1G?!JeB> +y8BmIro4CHZI$ +!R]BL(dBV .IyG{ !dPvyw!EH$B"IT(!w@2W!=B;!$BrBo)@O S" +!.1<[$)ggܢJȱ4 +!Iwz<!srAB6AH2>MBXW p( Hݫ;B!$BfB!$Br^2!D!!HT*!C"n!3B܄ !ɚ={!z!W $Q +yh*!@HB*@$rFc] OT lW+d+$3HK yB*(!"$Bވ܆Iy嘐o!$B !Z!Gq(ddI! $iH!Yrt!fBeY B>I\[_J슐j&)sB~\ȭ^ !撐j!9FȉI)QInY(ӦNFH4 +y*B"$B!B~DU i"$9WB(7B^Gf 9!!Ic +?Z!|!y*!GH6EB$_ȑEBN>!U +8B!$BB,Kj<!ɁB>){DrBHDH"Q郐_k($CDN" ! !U_"$Qt yBmDH I!ɘE!AH"))B"doV-z# $~!Q(g)U[C!CH%BEkC!o#K)#$Qd ++B@$(>ۅx!DxB> +BiB> +d!?-D\m/ɉ !!HB.?XBdK<\!CH$*B"d/ $QBR nrl) B-I~IF yB"$BR!d&!K饐!$Bz,;VȞ=DBy4Bݹ#KB^jDΥSැ"$BrBb!o7NȢ߫{N\N Y|D(%< !ɱ PB!Ǫr B"$QA +lb!҇S},!WTmD*kIT2B-R +y:BK(dDH$#rQȥi#$B!3B"$B!$B&rBO9+ + :B(B-!gr BF9'+_![ +!!orBJy dS$KBHO\G1l! Raم  +"C -E> 2RIIn 1fN6!vd] ! \DeBH\ZuI9BvH+!g#d=!7$r!BXg8W1!'A' *bBT 99]}*CV[C;}t y6,GH5B>Iz T.dG\CH ɾG"$9;BCԄ!4rRGBB^!_GH5B^n"!o@Hr>$!B $Z.BM"IT 0B"$BR +!$B"$"dG\$'3Cs>B"$QF!DH$ BGXQ !)!2ozBD!B6Y$i +yHȉEBndz zڧ!# yZ"$Y.BN-h4H)m!ɎB$3f_+\!!D#d?DH$ 2J}!oBHDH$DHDH?UBv,\nvq싐d@ 9rUBINeo8.䗞&XBFH2)DO yB !GHM\P鴐O#$Qr2Bj&maB.@Hr 9N$Y[<.!d:B.BHr0 97g!Zȷ" y5B!dt!*rU"!FHi'BފɄ|U5I$.o!rPȫ!2 !!D!$Br'$R+dODH$ER/W!w)@Km!2'BHʅ썐 (B"+/Hȋ !ɐDHID!c +9nVIvKHHJ y@1I6} {lR'!AHr!1vvB"$B.*XBC |1/!7AH2(k|BBOo!CHDH>L$d QnIXBdNBIy"dBD%*;K y:Bf!ITUBEH$RYB^ yKZBABj B"$Q!H^B\;nnBi)r2BY ǵ +9{L$IȃH 9=XqLOG!I(NB"$^ +BAH<!r B"$BY+k@[}! +9!ɉ#DHh(CBcZ y|"$B"$eBޞ#$B)#$ [| !!Iyn +B"$D y B"$BRVlz!?GHB"YYɄF3.B.dBB$)>!EH$RTBEHDH"DH$THDH$3X;!!-\鞐w)dU䈤t >4^$-+iBCH#$D Y,`_& yO҆i] r@!{#AMGIYTLSȱNȟ]")ƅ 2Z&f,$DUN& # 9 !3;왂I B"!*MD")i@B"IBB$%K42'$B"dBVHIi$Ut!AB@H'dB!%HIR!YzD + 7d.MB 9!2IO*UB6B 7m!! Bv.4V1(dԄH^AN@,hB._ְ!rFJITnM@lkYxB +'d!:8.K{wfzfgoϽO{mzێ_qq8v;N\@$ H@@$@ xB%]WwUuUwLz~W,d4rF  C Y,dXEk8!&2p2v@yqO|&2B^HIVotȴ ʥ}pq@~R(d!< d" !"!OBfe@bJB&"!=$O̥r `R -Bb B5  +٬ 9m| 'rPHowKkB!ssruzB)!sBNHH0yT X}i&\ȂB@!+R򼳐B&+[BHJ:DȨ)%d!'d)*F/,2!g<  r /d%2O"drDzddW,R vB3B"! +9 +9 i B5 2a +KQHe"$}=DG[ gr>KR!l y_ Bդ߶r-d+ @\"]D*(Y:JR$d%$2Z ir9rP.$iF!3)= Y BD青~1siIH{!#H8\,d ً\墐B!#eB1B6!!kh!!A!!b!5+&bFWtQH.!@ i!KmQB$d !FB>l#仁 yIvVHQ- FH%#=po5f\|3em| +9G4-Ӆ,BVZBB.#B!rB[w"!O\'Q"d92N Y DnC3`n=UR'bQ8!yHB!KBnHUׁoB.7r%F$E! !B&KdHǤ߀d\ydq$!ZR$d+VȞ޾J͆{7!!@B>?wAX-P庐mPzP]XT"0r G$iKdtIڥ4_HG @!eHjZX]NJȕDmc'vLJYX!? @HC0B~?g +y y yrjrb|"dB*$H,(" 2$]aoKqFGGtB"!s(!QNȚZCEXfU!ɅtJrB!+wjB =Vȯ&*NV$RN*$d.d12 O )HB#SS2m&$˖ye:2>J2$u(!)!@r"|$䂅Pa ;!oCBo +y +b 'B>c4򈣐(!0BV#!˰Q-BQBa#25"IQɢeZG>r@ζiOK #B!+8!M@$d7ʄ|@:%D8!Y\ B`!SBH,BBRDgoYczx  I Y)Q,z"!%B>A Dȏ!|HԄ lB.2B!D0҈|@d$"m525'#[ttG; BB!#Pb]R(dB d] r!=gb!_ y7"}{ !7#!WZlBR BE5 bHHHG$w20ҏeGchd>X( +Ye +ن܊c +y3."䣜/B~` +@H,osBd +kjmPn](dPJ d)+d!d#d +D):*G d !@r(d5'd)rJD;vB|(R]?!QD,BB3B6LBǢQ-ABR/H;"F**<*^h&)diј.d  +Y 9(vB|'R,RNc!3BvB#!-BVA!t!D0'D::#ã#ȹ(!-BVB!kB.^lB.ӅBy\o ++B|]"Hۈ7\B!!8!XXTӀ!JH.""6+ӳ$r2ѢX.d)24 lrr#'a"$9g!N! {NȏBy. +yÁ[7o2BB.B"!BԅB0B#RHH9Nz\5tmhh $a"d\ +Y% +٩ 1ܲu oA")^| W /Y!8ӅQOB+rϮ;&!WB.B !DBԅBY\FH\,"Jd`Ǵmh H>!Mt!Kt!ˡV!X,Z"ݦ'B>e5$fU3qBD )]Hț%BB B6!͈B&zDD0%$HLd#V$T}$guӶъ#c@BBV@!kx!@n"J ljwB>n/\WJG7DB>jı!72BBvB!DBV!,#2jR"tVRI=wyGG$I SB!+P6 d.d!fN#!FB-"'vBl!"! !WBv@!BV!+$"CT#RN +M߹8iIpDӢXq\ B 0!@庐}D5Hmc۱2MHCR] + dHf d'gsT׉ NXu " IZ{5I@b0l66`$/8ĉ$~L<9{9g$9_Hy!/=(!詍<2> + !C@p2:F"&2L!3uzl 9 93;O y$mBޑ OC!G8![BB,fA!SAr Q("rFHaDk"'I0R[&;{$Wۤi^(Б* y BgP82`tBUTV76pB3BNNM +D*"HIyQZq +ȵ$'$ dI )LH2L!AHdA!sdd'gB~ +'b!9K҉BZ&#-d + +BnzF$$FddDd(Dd0O#L$H!$%=u$FjjFR$$-d Ir+ +BzlQ<=n\qep uBPr] dQA> +頄423@d2#%+""!" "7"R=<#EHt~^[:\F#G?f|O d +Cr +B:Fl%dsK[{'#.!ϣWB~Qw\BB yxta~vrld2BI(d,#$?"c1"!"Cd"&r"# )ˤڔFHP; GHq Ą!@Hr"!7mF!).!Mf ek 9ǖN| |K߭LHs)䟕ЭOd2[-fAB(VIGH|$Jjw;HTފ}m#9KH2'$ +B&:dY(dAȾ휐&|EQOy,==! QlJHA!SArfQatD"R5?omLzIUF<)r- $)!AȈLHq d +30B:Q⒲Jmݜ'J|򍗼/"!NȻoB% +E!m d +QtDˆ|HY$L8^ITVJxF, +@>)LH2Hrk,BBZ6 +YS[rdtϣ!_! k-B~?uBSI|kWe̲۬f!A8tDn"r=%"FJ$3Iv'H|\Gu6 +u(r $1!A( + B&i `4[vGV +YDr`-YT=FH*!B~HұGfO< [ dYI1 +rجBI(d,IHH:"CHDHR&58NI`yGU<đ`GNGGGu@G  CHHr + +Bb;sy(diYEeuM]}cSKk{GWw/'䞽LB?q7BBBJH_Fe!!_ "-"!N P_[SUI ̡4 z2 LD!!"BPQDrDTH<$J$;JIuHT=/虎בȟ@,d< +BfFFܼ¢!v< +yM[VH:!D! ! y9;GGv,-.*C!:2LFd+"Ø ˆT&`$I$&NPFZo+QM>*G|%<>RTBJ!AȌLY(d +Y.`pǰPK@7xB~ +!i }+$H /QB^F!\=|H(@_owWG;%d]Mue +YBf;6Bf) xQLDcD#H,T+@O$o+uTcGNGG. I &$CNH2Lԃ͑D!QȪں斶ήONM_8B{B/?,!S){( 2%$Y$24MA YPXTRZB76ؾchdt{yB[:A y%2-mVȻB~ -B~+N{wB^@!O:Irtxhp{_OwgG[ksSC= +YQVZ\Ti5z]fFZjJ٭;㯀IKd! Lr mծvV%E1%)m;񌓋LSv9{ٳBBFg>ńdȽEDxD$02$EIIN&Aɫ$fF+~{2>ȋc6RtHH\m;X)$$$2 )Kdr + 7p!KJcw!B^!O%homG# q9 QӪUJ$DD"drDd%HɄ4&r%! Rȃ0:R1/@ڝAI_&$`6R$ȐjVo0-6B ¤Uյu -m]=Cãc&&q!O2B-t!{څ!iB5.GIBޏ y.Y\#'B6בBE +Cv:Vhi5*B.9xDB2"2]ˆčd"IQ$:Ѣ񞘏 +7!HHTPZhXmp$ZL +Y?842:N +y"HȷBυd +.y y"$.ġᡁޞҒ(y.f5 zFBBJŢ<E$CHFDfD @$-#)FHƕ`I.&ARȍfm@ȍ#K8:Rx|$ wdfB +!(!sDbThub;n TB**kB…< B-,.B!&$rUB)8fA3 Bv675TUBF¡`b2uZJI%HLHΈGF "1#YdSR)\=3ܓ18 +GBGGj?]$PB&GB +ZLfp=>,*.-+'lim&:24ӝ"VVR +@HaZFNABʥ $$Ƚ$2@2YU9ɪd +$mۚ,} T:r3v8u#GN AHHLT:dN  …Ѣ-!#!q!o$D IAB/!BB~B~L6yreiqanv< 95y }aY&^Qr2?5"Ȭ=\DR34ɸT&:)XH +4$rMR<Ƒdi:b<>2n2sO IHȼ|D*S(U`4Y6P8B+jH!;zzGq!!Ϟ; +!LR hS@!Ɉ y*Es cGAȉ uUe%EpA0]Nj6:Zˤ$$H6!DD#`!`d"$ $J&LI6%yLadz\d%ꘞqI<|$$eOHHLP5ZhX +BhqIYohjnm&<41 ypqfn~aiy2:6&}bB~F3"䧸XDbBT!o !\ZY^\B!Btu45U12~tجѠjTJR,!"wov")4$$~Fnp2|#8), Y|%!{Ҳʪj/2R Fjw?m (9=37D,yYB~\ yAȫ)!!!Ono'\^\!'@ޞNLp](Bb2uZJ!I"˩(/+9"dH V"2d$IBI&&;$kJɢ|L) GvpdFG\4O`i, O܏'-$,-pyH")jVo0-6j!!MLKX< y2dB~ \B>!B^! V@irtxhkmnj~rحѠjTJL* %dF}#[:h#3|LLG _D@ I%H +\@(H +ZLfty@llj!{@ѱc J,X][DBDBÄD IZZXl%_| nFTDB@SkD<0?;3591>62<4P >,fAը +T" +x\%"1"_M$YFdP2dNҘ(Y,F>+rY<2# Gh$l$pHǴ?${BX"+TjNo4Y6kpph!x,&Bp I"2х|'%[B&yq$j"[Y^!AQlijkCrmVɠiJ\* |EdyΈ"_f%2YF2 }4'W,J2"hܻD(#㑪cA6Lj#cx>}$$; y%$O I2R Fjw? ՅȁcSӳs󋄐ǷgRB^$u&.;w߻Md8!ф|.&Iȹ驉cc#C}]-͍ p](XzNj1:ZˤbOC$! "HYH1wNR̥$YhF"ȜYyyHñi:\W }aZFNQ)2D"""GD@d*#B$$}t'iL2+$SIfd#2r@|>~#SovfzrbCLkDLN$=DO`#F2ĕ1I:J4&)J#H\? 2ǟ2}d呪#G6qHGGb 1 #3,+B bTP5:dN‘Xonfzjb|D&t!q"_d!H $JI%)+ #H֍\?>qG $y#UG:#iH##8؁D- _ȱɩY_ KdrJ&p=>0T&+˕jќow'g0!/ 9=!o"$rP!BBކ$'eLȳ@% bn5jT,T2Cv:lVɨi*\& q0 L뽉3D$WFd +Iar-NҘ(f$ȭLuqm|b#` Y|ā|Q@b *'gx|H,)*Vo0-6P2 rVo] q i 䅋`!B^#\^^Y]Dțą?!/aBBB.tFZ)cBfRD,>[-fAըrT,y3ӓGP wlDnD74$dIL(Y(X\/l}d lHq0}$$$$񅜞 bTP5:dNÑhHHR1I8>H&JBH2FrܢDn4ԁ#z r?3<@$JZ3Mt{|@(œtR56($\OH(!B~X RՕ徐0! +0!O!!;fV-\&Jcp0z\Nj6:ZK%b?7;3O0o&/,N$$!%Lr4'LJ2Dp#Dn>o#a#|"_e +BH$36'QLBJAr0OrȭG'@"}He# T8Hk@򯌅"T&WZhXmH,H3|TM dwaq iLȋ}!$#\ț@@ȻC.䰅|B~s7!ɉ$ rjkreD< >۬fQӨU +L" Y|":D҉|aΝC3v%I +JDH#$-FH#ǡ:RqDHcOG*1 {>r[ȽBN )He +Jfp=>0T:+KjtbB„ *U7B~;+VWVp!oCB&L$.䥋ǁ] d^K|.N%H8{=nnV&r1|"r`$I}&N %IHIJGfS,FlV%r#D $S}# CmFǁt>\ B +DbLP5:dN Ch,LgB\ցNwty|OH !} y y)$$B!!"B~=TȻ}!oM$$B^<~_G#f8Zn#o#+TGאGG2ą}[Z;:{}N‘Xp4O\BVC  y" +y +9==s ;""$7TӧPcGA +B +\&Jcp(yܮޞf"Wȿ"!E"W" |IIˡ40+ɯj"v$FY'Yk(iGE,[r߁Fm!}N‘Xx4Σ%4((+oQa W^SH\Hrt!;}NCh,L|BVA$Bj yrjjzƞ_RjS"}A;Aȫ(%FkB=CG!GAY.L:"P]}=D6'rf2u\vq##|}M*NZBi¤DI3$\i,?&sE@.dRQGG[q!?0.dk{G']H Ch,Le@butuv'o8$DBDn""dF]IMIIf'(eN("i2H sq"YǗt%(GGSnFJ#rQHr& +䖭$,X]B6k r{|@(t&/K 9vD!q!9!/\R_H"FGF!4w=!6T}kffzj +9 BN(B*I$B~z9@>QD'H RH3"7Q"F]IMIIf'(%C8i H0l#ZE'@#˦(hm48: +<}d}\> 7nq!;{`!n"X"ds"Y!G@HXH y JIBޝB +Li*5 + +I& 3Dc Y!K|.N%h$ D:'$iE$l o'73Iv%5%' Oy&5%MTFRjHBFD04Q@e} (hm4RuU>>B@M[";q!BTV˥b!ͤx4DzDvy&cq"o#iNoHȍFōF]I$aN +PJR$&H#YȺ9g% (?>*c} (hmdmqTux$}\>n @ +HXHrNrO 郅 Gcd*ɁeBB($YHFSrBNMMȄp y"eEHa"'OQ!r\,䳙t*0.:DL$iE$la#773Iv%"<ơ1)i>2#_0H[@J| +G~aU6r4mqTtdyTQq }@5$,nBÑ(,d*勥@ +B $YHQ W7T!oS!)B !*Bޗ 93=5E!'t"!a"AȱQV!K|.щDK&rN8TH 73RIzJ%&2(Cn=Wyv!BQ+kt:3 HXc[RKR +-ȾC–H`F-I*ĖP}/ȉ <ܯ'&?c"H=YHiSE#'b# #E$BII/BiuRfң(Iiw #6,h!+E @29f3=<:*]C4j6&G/G$9 @Q@*!PHr +ru@!B!A!OC!ϝBC!(UH. dsN-d/J2DŽLr!)$H&$$| !ϞDDD$r$r&rRL$)i9d,| i)"J*&uR6I2#iHO #"|QQIptd<}>}|}@ș\XH{PXr(F^PPP#PȓP3g5XK $+.\ޞL춅|Ԁ,T!{l!$d&D-\HH&$&zDB"AȪSȣ=ȝB rY I@.]@Z ]ȽPCPP*(,dB2!H)[lg!>Y!QBB" &$K)$$ljD!j1UÐ}v"7`"B"?\D"1!""SE#'a#5#)?E#9IdJI^$U$HF r`$o|2 N 8hphu4y}@@yA   E!<< +<<B66Q!QH\(d+LB.G\/ WB. +ّf34DH.$$D51!Dn,D^"1a"KHi*lIGI^I$3rcEFٿD>q"@i@3x#GG[GcF1G]GƣGd@ $ W~@[_0  +yB +&iB2 !dB>v|W]I!m.H&+(dC= <YB:XiF!ɕ4ԜtBCuR2)+SR"94rHT#FLd| > #ɣ:ͣ $Y@A@. $ ׬ BBBb!/7B +H.[Rv[{(d%dH! Bv +!SvHd"DH.$$DQ"ϊD1YQ"1!" H)BIII':Iv$ ##9jd,D7ȑ<}<:pT6hT6822< $ ׭G 7n B^B^Bn!ͷQV2Lәl6ׁBBZB݆wY)d+ I!DKjLd&-b"7`"HL 4\LDB#F()TJʕLjN:ԡ8)ԔTt90yGDr-d(Ȱ!m }6hT68r*[a $BnB~,d()L;- d)dW>!p!5 K1 !өd I!y"HYO<>"y Eo H($ D Egt ɄLBBvz! Ȁc +ȯA/H#f2$$$2 !) H@ H($u K<A3B޸IBBv/dBEȼD6BvY!$$yK$ +)BR"/:<FcCb(&*)H׻̽3/0?&DD6k"wh#&Id(IWId#c"g:D~pD֑Hrr@dG]VGgc +F1 +V$ +@B"*B-($ ށB)! ,d +yd! @r,EHHZ,JBDvvP".$$$%'DWHE$$DD#"p)td&7i; qR3@F〤k0r5 ٠9Dg"6RR|\>u|\>>z,RBvvJbT.C!Q# ,d +99 +D*!D*"!HHd"04r52fEWR2īu2EIId#\F.Ѝ$ +& +9r2D֍SW1X E *mCI:::6f8:J}CU w@ Ƚȃ1 c*$ + @B!_ +H +v,$9 Rȉ2#@#yrZ ˥b00Bv: &DE'gTDb"HHdD#@h䃍>%&q(C'E&%$e$׃!#F.F2צye"B S(dHYHHb2HF&1ʣQ11yHqut&y u8z6树m:z:<>r }ǁT4@B"PH +gYWHRBvu\Hrt  +2d!v%!m"Qj,(!!]s&^"_=%H$@$6e6rnodDIɤd +IͤA()ԑ 6\l\J,"g=UH  \J@ M r #>>&ؘA_sC5f;T wr I@B!HUH +@R!_lkG!{@RBS!#ZH2r|rBN!#ByA2X.:=6J7SN"DR">2aѣ+I4cGGd |< H($ @R!O +IB* ۰ d?rRB!AH $ +9-D] +)i$"QYBB"0:~#$&RDR"ӈF*"t#;[H}dDI$:J餯$#ԑE52UH ry]ȹD2 rGd yQ % +2!GPG11Fc1[#h}ܮ}ܹk +^'O d Q!3T,r!BB2u$D$Ld YD˥b0DS"O%RɉD"u"Ӊ|FFn'#-\I_IfdIIW(:P$$"u#Lb"Ayu>"gDi"3L +9% 2*teoGGmc"QGOG#Q , H*dop![ dP(JPJu< 9$ /!H_ A!$ى<lj|=FM$E$4Ril +4H6\I_Iä$AIE-1ah8J9Gq +!H ) :UBrD!GӄBF9%R )D de\F!M";0g9gH\D>EDB#F*#j#wIQId8)Ki0*]I$ȵn#e'm& 3@ +HgGGGG#hmp4:n:z<657kQ<s) +it +y +نօ,K%(d +9L4B^?r9 DT" ]VJىtBDB#ǸxF +$fWIfu2fR(CvBhYo$\P9IBj"/DNK!] e!] E xx(qdiǡm8Zǭq'H>@G @ +!L.Y,$r + 9$ +BNrr@rBVAHJdJd&y&#X"]"ǎF*#FFj$[t%$BKB82Jr%5wwd2FFƉ\MLEyIt!9 g l 8>nb;#}<e'DvEHHe$~$ F2f%Kq2I$*)+")FD#GY;2 'KCd.d/wz!~dyg&n rRd- d#>OZb1"#Ҩm~Gqqzy02B< H ٬D![AHdqںHDB +$,dIDM$D1;ȜD"a#"e##C#I^I$:RFNz&EI\Idj$1ddj#,D䀐`"…ZH y H@H<>axy:2|4i8Gq1ȹn ȥ ],B^,Zȫ^ȫBd!D6DocDBfV\DF6FZ#ɟf%YI$:@ (C'=F)AqA2edY6rm#N&+60<t8lG#8ut:<t Fցj#+a#F"sqyˁ,Xn!ȾȲ9  Á|1QGcjVFOH:<"c1ȅ25 L Bn!wG2I\ȏ`!e!- %% !s/jDD:!n"O'M.7H2HH 6rHkd=FҬ$(L'@J e8I$$ MdGȱ`$mdodl$9|8eE yc//d. '   +r, #0iG#lc.F1q*ͣQ8a~2 @k-q e! HY;h!e/MOBƅlB~^Xl![IHOdL9S<'L4DwQ"7+W9a޼s4i$ds8OA&EId1##F@DLd)YDj!fmƄ^ۢ @ +$@` @> +8G##Qh2zcJǧiG1 $n=BH\H܃ yB,lc ? GIDa"D"!5oEBDFL\ď-Fz$Jz%IpCH2p0JB9| 7rH ,"&O$Y`"&y @# Bf 9@1 0E}$q\4|G4G#8'1e@ 7/| @B܅ ?x!B6; ?l ٦ +y )Dىl ̜ȣn"D"Bd"d!"_@"a#׬V5!9tJZ&O2p3)J$su0m&r9w)"$2D~e G -d,$yW ++a n |,ȣ֑ph2ZF1#㳠|l> 7/eI @Bn߁ Pl!O^BF@26KOJBZ"/dLD";[c6/"kF&F.ZpF$ge222 r3)JD24r9Y[[S]]5jYDDDYFD=p"2S @900dUUuMMf Ǐ'>z-<#6fdt4G1Gˣq%4+e @"/g ,{9BtB2"B$"YD6&L$yN$]""N[$62!rl%HFr!VR1(I$$!Imd0rn$92 4D,%"{DvBގB~-$9yk#,@NL||21GţZGch'47p$<2ccHr JȷH\H\ȝv!Gd!?-d y)2D3bB"I&ll"D܇DD u$$6rHDOtJz&&cPR($dɸHLdMuU'rX +^4B2${N]2   G=92[cGGQhhhGGGzAGM0q ! q!ܳ ,B.dct!/Bz!/4!!;8d"ȽH"L䟈?X"@"_E"a#7F˽ HBүQR$(JwIIbėLIo0q67[7f"rDeE'r09OYFY]27N,dd+}䠬@ՍG@$>Qx t8j5Q8*qg6|@@F }@B!-Z!{#*o!G*p$ +i'0D@d D~DD"?WD͇:$yy7 #w$$E%钊IȡN*&m% IO$ #Kkh%"KH"DD1'rXJdtBF]H 2L +Br) @X di*Ѷ'&Fѣ#PGG< L@B!@!mPN(d +9 rDp"Gȯy"(@d D"o#_ !D^`D#Hh Y#-#"$E% %II%$SIb+˗+"_DΕDB$r*+D!_a"ǒO Xr*9-9B)i,r2/ORqc5QQh(i4eT46r5U9=}x-H<@ @s1BB!;ݢ^ |(|e!njV"5!!K"[Ȼ@d#Hh)ld-4o䡃o1#I##IIKJJII$$Y,+42" 9 L "z"9O7 Ɂ d@&D d&  W,**.))-+sQH886I#(lT8JUUǽZ :,y>,7$ +Q!v!#ǴSHH.䐉D-7&Y<iT$%M& J%Ĥ$!鈤0cjJhdnFbE"r$2ȉL$"W "'%2:!(8Br|Y@dr  3L Y@ Wrǭ裷ģ‘+aOMGʣGq?<iȋြ@B!H(dЅ[^HS!& !r+CҙX$"ۈ& K Hhih;Z#k>| 7r?i! 4*ɕLJ'TR:2ɔt"iY^qÆ֕FZ%\DfzID0"%H$K$IBN~9 !S,dF@ h@. |#J.=:5:d4iDmIGQGΣqGH Y@$G@FVGBOD><_a")]@dkkK3yG#Hhd=4 4jdx#9F%&IJKJ IbRS]҃$HO#C9$2 DN!"G'c@Ho!0D!, +B + P9dY@Y#~>>zy:874ڠєѤm8:<=>>9 $y|@^1yC@=}}$ +2l!-!~D )d;%^$"țDB#߇FF S<~њ#|F%I餂ҒҀR;i1ɔԐ4(HFb#@dćԔP(`"0S1SD"5"'H"|Nr@! 4d*Br%\dEEeUզ͛l}}Q=h#nʣq $y unsK - +y?B>d@,]H~e!Z"5!H}ޞnId  ȳoFZF"hSdy ?+t_O!5!'R +Y"9=7?҈Gdy cZ#u#s#%$E%-%5&IKJJIɤ$M҈BG#WD"_C"_q Df)DhHdH$H䄡Hh2d!\ȧOB1$+dJ2r*r:+ŦGԑpt(itȨhm7AGQG+ +.  +[|\$E$)q_ׯ_Cd3Po5HIDҨIPdD( +JII$*@#ɌF3# +x#7FFZG$r6D "bcbx"d"r"BN@'B&'d9\@@> \fd.d diiYyG/JGG4GKGGmG㑣u@n:+W^~]Á!m +9GCi'_$R''"Lio#q#H}F%%5&I.)NxI II2=,*~=\DB"idN$%L"YDFiDrȉ WȐ +KLJ Lr OZrFBȒԑpt$lp(y}|<}Ryn@ or o*#&0L$yysDzɍ|GFRTR)1N*(]RJ(-'-&<^#ʴFA#7l"ˈ%&șHd&ʈLbD "y"DND>hBFI!5 z! + @&d&9ǁ\r@n,YVV^YUU]S|}y$Hg!B~#BQ"S": -ϟkn"Fw]H IQI[I`R:JĤP/A#Ɍ%%#++E# "_D9̚DIx"r*'7O݉J!&2XHG!$!K!C21L H($ $ _V@@nD 7E"U,[muqm JQب(u|Ky}4>|4y>@FPo7Oty{Db#x#롑hqHVI$gpRA+II$4r׷1#kjF!L"W("_D.\@DΚDf)DFd\\l 9e'BHG"Y +L-wBZBBL`LBgd XHr ȒRȚqq/hw:.d4i6j8o+-=>O*η\hmmkoxR. { + BQ'%@&%җ";;Z[/ ȓ'׌<i!IJYSRcpRҒRBpTJHHjF$#n卬F@# @"_zQ99H" i$1Dzt9BԀԅB22 +d@fs u WH sȂBL$sGGGe_h GKǿ'z + ? <@~L@ޕ@BI"J}J]HȾ"?tIllFFFH$J:D'J[J/rBIBҊ!3#kkE#˰^"iD r\"2; L"#HD3BXH[HO)d/dJj*  $RdY^Qr񧺏fG#H8lKSG G=Z(Hr)H/D䧂H+l"FFC#FHZJzD'P*)%\I(;۶FȍKu"/DΙMDN"SSR2Qt 6B~O2BB&C!33fR!H* +@[ܵqh4*F GGƣ$H>@@ ;::/F(4 .2t"H‰D`Y22=iItRA\JĤP򗠤$FR7rϞݻ۷FVB#"7ɄD2!ȌtL$#2>ޕ f"t&1D +!r%VH)!'B&b!ӰYTHRtYRJ@Vȝ,{>b<8l4*]4 +~:GG)4( +D 8 dBB%$RDg`)H-I_%II)NL&2{HUHF$4cɄԉdBr"ȴTȸp|'R +9 9rGH#$dKH㩐O)d2 I y!%TH<dY]S#rޟţ4*|SGG_Gy dw~C@]"tkj7 +6}m4iڪi6<l0lZEiMKtӨ&!LdA&KZϹs=}^O/_''# mp#wFړ*ə$'%BJ9iJ"H2#[ZLlnР|Ut"!9Hd"5[Dև'r"Kԟy2B!K\!PȌ E-v\_2 Lg/#;wlnF[| FG}Si$A=>G6=W,7[$ +@`!Y'h"/H`{Ha%et)($S2IF  DFZ"$R iLD"?ͱ,lj!DƄ\ xA D.S|!]!AB f!H _ @JC؇>JFG##s/;Br~H"Mg"="A D^"/l#HH1ɷ RIä'eJg(JIɐ#留ܭ6|Y( $|f۶"&rM$ Y2!gT  [H#d,;Bl!#@XQԤUt8C2A2*Gq| y@^7@$ '@>BfHN$y+H$I5R" J:/)TN*(P +)PZ&7ȃi#4D8($=DZ!WdB.ۉ̲B!K"BB|.dH\H 䫿D  q [log>rG4hp:b: +>"g@ yMy[B#!3(cD4 Z"?F")(i$'P;i4JdFvwwuvlnVDF*"_ )D/Ȝ2 2&d`"!RB* K-sv! r}h ے| wFiGi>d@~f<W! ݅4@BΥEO!r""?C"/#`9Q#H$PIɤrRB\ʀĤRRIȎ`#"j"a#3Ʉ$"!wDn&,B$!K҅\z<GncF+ѱ'ZG1Gd#iV ow< -r2DLHA VV"?E"ȋ|#FHzHZ%L䤄2%s2_OR0+16il"rtD!DTWU++AH ,>2QGѥbF)ZG#ca d $dQ ,j"$"']"o"'Cd#i$$=%LI \JJeR)WR ۓIYm$ 9m"S&MdNLda!frֈ̲B!K+ILB~;Q! ٸGy i`@t8FA#Q#yR jv *r! ȹrF9M$YȫH02LcIDQϨ$gP4JJ$i$ȡmmHȆ84DDnL&rNdH+"$!K҄ˉ\ @̱ByHۋ> D}D GFWF6Fe#Ǒǂ>r @yR./dF!'$~ț#1R@R+`:)dKidN2% I1~ EMsz"7\CYYDFLrIF!W !ÅY@ > dKK q} t|ud65hp|(u4<}|1 $ YBαq"BNFDƌ|t4L͘N2(K %2ɔFVF &FFFt&!'r-N$!3 +\O4B0!KQ$ZHrt٦9<<2:j1zG{ӧeT46ud8j]}T>~h} d@q@fZG9Bl"PHN䝢 l$!鎤@R+ə3)D(QʥtLM%I1QHd+#r%N%2DYL:Ț*50VHEd)IBH!λ@Z2|r^ȍE/$,d3sx8z6id2Z%GQgnZ#d扜D"'cD^BdH> IWIɤ$2(Ĥz##z#{a#"a#="D2"DZ69o"KDB.Kr̲R!W !BB&BBn6 "$lD @J ȣyGcFec GQGct 3i> +r!,dV"D'"Df#2e#]#πH3IP2ʤrRB^J17/HF;rmd_"Rm$#AO$#&6DD垐eZHM +91Y\RXRr5 Ņ\or[4@B:@& [i|?z#hl dd4Z=2%vсS\Bf$RLd[Q"4Ҏ?VwIex) J$2/F36r62!#RM$#RO"2DnUt2듉\YU!sf"H!J!K+l!s|Uu"d][Mf!B Bj a!9 M=Аȱȣ(p ddhiT6:hQh13/23,a|"PD~!t62HFIŤs04Nj&QIɨǎ398L#RO$&KOd"DVyY', d +L )r%) f^ȧBnͲHXH $,$R-do2rcO }$GƔid4ZƑpd:<}<<b P )|0 "#_"ፌHvJNRdN2% Ɉ'O8~|XbȑE$ldHHE$NdB &r=Ndm2UUJ2* )d.|:.r]"d}=,$ +Yh!@ D Lr`P9q'#G#hp Ɉ4 +i Gcse# U3Ey -Ù-YD~BG!/C$m6ks[=Vg?#33sfdwaQpAVM6mm]+;̰hM4QJlDŦE&g}ϙafW.4 FP2¤$CPJ`R+!i,6Y"H$ DDi9S$٠Yˉd!'UB9bBB YBVBi!A,iBB.Ѕ$ $2_0?/qu8h d48Nۨq:pxd><Ɂ<>K @'ȑ/D^Y>#HwGER(ifwR4N*&Yɨ]][6o޴\sLDr"HN䲥*wn9=5_YT$!u,IR Y1t!4@ +!u!+RZ2@&籐BPH +@b!|ic|}D<2>BƀFGQQ(}<>>z$ % +9LOp787Rwe߬FII$CjʗQ +&YIBrd`i/@$62$IDR"HN"921!u"; < +B沙 +Y Yy(r+d 9I IՅ!A6PB!5($ $ +H(dgȵk@B]}i|ͣl pDMo&(J5 2JGLoG|<)h@^I:ryeD~yVFvH_ RIˤt2eDJIŤc$=_6r$rCHN" Db"WD.s9['&D0&Hd.dPZOj%"UT"GHHdU,$%d>@f,d -4UyQ!H($ @b!#@n$ 9;v u<ǡhm$=Syy,@^(KI@BHKeyAy^iTe tPNJR% ]]>O!*HJ$\y$3L"Br"6Hd3$G!k7% +YN" Bި *$ +Yl![P| B + + +I@B! XH &GrGɣsGi68"ec><%Bt ǒ)D!?,Ƞ(#F*$2dt(/;wFvw%*HJ$I|`9*,dr";;:PHHdK2ktYDJ!+!#}B󄬌 YBf2BrJgp!\I| +I@B!-doȈ>GK1Bo1Ǔ@^M"H6SHd`d +RedP'TIdh===%DoR"9S%2MHLd!lmE!r9 9 D] +GRBE 4u*rh!WS!BP@nj>g- +#:ZˣQ(p:<<*O @^@^"/2Ld!N%IɒPZ'5IHHCpHNObDeEHr\rި;㏚*7v0%M  x_33'jJMRIiX xQ>kTQHEM&*is=s>̈́Dz + \!g  cҝT!aB>˅L\b Ʉb!!$-$Bc!ʱ5Xzk!۬,$ iȳ/d>#&hhы0IEKIȕLȵBBXȼ|,dI YB6`!B/-$-@b u><::8&wFm=x|k % x BNDN/LD:c4$՗t3:ͤIHk#\ r$/ް'DJy@vLd و a"!dY0$!sIHL#:$[HLdFrKȹOO !gBS\HB2!Ce$*&:l!!$-dN. YBa!#Xȸi!<R, zHG27Q`#QGƣm?@~}G c/NHu# FVdHVRR3irR/n(U&%%-$ F6R#mH1 Ol"+مlD6c"15HY(D۶2!7r-rtҼsL\̈́|y]H$$-l,dA! Y a!1,d;Z}GB imo @|yut٘F#LGO}|DQޔ>'rR4n +J:/fR8 |*l$e#DK NYo MBη\B.gBfr!\Hk!XHB +B!dS يB[ y[B*@ JQѭFFo9hQȇrD~sDJi021&%9~NjP~fR(i#$iaH"!Қ&={01ݘ6LdـDV`"%E27ܼ I +&BNR9^Bz9ɄY.dJJjZZzrr#BH,$Bb!ʪP)`!;XȝB'Bl!9=#Q1i.<&1@@}|$DޕO9 @A+fR8 Ik$Ft,"Չ|DDDa";1qLdB d%,2{ FKHDLr%d + rYȧi q +9KR,kB[H<,BVb!CXHs4omBvc!c!X y\^Hs +##cc׮}ţFFoeyt?ot "LHHO#=sRRvҭHi#FGF"Ͻc R40{1;0=vLd,PTUVK%2ʄܰ[5LBȌ4[H">BLșOs]B.\JBB3 +$!7gAȜ\Y! +B걐ͱxk{G' ߼:p /WU @*|Txt(ۘF7zG 鵑F#Dҭ`줪5b#oFޠW('gDDDDb";-hYA`),9$MLgrr."s \eL\_d ɄHBn!!d ,5Hs مBBB|EZȟ I@^4yiţl/ +::<*2 ȉM$iHO#ՑdH()4; I0϶.mL 'HDDDDnDvwucfYTUV@,Hȗ.$M$ r12u 9/ !3Br!o !yBWTUԆ"ͱ8   y yGB@Bv47]hiFf GIGO?y >NS[#Bq#]F#iDҭƤTTt)m-H+$"ՉxTum|߼fe=y4h/ odj 9A"F~鹑H42;I?Iy ryYMDDDDDDtwu[bHSc}]8TS]!" !dm!dBf&!i")L Uȵf!_dBn !I¢@iBֆ h,׿c.,~,,IZӴ{ um 8zhhѭ'X<}id"}&򾉼cioHu$HLz9CfVRER3RF*D^eD^Љ:M4/c"b"`"wc"zn}5Y BـHp ^UۛUҮ-ɖ\p :Xe58LB.3 W\d&3&=9]Y-|7f5V!K +Ac Arr;rF%!| \%LB>|XYȧ!\r !׭܊B? BUZXYUmX5XzXȦfXn!O -$r@rTRGGIl$hdHȣ +>*\B.HH9$CI6JCdRPGi$C@G< $Odz"{<&&&2 +zNGj1WWU:ZBGA n$6N l!ߑ ' L!z +B>UHa!I!_|r-/$NQ#G偐%*Vg!Mf^t> BFcqXd + -dBh!CA! $}$xt٨"liyTQq %5O"YFmd$Jd;1I#IIm$Ad?G~+My~"DLD&`"0v9j6TUijUY\XB![9!ׯc 괐+%!|yRE!ߗ ^HH} a^Ȣ2Ijj;.jÑh,BBB8GXK2 ׇr죌G,Q###>*rHDfĐd(f2 _ĕđT0'r BJDJً&h!R01P]Nf5+V(Ä܉ v ){BrAB> D!_rGHȏ{AC B^HF7Mt{@2'a!`!;`!$$fAB/ +:)Og"ゐO\! * IH|!)!B,-+W5:lk.@h, lmD {_r @@ @ @#6J62qty1r#3H o)$JLNRC)cPR@48@0"r#ĈT3h"DD x, >! 󎃐@Ƚ BꗘPB|[B> $N +bBn. +yd5NCH4!S $, XS}!($ȴJ<2p̶":<1#@M!ʈ̾L#ɑđd)I2)9lNRJHJ#o$c@5 rILn"A.&&2Ն8!]b4u&ǜD!e)|1^G?Yϱ|SQ ېA QI +Z!N CuH,oL`!a!BןʁrU$,ؘ H_><:qre:RHBQl! +KJ+T`6i!kQ1 + y-䅋̅@ 9< yrbBH,)!m$qH#c&\ "628$FI4o$BhkmiN%X$\ +|^H Ņ<*;- + r$[l!BnEB!GXBZE!S d y4,$-g/ZQXqXȩA" F@J>ԑ1$,3cց\@{"s$2 IBI1I(!)5o$M4O89!DB^<{!A&>j l4tZ (,B!$d^~AQqIYyZU.j"X!jjimkꆅNJRHJq#"D^&rHN˗gπ dG{kKs*XG#PPnYB#Er /f$r/y%l GbDCcd'ك!䀼",Z1XIXٹ7@b>sDfHّTRd'eL2oț7fggI rlHIHH$ H^S!-r +BV:ZU^VZ\Twr(^ȵwA+)!Yc +8!+TjNot8]/ YИjjn\qq| 7<Aۿ`v8 IHBL5a(꽀$RfM*cMM&/&/Lf=sՕ{џ3/  Br (!((э6:< +'3!#PΤ+'y&%HJdlDDCD^"9C$q` YY^VZ\Tܹ=+st*իVʄN Xv!2B>'("Xrr)N5Y;!+*AH $IHKH.!PB67{^ G $HG +%6jput#8ŀ {H!#I&8)0AyH;~4#"tb o3> +<:QJGW<:( ًtO:#FB҅Z'%JHR#7E3RHDd ՗ DS'@ȽDҒ‚ܜlKMTȏdBNcS C$T+7}Bܕ_PT\RFEBց(!AH$@ ;|yTਵQz]d3D2Ron)#idV#"\D~cH, A*n^ۨS!.p]H ~B!B!+\B\Gܺ-#y D i42 ow-v(Q"yT{@0.BDR1)) y06H6HHiDrB~z y( YK,+).*E +r>2iVB|d' $"LFȅTUT͖yEťDVHDH&!LBlk)npGSG%|(ۅ DF:=%-%LjsRH##E"ہȖ` FUHHHC3GUYTȍTDBȗ@ 9Or23kNFJ"~$a$'!$ JH]RGd"CH&ꔌ2$#F~G3!7"KI< +YC,-.*J\G\!ZBB"҅#-dbRr%rG!!O!QB +B^IH ـ}hQoGSG5![@!FR$äIv#"ly2HK 牐'AHDJC];BNҥq=$d:2'7 y y B^B67ӄl )$$xO#c7pC@&Rv# i)-&Hʌg)#HfWqD +B y&d&+7+Qg!d9$M'!r-+^=g !$B^k!=^/I3!@|dyutQ=-r!%DB>m!_ Sȹr!3,!KJ+*w˅D y*ك IR#ϣDG9t')AAIELʙt4y_E$v#"8"$"(A$o 9J/|D4 ThBar]K\B!7 /Y< +BB^ YEBFBv @ޱQ1<Bd|эcB~RZB64b!}HȠ!"!|@J|y(QTG#c.2Rjk$Y%ULCʤ$HL=B]4"[[^,$H +b9r,rFȗ^)cO!B> B>JeBd +B<!/~m +f&w9 > +<#|d}q {P"R2$&H+#ӈ` !qDڅ< BEBօ$<|rȐ1!a c!N1 B\ B!׃[@ +!Ȅ$ i + B-Bځ|yQ +:ѥ~@R #HHHjT3)SRkH[Db!o׻:;%B^S y +Y YB!Aզ 4B +'(P, r@ +ٟr9hp\ܐ[_QO^$j7qqW\gaEEA@pc_fE}K4mҴ&(iOӞMz>޹s܁ +oPrLHDʄ\ I.d"LBe\ Bʀ (ѐHDH:+黒ތ6R$R{"{1!]#BvS!.gsSc}]m5%BCl!8b6EGF!CBΑ 9rTs|BN|W*{sKD!C&j; d +̆B@JY][WtDȳB~F!P!?y!Q! 㣊Ǿ(0|@D"BILj 4ɞHQg yB<.,BA #d0rRY!'H!䰁*0BN +9[!\*d0\ *2 Bf@<Y!!d9<"T+TY) +HBz_H9 "B>!?s*< )((/+-!wBȭ2BnV B.Bg 9C&d``8M!J|K ! j"J|Dj9. 0P.LBɅ !3!VB\NWy!o%dOϓ2!( }_tGHDHߐW-% )HDJ|R|O~ IR%)*d[P_ !B; dL X%r!BH!|B2M=!A$/ADITL!, ""dxdT9bs'@4!w@=<!k[6*)"y)3*g!]H@}d?<d?H%^VROI,#E"'HO!/B y B(?PB dLiBn$B!䢅<5,J!I!j!r:/H "B%BnBb,V^d!A]r?<!Ʌ< yB^)L$/] !# ߕq@_"Fd_қd )H=2!kE!OS!Z]ΖƆ:yXr/,2B&&bTur\L-$/4NȉT-!!˅|G2 +9rR>Tr\G!iOH2B@Ƚ Bu M-NWk[;([HL蓎}4 #UHz[I/J!0RBj"_ЉB> y_Gț78!/!!BVCʃeJ ḋ2B:q6l$Bn\ !P!Ȅ|w6r d'X9J"%H XN AȩTr!\!WJ6-V[!S3!d>,%BVK"B!B^ y}_pBW +Jȟ B~8`7}4J*BRnH\B䄼$r675C#BCB!3 d\P"dr 愜7W),*9BNSTBΛ!!*"d2T.dRrJ*ܒ! !d1,Gx!.w[{yB^B~JϽ ' H~Z>F 鋑}C'%;^|!BA!$YHN+!Y"dw׉nWKsSC}] r7!dgfBx=f1"#ˆ뉐!RIR-L*d^@^ +!GB3,x!G( !BNBd B.]F\M\O 2cX#>1i3̄[, !K!dohjnq[;BWx!oݖ _AȇDǂϩBzZH@}Gumx 4h$IJj#HA' + "=B>}I$ I +!ϟ#BY[S}BV@}rg[r dZjfkĘk 2- 9!i +).P@7RHc!{r"mb 2 B@rOUoh>yyB^ y#QHn"UB>y۫B2d>雑YID'RG!_ +BS*$ +y!OQ!ZΖFyC@}{v dLޜ 2<,t#r-rr"EZBN焜$r #^Hd)r'tAHHQrr-r#c!drjZzf֖ܭ .Bjj F!B|ዐBR!B!/]$B9M}۴e`t/D`MgLkHHIeF^[lP!!.Go3"!Cv1yoH B.-olB*x!,d4;y#%)ɄFnDoH!VW|Mh!s 9B~tmAd贝u[ RUI%bYL:J!oW !a!"&$(!}HB &E"!?+*2#+;$)Tbs<@X.KHHMݮ}~ej;n!1!a"& 8ox!I阀ǽqI䮔("LdXȷE 3qH{SHl! r|^Y,~WߍlW47u +y5BT.DBY :$炐 5$$,$0!OLOO;J$g!? + yHȣi!!OcB^H ߾!]!3sr +HdJ1`KRLT!VʪZe م4Mmty>px!gfąD M$&#$3rqiy9,䋰!"9"dBnrgX?#"=CdDUHl!#B,G ; Bޞ}^i XLHȞn]Wg^YUJ2)a3tj1T B^GB~P!< )dd! y8,q&DFBf"J1`K8R>R,Q7 !;:=~y`6dw?0<2:61yyBF&M!Wב/,/2d}L^D<ȽȄF&@2)%w42H‰%j"|U SL!a!AHXXɉё`]upl3{]f$d + Y^&#!YLZL!rAț7@˗p!cą<<2-"B +y ,䟉 X! $rs"BE y2~"1!/_!o! +T*pK + )GB[.Go3̖Ap=^ BS <&2NHl"?"?_\ZJA_c[|yL}dDnoFȄ-B#+$&RH'-$ y.,c v:6o贝u[KsAYW+UUJĢ2atB."倐@HXH$$BbBEB!aBAB~%'HȏBs!Ȱ#!?S$Lc I$YL瘐WY9"2J3YlEbJV#W)T-mvMV׭5͖mty@pxdl|b!?HM.U? p!=qO}@J.HI@dDF S#BE\@B>~ @}^Y,~W߭Դ[[U:ZV%Tʅ>[f1b +!!!"&$(!}XBBBMK}% $x!2Lu-2;2DJ&odD31B .h!AE&߅ZH-3c d]upl3{]m-M ZEMR* 6: aY-fWߣvj:mMZyMuUD\Q^&r9%,&F-& M2HL󘐧@a!B@n +rBDD&)dȈa"BASHs y*y / )Tbs<\$Hd5rEAҦntju^lچN G'&AșYLHh!|MQBn !_BF&2L2{{dD#F2 '2CBrc-$@.` /$ 9? 9= 9 n>d^}SӮnminT+jYT" |f14*\D*ʸB^Ņ$ZH$么ǎDBn.$H&$LɓHȳHDn&W@*$Sit] +e +RV-W*n}5Xaxf*Wloĕ;UBHHB&.ݻ"ɬ }ػf|3s~ֶWW`xxd4ohw:6d4J!I"尘 ZMuUY B;B R(ro2'dMSi"2&V2'ABi_QcA`8\@(KrRFS}cb:::{<^_ 80O B޺BBDȇDD>} +|'KBk2 >>G23#?dLHHELȅ/|@>$ $!!oހ yxdltd(}}nWgGbZM&^WQ+2V$lN(/-).܏B'"kE2D$ dTB& +B.ss33SLȟȄ\N%H됐.?7 yjb< + 9}^bY͍ &AըU +L" <.dk*JAHHH2uBB!QBaB@Ƅ\JOUȥHrgn^^.Ƚ{Q(TBBDB;~`\_(KrR鍦&joiuutvuxz|@(<49>1y"De($FddDHD*"0"0"Ɉ IBY!&rDfaLod6Vȟ$rr!>! #B 7!!\<7u $xdltx(}}nWgGbZMNV*dRIHq,&V Y^ZR\ B BÅ(dܵ,dbBP 'LD&$!9 BnG!sI!(da:!!"Q'!"+ "itZT&W4uZXlZm흮wo  Eg!"/@D^!!" !~9"((< +2eDf+@>xܴ>y !DdLIBC!ߐB%kLȗϞaB>"2)!Hې0!/F !C{\mjnnj7:J)Iŵ"atZ5YBD!1! !"Aȝ{!" +PtBBD'NUTVU  DbLTzlňlkpu=}^? OBDNAD^yoWD佸|JE ȗdD#MDSȌ@nrDfedZ$#2!Jd!|.!%'wdBńKȩ3OABFFGÃ`y].LHf5776 :mZ$Z尙 :Q"! !〤,<B{ܞ d +5I-[܊B$ˇ? +y2HJHH" +"dq H@!D`2[lvGqIiyEUuM"u޾ѱSG? |WDyA<=&RPR =KǗ&A%2\|.RHOB>s$B^%=CJȷ!'F)!{:;ۊlY_WS]YQ[-fAը9@ $$RXiX$(d<Rd d2bBPPR,<鵐$\Dr9)dJ)RH@$rk:r@daJ&pUTVl؅܋>G'D"<B1D FDzR/Yq+4H{o!%<r`O7r?iWcaY&^Qy9PH dVPH1Bb!S PX(B!B+d$UA! +FJ!eQrH,$ 2 ,(,RkzlՈ]m}C#c tDa9 HB$[R +p W-M#B$@|/BFK|BOyOȃ]HȽ{ZHȊR]TX dqBOB&A!㡐J2RH $-d"\@$l"BD*PH@d 2 RH,dzF"27/Hٲu"Po#"HAW "oBC0e d@)ZH? r0pB#d;rOsn$dmuU%iY&^U@mH- !B2 B(r$GH$^ +zRȵDBI D&"SRH!= ̂B`2[lvG1"JFD~#~r@1[F.HN *| !?Eȷ !O  F و(/-)FB=!d>r2#!$RXȔd(d22 :XH.!}r"Dz-XHA!eQr 2LDyG$+Dj:dADA 9;"_H߅\og!_BK9qB^c#C}(!QB,-v:lVhi5B d2!䦍.B + > B*1 +2Ru> fB7M$l"B"xTw!i"]Db!32!" 8tQD6/"-$M$)" M0#.#&" ]B~& MVJȺ*JHl2u +܎ܺ +)$)dj +2 +G +)#!ehan_IPBJȻH[_ + y!ƒ !7鍐Xd(d26V2UHZH!\ )D$-$B2T"c "inD 2 K&ՍZPH6PHL4G@䏞TȰqFJx!"䷮B~㍐ !$R0,RVQBnc%X!RIPxBH2B*G!Wrg!#H!DD* ")oJHRH@$_P@d5my1W HHL飐r^BJ$,!g7W)!/rCȃYtحѠjԄ ! ![@B@!qqr$HBY0R"!Ha!b +ILFDH,$ 2,,Ri8,-+ryɍHw"]D>DΊ#[+$2|\--I"R!ydB>BCBf(!/Bw= [#Ã>۬fE\$dCM LB&@!cI!"`OB.B +B2TD"XHW"i![DnDDb;KJ%!8 ("[H71w ! Dr%Z);B@=B>BBAB޼A  y!9$>!F d>rCȭ P$(d<RQ0BKȟq!x2ҝHH,$ 2Ro#`4Y68";9:r"=DYDybdy6$.$$r977 AG"@g!'KݠEIBB'3@@ȻH[ !τ0<4! 9nBnXH!!HHQB R)ZBI D&PD)($"r߈9?84<:6>yx3s "/"I +I DNC"ݣeԣȀ 0/H~!#37!g !SB @8.TP*Ʀ C_+MՕt'M4mf{yݝo} `} +)*|߻ y[U@ ,r +r"$ +$"$ +$rr"drmVɨϔR|Y ǎQ<%$lB _Hz=Bs}D&K%)Hȧ"#'Ζ)St(`4[v$DG5/G$NB$$r*B\ [W\#(dZ\ ABRB.!瀐($\B@!Q /B !}=@`!O?T< $)$!d!#B~];rRԈ!HB +#d?Aa"ȗCi" }!W0"?B$;7nDNDB"H"#h,_EdJ$F$+)Bn.L) +]d!q WX4\B!gn҄d B!Bt!>rmɠiԪY*ilL?9!B~lBAddƅz S2Ot"D0($<)"}&"$-2yR Fjs8]N?D"/ D^1F$JdT"oDNDA"iD + NdB2O"=1BbB@!@)D1BHHT (@DHd/2 .fVRve4!*+|;#BB> ,-Mx>DHToх\B徐|D\T!,d AQ@"_n"T!E"+kj%ֶvCb;\n 2 +w""1"~|DDDNDΓDЉ-Ȼ(YCd" =A_Crwz}`( Dɧ"ىBDNLB"gP" H4C*$Ht!"S\嫰2sB@ B@c1H <r9  $ B!Ptvl2uZJZ[B3#I&! I"d|F 3.d)ȴ +ȽT"B +F$"8K?D:Sv6&isK[LѡTkzlN]=}H@K׮cDD& I%N$rJ2#|D҉d"rQȇEvs,$2#B>drM{wI2 \B!p 1!Q BRB@^94x +N iVVv(dm-ҦƆښ*BS B%LMH(ѣSrw*B x2Ud"w D "?8u AdM]}CD&+*V7̀HȮ޾~@0B䕫H>"q"Q"!sEHJ$DENdFj!sݕҶb 俙 +x<@!瀐(H.!q (@H~ dW8Bz.f1 zFPۙ!|B )HD +"A"@ۀw "+"k%ֶvCb;nO!}H@KHHHt"oBDD.@"W"h,_Ed#'nkIdjDn2w~!Q56!BSHj<F"$@YIț@B!B@!!Ctwv:Vhk5j%!dTP_[S]I!]B7mK7Jȝ@ +r+)<^"wr)PTH6"؈,D$N$ ?È5ȷD&ol4"JZMft=^? +w"HHH."I"P"P" D;$ى`"d%2=Dn2V!r}Br'd2K@ȹ9)HDHH6!I 8# ]Pz.f1zVR*䲶Y]UYQ~ } ;o$J/eNHF!wSF!7ȯ1Uٯ;30{lML&{r P{zpIy-H4IMf9{v"#yy3N_JF7t{@0T:ӋBD;$" LDt"ry9 "gg\>_'YCD>"rYKĄ\G@޽3?_s, 4&rE 4HH9 + z{2T2FBq96d4R!JB$dgG{+4+! y݄IȏX@Lȟ+%"Ye)"#"ٌl!"R\Rkuzl.‘hˏȷBVFH|)S@rr +HH%@?;:2<8דN%h$ aY&^QHHHȧ y yI]$!/ |5@rnA"9#|!C/;"DtحѠjJ$D,ymgGIBn+&d-$䯗?!UY&[ȅ#򓊈^D~ȽC&Dd"'rJ&fw? +GD2ݝcHH:"t"r"sl./ϓ\'%"B>/ |"{@(Y @\6K9MIH$$ $@^#@vx4>,fAӨUJL*FB:ۑHHH}$!wP  nUB +Ed"r#HFȪ͂YMd)"܍<<e%$"e!] WDB@~5<ntdxh7ӝN%H8nnZLFNQ)2D,𻐐HHcHȃH=$!*&$+ޘ\,"9\ "7>6"ԈBGND>DaD䉓[Z;x|H,*F7t{@0T:70"ςHD$!D$M$;"D@N97BdeD|"U]CB63Y@V&$ d!e琐336:$$$K"HH +ȋȳr@d<v:Vhk5jB.E> ق<tحѠj*\&|^WG{[k @;z $:!܄rj'e"u݈Z@dELT:dH4H3 rDTDD"HU rDes|D$[Hȇ2RD.ȗVd-oBr$@>c-$ ) , Y_8 ώX4^,fAӪUJL* <$d >;wP@ YrBnL7BȺF_D-TD؉ܷyyTSs˙N_ ?yq|2vr0c0$uW{+m_z5`; w66HPCUh0/9gu )P4Zh2[mv]PMDȮnyD"ID2Dro.""G(cq9#rK!! g)< (#, $@ OƆH8 *iY&^ը +T  s3IBL܍ܹ҄C|g\jD̈Ƌy}\D&EG9ȼ|Dd "R +Zfp@? z";Ad)9@DD2D҈#ҏQJe4%FDn [I|$'d,OS9r@QH1@"!Y / ^ [d}m& *aZLF^Q+rD, +*d= 2IBd2)lB% [Kr"DD "ID&<,*.B)ɕ*F7tWU{}@(\S[W"{@d_?!r!Fd2"D^DAݻSS33|%2*2mMH@ $#<|93=5yyI2H$$0 ;d3 Nj1 zFReR1 Y\TX AȔ 1 RȤ TB.="HDe#29LD!BD!r'r+"7hk  _,ȇ,IqrI(HHȋT/-@S]r:Vh4jB.E@? 3 p@&Kȯӄ3'Mwr݅\ADڈE"rId#!Ddz"qDdA!"\ K2RFi;\ Ad-lBd?!rB9J$D#&955= |"!'u"q%Fl T qX g oGJ$ H$$9dy d$ +|^tmVhi5*B.EBA,.'dV&2r&n$Ν;> IlBn[DBOD?۱ȽlD$FdaDdf"DHDdR$ +fp@? DjZZAd!4!r,!D$G伐)D刼?/_JVDnV +hB. =Ȼ,7 (@rBݷȳC @Y ^O5tجѠj*\ +e@? 3 Hdr/Iy +͘ˌ/#"1p "w&I#HL@Dȼ|Y"JD*UjNo0-6> "@d3ȋQ""% +%:!K}B伐,OJ0C$"9J"A9B"-F/+$rK7'@rBQ  s< 'xQHq@"!Y )}ȓ @6 ۬ J\&dحϦ4U[bժED&ΌqTPIM&t7IM$(TyC30iVnu?sO4 WI@wHHu yB)!'䪥D +~D`<"5,"9LHG"EDHD$DD#"AD&H]Zz`"kq) D."bDRD*9̉pDv"K"W6W ] ny@d@ }q@6zYUQ^VZl-SnH]JrRb|\@F" ;w0 )!2$R@n& rRAEK_9F$#WDd HID""A$"D "c I) "͖Y"+k765imDd#r)y#yO9::6>>19)‰Wr".TH\lOf bBɅ ɉQ@# oq ځdBʁā {{dW'lM@VkQ!4dg2@&= ɁTIm,!~,!EB\fBޭ\ !?"WDM,"A""ՈH"18 "A1+;dʪ"[" HHH Il9p@Zdٔ 2 @&XA@G@A@RB*)rkKHcBnTH5K8!r6AiH_D$THI " !KHLJNեgliERY"Ad3l'"}ȡHND(ID!"p"OlD#%lD.)k3#M + c17_%dpHH??͛ H(!-iHNCDzoa "XDr"!3,"HD$DD("Ad:4Hْ"Ad $"{N%u"9#6"*|?#"?" J@L@>Sr9 +K d Zd#@@RSda ]; HJH% EBn @BK -r=OH ϒ (F,"Ad #2t R1"HD$DDHDdT6D&4i0fy +"Ad l- X|4">"m )ݬ| ,!@"!% ϝe@" OG fY d),ܜl SdB<& {v3 *@B g C@zEBr \BD8"QDn޴IHȈ DD$$"DdL "M DUZ" D]Dd/'r"҉+?r"o0"Ȉ|BD>Dڅ"?E]!r6G  9%) ɀ|.yyCyH$rǀm @JY )';˨Hץ$8I@' w@RB~BYB"!ҋr%:YB!!W9'NB~RșF$' G$'Ezȍ""9 E$ !]$" PƂ$" 2DZKJAd "[N"90ȉFOț6"DkDJB;r;BHIH@R6 or )!2rp! ; V kd,2@dLdr^rv H,! HoғiO?-L!"=("=EDlDd'oW%ID""ȃDd LH:9 2Y"BDv݌~NKDs"GȻ +D>s&%'gD"g܀| 3w : nl @H+9R u2@jn}6Ea1ΪV@1g`DfŜE09gXǜ-}c뺟>NkLW2+S2@"!큔LMaB& !np(A CI?~B~"%"# "Idj"B"D""I  "ǒ9Dȹ t r,$D"k',DBD^RD w@}Ed-"D~d|ow~@@HCH 'O( k@V2@.r.,SdG s dHr@ H $d2 i/!;LB6+"k!ˆaDd4#R"^@I"$ "G|9q, r\Xh&r=,'$D"7HMe" D C?+lll{!@^@z% +@Vr@KB9@"9 @9 +HHOBH&drR2@RHi$d2l0";_͈4t:]n"{ F$"D""Id6@B9D "Wu rܺ DE"+"j"%"D yD! |?& @>'OyS<$Ryy`?E Mr\ r6 D GezIH) L np(4++DdS_"R#D$2U !Ɉ$H"GAd9DAbDAC'D>#AU/"| MM>Dm18Ld|, Ȼ&W >@"! ( ȝr+ r1 gr +0@!Y! +m $dZ*21A%H(&dJH:!M ;Oo)dWΈ$>D&ȴtH +E$I" 2D$r "E r9\"7h" {CmSDj!D -#i EH ?٤B +Ɔ: 5'AB1L\H-d Cy @2<(@ fY We@%r*, c d9B8&!$2% 疄t8d@6+!DdȞ$RE"2D("HD9l8"ADYH"AD.@zY"+IdnYS@4Km)!iDj"+"{ 2YC_D +H!rdcǁ9 D@"\Dn!;}B#D yD! |?&U )-  țHIH+HH >rJ 7ȵrr r% +A m@ HHtٓ@RH d7%d6͌H?";YbiF$$$26r@db"#R[0"B$"D$r +"K@\Y\"7$rW<<sW[ED@mjy.9cyW  r \ ȹ@Nr,!#G( $@@ 2@F* - ٕB~ȶ!Gd;o!_B! Q$ҡI$2M"$2Dȉ$D9 r!\"W2MdGSDj! "(dD~B ?٤B + ,@" yZyP#@V @d) d4@Qa +~}큔LOcB&%&* ]&Q2H +HCH dLH!4";Z"HFArD&tH +G$#RDD +Y$r @" A 9[DId"w '퉼`%6"iȠDj!<"[[1(Z @ZRX@-N@ +M +z +@. 53d! ,r$2*!dsKB: +Ȟn&A i$=$2&L )$Wo)D""ȌL9D'S@t9D.K@JDmBdY<~B!ȋvD>'ezK 6hRyF&\@. ٭Ϧ4Uj-@gJ2t7I c0 0a9`N1ǙvsΒtw#:U[ez9>iw\9 '1r$9d i$$@RB&'k@1QBȎ dHKB%d+Ed(4DJ"NW""ݺ$"DBYLD ,'"+U p5yM)"W >ȆȗvDΞވ$/ ?y=,@ 6yRKH7gN3*@Vd9@@A - )DB).ӑ cHR&dkBB}$l2"DF01 2^DDt&GODRD2Y 27D""r"r\"@vDb"ORDԈIyJdMMm]]}W"_lkS@6X䄔@RB@b  rKd)N@ s%R$dF:22)I c :o%!HPH G$q pd"3̐DmK$E$r r r<9i29 D&"kȍ r"2'H"/,."x DA!'n!Dn@4B|e|fu HHȓ'{6\C@P@' gid9@ + K HH2Ct8df ;I ;2af C4 5!"2Bk "@d,LD&J"̮Hi&):L9 +DGDNSA,"rD.'"W@VD`"K")"툼(a"q|b"}wHkm l: 7$mQy\y * W r9K9 @G @ +$'$@v& @F1FB @ψ RFNd$1t2) 2MMgDJ")"#A9DN3ȹeD*E DD=&TBz'c5ȏ~7zB* + kȇ7ށ<'<@;frr) gS9F9B9ho $%d*%dR2@0"! d&d{%W +!Mq pd"3`"{J$E$- D("ˈrE:"DUjIHR# +yK'F/V" @@>@+BHȳg#;ȕ,# @<;"! t Hq2RlzB~.l&#H&2D&"u"3%#DD r2"KDYADUDn{SDiy|dCK;"_[|gO{oD~ +yw _3|  UH-!5 O3Շdr;Y  +d)N@d.R@kHH ;V ,@K 4 GB6Aȯ|G"2Ld 21t2)DdAdWE$ A$"D@$9 D&"+"Wk@&"r#S@h@@^W@^Ry< mrr9X9 'qc(rmB + $I +x@BHR$dLH򏗐DHKD~mHH 2ӥ.'LA9DN3e r+Ky@yLIiGEI D@-Hg-cH$r7 + 72r9@$ ȉ1rr ?@v@Tt8dV@ !C 8m\G"2Ld`"25LDvLd^^D"Ad!,3@\"r!D""׃-GyI'=mll ?"?#ȷ-y ?@c ]r \O@R@.$ 9A GH $V Ojkȇ7ށ<'<@;fJr),# @ +  +)]$.ӑ cH i d ցl62#HD+"$i "I"G r2"K PDV JY-"7X IHCȝ.kȅ +4r"M@d/ iil@y6Y +I@-iEMdL 2C̶, "-IDvd"{~@"r@\ "72;.^\JDB~%#2ȳL%L@"TY{@y iI _ 7:@. Y +xr@v;_H$$@6 YW̰L3 )@F'd'QDjDB Jdh" Ȇ a ")" n 9XD$"%Jz&rw?zFD޴" 2HW*"$ + Cy/ +ky}@  r\@$ qH9@e 1 _~$'$@RB +a:$H7!m _Sz*[DD "9",!o,M }G$E!m;&+D#ȱ r29C\ "W:Dne"(ǎ!yBDZa"c~fqTa |} oFy?ȽV@ yr9Y > dWg@rBȦ6 +d=2K4 dā|Ku"u|KdL"2SP8WL$!T"]@d/&r DN""ȹD"D[J@"O"GY\\Rj| DȲ2/L*䋄,s!H /A@;j#@n +r9 ȁ7مl' 9!f dY_ BQ@4/IH%2!EdDd"%2:"V '9DcȉJ%r9\ "73 M":yKiGdL"U`"_ʶX|zNH.Y,@^' @nr3\ r:H@ً@i闐ds%dAda fRL5 (w&R#2B֐"k+uAdNN(ͳlD 6Bd'ك"D9 "@i$@F\@NS Gȡ?@v [} dc <2@U k k 5 nBȷ(!LHK "MD +u,$"&B1";tݙ~ rDNU"(AF&ryKddD*ȋ *yÇG~D>̟AD"2% SqH o(vBZ@4@ l9 G!@v4@~U, +dCP ;@Q L + +܈L"zJd!D6"[~@$E!=ٍ "ȑ r<9D""ȥDn";DrDD~D%No( @^u<@rB:@RB:@/@nj@' g)HȾ;A@ [ X@+,2 @V|2iD:D֌ 2SP8W?|T"1]> r")3y r \"7mB>%M?"2,"o+@COl"Eh"]!L~ EH' { +m K Yr @nr&9@S 3}d7};|DB2MdY_ B2[ 2ULb Y/DjDB("3, "J?E$ECd[& Dt "'3 r%\" +{Dd<yT;,@BK"@$ 9@3@"!@~{\+@nJ gr@v :@~HNHld,2!S#2y@BK?BVҟHWH!. ùyٺ ٙ9"'A\"r\"ׁ-BCcADO_"ʢ5/ہ?0qSa m OyL#@n +r9 ȁ d/El闐dsd * n|w#!6i 2]Kdh" Ȇ.!"Dd"aJD%rD] GbyR<y],..)-s"Rw$U3,S UH{Xy^< #kEr9@N$ ar@v@n dH uH'!4/L6)Jdj YBd=%2"a,")"ȎLd&? +"G@4"r6\DqioLڗH^D@"r""gȹE rEDTD:IEE`"s%,"BF@(a@ H)$\c i K@` 2S89H@@vH$d}Y$%$—DVD`"*"% AdsIdo"ED*"{ r,Da"ȵȝDEI;yIyDD>D>f"h"͈%&]j}w!WfB2O, ]K>@:<@@Z\@@X9@@T@m$dcd db !@e kYȿڀ Y," 2ƃjDd0l!l;""{a r " "gȅe r "w%ODD^A3'/D~} ]B @ޔ@^TBڀJs 7@9,@ ف|@ޒ@^@ iyr@nl@! Ȏ܀DB-ddCd2 X@ꄌ@@ƄL&D% +v" &2`')LD +!mDDvD%"؉"3ARA*Dn#"J"j")"M"ϞSD^u%2;;'7JG9, 2HG%{ mr` '/fپ]0d*ljh k%VDzYFҍ*AD֒D3LD6D4GEdWId"r09 +DN`"g1K r+GyDD:d7H$R'2 d-? @VT@V@څJp,CDVvY 2oٌl]$ADH9DNDAJ;C""]/| D,6H|$DByX@nJr9@# AdokT@" @g 15m@ +!+CH \YMHO!݉*41DVD`"*"% Ads"/""%ȁD9DNa"2+@:D""2=hyǝD:oC/D'2| +@Dȋ^@9DfDY%t #dy&ȇ{yU iyv@K d2@NP d_2} )! * S@ +RȯKg)dJdUȚLd=&$lFDGEdWId"r09 +DN@|A +Dn@IM$"2sL5"Ad&IdI2Jd1 2R$?v)4 UHwb8~<9c`s0giw1g&L"Lb"Hp$c("%}D("'3ȕ 2Dn;%HDy[yO#1, 1"=E M!@BY y@ /+ 8r@ȕ%rr& (9Dٗd &)dYj@RBt]DgR#ȚH#"]LDiNDv*CDf#Ad&3sAb&rՈc"OyVy/oL%!.7+ +ȳ@:@; \\@#` d d.@v$ dKdF&u :.@V1Lx@E Ad2T +DD~NHIdo"r9 rD.+kA&"r_y+W,((,RD>DȒcD@Wd! ȧ +Ȣ‚ |yUy ~rrr.@f@fH {+ Nv Zlh@T@BVBd\@ʥ#~ E<ȯ]ED$"i r r!\n%r;OyJ?-DWD^7wGzDzBtDg_ $  #;ț:=<~L 7ȵr99  d/]DBȶ2%% "K ; Jd(YÉDq RD$ٓ9DNd"g3@Dn#"J"Չ4" B"؉|#2 +#y_ Q^r eȅrr @ dOw@ d 5 dTt+‰HDVs$Fd=&Fd3Ad LJHDdI09DNS@&r5"{$5")"D^D^w|DKo|FNJKd$@~t3om@@> @>y.@ZRa r+ W3 ȩr $=L 6HJH=ZBL1Y/$\*\"׃-DnI!HHӿ)"/9YXX0F' +ȇE&L /1-@4<$M@nȥrrb9@% K k@$ ̈́ԁlلYL2 @U Dd+-D֔D!"D6*li1݈Ⱦ! rAd9S9D.a"s@f"ry yFy| "mDЉBi +#2hQ + b|yDB)<(er\@d Ǜ@! I Y$$ Ȁ d]d"Y +drYNdpDV"2HDI";y)"#lD`"ȕV"wyLHG"*"DDދH="H #Yg O1$;f Wyrr2d_ dz@v$ dKd*!dMUddXB~"dll"J"r'RD$$2 "3Ad r:D@d.ADg"OyNyD;ԑȒH|#o( ߇M0%y ȓ'y 2@+ȹ d6# /^@vٔL ?5#2>|"kZ6"DH" ""$ rDAZ Dn'")" |0w$EEiD:D;$JGdy@BO䣇EE;W%=<@# Mr-@@N89D@'7 -l%l.L  l@ +!k@p@Gd3 DV Dq RD$S9"ǂȉ r\"7mD^EQ RH k "H="C+Dv#2Fd44i +d1|my<䯧.r3+K<r2d_ dz@v$ dKd*!c@jLd|Dr#29'"*"[ȶDd'/"EDJ"DH "A A\\"s5"ȓ.D='BD旉7e&ۑ?1!72<I2I@u brr$v9 +daATI D%!齋.zoQDU$l־Mф- d$Y{syOyD zOodn^@ـ k|,Wt2"#YՙȚ:q"۵w#RD"?9LAtDՂ rFDVDfdyQKdnn^"$TDA ,.D`| H|2Ky a2@)E2 +d9@v +d; d D 1iRYB@F:R[ B'_"YDq )lHH&HD9D.D.V"V"B%Iu-+a" "$t']hD~jB]h@ROHP2[ +C 2\  ȉd?ΝDBȖ~@!!$Ȋ^DF9YÉxAd#VȎ)" /9EDNӘL*Dnȃȓt" Gv" x#9:%L YHS'% r+\ W  49@@! @ HJHȦ +x : d jQ.@Vr|4TBVBVQ!o-D֫W_#H)" w"r09"ق r)DnȿD^D|D o|F/`|[g ؀|!|f)|dyCy& r 1Kr* GI }4 LH d+Fd= ս"Y1 !\DفHLdm+ -D։#$$rF89Db"ȕȵ r3IDD7ԉ"1&i#"*yS#D>\'R +K)d%4)4|n |@>ЀI@^U@"!}r@n@+yrX9B9m߅ +d_ +dȪ 7"2 D${IIp9J\&r9\c%r/yHyE5;Gd 6ȏ`/cyMyȟȣGȽV r.9rrGwO ځl@B,28"#"AdLLl$2ADDs'RD$$rI$9C "1AFDLW"/("@-+ǒH)AdQQD!"b@( o@^pt&yLF\@r[Ww I [& d\lLdMg Zt2" ]Ԋ}Gdy"+%h?DDLHEd?IP"2 DNәȅ 2E +"7m ryHAE_"J"sBN.4"?zAc$ I@>yȻYȋ@f0=r S)r2@Nd9TُȖ~J.@DVԉ,DF9Ylj!""ȾD"r4"9 rDnȃS"$Ad"2N? "m"C',zBڀQ@fKRHS +ȃn@g 1s49@& %} ;$2^YCd@rғȯ,DrDFAH"[Edu FH!H}$CQ r< +"g3KA*&rII䉓zDD^&g6"8֍_"[g ߸#o /@ yRyr  +@.@.@" H @d+Fd= ս"4 d@ +"ٌlm&%ȑV"gLJ r/ }|S< =my@ʄd EB@8. w@+ T9I@@ր )4Rٚlf2H@~4 +a ]nDF. Ads"?"{D""G@&r\"\"ׂ r''V"o"2 D$RD$r 9 "'șLb&r "wȽȣLH"ϝyGyߗ'Dr#Y@B:'w@sȣ;&F@.f gr,9(# k@6` Z@ +!2" GdR#AdLLl$2ADDs'RD"r9"' r r\.\ "7GnD^D^#"o%&[ϞH?!y_y<i 72"\9@Ncadn^@% [&&q115j22 ˇtAY/,DFFd{"ED2ȡDd"d&2"iDaEdF;%YDǒHRYTT! &@KY@cd~^n/Y + @ff( i6r5La @&C d.n@"!-@&8$@,EdEʒ*Ld#5:Ȧ "CG"EDD#"V"ȅe 2JD!")"ӭDK 2[yWc'RHO"YHw"߅F6s!HH=!B2GyWy t!r@.sDr4H@3 +Ȗ2^YCdu +2$dDݺ2]8[VGf +X1 2!:kk:_ֿ5MDʈ !`Ad#!Dd8'2BU٧," "ȑD"r:#D&DEd +ʉLЉTYj"YJ2 +3' or ( :T2@2 +@I # ([DB]@6rdRˆJLdG""B*"YDD$"D4"2"cAd<#r "@d2yI)$2y DcD>!-DYDdA ,k; _y@@fJ Ɓ) rsrl*#"r"3#44t|y +; UyLr7 7J WH Yr +9΁8V [I [f6@2!AH +zDd D6UD8mAdgNdOg"YD +"c r&"0"5 r+"q"J"8yI'N|[n"D@-wȋ@@% V @3dr 9L.@@vm9aPdS@Y1+AnDV׉Gd]EdMJGd/"YDJ"I r "K"WK"ȝGN;yyCD>DJ!>"K8$ y ,@J! ܜl o /9y 0 7f ' ȡȟ~tWlR tA&!iYǝƒ@dAdoldBD""'\"1"WD^" H&+ț H="]B:lDV+3]B'1e7 O + {@@.s r"9{[ { -$5 ( J p ހtu$$!99F&"CpNd"$O_?"YDDF# Dt9G'L"2iDd|f%2 %S79WJHȌtd* wD\ $st ȑdw-@"! Ȯ +g  9FBY5d9V"y%RD$ g&#M !," "GDx"r  2DnI 2<ĉL3DyVɉ"1"Ҏ" ,r"D ,kd ȗ6@>d@8HsBj@q 2 @n@XB  h2R߷"!5 ;j@|!!~@6d@~"|H"0"9iDF Nȩ r6\ \)"=DA" I$EsWDfeez*8`1L@႘P /έ&L00a&0yyV1\71TUk'^\@ g}DV(wM!%1@nd@ W + s$r 9|>!9 {3 {h"s Hbu@ A@d 2\"2@"2L"$ 2LeD, 2E""ϛyYD%:"+*{"IH=$ Ym +@>,F 9z /@% sl2K!L  2di d LdM%"rDFh;"YDDd<9MKd 2dDn"w!9Hd 9s" 8E"K)GJT4 K% +Es -d:2 L@&@!@F G ]!d9Z % |@zEd;"[ԄΦD9ȒHDD@F r#r AK~$ %W87;Z"9OH!$'c"y"^#Yw=/L|j+V@=#<@ w[ lr9́k dO2L d&> YDɅlIB"IDvDv5!ٟ)," HT r9_\D"!9NyU&.#>YD>V#R%?<QYK 9H! +rwYy_&y>r'\π\@.g@. ȩr,L@d;Vd˚i)dCɭfD6LH#͉Έe o DTIDG"3y@bF2 r r3܋DDɅTFDޒ|XK" "mB)'ȇȻ-$ )y$@n@@. 3)xr? هًȎ@]f@6Yƶ7lCDG"; qu9@!jd9DN"gsEU@:F& r; =D6"Az"{0"{Hd'"cc$r:9G +DdDfDG"!"uD^D"@djH#|$Y@ + /ȣd.@n 3+TBr9L@ 4@ )B # u dSޘD"2Xn$2ږHDdD&I@d 2M Df@d/diBNdBd # TlDzHUH-$Udd)e3 ϟ@K@fYd2M @&d<G@ 2d2 2 B@}MlQ3""]0"'#2GD&E$'2DN"g F + 2 +D"yHD^z"5*+u ΁@q ,<+C s]Vd:@. gȉd,rȯ6@"  ȞdX˥H?u=gȖ:"[+DlA$HAh$r9D""";%"p"Oyy,+sW<"BHWN|hp' 9R@>@@@^ir?€@@. +@NE ' lv +lad]͈lfF*$*ٝωk"YD*DB"#SD."3"W;}Ha") LH ׈[@]NC#rD)&}͈l@aȇ Ȼ2W5@W )arjrrr9@RGS @ p K@v@v-B6A,JD!6Dd{NdG !Hd7"BA7d9b$9D" " """2jDD^'55-z[5H%!e O !{frrr9Sr9R @BB" {YّٞlÁTdVD6wJ$HAdNdȾH@HR!EJp"r,9 D"1"kM@v ry="[s |I@> |y. LH Ar$\@.e@. 3Xrw )W[Xh+$Dd?ټ6@4D6K"{0"{[FD0"rDt rPRDF" G"1"5D^dM#$’ϔH'@~k +nS o /jd y<@ kȕȅr:9@&OH@ Z @~Y[ H-@d["`AdDd$ȡ1DdD&I@d2ʈL"3Y@d6D+D7#2',"KtDVUDz"U! $ Ym +@>,F 9z /@% sl2K!L  2di d LH> f^"1 +.WhJd#E$KD")t 2܅D yȳ̉,Di,uBH/ +ik'@2 K 8@;ˁC s@f 42EO@C G ]!d9@}MlQ";SG K"YDr"GU"g "ݺj*K8~60t\C'qwݝ=3Wh@ǰ; +zYϻֻga$$:XoAbA +Jd +y'C#HH=!m@>R@ft dd  Dr99@Nr/?;dsddCg k8@ sLžk$U%ՈDFEE$A)"$$r9DNSAl&r\#"=DI䉓zDD^Df"X| +"_X|)|c#39EK;Of'&5rr!mr49D@RBJ [Y +:YMY/dXH?eIiYǙDdHkDjDD&"GY""LV/րC@` /ڀo$n@nK|,9@' G$,@ @% [ȦF d0"FdE+U@nDc"؉lIHI@"r9DN3@&r="wȽȣL9G"/]VD4'|wnDBc" HSH+RHW6 '@޳y ȣȽr 3Kșr2G@ J { d=YH!dYQ|ȢWYʋrY 2::&VX DDw'RD"r9 "'LbRDn;Ad +y"Y7"Df!u K w~| o* /y<@nf Wyr   +_{^ +@6@6@DG@ + r^@ +YXA@de 5.Dd"Èx"ȹL +&r"CLi"J"oDޗDfeegHR'"?#['2ȹ|>&RH2[ ++@9ȷzB2yd2SX<a k@! o( @v<&G@[U |9r)( ȶdKW k;)Y1 dq[Y7 "cbM"VDd;/"EDJ"Éȱ3@<&r%D$"Gȳ眉IDf("!] #4t  + @T@^vy +zR@c 'c d_=lgLـWOY*@Yw974 2Oq N@@.@3 D29dHJH2Z d +!`H-!ȀODyKPH("2F%BDԈD#"$,LDfL"Ad'dF$E U"o YdAdoMD~Hwyc[v@~ +3/l,@@R2K@f,)Li T $ q#C@FI@FF\f [1 D֭J"0"EDpNX"r29D)ȥ r r3"JDPy=%eODj'h2"dM$%$KHȓr/ 73 3*d + gXp HCB΀2T_nڰ*  ; "ۃȎNȾn:9DDNs@BAJ Dn{CDqA$"L[D=@sDkH.de-ovBm|J@K@# o / !r.\'\ + @N9c8ٗe d{ & OD6v* 7ωHDD"r "%ȵm r7y<&v@v@l\ل٨r@ +YӆW9"yDd3k"[[ٙDMDTADs"ș r\Ĉ\"W3"׃- r'GDD:#RR#'.|LDeK?iiO ; H9!O] LHgN+@& ȝrrr g)xȟX9PdOd7dgk [[dC+ Mwl̉ !"[ w""%"@dJ$R&EFd9"@d2LD "3Ad&"s9y2rDDs" l|a&Hs K U2 s5 d:rL2 @&8 @RBr @FF\aa [!` ȦUd@ȪODyK$EFd1%"r"@ 9D4F*!"9ȓ/ "ojD2"82VD5#"Lol:  =E BY@* I@Ԁ;Ɂ*2C S@&8@Q@@* A k$lo$ #;EDuGDNd9]%r!\*\"73"kDDDRD,?WUq|aluF 3T b9`Ƅ &L0a&`N=˙մ f{1#jG;ؽzު:=%wg]w_.ODU*HRrg +^K o )!U YBj@@v @e@K$4r99T =dWdnȚ +"Bdc#A !3юD$"c9q:$I 2"S5"3@d&'2[yޒ9ț"b%*\*'R +2_2@^dd S%rJ@#9:m2B YɄ *@֕:ND6`H',Ɉ=91DDD'"AdLDDni 2D'"f "Ϟ#J]ȟYUB $4 o + s<NE@f2M W0 d"Lx2V91Ȟ2Ɂ x4 ]ٰT IsȇȦ- D-^~6DDD#"ș r\̈\"H"] ryDyƁȫ[Dx /8\H׾D"g"("m +H]H+ Ȼ-g%G .@@.4 o_ـlkdS' EzVD~ę6 +T"?ĂHaȱDd9D$AFS' iLH8A=FCFISR'mm @R +I@O + ȇ@^uir r5r9\$I@N& 5 +H$$ @v@vR l d&; mn5HM$ ɉlƉl)lm 2ȉ[|d99d$r!\ƈ\" " "ODk+ [H5!M@>@9  O {N@@.@3IrI I@րH@l-lɁl& z kEd}DDDNDш$!%,"u"p"G r$r$r "w= +ODRDJ"$:'$f"_9)D  ϝ&C@n@K 9]r49tgׁ ɁC@v7f/U +d@ȪK"V&]"R!r0'r9"g% r$r"wc"/^DЉiD"K"- +6_ȗ@>b@wHH:9 r;Ā\ WJ rȁŁ铐f 2 ;lW@YV D66"[DH"#"{}K!r NH"2 +"gd +" "y˂\"2O!2_̚k"$" {o,*z  \ %V6 Z 9_r*ɁT} @ !U Ⱥ k*Ȇ ֈxu"@dO"2ډHX"r<"@d"LDH"@d:IDfI"ϝ&2GyS##/D%U@V KL@g>@>0y + %L + S2I9qX@F@F #HOhH25 @ޕ:ND6ȶDFώHD8"r r#r h$r?yTy֖+*w!RH"?T9e#\HW@>@% o + sl@UN-ȇȂo ' Yv">"+|!,=gG.U@.g@.L9ǁ.+k $m [h@6@6@6H[![?#^Dʈ4ڞ.|j"EF0"rB 9W DfD[@N<,D>5IkV!T.ԅT| k R)Y| U2yȝr r\-\ r299L/@RB@vc@va@v5#+ ]$'%ʇPOXXxGF"*,"u"9@t9D.DDn;@"'IH5"5"5"[DHVRMHOm5 H-! @@& \ W1 ȅF 'c8Cu ?$%$/<>@" [r @Ҁ Y}+IHdg}" 9ʼn" r\ʈ\ "I"DANqHH.J"ow@}F##Dr"$j|nu LRB*@8N@" r3\'\*  ! +@! [^R$ sId +$]Ad"oiDLDDNS5"%ȵ rcH"/9iDtGOCd W _@z9u oH /d y qH䠁@F@v@2! +d:ND6`H',Ɉ=91DDD'"AdLDDni 2DDfI"#ؗb%D6"w\4 o + s<NE@f2M"L2@ X@p {(d$2<р v dRlCdS"ۖBd/Nd?"YD +"s"S@L9D.fD.k$[A.v/+bE#Y4Q &6`ņ ^`Ê쀺{D)Qח)F/|眙3<<@P|o.Df "slDBBVY@q }d +d-ylr r5r\`r"9&dc @' k;Y2߈ "Ndg"C$ +тX=-d)D&I 2DTI*ƈL +Y'"/ˉ,..)D>u$rRKH/,yd w-2M@2 gidH@Հ +H$$ @ +  C%!@6@jBVȪ?Un"IHNd#Nd 2@dʼnшD~w,"5"p" F"%F"G8NDJ!u"/q"[G +RHAJ#ҕV$| + Ȼ [ +T !#> z*D  x޽@RBq1(2d2H'~ ?啋Zn)l!0ٞ)$":9DT9KDdDA<̉<iH^FNkȷ>Y.#=ȷf _J ,f T'$% !urr1 g)r<r$r)!ٖȿJ Ȇ 3 "ȖV +"r@N"r,9Ds%AZFF D&"ǎK"f"D^"Fs/["=i}n|au H ϛd yy@р J ȹ8@O@v! ;X@6 B@Ț~ ?Uu\L#2<<"R'HDvu"E$'r89"9 r$r$r+ED "jD$7ANd$q9|#Fڜ@>,-)).*RI@^@"!yN ȍrrXp䀯N**22"<\k NDȦD1٭,"ÈDD# @2FjH~"2[wƆ k"|Vȟ@+K"qI[#m{_,|e 3 k @=#< @nk2 9@N" p od7dG dK dm' k."BBr"5"+DH"C" %,"%CD"2"gK"J"@DfY\{" " +Iۧ*ȟ<y_Yo d2O@[$R9@N ȡ~}DBNv@J C k@J p Ue! D'E"YDjD + 2D2"Ut"Gs D~ȋf"r"KJDH#ϪE ssYd&!L$2@&$2٧= @2 c@[W3u Y]f@dDdXXxDDdBd{#R!EN"r'r +"gȕ r=#r3ܡyXyJ%RHK $|7e՚H}4g 7| + =,--).@e@9T IHG}rr orK#83Qaa& AF:4 B~+IHdkFd[*jD*D&"Gr"ǃ)@bF +H^yyN$E ш%RHAKAUCdy@* y$0@:JX9 @N% 8 &$3*"!YdK"kV m@DvDADN89)\$\ "7 r<ȉ<IyI"͈g$ 'RȊ&g#?T/@HH:'8=r;$\! g)8r$rG d[d +"Bd}# AgvDD*KdWG"YD9cu"gȹȅ r$r#"w+Dӈ75DHKKJ oWH2@;+<Ɓ<`r#\#\ r9.+ q ;v 6Ȉp f]Dz$@"z ' ,"C9ȉ r "H"WK"ȝD~"2[gGA5;&"{Or|[K _x k 6@@@VA @.09M@@gdwljd z*ӟoDXYW'3!PhAdJdDDs"$# r)#rL3IDf "srDBA}3*HF/+g}d +d-yld& 4jT9@NSL$ j@c$ c +g @ֵ2H[!Zgg+7$$''2Hl 2DhDI"F"YDjDD&dˆ"H"׃t"GD~ȋ UyH{}/@p /:#RUr 2@dāL u {2I I@i@p 0 d#~ +)"RBa$=Y' ID""u"s"Gȩ r$r1\) "wȽDaNS*ZDD^D^w9g0_ @F$Ҫ ; DU"z"袃}\Ŧ$1N1}̜=3jM ߔ> ED鑑?KKJȻ /@6 b w[ %rr + Ga dd׏ 9!vd+;, ̈́ *AN"SAdA +Ld&9 r$2D.D@dYD)DRDDȋD>D>OCdFzUH@>% okN T<@" @%3d9$ {+@:p[ "ki";xٽADf r3sA" ;&*ߞD^""E$ N"=?}[@^@rB@,b @r2r@( dxR !U c"@ "&IϗD6DȎDd"ȑv"K" r- "w0M"Ojr @@.s$9@$ 3} Ȏ dk dS- dU/ +E|\DziYd"kDV/l %lcYKHId"rB9Q9D.D"J"y b"?D H7#=FO^@>zXZZR\y=M @. $D9@ 1}$ ۸XY_ d du28 ]|O}dA|DV.H5 dMH&;L"DvЏH&Lp9DNS%ARA*FD1H"=tANJv )!U ~r'@%st 8r$b @vȎ dkBٔLJL Ȫ^@V.,j"kDV/lFd& "" "0v"9 r\"7L>IH -$iDgN%5|*O@@޶dyZ&&F@Α@Nc- 3}%_|dl` d "@F:"?Ed==M-U";w)"RٛHD'"ǀȉْȥ r5ܨWy̅3FM"]3Rg}TWcEy&{ v ir" G>&}ddc d}o [@~'B<2$$YCDu@D&;l+/"EDDb"È r*"K"W D6"rA䑣D5"uY^#]} 7T Ϻymr#\ r* G@'$ ۚ@6c  05 , "D""ۙDBHȞLd"r(9 +DS$@;[<$Y\\RjDBj|DFBdF.H U&,Ғb G 0[ +@.@S@# 0 ~ I@# [فL4ldi&d0@V ȈIdT8LD6iDd{FD*D3 +9 2DN3%AJDn!"w1ىDg"țN""@" eh K/܁|yO b w+@+%L x9J@g {@:p}Z "ki";xٽDv"g|I +DLdHey_G3=i7ZC*W5@v 2-v | d s!d&ޣ, i: dH!d,TsDdtD64Ȧ 5уHLd?&2"r̓D$k-"w2")"H!IܓtA򵷏,5@!yRIH", +H9@q2" 3 wd Ȕ䤤Da@FGEd 6"Fd'7"EDDe"#AX9 DND Ar r"WWTDQP6X`Æ {lsΞ5NIV|߹w3ù="97@]{2??s"I&&/_ q & y@@RB@j iy܏@ 7K2Sh@ 2 ;*l ]D: ِt"2%DDRE$#2A" ,aD@dY)yEK5M:d +IO%3Á_\@dL&HDd9"  +" gϩbKWH5DHHQ--W@?ǀq o@^,6r#ρ@N& !"o'$@& < \Y7")|SAd;[" 9DND"y@"Fj r%yD"?щD:)#PR>>L Cg ЁD=gN@B w#[ "lIXrH9!u !]NjȺjD6WٖE"Dv6LD$r99\D.cD"D$"O:y(("2"H3pGe@v@~D@^wAr jrr9 @N$ ٞ @S l$қuYljF&2ȈJDp RH"r49DΔ\ +D܉D "OD8"9#TG3U ȧ HR @ W1 sșTr96dWdG2ˁl:]D%!ٌ٘R 2eGd +ӎH-"u"G!939@FJ r܁D'"DY}"LHH>H, c+ 5 ?5R +Jr Y"@ A@ҁL t  @66|Cd#Bg56M "[HdȘX/.Ld*#[f"DfHd.ω,"K2F&ȽDQH-"%"dUIG1 @>e } >Y@ "E V !!Td"@H@@-t ЪEd=DbDDFLF"8 ADd9 \DDnH0 VnW =!_͹$nmA#&)DA䈑D8$r9 DgD."mH+$y[&kG"ID:dHH_@~@~)y[G=6r#@  qHHKB@q ;i@vpuu V D6lD ͈l:cȉH4 r9\$ r7yyVMe["#H##dH$l| ț j 2 @. )D@% Gv + 5!"< "k"r"cc}qDdG@dW$#CDA"' Se"ˀ՜ȭ@."N3vD^щɉ+DvDVDioJIXd= ?y; Ϝց<$@ 1 iDr 9|3ݭ@G cc ȶl"lƉl)& "{ENh$r<9 DeD."W-u"O9y58""i2RFAiy?ĀtU O@D w![*Br.9@N G@d+Y#'& ;Yқt$R! Dd#2J 2A'2 L!"{RE$#r#9D.`D"ȝHȓyL}D>A"U6Ҋ3f @> k O@@ w*\ +@.@ Q I@ŀlɁlƀlL@r!i+˾jyHlADDȉLՉJL$2" " \ r_'$"Ιȧ~WRxC@yM=3'$ wuJr rdC@fr P i2\ dӀ CJ#2DdLL/,d"4UY +D@dY)y\&#|$N3NlIOUɀ|"2 d9Yƀ, 2& 3 هʁL$ |ؘad(I ZDsOdkH8iL'"Hd>YDKD"7 D#"DbD"R zD>fD3drQH#5"}dR,  tȾo @RBidHH=!?+PT@LIDA@˟jTBakIl'{h٘bLbIuq|2w7d>:~. v@dHd$9DAd%9HdO"KHd5YD6M@d3"y G s8 u  $d8d77sDd'FԈ"s vDNF,C"+$lD#L&"HB#Hb3sF*R;/.Bȣ + d=Y@V E,@ s,dZjJd@鍟IB@hXDD$RHJd)9#r +\Dn> \ց4CTg$g$.t$hQ +'; с)g9 +\ @ " ȹșoRr51ȡ( +$K>ϵ qK$F$#r8%2U$r 9N'RR RHF B$r\D"7ۀ=@!$@GVDH=#JikJG[y  @@ {mFr \99k2Xi)4 _r d7sIdp_9R#rH1"9""g#@r r5 +DfD'DțoGYITF2$ULr|WGȇȭ +   9 _}$$r9F pȗ2қz0pH r 2I'2#2Idq !F"<.% R0' +$-'F@2 &@ )r@@ 3  +%|4y 9"@ Y@YȴԔx 2қEd DdF@{"cu"9"3(@d!r%ZDR"K Hd #QA~3myK'ʌ1GR< Ύ@< @n d=Y@V K)SY8hȁHCHw@Z +So/l}F$ +I"DDX9J&rD%ZDD"DC"!ˀU@: r3yT b@Dv"M4RBR$x}Ȁ|H63yQ(r\@ q@#@ҁ|kdMLԁr# y@zs7g"CF0Դ2cu"'" r&!r.GRK"qD. H9##TOG9 @ޱR i}@.   g@ +ȉȱ#d +PdrP gK"%ej" t"AHH-"3s +ȵ@& r;€<'y@ @ d:bv@y@zs6wiK$ra-B;"$D"8"TD$Elu%ȳ-d3ĀE e:Sdd,dȁ * y@zOĈ"DDD&##d"'LTEN,Jd%YD8"S":$wȶ 4eH$yd}4y-c s@l Yjd 5!<22F2F!n9*99L3)EH2Fz sTU $CЄE$tB$ aSgʪ,* +[5lAJ${'qʥfj';9΀Uyw{T_+D62"DdS"{H{FZ iqRh<|)$IJ㱨d;_q P@yyHKr-T9g qʊ +_y0-Kܾ$Z!TD)\L\cyPyL"sJ)ٍm!HII}w||tH d +d0% b k%Ё )9HH-e|"L` 2Ld!AFD"Jj r3!rFAND~yy$2&&"yFƈF! Hr%u'ݻf>*>$s <ˁ<Nfr5XrHd=Y +HHHo}q#2/3"K8>BdU&D.D"7"w"b""ߔy:E"[1ȠDd&阑 +d||m]D< +dcR ?|Sy \@.R@b@a K,r2[_,DЈ,t X%DN$DNIFJJ rDAaA{NDUnDxy[!RHHI*thك쒀 " ;0N@@R|OyXGr#\)Zdeǁ, <7 s< eT4g#ȁ&C$"G0"G9՝ +oHD~J<"-vDdJd7idlIwMAG- {p@v%X4 ;y1)J@!/nr|w c@+@@2 \t^DH rJp;c(1i.DΝ[J +DDFR"D‘H4'HlL#e$K9 + +dѕr aȇ,98"">"R\ D># 5B;D"IFjDD* H2LII~ : +Mmٍ2F#p(hyy>  !@&|,r-Tr,H@|@z@zβDd3ENDb"4"k0uN$R"R"rg/D~l%D^1 BH$a"Ռ!ɔL*c6x4}T@$ ;~ M@5 _J'f@BBddH$dR@2[_/%"s܈ˌNYH)"e"S"['!J$dId&.阑*TI$R~u$<*> >م2D¡Pَl@^< Kg &@*|\C\'$Y'Yŀ,; s< vE+T $YȉYY DEDb"'"$'r%r5 !UByy2 ed  aN$6t3 *:)hTuda>j H@6YD>" (@@~dyr3(9S +Yy)(~ˌ~)#܉ȅU +; zI%Fd$FviIC4J +&Kב Qd$2@! [075 Q@>NUȅ)99 +dd!r Ʌԁ/k"D"R"ۉCDNs'rF&"D~@uLd3"DvC!LnF +$Ia| Hx|d, t@^ȣȃ4 $r;# @zBzK^?]"BDӈ,'D"DNw!r|FJ r#yP"tD^DlE`II1#IdL*N + >G@6c ){ ;ȍJyn@N 'a # ! ؁N +@v,M"s{K2#)*0)3DɈ\]D^lcD)TC4TG/AGG5i@C`g юlE@@^ /f$@@}dѕr H$Ot-*EYYO|Q("9)G%g$& +! Dv:;14#Hb#(QQ Ȉd*y yLrr;\ԓV qB + 'x@z.%"s܈˔RLdFd"R^!rA1DD^&DlF )3#IdLPCt<>:$@@^@~ )$ 6$ I@ u K-@"!2K/"Hd 'G#D6"gH.DnKȓ6"qF"/"QFD +aɍ-)!IdL +'5e|td3h 9)s 9 HHHY'Yŀ, K22 Ho]fDIB! +*@XDd rD$"R!r)%rBnBdD2<Ljl$DlBDv`"iFF)Hr&5hQ  6+&:[+'r+Tr HHHZde'Yd̀t^s~Os5,"mD`Dr rH*K4"Dv!J$HB$HDUJ$HddgdXHbd5RC*)TJ?_ܱ|LȦ&Ƌsߘ@\uqID @t%:Hĕn n3%f\cb$vԯ*d1I^ HUe!@ @N@weEd^D Eb7DG hD~ɉLr"!#{HWF)D%s(qaF:4D%%JSF#hH}D Wy-@vr -H#@ + 8 kB< dtdQz@y sM4J,AdAd5:]g Re$ l"YF^ue"a$ER(I%ԑ|}yW} k nl@2ȯL#62"@΢@PoGh9 +U5QDTD>-| ȫ +d{). V@r5Y @Ve DXJD"rlDs,")"W"׆}GD~Ed=Dfy 3~HHIv5|a>++ { V!+ #/ R@ +$$$B9$r2X x nEd,,"C,D%D.5\&E&)A M"k"? %2 yeU7!#@F)4yD1$ d . +ȏ@ rr933 z Fl"r&rRB&."WJ"o"2ñD~$3ĉb٣2H{`dI$2Rxtx|Ā @6#/q@>/|ЃA !!ȕȥ&r BdrLP!G+._7k"HdMd$rIFb r'r"r&HO +"wyR6!?DdDBF$!#;̌S4R$ i)iJIe8JG=#} >d@vdS#|tI8CO@>p $OHrr1rA%^H̗yY$,΄[4,"M"ȈϿ DDs"!#F(IT$PG H-#Hd d>@~)|f@WH&B,@!H!o-M"s#r*#rEd$r r YCܺ d1DZDBF66AFBFv&IBR"ITNZQx}Gokd$Y_d> Y@ ߎ9 6FB* k@ r:rj@y FnC@("Q"g "J$rEdAK"D<|7H IWFݸF[Fj$ȤҚ8(u<|>>AɁ|IIr(E K ʊD E-9H]JD%r\8)Čllyg$76# F:D%Q({G`@@@r /~; +ȓ$ %L <~e96S"Km" "j$ru +D>OiMaDdDBF6Yɍ5#D$PHr%Ie`O#GcdV$1 +wd5Ydicp-!S$R9D"CDα\d& "DSDD~"#H3#{ #{! Hr%Icx:"<|4|}Āl)d>{S߇h,kl 1  BXJ$27}" "g"s KȵqD>g ^0ɉYH&Iă{:Gǫ=f@6@2@~@<~ + W@@+ gZ@* %H% do$7tDr!Ȓ\9DDA$#9!#IFJ# #yH"I#:|ĀlcYR >R Y@ +9KM +L gˡ 7Xˊȼ,Dk"gD.`D..ȽMHNȋui IRRA>0t^GH HY ( D>bdYEyHѱ4ɎȩJ~CjDWDTD DAHF$ddHbdi I$gRAޥwu=| فI" c|#g5Á \Ł\d` FDI"E1=1DL<BHF3#;::$$oI$2)t * "kc7e$17 q+ ȍ@Γ@Y@ +!=~?٥D("9Id"QQD.dD.D("7eN+H62#"#/6DR*LJ(g#"Dn!r7!YM!BHH3%4$"IL*(wHi@~)m Y@ _N. 7ceFdH!̏ 4"k3&0!5H##HN#$AIͤҞ8 )"WmdK_@ +H H ++ȃ@nEYi9!3 CoA'"r&99_YDVDnq+#OF)23M-dka +IR3֯lAG#G, /D H^%@-   sș +| $ xHѳ̋" J Bd9'r."r&rkDD:BHF$fא˱F$I 9qm(yt H} zr9YNN! 74KȜ,@"%6"WK~D9k2ig$3E!t Jj&dpK:>@n O@\ E <~qKTNd&rȥ5D<`;Hg88_H$$Q% B5عKONĦTP`I !昔<3<3;[Ԙ~bd$#3r#UHJ$IB%Qh(xhǏX@ĀD &ȿ@ }_ ׸\@Vedo,KD"KJrF̈كIi2} rrd%R'o.!iY$r~*"ON"YFF2+Ȼ`XH$*əD( -q_BG##Gi@^Hɀ܆@n  1,@MM$Uy%DnD"D0H$#ڍ#0#P$I%epx8xd ߻'|7Cd( by +ȪL@M"2/%ńȒp"9sD644.DdD>H"?GDedWF2#OmDLr'5_:r||B! @nNR\ˁ7,"]D%$r%ra8oH063r``ph=eI$gTT;:ZHI%R(iT82%v>>쇀ud2 r YBFYP!'{&E$ +""w22HMFF}~HIҞ8|8 +)Gƣ# F@而 _ +ryf@*!m <~a9"TYId-YG\1*#)VF^dfd'Hf f-{IT3P***9JGΣ]G.# %c" oudm$eeDda +"6kHgFVF#{7HZIᤔRR/K y Ȅ@IEUHg`"EdMdIUE|1M"dD:3p HFr$ITXGEɣ6xS* oe@* @ Y<YDˀDd ReY##[ #~a$/IpR@R{h$8y> +6Hcj wE6%@2TF,pBDA0"EHEȯ͌#.H7$0)PJ*ƴFQSAr ,@MRYHZH"iFH0 lu HR#I$g;)Z'q:8*-7# ȫ̀B@1H$ _Mdl>KDGY "yF*"eFJ"UF~gDF~3,d$3234 4%JIRk Huy;]>~ >B@~m$ >R Go8ʁ@OȊ%bߌZ&&$DnDKTɈ2$H0\`LIŤrRQIh#t >]U>~|dy4/E@@Hr> +IȢ@ +9ٟ\DL D!DD"UF2"eFH04yy1 )$L( EQ8JGcG㕠_~D#Fd%I%oj%:<9+ HQ >j ui  dYty"!G]@@}*"O\/1"R٠$")#HwUFˌD#` 0.$=J"JczC:zyD?~rc}Ā\ +I> dgq{ y61'-vݒ"2#}"O"L$e$IDrFg$FnFzD%䤀ťmD^}>B@&H|T@@1 d|2g?"H"2"uD&Ed`"M$e$Iy{De+#%4r|`ohIVR0IN2J1?a#:y r rrS Рg + X2@w<H%΀L(~삖TD&AIS:D +"kfE$e$yk3rܕ)#e4r |f|͛ޡ>$ȤqRIhi>lDģ'{N)|\A1 Ȁ$ Grc + EsJ@~a;KLAt<-y@d!2ND0ML$e$98Dyg3rJd$\Ih$#$$YIŤqTKGO>{: rrS@vu2 dd@^ 3 +iw^y<)"h"D Dd5HDRF@$e hF>HRI:J"I%䫰pd)ǷW/_y {CN@615d|@@~giE) Έl "[HH 2g9H0rQ.|F$IRS)Fđux<}>#C y +) +qa +Hld  KB2igR$ȣn"!g"\DHdYED-D$e$I9hC01r|F +$)%%I㤒|U8j%@! 0 a@r@ r/]y aߍ+DdYID!@dIy2rXd$9 FC#\F?}s4)J*&Rߥ#H}xG9o@ަ$ :f" 4H;-)"3sIC"+Z$Č")#(#(#8 F΁}Fn.$)%YIͤqRIhi>*ldYG/ǧq|ǀ- +~ +HlB Jd2+@H Xj4'" 2DE@d)'"k"A9H4r# iTL' JMKG ǧkkOL?*! g1 '1 ǜ쥀$ ZF@ c~ sr^'  +߿};TD@"z$32:edh8f$9 Fc#khIf8t4|62GqC#' oR@P@-dYC@Rg C^ /$䷟H+AA ,A"ˑ*$ČlFH0rb #W>$I$AiFQ}\x|! dd7$ٌ@#Ձ@F@^-vvId o#Cd!2OYDV"Hd#I`]0rc#j#'k>$I㤒p|U8GW>>Y rr< oP@vQ@MdY@#%d)t i;D WP8D@d @"kHfv#I0r F4J*&ҙz~/lDT|\Y^r8>B@N@@b@:$҂ @"d2o %$ O_[ R&yyMdCdF"!#0#0#2#'ȩ #2$FIͤqRI0 +G֑QhqG Yr rrd;ٌ@5d 2d 7yiwxD~MD)@dYB"!#!#[0#;2#FCJTL' Jc3F؈8zu<|$rdY@V#qQU +G֑Qq}gu@ r, }@^6@O/@Md0.ܚ/Ǔ%_YH4/,"KHȊ +$22 23ӕ`yy!IHRJTL'Jc~})lDG9$8>udH@P(7gL(~R]RGDDb#222#"#[ #] FQhINIVR3INJ)l48j%*3 q}dH +2d^^4R@ m voNWIylb"sCp$u,/G"H0d#G|F΢H[I$9IPK؈8)<)8>$@Udd+_,vvo<'y -"uތ#{țli4r I)J +&IoτGGqVxWx}b! {t@ kJ, h4r-vv' YRD "#k`dFD#gHRI$9IPJFmD~i68>B@v$Y @Vel%g-vvi-M"3wj"/"9P8118gd dd;#n093rB#}H +%IU$CLքG1GqR8}>]"  d,VZ@2H8j <'<&̴@}n"s^"DAFBFsFVn}y\aeƫ1 ٜgvč㤇լMozg3|B 2|Wx/ #4x.a'g@R$+)$(IJVQ˨hБy$G#=xq~ȓF@6r/ zZZ@N0< ) #qq+yDv4"_Q&P,&JJD62r2r9 #BF~? $35)d*ӯl#(x$J|6>6(k f@N K dB9d2ӀKLy#|995]odeku #ӐHBJj&uO +.c.F8 -"?}>~>8?'CJHI@V@ȗȧ}5!ow]1";Is"rDȉBX,W*Z\3rgwaqs#!Jd&Jc?(aQQh#÷߸>9=9!G+ )r|[2 +$K&"_| e5d7g玑H Ɇ$#S,Ҟl#htTH>~g|cǣÃF@lD@֪dϏy }e @]/M BT,+jm2DʌF #߲aIR284V/F8*<|L ȹYF@* 9kn&D rDʌs^Fnlnmm%0F~CF&,/K{6:8!`_)d# d\\[ 4D199]iA#&#Hd%5IR4FQx {c]d@֪Jyr)|d\vDʌDAdX*M˕j6Ck| #!H.'YʟC#l86tT1"Jz@* '@- ms&"adID6HeNTH:JI夅bi4F#|Txq~O{ǔ@J kJˈ|"{,/4c rP,2TF##FH Ά@R*L' J'8ШmFGIsq{ks>&RYU+2$  swȸA"a"2"UF 2WV=7ddI`R9$) v^}$mdaӰٙz "r U@z@f-=m^(dUt}H2g"UF\BF*#7`k1 $IGI0i$(Iʿ/ő"lḍGx>p@* 2O@]@ƄkȴlH2#2#Dqdd"UFN9\^Y y@Fh#CHZ%$Kiq4:y>>nu>Y)ON" <$}@E ڷ#LdwHDA2gdkdں0r<$#ӑd%%Ix)i8cG % "r@)D ڷ\HGF67R$)2P+6 +u<]U>&}\q>&@@HH@d\\[q"Dj#H9,ʌ⌜CF向@)BtIdGQѨm8P>!_8 C2g@#qq%+&GٯLf(eD8#g0502I$4N*(IJό1P2=W%8gcZ@H2n>M@HOddH 4 y$YIɤr$). }i48U<2i>n}u(@9 H_@6} F ⮾ԟ}|bh"sHi dd YGFKA#!) %5Iҝ~34j#x9YqȾt :d2yFd&2k3r,Ud42\F$är$).E+Q(p$][q|!9hi 3'2&d]kBL}G!"HdFVSȠ!)I夀XaƑt'@JrLZ' JRj)T42*Gp>>Αc( _5|t@ #qq؍iTDȌ&2l%*24 I!)iNC#l8R #n@Q@2 1E2.ά5"h/ '"9#5HY I<PR3Pj*-̟aQcG!GYJ H 2׶u["GD4O%^FH!!S2PZ+WC#t @S + +Hd/@ur$a"{@d #MF65҄.# % $AIR:\=FGG}49DLBݝ\iDDd8#aM4!!HBI0i$(YJ2!QQ8+|> d2Ӂ>d\\:N#C022G93r8dIV0$(YJy:4j#HgO) ( M@c2.C)"'DfA"dtC2U0INJKquhe$5FG};>Z )@z@>@>@]LdD-ednHH:J*&%KiLLQ(}Z@f) 36 -#qqڍe4F*"mFB4!#UHHJ*&IZ*Fe#pdǵ032]I52LHO)# t I$+IN,%S)7BF8Z xX|lc0 E@^G+ש]{d"'a͌!_v9p$w#BhcaX;bl##Gu.ߒ_fe-̺Qף RId2Z/qec#w\>>ƀ|E_@6R<#b|532$CPrŤsA$,i+GO*QQ H 䂀 >ˀ6r2q_8@F%fZ\&Df3|Q232AR+[rŤ2R7Ҹ11GǗG ++gV@.) #{ !_y;D."Ō|e633! IsC$,!#^GG.Ri@H $ID<3ߜo +&Jf%ӒH0 8JS)?|\Vicȋb@z ֵܵ|i332E2Q22P2+3l 8v:Rj H hfDTD."匼Y03#)R)tN)9G)#_=|YcG< 4r? 1lm4#OyF^,32VrŤs2Jɱ?`txt<~*_p{C@e. oH DnUɍ\g+O:";#vF4TJdNKf"(p :R<:?{C>V cr/ 1lJdsF>YedIId9ɭddQw3to;_w>>^d@, 1lAne$23댑:#YHHr%%J9:i13X|L^ ȻG< $ayGF. g347FR+) P*-ءߣ+_B%xF>>J ws@nH f#HgyY07FҧdTtNz(.d +GG:>^c! d@2$M5Y Hd02"$$YJj&練Fg#u1(GI@%9& r;!1 H$@b،Ȧ227JIƤwCITN~b6AG U>z E> @Z>H IDD28fdH +IJIΤw2@ITl$)>|,8,  1l$&w'1#F^E#}H2$_QIƤw2@ɭ4G>2 GcGGG +HXr 1lEdCFH +I$c;VZs1qǢ$ k@b؜GENȜ IdRXiνg6:}>^|l16AD6#ϣ'Ic;VZsﴍԎZGΣǫ'\@1[f^ D&yyFF#E#3HJ%Ja5:Hu2c$ $İi7;DdeFFE#RIΤw2@)F8 G1ǣGiG6z"oYD#W1%dRXiν6:9}>;| +HaD0332 yi )S))$(`pT:x#İ #v$#ȣ`HINIϤw2B)GGe1#LJGǻ@bȺy4BR )S)TN*+s:Q1xZ"c$acl@"/4)L*'qұ`y@>H [& F)L*'11G$İHތ32rINIϤrRYY]8*#|l16K5(#sDY$S3Tr4͏ Qcqŀܮ@brFdVR2TZ`o^xQ(y4ǃ1 1l %vBmFs#S$M%%Re|pt:g&u> ?cȑbd ,NIdtK|al8vx<|xcO@H [&$7#He$!yR@dtK)wmt4x㨀6& Fʐ4tJ +&FoQH>FmvV|ôm#uFJ#GP20IN +)EGc:G$İuo,fd<9%I!eK} S5S +dۦXsl0idP20dPZXf\d4=}~MMd"$K DIdJey}Qc;S$İ6Ɍ!)JF&ʌ֙e%"'@b ZWFJ$TH% &9+ .J#A +|=@na?FYE#H&JZLRVL\?tlqH ik%r6y%Ieٓ㨣Gq> Ha-lFV"dLr'M*7-u<*U>Kֲ2HD$gR9<Ɵu|Mf0Z3UY0TI, :V6$sD6~$IepLuLxGa7~c3rIHF$ %sLPN>eal>H [Fg#KH2%9Z+[ Gұ|D@bM\oUodISuG$0O0# $M%j+kG6 1n-F#ɕLPVO=ⱜs 1lBd=!IHJ +&-VW38uǢH 1DYPR2iB4[z@bئNo$Wd;r82m@bADPR2iB2V=t?c?~A2f(٭Kq .u,)[6|ΙceHcqQ.c,H~D򣒛L:e88G{ | F%2l࿱:VxG?v#TrVWhq,(p9eȏH*d-#vKG븠~ FodGrm% ea펿󸮏 CD򠒥LIJn_<>Q BX#7lJ2eȣ>k7rmIڑUɹPm۬cHxЇmя6J3ݶtQ&h.J6;9Qwy\G[}FD,$ﰺHF*Ydw*vݍ> +$HD!#YdNVxP;Ld-NU6(ˣ>R$er5#f-j kG\F&õ<\sqȮ<#<9,GR@'+OW>tn,dKCؤ2VgbA#+UɩR׭MSG}8He2*)js/}GxFQ`&g468ddgue}5yGxElD]u<ܦ1bdosNelh<#^O#Q0{Wi>MdE,])d&g>>V6wp݇@u6(1Ǖ<%]G +}7 aiB\V3#PJŲoȴ7&݅d7lέoӟ`%'3ynhd4?L#'~K@btDNv2t7dFg%d~;@xFrQ)Gv=a.a4!C&G~'u d8Te"'WipAsL%'Kz&~G&'+ξ{V˝%ށX/Onee~fȾk~E-:J~:˾a~SIx쒝!NZٷ > endobj 274 0 obj <>stream +HvEr082NzW=t66x_TU^DDuKoQ'"z/dRڧӾii["U}y*>DDH*M`m.틝^'HD/yMM>)}興0~/FDi@OO?n'D(i(""J-Q""lDi!""6@ڇ +I̴Yi""+m>0BDDLiSBi?DD[KR}TV{?rڴY2e-sg|wZm;}ƕ -Hbry o}‰^.yIk-N ;yZ"i{;'AYnUbjf-򙥔셈]nEnnm~ާ?{@^%w1o zq6 _}b3ԝl_#;[o"m5< sMѦ[ʖ}*Qh= źvDD]of} +$mM)36kXVDD[iiuz)mY^9;lلwvw P7 n5Z1icaB%"o!sNpE[mV] ŬW666kp~*"Ug.Fo }[mۓ Ƭy.D6l!49w#qcoż}dŠM3)";v"UWcnV:;V6Dv$l-+fxdn +\sՆkm= +𱍜sV0@+H#V*b86+66-J䜍ّӢٴ#s +o=񸝘X:9TV";*kOD_e ~ctG +oCnwѸ]ljVKmbzfHR8"5Usodn q)⵭`|@n:fPXk"W@e727yu6vjVWahCgGΦOX`SDz%"bSKtҍsNNۯxڂ-ml;kucf`llZciiCtv:nTkiڜnC:hݠ휵ж٘YGg 6uh['$vĭvguӶڂr=m~ЎBY6UZgkUBKuMi{kރ6j؜Un@9+1ݖzc`#Z3z "Vy#v{o;5VhDN`; m^,9gY!l8m#h)g/{>־VN۝ali{@+ml>qϬT{+iOiܞh=%n,š\/nmmk+`+?ٓt v:b_#U{w"ׄő\lܚ@+?`p3vgmݠuzf#e-X>!'7q6 +t۱[0n+m;ha-krJf We%,mU^on=GcnqOjm5L lZFB+=$lkǬٲXmTA{"^`:r#p!a,6tKI;vsv}yg[﬘nzez\CD8Ů$X֎[m5vKc;em5m8hgќ̺) BaNszHID2٘ᑻgN'1d%ḍO4j~A;)Y7eݑ u,iKDKws3\dϚqۆZklfwBNA ڑ~ʬ_XbYY{"u_c׫k[y?m~_9miǶ[m*uZh/IA۹m mi+hdk&Jۓ6hӶ)-vriSv à@u`vf\WKD{+;5U²h[Ü'ur8ъS$:Xm,%;c-}HLM*(}C/l_vIہ6Wtgf# TtN6i 'dOZR>s˵]XAl^mvGkτO;+홤5!iq]gsfrQY@'dOC'gMRަz5-c%c;{[s6l_ۥm&Bx].*ӂ٬l4,tQ<(d>77EknU"v+ywa^)IZՀ_hf)sM}mũcS&ɾoC{3E\pYj/*)lY{ƥͤ怵WȠŎw%Y٤)f e2ֱ'}mgoKni/I5fakda}{ k/%EigVIAn#AЭ)hbV'ftݓa(dcOeq+o5]]$ku [z%l v+VMaP~y'IuڤuڶmA%g58K>2eg4XjL&{>7:mul^혰u ۀmmm^'p(-$?#)uŠ-9 re'&pk:_~2LuQR[:l_zI;$im.i>iHZgNZUPMf5[8M3Z6d5V(iP +eB m֨mvx ko'vO.˶cvy^VW];69iefMi>޹+d? a}krqK񵩚V6taߜda.OZ'R1iVǤKZ. 1Va gd2ջừxÐxEoϘ*m +]sևY=ưU*XKa^-G!Oڥg` X! \#|L&.ۜ? ,jPKvva`PX~ƹMZVaҮ-m ,leye2V \nf6mc Iea|aߜ慬AOH;Zig/mmvжvoSmnncAL&{]dnWf, +N l픱Kr!lZ8ϧ3H;J;irnVZRv IJ IUY,FTSL&_hGwKxVmz+2;f}zXYؒ!l𬭵SW)g 'iDOZ/Б֧즂e&ouxlA + ְ h݄,*nwjL&{qz;pKgc3uӖieʇD!XIMZ`9Kݻ_uf`;pտ %we2ٝ苊}۩lZS5mx2YMk6m~taZ*u%]u I6Am" F:3ve2:UӲeileaeֺ%k)lovҮI@ZLZsڢkAgI 6" io$d&oÙm`;ᒅYq|kEJJkYS&4.S+hе*˲=fT]}ne2^V|s\m\m[n51lWV`nbOczsMixig'0:NiOڹ4vA?sl+46zAdG\z-m'l:Ogj]Czkm[i~QZݝb$6$ĒAKn-5$qlL&bE߯MkXClB&kCتq7a֪g,|YZ۲\ZxTӄ]k2`Ơm9 1[޹աbdXpSoMx+\5Efۙ !x*7?&kkl~ξI1H)v Ƥ5sLZ޵,nˠ-m2 2UuWWߟT'& +[6(j ֎OmkuZi}o>lOZniC˸EgS-%aGo]se2^ |Sߤ.[i`ⲰU$>yk+^!ޖvƤuG[Ե}hÿfn!gl |\=we2ު7+>|Śl59k@\ߴ,lsG6-XҾV{bGv.HܵzmPDIv)ѪuQlۂY5=uz--AvOXD"30E\tW:iQ.M+/OhvI.[:}hSѵٻlc@ilݼΕH$o 7 zT>ESPiM7b5i}E^[*AKVjbWl-a\D"12ЎaG[\m۰t[DW`?~7] I"im6mX©6-a qǎ,MOPD"a)ҫZme=l]ZXgåViZK5pUǬ}Z^6m4WZKEQB8퓈r$'NN2KaWj5TgҦv5~FS5&_SZRiaZ,lV63=\^߂DCB>g;|^dNRsk\^#Ҫ,mi$m\ p6Ud1jkzhB[mඝ [}&H$nEYRm :kb[Fac5݂N֮Z[M֪Cik}v"풤]ئE Ye* \h;gη.D"y1`Re{m[Zu6[*mvY>H K!i[EMVGdIAuY/|Dc qxFo{m鴶vpKEֺhX k+bi5j$mlyPK;mVgU Y{Zyi!J{Қ(rUҢFW8gcGI#[P"H~Q55niHW^uikZGkᩬ}?/CҚi}HVcqJkRz-'Ygݳ#XD"|8ouZ779k +栵ڗi({֭QZuLZ?mM^Akk~c Ǧ#x7qB́?!H$gNhGqbk툭m5ǬUZݶEk߳BMukuOZ5Y[C^\5@yggTD"])}Άߡ⊰/X5 /cm8][j-rFkJeiUViFe†P[mx .*H$Ƙ]t-LYlmmYWKn|ͬ]k`*֪lvIPIfi}ݐ /m}eyf+1@bkxgc+D"Ag&;`lmaͦ6]u6QrZ;BFi߽SioXZ8"m*mv(dG[ Dc'm-a[/ΚlQkZ־gkoqiM/u.-Ѷ=N-rܗD iCim1kƱ,cu~c1H$_Iݝ6 v0vjmUZUvU.EZ}WԮvRG6;'Zsm6+H${);{hn+Zf'fkA7(Z_kom]CUZWJm6P[i *m//vskDq:l|DE90>?k[M+uYm[kY낵fm[{Z;6QRuiM|]# YSeLlm+x [^7%IxZ:Sl!_eVk5,f nꂵnڙgBJmVUiu/]HZIY܎[! DXn&xdb&?K[h[Z[kNş^wJn7Hmv .0Jl%g=^M!J$ɿ疙6smg-+dmVݢk꽷v)})n*=HJmZuvi~,m=,Zh_XnH$ɿv8$Z :;6WlN`Y +3k /AZn[ i5Ti!KZbn y{VD"|iY4}bkɔGډk +kZ Yk۶`k_k/'v^ji5xi=..IZՃ.km]h2gA"H?_6dF0-Z˺7dZ[ΥMnZJn7@m֭aqJX/=*-tuAZ7%ylѶ0[kr G7iְEkùEk}[PkUv+~җ /{ZrQnǡhfdhR /PONL5nINᙀ:fʎ"uVn#+/A` nn*Z5_[ +r; LVZ'YW1vT%3k- Kͬ=چ$D IRH0&'Ֆ P#.ױ(_5rTvRlTZ`-Kk}M®O5QYk vb֢.Y{/j{vJHjJ I4@fˤ$E] $lm2Jժ$XFȕبm8yYn/66]yW6*-0kh<%kO@Z;$NCk;HHR;LڄZ"-Y_Hke]sb)Bw>Fs> kz5?i6ȍ +]6:)4,6Y;Ϭ0|,7eVҒi'"Z3NDY#i-vGjж-P[Bh45LlewKζBZᴖ{-N,Fh-vb֢JnjڀRRI4gyC6uNKkyjvUΞh4i;mw^-d*]=`-`Y:&eQk+kZHk~ m"-J{yxbʆZ3|ֆ_iB$myNÌEř:VZ\@/u46UR:wx@ORU[nmrEd+nk RY'v6=F7CjځvEjI HZ-=xWz)iwꭔaFSr%vVl2% #Z,Nڢibj[ %Ң~&}gYlqLڂTIZK\ aJ{Póh4Ǟ!<;e5Qia5" X=M#emH?Eh-4;IRZ%hЇ9F9!m` 6ksi/jK*N'ΌډY{֞Io6Bj`lLلLZXcvҺ"NJsFn;-Bق-df~aD}JE֢6Zs"j?γ [T͘"Y]>i؆-f]h4n?ݹvֺx8o1 UAv~DNh>ivHZZgQl=.{mY/*Al~ i(Љ^9Fy!{]_lMo+ն^촸hEQˬmIHm"mAJ-֎}6Ra +Oe1i-LFѼz( k3a]-TܒfuքZ;-yAJm&m3,6 &m$+>Um]e--VܮVYh4gUN^ڻd-4mlQiX;amA6kЭ?F %.6i( + fMKBSiݣuh47͟?l[}_඲V/JZKE eާW֯oMZKãY0 :+vkQz/ FKnh &&:[qNk|.eZkZF }>2nmQS uSVU`]ĭ$WFxŽuS ` \$&.c`o(Qkn^HR;7RDqE%%?&̂+29qIkm+]xVFBGy^wk BZ4#oQkηj+R<%%%dix4~LZXU=a.Vh4[`o]>K ȅ%22n},:yv@%eeު!yK.D&zzI+܊oj>ګwPj4q.ɾ/6|[:[ -S%;-5.UK HY wh5&Ҏ"VGmZ(6KB׬ʅ, *ҧVj4Mg`-%6 n.0nBV[\G/Q֐^ڟ v ڳ2nqDT=,V +ialgbVh6{Դ#VmYϟ +YtZ9kXmiZk#~}[j"y Y#p f "eX']+mAPj4tf-w~]풸V;AZ;vIkߐZ65Y1}5jC:j7-[9ж-SK׮^GSٕmSo*j}=dnNgGPVTjGQ_ZDmi|]^]kӺ5x݌w\[ @<1EeV*tdfD@zpOFP=f]SR֊j_cնQ뫨1j牃v<:שvfM`Z<_AeZi;1k}~OWnfޢjÇR-GZ?jnV=[<?k}K=jez_E)E홣h/]F;*^Uס<Vٶ{}U\:Vh+::.mKzUv?tXFְjV-,vZ|4jm5fĶQ ktXJ5kٲҶJ(՚QmZQ$QT+Q;_&A;ˡ|;4Cɶ?f\0?頦iCY܉dҭ#9ط4dT+YK1kf퓣w^GQhvQQ굝_;ZޏkG6JǑI+$mYku&kǪ#׎UkVnK9HԆdm6n[jJVGM_#eAդ:'L Ⱦk]vXq/kٱJJZ>٢ZZVmUrԞR^j?b^΋n) MmԺQKŶF}ڴZo ґehVY;]b~D^%kIVTWmگaՆPVz}Qk=׬1lF|g̪f@0-+*llcgJz*lYiےǬZ!QYU{b~de߲Xg9%y"Q淝eYs7kFͯqYN"Y2YKnjPڽ]TQ{e~^Eև ߆:ŎaNԺzzR, +L o&[-Zܖ;OkړdejS~ 6Zى,G-?;keMoJgmrD䐭[VbyvI[Ib6̖&i[VmYk6QYU{b~dJΗI|VX4"*j)ɵu֨Usk@1u@*kpM˪MeXN"Y2YjojPv`Z'ZV5G-6sl[9;[%W}}lKzj-0-9lN=m-d"^x6-5Y6eSTKTIY;߫inUBڏ3CUsZ_Er=´"Y[몬qEKZmj6fì}j?jg ߆b݆T֓km5Qjvڅ~֪oZeR5;U*sVdkT#Zv2$%;xbz~KYVVIv/jSkZލݬ`hYbؒ*GJۦJmUAG+֋jMV$'\4++Y_7c$jjX·![EaQmZMQfM}<0-'u"*k7M[K~Ѭ\ů"Y2YƈjS־\fUfHTyJ9\$Q뫨um:5B ^xR϶Yk7uUֲYKz*[K0[ZQUnjsT;0R-G퉣VTD-auΚ].ڳk+ٺC$s/j;{ˋCYڦ%7nh۹veNܶڔќ$kj~QVXq3|zMM0vŒoi=RR*T6 U2`.0zԶ񵈴Ds3}Z[&`z"9> ,]QYMȂbU֞JmK-*{Gڮ~;Z{'$DsrAC5];-[-J3Ⴕ6QKR*%SR:4OCmxY0y-'|TV"H~n>0IB >Zxn{]b]#.[VJŸHҪHu!QK#o +Hl;m+"D"XZdIcǥG& Z*Ej}kԞkMԆP{EL YuF뵶xڏKR%DW/ZdhkCE\KEWi7\ZZQ=C=@) jk.`| [Mzm+zvSeJH$7GͶ[kmf֧ZKqIvZ ԞN$mUZ烦klcavԖY?jV"H/;\yVڡ۶+8> Xp=hZ2Z{iԢ}kcSHm**7m*^j휵BP@TjJ$ɗklY[;)[ +-ZiFUZx|?\Kmvb5>h!bueΚ;Բb D"5 cx ʭmn-LR֢EQ{_cEj:RkSO=[)D9ؤNɓN+DD!֮weԪZGԪL-Eb[vL?,_D" i7SmyYܒ*uԪP{b>BjCV!ۀviն${g/BH$EDY/ +dxmVrZtfyTkRݷuHZ]2q!b[EL}v}vX,?a)Dֶ}aяz\kDnqY2KvEjSoCiϹFj"M X6jhYhUw(_D"H<GLU[`7yQkf4-%NBvIԞ=hj ZVeji%j5Kܶbkʲ^~tԣK J$;G*Ǝ)}4J%wn5QKfjUӉ ZnNGojO[bٱH+H$o_hz)\ô+Q 8ojԺZo7Qxl]2q6m6mУ-֟(q>yBD"Sg2UJ,m &7[eRUj{<^Om.R|БZZlZK't}vn-?])DZ;nkzrZ7')wH#Q} gFvQUD,q[-![툅\ހP+H$/~;?Q\6+-1K䢲TkZPQ{ jwLk*p:@'m U՝^+\l͕R+H$C_ +EWi;H-9Z 8 YPZwCK{"iDm^Qրdnim귝Nff6{V"H=O #*Pآ,xH⒰pԆD#S֞~VKDeh FbsH$kNm[e䒶QLҲ QQF}u>hZYZN-׵C7d\V"H?Ҧ]1kl#WZr7DjhZZQ}gFvQUZZq╨ŭ啶: h´%D3~w( tvzHfkt+!UZPQ{~5QP6s5iXZ6syL>}V"H2_ڏ2pZ.&5[M6R F6j=G6TjD-.>fVgke%v/H$C_EdC-K@Q oJ^+!QԢ_]%*Pi ry'\a|pD"6eS/YWnK:juv%jVZԮK-RZ5.g:7Z~ZD"yrtpm׶Rq#jQKv7jWֽ%R{QUZuGH-^Ruõ –3gϭP+H$F}G2`i@lUtCA%j3$d*R".%Ԟ@-R"fuj`ذZkUX訵?6D"H 0.!P6Wv*:bn#@ƨ=ZרzQkښBv34ZvdvZD"y|mV[ВQ&R \kֽӉM>PDe9PiU,;v>!?xD"M}gWzw#qJ Ze)ԆD#S֞vRS%RoHAӂ̆D.fgI]ykOq%D61:Y^[ui.7]ZuOZԮJ%_QW[UAXcTJD";9͏zjlzmfm.QKTa%jzoԮH{K R"*Qk\ f鑉Ŷ xmfok.H$oGӵ)kZ5*qp~.+a.`l$;.s[ad6{Qc5UyhO䩝<4yj;Pz@-kΎZYdgj< Lj~r!~A1`+Z%r|SKzYՅ_J;^5\ybuRB޷|hm[[ygR¯u䩝 |kvJjb+M+msԒֵCG!;󭟵^ۤltJmJ[Q-Qޑڗ'm<˅˪Pn b$gvuRfoM i9*ro!9]j;HmZSzj?Zv%̬6-Hm9ZjEqKڴئiZMnߤv$33;gjUMw,E!TV"l픵Z5vRMkC2V-IZgZCEgiŴ1P;vy4;ԪZZ +jGe B@mVgrɴԲU6RKjSk3VԪDJj"95E'$ge#ZwDZR-SkcjuV0XlI嗄BGw{ jᑩ.Ԯ Sk#Sh#aqt^mFc!ݦ7D" lwgM嬃qL%RޅڗjjMZi{jVyP!<5H7r m0-ڡN]vefJRg 5yL#j-EmZCmwTm_ jO@jLlOVYAZ3=PBOIj"Cj[{k3:S2Z͑Z@6jym]fNҟQK!NSK5{jZ:jjA-yjVjpHc!ھFmAmXl#aN7%GVVwRE!T:I-n MjUXiQK7C.ڼjˡ+y BnS?j0I[#Gm^i S?PKyD=M`m?7s !<$vDZ5zHmv,E!tMښ`ljuMPkO-5cjIRuzvZ33EmLcj:Kq-ҘZ3<Ln穥tZ p̠!4ܢFyjoQ;Cjcj- ozfpE1ǽ"Cjʒ=v*~S$J{LT?!RKO4tu*Orj_jmC"UG +` .JQK!FԚnKxN{oG*O%u׿MyjW'L "?m9m$hM%v*K !s;Gk-7X/v (';-6/?S[OmyOmjv4=`fSS'1m}jkR[SQR۽R&Rێl' vbjwKmRtv22|ZNtԾu"eV7z&P>0Srvj{jf*2LmyOnUԾ7σvS[S[60xjAj1djڎ"*=3SLjW}٦V27LDoS 5Nmڧi5k 䞩]{Mm]?Mw>?JmΦ?h4,%$v:uQjRR[gS;ء&, 6ک fR[ >>ҩ-]]5R[R;R ,?svj7_+MjR"aS=uuiHTy`ɎԶ~Rj]vPvbjjR dv6JmAju[jVԖc8J-T]彨ۦ=S"ԖsR[F>~fjԶ6TWͤMmycmR Lm=Hm;RR[OmZe9R[w-vvca}Jm;?㉤S[OmJ#v&7-HmS{=5Ej8UR}٧|rjY}hMjRNg|~j|jp̧i H-LmٍXImOmZ>vaj|jImJ-vaj$ImZ>ä%"qi[R+?ĮuB-ݽ-UfZդVJ9\h_6"Ԛ5CZ""cP++5ԚHm5SZ""jU qDVmjEeG(F4.PMj%V*Jw7Q_Ejϝj@@-ݵGR;jVT#UDRۻujh.R+H\MOQZ)|^SPKDQ;9Rhֿ۠S +oFjuN.6*JUijKԪEjucI-51jjVMvZ{}jSUN\OmЊʽ ԆG1lp s&"2HmLxH&nm6P?_ ZfklZQU* DDm%AZA[몳"I{ :gjMB"*Lj:jŶA;3QkFjUZy,_5Uj;)zF\CZ"Tp5TƯ;_jsBm@PKDDZ6wE@m[%"OQqMZjeVYjZhjZq+mڎP/\4b  ZU*ZOxS+&m2蠖h筤6yVV_R2juI@l:jWGF? +G{FjJ;R5fnUv4m2{jRߤզ6=<&jZl@m_v\jJ_kԺDʩճc56ΧzO:k""zV|NP6;j%EjmCZDqojeXoG[UPV;lZ?T%"e:hMYde;%ZkԉhuA +Ԋ +fi0rY>FDDY_xWQZZeD>q=&N(묗7YlQ?tcxPKDVRxuŽWgmN ԞoHmoUvuOk mBmeqɠ*[.Ʒ ENm˸jfzg=Gj5sjrށZ=Ժ1{:H;mJxj\FU6RگE[R;SjVفcQkjO>PkYOmSٸΩc~DDjUVJ/,&PdԊJPWÏ@@ʎ@mPGXjP/~dԦL73Qk nVEjzrƆvTRjB-ю[Amc*Z_grjL=9P^vjxnaQWZ%"zZ Ԧwnu@k:i.I?۸ DN ixڙᝢuX9 )JH [x&j|jRl]1-Tmkõ7 jA[cL!W*mvP=Ofj?#l-#{[4Z+fgMmKvUS6./ԝH:.ΎǸ?cZAս~nᠲִ"Rx +בey*=Fk+wa#iVa7qVj)Si@AΖ~(>V$*+͖zcjYچXj_Rskj?ZLf5)ۺg==9sAцa,QbgMvVꬍZd6R~_LG JLAfGjYmIYt6RhȘ#A9r-F[iPkrvFj= |6$jZq*OQ2WVun*6h[5uˎyAխ~.d̩MOmv.ۨQ˟ko>Z.J-o\imIF.}/NA\w]suP$ԚTl7).ZbjB-Oufp['Ŗ:]ϒ)S 7wWz*;ۂlK) +^@Sjˢޕ[XyYKfeS#q;c"=9r뷆\6.P^dJ%֛R{WjԺwQkmVjP6pJCYun^[֎Gm^; r6ٲ3li(L6$jVjc}/B-[Hej0>R>ZmTKs|ߝ;E9kvo\LG-ΊGjRkh& BjbR{ԺL핕u[t6RKZ}uۨ;TZ;=ģ  vm^"(Jq#YZ'jY+GJ"^ynJl<q)KAdv1 ]5EfkZl7ǓݮBRR{i} Ԯ +<|Z +tv14~ZAs}?1YJm +hY)J-#>j/o)eQjJm%FhH+4ˢ|d*RMvlvoQkAΟCw}Qv]YgSy;dIޕey>j/o6Z[V5>¸zfhضꎣ9r oz{XmkUt)Q+&j ܮVjS Zee]_s5Ŷ[%c#?O s>x 7΅NYDlqV `FjyjejPVj1{j[7wby gϡ@1vk24Z֖]n,-Z'jYŹ}QkGjR{[Zr~cYif[ݏBؗ'kAN.z{~#;KMvx͖VcsY;[+ԲAf=O!UmZ?|GJ{eZ rw*tfLT{b+r[oh P+*|4^DmPj-Sk|ElZU6Qَ\=~' gxϯDl:g+Y֚J[B-BmO6$j S 3eh+E9Q]}mL}M6:[xyG *Q&Υ9jυH'jY +^ftVnܾ8W=uZAfwǗRbVdVD]]Ǩ[{Dj]vjSejHI׮gvbkQkANWN֋(϶JZZuRR"9Xk3!Q{]pmd&nh6k-E9G^{[uy]x^yدԑ +(ouz2$ +Q}rfO^5ejQ{&jS~m9#R{Ue `]+N۽0:ZL&٨@F65;[_ hBrԺD̨c=uQ;gjIY ,?ze7ڮ7DtGX+dbtZlRk@ڙV=E)6g-RNZkUӚᯛͽ}ⷐd2[Əyƺj2gͪk} [Mo)5G-QJj~|BmNXm(khƚ7mQޖv?a}s2LvR YYw-t,<5*)gAM3QEj?>,}jrFj]yܲc,5#(V]Jd2ޣQ[yVl4Y,Ǐ,x lKZ߂66mW EzZV&{Gq62m][nص-u"iHRZp,k-J%kQY&|ttnNvն;Y[_/d2L^;xo)}Y(=˜Ō-ڢt<'DP;ヨM"gV嬥Yk1k )kT-gm[P kZL&{ vՋm_l j:~X]g4!Q L&iڏ1OHf-QKY9gjIY &S65]vC [oI0kZL&C;z|$\k5ZzIbϒڙH̨QOR{[ԦEj  x:: D-WnO4r L&}o{2vlY[_hkY39MQU6S{ajHHISۢm9lw}dAԶm˷Y.} +4,)Q{ ?JQEjHb֢'f=Tgi9릅vgv~$d2{no_צ8%cZzZ\+=IZgY, +ZWY j;mm-egB&dﱇQœvlc!tGj餞ՔJ&jFڕ fmZZTŜ)i3l@{:ZL&{=O_|8~6kR=KbfjBEmQ{Z=Hqa·AP5-ajYˏM nX+dwoe*j-Z<--ꀼNxAjg3Q[%kU%fmkԶȬIkNtkBSnz +LXˮ=L& igCAdB6]31l=q=bZKZ+틩=UjoZB-bbl:k~ֲeEX+dciW N:j#xq]ZOQ[ .R{G헨ݱP3[KVǬųĬYkLN֖\;.V&~ztJݍZ(E-yKAK%cᒥ%jԹD!_ k*kZBWmھl3^3GX+do;$fE@1l5ƞ -ڰZ=ĨŬuSk\}Vā]Ӛ[Vke2M`l/0j !yj u +ZEJ~~kZZUMm~6km=~Gd2os^vV"Z/FsQEZ",jYX*emW 6lrV'Nvuto4%[L&}>HzǵM]tZE-RZ=DԒsEq)kYJZoZ)za)اя$d2̿=Q fBG-E-Fi(;d풲ʲŬmgm_ۦ]9+d2_Ken۽Eq}ـ޶]xԾkH-emָp)kmf;r*j;xEv~}Jj{#mOj$..Ԯ[}j6yRZ'Z=yGk hUX)>VeEy}[vul`.׭nve.".H-E։f>֣tNk+ɭL7wPA |e!8}hI-uVPdֳvRZ;%=k=j^k=fw}jvZ6+5ث- ȋ3j{U=uZcܾ^ԾCH;ENcޅ}uIk?NVk˨oQ{o4З[Ao3Joi՚f-7z@j]$Ij iӤ=UZ;wve-s+fa-` Rۑ`eFڈ4+MIע6kmDmCu#-26vk-N{"1"5]D +iRSImDiD5ZZ^v\o#dݒjw\kA6 ` ܀Ԃ-Ԯ_&cQZJZkk-uj+X 'q1;;v$R˨ŨZ"k=j6q%n;;dZRnMpTa-`  r\u *Z("726VPHvngӭZq跧ߴFgk_\aǯ Мmm+'MmHQ,c!sNQ{7iOiZkֺp 8k* Xۈ- Wdp!m~x@Yo.k* +|RK[v4ZKie'CeY2q[֚- r o855^:Jj͎NWJP;b5j~$֚Jkc*ۆv_M̎ Nm ZyMtgCF֘ZvJRQ ô/)iL$ʚN#X "<+{]j0͠ V6I-y~k](ZWhrZn4k?؂ Onm&ؚV-lt$Ej?vvڇ@k]b۾.QkH< Jry~A[n ad(F BԾ%Һ/kv%+j;WZKⴔ:=-- csU,ikYZI&Ԯ^j=cov6rqZ+#pXK(cmx-@[AsP'mLU[H[rAj)K-XjZSv%pv.vqGͬ6sF5wE/ǭtqjUom +/:08dmf)RkԎQ{NkZ0;*Wɸ_͂bG)h rGN4,iINZ0E pszڧ>]Ek=fgZFKl34n㼑Gbk@[As}n~qi#X fkF5ɷDjo!7h&jxu[4K\CzWksXy~"\m̏[V +SjڙPd:Vk׭ֺT +5 UkmUNٮtzm[A_[v㓚qlX0]meu[]_%kv})jJ^k-4mRPAd?Ws?ZY] +Uf蘆JkZ~!KT [ҀMv| 7ts= ͌ 2p.dܮ Sl$BjoZat!w^=bmMLhB؈T[}YK]`-" {ӧM H[)F'e&^gw>H_.kG+k[(1kg%& +m.ohܴѤ= ʣ?. <6id%(eNH&CUpyR{*ֲ֒h-󖄷`*ZZ٭8mͺYgހkҾGyvƺ۠U/|"դˣ`6y-W8,yzRK,봖ZAk'st8mڈ kiS{b{?l{9"|<nUHK}Ғݐ6cx)Rtv+JJk'thva5* JkӜFf֚Z*hωsh _Ϡ[sӿ%Hk +ivk#i bku1,K#LRVkߴֲ2kq[Rf#ZgKUM*:EydF]i]wu!inڒ`O.SV`eVKi}jOi6kW-T6ɶ6WT!aSZipEyDtp&m7pM-vkutb[d +nW,/I,`6(usl VRb>Wڇkv]CEk}EkMvҪm-U}k/1Z b!$k䳖A;@{Fm第b;/ v]I*'kmvBk [+Zk'Toڨke Hn`;J$̉COlz'2iu%mԶTkPtbW6y{i-J;Ei_jN֖ZbuXk3kMm=o#kFVoykN"H~N L`sy-aaU6ڂꖴBV1\nMf&-ZGKK-ݟLM^zkוjmZ\gkuZ}dn-۴QSDs,q-#kEp̱lp(FiԮ+I ӅKR[k.Z;[{'kSb.YՌ兖j~fIN7vS[z\D"ipdLb/膄+tӞWFZx ,J[J<ݽ=kZburkxaJLVNkkm +mmT~WջD44W7ڮy"/VpɽVei#XlIZ@c+֗ZGKۖJ{&k/Xk늵X;CdNVC7\nض[z1H$oϏЎ[+mbҖ*6jl0iԮ+I ӥɥk]vBk>QMhkmn(]M=TH$7 8l-Pպ /IZťNڠAY ! tR;ݽ.IR{hmUkZZ6Z˭6d-`y'T{Ruym@"HXlƺ>+?BV{vq IK}uTjm}{Ծ^Fk:_Q]ժ+@5vTl)m%D9mWiH2t "]o,W&ti}{jjmEk'ZYKkVekWZ[vVۂjsw%D|eWpnU-44Iq*K-vu֢S%i_R;Zn){ZHb[ٴG ظ-[vSIH$v:g[An8WEQݔL,$-󍤝n:O"m[j{YZ{c󵖬6XKjYMe6okCmD"HxZfԞ +|dj^Z}NZ sZ5RLӥ5ݵ=Y벵UZ=PM-z펶_vcDGhЎeVHZͥEXIZJuIڽRWݣWUk ֭h)^=V{fUxYkP~@1vئ6o} @ +yK%7(l3Uy .TZmUZ&lPH)동-j.Z5(Ei'=.{־Uzjwvaʭck*_gUT[KOGς+H$?"0貪e֣ܪV5>KZZok{6,H{Tk.Z{c['vsX= gm6i`-R=v4o} WQD"9/7jsҧ F[2i=?#ipn7vZޜiDi]Jk 3YZ{;k-/08r-bv&+H~dؘqO`-T8apz{Jڛ%iI;'iKk^P]kR5ڏ ֭ZEֆZBvٱ6Xjl$^؍(9D"{)3x$vζ&ouY/E[ՏKQZ*$/EiHIݭ֚yڪ?6ZŖ胲-`QCA"H</Sݵ=Y뢵o!k+VV`|'H$ַؘ*h*m*'U\k-D/%J뒴/'Vֺh&f[*[Mن\ckp9U}rn?[O"Hc`hj`B -zS)I[52i۲Di]'R$iwk-d^{kgf-J?US^%7Hgp .oYM:mAZؔ ֵNfi_R]j.Z{!kuVs*=sgáYVl7eNj˓O#DiݪnϪ +JK!m8%핤U^YK^Ov7VkOXk6 Vek;Ŗa[S/n4VD"Pmpֲ-Wڨ*fiێ5'Ծ֐֐pZiX8ld6,vj CZw-D"6Uࣵq6A +'ESJ $N$Ǥݥ;?ܸ +DaDUdnA7 `O2ׅlK'k!X;6Wq D)ۄmQ+&Q97l:N@Ç=ᶿ>63~:(وYw-J[imO9H $IRڅگgYdŃlg9M[~Y{8ٻ"[wUs:NKXt}p^,i1gmY.:ڞEmCv>`-dkOFX62}E&` ŵV®ݏNUӽuתghpuBXmk&-v-$ip@9J;ܽ&k}YkBȢ[jk1n-7چmrqlٱjv m~MsrQ8u"iMF:.GiC&GݶCDcmԕMo^`` oƨn=q@{W<# `ø -h7,C+m|H~h4͟[kQVM d׉mTI-mÇە:Nr 6R9+u "i]7QVriM+xiڟ֏u*A[A sRJZ6XVHOH;iTڿv@kڀ)i} +Y+Jl%m+mKmM]y~t'YḹOr)goˢ&n@K]6rKaKb˚sx ҞQy=jZ;GkmvZDn`Xm`aa [Mӊ-bS:NZVBxEaנnEzL@,KZ`6J;wO G=-֎hhP- YҴ) [h9N]PK'z [Ac'nIZIҚiO"S}DN;-Vj+uu6^d} PvVmZƭL|$i'v:EiWvkh dm[6)+ubt|Y\(-+6'ۇGh)i=uE}*iگdLbU]ȍG;VbIb+疑8goSt}/I0[-[–'vv\=3fNI/&pPk0kgf0gCa%lIYNnlmی+ɤpVQ Vӽš[ˡZ_emx.ƁI;3ijs]Ͱv +\Xvm +[F*F_ ð'ZsӐ])3;,7w_; !I۹-V}/6vmk2oQB%Oa?6z'LY A;٠EV_MZHWE~Ml=G\[ôՔ1[Քi1aZpRmv֢esb6w3a4K5Rk9%f&fpvCZgڕCCmn=_6P6ƭ[HǭYM0 j)KӭRY/,hB{BھrlO{nھ[lcfjg񨢮-j"=o!a-w ]5֨lb^̮ ^ wN;}]io[bk㖸L\d[0 m q̂7~z ̦])h[-V5eq ޲ P~316a=*;F+o8l32zKgt w_2l%m^[=YZn\N.nȍa3y~p. V ˕̲OY̓A{CioXߪJzmuj[ҖulV]eδE\b=!x*"v5=R,9. AuBZ=c[K۳v&Y6muRu:ono0 9iGg&anVegvH9>=ׂv}7X{zڞ]*-{n:Maf ɱT61+U.hύ݇޵6퐧mj[Xro#ws2x3F ðY9:eGS`68zV~p lVjq+ՉN'nlW7'0ǯySNBֻXCe!gζSB|7n6זŭVxeFsI]o` ð'X~ʥ0pB2sLlYZH[M5me65|[׌]Iob ðN#l~mYל=Z$wwl mW+Fpd.a;\:T d2![*s6:VRh!msc;2mk +n)o= \.nB+VH۶Q#$Em$MU7 O$ʣ^X}MS koosVw6yBg msS~b=mzw(n#NN4]Y M:۹6 -8չTohޛQy+ΛZa]aUcCd~&,]פ36yچ~k{u+{~|n.|`& +Gld{gugRڇ4ms﮶}뛫{2<ǃ5[<{bHOٸ}g}f;Юgj=VvMF ͍[/D:xrF)#W+w{)&m_/_[}z;Sŕэ[o0Ti6SEV4۴#խes-7ђ&]YB< >˭mBs6tmYBdMYDN'њ,&-58闵V[G笚}Jpǫ SXKZS-?myՇNd4wKӄ黬;Ƞ§uL.Z>/Filter/FlateDecode/Height 2169/Intent/RelativeColorimetric/Length 102674/Name/X/Subtype/Image/Type/XObject/Width 1899>>stream +HׇvFa[L.Yһ8N?KL;Ӏ[8o['Ѵh7j}nigjԉ&SLKk&"~/5Ͳϖh>4Z?S"Dk0WNө[$"Zt<#"ڙZ|jPGGD>tym]!"ZZ[ w5l#w5h-hnDD^푽JD4qmMіmw]b[5J[@;'"P[5Tm&me[?\"o[#Bl#"Z~mgz*Qqksm fhVmת̮+5"差rۚl;dmg]ψn +"DDAr ebq˸E)V츲N{[mktv5FY*1wJm[óc9;숱C:ѮTܢZ٬®@&w*m[@g6l"KB"oGۆmٌcĎC"eUmo4+kۚEgǕ-'"jTޢt+ ź-bw3p[mk٦M)3c"ToNܔҶ5KkhM";ks=!"v %7`ۺBh M;*/}9Onmm`6lllq[[0DDoT4Yo#nж5Q iehCgCf#ezhћ$7mmm5ZB%V8a666Ȼ<#"}5 p[-nJh˜M+u~ND4jN{[-nqh0 FӛDDfڍ(u""s 'My[-nAcSG6Bs"YWpn +\ۘ[mW+8+# [m"Wpdn +\Zڎb.gŜ&-R*b82766-^JcFfmrΆc6F6vXԻDDl\6c6-֮S1c6;gJdC`XW}"~Ct#p>G-`VV>9uJdas>DDs]O\rͷAYD6-k>$"Jr[˭CӶ֐MI;alY46vHGDDKl])7ϭ޴=8 +'8'Y;fXشs}AD47-[m4n=m˰eخX[h=ОjgCfXhi H+mȭhkv[mqAcS!+ qigDD*В:q-ۄcjQb^6pVY=gCf1}ND +sۀ[=n'^۪& hs +fCeBW/r "[ًS׉k F&Ѷ[ګjhŠeJ`CZhie)uZqo}nBmŴ=vl[6j&z:goHgϭBYXlxR&"oɻSגkUڞKmoxiǖa[ơ=V9{Ye6P xMs&["7p {:r%[7Jbۚi48i}h=*g1X1 kƮ/]I_M؇יk*n홝Jlr2lSN!hO$v- kƨ=25 +pݾ5FڞZlO +eؖT>iYiОh}go;gŜc)Ƥ~ќKܵ`ɮGpkƭvtkb_O dV)1 ++u9nͭ=Zsn*omlUNhA;{GY7gvjdVXk,h^eYltך+u +nqh{Gkkm ъn^8fݒZa?L#"y>f \!q{uam֛ylbm*hIhCڻIgݚ}uKVkƒ8OU wB\Kn>PuvkUضFE+N,g[ +Z=hw +g*g%fZdFXx?M3"y>f]&WܾVh{_il[x^`sm=#3d߲VY1+t$y_ͯ=,s +\m?o%v*mm)m;l='6MmYYBVkzU/Z|Ҿ +%s5Z\ϭ׶մi;jضR6?i{i1^Hg}f-U +bV*뢾&"jSّ +.[sטɵzv~Uqj6¶t+MZڣ<h}gze-X5moF-T;Xi%]Mnhkm{C%eƭ:iGzH@u6da)kUa޳]MK,js~&O -6W5ОBYzje%X5VoWtb]%W{qhm(7:lO|ln[[^b~V ڔ f=X!UHD4J5js=ۘ[+eZlaWmk4m8h{g_g圕JeXO? K/y|]Ez+VkZiNۏTcmM[MZ,CoS8@n6s!vZ1@ T@D@j9nĶ}ivb"ۢelm+Zۈ/H m*h'}&ucg8+%Ȓ$Ugy1RξklwyK}a%r)WEnNoa۲O'؎!Uƶ䱭miضy~#IZ/m6MZEhʕJ.SSss YÐ ,  U{.l6[.hBWErQpupKqkضaJŰU؆%kSk$֦خ7_H-&m%m.{κ 2d, } M^]M}fk|"=.2[[ۤbHi l ma]o })ikI-WΆEgˊY, X5jflku>~l1Bo@ד[e[Kۙll2`[l{¶խ](-Bۑڡ hgڹ9.g#f,KIJ"k ~hlͺհ,B.F:nfn!n!mRmcNضh!i;sRV xv~^KKٕ٠, +qF6i0i.i\Ҏs= A{lyY;rYYdV+ ȢDU\囼+cfk%,<8䢸n-q{g1ny2hm6QöZ Ya nl V6Gr&vQҖ)i]ҎEKKG!hO<f1fceY4e_>f^E{yY]2pp[6h{=v(-balG8l]b\k_|>$JNav}V8vsjeeXPG#f6*b^VErcpoK.^@qKڞFmO 3ˈ8`;ö; }/muI[vvHZvZ}UC+ArApsŘŖeXI}f5oev\$7y Uھڪؾ*N{cq%lwZ־i}iJZbDI; I;I NMgm^H9K5c+KȢD,+jP~'6LKXxoO"/Eq \Vzeǭ j6liؖJ`-m*6&V]Kv$m/&m'$&C{0Zs˘ZYFVK +? {Zl6m/wI,򒺊xqqڞCmM=ucmm/$ldMkZv$ve#}Т+ׯ{fe=hKZcGy}alc^zY]4Eq=oQfa ؂1lG|ؖ}@km~kI!iwI;I JփhUٛ7fN{, e_=Jp?f5/Ke2\oP܊>[VnFRs{>i;Eڝ mv^ A^Fg]f]̊,Kz^t U_l6[3-ai=.zp[?k{]d-böaK;ΖyBiwB䤭T ik.Y۷ܲY6e_߄6clǥZ$꒹".%n]b޼lm6 mŅmT,hmWKXb҂>i>iZ h]%go9g?sG1b6( Ȣ$,*&^uGf[S%.GnA$m3U +`-m >d-vnOݥ-!i(irQh{f]̊,v'\tgfkE,9쒹H ޿qmۜ-ko^k +i{zz bI[`MuI mꬃ,,, y_k7fkվ"^Rד-m{Hۛ7jÖ6[ö¶T* +==-dsHۡݩs#.iړڬUB>~ b6( *bW5al6FYg~Zzp[[c[mMlO +m~}}ڝڎMkmҶeI-2$-J ВI".iym⬃}ϬYQVebXU*W/l6[s.ebgeqܷ'Gw$zlϟclW[ [md-mمmXkwdY֠hC{ViZ3GJMuIоu=CY٧O=ܲ,!IJkdl6VkxY]$Sx9[O@vaم==؋ks9vD4JPuFҔ| #k?=\n?xh;cЖbض#l#[?` a BغrؚXbv7HH{$-O"m@063h%gQ^jĬP!%R_F,'zzzz:8RuT\.+Wh +mikmm@BzD񰕬a BD}֘ITW;TZcI 74z`8E) + YY,GK*~vd6m_sx)\,.zKqk-6%!lp)6jRkհERkwbk_5v[[ŌK:v6LZ%ik i>66AkׯKebc9WNҟ[)̀1K%cmFlms4l}1l-$lͬC!־akdGK $i QҖI[Ip=W'Ю,E,Y,BK2]Qm~/]F..xqHV-v\6komiC5m +BkQ>ڗZSis6,^"8iAZVHZ ^)mx@۫BkYnњs+K%a2N.k===  yB\[-[$n-h+-v a;X` ~5lVZ[a-[v"kזJ{XZHZHE6Hr^)D[mU%"dX櫐_zzzzwKl^.!6.7 ئvvZPI r[-X[Oݐ/mFtesiwҤBBC: I -m.mAЊ"h7oO18fYb,ʏeq+3r,rp8o)o#mom_rlg8mMtuvZPb[1j- []־֮.V*v!i-[)$6]ݽ>6%C;UVr/DY,3Vq5+i~~l?%?5\^.#˽eB.-۾DowWg<D!X{􈉵cڭYd3j mHk-.eNۘm޾~@;š"h(g 8fc9 XAk&a&+fa/CťoqRnQ2mo|k`;MlSDOwgGna[dCO-ڧ#-$-6vG婨=M$SCh1j +gQ./Ӛeq2cWU~W===l)Rt X\ +W[-2[I[)m1lC@m5Օa/k-`m>{}:>kZ 36g*Ҿ=v-XKlrSYU][W&mWwOo`094<:6nvAKErgI޽+15QV2+tU=?e*,J•{-eRl؎%Pva[_W[]Uq;쥶=~ [bmƭ> iEҞ(쎲r +%m(iᑱɩt&J*΢e̲EbdXΫbEOOOy9\&.xs֠H lSc#é` +)lQVUV]eRtY{[n[ej7*;bi i vG婨oMR&SC#c'ҧΜ^^cbg1Y++Y,.Yf,Wmޭ٥2q)o++$n[e3S''FGR^)l>oC}]Mue,wK#wy k9[79vPk*mm"a$mHkEҖ;ݞںF? vhxtld3γU]B޿/1KSVB}YSOOO/2<2t \}am,m1WYٞ;73}!,lCPW[]Uq;ːVY{X66ZB-v[VYk&m,-o]Cڷ ZlCҺܞʪF)4MGF'&ҧLΝ]4B8 9bCֲYn,V蚡 ^2Rt\\[8nm1-qlelL9N%Eض4G&v!kmV X=D}k-k_lbkG&~G8H[dJeNIBhsk[,.'ɩ3ggfϝhegZYYZ,W#+e*a|nJ8>&ټw&@ELl0.[VrrU$r 6I60B˒a)-s}s~3gg&Ds1qK-[-|l}=݄l4jB.+dgeO?v'S~Y{'ݽJQ+);K{I6ONNff]/(*.+UKچFwsK[{3ІYhAK99,,PYd!"Pl7NDs"s4tBonQBm?β؆l> [^Q)%E92O}rx +=d᝭}q;kژF}Ibi~H{&5\z6/HVP5I=Y:hgoƘʲBc`yr` ###ۍ>3œ\>oqnA^E2`؆=[; [Z(k3ϥa}X'IRҞf_+(,*Vg06U&mk[H@wo_040CϾE޸rfSF*lMsbr +ԖI[>ᡁP;¶ [f5 :Zˊ r/dkkOO9&a[q[+D6frҾ -JڃP7qi=_PT\"W4Zd{Cᑱ8 2Z/0g隅e钅bbAx!###=bb1v1rpuKH/AA;CA븳Tr"e!XX>~KFFFrs1Keqh{h E +  = ʊ2nzFT0k8k?};k٬MhkcJG$-VB7X mYr *Vg06U^%m t +OL"h x^A{-,HYԱjc>cbeŸqKk{ hյkxbD''FGC l{> ۊraV\<=rc)kߐR+vOZ+!-/jiMN +F7V$m}c/iãcɩ, ZM~cQ"{@FFF'|jB~9t,[[7imql7hl(lggS lj+Jvdk5*\V̳CR&kfs Cm̨)^Z/Ҿ[Sy@Z%hҲ:(i4_ ř! +?'2226+ ː-_ۯ1  (l;`VWV:6Uk rY:m˔ikemdNBji32%rZ*I$m&ttvnAe +Z٭-cbq^@s ٳZJ +a]\\[[:nܹC F[:vyiq~n6:=516ąmKsSc}mMUEYFNVKٙ$=DVBZ籨ŤݗLI-kI_PT\fQ*ot7٤LLNEgW8hMݻg)gQb2%*Up%###݋3]\$.--@[жwӖveyia~n&:59can,w:lVUgk/Q&''YcZڝR+UL#@wcJ+jujwWV54Az`#3 +ł#g@gYfYe1cq_%T[,Iyqi{=ߠ Hxh nj,/+uحfAʀ9R־ =YZH-nmBfmrQ=}%>is*Vo0YvgiYEUum}CSsK[G'H,isK˫76%EAEÇŘ"+Up ###e1]\\[-[CJۭ-.mnn]\]^ZNca¶iZLV}X{M0i@i!iҾ#-mH&W4Zdٝ.JښFwsk{ tvr* +viyڥ+Bha>xsV, +YXW V{"###Km$eeqkϽ ʋΜ|]nSA+-,ì,m,ov?J_Z]Y\[rb*l}׋aN¶\]YQVZ\Xw.̩#`OkC/kѲF)]E JԂz j%i%iU>/K{}iO>WPT\Z^QUcp=Av\ 7yYYYYXZX[>>>smf++y+svfF`;8>{暪⢂ܜ3O``aU&KFKj`Ek%jkkV떢V!ZZ$m8VJ +HHGiWV`6Z6!i.?84 NB +.H~β̊RªpUƖQW&Ww[B^ƴUb; nS[ڌa[S]Y^VRTs=v4ȇo,Z)kᒵ:ڇXk5[@Sn%i}l#6hKHܶ/Ҿ~ҞiUTVkZZ AҎOLN]:,2(2*+䕹iˠ+VvQVvaAN+WNM#C>:l[[kՕe%Ņy`Ghۢ//aĄ81X Y+Zd^Y+[d֮i"a(#6ҦiKJJ1H{ H[PX\Z^QUckhln UA{Y1>G>>>>,Mz)sip*%i;3vrbltdhpPaPg(/-.,kϜk?FkAk_Ӳ6}Wk-dG0Hڠam   (m$+6ҦҾҾ~怴E%U5u Mͭmn{?i' "b*3K)+ 7m:32+i{qCH۹Y%SLڻ:ڭmM u5U%E`mZ ZZ{)hm|)Z PVՒeHPJU6IvJ{PKP(mn>H[V^Ymoljh/}췌~dag>>> fUpKi-j406KKSc} EkhY{6IvZl-ujjUI!TiÉ"Q1ƸJDڧii$AiOi A +butI;:6> I ~9B{yS EYYeƪuU_˘++z+qrKi+͛uvef47ׁ`m!$Z{X&m qؘ(ZZbm8XcjZDYne !"a(-DX ݞ3((m1H[UckhlnX;z}۟Ӑ-$h/nAw?fEe)cռ*||||kgeȕVVJ[ Jl1l? [ghZZ5U`m1Z{4Z;RS&cl4Z6o@mDmjjD-H7PHJڍdiEiwYϩ=J=Җu M-mή>'HZ@;B+Y~cվ*o||||kiK˒K{+sVN[ +Y[!l [l45Ղh9bQρO`ց{ekek!kF>6p*Fnic869uJHLjyDJ::&-VLZ?%hIR +9+0(ֿ!VV[R""rgyNGfkJbmvGj2Zg2ƀYk#dku֮0 a m8VH5'n#Bi3>>Ҕi[,V[GWrCIB{] {r2Ȳ||||kgeɕl؎ Bغ]>{wWjiinkڢMkςODkwk%Ǚb-ZZbm8XcDjC$jWjDaa(?jQڭ MJNّkwF`iOҖ:bm9]/I1!i$IZmg)f)d|U_?˒+{+rJlSؒR1^nufDD`k3vJۑڭh?kڰ04vE  +iuDZmi {ef=>Ҿ(H{X-mmi{zNI;:>15}^Lگ%k@+-Y +YM_=[ +ro +a󸝎ޞn m ֖=,X"Z XxV澽颵 (V625ku֮ ˉZF6>iK+{+pVL[߻wwq%b+R^p~jr| y.G6U(k_XZX{ sߞi)ۓMhvkm8XcDjCVG.Azͨ@6,H+Rnc4:8,-qB;ѹsJJ) """"c1x(ciav[M޻?|A"Ejw@\K[MڷN_:[SWKZo -uZ_Hg5SO,FGGG0/*pYomah{m[\~C` ֖UgkOB־ +lmQX ֺv+kB.E)Zgm|Ĭ]TƈZR8,m"Z$P,4Vg0"i m6HH[]w_VVU546wv Iˇ6g9bcl,]NGGG0.q9ܒqj;Ǥm`-`K@oOWg{[KscC]MuU`w[[XfdѠӪӔ +T""kE&bk֮`] v?jWCQQ6(mZV$ʐ$K nҖ=IJ3Z$mk[GgwO_0$"@;@K8Yroemm.m la;<4֊ + [iIe `m&֌ keR YHX6.@j~.ƎڕܨQ+0"jR"T&W@Zd.wfvN/ `i?iV745wtu AeEI{:lvtttto Җ +b @_owWG{ksSC}mYsl\kO-)Fdg]l2ZR.EBZd-V YڕKѥ%6 m6IZ$mH,4Vo0-6ӝTvϾ>rqqmA iGF=I{e9;ZcYQ6/u:lɠjT +T"k]=kѣ6 m\Z#mZV$4Vg0[lv;# ݸɧ~瞏)m;#g|795 I rH;;' O Ag f#!K%une h6wl1`5n"k/M{FkcZs>SO֖nfev%diiJL*vK1v%ql>[Zv]P$JZV殏" /2!iFj KۏO'΁Qvn.lІ;=_:::snѴi\kMM'ƽlmX[X{^|!sZn5:Zˤb6QZdm kȬ]Y mH,4Vo46+#3I[PymwڳC1A ׌D^-r)aL[dHLk_Wkw"HK&UAhoslTW:::r- (la ^pnzzAdm'SoAX{\k7䁵nfI7Z5V* SS k;L-cm"vɳnQGmDm H,) `LXNwFVbO!m vrj$mҾ"%{.\t[gJ>i[g1xxxx<֭ lY–[ox{/`v#ھ. 7;3 B4*\& AYk=k:sڅvjCq|"j +Z7BdԂ I)iٹ%eU5ͭ M i?xsϓҞpi'@ک Zwba\w/neǖ33SS`,~HY{>/aM쌴Z6֨תU +9|.v㑵\:j!EmH()mLl\|brZFVN^aqiyUM]CSk{gw/HeLi_}=cҕQ6i''1iihu=F[?Qa;9fK6kπʴvǶ[֦¼FMg-5k)k]}]DGH,AQ5Q QWPTR^Y]?0ݵgBړ^FҾ ҞwVioҺ&kв;;Smu?e'kσo#k_>uY{=m-MՕ%EyٙɉQaD k5(k%bhj#k|hW.!V Ke +Z QkQ &$efUT76ut  :r R7٥%%̠6iBﹽop-+vfEZK`n훤';BZ;2<48X_[UQ_;n_v[]][CUkuݮB@ $ II p}97bA@iz~ConvޟcrD8 +c k:;olHQ[{FAWw$jO a$rt HMcsxH[$EPIVuҚ$ߌ,T!vtbv~kZrb [omyLZ <;-HDIa<."Hz j09:JKLbk-Rֱ}D='hԞ6 'G)q4z2geKr eeյ@~D zvveum#w?Bn϶ l;k+ jbmow'LV\+s3Yd:-.B'qA k.GO]8;1Y>U\k* j}Ca*-1✼Ry"mskVڑ jrjD;$=likhk&Uʉ͈Ғ¼qe2iԘHR!$8dsY{ZQ<"-B>j_6c#j?;}H^  + %GFQb)$yERo`HPMjg-\_[H̤6u.G~X{c}ŅiͤJlkijˤEyPaRXJTd81d$k~~gY뱑,f+Eg֨MoFQ{$j}@rtl-1geKr jTTqJA >6V:9{[گ ~Z;3QèՕe2ia~$;HOe&'ba<dIwڭ֢aE,j/]QF'&1R\@(+,.)WV76wvi'jUD7QiA֒vKuˁm6֞QkAyc}̔Fvw67VWKK rBNKa$%Sc"IА`/eY"6k{&Zڝب}RԾ,D7 A%ГSXLP$+(+j Ҏi'ff˨PiA޻g&--*ݤ} +g +=-b-EZ ]֎J +$"!?JI'RD<.dצ%l|VYk*5Pk=j jCa$rt LMŹRYYyeM]CSK[GWOVF]B]3~>ξx8888퉴ڻF֮!.!NOMڡ20?Wf2iԘh2)8k]>vǖQk1jG˘}U{EE~APbxd@g@(+(.)WVփEWԚٹťk+k7o}iO_MY8888GIm_Y孛k+זf5jb|txdm}mu /G,8lV +ODECqA~ k/W1Y26k nuZr@"ѱq4z2Ir 2yEUMvBLͣ^G툴ZhHh}ppppnOZl[{:j̔F@lTUeҢ\(b&iqc8QJ EL3~~9gKlQ)RwX`Yz"V$ww@.dޟwwa +|^{y=cGkcGxb*)jQjj?v?y̹ '$fdfW0YM-m]=$j._ H +ZCi>Tvvˌ> 4jB.|.g=<48@Ŭ(/-*HMIJr¹3N?z=v~ꖵhEuڕG-Z稅zFn j9ŗ:r7sJU5uͭZKiRBJkҎO/z$-,2غ-ڟݷvbZk@U*dRH<Rֶ67TW1Jso_ONwHvFXKk]vYuZ+j֗ZŨiC.VԞ=w+גR2r +KLV]ν1_(JF7-}J;ڵ>_<<<7d[wF}bi-ZKZJ)IB>ol= }pN_ow'Ŭdde$]5kwXs1khZkkW) Q 64!16 mj߹!=:RB(J^Zŝ[y3ؾ c뱵Z^Q+2X獍ܻ mi2+K +kSkϸ`'1Q$k)Zo kQjׯzjR>LvkXP{667QU]SyD0{ E\hJ;1i/3Ii=v `_]Z jTJL"Q[7{5U\dڋYXdf,f%Z:v#ZMj<#mMJI+(.-dZ;j Ԏpb2hdjwRJynJ(֨,6%2ڈ(dUzFfvnAQiyUM}cK[gwڳjvi~ ֪ êHv(K\Z<<<׶%5FRkZ%nvk&X{֞5UEٙ~> +D,8lNfԾ5k7DN.Z!jyX*W(PdUT64w?w%ڛP;P/.ZJ Pk0K +o;n־rZqZZEvko"^=s t4VUegjSSc#B(2Xq,eZ77+Zg2Nvbk7G-L JMj4:"TPQJSkr K*[;z!~z<[ j5v(K\Z<<<״%5skͬ}nޟa-~zı#vu67UWdii)I qёk} +T,ֲt&(.(ŕB%SE1l/IdroZZڨdUz6;oD7joۣcԮuZo;QjmZkZSkߘko@~q3}ݝm-5UEڌtUrb\L`-J-`\& AjLIB5֙L-DB-L-D`֡V[ڷ@-(-7>Yma*`oWGksC]uEyIQ~nVFZ| mW/_X8?hkn,/-*HK'DK^BZ\6AI<FDZ5=:jR{njMPh,O$Qt&óRkemckwsQĤTEfv^aqo`xtbjzna B+~rL¥} J X}nO^vianzjbtxJYV\HMJEEJ>" +JbҩâQfYD©նE 5Ca8Lљl.,|$H-'gWT64wMfW!^~=~E} +j5ե QզvG{-kc7ì]]^QM t65VWd%ea Cwv?fi2bX%'d_j,@"Si k~&N._ OQdd*+k:{F'gVQ{o5jՠ-1PG_ + }?hXog@owG[sc]MeyiQAnv"E,{{ .NԞ9me4*Dc1}5ٗ>Rkd@B=Z3I*Ԟsp⻹ E>@ihD,.1)UWX\oji[X^]С/6kQݱP҂Ԃo;Z^awZ3k7Wf&Ɔz:[keŅy9Ԥ8YTD40@#lmAqX :B"q4l/kHсZCj=M-Z#,,5wt <Y#Z(z'.k7!޹}kWfTcÃ}=-MUʲ¼LEjRb\LTxhp`G$twsqr:w9bЩdàQ5ٗ:Rkd@B=Z3Iٯ臨W4GCc$6B,c1Ƙ{{%@LC 7uK|Hw%yuo,NHDLZ%5 m]}#3Kk;gW/߀’|K[go4:jԨ]{Gҥ oR Wﰖڗ=j֮Ӳvq]m-ʲبР_/Wg;kK3#}]m 5#jDpX~>nN 5 kYXNP{Q{ @^AƎBcy8aQ1q I)iY9%uMm=#Ss+{G7Ooఈ؄ԌF|k;phdZ˫k;{}ZQ{xOCjX[]^\}c#C=݄V|c}MUyiQ~nVFjrBltDXpV QlWjS% sH{8j#QK"ڣee@9xxE]GUTVU346wrq KLN+(.ojn {Iãtj=#/,olmӢ}v/4jS ;u{ЬR˘ώPv6WW@>S;>:L%:ښk*J 3Ӓb"B}<]m,L tUj_ +pqQ㬽t"BԞgje@ahbD7n޺}箼PhxTL|RJzfN~aIYeu]o42619`zZR>5j_AjN^`KڕEڙSc#>bWg[ 0?'3=%)>&*<4P_WKCMYQ۷nԊ bibP쿥O7Z6v4S+k`dbnic_TR^US߈om'tE2j@JH|¨;{Oz?#Y?ҭ1kg#Y;624Mho7Tfe&%FGz{9;Xjk() Ԋ|<ܜ4;ޠ jY^AƎBcy8aQ1q I)iY@_`pXdt\brZFv^AqiEUm}Ss[OwD-v}Ҩ}[BiNa퉬R P@{ k& mMUyiɉqёa~>n.6VzښJ +r2Rb8/7bgcPKZf&Ԟ\ԞCEڿP  j]S+ghlfamWX\VY]׀oi MLNj>'/.mlnQQ{L--jbZZppppr7}񯟎d>eog{scmey !vjrbl4Glk7UWd$Dx:9Z[h*+ө~ P+(D8_ PKZZZ{j0R{ZfftjQ e@a8xxB"7oݾsW^QEMCKW7 (4"*6>)5=+'NwoQ;;GQ%Z888Sewe-0? ooldhފo,/)JOM +puv431PSQ{7"BX~^.N J-=kY=HOOG%jhrcqB"btjT4u L-m<"S3s J+j뛚[;~8vzP;G^\ZY[٥ڏ^@eS{ZV@-' KHJIjU5u M-l\=}C"cS2 +*kZ:}᱉ɩ3ΓW66w( jTi"QHopppp}8kSEُTk~tH}pf0iP[]QV\dokeajl + +|\4tjj/|NjϾZ*W~uPB^NV^QYUCKG??S9G3)nH.S%\~?vEīst|g5ఈȘ켂2teu]Csk{WO/S;3.-Hd +`rN;pjA w۷AR$07ڗ/ t67UW˞eg$DFx:9Z[h*+oQ{᜜$Z>ړ'=S{S6`QHˡuj!jQ|"bҲ\q뎼o@PHxDTl\BrjzfN~aIi9pE"_&V(4:C}jx@ E}~L-rk}ɠ(+$2YeQ;njrQsjyQ|gE$ jϞgQk`djnicx/4AtYE%O˟U7uvOLNM/b"yJ3W!jij767Y~`ڿ@Oڿط͍uZZU&F]! xvq~nfzjrb|ldYӒܬɉb tsv4712TSQR`Q{,D>jyQR2/_~]%UuMm=cS +[{'wOS2s UTV64w v]Z&*\:wM폞OR_6;o{έeШ2,BvIQAnvFZJb~>.6VzښJ +wo߼~EZ) qZ~i.j}}_C[M)ZA!QqI)sljUյt ,m\ݽ|""cR2 +KЕ5uͭ]=ãg082B7\Ԯ!vϝ=}qrQơ&Nxfa~+Ã}=]͍u5¼̴ԤȈ _/wW'[k 3cC=-uUemjd$EEjOmSYڋ/K=S{|'!j j%!j/\rƭ;jZ:&fvή޾A!Qq ɩY9%誚Ɩ^ڱɩE,O W4:svZgevssc}vIQWD]hkiBd&'FEz{:;Y[hi)+߹uڕKHKA +AԞlj֐S'"Zۋ-kajͦvC7LJY!pׯx@_OW{kSC]ueEٓ쌴ёC|<\mM t5UF=VVZJBLTXH wGYM큿G>njrQyQR20^ Qg`ljaekWX\ZklnfS;ᗉ4:cvv?z4 >E[P [ Sʠ jxfqM`OWGksc]M%0/;3-%)aL@/w'{[+ Sc=MuUڛׯ^Q+#%!Pˏ=<\P{ +VPHDT\RJFZyEZ-=Cc3 k['W/_̜’rtUM}cK[Gwo"'+T Q>0M-8 s׭A֭}}k!j uL$qXڙɉ*tyiIa~NfzjRB\LTDXHu2")ԙE@-VVQ]ZH- mE-E}P8?7CStj{;Zk*J 3Rb"B|<\l,L uU%%n\r9ZaZ.@a:Ѩ݋Q݇P{!@-'7/1A@I&b2r +ʪZF&V6N.^>A!Q1I)9%eյ M-ݽG"y:;F- (lF&j`0oƎMv}}muׯfd"ar|tdxhpQowg{KSCmueYIa~NfzJb|LdxH(ړDžpsqjD=PKk7P]=LjiPu=}bx)9Ee5 m]#S +[{'Ww/_ʚtj&& $eZLZڵ5dnZ jYߘ$=] u5%EYIQA^NVFjʊr2Rx1ѻiԞ= š@f-=],nrj3ݍQ3|8/_P+WTQ306upv MHN-(*-kln>~/G&$9jYPK-``0 ۂZP˜ڥٙi +0}Oj;ښjK +r3Rb#B|=\l-L 5Teڛׯ^xV'(ϷnjG88Qjp"'N1w_/-+ghlfimWP\ZQU[NL/.-QˠvPnBja0f:vI@ B&NMb>hki(-.HKN psv436TWQƋ߿Ǡ J-7'ǑP y+jʤwZ^cB€3joܺsト_`HXdL\bJZfN^aqYEumCSK{'`phxPK s KPj(بHFi!0 ';k7R f*J-ŅY4Hv45VWd$Dx8Xh*)JKjܺP{ VXH/JLj?mjS{P˅R+($|¥+j$$eU5tḼl\ܽ|B£bRҳr K*ZaԎMLHˀZE]c&-[j`03ڂZLjjYPQK"LNa>zmmj,+)JOI + rwq271PUVCvB(\tj?Sv/Fڃ\<('STV5025wru +MHJM/*)klnm>}K@D_XԾSnPPHuBja0GaRX vx ]ZS/?{ +jomn,/)JOM + rwu2752PSVˠ$J-?/7'{1jw~&?}PjiZYڛx)yE5Mm=cS +['Wo߀Ј؄Ԍ܂涎ԎOLI7,ԮG- `0؟쬥SK,Ծ.P)$K'tu57Tfg&'FGz{:9ZYik(HoԞ= űRK}@_Xm,aC-'Q>~AB^GK+YX98yxED%$edVT7ut2$,B+Z -X`0 YmAԾgPԾSK&&vw4VUeg%'EGy{9;Y[bJj_|!1)9%eu MNj)3(`Ҩ}P_)k\373 +b(15Mz/a +].Ksd9ef=߿̳rQZZL-3crj aQP˘AԾ|΢Vzc}mUEiqA^vF:5)!6*"4(POGS ҅j@#{ojġvN>#N:sP+)%#ohbficHq MHgfUT7[; >b0g8ήPKZSp8'ƋZ"jgԾa2CG@j:ZMeŅyٙ_oWܙS'Ԋ۹CJ통LPM>R*ZF&67oTZfN^aIYeumC P{=@g/CG'djdj08Z%292ӌCϞjݹm75ɤ&'EGy{Qm,Mu4TUe$%HaSv3vZnnYv_`0v?AҲJ,jMͭl(n>~!a1q)|Dm]CsK[ǵlj_!jG!LH-Q;OsjWIpjv|k9#jZ&vQMkm- uՕe%9YԔĸȰ@?O7)ZY@BVu'@[ԊjԞ="-k`djaeF/*)klniy NPKZ6PZ.jpuE-+Nj {Cj;[j*Kshi)1!>.NVFj*JҐg!jnPA_o9B-~݂{R{Ӑ?W4 M-m]ܽ|Bãb㓨iYEU5ͭڛBj> OL2ojjcjq8n]Ƌ Yڷoɉё@ڻoj[kK +r2ҨIQ!A>^.zښjWd=}QHb"-χERo?;ơw@2Z3 k;gWw/_@mDTlB5=#;uM޾!D9CvQC[kPġvD 1}ɦ:(-.H&%FEz:;Y[Ρ7~D-:RVP{EKZHo@phDtlB25=3;EmQ#Dm둱A-.ciq8neIQHmWG+QNMN puv436T 'DP{P+Ϸc"k~M-Ok?B-?Vh_DjϜJ)*kY9R\="S3s +*km[wj<{DNN1!PZDGŧQkZ2 Zh-v15 }B'{wnjM eŅy9 qaZoW9HC+#?rSuk;VS{)Dn.NVFj*Jlj#jۿxRE6@-?Z1@j_D*uprqGjiYEU5ͭoԾ!jO6p8ܺj['D7Sڑ!@KڛRHmFPuwqr Q+ x~ڃZ1m,j7vgv v>z鳐+ګjzƦֶ.^AQ IlHmED jgHrJgQ[ +z8;Z[|l8<3A!&hTR H^AAKRD)"JwE셢io*0Iyve0bf~9s̹eFkWkij.^8>ԎԎRje8Iit.jZ:j-:8{Z6#3-*.)8Ez6icsKk[{'vuuj{Z 0j{ =]]ZRP{:TEYIqQA^nNfFjRBltdXpP=v:9nPƥv2P;C@(QjRRMC[g=[LYZ:8{B(ɩY9G +NU/Sjj2VH-sjũEi1 d&1k2V@-skj^&Vj jbya!AZOwWg[km[6mXRH JVAQrrR;ɧvvK7P?($<&=/!PԾb}ݗZVZ0Lƒ@-c8j_&JC>%'(Yi q@9K:J +>3کR;R;ٗq +'E]$ojjnEjGe>_xR{C'@v%7@mww;ڿZ 0YM*Ծj} Զ>j>P{R{0Ciɉq@tfc}B&P|v v$P;CP;LگR4Ey4By -!Ԫkja5#:^>~@mhxTL\b +(4ڍ(uBj_ LH-al%FSBHm+KԦ$D~>^@#֌v:vɢjMU(گD6hjK-VjZ]}CcB P/'fǎ,-j/]!޹P"N[0hԾBK@mUy&DE~>ZG;Bnȡv("AXoOjWkPkaec 86P[@j/}6Pj;Q30z a yG{}Bm:~@G{+ 5WqOOCMjUDR^w&?,SjwC#cR3sbJ9!Wxj1 d(1kEGBjϝ(=Y fg$DG3n0dF?DUBǧk?Pj')N§wVK@6BP6,":6>)U@mYEJmu ic3R Rj(̩Ej1 d~en-R Rj; ͍Oj)5Ք3UejSc#€ZݻZ'B6Z@|jNVDA@ן_gjjh^KBwrjr+(*.)8Ez]! ̩@-+-Ra&sI̭emR{vMj +rs8j]m [(kWki-{vBm|~y`aEgG;I}cgOUj i q@\@Jqj~~;ɏbS+N +(([ v > QCY'J޸yj"aMm?޺yOm@Ciɉq(ZZ;BVJ:J +3ĩP;J^Nn(UP;v9PI70&ZY9:y0@i5=N*=Ҩ0 V=Rjj]jOK C@P .gɡVa(> S (ˤSԆG%j#VXjPjZ%QۋbzR+ږFJK@mXQBmJb\LTx(P'eYکR;|hNa3o%ZuM5,fV6v.n^@mCm<6R{R{KmM.J-sjZ 0j[KR$6PPzy8XԮT'.Y`)@R746Km6]@mI-+-Ra&IvP>B@m:6/&ƆRUԎL*.V6.;O-,-̈́Z.gfRj#BZ_'nVǟKɾ ,Q#d#{dԐ%ˤ$M#k$IdF̠3~9{ι~s7||\⠶;$-kYm jNmGImWIm8Vj'ǩ5{NEM8(+QѠvvvQ9gũlTQ;0Nm/ImWImԮ Km 퓩-ӠwLj jJj+ j,Θ) DD_ΜaʠRR;TP;ؤv@ j{(I6a6jbdj jX+hP[#nR;OP[AP,FJ%"R!]&mQ[+gR;]P[cP;QP;BAdjOvRvJiԶvP}%{S{jA-&ÆUTQ;N|%"ԮtvI1jTVZR{;{JjwlqkF=ҤI)ju];떄v5WvIb;S{ jϕԞbR{--=pBv7''Ũ=?N Ծ^]?PIPKDTĹSI.A5կ{P{CcԞvS?g۩ӤvD٨ӧ@-QB?1jLG0Nn[j׷P+ԞW*jRԎÏ>~iPMIjZ"(CߒƠKI}}i8EC+Ԟ4\BImڛ> ĨZP]}PKDSCCwگc~"8:ɤO]# jwJ&Ljߗ~{DDO%Ծ-7;(; j AS;;n+IjQ>"}j3>)}DQ{"+Xݠvwj)jORϤVj?~e_(r~%̟[MjY=yR{,Ծ0nATA{jV`j[I{کƽ`>k*jSnEђSg)jW>6|tPjZ"(ڟR;|cg jOEfk=+Hj_uP+DDE^PjW$^QW%XIm$jhF^ڧݨ}jȚ7jT^ѯϥI jr̩S\QDD)qj2(js27 +j2Y>S\j\Z~JO.1ξn3j7hMH[vjyQ +j"]d-wjJMڍ+vQF.HM+ZykG^ ʕ' DDRv}y‹^%] #LjOV5YP{砖<>9٤d#S[ +SRjvk]i!&8=R{zQ;yiY@-eLٳ$ӦNlv+=^n0N>vvePKDBRI\ALOSɠ0;kS[ DD6TԶMPDDyy/Amؖ볩lZ(- N.ڍ˲-$+hM Ծ >RڡR}mzcj}-J#Ծ+E ?H-@k).mXj)I.9#ͦkS{O[JR{R.SE.kԮKKI%%I=R @NMSۧ'OM!j8nAj+Oŵv&O76imYj-Ծ;nR ꪥFR{MGjl ٩fԞّk"-~2Ԏ*L|j/OUS;gwvΪݸ =wvi|j/hO}#oג?՚;Ry>oljo,LiIj)Lve]UnW9w{h1u9LjtEjjwLRe6VJ\Y󩝫Rjͦvˊb6bd~#NݷSd1=$IAԞ[1IjlKIj/JM"~Ծ=9ڃ +SiJjΒERRiIjLR{rCl^MM^] KXڅR;Kv$DAj/L^4St6w2Z -N5|j_Ϧ$cnjz !ԞjO Q=;!>0jLjMRjAj?/ohF\j?lKIj-J%=1{yjRAĒ\_|='hURk6?vB&eSS{;(R: SS@Ajіڹ. 3:I婽(;F]2P!/hV)-וG S{!s==SxM=#ځC_ݑڇƌ}IR Sg.ʩ}BjkOmݼ4Ԯ*ݼ-{dR{HO)Mj_N;7|jIKjBMrIjWS{C6N*KThǢNʦvsOޛLj xy.vvˤvLj롩]&52IvȤvljNR{j.2,[3c}(SRzS;rjGgR{gZjΧv۶v\j)N<+vZ֘ډN-H-@s).m8ljjOٯ離4g2NP?$ѨQ1v1c,1H;RĂ"HDV*X@E셢;+*kfys=re/rj7քyک P.jHGR;Tک2jAQ9j3(yjSjˑZ ðv]+}*j38jF˨u.v!aS}Q{P{K4v@FVLIbj*3MoN-ZBmVP;i@3v#PIݽ/@ +Bm-?MH-a%I0ZMfF2j7+])歠ۇ*jgQΨPdkRRa)ZBK=QjZ/yjMM fjFנf_#GjSjM Vήn@6,2&nGc7n*%OH-aڦZ:j)"jO0j) 0ևQ`keinQQ;f#˨~X=e'Ԏ+Ou@ڽ)iY9y@ k5QKEj1 ԹS{P[YqR{Q{PGMIK fԮkڱa@m}RQ;&64&ZX;:0j7aRjO!^aީTFmRa.V R[ ^t¹3%nj׸8;ZYj gϜ ԎSB/e@FOaԮaED'$Rj3s +( +.jR\Aj1 ԩQ\E@mbB|\tDXpPAֆP;_D!RjAPj;uQFNZb +j]L] + GmRJ*2jfjZ ðl3ޣԖQ{ /PD eԮrsYN],P>tj#lkjj)P;c㹄ڥ6Z߀ЈXlyjo)>Dj1 _m!\Bf]Ϩ]foP;x +k+FgڿPQkQP_up.$1jFDLܓ?`fvnוS ohlDj1 ԿmlljQ{8Py0uҞĝQA[ڵkVjrNC"jQ?@J +v S{$*P[Q[>bI}-Pۄb[jj_Kc>Q[^eԞjs38jFnĨ]A]B53Ko 8js~\DBڟuL1kyZkeN@뽁Z;wQj3s ]@'@SbcJVBScF]/^8@Q~ji%ΣN;Q^}40jv]ɨCݷC(JnWT婥[+P7w0LMSA-%L-P[Q~䖘CY1Q!AۀZϵWv֖"juȄPkIuj=7mAMQ{CFm/8j_)0 S$J}7d9޵c{LdxH-ZW֖P`ډ2jЏRCZMmJm˨q. :89HB}ɄO5R[]S{_BmRa kk)@5c<Ʉ8ڍޞ@3\VOgf"Z1EvmIڙ& jZwF_`HXdL܎JmzVNP{Q{Q{0 kRj++0j\"Ԟ:d$ݝ@ j<=܁ZG[+BLEj*<jUH+C+ٷ߀#GC53Ժ^EFj&Pj Sg]"˨} y36!aꕄڦ} R[Tx /'6>.:2,8]j8jtcF9foBm7ev۠Xn{Q;R;Vv|3s +[{Ggv>~aq {RR3"joUڇ< Z 0uYj_s666xjڲ"jeg$M$Flj׸Pj-Ξ9M_O7R;|@mOԲ}[P{M@탇ھQDS>jgss|p8Ak%P;7ǜԾRtj>1> +>|pޝ7j[j*Ks(iɉqё _oO7gG;kK36*c\jw#jŶ j7}\j.VQCRz'c'dUNk9 sz#2 %چ6D!=}Z:WDj@j18'x-C< }ƥvQ{6R[KsC]56'+#-9!.:psv039gpVie9jwJK@ +Q)vǠS-Gr +JljϙZX:8zx^ MHN/,)khjitKcD}R M-{k18'L-GKHZ}bltxhC@mRxἷ)Z%!}׈Z)}j{n߶CR +PW_wCjeNV?}V aQ I9yeյ MT@vHmgW73&!쭝e2AE.Z&svQP;ɠjYvuj;گjM eŅy9I QaZ/W'[+ SsgϨ> {HW_&u S˖ڿHB"Z @lj8 +'Pknek  OJMfS[DmvܺsQKj"jp8`]Hm/ޝ[ڋԦ*@mA^vfzjR|lTxXpy/wW'{[+sScC}]mMuSJڣjJ jE>PڿOkPţ8VU]S[WИdnecN+(.o^̥ѓ^Z?v19EvQ;ǣvSp2CNdL jiOq mԖBj))I1QA~>^.N6V$.'ݵ2ԮcQ En*m4v!'eOij-m]=}Bɑ1q)i܂f@7 jFF'SOq[;;ˡ }ávPCSё>@ׯjkK +r)i)q1 ?OwG;Ks Aj$o**"REԮQRM%R+ ݳR{0VF^QYUMCKGdficBKLNdW56Ajo޾{R?cQQ M-{ky.,[pk iQEvR{훐ڶƺ,JZrb\t$9$Ҍdd(=rQwVH-{jԮ8n`QP+$"ELQCc'eUԚYZ98yx#2ru KW>FCjZN}[p2S@ M-!08,"*6!)5#3' +GI"`kL"ZvH-P;MvAj:f8ِea/@;-LݧS*N)EJeNp{ ; i ty y=Ԓ[I(E D?O7G;K3C}-uU%9i;ԊAܨM˦v?/F-/_JH)(kYZ98yzB#bR3r J˫jIM.޾~a +FLjPj?lF-f7J..͢ia^ڮrk(?7+#5)!6*"4`gmiflDBzjqljݹ9QjdR{ )AIEMS[7 (4<*6>)5=+'ϢvPKB]|Qvljᬅ`FIA-:jVWjaԾ2fg&TFب_oWg[k 3c=mM5EP{:ړQj؄ڝ߈_P,jEpG޾+%(ZX:8zxG'gUV54j>~WZ*}P;=@Ȭ]Z^(}+0 SqCv?o0js驉Q:uPgO?Զ46UWd$Dzy:9ZYjk)+dRwo=*ِ=֩n砖i>,C=s¥+xYyEe5 m]#Ss+{'w/_ȘĔ̜Ⲋچn6C#TBJ-s2]w.Bka0l+ sRN-2jsZudMmwg{[scCmuEYqa^vfZJb\LdXHF,^ʥ ԊD +AM-sԲ)Ka-wjAEZQ@S(njeU5tL-m]=}aqiyťUͭ{Ծ~34BMLN08]B]CI-0 Wh#iשRRAJ(22K@Guw[IUyi qaDOwG{Ks#}]- UeyYi@k(NjE9eZ_#?aQ˚Z^PjS{뎤184":6!95#;J> cS3EȬ]YAf- g폾 Z][]YAF-FE@FFE 6kK +r2Rb#B~>nΎv6f&:ZJ +r2ҒwnS{ VHA~^@? gڟ3C="*&P{2r%uM=Cc3 k;g7oʚ:RS >F0QԂY Eg2'sj0 ȅZTZjQ P˘FR0jj[Hu5%EYIQA~nvfƆz:*J9) @ϟ= =RǢoM6neSV@H(P{4B7HH*jzƦֶή^A!Q1I)9%eu -mڇ>{vJe̡2g%0kWW7Z m$ԮjPjQ CSG^x㇀Ɔʲ_/W'[k Sc=mM5EP{:ړǏD gSP۾ڝP{V'~:Je jںFVN^!a1q)i9yeյmXԾF&&gs lj]fZ&}/0 qLjF-=@(225Fꊲ¼̴ĸȰ@_/wW'{[+sS#]m 5eE,^m6Gq"(|6v7v:0j|IaBs.]A+(jh[;{"2 +K+jIͭd@GOz_~34L'ffo1jqPZh- m>rQQ"vvfjr|N j_>y^wT_[UQZ\Ltwq271PUVKj]tZ1aaAZO݃Qk_OvjM-b-B-AZQ@S(nܺ+)-#ohbficG MHN-(*-#5;zX S Yp`0Vo#ivuue5jTڞrK(?7+#5)!6*"4hgcif'~!aѱ I)iYҊ֎ɩY1izVN~ap2G )4:D'pnmZ@-AZɡ*Nv0Ǧvx]T4%1>6*",8H_W[C ;n\r VM- +YԞ`S{GS{KZaQ1 )iY >RTQ741spv OL~eIYeu]CSK[gwow?|[,aqx"B3L-HCkߟCO=noomn"Q S EARHD<Q;woG!j{;Z+J^=|4I|Р_oWg;kK3C}]- 5eGj/JKJ +#ԞR{kP/x=gPҲr0oކUV346upr + $9Yfv^*k^7utP;] ji *L-;k?ol +QXˢd-ءAQˢ_EEvɠQ$~8ϡvhMoWG[ꊲW/ +3&=~`kmafl +S{Waje +~AIj}GjP3Z]ԞC + KJ]x*DU5u M-l\ܽ|C#R2s +ѥUͭ]=}C#cSӳDյu.PnmZ@-aAZԮ2e@_OWGksc}MUy) 7+#-5)!.:2<$@OGS]UY}!j$DQjWljޡ;ԲRk`djnec_X.)kljmfS;YD2Fg@BY Sd&P ;W=noomn"Q S G*Nv07âvx]ThocenjdĥV^VFJB\V\jYQ˥J僩ZZyZ )Y+nܺs#%5 m]}#sK;Gg7oЈ9yϋ^UV54uvBԎ}Ǚ%,O$Qts;ֲY vwPԲܨdЩ]ZÃoz;Z+J^x491>&*"48H_W[CMEу{wnݸvD4By!D-gS{Ej +IHI_ġVQYMCKG7 (4qLܓgy/_UTֿnn}304P;=;'T e-Z(kxY gZBQˤӨd8?;=Q;624𦷫u}muEyٙR< pur031PSVܡ0BjO=A~[ZkJ)j +j%e j^yʪZ:zfVN.^>A!q Iiٹ) +@$ShtD-0Hn"YˢY ;D-M$jaj][ei2.c`j''!jz[kKŅYiI qё!>^.NVƆz:Zʊ߽}2ljQgy=5jHZ6x=Ͽs(A!a1qI)ڋ*(kj[;yEF&$gK+kZ;G[,aqx"B30؛Y vGZj n~Z_e2T +a0 s3};:Exz7 +ɫ(t&b{{wXz]"!lϷЌsMǺ*913!}&*"4(P_GKCUYQ^у{wnݐԊ n&E5߁3'QZZ<n.6VFzښ*J +r޿{u@^XH^fQ{ AakeT4uL-m<"'gUV54:$@U&e{JeQZZ0 v"O-Z0{tugN^]^Ծx%z; uՕe%9)I1O"‚=ܜl,Mu5TeQj] +Q{ڋ?$[R{ Z&\<"b{HV^QYUCKG7 (4<*&.1%-3;Hz6=3;7B^ߠl @-խ`03~fjaڗ :mwgF^YZ~651F"vu45VWeg%'Dzy:;Y[hi*+>zpέZ 1QaA~>^,I-Sڿ0FYvjqjOZZj1XP+%P+#ghljaek[PTZ^USFԂ]XZY]ޥ`k_}nk[ `MW`j4Z@`_O 7+#59!.:2<$POGS]UYANVZ +Pn@ԲE5߅3P{?27/ $~J*zFV6.n~aObRӳr K+k[ }CD/˫MFcn-B־aZ6j0 v"Բ"2vNlS6ɫ`jϟNC}ݝ憺ʲԤ'a~ޞn.6VFzښ*J +r޿{ui)Iq1?/5=}=!S{ƋK^PXV^QEMC[W7 84"*&>1%-3'H[;;7A٥{Z}Z `?_o^jO/tec0?7 vjbDhoij(+.LKI puv431PSQEvUR\/,(Njp_aԞS{P{Z. ZQq @[w=x$#ohlfam[PTZ^USF=څ5=־em;0 vԾcM[tjS{L-Ԯ./-ё.B[Kc}MUyiQAnvFZrB\tTxḤܺ9ZNN ߍڏE=PJ-'ZZ@-7I\FSPRU306wrq |_TR^YSJ"j..׏FgBka04i> :hj+ˋ`jjIġNBksC]MeyIa~NVzjRBȰ@?OwG{+sSc=MuU%9Zi)I 1 ?ԢҲSBYvjYړcjo-7/ $~*(ijiN8.5)ǀ`3CRJ `00`l0{g{a0{ M4;lQצjF'6N\.GOoxN.nl/NphDtlBRjFVn~QIYeu]CskGWo?7269=;7~w=(k7<}lW7=Z`-ܟŔ{Ϟ>yE;g'Fxޮ憺ʲܬԤ`ɑakcE57524׻xD-J$4 +$ZZyZAʊ#QjOCԞS{VDcTpxECS{Z3 +k:Á  + OJI+,)oji ML_Yd+w?_ڟQ S+;7WWDҕ!n_Og{KS}mUEiIa^NfzJb|LTxhP ӁA03٧V[SF"q*4|VLPǦV*!( +O$5ut/|ŗ_]26,wo߀Ș䴌켂5-mݽəQ>Xgc8k%k````׽ң9mom>E(oprqA^vFZrb\tdXH`;˙ioGYZ_/>NV#X +PVVNḐVN^AVh-D2%TZ"jMͩ4[ˍ MHJ/*)khnF&gP e~>{Z!G ZP ;yS +BiK{$jBQ޳]O-ӓc#)%=3'o`hxtbjfkoܼ}P~$8k{ւIP&Q?j:wo߼qե+s3SC}=-MU%y9)1QA?O ӁA]<N[KJ$4V"j!jajʊ=JZYQCԞS{V DaTpx"I Q+Z3 KΞr  KLN-(\^YS?[X\d+kۏvY]Y.k׏;mQ';77VܻÏŅ`owG[sc]Me쌴ĸȰ_ow3ގN03D-D:EDT0($Z1|jOV:2U<@2V $UZcSs*Ɩrc{s"cRӳrJ*kZۻzC#cS󢬽)ڽCYӱY+d-؉J{Lt(jQr_Sc#C֦ꊲܬԤ`ۍȰQMhiUIЈ؄’چΞ>KW]q;0k +Y 8iv?jBQZZnmBQ{׮.Q;1:&*<$(ۓt`Э&FzPhiPȪDAi SGZOL8k!jh̿ٯ_%}'DDYEI pooEmvmkDwV3tngM$!LCgyϋBTF6084<*&VO6gUV54vt O9qrjfnn&.k6hZZ444?vUڗXi!jSV1?} s3S/?31>:4PW]YVRnH'kbcC}!jAjdR㰙 :v:u0 e3])TBD&W{q/ ($<2Z&&efVT7w:}+W篽Xgka-h:dK,Ԣ֢TZ<Xj_BԮ>b]$P'_:}҅sO t4VUeg&%j0 +L"ARjԺ:u JߦJY@K-l-L-JrX*W + R4Z>Ő_TR^YS70j_rv|d0/'3=591!^菡M& <ɠS)dW0$D):buX+Jc0_( +w~JUV[PTZ^US78<Y{irzv`Gkb5c-Z<nioآ|0TZ ҚQ w-Q@Kj;ZkK +r3Rt82:2,$(KB.|.dШZSj₡+;I>"xk:[Lљ,/r`dmXDTJ'ҳr K*[;^] ֮YZ'Cih\_jo.@^B&jzpo +Q{cÃ}=-MUyٙiI q`3jqIB>f2T +ٕ(-L-QkJB.RkZ +X+Idr)A!aJFӧ2rJ+k:{F' k0޴ok\Z^׿־0k-ڲ mO~igYZ<0ҾS JdueyGo&)ډѡƺܬ C^ըa!AԺ+2HrXLJB ZG 6oݾcnyemsݽ~ZDYh-ZZddddM,jQiGPiBilV e2j.Զ6{EG4jwcnB}g0jWԦ1j#a1lj ;[ 8Y]Sc־X{emk[nЬB# F3ekvkIl|vʥbJfFVPAFjX@}ugƩ] MKINrV],j}vFM-yXem(fmtL\|b(5v랢YhvcmIyeu]C#fM>YR &3eف>:cͣdddd}[K;6p@irK{onRfAը>@m']ڛ uՕ%n=L=ڍ4jZvjTQrb|\Lt$Bm(AP;)k #bb1k5`6\=ڋn߹֎X+jNo4Q+ZKv[KbKFFF6yvN-*jLFNV˥wn¨S}K0jcc"pZ6Ljve+֢k  +#.uck,pY#*Vg0) Za-jȈcntk}l#K+]Q*-PZ2 :Z=\^AYOQ KFE!li!8zK K˛Z86,\dXWdm^aqiEU Uݽ_h숵Lk8Y?&o--lidC;4jqJ{onRfAը2Eˀښ<_}eZ07Bj9ǔvR~ k֢Ԇ kcS'6Oif!UVk5ЬmKrR&b Bj>tZKbKFFFX6(/>K ťY-ɨiJ\*tuӨmi,+)G͢Q)QPP+BjqiQjå sZkЬ]am(fmtL\|b(X;kҬ=XWP\Z^USJG`O&WZh,6;j:fdddd0ni:QJkY(ѠӪU +O .mku@mC]MUyiqA^n6BIQP*JJD v!\zjK-Z6~8Ԇ I)iڕ,ksYaIڜ%e koܺ}nW"+U`2SVZ`-ڟPkqk|%%###M?9V1\aTڟ}pJMVRˤn@m;o@xP[QVR>$?j׳]I6 6R(Ǩu6(֏Zgi=R;f|Z?`!ZXOǎWgWV54^²G,JF7h-i^[;`KjKFFF6yU~ҺJ;?7MFNV*REK uՕEy|uǏM B@mS`S 7ֆaOk3kO/,.^zZ+*Vg0(hZ[lImȦ?oA2EK;LFNV)>qow'ˀښܜj3jFmBm|l FmjwX[[Ԃ[+* j층ZCڑ(ok}klImȦ3o%.v12K ť,VRˤ6\ږkZ@mIQs_#~~a^P +P*JƨQ@Z&li=RkQjyX1kw~w}k|yYW54"ֶZ#H帵zLYqk֒ڒMq>JD-.2 z\ZT"w~s0/7/OB}{{dA-NدjGÍZ|j1Y֛fkYۛ14 +5+pBX*W:Xf-bb;ãs#֋- ]$ZiQh#2**iZLhiJK"aq!a1$R|7jwEQ &jDRD Y־@{@YLNϠsry2BTZ:PkL_\Z6x`mL[.ܟyI-V^i %KsS#nf1 v45j5jeL\VZ,(cЩĄXG@!pQIOnڧ0YdQ1q2%`r¢QDTkuں]=}灵fBD]X{U?k# ȵ;.8Iv_ii'i] = VӪ+rI0ٴL +9%u(ڽa9}?j7>({Yk-Bm}@;OJNMˠf8|AP$ʕ*`o\E`Π^BE6Zo خK[.w _jhI{ǛAҢQJ{ vH;62r؁/IXo4U*\* |+7'L>q D>lԾ>jQj=nFç6dnڭ߀=BNϤs<^L"P55cCSK[ǩgΞ֚,V5<:6X;Z{ Aޟ}9ppppGhD w#HP~J{vyqavblt[-& mgNhkij0j5jeLRVZ"(屙9tZf:9%1!.$o;jGGfvGP86*&Ff8\~aPT.+* v`pdٝn5k[ہb8C.xI{Oi +ښӨnf1 vuuB.) +\IIKM"D=x (jwD[RKdY{dmtlBbrjz eb\ή޾ZpGF'gkZ{+aK-.@hC&H0?73=51>:v:l3|_oOwWg{kscQVrLX,rsԌĄhm}8jDY֓po־ZZ$kYBd &+IdJƀXqc텋Cf + +?{]ű68Bn w m^iƗJ.jx#6DZCMFIJK<.ɠ2)䔤8G#QJڷQ +nn[5ja>}oz>˯vY{؉xRrj`q¢QDTku M-gΞC5v1ٹE?kCf-6l=-xBnB i -6i=b'MD]EC[&DsgϜҶ455JLR.*)*s9,FvL>q=?o|Z/k7F/}m-k?S4kw踄drz "TZkxke%Z -.pYJrGi'È @:mUB.~~;7NH'''&E<vh~kQڗ"ڍ~Q!K&k77k#_;pdmTL))LɤL6W ()-**`X DuX{g֮b 7i/HDtwu67 @ZB&.+-l&NˤSHq1Q jڏ>xQ1DmjyLc?w׿1Y͡# kcIɩijV6_){$יإ,u;!eaY{hJ{o1h5ω$dΉFxF/^yY}vAeJGs3Ӕ' I;FH{ё i/?{"i4VWfgbc2iXH0D-!-b!E%\.!jWNi_9kM4Y(k[n۾64U[v bpcxIC>#eHG(i H{WG!K$' iB67TUfgbc2iXHpP&j%BڊcaFDڷ"jPk(kij +eɅZZ\OTgfUVׂ{:~X{Um7n!X;95=k -]y}m1~s}g絝eNi֍o^i?.mGV /;3=UTeDԺ8A +PZYZh&"Q:}ɬ}_?kY (kZo_?6LP&$%fd M->z$i电׌X a;AvƖQ[fnxxx+oag@K% #^%mijiK r2RHiH Ңu eGo*j_-k?bYk DbZA!`<&6.A_V!kwv=}`hD1(l +'^<Q ֖UͻhY{X{Y?Sap||brrjp"lvA[mn.sff)gvZ'%H ^8%͍ mEY HJWen."!kgcm1'vZBEvWj_-k@֚M,8Vֶv-3 r{e ZZҒH_I{Y#i +@x":*6:;:̔mQ歉Zj(kכfV6\@d&"60(8$L +%Y9`miy%i޶.c'k/W.X=X{V`-=l)k`Qnxxx+qg,YCRҒHZB; _^$=qm/)mey)H&łҰ@2j<=$n.N"kkceianfGQKIԨ}}Ծt~k!kYfKk;_(wtvqsY!ǀ46f)=kkQZ*l'uÖ [fmNi}_ՇV'i'ՒG=E0MKQ1rYMZZw7gG{ϳ䘛 jjEo6j4k!k7ئ+k[.O ;8:Jj_.kWg:Z:k|My em42*Z&#kJ4ֶwv2Y;LZ{a-Q؎녭ql5Ҹvt3&8JdҎݥEJ;$mowgFڲ"$mzj2HQn!qsqr \uԲ!jG7/X{:YքmjFd/;:onݶ}G`Ppim\B6'y}Ik1[j{c:8_8Ȓj{ !B;c{m틌3(zP컌K2{bؐ9{ξٳ*!B?fB=_}9"M ui +r^nz]F$bD---9e-m-4kWJ$RBhubslhmIYEUuMm>/r=XFBZk vZlf."^,wg)hiioä%mDZPH`H mc=ɑ}vϮikk*Jٙ^aVV*dRH +FZZg-vj-ZX"+T4`2[/,fݸim?)krv [l`ՖO\/,wqfqg@Nک^ Bi OaM6MRȥD-*-ڤ jeCH>gm20kS"D&W4Zb;_FVro`mX֎k^ì{rv撑-|»bC{B&-&@1(?"m%m >vp?#֮Y]Y^ +yNb2i5*\&)0j)iMƣ$jEY Z`@fJ"TFpڼ";wE}퍷~9ֶBk{ѱ `- [Z6vCi[9Ҿ޻ok{w܎K[TMl렴 +T"QZe GeY*KrR FpyڒںƦ歈Ͻ+[˴lBlNOw [qlqmnYo1pg@PLFF6_v(K19B#7on$0iI ٥}CP_W[S]UQVLz\l4R!J@U+YiMJ.x/kvUP$ +:M7,VksX{S ~H[)L m!`$ւe`;9Im ?Qkmgl1!_SF-HI I I  F~ mgG{[-g~HSGđ6?Hvdk*\&@ZMxv}lbւ2RI&t{|YkXkwڳsZ; Gơa?"FҖ7.qЧBFFFgyew/+G(lB'i\ GPڞH{Ё}{v`]Hvd4*\&Ҧ`ҲQڇ$j瘵 0kYkA֦ +LTk:l9n/6'v6nڼeP~=}܅/uv G!`-[Z*lQlo"ijpz7yKFFFhoL(\geB'`Ҏ#ᡁޞKퟷ^8r4Jݶe֯[Hl4R!J@U+Yia&'S&D]Ш塖c- &k,k"`\RijsL`mAQI|=EY{vp£Z_~es +(S(_QII;<8 mҶPҞ`=#;omnjl`--fenf1 :FTȥ1D-ZZ>ky6Z]A[Kg-V(KdrJ56MɃ֖Wr?OgqUQ$.LwM{X!mNNQUUiӽiJ =1lBBi,U snpt>F'Ldn>|*a?[mUU eccc܋'(tvɌsV,B ^'*sHڳ ѹٙv9 m?-p>ikQҒ‚|ѐDNGMKKGFH(kEkxk5hM% +Y ffe  g"sEE^c{ÖOXm '|?BY)g)g^v1:? ctAھtH{H[WZ6hdgeRԦBj(6I)PجՐkfz)/oaqIYyEeuMm]=XZ8ԬmjFkZ}Qv*<QZ۫<7[j" +oEq%rcemk"LYdV,BK>TWV3 m\Zը@i(k%k:fd=`m@]}X ZgK6k;Z3X;4pyThzf s_JaM[*r +*սllll[k~Kl 7UKLs\L#~i m'1Vڗ8i@iiTWis@=%i1ju:"mJm6VjT`m6XkDkKUTOl['vlچ g"|خpac{Qv`іW"Wnzضb~,ŬvU-$ +󳑙pvltu!bi[Qړo%vUž"f%Q +Qբ^$AڍZZ Z6Xg-ZBbm%Z{X0Z79k?:ֶ]gzV۠t{| 0 e4+#9LKEeeJrЮ#s^Ah/ɡ]] I&Ih{t-(퉏8iߔKJ0H{ J[I-,7 mV4ը`iQbmhmLVo0桵%whS`mXov<^?=E-/-Ai=H)6]6YU 6YY[AkZvOh^5}4׉~ֶutu-a'b؞;/-E-boqEreƶ|qI2SbVY$h9h/9hEhBNF|^1Ei#Ҿ# G@ +9ۥ\^zmuxˁˋ+`W^666-;僣~߿)c ,_\%Az*  ZHZv!:'%mj1twvni?Aiy}-Օe%(ɠ%KQ*I(jje;vhS4bڜ\єW@Y[G=J["U8c m>k ڇ./mvavEQ]"-bpiqEsƶۨ'BXҲ\9K;KVQ+\DJZr3ݝ mH18J*EZڣD:Jڂ^Z$jԊM֦fffeckckABkK/!ke&5Y6xPKW]a-H;\rrqr+ˣ˳L_:::;wSI,,YYڿ$Bϯ]rbHH(z]>f H+Cm kұgYXڴM}nIk3k0ւMr`XmkMn[Oo_Cd..Y"0moh+zˀEr +ݐ`:::$w 2K:{; 6 Dh?^H&P8{݃}=NHk6i@T/i0fJvkw>6#3++{/c-簵o$XY[ ֪vw?DGٰ/,-\^KĖHۻȶeeE"syuEnd8=oE~9 %z]"hevt8 >wX;ͦV#V Vs&H9,-Z -ڽ{q$jj> }1gk JJYkZ%Volm0[690!vrjzvn~aqiy`{u-[7Aڊ%彅&n'Nظ_Ic!"gAބAU$gnvYmF=V Җ0ҞI&@gߥ}(nԲ֦f2W7ZZ+oT5Zd^_ S3slɴ}:ҖCg7qⓥf> E )3:m2h]Y^\La6]}=NŨj:yjSi_D}X4,vMeld!$$6'7/V֪4ZdNcRRliKr{eeM/qbc"gM +B|~vf:691F$X;ͦNQiښꪊ⢂(>#6;A!I+v3k k3SdmaqiYEVohRiuck[ea2a MMl/ Ӗr.E&Ll16r?D,,:dpZhsS C0i6kj45zFRUQVZ\$5iCici3{RQ,k9k֢Z{ih =-)He&Y7u,0l{DG'cS3I%Җ&-ˉ%M0?"c!77D&vf*69>6:I bhk1jeSCB&TV@io(1(ӄGrQI&v[DYZ.6++{/cY{6啒jL^ШTk:CKk{aFGF&&cK,e-[=-!SsWLGGG"~z0C(K0:=,?  v:6916:Iy.NQ+2iJ{!9gSqF@ڽYYiIianm-}*'O](,*)-M*MNoleֆ["mik-Ԗ-ˈː%:::WF97#2!K(3 Y,_A+v|tdx(|^7JZFYjjWkU%EXiOp֞>{Z[ MJuVohik7 ‘v +bOI[u-[-V.K.k.VvOvG +e%9mqvld8 ~ iMm-YljWjk$UP(9iX'ii1f$#FڍQZ= hmv2knemn^~AQqiYEF*54*Ulakw9`PtxVXl +jKpy26 EbeIfg٠M,ZP8äp9 i,fVR66eIeEYiqQA~^VM&m66I6 Kvkw%X6'Yo }'>:3r%e啒ji\QؤR7F"lNנ Cm6i 7EErz?=dXYY׿b:Ag!h#` "iz]ZXJ%e%ŅPڜsgN|J[oL'IE@]Uڭ}6ouqD{?@A$H=2vg$v qޫM6)Ph-t7iINtCtyG|^zoǨ*^ jjTsk:Nvdl|r +¹ť |zs%[6m묶$n\*.1++g2/|yQac1Y0hAB{ @O?xna&Ml9՘LĢPHc=i iwm{ieͷvk_g=X`d*#x]}!Қiua;619=v,bmm1˭-Ebtw{e + bdEef?!q )Yh?^Z<vfzrbLHڎ\[)ՐW"`uW96d( +~,k@W-/vvv־%cmIYZZlvH:^[hhl*ۉsgϝ_Lvy`KӖj-VKE"s1]L9{Ra!X,e5, Zʲg ϝ;=;=5QM xu4 +}iYZ(DFڷ,_4jڝXoK/Z6kqjZZBh&^H6[B ð=37 -w(nn"D\l.Q+7>>>b\7OW$,5V@)+2r;{Wp ZhL6ҜjL&5h8{=U.hi5j*qVڷ }}6vVZyk>CrR֚,VYp$&C#Ӆ~qkh{ms x ťRu~+埙rbYԲDYTYK_B;=91>:2$H8yUNj1Ai+*H{H{LHEk#ka=-S(+ԕh2[mZ E59}f,v6/mYmܽ'zRrX].cL<9|z% %Jwl~Њ.hΝ9=3=51>62<8%Iښh$>>߻.C?36V@,ed낳B"ha"hh'FGz:sY1iձH8yU.j1 z-V==}J=L>R־(Yhuzb9Un E6?08<2:] +i+j%ޮ%Br]® _>>>{l%g1E) 1+akߋβA]Ў tuv6 +}waZLFNQ#iKG}~SX!\T+5:dNWmjid;:{diKڮPmqx}r+Kąbt]ޟ$F +޾u2zG,,}=ݝmLkKr96d4jRQ^ +=^Zykw[-׭z\A5Z{W ̜~O +#VedEYYa9 gpv6)@{zrcc#}IIg7uI;_iWvRmy[[/rت[vnX۱mݽ}Cã`{6=Vpeo\.\%s ]o-e׿ݷ=aX1!+1ݷO=f=q6!gvtxh%$Hڶ$-'Y++IyXr"lZmv=C#8=`{AM-kq:pE\"etY]q_qqqqS%aX됥}o'iٻ^h/О@oOw6Ү|i֮5bmYېe- +}&lCEa`;l'N_L`kqk5:p!#u]Cogqqqq~YeMy?0"k5"g}g^N@; h0AEҾgv%Iڴ $mH[3oiWTsvMlmN-j-¶=ۮ^`;l 퇊m2mUVpxસJ.**oُ˓A2Y8{[M@vC I{8HvIZփV-9:S5K@ڐ[[ڬݝC: Kb ո5Vq\2נ:{#...n/ܱ^%aA:e|u_59l& ݀Cݝ"FH[x!.rj_l-mZm ۃGvv~v|Imry q\2Wev^߂Wy ޷+ +Ċ,)159[ُ3m?Hڃ.il҆67Eڅ[K؊|Xۨֆؒ6lq[`ۗi`h noijoW%s ]aW5+?wiaXk5_0ll4}G _$hmB6i\JK.Uij :-짰[¶6 V㖹%oXo\%s ]Vٵz{W Kߗ6svOW2NYYfVs!ΦV=C9L"i I6uF Fڗ kz +dZ Wz0aw-E2=!H@[-׭x J.Ux[}WfN/CC&VUdI/DYYYr!=Z$-CIÃVmi&i%]/ +۞Y־BrB"l9l[7g[mV6؎Xli+^!m7gĭց q\2v]cQ=[$+Uާٟ{2$ c-FYb3,!gUhG +-UhI65BڍPr5$+YҮBBE64bbkr*]ѱ$k̭[Vq\2eu]C7øJXܵ`0urf$c. -VUhXH[I[I[t}1B¶X$k9l-m li+~L"n"n7g[m.Ur\Qxe_W ]+ +bEby0 g/A[ +Z$6,mK3I[uu|>W]nE6rضڰMba;7l}m qkuB\%%t]⫻[~~)Q]XVY,1;cEΒ}g +-6 MVNZHѓvCBuKYZ–B]=¶¶|& i5ڼeo\%s ]aW:S\\\b^qyO' bXE(11 g?rABۙ\Ғ Pr$-A<]&lEmf 9a砭-s{vfƂ˅ q\2v]v*iM+K‚X%kE̲Y8{w6+h&fNZH[,UiM.ijzkm5Y[kE6RnJܱڞbm@[[4qkN\#.K貺5<...2|]W2 du쥋p ;{8;hSIK6BڍFZJ~H6a9Y z f/la7^9z+ +KĒUVM}m.@[%z qi'@ZMcyksaövvv; b}cXipyL. 2wy|>%[b&IX"Ed\lG,I*i7][#hLfiX y ۥ +GN1`j~Rn.EtQ]dW5gΛWV%c٠2 Eg?ghh;*iWV0iI; io k 6 9fN!`{Fi[i{NھCm)n[-Kr\@%xi?|ú蚅#W/$K"AYeVrr9[(h#0vv5I;&&JkmmSŰUl3UڞشiqF + n Eu]Wcq|˵59vtL,+ZeYٜ_h JvLkѰ]X\ZZ^YY]+c[IJSׯ߼EpI\&Wt]~|!Z툅 d,"k}oSrVyڵՕ%v&MZWzb`;.Nv¶n^ +8mo߽'no\s]T |ûɡ= d +K̾f1gSgMV>ݫ-C;vB7Zi5ka;>l@KEl= ik}qzvbZn[er\Rz7维+].saX2Ue#f1g_<;;}a A[A_vyiqKmLڱI{mg퍂qcj&lu=дi▸pA\&%u]7 kr|e_QX d#es`s,mm6Ю2 -H ֒6#k^a >,ax!l5mO"m9n-쭀K2b. +Z]Z\+sD,+Ȳ'GmC)iӤ=i61R*m%mS6 `.슼A߰?|>0.=fz}EaX5fOْݽ= K|mYiakvJ–Ű`زmܲns]TzyO>wkqisG# j ֘M}vxp";;[[YhAZv**mѐnma; N'a[cim]H۠1hs{Kq\4%vEޠo|>o3r^aX5gO]pA>CkvܤjŖövŴ@ִrA\ EtQ]vWnGVaX5Eesfg1h6ڕ&h%i'JI;^c{ٰmv]l9mw!mF,--h. +߰>7K^:|oXec YlYT6Ǭqv}rnnM5i/ul5V16-z}KಸB.2"/]v}>/{쁓G'bXB[19g5h!h vԤmk 6;S`m[5ikm#n[ \Es]TW |>߰/>kz`AX e#fY Zv ]vMB^[;@F/`mM⭂ +h.2,a>7|2sHחtOYX!Je3f6m%m%(Hۿ&l---k>#n.䢹.F{|~eO=:_@,ȊlٖN֥֒ư%l/26[6mmr\V ..zݫ躽 +`"+b"6g{:[ vJ홴.-lа NͦmV[[\WEsI]q7+^|>ŬݑWz"( *,Ƭ٬٠-B;֓Y{[¶`۬V J.ꊻ^|>߰~¹GWX06 +bZf]-C;Afh=i{z؎%a[a@մiq+Jޒ.䢹k[eoµG 2,Ƭ09sV}@V7BҎk{N3m­6"h.|kc ?:_ +bl@(+bΦΦA;GA[NmI;z^k Qؖ'l1m)mk-ƭpx+H.K蒺 +7ى ,#>XcDوYtv-rvŠ%h6B{+mE6m^[ۊی䒹j[f?B ֕%f1gΆ m 'm6v [vF6v]m[[WEr]R7Mkk!@:(,+f+flY v .m̈́m_Jm-".+Z{|>߰p{'" +ĊleVr6rv5ARҺ 1m-m3ښ ܲ[-"dZz͞|>0/s+HH, eVr6leho%zҶYmzڒsA8n[52nW|Ǘ JĬYuv.8m7uis?J1l{cI[v6j[(.Kv5^终:X OZdAY(gmmmuiqmBǴ}0[VUpQ\"u u|>ENo -%ȂufY~1h`a?I Zo#pI\"WUv#z=|]'/&f#ggKk؊iچemkZo(.+芺 >w%9=X"6 Zek̲g㠝4ζ֓Yl6֖pyq\EWٍMP+^4se\EdY٬-@I;ؚD{[66ksU] o`K\8rBcY09;C&~..m ښUn.K*ݘt5}>r|[ȷq9Ue~6Pݶif 4ER%I8{XlKgrҮRbkk[;eo/]TW 0ݹ<*^W27;ee9:MCKi0}[bۮr~VW7GWdW(J W4|͑l:fsYڟNh9i ~]rkqՕ GaN಍^"+Kf~ΎvöfmunMo/U]+kD;oj]LC)#YvgCIJ㰭Ŷ8msmOs[kp-k) +M_4Dd]"[9etҝ-R.7=m?O=ފ67%wiʮߖ)c =i$쥳gu^%[S۷~-[[[\J~ slu3ed/g쥳_}}tRؖ=2m +)n`xRc'*☽\=^:uЪRZmen漵MU5ݵjD4qj DTǬf9t>3bQwQ2ޚZ# NmaXYy̪~vvZJbj[\\ܢVJ`…cG25VGZY'vU5չprkz++[v +_)]̪. s+z+kVwm`+QmS(vگ=\[[[\]\] `ndEesfvK/b[[[\'awQ_Y/CKi^] WΤQ"tv@menUoMp$XC;o̮,}F,n[lL%UYB GhVVga9U+k2;YBXjkr{]x9R5f_=zjks[\ {XgvN~en:mW^Oe-Y-xg祍ɭjq /7Lgw.@ݹJ.pL珧+2KgwwphVV՟ր u6,.b: Oɪv .osgG r.=v x5lLN z>c,}]_[ zƴsgc:?kWo.;dzUz?PpI/f&Vxv0w^ܖhT`/~ى͌~z cV8V= :; + Mqfwwwb~pswY "~t2f>f>stream +@@@333...---+++)))((('''&&&%%%$$$###"""!!!  +endstream endobj 273 0 obj <> endobj 299 0 obj <> endobj 300 0 obj [0.0 0.0 0.0] endobj 301 0 obj <>/ProcSet[/PDF/ImageB]/XObject<>>>/Subtype/Form>>stream +q +/GS0 gs +1899 0 0 2169 252 79 cm +/Im0 Do +Q + +endstream endobj 302 0 obj <> endobj 303 0 obj <>/Filter/FlateDecode/Height 2169/Intent/RelativeColorimetric/Length 102674/Name/X/Subtype/Image/Type/XObject/Width 1899>>stream +HׇvFa[L.Yһ8N?KL;Ӏ[8o['Ѵh7j}nigjԉ&SLKk&"~/5Ͳϖh>4Z?S"Dk0WNө[$"Zt<#"ڙZ|jPGGD>tym]!"ZZ[ w5l#w5h-hnDD^푽JD4qmMіmw]b[5J[@;'"P[5Tm&me[?\"o[#Bl#"Z~mgz*Qqksm fhVmת̮+5"差rۚl;dmg]ψn +"DDAr ebq˸E)V츲N{[mktv5FY*1wJm[óc9;숱C:ѮTܢZ٬®@&w*m[@g6l"KB"oGۆmٌcĎC"eUmo4+kۚEgǕ-'"jTޢt+ ź-bw3p[mk٦M)3c"ToNܔҶ5KkhM";ks=!"v %7`ۺBh M;*/}9Onmm`6lllq[[0DDoT4Yo#nж5Q iehCgCf#ezhћ$7mmm5ZB%V8a666Ȼ<#"}5 p[-nJh˜M+u~ND4jN{[-nqh0 FӛDDfڍ(u""s 'My[-nAcSG6Bs"YWpn +\ۘ[mW+8+# [m"Wpdn +\Zڎb.gŜ&-R*b82766-^JcFfmrΆc6F6vXԻDDl\6c6-֮S1c6;gJdC`XW}"~Ct#p>G-`VV>9uJdas>DDs]O\rͷAYD6-k>$"Jr[˭CӶ֐MI;alY46vHGDDKl])7ϭ޴=8 +'8'Y;fXشs}AD47-[m4n=m˰eخX[h=ОjgCfXhi H+mȭhkv[mqAcS!+ qigDD*В:q-ۄcjQb^6pVY=gCf1}ND +sۀ[=n'^۪& hs +fCeBW/r "[ًS׉k F&Ѷ[ګjhŠeJ`CZhie)uZqo}nBmŴ=vl[6j&z:goHgϭBYXlxR&"oɻSגkUڞKmoxiǖa[ơ=V9{Ye6P xMs&["7p {:r%[7Jbۚi48i}h=*g1X1 kƮ/]I_M؇יk*n홝Jlr2lSN!hO$v- kƨ=25 +pݾ5FڞZlO +eؖT>iYiОh}go;gŜc)Ƥ~ќKܵ`ɮGpkƭvtkb_O dV)1 ++u9nͭ=Zsn*omlUNhA;{GY7gvjdVXk,h^eYltך+u +nqh{Gkkm ъn^8fݒZa?L#"y>f \!q{uam֛ylbm*hIhCڻIgݚ}uKVkƒ8OU wB\Kn>PuvkUضFE+N,g[ +Z=hw +g*g%fZdFXx?M3"y>f]&WܾVh{_il[x^`sm=#3d߲VY1+t$y_ͯ=,s +\m?o%v*mm)m;l='6MmYYBVkzU/Z|Ҿ +%s5Z\ϭ׶մi;jضR6?i{i1^Hg}f-U +bV*뢾&"jSّ +.[sטɵzv~Uqj6¶t+MZڣ<h}gze-X5moF-T;Xi%]Mnhkm{C%eƭ:iGzH@u6da)kUa޳]MK,js~&O -6W5ОBYzje%X5VoWtb]%W{qhm(7:lO|ln[[^b~V ڔ f=X!UHD4J5js=ۘ[+eZlaWmk4m8h{g_g圕JeXO? K/y|]Ez+VkZiNۏTcmM[MZ,CoS8@n6s!vZ1@ T@D@j9nĶ}ivb"ۢelm+Zۈ/H m*h'}&ucg8+%Ȓ$Ugy1RξklwyK}a%r)WEnNoa۲O'؎!Uƶ䱭miضy~#IZ/m6MZEhʕJ.SSss YÐ ,  U{.l6[.hBWErQpupKqkضaJŰU؆%kSk$֦خ7_H-&m%m.{κ 2d, } M^]M}fk|"=.2[[ۤbHi l ma]o })ikI-WΆEgˊY, X5jflku>~l1Bo@ד[e[Kۙll2`[l{¶խ](-Bۑڡ hgڹ9.g#f,KIJ"k ~hlͺհ,B.F:nfn!n!mRmcNضh!i;sRV xv~^KKٕ٠, +qF6i0i.i\Ҏs= A{lyY;rYYdV+ ȢDU\囼+cfk%,<8䢸n-q{g1ny2hm6QöZ Ya nl V6Gr&vQҖ)i]ҎEKKG!hO<f1fceY4e_>f^E{yY]2pp[6h{=v(-balG8l]b\k_|>$JNav}V8vsjeeXPG#f6*b^VErcpoK.^@qKڞFmO 3ˈ8`;ö; }/muI[vvHZvZ}UC+ArApsŘŖeXI}f5oev\$7y Uھڪؾ*N{cq%lwZ־i}iJZbDI; I;I NMgm^H9K5c+KȢD,+jP~'6LKXxoO"/Eq \Vzeǭ j6liؖJ`-m*6&V]Kv$m/&m'$&C{0Zs˘ZYFVK +? {Zl6m/wI,򒺊xqqڞCmM=ucmm/$ldMkZv$ve#}Т+ׯ{fe=hKZcGy}alc^zY]4Eq=oQfa ؂1lG|ؖ}@km~kI!iwI;I JփhUٛ7fN{, e_=Jp?f5/Ke2\oP܊>[VnFRs{>i;Eڝ mv^ A^Fg]f]̊,Kz^t U_l6[3-ai=.zp[?k{]d-böaK;ΖyBiwB䤭T ik.Y۷ܲY6e_߄6clǥZ$꒹".%n]b޼lm6 mŅmT,hmWKXb҂>i>iZ h]%go9g?sG1b6( Ȣ$,*&^uGf[S%.GnA$m3U +`-m >d-vnOݥ-!i(irQh{f]̊,v'\tgfkE,9쒹H ޿qmۜ-ko^k +i{zz bI[`MuI mꬃ,,, y_k7fkվ"^Rד-m{Hۛ7jÖ6[ö¶T* +==-dsHۡݩs#.iړڬUB>~ b6( *bW5al6FYg~Zzp[[c[mMlO +m~}}ڝڎMkmҶeI-2$-J ВI".iym⬃}ϬYQVebXU*W/l6[s.ebgeqܷ'Gw$zlϟclW[ [md-mمmXkwdY֠hC{ViZ3GJMuIоu=CY٧O=ܲ,!IJkdl6VkxY]$Sx9[O@vaم==؋ks9vD4JPuFҔ| #k?=\n?xh;cЖbض#l#[?` a BغrؚXbv7HH{$-O"m@063h%gQ^jĬP!%R_F,'zzzz:8RuT\.+Wh +mikmm@BzD񰕬a BD}֘ITW;TZcI 74z`8E) + YY,GK*~vd6m_sx)\,.zKqk-6%!lp)6jRkհERkwbk_5v[[ŌK:v6LZ%ik i>66AkׯKebc9WNҟ[)̀1K%cmFlms4l}1l-$lͬC!־akdGK $i QҖI[Ip=W'Ю,E,Y,BK2]Qm~/]F..xqHV-v\6komiC5m +BkQ>ڗZSis6,^"8iAZVHZ ^)mx@۫BkYnњs+K%a2N.k===  yB\[-[$n-h+-v a;X` ~5lVZ[a-[v"kזJ{XZHZHE6Hr^)D[mU%"dX櫐_zzzzwKl^.!6.7 ئvvZPI r[-X[Oݐ/mFtesiwҤBBC: I -m.mAЊ"h7oO18fYb,ʏeq+3r,rp8o)o#mom_rlg8mMtuvZPb[1j- []־֮.V*v!i-[)$6]ݽ>6%C;UVr/DY,3Vq5+i~~l?%?5\^.#˽eB.-۾DowWg<D!X{􈉵cڭYd3j mHk-.eNۘm޾~@;š"h(g 8fc9 XAk&a&+fa/CťoqRnQ2mo|k`;MlSDOwgGna[dCO-ڧ#-$-6vG婨=M$SCh1j +gQ./Ӛeq2cWU~W===l)Rt X\ +W[-2[I[)m1lC@m5Օa/k-`m>{}:>kZ 36g*Ҿ=v-XKlrSYU][W&mWwOo`094<:6nvAKErgI޽+15QV2+tU=?e*,J•{-eRl؎%Pva[_W[]Uq;쥶=~ [bmƭ> iEҞ(쎲r +%m(iᑱɩt&J*΢e̲EbdXΫbEOOOy9\&.xs֠H lSc#é` +)lQVUV]eRtY{[n[ej7*;bi i vG婨oMR&SC#c'ҧΜ^^cbg1Y++Y,.Yf,Wmޭ٥2q)o++$n[e3S''FGR^)l>oC}]Mue,wK#wy k9[79vPk*mm"a$mHkEҖ;ݞںF? vhxtld3γU]B޿/1KSVB}YSOOO/2<2t \}am,m1WYٞ;73}!,lCPW[]Uq;ːVY{X66ZB-v[VYk&m,-o]Cڷ ZlCҺܞʪF)4MGF'&ҧLΝ]4B8 9bCֲYn,V蚡 ^2Rt\\[8nm1-qlelL9N%Eض4G&v!kmV X=D}k-k_lbkG&~G8H[dJeNIBhsk[,.'ɩ3ggfϝhegZYYZ,W#+e*a|nJ8>&ټw&@ELl0.[VrrU$r 6I60B˒a)-s}s~3gg&Ds1qK-[-|l}=݄l4jB.+dgeO?v'S~Y{'ݽJQ+);K{I6ONNff]/(*.+UKچFwsK[{3ІYhAK99,,PYd!"Pl7NDs"s4tBonQBm?β؆l> [^Q)%E92O}rx +=d᝭}q;kژF}Ibi~H{&5\z6/HVP5I=Y:hgoƘʲBc`yr` ###ۍ>3œ\>oqnA^E2`؆=[; [Z(k3ϥa}X'IRҞf_+(,*Vg06U&mk[H@wo_040CϾE޸rfSF*lMsbr +ԖI[>ᡁP;¶ [f5 :Zˊ r/dkkOO9&a[q[+D6frҾ -JڃP7qi=_PT\"W4Zd{Cᑱ8 2Z/0g隅e钅bbAx!###=bb1v1rpuKH/AA;CA븳Tr"e!XX>~KFFFrs1Keqh{h E +  = ʊ2nzFT0k8k?};k٬MhkcJG$-VB7X mYr *Vg06U^%m t +OL"h x^A{-,HYԱjc>cbeŸqKk{ hյkxbD''FGC l{> ۊraV\<=rc)kߐR+vOZ+!-/jiMN +F7V$m}c/iãcɩ, ZM~cQ"{@FFF'|jB~9t,[[7imql7hl(lggS lj+Jvdk5*\V̳CR&kfs Cm̨)^Z/Ҿ[Sy@Z%hҲ:(i4_ ř! +?'2226+ ː-_ۯ1  (l;`VWV:6Uk rY:m˔ikemdNBji32%rZ*I$m&ttvnAe +Z٭-cbq^@s ٳZJ +a]\\[[:nܹC F[:vyiq~n6:=516ąmKsSc}mMUEYFNVKٙ$=DVBZ籨ŤݗLI-kI_PT\fQ*ot7٤LLNEgW8hMݻg)gQb2%*Up%###݋3]\$.--@[жwӖveyia~n&:59can,w:lVUgk/Q&''YcZڝR+UL#@wcJ+jujwWV54Az`#3 +ł#g@gYfYe1cq_%T[,Iyqi{=ߠ Hxh nj,/+uحfAʀ9R־ =YZH-nmBfmrQ=}%>is*Vo0YvgiYEUum}CSsK[G'H,isK˫76%EAEÇŘ"+Up ###e1]\\[-[CJۭ-.mnn]\]^ZNca¶iZLV}X{M0i@i!iҾ#-mH&W4Zdٝ.JښFwsk{ tvr* +viyڥ+Bha>xsV, +YXW V{"###Km$eeqkϽ ʋΜ|]nSA+-,ì,m,ov?J_Z]Y\[rb*l}׋aN¶\]YQVZ\Xw.̩#`OkC/kѲF)]E JԂz j%i%iU>/K{}iO>WPT\Z^QUcp=Av\ 7yYYYYXZX[>>>smf++y+svfF`;8>{暪⢂ܜ3O``aU&KFKj`Ek%jkkV떢V!ZZ$m8VJ +HHGiWV`6Z6!i.?84 NB +.H~β̊RªpUƖQW&Ww[B^ƴUb; nS[ڌa[S]Y^VRTs=v4ȇo,Z)kᒵ:ڇXk5[@Sn%i}l#6hKHܶ/Ҿ~ҞiUTVkZZ AҎOLN]:,2(2*+䕹iˠ+VvQVvaAN+WNM#C>:l[[kՕe%Ņy`Ghۢ//aĄ81X Y+Zd^Y+[d֮i"a(#6ҦiKJJ1H{ H[PX\Z^QUckhln UA{Y1>G>>>>,Mz)sip*%i;3vrbltdhpPaPg(/-.,kϜk?FkAk_Ӳ6}Wk-dG0Hڠam   (m$+6ҦҾҾ~怴E%U5u Mͭmn{?i' "b*3K)+ 7m:32+i{qCH۹Y%SLڻ:ڭmM u5U%E`mZ ZZ{)hm|)Z PVՒeHPJU6IvJ{PKP(mn>H[V^Ymoljh/}췌~dag>>> fUpKi-j406KKSc} EkhY{6IvZl-ujjUI!TiÉ"Q1ƸJDڧii$AiOi A +butI;:6> I ~9B{yS EYYeƪuU_˘++z+qrKi+͛uvef47ׁ`m!$Z{X&m qؘ(ZZbm8XcjZDYne !"a(-DX ݞ3((m1H[UckhlnX;z}۟Ӑ-$h/nAw?fEe)cռ*||||kgeȕVVJ[ Jl1l? [ghZZ5U`m1Z{4Z;RS&cl4Z6o@mDmjjD-H7PHJڍdiEiwYϩ=J=Җu M-mή>'HZ@;B+Y~cվ*o||||kiK˒K{+sVN[ +Y[!l [l45Ղh9bQρO`ց{ekek!kF>6p*Fnic869uJHLjyDJ::&-VLZ?%hIR +9+0(ֿ!VV[R""rgyNGfkJbmvGj2Zg2ƀYk#dku֮0 a m8VH5'n#Bi3>>Ҕi[,V[GWrCIB{] {r2Ȳ||||kgeɕl؎ Bغ]>{wWjiinkڢMkςODkwk%Ǚb-ZZbm8XcDjC$jWjDaa(?jQڭ MJNّkwF`iOҖ:bm9]/I1!i$IZmg)f)d|U_?˒+{+rJlSؒR1^nufDD`k3vJۑڭh?kڰ04vE  +iuDZmi {ef=>Ҿ(H{X-mmi{zNI;:>15}^Lگ%k@+-Y +YM_=[ +ro +a󸝎ޞn m ֖=,X"Z XxV澽颵 (V625ku֮ ˉZF6>iK+{+pVL[߻wwq%b+R^p~jr| y.G6U(k_XZX{ sߞi)ۓMhvkm8XcDjCVG.Azͨ@6,H+Rnc4:8,-qB;ѹsJJ) """"c1x(ciav[M޻?|A"Ejw@\K[MڷN_:[SWKZo -uZ_Hg5SO,FGGG0/*pYomah{m[\~C` ֖UgkOB־ +lmQX ֺv+kB.E)Zgm|Ĭ]TƈZR8,m"Z$P,4Vg0"i m6HH[]w_VVU546wv Iˇ6g9bcl,]NGGG0.q9ܒqj;Ǥm`-`K@oOWg{[KscC]MuU`w[[XfdѠӪӔ +T""kE&bk֮`] v?jWCQQ6(mZV$ʐ$K nҖ=IJ3Z$mk[GgwO_0$"@;@K8Yroemm.m la;<4֊ + [iIe `m&֌ keR YHX6.@j~.ƎڕܨQ+0"jR"T&W@Zd.wfvN/ `i?iV745wtu AeEI{:lvtttto Җ +b @_owWG{ksSC}mYsl\kO-)Fdg]l2ZR.EBZd-V YڕKѥ%6 m6IZ$mH,4Vo0-6ӝTvϾ>rqqmA iGF=I{e9;ZcYQ6/u:lɠjT +T"k]=kѣ6 m\Z#mZV$4Vg0[lv;# ݸɧ~瞏)m;#g|795 I rH;;' O Ag f#!K%une h6wl1`5n"k/M{FkcZs>SO֖nfev%diiJL*vK1v%ql>[Zv]P$JZV殏" /2!iFj KۏO'΁Qvn.lІ;=_:::snѴi\kMM'ƽlmX[X{^|!sZn5:Zˤb6QZdm kȬ]Y mH,4Vo46+#3I[PymwڳC1A ׌D^-r)aL[dHLk_Wkw"HK&UAhoslTW:::r- (la ^pnzzAdm'SoAX{\k7䁵nfI7Z5V* SS k;L-cm"vɳnQGmDm H,) `LXNwFVbO!m vrj$mҾ"%{.\t[gJ>i[g1xxxx<֭ lY–[ox{/`v#ھ. 7;3 B4*\& AYk=k:sڅvjCq|"j +Z7BdԂ I)iٹ%eU5ͭ M i?xsϓҞpi'@ک Zwba\w/neǖ33SS`,~HY{>/aM쌴Z6֨תU +9|.v㑵\:j!EmH()mLl\|brZFVN^aqiyUM]CSk{gw/HeLi_}=cҕQ6i''1iihu=F[?Qa;9fK6kπʴvǶ[֦¼FMg-5k)k]}]DGH,AQ5Q QWPTR^Y]?0ݵgBړ^FҾ ҞwVioҺ&kв;;Smu?e'kσo#k_>uY{=m-MՕ%EyٙɉQaD k5(k%bhj#k|hW.!V Ke +Z QkQ &$efUT76ut  :r R7٥%%̠6iBﹽop-+vfEZK`n훤';BZ;2<48X_[UQ_;n_v[]][CUkuݮB@ $ II p}97bA@iz~ConvޟcrD8 +c k:;olHQ[{FAWw$jO a$rt HMcsxH[$EPIVuҚ$ߌ,T!vtbv~kZrb [omyLZ <;-HDIa<."Hz j09:JKLbk-Rֱ}D='hԞ6 'G)q4z2geKr eeյ@~D zvveum#w?Bn϶ l;k+ jbmow'LV\+s3Yd:-.B'qA k.GO]8;1Y>U\k* j}Ca*-1✼Ry"mskVڑ jrjD;$=likhk&Uʉ͈Ғ¼qe2iԘHR!$8dsY{ZQ<"-B>j_6c#j?;}H^  + %GFQb)$yERo`HPMjg-\_[H̤6u.G~X{c}ŅiͤJlkijˤEyPaRXJTd81d$k~~gY뱑,f+Eg֨MoFQ{$j}@rtl-1geKr jTTqJA >6V:9{[گ ~Z;3QèՕe2ia~$;HOe&'ba<dIwڭ֢aE,j/]QF'&1R\@(+,.)WV76wvi'jUD7QiA֒vKuˁm6֞QkAyc}̔Fvw67VWKK rBNKa$%Sc"IА`/eY"6k{&Zڝب}RԾ,D7 A%ГSXLP$+(+j Ҏi'ff˨PiA޻g&--*ݤ} +g +=-b-EZ ]֎J +$"!?JI'RD<.dצ%l|VYk*5Pk=j jCa$rt LMŹRYYyeM]CSK[GWOVF]B]3~>ξx8888퉴ڻF֮!.!NOMڡ20?Wf2iԘh2)8k]>vǖQk1jG˘}U{EE~APbxd@g@(+(.)WVփEWԚٹťk+k7o}iO_MY8888GIm_Y孛k+זf5jb|txdm}mu /G,8lV +ODECqA~ k/W1Y26k nuZr@"ѱq4z2Ir 2yEUMvBLͣ^G툴ZhHh}ppppnOZl[{:j̔F@lTUeҢ\(b&iqc8QJ EL3~~9gKlQ)RwX`Yz"V$ww@.dޟwwa +|^{y=cGkcGxb*)jQjj?v?y̹ '$fdfW0YM-m]=$j._ H +ZCi>Tvvˌ> 4jB.|.g=<48@Ŭ(/-*HMIJr¹3N?z=v~ꖵhEuڕG-Z稅zFn j9ŗ:r7sJU5uͭZKiRBJkҎO/z$-,2غ-ڟݷvbZk@U*dRH<Rֶ67TW1Jso_ONwHvFXKk]vYuZ+j֗ZŨiC.VԞ=w+גR2r +KLV]ν1_(JF7-}J;ڵ>_<<<7d[wF}bi-ZKZJ)IB>ol= }pN_ow'Ŭdde$]5kwXs1khZkkW) Q 64!16 mj߹!=:RB(J^Zŝ[y3ؾ c뱵Z^Q+2X獍ܻ mi2+K +kSkϸ`'1Q$k)Zo kQjׯzjR>LvkXP{667QU]SyD0{ E\hJ;1i/3Ii=v `_]Z jTJL"Q[7{5U\dڋYXdf,f%Z:v#ZMj<#mMJI+(.-dZ;j Ԏpb2hdjwRJynJ(֨,6%2ڈ(dUzFfvnAQiyUM}cK[gwڳjvi~ ֪ êHv(K\Z<<<׶%5FRkZ%nvk&X{֞5UEٙ~> +D,8lNfԾ5k7DN.Z!jyX*W(PdUT64w?w%ڛP;P/.ZJ Pk0K +o;n־rZqZZEvko"^=s t4VUegjSSc#B(2Xq,eZ77+Zg2Nvbk7G-L JMj4:"TPQJSkr K*[;z!~z<[ j5v(K\Z<<<״%5skͬ}nޟa-~zı#vu67UWdii)I qёk} +T,ֲt&(.(ŕB%SE1l/IdroZZڨdUz6;oD7joۣcԮuZo;QjmZkZSkߘko@~q3}ݝm-5UEڌtUrb\L`-J-`\& AjLIB5֙L-DB-L-D`֡V[ڷ@-(-7>Yma*`oWGksC]uEyIQ~nVFZ| mW/_X8?hkn,/-*HK'DK^BZ\6AI<FDZ5=:jR{njMPh,O$Qt&óRkemckwsQĤTEfv^aqo`xtbjzna B+~rL¥} J X}nO^vianzjbtxJYV\HMJEEJ>" +JbҩâQfYD©նE 5Ca8Lљl.,|$H-'gWT64wMfW!^~=~E} +j5ե QզvG{-kc7ì]]^QM t65VWd%ea Cwv?fi2bX%'d_j,@"Si k~&N._ OQdd*+k:{F'gVQ{o5jՠ-1PG_ + }?hXog@owG[sc]MeyiQAnv"E,{{ .NԞ9me4*Dc1}5ٗ>Rkd@B=Z3I*Ԟsp⻹ E>@ihD,.1)UWX\oji[X^]С/6kQݱP҂Ԃo;Z^awZ3k7Wf&Ɔz:[keŅy9Ԥ8YTD40@#lmAqX :B"q4l/kHсZCj=M-Z#,,5wt <Y#Z(z'.k7!޹}kWfTcÃ}=-MUʲ¼LEjRb\LTxhp`G$twsqr:w9bЩdàQ5ٗ:Rkd@B=Z3Iٯ臨W4GCc$6B,c1Ƙ{{%@LC 7uK|Hw%yuo,NHDLZ%5 m]}#3Kk;gW/߀’|K[go4:jԨ]{Gҥ oR Wﰖڗ=j֮Ӳvq]m-ʲبР_/Wg;kK3#}]m 5#jDpX~>nN 5 kYXNP{Q{ @^AƎBcy8aQ1q I)iY9%uMm=#Ss+{G7Ooఈ؄ԌF|k;phdZ˫k;{}ZQ{xOCjX[]^\}c#C=݄V|c}MUyiQ~nVFjrBltDXpV QlWjS% sH{8j#QK"ڣee@9xxE]GUTVU346wrq KLN+(.ojn {Iãtj=#/,olmӢ}v/4jS ;u{ЬR˘ώPv6WW@>S;>:L%:ښk*J 3Ӓb"B}<]m,L tUj_ +pqQ㬽t"BԞgje@ahbD7n޺}箼PhxTL|RJzfN~aIYeu]o42619`zZR>5j_AjN^`KڕEڙSc#>bWg[ 0?'3=%)>&*<4P_WKCMYQ۷nԊ bibP쿥O7Z6v4S+k`dbnic_TR^US߈om'tE2j@JH|¨;{Oz?#Y?ҭ1kg#Y;624Mho7Tfe&%FGz{9;Xjk() Ԋ|<ܜ4;ޠ jY^AƎBcy8aQ1q I)iY@_`pXdt\brZFv^AqiEUm}Ss[OwD-v}Ҩ}[BiNa퉬R P@{ k& mMUyiɉqёa~>n.6VzښJ +r2Rb8/7bgcPKZf&Ԟ\ԞCEڿP  j]S+ghlfamWX\VY]׀oi MLNj>'/.mlnQQ{L--jbZZppppr7}񯟎d>eog{scmey !vjrbl4Glk7UWd$Dx:9Z[h*+ө~ P+(D8_ PKZZZ{j0R{ZfftjQ e@a8xxB"7oݾsW^QEMCKW7 (4"*6>)5=+'NwoQ;;GQ%Z888Sewe-0? ooldhފo,/)JOM +puv431PSQ{7"BX~^.N J-=kY=HOOG%jhrcqB"btjT4u L-m<"S3s J+j뛚[;~8vzP;G^\ZY[٥ڏ^@eS{ZV@-' KHJIjU5u M-l\=}C"cS2 +*kZ:}᱉ɩ3ΓW66w( jTi"QHopppp}8kSEُTk~tH}pf0iP[]QV\dokeajl + +|\4tjj/|NjϾZ*W~uPB^NV^QYUCKG??S9G3)nH.S%\~?vEīst|g5ఈȘ켂2teu]Csk{WO/S;3.-Hd +`rN;pjA w۷AR$07ڗ/ t67UW˞eg$DFx:9Z[h*+oQ{᜜$Z>ړ'=S{S6`QHˡuj!jQ|"bҲ\q뎼o@PHxDTl\BrjzfN~aIi9pE"_&V(4:C}jx@ E}~L-rk}ɠ(+$2YeQ;njrQsjyQ|gE$ jϞgQk`djnicx/4AtYE%O˟U7uvOLNM/b"yJ3W!jij767Y~`ڿ@Oڿط͍uZZU&F]! xvq~nfzjrb|ldYӒܬɉb tsv4712TSQR`Q{,D>jyQR2/_~]%UuMm=cS +[{'wOS2s UTV64w v]Z&*\:wM폞OR_6;o{έeШ2,BvIQAnvFZJb~>.6VzښJ +wo߼~EZ) qZ~i.j}}_C[M)ZA!QqI)sljUյt ,m\ݽ|""cR2 +KЕ5uͭ]=ãg082B7\Ԯ!vϝ=}qrQơ&Nxfa~+Ã}=]͍u5¼̴ԤȈ _/wW'[k 3cC=-uUemjd$EEjOmSYڋ/K=S{|'!j j%!j/\rƭ;jZ:&fvή޾A!Qq ɩY9%誚Ɩ^ڱɩE,O W4:svZgevssc}vIQWD]hkiBd&'FEz{:;Y[hi)+߹uڕKHKA +AԞlj֐S'"Zۋ-kajͦvC7LJY!pׯx@_OW{kSC]ueEٓ쌴ёC|<\mM t5UF=VVZJBLTXH wGYM큿G>njrQyQR20^ Qg`ljaekWX\ZklnfS;ᗉ4:cvv?z4 >E[P [ Sʠ jxfqM`OWGksc]M%0/;3-%)aL@/w'{[+ Sc=MuUڛׯ^Q+#%!Pˏ=<\P{ +VPHDT\RJFZyEZ-=Cc3 k['W/_̜’rtUM}cK[Gwo"'+T Q>0M-8 s׭A֭}}k!j uL$qXڙɉ*tyiIa~NfzjRB\LTDXHu2")ԙE@-VVQ]ZH- mE-E}P8?7CStj{;Zk*J 3Rb"B|<\l,L uU%%n\r9ZaZ.@a:Ѩ݋Q݇P{!@-'7/1A@I&b2r +ʪZF&V6N.^>A!Q1I)9%eյ M-ݽG"y:;F- (lF&j`0oƎMv}}muׯfd"ar|tdxhpQowg{KSCmueYIa~NfzJb|LdxH(ړDžpsqjD=PKk7P]=LjiPu=}bx)9Ee5 m]#S +[{'Ww/_ʚtj&& $eZLZڵ5dnZ jYߘ$=] u5%EYIQA^NVFjʊr2Rx1ѻiԞ= š@f-=],nrj3ݍQ3|8/_P+WTQ306upv MHN-(*-kln>~/G&$9jYPK-``0 ۂZP˜ڥٙi +0}Oj;ښjK +r3Rb#B|=\l-L 5Teڛׯ^xV'(ϷnjG88Qjp"'N1w_/-+ghlfimWP\ZQU[NL/.-QˠvPnBja0f:vI@ B&NMb>hki(-.HKN psv436TWQƋ߿Ǡ J-7'ǑP y+jʤwZ^cB€3joܺsト_`HXdL\bJZfN^aqYEumCSK{'`phxPK s KPj(بHFi!0 ';k7R f*J-ŅY4Hv45VWd$Dx8Xh*)JKjܺP{ VXH/JLj?mjS{P˅R+($|¥+j$$eU5tḼl\ܽ|B£bRҳr K*ZaԎMLHˀZE]c&-[j`03ڂZLjjYPQK"LNa>zmmj,+)JOI + rwq271PUVCvB(\tj?Sv/Fڃ\<('STV5025wru +MHJM/*)klnm>}K@D_XԾSnPPHuBja0GaRX vx ]ZS/?{ +jomn,/)JOM + rwu2752PSVˠ$J-?/7'{1jw~&?}PjiZYڛx)yE5Mm=cS +['Wo߀Ј؄Ԍ܂涎ԎOLI7,ԮG- `0؟쬥SK,Ծ.P)$K'tu57Tfg&'FGz{:9ZYik(HoԞ= űRK}@_Xm,aC-'Q>~AB^GK+YX98yxED%$edVT7ut2$,B+Z -X`0 YmAԾgPԾSK&&vw4VUeg%'EGy{9;Y[bJj_|!1)9%eu MNj)3(`Ҩ}P_)k\373 +b(15Mz/a +].Ksd9ef=߿̳rQZZL-3crj aQP˘AԾ|΢Vzc}mUEiqA^vF:5)!6*"4(POGS ҅j@#{ojġvN>#N:sP+)%#ohbficHq MHgfUT7[; >b0g8ήPKZSp8'ƋZ"jgԾa2CG@j:ZMeŅyٙ_oWܙS'Ԋ۹CJ통LPM>R*ZF&67oTZfN^aIYeumC P{=@g/CG'djdj08Z%292ӌCϞjݹm75ɤ&'EGy{Qm,Mu4TUe$%HaSv3vZnnYv_`0v?AҲJ,jMͭl(n>~!a1q)|Dm]CsK[ǵlj_!jG!LH-Q;OsjWIpjv|k9#jZ&vQMkm- uՕe%9YԔĸȰ@?O7)ZY@BVu'@[ԊjԞ="-k`djaeF/*)klniy NPKZ6PZ.jpuE-+Nj {Cj;[j*Kshi)1!>.NVFj*JҐg!jnPA_o9B-~݂{R{Ӑ?W4 M-m]ܽ|Bãb㓨iYEU5ͭڛBj> OL2ojjcjq8n]Ƌ Yڷoɉё@ڻoj[kK +r2ҨIQ!A>^.zښjWd=}QHb"-χERo?;ơw@2Z3 k;gWw/_@mDTlB5=#;uM޾!D9CvQC[kPġvD 1}ɦ:(-.H&%FEz:;Y[Ρ7~D-:RVP{EKZHo@phDtlB25=3;EmQ#Dm둱A-.ciq8neIQHmWG+QNMN puv436T 'DP{P+Ϸc"k~M-Ok?B-?Vh_DjϜJ)*kY9R\="S3s +*km[wj<{DNN1!PZDGŧQkZ2 Zh-v15 }B'{wnjM eŅy9 qaZoW9HC+#?rSuk;VS{)Dn.NVFj*Jlj#jۿxRE6@-?Z1@j_D*uprqGjiYEU5ͭoԾ!jO6p8ܺj['D7Sڑ!@KڛRHmFPuwqr Q+ x~ڃZ1m,j7vgv v>z鳐+ګjzƦֶ.^AQ IlHmED jgHrJgQ[ +z8;Z[|l8<3A!&hTR H^AAKRD)"JwE셢io*0Iyve0bf~9s̹eFkWkij.^8>ԎԎRje8Iit.jZ:j-:8{Z6#3-*.)8Ez6icsKk[{'vuuj{Z 0j{ =]]ZRP{:TEYIqQA^nNfFjRBltdXpP=v:9nPƥv2P;C@(QjRRMC[g=[LYZ:8{B(ɩY9G +NU/Sjj2VH-sjũEi1 d&1k2V@-skj^&Vj jbya!AZOwWg[km[6mXRH JVAQrrR;ɧvvK7P?($<&=/!PԾb}ݗZVZ0Lƒ@-c8j_&JC>%'(Yi q@9K:J +>3کR;R;ٗq +'E]$ojjnEjGe>_xR{C'@v%7@mww;ڿZ 0YM*Ծj} Զ>j>P{R{0Ciɉq@tfc}B&P|v v$P;CP;LگR4Ey4By -!Ԫkja5#:^>~@mhxTL\b +(4ڍ(uBj_ LH-al%FSBHm+KԦ$D~>^@#֌v:vɢjMU(گD6hjK-VjZ]}CcB P/'fǎ,-j/]!޹P"N[0hԾBK@mUy&DE~>ZG;Bnȡv("AXoOjWkPkaec 86P[@j/}6Pj;Q30z a yG{}Bm:~@G{+ 5WqOOCMjUDR^w&?,SjwC#cR3sbJ9!Wxj1 d(1kEGBjϝ(=Y fg$DG3n0dF?DUBǧk?Pj')N§wVK@6BP6,":6>)U@mYEJmu ic3R Rj(̩Ej1 d~en-R Rj; ͍Oj)5Ք3UejSc#€ZݻZ'B6Z@|jNVDA@ן_gjjh^KBwrjr+(*.)8Ez]! ̩@-+-Ra&sI̭emR{vMj +rs8j]m [(kWki-{vBm|~y`aEgG;I}cgOUj i q@\@Jqj~~;ɏbS+N +(([ v > QCY'J޸yj"aMm?޺yOm@Ciɉq(ZZ;BVJ:J +3ĩP;J^Nn(UP;v9PI70&ZY9:y0@i5=N*=Ҩ0 V=Rjj]jOK C@P .gɡVa(> S (ˤSԆG%j#VXjPjZ%QۋbzR+ږFJK@mXQBmJb\LTx(P'eYکR;|hNa3o%ZuM5,fV6v.n^@mCm<6R{R{KmM.J-sjZ 0j[KR$6PPzy8XԮT'.Y`)@R746Km6]@mI-+-Ra&IvP>B@m:6/&ƆRUԎL*.V6.;O-,-̈́Z.gfRj#BZ_'nVǟKɾ ,Q#d#{dԐ%ˤ$M#k$IdF̠3~9{ι~s7||\⠶;$-kYm jNmGImWIm8Vj'ǩ5{NEM8(+QѠvvvQ9gũlTQ;0Nm/ImWImԮ Km 퓩-ӠwLj jJj+ j,Θ) DD_ΜaʠRR;TP;ؤv@ j{(I6a6jbdj jX+hP[#nR;OP[AP,FJ%"R!]&mQ[+gR;]P[cP;QP;BAdjOvRvJiԶvP}%{S{jA-&ÆUTQ;N|%"ԮtvI1jTVZR{;{JjwlqkF=ҤI)ju];떄v5WvIb;S{ jϕԞbR{--=pBv7''Ũ=?N Ծ^]?PIPKDTĹSI.A5կ{P{CcԞvS?g۩ӤvD٨ӧ@-QB?1jLG0Nn[j׷P+ԞW*jRԎÏ>~iPMIjZ"(CߒƠKI}}i8EC+Ԟ4\BImڛ> ĨZP]}PKDSCCwگc~"8:ɤO]# jwJ&Ljߗ~{DDO%Ծ-7;(; j AS;;n+IjQ>"}j3>)}DQ{"+Xݠvwj)jORϤVj?~e_(r~%̟[MjY=yR{,Ծ0nATA{jV`j[I{کƽ`>k*jSnEђSg)jW>6|tPjZ"(ڟR;|cg jOEfk=+Hj_uP+DDE^PjW$^QW%XIm$jhF^ڧݨ}jȚ7jT^ѯϥI jr̩S\QDD)qj2(js27 +j2Y>S\j\Z~JO.1ξn3j7hMH[vjyQ +j"]d-wjJMڍ+vQF.HM+ZykG^ ʕ' DDRv}y‹^%] #LjOV5YP{砖<>9٤d#S[ +SRjvk]i!&8=R{zQ;yiY@-eLٳ$ӦNlv+=^n0N>vvePKDBRI\ALOSɠ0;kS[ DD6TԶMPDDyy/Amؖ볩lZ(- N.ڍ˲-$+hM Ծ >RڡR}mzcj}-J#Ծ+E ?H-@k).mXj)I.9#ͦkS{O[JR{R.SE.kԮKKI%%I=R @NMSۧ'OM!j8nAj+Oŵv&O76imYj-Ծ;nR ꪥFR{MGjl ٩fԞّk"-~2Ԏ*L|j/OUS;gwvΪݸ =wvi|j/hO}#oג?՚;Ry>oljo,LiIj)Lve]UnW9w{h1u9LjtEjjwLRe6VJ\Y󩝫Rjͦvˊb6bd~#NݷSd1=$IAԞ[1IjlKIj/JM"~Ծ=9ڃ +SiJjΒERRiIjLR{rCl^MM^] KXڅR;Kv$DAj/L^4St6w2Z -N5|j_Ϧ$cnjz !ԞjO Q=;!>0jLjMRjAj?/ohF\j?lKIj-J%=1{yjRAĒ\_|='hURk6?vB&eSS{;(R: SS@Ajіڹ. 3:I婽(;F]2P!/hV)-וG S{!s==SxM=#ځC_ݑڇƌ}IR Sg.ʩ}BjkOmݼ4Ԯ*ݼ-{dR{HO)Mj_N;7|jIKjBMrIjWS{C6N*KThǢNʦvsOޛLj xy.vvˤvLj롩]&52IvȤvljNR{j.2,[3c}(SRzS;rjGgR{gZjΧv۶v\j)N<+vZ֘ډN-H-@s).m8ljjOٯ離4g2NP?$ѨQ1v1c,1H;RĂ"HDV*X@E셢;+*kfys=re/rj7քyک P.jHGR;Tک2jAQ9j3(yjSjˑZ ðv]+}*j38jF˨u.v!aS}Q{P{K4v@FVLIbj*3MoN-ZBmVP;i@3v#PIݽ/@ +Bm-?MH-a%I0ZMfF2j7+])歠ۇ*jgQΨPdkRRa)ZBK=QjZ/yjMM fjFנf_#GjSjM Vήn@6,2&nGc7n*%OH-aڦZ:j)"jO0j) 0ևQ`keinQQ;f#˨~X=e'Ԏ+Ou@ڽ)iY9y@ k5QKEj1 ԹS{P[YqR{Q{PGMIK fԮkڱa@m}RQ;&64&ZX;:0j7aRjO!^aީTFmRa.V R[ ^t¹3%nj׸8;ZYj gϜ ԎSB/e@FOaԮaED'$Rj3s +( +.jR\Aj1 ԩQ\E@mbB|\tDXpPAֆP;_D!RjAPj;uQFNZb +j]L] + GmRJ*2jfjZ ðl3ޣԖQ{ /PD eԮrsYN],P>tj#lkjj)P;c㹄ڥ6Z߀ЈXlyjo)>Dj1 _m!\Bf]Ϩ]foP;x +k+FgڿPQkQP_up.$1jFDLܓ?`fvnוS ohlDj1 ԿmlljQ{8Py0uҞĝQA[ڵkVjrNC"jQ?@J +v S{$*P[Q[>bI}-Pۄb[jj_Kc>Q[^eԞjs38jFnĨ]A]B53Ko 8js~\DBڟuL1kyZkeN@뽁Z;wQj3s ]@'@SbcJVBScF]/^8@Q~ji%ΣN;Q^}40jv]ɨCݷC(JnWT婥[+P7w0LMSA-%L-P[Q~䖘CY1Q!AۀZϵWv֖"juȄPkIuj=7mAMQ{CFm/8j_)0 S$J}7d9޵c{LdxH-ZW֖P`ډ2jЏRCZMmJm˨q. :89HB}ɄO5R[]S{_BmRa kk)@5c<Ʉ8ڍޞ@3\VOgf"Z1EvmIڙ& jZwF_`HXdL܎JmzVNP{Q{Q{0 kRj++0j\"Ԟ:d$ݝ@ j<=܁ZG[+BLEj*<jUH+C+ٷ߀#GC53Ժ^EFj&Pj Sg]"˨} y36!aꕄڦ} R[Tx /'6>.:2,8]j8jtcF9foBm7ev۠Xn{Q;R;Vv|3s +[{Ggv>~aq {RR3"joUڇ< Z 0uYj_s666xjڲ"jeg$M$Flj׸Pj-Ξ9M_O7R;|@mOԲ}[P{M@탇ھQDS>jgss|p8Ak%P;7ǜԾRtj>1> +>|pޝ7j[j*Ks(iɉqё _oO7gG;kK36*c\jw#jŶ j7}\j.VQCRz'c'dUNk9 sz#2 %چ6D!=}Z:WDj@j18'x-C< }ƥvQ{6R[KsC]56'+#-9!.:psv039gpVie9jwJK@ +Q)vǠS-Gr +JljϙZX:8zx^ MHN/,)khjitKcD}R M-{k18'L-GKHZ}bltxhC@mRxἷ)Z%!}׈Z)}j{n߶CR +PW_wCjeNV?}V aQ I9yeյ MT@vHmgW73&!쭝e2AE.Z&svQP;ɠjYvuj;گjM eŅy9I QaZ/W'[+ SsgϨ> {HW_&u S˖ڿHB"Z @lj8 +'Pknek  OJMfS[DmvܺsQKj"jp8`]Hm/ޝ[ڋԦ*@mA^vfzjR|lTxXpy/wW'{[+sScC}]mMuSJڣjJ jE>PڿOkPţ8VU]S[WИdnecN+(.o^̥ѓ^Z?v19EvQ;ǣvSp2CNdL jiOq mԖBj))I1QA~>^.N6V$.'ݵ2ԮcQ En*m4v!'eOij-m]=}Bɑ1q)i܂f@7 jFF'SOq[;;ˡ }ávPCSё>@ׯjkK +r)i)q1 ?OwG;Ks Aj$o**"REԮQRM%R+ ݳR{0VF^QYUMCKGdficBKLNdW56Ajo޾{R?cQQ M-{ky.,[pk iQEvR{훐ڶƺ,JZrb\t$9$Ҍdd(=rQwVH-{jԮ8n`QP+$"ELQCc'eUԚYZ98yx#2ru KW>FCjZN}[p2S@ M-!08,"*6!)5#3' +GI"`kL"ZvH-P;MvAj:f8ِea/@;-LݧS*N)EJeNp{ ; i ty y=Ԓ[I(E D?O7G;K3C}-uU%9i;ԊAܨM˦v?/F-/_JH)(kYZ98yzB#bR3r J˫jIM.޾~a +FLjPj?lF-f7J..͢ia^ڮrk(?7+#5)!6*"4`gmiflDBzjqljݹ9QjdR{ )AIEMS[7 (4<*6>)5=+'ϢvPKB]|Qvljᬅ`FIA-:jVWjaԾ2fg&TFب_oWg[k 3c=mM5EP{:ړQj؄ڝ߈_P,jEpG޾+%(ZX:8zxG'gUV54j>~WZ*}P;=@Ȭ]Z^(}+0 SqCv?o0js驉Q:uPgO?Զ46UWd$Dzy:9ZYjk)+dRwo=*ِ=֩n砖i>,C=s¥+xYyEe5 m]#Ss+{'w/_ȘĔ̜Ⲋچn6C#TBJ-s2]w.Bka0l+ sRN-2jsZudMmwg{[scCmuEYqa^vfZJb\LdXHF,^ʥ ԊD +AM-sԲ)Ka-wjAEZQ@S(njeU5tL-m]=}aqiyťUͭ{Ծ~34BMLN08]B]CI-0 Wh#iשRRAJ(22K@Guw[IUyi qaDOwG{Ks#}]- UeyYi@k(NjE9eZ_#?aQ˚Z^PjS{뎤184":6!95#;J> cS3EȬ]YAf- g폾 Z][]YAF-FE@FFE 6kK +r2Rb#B~>nΎv6f&:ZJ +r2ҒwnS{ VHA~^@? gڟ3C="*&P{2r%uM=Cc3 k;g7oʚ:RS >F0QԂY Eg2'sj0 ȅZTZjQ P˘FR0jj[Hu5%EYIQA~nvfƆz:*J9) @ϟ= =RǢoM6neSV@H(P{4B7HH*jzƦֶή^A!Q1I)9%eu -mڇ>{vJe̡2g%0kWW7Z m$ԮjPjQ CSG^x㇀Ɔʲ_/W'[k Sc=mM5EP{:ړǏD gSP۾ڝP{V'~:Je jںFVN^!a1q)i9yeյmXԾF&&gs lj]fZ&}/0 qLjF-=@(225Fꊲ¼̴ĸȰ@_/wW'{[+sS#]m 5eE,^m6Gq"(|6v7v:0j|IaBs.]A+(jh[;{"2 +K+jIͭd@GOz_~34L'ffo1jqPZh- m>rQQ"vvfjr|N j_>y^wT_[UQZ\Ltwq271PUVKj]tZ1aaAZO݃Qk_OvjM-b-B-AZQ@S(nܺ+)-#ohbficG MHN-(*-#5;zX S Yp`0Vo#ivuue5jTڞrK(?7+#5)!6*"4hgcif'~!aѱ I)iYҊ֎ɩY1izVN~ap2G )4:D'pnmZ@-AZɡ*Nv0Ǧvx]T4%1>6*",8H_W[C ;n\r VM- +YԞ`S{GS{KZaQ1 )iY >RTQ741spv OL~eIYeu]CSK[gwow?|[,aqx"B3L-HCkߟCO=noomn"Q S EARHD<Q;woG!j{;Z+J^=|4I|Р_oWg;kK3C}]- 5eGj/JKJ +#ԞR{kP/x=gPҲr0oކUV346upr + $9Yfv^*k^7utP;] ji *L-;k?ol +QXˢd-ءAQˢ_EEvɠQ$~8ϡvhMoWG[ꊲW/ +3&=~`kmafl +S{Waje +~AIj}GjP3Z]ԞC + KJ]x*DU5u M-l\ܽ|C#R2s +ѥUͭ]=}C#cSӳDյu.PnmZ@-aAZԮ2e@_OWGksc}MUy) 7+#-5)!.:2<$@OGS]UY}!j$DQjWljޡ;ԲRk`djnec_X.)kljmfS;YD2Fg@BY Sd&P ;W=noomn"Q S G*Nv07âvx]ThocenjdĥV^VFJB\V\jYQ˥J僩ZZyZ )Y+nܺs#%5 m]}#sK;Gg7oЈ9yϋ^UV54uvBԎ}Ǚ%,O$Qts;ֲY vwPԲܨdЩ]ZÃoz;Z+J^x491>&*"48H_W[CMEу{wnݸvD4By!D-gS{Ej +IHI_ġVQYMCKG7 (4qLܓgy/_UTֿnn}304P;=;'T e-Z(kxY gZBQˤӨd8?;=Q;624𦷫u}muEyٙR< pur031PSVܡ0BjO=A~[ZkJ)j +j%e j^yʪZ:zfVN.^>A!q Iiٹ) +@$ShtD-0Hn"YˢY ;D-M$jaj][ei2.c`j''!jz[kKŅYiI qё!>^.NVƆz:Zʊ߽}2ljQgy=5jHZ6x=Ͽs(A!a1qI)ڋ*(kj[;yEF&$gK+kZ;G[,aqx"B30؛Y vGZj n~Z_e2T +a0 s3};:Exz7 +ɫ(t&b{{wXz]"!lϷЌsMǺ*913!}&*"4(P_GKCUYQ^у{wnݐԊ n&E5߁3'QZZ<n.6VFzښ*J +r޿{u@^XH^fQ{ AakeT4uL-m<"'gUV54:$@U&e{JeQZZ0 v"O-Z0{tugN^]^Ծx%z; uՕe%9)I1O"‚=ܜl,Mu5TeQj] +Q{ڋ?$[R{ Z&\<"b{HV^QYUCKG7 (4<*&.1%-3;Hz6=3;7B^ߠl @-խ`03~fjaڗ :mwgF^YZ~651F"vu45VWeg%'Dzy:;Y[hi*+>zpέZ 1QaA~>^,I-Sڿ0FYvjqjOZZj1XP+%P+#ghljaek[PTZ^USFԂ]XZY]ޥ`k_}nk[ `MW`j4Z@`_O 7+#59!.:2<$POGS]UYANVZ +Pn@ԲE5߅3P{?27/ $~J*zFV6.n~aObRӳr K+k[ }CD/˫MFcn-B־aZ6j0 v"Բ"2vNlS6ɫ`jϟNC}ݝ憺ʲԤ'a~ޞn.6VFzښ*J +r޿{ui)Iq1?/5=}=!S{ƋK^PXV^QEMC[W7 84"*&>1%-3'H[;;7A٥{Z}Z `?_o^jO/tec0?7 vjbDhoij(+.LKI puv431PSQEvUR\/,(Njp_aԞS{P{Z. ZQq @[w=x$#ohlfam[PTZ^USF=څ5=־em;0 vԾcM[tjS{L-Ԯ./-ё.B[Kc}MUyiQAnvFZrB\tTxḤܺ9ZNN ߍڏE=PJ-'ZZ@-7I\FSPRU306wrq |_TR^YSJ"j..׏FgBka04i> :hj+ˋ`jjIġNBksC]MeyIa~NVzjRBȰ@?OwG{+sSc=MuU%9Zi)I 1 ?ԢҲSBYvjYړcjo-7/ $~*(ijiN8.5)ǀ`3CRJ `00`l0{g{a0{ M4;lQצjF'6N\.GOoxN.nl/NphDtlBRjFVn~QIYeu]CskGWo?7269=;7~w=(k7<}lW7=Z`-ܟŔ{Ϟ>yE;g'Fxޮ憺ʲܬԤ`ɑakcE57524׻xD-J$4 +$ZZyZAʊ#QjOCԞS{VDcTpxECS{Z3 +k:Á  + OJI+,)oji ML_Yd+w?_ڟQ S+;7WWDҕ!n_Og{KS}mUEiIa^NfzJb|LTxhP ӁA03٧V[SF"q*4|VLPǦV*!( +O$5ut/|ŗ_]26,wo߀Ș䴌켂5-mݽəQ>Xgc8k%k````׽ң9mom>E(oprqA^vFZrb\tdXH`;˙ioGYZ_/>NV#X +PVVNḐVN^AVh-D2%TZ"jMͩ4[ˍ MHJ/*)khnF&gP e~>{Z!G ZP ;yS +BiK{$jBQ޳]O-ӓc#)%=3'o`hxtbjfkoܼ}P~$8k{ւIP&Q?j:wo߼qե+s3SC}=-MU%y9)1QA?O ӁA]<N[KJ$4V"j!jajʊ=JZYQCԞS{V DaTpx"I Q+Z3 KΞr  KLN-(\^YS?[X\d+kۏvY]Y.k׏;mQ';77VܻÏŅ`owG[sc]Me쌴ĸȰ_ow3ގN03D-D:EDT0($Z1|jOV:2U<@2V $UZcSs*Ɩrc{s"cRӳrJ*kZۻzC#cS󢬽)ڽCYӱY+d-؉J{Lt(jQr_Sc#C֦ꊲܬԤ`ۍȰQMhiUIЈ؄’چΞ>KW]q;0k +Y 8iv?jBQZZnmBQ{׮.Q;1:&*<$(ۓt`Э&FzPhiPȪDAi SGZOL8k!jh̿ٯ_%}'DDYEI pooEmvmkDwV3tngM$!LCgyϋBTF6084<*&VO6gUV54vt O9qrjfnn&.k6hZZ444?vUڗXi!jSV1?} s3S/?31>:4PW]YVRnH'kbcC}!jAjdR㰙 :v:u0 e3])TBD&W{q/ ($<2Z&&efVT7w:}+W篽Xgka-h:dK,Ԣ֢TZ<Xj_BԮ>b]$P'_:}҅sO t4VUeg&%j0 +L"ARjԺ:u JߦJY@K-l-L-JrX*W + R4Z>Ő_TR^YS70j_rv|d0/'3=591!^菡M& <ɠS)dW0$D):buX+Jc0_( +w~JUV[PTZ^US78<Y{irzv`Gkb5c-Z<nioآ|0TZ ҚQ w-Q@Kj;ZkK +r3Rt82:2,$(KB.|.dШZSj₡+;I>"xk:[Lљ,/r`dmXDTJ'ҳr K*[;^] ֮YZ'Cih\_jo.@^B&jzpo +Q{cÃ}=-MUyٙiI q`3jqIB>f2T +ٕ(-L-QkJB.RkZ +X+Idr)A!aJFӧ2rJ+k:{F' k0޴ok\Z^׿־0k-ڲ mO~igYZ<0ҾS JdueyGo&)ډѡƺܬ C^ըa!AԺ+2HrXLJB ZG 6oݾcnyemsݽ~ZDYh-ZZddddM,jQiGPiBilV e2j.Զ6{EG4jwcnB}g0jWԦ1j#a1lj ;[ 8Y]Sc־X{emk[nЬB# F3ekvkIl|vʥbJfFVPAFjX@}ugƩ] MKINrV],j}vFM-yXem(fmtL\|b(5v랢YhvcmIyeu]C#fM>YR &3eف>:cͣdddd}[K;6p@irK{onRfAը>@m']ڛ uՕ%n=L=ڍ4jZvjTQrb|\Lt$Bm(AP;)k #bb1k5`6\=ڋn߹֎X+jNo4Q+ZKv[KbKFFF6yvN-*jLFNV˥wn¨S}K0jcc"pZ6Ljve+֢k  +#.uck,pY#*Vg0) Za-jȈcntk}l#K+]Q*-PZ2 :Z=\^AYOQ KFE!li!8zK K˛Z86,\dXWdm^aqiEU Uݽ_h숵Lk8Y?&o--lidC;4jqJ{onRfAը2Eˀښ<_}eZ07Bj9ǔvR~ k֢Ԇ kcS'6Oif!UVk5ЬmKrR&b Bj>tZKbKFFFX6(/>K ťY-ɨiJ\*tuӨmi,+)G͢Q)QPP+BjqiQjå sZkЬ]am(fmtL\|b(X;kҬ=XWP\Z^USJG`O&WZh,6;j:fdddd0ni:QJkY(ѠӪU +O .mku@mC]MUyiqA^n6BIQP*JJD v!\zjK-Z6~8Ԇ I)iڕ,ksYaIڜ%e koܺ}nW"+U`2SVZ`-ڟPkqk|%%###M?9V1\aTڟ}pJMVRˤn@m;o@xP[QVR>$?j׳]I6 6R(Ǩu6(֏Zgi=R;f|Z?`!ZXOǎWgWV54^²G,JF7h-i^[;`KjKFFF6yU~ҺJ;?7MFNV*REK uՕEy|uǏM B@mS`S 7ֆaOk3kO/,.^zZ+*Vg0(hZ[lImȦ?oA2EK;LFNV)>qow'ˀښܜj3jFmBm|l FmjwX[[Ԃ[+* j층ZCڑ(ok}klImȦ3o%.v12K ť,VRˤ6\ږkZ@mIQs_#~~a^P +P*JƨQ@Z&li=RkQjyX1kw~w}k|yYW54"ֶZ#H帵zLYqk֒ڒMq>JD-.2 z\ZT"w~s0/7/OB}{{dA-NدjGÍZ|j1Y֛fkYۛ14 +5+pBX*W:Xf-bb;ãs#֋- ]$ZiQh#2**iZLhiJK"aq!a1$R|7jwEQ &jDRD Y־@{@YLNϠsry2BTZ:PkL_\Z6x`mL[.ܟyI-V^i %KsS#nf1 v45j5jeL\VZ,(cЩĄXG@!pQIOnڧ0YdQ1q2%`r¢QDTkuں]=}灵fBD]X{U?k# ȵ;.8Iv_ii'i] = VӪ+rI0ٴL +9%u(ڽa9}?j7>({Yk-Bm}@;OJNMˠf8|AP$ʕ*`o\E`Π^BE6Zo خK[.w _jhI{ǛAҢQJ{ vH;62r؁/IXo4U*\* |+7'L>q D>lԾ>jQj=nFç6dnڭ߀=BNϤs<^L"P55cCSK[ǩgΞ֚,V5<:6X;Z{ Aޟ}9ppppGhD w#HP~J{vyqavblt[-& mgNhkij0j5jeLRVZ"(屙9tZf:9%1!.$o;jGGfvGP86*&Ff8\~aPT.+* v`pdٝn5k[ہb8C.xI{Oi +ښӨnf1 vuuB.) +\IIKM"D=x (jwD[RKdY{dmtlBbrjz eb\ή޾ZpGF'gkZ{+aK-.@hC&H0?73=51>:v:l3|_oOwWg{kscQVrLX,rsԌĄhm}8jDY֓po־ZZ$kYBd &+IdJƀXqc텋Cf + +?{]ű68Bn w m^iƗJ.jx#6DZCMFIJK<.ɠ2)䔤8G#QJڷQ +nn[5ja>}oz>˯vY{؉xRrj`q¢QDTku M-gΞC5v1ٹE?kCf-6l=-xBnB i -6i=b'MD]EC[&DsgϜҶ455JLR.*)*s9,FvL>q=?o|Z/k7F/}m-k?S4kw踄drz "TZkxke%Z -.pYJrGi'È @:mUB.~~;7NH'''&E<vh~kQڗ"ڍ~Q!K&k77k#_;pdmTL))LɤL6W ()-**`X DuX{g֮b 7i/HDtwu67 @ZB&.+-l&NˤSHq1Q jڏ>xQ1DmjyLc?w׿1Y͡# kcIɩijV6_){$יإ,u;!eaY{hJ{o1h5ω$dΉFxF/^yY}vAeJGs3Ӕ' I;FH{ё i/?{"i4VWfgbc2iXH0D-!-b!E%\.!jWNi_9kM4Y(k[n۾64U[v bpcxIC>#eHG(i H{WG!K$' iB67TUfgbc2iXHpP&j%BڊcaFDڷ"jPk(kij +eɅZZ\OTgfUVׂ{:~X{Um7n!X;95=k -]y}m1~s}g絝eNi֍o^i?.mGV /;3=UTeDԺ8A +PZYZh&"Q:}ɬ}_?kY (kZo_?6LP&$%fd M->z$i电׌X a;AvƖQ[fnxxx+oag@K% #^%mijiK r2RHiH Ңu eGo*j_-k?bYk DbZA!`<&6.A_V!kwv=}`hD1(l +'^<Q ֖UͻhY{X{Y?Sap||brrjp"lvA[mn.sff)gvZ'%H ^8%͍ mEY HJWen."!kgcm1'vZBEvWj_-k@֚M,8Vֶv-3 r{e ZZҒH_I{Y#i +@x":*6:;:̔mQ歉Zj(kכfV6\@d&"60(8$L +%Y9`miy%i޶.c'k/W.X=X{V`-=l)k`Qnxxx+qg,YCRҒHZB; _^$=qm/)mey)H&łҰ@2j<=$n.N"kkceianfGQKIԨ}}Ծt~k!kYfKk;_(wtvqsY!ǀ46f)=kkQZ*l'uÖ [fmNi}_ՇV'i'ՒG=E0MKQ1rYMZZw7gG{ϳ䘛 jjEo6j4k!k7ئ+k[.O ;8:Jj_.kWg:Z:k|My em42*Z&#kJ4ֶwv2Y;LZ{a-Q؎녭ql5Ҹvt3&8JdҎݥEJ;$mowgFڲ"$mzj2HQn!qsqr \uԲ!jG7/X{:YքmjFd/;:onݶ}G`Ppim\B6'y}Ik1[j{c:8_8Ȓj{ !B;c{m틌3(zP컌K2{bؐ9{ξٳ*!B?fB=_}9"M ui +r^nz]F$bD---9e-m-4kWJ$RBhubslhmIYEUuMm>/r=XFBZk vZlf."^,wg)hiioä%mDZPH`H mc=ɑ}vϮikk*Jٙ^aVV*dRH +FZZg-vj-ZX"+T4`2[/,fݸim?)krv [l`ՖO\/,wqfqg@Nک^ Bi OaM6MRȥD-*-ڤ jeCH>gm20kS"D&W4Zb;_FVro`mX֎k^ì{rv撑-|»bC{B&-&@1(?"m%m >vp?#֮Y]Y^ +yNb2i5*\&)0j)iMƣ$jEY Z`@fJ"TFpڼ";wE}퍷~9ֶBk{ѱ `- [Z6vCi[9Ҿ޻ok{w܎K[TMl렴 +T"QZe GeY*KrR FpyڒںƦ歈Ͻ+[˴lBlNOw [qlqmnYo1pg@PLFF6_v(K19B#7on$0iI ٥}CP_W[S]UQVLz\l4R!J@U+YiMJ.x/kvUP$ +:M7,VksX{S ~H[)L m!`$ւe`;9Im ?Qkmgl1!_SF-HI I I  F~ mgG{[-g~HSGđ6?Hvdk*\&@ZMxv}lbւ2RI&t{|YkXkwڳsZ; Gơa?"FҖ7.qЧBFFFgyew/+G(lB'i\ GPڞH{Ё}{v`]Hvd4*\&Ҧ`ҲQڇ$j瘵 0kYkA֦ +LTk:l9n/6'v6nڼeP~=}܅/uv G!`-[Z*lQlo"ijpz7yKFFFhoL(\geB'`Ҏ#ᡁޞKퟷ^8r4Jݶe֯[Hl4R!J@U+Yia&'S&D]Ш塖c- &k,k"`\RijsL`mAQI|=EY{vp£Z_~es +(S(_QII;<8 mҶPҞ`=#;omnjl`--fenf1 :FTȥ1D-ZZ>ky6Z]A[Kg-V(KdrJ56MɃ֖Wr?OgqUQ$.LwM{X!mNNQUUiӽiJ =1lBBi,U snpt>F'Ldn>|*a?[mUU eccc܋'(tvɌsV,B ^'*sHڳ ѹٙv9 m?-p>ikQҒ‚|ѐDNGMKKGFH(kEkxk5hM% +Y ffe  g"sEE^c{ÖOXm '|?BY)g)g^v1:? ctAھtH{H[WZ6hdgeRԦBj(6I)PجՐkfz)/oaqIYyEeuMm]=XZ8ԬmjFkZ}Qv*<QZ۫<7[j" +oEq%rcemk"LYdV,BK>TWV3 m\Zը@i(k%k:fd=`m@]}X ZgK6k;Z3X;4pyThzf s_JaM[*r +*սllll[k~Kl 7UKLs\L#~i m'1Vڗ8i@iiTWis@=%i1ju:"mJm6VjT`m6XkDkKUTOl['vlچ g"|خpac{Qv`іW"Wnzضb~,ŬvU-$ +󳑙pvltu!bi[Qړo%vUž"f%Q +Qբ^$AڍZZ Z6Xg-ZBbm%Z{X0Z79k?:ֶ]gzV۠t{| 0 e4+#9LKEeeJrЮ#s^Ah/ɡ]] I&Ih{t-(퉏8iߔKJ0H{ J[I-,7 mV4ը`iQbmhmLVo0桵%whS`mXov<^?=E-/-Ai=H)6]6YU 6YY[AkZvOh^5}4׉~ֶutu-a'b؞;/-E-boqEreƶ|qI2SbVY$h9h/9hEhBNF|^1Ei#Ҿ# G@ +9ۥ\^zmuxˁˋ+`W^666-;僣~߿)c ,_\%Az*  ZHZv!:'%mj1twvni?Aiy}-Օe%(ɠ%KQ*I(jje;vhS4bڜ\єW@Y[G=J["U8c m>k ڇ./mvavEQ]"-bpiqEsƶۨ'BXҲ\9K;KVQ+\DJZr3ݝ mH18J*EZڣD:Jڂ^Z$jԊM֦fffeckckABkK/!ke&5Y6xPKW]a-H;\rrqr+ˣ˳L_:::;wSI,,YYڿ$Bϯ]rbHH(z]>f H+Cm kұgYXڴM}nIk3k0ւMr`XmkMn[Oo_Cd..Y"0moh+zˀEr +ݐ`:::$w 2K:{; 6 Dh?^H&P8{݃}=NHk6i@T/i0fJvkw>6#3++{/c-簵o$XY[ ֪vw?DGٰ/,-\^KĖHۻȶeeE"syuEnd8=oE~9 %z]"hevt8 >wX;ͦV#V Vs&H9,-Z -ڽ{q$jj> }1gk JJYkZ%Volm0[690!vrjzvn~aqiy`{u-[7Aڊ%彅&n'Nظ_Ic!"gAބAU$gnvYmF=V Җ0ҞI&@gߥ}(nԲ֦f2W7ZZ+oT5Zd^_ S3slɴ}:ҖCg7qⓥf> E )3:m2h]Y^\La6]}=NŨj:yjSi_D}X4,vMeld!$$6'7/V֪4ZdNcRRliKr{eeM/qbc"gM +B|~vf:691F$X;ͦNQiښꪊ⢂(>#6;A!I+v3k k3SdmaqiYEVohRiuck[ea2a MMl/ Ӗr.E&Ll16r?D,,:dpZhsS C0i6kj45zFRUQVZ\$5iCici3{RQ,k9k֢Z{ih =-)He&Y7u,0l{DG'cS3I%Җ&-ˉ%M0?"c!77D&vf*69>6:I bhk1jeSCB&TV@io(1(ӄGrQI&v[DYZ.6++{/cY{6啒jL^ШTk:CKk{aFGF&&cK,e-[=-!SsWLGGG"~z0C(K0:=,?  v:6916:Iy.NQ+2iJ{!9gSqF@ڽYYiIianm-}*'O](,*)-M*MNoleֆ["mik-Ԗ-ˈː%:::WF97#2!K(3 Y,_A+v|tdx(|^7JZFYjjWkU%EXiOp֞>{Z[ MJuVohik7 ‘v +bOI[u-[-V.K.k.VvOvG +e%9mqvld8 ~ iMm-YljWjk$UP(9iX'ii1f$#FڍQZ= hmv2knemn^~AQqiYEF*54*Ulakw9`PtxVXl +jKpy26 EbeIfg٠M,ZP8äp9 i,fVR66eIeEYiqQA~^VM&m66I6 Kvkw%X6'Yo }'>:3r%e啒ji\QؤR7F"lNנ Cm6i 7EErz?=dXYY׿b:Ag!h#` "iz]ZXJ%e%ŅPڜsgN|J[oL'IE@]Uڭ}6ouqD{?@A$H=2vg$v qޫM6)Ph-t7iINtCtyG|^zoǨ*^ jjTsk:Nvdl|r +¹ť |zs%[6m묶$n\*.1++g2/|yQac1Y0hAB{ @O?xna&Ml9՘LĢPHc=i iwm{ieͷvk_g=X`d*#x]}!Қiua;619=v,bmm1˭-Ebtw{e + bdEef?!q )Yh?^Z<vfzrbLHڎ\[)ՐW"`uW96d( +~,k@W-/vvv־%cmIYZZlvH:^[hhl*ۉsgϝ_Lvy`KӖj-VKE"s1]L9{Ra!X,e5, Zʲg ϝ;=;=5QM xu4 +}iYZ(DFڷ,_4jڝXoK/Z6kqjZZBh&^H6[B ð=37 -w(nn"D\l.Q+7>>>b\7OW$,5V@)+2r;{Wp ZhL6ҜjL&5h8{=U.hi5j*qVڷ }}6vVZyk>CrR֚,VYp$&C#Ӆ~qkh{ms x ťRu~+埙rbYԲDYTYK_B;=91>:2$H8yUNj1Ai+*H{H{LHEk#ka=-S(+ԕh2[mZ E59}f,v6/mYmܽ'zRrX].cL<9|z% %Jwl~Њ.hΝ9=3=51>62<8%Iښh$>>߻.C?36V@,ed낳B"ha"hh'FGz:sY1iձH8yU.j1 z-V==}J=L>R־(Yhuzb9Un E6?08<2:] +i+j%ޮ%Br]® _>>>{l%g1E) 1+akߋβA]Ў tuv6 +}waZLFNQ#iKG}~SX!\T+5:dNWmjid;:{diKڮPmqx}r+Kąbt]ޟ$F +޾u2zG,,}=ݝmLkKr96d4jRQ^ +=^Zykw[-׭z\A5Z{W ̜~O +#VedEYYa9 gpv6)@{zrcc#}IIg7uI;_iWvRmy[[/rت[vnX۱mݽ}Cã`{6=Vpeo\.\%s ]o-e׿ݷ=aX1!+1ݷO=f=q6!gvtxh%$Hڶ$-'Y++IyXr"lZmv=C#8=`{AM-kq:pE\"etY]q_qqqqS%aX됥}o'iٻ^h/О@oOw6Ү|i֮5bmYېe- +}&lCEa`;l'N_L`kqk5:p!#u]Cogqqqq~YeMy?0"k5"g}g^N@; h0AEҾgv%Iڴ $mH[3oiWTsvMlmN-j-¶=ۮ^`;l 퇊m2mUVpxસJ.**oُ˓A2Y8{[M@vC I{8HvIZփV-9:S5K@ڐ[[ڬݝC: Kb ո5Vq\2נ:{#...n/ܱ^%aA:e|u_59l& ݀Cݝ"FH[x!.rj_l-mZm ۃGvv~v|Imry q\2Wev^߂Wy ޷+ +Ċ,)159[ُ3m?Hڃ.il҆67Eڅ[K؊|Xۨֆؒ6lq[`ۗi`h noijoW%s ]aW5+?wiaXk5_0ll4}G _$hmB6i\JK.Uij :-짰[¶6 V㖹%oXo\%s ]Vٵz{W Kߗ6svOW2NYYfVs!ΦV=C9L"i I6uF Fڗ kz +dZ Wz0aw-E2=!H@[-׭x J.Ux[}WfN/CC&VUdI/DYYYr!=Z$-CIÃVmi&i%]/ +۞Y־BrB"l9l[7g[mV6؎Xli+^!m7gĭց q\2v]cQ=[$+Uާٟ{2$ c-FYb3,!gUhG +-UhI65BڍPr5$+YҮBBE64bbkr*]ѱ$k̭[Vq\2eu]C7øJXܵ`0urf$c. -VUhXH[I[I[t}1B¶X$k9l-m li+~L"n"n7g[m.Ur\Qxe_W ]+ +bEby0 g/A[ +Z$6,mK3I[uu|>W]nE6rضڰMba;7l}m qkuB\%%t]⫻[~~)Q]XVY,1;cEΒ}g +-6 MVNZHѓvCBuKYZ–B]=¶¶|& i5ڼeo\%s ]aW:S\\\b^qyO' bXE(11 g?rABۙ\Ғ Pr$-A<]&lEmf 9a砭-s{vfƂ˅ q\2v]v*iM+K‚X%kE̲Y8{w6+h&fNZH[,UiM.ijzkm5Y[kE6RnJܱڞbm@[[4qkN\#.K貺5<...2|]W2 du쥋p ;{8;hSIK6BڍFZJ~H6a9Y z f/la7^9z+ +KĒUVM}m.@[%z qi'@ZMcyksaövvv; b}cXipyL. 2wy|>%[b&IX"Ed\lG,I*i7][#hLfiX y ۥ +GN1`j~Rn.EtQ]dW5gΛWV%c٠2 Eg?ghh;*iWV0iI; io k 6 9fN!`{Fi[i{NھCm)n[-Kr\@%xi?|ú蚅#W/$K"AYeVrr9[(h#0vv5I;&&JkmmSŰUl3UڞشiqF + n Eu]Wcq|˵59vtL,+ZeYٜ_h JvLkѰ]X\ZZ^YY]+c[IJSׯ߼EpI\&Wt]~|!Z툅 d,"k}oSrVyڵՕ%v&MZWzb`;.Nv¶n^ +8mo߽'no\s]T |ûɡ= d +K̾f1gSgMV>ݫ-C;vB7Zi5ka;>l@KEl= ik}qzvbZn[er\Rz7维+].saX2Ue#f1g_<;;}a A[A_vyiqKmLڱI{mg퍂qcj&lu=дi▸pA\&%u]7 kr|e_QX d#es`s,mm6Ю2 -H ֒6#k^a >,ax!l5mO"m9n-쭀K2b. +Z]Z\+sD,+Ȳ'GmC)iӤ=i61R*m%mS6 `.슼A߰?|>0.=fz}EaX5fOْݽ= K|mYiakvJ–Ű`زmܲns]TzyO>wkqisG# j ֘M}vxp";;[[YhAZv**mѐnma; N'a[cim]H۠1hs{Kq\4%vEޠo|>o3r^aX5gO]pA>CkvܤjŖövŴ@ִrA\ EtQ]vWnGVaX5Eesfg1h6ڕ&h%i'JI;^c{ٰmv]l9mw!mF,--h. +߰>7K^:|oXec YlYT6Ǭqv}rnnM5i/ul5V16-z}KಸB.2"/]v}>/{쁓G'bXB[19g5h!h vԤmk 6;S`m[5ikm#n[ \Es]TW |>߰/>kz`AX e#fY Zv ]vMB^[;@F/`mM⭂ +h.2,a>7|2sHחtOYX!Je3f6m%m%(Hۿ&l---k>#n.䢹.F{|~eO=:_@,ȊlٖN֥֒ư%l/26[6mmr\V ..zݫ躽 +`"+b"6g{:[ vJ홴.-lа NͦmV[[\WEsI]q7+^|>ŬݑWz"( *,Ƭ٬٠-B;֓Y{[¶`۬V J.ꊻ^|>߰~¹GWX06 +bZf]-C;Afh=i{z؎%a[a@մiq+Jޒ.䢹k[eoµG 2,Ƭ09sV}@V7BҎk{N3m­6"h.|kc ?:_ +bl@(+bΦΦA;GA[NmI;z^k Qؖ'l1m)mk-ƭpx+H.K蒺 +7ى ,#>XcDوYtv-rvŠ%h6B{+mE6m^[ۊی䒹j[f?B ֕%f1gΆ m 'm6v [vF6v]m[[WEr]R7Mkk!@:(,+f+flY v .m̈́m_Jm-".+Z{|>߰p{'" +ĊleVr6rv5ARҺ 1m-m3ښ ܲ[-"dZz͞|>0/s+HH, eVr6leho%zҶYmzڒsA8n[52nW|Ǘ JĬYuv.8m7uis?J1l{cI[v6j[(.Kv5^终:X OZdAY(gmmmuiqmBǴ}0[VUpQ\"u u|>ENo -%ȂufY~1h`a?I Zo#pI\"WUv#z=|]'/&f#ggKk؊iچemkZo(.+芺 >w%9=X"6 Zek̲g㠝4ζ֓Yl6֖pyq\EWٍMP+^4se\EdY٬-@I;ؚD{[66ksU] o`K\8rBcY09;C&~..m ښUn.K*ݘt5}>r|[ȷq9Ue~6Pݶif 4ER%I8{XlKgrҮRbkk[;eo/]TW 0ݹ<*^W27;ee9:MCKi0}[bۮr~VW7GWdW(J W4|͑l:fsYڟNh9i ~]rkqՕ GaN಍^"+Kf~ΎvöfmunMo/U]+kD;oj]LC)#YvgCIJ㰭Ŷ8msmOs[kp-k) +M_4Dd]"[9etҝ-R.7=m?O=ފ67%wiʮߖ)c =i$쥳gu^%[S۷~-[[[\J~ slu3ed/g쥳_}}tRؖ=2m +)n`xRc'*☽\=^:uЪRZmen漵MU5ݵjD4qj DTǬf9t>3bQwQ2ޚZ# NmaXYy̪~vvZJbj[\\ܢVJ`…cG25VGZY'vU5չprkz++[v +_)]̪. s+z+kVwm`+QmS(vگ=\[[[\]\] `ndEesfvK/b[[[\'awQ_Y/CKi^] WΤQ"tv@menUoMp$XC;o̮,}F,n[lL%UYB GhVVga9U+k2;YBXjkr{]x9R5f_=zjks[\ {XgvN~en:mW^Oe-Y-xg祍ɭjq /7Lgw.@ݹJ.pL珧+2KgwwphVV՟ր u6,.b: Oɪv .osgG r.=v x5lLN z>c,}]_[ zƴsgc:?kWo.;dzUz?PpI/f&Vxv0w^ܖhT`/~ى͌~z cV8V= :; + Mqfwwwb~pswY "~t2f>f> endobj 263 0 obj <> endobj 305 0 obj <> endobj 306 0 obj <> endobj 307 0 obj <> endobj 308 0 obj <> endobj 304 0 obj <> endobj 309 0 obj <> endobj 310 0 obj <> endobj 311 0 obj <> endobj 251 0 obj <> endobj 252 0 obj <> endobj 314 0 obj [/View/Design] endobj 315 0 obj <>>> endobj 312 0 obj [/View/Design] endobj 313 0 obj <>>> endobj 258 0 obj <> endobj 259 0 obj <> endobj 260 0 obj <> endobj 261 0 obj <> endobj 256 0 obj <> endobj 316 0 obj <> endobj 317 0 obj <>stream +%!PS-Adobe-3.0 +%%Creator: Adobe Illustrator(R) 17.0 +%%AI8_CreatorVersion: 23.0.5 +%%For: (Mart\755 Climent) () +%%Title: (customcolor_icon.ai) +%%CreationDate: 1/23/2023 6:33 PM +%%Canvassize: 16383 +%%BoundingBox: 252 -2321 2151 148 +%%HiResBoundingBox: 252 -2321 2151 148 +%%DocumentProcessColors: Cyan Magenta Yellow Black +%AI5_FileFormat 13.0 +%AI12_BuildNumber: 619 +%AI3_ColorUsage: Color +%AI7_ImageSettings: 0 +%%RGBProcessColor: 0 0 0 ([Registration]) +%AI3_Cropmarks: 0 -2400 2400 0 +%AI3_TemplateBox: 1200.5 -1200.5 1200.5 -1200.5 +%AI3_TileBox: 910.762212753296 -1612.57507324219 1489.28219604492 -787.455114364624 +%AI3_DocumentPreview: None +%AI5_ArtSize: 14400 14400 +%AI5_RulerUnits: 6 +%AI9_ColorModel: 1 +%AI5_ArtFlags: 0 0 0 1 0 0 1 0 0 +%AI5_TargetResolution: 800 +%AI5_NumLayers: 2 +%AI9_OpenToView: -3078 1102 0.177083333333333 1616 940 26 1 0 1966 90 1 1 0 1 1 0 1 1 0 0 +%AI5_OpenViewLayers: 77 +%%PageOrigin:1112 -1304 +%AI7_GridSettings: 72 8 72 8 1 0 0.800000011920929 0.800000011920929 0.800000011920929 0.899999976158142 0.899999976158142 0.899999976158142 +%AI9_Flatten: 1 +%AI12_CMSettings: 00.MS +%%EndComments + +endstream endobj 318 0 obj <>stream +%%BoundingBox: 252 -2321 2151 148 +%%HiResBoundingBox: 252 -2321 2151 148 +%AI7_Thumbnail: 100 128 8 +%%BeginData: 15840 Hex Bytes +%0000330000660000990000CC0033000033330033660033990033CC0033FF +%0066000066330066660066990066CC0066FF009900009933009966009999 +%0099CC0099FF00CC0000CC3300CC6600CC9900CCCC00CCFF00FF3300FF66 +%00FF9900FFCC3300003300333300663300993300CC3300FF333300333333 +%3333663333993333CC3333FF3366003366333366663366993366CC3366FF +%3399003399333399663399993399CC3399FF33CC0033CC3333CC6633CC99 +%33CCCC33CCFF33FF0033FF3333FF6633FF9933FFCC33FFFF660000660033 +%6600666600996600CC6600FF6633006633336633666633996633CC6633FF +%6666006666336666666666996666CC6666FF669900669933669966669999 +%6699CC6699FF66CC0066CC3366CC6666CC9966CCCC66CCFF66FF0066FF33 +%66FF6666FF9966FFCC66FFFF9900009900339900669900999900CC9900FF +%9933009933339933669933999933CC9933FF996600996633996666996699 +%9966CC9966FF9999009999339999669999999999CC9999FF99CC0099CC33 +%99CC6699CC9999CCCC99CCFF99FF0099FF3399FF6699FF9999FFCC99FFFF +%CC0000CC0033CC0066CC0099CC00CCCC00FFCC3300CC3333CC3366CC3399 +%CC33CCCC33FFCC6600CC6633CC6666CC6699CC66CCCC66FFCC9900CC9933 +%CC9966CC9999CC99CCCC99FFCCCC00CCCC33CCCC66CCCC99CCCCCCCCCCFF +%CCFF00CCFF33CCFF66CCFF99CCFFCCCCFFFFFF0033FF0066FF0099FF00CC +%FF3300FF3333FF3366FF3399FF33CCFF33FFFF6600FF6633FF6666FF6699 +%FF66CCFF66FFFF9900FF9933FF9966FF9999FF99CCFF99FFFFCC00FFCC33 +%FFCC66FFCC99FFCCCCFFCCFFFFFF33FFFF66FFFF99FFFFCC110000001100 +%000011111111220000002200000022222222440000004400000044444444 +%550000005500000055555555770000007700000077777777880000008800 +%000088888888AA000000AA000000AAAAAAAABB000000BB000000BBBBBBBB +%DD000000DD000000DDDDDDDDEE000000EE000000EEEEEEEE0000000000FF +%00FF0000FFFFFF0000FF00FFFFFF00FFFFFF +%524C45FDFCFFFDFCFFFDECFFA8FFFFFFA8FFA8FFA8FFA8FFA8FFA8FFA8FF +%FFFFA8FD56FFA8FFFFFFA8FD58FFA8FFA8A8A1A8A8A8A1A8A8A87DFD04A8 +%FFA8FFA8FD50FFA8843536353C3536353C3536353C35A8A8FD50FFA8FFA8 +%84131413131314131313141313131435A8A8FFA8FFA8FD4EFF351A131A13 +%3C131A133C131A133C133C7DFD50FFA8FFA835131A1313131A1313131A13 +%13131A13A8A8FFA8FFA8FD4CFFA8FF591A133C131A133C131A133C131A13 +%3C7DFFA8FD4CFFA8FFA8FFA85A131313141313131413131314131313A8A8 +%FFA8FFA8FFA8FD4CFF591A133C131A133C131A133C131A133C7DFFA8FD4C +%FFA8FFA8FFA8601313131A1313131A1313131A131313A8A8FFA8FFA8FFA8 +%FD34FFA8FFFFFFA8FFFFFFA8FFFFFFA8FFFFFFA8FFFFFFA8FFA8CA351A13 +%1A133C131A133C131A133C13357DCAA8FFA8FFA8FFA8FFFFFFA8FFFFFFA8 +%FFFFFFA8FFFFFFA8FD1CFFA8FFFD1AA87DA87D5913141313131413131314 +%13131314137D7DA87DA87DFD18A8FFA8FFA8FD14FFFD06A87DA87DA87DA8 +%7DA87DA87DA87DA87DA87DA87DA87DA87D7D351A131A133C131A133C131A +%133C133552A17DA87DA87DA87DA87DA87DA87DA87DA87DA87DA87DA87DFD +%04A8FFA8FD12FFA8FFFD04A87D7D527D527D527D527D527D527D527D527D +%527D527D527D527D527D5235131A1313131A1313131A1313131A1352527D +%527D527D527D527D527D527D527D527D527D527D527D527D527D7DFD04A8 +%FD10FFA8FFA87D527D527D527D527D527D527D527D527D527D527D527D52 +%7D527D527D52762E1A133C131A133C131A133C131A13355252527D527D52 +%7D527D527D527D527D527D527D527D527D527D527D527D52A8A8FFA8FD0C +%FFA8FFA8A87D7D5252527D527D527D527D527D527D527D527D527D527D52 +%7D5252527D52524B3513131314131313141313131413140DFD08527D5252 +%527D5252527D5252527DFD0B527DA8A8A8FD0DFFA87D7D527D527D527D52 +%7D527D527D527D527D527D527D527D527D527D527D527D52762F1A133C13 +%1A133C131A133C131A13365252527D527D527D527D527D527D527D527D52 +%7D527D527D527D527D527D527D527DA8FD0CFFA8FFA87D527D527D527D52 +%7D527D527D527D527D527D527D527D527D527D527D527D52524B35131313 +%1A1313131A1313131A131413FD08527D5252527D5252527D5252527D5252 +%527D5252527DFD05527DA8FD0CFFA8A8527D527D527D527D527D527D527D +%527D527D527D527D527D527D527D527D527D52522E1A131A133C131A133C +%131A133C133527FD04527D527D527D527D527D527D527D527D527D527D52 +%7D527D527D527D527D7DA8A8FD08FFA8FFA8A8527D527D527D527D527D52 +%7D527D527D527D527D527D5252527D5252527DFD04525135131413131314 +%131313141313131A13FD0A527D5252527DFD14527DA8A8FD0AFF7D7D527D +%527D527D527D527D527D527D527D527D527D527D527D527D527D527D527D +%52762E1A131A133C131A133C131A133C13352776527D527D527D527D527D +%527D527D527D527D527D527D527D527D527D527D527D527DA8FD0AFFA87D +%527D527D527D527D527D527D527D527D527D527D527D527D527D527D527D +%5252527D5235131A1313131A1313131A1313131A13FD06527D5252527D52 +%52527D5252527D5252527D5252527D5252527DFD0552A8A8FD08FFA8A87D +%7D527D527D527D527D527D527D527D527D527D527D527D527D527D527D52 +%7D527D52762E1A133C131A133C131A133C131A13355252527D527D527D52 +%7D527D527D527D527D527D527D527D527D527D527D527D527D527D7DFD0A +%FF7D7D527D527D527D527D527D527D527D527D5252527D5252527D525252 +%7DFD06524B3513131314131313141313131413140DFD2452A8A8FFA8FD06 +%FFA8A87D7D527D527D527D527D527D527D527D527D527D527D527D527D52 +%7D527D527D527D52762E1A133C131A133C131A133C131A13355252527D52 +%7D527D527D527D527D527D527D527D527D527D527D527D527D527D527D52 +%7D7DFD0AFF7D7D527D527D527D527D527D527D527D527D527D527D527D52 +%7D527D527D5252527D52524B351313131A1313131A1313131A13140CFD08 +%527D5252527D5252527D5252527D5252527D5252527D5252527D525252A8 +%A8FFA8FD06FFA8A87D7D527D527D527D527D527D527D527D527D527D527D +%527D527D527D527D527D527D52522E1A131A133C131A133C131A133C1335 +%27FD04527D527D527D527D527D527D527D527D527D527D527D527D527D52 +%7D527D527D7DFD08FFA8FF7D7D527D527D527D527D527D5252527D525252 +%7D5252527D5252527D5252527DFD05522E13141313131413131314131313 +%1A0CFD24527DA8FD08FFA8A87D7D527D527D527D527D527D527D527D527D +%527D527D527D527D527D527D527D527D52762E1A131A133C131A133C131A +%133C13352776527D527D527D527D527D527D527D527D527D527D527D527D +%527D527D527D527D527D7DFD08FFA8FFA87D527D527D527D527D527D527D +%527D527D527D527D527D5252527D5252527DFD05522E131A1313131A1313 +%131A1313131A0DFD0A527D5252527D5252527D5252527D5252527DFD0952 +%7DA8FD08FFA8A87D7D527D527D527D527D527D527D527D527D527D527D52 +%7D527D527D527D527D527D52762E1A133C131A133C131A133C131A13354B +%52527D527D527D527D527D527D527D527D527D527D527D527D527D527D52 +%7D527D527D7DA8A8FD06FFA8A87D7D527D527D5252527D5252527D525252 +%7D5252527D5252527D5252527DFD06524B2F131313141313131413131314 +%13140CFD24527DA8FFA8FD06FFA8A87D7D527D527D527D527D527D527D52 +%7D527D527D527D527D527D527D527D527D527D52762E1A133C131A133C13 +%1A133C131A13355252527D527D527D527D527D527D527D527D527D527D52 +%7D527D527D527D527D527D527D7DA8FD09FF7D7D527D527D527D527D527D +%527D5252527D5252527D5252527D5252527D5252527D52524B351313131A +%1313131A1313131A13140CFD08527D5252527D5252527D5252527DFD0F52 +%A8A8FFA8FD06FFA8A87D7D527D527D527D527D527D527D527D527D527D52 +%7D527D527D527D527D527D527D52522E1A131A133C131A133C131A133C13 +%3527FD04527D527D527D527D527D527D527D527D527D527D527D527D527D +%527D527D527D7DFD08FFA8FF7D7D527D5252527D5252527D5252527D5252 +%527D5252527D5252527DFD08524B2E131413131314131313141313131A0C +%524BFD22527DA8FD08FFA8A87D7D527D527D527D527D527D527D527D527D +%527D527D527D527D527D527D527D527D52522E1A131A133C131A133C131A +%133C133527FD04527D527D527D527D527D527D527D527D527D527D527D52 +%7D527D527D527D527D7DFD08FFA8FFA87D527D527D527D5252527D525252 +%7D5252527D5252527D5252527DFD09522E131A1313131A1313131A131313 +%1A0DFD24527DA8FD08FFA8A87D7D527D527D527D527D527D527D527D527D +%527D527D527D527D527D527D527DFD04522E1A133C131A133C131A133C13 +%1A13354BFD06527D5252527D5252527D5252527D527D527D527D527D5252 +%527D5252527D7DA8A8FD06FFA8A87D7D5252527D5252527D5252527D5252 +%527DFD12524B2E13131314131313141313131413140C524B524B5252524B +%5252524BFD18527DA8FFA8FD06FFA8A87D7D527D527D527D527D527D527D +%527D527D527D527D52532E522E522E522E522E522E522E1A133C131A133C +%131A133C131A13352E522E522E522E522E522E522E52527D527D527D527D +%527D527D527D527D527D527D527D7DA8FD09FF7D7D5252527D5252527D52 +%52527D5252527D5252527652351314131313141313131413131314131313 +%1A1313131A1313131A1313131413131314131313141313131A13FD1652A8 +%A8FFA8FD06FFA8A87D7D527D527D527D527D527D527D527D527D527D5252 +%131A131A131A131A131A131A131A133C131A133C131A133C131A133C131A +%131A131A131A131A131A131A131A2E52527D5252527D5252527D5252527D +%5252527D527D7DFD08FFA8FF7D7D527D5252527D5252527D5252527DFD06 +%522735131313141313131413131314131313141313131413131314131313 +%141313131413131314131313141313132E4BFD14527DA8FD08FFA8A87D7D +%527D527D527D527D527D527D527D527D527D52765236133C131A133C131A +%133C131A133C131A133C131A133C131A133C131A133C131A133C131A133C +%131A13355252527D5252527D527D527D527D527D527D527D527D7DFD08FF +%A8FFA87D527D5252527D5252527D5252527D5252527DFD04522E13131A13 +%13131A1313131A1313131A1313131A1313131A1313131A1313131A131313 +%1A1313131A133527FD16527DA8FD08FFA8A87D7D527D527D527D527D527D +%527D527D527D527DFD04522E1A133C131A133C131A133C131A133C131A13 +%3C131A133C131A133C131A133C131A133C131A13354BFD06527D5252527D +%5252527D5252527D5252527D7DA8A8FD06FFA8A87D7D5252527D5252527D +%5252527DFD0C522E14131413131314131313141313131413131314131313 +%14131313141313131413131314131327FD18527DA8FFA8FD06FFA8A87D7D +%527D527D527D527D527D527D527D527D527D527D527D52522E1A131A133C +%131A133C131A133C131A133C131A133C131A133C131A133C131A133C1336 +%27FD04527D5252527D527D527D527D527D527D527D527D527D7DA8FD09FF +%7D7D5252527D5252527D5252527D5252527DFD0A520C1A1313131A131313 +%1A1313131A1313131A1313131A1313131A1313131A1313131427522EFD18 +%52A8A8FFA8FD06FFA8A87D7D527D527D527D527D527D527D527D527D527D +%527DFD0652131A131A133C131A133C131A133C131A133C131A133C131A13 +%3C131A133C131A2EFD08527D5252527D5252527D5252527D5252527D527D +%7DFD08FFA8FF7D7D527D5252527D5252527DFD10524B52131A1313131413 +%131314131313141313131413131314131313141313131A0C4B27FD1A527D +%A8FD08FFA8A87D7D527D527D527D527D527D527D527D527D527D527D527D +%527DFD0452131A133C131A133C131A133C131A133C131A133C131A133C13 +%1A131A2EFD06527D5252527D527D527D527D527D527D527D5252527D527D +%7DFD08FFA8FFA87D527D5252527D5252527D5252527D5252527DFD0A524B +%2E1314131A1313131A1313131A1313131A1313131A1313131A131A0CFD1E +%527DA8FD08FFA8A87D7D527D527D527D527D527D527D527D527D527D527D +%527DFD06524B35131A133C131A133C131A133C131A133C131A133C131A13 +%1A13524BFD08527D5252527D5252527D5252527D5252527D5252527D7DA8 +%A8FD06FFA8A87D7D5252527DFD1A52273513131314131313141313131413 +%1313141313131413141352275227FD1C527DA8FFA8FD06FFA8A87D7D527D +%527D527D527D527D527D527D527D527D527D527D527D527DFD055235133C +%131A133C131A133C131A133C131A133C131A13FD08527D5252527D527D52 +%7D527D527D5252527D5252527D5252527D7DA8FD09FF7D7D5252527D5252 +%527D5252527D5252527D5252527DFD0C522735131A1313131A1313131A13 +%13131A1313131A132E27FD2052A8A8FFA8FD06FFA8A87D7D527D527D527D +%527D527D527D527D527D527D527D527D527D5252527DFD055235133C131A +%133C131A133C131A133C131A132E4BFD0A527D5252527D5252527D525252 +%7D5252527D5252527D527D7DFD08FFA8FF7D7DFD22522713131413131314 +%1313131413131314132E2752525227FD1E527DA8FD08FFA8A87D7D527D52 +%7D527D527D527D527D527D527D527D527D527D527D527D527D5252527D52 +%522E3C131A133C131A133C131A133C143527FD08527D5252527D527D527D +%5252527D5252527D5252527D5252527D527D7DFD08FFA8FFA87D527D5252 +%527D5252527D5252527D5252527D5252527DFD0E522E1A1313131A131313 +%1A13131335275227FD22527DA8FD08FFA8A87D52527D527D527D527D527D +%527D527D527D527D527D527D527D527D5252527DFD06522E1A131A133C13 +%1A133C133527FD0C527D5252527D5252527D5252527D5252527DFD07527D +%7DA8A8FD06FFA8A87D7DFD26520C1A13131314FD0413275227FD24527DA8 +%FFA8FD06FFA8A87D7D527D527D527D527D527D527D527D527D527D527D52 +%7D527D527D527D527D5252527DFD0452351A133C131A13362EFD06527D52 +%52527D527D527D5252527D5252527D5252527D5252527D5252527D525252 +%7D7DA8FD09FF7D7D5252527D5252527D5252527D5252527DFD16524B522E +%131314133527FD2852A8A8FFA8FD06FFA8A87D7D527D527D527D527D527D +%527D527D527D527D527D527D527D527D527D5252527DFD0A5227524BFD0A +%527D5252527D5252527D5252527D5252527DFD0D527D7DFD08FFA8FF7D7D +%FD285227524B522752525227FD26527DA8FD08FFA8A87D7D527D527D527D +%527D527D527D527D527D527D527D527D527D527D527D527D527D5252527D +%FD0F527D5252527D5252527D5252527D5252527D5252527D5252527D5252 +%527D5252527D527D7DFD08FFA8FFA87D527D5252527DFD51527DA8FD08FF +%A8A87D52527D527D527D527D527D527D527D527D527D527D527D5252527D +%5252527D5252527DFD13527D5252527D5252527DFD17527D7DA8A8FD06FF +%A8A87D7DFD57527DA8FFA8FD06FFA8A87D7D527D527D527D527D527D527D +%527D527D527D527D527D527D527D527D527D527D527D527D527D5252527D +%5252527D5252527D5252527D5252527D5252527D5252527D5252527D5252 +%527D5252527D5252527D5252527D7DA8FD09FF7D7DFD5752A8A8FFA8FD06 +%FFA8A87D7D527D527D527D527D527D527D527D527D5252527D5252527D52 +%52527D5252527D5252527D5252527D5252527D5252527D5252527D525252 +%7DFD1D527D7DFD08FFA8FF7D7DFD57527DA8FD08FFA8A87D7D527D527D52 +%7D527D527D527D527D527D527D527D527D527D527D527D527D527D527D52 +%7D527D527D5252527D5252527D5252527D5252527D5252527D5252527D52 +%52527D5252527D5252527D5252527D5252527D527D7DFD08FFA8FFA87DFD +%57527DA8FD08FFA8A87D52527D527D527D5252527D5252527D5252527D52 +%52527D5252527D5252527D5252527D5252527D5252527D5252527D525252 +%7DFD23527D7DA8A8FD06FFA8A87D7DFD57527DA8FFA8FD06FFA8A87D5252 +%7D527D527D527D527D527D527D527D527D527D527D527D527D527D527D52 +%7D527D5252527D5252527D5252527D5252527D5252527D5252527D525252 +%7D5252527D5252527D5252527DFD0B527D7DFD0AFF7D7DFD5752A8A8FFA8 +%FD06FFA8A87D7D5252527D5252527D5252527D5252527D5252527D525252 +%7D5252527D5252527D5252527D5252527D5252527DFD2A527DFD08FFA8FF +%7D7DFD57527DA8FD08FFA8A87D7D527D527D527D527D527D527D527D527D +%527D527D527D527D527D527D5252527D5252527D5252527D5252527D5252 +%527D5252527D5252527D5252527D5252527D5252527DFD11527D7DFD08FF +%A8FFA87DFD57527DA8FD08FFA8A87D52527D5252527D5252527D5252527D +%5252527D5252527D5252527D5252527D5252527D5252527DFD2F527D7DA8 +%A8FD06FFA8A87D7DFD525227FD04527DA8FFA8FD06FFA8A87D52527D5252 +%527D5252527DFD4B527D7DFD0AFF7D7D527D527D527D527D527D527D527D +%527D527D527D527D527D527D527D527D527D527D527D527D527D527D527D +%527D527D527D527D527D527D527D527D527D527D527D527D527D527D527D +%527D527D527D527D527D527D52A8A8FFA8FD06FFA8A8A8FFA8FFA8FFA8FF +%A8FFA8FFA8FFA8FFA8FFA8FFA8FFA8A8A8FFA8A8A8FFA8A8A8FFA8A8A8FF +%A8A8A8FFA8A8A8FFFD2AA87DFD08FFA8FF7DFD57A87D7DA8FD08FFA8A8A8 +%FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8A8A8FFA8A8A8FFA8 +%A8A8FFA8A8A8FFA8A8A8FFA8A8A8FFFD2AA87DFD08FFA8FF7DFD57A87D7D +%A8FD08FFA8A8A8FFA8FFA8A8A8FFA8A8A8FFA8A8A8FFA8A8A8FFA8A8A8FF +%FD40A87DA8A8FD06FFA8A87DFD37A87DA8A8A87DA8A8A87DA8A8A87DA8A8 +%A87DA8A8A87DA8A8A87DA8A8A87DA8A8A87D7DA8FFA8FD06FFA8A8A8FFA8 +%FFA8FFA8FFA8FFA8FFA8FFA8FFA8A8A8FFA8A8A8FFA8A8A8FFA8A8A8FFA8 +%A8A8FFA8A8A8FFFD30A87DA8FD09FF7DFD57A87DA8A8FFA8FD06FFA8A87D +%FFA8A8A8FFA8A8A8FFA8A8A8FFA8A8A8FFFD46A87DFD08FFA8FF7DFD2DA8 +%7DA8A8A87DA8A8A87DA8A8A87DA8A8A87DA8A8A87DA8A8A87DA8A8A87DA8 +%A8A87DA8A8A87DA8A8A87DA87D7DA8FD08FFA8A8A8FFA8FFA8FFA8FFA8FF +%A8A8A8FFA8A8A8FFA8A8A8FFA8A8A8FFA8A8A8FFA8A8A8FFFD36A87DFD08 +%FFA8FF7DFD57A87D7DA8FD08FFA8A8A8FFA8FFA8A8A8FFA8A8A8FFFD4CA8 +%7DA8A8FD08FF7DFD27A87DA8A8A87DA8A8A87DA8A8A87DA8A8A87DA8A8A8 +%7DA8A8A87DA8A8A87DA8A8A87DA8A8A87DA8A8A87DA8A8A87DA8A8A87DA8 +%A8FFA8FD06FFA8A8A8FFA8FFA8A8A8FFA8A8A8FFA8A8A8FFA8A8A8FFA8A8 +%A8FFA8A8A8FFFD3CA87DFD0AFF7DFD57A87DA8A8FD09FFA87DFD04A8FFFD +%52A87DFD08FFA8FFA8A87DFD1FA87DA8A8A87DA8A8A87DA8A8A87DA8A8A8 +%7DA8A8A87DA8A8A87DA8A8A87DA8A8A87DA8A8A87DA8A8A87DA8A8A87DA8 +%A8A87DA8A8A87DA87DA8A8FD0AFFFD05A8FFA8A8A8FFA8A8A8FFA8A8A8FF +%FD43A8FFA8A8A8FD0AFFA8A87DFD56A8FFA8FD0AFFA8A87DFD53A87DFD0C +%FFA8FFA8A87DFD17A87DA8A8A87DA8A8A87DA8A8A87DA8A8A87DA8A8A87D +%A8A8A87DA8A8A87DA8A8A87DA8A8A87DA8A8A87DA8A8A87DA8A8A87DA8A8 +%A87DFD05A87DA8A8FD0EFFA8A87DA8A8FFA8A8A8FFFD48A87DA8A8FD10FF +%A8A87DA87DFD49A87DA87DA8A8FD12FFA8FFA8A87DA8A8A87DA8A8A87DA8 +%A8A87DA8A8A87DA8A8A87DA8A8A87DA8A8A87DA8A8A87DA8A8A87DA8A8A8 +%7DA8A8A87DA8A8A87DA8A8A87DA8A8A87DA8A8A87DA8A8A87DA8A8A87DA8 +%7DA87DA8A8FFA8FD14FFA8FFA8A87DA87DA87DA87DA87DA87DA87DA87DA8 +%7DA87DA87DA87DA87DA87DA87DA87DA87DA87DA87DA87DA87DA87DA87DA8 +%7DA87DA87DA87DA87DA87DA87DA87DA87DA87DA87DA87DFD04A8FFA8FFA8 +%FD1AFFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8 +%FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8 +%FFA8FFA8FFA8FFA8FD20FFA8FFFFFFA8FFFFFFA8FFFFFFA8FFFFFFA8FFFF +%FFA8FFFFFFA8FFFFFFA8FFFFFFA8FFFFFFA8FFFFFFA8FFFFFFA8FFFFFFA8 +%FFFFFFA8FFFFFFA8FFFFFFA8FFFFFFA8FFFFFFA8FDD8FFFF +%%EndData + +endstream endobj 319 0 obj <>stream +%AI12_CompressedDataxdqb? ǽX 3"S˅($5#av(uZUW5{~>"2h͊wscf~q~t3>z߾ᣟPnz~{o~/Q޼8/_|۟~s/u_~7g/~>xzV_q02o~.^_07xwf_!1Bt^ox߼y>_pӳW_?yv/_g~s/ݿ|W!~v͋_7_s f>Uk]NWٯG{Q7xoϢO~~/onoy?zVo7 _~]3[{ٛ?<+xEY&W_HCxnB)CMIds֠OFBݸ4^nY +߿y~B@4.$x_ރ?!qS0֐|҇FWK揿IpB89 VJb_.W}g߼y ߵgy7W)s)(W +:ͳu }#sA~.ߟv?>݅[o^>{_74N%?~5%_iX|;:[W.ϴw7Ƅm;}Wݿ=^^g_7TW_|B6ŒzCx}7__\~NO_/rhx^|&},7Uo;\tsͷzn믮I_t}vL/xPP&e/= asook_"g_=Yznv_|I<ܽh/! +ëWϾVatkׅ'ǧ)[98 + :!Q.܆9P~)Ƶ{ +Ԣp꯷%~<Oi8STNt{;O~>~}Wݽ7CͳYVO4 % +)1T߱ֆd\jրj>(\7i列I{բZ}]DC( %[-^I.o~xtã[y0 {C ?7߼|7^''JeRԢÏ=AS[,$rvi'l(U{+?ܭjo aW;w](a` `;eВQM'8F_@Јg&aQvxl4v;i/A|Tӣ9yCNj1yHIVE:^G&nH'㫤ٮ{0º;q› ֬nxdCχ.#9]fghYSrɗ@ $ut 64j؎YBC'k{ $[Eo]4 +Ga4wWȩ>hH#ff:i$x{}DILJ%{AK0k&w-`@ZӜGI,a;ޟڟ-(dXHt懻];=ܯ 4~a6&}mYOG=Xѡ vDNc`YOVj吭T sׇc/t9қ+7Re޳=,ye"z晡fQHO%nv ^,lΒpV6_Q G{d ! +6fexe2 +G; 0V˞Omr[o .Rd9\%ъՒ(KcU"*{\r/]2ّ$%$ vҰfIO { QRvVϒH6 []\ʝ({[ Tu76[o'm' z@ȱÐř;r4+g+-#wͲY/0{ [@+@ 'vX2`΀$'I!I$H5$wFE\>vQWrw?v^񗞃v<<;ypl|$$?ǠciG`y6 +팧IE##IV<7Mޙ7юXva´Sa?X2rY]EQ:cgdm*+C,c,w-6\v9 +E;O;']8g֓]8q,UM|rx]1l^s cxcxO?iEܜMUܜw=]2i"ٹŲp^ڧپ3.=:֝;!҄njwڲ7ˢjHUfh'k|]KgOؚF[xxݿ{>? w֕+~puQ|(5G}]FQ>jb(+9iGy.eI˂(09 )l63=6 +#^|'ORJN 1iR8! +~~4QXi1 yLhz'iby_S-_}*J_(3Vuhb@` ԣB-<-4P݇AGzkzsKy=tlفL#a%lN|Mvo{L5ӸWVx㉟s_R7O)W|{ty۟wOSoymJoVYWl};0\m+yx=&1/>^,\-k7к +'Smkf+=MQm6|X)SHwIVje!}9Y k\-M}U8r#atmY.R+X6B +z29Q :MiDWJ-f] mOsp,1kp\seZk8JἭsAêG>䔮d&]qVztGo6?ĵvTޞ;*{swY9w֊SΚkr$>=<:ŔZ@h_6>!a]+6]=++->{56kO?~ݿ۴W<4Nї!mE:Y ɛlp :b?Za0I&ڇؖ +f,:y6~-i<%$x ֶvV{빓uqqulf;,քM1 GFVd+A[v;Q+M{27y9,2Z:Iz;6|H[R[5]}NMW|wkmڷ :FWT ԇEϒi?On~:r#"0k1Q}"x^y= D }jElĠ4%%(T-saB(`=?cCQe]vkǻwG Op#5^"ɋ"hj`U}2 +OZ/ô*zyo Jel*b\7[k(Vb]6l_q)xܕo?w+kI2{lOzvF78;vŕFWm]۪ GǍFo766lV<w.K?쩣e9uێg֎ jk8v 6k8R-Ӫ(RSGi8;piZOgEZKGmH6<> ?}Rds6t{le>`-lPv<Zc)4kuhQSl7僊}ܺfbe[*ەjif =-3B +,i=~-3ڙ4Ќk%ʹOԤOi^?qvmH2#׽ />Q%;Y&mtMh[*n;rC| m0ªk _eO{ /rb /i/ZmKZlimeiZ4oe6qY(,Xvh;籵?> +NLvuςpB7 +Bn=+n5zh EpQFܩFbRnwu)p +NqWj6 +aJOg*K㲔f鲘RJ;(ŴVeAmjFnӞ<}ZF&d=.wEꇅTM3zaJu5vЁ>lV\ݴl]S3{lcnvl;GhvfН1}PpZҞ†-_ag'8\~׽ڗMLhg;l2v"ݻFkx;mG׿|;,r`2)i} N J?dYׁܭ>:x*;ɶz2OMDNVxHNRE^ ǘOre ݱy Od]ONpJ>x"O犖KJHi\ +׍Z͏ ń&j$,q0s`a/Kkqz,i_$ia?(5fn5X='*X Ģ  3zGF~epc>o=Jsx;<x=dȎ.x_ZWtx;g XYt%Js'kzՖRVݸD-NKqYh~z㱭2[츅\`/Wo++hwuOoi0|"+k(ۗ1q69_-SVׅ6M[VlmOsvú|wLP%|^G~l_ R׶sկh~-E 4xA{9'?=vOos@o^'ʷvS Ivji$UXل }\ǡLS2dibyUqץe^oƧACަۅ#SCXƤ-0ԐC9oPnicv'Ixv{њIZZ!m(?/ no{< 2p#޶i)sY5>#r4j}vp# wtZ3gR{'<-<2 ӣ +G`oXݱ;z;gݴ< 5x?X3H巁m.-iu;Aػv\ՎF<} c%b0%>흠MP^;瀆<|"g~C.WϾo`%yw@9Kݱ۝Q.) 5&~!MAjBZMLiwlqS|٥/`.2u٭싶 +.2snˤ%چ㑓,fM8UZɳ׵Mg)w+FjhC~K% 2V}ZX哢4ǵ&ʹ:BC-l^T88Nek.e[\]Ց}`XEEkMW<䝞GvU׊I7ilQh”\|g^Fsܙ퐼]dgZmG2k\]']]]]!^5׏ϝ_Μ߻v  th`t +ڜA;hXNnN'\-ߒ.Q#s`Jw+DfR-SSw NZR`X)Q jt}iE9uGtӚ>%z_G>jkzs>nK(<>o`"6ե}OxzAEoFOՌRv|=UkOR~w'_%]HtR4] !;KcxLqg\>3\;s+nv}<3wJU8OCHJΚ9j!2%` }$')NsgC{ +=Ҹs_bϘb؇;sL@7!aʱY nsCc `BB{xWi2B<Awκ骳ntue^;@Zԝo+cPO?"u:kӝ.Z_NC>(JNI"~w,b%[EIý|z]a芝8 re)k??KY-uǥAleKWe&7,SF7 q )Ņ%鸞=E7#LXbRUzEgkovinY[1IչDmԑ2۩CYM&Kn~{bgkzoZ\̶]Imvg>nFˠٮg>7rۣlgYdz }Tc5vƗg,UDvk5f{M0tW}37rY>wjSi.!o ęM]m.{mthדv=;N룗w_pEߪĦ].KǷc.ލK[#d;{=a($~r(98+8Mޮ&^f2X'Y5{;e]ݖk4}T w++!M_!";M,v%al@aspp2 }9ݡܙ!#0g.^r+6U* h}OdwI÷A2= ^%V"73,q?&mF{?Y=[y]gVZ4fw?u3,yB6ZzEorjˬ}geeH<,]3yK&}~[4`@Шg!k3'R~gu#gGM)?0v (S1rk|;Fl17_|k͉9R6 y|#u{{([IIoh|ڞ6~>rڻ~[ˈ7cڱʿ7yP"ݞm{'ܞj-QS/R׮g?ӝ?EiN3E:I"=kX=\+yDЬe-YI?#Xwܮ:|W]Z-4߻qMzd`&56ܹKn;?7S5GOt'c#C@jK8Ǘձv_]8;MXh;.ٻK~q3Ykvqn%Skk֧l-UZ]v.{aځ:wﹹ_q2s^}b:~w^JV+ŷwou^Zgߗo9ϥl:c+kpjL\Ϟi4Dl.VKiH"vY>D_&.~y˅dbCephswY^pqh蚄3M$f/;S:psglvW6\] m*ltOWwr +3JڨX\Ghgn#w O.ܸ>)̮́{Q:ссG(eLK&c9p:?\Y)G-߿}t6fNZO!/~0YF.}kܨ3҅L=}g?>IAoC%!qyM3Og r9 5D)8juH&>mI0L_|Ke_pׯ~ū/^ػ|}R7޾}/?k=8pPD,&s$i$y:q3o͔S4V?7/hoWO3]%`՛~`7}ſӋ߾xٛ?~뗇Og_xgw>7Mgg}۟3וAmOߴڇE< SĀp{:^|3Ib1s@8_:MDW |K<9RNēXzX/7ZvT$mt(.PR4}@MVo=E;-r҈js7&nZz2cr/&>>}^`Vv@^F['9}3SDɉť]$患q4AcۈG)ZV_!"bCh1Ƃ2%>ESiD}3䁵NRfPAsy3rF4FRW1 +H`Vb;.. ,Z1"El6`Y?,mҵsJ<ϫ/cF$G_7з$ɥʀIM/b$ciR~gɴ\MS!ޟ5NMUfzW.>7%]uY6)4*ZLx)ީTpE#uq%@&D)Tx#BM0{P#;dZ Azh #1M S:H8Rĭ$ƲWYC"v3CòBC&5j Lj{ѷy T~IIY|tsRuD/>Y&`(D$Ryˉ+E12i/ڐdhhܧeJKzW*RɫTT$8tcOHe Ej֛8+XXقIE'-5YZ僵X#֢;~P7ݴ8eZ,6dY,s {'o"MжmC jW!Ŋ h4𓁜r=ٕ>,1pI(ӃBZYH l@{C*=30HU5E8ש-$80@(Y]$JiC{ FSRbC(bBJcUʉlZ,\zoz30>EJ{6[&N"őJI|;$qxݔabL%6 +ɔՆ#EhNЃ;Lm; h~Ӏ?B"U@z8HL.BE-=q~b|V3pU/^cm܊Hڴ-wzj`cfL01J2>Z$=TG ;g ̭n 0hvD+_8z)GrGÂѤҤQBC.GL|=`,PG&H&¸k)|HZAA`Ll~F-B,]' #D7mjEOQVfpjBȤ MQU`s 4~tmܵ H& +M7zʈMːĄFϦFvb6JYmL\(" - +OS8I݁#;%T = x]0ATı}x_kWca'6sFTfc]J'lk+$PzG0Uau->A"&`Ga{Ya].hruVUS< +㕴j~[4EyȘˆ-L۞?_"T,>4Zcսt0tR5ֵ:TFMMOd;Ugh:nb?Ӵ%O`$=!_(r ʸű{hʵCpDģ@/Эy^"i#U0x0-,*0RScN==n%FqSūżXt <I\tC!-_H~; DG +XQ*u Q̋xW-٩؉ N ;nz*k_౬v~377eFJE}rHʱ "Z`5#[</$R~߽}?o8wj#_MI+"՚d.BKւj(>ځp/Iu\H6M :Q +be~^۸kw؆7GCz㍷c7UMq'@^t(lF6إZ%XHkN(A/ss?|yťLp^`N AouydDo]^ N2pdn3~ wҾ?_a*ֈ QO;Z([ +5@%|>(:< be}DŽu>e;1%l³P/bDo7[4}F8G4VԠ͘n\5a{Ԭ%3<*)Yu mz~ıᛮjM/4GFTGK:qE"Ke* Yb(ęZ\NN@mcC3ER}g^3Xώ78}X>/c c8>c rl(m,Yxm³{`ß5:]6/D idwIRٽ=sh3AOWQ 4Usd IC&%&Н@afxzR/6f,M/M{ j,$IpR0N Yn n5@I&)T6ZéXZ-X0"T]z& m'ҌT/l{T_ݗ39ּTFlLmƱ~Ω@pU~Xn[WvS_nd TTn4NX;\lT8 1RigI⦢`\pS7 q'Vaq!DOA/F|tL oes2 fjPlV\mU +HdQ^Ahl* + N}eAt0$rwCo9/,?C!M2Q fll6O#y3D(72V$swQ0Id/ پ.%'Ы p)`K&eO 2Ǖ%B/ؔRXG.dV![o ڏ{24x870[8K27D`\X|TAL߰sv[e'J#{9bLr!T=)1E ȆRp\#->N:ֱ!tx zel wU;ռ 2&}0 +rJ6t=^T/|c ^4tzH< Ķ;Ͷ2ːdaAq +Npw@Цn/NnaK9U #OD y HD+{ 0@7G96&S /fcM#F6;a}\ڳM4s4LXSAҡ[Ϯ[V.@Uc5V̈́dMC4G Q-okr`ksl]!Mǟ!BKJj-S@}%?.eNt6 1HbZuʕ[Lj+_YK1hmbaqJG=-bTTo5[-A4hfm"c>-_-U +vPՓoQTJ[#zAD3LKJq -anY +E4v-'#_|Ghjl?`3f'`2xL0H1]0U>~:ֿ{t:=ңsT`FNGb"Y:n`Gq3YI֖EF,x뱃ak!K2,4_n{X""w5.m+fW]$OZ:8|(%&4QǜSnjXr +C G|`|!J{ ۱CTSeQ re3# hk\3Ŗ%O䱲 STL=/ueMLj\Az(` DzF' Ęa{4EttwH&L0Xt'T抻N,΀"Hhʐ2@E3?ڪjQnKf"D`  +=掾3BÝ`tNP\3jNA[M.cX v([R5wyiq8+Tb4sNҲځG^t ;ʩYDwa=5Tmzhh^]hҎ"pU=Lࡽb 0[N@/(6s9 #ۖpKqJ!ۚ3-7o92$m" xo}Ho_ƃKCRKnE 'C0{F3JiL>p*J`l@ ? (O='_ު+D`6JS+ctrl=ԛVsn'xLh _Y"4ppuz܃ }aa\#f3z1]y/&C9Bw5M &k'fF&Ě} lt嬒f澲^SRziL٧b1)u͒pʩe%/qnU2Cf0g|ے !FNf@HOi>2[}v'h2O +"{Dɦz#k1 +]d1[gnU rj{:׈E,ѩ%TCN[LQ PDƢ6Hqk#U!@vXx Cv)CVri* NX$WUQuFM^6 '< s% DBFBrF90zh_r%!;M .*lU[OR?KDٔ8|t$f`:D -`$sk2f1>{30굖,2Ѭ ίn\c]lAMKv*%@b沠ȵ\琢 +~}‰ {Vg@;~jR6pĐ__FLbFDō.1-hqf5Ca5I*+,%!!txmp%dxװflLW"{}/t +ՎVrkA:H~HbŌ#BMhfLh5/œ!Vkm7lÒϟ/Y⑕zKSu)԰ȸ-i|r2*qv)uX[rqKWT^MTO !IǩĀRC؂T&=QaBh C| q%K3p'ګ\Ѝ4u5 om4KT9 ;Fnh:q((&:6WlJ?z.RZ"c7Ƴ2K$yTM +6ZŅgr%~e,-˷o ̈XfLiz eRpcIYk՚TM֋;wL®~,4ItƊS|+h!UNpNuVYƳ*}tN-yhO8QRJj00L E6x`%Cg.;'c)`W]f7L{2$I1!C[̜Ag<סhUFjy +M|A/&@sZs  Dm jW*mg6f[z,!fI_[!ĩEmf*c)ZI>-v$3+R#B{ 7/jCDMp.cbl_!^(;JK h4mybtC=(HIWL&"ZjJ@Yi GOгAj:ndfs :lT qހg ~#%k]˜-%QZá g\ %&@ cȦ$I:1EnnQ  ³eA؜/G OX! *G /㟖'ٯLEY(QJw5wa)WPٴEWG7,9Q?5E^ Hnu~ 3$gRKxO=C$ŎU؄\0'";4h +)/ugIS#8Ntr[yi!qT|'bh`BpŌԁ[vgeq/Y06dߵd# 5by]R0kf'uB+!GLusaJva[Y&d9(KdcRڲ-.t 8c42d/>5!7ThĬ +wc+2s Rg^ U_l$-jL +\ +R$ TX"&).uSѼLAhHcD 8KV 0HjiҘ<ۦIcBX)\7 e;yeH ;Ѧ@_5c}UjV,hf*j!qgN!.<_N]$vx1 d# I*x ~@" ]qp`Ɩ"IIC]QC%Xp9Z?qJtGds2!:У=d"K5 zِ3o9.Y^RJc۫i%zt)(YR,1 tg% .& +Ze-u`Ne<"Sh!c`G᱖Gv+`5J$1 ] &٘-_@^Yi]؁8V +Vص$\zdzxkىLqAy裛Yi Ί$zz"&d +Y$Q!+4Ѷם&fF2˼Xp+(ľ$څ0;+,JjRG[="O:iW~}W~LqG}+al)ÀU#E\~wK ʼnX[Tv$wt"@g " +3ȡ!POyhEZCdbΫ +X+r&e4 +r4"(̖):4D`b Ovf BNJb%BhKõwNԈY2} =9Jȧa&Nːotf6\eFۨ^H `GM^kr$ 5D#Os$A~) bnp=2 +!VNP(z-Ҍi,'[že S=/xiRkǖO7:-vmC+ԝU@ Li-^?-4 HZ{\pj^?ie=ZxW|ϑy({2eHNy~O&Q!h!8)GPRoUG3( V L5Al1a% O(ޕs,)-*k8N "7DdN2q8 Aę r- y$_ga]}bL2)Յ&177,udC0Cg;Z]>|8gS+ yI%24$/UIs|.?v:%Diĉa$Юw[קİS`ϑ &q$ցjf)Y 2幕`8D>"W@=NVSvCcBu,WvFny3@z`IGn1HC`|nDe^@?sg^HfDHEfyK>R$ S")F@:v|m.[ ]T$i\C"6Q=ujt2IQڹeqfVBUC*k-qHgd XMV%ifAeȋ_!  +1[ϱ+th`G>anc"``b0Z`# FqG0O=Hq[O㉲w,e:ֱRmU!4Ѓ56ya,Dt:Y7x}7}ĭ%"PDjy "ed l֖Vx VdssJ>N]epFN >ʧp'6t&\B)fL%Z.d\>T$?5/r# ԇ6Gdu+,4YDSf;RF<4)#_oHi& (!46u'q~Tl?qoxK7/#0Գj237fE;$X K!iߩ`@s=L{!`BU,3bĠqHH8pRv#9T_ PE/L9GrbQ %!FчhC2E `HmpO@I2rqJBUJb1LuIYvUZZ'r-Yh*FC"VHevAi)%%>Mh!ܰ@=tX,]6Z .ul=T[HʉY=)c1Qo'1]QT`VֵƋ +͠&Mǵ+%pb 1VrrV^y N06uϏXnF=9`6\tǩD([|o5m<5@eԞ.: kQp,B%J8Ya( Ba1 +ɎT0X{}7UǩPuA@k\!tsaRV5D;}!PwC[ÒuqZ}5*_nU %s+M}!Yqk虇DGYbR}j  8@fS)TzIZ8e'MAT*{d4! ĶI@>=]L)S0IS N̫k1jfzbp.Mjܸ cioMhY> 'ؚK 9: z0(f`;>=rX+0JDm|vFBtTso/"DM+:Vʝ`sq7uI5:; ͹؛3s`e`8ўp9#\\!4Ztv!"1MZs<5i%cB\"cw47Ȭ`|03=18|y+W5o$ޢbl3"yv}M> %]84o008w@\2@rM&3|ٚMm]eZ{:c7vD8T`na*ʯ.WW[ϐݣӢ&vȡiЪi Q!xr>g]Bzwe#0F3'B}o}u]k'hsPĤL !\$uB]8i +K۞\йҋS.MLH+t-G+m mn6![8;'_dr +\+q*AE$|BYs6uiK$ |M-[]YOiD*  :IrMC;ƣnH^obxW_ɋ]9W__=R;ًW_^O7g??GqPؐ(لT;dXgq&Q h,pfP5*J epGj+6թYe;`8UT"'N2nDw"sRme\nf_7'Oɬ[LBYK"H-f4ҹG-k=\J B&W  X*P8∧p,O9y9yܣ}peYRgsOn΍I2QEdwMԏd{x ^w7~p<@@6D}Y1`6n5@7Zp2| +7nXW:@䥨rid.\}8tKAŖ(δܡUˮA@fy,%Gs1IC&K=@zVkɉ&t֚`L~ęZZ«Lt,Vd<ۀu-hb Al<&Ub;4x- +r6?] +As +`O%([`ӒA v;83 ;sL `uHA#m\5؊e:]Brէ꘸΂%s UC8.,igJ%mF!xe$i-yGbՀ) IM!#Dz-%6L1Ls++uS).v4Z¡X]`ZۑiBbAd!Sj&S%^fKc-tc NG6,+;TmIt=9aW'tSu~ 9\xdq^hdzpvۓHm+֖?R{= 2ȣǡdM!H^Nᕬ3IdV*Df1K ^<!%us34*b6 F1"'A +`P>gEf^B7EBń"-{)݆6 SD06AтKe歟Pt P=%Qt =Nw J2rυmhEs@X"v2JK:X(MZ&C: +*d3,ӎ)a#bYudD&w=kB(@`(vb~^'eb)_#F XMhqab(x5%9a(#rij}Fpo?_( :nD{Q  /n +XwBӛ"@?wp?TBtsG/Hf*]gi!s2q L4r,8@L:G&"7҄u@`6ހVX |4Ǿ~Ȓ2!t =a0h( [Hb]9'g+Gͭiеd % +<xZO[>faVh0ݤJ8fRKAK{%޾I(¨kʀqjXߕ~a0!IΟ!-n=thLs>Yk ^5́dv!ϑIH2zHLK`4Ѣo`!HuP~"[sתE!b[v>7xx!8do#Soףu(2uN.EοCs)nNPytw i `%zϖD@j<{e؞ݯ5{m=%ӱBʇMf5qwDLsݸ&=s翿T9gzYZVi(ܶ2g ʁDwqI\TJtUC%XW&trkg\9kR@gtiCS p0;!pB=rn\݁a`={*xba%>冠bэGk\`O8?cJC~zPts%,7c1BCXc?!ʃ}@H[P!>mi2L S8BkIw 2`KտSwFJGe,*uijvy&N/1!"iEjY6VTL<:$f X3W~aZrz)AO YZS1LfW sjFvFId A[4֊aV_GΠ?:gFTm"tmHZU|c>zFKuGԬRvqa {|"b8=%"'P KEUKV㷬k"*>

͔t`7fJȺ)d7"#*}n5glԣ:8_`= +}GyEN P:hlWWU!r:=aVdT\× @9}{4>b Ja>RҨ9d]J=rV 5M[Oo,\I+Yx*@UU;6E `0#<ʗ_KV]_V0f[ 7t X0 <!9݈1+EĦ4|-?y;Q &ݿW4u"c`CTU:cD 3I3OZ*@H +솆ޥkK + +D$6v.%D2ǔW e[JC`toƮ'HT7\[X +<6A4BnA@ZۊjsjM8Q "j{=JZh9Pl}7궣+-@5Ns,D IZE5?x"y =jQZ:yR! "UgTm<~ +8dq#cr/8dE0B3b6ΜI8G>!܏a/< =%!8-v2 ̈}"H#"Е^$y 1L@PPbϪFY"B@m6o\9ҞCӅ m2D`$C-5A,F}mi+#i0$Ѹ 3upy$,@v9dkt4Q돪cTݭH +(EVWlN'`{"%G +;/M7p$ LZ6P~Gf2KDDUD_h`%9%ifpΩEj~(t@ 6i__==`愧mgmic;ot$ ڬL`V75}bY!o M y/H4.`Ad5+)3:h$?~k)j{QP?Ѝ(\$ߗ8P2FG@>cXiAWsG9I9gλwSݦ6D H3)-mr(JҫRQxQߥ-y $9/Sĸ5>5Ҙș{>sDkw+ ++>ĽKPˡ`'$K" Ec2l&4Mkm +DwQ=(85W8 `ld"vt<嶊"-Ü" ZTf;fxm1#Ԫ9ưrhPaA}<Ӣ M(2ʼVA|1T!捌ٞpݺD +7/# Vb">zb<-KThbpztCa-J.=",Sw''?zO11fbևwVbb钋{)*q%JCoagHc +<JZ~>8jUhRNKT %*( +!ʋOTK>èԮP~K_Qdv!|vLBWr dB=TQ8%=R(h /]od0bst)A}M^CZ$+?F6h7)+P $ۯD?QqenV[t*!JЩ,³ +GcD ]_Neܳ,4Uodz:glHzA>V(}ȲʾOۛhnsuDDWc>")5@|vk)Zo1gJ%7TYtƉtPW6I54r-(7XJ[bª$5X +@;v -?)ɋ?:!錝05jo~*=aZíEq5ab/tI0@#AD5arY +FYc2hT Č_!1{#bb&OL*tB3+ۮd iH(fgUXt$5F0W6킰5/#B&'O7#}Cm4}lG2gVuEJ>nW38!.z +~ Pcw.# @M`#CePi] ` 0Kvm筻 +,}T'YsZ?'=dPPQCHR4םsL f19 +SBPTkltۆ=s¬&O_u¾ +e׸U&];Tiez'_oἦFKP"J;p +yD~ˊQoşQR"О]@e3Re$>o7H2Ώ k.٣+{}/BA:0UC2AR@ 3.˖jԛ^ +ZX8(#n%YR- Ν+&AvE e!GS@5hqL|+5YIVp|jK;%Ք&HF_mB7imR\J{a-Lp;J|~ ՆDhL9u3ЇX֦r[a~D9 9gI +2䝘4P|nm+EC̝NBz,xSMaG&j-0qOEx&3 3E_bklv!ACzȒ%HM)Me` ˌ W 9@]LC8- +Aq<`:N(ա 1l^@Ц?&(p14%I$9ld3섅wns +::|BpB&*,O{l1з`&FT MqF(BJpD`?ZMg$J6F7umTV1:05? 䶹&`(|C[ j\HPr/ C7.; \Mr`_(j8Րʙؼ@ +3W!Hu1:GU0i6sg"0E uZb)xr-)eaٯOy5J;&X `.§G%8;U3>B5 +ՠFבVէ| UՎ ۓw#T_AHJh16T(|Ѫ~} kK"+{RW$V jN`$dKIej8B VrY>$Ig$5"_Rqh'Ì(I&P=:.%N~KMi/-z!^"+*˝lbL LqX%d#oxt>Otd{w]ΰ:XG$5\vݜF*VʯăwUyHlR6‡~'"4((m>]}&F:=W.43}U@L3r?S +Ǭ ;ՙ_ K[{L48Ne'~椀b|+=Z6zT/@  *b(Ø[o4֡8LG بRό1#.wp|7;YSR̵ZgZ !Wn@ʙ"&p}NjuZm<u0䅥s<[PsJڌfy+V(|نin3#۱cJӦ #4,VGn?T'EDNA $PMXdaj*QHv-3=+4"qvd/vXF@#DtQ_auʄ3.Sfu>q !T,?`4 ?Qe%w0aDxմ.r%0KOt Z躑J/Ym` )K<5&!T N5Y:˥IbAq"TKۅNn4d *6ns ˳s ׮kD2A=EW8>R{+Ah ^/6G7XI;F'whh92j>nއɲS nD'4A p{U!.'qaw@B6{J7ao՝U#XX`d~z᠘Ay ?1`[dFsGC*Y;1L48RQI_I n׳—&s`f)ԅ7` gETe/6Q":K-S FSX@ri b}':`Jv_v$d办PcO3ZL.%B%P$`񳷟USAUn*Hc +7c-\J?$H~ 7k x{*Ӌd,PȡA%4@ћf`n/D{TBUWNc0cX[H_e՚N*(P@dJTk?͸HS'RRٮuvT*j*e A2"B;HV9p8aӊd!(ɚwT:tX ?g_q S',@@Hjz f@rz.睃kvaM +} @eb- =S/cɰ/7̝C˜S,0~#so}R:AIU2<2 85UuG)q|e!3*z)i2Xq“آc&D & .8old?a$8қt$nLe&T w2 (v\(t,"SRGMnNgm/r@r vķN?BlNɺot"Ѯ=&(oͲq~S0nbY%0:O'&J 賨#@pAsT{U=z d,Q(Ɂ~C.`=z Ϭ Ջ8::"J)! !GQ}{иIP^#J,5ydѭp>JOQ߮kmл녦ҵ +j QH }L*fxAϹ"H vYsž3 Qê 2)USKJ0䉚'ՈHUwJc?_yz9Z rf~!h9P(=rsXuᨳ"B 品v@p)/{t ZjG?#?2{FJ7(` ^$'RA MTa]Ns,!glGg$~.#24j{[fa@S>3g>"@>Ib=K /P^oWQC)F'yёu '_%FȁTW*h-OEtQW'aᗰD4_OA+vn Y,c] ? Xqm4\Q2a +)dž EWBK(ʉgwN,R09oL CFKL9 +ًDeFkb!5WcPU= Aq2쩐kqzNr۰s2_S}"V&:䚀Sq*NȃAM{&c.;vlf\^g4e!KH&f.znXL:O\S +gO.wH UԄ6e2d=S|b;(< TcVIgL!IC>/B)kD< Y~_VU[Z + $DeP׷Ќ\+ABB ;@ j| uj~ju*^Y 4RuUe"7ee},6p IrhCF]!$oL4f ++6kR)4ѝR:0l9$ ]Nm/QE)rˮ)(sCnLK0M +]{-˪cPSJnyH4e()i 7Ha:زpv6,ZJ/!M5 %Ⱦuuy0uΚY7ve7<b: p51ӯP}b:):TUŨq6Q0bD^TWL=LmoQh ɥ;5, [A|o ¯KzP¦*:na)/73iŊ!h_ӬGR$oOe2{{ )qt,P%%˛D-Cc}t܃b5B`qcrܼ-=^ U^ ŔvK3mӦL%>7B֨9~;ߕnޙtyYcC߰rUϝ cBl] tS + |0-ȯ>H@ JŗP%}Z~&|J떎f +ipBd+?/\!B@K;v(Js$ jp=%U+zg6uEh@P}2zdwx4hNޝfEA{AOW?iY `ZT`}EQQ2(5];c Ғ`]# "\(!ję nH%u@`( ++KQ;H9-)ݩ7=4&yj^!|sZ|:$hjM +ƹu\4y`4QF6e2qTaxAODf_ wMX K\Fw+:A\əR8h} +HR#B([V~SMb) #_N`wrRM*>"Ђ")w")㧢XqNT<VK )!t|:Xu3~'$U",_r ; ꍧFɉi)giYD2 8 *T +IwBuSe&,͵zʓ|dof)KشC.k;(I燙RQEdA`@ٗd9+)>j݁Oʶ}g| S><¿Pkb*(CLsB{TRS\wqX4(:=z,-\k/Y'hP4V%[O)#<#$Z];E|Hӳ]dEw# lBgO_tV+i@H>t3 ‘$bT2 qfk|{Jߗ rX@&CE WrCXKEV\Ҁ0mL55cJCb +L'u_Ý{^3JqWzQ:jۜk@)a \G L^1B9Ap?7xgE=@q#ZES.6Gyk+xr=4PcG"EJ,؅!2JM %${o2>6H2!y lU + Bȹd~;E7ci<9bvr H| +4rqyځK%Uh7-'~v %J% T%ZMm}U5JcFuEPLJ*[¡D]q`Nܵ#&?#>|F0{hQ!Yūf@Vub DF+cH u6Bb\U8:KsCg'?CILtFOrW0Su慨,:IPP~םՉ6"6T4Z[.T/L$*2[ /7C*xO5TTD ^>=%|n5 j޼(:SR`Hb2M2u"d 8xJxoI$ dCNA!oQlmqɜ5L}߾XxFqhuv6Q7u(DM[LgJk:-ƜxSz5hiZ"^z!n +4Qe*JgXUMR2_Nmĝd# ׻?(E= K$*H &$JYEx-y24wyòQՓ= ,6,#UHܳ,+F~p$J7JnH +8(CYܺ<6DC8'XzR#2p僙BDhPZ |H^TgBZHh?1zf"{Fzԅb:D8?~VG!=YsKn #A[u;zSa &Kn*IS[aDzRn> z9etNTԧYOjEJ-,U446Ѕ+i-Uy@:Y#:V]g&kU Ndm*V ;8$_ƒԜ;g9T f^%Mc2EyW^^:/ M:G8p(}aNT-P %^%\IPbaLy-wEc -2Dr4:>CQ-0> cZ颚ZzJ`9lCI +A;,+TcW^-kPeD S937Pv7.ղN+cB:IQCDPAeع"0~t /1w(@Ь-ãK۴m{ =99VBV_ktaN@1CN fܙu[wAD5[{sN{8LX#ԊNܘ9!ީ~^w|"8s`?ْ:c}&OS l(IqD -{?^Th?"@pj3"F65R368iG(- +˨F:DP1:_tM2-edٯp!̹>Bf٘&s1L,&(ě8S7.$_.|tmgԌe@{T(!}ah'us:<Ԫ1xWqfݾ}JaQsEWP;P ׄ`KQuԍكd5;O3%yXA'/R6ΛyMD%Ea ;Bh O& +G@&lSAhJhZ" _Qďo=IUޚ6eb*ӌn  +58F=>~P 2V|N;h8#{ZW"eE5U6|m]1B#D*>Wms^:h^10.Stn `P9Ϭa6+_-LTڴ 7{{"-Yt];| +=[}F3J0(Ȗʝ"-"7m;=:K^=3*[-_+hD((ȡ؞0ȬilآEiN +|-x< $p\&LP;"PPr9A +TGcxv  "#D֠"Y1iB\F-$Nf^/ MWfQ+EFINjqT-l4J%b&(dXn4=,6B:?%j W`Ӿջ XbAk{/Og3N=J{r1>=cS?niZ1^ށGqk oLYw %QOpTVIyZ \ĊڳE4>(wh3Qw~Na=(}JKYcv?)wZT ZF'.^#J9qA66#!gcUqW4X@M..)&eyXݒElkT^i:V~R`23HoE=[K0Pj$h[we\UCDq+ 4 8X0<ૉOc<rS(-qӼ2PJߤ{Mқ{m9[,':)'oR|@gjZ~w]5k $>/MqS\OF\XR0Ά!lͮP/}؅Y苧6;JgQT=x,ٮ#t d ,ɟl*x]0dXZr,,HDf6awG.TWJ,kwDz)Op4'Uʩ0m[̖,'(ɶUJpYɃr5Fڀ^1J7Mh)D.Oa`0a-Wk,4fP5c6G @d< #Y"Gm|C$dcBVU!o.PHI:̯}% l =_L۠t/L)Ϟ ۆ:#W݅9h]YˁRAo ڪCQ:% !Fɿ:'yL`9M3ቁjԏu8Ϝ3 [`MNFb@1)B5$ГvŲQ/&6k6p4kB>ujQ\Α-PTP]Ym( =zJT fgd}yuY_d[%x+Cw֞W ^hFשأHhQ*n2ĻE&]aa4Y۰UJN5Pd\'T!Y˓q #ŔD^ N8[+$TN(/A̋tl;<_>>8plhmVwD$/n#BtL}+d`D}\"2 e6Uj.g# $ (862jX_cvvl#PE0Q j$5 ŗp#!7ZnFBTkiaTtn(+Į̏3CpAF-D4ZW1hyp6^{JR#N]rKc3F5DsTԑ3s}_UoNŏ y`ΰ>T0hn tFclPLgw_2F4 NY +KGaC,ZjU0-[%|ƧYF(76􃁧!Xc=@NqXS,z,n334 .RKBovY8u1 te+"Sttc샕u̖)Ω2 .^v<`Z&S9~$Z"'޻  c,t퍠dc8y( /w~)&z=;opd0CLOOSb!8(u;ǣVMnv_I-Xm+*h˵"Ђk[8s;u\F{$w'v,lS+环w "CxPTeG`'GTL5W1b9Gy"XKr):\Z*,!Do=%fPc`c| 2T!1ι}.Wzy:4$|JRgϙ.ʃ`OLM:͇-0tE`;9" [+CsyCyr`I'3p %gw8J)p +tz /ϛz/ac;Neq9TȴdO4 v t Z*z%IxxWv3wut锺سW<a:/FKfe=cn]ןaA!QUDcߌ&Ԗϼ{מG?.N1겮43=כmDmf>;-+aZGv2PBǮh1@Q.tA-=i:uL" AC1\t(@TG\O0FT4{R dMHv(GD 'MPh00jLW%Jix">FtGdEIć5܉(hsb`!Y1 +L1$/OxbﭬV(vqĿ|^/!h ka8H;JfCi/ !(7M ^1%#RLjqIyxKldAǥW>:B +-KR٭BDmt0]W,;#LU%V%ēQ:x^q /LRB~AOڞTzdq&-A~$]9fdtL!v"nPndiC|r 3KڐFp 85_v 7Nr遄X1tX PC;N?ʀPa @ JyZ@c$ +z,H#t۲VeȠv9d@)%M6fG2醒jPs&˯b, ѣ9* u^ZqqDq3r yh^ZOW:C. +PĨCYD }F̦UOUlŵ0ώ%я^DVhj|@EaNmk\M0@&_^ HcRK=xl_X7h.hIB=&0]Xt{ .ñA0 -%'H/ /|lhR/Ztt;Qy!Z)vZΠi0wS +>伓΀JK(8F\ZEB\'s~D +c +D%&Ğ 90:J!^wHj1!裖sr- RڑGhaMU"0g} >GD ЧXA%)n-j䕈3cm5!9QFQ47p}N||sLi0rR7N)'`2bbld|Эm' ¹ U63"#t:/_7姒 fc44p|p5%cz&+tk*T\ + H9tPĂEJF2R%cz?kkFt?9f"< X3b?*&>V~=O\AjIthpyj~ /U{пO~#z o?R_qʹ a+OyL݂$sp1M + ]ČcЪN6#mF#֎-gQ?_4Orh-3i(uN~\M/0[\6ɍ Ģsl|GWYRV̂b*!+]i(W,5E݌U9q<>1<ԼOt,(4(8M6BqJU5͠^לRǰ93Q@1?"JR$0|gɝFs}Zg4?xv˒aAc{Wl|/7<DoF6S0~0P@Tzt7z2d>ބQJ:gR(19Xe>?E!K=nr +R*9rZ蹨?R[Yb: >6#tq5,ahKXؤgGLmIXuX۟_S@A/|@A&ahX{.IjGe$ph/c>,S VOu(W9rL==Lt(5'8Xs Cj@̈ea>G*>|F\=*(Sp vDQynV3:| kt0)7q[ bpbH菱t+ꥠ,8Y증z aH(R4H,5)+Kˆ$U[)gdOj Qt䨏ȹW7MV/ma؊1pJS/5 +GsQEEd=4`$̿ҰZG)VϭypվH$&/~SwI7r!'%7%ρ><X-dȼL]]iZb4qEm MABb'J&Dipn"h:bi HW,j8o[੎9d]PAԷqz oיv~si3_T +EJ`ojkݻ"eՆV=pyz0qPCm] Ub͒BdyiGDCGu +`q}608^+ WR9# ,bgђv@L4  I"K8*,!ҎRGdWa>Au +=@oU +[h6;H#!T)Kg#SPߣ]v pp)iy\ƅ8b a^#] Yf(z,J@l<8+ + p:pGI*ʖHot/eЮ#@}쥲 +5k>c^0s& ѡ6.0%pXA5B ϋpx{\:ntnn( <_2V4ʎ Sfs c#u=I7L @Cås!)&~( ;NWǭy]*;Ѥ6OU) W \ n~;*+hIOu0 +]jB?w)I1JvԊQs$$CdIBtD +E$dbm'i} Vq +0La])UI)NjK]-gywz#[ +Ti%C}6M0n؛)wNㆅ"5X:lЃI\;F\€**!fWx859[y(@vZUޚ_"90uFT F(klBscl`{nP +!zGߛb R #c3@21=p;U6XC &|5R I= c^d=;hV6Ї ZNu<ǔ`BޡLWKIHt~u;fD5 U^5`@Q%\͵[Q.I`bԢVԈmV Gj(YU X`')Mk!G'{ĽQAQA\["M>GZQ5 FR˦=a;Ag;"9vV hi}+^8[D?m][y?{Rߊ}l 4 P5A`sϰIӹ@Xτٍu [!\ӐVkiB= ӷgU$#it/63l xCBDis"ZD?6R#O`lthVwǚgdF~nkdu=L7XHOS:av$ld{ +s4y +5Nk> f %π.ȻA[gc.Z<ps~_>5ch:g+r(b`f#~])' YӴf 1^U"#68#p[ WylNTh]*G"*RvO)rX`[6]Bξ`j (,c`,M?YCFubo# qCg{X\Uvֈ4 {h,< +C]H7zEOx:xKkJT!qB `\??2|,51שzm~-zD4*+Tį`FO K&J3{:IT^arNE!}$ fxfD.@_wB \Àfi\O2g:9(}#(O1S0;-V|Ϝ1̜Cqp?3Ev,#t5hy/%{}F (ľ`#%pC8i3N*8ŸcЁEvLQy˫&5J }~uu\`"7np4sé>.65,ҋ&3lhMp@ ò^BZ"['??%4T訛`Mvdwtq\h:o|vnOlv"#te??V7.,G>.!T́wMɚ[dpB-v:bL/:BY>&0l.4CRZ$6eG*/℘Xc_DNMܱjk!ijYg-9~?dUEÌ;!0|O +mkBPfD;aU 89@WXnq'[_ˆIyNXHgF՟뢕 xu3 :'全CzkیG@Dh,1 Q0D! Eiw*xTD|P jR +>{jJZ_Av{\ą*8$aG:j +1t0=Φs&:>!<# +S=ng'EEQn,uȬpB˓*S27I3t4ߑypcf94 U]2_{X2eb.mΟ +#'ηB|Q$BHzpr:>'rQ=.H%+aFG'FQGj{" t*wO\@7 +3h;>$%*a3 +$h.'g5 3 ٰwsAJ8*OkS\3buJg0#:\LĐ[XBKMIJ׷Js2*LFEYcnL݈UK:$blܗ.c\fḺOsCQ.Qi@?16B=!JvK]&:$t2a@RG*h1Z.D[S//U"nXD'*S/(DJr˽5JQ̀ks:wDmNeY@ԹKqJ7ӭ{0#)щP _>V6fLFŠ4>fwhEH9`;,x_48@WO߀uu0RɄmj&i qoB "զūI<f CYv@H?} +,P69mJCF6ӯǣrggZUTԜW~М㠂)>&zÜ#l֨ u@/;u[aeEER"^4i:Pba>$ղ\+#pf#kp(ZذHyXl,d&, 1ԤrPEA-Lh穽?lb'QES* q,Y}zW\OCy +x!AS ŢA%$Wߑކ"9$idkv.Nx{a%Hq Wavaʊg."lj??h +fTDe$rO$U=s 4JȋK6kr[uhzu^X@֨s1Bb34e6*12vuF5rP+<\4~_fb/h78{E BХًXɂ_nZȂǶT@xoͺN;TB +;,(6#$ k4Uc1 Dmm,f?l?-$ȭX*1b؉",f_ +3[ N "t'<|H !h]Pʑ0!كžX@ u nFV!ڏu|{V(y=wg[TaEh6.i`G,ƤOo\i +dց,U<"d{P!Y@l;2 +E Il]+$'iif ϤRG&vSb/TY $],7X- Hp._ oUX|]gTrr⡓?H%}Kw1|MHM\PB5|S|on|o𸕒(m. @zQ-+]/h1i"U͜HҢ- +7:=Nγ k1R +Y0Bcpwv(|c#/Q7B@+# A1EQ5J6H8hl*3U& a]Wi{fM+=bu~6.h AtK+pu8 +pV @lX-q" + 5͌~3*nK6SNFxfCh'Ñ h+: +}bYzjMyzA̵f< 0WDűh p?njNhƱ|BMv$ .$AD \iV-U\ Iu ^wЉnR+}{PA0XU)4Ai*'W*m9xV*ÈP&ƧT҄ LS@nt%mG* +h BeT ! b(:1[9DvZެ38Y֔luBl)wxprprV0$JΆ!O{8J?WP>#nJY պHCBi&Ve{歭МlZF")H^lW)m8b/LJ{lzx: jfz [*P[DXFbML(>I5B.J7Υ<% P,a$҅!yCSy-\\`}da&.^]nQ{7;1 88\`şBmPvRv!4O< Y"rCBcR!>:SmY/HPrq IJUT+L>^Sro2 ]omnb)8N΢Q^]p0 +TS,$}(#|ɲp(RNI'\ZUQ / ;LP"=ypP*+{0hǖj ?Z%ТE/>IH&ɜ +4lʼne8-Yge$ +*{DBf^I`]#EhDD @*xh)`KjEIC,UpZd}w>ȉ m -tJ'8O2*zWe#bXR3EӞC,w,>P)綰k1TD>j +aZ/~8U4%4$1f@'C[`eWӋ7R/0n/J0NՊ @%O[Čv֢<gVU?E{i.S2* +ɺ8/ i6ta  &K % ĘsÃ#? UVAzJETLOU5i2fH_TV"+NevaA4m)Բ~k-N'4CɼҞok+)#J-\Sus'4 A$,@"Kp@[MG)##C%iٖZxіrGE%߹cOPH// 3vOOMPCW[-㛤{/ŰL$My4@bA Xou%f 'eqʮcYyLM<9AwD9r 0XuQIYS`C+L9T(AUpRt*$UA +4o7B^bw"{-aMR +9aNHPىnT %x4ٝ0HY,{1u. \*6{ OCv (ÈM-MRYhULʸ{=p{JU35ԫ^ Q]{ +/籉D.D?bIs)^G>LOCc냚٨d,Y jՃ$h8B9n& StEnfNQQ=:Y{¬t H5rJ/ +k†i9{0TTJZP~Jnlxtf!@"$VQqQNŠb `*bwB82`DvL3T뚈Avϯn{2mlыYwiP,{-KG}; +#趷jeɞU7vFO} Ai1rΪ&a8DNV!/0&i`,z=đ+&5S2$L$L"d"%(oF}¡MNDPHz|=B&H1+E"v^ +d-/tRTHs1y3QL9SE':'Љ.v`%RpTO8E #) 9 +vy&~FFukcu^b"ΎZŋdyރlO,NrAr,?RHUGYeam0H`cU9Ⱥ̐42YU9^Nf85QKKP |T8(B nܘp9e1 YQ^ Be5 +gjq]pY00x4a2fxd"~CꝢg RfTntR\=F0XyR-+3 ʧ)!Хȍ>_ abѷs(ixcay^,ԴP]dR)f.IU]eW0N4*r-+޳FP)'C\U@ ]K)G +N1"dTl'P ^&":9A*cz1y(|g H gkj̐LpL즒XG›1Qj/U( =ǙŤxI i)$UIrAB# +(_4gS4ÿj2V].RVRm +JځI0\p)^R!/7;Yˆi(jXGb ;dM3qZܘr+%?l3 +^D~D(N̐P>̋XOϖ9!"mTyP.IŚ7)9$Gc^$l1Dԗ*裉ۀ"W]M}3XXK IChYOYb!;SjZ$+QN12J;.財5{Gk&A #uQJ opc34J Be EYBA* +2.%&Kb[G=*l[)mJ ϥ*4t7dV[AP@΃rr,νjTE0%aE Jx Evzj\ aN[+-MY:Ob]w@C1 D"H a]W D݋EIYgJ賄|Ϊa1WӪw3+ $RE*} # k!f< V(9fA37v:9;:btGDd AOsh &(5AVO9B>t0AڈlMǫK7YRDdkIRYMd1'+#MS`ys7͑Nh[V-Xx<*WKKA+Ϧ +"_f Ui٥%V߻beXy{/LuN]^"$oG^O^ JBQ|p%41m%& j"I88CIJ*j0ʳ_u"yh0iRUԟXTT 54XːX;Y!u*:_xfс0է*MМ- +/kI ⯐9< +v?D(+OmP3g p؅Xܢ'd'i|m,HFLP%m HꞛדఢdeDM-&8bMuQѵIxZ`=zgHȟ%* +d4? d+V'qxkJ7KZÃ#vK<#& 6o2rᚺ c$PXQ G/YE$T^J ][¬"`dʇɾ48XHFBB 2 b`>cKZd$2 rA١7ŹI +l.ѽRTPB/gfqj(H H;Cz_W!ޡ8ǠUFz[y`(_'>Ӑ5|:@ C1S&H:->!"L[04@<t{*lE'_[ Kn7's;OV!'YgD]kWd'`Fm #a70F&D<YŧQ E>stream +4 :L ,ruEPEYEMԔ(I\jE7ϊIR ˆ#}35|韘DF@!K / Qt $ :yQuhCLT5VIlZ1@ J/]HBȻV@XKcu$HC{]ja,'T;5*qF@I{hnZvѳ@Mghβ^)q=7DITSM0@(f#_X&#!a6] N|՘6S͊K K%b`5K>HX$z3=PlJVv0jߡS /x#ͫ'K Q@ +J$V|),"1bCIW5owIQ%(c) +sB/ŵH޼qfƼfÃO)Q,lHxacP6cGu_~A6E&G ѫ@,R,Rމ/ T7eŒT҆H-.Q̍¡ ηDlr2ːN@\<58V @b#, )W뗲M3ha.i } {$%FP' OW72(lp5E +*ˆ +iAWfVT$+!iZk\vhrGxhڡkC ,0="(R>UUr} ѵ6 +鱊c:,6QlD,ψ7[=x]P"RH9JbR:3SW0/^zʥUb}J@Dx,]\r-EО6,v+,U;=y'[cUe}C҉oZ۾[n@\94 g3A|fS#y:\'L엗R ngbnL\kkKQp]*QVIЈ"J0ΊСqbcЉ -ZEז8*QYpM79:#;%(N39HdYsyIՃZx0:{=hŎO R'{GQG*A :xbiw0T 1N 6|mldA-쑒s,\+`6[V؎KrAa&{ŀl4W;v8lQ+K &»hɔc-Hj514\BbҜ?Jv2DSDEHS~ W[膰UU!Յ^i +NJ?Aɦ +_FO{ҐG(?: wcUeOk'dBd"BaPYTDacER +\zɵ?"ٶfƞHҫPm嘨 /#=幄+F /IK4JlID{;\a5,4~*EAI6(F@*Q!Z=:( AӚKb +.jڪ1Pep(&s ك8H +CzZ(glӥ,$м +r.Π<-#bwhQBb{ #Gq{Ȩm`JGcԉUnN'%"c*'aB LOˉ,(!J@hâhh2:U6#p:Pf1.X >:5|ENi"D}0PЈ+ c)yP +p*|tPbAߖLt>CtR 0Yc?5 +\;"4[Ӌi8Р;VaFv䇚]`ծZ=*8B*ec&D is% +`P].RA0|Wu0Ϝ2qk) IZzMjrݚ7w?HޔJl[wOZ^(#L +T '_a#)@XY L*QMG؃&Ƞ lHK1-ⲥetTJfP+ SGJiذ^Wɝ1X<DŽ@ ts@ϡL !q +6_".t; uPD̪,bQ*snn  ҌmwhGlP =IWdqR(:찚'A͹k ~!SwAŸCTMV]U4xPY(=@iwWH#3$4pout5nF䨒'bUupn&\rfKlZr,t̒%@B:5"j_uyhØXנᚙ +aaO +La#'""N S}Q0k[:cz_,93/,UJKpz_5{@vJu&^U揙Q}Oar %HFDIؾT?"VJ w= j <'SℕsrI7lZ JB $E/mqT(_؈pO + *~Hvpek$Z:gi gU6@ ^AYuh2rND>_XHF\6 e)H.CO3?)(U]xZD Et1//ܧmAۖ$lQG+@y@[؉wo . /(I+J1t>߲`8`JV zm85 % +T@\ioB|kp(SvT-jôyXٌi.cI_!]- P|tS7o ,f# l*hgo ,!>izǜƫ~%qLQryR eߊ䲐wPkOSxЛEo^ +@({ _:NxoMD/cH0fpU+%" bד*+"3QUQja1ORKJ+ <)FXCR0ZC}aMjAYb4j'rfhӊ. +w@Xoy$J@B>/T!BTzɟ9  ?~̍5 +T#Ɍ T9@ ^d +6خdR1ϒ F`nۗti `*Q($BrI YYUşXEnJ)4-q\Ԉ{N'v%vYv /) NDpGZ3C S記 6~ &ǏF')zJH.9K3"ama%a#4|< F%S$6CO_з0O($E.7H-\TPCQn!OD`bc˂z5Cw+bʜ0YҺ]N" s:۽UA?~ Sqql'@_t@2M/*T$Ң Vh\k|'g:{HdrG++]KQTZPFuD\ [5aVA` 3x@i/l@ֈ@!k_Ƀ,O/T{I,KW J-IDWwb}^),v GUS"y/, NpT0 1B%2HR$!o'AU| ++r,ZQ#ʺx U DoQ ߌ>w{eR-wӥlU5ϾMbp}:ZDorp@wZaojpkI-,V[ڢ09F$g74hN5Xq& ԛ3)qb+w|q|dij@aPHHT*8 qk?w.[$uU=`  e.P}]Q0իDm+p2e(mX*> + [*uXl 6{1H`IYJ&ê e-rEڬy=^jB`Amy8 2 :Ih`֋Bɞi7˰am !\@A@#VD` ^(' .Qf|m9pZ(Rz!* +;M}ϋ[  +Uj^l(ʤL* 4Ơdۋ/Y=tkHk#Ď8 +gXx sE(?0TEo]*{Iu:WU, G Y#P\ '# R-yRU!lĶ!ǷRe(seTg FX:Y,܋57 Q tN$;R/(@@/;3j$R(+֞4d"âx +xWF*M@i_>hEp17FBmd*e\q#she"eXei^Ū;ndM&Lɡ.<ΗH=)B}ZY̅й4*jxɹ%̛҇\ + +_ +GU% duυ,OtTa r"Ш+F|xEzf&(ܢ$wTt7/*_=n +q.us PzJ>pk%v)*@pb`B+ *-4@BLYI +> +<Et5 +t tS{(8Edd!yO[r̥noRmtI M<^$BJizrAYPf VP(%Y -bMƗ쫤*ձIrkf n!e5& fO}Ek9<퀦ה 5EVEco wq_2[3nv=mP|}1Djmy>qt? + TKlrW*F[WhkĬQl*UEl_dW_Hj +NF"`{Ǔ^7V/Q9&ԯU@Z`D=b;O>wŸ(Z`qG]q&tj5_7/Ě>]LI5ډ'I5Xz +cUF,'ʣyPe+ +(:>^ ^ F13S\">-cHv $j3){-IUod1|R ST|XT8F$ڣXJL@ylJr~_ P4( I-E US= +RLkx-`M+ fIKemq\8k^pl6U1iZho׉%ͪGQ q*ON:Lf] YE뤄@/ +8dȕ.azOl9j%)/ 'ÌH3-__Vs*QPA,V+9}F]+U%IdY}Ԉ i v4!oQ, L?Jh-E(:@Or gUT;64(iQ,2s'f|b [@YUOF!)cUr8_Ì +Śh V k e@TђR(p!S +NCvih ١cXQjոCƍeC*Bۣa!MwNH<%{+됚"@V^TҔE=5L_!3j2UrDxp|Bv v _ĀXm^>91YJ8y"uNjඁZ䜂I.o%(4y< 'ϲE;FA +NѬ@GQ?Hri%b r l䓧GP$TDSfk48Pst` $s`B::meI_&gvQlXJ{\06Q6ȤHk"c`Z@q!9PdWa:NL`QQ +lt!#"F"B=AEU~Lib%f4zUtDƮ WEe*CK甂uͨ?LBiBVi|R~<1tF?F 2^0\z0)N֊ $ t, q(:OxUb0>JZ;` Nb[-'7 {Hv/{p>B sg bپP9P|"9'3V$cAgɎS j!K/PBUjZ17?Z(^毩 +.U)V [m j!dIس-,2//wjaD$B̴i*/+P’0{vn{6/BϜa%@߀"!ig5i 1xIbd2-_T@tyQgJ5 HdDQC2(h4v2FFwm.@q36l>lD}_OAIxd#ŘD<ڷDvpIk/?dtSeSՂ߅5 W٥ !qE5k6x{yCRjoYdzNϞchzGH^_^]^}?~揗?*pS]g'wOg}nLm/:˗7[7qy1u(6ug~s龫yj?'<]IwήN^^}o~y;d|˗_(~tԎ?;=o>?{vg?.ڧO?+y'a|>b?g~\vO +ϋ'x!>QtqїkO/uW%=R |tggPU9үܛ,* fj>x?w?w'Wb^8tP +Uw\eL'nl͇[xpn `Y]{y8TTѿ:;8{Ha:Ƌ]?xq~Шvc&#ڈC|s*0ܾvqqnq[vnC~+o6LWs~Xkt޸nbX+7ӎɸqiQ_#\[7SKdYN~ HCj7VzǾy?ǟ_O {+2@&\T} [V},.8'Mnr:lZF_}Fo7/4/h4rュzý!V,Lz+?7<X55+k{tiu\h~2ۨt"{h!֪?j,߫J35$}ntKhVM0[sݭV n1Nww7[yw ncn9oϵY9V8X/߿O~93˿_>?~l/|qҾ<:f/_y#6u\O^Lſ.~v|GwԚYv~}tmsNs/:iwj}BUehk'^?|JOjam_mݵϟ7_7aΞ?_9f7Wn0^bOw_^~}}~}WjN$v-]޸ߞ:>{yR|gjܸ/_?yU/)mU񦝜/sԇ]OrBv򮾾|}uz۫??|[y:ۑE뽊CS?]\_^m޳/v<|{/uⳃs9}s9npot󹻯wW'v <uN/;=xo5{vғNOҞx }P[{v?y~!x'ͭWuVг]ۋޥۓׯ^|`_}|>|=b|}p/Kw߽:~xRt͍W?8듗[ۿܙm_˗go/w `пW̔.̵W;9=d]N1_ ǶBu[46}ړ0MEm٥/ +evۗUb=44^ =u*=o1ɵ"Bk=J{ѣ^Z={oѣ~SClofV|ru~-^>n_?:oFۖXvwv3>[^[Oɏ%כy7$`=ۓ06Щlh^ˋgWggyW'_oڧ&}.7iVJp|p|zo_^\m=POyM<{>ݢ-+.n~r ෛnyزNiևGione&maL;6ޱ9qo7=%gvAH35_|gg[9I_V7- sv\Q[fvo]۳mW~89={qw'?-]3ԟ[ؘS}Tn۷Uʼnns^[ςu޿=r'+< Lyd-6KdmXN??>z//_n/^?!_ovﶃ}w~qb._l+UN.~<}>n쪃ח[X;sxW8yvy.('YŮ5L{e`grP-Ry|NnM ңw@O.riY_>?僂kN OvtT7;tTWg/.z-{JG䉛1s6>mhH.Iv3-Bv o3b!v>c֞ww~sB:w(%كw'k&uO|?~`{7.ב/"y[LpmsGa=z֣~ڔuVeK>:ƾo")z~|7n?d7co}zl!w#P-:d~eeޒϏgۙ >#w2:dUG۩hW𧳋7߾Goכۙ%}w_}qҌ[,~3e]wo9~ lm =o}$J!x*:hgTq#Z|E>̚=̀]~ˋϮΞvyu!!sl>OEV~-cؼ'uk ~u.KVGe[ylꇳS3n,`~tw9O)xmtm1-ԇH!uD"QH!uDwFZ#Q-,!o!"Q[WwXk_7w)Ƶi?qGsy_ɓ ق@<+h hOg8νَ?֙NJ7G'| {{֋޾loG%Hܓg>̛y7 >Rr?y~A؜mBQ5?w7jji_{uv:{jKWcpZ`{Srː_l<< ܯ5Vz]ŠۡU0vhŅ~Vƹά:xs7y"S O.xECهW1:oXmjOݹ<} tiQt0L?_lS]u;ޜۓWg:g/OpanlW=݂8>6os7wW'v <ߢ.i7=5@j| +YهL|EzWz$lrח[얗ӁWn?y嶰boA=bz} {{HZޓÁi ++]ߪq"d[tl?[thO Tp/r9KkX.>ε=C)$@%9Bm_ m??Kix[-ӃzOm?ݹ)O~{y?=zpPA=8!I''nե=qR'u/|-v>myͽ#2l_BOG@a<2Td dw%|8 +^mytzyqy߿89g ?tO}.7xno<|;O_;ĉoljJ4_<#o6fڏv5~ °h}d7nFR/_]<$=9NN϶:Sʴ T6g:OW~|Q:R?U}Yt:~V{5fY|v$Yr;[6_妛?|y6]``΃D2xy= <`v>}u[N6K,p'M}(0n-fw8x@聦k= +{ZQM°v|ru~mTvq[8xaO~{aO~=ړ=yQ'{֋޾loÖ} s޽z3Lݝ=Рj@.w5E-F~6}#k~0hl'vpQ6^e)qP}r]Nžss6w?CEvҹ?V}lo7~qTOIچ7RTeE [q7/iT3oί>HtksqyۋevG 뗧U.a$>۽$>1@A񧫓B*Ύ`|2C}>&y+|y!}@̛y7vzCͯ_>t,s_"bv_~'ϓ˯zݒ_?IˏO?yƒƘS*kB-vŎZ c~Ya/'\\Cjg<ָT;?]*C.Q1e)嚳be(܍4/~O|c?.ws{F;=t,Q:a{*C?,^8!qXd\˿.cɗg]7Nn7=xݢd=}#w:䟺ũ5on6Zn27?_|ɳoOg߳˟_2]/vuܼE4K;DC3ٓ8N]D>(mF}utQpܕd3`Q2ؘKgоΞ=&ىjBmru)96v}_}h3$6]WJ)dkU"(ktӉ# )l[M۞=֞k7>M{th+>0cG+Mh#?oxk[h+iG>jDx}iBJ׫\?RY3W3iu߄,t/_mܜW{;&kbt_f/I`qӫJplK}RM6˿j-Jf۴6Ȭ~6}`׷qoC1m*aem,#l#vbclzݧsy|͑GluZdoɖ 6_䇳 9ico82YM[e˵CG7Qv6uq<,n>7L)̷ʔǚpVjǿf-q}vM퀕bj*5}E ?TiLrf̒ ^V՜rT+3:2mYI=ܒb1fsUlӍ6l;m-3?\ϞÞd6yxo=K6oYL;۹oϫMf/zn)rb3 ϱ8/u&K>u}ˁn|\}lsj9Rme~`+Y\*[j0tX2-!Mfv`aK'gVzgvKͼ×.SfK90}=1bpPw +(G<}{M/]^^Ȩ_⫳N=?N^>mXk:>z@c~yK4cVOS>짩yY+4~dz k__H^?_i;_]_[E!@c$q5?~@ ZWnϯ2oS%U&=^bfds瘷->9TsV3OVN-c.?viWk={}x>ѹV9boNi8i7Ow_D-4#.IEX?׻X OCa^~qiB#%)y))ͻ:f/-m(f́/CikHaioq#FզWSP%khsw +ꗚa%{C]vz6ٜuCLudKb!cϮ}+x1{6x>հѿ4#}RVTZ +VL([][u>)[[&)opΦ 2~yv]uE25ljۗAc% |uGV>wƾmҏ̴Nd{ q|m[lUՎ B "~_s-u6z*C?fmeOQўh>NݘM5/{B[+Qf nv7,^4?$0ʹ\NjOB0{F)nM- |-Z:.8kxܛU`OSϞ1PyY֠{Of7EV<em(d֢Y(8,2){^aier7%̌wdMOl ͑XK;/VwDM⾯"$ltI>QedEdžHrӷ7iYi?dnR>ӎM䫒k@֡n`kMa-^VDWidN~lqb[6}k CTdU>C~kՉc[LD&~U&|d?biz&,L~g#~p!)_q|eJimgTi>[lAY6d knEVri%t*U^ݩkcU#TkP GoɞūycՖCvH~PF'?d4t}vH"H$!HMOj<õ &mAGrEWGy!G5ɕdQ-?Jw7'WLd3VRl)RC~yX➫y N4͆2+yѵgk7 U{g-o4B)܎3ֆ7ϙ+Z7-Wt̹#W.rE)o+o>Wo+ +V{>rEټbݜR17ƭr**Rr* 3hYf٦*Lϩ^";mb%sHqcWEoi"iҮ|Qp3?/zShw3COm:7[t!o=Yn78jۊ`mݘ{s,*RW' k>S͈q7%#d-EXA=il[& +떍~NeLXl5 ~s~U}ĄoHيGȡHlx`9J64Ͼ{7׈0 ۫(:*ERuO ڪ6(r'Au~}4K_WI$W34!vrKtv |OJ%R/60`rC`Ì`[YikKOW +wDnѲ]E?xUtd<=5l xϑ}nR%[B%TS[lU2O7&!շN^zϹ>[Jo8vWW4J?N-oDz뽧mmtZ:pyt`aؓ .od= /nv`ٻ僛ڙo&[stfr~~o-RuoepOaج+ z:sz5;#|5;SǛ91fZWZ5q}::t6{HvZ/*QA3Xz5gB }l\Ln.бTf.XRQmv5Ou-ܣJR봇㸖|={N{N3kV2}H}twVm4n=4ֲ[LTm ̐nәuG=]YO!tGB%|2;a?<)|#M:AC[i4dH{&U]$}۶+LW+\ 2((]+vO%I NҦWk5u=ݘLgKJx[!{]{N֊lN9R/̑xGr|YJJǏmK(մ.ZZǃ7:a=?w75?(@>b(9S +rgc+>[~-ڿ֫e"Q\0ܢ}Wi/~)H:vLiS[z3l5Ҧ](iSiҦεfV"Ln:nR7uےݕ;$7NDW4W- &Y:ݜ.&Ҽ|Wv^aWhoggE6^722ҽo瞄Fc1O`5ȏj<0 |-eT-_ϡ'Zn]e۹< y*4k3|?_o?/~2[?w OpRRsHΣX|y}yN:T'I:UsЪ9hjZ5VA 1V͡PPJV͆J*zL7"sO*4;uA1xkDTT;fG+CB`%>EpFռl{]ڦEy0O+>Xw$I\:N\E)u8Iml𻧃X-vyqy/#DT@9 $͜_lX):8ԱD!90QC]#IF?Jw{CW,ߟ A2hr4X՗( +.*H;,t 8,<ݞ;47JD[KCtPJg?G/:8U):8opt_h:rʍM̬*Y MGڭL'foNWz4-2@ŨG>-> u'# +юELߊM';\gl +SݔJAjYY+(] enJGaYD)ڨ +;94yCӡ\, qzv%Mbg³ҕ r`uhs4|/Xfr< +B|<yE[ݹnG[,o&c2NHC+ugYUc5`u-mA_cvՎ5Ƴ8>S}^c;(tRj-%qZљySBԏ(ltvl|uS.#de+v+?_\KhK&,Ҋ| X{+=X{AcQ/7QbS]PRL˷G7tP3cKEkXdDU3Gن QڶMazRr>zoΉg.[؉ka0Eֳyc]9ajgcVOnc]m>Bza1˸rզCM'ofN[w4^LEn8u9dUSKn)"ثa۶َmK~|fE؂9͵ܕl\ m\[ye0_eJMJ|畾Lۥ|1z ^.c_}%_c-EQwq҇I]VنB\fX[3=*:DO1Cskv0ߦϷ-{wQ3w;~gϭb~KWsNl 7fj)1w)o+qfl]RqP& K6'SPQ~4'#g{-Ӱx,Pn߁a woɆy$}~ n*:mSQ@C2cK2S)>{FҪ3E BmS6^" c!4?_ב+uX $,pQd?8WGsd^f}C J S2^u>‰ƳcOEŁ82 pR uLF5 6p"3`Fb!ӄHET'{* X pL-J_1 N=ͨPHR'4MƜA:8rםW>pdGƪ=>HR2f_0Ӌ7!jɱ0K무ϛ9JMveJ_gL4έZu4%{2r/Rظ}X۲}ίLg'c @}KoߓyEu UH358#Gd O)U5荤YW5@s5Ew&&pN,Wd#7uPN-nax4OYWP7y!g vFcHkKx!%Q5$+3WVDυrgXjIFbRL L +%ы$S>A*2P4O@x./ۡoLYIt J${>Wa3Y]Bd<©A_K(D`vx"W@%U~0V*Д4ZIѥ-`']D;BK(>4ƐR,]&)eDB V@ sQ2u1}`.)nڡs67,SNB9%Yܜ!ӹNO% .Puf#j +*@(HFQ'(;0p-ݲ)XYˊBAIEdr +\V'3A;*SۣZ̯̓xZy2Yն׫mW[浽^m{zjն׫mW^^m{zjն׫׫U xq6q[ϟDY1&H#ZND3 W&Z օY+FWŨ;+QuǸK<8K #? +~t]p'm~۫+z.Mۦ,;}2^T-]L~bwi֏Q֘=` .^Ŋ +$ƒ'lYc*{**F0a̻Yu4A֓@\C'JCfxA2Yg#.kA6uO$2b22CH"D aa SId$ohiѨ3(FgF)#AdLJ3痚(30V H ` +لh)l`DG[&Θd (9G]rpVyA}a=V{E ḛy A4kV{W@/kt=N{=sqA홟Fv{홟3?g~nܞGng~n#ow'TvXBmt>&Bp~v>W(8!!@jqpNi=X\6ņ_%Zn۸6$jcqo2! Qc '*3* +\B̤QARCb1iTXvV፤Qc, 8?r^ ;i: +, ;FC/!3HJ3G~%hDX7#q *.o# ̷ȁ=r, _;_#vS`*ſ=T`}"V$VbLe5Uvj) +ꅂ'T۲`X",Ut\QNGb./ɂfK*d~%0 +L^C#(nx6&{T,m0uLn~X*oRy=z3N'eiHH$4"ƑT9%6f!`;ε?HA?W ;_^A( BuX‰5+m_0Oy|#C"Ia%T߷ `8ؐ}+Q7_]mO? s 2@NT]3S/‚ URjEk?{z}q$itI#I|yOqnkdy2t4Gk?Y+)ʃQH]NT 4fZtLU(^iOhS-AZ2\jԆ +|ݪa^=O!m`uS85og O +a}$e"EI07d'ZEvj¤= h jb8*57fm,/$﯇cSſkߵ~Ѡd`,"ڡm;:BSO3#ibQԟCO./o Vc/8O1<}f'iT!KCGUm *L{%'92Zs0hF ڮMZ\Hv#>sr~F7ٺj{j^C2 JHmK%cUE#a~THʱikCe 6̯\m@wm|i6t߇lSm+~n^}qVm>m2m[Ѷm[6b9S!l(~,[MIlV8c+~VZ#X%(a.BG*J?jV +U2tIVF@8 .uu&'~O0ϤuBtB~ +犵K =[XB>CpI>]j +VBe:y'ccMZ' + ')s*"q , ^8a1SbpȩD|fuV'< x?HOT߮1!k_nt)2PЙ,*0s"ZBU4(2I:UAQFxo0IJٍެ#<<,r:|^7_Ċbʹ. dH`nu=k3\9kSRs +;Q`k'U VRT(.&.ð d'+BU\$CIřm6ogĖ)DeUޑBdTYe8͜pod OEF=݇K 88w{'8z} +3_(@xFx<ArgX +ϪzG@aten,#`*3$l&1+H ى2RxXKcۈvpSeu13=al(0@' LshDbU/Sj]ώzehpdQ dQp *XD_3E;!xHڝ2T2U((0*qAiX3dڛy$bƆn `'IH*jAxeQ^ 0܌ +0|Q 69 A/gxV1@ QYQX*Y9;"SX,XlT`I0 H(øT`"t %Ύ$?2~OOʼn-(Anc0V0$<$H&C0*P󄙧 #A-N @oU 㕼EI5)@xt0Y%BYd+F1*,3<86҂D#| I$Rǽ +V-x7H]-@2dBQ MՔ^p~U,ғ`*T,(*2* H3^00@rz̋,KBT@ Y6a)w\0A}xz@̋2,=Z )/$,[ȤD+ɬ4 V!xjPI!"De0/Q099K0-H&WcDHr$ G$ɠ+6+,e. A PRn1+%rtkL8 :Q&n&?4f,# IZHaN"Nd%/ +-Эx`*,@ +6p a9r>W3C 'xT;yuF;&ʱM%1-T˜D3CdT`'N ^8ԍ +%1lf#9HI|E D,0<f֋,*N%0GTK)DAB4`_0fTLv=+@Hn_Z-Ba<Ѽ fF#}Scwi([mhȥ\Zmt46hrm싎0 /75to=h ZlS`6G."C" !x($ ׂ=Gz?ӱo3$U1R 7x;D +DjY%tE"A"~rԠ6X@cED"ZZ x@=S[,K*{9`J6 I`CI;/-#6I[Xd8- `Aw|@`ȐX H}gF[ǿQYd&R`}B @u짂H'aqoqD"m@K8KX:ԀLEe%`̠kTT$ÂQ gV=y]VnKXI +-`A$7 .V*#7FWd%jqVxj #gю D' + 92@=< + XEyY4M`EPa)D,E.7y!.;]fdI谠*'`|ν@ +oL-\ ůvWs +th1oqdh ,p0Ȓ8T[P=/^&'*DE*`FZxCelԢU|s9ʆ.8 z?Y{NUPt7+pPqU>œ{7 7!]cA4VT·z|3bx2r;ڢ80pTGڠ:j8JI}uee!x%)lx޳=tQȾٚn8VGZ4n85>}`᩶imemUq7Zɨ7vsTuzg0@Y#7k;likNF{R6ܞe-f߫㲅ÙhO{K fr{{(d:$%}8p:Gs[̍68zРUpI%3xI +`Lo4x6a$u]\ +YbUiފ1 KEF'%?NSWֺZ}8mV &#EY崫60gB0l%ĥ(c}u+K +v4q3kr.H޸.׍3;M<7&n5pndsTZ^͑7?oGdF9#˘rS0Pd)s8*j1تjCN%J7}"˳<vi 35ߌ)j=n +KXh m~?z:3UFdjU}/qN*SZC ~FCFWYCtRuDi !;' Q0EN@Y EsA٤y',lb%aYLqY ;\P&`tq͌Lͦlda7Şll{46!KG /Up*\31^uܱڦݶ:xXjàPvhx80) #őt206tVw@  e`_֧ң\Mt2)FDEM}Φ ⪆qպfZR+VSe 4ՋU!!!*+wp@؄Yl3,bV-߮NT(^_e~[R,i3LV'kfFg$lU @#θu#J_3bձY?9an!5ӫi/+iN;[Jg@35Fڝ_dS||p/eću6h,"gt※h ^ +.EeoSYLj0=+c]ikh u kA>Nzak ]^U:|z{ubg`mLR\a +6W7-q*u?[g'w%SkInxo?轐-Kk H,\ :J h+#4Km8giLcG]]>ZPxIPt4ތlI&r*WĴ*)/́SquOͶ۳9]nC?{>iڵĤ.}f[:(;Y b|ƿ&y߫qUeM-0^QoyތgzTġn)@iY9^k?l_vr iDGfsFdvrplDO`b>?ٜRǺ)cZ?}|m6n+[#b ~Yܲ[&+GA|zbhl # +r<~:6W, ew10ܱ+1^7P( +3;4D?)m[kVc3-V-hdGoE%Ji6:$hpvR=kEl9~`*,:^;[W֚Ϛ.ÌtC/kٟ9lO\'F=6H-rHrfAo-,6ՇO}}r# MRh-]K6E}yTJ:dC6葽2^GM+֪mӪe5 hUmY,Km1X7H힃s$3/?ks|h7I?%~7(b&@LrOia&t9-mmGVc +]j/w?dP/ߝf}F|e__tFNvۃf5I{v#t-|7!8<_tw&Nti'n)Q}z.^R-%r=k ^eSt/v}nEjfEAL*;F{ D㑓`S<ѯ{{Y$,mY|bTϳk6YOsWoxqN0Yג]ԣc+SCMf_tAr9pxx8j'n CI{nF#bɎ_ +z(0,zHᙴB !o2|j?J[w֔nhtlL ,gn#7teyaI$ZW%El$@r>csvvMH :e]6ɜWiӆbRmT&Dd2]lPoȉ*>Bұd`$j unѹh9mh;).:՘kffjcˆĒ%1X2%U}4YKub-# .c˸!FɜH;4!^^J +/_t +̱u '.opGr}Y`r@lb02#L\-c1l¼e/vUj@*lAsV[r侐Mb%)@ N9o +ӣ&%.Dyeok7Wwq3 +!PHSlt70SQ;M#˄xr>.k !?7C}Em) 1dziՓvn^vTG*tV/9fWnW) ^8I^0޹&.ٴa|h~aδVb +eI;'M<r//}=`CYRZyNv`: FˠL9G[~4 +@ڠuܾuÀP;-lD9xS%@&!r^|@vOLbsڨ3/C\yC6'v]\UA>yqu*a͢c[p3N+ᤄ']\oHYɦ{.{[lro݂m' /-Rt2M.{ǔYɕto"`p1h÷Rniϯұ޻\:ӛK1k3ȹ,N{@8ؓ6fQP7H?ڛj (cҸME:}$ cHw\rB$N?4:3iB'2R?E̷pW%׉J!Q .vit~:h?+M=CS4 tS*ir3qT׬8_ӄR}L3i`7PsZ!Ym";}Lv{Ls/wPe#sEeb)rh>ӌzͦ4lh]2ivf@K$>I%.+EqS8~ݭJGm.u>2Fɐ7a/KIᆛ, „N +cv+DNN~s? 0%g5EAl ;/H䇙Z~8Ӿ)N9aNܖ(M2DqΐQl;t(Pl<>cw6x1G`6_M7#Id* Y|SddVAPE[WL Q'~b(3%mhɎwr\WGXuo_葀< PP>,n UVqgwImؠFOFOݟx@|7S( Mw0]ć:G4H<8Oӧaq`66}كĥ˘JXf;jwwuK~%2P4BGJ:ܟqf߯e{,عWXI`[O P"?\OC$jܝMݡ|F{{Zv,rٝJa0_Kyrd~R~q; Ƶ')<=X`ʅ$oVzOhX&ݴZd F`HKW˹nILm'@|'$Ith)~[6I_HK#%1ˈ֯8treWqe#._4(6YiN4!ًG7~&ʵazK\ʻM?i?ʑb)Q^qFX]J׳]uVP<8DGWQp/sCPA xn2׼+ xl2ۤ4Nrt~ ݶkͶƊyx҄Yt%iL!0m;))NCnOϗxjFjhL'4@`xu^[X@O\콀̬X;s>NCpnY^98M\)7cvjI4O1t@VM-MN'K7~ρ2Fs<( B5!x9 'x@Woc+}z]֤QU'y KgXW82y +f^2ѓzљa7@Zǃ-rJ1S$no=L&f/SpSOKL~PfpMÃt0MVLSNzˇ|F7ӥIa헳( %r$G8EZ^i7/@ ~ $jşD20Ұ6PΨ7zJ,4o6֩uLJ\ +R߱ֈJ:.׳\_ ۈIv]²^ah =Q`[]Bt #IdT P*5°d@ Y "[7 #e=ots o'*Wr9qzW,-L}zV|EO"ٗј U29Q>kꭕb ]P%0n)wз +Ng +f ЍϲngM`A'hݝdٖp{. *r3>'9yNi p$; +KD⑧W~r76ZQjBl˜gL֓+ N!GT sg0nf=l| ?NODL`2\` \rney-yix6"尔ξ zk4i}zh6 pO3Qq[aim{KE[ 0« TuH/hۊ9{\n{w0j h=UGcR i$5jBлA;NV^h= OT gaMh5 +n;~-W Bl0’m.e):vf0XlZrIRT;C(qhuQJ!GOd2:3\ylM +~r6}~6|o}>Vhˈ)+祲6Wy^HGZuRM؈xmdd#] ]/I_t/7?dv~S~VǓͶy +fk ӕ|<N^-+$Kgak>%SX=54*Ix^ nVI_\V}aʗ4s/ef_6LtēZadE1|,_0k*N4rntL l 3ә.VwGdy.sst8=eJn"ft_NtN\ ?x8?]Y3JB~z ˥q-G{ia1~^/y̼'!I^co<& ~?|.l0ޛG,漡>ep ?,Mi|`5UK\6"t4*M{Vl[L¸i"d8XJT>ƻLr|2LNg5O8` ťy8`^˿ wF'K/07;D^5)ӗ;#ۅXޟP6 +p/%iuX&D()y%/#O2v Gs D3^.(&;];i("lCAMoa6_:f2g7WȁL!{.;;'@l2 WɁ[c,!39s&IL"| rY$?>.fj4qzn|A $ɮ[Sp.Nva(O@25s vĬš~ɳ37!濝n?t8~w:7(tL.}{O.ùwb E{'w7P`7D"wz.Ӂӽ>wpsWUq{䜾ӟ){3pJ:̻3T vJNv,kN=q+)zOҾ)/#?jV8v\9zX<9}6L쥝38xwnipp/YHyE-vg󊹽r^O]~y(Jv>_tqY,;g+8[0݇sP d;v9թ=LVzձ5t/d݅N]zܕh}{O宖#V߹w_Z'*5wsDNwDUoG}|؉;49s?܄r;N<;mt^ӝ$uF=/]ߕ&'d\뢵{vP|5}v>vmi嵴;l{g*xƅ' =xJ'N`ܓO=gُz/r5Oi 7M|7!4z7AoP z말7ry&O7_,7ؑz3oS x{w҉!7ƢN_$U:Eߕ/΀G*X'Âd$$y{ZNJ~P!#=B$u8OX?<=)wt,tm3 Zi?=M/))@U _f|? ܜݎUx7~ץ `}/>͟q_wO%~g{MկtX (MG>xs.[= +$B [C:݄ ;q{]'a8xyY + NMŃ :y9s 0Gb5˜LJn-}.x`v7@+˞lo*s^ d?.]sE.6twqGr+_<ԝ8^xSM7 +I* Deprp {;A c~g,:{Q]b.EX1,%$}=pY\_Zו>;(Ho|:rc4ؓ 6gxr+.9NKjs=T/2CUہ..'+4v!Fi8RI?"odRen[<ۇV=XUh.5j}9OD>;ŢSt/{?C CQ0GOGatTFêsxBoo:ÄDqyi&޽V{yO^tȌɜ;9 WʓIY]wn\<OP馕H_ʙ'$=љȴzwY8 ֹ֊qyĠLi~Gnjz:NFV&v+|_=Sw57:O+ֵ;ƧST`I + +eobк~x?X;:\dyZ )p~#{b,)?2okUݥ2y\8 %;p]U.h$/\b.wZ ]ίNasU΅/kXqrtX)IvWv_%NQ%ҹY+vvdoɲ`noͫ{eu3j2m1ܾuw.tU{z{gݼ?h+^_x`㽇S\=ucj}XƞO!LzԞ.ʅA+? U\t7K*Kx kv^&NX=_Tru/]"Rq]ju|}NՆ޸3F 'I\6zxs;mvq[yyяJu£?Ҿ:xh Kzю6:̅ҽZuۋ^˞>x~=Drh289oZp1ET~yď|5r!m=]^ؿTg5i`l6$J{^}e_[ ?CZW9pt] 3Y0pԚ/xÅ|GI2Tscen2w1+^J-?:a/ncsǽokAٹvv3 G|L/17>ޥ;Q5'^ wON~ yWEݪ# $~cM(;3{&}dhK}&\Ԯ0YcNJ)U s"m]{"_$T{LP;1x} c7yc\Px#3<`ޥ ƣQd|=z*LX(S$F2Ur|烚l;S0=zJC|Ab9* .UPiO/xjU2K>KUPZނH>t>wP/Ad@.*s$-pwdP]ن#_ϗAeXrʉ*L}j.kePqn߫M-t*Pf-3;w'5 DR*`A=fWBEdٳ{ *ٺJ<<uxWA=wP]WTBi3GWv;zxZ5p\5Vˠf#=0R$=uW8O_,d퓕P=gE-G1?\NcrS{~ve*砎wA(,~tʗtNv})U-! #aTkj*a3 T,\[)vPO`43^^6\NP/W@NʅK{L+VpkDxr㋻ ]5;_|o]t}=]l_7I[cuJ=ڽIm[KN-Go~ɯђhvzͨWeս݂_on_6wͱۏo^zřί͝8H֤fWMĿٍ(W<]}0=% 黮-Eq淿l=ݻ5;j%bk\,X,{=t[HB;uuS%^vP8i +}u_yWF'.?ngEi:^G<;^ܧmy{=v6q65n2m7Y|[֯ ,{>8;yjk򠑿ZiL)jv X.d9fr;]LEGt'pV/m/Fo%'fIcO>3.7ewU|^ML};#;`HwQ܀oVab%wm.PvJ\@6ۤ >ӎ҄}{ޢk}6uh&4ϒ=C~-Y>C 8ɵ6 )(>_׿LTsjK-5)WĽwk?k= :A^{$Oe=@JRoәڮcPĭۜQ ZOB}'m֓Tuk6n?nn-{r^\`,DLϺ2hӷoW= +67+mm]%Q>Ao6$ٿ͞:\0}H H|emE9ɷyuZZc}/XT؞l^wKמyT:Y䯤Ջ+}5XB/9Wc4[o"EãZ"J:|+"֮->Pn֥8dʗtXjm۪5 M+/xoO 1ZS;EH(_fgtǒpkzNIt;}O 2<@Nd 1 +9%̞IO݃1{ړ1}㿴q֋y yma{MO[~'C/wK%L{!{.;J}%hͿ+S'{GXcn+0[A S%/ u&ahdrtX$K%_q(\@5hH}ߘ%k{ex+rQCYFsaJj5{p$,uAJœ%SW?Q}Sh=Φ鷑Moz/3n+ErݥQt+ TۃP;OnR)x5nI.zfҼ.PJFK$^w򫛇AjggV]eLL;O^Ftm~a )&CL$Y]mB7m){K{(~{#s6 +FUMQP{8&ey]ͭR~n{[I6WQ(;|!Wkweo#yV*Z?Z3/ҫvm5|?> ݕČ~ uVOG(Gy<$fo;BR>6LXٿqnLMqnH!I+83*䦘u8Y3>,Ӭ!T(TwXitA%:;phC&(%[gho[?pnM2An,:fyH]6wY_v(d,8}#1^07}ݍU˧Tku_W7;/Hb||n7u],ٝݗ/):k7w],םݗ/P;/BW|ջ)z."'o\o|~`3[1)՚zǴ4+/|%>xkSeiT?vA;M=U7I|G-ŇWMa}À+N|߰knjW@X >o߳=R/Z=7K'|]$2>|f|x7BLl<Ko;iIfkwE~no+ܭ}xMnsOo7}MbSidJX8=NR mn)HIrDeIK}Zh1/i7)%NR/>\E.HiWz[S20[;fDB^R^nnۃUKnBJ!,s[yzRMj9pa?ﴤ]@)?#Aik{.hO(OG|=Yk:sګözi[z*߃_u7ݐ*fo1q +1i#T8UA֌֥ۛsy{sj*8ܖ%:ɿN ZYJ~9ve{3 +pQ:&ڛ`ޘ]й9WwPc TwPmV]c=i{tBgzH #lw*{֯WWg +$dp4(BJs{9]Qɹ H΅ :0V~BqaB{xg^m9y%2=Iz{U + {vdTGϼQXG/uw쳺:>3@r0']GS΅@$h:])m-Z]FJv]SވӘ[]2oWgn{)Ϩ׭=NyaO[ly3}>[p&έ6ntɀ<٬^{P.'c KoސjX]tY(AE]q2ݩ>|}7:̍ף3/m$'NSgoN|9z%~Ҏrݿ~{?7Kj%s+g;)fg\+Zz~l_غ=wu;8_<p{mFNak*>KH]~ֽ'?,{)|e}[o:S?~mY^Fֽ&QjO1k%}Wo~عMwSAt|zyCyJGge-;5ezq7ρ^&בA)e9G"]EcDWQ5Mj[鉳If6 jYTx; viN}']Dl7"+`CL|uugu3Dã}&?it3jS_>ST YcW_c_]c!)ಮ}^}H2LyΎ}ֵR{ѱO:_L5ŭֱԫc|Ǿ~;7~ZLgէܱԫ/+ljg ֎}:,.ݱϔՈ;iއB'\>IcWHpO}2kgէV5tsXc ĭco8ݚ:~mmB۞;^رtKc_W:WWWfm[ǜ7̿({6μGf=rxg =UQ!a7u)hxI +K?Z:,SDaV;/C 7Mkg66_魯+nO9iˡWf^]d?Wt +.bn+ap2oɎ1q}p|nAsNx2#O)=z^u/| A~:'|=m|:Si)v +uyX QVǹHw:J nv>t7>V )5Vת'<<:ݚFM :{dZ&dwOby#SOIo;Iǣ{~w|Э~,]Eo$]'Ļ`n^>ַr͗n]\=Gk3ֽooklKl]_;5zξ׭R8륭gŇI{}䒓v[s&?nhjMjXw5u$vkx{̺їct~}~[Mљt_.>wsp~Hg_ H綤ZDڻͧǕվP8(:_7Jp2HGpwzΘ{W}Md_U(p:XP7sTE +» rCv+pU]vਡ%64a?cʅ(;700Q=1*t:¥Rt%z7;)an7 +,X7y >u=а|9;>mw{ iI_މFZ.:ú$]W=sSIV"lB'2tm*1WA۳;jIo3bd g+& 6MB4_ݔa42 Ea#YHΪ,ߡmD?B(C]d۶Z.Q=X/)0@pү\=ԷU(Q;oMgaRXWۮ{'כI-5[M'mZZ\Ͻr?9Z$xt%1?x_KbA]Kء?/%1?bB#WzJJtZKXDSKbp0Y:`&+T.hOғЬj_ t<̷_kЮjc +NV8:,suv8Q*Oxz]wCwQժʄ/WǨV  +I{.;{CL)5[Yް=aP~SX +w(#&rۡPEb  +)) +OxX"̄ΑvE'<^Lxi'< WÄndwe'<,q9 ݹ):鯘 /*Nx莣1S|Cw[]nCݛPnT}6&u6i%&<,P~C9d[PM K5qOxh% Lo섇fw8Ffޒk↺lӄ, ݳV k2aP_r1w .e0٪U?5Lxh̻Z˴g;_Wݺ6'lvd3sə[M&#}4z)9~!/?ٍ/ܸ멛_۷n//7&^܉scH+)lvizAq[.ێ_MQ2d9ŧݏ볳Yӝp^.]{}ms s#3?qLMIa{bF^¾X᫸x =@ۺ:_0p~k}ZZ~lWs2>}/5WݜX|{o/Rgs|ܙ&O|vwWwぅR3 _+0 +ۣ4-vuw<-!xz߻IHBEwՃ|'aM$|ޞ_Hzl~M2룯_?)?}~;{ze*2m@wK Y$ͅ`Y0!~W[aꔴ[q%^ɳ~ٷ?]xr2\ B|}]\N֓/~Y]q99if[n޾m>|L'3`(=JjEEx^ZGLsCL$O,3U;ғhlp@d4ص<'fo|z3~6)?\ϚWf2>._]?rd#(Z7{(oq<<6wDy[ėT2-߫O6ҧr[M/޲?zvM_ZWIφ/y4?7ɞ0,JsZ:vnpgba6=tMd҅cJ,Z?ω?}͏#2?i;61~HOe|,oe#:= #?9yx.tWFN\$dEgort&ykz+2v᥽ ϳR Akc}vy2'nrH?ziɣuXoO<1[zHVy{~K/](}}{ٌwLB٭)1:䋟K?t[k?&6Yk/q2o@+-.x]v>_J>WN/ NM3ɐо ΦJxu/uzNZd8x2>U rJH9cS_Z[W^߽ٜٞVYlP l_{詤-<g\붧J*ixqjA|O{WE޷.T,:\=8tɛ[>?&=zNfW3˗W]*\?>{-w,N<t]N~ki#g~xsL}~浩n]uXא>#;qA>bS]S17𷞥r`\2Wt[v=Žө5뫃O3&n]lfz,+yID1Ѯ?LuAje>:Obo%Ux7]V%+^nJ+{&gLQpA:7Lb=KǴb6m&|72|B\{||(gɣîo̕nj޷'x8ʙOÅJK7z$w)5fDrU'wП3vrK<|u[!Ȕ|A;WB4=i,޽*\;wŏ7jÃޟ zy_09yxͤp|6{,ݫlg֞/%- 6.IF=Kv>w_5f߽y$Ӭ}糶Dbr{.1}iO[S@d_Ox7bܫ^:*gY"]^eWZâdr<|twʼn͍{O/sVΧ(.y]ou.-I{gǖ#ݸo?o~{3+gn<^u⹛}?u>${ؗl=+1nuiأoo5?5?n*Ѫd|aߘ{%׽׈9Mo^ޢ+-ڽFZ"!ݜ0=]dùCD"έܜ75' yE5n.*&WZ}HvS""yԭ`TOPڲqnh&]˞|fZ>q"Flś3/'SǞntks&ڤ[wϽwKw?I-? 3x;rLcz1j}Zzaы~r7ϔx7\%D?D9XٜHꓽ mƕ7YYǯ\۝[d#맿C|S_bٜX6ӏȎήJKp*_ZeoA_)oAEuq:a`ëI$wVroA'֟x;.,Pz&ɰ€v'x? n\av+ғ)6M;(@\iZߕM=,pC6XxDۨy;E>R^NZ/piQZ}g=BSAdKo<x6Eꃟg{y~1}oݗ2ޕ~-ٰ__iBz~=ZJV 3xӔAmr'|*{6+jM9BxAdsxBO{]u㻜_s{U"?{ttKq:[ Tҋ/yFO?=x.JWq;$]WJz2}>\tsK~wty&s{<{v[$':br9;?s?{ڋȤSB/iI&׹n#YR=|լ)gS۟ag\ֈ7wI}Bqe|&;c|V^+|M TS"=Askr#^93Mn\|Xn}o41i૳>0qn|̟뽹?oo_3+鲝{wܺyfL^3UkֽxҼvwᅭct{H;OY?s̋Wg>ě=~Ϳ_ޣH}G[kgv΋,:pҥ3 /+v>Y D_,%gBr_09|{v%>K_ta[coǍǒ+p#JMvtM pi`J4 t5д`cOU U]ѴfhcIJB @P8E4-BC@5 $4]xhZ..JҴV84]FӢ$tY0p0njmhZ].M#AӅ1iyMnjui84-xjb4r`4>4|*t!zihǘ%@1.5.VKǁzM7.M !MG<0@-Ѵ"t$O Aiy$MK#84] +EqӏapMiL NM{`ZPKKܴRO]lg^])7-*Hz N&MmS.X5]iOOnZ5 ¬f㣣OLU> 2iǕKz(mfC,nh24|}r" +MX508cܸndKuH 4-t)UҸ^]\h p-k'I&7-tTpi\1n84ɘd8I4]Fi\.n _NfqZWx@bO>2iqMt T@o\RT!oNJPK.\UOInZbi)@qE]\#ɥFgB9\X.+D&7-]ѴatIS޸4-qZ' W04n ("tխr2 KPQ Ƹ(6J; m\Ov1M. ?]q~J,@sҶ0E}`ܴzh,P7E;tqK^Kw6dp%sUQʵjV_PՍq W\X%ep%s \'1Mk0(Lņwq#mpj}ƂpclfK˅r|T#7- K 3CƁaҊ8\ͽg@p]Z/+e'cC#m.!ԢKB8\Suj@)J o&U0BCd2IBq..a5* BV9P)dLUi9\&{GKnK@r" tǡUq`c4v]\`o< }8 mjBnRdLVNM.Lydo.Ա^z+nc-MM:zS}Z9 sXֿNOvde/ 7ɃH>jipiRE{cY{XAJbE<&Cc.:D/xUvs2Y.6\eh 42aRʙۼM;Œvb+a15=[%TC,۬l2Y,@%&ieɡ9!\%`ȱc^<4nI޸4v[pb(.$kwJN^K&M2^`@~~oސc]x0c1!1USHMΊ9\/C)ne%2䣬oǕ݄B޸76rM]q"z, (h-!mdc|r!l KdBLriд8f4}֠UUQ{qQc^K\T {kV}_iVgbu.}-*&YǦI.7qM 9cCj8ZE*X;t*nibܮ8DEky;/yPEYh{fXv[e>9\&&y4$` H8j䦵Q;tp8ZԱ(Ge(2q@?\ l8F `b; yf[6:kwɁ2٘8ImkF814{cT+UO- u,xi\[aڳ"m8ޢ.٫g^';d$da9&YZTͪEѢx\:ձeuxc8&D0!!:.\ ڿ0,c TʊO6ab{B-Ȅ"Yd9yc!lK:, b(_ 8݄7!m g[Yey_6doXuIvh4M;iY&h!CmXʆ0c1b(.-jWHPPo&hJ2Ym}ebDB-5QѢi tE;KzcQ}٬o4mc>bwuaoݩFpJYNJ̶#>+Ò r5; 0L +Y1hu<33c 9-kHlƎc+Kpu(@#s!9-Vbq ưdlbI> + 0Jw\: 9.nլKcuZ(vmc JYZySf0d(C]ÒGmo HW#+'ji>@ձJPbENŒ buXbsX$s#%kTV-2TJ&ٶb_^,Bd> l EnFnJs5EST1+uc:.4Z(QC olHHcQZbEץ̅p36735ok{׳2+9(de/YX7}YzE#ǵߥ.L(2phVqԱ(Mto<BNʏoBwU =ءmՖ{q:ZN;ܲw/zd},Q;&Y䯛)JYU4r&yj)մF wRHYfTBmXzҸVQ\ TQ)2@Fg0]hڬy孔ݍka"að$+9y2˞Dd^T#+'"7j{1+U⥞PǎcXKcQNvK Nv@ WWC59|qw0MBdn~8:8zJ9 8Br\x@yeձu*BB!XƊMܺX56ER*k۾xXQ`r *.cY[r!lL0W H"˰F>02hN)x\h +(˩Axc9[G&ftX34"lC*q8 (%yH dbdrr&F"тPd* +;ձ;"MkX8ҷLXyqvԘUS΀ڡ!M`dC)74n"ɊdC0,hܴbb wlT333ձ7Xέ7"m­uB7vUoVnޣ-+>P&{MeƽN@@hdt"t|G (XQǭpձ,9K0n 9VqC)tCw%m!EFB.:3͸WʉC{adr*qyffFȺ8M B+CJ1+8K#ԱLcYNXv6o nc3& pEp¶*҆.0)ڤuf݋UHqo'vd%+IxZ P!9˓*ǥձu'GPoƐcKIsc %5:^*bGj8*ii#y.C֖fd6 ,ҸMr&7 Z(#0,;dFD+ a^<6ZԱwc}dVQӸXMpHpԳGoV޽rlbL(mYEI mC[șǵJhd9;ʈI;:MKD8 "%Ŷ%ƬPqd2ÅԱF*t[8Ҵ,ءsLBNaU!I@ >ZrӸW ĸ^Oő6G&Y:42˞@uhQ( a^E2Y!qVd)1+c*˿pV  a%FVƘ[T$&UyG-cXW#4xlC6) 4J + /ĪL;*˝=0CF+ 'a^u [Q:8Kf8˪ eVǎqQY }onT*&6cЍmwP*쨛ՑJ2=+ A˶d}sxiP #,CG(0U[ZNC[Q486f{c4UԱتf u\ 3gRޚ@fpMTcX!cܼ 94Q\q{N~\ =(@#*k;FS.X gѴ\Ю了(xB1+D8+ZhQ}ؑ@#UI!?5/)z o+{#C}V!,aekǵjLh1Pd2v b+Fu,ew*ce%@)BDvMI[VwږsD]mm4zyW<>>Xesť5rс)CЮ{[/OlX:XXJ@VBkձJ֡mvj6$A#@n8N%7i +73=q+9%7+9VZJd!lYp8d8 -4qa+*+ 1+1[=u*Jǩ4-l3%蘌ƘXlT| ;H`+-VX%-,嵺혜; YYiERȱ2fEwD%9aN״tp.Wǔy- =.:_-XcG<ܱ\$F(!NJm{ceU;o#4vcj9Fvl(PBGE5X=s`UwdE(&-c6*jYN/偑 ;PdzPdqȁY45^=ùP+zhP"X,,X"&:ΊY}y'X)+sڶ*Ƙaz՛"&(ц l;vfn0ZyUi],g52^7+Bul\/˳h(r9pM H8 ea+cۘXr&u9xcymr6JЎt;g#mm +:{34`ŎUF]Y sue1ߊ,MkH8 ,d[x,ǬhK7P+m +9vZܶʸ-Ս");aG%ppY~<ܖc46V= 9 s3kd#ZC2$2&ù,BV 9gEAK <xq="Vk}m嶲ܸVOIJcѹrgʛ-xJ-c9Oc.vrdcY-6ح#Z!"gCp.ڧsc[qfUmظЫm9XW͝i,،2fJ9Gnq &pTa^W?0cE ['"SrrJFF*8 + Ee^a+]^9Xc8Y"d +0bX6:q2(UVJM2͍)#Wspћvq`>;Ҹ7׏ĸ\T#+ucD 98&8J,v +άvGg8%%Qp sB*mWǑ)8 +P*dYն,mVl)lR}n"Eu5rPt4*e[r}Grظ6[#ezz(r>df4$rӪ"cmV YcQFK,}( ;Nod+t,(U;{۶ 9|oC馡G;0nxx!kXh6[bz1֗X_npE!dX {, "arlYkIYxnHrmLIcemDŽR=9R71@RDe)-u7p[&J2w& BcJ};yaQ [Y3F!Q`З0qV͗'k;qH(r9u,獕ɫ[Jl睭c}CȂ7Ock:Z 0$ƸG*re1XQīƅerDY1苪=wAV[U dk˕=m) +endstream endobj 321 0 obj <>stream ++K*&[cC6άWn8 Ǵz!C"YtML*8dʼ8+Za+KBYH%c:֗t|ؽЖw혍 dlYy7T)CoFwCeGެWENcl\3pQ#+xqP7EE2}>$r\YqwMkN`lXXL'й٭'[1Na+nǬPzv:V(yEU#-YmM %r <'jW6dCKlfے"M755eVO8L#WqȲ!C9w 2İzq;?Ex,c=A' 9D 4ޭmlrx${YƠb < @% E3,:X"D7NCEB p{]"gǙ-iBmLV>z(Ų#7Wk;ؖa! T#iuKнkU&ƽ۶5.Q>ʎWIm޲hBlYypYX8ClZ|B +iۦGN{l"ʻ_} d"Z?v*cȍ,XYTYvz$9YQslP(+B9|[w2Lq/×5rƏ%Vֶ1ݵLY8$26+=l݁XWRFUkKfVC6}5rQ$)7zh8DMظлaGUݡȊUͬX8dH9d0UXJ=- R4ecmr9u7z'{嵁H)j:&(5ux hKdX7N_FVYH'ǎ%7Ҋ4K9"{XU!+!!]`6l2Oho +cBG}_JQKtjLu$Гݶtl9d@MfT"&ّ̱Ħ5l";DCG5L̄z`cpñ!V( Ď[Eyh\[B+XI_kDUqNTz8UiY(('WEìg$G뇤'E+;PH +<9ۆhSP]gp4(|Bx,cBl?-Ķԛ\GL&\.gFΥsf}W7/%0~to+L0"pSP]1÷r1D'=CʰXyf\*kQ h)厺Cߩ-B5];f fs+v3y|)m3mͬ <V9҆Dtȝ8SSSwȃMkQbpQْ6eD4VB%lBmfHb-+er!ol!kݵ- qN0x-z6mٖ[/7&V.c+%c;q EփyK,>*C"+z1!d@?GxȧK'm.U޺ƘҸ@ylutCvf;cG|Wȑ)2Yr" #mf=[r'oEb9qZ#2h@V.+cQc}<=8eQv!B8;$w4c}I"ݙȫHSTh>Zd6]ܱN4֗4#‘2+82,NȴzCάo*YȺC43_iy/ !ۂCv!OkٝUge{O1cw(r]>lEwn,Q5ul,m<%0&E*|bεY^4$؉YI,"[,l)XV%!c\uف!uMW=H#!cQb2vbw}tcE +g.kmK`jQͅr93`3ɑ) YOimst/Pd}YCfCnvBu)Я\=r=:q[YGYbYrd.xlPOl[b,V\`LSHdDeiIm6 lqUTp0dǒȤm7nQ/k[e Kh G9Juq I'!x'== +cQ+2Y_kBr{˜($Gvuܶdݯ5dya@OXWMi燳8j9Z5!>@0.Jc}[#;{?a4+x3gd3_h@=rGĊ=Hal,cB/I?fK:y:׸ab_Idź'e9♋*hde_ƏQ>rXúR"p=!-Yd";dy&9t,A;) {'={m.mEIX$Ӌ,}@?l,ĝ -lc12xEi{,p9{[)zIΖSXH{Eq.]ؾK 򹭗H]O[Cu@.Hi%4o,!X97Y|(ᐳK;d} @< شF= ׬>Ǚ@.mJc]Pp>lneqCGmM TOc+K!Ww!dt4Q*ƔI)x!+a9X!g"N8#8r2d{,&wlQjE)C6 +XdVlE!1fw9_nݕH0MYWc±Wێ(d+6mƝ!gMv28dC> G9xŐq{,Ǻ +8L\R9RrfU)om{ywk0,nY,0dwΎufeGoRn9iXNV!Cv dqR/8S:y{/=}9&Ya&6+UxqG]J+,wUnDNvTpp79Ў+B| ȶrn"p4-ӐCRr4 cJ1/d8k|!\=b}cߝu'S>v$ڦ!,ulS oio\e;6GBT "[ 0 l¹޽֛[0.#TuQ82$;&,urv|9kr XSWy='K)mdqd"K w ++a;>ܶcO6*b'2 jm%Du!/tKc}6R†An!:LL) ܴX=VycaNJ=n>vWǎaXOo+J+u".7TҔĶbrbm o2wjde!ٶMJY^.򷾭{.e]ls@F,C.d0,| +Ƕ8^bshVJr&YqqZh$Q@enJ)&ٶ6Tr2)]qQIXN8pP` dq=' "M{8$K!hJUrmGe\[Q;:.8բmPQ_E##daiU00!G[vErv!7-YO,RPm +a[ū8cNJ +¦C.meX5Rȭ́4`ƾcmRY'mWtș2:l0dCnCVr l!3űc?S]C;&4Nה=bmm:1+ +㎅Zq]8? @uk1Vjdezd]iQm0prȶ \}B=C>>xERމ:OXǺ%V*T)c`k+Y<&sl( *Τ8p!shcel[p*Y);0ũ_7)me\y=cE{,ʇ{l,XlLxc\b|a1Bpl(hX4ENCk^v`UE0Kmpo_@oX!6Nb,_=Vz!0߶ZzzdJ?LRG}J@l]r4VR=k{z@,X%Gȝ"={0dG2YAjE~ Ƕt{g"'C!q`cG Xo goi_@wn!<(ؖ+Zضظ2^RPOvősBClZoj9J ^QY+X En;vBc]&)qI. P#ha[ks%C62^f42Y/j-J^!qb<=zfX<{*J`I%qxՠHt[k+Jۡѭ!d69HBwQ؄zbCf cA?D+l ])bn;=c,rVCبCʥUK:eձc{nI.xJƨt"_L#{*9c!+3cܩ{00E"XRPC {z!wcUJcY #^)i-8P;oLGD t2&ٝгuxpCvbwbC1s-mBV!3_E>NYXUmrMuB^JiVj9dW܋M)lpC6d}+c!G+Lc#G ,"9#8~"cH=nYil8&mf;6lz:u\bV8.%NchKkkȺ` wuF#;ger!;y 8Qw5x{Vlب|unC,om?v@&Ni6Q PЬjNCc9NA9cm٘RqzC C} s>+Rtm88E!!F+onˁe[&ۖJioHxpi""ˍrPdߊuH`9d=8,굜! 8#>EjP 4w^+~l8S߸e8Oܪa"&9s`K|!cF~\ +l-;29w,x@Y_8d8xEPO8*>ȿ,MA=^ 8OY]G'oA*\=;4nɬ%^yCZ18j S n6"rX׿z>6ltJYD"pʈƘi03EӂHS)B 83 c& -i=V8h[b,cqŁ8ec/U6o,M7jKRCDXe. Ybmi"K{[ѝg9&Qǝ@bxd!u@ǔzϳ7xWX""#u(m\5кTuCtV !䐽klt yY ޓ\=HRǨy#f`wpR$2 JWïjM I$XKѻT EV"'mG 9d}a2쓅c\} L9Ƕ+U#Ǒ42xEyI+"| RE."6ĶP?zNuS8YX%Չ9d!kuoX +POfy +`8E& o8xE顏{FEqGBy.r^@TdajҡJ!=ī;dZaɌ`@rXrgY*^ܴ=BxV+>w^Wt4{nu{ }c4d}Ic.D5` woqF= `^z: E/qɋĵ̴RO?Mֱzm6> y|PFCnP4 nNw^9"#+BRӇ FI̮n4n/+qmAcq-羕b r筶F\`5.ίhwlx C{Yk,MȷkȏOį緽ۏc=~^|]ާU+UnKi>v4'3|[#qq~Q9'VFQC^čg38{޿/aȗd0,V7!_Y؄|'~1l?Nqxi@+9q?y-cn?;RC:3xu ȍJYMdFFRאaݜ{ӛYM8&6" eCN聯 NJ~[ zܸwiLN;j(F+nGxp~4q jlw1|v79Ґ_qOݢ!ǃnL^ /kÐWYlBn z7=Ot◱;" ;Wzr:"} iU.,f8..9ŢT.طxOr;gMR_7՗;c*ׯvlxEzq:"dvdE^6aNۏWW9^19hlE~yFIvFzRT>aqq~ܑOofpV8^lEn<rOr~5ǃaPr>MouE| c&d xdxrr3ݖ3Jd1R{*>V_;~n s: IaVlnѐkW_{:Ȣ< rg}vl?~<8"n?~(zِZ4n[>UWϴϷfy?^}U;H\q2А/k+ZC.B%I-Ǎ-}-_Ն X݄ʇ_I;^B7p2l8?GHCkȍW HwEړ/A6!oda~ش8]fۏGW>΢q\{;27>40[J=~Oؗ+coud}c]-ǵ86[]k9ӎqq6y6ǞmB^Y$mBNY؄|g}Ѿ?B'W>8a`xEmLvigRyyUqu)v|t?PSsCo/>{YKī'Xh\\:~ǽnzwWӆlۺq7">N[Xăc85mx{|S)rx5ܧ~1;rkYjo9'Y1>ﻛ mB~\n8tq;627H4on^*?j`???]:~¿yY9#^8^`ڂay!ǃZL=YōAM אָՉۏ}y.Ww Wċ9qxr}?]oxZyyK} g!v_˙XVsd4m~]ۄڄ|;g}o?>~P68~Wl}=v4^Xh|n ~~j\ `B_0!_>ާo<cr|8 9ld.h x{7ڄ{sg}N~;/:>l;/$19;LJW:;غ!m<]W_x;}!x? Ɩ[4Wٚ՞_Q d!9=_nB^,{@.gCUz{DZ 8^kǣqHiR^={zxw;~;ɦ՞r#qՓrc. sy8݄Mo&ؐ6!Y_m?~I9rhWP|6=J/ gqIFЍӹ?wOҐWc9bS,^MoujA6!Y_;o? ۏ<{^Q[2Op浨2dF`C.{Tj ([qnz,b8s1Y[܍ kFN6>72#T>0_u|;;ONiGd1xd9>"-wބ|V }t轉8~Rw^ {Fl|x{~tq8?LgkgF<0lٳ6,һKelB~*g}e8$+2|{ŃxM*ں!q\pX}vDl׍`Nkw iȫUVO (&/={]޷Ϯn3Dqrl]8rJrK=#s?{cF}`Um;fxTY˧6!_ 9]^*W)yJ/}t=)_ow~ǯBeqǗ^V5iq|J=nX|-%v# ۍXt*kqq!_6!wӳ i}^cqN?NGOl?NO+h< #%9}+OKxegGNf ^T&p\Menz~&Q'!/ ٭69Kq߿o~,ɍrxEHsԞL)TGe`J4jp`i^^;8Ѣ 9; O |m?^}oP[/ώkA?HZ}z5g},SB`Z[3KC%LX^& 6!7E}}ۏcO.1#[A85-9m}c,#+7mw͑FtnZ śa[s[o?U9T^)?;rXx8l?N[VLx0,.5>x\>\=L;t1pg7tΦ^tƵf5 / b\crxMY@>eS,NϯX~<8ۏ!gN<<7uz,OLq[8Իj(.K. 6!$ Jq)m>~:"% ۏg~<˃TWCH4֔E#g1K>`iMǧF6򉛐ǻ7!ޠSobqxɱg8مf0/_<9/!_ rVV 9lrx&ƭMǭFG>yxYn?.ownFn{ծR{;ڳ1=aC>ڛTU>F^=inB.7e:_>J 9b[=: opʟw˚v@ۏq׶[l?Wʫr||uWcyҐk-;ur(*Vvr ͿwބX, M1 ^)SW\d9~$yr]ʃ<2U>o*ɫz kȫݸ;io-.mBnt8Gބ86, _Xluvϋ8}^wl??)Z4Wn:Xkg7QyIq*r֧Ww#wq qSPv+K 9$4buq- /+Cq0}6}m<=y<>ӷqz͖.ڲϥxxF#%gpWa{Hκ&8obڷMݷ˦X6 XǼi4^?dqJSg P=IC>qE;&?&tBer~+=S,F3rՀy8 l?^NƟw\ƒ ҫl$xz y`rpEX&v(_%\ބ>oӭVrVze@&GoWۏW4n̊2 ?F.8> |!;uj?7!ǃD؄J/b1 y)W|cyK@ۏC2"oW?HSG7.8}'z Ps\{vR#IzrVیkxya8݄ܾ^# c@/ɱЮ:N=X܇]\gm?.d8>l[?c`'y|EyӼ*I9;[x/[n=biȓO8=ŝ̊$36w~Ghxz 0|},.X^L?'cN[cX<:W}ee>_Z}^z2;ho?G.0Pۏ3[ 51# y/wdŎMݨirKq+'_[eS,[kdŲ?W [WdίXIKM .sdiƳ;>c`Z7)cֈtMȫ9K(4z1"nBnLބ|uK%w҃՟ jۏG~d=z)?2nI5Oֶ/:[]Oی).S,[M>WۏίiwdlEځwl?n\eϊgwF<zh5ReIy|lť>FS,b@|? ȍ}q6"eNMϋ?Cݒ\)/2`5٧WӾMȵ2\.Xw+nLoN$ҋMK:b$ MD7_ǡw>/[~|JUz>v2&9#{8=YnBXcM8':ίۏ{ +Ncrz>u>/z}P<Ƿ}/遛K7!w=g؍lr>MS, 8߶ @+Ҁu~Ev8"\ Է"g^>o>Sg?@nTdԍ6!݄Hʵݤ:|+l7rbqJq}t6YjۏӀ W\'ί܇څVݟc2@۾~ɝ7!o +\Gb2 |Oqd~E# _Q+ɵn.n |b1-~_:qrD\;?/% OX:S,)?~\t~Ų1}o:?9ه_:eqG7!wexuYmrcqLS,]/lŏ?ʀMwW\ȃ+B2yxP۸ۓ;~_2[D}i843W(pmqԳF1Np$b 7X )A>^ +F +.؊էjیί]ۏW/v1c` x7P$ZanU>kEWX<G@^֬r~E:9YqZOnMWdJln?y#/`qz9wr;UbQ;LɧXl_VdP\ɰq~EeRlۻGJzl1"hD#=1FJrl$NXWXćS,) W\W>_vl?^[:qz pxvMqѠ6!gfEw rw>6eq~E#nEg}ȃݸ1}%$ۏ 7!EU-Xd+{m<.crXbׯ_ܘb @.W\åP0 ̯hwPvn~<2bۏУ6!7?_Fa^}8^S,r ?A~H@NW\ g+By _؇|d~Eۏ!);W\b,bQܝb! /n79|_̯yuqV>SuZqtarvˍ`m!n1~%-1i.; @^W_%=^ ȵn(^}^ָvl?n 88!? RivT2o/,ɫ9v8N0݉i(n:7>ug_1'y +ۏ6!׌L8R=Nז\4v#7 eAuk䃿o|^v @O w˷eWGiۏk~5N܄|<muq3cgsbY}j_n:qE}~pYY8eqX#G3NC@~drThv>ͯlK;>d[aGFtz)娊;b9y1r7 n?er ! ȯtj@~89 PtF^=|:ބ^s)=Ñ)1eqc rx}VXL@ Wl +ŵ}ŵ|l 2"UVelfE\029:1F@NXĀ 3 A/w{89>Bq'_~~z pNbnX~9{ }~Yywz@^_ѾKq0FYr9c*[0W|ywn8LȞm h$|amx11 AG/6w< zt낛@ntڶ|ݗdۚeZΪF|uxEj/n<kcd{H@^ A, N՛+7ܽd̯`ӧXrZEYQq1i@N ?}>Q=~^݀:bd$1GƕX?y>vhtS,6=nXY1/1qѻg@}erht[r(Jr<l*# q^M ̯PnkCTmx@^=Z@n||xE ѻ|;evx>lF7n_5݋k|.9j`+%lڇWVr6FыT@n @Lz˯0x0~Ӗ¹+Ɵ! |.b}H +k׶FJrRCnG/7|)Y@^9}[ZH@N%$3nܽpWc>2gt3Ҡ[>r}G11 >zO^zY@^؊ӭȵ^7/~ ط>c~)Xlڊ=^G/q_z r>z7 whȧwV+|]ͯXrz& iN聯䗛AouJ\e+|^l;}Qˇ崊-ы9 }b@/믿1e@^rMw+rxFg^{`P άH ξr.õz>ziLMIXzi@O-X@~rt\:q1v#%j8cn9~rtrv؇?};re^ ȗVgYl?*<#oS[xIn?lt˖|:p&ׇRGO@x^Grm+H7mq yyquA6{N聯xf_w_=w nV&VۓuxE- ~z-Oe9= s7 l BoڐO/;!3h0sWVG[lU1KvJ#l3 +3&#j}MW_5 qK@}\6r2 / 9S9|W|gQҀ>ϧےuP~Ww'Wtȵj+mm 5v̲/xF@eAҧFrb1_> Aow@^^\|I!$ g%9>&Z\Q>۽"ll1[)][gY\>N<kr. ?}2 /58 iUEI|6rveWMY!_Q甮i+rǃVPLHrr9.r_ ȃi@9A/nzK ^g9݊3v1d{\S0d3&Uj{Gy|l'K}Q w#{W ά_}X,x?C-ǍY@^P@>1 =eH@^q2F|- Y^~zry~G@V +dW+־ceSiMJbe'YۄW_ ȯuLqzq! w?ʀb\>"Vd8$,̸̫Om_ΫKrd ' gr#ZpLW>m9.rzo99 % s5 6i@w(ɵn\n<^m <zH@O[VP\nE^=X{r^1򑀼:9 3qM50ks-?v.U #kMgpJy}V.l%y5 㘂qqkS,䑀ap96"ħBe6򎇍6^8:F@rȴY$z!uŧҐL:s@9fSH@obs=ߞ{iM!>yd/Z%+XcqhxPz) _O&|=C@ y._5 Ǵ{]ȯ醴ZC}qGΏڏcj ?d5@Sr9|X ȵYiIE7N9>\4Q yyP/F4 ׶"Iy䊰1 n@NM?W>Mё6*݀܍cYL+>4bŵY@^- N ȫS,0 ,yz1 /ߢqe@r30|,õgǯ WtX ]}Xer8 +ׇ݀|yH@^f;O@^}Koڮ\ۙ\kpk=7f) HZ}HLī:C1"| oooqӇ)丯cYOnlq-~'Aȫr4_*GfV\e8=߿ #yYP דY@^l, 3Gr{kÑK<8 0_{Нex/ 9x=?9AWy ;qwrE㪉[4~Oݿ +u=ZH@)#y ݖ, ?* 2 3yH+ۊ\ƫ컽q O\G.j` ZH.[Mm<ҍ2 /ՀXLǹMr:[\.FVlA@6U#PDv@ܾnEnׯ_ keA;ez&%&8ŸpZD|J@-&qJ@ޝB/ ZրVՀc +ǻy>z|J{ 1gzC +{ꅍŸl @Cj:GKywGJ@^V*AXq;8bw@N˟h\YwJz`@nՇY@n,ȃ9Go KC^b|< 3q ˰$1nWK nW4 [ŵ-q?n@>w7 1 /5ǭ=ՑI_ @Crh-= i@^`l;ؐ|]Z@nlEn,ƵQ1J{5O@non"U<29 ȍǵo{ y~r~w@w^Y@޽xM~Ecr{Crnz y96, 㑀ȵD| sZI^oq; brEelE(nY@^9% Z@Nۃ꼋A2<iE@^lF̊p8 #yY!ǚ:[@ۏcW-H>O_ sO TngCr ƍr:,Z@n ˂D4 'va6"mHL;7f)9H@n$h.xYy9.^o<7 %yy.  דypeqˀ\&#9_M;`*7 + rq9 ?~3 ǯX 2 ߥ-no\+F@ <( vڄkrliU?{@^K"&Wl +ȫ'kW }\Փ#ReQn% 7A@䑀(ɵ ?|€F{G>u@^-ơY1~O?y)'vv@ LL KL7 9rL?ׯ_ ?vq|6嗈iU2Ty /)x9~{{;, w߿oSosr?# p3n(>Ϧ9߿+S{܀ܽ.V#F@|WlNrP@~l@gyx|ay 퀜pv@^nKCnؐԓuѽ6dyl@n/膲' EI@`r|+|=XR@>Rdٜ7Ţ/?ׇ҄ ++ +峃w\F@._+ ' # Rc7Q@^/ ބ?E@nզbr緩5R̦u< ].O˧ +KCLm @~( rf%  +dY , `Vr, A@~( rf%  +dY , `Vr, Ǩ+ wg! f8=# o K@n?{{u*djkdھ@@l# b|<ޓ^OA@E1u@>l%c +OGr;y*djkdھd@u\<c 2;9k, ܁dY@ 0'9 +ڵS# E@n/X[9d ac@W@w3, Ƚ2 ro 0'9[ I@, s, Ƚ2 ro 0'9[ I@, s, Ƚ2 ro 0'9[ I@, s, Ƚ2 ro 0'9[ I@, s, Ƚ2 ro 0'9[ I@, s, Ƚ2 ro 0'9[ I@, s, Ƚ2 ro 0'9[ I@, s, Ƚ2 ro 0'9[ I@, s, Ƚ2 ro 0'9[ I@, s, Ƚ2 ro 0'9[ I@, s, Ƚ2 ro 0'9[ I@, s, Ƚ2 ro 0'9[ I@, s, Ƚ2 ro 0'9[ I@, s, Ƚ2 ro 0'9[ I@, s, Ƚ2 ro 0'9[ I@, s, Ƚ2 ro 0'9[ I@, s, Ƚ2 ro 0'9[ I@, s, Ƚ2 ro 0'9[ I@, s, Ƚ2 ro 0'9[ I@, s, Ƚ2 ro 0'9[ I@, s, Ƚ2 ro 0'9[ I@, s, Ƚ2 ro 0'9[ I@, s, Ƚ2 ro 0'9[ I@, s, Ƚ2 ro 0'9[ I@, s, Ƚ2 ro 0'9[ I@, s, Ƚ2 ro 0'9[ I@, s, Ƚ2 ro 0'9[ I@, s, Ƚ2 ro 0'9[ I@, s, Ƚ2 ro 0'9[ I@, s, Ƚ2 ro 0'9[ I@, s, Ƚ2 ro 0'9[ I@, s, Ƚ2 ro 0'9[ I@, s, Ƚ2 ro 0'9[ I@, s, Ƚ2 ro 0'9[ I@, s, Ƚ2 ro 0'9[ I@, s, Ƚ2 ro 0'9[ I@, s, Ƚ2 ro 0'9[ I@, s, Ƚ2 ro 0'9[ I@, s, Ƚ2 ro 0'9[ I@, s, Ƚ2 ro 0'9[ I@, s, Ƚ2 ro 0'9[ I@, s, Ƚ2 ro 0'9[ I@, s, Ƚ2 ro 0'9[ I@, s, Ƚ2 ro 0'9[ I@, s, Ƚ2 ro 0'9[ I@, s, Ƚ2 ro 0'9[ I@, s, Ƚ2 ro 0'9[ I@, s, Ƚ2 ro 0'9[ I@, s, Ƚ2 ro 0'9[ I@, s, Ƚ2 ro 0'9[ I@, s, Ƚ2 ro 0'9[ I@, s, Ƚ2 ro 0'9[ I@, s, Ƚ2 ro 0'9[ I@, s, Ƚ2 ro 0'9[ I@, s, Ƚ2 ro 0'9[ I@, s, Ƚ2 ro 0'9[ I@, s, Ƚ2 ro 0'9[ I@, s, Ƚ2 ro 0'9[ I@, s, Ƚ2 ro 0'9[ I@, s, Ƚ2 ro 0'9[ I@, s, Ƚ2 ro 0'9[ I@, s, Ƚ2 ro 0'9[ I@, s, Ƚ2 ro 0'9[ I@, s, Ƚ2 ro 0'9[ I@, s, Ƚ2 ro 0'9[ I@, s, Ƚ2 ro 0'9[ I@, s, Ƚ2 ro 0'9[ I@, s, Ƚ2 ro 0'9[ I@, s, Ƚ2 ro 0'9[ I@, s, Ƚ2 ro 0'9[ I@, s, Ƚ2eBݽG0Or d@^ @l +0>1 dy2'9l @d @6  @6W` |2c  + dOr d@^ @l +0>1 dy2'9l @d @6  @6W` |2c  + dOr d@^ @l +0>1 dy2'9l @d @6  @6W` |2c  + dOr d@^ @l +0>1 dy2'9l @d @6  @6W` |2c  + dOr d@^ @l +0>1 dy2'9l @d @6  @6W` |2c  + dOr d@^ @l +0>1 dy2'9l @d @6  @6W` |2c  + dOr d@^ @l +0>1 dy2'9l @d @6  @6W` |2c  + dOr d@^ @l +0>1 dy2'9l @d @6  @6W` |2c  + dOr d@^ @l +0>1 dy2'9l @d @6  @6W` |2c  + dOr d@^ @l +0>1 dy2'9l @d @6  @6W` |2c  + dOr d@^ @l +0>1 dy2'9l @d @6  @6W` |2c  + dOr d@^ @l +0>1 dy2'9l @d @6  @6W` |2c  + dOr d@^ @l +0>1 dy2'9l @d @6  @6W` |2c  + dOr d@^ @l +0>1 dy2'9l @d @6  @6W` |2c  + dOr d@^ @l +0>1 dy2'9l @d @6  @6W` |2c  + dOr d@^ @l +0>1 dy2'9l @d @6  @6W` |2c  + dOr d@^ @l +0>1 dy2'9l @d @6  @6W` |2c  + dOr d@^ @l +0>1 dy2'9l @d @6  @6W` |2c  + dOr d@^ @l +0>1 dy2'9l @d @6  @6W` |2c  + dOr d@^ @l +0>1 dy2'9l @d @6  @6W` |2c  + dOr d@^ @l +0>1 dy2'9l @d @6  @6W` |2c  + dOr d@^ @l +0>1 dy2'9l @d @6  @6W` |2c  + dOr d@^ @l +0>1 dy2'9l @d @6  @6W` |2c  + dOr d@^ @l +0>1 dy2'9l @d @6  @6W` |2c  + dOr d@^ @l +0>1 dy2'9l @d @6  @6W` |2c  + dOr d@^ @l +0>1 dy2'9l @d @6  @6W` |2c  + dOr d@^ @l +0>1 dy2'9l @d @6  @6W` |2c  + dOr d@^ @l +0>1 dy2'9l @d @6  @6W` |2c  + dOr d@^ @l +0>1 dy2'9l @d @6  @6W` |2c  + dOr d@^ @l +0>1 dy2'9l @d @6  @6W` |2c  + dOr d@^ @l +0>1 dy2'9l @d @6  @6W` |2c  + dOr d@^ @l +0>1 dy2'9l @d @6  @6W` |2c  + dOr d@^ @l +0>1 dy2'9l @d @6  @6W` |2c  + dOr d@^ @l +0>1 dy2'9l @d @6  @6W` |2c  + dOr d@^ @l +0>1 dy2'9l @d @6  @6W` |2c  + dOr d@^ @l +0>1 dy2'9l @d @6  @6W` |2c  + dOr d@^ @l +0>1 dy2'9l @d @6  @6W` |2c  + dOr d@^ @l +0>1 dy2'9l @d @6  @6W` |2c  + dOr d@^ @l +0>1 dy2'9l @d @6  @6W` |2c  + dOr d@^ @l +0>1 dy2'9l @d @6  @6W` |2c  + dOr d@^ @l +0>1 dy2'9l @d @6  @6W` |2c  + dOr d@^ @l +0>1 dy2'9l @d @6  @6W` |2c  + dOr d@^ @l +0>1 dy2'9l @d @6  @6W` |2c  + dOr d@^ @l +0>1 dy2'9l @d @6  @6W` |2c  + dOr d@^ @l +0>1 dy2'9l @d @6  @6W` |2c  + dOr d@^ @l +0>1 dy2'9l @d @6  @6W` |2c  + dOr d@^ @l +0>1 dy2'9l @d @6  @6W` |2c  + dOr d@^ @l +0>1 dy2'9l @d @6  @6W` |2c  + dOr d@^ @l +0>1 dy2'9l @d @6  @6W` |2c  + dOr d@^ @l +0>1 dy2'9l @d @6  @6W` |2c  + dOr d@^ @l +0>1 dy2'9l @d @6  @6W` |2c  + dOr d@^ @l +0>1 dy2'9l @d @6  @6W` |2c  + dOr d@^ @l +0>1 dy2'9l @d @6  @6W` |2c  + dOr d@^ @l +0>1 dy2'9l @d @6  @6W` |2c  + dOr d@^ @l +0>1 dy2'9l @d @6  @6W` |2c  + dOr d@^ @l +0>1 dy2'9l @d @6  @6W` |2c  + dOr d@^ @l +0>1 dy2'9l @d @6  @6W` |2c  + dOr d@^ @l +0>1 dy2'9l @d @6  @6W` |2c  + dOr d@^ @l +0>1 dy2'9l @d @6  @6W` |2c  + dOr d@^ @l +0>1 dy2'9l @d @6  @6W` |2c  + dOr d@^ @l +0>1 dy2'9l @d @6  @6W` |2c  + dOr d@^ @l +0>1 dy2'9l @d @6  @6W` |2c  + dOr d@^ @l +0>1 dy2'9l @d @6  @6W` |2c  + dOr d@^ @l +0>1 dy2'9l @d @6  @6W` |2c  + dOr d@^ @l +0>1 dy2'9l @d @6  @6W` |2c  + dOr d@^ @l +0>1 dy2'9l @d @6  @6W` |2c  + dOr d@^ @l +0>1 dy2'9l @d @6  @6W` |2c  + dOr d@^ @l +0>1 dy2'9l @d @6  @6W` |2c  + dOr d@^ @l +0>1 dy2'9l @d @6  @6W` |2c  + dOr d@^ @l +0>1 dy2'9l @d @6  @6W` |2c  + dOr d@^ @l +0>1 dy2'9l @d @6  @6W` |2c  + dOr d@^ @l +0>1 dy2'9l @d @6  @6W` |2c  + dOr d@^ @l +0>1 dy2'9l @d @6  @6W` |2c  + dOr d@^ @l +0>1 dy2'9l @d @6  @6W` |2c  + dOr d@^ @l +0>1 dy2'9l @d @6  @6W` |2c  + dOr d@^ @l +0>1 dy2'9l @d @6  @6W` |2c  + dOr d@^ @l +0>1 dy2'9l @d @6  @6W` |2c  + dOr d@^ @l +0>1 dy2'9l @d @6  @6W` |2c  + dOr d@^ @l +0>1 dy2'9l @d @6  @6W` |2c  + dOr d@^ @l +0>1 dy2'9l @d @6  @6W` |2c  + dOr d@^ @l +0>1 dy2'9l @d @6  @6W` |2c  + dOr d@^ @l +0>1 dy2'9l @d @6  @6W` |2c  + dOr d@^ @l +0>1 dy2'9l @d @6  @6W` |2c  + dOr d@^ @l +0>1 dy2'9l @d @6  @6W` |2c  + dOr d@^ @l +0>1 dy2'9l @d @6  @6W` |2c  + dOr d@^ @l +0>1 dy2P-7dYFBud!H?=:xy䋙""@ec;5 ! r6 $ , ـ P, g2@Mr 5 ! r6 $ , ـ P, g2@Mr 5 ! r6 $ , ـ P, g2@Mr 5 ! r6 $ , ـ P, g2@Mr 5 ! r6 $ , ـ P, g2@Mr 5 ! r6 $ , ـ P, g2@Mr 5 ! r6 $ , ـ P, g2@Mr 5 ! r6 $ , ـ P, g2@Mr 5 ! r6 $ , ـ P, g2@Mr 5 ! r6 $ , ـ P, g2@Mr 5 ! r6 $ , ـ P, g2@Mr 5 ! r6 $ , ـ P, g2@Mr 5 ! r6 $ , ـ P, g2@Mr 5 ! r6 $ , ـ P, g2@Mr 5 ! r6 $ , ـ P, g2@Mr 5 ! r6 $ , ـ P, g2@Mr 5 ! r6 $ , ـ P, g2@Mr 5 ! r6 $ , ـ P, g2@Mr 5 ! r6 $ , ـ P, g2@Mr 5 ! r6 $ , ـ P, g2@Mr 5 ! r6 $ , ـ P, g2@Mr 5 ! r6 $ , ـ P, g2@Mr 5 ! r6 $ , ـ P, g2@Mr 5 ! r6 $ , ـ P, g2@Mr 5 ! r6 $ , ـ P, g2@Mr 5 ! r6 $ , ـ P, g2@Mr 5 ! r6 $ , ـ P, g2@Mr 5 ! r6 $ , ـ P, g2@Mr 5 ! r6 $ , ـ P, g2@Mr 5 ! r6 $ , ـ P, g2@Mr 5 ! r6 $ , ـ P, g2@Mr 5 ! r6 $ , ـ P, g2@Mr 5 ! r6 $ , ـ P, g2@Mr 5 ! r6 $ , ـ P, g2@Mr 5 ! r6 $ , ـ P, g2@Mr 5 ! r6 $ , ـ P, g2@Mr 5 ! r6 $ , ـ P, g2@Mr 5 ! r6 $ , ـ P, g2@Mr 5 ! r6 $ , ـ P, g2@Mr 5 ! r6 $ , ـ P, g2@Mr 5 ! r6 $ , ـ P, g2@Mr 5 ! r6 $ , ـ P, g2@Mr 5 ! r6 $ , ـ P, g2@Mr 5 ! r6 $ , ـ P, g2@Mr 5 ! r6 $ , ـ P, g2@Mr 5 ! r6 $ , ـ P, g2@Mr 5 ! r6 $ , ـ P, g2@Mr 5 ! r6 $ , ـ P, g2@Mr 5 ! r6 $ , ـ P, g2@Mr 5 ! r6 $ , ـ P, g2@Mr 5 ! r6 $ , ـ P, g2@Mr 5 ! r6 $ , ـ P, g2@Mr 5 ! r6 $ , ـ P, g2@Mr 5 ! r6 $ , ـ P, g2@Mr 5 ! r6 $ , ـ P, g2@Mr 5 ! r6 $ , ـ P, g2@Mr 5 ! r6 $ , ـ P, g2@Mr 5 ! r6 $ , ـ P, g2@Mr 5 ! r6 $ , ـ P, g2@Mr 5 ! r6 $ , ـ P, g2@Mr 5 ! r6 $ , ـ P, g2@Mr 5 ! r6 $ , ـ P, g2@Mr 5 ! r6 $ , ـ P, g2@Mr 5 ! r6 $ , ـ P, g2@Mr 5 ! r6 $ , ـ P, g2@Mr 5 ! r6 $ , ـ P, g2@Mr 5 ! r6 $ , ـ P, g2@Mr 5 ! r6 $ , ـ P, g2@Mr 5 ! r6 $ , ـ P, g2@Mr 5 ! r6 $ , ـ P, g2@Mr 5 ! r6 $ , ـ P, g2@Mr 5 ! r6 $ , ـ P, g2@Mr 5 ! r6 $ , ـ P, g2@Mr 5 ! r6 $ , ـ P, g2@Mr 5 ! r6 $ , ـ P, g2@Mr 5 ! r6 $ , ـ P, g2@Mr 5 ! r6 $ , ـ P, g2@Mr 5 ! r6 $ , ـ P, g2@Mr 5 ! r6 $ , ـ P, g2@Mr 5 ! r6 $ , ـ P, g2@Mr 5 ! r6 $ , ـ P, g2@Mr 5 ! r6 $ , ـ P, g2@Mr 5 ! r6 $ , ـ P, g2@Mr 5 ! r6 $ , ـ P, g2@Mr 5 ! r6 $ , ـ P, g2@Mr 5 ! r6 $ , ـ P, g2@Mr 5 ! r6 $ , ـ P, g2@Mr 5 ! r6 $ , ـ P, g2@Mr 5 ! r6 $ , ـ P, g2@Mr 5 ! r6 $ , ـ P, g2@Mr 5 ! r6 $ , ـ P, g2@Mr 5 ! r6 $ , ـ P, g2@Mr 5 ! r6 $ , ـ P, g2@Mr 5 ! r6 $ , ـ P, g2@Mr 5 ! r6 $ , ـ P, g2@Mr 5 ! r6 $ , ـ P, g2@Mr 5 ! r6 $ , ـ P, g2@Mr 5 ! r6 $ , ـ P, g2@Mr 5 ! r6 $ , ـ P, g2@Mr 5 ! r6 $ , ـ P, g2@Mr 5 ! r6 $ , ـ P, g2@Mr 5 ! r6 $ , ـ P, g2@Mr 5 ! r6 $ , ـ P, g2@Mr 5 ! r6 $ , ـ P, g2@Mr 5 ! r6 $ , ـ P, g2@Mr 5 ! r6 $ , ـ P, g2@Mr 5 ! r6 $ , ـ P, g2@Mr 5 ! r6 $ , ـ P, g2@Mr 5 ! r6 $ , ـ P, g2@Mr 5 ! r6 $ , ـ P, g2@Mr 5 ! r6 $ , ـ P, g2@Mr 5 ! r6 $ , ـ P, g2@Mr 5 ! r6 $ , ـ P, g2@Mr 5 ! r6 $ , ـ P, g2@Mr 5? 2{32}_2 ތ @[ydy}xc |/ϸ-_ym  c,yw4 D>텀, #0ܿ<#xjrV@, Pܿd9d, ! T% odY@*+ rU [Y@C@J@>N@, ٛ8>= OԐCd kyф +r=?dM@`yʧ|C@`|( n S;Od ȷKi@^hs=# /B, _-򡤼& 0N@dy ȋ2yyn§#<=6!d, 7 +zҀ<׶mkoo|OxΌ~. p7%-ɝ|' Ov2@54s- O! 7dj0 \|J@nKgӓK6xIk2R@~xj, ?W@^x?Q@' bܿ䑀/ƛ7 zꀼx/ /n/ ȋ, Հy~qOpճ顀< {^@ Y@RB?o@>]zo|5N <_9 }@t>y1 #<Ňy O@ǿ|v@>+ 1FxpW v]Iv g!( O#ܮɝw2@59 ih@n2@=rX@.n|ŀ^}( p 𵾘GS{!?f@^=) _3\oẀ<5N@>=Z6ȧ'W "{yzo}|y@nk\|I@i? _Rn$ O ymX@Ndjw8}& ' 3 O{gnܾȧ+M 2Jz&x *oνO rqdynˢ}7rV\d> ȋKrB@2x}qπ\dSrc6\yh[d޶B@~lO1}[w$/:8|ӱ؜9: rxry@i@B`@ӯZ@ޛ2yltymO% /޶xz>%䷷E@b|Ӏ2ynWy݇=y)W 2@)7 +gN[_DE@р|^y^@s@b+ x0 /{ŸP@\qhf P}ZСZId"GW cՓ ׯ_U/o%Ǜ. ^ Cеrbx$ \8jyj7 +Ko3 țZ9W@|]1 x1|y@~q=_v"y S>; n-r١,>Y:y +~@_% Mt85oȧkk, noc1tWO 2JJm~x"E@^oww܀=?OۀӀuŝ<5z ȿ~†6ȝ7nrՎ +#_{$>h@^߹b{yy2 mI sn]6??Yx{%y~޾+vnyo ㋐dg4[ #{yo99V%yZ)1oybі{y@>K>_|х O1y3 z~zx4 x}1EVܫR~xt +O ibg\uJh[q|,۷orې {X9fu@sպK7o7G"w.6gXi< Y1ϟ?Oy +: OS@l|^@~y6O7rvOț~ƛ˒|6}Fc{+ޞۋu@~{{[x/Ƌ?AO@>Oآ't J㽀|b_y {3g +ȭ r Ιz&<]/Tc, O) OT@ ȯ[i, +ț~@n7X/mMWg>ȇ}šiG_ޯS[͹xz9 O<' ynȷ u@䣷b|B+ r|{i0r|,RE@yꥃ+ O ys:1?Yvx^h:5os-=Eޚ+{=5dws<eloWV,q| mny~t}I@n- y׋yd3 xou@^R佽,o/|0 |_We"7N@U7i`۷oߦ"  |@o׋G9jU,n7|X6[^~d>4 NYH>{el {v0 V7b)4 o.? #'}ɀ<5.s@ǧs6O7rx~2G"{Yg™kd ]\gmۍQzt^{۷ ;yMxgN@>tȋ qec1 |o~:FS[8v=np^y?鶿r' #u9oy"Vxxׯ+V|URk;jpwXi@nKrmE[;y= ȋsOONA" 9]<~t.6p=p|?_&vI/<^hN\Goz2E]l[U{V,Jr? wXߦӅ{Ff:d/OCK'ozkOڇS~{޴t;7yv|( Myy0 6[v< s,9~<9b0/~C>k6mۍWo>X<: Njyn#.s@MY=Gon‹,=+bC[[?_X>G끽1FݳtJԡUƋݝc%r4Vyz8]Oko}f@~>1 n<il$ [[iIgRg? 2V&0uy@|~tW8ܮ:n g9 9zb㽅DZs|NjܾLN?ydvMJGJђ_ckCq{3K=+E@9Aoȋ*6W ȧI۳/n@^_-ENR~X|sM-Ut^O: Oqnrޮ/yԐۀ2 ,i`mc@~mыV9 ;Kt1RmUl~D]yݳ,+r;JEۊ'y_96'Y)'Myzr? ۀ<iq{;n֦Ǜ87L|,:?2#ߤn[1Y^v^{?7=q9 m@ˏyX@ 9zӹX99GoțYOؼb̜"dgt3Ҡ϶9pt#W7ql[ zoh|9z \v:v^q3PRMN f2\a#'K'-鶿: >+ 9zbG8Go|[ڿREv'wrb^' /9z|r( ыܞ~^.^4N/G{4"drs4L]+.ͱx~>%/ z)6@i@r; ,rvm.Mx~xvw6m >? \GKg8{67@t=r$?,) ϽT@N["6 S({%y0oFp+3Wl> ‘'o~n7hNˏ'}ɀܞ7Nxsm لvb<!<ݿb< qqumn zmI zm@7@ 9z~W[ 0.' 2j:?M,0^؏վ? M yo9 ?lwԐs "by$އt1X jΨF#=W/W^l[ ,9 6@ sW( wm;^"޼.d=|!k)ƃՍldnyzU],mO_7y^-ݰAk^b7@VWvŝ!B,/?Ŕ&9håaF}rS(_8 ȯֿbO_*ibzqI&{W],RWI^8jV,B&V1}Ouc7VpȢ$'U8} ʏ_\ /wMm[Xyq.%c\*B.}Y//B`ˏ?*jxy.^_-)BA],6!b +M X}M)g!M٨ )[HǥavV݄zK:dgT y +_17@^^ǟ,-v3Yry.Z.).xe20b<3|+~Y~LltrpiAtT\zPŭ],:>tȎ//B4ؒc{>c&tg^EԿb2F +b6],.)jqVEV)B6uC(%vTBz]Wlb+jdŝ4@~m"#ANr*g?F?i [e#w(BY}puٮةª8omi_ ŏ?RIoT6M],µ n^S~T*[!YM?߹0Z:侶`4@,]Jy.q.YrU5+W3jq,}K_T/4: 3'}E^RGBUOKǝDzW =XD<.%VbUY_A_qpW*wXp}ʏ /?. !O".WԿ" +}Wݓ@XDcORqR6TvE~6r}/)9K)?ޮmEk +Y~L,r_!wwnޭEbr6~K2B6*?qc̸t\ +`z7ՙ=XL+dž7V#OohcR^9lTCwk]Vrc$C +r @nb1 .cy+88+B.c,}HU"8d=ZYa_ 'RK /bǧNRerzJ/hJs<"V7 <0l7UOI%pd%tQ .Y1CκXL#R?<{W4;ϬQ\&(]ulO)}^tJliHIjqEf'Kŏ?Lrj+d\gjvrzx,g$_<;ݭjc*ia9.?N -mԿb9_1Wb!{Xd;z7T#uQr]2u8ܢțt-ʏԪc$G %g5j@XEȲǿcS 9JZUǫT#f o㡰}ׯ_=獵YXm"[Z`ܬȢJD7&bvc7cuˏejcyp/JOv[}r³^H}#SէOPՑK;2<" %8#EAid'ZqwBn>~w}go7 {{yltEF Vz+^n~1` a}Uo +X~s?bhJt,B>"dg5q~ ?H&X=k2mY.1<7|RUע8h8+E ӘI ]ѿ**], W8KO;7MG8dxe+K)?og.ld[M#"(T#7=x, W=vǥǫ<*8Ug,?&YO +}жϋ;l獋Ue 9޴9צXzEȶ:6Fݔ.ȹs>Xk.E#=pdGZQW/Qpvgq|[zJ-?N{VĒax-?Ǔ۷ojlb+=Ţ9 +=C QleAXہCHQ +iIX:\2Z~<&c)on:l+*Eȩ4^yz]Srzccz`p(k-q4Qk|Q~< H^~8 +yo)JEVzcҶb"d%釫Sr4s8dؓU WHJڪ%ˣVJd&X*?2٬/JO!B yz9Fكx-;j !42Z"&kZATQ&-+?N]qktX.?6Wt#ޠEVzcR[g.B viC_D]ni\Cr8ͰYcl,?%aT OvGm;(Bo7 q"x8L,[7<.q9`3VcI)SRB,IyUʏ'/?nV#_ "䬋ŷoJEQExC(3f]g1޳H۷oj +Oq}yb?›o+!],6-B.yVɒ8/#GqgT: wQUT;4QՊ>b}q&=*һ"䡼^p-ΥqpW:,taRuo/QUȃUrAq`wޣӿb )|EVz!S'c!Oq7ؘ@gm ~U +[qê/),3WR2iig$gVyI S~Z!nzaK8^~pd)kJ3pZrlF9PJtxPSqho^Qo$!v[8P~,磷E0yȩ1V%"1:"yU3?*yɺ "XtUe1Vˉu kj*'{yX` +pVΒ/,*yC-rCF#챧0ռRv<>YEϊF'ScLߤU 7!W;!gKTl:Zq*r 9~r`;N3 +95Ʋ9Jظڼ8~jd1czbD`in>3&Züx2ƥ㱼wǻ"p(B8㓹^G6Yd)i:Sa{M/& gKRd!w0_$<-;bE[r=x_|drj/?F {XOsr\E[Wjd~N2Y}!]ZL2ݳY*ؖzMGujqh;/-?N)?+X79\qV,Y'nzY,a lCnbgLYtqvaRv8;/3Ʋy,?W{Y9mdT<\w ZѼlpųHT8Ղ:_uOlteH!x3+F6FeraRSݼbl;/\ˏS#T~_TldCnz,*%29A"l9Kfȥs?/ pvռ:nآ8hoKx,W/O[C)YÊqyih6(X/Ari7X<9䐔%8I[ŵY ͐Տ:,t9MCw3|W *K^ޣOgv{l?M3筏Ui%a]gcҐrf3F(TZy G2,* rc݊fԜϘѴǣ{_ҸT+&%{Q~|?[R<^rk<2vs6fj# KUy(drhwȥSGC6ꍷ(EW=t-98z+wUd=c=])f ikk˳AbQ~|kz28Bɟ?08qU2ZDz9,;/-?ΚWP~?+;e# Y:a(YD#=YS,*l|Єrd=ws`G)%6&X,Mo`2{\=N{^bH"`yEܼ";/Ǟco]~}3l!5f#xm|aUdre%qXvDTY"3oV&XqItcC =+ƏZq`¡ּ"uo^aK{Lg|rkn,ԞF%|TKlUrqO;/&YwuMw;rV4Ti65X^~NV5ɩ.5ne4Kˏ=Xֻ4{t7H[g,k"^ YuaKúr:#JYl;"WIF&W\/Qa`B&{l`cX<[jڼbG.5}+FG |fſ"Qkd1 Pvnz"Q6F.$gؖa[8mrALKXVdzaϭZ%:`{4dKKCŠ>Y3yl^Ai7> +dũ Y}u!oX(8c.[)#n5o)ka] Z uz.^ĥ~{,I{ +Ak}<+}y +US|7a,d3䬑E'͐)ӹegl%KV8(_*l!x8C)x}vp*y,g?njC"aI64cҼ"{<4;MY(B4F4+hZhU,S-qUD79ɳYa6C,\5op38 f:Tz6raEl}+D;6h^AQ}yFfq|SA?}r6稏=p?:W.\8n[sĂ-4<GC<}1ci.8Ӽ"-6{i +Y~=~C v즷J# ydLq(kCPp됝Ȟՙ:wζ#O3L+g^h:YJơ,=v6)?~S^G#!"+<>zq1Z!fgQs%]1%,q)-{ItXhÃddz:]V$TR&.HVl7&SEN*+;Y/٘S\_)riDSbuIKTZx,LC6-)z8=cW<ߎnd1&e3Cvz07Cas=9RuȞccE9E|kTl?WcŠxaY-E:tJ^IFW^X}\u~{<ȡ$K{>T35xC Y/ZidqGfȥ ?`搳Sիr*+ZttOIk֬kWr p'-uQ \RxlR7Vq˫ {6(Z{Z+R7mda;R3d8k/Lks.rUC.yc[ɤ4,ctEd\b x=c-G&Lllc{@WjS{y?۲F!;!Oǫꥢ8->yy1t7Xrڹ"$̲8lKZ؞O =UA9&a,4-d|n:JMEnq${lL4^>z8"XUZӼXߥZ͐37 WK^qv !{,Y^UkiMr6ɒʞO +!Ku\NR*W..ǥǙ=NUpf'ZqX4oF5C86C;M8uiq<'pȪOeu1ܫkdcAwܳ_xږ,mȸxYq,]a㸡^xjHћ\q<]cW<t4hm\uaXsȧk_qCGCMQM8$TSXZu=@DWa6 +VUR0ɥ%clc,qzj֭i^q ٹ^ֹ" W#GC}|\JcJ9̿SgN ;FZ%5J .W\bNk)g.i}K-qG]ncGs㼾;7xC oL!gE}͐zCV7!e\zǩ# %InGe 3<%r+r]T-g/R1}\5x\=Zgi8 +d,lq0QǏ;P(!.M>cA̴M?f>^^zU٦'H Y3VgDojK>Yu}?8y,_8bi'9cy4xeVz!O7irș^!ZZUi$OiJJ1-/),y6h xսܪy +endstream endobj 322 0 obj <>stream +9zi;czIKV1guu*^U/=}VHpe{olf!g͐m~UVW!/PorzCN;:VgHhm9> nd+ܭ5RWձ- >.l[ǤV9%{<)xo߻h^ +lg4͐=T!OGRCNk%qX6SO1]%ܩ:g/,;:۷Od!9c}^<z3[Zq +(=X(EʵKNj,Hh,Ei {=64x|[ y47 s~fg<*M>YLc,0>q:j_֤aO =w6:;'OdžINOdya|l5|mw?Ȼ?f+:xdC?Vr(x84.&.)zDηD7WM2Y>KK,Hxhp +I.]8_Ozj{Lg7ԋ9P/sq!{j_KM*94/qŭ9uZcGӜ7+n]Kٷ pd|POXciUE:=x_i'Q=ѼE_m Cr&\tQtm^wȃ(Ksөf\\\م`G䳤LsLF z$&$tq(w6NO8\qCg=N y=oa_O#Lw; 8tD5olS4rib/RX4EIS5%vi`pue/qΎi9X[YQ*<$K{MCA,g?ׯ_Ǵ>~6W^!O{AN!!9ǹ FT +v)ب,JݒK0),HouU>3PتO#=긪PW>.&9DmӾMxȓjCC7mCnwـC,Vd04FǛ^ Jyq yTǪ[Vo8 Tl,~{<=>v7]ѿ*y琇rTU|Ҥ :$?.R|j)E.Y]|j&B\N_`WgQٱL^JW}G߮yc:86Zx|f1r +2d㏥MxRRchequC萳F!OtǡIkGe3gS)4:ˑMSHcZMlz.Zj)zIř1.bY<+"8-N^OٰQ B{ 9+BoC8sȲxI +IQ t`JKl}v{Dq>UuB47T/], E)i,ݭǯFomC읮xLg-2 ig6S=Po]1`rș.6rH:'W,E|Գ#l293lV.~IUS%X=2`׎?.'mE9HOOq~Ӽ&6z=C>]g[L?V s&ՙ\<= +ct;gX") Pϖʞ.}Ƒѡ=?N^å-䑗od79LNd,ǹ&qFWaeKI Kk>"\JHw\k* 4>/UXn=cDꐿ& +!W["K}V|7I>pvmi|6TrTU[$=L8rRD}qgKގvKK8xc:vc|16:8(<+={ %{c8wW8I:rk9xPJ6"C5̑+ +e;{.YjY"XTF}u^R>`yzD>XSv,<LNG3{(vF:䎖ȲXZO]ȣ*O'a>0׳:LRVKRϖ(drIjө8=" !r|#sVe8zvgl=2zV^^D=].Ud?j70]_xܲZl1K{W13۽IJE5C!ꥥșCԝ#d>jOB#Jw79 O-s[[Ұ1իgߚF=5kƝ׭+_[>(\quȡ\x|[[c@.cW*;8I#C uȡc! +Cyg鈧X?'O5i',t14sI377lYq7-s\)呡BCN&A+EV1m+Bb'Iya Srȱ!O9uꄧ9E鐳b9RTgV$,*4K#gTPlܳSK2/6zk m勩ӸxvP)qtq58ݲ,<DLW –yOOϕI-ǩ@B{ϼ䐫u8 +jqrH`KG<էHOŘ 1ՑU AZxt^k*t߅q5B^wT.3vMm+[==~C ?5su_ŶzFKdg; ^{NK)kd`&`Ճx*OB,J79i Mw8t1vh"g7TSAG䋌)_xl񷭈M-plY!Fi[%R,w֓HbFWqUg91Ɵ6)JʯźϹ\>tҀ w37̎d0WǧEť#zx(4=.x*nTc6}e)rtȓFVry2(E?ʍF|$N^: t+ϵ':p.>\zƝū/I4Q_8ow|=+ նƖyY-=N { w¦索C9uȥvym+J,l\2ü8Oxթ]#^iduq<JW10_Ɠڨѷެd_V`=T*=1DSu*Qf bTǥ-Z2{,1aӷ[!!W["GlDζvaA)rN=PU)1Ց% pbo)ںൟslTv:zPtƞ'_qf'uѶ{ OonNCDYB/I+&\h1V\mztVxמL!_uac[;^: ;޶\AӑVuz{Vʅǣmq{!l6[!mYȝV,E-FVi gqX(#t[?ٝW=Brlob|M㫷Ug`jk:ޢ}IۊҖy#l q|:KTj,b)rW#uѡ yl1YuzIsmy5*}J^h<1Uoe|%;:ZqձmEh2er%KYKUcyPaU#K,.,LJF\:2# ԛdOm\,Wrܤ7/-=8Uu,X=8 +m+pl{!g-hgY/Rb|2 |操K.iE>Pu"x/QG<㫫cgϊVx\/Զ72䐣FP69j;ȆFNoL&tJ4@ s;JȌ,IKw00nG1Xwٱ.VGbOUQr\*V㵐أs9N|&YzҀ$2!7qb屛ZSZrV}m[7IzUzldVlza4C8o8Աxw`oc؀޽ ["O΢y,kdS#yiqGAP3gӫ"ٌ3}ruĈ>SgI;|Helr{p6ߓCGq+E::^xcO=f*b0K'kis :Z*Գ"T _?";5rC6ҸuXW/YqT>S}- ghhJDja^̯3WM>9_eƭVkgEL MqpqxSoԭ" +U)Rux˞ocxp5"[h`$MX(Kɭ>9U|Rfa~E[H_ک;+J,[z*_K< ZUH;=;ulw=؟>boktX}-.g=zU*a7vz㡱[ZQzVa8&Z<Z[8MOdC&kKc[E5F3g8&*M{I+pÙ"4^|l_AvƥVVr|:F40qZg&]&Y^%2Y^)QVnvdY>$T@ҽ}pKVŪHRro媎=xXUfc1ՙȶFLcWAZh/KNe'ڠ~OO? c^qݥU]<8{AKIxThq8SǓY=сhup|Q#w$K^jU';O[%mwP媽--:[wrtn1ҸW`αCF^Rq$ +7L +}Ul(잃V ُMCҹ5+e|VA/#4j-T9}ݒ=+P`+j$s~&*'OJ9м2= }%,nJU~/ gHfpn5YqY]j=sߥj'IE7V*9~Pu=h'j&W-K)Nl+fKn0ܭVuj/UWlaKx0T|Mk㫪71@/Gv/C#}-V4dC&{e>Vʡױ|d VZunI(vӒ_c4b㭽ݭ¯?ğ쩑;L/J&\&RZe-٣(hU _ ~XW>}ƸTl\/_DaO'~,MrS8 dLR.NRVld6^:4+=]c\Zb\SV2ƭƿp{㎒cAG/죑&ِK|OB)VYUQK3.cbcM.KXbB-;rWoc-9}aF7Ƀ[&U}g=VY6UΨ@^ۼ,\:W +dRg)ƨc(q; +m5I6[ drV\ɡe<-Ks+ Vn\.r!o⯢̸[fVR?jfMaOYd q)e7''WKV$ ̆vNl!Bu}ںȭKmW 6cChzJQrFS_ۛf eI,KXe-7yU3-i=ec=Xc)+1>XUwPw@$}e'WKJYV)V٣<ճLܩeƃ4W{ZU \rPʶUvf9¦V7Vbzc1sIuMZ2mt`Yem_JWW*ޣWz71q$w>a7r۱d_\˅i)Ѣ ٥ICO(e)exu%5WpѢ{ElD%^g6䯽2MV8*+rYĹFn(1_^gf~LdRn%BSʺU]wkV#^g&*|G)Bg{qcYW@-j⡽=-bEN-7wY{sK +Ej=[bnߢۿ_n3i7YjZe'7)%b`DؚWʭKuȄgGK)x$VW}rU0okr*˒Ew?48ZDr2rwV[.qttt2oI8Zo 'MXⓗXM2pݴc9: .IA/"9:C 9Zx&/4;pQ+Gxx2XG ,I'?wKvh4@opgC- G'dx&~7?GxH!8m +=Ýr8zb"Ss$re8z‡8M=~l5gcY}r@VG +`m[Bܾ6D,n!7[L}m{tT6٣?;q!{ ohbŔ= pG8Y%e~< !Ul5}p, +fQʂ%_ \٥ (S7$pcƸyZKְ=:ʒ8M36 X+QxF B7M[v5 [8sq1{K$c?[✦ #kJR7FnLyv#a¶Ճ&7i)gcf){ [U/eccxMw1ncN?M$GG}`.i/iA{6lcl$_eߩk*Y&\ۢEfaѺv m*Z6 IP߼ y̽&n5nEJ<հearFs<߼l[^BvIH&GFd;[5m3O#ak[dvI}I[ +vr6)e/+kƄMU?Fa>1nkVS&q/ngi+z_ٲi\Ҷ zMb6.e/!{ؘi$tEǢ0,Ns7fn=mm׶-a¶;i嗴Š-hEޖl1atIK '3%܍$-poq%no۳J׶s-Y[)hŗMűlm%dlL$]e* +cOf2܍$-p/qeq{I7|^a[Gt.iA˂m?L9u-Cׄ,Xw_S=Bd'Cĝ_q{Y&i4l,lAkՠ #h/8l1{^ƔBׄMU$鿪<|&8k&;5o4nvJi{#QutL6V ڹ9-h9[cS^21_gz{ku)I5s/{Is^vS4Oۿz#*[d$B=ik˜)y̞ײSN!Dl4Xߘ.1&lfs̽Dn YF|MU%/߾-"oKKR/m= ¶/i%m)ho U˜b3e!3vkޢU{H>tE5ucwZߊ;7\ ޅd_kK?,ieǥD'9{^&19dc^I^ߘ?GG㘫ҩm÷ཤn씓MM6ɉGV6G) K粤-r6f1;%dcN{[2'Qf"c^R7F9q/;ۏ;\&imi{jئQŅ:*/vj_fX]^S-h_ўq\О>5gߞ-e?C1b:%on,cND9q?7ۏt|N?_~VHMaLoY] +l~a|Yې:fllX4'5ŵ7Nڊ Jq}p͹=z#rrjmumb;Mݤ(=ǴjҦmoA:떳ngVvse]dUbC_SZː)pE*YieSzsucrcpSo֝VնYl{Ȫ,6Ձm5YJ[y8uCvκYY7ifCf7)!!*W{v L˩1Pܰ͹=a#nRJjmsm>rmFE֏G6pTl#:Ԣ6Svt;{vn9f}fZUGVVעoN.mvWVT87TW+\'ܞ|rXܪK2O>~yrnݤyYb뷑=b9-lDvj8jZvDg+~ʃmh[Ξ~a1*"⪚;O.snoȮon(nnX߆ܞ~zXK6?c pԚvJ+Q +]ZU{n*CƝ㪳'rͺ̆4'65Ƶ%WVY?WVf87T7&W+d[|ڞX6#KlT]dV6un6DVyM{nvA:떳gV~1+"+ }e2NJةfUs{Cu}sCq]pSom&mm6G]估si8jZ옎W_:6C~9yJBwΞ;)))EP]q5޿]:)!\)n nϭ;nm>rmgl,r^l"Qե;?;Du桊%m;v:6wZ6FVZ5sϪJqe׷9u'Rfim]l4rFOZ tTw8j-٥timZ_ڰy,wi6\ P/xeh@gr bfb6TEVZדk{+s+++܍m^۪}2a>*"녭ܱ Ukӭ~v'vd$jƁ=siCjI!mx mgA;떳]V uYjV87G77vcu{E~qj饭?Qpdwݱ騸\߰Qv'F-mx1Ӧy(w6/iܱ;{tM2+"+M}e?w]Kg+ָUnݤTY۴ul|E.(DNZ]]vT(Kei1m<C%;>#ڼ}}κmckHfe1+" ZT5Xo(|v_YP]X\•6%dwn{nmGN/=mE.q:J6{QO߳[;\5)myRKZ?w,{e(Zs\,hUgrjV2+" ZFS~kVE87D7&Wzs2յUKnl0",rZ؆ǣMNkڝ8U=U]dE [ D}b֮Ei@T| *MܥMKZ +{e6ł[ƵD766hoiuPg+ ++mʭ[VK&} #.rJ [l"ItD^Nn/Zz =ڸGł֟φn,ge8f6,eUd}bS_uVw ;IoqoOnnm{#[wr{e8K[hWOxG]p/ltTD4Gvh!})=QrL+Vcw6.i;>ē X^wˬ1ȦƆ65'`5 ŕ +V:YJm +?ulO=dF]dE [xD, 4Zr9熩c о'嬬f}f]ee%#[`k#++\[ɭn77j~_"oKF,ltD7le8*'ukÝ;[[!djgNvOULQ4y,yWjspa(Y}ٍlllhl +lV3lWpnln(76/ncmݹ6ԶAJ"<%i9rkZŅڲ{J/āpL&ee/Kڸw|;O0Іcc7vٜPٰUUuW`=ָ*~q+u;y#/mUl/7^pن?2q9L"[?/ZG1U=]_mK{1mxo?XҺcHHhcn,gufce}dCbs`?/NVSzr[Rb9" [ymyTxb+GMt`ANkorv4j% ԪHDi%gbtǴMuyIy: Zq7:뗳*uds`Vد7⢻):[۰u網ulu;.Z[s?VHcȋ׮Xis蠶>.OۖV0zQo< q(;{W*CnXulXv? `6յҶ H(EYdY(rr߰Q|#lW17~^f$j-mrǴ:<\=yJ-iO8uSMh糪UfUds`??nevSrSp綪>7ҶFGa9-l(|9 9 Q#HkѨB|iRWO=vQ(wL7eJ8T;=MhlTYX^Ul_YUMۍ~6,mغ?j9GQ86݁a놣 #YtZ뾩ukcȫ<}\vcik,탛JF@{Yg%;66lrllll.l/3nNnnmm][Oma下~:S$ rhMk[_ckcqm!mԦ4|<=(@;ǿrVKOik~8ҶZ5vV6̆Ȫ6q~aEuSrSosnm-ֱ G~/l(_ݰ(7.km1Y涏c}~%niuZ?zܳ~sTrm)Cc;` ybQ;6UaҺ~ؽ[!DcZyjGiкq:[gl +XEauӫ涮,m>r[9d<*-l&;u7l5 D mkw~rkGG:kWd y|PیDG\i"_]eXKn d%m;C+;aA[u6gVU65n~vu.[66VmF[}"q9/l(LG]p~D~i(Dv4ۦzq FF:ǵ[ȫRq9U]>0gmi咏۴rL7eJ-i@h݂VtgUfCesdŽ`kp&EnUmeJj8"녭LGMdw`n؆AdӴmƐhn!wfǝ8oDҾHJ+|Һ(wL{Z҆c;.Bfe‚VwV6}fZjl[MX#-zs+ɪ~i݈jcl,r9 w`+Qr#YwZ׆1z4jVo!/i2jZ5|,D=|d Dc7]6<ͻya^6| GAdgoXx6*!׮bǃ񍨪Ii Q~ cyz8Cm*m_` LmmS۴U z9/l&{p_DZލzkZL׮vAm>j7J()rD.Hocb86˂Vu6mו-;o:Ioܢ>qqkaYme9",r\غ;a-ʁa놣`;p;,^kFڽǸqm!of>UǏJ.(wL+VqKNiq:֡~gUfUd{}m a ?mvo[>Ei咏 D]t 28T| mXζUu7w3joܢUnsm Z( +ݰuQOZG7ZƧ,1䝲K{t,|VޭǴqmc-i0T8㸠;TN,QWW7綪mX>r8 Rz9.lF,V^p߰=Zֿ,ߊB^v tPF<}>oǴqmKZ~?h}hqʝ ٪ub_:n۴kf>rl=ja6$r8pIk)(u'FZ2R;9>|Wq|$KK>2iCUK4 U6/hΆllر-ry? ۏe:*M"r GK?}omx6*!FuoT[KjSq:u#Qq8^(J{.\w+k6mcw4 Ǫq9[U[؁oFxޖ۰CRml 6"DžD[7^~׺,i{_18Bޅ]h&>{>Fmx%>D=,yRZnǴz8߬dJ6.hζmpWVmmSۍRQ7m,n8JEd#g1x\n?[YΚ>nj#E%CkcZ<ǝ%LC~MV栊V$حDn[]۰Ul|Tub7$n|_ck4Nm!ONFΚlZZ?#Q[ieCKpHKZYЖ͋*3OnܼkԶlVm"[#lZc2>^kWdY;}]3QqSG5ҺK> +9.Z!C[/h;-+;Te9.3ܶMmmglD\x'FW7~r; ? DU6D-ZRiqJXo{>#rP'FTi[> +UZ1myǡޱlSY +#-r;T[td+~V#VJTpL[n%m;m:_`-,nnumMza7ӁmDvvj 9m!hT][)Ez&*n{>rsPgV DcZ}Jw<ڪʒU▹ME xblpԌֶcq][iȓQ~vɲvEm>MWT|tPG5WuKi@6K4]h~g*`umMn}d? wxT2%~cWTW~hTq\n7~C>wUk-/Wj;QjPKv]ڛRimr8-i㰢-uf5v(`f^q*~Y-l&raZ{nsk0\Zwgr yϮX^w{>Fm +Bm@6Ӫc9-l/mm^JlF6"۸luZ}6!Ѩvmurf־Ëځx>|A + +%L,mya[qx$mfmhnۉ{jYz93KSa ُFǵOBYkQzYȢEj&Jo{>֏D㺴|\iu8zlSjI+)@f)6mj[ŶX(r[iyw8Gqm}'m!ɨ=em}gW.k7x6}\n(?UijJTVƒ;nBdd]l2UmFr[}dOlekVئ~iUi ُFWZBVQwXvEmyѧ><||i8Ҫc +mٱ.K7'Ҷmwlj9!÷/ǐQvh yp2𳋗>pѧRl(?U\ӪqIK!PhX1ۢ>rE^G7V_Qըt\n!7kՅ9Z>[ZWjv8WHTQk+ץͣjXvA윟upoږK۴M ۿy9 "7u!kskhz5Jk[-dr.j3QŧcuVGBi&Vވ*K[~]-h% [[ہm9lw|k:JǵՍ>ם\֚vESD+q}oA*\+_16Ly mZSj;[ F|+ʏJǵro ٽ,kdj,k-gyqz8Ԇ(]j^|b6nKXЎfvٿnX!X#[Mmmz}SO6Fr,ӫ&XeMEmg:FƑ|?O[Ճ]wvٿhXQskWDnZŪt6Fr?& ?yϖO5Ӎc>GJ߭cڼy.if~{;6䶩`l6m"(pkQj4*ǐ-9r2eMEmgFJTya}ځ҆tL[-i˽90sj[" [u`;G?aZu'or^~\nj}LqQ[DɅڏ|x#*ǮyxlI[v~f^ljٷ6m"ZF|\hT]hBQ +,kS;ͯW D+jޘJ -rE[tLYs]JX{ [u`۶Vht߯QV׆?dTvפկWfa8AnJOzI[%0dm˥mMkpԗֺ,Oy\+kNF c1m3j&*}=6 ǧ+yiݽ㙝]V"u߯MOY1dwBo!Q -kwPԼE{B]y?N~&*}\n7j7J^?减}cyG D%xg+7^۩mDQOxQ_c_ލk-dy _em~yZ--jՓO煷qnԆ(//WԥVS%Hhf2moխ +?i4ʽki 9ܙ ?fY^B%}R;SZ>Z+/?q>|HMi$*\M_kKiǖe7\m5UzmIF?~ 9/Vڇ,kۗ;Qۙy7}q&/;#aXw~7 +ky"jCKmr`mKmGSQ!Ѩt\[IS-d=,k4cYKj?,j坨|cWcϧ<#Qr==iui@v ]_2[팅m[QOǵOBYwQrvW Fե?Z>B/j;QŕS_{BrPF5cځ%:_<,ͦj;UkZѨt\n-sz=\ߌGL/kwjqy'/jwj;Zw'|f@_ W|Ƒ(?|կWwd&_MocqQjHT>5^Mv?_!6۱{j4*׺۵rz 9^QiY߱;c<{(xq|zqqP+,J.(F,hT>7~.7SZwg>6; E5= +Y;Qi&] Wꕨb$}5Ͽ+m<ed`Z0jmxV^J7~Crm7Se힝e.Mm=y1}V?d<uZ3UnSAҪ%-5GM<[ȿɨ(y +y`Y^B߭_v4Q&7 EM/jc߉WjAmyͧ_Ԓv?S-l;Ƚ֪+?qm/7G>ֺ>lX`0fQн3O2E\ID++q:[. +k`@kw~1⸶B./ת7};XF-쇢>@Z=-j +yؿfn8nڍtg]66]hmyVm!)<ߌ +O!wk73>ƢތEV?}LT>X}\ZUfvr>Cq2*^'?FX ?._jn<;Zy_fsq57X.7 kg¶j{7J_ѣQ-8%~;f oRm5oLTx"m[>ceI ¶Fc=kca 9=dQNF ?Zڟ~ȃ>`Tj6 orX E+O$^qɥo߉xx8Dm5zkqm YB(E|G?c F /4R[ E 4ߩwjӓiQ߉RWjGAmQiJ1,&ryVw\BkQŲvY[6=c;=ҎjPTdڧO'jQ߉WjW=}P;vɅtkqm5춐tGޱP0,/!?wcY4M3>j6 ?n?ڛ>},jO' +u'Dɧ9 SZX CǵjV^B_OemO;U_W]CQM}Ƴ HXV3Qr}9]n`֎-d}6LF .k_嗵ȲnYۿ6qvS;c(P[>s<-j_ZzLT|bltk-dTxB-kK_W^Z`yKKQPTz%t+ÈʟO|:%,{\+7~gd[~rxY{^־ܲ *^Z[ ovV_QחjeEUo2ES(u}RZX%Z9mfIJ?P3>i0A[A>_ئM.VCQ +=ZW>y&j]v3 vƏ~zY[{Gem|ƢJWkZ;W}K(}ǽX.jWwjE蓶vFi`ߦZɨemBNE9^AAuW}&/VCQᦏ{c_}NmxwRj&jx{PKi`eLs\B֓Q6^\/k3rߧZ;~Xef(*o2rgN.jtP;njv +9/k߱he홧vI' ǝKP~swj'}EgoN}ꙨxŜZJ o^Ɨ/8ܳ`Z+ҏ3d.rէ?]rW򡨴 }vxiqm&;ղ?%߭}3`Tsv3;ț>_W}c(c?r7]渨}Ȣv`&jꠖhms\۟[iY>>~0*A3vFmbㇹo‡-j; EAcۛU E7qU;,j0/jL1hk? }+ឱ`ZgT;;}6Yڡӥj(*?_qw]S=Z`x?/vh ?5u߭]XQډ8UqTw|^5o77wV5sQKi`Lv`2*՜eZy1=cWk I?Ͻ_1/զO|Q~j[ȝemx2J[{nYbrfk}y**~??2K饨*nZ3QvY'Ɩ}0UU^A63#OEj8]/Ewj;LTjm YYXA^vԋQj؃QO}j{RkӥZ^S+wjve'em[?s>^֪۫vQU<5×ZR +7}wjlN2s 𣖵}0^Wk;;vlaG:WTKRmz8o2O-j>gz y|Y+߭+`\ A_AV},k7uTR; _d ߩϜZ 1w2{Z[^gZ?90RɁ΃Q}Xtէy*jq&|5U,j/CQ墖rZʓQ3`TBr^`ajW}y8?ʘ/CQOoQ۝bv-45U}Cf|}Io躏am'RU;yT[?%ϫ߯Rz(E-`} +/F嫵dyŢak7kK/kNQm|g헾߯hK|ҧ: 3Qvɨ6}3U\ w}yr?pvfNE;OE=[jqT{cRME-3t/k}AVQ;xxS>Ç;5w*jx*rW}<(|wӟ9<ʛ>N-sMn!뻵_e{1*]w+Gg?a6E͞qT9W}^v'OK珛əefLFŗ(rAX ;'dwpXVݬH{߬\Լ;9+ꧢsW}NwW}3GnmjY/Cfja9,_;WW^{mafsȣGkU=q?fL/Fo~",_;k}vksQSQjjUUqjolzY[drOsX[=\ +?PԲ:69վbA_һ}.}x>Yk'򖦢oնjQ|էS<>a~>sQsRۙ +XȷtnQmS|?olE-yک%`Ԍ}gYsQ[N@NEXoնjQϭrT۾_1Li`'ZAN_+[am~fzbp.*Gos#ȳo>5}V@.jW}U[>|>ZAv /}ϵO~Qge.w6=T,ȳjU/GXfwGT>3碶my䁩[[Vm8m?U[|?o +-^_k?Z= o־|=Em[QTTրVYߪjUyA=7kOmfmE1UGS#oEuҷjVԲ kk%ސk/:xt.|/jG71\|A/5c**< ϘE ~#[@/ UMEo wjU`MA}k3ڱ}'\T=䙩 2NNE,·jj ebyZ< s\T4c,]d=:HME»TTryTۿ1tݧAk9sQ{Q;zzyn̿@ם GW}?u0kkgG,s#i.yq]gHjGZA֪gA=%[py;n,~grz+;U;zcX7;Cz.Jދ&'E#仏 o& n z?˨ފNEoՖjGzA.kѹW#WϼԖw}^QO@ߊħ>RuE-08ռ5=< +rygRջ>C'd^x+(7ZXw߬pE}^;\lzgnj]I>7jފSQRoOղ ;_ c-۩ j`=MvsQ~^9|Aί Ox>[y;S;q|'/S z,83簶E^T1?Y{A֯ XM-_^jeקroMEvv?8C#ȝW>Csv7,r6}>]w'X?m碊dIr~yOڅS|B]]rg(me.A֯ }JmԶ_svUᮏL3\LEC1Q-ڐڿE#ȟ'+ȝ>>}.bMj O9Î8*9sgr9Q-mm8Co }FOaXTszkv齀\}vh*E-\dzY<9XS\榶axE Z ZmsŕWn5p#kOq^=5;/X jw}w}d*JI/ LE:FAm>݋pk[v,λSV9mދҟGmmykgaaw /X<5^Z@SQ&}:}&.>u mq8X>? ߼`q(tk]ފ`juh^>k_/־B_oXďÏ=u⹨Mv/X_V9w}85s.xG}ۧ{T6~v _fSy,j .xdMlO>ڷ_->+LjS;XTEZ5.'k]/ /تǑ>ZI5/֦7,sQ q 廌?//XZ`q cj522o^ oXE xǭ>5/2>xE|jߒR^h>׻V]X{o苵.~3y"|?(<ȥ6?Ry,*,2 jmZďN(rME'2H3⻌cQ/X \e* +ambNEq#Ȼ4]㻌w'-V`]},|'a SsQe^fN"_эv@.cjI-X;q^j/3?];mvk/ve|wHcQ``,ڿ}.=__fAo~o`#񽁩ԶO ڀ~ }jwoES;e:`^j7,Tj?OPx1=#{{lOO@ C@2E v `^aQ./36 yY}o>Ca 6O _Re~,`4ڡ7,ˌ_(_fN^fAJmmfR>sځ 'O yyƻ`oX{Q=|x^fO,?Hm.K-@|,`I/3R{wRSG?ө_8m?|2rmGA\A8'P|EoR[~v }v> |X.]ote$V/3Q|9k6֎ Ծ07Ԫ |.#w}`1bm|y{TA.?sKmin߱hjG =aUjG6@j`VO?39߆vIms7k? l e6bV W~'EW>Xe} \}e6bfj70iW`pjtj>ʧځo |m`fj53rv$F~֥Q}Mme/>WպOZX3v>{ϯ%ꃵ*V߆jjڱ/ÿƧCs @Ӽ}}WzooA+:ȩ~© t6|mK>9vcR;sF70Nj?ujm:+S{Om2R:Տ o2.}tjkSTjǻʗCj9Z/jGZ6v7+zჵŷᯗ֦ԞS)~\jMLA>W}gL2 Z>S>S+ m2_ G7RsS:ڋsjo _X4`L^4{>7^S~y*.?RXKjϩUI0"Kj5pIujR.+'S{tjp[ejI-oԞS{Nvfj_PLګ}KM>WKj`NoRɥw_R{f@j;9?8HjS{.tnj_'J7ҋtANQ9HS%J!wijI3ԞS{Uj?SjJ-u77R9_+tjOS&?R{AS{V/%m(Xj?KY9|ЁO/S՘ڿΩ_v3R Sխ:/KJ]R6n4 /vSvgJvS.œc>q2߿R{;.ۘڏPj>Cj`LR2MӮLԞ;/ZRԞ;/oR7`jM5׾:7nj0ڟXOSrj_SԞR{% ^Y>/˩}O>Kf*7'nlPjN3R{OUjSSgMyEj?>,gn&o˩3~~Hy̧njJ#]jN۫~b#S R S:H'Ծ}:{>J포BjS1;_"-KS{HjS{H=RjЇ=n}{,9{HKRjOHRmKjw HI)/=V>Ml1M!ԒZ)RԾKޢR!R l_j?RK.|M}tjS{tګI-oS{uڣĽS{SԾg#tjqԾN) ?![\j R{njsuR{vL;H-`AjS{{7Nzڏ/PZR kZڅRq'Rͤ{I-`'#K+-7ZZRKj[CjI-]4$EԾrMRRR XЮKKI-%Svܵ=89BH(PB Z" HB%t! RetEQܫ<}7|~ JjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjJjVjjǩ*:J-Qa*_9zR ORy@j+v/Z`^jwR пwRzZJjϝMzګ.K=Njؙʩ}N%Hګ S{UjMR Z}QS&S{SV} ]N ץER "ZZÔړ_jؒnړmHPJ-U-vUZZ8kjﱓG`?Hm(v}L[Cj_Rw{I[cj߿ejsk`>'R ~~RXj_H?H-QcS{/)>jڛ7 CHSPj'R{录+эozaj5NR KEj9E=EgSb`@jVjSǛA}DjijXjhJj&^K5ԑK6H}>qgϤaI3k_^n/rmjٙԞqj?+Bj?{nګ^q1WoR{]mڿ~()>)NG:JK}~H)oO*贃~??}w/gΥv?q.gR??Ej)G~igS͝u?>Fj47RAjS{b[^oz1R{bL}*oZ&vj_7ڇԞ0+^i6'>l2Z&8~H{ǩ}fQjW=]vڟ,Ej?֥[;IKԞԆEKmX }~y*ߒZĎR/}a"(S{FnjS{Õ\ڛS.g}DjSu8*mڿRCHDj/}$S{`Nj^jsRFڇBjҥ7rj_^}mj?IjYjMSwmj֥ӃԾ%ejJ#~ڟ$߳[wsGRqj2گ;8l6oxkԞ}MΫ*R{.W7ץsŐ[ͦ3Vjk~W>=]jդ~H_|k>8O_YJV`/1S{_}CJc}e?m?HZǚcHMj$p7]jKCSjr;6Mjy2)R'{^f2ܤ6eR7q?iRřcZXהoo}/~aLSNF}jL _|KEzV6<7aAj|j{&ΩgJ-ڟurjoR{&^ۧOvj20S[e9ޥS\gljJϭIԾ,گR;0RO[ }*nR{֋_'o7&أZH7qNMjRUjS&~Ծ]^j??k65w6}TjѥNw]NcjOdj_n>s~)6KLK_OtjJcjФn!Yj/q@Uj/1H] +!WW> 1{ _tKM}kH~*ϥਸ਼ajQjߚR{Kz _.W/S{Ր+\֤6R_ћMzWHcjV^ؤUjSǫ~v"ߔZɖ~v?}*7pW}*S{aj<HN1WԞS.&/SZѡя|^ФRړ7=N!7R{"?mjJ;0ַ;N7|UjS{:MSj+z-EͦVk[)Sy|{W}vLrjﱳHwRS{ޣHW}vN]j]6vZCۧy>Uj6s8S{Ujۧ}VImUjwSUjO;̳ o}viYzC}vgR='?!:~Mj7*7Hlj/ݥxE/V!woR'Ԯy~=k^eu/?7 S&w/R[7L1#w#i?MkRK6֦;{'_Zd]M{2|H&0oS1qYۦMjvgodNm _?!7L1WN Ԧ~6]~'1i~j]zg3,kS 7REj/K𛼢7@1  60s72! Wfyc>щ!_;;.di\ⵁ4@a7f=쩽 ~67ཁOMf\aRw پ6YxvO,7Л̸8.dG,\O.@N <~k=Wuj7zvickzoa!Ɍ;%jsaQs8xm`7v27pA~J<8;.j>0&X, =o<! }g2,=3Ɍ!/X]aQ\ύ@.707qj\ 勵 L_N`Ѥeelv2=dn\i[̰^ݵbǛԆk3âE=fn6{xo`j2E3,FkG}8vpyZ ݰ 2k[>35?qz\s¸ZG:;3sZk!ωâNUe~콁dƹqQ3,X?\T]/>j'&X<`1Um.C7.3,ʋoh/~.Y̢vrZm{j&X Ee<,On2vڷ .֦>_^cZw*jt9~]ڧk'jE\Lf՛abmjw}f|yak,EJ[ک\S>dkO 9ЛZmoEoXsIm2 tMbm Zv>Nw}^j4s`q ߻aQ&35X{Nj}gA%q{*j]tקx0k Sk/ֶ}|hxٹ(槢9: \]72 ɋ틵b>sQÏZ _ Sj{w}V,6Omb kRY8\~&j5TzakN:[\캋xgmGEEA8`ϊ@xgϚk?pw}bm8ċcG+ ONAfy.jcOO0U@w}ΝzgtW> _Z/vÏo4GmGSь\ڏTi>ΝN@n >:tgaKJjQj7g wSӹE5|8 +lvXTT͵ڝNXa1wv`̃<sQ}Zhqxݬx*j89@>{걁t-.ֆm>'#OG{Sь̋baY<;bݩț^n}ۧ~GEM72A1SSQ_@3}gwnڅgm)ŹL͋ZXkhTI,Ƨ/cg nwgO><|ԧ=ן,b1{ֲ`[?^U۞ skm#ьyQ!iYm;͚ojƧʣTwϚ> A8:|7/jcZ;ȦǛ}}ũLz@y**@Ȼyg>G)kEyQw&>֮cY m<<`ѽ71+jt*j0yxxg>ڙ#?>8\fw?Ewf?NA\8mvݩ S.ANkWFfX n_ p`dֶcA8H?^@j:T[z.yy1#ȱ?E]nb4ļ^7Ģ6߬- >;AZc?ҧ zkNE].*' A;5cmf9R ?ṋ̀p쬨SQ@>A=̋Xo lfڅUjn /mt*j rq.{Gb1X[A~{71qiyͲVkLRSnN|*jW oxy\T^T-sQk˛͛] Z;.j'i ~~A<5xw|.j^;k7ku)vqq'U [ jѬv!۝꽣7bX 7k} _Ze\ڙK>09ܪ>ն,j럊鹨ډa cmqw/ [0-j?<j z;8Qjw|.j<"}߬ cÛ>w6A^s0Jkǿ0yOEmwysQwk7k=)6kٌ;.^A^85Xj-1SڙEmPyxv{' @^TX\)^SQ۟꽣Xެ- 7k} w/Mؗ-jOn7*jp' @~d9y`1zAoNEmp.{確!k>vo֦>g> LZ}faQ;yQ۽7_QQQt'Uɧv*jGf?ֶ7;k߬-tv9KzkF͝ZƩvPT|?oTxf8] o]T{W>vc}\A. Ok-vԡqyUS,-zX{6Y^yRsݧ5A^қ:VkKPT~?ojf7NDžO7U[~~Ao秢8cmfm)uh`_NVdMǣ3Q-jj+O,v)6X[flv 2ܛ.k._\ƛ>MjEm?DۋNwCx&O?1vwOEm|.jclnvry955Zf_ԆIQKiq_Ѿ +_wW}nuv,S%vS>֖oֆ>mF;w'v`xY۝ >.EڅCQ!͡va8\}fvKzlw˃QS}wk-k`+q\NIOT> S,KzwƉQ'F-.km!3viQ͢6*7_̯?NW}ߪO;X;{gz9M(^{݅ëabT[2~x6j.^TVm[v6Y;q'3ANS,Kz`ԫQAݲ6NB l}ǃEmTp6ܽ3ӾU[%}wӾ3An zWknY1e+vaQvp(*\mKë>O_Or;gZF&F-,kNFi-g&q|`RT>ջT{ʣ;/lvnir~Io|=O,k?.kmNFi-3v홨6ddQEjO~X~x~Eoxxէ§] A/'~'vWkOmֶ}nmyGkmK;N/j>ݤޡ_{C?/ϯX?v]jw8ܼw;vQOc1Z?Ǔp YlovNTLTv-W>IQݡRovJj>֮A/w]FQ} [Z ')™ >r;6&^9O;5A.^[߮69PIg_ɨ-d[J}[~yq1?)w(;w[7yQ;_qHS,n~[J} BpYFFwkӅ ϵZ pLvrGOS_7xgPԭoySrb1Z{\svx0*i_,kQͻ兟[oSTOzgfQWP¡tx?ogǻ>Sg9SWkemO\NZVk>jߩӏi|ġK[_:;U _*Wf| ~p0j=+/k8mޭZh-ޱXݜLTxg}c^Ԟ5\ԎEj }AQvr;} 0mXɨv[gL¢կhWx|gx(*^|7x8=u\jט=5_~x~*[k۬<'>};_jӢvpgP5¡JW}斵AZFQ}vY{6[[j?NVlNvCm}ܞnmo*o>0CS;QqbTc1pX9ɨ̨v Ykvb.EyaRTq(jjvK]f4w0*>c,r12*ͱ~ɨp7bsF[?kK~-W+LTF2EiQ[7}բ2?rէڭv'>iܲ{ড়cќ_\{֥]>Wj㙨<|gfQWnr/K]xxG`b] +} aE1q.Lm!oZ8|Bqi>;Em11oǛ>CQKJίO O_jm`TX岶P[lO*4_o:s(j~~Ůviy^y0j01*X錓_kûQSCl쾉_mKɧ>MN͋f|m8)v4`T;1M\֞3,\.o!wk1ZԷ~xPt[u/jOݤCQK`Oc3Wr؊-nZZi-?ÜHN--j{+ʛ>CQ _-'F}rY!Iȧ̳_XqYۻ\[BWW>FͶVl BPHTPJW28}^p&^ҳwjq\?\oCQ3j/vj`bTsg~Y[zO{:Ow2j)Frk`Ln[HTqg}<8\9^IuԡK-vF}emw6<񌃓Q-sѨ֎65-7J[nD<3-f27MCQAZ>O}3iad` \;oOvVmvlwuzI[ܧ)C~n}<>u֋^xo=9~.jT[+kF}arx3_'.|SX֎ϵ˭-fYl"Vm7:Zv5MjaQÙx7=S/j{7}څɫSz>t6LB~fYͱ'&ϵ1QkU[m΄y+mq{6>gE퓚wjEmo|EsrQ;{v7?u>8 9[{ͅp2 }WjlhJ[<_~>s™x'd|)8x͢vϦjw?K}~ﳴ ֞< p2*̌ʗkA/v[Ƚ+?sIl`ѥ.<|/>v++͜LT^>Q'wj7XԎnl~(Rn0jtߧhdT}ģӅɨ7Yk[۾=u]Z?Jv7jyo}bQ;uvxgRou0jpߧc1ZI'eIOQ̨f y6 C.,b+#~8׆v#QއqR̉jDő?),jOO?nK7}/ FL-k'}xdT33*^M[qE^8Mb+&?]<^Wx$*m΋+Jm3'<k}ȃN}5⢶P!v}f6[{½3'Q-O\hm3`faYm8m;qm3m{gHT3}ΉjD}Ѣv0bM]?A}zc,]-kr{ɨ43*\-x6j[Gmݼ ]q?aey8^sϝ>[.jϡNYX^cs,ɨvfTs6l!SMkT|FҸ(Z;D-4٩%3m8,헺ҶGojfDg㵋MÚڥ> Os2*B..-s{[vm>!kskvRl`SahgBm<|M+qw6 ?g;s57}jvQ1ݲiY{XeMڼYϵhT/L6_DDm`̇vy^*Gt^^ӕ4wK7"-jW\Ԏo<5,k׼V\֖~ړQp +9 8'o!wkѨfjT{hm;7*v_Nvr 0gG;3-\گw'ri50%*W󉳏Jmw&JEWk痵ݻaY[l!7~̨rm>g!߻]FcZ]_[’vx j弮iq:}\^ s|b[d;xEmK.xY;q2*_-A?Ѩ| vfZ[n"b/Ss?ߙ +B;<k吨qs$jt' l7WjGg]־Aj-W_'̨r3ȢoGzǐډunm`;Zv\8qMiK jǽO3^>s3Q;?snڍL.kIͅXڼܜBnf!ֶ[hT>׆Qy{v]؎wk[~geh=1qtE#QKÇt3֝>Jm~ܛ^qpg4xaQ[PljX^]ֶ~3[ x';P~]4=7kkIn8(vM:;Mq{ᕁO^1>.D}Ң +{dQ;Nv]c1<5Bnf!7鵟k=B.!+?yO-lb;_(0uv>咶L[00.m擎D5DZCmt^3x~W\r;XH-k4,kNF,t㧸]|m'4ZvmENݠ Plmo︷ 3̠#Qi cg{gE̥5SO{2jg!?sm7 Ӎim`;D^NVswv!qi?6>.G=vpw&*_.jH-jmYۛcѝn!A,G<ǵk0t4?)ZJ¶Ev ^_v m;/iyqHT}>>G=">N+љ#-S;ugfY;c;5B>a'?\o!6,z_r6l"-l7Ҷm?ә͝/hЎq8}ͥ#QFmPȓvR}<>OX鳫=emSm!Y'>!m?׆۵stk?RsoZ[|-(ӱ0 /tv:bI?6mtiÇTt6~}Cxb7}<:տsDkL.k~Q[>\o׶ģQzmzQkm3Sra[Amshp"egBK[,i|[>qFT,mz7/^-DҦC~5|osF}6]KɓQq [ȡW6 h,Fcȣ~m{-N"Sm۹.p-~#y^i?ݖCG@^,J[nt}?q&/j[ṈhNFu3z[ȃ?q@c[jme񇹵 ryy]m["O?3;v-OwGqiyHT}2 9QLhző[ng*kÀ4 9;FYL6]l"Džm:<ۼ\v2U]vM;Ǔ _i6\,m]>ΥMہŇܙn$[Z3'zkrZ{6 CCW~^ԶÏ~8\l"GlؖKXQn{]*?joOflZ~`8=Gisi/*K[^iCSibRDMd\ڍ ~k 9smMO37y`}-l{ye_NԶ;k.>6(#mo[Җiu}8#* +}場픨vqCm}W^9"헵l!鵭kQZۼYăÅm{ǶEmnNW~go]wwv&y8oǣapEjSڶylEܲ<}w6m!AszϵԨ;?Hm/~. ڎr8xF4^gC%mxw6Bi8"oWj/^Ԯ_.˵,OhTtg0y+>_Ml ¶EbXۜۢ]@+BK6mL^m^͋3Ҧk>EiGzjyyڸ}<p-j\ֶ{ksmRk3xTۿǶ_ۜ۶.DW}e߲o~qPِ^gm8T3gx jmiEi?Jm1/j[NJ[szsLk+?qEwuoxcxֆpT.(qyw'zůb;ǃbInQ/~gx6͈-FWGj{OuSgvͲvQa oo׎!omGS Qlmm{m{[w63 +m~+AewY҆۴@TN{>axExLXnόm!n۵SG&ZͲ pT`;*>٦K۲Env%wS?x?*evٰ͡ehKx8}G>m7b#QFqN]Nvr3Ȣnצa۴6涵mD..r-mmܲ38?Ȧ̖nA[h6lϴo/oS48ݨI+'/.vx2jf NJ-6߮G6jyoZj>؆M䏖mw؎{[w\_Ǖ`Aۅ;.KѴymD5}},y6nm}|&fiΝo!A卟smdZh |aEs9|M$roaw'bemCn{Ow߼0Bv! Ah{aIۜ<3m8z|_^iJ ++j=bxEJvڍr7 \F!Z{ZnCkåp8*m"7'˅mE.c"yi[v +endstream endobj 323 0 obj <>stream +~r';HoYׯQ_k^g Wƽ9y7とpgUڗҞ6*q{$j𡶽W^=‹o!7~}F[F["q9ݑC53Qs]3\)!Q+?30x8*|MtTgQMK۲yqr{; KFv/am*2Eg"V6MHqL.7/iKM#Q{>k/TO\k-Osm8F+?_jm`m"Qmw>*6vM%wGƦʶMAg'2#pIۜ*6Q:/sK[cLS|g̋>K&[Uڶz1xgX6_i>vmE1ii;mm"8?|7햳EgmS;.q6^Y s-SBiӇ=sj;m!|GcO^;O"awlQmgZLԶmq䎪+7V^e;U{myK[.iqL.4#[>SMjyq:5vnȞZ5[ϵhrFY[l8"l"_g"wGDl}Ulsm'r{wX5_?p_I۶̖mwG햴8y&Dϴ:m|5o\4?|D ?n}|Rdsmq4*C^jmޯlfEDnNGm<">dmަvTw&7?Vdgq: ՞jfI{;q[?}|g唨HTC#] 0p4;/F Ʒ6n"]m/lPnm?1mr՝N/~6+~hllS^fζ;q`EF~hWw%m>ylϴO| ~p/G}&[?SG6jm|+>_9giI6"bGjm)mr՝L/6~ׇ-3[t67+-%m>yV3%]<ًkZ;<\!S+?iŨqFK?ma۞DN p=ZvȟαMKۮmm.n^u _w-2Άm nIۄ6 p6~͗|>.Nc6]iDG{vxrf8 yt yaOiZ\In]6G񨼋\6#Rm۴ Mdw뢱!Mej6.gٮy mo9%my?6K>MiOyt{Tډчڹ9Q1[n!Fua;6mmxdhm'"7Mvaܱv˕msG.j[,nmnYܶN`{mlX˦Mb9[v6,hP^h;[s88_ }dxaJDݰ(m9%j{`Q1䢵7jmx䦵O`n6']AlGۼmksmXܮ.5`AEWٜٮ6ߣ6ۚŒ¶E6\aivۦ;N/?~ǰlSaf'>pgv8/i؊p8nQ>m8*m{67%j{dQ;y2ji \;FuW~[!7oŷ,0"l" W_ܱmG]Al}䢶6vܔ.]v  ~ݺ;Ox)%Ui٨iJHTC鼽]hѨp'mkOX6_Ir&rgqqaWm?6l$wk.]oCpCqSrSsһTm~_.Mdv-ֳq8/hǡm>ҦW".iPa@Tww/QS\?G]B<YkoZ{;/vMt:jMG_z^En"[ElmQxJmܔݢezG-c_×~obl[2TnA BhsǯxYs*ٞ{aAlҶHεM۔~pcrcssu`?vS)ʖt6,hGm >q;.alE<Οi0-uKLi07~FZ{uM۰N"QmcZ>,r6ŶK^mÙ"moSp`xl $illlpl\ЎW!gٜ;>8Tst*<3m:zW*쑨{>G8~:U\jmz7(^M۴Y t<*E=/6zc^3Rq']ܦ+.)mw]GT\ы?)y%llp} 0Tm em6m +n.njnn^| ?&~Ŋ߸\ض1]esfrl8mNCv8ޥ_iyy~G|.Պ^~#Q{Clj*Qek;|M7lM0΢]؆]fai"=b#9$3]nަ6 ͍m[ gS埽6m#Ul<:6= o=;ǡvIV{| *=芩k>~srk/;k^:?۴6\>ئqyMǣYp>*6ݳ}yikOImmTܐݔ^{ G?f\H.lٶ9q9Cg6Оs8pI77gpgUڟε9Qn\=6sĕAk/W깵׻A>Un"-n"Qaaܱ]-l.Dlm[۷چm.1e{[؏?f} ͍m#*e6,gٶqhqsGKflEXlQ7^.^n\څk>{}v yt yOxSi^ lM䉅m8"cئ䢶a+mM ܦ9mz;؏?f\Ջ?)MccdZ6U6f̾^t6m=qhxjjI[lϴ:uJ{c[>˥]<SDk˹Q|'JlȽmsǶE>şp`i[6l%ͽmgS.q%ll/o{[]h +|{.mNϴqsgQ6͈(Ү\;8\\km|{*?ٴ`[JlM{ޫ\؆Q}|sal}Mnܮ!MssvSw>ƺ缦6m#*6̮bOahO+C6xXaLj^~*&K[\8|MZ;q4jWɫ^-]͇ntlSl" m|mcO;=k<%Ҷm<-9y})nݔޢcػ~_{{ccȦl[mgmm=-osa8ܥmqs썺Q:ծK۽O;]ڥ{[l!oRhmf +7lM¶En>>6ͱm]m_skM ɫ6 Mm/V/ş6 KUdb^𚮳t'9 Ǘ{%myncoY}ܨڟ8&ȇ ۛ"Df9EmĶHε۰l&Mm۵O;ޕ#V6l]㸜͝m7ShІs'=A.mM'oq6m{ *8'|i7Bެ6jG$r G.rdSRl6rlmWWUyqVܦޮ$innnn=QO\ͻ()lUdZl\Φﳱm qxM{q'@T7"{Uiq6D· ۸OG("?0 = 66oWMmۖo]Wr_CaƆ*}㶳wgFifVL6mw ۥs]B> t9 ۻ3>ن)vKX۰a/96vX.]tswszwugQ?tw/Kll*)|r6!}*Gxw/qlEynDNiZ򳦵hma6ۅqiaGO!aeN##k;mmnMr𾭨Od/\ŋ?o-"+;츳q\6iq=XҦ6mvPKmR|x|hNۼYt ;9jv'2Olc.mڦ䰗r67InX6ewMpl.M7˜\ٔ}i6:[І>6.]nIVt3m:z/%KӟkGǐ7ozIwɻ(Omv͹ X.19m{7[#~ސ%666D6V6fcfWLg4#m;˝K|8m \nҮ9|GSѨtmDnN"7ַǣO/aE?T۰zVMr6M}Cߞ7uS?^vm.6g^m=îgDL0n=bh1RRَFK|Nf0@( J:L'ֻ^O&s>Y*[7l}.̶A՝qh/);n*=ҖCUOח/֥ w.Bjڟ3/VYTOGwU~|qͣmUup[%7[Ln*Uu>K4gݔ,lآ}dllukgg;:< +m>勴ߩ;ҖCU L^?jofѽ`[`[>\~||ɶ|>j;H c;msmܢ}rխۦw߱pW7ښYW_V3$hlٶmfkag'$P勴ZH[=Uo\QW\%PدvR7mĶimtT-yTxTm?QmlhԶ|ݶ>ܶ +nS&es6/G X4f\=/v"; q|}恶-*|zP#m<_/PvE>Ei|U_-rg`ǣQwhᨹ`[~|~>j;H b;msms[v n]2es6w8`l?[Hl*}eK*qvxǟLC[> U=w\jt=;Ҏ=>^kK46G5KQml_tkmmPrx; +nQ&esV٭[?GY?7} +['nlٲa96}ل PՋq#Uw^wDomۺsGc[?lo"/Nb[>ږOI5tnQ&esm۶I5i혫^5Y]:Ecȶ.̶ƣΎC[~ÊihiCuGV *m\K{RAQ7n/c]l'Gۺmm&uq-[UnA7%_hk lتUdV*qz}Ɓ  C[}Oww\}{GڍG9Z[G_d=ǶR}lG-jmq(nܲ}uӮHQMf㦯Ub6-+?ԕNqzjIh˯uh/m=vKiq]#Qێe1imE?ߦqrvp>ny$7WUn䶷}p6-[Fnݶ?8f`usiZ,lآ]dVmfk恶 ~ mw}-H;<>5"{|kivQ7Mn~mu؎j[>%nv۪Mp-[Fn6}Gl~5|lآUdV6qzjih˯mC.ߗW/>mis-\l7*mu\x[vܢMrխ[? 4dm]V[7ly*[8[g6hv|w<:n<^Qi _/4-ֶ|J9Vj{(nܲetC`puS7u[Nl.meg9ag mvm+˴['>QȻؾ3h׶Jnso6[&ln:ux̵fc.lغMdVAfk㾳8lvבvxdXvpyt^;k[n[nVOJU/i[Ln2uv6K2aVkزEbV'6Pee-Mg{vv/nξ-_m;[]Ӈ;n<<Ԏ&_UiڝyE_h]$j[n܎z[.n*]u#ͳn5SkU:uc+e>N:[][C=w<U?x<<|v%ݻ[;n"ƶ:h]$7Iv*uq-dnƏ{ p`O\kG]=ubVV9Ͷ-t8ΆvxHK{n`;{=5&GھSն.V'nU*]zCؘaxkGM_vlzξ3@[=t< <5w2JJ{[kw`\"Oǣ/َb[==!mˋ亶SRUp-[FnGC?X4\3 A].uc2ggΖǣm,TqǡGx˴yέ$`;zv5]nGm[Onݪuw^lb8aWrm[7찲]f\gm-gBrxx}`k'Guc#7G"m8V$mnݶuyk?l ~5M`։vXqf6큶9C J[/n}:jx|lۯm^mm+emp6-[En> `&tM`–Fv\:Sf:N;;8ж߂yjKhǡv<u˴v?En_Eh;mTsmܺMrխۦoֶ5nͼ5- ['nlٮV9agmOwi4yvnDlG^b|O\m7jn܎{,nܲuu}eLrAתebƶUle=qv9 Eq#=/s+Zq`۽d;Eh[]$jnmz.nܶuu0@=`~k[Nl6MeG֏%m;uvyޣm/ĶGmls;mܾerխۖowh:̺)LwV-5쨲mfv73"mGՖvGkw]"[_ko7b[~նHv3Mo-[6nUݦmz߽1wvزebƶm*Ig㪳K7 mxz}yn-5mۋ侶܎{[/nܪUtK4fݔv3,lخudGgy}l +m{s~g?Hki[oG]l{h[]$ov6Uo-[6nUݦ]zGVzNزeb֑*;ٙVV _ڹcփV߮zѶն{ٶlnV&MqVͭ[U o;K5hݤk&7-4lu*;Ag@[D[}gv-ǭv`;zvmmsm.muMn*Mv6ޞ;ov| \;mb֑βUe2;luqhhOBHvx^펶~yPQn޶ܶerVѭۆon<ֺiz} lY2Mcۣl[Qf~y@[P#m<ܮl>N^hQ۹ܶ[Mn*Mv~mgc \]׷1Ma':meg2;сv&ڇiPڻvpxvnm2mܦUrVmەwߩ5qo6c-lئ]d6]fvvN^8*ydj;:V폷Eom[5n>1.VohF;jתmbvm+[fvv3/zU}/vh;[=[Knܺmw^~ ~CjʶN~wHțmvxܼj;mTums;mܲUrѭۅw߉KEe;oiتeb6Tv9agWh'7ǃC;;vy=lwŶ?׶=֗ޖ[%nnSݶN,,Lf5+mbƖݬl8;@{khG/:g"vtYu*yp nW*Mt;u +,[Y?XêUbƖUvpmgGo ݱ3;Ŷ=ڶɣڶ.ޖ[%nSݶN,͖ygbU*mcȎ*;l{u8h#N`Fl73n6mVŭ[7naz,\^3V[5lscTv8;Ɂv{h;cK<^k;>ܖ nUArv2@|$ '=ɖW8u;;= +cAz=3Ge_ֶVŭ[7n_ލ2~?[5vٲavtg}́vuU]ch[l=%5msm{*nܺmuw×ߎ)6v lf%j0eeff{-]uۻv&s;(uq;JXcm0QLƿ5줲}fG +[b;GٶFn[Nnݶ 9 <_71n+٦x:]}׶9r;mAqv;N3mhMf2{VVvx[BH{?[{Nj;Jns;mAqvw&N~#}c+fv|mІclw*;8{[gub;/k[vupUw޹`:MfJ"Y8vg:Uڭv<ygmG펷Uo Nlmiv@Gl{88ŶHިm۹m$wPax n6Ac]f7:]%v{lo8k0̎b;(#fǙ{֑^n9nvr$oMpTw3S)8P;'xC>lc5x@{*^!ӣmm_qo۶mr掲;THnk:McGie[8[gwh{[k%>N7w-nF63sٺUvpk|{g c[cykۿn;;8@; +>v[mvvܶN;`!v,Gd;4GfqvB܇q[l*y3Mo';S>I 7l;0;9=;{{h^-$ݩn~HGLfǝHLn'm;HݝY +pv8d6ʎ3 svVhch;_ܶwN$8xx &ȶz>cgmN{/ݰS`ns84줲mfYMdޥr;n_Qs7oiidfڧ4ۭfo&w; 78ndvgg >-;v3wit6`|;o33GSr4?ake73 +3v&}o''w[wg4@Bwi*;ٻuVhWl7h6;Mlu[`{mL츳BjGεvapŝ^1)~6}hglov[ms;(3]-Z}JPAnvZՕ_ WL19dVgj;%wd4sKeg6vWnvTw? w͍$V2+aovip4X]pstdڴVInǽ+-XI9Omj/B;ܘ3 ;Sjϖi9V7G܀=ңjwLngz 87Jg&d7h +0;9;gY=6v>ۂ{dmǬ2]Gm<:0 ܯ[{ ̞qD6uvqn-ۚCsj :yoQaޭq;r{KpU`c1{>U_`m8wN}ttJ>s{pKc̬.^Vs0s.G烻uު.sq e;WzUϘp{6:nn7:<~ǟ&+qב]%n5gcק>)_{P\{1=T'?{iyO vXO?EyG"@v;* ѣe<X2EAMN?F@f5?L} _o=믽_›o__Ȼ?ū_VCW|/W;9ʻ/r-79?e'/t ?^_;9zWϊp}vӓųӳӛ 믝_<9-~ec_9<~v;)~U8<{?_|rYou6~.fO:;UNُb|w_eOGL?3D+\a|/><?~/U%'gL9[''7'Ύ/Oo(~gnn/NNo8;yvuuuz~q~}srzTΞ_\\^]]<;,~'ί.χgWg7g7W|*q~~rggů?荛³s}svrqr~zVx8]_\?ze{rzu}\Ώz_9zK'.ϏߌxYv^vs/O +w_|ώ/OGgzWZ_~ɋ~kzջŧO>WϚ7٧b}/?_|WhO^~X^ ~>}?};~wt??y;~w!-J֧μ|ǟ!>+z?gow&o7~W_~o.}^~{mo?G͛]cŶ{с~{ӛ[v;w}?~s凟xO[ӭm>|vk߾|^u{ug5TSa=_xͷZ~6~g/^Ň?{~s+;++) Un,oIqT7'QӍaR[Uwŏ\I8{MwZFdf|O?O(ު8F=+߹Th>~)E6nuݜg⽸9yu]I,p͏և?+tJnw~>bgǧ7WW{\98}Vi{qD?ۼk|y|zs}|uutruuP_\[ey.^Uq|.~^]]<8_aϮyskpv~YBno_U)>7?78)>W'''Ştvrzuys\Ƶ z}_;y}sۄe9k}XF3tA[h ^-f+:ۊί.q+9A_N7/֛|ˉǭ> SyTF[6nM[aSu߲:UQ2an}j-P;. ZM\F7oVI]w#GL;o4?֋>~YPO'̋Ӌ[g/Vo}T}eu׾}[!9?}͋pE螤|΢xw|wߟo:>'/}X&oW~O?Ż{zoǛrTv>:+?WO9/xBΔ|{`~nM?3JE$, + Oѧ=W&>Oj}R>E}Dp&sEx DA)('8PчDe FYV!:TOv3xSUxn}n#zrȢ +N!H!z@W~ LLDaIHы<у +Z,Ug&zr= XO"z.z +ެF"G KD/w=5`^ Cѫ1W. T+$=n\  z% X [-a,U& p'4K,CEo=8D[*EOqEf +@m OԢ7PEOz^<V$zM<gmD/D̈wBpP}E[D/Yt:$ 8{#6@nRk O%0S +KD7 s-0 JrA@w:Ht,zE `8Zt$zw`c [,H8D; 1x)8{@u D L"@ z sѡH'z`sBDGiEo[NtDzE7EW]t Mb< +Fpћ̈#}DPUt$&z{[D`_{.{^`_Ew]N]w%x̋ޒ +0D#)@)z'GU`!xL]V-z]W` xс(z'Y`]wxrѱ"zD /zt /z ,z@n RtDo7,:@>8Ar2lѻ 23T[ Dኮ4< PKDX!2D,] npE)<WpEo(`Nz qD&x1EVN:pWDtxd%:@Mrv R&;#zB+}iE.VDoR+$W Xx|Z"<V-zSf8h@> +)2Sx Ј^ +&xU^ # pOK0#zA#z^;^nw`ME+zkn/D ^W`/+p}EA)w>[E E #D3`*z;$zFWAW  zK + zJh +)VEc,`wE/jыȢ X-x+T +<V*zDk E/:P E/.\+}E"\k| V!:@"KBtD_tW\tW\tWYt d+:@y @ي< zb +ѫ N1EJjS d%z`)@Y^m XtD6,:@VWb +ѫ N1DGPa# d(z02@^p Lt E/8&:@a C 0DGPa# d(z02@yq Ftpzgܫ޴Y7,p:] N@pzs\^4*:u +P'#HHTP) ^V/O^?J0~MzUNO% :C7:ICQ*NWoB ԫ`:sz4&0:zeqE:pzN^<7W%Y_ k`u2XRy:̫X[gb7 0Bp:\S:A_ !Y/5d .uRx0Nm<l`.uBT]0: ?*XLI՟NvSg|Q=:ԟ UJ|-xYm?K+W.MuR bdܨ.p6W?q PSRH`kfQX[MSZ`jueXC]`vSQ.՝&R?G`u^ +-U~s# 8H]^ NT7!^ՕT'/u7 nH|JKݙsYݜg+xMݢ?Տuo}u5\V~W;G?špoqܫn]#݋w`v46ƆK P;[3@nfl˫0\ 0̫nl,{˨*K +1znrLө$Jt+ 12vLyd/Gt;;C `ucܮbg[ 7/q"ȍp rZn\P{!Wo^erPwD>R_MwguSM{u_e_kԭԗݑ_ U7H~V~n jJ;67KNɳFS:YG}@].\[[JusR7y]]=R5#!0H]@P2ts0T]C7W/Mt[Q G +@RJR&n>Lzu7G}nEPwP!`.uO][}z̥ muU0.>4&U%ՇκWYSJ`vus]F}PkO 5u ).>"VRJ;pXL]dV멻`=uT},n3UՍvFN>Vڹԧ^;4X[k'R;,s`uE}nS}W;n>Qw^}znznznzzzzzn`gu7;[P\]| ;N=iWwqISOwzn#3u18E݀oW%v8K݃UO=^t8K݃UO=Fh8N]oTm.\8Q݆Rm.\8Q݆RmP8W݉WOs՝zD8W݉WOs՝zD8W݉WOs՝b88Z]/VJ,8]݌TJ,8]݌TJ,8]݌T2 @+KݏQOKݏQOKݏQOKݏ/P+Cݒ?Uz~PO%<-SnɟuKT=?x[Cݒ?Uz~PO%<-SnG_zx(<+<+<+<+<+<+<+<+<+.G_z~PO%<-SnɟuKT=?x[Cݒ?Uz~PO%<-SnɟuKT=?GKݏQOKݏQOKݏQOKݏQO`,8]݌TJ,8]݌TJ,8]݌TJ,8]݌TյzD8W݉WOs՝zD8W݉WOs՝zD8W݉WOs՝P8Q݆Rm.\8Q݆Rm.\8Q݆RU^t8K݃UO=^t8K݃UO=^t8K݃oWS xzn#3u18B]ǩ' ;N=iWwqISOwzn`gu7;[hYzSwSwSwP]vKMtKMtKMtKJ]s{ `u'&;AngQ;,s`uH}sOսv.iΥ> VgF;LXUhgT K`=uW}2OEvvή>VRGXC_P J`vus]I}V̮n+ +յu=0>1Uw%Շ궺QVWUө`.uO][}z̥˫Y u0n>Fzu7G}n$t7yP[nT G +@{OFGU,Mtg0ZD7W/t 0NAP2#90B>R5{Y^uyWwͣՇyR2Q6QKԷk?fC}T,K}x_)yVWwJQ_ +QIW QIS}5xM#vD[uWko7ݑԗ[# RF^V_WEQQEWM#PwD.P_"k{+m8] X}U7BW)sՍ[ +DuF8KW}R@nW_1S[p1N}W7?hV]h`Ou#S_==R}R|wMOO=? JU?{n o^7՟n G/xp#LN\Qtu'.V*p 8Q noNQg`թr`guFY@dvSg| VB:S"A끉Nto VUgy`RS<0)ZEJ,` urQW0:?-Wց%_̨ R't`m9'YD@NV/ Ju6TlШ8{ l`:}G:)Fs7p{Չ8N] zuVp:_(lN!|5_is4?HxM~P[uvթ Re'|NN^T?Qx1Թ2 +D p[\uEp:ܥ_8NUο?ZNQ'_Aՙ``gu_/{s.@Mpb7 >l ЫbQg[)ԟ1;S-D/y`: $ 0{`=uZI:,XC[P,+lfW'V6*)`a\| +#`u2DЫ3)VORFvS4 +kQPm< `s78u8B0B:RܫΛǩ?~R'M?c& pz p:]hlΕQ/>U'JRWgIQ/QHS"xMzK:?zQ[urWu iի97 guB#Ά|$< /u*2J8]XXU'AnQK,uv8E^8;`u`zz:Wn|@^DSLD:0z/NsL^Msz5:zYNm,^Y0:z̨h,^bs˫W,\&Ы[@bl^n:zV/vVo9E0N8BF3qp:gpz\NX^W7!e`_}p:UJT/bx_zxG?K5uzԫR/LՉ ~ޙ?^Rg%xY<W$xSB>R/R:u +Dpz\ޫ(׫+p:- N@pzgܮ^)+_w`z; 8Ш70:@ntzs L^D2:t N10zE ̫bw5:u ,zi +,^K80:5̥&zS H:Ыl^@N"z:%V\qG>0B8 Ug 8KANT.uC^/huT' @Mԙ4<:D߫3:A k oթ:2?:8R'eu|WgMux_#T&:NeXp:\ܢpz7w>0B8CPu{Tox SMXF`VPGAVor`.u6՛NO`U&UXOQVRm`u`5XF[`vSW%fTg`UuXXd`.fWEMԡz6RG({PpQo``[u l;0NuyƩ.p:RWiRXPu8ZJ^PDQc|ޥu2Oջ/u8[uDw?A ^SoNq ~ޙR&Y-^PG'zOPzCQz=Qލ<[u/>L8] .V+U@[! Fu,]8EcwPu`s_r:zd nwPm0:zLh`cwJ:z_,n,^V+Sz:0z5,r̥K˫7&X@E[z lx4:0Zy6W=Ʃw8HWgS@RoC1ջhuJV@DO|$!|:*zo:0[W] [7Agf#u \Ε[%% p.u8Kp:rz'?@BTd( +_WgRM9)`U +`ju\XIg:XI^Vΰ3fVYԿ2˫#-,} V&D#(nP&ɠ((*9`&rE dM(HT:8a޵NSuιyk~~+86N˰}hY:웥 Gҁ`,m\8N;giitKN0,mV8isS6,ei(Yڠ6K'e,-NKeV%@Kga6%8N6K`"KGi-Kgj:5:K[`~Np,-?]tbi샥s7K`,Yp˰t#di,y}p,05tNdiu:K 0X:;p,`],$c`\˳3>,8NNot}iN+KtY9Y(aei@ULdiy@&.`%Y[tIetyp,bjX7ҕo9웥dlX+afXK(ҿ^W_0XvX;KAt).c``y-#dB`,;u>X N Y +rR KM,[0 )'a +Nv% +K앥08NX+38lX/KWlp,s +p`,]YHXeXYݲItQ۲OYd&1),]M† +`W,]q?K ,]6Kat.ewW,Esdgl7/K0U8YTuOYZr3F8&6ڮX+2Kl_, KWVBӺX_V:Z-K,`"XsH,odi$KY3z;ˑ?#Z9.YZ(==KXf` yµ{s[؊}b %X0ٹ`34dw:XZw۰*K{@3;qv]Z_i픙[-oUu_^cjK@~˗62_Iy~dgO?? zvLT 9*G!2=kr mx4V,%8uқ\ٳVLْK({J ?('^8>g~^$ i{=̇;V-O c;kԓ8`REhGĘ3&q$؍Qy03jG]qj)X;?Ez܁wnٍ9%q$̭临I ff,r\ZCJr(#boz܃Ϸ {06đg>?n#ǽpB8`MCqJ2''ZE쑙8ɎE-=sI.p v܅?;qKHE٩'q2_49^(`ǑvFb-D9RsɥqwŮ\9N KqGqG"ޒ;r7b[?(9.n9ʓ3HGNj j\ڊ&xՒ$"d~l876vld$q$Ώ.ǥ82=dۏ-zlt*Xd([,$I ;va;pc>GlM*I qݸwf',9ݑM8N8ڎ#8Jc_0yl٢%IߞF?;6qg*Wg]:rDC?V8$1f ԙӗ W8`.vzt4-Hp2e9R5INs$~l5߈ӕɚ%GHr6G. "~c8QU;`_8e9VKH=?8B8 (+,J$"&ȩ~,&61 L`[_x͒Ar&؁cM8EsPeM.&L +~lcюU7n/v{ŒInH PgqvqNjpVuAI69' ѶcqG/$q$1خ;qFΨ!Qkr@"ڙYC~Eblqڅ2Q5Qښ :rSe؃ Ǫ6<⬋ɪ%ۃ8GHr?zƑN˲(mMNd#ȥVζG#>zXrcGKJl̚(mM,Kr#K9d[hٱf+,4It$1clcNJM98M4aEii2dYmUjHXAc9>fla7Yq f˂'ka2 H .9%=vXcg_:c|YeM(Y +s9E|֐ *~܎جFeSV5Y$q$ș+@NcA 9$ŢIQd!HilQKflWA0 h2d]I9r.')2~z,ѐcɌ|-Lqfє' LVDE r?61c.G[Rl4mi2dbI;J$9"aANcMs9flTEї)3M-#H 'dAVdU|Tz1scɌc|x rf'MJrkGH1lU?cE9j8 ^\gI'MZ4$dՑR{r3rb]1 vz44/>?ú4EzҴ!Kr#gK솩 ?ԣiDz+^,XsfLӔ'&(Kr[Gnȥvv=vbŲ.9vgڦ +=1aƺxiI,2ɪ$kAّ(Įdv|ђcƒC4LiknT9-FH8 ~Ls5h84eJۓ*L +KL#U;r"DR~Ls;j9V8l3A*SQlGc䖊\'`N\aHӏu=(䘪b/36iLD4i[2JrnGHy9 E=D-9fH"˶3B+SQ*Ol(GU(NYif?1cjGˍ+JWTN˕(&,%iIӑTiH81dr zQ1cE5JRwjL=i2Z $'9rDݪȥaA +ր4Cum11cFӋUJ͘)-O-$IÑH9" pܴFAVdд1ӣe\M/"܎334LK*I^DJɑYQ$$;d1@~cb\M/*P3ffJ˓IDG(NY #h1c.DS}.33$L($ɩOKtlRGKzL1QDf_ Liy2 /)%9ޑ( /S=&v嘨b"eaQQ1cY_ LL<)4äKArR\iH8E"(A&]`WcMS1x i ea&T45,iHRIѐ,9#G): +cM37b,) +uXLLDh2XR܉$u I#R;HҞIKLI&bm?Xcc"GT'x&Zd$ 9rt5(N]  Xӣctc*Fۉ5yf4D5i[Ґd Ti7*X,0TAd HÏ~L(ҎQҍm'Z4͙e!LzK$d,SGv XKLa'+=vrnLh:1UM[R1N0XRH2Xl9# H 'n@vя +~ŵcj(GFmFˉ߮:Ug&E +EI H5vKDpE$~t֣ҎQҍʌ]3*jgjU*Q<)-DI'IWn ܑm1]rPV]Uu£cpR!!v\c+SR2%KL6GH" ssAv=@c,uxvrnj48$kaH.3Q&4,mUm 9H=)7#Q$2 Va9ʏ*>*=1ScnŪ 57s[ +Qy`IC#Yp#J[5#wȥư?Ad=hQ1bņގ5sY +Q&,X&ɂ#bdHB$bې,hdُ2>zt11qaECə,OjMls. 1،,( Τ9$H9v }m]xv(Ԙj67\w2d2L +K$Yvd6(3IcOYa ?£c.Ge̊U^o4Uu涔ԞL5)d&,HjGvd#JIMH N!gYaGs=(r2cŢ Emf TiYRTZ"HڎLۑfԕdE"x!&dYmAH }]񣏏]xtv̒ctc.EIOvf*KiIܒBi4#+mь,(ri?M Nҏ>>&z(ݨĘYnSgI”B’TA2mHHl8:aJc lA&j~軏]|*kaG/FiTex*EoT ,[2FI/I_mwA+#F#clPI#A HY=a<.>zvQQ1bA7qSOOR2xRhR[2FI/$T$FB)r"fz=VR؆c|4vcEol$7R2xRh҅ؗԒAEGb4E" pl[c! 3?^.cM=*;J9&j^4(Qg"KeJIhkKjI lb;rD4kmB$jU1@d ?j=ZQQQ1j|lijYJUjO*KƊ; 6il pVc7 RͰe-dX~RL(ըĘX_d2r4eӤ $],:RYvMٍ6gNAzCFA~-HWa ڏg~,1ct4bɅN,3SO:M, %$]tŶkH*HWj*mYTdI „9Xcۂ[zDLxޏXcoG/ǠFiFEӇ߰])L=i[RH'I$]9ҍliUڻP$!"d -H= р4xޏM;J9F5J3&Z,z[GSvgbKJ-JI&%mI ֮PiEQg/+Pf8B֔fPaHU`~jǮ6(((ͨhV%n)9Ӛڕ”ړN!K(%mQl{G;#/bdf$DQ0ƮOi&]-H;@F?~~t.>*=((͘X[IaLJa JImIS.Hb;ujve3rXƴfr/@j\_8(0þd1@j?򺋏]Q1ގS3j-dӱe)L=)4),飤d.;Ru#C "ku6!"dք4y [T-~tuG37Ȩh6B e*W +SQ&Q2JI mÑF ь#m ]5vuJc RhB 2aw,1Ǯ(S0bA97-SStTQ2d,0QDT ȥL XcY\J + ]Qf=;J9j5 +1R1LJ*3OK(IUa-P;kF6(<((Ę:QX9w`TԉyR[RJBY9*-E^z"Ǵ"1$"yA +lˏ!>zc&ƨF)̈Z}wOږB*Q +M +K$۝#R#Yh"&B&KHW`~xc{tzwcTc"E;ܹ-i*YFSD<4),E I7VIЎtS6T$`tj”.dm%?ŞT]xecpcTbnDN%Ka J'{MzKjI~S/,HGR;5E^T) EZHQg,2g̛R_ +ү' .1Lѻ1Q1q]sVӆ3+)-OjKvQRI2Tۆ#];2nVdI#cԄt{>A&v$f|4R0bA=:-)('&%$t;̑c59 ϣHB$"dƞ(tD;]oޏf1wc4ûg|OT Ԗ$rlGY HH=ѭH]g"1B&5v)^Qa'+~؅`G'GƨF!TJ|;ۜʖє*Q:O4,E^Ydpd,UՌ,(Ҟ$HB$r& }2خ(Ĩ(,w{{TTiA.K,;2iL+mь4k*لH8d&m{HrG4}?1ccJьJ 5 Sʖє^2OMvtQ/oIR8ڱ12#Ģ"/YoE6لH8 捐Մ_1f4)*l [*{=vQ11`F\ߗpҿ)SR2d&,HjGR[ kFi GلH8@&EȱMȸ2Ji-:zQ1QjtO򦒥6e̒$-GvsmUj12( +y3Ҵƨ pl![jl=ƶ[v؀1Q1Q1(ӌ{?SRRx2IgI!I#HjGvd#cc3RoYۇ5VͬiJ3 H%* }m1^]x v嘺1QjѰZ7c5,)('&]좤!Pl[c3E^TִلH8hfƎMHkJShA7 c(zL옸QQYmOe˨ JɨIe4I )l|;RHҎaEVu63Ok|J#rHV r# E2c;;rn j^4txWrgJYFSzQ:OԖLlH*G1R *R uv!9#d Ҩ=9ւ -HUa4ʏNc%*xLs*[jS +O&,Y ʑ~d_j12iFyWd~]SlElB$6E˜Fز )ة V 2 ]d߀GW^[z£ctc0bIaҿ)SRy2jRYJ!H*G9҈Ⱥ"Kȶa !>)b u-Q~t1c-4,mJ[FSzQ:OM +K4rkN,"u6!qaLc_HA-HQa'[ѕ">ڱchFeŠh؊k1+)'&0YҔ+#ob7Ȓ"^dxǚu!a!5f2c +ҵ }s ~>k) +=( ? ÚR'{M +KvY2,3GRM5#TӚ: G8CiEt]hA +;ȚhQ۱ˍJ‹<SJє'MvtQRHԑ~*]7Wټ&Qe"iUgW5Eȼc˸=\SrSa) ~~+]|LUގJs>$U?ܙB'{M*KJI ]C2ud+mߌT#Dguo#=9#.BEq'ȳ e r#H ~tQ ŽJJQ~b8,)('&%$UŶ̑v1 J[*jyPdhE: Ү&)A!vhAn*l ]-3i|GFmFeŨ)~ w)3QedjIC#E~`#b^#ٿ VdRg"ᘘRdDH.OilAͦ7#Mtv߀̯Q1QzѰO#6,)(],U܉$]ԑR;}3ȯՊ&D1S+S/+f4~O__+?z*ko(GhFiE[?3۞Jڔ“!M&TđNbdߌ qXSdڊ4y\"dMH1c͢b +; ;cW^c/GƠhF-hFvCfa٭띟"e+2q}Y3"Afȑ2Ө[7!E/~W1@d?q~k ;F7Ř8Q񣱼)eLxd&;KvʑPjW}32Udߋ쟱ȧ5F+i")pخn[Oi=; iRA-Ⱦ7 R]e1FFԈOFvCXiC7t;?F+<"]dObL#klՄ cl);xA +[H߀{?vuʺwc0_eN%K%JɠIoGttAΑݟPj1jJ;kB۽)5}+2[I5 KI2.l[[5!&.Bڂߩ{?v嵋Q{9J7F3*+FzJd2SpeIgI$EŶs䃜#RP;Va32*RaOkV_u֌f5K)u!Ø} + )!kAzA +[H_`o:GǮ(h7FazSRyפd&I_l;G?Ԗ12Tq3R*"OhEuC88*EHNj']ߩ 3ΏF|(Q1Qi1 ϨLBJ&;KfdȮٕ>FJ;nF&RdָVdX٥aM-DRfÁ1VvL7}8C튻;4!Ŕ;dN] v?~(h㰬)]DM]? w[euvK4)a͌.+s)jl#N i BT}/7 ~>?zvrnjTZ ;;Y5?S2DJIhI!I$#0׎cdߍt6EEٯtuv>?sHlXlkN![5!=[;f5 Ə]yGǮv(h㰬)\Ded ёݟcdߍv8+2#]m kFH È"{hNS2ijBٿSW dcW^؅\!53*-F='e?SҋR^ޒ$UL 6 5q'+ ?ٰv)#\c~Wz=;F9͘8Q7`iS22dIgLvRXifEH?Ά5ټ"uSêdª!/D~LvUF7 7GGKގBލڊvxM2c +UQ +O +Kv #Ru#āHEƕxϜ+DRf +E-w!etLkт-H?/7G~۱cFaF-E%jte0ddgI%$CTGҖ"K0ϖÚ!r`%2V,E,7}ܘA%d lؕ.>fz vLͨ}&X&7PedԤd$ULُT1{P`FZgȹg5Ki1c]37}. +2 ]?ףpcTmaSRRi[Ґ/#HWj6"?Kuga!CJ[d7i.d铏ik c ҍ]i@cΎJ^<CBA&;KtA2:яvv7vCmHьloEnX6~e6GpE81k Ydai@J?h豷VbK4/BLєAΓQKn$$#7?]cd֌L5EC: kCd>̆C`&Cګ>ƊCc= ϰC c{=; +75J1Z:|8,g +UjQ*M&A+#7?]Ⱦ7#"@!D^Ikeĭ 9fN#V}>!BM6 +2V.@dcW^R4cNyM2a +SQjMvd"I'>Q>FʙH1neM!D~Ɨҿ4pBȾZ2lc uA +MIh豳KҍŒ_ъMJ-JIaI$Clbc[/)R U+rxX}̆u3o#"5Ȯ~ˎQQZyyՆfSRi[RHRđvH]i4 !!ҘPfA]ݼ-w!Y)͐ }MϯzrjT^FS_ +SQ*Mv%92.FJRdh[aM5Df5ۗK Qd"ZQY5v6wrS`K?.@>>~1cGS)6u5?25Фd_nٕ}vIa"e=2D4=!a9Fҷ!iG}"dNilAaϯu| zcoFaĊ~oǔTe󤰤%IWlGGvv#_iTa:{Bjc"CE!Қc&dҤ%vւrS`~4(ݘPc33$CtH#'FE&gYeҿ6p*G̐Evvp!9jB)MQd,((͘9)o*L”N%|3~6Pd:[I=*DЈU";Ӝ4"B1UOi;oA)7~<[QeAŒ5+(&cHM-cь)2hHUg6~~f5`Ȧ";ӈ54VMH?) ϰ]r 71QaSRy!I +IzG>9)]̛J~nkD5Ce6id"ۘӈU+BM75lB1߃Z +~~>MүB9vڄc %qׁtv^ z 1cن?DњJR%$sGebfgڹ"@[Nk~o<<#uLB䙅2[LjhD² E^2ӄE\cٵ cޏ1>&zt11bb?hLiJޒJoƑ*FfdH5ЎΖÚxCdìfdM#l 4zǎI#cw> 4Av3؁+^1GSNB2MJKv|S/̑bfgڹ"մkE:[k!25׉Y͔2F$mK!"ۺ)=GH9 5vlB1vI] ̏p0SO0K2ud,CTn-53Dj,\Om/>Ci C&>BM95hB)MA ;Ⱦ~z|cc.GmF)x{K{,_ +Q4,%xGjvH5ZvÚ4D&qyز4!aL2d3PdlkN#i)4ƎMH7. kAv#M2؉ =z;7j1*OaL=)¤[$ ёbd_ifdH7ЎȰƓ"aM}'ٗ(1~ꦵ!'*EvqR}"Ec_c&ٵ +Ȯ+;=F;j9j3d /eb\ڑP;6#SEiMVga)Ȣ!լFOG5"1$9|ק*{4ItbLjl5ٷ C (ܨX?`aL“R$pdWkFoF&؊uָ"Ndx opaȴ 9ȖO]!ŘFrJc 7# -LǮzvn̽TM<-)%:/}+m׌L)5a+ϳݰmq"~a 4plml'*ժ";))T؛d(]1c&G%ƪ?hS2eФdWn'|sd]]P:gǍ4K2{Ӻ/9[Mmr4qǽ idtO]q_c)MA] rSaQQ1?1;S2wd)*~- EiMZga!=Kw5>H86d҆,Ev~O#ݣ>ItOgâOׄS%ȗmoޏ>EUZA$#C?vDqZ"}5n' q{V_!2ɐCmHcק\dscFH4SlRiO!ݦ{V<ՔA! E(hyE>R,W +OzKFI )bsEi܊tuč.Dl#f5VY,H {fCVېME1߅.e|h~W\ɔ&cLc*GS)KԒBґ1FJSH;W܊tuč.D5.+.3m#2qEKZml~L.C9/Et_uc6mM_aQ1Q`ŏ`KIiI)H#Fn*M3R6~VtYmx߇F$ iev}œ"/C&sQ&DHwM4MBZy(c*Ǣ-&%{I/HEuf"<čC̶@Sg58fg(CmCZ>Ey!ݦfLZ'ȷzA)1Qď QѥH#]k"_)"x?Cd8~ܬFD}F5z 6Qd{/et>d2 +RnFW.@ZQ117e}<,KRHٍT|W_O"޸{Bc ?ְY+ֈ\W!׶!K>Y!ŜƯl!ŘF̱EbkAMRHTOxJReԤd"#JEVݰ]kOaVʾψF$1ŐAM YːEUN";҄ +-1~b +*&%{I)*m[l??]5~kjB}+UfƛۍjcfT6d 4~ǟӤ2i\ uQot2̯S=F;fjqT,H9RH_ifd7 mHUgX"aZIf5I=ioD2̆U2ʐ5}1l i⪏?1#cKA6e4(옩Qkm\=)-Yw"]tNÚ$DÚg5 4_fҾՈl`HXVC6 jmȯR=M\4!BM159^jA +s5fT,OK$I9җI5Q'uv$!t[qVSXO)C~Uވc5 aLiC6 jP2dEvwO4ݪ?Q2i9Ҹ5 H_aiQ17cEU S*MjIt1WJPHXƻ8IW"mF$8$r̠چ"Xtsib4FO }ZŽ~GCb$*'MI:GR;yS2Eʽq"aM\J.+>4{Q =!jC]Y^dwː=Mt>FG~L5ԏ^Že %WjOK:I 1WAov~x !ą8V"]-_߲!a4!o5ɾjCʓC}PcwEvt>&FH1 5۷ ;AJ?~(ףcF[2dKLʑԎSdWhaZ8Cd\qiq';<l2i Α1WRaGbXcȸjJd^fxèCTQ6mȸnEQ>qREH7т4=Ȯ*lQQڱ ƿnܒRґԎvP|Vl"O) ~g`#0İ!ǎ";Q7ٱȖː=UUR.ޭ[E[s~էȖ1f2 +JҎKNb2dȮ)JEval3DOą7q+y?WjFڈdTVlԔېrקTdߧ/2d9nL2)vd d֣cIn`ܒ^uGJEn5~VHCdN+2=}ȖQ 1ѐϲAM )v}uq]d{? vM~J3 HÏQʎC^ۜ!W*MjI 9ҕIܬioEd݅8jJ,luVSiDG5hbHc Ye[5bPSoC]mn2U<Ɛ7ʂg}/!Ů`4it>F(A37f!*Ԓt"V֤!R,tQf?,}yxX>acfC5b_| > Ȏːݜ&Dȳ.d!&dl Kȏ 7ZAڒZʑ!FZܬߊl#D"ƭDt'iD:C~W7j0$AC- 5 yӬ v}Mv^dw4rN/cLklф)F"@zL[)RZRI2:؍ܬiMhE:;H?ֳFe/iDQvl}`TڐEC5mHXwV";s!kBn4@ S=n,<-ԖԒtA;2"?0u /!2Մ+D@7"GjfygԴ!g!9M8#}tC-.@11c-<)-$#")"v"evjDVwƧ 1$,DCGa6ɏ6 E#t4Q3B[6!mA)(?U-$cЊ44Dw"ŬƭDC@+5"HsT38w!aO1䈛Ë&lz܆ mH&zG}AvZc&AzA1cK<)$Ysd~OkVd"N[g52[߈L@c YeQv ne4~GӔj؄L*^ҏbuSڒ*RNk5bGjJZӈ,jΜ{!aO4rҲOPgG٪ ^o/"ۯ$2 +۝fb(jfcH7f٧4϶!(l?.e]!U-1)Ȣ r,XD$ ,)2aH7j2{ij 1$ /eW5CiR<|l{Nibwų[S 3?*=_RMiH2qRoFvH~䳚n%ҕُenDx.Wf/)mmȱ>QveP틫/6Qd9|-o>q ?.9TCR,SҤd͑%E&u?> f5ymFwq;-,D +Se.j zPېr!9& "ljfRI2IHH7'V-5],jHWfHu=3>0C‚1es]5Vq}RzNV}~Lkl!OHA1cfm\GOȸj2nDn x>amT]>ʮ]ԈA@2+="x.܏;6Ē#EȤ6Cd> +]@+7"QMkόcHX%[a٧2V95ܐ l ijl5ǺLݓuG+oE:; F2fFdn{lTs}U:.2+ѐ!eW>5v1F)4} + я۽JKF8!^fwKF9< ^f_xܺ+ Z91ʮj*mȴȎːy|Ř&eAh豢MZ#Kuvָ|VDFՌf}XRu/J!eCYàƷ!uXdvZd[ҏi|2d 3;XI)̑!F 0ClZ~x4ifϳ!aL3duRmC˃ Y,.d![ U4h۱ɌUS&)cE:Bd\W2~T@kfg^\W "{!uȫWj}gӐ6 9Tdl3B5%?6i4YsdA:[&jJdfwKCHau 3ҐCl=ʾejBR"%Bdŏe96ʚ;ȾNBg+\/}ސijh|gȥ(aȹ!Wn}̐6b2+9nLÂh۱Q5QjI&LD6Bd9[ٽ! >j!qX%dC>eQvކt >+N9M!mAc*HG[Mf2p;EH9!r3Il4όHcT34 ѐ0nٶSe5]Rd"is![&Ȫ!G"O4}FӲFdfu"}0$ ǭC}Uv6ʮwې~Gkisr욐 ?u,82QUgg~0enDG5!0[\sfB$kCZ됅oe}j5qPӷ!gyG]Bض m?3)+4l"uq}ȳ aCӲQ i0C^5[̖}QvuPNq]\d9M-B&d/Pa~FM+mHΖ!Cf5 4x׈tٕQeŷ+ȫl!aqʂl9:y:dq'e5 ε4n2Ǝǒ3#eLl#DY+090)}҅HB dW>˖}GbP!˻>zNS elcE%#u uv!DY^ׯW!Klc,D5r!CX# 9|Rc,! .$j]]dspEȬNd n,{HjBXev4Iٽ!0[~RB$G5fڐmlX>^>*{hP#ېO,f(BjA~Ύ%MG~'Rf'>ɨF^$ʺOguCn}T/!# 90YxҭC}Qv<=Ԕېy] eXY2qd":;XenDQMF]foW #Vƭ b[CVOjJ W j2]QW(Y!àjCR~NGH_c&d)@J#"+!2/Ҹو'?29Q 5!ͅqi.$WC j6_EvTkD~RcՓGJE~V,H}Uje#"/Dj ٸ2/![R0^Y>(9a-56d\ːj(̏[ѶHKv?Nlш1G50c,DVl<|v/!r^ww,/TF峴 'nNcEȊ M?Neԑ1F: f5aiЈT{=-DVVƭarΣëfX>ãl(} ٯ"!}-i%8Rr(D2îH9qavr-}}kY+m90VƮ &'5ja<_lXCA?Nw}$٥Y?Sё"F4BXe-u>+jΪՌ=Ɛf5daFCޭ3z',4]ZG˱ɒ#u]4;03Wƽ!դaq!a?d4>:LOj!K/>*;KqG"!3A,Ǣ&3GB"uj4"Qf7ϺQG5 a6ieW$ ٰ0nSv¾xi +rk=Z,*r8D7"Q=.,DG5; 1$,̠!>\Q=:b0,^,.Qv/.!î_Ol! A~GC#KLBd̖tT2YjmSx!fg<kc?RWPl\ٲOx`?+F٠nC&s+B"WG抬H_f})F5a^f>a!2j1$,Ȝy2_!ey-.jjmH! _e%+" evju> ze|pl , 9xsunE:niC"[ik&?V8ܑ#B/Fd~U#gʸqT30+`4丧}ϲ¸XZ)\mH3"B悜hǢ%I7"䪦u-Df/D7tӣ_Ɛ rW i:,,$]5٠F!"!e]H=,+"YM,QM 򃇃>Bdee:; + 0O<\a'5¸tRKirV?96D&e}--> y!̆pE~txgH3߭GrPې"YhIbev҈pވ 7X>BdBdj䨦tř<[ 1dzIMx?0n}kק!BN\VeevyT#}*䨦tvh>y VMِeȱOazRc-[/Fɠ&!E!,Y 6hyX ʸ}TcZOW\ + ka{CV2d0=ƫ([j|*-78Ardi4"}]\WƋG5}KfOzCZÐ<\!R#ӓ3dG<} j6.5vݏvXj,7"3G5 +q kgwdyY}tNj gj'eAMچ,2Bبǒ$ˊBdRfFdF ,DG5a0{}0$bECZOܢlHwt 3^r86ڐvszΏ#SEVC.G5>;Q>6Cn6d<)i,QԴfڏUGVB`#:..DjZ\lg yْ!(_,Gv2)Y$?Zi]hDVOae<=1TSyb>#~zQ$ >~!+gIMia0'ڐmr&?,f4"KH{e<̎_;Đp|mHyȯL? g091k>ڐ ٥93GFd7>z!^8;k`H8(2'ƭOβ퓚\ːr٧ Y +M*D>0;Wƍzm>!dϬ'G?~pԼ1?I!QՆb=1HYf I{GMav>D&OX;2kO=~eۆ z2[!+sFAߔi3&ӷ+ңOfg0|bECX4dg`!YfaY0ya\~+]t>(Xd"d-+\}jG5١<6+I?zBCYyiarR#ې!e5eC +Ǫ$k!2+QOqyvh>.2dّ!KCڏ0Dzqc'Iv-BNcّ#Cdڈ Bd~Tc?]qO! DbHX)+1mȱEG!Ր0\l>;OWTϟ]/<!٩!ʐ>ůT YeW !Xpd%D2;Ռ2yvhfx rC9XX! ~7dea쓴!$ێ[vp6"UN}چ|>.}V?Sy r!/4c. YW0dg+Wj +.4!ˆ)HÑv,٥avb?VG5a +'t1$[r§aOCϊW e ΐz=Pd9ޏ5EevYX;fOWԞ?>+/~fbH 9`kaOן?\Q7dFf)BNd4Deve-Dat|, R=;֐-c82dSuCV->~V0yesP! +R]>!?wgŧ+4ǐp kȩ7е Y';:l7"{ Ei2;.=#bȳ YP 90CC&O+줦S5|r## T L'tƐ!aim1LWL1 QlC BȪ!)]!" }V~1| rC5|0 l35y>ECV! EȒ"qݧ2leY ݁0Oy冼a4?? Y~]? Vdo+jlfO7+D't#gfYԐ7א? :P.6d-DZ١Y!!HXڐ74?g¸YkC,ȶ2[ [Vˆ|{!O? yۂ!!bHX9{6䕧'VaȝuEڣc!͐o򥃆|hS^!KƐ^vl˘mH1SҐGl<\2l2,}aC5\!/!a=d?a y̐b;k§+ц,>;ֲώ#V 6ӐqC5m3C;Đ0 yC|.fya(? Y;gy9dHkTS3Cq)`!kŐp!`Lֆ.А"ˣ9t=!,b͆4> i}ki̐;dK]2? җ٣/p{C^C!p(L?k}k! W؆45 3uT)3L?!Hٳ!ϚǐƧgjJOԆEȐ3 Oyݱ!>d!g2|ݐtQ4eOo +CN YN aGS ?fUմ6c Y ?G5 |Їj|2jY y2@75";c""?e'T>=Րg`H8676'# [r ,3s2PxC#zCCѱsC^v!KC趞e1dI i4"QXC)9ح y ?2>p,,+iTn?- |0CC};C^t!bH-1wlaȗ:Ce?;ڐ ٦ j2`a`H8vhK冼R4ug7[ qmH:NOj S!kg&ҐWŐp،7!`3)B9!C%`țaH8.i{*C>dg ?m| 6XCn!1$ hsjȒ"n7 Qm#d!C^#5L0 +|Sb`ni!A6}!A;2cHX'6 5p\!C‰FC~eG AC~ՐːOy b &C޶ݐO]!܈h21$,Ⱥ y;.wՐ[! jZ?l7ϐ_!aM!?1! r!Q6|wgw4IN% y Y,L c y} G1CkvCXoO  yUCbH r!5m,kTOf ސ<ɐ5C Cd`1l\i4P=Ґ8ِ6+6}{Cb̟ǐN2k3CC!}3mC(C^3U0$4+1䭏ɐ܏!?6ΐ7vg3;C^CAp<|ސǐpՐWĐ0!Q$ +<C4߶` ) rCC±! 96oC2bH8MjOj0$` i*rސp`H yȆdv ĐĐĐĐJ 9>CbH !1$@ !1$@ !1$@ ecH !a`H !J`H !J!N Đ% y !1$ !ِ/YCoא`H oC!# ސO|C>؁!l!o;s=3|/CbH8Ydf`H !a7`H !JѐwǐițcH8601 T !1d!!4١!/!2!"1$b%Đr!{C !k|dC^31$4cȇcH !aאWgjcH 0 5CCАŐpr!CbH C!V10$< ;0!b>Yg?C!!1$!{Ev!S2u y _C~Cz y!?~:d!_1K1$@'h>"C^Cš8XC30dfȿƐ!o!wl?א?{30$,<CrC~C.hH/cH +t nX!!HX!2 !1$*kwaH %CNȐ?7ɐÐ`*g'`H !aO,bk8Cp.CCbH ;Cb6C$C!CTٳ!!?!1$XАǐ|H8C~\Cv y { 韮(1 y | !;AFCvO:C} Cާdop\`#5_Đ61$k1䭷7^sk r6c` !7#  ֲ!?!1$@31E1$Đp`H !J!71$CːmbokȻwTC~9ճ;C^3Ge`HidKcH8ؐwΐŐS\CbȐ?!$9CCՐ?;1$+bȟƐC'ncH20`W }ΐ,ws4}'MrW|0cMmgȻ-l4!=ʐpҔC$<C묆 y !CnkwDCCXڐh{|4ĐĐĐsy ya !1$bȗc9 kE y#iCr!70$" ސ70$@Đʐ~33C`Ն?ĐdgnG(C>Cno7v G + y | !1$ + !wnH'H Ǯ yΐgnaȅ  }ʝ![C CbH98C>2 h8 C^2W`H88ܐŐC8`C>gmkO!?!r\|]!?!wfț䆼<CCI0ۆc ꑆ5_M1[ c3R- yu򥍆3 !F0ΐÐÆlV K7b ewoŐ# w͆C>7/L50$7/! eȻNw=cCb- ] !!_0ΐw01$>CbH +C!2!o!م! r$aUx`ғ r^C~xVCC q4|E!?1XC>|!!;k WC!!X!CZw !a_!_!1$|`H y!`ސ_ibHXU{ +rȐݐސp`!,  9ƐO ޝ65[ʆ|xCI15ѐS r|SCbΐ/ː7t#`5FC>~АoƐ`0$Đ%0)CJ}+r!CboaȇaH8E0IO\C~Cd)C^0 dȿ C1cHX  `i熼>  U y1䬆|@op*ҐƐZ b Y0ʆ|+t WrIC^C!0!xc/]!?! ސ!YWj_ Cn!CbHf7` yц u!1$(!Wno[ΐgvCaz 7C ly y!o!WmȟƐple/ +endstream endobj 324 0 obj <>stream +! +CbH CneHS'iop`6&ѐwJfgȳ0$6cW!maCޭ3mdȥXҐ7Oې!1$, !97䏯ΐٰkʐ`ȹ !07bH82 Q!+C ĐVd`H 0 !41$uw]6C +E!_!L0 i|\֐! y#  yw !1$c4[0a" yfCCbH kCbQ?Sh N ! ܐĐpڐ|ֆ0021$5!CbH kgǐ!uw 9! yq Br[CyАo4cH8Z{w_W 1w#LdLTWyhРQT +by!ZHr99C aEȏݯ/B!gsB?BHB~rr\g^.!㌅|!8gxX'?i +C!84g$Rțz!o4K oQ[ !ǹx S !$ ! +y!8tvNC]!f98[eBr^N"CqN_^!j!䅼$!9s*Bj-+z|tk!8OO:! +sCqi3;7B!9Lk!Cq.B^,!t|!8wC3Mo<pg9][B~r>C!伐:o9y- 3򿇐CqN !CqΜorB>o9B3Bx98ٹBJ7GAH r Um!o2" FOτ*"_ ! y!8WOBYȗo1HB~s*!Q7KB>l9>C$5'$;!93B!';C!J!|p!89PB>w_QCq.ه=#!D OIȻ!ǹ 礄wB!٫J/B@_:1΅':"!򳇐\sBB~AKoBn&+yNYȯB!\0!vi㝅6!v , !9sB>vy\!>rKqCq) f! !/o6\W/_O]߃/B3N|./a! BGwBV B!% B^\!_oCq.9<iOB GCqY{C~! +yHBsyN!9+/!Bj98g9B3NvC!8dB"|r !_LGU!c9%>C!!_=Bc ! ! )Cq.9=B!9s!䁅r3?F^ț!/kwCq.9أ9d!{98K>.B~Ez|!pEB33 BSS!!8,< +9y!lyB!8't GUGn!q9g\4!n7_!!8 !/?җdBs !8v/{wy +.Cq !CqAT[!OLT!k9Υ>o,|c !r9r'!C" |!8zCȍTȫ>|QB!99a!j!m98g'!r7!o%}GυC!8lyKȇU!`_Ba !8\p!B!gB!㌓vwNw>5!JȟPBs1C +,r ~NI/B OYȻ!o 1EBsBҥ߆Cq~ ;!/Bs 1!r9Y ++;UȇBm9Υ8H?B!gɅ|!d!r9)k6B!99S!w!}9璟C +!8$!r9r +C!8ts{C!8:7v|r[!oCB0Br݄uABo@A8'ˆCqCφC!8gqC!8$r9璟3 C! ry!ty|1|H7 !rNg!^k!9ɳV GCZkDi &C! 9p9Ά'}OzS!m6r9f^";LBO?xy|W#$>!!8[fܧ{CBer9NB^b!Nݠ{r9'm  Cȃ g';AA85Bn"!?lNA8Y KC! 9g:ڐC!\v1{9^NZ.['B${Z!?d9\'T"?@n) Cm/>Gk-}@΄!rq>Ojo/$!!r9ΚBr!?eyB~ +!+& r"$CY.B~Rdԏ>qsZ& dߠ-벏:EwX!OV/B~nX&qO)_kB^?愼 ;;ktev[a8gwo|]x_Cȍ\% nD.!r 9 i +v^wB^j!? ޙS^%<q2!? +yB>bG,  +]ȡ8t"~!Y]B~CP!s9%?jNȫzY!}yB~B!? +C5>B."r8yyr !3!gXwB+aD(/Yh)#iCF:TB + ?`ȭN^- By!cB>~y!g!gBND'/'Q ARW(!o_] ><]nD8M~ ImCKDȏ(B~!o2Qev͍|9= Ee'BP +aUȏc!oAB~aC+!pyT!\y%B&Dl߈<o4<峟xcN!>3" +y^Cȣ +݋#W 9WfK!=tx m+5]l򓽐ۧ<\"+! 텐a+d]ˈܓC:+<* 7jxPӸtOBR yEBhK !7YȻ*k!} +M@=y@R,xG}ǦB^};宙5R_PB>owQBD>`?}|#2 D%/ϟ51RFȞ6R?~&"gB~CJ !)w"xB7v "ܟ6}98-.B̵+BNO'U!?Br !O y*eB~PHzBW]+uݧ1'i侘<lWH!6X9!_gY8B7M.alD{r^\FcȰ `{*Q|TCȟB_ȯ򓵐ɵl݇iL2rN[Ks6u12eҡM>I/0B~B> +UB~a(&BH=nsDv5ǶT~"8Bfmha<~, +IȟBǖyO!tBƏq9qȥD.Dr;& ?y2/qmƣ+HC$WB~[{ +yj!g!c>ɺP#CdHoR$r؊\سf/"ұ!!+]V(wj!_XȿB?|SOd!^|p^,v׻ +>\"F \&LےxNFGcȎ5z>\Qr!.O.oX'˫?|:!omhǎjdȀuJ=`8f:*S m6$ݨɖ}̵lfEH\vCU!B>!^|UoR<i.f'l9e OWȋٺj\Md 3ylY.9_|fP-C/m3!P|( +Bg'Br9+ϣ/|L_dTOWx7"!IduN#wܯ2\R]+̇XȯBE_LB>BBf+nTi4F"a1Axx> m jWj*䗳\| +h#sB^3! (#}XHC~B^;WD)yc3sg:vD< I]ڐ~P^K]!*位B zB~[[H@$alD2ۄJ.rry_;яJ26~a^a!o9+䷶|>!d,k +Fo +OK5~eG5i#B 3Fau G,~{,AM0ΗyH/7!'ŽB!|A"êB!>>q=&Dv"5}񸛍G]ahC\TBZ +u(T!{^ȟ!_%_L!GFWMB2 Jȧ>IO|B PH9X@$];VQM"C"C#s$fl^xF#REȬ jp}粍?~S!S ] + q,C!ϟHX񣚸)C$ٝD(}=NG6B";ԨuHpE\$w%!UK(S!_f|XȇT!9\̮Bw&mDb4uvNGd#yl~Nl6z ̊lP!!_N?*̈́sw򅑐vBFOW,DR#2-)D&Dv9d[#ylNl>pT<ЄTlWdSҼ[Cҕ?VȿBZB> H[YH-VӅHՈl" `r[8mΦ>GͣTdS5eetV?W򟄐z9|$/=(䷰͋e!2~C7iD4CdDɝ0rgCw1HWcgEv:>JM+>uXBB /fk!b!$?2HuЯvV>"sNFrǵ6:%c0B";jCʷ`G]IХLBぐ0DCXt6"!&kWB&5:.QdPdCrf_qOy!+EpB"_ !? Iy0 ^uO})lՈ:{Hdj&W!9\|qKq:]@;`!([,B>Ѝ?SJȿB& VS^Bʸ\܈te 1HɵN@rǥ6=@iPH?ƅq/7k +S/yEH>!_2#w +2 ޡjDBmCd?Hdr$g1X%GZπ2([lԸqs-[=|gj>OV!?>àWa ev"F6L\>_("ٲV!ҷ" Ir'Ar9vq;ۨp<΁A6EH,6$}F:OZ!-uAȿ]#a𸏿-"0ۍjT]g5*DvF~˘adnhp:":@j yJEV->RVCKgc[ g$? E_C%d@CY`e\پ)[b/+m42E2f2q_ɽylsvqۨt$3@r#$٭AesaB!D>!uNS^JGƃv!&,iV#v"gLJLwFr=^>GS0B";{>׎˲Oҡ~ڧ-P!y)L_o <]Q";2[jd#L.pO<6X>c'Gy>Yv!el:Ƴk35TdO?g#Bո'tB$ ݨ4"4[j DVd@2R ."9>NU6JGjĝC5ʎ}-[?>S#?H!OQoBOyeORfQMRfDFJ$S$6jcO|qEQmptgmLp$@[Eȴ6O6$} +6!}fB +o !`_>2>ӳ2oWF$jHi5 FV#=J5N6\ 2:kc[e6:c6݆}`PCײ>]w3w^Ⱦ"kɺFd6! kz# Ia9l*BroF[౉Gc] w}̾8ިAM\qײُo*D2{ڡG5tF6"?-RH5iIF&H8fdɭ<6d:+%8l81kl!"@b#dRd6~juHw]˞}2{ }0\4U4"2BDdrJKE#>nTn#RAaMH~'g\䈑x }68G)@@&9B9-!K5ٕኅ9{ C,dxFlθ݈2/HQgDfF^UNJ y#m&g9}l8cj62ZGRa@#ddK٦ 5fC}^:l>{ᄌ|1;_t3^j6AuvLhd$))t[$;Dn }l8cfQXxDm@&du`Ncކm|P}z4Fu<*΁ v!yNS&jGmCBR jf}_BieBI5v!˜FKٲ 5zm}fƓ}K3|+XaF Rf,DBbdE$&9T2GUl'F^^" |t0̎F5Yf7"Nf51kbdE*L.r2`2E'Hc;l |t1屉cБ#H KD:"[ !iPײM!","ul1҈,WžZf!H#IT2brɀ4JEF^"r91pGE60Є1MSţ] ImHģlSmu31SХ".f` UɾO-#dDYD%=KS2-# H.@9YLh#(u$؁ +Is$B9*q.e6ԸQYQ߂WjZW,zD[WoaFdqդuvFl$!)tL.pr^IF^|" g}411qcH>b2RA,s.qކېF Ζ}w.^p!HjFd3nvlOld$*ILi;陜AɕF^*" }41 VǾ~c`#:!>؁d ?2Y..lrXv}tR>0h\pBڡ]HZl ݈,j߇r7֟HlEDbH^'甌4Ayy\dc\^7y̢c1GUcd.s;\d+ o[ +;2ӜfZge'hC⠆>RF:k٧!a[RMY}`j`g4"jiijȘHwߧsN ܏Mhu q:*!>"@@<3i\ͻ>rR~+jtg*gBd4QkDF>\f)Tg'DRF*$`cl)!-*c }p\`yh}LMx]#4E66Qk~w/ݗju7̮׈,W}(iV"f#BId;ގXId$U12-L|֜£qv4GyX},6XEd3BNsNv-]ې/54>3z0B6"娆@FdSl]f5u'qZ c$鑬J& P:' Jn#c$rw [ySɂcy(| 7iƖ7oM>ӜFf.e6QCpgFȥײO^Hs"ufQiDh߇iVC!DBI1 \aR)gLcDd҂,mUx: 5UG +#GcF9 FHӈ"w}mH T݆Qv.kB_aF$eN LDr F:$%N&\iE&rAdž6QyL|@82 ] wq,d @HX }h=jxiDټcnQ95#e=!)&ʄId%w3re It!}0G5Wy4" yJdh$IP0N2d2PR VF^P"Rȶq|tr*" y[YlڐzPFv٧0~ +BtP][}0G5Yf}VS񁟲C;.DDF*$䜓v୙J:$ 6r飈Ixl؎hÑģ# UCd\c.$EHI6ٸ!ƍexa\\:O"i-G52g5"!2#"?LH +%I\tJ6:#w$Μ5@nmyu qHy>rR?Y#$x)[!AС\_tײg Z`Gl9q~G"k'ng+!"ch$ I$0ɈId9#R{6F^<"2 } Gci6:)<"8q>@F.BҜOmC>޶!q_ jVkQq/,d|&Z4\ z-G5Ԉījz7{ȫiwkLH +%I vR1)Q|Y#ٮ/2 =>F<6uԖFmñy # $^Y5Eїi_ j[ٍes_;l.DuQ 5"H2Y D~ H%$PL +%ml#iJ% rK +즏m6^(qd-G +.vpDHXs.E6AMr+[C^:2~ge\̏j`gOFdPfì~dtÚH$%EIdd(3&ˌ숑;yl!# -Hd:>jC$6j%JGk#xLSw!1B9Md>ІnPskQ6-l0W!^}F5bgbGjVC!DƏ +Oddd3P&w3$u0r.F. B@Fv\`H1Wxبm8JRa׻0B;N(hC}:wlsNB+z!o-G5Q#R2ۄ2Φ"!F*#K?r[(Ylʄ@I$n#Uל5 y4:بm8P\e>c},HxGGH9"> Iɠ&eoyBF j'fǣIe#̮wYM";/L1cH6!J*&@4Jz$n9[j B@vر*><466IGˣ +Ra׻!bEӔ8Ȟ"})B";lC}qQ5z.\!uw3ۍjθlD}Zf׻<Yv"H_g["m#!GZ$IIǤq(n#7'0@(y߰~7mc36zG(|$ޤ@5vNc"duq*U!5]>~al"0;{"Xr;5m"ovOYH$VJ4 N6L ̐l#v7"@vHU`M|<1Ul4ZQGã:5@f74Ӎl!yNcly)!}}OJ>jTlDlSyVcCt;5fo\9E޼1R$8)⤁2r1()Ldv@9> x [>:qx8'1:6V-᱔R`S=HRӘ`|EHZEjCv,Weju7G5)fþ*yV!rgu'-TiCF )$) N8iT2a2PdY})HSa&>16Mbtl4ZQGcR`St@.cF6EHX9 r'܆l j({>rnegӈ>\fì&lքu$3+#*H(IJ"N(@)̔Lv,Fc(ΞlG(!>: !hqD %>JK]$T- .c!E6 i! 5=rf7F5؈,Wp7f5QމuvB$4#K,He +2Jई P8$) A242-)FJbE@TYQ]x4:omXi62Gc)K +{H˘`r0IoCFl}uY!7fQkD֫jGӬ~0DP9sM0RI% PFL, 䬑1r g+F@HϰP^: +x##hx,QX +ҁE Ӣx H˘fEiN#l͠fn}u čH]}D OMX9Άa )KR[EI$82bR) A22Uj_"" \[ }m}Q]xD{1FEQ:J!>X`S=ݤiYP7}9iN*ېznvf(lj62{ZYʹBd:[Nk".1Jma$ɚ$E,J +&>P8l AȈȷkF"ϳ^!3 vZ`>h?W@cl#EGQ}[Us@B]4ӍlrMEv×AM:^[Dlle4>j0D>B$^a ٦i~.1Jma$IF4LNFw')LJ +$9HrMF^G9#w"+Q ln@u|:QhnQXp:jK|dV^ @o/1MEiNCȖ/]ۆ5n焅fQMЈ7"2{ZY ,\i 0$#J2>(8)AR$IؖFvJ;A0>28)OC$pǷ!׏OUH7֣F)i=-~J|8Ȳu:Yn#&##$I¤prx3(Q#ARH#*͈<6O*侀L +G!fM3J#G lQa41+5vL7uV}hNc'\dxeA͚ +v=߈evfOwFvxB$6#a]b$dd XmOHNJLV'3(&N%C$9Hb;3r&F Bux:FgcBcQ:j)>B~$ S aW~{.H!՜FS2Bη!׍7RG!Ũ&iD"e6/ӬFH܉,DR HlFA&I$1YNJBd$%im42.&gZg!@G=/~oocBcԱh#X   Xc1t#DHӔ;r]<*}qu&eha|Õq?̖3_e6j|.ԍxDd]f$ l$ dGNBA]쏑ywR +VQ }hu V?!aՈIev]Y -;rXCȺHؔRdETL +']PNBI\oW$b.FJ[5#y!r;HQ`g>z?x:{1.6&4IGˣ$ O$α.>Ӎl!yNS!iHUdmA \u%sE߆5-FEp7f5#Bd]7~ti"<YJmmCR(iR8kQMs$GIdbd܎D^;nF>3 &m,.@(cc6&4Gy>b Rh4*^!]zEz!պ8ې洅\6>YMWcCdXSމu؊4Df%F*HV$AIȒI*M(I&%"HFiw#!Cd ȷKT l(1>zKGccbc#<:k g4Hބ5vy8n42BUx;W>|v}QinfQM܈}"̆{5uGr6~h-"-<1&IVRI'M(L%I Fvd#u)"wOYy bH߂ G7r_ :;vFhXmp:"G<) ϱaLSޅiT4bN6!mTe6j`GȲY߉a b+HXjk# Xn"L8YP%Iɤ{Aiۑq\FdԊ<:{M@vH,.JYG{ E 26!]]ޅ4:B} im jv]YԈ+DRM ?2DN E$N1AR()¤&P4(YTA27Rjmg9٧+&2@>QG#sQ&:"fh46Z!;X+<:k-dmA@&aLSilL4ڐc 0e6}Ƅz<V$~I1ۑH$+)ävAJor0)TQ v Pl+#}127%Bހ|6\aY +G?}b(q 0F5ǒ .>r$M slӔG}: EHZeBg5)dvf"FIl^Y/֔'~pXCu6=aaĽҌ1Km#JId[:J`R+dAdQ܁u ]c/#@:My]QWGccFQёtb]Zc+T cO!}sf 59![F*ĔYa x ܌)HZ%E789 %9TP@$26ކ E. }-i@||,5[FG-lid%.<*k-dmA"BTFȨ>mr\#r̦/zYa E@$ܮJHF*)d'gN6H HUiOkV'#: G$m$ N|yO}X#DG3Rax$+]ًF5jv̶jd'Φa t&$RE,6i tL +'c("L*%2HB-PifdNd{}Úr iZPa +lcȣ|ͤB#ۈ8Bt4:> |6ZaMH|L04ٜdw!5 Z Q +?!6~DMWkB"cdb$#(,NCNDd> |?e$2F&"ODȠ +l4>r|DZ6sFFGˣb@›gMNcd;ٺȞkCn3Vţӈ }/C$nq?;!R5#!FZ#-IdJaR=;)>X Ŷ1}aLӯ~χz*laSc£4hdFa>>BRh2 eR`Mrm}AM"6nD2,7CA5ONlFYڑ/&# D&sP'c%-$|4RȠ)5sD.OXm|HjA +[HFG_R8&9LNcht,xt>f49 Ii~T<ꣷ&-I j6l +/I~A$4#igFz#⤅2,RITlbb1R4#DgRg ScMRc+ m *l H飌ȣ2c Fq4:Fmc21ٟq?j$R6#Ed#HbJ"NPz'+d$I*3#U72iF2#|Y!@R Bã|.~uH6JR^[1@d~ }6Os]d]6>GK̦jVn H##IJɉI豈2- ɛҷg)HR F1#U3rȹV)]"d $}k. 2 sZ-!C'GG@ +Z}@>Mgۆ<;5"}UfY /DElFBRg5R")$+)$'6RZɛ*$ؾbd#GHӌ'rM}d!#dkLk:=S M-}81zǑwՈ:4lt hx$k +lЂx43Eɴ HiP),vU.ZIdR;Y #eg}7BmUl_1Rq6#i D5j}!r7!灼kA +lP]T:&1_hDc=X}R &dPcGRi2dcXm~!6"OYLLV~b"I1rFZ# +$1J{RrbR9YRj(IT,oR4ŶnGR|y"W"O.D.vL5v܄*Z@/>h(uԗbMc㈥5G1d2G&(erFBn1}\g5alγDf$HmV#%%E,N -ÓQ?>+ mَ슑|G^99!DȰ ɯi$5 *>h^81LFđc G?V ;\!휆d//OQ>Aͳ!rHhFLb$#Hd)1Jւ[3INv@޷I5vHy!r7!W$Ѐ>yS5rA#2(ŬD!Qg'DOmFL{W# Rn( J +&;'PZ'[P-ZHYjsDY"Bv9+l|ь''):%"qu6#1F8Yr}H@REɪ$ɉIr4R s_ D7H.1Fь̈4Ӛu U&d@f +|d??^ _g Q6Ya4#QX}F k g5ݎI G5Klդ!2 kƽH@$IrrJ(ETIa*1Fv/=u!@DH3i5!{T +nOu]z4Ǫc P\#j6ޤI456iiV}hN_d @ȬQfYM"Ə3"H[HmdGz$U&J#JfR(ndl*qm*m=ɉkECOHyFU8 v)#gBQ. Gc {!IFB?Kmэ6k""ݴf:\![7! ˌF k-:X`qۗxNb#$G‘tZX}V#p Cld܄c8B64q=׆< !ۍȴNC$?c5"R6#E $$(IJj&)Ov@id&HzHvvH[D"B"do=aS]dcG'6zȨi,6NKqY![evQgV$Lk4hFBRj$! 6GI$2yBR~MܤN~{I$2v$Hu3B. Ӛ:{y` w356Mi_|@rM(>YKTcӘ#䟙s- +"ƏVdDdH#k-( JdJ?͹'ɱ`Pot HPifdJd2鬳]<5BEH_c)} 6ڀ ޸`{GLq$em >Jh$ MHnBmE`Ns6䆍֬ƆH-54Vdh'DҼT#kF>)rd̤͒rʯ;9;*H*#qJ)FN6̴f$k2"R[gwȓ,rqj'f4S RT&@5G(u|;}|CIh4NG5 u HYc1Ͳy"{ev3D?ظmAdh{XiC1ۄ$$1J*%'& RA)4LO=8$8צRb$VH hVg$R7!o4UCAN@ 9U >Byym ll5Lp:rxGT`C-Hm)lB1 <BsE4 Cuv UiCR|4HrJe$R8d%\~ m2JmXic359rZtXm< ;FdL#@TaC;czL\;Yh,2FƑt#g"@dH@Rif"侊C ]"aXu$UDJb5IUI$9Yd)( n$9#9FRm5 "@dފ:+DD"BY!M4!c +ȏ1@bmԀ>GW&{ڷ4iDGґccqc-'[@&$3r}}p!evx;[n@-[4Έf$@Rkm dI( Jd%K8除9$-#RbdI$5Φa9]k w˚)g4ȩ4u>|xt:ҕ{ Ȩil8Vz9@ iz"d\d #do"ͰlhEv@tGXi6TQfIdqRCi' oAmc܌lMk:{!Z32҂*i  +l#Gϣ}^[z +@/qp:rxQX l 9Ë Ŕ&"!ԆK +lhE&'Gڢ҆4R IREIV$'J#}o $!Hj#U;rЍH; Z<5a\;9>K"$i\m8& ?ZYf4k#GǣQm}/qQ(t,kⱴCudcsY4foCRɬ&֭Y"E 1!i()L' R(RU?kd)ȫPjYe^㉜";s?"WF7_!M]L{>UC'{ +$R^>.SoM1qQH:rm ZYGy~yШed'-c G)#5@ˆZ9& Qc99i!g5Yg*mȧ#Rnc,,NC9rӓ +I:מJmPTb^[?Ȩi!e"{m5hB1 k T2@Nݠ>hyt:ҍec'HR[2@8Hb/2Fً}:DfÚkR"Rjk#-*JdRAC,HR,Ŷ2R%FR Ad):V^qu]BdsBvFH2815jBq4[>Ђ,6e-},5G#%QH:b籄GcG k _24UBmEڝO$:^+m`F>$$KQ(),N2 +J$1RR[Riü=eMHc B)!b>BFcZM +$ ?C9Ͱk-T`KKym#~SF1il8%>xc󮸯]d=e 4 llE /P-c(K;r2v&%HI$jdGޣYJm\iHzGڮٚޤ)k҄SXnVӈH,'Bu1ƖLdx(| g4Mȵkr@"'D6llE.#H0hd$FIVR0Yd(#) Jaa$IoTjS,CRi6a1;?uZ"*"OX9M!YFH9WaJS|p4® +:!)>/WSD#[4N6jEiQk:@RM@j҄jl!!C4DNkZDR3T:Fj#\ QR0Y\q= Yme$#L$O"@NkT+R8Y";g5r"?B6jڄ16\5%6 a]G4r*ͷ]v6B#ӈ6N8>q$:RqMQc 9eiiNJYM"ȜW "2dA$1JIrL 4L~t 錄vTj9 ҮHDӚҊuUttT}6 IFֹv)9FJδ[17G"qZIBdϚYQܭa[nB16N,3:®r*'},5G#.S;35hQ5R|4<cdcbcё l 546ͩF4D:;$D֗~H!FrHW2`8YRz(&NϘt Yme$5F6δ5DZ$Mk`+Cve\\dGsv1 uG4!ŞbK )@Nvu|ďk=]v6f2z%ǖT}@̱[i d2YUgY*m#e4Jz&!,%AiTL3I.ȩYJ#Ҿ] "?WmjE:{y2{^!qLjl܄TSy-HaS +l#ז gc342PG#ͯЀd +Ȯ{"BvH;YA$RiPJmaOTId8P#e$]Ϙ+$#sjGBjF:"6"?:5>D^Wx᧿>h_6,cD#ڈ8f:}$ K3j cwE#ٛjuv$5PiCRڑhdĤr#edۊW )?2FHnFH&Rlq8^> FD^ dW-4Yksl !wd Y+ 9ͯ=h/S+i$!9N8:*S}$T8v}br kNZbs\H)FR Hc$'TI$9i4RIf8ARYg6.1t#҆H5Vuv/q!m/+&^Y4+jl~bHlAHS]{2>2LmwXi$ GQ`S,-e@E +CN#rEv!aG@Bm$T%@bM>Gu66Fh#*kH#  ҸLs"SȹbW=DB3Hd$2INPFR:L1:YXiy!r)5jLJpV>!miRi y5dk +C(Ԗg4G;*G-M@6bgS1rB.:[Nk"iJ$E=c$ID*Knb8i #e$1Ϙ+$!H*#RҍqEd4ϦaM!@e>\چӴ#$^ $,`x'Qو8ra :Z)>}T6}rȤ 9!3i9/dwmZDa%RT3FRtH"LNLv-d&g\4Fb 1y""& Ѭ&W]fXUm9Nt\$h.)@N6Xk8Q.626Xl8ra ٱx8i4 ؋" (D:["ÁvJ$k: tJ0IL'-y-d&3ImCZڑԮ1+m9YCd#D.>Q;mȮ"!uC-!W kR(A}j CQhԱh1Z5 iVdVf!2D$RUڊHe I$TܒIrBFJ3d"Fd5ε9Fn$Ub^=lX5-ӈ\#"4;E߄@S]{j}'qt*bQDGQ㬏H4̛y})dkVYgiMJ$}+Tl i%&I ,%%JP4A9%Fn$δMw-B؏yV߫ BQ=B!"[inD Vȩ&yW2TAFAq|1huDK|:Q)*썀\!,NevށHӌ,DfFBtJ"/L'aT<!FZ[#xLd^g;!v!YI6"l":Ȇ95!83l@rM11bc#4V FQW#QG?Y\ҴkV}-n!Ҷ"qZ FЏA JJ&!L'+"QH|6]VϘG)H +##Pz_"t"KLg5eF!l>QE5! ˒ z#-z4*-JGIS UkxyBFA#pD^hy(}; k]4$҄ȐHLcdh) %Ie) oóc$#PH;uvwOYMXfK$ۆ w}EY7Ym4Ħda9ؑ۬nvAFbJAG#G ]E5v!O^:HWi0;IT0dq22f\<HFݟԮ1Vu 2Bj,rI<쉐qm4ڂ$؏{#) >4 +FUV#BG#R^5HvVaoDȍC6Dۑ2b;2IIUt 'HiJFH:#)FNCmьL YͬjDPAMυȖs΅cnY[u2Q}۬h +#e ipT:J( +l )_Yd\c1͹ K~Hё$$Ĥ1R`WQIB21Rv#k]g 퍷jދg52#rBD~!l4#$i| !@^ +'<|k>xjENJ#(tyG +l +,{<;zZO$U#u;b[WیP2`:YL"Z+/V|"!錤Yv#lEҰƆ`VctgFL5 UȠniD1 nJぬ-:Hյ|1(he5(t$MG eȥ5#muv?Ҧ 1wEGR!)$&NV(6R?!pHF>Xjn$T،tDV$fѬffՈ<ب_l'-yNcc 3 'QVjɣ/h0?met4rp$QGGq>#_șyZBٻiclGF۲ڞ(IJj&ʗPi`R<=n@I1liH3Ϧa Y DۍcjV +)?`v܄-2ZGӦF#Gţ.#e +?HnBn!$LÚ&<!F&FbTQfR8@)N o0$'?SPiDVg9;{5W]%f'NB6dNRϱ T ~<>~|PܦΦ0^J#FacȽG#k ž/B2!"hu\ɕ6e;g6Tl+$9JZ% Ie3RH#Ҧy )[z "gՔ2;kD2yBېᳰȞمM967! K]$x11[n(bp:r1('4d H9K}0!BdZgvB1FR#TN@aR( F>iԦY+mOdЊy6 kt ?^j=''d(Ն v}$B+M Et>Bu%ћ(e4 + G#E +[+lϱ!W|0DbJmeFFF%I ɟ/O!,9ϔ1rjCm [ή"iiD69EmHUdeHꣻ5B1e2  61Q=skid F&Ihf 4!CdO5sDFTڶԶFJ2I6)岹RR~Z񅄤5cd"k]5A䅟Ee6?nDȝ56d_ӈY4VMHՃd9@>9GAõ.Gytx4>Q r]\ӊ!HՎę2r[Dɢf2p %9iA v҆$Lkt-52DŚY)6"Wj#Ԅ]uq4"B1]Tahy:%c@Q(uyt>U ]BVDJەRɀ꤂2Hv-TJT|Yۑ#k"RbX#Byg̦'`'oD0{nCl? #d{RaC>>A9+6">ޣ@11H8]m huI1‘tD8a쏐XD#IJL*'_PIωotk#k 1|*){.Ú Dr]f'6"|r 9Sd_i\mO[Hi}(4V JGcqT-U@؇ Bd^giHk Ie: ^D&YI2Ѝ,D>YWǃ: kt5 s\#t٫k55؆|EmH sNDȠƦEq$ + lGcڨi|H:BQv yr FrF  IJLNPIot+#)Fb D>MZj oN$=#f5evY99/!(oPs6dTdӜ^= "dRc{  +򣈏 3KQ:ycTac 2FrTQR()TNB(#%IeD}$"]n7"ը]]{r(ި5؆OCB򦏺LY{4+kx/ʯJcF5)GQ'u|>BTm yB.iEz"A iY1 NFP^d'%B)c$6#ȧX"U'ҥYMXf`TrTcn4> !{53mH9ɦ"W}: F5)HlAGGWzhQXqdex4<[ ; '!ׅV+2"2XJcdHQl$UJV&*P6d'ERn#kD>| l":2[-WaT.4{24ڐj]lù )cs@> $c OG1}K  O+Bn"/#FBRgIϤvpR]Q$!H +#1FB=5#˼Sdx7?")]J*ȵ2ejKٸcl9G}Tn965!I3fSso٧1V7j`P^>Q-4i 4ʁ,2QtGmǢccG=6@. alTQglB)fR(Hj,1+m^ Rk(D;Qev]o4"jv&]9+}Qv0d2Il\4ԅ4c3%ӌFV %>*Ɗc,&@rH##瑌L4P<..J$9H~SMDb HjTm}«uTb=sJBf>+5ᳬUw!ݘ|)ѽplt8K| j省<j'nIHz*'{NZ%C} Yb$bD;mrf5i|#qngnjdQdUd隐@RdzYQ6JMx<|0@|&9ߊ!2NLJJ&[N6*oA20HYi"kqM 4f5QՈCfG]BQv\#ȩZW㯩Wf_i6z 6@'!7 DJ;*H2VɀIpʈIPb#VDX%R<釃9Y)ii\6"fO>'+$'FFoCEO#W}L1c5 u +~n]Q6*GU||+y\!Cd#C#)HHz%F孕HbFBԕ /iM f5b%Rٮߪ90l>3jCuq(aRiUޅp&*GǣQx +\GQǦ¾ @H$܎&c'PFLI0UdȟD>Bd0e)H$j0z ,dϲeAM܆E6,C9 ]QRYeͧز¶z'hlp:<HnAni Hg!^IddTyk%5H#VDE~ZC$]1]fٴcffͅt'eKٲ wy ːrNGH|"$TرGZ/ۨp:<>2k>=@Z\_g٪s#u JLZ'(#&AId`+eڶ!~̬M7"g "TH0.ޭx7-d2qR!$l9)7 8|JM@i}OpLhDC)T^{y\_g&*mH$C$%I gH#MJ,kĴr&ը2fFdsTlNzݧ2~B6Cl9ې܆Tl(ݜF}rc)vgؙG:uLy;yB@L3@ɘIr2 !D24+ȩB$Nkpqv"Ś`V)F5avTH_9w0]2eA lC6$vE6iē>BbrҔ!͔ +{{h1Hc111 <&DB"##Ol 1IGb!/խH׉|,6nf5jr#RjaUBdseC[FM0 YېqsB* _dsxLb#uq'"FDcd@ɘIu ID21R9kHjE:[D5ͦFx|nf7" {0ݝrGߨg+ܠF!}MoV]H!erZJž>~Hc1Hc FMlKd֌0r@ɘIr.P[IcH݊T!v"iVclfF$j,D6.f ֝C9ʆiP#ې,F mMڃ@<&7c66! =>&BC$2{HCR+iN@4J#%O@+R4ֳQfiv(0; }Xw_%q} +B;BEHن l1 #hBN{>f<;@>;OH~.^:T BHCB6$"[FH[cԂ,R66p:v} }ibdTj=H:% NN&HR?c'ii6VƺO2.![B^ouHRCeeàFɦIڅr;|11l< WٳDvȦIdId2H"H`C)lhD +!ݺ_\+]z!o ^N:YՆ4e:BJlє +||u11ӱg[+J!8)2RUڂHYgs;mDθZH2^&!Y9˞^iC([Y@ +[رH:<> gD.d%`2BRI6WDk,;VXMY VRB׽]߇DH}^B>NjVET RHcVoEy'ytGE!b%8%#!Q?E ATH". dPQ$A " +jhӱj5UժZUw~{s}]e8F:xler5D60Rd,'JHL67g&rDc6j'7DxnT2C0 +fL>q~k} dH ydy>"<HG9+ Er2"KmdH $%0Ccd9D&2`@ȧqDȇ75}Vw\ +J OȇCB2qD(ԤBHXa#DǼy̧"V@ !D*EFLS$d%IHdb/LC6?c;@HX9#cxGdlcI +L m"ri"38O'fky;Å < yBd/!? ҽ€!SrO/k!@|8WtxGǫiHH$EJfn#"&q$fB!cQxRɌD,픬12rl( +!aL?[!+ K^[k{Yv $2+"#dN!NMwg!B&7/f/Ԅ5k! |GLG5k|L@^HJ*1)@eC$D1[AHW„\^aX^j "YJVHċ6B +N#!S,[uR3\qB,\t<;z8HEZB![h!5|MG9|@Ed# $ %#I&2," lgDJMt5Yva|۳lMY!5D!W ? pulLl uL,QcqtlģrV"m,SRT $s6l""2>C\FBW$øI Y<>J#zC$<>>ީy3oMkH0d-$h 1<Σ#c7/lg$d,Q$ȈH5X+zU~^a '5Oyb􀬝;{.eϳߺlsf`CPe&AW!_'6"ף|< @"2gd;${#S# 0"Nj绔fOf퐨D 5 fl9bG5+ l +HlD<2|T#RF2 Yk%{ #"&2셐o(ҿ >R0rcC fSC$[-fC"Bޜr2d}cMx6Fd'#d$1#"M$O7cBzNHpهYC +f+J0xlIbv"_k|{"ddHãK-d%u,6UB.nwSϨyɘ}tȯV}xCg9FȢG)f߽)%dv!B:e;є!2o s>,xler"d #4~RM".CBTf.H0,7Hw2KȚ!RcARM1CJ5#bv$1;I5!2!!B8Z Rdٜ-IQjh:d5!܊*) YoOlD$f̆b@1F$Ԕ[HH%) H],2 Rh""2JoBM"n Y9r*I> !lQ@j1" ռ}2-$d*4&!r}HIIH7fcB-֐*!ACMB͹0ŌsHzU#]D욘 ٤QOG xրF dl lPSZC!5_D.jh8PSI죲 RM +fYDl5!鐝>n6>9 Yfڐd)6̘ \I5d6dgg2C~/Dm)ԬNM٥EdYDbB!GHYұ+SMf I}+Ygd,|M3͐>Mn{א}5; 5+H5}iM_nB00c@8d-xNjd;"H )5`!(jR/UF\D4Ecv-ߧ:fvyNRMFHYxI@ +T30fW !qiYl듎kyB.Ԉ ."eO>fj6CQ} u|UV`8$ˈ,6QRvXC>Z%냔և`5*k5I5E$3xPczƦq!mQl| ǍxyB +T1i"B֐(-̐GH.ŕC!;*!9싚#\=RZl&l4F՘]"dlad+$K40d;F<^vqqΒϤlL~q 9o2">if2fSFAAy+f1d +>ᱏ +ND*I&R$drCx noox+CvӸj&rTSpD^~Jи+["]|+ Zr +cbxο!Hi"!R9dCFLgaxËK_2Ov=c P"E$!jvaxi5OjnbLo׎ZBQol//݈0 "˄,!c|6C7lXpP#$eG y88OE$l!ᵚ'1Z/B?-fGx6fEd"lxp>feF +!-Ņ|xӀB#O-$ɖl9!!`kc6zh䴚 ?ocbt1E@౟WT1Ron")!CvvZ|Ȧٹ?s^rB !c Q]CVא=lXDr~lj/G 廚yH$j1["d~\ >jh&#MDHYa!A )Z}=ϑ{Ӱ ,J6;dcuק<!Nߛ}cvld,k5-Dfl!e@+!Ddd FBBsOfȇfBېz}֐5eFw~ݘ-= +.%RIRo $1;'$B6O5WIYI Pɬ>AZH$Y}= P3d l6d-s5E~^"K$jb|E!DD;x9,4EBVu lO rHhid3А}5zHS^"Ƞw5l"}sWDcvu@W}Yk"!!kCvn![t!Kvq:dw{}KH"}7lw\]D>jz]m"O&\Wڮ5,![` ѹ-d{ƄV:M2Cldkȍ a}1;Kd] ?H&-k" Yqڃ&aȮoTj!I6=4;ًҥK7ِ}{]]CK-7Zg+&MkzHv.ymFB!o!sj )Z}= i|V^D*l|VCM`( VjqvKkaͤ&2#d\WKH-d 4'B2['X}{ӄ{ܝߡ6Dl] i|ܤVfd!4]-oPᜆo!x8v:͗4U3dÐcv6;jdOKI闯FqMHfVrU>cժ,!'dS {!Q "VpO4B0d{ Y&SVaRj] wDf5ytvk&4Bٵ"#' >b.d q-R/4l8d>{!}J%j5&;7:D$dM4"4>P Td}Q)B9 ZHӰ:M} cc`$B@r\gH6Ί5pΞDVH=!ZH!疢LG\B Ym!'W`CvY>SBl6;Ż8m"a ^"~H6> KŜD{3 "Մi! 3-B}ZHjinow!dߧ2fWoii"ɫ:{ɉtak@xM&Ǖk FM$&X d4ceq0ԧxN÷!:Z}fMvmV!'r1Z?M(ƫ)h#M4>^ tTen4L>1ZBf/snp-X}83do o9dO#ckeykol![@ +HCv"R7fcK3ZM5_cHMd2w3V9Ck1f뵚k \ ͙"svgbMg9{SkBL{X!5MMNBPBur51!DkdS$g|5Ƚ s5 kc3vBk\)h!I6ijuԚZM1H7k"'2]gKS˚)ٿ:gE9{j +![Loqv4XHF=-$Tu y!7C6.55S$7gsHi|ܧ& 윱\/%υdi@ I>ЊM!~HdŚtY#"s>[?g MTB͕KU;cu췪ٌX!'M>\R9=0fi5Z8j"AďS#1h򜭰lfŚ1[ RB6Rw]i n!Yfh>!5^D&mXL9;I|Z#gKsvU)7j>!gl}33 +)8}N0ԧZ}tvll"uv9c8k)2gg姲옳uMrǚEHB*d%$3ϠW:c32CLE6U-$ӌ!#V3Þ^q/059;ټo\YEbiܳl!g}󯅗Z!%: Ʌ,\dl-iΖHDx&PSdiNq姼Ė圭j"{B-$/cgF%d:v6cS+idӽ!g.[[1Iޫii"CNH?eMuqV~AZEҜJ7L.frT,!2g 5U Wfm"V 9Bf%۝ѧ8cg>i$xK uCU >=dŚpYL0ӳAcQ" Z"m"W!glJK0W\ij2 yv-,OkМrȻ^*h?*h756g^S@r2v- ub'dXB~ZBc+4cSsBM{&$h씃ƜTW:QfAiܺ[Hذ&4wɄ,-!kgDq\ȣZM/dY9;q5t8ݪk ëȽyry5 +ȿ^_.&V%.!3[Bc%W{ŹX!L#VDCN]{ZSYEHN 5$qA{*ro\\R^BN86dT(c J gWweglk!8d j"lGS$4R~Ulj6GЖokDDZi5rsdJ;,!AO~L+9}idȞD'n"+b8g'߸A|X}鞭iUk}3]Cж9{m!U.!חr2B>B6b 1Ej'"#"s㸨ְ{ Fj/@Αy&>L#8!Doq1lhaW"9qv*ro\PK}elAᖐ.! آLC>[ aI՜,?)GpE^Ih/ڼ- rmM.5e2Wi.gf2v $$I* s2ӨgLs-jM,0svZ~JH)5@о# .5!rjde ޥ49v\B~Q,}J369jDiׇpaɪ51 ̜E.h˨4z@je.M] ;6KH:c,~r~9~jsv7-?U$yWk-"9ޤ֔5DNA@K~OޥgN%g%dvL# +Yio!65s}w*<W-F7z~:m#Bi2磽Ndž|j 0c3N3l!Wj" H7[EbW$̊q&7jϏ gV}-> 2F KHmX0glm wBn"E&3ErshA,mAE*NSelwlXWiAt }>$[̳"Z# =?&h&Ui}>PqN&g*qB IY}n-&29~X"Y=pZUd|5|~( ڥ=? ݵ6 g|ZdgaL4WWE- +M,Ȼd5)"q5&[;흪+|׋oc2vL<4` 9 ,!ѧiΨ7EǏNϮZ~HE267W *Px]]QIVq0Md3vLs-hYyFd\E&&hg|>W$c󑐲JYsli:g~n\llѭ"}V$kg՚Gk" '|Tq)T?" +&Z5K.l"bM˜]_E85YU7x~2DPU>*5*ʀ$KH`2cA D2sB=)"5q څ"j[}>:(DՌiB +lvl#"8NVy~ZX>Wf JZ_%$2dZMd˜-[~j`Z +9B,fx~ ]9*kL.4*/!{l2c74k!Wj"9%!A;^hbE3m/Sk@nSCC+2vIY7H3{{ggBNksvfi]EF8Tkp,h\,Ϗ!@u(@6| +UU^F3[Ȇ&wΎyEˏ'ɂv9nUYfwBD2s6*KsAFWC,s~sZ|P񊌍niJ*Mc_B Df1h9Z~UdMnk!K[s>U'wwqLJTb&v ?cA 9Drs6,?*&5E!c4ѫe/}|P񪌭Ui9b y3Ȯ9$t~.'!ĂL1D,#ü*T2wi*M ).!13!9K)1$h  azy~βZχR.ķkl"c3IV%EطRrʜ-?*L]zC{;Ϗ!Hu(@")|>Wkl cDZYfh ϴ=gsyUdZ# (r*CmUA[B3F |wr3 +'26:6Lgx8ѧc>l.=?\m9^cܥ&rb[.O(ذxֱ1cMdyΖVCj,hqb)E}_a@!g|P\$ccäٱ +3HŜݼ,51 M%h!C7ʞEÆs}>1,ccC) YA&d}.j>s6>$deOh3燌] =?^l-}}>|} ?KUcx.ccCqJ-!Ќ}*{FCNЮXpd>I26ViB=,+5]Wg6dהs~^]X!P*|L=Ũ44 9s1gWRkZsɁgʇ }>m;SiiC29g֮"jMYl*h !#{4 ]'hyZuKH [HM9oY4gjMMڵ SzˢάEYa~O;* |KTÄT"ujZړg5Ϳ(K\-le|E.d*͚Kc.ȫH`5UA3X$7-2vJSYB^F 9T"KjJC,=?7vA@$|w>m&[ҔBnԪ5JA΄XT=?m=?-rgÆlY6vP\Tsf١T?lj|ТY=י3s4AV%اk"ȢZ ,"ᅭCE]-/73aһ]χUocelJ3q yxBT5md] +ϏEa\ <|>dq*M"3TZE65%A;" +(Ģ|Т\{O#dR\d;ǾT-l\ER$u YE}ТΡg-]GhQiΝ+"j L9=? '0B;j|>_Wq2sJs-Ȝ?[Tk6X@ϏDڢЎWAg߂eOW1"cJJA8s[v=Ă[c(cQhgV}4|r]RigE٫Is9 |:e%䥵}svZ*hz~>hQhW!ϴ|>:[Tk"Á=?GՖ g[4gGi&|r~:?(V xV}|)_cdlxFT%䥴Z{*h'I=?çIգL)d=6|j*~3nwή56b(K@;ٲRGP؅ci*Yrs b*xAy3yPW1Wƾ%+!qZSB,*o{M{ТvxV|O*^K*UYB.D՚Hm/(?0 <6ȯF&T4F٧p]CGzТΣ9s L<@+3OƾKHW +Bn!h !, +moͮ#rvaY>Vƞ\ތ}*M٭hbgAOCB;j~eNY{Js愜t EUϘ : <#>'!c_%) OC> +- +56d*>gU7B}>:jrfuYDGYr m >SiZKCU ԚaO)QhǢV?d x%@|>U |F#hOW_ZZgzNO}%UPDv5x~, +rȝ^<+=lXǐDAsGEgOAFHÆc2vki[E=4g8Drv6ȳ<{fkI|Tq2՜O5mB{1vCuCo{i?(3+|s59 x~>ylUXW <;/!]I +ڃ2ϏEͮA@$g#SUgÆJS/ !m>Ģ(W Dg=3Bf +rCB;:" ug/t|>]Ok^BwLi|4?(V xygÆ,ۥ>*n*PDfsj- +y(@v3laJ+hϏE&Pg="a-|>}*rA[b!5vF 5@y~v3(4UUQj3ÆG\{6D2ϏȲǢΞ[raD6XJ^ED3Ov^lϴN <޻s4Ri9$hRϰGx=l83%@3Ry~VB{Eͬg3}>&c׫ G$B۽*yF.|LaK~p(UE)64ʥBNCKurCʁg<Wq)<hQhg]y-ng ri9s;(h7<<(ցz6xTM r-YD՞?4D: e@JSyQh/(: + /6|>"7l ?xfvQD +z1is*y5sjk"|9Zڛ"ig>@J>Dy~2 +* -a[O<3@Klg"%Jg?lhkg&<v՟?l<U#"g"- + -|>$D{~, +=?9W <3@N-"{~VG{~) +mm@Z!QmMEYs}>ro4L~ЌV"9E]oQhʁg/o <{Yg2Mr*QhnQh  5ˈB{" +͞? H <xf>U3=?vlmxf*ZvQh3Ty(o(cr3A]-/hrXyQhiQh[,좪3mGBcWv0@Z$D3 +- +Px#gg٭T9JZQh#r3@Z|YmMDaϏErݗ_ xf\wBz]9(Ɉdyg3ݣоKBN@^Pٗ_PiQh7_lڪel)iV}>YyV#"gz~&Gq=-3 KFDδEE9p"C 7I"*"|6F- %>/Zr>QhC!DQ#䤗_-lov\R!rjF5s Սxfܸښ͢>Qh7Aϡ^ȝ3igV+V"u]2% +Qh0B^lmF×_aD^Rd[9ӌgÆ UCBڏ/NEN@!_~]5LϮN5"ṛ:_uOf$s@ne# ^+ L^#9 + /* +Fck"- +jt\32 kjgV[ +z9DH5 W3BQg!g#YuU[fiB{0E>j(-r ,DNd9W=xfn!F=BEL\_ }Y %63y)Qh"3D32G9;Wx&!-̪笢Fl!r[@j_~gF.!-jJ5"r-r(ְENpE {/igV$D^nZ-9Bd?#);xfD*sBmp3 U4-#`c-j5D5by[*lb$j|$zm/ϾϬ&"B'.vrS<!_~3JVAB"khsDHFus5#d)N-/Z^5F}UBl|D"sk +HSs덐_Kg -jjDd-RLB{!<=H#zk@"s;xfuAJQh-2Bms|DRF!IY7Bjg¥Bn QhcHs|"  }-@j"sׯ䌐;V[9) +gE5[Ea"62g$$weQ@j[!-jCBЖLB+ELY"L@`d>Ϭ)yÈlxv( H9>\H9Ň!_~>Ϭ֫!D? +m-9^8ƈ3'mH5#U$ˀDְeT +i> $E"_ /;C.B#|W +҇U@i) /G*_~5ZD_U">4 5ى6AdWEH clSxf_MBQhMH!-/sFBgw&lN ;:_ h_~3JH"(4 U[d[/h!Rd$d;+ dclSϯ=0Bҗ_-jjk"}! Z3AҦvFrK4Hf IRxU<Y_}EU^"|\N;k#|gG@"oŀgNqYV∰ +"{YBS"G=?)Y;E> dcl)yFH5jgVkBE&VR,x_FY;k|H) [7B^~H <ڸY/ +MBl |n9^?Bd %瑏||XS]Q#Y&!r^]_}(pȲsv\ӂllyϬ&RiB^mJ/LM8"9#+ [ɜNqW <ڶ#"gG5"G8/\SBH16 +2=U;\&#d˯xfA5FdC7EUllm>P%Fğ|VUN@9E#d˯xfG !r(9אC"#P҆vROGHS5]FH{җ_5>ۙjB5"R< +qe]?62cdJ>"@z;dVQ5E##YV@(4 *[-:5""ߒ!]d5]fdK Հ,Nq.2w3#YPNXɤER8? )0 @'Fʌ(>f2  N&#d˯xfjLBSeqM"3o# #1$(ee@Dq )kϬV& Qh.[$vWk af閑\32d`.|8@iE@Lq)N!G^~3]-_)"%8=% hH  J@26H)>+j>+}5E^l#ڬs\u\SFd~[B$m$ɜ y> ̀Ni8.Fg&c[- +-EQh +[7 [\3H8i6HN5a6#7B>ҀLqb|tiF#YZ 1Ȇ(*Fil0-sw({MHIH@J#ǜdV5@|4ldR|֪!Dn6`drM"IH +IE>fl@>ҝpNE#d˯ZFsuD#[XDf &7hf|U@o )?#Vvτ(4)#4=,Opd )#Gf&.否ְpJ:śxfuGd燏BKKE:"c.SDrm&7>[5,U[CxJ9iuaBdg(rqx\|]B$w^#O<#=$%Lc#G@26A6@[Cr^~:@5m Qhj[d9k!>іBuo2,0BXcY&G o +N݌xf5VC`Z- ;nGd 6HISGG@ h( _'% 1689F /Z*%Dv/6"s=#,5D$$_{>r+ YB򀄷) m4BW#UFD)EX,<Ⱥ H"%#n e&clxko1BZjD;uЈ-W"24\߮d\ !( I~'%> ;j4P("s%#YEMB>"[$t5D;XlvDJmILI @ +q>P>AFϟa4ޥB %[$"*F$?u|, # _*HVo Nr_c5ښIha8NA??D&9#a)0AQ"dhO> $hOAV *)8ŏa4۪&!r3ddh35Hvpco aIHIw#o2NA"vѦhCDe$aI !(I ~H҄E_5#q<52!W×D"3p\NQE!~22k#!#H2|GGGDŽǜ\ &l|I0cK4)2 -j5DjM x\hDA?)9"2OpԦ ĿC~&l,bC w&cS)u@~TϬ6.q Ynx!6"qmbA"i"H!Ȭ (I0k -* a8~T) WsFDQ"sgp"a^+rDI&H8j{FHzJFL2[FiRȧKn )  H{LkDjȒsgpX65^'mFr ?vtLx5xB0c[CtJ9ҌVg\-RpxN""Y:t҆m$H@ɄIT1#?ac4HSVl0BꐥB-t\OYD>#2PFl#1#1$=%#&*!<">d@ ; ! z+Af*!9!N#!c5\mMQh5ى6 #xe$@Ss211ؤ _AFk|D0R3@fF?dlCn̎kDBȸ\&(Q12d$?t x #m V?*ܭ>S|#|V)qFd -Hp\sD>qYn;,#AYbdddb%>>5pb+Ux@[jp"|v!Dvx~"!2:ǹCw ~|\ `~A!##$=%&'3:|_"ti@c씦)nFHFD`qM+"HH:Hf?ttxD|o ㄍ4鐦ș +#|_Q"9D~Z~\vӂ\NemdFQ;g$$W1&l)G aLfR!r OYԽOek!L@ OK~ &mF&F];AS2`2Qj ӄV!M ɭ!:3iuIDgD _ӀI$lN #$=%&' !Q(7q+H"b Q0·=ƀęmFH <:Coq/&规g$67i62ڐo$>t<#i VDf@cl|k2%l__glxS,"Lj|ȥL6j$HzJ&NzT_ + $YACߝUCFH{5Ȯ(-9É6 +  %m H (8y CG2S5lL"63Dq>[qk7B˯VǯFD{~ZmC6ERDF~bA$ g$h#2CQ2`DGGG\Hf5wQ<e@cai/Z_mH-@[0Xt!22hڨL HIOIʛ #6H0a$ RHC* cu5 +"kqtR,|ЏB?XF$ZFf6F&FbH&JBP +{:"_Vՙ_aD/v" )'dD&E:E$]FFM;Ȝ{SI&츂d>1䝡P=i_Ck9ӆ~@dvFugdO$%( KGk cYt6H Hxk33FDfus?lA1" Ȥi{&6 $@LjGG6h W'\>R!WsɽnT:QZ "aFzU;#$#%&#(I+1~Qgj4#Յ +EA{-rD%DI; +6qFȸd!(981^|H8ao# 1Lm+FH <:L#rYu+uD~GB俓qmd#f  %&#(~| D*J|d@FHX4Bl/|dDw&D~1Ȥi6r:16'H.t d}k8`hV O&,,d)NcOc j"wEVkH\dGڹ3m#YFbHbJNr<:<:qY@4) @~/wȀռS\~ϬέCr "?4FQK6K# I)9z%> d4A2.H0=IN[j"q2QSDe$I #C# )Aɖc>">dC 5좈GY 2Oc<+"Uq"4"k#"]DIArJ灎nǜndd\ W 9Mƶ:LMBdAV"t\h'6i#è 0m (09ɕu#o| n h] )!, @)M!2׌V]*D)"gy 3i6H @Iʼ'::<1pI'l'}-R4}FH{a]y1!FzD6m#Mm7nGJ.}딎E>2C 9@fҌVG>Dvx~qM#"-HNa ydd%-k=!}8`R V$xJb__# a:Hc#Nڠ6`dl$!$#%LFPzmd ': K2@ҭ/!-ܪs\g_Ik!cIFmHpވH4a>_W$HeSzd!κE*qh@$y;%miFmHHJ&LTB08"::< $8a>G|ȐcNiiu5 }qM"!FHrEm0j{FADɄIWXl#_ RDIi@Pr㤯E_(ᑶi dy 4Y`aS^~:jk"WEJ +endstream endobj 325 0 obj <>stream +5\E|WD4i&p|bd%&'rёqk Gd4o()!HOsE$N(5MH4i&~BS2b2 1/b$ р $w[v^~:Z-G'8d "I!.H?j#F>0C2Pr$@%_k8_4Av'lZ@=Nq{kH9."8 M~З2ih"`~ƌ (9 Y xc5<:9ikT >.@J4!ξ9C"?E$@$FQ;H6^A\0Ah~ +Gǰ{\G҄iS)nFH -YpC&Eʩ_kc$Q#EHJ.Ǹ|"2<H0aD݀n %!.T, +mH/Yz$"R6ҏFHzJ.\8P| q#n S4@ $ G HS8ɜfjk"{"k2"F6R4i6 #>9#H(@DNYHG8` d ^~K]Fd3M?YD$'odP #EH(`rdB%-h| + j $n K9 ˷FH <:Z @]z\HlmdDȟ!L\0AQ ƈ qk4`L@2v("5,;iui5Ȣلȏ(!yG[rp6i# ~)H7B0}cr#GǰLWظd'lɧUgt4H˫FDy~tHNSLDq#$=%O Lrx㉎i|Ǡ`/@[id唦)n2&d; +DIjGƯ##12dIJOJ\"#<1 Pv=fR!D6B$62)6~)BSq2ң򅐋 pǰ + 6 HМVWښQ[dID$3imd #@Q2`҃ғ2221ţ3>l $6H ckiFHmy; #I; 6_GF>1Ar$%'(=)qFG^I6@r'^GVn [f:]Fd-xHS,XDJ "H0i6ڔ<$=%Ott uC"FGGGe^qF $h +tHC81cְ)nFH3 ԥ)D/ xm$ #0C2Qr@@+qkL6n ]XAUBdYu I 2Lڤ #9$=%O\8@POpttd(1 d&lib!.A]H.H6Ț6u#de>QIOEƅ'8F:rx| 1CH2a+H ,PHμC$ukODރCd&i&mFQ2rG2t$@JZώh<GGGG> +|\l@vѐ5i>/"qM"? K2l@ET# '(*S4`5:<:>>1, Ӏ„MDlUHp)|ΨښșQD%m0im$Pl:3K')yd'ee<!)84``A"6{@*eAQx/#MHp-0?I#s<.E| H`!H0a$AVE Ŵ +3BZ]D$Y E$tH(ؠ6^ \$%&(,=#Op txS뜏 +4pF+HS)n2LD +qPBKȏs#^'L'6Aզ\l`#!(yIJGJZ#kpttx |ǰL6j Y  SlȻHX]rm^nm$Pl:2raCSIʀP? ~HlSA%0ayq>SeW#"ma& "פedq ?9#mIGIIOʬGe1NA $7a3y⫆ SX]Tm6!|s'miHH?lHJ0 @Y鞍 ̢_'>k ÄѐK ;Ȁ4+"lqM3"?&Cd&ig mdTsFaAri%O\8 @tK h<G@GG'd| + @ 4Ί yg3OicuDN8C5 "ѴQ$\$%&N:PzT?~`cGq1$v~Gi)YSXoa8?@$<&6uFbz#Ѩt&$ S#~caIh;ȏi5)n:DdEkLihINɤ.l62"#$#H:JzLFN. ~TIO ӥ!]뀬c*m"D]q$iSg$AG휑˰ɥLltp tx5G<`g $ +|( ?| cuht{}Cd~^$mi?aNt!v$dʀJX琍'8::.#cX? +|< شt +|!jTl *DRI-# .lMPdmɥt Lt6:8::R~s#@$| \>'>H3BZ]jk"k>~ P&m$YFaA2Rc2rre@%,s){b$aMiI\>KU]i>3.U"3cdk3jکLH0j{&02,$ $%&#'=)-/ݧ~&||(i& $L+H^N 1VSH,ie$ԴIFm )192Optx5cX@40ɇ E?1@Z]D9 )~^@f0juF.e& Lr6:8::zV"2dI^ i#èבtv $#%=&#'PFV?~` KH>a@$8ac Y@Q$Nn VWwAdzGxǩifH2jgvj$=$#%&#'=)r6:8::.ccl?/ À=d&lV..@9@kED'BFdedt3m$YFa6K'y\@Yq'8R:<y>#@v\A.H)KHZI"wed6~,$A#y t \8ң2/!`<&6tF+\F.Hz!|݁H׈vl#Q;0<#9j$$%&'PFV<,FGGǥykbOdDlՌ|'mFQ3򁑑~ I(y$'//xb##Ǹ~\Ǹt@Cl2aie5H"i8iKm$qd! (,A?$FG@Ly>;o ͬ +ʪG6Fud`,w6y#!(1IOʇD^_~MD㉍4Kȶ Bɯ M. uS++F OH\ (yT_xbc& YY9f JKȕ)5¤aN/f_H\8ґ22U%F@G1 ؠ$8aK+H|i8HiuE-HF5C'mF.6ZGBF>12<##$%Ott|p%=#=)?ӭOo ɄVD. gZHY:DJMMh h#Ө18F~Z`$D&'=)#,So6z8F:x ||cZ@;l C)MiY:1@ZYv/g$`4j/Hc IOIɅ (*#//p|\l6uA.ՌZ^BdA'mvDtĘ\8 @Y +|xb#ch#1?խ)r>aK>qXH>ǂ vj#6ҏ~I D6^ @"6q0o %Zd$m$vF&H6#F2$=%&NPFV +E46X#Gv@F^Al+iuɵ"KH"6@AHHIVar#%¥b"ƅ*>K4 +RZH+Z:BI߮aP),#6 #FBDIɅYO#Ol ptt\v1?/ c** $4@ZYͯ}-#6_jQ[H +0of2qҁґP1qAFy`DFkt\G>J| 8`GdiVP24*{."edmdT4q^ aގ\8 @P xbcch3fG4vUYFHS^'mF#c#I %Ot4.l<1qf}J6 "bkiNq+BHF.LQ +#q#CS2br'e%ѧ&46x|N|'4+6h VV+V&MHV279$%#&'(*/Hk>#c$@'ie_;#2kmHHRH"J.\8@IYU~ Optxc\?r|5 ieJmHDgpmda&HRHRJ.ttTdth\x'xuf4 +LD22lbCHHRH~'G%&ɧ2:6t G?^6P&삈mR͈;ZDI:igm$Kd1$1%!')#+dFƅ'8B:x5G0`g j dc/!{HqN6#II &'(#*,SŏWxc'$::<&s 4D&삈muXFH؀u$`dl]I@ʀJK35ƅ'8&: +xL9k [^A fצ'mviƐIʈJW>)qcF }5G8`#DXA*/F"6`#pԦvH2ĔtLD?ĄGOG22_A ֭5IdfImɌB} cc㉎y:BSm d1@ZY8"Hff0j t *~šqaG;11LiG4`#&4DMؼie5v@dFm$ 6IJ7utLͣcSHB6҄6@ZYu"u6?im$:21rGa$IɄJKDFF@<:J>"6]YA fժln#]gdh$HBJbL:NBVdůHG8]:π. 0a5ՄZ^6XGRFa;4 $!%1&(,Js116BX#PR9a ֭ivifH0ju$fd$$$d%%-𥏍l\H>~ox-(@al¦+ȪieS6`12 <$}+)08A2"@cbGH(ͤa((Yh Ʉ VV}"md 8li@wy x7FGH8['<#>Ḧ́=FH++R),#I[udHdj&'=(CݍAblp tȍ,[h VVʈ&]e$A+ 0 9I +0zbccY<*@ &&mEYa$ɼt ?hp t#N>2x| ieIFdq#i#AhF@G<&n mi)DHnҖ4jWHHVbs22RŏlLp tG4^@vj4H+H~l  ) 09@ YVއ6&8B:xL#Gn +Men^A :k-D6h02H"JLzNP"VrO)1E>]A k 2R 6ZG"FadFIIJJ +Xc6^m6@ZY[]i#m0mHV2Qas2lL##c6^s|RL +ieR 㽈HfmH>6";`#A l/ H(1 |o VH++}!R5i6R$$$n%%=&='#(1+J_‘Q#h?1H56Rd$3$$n%%=& ' +J_‘Q#|5'lU["Gmd![IGIIIJHXc7aOH+k6"md#ĭ$$aeo#cG},q4@ZYmV ,Or)mĭ$$aeo#cc}l@ vҿT&mv.0R I@IIIJMw?‘1#Xl Uj~MGd22k$sHRJbLN"Tr$GBGG}1GHՋHH4ld)0@ QВRßg:>6ʪZ9F026"$%&#'!) +$`1yxcXi VV[DDVH$dmEJFNBR"Tunjutdf>5H+k"md+#q#BQa2r2Tѳё4x. U7LHnnd IoGG2u|h VV[ׄ6Hi2RDɀIDJ1#L>26$%&#'(9X +\h lpXL>OH+I&"vI*Y8z:H>6H+ 5|#Yddd$&eo LGG>@ +j*#mdq.32H:H20@Y%Q68":V>67H+ k +"6HJFLBPr +}=)"cWj VV zF6bd3$ %#&' )+8b:2x,m|@ W_6RHU# I(18@)fl ptL}T񱽁4@ZYm_l댬AP2$K5<20'lJ5MD${q( 9\7##G>jXHj5iD$$d$$K;LGGn@UOFYyHJ2XY"fccm|i mieg !RFYdFI9)~m%8:6q@ZYZ9H~!)S2aB٘HGc|k VVW†6JHFJLBN Ny$x$#@ 6ymd #)$C@IIIÑґQhgieul#g1Rd$$#kxlL@3VVWj# B2$B{f|4@ZYmYldH! ( 0I@f%] 93G"grw+;q|,O@ȅF~ɅJC[u.O@KX{@$g cɣ> n\NNsOW>O@ Y|oDa鐼ɫɛ\\RwQ᜞ȵHJ'.kyGy-W+y+*yW^K} /i UH^L.rG\pz둼QɅN>֟w7p^HެSCyḳ>OhHުL~Fp>#'6f$2˵r{?|G8g4f$Tr1q K?)?{N#oɣ>©x{*x$W3̽?toԟ"Yv#ܟɏU=;lf%?`H8MJv%?%+毾Q#L7 YBGm\F.WX+'0Bdgo&ec?aGf&+L~nX@#W#\ןPy;"?X>#fCc<O8G3~ּy6;"7O/[,ߪ5zs.9/ӪN犯0ҾSgP38:hU?Mt=KQήܣ Qn[U?'`~[Wg:ߨ2j#ptp6lQFMD>~_?ٯÿ?_o߿_/׿Ͽۿ_?o~?.ۿ_~k?/~g_?VO?????Wz_ o?_~~_#9;uˋq<uK>|i 8/Rj(phSQW 5 /~qP_p |Ā_k9ί~wRnCկ>>3W}&ߨW_u(6ԑ[XRO`:0KxOPάyi9 ]=˫3^Z$'g8:fYNN|z`SW+p6uuNr};Գ UvgP&0T?ءM`:~L`:L`:L`:L`:L`:L`:L`:L`:L`:L`:^Kg3GWO% S fp3ptT8z*]=nfJ73GWO% S fp3ptT8z*]=nfJ73GWO% ; pQnG!T$ECI:pS=uz$.MH\9s7# pQnG!T$ECI:pS=uz$.MH\9s7# pQnG!T$ECI:pS=uz$.MH\9s7# pQnG!T$ECI:pS=uz$.MH\9s7# pQnG!T$ECI:pS=uz$.MH\9s7# pQnG!T$ECI:pS=uz$.MH\9s7# pQnG!T$ECI:pS=uz$.MH\9s7# pQnG!T$ECI:pS=uz$.MH\9{xSwMBI7u z'-{xSwMBI7u z'-{xSwMBI7u z'-{xSwMBI7u z'-{xSwMBI7u z'-{xSwMBI7u z'-{xSwMBI7u z'-{xSwMBI7u z'-{xSwMBI7u z'-{xSw S fp3ptT8z*]=nfJ73GWO% S fp3ptT8z*]=nfJ73GWO% S fp3ptT8z*]=nfJ73GWO% S fp3ptT8z*]=nfJ73GWO% S fp3ptT8z*]=nfJ73GWO% S fp3ptT8z*]=nfJ73GWO% S fp3ptT8z*]=nfJ73GWO% S fp3ptT8z*]=nfJ73GWO% S fp3ptT8z*]=nfJ73GWO% S fp3ptT8z*]=nfJ73GWO% S fp3ptT8z*]=nfJ73GWO% S fp3ptT8z*]=nfJ73GWO% S fp3ptT8z*]=nfJ73GWO% S fp3ptT8z*]=nfJ73GWO%P%0]]AV%0]]AV%0]]AV%0]]AV%0]]AV%0]]AV%0]]AV%0]]AV%0]]AV%0]]AV%0]]AV%0]]AV%0]]AV%0]]AV%0]]AV%0]]AV%0]]AV%0]]AV%0]]AV%0]]AV%0]]AV%0]]AV%0]]AV%0]]AV%0]]AV%0]]AV%0]]AV%0]]AV%0]]AV%0]]AV%0]]AV%0]]AV%0]]AV%0]]AV%0]]AV%0]]AV%0]]AV%0]]AV%0]]AV%0]]AV%0]]AV%0]]AV%0]]AV%0]]AV%0]]AV%0]]AV%0]]AV%0]]AV%0]]AV%0]]AV%0]]AV%0]]AV%0]]AV%0]]AV%0]]AV%0]]AV%0]]AV%0]]AV%0]]AV%0]]AV%0]]AV%0]]AV%0]]AV%0]]AV%0]]AV%0]]AV%0]]AV%0]]AV%0]]AV%0]]AV%0]]AV%0]]AV%0]]AV%0]]AV%0Z@XR&0Z@XR&0Z@XR&0Z@XR&0Z@XR&0Z@XR&0Z@XR&0Z@XR&0Z@XR&0Z@XR&0Z@XR&0Z@XR&0Z@XR&0Z@XR&0Z@XR&0Z@XR&0Z@XR&0Z@XR&0Z@XR&0Z@XR&0Z@XR&0Z@XR&0Z@XR&0Z@XR&0Z@XR&0Z@XR&0Z@XR&0Z@XR&0Z@XR&0Z@XR&0Z@XR&0Z@XR&0Z@XR&0Z@XR&0Z@XR&0Z@XR&0Z@XR&0Z@XR&0Z@XR&0Z@XR&0Z@XR&0Z@XR&0Z@XR&0Z@XR&0Z@XR&0Z@XR&0Z@XR&0Z@XR&0Z@XR&0Z@XR&0Z@XR&0Z@XR&0Z@XR&0Z@XR&0Z@XR&0Z@XR&0Z@XR&0Z@XR&0Z@XR&0Z@XR&0Z@XR&0Z@XR&0Z@XR&0Z@XR&0Z@XR&0Z@XR&0Z@XR&0Z@XR&0Z@XR&0Z@XR&0Z@XR&0Z@XR&0Z@XR&0Z@XR&0Z@XUo&0W?XUo&0W?XUo&0W?XUo&0W?XUo&0W?XUo&0W?XUo&0W?XUo&0W?XUo&0W?XUo&0W?XUo&0W?XUo&0W?XUo&0W?XUo&0W?XUo&0W?XUo&0W?XUo&0W?XUo&0W?XUo&0W?XUo&0W?XUo&0W?XUo&0W?XUo&0W?XUo&0W?XUo&0W?XUo&0W?XUo&0W?XUo&0W?XUo&0W?XUo&0W?XUo&0W?XUo&0W?XUo&0W?XUo&0W?XUo&0W?XUo&0W?XUo&0W?XUo&0W?XUo&0W?XUo&0W?XUo&0W?XUo&0W?XUo&0W?XUo&0W?XUo&0W?XUo&0W?XUo&0W?XUo&0W?XUo&0W?XUo&0W?XUo&0W?XUo&0W?XUo&0W?XUo&0W?XUo&0W?XUo&0W?XUo&0W?XUo&0W?XUo&0W?XUo&0W?XUo&0W?XUo&0W?XUo&0W?XUo&0W?XUo&0W?XUo&0W?XUo&0W?XUo&0W?XUo&0W?XUo&0W?XUo&0W?XUo&0W?XUo&0W?XUo&0W?XUo&0W?XUo&0W?XUo&0W?XUo&0W?XUo&0W?XUo&0W?XUo&0W?XUo&0W?XUo&0W?XUo&0W?XUo&0W?XUo&0W?XUo&0W?XUo&0W?XUo&0W?XUo&0W?XUo&0W?XUo&0W?XUo&0W?XUo&0W?XUo&0W?XUo&0W?XUo&0W?XUo&0W?XUo&0W?XUo&0W?XUo&0W?XUo&0W?XUo&0W?XUo&0W?XUo&0W?XUo&0W?XUo&0W?XUo&0W?XUo&0W?XUo&0W?XUo&0W?XUo&0T?ءM`:~C=Pu`z6lC;Գ UvgP&0T?ءM`:~C=Pu`z6lC;Գ UvgP&0T?ءM`:~C=Pu`z6lC;Գ UvgP&0T?ءM`:~C=Pu`z6lC;Գ UvgP&0T?ءM`:~C=Pu`z6lC LT.S/'0Q]>ا^N`|ODu`z9>r}& LT.S/'0Q]>ا^N`|ODu`z9>r}& LT.S/'0Q]>ا^N`|ODu`z9>r}& LT.S/'0Q]>ا^N`|ODu`z9>r}& LT.S/'0Q]>ا^N`|ODu`z9>r}& LT.S/'0Q]>ا^N`|ODu`z9>r}& LT.S/'0Q]>ا^N`|ODu`z9>r}& LT.S/'0Q]>ا^N`|ODu`z9>r}& LT.S/'0Q]>ا^N`|ODu`z9>r}& LT.S/'0Q]>ا^N`|ODu`z9>r}& LT.S/'0Q]>ا^N`|ODu`z9>r}& LT.S/'0Q]>ا^N`|ODu`z9>r}& LT.S/'0Q]>ا^N`|ODu`z9>r}& LT.S/'0Q]>ا^N`|ODu`z9>r}& LT.S/'0Q]>ا^N`|ODu`z9>r}& LTvg, lMBIEp/xU7{/RΩ0Q}^}!ǩ?pWߒ'W3lr3}ffp6>3lr3}nf ps0&73fp6>73f >73fp6>73fps3}nf >73fps3}nf >73fps3}{ofg373f f`73f>r3;8nfN ྏfN)s3}Ϻf73f{3;8nfN }l4>`v3pw3;8O=gf^nf^f^ԗnf^Wf^nf^f^Hr0x!l%73{{~ p]})~^}#W?x o {goxCx [xQ0Q}S?-&,0E}~H8p~#ki 9wՏ/OQ?TΣm?Qh8\ V߳_~R7l~zP߭ptګ?X8V=+pcӃ?Lp7 ?"J5O R}Qߡ/j Sߞ/ +Uߛ'Q|<lo?R.O`x<rCq-9HQا'?sǡU8Zq6Z}-rQFuBKېo꫐{oo꫐ `dI5١LT߀Vef?Tq>>_}Q7ꋏ'DgVzW}mqwR8K Lmi_m稯*άvP`U}71ZV_LlMSJpQ +W|~!ޫ#~-~V_FpSro"P"t5K`UswP.D/ 0K}WzC8ށ'_#K~soxΦn +8OQXyw |Πh/[HbK/zkrF\ S|koկ ptPqw +H:GT_(p8K K}Aկ&pUV@Gw5J%/~YF}_YN}w __+%>W}k1[N~R_p* <_}_ կ5LeUs7\U_0B~GR# Ʃ_z`vWXU_ 0Z`[}/f8R.7: {uWWx+0?:"6ԑ[XR檯`:0Qnu6`z)W7:!p~OPάyi9 ]xm_ zÁ/U'^O@zLx b:BptVP^i(q+ H$8zéR/3pPu(MN5^@*(; :WШx%uQ/0bhWxIuԫ :`^^1\'Q >KI8:lLT Usԋ +\9zKS/'0T?XUo&0W?XUo&0Z@V%Cw!\W/$7({6\Q~V"Mu ML0]R0]KX0W;`zv ,<'Sԋ!uD8zN)gVs5x:SoOVg Sq]Z^[c_-^0/UGSoW 멷 PWR@0+Xa^*Cc qp u8z3RmX]8:EHVG^E/N5z^Fl:|zy^RoN9/N8_^VWP ˫Cw$Y8:<_-'TgW\y>^KGK0B{Wo uxD`z7z1FGmVl8z%}g&p]|ޫ+qg&pS= PLWK^vG`SDuحYz@{3p~uxzLάn<OSO +9ua8|z^Σ.:^'G xmu"|zv^O]nd x u(+ZNpW]h%# p,u8z1V@.1/+R`^CWzu}x1p|zN]\^X=b_n-/2UW }}j0Q~`zVս`zեg3phu#࢞D:7ax"\w~R?^= +d%J9HsFr 9sF%Hb%[U33۳ݻ;3ճ|fw_Uw/G=+$F ,݋$H p{ &KI{ t/y$%@ZѽHtRR9"@r + 5 @^TN0K+FQ{z> t/RdD@|@,^o7aĈ%@@L^x[h{OtcE@|]fb^[ +Oн .Oxef[tH7{q-(K4m^{8{o E{3n[{kuKp8{ i{sѥ;TB Zt^DR!;H@{KHt"Cw @J MнH>!}ɡ4G itgF4M :ݳg'c3i!IPDh o`C @K@MNwpE]nKw t@Z{d m]<H&CVnQHtW"@@f{R'eH=Y@.Fw *t@꡻fE 51:t bD+=zGw@Ot +=Dw@ct +4=^Q Gt 4D$n@{Fw1 =nniG!Ji0{{8Bn ]@X%@:{hBڥG'E?I{BڢL(?){B3*N?{Bj ,?Q{BjS  g.+ݟ\=|!h{C_ݿ!m TC^xM݆q*\ %[ZSaR/“k 7mw-۔-Mr}MPkp{M+ -9] O-[k.2ħа- ʗz56Z5GT5a?a_Kv! YtrY?X_Ƶ T/K/ \ƨl֨}tl$^ݿ>Y\lV~0<c#a KWZrej55-k6CMP/B#E,nUf*GqUª`o _5<'R_#Ҟt}㲥\cuUʏcR&Iտ Y&aop!/ -㲿\p}ժ`e,>YjW-*_S+Kvѕr\nj+Uժ`E٤>9YlX7Py [tQY+V6kSeo|.F2bQ +X+_\|}Zxu>fk)W.FFZ٬j !SqO lX,+\|eYzCfݿQ*\c5UbUy|J8d\7e2a7^K"4].:[65\Vf+ŊBG](P@W%,a_oP2޿[6ċIo^V㲿\K[lU… )RR,"!K*ZsꕧVjpVM/"F5e߸(V, +zZ&+k-^x%R=rԕ(QB;d"bYpr|7P18[^E,K隋Q\rn-f$++-STN)O/SLZV\\,|Z뵍Wo]Ƽltոl+\%e+TXb%_ \ieyPBٲX&,V|kkLξxs3"I\tl+\p}ݖ)[N6+sRjjժUj=i!/[\~Ue"cpYW+V_Z.25#}brʛXq3-/ъdJk֬UVm߳:׬)+ˀU"_,/Qo,gzL,N"5K._N7Y}*`E/YJ[mψdkJ֭W^}_CO \gy֕Ikʄe*ߢEꕧVr镻^x}։&]nrŒ[trblkyV$[_VڨQƍMMb7nܨLZd\W&\W2ߒb5}"wN983+17/4K70/U;]>)eUnVZVd[AClj-ZZI񔐋kX^z͛˜4n$'}X~+U(_V,FOyBΙ}ssHL͈9(]UE7_9-r+T­l"&M5Ŷymۮ]Rc<0.U^vmʲ[ Eu5\|2ނWz/[^D_f&Yn}Vr:u5hظ̶U6mE"N:w"t{SB.bq;wI^6, 6j(_ou1;W(Wdқ;WlY^uȌ`jF $G2銭nV[xIܚ۸i-UYѫȳ{=z +q¸^{ѽ([dܹ*XۼX~׭SfjU*Yk,U".Ųϩ>nݒ˖7ʭ[A&Zjݶ]he">}ׯ0t~ۧl }6ۤQz,gc͙olfˋTY|XtK)_QXrlݶ}Nv.ӷ_ y#G>|a"!2ezvkNڵie+rp.UBzl׸UΫUu-+ 2ĢLg5lܬXr;v\^[PH1cǎ7nxiBP;^\رcȬG>L~}{k玢M7WV .)f}Qc= +L#tyR5mиiVmۋ%{}??h CUcƎN8iSʴ`\TqՓ'O4i "cF)2x":wl/FKobn^_<, +iQfb/=ȣ2|hRr^Q4oF+~2a#FlO8I;u3f̜9s04|*Y\ӧEcLj~ ק]͚4Wfrn.^iKHrP8b~!ntVW˵Ţ۬evt!܁2QE"۩DDsΛ7BEąϟ7oܹ"Y3gLO0nhAWvh׺XzŮZ + 5Ϋ,S3" +l]H7tUrbmۡs8x"܉L>CT;w|ŋ,Yte8a\K,^,ESL`Qo];Ybn+W15#]9+|yi:u}g 1j̸ Ll-.[bʕVZ-18ukr"K˂~O9\ۯOtK╧ٲxyej]DAȲ;c]uN%OWlużF,=z{~(W,29sVVruuׯ߰aËƸ.W\׭=WXL`\U^97xx ț'wlY*sjfE.9[\y(Tys=QcƋ%wl%˖l׮žqӦ͛lٲUfx&/Y\͛67_' +^R+5cY!,vm[6^[(SyrlyYxEnlS*kۼU]EwN9gނEKj7bE۷رcΝqŵo.zo޴Qf2_zG:X,bnn+6x.'-'4B^ݿqvn`bΞS1.VlXtN}l|0.V\iq"iQ#"X}UVKǎ2m۲iú䝢Ԝ5s" _:RIͲ+,76lڲmǮ=db;m܅K^a*_?t Ih7ЌmndQ~Yv̜xŚļ7:V]1/٭rEZ/_yFò_oco=y찜fo\-ׯ]CVȫfsÛv9ww#h?2?۰Y]{4\vo~IM'ϼr_pU┿bTjsgĖw]/mZjSQs]U9ӣ4G< :2Yfs !ղs^91{tŢlU_̫6Wzx/]xGlyx}[ͅw!ӪлDV!ULr<2;p[vV0\Z?Q b#_YXzx?qĖC_ Jy<~ЁihV'UE%Y\bO* +JU*5ԃ]z3Gk7n۵g!}cb_bUUMP*_xŞ+r={}{v*ЬNox9Bdٵ; +vkȼy˯eWNc*XtUqm0_*l,qൗi94&%ʛ'pv1a2nMQ燎0ujdwIy,O?sPFƫ|EF??ŖW.b{'ʎ-[j[b^YEb[^j;ls)I?tżʍl|K/nyءмpδ klx;UH sl9|]`4xU՝_YUSwrGׯ*94o߼ҿWAU^Ed"2SUe*TGUQCU7lݹg!sd𓛷eH@7k\x}74=ouh#_wxaU +e|#I~昹bUQ;gz:e6Gf߲62]K+Lze[x=^ch>w|6.4pjjUݑvޤ]څImwM_."·+!KK"v*jVڥ]hx>\kWZl3o]D ]-YhIvힿt:.pnOڥ]xDpwKXDKE;iv}kw֝{]څVmپhwD]څFG[6`pKskn?KWmB \[KێviDvժ'!۝hs/}p[ڥ]Ěme|,sy,RlEncݱ%niQv}vo hvݽOonvG.]-uolw>ڥ]]3ml?vi1n}e3-Y~sv]Ell$v2.bE5v;kZkKo=AD}hjͺvLjvӮvo\|BEL$avvz3|I`۠N E8[!Ah7 V._ʾ]."m@am;u;P;W +.4o_ôjkZ㯿hv#۝nmݶqehQXOٶb&ڥ]hv'Z=IۡuSO&ҮTvϚnN.K-mmw4iwlM."ǹ*J\ST;.vӧv6{f.FvسsH uǩ;Bۥ}KEѮ;!/ڝ/hl7"ҒMQw"B"ϿF[6Z:lCiuvۉvk.%._vv7?N ;YC[V5nliEjwhwhwncnŲ%̛'g̏e|v9N'lw}] +[=ᴋ]w\hwlwP۵]Dݟ~5)fH]wl!aׯ\2ol2]wWN2mK&u'_.ۭ[v-vvǘ6[H]wtö橣v.vqV]DWTsevԶnȣ]w,v?j0"hk{ke}hQFkwӺ>E8uǩݓv'.bvIrujcm7GiE$vK.vݱm>IH>LEЮ;̶ݡF iC$UڅjMkiB$9iF$ݎm.v]]xx޾ݳ'.bv]]xݗvv{vi늋v_Ͷ]W"H]WRn>xH]WhC.vljvvw.B7v3&;8L ܵ۲}@?M i7lliv; ۽h7{n?KWmB \[KێviDvժ'!۝hs/}p[ڥ]Ěme|,sy,RlEncݱ%K-{ 7.b"){!_ޢ]څmѮs~dv.BvJmd׌vOK)v+۝1o.bemv'ٶhv3.ڭYWݩ_ivCn՚u.]څ$avvz3|]E9[!Ahv_(lۼm}vv_]څf>kxvTCk.b}}dӭs1?iv#m+m]څvIkwݓK(\gamMhv%N햶;vi^ng(On}7K5W64jgK ^]څhw\]xO}^;vifm:.Sh څ$#'ڷ_]xADno4ݗivcm}uڥ]hGi׊v=6{f.F{h څЮ IZhvk_]EЮ Izn]څvFֱ5"h׍{wtȠ]7(E Ю ]7hCn.vݠ]xa?|͗>{vk]޸z݅]7 F Ԡ]D v+/e߮Lv{h څЮݶqehQGn.vHFZ7d" nѮ ]7Tn/v]D]X]7=s͞%"h xu׶,펧]۟}| +B u#l7)ڡj"Jh viw"Fh׍$;$\]7ܵնݢ+ҥ]h.ue fvv׮h<Ό]7iKmߪhR]7nOEѮ)]*XIuùܺ!v3."vpjviߒvUFHKvv-+Cp=]7ܵeêgv9˟VGѮhh"zh v7?N ;YC[V5nliFnjwhwhwncnŲ%̛'g̏e|vIF'lw}][=ᴋ]7\hwlwP۵]Dݟ~5)fH]7l!aׯ\2ol2(]7WN2mK.u#_.ۭ[v=vvǘ6[ȣ]7tö橣v.bvpV]D WTsevԶnh]7,v?j0"h k{ke}hQGnkwӺ>Euéݓv'.bvHrujcm7GiFn$vK.vݰm>IH>LEЮ̶ݡF iDn$UڅjMkiC.$9iG.$ݎm.v]]xx޾ݳ'.bv]]xݗvv{vy낋v_Ͷh]"Ȣ]Rn>xȡ]hD..~vi%nn@eõo."v{}nڅڽá~ݙڰviڹhh.%\v VUOC;9_G7oK5vXl9-XDيfcEKD;hv[2]koڥ]DRowCv?E ܵۢ]v]څ^!ޕ>vOvǟhvSNW;cޒ7'lڥ]ĖvNm+."f\[lS."i ݪ562#]L /HJ|n=fvC(slBv.BD-PlyNUB }n0=}ڇv/ڥ]Ćvv[}bh."Fk)vWD DK'ivQvϚnN.K-mmw4.¹*HcvE,)NiaEdѮ3W]:sj̉7o7{LH]g.=m/Y&O u۟}| +BuݛvvJ[v5̾ݯm]@uvv][m-Z(_p"]E$ЮD۽t3ǍvW/[0K_[vDqf :KW.k}&JJ.v%)ݞ]g)]*XIu{vnݐXiFΜ=}@#D]ڷ]D: i~ |@eeyh@"C u-V-?Sϡ]:"v%vZh]g~o~tKϝ>hwll^j"E2."vjwhwhwncnŲ%̛'g̏e|vY.mݱX +m7]i7Dvo}kv.b"I펢03ڝ'ԯGv-hQFӏ4ڽ&= w1̦y%fv-Cuvmwn[EѮvujlnME4%g߾xY7#_X;lQݚUv]DC]hi7vO'|o:*kw"&\[Nh7v%h"zve*_v]jwlw`67-\v_amkv nq_."vY3݋X۝.C$;@;{5nv7[aS]gNힴ;v+ݦ;Юvn."v%vK.Ƕ݇m%۝Jf|OB]dmg.)Y]g5mH0fʒ=v8qv?J&I.[]H;v_ڴvS)kʍ?Mvv]ĄST:t펴k&&hcfhKj lvi1\I vϞvOvǟhvSNW;cޒ7'lڥ]ĖvNm+."f\[lS."i ݪ562#]L /HJ|n=fvC(slBv.BD-PlyNUB }n0=}ڇv/ڥ]Ćvv[}bh."Fk)vWD DK'ivQvϚnN.K-mmw4.¹*]EvE]E-vowMMkWطD/oAݾ +v'nN[ݿK-n]n:_iv3M' ]xRFO/:2Kn!]w i7g6ݻӧqo{tA( +t-+hihs{h_qnh݌{x}tjK%J۽vvTZFt2ڝn =lwn6=[j2ݼF?pTU ?h/Jޕ.h3f[p n]݁v_v_ ;hlDyv3e|Anծ\x}~=5W3ˮHnlDEJm+&ڝK۝+&mڭXDnlYvfc)K\yvv[];FN{䛴+}Q:nNm[vvɕ=KGEXxx^ O囜h;ҵ3?jPe+VUlhwEi7sO6[ZŲ%R4^kq'9 k7UdwA3D>Pђe+UUO۹{AX3Dv,ڭWZ%H 7NM9`mOxw3]cU]hF'vU.m׹GAE\vyDѹlzr]y,7j5{XGM &r}e_.Z6_zrKOW?G +q&*חXvv7SnR+אҳc'ϘdzGO~z+]n*lWOvO=O~y3&>_.e5*/ULUbh /~ +%}1+7۰OzYSƏ2W5|fՊeKUY+f#^U]fʾdKAF50 j6qW\v#T|$s0jY vwi5=}=;E̚:~ KխUR9͓+GVY+M~)b[r @Ѯ׶\_nCkMNx!*חXv#s"b[zmy{W0j ~qljz".Rijlw닫-=u(2[ze-RP 97Cݿ$ A-9_F\kna=>#rb&]92n:QgX7 yqWv:ouZlkovkk/F>XY$SCnx,^oG~Ȭ{]>EB$ךo/mYqp}\YvŲ+Ffc۴U{u{w|hڍDo?KWt_ݿK:s 6OnoY,b+fxE'In ٗٯ%_z#\B kt6{}Zt,-v#c#ƪG"ի8aۢ~XvSwbӏߋvohC&nzX,YY,%V#0d3-Y'ξ}/e?v~)ڽqϞ0pƺK͜,ٰpPz,K׿˵+5ˇfh|cL"3pneWn&bd&LGUk-CN_Ej7սeN;nU nbhn@,˗)ŸW,9|3?.$0fhkeD9rpXt >ҭXz-vT#|jyTu |*yD@`k4[d|J [z*ާ f׏UvDG^WUj;qpyܹ}fשi[hB+}"wn?wݿd}_@*;yٯW ϖz-JWt囬rW=lltH+JIѭW+QH3u5lR.}#\ݱ{Y }*ky8&ɣޡ6sQ92ZOǣ *$/QJ[rU10tnש[~rٝ4}eݕoʿVeUUvՃUUmwx-3}\x֩]"^16W\Q[DqP!#u +U_A*dq_NK<7 e5.}"UOǣ>E)ZdeDTQK۪]Ǯ=3-^Fv7Y=V_ } `UYmxUCfN w}ztخVjU*z˔.UR[hQu +T_A!V7B`7ˮ?]s^K5pY<eAYC/GM%%Kn˕P(fgvQ&O`uȬ*U7x͛DayӺUK̙>yܨn[5E+V(_N[dIu +_Aj+ VG|Nk?I7/Xrpi.SS_R)P:xUו'o|7d23vb9%ԋ+*zB!B.D{5S'Nb$N{kO/{] =^˯*pF5k#6o٦}.8t©3-\ṙu]95u 4[tἙS ǎ:0/]:oӲyHo5+/<{ɥ}O@T|2뀮ާ$,ׄL%=2WHoT^FZnHnVm;`홓7`Ȉ1'O3K-3VE]*"ՆUjزaL<~̈!rzbжU A=V5W /N>~F" 8Sb7ui?0KC**REpikQMSMPZj~:uoаQf@nҡa7`&Newm:-՛cUaYY7ha`UhڷkۦXxgM8n!A햞ֱ}YF ԯWΛo֮ zKw}OAHZ>q/U_^XR#+=X;f=ʙM?UpG+T#󄖄&eJx۫;իW>`۰Qc7e6:v[8eTv)hiW2 +1Y>|(f4CxS +ǎ>*o]:wlצuTqp}x̓\zkD0< z)S.=M ]:='D9,բ&&Q. |zA T57nҤiS۶=۵[Vv0-ߤDtV׿-UlYѥ~.X\,zBbs%U)ǻ^U3ߩ9(55E-[w씖޵[^9}$t'O=ok{2Mu]UEbX-xi|Rx׬Xp ށޭkzZZl.6^`%6ǻ1~NPW2zO>?yV<߰_ƢȱV +5k+KBRx=7P+?5 -P۾CN̬^} 4t ]oNe+oZU9 tMW.»}zaK:h@^>2Ν:vhūW=|-gb1_&:ٯ$C%zIrtISϚ[kţ]znRoQU Y7usk%hS'+=r8;h@~~}W=}$uC[ \ !m M5$JUC\XvY<O$/Y8 uvEjzP-nyQy0:lnj_8is-Xd@w#iPZf\ߘY7h4 +[4:~^%̛3sIǎ=raCå+wTRsC7"oD/{_3CL /NM]WvegFxJ5Xb@ ]Nb#;Kl-=<OAC  +F)7pgΞ76<;waKeWmvkYM(ݽs '&x7[JygN:ybqcFpz=/{xOq^0M;uhf-,VE.gd׶ +t=MHz4oZV"Yě@ /Ў)(;n&O6c w֬ߴU{?#hX 8.GwuMկK$%C~"-E5ŮxܻntlkYaf-Zm%7<ܾrAǛpϏ+54~ 픩ӦϜ5{nтEK\nm;v芎}1ddWLĨ]5 xޱmuW._ZhAٳfN6u +\X8ax4nzjK^vm[hָa7kV9!6Z/ΫtW粫Ŝ +k].u7jRCx!vxϏ[yD_jj2hʔ@ k7lڲ}tݼ vE٥956|ޏ]G߳sM.(ΘO24]`肋'x x@eCFԦY‹k^bݒfO׹cGFGJ[CҮC=1Xm/x煦R3@3gΜ5k9s .Zd֬rصw#%P Rx㥮#ݵcлnͪ˖.Yh9Åt9)@#|螑޹C;yO /!]s.tb+]YMAa?!6Fl<9P@EE/X-nXzzA}=q@1!FjQ3vͰ=uzׯ]jr^`EEx~F N;} +G'c FB|i(܁& xg%kTxve;f}^RЭװIjPte;`P<[9xRQ5 'v.uO=MW ڪ]Ǵٽs)8XBgHKJ-󥖣VXr*vu7l$pwK8uWkA2Gb,Uׯ^x̩D; ߍ֯[^x +~K'._"?g-h'Q@o~ٙ]:k<"DSkv(e/:v޳%F7ad`1(hZ ZnzݲuvwϾ%Xtou@J,ʮTiˬo}XxE K^o+=w[` x=\`κ;]~ +-ˁ_w ؿo3tlZKC5Zx'UƲ' ,vѯUǵn<%1߀)\hE-+DAh? y-[n݆ڽg/{q VXtjs]+f#Tzϟz=ݳ{m-[ӥ]Jɛnxf ^/Z8;#ő?xRf*yFOg~̅˴ʦeVʮaKlk]:WnQ'"W]M}%MxOmڱcΝvFl?'枿HEաKؕpfW+8Yw޾Ey'; +}]vK\`륔ӷ~mjx1$6eQPzr{հm@3%/ui̺t: ѕtxnCGW8Y1Xn]xR{H퉓N=w+` E&th7d;tm +5}p.^X^rsgO:y=| ޏ [yfk׬B| Ǎ1t`\q|*]zmmZf]U:fwzV}6Ys\w&Z߷x9r%nϜŒ{5l>xTtՎ9B5v*|b|e,g#G%V/wRnuS ZoH"sg;rؠtm[Ⓢa+fk 4[[fs٥vF$ ͜SpRWab97<_uL8 {I{Ps~&tEl,aˮbl߇޻@ﭛ7_^@~ϜO¥ ,/uRKcI[^͙9m҄QoYzk6^MecMIx;viPt1f`_yTWuʟ:}=ss[ ;HPt?33Pv +>;|sg}.t7 cX @%NBVrHD^ڋJ~#.wo+4._`̩䅮WVNDi.w)sT%۸9ݜACga8$"@ ܪwE}Bᅬ~To?nYEg^9~BC }.~OtҊ6+=u/yţˡۼ1zbZ4^,wiceӠi5:EKWyO4M雼'Jyg}(GXl% +*(*k6QW_K0AL +\F{]|+zniޭ֭Z汣۶Eu M؞eUZfT5j֪},KVٸqRyG#yYH}-.re%reэDtKK_`dX(r%ouu܌"'.[6YEХ+K~(3W"fZVp+ikW+W.k۲p!D%z1L=o7=qJޱMji~Q_,)l{ewᒕk7m۵Qh/B| 7ʭ +8Q*rYVnJrэv~7a`e،۸oA|ڶi% e[6b\EaA8*=h3pwr7VNE,EPvyчª{#CjsvW[Z%p-FvZ%|_ ~_& .?~Euq7ob=u0=G +o˦YLcW pKVybW3FUrWL3{Bq U͛ M4シ .xݗَ]ugUnF>yFN=x[:{AyFX +rzPגZnɍTtEzsVE~`"kkw4ˁܯ)g\8{ + ֍kϟ=`Ġ>=2W aWZDrgpw6mٮ3.w;i:6m-.=D7oz7 +ȭי܈AW׎^_F~_I=Q7æy#sM +Wj9+vUјYUr7g][@Wi1vPGEn \܈E^^ė%$/5;_I _`xk{4/]8wdXÂWVfa]ލzZkmD^} =Woغ[f|mYHYwOg[ \^^ oS/erV2xmXæy waaUYe׃k.ٻET۽U*Z m>~kCg?b Yoոڒa+pkܤ"LvW_})TyO?6X..%Uvo)5ٻhѮ*ڙQ8ukr wޥg65ַ/znr#]=zz%UZ-7)󍒠5gb}6gĂw ^7v_٥]Uf/Q՞GNxƭ;w?P<0w +tX15p+lrQz%S/B}-7*@w1>έW.=yVϟ=vVP*v_y=8wpRW_wM=s׻fvil?VwwI&$'wcr@ S:|uu +wJU׻*$*UsfUmގ]g쪏 n-+L~.o2႗ؕ=3woYΙjjew}UU<=Y虡jV(OYoN& BW)]g*3 H*{3,{3 =b_UOW5a̢nچ Wnܒ*Z^Dj +\ۑuP<ݣLi+gUn\pm._\4sWS,~fSyd)U w#2W|UK_+ؠTbdWxDwܢr_բy3'"|_>Y `v3s7i܅~feO=ܛoݗ_9\ +6!`;,Gvw_sܛqO)3/[8wƤq#dg`L@v{XC.?s(6^xiǎ2@eWi2;4Px[ĸJ5Ǭ}YuĬ3vX@gʓ_rhެb,:f9 uecl4kWl&UBלѣOF$*)bxY>];ͩ6Фq קGt̩cN&Tʮ٥*\wFB]2i\._U'Ny:lf +ሙTNSzhˆ5bveEӆ1n*T ~\tm;w?xD)3.XE{9qW)#u;^V].fe+$:sΩ6YdS&۫{zJǜT9]WvM*UjܼUY]^WQ*0lfv +G̘@9:r;+sV͍TYn١]r\E]3͚FQCG8mVͫU<)bxY twH.+hNU4kqb[Z֩M3uʠ_+y5^JtɴCCE94}Vy2l;)bC{G19ժeϞ>i:E{veЌ:fAk,* kNH-y>U*9l1,*zwF̴jy|SήntO dWWx既_V]z*_%7GҰ)bk9fwGyES U]쾜sZ +T',.y(%o49T܅)f)@ ˷r5vrļv*,s*tviK_|gJ,%-NWv8kFUUc'*6˝͗Y)b\w%F̸ +rN.v=̘c.]5^KL"us]21k6UVz蚎һCx>iČ]St]ܕaKXvݺfCoʼ*_5i::"VDOE`o$g2Bg7.(Sld5K^*'ҹCcL1kĜꟌ薒]c׬[ҼJW՝͚S4CsS6/*{Z;$w1,Fr?aN%/fxQa8UaN@ ˯r6vbx8j\ꭺCF?ң[Ů]k6͑z[)8 +y0v?'N۴n3n;Z!ˈNP_ ͚S:EӄSā@eF[쏞CzwHŬq? ]y:l;)N@ ˿)?r:w]r\^s**Skrur9,{xpu;ktTe`y^LQVsp cRbd9:JC1˰YiXSr S9C؟pҴRFuW6"qa q Y[I?;$2C1b6ͫ;-NQm)@&-x,b؟rtj۸C]ufSd8e؟MvH*Ot:EZH r sCbZϚrs])zޔ)Gp gy5vb%ܡrZ=9EN,GGr 'r\cʡ%;tC::E7e<7<*k6'hNrH&gck쯏.,sLb7S3S?:.xЗcWܡPeY2EQ'#9ܡC!%n١BdNYU;d׋Sā@*a!'xm"Q'd[#Rt/$w#?Bx@ +<*qqDGnl=З;[,g5v+]7NY>E9*rN58З;)7kT66Ɂ@`>gs(I)@ +UXBTɁ@-I/Сn@ O +.WB]QUSā@_l6g>Rb,˃_@ rp|/Ya 3~0Ww?or r14W*x9y,_ʫ؟7x9Cb,ʳ؟x9򣜍0^ Ʈc%, +؟r  ؟9EdC~9+Sā@V(qv?gˁ@Vʳ;؟ؼdݡ09)@ +$eE7crP;Ʊ?gټd09q rq6,o6/Y! nx@ +4 +؟8Ed_p9)@ +l}Y.6/Y"neq Rrp"$,3dFZYޜ"$P)@ +xr1GPY.r \yv9,/6/Y;Q?g8EdQVt#4,x9 +lݡ9@ +r0v#2,Sā@V؟ټdUsV@T w(bq UYlFNYNY.gc7cry9Ȫ\y0v#0,; ؟r _`ys8ȪPyu"1笀NY-3\/Y!Pd@ q/\"*\Vt9Yr Uu8Qv6/Y"ccet8Ȫ4C$o6/Y,.@ ؟yq8*_y6v9&G +˱@ "؟'9EdU!Bfx9Ȫ@_Y)@ ؟7t8*99WJˁ@Vɳ;ı?br UV9C+\"IVt9Wr;ı2@ `r2:Ed\!Ql^J%.J6/YU wceȳ˱)@ Lr6v9WNry9*<+"(wc*3dYft9W1q Y^!U"J"3].r URyv8Wvyy9&gwc Ɋ.*Tr URٺC@ټdX.*PFR_ɛˁ@+_y9rW wc$/NYlr쯼q A.*\.6/Y_)@ ˓!Ur Qft9Wq eWwcNYV99Wr,{yv8Wbr ;ıJSā@r/Hr,{ٺC l^`r/(2:Ed_@ c!6/Y@*]^"<<9:Edr6v9Dؼd y0v99Edq/2ˁ@Aft9:q 0B_0)@`q̱ lyv8yy9rv8"rq8˱lٺC 1ټp9 1"8yy91jr/ +hr 0_ɋSāHgcc G'gcc!)%.BJvN#PBXfx92˱??țSāWwcN]#f\@`$ȳ;ıP+gwc!/a/+@`$؟odgr 0"`r72:ECټ 3y5v9 +hr 0؟/)@`xɳ˱ЖSā0˱?@`8ʃ˱?)@`؟/ea,39E yu8t8r1sϷr##/6/.gwc>Sā0]@`_@`_q 0qfr Зjrϟ +hr Я +qq Џlrϯrt8k9 ؼ<"\Lfx9{_ʛSā@ȫ;ı?+Sā@?q̱0 SK|xcl޲=ټ]cc,_UD `xu0v9ټy+^ cRmټ6.X>t@cRuFאrtJ4ټ{4*^;tM]˱?b:zhsE늮9˱?ey :jx]е}PycDfxK@kG2.%vMl4v99EI"hyC[~]Qcw>cL@kݣQ)k'dr?-(m^5\yzCW3&vcc,?ʋڼ Vn D׸'CK]&1ئ#ټ 65ѰK\Gtu{2(7v۱ X>]d `h8[ΥZtUd]±?dg^}ڼ=o5hy1v9 +="@ͻm^ | mmë_^R׀.nbgd[OnJb6ڣKjG1]-. +hLy@jj6_`ehcp~gSt7Y;J<OQl4v5wi /NbhmV5[|-uU?`6Dc7Eg; +}9:E@K歭ټUh VFxJnf_o0]q< +׺tTrOH*nm4v㪽ı?bZ&W=O\𞵁K o7ْПݳ]qr˱?dl^c М=r+Gb.:k)#jL`@C:t7Į1g0vb~5W٣'ݑbk6}ׂ`o]%/ۢNHy>stream +6s48q`|\펴4zEZz%*DRWغѕOT)ZbseS.NUҼʉq &xOp SEbbE}3^WBl~oEW4"t%1a6+ NQFc!c6r:nݑY/mx{(j,gV:z|-ZUJJVt_K݇ +tϟ1G ۩LG1]doC VCf/ x4n}3Λ +|U~kUL.͗_])h VVxw`+oqCcE߫3kWǯY5+ȕiL{W.RdXT=cUl^ Jlm#jߡ'k7J-q6K* V_WOl+T77'0~c d5n ]vX~a-2cN"X"(I/KW ʯ/Tq\I\hJIpSEEsfL)ۥ l@n6~^êaN>[L6nA0ދe/ E`}{V\~{BƵFkhF1=}rQnbcg9ۼ+ bF\wdf[Pvُ 8cuWH`X[`5 Ncݿg'˰-^0oִ +FĖ {tb.ϩXT=b7oБcO:s.,zoA} + +0A,E_*>|p==gNa;wInj:0n V Oa.AvXagN7âU;x؉Sg_Dzo™3_h_&I +"*Kpge얯\x̩J*藋hJ漜t1 +C9Ѡ V?Om:u޳O4<f7^l8}~T| _/ #z+Po[ .oݼN=}˰ݴ/RwٽkZ6b#]Rl=Uh+'x1۾s>} U0aҴs/w8y蜯^_?!Ib+%py64ׯB B;h&M(5lP~>ٙ];Ǽ3v*NAv{4+{x߬ߨi;gP웧̘=iy^\^LCB}bEDPo;.qK۽sq?Ƽ3`bܪ^f׹\jΝ9e\֥S֩M֣_SI=5$x.H`6ImնcZ.zY0~T*KW@iB/P| /]BR,D_w%l YVݺ KN8`HضUjjנПD焮e'$P &۠Im;ࢷw_G;ha%{<|S_l[`@F!(xR{qԉGܿWzŲEsr޸жe& Jt1Hul/*Jz6h+݌}aN> bX[^Q|_ͷaX~оuzp%݂\V S6eS ֪I(/T3E5D@ h]%l/"g;%wߞ];Ir,vy҄PtrmTC!%È.Cp7xs/T5&^aۼ=zb9g7cg'K.U|ҥcG`yz\jnjĢ۫˭7)c?`tY.wxsx]\bX􊾹KFށCS ^ֽ֬߈ߓsX| О;K؞{+Xr7_ +ֹ@.,t]>d ݬ.JKݔ8>z >~cǎ>v׎:,K/?ȅh{gwR4.+J0mF(&> on 7h'O1kn*@ݴy+s7 F6m޼e `,ܼyӦ@-beK,^;aܘQ*.wvVPti[M]҉?WF1 +bRߜ,Ko8wLJ?`:"P}!K-_x5 v@ _[jWXlI1r[4*.[KvMrjF&'PLp3ˊ(9+ΰ4Jt,k3,{^9} ;vy(vA +pAЮJn7^vXts/ReElf1E/͛|iQz.zMYj֢ۯAPc +ƎO(T57vlv8A*Jn떩r_#c(Zݧz˴)2`ftY$GxE/ҋBo/;:l8 }rܾR˜>}z@l3ێ۵iݲEsXRɭYW5r]&OTtMK]FQk\J/z8M~UQ| ߦS[bsw#;N=zdeuGj4Lmޔ%՗ be"H-zYzqL3,{z֨bU60T4@8+B/ٮ-PmBVUJnrbB..t]beReE,ZXze^AojѱX|_yM[fS%@p;u J_wԱcVb +BmPO+XrcUBWZˌ.+Be7g^ZJh,I)ߚ߬S>X jݺM@1=~Ѷm6[j 2%7*Ζ[Vյ˖~eEfQzYֽ 9:6.AFߺ` Yq:͛7j%uZ5!M[_?+eAhբk]V$ +}:CC 7lԨqcISUԨQCVrk\VPrY~i#EeEfYz-> b+_cE%~ ` Nݺ/ॺu +n< 2rYٲ\rb 9͢blqWa W7רY@\MZj֬!%lnbhٲ\*Ee 7^"/`D7^GhZ\Yr-veˠG~PzElKo_/ #˯^%/l%pe~eElK8+ #qp"P@-`KVrkD]bizĖ @,"X0(N'hbEnE%D.C2ˊlY54zzu++/%U FfRRɥfL]ftY,ED/:FJU+/? @^/"/7j ؊zWW)EŲ]5+^Q|%< ~"H0 #$Aj[Qo[*# +?׎\FŲ'zuV=3L0U_ H-b }2r W +,3,wWW|5|b0@zJJ|$2K*"4VJ.}#.e'[zQ^}Uas)8Ra+Ձ+#b#Vz9ʯ  @j% +p5[etY,l^*:|U~`@ĄN}'*:pk^2,qW)__X%UP jjB.b9ȅ^* +~VF bP+d\Yr\r_gY` Y;ZĖd\&*l5+VgIY[ո5X#%%vUEl[YpZetY,Ok/K abMGUj [ڂX#U URC[[wp\Dr+(K2,V_`a=fbh%n\F~% +FMj +lerY2w|%*&jj:Xe*fm5brXGlfF'n\!1%.עcRbbؤ踔ؘD|%YRlTtk;Gc%&Ƨ%%EUIG$UMINKOI{I׉Kcb%%'E'FUI3ؤ#qщ?/%蘄 &ÿ4~,Ub&Ť$$&?! qI)1I# 1pRRZ%&Џ#)%!c&G'WM/GRF&oKL˕"W5&>ހ䘨*ɱ)UU\\ت )I1I)$~KlSbb=JN1^S51.9&$K$VU]5%:&>9~OTLl\JXW39jJ 7ꏘ|$ƤTd+&/~glI qjEUEbXII|l<ܗpcD$U;q7FlRl\bl2wf,]JO!O%DM/x_ ($[*[p/wuV= QmX~P37>hY/~55VUj7aMTL> endobj 6 0 obj <> endobj 88 0 obj <> endobj 89 0 obj <> endobj 169 0 obj <> endobj 170 0 obj <> endobj 237 0 obj [/View/Design] endobj 238 0 obj <>>> endobj 235 0 obj [/View/Design] endobj 236 0 obj <>>> endobj 155 0 obj [/View/Design] endobj 156 0 obj <>>> endobj 153 0 obj [/View/Design] endobj 154 0 obj <>>> endobj 74 0 obj [/View/Design] endobj 75 0 obj <>>> endobj 72 0 obj [/View/Design] endobj 73 0 obj <>>> endobj 253 0 obj [252 0 R 251 0 R] endobj 327 0 obj <> endobj xref +0 328 +0000000004 65535 f +0000000016 00000 n +0000000250 00000 n +0000039832 00000 n +0000000007 00000 f +0001398533 00000 n +0001398603 00000 n +0000000009 00000 f +0000039883 00000 n +0000000010 00000 f +0000000011 00000 f +0000000012 00000 f +0000000013 00000 f +0000000014 00000 f +0000000015 00000 f +0000000016 00000 f +0000000017 00000 f +0000000018 00000 f +0000000019 00000 f +0000000020 00000 f +0000000021 00000 f +0000000022 00000 f +0000000023 00000 f +0000000024 00000 f +0000000025 00000 f +0000000026 00000 f +0000000027 00000 f +0000000028 00000 f +0000000029 00000 f +0000000030 00000 f +0000000031 00000 f +0000000032 00000 f +0000000033 00000 f +0000000034 00000 f +0000000035 00000 f +0000000036 00000 f +0000000037 00000 f +0000000038 00000 f +0000000039 00000 f +0000000040 00000 f +0000000041 00000 f +0000000042 00000 f +0000000043 00000 f +0000000044 00000 f +0000000045 00000 f +0000000046 00000 f +0000000047 00000 f +0000000048 00000 f +0000000049 00000 f +0000000050 00000 f +0000000051 00000 f +0000000052 00000 f +0000000053 00000 f +0000000054 00000 f +0000000055 00000 f +0000000056 00000 f +0000000057 00000 f +0000000058 00000 f +0000000059 00000 f +0000000060 00000 f +0000000061 00000 f +0000000062 00000 f +0000000063 00000 f +0000000064 00000 f +0000000065 00000 f +0000000066 00000 f +0000000067 00000 f +0000000068 00000 f +0000000069 00000 f +0000000070 00000 f +0000000071 00000 f +0000000076 00000 f +0001399555 00000 n +0001399586 00000 n +0001399439 00000 n +0001399470 00000 n +0000000077 00000 f +0000000078 00000 f +0000000079 00000 f +0000000080 00000 f +0000000081 00000 f +0000000082 00000 f +0000000083 00000 f +0000000084 00000 f +0000000085 00000 f +0000000086 00000 f +0000000087 00000 f +0000000090 00000 f +0001398673 00000 n +0001398746 00000 n +0000000091 00000 f +0000000092 00000 f +0000000093 00000 f +0000000094 00000 f +0000000095 00000 f +0000000096 00000 f +0000000097 00000 f +0000000098 00000 f +0000000099 00000 f +0000000100 00000 f +0000000101 00000 f +0000000102 00000 f +0000000103 00000 f +0000000104 00000 f +0000000105 00000 f +0000000106 00000 f +0000000107 00000 f +0000000108 00000 f +0000000109 00000 f +0000000110 00000 f +0000000111 00000 f +0000000112 00000 f +0000000113 00000 f +0000000114 00000 f +0000000115 00000 f +0000000116 00000 f +0000000117 00000 f +0000000118 00000 f +0000000119 00000 f +0000000120 00000 f +0000000121 00000 f +0000000122 00000 f +0000000123 00000 f +0000000124 00000 f +0000000125 00000 f +0000000126 00000 f +0000000127 00000 f +0000000128 00000 f +0000000129 00000 f +0000000130 00000 f +0000000131 00000 f +0000000132 00000 f +0000000133 00000 f +0000000134 00000 f +0000000135 00000 f +0000000136 00000 f +0000000137 00000 f +0000000138 00000 f +0000000139 00000 f +0000000140 00000 f +0000000141 00000 f +0000000142 00000 f +0000000143 00000 f +0000000144 00000 f +0000000145 00000 f +0000000146 00000 f +0000000147 00000 f +0000000148 00000 f +0000000149 00000 f +0000000150 00000 f +0000000151 00000 f +0000000152 00000 f +0000000157 00000 f +0001399321 00000 n +0001399353 00000 n +0001399203 00000 n +0001399235 00000 n +0000000158 00000 f +0000000159 00000 f +0000000160 00000 f +0000000161 00000 f +0000000162 00000 f +0000000163 00000 f +0000000164 00000 f +0000000165 00000 f +0000000166 00000 f +0000000167 00000 f +0000000168 00000 f +0000000000 00000 f +0001398819 00000 n +0001398893 00000 n +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0001399085 00000 n +0001399117 00000 n +0001398967 00000 n +0001398999 00000 n +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000912920 00000 n +0000912994 00000 n +0001399671 00000 n +0000040428 00000 n +0000041137 00000 n +0000913793 00000 n +0000147887 00000 n +0000913304 00000 n +0000913429 00000 n +0000913543 00000 n +0000913668 00000 n +0000911699 00000 n +0000911845 00000 n +0000042814 00000 n +0000043118 00000 n +0000043424 00000 n +0000041201 00000 n +0001398496 00000 n +0000042249 00000 n +0000042299 00000 n +0000650407 00000 n +0000705115 00000 n +0000808210 00000 n +0000650471 00000 n +0000246865 00000 n +0000052280 00000 n +0000454275 00000 n +0000246929 00000 n +0000043731 00000 n +0000150630 00000 n +0000043795 00000 n +0000052326 00000 n +0000147924 00000 n +0000147980 00000 n +0000150746 00000 n +0000150812 00000 n +0000150843 00000 n +0000151116 00000 n +0000246752 00000 n +0000151191 00000 n +0000258703 00000 n +0000454391 00000 n +0000454457 00000 n +0000454488 00000 n +0000454760 00000 n +0000454835 00000 n +0000705162 00000 n +0000808093 00000 n +0000808326 00000 n +0000808392 00000 n +0000808423 00000 n +0000808693 00000 n +0000808768 00000 n +0000912456 00000 n +0000911991 00000 n +0000912138 00000 n +0000912229 00000 n +0000912335 00000 n +0000912602 00000 n +0000912693 00000 n +0000912799 00000 n +0000913186 00000 n +0000913218 00000 n +0000913068 00000 n +0000913100 00000 n +0000913869 00000 n +0000914208 00000 n +0000915409 00000 n +0000931446 00000 n +0000997036 00000 n +0001062626 00000 n +0001128216 00000 n +0001193806 00000 n +0001259396 00000 n +0001324986 00000 n +0001390576 00000 n +0001399706 00000 n +trailer +<]>> +startxref +1399894 +%%EOF diff --git a/media/icon.ai b/media/icon.ai new file mode 100644 index 0000000..ee1c916 --- /dev/null +++ b/media/icon.ai @@ -0,0 +1,5121 @@ +%PDF-1.5 % +1 0 obj <>/OCGs[5 0 R 6 0 R]>>/Pages 3 0 R/Type/Catalog>> endobj 2 0 obj <>stream + + + + + application/pdf + + + UniGetUI + + + Adobe Illustrator CC 23.0 (Windows) + 2024-03-31T22:47+02:00 + 2024-03-31T22:47+02:00 + 2024-03-31T22:47+02:00 + + + + 224 + 256 + JPEG + /9j/4AAQSkZJRgABAgEASABIAAD/7QAsUGhvdG9zaG9wIDMuMAA4QklNA+0AAAAAABAASAAAAAEA AQBIAAAAAQAB/+4ADkFkb2JlAGTAAAAAAf/bAIQABgQEBAUEBgUFBgkGBQYJCwgGBggLDAoKCwoK DBAMDAwMDAwQDA4PEA8ODBMTFBQTExwbGxscHx8fHx8fHx8fHwEHBwcNDA0YEBAYGhURFRofHx8f Hx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8f/8AAEQgBAADgAwER AAIRAQMRAf/EAaIAAAAHAQEBAQEAAAAAAAAAAAQFAwIGAQAHCAkKCwEAAgIDAQEBAQEAAAAAAAAA AQACAwQFBgcICQoLEAACAQMDAgQCBgcDBAIGAnMBAgMRBAAFIRIxQVEGE2EicYEUMpGhBxWxQiPB UtHhMxZi8CRygvElQzRTkqKyY3PCNUQnk6OzNhdUZHTD0uIIJoMJChgZhJRFRqS0VtNVKBry4/PE 1OT0ZXWFlaW1xdXl9WZ2hpamtsbW5vY3R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo+Ck5SVlpeYmZ qbnJ2en5KjpKWmp6ipqqusra6voRAAICAQIDBQUEBQYECAMDbQEAAhEDBCESMUEFURNhIgZxgZEy obHwFMHR4SNCFVJicvEzJDRDghaSUyWiY7LCB3PSNeJEgxdUkwgJChgZJjZFGidkdFU38qOzwygp 0+PzhJSktMTU5PRldYWVpbXF1eX1RlZmdoaWprbG1ub2R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo +DlJWWl5iZmpucnZ6fkqOkpaanqKmqq6ytrq+v/aAAwDAQACEQMRAD8A9U4qsmmhgheaZ1jhjUvJ I5CqqqKkknoBiry/Xvz70e0uGg0ixfUAhobmR/RjNO6Di7MPmBiqUf8AQwt5/wBWSP8A6SG/5oxV 3/Qwt7/1ZI/+khv+aMVb/wChhLz/AKskf/SQ3/NGKu/6GEvP+rJH/wBJDf8AVPFXf9DCXn/Vkj/6 SG/6p4q7/oYS8/6skf8A0kN/1TxVv/oYS8/6skf/ACPb/mjFXf8AQwl5/wBWSP8A5Ht/zRirX/Qw l5/1ZI/+R7f80YqmEf51apJGGbSYomP7JlZtvf4Vzb4eyZSFyPD5PPan2ghCVQjxedrv+Vy6n/1b of8Ag3y/+Rh/O+xxv9Ecv5g+f7Hf8rl1P/q3Q/8ABvj/ACMP532I/wBEkv5g+f7FK7/O/UrePn+h 4pEH2iJmBH0cDtmFquzpYhxA8UXY6DtqGeXARwy+woT/AKGCvP8Aqyx/8j2/5ozXO6d/0MFef9WW P/ke3/NGKu/6GCvP+rLH/wAj2/5oxV3/AEMDef8AVlj/AOR7f80Yq3/0MDef9WWP/ke3/NGKu/6G BvP+rLH/AMj2/wCaMVd/0MDef9WWP/ke3/NGKu/6GAvP+rLH/wAj2/5oxV3/AEMBef8AVlj/AOR7 f80Yqyjyr+cfl/WrlLO8ibS7yU8YhIweJieiiQBaE/5SjFWfYq7FXYq8m/PrzDcW+nWWiwOUW9Zp bqn7SREcFPsWNfoxV4hirdMVbxV2KuxV1MVbxV2KupiqraUN7ApFQXGZOjAOaN97hdpSI08yP5rJ aZ1755bdMUW3TFjbUqgxOCKgqQR9GQyC4kHuZ4pETBHMEMUjaqg5xT6gvxVumKuxV2KupireKuxV 2KtjFX0j+V/mC41nyhazXTF7m3LW0sjblzHTix9+BFffFWXYqtc0GKvCfz4fnrWm+0D/APE8VeYY q3irsVdTFW8VdirsVbpirsVVLP8A46Fv/rjMrQ/30fe4Han+LT9zJ6Z1z55bdMUW3TFja2Qfu2+R /VkZciygfUPexKAfAM4l9TVcVdirsVbpirsVdirdMVbxV2Kvc/ySkp5Vdf8Al6k/4imKvSx0xVZL 9k4q8H/PI/7mtP8A+MD/APE8VeaYq6mKt4q7FXYq3TFXYq7FW8VVLMf7kLf/AFx+rMrQ/wB9H3uv 7V/xafuZPTOufO7bpixtumKLakH7tvkf1ZGXIsoH1D3sRg+wM4l9VVMVbpirsVdireKupireKuxV 1MVe3fksf+daf/mKk/4imKvT06Yqtm+ycVeDfnj/AMdrT/8AjA//ABPFXm1MVdirsVdTFW8Vdirs VbpireKr7P8A46Nv/rjMvQ/30fe6/tX/ABafuZTTOtfObbpixt1MUW1IP3bfI/qyMuRZYz6h72IQ D4BnEvq6rirsVdirdMVbxV2KuxVvFXYq9s/Jf/lG3/5ipP8AiKYq9QT7OKrZvsnFXg/54/8AHa0/ /jA//E8Vea4q7FW8VdirsVbpireKuxV2KqlkP9yNv/rjMvQ/30fe67tb/Fp+5lNM6183tumKLbpi i2pB+7b5H9WRlyLLGfUPew+D7AziX1lUxVumKt4q7FXYq3TFXYq7FXUxV7b+S/8Ayjb/APMVJ/xF MVenp9nFVs32Tirwf88P+O1p/wDxgf8A4nirzamKuxV2Kt4q7FW8VdirqYq3iqpZf8dG3/1xmXof 76Pvdd2t/is/6rKqZ1r5rbqYotumKLakH7tvkf1YJcinGfUPew+AfAM4h9cVMVbxV2KupireKuxV 2Kt0xV2KvbPyY/5Rt/8AmKk/4imKvT0+ziq2b7JxV4R+eH/HasP+MD/8TxV5rirsVbpireKuxV1M VbxV2KuxVUsh/uRtv9cZl6H++j73Xdr/AOKz/qsrpnWvmdt0xRbdMUW1IP3bfI/qwS5FOM+oe9h0 H2BnEPrypirqYq3irsVdirdMVdirsVbxV7X+TH/KOP8A8xUn/EUxV6en2cVWzfZOKvGfzciifVrM uisRE1KgH9r3xVgf1a3/AN9J/wACMVd9Wt/99J/wIxVv6tb/AO+k/wCBGKu+rW/++k/4EYq76tb/ AO+k/wCBGKt/Vrf/AH0n/AjFXfVrb/fSf8CMVd9Wt/8AfSf8CMVd9Wt/99J/wIxVasEK3MRWNQQ2 xAAOZeh/vo+91va/+K5P6qa0zrXzK3UxRbdMWNuYfCfkcEuRZYz6h70pt7a39Mfuk/4EZxD7Aq/V rf8A30n/AAIxV31a3/30n/AjFW/q1v8A76T/AIEYq76tb/76T/gRirvq1v8A76T/AIEYq39Wt/8A fSf8CMVd9Wt/99J/wIxVv6tb/wC+k/4EYq76tb/76T/gRir1f8qkRNEYIoUfWHNAKfsrir0VPs4q tm+ycVeN/mz/AMdWz/4xN/xLFWDUxV2KuxVvFXUxVvFXYq7FW8VWD/emL/WzL0P99H3ut7Y/xXJ/ VTGmda+YW3TCi26YsbaYfCfkcjLkWWM+oe9LLf8AuxnEPsStTFW8VdirsVdTFW8VdirsVbpir1T8 rf8Ajit/xnf/AIiuKvQ0+ziq2b7JxV45+bH/AB1bP/jE3/EsVYLirsVbpireKuxV2Kt0xV2KuxVY P96Yv9bMvQ/30fe6ztj/ABXJ/VTKmdc+X23TFjbdMUW5h8DfI5GXIssZ9Q96V2w/djOIfZFbFXYq 6mKt4q7FXYq6mKt4q7FXqn5W/wDHFb/jO/8AxFcVehp9nFVs32Tirxz82P8Ajq2f/GJv+JYqwamK t4q7FXYq6mKt4q7FXYq3TFVg/wB6Yv8AWzL0P99H3us7Z/xTJ/VTOmdc+W23TFjbdMUW0w+Bvkcj LkWWM+oe9Krf+7GcQ+zK2Kt0xV2KuxV2Kt0xV2KuxVumKvVPyt/44rf8Z3/4iuKvQk+ziq2b7JxV 47+a/wDx1bT/AIxN/wASxVg2KuxV1MVbxV2KuxQTSqttIRU0X2zaYuyckhZIi85qfabBjlwxBn5j kteNo+vQ9CMxdTo54fq5d7suz+1cOqHo2kOYPNbmK7JYv+9MX+tmXof76PvdZ2z/AIpk/qppTOuf Krbpii26Yotpx8DfI5GXIssZ9Q96VWw/djOIfaFbFVWK2kkHLZV7E5sNN2dkyji5B0HaPtFp9NLg 3nMc66e8ultpIxy2Ze5GOp7OyYhxcwvZ3tFp9TPg3hM8r6+4qYGa937sVdireKupireKvU/yu/44 rf8AGd/+Irir0JPs4qtm+ycVeO/mv/x1bT/jE3/EsVYNirdMVdirsVdigmkTBBT42+12HhnRdn9n 8Hrn9X3fteE7c7c8W8WI+jqf537PvV6Zt3lrcyBlKkVByGTHGceGQsFswaieKYnA1IIOWJo233U9 DnLazRywy74nkX0rsntaGrh3ZBzH6R5fcpL/AL0w/wCtkdD/AH0fez7a/wAUyf1U1pnXPlNt0xRb qYotzD4G+RyMuRZYz6h70ot/7sZxD7Ujba2Mh5v9jsPHNv2f2fx+uf0/f+x5Lt/t/wAG8OE/vOp/ m/t+73o4DOip87Jvd1MUCVbhBXNsY/jQfB3HhnO9odn8Hrh9P3fsfRPZ/wBoBmrDmP7zof537fv9 6hmoeubpireKuxV2KvU/yu/44zf8Z3/4iuKvQk+ziq2b7JxV49+awJ1W0oK/um/4lirB+LeBxV3F vA4q7i3gcVb4N4HFVW1jDEuR0NBm77J0wN5D05PH+1HaEo1hiasXL9X60VTN88TbdMUW3TFFtMis pVhUHIZMcZx4ZCwWzBqJ4picDUggXgeO7h7oW2b+uaGOjlh1EesSdi9xPteGr0OTpkEdx+keX3Jj TOhfP7bpii26Yotph8DfI5GXIssZ9Q96X6dal41eQUTsD3zn+z+z+P1z+n7/ANj3/b/tAMN4cJ/e dT/N/b93vTMDOiD50Te5bpii26YsbbpiolW4S65hEc1FHwsKgZyvaOmGLJtyO76r7N9pS1Wn9e84 Gie/uKzi3gcwHoHcW8DiruDeBxVvi3gcVeo/leCNGav+/wB/+Irir0JPs4qtm+ycVeYfmB/x0bf/ AIxn/iWKsWpireKuxVo9MVS6RqTFW2r0zd9k6kC8Z68njvajs+UqzxFgCpfrbpm+eItumKLbpii2 6YsbbpgIUSI5N0wsbdTFFt0xY23TFbbAxQZXuW6Ysbbpixt1MUW3io3NBq2kEkpK/ZGwPjnK9o6g Zcnp5DZ9X9m+zZaXT+vaczZHd3BG5gPQOxVumKt4qzvyH/xzz/xlb9S4qzZPs4qtm+ycVeY/mB/x 0YP+MZ/4lirFsVdirqYq3iqCvbQSKSOuKCLQsMrBvSl+1+y3jnRdn9ocfon9X3/teA7e7COG8uIf u+o/m/s+5EUzbvKW3TFjbqYotumKLbpii26Ysbbpii26Yot1MUW3TFFt0xY230xUWdggpZHuX9KP aL9pv5v7M53tDtDj9EPp+/8AY+kezvs94AGbMP3nQfzf+Pfd70xtYBGgGah7BEUxV2Kt4q7FWd+Q /wDjnn/jK36lxVmyfZxVbN9k4q8x/MD/AI6EH/GM/wDEsVYtTFW8VdirsVcVr1xVB3lorqSOuKCL QsExDelL9v8AZbx/tzouz+0OP0T+r7/2vn3b/YJw3lxD931H839n3e5E0zbvJW3TFFt0xRbdMUW6 mLG26YotumKLbpii26YWNu6Cp6YFFk0EHJK1y/px/wB1+03839mc72h2hx+iH0/f+x9I9nfZ3wKz Zh+86D+b/wAe+73o+2tVjUUGah7FEgYq3irsVdTFW8VZ35E/3gP/ABlb9S4qzVPs4qtm+ycVeZef /wDjowf8Yz/xLFWLYq7FW6Yq7FXYq4iuKoK7slcVA3xQRexQ8M7K/pTfa/Zbx+edD2f2hx+if1dD 3/tfPu3/AGf8K82EejrH+b5jy+73chNM3Dx9t0xRbdMWNt0xRbdMUW3TCi3UxY230wKLJoIKWR7p vTi/uv2m/m/szne0O0OP0Q+n7/2PpPs77O+BWbMP3nQfzf8Aj33e9H2tqsSjbfNQ9iicVbxV2Kt0 xV2KuxVnfkT/AHgP/GVv1LirNU+ziq2b7JxV5l5//wCOhB/xjP8AxLFWLYq3irsVdirdMVbxVoiu KoK8sxIpIG+Koe3nZW9Gb7XRWPf2PvnQ9n9ocXon9XQ9/wC1889ofZ/wrzYR6P4o/wA3zHl93u5C 6ZuHjbdTFjbdMKLbpii26Yotv59MCBZ2CBkla5f0ov7ofab+b+zOd7Q7Q4/RD6fv/Y+lezvs74AG bMP3nQfzf+Pfd70xtrZY1ApmoexRGKuxV1MVbxV2KuxVumKs68i/7wH/AIyt+oYqzVPs4qtm+ycV eZefv+OhB/qH9eKsXxV2Kt4q7FW8VdirqYq4gYqg7uzWRTQb4qh7edlb0ZvtdEc9/Y++dD2f2hxe if1dD3/tfOvaL2e8K82Eej+KP83zHl93u5C6ZuXi7bpii26Yot3T5YECyaCDkke5f04/7r9pv5v7 M53tDtDj9EPp+/8AY+lezns54AGbMP3nQfzf+Pfd70da2qxqNt81D2SJxV1MVbxV2KuxVumKuxV2 Ks68i/7wH/jK36hirNU+ziq2b7JxV5v55t55b+Exxs4CGpAr3xVjX1C9/wB8v9xxV31C8/3y/wBx xVv6he/75f7jirvqF7/vl/uOKu+oXv8Avl/uOKt/ULz/AHy/3HFXfUL3/fL/AHHFXfUL3/fL/ccV d+j7w/7pf7jiqDvNFu3UkQPX5HFUIq38B4T27lR0cA1+nN3pe1qHDk38/wBbw/a3siJkz05AJ/hP L4Hp7uSsrKfEfMEfrzaw1uGXKQ+773kM3Ymtxmjin8Bxf7m3NIF6BmPgqk5HJr8Mf4r927Zp/Z7W 5TtjMf63p+/dRNvqV23FYHSLuKGp+eaTWdpSy+mO0fve77F9mcekIyZDx5fsj7vPzTK20i7jUfuH /wCBOax6hECwvP8AfL/ccVb+oXn++X+44q76he/75f7jirvqF7/vl/uOKt/ULz/fL/ccVb+oXv8A vh/uOKu+oXv++X+44q76he/75f7jirvqF5/vl/uOKs18lRSRWRWRSjeoxoRTsMVZkn2cVWzfZOKs N1//AHqX5fxxVLKYq7FXYq3irqYq3irsVdTFW8VcRXFUPNZxydRiqDfRYia0xVdFo8SnpiqOit0j GwxVVAxVumKt4q7FXUxVvFXYq7FW6Yq7FU70H7P+yP8ADFWSJ9nFVs32TirDdf8A96l+X8cVSzFX Yq3TFW8VdirsVbxV2KuxV1MVbxV2KuxVumKt4q7FXYq3TFXYq7FXUxVvFXYq7FU70H7P+yP8MVZI n2cVWzfZOKsO1/8A3qX5fxxVLKYq3irsVdirdMVdirsVdirdMVdirsVbpireKuxV2KupireKuxV2 Kt0xV2KuxVumKuxVOtC+z/sj/DFWSJ9nFVs32TirDte/3qX5fxxVLcVdirqYq3irsVdirdMVdirs VbpirsVbxV2KupireKuxV2Kt0xV2KuxVvFXUxVvFXYqnOhfZ/wBkf4YqyRPs4qtm+ycVYdr3+9S/ L+OKpbTFW8VdirsVbpirsVdireKupireKuxV1MVbxV2KuxVumKuxV2KuxVumKt4q7FXYq3iqc6H0 /wBkf4YqyNPs4qtm+ycVYfrv+9S/L+OKpbirsVdTFW8VdirsVbpireKuxV2Kt0xV2KuxV1MVbxV2 KuxVumKt4q7FXYq3TFXYq7FU50Pp/sj/AAxVkafZxVbN9k4qxLXUPqh/DY4qlWKt0xV2KuxVumKt 4q7FXYq6mKt4q7FXYq3TFXYq7FW6Yq7FW8VdirqYq3irsVdirdMVTrRVoo9zXFWQp0xVqQVXFWO6 vbliaDFWOyGSNiCtRiqz6wf5PxxVr6wf5PxxVv6wf5PxxV31k/yfjirvrJ/k/HFXfWT/ACfjirf1 n/IP34q760f5D9+Ku+tH+Q/firvrX+QfvxV31o/yH78Vb+tn+Q/firvrZ/kP34q763/kH78Vd9bP 8h+/FXfWz/IfvxV31s/yH78Vb+uf8Vn78Vd9cP8Avs/firvrh/32fvxV31z/AIrP34q2Lz/is/fi qpC0szgU4r4YqyjS4CqrXFU4XpirZxVB3VqJBiqS3WjlmJAxVCHRW8MVd+hW8MVd+hW8MVd+hW8M Vd+hW8MVd+hW8MVd+hW8MVd+hW8MVd+hW8MVd+hW8MVd+hW8MVd+hW8MVd+hW8MVd+hW8MVd+hW8 MVd+hW8MVd+hW8MVd+hW8MVd+hW8MVd+hW8MVd+hW8MVbGitXpiqOs9J4kEjFU7t4AigYqr4q7FX EYqtMantiq30E8MVd6C+GKu9BfDFXegvhirvQXwxV3oL4Yq70F8MVd6C+GKu9BfDFXegvhirvQXw xV3oL4Yq70F8MVd6C+GKu9BfDFXegvhirvQXwxV3oL4Yq70F8MVd6C+GKu9BfDFXeinhiq4RqMVX Yq7FX//Z + + + + uuid:C1BCCE1871B8DB11993190FCD52B4E9F + xmp.did:945c8dd3-9951-5046-baa9-365c998da5e5 + uuid:c9f8569d-fa33-4662-a958-36c3c462b918 + proof:pdf + + xmp.iid:3faacfd4-b8ac-b14f-9df0-f9c23c6d178a + xmp.did:3faacfd4-b8ac-b14f-9df0-f9c23c6d178a + uuid:C1BCCE1871B8DB11993190FCD52B4E9F + proof:pdf + + + + + saved + xmp.iid:3faacfd4-b8ac-b14f-9df0-f9c23c6d178a + 2024-03-31T22:46:44+02:00 + Adobe Illustrator CC 23.0 (Windows) + / + + + saved + xmp.iid:945c8dd3-9951-5046-baa9-365c998da5e5 + 2024-03-31T22:46:56+02:00 + Adobe Illustrator CC 23.0 (Windows) + / + + + + Document + Mobile + 1 + True + False + + 4096.000000 + 4096.000000 + Pixels + + + + Cyan + Magenta + Yellow + Black + + + + + + Default Swatch Group + 0 + + + + White + RGB + PROCESS + 255 + 255 + 255 + + + Black + RGB + PROCESS + 0 + 0 + 0 + + + RGB Red + RGB + PROCESS + 255 + 0 + 0 + + + RGB Yellow + RGB + PROCESS + 255 + 255 + 0 + + + RGB Green + RGB + PROCESS + 0 + 255 + 0 + + + RGB Cyan + RGB + PROCESS + 0 + 255 + 255 + + + RGB Blue + RGB + PROCESS + 0 + 0 + 255 + + + RGB Magenta + RGB + PROCESS + 255 + 0 + 255 + + + R=193 G=39 B=45 + RGB + PROCESS + 193 + 39 + 45 + + + R=237 G=28 B=36 + RGB + PROCESS + 237 + 28 + 36 + + + R=241 G=90 B=36 + RGB + PROCESS + 241 + 90 + 36 + + + R=247 G=147 B=30 + RGB + PROCESS + 247 + 147 + 30 + + + R=251 G=176 B=59 + RGB + PROCESS + 251 + 176 + 59 + + + R=252 G=238 B=33 + RGB + PROCESS + 252 + 238 + 33 + + + R=217 G=224 B=33 + RGB + PROCESS + 217 + 224 + 33 + + + R=140 G=198 B=63 + RGB + PROCESS + 140 + 198 + 63 + + + R=57 G=181 B=74 + RGB + PROCESS + 57 + 181 + 74 + + + R=0 G=146 B=69 + RGB + PROCESS + 0 + 146 + 69 + + + R=0 G=104 B=55 + RGB + PROCESS + 0 + 104 + 55 + + + R=34 G=181 B=115 + RGB + PROCESS + 34 + 181 + 115 + + + R=0 G=169 B=157 + RGB + PROCESS + 0 + 169 + 157 + + + R=41 G=171 B=226 + RGB + PROCESS + 41 + 171 + 226 + + + R=0 G=113 B=188 + RGB + PROCESS + 0 + 113 + 188 + + + R=46 G=49 B=146 + RGB + PROCESS + 46 + 49 + 146 + + + R=27 G=20 B=100 + RGB + PROCESS + 27 + 20 + 100 + + + R=102 G=45 B=145 + RGB + PROCESS + 102 + 45 + 145 + + + R=147 G=39 B=143 + RGB + PROCESS + 147 + 39 + 143 + + + R=158 G=0 B=93 + RGB + PROCESS + 158 + 0 + 93 + + + R=212 G=20 B=90 + RGB + PROCESS + 212 + 20 + 90 + + + R=237 G=30 B=121 + RGB + PROCESS + 237 + 30 + 121 + + + R=199 G=178 B=153 + RGB + PROCESS + 199 + 178 + 153 + + + R=153 G=134 B=117 + RGB + PROCESS + 153 + 134 + 117 + + + R=115 G=99 B=87 + RGB + PROCESS + 115 + 99 + 87 + + + R=83 G=71 B=65 + RGB + PROCESS + 83 + 71 + 65 + + + R=198 G=156 B=109 + RGB + PROCESS + 198 + 156 + 109 + + + R=166 G=124 B=82 + RGB + PROCESS + 166 + 124 + 82 + + + R=140 G=98 B=57 + RGB + PROCESS + 140 + 98 + 57 + + + R=117 G=76 B=36 + RGB + PROCESS + 117 + 76 + 36 + + + R=96 G=56 B=19 + RGB + PROCESS + 96 + 56 + 19 + + + R=66 G=33 B=11 + RGB + PROCESS + 66 + 33 + 11 + + + + + + Grays + 1 + + + + R=0 G=0 B=0 + RGB + PROCESS + 0 + 0 + 0 + + + R=26 G=26 B=26 + RGB + PROCESS + 26 + 26 + 26 + + + R=51 G=51 B=51 + RGB + PROCESS + 51 + 51 + 51 + + + R=77 G=77 B=77 + RGB + PROCESS + 77 + 77 + 77 + + + R=102 G=102 B=102 + RGB + PROCESS + 102 + 102 + 102 + + + R=128 G=128 B=128 + RGB + PROCESS + 128 + 128 + 128 + + + R=153 G=153 B=153 + RGB + PROCESS + 153 + 153 + 153 + + + R=179 G=179 B=179 + RGB + PROCESS + 179 + 179 + 179 + + + R=204 G=204 B=204 + RGB + PROCESS + 204 + 204 + 204 + + + R=230 G=230 B=230 + RGB + PROCESS + 230 + 230 + 230 + + + R=242 G=242 B=242 + RGB + PROCESS + 242 + 242 + 242 + + + + + + Mobile Color Group + 1 + + + + R=136 G=168 B=13 + RGB + PROCESS + 136 + 168 + 13 + + + R=127 G=71 B=221 + RGB + PROCESS + 127 + 71 + 221 + + + R=251 G=174 B=23 + RGB + PROCESS + 251 + 174 + 23 + + + + + + + Adobe PDF library 15.00 + + + + + + + + + + + + + + + + + + + + + + + + + +endstream endobj 3 0 obj <> endobj 8 0 obj <>/Resources<>/ExtGState<>/Properties<>/Shading<>/XObject<>>>/Thumb 22 0 R/TrimBox[0.0 0.0 4096.0 4096.0]/Type/Page>> endobj 9 0 obj <>stream +HUˎ[7 ߯,RDn3II R“ =ÙMa&istXһi$z˟_J Gx㵤?'|~.TMJz][FSUUr>&M aKUM\dyJ._=ef*Qz ܽJϑxZxnEX8=.ᆭ˗~_lè Z:gwOؿL݊t$c.dL59RBV5{{2[2Dᐌ U͆KoљsEOIH;'ngr.mOODF_\nam)M +&4VCM\3b \5Vh{6.Ny/%&LYau+'p2FaOcsF2r]IF݃e`XF]N @tи%b(,v}\n>HJRraFe(X:(Z>s`#PE1P-F^g <]"&Щf[IQFgS8Z =( `ڼGA S%XihiP7yTA]cp'n!}'pli4HcUǣv֬mF@ 7(&8$Y3Y%cz'[9TZ `> endobj 22 0 obj <>stream +8;Z\ubEX:q$q7M$'s'G(cc3&V!Vqffq)FoG`4%u;$LDK!YrFfC/%=fpe[(moDggqq +PU&lV_N@a8M1!ShEV4PVa-a]mH)nUY%=,OS6$G([kb*,TV*]>Y=h;@-:E,_kHW6(SCIg^?:7f&/G6^K#7Qgcg +pO5K$_D+_lLd?M_Sr!.3,OQTh9VV1?mZD:3@\U$GR?[Mgh5Op=AD/^dW\uT:!@G0W +6q&%-B*arN!ihH^pNc&[+*\ELa"^GFk@p$7q;/i4WF\icG-CWCp?`pY_M".`M21`1 +^r/!$0@(;IjCrZ/`q.,.oTH,$akY>D4?8Gs4W#r07o/sTn[QV#Q_ur-AY)!tn3*(] +0BNL_O!dRa:R9(m78NIQJY;`/YWT'-<"hqoIb`7W#hiNl^@KpE+_YsqPp^b#:EjmS +DANtO(u2eoSj`;/D9^_hj,$BK2Op\)WoE/,LttGFA"p +uBN\fqK))gQ93kp-6aaNgCG&Th8a1jXrNusqb +4:1\U7LX8RFCOOrW@g2CLc7Ob-9Tu72+Qt34<:;r-`-b(:Y-0@B1%l.$JdTCG+b,U^CYNp")=BR;fOOA.%["3MQ,@a\k0%;Y7r!4P@\!3n!8D +;7NNdgXL[#nukj&1aqi&e2l&lFVfWb2)jb79U2:mde8Ijmmg6#\h[s&VktWN,>V5s +nZGaFL"KqW:YNY7[A1K^=u,.DXa(g?V#T=7m@/3_C!'6_kp,d&<7o+;S!d7-e';Cs +R.lZqG)4j4MB)?[olgCA`$W(~> +endstream endobj 24 0 obj [/Indexed/DeviceRGB 255 25 0 R] endobj 25 0 obj <>stream +8;X]O>EqN@%''O_@%e@?J;%+8(9e>X=MR6S?i^YgA3=].HDXF.R$lIL@"pJ+EP(%0 +b]6ajmNZn*!='OQZeQ^Y*,=]?C.B+\Ulg9dhD*"iC[;*=3`oP1[!S^)?1)IZ4dup` +E1r!/,*0[*9.aFIR2&b-C#soRZ7Dl%MLY\.?d>Mn +6%Q2oYfNRF$$+ON<+]RUJmC0InDZ4OTs0S!saG>GGKUlQ*Q?45:CI&4J'_2j$XKrcYp0n+Xl_nU*O( +l[$6Nn+Z_Nq0]s7hs]`XX1nZ8&94a\~> +endstream endobj 20 0 obj <>/ExtGState<>/ProcSet[/PDF/ImageC/ImageI]/XObject<>>>/Subtype/Form>>stream +q +/GS0 gs +3433 0 0 3944 331 -52 cm +/Im0 Do +Q + +endstream endobj 21 0 obj <>/ExtGState<>/ProcSet[/PDF/ImageC/ImageI]/XObject<>>>/Subtype/Form>>stream +q +/GS0 gs +2101 0 0 2880 997 1020 cm +/Im0 Do +Q + +endstream endobj 30 0 obj <> endobj 32 0 obj <>stream +H XA7=mӀ>*b K} Կ S_NNxp\u6puϤV|f7{w3{E7m>NQgآ<zNV{x^]M\S${@r[ .#&X<0[AXuY cz9 S-0G<7uG#.{Ցco:pB*nSo Kk:j:hC2.R/ C;kn8`_9NzwN.:8[p"u ,bѫ7)Թpxu8z[)^#VG QՅxMpLu8zP'^&GS㪷 Y}pu8zE]$(P3W +1,PKy[Uw3 +@RL Χ,?QZ +u}8z_Ϊ^.V [>us8zK]ί0Q+W ;ԵzukzZ]2Uw+ +ՕZ=:uczJ]4Q+W +u]-\UlV몷 p]W^7{µ`?uSz. +Wo}=az +`uM9-azlU9M&&uF^;[azW7iV]7:u?^=`zQ׃\bu:^>K`z,SwD] fu4?ϫtPO _IԹΡ|WխK:C} :*R7q[ou2K TR]'ukuQ]>u>nW_I ৺H}#W_00Lz S?^}=ԯ>lQ([0JLRM}AO>lS_ 0H6 R?M}As/>lU[70FV Q?U}Cc>lU{W0Dv Q?]}EC=lW_sW0C;~aP?ehg=_g/B={xuI?PިKzF]ԫ7~^=Q>==R0=R0=R0=R0=R0=R<]L&suWÇ+ICz +`R=wPw0;|T>]L&suWÇ+ICz +`R=wPw0;|T>]L&suWÇ+ICz +`R=wPw0;|T>]L&suWÇ+ICz +`R=wPw0;|T>]L&suWÇ+ICz +`R=wPw0;|T>]L&suWÇ+ICz +`R=wPw0;|T>]L&suWÇ+ICz +`R=wPw0;|T>]L&suWÇ+ICz +`R=wPw0;|T>]L&suWÇ+ICz +`R=wPw0;|T>]L&suWÇ+ICz +`R=wPw0;|T>]L&suWÇ+ICz +`R=wPw0;|T>]L&suWÇ+ICz +`R=wPw0;|T>]L&suWÇ+ICz +`R=wPw0;|T>]L&suWÇ+ICz +`R=wPw0;|T>]L&suWÇ+ICz +`R=wPw0;|T>]L&suWÇ+ICz +`R=wPw0;|T>]L&suWÇ+ICz +`R=wPw0;|T>]L&suWÇ+ICz +`R=wPw0;|T>]L&suWÇ+ICz +`R=wPw0;|T>]L&suWÇ+ICz +`R=wPw0;|T>]L&suWÇ+ICz +`R=wPw0;|T>]L&suWÇ+ICz +`R=wPw0;|T>]L&suWÇ+ICz +`R=wPw0;|T>]L&suWÇ+ICz +`R=wPw0;|T>]L&suWÇ+ICz +`R=wPw0;|T>]L&suWÇ+ICN0 *Na$Z`R=wPw0;|T>]L&suWÇ+ICz +`R=wPw0;|T>]L&suWÇ+ICz +`R=wPw0;|T>]L&suWÇ+ICz +`R=wPw0;|T>]L&suWÇ+ICz +`R=wPw0;|T>]L&suWÇ+ICz +`R=wPw0;|T>]L&suWÇ+ICz +`R=wPw0;|T>]L&suWÇ+ICz +`R=wPw0;|T>]L&suWÇ+ICz +`R=wPw0;|T>]L&suWÇ+ICz +`R=wPw0;|T>]L&suWÇ+ICz +`R=wPw0;|T>]L&suWÇ+ICz +`R=wPw0;|T>]L&suWÇ+ICz +`R=wPw0;|T>]L&suWÇ+ICz +`R=wPw0;|T>]L&suWÇ+ICz +`R=wPw0;|T>]L&suWÇ+ICz +`R=wPw0;|T>]L&suWÇ+ICz +`R=wPw0;|T>]L&suWÇ+ICz +`R=wPw0;|T>]L&suWÇ+ICz +`R=wPw0;|T>]L&suWÇ+ICz +`R=wPw0;|T>]L&suWÇ+ICz +`R=wPw0;|T>]L&suWÇ+ICz +`R=wPw0;|T>]L&suWÇ+ICz +`R=wPw0;|T>]L&suWÇ+ICz +`R=wPw0;|T>]L&suWÇ+ICz +`R=wPw0;|T>]L&suWÇ+ICz +`R=wPw0;|T>]L&scH`w}0퇺+ICz +`R=wPw0;|T>]L&suWÇ+ICz +`R=wPw0;|T>]L&suWÇ+ICz +`R=wPw0;|T>]L&suWÇ+ICz +`R=wPw0;|T>]L&suWÇ+ICz +`R=wPw0;|T>]L&suWÇ+ICz +`R=wPw0;|T>]L&suWÇ+ICz +`R=wPw0;|T>]L&suWÇ+ICz +`R=wPw0;|T>]L&suWÇ+ICz +`R=wPw0;|T>]L&suWÇ+ICz +`R=wPw0;|T>]L&suWÇ+ICz +`R=wPw0;|T>]L&suWÇ+ICz +`R=wPw0;|T>]L&suWÇ+ICz +`R=wPw0;|T>]L&suWÇ+ICz +`R=wPw0;|T>]L&suWÇ+ICz +`R=wPw0;|T>]L&suWÇ+ICz +`R=wPw0;|T>]L&suWÇ+ICz +`R=wPw0;|T>]L&suWÇ+ICz +`R=wPw0;|T>]L&suWÇ+ICz +`R=wPw0;|T>]L&suWÇ+ICz +`R=wPw0;|T>]L&suWÇ+ICz +`R=wPw0;|T>]L&suWÇ+ICz +`R=wPw0;|T>]L&suWÇ+ICz +`R=wPw0;|T>]L&suWÇ+ICz +`R=wPw0;|T>]L&suWÇ+ICz +`R=wPw0;|T>]L&suWÇ+ICz +`R=wPw0;|t 0bN⡭ uW/s+BKa +zPwR=wXx;,]T^ uW/s+BKa +zPwR=wXx;,]T^ uW/s+BKa +zPwR=wXx;,]T^ uW/s+BKa +zPwR=wXx;,]T^ uW/s+BKa +zPwR=wXx;,]T^ uW/s+BKa +zPwR=wXx;,]T^ uW/s+BKa +zPwR=wXx;,]T^ uW/s+BKa +zPwR=wXx;,]T^ uW/s+BKa +zPwR=wXx;,]T^ uW/s+BKa +zPwR=wXx;,]T^ uW/s+BKa +zPwR=wXx;,]T^ uW/s+BKa +zPwR=wXx;,]T^ uW/s+BKa +zPwR=wXx;,]T^ uW/s+BKa +zPwR=wXx;,]T^ uW/s+BKa +zPwR=wXx;,]T^ uW/s+BKa +zPwR=wXx;,]T^ uW/s+BKa +zPwR=wXx;,]T^ uW/s+BKa +zPwR=wXx;,]T^ uW/s+BKa +zPwR=wXx;,]T^ uW/s+BKa +zPwR=wXx;,]T^ uW/s+BKa +zPwR=wXx;,]T^ uW/s+BKa +zPwR=wXx;,]T^ uW/s+BKa +zPwR=wXx;,]T^ uW/s+BKa +zPwR=wXx;,]T^ uW/s+BKa +zPwR=wXx;,]T^ uW/s+BKa +zPwN`7#Az^W/ gf7;<`Kq TwP +`Kq TwP +`Kq TwP +`Kq TwP +`Kq TwP +`Kq TwP +`Kq TwP +`Kq TwP +`Kq TwP +`Kq TwP +`Kq TwP +`Kq TwP +`Kq TwP +`Kq TwP +`Kq TwP +`Kq TwP +`Kq TwP +`Kq TwP +`Kq TwP +`Kq TwP +`Kq TwP +`Kq TwP +`Kq TwP +`Kq TwP +`Kq TwP +`Kq TwP +`Kq TwP +`Kq TwP +`Kq TwP +`Kq TwP +`Kq TwP +`Kq TwP +`Kq TwP +`Kq TwP +`Kq TwP +`Kq TwP +`Kq TwP +`Kq TwP +`Kq sd>7}P*#x{scwu,1ܝ Σ1XwLhЪw5Lj Øƣ@9Oh1KоcJBaV"&Ўcj$(?c Vs^QWu+„zW+Q:WzW/S/su2/à ^R:Oo=N&Իz^ܷ;FT:6PIulwcxH3`Bgԙ= n:ՁzW{BēT]=Iulz{DLw:^Vx:)P~uR/:;1zWwcZV(R]ݥi:JVW^Lwu:8yGQ:P;u>#Py3S:Pku:c`y#gU:P+u6pyGW:Psu2y'?Dg\`BԹ?(uηթzWթտHuַԙzW7աm_huՉzW7ԑ-:PGALwAHQ:Pu:vRNo0`BidHSu ~UggOT']T' `/>9zW8.'Q:Pu 'Q<&~C Vpu\XyO./u0_ N.}h=ջiK Օ-ջ2JϞR`xVvuK] +SR fUµԿk2ϥp)_=7R&uVa3\HOO5P6(NW Q+ SɠuU_"˘әEp"ɘ^M=\C;D?-\QWP̋,aJg4zT >$Kzq~"ޑ!=8O^eftK8&έW'x͑2VkS +,3i +^aAq\UW 7+x]a]qZ܃i~V8,Ϊ<Io'2Y嘺8D_#c<gTh b:Ws@cP2xp,g8Hgzq:ۓaó ӥq6ەQ1íq2ۗA)q.oۙ119q*_ۛ!Iq&O۝sYsq/{uui=(64{9TyEޅ^3k1c I}42k9L}Cމ>[1)(20[9DAލb*hQ!aP,h+WwCwHSI3?]iv%fX"?/57J*kkUwGʍIgi _Z8),Rޝ&+b"M/,UIE[Rj[%e§>`UTߴ Y8EmR'|b8,I=Om6rr3ܢTЫr['H@ g鵞"Oe"'Uc2X{-]_ >R VxFnSWesvS:QgnY;z6<`^閞K: Ygny٥z`~鶞C:XAg֐nttgHvVto'okI7wNtwIwFt'okJ7x>Zt6,#o kK78K]>Jt2 #o {H7z .ҝ[t.$=o {I7{?nKt*(=o +{J7];n{-5`g鞿St'}I]#/H_*H7ҍ]PEJH5@%޿"};%/դtTSG8.}1*J Jc;hTwkMJ!}#Mz4Hx^/^ϥKgҷ>J/җ>Ko҇HgJ說+ BW"GsWgkwG[Ϥ»%[!cWk{M@ba4ҋfU @hc3Ml1&6f @hc3m6Ff @hb3m166f @hc4ml&6h @hb3m1&6h @hb4[01ƧMTq  q q  q q  q q  q  q  q  q   q  q   q  q    q   q    q     q     q       q          q                                    i@HDAiiiiiikH(֓    iNA`9iiikݤ(V   ykͤ(ޜA`1iiWiK֒ ykH(ޞA`)iiIV 9H5B'gXH( HPA`i4X,szieH` 4VkM(A`OiCk-(A`iXVk (nA`+iƻk(nA`kiFkɤ(nA`iƺknA`iIF IPskq(:50`? 0ȯi3X! @:" (G04P]]Kf#$wpf0` pf0`wf`vWm&wh`jmvh`bWnuf0`Z&uf`RF73*62G4jTjthjjyji #`5Mz/|W| ?)_Ou}VN^ +YwC: sN]z%n-u& @[nSTԹdepO A= ~w}u:O*JC V'|S/GslzxPPG9-:)[Qg;ws`_ +xVϫ= uf_SUun_UuurQg;{=uzU;}uPg;uR8uTg +{XuV ;xuPg ++uR +Q7@9W;np{U_U7ޝ[}=NݺW;w~u㮠!\5WmpkQ_U7J[]K}M8Oݲ g;v=Euî)5Wp[U_U7^][}]8Nݪ G;u}u1=WmKQ_S7N[;K}mx]ݢ ;t?5u9=W;U_S73[}}x\ݚ;1ucb50/ZݖP|J~?__{suK3uG#ය!~ +GnR#PW#_~S#wԵ]{R JKwu!Ia0Q^]<~6W!O5Sw`cu aV]<~6U /-K`CuqN]}~6SoԵ[`#uF]y~!6Q-u!7`uqX^]u~%W 5ǡw`auqXV]q~)U' +%)`AuqXN]m~-S'_vF$^;ݯXa3l5nUG6Ivzx@}dl3Qnjԇx2T3ƣs`zxX}pUOO#P#E>;NjH}xSO.B0J=[`zdO!b0B=W,>CNJEԇb)zXH},)R# G b9IzXP},'T% ljEՇ ribYizXX},%V' G +2Ibyz>RP#g +1bPSЪwIkT +@ /J@S,zZ +0S}</\zw^T saxJ8W0ϨW apzkE}ܭ^Q2w a/=pzcM}ܥ^S4W uaO]pz[U}\^U6תw Uao}pzS]}\^W8רW5 zK8E}^Q:w;,zC8M}^S<W+Lyvpz98W}|N~>^ V?WoGՋuz/0CE +_^ +W|SWW?7~T'?~Vg߫~Uߩ~~N??wN߫WԛW'E3=SG9uR> +pz3:1> ϫSpunNTw?NyW8M:=g[Q$u{n|xW!S}Sp +uNPw=\NꦇY]p:M{[T `guõDnxZ)]׫SuvTw;ܣN~fMp:]{[T `'uýnt[1]}S uvPw9U# mn𷺌muSૺ}u>|UWwu6.#pK][6p[]G໺ +}p_]H೺ԍ>=x$G]ԝ~[𳺔/u QQԵ +<%nblQ7VV`z[݄Uخ.'^>+vŠ'^=~j.(^<;J(^;*.)^: +죮)̯^9^.*̭^8}쫮*̫^7¬m.+̩^6Œ]+̧^5QlM.,̥^4L=,̣^3,-.-̡^2 -^1Y ..^0.^/¨./^.@n/-@/^-@/,@.0^,@n0+@0^+@0*@. rFCAyB%,0#o1̠)k [ +00#o2'X 0.èn0#o3% [ 0>hN0#o4#+ 0N(.03o5!k 5̣Ъ0fC\ }6ŢШ0vC ׫[0~̫pq3o8\+ש0U̯pi+o9\k[pa+o:ZYnpY+o;ǫ[NpQ+o<+ǩQ.pI;o=kϫ[ó죾A;o><^ã짾9;o?< [ý^Ozvu[vWܪ +mு9=E%QE z'u?x^^ޫwSwez+u/JY +V|Tw Ս{F[uIW~Voꥀ?&z+EnQgEPw[Ջpz3[Q;}`_uWN>=չz:<SgG nzCKwQ;sauxV$N:DŽ-1:^VW'ԛ|pzUXYnU +몳 eaUu8^-5gׅթ:S#J4pzgXGeV/ a uB6N1ר20:\fVkջüpzyU\Woss @&TH=@̦N,zKWJ +1:buVS0zARP3 +(EbtuBH=JN'cwq`421: 'T!xL0zMHVCbu]TN"NJ)`^ѫ34"VԣENswN=SO:w̨^/ +uT=`\Ӫ'ky`fq:mL2R' [5z8_1QO'BQLuXL=l˩sԹ`Iq:S,8V +#Ǒ4z8J$WoǨsyuF=y<;Wg`3:9l?QMzOV )6uN SC գOt;0:I=|N|H>ߪG4UU=S7:pz4V>ܧ^msG MzFwR5<=ԯ u} aQ][pzYWU+o +g7v-k]GpzmWP!\Www^QfP7x.k@^ix0QZ80zU? #wzK@0zK_vA`]G a)a?w,DUOzRg-ԃ>[R,uWSkꩿG]ޢ}W7Uu'৾g6A} )| `q~|#@1 +endstream endobj 27 0 obj [/Indexed 12 0 R 1 34 0 R] endobj 33 0 obj <>/Filter/FlateDecode/Height 2880/Intent/RelativeColorimetric/Length 201876/Name/X/Subtype/Image/Type/XObject/Width 2101>>stream +H׉zH$$K@Г ݳ_Դ\VT)J]}W Ky|CDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDvt~#DDD'V0D+=+[s (*=S"""*Rrс*=RHDDJ1V ]m=J]""a*RLDDKw*ʼn+g#[(퉈|K""ټ#^A^bK ""j ) n " +7@DDZ8T\8x&ءp~/N=zkr(}/DDt s=C!"Sl@0^)4 J_X!o6/Ah\SFBW;7XQ @!r DDTW,<m=DDDG\1섅ҫvC7("":! |tWEDDWO1xamC:p^bH„=0\=@DD*_ I^8m&e48"":@dNR:vC`Ő~r0J_ML2! iz=z Kn DDCUy!yn(}qDD4rȐ N,$lD ܀h؆C iT(=-ipwGDD+ q1DХuO^!v7""~d!*Cn8Dݐ̆GDD* bPЪM}zte"F n DDc=ȠACL }lBeDp! o&ndŠ!ào ~PAsl "'C0\HdJ$J8t6%\%C\ "\3re)Zpsj "rɐ 8"X臃ըg@DD;3<1`hBJ~D"pЛ oY2!M LXU .7䱡U$*4,df3BCDmnhaC`yD1`Y!'S&&4=D P6hT" \0DℤE~1BG \6< (n3tJ! q&$- +<:8rJ! $Y 1(`pXnGZX(zpC 6u84C.t1,%.(VW#,=(tX +9n@DDz;S  <,DͯG[,>(tX 94pvl "e! "^cB2ߍ\X|PnuCPKZЀAxBH|7r\!M# v7leCk%"! mbh\.+JpÑ<8hnX7t2 tk%C IddŰ +>}Lkp  nЮ Q\2\dXJ2DƈBa@ (CcK!7 ,:46""2%g(V*<18`jAJA/~5W!A熐 V6jP؀N 3dfɰސ!. )0kOok8ݰ6n 5b pAIL,7|p찥 7lpAaCk&"}f j3d؈  5<%8he9!`Pa++6l0np`̨a.pQ9j ":`p)0ȰT""+1/</H.X+8NċՃG bnxuφdž`å@Dth5CMGW*2Јa# +L[׏?| `a o*7Unٰl0j""RJ0ÅgAY^Wd"C ]/.X,H(h8]'&$ ,\:9Tb`0\,P#?tQ*( ,vlC n- $PI [2^2dNJ 5/lZA:!F?M/ n`C +8X73n0l3lxa!0k؀3̅6d{G *1`^`0n2SBV>UpnxocOmÆey+@Dtp.`PafPaQa Ã# B +&VM@xCᆇ 6nٰذl6j pWC&"a4Ehkc0ò2ú2CE.}2bh ` ݿcRpB8nppaúbòbUܨZej ":rp嘡&â"ʐyHN1H0H/-X*8Hhf~P񰵃+ N7lxnذذlhpNffXVfX3k + <|V,\7'5+5,]5PщaK 6dXTdX5dhM ~P{rƂ߄ +D6rܰC<64jlXUlXl07l@ DD']3\[3<ݚaYaݘ2F[\QdiHr+u"4M(A n}os_8b^ZPVNpi|w9`ˡrpHtbCA`A&pKPuREQU13܈ЎfH$'Pd1 bbJ100/(.XNpiiBw9a؀n॰Њl8SEQ7YІfp̠ЏdpĠ0`^ZXNphvr;Ђ0 ullЁjhC5H54s5 5PE]ef`dfhG3Xd@3PF2!"R`xscuG0& <(:h9p8$pЗPÆvdP`H EQW2#C!@2M2 #L1$yAq 6& =ՐjTjh7#( +  h\ |P*m2'&'b`P^`\XTLp\lewD ! `!ɉq`è͆~`COOl0 |P \ _T j 4PE]N ]hl6y~Qd(e Cn@ VQ & ;)}{/ԁ!lL(A=p;0: P ssf SS l l6˥"! =/͢H EQWo7CK w L6|?(f( @$àI 4yC ( a {|txsЈ|x`v`t@9Xp7n{0 l00l6J%PC> +\.ɠ5\#5PE]hk -a@ C?>a" anİ,Űb` `^oB .AAܰ!ݰn6XlF6G6z E`CA Ѝj<55ͧ(- M g4C!y y0C ׇddJ Q_e"փ;ógVWV 16T# !E~"5PE]N ݙl6y~fȣh4̀d3dXB26@ [,08$1֟yŎ1!$$~A:l7<7 K&@ PPF5A yL ݧEQK1 7p; !P3 hNCeFu M.ݽ/9L/G/0.h+(&,_N&"փ{˗{ [`:còÆ`j6( n'WC +H EQRР E3tf f2 ` 6 [ۮ58$4o եFăAaqp`afZԀl5P 7jpYEQ1k 7b!3 f 3"!FǛ@'O _bxf[#a0oBBAсA7o^v pC S dj 5侢L ׏(ul3\fhN6CWWw0Cɠ͠ɰɰd1)908nxn@6li6,lPj`l`j6 +!ՕfREQ%- M'1Cf(bd3d~bk.ã# $ !wV@mW(B>p<0;p9|pttxpܰ n@6 6,. l@5@ IД (]2YhV<4CPf`dH2C; W޿#çO Ln8>j P4g @]ދhUWp Ɏ11M˜{n|?9{WTEF05`Aaa!2ܐB7  668VÉbj4@j(vd2s ;!!2h1`^`\`ZVR0 O񪥵ɺ + EfF!  ـn  L ?ޝH EQ}fxS13IFAa~-A_,/*?X4!!`y c9tȆ"j6p5]a_EQUrhfh`f8P 'ޒfp&C6 FAAaAzAj[AB<_Y{PFh ! బ09n@6L6h5taP[L 'A NjPGRC)4(*f7h7CN4&`b2h1np0h/ZVPLk}Ǖf\ 9h8h7 tPGN9ծFS ԰׏(*Nаk3v2 C73$C 2b`d1 Kk d/!$4f tP0 -आӻVC(ګ)'34 glf2tJ3  H$Ű(p۷ 0\ZTPNWox*ɘoaEd`C4l5 ": 65ٙ J 3ۥΞSf2f@2 n0'C,0ɀb`d1, 1|?" `@'VtsmЈ~x`vr`pXpPnXB7  6$1PjA656(5v}JaEQUrfWfد̀hfhkf8f3{K3\?f@2ANHBÝ;wC0^0`u3* +E9p8Xl`na$ >˗]Pc\ mR J j!5PEUG5% Јf8м3g(3t^df3 @P8ɐdb{UǂBB(l"sZ fCޕnX`eC&blCPkxpS`jhfj8jhjhQ {$(b0C]I3h3.g/03\f3x>d@1ܖbKA+ +,P|vt`rp0p YƆx, +l}^app*SÅwj#5PEU]5hff'dN3C4C_?x`( dH$rcNd@1b-rk[A9b_;@M(Ap=H;8h7anp`X!6Cq@ }+]L T  54 5j/PC ( +r4C;(ᄳ33\F3]n#X"9J#'bXb`x`hAPA)ڮmІ|0 px$ܰnpd8!I&bH8npἳNr5;ajհׯ(r  JCfKhn0аp4O$SL09Ƞŀdbxb`^ZVR0 +ߕk-P|`x`v0  ņIdC6N%X4 +|^{xhpЍjai5bjhjh8hjhj3PCj(ѠPlB3h. .Ñh,Ie1 t L @C  a>?VdC !tD:09h8nX[n!? lˍf3d"vA P >pTjhvVC}5( +s4C  Ma4C[{GH3t .‘X19cd (Z Ϟ!678$^I|&$ 67 +)cL~jrb<7ͤFX4 +|^kx jRF Q Z( Pg@QU9Vnfֶv02f fv{@0T:͍ONMg 7 2}! 768 L + + +u{aCB鰍t`r`p`nxŚȆX.Ix4^{xhST cB m\  65+5Ԓ( ЬppL ] C.‘X<1JgGs@囒 kR HW R + 6ֿ f*!^pX_70ɑt&/^d p L ^|`^`\XTHf,-Pz`v`trF8|bkK1w K\_OOM岙H2CA+sg~xPCPCTCPC]q5(PPo7G 3C3AmG3 |*K8^( y;FPtch%C9g:w4M(*(*n^7￵9طykO{N=`+W5hmhuzlٝ.`2ĥd1Q1ܽ{oax!xsZυ^lVD J@, {wR7a7(!y.f5zVz+/|"5|հ @ SC>mL ,)a; %`1C6^k0斛=>`4[v"21d@bMŰ`X`/p\ X p73{)LObJaq6! q`Cq;vl4}Ύ֛-A _gSCMD {*PC UC1GC ,)aDf(f(̰Gfl23\3|ffFj;]n@ H 1,/0/`.-P+N൴7?deAayYpφbC8 }^iY&^ק55|j$RC#R P5Trj(HQ ۔b!aod2ZP̀ 7 ffhkhub;n#QD$GID" ʊ  +"$p'qY%.lL%Ć ʆ$bC4^[-&AtueWQ5jPUeN ;jcj`XL  + + ŀl  ;83U4W -zl.Ch a0%'  +VjUJ xtrpX]}u= h$ }^aYF^ǩ+NJ@@԰Aj(j(5b5P5Ѱbr<%4fHd2J]^P̀ЀͰobZdfGӧLfty@( C 2 1 2İF^\ ZV1!C) _Aᰶ&v}1&0RD< ~tجfAtwv5|Z5| +T"jcj`X\,S34P34 3jdJ0B`!3546> Wf0,V`(%0aRF +Ó'k8)H \?(ǜKqf+BP=;`:9P8=y#p P*9E#`b2JpUOϜnjlCj8pH {v*jUSAC X,+ˊ|lB0C15C g +0.Woi斛]ݽ`4[lvBH,H#@L2bx +b` ^\ ZX?)Lii*Axvt r8 7<%nX7da +02N &X$ +nnVz9԰ PԠ5P5 +95ՐbXWV3l̰P$2CiJ./Gf@hf@hfAf8Pt +pvk38]?Dcdj(=2:0=ÑD _x-pTQ9V9)AP=;rp@nx|c1rc4bHz(HĢP[,TSc=UC UFQ*rR@  <_ bpY@PPfЀPR*~ˏf8 gϲO7V`8'"ì D$uN < <(x'dofŃ  +M G w fg&Fөd"v:lVɠeQg>Aj8հX  X H j @Րϫbrf7C APf@hp (2ÉS_xKz3^_ <&= H O=#bxb@ `AB ?r6!AW֞86lJ%h8y.A =b5|yD O55ם@j8 +j8x@ݻ@ H *PC "PA ۙX,+ˊj "3b3#3 4Hp02C-2F0gQ3|#3dډH4LG'goa2,Ȱ T F?W5C ( gO 0nLOMSX4 +5حQoΝP!vV!5c5JPP VCbf[!_d e*C6C521d:0̠#fp<^?6C<JOLNߺ}Ȱ H /7791 0yj %BɔfBl6o 7"[3ӓ#d"z\NH W$j8jCj8V{CQC%RZ*5h GSbX[@ %`2C@Ͱod#ǎc34~u翸x 60#@254<26>15=;7?K"ëׯ911Hp-oCeۘ) +Ar7%Ăv멭3Us$ סzG^D&''LnM*! ITcHc`&{bFyoLONܹ}k׮|_!5R.Z 5UH FR 5dgj4 5H@ RGTJAf4̐fP5Zhpf3edO^ᑱɩ9ùx mbx@y7۟W%Q@ 8: 9yh7<ag bC(lz N}nvzjr|ld]Ej1585YFԠ5rANA*WFåtF )A2!6 `F3M Uյu "3|2́[CwG&&gfNׂb2| d`g Cw/XɁ! X8#8nkp %`,ٙɉ;Cn"5|q\ H H uUH &Ԡ5Sj`@! !R@ 2 IА2 Y`BJ&s3C#2CG3|p6ܼr{|!,&7vwY1@y'DXx::Qx;0rq. brX:B:ЁȩZd6:Z,,5dgej4rIR 0p8.; 4"40fH rr +ZLf֌{f0x6c9õ`pC^ ,X/\` bxbJNyL;t`sCpwBu/)J o 2j\/]ۍlk(+-Z!7GtPLFT"VKNCe3 4 R$ i84 3**Vg0"3WV!345!3fxGl #cS3vp$.{80p^`C!) |zF%e9p`ݰ` dJ<BEv93Sc#H 7_"P;Z*JVR* +84PjH5$!EjpQFånI 4 3X3dfe + jNo4Y3745utRfx6b3 !3LLN; n‘h|eum]H {{1 0jA!,h8Pn8`ݰ@ȆՕxt9~ǽtLON 5 (5tv4752j(zVR295@ r$F gh4$R$f2d `)A`@ 9 +ZL"kIiyEUum]CU0[I00;gw<^b Dcq ] #5 CPûKޞf[c}]MUeyYIqdj ?/';KtPRD B@ 4`5p8\@D*%HR&484rr + +*F7E֒򊪚Ʀֶn0E0` %aa-KhleumcEh2|d8<<& -TH~Nߖ<X;Pt`C` Slغ.EVL25\5 jjhkmnj(/-MNV) + rx4rIR<KAh83 4$R e20BkW2  +Jffx>2'I`Z,+kpdŐ pEd]ځC(7< ;67VRRÂӑ/A 5jxbkj(+-ZFNQ)Wx5dd2  Z /WFåDI B/84R$er@20CvNح-L/Pur2zﲪ%KlY{ NBL2Hލ+ 2!`INo_wo-mϼOf:{_}/_?84 f%O@۷bHBZ +ɢ<i;PrH!۷ ?0<4yr/|W@j8w3NPjص԰jHT'*p+svl2uJ!I% + H EBqU4d^i 48. H3 )*Vg0-RH4VJׂփ@f82Cf2p pN`x!X+t ^0@فCfgg6ba 048فYj8Haa}am}]*YE#q;6hi5*B&5~R y<.CBC0p8Em,4f(Ͱ|@Ѐ *KerJ&ty@(+5`0æ- {#3c0å+]=}C# Sh2޽K! ,d;!kdK &v 吆rݻ33600:2<4q!5ߋ԰e P[ǢPRdjB.KDH  Br9h5PjAr[= +i4p8\/ 3hxO \Tkzl.w G㕉ں5 `uv&p4C _"3\tphx*! ?p%42^`XmdQ0! 3i2!1 2 0a% +0p8ňm6 + 4fpy<0a"D*S(U`2[mvS X*_ fظyi3;&a3 0BadIM 1d EY`ꁢCZ On`PM`aP[ !5!ci5ܾuƵdUe< 2aY&^Q)2D,*^TCq9 +@r[ܖ- +3hry|@CL4J\Rkuzb+u8e^0)W$k M-m 3ڳ#GI32ç`3 3OLM_2M0I~Gd rY-( (:p vlwfR7MOM!5 fp)Rj8zЁ}{vjhkijXS_[SGBAtZ-&^UrD\"*f y\.B jȃ +rPF VLTizlٝ.DU2Uкnæ-vPf8~w3cadɩ 7̀&#DZ L0dCnE0@с G4lMSH yp,R;Op쭛_~ᬆP 15  tQP\bKL1E"#´@JK}$"封p454 FsDU  ( + h،C ̀ჿlX")|U~ MV7FZI Y9yE%eU5u M-mv3*f`oq3`dfdŕ (`psc +@ @65`l-PÝ[_P C /' !9o1D:m&(@UȤHq!Ѱ h@j@Pw ̀hf аÛBG&W(U@Mp.,Bo2-q ťյͭݽ;wރqh &8h=̀gG2bX&@ u;CP@e lgTGC5|㤆+S&.@5?aݝ͍ՕŅ@ i)Ą8eGB5jR!HDBj b4q4`jjpEF +ZܠnM 8ht@ 4py|H,*?u@&D 4cbIɩٹa߁CGΜsk9I% +bJέ!(tp H6ff3Ahy@%G2ɀ ZBٟvpxwG6,665l>T,PP ׯL5L\8pȡFGz:Zp5fgfbcp6DSeRX(8lo/ @  ( +mx<)h /G4p2O # ظD[JZFVNح(g5'x MTi00{{ޫHE1 +IٳID$7,zy>!aQ1q I)iY9y յͭFƀ3,fG`} 2H具ItoJg$X ˈF567VW5de$%DExy89XYp,5&FUQ&J +hjE -B5H$J1DAAd[ "LQљ,u6GW?084<2:6>195=3'oabrjzfamca {fK@.w B1A +oTBB"8 ng=lx #55lnA5LOMNC5tu45TUeg&'FGz{:;Z[Zr5j :MB& Ѐh4bhºtPh2 oРD )T`kqt M-l\<|B"bR2s K+kfwaQhmI32Ͱ|~FH ^B{wDn8b(6<.a_I5l հpP`o7TCc}mueyiqa~nvfZJRB\LTDXHP[dШe2FP CA"4`j%i+bfAi  |*Dí DB3T549F&fֶή޾ѱiY9yE%e ݈ͭf_\^Y[) 3 <_ 'b8ŅW]%n@A x?Z OEjX_[Y^j{glQCg{k3PCUEYIQA^NVFZrb|ltdxhp.G[SC]MAP$P @ Eh R + W04`aaa]J  x9 nB4($e +FgZ:zƦfV6vN.n^>~A!aQ1q IٹeU5u M-m]=}C# Sӳ K+[wC3<{b1÷B3b.  $ÉN o`-#8|>E؀[D /?jxp{ks}ueia~vzjah0?7;3=5)!.&*",$(P_OG[ReiT2HPh)TD@A>ЀuIPh2 oA^AQ@"+P KCSg`dbjnimkWPTZ^Y][?8<:>033܇fkhSd3n@r8 bljx}(y<հ07sjrb|tx /'+#-%1>6:2<48@ORc2Te2 Y<BbhºGbhF ɧn޺ @ RgkjYX98yxED%$gfUT54a{gW6<|_iW |Adq2H|+\6׃NQdᡀχjxuxGlm./5ܻ{glDԤ?/7';+ 3cC}]mM:KIP$"d4Hp A XXXX̀Bb<@h D2Jc0Xl-#@`phxdtl|bJZFVN^aqiyeum}SK[GWO0G; _>47(3A B1z$1/+AÑ~=r @ Ej8@_=aI₼@_o ֖Fz:-KɠQ)d"AI3D  r xPh . Bh~ +JDYYJgkhjst L,l]=B"bS3s J*j[;{G'fVV7@3<  oH7P`8 }l~dÛ7@ jzo9TՕSÃݝ͍u5Ue%EٙI q1Qa!AޞΎ6Vf&FmM u5UL&4(ȟAVFá  =I WA4Y`n4$e +Teu M-\<|C#cn]=(m;Sݽ/Ԁ@݊[qH@HpK]}؝)ss! rgvWPTRVQUSW?8<:fs"iiyunV3ysxtt|B7 R_L7e8pN߼aU] kK$"a?Nb5vw67TUde$%Dz{89XYjk()JKIQHAǏBhBh u5 3ܡDgh _!D KJ+*ih[Z;:{ED'&?K/,.-}7042H7*e49~d ] ^pp#hn8gÏt60[V5P)Eanv75hkijxQ[]Y^Z6:",$(P_WGKCMEYQ^NFJR\LDBh>. t59W888%3ܢ2894< O#PhaQ1 IiY9%eUuMm=#3 +;'7/_𨘸zG'ӳ +hm +u0KV3 `Ats=0Á-hj8=9>>::< /'+#-%)!.&2<48@OGKS]UYIANVZRBLTD=}r@ <\ 4܂-h{ x@4|O = D"R2J*jںƦֶή~A!aѱɩٹťյͭݽC#cI,n?O VV7ԝ] 29~b ot2zM ns6Dg){5԰C%jX]Y" v362Emueyiب_oOwWgG{[kKsScC}]mM 5%EyY) qQ4 +)C 4@hࠣ[t Y1{ 4܇DBSPTVU3021sprq  KHJI+(*)y7042:>1#,W66ɔ= ?c6wt3B lp/&8;=99>:bVg5PۛkK4njb|tdh /'+YJRB\tdxhp#=- 5UeEy9)Iq1aR!R@4c0S@7 44phx'OB(. ή޾A!aQ1ɩٹťյͭݽãI,~~EPwA3|f bV ^ځ lT.B\_[Y^$.gٙiɉ1Qa!ޞv6Vf&t5UUd%%DH!A?' hx0F{F' |zh@"QhQq )YyE%5 -m]}CcSsKk[{Gg7/؄gY9yE%eU5/Z:zF0SHZZY]ڦPw 3|hod s2Jv~b/gl՗vՕ%0MM`Fz:Zj*J + rҟ$%FGxy:;Z[jki()HIQHAǏP8߂[0uoA]:8884DBSPTVU3021sprq KLNM^\Z^Y][?8<:>1_ -.mln;/_AfD f \2{?nh&7Asù~eV4| ˃*y{scmuy0?7;lomn,/-~`gceafbd '#%).&"B +!@4D7' wa4nc hx'OB(_@PHXdtl|Rʳ’1$7'V7Ȕ= ٚ33|f6d`C wP ?{jx aoJ!om,- v36?vꫭiݳE*-bwR5H !haw:ә)=CG^vބ@BB۲{uw67VWd&'Dxy8Z[SР(/'#%!.&",(NjB"4p>E=*0E 4@j]hD*qh(^~!aQ,l\=}B"cS2r K˫jZ:zF'g0Kյ ~k@?853O!)- +1%7PpJa4jxCÃ]"a{ X[.-bf'Fz:ZjK s2Rc#B|=]l,L ?{@8ZTXH4p<P]vv6VV gjEU(((9n^ D7 D +%e4hhiYX;:zxG%$gfUT76wvOL/,-6w$ Gf4[N d`>tnj8!-op|KoWWf&G{;[k+J +r3Sb"C|]m,L tu4Te$Т"B|<($ !U ^-3У9XXX4ܣC'7 D  +KH+*k>y칾`HXDTl|brZFVN^aqiyeM]CSK[GWOlʆjx=.ag X[./bg''Fz:Zj*K r2Ғc"B}=\l-M ?{DS]UYQ^NFJB\LDXPD8p@+ 9n3AWl h wp 4H^~!aQ9,l]=B#cR2sJ*j[;{G'f0 Kؕu6@6k d3|z3L5%2\~*80(jT.[_[.-LMvw67TUfg$%FGy{:;XYAMEIANFZR-*,$˃D4@%l77WˋɉҢĸ@?/7gG{[k 3#=]m-  ҒhQ!A~>񈊆 XYA4p >p[ h bh!(^>Aa1q ) ʪO>{ohljnim_X\VQUS?8<:>153YX®["ioK\2) Й d9\fù~ޜHD]ZLMvw67TUfg$FGz{89Z[?􉦺ZLDXPøA4<@]4܂u}2XXX4ܣC'7SPR@_@PhxdL\BRjzfv^AQIyeum}cK[GWO^nΎf&Fz:Zj d%Ѣ"d4pc 4FL(((/n\Bß4 4pHZBJZV^QYU]D٭뷶Ϯ֮@e?] ww(uRݽw.AB!!*g?=ɗB x,l]=|C#^ b2yE%eU5ͭm]=}Cãi4;$2n=fq @fxG7^2|^؍vn @SÏ{ +PiH$j|txh 7xhoceafl Bý;n\SQVThxwp +B  ppppGW2h`g2yyE$$e\РACPHXdTtlBRJZfVN^aqiyeu- ݽC#c) v7OX 43fUf3tXO٧Ɂ V!5l5P2yD\ f3 `owg;@C}mueyiqa^NVfZJRBltTdXH@ u5m4\QR梡<] 44`gR t5U888k4? g_PHDT\BJZV^w?xZ:zƦ6vN>~Aᑈtdvn~aIYEUM]CSK[GWO8jr"LYa6[` *>@>n`}jR7ց2aL&- xDtu45TUf#SbA~ޞNv֖z:Zϟ>~o^zEIQ^VZJB\TDHs/|`5oh`cch8˄K9xxE%dU1A[W?08,"6>1%-WPTR^Y][?0426>15=%2e%@dV 3ljGA7MH k@ ^PK$a7lomn,+)*Af$"^Dxy:;XYj3AEYQ^NFJB/KLh8 @÷;h8HH4bt4\OG@Í[wk1%-WPTZ^Y][pxd 59`pxqD^3A0ڎhh_!42X}5 ;jX7@ e2iH$jldx /x`gcenjlGܿ{uEyY) qQ!A~>Na h8@t4aB622@/I)9yEek 4<741wtq + MHJI/,.-khji%2e]34olP77}f8 )nx ԰IjX}P@ +D".f13ӓÃ}=]m-M u5UŅ9Y)I Qa!^nΎVf&ښLhPQV4هo`4]_Dqhࠡ..4 ,"&.)-#p֝{jO L,m\=B#1qɩ^1z;Ieʫ׻hfXߠR7>  "|LհIn԰7_Pɤ7AOMFz;[*Js q1_oO7'{[kK3#=mgO4Tݹu@/@%&4h`gcۏ[__M 8UGg ^B;"ޥwJ=F +3W3{ޗ sxs|6 ,a'%$eTT4\D}-m=CcSs+;GgW/o蘸Ĥy4wv $2J3Xc.o|b SSӈ>} kaK^6,S'L BT SS jq9c,FIA@_Owg{+̴Р_o/wWg;KsScC=mh8yaM 5U%Ey9iI q}{145?6C4`0F&~Av sf؃AL\B +CNMg_|wt ,l<|C#D'&gWV7465utu Cä(d9E4|CZfyaY5h@j԰ɉq.b2hP_W[]Y^RT$"48P_ׯ^xi#4p$4 Ԁa;- 0 - ̀ar4SPTV4;{>721wrq|46YrjFVN^aq)@/_~o?H&PG X4@4_ 13I~ݺذY5iZP@c10qW/_<h(-.HM~4*",8籧Dp@:NEYQANVZJR\ ]@ h؆S +h;D }; ߯KpE*N]0@é3.\rƭ; :zFvN޾A!Q1q I)iٹ%eU5hh Id +Fg.obr >4!3`hXn:EÂ>a &'x\ŤӨ28HlGCMUEYqa~nvFZʳȰ _oOwW';kKs#={wnݸv҅sgN!hTǩ*+)ʠh8 ;VBh`jhA [4H,A qQ4hi[98zxyGF'&gfUV7465utu Cä(csx 4LMO m~OE? Ѐaa1Qixhkinjl(+)*LOIJ  +rwuv2756Z5 а_ ?/G 0 aM+' ̣a>q Ii9yE%U5  'O=7o߽ohlfaec$:6>195=+'W߼mh*`qw1434p fXD$ÊQ4̩avA Bh@0&y\AQ)a ׯ^4Td&'F? psv056h(N<Р(/'#-)!аo<~AӶ[aD }:6chزDа{1q ) 85CG#]}#3 k[{'7>!aQOc%edVT<7@"F(4p'4 f@05=A' 2F:E0#@ 5 hr,&6J!94x^SUQZ\,!iTDXHcO7'{[k 3C}GQ4\|Y Gi04HI!hسEh `ןB943BpPL\RJZVNAQYp) {𑞁PHXdTL\BRJZfvn~QIYEUm]}CcSsK[GWwo?04L164 fhhf} V1F_j@рwD Bh@ۯx\A~Ɔ:̴Ȱ _oOw'[kKs#,1u,(vj@аEÖdk5mpE @*N]03.\rm=cSsK;gWw/oĤ켂j4 d +Fg8\;4L4™ 1>:0afF(4Lc14*195=+'^y @"ȔQbs03 hB̿14AshX }^Uc%ICc%v@Dc#{DQR,]e" {oD$l}aarƀjh` '=|pέ*J +s3Rc"‚|]-M /^8wf:vlۢy2֮%b4|4|рp [hXdаTU 2U4 Ch8r)-=cSs+;GgW/_؄켂K@4ܯholn!I.J`hfhp<h7 |3L9f\jjxr8 P |4 {Y :A& -͍ U W._*)*LOIJ puv2756h8u}{v4h(#4l@hX= KF@  8 RRC4,a +U4nh 5t M-l]<}B#S3s +K߼}yCcskMљ޾~hp   {4:} hahK^Nh$ jk*߽}:@CiqA^NfzjRB\tdxHyÇ؏аUCMUyL SB5LhjahpdЩ=]dR' ܺPVR`kmifb}џ!ۻa&y915@4| F-tӹ аa 49Рg`djnimTRv +BCeUu DCcs NLV/1q&hU9 /lSï5 4L0r9c@  @  ^NtuIDBKs#BCuBõ+J +r3Rc"‚}]-M /^8ӏ?|а a3B|4wST 4|Ѱa 4YNFvF95Dh8q +AKG?0$,2:6!)5=3'@wC4=ohlnm#wtvS4hypy<&f KH SB5Lr8 P ^he14*Nlkhx^W[S]Uy J +3Sb#B}<\lM tΜ:!Bî j +r@E _4|6p8kh=hX= *j {?p# 4 M-l<}B#Sӳr +K/U\> M-m*h卋0)D< }KaR. C}^&0 ׯ4d&'EGz{9;XYhiB4;аoD 2 ߃1p8N} Ѱ +AZFvFyE3p_@PhxTL\brjFVN~aqY9@í;<|g 6Y@ 4h ^$S 4Fihh`1Ԟ2PǏ>w!?'+#591.&2<4(PYÇ؏аAQA~YiUb4,hpKoAdѰL3Ѡ +а} 'O4hYX:8{FD'ed4\1 -"Eљ޾~8. 40 $mI7j@h@jr8 |5@440JW'D$47pƵܬ?Ow'[k 3C}]m'hعAu&VΆhAJjb|4hX'-~&E%eUu{h8zᢶ_`pXDTl|RJZfvn@+ +kj Z vrg7Jc0Yl>Dt4`39 @L4\a>6DIn'Z!jk*n}?Ea;KDSذc]c{{ウ`ػ"RD`!hewawQIO|? ǎdLg$'DEx89Xjk(G4lE򥈆͙=Sv)2҈I<4h3z(FD0Ch0,$hXz WRU3065wpru OLag4>CCNnރ"& ,@Cs m4tsC7;Ifa$ᝰzP n!4 h`40 + 9<4d= h8HI rwur2756TWUڿw7akW$hX(Pø0FĢah3L hJ0a0v4(kZX;8zxED'022=~  Ҳ:@C /^rp ]\3G{ h[$P  . u5Օeb@YRF44Eh |44Aéi q1o7D"as0aA@÷ 46lAÈAa,Da2.lC4#h74hHLNM4#htڍ[wr   M hE{1h;Ġ(ECSC=Yѐs֍kW.44&'"B|=\ L u !ma A0KvjhhaX4}0Y VZn&=5D ~Qlr ER:V}#W6ӉhF3!fx3E wBh5tw#:9l6gzVAC)АCÅlD@hѠh?`|ՙܙ45j5{ctԠ1bCwPҤ; +H38|g+.;>O0lȠR M0]U;4`֩sW4X9\ 34lCѰ Q qR4q4s4JP!EA4T|<%Dh8zaE6ܗ.4lеs'3 mECCDaػL?44j,GC  (I0quB@5 >~ .\Bp!)95-=#3!W 5Z4PR\TDPFC.ACvfFzZjrRb|\{ W.]`h8H hXf5C+i%Ah Q4tЉDaQ=L  h9a g7[wxEڻp9k7 1q rGC >s}N*ѐCА%!!.&pAù3 ‚  +/48pF`A0J vm)Zрaft=)Z=h4tv㺀sF@`HXn@ñ 4%hho EwR4!hlmhаa ! ($E/_FCrJ)CK%%hB4 U4+)!-%YW/_<ACxHPa Cò% ֓ HE7 a5AC3 ZI_ &Q4hаc-ai bb)22)8 uhhchȠhH!h}I@>/@ZU s v4"h\f ðzQ  ߋ;@?-ehشeN=j4D4ĩАMАFCACQQqN4E4h().*!W(5D6q4 h`g=y'h  0 Ìhh$CO4|I-C*4 h8iT@ +Vah pTԴtP ƾr}OJA P EC6!59)1>N V,[ +hCUhA>a3DaX}_@͠ >hB΀$A @| j4"h8,A=r5CDC-҉7ѐCѐB= 4h4lXa>CT;4([/[)EG DhԀh0 {bEhhk5z'Y9\ 34l4F4dhp +CCtL\GO$h(h(+304T jv4Th`jP(GCh+.04$h 4lhX0a횪i82 Nn4loIi?L]Mi4R3 _ޚ4|Q3 4pz4Lm; +i? aiضvkᶑixG4dPMCκNÓ?pi8{lmaiX4,M` aiا< GGixocm6 ߙh~ivl>4<]Gpd44,`0jLiiMó ᛑi4nx~o1 ߏL7 4_]sUi.Lñiا4l` +.> gӰhl*pbiz^{ͷGc{Gi4X3 SFak0<: 4R3 MU!OUy4M5pKe.7 t1 fӰia4lUƦVpwi:6 n?bupji4 LÊUӰNpΜ; u5 {ͧ| saVGp4\7wCa4lhiXzӰee&OwyJpEix1itCϧΦaiX4MӰqiO4U7 o4i4,ixnnƦ4=u4lYFaiX4Ipj< M&nyyvcLCu0 dcixnh(MƦ:aIw: +i詮᫮ᘺiر< o&uӰJiX4 Rϧa44|t~5 9 LïM4v.L iX}jӰآupJ4\[;Lû4|qiDlm> 6Mpncn7 /GaΜ3<9!9s:;O)iX4ZaS3pi(qpS44,k +iX4P5 4\x2yvӰi(a4,n!a0LM34%iXi84H V8P<44Valvb^OMCMl>W#p\e5 h piix4̜9kiQ\Ӱk6 ۙiسfNj< NY3gƧᾚi4+M4T3 {cViX4iHi pZ4j4gֻinN3 C4$4ׇi84i npia$iaR1iX4 L=@0= gN6 4|M; uOyN -ᬎaeP8!iyM ai h4 `3 I4\i!i8Ӑ4@iHi 4$4כi&MCLCLq!i8ӐN4lciHi 4$4gf3 I3 ęLCLq!iO8Lq!i8Ӑ4@iHi 4$?pi'LCLq!i8Ӑ4@iHi 4$4חi84i 4$4gf3 I3 ęLCLq!i8Ӑ4@iHP0LCLq!i8Ӑ4@iHi 4$4gf3 I3 ęLCLq!i8Ӑ4@iHi 4$4gf3 I3 ęLCLq!i8Ӑ4@iHi 4$4gf3 I3 ęLCLq!i8Ӑ4@iHi 4$4gf3 I3 ęLCLq!i8Ӑ4@iHi 4$4gf3 I3 ęLCLq!i8Ӑ4@iHi 4$4gf3 I3 ęLCLq!i8Ӑ4@iHi 4$4gf3 I3 ęLCLq1 ?HA44i' iOҤ4I?iH~Ґ& !MIC44i' iOҤ4I?iH~Ґ& !MIC44i' iOҤ4I?iH~Ґ& !MIC44i' iOҤ4I?iH~Ґ& !MIC44i' iOҤ4I?iH~Ґ& !MIC44i' iOҤ4I?iH~Ґ& !MIC44i' iOҤ4I?iH~Ґ& !MIC44i' iOҤ4I?iH~Ґ& !MIC44i' iOҤ4I?iH~Ґ& !MIC44i' iOҤ4I?iH~Ґ& !MIC44i' iOҤ4I?iH~Ґ& !MIC44i' iOҤ4I?iH~Ґ& !MIC44i' iOҤ4I?iH~Ґ& !MIC44i' iOҤ4I?iH~Ґ& !MIC44i' iOҤ4I?iH~Ґ& !MIC44i' iOҤ4I?iH~Ґ& !MIC44i' iOҤ4I?iH~Ґ& !MIC44i' iOҤ4I?iH~Ґ& !MIC44i' iOҤ4I?iH~Ґ& !MIC44i' iOҤ4I?iH~Ґ& !MIC44i' iOҤ4I?iH~Ґ& !MIC44i' iOҤ4I?iH~Ґ& !MIC44i' iOҤ4I?iH~Ґ& !MIC44i' iOҤ4I?iH~Ґ& !MIC44i' iOҤ4I?iH~Ґ& !MIC44i' iOҤ4I?iH~Ґ& !MIC44i' iOҤ4I?iH~Ґ& !MIC44i' iOҤ4I?iH~Ґ& !MIC44i' iOҤn +4\:i& tpM4I5ik@' פNI4\:i& tpM4I5ik@' פNI4\:i& tpM4I5ik@' פNI4\:i& tpM4I5ik@' פNI4\:i& tpM4I5ik@' פNI4\:i& tpM4I5ik@' פNI4\:i& tpM4I5ik@' פNI4\:i& tpM4I5ik@' פNI4\:i& tpM4I5ik@' פNI4\:i& tpM4I5ik@' פNI4\:i& tpM4I5ik@' פNI4\:i& tpM4I5ik@' פNI4\:i& tpM4I5ik@' פNI4\:i& tpM4I5ik@' פNI4\:i& tpM4I5ik@' פNI4\:i& tpM4I5ik@' פNI4\:i& tpM4I5ik@' פNI4\:i& tpM4I5ik@' פNI4\:i& tpM4I5ik@' פNI4\:i& tpM4I5ik@' פNI4\:i& tpM4I5ik@' פNI4\:i& tpM4I5ik@' פNI4\:i& tpM4I5ik@' פNI4\:i& tpM4I5ik@' פNI4\:i& tpM4I5ik@' פNI4\:i& tpM4I5ik@' פNI4\:i& tpM4I5ik@' פNI4\:i& tpM4I5ik@' פNI4\:i& tpMn +HC44i' iOҤ4I?iH~Ґ& !MIC44i' iOҤ4I?iH~Ґ& !MIC44i' iOҤ4I?iH~Ґ& !MIC44i' iOҤ4I?iH~Ґ& !MIC44i' iOҤ4I?iH~Ґ& !MIC44i' iOҤ4I?iH~Ґ& !MIC44i' iOҤ4I?iH~Ґ& !MIC44i' iOҤ4I?iH~Ґ& !MIC44i' iOҤ4I?iH~Ґ& !MIC44i' iOҤ4I?iH~Ґ& !MIC44i' iOҤ4I?iH~Ґ& !MIC44i' iOҤ4I?iH~Ґ& !MIC44i' iOҤ4I?iH~Ґ& !MIC44i' iOҤ4I?iH~Ґ& !MIC44i' iOҤ4I?iH~Ґ& !MIC44i' iOҤ4I?iH~Ґ& !MIC44i' iOҤ4I?iH~Ґ& !MIC44i' iOҤ4I?iH~Ґ& !MIC44i' iOҤ4I?iH~Ґ& !MIC44i' iOҤ4I?iH~Ґ& !MIC44i' iOҤ4I?iH~Ґ& !MIC44i' iOҤ4I?iH~Ґ& !MIC44i' iOҤ4I?iH~Ґ& !MIC44i' iOҤ4I?iH~Ґ& !MIC44i' iOҤ4I?iH~Ґ& !MIC44i' iOҤ4I?iH~Ґ& !MIC44i' iOҤ4I?iH~Ґ& !MIC44i' iOҤ4I?iH~Ґ& !MIC44i' iOҤ[~!4\:i& tpM4I5ik@' פNI4\:i& tpM4I5ik@' פNI4\:i& tpM4I5ik@' פNI4\:i& tpM4I5ik@' פNI4\:i& tpM4I5ik@' פNI4\:i& tpM4I5ik@' פNI4\:i& tpM4I5ik@' פNI4\:i& tpM4I5ik@' פNI4\:i& tpM4I5ik@' פNI4\:i& tpM4I5ik@' פNI4\:i& tpM4I5ik@' פNI4\:i& tpM4I5ik@' פNI4\:i& tpM4I5ik@' פNI4\:i& tpM4I5ik@' פNI4\:i& tpM4I5ik@' פNI4\:i& tpM4I5ik@' פNI4\:i& tpM4I5ik@' פNI4\:i& tpM4I5ik@' פNI4\:i& tpM4I5ik@' פNI4\:i& tpM4I5ik@' פNI4\:i& tpM4I5ik@' פNI4\:i& tpM4I5ik@' פNI4\:i& tpM4I5ik@' פNI4\:i& tpM4I5ik@' פNI4\:i& tpM4I5ik@' פNI4\:i& tpM4I5ik@' פNI4\:i& tpM4I5ik@' פNI4\:i& tpM4I5ik@' פNI4\:i& tpMuJvEQ$hu}{$d1ލ]܉4N4v!M4 ihH DCh`'D;ѐ&؉4N4v!M4 ihH DCh`'D;ѐ&؉4N4v!M4 ihH DCh`'D;ѐ&؉4N4v!M4 ihH DCh`'D;ѐ&؉4N4v!M4 ihH DCh`'D;ѐ&؉4N4v!M4 ihH DCh`'D;ѐ&؉4N4v!M4 ihH DCh`'D;ѐ&؉4N4v!M4 ihH DCh`'D;ѐ&؉4N4v!M4 ihH DCh`'D;ѐ&؉4N4v!M4 ihH DCh`'D;ѐ&؉4N4v!M4 ihH DCh`'D;ѐ&؉4N4v!M4 ihH DCh`'D;ѐ&؉4N4v!M4 ihH DCh`'D;ѐ&؉4N4v!M4 ihH DCh`'D;ѐ&؉4N4v!M4 ihH DCh`'D;ѐ&؉4N4v!M4 ihH DCh`'D;ѐ&؉4N4v!M4 ihH DCh`'D;ѐ&؉4N4v!M4 ihH DCh`'D;ѐ&؉4N4v!M4 ihH DCh`'D;ѐ&؉4N4v!M4 ihH DCh`'D;ѐ&؉4N4v!M4 ihH DCh`'D;ѐ&؉4N4v!M4 ihH DCh`'D;ѐ&؉4N4v!M4 ihH DCh`'D;ѐ&؉4w\7^E4OIK)ؔhh N9 =GsO[PiN7_*zD=_ M*#EChq;xȷOt}G4$<1|h ?īG>"iltUG4W_qOW“|h og헮~xu[<爆^}~ǀ3ͯ\&#ի'</t|!"ѣ[>v|xkv^v+A]L'_M4rű;;~&Ȝ~3o'BDN䘮~_P4wqיq`Bgt!D4-귻-EChx]yx`Oб1]{p{nt?iEOϽ)T4kM[o]у )K:>\4D+ѱ{~J6?nh /cwĊ r;_t~Z4{[WFCh䲓^Gũ ɇ[t@Xrei JK|8Ѱ]7@v& i闯/] C%b`4F'Dv|/=ֻe:dIR$i44=7Dvt10ٰ'Э~QE`#AIhhz n2csaّ0FZ3=F9`HtZK 4FìXvt/$][P!(IOKdٰLi4̸bɊa*1P 97@G<,($0߶$R-%?nO(f(Cq Q,K"AFChXU.|8`i67 FE9b)54J ;y1DKE2Ų +pnm"f$94K,Jk"Ii4MazȄfnF0B<=D10PZI MOafFˎ&|[VDje.oE"W݈C@0Qp Q~4FݑHvˎ<#)Vx"j^#K(#L(GSRQ6TDFCh!ԲCIlHP'(.o1EC ??=7CML1Jl6$i44=) \Gʮ p1 ~ e_ID7eC' !.,ED!P>h"XQfCIK|+0!@ʎ>.(=y$;W@7*] FFE"ÐC3e4'aE +Ihhz 3Tv\2 לb׽\E,;2wEQDC{cy/``YQ" +ɆzIhhz S*;}@v7ew!\6HԫU>}cP ½u$ +uR6"Ii4LAN:R@C ; :ݡ'uVv9ىIW݊1; aw^JF!B) + Ii4L/]Nv,Y ^vF· ፄ\wO$Bvቤՠ hG/o:lw[ C,A7po-x8yn < 4s3Lvd Σ!ûE3"|#ِsΒUʒg"y5[)  JlXI MOa463.u!;ua77RTtM`( + B \6o@ɔ>$0ue!>ed! ̍ %y?{7QFYo(! A~șP& ewAx Hr5h44=ddG&C^vO{=+p@H8;fn6#T Lw#C @GOf' +`X`P!Ihhz (9e1ǔpHL68O$>1QtQdfC0rdYrPrd +Hhhz cae;Lv&"ٙbxezn2١#tzٙl\${" +\ +1"aȔ7 b#dPl'4i`,n(7x4ڛF`2]Xvq2{5Rv#ٙtuCp#Nc鉤F`cS|2vu1tg;3ep +a2,g@iCeO͆8+$Ii4 %/}^v}tG4\v|8nx eey ̉ĸngvu-H0C=BpTY@9tt͆% 8$-P  MOa0.u2فd d$*d8nC٥Ap"L_OW0{Ce:²OrL.,h7vED'Ut7DQ󕟣di,E(OeC$i44=Ae.{enمq],;p#l]ΟHuu{Z F;9;1F"LwCLtz,?lOnݯM.x\l$HZ4FRnGRٽew7ljȝHZ -l(F(o.:Lwc6 uY|~~3D L%/p t$-MFCh(d쎝D # wb*;[VvJ"H(}6'҉]]z:L2<#᭣nbGh6/7 M JQ6D^;I MO:쎰}5]x`:FvLdH67Fv߲DzDHNJ03=0/ E]wG3!dfgޢH80`u UlU@".8LlN3O-FdBQʒq sV P01K 4 +\a!a4*ڲ !)+MnT N$VvʮKʮ?cýa F\% +^2L0EݮCBw/hpAPRgǀ  !ٵySɐ]1ͣn5,;I[ a7́F02y";ܫSQ atè##WPd0܇{~Nr4 ݠP +!ǂ  c˓.#9- NA+ ;l_e"uΐZub5d):=In)naHb|­W8x'@9T8n (.U cBRL_}!ҠCudUGMC%;Iu ;HWFJ͆DrtVMX ٽaw/B|dQw D>CBan#% +@А6Hv\A8H7\UȆ&r]C1Q¨ 00F9J!Ess-D!!Hآ{쎟lIB OB,n(]*0e!cBRL_}y]}bݩSv[{$[$H$;lVM$u6քp1u2F\޹ XB_ !EwL& Y +A8d$eCI !FC/FC|Ԓd7`e#GX Iq+T'-Ϥp$nXX)ȆR)}"d"} \wƹt ]!E!TywCy${ʻ\6M%)ZZZy!r 1B o;J)iۮ"-Jv6Hvj#-.05Ue"Dꦉ=\vw8$ly3F#.) (KdX2ݺEݭ2Ľ@19vJ)R ~IARL_ب"S]ewʮhمhAˎ)u+; +{d#![n}l%/f &'L}CLI:xutWP8!.4]kMG ;,;G67:) +Gj#-/p abBOAHp]wvuub5;FguY.OP/w+)L*Eݶ!&yc "Jpbnav8dW(Ir$hhe.Ȯ(OG7AvwAv2=֔κdGC#{d#y00=:uuyp]r]l]CIň˻/gfg)d m1!dp{9Qɰ XPZ[Kd +2dCTIORL_)N-\UMN#J+;GT n08]G{ceFƆl̆:._'ҐH뽈I\w]WÙX F1È;Ĩ`T(誗 Dу\ "nb"p}`'ID Pseʆ) 1Z$ub4db4|Cl 7 ٕ˴f}ɰ{- Vv{Zv*dVI ٍJٰLpavfFMH3Duj"뾋Ր;Fm } Fb`yEKEݮ D @39938Q9H8n@6ʆY + xH:$IѐeDzRhuMN} Nv:$ l:?OQHC0h"jN-VCuFy1h0(Z a)ަb0ՍM @} (NC݀(mm_{fuC44vnp캎X `g|w FQ1 EimEwwDm0B/Sqr,a7` JDfZ6?b4db4ƜuUdEdG\I$p#%]L1HCEHf"]4?uv"j5.Qh0F!F(zyk(F!os}!'dAPr$UφARL_Ó~dC{'(ŗjc}vs# ;H;j&0L3z{뺎}k2F9c4#HaTWDя?|!ǐ;G_+ɖevEi$M}b4db4TvdC d'I#+;r]~e'3ÁGv^Fc"p"͏g&0WuN5s)X R(zC`(R1CRR&,J!)++/yɸcQ4V81UT,B/" &`ѶmL[4TuTuk#)[!a[d+0e4 Npn\ʎьGv ie'\'eg$I l4TZ=~}!'/3R +" #} 3E@0$"[pmBLJia$@RVECEædQ>ތ(١뎟G dױ.Iuews= + );KmM$CVUÇ|[3}AQ!cTfb+o 1 RAt !}x"L68uB)e6I2a3$e\4\4dBvd;Rv>$ΒXvw֗ݢtɜH]G \W(\w\vgr2QXFFyd|MLEѴH1@poE8Q9P8Kss8dհ3Irsѐ- }eN#Gm`aa#3\=׃rutb"YTRp~>Kݮr)bV(=3; $Bޏޣ7A4pn2MʃI*a$hhn.89L+1dG(;"Qɀm:,;9T9P8ݐr#&RU` ULO@?O $`bU7@6xQ8TҝFP)xjXv1]]`2e'&e'g  ,lHUj"Y+~:1\5ec&F\ވw=w 7%C@0EтH0?HCGCFp"(% A(N$E!$)o'!!+TJʎˮd`ʎQdؒHrpPݰ 7/<'RM$:Hudǔ]>ʮ(αjIv1-;GF2bbNnee'A$ :);#x"uDjTI3uE|u{,}!Gn1:0*ƈʻ˻Aw'7&Nu1`@ f _=GO*I$Xn}[O#Im%i'TP$rSv(a_2P1a1ܵeFvOP"Q8Ne1:DljDbU ]5e?FXވwM-w*oL12DHT<"& +dIwgdfHR" ECEvn!dweWj]Wvm(;G}F>fndwז ɎA$;KKF@i;8u:Hp"sܼ ctă7b]U ݬʻHkEf1ܿ/B e w4p@(l$%%II*))!! +3dw"RvC|{d3V$ec#Y@i3uQp]]-yvL$u4u]5e#,o0򮫇Ayby'eyE) Q@$"x/7`,q7gp G"HR$O5\4\4lvC(C>bٝI!.!LqGA -t{edG F膀l4iDNNHfp]#]eG㉤\!g/ f #(Z(wʻ,oHK EH"E+8_Q&Ynw/%HRڀ& ATHptPtj>}4hWvL٭{Rv{!d3IFZS@2N1H^p]'\Ճ*OjP]W`WnW 9tYa]U 5AyAy'DyO`yEgd2ݭA0? ^]}- +qW  +kA HJI-~NT\4\4dLv]Dˮ dϲ}tHR:!,; p$q7IdN)Hb"DLtMh\Wqu]v1:IGjF9HvuCydd'A𑆈B7xSL Y݀(l.H$ Gv@:}C;kbuYvRvb-ڲ{$eGv+%; +I lANI=a"uěFp]M59to\W(]wUC]&0: QbFm$w.+Pސ 78mUD731>o); Q&AwOILRO0Ig'=UP_أ!s+ew’]=ˮEɮ_괒? Bv(׉pnX]UH0.DӝL47" *亯}+"rՐ{u FQ`5DgWwO_.P޳Pީ z !2ݻ[_(. Xnxܟ fIGG +3I.B}!^[v^O)DהiH9G:uRv^nHv(n סt6l4'Ld%u3ǽ+aܸa'ƨ1jH4oikLv{nϘ T2x[A-B_9zb' lmM p&iIz!hVʮT,Ӧ Kv< +ȅ#;Ib$Q7x7H މ46:248ӕhok7ǢZp]4M:HjȑF010FMֶDg`pxd,y(o PAuS00BD0}L$As+:TI@+/M_\S>{h:Ev,K)c^]Cc$&e?04<2&ewݐ/{!dG VI c0*+Yr337@ +%nٖd.r6$ SM'L&Sf{d|WVynml$ rmV8ji5}um-uh5d;z]^ .?հ..èYh@38 MtI;Cʛ$CB2E(C?wûO (F`իM% H(y=5pa[E}ˎ# ]{GgwOo?^.d'R]ju ;0h7\"n$̆y d"ĉ aZL1È^;<homi&;KVa:Hj5.H1Fnjfp=sI)  `(@ ;X%Ql8!) $H%='IE;;kkցL(;DvYʒAV oݎLuDٱ$vCi6DOp(y.f1FG~V m-j8Ij8'51j;]/ N.dX@7D9C@藇)„,n(GfpFR"V)IǪTjPAѧhx?쎕ˮ_3(0]N~xVrd%H@]Ge'dLYDFq96d5uڡAM_Ow&ӴUrj57FF Fm"F#0r{@(=N{zfa'HR !D7D +hBKDl_'$2T"5@FOP?}QQvaMd@ýecc#wl#l i^6h8FCd sr F% r-C,;V4p%Dt#l Ll&LģP0]b6CޞΎsu_jA\޻b#j;]? Gb񄤼Hy/.M[8D!@ (DXnޖijAɉB>I$$9tV AAEB^*309$KLv$V>ڔM,{9ʎ$ 7ol$:e)˦Sx,^YͦQ^馮kjVg : v`add=> ɔI2dؔS(C! r/ٽĺAfYJR!0B5@FO2Yv& ]d71YnTvtbPYv/E׽d'Io$fL4^g3d" ~ :@Z ѧ2.4wtFh00rQ$O(IHyC2lRtV "݀%kz?c'!*te8'i1"$5}$CewLٙ\vY]qjzvn~qi$F}{ZMvK]d ;2FeLKd"J&R>Mqp]uvl34ຮ ugNR}ZCj5Szaad;](œL6W,N^&q$÷ߕRD[B7~c/d$ޕD|$8II:]WC\]eDe)ݨ(; eMs٭s M.;>HeTI ߻[ &x!ͤX$ +n׍N꺦]#"Fdh,Lg'gxy_$ p,D$!<{q&IdvC9JBV瀤HjVAw`NNKd%- :H1<{&Cu*Lv8p#ݹMe'd|"D2d"dd]&;B8`7<}NH&I%H8y.i5 jhkmt]w>\Z ѩrØlٝ.D2'S3sPޫByd:KmFFtc"7"Eib0QRII:TWhP)-!dWAvkfeO:*;GDvovuLvHn`(;6n&"Lx>I'h8{=.f1 #:-nN;V¨:Fh})Y*6FvFE$;.59^Tvu nHׯ 'RH~ 'j1 :m_ \W_{B}T6TiQ]%WFA\yd0]GMs1C!=}v %6>H?%IJ4߶q4,ȫ)^Vv*9RzL] ]Gg7/;&w%}4N $>Wv +ȎIDH7)EN`]Ab6뵚^uO7R}ˎ+=Rr~> {ujj0><ƨb0Fq2p1Aw@6~?M{Yͦ^u67j.qݧຏUKWal-1i1F_0<]b;$<^I2p0bC @a(RL% ,JL6HǢP0$D$VHZ7W %j7˯kK݉"ٵPiubcFdq)c$`IOh$ pj1 :-\PW :]y$/D{qkЉTbraI11F=^#|ygI2 0E@=&%q6ΑIrIkߔ|U!o~3Gv ;xTvuR ݁eɎGׄd(,GeG\Ge'HB6Nw" ǢP]Nf1u֖Fp]su'=rvV9j:tFm#Vc4P$'\yBy$n"`#aĆ %I6HJs$y +t IkyDCm{GC<^;ٽ**π.욱Xv&6n8),;˓-H"pknfD) >/nf鵚^5 \W_{LjA\R [s'a kBHl8Ζw0DTao`y~Z#hXNCh,HB-K|1C!g/⡷ NpJ90J$l&Hb.=\6hPFVѰNDz; ˮ_"Hda~Y]s$174ЉĹn4N%X4 +}uSZugq5]Qakn=A^Q& 0blvsHt8{)oJOn" ޿ȯ''&npK#i#)NIkY K ŷ⌆ul,; !kfyٍs +ɎIedxi\wp6Nl&5G#`u9v :/םƮ+=\r+gjt5z#=hxP8N$Gҙ,)﫴gCE Q1F[:) +0J$]fH%M$ՠDCwk#7Eە#S Dv-bYEAvtfT,; bّbaq=Át=FZX@pȎH&)N%ñh8{=C.Ǡj6u=uujV[fxZ:# `d=>0'FRWޗoSn0+O De=lp$Mn,I] J4ߊ0 =ޗ]Ȯ +dW+N 3`9""}%/DvYR@v2c$ FHw.KOkp"MMNfөD<~rLVӫlomՂueB{MֹQcSKHYvxr$Ɋ[>pwSC oHQ(K%PΑtyrb|4eIRIH]jX#S%o k ;Av{deW-Ȯ[,!#1]Z,;dxԲɎ?nnFpUuScLz$ >/ntZuիV )հ) +ͰR02FD2ΌON]fʛh~RBDh DcI@ xNs$][ %U[Er+]%]}Cc ~.n:>zJٱn 7ΆFvu78}}yjrbl4N%놜b2u>uO7q]=Jp1u{u;jz, ƨ[E02c<^?Q4OIȕ_&UUy˵.w \`aUZNei96L d$9yI @qh_3s=oJxCrww|>!@PBpM $? ɕ2$7KR&{F4ez5ÛDv0}] ] 1*;/]N}/,#{*ّ# umz#ldGO$:rmV@_ Tӧ +N?FKM5nTC~Y504FzQWwOo?b9.H]ސ +E)D( B%@,Qhl@$6DR;RhW4݋in?~=Qv>r؉.`ٵ BN7]NzIdTv,)7:)O$82>6:<4]W]WqıG<@SvհEfHQѹ2QbFdAB< {HF)N&Ҫ +% W@IQH?eH@gh lW 쪠L=}C#Pv6$;]NzeHv~$ FpHqv ]7ckijP]Uq\ӅB5|\;o] /Ր{Ͱa>NQĨa4nNPtQf'a +Q &% 7i6G$F4$UIڽ)6߉jDhE3PCPPxlQqn= +#òC7 uW&~rmV8s]g{t]R g + Gx{Ũ-|j!Q3Ĩ708<21r8]/0=%&M!hwC0CG10L|70p6 Iw\rU F4pz4˂^KSv Pv,Pvndw-/b[߈P8nn$ nNQ`D{S{aqH(bg(N% % j5IDV5AQ4T;Ux滢ҲJ"V,~ 1"$K7dϣ)Ȏ";FR &;dHv9uCum͍ ueEi\Q [xy Ej F]= #F#`2S$%teCφy1$$e$ū$e`D^h~3|Hdk운sREfԲ#$;H/pˎ]IJ7ٰ9&P]N Sߞ8N]Cr aԎ17[!F/ EFgEdP bw KK)I%BI] z6Mew|yeuMm=Ρ qR)n$  n +. +|^t<>:24]]W_[S]Y~sׇ7aK/A贈Q#Ñ((uy^Z) ewR&N,ᑱq ŗ ӑ:,;lN$KuH8]Ʈî3A׵pZS @׽oTZ!1FxFv , +E;wQB_5c8p +Ȇe0J +I G #2DCΛ(] ]cSK]/';]0M# ɰ9=et:$'ttlr"\\7<8kꄮkP]Y\wҨk1F^HZ++~XîBX5 Buu676Xjxݨ]n!ujd1FAhb$7hm}]ID!L͟q4q݀Q2 ILUs`D޶ !agPdQòٹb@vewW#&')Ntx#l@']\7{ifz +.]rح>j늌jU30ƨcT.h`EF!FWa@@_8nPPbـ|e%9IN@sH9M2ѠmhHPkR]o(&Dv^vW$[۔t`n$ Ip+ubH(yI5I0纏׽aTC.wͰ3f FFHt26501R(×Opwx'IaGI$$$jΈ]m[Ffx>DvXv29=Y2&xM Dgreນd4Į3uu6jxkΔ%^0!D3lq1-6c41AJCu20B l"Oatc0Q}* ,o E!7d`wblIW JR`hI5Bv' Nn2mDBhkmxvuN5| [ ͬf@A]1jv0aĔ ,D4hnQʡl'>uNNI*}ȋѐޕE4 χ+މ(kRd'Rvt:p ?Huݝu/!םQT;^5b 0`/Lj-o""Xn HJUP „p+c}e7Bd]줮òcH3DB#w\wri\}PH5jxVC"+I3FF133Fv!re$Cpj:} + e6:8^+w0-:eVvR׹H u3Ǡjhu]wOJ׽)w݋4bu] )F=Q#@hv`ɐ&4D\lpI@f#a5(FC-ES7ÇXv_ImD܍De":Fzpc_~]!pݻa[ /f-o< Pyc֘dp!ry  $ DH$BoVCEhxFKS4Fp`e ]Lv7\MGad+Dr\7\GHu׀:.7]Cp5lAi aԍ1AMRE-r9 4IQIZ@/,&)j(=˨h⠍Nhx&Z4("Xfy"^v e8vn9VD\AC'u#uuMfB3bԯh2 ^2qdÆ [P+0hH Q 5kn.+ #NiH|.EUŭm5;ƨhb4!`4O0Z^d)s'$$B5|6;~ѲhP%pIU쾩?][dG#/ve'u. ΉHu&׵݉o{VӮbG0'AF9#dŰ t$ +"ɜjP>33jh +Q5{@va}QvSdǟGi$sDvDnɎnKU _a}\ͧu30h`41rcd.MY2=r'DGR$%J*Vh(=iׁ% 1N( saHuy v{"a׍ yxvݏjx u[ ZNf([.F3l)yy3aG $5I*e5Ԅ etDozKJvGx]$kdwGvdϣ{ HԉNlHun +k#pw[ ̈fǨ`4 +1`4'*o""h2lpI($;L5Th(:*י%y@ZS! uN6x/N$u7Fzm5>IFKg"7hnKJ I[!EJY q/%4÷un!dxAvB6':>Vw^"[]7ɸr9om51kjFA:#Ijl< i@!~uiSQe![ `m/;F]e\O|.#w5Nj0dE7! 0 ]H^\wSM loP$IP Ӫ) )ѠR6KblA ԉnqu׉l546NQh7聜"Dlf:Ib5TP63(i ٝ،e׃d7ȲcAy eDn +vu]dO3č̬AMSY7H| TIWC% 6fU& ղkee7d'Lvۼ(Ѳc\|kЉ\;vᐭ3ќ #(hS ;lG'IU* e4Eо5*5un^z9h׭ C'vojh0p Fy#iyIXQbHp8jPdHl4x)Mʮݯʎ+h r{]a 0h c)r0%C8lp'i j8(>a!3<Wf.Hvul tݯuˏ fp1b-2mVb$/v2$9!-HAI nkl4}FTl4Cw²+uuul5;!$F+1p1ځ))R"$ID顃pD҆Y$P+TCL\4pHR lk!KA4Wfse7ewn>ىyr{ q]nWmZl59 EFV?r1A)2IN$jK[ M57g4e\f{ux!83X6C5LjhZ`G1DS148f֡84CkeMʥD i6&h{c4T;4f1v֡f\#dפL5P6NД 0ˎ ;2n!4r 4h=,`:T FJ(s5CkR~5+jHNU(6R4\D4@;pKFÎ qJaʶS3Pd1CƇ]dݺW`\̰brgF :Hzlh8h{>"C )V4t44؁f=_ ;ˡL5N{`7)S I 5f?O7.! 'mh6h33vEdP C3 A6$6H찂D.ꔘ}o%f2>@`:4C0VÌKA~tg$4D7Vh%uPScP }hb +!͆1 $@ϲ  nPh  f菛q'U2 !cczw7ÕPjTvAhR5h6%CL8yD hXσ*a7C]A53ӤbjkLb8Ath8Op D Kkhٖ͐uYͰQܤRj0A6Fhx|@ hX`h/V!4CL !aͰFVraިƆqu%4tShxa[n04hp^ W54`QCBfؙ[_ @ f$j +5loBZ ' pohxk +4lS4aHX&5LHfE3ܭ˥aQC^3TD35pVò1d9{fhhXC4?hk%1HE3THܭC5$M0b0TN4ó(&W =fsLSy596 qDe3,b^k랁:E 0% x50sF |aѤl5,(j`O9:|' uBG//4\HаACÖ$֡Z4C ݺjIA b_6 *a73԰4)K~S+I(F w4|T +wOjL+*aaHP{ +nUni5j8VÀq` wF4)h(,lq"Arh|ޡ $bi<-Sf[wj8\ 5!z0fIN5_sfhKD QDe4̒xrNi9v[ԣSR f342zfIeհ t QZmG4hw֩4fimͰf($US~0j6$3C3Ҥjj`Laz:!:|W׎"WhxIAú>aP) o]5TC#5rfh+f=2qA3lR55f~dggQ^Ip|FQ6dƢD3.C $5lԨP  pI%԰AcC֜hx;B "=p-}NiJdSfNxn\fT@jh*fgffp !&T{ϱmlH-=e4DeY n0h o;Ѱ_<ϦͰf.XХj@^ 9pl i T\ k\ t6٠B h#1 /S4p2Jy8g$$s h:V,5h@3[VPCJGGf#qHM2YdD3>hcG4jd9|%Dh0_4IpͅE$ʲX\ʄ[WR 't525jhS> 3hfԤj U]DZbÌ0ü[?"-w/7x-$=ΡiiKP(B*01DcH/xC;~?zgך}ff~EWP4덆cGh\j ߜE|r +NSM] KFRɸZjQ ՠ05 1 fcP4MڬbNhjl2S1@E)a434 @VqJ6tu5VSaI5 VÄ& Аm&asf4f34o + Eۤ aK ]' 0Mb0BÕ`4ECW4|!4 brz:V5er G +SCsNPf 4(fMfd3@.fxӚhu5 5lHf`brR!2󄆛 _+ChBøYՐX=.3 Y3l=mM] 0૆zRC@hj 4mYѠ̰e5GF7[ jHAl`CgMG! Z4v!&|&,μc+k͐`uR~_5p5Tr5 +RvԐ 90Cmea+ Eۤ-aP~ +cuaDG9",hH#hqtK1C HY[!᫆ 5P4 e*3T 3azf843;wĚ9iָu5{4>h ZsDÔ[4y!ᜎHXGoĒby" .X B 3@ YP'PRCՐ;34r3*9ER͐fX4; EӤͩaPUCTA4DC 04H14L 44Y4~G}4LI4D*qljP +u3,s3Y3l$fmݺpDWU54BQCjBjfD^p= O_ݤ˄3AA,a٢(.D44L34$$@mGAjAk#{wհՐVC;JQC4^ BC$ ;P@fxŋDfHf8f8 [3ڤgZ4jX F󉦅f=6h4Tp[Aç F]hX&4̪hmid $,h͐tuB {Ắj@b@ L ~j 4H5 aVi} Ch13Z3i$a@Qy#!  9Y4xCç +nh8 h4Lm'BX:8Z33onkj8롆d"Ζ/]PCv5o4f(4C%!afG3(f2Ia5 ]fxb`jriV'ZjbC+iZhV%kRG%ӯhxpAÉŅhh*Xana0CҚ!@ OapRSØQPC 5Tzl=j0 +2Pof =19dI֣uk"hRN ;b%2KFKxe 6zhޢ  t4LiG4 @UlL<[ 5eQ]j\jU7 +f(%3t3T 3ԁ2  v4ayePMڔf|ЅjP؀{_n=L?0>hxŢ3(X($e >k%$z4f+1TYWCv(j(1F [5C4 G Ϯ0[ Ԥ-!xõ&7H2iiaA@5D=@cB f\hxEEáIFBC,$Q  3 H[V[B XI5&5]@ uj)PM AG0C0C9Ѐfv2C!cK;OFxf5i js j 6I3`4f9,а"pˢ? 4<4C4\4\p0h,B`%_U((fHX3+#opTøP ]̥Fh4RMj 44p5ijFC!`3vP o '2 f _Mkf0Wu'5M4u:;q1BÑyDYbppKaE :g}?kmj]ffu?}3M 5\UC*02 kMQR ԃjlphG2[MS=4OF F_gѺk` 0=@4 `o]])"ru+nhNͫj#5t9jhRCPC: ՑhTI3C0P gd3<3 fĚ!@<r'ūl8h`cC 4, X4@]l_0h/)OkG a y"Së5 +5`J54H5AK %a ۥJ +@7C0C-1 =bY i*a pA1 "VÒ4SÈlt1XMbh8*ppCmo h' ~hxh؅ +faB`7¢5CT5|jx3R }C'֓FPCPCTCWRCT7 +3p3 3kfD\f.3p=ӲH.S<~n@ShxGa֎m@CDCU?/YVKh<3D.ѩ,5g5Wj+06loC 2@aFVßj 5Y B +f8am2(37̐ 3; 5z̻`m 0e7aw>v2 ?{fЧlS-06kV[L=a2 *C0h8O5(09Y iV4CgHg8T j5ԝ?pPaհq*{VPjjذjH'5~b5$5i5ĸG4j4 4$ @!E!@h!'Pfd75W"3FFG<|p0k7 ~gduazp jh2 [AbMfУ=k3[L2=F%;h!B0iCC/(g5 5Ěoկffe> jY{'5|Lj@MV, 05B [xjieEPCNM 렆4K + @C@CFChp4C6Ca$ >? 2 Ŵjj:XC c lKx3*T:`f>>,682C{VWhm=oᒅ[q W gi@cNkkmcd-+-]Rha& XEf jBS7{0 5phZjF2- UZ! $G5ĸG4j43$h34|@̐f 46nb3JhyoyA#q8fx0~̰<jn76H6rtvdj[^CcS˖.l6=hz@Í%q4ܻsKK4lɊA W mfhȬ63D^P!aE#5 B 9FjVBjg5h42RCՐ 7h lD!Y!E! f 4h3df %:{ G51e=3A-ghȫCߎ)j+s>аyhi 40pn@FƩrmK uOl m`5a<3V×>$5KMVߏh|xjhc5VC !+Saz!}PBC2А(Ѡg!0C0Zs`"s7|̀) +3c3Мff3ò0n>ltJx zlKh8BhGY4|ja~es);z \=˫% WU*k7Äg%zpEhaXU}M`5rmjXԐFjC )Z Ibb4`2 0D!7PL +4~ O3>> ׌3S2w0ʪTØTC?F7]@m7Cʳ0Ѐf4h!j?hx ӄ# ZfҊs0ägd+Oxꮱ. 5j8j7 ]GZM5lZDj] RCՐK DZ 'Ѡh`3(3 7e dRU5 L4=J;FO:$0+ 0{a6ÏfF*U~-wRC`CuXoobnpk44KʮUN +4PϮ/\g4q 7 4H4zQaаފ%oQV7W0WuZ: c"P÷O UO{PWX OA 'aI]knjm.+-.*σ,4I 5(4$  bb-3$!A`!+P@f(ko;'8>\G tyn-ؠ İ M5h>sn1{hD w Ҙ 4d4`wCkhPZ Ūl^pz^ATtr;&5fHG ~xzpB \t)i릴pqPCAAa`۬߳ 0o6Ր fPѠ3j  E0CEx`Mm8q;- S w3f8fH4Ǫfx{~@ω&_KN 53pwc5Z-JhxZ}1hDC&n}+аа=b!vUSdЬJfha3tfX gL3eB U5|S5U d5ڱ0jg[9mHQ QUQ5.U԰d1jjhNDtA5C `nJJa*BXC#^lAnqL cf3\ 33oigL H TރR T<6 pw jy'G6B~D@{@-F'&2w3#eUFßƁ8RGVQ5TuTfhn }|sA 3apmR \t#qz{Dq1VC0z\NG%PRlPâPC>bQA!+Q fO ̠![A ydPfPf(.V1ZZ b %34~̀I}w5ХI!, ܠ^0 ;݃\ [ {QۇT4\ңD&2pO "} h-No9?SHUT 3yfHeF _ӫ¹q۷Gat#᥵ +R;;PrXFH:y.GUeEY)AհjmV%OUC.A!; Ӌ Yr +,6C>hP̰f(r8?P] +E1PxLo2X~[c3>f8}Yi's^VC\1jkĵ"jw{`Pmа[a;-.pDCoD}=.h8%4lQѰj%YIUQCT%4J3t%a#ga/jo 5諎0 5 ͣR {n-Zּ>ZT> 5 +(հd1j٬r5d%a0/%4,VnK`Jp$k.(q2^0I6k4Pw~ ?fxsjxK5{+ 5A3껥5N аpPEE=𽉆ެ&@idOa7aӟzhT%(oF*ә!&Rg!#5Jj1>;uI#B WX OWm[6K*C[Qq H +HE |f%5hhe4(jУaԐ Yr fXm6͠PZVQYp>6?rh5A~c3;f8 M3\aA kW{Ń`5,OA@T4lAh84'Pړ7 w54<2ѐ94|o@==.h8Hhe@X~](%qSL;̀)t$UiO0Äi~.]d5j@ބ8VÚPC?J0jlrVA %VÂFjө!ՐD AC\`+̐33,-,akBX}c_[GgwoU:·'3%K|OE J3|e4o%S45je9l>oOS+G7 GΛh;7hx.whqav kV#4hj)2DYdP32͐ˀjTS *<E'ՀL%5p6Rjc}.}QUY^5.}Qh 5,45D̩!3̐f  l⒲Jp$Zдv*|γOf8upj 43ޜWØQPݤʆ}7Rg(Vаgph8.@iݞ2ѐK 4 [7#tb!r}8 +[4BuH>rfIfcfҡ5GPÇSw>@خOx~P*@NE˭4&6/ojօC5r:*".vjөAECj5 +ruhX6=hX3hJ**.GfEe-v<'k_|k\K"3\* 034Cʛj8aTR +ijP@n.O$F%_2UH@zzDC:wU8phطǀUpj ?t(- R Rdn L3Ҧd}!pTˬS'(q:VzPqeM h$\[ njPj(l6ŢC!3̐gZmv;4PX?72ե&tfJ˾4~LtzvzSz@YpYeeRdQД]\pD] +%QQ;9gΙNaNk{u f Fjw ^ ^QY fhgz ^{0B14tfdog4?5twu5@Ǹ@ݐ8Bhp꫍745cwCLDnaC :zZkHh%4hV <a5řR R!U8TL\c33C/3ó 3Q2C/cj*M5Q51jxϻwrjظa=9 +\(x\b6ZZUW԰('G!˲j0+j/А%@L&W(  JFMft=^_ .WBf-K:0thx{Hg 03|ȿi􌦹y54D tl*O!>QՓ՗9 / ۀ _Khph&BiDX _ ފyHMǨor:lVɨi5*erA +\jАP7̐-9ňf%K*F7Y.*.H +W}Ϭ]oio}  ǎp pp#bgdtn^T#Su~e:R94a{y J=H=vzhABCq5A]@meD -"4``jkbQ!l!Q92F3 M3077]T5Ū +w鎣$jrjزy:T1sh$J܅Nb6: BaA.G4@0 jHaАţ +`@ JF3MQ*xP& ͰFC"fx/>+an>aQZTC/xGx!Ʊ!±? R3gB5)tH栽S 'CDLBCCzhx0yZqu4EjH"jRܠ7 s~S×>KhӍE5jzZnK BRT!qP- +vl4赠|@ 9 +\jhx +0h fX h3Zh2[m)piYy%:0Ck;|÷ěW }I`'!qf7C/fQzF5 TWqjV@U.u:A ՚p({.f5zVRh5.5Q P 40hx(x4dr!7/Oh*F7Q.*.H*b3عoo +̀ ύޑd45fj"j"lrl@7 2Nohjn_NSG{Cq Hޒ𹄆ٸG@{p} +B44#G[>}F(Z.j逊d*6z ssTCrݼD5|@@njxpxC[߮A5.UUGKA],fAӨUKjXjA5dg341bP=}hufG x5|̫aH݋jX̪ʊp({.f5 zVRj@4rrr,;SÓL ʘRAb r9f`h@3(`4[vGSÑhyeU 3÷̀ f8N^3w¯߸dǽyL kVX׻ _kK3QY xr"U{VL* EX W%4=<~"h. rh01Npа7moaPiHЈRPNO1kT6f!a1S'7o\G5\Ľ{pvb|p SXejlYPW,FA],fAըUb5 +Ls(x4dr!7@4@Rkuzl9."eU5z|]XS̀oi߫ G gΞf,6Tf'!ݛ/j@ :q6H뜸ʡ?  udbDhV%;LpJHN$4df Whh8=e ԐRHQ]ݘU03l0w7j.S5L?{f|(Iaٯߨ3 */WMx}=^2ga0RRDh!TP( %. 0I! MsΜ9q]7G#%RÚA̝ +UT,fAӨUJ>@ iirL*phHe TCаr&R83 d20@ЀfP4Zh2[mg^~aQqiYEUumх/1f8zs4qmC~E3|g-W5a aQt9<TCmss"rqf`_0XeGND߼]~C{ o,o|~S6gD,Nc:KF <xf(ao"N ţXݸ>ym) hpMU䮯(/-v9s6d4RWCjP\.J%85jaAհ⧠!CA +fH34~ hP`4[llgn~AUgwlfoҹ ._۟Lh2W(uN C}09 wȅMQ -۠G@JzV" H{#,>Ib:%j6tJA鴫?YDwh@>yCs IE]!򦋏}tmKbƤiiƙuȚh_3@RtW._xΉT :p5Q*䮳PWSUY^Z*,vحѠjJE&O A rL*ԐªAIBYАʡ  34+@A &fvUTVֻ=m`_ =8<}t[B34G%ݾ3)k ߈f-G5aaȺa+du{ 13_h?A4PEJ@C'$q 𣈆<4s)q3#z:pT ԫVOscC]mueyY /7'aZF^QԐ ˤR*N )!9hEB4H29au +J &fvUTֻZZ:z`8svxNvkb=h%f`h孆]6n"j|60n r ` d.畹? G[>Q).hyKohx!!)hO$Ơ 57aPBf #6L \|3 ;fX[P5Ī[uF5|Fqsο{aaqnDEA\8 +\ʑ5Cd +)3M'4OͰpj:?5MVo\ĞrD8텎=To6"X|ݝ-M u5Uق+ !NhFpO `aq:1a0,Xa!g̰ b6 fx j/[ W}PUtqs#I9 [Xr{ +ٳ[ͦ͝:PCyiqa~^NVFzj1ѐjԪ\&> (Ph jX毆h ~싆HˋB4g |P,JU:N7$S3s +J*kZ:,6(n{]cSꞺ}c_3,l\(fT6:@ˁCӇ i2@{7 'JJЀ5hM!H0 i4>sϋm6ڃ↹.ŀQ<9 = +o { +[Kb?(l9\a'aU8locfoBߴ%P>0FrA#khz bV`@ JM& Q CYf6Cݼ>d7]twj 57rfǼ5{{<.X_[]Y^Z\TbL4$*F)I" ՀhGó30W514! h30h "TPĪzC1%-#3;7iڝnzCwOz[sd]B3Ss%C4{3|~F.$հՀz jPlhb'N\#J;nY;ކ6wrQK0~  XG?z׮|tS23j>2(ŀub̰ Ͱ3lPoGP#Ew@zn%BsgG ~ H{Nlj(+).HKIN2uqXR!JB@ЀjXhPh jXj%b4DFr\0k|H,1*FK'S3r + +K+kZ:,6So`3J>O7Ho߻)6l/G%TZ =.ß }Cg \ d%{y@GFӸhi4\"h={fn탐1z2lך!/ńVe|J{1`Rw !nZ Ewz$Us$~O8A4@q#nxpqhؾu3kj &-I`RO7/ [Ji3새*7W5VݗD R$}Ώa ;w`? } +?`o尚;[M u5Ue%ŅYi)I}.NR*dRX(GdjgN8Y }VH}}}_!I Cn]wv۵bQQ<1}3uδ>KOEf3I:;/hj0F\4,O k bD`hЛa=ρ,{xyGD%$&gfWV760T]=}ڡG͠/Bi_6}{.,"flxT [p e1Sl7@`R Roi%Ry;vz7|hYr$%͌7x+o 4LN`k/]ih ]vT""eBա|Q3ћOf3{M5M@ ڞ;Mj-7rqKH]MVYŢԔА_o/wWىթ`kcmͱbr>4]Q45D18ր h.B7wO/_6 Z[; vpM#F3֞}HNIofXgrj8BհQCo7:A,v:67  CA(u A6:2",$8M"prvXh54hXh`a   6okf:BW7Oo_X*W2S_9waWn[3<$~ Ͱg +j ?V>TqJ$ՎNڝȡZꭺVjeA9}Bo~ih'ĩq\zsѰ,=,mChH!]."R$ḛ _SÏjHݜ"-wyKܙ:j)R0?7;3=5%)!.&*2<48(U(pv; ԰A4P5beаf., `h30hl <G'g`PHXxdtl|BRJZFVN^AQIYEUM]cskDCo`РO~|v +ω+cױoݙ~w)~AI{G?;2aYϴpL,5f@ "C6KZ]gQD*kW:` "Z@'A#4|CxA4bFJy44|h־K{A%6 \z}(RV^ xR Eڻv4>N>3$^`h=5F>Fx>j Z! + /'+#-%91>6:2",$8M"prtq ѰښceBbhXAb Vk@Æ,4lW7OoаچX*Wva0 'E[;.|9Tԭf63^Ͱ20Ĩav}=]jv\&e]"U2j];io +Kp7LS@0hI ^Ѱ +u˂hxL2h`* ۶Jh֣egK"3 ՛a f0,5{EH N߾5591~mW#qVv[{4eL,jij*/-.LOMNJ  +ps +\{;P [  l5C[,4#hñA4wrv{xyGF%$edUT76Id +U' ͤ?4?32)y3`䖌Cba;2τppp@ ugR,BR K %A+׻[@$CR4]40jE f4["^74L߾9uT6v~:D5tabtekԀ-񨪓d AB3 `o j0:^-Rs5@]Ŏ;O?uwuri[ksc}mueYIQA^NVFZJRb|ltdDXHPى"Ѫ` h `Jh0@%̀hX[ `.n>~aQ1ɩٹťյ M-"TPkzwwp0q;}8'll;3153%|ipHf33 5|jw6!vJ j؀Ajk֡ufʎN bR $ 3fŒU{l>c4<6Č,Y:n_G4|Ij졃"H1Y=]j&X(jDQZc`Dhf3{5Uo:CRs>73}_\Ɗ?0Fp&psFݡlE-M u5UŅٙɉ q1Q~>ޞn.'G>koP5ʊаt5y}4'h4l|[0=ׁ,{xyGF%$edUT76Id +UgWw/V6̼X+ ,]yWOLҙG'd=c LJ Q @STyu(E1^?ޭL# wthNBV>hX,4B8 hlDi6=L:; WzB~}E}qLL׉{{]",1(\ϳr3kGD92jtZf84O t$thXhnb/\qd$pIpBAScC]MUyiqa~nvFZJRB\LTDXHPafMPAAᏈy5[B:83f@4hP4lD403h"ut M-l]<}C#cS3s J*jyf-^y$?855jGհOҳ'a3ބwN®Pv~SUԆ }.V C hX) _4|)E?94^zy` /'+=591>6:2<48@_WG[ ѰѰРh`jx1hX `D:uy4lݦo`dljfaimkWX\Z^Y]"do!W #i|NʻwHKRxHJ3@A5 ɩ],º7A url`nȳ~KA>w Hv|<\' WpV2AAJ4 hxC= ذ.6A;ؒnUU@gU˩7,J (K vtwR3f84ÚQ aa=+Dߧ/OA*:H* +M u5UŅi)I q1Qa!A~>ޞ.NvV&FzZ۶nԠ* +hXаC +A747o4[X;:{zGF'&gfUTμ~w k|PHgߘI_}L Y^ +T5˫T w< &4܀B {I,i!nCF8u zCL_~Va%ߋ>Ɓ`^Wٕw^yǏ+pwjiUIGUƱAѢlX"1 Kf%fxD4ÚVF jSDnslS&Ν4 ȉclޞϫ(+)*LOMN  psqv4731644lDj4h4ȣaаN  !   Z:F&f6vήn^>~A!aQ1q I)iY9yťu M-BH> ^5)r77ɋSfX5 _q/ wJ3rԀ7E0*UáyP(h$r~%.h;:iw &!y@i:w}ġshXIhY ,GC XQkpWo'j9E} EyĢtWѾ;wF˛a\i=cvj`n\!E].!nO  +j*K s2Rb"B|<]l--L t!DԀhhPC4pj ϣ?< (̀hPUUS4.۴u LL-m\\=}hHLNM/,)"qGWw/{оٍOxgnݾKz?aQ%@-- 50<4{`]ҽ],86#(Pv)߃O$ WX&9(:n3%V{z4,9ȕ7 h8G=hYEm0*(O -! d jY v8$5(3Y4Ô k{:54tr=dVS2»obb+h7!ye%Eٙɉёޞn.NV&Fz:Z۶nԠ* +h4&C-]=Cc3sK+[{G'7/_䴌چƦֶv80ػ=O̹IDՙ$k{Aiֈ=D w +m"PC<0Py+ǴWV=HB{+ƽk{>84L# +p'/4ޝBhx|h F<vpYkz^3GmRJ%J30nIov dfQa~ϥE9Z94+ӗ.NN;3~O]%ݝmBAScC]Meyiqa^NVFZJRB\ !(@_WGаYsAРAР+hXѠA@Ͱ Ѡo`dljfaimc_X\VQUS7 D⎮n < 'Fȉwx{"&5 {JK343kH :ὃw +I;۠rl 'n r@Ȁq lwtvgp>"WBiyBqVE|+p\#.²hɑ6y)2)nQR*8(G*Qq{'=4_ǥjNmF&n]GN]`=]bQk3W_[UQVR?+(4 pT$gHlr9H9HHNMhDG1(Z53nln3Rs}iVuё!A~>^7';kKs3#C}=mM2a QA h Du4fA%)4TVQUiiYXZ;8{xzGF'&HK/*9\^US †KzN<7mhfפS\IvF+zL oWB!xP&*",$(k]Ύv6V&F:Z 75'py8(zO_dnI %1惘ٷadw!QCg6.C%%&v=t]ioLAE4`4ZgJS(Ce_$#ob4Љǔwwnߢez#58mk%.PBRhmT82 Y3L̰&߲)sԀ 7 "77l7cCkoȵQPWSY~0?7;#=@ёa!A~>^{vruvr47512䩫ocjPRTP[ + %hXа=Рh [TTy:zF&f6vN.n ѱI)ef ZZ;{q]x9{O?s&ޯSaﮆj8=vv<,C,F!Za<)zʁ~3u"5Ӎ<ղj`ٰBKJ8D  ᑷaVfVIa +%1$j + "I@_wg{Iȯ(+)*z A~ pltdx#͍DExٽ@OW[?+*3 ٘bV^2ޛHG@""RD:R 000E @QIIrn/\1d}_:TΙ+.y{xF%0Р  &a6A sаxR}C#'aͺ l۱/ 8$,@tLܡĤ􌬜j!l&9.S]>{cxQh3D3`T}A{޹}׮4x89XY  4 stu D )4|8MhP>C4fXh704X;:y,[hظyv@_@оQc>zxVN^AQɊYl뀁GwLUIRW5jrM~Р5w nJ kE5jrـn}O~†瘡PPL–VU{6|O/|?+7wIQ#~?hx|4Ɇkh b"LQjXxg(*z I  !(rʠBQX"mh5+Z(zϑHi0먁9HQ%Gu'C޿{[tpANu!ZauUEYIQA~NVƱÇbx{ڱm˦ ֬ZԘgd0W@oOX4M@ÒFa1Јgbjnaemk|v?"`l|‘)i3N,׈$ M + +޹  YU\301 O5ôw!Xx[ ZaB7H%:PT=t={Blx K^R tUw"x A_$NC2hxE4FhxV5jt\,<(k&Y fRKZ!^ڈ5 |5<:?PQ#Q~ +IsR*Ţ%E'r2K=zp|}ٽsׯ]`okceinfbldhhXAAٓ04 fhFOJa.   M-ll\<oܼuN@_@оQ>z,#+'ZX+oA[u uwꦦN=('z=arZk)}o_ #5@z֡ ԀPDC PP(|B,y0+m흐ó=D+#4_!1Qd&"ߵhZhx j*To} ŪG,1^YBV2j(z9@ HHDub y3AfU0瘖{ߴHaQ^rJ b(kkҢܬCq1QB|h4Yb5A@Ѱ`>Ԁhh j@4jV4|LS + w@?/@4M,,m]۷n޸~j@}]-M @".T sX4̜"4dѠ<РE"@CcS3 +k@7oݾsspr9qꌧYs.]~-*:.!)FFVN>PhD74utf݈vHj G t^ ՕE2ٮlG7PE12p͐ 5 E%\57P$=~_ʡ;hxKlHfa0PO}GTY*+-(@!I2!l n'I `\P X˜ 嘡_a~Vq FHۃQhkinVWs3n&'D]vRp9_oOS'\lȠaR}=mM u@a4Wa8hxWq0E| 54u[ZYXA!vή'N{ +v5zL\brjzfvn@XT\RZh +Ǧ;|UQ1=-&f]q:;PC7U}C}4}UCzaGb P (rJ^J938 IW2${`l 4TaRM=EwF5λ'dASA;IU7@*1J"$g&W '--0)0}o̦ Җc;n80vcvP$3ӒcGFr?}QCٵcۖM֭Yz!Aa ys2h{94>2h?ᣏ jZںzK[.[b՚u6mٶcמ};nv򴇗_!ѱ)iY9yjAaE0Q5f<4aE24Ç j M, +Whc\N>x+עRndd +Eu ljXw]{'k}K +3LMX5tQ5>ǁ] P(d؀}ϸ@@K@Ȑ=1Xlں[ 8 ;:2D,3yʠM  ESɼYjo(a$%bQHN >9%0J|RI)&k +3Ldk'NL۞,޻uZVҒ~~nvƍ䄸kW._ +<̩.Nv{wܾukW,L hij.Eü0c0c,4̓EbU5 M-]%ƦfVր7n޺}vN'N{z t91qɩ72s¢)[q?|?0Ȍ;nOɎ;X3fP_{SF XBF'}O r^SG'CrJ*!4I$OLRe5D IУ0tX40"a7M#6Ɓ'}10m-R4HĢ^^NVFZJR|ltTDxy>h͡ڱm˦ ֬4XhP4,\ EA fN f@| 4h1h015\hXnæ-e8M]5荚@*c1^ H# @"gO4ؽDpϺ+y}k9^y;q̹ zF&fֶN.n޾WBGވOLN+,.4 ZݽXjH]q2/IB4!ETQ(G {8I++A %6` }%R1P2Pf(^M-m$iRy&a^$,L-,IhxGC`O8>y3oOq|WTU}(?qJr3,h`+iS8bAőAkG[KViqa~nVFZJb|lt@?oOw';kKsS#hسkv- u5U͛6()"֯C4 +4ghx аa%au eU5u -@Þ"4=Q?08$zdtl|RJZFvn~aI٭*!zpۚy)}P3EDE%$gfWVnhlnm542: ;xYafgs+ 2_ #8-͍zPC5s%2'Ňc)#`3P a9[;IawNN!`? 8'G쾗44{-`Iw ?Ɏ:- +15dq)&O=Ȁ;|: &fXz 0S35a1B0N Օ7K +rSb"C\psv036Կt;uu5շnU޲iEhаd4+hLAqM[nS4 M,l<|/]q#&.195=+'&^,4CuqO ^7ӿ`M1O4<'c#} aTC/Gb=IlKqA1ԓs@Z hlni%a_~8=kAv߫A,qfIIf$+B{j!Lg +#ό,B`F=qG8$ԧ K:~䄉#}axkAp1HZoOWG[K +P\s#2ZH_oO7'{[k 3#@ù3N#h ۵55mUٲS.VIE;"44|JаРMCS{;/o;q̹ L,m\<}\ _X\z ^ B݃hҘ'sM +Lh'{5 tj4W!!}Xa;zzhܝcC4<Vl1JXizܑ!Q}tÊQW b'O2f$hB3tz r3,OJ~QF '3G!alq؇hhmnl4T*+)HKI|@ȷ|a׎Z, *@+/}'hxg!/_a  *-;vpQ?08$zdtl|RJZfvn~QIvCcsk;wPq mzi H lɅQ {W"Q|>D bebAá<3'KX (Gk~Ƶ ϤvL? {jpAt@If$aE`A#' H's ǢAlİ aqSpz; k+J +3Sbx:;X]<4{ :Zj*ʛ7mPR4|Ahx# 6lڬhسE ƦV6vή^>~aQq IyE%7+Y4y7^/+͞vEInEdGfj'jw/>>Գd=9!DzL=3k9 7Ai^L ^w1X@ Byr'䬨 fhE3t@ a)|R:'jsqmnv~5BfS4t4 7K rSb"C\puv056G4<~C4hi2hبhXѰa%AòED аz Aú4tt 8x' ƦV6n^GD%$gjM-maxaj$9-NHJ<5?٪1iƈ:ډ ttЁ~9 y$b QXή@G19>^ l~h + %s9 +@Q#c-4 KbPSUh(HKN~jЕ˾n.Vf&.aN]mM_Q]yTLu6%3333333sGdEVYEvUdG7QMEQDf6'c Vh>{` +;~ѣdhjPy@ßz ( 9F5z&M:} VZcbjnimy&-[cS2r ;wP O"vRJgE*Muf{=K\ D 5D hxih=aD@O&DUsA0"4Ibs ^gjxpOXhM6G\?c`G.=hYThokmeajbаd"Y3 S&24 7:D ) <QE1G4 j0\B@Y ,4ZXY;:{zGE&$ef(=|hʼn*hu|c0ԤRi#-*k{4h_RnU5ZΞ!jbj(Ses?؁r'dw<15'O Qv 󐬑QfpJsO*+- Ci\n'DtP"dg*V7TGff?{(W}5Ķ)p׈c- 'k..*LOMJ puq04\hX`sf#4=v̨ L =hx-@   ̝7EM,l\\=}CB#R3s ŻK$4\Å&T9|`}ѯ&eQSo)}=9UCiJ BHɉ(Bg!ړpsjhxܧ pWAvRaElD|C8!'.SΝ*씩=;d(cf Μfhf>tTN> w%4 bj k}}喋M 4T?V^v am q1Qa!A<\l[[ hK94LhhxCzF1^4hhhhxG֙Ysprq а}aCeǎWBOLJ%]v"ڗ}ɫ_B ۫>3hP%ZnS;䑿8H߈p"%osM;ߙa-54ӎvh .pAĝt@v:%23 U K#зzS#E,##V"ԬS 4eoHKN%(o&ONl[[ hO`C!CLB 0]J2 UㄘpCJ3\쩙<ӳ;d°X4cK-0EhYAC# vde$n }[kKsӵkV@4|'#43Z5^߯_9U4 c4LE4}ɧ}hXh0\oy&-[cS2r +v4>rl=ҕViiH?PA)5|G p)QS`w E$ %4r3TאoD)b ԰6hh*2}uL,HUCЩ4@2p343<%O=r=AҶHMFCC,pp}%B@CfZJR|ltdxhp aRF 3hxGFCU4chx5% ӕhX`jnimy_`phxdtl|RJZ&Ѱ@)ACԺ,wM L33p4/6?:ACo~OL mpCr@:8TOD|YIgs:a骴&%~14N]ُl>RΆ: Ƞf\3|=Q,0GF#nbӅsW9vfe$%FGx{8Y[Y#,h90hqcG0x+5N2AW C h?ha KMLͭm]ݽ}CBãcR3r wb ^wmO^ie8wj[SjMH (+bdPiYޓΑV{]co 2ƾD :ECo=.F +B=#$T= G Ou%ϸ"~LCa=D v"'5'%^3\xAX +41244764hؿw 7{[Fjrb\ֈ^n.Nv6-4,?oiChhxW0 5`h4i +a9s_a%kPHXDTL\brjƶ܂퀆24Ԟ4ohlfh Hߥ[jৢN56 8ވ |]g"fkdI^CC7rAIE%4~|TIA?9'UfubI8P t _^xO 2`_ @[F`bCܛ5 롡^hhᆪmgV9I ̆)I1 {<3 /04A)i4G#lPx4dlڰ.=-5ѰxccfN:iFG:7U@óO+4܃hd G!F D4چk 7i;lg@CWBà!F !NChH4,&4۰АWhό:ͧUZ\vA5k5T)5hT%:47$M݉f3 + rx/x4i'*4c5RCM'PqXn}rA"C) qu +pE΢ V >4MC4LF4&a@= /#|p43~ZpBӈW  hh4?yg R22 ; +vRg&3-*~hk:;/jAϾ#\~fJa||ѷ6_(XM?jޣ}No_T$==Y}g$/;ZNʴY j0q6A 9mf2Cg}1֊: 64lѰ+@ç ӧN`»Ƽh:h@=^$4<#?;upC hip4\憆[ 12g o3 'O>3&.>aO V(4lfCC: `1y!WaVCY t-j@'7@/zL>6o5 аq5 _>?71>n"A4!  wnj6p5 ?Ï<E@CwBPDۈ  _7^~AѮݥAP/`9F jj7߸E r@tB`әHчCqlh-1=44 e(@NԠĩA3N75p@Xc6CgH}A RQ!  ;r [6#z5 @s>-D0V Rhhh  dжMM D;%>4|)аf + w؅k.5б(oEF[ p3R)z<%(D,Q6B7о`_ 4fZwj ԰Q ǿ7q=k #c7Cg|yyʬXFhECv F4LA4E4 :x`>whxFGÝD4<hֽg~#B4hhVܜĹ 4| aDC L'fE)юUK|zPCCjW7F? \ 1 p)fХhb%7FьAzh8(d vL`< C ?9FhسdohXаPa=DH+Rh[ᢐBW4\bFU@s.  c S44|hXZ! ѐh(ٽGPqywjhjs)q4b(OMd̠`P1CLh8ZWQd%j؜DNFp8nܸ)LN9!^@Khh8(а K̎E4LB4F4 <^=uyDý ۶A4\ h2 tA@ 1fIhX![a'6:* c64xw]fR:ŽS(@pHvX\ 1  [2T4P`2PG։3QQG7Ȑp„eSn)Р!twnss+x >=3D  8HaXg44lXа@aaG߄BEq 8znG.g5pjخFcצc:`:9t {v\p3C$>Ǵ9*莆2LFCDC򼤄ٱ1h /G54\NhVCmDC,aa@C  9RD~oNhv^T 5R Uu1݀p@9lN𗔰[S-7CC?4藝DCDCM`6[4ML&LH <3DShPHaUEh낆?Gh =zoF4; 44<4Dk65`bcK|̿d'@tb0fȵet,{ }ziG:MBfcUÎܜ5iy8p88'3{fZ4AA⊖Gå~p!ł" V4yNO P3ʪ&Y+1IhHJ0Xb-2* RD0D ""DD3o{3L)< 9{+fެ?ޯ%5%6Hn K@qj64z-jf[Ѡy&TG7Xفfa,jj(d FM. $7$8^%8\49 mcW4,h h(!ΠN?$616`  VbB42z-毩j߆=&Mk''TWܔ}v5dhTif\R]~)8 5nf8aCc.#@" [<Jt4`Qs4T/;ѭhz3gO@.Y:p8P:X_,2ddzsP;`b `?5Cdcl%-jdڄ6 +5&M$79RnD ^W4,hh W, Wu^RѐHѰ<"4 bh@ j@_Zt`H`uR?p"L7eBRKM +bE ^̌#4u2ؐbdAl23b~dhH'h.D׿)4<hxZGwlhXhآ!?<444i5'W#[ ((͚_w߾l{uTE+i4h8& IpXnhl05`MM,]4..Ѥ%6%3d1fq)4 +OwACWCw_.4\DpjW4tջoH4]afDnDC7jhRϏn\6-@` ~A12H?_)2k)hWب I t4I!jtV ԠGbSLIbC˘Mh8mhx:hV huhTBC0-@Ü4RNEi5͢k O ;@r~9JyWUY/gѠy1?՚=]ᐕ~|, a9N+5~Ld*˚ m`\VFC@FCOfzUeh킆 4<hx6R4$hG [DI j<@<`Cm҅hQ7C8Ig/T48F<ZVeTW:SfAOKM%ƘM4,| [Vs4,Z0?1~,@ÛW4< p@ùv4)eh2aA% .Flr0J/5R&MhhhV 2CPgF09331Hd(@fjncX0`c芆 6hXAа@$4gh; 2**SpR-jSӭoZ\E~ P= _FP?7CF sx䞖P2S jrVCaA~L Npf:;4& M J1ClOP6p@BN 34$'4hx 0dЀ{uYDC 7HhV khx=h hАD_4| aOZF&CC!;Ey~2hhp#kEd5G+dKAs>~*^>QC)<W#بMp4j IS23(Sc,93 "3eYZh¸QDj !+4dgd4l)ŋR͙50𲎆Gnhp-h;>(N9{^BRw >hjF]} y +NZx:75˱l(rPr12Q3HP'A~o rf8ESfvHefʤd(Ȕʁ Vf3fEAFZfD4ݷ hX*a +a aؐAٽsGe4γ@%:DíxD`@è1cM4e4>DFt@# L  11S%`m l0:o^.mfW_j[4DkĦARˌMteDLȔAd*!2nf3fq GPА$'̛30008lhl2.$h8h?iha@3 =49j4a2anB|%8n#hHM )JpR9W5tDK rNGk hlEہ Šn*goA AC& 44Jhנ)DS̠#d"SmEƘLh)D44/.zLO۳KEG40%)aӧN4qX@p p=SfA!4p@K?^Gh0if̞4A2D5koܴy a7!˛hS + 橵DFxĦ46p708,n›Ys/XDа|Eú  ; 2 +|"@CyE%6a֍g -vk@lG_].G#V[fAC'NIj"s< .2mԑ)%1"1Jd3U343҄DC30}2b?!ǛhH4lBѰzJeK'%̝=cɀр׃@24r D ?fh.gh O4tѫwg.0߶kuҵJIN)RJ)ť@qwww]Bl2q u>3g:s|vN ~Q1q ɩY9y 2h^ WV74I 4=0P` 9pd$ s4R 9Q4@3hj' hh +0g.+6n741wrq  + MHJI-رkBg#4,.C4A4i4 xω '5з#h6pHI0b`ȠX 9T^_4jxHlR 0. +ieĔЉiVaL,02fPQC6 hCbЊPW[]U!4\zvd&%EGEB4x:9Z[nڰaŋ.0}d J.Dàׇ 4| +0BCS a"B, !YX;B4GF'44;pFõ e5uMRVBP= <֑ǯ7ajZx= `K>3tf 9* + T^dԠhL"+ -0/4IF0e+ +hFC{@LD\TZ|O"4А`afbаa2 *a8h6B4Cap4L:}B7~?B4]а?($,r[L|brZFVn G8u܅KW JŕU M6RDC}K@S y5["ـ6r 8: +6^ 5YIE90bF0݅ɕL }{@C 5 hLKI  +tsq03h аz% sL8a |<U-hxG #5F;n Fl}6r) : WVB,*-)*Br2RbEzy:;X4O?w~5D hBÐ!y5h Ԡ F5z L1GÚu zF&fֶN.>~Qѱ I)y;vAh8yy7K+*k2y3@-J  &= VXj`s>2M 8r02%pVD){9C 01`K "o1J&B+i. 0r 2iScC]muUE=| /'+=59!.&*",8`&U+h4|%@ôS&!4 9᭿ ".@ +h$0Ygty,\xe 6YX;yzGF'ef4;pKW4+jj$ -koBcң_*~663% *J@I*S~UKaS=J \6jgA0q%P(.3q̠ó*EC'B2CDC\&ij(/+-y {v(LOMJ + twqr4312hXCl  _J4hxC) Ap1 4̙Ka YX;yxEnOLN߾s7DñΜPXTR&W 44Jֶv + @ AE^ +K[x|qI T0Ubi@EU*é =|aBϦVRp`f;Հ->6 n@Ɂo_0 /G #,^.Ij 5< +$|J,80m9B.,j}H{o 4@rgC4 r9f?@CgG[ksc}]MUeEy@íE ɉq1A~>];XY49EAú5ʊ +re$W@E?@3BW s!hX &l9YyE%yh8~򴺆9k;'7!aѱR2s^~kZZ;zzL384<2Kp&'k)||;N "؀Y8>2|hN T _+B2|A`,Zxf)#><>ܫ4`llACiI1DC~nvfzJҕȰ K>^];XYjk4=|p;o Ѡ(aRh;4̞N4M Q4LBbqIiYy%յ vڳZ:zƦֶNn}C#b.'$&edA4ܾsDCUM]CSsk{GWwo9p!05cφ $Zh3̔Xq4%Ѐkf@06:aޞ֖Gܿwׯ]HKIJ{yhظAIQ^vԪ˗I4,ZhhA + r +J 6mApȱjj[Z;:{zG'&gݸU\RZV^Q P`qC$4<hx- 'A jۀ7r4l jɮf03Mi 5 + Kdטɛ?hu09 1D `vwu676TUh(,HMNL puv4756:=vlhX /+#- аΝFGyT4,Xbj9Ee5h8odbfaecx%+I)ٹW 4<|T][`1 P *hxCao/{[ɁާHbaOG\ )ėKf#ҫxxUas@m4A.5lokij(/+-)u!;3=5J|\LdxhPYS'9a˦ J +rV hh&F +5 hX*. C +@[ܽwG4hhYsprqu`HXDTĔ,ko޾s 5u Mͭ]ݽ} hxNB wLW e@W$x D GoG_j*ʆߧKL ψTd 3q&= ހ^̞fhr,&4\v5?7;3-%Ȱ K>^];XYjkaUeE2R+W,[BEüqhnz4FDPD b˖\%%ZV^QIed4#&eAMw@aZO82PS6 ѽ@ hAdtu45VWUVߺQTX?3*3`I>Jޫ{J"HA {fUb'Q};Ý(dtyt]OwW';kKsS#=M4hPUVR= ,( aׯ0~B6 \\a:a+7@4h %#'r[w4u ,l]<}"D'$gfUT54utv OLMcfyBPЈ"hx&|"%Ƞ2X +aYL3dxSu*]a]&j@ᒑ .TڪP16T1 P@A`40HDLM tu45@h(+)*HMy0*",$06@ÍkW.]8wԉcG4(*HK@hhس;)h؂Df2~`@vZ4WTh8|g_|:@蘸'iٹťյͭ=}ãc3sy<0Cc5%6dVRW@}F#X/?.[Ko +-U ,ذ&\>G%V +ekͰBh(l $"~77lohhLOMNJ~hoceaflq Uee`4h؋F `hn*jа_@H + 7ok[Z98{z߽0Q㔴 +Z:zzF'f0sX@$-԰7ojX<'3_i֨e.n@,t-*4dS3,*/@גE7oL]3,c6T " h  xv3359>62^v6z: 7_|'= Р /+-%!.*",$ǻ YagFwthjBа BP]xa4HJ)(*:rĩ3.\r-uMm]}#3 k[{'7o_ఈѱ I)yE%eU5u ݽ}CãSӘ9<@ZxR[0`V!4ArtQ)j@o6PH h8Pw3]­CXV(+.ٵ%S\"tMa "m#W 1k /Cf@ϧ $"~LOM vwv45TUde{o3025spru{/ ($,2a)iY9yE%eU5u M-mݽC#SӘ9~B#b%&?I/,.-oljiDJ }f%G @֠L԰"7P2/Pb%uo}/̈́uQU#hi-hHwL1'- /AD$㰳񱑡̴'I q1C|<\m-~}E5auf&*"<$(P_W[CMǏ>w 9YiIq1!A~X!b˥Kh4C, + ?p ԛ @$jacy}E%eg5u L-m\<}C#cS3s +J*jZ:zzF'g桋K+kM@ (4jyK {45D @ (7`W8Zd8h5; ْP)Kj`I,5 !hf8&3omfG "t~nfzrbltx /'+#59U\t˰~ޞ.Nv֖z:ZjT #%).*,$t6.h;  ?᠁@ ._aepރ?yohbfaec_X\Z^Y][704<:>15=;]Z^Y[mhxRÿށj÷SFê˾7 p@ h0l 'djBeyXR%p"r83 gc77akKЅٙёԤبР_/7G{[k 3#]mMh4ܾ)/+#%!&*,( +aafр4 34:j4BZ h4j@5F&fV6vN.^~!QqIi0hP3465spru{22:UbrjFVN^AQIYᑱ陹ťյM~'R ?٢_A @:p@ Tc5G6F5Ó% '71 R!mH3 ahomn,/-.HKI|2,$腟'=|pέҒb"B|<ܜlf& W.#/ @4fFÙ$p@E4\acy}E%eg5 L,m]<|B#bR3s *j[;{G'gK+밍M P [[],5QRNm@l 2v`c@k e4Rq6|"M! |m '""Rf26|k 4 o4lV 3S#Cݝm-M u5Ue%Eyٙɉёޞn.N֖Fz:ZjT '#%).*"$}4\F9΂h@4 4/(,"&!)- ν=~TUMS[WEPHȘW)iY9yťյ-m]=C#cS3 K˫kTxjCM ?Q/p@*q 4`GCjXRt%Ubd嘄pаo$3l4`ashomn,/-.HKIJ +puv031TF2Rb‚|\lf8h< 4>24Gbhg`+W40CX88xxDD%enРg`djnim_TRVQUS704<:615=;]\^Y]j@j qŤ@{ԏT6s>H/M 43!WJj :Xp"?v*36If64j 21S̎Q'vĐ6M;s$ˑI{F$"n'fcNaog{ X]^Zhkij(+)zhokminbd '#%!.*,( gge1A! ǸB5nj} b#Z:z(#_@HDL\RZVm]}CcSs+;'WwOo߀'qɩٹE%eյͭ=}C#S3sK+kȭ]@ /_ ߝ=Y yT.\p qŀs . K8~/Wl뱋f ^?Bn!Vf'F{;[k+K s3&'FGx:;XYjk*+JKI pqXaP=OpK TTp#pPPRhA 4@`,pNn>AaQqI)9%5 -=#sKk[{G7/Ј؄Y9y +K+jZ:{G&&gWk/N^PIU =p Wb$!_um pv!3 4fЀ2Ë;[奅驉gy9Y)I qO"B}=\l-M u4Td%EEx99X =Bݻ4`pcς[xhD41@L0fV68'/_@PHxdήɩťյ 4ۃãcVOd5\_na6$vpb 4())AÍ߈jyO@AIEP h@a,l\ܼB"T4t M-m\<}"bR2rVT54wvMLN-,. 7[;_:QwT>mPـtz9 5 t"D! <7r%We5Ï(3 0fxbowgXY^\hkij(+)*HOMJ{`gcenjl(/+-)!&"$gce1B!t?Aý/4PBZ O@ =g02XX<|¢R2r +(4YX;:{GF'&gfUV76ut OL/,-"76wvV5."ll8Ā9?+>qNVGr2#ʻޟ ^e{;[ȍu@_Owg{ksc}mueyiqa~nvӴؘ@?/7gG{[kKs#=- 5%9iIqQa!>^nNv6f&F(Gp. 5% hI 34 ;(4Ph8UZ: WTVU7465sprq KHJI{VX\Z^US?0426>9=37ՀFZ o>U{,5|j6;!D@6|Yy\F'B6õ̀A!3fx2o' ;[5`owgG[KSC]MUEYIQA^NVFzjRBܓ舰_oOwW';+ 3#}]mMuUeEy9) 1aA~>.N8;+ +a} eh4Ph; + A4̀/84B%@ 4^n.N֖ƆZj*JҒb"B\p6Vf#BOQhjnf40n hp𘖞caesr +IH+*kjYX98ݺ +j+8~۽}h}Ŋwwwwwww I{nLg_9'P5 a_/084<2&.!)%-3;7`hdl|rzfn~Bbqkk@ j:fNp{p|TI \.` nmn4j07;=91624PWSUQVR@B/7;+ @}p whh())nMhv x5* jc`#Y9xxD%eT4t L-m:yxED'&gUT54utMLM/,!WPh ) x5԰WH ͈  n 1:d JEl!WDd3|3 df2>@3^nm-M u5Ue$Dx99X 0: x3@h@ 7!3k ?4@#hA5|Dt0z8O@HXT\BJFNAIEU]S[W_`phxdt\BRJZFvn~aqiyeum}csk{gwO +z[[jjxN}~NA|DPWF$ojwa3v`43 k8*zeyiq~nfjr|tdho@_oOG.Nv6Vf&Fz:Zj*J +r2Ғ"B\,8#=A4PAhu < 5ih@j @430™Y88yE$$eh0465WPTRVQUS?842619=3\FWM@ ϞTKP oY MRil8pOlK@H\Lya27rUfuoww ͰtkscŠQŅɉޞȰ?/7WgG{[kKsScC}]mMuUeEyY) 1QaA>nN6Vf&#=PSQRR&@Í#hp j B- T 5h{`p3 +;7/#wO~q I)iY9ťյͭm]=}ãcSӳ KŭjxMW5{+$, l G@>,vjT ffx} O3a1@_OWg{ksc}mueyiqa~nvfZJRB\LTxhp#';+ 3#=- 5%yYiIq1!A~^.Nv6fF 4Ph ?|)4n6%%@ p-' (,"&!%#+ohljnimk?($,"*&>195=3;7PC{gwo +j][zDY u$8N \u|ESs!\>5 x4@f\_aV+Ks3ӓc#Cݝm-M u5Ue%Ey9ɉa!A~>^nΎ֖Ɔښʊ +r2RB|\,L8={h* pD hp$j@B^ ` p3 ;'/c}54utMLN-,"WЫX&/~!59>k3p'#~f0㸨)I!y!Wwvwv2Ë@3lᰫh2rqanvzrbldx0Cc}mueyiqa~NVFZJRB\LdxhpcoOG.Nv6Vf&Fz:Zj*J +Ғb"B|<\lLpFz:#hMp~3C5*  4@g#XX88yE$ddU5u M-m:yxED%$gfWV76wv MLM/,!Qh aG5r_ ;;{x5NVwIj8 @}8Id _|j8ӔMʋ +EC3 O34j0?;351>:<4 4Cnvfzjrb|LTDXHP/7;+ 3H=4j  f8gL83% l)B!K)׻r{3wm6v7s(hHB{̛_shJ ) +(D1X(MWTRQ3021sprq  KHJI/,.-olnmkj'acs{gPgTjxqZ 2w^6P,~‰4剞uLy@K@ 4 3ï5S`;ۛ+K3SC}=ݝm͍ՕŅٙ)I q1Qޞ.Nv6Vf&Fz:Zjʊ2DI 1Qa!<ÃF!8n 2n죁BBmFp רѰ@C5ppr!<,?^PHDT )ESPRVU7465wtvu  + OLNM/,)khj ?0426>9=37s15(MWTRQ3021sprq  OJI+(:TÝzzG&&gW7w敏=5| o S y3TF.:qadǸ~:0˿9 v60;=516:195=3'6PCgwo +}zCjT5T{ۉjxh 1p)bh4~1R2rzfx +Ks3ӓc#C wnij(+)*HKI  psqr0312PSUV&JJ + q|X 7 + ph ld4BhdhpH d4 @N.Ǐ'HJdU5u M!58:{zG%$ed5WVCjs^Wwo7wCjxzD _1!G?0߇IL3\às'o Q3<f07;=9162^@HXTL@&+*ih5XZ;:yxED'&gf^WO]OhS b'`Ùw ѻ i$f~>bfxA v6!3,AfhoPWSUQVRT̐`gceafbd(/+#Mn p8((np C4ppr^,/($"*N")()kjYX98yxGF'edUT54@jj_XZ^][$M5 #jS@@AJ\EVx[0 }\N #fxo}3<fX[f{vKSk3de$%3z{:;Z[jk()ɒq1aA~ÍF!99n 4# 4pp4R>Xap8 'jBy0X>^@HXTL@&+*ih~j2;5H!HH5{Uz &""""VDz/Amunl9I99g|'7/0\ں7[Zwv B5LC5,,.=|)G 4p?D 9B1 79 {,[h&@cOEX[6a/aa@_owg{[+4CsScC}]mMuUEYIQA`m-M t4Tt_X\~ [ ϞsoD (f1?6ræ\d'l?<5P"SVUh֙~X1ó00024z֍kl3\8rNfg&'FC3z{3XYt4Tty9 +YD$qRE0@#kа kհ b\4@5  <54DiYBLe5 Mm]_@PH؉dܼӅťgΞ;P ni;vobjza_UÏP S_Wcl&,=-6c[R7B&z'4�ybט;hfghp˗.rPZ\x:/7'+#-!DXHP2ASd$i"'% 1DQqq,Fxf;аh@4`Vp\B'I2dUPRQUa[Z;:{zGD%$edqPVQU]QÕo5wvC5LB5̱[jxUß[dlx!,d)l;QDk֙[hGK &C3 tw3d Ih@_oOwWgG{[kK 3#}S /G!ː19 հk~jQ~, z_;6c'㊰zl 550åŅ''FG{:Zoߺp ϝ=SY^Z\x:/7'+#-%)!nm-MM X:Z*JLE,C"8)`hfhb1h44 bppp@֩0O (54ABR +'Jdd)Ty"SYEM]S[o`dbfaemk^ /]pN[GWOoW 3}[1gAMPnǓ(?Պ3,/.C3LM܃fhpj*J +O!&*"<48PdiT,$M$$!h8vA8hf8,  A#(44@5ppO Jːe +4E_@PH؉쓧 J*kj^ pwe+jx@԰/#j7q ̇R0Š34zbff;2< rv '3Sc#Oxy89X[hi(1i +T9 +YD$qR hfhb1h4 l4m 1?4<5Ph +а M+J*Z:,=#SsKk[{Ggj8]XSCCcS3PCKapW >;D߶YMcɆk3<6`ٙSơz;Z57py9Yi)I q<3x{:;Z[Zt5T :MJ% l4; +ЀQh8ch84pFcX.5 DiUFg0U44uY&fV6v@ ޾Q1q I)iY9y@ gL8؁s@vGJz=! ޻] 3N{9s>A $}yϑc'@5\00ϞUXH JO;Zp`kE, 3G~K`WS/f0qޝc#C 7C3;ݵ*K s3Q3DEB @ZK%"!a3t*L$A3 Gp V3C3|hBßg.40-hQ3;r{޵sm[l,/-.΄fH7 zV$betLf4co/fUhpT;T_-j!ԨU +T"y6AR ~>634x{4 4 nV43 +a!5أw;5p0"L,6'%2R (yE .5jSǨ>jz~԰zoJZ<ƚE- :aG3 3\sͰesueyiqa~nvfz*0C\LTDh\& <.ŤӨd̰ɆY`X92ç/3Lܿ0<p S3ؿw];wl߶ i)I 0!$H P)dRHrXLJ! ~fhh@hܬhX +`Ԁ!x<@PM>@ $2Jg0_(H +Z + 5#cR2r +aj8}PC_{B5LMjm?L c~`Kx{dzs|UNΛ+0n5 `Q3;r蠽jk*J +rc#А`}FRʥY :B&|f ̀Gp V3[4Q7;4x ԰aF B5$2Fg\@(JZBM@ ɩ5UT7465[p nSs԰[{ػ[65Z&3LN;3TWfHJf0 !A@MJ!E>f2T +Dhfa7@pvfpj@`QA P V45Id +`95ÆuW._ʙu40C]MU" >iYLFNV*RP^l@C@@4h@hՐԀ<VC>hRJJ@ "D&WZhNqPCݔFPCk{GgנzmشQX @ @ qjSh5a pd]3|pfx6+/]3Ff8z6î۶l̰{NWg2)`d<|^aVReRHf(-)h(,4PK1C.k 3 Z yH a H BX*+U`2[m"x0aNwςEKjضc#GN.`5\ְjD>Rfc 2Г~d56`On~2û`ׯƘ" 21l}{fXjŲ%3hki3V'H(]l2R!JD +d `RАâ!WZ H  H |>%5eR(H +ZMxP$57 5͘ɩaŪ5k3jػ PPK/"5vuPûH | FydG{ 3fx3+W2 dC3l޸~-ggfhj3T%bpvd4jB.Eeif4 (㥘!5Cad4dhAh`) +j4pj()-+\Rkub;?U5iӑf͞;oBV 7opVóX5©}O@ c5|ͨGHi 0&RCfw {) ;oeͰth3NfJģ`q;6hi*\&`Ғb  `l>// 9, #!UC.R<O @ X ,A BD*+U`2[m xn +RCk{Kd԰}nFjxVQGRZ82 Ӎ~0g>&m3fxil'vfX׻zr ]`S x4 +nf5 zFTȤa2d@C@K1C.kq2!M <Iij(+5%RBFjw^ œՠƩX ]s5]VOb5<è0` fزik=sZ x, +nzFTȥ4 @E!31fxACxj`CCPh`P\R +j\Rk58]?zPCsKX5lBa?VqP󠆾i55!ψH#E` Aa/cWpp 6ÎmV,[6m`0CU" >iYFNV)20x26B |d  G4UA5" *A R\`0-6h,QUS[Є0c,Z KXEaN45"j s$fx9 Gc3b̰fcga3L3T%p0l2R.JD +lb4`3!kD4ѐ 84 5P aR+*bTP4ZdNqPCaVs1jXVî=X GNeN 參Kt?[jpfry90)0Ql{6_Kay S x4 +ncFTȥ1,   |^^ +83dga ]145@h5X5DBFjw^ Ɠ)H X .հ~#X G5;?pROD $6.f'k0i nf̰t1md`d< ^aZLFdB.EB0CiI16B2C!AK1 83<:fHGCՐ8VC>AC1RC +Tj΀ty`('kA S:h5,]NaV}N5H$i Gfxp}!3fΘar sZ D,}nVReR0Ce2dl@CA~083 〆GCàY5"50h@j@ ILSCyA"ɕ* Rb;?PC VÜnZ +Wjؾаj~45|J@"H{!3\p0 dC ;i3Ӎfhj3T%bp0l2R!JRh3`30rK5ãat4. Y,2SPC!Rß̩ A jP(`2[m@0%j@ MX = h5հS PÙ._Bjح ++-V{%y /E.[dٲ-˲eY޳8F!! I20PL)3@ }t>s]]KoVqW3|Sn_#3\(12.019= jJjGj8Ij Ts8.g7h/ f#5 Ozpp̰ ̰01>@3 ftfhnқ`%3f(`ԛ!hXECU &fAP&TCF5po0+jjضppZRC'5&8TP3|flT3<,^2!4î``db$fCA4`G346hh "\6!h`PBj(C5hP`C5TפP@j;\nO!TCr|b +԰հ ppU5 >jG߬㸻d73<1}d#hE4D5|j8[ jG  s`a v:;|^ fhPP f34f0f(ΫrXUQF f +RRa6СQp|t0jX@5E5#5OjxDUË7KT|8nյ[j4Q2dhh`M`Tr Ѕf0CK UD4Clui3f06CP PhPj֩YV &A @ Q Q 'H E5f(b&7 j PCKA >jXaM%A@Dd5x`A T v54hj8<5;\ ?F DDR%2Õf7̰en m 3Rc<52lPCM5l~vjx[j:7@D$TJ!a d0C jPP] 5,DK>3\d^fQ0r WC԰75$\ G DD$n`3,˶\jVհ:\ G;sC DD%7Ɗ!"h"" fX71>m3kfe N4DQCM 9M 5M@ Ohj~_ L5l@ DDI3,uanVJ7hZu5 UƊE5|5IQ+V0/f(] ᓦB DD3LmY53gfYjgU҂'EUë1@D$eb2Ͱ$ -.34`G 3=RCK5ތfp / 5hF ""Y af.P'"[ v5t9հ5^F0f10[ +ע",%v0k 44d AACA yM S|F@D$a_ ;Mya03 i +4Ħz@D"?Ra4!3ȀrfSÂʫ!@D$i5@jfh +0Lெjh!M Ha +n}UdSc>d)f-JPq5tǨAjj ".p6L 0CIj/Y zˎ֖mFj j0Py(0fj=BC. jh2*@D$yffXf fˆNWCYajX5Ug!frj[\^i6G DDU=f.3d_ A DDVfJ3jxC w)j5IfȰ\h@ 0CYf jI55W\fu&0Sz3TX CH60CIQe 1Cp~hHH { 5P%dHnV@ɧxi@D^)᫘!DPåN5Y U@DbZ nE DD2 5<|GQHe #!$)p>3g̠!]5\PÝ!jj "J/PefY +հ/D w㨁(0Cՙ!^5հPZ@D*iOAbTâT}@Dw'bj0Cj3&fWCMjXaQv"" O +0CRSE TPQ:aj6CjjB DD &E 'QXaj7CV`T5\|E@D2_[AQG DDU]fh >Ŧp j "3C+f.)5 {aw@ DD闚>D+5L(j "a NR^@DN b3$N" IPg_cPj "*E3| o "PQ P2oE4'0ť>jX/3| 3Hj@ DDJ5ÿ5Ñʚ%!ʫ˩%ƢḢ(J1 ̐Vaot55Ś0fx'f3p,T B DDbc!C H-F3<[43uAQ!@D^"v3 3j8U @ DD/i3 PU{ AbRü5lD DD 3l $n}\{N}ѪjQjVRj5F͚5FԈQ#Jb(!Ф$ [oxy羮ss|o-\EpkðgWgpg0pƞk85  es \PXƖgxgHpkH[ggRgxgHxpk85D63c3|3*5]>r\Pnp3|` o p WP)M 3\25\ ˰6a3iyom>W? n\Pʥpϐ n&5J2 /^ Yn&\P$}Ki!5%I޹2\Hgg(kp @)x/~Owyn{x<} 7^ cP%$ Wxrogs335 w3\>];>==C\kr3w +\|ᅞ595 ?E<Ã1u e Ϙ=u r Agj3\ / es H_ggxgIk805\ _o}4< ቞<]A+h0*Κ]ùAgp3u n33ds ,3$3w[ϐ$SȽggȐkp @Rx/|Go<^sp{ϐ/ ] yr HOgxgkp @jû<s\k+J\g p 3x|pg(kp ԲP#ie gzokp `<15)N r g q DMpgkp  +{V<Ñ5+N l\02\0* +\0"\0db(\kF9yֳzww}_3yGK3h"u5ܧ bA3ՠ JA3!ՠ BA3%ՠ :A3)ՠ 2A3-PP hf DL5f DM5f DN5f DO5f $@5f $pji@"R Hf $C5f $wpjh@RzQ gHf $F5f $G5f $H5f $I5hf $J5hf $K5hf $,jc4IS 5A6@uA38ՠ%A3,V P Z4T4=T4ѧjL5ܥUA3#A5@@A3+A5@0A33Wib4j5 nA3C+TtO3hz)jU5@4fz^ 7hf V:pЈj8E5@l4f#WT 4r5TnFdC  A5 +A3{TV4P Cj4f Ua4HP f d#jأN5\nP f d$j~5 A3aH| _ {f djP5@h@ZuCW9u^i@rT LW V WI3h֙vT -͠Xai@֢U4J3h2L5cA3Ϋa1հKj8]5@+4fapla5\aA3j)VUpj4fY)U!Epj4f9QWsհjXZ\ (E3hX)jX2͠`HհWj`A5 A5t4fyg1p Wl6lP f @, IN^T hff jXZ5l2m58T hf 0RWհ6U #͠`apP5 ͠`֫ajبvTΪ4hlR 9͠հzjXb5l7T hf 0Aհea5 <͠`ajS5@J6ÿ5f k U J6W ۔g͙ UÅj JKhf PAߪpj4fJTj [A3@ET VN+h4f" UT4J3hjxij|O iD^ TT4J3h)jj4fr4Ljxjnj4!jѼjjn4Mjj4fET -Y U R Pf\3@EQ _ ?(A3⬆/ ᫪44$jɒ?S Pf И##7& w5|sB5N5@͠QW{#cᷪh S ̹jx\52x5E5m˗ݡV Z?xA3@VGWk_ oU f JjxP5l<׬_'D3ܪYiEF!h!EY _TWTT4]>R\ ?[ P 0C3h-jjj:j4ET}4jxܪjxjxjxL5o\5|C5@A3@;:׏f8M3@n}Uy3 WwTR3\9v 7A5ppfFR 4u h4@5Rq3 P1*S+HpKf8I3@Tj 54ÙP OXX ]Y //W _T×UT 'UËTûWÏU٫ j >=~V4pf<@*l'4áM5|X5@pêfN3 qTVOUy kȏjP įf8?fXC3@dUÓ ᵪ c W\6 ]VVT{U3]3[ jHV#:n4F& W iH_c ;N hHKxk. @YaA  +ll5dF5b[39VcULf8d326 1%&j.lcK7öz5Z584 pfFS X4 w.j*6!XL50m33) KW6~sͰff@ me"jj a_ m40jP tF3&êf$CA3׎iSgxn5B54YjxjkK5ɚv5<ܡf8qfؤZ3 yVTyH64ƚrT݈j7ZҧT]v4ͰL3l +U'U9Hj <ՠh[ͰP3l7֯ kHjP +fا +uA5PSͰgQ3lYA5Оpf*\ Y V 0IpL3^ i`jP fP3@"j%K5kn i $ՠM3h ՠ+fmeq05"ʊy*(,,"""HH"$"J +968^z3 +asky||^E"f5P,<3 `IjP}d՚9rf:5P*L3` aIjP=c0Q5*3~fNp>5(0Ap4jFj 0ϘARUQ5ڢ3Gzfx3H5Pq3= i3BT):)0f 3H] j8Ekf +3H%jUS0fͯ fTK@ pi~a3YʯT9Ԡj bo3* jPj ƚfT ֶljP13HiNjԚ2ÿj7ë{fxq ~֎ 6 +B gQQ3Y3< i8j-n3} 6әAH@ *Wf}I3s o7+f4.j)~3y jPB7efTy@ *Z;fX3t> eISjPb1afTQ@ *30威qfޝm ;fx3HAy c72jPB4ARQ5(O{ 4D Ac_5ÇARSQ5h'f`IjVidf4Sp"5PCo?77 fF@ Z/N3 `ID Ԡ2fx3H*5P7[2fTC@ Љ"6ûARQ5t :\fxS-fx3Hʌ13H*5PCG %fM1cAR%Q5tTZfl@ ARɨ:30Q5t*f`I3D С5wARQ5t&f`I3F Б2ëARKQ5tBft@ fx$3 !0ARQ5$30ʢjH:f`IF Ԑp )ARQ5$30ʣjH2f8u ҨAR-Q5$WL3<$U5PCb13H-jbfTc@ ֨ARQ5$30ڣjH"f`I D Ԑ@ !$55PC13Hj,jcf`@ o 3Vj4fJ@ AR Q5D3 ڈ!4y Q5D30֢j*f`I-F Q&p3Hj8jhΘjAR+Q5DRtf8g3AR2Q5D3L4 "(F3 ҋ!$5PC13H +&jcfP@  )AR`Q530j2f`IF ` !$5PC`13H +6jbfp@  )訁ARQ530ࣆ,5PC13H jnf`IG z "嘁$E5PC13H(jcfU0A Pk "JfmV$Y0ejh23H +>jkef`IAE ta$ŨFp"3H$j&cfs@ )!230أjh d`~3 jh"f`I)D P (u5[!gcfg@ VeIj:jcfT-5D )Ej8f`IE }jXV +5Xa3,4M[f$P9԰w\a5NR6-[dX鑁ARQ5T30TSC^0Df۷7fIjNa54Uuf8 \P^ 030؈\Y {Aհ@ #f8n I*gf`IqE lQ633Hp5]~2TdAڪj8#YjXk{A*v5\93aΆfX2Ñ 3dI.a5R<5/!S̰8jÃfx0 73$PjA lh{k2a~ p3\ Fi2jXWd5t !C3< CRþBjXq3 +\f$VYjʪ{l A(B5\v]pÐP}j?cՐ͆G٦aJ,3\ ^joa jX +ai džͰ m!3ܰm6p˘A*E5SÝ;jx K GPCgؐ}̰ip].2 IΝU wdT5 )lh{͛i +!Cf33í IaTmkjXcÈPCؐ}wy36\fzM MTÍ=5ܾƆ-5aa~V!u6L3jN37ܨ536hkAB**5\SfS55RB5aC۳^gȐ f8<`=36}{ 7N4E ImM5SC =5,a%eØsGͰcF̰Fjp!3HRKšP?&aO.5,nay@ ]eT2 an7x $$7H !!8[YHbqbq؉/c}˾س2^;WUwWuOa43%&,0[ WC1"f%5,P' +2ìaq7À3E3`",jر9jD@5zV6cC+ 6bAfІf0 ]e:z 5!.a.D6P0!е3.fx ̀aV\ ͠ SàN5s5@ KҨ`!̰fHf3mf7 ; alPaԠՐ4ࢆέv5tJjf%jPԐjl԰"a͋ʒ ٯnw3,Rff0i!4Q4a԰ۣE56HjD0Ր̦U5l#6 & 3P2fHr3YfP 3\i7injw3|f0 +ISͯC }߸u!PgaQPɆ kۗ aN ]phaf- 4aX ++H 6nޒ70TÒC A \ܐ73dp5âa.ffs-3fh) 0 JRaL ڃ]\ #N5TMjHq5p6jXհP($3d3dpa0C\6íyPf_E3`-QSNN5TUp񒤆~PèbfM5$jaUfclrf +D33̂t]SN3p3tu W337̰=fx̀aVĶBN5Q5,05,fWÊm ! In9 10CnQ0CdK 1;h ða5ڠD3`m^~S{~`j#oY `'QCjjX0հ$A`ê fˢ7jxӡ$5:tO\ Mv5Jj l j5UtԐ2 RC^6xrӔdXs!#4C +dxd3躦J!f/aGf[2fd3f0 OSË/] SC]FPC UCQC?UظPC!f!!! jl†pX0AE 5|V3060C7Yf?k< +4aO+^:UۮjUV_N5jj ljq5( ʆT6 EnN  3Ĉ wp3L333tum-`Ɔ ud7 a>jxͦ-5|԰KRIA W 5t5 r5\l`j5D 5L $AfCl\9}q~2f@̠iB%fq302Lr3 3t/ mjM3ҋh ðҵjx5|)a߁ʃaj8Mp5Ajra +!j+ +jHjXpSzP6.^sa3D3$mfuMU87ô:f8 f8ba3w>n agjxK ?j8P[w*UCPð0QCA5@ l C8&C& R "`v3 zZ /R36p> _5 σE3`U365[ SePCSC/UȨPCA5L s +jH jĆaF2fH fx(!@̠ic aj{wE3 zm-W23eOE3`2vڳw߁A Ojh54S5t515OP56P5Lx\QUPCTeCJ`ã,l0ErC)dx$!`A5UUX!paQj> 33T:X!fxfg aGjϙ~PpzS ~C L SUjddlXeX>2dld0͐df0ɐ5 binNqf~0Cg# fhXOpJ4=v:0E oP5?L eja +pLRC斶@{ 00hWaQC!ՠ jl0`a`C&Pj8&mdH12Xf 3;0f2p 3Cl>G3`E塆{7pBCnaQ QC4+ +jj! rۖ5odHs2<@d3$ (1CplA0C71C{(`}{wڹrBU*Z%UJ.YhR)g$9sirF$AjkLd IisN7zfzMa\up{wTbK 'OF"=T˻QÇj8GԐDԐ密fpMLE5ܺ-؀j60,# AV6솃v1' H @4W4 fXpf$a09rm4[fhH`nԐLԐ_X\RVQY][jhSAg0-V919jX jIb7԰jPa6654jG5XlvajհxO P +a9TAdæF6hppvbMbM4} kH0 waq0fpmɠ3C ?7[i=6Ë 4{GQ p,)R22E5WT7:{Q :lNaFTÍKD "P UaY/c} D AlU ܠ;A덠q1' [H  ^4fh ön޸.atح02<(PdI qAfF"CSûjVR؋q |jF54+0j0Y6PavaQl`xA@5aٰƆGly +Ubؑ h kHxV wE3dX"f3D31C_o71C /7;3#-EiS')p#fxFWÛjgfP m=}Cd젆IT 7ð,ٰ 6<nW9,2< +AMB{"h @@3ρ&'\N ͠׍ ڌf(7CbB 0û 4QQǢN:s|t*Q -GtzliT"Adذl`xٰ`}dæ6<drP" dG5$d`<`e @m3\_\@3L`3a ݉fhlD3dg\S3h&5FEfW}jxCE WC|+RR3r K+k;zzP zlNafaATa5xx@l e6hs* B ȀfE2< @ hi0`1 hᡁ^0C{[ P0Õˉqcϟ=sDԱT5FEtCtr P U5uM-Gub&P s J5 @ `ð D6lĆG*lpؽBMAA_|d dH4AxV ` Cf .f1C1C=͐f ^fh z(5|SqQ b.^OLr-95=çRTC-QCGW7ahdt\7V09%aQTa5xxdAf=mlpЮv6|baK&= <ϱ,@4g$Ao45 6"60 nl n8 9_N0p-;(2܎!- `e2~dD0C .fCfzNf1 zF#3 ~0P_[]UQ6I0a0Þ;wlJf 6m"jxRÇ1jUS)5UTVց@ |A&WԠjs8]noxbC6LM#6Bp$27l@jX/ n9S 7VCRb$w 2\_D¡P0@d3 2 dar:lVhi`)iޞ.0CsSCe‚d ǘf3iMf=e"2`3p8u ̬|J 5u -mnR PR&fw1B bـlAl 6)6\g;6bذ7XDbz0 C ",@@/`ёarmVɨi*\& |0CPYQVR\lQ31Çf%0ï_,6m^^VޏSJ Ir JA vPC_ KeC`4[v'.lBlA ss \lf$n5Q!n 1,' Ka! ~DdD 01>6:"386d3(CAX$vZ 5Օ2SS ' ap8nbKP9J yEťeUՠ6R |0P5Zd'Rop@bÕi? ͆7@ \l! kpZ$ b -&h22D̀0fy=nnMNV)2d@$tk*K Yiρ$p jOH3l^6k 8Td&p!%-#Pjkhlniutu"dԠhub9.7R@ M"6̰ـ@a1VtCKy0bÚ + 3  4.fy.fVR*dHു e`L _90Gal=Z5<éW 5OlݾcH5|j8 jH/,.)+5wtv A\Rkuzl.Cj'(`b?p3 ݰ8f>p^ryCB1,1@a1J C&," e c ^2f5zVRʇQ3476TWVRΟ; f6];o%m7p8qṄjxw@ ǨCA 'A ɠ,PC +Bj ELP5ZdX aTeZ +W 1l6n`rR)n:+``GJ ,2\ @@ $.f@dy=.nMNV)20P fhj3 i)`>?2çqfx0ëfx6ZOX o%V1PI)Y9E%U5 MͤzA bɠlHTi:dN5o ׸0pfÿ n ٰ7ʁE{! %6nđ!)2\Cd@fɀ@a q#3جѠjTJŐL* =]֖ښҒܜT0i0ñfM&4s 8{jU~Gjm;v޳o?'O΃A Šں6^GWwo_  J +ZLfp<^!V $00331lX`f ]8aU?p0&q[ cp @%C& "$" ._Htmɨi*|H:(^[k3Pf3$Ndp8?FYT 9vpԐWPX\ZVQY]jhikLP5ZhXmvcـ@*bԊlXذl7aX#^`!H22,d@b'"U A10r:lVh4jWs\w&3aH^^j{ッV{]ْb'6vw$. {sΖsȺMvl4jB.|d.i3S#C`.0CSc}]MueEǎJfx7ïssd +U /jx S\ E9j5 A K+._ Ke +ZMfty@0No9{gCR )6\ 7P Yp !;C?ۃ,İ-޹} 5 Õ$Hf2=uF"Fq;vd4"a `^0Ck&2 +Bgjj8zDYyeUMm}CS30619=;@[0Xl.O KdrJLft>0 L [@ %jpp`llxdön!# +agQx lj n&N0C 3_Eáuvl2R!3lcey07;=516: f P[SUY^v0þҒ" {03e^Bf@P]3R+d5|p(K mP6f1!0CqޏfxBviJ IQq p;zzA ť bLTizl.Ñh,j /dpclHQpȸ! \9da'~r!l0CC  +2N 2̀!_F¡qvl2R!E>3,-.ςFG m-͍ uU'O3O} o#3P(.\5jxS)5 PVQY]SWJa`hxtlbjzvnD_Y]cjIrJ&p<^? +GcNon )llKa÷n i9Ow +!b . _cd3d<} +#C,>tجѠӪUJL" +x\6kf3 t0^Ef@PW ;QRB )j5LNˠ/2R &fw? G06$6NlȨ!Ɇ/ ה7Nm$02D¡uvl2uZJ!IBf1Vgg&GGz;;Zkk*N!fw !3P(O_dlVG8xp`hxtlb@[1._ Ke +Jfp<^?ذOl Ԑfy p`C o ܐ2t1Ⱦd/(b" |d$ 81 q;vl4R!JDB>fЗh sS`ޞƆfxƶfxBvMON ?ˣ ~+B o`jxoQqc)576wtu fiUBD&WZh2[mvP$ـ,L I6\Hr ׁ  +!9@C>䏺I' T0 G d22\&I2D- @h#qvb2uZJ)IBa1Ep*n}uq]ڠifhc;vmkHE"Mqw mz 5-$h7}8$Ԣ(x~4i+ 3|0F~̀BP'Nj8 p259\_ KdrR &fw<^_ LGg66!>`=vp6B6gC ߒ)4r#n3B(2Đ"^< w67WWfӑp0z\Nj6:Z$brcLuxh fx3o~Mb"3P(9MNj8PõyEP UP -m]=C*eǹIH"O)Tj`4[vp$:3;p\6'g 7|nH!Wi;dD.^db%c p-@U@ٙh$ +}aYFNQ)RH8ɟY :JlP[SUYQ͐"4Y f[ ( +u{jxUL odLZ p5@5WVUA5wtu Ri# &kl3\Tktzlٝ."љȆlG!/8nl ! s@CD< \(dh!l/21dx I2$̐ M@奅t$ aMFNV)dRH0ɛ0ep3õf8M0Û ( +uP ^ ph:Bg9\_ I)Jfp=> L/.6olljgP lxذap9rHҁl>qzCB I0# dۋ̀S` k s3H8dn89$A9?B i/dR1B1cݝ-@Ǔacaq!:>tجQӪU)T" +<.=6ʤP)}]m-͍ u5Ue%E3\>2 +BXB^"W`CR g.5\j((*.)+oljimPit(=ΙM +DbLP4ZhX4`dl +n,pㆿC7|MpC)9!@D=5Lh` N HxP9K@ ׁ +KJ+*kz)ô5py|P$ʧ*V7Vr{|@( 0;ٰJʆ16| ƆX wdC@N4z 7Q D*$@#5C 1Hm _E i2,/22~rmVɨi*\* |3>b2FhÔޞΎꪊ⢂ 03M /d +:1=35$؀\ .5j(*)-ohlnikЙ,8w?)2Bhb9.6Dg cßlxذٰnl o dpCz 5DTHi`L P q(Ǐ2|IC2ܽs;EEHt8 aZFح8;\@MnwmM[ڦj{o]Lhmj&$09o}O2wseҩD< tجfWӪU.L*|.dЩ֖ FoȀ1 f ###w԰U`CU ۶#jػ0P *d19=3;w_lx*l +ٰP*//6_n +nnD(*x9"Yw\ z +T 5k(HkVWJ yHy ad^{< é3Sc#Cl&LĢP{.f1 FݭTePrXLJiok=pa/jmU3<6u?] հN ;v"jpB3Xl/;2EWJ{&p<_ Dd:; pW+l‡5lRaCT.6C7: ߢn@=5r@CE(0-Tx 5`Wb2 Ca j#{#+/2; 009>6:24ˤx4^OY-&c^ըriD$lNv3f؇a3b2TJG01`h'fx f ###ۼ'jA B5ܿ6jس0P *d T:l8 oep`UBX*WVk܀u7 pȡJ=q?pq/ +1P/2C2\%(C2ddeөd< ~v96djUwB.|biTJ{[ nj'fx wn#@FFFOQ]15@6@5< ؀aT +`9\@(He.eZ&p<_ Dcd* M@6A6;M ."lذؐ/ryya ˡ8*zDcw#``CVRX >2YHY@ё\6J&bH( x=}nn}NV)2D,y6AQ:Zf؋'C ט~h{pi222׿5Y;5?pPC[Jg0Y.O I:rEWJ{ &fw}^? +GD2 6B6 8>ln:?n@'  r +Q"jsB0 bN RX(.C2\"^pafa a0IX$ +}~۬fWjTJ\) <.dЩ GC̰c6  l`H3m~n5<1D Oիaj8NL DbT&R]`4Y6p4Oҙ`(d4†35ln 7,,,.- bT^FݰMˡB~Uͪ.4 +?`Q1,_d gbdbh$i S #Cl:ǢP0zNj1 =:ZRȤbYLJiokm9~  v֘ᙧQ3aش jpC|~iqqa~ |#+8N!dddȤx4~۬f_ǓTW +U0 x@"Ms90=yfȠX୽'ظ%,*{{u%Kx.O"Pb6:Zˆ ] o2]b3mbf`Xu׫SÆ&5SÁ@ =aBhulٝ.Xppܱ3Scj\*sL*E#`ub2tZZˆ = >lih`NfZo԰հS=`U#~PLT:dH4H3|XTG'gN">l p~K7 px!I?41o~/ \@=/<@e =$íu2~'"EJO gf&'FkrfҩD< ~rmɠi*B6 fC3>tN ;fbXWN ۩ b5QCW7a`ԠP5ZhXmp4O\P*TkS33ȆO^tpoܰ nx`G97<tCR9tvx@VgchB  /(V@ @w 7E #N 3@Zu\*st*E#`b6ZZ ]Ga 3b~x64@԰WfP6`C>p pÝťf7 $w"8pr t vx A# B/HPSVܿbX1nB2^J sfg&FRfD< ~rmVɨi5*B><4fF3K; 93tt13X,:ǫ57j]5:j5JZfp^? +GcD* H6:6>9l8l8y +њl@7  n-p 8prP Hխ@ 0P1| ep!pp(aPK|.N%h$ aZF^Qrp`K3&ff̛a#5x203X,e?Q ojxSC{Gg'a+a'd=dUÑnPLP5Zh2[mvp$K$Sl._,G dQ` .@܀l@7ܸ nsayy>G pxp h0?TV X@-\Y  İ&22&GkJT粙T2F¡qvl2tZZ3 f3îfxMjטX,kjհA ; b565e +J Fjs8]n #x"dsbil6S6"euenŹaQuDt-V_Z x9zA^ P Dbbb2\Lɀb2f c@RfҩD< r:VdjR!3t3˽ ; [ m o fxb]?I 7aH [@ ۉ j8l@5 +Z&fw? Ex2b0:l^ x6._A777ݰn@87(?S9:v Bˆ7Ə+1A/4Ű*U #!Å/d8K0d2ʥB>MX4>۬fѠj*0߇f2h2Þwv03X,ϨWmD 95084 jP:hXmp$O$Sl._,jȆ)†nz pS%t}"phҁء ꄐ& >,@ *bb22.II C +d(2@x,>tحɠi5*%ahu7G F3laC^gf`Xu؏ReC6j̩؀j@6հ@j*F3Mfp=^_  +Gc4l"& ^tp etG8A1!H V\haI$[  W_"P /'1B $CPg3! ~rmVhk5jR.3P3 ̀df؅ffؼb~.05PC;UVP`C!@ BRkuzlN"d* dÄ @݀l@7|nn..a'A":;<|z֩@kA P  (B12p'QBq$!dH& a v96l2uZJˀ `BR3C̰ͰUdaN:WUhf4ZsN +̮mFՀ%6vRIp`о#r9@R*_~ݧW?30l6mG}5OQd!r\ԐOj(j k`칲ʪXwW Ȇldž rCbܰ'8H9t@;(< Dicq  O Ű[O (YĠn2n#>p dhominj2TV;{d8 PRf +3B2a+3fl~ VC֖j6 l@5E CO7P_[S N 32Bf(B3\i\4a$3fl֫!SSC6!/ 5 j8l56TTVj -n`Åא lğ `atڣGM8p9xtvPx|6ǧiA  (ǚ@ ɀbHOdxp Å@N CK3&3N 1G `!  6ͶK]/M aPCl 5pj(6īk MN`Cyd;Ć $݀l 7Lqa#R4=x |&X@-.yb0#,//-jb"1 H ~dX&]"$C_/dǀ e` l l2C!͐!Ӛfv~T>S BQ EdC!@ g U1dC}KlBlx7 ~fat 0nH(7,-! IpH `Fg +Sp  (4b2 $ 2֊d2TUV N 4d 3 넄r^ l6sհ[a \M Pl`5$pj@6 =ȆK 7Gvataye$9 t;H +"X~*k`xaeyiiqaa~00Lbd0pG#G DK ]H&$CMuPf@2홁ȠQ2Cafg`l;SS u50!j6 @ g x5El̆in6u7$fg &t90L;F_ +? G.x^`X^Z0b@1 $-[IL D"Cc!VUd8f@f(-A3"`  h# fث̰ۚfvL VCRCRCՐj(B5 t6N@ UȆbC{`Cdž[ln@6 # s K6<:; f +?J  0fg3FQ $$ uP(@3fD3dX3l6RogjjE5Cà(Ԁl`5l`5f6T - }/vnI̦: @zab{ajAqa@^0`Mhb1  $A] #dUU +27PR f(3D43ni 6Ͷ{E5b5xl5ij5@ TASq  M =apѱɩirPt@;lX]ZތwV@,(-0t/0 aPkbdVdhc2Tґd@3`puP0c3!23Jc=fH}iol]5Sj8Ԑ!B#PCj@6Rـj(lm? v47LLN䰊rvx~`@h&IT@+ P : /$arb||lttd8Y _ ,_2\鑡Z0A3PZf(,(\ )3d 3fl׵a ?5 +58n8 j G fCN)6īkbÍd7  $7 8LJ8rXB90$H%('* B R06:22<448",&NL2tdǪ 2g3xd@3 hh4?"@3hfRf8̰Ϛf^^] f!/ J5 +A PԐ U$6t= dn  #R 䰈rtv < ddb$@ I^`@0  bŀd 1H2hbO!C{AJ0 h`B0C~~$v'D3&!͐Af8a5f)j؟B ٬@0r\7 +@ Ũ`٠ P=6 ?I7|nn ?90$It: XPZ.,  + CW>b@2O֖$23d3 + Hu! ``l{[a׋!KS 9R`Û?G6465& O?sܿࡂÈg ! ᓜHdʥȐBc}4ÏRfhܴ93\.sڳNaF AEPCj;Ȇ 6Æ-7$l7 YEanXs<$ !CځxPzP|0/~_N-X\^H$ ammuR $&C"*dx +23d@f( QyfAEeAȠPc̰ݙrFOUP/jh@6@ s90`C lhm:!fQSA@6(7LLVsڝ;wpA"`nzzC[X-.|E./@rV S"A&C" $Cb bf`2P0 |@m\.kVoPUCcF {AFPvaaԐfR& nPlPnpܰ%Qă҃!6D hbA \\H{;kk++KK!)1 "C( i +2 BdZ[Z@! =/L3 )34 jv83\.V[A@6P !|?(6Vl PC g6dAؠ00v 0/nCƃAA "aUrL5b-.h/$`aueyyŅb(!C d 43 RX0}/G332(34h3ܴP].jx1QCQCR54<0b 6 ]ll8 ↞^冡[ 1b9:h;F&$@,  )0,/-^\\u<0caXd4( .`Md@vf(A( ߣ Cl  7r\ ԰V XTC "laéu@7A/ Y7OLNNMOpAAAAb0PH-< 0>>6 +1 1(1\Ub(!`6~e!2 0CkKKTQO24 )34f2fr\[WCΨjhl6@ dAFQP(Vl8pTa gl6 lnr 02:66>11955=Ár8r0tH@e0<2::6>>1aAaI`@ +IaebgrU԰#aRC!a@6x yT* `CpHxu6a7(6 `ptßO-7 CC##c1Iҁvx ~0X'}k\X.^0L cc##CC}C7p͈ +2@ $Ġ12N I C +2B> =d M ; dpfp\粍԰mC55ݖ!dC `C +6t ɆÊ 'N +Ni67 t@7\npr qCp)9,PClA dKNHZX-$\H{@_o1\@d!/dxCᴐ' 4@rXTd'hAdM24 ua3rmA Y54Q #0 EaC 6 džׄ p7 tïC7nl᪸ +9:$v Cuӣ5CZA Z0\@0(/`QE (b E ^Bd2$C{f2(34 fqfp\.W&`! dn!V5 AFQP(J Ua/n~E7ndq=i8T0O:$v "2G٪ז  x!C_ooOwׯ]"1 ᆪ9Eׄ N&d8J2@__mgQIZ(+M$@t( ;Md2IfR&?<߻9{ + :%ݻs }}== Cg0 4420l3<7f0L&ӯ~Ьl6 ]N6%6 {ِPll 7 p>pnp@t =>0 $!,XJHT¿? ?Y`w751@ D " ü CdxGdx=48 2t 0"0CfxY3Wa~&daK - `@jz{^gC^a +l 7 +䆍Mrpp]s +Be9:8<@Թ * +K ą `x]_W+>b%1׈ K ,Pd(!Lda2a2 ] @d2A6C 1f0L&ǫ[ ͚^@ Agltፓ Q6L `aiܰ7lv57*uvs 8<8/=>?(Bdžt-(.Mv]V./b#1lC $"02LM y!Ӏ C}}== C'; A&C d2~=F M,6jhjh50: ==}}CF a i!Gl 7L 3䆅Er +a WJڂ=%E2or /qK  uR8??;aİJb 2 Cd)2$\dx!C7d2A53x``2LU _Z Æ ݍِ%6)a@nX"76 =vU.EABBswB +X@\^D^P`P\]]^(19İIbX#1, 3D0Ȑ'[ C3df :Z423L&7/ TC6 ]`C/B qbC0Nl 2aܰ@nX&7nUn8>9==;?pcG%E~ ៜ9+  ?Z^P`1*WI1I Dr@d( zhpp"C'a!28 όL&Ʉ&Zl 6H {ؐ$6d 9bP*O væCPQp@t:H;ЃG/%XXе@\\нpzr||txxa@d(DfhzL&筡9`ASΆ{ņnOb0aِ`6Ćaܰrܰp80 K;A +R+됷T BMxc`oowgg{kks%9tDd(I \Ȑf2Ę dɠ%dhdhe2Xf``2L&| ~QCK :450lx!lj t&Cl ɩR( ""j!ɬ@XZ.$^ y e1bd 10Z0P222 650UaàȆ vC27Ax`=0NďA +l‚ӂp*P ##f ӵdB_Jj jV5S6,ٰelhq!C"dA ~OeV ,]@Z.8/|$/0`haȰq2f f@!tp3lX%6  + Ɔ*$8'8r:Ẋ WzJVX -  +`b 0@b`2za&aD BW Q S^l6l n`8CdփA6p0S@Z./|^`00\T L Q LaȰNdXU2,92,Ȑ3!еˆȆnlXV66 qApEt< !ҁzP?Bm҂B á@b`2l 6 4ȀBY ]0Wdže:aSذMlP7gn8670^.. ",HCAђ7H ʅ+BÙ@`îa`dXS2~23f@!tcufÄgT6*6 rngs*C~hIgeah!p!xᒼTb81vH [$MaBF2J!P:WCUC K MrÖs#'#r9Bx`=-`ÂiyAp9pT#I $$  }Bݯ@o ̆ ĆĆmbC crD rxAx= ڲi}oXZ\^0`xF`İ_'M'RfM!PZِ CMrV G"sECăCD{6.X`Z .\./NJ`8$0TŰCbR1l$bX1aJf{B>֪v6gAܰݰGnxn(!,|P@$ylmc@\xPñP'*=0ٛ 0BφIdž ʆ9aB`C U7 %8*GփA2); +qBPBÑAİW#!C&%'$̀Bhza\6,flX#6x7lG7Ds(_a,x-Nj0Q JaޑaF3 ^7dž nh!A z0?DB4uXZ\P/D0D  K 7D3MC!t렆la.a(lP7vqCU90CD + xaV k0ӑ 3 :A_6 EqrpZ<DL!SD%?ւa?C1,G1 R2L !T†:7lfnˁ xP=(!Ӻ@$yұc!B26  b71 fj }B!륆 Ӂ nX7!ÞA v<RDs}ZH{/%'Ü  B;'eÜ!wAݐá(HCՃ/+n8+X jaIŰX#ô#3 t=>!s|AxP=?dcBB m`X60&@BawCʆn(¡*!")Á/nW Z`.^((aE 9 }B뤆^l9 RC4GUz =pdBeà ӑ nhC&GC" Zp\HPÊ] 2L !Ica"aÔcC7D8V E9C*#!$NpVP,2/l`X40bԈa^ B;Wk4&unpX!!CCCF}I \(y!Òn 0B[omQEƉ4K?֢8 Eֳt8 8׺<nx9rk=!k 1X8B A/TW Q2 *dC Q7|-vC/px=CVt8zT! Zx˅r/ԃ] I2XF[/B ?`-A3prȆ-sQ9鰴Zq@$2Hk!ʅ~ k0 C b |LfCTtXa&c!Ʌ^^x `8S$hK6\ p8kXK:CXXj!΅^^x n1<d n S9尤C)~N3$^x{! +o`Hd | ]P +b9,ZI@ 'd3΅P)/S  +}vC9z +r9,CPq?gdp΅~x1HnD6vc pHk;ÜhkV K.$$zŐ&Cg@fk6tC%r8A[ʽ^1HnOgSp(Cq;VOfcs 6dC!,x'DXB P( lnavhÄ|fJ/ԃb \˻a0rڡj ^hbn^pxhCTI:d!\{! b ܏MِvC;rHӡRcf I.$% 1tCi9$Pv>)MMj!ͅ`P r7!+,0\/ʎ Y-X|fᐗC!02 wPB8 C=&*7t;dlR8ʡ0‘ +P 8reZ]54] rheѝ\;R%_ 50[P-vSÏ^?|krxxh>y`P ޞpî{Po 6E;x &^U1@2x;eHSxR*_c| uvξbQ[v6Ćg̿wWg~nKٴwO>m*Å<~\%8 +i-8G&ܸ=qEGK}wp1gGw Ir s-G`Z`Vɿ  +endstream endobj 12 0 obj [/ICCBased 35 0 R] endobj 34 0 obj <>stream + +endstream endobj 35 0 obj <>stream +HyTSwoɞc [5laQIBHADED2mtFOE.c}08׎8GNg9w߽'0 ֠Jb  + 2y.-;!KZ ^i"L0- @8(r;q7Ly&Qq4j|9 +V)gB0iW8#8wթ8_٥ʨQQj@&A)/g>'Kt;\ ӥ$պFZUn(4T%)뫔0C&Zi8bxEB;Pӓ̹A om?W= +x-[0}y)7ta>jT7@tܛ`q2ʀ&6ZLĄ?_yxg)˔zçLU*uSkSeO4?׸c. R ߁-25 S>ӣVd`rn~Y&+`;A4 A9=-tl`;~p Gp| [`L`< "A YA+Cb(R,*T2B- +ꇆnQt}MA0alSx k&^>0|>_',G!"F$H:R!zFQd?r 9\A&G rQ hE]a4zBgE#H *B=0HIpp0MxJ$D1D, VĭKĻYdE"EI2EBGt4MzNr!YK ?%_&#(0J:EAiQ(()ӔWT6U@P+!~mD eԴ!hӦh/']B/ҏӿ?a0nhF!X8܌kc&5S6lIa2cKMA!E#ƒdV(kel }}Cq9 +N')].uJr + wG xR^[oƜchg`>b$*~ :Eb~,m,-ݖ,Y¬*6X[ݱF=3뭷Y~dó ti zf6~`{v.Ng#{}}jc1X6fm;'_9 r:8q:˜O:ϸ8uJqnv=MmR 4 +n3ܣkGݯz=[==<=GTB(/S,]6*-W:#7*e^YDY}UjAyT`#D="b{ų+ʯ:!kJ4Gmt}uC%K7YVfFY .=b?SƕƩȺy چ k5%4m7lqlioZlG+Zz͹mzy]?uuw|"űNwW&e֥ﺱ*|j5kyݭǯg^ykEklD_p߶7Dmo꿻1ml{Mś nLl<9O[$h՛BdҞ@iءG&vVǥ8nRĩ7u\ЭD-u`ֲK³8%yhYѹJº;.! +zpg_XQKFAǿ=ȼ:ɹ8ʷ6˶5̵5͵6ζ7ϸ9к<Ѿ?DINU\dlvۀ܊ݖޢ)߯6DScs 2F[p(@Xr4Pm8Ww)Km +endstream endobj 31 0 obj <> endobj 36 0 obj <> endobj 37 0 obj [0.0 0.0 0.0] endobj 38 0 obj <>/ProcSet[/PDF/ImageB]/XObject<>>>/Subtype/Form>>stream +q +/GS0 gs +2101 0 0 2880 997 1020 cm +/Im0 Do +Q + +endstream endobj 39 0 obj <> endobj 41 0 obj <>/Filter/FlateDecode/Height 2880/Intent/RelativeColorimetric/Length 201876/Name/X/Subtype/Image/Type/XObject/Width 2101>>stream +H׉zH$$K@Г ݳ_Դ\VT)J]}W Ky|CDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDvt~#DDD'V0D+=+[s (*=S"""*Rrс*=RHDDJ1V ]m=J]""a*RLDDKw*ʼn+g#[(퉈|K""ټ#^A^bK ""j ) n " +7@DDZ8T\8x&ءp~/N=zkr(}/DDt s=C!"Sl@0^)4 J_X!o6/Ah\SFBW;7XQ @!r DDTW,<m=DDDG\1섅ҫvC7("":! |tWEDDWO1xamC:p^bH„=0\=@DD*_ I^8m&e48"":@dNR:vC`Ő~r0J_ML2! iz=z Kn DDCUy!yn(}qDD4rȐ N,$lD ܀h؆C iT(=-ipwGDD+ q1DХuO^!v7""~d!*Cn8Dݐ̆GDD* bPЪM}zte"F n DDc=ȠACL }lBeDp! o&ndŠ!ào ~PAsl "'C0\HdJ$J8t6%\%C\ "\3re)Zpsj "rɐ 8"X臃ըg@DD;3<1`hBJ~D"pЛ oY2!M LXU .7䱡U$*4,df3BCDmnhaC`yD1`Y!'S&&4=D P6hT" \0DℤE~1BG \6< (n3tJ! q&$- +<:8rJ! $Y 1(`pXnGZX(zpC 6u84C.t1,%.(VW#,=(tX +9n@DDz;S  <,DͯG[,>(tX 94pvl "e! "^cB2ߍ\X|PnuCPKZЀAxBH|7r\!M# v7leCk%"! mbh\.+JpÑ<8hnX7t2 tk%C IddŰ +>}Lkp  nЮ Q\2\dXJ2DƈBa@ (CcK!7 ,:46""2%g(V*<18`jAJA/~5W!A熐 V6jP؀N 3dfɰސ!. )0kOok8ݰ6n 5b pAIL,7|p찥 7lpAaCk&"}f j3d؈  5<%8he9!`Pa++6l0np`̨a.pQ9j ":`p)0ȰT""+1/</H.X+8NċՃG bnxuφdž`å@Dth5CMGW*2Јa# +L[׏?| `a o*7Unٰl0j""RJ0ÅgAY^Wd"C ]/.X,H(h8]'&$ ,\:9Tb`0\,P#?tQ*( ,vlC n- $PI [2^2dNJ 5/lZA:!F?M/ n`C +8X73n0l3lxa!0k؀3̅6d{G *1`^`0n2SBV>UpnxocOmÆey+@Dtp.`PafPaQa Ã# B +&VM@xCᆇ 6nٰذl6j pWC&"a4Ehkc0ò2ú2CE.}2bh ` ݿcRpB8nppaúbòbUܨZej ":rp嘡&â"ʐyHN1H0H/-X*8Hhf~P񰵃+ N7lxnذذlhpNffXVfX3k + <|V,\7'5+5,]5PщaK 6dXTdX5dhM ~P{rƂ߄ +D6rܰC<64jlXUlXl07l@ DD']3\[3<ݚaYaݘ2F[\QdiHr+u"4M(A n}os_8b^ZPVNpi|w9`ˡrpHtbCA`A&pKPuREQU13܈ЎfH$'Pd1 bbJ100/(.XNpiiBw9a؀n॰Њl8SEQ7YІfp̠ЏdpĠ0`^ZXNphvr;Ђ0 ullЁjhC5H54s5 5PE]ef`dfhG3Xd@3PF2!"R`xscuG0& <(:h9p8$pЗPÆvdP`H EQW2#C!@2M2 #L1$yAq 6& =ՐjTjh7#( +  h\ |P*m2'&'b`P^`\XTLp\lewD ! `!ɉq`è͆~`COOl0 |P \ _T j 4PE]N ]hl6y~Qd(e Cn@ VQ & ;)}{/ԁ!lL(A=p;0: P ssf SS l l6˥"! =/͢H EQWo7CK w L6|?(f( @$àI 4yC ( a {|txsЈ|x`v`t@9Xp7n{0 l00l6J%PC> +\.ɠ5\#5PE]hk -a@ C?>a" anİ,Űb` `^oB .AAܰ!ݰn6XlF6G6z E`CA Ѝj<55ͧ(- M g4C!y y0C ׇddJ Q_e"փ;ógVWV 16T# !E~"5PE]N ݙl6y~fȣh4̀d3dXB26@ [,08$1֟yŎ1!$$~A:l7<7 K&@ PPF5A yL ݧEQK1 7p; !P3 hNCeFu M.ݽ/9L/G/0.h+(&,_N&"փ{˗{ [`:còÆ`j6( n'WC +H EQRР E3tf f2 ` 6 [ۮ58$4o եFăAaqp`afZԀl5P 7jpYEQ1k 7b!3 f 3"!FǛ@'O _bxf[#a0oBBAсA7o^v pC S dj 5侢L ׏(ul3\fhN6CWWw0Cɠ͠ɰɰd1)908nxn@6li6,lPj`l`j6 +!ՕfREQ%- M'1Cf(bd3d~bk.ã# $ !wV@mW(B>p<0;p9|pttxpܰ n@6 6,. l@5@ IД (]2YhV<4CPf`dH2C; W޿#çO Ln8>j P4g @]ދhUWp Ɏ11M˜{n|?9{WTEF05`Aaa!2ܐB7  668VÉbj4@j(vd2s ;!!2h1`^`\`ZVR0 O񪥵ɺ + EfF!  ـn  L ?ޝH EQ}fxS13IFAa~-A_,/*?X4!!`y c9tȆ"j6p5]a_EQUrhfh`f8P 'ޒfp&C6 FAAaAzAj[AB<_Y{PFh ! బ09n@6L6h5taP[L 'A NjPGRC)4(*f7h7CN4&`b2h1np0h/ZVPLk}Ǖf\ 9h8h7 tPGN9ծFS ԰׏(*Nаk3v2 C73$C 2b`d1 Kk d/!$4f tP0 -आӻVC(ګ)'34 glf2tJ3  H$Ű(p۷ 0\ZTPNWox*ɘoaEd`C4l5 ": 65ٙ J 3ۥΞSf2f@2 n0'C,0ɀb`d1, 1|?" `@'VtsmЈ~x`vr`pXpPnXB7  6$1PjA656(5v}JaEQUrfWfد̀hfhkf8f3{K3\?f@2ANHBÝ;wC0^0`u3* +E9p8Xl`na$ >˗]Pc\ mR J j!5PEUG5% Јf8м3g(3t^df3 @P8ɐdb{UǂBB(l"sZ fCޕnX`eC&blCPkxpS`jhfj8jhjhQ {$(b0C]I3h3.g/03\f3x>d@1ܖbKA+ +,P|vt`rp0p YƆx, +l}^app*SÅwj#5PEU]5hff'dN3C4C_?x`( dH$rcNd@1b-rk[A9b_;@M(Ap=H;8h7anp`X!6Cq@ }+]L T  54 5j/PC ( +r4C;(ᄳ33\F3]n#X"9J#'bXb`x`hAPA)ڮmІ|0 px$ܰnpd8!I&bH8npἳNr5;ajհׯ(r  JCfKhn0аp4O$SL09Ƞŀdbxb`^ZVR0 +ߕk-P|`x`v0  ņIdC6N%X4 +|^{xhpЍjai5bjhjh8hjhj3PCj(ѠPlB3h. .Ñh,Ie1 t L @C  a>?VdC !tD:09h8nX[n!? lˍf3d"vA P >pTjhvVC}5( +s4C  Ma4C[{GH3t .‘X19cd (Z Ϟ!678$^I|&$ 67 +)cL~jrb<7ͤFX4 +|^kx jRF Q Z( Pg@QU9Vnfֶv02f fv{@0T:͍ONMg 7 2}! 768 L + + +u{aCB鰍t`r`p`nxŚȆX.Ix4^{xhST cB m\  65+5Ԓ( ЬppL ] C.‘X<1JgGs@囒 kR HW R + 6ֿ f*!^pX_70ɑt&/^d p L ^|`^`\XTHf,-Pz`v`trF8|bkK1w K\_OOM岙H2CA+sg~xPCPCTCPC]q5(PPo7G 3C3AmG3 |*K8^( y;FPtch%C9g:w4M(*(*n^7￵9طykO{N=`+W5hmhuzlٝ.`2ĥd1Q1ܽ{oax!xsZυ^lVD J@, {wR7a7(!y.f5zVz+/|"5|հ @ SC>mL ,)a; %`1C6^k0斛=>`4[v"21d@bMŰ`X`/p\ X p73{)LObJaq6! q`Cq;vl4}Ύ֛-A _gSCMD {*PC UC1GC ,)aDf(f(̰Gfl23\3|ffFj;]n@ H 1,/0/`.-P+N൴7?deAayYpφbC8 }^iY&^ק55|j$RC#R P5Trj(HQ ۔b!aod2ZP̀ 7 ffhkhub;n#QD$GID" ʊ  +"$p'qY%.lL%Ć ʆ$bC4^[-&AtueWQ5jPUeN ;jcj`XL  + + ŀl  ;83U4W -zl.Ch a0%'  +VjUJ xtrpX]}u= h$ }^aYF^ǩ+NJ@@԰Aj(j(5b5P5Ѱbr<%4fHd2J]^P̀ЀͰobZdfGӧLfty@( C 2 1 2İF^\ ZV1!C) _Aᰶ&v}1&0RD< ~tجfAtwv5|Z5| +T"jcj`X\,S34P34 3jdJ0B`!3546> Wf0,V`(%0aRF +Ó'k8)H \?(ǜKqf+BP=;`:9P8=y#p P*9E#`b2JpUOϜnjlCj8pH {v*jUSAC X,+ˊ|lB0C15C g +0.Woi斛]ݽ`4[lvBH,H#@L2bx +b` ^\ ZX?)Lii*Axvt r8 7<%nX7da +02N &X$ +nnVz9԰ PԠ5P5 +95ՐbXWV3l̰P$2CiJ./Gf@hf@hfAf8Pt +pvk38]?Dcdj(=2:0=ÑD _x-pTQ9V9)AP=;rp@nx|c1rc4bHz(HĢP[,TSc=UC UFQ*rR@  <_ bpY@PPfЀPR*~ˏf8 gϲO7V`8'"ì D$uN < <(x'dofŃ  +M G w fg&Fөd"v:lVɠeQg>Aj8հX  X H j @Րϫbrf7C APf@hp (2ÉS_xKz3^_ <&= H O=#bxb@ `AB ?r6!AW֞86lJ%h8y.A =b5|yD O55ם@j8 +j8x@ݻ@ H *PC "PA ۙX,+ˊj "3b3#3 4Hp02C-2F0gQ3|#3dډH4LG'goa2,Ȱ T F?W5C ( gO 0nLOMSX4 +5حQoΝP!vV!5c5JPP VCbf[!_d e*C6C521d:0̠#fp<^?6C<JOLNߺ}Ȱ H /7791 0yj %BɔfBl6o 7"[3ӓ#d"z\NH W$j8jCj8V{CQC%RZ*5h GSbX[@ %`2C@Ͱod#ǎc34~u翸x 60#@254<26>15=;7?K"ëׯ911Hp-oCeۘ) +Ar7%Ăv멭3Us$ סzG^D&''LnM*! ITcHc`&{bFyoLONܹ}k׮|_!5R.Z 5UH FR 5dgj4 5H@ RGTJAf4̐fP5Zhpf3edO^ᑱɩ9ùx mbx@y7۟W%Q@ 8: 9yh7<ag bC(lz N}nvzjr|ld]Ej1585YFԠ5rANA*WFåtF )A2!6 `F3M Uյu "3|2́[CwG&&gfNׂb2| d`g Cw/XɁ! X8#8nkp %`,ٙɉ;Cn"5|q\ H H uUH &Ԡ5Sj`@! !R@ 2 IА2 Y`BJ&s3C#2CG3|p6ܼr{|!,&7vwY1@y'DXx::Qx;0rq. brX:B:ЁȩZd6:Z,,5dgej4rIR 0p8.; 4"40fH rr +ZLf֌{f0x6c9õ`pC^ ,X/\` bxbJNyL;t`sCpwBu/)J o 2j\/]ۍlk(+-Z!7GtPLFT"VKNCe3 4 R$ i84 3**Vg0"3WV!345!3fxGl #cS3vp$.{80p^`C!) |zF%e9p`ݰ` dJ<BEv93Sc#H 7_"P;Z*JVR* +84PjH5$!EjpQFånI 4 3X3dfe + jNo4Y3745utRfx6b3 !3LLN; n‘h|eum]H {{1 0jA!,h8Pn8`ݰ@ȆՕxt9~ǽtLON 5 (5tv4752j(zVR295@ r$F gh4$R$f2d `)A`@ 9 +ZL"kIiyEUum]CU0[I00;gw<^b Dcq ] #5 CPûKޞf[c}]MUeyYIqdj ?/';KtPRD B@ 4`5p8\@D*%HR&484rr + +*F7E֒򊪚Ʀֶn0E0` %aa-KhleumcEh2|d8<<& -TH~Nߖ<X;Pt`C` Slغ.EVL25\5 jjhkmnj(/-MNV) + rx4rIR<KAh83 4$R e20BkW2  +Jffx>2'I`Z,+kpdŐ pEd]ځC(7< ;67VRRÂӑ/A 5jxbkj(+-ZFNQ)Wx5dd2  Z /WFåDI B/84R$er@20CvNح-L/Pur2zﲪ%KlY{ NBL2Hލ+ 2!`INo_wo-mϼOf:{_}/_?84 f%O@۷bHBZ +ɢ<i;PrH!۷ ?0<4yr/|W@j8w3NPjص԰jHT'*p+svl2uJ!I% + H EBqU4d^i 48. H3 )*Vg0-RH4VJׂփ@f82Cf2p pN`x!X+t ^0@فCfgg6ba 048فYj8Haa}am}]*YE#q;6hi5*B&5~R y<.CBC0p8Em,4f(Ͱ|@Ѐ *KerJ&ty@(+5`0æ- {#3c0å+]=}C# Sh2޽K! ,d;!kdK &v 吆rݻ33600:2<4q!5ߋ԰e P[ǢPRdjB.KDH  Br9h5PjAr[= +i4p8\/ 3hxO \Tkzl.w G㕉ں5 `uv&p4C _"3\tphx*! ?p%42^`XmdQ0! 3i2!1 2 0a% +0p8ňm6 + 4fpy<0a"D*S(U`2[mvS X*_ fظyi3;&a3 0BadIM 1d EY`ꁢCZ On`PM`aP[ !5!ci5ܾuƵdUe< 2aY&^Q)2D,*^TCq9 +@r[ܖ- +3hry|@CL4J\Rkuzb+u8e^0)W$k M-m 3ڳ#GI32ç`3 3OLM_2M0I~Gd rY-( (:p vlwfR7MOM!5 fp)Rj8zЁ}{vjhkijXS_[SGBAtZ-&^UrD\"*f y\.B jȃ +rPF VLTizlٝ.DU2Uкnæ-vPf8~w3cadɩ 7̀&#DZ L0dCnE0@с G4lMSH yp,R;Op쭛_~ᬆP 15  tQP\bKL1E"#´@JK}$"封p454 FsDU  ( + h،C ̀ჿlX")|U~ MV7FZI Y9yE%eU5u M-mv3*f`oq3`dfdŕ (`psc +@ @65`l-PÝ[_P C /' !9o1D:m&(@UȤHq!Ѱ h@j@Pw ̀hf аÛBG&W(U@Mp.,Bo2-q ťյͭݽ;wރqh &8h=̀gG2bX&@ u;CP@e lgTGC5|㤆+S&.@5?aݝ͍ՕŅ@ i)Ą8eGB5jR!HDBj b4q4`jjpEF +ZܠnM 8ht@ 4py|H,*?u@&D 4cbIɩٹa߁CGΜsk9I% +bJέ!(tp H6ff3Ahy@%G2ɀ ZBٟvpxwG6,665l>T,PP ׯL5L\8pȡFGz:Zp5fgfbcp6DSeRX(8lo/ @  ( +mx<)h /G4p2O # ظD[JZFVNح(g5'x MTi00{{ޫHE1 +IٳID$7,zy>!aQ1q I)iY9y յͭFƀ3,fG`} 2H具ItoJg$X ˈF567VW5de$%DExy89XYp,5&FUQ&J +hjE -B5H$J1DAAd[ "LQљ,u6GW?084<2:6>195=3'oabrjzfamca {fK@.w B1A +oTBB"8 ng=lx #55lnA5LOMNC5tu45TUeg&'FGz{:;Z[Zr5j :MB& Ѐh4bhºtPh2 oРD )T`kqt M-l\<|B"bR2s K+kfwaQhmI32Ͱ|~FH ^B{wDn8b(6<.a_I5l հpP`o7TCc}mueyiqa~nvfZJRB\LTDXHP[dШe2FP CA"4`j%i+bfAi  |*Dí DB3T549F&fֶή޾ѱiY9yE%e ݈ͭf_\^Y[) 3 <_ 'b8ŅW]%n@A x?Z OEjX_[Y^j{glQCg{k3PCUEYIQA^NVFZrb|ltdxhp.G[SC]MAP$P @ Eh R + W04`aaa]J  x9 nB4($e +FgZ:zƦfV6vN.n^>~A!aQ1q IٹeU5u M-m]=}C# Sӳ K+[wC3<{b1÷B3b.  $ÉN o`-#8|>E؀[D /?jxp{ks}ueia~vzjah0?7;3=5)!.&*",$(P_OG[ReiT2HPh)TD@A>ЀuIPh2 oA^AQ@"+P KCSg`dbjnimkWPTZ^Y][?8<:>033܇fkhSd3n@r8 bljx}(y<հ07sjrb|tx /'+#-%1>6:2<48@ORc2Te2 Y<BbhºGbhF ɧn޺ @ RgkjYX98yxED%$gfUT54a{gW6<|_iW |Adq2H|+\6׃NQdᡀχjxuxGlm./5ܻ{glDԤ?/7';+ 3cC}]mM:KIP$"d4Hp A XXXX̀Bb<@h D2Jc0Xl-#@`phxdtl|bJZFVN^aqiyeum}SK[GWO0G; _>47(3A B1z$1/+AÑ~=r @ Ej8@_=aI₼@_o ֖Fz:-KɠQ)d"AI3D  r xPh . Bh~ +JDYYJgkhjst L,l]=B"bS3s J*j[;{G'fVV7@3<  oH7P`8 }l~dÛ7@ jzo9TՕSÃݝ͍u5Ue%EٙI q1Qa!AޞΎ6Vf&FmM u5UL&4(ȟAVFá  =I WA4Y`n4$e +Teu M-\<|C#cn]=(m;Sݽ/Ԁ@݊[qH@HpK]}؝)ss! rgvWPTRVQUSW?8<:fs"iiyunV3ysxtt|B7 R_L7e8pN߼aU] kK$"a?Nb5vw67TUde$%Dz{89XYjk()JKIQHAǏBhBh u5 3ܡDgh _!D KJ+*ih[Z;:{ED'&?K/,.-}7042H7*e49~d ] ^pp#hn8gÏt60[V5P)Eanv75hkijxQ[]Y^Z6:",$(P_WGKCMEYQ^NFJR\LDBh>. t59W888%3ܢ2894< O#PhaQ1 IiY9%eUuMm=#3 +;'7/_𨘸zG'ӳ +hm +u0KV3 `Ats=0Á-hj8=9>>::< /'+#-%)!.&2<48@OGKS]UYIANVZRBLTD=}r@ <\ 4܂-h{ x@4|O = D"R2J*jںƦֶή~A!aѱɩٹťյͭݽC#cI,n?O VV7ԝ] 29~b ot2zM ns6Dg){5԰C%jX]Y" v362Emueyiب_oOwWgG{[kKsScC}]mM 5%EyY) qQ4 +)C 4@hࠣ[t Y1{ 4܇DBSPTVU3021sprq  KHJI+(*)y7042:>1#,W66ɔ= ?c6wt3B lp/&8;=99>:bVg5PۛkK4njb|tdh /'+YJRB\tdxhp#=- 5UeEy9)Iq1aR!R@4c0S@7 44phx'OB(. ή޾A!aQ1ɩٹťյͭݽãI,~~EPwA3|f bV ^ځ lT.B\_[Y^$.gٙiɉ1Qa!ޞv6Vf&t5UUd%%DH!A?' hx0F{F' |zh@"QhQq )YyE%5 -m]}CcSsKk[{Gg7/؄gY9yE%eU5/Z:zF0SHZZY]ڦPw 3|hod s2Jv~b/gl՗vՕ%0MM`Fz:Zj*J + rҟ$%FGxy:;Z[jki()HIQHAǏP8߂[0uoA]:8884DBSPTVU3021sprq KLNM^\Z^Y][?8<:>1_ -.mln;/_AfD f \2{?nh&7Asù~eV4| ˃*y{scmuy0?7;lomn,/-~`gceafbd '#%).&"B +!@4D7' wa4nc hx'OB(_@PHXdtl|Rʳ’1$7'V7Ȕ= ٚ33|f6d`C wP ?{jx aoJ!om,- v36?vꫭiݳE*-bwR5H !haw:ә)=CG^vބ@BB۲{uw67VWd&'Dxy8Z[SР(/'#%!.&",(NjB"4p>E=*0E 4@j]hD*qh(^~!aQ,l\=}B"cS2r K˫jZ:zF'g0Kյ ~k@?853O!)- +1%7PpJa4jxCÃ]"a{ X[.-bf'Fz:ZjK s2Rc#B|=]l,L ?{@8ZTXH4p<P]vv6VV gjEU(((9n^ D7 D +%e4hhiYX;:zxG%$gfUT76wvOL/,-6w$ Gf4[N d`>tnj8!-op|KoWWf&G{;[k+J +r3Sb"C|]m,L tu4Te$Т"B|<($ !U ^-3У9XXX4ܣC'7 D  +KH+*k>y칾`HXDTl|brZFVN^aqiyeM]CSK[GWOlʆjx=.ag X[./bg''Fz:Zj*K r2Ғc"B}=\l-M ?{DS]UYQ^NFJB\LDXPD8p@+ 9n3AWl h wp 4H^~!aQ9,l]=B#cR2sJ*j[;{G'f0 Kؕu6@6k d3|z3L5%2\~*80(jT.[_[.-LMvw67TUfg$%FGy{:;XYAMEIANFZR-*,$˃D4@%l77WˋɉҢĸ@?/7gG{[k 3#=]m-  ҒhQ!A~>񈊆 XYA4p >p[ h bh!(^>Aa1q ) ʪO>{ohljnim_X\VQUS?8<:>153YX®["ioK\2) Й d9\fù~ޜHD]ZLMvw67TUfg$FGz{89Z[?􉦺ZLDXPøA4<@]4܂u}2XXX4ܣC'7SPR@_@PhxdL\BRjzfv^AQIyeum}cK[GWO^nΎf&Fz:Zj d%Ѣ"d4pc 4FL(((/n\Bß4 4pHZBJZV^QYU]D٭뷶Ϯ֮@e?] ww(uRݽw.AB!!*g?=ɗB x,l]=|C#^ b2yE%eU5ͭm]=}Cãi4;$2n=fq @fxG7^2|^؍vn @SÏ{ +PiH$j|txh 7xhoceafl Bý;n\SQVThxwp +B  ppppGW2h`g2yyE$$e\РACPHXdTtlBRJZfVN^aqiyeu- ݽC#c) v7OX 43fUf3tXO٧Ɂ V!5l5P2yD\ f3 `owg;@C}mueyiqa^NVfZJRBltTdXH@ u5m4\QR梡<] 44`gR t5U888k4? g_PHDT\BJZV^w?xZ:zƦ6vN>~Aᑈtdvn~aIYEUM]CSK[GWO8jr"LYa6[` *>@>n`}jR7ց2aL&- xDtu45TUf#SbA~ޞNv֖z:Zϟ>~o^zEIQ^VZJB\TDHs/|`5oh`cch8˄K9xxE%dU1A[W?08,"6>1%-WPTR^Y][?0426>15=%2e%@dV 3ljGA7MH k@ ^PK$a7lomn,+)*Af$"^Dxy:;XYj3AEYQ^NFJB/KLh8 @÷;h8HH4bt4\OG@Í[wk1%-WPTZ^Y][pxd 59`pxqD^3A0ڎhh_!42X}5 ;jX7@ e2iH$jldx /x`gcenjlGܿ{uEyY) qQ!A~>Na h8@t4aB622@/I)9yEek 4<741wtq + MHJI/,.-khji%2e]34olP77}f8 )nx ԰IjX}P@ +D".f13ӓÃ}=]m-M u5UŅ9Y)I Qa!^nΎVf&ښLhPQV4هo`4]_Dqhࠡ..4 ,"&.)-#p֝{jO L,m\=B#1qɩ^1z;Ieʫ׻hfXߠR7>  "|LհIn԰7_Pɤ7AOMFz;[*Js q1_oO7'{[kK3#=mgO4Tݹu@/@%&4h`gcۏ[__M 8UGg ^B;"ޥwJ=F +3W3{ޗ sxs|6 ,a'%$eTT4\D}-m=CcSs+;GgW/o蘸Ĥy4wv $2J3Xc.o|b SSӈ>} kaK^6,S'L BT SS jq9c,FIA@_Owg{+̴Р_o/wWg;KsScC=mh8yaM 5U%Ey9iI q}{145?6C4`0F&~Av sf؃AL\B +CNMg_|wt ,l<|C#D'&gWV7465utu Cä(d9E4|CZfyaY5h@j԰ɉq.b2hP_W[]Y^RT$"48P_ׯ^xi#4p$4 Ԁa;- 0 - ̀ar4SPTV4;{>721wrq|46YrjFVN^aq)@/_~o?H&PG X4@4_ 13I~ݺذY5iZP@c10qW/_<h(-.HM~4*",8籧Dp@:NEYQANVZJR\ ]@ h؆S +h;D }; ߯KpE*N]0@é3.\rƭ; :zFvN޾A!Q1q I)iٹ%eU5hh Id +Fg.obr >4!3`hXn:EÂ>a &'x\ŤӨ28HlGCMUEYqa~nvFZʳȰ _oOwW';kKs#={wnݸv҅sgN!hTǩ*+)ʠh8 ;VBh`jhA [4H,A qQ4hi[98zxyGF'&gfUV7465utu Cä(csx 4LMO m~OE? Ѐaa1Qixhkinjl(+)*LOIJ  +rwuv2756Z5 а_ ?/G 0 aM+' ̣a>q Ii9yE%U5  'O=7o߽ohlfaec$:6>195=+'W߼mh*`qw1434p fXD$ÊQ4̩avA Bh@0&y\AQ)a ׯ^4Td&'F? psv056h(N<Р(/'#-)!аo<~AӶ[aD }:6chزDа{1q ) 85CG#]}#3 k[{'7>!aQOc%edVT<7@"F(4p'4 f@05=A' 2F:E0#@ 5 hr,&6J!94x^SUQZ\,!iTDXHcO7'{[k 3C}GQ4\|Y Gi04HI!hسEh `ןB943BpPL\RJZVNAQYp) {𑞁PHXdTL\BRJZfvn~QIYEUm]}CcSsK[GWwo?04L164 fhhf} V1F_j@рwD Bh@ۯx\A~Ɔ:̴Ȱ _oOw'[kKs#,1u,(vj@аEÖdk5mpE @*N]03.\rm=cSsK;gWw/oĤ켂j4 d +Fg8\;4L4™ 1>:0afF(4Lc14*195=+'^y @"ȔQbs03 hB̿14AshX }^Uc%ICc%v@Dc#{DQR,]e" {oD$l}aarƀjh` '=|pέ*J +s3Rc"‚|]-M /^8wf:vlۢy2֮%b4|4|рp [hXdаTU 2U4 Ch8r)-=cSs+;GgW/_؄켂K@4ܯholn!I.J`hfhp<h7 |3L9f\jjxr8 P |4 {Y :A& -͍ U W._*)*LOIJ puv2756h8u}{v4h(#4l@hX= KF@  8 RRC4,a +U4nh 5t M-l]<}B#S3s +K߼}yCcskMљ޾~hp   {4:} hahK^Nh$ jk*߽}:@CiqA^NfzjRB\tdxHyÇ؏аUCMUyL SB5LhjahpdЩ=]dR' ܺPVR`kmifb}џ!ۻa&y915@4| F-tӹ аa 49Рg`djnimTRv +BCeUu DCcs NLV/1q&hU9 /lSï5 4L0r9c@  @  ^NtuIDBKs#BCuBõ+J +r3Rc"‚}]-M /^8ӏ?|а a3B|4wST 4|Ѱa 4YNFvF95Dh8q +AKG?0$,2:6!)5=3'@wC4=ohlnm#wtvS4hypy<&f KH SB5Lr8 P ^he14*Nlkhx^W[S]Uy J +3Sb#B}<\lM tΜ:!Bî j +r@E _4|6p8kh=hX= *j {?p# 4 M-l<}B#Sӳr +K/U\> M-m*h卋0)D< }KaR. C}^&0 ׯ4d&'EGz{9;XYhiB4;аoD 2 ߃1p8N} Ѱ +AZFvFyE3p_@PhxTL\brjFVN~aqY9@í;<|g 6Y@ 4h ^$S 4Fihh`1Ԟ2PǏ>w!?'+#591.&2<4(PYÇ؏аAQA~YiUb4,hpKoAdѰL3Ѡ +а} 'O4hYX:8{FD'ed4\1 -"Eљ޾~8. 40 $mI7j@h@jr8 |5@440JW'D$47pƵܬ?Ow'[k 3C}]m'hعAu&VΆhAJjb|4hX'-~&E%eUu{h8zᢶ_`pXDTl|RJZfvn@+ +kj Z vrg7Jc0Yl>Dt4`39 @L4\a>6DIn'Z!jk*n}?Ea;KDSذc]c{{ウ`ػ"RD`!hewawQIO|? ǎdLg$'DEx89Xjk(G4lE򥈆͙=Sv)2҈I<4h3z(FD0Ch0,$hXz WRU3065wpru OLag4>CCNnރ"& ,@Cs m4tsC7;Ifa$ᝰzP n!4 h`40 + 9<4d= h8HI rwur2756TWUڿw7akW$hX(Pø0FĢah3L hJ0a0v4(kZX;8zxED'022=~  Ҳ:@C /^rp ]\3G{ h[$P  . u5Օeb@YRF44Eh |44Aéi q1o7D"as0aA@÷ 46lAÈAa,Da2.lC4#h74hHLNM4#htڍ[wr   M hE{1h;Ġ(ECSC=Yѐs֍kW.44&'"B|=\ L u !ma A0KvjhhaX4}0Y VZn&=5D ~Qlr ER:V}#W6ӉhF3!fx3E wBh5tw#:9l6gzVAC)АCÅlD@hѠh?`|ՙܙ45j5{ctԠ1bCwPҤ; +H38|g+.;>O0lȠR M0]U;4`֩sW4X9\ 34lCѰ Q qR4q4s4JP!EA4T|<%Dh8zaE6ܗ.4lеs'3 mECCDaػL?44j,GC  (I0quB@5 >~ .\Bp!)95-=#3!W 5Z4PR\TDPFC.ACvfFzZjrRb|\{ W.]`h8H hXf5C+i%Ah Q4tЉDaQ=L  h9a g7[wxEڻp9k7 1q rGC >s}N*ѐCА%!!.&pAù3 ‚  +/48pF`A0J vm)Zрaft=)Z=h4tv㺀sF@`HXn@ñ 4%hho EwR4!hlmhаa ! ($E/_FCrJ)CK%%hB4 U4+)!-%YW/_<ACxHPa Cò% ֓ HE7 a5AC3 ZI_ &Q4hаc-ai bb)22)8 uhhchȠhH!h}I@>/@ZU s v4"h\f ðzQ  ߋ;@?-ehشeN=j4D4ĩАMАFCACQQqN4E4h().*!W(5D6q4 h`g=y'h  0 Ìhh$CO4|I-C*4 h8iT@ +Vah pTԴtP ƾr}OJA P EC6!59)1>N V,[ +hCUhA>a3DaX}_@͠ >hB΀$A @| j4"h8,A=r5CDC-҉7ѐCѐB= 4h4lXa>CT;4([/[)EG DhԀh0 {bEhhk5z'Y9\ 34l4F4dhp +CCtL\GO$h(h(+304T jv4Th`jP(GCh+.04$h 4lhX0a횪i82 Nn4loIi?L]Mi4R3 _ޚ4|Q3 4pz4Lm; +i? aiضvkᶑixG4dPMCκNÓ?pi8{lmaiX4,M` aiا< GGixocm6 ߙh~ivl>4<]Gpd44,`0jLiiMó ᛑi4nx~o1 ߏL7 4_]sUi.Lñiا4l` +.> gӰhl*pbiz^{ͷGc{Gi4X3 SFak0<: 4R3 MU!OUy4M5pKe.7 t1 fӰia4lUƦVpwi:6 n?bupji4 LÊUӰNpΜ; u5 {ͧ| saVGp4\7wCa4lhiXzӰee&OwyJpEix1itCϧΦaiX4MӰqiO4U7 o4i4,ixnnƦ4=u4lYFaiX4Ipj< M&nyyvcLCu0 dcixnh(MƦ:aIw: +i詮᫮ᘺiر< o&uӰJiX4 Rϧa44|t~5 9 LïM4v.L iX}jӰآupJ4\[;Lû4|qiDlm> 6Mpncn7 /GaΜ3<9!9s:;O)iX4ZaS3pi(qpS44,k +iX4P5 4\x2yvӰi(a4,n!a0LM34%iXi84H V8P<44Valvb^OMCMl>W#p\e5 h piix4̜9kiQ\Ӱk6 ۙiسfNj< NY3gƧᾚi4+M4T3 {cViX4iHi pZ4j4gֻinN3 C4$4ׇi84i npia$iaR1iX4 L=@0= gN6 4|M; uOyN -ᬎaeP8!iyM ai h4 `3 I4\i!i8Ӑ4@iHi 4$4כi&MCLCLq!i8ӐN4lciHi 4$4gf3 I3 ęLCLq!iO8Lq!i8Ӑ4@iHi 4$?pi'LCLq!i8Ӑ4@iHi 4$4חi84i 4$4gf3 I3 ęLCLq!i8Ӑ4@iHP0LCLq!i8Ӑ4@iHi 4$4gf3 I3 ęLCLq!i8Ӑ4@iHi 4$4gf3 I3 ęLCLq!i8Ӑ4@iHi 4$4gf3 I3 ęLCLq!i8Ӑ4@iHi 4$4gf3 I3 ęLCLq!i8Ӑ4@iHi 4$4gf3 I3 ęLCLq!i8Ӑ4@iHi 4$4gf3 I3 ęLCLq!i8Ӑ4@iHi 4$4gf3 I3 ęLCLq1 ?HA44i' iOҤ4I?iH~Ґ& !MIC44i' iOҤ4I?iH~Ґ& !MIC44i' iOҤ4I?iH~Ґ& !MIC44i' iOҤ4I?iH~Ґ& !MIC44i' iOҤ4I?iH~Ґ& !MIC44i' iOҤ4I?iH~Ґ& !MIC44i' iOҤ4I?iH~Ґ& !MIC44i' iOҤ4I?iH~Ґ& !MIC44i' iOҤ4I?iH~Ґ& !MIC44i' iOҤ4I?iH~Ґ& !MIC44i' iOҤ4I?iH~Ґ& !MIC44i' iOҤ4I?iH~Ґ& !MIC44i' iOҤ4I?iH~Ґ& !MIC44i' iOҤ4I?iH~Ґ& !MIC44i' iOҤ4I?iH~Ґ& !MIC44i' iOҤ4I?iH~Ґ& !MIC44i' iOҤ4I?iH~Ґ& !MIC44i' iOҤ4I?iH~Ґ& !MIC44i' iOҤ4I?iH~Ґ& !MIC44i' iOҤ4I?iH~Ґ& !MIC44i' iOҤ4I?iH~Ґ& !MIC44i' iOҤ4I?iH~Ґ& !MIC44i' iOҤ4I?iH~Ґ& !MIC44i' iOҤ4I?iH~Ґ& !MIC44i' iOҤ4I?iH~Ґ& !MIC44i' iOҤ4I?iH~Ґ& !MIC44i' iOҤ4I?iH~Ґ& !MIC44i' iOҤ4I?iH~Ґ& !MIC44i' iOҤn +4\:i& tpM4I5ik@' פNI4\:i& tpM4I5ik@' פNI4\:i& tpM4I5ik@' פNI4\:i& tpM4I5ik@' פNI4\:i& tpM4I5ik@' פNI4\:i& tpM4I5ik@' פNI4\:i& tpM4I5ik@' פNI4\:i& tpM4I5ik@' פNI4\:i& tpM4I5ik@' פNI4\:i& tpM4I5ik@' פNI4\:i& tpM4I5ik@' פNI4\:i& tpM4I5ik@' פNI4\:i& tpM4I5ik@' פNI4\:i& tpM4I5ik@' פNI4\:i& tpM4I5ik@' פNI4\:i& tpM4I5ik@' פNI4\:i& tpM4I5ik@' פNI4\:i& tpM4I5ik@' פNI4\:i& tpM4I5ik@' פNI4\:i& tpM4I5ik@' פNI4\:i& tpM4I5ik@' פNI4\:i& tpM4I5ik@' פNI4\:i& tpM4I5ik@' פNI4\:i& tpM4I5ik@' פNI4\:i& tpM4I5ik@' פNI4\:i& tpM4I5ik@' פNI4\:i& tpM4I5ik@' פNI4\:i& tpM4I5ik@' פNI4\:i& tpMn +HC44i' iOҤ4I?iH~Ґ& !MIC44i' iOҤ4I?iH~Ґ& !MIC44i' iOҤ4I?iH~Ґ& !MIC44i' iOҤ4I?iH~Ґ& !MIC44i' iOҤ4I?iH~Ґ& !MIC44i' iOҤ4I?iH~Ґ& !MIC44i' iOҤ4I?iH~Ґ& !MIC44i' iOҤ4I?iH~Ґ& !MIC44i' iOҤ4I?iH~Ґ& !MIC44i' iOҤ4I?iH~Ґ& !MIC44i' iOҤ4I?iH~Ґ& !MIC44i' iOҤ4I?iH~Ґ& !MIC44i' iOҤ4I?iH~Ґ& !MIC44i' iOҤ4I?iH~Ґ& !MIC44i' iOҤ4I?iH~Ґ& !MIC44i' iOҤ4I?iH~Ґ& !MIC44i' iOҤ4I?iH~Ґ& !MIC44i' iOҤ4I?iH~Ґ& !MIC44i' iOҤ4I?iH~Ґ& !MIC44i' iOҤ4I?iH~Ґ& !MIC44i' iOҤ4I?iH~Ґ& !MIC44i' iOҤ4I?iH~Ґ& !MIC44i' iOҤ4I?iH~Ґ& !MIC44i' iOҤ4I?iH~Ґ& !MIC44i' iOҤ4I?iH~Ґ& !MIC44i' iOҤ4I?iH~Ґ& !MIC44i' iOҤ4I?iH~Ґ& !MIC44i' iOҤ4I?iH~Ґ& !MIC44i' iOҤ[~!4\:i& tpM4I5ik@' פNI4\:i& tpM4I5ik@' פNI4\:i& tpM4I5ik@' פNI4\:i& tpM4I5ik@' פNI4\:i& tpM4I5ik@' פNI4\:i& tpM4I5ik@' פNI4\:i& tpM4I5ik@' פNI4\:i& tpM4I5ik@' פNI4\:i& tpM4I5ik@' פNI4\:i& tpM4I5ik@' פNI4\:i& tpM4I5ik@' פNI4\:i& tpM4I5ik@' פNI4\:i& tpM4I5ik@' פNI4\:i& tpM4I5ik@' פNI4\:i& tpM4I5ik@' פNI4\:i& tpM4I5ik@' פNI4\:i& tpM4I5ik@' פNI4\:i& tpM4I5ik@' פNI4\:i& tpM4I5ik@' פNI4\:i& tpM4I5ik@' פNI4\:i& tpM4I5ik@' פNI4\:i& tpM4I5ik@' פNI4\:i& tpM4I5ik@' פNI4\:i& tpM4I5ik@' פNI4\:i& tpM4I5ik@' פNI4\:i& tpM4I5ik@' פNI4\:i& tpM4I5ik@' פNI4\:i& tpM4I5ik@' פNI4\:i& tpMuJvEQ$hu}{$d1ލ]܉4N4v!M4 ihH DCh`'D;ѐ&؉4N4v!M4 ihH DCh`'D;ѐ&؉4N4v!M4 ihH DCh`'D;ѐ&؉4N4v!M4 ihH DCh`'D;ѐ&؉4N4v!M4 ihH DCh`'D;ѐ&؉4N4v!M4 ihH DCh`'D;ѐ&؉4N4v!M4 ihH DCh`'D;ѐ&؉4N4v!M4 ihH DCh`'D;ѐ&؉4N4v!M4 ihH DCh`'D;ѐ&؉4N4v!M4 ihH DCh`'D;ѐ&؉4N4v!M4 ihH DCh`'D;ѐ&؉4N4v!M4 ihH DCh`'D;ѐ&؉4N4v!M4 ihH DCh`'D;ѐ&؉4N4v!M4 ihH DCh`'D;ѐ&؉4N4v!M4 ihH DCh`'D;ѐ&؉4N4v!M4 ihH DCh`'D;ѐ&؉4N4v!M4 ihH DCh`'D;ѐ&؉4N4v!M4 ihH DCh`'D;ѐ&؉4N4v!M4 ihH DCh`'D;ѐ&؉4N4v!M4 ihH DCh`'D;ѐ&؉4N4v!M4 ihH DCh`'D;ѐ&؉4N4v!M4 ihH DCh`'D;ѐ&؉4N4v!M4 ihH DCh`'D;ѐ&؉4w\7^E4OIK)ؔhh N9 =GsO[PiN7_*zD=_ M*#EChq;xȷOt}G4$<1|h ?īG>"iltUG4W_qOW“|h og헮~xu[<爆^}~ǀ3ͯ\&#ի'</t|!"ѣ[>v|xkv^v+A]L'_M4rű;;~&Ȝ~3o'BDN䘮~_P4wqיq`Bgt!D4-귻-EChx]yx`Oб1]{p{nt?iEOϽ)T4kM[o]у )K:>\4D+ѱ{~J6?nh /cwĊ r;_t~Z4{[WFCh䲓^Gũ ɇ[t@Xrei JK|8Ѱ]7@v& i闯/] C%b`4F'Dv|/=ֻe:dIR$i44=7Dvt10ٰ'Э~QE`#AIhhz n2csaّ0FZ3=F9`HtZK 4FìXvt/$][P!(IOKdٰLi4̸bɊa*1P 97@G<,($0߶$R-%?nO(f(Cq Q,K"AFChXU.|8`i67 FE9b)54J ;y1DKE2Ų +pnm"f$94K,Jk"Ii4MazȄfnF0B<=D10PZI MOafFˎ&|[VDje.oE"W݈C@0Qp Q~4FݑHvˎ<#)Vx"j^#K(#L(GSRQ6TDFCh!ԲCIlHP'(.o1EC ??=7CML1Jl6$i44=) \Gʮ p1 ~ e_ID7eC' !.,ED!P>h"XQfCIK|+0!@ʎ>.(=y$;W@7*] FFE"ÐC3e4'aE +Ihhz 3Tv\2 לb׽\E,;2wEQDC{cy/``YQ" +ɆzIhhz S*;}@v7ew!\6HԫU>}cP ½u$ +uR6"Ii4LAN:R@C ; :ݡ'uVv9ىIW݊1; aw^JF!B) + Ii4L/]Nv,Y ^vF· ፄ\wO$Bvቤՠ hG/o:lw[ C,A7po-x8yn < 4s3Lvd Σ!ûE3"|#ِsΒUʒg"y5[)  JlXI MOa463.u!;ua77RTtM`( + B \6o@ɔ>$0ue!>ed! ̍ %y?{7QFYo(! A~șP& ewAx Hr5h44=ddG&C^vO{=+p@H8;fn6#T Lw#C @GOf' +`X`P!Ihhz (9e1ǔpHL68O$>1QtQdfC0rdYrPrd +Hhhz cae;Lv&"ٙbxezn2١#tzٙl\${" +\ +1"aȔ7 b#dPl'4i`,n(7x4ڛF`2]Xvq2{5Rv#ٙtuCp#Nc鉤F`cS|2vu1tg;3ep +a2,g@iCeO͆8+$Ii4 %/}^v}tG4\v|8nx eey ̉ĸngvu-H0C=BpTY@9tt͆% 8$-P  MOa0.u2فd d$*d8nC٥Ap"L_OW0{Ce:²OrL.,h7vED'Ut7DQ󕟣di,E(OeC$i44=Ae.{enمq],;p#l]ΟHuu{Z F;9;1F"LwCLtz,?lOnݯM.x\l$HZ4FRnGRٽew7ljȝHZ -l(F(o.:Lwc6 uY|~~3D L%/p t$-MFCh(d쎝D # wb*;[VvJ"H(}6'҉]]z:L2<#᭣nbGh6/7 M JQ6D^;I MO:쎰}5]x`:FvLdH67Fv߲DzDHNJ03=0/ E]wG3!dfgޢH80`u UlU@".8LlN3O-FdBQʒq sV P01K 4 +\a!a4*ڲ !)+MnT N$VvʮKʮ?cýa F\% +^2L0EݮCBw/hpAPRgǀ  !ٵySɐ]1ͣn5,;I[ a7́F02y";ܫSQ atè##WPd0܇{~Nr4 ݠP +!ǂ  c˓.#9- NA+ ;l_e"uΐZub5d):=In)naHb|­W8x'@9T8n (.U cBRL_}!ҠCudUGMC%;Iu ;HWFJ͆DrtVMX ٽaw/B|dQw D>CBan#% +@А6Hv\A8H7\UȆ&r]C1Q¨ 00F9J!Ess-D!!Hآ{쎟lIB OB,n(]*0e!cBRL_}y]}bݩSv[{$[$H$;lVM$u6քp1u2F\޹ XB_ !EwL& Y +A8d$eCI !FC/FC|Ԓd7`e#GX Iq+T'-Ϥp$nXX)ȆR)}"d"} \wƹt ]!E!TywCy${ʻ\6M%)ZZZy!r 1B o;J)iۮ"-Jv6Hvj#-.05Ue"Dꦉ=\vw8$ly3F#.) (KdX2ݺEݭ2Ľ@19vJ)R ~IARL_ب"S]ewʮhمhAˎ)u+; +{d#![n}l%/f &'L}CLI:xutWP8!.4]kMG ;,;G67:) +Gj#-/p abBOAHp]wvuub5;FguY.OP/w+)L*Eݶ!&yc "Jpbnav8dW(Ir$hhe.Ȯ(OG7AvwAv2=֔κdGC#{d#y00=:uuyp]r]l]CIň˻/gfg)d m1!dp{9Qɰ XPZ[Kd +2dCTIORL_)N-\UMN#J+;GT n08]G{ceFƆl̆:._'ҐH뽈I\w]WÙX F1È;Ĩ`T(誗 Dу\ "nb"p}`'ID Pseʆ) 1Z$ub4db4|Cl 7 ٕ˴f}ɰ{- Vv{Zv*dVI ٍJٰLpavfFMH3Duj"뾋Ր;Fm } Fb`yEKEݮ D @39938Q9H8n@6ʆY + xH:$IѐeDzRhuMN} Nv:$ l:?OQHC0h"jN-VCuFy1h0(Z a)ަb0ՍM @} (NC݀(mm_{fuC44vnp캎X `g|w FQ1 EimEwwDm0B/Sqr,a7` JDfZ6?b4db4ƜuUdEdG\I$p#%]L1HCEHf"]4?uv"j5.Qh0F!F(zyk(F!os}!'dAPr$UφARL_Ó~dC{'(ŗjc}vs# ;H;j&0L3z{뺎}k2F9c4#HaTWDя?|!ǐ;G_+ɖevEi$M}b4db4TvdC d'I#+;r]~e'3ÁGv^Fc"p"͏g&0WuN5s)X R(zC`(R1CRR&,J!)++/yɸcQ4V81UT,B/" &`ѶmL[4TuTuk#)[!a[d+0e4 Npn\ʎьGv ie'\'eg$I l4TZ=~}!'/3R +" #} 3E@0$"[pmBLJia$@RVECEædQ>ތ(١뎟G dױ.Iuews= + );KmM$CVUÇ|[3}AQ!cTfb+o 1 RAt !}x"L68uB)e6I2a3$e\4\4dBvd;Rv>$ΒXvw֗ݢtɜH]G \W(\w\vgr2QXFFyd|MLEѴH1@poE8Q9P8Kss8dհ3Irsѐ- }eN#Gm`aa#3\=׃rutb"YTRp~>Kݮr)bV(=3; $Bޏޣ7A4pn2MʃI*a$hhn.89L+1dG(;"Qɀm:,;9T9P8ݐr#&RU` ULO@?O $`bU7@6xQ8TҝFP)xjXv1]]`2e'&e'g  ,lHUj"Y+~:1\5ec&F\ވw=w 7%C@0EтH0?HCGCFp"(% A(N$E!$)o'!!+TJʎˮd`ʎQdؒHrpPݰ 7/<'RM$:Hudǔ]>ʮ(αjIv1-;GF2bbNnee'A$ :);#x"uDjTI3uE|u{,}!Gn1:0*ƈʻ˻Aw'7&Nu1`@ f _=GO*I$Xn}[O#Im%i'TP$rSv(a_2P1a1ܵeFvOP"Q8Ne1:DljDbU ]5e?FXވwM-w*oL12DHT<"& +dIwgdfHR" ECEvn!dweWj]Wvm(;G}F>fndwז ɎA$;KKF@i;8u:Hp"sܼ ctă7b]U ݬʻHkEf1ܿ/B e w4p@(l$%%II*))!! +3dw"RvC|{d3V$ec#Y@i3uQp]]-yvL$u4u]5e#,o0򮫇Ayby'eyE) Q@$"x/7`,q7gp G"HR$O5\4\4lvC(C>bٝI!.!LqGA -t{edG F膀l4iDNNHfp]#]eG㉤\!g/ f #(Z(wʻ,oHK EH"E+8_Q&Ynw/%HRڀ& ATHptPtj>}4hWvL٭{Rv{!d3IFZS@2N1H^p]'\Ճ*OjP]W`WnW 9tYa]U 5AyAy'DyO`yEgd2ݭA0? ^]}- +qW  +kA HJI-~NT\4\4dLv]Dˮ dϲ}tHR:!,; p$q7IdN)Hb"DLtMh\Wqu]v1:IGjF9HvuCydd'A𑆈B7xSL Y݀(l.H$ Gv@:}C;kbuYvRvb-ڲ{$eGv+%; +I lANI=a"uěFp]M59to\W(]wUC]&0: QbFm$w.+Pސ 78mUD731>o); Q&AwOILRO0Ig'=UP_أ!s+ew’]=ˮEɮ_괒? Bv(׉pnX]UH0.DӝL47" *亯}+"rՐ{u FQ`5DgWwO_.P޳Pީ z !2ݻ[_(. Xnxܟ fIGG +3I.B}!^[v^O)DהiH9G:uRv^nHv(n סt6l4'Ld%u3ǽ+aܸa'ƨ1jH4oikLv{nϘ T2x[A-B_9zb' lmM p&iIz!hVʮT,Ӧ Kv< +ȅ#;Ib$Q7x7H މ46:248ӕhok7ǢZp]4M:HjȑF010FMֶDg`pxd,y(o PAuS00BD0}L$As+:TI@+/M_\S>{h:Ev,K)c^]Cc$&e?04<2&ewݐ/{!dG VI c0*+Yr337@ +%nٖd.r6$ SM'L&Sf{d|WVynml$ rmV8ji5}um-uh5d;z]^ .?հ..èYh@38 MtI;Cʛ$CB2E(C?wûO (F`իM% H(y=5pa[E}ˎ# ]{GgwOo?^.d'R]ju ;0h7\"n$̆y d"ĉ aZL1È^;<homi&;KVa:Hj5.H1Fnjfp=sI)  `(@ ;X%Ql8!) $H%='IE;;kkցL(;DvYʒAV oݎLuDٱ$vCi6DOp(y.f1FG~V m-j8Ij8'51j;]/ N.dX@7D9C@藇)„,n(GfpFR"V)IǪTjPAѧhx?쎕ˮ_3(0]N~xVrd%H@]Ge'dLYDFq96d5uڡAM_Ow&ӴUrj57FF Fm"F#0r{@(=N{zfa'HR !D7D +hBKDl_'$2T"5@FOP?}QQvaMd@ýecc#wl#l i^6h8FCd sr F% r-C,;V4p%Dt#l Ll&LģP0]b6CޞΎsu_jA\޻b#j;]? Gb񄤼Hy/.M[8D!@ (DXnޖijAɉB>I$$9tV AAEB^*309$KLv$V>ڔM,{9ʎ$ 7ol$:e)˦Sx,^YͦQ^馮kjVg : v`add=> ɔI2dؔS(C! r/ٽĺAfYJR!0B5@FO2Yv& ]d71YnTvtbPYv/E׽d'Io$fL4^g3d" ~ :@Z ѧ2.4wtFh00rQ$O(IHyC2lRtV "݀%kz?c'!*te8'i1"$5}$CewLٙ\vY]qjzvn~qi$F}{ZMvK]d ;2FeLKd"J&R>Mqp]uvl34ຮ ugNR}ZCj5Szaad;](œL6W,N^&q$÷ߕRD[B7~c/d$ޕD|$8II:]WC\]eDe)ݨ(; eMs٭s M.;>HeTI ߻[ &x!ͤX$ +n׍N꺦]#"Fdh,Lg'gxy_$ p,D$!<{q&IdvC9JBV瀤HjVAw`NNKd%- :H1<{&Cu*Lv8p#ݹMe'd|"D2d"dd]&;B8`7<}NH&I%H8y.i5 jhkmt]w>\Z ѩrØlٝ.D2'S3sPޫByd:KmFFtc"7"Eib0QRII:TWhP)-!dWAvkfeO:*;GDvovuLvHn`(;6n&"Lx>I'h8{=.f1 #:-nN;V¨:Fh})Y*6FvFE$;.59^Tvu nHׯ 'RH~ 'j1 :m_ \W_{B}T6TiQ]%WFA\yd0]GMs1C!=}v %6>H?%IJ4߶q4,ȫ)^Vv*9RzL] ]Gg7/;&w%}4N $>Wv +ȎIDH7)EN`]Ab6뵚^uO7R}ˎ+=Rr~> {ujj0><ƨb0Fq2p1Aw@6~?M{Yͦ^u67j.qݧຏUKWal-1i1F_0<]b;$<^I2p0bC @a(RL% ,JL6HǢP0$D$VHZ7W %j7˯kK݉"ٵPiubcFdq)c$`IOh$ pj1 :-\PW :]y$/D{qkЉTbraI11F=^#|ygI2 0E@=&%q6ΑIrIkߔ|U!o~3Gv ;xTvuR ݁eɎGׄd(,GeG\Ge'HB6Nw" ǢP]Nf1u֖Fp]su'=rvV9j:tFm#Vc4P$'\yBy$n"`#aĆ %I6HJs$y +t IkyDCm{GC<^;ٽ**π.욱Xv&6n8),;˓-H"pknfD) >/nf鵚^5 \W_{LjA\R [s'a kBHl8Ζw0DTao`y~Z#hXNCh,HB-K|1C!g/⡷ NpJ90J$l&Hb.=\6hPFVѰNDz; ˮ_"Hda~Y]s$174ЉĹn4N%X4 +}uSZugq5]Qakn=A^Q& 0blvsHt8{)oJOn" ޿ȯ''&npK#i#)NIkY K ŷ⌆ul,; !kfyٍs +ɎIedxi\wp6Nl&5G#`u9v :/םƮ+=\r+gjt5z#=hxP8N$Gҙ,)﫴gCE Q1F[:) +0J$]fH%M$ՠDCwk#7Eە#S Dv-bYEAvtfT,; bّbaq=Át=FZX@pȎH&)N%ñh8{=C.Ǡj6u=uujV[fxZ:# `d=>0'FRWޗoSn0+O De=lp$Mn,I] J4ߊ0 =ޗ]Ȯ +dW+N 3`9""}%/DvYR@v2c$ FHw.KOkp"MMNfөD<~rLVӫlomՂueB{MֹQcSKHYvxr$Ɋ[>pwSC oHQ(K%PΑtyrb|4eIRIH]jX#S%o k ;Av{deW-Ȯ[,!#1]Z,;dxԲɎ?nnFpUuScLz$ >/ntZuիV )հ) +ͰR02FD2ΌON]fʛh~RBDh DcI@ xNs$][ %U[Er+]%]}Cc ~.n:>zJٱn 7ΆFvu78}}yjrbl4N%놜b2u>uO7q]=Jp1u{u;jz, ƨ[E02c<^?Q4OIȕ_&UUy˵.w \`aUZNei96L d$9yI @qh_3s=oJxCrww|>!@PBpM $? ɕ2$7KR&{F4ez5ÛDv0}] ] 1*;/]N}/,#{*ّ# umz#ldGO$:rmV@_ Tӧ +N?FKM5nTC~Y504FzQWwOo?b9.H]ސ +E)D( B%@,Qhl@$6DR;RhW4݋in?~=Qv>r؉.`ٵ BN7]NzIdTv,)7:)O$82>6:<4]W]WqıG<@SvհEfHQѹ2QbFdAB< {HF)N&Ҫ +% W@IQH?eH@gh lW 쪠L=}C#Pv6$;]NzeHv~$ FpHqv ]7ckijP]Uq\ӅB5|\;o] /Ր{Ͱa>NQĨa4nNPtQf'a +Q &% 7i6G$F4$UIڽ)6߉jDhE3PCPPxlQqn= +#òC7 uW&~rmV8s]g{t]R g + Gx{Ũ-|j!Q3Ĩ708<21r8]/0=%&M!hwC0CG10L|70p6 Iw\rU F4pz4˂^KSv Pv,Pvndw-/b[߈P8nn$ nNQ`D{S{aqH(bg(N% % j5IDV5AQ4T;Ux滢ҲJ"V,~ 1"$K7dϣ)Ȏ";FR &;dHv9uCum͍ ueEi\Q [xy Ej F]= #F#`2S$%teCφy1$$e$ū$e`D^h~3|Hdk운sREfԲ#$;H/pˎ]IJ7ٰ9&P]N Sߞ8N]Cr aԎ17[!F/ EFgEdP bw KK)I%BI] z6Mew|yeuMm=Ρ qR)n$  n +. +|^t<>:24]]W_[S]Y~sׇ7aK/A贈Q#Ñ((uy^Z) ewR&N,ᑱq ŗ ӑ:,;lN$KuH8]Ʈî3A׵pZS @׽oTZ!1FxFv , +E;wQB_5c8p +Ȇe0J +I G #2DCΛ(] ]cSK]/';]0M# ɰ9=et:$'ttlr"\\7<8kꄮkP]Y\wҨk1F^HZ++~XîBX5 Buu676Xjxݨ]n!ujd1FAhb$7hm}]ID!L͟q4q݀Q2 ILUs`D޶ !agPdQòٹb@vewW#&')Ntx#l@']\7{ifz +.]rح>j늌jU30ƨcT.h`EF!FWa@@_8nPPbـ|e%9IN@sH9M2ѠmhHPkR]o(&Dv^vW$[۔t`n$ Ip+ubH(yI5I0纏׽aTC.wͰ3f FFHt26501R(×Opwx'IaGI$$$jΈ]m[Ffx>DvXv29=Y2&xM Dgreນd4Į3uu6jxkΔ%^0!D3lq1-6c41AJCu20B l"Oatc0Q}* ,o E!7d`wblIW JR`hI5Bv' Nn2mDBhkmxvuN5| [ ͬf@A]1jv0aĔ ,D4hnQʡl'>uNNI*}ȋѐޕE4 χ+މ(kRd'Rvt:p ?Huݝu/!םQT;^5b 0`/Lj-o""Xn HJUP „p+c}e7Bd]줮òcH3DB#w\wri\}PH5jxVC"+I3FF133Fv!re$Cpj:} + e6:8^+w0-:eVvR׹H u3Ǡjhu]wOJ׽)w݋4bu] )F=Q#@hv`ɐ&4D\lpI@f#a5(FC-ES7ÇXv_ImD܍De":Fzpc_~]!pݻa[ /f-o< Pyc֘dp!ry  $ DH$BoVCEhxFKS4Fp`e ]Lv7\MGad+Dr\7\GHu׀:.7]Cp5lAi aԍ1AMRE-r9 4IQIZ@/,&)j(=˨h⠍Nhx&Z4("Xfy"^v e8vn9VD\AC'u#uuMfB3bԯh2 ^2qdÆ [P+0hH Q 5kn.+ #NiH|.EUŭm5;ƨhb4!`4O0Z^d)s'$$B5|6;~ѲhP%pIU쾩?][dG#/ve'u. ΉHu&׵݉o{VӮbG0'AF9#dŰ t$ +"ɜjP>33jh +Q5{@va}QvSdǟGi$sDvDnɎnKU _a}\ͧu30h`41rcd.MY2=r'DGR$%J*Vh(=iׁ% 1N( saHuy v{"a׍ yxvݏjx u[ ZNf([.F3l)yy3aG $5I*e5Ԅ etDozKJvGx]$kdwGvdϣ{ HԉNlHun +k#pw[ ̈fǨ`4 +1`4'*o""h2lpI($;L5Th(:*י%y@ZS! uN6x/N$u7Fzm5>IFKg"7hnKJ I[!EJY q/%4÷un!dxAvB6':>Vw^"[]7ɸr9om51kjFA:#Ijl< i@!~uiSQe![ `m/;F]e\O|.#w5Nj0dE7! 0 ]H^\wSM loP$IP Ӫ) )ѠR6KblA ԉnqu׉l546NQh7聜"Dlf:Ib5TP63(i ٝ،e׃d7ȲcAy eDn +vu]dO3č̬AMSY7H| TIWC% 6fU& ղkee7d'Lvۼ(Ѳc\|kЉ\;vᐭ3ќ #(hS ;lG'IU* e4Eо5*5un^z9h׭ C'vojh0p Fy#iyIXQbHp8jPdHl4x)Mʮݯʎ+h r{]a 0h c)r0%C8lp'i j8(>a!3<Wf.Hvul tݯuˏ fp1b-2mVb$/v2$9!-HAI nkl4}FTl4Cw²+uuul5;!$F+1p1ځ))R"$ID顃pD҆Y$P+TCL\4pHR lk!KA4Wfse7ewn>ىyr{ q]nWmZl59 EFV?r1A)2IN$jK[ M57g4e\f{ux!83X6C5LjhZ`G1DS148f֡84CkeMʥD i6&h{c4T;4f1v֡f\#dפL5P6NД 0ˎ ;2n!4r 4h=,`:T FJ(s5CkR~5+jHNU(6R4\D4@;pKFÎ qJaʶS3Pd1CƇ]dݺW`\̰brgF :Hzlh8h{>"C )V4t44؁f=_ ;ˡL5N{`7)S I 5f?O7.! 'mh6h33vEdP C3 A6$6H찂D.ꔘ}o%f2>@`:4C0VÌKA~tg$4D7Vh%uPScP }hb +!͆1 $@ϲ  nPh  f菛q'U2 !cczw7ÕPjTvAhR5h6%CL8yD hXσ*a7C]A53ӤbjkLb8Ath8Op D Kkhٖ͐uYͰQܤRj0A6Fhx|@ hX`h/V!4CL !aͰFVraިƆqu%4tShxa[n04hp^ W54`QCBfؙ[_ @ f$j +5loBZ ' pohxk +4lS4aHX&5LHfE3ܭ˥aQC^3TD35pVò1d9{fhhXC4?hk%1HE3THܭC5$M0b0TN4ó(&W =fsLSy596 qDe3,b^k랁:E 0% x50sF |aѤl5,(j`O9:|' uBG//4\HаACÖ$֡Z4C ݺjIA b_6 *a73԰4)K~S+I(F w4|T +wOjL+*aaHP{ +nUni5j8VÀq` wF4)h(,lq"Arh|ޡ $bi<-Sf[wj8\ 5!z0fIN5_sfhKD QDe4̒xrNi9v[ԣSR f342zfIeհ t QZmG4hw֩4fimͰf($US~0j6$3C3Ҥjj`Laz:!:|W׎"WhxIAú>aP) o]5TC#5rfh+f=2qA3lR55f~dggQ^Ip|FQ6dƢD3.C $5lԨP  pI%԰AcC֜hx;B "=p-}NiJdSfNxn\fT@jh*fgffp !&T{ϱmlH-=e4DeY n0h o;Ѱ_<ϦͰf.XХj@^ 9pl i T\ k\ t6٠B h#1 /S4p2Jy8g$$s h:V,5h@3[VPCJGGf#qHM2YdD3>hcG4jd9|%Dh0_4IpͅE$ʲX\ʄ[WR 't525jhS> 3hfԤj U]DZbÌ0ü[?"-w/7x-$=ΡiiKP(B*01DcH/xC;~?zgך}ff~EWP4덆cGh\j ߜE|r +NSM] KFRɸZjQ ՠ05 1 fcP4MڬbNhjl2S1@E)a434 @VqJ6tu5VSaI5 VÄ& Аm&asf4f34o + Eۤ aK ]' 0Mb0BÕ`4ECW4|!4 brz:V5er G +SCsNPf 4(fMfd3@.fxӚhu5 5lHf`brR!2󄆛 _+ChBøYՐX=.3 Y3l=mM] 0૆zRC@hj 4mYѠ̰e5GF7[ jHAl`CgMG! Z4v!&|&,μc+k͐`uR~_5p5Tr5 +RvԐ 90Cmea+ Eۤ-aP~ +cuaDG9",hH#hqtK1C HY[!᫆ 5P4 e*3T 3azf843;wĚ9iָu5{4>h ZsDÔ[4y!ᜎHXGoĒby" .X B 3@ YP'PRCՐ;34r3*9ER͐fX4; EӤͩaPUCTA4DC 04H14L 44Y4~G}4LI4D*qljP +u3,s3Y3l$fmݺpDWU54BQCjBjfD^p= O_ݤ˄3AA,a٢(.D44L34$$@mGAjAk#{wհՐVC;JQC4^ BC$ ;P@fxŋDfHf8f8 [3ڤgZ4jX F󉦅f=6h4Tp[Aç F]hX&4̪hmid $,h͐tuB {Ắj@b@ L ~j 4H5 aVi} Ch13Z3i$a@Qy#!  9Y4xCç +nh8 h4Lm'BX:8Z33onkj8롆d"Ζ/]PCv5o4f(4C%!afG3(f2Ia5 ]fxb`jriV'ZjbC+iZhV%kRG%ӯhxpAÉŅhh*Xana0CҚ!@ OapRSØQPC 5Tzl=j0 +2Pof =19dI֣uk"hRN ;b%2KFKxe 6zhޢ  t4LiG4 @UlL<[ 5eQ]j\jU7 +f(%3t3T 3ԁ2  v4ayePMڔf|ЅjP؀{_n=L?0>hxŢ3(X($e >k%$z4f+1TYWCv(j(1F [5C4 G Ϯ0[ Ԥ-!xõ&7H2iiaA@5D=@cB f\hxEEáIFBC,$Q  3 H[V[B XI5&5]@ uj)PM AG0C0C9Ѐfv2C!cK;OFxf5i js j 6I3`4f9,а"pˢ? 4<4C4\4\p0h,B`%_U((fHX3+#opTøP ]̥Fh4RMj 44p5ijFC!`3vP o '2 f _Mkf0Wu'5M4u:;q1BÑyDYbppKaE :g}?kmj]ffu?}3M 5\UC*02 kMQR ԃjlphG2[MS=4OF F_gѺk` 0=@4 `o]])"ru+nhNͫj#5t9jhRCPC: ՑhTI3C0P gd3<3 fĚ!@<r'ūl8h`cC 4, X4@]l_0h/)OkG a y"Së5 +5`J54H5AK %a ۥJ +@7C0C-1 =bY i*a pA1 "VÒ4SÈlt1XMbh8*ppCmo h' ~hxh؅ +faB`7¢5CT5|jx3R }C'֓FPCPCTCWRCT7 +3p3 3kfD\f.3p=ӲH.S<~n@ShxGa֎m@CDCU?/YVKh<3D.ѩ,5g5Wj+06loC 2@aFVßj 5Y B +f8am2(37̐ 3; 5z̻`m 0e7aw>v2 ?{fЧlS-06kV[L=a2 *C0h8O5(09Y iV4CgHg8T j5ԝ?pPaհq*{VPjjذjH'5~b5$5i5ĸG4j4 4$ @!E!@h!'Pfd75W"3FFG<|p0k7 ~gduazp jh2 [AbMfУ=k3[L2=F%;h!B0iCC/(g5 5Ěoկffe> jY{'5|Lj@MV, 05B [xjieEPCNM 렆4K + @C@CFChp4C6Ca$ >? 2 Ŵjj:XC c lKx3*T:`f>>,682C{VWhm=oᒅ[q W gi@cNkkmcd-+-]Rha& XEf jBS7{0 5phZjF2- UZ! $G5ĸG4j43$h34|@̐f 46nb3JhyoyA#q8fx0~̰<jn76H6rtvdj[^CcS˖.l6=hz@Í%q4ܻsKK4lɊA W mfhȬ63D^P!aE#5 B 9FjVBjg5h42RCՐ 7h lD!Y!E! f 4h3df %:{ G51e=3A-ghȫCߎ)j+s>аyhi 40pn@FƩrmK uOl m`5a<3V×>$5KMVߏh|xjhc5VC !+Saz!}PBC2А(Ѡg!0C0Zs`"s7|̀) +3c3Мff3ò0n>ltJx zlKh8BhGY4|ja~es);z \=˫% WU*k7Äg%zpEhaXU}M`5rmjXԐFjC )Z Ibb4`2 0D!7PL +4~ O3>> ׌3S2w0ʪTØTC?F7]@m7Cʳ0Ѐf4h!j?hx ӄ# ZfҊs0ägd+Oxꮱ. 5j8j7 ]GZM5lZDj] RCՐK DZ 'Ѡh`3(3 7e dRU5 L4=J;FO:$0+ 0{a6ÏfF*U~-wRC`CuXoobnpk44KʮUN +4PϮ/\g4q 7 4H4zQaаފ%oQV7W0WuZ: c"P÷O UO{PWX OA 'aI]knjm.+-.*σ,4I 5(4$  bb-3$!A`!+P@f(ko;'8>\G tyn-ؠ İ M5h>sn1{hD w Ҙ 4d4`wCkhPZ Ūl^pz^ATtr;&5fHG ~xzpB \t)i릴pqPCAAa`۬߳ 0o6Ր fPѠ3j  E0CEx`Mm8q;- S w3f8fH4Ǫfx{~@ω&_KN 53pwc5Z-JhxZ}1hDC&n}+аа=b!vUSdЬJfha3tfX gL3eB U5|S5U d5ڱ0jg[9mHQ QUQ5.U԰d1jjhNDtA5C `nJJa*BXC#^lAnqL cf3\ 33oigL H TރR T<6 pw jy'G6B~D@{@-F'&2w3#eUFßƁ8RGVQ5TuTfhn }|sA 3apmR \t#qz{Dq1VC0z\NG%PRlPâPC>bQA!+Q fO ̠![A ydPfPf(.V1ZZ b %34~̀I}w5ХI!, ܠ^0 ;݃\ [ {QۇT4\ңD&2pO "} h-No9?SHUT 3yfHeF _ӫ¹q۷Gat#᥵ +R;;PrXFH:y.GUeEY)AհjmV%OUC.A!; Ӌ Yr +,6C>hP̰f(r8?P] +E1PxLo2X~[c3>f8}Yi's^VC\1jkĵ"jw{`Pmа[a;-.pDCoD}=.h8%4lQѰj%YIUQCT%4J3t%a#ga/jo 5諎0 5 ͣR {n-Zּ>ZT> 5 +(հd1j٬r5d%a0/%4,VnK`Jp$k.(q2^0I6k4Pw~ ?fxsjxK5{+ 5A3껥5N аpPEE=𽉆ެ&@idOa7aӟzhT%(oF*ә!&Rg!#5Jj1>;uI#B WX OWm[6K*C[Qq H +HE |f%5hhe4(jУaԐ Yr fXm6͠PZVQYp>6?rh5A~c3;f8 M3\aA kW{Ń`5,OA@T4lAh84'Pړ7 w54<2ѐ94|o@==.h8Hhe@X~](%qSL;̀)t$UiO0Äi~.]d5j@ބ8VÚPC?J0jlrVA %VÂFjө!ՐD AC\`+̐33,-,akBX}c_[GgwoU:·'3%K|OE J3|e4o%S45je9l>oOS+G7 GΛh;7hx.whqav kV#4hj)2DYdP32͐ˀjTS *<E'ՀL%5p6Rjc}.}QUY^5.}Qh 5,45D̩!3̐f  l⒲Jp$Zдv*|γOf8upj 43ޜWØQPݤʆ}7Rg(Vаgph8.@iݞ2ѐK 4 [7#tb!r}8 +[4BuH>rfIfcfҡ5GPÇSw>@خOx~P*@NE˭4&6/ojօC5r:*".vjөAECj5 +ruhX6=hX3hJ**.GfEe-v<'k_|k\K"3\* 034Cʛj8aTR +ijP@n.O$F%_2UH@zzDC:wU8phطǀUpj ?t(- R Rdn L3Ҧd}!pTˬS'(q:VzPqeM h$\[ njPj(l6ŢC!3̐gZmv;4PX?72ե&tfJ˾4~LtzvzSz@YpYeeRdQД]\pD] +%QQ;9gΙNaNk{u f Fjw ^ ^QY fhgz ^{0B14tfdog4?5twu5@Ǹ@ݐ8Bhp꫍745cwCLDnaC :zZkHh%4hV <a5řR R!U8TL\c33C/3ó 3Q2C/cj*M5Q51jxϻwrjظa=9 +\(x\b6ZZUW԰('G!˲j0+j/А%@L&W(  JFMft=^_ .WBf-K:0thx{Hg 03|ȿi􌦹y54D tl*O!>QՓ՗9 / ۀ _Khph&BiDX _ ފyHMǨor:lVɨi5*erA +\jАP7̐-9ňf%K*F7Y.*.H +W}Ϭ]oio}  ǎp pp#bgdtn^T#Su~e:R94a{y J=H=vzhABCq5A]@meD -"4``jkbQ!l!Q92F3 M3077]T5Ū +w鎣$jrjزy:T1sh$J܅Nb6: BaA.G4@0 jHaАţ +`@ JF3MQ*xP& ͰFC"fx/>+an>aQZTC/xGx!Ʊ!±? R3gB5)tH栽S 'CDLBCCzhx0yZqu4EjH"jRܠ7 s~S×>KhӍE5jzZnK BRT!qP- +vl4赠|@ 9 +\jhx +0h fX h3Zh2[m)piYy%:0Ck;|÷ěW }I`'!qf7C/fQzF5 TWqjV@U.u:A ՚p({.f5zVRh5.5Q P 40hx(x4dr!7/Oh*F7Q.*.H*b3عoo +̀ ύޑd45fj"j"lrl@7 2Nohjn_NSG{Cq Hޒ𹄆ٸG@{p} +B44#G[>}F(Z.j逊d*6z ssTCrݼD5|@@njxpxC[߮A5.UUGKA],fAӨUKjXjA5dg341bP=}hufG x5|̫aH݋jX̪ʊp({.f5 zVRj@4rrr,;SÓL ʘRAb r9f`h@3(`4[vGSÑhyeU 3÷̀ f8N^3w¯߸dǽyL kVX׻ _kK3QY xr"U{VL* EX W%4=<~"h. rh01Npа7moaPiHЈRPNO1kT6f!a1S'7o\G5\Ľ{pvb|p SXejlYPW,FA],fAըUb5 +Ls(x4dr!7@4@Rkuzl9."eU5z|]XS̀oi߫ G gΞf,6Tf'!ݛ/j@ :q6H뜸ʡ?  udbDhV%;LpJHN$4df Whh8=e ԐRHQ]ݘU03l0w7j.S5L?{f|(Iaٯߨ3 */WMx}=^2ga0RRDh!TP( %. 0I! MsΜ9q]7G#%RÚA̝ +UT,fAӨUJ>@ iirL*phHe TCаr&R83 d20@ЀfP4Zh2[mg^~aQqiYEUumх/1f8zs4qmC~E3|g-W5a aQt9<TCmss"rqf`_0XeGND߼]~C{ o,o|~S6gD,Nc:KF <xf(ao"N ţXݸ>ym) hpMU䮯(/-v9s6d4RWCjP\.J%85jaAհ⧠!CA +fH34~ hP`4[llgn~AUgwlfoҹ ._۟Lh2W(uN C}09 wȅMQ -۠G@JzV" H{#,>Ib:%j6tJA鴫?YDwh@>yCs IE]!򦋏}tmKbƤiiƙuȚh_3@RtW._xΉT :p5Q*䮳PWSUY^Z*,vحѠjJE&O A rL*ԐªAIBYАʡ  34+@A &fvUTVֻ=m`_ =8<}t[B34G%ݾ3)k ߈f-G5aaȺa+du{ 13_h?A4PEJ@C'$q 𣈆<4s)q3#z:pT ԫVOscC]mueyY /7'aZF^QԐ ˤR*N )!9hEB4H29au +J &fvUTֻZZ:z`8svxNvkb=h%f`h孆]6n"j|60n r ` d.畹? G[>Q).hyKohx!!)hO$Ơ 57aPBf #6L \|3 ;fX[P5Ī[uF5|Fqsο{aaqnDEA\8 +\ʑ5Cd +)3M'4OͰpj:?5MVo\ĞrD8텎=To6"X|ݝ-M u5Uق+ !NhFpO `aq:1a0,Xa!g̰ b6 fx j/[ W}PUtqs#I9 [Xr{ +ٳ[ͦ͝:PCyiqa~^NVFzj1ѐjԪ\&> (Ph jX毆h ~싆HˋB4g |P,JU:N7$S3s +J*kZ:,6(n{]cSꞺ}c_3,l\(fT6:@ˁCӇ i2@{7 'JJЀ5hM!H0 i4>sϋm6ڃ↹.ŀQ<9 = +o { +[Kb?(l9\a'aU8locfoBߴ%P>0FrA#khz bV`@ JM& Q CYf6Cݼ>d7]twj 57rfǼ5{{<.X_[]Y^Z\TbL4$*F)I" ՀhGó30W514! h30h "TPĪzC1%-#3;7iڝnzCwOz[sd]B3Ss%C4{3|~F.$հՀz jPlhb'N\#J;nY;ކ6wrQK0~  XG?z׮|tS23j>2(ŀub̰ Ͱ3lPoGP#Ew@zn%BsgG ~ H{Nlj(+).HKIN2uqXR!JB@ЀjXhPh jXj%b4DFr\0k|H,1*FK'S3r + +K+kZ:,6So`3J>O7Ho߻)6l/G%TZ =.ß }Cg \ d%{y@GFӸhi4\"h={fn탐1z2lך!/ńVe|J{1`Rw !nZ Ewz$Us$~O8A4@q#nxpqhؾu3kj &-I`RO7/ [Ji3새*7W5VݗD R$}Ώa ;w`? } +?`o尚;[M u5Ue%ŅYi)I}.NR*dRX(GdjgN8Y }VH}}}_!I Cn]wv۵bQQ<1}3uδ>KOEf3I:;/hj0F\4,O k bD`hЛa=ρ,{xyGD%$&gfWV760T]=}ڡG͠/Bi_6}{.,"flxT [p e1Sl7@`R Roi%Ry;vz7|hYr$%͌7x+o 4LN`k/]ih ]vT""eBա|Q3ћOf3{M5M@ ڞ;Mj-7rqKH]MVYŢԔА_o/wWىթ`kcmͱbr>4]Q45D18ր h.B7wO/_6 Z[; vpM#F3֞}HNIofXgrj8BհQCo7:A,v:67  CA(u A6:2",$8M"prvXh54hXh`a   6okf:BW7Oo_X*W2S_9waWn[3<$~ Ͱg +j ?V>TqJ$ՎNڝȡZꭺVjeA9}Bo~ih'ĩq\zsѰ,=,mChH!]."R$ḛ _SÏjHݜ"-wyKܙ:j)R0?7;3=5%)!.&*2<48(U(pv; ԰A4P5beаf., `h30hl <G'g`PHXxdtl|BRJZFVN^AQIYEUM]cskDCo`РO~|v +ω+cױoݙ~w)~AI{G?;2aYϴpL,5f@ "C6KZ]gQD*kW:` "Z@'A#4|CxA4bFJy44|h־K{A%6 \z}(RV^ xR Eڻv4>N>3$^`h=5F>Fx>j Z! + /'+#-%91>6:2",$8M"prtq ѰښceBbhXAb Vk@Æ,4lW7OoаچX*Wva0 'E[;.|9Tԭf63^Ͱ20Ĩav}=]jv\&e]"U2j];io +Kp7LS@0hI ^Ѱ +u˂hxL2h`* ۶Jh֣egK"3 ՛a f0,5{EH N߾5591~mW#qVv[{4eL,jij*/-.LOMNJ  +ps +\{;P [  l5C[,4#hñA4wrv{xyGF%$edUT76Id +U' ͤ?4?32)y3`䖌Cba;2τppp@ ugR,BR K %A+׻[@$CR4]40jE f4["^74L߾9uT6v~:D5tabtekԀ-񨪓d AB3 `o j0:^-Rs5@]Ŏ;O?uwuri[ksc}mueYIQA^NVFZJRb|ltdDXHPى"Ѫ` h `Jh0@%̀hX[ `.n>~aQ1ɩٹťյ M-"TPkzwwp0q;}8'll;3153%|ipHf33 5|jw6!vJ j؀Ajk֡ufʎN bR $ 3fŒU{l>c4<6Č,Y:n_G4|Ij졃"H1Y=]j&X(jDQZc`Dhf3{5Uo:CRs>73}_\Ɗ?0Fp&psFݡlE-M u5UŅٙɉ q1Q~>ޞn.'G>koP5ʊаt5y}4'h4l|[0=ׁ,{xyGF%$edUT76Id +UgWw/V6̼X+ ,]yWOLҙG'd=c LJ Q @STyu(E1^?ޭL# wthNBV>hX,4B8 hlDi6=L:; WzB~}E}qLL׉{{]",1(\ϳr3kGD92jtZf84O t$thXhnb/\qd$pIpBAScC]MUyiqa~nvFZJRB\LTDXHPafMPAAᏈy5[B:83f@4hP4lD403h"ut M-l]<}C#cS3s J*jyf-^y$?855jGհOҳ'a3ބwN®Pv~SUԆ }.V C hX) _4|)E?94^zy` /'+=591>6:2<48@_WG[ ѰѰРh`jx1hX `D:uy4lݦo`dljfaimkWX\Z^Y]"do!W #i|NʻwHKRxHJ3@A5 ɩ],º7A url`nȳ~KA>w Hv|<\' WpV2AAJ4 hxC= ذ.6A;ؒnUU@gU˩7,J (K vtwR3f84ÚQ aa=+Dߧ/OA*:H* +M u5UŅi)I q1Qa!A~>ޞ.NvV&FzZ۶nԠ* +hXаC +A747o4[X;:{zGF'&gfUTμ~w k|PHgߘI_}L Y^ +T5˫T w< &4܀B {I,i!nCF8u zCL_~Va%ߋ>Ɓ`^Wٕw^yǏ+pwjiUIGUƱAѢlX"1 Kf%fxD4ÚVF jSDnslS&Ν4 ȉclޞϫ(+)*LOMN  psqv4731644lDj4h4ȣaаN  !   Z:F&f6vήn^>~A!aQ1q I)iY9yťu M-BH> ^5)r77ɋSfX5 _q/ wJ3rԀ7E0*UáyP(h$r~%.h;:iw &!y@i:w}ġshXIhY ,GC XQkpWo'j9E} EyĢtWѾ;wF˛a\i=cvj`n\!E].!nO  +j*K s2Rb"B|<]l--L t!DԀhhPC4pj ϣ?< (̀hPUUS4.۴u LL-m\\=}hHLNM/,)"qGWw/{оٍOxgnݾKz?aQ%@-- 50<4{`]ҽ],86#(Pv)߃O$ WX&9(:n3%V{z4,9ȕ7 h8G=hYEm0*(O -! d jY v8$5(3Y4Ô k{:54tr=dVS2»obb+h7!ye%Eٙɉёޞn.NV&Fz:Z۶nԠ* +h4&C-]=Cc3sK+[{G'7/_䴌چƦֶv80ػ=O̹IDՙ$k{Aiֈ=D w +m"PC<0Py+ǴWV=HB{+ƽk{>84L# +p'/4ޝBhx|h F<vpYkz^3GmRJ%J30nIov dfQa~ϥE9Z94+ӗ.NN;3~O]%ݝmBAScC]Meyiqa^NVFZJRB\ !(@_WGаYsAРAР+hXѠA@Ͱ Ѡo`dljfaimc_X\VQUS7 D⎮n < 'Fȉwx{"&5 {JK343kH :ὃw +I;۠rl 'n r@Ȁq lwtvgp>"WBiyBqVE|+p\#.²hɑ6y)2)nQR*8(G*Qq{'=4_ǥjNmF&n]GN]`=]bQk3W_[UQVR?+(4 pT$gHlr9H9HHNMhDG1(Z53nln3Rs}iVuё!A~>^7';kKs3#C}=mM2a QA h Du4fA%)4TVQUiiYXZ;8{xzGF'&HK/*9\^US †KzN<7mhfפS\IvF+zL oWB!xP&*",$(k]Ύv6V&F:Z 75'py8(zO_dnI %1惘ٷadw!QCg6.C%%&v=t]ioLAE4`4ZgJS(Ce_$#ob4Љǔwwnߢez#58mk%.PBRhmT82 Y3L̰&߲)sԀ 7 "77l7cCkoȵQPWSY~0?7;#=@ёa!A~>^{vruvr47512䩫ocjPRTP[ + %hXа=Рh [TTy:zF&f6vN.n ѱI)ef ZZ;{q]x9{O?s&ޯSaﮆj8=vv<,C,F!Za<)zʁ~3u"5Ӎ<ղj`ٰBKJ8D  ᑷaVfVIa +%1$j + "I@_wg{Iȯ(+)*z A~ pltdx#͍DExٽ@OW[?+*3 ٘bV^2ޛHG@""RD:R 000E @QIIrn/\1d}_:TΙ+.y{xF%0Р  &a6A sаxR}C#'aͺ l۱/ 8$,@tLܡĤ􌬜j!l&9.S]>{cxQh3D3`T}A{޹}׮4x89XY  4 stu D )4|8MhP>C4fXh704X;:y,[hظyv@_@оQc>zxVN^AQɊYl뀁GwLUIRW5jrM~Р5w nJ kE5jrـn}O~†瘡PPL–VU{6|O/|?+7wIQ#~?hx|4Ɇkh b"LQjXxg(*z I  !(rʠBQX"mh5+Z(zϑHi0먁9HQ%Gu'C޿{[tpANu!ZauUEYIQA~NVƱÇbx{ڱm˦ ֬ZԘgd0W@oOX4M@ÒFa1Јgbjnaemk|v?"`l|‘)i3N,׈$ M + +޹  YU\301 O5ôw!Xx[ ZaB7H%:PT=t={Blx K^R tUw"x A_$NC2hxE4FhxV5jt\,<(k&Y fRKZ!^ڈ5 |5<:?PQ#Q~ +IsR*Ţ%E'r2K=zp|}ٽsׯ]`okceinfbldhhXAAٓ04 fhFOJa.   M-ll\<oܼuN@_@оQ>z,#+'ZX+oA[u uwꦦN=('z=arZk)}o_ #5@z֡ ԀPDC PP(|B,y0+m흐ó=D+#4_!1Qd&"ߵhZhx j*To} ŪG,1^YBV2j(z9@ HHDub y3AfU0瘖{ߴHaQ^rJ b(kkҢܬCq1QB|h4Yb5A@Ѱ`>Ԁhh j@4jV4|LS + w@?/@4M,,m]۷n޸~j@}]-M @".T sX4̜"4dѠ<РE"@CcS3 +k@7oݾsspr9qꌧYs.]~-*:.!)FFVN>PhD74utf݈vHj G t^ ՕE2ٮlG7PE12p͐ 5 E%\57P$=~_ʡ;hxKlHfa0PO}GTY*+-(@!I2!l n'I `\P X˜ 嘡_a~Vq FHۃQhkinVWs3n&'D]vRp9_oOS'\lȠaR}=mM u@a4Wa8hxWq0E| 54u[ZYXA!vή'N{ +v5zL\brjzfvn@XT\RZh +Ǧ;|UQ1=-&f]q:;PC7U}C}4}UCzaGb P (rJ^J938 IW2${`l 4TaRM=EwF5λ'dASA;IU7@*1J"$g&W '--0)0}o̦ Җc;n80vcvP$3ӒcGFr?}QCٵcۖM֭Yz!Aa ys2h{94>2h?ᣏ jZںzK[.[b՚u6mٶcמ};nv򴇗_!ѱ)iY9yjAaE0Q5f<4aE24Ç j M, +Whc\N>x+עRndd +Eu ljXw]{'k}K +3LMX5tQ5>ǁ] P(d؀}ϸ@@K@Ȑ=1Xlں[ 8 ;:2D,3yʠM  ESɼYjo(a$%bQHN >9%0J|RI)&k +3Ldk'NL۞,޻uZVҒ~~nvƍ䄸kW._ +<̩.Nv{wܾukW,L hij.Eü0c0c,4̓EbU5 M-]%ƦfVր7n޺}vN'N{z t91qɩ72s¢)[q?|?0Ȍ;nOɎ;X3fP_{SF XBF'}O r^SG'CrJ*!4I$OLRe5D IУ0tX40"a7M#6Ɓ'}10m-R4HĢ^^NVFZJR|ltTDxy>h͡ڱm˦ ֬4XhP4,\ EA fN f@| 4h1h015\hXnæ-e8M]5荚@*c1^ H# @"gO4ؽDpϺ+y}k9^y;q̹ zF&fֶN.n޾WBGވOLN+,.4 ZݽXjH]q2/IB4!ETQ(G {8I++A %6` }%R1P2Pf(^M-m$iRy&a^$,L-,IhxGC`O8>y3oOq|WTU}(?qJr3,h`+iS8bAőAkG[KViqa~nVFZJb|lt@?oOw';kKsS#hسkv- u5U͛6()"֯C4 +4ghx аa%au eU5u -@Þ"4=Q?08$zdtl|RJZFvn~aI٭*!zpۚy)}P3EDE%$gfWVnhlnm542: ;xYafgs+ 2_ #8-͍zPC5s%2'Ňc)#`3P a9[;IawNN!`? 8'G쾗44{-`Iw ?Ɏ:- +15dq)&O=Ȁ;|: &fXz 0S35a1B0N Օ7K +rSb"C\psv036Կt;uu5շnU޲iEhаd4+hLAqM[nS4 M,l<|/]q#&.195=+'&^,4CuqO ^7ӿ`M1O4<'c#} aTC/Gb=IlKqA1ԓs@Z hlni%a_~8=kAv߫A,qfIIf$+B{j!Lg +#ό,B`F=qG8$ԧ K:~䄉#}axkAp1HZoOWG[K +P\s#2ZH_oO7'{[k 3#@ù3N#h ۵55mUٲS.VIE;"44|JаРMCS{;/o;q̹ L,m\<}\ _X\z ^ B݃hҘ'sM +Lh'{5 tj4W!!}Xa;zzhܝcC4<Vl1JXizܑ!Q}tÊQW b'O2f$hB3tz r3,OJ~QF '3G!alq؇hhmnl4T*+)HKI|@ȷ|a׎Z, *@+/}'hxg!/_a  *-;vpQ?08$zdtl|RJZfvn~QIvCcsk;wPq mzi H lɅQ {W"Q|>D bebAá<3'KX (Gk~Ƶ ϤvL? {jpAt@If$aE`A#' H's ǢAlİ aqSpz; k+J +3Sbx:;X]<4{ :Zj*ʛ7mPR4|Ahx# 6lڬhسE ƦV6vή^>~aQq IyE%7+Y4y7^/+͞vEInEdGfj'jw/>>Գd=9!DzL=3k9 7Ai^L ^w1X@ Byr'䬨 fhE3t@ a)|R:'jsqmnv~5BfS4t4 7K rSb"C\puv056G4<~C4hi2hبhXѰa%AòED аz Aú4tt 8x' ƦV6n^GD%$gjM-maxaj$9-NHJ<5?٪1iƈ:ډ ttЁ~9 y$b QXή@G19>^ l~h + %s9 +@Q#c-4 KbPSUh(HKN~jЕ˾n.Vf&.aN]mM_Q]yTLu6%3333333sGdEVYEvUdG7QMEQDf6'c Vh>{` +;~ѣdhjPy@ßz ( 9F5z&M:} VZcbjnimy&-[cS2r ;wP O"vRJgE*Muf{=K\ D 5D hxih=aD@O&DUsA0"4Ibs ^gjxpOXhM6G\?c`G.=hYThokmeajbаd"Y3 S&24 7:D ) <QE1G4 j0\B@Y ,4ZXY;:{zGE&$ef(=|hʼn*hu|c0ԤRi#-*k{4h_RnU5ZΞ!jbj(Ses?؁r'dw<15'O Qv 󐬑QfpJsO*+- Ci\n'DtP"dg*V7TGff?{(W}5Ķ)p׈c- 'k..*LOMJ puq04\hX`sf#4=v̨ L =hx-@   ̝7EM,l\\=}CB#R3s ŻK$4\Å&T9|`}ѯ&eQSo)}=9UCiJ BHɉ(Bg!ړpsjhxܧ pWAvRaElD|C8!'.SΝ*씩=;d(cf Μfhf>tTN> w%4 bj k}}喋M 4T?V^v am q1Qa!A<\l[[ hK94LhhxCzF1^4hhhhxG֙Ysprq а}aCeǎWBOLJ%]v"ڗ}ɫ_B ۫>3hP%ZnS;䑿8H߈p"%osM;ߙa-54ӎvh .pAĝt@v:%23 U K#зzS#E,##V"ԬS 4eoHKN%(o&ONl[[ hO`C!CLB 0]J2 UㄘpCJ3\쩙<ӳ;d°X4cK-0EhYAC# vde$n }[kKsӵkV@4|'#43Z5^߯_9U4 c4LE4}ɧ}hXh0\oy&-[cS2r +v4>rl=ҕViiH?PA)5|G p)QS`w E$ %4r3TאoD)b ԰6hh*2}uL,HUCЩ4@2p343<%O=r=AҶHMFCC,pp}%B@CfZJR|ltdxhp aRF 3hxGFCU4chx5% ӕhX`jnimy_`phxdtl|RJZ&Ѱ@)ACԺ,wM L33p4/6?:ACo~OL mpCr@:8TOD|YIgs:a骴&%~14N]ُl>RΆ: Ƞf\3|=Q,0GF#nbӅsW9vfe$%FGx{8Y[Y#,h90hqcG0x+5N2AW C h?ha KMLͭm]ݽ}CBãcR3r wb ^wmO^ie8wj[SjMH (+bdPiYޓΑV{]co 2ƾD :ECo=.F +B=#$T= G Ou%ϸ"~LCa=D v"'5'%^3\xAX +41244764hؿw 7{[Fjrb\ֈ^n.Nv6-4,?oiChhxW0 5`h4i +a9s_a%kPHXDTL\brjƶ܂퀆24Ԟ4ohlfh Hߥ[jৢN56 8ވ |]g"fkdI^CC7rAIE%4~|TIA?9'UfubI8P t _^xO 2`_ @[F`bCܛ5 롡^hhᆪmgV9I ̆)I1 {<3 /04A)i4G#lPx4dlڰ.=-5ѰxccfN:iFG:7U@óO+4܃hd G!F D4چk 7i;lg@CWBà!F !NChH4,&4۰АWhό:ͧUZ\vA5k5T)5hT%:47$M݉f3 + rx/x4i'*4c5RCM'PqXn}rA"C) qu +pE΢ V >4MC4LF4&a@= /#|p43~ZpBӈW  hh4?yg R22 ; +vRg&3-*~hk:;/jAϾ#\~fJa||ѷ6_(XM?jޣ}No_T$==Y}g$/;ZNʴY j0q6A 9mf2Cg}1֊: 64lѰ+@ç ӧN`»Ƽh:h@=^$4<#?;upC hip4\憆[ 12g o3 'O>3&.>aO V(4lfCC: `1y!WaVCY t-j@'7@/zL>6o5 аq5 _>?71>n"A4!  wnj6p5 ?Ï<E@CwBPDۈ  _7^~AѮݥAP/`9F jj7߸E r@tB`әHчCqlh-1=44 e(@NԠĩA3N75p@Xc6CgH}A RQ!  ;r [6#z5 @s>-D0V Rhhh  dжMM D;%>4|)аf + w؅k.5б(oEF[ p3R)z<%(D,Q6B7о`_ 4fZwj ԰Q ǿ7q=k #c7Cg|yyʬXFhECv F4LA4E4 :x`>whxFGÝD4<hֽg~#B4hhVܜĹ 4| aDC L'fE)юUK|zPCCjW7F? \ 1 p)fХhb%7FьAzh8(d vL`< C ?9FhسdohXаPa=DH+Rh[ᢐBW4\bFU@s.  c S44|hXZ! ѐh(ٽGPqywjhjs)q4b(OMd̠`P1CLh8ZWQd%j؜DNFp8nܸ)LN9!^@Khh8(а K̎E4LB4F4 <^=uyDý ۶A4\ h2 tA@ 1fIhX![a'6:* c64xw]fR:ŽS(@pHvX\ 1  [2T4P`2PG։3QQG7Ȑp„eSn)Р!twnss+x >=3D  8HaXg44lXа@aaG߄BEq 8znG.g5pjخFcצc:`:9t {v\p3C$>Ǵ9*莆2LFCDC򼤄ٱ1h /G54\NhVCmDC,aa@C  9RD~oNhv^T 5R Uu1݀p@9lN𗔰[S-7CC?4藝DCDCM`6[4ML&LH <3DShPHaUEh낆?Gh =zoF4; 44<4Dk65`bcK|̿d'@tb0fȵet,{ }ziG:MBfcUÎܜ5iy8p88'3{fZ4AA⊖Gå~p!ł" V4yNO P3ʪ&Y+1IhHJ0Xb-2* RD0D ""DD3o{3L)< 9{+fެ?ޯ%5%6Hn K@qj64z-jf[Ѡy&TG7Xفfa,jj(d FM. $7$8^%8\49 mcW4,h h(!ΠN?$616`  VbB42z-毩j߆=&Mk''TWܔ}v5dhTif\R]~)8 5nf8aCc.#@" [<Jt4`Qs4T/;ѭhz3gO@.Y:p8P:X_,2ddzsP;`b `?5Cdcl%-jdڄ6 +5&M$79RnD ^W4,hh W, Wu^RѐHѰ<"4 bh@ j@_Zt`H`uR?p"L7eBRKM +bE ^̌#4u2ؐbdAl23b~dhH'h.D׿)4<hxZGwlhXhآ!?<444i5'W#[ ((͚_w߾l{uTE+i4h8& IpXnhl05`MM,]4..Ѥ%6%3d1fq)4 +OwACWCw_.4\DpjW4tջoH4]afDnDC7jhRϏn\6-@` ~A12H?_)2k)hWب I t4I!jtV ԠGbSLIbC˘Mh8mhx:hV huhTBC0-@Ü4RNEi5͢k O ;@r~9JyWUY/gѠy1?՚=]ᐕ~|, a9N+5~Ld*˚ m`\VFC@FCOfzUeh킆 4<hx6R4$hG [DI j<@<`Cm҅hQ7C8Ig/T48F<ZVeTW:SfAOKM%ƘM4,| [Vs4,Z0?1~,@ÛW4< p@ùv4)eh2aA% .Flr0J/5R&MhhhV 2CPgF09331Hd(@fjncX0`c芆 6hXAа@$4gh; 2**SpR-jSӭoZ\E~ P= _FP?7CF sx䞖P2S jrVCaA~L Npf:;4& M J1ClOP6p@BN 34$'4hx 0dЀ{uYDC 7HhV khx=h hАD_4| aOZF&CC!;Ey~2hhp#kEd5G+dKAs>~*^>QC)<W#بMp4j IS23(Sc,93 "3eYZh¸QDj !+4dgd4l)ŋR͙50𲎆Gnhp-h;>(N9{^BRw >hjF]} y +NZx:75˱l(rPr12Q3HP'A~o rf8ESfvHefʤd(Ȕʁ Vf3fEAFZfD4ݷ hX*a +a aؐAٽsGe4γ@%:DíxD`@è1cM4e4>DFt@# L  11S%`m l0:o^.mfW_j[4DkĦARˌMteDLȔAd*!2nf3fq GPА$'̛30008lhl2.$h8h?iha@3 =49j4a2anB|%8n#hHM )JpR9W5tDK rNGk hlEہ Šn*goA AC& 44Jhנ)DS̠#d"SmEƘLh)D44/.zLO۳KEG40%)aӧN4qX@p p=SfA!4p@K?^Gh0if̞4A2D5koܴy a7!˛hS + 橵DFxĦ46p708,n›Ys/XDа|Eú  ; 2 +|"@CyE%6a֍g -vk@lG_].G#V[fAC'NIj"s< .2mԑ)%1"1Jd3U343҄DC30}2b?!ǛhH4lBѰzJeK'%̝=cɀр׃@24r D ?fh.gh O4tѫwg.0߶kuҵJIN)RJ)ť@qwww]Bl2q u>3g:s|vN ~Q1q ɩY9y 2h^ WV74I 4=0P` 9pd$ s4R 9Q4@3hj' hh +0g.+6n741wrq  + MHJI-رkBg#4,.C4A4i4 xω '5з#h6pHI0b`ȠX 9T^_4jxHlR 0. +ieĔЉiVaL,02fPQC6 hCbЊPW[]U!4\zvd&%EGEB4x:9Z[nڰaŋ.0}d J.Dàׇ 4| +0BCS a"B, !YX;B4GF'44;pFõ e5uMRVBP= <֑ǯ7ajZx= `K>3tf 9* + T^dԠhL"+ -0/4IF0e+ +hFC{@LD\TZ|O"4А`afbаa2 *a8h6B4Cap4L:}B7~?B4]а?($,r[L|brZFVn G8u܅KW JŕU M6RDC}K@S y5["ـ6r 8: +6^ 5YIE90bF0݅ɕL }{@C 5 hLKI  +tsq03h аz% sL8a |<U-hxG #5F;n Fl}6r) : WVB,*-)*Br2RbEzy:;X4O?w~5D hBÐ!y5h Ԡ F5z L1GÚu zF&fֶN.>~Qѱ I)y;vAh8yy7K+*k2y3@-J  &= VXj`s>2M 8r02%pVD){9C 01`K "o1J&B+i. 0r 2iScC]muUE=| /'+=59!.&*",8`&U+h4|%@ôS&!4 9᭿ ".@ +h$0Ygty,\xe 6YX;yzGF'ef4;pKW4+jj$ -koBcң_*~663% *J@I*S~UKaS=J \6jgA0q%P(.3q̠ó*EC'B2CDC\&ij(/+-y {v(LOMJ + twqr4312hXCl  _J4hxC) Ap1 4̙Ka YX;yxEnOLN߾s7DñΜPXTR&W 44Jֶv + @ AE^ +K[x|qI T0Ubi@EU*é =|aBϦVRp`f;Հ->6 n@Ɂo_0 /G #,^.Ij 5< +$|J,80m9B.,j}H{o 4@rgC4 r9f?@CgG[ksc}]MUeEy@íE ɉq1A~>];XY49EAú5ʊ +re$W@E?@3BW s!hX &l9YyE%yh8~򴺆9k;'7!aѱR2s^~kZZ;zzL384<2Kp&'k)||;N "؀Y8>2|hN T _+B2|A`,Zxf)#><>ܫ4`llACiI1DC~nvfzJҕȰ K>^];XYjk4=|p;o Ѡ(aRh;4̞N4M Q4LBbqIiYy%յ vڳZ:zƦֶNn}C#b.'$&edA4ܾsDCUM]CSsk{GWwo9p!05cφ $Zh3̔Xq4%Ѐkf@06:aޞ֖Gܿwׯ]HKIJ{yhظAIQ^vԪ˗I4,ZhhA + r +J 6mApȱjj[Z;:{zG'&gݸU\RZV^Q P`qC$4<hx- 'A jۀ7r4l jɮf03Mi 5 + Kdטɛ?hu09 1D `vwu676TUh(,HMNL puv4756:=vlhX /+#- аΝFGyT4,Xbj9Ee5h8odbfaecx%+I)ٹW 4<|T][`1 P *hxCao/{[ɁާHbaOG\ )ėKf#ҫxxUas@m4A.5lokij(/+-)u!;3=5J|\LdxhPYS'9a˦ J +rV hh&F +5 hX*. C +@[ܽwG4hhYsprqu`HXDTĔ,ko޾s 5u Mͭ]ݽ} hxNB wLW e@W$x D GoG_j*ʆߧKL ψTd 3q&= ހ^̞fhr,&4\v5?7;3-%Ȱ K>^];XYjkaUeE2R+W,[BEüqhnz4FDPD b˖\%%ZV^QIed4#&eAMw@aZO82PS6 ѽ@ hAdtu45VWUVߺQTX?3*3`I>Jޫ{J"HA {fUb'Q};Ý(dtyt]OwW';kKsS#=M4hPUVR= ,( aׯ0~B6 \\a:a+7@4h %#'r[w4u ,l]<}"D'$gfUT54utv OLMcfyBPЈ"hx&|"%Ƞ2X +aYL3dxSu*]a]&j@ᒑ .TڪP16T1 P@A`40HDLM tu45@h(+)*HMy0*",$06@ÍkW.]8wԉcG4(*HK@hhس;)h؂Df2~`@vZ4WTh8|g_|:@蘸'iٹťյͭ=}ãc3sy<0Cc5%6dVRW@}F#X/?.[Ko +-U ,ذ&\>G%V +ekͰBh(l $"~77lohhLOMNJ~hoceaflq Uee`4h؋F `hn*jа_@H + 7ok[Z98{z߽0Q㔴 +Z:zzF'f0sX@$-԰7ojX<'3_i֨e.n@,t-*4dS3,*/@גE7oL]3,c6T " h  xv3359>62^v6z: 7_|'= Р /+-%!.*",$ǻ YagFwthjBа BP]xa4HJ)(*:rĩ3.\r-uMm]}#3 k[{'7o_ఈѱ I)yE%eU5u ݽ}CãSӘ9<@ZxR[0`V!4ArtQ)j@o6PH h8Pw3]­CXV(+.ٵ%S\"tMa "m#W 1k /Cf@ϧ $"~LOM vwv45TUde{o3025spru{/ ($,2a)iY9yE%eU5u M-mݽC#SӘ9~B#b%&?I/,.-oljiDJ }f%G @֠L԰"7P2/Pb%uo}/̈́uQU#hi-hHwL1'- /AD$㰳񱑡̴'I q1C|<\m-~}E5auf&*"<$(P_W[CMǏ>w 9YiIq1!A~X!b˥Kh4C, + ?p ԛ @$jacy}E%eg5u L-m\<}C#cS3s +J*jZ:zzF'g桋K+kM@ (4jyK {45D @ (7`W8Zd8h5; ْP)Kj`I,5 !hf8&3omfG "t~nfzrbltx /'+#59U\t˰~ޞ.Nv֖z:ZjT #%).*,$t6.h;  ?᠁@ ._aepރ?yohbfaec_X\Z^Y][704<:>15=;]Z^Y[mhxRÿށj÷SFê˾7 p@ h0l 'djBeyXR%p"r83 gc77akKЅٙёԤبР_/7G{[k 3#]mMh4ܾ)/+#%!&*,( +aafр4 34:j4BZ h4j@5F&fV6vN.^~!QqIi0hP3465spru{22:UbrjFVN^AQIYᑱ陹ťյM~'R ?٢_A @:p@ Tc5G6F5Ó% '71 R!mH3 ahomn,/-.HKI|2,$腟'=|pέҒb"B|<ܜlf& W.#/ @4fFÙ$p@E4\acy}E%eg5 L,m]<|B#bR3s *j[;{G'gK+밍M P [[],5QRNm@l 2v`c@k e4Rq6|"M! |m '""Rf26|k 4 o4lV 3S#Cݝm-M u5Ue%Eyٙɉёޞn.N֖Fz:ZjT '#%).*"$}4\F9΂h@4 4/(,"&!)- ν=~TUMS[WEPHȘW)iY9yťյ-m]=C#cS3 K˫kTxjCM ?Q/p@*q 4`GCjXRt%Ubd嘄pаo$3l4`ashomn,/-.HKIJ +puv031TF2Rb‚|\lf8h< 4>24Gbhg`+W40CX88xxDD%enРg`djnim_TRVQUS704<:615=;]\^Y]j@j qŤ@{ԏT6s>H/M 43!WJj :Xp"?v*36If64j 21S̎Q'vĐ6M;s$ˑI{F$"n'fcNaog{ X]^Zhkij(+)zhokminbd '#%!.*,( gge1A! ǸB5nj} b#Z:z(#_@HDL\RZVm]}CcSs+;'WwOo߀'qɩٹE%eյͭ=}C#S3sK+kȭ]@ /_ ߝ=Y yT.\p qŀs . K8~/Wl뱋f ^?Bn!Vf'F{;[k+K s3&'FGx:;XYjk*+JKI pqXaP=OpK TTp#pPPRhA 4@`,pNn>AaQqI)9%5 -=#sKk[{G7/Ј؄Y9y +K+jZ:{G&&gWk/N^PIU =p Wb$!_um pv!3 4fЀ2Ë;[奅驉gy9Y)I qO"B}=\l-M u4Td%EEx99X =Bݻ4`pcς[xhD41@L0fV68'/_@PHxdήɩťյ 4ۃãcVOd5\_na6$vpb 4())AÍ߈jyO@AIEP h@a,l\ܼB"T4t M-m\<}"bR2rVT54wvMLN-,. 7[;_:QwT>mPـtz9 5 t"D! <7r%We5Ï(3 0fxbowgXY^\hkij(+)*HOMJ{`gcenjl(/+-)!&"$gce1B!t?Aý/4PBZ O@ =g02XX<|¢R2r +(4YX;:{GF'&gfUV76ut OL/,-"76wvV5."ll8Ā9?+>qNVGr2#ʻޟ ^e{;[ȍu@_Owg{ksc}mueyiqa~nvӴؘ@?/7gG{[kKs#=- 5%9iIqQa!>^nNv6f&F(Gp. 5% hI 34 ;(4Ph8UZ: WTVU7465sprq KHJI{VX\Z^US?0426>9=37ՀFZ o>U{,5|j6;!D@6|Yy\F'B6õ̀A!3fx2o' ;[5`owgG[KSC]MUEYIQA^NVFzjRBܓ舰_oOwW';+ 3#}]mMuUeEy9) 1aA~>.N8;+ +a} eh4Ph; + A4̀/84B%@ 4^n.N֖ƆZj*JҒb"B\p6Vf#BOQhjnf40n hp𘖞caesr +IH+*kjYX98ݺ +j+8~۽}h}Ŋwwwwwww I{nLg_9'P5 a_/084<2&.!)%-3;7`hdl|rzfn~Bbqkk@ j:fNp{p|TI \.` nmn4j07;=91624PWSUQVR@B/7;+ @}p whh())nMhv x5* jc`#Y9xxD%eT4t L-m:yxED'&gUT54utMLM/,!WPh ) x5԰WH ͈  n 1:d JEl!WDd3|3 df2>@3^nm-M u5Ue$Dx99X 0: x3@h@ 7!3k ?4@#hA5|Dt0z8O@HXT\BJFNAIEU]S[W_`phxdt\BRJZFvn~aqiyeum}csk{gwO +z[[jjxN}~NA|DPWF$ojwa3v`43 k8*zeyiq~nfjr|tdho@_oOG.Nv6Vf&Fz:Zj*J +r2Ғ"B\,8#=A4PAhu < 5ih@j @430™Y88yE$$eh0465WPTRVQUS?842619=3\FWM@ ϞTKP oY MRil8pOlK@H\Lya27rUfuoww ͰtkscŠQŅɉޞȰ?/7WgG{[kKsScC}]mMuUeEyY) 1QaA>nN6Vf&#=PSQRR&@Í#hp j B- T 5h{`p3 +;7/#wO~q I)iY9ťյͭm]=}ãcSӳ KŭjxMW5{+$, l G@>,vjT ffx} O3a1@_OWg{ksc}mueyiqa~nvfZJRB\LTxhp#';+ 3#=- 5%yYiIq1!A~^.Nv6fF 4Ph ?|)4n6%%@ p-' (,"&!%#+ohljnimk?($,"*&>195=3;7PC{gwo +j][zDY u$8N \u|ESs!\>5 x4@f\_aV+Ks3ӓc#Cݝm-M u5Ue%Ey9ɉa!A~>^nΎ֖Ɔښʊ +r2RB|\,L8={h* pD hp$j@B^ ` p3 ;'/c}54utMLN-,"WЫX&/~!59>k3p'#~f0㸨)I!y!Wwvwv2Ë@3lᰫh2rqanvzrbldx0Cc}mueyiqa~NVFZJRB\LdxhpcoOG.Nv6Vf&Fz:Zj*J +Ғb"B|<\lLpFz:#hMp~3C5*  4@g#XX88yE$ddU5u M-m:yxED%$gfWV76wv MLM/,!Qh aG5r_ ;;{x5NVwIj8 @}8Id _|j8ӔMʋ +EC3 O34j0?;351>:<4 4Cnvfzjrb|LTDXHP/7;+ 3H=4j  f8gL83% l)B!K)׻r{3wm6v7s(hHB{̛_shJ ) +(D1X(MWTRQ3021sprq  KHJI/,.-olnmkj'acs{gPgTjxqZ 2w^6P,~‰4剞uLy@K@ 4 3ï5S`;ۛ+K3SC}=ݝm͍ՕŅٙ)I q1Qޞ.Nv6Vf&Fz:Zjʊ2DI 1Qa!<ÃF!8n 2n죁BBmFp רѰ@C5ppr!<,?^PHDT )ESPRVU7465wtvu  + OLNM/,)khj ?0426>9=37s15(MWTRQ3021sprq  OJI+(:TÝzzG&&gW7w敏=5| o S y3TF.:qadǸ~:0˿9 v60;=516:195=3'6PCgwo +}zCjT5T{ۉjxh 1p)bh4~1R2rzfx +Ks3ӓc#C wnij(+)*HKI  psqr0312PSUV&JJ + q|X 7 + ph ld4BhdhpH d4 @N.Ǐ'HJdU5u M!58:{zG%$ed5WVCjs^Wwo7wCjxzD _1!G?0߇IL3\às'o Q3<f07;=9162^@HXTL@&+*ih5XZ;:yxED'&gf^WO]OhS b'`Ùw ѻ i$f~>bfxA v6!3,AfhoPWSUQVRT̐`gceafbd(/+#Mn p8((np C4ppr^,/($"*N")()kjYX98yxGF'edUT54@jj_XZ^][$M5 #jS@@AJ\EVx[0 }\N #fxo}3<fX[f{vKSk3de$%3z{:;Z[jk()ɒq1aA~ÍF!99n 4# 4pp4R>Xap8 'jBy0X>^@HXTL@&+*ih~j2;5H!HH5{Uz &""""VDz/Amunl9I99g|'7/0\ں7[Zwv B5LC5,,.=|)G 4p?D 9B1 79 {,[h&@cOEX[6a/aa@_owg{[+4CsScC}]mMuUEYIQA`m-M t4Tt_X\~ [ ϞsoD (f1?6ræ\d'l?<5P"SVUh֙~X1ó00024z֍kl3\8rNfg&'FC3z{3XYt4Tty9 +YD$qRE0@#kа kհ b\4@5  <54DiYBLe5 Mm]_@PH؉dܼӅťgΞ;P ni;vobjza_UÏP S_Wcl&,=-6c[R7B&z'4�ybט;hfghp˗.rPZ\x:/7'+#-!DXHP2ASd$i"'% 1DQqq,Fxf;аh@4`Vp\B'I2dUPRQUa[Z;:{zGD%$edqPVQU]QÕo5wvC5LB5̱[jxUß[dlx!,d)l;QDk֙[hGK &C3 tw3d Ih@_oOwWgG{[kK 3#}S /G!ː19 հk~jQ~, z_;6c'㊰zl 550åŅ''FG{:Zoߺp ϝ=SY^Z\x:/7'+#-%)!nm-MM X:Z*JLE,C"8)`hfhb1h44 bppp@֩0O (54ABR +'Jdd)Ty"SYEM]S[o`dbfaemk^ /]pN[GWOoW 3}[1gAMPnǓ(?Պ3,/.C3LM܃fhpj*J +O!&*"<48PdiT,$M$$!h8vA8hf8,  A#(44@5ppO Jːe +4E_@PH؉쓧 J*kj^ pwe+jx@԰/#j7q ̇R0Š34zbff;2< rv '3Sc#Oxy89X[hi(1i +T9 +YD$qR hfhb1h4 l4m 1?4<5Ph +а M+J*Z:,=#SsKk[{Ggj8]XSCCcS3PCKapW >;D߶YMcɆk3<6`ٙSơz;Z57py9Yi)I q<3x{:;Z[Zt5T :MJ% l4; +ЀQh8ch84pFcX.5 DiUFg0U44uY&fV6v@ ޾Q1q I)iY9y@ gL8؁s@vGJz=! ޻] 3N{9s>A $}yϑc'@5\00ϞUXH JO;Zp`kE, 3G~K`WS/f0qޝc#C 7C3;ݵ*K s3Q3DEB @ZK%"!a3t*L$A3 Gp V3C3|hBßg.40-hQ3;r{޵sm[l,/-.΄fH7 zV$betLf4co/fUhpT;T_-j!ԨU +T"y6AR ~>634x{4 4 nV43 +a!5أw;5p0"L,6'%2R (yE .5jSǨ>jz~԰zoJZ<ƚE- :aG3 3\sͰesueyiqa~nvfz*0C\LTDh\& <.ŤӨd̰ɆY`X92ç/3Lܿ0<p S3ؿw];wl߶ i)I 0!$H P)dRHrXLJ! ~fhh@hܬhX +`Ԁ!x<@PM>@ $2Jg0_(H +Z + 5#cR2r +aj8}PC_{B5LMjm?L c~`Kx{dzs|UNΛ+0n5 `Q3;r蠽jk*J +rc#А`}FRʥY :B&|f ̀Gp V3[4Q7;4x ԰aF B5$2Fg\@(JZBM@ ɩ5UT7465[p nSs԰[{ػ[65Z&3LN;3TWfHJf0 !A@MJ!E>f2T +Dhfa7@pvfpj@`QA P V45Id +`95ÆuW._ʙu40C]MU" >iYLFNV*RP^l@C@@4h@hՐԀ<VC>hRJJ@ "D&WZhNqPCݔFPCk{GgנzmشQX @ @ qjSh5a pd]3|pfx6+/]3Ff8z6î۶l̰{NWg2)`d<|^aVReRHf(-)h(,4PK1C.k 3 Z yH a H BX*+U`2[m"x0aNwςEKjضc#GN.`5\ְjD>Rfc 2Г~d56`On~2û`ׯƘ" 21l}{fXjŲ%3hki3V'H(]l2R!JD +d `RАâ!WZ H  H |>%5eR(H +ZMxP$57 5͘ɩaŪ5k3jػ PPK/"5vuPûH | FydG{ 3fx3+W2 dC3l޸~-ggfhj3T%bpvd4jB.Eeif4 (㥘!5Cad4dhAh`) +j4pj()-+\Rkub;?U5iӑf͞;oBV 7opVóX5©}O@ c5|ͨGHi 0&RCfw {) ;oeͰth3NfJģ`q;6hi*\&`Ғb  `l>// 9, #!UC.R<O @ X ,A BD*+U`2[m xn +RCk{Kd԰}nFjxVQGRZ82 Ӎ~0g>&m3fxil'vfX׻zr ]`S x4 +nf5 zFTȤa2d@C@K1C.kq2!M <Iij(+5%RBFjw^ œՠƩX ]s5]VOb5<è0` fزik=sZ x, +nzFTȥ4 @E!31fxACxj`CCPh`P\R +j\Rk58]?zPCsKX5lBa?VqP󠆾i55!ψH#E` Aa/cWpp 6ÎmV,[6m`0CU" >iYFNV)20x26B |d  G4UA5" *A R\`0-6h,QUS[Є0c,Z KXEaN45"j s$fx9 Gc3b̰fcga3L3T%p0l2R.JD +lb4`3!kD4ѐ 84 5P aR+*bTP4ZdNqPCaVs1jXVî=X GNeN 參Kt?[jpfry90)0Ql{6_Kay S x4 +ncFTȥ1,   |^^ +83dga ]145@h5X5DBFjw^ Ɠ)H X .հ~#X G5;?pROD $6.f'k0i nf̰t1md`d< ^aZLFdB.EB0CiI16B2C!AK1 83<:fHGCՐ8VC>AC1RC +Tj΀ty`('kA S:h5,]NaV}N5H$i Gfxp}!3fΘar sZ D,}nVReR0Ce2dl@CA~083 〆GCàY5"50h@j@ ILSCyA"ɕ* Rb;?PC VÜnZ +Wjؾаj~45|J@"H{!3\p0 dC ;i3Ӎfhj3T%bp0l2R!JRh3`30rK5ãat4. Y,2SPC!Rß̩ A jP(`2[m@0%j@ MX = h5հS PÙ._Bjح ++-V{%y /E.[dٲ-˲eY޳8F!! I20PL)3@ }t>s]]KoVqW3|Sn_#3\(12.019= jJjGj8Ij Ts8.g7h/ f#5 Ozpp̰ ̰01>@3 ftfhnқ`%3f(`ԛ!hXECU &fAP&TCF5po0+jjضppZRC'5&8TP3|flT3<,^2!4î``db$fCA4`G346hh "\6!h`PBj(C5hP`C5TפP@j;\nO!TCr|b +԰հ ppU5 >jG߬㸻d73<1}d#hE4D5|j8[ jG  s`a v:;|^ fhPP f34f0f(ΫrXUQF f +RRa6СQp|t0jX@5E5#5OjxDUË7KT|8nյ[j4Q2dhh`M`Tr Ѕf0CK UD4Clui3f06CP PhPj֩YV &A @ Q Q 'H E5f(b&7 j PCKA >jXaM%A@Dd5x`A T v54hj8<5;\ ?F DDR%2Õf7̰en m 3Rc<52lPCM5l~vjx[j:7@D$TJ!a d0C jPP] 5,DK>3\d^fQ0r WC԰75$\ G DD$n`3,˶\jVհ:\ G;sC DD%7Ɗ!"h"" fX71>m3kfe N4DQCM 9M 5M@ Ohj~_ L5l@ DDI3,uanVJ7hZu5 UƊE5|5IQ+V0/f(] ᓦB DD3LmY53gfYjgU҂'EUë1@D$eb2Ͱ$ -.34`G 3=RCK5ތfp / 5hF ""Y af.P'"[ v5t9հ5^F0f10[ +ע",%v0k 44d AACA yM S|F@D$a_ ;Mya03 i +4Ħz@D"?Ra4!3ȀrfSÂʫ!@D$i5@jfh +0Lெjh!M Ha +n}UdSc>d)f-JPq5tǨAjj ".p6L 0CIj/Y zˎ֖mFj j0Py(0fj=BC. jh2*@D$yffXf fˆNWCYajX5Ug!frj[\^i6G DDU=f.3d_ A DDVfJ3jxC w)j5IfȰ\h@ 0CYf jI55W\fu&0Sz3TX CH60CIQe 1Cp~hHH { 5P%dHnV@ɧxi@D^)᫘!DPåN5Y U@DbZ nE DD2 5<|GQHe #!$)p>3g̠!]5\PÝ!jj "J/PefY +հ/D w㨁(0Cՙ!^5հPZ@D*iOAbTâT}@Dw'bj0Cj3&fWCMjXaQv"" O +0CRSE TPQ:aj6CjjB DD &E 'QXaj7CV`T5\|E@D2_[AQG DDU]fh >Ŧp j "3C+f.)5 {aw@ DD闚>D+5L(j "a NR^@DN b3$N" IPg_cPj "*E3| o "PQ P2oE4'0ť>jX/3| 3Hj@ DDJ5ÿ5Ñʚ%!ʫ˩%ƢḢ(J1 ̐Vaot55Ś0fx'f3p,T B DDbc!C H-F3<[43uAQ!@D^"v3 3j8U @ DD/i3 PU{ AbRü5lD DD 3l $n}\{N}ѪjQjVRj5F͚5FԈQ#Jb(!Ф$ [oxy羮ss|o-\EpkðgWgpg0pƞk85  es \PXƖgxgHpkH[ggRgxgHxpk85D63c3|3*5]>r\Pnp3|` o p WP)M 3\25\ ˰6a3iyom>W? n\Pʥpϐ n&5J2 /^ Yn&\P$}Ki!5%I޹2\Hgg(kp @)x/~Owyn{x<} 7^ cP%$ Wxrogs335 w3\>];>==C\kr3w +\|ᅞ595 ?E<Ã1u e Ϙ=u r Agj3\ / es H_ggxgIk805\ _o}4< ቞<]A+h0*Κ]ùAgp3u n33ds ,3$3w[ϐ$SȽggȐkp @Rx/|Go<^sp{ϐ/ ] yr HOgxgkp @jû<s\k+J\g p 3x|pg(kp ԲP#ie gzokp `<15)N r g q DMpgkp  +{V<Ñ5+N l\02\0* +\0"\0db(\kF9yֳzww}_3yGK3h"u5ܧ bA3ՠ JA3!ՠ BA3%ՠ :A3)ՠ 2A3-PP hf DL5f DM5f DN5f DO5f $@5f $pji@"R Hf $C5f $wpjh@RzQ gHf $F5f $G5f $H5f $I5hf $J5hf $K5hf $,jc4IS 5A6@uA38ՠ%A3,V P Z4T4=T4ѧjL5ܥUA3#A5@@A3+A5@0A33Wib4j5 nA3C+TtO3hz)jU5@4fz^ 7hf V:pЈj8E5@l4f#WT 4r5TnFdC  A5 +A3{TV4P Cj4f Ua4HP f d#jأN5\nP f d$j~5 A3aH| _ {f djP5@h@ZuCW9u^i@rT LW V WI3h֙vT -͠Xai@֢U4J3h2L5cA3Ϋa1հKj8]5@+4fapla5\aA3j)VUpj4fY)U!Epj4f9QWsհjXZ\ (E3hX)jX2͠`HհWj`A5 A5t4fyg1p Wl6lP f @, IN^T hff jXZ5l2m58T hf 0RWհ6U #͠`apP5 ͠`֫ajبvTΪ4hlR 9͠հzjXb5l7T hf 0Aհea5 <͠`ajS5@J6ÿ5f k U J6W ۔g͙ UÅj JKhf PAߪpj4fJTj [A3@ET VN+h4f" UT4J3hjxij|O iD^ TT4J3h)jj4fr4Ljxjnj4!jѼjjn4Mjj4fET -Y U R Pf\3@EQ _ ?(A3⬆/ ᫪44$jɒ?S Pf И##7& w5|sB5N5@͠QW{#cᷪh S ̹jx\52x5E5m˗ݡV Z?xA3@VGWk_ oU f JjxP5l<׬_'D3ܪYiEF!h!EY _TWTT4]>R\ ?[ P 0C3h-jjj:j4ET}4jxܪjxjxjxL5o\5|C5@A3@;:׏f8M3@n}Uy3 WwTR3\9v 7A5ppfFR 4u h4@5Rq3 P1*S+HpKf8I3@Tj 54ÙP OXX ]Y //W _T×UT 'UËTûWÏU٫ j >=~V4pf<@*l'4áM5|X5@pêfN3 qTVOUy kȏjP įf8?fXC3@dUÓ ᵪ c W\6 ]VVT{U3]3[ jHV#:n4F& W iH_c ;N hHKxk. @YaA  +ll5dF5b[39VcULf8d326 1%&j.lcK7öz5Z584 pfFS X4 w.j*6!XL50m33) KW6~sͰff@ me"jj a_ m40jP tF3&êf$CA3׎iSgxn5B54YjxjkK5ɚv5<ܡf8qfؤZ3 yVTyH64ƚrT݈j7ZҧT]v4ͰL3l +U'U9Hj <ՠh[ͰP3l7֯ kHjP +fا +uA5PSͰgQ3lYA5Оpf*\ Y V 0IpL3^ i`jP fP3@"j%K5kn i $ՠM3h ՠ+fmeq05"ʊy*(,,"""HH"$"J +968^z3 +asky||^E"f5P,<3 `IjP}d՚9rf:5P*L3` aIjP=c0Q5*3~fNp>5(0Ap4jFj 0ϘARUQ5ڢ3Gzfx3H5Pq3= i3BT):)0f 3H] j8Ekf +3H%jUS0fͯ fTK@ pi~a3YʯT9Ԡj bo3* jPj ƚfT ֶljP13HiNjԚ2ÿj7ë{fxq ~֎ 6 +B gQQ3Y3< i8j-n3} 6әAH@ *Wf}I3s o7+f4.j)~3y jPB7efTy@ *Z;fX3t> eISjPb1afTQ@ *30威qfޝm ;fx3HAy c72jPB4ARQ5(O{ 4D Ac_5ÇARSQ5h'f`IjVidf4Sp"5PCo?77 fF@ Z/N3 `ID Ԡ2fx3H*5P7[2fTC@ Љ"6ûARQ5t :\fxS-fx3Hʌ13H*5PCG %fM1cAR%Q5tTZfl@ ARɨ:30Q5t*f`I3D С5wARQ5t&f`I3F Б2ëARKQ5tBft@ fx$3 !0ARQ5$30ʢjH:f`IF Ԑp )ARQ5$30ʣjH2f8u ҨAR-Q5$WL3<$U5PCb13H-jbfTc@ ֨ARQ5$30ڣjH"f`I D Ԑ@ !$55PC13Hj,jcf`@ o 3Vj4fJ@ AR Q5D3 ڈ!4y Q5D30֢j*f`I-F Q&p3Hj8jhΘjAR+Q5DRtf8g3AR2Q5D3L4 "(F3 ҋ!$5PC13H +&jcfP@  )AR`Q530j2f`IF ` !$5PC`13H +6jbfp@  )訁ARQ530ࣆ,5PC13H jnf`IG z "嘁$E5PC13H(jcfU0A Pk "JfmV$Y0ejh23H +>jkef`IAE ta$ŨFp"3H$j&cfs@ )!230أjh d`~3 jh"f`I)D P (u5[!gcfg@ VeIj:jcfT-5D )Ej8f`IE }jXV +5Xa3,4M[f$P9԰w\a5NR6-[dX鑁ARQ5T30TSC^0Df۷7fIjNa54Uuf8 \P^ 030؈\Y {Aհ@ #f8n I*gf`IqE lQ633Hp5]~2TdAڪj8#YjXk{A*v5\93aΆfX2Ñ 3dI.a5R<5/!S̰8jÃfx0 73$PjA lh{k2a~ p3\ Fi2jXWd5t !C3< CRþBjXq3 +\f$VYjʪ{l A(B5\v]pÐP}j?cՐ͆G٦aJ,3\ ^joa jX +ai džͰ m!3ܰm6p˘A*E5SÝ;jx K GPCgؐ}̰ip].2 IΝU wdT5 )lh{͛i +!Cf33í IaTmkjXcÈPCؐ}wy36\fzM MTÍ=5ܾƆ-5aa~V!u6L3jN37ܨ536hkAB**5\SfS55RB5aC۳^gȐ f8<`=36}{ 7N4E ImM5SC =5,a%eØsGͰcF̰Fjp!3HRKšP?&aO.5,nay@ ]eT2 an7x $$7H !!8[YHbqbq؉/c}˾س2^;WUwWuOa43%&,0[ WC1"f%5,P' +2ìaq7À3E3`",jر9jD@5zV6cC+ 6bAfІf0 ]e:z 5!.a.D6P0!е3.fx ̀aV\ ͠ SàN5s5@ KҨ`!̰fHf3mf7 ; alPaԠՐ4ࢆέv5tJjf%jPԐjl԰"a͋ʒ ٯnw3,Rff0i!4Q4a԰ۣE56HjD0Ր̦U5l#6 & 3P2fHr3YfP 3\i7injw3|f0 +ISͯC }߸u!PgaQPɆ kۗ aN ]phaf- 4aX ++H 6nޒ70TÒC A \ܐ73dp5âa.ffs-3fh) 0 JRaL ڃ]\ #N5TMjHq5p6jXհP($3d3dpa0C\6íyPf_E3`-QSNN5TUp񒤆~PèbfM5$jaUfclrf +D33̂t]SN3p3tu W337̰=fx̀aVĶBN5Q5,05,fWÊm ! In9 10CnQ0CdK 1;h ða5ڠD3`m^~S{~`j#oY `'QCjjX0հ$A`ê fˢ7jxӡ$5:tO\ Mv5Jj l j5UtԐ2 RC^6xrӔdXs!#4C +dxd3躦J!f/aGf[2fd3f0 OSË/] SC]FPC UCQC?UظPC!f!!! jl†pX0AE 5|V3060C7Yf?k< +4aO+^:UۮjUV_N5jj ljq5( ʆT6 EnN  3Ĉ wp3L333tum-`Ɔ ud7 a>jxͦ-5|԰KRIA W 5t5 r5\l`j5D 5L $AfCl\9}q~2f@̠iB%fq302Lr3 3t/ mjM3ҋh ðҵjx5|)a߁ʃaj8Mp5Ajra +!j+ +jHjXpSzP6.^sa3D3$mfuMU87ô:f8 f8ba3w>n agjxK ?j8P[w*UCPð0QCA5@ l C8&C& R "`v3 zZ /R36p> _5 σE3`U365[ SePCSC/UȨPCA5L s +jH jĆaF2fH fx(!@̠ic aj{wE3 zm-W23eOE3`2vڳw߁A Ojh54S5t515OP56P5Lx\QUPCTeCJ`ã,l0ErC)dx$!`A5UUX!paQj> 33T:X!fxfg aGjϙ~PpzS ~C L SUjddlXeX>2dld0͐df0ɐ5 binNqf~0Cg# fhXOpJ4=v:0E oP5?L eja +pLRC斶@{ 00hWaQC!ՠ jl0`a`C&Pj8&mdH12Xf 3;0f2p 3Cl>G3`E塆{7pBCnaQ QC4+ +jj! rۖ5odHs2<@d3$ (1CplA0C71C{(`}{wڹrBU*Z%UJ.YhR)g$9sirF$AjkLd IisN7zfzMa\up{wTbK 'OF"=T˻QÇj8GԐDԐ密fpMLE5ܺ-؀j60,# AV6솃v1' H @4W4 fXpf$a09rm4[fhH`nԐLԐ_X\RVQY][jhSAg0-V919jX jIb7԰jPa6654jG5XlvajհxO P +a9TAdæF6hppvbMbM4} kH0 waq0fpmɠ3C ?7[i=6Ë 4{GQ p,)R22E5WT7:{Q :lNaFTÍKD "P UaY/c} D AlU ܠ;A덠q1' [H  ^4fh ön޸.atح02<(PdI qAfF"CSûjVR؋q |jF54+0j0Y6PavaQl`xA@5aٰƆGly +Ubؑ h kHxV wE3dX"f3D31C_o71C /7;3#-EiS')p#fxFWÛjgfP m=}Cd젆IT 7ð,ٰ 6<nW9,2< +AMB{"h @@3ρ&'\N ͠׍ ڌf(7CbB 0û 4QQǢN:s|t*Q -GtzliT"Adذl`xٰ`}dæ6<drP" dG5$d`<`e @m3\_\@3L`3a ݉fhlD3dg\S3h&5FEfW}jxCE WC|+RR3r K+k;zzP zlNafaATa5xx@l e6hs* B ȀfE2< @ hi0`1 hᡁ^0C{[ P0Õˉqcϟ=sDԱT5FEtCtr P U5uM-Gub&P s J5 @ `ð D6lĆG*lpؽBMAA_|d dH4AxV ` Cf .f1C1C=͐f ^fh z(5|SqQ b.^OLr-95=çRTC-QCGW7ahdt\7V09%aQTa5xxdAf=mlpЮv6|baK&= <ϱ,@4g$Ao45 6"60 nl n8 9_N0p-;(2܎!- `e2~dD0C .fCfzNf1 zF#3 ~0P_[]UQ6I0a0Þ;wlJf 6m"jxRÇ1jUS)5UTVց@ |A&WԠjs8]noxbC6LM#6Bp$27l@jX/ n9S 7VCRb$w 2\_D¡P0@d3 2 dar:lVhi`)iޞ.0CsSCe‚d ǘf3iMf=e"2`3p8u ̬|J 5u -mnR PR&fw1B bـlAl 6)6\g;6bذ7XDbz0 C ",@@/`ёarmVɨi*\& |0CPYQVR\lQ31Çf%0ï_,6m^^VޏSJ Ir JA vPC_ KeC`4[v'.lBlA ss \lf$n5Q!n 1,' Ka! ~DdD 01>6:"386d3(CAX$vZ 5Օ2SS ' ap8nbKP9J yEťeUՠ6R |0P5Zd'Rop@bÕi? ͆7@ \l! kpZ$ b -&h22D̀0fy=nnMNV)2d@$tk*K Yiρ$p jOH3l^6k 8Td&p!%-#Pjkhlniutu"dԠhub9.7R@ M"6̰ـ@a1VtCKy0bÚ + 3  4.fy.fVR*dHു e`L _90Gal=Z5<éW 5OlݾcH5|j8 jH/,.)+5wtv A\Rkuzl.Cj'(`b?p3 ݰ8f>p^ryCB1,1@a1J C&," e c ^2f5zVRʇQ3476TWVRΟ; f6];o%m7p8qṄjxw@ ǨCA 'A ɠ,PC +Bj ELP5ZdX aTeZ +W 1l6n`rR)n:+``GJ ,2\ @@ $.f@dy=.nMNV)20P fhj3 i)`>?2çqfx0ëfx6ZOX o%V1PI)Y9E%U5 MͤzA bɠlHTi:dN5o ׸0pfÿ n ٰ7ʁE{! %6nđ!)2\Cd@fɀ@a q#3جѠjTJŐL* =]֖ښҒܜT0i0ñfM&4s 8{jU~Gjm;v޳o?'O΃A Šں6^GWwo_  J +ZLfp<^!V $00331lX`f ]8aU?p0&q[ cp @%C& "$" ._Htmɨi*|H:(^[k3Pf3$Ndp8?FYT 9vpԐWPX\ZVQY]jhikLP5ZhXmvcـ@*bԊlXذl7aX#^`!H22,d@b'"U A10r:lVh4jWs\w&3aH^^j{ッV{]ْb'6vw$. {sΖsȺMvl4jB.|d.i3S#C`.0CSc}]MueEǎJfx7ïssd +U /jx S\ E9j5 A K+._ Ke +ZMfty@0No9{gCR )6\ 7P Yp !;C?ۃ,İ-޹} 5 Õ$Hf2=uF"Fq;vd4"a `^0Ck&2 +Bgjj8zDYyeUMm}CS30619=;@[0Xl.O KdrJLft>0 L [@ %jpp`llxdön!# +agQx lj n&N0C 3_Eáuvl2R!3lcey07;=516: f P[SUY^v0þҒ" {03e^Bf@P]3R+d5|p(K mP6f1!0CqޏfxBviJ IQq p;zzA ť bLTizl.Ñh,j /dpclHQpȸ! \9da'~r!l0CC  +2N 2̀!_F¡qvl2R!E>3,-.ςFG m-͍ uU'O3O} o#3P(.\5jxS)5 PVQY]SWJa`hxtlbjzvnD_Y]cjIrJ&p<^? +GcNon )llKa÷n i9Ow +!b . _cd3d<} +#C,>tجѠӪUJL" +x\6kf3 t0^Ef@PW ;QRB )j5LNˠ/2R &fw? G06$6NlȨ!Ɇ/ ה7Nm$02D¡uvl2uZJ!IBf1Vgg&GGz;;Zkk*N!fw !3P(O_dlVG8xp`hxtlb@[1._ Ke +Jfp<^?ذOl Ԑfy p`C o ܐ2t1Ⱦd/(b" |d$ 81 q;vl4R!JDB>fЗh sS`ޞƆfxƶfxBvMON ?ˣ ~+B o`jxoQqc)576wtu fiUBD&WZh2[mvP$ـ,L I6\Hr ׁ  +!9@C>䏺I' T0 G d22\&I2D- @h#qvb2uZJ)IBa1Ep*n}uq]ڠifhc;vmkHE"Mqw mz 5-$h7}8$Ԣ(x~4i+ 3|0F~̀BP'Nj8 p259\_ KdrR &fw<^_ LGg66!>`=vp6B6gC ߒ)4r#n3B(2Đ"^< w67WWfӑp0z\Nj6:Z$brcLuxh fx3o~Mb"3P(9MNj8PõyEP UP -m]=C*eǹIH"O)Tj`4[vp$:3;p\6'g 7|nH!Wi;dD.^db%c p-@U@ٙh$ +}aYFNQ)RH8ɟY :JlP[SUYQ͐"4Y f[ ( +u{jxUL odLZ p5@5WVUA5wtu Ri# &kl3\Tktzlٝ."љȆlG!/8nl ! s@CD< \(dh!l/21dx I2$̐ M@奅t$ aMFNV)dRH0ɛ0ep3õf8M0Û ( +uP ^ ph:Bg9\_ I)Jfp=> L/.6olljgP lxذap9rHҁl>qzCB I0# dۋ̀S` k s3H8dn89$A9?B i/dR1B1cݝ-@Ǔacaq!:>tجQӪU)T" +<.=6ʤP)}]m-͍ u5Ue%E3\>2 +BXB^"W`CR g.5\j((*.)+oljimPit(=ΙM +DbLP4ZhX4`dl +n,pㆿC7|MpC)9!@D=5Lh` N HxP9K@ ׁ +KJ+*kz)ô5py|P$ʧ*V7Vr{|@( 0;ٰJʆ16| ƆX wdC@N4z 7Q D*$@#5C 1Hm _E i2,/22~rmVɨi*\* |3>b2FhÔޞΎꪊ⢂ 03M /d +:1=35$؀\ .5j(*)-ohlnikЙ,8w?)2Bhb9.6Dg cßlxذٰnl o dpCz 5DTHi`L P q(Ǐ2|IC2ܽs;EEHt8 aZFح8;\@MnwmM[ڦj{o]Lhmj&$09o}O2wseҩD< tجfWӪU.L*|.dЩ֖ FoȀ1 f ###w԰U`CU ۶#jػ0P *d19=3;w_lx*l +ٰP*//6_n +nnD(*x9"Yw\ z +T 5k(HkVWJ yHy ad^{< é3Sc#Cl&LĢP{.f1 FݭTePrXLJiok=pa/jmU3<6u?] հN ;v"jpB3Xl/;2EWJ{&p<_ Dd:; pW+l‡5lRaCT.6C7: ߢn@=5r@CE(0-Tx 5`Wb2 Ca j#{#+/2; 009>6:24ˤx4^OY-&c^ըriD$lNv3f؇a3b2TJG01`h'fx f ###ۼ'jA B5ܿ6jس0P *d T:l8 oep`UBX*WVk܀u7 pȡJ=q?pq/ +1P/2C2\%(C2ddeөd< ~v96djUwB.|biTJ{[ nj'fx wn#@FFFOQ]15@6@5< ؀aT +`9\@(He.eZ&p<_ Dcd* M@6A6;M ."lذؐ/ryya ˡ8*zDcw#``CVRX >2YHY@ё\6J&bH( x=}nn}NV)2D,y6AQ:Zf؋'C ט~h{pi222׿5Y;5?pPC[Jg0Y.O I:rEWJ{ &fw}^? +GD2 6B6 8>ln:?n@'  r +Q"jsB0 bN RX(.C2\"^pafa a0IX$ +}~۬fWjTJ\) <.dЩ GC̰c6  l`H3m~n5<1D Oիaj8NL DbT&R]`4Y6p4Oҙ`(d4†35ln 7,,,.- bT^FݰMˡB~Uͪ.4 +?`Q1,_d gbdbh$i S #Cl:ǢP0zNj1 =:ZRȤbYLJiokm9~  v֘ᙧQ3aش jpC|~iqqa~ |#+8N!dddȤx4~۬f_ǓTW +U0 x@"Ms90=yfȠX୽'ظ%,*{{u%Kx.O"Pb6:Zˆ ] o2]b3mbf`Xu׫SÆ&5SÁ@ =aBhulٝ.Xppܱ3Scj\*sL*E#`ub2tZZˆ = >lih`NfZo԰հS=`U#~PLT:dH4H3|XTG'gN">l p~K7 px!I?41o~/ \@=/<@e =$íu2~'"EJO gf&'FkrfҩD< ~rmɠi*B6 fC3>tN ;fbXWN ۩ b5QCW7a`ԠP5ZhXmp4O\P*TkS33ȆO^tpoܰ nx`G97<tCR9tvx@VgchB  /(V@ @w 7E #N 3@Zu\*st*E#`b6ZZ ]Ga 3b~x64@԰WfP6`C>p pÝťf7 $w"8pr t vx A# B/HPSVܿbX1nB2^J sfg&FRfD< ~rmVɨi5*B><4fF3K; 93tt13X,:ǫ57j]5:j5JZfp^? +GcD* H6:6>9l8l8y +њl@7  n-p 8prP Hխ@ 0P1| ep!pp(aPK|.N%h$ aZF^Qrp`K3&ff̛a#5x203X,e?Q ojxSC{Gg'a+a'd=dUÑnPLP5Zh2[mvp$K$Sl._,G dQ` .@܀l@7ܸ nsayy>G pxp h0?TV X@-\Y  İ&22&GkJT粙T2F¡qvl2tZZ3 f3îfxMjטX,kjհA ; b565e +J Fjs8]n #x"dsbil6S6"euenŹaQuDt-V_Z x9zA^ P Dbbb2\Lɀb2f c@RfҩD< r:VdjR!3t3˽ ; [ m o fxb]?I 7aH [@ ۉ j8l@5 +Z&fw? Ex2b0:l^ x6._A777ݰn@87(?S9:v Bˆ7Ə+1A/4Ű*U #!Å/d8K0d2ʥB>MX4>۬fѠj*0߇f2h2Þwv03X,ϨWmD 95084 jP:hXmp$O$Sl._,jȆ)†nz pS%t}"phҁء ꄐ& >,@ *bb22.II C +d(2@x,>tحɠi5*%ahu7G F3laC^gf`Xu؏ReC6j̩؀j@6հ@j*F3Mfp=^_  +Gc4l"& ^tp etG8A1!H V\haI$[  W_"P /'1B $CPg3! ~rmVhk5jR.3P3 ̀df؅ffؼb~.05PC;UVP`C!@ BRkuzlN"d* dÄ @݀l@7|nn..a'A":;<|z֩@kA P  (B12p'QBq$!dH& a v96l2uZJˀ `BR3C̰ͰUdaN:WUhf4ZsN +̮mFՀ%6vRIp`о#r9@R*_~ݧW?30l6mG}5OQd!r\ԐOj(j k`칲ʪXwW Ȇldž rCbܰ'8H9t@;(< Dicq  O Ű[O (YĠn2n#>p dhominj2TV;{d8 PRf +3B2a+3fl~ VC֖j6 l@5E CO7P_[S N 32Bf(B3\i\4a$3fl֫!SSC6!/ 5 j8l56TTVj -n`Åא lğ `atڣGM8p9xtvPx|6ǧiA  (ǚ@ ɀbHOdxp Å@N CK3&3N 1G `!  6ͶK]/M aPCl 5pj(6īk MN`Cyd;Ć $݀l 7Lqa#R4=x |&X@-.yb0#,//-jb"1 H ~dX&]"$C_/dǀ e` l l2C!͐!Ӛfv~T>S BQ EdC!@ g U1dC}KlBlx7 ~fat 0nH(7,-! IpH `Fg +Sp  (4b2 $ 2֊d2TUV N 4d 3 넄r^ l6sհ[a \M Pl`5$pj@6 =ȆK 7Gvataye$9 t;H +"X~*k`xaeyiiqaa~00Lbd0pG#G DK ]H&$CMuPf@2홁ȠQ2Cafg`l;SS u50!j6 @ g x5El̆in6u7$fg &t90L;F_ +? G.x^`X^Z0b@1 $-[IL D"Cc!VUd8f@f(-A3"`  h# fث̰ۚfvL VCRCRCՐj(B5 t6N@ UȆbC{`Cdž[ln@6 # s K6<:; f +?J  0fg3FQ $$ uP(@3fD3dX3l6RogjjE5Cà(Ԁl`5l`5f6T - }/vnI̦: @zab{ajAqa@^0`Mhb1  $A] #dUU +27PR f(3D43ni 6Ͷ{E5b5xl5ij5@ TASq  M =apѱɩirPt@;lX]ZތwV@,(-0t/0 aPkbdVdhc2Tґd@3`puP0c3!23Jc=fH}iol]5Sj8Ԑ!B#PCj@6Rـj(lm? v47LLN䰊rvx~`@h&IT@+ P : /$arb||lttd8Y _ ,_2\鑡Z0A3PZf(,(\ )3d 3fl׵a ?5 +58n8 j G fCN)6īkbÍd7  $7 8LJ8rXB90$H%('* B R06:22<448",&NL2tdǪ 2g3xd@3 hh4?"@3hfRf8̰Ϛf^^] f!/ J5 +A PԐ U$6t= dn  #R 䰈rtv < ddb$@ I^`@0  bŀd 1H2hbO!C{AJ0 h`B0C~~$v'D3&!͐Af8a5f)j؟B ٬@0r\7 +@ Ũ`٠ P=6 ?I7|nn ?90$It: XPZ.,  + CW>b@2O֖$23d3 + Hu! ``l{[a׋!KS 9R`Û?G6465& O?sܿࡂÈg ! ᓜHdʥȐBc}4ÏRfhܴ93\.sڳNaF AEPCj;Ȇ 6Æ-7$l7 YEanXs<$ !CځxPzP|0/~_N-X\^H$ ammuR $&C"*dx +23d@f( QyfAEeAȠPc̰ݙrFOUP/jh@6@ s90`C lhm:!fQSA@6(7LLVsڝ;wpA"`nzzC[X-.|E./@rV S"A&C" $Cb bf`2P0 |@m\.kVoPUCcF {AFPvaaԐfR& nPlPnpܰ%Qă҃!6D hbA \\H{;kk++KK!)1 "C( i +2 BdZ[Z@! =/L3 )34 jv83\.V[A@6P !|?(6Vl PC g6dAؠ00v 0/nCƃAA "aUrL5b-.h/$`aueyyŅb(!C d 43 RX0}/G332(34h3ܴP].jx1QCQCR54<0b 6 ]ll8 ↞^冡[ 1b9:h;F&$@,  )0,/-^\\u<0caXd4( .`Md@vf(A( ߣ Cl  7r\ ԰V XTC "laéu@7A/ Y7OLNNMOpAAAAb0PH-< 0>>6 +1 1(1\Ub(!`6~e!2 0CkKKTQO24 )34f2fr\[WCΨjhl6@ dAFQP(Vl8pTa gl6 lnr 02:66>11955=Ár8r0tH@e0<2::6>>1aAaI`@ +IaebgrU԰#aRC!a@6x yT* `CpHxu6a7(6 `ptßO-7 CC##c1Iҁvx ~0X'}k\X.^0L cc##CC}C7p͈ +2@ $Ġ12N I C +2B> =d M ; dpfp\粍԰mC55ݖ!dC `C +6t ɆÊ 'N +Ni67 t@7\npr qCp)9,PClA dKNHZX-$\H{@_o1\@d!/dxCᴐ' 4@rXTd'hAdM24 ua3rmA Y54Q #0 EaC 6 džׄ p7 tïC7nl᪸ +9:$v Cuӣ5CZA Z0\@0(/`QE (b E ^Bd2$C{f2(34 fqfp\.W&`! dn!V5 AFQP(J Ua/n~E7ndq=i8T0O:$v "2G٪ז  x!C_ooOwׯ]"1 ᆪ9Eׄ N&d8J2@__mgQIZ(+M$@t( ;Md2IfR&?<߻9{ + :%ݻs }}== Cg0 4420l3<7f0L&ӯ~Ьl6 ]N6%6 {ِPll 7 p>pnp@t =>0 $!,XJHT¿? ?Y`w751@ D " ü CdxGdx=48 2t 0"0CfxY3Wa~&daK - `@jz{^gC^a +l 7 +䆍Mrpp]s +Be9:8<@Թ * +K ą `x]_W+>b%1׈ K ,Pd(!Lda2a2 ] @d2A6C 1f0L&ǫ[ ͚^@ Agltፓ Q6L `aiܰ7lv57*uvs 8<8/=>?(Bdžt-(.Mv]V./b#1lC $"02LM y!Ӏ C}}== C'; A&C d2~=F M,6jhjh50: ==}}CF a i!Gl 7L 3䆅Er +a WJڂ=%E2or /qK  uR8??;aİJb 2 Cd)2$\dx!C7d2A53x``2LU _Z Æ ݍِ%6)a@nX"76 =vU.EABBswB +X@\^D^P`P\]]^(19İIbX#1, 3D0Ȑ'[ C3df :Z423L&7/ TC6 ]`C/B qbC0Nl 2aܰ@nX&7nUn8>9==;?pcG%E~ ៜ9+  ?Z^P`1*WI1I Dr@d( zhpp"C'a!28 όL&Ʉ&Zl 6H {ؐ$6d 9bP*O væCPQp@t:H;ЃG/%XXе@\\нpzr||txxa@d(DfhzL&筡9`ASΆ{ņnOb0aِ`6Ćaܰrܰp80 K;A +R+됷T BMxc`oowgg{kks%9tDd(I \Ȑf2Ę dɠ%dhdhe2Xf``2L&| ~QCK :450lx!lj t&Cl ɩR( ""j!ɬ@XZ.$^ y e1bd 10Z0P222 650UaàȆ vC27Ax`=0NďA +l‚ӂp*P ##f ӵdB_Jj jV5S6,ٰelhq!C"dA ~OeV ,]@Z.8/|$/0`haȰq2f f@!tp3lX%6  + Ɔ*$8'8r:Ẋ WzJVX -  +`b 0@b`2za&aD BW Q S^l6l n`8CdփA6p0S@Z./|^`00\T L Q LaȰNdXU2,92,Ȑ3!еˆȆnlXV66 qApEt< !ҁzP?Bm҂B á@b`2l 6 4ȀBY ]0Wdže:aSذMlP7gn8670^.. ",HCAђ7H ʅ+BÙ@`îa`dXS2~23f@!tcufÄgT6*6 rngs*C~hIgeah!p!xᒼTb81vH [$MaBF2J!P:WCUC K MrÖs#'#r9Bx`=-`ÂiyAp9pT#I $$  }Bݯ@o ̆ ĆĆmbC crD rxAx= ڲi}oXZ\^0`xF`İ_'M'RfM!PZِ CMrV G"sECăCD{6.X`Z .\./NJ`8$0TŰCbR1l$bX1aJf{B>֪v6gAܰݰGnxn(!,|P@$ylmc@\xPñP'*=0ٛ 0BφIdž ʆ9aB`C U7 %8*GփA2); +qBPBÑAİW#!C&%'$̀Bhza\6,flX#6x7lG7Ds(_a,x-Nj0Q JaޑaF3 ^7dž nh!A z0?DB4uXZ\P/D0D  K 7D3MC!t렆la.a(lP7vqCU90CD + xaV k0ӑ 3 :A_6 EqrpZ<DL!SD%?ւa?C1,G1 R2L !T†:7lfnˁ xP=(!Ӻ@$yұc!B26  b71 fj }B!륆 Ӂ nX7!ÞA v<RDs}ZH{/%'Ü  B;'eÜ!wAݐá(HCՃ/+n8+X jaIŰX#ô#3 t=>!s|AxP=?dcBB m`X60&@BawCʆn(¡*!")Á/nW Z`.^((aE 9 }B뤆^l9 RC4GUz =pdBeà ӑ nhC&GC" Zp\HPÊ] 2L !Ica"aÔcC7D8V E9C*#!$NpVP,2/l`X40bԈa^ B;Wk4&unpX!!CCCF}I \(y!Òn 0B[omQEƉ4K?֢8 Eֳt8 8׺<nx9rk=!k 1X8B A/TW Q2 *dC Q7|-vC/px=CVt8zT! Zx˅r/ԃ] I2XF[/B ?`-A3prȆ-sQ9鰴Zq@$2Hk!ʅ~ k0 C b |LfCTtXa&c!Ʌ^^x `8S$hK6\ p8kXK:CXXj!΅^^x n1<d n S9尤C)~N3$^x{! +o`Hd | ]P +b9,ZI@ 'd3΅P)/S  +}vC9z +r9,CPq?gdp΅~x1HnD6vc pHk;ÜhkV K.$$zŐ&Cg@fk6tC%r8A[ʽ^1HnOgSp(Cq;VOfcs 6dC!,x'DXB P( lnavhÄ|fJ/ԃb \˻a0rڡj ^hbn^pxhCTI:d!\{! b ܏MِvC;rHӡRcf I.$% 1tCi9$Pv>)MMj!ͅ`P r7!+,0\/ʎ Y-X|fᐗC!02 wPB8 C=&*7t;dlR8ʡ0‘ +P 8reZ]54] rheѝ\;R%_ 50[P-vSÏ^?|krxxh>y`P ޞpî{Po 6E;x &^U1@2x;eHSxR*_c| uvξbQ[v6Ćg̿wWg~nKٴwO>m*Å<~\%8 +i-8G&ܸ=qEGK}wp1gGw Ir s-G`Z`Vɿ  +endstream endobj 40 0 obj <> endobj 26 0 obj <> endobj 29 0 obj <>stream +HN1OGHݶUO?//Y +{,#g-!.V1W$WwՇ2<6I  <>Wԧ5\>9Vp(H}3TrfQP1,>Y\gG곝 +wvPo)l>YZgM^꣞ Cԧ=7O|r +HO^>>IkG?7Qܦ^58Jܠ^28P\^/8V\,8Z\^*@kRKV8L' uL] z#ROu"z.pRQOՁNG:J=V^83@z\T]u꡺pY=TwY^P/MuSuK%TP'xQU/:@V50Q;u +ީS{[`fzSg?uz~#LՓT=Y,۩7gߏYkF `g-1f|YcF `h,50֌X3ZcF `g-1f|3Zc> `h,50f|3Zc> `h,50f|3Zc> `h-1fƌX3ZcF `g-10֌YkF `h-1fƌX3ZcF `h,50f|X`$vELf0,hD `&Z3Lf0,hD `&Z3Lf0-gD `&Z3yMf0-h< &Z3Lf0,hD `&Z3yMf0-hD `Y3Lf0-h< &Z3Lf0-gD &Z3Lf0-h< &Z3Lf0-hD `Y7Lf0-hD `&Z3̳n0-hD `&Z3Lf0-hD `Y7Lf0-hD `&Z3Lf0-hD `&Z3Mf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lfu,0z;ˢhD `&Z3yLn0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z~ βLf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lb[ObgY0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-h_',`&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3دcA֓YLf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0:o=ehD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Zu,0z;"Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3L:o=e0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-h~ β`&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3b[ObgYLf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0دcA֓YD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z@ױ I,Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3L X`$vE0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hu,0z;"`&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3:o=eLf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-b[ObgYD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z_',Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3LدcA֓Y0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-h@ױ I,`&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3~ βHf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-:o=eD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z3Lf0-hD `&Z~0X<b-hD &Z1@Lb-hD &Z1@Lb-hD &Z1@Lb-hf2-1@Lb-hD &Z1@Lb-hD &Z1@Lb-hD &Z1@Lb-hD 6ǐ%Z3-hD &Z1@Lb-hD &Z1@l-xhL@Lb-hD &Z1@Lbi]=KD &Z1@Lb-hD v-8|h@Lb-hD &ZhD `Ob-hD &ZhóD `Gb-hD &ZhӳD `Mb-hޢeZ+-@Lb-kL D hD &Zh?%ZدFrsSo 66K)-0fŒ@ؕrZ],3ZaF h9-{?h3ZaF h9-[?h2ZaF h]-UೌWF h%Fi||dŒ@Xfg-F hFi}xgŒ@Xng-7F ,9ZN YF h-h9-g--.YF ؝3ZarZ|fFv6䳌36fAe}-Q] ,h-ig-`OF lh9-`GC?h;2ZacGiYF ؏=ZN 2ZnƏ2᳌6c)e-9}L,ch9-`>h0ZaFi{YF rZ~v0wɟe-٣M,nh9-`m2ZU>h+3ZarZJeuFi}V-YF XSsg-`ErZzʟeGiio,=Yo ړvbkWj/_ 1!B{] }W_[DF;@@{nkN;epY{iU\ҞGM.iOC(vCL izN=.pR{~NpJ{~ԎpB{~֮pB{~HE]u@;KuH; uL uP;a: +>.~qDQi%Pb7CU"p_~Au>= +!u<= u:=^ u:= Gu8= u6=^ u6 [u4 u2 :^UpWL/Υ7T[nS=z7ԩz>/Pz[= _L:@=!H:B!H:D="'u":S ΣK|@P,YJ @FWg IQtzS`suZD'g6Viam9tzZ`Su RB'6Ttza`;u]LAGR'Etzh`u\D?P szp`yuѓGV'OXX:qFQXF7O,P`s f8AY3$R}`juҌ 0:gVT3CLN&Tө3f 3LDꀙF}(`ṳ0:]&S @.ө Ζ7V'ˤeZaչ2vT\}>`@uL> 0:SVPJ( uԗQRcCd5=\% O +(YS}U Tɲ:GVVH)@.VG#d%L}nux짾8p::T8U΍շNQ3#ԯ8PR u\Ya_ +:)~m/SxZ~#3QKTϨ_ :xVbKgUpS +~?u&pԁQ|C PY+lR,V~^:@`+up&?,,,蓫 ,3%"=$L3] U ,=p +endstream endobj 42 0 obj <>/Filter/FlateDecode/Height 3944/Intent/RelativeColorimetric/Length 170418/Name/X/Subtype/Image/Type/XObject/Width 3433>>stream +HVQjh3?'GKwtZyb}1ᅬZ/[*x E=aS EOg=(*`i }A汢>l=y'_ S~.zs/.#zs .(zʢ_/\X\E?p/ClDV@*hqLnQ=㹴sa015m~v?loQzhw&p*vF;p'}%0h2Z +%+'r'ĪGKtXlͳYXQ׌iW}<%r+:8AhcEZ[V1}Qڊv99*N `"+Z>p%؊:)?O|}[q*'D>SnܒZO;׵=3m,q V[RiUu-"+>,ۖZO(#%[[Z+:象V=p[{zkCkEWĊ>8hini'Z]Yk]l^jkukEgek+k>_qBTlI8VVap;+֊ Ϊ}x<Ȃ:u5X;ObNN`lIFKKUI,]@ꏭEjMfFxaE3[%#Fk(юꋭȬM,=[Kjs+F=VtjUlb5f``w{+][jhbjԚuVf+YjΛ ϱblZkkjEʋRfTV9rU+!Udmbk6:; +tck~_~(bpUj+[֒Z6YꬬbdeW;{+#BlV!Yf3#*Y*VXE<^JV!ZZo,ә~̬\e"+XžiL3U,Jmc+ZLjDgάF3 +NJ^i)iήlor+[ՙZǙJT{oe"X* 3 +ŕ̭ll{:RKisVf}YʪGV*}5TX\jLk}9V%ޤ9uVSfU*'V9?%VNrnbRKiqJf}IgVjH|`UupqDn5V>֗SR+:a^AV˝)YzLd+X*^пW/Tn}LlRiVTf-ȬRee"XUm|r%{cmcZ36Z!sqSʬϕjtd+YXZQ.X!dl5V6>WSKi-4Yo-me%3PY*%VZ*W)JoTjZZo336YՔYTO*E1RUn~'ru쭏UDkhI-DW;t[csfU71~}(Ǖa8a(ʖ^"F;Z7 aeySTDDDDW\oڊUg +j z\V5i1QEfmIfIeMr#K+VWKxꂈ֯%GW +J5I%֠ZV9+ì;2FYYXXaUDDDD[VatR܊%UcQI-ի8+Ǭm,,bcibټqU>#""" +$VPW +.ŭX[l%֚ +kIjmuS iU0+TDi,M,Wu'""":{pV/kM:Ui] +gfN`PT~PDi,M,WzNDDDDV/\nY +֚֒k j܁ZH謍YwcV^YAYY4l^ """""WpVVZ`娵aS i-z2vVYyVYAYYL^%e/*hƖeyk-AIZi liAޭYwfVYYGAYYb*ɪ4DDDDD fKVfZIK;+ebָi̬EˬldeҨ^Ѻ`&4,n֢Vִ@EAZHO}쬡*f[fzfU  +zMDDDD^ಸebhZsoJj`֣2Yfm5*k/SR_`UX{= fKV["kԚ婵֠L-MiuFɬgVNe)dªѺ`,ne~dVoj 2UPVYL]k-{3e{+V7 +֪VHIZHheFϬ]ɬ,[YYdR2qUk""""jR2UĖmo-Oe5TBZuWg FYYۭbf%$Lezee%e U-nnnj fVN=LkyjIjSjmjmj"j j!bֆbP0kfzfieyeƊVVA#""""Z- t)pRڊu汥uXk['ƂZCE Z HKV5 gfmfAìν d%ƊUnM|u3̥%bc+gZejRE*JKS i,Ŭ`pVY ."dicIbe=HDDDD?^} +RJacKYS(CEƑRj!V묑pbֶg֤Y ez*#+K+VNRUl=Y]J\"lyk=5u,UCֶEQD-տ550;kfP։,YXX^u8h1] +\bmR:u%+ePKIk\*WǖFYv9m l9k]֊XZ@-!@-[ZC龜0k1kYeݴj!+1V ,V%OC+ `[R[ >l9kkNUIZ@HZ[HGrbVpV,יּs֮scsVYϳrz*+EVb,!, VYSe+O(KV[ZUnuPyZNZ vZZjJv֠YY3笅sc־g֑ͬgYzeoU0gi,-W(w""""ZVPF[[{k5̦֑~KQKJkSZQtYCY[Y YY{1u1++CYX4LW5ê,,U--gZZZj=Rk5 jeJkX)>/]vfYYYY6zu,HYcE+ҕ*A֭*Y%K-Z nuuXSECZj9i-fAZ;HOtVˬM,﬩s9e-N.^5z0VYldicJpAU?DDDD#BX.).[J[65ֺ֛Z.No/5wԚ:jyim{i j!8kTp$rB:3(0bˆYW_uFY +jK۪KDDDD8KV-Zk]7ֺj[juu$JkIkRiY[Y;YYY 1Mì̺UևHY6~}7UQ6u mۀ `.atrWY{O@oz `yJ*hc1Vb!lqYri+-ZkZ+VNUZ%Қ)5u*85-jZrfqf]7ZV\YJY[d2 +۪ SO!c1*`|ueiVZZ2u=NVOQk1'Hk8u<:>&grQW3+0k̺ fEGo,CXJ|ݏc1UKd!lqYri+nZ+WVZZBBZSJZViG,ìf|guᬜY0uY`fmYvedŌeʷU6c1;5|e x+-kmZk*P5PZ挴fҲEi>&Y⬖,Y0W/Y¬`:SVY)bYrxʪ~c1ƫZ8 W[)l%k݄@e֗ZZFZ-ִHk*!j8bYڎpVY,0k)Ƭae݂2ed*ʧU)~Ҡ2cVW0] +pܲeXm-X քZ+1j- .ZCPjuA-KZ\ZIi]l$q9BY3YsYY0f ,f]`ֺ0k +U,eX^e1cqBx9V[1kmaRj]j]Vʥ5g5#Қօ8YZ gu>5g]YׄY#fAY@YQdy*ʧU)7c1;]5{ 含-W[1lֺokZ[B ij]j A>-iiMxΚgMgj+gY=0k1+sVՂYPVάm0 ʺc@)+,eX^c1cl^,pŸVnZwZbMjZ?Ժ,Z=PKKkHkZ5Ii;gg)g-(gu>54(a֖0 e3z"3&V,W(b1c&calrಹj+VnZZb-PkZ_hj-ijAZCHiu挴fAZ'M()㬖yՃpfUͬ+êQ +e+V)Q5c1,c\[lXkOuWj*ZZP+ּ%VRZQZy>9rgj+g-Y]8gYY¬k>Vb̂rfAY}eCY!"re*U 4-c1;m5{% eV\[-ZZVnZ+>i !>ՅڹfmiMR,9i.iYsY Y=8k ʝ2k9,(+g(눲BdEUj31c[: W[1lZ[ ʭֲO-ZJZ JZsVuy嬎8gYYʙe)fY:ȊūViK{c1v3 + eǭo-ZBZ*eQKKkiEZ%@ZWZ' CVYg:qEI㬙ᬮ8k *eUYEEG,XYU闌1clTY.\.,rಸ%ڊcKL[g-CQjeʤUP+@յ5hY=qǬY9,Ŭ[Y;Y{Y:Ζ9sY9g]EgΒ$Yz ڝn3d,d]',4V,f"`JQEQEQkW@R +5V +[[O[hݘZh-Z E&Av;mRdPZ5Yi.3iI보>uv&Ci-'kNgg:B+Yf;+bs%t":kU +(,UtpVlL;8V767gsd,dLY Yd}!'V+WiWEQEQqLfiyzVJ[>1l=f؊BkZ@/cZ__[Si{!Z-VuMUQZ$BZuI Ťu*V Z{ֻTnJA+YYE4g5-Ӵlq]fp4O& + d,dLYqd%+W1\e*[OEQEQQ,",.\o܊kZ g-Z j}Md< ~n{ضe F0tMSe&J ńj)ʂ!V)ނg (IrFje;yn/cȬ,_YȬ1e⍕ V,^WIW!((:?0o\inJ` c+P Bk.VgIJUPU["_rqqGF0] +\p) +h-Zd-Pknvf5QZZݠV +j@PҪ ;-HȓK_-sUZCi):ҊrVZrgЊrA+ 6g]U gYpVU[g5YpV[{;fYVfMOqR1KW,X +<`ueChJ7qqa+ťDbTsyҹk֦Ėf-PfgC juZVKs3iZUUV9UH*ɤ%--ZI%M+--ҠlY>i +κ"UXXtuV)UgUYpVS,fY`Vf 1k~>@̂V,R ,WWEqqq*fyzK疫-[% k@|@~PZAP_iZV)IҺQTXi]zJ@Z ir"|_ZIe@D>$iY>gez 8Y;欛pmrVUIΪ0 A0k̺¬%R1+,YbyRx*So88;j%Y٥-W[[ ֶĖa-PB05jZݠVG; iZu$JHuҺN+$ OZ|h[Z[WJQJKtrguuֹpg}g9κC*YupV9 ̂zz{0.53kjjzffvnn>_Xte[ kWGN,X]HrqqbvI5fK5.[:v [/%Z'kIj-.ss33SS>F@ juuZmV  *HuǑV%%V#\ғK+HzO,Ҡ9+C:+꬏笫nJYpVu 9Ί5;:,8r5&53kyyeuE̲)k%eK%,UWWbqqqGTj.\tm lHljVWWujMJjAnPjiHZVeEIu+ei1UZYRZAi:FZr-Bu&5g݀YJrV-9 ji%guvuYp 15¬YPֆUY*Tc9rJÕU>?pqqŗaryrpKі-6ZԚFA{DAPZAXiՒ*IZ$bH#V^|h[ZXNQJKYYن>JY_κ9UEΪ'gYmb1k̺O̚И$)eS,i,XT]98ULxЖ-@'DGkk++KK :A]Pk:A-H+F *VYR'iA +2SV>iEA ZMg8sYY_&qM8pV99Z8B$gYCpֽb8̚c*(A: byt`ZqqwJfK!-[:%ERIذRkzHFZCD^PԂ@-HAHڗmWZ,|GZ9uiЊ&@!%%c9pV9F8F&gYw,0k z`eǏ7eId e92en+g88xc&syRЖ--Z3֓Ǐ[5 +jZ=ݠjAZIFHuuGV+,) GZ> G*qgAg]qV%9N8+&A%g Y`5>1A̚rZUIڒJx"d eK%,UWAWi?{88z!K0D`qRhYK`˱VBZkPkUR+Pk5AԺOԺ;jAZjbBZI.Ai'i}"V>uOgԝ.)p +UHκE*ΪΪjn"gYpgYĬIb֬YOn>#fmoKe\eId# +SVI$T;qqwJy%q.C\zb˱%MzZDI8QkQ  -Pjꥴ*J2$2@4M4M|epgWD\ \m1[&a-֕Dj}sP'?fj@-ej"jy::,2UiuzjZj4Ҫ@Ve8k+;9Y]u$YQq1+p1KEbgY,rVYYcP+CcX`ٺôiii/`* +eekÖg-5>6:Ժ֯~ j}P XZUiLPZ}Rښ$-ZZV51[ + jgY6YpV1pր8kgw-ggY`E"gYYg >05( ƪ K8TŭiiX]BpYmغl[kMZQj#j%jI@-KZDliHk VihZi5RUWҪY9Yh5 +2!q8kO^u"fY,8 "gf#f}2kll|bbr +̚|eYkYlbUe* ++oXM퉦iiJ 橫[,m1[Z3XN1HZKej"jGZ;DZFZ="jhUV ,iՐ⠕,;j:TMp g,0+p,b9eֈŬi( uʊ ",GWޗii*c>lqಸg-5mQkģGg@-S bjiiHH0ߓV?KJӓV;j%ЊVޕg,gjg5jNqVU/&g톳[:,b,fqY,rVHYeY |cĪUV~5M4MӴPۗl0]Bonyblly֚fgǠZSHKH ԪZZIZ$AKZH+EŹDZ -ijZZUBwFY-pVeCmUg >YY,0E"gYYYWYSWN΁Y `P](+D+ VEX"P4M4M6KU,.\ D[[-ZDPknvffթIEُ@-H2jIe֡iEZ6Zm#F#-IҪEhY$g YQguz +";O5Dg탳^ta,f;EY̚,WYw8db˷Uiir+\[غl9"j-Z):EbjZ !}.֐HU,zDZQii ⥕yiC+B>&;9tVNY lgY,0E"g1) +X\\%*q4M4M6r +-.[\!\XkZ\LgZ|,ԂZBjU',i5KӓV{(@ZM"-Z.r5tgչG:jqVU(J^qrN8k/uPz0+p3E"gYYĬ aܵk K` +*uʲ,GW_4M4MӴY|uY +eq}`Xj--.,_67;+Ԛ j.3.XZL@Z!ɈI!-J#6HJ1"+ZV:r.Ch5hZVq -vV~Y{,gh9亜%2,0̬e( ̲,X<\%M4M4M(e~V<,k@j]"i XZRZ/@Z{,i[ibiBZ,i[EUJwV|-YZY펳:Y=bT.Y_Y,0 "fҘE*ʺ/bd,WWJX5M4MӴRWdm1`Zj2FZ$-KK: $a I\.V#vV%-Vc-QhՄҡsmpV qV>qP⬣gY,vEƉYSĬa++k`)K(e#+X6|[aퟚiiZ-. a|pyrزԂZk++ׯ/-. +fZSDqKL-HKz囡"i H-ֶLiҪQhEe9ˁVSf@ЂlhBT*vYYGBgϬY`; "g%3&2 +|bU|*Tiiih1rzV[ZL-Qf +FZS+V,7HHk !-JibiBZ,-VSZRBg5jg;ꀳ-gvvY{Yg2λ;0K̂YDfze1bUViiʤX]nh؊Xu;ZIK +'nH!^HkV%nHÑVHŕVcDZ$i1C. Z! Y-vCsV'S(K8k5 gagY g,g1Y`9 ̚&fYk7nܼf|e=~zb!#VEX`5M4MӴyie+- [Og-ZsDiS%J;ogJ@ZYZ{ a֠H\.H3"-@K%2jUoI+ +8i=kg|-YZfY6Y]pVA'vg*g1Y`9kfv6Yw{¬~}5YUfaRD(>dplV0F̣jtDBwC7tn$K 55ZaaާkF:XWOqdqcE|eӪ 6J$I$I5A3]"obغ2EAjGf5"e +ue +4.,WNX96I$I$i`"o1mҬERj:"jj Ӕ=w:AZuVR};Ղʐlh-dКqjZS9+C UUjpV79k9ks"fY,``qYYNeƊE+cTM$I$I[ʟ/_&Bn1mrY5nS8PRPZZIziJk5IkIҪ)iy(JKI+NZZIβAEҜCgKY.t@ jZ,ŬY,r0 u1d@ĬY,,8br*5~/I$I$R.&.'tl9EBk@jj}q"jzCZ>3BhiZEZڋiJUDi i!"h-NV:iJg%Br" sV -pVU|UNtVrY,g=ΜGw2krV,,d: u:1k,b(K1)*@Vh,,[MI$I$i~abұeX +56:2uՏ:i"jIkZJZK{QZ] zViWBi6&--%-'LYrB偳*:8BgZac +d +Bg g̺e)[KYX1t_h\%I$Iܔ3żq+Жeomku5 +:} +"jҊImSZi=HPZ6nH֪JZ=(NVVM +Qkji/ua|X¡W>2lNbے{,yc=]G!9Ne1 Az(yrnPpT'OHk+Di iՑIZm"Ҫ*ҺߗVZu7BkSZ)@YiMׅl'!gYY!,gV,,Yu9+ "e̒"fʊ!3V\Xq]R886vPX\qoڒ؊Zkճ֢lZWZ/HZD-)-I-OZof :&_Hk֐VwWg -Z~}!V-I+CҲ -]Ґ +TZBh݊#,0s1 κr=f͇e f}QVTauL88aqs{W[ql֊PkԚ-3D,Q*QjҒч zIHYH@Z!BZ A!N)8Z$:V5I˶-4tH +%ThҊCI|h8rhpaZ9+CΪZpsVSstVOp0}:gt9Yッ: ru519I̚"f .$VHP"**88GaqrފkKb+j-P˳K0ZD-QKJKP+:,Hkc;5,#AKJUKʐ,4 thUZ!iyкVY\gJZgU5 2YNUWO"gZE.vYᬣp#ppsIz7,0K8ErĬ|PYP֗$~ +BӪv886vAXB`+f/=kZPP iMOZWA-HKP+*Ms#QHk? +iAKHUS]qHZ&i*)-@˕V +RK;%u{UY7 +8+ +tZu,dYF@K8+-鬎.8v&g),bp$9k2+0KQV?zRV Y>qqm}K0W[`KX+XZyIiZH/'!G!!$ݻ 1HkҊCKJEҪ%ie2-Z:-%%U hUnʁVYKgJZgU5M7 Ӳl!gՐZpVY[{!r68k9 u($1kmm|d)ĊU88{pV kZ +>VW_0O*VΕi^^uuuuE#i z$Jiב3Ƕ-4t]KCZZBZV%U@˗V.hŜUZg,Z,@Kt0-vZ5,@K:+ +-8 酳Y~}57uq+|p#! wY\p+Bڤ݄'wB%[NvRlߗёts$asp儳f8kY7MߩκuuxtEΠ,=JV],bX,e[qm鰕lJ_G-HZD-nIkZf -'5i 8 -+i57Ҫ$iiBZ"˒( +5gY.8kZVcκFκ~YwY67=[pј20{bV 諃o,bX(.LlZ) +iy֖gԺw"iZ*$k1iBZ,rNBZijkHZeg "h*) + -E%I#iZqi呴uL2A)I+r̡u4 +-ThC "h ,+@:*AKsVZ+*Y -m8g ;]p:gYY1ת<0ksf@2QV229wbX,֯\ڊahZ) +<=UZVҺNҺiAZ -75rCZCiAZ $ʊЊIiAZ,E%QxEҊADZI:Ih#ʍBKsA xA%IV8 *.YbzM9gZm~uΚpMNYspg]9u698k zc +afH2SV YFb )bX,sO03q鹕V [FkH2V0F-ڂ@-H JZƤu Z 9Ԥk: i96+i57jHZ$AKV UXi),I V\Z\sh-i=#gpK:gK889K-DQehZ_UeҲrrVm]=gYpsrjz=7g-kκ gIzTf%u.9kzY~Ƭ ~ҘU֟2"+XbbX,b=ǹTm鰥JLѨCZ>6$iZ iL1I=֛eH< iϹg -5Y{ HU^Vj.-@ *.NY,,K(108gM8]p~>欷RyY_~: ̊;9˳gy`֮?BĬ=sf=1+d% +ObX,֋^V2K$l%YK#sjB` ^u/.-ZW_&*Oz Һi]V ٙIsb p!H jl iUUVLJt UXi),I GJV.IK&y:dD,=|Qd:gZ_UetgJY5pVS3ka8k障u/,Y/YWbzIzgY? g=|pC01kYien,X,b^`/̵Z?RO +C`|iݏI ,!5im@Z¼{vf +vjnjkIZg0A *.NY,,K(kowP_GҪ(/#iJt UXi),I GJV.IjJ@pz +u|QdYZEB+YZpVeU59ꁳ쎁A8krMMϸյ kp;Y:,9Y@0 +#{{Ĭo͘K2Ll,S_1BX,bqJ^[؊Z+F_̨-Qko/y$-&-P+>#i}HzҺv%Hk}muy{fzipm}=V{[kKS#I^7H "iAZ,E%QxOV^y:dTgӜ +9+7Y'9QdE9+ZJᬚ:8j;GFƝٹť啵/YpևTg}YwFgP(dƬ J +X|vX,b^첃\znűZԂZ{H8 +imEjҺi]v2u~}meyiqa=;3=r  :6+ i@ZeJ Ђ + -E%IOH1Sie"æzYhsט$\Y]`;3;BoB^AH8u& $v((Nf/v6WsTd5ٜ_ΜO}C#8]$HerRFjz\n?8 ‘t<Zg"gݠu>rpV2J.ìb 됱 +#D"H$ЯWpV[ES;0T2ҺԢaAiݦuIkJħc Hx, ۬fQjTJ\&Em Ɔz֟J A IUYQ!<aX9*BɼV';ZТEAZNlB!8 UsArZY.ׂ[YbST5:hX.gOh8gM3EprMuG9.8kccsk+JY26/heDb?I$D"HrE[+Zi!jөTrkkscuIsZZJ-n"iAZ3Tlr< Áq8vl4uJ)I &VKXZLhQh΀BOA:r-,- RZ%9:^Z]ZEu,Y'hgwV, -͡%+ZU-pVYSg7Z;i\Tk:d], F"tbfκq+㬿bg}vV2Jv2fV^e +WXBǽ~D"H$Aؕ뭼c-Z?S.V:J&BK #iiu I +Hk 5;MGcuz]b2tZZwJ%VVC}HLi!h!iT*+*@H ISh܇Ai+"#SZ hNZ@UU :, SgՃZZDbSP5ZhX.gOh8Msp5p ^z'>:k]Ĭ0 ++bգI$D"HG+NnZcX5@Z;XZQzu 0?7O&'h(8WoaZF^QND!jkminjCҢu>+- -VM5Hq6C!2$0Jih@xh=diqֱgurZuAx|@A,@ ;+- &pVH, +J&fv^_`00<D'cS*8:8EYcg[Yw6Yd*CBheGV.V H$D"P][YkP{ZvwvT2 @ҺIi:%AZAZ+ˋ D|*69F>uvwmVɨi5*B.JĢF@%-Νi*Z>p,$-&3Тu։i+"-YBb9\.Zg=KCkYahjEbST5:dng#ѱpt|"65g-n^v{y)v]wvw!gQ̢UY:"D"H$N":-ZH S uoowwg{!XZ{XZo iHHkmueiqanv&1=BРqzb6:Zw$Q[k HEAp,--2-,R,}i8XN:I9 CVyZNlB֙*s42z8rm8]!:JZLfv^_`00<D'cSڕn/uڕqIG̨ `M>HTAAq_PTTPDE5IK,LQA9mLO +-7cNdp=}Yκu;>Fvw}}cs3 +!fB:@V b'p8>[{؊a(j}MPV(X_IcRZFI6%kHZ@ZK YV?z}ޞnGWgG{[kK\n2MqP$\QE@=iiix\VJr:NB.ZUZahQ"bSS9\./ A+=E:kZ%+ +"D[7+*k,-v[Gwy#cq`5Zg"g]A:N4VLa"'p8 Wh؊V\jHjBMZēRZ7#iAZs3Solt={Wbij2W RmIH,Pˤy\:E)3 -VhhB"u`hŐc֡(hu +Z hShq8\uY +Zag=O@ Eb 8KPmN_f4U+kj,6[Gu#<8ku +rMYᬏhuY{6̬[YƊ,"p8~X]ܢc+Z1-ZvhҺ bi)HZW.V@ZsSqgx=uv;Vk\a2u%bP$b B:K-@ R,VR(h u֑(hz<Њ>=gup SZahA+A ryiZY h!gh9BX'JUZS eʪںƦk[p{c `jzfn~u9*rKވOgolnCm,`鬿"g!f}`Ob"+p8{zhl1ZHZ`BimoB͍^BҺ +Һxaeyqa~nfz*z=Ã>WoOfminjl(7H,PeRH#!i1EH z:- IeY))ZHZJD:EA8 :|Ph=Di@$V,$- +Y3$:K@+3+/r,_PmPf4Uk,-v[Gt<ޑ1߸?09=3;r%p֋Y/B:ͷ0r=,Y07(+h_q8pxڊo]j¥QZ {HZ[`֗HZƐoQze$AZ@ZK ٙɀ76 \jm45TW+L2T)V + +yL*犄~vV& ii~r9l+%9VXZ HZ'AHhŐc֡(hu։0iVJ +NZZYLh:EbIT&W(UEjMV7MʪںFKsKk[{Gu#28ku:r֫~݃8kg1tɬ2,beop8ܓӃ+EVlj}GQ>ˮ}gWZ"i]Zi-/-LM&}#!@wv4[jk*&AӖhE*eB.I"ayI+ZHZ -JINBڃVbZ'huWû:JB8S$BJ&F8C@ᬳ2(W,BX-ʌꚺ&Keq܃o_XZ^g]Fκu+~,֮>CZgmD: E9 1HfL1,& ; +p8w(nѱŰϤ!-DimĐ֟?}{Һ} IHKVf ب3<s9{]6k\Qn,3JbPY ϗI%\PDz!RZ-@ ZZ4i!hu]hC> YuA+!ZIZ,9sQB:EbIT&W(UEjMV7MFKiw8{<ޑ1߸?09=3;r+WY7ns8+޹r.YY?2OYXjp8=9=w[1E֏$EH+${;[%(i'Һ Һ +ҺZ\ }c#^@_a찵Z- 5UrѠiK4"@!I$b0G:-@ R,VRNƇSzҺ/hu։0g!h-.hee9\D*˗( UbTg(3:}JN8 2y6i鶝 """"(("! +"g~@ ݸ|^iLެhQ;:}Wwg:.wgE5+W_YY΂f;f(+X՛: +BP(jOkth+780iAjim^Z[ZҊgio;1v9#֡sݥi;ԪE\(ԋkEj-Yz1J! +0h:EZZ@ZZ'rsDBv6V Z:APZkڗ1hġu8 + ZQg&9ZYZgK-謳$2J3J2v9ǯkD:IT$W(UvSe1-aۨsOx)  +Gfcκv=9oY_';,,YYOS$d3֏$P( +B~HF[ JKzS J1i=H;H5LZ灴--.F¡`?z&c.}6l z݆.]g]ݪR*M2iC}XT#Ty\,ai" +TpJ+ rsrBvV 2:C` ZoO@k: +u, ZYYrNh:  +Hd +VLg0KYlN9WT EzQ&oVmZk3X9x'Ldvn~q2pօnYwܽwo}cc>ǘ 0g} gw JQVv7=w +BP(jJVZkE]Ԃ¨R ͍{޹,/Su&恴fBiԤ3s:#6eg6uڎ6E,5J%ZZq9lV)A/Q)BRG^@ J @ H @+?/7VvV&V"AhZkY[C#qhCV@+@mwЊ:Qhg- )ETQd9 +J $ RY\T5N]hXGFN{|;OB3p*p֥˘n~Y_nG `mFYidBP( +zvzZ[R)N>} K@Z+@Z sL(0Mz'\NȰ28g2tZMUTțdIXT#Ty\,ai" +Y -Zz!-- -- <-"V։8ǡu֡IkhKVb¡C+,L-)OtZB2J+3,6˫ ںzQ&oVmNo6̓aۈsOx)  +Gf֠;iw,YY^bVLYߧ(+X?@WBP( +B̕k}`Dj S m?(5 ŅH8 |^τ{小؆,~S۠i;4mjUY.kJŵ"a_sXLVD! >J|" VFZqhť}{ZQcIz B+;@$h:.V>U@*QitF Up+x*F$4HeMrRժnh;]<08d:.;9f"sKW_κz-/0ghsD9yBY[ kzCFP( +B pm^P+&-@-(-Zzpssc}=QZ_ŤCih&&kW._[]>8?7 S^ϸtجC>Хjխ*B$6HĢϫre,f F- +0h},-- -Z9D"!;B$h:Zړ:AHZ:A+''7@w μ-O +ɔ"Z1,eqʹJZ(K2yEnthuzCoXmvkl|3OB3p +pKYo܌9*Iz,Ȭg[3+UYz7 +BP(+[+=J㝥n޸u"ŅHx&Mz&\Nmj4zNۡiSZrYTR/ JS*e2Ŵ" +B hihiŠu"qhuAkgg%@+ꬃpheЊ: B+Bu4tVZ>"bF VUaH\'iʚJUk[F۩1!mp'<^ߔ? # K+kY1gݺ +zs,Yϡv`V$ +BP(5RhR VTZK/u&@Zk+K sp(OqaY,>ХjZUJEsLP_'U|^.+e0i"r!,Ђ҂:C$ 2!҂ʈB0C'nu :}J;=8"obWdu3IEoEDDQDEE<D6Gӻt33lLߴ}<6> +"B"# ^á;.h--9Bd;5-#3+' +qDZ#7(M6MVݫ7  &&3XXt.awt}?:Y dÄEP( +B}:[G¨`iǥiloaZ[]Yv..89ef<9a7{tM[kIhj*qEyHX\Ts99YilV2HQ)d16H u0hiEGiEFDZ!>: u:^ֱ:AZ<:uV8%h Zo-Z8BMILV +;5=#+;EQYRR-fUZѩ#cIԌejg-goڽc/gh/}:Y/P( +B_{!r틭#QN-/LOKMa%3tO# .iEDhBh]H BNZ;Yi> +"B" ^ pM89@3)NW KDeJIV&W465Z՚vmGg0 'S39ݱ\^Y]κv0h:=g}嬇qfazfW!6BP( +;6WPlZˏZniԂ¨𡗴>ߓG~[Z[wVW mn23e7  }n]]nU5+rYZR)./7NIf&1j<uH+Z@ZZQZZaVBh:C덠JphZ<:y.hE_ڃtֻbqx +5HJfgfer<~X(*-WI5:yB٤jQi:^8842j0OM[f6cѹ,->wWg=zv!SBBP( +BWly[ j#GZ}vw0im./9vu2=e7  ޞ.CӦnQ5) :YTR%(+ |^>Na%'1 TJ<)A](-/hiAhEh] +ǠuBZk6NA - .@hhEh]z*-Ί%=1bedfqy|AQq\\YU-MͪV]۩GLu6Xp.-gm޾u@YZ>rgA:)tY\S}P( +BPߦp+[^ڳ.-ZBi=*ϼ!.[ZZX_]Y^Z\p欖iiltx8ߧuj5VUsS^.VWUD%E~f%3Js?g=r:X/׿P( +BP+} +@kyIpj=?i}---(-pimZ_r..mYyb4:2195=3k;K˫kY;ngvY謧.gzv)yoGP( +B2=/Vpj=sS [Znilimn:J8C/gI{g6:" =.~G;[˩(/+).,ageRqX5B"##B1hҲC /-O hB;hzr1hĠuBZ6gAhy@hyh]кz +-޷B+(8@+2*@"SbhXF|3)/,*.-q[xm]݂^_<(J̬fn^hXZ666v8 @ :β2gvga^Y]uDbP( +B[.zjaz~zIH @kHkksH˼bZ^2,.43*ĸ\6* E^AwWgG[ǩ(+-.*fgf X:-B&"Bz.- Z@ZZZ!< r@4.:v(^YZ//ujh]к AE 1TLLJagdsr + +KJ+9ƦV^{K#I#1B9QiKe8kk{ZghpnY?@g=β2,w:PYHW( +BP!Z8eUZVj=Ԃ'&H WaҺ j1, ڹYjJF!@Gh675sk9U%Ņy9쬌4VJR"3>AQc$"!*2"B+HZ@ZZZ| .YN3NuBZ <1hhh]yc + &ɔ*=LJNIM/(*.-q[xmnAP/ KGeqŤR5huEqٴbY][κ}hYesvg=vgvgYxfC+ +( +BP^[=ҲQ 3~pcKOlҲCUZ;wnimZVLKEn^V)'r٨tX2( {Ύ6^KscSSUY^VZ\TLcҩ12A뺳 |1hyBh]ANqhu[g- < .hCh]ZAZQDBcYYܼ¢jN-D!tD6&P(T3j͜V7,M+f pp>9ۇng2Wgf,$* +BP(KqZ⭵Z{i>&1i{uJkkHb^1 vNQM)1وT2$ {]v^ksSC}]- /7JNJLӨ2 @+2@+8( .hy;־zc.:A4Ywк AuB+,@@$QbXF\319_PT\RV^YUé646;݂^_<(IjZ=lY][ھu:YZ>(r0'~1`e!]P( +B^SG~rHNp:\Z_Ai}f֟1iݾj1En^UOqlT:,n~g{[ǩ,/+).*ageR qX5L" n~pZ@ZZZ|<=<\uB4.:v(^QZ/-N`βC.^Ġ u +-A+8$@+*@$SbhXF|3)/,*)-ohjnw=}D:"O(S3j͜V7,M+f&p֝eu/YOs8g2m +BP(;*S&qz +JMZh*;w67,qɠ_i4ՔR1!H%CQ_okmnj(+-)*fgf$'1tj L$DGhCh]w+Z~Zvh]t9N?Xu 6hy۠U7кM$)TLLJagdsr +K+j8ƦֶN~W( KGeqŤR5huEqdmlnmCg},->zq+P+M_ +BP(uR i}Gv'.HڪlZ6yfV=RN*QР_$t;Z[빵‚vVFz*+%)ǠӨ2Z@Z6hy{yzBh]p@Zgp:񆡵Yo9?l΂u]gh]VhXxDd4H:}JN8$ g3}EQ@BF QDQDE4t4I5=vvv7}#4|}QĘxrBbNbfUTV79-m^_@8$KeIrZ5b-aκYZYZWW,`?cֶBBP( +Bތ[򤖛\]Z@ZJZZ1i-٬ѰkԳ3JŤ\&GDCB@ib7TWVf35)1CBCnߺy@:u*0 KZ;@k;>/huBNA4y Z9S Z׮h # QDRL\Z\кu@+$DIqJ`f + +K+jjMvngw? FcL>PNfNh0-Vt=-Oghg=r8 M3Q( +BP톭^=gi=_<uHkfEn^QϪIL*~ib7TUř5@% 0\([ZWl- -3Z~Z'ܠuvhGhZ:q-'NhŠкx BMP\8>M''$&%RY̜\V~aQIiyEUum]}#aѨX2.+gT9ͼnAo0V +/  :ɛ9ɬJYoOP( +Bz{n`-^Q J!&-- dMF~A̩U3)|B:.~>if7TWVrsYZrRb9>6EBCnк| hz Z:f?8-Y.hh:gpZY ] + GJ"59%5=cWV78-mή>@8$HeIrZ5huElږWhٝZvghgg}~Y.f=( +BP( +{smma-imIE-/i𚴾ZCZvh}mݕeb6yF=V*&2dltD4$ z{:m-&vC}mMUeyYIqa+/';AHKMI&RbH(B$>< |'@5 @ZNhAia:u@+-v-OgyCCZG"M$Ƒ(ITZJZ:=/(*.-od7sZ:]ݽ<~pX4*K')J=- Fj[Z^κ,-,-oxz+lY +BP(Y{֮zFm]Z/^l=z + i,/٬fѠ_i5sjՌrJ!Kģa@?hk4j++J +ř5@% 0\([ZWءSZvhi=s@+ :uց)m.hu : Gкx2֍Z!p|!*O$&%R2,fN.+?  I2B9=3huElg欯ܡ9!t+g}Y?ٝt:5fm,, +BP(Իh/+jm:!_ )g@ZOڥ0iʲj1 zݼvN=;3TLNȤё!`PW[]UQ^ZRTafe3RiIr|l 1:Džh݄к|': u ZG]:Qp Z:q-_??SZ0h}gwh}zBu;!p|$!HO$RSR32 rqu >D_@`09$,<2*&6>!)95-#3;'/G Ї#c wz?;'Kd%*pYZYjV܄z^X:땅^,D+ +BP(Ի-ei-^YJŞzj5j#0҂Z]YV*2d^,Ls&aGlokinl(/-)*HKMNJ  !>o<@@kWwC H Bbuc@kih8hށ-kk[[;h]2@k@hݺ &IAа蘸Ĥܼ⒲ʪֶ޾~ LYH,.%}-謯ЂzjL _ 22~?>LQ( +BPa-C_ 2I'~H ?h} uuEH8+O8cL}P_[SUY^VR\XJ +'} ^8OwWg'۷ 얖Z 9X[ChفiN`e߰BK,shк^кqB@"!Qѱq )iY9Eťe5uM-]ݔ^jcxd5Ξf9h^"-U ΂zR5Nepֿ LY,vгDP( +B}$ _0_1IZ:VQCihֲR!_I%"ᜀ?NMYc#Ì~j/ ?7'+3=-%91!.6:*"<4G<!n Z@ZZ͡#-K{CZG:u ZVV66vvZ3sh]u'M!!aQ1 Iɩi9yE%Uյu -m]=>*m>`sx39x^ ++ -,'OjV6:G~Yof2 +BP(}fkO-Kil֏FimoomnZZ ^Zڃ%ŢlA:/ +fyS0s>@Qz:Zj*KK +r33Rcc"B~$twsuqrwB5shiAh]r2ɽu`:c&h@.߱кrB-g-O7H +&EDF'&gdeWV745utuSzA:92gOr`N(Herr@km}@YZh=S0zg8ޤ=@ +BP(GixczH @LZZkWW +L* 3g0AZ?_ ܥfzf=m${)C%BN&^ v޵iw$@~?{yp89,V3AwsuvQ$"@@kW h ]i}|h:k_hAmhв= uqZκu6='ȎT;/ 08$,<2*&6>!)9des9¢ʪֶ.^O__01)͉%R|aqiy8 ^gml**: BkYr>zs+ BP( +{=,f/XЂRUJ ('?@iCѷh--.eRxN43-Fzx]mM 5U%E|N.;Lg&'%DEz{y]]hTGa n߂кb(-.BhBBZ'ZGBkY{u)Ah]|hݸ u='*͝_PT\ZVQY]SW &3"D&W,,.Bh8 @ 8 @km}}csSR5 ^|skcgg,$( +BP(;ck O3zZ:ii4jJ1-\*fgSq@_/ ?/7';+3#=-5%)1>.&:2",48(˓LR$"{pB}uN-+=҂:n-JYi}h0֙3V6ZKh]u#IdG +ՍHcf9?842:6.Nϊ%R@ke! >Z[_Rj[8P( +BP立)# V@Z@ZϟihH @B.ωfSё^^wgG[ksSC}mMUeyYIq!7fe2I 1Qa!~^t7W'Ց@${;!^1Zemei uZ'v>ysPZ':eYue cpxɁLҜ]^>zh'&gdfeUTV76wtu '&gfR\ +ZYZYkYJJ@gAhJ笟 zcC+c% +BP(C[DZo:iJ @K'-FR)7֠>2Gh-/-*2xnvfzjrb?62<8X_WS]YQVZ\Th-/O3J!;x--.HKZguJ:hmKZG ZuvZV:hк^h]u>')T'gW7wOoаhF3q JJ+k[;x=}Cãc|ĔpzV47/ K+!LTj֖Y2]fzP( +BPY˄ZS˜vQUJ%:K B뛇Z +T"N &ᡁ^Wg{[KscC]muUEyiIQ7be0)ɉq1ёaA>ޞn.NTaкyc?h]:ecmeeia֟:jZ(-:bc:Zgve u^ /4kZh݅`q"HAh=}BB#cSLV6;-,.)+ohjnm S™Yx^"+3p֋5gAh:5t.YX( +BPo[0ځ F+M 5 gOg -\&fgSq@_/eg2Ą計А@?-H& 8,B.k:A:f(#fub/,-uAޅ+Zhݾeg f8O2M־qumo̬{oTDA4.@H``M]&yUxxl8w3ǜfiŰwD + KHJNMcfder%eU5 Mͭm=.oh/&3L1 ZZ&Eu OZYJB8 A'p -g|Y{d~p8PK'H A I FRAZkO@ZZTi!h,/f2dF<5) +C<@0`&'%FGEx{z:;9X3,ifhݼu"Z -ZN8qѣ3:@$h#hF:Y_кvA.@̂fIgX98:{xyGF'$33rXy삢ҲꚺƦ^Nwph/MLg$2bv~a +-,S@ Tj-Y$42t֫;kߔop8ܧ*ejIZ @K#M$-hm@Z Eַ -B.LOMNFA@?d$%DEz{y89:Z34 3S]$.PEBi +:ac$N hZW"hݾ2615Y6.n^>Aa1qI)i9yE%Uյu -m]=}\@8:.OK2@kyeֶHh=~zR*rֶ~Fzgw"p8h7Qk $-h!iTZ{" Օeܬ\&L&DB PW[]UQ^ZRT`okà[,MMZwn] Zu:IBa=iZ>Mh}YzhBKZ.ккҊnmcgf K+jj[::{8}\0_ Hr@kq 6YZkOZϟ+ BVk~°p8}~ -Z:i!hA I V9HS@Z߁Z +T2# !wP_[SUY^VRTeege0Rb"CC|==\lVf&n!h]Z -3hCK/+YQ :)$ +.\$u&@@̜fi@rtr4ffV+]PX\ZVQY]SW cIT&W/VjE:K-p@:@K$T*&,ZY[73 +p81z/kPI'~DRZ{ZrdfZ<9!G֖ʊv+'+Z.NZ +KZ7o h]HH֗S:h5hn2$22:~Bshm;k #hhY, k[;-w/o_ȨĤtffvNn^~AQqiyEUum]CcsK[{gWOo_?78<"&L1 ZZ^h,ϕRt; p8qۣAZ/)zVZ-$-ZE H @{RZ%֬B&L&DB PW[]UQ^Z\TLOMIJ   pGrf-if&ZIh]ii@Z'Ơu$ZML-hVt@PphXDdtL\BbrJZzFV6+_XTRZ^YUS[D*h-,>f'~xlT*zsS,=vB_:h=(kp8 >2Z(IK -$-֦Z" u@ ZPs CzhF:FB$@ u +-&fVtk-'gW7Oo?ظ4fFV+]PX\RVQY]SW cIT&WVVIhQEB hJA-g0p8~+*פ7$-ZE EZ$VWZs +L뫹3 2MrL-*{ɽȽ^U-ْ,ɒ{6lf7``$I~W-1Ɍ5sF%`x;a1=]m-͍ uUeŴ‚LjzZJ2VtdDXhpP@_A>֭;uYsN#h h}ZG>bh}I@ZgкH@;]h]A@@@ܒbeckA/(WV745utvL6 "D*h~-,e\PTY$~#^gIfp8pZJkIwo$T*BZh-#hڄ -ĘL*a3Ύ榆ښZQA~nv5#-591!.6:*"\ZN6VKs3Sc#C}ǏZhݸ -Zg:q->Hut i"uJZh}&^#ue`hdbjfaIȨx̬¢⒲ꚺƦ޾:dT:6>19=ZX\RCpZyz +%+J_IgAҁYYXY8pj/z"-zEHWRZ5R^^<i@k5.E#0;f1}]-Mu5Ue%E9YI 1Z!A~>ޞnZv6K 3S#CC]Z׮nB E@"@ZHhul  :jg Z_k- -uo`hlbjnaiNFТU h546wvЙ, ohX KFe)-YB"bR(*r,-笃p8iCZh!iTJi!hhE@lT" +>ҌU]YQVZL+Τ$%DEz{y89"hYYZueSZ$.ZۥW@kǍ?/tZк.hx@KO܂bemkN+(WTU"hutv#h1l7EbT66195=;6h^VrRZCgwgY=6p8ܡjz6HiBhJ*@%)ĘL*a3ZݝZ uU%‚,jzZJrbB\LtdDXhpP@_@ַZߐ:8hh}@Z[RllA+<"*:6.!)95-_PD+)+ohRC`apD$'&gZ K"@ +@KP^#h"VZwA p8w im[ZZT- +HkHFZ$Z3qtT,yA6A#P_[SUY^VB+*ɢf&'%FGEoP_1@>֭;uYsBZ{]h}q-N"h>}, $Ӆ=304215X#h99yxz h'$gdfUTV76wtu Й, whX KFecS'Zi" +R*֑Bu.ڕY=0p8ܡmWj + E@ Ik}B +i!h!io$-'3ScQxD(rXL@_owWG{kKSc}]MueEYIqQa~^NVfF:V|l VHP5BG{n\ׅH AZNju֦4:BK,hh]$кz]C -,m\\=}C#b9yRں斶ή BX"MLNM>-p+\$HgAz:mp8u.HZo"z}mMT*r+-$mzAknvzjrbL&EB7a3=]m-͍ uZŴ‚LjzjJRb|\LTdxXHp`@!@. kW7"uuuV ut )h]RCK+$nh=h#hQm@+(84,"2:&.!19%-WPD+)-ohjnm3Xl7ģR8@kHBkY$^,VVW +RZ[Ggv&嬃p8з_ii_ 5Zk*Rh@Z6E@kiq5IGŢY zدϧ43S4;hFc.1wwiJ RIw"M@@:O/t6Xx us ;8P_WsUVR\XHKMNLEh +TQ;[#V&ƆݻhhmY jZEC KZԄֲ7:Fډ70261Ch \\=}ihE S3ZEťeںs M[Z=._ KãcZ gQк{53#J%: bvhi9K&"H$D"-~ZWniiBK]Z-@ T*r HݻPZк}&KcRH(q9=M ZUeEyYI Q"BZ~^.N-@k?BkNhmDhhyhKkW@kV"VIZw [ZYuptvqs=ЊOLJIM/(*)-8]UjljAhuvu qx|H,hM^-pB>@K&+JB EAv 4YD"H$ZPZo&hQhZ*B!Z _PZкqBk5"E>34ՉjAh՞:]Q^ZRTJIJDhtwsqvt8jokcmeinfjldwc66R Z+^-Mi-MhhYZ[Q :DAeA!1q)iBV35;:/vqy|H,hOb94B@K.W(Z5E9˜~H$D"HyNTZlh֓yiiZҢu +@kb|tdX* <`_oΎ6Vښ3+Zy9YiȈА h!,LM(hhm6SZZ$A3 +Z_rZ_#ф_ʂO?Sڽue2SZТ@kAZYRe33-B 5;oQк<hIDB@huu\hkminl9*+).,HKINL@h +Ch8p9Bu?Ҁ7% /(h}ᡥDZg +Z_C[wh ~BCkB@Ke:zD`ɐSQԴ\ViYB\CS !/%%ֵ7_ZZ2\PT,!A8kK"H$DEA B Z(-JPe2}JKZ7o\Gh]hH%b [775ChUUV"r2RbZ'Oz{y89;вBhvGZ -Zh};:>w{8*5hmhDhh!ll5|2_PT\Z^qr ?8"d5кrּhM#rR/Y#hg=r֋W:D"H${'jiH녖I1J EK֬JTiZsҢu*@kr5,|ghՂЪ=[]u u*",T Z6-3c#}=~NZ?0bA Zhh1Z/:F]ځ:LAܒqVxDdTL\|bRJZz&BuVG^ᑱqe +Znߙ8{Y YY kAWuh{$D"H}*_YbC (iQBi-@kBhhm +ZW.ZRHqZ;;Zkk J +ss2ZȈГ}}<\hhYR: ڇڡ ZZZk^,h}T5ZZ͆&mhmGhhh",,m쏱u" (8$4Td4B+_X\RV^ЪohlnimхpyH"h]h]qSZ,}L&W(*C h=f+8kI"H$Dmz8R) +LкBiA)T" +x\BB[kKscC}B0?/';3=-%91>.&pcv6V-C!^vmhm҂@k"@@knhhYZ[! LZGhh99yxz!N!bS22s +ZUg"Ϸ#zz8\@(HGZh1b5z03#Jj9h=,htAD"H$i1!byhI֬JTiZhh]к4 |8>3IDFMcK (w {vłLWp#$j439r\]$?|_|Ъhdb##B|=O:`okceinFBKuHC] AK Ak@k9hm Ak5ʙZhKkXZBk&m'!-mq'gW_@PphXDTt,@+5-UPX\RFA`9\!aZ#7)h!gк{OZhz +КAK4g@p8_9J%MZ/hҒBkT-"h!i@Z$nк45rLF?@VYIqa@+#- +hz{v?u鸣>@K[됦*oA IKCkB":RZFBkŊ h7l%u@IYam]r;qЊOHJNMhUTV76{,68u"@Ӡк56& +Ebd8@KgYp8;3&@Z'RhKbP(CкO@ Iׯ."h=3q,F_O7@8Z:ڇ h(+h!u -$-Z֐Z1ZKZ 1 ZG"hBtf +ZZIhi74215sp< + + OLJhkZ]ݽ}L"hh]*;2h z%E"E@ 5~Ahaep8Kti.sRZRhMi=&%DBA@ I֝Rh]u< e}]*VQA~n@+%)1>6&*2<4$(tP 6SҢ^ +U2h-ZSH Z_T]khjA$@?08$,<2:& *,*)- b0Y.oA֥$n&EB=4h= +Z)cКp8pMӡR~51 ZhzкKB[HZ$._B:5rXL@VyiIQ!@+3=  +hx{ztqQAZAK2h}FB"h͐֟t֟2h}5ZCR&uH@8@iV@+*+ohjnh3l?0xvAk֍)h!gк56& +Ebd8k +ZzFBYp8jNҒA g~A E@k\"BHKё6jmnj,/hdgf$'&DGFNhw473164hH@ۙJ9RZohDZVRZK@kf1z;;Zu5‚\VjrRB\ltTDX(@ $-=! u5 +ZZ;塵Z +Z+ZA>Zp8 ZwRRUSh70265w$hZYҲ + +Z-]-&\E8wZiz4 Z-QR-,p8쭤Z2iMhzDC-$-)^hGlBAЊh Z"Р| +ZZHhmm(): :&-W7@+$4<2*&6>1)%5=3+'7U^QU][c0Y.oA@2 ?H@ 9= +ZBH,KD +ISz^ > p86 hiI5))%bH(uH[?@A2@hZj*Z9V@2Z:ڇ:C@k)hm"z +ZiZEwLh---$vӠ:24215sp<r + hZyE%$Ihuv.AkAk@( ZZcZ"XBB_?&5'hagp8X[@c-X$BCкO@ %Z\$UOB0?/'+3= phpt07512?{"nZ[6BҚ%+ZDR +ZHhXrz)g.Z(TQUhI7@+ JNIhWV h55u/T均q|fgRLb-X{i$6:j4j,EE.RT*RC;UTf2s`:h]QBM@A-,-YOg[EQEQߺ7V 2i5AZ -Zw8hP@b S Z" +ܜLZVhpVZ,@k*-I9h5/-ZC ZCrhKtZc8hMAk:5g|.s +h + ڵ{/Դl@+DaQJ"$hyh5ʠfZhXEQEQ߼7VEh&V#z@IZZ Z:F*)*+-eK/okm5w5в5֘.CZh}b!0Ch5Ar +5ZN׺{zZV$ >#yUF[V^QuA9ZW]gbU+@Oz%YEQEQIShqzi1h=uOV-QZZ'ʴRUI1u,C Z;H@+80r^dK sScFBk5Zzq$AkZ8hc25 К=gEK:8\-o@k#9r@kuPbRJjzFVv.uRjte啀Z._ŜA6#-YOgJzF΢((ޚ^%-=h=CKV%AuAmZW.s:{AAK)UZ쬌ԔDZ{@+hy{Z+._djޜـ4ChRBkAu ZGWa{ @ Z#5RZfZ6o +hm߱ЊӃcOɡuEnpЪcк+BZ2hj{mhu(((H녁^BMV Z +h=uA }h]A4V"@ Z;l)8h@ZZ3f&F ZxhԇZ_e ?ZuځWrh}C'IFƦ~~x2Zun^}7ZaV4{>@pbrJZzfVNnUXTRjueUէ 5кy Ъ(AwVZ,(( +i=K%BV=ŤV@VEN[V/r2RZ0@+`zo/u<;,AW@g9~Z_PZ5q䩀,=h9._ hZ>V`PH(5z:t8)95-#3;uDUі :{k9h1gк͠uA>H Ehj{Mhu(((J5&@EV Z Zwn Ђ_CY2hdgf&' hm9,4$(\5 К*Bk"o:֧2h}áA@ZCۅX%ZsZYη[hx) "x=h?.VZ._A?78h1hPN\ -rEQEQTZZ +h=uA+/q:àUUQ^ՔJc2hJv"@r桵tBVsZ- 3SZcEh5T ZrgɡZhՃ5քML-,Z3ZChZ1֞Ĥ#GuFWV^ɠuE%nʡ(AKt!ZEh=CA((z[Z/z&Bh(>.r:͠UY^ӔKNr2SS{Z1V8rVP@k&p!AޝBK)ZdAOf+5[-@k hԃVRjue Z 5кh3hz,A В;EtV"gQEQEQ=Ne6Zri5AZZ8hcЪnBuJZǎʠu0> hm6Z|}==\]xh9Ƞ5K sScFBkXꣀ O 5p%FI25yi@pbrJZzfVNnU(V5u^,ZASh=FEQEQ zz$@VVuUeEN[VZy9Yi)<ZcDFZAz@kUEv lmК&BH֨5ZJh5%FCk$q<hP@k9hEZ;wZ zJTjVW3k MLfb2MLbK$KFJoK4AjJQ@vb$ޙkS>7Fdw7d8Wx @BqV9^o0>ZjC aa,AI FZJUѠ3h3hn[Y)VVNh@kmkZ+Z ZsZerrJ5PpؚZhuBZ(h 55a$SZZ ZKZ!akZZDPh'J: +:3h]uX[ZZUh^͠շ`ah@k@k@+Ak@k+@ko3yh Nhh]]V%Vu`0VZM- 0 0meZMbh5AA +Zh0諫 *ZwкA<֩|&/7; +֭ h-hI5^aZe"RVڋ%h)ղ +zuVZllFQh9{zOhhh-h6vQhO$:F:к{"h=@^ +-Yf0 0 H/-%z =h] :'VZɇRhhmhfxy8ShrrtCϧZDZ ZhbZo3hcZ_AkZ3Z?Z+W6"Ku<#V!%ZY-,% 0 0 ð6ӡD Z<Z%CVaNu23Z"ZZVZ?f(5F 5C"+ ZˡIB+6#ZI=@GZJHLJNᡕ +hQhQh&V9@Z7 +-,)(Vyh|0 0 0LdZ8hOh뫫ZZ -VYi VYVC+%9)12Z?@;H T<ܩ@m^g%j%^B- 5 /T5gdZ.h + h +I{AhZZg.Rhu6 +"0 0 ð֚xUVZЪк%V1E3he:C+@+,$h5@kq`/Z?&Mpsu(@fW/B]Kz 2 Z +r9[Sh̠Ak=@k@+"r Z'2s4|1]BjCwj`aaZ@V ZDZbh]&VV:!־6z Z?ShMW@[>WBChŠ5zrhqΒBM+oF1h@k*\KZ!akZZyh'J:*@4U* dy V%hɝ0 0 P%hKd2 jJ].h桕Er8PB< Z Z Zs)J5`og3>ZoʠŤ%˭ZY<:rB2h 5D ]\=}'Shh-`ZŠB+:&Nֱ V.SZZWAeh ը +-OEhaaa7 +F),A9h]h':U2ҏ Њڸ~֪˖fSh К`Ze.@ <8iMhu@Z5:f1h2hmh퍈⡕C$@K+eZ7#@*2Zz:aaf#ԠuO Z:C+VT^VPEfRhz{yPhAk8 +hzEVOSh fвe+4)3hcC`|"֑4 +ZZ.1h pV9^o0M5:1Zaa؋_VZuhxh]":GUPh!J?Ck: Z(ɠ5VZE)VZhAkQ"hMК +Xh @+(84IXgduVRZ7o5CJZ:g!0 0 ð֜Uc$z +*n2huV̌"hF ĠКC5EQ-[ զNZ-AZ}2h j-g7wO/_? +Y Z+6"yh%% +8huV ZZz8aafZ2hUp"URAA@HC+AkKZZ(|}<\eĠ՗A7n^ZZ+:*GO>U@ˆAkZ3h2h0hmh:p0ѴtV63Z9h]BJ +-hCA:KV#B 0 0 {ZRhU/h0PhUr?\Uq|:`@PϽP*(IHA ^K/!BB^@!k}N$}}[kfuD^ Z;hmcЊjryZ9dVWЪRY$-Zh)*Z5hj)jDjVZC8&ph&h-AkA+)9%-=c +Fhe)Vu B!<=Zwк@+ZUhmHOKIN"hmڰ^VDbl ZC8z0huA +jzO*A뉂AjBV7V~F=5CkhZ[Eh!hrC˴B!*ڙ_XϡuZY&h"hUVZSZcG՗ՍA + Z@bV sjԭ׀՘A+ 0(8U.^Z8&f +Z*Rڸx#vZ@,A"V +B!d -DhaВB+A"AvVV䪕f&qh 2x +. ZmZj @Kh+Z%eVBAB?(i%hm$h%&%g92nphB!ouCA ˮuPVfzZjrR"AkeKZs Z8FqhۻVGshՑUZ+JU ՐT Z98sh"h-2Ak] +-B!uN,-ZZhm1AkAkx0 ZujJjVU;hUUREZϻ&h}"C"jˠՕՇCkQcZZ+@+%5-Ck?։ ZqhuIu h+hvB!BE=gzк.@-IZ'\C+6: 1F #@ +Fhհ.|KC>A[-A!:8(l(D |e+8o h%(کAqZɽbm]ZvzӏCk$TVZ 'CYB!*BK'-ouZֱ2YK ZsZS9FjIl.+hZOZA#ֳhȠ +W]@sZ_A'_9shst2uF Z +V>B!|(wk +UhCAAWh}2>֫^2֋fh=cSEZhAM>ҠUh(@Z h-dZzMTLl6Z;le +кh!B!3huGM h] heYBk)ɉ bc֬^ŠAw Z ZUhd2֛ВBY/XZ4>ЪGA!h"B#GshM'hcZBk5;V^9*A!BA$<:l *3h#hMנ_~T +z:h}Ze}Zo h h Р5A6SuuQ9Wnphݲ+hB!B!kvкeVfh"hCkZzhM7f4VZB[>C5Uh} @ ZML$Bk)&hmUB!BȦ2.KкZ3Rm5Ak1Ak6Ak!":>0A5_VyZphϡ)VzVV7V_f&:fZ Zu -B!{y -&-/uZkcD5Snh51@Sh]̡3hKЪ\ZhXZ Z˖ЊWA?%Zhv--B!T,NZк +Z,u@n#9V._FZ Bk5 jƠUzuЪ >26ВZh5bjՆA AAkIZsHJi,к h!B!Kh5BK:h2B+3=-59) Z4h RՅA V jUIZe zh@iUZխj aZbZh8ɠy+Z}0!B91CJnNZZ'O@kZKThMӠ5CZA +UUaAVc:shҠ5-3hWu +B!BQA<)ZKZZ4h2AЪ1.+[% j[@kudTtu*RR2t:&@lZ к#@+hB!B#' +Z]@N :VFZj +ukc"W[@kjLjPnZ\B[hhAZ +Ӡ5Ck> +ZZ +v@ BB!|'Gz`;vvZ+shM֠V{ЪZ~ZhU hUZmph נ5CR6OQ@ !B!]ZdhA }v +ڬRZ34h CʠVVSЪDЪPUЪj Z5FV Eh1@+KV-rB! + +-ChZc՚C%:VBZ5$hՖP@ˠZUh Ԡ5-V [B!z *nS+B+SSNКá5Q@Zh WPVv2IBTU%zrh ՠ5Ck5Q1q Zh퐠uZ%h]?umq|ǴVY2c.S!7!25"2D$)HD"%"VJQM4S<k5zgϿ=s%Ck=gerZe="""""eZ졵]6Cky)hJCk1F OCk +^::j +BZ5CBVEWhU@Z,jiVZ}25T8Qh.EDDDDI/AkWhS5Z],jiV= [UZ +f hMPU~hQ ZZ5hQMV;Z5RЪCZ-C +~Y5E~EDDDD.B ZshL:E+C + +ZU_V$AR +ZehU5A Zujn:zZ Z3Ze>NEDDDD/ Z;}AkA?hՐUZ S@@*HC:zBkZ 5ahF ZkCB +:f@hխSX2*QYB:)4lܤ++Ak`Z#F[5-Yhmٲu;-""""cQBk-VjZ AkN&Z5PV_ghJCZ BT Z' A]uРZdhՠUleZG)_: -fhU| 5h3ha6CZ͚4v um +Z7xB9Zuh4BkZehP5_RZ+UhZDDDD선u7֩Z@k Z35::fB /h] Z:ZyA6 @ ZI/A hw֒4VAk ZŽgWh-Q5ƛ7th=кZ9@DZ'hRUr. uhZs hم*;hv>rc@KZ +ouZD +:V(EMZ ZozZwHкZAKVBl'h]#gThC=ZJM Z%lBkZ>UWTh=@`:;^:Z9A. ZCwhM+.9$g AEDDDDy_HhIҲBk~.)f/5h} +,к&y:Z @yZBk̄_-CkO&?EDDDDq ZiCk lסu-Ό9.uֽ 5n42AMZK< )h}@4~VGhZDDDDBK += Z?)n# к_ֽB:?N:ZкZBh}B{ ~ZDDDDDE +5_l%h}B+ҡմq#Wh]Ze~& ㅠu к^r7hpqKкZкZu|~B4$g]dM~$ڠAk]@U$%Ak{z?0NCbZfZ*3hձUZY +bZZDDDD?eZ5ZY +g%h=n:o@"YZ*Z.z]ևBkZDDDDDhZ5h~0@+ Zzhu~8f5O@R yYu@+кG5hP: (~ CptК%thc/+Ъdhճ@*:8@k4,EDDDD.JItyZ 5ZܡUhZLJ!hZDDDD 2EZ&Z$hU:-9Z +>?Z9К@+J:EDDDD/;Z@kUhUU!nЪʦXA +b*@k """""2 ZEhQ +Z;\KŠhC#E@(h9|Oh tV[ Z-UZaE#Vr A;"""""E#m]Z%h,Wh0ZcBKr""""T+CkRul&Ck5""""" -IZV+C @b\6Z}@}HhUUYZZ!5DxdnZ{%%:Zݠh/m&AkZ=Bh -"""""s9hheZ +629 hQ>VZ(ցB?9:lEDDDD @ hʼn+(t8&$ TԳ ScxBj?Ns3ϳK#XcOBk:+L!$v,bCz:ZB `졵N1 $>>C҇緅֖zZ{Bxzh}Z0ch}|Zf Ihm-CX:=К)vZ֝`]DhкZ0|u.~Ch - ZCjZ Ba +-dCLh -,*nZ %Ązu1 K/ZBKh@ٞ]Th]NBb:ZB FBh ?Eh@Ah Mh<8-%% oBk:Z0$%FZGBkuB` ;Kh -VZ~x Rh=--%BKh -Z?Z0%ԄZZBKh@Lh -1%ĄZZBKh@Lh -1%ĄZZBKh@Lh -1%ĄZZBKh@Lh -1%Ą.' X;BKh - -% &ZB bEh=LB^h -ZZBKh@Lh -1%ĄZZBKh@Lh -1%ĄZZBKh@Lh -1%ĄZZBKh@Lh -1%ĄZZBKh@Lh -1%ĄZZBKh@Lh -1%ĄZZBKh@Lh -1%ĄZZBKh@Lh -1%ĄZZBKh@Lh -1%ĄZZBKh@Lh -1%ĄZZBKh@Lh -1%ĄZZBKh@Lh -1%ĄZZBKh@Lh -1%ĄZZBKh@Lh -1%ĄZZBKh@Lh -1%ĄZZBKh@Lh -1%ĄZZBKh@Lh -1%ĄZZBKh@Lh -1%ĄZZBKh@Lh -1%ĄZZBKh@Lh -1%ĄZZBKh@Lh -1%ĄZZBKh@Lh -1%d[ObgY0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--h_',`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--دcA֓YLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0:o=ehhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z_',hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDKدcA֓Y3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hh@ױ I,f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3- X`$vEDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3ъ:o=ehDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%ZEױ I,hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD X`$vE0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hu,0z;"`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--:o=eLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0-ъ:o=ehLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Zu,0z;"hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK:o=e3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hh~ βf%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-Yױ I,DKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-ъ:o=eDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z~|J`w-&ZDZբ-KDHH$H$HD\"iQ~("HJ{gqyߙ?<<_ Lh -aBKh -ZBKh@ZB „Z&0% -% Lh -aBKh -ZBKh@ZB „Z&0% -% Lh -aBKh -ZBKh@ZB „Z&0% -% Lh -aBKh -ZBKh@ZB „Z&0% -% Lh -aBKh -ZBKh@ZB „Z&0% -% Lh -aBKh -ZBKh@ZB „Z&0% -% Lh -aBKh -ZBKh@ZB „Z&0%%Bs+> +-5=>B`-% Lh -aBKh -ZBKh@ZB „Z&0% -% Lh -aBKh -ZBKh@ZB „Z&0% -% Lh -aBKh -ZBKh@?+V#CKi0LК)ECZB JZBKh@Z:+Z%Ah -aBkCk: ahZB Mh uNh@?Z|I BKh -ZB „xuZwtWY֝Vh,ZX֌Қ@BKh -ZBKh@Z}3 *q!BZUchM-5֛К1V ևBЪ%6Zd$Bk*Z[nZ{ԧu8m[[h-n֒fZhmnuFh@5CkZS6Bk(֊BƇBk MB fCk=Zlh=+ -@h WB 0zP9 +w=Z КYC:_kh}ZB{u^h -ZcZ;Tht +!ʅֺu3.M֍j#C`\Z_ۡ#W u3NU uBKh@3T BZP>CkyuBh΅3^Z+֡>Cky;Bzh.vi -Eg Br; -`Cz;. Z ,ַBkc:1kh]zMh@%MkWZ'JVhXh(f~B41Z#s2օXhZօ:0Z;Z*fcBl$C4gh=  cBKh -Z+`~ThZ=֑DhZocz+^%BBkQ+6/Bk`CtahݚZsz oUBz8%niUhK֋vh,Z߄cz +Bjh9#vO +BnMmVZS3ȽR)pQJ))%%H$"p" ʐ<Ϭe/}}=^Zk׭H hR ׯ_քoѠU:`&CbJ5$Fhh٥ZZCRJ @OhQƖ\hM"$J@+,-""""WRhZ=}4 Zb~EDDDDY?6hҠ5Q>hZhv@ZU heZUbVQxhmSAk~jlZU*V錃VjV7ZCCkyb*ZDDDD#@ZlhqAI܆ Z$ZMhUwBZm5̀) + h-VBk"""".9:.%*5E@kaAZMhUNIhvCZS CQu* |kVSZ%jV팅VЪZ7!oR>"""""3Z&B_Xh +@˄V37:$@_1BkEVUdCL٬$@UhAkFhmZDDDDD)Кֈ(jhe*jh5Vo1 Z'yAc`j ZUV*^h V[Z=CkAuhQZ'ÆV@hZ2hUK1Z |VZbhUZA F5](bAkOIt +Q肜/XZ5hMwAk6-ʛҥV9rhРZ@ZCUZ;et* P?: h֠B5|ҝeB|:C:Z'I ZeVIa Z CzZץZVXh%2h]+um.hݯV{F[КU@[AkUZV{%wA6AOhݨVFJh@h- +}@2Bk_Th- X hCEZr(uc@PzL&^Ԡ h 75>obdZ3Mh- ZDDDD +-Yᠵ9Z Mh459bxZ=nC5СX(h]к\ +lh$?VZGJ hQ-ZNgB#a:~hu@heC&).Xh=ZКSP8/vHK hQf "Β@kG4h+,Vz3ZWAv%1[6>L֗h26-""""R M>h-@Ԡև6zـ3A ֽ94h=7)v-""""ؼ[6qhBkMz#ZiЪ}o<ҜU"I+ndzZhmAkQ 2h= +Z7thrAh] ZAUZD^h}MhmAZǁ{qCZ݀֯.hA{/>@]ZAZw@h]CB Z@h]V٨к#Uz mh}7nhCg_0A@k{:( +S1CkZx Z߸ z! + [jبZo,h͕@O Z{7*c1A(*z)\ ZM4qozƍ*uKI١uK:T@O5h}aBkI~hZMZhZDDDD%ZZ4h֏>h}ASzɄ֓:Zjк8N1JZWкJ93 hAuZE֏^h]uhQZ'CCkm Bclh5u_*h]Cu֙u;c;6>U\֡""""9+FhJAؠu[uY&AZW:#5$Zth͏@kq:(Z'r Z#К󼂹sfiК>6: +hb@YuЊZlhAkZ +Z+-""""J1%Q +h.uZ}Ъփ>h=V7Z#5%,JuXiB_')Zc>h=V%**u VZm:'5ָ̄ y h0 %Vȡ3=:ȡZ^iyiQȷde@9N9VhZZ3 hOʛ0΄0~6: hQB+ۀVu^BVЪmB~MLhVo'FȠ5;>hѡuhQ:" + ΖAkZmhu҄Vƹ ЪCzq@祤C\%JVe) h5 VZU*tBkZ[瀖.-EDDDDPЊ8}*hZ=T@Z@ZhӠU!h53JV[6XtZ\VZB5҂Z]jje@ZuCBrj.huAZlhj@kfZ:vu\S@ҧP:% h@kѠ5ST Z h kCZЪ*S6+K *h(^h7>obd Zs + +繠M6v:V +Z>i!"""" +U*R@ZZּ‚9&O?nZlhנZ:rЪVVV2ghV 5ʇVsjۨRhu߂֗h"~ÀZ{Z'CC i:^8ndUYiýޜJ-4KK41M3MS 35q!!ME@Eqb4 qg{^>yBU ;ZJn:ǡuA! hAk +hO7 +j~AJV5sh1ii\V[Z~ ZZCZК¡55dZzh1IZBB!*ow kΠ+Bcǎ~Dd#qhMq@k +~ Z~Zujs9UhUV Z[C +4|9*Zhr@돣Zh +*u B!PEZ,uUV5. Z[Zš<|)AkshՑA 3hU +ZU+8*jՔC˽m̠՛55YhE3Bk+Akκ-.-@ !BU -Y.@v[@+.6zeZá@@ꭃV{-wZ hխЪeVCZ-joV_ZAhM#h!h-2@k@ !B!;$h]( Z9Yi)55 Z}AhժЪ#@3hyzy +Dơ2qZh%R3uuAV^f/( hqh[A zB! Y9KV**"hmM $ BК41$CkAk-_o/O. ZLHVJ-RՌCAV ZEhv@k&Ak>2Z".K^i!BaŖZrrEh5V +e Z Z3-B?VZThjV**&HZVЪVcZ$@ +-VZS Z Z "VD3hmPIvShZ%nZ!BU6hU@ NBkM9ٙ)bWDE0h-$h&hMu@+BZjVc j[BAZ:h=luzA9Z/HЪZoA>:hMpZ"iuJy Zh]*Z-B!TrZJ%ZUhBk]@kZ Z}tꠅ2^7VM Z/zAi7å@egYB! h=&B)gzU]C9rhM'h%h-AkZ;dh? @=AK/-@ !BU,%:뮡uRց2v蠵VZc9&h}}wz*'z%hB=V Z3h}ջow=~ ɡ53AWVزp +6v2hTuB |ݮU5Z7 -H !B#4hݐuuU-ݖϡuA + Z; Z7defl$hNLΠ+AgdA?ݷwW>&hn +7\3ZO:+zGTh} A;'hV䊕122t:tX$-srh@Z͠eփB!JYhB +h +: ÇC+6fZ?C;7 Z_Lw,Sh=YZ +z +ZojAS dCkD_ZN.ZGdiqhB!߶*"gQE:~#h¡5Ckַ Z_j)A#-޴֋C뉊 +B}O JZ8f-@k3h* hqhuB!BAZZEZyΠ[VvVfzZj2AkaKZZ38qh}B+>z)^.)ZϻUZoe@GWn>9Ck +AkQV页 +ZgZl*.KAD[*2)B!w k;Yh0hIeZ6 3Vڪ֪8 ZQh"hM5rpV?->ݼzA][NUC+h+jˠYVO1Ƈqh-p@+ZzZZ{ :m+eQZoB!r+V:m6ZhE;CkA+d1Z Z=Uhufj +^Xzn%IKVVs Z*:j՛AkV$9EKB5J"hgdek +.uM @ !BU2uIEKhUBJZ(@+t"IZAZzkQ&*$g -Ъ@Z@ AZ}Uh +КIКϠly U +6I.CkZdhgʷzh]кmנi!BqBZ9e:>Z%hmRA+>.FVe Z Z399kV{VhMֿV Z+@3hRUCVS3hu՟O + 5Ck*Ak6Ak1R329v-IZs:hZ!BoVZdh<ց2vphefjBBlTѣ Z Z=|}<=ՂՔCV=ZA T(hUPV ZZZhbHʡ568dAk +šaV'YCZhBX-UZw\փB!䚳BZsh:(@kIh.V55!$x,P@^:ZPV -7-jĠL:ha̡5Ck2\Zb6edfI"Ak\Z Zg9m6{AAHV=@ B!B7|uZ%"Zv-?C,saZ;%hmA+!>VVdDZ9Frh fꣃV1h5UG -J Z5jVKZe0I[+k41j4&S.fؒXbJGPc1[fP"sgb]8s!&*r1ٿvdE~]Ck 9ZZR%hiuZ7 ťEТ(({h=@Kt!nAZyR%hE6phrh͑5AcHA]EhiVg>d̡iqhNV' ꡄ @k؈=}0hM /Z hmf/CkA@dXKh؃j:Ch((fY*hթ%:!؃@Rl*fAk3Ck`@k*V a:hEN2ډj-A j2zY -&-Z6Z]eh?Ck +ZZ!ZB#u6 Z{Se0hK:$@8uVmZ6[eUUuM +ZTIZEQEQTSM?^ eZ*hTWUUlnZu: huHV>Vƾ䤽ZeZ!tq*h \]+@VK zKV VꨇV7@ -5A+CkJ@k##:F@l)QBy5A}h"hQEQEQͼgw=h3ֵU:N @+&zZɡC+AkZuꦇVGhjh;@K'AuGjoZ 5|(Oo?@@k2֬9sB5 ZuX  +h n }@A㡥֋((}gUg}_tкŠuU Z'hVAL Z[5VX貥9!&Z~>ޞF4^VwjZ?Y T@-@6mJZ %@'gW7w@k +Zi2Z""v Z)i +M#N2h]tAK +[eeUu5֯"*UV}h((~jCZŠU]]UYi( hd%B Z'he- +$h$'Jh"#–Z dhMƫ5rWA3Ch} Am6Zo)fS֫z+Zl@k1*@k3&VbZʡuJ&-<ZA A((j=ZOSuG-8SZ ?7'[ؘ&@kb@k65КW +hVCKpBfw%hqiIC@F{z  hMfZZk Zq {RRefiu:mZhըU,-ch((gŝV +Z5Zh0֙ӀQ-2$%Ic +hÖhfZSc}}cIZ"iQEQEQM=C1Y, Z*ZnZ:s:V,bcvZUr@kCf͘> p-w7Wg^"Z-5bzRIZphRA]huջO~ SBfϝ`b@+Z hmh%ILJIMh+(,2-2ZDh@KZ6Ztz$AN zEQEQ\rz%$h=2w _OQyfҌΩM4~%%j5JGa *iV.r?ܩXEs:K}^|wp5s̼C-kzк @4VjRQQ^VR\hdgfZ;w$ZqVZhXTZ3ڠ5a1Ft:#BWsV@GD`- - Z#%h[XZS6vN,r-@+ +ښ Jсa@TV-VƋmbuAzjZCEQEQEu:urguV=hݗuA jkW奀ahZZQVHp? hsh-\6&zSdxXhpPh.7t@kx9օ֧>A@JhaZCZˡ#k[;ǹ/XxR@k +"8@+ ڛWPhZ +AAC% ZuAVZȠ+&ke-EQEQ={t\S-Y6h=4u3$h](@AAKTTZEVaA^nNvfFZ^@+ Њ"@@k +Zdut!ч'Zh} @}F !!3s Zj/u7ZQV@k:p0UZ^QTU1h`Ъ?#B? juOV i=zHZEQEQ_WsVЂYV{"Dhκ,B uAJ(/:־)wZ[(@+$8ou^kVrw[a֤Vf~!>>4 ZLZ{ Ƞ5Кmmcg4y.Z1"2*fs\mIZY9#EJJ**jY-Z7ZjJjAg-EQEQՕuR;3ZOdjP-5m@uCh; hdЪR)*+JKdesh%'mK9&*2bcXHhyph,^yl@k*eɡ5F[ZtCh-V/Z}871ah ť%Bk'[XN4Кe+\-O@ +@kWʞ} ZZ3hΝׇ- j+&ZEQEQTWEYEg=91-, Zwn к hb:.A:x ?A+#=uߞ]V hZ'bfZhN?VHZYZLL#BZowteBIK֐ZdвZsll:_e cZAX@k{]999 +hW* Z5 Z mЂ Zw KuEҢ((WF8Ug=84u3к @4V RQYh=rC+Ck۷%l7Yc%esmmZ-+K 3 Z8 cգ}h9+Smh ZÆ  h`j&@kig҃rW7@ #7EoIHܞhMM+(K+JV-UϡuIA juYִHz(AU-#юZEQEQT=5YZhJz(AEV7$B9AK"Z-RQQ^VR\hdgf'Z1ћ"-?@ rs]Y3O:E8@kڠ?3L4f6hX2-$4QBQzw,`͌fW­ +>sν{"w$Bk Z#6@kVN +Z:zL-m]IhZdVvn@V{gWO/@p!@kl\HZ&hКR4@kVZ@ K p8({+gZ +g=gѡ5E@]nߺ@kAK(s9l&@VuUEy)@+/7 Њh|Ih8;:Z[Y04٧u +6,h-AkVVQZG@k:v!hE72VQ/o_@`phXDdtl\BbrjZF&@tqi@70`8\@85zu:z%K$R hzRB)-MҚY0p8pytFԜtZZ,r@K&J$bZwԡu2@(ְPrXL@_o7@UVZ|:-c~}] +ZZԡ: +ZZ+ՠ'H/CkZBk;@k7ZF-3 Kk;{G'WwIV@+&.>19%-=3;'/UY]SWb\_8|,ZW]H A IkbrR$KR\NBZh=!L Zo+-L-p8܇j-}fZhB"%ˤRX,Dк@ 9kZׯ]%uAa!eC֖JVQa~^NvfzZJrb|\LtdxX@뤯@ enڨthC>ZT@K%6h-m]=-5hyz9q?0($,<2 +hWVQjh1Xl/@:u HZn"u5A֔ +)h=z@hakp8>DoxR zEsSКV Z{$Yo!g u"9-aΎ6 +ZUe%ܜ,V@+ +w1oO5h h#hh Jh}IBtk&hq҇'4h!i}9 Z_+Z(h>@됱ofV6NήnG<ZBB#bbRR3ZEKJZ M!BQqnR@ I AH,He2H EH!HK ӠR$-l-p8tF^ҠSY-,L&H"wкuS1-尙ޞ.VsSC}-@tQ@+#=5%)!>6&*"<4$(@󈇛o&ƇZ$~hDArZ*Z_́'Zӡ/Hh}EBHh} Zji#ua :~ ЊKHJNM+(hUTU546L hh]rUZHZZ"X"rZZYi={op8M-Eg4g=gB"%ˤRX,DкO@Q+Z <.d Zj*ZyYiI qQa-5@!ik +S(hGW+>U +BҚ֏[ho`x @Q/o_@`phXD$@+*.- b\A,օ]AA BR ZҠ ^p8p}&g9YJh=hI ZZ#EAk.^@:q,@VeEYi1@+';Њh9u􈻛)@C}= +Z; hm6k +uh}4CkfhAZG@knhBڋoeLB{?08$,<2:&.>19%-_XT\Ъolhuv1Xl/@:7uiHhh!iDbD*hҢӠYZ p8Y/R@ GJh)ВɤXuIh]B9%8lchX_W*).*h$'DG$hogCB@_Ak/.ֶjD@kUs|h9CBksAK AKet’-Oc>'ZAĤ̬VyeUMm}CSsk@`ds|pAk5~*@ZZ&EbD*jКҚyialp8z z"5-\&Jb$}r*\h"h |.d Zkk*Z9Y)I1Q!A>Ǽ=iв0351>lCB >Z@kd@k) Z^ZkZ4Ak@k6-ÃFHhY;89yh + h%2ZKJ+ hwvLsw;R:S"ťOHBqwwwwwMv8Ā5~ \~w7+ ~=КhRZ\z$J Z][JG +Z6PZ4+@߲ڱH$D"H;Wd\ :8K +Zk'Ybh=ZZ5;Кhq#,BA +Ghx{qqr03MCK[AB@6-BiQ'bh%9 eUu M=||BB#bbRR3rr KZu ޾ 5Zs4~Kc*@B! -ZBh~}^Z[$D"Ho'c/t֯ +E쬟Y(g +|> ZEh=AKhhZ09@h56!J +ss2SZ1Q!A>^ +24Chij(h]AhAK,1@k -t֛Ғ.Yh/(h},Aa1@Z4 -%U5B趉WwVB+"*:6>!)WPЪoljiEh3X#ѱq]rBiVZ\/6 !֛1D"H$i^o`Y46ZϤz*<wgA](gd54Ah45TW" + rZI QA-w;N6Vf&Z:-5U%Uօ4FA@0@ZSH +ZBkVz}g:ޣ =hEh헇HkZ'OккRFhii[XY98: }CZq ɩi9ʪֶ!5к7CAZ(-HkumM -!BKJZ"hߒkRK}$D"H7&噵E9K -ZB1ZO(h$ZZ|HAk@kf twv675TU r33Rb##Z~-gG;[k+ sSc#C}=]m-2@@" S'ڏ+ZPz OZG)h}.g(h]h}OAK]S&B@Zn>~!a1q)i¢ + +Z-m]=}!&khz$ U#@K,_ Di(iВ"@}T$D"H|3KY +ВrZ,8K(y\.8 8kZPкwwzjb|l=2Dh55TWV!r2Scc"CC}}ZN6Vf&-= ֹ-uuu%%v; +'"hmJ -%U5-=}C#h{xy#C"cZi9y%eU5 Mͭm]=!&khMffih-mJHkyeB ECK,- v&-B-D"H$La$98 %y<:@k4$Z57;Кhq#,c /';3# pw-m-M 5U%Uօ46%qhS?Ғa1Z - NuuM --m]=}#cSs +k[;GgW7Oo_蘸䔴tV~aQIiyEUum]CcsK[{gWwocfsF&&Zs BiZkbh ih ""H$D"+;kL,ZB1Z-p<ZSc09lokinl(/-)*Gh$'&DGFz{z8;:Z[Y"TZZih: u uuP-Uh풂DZ=hEh?p 43.~}}Ii{צRmw6Iƀ1{=l0` 6fӻkC 4R{%RT|?۱ I\O-3s K+kmeU5 Mͭm=}hD,&)jF= Z\Bк 2@ I A Z$GHZHi=62p8ýw;kh91, +ZGYZBh#2@ uAki5Q) tL" }=ݝmM 5Ue|^q!悠ef1ккBB9ShucZG :LA,*h/qօZWZ7iVtmkZQѱq Iɩiٹy"QhX,IjZ=;7Z^Y%AZ$@ZAZ@Z#NZZۦz iakp8^k{>e m +Z~D"pp@)h- ՕeܬzZTeQxX4(A+*,fgf&'%FGE쀖-ɰ[Yn"h] Zg :#RzZG>u齠u2@@9Šn`l\\=}C#"cS3s EҲ.-dtL6>RMϨ h}ZHZu&@KChZHZHi=>M-l-p8i݋YpcYYZZ-hmY;֝9̴jjR11.  +:Zj++JKxE܂ĄȈ?_o/wW'G{;[aMh]h]N:AA&zO-iAZ(h=Z_htk&~A+>1)%5=3+'7-*.ᗕ#h76wtu CdL*+,@kq A.)-Z@Z76Z[>DhCp8{qZ;"z%@kuZHgEZZhͪgT)|B&GDCB@_owWG{kKSc}]MUeyLOMIJꌠf1m43u:h=qSzh}t@hag/C Izh}) -Z}NAKW-s K+kmk ZQ1 IɩYٹyna1_Z^YUS[/ŒQl\TճsU#EA uo hAϔeoϒ־p8ýߟߌe m~ 8kzhAkue5?7V)'qtT" +}=ݝmM Z|^q!鎠`of1l,-Z_gOAc=ާFzZzuYSh;OB +@@fiEa0ٶv.n^>Aa#c22s8Eں斶ήdtL6>RMϨ,@ZF"кhmiBIO~AzZ[8pWSiz#g8롖 4[ =-,#hZw3ӪIĸllT<2<4(lokinl(/-pr33b"L`gf2lV4 ZϙBOtHhkɠuZi!h6@1ZZ'Ih n2YXѭL_@`pHXxDdtL\BbrJZzfVN^~_VQY]SW7 FĒ1lBRfԳseZI A Ik}փ-jLRz0p8p\OOSf=M9KKh4[ZZ,ZO %ܬzFR'd1xD4$ vwu45TWVKy9Yi)ɉ q1ёa!~^.NZ,&ÚneA3uuA:uu1#h7ZoAk_^ZGu齠u2@u’nmd]<<}BBoGF'&gds<~YyeUMm}CSsk[GgwO_@8(KFqbRh/VVvB im4}HIK- ZHyp8{y0kZ:gB"8k +@ka5RN*2D<, +z;;Zkk*B.'?7'+#=5%)1>.&*vxhHPŴ[ZZׯ._ArZNA ~}?}q&KbxY.{ @{{!$Bh 0vr˯ml;]Kߟ ں#^z; ΡuZ':OBK_Z!hhQ̩4K=_@`pHXxdtL\|bRJjzfVNn~AQqiyEUum]CcsK[{gWOo khxd3>O "T&WZ"EJ Z][h)Uj9@K'HZڇp8ph_?s9݇95r@kYZZh!hB"=@kqaˤbP0Mp9c#l@oOWg{[KscC]muUEyiqQA~nNVfzjJRb|\LtdxXHp`+ݒF57 h]# oلֹMh|e(v=i ZhF:G@  hhS-, -'ЊOHJNM+(,.-oljim`C#8o/%Rbfv1 iBZ^iol(U*FEJ^WZAY p8- ~WZgB:oYJhYgDB%B.$ob}]-Mu5Օe%ŅyYI 1Q;䀠Š[ZPM)&n\GкxAZ_EB,@Z uTZZgY:h%ZF:KnݧQ-ht`PHhxDTtl\BbrjZFfvN^~aQIYyeUMm}CSsk[GgwO_?s=4<:OM ELz8-$-Hku TjsRZ$A:0p8p[HI,Z"A VJp@krZ'ZZrT"NO''ƹcCAf_OwgG[ksSC}mMUeyYIQa~^NvfFZjrbB\ltTDxhHPNR#hDк|i'#3$t:}Gۡ{>ASN h}\hݺ 2153Y2m\{zEDF'&gfWTU546wv #c?%\1ZX\"㖴@Z+ uJ iI[?jZ=8pݜ^2pߵz9 A QTup@$@kF!I"`ϛrF٬ޞƆꪊҒܜȈ_/Ow.NvV K @-+A -N:Z"/h}L@LZ#h߄֖Hh]CкТSit+k;{G'^޾~!aQ1I)YٹyEťe5uM-]ݽ}L{hdMBD*S=h=iCg յ5RV#hzڔ+CiviJwd-p8u>Y:YZV)Zkg-,}h(dRX8-Oƹё!69X_WS]YQVZ\XڊnIQZwr&#h}:fFƛ:GB w."h]к{τbjN3ml<<}BB#cS22s K+jj[::{1?%R\К_XDA_ZZ :HKRkHii!hJ6iZ[8p`{|з0K788 A 9KZgL@KY? h-.rT, +qkP_[SUY^VR\ᆠ`okc͠[ZPM)&n\Gкx-h}5 sZO266:y:>@w;ZZi Zhh%Kn"hݧQ-ht@PphXDdtl\BbrJZzfVNn~aQIiyEUum]CcsK[{gWOop'xSiX"+ffZKg UֆVZmzցp8p~K-=g!hi46Y,8k;YK\*S .gtdbtu476VWUde$'&FGFxy8;:X14 )>M˗v@/ hZY@K#pOgZ`QZZiieDB HZWnh[,VֶvN.=}C#cRR3s +K**kZZ;{졑1$jZ(Her֓_WVZJwSkgj푴f $K{)b/! @u ;v +! 8{|P쪤!Ҡ/Q˸P( +BPCØ6: BkY; +\&J"-]asi:mr|J&wv675TUdgf&'&FGEzCh]]NZhݺiZ_u @D?* +ZgF۠uZuBD - K++ҐZ!>sp8cqx7OR3rr K**k[ڈ$rWOo0e:>A2Kˬ/Xh=yLZPZ/R\؁ڗ;~<\Zґ +BP(04eY?N,-vrL*چҁֳOք>Z^b.3fgSq(exhL 476VWVdehAǛwa1v6BhVBKYк +e:wS!Nh@ZuAZWTu.# s{z||C""cRR3s + +K+kZZή޾ +ulbFe-0YlEZu5HK&+% -:ZH\( +BPXw:k8 B 8K!ɀYZ/ @kC&y\\cNicT@_owW'X_WSUY^VR\XCtwsua0vZw@h]NZ~֕}hBh]ЂYJhԀ։Zguu@Z@Zк~B}-;{3E   OHJNM/,*)-ohjnmk$w SF'iS3s K/X6i@ Jk%X֮ZZo?M=:P( +BPЙԻ=]gi02ꬷjg%ohz -5᪀嬰fghcnrgG{[ksSC}muUEyiIQa~^NvfFZjrRB|lLTdxXHp`7uv8hݿu'%.hYuBK--=hKZ@Zкy BCk[{G3w$xGDE%$&gfUTV546;H䮞޾Q}z1\\f9\@k]\GZJk -X"rŎJZZ@ZWI#Y_Zҷc y BP(Op,MglY?BK\.J%b1pphm<.Z^d.1fSёޞ.2X_WS]YQVZ\TMpûG{[ n4кRB~oYZZ23*h}Z&ffVVZW)-w ;b8@PphXDdtL\|bRJjzFVvn^AaqIYyeUMm}CSK+IP'if--23t224M$[kk*J r2SSb##B}}<.8֝ZڇU-++K %L @ܱS: :к]к{@@squs"GF'$%edfWTU546;H䮞a(u|6Ee/0Yl_H @ H+ m iOǓBBP( +B} ~!e鬟8kWYYZ/v3-prج%ER{{Ȥb[KscC]muUEyiIQa~^NvfFZjrRB|lLTdxXHp`qвкwB5Mh} +ZWtuAZAK_ZuBZ': uVZMLM-,-.+7!?xdmckŹ<< ޾~A!Qѱq )iY9Eťe5uM-vRgWwo:61IO0晋K, + +E@ZRJ&뭭mX"rŎZZozoXZǥak!mP( +B>RF~seYzv֎B.Ix{ @&t66DUo+s{fH@EQܸ Q\ """""bIzN{iFqiOz=ch&W|?jI Έ1.b 3zΎ榆ښҒ̌䤄ؘHJxXH090ߏKpwsqBEsh}ZglmmNAuhz;hig}ha2i- -+r M'BB#(Qѱq )iY9Eťں斶.ZOo_0k3OLN gĒ9lAXRԚ-;Z_J @ J@Z~z-g&zaUZvBBP( +BG\>c^8YZ?Ch܄ze⬯^Үh*B I3©ɉqw3uu476VWUSK +ss2Rb(!A@@B벳5h}rB90g@ -`:Z6vvNNZ0hJ BU-W7O/o_?)AOLJIM+(,.UTV76wtuLO +EYt^&_T,5PZ8ha>#Ci=1J)^Z0i=7 ^Za BP( +i, 1瘳'Yqzp@K,h\j˪%Ţ\6/̊ESIf1}֖ʊ2jIqaA^nvVFzjJRb|\Lt$%",48@'x{yzh]e, Z lm NA8#8hw=в.-3h6BZ'͠uV- -h]u:;G + + DF'$%edfWV745utv轌agtǟfĒ9lAXRԚ͵[@ZZ_(Mnk{{gJ'RZ/-^BBP( +BY>2qKKgfY?AglootY΂z!nԮh*B I3"76a  3zΎ榆ښrjiqQA~nNvfFZjrRB|lLT$%<,$@#_кxZY3hAZuBN;8:hҲ%g.n?)AKHLNIK+(,.UTV76wvz}a{O +"D://*evH0hI{PZmIǷ ̨uI[c( +BP}78Ok3wY?9kK 9 欻wngjW*bQ.JfŢi`?㎲GÃ>zZR\XE ">oOw7ZΗ,'ZglmmNA(zh}֡Z¤eZ1huU-W-//џ@ + DF'&gdfWV745utv轌!&'SBьX2'-KJZZCLZzhAi}JAZ;;-ziPZ[( +BP Y/q;W g=18tp-C 8k@KQK +L:'ψS >olf1tZwgG[ksSC}mMUeyYiIQa~^NvfFZjJRb|\Lt$%",48@'\^ wZ1h9@=.2H#AZNNZA zh]M%C)Q1 IɩiY9Eťں斶.ZOo_0s='ixvN://*eF +Jtm FiYPBBP( +Bo|ue0wtkgmot{ze/VJX楒YhZ(@_oZZ\TI  &o/Ow7WкZ\sZNNzh@h؃q ZGp28?ZFhA$BhiA%gZ?)AKHLNIM+(,.UTV76wtuCL'SB̬dn^ W,)Uj͊vuֺ^ZxhaҺHk ]LZOS+zn)~BBP( +Bs嫃cK̝s/zg=kppC{;kڪvEV)dvF$Lyc\g{:[[j++ʨ%ŅbΞ>0_$s_4fO^$,  ("d:Yt.v˾PdQ3'y3'?7'+3=-%9bF04*J +!@h=Zw@hݰ@ swкl: Z>.3Ah]+<hieZ>Z~Z"L #"YQN7%5=#+;7#q|RVͪ5 Z~ɰb\5o<҂VZZPZ/_i}YZ>B +BP(ꨎڳa+gjv֏owwwghgAh8-ଧUaI.hճibR. Eޞ~; /7;+#=5ÎbEFia2B6C, nкi;h]:A+hvǀ#en8kZ7ЂҲ@ -")F3",vtl\B"_XTRZ^QY]SW- G$ұ bJ9R/huKim}@YZhY{(@ZiP*wvڧQ:P( +Bx:(¬gqY吳6^CgheY6LƕeÒnQ0?V(1dD<48 twv45TWVdgf&s9ql3NQBID>8(@C-/2C&5-U3: +Z:o% >;-/CZh !P2J3"蘸NRrJZzfVvn^AaqIYyeUMm}CSs+%ÒQL>PNfNdX16b҂"--LZ/~0iSkϞZN[- +BP(Iή#u=f}~z9 YBhazfZ5:f^=V*&qdX,:榆ښ‚쬌$NB|\LtӨr() +z@{v.Z^Z:(-вJ,&- .@2; uB H }| !DFGD21q IܔԴ으¢ں^[' G$1ل\15=Rk:ayhZ[^ZJEZ[[;;o~>KˑZ[\( +BP{ީ3+N䬟lomY: @Y_hg+nQSf ٘T2" zݝ6^KscC]muUEyiIQa~^NvfFZj +7)1!.6Ō(d1 ZwnCh] .@>ΚeuI_9xhr Z .A Ah e'-")F3",vtL\|"_PT\ZVQY]SWkwv z"dT:.O*ӪYfA/5/1i@"PZ޸oPZHu\k BP( +u|ǼIJY옵ߡ~s7Y[u-Y_hVˆ%NSϪIl\:*}=N~; ?7'+3=-%Ifp5J"AZBh9 -k6кb Z0hq֩ -iޗKhYuuB H0@`B %S4:#"ŎO$qSR3s + +JJ+k[xmnAop@44<"&)jvn^] +յuLZZ_H @ /^DZԲSjX[r BP( +;mtx:*ˁYβ2z אָ0gW zݢV3?7QN)1ddxH4 twux-͍ uU%EyY)$NB|l ;Өr(1 + }@{v.M-//OU-i[hv'y3.CZ8 nhi9`P0>H"S¨pF$3&edfUTV76]AxX2:6.O*39͂vQdX69HJkssk{{gJcZGY[­ӧ^ +BP(s38(Bкaкdyh -bҲ@!h]A@:-3K BZxJ̿دӧ4/4g$1Й}(*""x"ފx( (ޚfgҷ=6mng:io{|L촿_n&/;'/@PX\RV^)Պ%Ʀ6yKQi:а4j['l3sť 71i({@Z_C($iBjX [ +BP(Odd_Hz Яκuhκyc8kc}ueyi1?7;c[̣&Р^{T.EQZ/׊e%Ņl^&f1)DZ<5ue-wg:u@$ܠu;--Oh~ Z!։ Z0hiA C"c(ZR2ds2|~AaQIiyN m]ݪ^_77 GLc Դm>XX\ZY][߸u$?¥uJ~%Q Zϳ_m!tP( +BvoN™Ĭ_Izg} uwYhaڼڦ1ӈqȠkԽNEE$mTW +KK + 9YNiݿͷ>|P;HBP( +gwk>VS<>7;9,-g@ :p҂c>;c[̣&Р^{T.EY(kE"AA~^nvV&NOc2Rɉj\,%@+,@}@7!h +:,KgrhF!#$h +u@ 0h]C'$&%0RXlNF&/;'7/(,*)-VjuiUޮTvz՚~݀0d1-iی}n~aqiyumHkk.-3BZ_]ZZPZi9EaV4 McɩYcaqyJ&&-.i$i}CZcC(-'piOvOm!sP( +B^8?龝~,0f=œ}8 gœy:keyq1oÆANS]y[kQZ/׊eE~^nvNg1SSɉXJLTdDxhpwh6sZO@h;*--Oh~ Z!"uB+@Y- - Zph]|@+,<2*:&6OKL0i,6 +KJ+Uq]}I*oWt*UjMv@o2̖ m>7X\Z߸uCZ~I_iarI!-Жn!vP( +Bg3%)pg="9 0˯`rw--kYK9mz:a1FC_Uu+;YN\#V +y9ټL.Jc2RIxj\lLtTdx֕˗ph¡֛ZgNhBh"A0A ZzigyCKZ{]]: +A$- --(-' u58$,<"2:KO%%LV:'UTVUjŒziMޡRzz4Z~0l3OXm96!-->ֽ])-'~ލZ>剭 +BP(~ }Sì fz"E8k{k8km8k1gMOY'c#aà^]y[kQZ/׊*+J + y9Y3Lgghvv/if}~045tا1idx0hԪeE.k6׉E5UBA9WZ).,`rs,*L$dgC+Y_JJJЊA+ZVh3AhBVZZ@ZZ@ZкA+=#H"ShtF37/]XT\ªjQ^"m5[vUgWF۫4Mqfs8\n׷{֓K JHi}V@ZGQ+Z؊qą4BP( +/(o( +Sk;t֗AghrO0gX[]Yy=nׂ17cY&-QӰ08Яj՝vU,kJŵ*a_r9 :-J&331hAg +Šu@+@2 AhBL h_@:;i: u. Z!.%&%hh]:;@ZZLBѳ\V-ʪN m[mKӣ Cy21i9܋GqiAhEHi}"0jiajŰVr BP( +(Jg$Bɬ0fa΂NjBՁpǏBglon,/).,`rl:J!2 ZYwC +Z)ZII .AhCd(ެ~~{hK @+B+@+@+ @ H B+\Z{?I$QY4:#gqJ2BXU-KfyBٮTwk~8l5[&6̜ùr/z}K+k[PZJĥi4i}K.cZ1m +BP(߱M:aeAf,qgu4g}; @ 8c@gmm,nׂ17cY&,QӰ0j5NUR*o5J%ZQuB/qK8E<3AeQ)$b&!0hE8 B54dDx-Y; Z'A3AhBVZZW1hiA6VH"S4z6gs<~@XY]#IM2yM١Rwiz}:a8b2OLNMsע[ڽwևӟ_+oBQ屨V4lֱɅBP( +BEʰ GV@YG1륟Y +:C-Ygmg-E¼cnn3FCOۣR:mI j+r>).*`rl:J! -z&UT .u>31uh: u. Z!.%&%hihia¥] B&DfѲ9LV^~Aa+ *UբںzQ,oU(UnWׯ4GF㖉)}fw=啵LZ?'~i}CZ1iaԂֱBBP( +B,@F,ȬPg<>;Hg=ysϳv;3iԄe<:2l4 uZM]h7ZQuB/qK8Ey,f#E ଻~h֍ZWRS/Ah] 9Ѡu2Zy:K4&- Zq~hЊJJNIM¤-(- Z"Lɢѳs|vAQ1[ 5"qA$);TmN?08d1[&6ùr{U -LZ{Iiti=åQ/VBu[B +BP(ԯ7!cEQV,f +8 0 wֳzY0gmg,k阛۬SQӈqhp@twUʶI j+r>).*`r9tZL"21hAg +B 8 5ԔdDx-Y:zCu +֙ uB+- -- Hh҂$~>}&I~&gtvDADDDDQDAAP9O<0>m;}G_3ƻ$lnfg}64}S@3E,v + **FZ'7(MMۡ4tMfop<ޑ1߸?09=3_X iiݸ u ַiazZIA[zsP( +B/KیGGYYYvgAhE=ଛ7VB ٙɀ76 @b6 mFݢjR*:iD\%Ve<.*bi|2pu<֙\ Z!NFu" +#ЊV[.f1*% >- Ν $@8d"8WցhEuc8":N"@(-<2Z@3E,v + **FZ'7(MMۡ4tM^k_t y#\paqiU(۸>ڕ_ƥVZQiAjEkEDoLsP( +BPd;ψJ,Ȭœ1 w{8 @+꬏ǰnCg]κ LFG=CAg5݆N]MnQ5) rYF" +2Sf1tZ5Zo_z V6VF)BVYuVYDhšRB#QhB$i-VV.zH+O &aH\-FeJݪib9.аwd7LNC@Z+@Z7oa71¨Ri*j%.J.. +BP(T\{lY5OFkaY{=nCCۮimQ5+u_g_i d1&ѹd3&HTPeEEEP\qML,]to/sڛi\72s</JLI;Xci5*B^%E²RA u! Z/:} +@aZ'RulhLYO C1he&uVBZZy,6҂J֥BDP&,I2yBlolj;]ݎ~аkt=1Mgٹť+נnAiݹGhQHk;UZZ0jJGR-2Rt!P( +B=x+(̬qfJu6>@+欻wnAg]ۼrycmu%07 +| بkxhwZMuh4jZ.JD2AI1WXp B+YZg!Nr6ĠpqheŠuOi:L@qh咠O-`XlB H+&dh]*(,Ke +X"UJF3MkwFFo? /,WVׁiݸ u;&>I z[H-LZ~ܗZ)JVB[dnQ뷹 BP( +"kL: bŌEFV\Y1fά f 4?96tYWWWË LGG\C>GOfminlԚ5zVR*U2D, +J :sBaXLNAgQ ZGhNց?Z{hʁЊI @dl- 3g0h%I ֥BDP&,I2yBhv'=ީi _XZ[߸ uJ7i>ҺGHk7Bi=ҢֿIZ(' Y BP(Yo œ$dcJS#\Y8ҙ:+κpCg]ڼ0? +S^{l5<8hok675՚M5VV)JDTQ.,y0h%9 VYS'lɠiy8b;tVt־: +- + =?hQH+Z$ieƤA8VnZʃb0Y,-.&-2Cih%R -X"UJZMƦkw F^ߔ&_\ +_zJ5BZ;YZ[;;HtoJ R+!-Z?Aj%YQRV([BP( +z.&_q:Ҕ IYY?J8 0 :ko/loevֻz :k+``?NNF]C^GOfmijlԚ5zVR*U2D,*yEZY瓠u4@b2tpVZZ heʊAB9:+A0#IpOihi"I B"_ %,2yBhRfw8CQCs K@Z@Z^z[og@ZIzKDEe"q+\OR + +BPQ|H|b,YڏY?;Yଷ*t׀6fCw}n{gRk6ZZ*bQE8κEvsZNrLBD +rhŠu4hֱ8b G1h9\.ֹi%uJ @HKPZ&,%RYZRkuzd76X[mnGos`p52x`hn~a1 uJ-\Zo'IݍDPZ82PZJp+[BP( +3ć(04e,,YYhdwwgs֛n݄κ +^\ )gr=6p:VkKSc}l2:ZWɤ\XV**Ђ:O,g \@p-YOt =Whe4ieƤA8VnZh4:d| -Z iaк/. ++DbiZTk:C\kohln;]=~аkt=1MM@ZK5 M(I\ZAi}흝H$I wTԢV2(d +BP(u$4bEtf}1 w`^4ں pWY$Yw g݀Z[]/g3S>{l5<4ut;mm֖ƆzKXci5jJV)*ʅb>tE Z g:ufaТѠH%C+VV ZIL:`:J@+' Zy4:dlH --\Zqh _,(-ieZRktzdoljwtڻ{}!Ȩ{|Mgٹť +(븴n(/Jqj%TkEŭ$o.1 +BPLeN<06vavAcZڅBE `6v;[goۤxIId:mg)z~$=ZNKǹ᜹~/ v#YLe4,䬿0gmt~{YwnݼqŅh84;=ƽ9[,fѠjԪ.B&Em-M u5-ײТUU Ъ +|>٬SZY(g:vV.LŔ@p<_ hZ - 0.j[ZENLP`1Ylvǰkd3MP$:pyqie5m;w>`i=aH+UZ9bb+b*JM/D"H$ҫۮk1wT ,vgr,䬝YOqgY"g}uu兹h$4;3 '|1ka Xz=&^Qw +L)476Ղ.Pb8 CY3Zr8l8I /=C!#QB<ZHZl6 +-ֹ_JC5,-VMm]CcHC$Here[&?`;gl71N̆#yU-۔>ci=FZidjssk{{%-ZϋQ+Z*ƭqT~S? +D"HW+qGd)Y)fagloomnD;~g}嬷YYWWWYHxvf:y#.>dZ&AtrT"ujkZ3E9 U]Uy\.FʁVyZYhg)p֡gh|ieuQ +ZXZeHZ'Ңbs8\%hς0ҢuU[WjimkwJr[ or ;]nw LMτ‘ť+ (iZiA:Zebb+,rU\oH$D"^yS2+ hc1T e]FJ;+ZY`gO9-pMp֕ŅH843=ƽ9[,Aը +T)hokmgՂ.P:ֹ3-!@r8lVY'ʐhhuZK@kCV9ZHZ-6h  *@ K+XZ/ՀAZ"qT&WtZhYlvǰkd3MP8:7 +Һ{%%#ZZ D2BF*Fʷ[imeV!^^$D"H_FŜM|bac1 /,mT*gmze gq p*8\4 +>gt5}QӪU] +L)uY5.bgBrVu@tEPr9l-pZZ'hh{u Z iu,-- +ZeZiiQ:hB!@ U}ICZi7Z;DLR5Zh2[z!q{}l([i#i.- ԢI)Vurm䬫%p\$g'1sa Xz-=&^trT"uYrEA Ъ< +|>٬S*BXQhzIu8 +u \iXlaH +Т_SҪi5ĝ\RkzdZlCv5y}@pjf6suw7i(iGj=ytm}}#'HZV>rO"H$D"b+sVefk2@*`r0+L$Sp֣Yݜu7Yٯ<lfcj{d{UlM.mR'":e %[ņ$3B6d_>SsY,y>/?wfɥǏ&'|ޱ^O jokinjjҒbYH9hdg˒$ +q,hzYVhhwgG:H4A,yA%Y A,-@*$i746BZNW?084iOLNg ťSBZ $HZJkiZH4޾{ZZY[&m%e!RbX,$|6Ʋ KSVY31X,Yp:9kUsk99#re8uv8kn?=91g zz].'POΪ(-hYVa@K%Qxs8^5A+sڳвZ{O*-Z-, JhAZGTi:IUS[W iut:]O_Ȩ7>15ퟝ?~ba*>$i}HK[iZ@-H‘h4}SJj[+-M[:2b_,bXt߶JK#j8씕Y?nomŢH +YwYoiκT9CYUg\\8q|~n?=51  yz.ggP_W[C*+-!gn,@+?$IY-2 :9;Sp ^VBZUi)RI2@pp gɒ( +<9$he_VYVhh'-$A2J rp/$ِVnUxDZo+HZuVK+儴z<wCZ2uz;.Oi]IH뫯IZ +tiVIZGQ랅ZZtj%[ˌ-M[ oe"WzyX,b^lQƁ~<"+YY*ZuF#0 +VY+7tgY_uEq֧qg g]E8k~vg{Fᬁ^O儳Z[:rVEy9 h<@+';[$Qxsd:DR:+ 6leAZ z%!LZ'h98DQe@ /Z*.)%iUBZM͐VGAZ#c>Hk?3i-@Z![$IZHVBZuAHk3ѨuמZ$j%[+[FmŹVR+ez,bX}?s4ʸ4beDVluWcV`u[qgY8r䬷pi8kΚOYёa8v9;;&8UZRl,ZVa@K%Qxs8YI$h)Ҡ;kYiTe@e{heҥh8QlH+7*HkҚIZgRH Z$-P +u{u5fVJ-Z-J–U[qoe6bX,z1J___N2)뾪, ":שּׂVᬛ+pk,H3E8kΚ|p0 guYmpVcʊrrQ3Tg +,@K%Qxs82ZqgV:g=ShM.-Z Z*HZ +HZ (Ir6 iZv*)-SU[WiBZN!i AZ^Hk +ҚӥLҺHҺl֕diTi]%i݀@@?Go\Ey>$gHA$IRͶ^’[Ve!r+Ɉcasm4PbwxR.WVW]ԺߐZbؒes .d/((({ʼn!+JYPYf]vuuR.J,p2:kq; u>gCg[ଓ#]Ycଁ>abgYiBg1hZ%%Ag iE@˕ -.-:@K WTUu4H9 j}KAK@k VwO/Jkx5ҚAi͂NNz=\Z_|)ŨeK \ZY)W*WCŬuMZ [lqmy%ghyݡ^?EQEQUsQ>˔ō0"˧QY7n8̺ZWVY|AgBf g}E^zu +uu5ΚgMFY=Y[Z~àŜJ%ZekZY Zztw-Y5Ah&Z\Z1Z(-EQ5M7 ӲZ J %B1..&!$Hk'Jk>!qS(PZTWZBZHE2P+/%j]e[ ֺ嵖֏[mܒ5WBuREQEQg5k27?ldŘŕrf]U,,pVzu,Y_Uu+YOEggMN:;e; JZei|Њ!$hm +V5g3zKKVB/x\QUM Ӵ fVK+B+(m\Z(q(= AZjot: lng%,4t]SU%8C6Z/hUVuhҊ|j+1iYVLZ\ZhmCiviGiEi=z֑k5I j-ә%VU,V"V4ln o9+]w0((ꁯ=GS'3VʊbJXfYK48k~;7595YϢDgEggޅچAgpgm B9 Ւh556&,9KS%βChΪ Z[gUWZ$h!Ҋe HI %ήn&aJk5:z J0iA@ZZ(-P+iesyj.Zdn o9+]#((U~J,[X.(K0kǬ|. dY,`s2+sKgYOfY3謩ItsVwWgZp@+g,UǹYh gI +8+-Zb(-@!t0AZ $H Ť +JKk`Iksuu2\Zo#IZZ\Z@-PkVEP˱R+h-Vo9ꮚFQEQEmAut?mu %+;Tc,YKE`:Y,Y}:pgDgFgCgMDgM0g pgubhIpV#84tZY Z1,ZZ5I-!- Zu-&-Z(8JKt0-VH+Ղz\ZhmgGi`ڋ:Ji֋LZgB'8li!@Z@yVB*%U[\[[[< +qW((6F:JGYXXXU%gVU* +\. JY,`pc8O>qYO:˜5>Ɯ˝5-,Vk @ ek:+rΪGgy%sVMKˆ,J Ji%@ZIV+@+JZ]=\Z#(mۙ2i@iY>jjZWZ LZZլ`iK-W\sU3(( R?{'(K0dV&Κrfyu6YY'0gm߆rB +h5&i*:ArV %;ˁVY$h!hE40LhR hiKkhIkIkn&i*u.BZZ -K@hj9Bj؊Җ-\sVQEQEQjw{G,c!b̲,pK0g!uN8Հ3g@gΚbtB9 ՒJZei$hYh ggк'iВCimH WTUu4HՂhqi1h i!ڄ&&fK:Ť_ZoJ uPb:YZZfsyVG-%s#.]aEQEQFP]DHdyeVeKKtzqaκxBf֛~guJr~t֮ 6psB jg%,4t]SU%В:ˁ}{֦ ZhEՄAZIVLZ#-ZҚfҚ:"3~]GZZ\Z@-P%֜Z9NM-ZChK+.\aYaEQEQ_+{t>bBdu](3ę2kfpcpֻ:Lqg2gMsgsgz\@K8 hIpVp* +:zV]Zh%A6Ҋ6+*J0L JyI *[Zc\Z;qi~P˖BjԺM-ZH-aHl1mܲ%K6WbEQaz0GXggY{VyvǾpGE(d(CcIwJ>Z{^C%bQ$O$Imk~h`PY,VV:Y,0+rf_Z;kr֟YvlZvYE"guJ9B>s geZ9ˆVSgI+-SZ)V˕*IA酴VrPZ[iiHkցPZJS "jMLZZ/^|"j]7j-`֖\u%I$Iۢv_-WX&LcYiʊu=bwW\|Eb9kjÊ4g(tgڶ5t\gY-rA gU+rP*YbZY@,g5֯A' H+i (W*I ci-Y@HZzBI9%=iZ,-P8Qk,QKkZnDֲЖɭ\1uELT$I$IͻٛyƏ1\c)K1ˬ `E:}J9 J:듏ӜG99'Bgm9AZ,gujJb9ꄳ2)ΚК< BXbiU:I?Z6n +JZ!O?<uzԚPjZa+&$I$I<|bc#+VV̬::K"gYY̬YᬷzV9BgmY-8CjjU* +p,ՑYA'_Z|iIZA i VKk zFKk+w,i}SKKE"j!jMyO k[ nioȕpW I$I$Is=9m_ia +dRV +&Y,b9 +1 Yڭv֣6_wA5gYzF*YB>wV&Y ZK-%-XZ\iABҪIZ},%JZ-WZkz4i틤{bjAZiPk5I-X+c- [ nV$I$Ih)64 b2P0k5fFNTgn}izYk Y-rV9U* +\p;u-OZ-"l(ZsyHҪ$VtզvDz )-E-5r5 +jM(jk1('2zXXL,X +Eʊu.bbi0gY4zںZ!8jJ9eA YZY Cgк{A'4hZ:CZ%VUIꇴ,UҺimlJI^#MZZSQk5uԂZZ,m˯/I$I$*yŠeD?,GYYYY`1Ebg1Ҝm8kgY-rV?խUeg|YpVp֢g[,RA^ ---VUЊVU$HklA+!6JyKZoKP8Q뤦8Sk +:kMea+V-- P\lw5$I$I4B8gXJXBc(kR:fMY:I:f,,fVYoi9YOڸa}Y;g Y=FV#g"3Z@-g2hҊi (WHZ֠֊PZ +Z֬]TZmiPZ$-P(uuJQDD-X-֖-[1vrN$I$I#5yc4d.caĂdR"eE̚uu: +fY`vˬv7uֺkBgihigPzY]YrY8ˀV䬌E)jZY>hJ+-[ZyHҪVkuV7IZZiIKCk#]HZuk7HZS˵-h-P\&,v%^)J$I$I.s6>d+ϼ%e" Qb)ϬoY,b; j嬽{Z:k8鬕,9MΪתUvV ;bhbh-LV[Κj)-Hi$V?Kk)Kk ‹RԂZuu,IIETkY؊es+WD.]R%I$I$I%q=bi+44e)fM!f#fY`;_VY=䬆rV*Yl{ΚuIk^GJ@>@+h%U\Tk$.V/IkumIkgBZ/+-M-Sj}jMRkR\kbmR2ˁWsI$I$Is5%^ [W!XX6`,Y,V5dQ0+0 4gK3tA Z gYjR8qV'agy5߀֬sZwAZIiu@ZYH 2J,jV'iuki +i3>ZZZL-SKP밦qZcԲuֲmyDW$$I$In]@,*VX0@,,R5aa0Kf +e3kYqA5MΪ*YyY ,J:^YZ>iKHZ 2 hAZEHPꃴXZ+՞ _uU+dI5}p'ɃAd|( @28& j%[mCBHAUpww}νRQd;ffAEZkj}!Ԋ `i+#.])|WKM4M4m[{t^L9orkiIiYjZ$-P9SLVZ[imeoYq+_rtiiNg?9\Y_a9b%Ȋf=(f9 ̂,,aVYofkglEЂNYG{g CgF*rV +ZY)h=C˗ViBZj^oAZG!"sVZ^z'I-+-ԚYB{X WX+-h+{ˊ˒CϮڨliio.z{tߙ|bX9d}dyXY`ֽ2fY,09+ŬwpA88$u:$ojhYpV;@'V謎Rgm3h +U&}V?5Ik$/$I'S"qjAZLטZDYւPkiΝ++kk +X+q+#ii=a+ieX0V@Y,RrΝ%a1kE"f,v3k"hYg :5I:wHA}-;k[@:Biu9iui DZ}NZCEZJV7$$$cҺi XZL-uF1Va-Vl-V[\F\vJ^iikurOV+?|!+REZ_[-f9gY,auYYYYFVV*YC~YZZ]:bhm g֮ZZ Z"-֘'CZEZ/nUZZ,-Ij@Z_ZIlA[[-\\JL4M4M{Vaݟ42  J!O@,0k ̺[,rg1Y[u֋pqY=ghYpV;ksVunY ZH#VW$PZ`BZVZ"C$#NZg"iҎZ,-P+LkD)VS5xePkY X` +%pq9syJثaiiSTE#6 '!* Zn߾0/jYטY,b8 rβjYD:uuH5ިk*5p gsꍜ:c9vꌠ#i9i 5OZ'u9QPk933;77j"k=Z"fY,bfYY,Y gϜu:gh ZsqVO謮YY+VJ5KkIH s.fzՓej@-H @.gL7@&Y+P[[-˙+SW("iiiB_F%ͷ|eC +Wn\gf}3E"gY,q1:9YKu9kwhY{[83vv֖-2g5i 5"ҪBZV:QJ 2XZI_Z~ZW `Z[ym9n\F\\\>b|E%ViiJ_)f+e3Vf,ì"gY`EgYY?AYY犝Հ⬑}YYvچVLZ="=.֤'_=u]iG.28i\(Ľl wB 0NlɞOHh:}> d ;,i=g"*Ҫ6ZBZD-Hi'Z*-J뚔u%)-PEԂZQ3 Q+jZS^j֤@-ZoZm9ܲeeW88㸽:H},s6Kd"f eV̚1kgY,0f g57Igܒκ.um:4:>8JkOZZ$i+i;:iNki]U!j@-i -֣D>PZZ/Z)ilEr,ukӼc88vf߼A__9"bV"+PK)kyflYCĬ>bf,rV{pVctVtV嬋YcvYYEY,hZYڲʒʑʋH˂V:kuUH\JJH "iZi? j=!j}z>@Z"jIkmk)lcpKxW.]!{gqqq{.toԷ2M,2YBY, ,b1kaaYĬ~bbf:Y-YuYU7ʅgY]gIgHge:Uhe&BVq>!i}w~i iZ$Z!-P  -P.Q!Q)Qk@QkTRkҢ"YkY[k]XKaeaі-- .%.m@]888E}XBX6lcYʒ"eke--fMJf*f ;䬎vrVspVtVpVYE9g +I@됄VV $+$R!BZjAZVG'QԺwzDztrffvn@ +%q6W..BEqq_(Z/z?`"b%(@̚IN{̂z{,0 jk%g56jn g*%g]!g]U+eAkW:+-H++,|%mK{-ˁ iU@-H jknzZ@D>PkKٹdkilpKxKKK+PK_qq88M}|h4&%FOY ,bV29=55911>66pzfY=pVW' +g55jYU7Y䬒8g}m9 gZr2rVZh}h` +L'-inWZCZHZHZ$JUWj55ZmVmPuzj=trk-[4$ ,w88= +:o18V |%eAVTY,(k&9Ǭ`#ͬ0 hZᬆz89UNκFκgW:]g;˂Vc>lhʖJ룐e,$$2H Ԃ!-Pji::A;VcI~ZD-֜Z[ +[am9ޒR +O88mEOqg$lb%.U)59912_211> fଶV8ΪY7Ye䬫䬋;XYy+uVZAC*@bVV&:ַRZg sJZWHZVI ԺUSiZM͠V[;juZwAGFZd-P+b-aKj`esKxKK+l.^Q~N88mܛhH[WWXBXXYX@VJ"+,b559AM   zf.0 ji8&9*%g]Q:g8X9㬬͝8k21ʏHcKZG3H2I*'iUBZVm]jZmPԺ 'k lVl)mޒR +ŗ`qqɷHX6 V Y+Yae%IYĬMunY`gYJrV9UBκ g]YG-g}qVqV, Z[u֎_Z<Ҳ+@ZEu$$#:yiH!K$kVjݬ@zPj:A;I$Zd-P+d-%[ޒr+D63D88n' C:?iJK+D,c, YKYYP1+?\uq|:*v)wIH0.cMF61N0ɷZ{>{EAb?zf=Y"ff]f]fV&`8jY8FgUYib9O}gIpY:Ki%lhHˇLi1hM֒(-MV傴 -V0iAZ@u&P֗qjzwZ~ j+V-...\2T|MEQEQuJV6+W Xb) + G}3kg]Y_rffmցY18kvYMp Ϊ Dg-Ms +r+)Tir VUi9 H j ZPkuSZܺ}{k{ݻHݽ}Z %Ya[ ڒż'W`]FQEQEg8)_WBd̑%* Bf޺}7!>̺f&!0 g5Y8*Y\6Ü :LZY :y|5Zh +*K%MAZH +ҲAZ^ t pZj]j],ZZ{Jbzb뉌-V[\2"u+QEQEQGOوz +HX>X"z̑%*!W=dֽf}ƙuu .8l6

ťKTQEQEQdz-(EaE>yo>9}`R#GV,d( ̺¬YU`x4z,pVr:82SupzOt։Jq ,r&bi\ZeVn -iu{}h486SBkrk=ŰHƖrm1n1oE ++bBScREQEQ/4fhL>x% wN,XqdEzBfm0k3k 5F~ jf3s;CY>fCk|h=΢.ZI0- U -k@^?jǓNjBjZh-Vh--h--U[pqq%KWQEQEQGiO~ 7?#_EBaRőGGV,d( BfJagd<f 0 jx.8^UYe1g-κ: +5fKkKyuٗV& ba JVi9灴ZP 9VW׮PkZ jbBkJЖ--...\$xJSEQEQuK^W4#aW XLXd}bBdBfY_0*gp:8\UU+,4t]+B>f|g]Yt֜:Bz:yxi$rZiَz Vh4S+Z ŭZa ` -V--\2DvIJyFQEQEz?bPXќx% 7YLY,,dS2 *Yh4 YN jxjRNr֒swY[H"JkV6ŒaZVRimq=ju:,j}BkZZ*"mb +K/ػQEQEQǡ(EaAMԕ+,&X9BcbBdqe!Y,dv:f\DZJlYaV* |.;kuuliJ։ũ%K/HZ%M ӴeVnێzFv{`8ujqkBkrkIRp+O]{ ((:%MBq2FC2O"_1` +KBSn,dS2 ̺ʬuV\ױz U.[iV;,άyubuĜiVH_ZH-&QZl./PZnez@fՖ&QR jbړ-[[$rWzIoHQEQE7ԁ(lhP + ?ʼnKBGV,dS2 ̺!1kmuee2 j̀YZeYa:Pr :k1ty,`O?Β5^ahHv w"iu:.%iҺҺZ/(-KR!ZVzA"!Z@-n-`ZhDlnK/)((cT!Y)+37VYLYwe!Y,dֵ4fNfy j +w* yYK Yg$g}wiY"g8liZd(BTb2rREjٶ^c:"sjqkk1l݋aKҖȭ[sRl0((5(a1"a"GV,dSgud8:̪Ved*tV6YFg-:KΚVͿKZ%HJ""J+PZŒaZVԪmq=lNקȧ*RkbԒŭ%`KՖ--_\>sWJ HQEQE{Dc(xOX9c bڒřŔDf#V}f"f[f\DZudVlYaV*rlȝuu.Yg%B+,/R3 ޜ-wGZH-J+QZ%M ӴHZnC PKv[n%+D/_?MEQEQuJYZVd0,^gXTdmsdBf1e!6Օek5dV2MC׵:+eYK,`8zs~5Gy]Q + z)A AkDf1bCؕ "o}}ŮZOZ 76&FlEZ9i]@Z׮/.BZ7{+ֆݽ;Zbj=jZZ~kزlA["rEJU"c1C=Ø2<KcYdc2)Sef5ʊ 0kΎeܻ g-.^g].9g}Vq(Κ[gU5N쇴@-#ːUH-ZvZ@'B-VC ~Jne޲r+/;c1vH?WLb%RY*K(1 H3e&f,z`u8*uY0k?uuUVZiOur`iijYi]i} i-@Z2jݲԺmu7eUb"2no%rUcc1׊k0jIj]׮eUBQEe Rfݵ̺mu Z{7E8kRu9K3kPgLuA#jѷ5ՉjiZ@kVA Pk+}cG-g-֏[%mE2޲Jؕګ$7V|Jc14֡~Oj] +RQ%2 +z,̺1k Vf]ଆY⬆Y:Y3p[89:VV&ɢi]pi-@ZMPkZ6APkOQPK婕ZX+VЖˑ+1W _Iٿ1c_,E="#]nHXXX^r̲f=PvM0kZnYp09BY& Julxgh.ѥժHKeuiZˠZZ_9j= ԪY{XKa+{ˊ+5W`WA_1c4 Ƥ֕*K!5UTfCǬZ,8auEeUqVktgMj*BkTiҚΤj5iZ@U֭Zwz!ʱeqxKЕҫJ'd1c^:Je+C+ (EUYYwsffYpV,8a0+8K3+uִuٷu:h> ^RZsNZHZZFZV#- ֊PkC-uԺQ+sVL[\".o..H1cY!0$պ22J"%)+e=Ǭ]aֶ0kC"̺!̂f,"gu޿ѥu.V"-V#-V#-rZ{Z ֪`j+#GWWjc1|WW +XFXXXd(1kƬeaegfUɝQutLuҚiEZ9ZzZZ[Zw"jUʴe% + + c15[aD]iwb`a9bz d=J̺嘵ŝ rfgYtVh:IkJI%HQVZہZ@Z5lYmynorRJ˾1coIF&ݼk3#5V YπXYYJYYEfYYpgVY]qVK9k*s֩vx@kiIuLIҚDZ @-%-GFZ}kijUc---˛+Kë">?1c} _veU0Gַ@VEYY0k)0K;+0;#ΚftqcRZmVJFZ)rjE +k= +ز2RJ񕔿c1S0aJqO,#,G,kYYZYYJY9bfYYYm:k*+iMCZVKMeUjZZO`a[<\\\A]j{2cjYWz>MV#Vl,o'@VVsf9gif%ꊳZp,5~uU֟::>.HK5'ꈴ"j)i֚Vb-Pd-V---.G.g..\_yc1c0ًaHvwz`a9bX/2c J2̊嘵֏Y4:9,aV欏rѢj:h4֤5iki C-o@Z`GV[V--'3WPWB*c14_5,4`d=be)fYe ,yqV;kΚrΚ #iMI/3iBZ-VRrZZw*c ڊeԥUW1cC /aFe&UDVIYwbwV`y08gu;uGgMTud|U~It&i+9VҚR +zZZwaV[V--'3fWLu1c wWXAX)`"Y,,,( +Κ:9Y߭-ޫYixi!.%JPe[V[V--.G.g^~2ca^:ՊVJ,+GV],,(̲r:fu,st@ uJK묑֔,Ղ:ּŔZJ2Sk}kUҖ˓˙K+W1c< + + ,OX9YEYYPVY 1.fYgY8gZgMg:ΪA렱VNT55m5i!.eiYj}jkZZbo=k[J[\\\A]_c10c/[jEeL+#2V,Q֞W֎(kSee%̺3 ,,ay0 f,qִrdY',W}/sVZ3VZ-Hi͋,.8j]Z26Z[Z +z(o 4R{cc1ʣ0aP~J|%2rz,ʑ%ʺ핵%efAYY Ef]p2Κ:pV:k:w֙Cw("^ZgZmP jj}yjjknykm[ksKeeȥ1c} 3Vdh_ 2b)cem{ee nTuIc'¬`Vj[fzgg탴&ri}IkRIk:Hiu yHPSGBj- zBUPYkZ{---ˊˑ˙+bWBo11csUO0)F_ <emzeCYY=aRYf}*35fu,_':%Gf)ZXY + +QK=cٲl?722#2#E S +|YY[,wIkIZ;$nK+Pk5qԚ9j>Ԛ3*k}Uk+y˃ˋ%ԥe"B2s/ۊbGqo+V%XlLe}%e=:eyff]>NfYǬQd9k%g49km՝,HSV֑֞IkuUQ뼆Z GOZZ2kEl +"o\l.Ů^cB!zvqTK|E+"+Q7*f=8f-u5u;fIgUYY6IkҒ9jMuIԺ!j9j;jb7k+y˃ˋѥe"B2/rJ}O+V%Xl,Y%e=:e;eU̺!f] +f f{fMFYY=r.9kjeH5HuEԚ9j8jQQkUk-S[[./.&K+WB! +T؆j?Y+VEXYu))kĬǬg1+q 8[pVdz)imyi(i+i%yjMu5wԺsԲUV[[ +\,h..C_VC!BoNF9'{(Xldʺwʺsʚ;eY:̚zfRfvଦJ/|Vi풴zNZDֱM/ZWZ7ZZdǢ42m n<$Rz B!V(s! %Ϳ `"Rcid蕵pʺuʺqʺr2u5::G_8AeaimGiu=ƭu5w"k=(ki+KW3B!{<('èؙU+5,;SV[f=fyguY8zvRZZHEϞZZ7Zd42m n<$Rz|!Bˇڑq^ ++5F{[,b֥ggYȬ`VtV_9kYpsJ+Rk奵Kꑴ""Z .1K9kYw gVJ -V5 iyjUҪ֙Ym\[--H...[_B!R_:ŜX<<%HXrcʺeeHYYgu"f,v3+:+cUꥤI+jVEhyc1bKkKp0fWY`!Bhղfڑb_͙KK@W\(3K(-YY8kɾ_Zkeij i1ZQ%eX&XKbcKkKp+KK+WB!; 2o9 dyeݘʒ"e`^dtV`VYkpVM/!LZ)Dj͘ZZ,lEmJJe+xr!BW?(Ge+XXe]heyfOJ g-YKiYҒ(jZZCZӜZZ_LlEm +J%ѕW]B!^aK|.9gW]+BWUPYSYÌY}NƬYEfKZ[J+PKuPku^V-[\Rv* + !BPFLvWXRdu(3k0P1k/2+8Yr 5)-Z;j$>.Zd--C[ĭȭ\),{51 !Bʳ0r]1+7D5!뒐9(+2k5g`NYYpVmŧ//$-IZ@iVZ_Z +[sVVέ.\ ++B!zXtT2VNh;6D!NYǤ,ϬQʬͬgVpvYKIZ")&ZDSֹ cKhUWS-.!B{dԣW ,),"V4-K"K*뜔5#fMRf 51 zZ(6 +jG#8Pl-[׌-V-- DW:!BUފ_K3)Xl, YIYSR֘ՒYEgmHg1C[fWZBZ%ju jjN kl]1H[[[ ry5" !B@ōlI93T"aIbUƺacd::!eHYR}Y:fmJfY(I-Zǹll]2H[[ .A]Z1 !Bja:# s25DVAYSR3p fڀMvZ=A=m-O#[k`-[---WW$W.^m!B!O0[j`^<$*cEd]0J:ʚDe1*g1z̬6,8$i}ֆ%Z^Zd-Aa[kjXV-ŭ[\\JZc!BmbQ8;o-aIbEc K*k%5LUnvVάYg5ZJ궡İ։V---+K+wW_IB!Zrqes ,/,I,a 6VDY\Y2v,fm*fYO;RkCP+JZʬuʴ̕A`!Bh5+F=-L%%e 딑%ՊY&f gm(gê^Z?ֺvn35ckYʵ + +RՂ`!Bh*.dYy +39+"넑ըffm'T̪wV8KW)>XZK!ySje֚lebopEqIsYjA0B!Jb+J’Ʋuʔfu6f:m$9( (6%jiIy<_Ѱ-"3*#dTwm1vVĊsL͕֦VHk7I(ZZ_`-[Z[R*e+C0""""ZO\vX -J,e, Y+#5&fN*fu!jz֓c-[Lتu\B\ w FDDDD+)Xծ’ĒƲ(Ȭ~e֧Y8kFjPk[PKHZ_rc [JsJQa)64DKaKE烲U8k[9+,嵜 iijCjMz:X%VNr5K0 hkrtVE,mY^z*3k0S,5ijj]ڎPASˁZll6a$\&r#"""uE,VE,m,Yʪ0¬m̬Y% #_bi][M +UYm-Lr%%%+g0""""ZG\ToWiA,m,XYOZYn*g]Ϊq↥ePkkQ&ֽG-Z!n p qIr9JVR4պ՟DžZ0V,KY&fXY-)Qju+ +mݕ5p3OW7jA,XGPKVY3lZM-SZ|j.Ui[\,v FDDDDk*܍ƔZXb)%uBV,Yw!,m nURrէ/""""Z_ԣ_,bic+Ŭ z˺eZMkEe W^DDDDD*oY*^="V fYaZփjj]R+o-[nU޲ K`4JaĚ#+^fig5Upn\bVS˵{[R[ qyxJZ㳜Mb d+d%35ʬM 6X+V[Ju[` SMb)+\ffK˥V,lUyW̮eFDDDD_f::ڦ,cMȚY8m{kjEj`Kj\yypYK1A$LeKh@Z!Vɭ[bDDDDs+zpe!keN^󅗢VZ&` Χo-[1Lp5̅(,?&16k,YN,uV*exWilj !WY0띕xAjUbV-\ s!0""""j U;Y=2e- p ր:劫]DDDDDi UfwJ(fVY/#aj֪Uk+ǭږ0m2Ve:yRkpeͅƈV̭Pke[OʂY!j YV[[Bq-/""""ZmiVX5(+,F-M~k)lr3#""""]'5`UKxHY0BC-ZH`Жɭ\c"""""kO{V&lfyfR7VZ,m9j {QgnTkWm㤲1 gy,oou %cH1S( fm\jǖtte@,{ZK<;Mv"jYֲej+V\h֚TvV5̺7ZZ&m4QgUYsTʂYgn>ecV\+9?=`yƲխ,uAoP˳-G[B`DDDDhp]Y&&tȠׂ r\D2ʂYeZŖP G.ÍYVȭ4 ׻9#` +`{x֊kkD\(DKfcQ+V63QD Wn4a >B}WaB]DDDDtzhcƳxIew\)j`Npa/""""hpr4VYʂY{δVF[3ĕ7دܸa plg+h(,.Ƕ|=ef]@G=Zcqm1૎^=ߣ|n~k5euV$a7xz<Уo5L/L%hjX#+̺2ZIpeaٸ,3Vmtqmc+a>x\[&Ycѝ +ck`m]eV[sx43ylM- JaÝT>U1>I?S6V^=;Qq@K[+ִ?8wg:= X` z֖{ SM2u#c`?];Y1R1L.fBv3L_ڲ8|szpky[ 7Qب5ќNNVs6k#`k K*OD[xҿ^G}*m+.tW|Q_ 4Zg+]7V%p:̪C~Gkݼz>sNcs9?j_&NW#k~KftsEs+K_/l(B`8^ q(҇ !7'J7>wX.> endobj 43 0 obj <> endobj 44 0 obj [0.0 0.0 0.0] endobj 45 0 obj <>/ProcSet[/PDF/ImageB]/XObject<>>>/Subtype/Form>>stream +q +/GS0 gs +3433 0 0 3944 331 -52 cm +/Im0 Do +Q + +endstream endobj 46 0 obj <> endobj 47 0 obj <>/Filter/FlateDecode/Height 3944/Intent/RelativeColorimetric/Length 170418/Name/X/Subtype/Image/Type/XObject/Width 3433>>stream +HVQjh3?'GKwtZyb}1ᅬZ/[*x E=aS EOg=(*`i }A汢>l=y'_ S~.zs/.#zs .(zʢ_/\X\E?p/ClDV@*hqLnQ=㹴sa015m~v?loQzhw&p*vF;p'}%0h2Z +%+'r'ĪGKtXlͳYXQ׌iW}<%r+:8AhcEZ[V1}Qڊv99*N `"+Z>p%؊:)?O|}[q*'D>SnܒZO;׵=3m,q V[RiUu-"+>,ۖZO(#%[[Z+:象V=p[{zkCkEWĊ>8hini'Z]Yk]l^jkukEgek+k>_qBTlI8VVap;+֊ Ϊ}x<Ȃ:u5X;ObNN`lIFKKUI,]@ꏭEjMfFxaE3[%#Fk(юꋭȬM,=[Kjs+F=VtjUlb5f``w{+][jhbjԚuVf+YjΛ ϱblZkkjEʋRfTV9rU+!Udmbk6:; +tck~_~(bpUj+[֒Z6YꬬbdeW;{+#BlV!Yf3#*Y*VXE<^JV!ZZo,ә~̬\e"+XžiL3U,Jmc+ZLjDgάF3 +NJ^i)iήlor+[ՙZǙJT{oe"X* 3 +ŕ̭ll{:RKisVf}YʪGV*}5TX\jLk}9V%ޤ9uVSfU*'V9?%VNrnbRKiqJf}IgVjH|`UupqDn5V>֗SR+:a^AV˝)YzLd+X*^пW/Tn}LlRiVTf-ȬRee"XUm|r%{cmcZ36Z!sqSʬϕjtd+YXZQ.X!dl5V6>WSKi-4Yo-me%3PY*%VZ*W)JoTjZZo336YՔYTO*E1RUn~'ru쭏UDkhI-DW;t[csfU71~}(Ǖa8a(ʖ^"F;Z7 aeySTDDDDW\oڊUg +j z\V5i1QEfmIfIeMr#K+VWKxꂈ֯%GW +J5I%֠ZV9+ì;2FYYXXaUDDDD[VatR܊%UcQI-ի8+Ǭm,,bcibټqU>#""" +$VPW +.ŭX[l%֚ +kIjmuS iU0+TDi,M,Wu'""":{pV/kM:Ui] +gfN`PT~PDi,M,WzNDDDDV/\nY +֚֒k j܁ZH謍YwcV^YAYY4l^ """""WpVVZ`娵aS i-z2vVYyVYAYYL^%e/*hƖeyk-AIZi liAޭYwfVYYGAYYb*ɪ4DDDDD fKVfZIK;+ebָi̬EˬldeҨ^Ѻ`&4,n֢Vִ@EAZHO}쬡*f[fzfU  +zMDDDD^ಸebhZsoJj`֣2Yfm5*k/SR_`UX{= fKV["kԚ婵֠L-MiuFɬgVNe)dªѺ`,ne~dVoj 2UPVYL]k-{3e{+V7 +֪VHIZHheFϬ]ɬ,[YYdR2qUk""""jR2UĖmo-Oe5TBZuWg FYYۭbf%$Lezee%e U-nnnj fVN=LkyjIjSjmjmj"j j!bֆbP0kfzfieyeƊVVA#""""Z- t)pRڊu汥uXk['ƂZCE Z HKV5 gfmfAìν d%ƊUnM|u3̥%bc+gZejRE*JKS i,Ŭ`pVY ."dicIbe=HDDDD?^} +RJacKYS(CEƑRj!V묑pbֶg֤Y ez*#+K+VNRUl=Y]J\"lyk=5u,UCֶEQD-տ550;kfP։,YXX^u8h1] +\bmR:u%+ePKIk\*WǖFYv9m l9k]֊XZ@-!@-[ZC龜0k1kYeݴj!+1V ,V%OC+ `[R[ >l9kkNUIZ@HZ[HGrbVpV,יּs֮scsVYϳrz*+EVb,!, VYSe+O(KV[ZUnuPyZNZ vZZjJv֠YY3笅sc־g֑ͬgYzeoU0gi,-W(w""""ZVPF[[{k5̦֑~KQKJkSZQtYCY[Y YY{1u1++CYX4LW5ê,,U--gZZZj=Rk5 jeJkX)>/]vfYYYY6zu,HYcE+ҕ*A֭*Y%K-Z nuuXSECZj9i-fAZ;HOtVˬM,﬩s9e-N.^5z0VYldicJpAU?DDDD#BX.).[J[65ֺ֛Z.No/5wԚ:jyim{i j!8kTp$rB:3(0bˆYW_uFY +jK۪KDDDD8KV-Zk]7ֺj[juu$JkIkRiY[Y;YYY 1Mì̺UևHY6~}7UQ6u mۀ `.atrWY{O@oz `yJ*hc1Vb!lqYri+-ZkZ+VNUZ%Қ)5u*85-jZrfqf]7ZV\YJY[d2 +۪ SO!c1*`|ueiVZZ2u=NVOQk1'Hk8u<:>&grQW3+0k̺ fEGo,CXJ|ݏc1UKd!lqYri+nZ+WVZZBBZSJZViG,ìf|guᬜY0uY`fmYvedŌeʷU6c1;5|e x+-kmZk*P5PZ挴fҲEi>&Y⬖,Y0W/Y¬`:SVY)bYrxʪ~c1ƫZ8 W[)l%k݄@e֗ZZFZ-ִHk*!j8bYڎpVY,0k)Ƭae݂2ed*ʧU)~Ҡ2cVW0] +pܲeXm-X քZ+1j- .ZCPjuA-KZ\ZIi]l$q9BY3YsYY0f ,f]`ֺ0k +U,eX^e1cqBx9V[1kmaRj]j]Vʥ5g5#Қօ8YZ gu>5g]YׄY#fAY@YQdy*ʧU)7c1;]5{ 含-W[1lֺokZ[B ij]j A>-iiMxΚgMgj+gY=0k1+sVՂYPVάm0 ʺc@)+,eX^c1cl^,pŸVnZwZbMjZ?Ժ,Z=PKKkHkZ5Ii;gg)g-(gu>54(a֖0 e3z"3&V,W(b1c&calrಹj+VnZZb-PkZ_hj-ijAZCHiu挴fAZ'M()㬖yՃpfUͬ+êQ +e+V)Q5c1,c\[lXkOuWj*ZZP+ּ%VRZQZy>9rgj+g-Y]8gYY¬k>Vb̂rfAY}eCY!"re*U 4-c1;m5{% eV\[-ZZVnZ+>i !>ՅڹfmiMR,9i.iYsY Y=8k ʝ2k9,(+g(눲BdEUj31c[: W[1lZ[ ʭֲO-ZJZ JZsVuy嬎8gYYʙe)fY:ȊūViK{c1v3 + eǭo-ZBZ*eQKKkiEZ%@ZWZ' CVYg:qEI㬙ᬮ8k *eUYEEG,XYU闌1clTY.\.,rಸ%ڊcKL[g-CQjeʤUP+@յ5hY=qǬY9,Ŭ[Y;Y{Y:Ζ9sY9g]EgΒ$Yz ڝn3d,d]',4V,f"`JQEQEQkW@R +5V +[[O[hݘZh-Z E&Av;mRdPZ5Yi.3iI보>uv&Ci-'kNgg:B+Yf;+bs%t":kU +(,UtpVlL;8V767gsd,dLY Yd}!'V+WiWEQEQqLfiyzVJ[>1l=f؊BkZ@/cZ__[Si{!Z-VuMUQZ$BZuI Ťu*V Z{ֻTnJA+YYE4g5-Ӵlq]fp4O& + d,dLYqd%+W1\e*[OEQEQQ,",.\o܊kZ g-Z j}Md< ~n{ضe F0tMSe&J ńj)ʂ!V)ނg (IrFje;yn/cȬ,_YȬ1e⍕ V,^WIW!((:?0o\inJ` c+P Bk.VgIJUPU["_rqqGF0] +\p) +h-Zd-Pknvf5QZZݠV +j@PҪ ;-HȓK_-sUZCi):ҊrVZrgЊrA+ 6g]U gYpVU[g5YpV[{;fYVfMOqR1KW,X +<`ueChJ7qqa+ťDbTsyҹk֦Ėf-PfgC juZVKs3iZUUV9UH*ɤ%--ZI%M+--ҠlY>i +κ"UXXtuV)UgUYpVS,fY`Vf 1k~>@̂V,R ,WWEqqq*fyzK疫-[% k@|@~PZAP_iZV)IҺQTXi]zJ@Z ir"|_ZIe@D>$iY>gez 8Y;欛pmrVUIΪ0 A0k̺¬%R1+,YbyRx*So88;j%Y٥-W[[ ֶĖa-PB05jZݠVG; iZu$JHuҺN+$ OZ|h[Z[WJQJKtrguuֹpg}g9κC*YupV9 ̂zz{0.53kjjzffvnn>_Xte[ kWGN,X]HrqqbvI5fK5.[:v [/%Z'kIj-.ss33SS>F@ juuZmV  *HuǑV%%V#\ғK+HzO,Ҡ9+C:+꬏笫nJYpVu 9Ί5;:,8r5&53kyyeuE̲)k%eK%,UWWbqqqGTj.\tm lHljVWWujMJjAnPjiHZVeEIu+ei1UZYRZAi:FZr-Bu&5g݀YJrV-9 ji%guvuYp 15¬YPֆUY*Tc9rJÕU>?pqqŗaryrpKі-6ZԚFA{DAPZAXiՒ*IZ$bH#V^|h[ZXNQJKYYن>JY_κ9UEΪ'gYmb1k̺O̚И$)eS,i,XT]98ULxЖ-@'DGkk++KK :A]Pk:A-H+F *VYR'iA +2SV>iEA ZMg8sYY_&qM8pV99Z8B$gYCpֽb8̚c*(A: byt`ZqqwJfK!-[:%ERIذRkzHFZCD^PԂ@-HAHڗmWZ,|GZ9uiЊ&@!%%c9pV9F8F&gYw,0k z`eǏ7eId e92en+g88xc&syRЖ--Z3֓Ǐ[5 +jZ=ݠjAZIFHuuGV+,) GZ> G*qgAg]qV%9N8+&A%g Y`5>1A̚rZUIڒJx"d eK%,UWAWi?{88z!K0D`qRhYK`˱VBZkPkUR+Pk5AԺOԺ;jAZjbBZI.Ai'i}"V>uOgԝ.)p +UHκE*ΪΪjn"gYpgYĬIb֬YOn>#fmoKe\eId# +SVI$T;qqwJy%q.C\zb˱%MzZDI8QkQ  -Pjꥴ*J2$2@4M4M|epgWD\ \m1[&a-֕Dj}sP'?fj@-ej"jy::,2UiuzjZj4Ҫ@Ve8k+;9Y]u$YQq1+p1KEbgY,rVYYcP+CcX`ٺôiii/`* +eekÖg-5>6:Ժ֯~ j}P XZUiLPZ}Rښ$-ZZV51[ + jgY6YpV1pր8kgw-ggY`E"gYYg >05( ƪ K8TŭiiX]BpYmغl[kMZQj#j%jI@-KZDliHk VihZi5RUWҪY9Yh5 +2!q8kO^u"fY,8 "gf#f}2kll|bbr +̚|eYkYlbUe* ++oXM퉦iiJ 橫[,m1[Z3XN1HZKej"jGZ;DZFZ="jhUV ,iՐ⠕,;j:TMp g,0+p,b9eֈŬi( uʊ ",GWޗii*c>lqಸg-5mQkģGg@-S bjiiHH0ߓV?KJӓV;j%ЊVޕg,gjg5jNqVU/&g톳[:,b,fqY,rVHYeY |cĪUV~5M4MӴPۗl0]Bonyblly֚fgǠZSHKH ԪZZIZ$AKZH+EŹDZ -ijZZUBwFY-pVeCmUg >YY,0E"gYYYWYSWN΁Y `P](+D+ VEX"P4M4M6KU,.\ D[[-ZDPknvffթIEُ@-H2jIe֡iEZ6Zm#F#-IҪEhY$g YQguz +";O5Dg탳^ta,f;EY̚,WYw8db˷Uiir+\[غl9"j-Z):EbjZ !}.֐HU,zDZQii ⥕yiC+B>&;9tVNY lgY,0E"g1) +X\\%*q4M4M6r +-.[\!\XkZ\LgZ|,ԂZBjU',i5KӓV{(@ZM"-Z.r5tgչG:jqVU(J^qrN8k/uPz0+p3E"gYYĬ aܵk K` +*uʲ,GW_4M4MӴY|uY +eq}`Xj--.,_67;+Ԛ j.3.XZL@Z!ɈI!-J#6HJ1"+ZV:r.Ch5hZVq -vV~Y{,gh9亜%2,0̬e( ̲,X<\%M4M4M(e~V<,k@j]"i XZRZ/@Z{,i[ibiBZ,i[EUJwV|-YZY펳:Y=bT.Y_Y,0 "fҘE*ʺ/bd,WWJX5M4MӴRWdm1`Zj2FZ$-KK: $a I\.V#vV%-Vc-QhՄҡsmpV qV>qP⬣gY,vEƉYSĬa++k`)K(e#+X6|[aퟚiiZ-. a|pyrزԂZk++ׯ/-. +fZSDqKL-HKz囡"i H-ֶLiҪQhEe9ˁVSf@ЂlhBT*vYYGBgϬY`; "g%3&2 +|bU|*Tiiih1rzV[ZL-Qf +FZS+V,7HHk !-JibiBZ,-VSZRBg5jg;ꀳ-gvvY{Yg2λ;0K̂YDfze1bUViiʤX]nh؊Xu;ZIK +'nH!^HkV%nHÑVHŕVcDZ$i1C. Z! Y-vCsV'S(K8k5 gagY g,g1Y`9 ̚&fYk7nܼf|e=~zb!#VEX`5M4MӴyie+- [Og-ZsDiS%J;ogJ@ZYZ{ a֠H\.H3"-@K%2jUoI+ +8i=kg|-YZfY6Y]pVA'vg*g1Y`9kfv6Yw{¬~}5YUfaRD(>dplV0F̣jtDBwC7tn$K 55ZaaާkF:XWOqdqcE|eӪ 6J$I$I5A3]"obغ2EAjGf5"e +ue +4.,WNX96I$I$i`"o1mҬERj:"jj Ӕ=w:AZuVR};Ղʐlh-dКqjZS9+C UUjpV79k9ks"fY,``qYYNeƊE+cTM$I$I[ʟ/_&Bn1mrY5nS8PRPZZIziJk5IkIҪ)iy(JKI+NZZIβAEҜCgKY.t@ jZ,ŬY,r0 u1d@ĬY,,8br*5~/I$I$R.&.'tl9EBk@jj}q"jzCZ>3BhiZEZڋiJUDi i!"h-NV:iJg%Br" sV -pVU|UNtVrY,g=ΜGw2krV,,d: u:1k,b(K1)*@Vh,,[MI$I$i~abұeX +56:2uՏ:i"jIkZJZK{QZ] zViWBi6&--%-'LYrB偳*:8BgZac +d +Bg g̺e)[KYX1t_h\%I$Iܔ3żq+Жeomku5 +:} +"jҊImSZi=HPZ6nH֪JZ=(NVVM +Qkji/ua|X¡W>2lNbے{,yc=]G!9Ne1 Az(yrnPpT'OHk+Di iՑIZm"Ҫ*ҺߗVZu7BkSZ)@YiMׅl'!gYY!,gV,,Yu9+ "e̒"fʊ!3V\Xq]R886vPX\qoڒ؊Zkճ֢lZWZ/HZD-)-I-OZof :&_Hk֐VwWg -Z~}!V-I+CҲ -]Ґ +TZBh݊#,0s1 κr=f͇e f}QVTauL88aqs{W[ql֊PkԚ-3D,Q*QjҒч zIHYH@Z!BZ A!N)8Z$:V5I˶-4tH +%ThҊCI|h8rhpaZ9+CΪZpsVSstVOp0}:gt9Yッ: ru519I̚"f .$VHP"**88GaqrފkKb+j-P˳K0ZD-QKJKP+:,Hkc;5,#AKJUKʐ,4 thUZ!iyкVY\gJZgU5 2YNUWO"gZE.vYᬣp#ppsIz7,0K8ErĬ|PYP֗$~ +BӪv886vAXB`+f/=kZPP iMOZWA-HKP+*Ms#QHk? +iAKHUS]qHZ&i*)-@˕V +RK;%u{UY7 +8+ +tZu,dYF@K8+-鬎.8v&g),bp$9k2+0KQV?zRV Y>qqm}K0W[`KX+XZyIiZH/'!G!!$ݻ 1HkҊCKJEҪ%ie2-Z:-%%U hUnʁVYKgJZgU5M7 Ӳl!gՐZpVY[{!r68k9 u($1kmm|d)ĊU88{pV kZ +>VW_0O*VΕi^^uuuuE#i z$Jiב3Ƕ-4t]KCZZBZV%U@˗V.hŜUZg,Z,@Kt0-vZ5,@K:+ +-8 酳Y~}57uq+|p#! wY\p+Bڤ݄'wB%[NvRlߗёts$asp儳f8kY7MߩκuuxtEΠ,=JV],bX,e[qm鰕lJ_G-HZD-nIkZf -'5i 8 -+i57Ҫ$iiBZ"˒( +5gY.8kZVcκFκ~YwY67=[pј20{bV 諃o,bX(.LlZ) +iy֖gԺw"iZ*$k1iBZ,rNBZijkHZeg "h*) + -E%I#iZqi呴uL2A)I+r̡u4 +-ThC "h ,+@:*AKsVZ+*Y -m8g ;]p:gYY1ת<0ksf@2QV229wbX,֯\ڊahZ) +<=UZVҺNҺiAZ -75rCZCiAZ $ʊЊIiAZ,E%QxEҊADZI:Ih#ʍBKsA xA%IV8 *.YbzM9gZm~uΚpMNYspg]9u698k zc +afH2SV YFb )bX,sO03q鹕V [FkH2V0F-ڂ@-H JZƤu Z 9Ԥk: i96+i57jHZ$AKV UXi),I V\Z\sh-i=#gpK:gK889K-DQehZ_UeҲrrVm]=gYpsrjz=7g-kκ gIzTf%u.9kzY~Ƭ ~ҘU֟2"+XbbX,b=ǹTm鰥JLѨCZ>6$iZ iL1I=֛eH< iϹg -5Y{ HU^Vj.-@ *.NY,,K(108gM8]p~>欷RyY_~: ̊;9˳gy`֮?BĬ=sf=1+d% +ObX,֋^V2K$l%YK#sjB` ^u/.-ZW_&*Oz Һi]V ٙIsb p!H jl iUUVLJt UXi),I GJV.IK&y:dD,=|Qd:gZ_UetgJY5pVS3ka8k障u/,Y/YWbzIzgY? g=|pC01kYien,X,b^`/̵Z?RO +C`|iݏI ,!5im@Z¼{vf +vjnjkIZg0A *.NY,,K(kowP_GҪ(/#iJt UXi),I GJV.IjJ@pz +u|QdYZEB+YZpVeU59ꁳ쎁A8krMMϸյ kp;Y:,9Y@0 +#{{Ĭo͘K2Ll,S_1BX,bqJ^[؊Z+F_̨-Qko/y$-&-P+>#i}HzҺv%Hk}muy{fzipm}=V{[kKS#I^7H "iAZ,E%QxOV^y:dTgӜ +9+7Y'9QdE9+ZJᬚ:8j;GFƝٹť啵/YpևTg}YwFgP(dƬ J +X|vX,b^첃\znűZԂZ{H8 +imEjҺi]v2u~}meyiqa=;3=r  :6+ i@ZeJ Ђ + -E%IOH1Sie"æzYhsט$\Y]`;3;BoB^AH8u& $v((Nf/v6WsTd5ٜ_ΜO}C#8]$HerRFjz\n?8 ‘t<Zg"gݠu>rpV2J.ìb 됱 +#D"H$ЯWpV[ES;0T2ҺԢaAiݦuIkJħc Hx, ۬fQjTJ\&Em Ɔz֟J A IUYQ!<aX9*BɼV';ZТEAZNlB!8 UsArZY.ׂ[YbST5:hX.gOh8gM3EprMuG9.8kccsk+JY26/heDb?I$D"HrE[+Zi!jөTrkkscuIsZZJ-n"iAZ3Tlr< Áq8vl4uJ)I &VKXZLhQh΀BOA:r-,- RZ%9:^Z]ZEu,Y'hgwV, -͡%+ZU-pVYSg7Z;i\Tk:d], F"tbfκq+㬿bg}vV2Jv2fV^e +WXBǽ~D"H$Aؕ뭼c-Z?S.V:J&BK #iiu I +Hk 5;MGcuz]b2tZZwJ%VVC}HLi!h!iT*+*@H ISh܇Ai+"#SZ hNZ@UU :, SgՃZZDbSP5ZhX.gOh8Msp5p ^z'>:k]Ĭ0 ++bգI$D"HG+NnZcX5@Z;XZQzu 0?7O&'h(8WoaZF^QND!jkminjCҢu>+- -VM5Hq6C!2$0Jih@xh=diqֱgurZuAx|@A,@ ;+- &pVH, +J&fv^_`00<D'cS*8:8EYcg[Yw6Yd*CBheGV.V H$D"P][YkP{ZvwvT2 @ҺIi:%AZAZ+ˋ D|*69F>uvwmVɨi5*B.JĢF@%-Νi*Z>p,$-&3Тu։i+"-YBb9\.Zg=KCkYahjEbST5:dng#ѱpt|"65g-n^v{y)v]wvw!gQ̢UY:"D"H$N":-ZH S uoowwg{!XZ{XZo iHHkmueiqanv&1=BРqzb6:Zw$Q[k HEAp,--2-,R,}i8XN:I9 CVyZNlB֙*s42z8rm8]!:JZLfv^_`00<D'cSڕn/uڕqIG̨ `M>HTAAq_PTTPDE5IK,LQA9mLO +-7cNdp=}Yκu;>Fvw}}cs3 +!fB:@V b'p8>[{؊a(j}MPV(X_IcRZFI6%kHZ@ZK YV?z}ޞnGWgG{[kK\n2MqP$\QE@=iiix\VJr:NB.ZUZahQ"bSS9\./ A+=E:kZ%+ +"D[7+*k,-v[Gwy#cq`5Zg"g]A:N4VLa"'p8 Wh؊V\jHjBMZēRZ7#iAZs3Solt={Wbij2W RmIH,Pˤy\:E)3 -VhhB"u`hŐc֡(hu +Z hShq8\uY +Zag=O@ Eb 8KPmN_f4U+kj,6[Gu#<8ku +rMYᬏhuY{6̬[YƊ,"p8~X]ܢc+Z1-ZvhҺ bi)HZW.V@ZsSqgx=uv;Vk\a2u%bP$b B:K-@ R,VR(h u֑(hz<Њ>=gup SZahA+A ryiZY h!gh9BX'JUZS eʪںƦk[p{c `jzfn~u9*rKވOgolnCm,`鬿"g!f}`Ob"+p8{zhl1ZHZ`BimoB͍^BҺ +Һxaeyqa~nfz*z=Ã>WoOfminjl(7H,PeRH#!i1EH z:- IeY))ZHZJD:EA8 :|Ph=Di@$V,$- +Y3$:K@+3+/r,_PmPf4Uk,-v[Gt<ޑ1߸?09=3;r%p֋Y/B:ͷ0r=,Y07(+h_q8pxڊo]j¥QZ {HZ[`֗HZƐoQze$AZ@ZK ٙɀ76 \jm45TW+L2T)V + +yL*犄~vV& ii~r9l+%9VXZ HZ'AHhŐc֡(hu։0iVJ +NZZYLh:EbIT&W(UEjMV7MʪںFKsKk[{Gu#28ku:r֫~݃8kg1tɬ2,beop8ܓӃ+EVlj}GQ>ˮ}gWZ"i]Zi-/-LM&}#!@wv4[jk*&AӖhE*eB.I"ayI+ZHZ -JINBڃVbZ'huWû:JB8S$BJ&F8C@ᬳ2(W,BX-ʌꚺ&Keq܃o_XZ^g]Fκu+~,֮>CZgmD: E9 1HfL1,& ; +p8w(nѱŰϤ!-DimĐ֟?}{Һ} IHKVf ب3<s9{]6k\Qn,3JbPY ϗI%\PDz!RZ-@ ZZ4i!hu]hC> YuA+!ZIZ,9sQB:EbIT&W(UEjMV7MFKiw8{<ޑ1߸?09=3;r+WY7ns8+޹r.YY?2OYXjp8=9=w[1E֏$EH+${;[%(i'Һ Һ +ҺZ\ }c#^@_a찵Z- 5UrѠiK4"@!I$b0G:-@ R,VRNƇSzҺ/hu։0g!h-.hee9\D*˗( UbTg(3:}JN8 2y6i鶝 """"(("! +"g~@ ݸ|^iLެhQ;:}Wwg:.wgE5+W_YY΂f;f(+X՛: +BP(jOkth+780iAjim^Z[ZҊgio;1v9#֡sݥi;ԪE\(ԋkEj-Yz1J! +0h:EZZ@ZZ'rsDBv6V Z:APZkڗ1hġu8 + ZQg&9ZYZgK-謳$2J3J2v9ǯkD:IT$W(UvSe1-aۨsOx)  +Gfcκv=9oY_';,,YYOS$d3֏$P( +B~HF[ JKzS J1i=H;H5LZ灴--.F¡`?z&c.}6l z݆.]g]ݪR*M2iC}XT#Ty\,ai" +TpJ+ rsrBvV 2:C` ZoO@k: +u, ZYYrNh:  +Hd +VLg0KYlN9WT EzQ&oVmZk3X9x'Ldvn~q2pօnYwܽwo}cc>ǘ 0g} gw JQVv7=w +BP(jJVZkE]Ԃ¨R ͍{޹,/Su&恴fBiԤ3s:#6eg6uڎ6E,5J%ZZq9lV)A/Q)BRG^@ J @ H @+?/7VvV&V"AhZkY[C#qhCV@+@mwЊ:Qhg- )ETQd9 +J $ RY\T5N]hXGFN{|;OB3p*p֥˘n~Y_nG `mFYidBP( +zvzZ[R)N>} K@Z+@Z sL(0Mz'\NȰ28g2tZMUTțdIXT#Ty\,ai" +Y -Zz!-- -- <-"V։8ǡu֡IkhKVb¡C+,L-)OtZB2J+3,6˫ ںzQ&oVmNo6̓aۈsOx)  +Gf֠;iw,YY^bVLYߧ(+X?@WBP( +B̕k}`Dj S m?(5 ŅH8 |^τ{小؆,~S۠i;4mjUY.kJŵ"a_sXLVD! >J|" VFZqhť}{ZQcIz B+;@$h:.V>U@*QitF Up+x*F$4HeMrRժnh;]<08d:.;9f"sKW_κz-/0ghsD9yBY[ kzCFP( +B pm^P+&-@-(-Zzpssc}=QZ_ŤCih&&kW._[]>8?7 S^ϸtجC>Хjխ*B$6HĢϫre,f F- +0h},-- -Z9D"!;B$h:Zړ:AHZ:A+''7@w μ-O +ɔ"Z1,eqʹJZ(K2yEnthuzCoXmvkl|3OB3p +pKYo܌9*Iz,Ȭg[3+UYz7 +BP(+[+=J㝥n޸u"ŅHx&Mz&\Nmj4zNۡiSZrYTR/ JS*e2Ŵ" +B hihiŠu"qhuAkgg%@+ꬃpheЊ: B+Bu4tVZ>"bF VUaH\'iʚJUk[F۩1!mp'<^ߔ? # K+kY1gݺ +zs,Yϡv`V$ +BP(5RhR VTZK/u&@Zk+K sp(OqaY,>ХjZUJEsLP_'U|^.+e0i"r!,Ђ҂:C$ 2!҂ʈB0C'nu :}J;=8"obWdu3IEoEDDQDEE<D6Gӻt33lLߴ}<6> +"B"# ^á;.h--9Bd;5-#3+' +qDZ#7(M6MVݫ7  &&3XXt.awt}?:Y dÄEP( +B}:[G¨`iǥiloaZ[]Yv..89ef<9a7{tM[kIhj*qEyHX\Ts99YilV2HQ)d16H u0hiEGiEFDZ!>: u:^ֱ:AZ<:uV8%h Zo-Z8BMILV +;5=#+;EQYRR-fUZѩ#cIԌejg-goڽc/gh/}:Y/P( +B_{!r틭#QN-/LOKMa%3tO# .iEDhBh]H BNZ;Yi> +"B" ^ pM89@3)NW KDeJIV&W465Z՚vmGg0 'S39ݱ\^Y]κv0h:=g}嬇qfazfW!6BP( +;6WPlZˏZniԂ¨𡗴>ߓG~[Z[wVW mn23e7  }n]]nU5+rYZR)./7NIf&1j<uH+Z@ZZQZZaVBh:C덠JphZ<:y.hE_ڃtֻbqx +5HJfgfer<~X(*-WI5:yB٤jQi:^8842j0OM[f6cѹ,->wWg=zv!SBBP( +BWly[ j#GZ}vw0im./9vu2=e7  ޞ.CӦnQ5) :YTR%(+ |^>Na%'1 TJ<)A](-/hiAhEh] +ǠuBZk6NA - .@hhEh]z*-Ί%=1bedfqy|AQq\\YU-MͪV]۩GLu6Xp.-gm޾u@YZ>rgA:)tY\S}P( +BPߦp+[^ڳ.-ZBi=*ϼ!.[ZZX_]Y^Z\p欖iiltx8ߧuj5VUsS^.VWUD%E~f%3Js?g=r:X/׿P( +BP+} +@kyIpj=?i}---(-pimZ_r..mYyb4:2195=3k;K˫kY;ngvY謧.gzv)yoGP( +B2=/Vpj=sS [Znilimn:J8C/gI{g6:" =.~G;[˩(/+).,ageRqX5B"##B1hҲC /-O hB;hzr1hĠuBZ6gAhy@hyh]кz +-޷B+(8@+2*@"SbhXF|3)/,*.-q[xm]݂^_<(J̬fn^hXZ666v8 @ :β2gvga^Y]uDbP( +B[.zjaz~zIH @kHkksH˼bZ^2,.43*ĸ\6* E^AwWgG[ǩ(+-.*fgf X:-B&"Bz.- Z@ZZZ!< r@4.:v(^YZ//ujh]к AE 1TLLJagdsr + +KJ+9ƦV^{K#I#1B9QiKe8kk{ZghpnY?@g=β2,w:PYHW( +BP!Z8eUZVj=Ԃ'&H WaҺ j1, ڹYjJF!@Gh675sk9U%Ņy9쬌4VJR"3>AQc$"!*2"B+HZ@ZZZ| .YN3NuBZ <1hhh]yc + &ɔ*=LJNIM/(*.-q[xmnAP/ KGeqŤR5huEqٴbY][κ}hYesvg=vgvgYxfC+ +( +BP^[=ҲQ 3~pcKOlҲCUZ;wnimZVLKEn^V)'r٨tX2( {Ύ6^KscSSUY^VZ\TLcҩ12A뺳 |1hyBh]ANqhu[g- < .hCh]ZAZQDBcYYܼ¢jN-D!tD6&P(T3j͜V7,M+f pp>9ۇng2Wgf,$* +BP(KqZ⭵Z{i>&1i{uJkkHb^1 vNQM)1وT2$ {]v^ksSC}]- /7JNJLӨ2 @+2@+8( .hy;־zc.:A4Ywк AuB+,@@$QbXF\319_PT\RV^YUé646;݂^_<(IjZ=lY][ھu:YZ>(r0'~1`e!]P( +B^SG~rHNp:\Z_Ai}f֟1iݾj1En^UOqlT:,n~g{[ǩ,/+).*ageR qX5L" n~pZ@ZZZ|<=<\uB4.:v(^QZ/-N`βC.^Ġ u +-A+8$@+*@$SbhXF|3)/,*)-ohjnw=}D:"O(S3j͜V7,M+f&p֝eu/YOs8g2m +BP(;*S&qz +JMZh*;w67,qɠ_i4ՔR1!H%CQ_okmnj(+-)*fgf$'1tj L$DGhCh]w+Z~Zvh]t9N?Xu 6hy۠U7кM$)TLLJagdsr +K+j8ƦֶN~W( KGeqŤR5huEqdmlnmCg},->zq+P+M_ +BP(uR i}Gv'.HڪlZ6yfV=RN*QР_$t;Z[빵‚vVFz*+%)ǠӨ2Z@Z6hy{yzBh]p@Zgp:񆡵Yo9?l΂u]gh]VhXxDd4H:}JN8$ g3}EQ@BF QDQDE4t4I5=vvv7}#4|}QĘxrBbNbfUTV79-m^_@8$KeIrZ5b-aκYZYZWW,`?cֶBBP( +Bތ[򤖛\]Z@ZJZZ1i-٬ѰkԳ3JŤ\&GDCB@ib7TWVf35)1CBCnߺy@:u*0 KZ;@k;>/huBNA4y Z9S Z׮h # QDRL\Z\кu@+$DIqJ`f + +K+jjMvngw? FcL>PNfNh0-Vt=-Oghg=r8 M3Q( +BP톭^=gi=_<uHkfEn^QϪIL*~ib7TUř5@% 0\([ZWl- -3Z~Z'ܠuvhGhZ:q-'NhŠкx BMP\8>M''$&%RY̜\V~aQIiyEUum]}#aѨX2.+gT9ͼnAo0V +/  :ɛ9ɬJYoOP( +Bz{n`-^Q J!&-- dMF~A̩U3)|B:.~>if7TWVrsYZrRb9>6EBCnк| hz Z:f?8-Y.hh:gpZY ] + GJ"59%5=cWV78-mή>@8$HeIrZ5huElږWhٝZvghgg}~Y.f=( +BP( +{smma-imIE-/i𚴾ZCZvh}mݕeb6yF=V*&2dltD4$ z{:m-&vC}mMUeyYIqa+/';AHKMI&RbH(B$>< |'@5 @ZNhAia:u@+-v-OgyCCZG"M$Ƒ(ITZJZ:=/(*.-od7sZ:]ݽ<~pX4*K')J=- Fj[Z^κ,-,-oxz+lY +BP(Y{֮zFm]Z/^l=z + i,/٬fѠ_i5sjՌrJ!Kģa@?hk4j++J +ř5@% 0\([ZWءSZvhi=s@+ :uց)m.hu : Gкx2֍Z!p|!*O$&%R2,fN.+?  I2B9=3huElg欯ܡ9!t+g}Y?ٝt:5fm,, +BP(Իh/+jm:!_ )g@ZOڥ0iʲj1 zݼvN=;3TLNȤё!`PW[]UQ^ZRTafe3RiIr|l 1:Džh݄к|': u ZG]:Qp Z:q-_??SZ0h}gwh}zBu;!p|$!HO$RSR32 rqu >D_@`09$,<2*&6>!)95-#3;'/G Ї#c wz?;'Kd%*pYZYjV܄z^X:땅^,D+ +BP(Ի-ei-^YJŞzj5j#0҂Z]YV*2d^,Ls&aGlokinl(/-)*HKMNJ  !>o<@@kWwC H Bbuc@kih8hށ-kk[[;h]2@k@hݺ &IAа蘸Ĥܼ⒲ʪֶ޾~ LYH,.%}-謯ЂzjL _ 22~?>LQ( +BPa-C_ 2I'~H ?h} uuEH8+O8cL}P_[SUY^VR\XJ +'} ^8OwWg'۷ 얖Z 9X[ChفiN`e߰BK,shк^кqB@"!Qѱq )iY9Eťe5uM-]ݔ^jcxd5Ξf9h^"-U ΂zR5Nepֿ LY,vгDP( +B}$ _0_1IZ:VQCihֲR!_I%"ᜀ?NMYc#Ì~j/ ?7'+3=-%91!.6:*"<4G<!n Z@ZZ͡#-K{CZG:u ZVV66vvZ3sh]u'M!!aQ1 Iɩi9yE%Uյu -m]=>*m>`sx39x^ ++ -,'OjV6:G~Yof2 +BP(}fkO-Kil֏FimoomnZZ ^Zڃ%ŢlA:/ +fyS0s>@Qz:Zj*KK +r33Rcc"B~$twsuqrwB5shiAh]r2ɽu`:c&h@.߱кrB-g-O7H +&EDF'&gdeWV745utuSzA:92gOr`N(Herr@km}@YZh=S0zg8ޤ=@ +BP(GixczH @LZZkWW +L* 3g0AZ?_ ܥfzf=m${)C%BN&^ v޵iw$@~?{yp89,V3AwsuvQ$"@@kW h ]i}|h:k_hAmhв= uqZκu6='ȎT;/ 08$,<2*&6>!)9des9¢ʪֶ.^O__01)͉%R|aqiy8 ^gml**: BkYr>zs+ BP( +{=,f/XЂRUJ ('?@iCѷh--.eRxN43-Fzx]mM 5U%E|N.;Lg&'%DEz{y]]hTGa n߂кb(-.BhBBZ'ZGBkY{u)Ah]|hݸ u='*͝_PT\ZVQY]SW &3"D&W,,.Bh8 @ 8 @km}}csSR5 ^|skcgg,$( +BP(;ck O3zZ:ii4jJ1-\*fgSq@_/ ?/7';+3#=-5%)1>.&:2",48(˓LR$"{pB}uN-+=҂:n-JYi}h0֙3V6ZKh]u#IdG +ՍHcf9?842:6.Nϊ%R@ke! >Z[_Rj[8P( +BP立)# V@Z@ZϟihH @B.ωfSё^^wgG[ksSC}mMUeyYIq!7fe2I 1Qa!~^t7W'Ց@${;!^1Zemei uZ'v>ysPZ':eYue cpxɁLҜ]^>zh'&gdfeUTV76wtu '&gfR\ +ZYZYkYJJ@gAhJ笟 zcC+c% +BP(C[DZo:iJ @K'-FR)7֠>2Gh-/-*2xnvfzjrb?62<8X_WS]YQVZ\Th-/O3J!;x--.HKZguJ:hmKZG ZuvZV:hк^h]u>')T'gW7wOoаhF3q JJ+k[;x=}Cãc|ĔpzV47/ K+!LTj֖Y2]fzP( +BPY˄ZS˜vQUJ%:K B뛇Z +T"N &ᡁ^Wg{[KscC]muUEyiIQ7be0)ɉq1ёaA>ޞn.NTaкyc?h]:ecmeeia֟:jZ(-:bc:Zgve u^ /4kZh݅`q"HAh=}BB#cSLV6;-,.)+ohjnm S™Yx^"+3p֋5gAh:5t.YX( +BPo[0ځ F+M 5 gOg -\&fgSq@_/eg2Ą計А@?-H& 8,B.k:A:f(#fub/,-uAޅ+Zhݾeg f8O2M־qumo̬{oTDA4.@H``M]&yUxxl8w3ǜfiŰwD + KHJNMcfder%eU5 Mͭm=.oh/&3L1 ZZ&Eu OZYJB8 A'p -g|Y{d~p8PK'H A I FRAZkO@ZZTi!h,/f2dF<5) +C<@0`&'%FGEx{z:;9X3,ifhݼu"Z -ZN8qѣ3:@$h#hF:Y_кvA.@̂fIgX98:{xyGF'$33rXy삢ҲꚺƦ^Nwph/MLg$2bv~a +-,S@ Tj-Y$42t֫;kߔop8ܧ*ejIZ @K#M$-hm@Z Eַ -B.LOMNFA@?d$%DEz{y89:Z34 3S]$.PEBi +:ac$N hZW"hݾ2615Y6.n^>Aa1qI)i9yE%Uյu -m]=}\@8:.OK2@kyeֶHh=~zR*rֶ~Fzgw"p8h7Qk $-h!iTZ{" Օeܬ\&L&DB PW[]UQ^ZRT`okà[,MMZwn] Zu:IBa=iZ>Mh}YzhBKZ.ккҊnmcgf K+jj[::{8}\0_ Hr@kq 6YZkOZϟ+ BVk~°p8}~ -Z:i!hA I V9HS@Z߁Z +T2# !wP_[SUY^VRTeege0Rb"CC|==\lVf&n!h]Z -3hCK/+YQ :)$ +.\$u&@@̜fi@rtr4ffV+]PX\ZVQY]SW cIT&W/VjE:K-p@:@K$T*&,ZY[73 +p81z/kPI'~DRZ{ZrdfZ<9!G֖ʊv+'+Z.NZ +KZ7o h]HH֗S:h5hn2$22:~Bshm;k #hhY, k[;-w/o_ȨĤtffvNn^~AQqiyEUum]CcsK[{gWOo_?78<"&L1 ZZ^h,ϕRt; p8qۣAZ/)zVZ-$-ZE H @{RZ%֬B&L&DB PW[]UQ^Z\TLOMIJ   pGrf-if&ZIh]ii@Z'Ơu$ZML-hVt@PphXDdtL\BbrJZzFV6+_XTRZ^YUS[D*h-,>f'~xlT*zsS,=vB_:h=(kp8 >2Z(IK -$-֦Z" u@ ZPs CzhF:FB$@ u +-&fVtk-'gW7Oo?ظ4fFV+]PX\RVQY]SW cIT&WVVIhQEB hJA-g0p8~+*פ7$-ZE EZ$VWZs +L뫹3 2MrL-*{ɽȽ^U-ْ,ɒ{6lf7``$I~W-1Ɍ5sF%`x;a1=]m-͍ uUeŴ‚LjzZJ2VtdDXhpP@_A>֭;uYsN#h h}ZG>bh}I@ZgкH@;]h]A@@@ܒbeckA/(WV745utvL6 "D*h~-,e\PTY$~#^gIfp8pZJkIwo$T*BZh-#hڄ -ĘL*a3Ύ榆ښZQA~nv5#-591!.6:*"\ZN6VKs3Sc#C}ǏZhݸ -Zg:q->Hut i"uJZh}&^#ue`hdbjfaIȨx̬¢⒲ꚺƦ޾:dT:6>19=ZX\RCpZyz +%+J_IgAҁYYXY8pj/z"-zEHWRZ5R^^<i@k5.E#0;f1}]-Mu5Ue%E9YI 1Z!A~>ޞnZv6K 3S#CC]Z׮nB E@"@ZHhul  :jg Z_k- -uo`hlbjnaiNFТU h546wvЙ, ohX KFe)-YB"bR(*r,-笃p8iCZh!iTJi!hhE@lT" +>ҌU]YQVZL+Τ$%DEz{y89"hYYZueSZ$.ZۥW@kǍ?/tZк.hx@KO܂bemkN+(WTU"hutv#h1l7EbT66195=;6h^VrRZCgwgY=6p8ܡjz6HiBhJ*@%)ĘL*a3ZݝZ uU%‚,jzZJrbB\LtdDXhpP@_@ַZߐ:8hh}@Z[RllA+<"*:6.!)95-_PD+)+ohRC`apD$'&gZ K"@ +@KP^#h"VZwA p8w im[ZZT- +HkHFZ$Z3qtT,yA6A#P_[SUY^VB+*ɢf&'%FGEoP_1@>֭;uYsBZ{]h}q-N"h>}, $Ӆ=304215X#h99yxz h'$gdfUTV76wtu Й, whX KFecS'Zi" +R*֑Bu.ڕY=0p8ܡmWj + E@ Ik}B +i!h!io$-'3ScQxD(rXL@_owWG{kKSc}]MueEYIqQa~^NVfF:V|l VHP5BG{n\ׅH AZNju֦4:BK,hh]$кz]C -,m\\=}C#b9yRں斶ή BX"MLNM>-p+\$HgAz:mp8u.HZo"z}mMT*r+-$mzAknvzjrbL&EB7a3=]m-͍ uZŴ‚LjzjJRb|\LTdxXHp`@!@. kW7"uuuV ut )h]RCK+$nh=h#hQm@+(84,"2:&.!19%-WPD+)-ohjnm3Xl7ģR8@kHBkY$^,VVW +RZ[Ggv&嬃p8з_ii_ 5Zk*Rh@Z6E@kiq5IGŢY zدϧ43S4;hFc.1wwiJ RIw"M@@:O/t6Xx us ;8P_WsUVR\XHKMNLEh +TQ;[#V&ƆݻhhmY jZEC KZԄֲ7:Fډ70261Ch \\=}ihE S3ZEťeںs M[Z=._ KãcZ gQк{53#J%: bvhi9K&"H$D"-~ZWniiBK]Z-@ T*r HݻPZк}&KcRH(q9=M ZUeEyYI Q"BZ~^.N-@k?BkNhmDhhyhKkW@kV"VIZw [ZYuptvqs=ЊOLJIM/(*)-8]UjljAhuvu qx|H,hM^-pB>@K&+JB EAv 4YD"H$ZPZo&hQhZ*B!Z _PZкqBk5"E>34ՉjAh՞:]Q^ZRTJIJDhtwsqvt8jokcmeinfjldwc66R Z+^-Mi-MhhYZ[Q :DAeA!1q)iBV35;:/vqy|H,hOb94B@K.W(Z5E9˜~H$D"HyNTZlh֓yiiZҢu +@kb|tdX* <`_oΎ6Vښ3+Zy9YiȈА h!,LM(hhm6SZZ$A3 +Z_rZ_#ф_ʂO?Sڽue2SZТ@kAZYRe33-B 5;oQк<hIDB@huu\hkminl9*+).,HKINL@h +Ch8p9Bu?Ҁ7% /(h}ᡥDZg +Z_C[wh ~BCkB@Ke:zD`ɐSQԴ\ViYB\CS !/%%ֵ7_ZZ2\PT,!A8kK"H$DEA B Z(-JPe2}JKZ7o\Gh]hH%b [775ChUUV"r2RbZ'Oz{y89;вBhvGZ -Zh};:>w{8*5hmhDhh!ll5|2_PT\Z^qr ?8"d5кrּhM#rR/Y#hg=r֋W:D"H${'jiH녖I1J EK֬JTiZsҢu*@kr5,|ghՂЪ=[]u u*",T Z6-3c#}=~NZ?0bA Zhh1Z/:F]ځ:LAܒqVxDdTL\|bRJZz&BuVG^ᑱqe +Znߙ8{Y YY kAWuh{$D"H}*_YbC (iQBi-@kBhhm +ZW.ZRHqZ;;Zkk J +ss2ZȈГ}}<\hhYR: ڇڡ ZZZk^,h}T5ZZ͆&mhmGhhh",,m쏱u" (8$4Td4B+_X\RV^ЪohlnimхpyH"h]h]qSZ,}L&W(*C h=f+8kI"H$Dmz8R) +LкBiA)T" +x\BB[kKscC}B0?/';3=-%91>.&pcv6V-C!^vmhm҂@k"@@knhhYZ[! LZGhh99yxz!N!bS22s +ZUg"Ϸ#zz8\@(HGZh1b5z03#Jj9h=,htAD"H$i1!byhI֬JTiZhh]к4 |8>3IDFMcK (w {vłLWp#$j439r\]$?|_|Ъhdb##B|=O:`okceinFBKuHC] AK Ak@k9hm Ak5ʙZhKkXZBk&m'!-mq'gW_@PphXDTt,@+5-UPX\RFA`9\!aZ#7)h!gк{OZhz +КAK4g@p8_9J%MZ/hҒBkT-"h!i@Z$nк45rLF?@VYIqa@+#- +hz{v?u鸣>@K[됦*oA IKCkB":RZFBkŊ h7l%u@IYam]r;qЊOHJNMhUTV76{,68u"@Ӡк56& +Ebd8@KgYp8;3&@Z'RhKbP(CкO@ Iׯ."h=3q,F_O7@8Z:ڇ h(+h!u -$-Z֐Z1ZKZ 1 ZG"hBtf +ZZIhi74215sp< + + OLJhkZ]ݽ}L"hh]*;2h z%E"E@ 5~Ahaep8Kti.sRZRhMi=&%DBA@ I֝Rh]u< e}]*VQA~n@+%)1>6&*2<4$(tP 6SҢ^ +U2h-ZSH Z_T]khjA$@?08$,<2:& *,*)- b0Y.oA֥$n&EB=4h= +Z)cКp8pMӡR~51 ZhzкKB[HZ$._B:5rXL@VyiIQ!@+3=  +hx{ztqQAZAK2h}FB"h͐֟t֟2h}5ZCR&uH@8@iV@+*+ohjnh3l?0xvAk֍)h!gк56& +Ebd8k +ZzFBYp8jNҒA g~A E@k\"BHKё6jmnj,/hdgf$'&DGFNhw473164hH@ۙJ9RZohDZVRZK@kf1z;;Zu5‚\VjrRB\ltTDX(@ $-=! u5 +ZZ;塵Z +Z+ZA>Zp8 ZwRRUSh70265w$hZYҲ + +Z-]-&\E8wZiz4 Z-QR-,p8쭤Z2iMhzDC-$-)^hGlBAЊh Z"Р| +ZZHhmm(): :&-W7@+$4<2*&6>1)%5=3+'7U^QU][c0Y.oA@2 ?H@ 9= +ZBH,KD +ISz^ > p86 hiI5))%bH(uH[?@A2@hZj*Z9V@2Z:ڇ:C@k)hm"z +ZiZEwLh---$vӠ:24215sp<r + hZyE%$Ihuv.AkAk@( ZZcZ"XBB_?&5'hagp8X[@c-X$BCкO@ %Z\$UOB0?/'+3= phpt07512?{"nZ[6BҚ%+ZDR +ZHhXrz)g.Z(TQUhI7@+ JNIhWV h55u/T均q|fgRLb-X{i$6:j4j,EE.RT*RC;UTf2s`:h]QBM@A-,-YOg[EQEQߺ7V 2i5AZ -Zw8hP@b S Z" +ܜLZVhpVZ,@k*-I9h5/-ZC ZCrhKtZc8hMAk:5g|.s +h + ڵ{/Դl@+DaQJ"$hyh5ʠfZhXEQEQ߼7VEh&V#z@IZZ Z:F*)*+-eK/okm5w5в5֘.CZh}b!0Ch5Ar +5ZN׺{zZV$ >#yUF[V^QuA9ZW]gbU+@Oz%YEQEQIShqzi1h=uOV-QZZ'ʴRUI1u,C Z;H@+80r^dK sScFBk5Zzq$AkZ8hc25 К=gEK:8\-o@k#9r@kuPbRJjzFVv.uRjte啀Z._ŜA6#-YOgJzF΢((ޚ^%-=h=CKV%AuAmZW.s:{AAK)UZ쬌ԔDZ{@+hy{Z+._djޜـ4ChRBkAu ZGWa{ @ Z#5RZfZ6o +hm߱ЊӃcOɡuEnpЪcк+BZ2hj{mhu(((H녁^BMV Z +h=uA }h]A4V"@ Z;l)8h@ZZ3f&F ZxhԇZ_e ?ZuځWrh}C'IFƦ~~x2Zun^}7ZaV4{>@pbrJZzfVNnUXTRjueUէ 5кy Ъ(AwVZ,(( +i=K%BV=ŤV@VEN[V/r2RZ0@+`zo/u<;,AW@g9~Z_PZ5q䩀,=h9._ hZ>V`PH(5z:t8)95-#3;uDUі :{k9h1gк͠uA>H Ehj{Mhu(((J5&@EV Z Zwn Ђ_CY2hdgf&' hm9,4$(\5 К*Bk"o:֧2h}áA@ZCۅX%ZsZYη[hx) "x=h?.VZ._A?78h1hPN\ -rEQEQTZZ +h=uA+/q:àUUQ^ՔJc2hJv"@r桵tBVsZ- 3SZcEh5T ZrgɡZhՃ5քML-,Z3ZChZ1֞Ĥ#GuFWV^ɠuE%nʡ(AKt!ZEh=CA((z[Z/z&Bh(>.r:͠UY^ӔKNr2SS{Z1V8rVP@k&p!AޝBK)ZdAOf+5[-@k hԃVRjue Z 5кh3hz,A В;EtV"gQEQEQ=Ne6Zri5AZZ8hcЪnBuJZǎʠu0> hm6Z|}==\]xh9Ƞ5K sScFBkXꣀ O 5p%FI25yi@pbrJZzfVNnU(V5u^,ZASh=FEQEQ zz$@VVuUeEN[VZy9Yi)<ZcDFZAz@kUEv lmК&BH֨5ZJh5%FCk$q<hP@k9hEZ;wZ zJTjVW3k MLfb2MLbK$KFJoK4AjJQ@vb$ޙkS>7Fdw7d8Wx @BqV9^o0>ZjC aa,AI FZJUѠ3h3hn[Y)VVNh@kmkZ+Z ZsZerrJ5PpؚZhuBZ(h 55a$SZZ ZKZ!akZZDPh'J: +:3h]uX[ZZUh^͠շ`ah@k@k@+Ak@k+@ko3yh Nhh]]V%Vu`0VZM- 0 0meZMbh5AA +Zh0諫 *ZwкA<֩|&/7; +֭ h-hI5^aZe"RVڋ%h)ղ +zuVZllFQh9{zOhhh-h6vQhO$:F:к{"h=@^ +-Yf0 0 H/-%z =h] :'VZɇRhhmhfxy8ShrrtCϧZDZ ZhbZo3hcZ_AkZ3Z?Z+W6"Ku<#V!%ZY-,% 0 0 ð6ӡD Z<Z%CVaNu23Z"ZZVZ?f(5F 5C"+ ZˡIB+6#ZI=@GZJHLJNᡕ +hQhQh&V9@Z7 +-,)(Vyh|0 0 0LdZ8hOh뫫ZZ -VYi VYVC+%9)12Z?@;H T<ܩ@m^g%j%^B- 5 /T5gdZ.h + h +I{AhZZg.Rhu6 +"0 0 ð֚xUVZЪк%V1E3he:C+@+,$h5@kq`/Z?&Mpsu(@fW/B]Kz 2 Z +r9[Sh̠Ak=@k@+"r Z'2s4|1]BjCwj`aaZ@V ZDZbh]&VV:!־6z Z?ShMW@[>WBChŠ5zrhqΒBM+oF1h@k*\KZ!akZZyh'J:*@4U* dy V%hɝ0 0 P%hKd2 jJ].h桕Er8PB< Z Z Zs)J5`og3>ZoʠŤ%˭ZY<:rB2h 5D ]\=}'Shh-`ZŠB+:&Nֱ V.SZZWAeh ը +-OEhaaa7 +F),A9h]h':U2ҏ Њڸ~֪˖fSh К`Ze.@ <8iMhu@Z5:f1h2hmh퍈⡕C$@K+eZ7#@*2Zz:aaf#ԠuO Z:C+VT^VPEfRhz{yPhAk8 +hzEVOSh fвe+4)3hcC`|"֑4 +ZZ.1h pV9^o0M5:1Zaa؋_VZuhxh]":GUPh!J?Ck: Z(ɠ5VZE)VZhAkQ"hMК +Xh @+(84IXgduVRZ7o5CJZ:g!0 0 ð֜Uc$z +*n2huV̌"hF ĠКC5EQ-[ զNZ-AZ}2h j-g7wO/_? +Y Z+6"yh%% +8huV ZZz8aafZ2hUp"URAA@HC+AkKZZ(|}<\eĠ՗A7n^ZZ+:*GO>U@ˆAkZ3h2h0hmh:p0ѴtV63Z9h]BJ +-hCA:KV#B 0 0 {ZRhU/h0PhUr?\Uq|:`@PϽP*(IHA ^K/!BB^@!k}N$}}[kfuD^ Z;hmcЊjryZ9dVWЪRY$-Zh)*Z5hj)jDjVZC8&ph&h-AkA+)9%-=c +Fhe)Vu B!<=Zwк@+ZUhmHOKIN"hmڰ^VDbl ZC8z0huA +jzO*A뉂AjBV7V~F=5CkhZ[Eh!hrC˴B!*ڙ_XϡuZY&h"hUVZSZcG՗ՍA + Z@bV sjԭ׀՘A+ 0(8U.^Z8&f +Z*Rڸx#vZ@,A"V +B!d -DhaВB+A"AvVV䪕f&qh 2x +. ZmZj @Kh+Z%eVBAB?(i%hm$h%&%g92nphB!ouCA ˮuPVfzZjrR"AkeKZs Z8FqhۻVGshՑUZ+JU ՐT Z98sh"h-2Ak] +-B!uN,-ZZhm1AkAkx0 ZujJjVU;hUUREZϻ&h}"C"jˠՕՇCkQcZZ+@+%5-Ck?։ ZqhuIu h+hvB!BE=gzк.@-IZ'\C+6: 1F #@ +Fhհ.|KC>A[-A!:8(l(D |e+8o h%(کAqZɽbm]ZvzӏCk$TVZ 'CYB!*BK'-ouZֱ2YK ZsZS9FjIl.+hZOZA#ֳhȠ +W]@sZ_A'_9shst2uF Z +V>B!|(wk +UhCAAWh}2>֫^2֋fh=cSEZhAM>ҠUh(@Z h-dZzMTLl6Z;le +кh!B!3huGM h] heYBk)ɉ bc֬^ŠAw Z ZUhd2֛ВBY/XZ4>ЪGA!h"B#GshM'hcZBk5;V^9*A!BA$<:l *3h#hMנ_~T +z:h}Ze}Zo h h Р5A6SuuQ9Wnphݲ+hB!B!kvкeVfh"hCkZzhM7f4VZB[>C5Uh} @ ZML$Bk)&hmUB!BȦ2.KкZ3Rm5Ak1Ak6Ak!":>0A5_VyZphϡ)VzVV7V_f&:fZ Zu -B!{y -&-/uZkcD5Snh51@Sh]̡3hKЪ\ZhXZ Z˖ЊWA?%Zhv--B!T,NZк +Z,u@n#9V._FZ Bk5 jƠUzuЪ >26ВZh5bjՆA AAkIZsHJi,к h!B!Kh5BK:h2B+3=-59) Z4h RՅA V jUIZe zh@iUZխj aZbZh8ɠy+Z}0!B91CJnNZZ'O@kZKThMӠ5CZA +UUaAVc:shҠ5-3hWu +B!BQA<)ZKZZ4h2AЪ1.+[% j[@kudTtu*RR2t:&@lZ к#@+hB!B#' +Z]@N :VFZj +ukc"W[@kjLjPnZ\B[hhAZ +Ӡ5Ck> +ZZ +v@ BB!|'Gz`;vvZ+shM֠V{ЪZ~ZhU hUZmph נ5CR6OQ@ !B!]ZdhA }v +ڬRZ34h CʠVVSЪDЪPUЪj Z5FV Eh1@+KV-rB! + +-ChZc՚C%:VBZ5$hՖP@ˠZUh Ԡ5-V [B!z *nS+B+SSNКá5Q@Zh WPVv2IBTU%zrh ՠ5Ck5Q1q Zh퐠uZ%h]?umq|ǴVY2c.S!7!25"2D$)HD"%"VJQM4S<k5zgϿ=s%Ck=gerZe="""""eZ졵]6Cky)hJCk1F OCk +^::j +BZ5CBVEWhU@Z,jiVZ}25T8Qh.EDDDDI/AkWhS5Z],jiV= [UZ +f hMPU~hQ ZZ5hQMV;Z5RЪCZ-C +~Y5E~EDDDD.B ZshL:E+C + +ZU_V$AR +ZehU5A Zujn:zZ Z3Ze>NEDDDD/ Z;}AkA?hՐUZ S@@*HC:zBkZ 5ahF ZkCB +:f@hխSX2*QYB:)4lܤ++Ak`Z#F[5-Yhmٲu;-""""cQBk-VjZ AkN&Z5PV_ghJCZ BT Z' A]uРZdhՠUleZG)_: -fhU| 5h3ha6CZ͚4v um +Z7xB9Zuh4BkZehP5_RZ+UhZDDDD선u7֩Z@k Z35::fB /h] Z:ZyA6 @ ZI/A hw֒4VAk ZŽgWh-Q5ƛ7th=кZ9@DZ'hRUr. uhZs hم*;hv>rc@KZ +ouZD +:V(EMZ ZozZwHкZAKVBl'h]#gThC=ZJM Z%lBkZ>UWTh=@`:;^:Z9A. ZCwhM+.9$g AEDDDDy_HhIҲBk~.)f/5h} +,к&y:Z @yZBk̄_-CkO&?EDDDDq ZiCk lסu-Ό9.uֽ 5n42AMZK< )h}@4~VGhZDDDDBK += Z?)n# к_ֽB:?N:ZкZBh}B{ ~ZDDDDDE +5_l%h}B+ҡմq#Wh]Ze~& ㅠu к^r7hpqKкZкZu|~B4$g]dM~$ڠAk]@U$%Ak{z?0NCbZfZ*3hձUZY +bZZDDDD?eZ5ZY +g%h=n:o@"YZ*Z.z]ևBkZDDDDDhZ5h~0@+ Zzhu~8f5O@R yYu@+кG5hP: (~ CptК%thc/+Ъdhճ@*:8@k4,EDDDD.JItyZ 5ZܡUhZLJ!hZDDDD 2EZ&Z$hU:-9Z +>?Z9К@+J:EDDDD/;Z@kUhUU!nЪʦXA +b*@k """""2 ZEhQ +Z;\KŠhC#E@(h9|Oh tV[ Z-UZaE#Vr A;"""""E#m]Z%h,Wh0ZcBKr""""T+CkRul&Ck5""""" -IZV+C @b\6Z}@}HhUUYZZ!5DxdnZ{%%:Zݠh/m&AkZ=Bh -"""""s9hheZ +629 hQ>VZ(ցB?9:lEDDDD @ hʼn+(t8&$ TԳ ScxBj?Ns3ϳK#XcOBk:+L!$v,bCz:ZB `졵N1 $>>C҇緅֖zZ{Bxzh}Z0ch}|Zf Ihm-CX:=К)vZ֝`]DhкZ0|u.~Ch - ZCjZ Ba +-dCLh -,*nZ %Ązu1 K/ZBKh@ٞ]Th]NBb:ZB FBh ?Eh@Ah Mh<8-%% oBk:Z0$%FZGBkuB` ;Kh -VZ~x Rh=--%BKh -Z?Z0%ԄZZBKh@Lh -1%ĄZZBKh@Lh -1%ĄZZBKh@Lh -1%ĄZZBKh@Lh -1%Ą.' X;BKh - -% &ZB bEh=LB^h -ZZBKh@Lh -1%ĄZZBKh@Lh -1%ĄZZBKh@Lh -1%ĄZZBKh@Lh -1%ĄZZBKh@Lh -1%ĄZZBKh@Lh -1%ĄZZBKh@Lh -1%ĄZZBKh@Lh -1%ĄZZBKh@Lh -1%ĄZZBKh@Lh -1%ĄZZBKh@Lh -1%ĄZZBKh@Lh -1%ĄZZBKh@Lh -1%ĄZZBKh@Lh -1%ĄZZBKh@Lh -1%ĄZZBKh@Lh -1%ĄZZBKh@Lh -1%ĄZZBKh@Lh -1%ĄZZBKh@Lh -1%ĄZZBKh@Lh -1%ĄZZBKh@Lh -1%ĄZZBKh@Lh -1%d[ObgY0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--h_',`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--دcA֓YLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0:o=ehhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z_',hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDKدcA֓Y3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hh@ױ I,f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3- X`$vEDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3ъ:o=ehDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%ZEױ I,hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD X`$vE0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hu,0z;"`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--:o=eLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0-ъ:o=ehLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Zu,0z;"hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK:o=e3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hh~ βf%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-Yױ I,DKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-ъ:o=eDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z~|J`w-&ZDZբ-KDHH$H$HD\"iQ~("HJ{gqyߙ?<<_ Lh -aBKh -ZBKh@ZB „Z&0% -% Lh -aBKh -ZBKh@ZB „Z&0% -% Lh -aBKh -ZBKh@ZB „Z&0% -% Lh -aBKh -ZBKh@ZB „Z&0% -% Lh -aBKh -ZBKh@ZB „Z&0% -% Lh -aBKh -ZBKh@ZB „Z&0% -% Lh -aBKh -ZBKh@ZB „Z&0%%Bs+> +-5=>B`-% Lh -aBKh -ZBKh@ZB „Z&0% -% Lh -aBKh -ZBKh@ZB „Z&0% -% Lh -aBKh -ZBKh@?+V#CKi0LК)ECZB JZBKh@Z:+Z%Ah -aBkCk: ahZB Mh uNh@?Z|I BKh -ZB „xuZwtWY֝Vh,ZX֌Қ@BKh -ZBKh@Z}3 *q!BZUchM-5֛К1V ևBЪ%6Zd$Bk*Z[nZ{ԧu8m[[h-n֒fZhmnuFh@5CkZS6Bk(֊BƇBk MB fCk=Zlh=+ -@h WB 0zP9 +w=Z КYC:_kh}ZB{u^h -ZcZ;Tht +!ʅֺu3.M֍j#C`\Z_ۡ#W u3NU uBKh@3T BZP>CkyuBh΅3^Z+֡>Cky;Bzh.vi -Eg Br; -`Cz;. Z ,ַBkc:1kh]zMh@%MkWZ'JVhXh(f~B41Z#s2օXhZօ:0Z;Z*fcBl$C4gh=  cBKh -Z+`~ThZ=֑DhZocz+^%BBkQ+6/Bk`CtahݚZsz oUBz8%niUhK֋vh,Z߄cz +Bjh9#vO +BnMmVZS3ȽR)pQJ))%%H$"p" ʐ<Ϭe/}}=^Zk׭H hR ׯ_քoѠU:`&CbJ5$Fhh٥ZZCRJ @OhQƖ\hM"$J@+,-""""WRhZ=}4 Zb~EDDDDY?6hҠ5Q>hZhv@ZU heZUbVQxhmSAk~jlZU*V錃VjV7ZCCkyb*ZDDDD#@ZlhqAI܆ Z$ZMhUwBZm5̀) + h-VBk"""".9:.%*5E@kaAZMhUNIhvCZS CQu* |kVSZ%jV팅VЪZ7!oR>"""""3Z&B_Xh +@˄V37:$@_1BkEVUdCL٬$@UhAkFhmZDDDDD)Кֈ(jhe*jh5Vo1 Z'yAc`j ZUV*^h V[Z=CkAuhQZ'ÆV@hZ2hUK1Z |VZbhUZA F5](bAkOIt +Q肜/XZ5hMwAk6-ʛҥV9rhРZ@ZCUZ;et* P?: h֠B5|ҝeB|:C:Z'I ZeVIa Z CzZץZVXh%2h]+um.hݯV{F[КU@[AkUZV{%wA6AOhݨVFJh@h- +}@2Bk_Th- X hCEZr(uc@PzL&^Ԡ h 75>obdZ3Mh- ZDDDD +-Yᠵ9Z Mh459bxZ=nC5СX(h]к\ +lh$?VZGJ hQ-ZNgB#a:~hu@heC&).Xh=ZКSP8/vHK hQf "Β@kG4h+,Vz3ZWAv%1[6>L֗h26-""""R M>h-@Ԡև6zـ3A ֽ94h=7)v-""""ؼ[6qhBkMz#ZiЪ}o<ҜU"I+ndzZhmAkQ 2h= +Z7thrAh] ZAUZD^h}MhmAZǁ{qCZ݀֯.hA{/>@]ZAZw@h]CB Z@h]V٨к#Uz mh}7nhCg_0A@k{:( +S1CkZx Z߸ z! + [jبZo,h͕@O Z{7*c1A(*z)\ ZM4qozƍ*uKI١uK:T@O5h}aBkI~hZMZhZDDDD%ZZ4h֏>h}ASzɄ֓:Zjк8N1JZWкJ93 hAuZE֏^h]uhQZ'CCkm Bclh5u_*h]Cu֙u;c;6>U\֡""""9+FhJAؠu[uY&AZW:#5$Zth͏@kq:(Z'r Z#К󼂹sfiК>6: +hb@YuЊZlhAkZ +Z+-""""J1%Q +h.uZ}Ъփ>h=V7Z#5%,JuXiB_')Zc>h=V%**u VZm:'5ָ̄ y h0 %Vȡ3=:ȡZ^iyiQȷde@9N9VhZZ3 hOʛ0΄0~6: hQB+ۀVu^BVЪmB~MLhVo'FȠ5;>hѡuhQ:" + ΖAkZmhu҄Vƹ ЪCzq@祤C\%JVe) h5 VZU*tBkZ[瀖.-EDDDDPЊ8}*hZ=T@Z@ZhӠU!h53JV[6XtZ\VZB5҂Z]jje@ZuCBrj.huAZlhj@kfZ:vu\S@ҧP:% h@kѠ5ST Z h kCZЪ*S6+K *h(^h7>obd Zs + +繠M6v:V +Z>i!"""" +U*R@ZZּ‚9&O?nZlhנZ:rЪVVV2ghV 5ʇVsjۨRhu߂֗h"~ÀZ{Z'CC i:^8ndUYiýޜJ-4KK41M3MS 35q!!ME@Eqb4 qg{^>yBU ;ZJn:ǡuA! hAk +hO7 +j~AJV5sh1ii\V[Z~ ZZCZК¡55dZzh1IZBB!*ow kΠ+Bcǎ~Dd#qhMq@k +~ Z~Zujs9UhUV Z[C +4|9*Zhr@돣Zh +*u B!PEZ,uUV5. Z[Zš<|)AkshՑA 3hU +ZU+8*jՔC˽m̠՛55YhE3Bk+Akκ-.-@ !BU -Y.@v[@+.6zeZá@@ꭃV{-wZ hխЪeVCZ-joV_ZAhM#h!h-2@k@ !B!;$h]( Z9Yi)55 Z}AhժЪ#@3hyzy +Dơ2qZh%R3uuAV^f/( hqh[A zB! Y9KV**"hmM $ BК41$CkAk-_o/O. ZLHVJ-RՌCAV ZEhv@k&Ak>2Z".K^i!BaŖZrrEh5V +e Z Z3-B?VZThjV**&HZVЪVcZ$@ +-VZS Z Z "VD3hmPIvShZ%nZ!BU6hU@ NBkM9ٙ)bWDE0h-$h&hMu@+BZjVc j[BAZ:h=luzA9Z/HЪZoA>:hMpZ"iuJy Zh]*Z-B!TrZJ%ZUhBk]@kZ Z}tꠅ2^7VM Z/zAi7å@egYB! h=&B)gzU]C9rhM'h%h-AkZ;dh? @=AK/-@ !BU,%:뮡uRց2v蠵VZc9&h}}wz*'z%hB=V Z3h}ջow=~ ɡ53AWVزp +6v2hTuB |ݮU5Z7 -H !B#4hݐuuU-ݖϡuA + Z; Z7defl$hNLΠ+AgdA?ݷwW>&hn +7\3ZO:+zGTh} A;'hV䊕122t:tX$-srh@Z͠eփB!JYhB +h +: ÇC+6fZ?C;7 Z_Lw,Sh=YZ +z +ZojAS dCkD_ZN.ZGdiqhB!߶*"gQE:~#h¡5Ckַ Z_j)A#-޴֋C뉊 +B}O JZ8f-@k3h* hqhuB!BAZZEZyΠ[VvVfzZj2AkaKZZ38qh}B+>z)^.)ZϻUZoe@GWn>9Ck +AkQV页 +ZgZl*.KAD[*2)B!w k;Yh0hIeZ6 3Vڪ֪8 ZQh"hM5rpV?->ݼzA][NUC+h+jˠYVO1Ƈqh-p@+ZzZZ{ :m+eQZoB!r+V:m6ZhE;CkA+d1Z Z=Uhufj +^Xzn%IKVVs Z*:j՛AkV$9EKB5J"hgdek +.uM @ !BU2uIEKhUBJZ(@+t"IZAZzkQ&*$g -Ъ@Z@ AZ}Uh +КIКϠly U +6I.CkZdhgʷzh]кmנi!BqBZ9e:>Z%hmRA+>.FVe Z Z399kV{VhMֿV Z+@3hRUCVS3hu՟O + 5Ck*Ak6Ak1R329v-IZs:hZ!BoVZdh<ց2vphefjBBlTѣ Z Z=|}<=ՂՔCV=ZA T(hUPV ZZZhbHʡ568dAk +šaV'YCZhBX-UZw\փB!䚳BZsh:(@kIh.V55!$x,P@^:ZPV -7-jĠL:ha̡5Ck2\Zb6edfI"Ak\Z Zg9m6{AAHV=@ B!B7|uZ%"Zv-?C,saZ;%hmA+!>VVdDZ9Frh fꣃV1h5UG -J Z5jVKZe0I[+k41j4&S.fؒXbJGPc1[fP"sgb]8s!&*r1ٿvdE~]Ck 9ZZR%hiuZ7 ťEТ(({h=@Kt!nAZyR%hE6phrh͑5AcHA]EhiVg>d̡iqhNV' ꡄ @k؈=}0hM /Z hmf/CkA@dXKh؃j:Ch((fY*hթ%:!؃@Rl*fAk3Ck`@k*V a:hEN2ډj-A j2zY -&-Z6Z]eh?Ck +ZZ!ZB#u6 Z{Se0hK:$@8uVmZ6[eUUuM +ZTIZEQEQTSM?^ eZ*hTWUUlnZu: huHV>Vƾ䤽ZeZ!tq*h \]+@VK zKV VꨇV7@ -5A+CkJ@k##:F@l)QBy5A}h"hQEQEQͼgw=h3ֵU:N @+&zZɡC+AkZuꦇVGhjh;@K'AuGjoZ 5|(Oo?@@k2֬9sB5 ZuX  +h n }@A㡥֋((}gUg}_tкŠuU Z'hVAL Z[5VX貥9!&Z~>ޞF4^VwjZ?Y T@-@6mJZ %@'gW7w@k +Zi2Z""v Z)i +M#N2h]tAK +[eeUu5֯"*UV}h((~jCZŠU]]UYi( hd%B Z'he- +$h$'Jh"#–Z dhMƫ5rWA3Ch} Am6Zo)fS֫z+Zl@k1*@k3&VbZʡuJ&-<ZA A((j=ZOSuG-8SZ ?7'[ؘ&@kb@k65КW +hVCKpBfw%hqiIC@F{z  hMfZZk Zq {RRefiu:mZhըU,-ch((gŝV +Z5Zh0֙ӀQ-2$%Ic +hÖhfZSc}}cIZ"iQEQEQM=C1Y, Z*ZnZ:s:V,bcvZUr@kCf͘> p-w7Wg^"Z-5bzRIZphRA]huջO~ SBfϝ`b@+Z hmh%ILJIMh+(,2-2ZDh@KZ6Ztz$AN zEQEQ\rz%$h=2w _OQyfҌΩM4~%%j5JGa *iV.r?ܩXEs:K}^|wp5s̼C-kzк @4VjRQQ^VR\hdgfZ;w$ZqVZhXTZ3ڠ5a1Ft:#BWsV@GD`- - Z#%h[XZS6vN,r-@+ +ښ Jсa@TV-VƋmbuAzjZCEQEQEu:urguV=hݗuA jkW奀ahZZQVHp? hsh-\6&zSdxXhpPh.7t@kx9օ֧>A@JhaZCZˡ#k[;ǹ/XxR@k +"8@+ ڛWPhZ +AAC% ZuAVZȠ+&ke-EQEQ={t\S-Y6h=4u3$h](@AAKTTZEVaA^nNvfFZ^@+ Њ"@@k +Zdut!ч'Zh} @}F !!3s Zj/u7ZQV@k:p0UZ^QTU1h`Ъ?#B? juOV i=zHZEQEQ_WsVЂYV{"Dhκ,B uAJ(/:־)wZ[(@+$8ou^kVrw[a֤Vf~!>>4 ZLZ{ Ƞ5Кmmcg4y.Z1"2*fs\mIZY9#EJJ**jY-Z7ZjJjAg-EQEQՕuR;3ZOdjP-5m@uCh; hdЪR)*+JKdesh%'mK9&*2bcXHhyph,^yl@k*eɡ5F[ZtCh-V/Z}871ah ť%Bk'[XN4Кe+\-O@ +@kWʞ} ZZ3hΝׇ- j+&ZEQEQTWEYEg=91-, Zwn к hb:.A:x ?A+#=uߞ]V hZ'bfZhN?VHZYZLL#BZowteBIK֐ZdвZsll:_e cZAX@k{]999 +hW* Z5 Z mЂ Zw KuEҢ((WF8Ug=84u3к @4V RQYh=rC+Ck۷%l7Yc%esmmZ-+K 3 Z8 cգ}h9+Smh ZÆ  h`j&@kig҃rW7@ #7EoIHܞhMM+(K+JV-UϡuIA juYִHz(AU-#юZEQEQT=5YZhJz(AEV7$B9AK"Z-RQQ^VR\hdgf'Z1ћ"-?@ rs]Y3O:E8@kڠ?3L4f6hX2-$4QBQzw,`͌fW­ +>sν{"w$Bk Z#6@kVN +Z:zL-m]IhZdVvn@V{gWO/@p!@kl\HZ&hКR4@kVZ@ K p8({+gZ +g=gѡ5E@]nߺ@kAK(s9l&@VuUEy)@+/7 Њh|Ih8;:Z[Y04٧u +6,h-AkVVQZG@k:v!hE72VQ/o_@`phXDdtl\BbrjZF&@tqi@70`8\@85zu:z%K$R hzRB)-MҚY0p8pytFԜtZZ,r@K&J$bZwԡu2@(ְPrXL@_o7@UVZ|:-c~}] +ZZԡ: +ZZ+ՠ'H/CkZBk;@k7ZF-3 Kk;{G'WwIV@+&.>19%-=3;'/UY]SWb\_8|,ZW]H A IkbrR$KR\NBZh=!L Zo+-L-p8܇j-}fZhB"%ˤRX,Dк@ 9kZׯ]%uAa!eC֖JVQa~^NvfzZJrb|\LtdxX@뤯@ enڨthC>ZT@K%6h-m]=-5hyz9q?0($,<2 +hWVQjh1Xl/@:u HZn"u5A֔ +)h=z@hakp8>DoxR zEsSКV Z{$Yo!g u"9-aΎ6 +ZUe%ܜ,V@+ +w1oO5h h#hh Jh}IBtk&hq҇'4h!i}9 Z_+Z(h>@됱ofV6NήnG<ZBB#bbRR3ZEKJZ M!BQqnR@ I AH,He2H EH!HK ӠR$-l-p8tF^ҠSY-,L&H"wкuS1-尙ޞ.VsSC}-@tQ@+#=5%)!>6&*"<4$(@󈇛o&ƇZ$~hDArZ*Z_́'Zӡ/Hh}EBHh} Zji#ua :~ ЊKHJNM+(hUTU546L hh]rUZHZZ"X"rZZYi={op8M-Eg4g=gB"%ˤRX,DкO@Q+Z <.d Zj*ZyYiI qQa-5@!ik +S(hGW+>U +BҚ֏[ho`x @Q/o_@`phXD$@+*.- b\A,օ]AA BR ZҠ ^p8p}&g9YJh=hI ZZ#EAk.^@:q,@VeEYi1@+';Њh9u􈻛)@C}= +Z; hm6k +uh}4CkfhAZG@knhBڋoeLB{?08$,<2:&.>19%-_XT\Ъolhuv1Xl/@:7uiHhh!iDbD*hҢӠYZ p8Y/R@ GJh)ВɤXuIh]B9%8lchX_W*).*h$'DG$hogCB@_Ak/.ֶjD@kUs|h9CBksAK AKet’-Oc>'ZAĤ̬VyeUMm}CSsk@`ds|pAk5~*@ZZ&EbD*jКҚyialp8z z"5-\&Jb$}r*\h"h |.d Zkk*Z9Y)I1Q!A>Ǽ=iв0351>lCB >Z@kd@k) Z^ZkZ4Ak@k6-ÃFHhY;89yh + h%2ZKJ+ hwvLsw;R:S"ťOHBqwwwwwMv8Ā5~ \~w7+ ~=КhRZ\z$J Z][JG +Z6PZ4+@߲ڱH$D"H;Wd\ :8K +Zk'Ybh=ZZ5;Кhq#,BA +Ghx{qqr03MCK[AB@6-BiQ'bh%9 eUu M=||BB#bbRR3rr KZu ޾ 5Zs4~Kc*@B! -ZBh~}^Z[$D"Ho'c/t֯ +E쬟Y(g +|> ZEh=AKhhZ09@h56!J +ss2SZ1Q!A>^ +24Chij(h]AhAK,1@k -t֛Ғ.Yh/(h},Aa1@Z4 -%U5B趉WwVB+"*:6>!)WPЪoljiEh3X#ѱq]rBiVZ\/6 !֛1D"H$i^o`Y46ZϤz*<wgA](gd54Ah45TW" + rZI QA-w;N6Vf&Z:-5U%Uօ4FA@0@ZSH +ZBkVz}g:ޣ =hEh헇HkZ'OккRFhii[XY98: }CZq ɩi9ʪֶ!5к7CAZ(-HkumM -!BKJZ"hߒkRK}$D"H7&噵E9K -ZB1ZO(h$ZZ|HAk@kf twv675TU r33Rb##Z~-gG;[k+ sSc#C}=]m-2@@" S'ڏ+ZPz OZG)h}.g(h]h}OAK]S&B@Zn>~!a1q)i¢ + +Z-m]=}!&khz$ U#@K,_ Di(iВ"@}T$D"H|3KY +ВrZ,8K(y\.8 8kZPкwwzjb|l=2Dh55TWV!r2Scc"CC}}ZN6Vf&-= ֹ-uuu%%v; +'"hmJ -%U5-=}C#h{xy#C"cZi9y%eU5 Mͭm]=!&khMffih-mJHkyeB ECK,- v&-B-D"H$La$98 %y<:@k4$Z57;Кhq#,c /';3# pw-m-M 5U%Uօ46%qhS?Ғa1Z - NuuM --m]=}#cSs +k[;GgW7Oo_蘸䔴tV~aQIiyEUum]CcsK[{gWwocfsF&&Zs BiZkbh ih ""H$D"+;kL,ZB1Z-p<ZSc09lokinl(/-)*Gh$'&DGFz{z8;:Z[Y"TZZih: u uuP-Uh풂DZ=hEh?p 43.~}}Ii{צRmw6Iƀ1{=l0` 6fӻkC 4R{%RT|?۱ I\O-3s K+kmeU5 Mͭm=}hD,&)jF= Z\Bк 2@ I A Z$GHZHi=62p8ýw;kh91, +ZGYZBh#2@ uAki5Q) tL" }=ݝmM 5Ue|^q!悠ef1ккBB9ShucZG :LA,*h/qօZWZ7iVtmkZQѱq Iɩiٹy"QhX,IjZ=;7Z^Y%AZ$@ZAZ@Z#NZZۦz iakp8^k{>e m +Z~D"pp@)h- ՕeܬzZTeQxX4(A+*,fgf&'%FGE쀖-ɰ[Yn"h] Zg :#RzZG>u齠u2@@9Šn`l\\=}C#"cS3s EҲ.-dtL6>RMϨ h}ZHZu&@KChZHZHi=>M-l-p8i݋YpcYYZZ-hmY;֝9̴jjR11.  +:Zj++JKxE܂ĄȈ?_o/wW'G{;[aMh]h]N:AA&zO-iAZ(h=Z_htk&~A+>1)%5=3+'7-*.ᗕ#h76wtu CdL*+,@kq A.)-Z@Z76Z[>DhCp8{qZ;"z%@kuZHgEZZhͪgT)|B&GDCB@_owWG{kKSc}]MUeyLOMIJꌠf1m43u:h=qSzh}t@hag/C Izh}) -Z}NAKW-s K+kmk ZQ1 IɩYٹyna1_Z^YUS[/ŒQl\TճsU#EA uo hAϔeoϒ־p8ýߟߌe m~ 8kzhAkue5?7V)'qtT" +}=ݝmM Z|^q!鎠`of1l,-Z_gOAc=ާFzZzuYSh;OB +@@fiEa0ٶv.n^>Aa#c22s8Eں斶ήdtL6>RMϨ,@ZF"кhmiBIO~AzZ[8pWSiz#g8롖 4[ =-,#hZw3ӪIĸllT<2<4(lokinl(/-pr33b"L`gf2lV4 ZϙBOtHhkɠuZi!h6@1ZZ'Ih n2YXѭL_@`pHXxDdtL\BbrJZzfVN^~_VQY]SW7 FĒ1lBRfԳseZI A Ik}փ-jLRz0p8p\OOSf=M9KKh4[ZZ,ZO %ܬzFR'd1xD4$ vwu45TWVKy9Yi)ɉ q1ёa!~^.NZ,&ÚneA3uuA:uu1#h7ZoAk_^ZGu齠u2@u’nmd]<<}BBoGF'&gds<~YyeUMm}CSsk[GgwO_@8(KFqbRh/VVvB im4}HIK- ZHyp8{y0kZ:gB"8k +@ka5RN*2D<, +z;;Zkk*B.'?7'+#=5%)1>.&*vxhHPŴ[ZZׯ._ArZNA ~}?}q&KbxY.{ @{{!$Bh 0vr˯ml;]Kߟ ں#^z; ΡuZ':OBK_Z!hhQ̩4K=_@`pHXxdtL\|bRJjzfVNn~AQqiyEUum]CcsK[{gWOo khxd3>O "T&WZ"EJ Z][h)Uj9@K'HZڇp8ph_?s9݇95r@kYZZh!hB"=@kqaˤbP0Mp9c#l@oOWg{[KscC]muUEyiqQA~nNVfzjJRb|\LtdxXHp`+ݒF57 h]# oلֹMh|e(v=i ZhF:G@  hhS-, -'ЊOHJNM+(,.-oljim`C#8o/%Rbfv1 iBZ^iol(U*FEJ^WZAY p8- ~WZgB:oYJhYgDB%B.$ob}]-Mu5Օe%ŅyYI 1Q;䀠Š[ZPM)&n\GкxAZ_EB,@Z uTZZgY:h%ZF:KnݧQ-ht`PHhxDTtl\BbrjZFfvN^~aQIYyeUMm}CSsk[GgwO_?s=4<:OM ELz8-$-Hku TjsRZ$A:0p8p[HI,Z"A VJp@krZ'ZZrT"NO''ƹcCAf_OwgG[ksSC}mMUeyYIQa~^NvfFZjrbB\ltTDxhHPNR#hDк|i'#3$t:}Gۡ{>ASN h}\hݺ 2153Y2m\{zEDF'&gfWTU546wv #c?%\1ZX\"㖴@Z+ uJ iI[?jZ=8pݜ^2pߵz9 A QTup@$@kF!I"`ϛrF٬ޞƆꪊҒܜȈ_/Ow.NvV K @-+A -N:Z"/h}L@LZ#h߄֖Hh]CкТSit+k;{G'^޾~!aQ1I)YٹyEťe5uM-]ݽ}L{hdMBD*S=h=iCg յ5RV#hzڔ+CiviJwd-p8u>Y:YZV)Zkg-,}h(dRX8-Oƹё!69X_WS]YQVZ\XڊnIQZwr&#h}:fFƛ:GB w."h]к{τbjN3ml<<}BB#cS22s K+jj[::{1?%R\К_XDA_ZZ :HKRkHii!hJ6iZ[8p`{|з0K788 A 9KZgL@KY? h-.rT, +qkP_[SUY^VR\ᆠ`okc͠[ZPM)&n\Gкx-h}5 sZO266:y:>@w;ZZi Zhh%Kn"hݧQ-ht@PphXDdtl\BbrJZzfVNn~aQIiyEUum]CcsK[{gWOop'xSiX"+ffZKg UֆVZmzցp8p~K-=g!hi46Y,8k;YK\*S .gtdbtu476VWUde$'&FGFxy8;:X14 )>M˗v@/ hZY@K#pOgZ`QZZiieDB HZWnh[,VֶvN.=}C#cRR3s +K**kZZ;{졑1$jZ(Her֓_WVZJwSkgj푴f $K{)b/! @u ;v +! 8{|P쪤!Ҡ/Q˸P( +BPCØ6: BkY; +\&J"-]asi:mr|J&wv675TUdgf&'&FGEzCh]]NZhݺiZ_u @D?* +ZgF۠uZuBD - K++ҐZ!>sp8cqx7OR3rr K**k[ڈ$rWOo0e:>A2Kˬ/Xh=yLZPZ/R\؁ڗ;~<\Zґ +BP(04eY?N,-vrL*چҁֳOք>Z^b.3fgSq(exhL 476VWVdehAǛwa1v6BhVBKYк +e:wS!Nh@ZuAZWTu.# s{z||C""cRR3s + +K+kZZή޾ +ulbFe-0YlEZu5HK&+% -:ZH\( +BPXw:k8 B 8K!ɀYZ/ @kC&y\\cNicT@_owW'X_WSUY^VR\XCtwsua0vZw@h]NZ~֕}hBh]ЂYJhԀ։Zguu@Z@Zк~B}-;{3E   OHJNM/,*)-ohjnmk$w SF'iS3s K/X6i@ Jk%X֮ZZo?M=:P( +BPЙԻ=]gi02ꬷjg%ohz -5᪀嬰fghcnrgG{[ksSC}muUEyiIQa~^NvfFZjrRB|lLTdxXHp`7uv8hݿu'%.hYuBK--=hKZ@Zкy BCk[{G3w$xGDE%$&gfUTV546;H䮞޾Q}z1\\f9\@k]\GZJk -X"rŎJZZ@ZWI#Y_Zҷc y BP(Op,MglY?BK\.J%b1pphm<.Z^d.1fSёޞ.2X_WS]YQVZ\TMpûG{[ n4кRB~oYZZ23*h}Z&ffVVZW)-w ;b8@PphXDdtL\|bRJjzFVvn^AaqIYyeUMm}CSK+IP'if--23t224M$[kk*J r2SSb##B}}<.8֝ZڇU-++K %L @ܱS: :к]к{@@squs"GF'$%edfWTU546;H䮞a(u|6Ee/0Yl_H @ H+ m iOǓBBP( +B} ~!e鬟8kWYYZ/v3-prج%ER{{Ȥb[KscC]muUEyiIQa~^NvfFZjrRB|lLTdxXHp`qвкwB5Mh} +ZWtuAZAK_ZuBZ': uVZMLM-,-.+7!?xdmckŹ<< ޾~A!Qѱq )iY9Eťe5uM-vRgWwo:61IO0晋K, + +E@ZRJ&뭭mX"rŎZZozoXZǥak!mP( +B>RF~seYzv֎B.Ix{ @&t66DUo+s{fH@EQܸ Q\ """""bIzN{iFqiOz=ch&W|?jI Έ1.b 3zΎ榆ښҒ̌䤄ؘHJxXH090ߏKpwsqBEsh}ZglmmNAuhz;hig}ha2i- -+r M'BB#(Qѱq )iY9Eťں斶.ZOo_0k3OLN gĒ9lAXRԚ-;Z_J @ J@Z~z-g&zaUZvBBP( +BG\>c^8YZ?Ch܄ze⬯^Үh*B I3©ɉqw3uu476VWUSK +ss2Rb(!A@@B벳5h}rB90g@ -`:Z6vvNNZ0hJ BU-W7O/o_?)AOLJIM+(,.UTV76wtuLO +EYt^&_T,5PZ8ha>#Ci=1J)^Z0i=7 ^Za BP( +i, 1瘳'Yqzp@K,h\j˪%Ţ\6/̊ESIf1}֖ʊ2jIqaA^nvVFzjJRb|\Lt$%",48@'x{yzh]e, Z lm NA8#8hw=в.-3h6BZ'͠uV- -h]u:;G + + DF'$%edfWV745utv轌agtǟfĒ9lAXRԚ͵[@ZZ_(Mnk{{gJ'RZ/-^BBP( +BY>2qKKgfY?AglootY΂z!nԮh*B I3"76a  3zΎ榆ښrjiqQA~nNvfFZjrRB|lLT$%<,$@#_кxZY3hAZuBN;8:hҲ%g.n?)AKHLNIK+(,.UTV76wvz}a{O +"D://*evH0hI{PZmIǷ ̨uI[c( +BP}78Ok3wY?9kK 9 欻wngjW*bQ.JfŢi`?㎲GÃ>zZR\XE ">oOw7ZΗ,'ZglmmNA(zh}֡Z¤eZ1huU-W-//џ@ + DF'&gdfWV745utv轌!&'SBьX2'-KJZZCLZzhAi}JAZ;;-ziPZ[( +BP Y/q;W g=18tp-C 8k@KQK +L:'ψS >olf1tZwgG[ksSC}mMUeyYiIQa~^NvfFZjJRb|\Lt$%",48@'\^ wZ1h9@=.2H#AZNNZA zh]M%C)Q1 IɩiY9Eťں斶.ZOo_0s='ixvN://*eF +Jtm FiYPBBP( +Bo|ue0wtkgmot{ze/VJX楒YhZ(@_oZZ\TI  &o/Ow7WкZ\sZNNzh@h؃q ZGp28?ZFhA$BhiA%gZ?)AKHLNIM+(,.UTV76wtuCL'SB̬dn^ W,)Uj͊vuֺ^ZxhaҺHk ]LZOS+zn)~BBP( +Bs嫃cK̝s/zg=kppC{;kڪvEV)dvF$Lyc\g{:[[j++ʨ%ŅbΞ>0_$s_4fO^$,  ("d:Yt.v˾PdQ3'y3'?7'+3=-%9bF04*J +!@h=Zw@hݰ@ swкl: Z>.3Ah]+<hieZ>Z~Z"L #"YQN7%5=#+;7#q|RVͪ5 Z~ɰb\5o<҂VZZPZ/_i}YZ>B +BP(ꨎڳa+gjv֏owwwghgAh8-ଧUaI.hճibR. Eޞ~; /7;+#=5ÎbEFia2B6C, nкi;h]:A+hvǀ#en8kZ7ЂҲ@ -")F3",vtl\B"_XTRZ^QY]SW- G$ұ bJ9R/huKim}@YZhY{(@ZiP*wvڧQ:P( +Bx:(¬gqY吳6^CgheY6LƕeÒnQ0?V(1dD<48 twv45TWVdgf&s9ql3NQBID>8(@C-/2C&5-U3: +Z:o% >;-/CZh !P2J3"蘸NRrJZzfVvn^AaqIYyeUMm}CSs+%ÒQL>PNfNdX16b҂"--LZ/~0iSkϞZN[- +BP(Iή#u=f}~z9 YBhazfZ5:f^=V*&qdX,:榆ښ‚쬌$NB|\LtӨr() +z@{v.Z^Z:(-вJ,&- .@2; uB H }| !DFGD21q IܔԴ으¢ں^[' G$1ل\15=Rk:ayhZ[^ZJEZ[[;;o~>KˑZ[\( +BP{ީ3+N䬟lomY: @Y_hg+nQSf ٘T2" zݝ6^KscC]muUEyiIQa~^NvfFZj +7)1!.6Ō(d1 ZwnCh] .@>ΚeuI_9xhr Z .A Ah e'-")F3",vtL\|"_PT\ZVQY]SWkwv z"dT:.O*ӪYfA/5/1i@"PZ޸oPZHu\k BP( +u|ǼIJY옵ߡ~s7Y[u-Y_hVˆ%NSϪIl\:*}=N~; ?7'+3=-%Ifp5J"AZBh9 -k6кb Z0hq֩ -iޗKhYuuB H0@`B %S4:#"ŎO$qSR3s + +JJ+k[xmnAop@44<"&)jvn^] +յuLZZ_H @ /^DZԲSjX[r BP( +;mtx:*ˁYβ2z אָ0gW zݢV3?7QN)1ddxH4 twux-͍ uU%EyY)$NB|l ;Өr(1 + }@{v.M-//OU-i[hv'y3.CZ8 nhi9`P0>H"S¨pF$3&edfUTV76]AxX2:6.O*39͂vQdX69HJkssk{{gJcZGY[­ӧ^ +BP(s38(Bкaкdyh -bҲ@!h]A@:-3K BZxJ̿دӧ4/4g$1Й}(*""x"ފx( (ޚfgҷ=6mng:io{|L촿_n&/;'/@PX\RV^)Պ%Ʀ6yKQi:а4j['l3sť 71i({@Z_C($iBjX [ +BP(Odd_Hz Яκuhκyc8kc}ueyi1?7;c[̣&Р^{T.EQZ/׊e%Ņl^&f1)DZ<5ue-wg:u@$ܠu;--Oh~ Z!։ Z0hiA C"c(ZR2ds2|~AaQIiyN m]ݪ^_77 GLc Դm>XX\ZY][߸u$?¥uJ~%Q Zϳ_m!tP( +BvoN™Ĭ_Izg} uwYhaڼڦ1ӈqȠkԽNEE$mTW +KK + 9YNiݿͷ>|P;HBP( +gwk>VS<>7;9,-g@ :p҂c>;c[̣&Р^{T.EY(kE"AA~^nvV&NOc2Rɉj\,%@+,@}@7!h +:,KgrhF!#$h +u@ 0h]C'$&%0RXlNF&/;'7/(,*)-VjuiUޮTvz՚~݀0d1-iی}n~aqiyumHkk.-3BZ_]ZZPZi9EaV4 McɩYcaqyJ&&-.i$i}CZcC(-'piOvOm!sP( +B^8?龝~,0f=œ}8 gœy:keyq1oÆANS]y[kQZ/׊eE~^nvNg1SSɉXJLTdDxhpwh6sZO@h;*--Oh~ Z!"uB+@Y- - Zph]|@+,<2*:&6OKL0i,6 +KJ+Uq]}I*oWt*UjMv@o2̖ m>7X\Z߸uCZ~I_iarI!-Жn!vP( +Bg3%)pg="9 0˯`rw--kYK9mz:a1FC_Uu+;YN\#V +y9ټL.Jc2RIxj\lLtTdx֕˗ph¡֛ZgNhBh"A0A ZzigyCKZ{]]: +A$- --(-' u58$,<"2:KO%%LV:'UTVUjŒziMޡRzz4Z~0l3OXm96!-->ֽ])-'~ލZ>剭 +BP(~ }Sì fz"E8k{k8km8k1gMOY'c#aà^]y[kQZ/׊*+J + y9Y3Lgghvv/if}~045tا1idx0hԪeE.k6׉E5UBA9WZ).,`rs,*L$dgC+Y_JJJЊA+ZVh3AhBVZZ@ZZ@ZкA+=#H"ShtF37/]XT\ªjQ^"m5[vUgWF۫4Mqfs8\n׷{֓K JHi}V@ZGQ+Z؊qą4BP( +/(o( +Sk;t֗AghrO0gX[]Yy=nׂ17cY&-QӰ08Яj՝vU,kJŵ*a_r9 :-J&331hAg +Šu@+@2 AhBL h_@:;i: u. Z!.%&%hh]:;@ZZLBѳ\V-ʪN m[mKӣ Cy21i9܋GqiAhEHi}"0jiajŰVr BP( +(Jg$Bɬ0fa΂NjBՁpǏBglon,/).,`rl:J!2 ZYwC +Z)ZII .AhCd(ެ~~{hK @+B+@+@+ @ H B+\Z{?I$QY4:#gqJ2BXU-KfyBٮTwk~8l5[&6̜ùr/z}K+k[PZJĥi4i}K.cZ1m +BP(߱M:aeAf,qgu4g}; @ 8c@gmm,nׂ17cY&,QӰ0j5NUR*o5J%ZQuB/qK8E<3AeQ)$b&!0hE8 B54dDx-Y; Z'A3AhBVZZW1hiA6VH"S4z6gs<~@XY]#IM2yM١Rwiz}:a8b2OLNMsע[ڽwևӟ_+oBQ屨V4lֱɅBP( +BEʰ GV@YG1륟Y +:C-Ygmg-E¼cnn3FCOۣR:mI j+r>).*`rl:J! -z&UT .u>31uh: u. Z!.%&%hihia¥] B&DfѲ9LV^~Aa+ *UբںzQ,oU(UnWׯ4GF㖉)}fw=啵LZ?'~i}CZ1iaԂֱBBP( +B,@F,ȬPg<>;Hg=ysϳv;3iԄe<:2l4 uZM]h7ZQuB/qK8Ey,f#E ଻~h֍ZWRS/Ah] 9Ѡu2Zy:K4&- Zq~hЊJJNIM¤-(- Z"Lɢѳs|vAQ1[ 5"qA$);TmN?08d1[&6ùr{U -LZ{Iiti=åQ/VBu[B +BP(ԯ7!cEQV,f +8 0 wֳzY0gmg,k阛۬SQӈqhp@twUʶI j+r>).*`r9tZL"21hAg +B 8 5ԔdDx-Y:zCu +֙ uB+- -- Hh҂$~>}&I~&gtvDADDDDQDAAP9O<0>m;}G_3ƻ$lnfg}64}S@3E,v + **FZ'7(MMۡ4tMfop<ޑ1߸?09=3_X iiݸ u ַiazZIA[zsP( +B/KیGGYYYvgAhE=ଛ7VB ٙɀ76 @b6 mFݢjR*:iD\%Ve<.*bi|2pu<֙\ Z!NFu" +#ЊV[.f1*% >- Ν $@8d"8WցhEuc8":N"@(-<2Z@3E,v + **FZ'7(MMۡ4tM^k_t y#\paqiU(۸>ڕ_ƥVZQiAjEkEDoLsP( +BPd;ψJ,Ȭœ1 w{8 @+꬏ǰnCg]κ LFG=CAg5݆N]MnQ5) rYF" +2Sf1tZ5Zo_z V6VF)BVYuVYDhšRB#QhB$i-VV.zH+O &aH\-FeJݪib9.аwd7LNC@Z+@Z7oa71¨Ri*j%.J.. +BP(T\{lY5OFkaY{=nCCۮimQ5+u_g_i d1&ѹd3&HTPeEEEP\qML,]to/sڛi\72s</JLI;Xci5*B^%E²RA u! Z/:} +@aZ'RulhLYO C1he&uVBZZy,6҂J֥BDP&,I2yBlolj;]ݎ~аkt=1Mgٹť+נnAiݹGhQHk;UZZ0jJGR-2Rt!P( +B=x+(̬qfJu6>@+欻wnAg]ۼrycmu%07 +| بkxhwZMuh4jZ.JD2AI1WXp B+YZg!Nr6ĠpqheŠuOi:L@qh咠O-`XlB H+&dh]*(,Ke +X"UJF3MkwFFo? /,WVׁiݸ u;&>I z[H-LZ~ܗZ)JVB[dnQ뷹 BP( +"kL: bŌEFV\Y1fά f 4?96tYWWWË LGG\C>GOfminlԚ5zVR*U2D, +J :sBaXLNAgQ ZGhNց?Z{hʁЊI @dl- 3g0h%I ֥BDP&,I2yBhv'=ީi _XZ[߸ uJ7i>ҺGHk7Bi=ҢֿIZ(' Y BP(Yo œ$dcJS#\Y8ҙ:+κpCg]ڼ0? +S^{l5<8hok675՚M5VV)JDTQ.,y0h%9 VYS'lɠiy8b;tVt־: +- + =?hQH+Z$ieƤA8VnZʃb0Y,-.&-2Cih%R -X"UJZMƦkw F^ߔ&_\ +_zJ5BZ;YZ[;;HtoJ R+!-Z?Aj%YQRV([BP( +z.&_q:Ҕ IYY?J8 0 :ko/loevֻz :k+``?NNF]C^GOfmijlԚ5zVR*U2D,*yEZY瓠u4@b2tpVZZ heʊAB9:+A0#IpOihi"I B"_ %,2yBhRfw8CQCs K@Z@Z^z[og@ZIzKDEe"q+\OR + +BPQ|H|b,YڏY?;Yଷ*t׀6fCw}n{gRk6ZZ*bQE8κEvsZNrLBD +rhŠu4hֱ8b G1h9\.ֹi%uJ @HKPZ&,%RYZRkuzd76X[mnGos`p52x`hn~a1 uJ-\Zo'IݍDPZ82PZJp+[BP( +3ć(04e,,YYhdwwgs֛n݄κ +^\ )gr=6p:VkKSc}l2:ZWɤ\XV**Ђ:O,g \@p-YOt =Whe4ieƤA8VnZh4:d| -Z iaк/. ++DbiZTk:C\kohln;]=~аkt=1MM@ZK5 M(I\ZAi}흝H$I wTԢV2(d +BP(u$4bEtf}1 w`^4ں pWY$Yw g݀Z[]/g3S>{l5<4ut;mm֖ƆzKXci5jJV)*ʅb>tE Z g:ufaТѠH%C+VV ZIL:`:J@+' Zy4:dlH --\Zqh _,(-ieZRktzdoljwtڻ{}!Ȩ{|Mgٹť +(븴n(/Jqj%TkEŭ$o.1 +BPLeN<06vavAcZڅBE `6v;[goۤxIId:mg)z~$=ZNKǹ᜹~/ v#YLe4,䬿0gmt~{YwnݼqŅh84;=ƽ9[,fѠjԪ.B&Em-M u5-ײТUU Ъ +|>٬SZY(g:vV.LŔ@p<_ hZ - 0.j[ZENLP`1Ylvǰkd3MP$:pyqie5m;w>`i=aH+UZ9bb+b*JM/D"H$ҫۮk1wT ,vgr,䬝YOqgY"g}uu兹h$4;3 '|1ka Xz=&^Qw +L)476Ղ.Pb8 CY3Zr8l8I /=C!#QB<ZHZl6 +-ֹ_JC5,-VMm]CcHC$Here[&?`;gl71N̆#yU-۔>ci=FZidjssk{{%-ZϋQ+Z*ƭqT~S? +D"HW+qGd)Y)fagloomnD;~g}嬷YYWWWYHxvf:y#.>dZ&AtrT"ujkZ3E9 U]Uy\.FʁVyZYhg)p֡gh|ieuQ +ZXZeHZ'Ңbs8\%hς0ҢuU[WjimkwJr[ or ;]nw LMτ‘ť+ (iZiA:Zebb+,rU\oH$D"^yS2+ hc1T e]FJ;+ZY`gO9-pMp֕ŅH843=ƽ9[,Aը +T)hokmgՂ.P:ֹ3-!@r8lVY'ʐhhuZK@kCV9ZHZ-6h  *@ K+XZ/ՀAZ"qT&WtZhYlvǰkd3MP8:7 +Һ{%%#ZZ D2BF*Fʷ[imeV!^^$D"H_FŜM|bac1 /,mT*gmze gq p*8\4 +>gt5}QӪU] +L)uY5.bgBrVu@tEPr9l-pZZ'hh{u Z iu,-- +ZeZiiQ:hB!@ U}ICZi7Z;DLR5Zh2[z!q{}l([i#i.- ԢI)Vurm䬫%p\$g'1sa Xz-=&^trT"uYrEA Ъ< +|>٬S*BXQhzIu8 +u \iXlaH +Т_SҪi5ĝ\RkzdZlCv5y}@pjf6suw7i(iGj=ytm}}#'HZV>rO"H$D"b+sVefk2@*`r0+L$Sp֣Yݜu7Yٯ<lfcj{d{UlM.mR'":e %[ņ$3B6d_>SsY,y>/?wfɥǏ&'|ޱ^O jokinjjҒbYH9hdg˒$ +q,hzYVhhwgG:H4A,yA%Y A,-@*$i746BZNW?084iOLNg ťSBZ $HZJkiZH4޾{ZZY[&m%e!RbX,$|6Ʋ KSVY31X,Yp:9kUsk99#re8uv8kn?=91g zz].'POΪ(-hYVa@K%Qxs8^5A+sڳвZ{O*-Z-, JhAZGTi:IUS[W iut:]O_Ȩ7>15ퟝ?~ba*>$i}HK[iZ@-H‘h4}SJj[+-M[:2b_,bXt߶JK#j8씕Y?nomŢH +YwYoiκT9CYUg\\8q|~n?=51  yz.ggP_W[C*+-!gn,@+?$IY-2 :9;Sp ^VBZUi)RI2@pp gɒ( +<9$he_VYVhh'-$A2J rp/$ِVnUxDZo+HZuVK+儴z<wCZ2uz;.Oi]IH뫯IZ +tiVIZGQ랅ZZtj%[ˌ-M[ oe"WzyX,b^lQƁ~<"+YY*ZuF#0 +VY+7tgY_uEq֧qg g]E8k~vg{Fᬁ^O儳Z[:rVEy9 h<@+';[$Qxsd:DR:+ 6leAZ z%!LZ'h98DQe@ /Z*.)%iUBZM͐VGAZ#c>Hk?3i-@Z![$IZHVBZuAHk3ѨuמZ$j%[+[FmŹVR+ez,bX}?s4ʸ4beDVluWcV`u[qgY8r䬷pi8kΚOYёa8v9;;&8UZRl,ZVa@K%Qxs8YI$h)Ҡ;kYiTe@e{heҥh8QlH+7*HkҚIZgRH Z$-P +u{u5fVJ-Z-J–U[qoe6bX,z1J___N2)뾪, ":שּׂVᬛ+pk,H3E8kΚ|p0 guYmpVcʊrrQ3Tg +,@K%Qxs82ZqgV:g=ShM.-Z Z*HZ +HZ (Ir6 iZv*)-SU[WiBZN!i AZ^Hk +ҚӥLҺHҺl֕diTi]%i݀@@?Go\Ey>$gHA$IRͶ^’[Ve!r+Ɉcasm4PbwxR.WVW]ԺߐZbؒes .d/((({ʼn!+JYPYf]vuuR.J,p2:kq; u>gCg[ଓ#]Ycଁ>abgYiBg1hZ%%Ag iE@˕ -.-:@K WTUu4H9 j}KAK@k VwO/Jkx5ҚAi͂NNz=\Z_|)ŨeK \ZY)W*WCŬuMZ [lqmy%ghyݡ^?EQEQUsQ>˔ō0"˧QY7n8̺ZWVY|AgBf g}E^zu +uu5ΚgMFY=Y[Z~àŜJ%ZekZY Zztw-Y5Ah&Z\Z1Z(-EQ5M7 ӲZ J %B1..&!$Hk'Jk>!qS(PZTWZBZHE2P+/%j]e[ ֺ嵖֏[mܒ5WBuREQEQg5k27?ldŘŕrf]U,,pVzu,Y_Uu+YOEggMN:;e; JZei|Њ!$hm +V5g3zKKVB/x\QUM Ӵ fVK+B+(m\Z(q(= AZjot: lng%,4t]SU%8C6Z/hUVuhҊ|j+1iYVLZ\ZhmCiviGiEi=z֑k5I j-ә%VU,V"V4ln o9+]w0((ꁯ=GS'3VʊbJXfYK48k~;7595YϢDgEggޅچAgpgm B9 Ւh556&,9KS%βChΪ Z[gUWZ$h!Ҋe HI %ήn&aJk5:z J0iA@ZZ(-P+iesyj.Zdn o9+]#((U~J,[X.(K0kǬ|. dY,`s2+sKgYOfY3謩ItsVwWgZp@+g,UǹYh gI +8+-Zb(-@!t0AZ $H Ť +JKk`Iksuu2\Zo#IZZ\Z@-PkVEP˱R+h-Vo9ꮚFQEQEmAut?mu %+;Tc,YKE`:Y,Y}:pgDgFgCgMDgM0g pgubhIpV#84tZY Z1,ZZ5I-!- Zu-&-Z(8JKt0-VH+Ղz\ZhmgGi`ڋ:Ji֋LZgB'8li!@Z@yVB*%U[\[[[< +qW((6F:JGYXXXU%gVU* +\. JY,`pc8O>qYO:˜5>Ɯ˝5-,Vk @ ek:+rΪGgy%sVMKˆ,J Ji%@ZIV+@+JZ]=\Z#(mۙ2i@iY>jjZWZ LZZլ`iK-W\sU3(( R?{'(K0dV&Κrfyu6YY'0gm߆rB +h5&i*:ArV %;ˁVY$h!hE40LhR hiKkhIkIkn&i*u.BZZ -K@hj9Bj؊Җ-\sVQEQEQjw{G,c!b̲,pK0g!uN8Հ3g@gΚbtB9 ՒJZei$hYh ggк'iВCimH WTUu4HՂhqi1h i!ڄ&&fK:Ť_ZoJ uPb:YZZfsyVG-%s#.]aEQEQFP]DHdyeVeKKtzqaκxBf֛~guJr~t֮ 6psB jg%,4t]SU%В:ˁ}{֦ ZhEՄAZIVLZ#-ZҚfҚ:"3~]GZZ\Z@-P%֜Z9NM-ZChK+.\aYaEQEQ_+{t>bBdu](3ę2kfpcpֻ:Lqg2gMsgsgz\@K8 hIpVp* +:zV]Zh%A6Ҋ6+*J0L JyI *[Zc\Z;qi~P˖BjԺM-ZH-aHl1mܲ%K6WbEQaz0GXggY{VyvǾpGE(d(CcIwJ>Z{^C%bQ$O$Imk~h`PY,VV:Y,0+rf_Z;kr֟YvlZvYE"guJ9B>s geZ9ˆVSgI+-SZ)V˕*IA酴VrPZ[iiHkցPZJS "jMLZZ/^|"j]7j-`֖\u%I$Iۢv_-WX&LcYiʊu=bwW\|Eb9kjÊ4g(tgڶ5t\gY-rA gU+rP*YbZY@,g5֯A' H+i (W*I ci-Y@HZzBI9%=iZ,-P8Qk,QKkZnDֲЖɭ\1uELT$I$IͻٛyƏ1\c)K1ˬ `E:}J9 J:듏ӜG99'Bgm9AZ,gujJb9ꄳ2)ΚК< BXbiU:I?Z6n +JZ!O?<uzԚPjZa+&$I$I<|bc#+VV̬::K"gYY̬YᬷzV9BgmY-8CjjU* +p,ՑYA'_Z|iIZA i VKk zFKk+w,i}SKKE"j!jMyO k[ nioȕpW I$I$Is=9m_ia +dRV +&Y,b9 +1 Yڭv֣6_wA5gYzF*YB>wV&Y ZK-%-XZ\iABҪIZ},%JZ-WZkz4i틤{bjAZiPk5I-X+c- [ nV$I$Ih)64 b2P0k5fFNTgn}izYk Y-rV9U* +\p;u-OZ-"l(ZsyHҪ$VtզvDz )-E-5r5 +jM(jk1('2zXXL,X +Eʊu.bbi0gY4zںZ!8jJ9eA YZY Cgк{A'4hZ:CZ%VUIꇴ,UҺimlJI^#MZZSQk5uԂZZ,m˯/I$I$*yŠeD?,GYYYY`1Ebg1Ҝm8kgY-rV?խUeg|YpVp֢g[,RA^ ---VUЊVU$HklA+!6JyKZoKP8Q뤦8Sk +:kMea+V-- P\lw5$I$I4B8gXJXBc(kR:fMY:I:f,,fVYoi9YOڸa}Y;g Y=FV#g"3Z@-g2hҊi (WHZ֠֊PZ +Z֬]TZmiPZ$-P(uuJQDD-X-֖-[1vrN$I$I#5yc4d.caĂdR"eE̚uu: +fY`vˬv7uֺkBgihigPzY]YrY8ˀV䬌E)jZY>hJ+-[ZyHҪVkuV7IZZiIKCk#]HZuk7HZS˵-h-P\&,v%^)J$I$I.s6>d+ϼ%e" Qb)ϬoY,b; j嬽{Z:k8鬕,9MΪתUvV ;bhbh-LV[Κj)-Hi$V?Kk)Kk ‹RԂZuu,IIETkY؊es+WD.]R%I$I$I%q=bi+44e)fM!f#fY`;_VY=䬆rV*Yl{ΚuIk^GJ@>@+h%U\Tk$.V/IkumIkgBZ/+-M-Sj}jMRkR\kbmR2ˁWsI$I$Is5%^ [W!XX6`,Y,V5dQ0+0 4gK3tA Z gYjR8qV'agy5߀֬sZwAZIiu@ZYH 2J,jV'iuki +i3>ZZZL-SKP밦qZcԲuֲmyDW$$I$In]@,*VX0@,,R5aa0Kf +e3kYqA5MΪ*YyY ,J:^YZ>iKHZ 2 hAZEHPꃴXZ+՞ _uU+dI5}p'ɃAd|( @28& j%[mCBHAUpww}νRQd;ffAEZkj}!Ԋ `i+#.])|WKM4M4m[{t^L9orkiIiYjZ$-P9SLVZ[imeoYq+_rtiiNg?9\Y_a9b%Ȋf=(f9 ̂,,aVYofkglEЂNYG{g CgF*rV +ZY)h=C˗ViBZj^oAZG!"sVZ^z'I-+-ԚYB{X WX+-h+{ˊ˒CϮڨliio.z{tߙ|bX9d}dyXY`ֽ2fY,09+ŬwpA88$u:$ojhYpV;@'V謎Rgm3h +U&}V?5Ik$/$I'S"qjAZLטZDYւPkiΝ++kk +X+q+#ii=a+ieX0V@Y,RrΝ%a1kE"f,v3k"hYg :5I:wHA}-;k[@:Biu9iui DZ}NZCEZJV7$$$cҺi XZL-uF1Va-Vl-V[\F\vJ^iikurOV+?|!+REZ_[-f9gY,auYYYYFVV*YC~YZZ]:bhm g֮ZZ Z"-֘'CZEZ/nUZZ,-Ij@Z_ZIlA[[-\\JL4M4M{Vaݟ42  J!O@,0k ̺[,rg1Y[u֋pqY=ghYpV;ksVunY ZH#VW$PZ`BZVZ"C$#NZg"iҎZ,-P+LkD)VS5xePkY X` +%pq9syJثaiiSTE#6 '!* Zn߾0/jYטY,b8 rβjYD:uuH5ިk*5p gsꍜ:c9vꌠ#i9i 5OZ'u9QPk933;77j"k=Z"fY,bfYY,Y gϜu:gh ZsqVO謮YY+VJ5KkIH s.fzՓej@-H @.gL7@&Y+P[[-˙+SW("iiiB_F%ͷ|eC +Wn\gf}3E"gY,q1:9YKu9kwhY{[83vv֖-2g5i 5"ҪBZV:QJ 2XZI_Z~ZW `Z[ym9n\F\\\>b|E%ViiJ_)f+e3Vf,ì"gY`EgYY?AYY犝Հ⬑}YYvچVLZ="=.֤'_=u]iG.28i\(Ľl wB 0NlɞOHh:}> d ;,i=g"*Ҫ6ZBZD-Hi'Z*-J뚔u%)-PEԂZQ3 Q+jZS^j֤@-ZoZm9ܲeeW88㸽:H},s6Kd"f eV̚1kgY,0f g57Igܒκ.um:4:>8JkOZZ$i+i;:iNki]U!j@-i -֣D>PZZ/Z)ilEr,ukӼc88vf߼A__9"bV"+PK)kyflYCĬ>bf,rV{pVctVtV嬋YcvYYEY,hZYڲʒʑʋH˂V:kuUH\JJH "iZi? j=!j}z>@Z"jIkmk)lcpKxW.]!{gqqq{.toԷ2M,2YBY, ,b1kaaYĬ~bbf:Y-YuYU7ʅgY]gIgHge:Uhe&BVq>!i}w~i iZ$Z!-P  -P.Q!Q)Qk@QkTRkҢ"YkY[k]XKaeaі-- .%.m@]888E}XBX6lcYʒ"eke--fMJf*f ;䬎vrVspVtVpVYE9g +I@됄VV $+$R!BZjAZVG'QԺwzDztrffvn@ +%q6W..BEqq_(Z/z?`"b%(@̚IN{̂z{,0 jk%g56jn g*%g]!g]U+eAkW:+-H++,|%mK{-ˁ iU@-H jknzZ@D>PkKٹdkilpKxKKK+PK_qq88M}|h4&%FOY ,bV29=55911>66pzfY=pVW' +g55jYU7Y䬒8g}m9 gZr2rVZh}h` +L'-inWZCZHZHZ$JUWj55ZmVmPuzj=trk-[4$ ,w88= +:o18V |%eAVTY,(k&9Ǭ`#ͬ0 hZᬆz89UNκFκgW:]g;˂Vc>lhʖJ룐e,$$2H Ԃ!-Pji::A;VcI~ZD-֜Z[ +[am9ޒR +O88mEOqg$lb%.U)59912_211> fଶV8ΪY7Ye䬫䬋;XYy+uVZAC*@bVV&:ַRZg sJZWHZVI ԺUSiZM͠V[;juZwAGFZd-P+b-aKj`esKxKK+l.^Q~N88mܛhH[WWXBXXYX@VJ"+,b559AM   zf.0 ji8&9*%g]Q:g8X9㬬͝8k21ʏHcKZG3H2I*'iUBZVm]jZmPԺ 'k lVl)mޒR +ŗ`qqɷHX6 V Y+Yae%IYĬMunY`gYJrV9UBκ g]YG-g}qVqV, Z[u֎_Z<Ҳ+@ZEu$$#:yiH!K$kVjݬ@zPj:A;I$Zd-P+d-%[ޒr+D63D88n' C:?iJK+D,c, YKYYP1+?\uq|:*v)wIH0.cMF61N0ɷZ{>{EAb?zf=Y"ff]f]fV&`8jY8FgUYib9O}gIpY:Ki%lhHˇLi1hM֒(-MV傴 -V0iAZ@u&P֗qjzwZ~ j+V-...\2T|MEQEQuJV6+W Xb) + G}3kg]Y_rffmցY18kvYMp Ϊ Dg-Ms +r+)Tir VUi9 H j ZPkuSZܺ}{k{ݻHݽ}Z %Ya[ ڒż'W`]FQEQEg8)_WBd̑%* Bf޺}7!>̺f&!0 g5Y8*Y\6Ü :LZY :y|5Zh +*K%MAZH +ҲAZ^ t pZj]j],ZZ{Jbzb뉌-V[\2"u+QEQEQGOوz +HX>X"z̑%*!W=dֽf}ƙuu .8l6

ťKTQEQEQdz-(EaE>yo>9}`R#GV,d( ̺¬YU`x4z,pVr:82SupzOt։Jq ,r&bi\ZeVn -iu{}h486SBkrk=ŰHƖrm1n1oE ++bBScREQEQ/4fhL>x% wN,XqdEzBfm0k3k 5F~ jf3s;CY>fCk|h=΢.ZI0- U -k@^?jǓNjBjZh-Vh--h--U[pqq%KWQEQEQGiO~ 7?#_EBaRőGGV,d( BfJagd<f 0 jx.8^UYe1g-κ: +5fKkKyuٗV& ba JVi9灴ZP 9VW׮PkZ jbBkJЖ--...\$xJSEQEQuK^W4#aW XLXd}bBdBfY_0*gp:8\UU+,4t]+B>f|g]Yt֜:Bz:yxi$rZiَz Vh4S+Z ŭZa ` -V--\2DvIJyFQEQEz?bPXќx% 7YLY,,dS2 *Yh4 YN jxjRNr֒swY[H"JkV6ŒaZVRimq=ju:,j}BkZZ*"mb +K/ػQEQEQǡ(EaAMԕ+,&X9BcbBdqe!Y,dv:f\DZJlYaV* |.;kuuliJ։ũ%K/HZ%M ӴeVnێzFv{`8ujqkBkrkIRp+O]{ ((:%MBq2FC2O"_1` +KBSn,dS2 ̺ʬuV\ױz U.[iV;,άyubuĜiVH_ZH-&QZl./PZnez@fՖ&QR jbړ-[[$rWzIoHQEQE7ԁ(lhP + ?ʼnKBGV,dS2 ̺!1kmuee2 j̀YZeYa:Pr :k1ty,`O?Β5^ahHv w"iu:.%iҺҺZ/(-KR!ZVzA"!Z@-n-`ZhDlnK/)((cT!Y)+37VYLYwe!Y,dֵ4fNfy j +w* yYK Yg$g}wiY"g8liZd(BTb2rREjٶ^c:"sjqkk1l݋aKҖȭ[sRl0((5(a1"a"GV,dSgud8:̪Ved*tV6YFg-:KΚVͿKZ%HJ""J+PZŒaZVԪmq=lNקȧ*RkbԒŭ%`KՖ--_\>sWJ HQEQE{Dc(xOX9c bڒřŔDf#V}f"f[f\DZudVlYaV*rlȝuu.Yg%B+,/R3 ޜ-wGZH-J+QZ%M ӴHZnC PKv[n%+D/_?MEQEQuJYZVd0,^gXTdmsdBf1e!6Օek5dV2MC׵:+eYK,`8zs~5Gy]Q + z)A AkDf1bCؕ "o}}ŮZOZ 76&FlEZ9i]@Z׮/.BZ7{+ֆݽ;Zbj=jZZ~kزlA["rEJU"c1C=Ø2<KcYdc2)Sef5ʊ 0kΎeܻ g-.^g].9g}Vq(Κ[gU5N쇴@-#ːUH-ZvZ@'B-VC ~Jne޲r+/;c1vH?WLb%RY*K(1 H3e&f,z`u8*uY0k?uuUVZiOur`iijYi]i} i-@Z2jݲԺmu7eUb"2no%rUcc1׊k0jIj]׮eUBQEe Rfݵ̺mu Z{7E8kRu9K3kPgLuA#jѷ5ՉjiZ@kVA Pk+}cG-g-֏[%mE2޲Jؕګ$7V|Jc14֡~Oj] +RQ%2 +z,̺1k Vf]ଆY⬆Y:Y3p[89:VV&ɢi]pi-@ZMPkZ6APkOQPK婕ZX+VЖˑ+1W _Iٿ1c_,E="#]nHXXX^r̲f=PvM0kZnYp09BY& Julxgh.ѥժHKeuiZˠZZ_9j= ԪY{XKa+{ˊ+5W`WA_1c4 Ƥ֕*K!5UTfCǬZ,8auEeUqVktgMj*BkTiҚΤj5iZ@U֭Zwz!ʱeqxKЕҫJ'd1c^:Je+C+ (EUYYwsffYpV,8a0+8K3+uִuٷu:h> ^RZsNZHZZFZV#- ֊PkC-uԺQ+sVL[\".o..H1cY!0$պ22J"%)+e=Ǭ]aֶ0kC"̺!̂f,"gu޿ѥu.V"-V#-V#-rZ{Z ֪`j+#GWWjc1|WW +XFXXXd(1kƬeaegfUɝQutLuҚiEZ9ZzZZ[Zw"jUʴe% + + c15[aD]iwb`a9bz d=J̺嘵ŝ rfgYtVh:IkJI%HQVZہZ@Z5lYmynorRJ˾1coIF&ݼk3#5V YπXYYJYYEfYYpgVY]qVK9k*s֩vx@kiIuLIҚDZ @-%-GFZ}kijUc---˛+Kë">?1c} _veU0Gַ@VEYY0k)0K;+0;#ΚftqcRZmVJFZ)rjE +k= +ز2RJ񕔿c1S0aJqO,#,G,kYYZYYJY9bfYYYm:k*+iMCZVKMeUjZZO`a[<\\\A]j{2cjYWz>MV#Vl,o'@VVsf9gif%ꊳZp,5~uU֟::>.HK5'ꈴ"j)i֚Vb-Pd-V---.G.g..\_yc1c0ًaHvwz`a9bX/2c J2̊嘵֏Y4:9,aV欏rѢj:h4֤5iki C-o@Z`GV[V--'3WPWB*c14_5,4`d=be)fYe ,yqV;kΚrΚ #iMI/3iBZ-VRrZZw*c ڊeԥUW1cC /aFe&UDVIYwbwV`y08gu;uGgMTud|U~It&i+9VҚR +zZZwaV[V--'3fWLu1c wWXAX)`"Y,,,( +Κ:9Y߭-ޫYixi!.%JPe[V[V--.G.g^~2ca^:ՊVJ,+GV],,(̲r:fu,st@ uJK묑֔,Ղ:ּŔZJ2Sk}kUҖ˓˙K+W1c< + + ,OX9YEYYPVY 1.fYgY8gZgMg:ΪA렱VNT55m5i!.eiYj}jkZZbo=k[J[\\\A]_c10c/[jEeL+#2V,Q֞W֎(kSee%̺3 ,,ay0 f,qִrdY',W}/sVZ3VZ-Hi͋,.8j]Z26Z[Z +z(o 4R{cc1ʣ0aP~J|%2rz,ʑ%ʺ핵%efAYY Ef]p2Κ:pV:k:w֙Cw("^ZgZmP jj}yjjknykm[ksKeeȥ1c} 3Vdh_ 2b)cem{ee nTuIc'¬`Vj[fzgg탴&ri}IkRIk:Hiu yHPSGBj- zBUPYkZ{---ˊˑ˙+bWBo11csUO0)F_ <emzeCYY=aRYf}*35fu,_':%Gf)ZXY + +QK=cٲl?722#2#E S +|YY[,wIkIZ;$nK+Pk5qԚ9j>Ԛ3*k}Uk+y˃ˋ%ԥe"B2s/ۊbGqo+V%XlLe}%e=:eyff]>NfYǬQd9k%g49km՝,HSV֑֞IkuUQ뼆Z GOZZ2kEl +"o\l.Ů^cB!zvqTK|E+"+Q7*f=8f-u5u;fIgUYY6IkҒ9jMuIԺ!j9j;jb7k+y˃ˋѥe"B2/rJ}O+V%Xl,Y%e=:e;eU̺!f] +f f{fMFYY=r.9kjeH5HuEԚ9j8jQQkUk-S[[./.&K+WB! +T؆j?Y+VEXYu))kĬǬg1+q 8[pVdz)imyi(i+i%yjMu5wԺsԲUV[[ +\,h..C_VC!BoNF9'{(Xldʺwʺsʚ;eY:̚zfRfvଦJ/|Vi풴zNZDֱM/ZWZ7ZZdǢ42m n<$Rz B!V(s! %Ϳ `"Rcid蕵pʺuʺqʺr2u5::G_8AeaimGiu=ƭu5w"k=(ki+KW3B!{<('èؙU+5,;SV[f=fyguY8zvRZZHEϞZZ7Zd42m n<$Rz|!Bˇڑq^ ++5F{[,b֥ggYȬ`VtV_9kYpsJ+Rk奵Kꑴ""Z .1K9kYw gVJ -V5 iyjUҪ֙Ym\[--H...[_B!R_:ŜX<<%HXrcʺeeHYYgu"f,v3+:+cUꥤI+jVEhyc1bKkKp0fWY`!Bhղfڑb_͙KK@W\(3K(-YY8kɾ_Zkeij i1ZQ%eX&XKbcKkKp+KK+WB!; 2o9 dyeݘʒ"e`^dtV`VYkpVM/!LZ)Dj͘ZZ,lEmJJe+xr!BW?(Ge+XXe]heyfOJ g-YKiYҒ(jZZCZӜZZ_LlEm +J%ѕW]B!^aK|.9gW]+BWUPYSYÌY}NƬYEfKZ[J+PKuPku^V-[\Rv* + !BPFLvWXRdu(3k0P1k/2+8Yr 5)-Z;j$>.Zd--C[ĭȭ\),{51 !Bʳ0r]1+7D5!뒐9(+2k5g`NYYpVmŧ//$-IZ@iVZ_Z +[sVVέ.\ ++B!zXtT2VNh;6D!NYǤ,ϬQʬͬgVpvYKIZ")&ZDSֹ cKhUWS-.!B{dԣW ,),"V4-K"K*뜔5#fMRf 51 zZ(6 +jG#8Pl-[׌-V-- DW:!BUފ_K3)Xl, YIYSR֘ՒYEgmHg1C[fWZBZ%ju jjN kl]1H[[[ ry5" !B@ōlI93T"aIbUƺacd::!eHYR}Y:fmJfY(I-Zǹll]2H[[ .A]Z1 !Bja:# s25DVAYSR3p fڀMvZ=A=m-O#[k`-[---WW$W.^m!B!O0[j`^<$*cEd]0J:ʚDe1*g1z̬6,8$i}ֆ%Z^Zd-Aa[kjXV-ŭ[\\JZc!BmbQ8;o-aIbEc K*k%5LUnvVάYg5ZJ궡İ։V---+K+wW_IB!Zrqes ,/,I,a 6VDY\Y2v,fm*fYO;RkCP+JZʬuʴ̕A`!Bh5+F=-L%%e 딑%ՊY&f gm(gê^Z?ֺvn35ckYʵ + +RՂ`!Bh*.dYy +39+"넑ըffm'T̪wV8KW)>XZK!ySje֚lebopEqIsYjA0B!Jb+J’Ʋuʔfu6f:m$9( (6%jiIy<_Ѱ-"3*#dTwm1vVĊsL͕֦VHk7I(ZZ_`-[Z[R*e+C0""""ZO\vX -J,e, Y+#5&fN*fu!jz֓c-[Lتu\B\ w FDDDD+)Xծ’ĒƲ(Ȭ~e֧Y8kFjPk[PKHZ_rc [JsJQa)64DKaKE烲U8k[9+,嵜 iijCjMz:X%VNr5K0 hkrtVE,mY^z*3k0S,5ijj]ڎPASˁZll6a$\&r#"""uE,VE,m,Yʪ0¬m̬Y% #_bi][M +UYm-Lr%%%+g0""""ZG\ToWiA,m,XYOZYn*g]Ϊq↥ePkkQ&ֽG-Z!n p qIr9JVR4պ՟DžZ0V,KY&fXY-)Qju+ +mݕ5p3OW7jA,XGPKVY3lZM-SZ|j.Ui[\,v FDDDDk*܍ƔZXb)%uBV,Yw!,m nURrէ/""""Z_ԣ_,bic+Ŭ z˺eZMkEe W^DDDDD*oY*^="V fYaZփjj]R+o-[nU޲ K`4JaĚ#+^fig5Upn\bVS˵{[R[ qyxJZ㳜Mb d+d%35ʬM 6X+V[Ju[` SMb)+\ffK˥V,lUyW̮eFDDDD_f::ڦ,cMȚY8m{kjEj`Kj\yypYK1A$LeKh@Z!Vɭ[bDDDDs+zpe!keN^󅗢VZ&` Χo-[1Lp5̅(,?&16k,YN,uV*exWilj !WY0띕xAjUbV-\ s!0""""j U;Y=2e- p ր:劫]DDDDDi UfwJ(fVY/#aj֪Uk+ǭږ0m2Ve:yRkpeͅƈV̭Pke[OʂY!j YV[[Bq-/""""ZmiVX5(+,F-M~k)lr3#""""]'5`UKxHY0BC-ZH`Жɭ\c"""""kO{V&lfyfR7VZ,m9j {QgnTkWm㤲1 gy,oou %cH1S( fm\jǖtte@,{ZK<;Mv"jYֲej+V\h֚TvV5̺7ZZ&m4QgUYsTʂYgn>ecV\+9?=`yƲխ,uAoP˳-G[B`DDDDhp]Y&&tȠׂ r\D2ʂYeZŖP G.ÍYVȭ4 ׻9#` +`{x֊kkD\(DKfcQ+V63QD Wn4a >B}WaB]DDDDtzhcƳxIew\)j`Npa/""""hpr4VYʂY{δVF[3ĕ7دܸa plg+h(,.Ƕ|=ef]@G=Zcqm1૎^=ߣ|n~k5euV$a7xz<Уo5L/L%hjX#+̺2ZIpeaٸ,3Vmtqmc+a>x\[&Ycѝ +ck`m]eV[sx43ylM- JaÝT>U1>I?S6V^=;Qq@K[+ִ?8wg:= X` z֖{ SM2u#c`?];Y1R1L.fBv3L_ڲ8|szpky[ 7Qب5ќNNVs6k#`k K*OD[xҿ^G}*m+.tW|Q_ 4Zg+]7V%p:̪C~Gkݼz>sNcs9?j_&NW#k~KftsEs+K_/l(B`8^ q(҇ !7'J7>wX.> endobj 16 0 obj <> endobj 17 0 obj <> endobj 18 0 obj <> endobj 19 0 obj <> endobj 52 0 obj <> endobj 53 0 obj <> endobj 51 0 obj <> endobj 54 0 obj <> endobj 50 0 obj <> endobj 55 0 obj <> endobj 49 0 obj <> endobj 56 0 obj <> endobj 48 0 obj <> endobj 57 0 obj <> endobj 5 0 obj <> endobj 6 0 obj <> endobj 60 0 obj [/View/Design] endobj 61 0 obj <>>> endobj 58 0 obj [/View/Design] endobj 59 0 obj <>>> endobj 13 0 obj <> endobj 14 0 obj <> endobj 11 0 obj <> endobj 62 0 obj <> endobj 63 0 obj <>stream +%!PS-Adobe-3.0 +%%Creator: Adobe Illustrator(R) 17.0 +%%AI8_CreatorVersion: 23.0.5 +%%For: (Mart\755 Climent) () +%%Title: (Untitled-1) +%%CreationDate: 3/31/2024 10:46 PM +%%Canvassize: 16383 +%%BoundingBox: 331 -4148 3764 -196 +%%HiResBoundingBox: 331 -4148 3764 -196 +%%DocumentProcessColors: Cyan Magenta Yellow Black +%AI5_FileFormat 13.0 +%AI12_BuildNumber: 619 +%AI3_ColorUsage: Color +%AI7_ImageSettings: 0 +%%RGBProcessColor: 0 0 0 ([Registration]) +%AI3_Cropmarks: 0 -4096 4096 0 +%AI3_TemplateBox: 2048.5 -2048.5 2048.5 -2048.5 +%AI3_TileBox: 1758.79999351501 -2460.55996704102 2337.19998168945 -1635.44000816345 +%AI3_DocumentPreview: None +%AI5_ArtSize: 14400 14400 +%AI5_RulerUnits: 6 +%AI9_ColorModel: 1 +%AI5_ArtFlags: 0 0 0 1 0 0 1 0 0 +%AI5_TargetResolution: 800 +%AI5_NumLayers: 2 +%AI9_OpenToView: -1721.35294117647 377.352941176472 0.177083333333333 1616 940 26 1 0 46 87 1 0 0 1 1 0 1 1 0 0 +%AI5_OpenViewLayers: 77 +%%PageOrigin:1960 -2152 +%AI7_GridSettings: 256 16 256 16 1 0 0.800000011920929 0.800000011920929 0.800000011920929 0.899999976158142 0.899999976158142 0.899999976158142 +%AI9_Flatten: 1 +%AI12_CMSettings: 00.MS +%%EndComments + +endstream endobj 64 0 obj <>stream +%%BoundingBox: 331 -4148 3764 -196 +%%HiResBoundingBox: 331 -4148 3764 -196 +%AI7_Thumbnail: 112 128 8 +%%BeginData: 18346 Hex Bytes +%0000330000660000990000CC0033000033330033660033990033CC0033FF +%0066000066330066660066990066CC0066FF009900009933009966009999 +%0099CC0099FF00CC0000CC3300CC6600CC9900CCCC00CCFF00FF3300FF66 +%00FF9900FFCC3300003300333300663300993300CC3300FF333300333333 +%3333663333993333CC3333FF3366003366333366663366993366CC3366FF +%3399003399333399663399993399CC3399FF33CC0033CC3333CC6633CC99 +%33CCCC33CCFF33FF0033FF3333FF6633FF9933FFCC33FFFF660000660033 +%6600666600996600CC6600FF6633006633336633666633996633CC6633FF +%6666006666336666666666996666CC6666FF669900669933669966669999 +%6699CC6699FF66CC0066CC3366CC6666CC9966CCCC66CCFF66FF0066FF33 +%66FF6666FF9966FFCC66FFFF9900009900339900669900999900CC9900FF +%9933009933339933669933999933CC9933FF996600996633996666996699 +%9966CC9966FF9999009999339999669999999999CC9999FF99CC0099CC33 +%99CC6699CC9999CCCC99CCFF99FF0099FF3399FF6699FF9999FFCC99FFFF +%CC0000CC0033CC0066CC0099CC00CCCC00FFCC3300CC3333CC3366CC3399 +%CC33CCCC33FFCC6600CC6633CC6666CC6699CC66CCCC66FFCC9900CC9933 +%CC9966CC9999CC99CCCC99FFCCCC00CCCC33CCCC66CCCC99CCCCCCCCCCFF +%CCFF00CCFF33CCFF66CCFF99CCFFCCCCFFFFFF0033FF0066FF0099FF00CC +%FF3300FF3333FF3366FF3399FF33CCFF33FFFF6600FF6633FF6666FF6699 +%FF66CCFF66FFFF9900FF9933FF9966FF9999FF99CCFF99FFFFCC00FFCC33 +%FFCC66FFCC99FFCCCCFFCCFFFFFF33FFFF66FFFF99FFFFCC110000001100 +%000011111111220000002200000022222222440000004400000044444444 +%550000005500000055555555770000007700000077777777880000008800 +%000088888888AA000000AA000000AAAAAAAABB000000BB000000BBBBBBBB +%DD000000DD000000DDDDDDDDEE000000EE000000EEEEEEEE0000000000FF +%00FF0000FFFFFF0000FF00FFFFFF00FFFFFF +%524C45FD7CFFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FF +%A8FFA8FFA8FFA8FFA8FFA8FFA8FFA8AFA8AFA8AFA8AFA8AFA8FFA8FFA8FF +%A8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FF +%A8FFA8FFA8FD14FF7D7DFD0B527D5252527D5252527D5252527D5252527D +%5252527D5252527D5253353D363D363D363D363D363D36595252527D5252 +%527D5252527D5252527D5252527D5252527D5252527D5252527D5252527D +%527D7DFD11FFA8525227FD23525152363714371436143D1436143D143D14 +%FD2852A8FD0FFF5252527D5252527D5252527D5252527D5252527D525252 +%7D5252527D5252527D5252527D52525276353D363D363D363D363D363D36 +%3D363D3676527D5252527D5252527D527D527D527D527D527D527D527D52 +%7D527D527D527D527D527D527D52FD0EFF7DFD2852361436143D3637143D +%1437143D143D1436FD2952FD0DFFFD26527D5252353D363D363D363D363D +%363D363D363D36FD04527D5252527D5252527D5252527D5252527D525252 +%7D5252527D5252527D5252527DFD0452A8FD0BFFA8FD295236143D143614 +%3D1436143D1436143D14362EFD2852A8FD0BFFA852527D5252527D525252 +%7D5252527D5252527D5252527D5252527D5252527D5252527D5252527D52 +%52363D363D363D363D363D363D363D363D36FD04527D527D527D527D527D +%527D527D527D527D527D527D527D527D527D527D527D527D527D5252A8FD +%0BFFA8FD295236143D1437143D143D143D143D143D1436FD2952A8FD0BFF +%A8FD20527D5252527DFD0452363D363D363D363D363D143D363D143D3652 +%527D5252527D5252527D5252527D5252527D5252527D5252527D5252527D +%5252527D5252527D52527DFD08FFA8FFFFA8FD285227361436143D143614 +%3D143D143D143D1436FD2952A8A8FD0AFFA8FD04527D5252527D5252527D +%5252527D5252527D5252527D5252527D5252527D5252527DFD0452363D36 +%3D363D363D363D363D363D363D3652527D527D527D527D527D527D527D52 +%7D527D527D527D527D527D527D527D527D527D527D527D52527DFD0BFFA8 +%FD295236143D143D143D143D143D143D143D1436FD2952A8A8FD0AFFA8FD +%1A527D5252527D5252527D5252527D5252353D363D143D363D143D363D14 +%3D363D36FD04527D5252527D5252527D5252527D5252527D5252527D5252 +%527D5252527D5252527DFD04527DFD0AFFA8A8FD295236143D143D143D14 +%3D143D143D143D14362EFD2852A8A8FFA8FD08FFA852527D5252527D5252 +%527D5252527D5252527D5252527D5252527D5252527D5252527D5252527D +%5252363D363D363D363D363D363D363D3C3D3652527D527D527D527D527D +%527D527D527D527D527D527D527D527D527D527D527D527D527D527D527D +%A8FD0AFFA8A8FD295236143D143D143D143D143D143D143D1436FD2952A8 +%FD0BFFA8FD10527D5252527D5252527D5252527D5252527D5252527DFD04 +%52363D143D363D143D363D143D363D143D3652527D5252527D5252527D52 +%52527D5252527D5252527D5252527D5252527D5252527D5252527D52527D +%FD08FFA8FFA8A8FD28524B36143D143D143D143D143D143D143D1436FD29 +%52A8A8FD0AFFA8FD04527D5252527D5252527D5252527D5252527D525252 +%7D5252527D5252527D5252527DFD0452363D363D363D363D3C3D143D3C3D +%143D3652527D527D527D527D527D527D527D527D527D527D527D527D527D +%527D527D527D527D527D527D52527DFD0BFFA8FD295236143D143D143D14 +%3D143D143D143D143CFD2952A8A8FD0AFFA8FD0A527D5252527D5252527D +%5252527D5252527D5252527D5252527D5252527D5252363D363D143D363D +%143D3C3D143D3C3D36FD04527D5252527D5252527D5252527D5252527D52 +%52527D5252527D5252527D5252527D527D52527DFD0AFFA8A8FD29523614 +%3D143D143D143D143D143D143D14362EFD2852A8A8FFA8FD08FFA852527D +%5252527D5252527D5252527D5252527D5252527D5252527D5252527D5252 +%527D527D527D5252363D3C3D143D3C3D143D3D3D143D3D3D3653527D527D +%527D527D527D527D527D527D527D527D527D527D527D527D527D527D527D +%527D527D527DA8FD0AFFA8A8FD295236143D143D143D143D143D143D143D +%1436FD2952A8FD0BFFA8FD04527D5252527D5252527D5252527D5252527D +%5252527D5252527D5252527D5252527DFD0452363D143D3C3D143D3C3D14 +%3D3C3D143D3652527D5252527D5252527D5252527D5252527D5252527D52 +%52527D5252527D527D527D527D527D52527DFD08FFA8FFA8A8FD28524B36 +%143D143D143D143D143D143D143D143CFD2952A8A8FD0AFFA87D5252527D +%5252527D5252527D5252527D5252527D5252527D5252527D527D527D527D +%527D527D5252363D143D3D3D143D3D3D1A3D3D3D1A3D3652527D527D527D +%527D527D527D527D527D527D527D527D527D527D527D527D527D527D527D +%527D52527DFD0BFFA8FD295236143D143D143D143D143D143D143D143CFD +%2952A8A8FD0AFFA852527D5252527D5252527D5252527D5252527D525252 +%7D5252527D5252527D5252527D5252527D5252363D3C3D143D3C3D143D1B +%3D143D1B3D36FD04527D5252527D5252527D5252527D5252527D5252527D +%527D527D527D527D527D527D527D52527DFD0AFFA8A8FD295236143D143D +%143D143D143D143D143D14362EFD2852A8A8FFA8FD08FFA87D527D527D52 +%7D527D527D527D527D527D527D527D527D527D527D527D527D527D527D52 +%7D527D527D363D3D3D1A3D3D3D1A3D3D3D1A3D3D3D367D527D527D527D52 +%7D527D527D527D527D527D527D527D527D527D527D527D527D527D527D52 +%7D527DA8FD0AFFA8A8527D527D527D527D527D527D527D527D527D527D52 +%7D527D527D527D527D527D527D527D527D527D5236143D143D143D143D14 +%3D143D143D1A3C527D527D527D527D527D527D527D527D527D7D7D527D7D +%7D527D7D7D527D7D7D527D7D7D527D7D7D52A8A8FD0AFFA87D7D7D527D7D +%7D527D7D7D527D7D7D527D7D7D527D7D7D527D7D7D527D7D7D527D7D7D52 +%7D7D7D527D363D143D1B3D143D1B3D1A3D1B3D1A3D367D527D7D7D527D7D +%7D527D7D7D527D7D7D527D7D7D527D7D7D52FD0F7DA8FD08FFA8FFA8A852 +%7D527D527D527D527D527D527D527D527D527D527D527D527D527D527D52 +%7D527D527D527D527D5236143D143D143D143D143D143D143D143C527D52 +%7D527D527D527D527D527D527D527D527D527D527D527D527D527D527D52 +%7D527D527D527D52A8A8FD0AFFA87D7D7D527D7D7D527D7D7D527D7D7D52 +%7D7D7D52FD137D527D363D1A3D3D3D1A3D3D3D1A3D1B3D1A3D3C7D76FD27 +%7DA8FD0BFFA8527D527D527D527D527D527D527D527D527D527D527D527D +%527D527D527D527D527D527D527D527D523C1A3D143D143D143D143D143D +%1A3D143D527D527D527D527D527D527D527D527D527D527D527D527D527D +%527D527D527D527D527D527D527D52A8A8FD0AFFA87D527D7D7D527D7D7D +%527D7D7D527D7D7D527D7D7D527D7D7D527D7D7D527D7D7D527D7D7D527D +%7D7D363D1B3D1A3D1B3D1A3D1B3D1A3D1B3D367D7D7D527D7D7D527D7D7D +%527D7D7D527D7D7D52FD157DA8FD0AFFA8A8527D527D527D527D527D527D +%527D527D527D527D527D527D527D527D527D527D527D527D527D527D5236 +%143D143D143D143D143D143D143D1A3C527D527D527D527D527D527D527D +%527D527D527D527D527D527D527D527D527D527D527D527D527D52A8A8FF +%A8FD08FFA87D527D7D7D527D7D7D527D7D7D52FD1B7D363D1B3D1A3D1B3D +%1A3D1B3D1B3D1B3D36FD297DA8FD0AFFA8A8527D527D527D527D527D527D +%527D527D527D527D527D527D527D527D527D527D527D527D527D527D5236 +%143D1A3D143D1A3D143D1A3D143D1A3C527D527D527D527D527D527D527D +%527D527D527D527D527D527D527D527D527D527D527D527D527D52A8A8FD +%0AFFA87D7D7D527D7D7D527D7D7D527D7D7D527D7D7D527D7D7D527D7D7D +%527D7D7D527D7D7D527D7D7D527D363D1A3D1B3D1A3D1B3D1A3D1B3D1A3D +%3C7D527D7D7D527D7D7D527D7D7D52FD1B7DA8FD08FFA8FFA8A8527D527D +%527D527D527D527D527D527D527D527D527D527D527D527D527D527D527D +%527D527D527D523C1A3D143D143D143D143D143D1A3D143C527D527D527D +%527D527D527D527D527D527D527D527D527D527D527D527D527D527D527D +%527D527D52A8A8FD0AFFA87D7D7D527D7D7D52FD1F7D767D363D1A3D1B3D +%1B3D1B3D1B3D1B3D1B3D3C7D76FD277DA8FD0BFFA8527D527D527D527D52 +%7D527D527D527D527D527D527D527D527D527D527D527D527D527D527D52 +%7D523C1B3D143D1A3D143D1A3D143D1A3D1A3D527D527D527D527D527D52 +%7D527D527D527D527D527D527D527D527D527D527D527D527D527D527D52 +%A8A8FD0AFFA87D527D7D7D527D7D7D527D7D7D527D7D7D527D7D7D527D7D +%7D527D7D7D527D7D7D527D7D7D527D7D7D363D1B3D1A3D1B3D1A3D1B3D1A +%3D1B3D367D7D7D52FD257DA8FD0AFFA8A8527D527D527D527D527D527D52 +%7D527D527D527D527D527D527D527D527D527D527D527D527D527D523614 +%3D143D143D1A1B143D1A1B143D1A3C527D527D527D527D527D527D527D52 +%7D527D527D527D527D527D527D527D527D527D527D527D527D52A8A8FFA8 +%FD08FFA87D52FD277D363D1B3D1B3D1B3D1B3D1B3D1B3D1B3D3CFD297DA8 +%FD0AFFA8A8527D527D527D527D527D527D527D527D527D527D527D527D52 +%7D527D527D527D527D527D527D527D523C1A3D1A3D143D1A3D1A3D1A3D1A +%3D1B3C527D527D527D527D527D767D527D767D527D527D527D527D527D52 +%7D527D527D527D7D7D527D7D7D52A8A8FD0AFFA87D7D7D527D7D7D527D7D +%7D527D7D7D527D7D7D527D7D7D527D7C7D353C3660597D7D7D527D7D7D52 +%7D363D1A3D1B3D1A3D1B3D1A3D1B3D1A3D3C7D52FD077D59603C3D36FD1B +%7DA8FD08FFA8FFA8A8527D527D527D527D527D527D527D527D527D527D52 +%7D527D527D361B143D1B3D537D527D527D527D523C1A1B143D1A1B143D1A +%1B143D1A1B1A3D527D527D527D527D593DFD041B147D767D527D527D527D +%527D527D527D527D527D527D527D527D52A8A8FD0AFFA8FD177D767D3C3D +%1A3D1B3D1B3D59FD057D767D363D1B3D1B3D1B3D1B3D1B3D1B3D1B433C7D +%76FD057D593D1B431B3D1B431B7D76FD177DA8FD0BFFA8527D527D527D52 +%7D527D527D527D527D527D527D527D767D143D1A3D143D1A3D1A3D597D52 +%7D527D523C1B3D1A3D1A1B1A3D1A1B1A3D1A1B1A3D527D527D527D593D1B +%1B1A3D1B1B1A1B1A59767D527D527D527D527D7D7D527D7D7D527D7D7D52 +%7D52A8A8FD0AFFA87D527D7D7D527D7D7D527D7D7D527D7D7D527D7D7D76 +%7D3C3D1A3D1B3D1A3D1B3D1B3D597D527D7D7D363D1B3D1A3D1B3D1A3D1B +%3D1B3D1B3D1A7D7D7D597D593D1B3D1B3D1B431B3D1B431B7D76FD157DA8 +%FD0AFFA8A8527D527D527D527D527D527D527D527D527D527D527D141B14 +%3D143D143D143D1A3D143D597D527D523C1A3D1A1B143D1A1B1A3D1A1B1A +%3D1B3C527D527D533D1B1B1A1B1A1B1A1B1A1B1A1B1A59527D527D527D52 +%7D527D527D527D527D527D527D52A8A8FFA8FD08FFA87D52FD137D363D1B +%3D1B3D1B3D1B3D1B3D1B3D1B3D597D7D7D36431B3D1B3D1B3D1B3D1B3D1B +%431B3D3C7D7D7D593D1B3D1B431B3D1B431B431B431BFB1BFD157DA8FD0A +%FFA8A8527D527D527D527D527D527D527D527D527D527D361B143D1A3D14 +%3D1A3D143D1A3D1A3D1B3D597D523C1A3D1A1B1A3D1A1B1A3D1A1B1A3D1B +%3C527D593D1B3D1B1B1A3D1B1B1A3D1B1B1A3D1B1B1A7D767D527D7D7D52 +%7D7D7D527D7D7D527D7D7D52A8A8FD0AFFA87D7D7D527D7D7D527D7D7D52 +%7D7D7D527D7D7D593D1B3D1A3D1B3D1A3D1B3D1A3D1B3D1A3D1B3D597D36 +%3D1A3D1B3D1B3D1B3D1B3D1B3D1B433C7D593D1B3D1B431B3D1B431B3D1B +%431B3D1B431BFB35FD137DA8FD08FFA8FFA8A8527D527D527D527D527D52 +%7D527D527D527D7636143D143D143D1A1B143D1A1B143D1A1B143D1A1B53 +%3C1B1B1A3D1A1B1A3D1A1B1A3D1A1B1A3C533D1A1B1A1B1A1B1A1B1A1B1A +%1B1A1B1A1B1A1B1B3C527D7D7D527D7D7D527D7D7D527D7D7D527D52A8A8 +%FD0AFFA8A87DA87DA87DA87DA87DA87DA87DA87DA87DA1363D1B3D1B3D1B +%3D1B3D1B3D1B3D1B3D1B3D1B3D1B3D3C3D1B3D1B3D1B431B3D1B431B3D1B +%433D3D1B431B3D1B431B431B431B431B431B431B431BFB3CA77DA87DA87D +%A87DA87DA87DA87DA87DA87DA8A8FD0AFFA8A8FD137D5A1A3D1A3D143D1A +%3D1A3D1A3D1A3D1A1B1A3D1A1B1A3D1A1B1A3D1A1B1A3D1B1B1A3D1B1B1A +%3D1B1B1A3D1B1B1A3D1B1B1A1B1B1B1A1B1B1B1A1B1B60FD057DA87D7D7D +%A87D7D7DA87D7D7DA87DA8A8FD0AFFA87D7DA87D7D7DA87D7D7DA87D7D7D +%A8FD057D3C1B3D1B3D1A3D1B3D1A3D1B3D1A3D1B3D1A3D1B3D1B3D1B3D1B +%3D1B3D1B3D1B3D1B3D1B3D1B431B3D1B431B3D1B431B3D1B431B431B431B +%431B3D7D7D7DA87DA87DA87DA87DA87DA87DA87DA87DA8A8FD0AFFA8A8FD +%147D523C1A3D1A1B143D1A1B143D1A1B143D1A1B1A3D1A1B1A3D1A1B1A3D +%1A1B1A1B1A1B1A1B1A1B1A1B1A1B1A1B1A1B1A1B1A1B1A1B1B1B1A1B1B1B +%53FD147DA8A8FFA8FD08FFA87D7DA87DA87DA87DA87DA87DA87DA87DA87D +%A87D7D593D1B3D1B3D1B3D1B3D1B3D1B3D1B3D1B3D1B3D1B431B3D1B431B +%3D1B431B3D1B431B431B431B431B431B431B431B431B431B431B431B3D59 +%7D7DA87DA87DA87DA87DA87DA87DA87DA87DA87DA8A8FD0AFFA8A8FD167D +%523D1B3D1A3D1A1B1A3D1A1B1A3D1A1B1A3D1A1B1A3D1B1B1A3D1B1B1A3D +%1B1B1A3D1B1B1A3D1B1B1A1B1B1B1A1B1B1B1AFD041B3D59FD067DA87D7D +%7DA87D7D7DA87D7D7DA87D7D7DA8A8FD0AFFA8A87D7D7DA87D7D7DA87D7D +%7DA87D7D7DA8FD067D533D1B3D1A3D1B3D1B3D1B3D1B3D1B3D1B3D1B3D1B +%3D1B3D1B431B3D1B431B3D1B431B3D1B431B3D1B431B431B431BFB1B431B +%3D59FD047DA87DA87DA87DA87DA87DA87DA87DA87DA87D7DA8FD08FFA8FF +%A8A8FD187D523D1B1B143D1A1B1A3D1A1B1A3D1A1B1A1B1A1B1A1B1A1B1A +%1B1A1B1A1B1A1B1A1B1A1B1A1B1A1B1A1B1B1B1AFD041B3D597D52FD167D +%A8A8FD0AFFA8A87DA87DA87DA87DA87DA87DA87DA87DA87DA87DA8FD047D +%593D1B3D1B3D1B431B3D1B431B3D1B431B3D1B431B3D1B431B431B431B43 +%1B431B431B431B431B431B431B431B431B43597D7DA87DA87DA87DA87DA8 +%7DA87DA87DA87DA87DA87DA87DA8A8FD0AFFA8A8FD1A7D523C1B3D1A1B1A +%3D1A1B1A3D1B1B1A3D1B1B1A3D1B1B1A3D1B1B1A3D1B1B1A1B1B1B1A1B1B +%1B1A1B1B1B1AFB1B1B59FD087DA87D7D7DA87D7D7DA87D7D7DA87D7D7DA8 +%7DA8A8FD0AFFA87D7DA87D7D7DA87D7D7DA87D7D7DA87D7D7DA87D7D7DA8 +%FD047D593D1B3D1B3D1B3D1B3D1B3D1B3D1B431B3D1B431B3D1B431B3D1B +%431B3D1B431B431B431BFB1B431BFB1B43597D7DA87DA87DA87DA87DA87D +%A87DA87DA87DA87DA87DA87DA87DA8A8FD0AFFA8A8FD1A7D527D523C1A3D +%1A1B1A1B1A1B1A1B1A1B1A1B1A1B1A1B1A1B1A1B1A1B1A1B1B1B1A1B1B1B +%1A1B1B1B1A1B1B1B52FD1C7DA8A8FFA8FD08FFA87D7DA87DA87DA87DA87D +%A87DA87DA87DA87DA87DA87DA87DA87DA87D7D593D1B3D1B431B3D1B431B +%3D1B431B431B431B431B431B431B431B431B431B431B431B431B431B4359 +%FD047DA87DA87DA87DA87DA87DA87DA87DA87DA87DA87DA87DA87DA8A8FD +%0AFFA8A8FD1E7D523D1B1B1A3D1B1B1A3D1B1B1A3D1B1B1A3D1B1B1A1B1B +%1B1A1B1B1B1AFB1B1B1AFB1B1B1B3D59FD067DA87D7D7DA87D7D7DA87D7D +%7DA87D7D7DA87D7D7DA87D7D7DA8A8FD0AFFA8A87D7D7DA87D7D7DA87D7D +%7DA87D7D7DA87D7D7DA87D7D7DA8FD067D523D1B3D1B431B3D1B431B3D1B +%431B3D1B431B3D1B431B431B431BFB1B431BFB1B431B3D59FD047DA87DA8 +%7DA87DA87DA87DA87DA87DA87DA87DA87DA87DA87DA87DA8A8FD08FFA8FF +%A8A8FD207D523C1B1B1A1B1A1B1A1B1A1B1A1B1A1B1A1B1B1B1A1B1B1B1A +%1B1B1B1AFD051B59FD207DA8A8FD0AFFA8A87DA87DA87DA87DA87DA87DA8 +%7DA87DA87DA87DA87DA87DA87DA87DA8FD057D3D1B431B431B431B431B43 +%1B431B431B431B431B431B431B431B431B431B43597D7DA87DA87DA87DA8 +%7DA87DA87DA87DA87DA87DA87DA87DA87DA87DA87DA87DA8A8FD0AFFA8A8 +%FD227D523C1B3D1B1B1A1B1B1B1A1B1B1B1A1B1B1B1AFB1B1B1BFB1B1B1B +%FB1B1B59FD047DA87D7D7DA87D7D7DA87D7D7DA87D7D7DA87D7D7DA87D7D +%7DA87D7D7DA87DA8A8FD0AFFA87D7DA87D7D7DA87D7D7DA87D7D7DA87D7D +%7DA87DA87DA87DA87DA87DA87DA8FD057D3D1B431B3D1B431B431B431BFB +%1B431BFB1B431BFB1B431BFB1B43597D7DA87DA87DA87DA87DA87DA87DA8 +%7DA87DA87DA87DA87DA87DA87DA87DA87DA87DA8A8FD0AFFA8A8FD227D59 +%7D523C1B1B1A1B1A1B1B1B1A1B1B1B1A1B1B1B1A1B1B1B1A1B1B1B53FD24 +%7DA8A8FFA8FD08FFA8A87DA87DA87DA87DA87DA87DA87DA87DA87DA87DA8 +%7DA87DA87DA87DA87DA87DA87DA87D7D593D1B431B431B431B431B431B43 +%1B431B431B431B431B4359FD047DA87DA87DA87DA87DA87DA87DA87DA87D +%A87DA87DA87DA87DA87DA87DA87DA87DA8A8FD0AFFA8A8FD267D523D1B1B +%1A1B1B1B1AFB1B1B1BFB1B1B1BFB1B1B1B3D59FD067DA87D7D7DA87D7D7D +%A87D7D7DA87D7D7DA87D7D7DA87D7D7DA87D7D7DA87D7D7DA8A8FD0AFFA8 +%A87D7D7DA87D7D7DA87D7D7DA87DA87DA87DA87DA87DA87DA87DA87DA87D +%A87DA87DA87DA87D7D523D1BFB1B431BFB1B431BFB1B431BFB1B431B4359 +%FD047DA87DA87DA87DA87DA87DA87DA87DA87DA87DA87DA87DA87DA87DA8 +%7DA87DA87DA87DA8A8FD08FFA8FFA8A8FD287D523C1B1B1A1B1B1B1A1B1B +%1B1AFBFD041B59FD287DA8A8FD0AFFA8A87DA87DA87DA87DA87DA87DA87D +%A87DA87DA87DA87DA87DA87DA87DA87DA87DA87DA87DA8FD057D3D1B431B +%431B431B431B431BFB1B43597D7DA87DA87DA87DA87DA87DA87DA87DA87D +%A87DA87DA87DA87DA87DA87DA87DA87DA87DA87DA87DA8A8FD0AFFA8A8FD +%2A7D523C1BFB1B1B1BFB1B1B1BFB1B3C52FD047DA87D7D7DA87D7D7DA87D +%7D7DA87D7D7DA87D7D7DA87D7D7DA87D7D7DA87D7D7DA87D7D7DA87DA8A8 +%FD0AFFA87D7DA87D7D7DA87D7D7DA87D7D7DA87D7D7DA87D7D7DA87D7D7D +%A87D7D7DA87D7D7DA87DA87DA8FD047D765936431BFB1BFB1BFB1A6076FD +%047DA87DA87DA87DA87DA87DA87DA87DA87DA87DA87DA87DA87DA87DA87D +%A87DA87DA87DA87DA87DA8A8FD0AFFA8A87DA87DA87DA87DA87DA87DA87D +%A87DA87DA87DA87DA87DA87DA87DA87DA87DA87DA87DA87DA87DA87DA8FD +%047D596036603560597D7C7D7DA87DA87DA87DA87DA87DA87DA87DA87DA8 +%7DA87DA87DA87DA87DA87DA87DA87DA87DA87DA87DA87DA87DA8A8FFA8FD +%08FFFD27A8FFFD06A87DA87DA17DA87DA87DFD04A8FFA8A8A8FFA8A8A8FF +%A8A8A8FFA8A8A8FFA8A8A8FFA8A8A8FFA8A8A8FFA8A8A8FFA8A8A8FFA8A8 +%A8FFA8FD0AFFA8FFFD2EA87DA87DA87DA87DA87DFD2CA8FFA8FD0AFFFD65 +%A8FD08FFA8FFA8A87DA8A8A87DA8A8A87DA8A8A87DA8A8A87DA8A8A87DA8 +%A8A87DA8A8A87DA8A8A87DA8A8A87DA8A8A87DA8A8A87DA8A8A87DA8A8A8 +%7DFD30A8FD0AFFFD4DA8FFA8A8A8FFA8A8A8FFA8A8A8FFA8A8A8FFA8A8A8 +%FFA8A8A8FD0AFFFD67A8FD0AFFFD65A8FD0AFFFD04A87DA8A8A87DA8A8A8 +%7DA8A8A87DA8A8A87DA8A8A87DA8A8A87DA8A8A87DA8A8A87DFD42A8FFA8 +%FD08FFFD47A8FFA8A8A8FFA8A8A8FFA8A8A8FFA8A8A8FFA8A8A8FFA8A8A8 +%FFA8A8A8FFA8FD0AFFA8FFFD63A8FFA8FD0AFFFD65A8FD08FFA8FFA8A87D +%A8A8A87DA8A8A87DA8A8A87DA8A8A87DA8A8A87DA8A8A87DA8A8A87DFD48 +%A8FD0AFFFD3DA8FFA8A8A8FFA8A8A8FFA8A8A8FFA8A8A8FFA8A8A8FFA8A8 +%A8FFA8A8A8FFA8A8A8FFA8A8A8FFA8A8A8FD0AFFFD67A8FD0AFFFD65A8FD +%0AFFFD04A87DA8A8A87DA8A8A87DA8A8A87DA8A8A87DA8A8A87DFD4EA8FF +%A8FD08FFFD37A8FFA8A8A8FFA8A8A8FFA8A8A8FFA8A8A8FFA8A8A8FFA8A8 +%A8FFA8A8A8FFA8A8A8FFA8A8A8FFA8A8A8FFA8A8A8FFA8FD0AFFA8FFFD63 +%A8FFA8FD0AFFFD65A8FD08FFA8FFA8A87DA8A8A87DA8A8A87DA8A8A87DA8 +%A8A87DFD54A8FD0AFFFD31A8FFA8A8A8FFA8A8A8FFA8A8A8FFA8A8A8FFA8 +%A8A8FFA8A8A8FFA8A8A8FFA8A8A8FFA8A8A8FFA8A8A8FFA8A8A8FFA8A8A8 +%FFA8A8A8FD0AFFFD67A8FD0AFFFD65A8FD0AFFFD04A87DA8A8A87DA8A8A8 +%7DFD5AA8FFA8FD08FFFD27A8FFA8A8A8FFA8A8A8FFA8A8A8FFA8A8A8FFA8 +%A8A8FFA8A8A8FFA8A8A8FFA8A8A8FFA8A8A8FFA8A8A8FFA8A8A8FFA8A8A8 +%FFA8A8A8FFA8A8A8FFA8A8A8FFA8FD0AFFA8FFFD63A8FFA8FD0AFFFD61A8 +%FFA8A8A8FD08FFA8FFA8FFFD65A8FD0AFFA8FFFD1FA8FFA8A8A8FFA8A8A8 +%FFA8A8A8FFA8A8A8FFA8A8A8FFA8A8A8FFA8A8A8FFA8A8A8FFA8A8A8FFA8 +%A8A8FFA8A8A8FFA8A8A8FFA8A8A8FFA8A8A8FFA8A8A8FFA8A8A8FFA8FFA8 +%FD0AFFA8FFFD63A8FFA8FD0CFFFD61A8FD0CFFA8FFFD06A87DA87DA87DA8 +%7DA87DA87DA87DA87DA87DA87DA87DA87DA87DA87DA87DA87DA87DA87DA8 +%7DA87DA87DA87DA87DA87DA87DA87DA87DA87DA87DA87DA87DA87DA87DA8 +%7DA87DA87DA87DA87DA87DA87DA87DA87DA87DA87DA87DFD04A8FFA8FD0C +%FFA8FFFD5BA8FFA8FFA8FD0EFFA8FFA8FFFD5BA8FFA8FFA8FD10FFA8FFA8 +%FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8 +%FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8 +%FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8 +%FD10FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8 +%FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8 +%FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8 +%FFA8FFA8FFA8FFA8FFA8FDFCFFFDCCFFFF +%%EndData + +endstream endobj 65 0 obj <>stream +%AI12_CompressedDataxu}j?.vffj tUu{lA}mx/ -C8y>'"qKfF̌8qs^/_翈7O/o?{/w˗| ~۟z3Wg?<ׯ~ &޼jλ_>统s=Wo_bbut|VO_n~7vg_j18En_wq"iZ\hoo޼_^|_zjgГgz_>__|=Ego^o_kB8~̽N=}~/uw߾ Roz?^xe4gKo^7ίy\vП_{ +E_xyo/k~oՋ{s_KgA_߽"/ykַhٟ꡿zCXxs8rnvX0hu,9 P<Tq뿗1B^ VH7{/^RԪ ct͋/NS}!qޙ1Oc +O'MKW˲h7~׿^}qx%7?>M7o^O?l7/ÿ~~__C矋i¾ݿOEln7>Wً~ūp/?;qt*ouS~|zשv|զ)=Wެ߸LV% ']ѽ{l=UDW_|z9_=ó/_ͳo_~~3?O"?}/_5;ɽϟl7U_\~xwͷWޤ=3qh}O|˲w_~d㿳߼lT__B7/>?_~ߞ};giS3ɵ/>$r<Ģg_J`ڍY]-Qv/>?}|{]wۃzg5romnat?d>·yO3 is4 ~k!0wA/*t~: yH '~~F]R+']ew?hmpNu?ܫ{:o0k(>?)`uݍG]L~Մ㤋ilԤ1XS^pnMC]>W%i?kE߫Papw?`11˱|=xw['Yҧ]QWҕu]UפkӐ;u~+I4|_tU].Qyu[/>ۿ1EKߨ5%ϓnJ-JCChBMy!BZ(Ll)lq|P.,,.C~ýq5WEb)1S.ckM9E CҌ6ݐjG7)gg}k7.pK~xUڱv(n!mATxWP-|D߲r{톃X^b/\n˾Q>T5~гP\4T-tsjtzFkgT¿ۮk}|<2(la^nǍ"հH,d> 9LZcH/wP!P8Q;lmmh)& I9W349tm|G$I~xϞp '1왇.1=n_s ϟb_]ecVĆ4FsBCNѭ8 +N\6V[;Zi/ߙi|ݻ=xڏ57Mq-oy7^99SO31jrNٶY_BHI7xs&]}&f;ؠX7Eyc7rn-^^6',PwB{aYYr?蚱1U*܄u5`P{YQ{hJ{]w {K*W9 + AfVu H8R1c<0G $}/jBj`HHz  6]G[fb@P7s4ތm6gƻq ujqtWlXqS86 #_w*1 #ekAUxbœ/wy\J󸈂ԃ-\s7 2RMAPb6;5+AC^ʔY>QW~uމҎ,#㭴G됐N2I%box?{%feZ }>;t9?QM2kIF#0Q~DQ庋(PJV[f3]x𙵥h~3y/k޲.S^ 6Sg` sl.S.vO>Xf8:/9rq;Gq9^Us@dP(0("c2:]5d6P`< o9sYcuVs68 +e70֊xԾI@vC7[zl]#;o;q`tw\.sG[ꓯt[^/zrOQ6dc"4nDU$ ENڂ֠6qdԂ=ZNV7D +UE~,+>ZCsi8NQg\\p+էqǯ R׻yޟu}G^ +kÒPzfO?1oKFm4VfV7-IױI~@PlfF7~R^ VPr4r՚l3`,W[jpc;-s5DxTFqfim|e_ta`K^I%@:iV[i/vGH?+䗺zz\Il>ҥrK|ǻ~fڂx`P.t 6${ǣMg&c Ƙ1c*nf&>L@gnL<01 05 wx4b"nFf&nf*n}aO6c4n|Q^ۘ|FpKN=Y]zvH7|c|nײ3jH53暏tOJ+]ӥWdk;)z|RGYW.xQ>r#G?r#GQ/WU[tJsv` (9š\Ze!i_)mv ZBtEX_ )XVHp ^ʣ*nʸxG:AC#eszlr  1> 1Se5#Y=Wkr ӵܑX)OK|;S;Ŗ5Myq$M!='=•y$2^#N7<0CpF1h YXz4Ӡ1 < hz6tS2O?Ԩ;`VcάtYnMv Mb,XvfA`&VMv4?nɎЭ4%Њܑ9lg]]GnbLGU{V'&TxXj'ir z-bŏI-MD~#>%BN1-N|=RXmܽ Ŏp+/-՗Zi*1m5ǹWj:]gkK+ +Sgz|pî=~_K[n˩ºZFsVvѣS(}< ӽH1Ym>eyΑIw+Wju rÝlpa^-_! q]KEXC+pX%`P*Z0ASZ$AkH5էM 6vsX܍K^̒d,ܯqʴkZSG-S?VιGCTJ^=WQWrMz|pK=>շk$ ߵPܛÙ28u۲m\gsʲq6)96=SbU#eh6k5@oyRx@yi\e5N&%ŷOFs5sdץrc~T'cf SYi&GbRw\ iWvY5rRLB ~s7:H>`$evxӲS߷e0ϊ`\,o\r\)&{TDA`AL.w]Tza};kECkRwD>=36y`Uj S)ԐMܰNnrq\k|e˜ק<]'68SmHۿuMZy h!;jבּ̍Pf$lڤj +(V;󫣳ڛpl:89-$x D;bUh(|h^wXL=ۭ6afu m~qvU39Zv;Z_*$wc Fz.9z٠d")ǵR:hЦ +Iܔ.qʛڦ*lǩfX|/ėºǥvWl@4 rLh +khf\5tk>ƅ|oo忒'7eF[Ne^Pg-tU쯆<,hj=n4^&hfohoOs?o:ޛ~e~AH]~Ylk)uhsRwz˥MyBb1D3W֙v?t-ӟ~~0,Lvp뽅n\m +BnzG\xry'_. 71_ W.RlBpBzSl:*Thq9PLŴ-JŴK) !,_/ jSNgOaMcO>;η 5E6~ Z]^/«C7A\=] ~Xh8u/J`^q?g*ap;X/ݩ:''#˭K찹^-<7xY)9AvYlU`{]=NΏ 㙃G禇wy= +Uꮘ@ۖË/ܭ-#9{8/i$qӁ[ɮ} 0[mzV˰?,ľGyzʳ=kz ]]*m{S +1^=|k+E/+ǫ y&1nqBU eޑ +BSU9s5 T8.fT:wJnpu=[we󾫖`<6ULVfiZfg kВ\ +|bGp~{ֶ߽lb\F nŇxZ^ +xi.7,r`:gqǒg"7}FU|4i w+;v'H'rEXfjȣy7c̝fqo~Sa|f`gykGnHy|,%G}=)?=V^ƌnB )';܇lIxvnyNV7>d3Ϸ~-1Xm,f1t/t-X^&G.Xή5);Mưz<\ќp҄ȯⷚ{B9ژW4u㖢Z1^NzZ-M#܎ހO-PGOovjذcsIvji$UX H+ZJ4X>MjǼ_W)^it#4^ +N(š$):Z3n!򸎶C9o<Ji|Q(85E\Z7WnO_C >rd3%|m t[̥yOQr<7s-|]^(\qau#34pƘ|؀msw{5`:S A'֖6Mm!$`(|U7rM+G_8.=ܟ{h~8}TYv:m9W8Ώ'k2w/R,qN+b4ݺX&nlGI:lE5q^mc;n[ɻu6Po7;O'PCjs:v{d 8hkKUuFO֜jU-u -4я Y̮$-F0>:{{qoV +ar_2[U`U|H{3`9.r\wy[Y׳Yv)Ui~8[G}E +lKbv{aQ6lXw6Fq{:oS㣇^2`9b'v.5xivaS98q=ң^oSNKv}wjYM:ug\a +H e@EE]ԮJ9WRפg9-v^=s} fG zwplm|:qtmqt|%{g[6lޙm)=/4CN 7Æ#jhy޻[3zD)E8RwF}k]:nWr wZޮfUvv]ו7]i߷+]*uB Z;gYu pɎeշ~ZoWzl׿Zh`K|l)aK MqiaL9L~E$j3Yԝ :%c,cw?ZQzE3K )جY#Bj||}~~/zVbIPh~ Ea" eZuwP{F .yu1mzJcX('C H7)lc8S/z粍4{<.'I֞mpͽ؎m| 7 u9 +.ilѝwiW&1KNB'zF]t>wwQiڎOz.g|ۑu\2ur]r)n$917uvThqDn:(sK\|<@kŏ|(/WYitq+o͸ '=ZsNjôQ$5ǝbPbNe7 +H|dYRڎcmXM8yfVt#6q5mdbfNO&ڴ&/YjuaSidp vy𥔽[NȂ9pSnzFOȺTk9윋O?$ZnTtJ|hߞ~yrRBi5o+lkܵs*omc;3ٞn ߒ&dnƙgzK'~fܨPt5[<_kĥ!/ [Mcht p|VpB`kȝ}8ɫ2:qF2:p/ـ?p?pcHi#M|w-_?g>%ο:x6"ka%Be*-@~Z K'3{?> s^_Ӄ?W\ k>_}~ð5˗$ĦZ$ 37Hgjkjs,`0<0ۋrK]]]]]]]]] #M|4.Sgo޼xū?[ɧW~۳<{WlCH,D"ޤ2@l*9Q?,jroJXOMWݶ>ߴ,jm?aŧo}b.߸fo6{sOlv_ݾy{|_={/ihg /޾~/^>?_]Mn]'gAD1i夭]¡oBНxJ]ճp%&7/jMJ x1ƛ,gҔTf!5QOͰib!y't#=L@:ZF[OƛQ10yOGRuy{àeZF ~bFOcЗDAzVir D>k,z~_oa佚ehZ,OtYغb-f +HJ I6Ѽ%{yP<BT *RU,y (f>QzPĶlp<1U(-T~bV]>5T&܏Zj&R]܌{ܑb"37"6d؞ FZHEanvԠVCR x>b &ȉہ! t6HGE(@Ցod4ST7$*-8BCAZ=D " &~MTMocT`+peSRdCiP!A~vDg +6.-7-2B*l[!&${JBA=H$3F6_TDP4`>WOkGPs ' AJg& ooGd ?Hŷ 3@<.\I{CKf9JڍŢ1B6Ow^o0#gh $t3tD$ L?3LTEXR4mr $cXEn!'4jKϝ5Y)1/ObE253D P(*sqMV;FrGrf+ühЂZ$az RR$ȱ`Xy8)U^%)fU#:8Sb< +Xc|uVE&1A6 x~*WbTe* O-*Dj sy w_f5bZ<5h +>M?- @;i7%laB XjFL z6a'* U7f@`nDMEQ<ÐU!,(](HS+fh9LL<"V(I(}{Z`'d j6 ="%FǼpYrru&&HC|l02 $jD09O(m~x d>g"$LUZQ}D(!j 1hkv+d4 +*MQIr%^s _0:yIe2sP^vIx7&)ѳiXVӦ4$jBqMіf}/Dmff6D l44^j*Rfs@eXC' +9VP5`+bC "l0ɸF]VoAyƉ2\Qwj1 !ڞbCM1;5Wsia?W8|yrZUJ랣xE"КUr۔ϼ*dl)`{0O)7pE-6iǰ{f{kk5/DR1|W{ū?~~7_g4~;ǮP +PY 0K֜j0>@:pSi-D9X(__6G,vyk040ȫ=XKL}h¹ŤTѵ1Xak]`3c!qx;v}dJ‡!L0d3m]&>1ڀ)[HW_B4j,̥+[;fP{_-1]skz ͧ#-řA"6V1>}Pzi6e1%ܦmgVbŐ +nD4}=1yQ\q1d`hN(si¦ czqքYcӖ1 +sU}H 4'숹ΥpjM΃P2x$:FѹA$ѱT6M 8St^K"q惑P[ZXh2+qybjZ~`]A_*r=3G8}E.T'bx{%;PZY8958ذge;Ɋ5fp:]Tgvm0s |zśC63I}RNi/j<ΧfalbDDc<1bqIb`ff/B (2E: o%"D4eHԤ$0DB &1 5F҃T@ qJ`Heֳ9(?C!-2^ ftdm{ F + +#RK\&"DҐlkĴBP>M\1zkŎO ,J؞FyѤ݄׀^:~AÒ89ǰБSRLː!BEXf@~@I 7PӉ>aR+Ѩ]P1ݢER=xS^J|-k`Mn 9LґP L J~@ nTq"a@iU3$`Anm1oJdq4H<1n=/娯ԢZg %c͚zՈR6`JF#N JӉdC1E`>V8j^`R,s +1*Ҵi1Ƅb `,dC)$WԹ^m1ݘujEzKL\=`4MTdA:4jhZ1Q$)"q5Z6hE|U!_un)遇W8)?, !wj?'vR-7y1aH ئ:gv[`0Jef>aIS[U Nu Db+Ff-uZ*N܄ +G!B $(*} b-m>NMnu04cC.jnvVQex5/ Ձ?[VBX!p3@[?}@ƋoNҀokyl,L7a(FD!$ [X)Du_-ǽo@z-bk-'nx=NJx_D>/r + k֢c]_F98.c*DqjOQ %*eA%tמ ぐ.c4 ?f&Wu90'ωC$ +>cvU>վ@S_ ->_~(opȪ +"}"f^L`&8 0Q-4=~@o:tBWhXo,pqQѳ'9e `4߶A:8Eae:d M@O i`jCN1B;Qdy''4xۺ_Z\edCD1 +["9c +L!R7asR!&)hfFV7@&H-`^0f${0@W3؜6cmY~%bM [Dl$a%橹DHOKOt T" kiuW]ȣUS0,iPWߛ7'F ̴ 8,>qnY +UaNF؎Ըٜ>!ĉ`dq8P#n| u`77m0m5zsT,pg|"I/XGDxX`Ξ(f'Rڟ Z*j++H@C/Ɨ?:2t}DY?[.vx0Z'gT+ЮZrqKWTZ'8 ǩhW^` +U"x:ka1WZԀa1@6i $,؃B[+1tYfZm-frI1j?ZbNAN X́ԲQKEyK5AlYGO$ȣ^̛kK~6J끫`nn:8v$Xg&ŖΡնB{Q|l^(Zb:b\T"Rj-l/3I8OH^BH _oҦ+6d2 ˴hph ]DZGQ[QۥjR5-#-s,yo,]΄W[Hm駴;[PC3N9şy)^)oI2Zݵ&'Լ9҉+[d^W"y^$ikj Z wEj̈́l)ŁDPfR1D +%ʣf7g*86(`p1C_4$FQr! .$QV5\[yg7(:Q˘eKJ-'yLc3v7Imw#`i]Bߟ|Ȱt"88dyz}Z)AL;!pnM\HOSk?M) `09n?H_ZI^gEq43Rk;NMZ-y -ȤV" #z{p WGJ.{!z%lzh5HB5"5 ,C]E$jFxd\_sjVpBqnھ'A,.pdX6a=p2𺐘IQڹ8yв8}3'bJbZG30FQ+Ȓq +{ERR׆լFT.鎢 $PڍSk%k^bsv8^pSDx3iu~s"9E4u^[U2S;3k䰺ЃPf/].eHRY0Vz)[]$QNwxU-:{f+T4@OV)TM1#D=.a xZdR0R홨`/^G$oX,/zrifR B\`h.b-|M}e2,:낄9 +3;K7)Ș7 -gc؀ ;sjx<&fqWHuG^sKIJ//IUuɥ4`Sp*V QJj! >SݴB&:ZH {Ր'^mE;j}x-&i7ThQdNAh73?~`1]ɲ} +X5iSbX!o] +܌aD4Z Vy;q掣}KzZѕ@4 #|-H"c…E=ug(ރeyy8@%Ǥom2 Ia"]à4Tp2FĿ=jX)U` ji  T\a9(%5!Kiq J~?2H)3, W :-b٥!4+"vVx  +ιB +`7,DwT{*(:&#P MMΐ0 xx#Rej*=)3~4US+PSW43J35BgF$ivN⽜NaX[hi:[ & u s+Dgmo HXA'T@ ZtюV*hA1wWG#sM ySgg}yd^FŞ냥Dcme8T 0FjLM!jP+\OUp.@) ld\Yta0yz#5*يœ]gD{j5I f0@3PVjAۢ}#JY>muy<ˆXCݬLU4X#jxt3m֮":<;z}oTXZ@@m4<~0-XߝZn~8K `E67GgԉIPf+Aݐೡ|jOu W{F =.?&%Z."Ȣc`Sr-8k&@V~gﰱ"5ߞ2JQ8ځ)TFpnFI0r\{x"~ɄNcৱ ^l=.x"MU+ -a.P\ +Irgjg$Z#|8aZ˽0*DGgIVb?~BclGb[]_)gUNLjYs )-oCtb}'Qn9SY^P'7vWaPeW%js.:e lW.,,">|#R%Kh%E>7!!7$PCO.H&]lF6)hS`4R +b<8x)-źt8z\2 ؜ƦP%¿xP9pbpM1qB#Oˁ:Ⱔ팎];?ֲ`qytǨD([g]>dFG*&N6$yF+>A$&}&ا C!S6RL4~z9krcaO~JF{KʶAY?"jԃIg8u_BjV20 u%IyhC<]}|dN8%ݟr牆y9ybʲ] +fnN-PEdwRU< ;K܂4D}Y1`v'͢k%5odb)pez_zh1W[ՠ^jM@ZgZ7hUk85R;qs +y,%b M>z 8"[zVkщQ/+VM.ZcrԪ^e`#%}]dF!0]/NNi);k4hl +%~&:R/-%(cӢHbQJ3#54E +d嚬V,B8XORr&҆)IvjeѼVhphF2`At`-4wfV])5Ȓ{i CXǥ¾{JM80ТUf;. 5$mmi6d-$9dk-b?=Չˬl+ zŔ p$Q0]f;dKx+EN>h^i`!瓯=a4Y0KieX%I昞#7\>DC,>EpM-dkf;~A.?0 LX[0G.e?9 #$i}F?T90|:m I"Z1WsRO^o95[QT޼s>3rKDjְіX5'0ri1 8X +8h0ϑD .~;!bNPKEֈ;#(qؓ::ElmfR8toldzpvm.͞`v%۩g}dS9pJִ儡>UM ,1; @FѢ^S;4)RkՂh\a= 6H[yrJw64H.-& R9bJfDúP=&QXͱ9.Di6?UHH;JK>ĆavD0&Jü'Dґ36#TjPo/SGfhap=v1q) oEM Q%Z_y{WXP +y;3 i{+ +nN?ɩOBۡ}lr$05ڰd'ܿQjǟaCIH.ӿٿg欇B:f-Da1 'KЂ=£ eNa{v2_W8G@XO +*F+7ϧ}U;W3A}tL~p}[OKR9LghZrʜm(U@܅~%JsQߦ_*U58`R8>KpJu$EMI]nU9>GD&8;vtТA2XĖ4FN68N [= bY\EŢEfs4z0J➍n M$ Vsȹqu(@rFzua^tfۊE7EqA[\o Pݾ( r#UhUŖq.QK/)JDž5#!{{t?BY. +D/U.Y߲.`,%(P@u +>XsU:0 vԜ"F;fQt:p.y9+օЫEҰ>4ua`/a2\^n1w/msgZiU!VyJh#dy@ʚ.'ՁZ{L3?$r9DD^Tfhp)GҘcya9rx<%q, R~=V=VR5B"ѫWpS|y6C>(l@(DQTw.{rcM{g)mⱻP{PMں9]5Y8Lxt鐹KكU.5:n!|܁~"aqְSbj%,\C lCS(LW.7 + +aˊ ;E%ͭtI]_!FCrS\=5#;^ x0,7SmH_d=|V*!Z4vla 5ʌiʈۓ cӏӑNh!ݍZK; ovđ9J5^ym'C#<}~1 tPp,FhռwSK t+ ;%|Bh]^q^ GZjW Rx@ +[3QPp _R;&w Dk?+V:,~zDl+`3pZ7:;dqn{ sS/>KN>&Ll3v\wMW'$+`xoXP+ahHI7u @ʶ+ȉs[I224Ul=8*s%n6kfBst]WVf3U `S FvDx+_~-Y;w}Yn.%\~hXb¸2H̆Xt#ƬWDa3t^aDVb׉ ISBT-P&uGϼFKYp;&v,\~h+c*jhwJy[V2Qض{p"T(NdnhCh=3"Z~ZĂ2!/&atjο?~maJ')$x9L̈YO3_~{h+0- h`cR60B&Ud@2$#urҳ-ݶ +CQH, E'7 4 + +ysTO: +墇#/*{vɁqb=^Nϣ"d?R b3lS>:ytM0q|bΦ~勺H\|3]-p'65π{FvǸThMe+y.x>ԁd$@͋)'\ Crě4bM޵LӚ~j jJ{_eS"*8z쇙+.l6&>/O^3"&Rψ @8s&!Sp@?s?>DXL$,*&^@p| (ȐZ"2 0#f2 _PCWz}l/Ę2޷AA={{idU"񖪷"ڠvqU$6H{Mn/} ݷԌ>{xOfJ ~@SÐ GF, Flwa䝓s吭xWF?NXQuJv")Az[!_5; HM[Sa*4,0i)J@ך\w/U[UA\b +~?틖He=‰J1=%3ۤ~=>ZQy  >'oxk2 :ZwPhT }]Sg /TW~`4|#ш2quW)tf輢xEA4KB7p|_@fa`-_u$Bg(}:N֎" L wl}v,_ ͤ~ x2 Br+uJ}SԜ̉2b2Έj*A0ЪSUL'3k/zeopЀK3@vѢLpr-3i!35}H {*rK_dI/άh1f7m~t\|Z5`!N=g&Bor{,b}"oηTpYW<!NnP<TQSpy8/QRtxe+aó`9v2P5&ꮣΣÓ¼iJQa$,~N +J Xقw+˔L]ʗ6DumL*E碬hZ@^,*I>HEG}eS LH\8t?Kc*[#gJoTUWN(C.yC-/nΊL'Ύp4+MEi&<6Լ_$v p8*|hs0xjQAnjFPHRl~֢A}ZLNz34( +oXlR 72Jg{ru^I+/#4ߋScXa.Qau|O遛_Q: +xmև+=L0L]L=PvYZJ,K.(Ǖ+ ݾ9o!}"*Pn~+TT|L{+i}UKM8AB.RU,((/>S-a Od62FPOBf/EIqE`1 ]E +dǛ2 qRE?80H]&B+pRvuX"=Хp5{ mjt<6ra +ؠE{G @-lV1_CdDb EZmҩ(A*h +c3ttQ~m"o;Mqϲ{TR:ZL"W;YZâ *f? noimbr]R22 +kڭh+}܌VSe'^tA=o\D'%sb1*EVo= +`c(^B3ضHz&/3v: +@PhJjvV\uhZԄ_'YeOԄ[e+e]xC\ ɠQ-3Z~e,g芉?00ӉG ͬla/캦!QЎ**nfbihFq_EX.QCGܩ,hĜC5$:E7YM\oOpW0d  w$ŐjXN2g$ڴS1_ FDȆDRF`tl%FnL^}/5a+PP&/2Ic yx$uŻ[k(aI/hPL1G"y_П|/U֙trBQ39 0U8c}PL\tz&^gJ ּ̟<ݰ;p%iƟY Z+Âc_E@Pt(`. ۵+ Sadai=<8dDTBAQG%> #II \w3Y&*Oi +!@ "8^SQmΥ +Y?ms'.D#ꀻ0΅2)$ep3ўCQ󨮎"-vO5럍ғ>.l?YQYOe+F;&:E޼]0K%D 93wQhOSoB;-. + r3l^i} X=cK}<̦PK݋1卵|T( [ī U`Z<Hy `4e}&Y_ 2јD >Lfڎʔf&E2d +E<3=6KӃNnhgx"燙֣A%: /& Q=GA?ʖ׬Ȳ(}J<$/VTVrR#LVRO/TJpsݓ:E*Kٮ 8Uc"ȼ0s`O9fB2UqIfC.Nm̿Qk{:f΋zV\.ǰe`xUI7C 蚠!ǸҔt'?,R:簑Ͱa"λ;osK)O XLBb ~S<>R#DC߂Q22fj79Bb)/hM7+و#r9RXdNbjl}OHckO m5r.VGHr Am4 [6p5bʁc?T~_WC*g +c7PjWHDO_i ,U̝(!U[hQI<{ɩxe?oX(`5g| w&(5%7GЯ3(a V!NV6Nl&O`!d-6\AF6Ζ-=$?bejz) AWoOVKdE +#+3).\FK_Z-Y^8I|.%z[Y_4 ;&Xg$\|HAĽB )cP> 3$@ul블8A-=*7Al즯?xf S^*fx@.w泉110!8`Ȳ%SHfs8^4>ґu9kbԌwqusy;X5+ߑW"J +` Ӡأpov{\0 ^VT1L)88DVg~]6,8n1^2:5OG eh.j٨z)RZO%@6ܛL coz4dZ83QC4گjbXJ<3vqNi,`d%N9KA0j%k'>\)g: k!@> .!>e'jF+U dFg{: _[ۃa0觨6/L(6P(;%d,&UsY~8R-^/o: ^,<%z/΁H_~CG] HM%zpX=,hc%IܡU:q@ʨtz'rFVN1$۶44j8ƺ5JWu>Dž O@2(&+݄%VwV᧛?\`"cIGF hbFK&ǀoE g0Ӱ4RHE%m~',g^ +__ρ.YRx(N5 seRbJcDd/ǒN 4Ma5-n)%}ۑLZ+zB=hrR2{= +@|ڃ~VMRU8"#t(4r)M Cx#mdԻB2L2߬,YcL/B# +Eo=UzS +K +Ti^8ŒՃcm E|]D8gWk:@m)gP4# O}p&fJIeQ98TXK צcp YP`M+FTǓ$kyDSBa#vG~3}E7N:3#q_DTᢚ/KAYw7:6)1\gVa&dONm _.'Êܠ3w cNqHC IqPd%W0T.)ї!r:+d!0\(tEI ɾz03BwbTh0pWW/bTB(O`x:7l(MF4,$J#dEAbZN&fȃ'CyMt(|rEšc/:+>E}Y]+@Jh*'1G!M4l2@Zi?֊mUyW`4Z! k$cz#&(ڽf {4F..ˤTwLm #/)˓'jT#b#ylVYf$gޭ+%N|E +hș&[g@Bݒ7h͹b7cՅΊD %OBI+2åjnН.jޫկ߿:+9ޠƯ6{e(:K-7 S^SF0v ;αB Ei|PڞbrpelnOfppΜۮZP5)'jO.-T|DCy_Hc_^ G >lEGց|!Rqxnd\8?F]J#h[Z;_j|q?xNQ۹-pfoxkucEp‡ +pgMs |DɄ)V,]!-p('vG:nKi䤿B +(2s@ӯr, -1ħg\:(Lg/RFLҗs^ڏMC%V|4x!ɰBG9mî<|- +OJZocD8kNfY9Q 5 aqMzAє,#&zb1Xp#0FzQQxg}vXUni)0{]AC_B3r >@x +m41YݪI}թ {1g-@hK֢U!ثFnTIuی p&Rr4$-ˡuMkR2hA(hiJqФFwJ=s(c̳琀tVg: 涽D} -b< $F ii0-/I4=(tev,AM=;+2"єçX eU` Rm4۰h*a 4,j"fԵ:kfޤڕ gb;4e` +OB9{\SSUDq¸~yWSa^2HX0gmGy.2$7,vDװh3sxnIhj\s j/MA bH| |?lnp]Wc+{:~MI?y҃5K'N 6n\(Z@$.o ?q׸*F ~l,b"xSaI>CGIKuld0[8@v'kG<8 Q]R|<k }%Ի/d9(Z"7E`a܂j/rA//Dcq%gZwK) ^@JkK !lXmM7է0});e *ܙc|H6sPH?.C P!xb9qS +z[ TG/5i8lbqԥ%TpV~2H47%'ŗ +h~^['gɀP.Ȯ^P+$o ՁO04 +)O!~eT/aӒC %ǻ$qfTKFY6e_du>* 7N BzbDqFR`CO 5Sk}0ͅ a^cR'*KdN=Fp(ޅabnӼ豴pdA X0n]>xhw9T!@"GDLLv= M܍,W߻{ +A>~YXu 0 +GoS,^[$ę)}_&9`Mݚt _S4\ʑa-Z+s +Hô2P?+ )K(0} wzi(]y^j!GчmssV8&2yŰ +!hd(_\hƦJmh0M eh} TBێ*J`?Ȉ*5Q R1hP"ɄD!*Z&%W+p\ + &FPR`eH^ +pDæa]`#Y+"k.`T(8">%`S8+0Ph7Ͷ9zT];*yA3e*l ~av%ā9qގ QFAfuZqbB'Al!/`@{QրyL!K6!`Zȃ48[`VJ,4:8+rn YIiӓҳĩԉH})U%#ߓ$ 99BE9lAQ$s~0Y~sa{}^Deԡw=7a*Zn1+]sk0iNC0ixM)dFDDZC*ICcmW5Hʀ~O:w\3,q4d# 0*/g=i@㵀ag[E ˊ"DUOXSdTNpذTOT!r6P`9)MfDX+1(!).ҢP MfsM`ŒI`=QEE]i5+,"hpDíf +>A1kiG yQ4 Ҟk"ƴꙉ="gxRfYjŔ(ۄɉ=+ut Ta1әi ¿*y> #/nI0ORg#9:/\FuEz1|TqOڷ!aĿF+0)u@@`Z$ndٔAz[ōIBe6l_s.8 m&BTγ{F`/ePgxO"K;,.R< |3򎠀iD +V*9;TИ[@T0filXu!U1zX:ڒar0Ux[i,|f CSsRNS5bxU6ɔ6o]zzl4WOjg @dd¡9QtB-xUp%eB M0igvgg%ƞ$1Q#`{!Tm8cΏ]-fL;ty]UbvmgCZ;s/x1F ; u$a?9gfkMR9%% вDjY04J\1i\иPSj uwUA Rk"~XfܧhkPfUBL`*@g\2Һy8:*N^ A:D0 hj:h)҃ %)%"sPY_{BKkn3LI(BػTr<83=K $gD I@F)c~aM#/ón `C`v/mӶE쁃n[nY}Uх9Ϊ0[ 9j0qgil^?dpl Y8U0aAP+:qc~.hxy XO[́xBlZngK`e`7u˜u?V _"iE ċ#"ݡv>1¨B0HV3T@O^,'n׸ΙUsW`c{X"O7w]c٢f9+wCnX'era05B툊BACE)dS ~5J7C/ P؎YꊘKdaĤ1 +Gq!>;jxT4.>^Ey8' :]|1QAFc(PZ/ aрH@pZ` +8'\MVJGL.ci>Nzg[k[=6;(+@OY^ykxyvfE-1>o&gINFz,!d'G=QqX%Ajy$p+FhϢD<5Dߥ}:e&"(z^*5/e=yԦMkQNT0Tj!f!bPVx(ǡIۄڌdj%Fj~W]HJb6nk&*P n:b`] 8tK%Q{a +'ZA,K=L#{sOnU*G,@|ņ;o:rU rbYKh7o@2`󬃯&>,:MOOCNz*}94IoNP +o餜PJ5Ϫ=kfovNXavh@i.,#|"4)ΟFO6rQ?aqUbiJ,+ZT=4#=AY9EI9'G!jV !ʾ-w0'J0>[>H+`:QhE̔?:VŪ7\N܀=C㝤f6ؤd@2IzGZ9M5h(3;wTToiJ/dzYdț%'1flF #5R;5@@ajg96/ڌ*}JEkoSl⡳fYG.#sP%䫲$-f~'\u Þ_Kaj9T#Ax-ޥBSA_a*]8>x< +@Vi+´m1[8(j&V)Q7kx +d%rG!k{wĬ*4l<]T~4·\qlOuܳӘCՌ60f dt̒nTa a[mlV |FGȻ@!Փ +'0G/60P*:|A2mҽ05<{&oJ_u戢uea,?K|,jqD销 `P= &B>C379zo'Q?h/ZPb-JtʇEXdnV+=_:6LB hSzqj38lfgSA7;1:SZ1/ XW8~ RAߣIyXAiCh9ݳ1%qE0_(WIdDP@7?6!҂9@P= +2A_׳@T /B93i^]~`Ѓ8e!+,i ݳh~MTôoA,>f)Y짦(6:`IU?QV;}aMMh,(SJ9/R +QIIf/(-JD{Lэy$_dV*N2[C;Z$xasjB8s蛓!^NL|>oy`'`CQzFɸH_8hbjPm`;2!gُ}$ݏsL1: +-NCzJ:"#R~`E~5y5#8` +Z.O,W aF)j3N *a{:܅IAΓ>t6j<ֆpH#/o;|& ±ȰyJعSZO]9I+7; +Ff$n(48r5~| ;h9 +m^?GUF@E$*fHGɘM_Dd{h; SDť?Y _O7` %afM gvN*q /# k*/Albc~+Ƨ8y=+†|qkB&\mkś|N}Lhu^x2 Rx42[е7B#䡠P\Vg L MW3= V_a$S1x_1ƈ牀.#`.ɥs)j̳aCug^Pm8R^YqА*KVx2 6Q$"?xx4&Ì2`tPnծ@}Nb4 5n͂e'h]pw@*M*G蒯eWh2S!Ӓ=р-Dh)huc$5_iQ9MSb^^q||-Su]xGUU])~3DP[>5^{ +D^8iGtX˺F4^omY-<0wDjّ,B mvfE4ҡ,1P.1SŰr {IFoK&[uR%DξwI%ԓ5!QtJ 8/@4%C51A _*%h0@i,'v#r'z?+ˢfЛoR͉' +dx"+0Ŕ>ׯO<E[yl^ +1U L+<&6@*`>4~xB2xŔH#V%i⹛/kvn^MS*"B'6+iu[, +(F +SXh mkZ!۹:|eT7٘a8FxJJA͙,^m<۳lxGNyiE[#oǹW<#/n'䡉{U\jo?] (T[@6g/v2VV=U=bזT´>;*XD?Jzю}Xi87p5h9yA/0@ I-P +~R c]~w7ޠr& hvIbi2 rs v/38" 0|qIDjhDtnjŎk9rvaudO1TzדN:*- m siQZqLm()xXNg8F|\6qIG߂fХ|l <`eJt] +JCp!\EcP1l[ /.Mف>k³π)&YK0u 0hM)w;&&Yu#_8inlR^Iq%)G7CJY8Μ .'vI6tt }_l_DZA;HogˇlL|7V|O #Q"~%,=Jw),AfP"6:B r)y\`m"D`U/@ s `W܉uŒQ:=酝 R +L6b75oP4d'+AO@O >#+HSѪdA*O6O‹ +Q(T̲̱E)ah̞GO*څgQ3t3E~uo oV +<>H%x3iF. Ъ/Z>t5;VLvP&a8 L@2ЙfzMqhcr2̙JꙪg%0Ly:Lr ё$P`+XR&-s݃NƲ6v($Lti3ڏA;H(aX;*G|шW>5@Έޢ庶;qnX4&nq٨:0'7t$w̱^gmSJY3 \v]G<S_u3VU 9P? c$"vmG䳠07!_X ) Wՠ6z"z;h_sJbD)ǬXv(EHg%w棢rDji6Y.KY@k~[)U, E) ֍ODLcG)3nJ(&;.y!?8x0ݡNN_^itZP;E5P +oV`53{99}SBƧ"Pp(G]A'ϗ?2+:7UbVX:Ƈ|yjTF p\epW`(KO@MQSKݘY~ː#xG_+*3_Kc[\ kcmۆ_/=x@23;0b+Hݪ 7 `MOkBH)oflc0LȎhgհd +ݒ;"+y,ba_1f%a.>cyl~O^ a:b$ ֗тF'Vs ޣ ;LQ&Z=m^yOA3b0]ӵ@NHbUϑ&ȺR1#I3#$gH` =ra;@hN '?.ʂڙE啻YH&o*q܄m/P=f‰!]?2ƞF\dv1PL;cd"]SK pK@@r/.6˒dTm,Jr#h>-%D~vc>"^ 4[Զa+ǀ)N d(qFpB0Kj9Y=YU#@0MEh%zDQtf7/zH |5XqRtA _c#9foWp8 ˮJtm iP=z01yjA!mǮ8 @xD?A'$=']$PԡXFŁtԬg@Vg!Q O(@-WKmJ @Iʀ 5]Ӹ9Y: Tye5k2 eypZΒr"4ԣ %8rwwzW8#4В!7C!D$`,4 jywKp{p{K+A[H,Nȃ44!QG_j/˗ޔ$>t2T{`|!r~0uu+fHj U&T_75%N (HŊak 5 ]#,1m:t Pu1BQ2!3tr_gRqͥy(]R)*łA#M̮uUZ jM`7BY wQ6bW4Yx7K +j9 )YTTzOzk\9;kH渧S$3 +t֋yHDK1]FҤ6[$',ЫJ;K)nFtUz]]; cpZ6+AT*l `{tP,eVcOAeC||n| vw-Q{q-yt- d}HZ[*"e ଘ*9F뼛O%([n#UO l=B*F+ -nɆ +2׬cxYh0ltF۔@bA ;ה4f&'?/r As?g]GL74 +} [Ѵ*;2LN%؏=0hh $20.31 BL̅ 82[|L;_2wuD~?U\.DLp5T\⮠mg'%>i^({v ~v #T'\R(I4R+F3;ᓸH %z& c+϶џnQX6xPd2VWFwT& +j:«-u@鍠n)P|@75P6ao9Ԥ_:ca +ꄳc@&qq%Gp +$ī ЇR]n础)ўjUyk~|"O_!'R6K I!E~xB5[*4+k"AZ}o'HiDFtPʏ͐ IHTb 1%HY.Ԃ$ _4ySl;[ @2h:*Sr^ yz0^-%!E"dԧ46;,T{ր}Z#tGD}N,p16l1ZF-g޻lj'K"o2-P Ey3D×+ +|ho&ܣЁ"L !S)C0NV.5R\Nو 5?%^__)c@6zCE pXh=N$M +fa=f71l P.rMCZ E +7@LߒF5WCy,zf%Ug = 5mWjJjudK>6eљ¢aXqk^̞;y|<2`ugB"=Mّ|E+xf*HԬ:B$-F>f| mUȺhII s}YԌEnPCwYd!Lf~oQ'8X\zBlkV㊌@m%_-9R#wK=0RG~ bm=/tA +9gܫ&>bآ-@<4}p&ge}V,N cqr1oTY#4( u!X=Q_t.~)S%A +J3qEWMkטNk\=],L֯NoP=,($Q {}!I[; T$M55S}qޅK 54r3 qr?Ȝr7W<ňOķXX=sbW0sx9ÑlMA +;ՠ罔CW|6(᎔< ┶>8BUL1E/ *<=s҄ Ļ;Κ$~vJ/Xlh̰6 BF2x# z il |Мf{Sn5IAĉr7bv@-G\=~ع?mxw];ۅ6Еt\[pFvóaL |lP55%knyS= N:܊3et{ZȻ ??Ji JHd>ɖƪbbΏr~M=;5szwoEϖfw6cvV.g3H=)Y^2Bm#$UFr]Abѻ +,ǝn}E/>N$9a#YiUZ87V:7r+<~蜐m3F;>P3D\6!,/FtQ+*A1K)ֻ*i}M&&q90z#v>'MJ됫y+ 6|g6!1NcYRE#4g&|QBH#88'^ 'xDm@Bts +5)5>b\gH# ]4Pgҏ +LDlz(n1u}lGdTtE!γ5 ?$,5? +hckp€;7+=Um,A +~?hH1+QDfR=(G`e:q4 +|xg8y( 'Q7SW(HxW*G9*# +|+[:930􋘖Mm_㽕RTBz>*,ÔʶcaZXv?o$|Go;ZvquL40ºVvcTf9B*j; +Ep !mÁZ{#E̚L; uŃFG,LҩQJ??s!(Ϡx1+D@Vn'R0dusJ+5xr#9i }^3R>3r~HH%&UHxR1H 2Vƽ) +%"  +VBFB$Ou;, e"4|*P(Ble(Jd5;ЂoRNʝCZJMhWUfRQskx\Cs +ƧxFsYR$UmQ&bXJ7{ѤĒBa燆ѳTr OÙ1bhc"eZcT0՛RxgԳ<7TSAr3=΢YZ(; aG5OT$dY_As= Lj)"p9NE/ȓ^}Gz䐤ٹ8Y텕l@`#y5\مu'++VݻjDԣk[ +mSu+FȽ +?I|pT -<*#/V.٬)CoYyaD7#]@XF5~ڊd_ĵYApp G}a󧛉$- +5FCg/^b& ~i! FPn5:}P} Y|*( fی Lt6Lx- V0Ͷft{`F"bĈa'})Pΰo3 ;58ҝ # J4uAE*GȆd +{NcD}pYj?b:~YQBfzP@ߝ nQ)ٌ3УJb>ks*Y^Tm@葹8B:W咿ɷqa(td⪈v3!pA"~ ѺQɋ|ʟMĶw"s2J:|Ȉ3X<*@8@ӥgz =-OCC":褢nJvdc VtҐwZVϋ("kRՈ/ϳxnѪN-Ӟ1{Zn 8!@yh5mw#n'斖cو@5aWӥxr3Q;D)C>ˏi.HˡnjM"#pNQn8֯޻6q\io1aYy.mo;vll( 0 Z|='" 4]]]Yy\<~[ @sa=鱐ta@RP/+RR*Ò$~0p3X S%uXPjrQh1YK]&9B%zp1;ǀJ +& ;q.zW[Vt$GEC+ʼnؓOָNUF$sJr@y'`:tS$Ξᚍ֑W'MUbBL{2 +XvIq /kNW,F58qT:"iKt'L00ySۺzJâ!9196̌5Jrȣ\e'M@X6V041-gG>(+F%j}bnDmUɻD)ɓahQ͍eCEQaߌٙ1'B(4|/+Uo]J; >؜zœ U*`Q|]!jOOɨHѤapL./ۂ^ZX + z MdRSd:v RIʽډNaX; 9B()ޑ8-h!47UK#sA v)O ٺVJȶT/MZGCfW1h^1i"U4͜HҢ- +7lOfYXOS,Nla;;bR>󱑗!q~ Ec ԢN(\i$4B6J.0,.+aM+=bu~6.hu#FtKkpu8pSbѶxÉlyS*4H\3t^ w)m9l9rpB'AouXL6=RO ZS#s§CGvj+"xM ?njNhƱ|ۅH@\EB$Ҽ 3UB Iu wЉnR+}PAXգ%T4Ai*'W*m9DV:&nΧ҄ LS@ nt%mG. +h BX1}!;^Ao,kJ[:!;<8@_\9+%gC (~nb7(CAi&V{歭ќ:t; idZL3|ش(DJM/0W[)m8b/L*{j\0H.q7[pU=ܒ~W0O6k݆b(AOB?\И|HbCfV %:&\\Cq5Պ18b !O'm/=Hbdd%DśA;l}Q4vѣbx?hYX)u,2K$50${rڨ$iaͮ{Eݏli!`[ еpa80*Ul7:8@H R #KKRD);[=ﵤNmU6QIEGT_Wx2{0Ҋ?L-4ݪrB̦JW* 7:VW Uy X[I.ZĺԞ3qѳFPHT8S⥒5)`KjEIS,]p^Ԗr:;są:7Ӝ'9BT7V,i!;(du32G{8SGS +Kc{A cBEV6z{4x#C/bKD ԭ( JT"$EhG/KmGre{VUS$qz<CB XBJ[:^mCbzo½O0N܄=<8[n'|t]DTTWӨvHjc(e%R1eOXfLo/TICݖF-kAw:1f*U|gX[ O)TTn!xc;aMJ DjGk"K,T ht1[*2Mq!;$\̶duP;*-K~څBzEIuD|jJ$|}b`{$SLDQH,lAT UgbXN<8A]Y#Hx:5ܱ:s/TFmgGOG෉+2";7rٞXh9:i(!T!P] 6`>hF%8suSX#e?idbU9^Nn85KKYH(Ъq@k>V~p Sdw bn 2`$ŊH:YQ^ Be$5 +Wzq]pY0𰬸5a2fxd"qCꝢW, Q*10EtHt;DϬÄà|Zp?Lrqkܢ"iA,|D3$0a`'%룃M'K7yRDdk)RYId1'ό +m MS`y 7͙Nh[-Xx<تPK% ؕWӅpX3RKq`xk]6%0m& j"IVMPQ!¬JWH66#&>($DJ RS Y"L/y=Q̑@ w nW!ޡ8`UFz[y`(_'>Ӑ}:@PC1KH6EQKEȃ"*  t\}=6Т@nNaw +BOMf<29'`Nm 3a7pF&D<YͧQ !HIyRH{Z V\IJKDj"41"ŔTjņ΋MYT69]mxmyu ꄍ=[Fey=SUz:EA+Ïa({gn $D}9s=8 zu] Ȋ̪',@LPM`.'gCyDk 䏼PB^BI-7I* BLR!;y)rFqF +& :aw3ΡQ!khKr`Q)Y4FȀ9B$7IRaBҍ9Y̜b̡^! Oy}c"DBuqwq:;3݉ϛĪ M(iᷜ5B +)FyyLb vK J`-ݫKHKvN𜙗Og"eq=\xBܙK1}J9l(AS)j~~? l&~c9a$GM#}cI62cxs TuU<ύK~[ ?EZbZ`kTO7ܶ6I >* ka7}3íA1=ݤnzµ SʑQ@ +"Hb#䇣+F}'E͜+{ + 8ϘBA#LR>Ke:RTad(9DCrhX"#[iE/FX $̔F}T2A +'b)MO)"7Zȝ +H캧8 [I\V$ݻfYj񶭮Qǽ +}"@m[uI (IFζʬ4wDBb;4%8RUĴ䁂WOZ|Lk>-m"u[m0vcAWf6x*:ĴIl/6-T%0DX"(RDl*4~udġ,; *7%91U7=J~9dknck +̞afh=&"96W;J$};kI ڀ|!RFq DW}ځȥ +"aJ +(*bR˩J.ȤMHC$$ďC~͏`g9Ew9U:T踳t05vi'r1Q1\Yitj@xuEXPEYEM(I\zA7IR ˆ3}4OLQ"MC-CjT*?d)AQT|3RɈΡ &$6Ja.X$P!]GwtX)О{rlZ :1u2,k<*NQ+Pۤ ;{UҴβ^iq=M4DIM0@(fC\X& c6 p0=%qm:1FNAJ%:z|k$ajzT`C5#Y4^/5F)(}HX$@Lj %Xբ%EUVcz4(a ~"uJĥc[yDCW+"yK2@ X@ K7#PHJ}i +endstream endobj 66 0 obj <>stream + q4Q'j̚1ӻ&Dn|HOHx'$Q݄I3R-J#7'tD17 +28 4!)GW $yjpP=GI`*c#, %iW뗲M7haniLc{$%F IO`OdP! j|5!XU (ƧeL QQZY[QeHBZ@QBeֹ*ՎдC׆$6XJ `zDQ|&܋(Gf(tylB)؈xY: 7<."RH9Zbuf07Jc}<3i^8TH62|ΕJAaX:߈T4>d;Q Q%Ǩ,ɠH`T(32 UٞHϞar[j[ }8B^#FIr4ҰUTDyFDv|L_&ެauC 2Vm6'~v4fm@9ɔCԥ4Nl6kί>e96(qEbL~*μF '|wlN|wl<hFq\N2{ 3;@'tUkZRmlwڣ2(B`(RA{e;+/Uх#>=x>dFas:UI 9Xe8TpfڨG9Żj:ɗlP::ԢB>zvP/@5($]]tp,kV? cH4:QL:QU'G~ߓe(glӥ,м +r.Π<-#bwhQBbG #,%0jYC*"Օ4ƨ9OJDt O񑝝-9XQB,RtM G\btT54sׁ2ٴwJp%0ѩ3-p*xx$N8qxG%ꝵFlq>K1͓dPSUi磃LZ.ĶTcI&ɂ&Qx:x\ߑ15L+ e`=rsЈ 8åvr) WB(Pq>2eVeZЙrt-Y\@%.vv + $|!xJ-yԜG pPrqQ zWԌ;OaU)Yk_%LN'҃ vw2B@ZB#9 VG^XXfD*9?Nq"^U'oϥf4ȧ<)Y,)^RS/SW6IPu P3U" QibUa!LvTĂXAdf-Ա=YoR_,9 5/|* H8QFă?J;W +h;*G̩Ӿ5v$gxJ${lFb+%mwF5 |?Q&`:`JሔV zm:5 %m&ҞbQ'SOvTP4O<,l4Ds LHq# P|tSa%`/$n᪤=1[ms +'׏_R.7)Pf9H. IxtmiJacocK \dWÿ@S);SaEbQCo5J'z5(`ӬԒJ(H]kHJqD P_~ӄZB- Y财 d4%-DYه%_*dX*B/=[\oWj~#Y.hK4ز`:M&, )<@?4m5 $L' +M3DH.9BdVu{Dh>p[W?% n"wĮ.]?;)CKbCŵ7ܑvSǡǩlvT\?s qJ,)ޯ`}ҴK+EҜHX[;eDn.xYdHy7,OBT&3! +I ҆j{spf.W`*( s'M"01m@IgAd֡ػ1Re\O,.F,y?\)viUПaϬ6S8eOFً: Plj\iI+4Umh3| +=$ 2U®,*GFwD\ 3bOV)DL9P ۇ5"Pryj/ie A! #R+%ŎyrH% $:C3HxP ҫpIR˵e]Elp<:J7N}of;B=tɲ}Rg&s1 +>vBGD?)Mi Qc$$_H`.,/dG4|Җ97'ݓFmvJ0IނISSlOOa +$&TD#wлcvUE2ܺ"N " +@t*,F Tj?,p*e(mX*> /[*uXfrp~]= +$$,%CbiUфb Ťl6k?(o^P)m(NHc~$x%3صr7{QHE1ٳf6m:$(;P-HU:#+YB9J KԭY _3V+0tdB +eRJ/6Ck9H鋚BAX-tËSeTIŐ)JcJ/C@D6r@ȃ;>0yuh7 +赟 +*nR@Uj;KvzCibLp:" zS-yRU!lĶǷRd(seTgIFX6y,݋57 Q uN$?"Q% OoOlM12LETXWƈtx_KB՝>x\6r1"*;UViuQknu[5R~u)֔kOcraQqE<%+3[m`&Ӡ/BFptDp17FuɧӛdU.zѸ 5RcjdXiq$տ#&wœ+LѓC]EjH=%B)|ZY̅й4*jxɹ%̛҇\ + +R +gU-8 Tuυ,OtTa r"Шސ+fvxEzf&(ܢwt7/*=a +q.u $ (=[%TE_ 4K[  +11!SMA !&j$tS]DwND}:=]r"*2P^^ f1ƙ|ͩ.3HHMY$54U(ɖ$*7NIT>Q)uxTFڣXJL@ylIr_ P4<\fpz .nd!WRxGf18(0rU]:E#Kzˮ}sa20 hz(x  ,]:X<=x#za]ızCGԤB4 jȌwCp,{13wbՖ!dhN)ŤéКǡ)z8'ҝ:E blmby!I篍n +%d&aibyeγȄD\HQ/wE+=,9+ 囹eHHC],{ ZE (LOOt{zV +D4A*a|$SXہJ I5~ΙyhʚT(ȴ8‚,3l;mu<?ڕ\)4,tP +K(Eh/Q(6: +j(vzaSBA7 [KyRMѻz3O{+rqtG\:q(u" 3\vD4(U0$[UjH-zP_:i?KN vvR*Vؗ#F瘖bj0ӯ 2@ɀ7:)WNrWb?!Ň=b18T&5J$h/H]&#`vP`taə@䋢rkR,_H %0<7Ə"`~IUZs&O6-B^^=Ս(` Eu^ eP'aCfH%R&!9*|).ԆvQkhSbKKXãy]@f8uy!PZAS=)OV,m[V"2j|R +.`+ 0!SKE>w?Z(毥 +.U)V ݶ!TIؽ,2oU/wjaA$Bδi*Se,+QImp?^kEgN\ɰ Ho@ +BE*ҲT˫ qEt$i1*IttvS~U?]^mu +̭-%xUAR&`֖ȺjHWмfN̈Xm|"ְt΁MÇOK))/Q=`<",sD3hW6(N" B`Eǁ +"Un_u˜d6-y]XP!MoTn@ s7()J 9]!*D;R{>?:9͏ noO;4`ب! Lg?o~G|y#?:p9Nxu$ݭȿ>8>yy7g z#Ʒ8K''_J ٓ7/8q^-_?_~Y\ɛ? /_Rq_-ٷ?;Oy|%Nwە-^ѢtkW/uU87JS{1|?$%+:/x;/Nso10Ewغ_[L w+WV>bSo1+~zWez߿6l2Oͦ[|O@ F具:i73<tGVw %u6^2i}~Ԩvm!2ou^&_4 ׮az]o\7% skҕ7/f~ĥ][,S=>\5_LZՕxˣ'z3o oUkR۸ZqYqеO7V7[?XŦKz0Č\-1 NtF\`mZXw.8'MQt@V'ݪ.6\?-֫Ѽ˭׶~[@tŭc~erv˜k閣?fNaWmx6׎jϏfyJޞ=x𛷝QΞ7MO 8|rmaz$!nkGvusfȎru׎I܊IW=O,_OnY ]Ng&_NzX?_/N{syﯾ8zg.N<[:}._l_c{ʘ7=x~:.9~C%B6ɽ n~ډst_>9];ze|e-כtK5//^pmxV2 ~م?4{7g'/O6%MS2^yˣl1Wso'87Wv_Cen<ԋoζ1kp/Ͽ<<YkN` Mm oFsu9gp<}yAZU87o.O~wq-Ʒotw]ʐ_\]_l>7y}u˭_ǯ~}|>8eiN«?~zws-t}tN-kn¥n3]N⣋OnD=97?=;q_P5+}twgo%v<}}'8mJ;ߺgwGo^>=z'ڳ-{4[]1[<-vg?~ }?jl$Biur7|uO7-:z_|}y.]~F{F~Έzm'ldy;9G'm5o78(ܱ>^,AEy1FzPO_^>*Yw5ߴiv{Ȯcg}2N< ީ !͟skG?8bhhXp[˿i_QGwemv"##ңۓw1;r u=̧>< ypr` nWÛh7ŸhWgO.NN{ӳ-˻ov-b:>b:>mpsvgo흟_7C-Z˸EC-=Mş3}[)mg>>J{g#wlH]]n jCwOHܗ2˓oNN +f6shs[6-{)lXׯΎO^ѫ]۶yH;b*^6fR晫][ mWn1oqϰCן[l0n,;b,<seEق&=U#d]_K߹M`5ʼnzM?]}5AA|vh +}5MD!Sٳl3;o<-:L{~} ǣ6fG9s0Oζst6^/?ԅ<G\r"ڎ%wͳK[p.tQ=~إ-+=vi7=v>6ffgK1;~إ.mv,t{DإmҎG]:~إ-+=vi.?^C K;TBE(6x{sQn?x>(=z1B#E;Hyhqk-|,c[ds?%ުY|XfqoY|*,bsaO*Q{Ua(lZavK#߉Oʺ_i~m~'+mO[t~ n+}s_볣ݲ#=KwiCh(^i"Eg'O_ީp}urtmHrVr_$<{gwMOrt?3r"do%3F+$ΚvB\Jxux%ū6liGƺFdެ>!)nծwZ`b.N/xqrvFr5Ŵ=,ck# +c=^B-8޼wןy1B}5?j4j~+W?x?}5jpo\}̻W}ڛ}%ڷvc툅Ǎuvv1Ǜar7r}7[(}ھ3lwb׾+iN< gU<6>O-SZP/NN^~afpN?g'_\<]Ѕ}0l>o.]kwrf`|W>Utwz,=mN/-RjN-R?_YTM{llb> ]MdK󀚠g}&jg}&DgZZJ }&j}&=eρ_!%pߕ#gy9eO;B<5lgDXgXp;:ΎΜ^~}tzWqn1{™'?>2wswe_\%vgKޓ}{.,{y1B#'JGy7v؜oOQ`V0kñc\B]׈Ο?}r8yѲ5O8VSZhU{Rrː_l<<} ~_[i'[kp!o>-|{t}^=:ݟvfOkO\Ԯ%o>y{O17o1>yPSq7I|6\P]_t"Û3|v3Mwke>9yyk5]bh";k6+pK;|de[=צJpsi-܆Ӟո4e۸G/_lמ}mϾvuBNk{ޜigGR*>S8ozpmkp-`- +=ZnOsŏ́?[>sі?n`~VKn}|OC>>ݍtsǧ9Fq}P>@?3ˏ7@fhGn5}8?;cPtӣ\َbG6<2ƈIwIwڟo@ }ZJs?3-/_^o$__tE ~_SS~ oغ-StϢڕ4SpGܑG.8 &Ecc6Bus`7ϏO9>Y>v{m Ψ#b[ӵ/>f XЮm +?v':./ʳ@CoBsߧ/lSĝp_lNMwrfKT|ݧGS[!G6iۂw܂7gG'|;tou׿y_ b'ie. Aym}fNQbwe Eg+ +o)֢'ı5NY|Pߣ^lwrż=Nͳ'еt/>:+å-&G{G^P;'C+b%?-y#[}%ڒw1M)cl;>ly\nx't7ea7qO;L]#^6٥wwv؞Ew_;_nai=H=;a[~{\u>cym +W>g;=]"IنD*JTven]y{ǻDZⷧ%ˣx͋c gڗ?z.ŧ5r&O$>y!gP[H<]\y'qWO !y[_=;N=g^wSŗo٬2o}_YĎtrO> þ8U8vZng|'q'?//y_=;5Go̓9.t1.>dw0u]nzӐЇR>:A ?Jꇲ(!v)ҥiϹ'O=_vǮue9>U}x'tC,Zc?pLוc +َ*1;9n~!{g,]U֘mpݡb娺bGk^/L{nW]?n~߆ŗo;Fou2V.N{竣XCnyVdzz4/J|I֞^81rX.C߅E^:N{a_w|޻7گĮ.y60/p8t6 yap9ȵ!EJsSM]zLaLmjɇhnC8&2s%as +z3"1m+KTNN4 }{V;Зba_0E]o:.̱=ycrl:۩ްǔjlDiػ[;c`۵s|enZE-uskW*iX12wXr!tFXueTF.dF -fHvU7ױioSr&ܻ-+7Kâyvj= `.7gg 6㷘"wmrk-J٢`m-2Mt{^)ۼ1!lﰅ7]ͬgm~Yu<,v̘~OKڼ)n_+SB/ ^oˉ\N_{l[qk ؿH>™e6tHzK8:feNKH擙_c.XU<1"}c?~S3˔RN9LLߘ=Rf/kͯɑ˕S[10"@KߔקD>O#$$Drxj]秺i>~|-b?ٛO9o[vz9ossیO|~,si0Q;vXKs>Zl]e>c[瓝r{ Js}O}|"ji[ i/ַM񆴾jZ?~ J믎s-̞.O1%<3NޜRѹںciN|[,oy's{KG~RgWXZ&pS)ohkwJꗚɔa%G低S].#k)h>gsoW|}N~Nյ9?^p<~Mf[jzUK\nHYYjc+x1luzhNlo Jwi Od>5-mI6z m /Rơdvٿd>ڿ}t=\'xW=7~eoc;C{fkьCRkᲝӭ7t +1{MSܵR=]^EF - +ClyGd?k7!}1`Q2}muCmTr&۩u8ԽgTE7ѓä-^;ϸvRT`lV +zn6p̭'FBbJc&nbnn+ 3{P<[#V8z/W~[AݮB-⾯eu + 6](unqlԩ1}:u~07 %D)WmlCvQv=E9jdeC c1-ah7վ\RɓV${-jՉcT"X*iُ0M]bf#2ѿ[ 9\y /,{Ti^{U ,s3M3c̰&\!I 0DA%lZ{[9nq ST; [ovdQC3pj538({ jo)^j ;*ҎV.OE}i_D>BI)YMd֢>jHJ(o\8>fᨦ~4+Q\\IՒMVHo/[?WI]YkDcT\)!b߼,q˯y'FfCړ9V7*h=V7H!gv~VckCԊVMݺrn}ZQ;Ԋ""&Ԋ]QZQN@+~.XBAc V5Z( )N5dk rբiJk*q0Ǿ#٢ZdMXrѦkwERE{OAKE?+u۵fy/bWj׾}K{#b$-tA\A=el[Yx~Lp([ID*^\-ٵM'4%02_fTEj~wI&%.ڙmm.+}5hѲ;zow/ZNOb +V+c'XFpovwo)XXbQ:vhvt[\-e-3d[jDܚεQ%P0U){}2ȝVAeB-4Bɪk5t W[{ו=_& 6Mf _KQQ)ew>v[;5][x?o[p>F„!^h^ &bT60fЬOؠ9OT~s\J EaKG +-VmNG u{?m(!<4K-n|m*7'ah!t$[|$ou^B%\;P5|u_j}Х귁^j]z]!#O/.^ߟ*^s$G["Yd*,R~NRUKmer˳/|7?pBk>޻V9 +Jt?xoNk!O=ˁfۃE6ݸV\{c900HE{eO9xZ{+QbJjY5ůH4 h~_ i/~)ILeS39\fͧic̲ke ZuvvzNJ[R7]sJmnw<'bQ؉;,. %i^)csd`0#+ ++ +̿A>^2R醁nl}9L63f$sMW#=0/5-Ce>~kytrrnz,_-厲GSѯU8h-sc>Q>:s@q4B}wҾ;iߝNI{V^fUתkjZ5ojJF]oTDj6lPR;N9{}Rٮ ہIJEewE27T(){G?xV/55e 뷪m:2v-γnxZyͤux⸣hLI15>^ڹ ve3@\igrF;}=Ƹ٧"*zGffq~Vί[V6sXN"iD#0@FO&T\.X>?18 ubh~`iT_’(T +BX~Koteha&DrVZpG flR Ţ;Xg_Go:8V+u=&qc.4nz,aqSg^/hz]tJxe*D{r+3MnLtXAQ)} F:~O?B> +PV;fhYE &oȝshi5oJW n5Zա2JGa^)aRY;wrHiʀQca۽~ot-1bxVA ,`f:Gs7bkzD(o $6# M[_͵ /-[7m n=XV@XMGvݻ˖fט]#x`3ݷN==YH-fmiɍEgj_iOeY Q?z3$c#@Up|໷o|ǭ|}y^O,-)Y$ n= ˱MCDQbiPRLwOMwD{Gx ևt`{ͬ/fka{H퍶mpS%4ܵn9LOvz qXGLlXWXCKdz+h1'~m~L4æ/ʉ7V~mzk$%_qnf׋I~9Zܰe +rȭa&(WDW^mV^M;6+3n-dde\m\oWNa UEiasz2ySA1Fu=/w>VDZVutM|}vنB^fX[{cyȞϑyho(SoWCk)殐J[© ^NoV۲ܴUd8£~&0HR\ʇᮑ]TuAkg\-%-/RW3U@]>i_*!f?%uӵ/<}M U*|ioN.J{R^H.R^}ԾWj'h }v^}ԾWj{JE~?p6EI6s OJ%XwnW.dmjNw06f9b}\w MRm3 $FcggS[ +>!`, ,lAoO) +>t-B%6;Ez|_Iwހ^wǸA.~@m`Ʀ7dle/b~zzF$e!ۘ:4S No^2v)ܘ~ ۻ^͆ÐbӠPT\k'^ _[ϞxMNb6c5/15TSoo/wjkco&uC_'VGW>1I|}'Gɀg{j0~)V/6t\`ʢjJrogըf'{';9>9qXkIi4*;d :v܅۲eU Γ3md1*LuJ#x4Q{_G:``x5OO3  3y=>>SB G2^ r|gAǞBqL/q8=d0)`3 +1!A֙p! =k3l/Df8:LD +.9U r: aԢEO{a):'*r(ezM3tyq;|xU{|d<} s@6 r +N/ތ %,m #>ob>\(5ٍ*}a@Yr-pnզԔ`B1 Haх"e^`m˺:<$nFI=QN?c; A*9Lt 8 9r O)U5C/jjRUCg@9G]0nuUXjHԙB9@29e^Ae䅜Ja9N Pe][ )!Y'seED\H w%Wd ^R`ӸlEh)u2P4O@x./Cߘ %+ރ9Z :c%`MɣK(񺄒1@ +f9C$»JTBz$VRti &*,IQP21d1(qjɑ2"譀f9F`g8]LAwp n qR9 ) +Qr3|:#wG@`%gTY􈚂 +P; +,_4{ARlcpnTHŇu_@SˊB "WR9E.skDK׉q)NG\5Q-X_m[~6'W^zǼW^zվW^zվW^zվW^_y[p_'و^neI?bdǘ hV8[Nd]1XaY#bTܝ ѨCRD/><8K9CO]\rǮ֪~+qbb]>^TK~ܝN1X`˨ꉱXXJ-1 &@Uy̆ Sc +xfԘ,9lscK|ϱI ^֩10P|jlN-."wvct~1n1.c ;1acgXTX&:,1 9{Q`=H9-[G&TO$SYiJ/yz?;&5}x/Qg4~h\%3dp<* 4_od xDžq#' 9k/2&D{x}ϼVM#9mkcxUqO/gt;̓wlO5!W,8rajkAoQpQɑsBKIk'IoT*Ft2423"VY$!L͙5"cuKĘҜ*mzSk39duQw&m40xI'%de=Yc; d2ddx$dg=FƬY? *!l3[A!;" 쓖XhkB~3C!n "JQUA^hP_;F{#8d [ۓaWԱAZa w+̰Dk7rgUG@su_9?_Aܯ WO#z+Wϯ_9?r~~Gnr~~En"_9?\O3%b0}BMgp~ūK tiwCPEoSG+PxJuhh>tomy{3_[X,+ /EkЏ*ip$M` ׃'PE`F$c*j e|$  +{%0+ iI'1& {#b$2Rq 7gPaXg~?1w0E +QAUJEf\3I'BR m+=7&##sY[OvsCLۻ`(e΃HQǙlI8 K V0v3(T6@ob@ㅍZW,c01' z2@4pP}XH@"h_ r,yJH2/BA("SŃA ,aQ`QfbU%U +699`[fT^ߓClhY S2z%CLrƚm؎.'„ Y=-.56ZHz@VSIB~}K "D]RH//ig4ILtI>0P 'v-Zu9Qƥ9'NʴWp,e(3CDF24R +&٤qs7x\иs#WH^pTf7bt_FIJiF"^5 +8'4܎V+æذSW`X͍~~U_qտ J6F& h@,qBb2* +\BC +QakQ@[o7fBHUH,vtYvT_`CfDU@RCK|ϡUIl *W kG=q n_;#vS`*ſ=T`}? (QQYڲpVT"pf>XC +fU`TѽOϊr +h=PNBr<K*dcK|ױa0$&^4L9P0W4uK4U]Y_ԯ`|0uof,ף;C$y"QDR{A#Id VHDII͑EQ1"+t&o8 & о=XEq,-z!{H0c9⏦z a}RתFG<0JcdxېΆ +IsJ"L}޸IzYQe^èDUe e',0z*008NXw +NJ4"=<(fH.|D<`)*&D_BXb1Q-#G_<մ-6gz>4zL#S{"4%)8Z}'OBXh,}ڞHArϚd4SH$f +Uu'KS$a`I"!Z/̴N A&wp*dHtJaEnE8^E'*E +D[T\4FŰFe"Bqetz +`"YQB1Z>X(p[¢cLۀ~mih|mL;F&baF} +Cm M>GH<"'1zkbDH\5Y"+5>Clz+Ǵ,D,ǕQ6h= +a3uPD(K8/A y%DOOy|'A"Ia%T y='>@8Pq!QTo .˳?~'z-|K8RNL TIvjݡ}TeQ_W.7FʳZg$jnl2iB5f> 66=D&!tfѻТ#(u[@JwF~aѬ5F P+-wvoK7XݣNi-DZ?N$ơ%;tܯF}|PMV86c$dv}m&>5=kfvbCqlTr4lλY^HǦ +}3ҿhBIEVoQ\޵}];TM1Z54^҂]!]F}C^}"T)xߟi2Ǝr*EiP;^I-4gN۱^t !,8qU?t47Emc>Պ\(F`Nb6Fv }Xڤ8q/dRrc%?E괎5` 5h6vѪsp__6o/c?uO_+|\_>ǵί'HZWk*!n/%~%~pc _nGN&3_K}/6b93 C~P\ B} //|}ɷwn>J֫Bg*:|"9H-9ڿğf?dV5#a['=3i )iRKe)bjkRZtɉR|ZB{䰟Oq|<u:9ie$U80`NQAX’Eey{|'0,XZTT9U`Ypl>gL| +|36FMm,92.N꤯m~^S&$@c˸b9EeUE$UQ0 hIXQad{5 +**e &y66ͻq?uv3w,"XclQҚfU8UE +\~AG +Dax ~نI²*ǰp˻hhЬ" +؀ZD a? +ol"[jAQxEP +g%!v1K #[@wYLGa'l kmm8mBEYwE0qUFp" TNȭ 8&Nzn3g6-rhNXwdONDYe8͜pod OEF=݇K 88w{'8|>gg/L @xFhgRxz@ 3gU#0]Y2+mi'*$l&1ASa)< +,Bcmz+ũ:06t94"*ԗNnE Ăc2^48(Z8DAft/}JW]2T2U((0*qAiX3dڛe$bƆn `',IH*jAxeQ^ 2܂ +0|Q 69 A/gxV1@:0*+ PE]#BC +DzGDB~ + J,4r" E0.إ`us#5ɏ_@,Sq"} +#eJDD Wè@<@"Bf&܃)B8%4U DlNXB_+e;I kemQ +(t5 +9l<0Fx'@Zho![븗 @BQ%U}URN +|,C(+/MP +Pb,P +/( d,FQyca G8BEh XӷC axX T ZP1ݓrzVYWo(0P AzQBqO2/,!^L +" 3Faז)_v\0A}b=Q`P `E{ATpBV8 /eʋ@e ˖'2)$J0h(! 6Ƞ$!U+8XmZή4n !t`2H*|ID5QI.`pGX ;a,-)tzθ8[d STeL +!/ |ŽTX@V,M6Ư`[ %L6 ƈfaR\@faCf'ߦx!~Bi0僤Y$%DT Q4|l5-No -ɆCj*f|`y %@" [DEQc0QnƁGsD "0f^LUN:5PHD*$wegonɄՠ_HIYvĢE& H p{20t7 cSLF:rZ@/vF3.nS#?iA>STZhL^k$P魎`#GQ?H%6it|FG 2$QRLkxak|y0״&Z0FWr0 h5^~Ю!GY|}mRtKPcy#+}V&Mz +z9E1^2elKZ2*QѴ=&YFMAw纜}|jLkn./Pc'h6p~]6`jwB`mhMM_wb+t͉fqf Tz=/v/6R' +c<76a.5fw@$?>h =\; (=#ݎ[V.O3_vg X rgc>?$z4m-jSKך債~X4Z.7fz|6rjә6FqIe38@f駅'iiQ?*{6LAoh>$а\Vukcm9k֢Yk&?ҷDj_4GȆnvgzߝ wgfÆ6YR>fw>p4 ~\>&fK0s]ViM^vL x1YRƀO*/W絶(dywQ/iyО́]BUgɃm\A;·Mב-.U:A +t_8+j_jd! 8Y/(2̊=d?MawR%,2ɵa]_XWm +Ykpʄa6l%i͑'~?ߙi_M1Z?/&42:[b} [oU{8daw brqA%Sw,f}WV.Fak䰹&sMIgd<jrt \Xn3-qdgnZ~W#[L`\|BMmmk5~X~ :PĴޝ j]svbe6\`p+Ih`Q/L #5I<{4}Lrځ0vokۆ}ڹ}J?GHB!UUQ0GnNw &Dwr'aUe"Zubg$VyvkM?)zr@6.xK7T\YQCK"˕=DR(G4Cc5N:&YG|Ph8N$ߗ\hV8v&^ĝ. +pBa ouZi!]3N?kN+=&oPӶ@Ѹ9_KEk4`CZ= Չ)pjǓRׯ&)HOYY,Pg[!bm!-=(%߼vĖnKmbSJAZOF2W͝զv_oIf6i?]<6޲K%3mԆs7h|&,dqmOFt8R-.hzm &swXVڮg{u4MM9[ئtЁfZf;ZT#9вO_wj`djDm68& +ue2Y@+^) `/-xzwǟMQgv3-z6J2mɡhlRq-čvV_LEypL=''r+WNqzRLwp?d<w:}o)r:.hVs&,؛c%.?cl"ei<, ƪ>qp@o |<& ^9>-\yhc<ƕk~ ?.l<W-; +RRvwï+Nv0>P)8A|$>c0QשO# +}āU l=.=HN^a\HjS?t?N99];zLSs` ngKy.xļU{{$]tR%xD39zL4NMKB}ݛv.uzp{] +_KVeB4?]l/5O=t-yC폗@*;I{FwlIzK􎚇nFQV7lنL$s^F5=9; +96qڐ\J..l"X^ˇanbB=+<~yn|A1u>i u}sxyi` <Ǖ`ȕjT".O>bAlBytn IrSW=.Pw˰='WuzON_>+6p%;+r)ΟYUhW=t̪= =.ktsuo{s3;ܮdN;n_~37+nʠ6uGގ[X(LƝ흸Oׂ~t߻}gur׊[kwd={ik0 d;{O{˱s/bxp/JӓQv)\-Վ܏{eg6gоx~`=wWi Y<DL\w'߻fw/~+ǭlAy yc =GEƽƓ]oxO<ٺtO[=m3n9N_!_#5C"y{9/}h>O}!ϣ/=>gBikϨi/zuck?8e8>s7:LIJ(0sds}u'a$8z.7>}8na GA(Ư>n(Xm> :y C.P5 .oBa?#`T+MN^…~x 9KzqSa.fE7Smn5/2C{se|a5&ތd;<+VnN\tsɗ{r`,G}R!/ 7>)E9q?{1=Vm0Bx '#\\o&h{SaM@?[%f}&\`?'N%};2pYʯRKG? pٗ;zrs2& +|VdBPWJ2 1NˢTuQߴ=XJ߽>:ʸNGZg|ԭet,$T`z\I=玛dzsan1Kw#Ny7}'WN䵺wy2ar=I՟WCI :=`w<ƹi-s:kj,\Ȇcq?Xsǝ/Ͻ8_{v}ۊ:H=^13I$xd'\.,fV=[M͛)p5M]Bm''M'/}䌧}}9wֻ̕ iy;ɊA%{B0F>M2y*Nzgwtl+~~HɅo]]D5w\<_tZ[x^s{:h7Wn\=q +U\J?^݊A)U3Dž ]GwP:5wi^|̮ϭ w\ ).J4(5M9./߸t=*J4R)y U7C9v}3 [wj˓~%[7ʾvҊ盧B{|=>|S~gz8N*GAڗ{d[S%~ylԣO)}xz<_՟o˹Q/5Rp>^5ts~=kx <S4V=Ċx]?.jZORCUL4CB'K-*[Vo.=m08zx)N7t'q;ʡb.}>?驞~WM}\GJ~j :Eʃ xՃa}6PFgSFSp׷(0[T=&N>Mb/gjlɡS p?˃5l.U|ɷ<<&5d6 j\1c6}h%wTN^j񈫻I> )*8-ҭt=DTE= 1; +"30A0~x!"f"mOhk=w|!:m ݞDW/d6C{hR VXI Kiy':Wnt҃ވWRT+|RZ- D1*w?bGmW~eՄp/dR﷯>n ۙdo\j,Jcp/yIc.$8t8>萢RWfxb6_rm0&n4* +*$у~hidP9퀩xQu_/XB7-m]L^"'%Ux=c_#z@.0r5ܾdǍR\~nx֯.4ʦuuݴ=2 `|3&޺r{'1\VȯϬǙ7LSh he)QNHB{V=$PSᷱ?>kautˀ8}82/:Pٓ:}oeݙs'wRusoLyc_y#YrXFL$󎻙HXC_duL}|Zg+w&Zy8>7b巋U"gy?y5^W+)< bƑN}#P/knbc.4i&K.OTuwN^׼FwS^݀@3PS^x1; 0r5.z͔'i:AБ&[`wzkd\ V_ƒehVbV@Sc DFmH(}82Zy[E0~~u2f9zǨr#%B>zF˴1_FׅG 27c m<8sqY/Y/:\ #Qcx%bC iJ:@V+ct*GE麱lqj)IZn+:* VtJ4wtp6J3gߪDc;L>`4O*Ȑp t6xz9 +-.?g;ye5F)}&Ջݺok,}xl⬸ܱ"[bh񐮦A) 'K-c;V=μH؇xa+L4P9`iqt_#hk{C:N7+tm%S?}f\DntI)ج;f+j?3jQm;G|)C +ty/;X.DQzB~YMyjEhu )u=3*3YV^*B?*]Rr<} +3U⅛K {XFl9(J7A6їڏ6yU5Xgt4,;vU5p,\-`DtfToi8Uݜ5WO9=ΓzjsB.`[PnxIy938U DO!9wg9.On_(]$"\]ǯU4ɍ.摇{zɍC촠M@s !23ɤs#oO c $R YB'f\Ǘz|4?TP7Nal8}[0CWLXX2^> C=GNE͆Gb"ˉۜ*`N©ǜ5):R^}+g^ݞT P+{ KT P]ǭrg Tji]|_/lf4,A0!VBoN10E.[utx&u_7r"GOJUU㸰TX{}MX`"/`?r&Y%dKC՛S.JVOD}LR`c6Qo o?Y3!Xt89R|q;S(u@B!>¨1V0//clj]-&Au:WN?h3JAtS#IԢ}鹍T'J^<]j蓯4zܙdIڥ<{EXr^DR3[w/][SƓW\&d]JV"~~37l5St_{bVenk<*]SR3H4wS\aRݘ#a("1y0pG{y3Э v橳4uXϤ#ĠW@c LON*ϧo26qR$nUm2)o-#þAAF-U2{w]{T6ޡJsۨ>Lv3-O-RZ y0qr| R=^` ?*G† Cω#02!:JGVdbȟD?~[mft{I~k4aQn:,|4 77 oOᒞqN2it|rĜ>n <%KEZCdE6(/myX{:Zoc~gWЗ[+o^?Wi@tZY'{G *uEt](y%`R?&ߵq%;a =^If0=֎<ugpӆ:q>n$a׵3PGqkMȟ +j1fB9`2(L&b/+X"1Z y[H8=.!4n]t'?|j lJ՛"&ϒǦ M0W,rͿ./#.3\ L͓?߀F*_Lb5KŦ;Ww'븫 W^xMڢΟRß3d:QdS{yT9ILvfsR.7GT{/A#zl6*G\_Ll%{p7%,-rRgޞrOaE apoaoa=5B/܀HE۾v׾WnbOs0킛1v 2kLLjls|%"nD/qtq4d՚z&~iбx {Чk +v;]p}?VG]xO~M73\icxnH>1:@ e75PC:x-@~vzlŏGsm#7!b ljNvb`꼟]Rɝ^&Ȇd.ڨb^I\Yx gʃJ/Ē(]{{?ƠEpF/煳ttwSh]wb|痎;Z@:Paa-UF ԛھEKv>KḭEl{D?L}[3Ia޷T5?hFKF7a4A8|ֆ3}{+/]|ߐy|2# [}piֳFCIwTRXkk WOe;MnEIk; KFNd~ɜ*@6s&9 1=uцi :jCtɆ_[[T!͔4 m4wCJ@ڵ:YupFDCstI*_ @4t`·)jBлQߝ:Lh4 4ݘtǟy7p1SKx%1. 2aPkPja]I`B?'3欄PyV6k k, Fy5oH˰U +`g'lمێOe~Mz LX۱U ?ckniuͼ.t· `$M| +!f 9&"GfڏoKP"ɨ^jiۉFF6>R$-.I߉tK'\h$YތnMv'-Ulg6X[Y3ILb'L_̼v:SX1CBs1-+uߐr@ϺC=s![uۤXDSfmjGA$&Y[Uf'Ö<{C9ܷ% i#rfBgXwuT]!.DŞm1-_vMg]=CnQX|bS,F/|%iZXq끼!k,y }M)5L&`?GPl^ *Ɂj=̄`3'Dxõ|8O+Df{gI cxQ+8)I?;qww:;] +90r<DŽOL)7CR= +Hh!+si$zR.b4EnCуPMOC澒94X\2v?sEd0<+'a %1RwuS%˝^1gt29V'O} eӑFJv]{Pbg +'I,y uz,¨TnH{~- POY Ez(nzTD p8uW^DBdTjS!~aP]'|W2mʂsc,x|7&~Y5Cw<$p`ijYIeӋS{?y.ou^CI>&[!Hf#T_p6AM^b.í2F*D" +8TΫӵPoUFq{.px`pεwg] o;\,A%`(S%.Z~kwލP]/0kq:'LP+.%Gi:Ԟ'P ]x4}hFK/t%.5}5TI:i`/3{tpϳEFqͤ7Ze+̜@EfœpB=e/KP] +eM.g͆N.9k TfeU ߥ"~|\Fd8X|6}y 5H{ +w__AGHcjIukB_hƯGuW'U9ўQ,~/hqJ1̨uFT+%_opvRId"|qrki\QN~e {4-pĚLv'u̥+ '.:AF4~1 |=-W`+Q "?b7B%vGSi#Tzfh-"`4l5١ +=;"gxT4<<0 PPfL--&`2mF8WvO8\bl +(MPKT]\@eu3TT4 j? |١I^`D XZiu@dpj.2~?=LSIIӬƔd* $F+ BC^Q}j l=*zFr\֟۬4ie填ZjH:w>qsSlm!gs a}a~[ }LްѰt}6G >l4$&ҒI&ya}HKMumՖVյ}:Go^_o>{a|r[}:]ÑY0)-1O<GkX_"Jo3/vVN}R+_JԠS>igs{05T@pZ狧Z[f+h+1r{r"pod-7R}w6DM˜KVϗ˳/~^ݎgV^M:ճ]^uidR{tnL|oTZuV2mr#(}H_7cKq?A~\;stsvb7(Gh\3]?P֮==3PT1[kVn@^틋@ +fgq[&dbl tG;_ի7S@Vk=fn,ܾ>zg60?|욥NZe![.jYK+TCg6D߿[9uJv'ыJ>-SGgmj(ӯ*T{ש>[[GWSj^FSf\^':k6U=_'V"WAG6]c(G[ yjwZqt~nrCK@w9^[وdus۴å{Z{_s.vm}D?'(ޝmO+>AכJ>HjMzV_geM>M7{y]B77,n _.mhWN5Z6Jd3u8c +1KHPviqv'&)%@_Ϗ)u޹mY^^Xi{2L)pS٤T fGQߩ@[H2mqf `q.2cWxcNazlgk|ȑkl"1ާcԼ|m0/}Գa<9T_[-ɩ:Zr6oE X|I+̤pZmxwG5%}kw1,^os}6:m knmr{O۸>C[}m՞׊SEksCyK(ܹi2|T)+-;9gڕh:RyEDm {wy՗;S%{so$f~QG@wHꐨY6iG^h%~ZWuF6{vG9U zAM-dnu7zاnu5zSO{ǩ*5z:z3wћ] 5^{v/7=$̭%G9J$_RϞ_n=zeP4.2z3Ԗ$;z$ +d ە:7`rhn'u½ˏNt)ӑx!yllD:+_{ּI/?./*:Y.. *tqQߞ.Gn3sS*c|G|vΖ+%cG3&dx`yC;8̼lT{rޠ3z(ide9u+|f^]Ad%R/kk:of^V:O̼geFVmH6T֜^>^x7TrBU<8*C7ﭏZ+cfXBMD}N:?L(tcUgBwUy-]>}V{zĭn̼Z~_ɑlĘMuky/(xqivC7{ʹI &IvhWO9h9GCEIn)B<TA%>T쓁$>zuD&]Ek{uKDFT8#Qth`jGs[TRPo!)ogWgR^2W{v;'16ߐrowo~j9[We^hkZo#N_8rQ%8|Ër߁! n+}J n]8^G/T.BmiٝÓ_oO<~<۩,=qIOq`=hgvdI]8wɢ%&"[/ξg{󳼴E~;GW>%O=9ssmާjMkO +0miw>l5[<ǿ4uOFF'R~_e|OS˼dO]xC{)=!o©O=qy8{W^Lri??v1ƖwV/~qgx~ߝP+}wljOϯRs@{θ3ޡ=okf2=iMK"Ͻ^ZE&+?w9keuӳQZ^o1cmgw*,#vZx[Y/7ZU/xz2{03:^xu4>'/Y\踊LFucJ`b_.IzJh5fxSZN)ڭNhl*];etti)N8Ynج'xn뙋#].3Ѷ_9ͺG^E0RS )K>F?< VK5rYenk %__"js{ϵy:?77Kou3yn=sS[~1ٞwzCwtz6ԌOݶVڨz==۬٨r ] :}Y $;fo>彽RaRçn]IÇ>3Wjy6OW?݈.}޻XT3}k(N]8< ޹{ӕ)m]o;_to?ޚ#hZYvn֧FS]܅ͼ:|:SWW7])~`~btWZok퉈/;iO}CIr+ Y[Kk}X??vQH>yi?'.m\G'O|W9wVM{imt"5R+{zJѶiE:N~iQ3ϲn߻F?JnɎ+jDU]nveǝSu/3-;Tt\|z\w[yh(U&tPlZ[<ݚgSKPK;՛0F#(;ژHptޘؓrWcaCū`\$P5hWiŹre;.4="n:˥$vݶgtnxS1 7R?$27FV V^#(3:g77"j֛!ٝ_Ѹܛ,R#' }Z)Pd˜JAyw2]ji;%&%/~ҹ_;$rGK +(C+A0uM}lmx.OZlNZnֺ mWZo[9$}֛S#Wώ)e$v9kJb;#6B{KI,X6q课R˞MIJ{KI,EO$vgqXp}ك_Xa[>.nzX𰫰T>WY9|ZeuמUn?{rTᅑӕU}|x3?*<^yrʋnU^NW6oL~:Dŗqߓ#;W_vυg;Ǿ_wjT-ډٳG{_WNo=¹|;9ʽΌ7Yzqڍc+cnE{t 976scGwok鵑Wɒ+??cGBk]|"vTT_N/?^_w߯-zz28?<{'[cLw__p{x;x&nmb2gh~j4OLusezҩgN-\D/]Ty*:}55Fx0|;wp+zkml&7+9?UkI[sq9Uџܝߏ7cF>J{j/ѷ<4]F~zlr2E߮OgW/gEMEXۣORx9w\AP-=zHU'# +Ƨݗՙ+Wg_m]dz#I..%E{4;~וf[=[Q㵥WK7 cq_Q:7S=FEW]W̬OSo׎_~JZ6nW&#TWrKj)h_~y:?؍W򊉸23^|{V'lxwt}6ONͯ]Ryw_Ts5/NV>f׎_oɶYdצSۘYY_i<:_5QqEor;bR?{/JmRgvWDZ}^ڟ̥N‰ï'a~yT: O_RZO}jcj+P<$w$p0 <;Y0$:K[bG05[XD.djI+Fjo9 %6PdhaQ={"qT٢=(6Ngn٬^ʷ71̹6/U:DlFӾo$9vmvS϶~nڏ߭|i݉j[7ߒV.곤ݞ꯸R黤|Uu7p{|tIk=m9g;%m~~ZNF6w-՗S}]9uO>tZkGt%}޾dmr{st<3gىc.?p^ilcm~wNyy-z.:oޏߓ⾮g'l:gN^)/=ԼIX^q9+o?Z>}v-;>vrB3 ^r)b/ԛٱ_^Kr*ӧgFNp}9v?_^zq+13|ĩϯF*EOH˅ջ[_k8&g7M$ա;&k߹ˏVGdW$]GcɷE-va6jD[V28|,oi6F+FGc RccX}Z\J">&̸O3su`OhMH/¸"S-_\=\~{?=^k Q\=ZMVQMdp&.%dsHkuumsqk?W.sa?}z꽷޾~C2PLYj48r-n2k{ֲ/56y[/{-?}w/gQ^^;Jokη ^|1Fd29/ <Óho^ďOf#kOoWsX%zZ^1o1W*Uf_;;Oҿx}<=S}?WO,O{yBjA͉(Oj~ɱy}oI:e{ޱ(۫HsXGԧfm/ןݚYgGN~_~rޞ~s+n=wnʘ0>0~:{m¸|r֌s5,ϖm\krǧf:DxMO_M5~6Ytm&ƑMZn+SO۞&K%YuE,hz6x`68yg}چ%g3ON³702 :yjY஦Id`5 8E;^4OB1Eaj)+?4\O.[(i{PvY"vuCuIAɵiƛ>϶I+E=ot(QZޣxo3z=v g:ZmNdFml|invgm67F귮2[}mD%Kn!=/i_6GxhZNӢLO?"6rƛDus+󄖿"2~\ +S{u u$ZyxzX6Gxƛ7o ͛t~dt؉rt=o>t9G{MCgx smwLϧDGaׇ'~|=n'$%ۅVha~<#Pɴg*)my m܏ťԴ絧.qccr3OvR1<LIc3Ov2T} @4Ny2d &^y2c3Ovfv?6QGjs#oi,rjwFSog&խ::8?V/lm̬k=Gnג+WAn֦sEVIGL" 8tUcTm$pDcfVmcQzk9lݒY]OiLvjUeW?jӪ?N1-YxEcuqmr6wzF2f<z!neol.}~|"íݟߓ?9ym_o߭fTD?{#OGߜz__;rko#כWwvo__ogwn?q‘ٌͅ#ўU6?~5Ln9W|5xӵ]Z77?Fϑʑ;Gy7CZBٍot,_׷o^;_<77sdr2ő#s_?l~u\|&&fH0Hv G+gfϞ~~- = @,t&$<@`τZ +:CX~=`"t8BDM!:h7|BWfЗ }Bh@`o!:&M`_ + }8PB@wHC!t];!:x" J8B(%t [} ~HOo:PB߈&t +U,Bo2B00o)3^Q^J } +@7a2B 8tBRC;n C)t8 B7еA7U:`? fn +g *o:T -1:l M/BZUBG 0HT7B+t; +R^n;` ЅM&C: R:, [!BM[D8DB ]VСC!C-tpnD2,+txpЄnRBD B#` ݆= +|?-`B"F +H.t+C?T B(mV" +  >: B73'tXn]?Z'`B7*>: m τz СO@B7>: +N68 BCn*%tHAF8BFB :H +hIСR@M8DBLa SpH: +Е@ &:@AUpBVr +`Pj A0+8PBWhRB[At-tc/@B_%t3,ł}#teY:, \k':> D%/:P #o:\ +"o:h  ]|BW;BqoBsoABt/qBv/zBw/bByR@P/Е `3þ/+: zcCk+ : @ "M0 t8BAЕ + BW .t]!bP*"C@ :pC-t8Bqx.T1P Dơ z'ta&t@Bb@aep 8Bq.d\Ɓh+tPB @8PBgJ n,PJp3.:c ]Z3Ѕ@c +]rQ4Cc ]`h*:$!t9``B. X4h'D4P &P 5DK%P 58$\P5 #I5K"I5!U5 ] t!.}:x`B= F dw ],t U!t8I$tPCR$tP\"'thP*tJ*tDb-t@vcB&n L:]7B1 L7/wR7zk ^P8 D8 +]R8 BQJb:,BБqtp#W:DlV92.phDpE:\eC!t5 H9 ;B_СsZ!: +}8BR/;Z0(5P Fw脾 z +}@R@M萺"u!uB MZ;B_ah: }y C, r;B_U: +}IСvM ;hB_O t݁b@)WJ pw@ЅawAk]vеw[] |zеwXK= +_nУ!xR} bЗЁxO+} τ\0 + t8~Z?Aq%Nf~x:;(x:;%x:;"x:;x:;x:;x:;x:;x:;x:;x:;x:;x:; x:; x:; +x:;x:;x:;x:[^~ުbR=|To:@#F:dꈯQ: ԓ@NޭbunSCCCC7gw7w7éתéתéתéWwWwWwGCCCCCCCC'sgsgsgsӨWӨWӨWӨWӨ''ӿӿӿӿ?S)qrpJuz98:|P=X> NQo'Vg73Gԛ# wwww"$"$"$"$"$"$G:*GR0{Bp)uz!: ^\J~^.W/Rߨ yWm<+6pAuz:J \P~.W= \S]z:\ +\V ~^.?WUGW˪#իeՑUHs*pYu$z:.N?S=Tz:.N?S=Tz:z Pw0%`B K: u0xW/`^&]Lz Pw0%`B M zRg70o `H :7!u6xSoClM zRg70o `H ݤ0E:S0E:S0E:S0E:S0E:S0E:S0E:S0E:St0E:k0E:S0E:S0E:S0E:S0E:S0E:S0E:S0E:S0E:S0E:S0E:S0E:S0E:S0E:S0E:St0E:k0E:S0E:S0E:S0E:S0E:S0E:S0E:S0E:S0E:S0E:S0E:S0E:S0E:S0E:S0E:S0E:S0E:S0E:S0E:S0E:S0E:S0E:S0E:S0E:S0E:S0E:S0E:S0E:S0E:S0E:S0E:S0E:S0E:S0E:S0E:S0E:S0E:S0E:S0E:S0E:S0E:S0E:S0E:S0E:S0E:S0E:S0E:S0E:S0E:S0E:S0E:S0E:S0E:S0E:S0E:S0E:S0E:S0E:S0E:S0E:S0E:S0E:S0E:S0E:S0E:S0E:S0E:S0E:S0E:S0E:S0E:S0E:S0E:S0E:S0E:S0E:S0E:S0E:S0E:S0E: +endstream endobj 67 0 obj <>stream +S0E:S0E:S0E:S0E:S0E:S0E:S0E:S0E:S0E:S0E:S0E:S0E:S0E:S0E:S0E:S0E:S0E:S0E:S0E:S0E:S0E:S0E:S0E:S0E:S0E:S0E:?ځ A.XQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQb[rq+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ @ځ A.uVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`Eub[rq:+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :@ځ A.XQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQb[rq+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ :+ @ځ A.uVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVAXQ`EuVA]; ֋0l=Q#E4V lE:[V lE:[V lE:[VA  lE:[V lE:[V lE:[V lE:[V lE:[V lE:[V lE:[V lE:[A \/p= lE:[V lE:[V lE:[V lE:[VtP=WzH Fl6Rg7:7Mlo `#u6xSozH Fl6Rg7:P_%` u0^P_%` u0^P_%` u0^P_%` u0^P_%` u0^PcTzX\ +TS=`qu*S,NթO:W?{TzXV W˪#U`Yu$x_ +,WeՑ}*:^UGիHW0:K ,Ro V/K`)uX,acB: |J=,NUg;"$YN: |V,NUg;"$T0:|ML_Sӫck5Z0:|Y=LQo3wԛ f0:|GLQo37ճ}r0:|_LW/S#x0:TLN>UӿOd0:;F"LQӨc+40:;L=$LTo s#[H0:;X=' W/ +CCՋx0:;E=* NR +Ի,0:;Q=- U ésp\0:;]=0 Po +@"0:N4 S/ CKRS{@NV : ԓ@#F:dꈯQ:@JR=|/Vý^}p:'ý!ԇQQGcԧcԧc'3g'3g'3Aq'q'ՇӼӼӼ G9ԧisgsgsC'C'C)ՇoYoG/㻹է/㻹է//g/EOu' Oԇ ԩjn5yujHWudTWud`:[Y}pG->^W0|SuOú-ԇ I.sn#QnRitj:Q}l6U;}'nk:]}lNPp:":K}BM}X\S}#X\qG})XVq_}/XVj:/`5uc`)uSk" g7EA// ӫS8^SWp2LxS}qR0:#`2uK4cic7T&&PnP 8E}Tqf0:pD`8u+@ꨍ+Է Q/Cs6.U_7bu@ԗL:^T>uF\B} H1&p:Xc etup+ HշՑ/&4V_OViLNҘC}O8L1p:Fc2#uƔk Y77///3W_a^PGg,='y~zZ{9 `gO +-=Z?28 k/j^]l8Dk ;B +X?Y'mk&#X{p*/I[{yp/!IX{I8*k/8^`g*Z{oV+[?{nVle νc0c +N'j w8Bk/DM8^pga8 +^Xj?RV^=Gh?p8ik/Tڣ~'kgO,Η8 +kY j N{O 'o?YC?:ZOiؑk=Xl{8)ks~oXHX㸬8kq?cg:γl?qvฬkَd+gr_&Q8hgpN8L{g ޛk?q`mP?bcu;Ў2^}h]|2O*vg_=%?gl7lv/y)Fk3-]pv XkpV3{Ncujkqdfql؃-O!YY:?'l}Qlؕ3U3Q8"Nپ#{nZiE\[mZfE^}mZc_~_}*NimZ`/uY^Zkp{ڿGZkx@WNkNNs:E5֞8cwT[n3mkkp쯸-Rx]e2a2ή ΪvPXkpBv[gZk'Jˬ LpvValZ+kƢw;-bkWvX@wemXtֳ}p-qh746/t81"Ibm Z[{m#ȬE4)kIm-n-R8ZXַipZk8e[gւo?JmEkZm?Y +*:k;H*/6>l1n\>Zk8=eƕX?j7צmkZh癵Qdu'UQquֆUjdfFV_bn +;Z[KZuf-ڴڴ:rk'Ej3kZX jp^]5S[k-J4ULcu*s[uY *k?O5W[[.Sk9ffꏬڲsew֦akuOjˆ5Yݕj"w [ZZK8,+3f +k˲,ڲfzkZZ֡8̪VV5Z,lVnuVZkgɱQfm]Yƚ)kJmHmY3UYJEqoG`QtrkQlVOjQZgL3˯,7W}?-[~mUi-R|Efj$ւospȭikmZk'18YՎjbul]k[L-Zk8jWLdnӱjW5Z{MC۠ZIe#X}EH`7fWjƭ5Zuf5*ˉ,EW}.𹟻Ey5kjuжZf-fdUkSf.ȮjnՈH-Jt5YUFXZVkpW#jVGkͧCZY0VYW44mS_⚩zlU[kmZ vmqVfuWV#Ě+Z +;ҝ]r[0jٖ,?Zì*"k.0V5z[=ZZUfaV#Kf_mT_Ӵq}5˭تVXkk˹ʬee#XIK}N*\ܪֲ,(8̪ ʚ,'Vkpë\NnuƖZ^Sk9g[ìfeU"lJ`U_[*ʱS-ZqjUV%Ī|Zuc'[j6Pkv5*+]Y~dV#vQQ5ZmZԚvhGzfu FV+*}VkpzëR\jVZjv]2f9Պ2jUt+@Z_*{V#Z9sVt8>ΚϬRe)j^-,[-jr5zKזHSPkNqVuk4Y,+Y=%8=X=V5rV[jmkqV`gfT,X68~VX#2kKVOkmZ";鬹YrejdƲUOW-^ckTW\&tmUbh-BX EiYz2kddeϫZ7^~rUr˫E%ZisP9Ϊf,VmeQ,lbyT򓫒[^m-ZbA0(5Y8k̪Wer&WK6dIU-`gZA؟Z*%vʠWYb%#m,[Xn^-/^`nrjԖ[^kaZ luf+Kdd5VY~R5\6*bnV[ \ZNlYq5g+#XN_ªNݢs[تV^!t7rgZK:kq\f9ìvej$WjnSZPҪ8Kl wʠSY9ni"Xe_ªN݂s[rZKz6;j:]gq̪ 6+DV#ʾjUWu N݂s[تBQj (. :kqʬFe#I,[Xn]pm.TnVRkfpPr쬳R/ʠ_YrW5u)`ntrr[~kBA46jQZm;5rufYe[YiU,X~ayq՛S]֛`^tUV-`mbPH (~u/:Yݙwʠ4ґeK%V%aUA &]&2cK dkb3HivYYzmЎYefŝA5̊+ʑe+%VXZ=U=~5݂8K5 [TlyeWDZzRT\Z{`ek'0+ #6VJ"L\U=#%K喩-7Dk<֚OAJ+:Ϊ ڭ8ˬ3Yqepr"6VJ2l[bk< e/V+喩-[~k|=?2ejC-}pov̾:6X,3r+ˏ,X)2qUIʯ8=]EVf,.\*Lm嶖kͥVup~}rϳHiVGg՟gyky%mf0+ycЭYbbRyeӪR\p,sa6Tr%j+Ŗ7ʭ5!cAhSkq? C:ڪgΪ VYqV#0TV#Bc%KUV](:+K%./BmUbk-=jVxUji]Z;3b,Ye\4FiX9T^ٴj7,pΗ%53fJ\2tmy[;veR+պ8VYZ묙Ag̺Sάax"TVeH,X*ʰio)驳2Trr+Ԗ[qZSkٱR+= +Pk}Πk88+}ͬ2+ BeQVYbbyUU+\8_ʰ"drk8 +ncB1rSv1SP_kiJ[egsAwU>Ϊff18VVeK&V.,WjESSgexzKV"`+VxVXZV4C{|ZIg9kru<ܷY90+ GYed9 KUVyϽF%K_[El-ZiPtj]fSK<ժ AscҪeڹ=wzU ,53zfaVze*,'t`*j S3_gex[Ek= kyuM-uP*냔VYwYY zfaVqape$V.,WEZ[ z%KɭJlDZˌgZgY 6x+Y%+K De (Y&ramU5=ǧ'`5luҽ%r[`+,*ZKR I JkTI{qYYwy]\Y0Kҕ#47LK+[Vs <f?zvj.\"lKV-Zὖ;jV(>>μWK؟imgͯ 0Te}MqeYbbyeڪVS_p:K,/\9RoR%bklZԺZKklZlJkҕUYaFX1t`ɼęod/5SvL.\"cklzir/냔V[GghdmPl Vf,Dd9+V+Vr#Ί͕+VȭDlU b5rV=Z2ZY3yVum5eԕXYUbb9ʩ*ۺ)8&?fK$.[Sm%{ZbK`{}ОĨ~PkyiChygu [{Ȭ4fy5 4VL,XlYԷ4.\:Dn5ָFV1Jr5냔oIg}ujkie2QYa'Y2ƒKUU7Ԋoq!Xm0S]"RpܚjK֣SlzkͥLC,[l^ZGL;+=k8+l Yri0ajAoZg[ZkS% ;˜ q Uo*k'Y2ƲKUU8-]Vj\NnM%bkl-bmzjaP냢IJxFZw֧uVy]],5eVxY +1 +˩+Oui׈0]rk+VlyZ.I?XjEVєbhuVyC 㬼58>ΊݝRì(kdJ++]WnQg.,ݵk̄j\Bn5N`KkZjOj9'1jC( bP]t8Y=a`qV70 y# aV4#o,XT]UՑKiH抽%r˭[i[K!R+?yeob'13KȞim8h}Y묙A5R[Jf,]Ya5NLdMe)FJ}GwXkd.\NnMcklVZieR+^ `jC/+ϴuϴ,@kr8+n Y{̬iVLì(kyRT) 2^Rqj+VlJcAbԲqյ>vpc팚iga4: * qV +;ie++IV,X6r_ɼrJ{.]/Z{K䖩[dK Dk /NW1S?(Zy}н}PkAim|c퐚18uCwuVxe㷳q`Yrg0 teQY+VW6!y^#lx%z+T[zb+ DkVGjiu0*Ku\.n8gYqm0^HxkP>r2kYiePWVeIi,XT]]5NdYQ^Rqk+O`+VZ!Za<jݘZ*LCxC'1OoZZ2:βϺP<ϊk +i%n jY8J+(KEl,X)ʺrJ^PpjVLwl\:DmJZz7멥CMx#_BiU,_*w|8wcyp]u}e`qVlgV~VseQ,X&R`ɺ]Պt{)·?Z1fK6W +2bmLj<*ob8ήUh>syg]$;^g k8Ye֓0+VVeJ%K̫f{p*f,"Rp܊G[!`rZ(FQIťAsTZ.Cκyog3A= +[F-ˬ2++Bd},X)D^^Za&Drҹc;Sl֍匵W1jٛV>YiHkǝuӲnYA3[|d=^f\Yi#K6VbJ̪XzN|饚KWȭ0%cK ++y֣r%nbJOZ8scagݮYrm0G0UϬ2kf +,YtbVYW^Tث^c0W_=LxJ#"bm +[Xk|Sj OAq#71NjҺݲZp/n6rhɃ ;+Tϳڠgɭ+5]O0+ +oLdM%+VWEW{pzEVW\ܪsVk-?R+>V\QZG4vq~YRϳtCn ^yfM%v- te7Y!^("kj,XT]U~VWpjLgH\" +)TkV |x#cԊO8ԊԊ71zϼҺZZJk硴Н5VY:K<ϒk 5Β[yYӞWue2%+VYW^Tk/F͕K疮[OZ+ZZָ?Z&|eJk +x5juV#\`wؽ,68YƸ5gY0˫,YBb}ʉ*#9?m/Fɕ+V-Q[2֊cJj SqjAPKy_^Zypaw.͝R<=k:k<1n YwDfYˬ2ULbuej2d6ds*sk-[NkV kzb|5ڡV1NҺKgZd!Zwg0YGx#`qyY0KTVx5TVW2KUUiW0S]"boұ[Sk %Z+b 06r$XZظ1\\;F{YMgMg0,y#8ɬig0DeQV,Xr_NS;lvJ%z[zZK B'ƧZxp<ZxXj[֑.. κYuJgMϳƏǵ +Fx5pj02"ì1XrdƒKUU7f[p* V +LW(["Dm2CZ9=Vx5 jMrG$FYZw.K낡nU)ϴShxqqgsyV\`qxcg *3K һXYMY&L_ٲjԏz+Γf-?^c+Vz%ZNj OQRQtc:>>UZǵ<8Y}0hu7Yӹ8}8g㧋+uXZϴ>6,<+ NJG0quץ&ƗYyePW,X2r`ɺr~lƿ1^a:Dq%jĖjBVk8~uִ?hZi}0> +'13 JkϴHkbg]x~,y=}=+~8 Y58p2+ ʕA]Y`1Ț+&V +,Wm8-sEf([!z[j-B6ԚjMv{YZ{ZA ji`oh-vuVNYY FHq^g[pjPe:ʠ,92% +ijM46.[\ʓ-ZyP&aMbA\Z3.>~y\tV@8>tm{;+H)W0pkp|39}7dִ3!ƕA[Y&lcʁm*g8=39fK$W[LlWXk 45|WCjA;ԊNjIp=ֽҺ*tzL(7h,;뮹g;+H)W058esEfA[Y`1Ț+V,WeWO$Kjŕ+T[zMkœZ/ ωP>6o3ﲴ*JҚյojuI*dii,aVh98uIog3`YY}A!^Rd8*+k\ԃbbqE+K$W +.[SmVX#,Z+j SZbo>oK\Z#gZG][ZgZ[8hZY,uì c52"0V8*"K$ ,UWnT?i1]Rprb+ DkcVNWԊ(F>?hoz"=1]LiكsϴzOh *.TкtP]":g0 1OO5leu1lcʁ +c0g_LtJr[?:Ŗi8֪T+ʡ֍d>JKĘ/K/-?Ӳ˃gh`~nY Fg}g]?KcfMOnA leq"kjXD^iPSdEvҽrk[d+ DkVx 5U-569ʥNb8u^)x!~ghɃw>T|OuβWݝqx#l V3+teQVY!mj_Zp}ת0[]^pc+ DkcV=j=] RiZu;#]4L8ۡ5{ wq8[Z_vXZ nqkyVv:К[thC%Yp,2q%#K6V*,WeZ-Ȧ-H2Tq2%b+ tkZc.FJ*FCV:.b/\aP/)-}C~<8w=Z93Ъ-^hhY<#%%8/O!oY͵A9Κo|cYje*DlTX2?~_F[tlyZEj bA;7,-y|M_\vV@Kv^@+XY,{Cxi0dBfaWY2}Uw<Yw9%-[NkM,TC^"li1״= ֚@˹Q_ !`9ጳ^iYpc82)0KT82-:JwpZ::.Dm2Z1Zcj ǫjP˜hV1Һ>nMaHkV{y ,VFggkr5L`|v0KU,XT_aU~lltJ%jKǖiq%7 +ST+KK>>X=>!iu,{}#𾗁Vsq~AuY{ygMUfָ3^fy%#K6VN,XnYwO4譔[Dl9^k"jMcjPfbi],oHY7i *%rqp-YWye`̊Y8kn6KeVfwYRdJIEop|E]epcl4ҩ5>a<>՚PKİ'1fJ}x^0_->g@|>к]azlYܠ3κAp#> +;q5Uָ0LcyU˪Ə8v)VV [tkiq%7 +g1S-1ԺPK(K뱩Niݎjv70ꋃ᲻@K,:^gkؠn`L'0RfYj5V,XL_]U}/lsJ%jKVZVJRkb}UZWNϴTx˃=ƉijU9^_YWgkϳ8뇦qָ5gM'0Dfa,YrbU򪣦>S`ҹ%jKĖn-15OxVZ/>yVVsypv7Ъ^¨/޵8Zg32`gAYag%+'+/_ׇpf &譔[zOZ^jZ88}qV,9ì]V"bcUՂV6W[زZakPKZSZ:pw#V*<}Lklu8@ %K./ZugY68};+8UVV,X2o?0dpڊ2Rk i˿,jVV>hKkz QZ{q*zY 6 N㬰53re,Xi} ǯ?œ撽rKVXHapjO93?\Oő F31։#Bk_-4JehCŹ[`9AY`YY9tc*jIL9ݒ+KV8*c+VA8Oơ;P|R_.~V.-{z>Ӫ~ػOÑVhm2R%;Z8?5tֳrg;{6:k:68q֔Yai0ƇYEe2eZV_pTX\ښb˶kɩVNap<^j U3~iVmu'}vuBkVt #}B_,h僃zY:{`L,5Xͬ.+VV^eV=?q[aNrJ%bhߏZ:p0M P+ 5|sZVsyP|LiyМxBsimhm97OYehxr`LwqV-aYi%VڿOx-0ToڪZbUVxeZxXl֋Si Gޟ?bgZ{Zw0nSi`Oh5*N7.aV:88v:;zY/V`qV|UfYNeIn,UX^^mR F%ꭢBl_kROƣx-;JKϴ{}'ݑa|5Vm5w}Zyq0\v_҇0҇κv:뮯O㬟㬼58etwYDdRN2IͥzKV-ZkZ!~5CZwޛ5|9 LkZ{Z=Ɖw3v&0@+v/a鲻@+T]~gqV`g20T,X6j_?\yUĖn-;RPk(-=KbiiŃt㽾t nYbYaUY"ꩪii"DnjVkRk!ASZ㗋{(Ҋ3k״x%KGZ=0$68Z1܁m@ew@+H*t<+\YqVYaeTX*uUmNSg~%s+Ֆ-ZaЦ|Z7APRZpC=rкGZ1Z#`h͜v{|%ah ^Yӵpl0K6a"db}cI%rˍ-Zi%RwBjA=Jk5|PZ/`ŵhֲ=|wKU|X]v!x}謗zLgɵA5Κg5ґ% 9p'\nm*[+TjŧZC&FZ(sZ/GA LXLʡaύ6bh6Na S겻x%ah +k÷8K<*3kfy#L,Lyey%s+VXLT+ojzU,x=Đϴ➯>Fc=T8hCZCgz3+wV^,8̬8̚*+, + +3溫-[["dk屖I-T+ `vSZ7 5|{8iůi= b3E -b8hCZĽ F\㬸5f֟ʕe"KV**"DmRZ^jŧZ-Zr}Pİ_J+y1״fy0|LGZ;ؽ9h]1 +ʟ* ZFY:uΊ_ϊk÷8kY* kAU8- ګ-6Uj8ړniikZ`cZZ0V|spe6Ohɋ{~%*:;yV謴6qָ5h3+Re,Xql_^qJUiVкCme?%ew@+vpc6XƭA'LgYܾ"a.lnڲ5kPK:'1ti zmV>3-{yP~L6ҺCm5s`vo0hKZ`5=В݇zYouV88kt2QY9tbsp« .[)eS+jMI UZoҥNiy:yP|L+Сu٢Xgwp7[% 8.A@+v?Tuh9+1Ziw} #|BkZ6-/hMY?;k:1= +kb52+ UDVYX=i'rciA8 C>8^'1Dii 9pczu}ze1RèxFZ`s.Sq5m6Z活qt cZ|YhCap#>߭Dfa,Y6y58K-Y[9tkVZz5Z$WZoNOgZryiiy|LkGZɡu'o%.^A6́V-Z򴻹Z.N!Yo:^gFyVZ,YKU,YEbj?ڿvrecK_ +1Zq>8>jۧ?x]=j-{buoiu\x?lho/aV<88}xwxC #ᠻY* [Ԛˣz}0HUiTZ zU.0Wk.`ŇvcВ0/oe.a{~NК:'Κκ3CgUY̊,Y<'ӫ[&\ZP+oMNiTZ{8-iɑ?i]t} +>}mځ7oW.a4!Y?tֻsgYSg,YOU,YebڿpV-ZrR*K>8>Ԫtm2ϴ˃F:GZ.GZ{#swϪ6:hhoKiX4ƃo Ъuxcxo`gNf"IipjfW=rl9UtCPk:>?K+|Nm~U_T0w1Һ;Һi %`C@˹QY4j~YqV-ҍ*E?`Lr%b˶V5ܡV*JK}NK< +_0U{i]ҺTf.Oi;Aq]}x~<20{Vzz,<ݬYjTiZ`Eh鮮2dl'DjZjJKybgZ{eyP'HfGZ΅teocŗQV9zxh}hM0gW|#v;k<1Qt;kzY2je#XKj ˫-[nk2OPC.-y_`X0wgH|x!. +A-綻hoh}eeO0'⧊`h5 qVeVQYEcu?u*jmZj0tC>7`x);uH+_xo8=m0b0zhZ`Rq8v>k>stream +vVz z㬔YrUTVXur[Kbj9C>jzYZ }_:,{͑W;#Z`wpohsS6GZ0ʁ '^Wp=A)u\Ljf96e--ZC-y}35p}\׼`V8Z쎴.FZ aHkGSqu@K}8v/aOhUZ`V|e;+*KϴA68df]ȬZez-Zr5Đ'1li}0{(-LK-{HQ_GVm9AH;ZmsvtQpE}UO^ AV?̝% r3˯g|qsUI-;71TZhJK>*=|}fu8zxi ]Z;x7E#ZwȡNa|> ' |=]*eg0,omp&Le@ĖlVj9냦>JK|N~M+^ ˃F>ZFZO#+hs#~JBq;#MBK<?U~ZORв-q}.Κh}#ngA8fDemV[XK>ՊC->JEi}#A<8|'Aqc<.FZǑV֓H1H˽3~f#ZoZ/7VmqP˜:Mg8 le$?bVZ:Keiƻlii=+FZW #{FgZ˟hm^r=o_ث@y8zhKSŵxpp?mvV|U*ki`kX\SjUKOciӃ`lqx#^QzuOM#x~)@kSm?iX0zhZߛZ;~8xcg} ;6h2f6:s-9rR+Ri U+pzg򠸇Z\.FZ #xQ,<2RY_8 7Z顖SZA Uf-GZ7֞Ck{{sP|D+¸j:nˁ+@@+@]T*gy㬮ʢC]UkV:>NjgZǴH'HHHqC}J;u}GZmh[76G)SSNJ@@My1r.a!7<<*2k.e(ŖZPZZ3>mi/ɑ9)OiUwo]tihU{#ZWOz%>V< ^_ ⷊ% 8'battV9jTl[rZ J+X.{b#HqU>sSZ=xZ<ђoZt +hݧ:-qڽ8h[YET`CkiVQZJ+?rwoq5èx;C+x_Hkϡ5 Dw}ZONak@G@rqP˜8̬Z7 sfSjG3-:iisa,袙3"hAZ'Aab@k:^7 qʬJeX؇*Z+j=,{[Vsa7o{3+_:kUw aU+ZoLO'oA@KluVg̚8"%SK jOgZp]~<GZsOaTw;к]i6  k0вy>V< Z?Yh]p㬾Oyӿ eRjۃ _gZiyJKiɏ{Orv,vw>5ZDk9VX[~zKy,~\4eY^fmXkp@6-CFigZGHHh|rVkwGZgZ;zuqqsZS@k{92Y_vV9ΪWiX[ekyC\ZV}yP}LK~XGZ?6G[0C iƙ<Ѳl˜ZoZohyV쬿g5YT?S[V{jTZ״ۆhqF;;xowP>Cz'Zq{oz+ 0.a]L}<Mg5Y]GbYku5y7ϴ򠹇a; oa9_xoðvӁ{WjvY;8~64+~@ϼspYEc,̷V;*OƟGZ÷~~~gY|xցGZgBkW掻/40NJ@7Qy;:kuLi}3=H+]xvx˪ޛnHLCkOqh=_;l^190]ks]T0j即 l!6[j5K+(?Hre/y5;xE|;:k{ ?Rh}D9X9a>V,e:kh}YFeQPֱ5;rJKĨ,N0Ĕtxp8kpcnwg_t +Mh{7[0ʁ{݁@_t;+ VYUڿ^VPVZ`i}>Ҳ-Ø|԰;;X=niMeirhuy%?w;1 1Ϊe}XZV3-<=91;bw0> +7{6d:k[qs fh` A⹁.Z},;ꮬ8ݭi9˃= >9Ҫ223x#-ZKiah}\hmD+w8) }}hN[ieΪ*k"N_kZ˃rW -Ns?av#GL޽Ъ=,>k[=Ѳy1OxueDkvsdžA{ +cX;s9*/;YoҪ>ӊ#)Ox»8F{wp{m#Uhoa8O&h=`F^P08<*{3kN&K2˃FiWZG9ދGZ<:/-7~e{GS@]ՏWZAy׽YUv&SVZ,ry0hGs?aOivgoHV-鉖Z'Zq׊)V8쬮'`e;lZjJϴA}C>J˻aOiAGZ[~pBkFxu'Z_7=rl´98xw],/a.oYveZPZiu`q;;j;# +&2:,FmaTnala;¨<Ѻ$}5w9X{Z t\@VikjvpH{#SGZ&F,nXB)fg= h;W|t{uZ'O*ٗnlv/U`Cg),fTU*ǃ埴i}~i#GZÓzk#gmhM?:6qĹc-S-'Z;mN֤5,xӖ$?iuva#N'w0ͯa΋}tp` cF\qVZ+Z'ZqɾOa`vMRZ#?L9--?*,>xZ 0+a\15s--e-}s[sg0 +W*Ou_v5A\;?,U`{#i>*,a,K0YØ׳ +Z6F[/n¨9W|^a |Ea}/;8(+VOZ;x?]HVdp 㠆50ڴc+gahծO0:u/+oa h]Qy0`FVHg[Xia4~;xo#[ (<Ҫ9Y<\ا~vp^hmuvp' B`~-%hU9Q,Z`OZ5GZdOaL0;m}vB+dݽJ+la_VZ?`4?hKƴ?i(~; i]U=Y\Z8N:G5qh3:`-3['ZW6=*9xocv\LTZ]con+<ҺHxoijsvHk^?:Autp`)[K~5ᗃ|88g,9Jɾx`Hd񙹓ŕ5-aZ?;8XgЪxkqpF\Ih5=*<^?h,摱J>?ivpyhgr'[0Ƙ,:֌Қ&׬7.+޹ƙ-Th}D4^V05 +?iއ/iekGZ5c5'kk[f+kwКVyݽ0:yCna;(+NhVM`'os7i]*,a[ћo}ypHkzF~uG[7=ѪwrpΚ-IJuGZw .i,aaaa6ܬqv۾,Қ$&?qeݽ~tp໓-sŹ+Z?aBk/uPOZo};XH+qWek''k}g5 ?5}hjh5(m^ܳytFwhh`vkw$*nZ;;X9r}9 3Z6w<5¸q\q'Z|9Fd~Uwqq1`96CZ^qy}g6(V +maB~ +Z'ZݾZs'?iuvpGZ5^hݐU3v,oRv;{ h?<մyte \q:VA5OZ#B+-Ώ0̭a4ֲ۟¾{Қjrp{u~hW=ո^<)<~t$[_la}=]hGZݿYgJƵݳCZCi}N.OZh7^<8:xN::¸q{Ə1hurPg0Zu?iuydqyv9#fݟwzZZ<{jcѪ[w4:x~et`O}UrPg0ϵ8=Ҫ?Ya4_3;x`vpԾCZf],К{Ń3Z-{ ɍ^\¸F\qVݸ$__L`{VZGZ kfMfKgk'>UsZV{h ޺{at--/h~5Η: yOZ|;Xyվ ݇xbxIg6ڮVo$݇6:زq.?#(GZYh_Y~e 0;8\P:;`$wzN!r80*':հ>`d[98EP`5,1zv`a}t}CZ^,ЪW\Z+VgG9:Xr-x_TL`y=U]EFG +&]sl8څКb܄VJu3*hO1:x_]huS};ⷃGZݏwuH+ gXZ^if\lw:, izHkڋcVųZ+Ck\h+ިֲ3ZWh ݓJG1rt$_4`#5~jLB+haپ{V/)Z68X\ZOp}Z+NhUwu Uw.WhPF{::◃ > 8xUivt߽H!iU/7md5Fi5C֣ZBkjh hm|x +gjݧ\@)iU0fs.?5X\>X<VMh=& Gu Q5^qZZ^W<]F v_h,'ue!CZŻwX1] +X gjVDw`t fvwGZW~pHܾ{bIwf{W%^jBiO]ZCZih{h=shfݽ⍒{޼Zٽ|h푆YhYhWh?uGNh8MHk{%h;տXbqZGdZ{BkAhm<6OB],#>KwӅ'4IB+W|dv^Y{ŗUOrF-OX`ZpH/+],>+X|Jv8 C' 7 Bk4^%\8ѡʨJozV[oih 'wZfuTZIB\h hBV~uwOX{8;FHZW/?X|zvbq?NC+w8 msqkh/ÚBRZsZ' CkAhֻ:# )`/:zbqZBC:0 =+CZ]Z5jhPF. Bk4BYh@%nȅW +Z,r3ZCZ?VbW._2X|~r8 zgZ{!^vڨ)VυJZa֊V%6ֳslZOCIhVz^q13ZjW,Zh8t }!JiUBIh.up.^?ezvChZ+.zMZۧ5W֛Ó{Ž:% к rZna XZcݳCZ;buŽк :% 4$B9ڰSh=fCBzT5V֓JAzSZ+qYh`)/{㆖/X;8Ih\,Ji]\,>;Xq: 776zTjjhB뿗Bih=vZk֦z~Z/.7 wdubJ1^q3ZhH!_6_,/Nے7 7BڴZԆCk^h=6 GWC>k5\xZkBkahm\hT +S:' +}FxUYַo֛o${uQZ$u0ޑAzc5 -Bka+:l&Yhm +NC-:B$OCcк>+952U<5bq}h]3u~ZgC|h% BkAhm][Bq0Ʌ3 :lZ'CÅк. ^qZo+gFOZ-}_^,.up1N>guXZBկm]^4^MzF.Yġ,zbZ/^:bZ%unZWBsкCh@zZwv-7/$KuqZ&u0ȇ^mE.֫[h'g,V[o# }:$ cuv!{ŕJtغ;ءCZB[ ^,·:6 C' =JRh=+ CkZZOIB+=UZ;B uB>.LBDZWBah}sZwS {j -[,վ`yvZ rh]Vrxyh]C 1 mVzZZO·j Vn~hmsZMCk$LBah' umZ_JZhMZu!zUo$yYhgZBk4^ΥڼZZZбCkzf}h|W:jZg BCк!Z_Ʌ,ƻWltEsh:UXOZ uC)>43uTZBUbCz"GsڡZ{&_Zfah/  =Z0S4ruJkh} C]sZsz UVy[Ck\hm;FhTZ]qUк[n+Va cZ{:b_05~;8V9~_ZGZк햛oUW^q٥TMh4 Cگ>vHBkۭzn?6n Ǐ /ڬZ/)z0ޛih}|ZMB к!^2:")B7C Ih}vZOC,; wCkڬShCk\h'ק$Bah5BRh}Z `fBW*BC\h]_ BahIh5 B%C+X !6}hmTZ˲zMSh{ZOB uk>*g@.Z,ӆVRZC뻓ֻB5Yh- JsZ7ӡ^hm|WZoۇuкq*+Z,^ӅV'~h=!|hzM7օzZ Czs?^]_~hm ÚBRZ3Z+LZ۴Yh9 ӳкZ\zICzZߩϝѪ Ih tZM5]C5GR2nh.8Mh]'CJhZWBkJhZ+.7 CJh},ZeuK.=nhIhMZj Z9Yh8 1Ck塵0^\7C:5 p5 ;&Z,jVVvZ_KC떛nRZUC,N;7 7Br)֪Ck^h=ZBz]Mh= 3 _$\h5+`ѩ[vXuGSh}./6| Z'NYhZoIBah?2>Wo -ZZ_b:3 ㇡uP.^7zlZOSV{PhNB/eZC,MB~h]vj!ΪVz-*X"C_jC랻$ UB$mCսz餡$)FҚz\Kh-a^h]=kB+AkrF Eem9ҟjBAh]+/Oׄ:ZKKhBQc&CkZG Cbh}Z_Yh}3 YhRhu +,BD1NkThm22 BYztCh=*^X =*u0NB$> kCkD.~_ +ġ`)~ZOC뛅bZזCRh; Bڢ!nGBQJk>V1:1fh2 ~h t5uo]h}1>:Bk=z%Bh!4` +Ԇ?NZ' CzQZf +n};PC M.OZC=YhևJuC)j +_ - VBRhPZeah>ihaz +jCkqZm3C릛omJ:Sh7eh%U _ +n Z;VBYK/֩ ;ցYhZWV^qChʅ_ʡEShUݛC_&jB 0֫ yh=%v~wynޥz0ޗuк* /CN@chYhZiieuߨBZW]ye6ֻu`!^ ;:)V uzZmhkhTZB볕zк6>z_Z'UCkahbUhgC둝Bɽzj?9FhZZ lBB볃x[hZ/ en]h\ +G.ZZ{ŅzءސкZKBB %$C3^h=yfCciYhm[Z{&_Zstк> [?OZ4 LCкZBk$m깕a$j cu >R GτTBv}AhlDhݘ 1Bklzwz/+bB뻽 fBkyhm\J `Z /wwCaхGg&NBIh}Z: +-Z + Zez}ZoB?ԡJh}0 guJ5Z_TĎz{!N+#jBbh~Ze)k K.-|\qCĥZC9. e-uuKZ_ZZ%OZ5udMhZ-z̆˖+ u0+Eih}2 k _ -C.~Z_KCAh]'кhZCkEZ+BkCkah9ZwCӅ_,ַ;9:nZB땯/zBguqBCmu& gZIh B B_KS`hx$˅*uК 6+& B Z+4N +-m`h:Ehm( Z04uc3Zk-ھZoJBk,ZZV-}3ZQzG{hm/f%>ZٗBA0};Z&%Z+$,:Sh}5Z?ZP4ih=8Nh Z_ͅCLB4~)Xf&~ֽu,֊IhBkKscQ֖Bk:[h\ -(ZK08& ۳f` +߷u-ZjchmZ -Ԭ7G͡u 8:6h UFhm:Mh[.RhXch;Mhm0Bf-֋;B ḂкjCN$?kU)ZoZӆVYB %cC^h}Zh/OLZIifhEh Ck^h=ia_LOCcaS֓zFz O BB7?Z,_B׵iB 7UhiC7ֵD1N7ZsZ(lBcCuBkC ?ׄV Zѡ+R7AhyFCB5uء-BPZ֯Z,aZ_;Z3ZOZw -h Hh$`nh5Uh/, =vZJ$ZBkRhZcęudЪ.ClSZ^hZ[t &%`&:9n": ' NZ-EZ/ZZ5}B tQZLZ'-2u_sh6К V?LB2C% lZ,BKh -&vh=nHB& -% X߳Z7%uC:Dh -X {DZBZ -<-%Xah'f:Z0ZlBk߄КwZ,BKh-К?ZZB FZBKh@Ρ7%t"hBKh -&`BKh -&`BKh -&`BKh -&`BKh -&`BKh -&`BKh -&`BKh -&`BKh\h. ? +-%ZBKh@0%ZBKh@cZZBKh@ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB -% ZB ~ βhhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDK`&Z%Z0--hDKD f%Z3-hhLDKbn:m!8 k MA4oPt )DT$HD$"RDqiPjҫNo"R4Zu>k{^;yZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &ZB bBKh - -% &XZ B%/MhsZZBKh@Lh -1%ĄZZBKh@Lh -1%ĄZZBKh@Lh -1%ĄZZBKh@Lh -1%ĄZZBKh@Lh -1%gZRZl%2ZlC%LEh -15)uVZ#%Ah -1ueкMh -XkBKh g,b CuTBKh -6ZB bBkCCAhZ0ٸZzh֛ӇֽBkB@i ZZBKh@Lh B*>ZZ +-wh=* ˖Z'ƇB ZߏK ˄֚B ]ϋ֋Bk)ulEh]- +nTh!`y3Zw +naBAh?mh]/C) кyZ + u6%B :kZZкNhlzh]' +pк[h -BKh=̡C>ޟ9ZZ?ZKKhƅΚ9~ZZ-5Zl9B믥sBKh -6ڹк O췢 [tu嬡hht:ޘ-~ ߇`W,Z Cizth4ZOZW +-a[h-7Ξ>. }3]h-b g uuК=ZaN&֝Ӆz]h >^Ӆ֝Zg,ֵScg W^}MhL!^{3cSֵкjeu3._$Zu  w#.ZN[O=C3[ih}41Z['֥cCuzdzg֯B T֯gމwߙ.ZBKhq1GcBК3*BB[Nh_h}[C+su9:wzkOh}'>Z0js|Oh}'ZO +]Uh}1 o +?;`0BAh.f k{C1¤Th}HKhВC'Th}<)^ZZrh]zv7 콇Uh蓼$} MEE(R$ɱ(rC$ +H"HE VƄվm޳k͵9{>wͨ>Fsz(Zh KoE=s ZuD 3(uDkEDn$uډ֯ Z`bCU;zLDnLDtV$Z"dQV75y4Dh@sh$ZOw!ZDkՋ$M8zDkHN5Z^N Cբ57Aa3zDhCEk ZE*#Z7[ѺNj#Z/EMF~CD͢h`Dk{hlDv5:NVhc8DkC.Z; uhoE5CD+Z  'h-[)ZՊh}qw Zwy/Ƣu~hmV)ZBhE.D)c(Zt!ZGqڵK`և_b um"ZW!ZhBNDڿD"-Z{dD,+Zh^!Z`LD%ZY:+#Z{4J]".Z+ŢIVujh=; D բމ3ujó DK5FY^Ԣ*D Wh8ʢD3:1E^gD /Z?RpH .9T~Ez\LuQ!ZZƉ6D]ohD +ZǦh-lBf4D͢0/ZKEX+Z)['n"Zڳh-3̢eGZ݋ֹ=_+-D L,z"ZUֹ݋hhyVjZHDghDkh*hݛ ZČh{h}$Zh$ZFOEkE +ZѺ%+Z_n_BĤFrVn!u3R7v3)'&h-_%Z[jщ־J 5'hvw}Ɉ#Nֿ͈W5-NڊW\!Zgh=bDKwqmNDkNChEk*Z~(E룢h}2֚YٝjDwZ*VSx+T-YYzKjDklAvΈ֚A>)G'hm^+ZEkO6OѲ#-t)Zt04֓ /y"ZL Z:'ZEk7#ZX::V.Wu]$ZFD~h D`$Z)Ѻ܊Au:'hM%ZӲ5k(Z?h K^~&׻YњDk'u"ZʳBiU֧DkOINKD놬h=7%z.+Z7xѺ؊ihY%Zt2DxhM͉AN +u+cѺ/+Zp}I#?@ӱh!(7hDQ%ZŢue$Z':8'ZShgD%hCz$Z7֪#VI>KE ZqѺ֣Zoz݊֏[Jhh؊FShE ZQlh(Zh} Zn}*ZGEV-Zw{zBo)^,Zh?C0J(ZE{wXucmETnۂh}zDUA%Zu*Z[iLAδukhͻTg#D L@z)ZE+VU%Zz(kh]jETs-Z[u*Z)`h}Eoh-W֟-hbDk?%Z:QEYzZFhZT.EB+Z:.^0+rZBD#YW-Zh]E֏bMg~w0Vhkњ\ChD|+ZW9ˈNh"OGDZ~-.%y+NEZ~>"Z?E%Z/3N6uםhDx+ZEk;hz)Z:Z6t3>^ +uk%z3 Z`НhEwhQ x\kh]fE ZGyljvk'ZjZg,D+񥞋;ZQVvʉ֩A.+B*ZF_m-0t+Z]/Kj'ujNv5]kDCEz ֒J@v5íhD"/Z3z /kz cD5-Z_gh=Dz/Z:ъJ7+*EkY%ZKN(ZfLulsh}ΈhݫD'ZfDK_,OJAp UWA{^~6"Z?ѢM{h}hDX.Z{Dk!Z^|% uP$ZguoEkO2(֟KA0hh]IE4Yv#)hD.Z!;hEk+Z&?E=hDkh]Dqg*Z+$Z?-ahvhHfD;v+hdEkh4+ZhbE+$YNDD +5-R:.yJ.UuM"Z9z@?Uzr{ѺF֥J uϖDk-"ZLDk!-ֆQm~:X֑VN93h}J#Z/(z9-bbzE+s؈x8hE~&ZubEH%Z̎o6[њ*BZQVFhDB%ZWѺы=hR)Zݭh@hՊ9WWdѺNj֍FPuahgDk/Z[xZϊ֪`2hEA֦ݽhD Z(њD*#Z7yyh=3"Z/FNzpH vUjwgehh=S lD;o[o6uJ uüh힊ZgEKyVbZh]wG#ZiȈh-UռhmDkHRu`$ZWO,XHEU.Z\,F;&EVr֫hDkH6墵FD#Z3H-Dڳ7zD+X\'Z(:䰙GX:يJ.Sum$ZD!-"Z?JІh+EDLJ.Suh1Chәh-WSzWFODUu&7YFv;|fX:hD"%ZS.=*zĉֳϓ^EKXLii~'}VJg⟑3Z^Ƚ}'.c(Rh{J>D"%ZgY:cEkm6MZNj +UEcZ=^v5íhx)*:7-{؋ DԢb10PnE-XW-}8shz'Z:\Fv5=3hE=h}֒9ZֆJ6chkE +Z(Ѻ:h=D륗{uH - z0h]bE +ZZ:ȈL6S!s$ŢAeMۋ,+Zsh]Dr%ZbqhًNE|H `h'Zn:egENzrT}Dn:%Z+Ѻ+Zh흈&V-ֲ'Zb;i5X\haDk}"Znwو־JUu϶uhCZ\ωV!.0`ZivaԟѲ|,Z^hmEkDP%Zywn6D7e7;sҸ25-hfD%Z3h4ӔhgE Zh=DE\,ND!haVU`*Zo${zȉּ ZWZ:Oi9ɊL%Z֖͋F6eKDFLˋJI^6ghgEL+Z*RhݯD^,X\whhB,Zxz'<11%Z=篻F֥VδuhDks/ZFDkM%Z+{NDk~Eh}i 5EִD>EH+ZXѺPF!-%Zbť~0`Z'vah{ŷ{W{ŗ{ZNu&5MA@Gh-گA[hU$ +hD0%ZbshUu-ƋŤgR;LD7Mgrdh]Dksh{ųfDk?#Z^1hbE'h-] +-EDkZOT%Z[݈ցJ/.;RA!G!-+Z͇AdŊ+,ѲhdhyRA-+Z+2hD@#ZBT%ZEEVS0h֦heD+Z[:ˊeNTV8H\:8KhIhEkéb1hjEkhًD%Ҫw/";nVJMvkսb-ZhjDkD6IDKW,VHV@ӪDkɬh$=XEK_,>^,>+X|-pH뵯Wwچ :H0ݿpFnD^Y^^}h3ZN֟޺#hRV,{:Սh6\eEGDk&:irxu؉VbxHKw/&KZ*,ia恖-^:XnwOhe[:@V|xSuFʢh-D˴/VWΞ֚D%Y%Z+:RtZ&ZQ~0J+Z ]vvw*ZUW7hM#&T9 i--kZNV5iX<=X|X(W<+<Ɋ*N@ˉ2{!Zb;Iv0'ZJEFZhCZh KZA _t0nwOEK<*+E$%Ѫ9%VJc"Zb'Zb,;EbqV.Z0:´@![m0*Jm{-^1Mh3ZT؊D +h-D+ZZb֕!\7hU,i´@Q,99ؼeDMR:eK3ZWg=*ua0ZVz}i--_,6-^,ޛ_,ևN.MiEϱo*n]`nI:;F@LVo֥ia3Z^^{(Z*ZKɢJ!#CZ~~wv6 L ң99eX:h!+^)mw_NWDKyV?1-/Zf%Ek #Z!CZ~LWSѢmKZ´@?Q-bFt~"owhmhMrW+EhIgFh %*!bq>%vAvV99hQFt>t0 U{sgh`IB#|XVro9m l૯z evR_+R +4]81;K^q"Zs\,FZbqNkj mJ0KZI{ L {.9WXƷ.BUt=>"WV^(VbZYzghe.i=MAI,+h:´@SYUAqE ^KvLttIgjYDkh-*V'l{<^$Vat`Zoi`ŊVmX:x* t0mw:%V{,Zb$Z/kuJT!h6W6%|viT `WXrGCL`:3Z+E^,Ҋk]J+ kNj:´@Y-+ZNW^]+A:5GbqVC{vRS;x;}܆o[ÒoGDUvv՜Ol\J00]N36۞{ŝVCZI^FZVa4.ifD Ɠ+(Z5_0ڕv3ZNJCZƴ!~hkՒ- >ՆaDІ!.i0-/rOZQraE˞+v]F0jEׅQ(<ؕ-Yg2Jzt8CZRP;xR\;(a<0ܒVVA/*<`yE+]e0.Q]trhV?+ŹCZh{6BOKZU.FZP-0䟧՞UV]-KIB{'g@:X,ZL00%/xi@_ʳ%I{iE˜+0]r> kzxTECZvjⵃsh%-چqW҆QE lFA[ +/ӊ` +COfWȹbޅq¸ta\0T]tr`hwO0zxF[JLk*Ҳkm6]FbnI";-ZV[ӂj,{4/;ЪKzU:WWf+ZJ.0JYT:h1>eknW8P𥃓O}Bhw_ʔ.KZ&wԿm'6L% #s\z/xVD[ֳ89hh犯0+ZԊlE0JSI2qFcJi}H(;bU` ׆q-zX-i&;^֘\ wY`<ЪI6]"犕h]0.00h຾tplr`؉Vw:L0WmǦmW6tI+xMuHVjA@Ϩ|OāV +#M +/rxEva\8J)wOh)Ѣ+Z\-ЅѲt}c؅~wv cK %ZdU,xA5UiUT 'qVٳAWa䓃i{vE+.-U& ]iwhŵᵃ6) #{hr-i;X;Ƣa4kL Ƌqڳ +$Kr;H{|talЅQ_:_վvpiv0ӆp8]J CvI1;(avAjZj#KOYA.Ua'yr0.wVsU].BƺvPn(,TvЈ-xb`/GZMc&/w7uEtEˮhtaY`w\*_;ʪqFՒ5-i`4*Vj ?G%ͪt%VaIVVԅ܅h_:8%.iՈV\;І!,ߜ,/i,i5d_yUVM FSƳrAq%Ta(z _E7wa)|hhvPև6e0p_:,i+,ifGZx& 1<ʴ='d/*A0@KvU?*9xSSr0-w+Z[֮he0g %htp0:\ KUvPx9ini}Jヲj] zD%go(T*zF˜049bEk0:6̒n͒VSvН +#-UPa<z=i>dMK0xVɵ[ ^-kVf{]Њ|z5"ZzB[ZwS/4'W֕hV.&]}!Za\boxFZ# ֛VV\ ZPfUy$MVv0r6+Z=9W'ŒZaI\^SZz%4M+,jeZjչ H}L&ѿY],18X;ТUVs\VjoaCrKZ\Z,i.CGZR`XL8\lQx!п&%b" ZiphVHEW$r. Zm0ꖴVKZ%-^^0tû|8xÃj5AxifLp0v+V* U ݬhJ+tY܆Q*}2)xR-i5ubi FVi5l )YVg88hcU }/w_%hVG[cIkբwܮ1;èiEWxiժZ-#2Ϳ,|Ưg U\;Ta4$ AVވV%ܒ*xo$uט:[HF8Z,-iEq!3-yTε[ +̌eY͒Yxh9ϊ0-wWab0IhHrIܽhEkPD%R{+\MÏ>5-bZvOVZ%قqzY0΢A<+W'O.$-_q¸X^ղ cTEKZ 6#jx/`E҃i Cn\ $Z#-+=g-)8X=ׇn89ZbrpS,׮hu|xE%MGZ.;0҆%[Z#eD+kZe ʮʶcCNO߆S,qUYnA6a-YnCчnwVa@KJnLrQ^BFaIktI+-x_:.[Z`Z=L+;ԒU+u^Hο4KgQϊ  -ieݫ0/w_#[^5+Zc%7d0ai> gi)j0dTٵ[[2Lٲf%,ѳ|,rX& Z9hUTa4&3]hh]2[6aw~؏-ӢEÃɚV(Đ҃ڴSkd ZSx[lYD8+߸bwRhpi07@+U ]2NVJ0,iwgZ}5Bix VwZV:ʪVZEۂtOF͢㬜g" ~8 X1v/'\ݖ;bh~F0Ȓ.-x LNi Ct+`tM+2桖Wk `ɘ>:˲Ug/h * ngv~\[LrYr+Z&ZKZ?Gӑ֣<<´C-ٵj[HO?,aUY$8(W?hn0Aܽ5aFVC{&;6aGoPGHKFZj״iVZ̵Dقp=/,Z׬dU,RAs 5󾨎ߐ+Va#Z;*RrܽՊvatԆQE +6| aHGHҺ2z Zl]ӒMKwPѵ4&gβq}g(88"Z68hZ+v0@K%U&I{+Zc'Z/i +oOuAChxGH+#-{8 ̓5UjŪE\+F݂yE1yq)D2&4& } -=ЊGlrpjr^֢Vh{1;8iS60AvJa hi]kGZnE0Xx_%YTZlѭNOxgɲ*z.vEڳ࠭v >9V,t*pDkh)OԘ KAVVŒV={x2FuQ;;ZiżCZӒM+YԢC-Ak1ْlk !DrkgY9Jh࠿Uhc* h L^+,wrEK%&;XÈ5H\-05F* j5Vֶ ]L!:se40j,Lp*ZDXq +c[O +}Փ%fdנAzJaHKU+/5-_/T+k׊eI_o_eaVYgB,RY|ݦڽ8Њ*$9F&9LqEh-/i5k`8:hu_-v}$<ִbPӊVfd+־@@x_$Y0KkgEY̳XƷقV|B6a[ŷZX1vU;* \Mr0W>>+ZU\mVZab>ҷobWsAj]m ɾ'3cYfboP*L - o#7@+B?4ЪJVδ\vP80t;9Z +#-҇ikZYZP+R->֢V^] _9˒4zVƳ-B+4a$@+RF|DkDg%aEKZmvTAӑ~T#><hMUMP+ZkŲU%\01a'c޲2EYzVYp,hG Z] GV[5h$Ek0#-[FZxPW> {LY!FdZoDUjʸ-IS.0ȼ'(:dYZ +,YoDŊ0C>8Hݯ |0:HG"9ؑh+V}vu۫:h5Ki]GZsA[ALuѴJC-Zo1VV] 4Sɲ8K׉g"\p~K֬xh0V^xVZ|o&9'ռU̝J0f: 3Gőօje*CF8Eٚ7oǦCoZ!>ؤZkQيmƸ`cCL7AmAe5+g0o{ϒ\;E0>wh]в-zxםUƌLpD`VDbv0sJ+ nu@4Ҳ#-և!GLKVdZ=bZ?1-CT2dKԭ LrOI%ZVY|c?1Y<7 +g) Z68x & 7:'eZЁvTatr%,iUd?d:MkxGZxt?Һl  +#-^=i%A6Ҫu-"[m} +T%"`Ya9x ɳXhYϲꄖmK@ƁvJU ÈHkZ0#qxhZ| ʪe]KT dN.Yֲ4ˎX`#ip6a\rq@k0ЊKU-9;,uI;iigGZ# +>#隖̘ \ѵ"ے} K3ZU1-wotH]v*aБִƑx?4<bieMUnZ~Q+jqՊ\˖h[ܻRx9'fXTeŚzW<\2 ZT?u +&cnhMZ* ~D998mE&;(Ғ0FLk 2Қ*vsH@5rWO8IHƒlqxwkZPZky +VtA=I^[ r,lYvA5SQp tMfցj<КJZk$UyDurpEkV-FZ{ϴmFƄ횖zɚY"A= +ZYJdږ,\zjGJVjYf gؠ_ϲRYp^ Z7488GMLu@ux=3Xq +``rJkYZ!&GZx7}䘖 +^nƒ[5-V=(+iA ZkEEu+邉 ;-߂k5#IhY\lj rzE,7re.hzmvWIpНrMZZ3-RlV}rpEi}H2}>C>8<:͚+`ՃAT+r-.[nՙwa&jdˠXαdy"ìX8+" ݣ o8T5agwىЪh}< *J +զ=dSZنwmZFZ;.ѫ&$}hrDzXfYvg}K႖kvO cmpwev, Vg/B{ +`E7)ƆZ'6 #wND# +^psMxPwkZ#LL/jVXbĵ"}K4N !"W&<8JVbYo +Y8g=" }AK5\}8 & rX M@ky%w0#9ؓ`i[Z ?VƒݬiBz)A6UKr-'[޶nd]bC7$}b:r,#YܲrHl <" eASh0 -qvTaMr[d:Ƒ:ƌxŻÐÃlM-i=GLPZkYt\c.`h|!F/_'eHVbYy",t\γlᠾTo j hMihnrFhnrpaޅj[Z~iъw1<i}Kމi7E+1C-AbJeKҭĸ+G0Č[.}>eXdEjVnEk0g<FYтV68TִV={D`Eu}=iGZSHkaN:yΩ]Ճ=gZlQKZ>?TkQt\cm`_hzFO`X^cɢEYNxjPogqYj,Sn +~꜓O:A +& U>]*djn+IF%{0>bqimZ0`xWkZꚖ5 1-W>HvDbעl+T L 2EyXƱdE5uI8uݠ u,uAK-hfw!8ț0­6uā?V\vO0R곃#mxhȍVs#z4R0A 1H`8EMּ?I+1!kQJeȸJx#}Z盢dIf g'm{YV(V180t4}xd7ZaźKZ}őVhiGZNaQxiB S=LԴA-ņZZε"ٲt.ѹz``h|Fȟ%e8,gYfqkle׳҅,h>8(6aLշ[rU?*z(ZᝍiّwׇÃaaw-*[mqJ^p{($yg2 +xERtֳl`YZ2pPa ZvAwG:baqp5aj ַ-YV +Md5NUVat0Қ49T>pLCǻEMڜiJ $CP+Vkيu W\E^IHV޲Ͳetb#YrrB{t'Bv&>:՚[uɻ9XP+Sբc-Z\my +ō+]Y]헼ɳU,XTeaVY.5h\۠\z>UᠻTLTgL-4abU:5Femû3Wiّ֔ 6ƒy0xW״T!%P%r ԵlQrEWλ00X4cEKVlY.3(jO q y+vׅC]Њy nmX;xV@޳n>Kvdun%4FZrLw3t5-ZaJL+ڡU-Zd]+-[pe0oDe+8,0+,eRaEgU{.vEtAkݓ=5%݅*K0GZGZiGi xWkZ×sZ-CTˍk el+-f\uU^dx`R2HVdYzk[ +em0u.0 ZʳlSŅ& ;2h%Zu#-gZnUxϞ-񚖾[ 1t`ZgӺ2bZ$>Z_2Zk)ٖ-/\TD殺00߃ޔNm_c)ɢ#|e4k!,g~VYp0\*f Zo:-{8m v>stream +9ˊ5KO|נEZ0Xlpijl FYsNg"E悖]t`ڽÁ8WaԊV'#|Żș 5-S>wsN+2iE-2rj-Ur-/[ڶnY +Ŝ+j CB=Ó=2)v,'Yr0,W6HYRNqY.vwC_xjγhFC :ڑVJM˅ݚe 1L.y҃g1-։njeTRR-[^s U+a`8(=Ñ(A +XJˊ3f,)6H<뜳Ynz.v7ϲֆOhWhhxpa3ִl!}llZ瞗Vn\+/[TpybΕzW!ލAu*XD,kJr- =K`p:hz)Eɂ-Y$86ado@ֻ[> Yz[cZ;A{N+29οBoZ4> j=bTkU-!dd-[sIUma`)=WcxNkbQRXf͚o4YlPXly$w#2lƳݺbA+ۄQ=*+;*aiw|xim)ĠՃVٴ`2ʫk9ʖ-[ַqQͫ5F+#YβxfP,]AYzVѳ-V86[oY^JOhP"yG}kŊJdYF5+`D-gAѳ̡bW쾣[ljj@EkGZc3 +Ǵgi5-_=hKS:;vbAAOU+VImݲ+(Fȗ_YҊ+/Yf=l4HTjhl0=E]oV,t'Ӟ0yVe ʦ/fifMkشcPEJ]kaZJmݲ+W] qޏ_~e +(s,%YM,dY,YŞ,W쾝Mm"{;U삃M4ЪèiN0LxwǦQ(ՃiMYC-AȲVZLmr%( ^M +̫0z;rE:IJHf0,_YYR5ǰԳHhŞCp CVqoZc"Z=i5a,26miZ2NLMtbAVȲVZl12e| 7\z5[_e K+uHea^ +e|jЌH FYn0YzچzVfA*&Mtքї HKЃ`Zz.fu85-5rvdU6\ȵsRl-+\AuIUmb``)?"yI İbQRE-kdYF喳| gؠ,_a=ԳvV M0hKhI{Nz:JÃy0NLWLkܴ j]բekVZAmi2Ņ+(W]{e)o}E/K"XڰbQǢ,nYN0+f`ڂ׳g1^,HdH]^ +IxП-| jZ;˦5ȜiC-t^t-IrLmݲeIW]} E@|VP,XT^, e;0t`Y95MTq18T'YV)شFeX+vXmq2e8WHI^Orr +rHb",}8֬Yg.h&ܭ>hH9{l)t3.*]R?;00+WְRE%Kw 2",}7+,lg%Sg" ]@X^iBfکδ⡖2殖O[Amqr啋H.IʔKWyODz/J4NXıdQVbY>3hf,Y:5zYQ]Ъ ogZ[GZbFdkZq!FiKiC\lPr-7زl+-[Vsޕ700䈯Bl 6,XαdQhY63i[2AaU]vn,7烃m0qHKx5pM-ͦn%B)Z6A0%V-[θtJ+FSz\9Kr,#Y",iVt;DYM0bwA.hUj>hՎ+K}<<\J +1*L ¶q-7bl-g\NtQ ƝH^EH+kXTcEGYIJf]kV4j 6x\A/h5MR{ D> 1$<[ʘNLKjZXm߲e+8ӮԽ MOHސY`3X^ˢìf iՁgMxViA18Xӄg^AyM+b%LKjRjkyZl)} +W ]y& +Ӑ{Ҿ/`irK,E-tf0Yv<Գh -@VzM+jL+CW̮9at0r0bl-#\ָsܫa`ȾG}AaQRHeq˲Ae +ݍf,YIlƳZp~A&hjUfִx-y4-)>B~PV-:"[f%ۖ-+\̸tQW3/w =cyɲ,nYa,LYRlҳhg5.hOh @i#lx0-Ճ%ӡ)ȨNڱs-=eKٖ-[p9WI"?ٛѿ$2,mXJcIGYܲ0Kg",16Ƴ" sUӄѪ}|<Yj;/h ֬iEՃ6UiLE-Ce]Ў"׊eۖ-[Fqy ++``" ѿ% Xڰb1"GYea[ͲMf g YϢu+xV(v[Y ZMhUxii)$Z>>ȇZCT-׋Z̵`Vl[^oe9ծT 2_R O[^҂ )VXLb˲,Ӏ,v;ˎ|lgسL*yϢE Zl!Zƒ5Ĵ +iMrâV>:Nmȵ`LlYҺ}5.\^")Bloɛ_҆:V"Yv-cY:35dAX`6(`8Ϛx +ij)YV71 B V^2uiAV Zz[Z̵bJlK-"\NtQJ+AR|EtOJ )w,"Yz-nf,sh8i4Azֺ],^0>8BڄL[3-݈:3-_>A6AZsղc-!e[FbR}5.\ye ;ң>KҾ,_â9,nYv3KfO4˧q &5̳Vg)Yؽ³\z̭iAZnLeL˜.WbDljpIdYEklRuK.k\Vs1JKB^x+WZa9R%IeQ˲Ae +"8+Rj0gE=+K҂+Dex0EMԼbi]T-;BZzEd-*\ָsyJ+ka`x߃ߑay,XԱdQV,,A\{H Jh=`ZgɂVς.Z= kZB 91-^ljTK'XDk1يmK-k\^KX/ɿ#Oy{Ҿ/_1R9,; +e#z3#ҬY|=Ҟu=,i5J޴X;]L;1P+ݪVZÎl3u-?eK-[̸tQCd#=+_âK,?ru,;2 f嬐,d5{JU5AEG#״h{lZMUb )zAe îV-: +ZdEd-[Fq9 +K400qHqy,mXTc",ŇY^0:0rVH Rwd5g}2ؽ^kZj$v19^LZ*?W:ݲkV<21Bf[Jo2+X."/ <_Pju{R^a)ŊIVeYf,s7+,R8i Tj<+^zՇYȴVtEjɢ9^6|~ЯjEZk9:Ȗ-[ڷp9rU9 Î&doF,mXTcy:KlYa%h[ҩY$6Hj0,Y+vYo0JxP.' +$> |)[ +eɲk ˖-;}1.\NxI%!|`h|ODzڕ+-Xڰb9d1ɒ,Kof,S5˥u F4"P,z?|AheD]x0Չi}ښyZx1j`NX+q-&[̶ny2e*.]|< !S#=+/ ~S,XLRˢ,Y\jpWY!6j0|OwY.}#Z݆5-fZɇ+LWb0rAWn jJ\lŶtK.\ֹuq +Lw]4>cr.+#XڰbEe$ˎRқY!3H5v`喳\ 0 +AVQYD/h=tUXJ 1DZN0OӢVC-$Zfeje-?֊\dt"[ʶni2e+v.&^~Ep +?LHjW֯`i"KveGYeaY2w4-g`:A_Ax'ZY"a *z$z0R||wbTK'VZv&[lEuK.c\VsJKt00/Bb  ^҂ *dIeŖ7lf0Y45YzVg-E<+- ECT B]lŶt.c\sq b`=[!]Y҂ )VXN([,i]rA:-.6`xg݉g"8g5*kZ ՃÙ?jb5tQU- 4e%s-;r%-[ָr9 +``b> 1<%!zuyt)VXN(Z +As4 zͲY.5hlgYO=cB]l1۲-[ڷp9r+R/Aj?L0}%OCl<3<&OzEKR,;Ƣ$ˎel,jYv9˦m`ԂgJZ,EYÃͦ2Oi C-[V$ҽ~kY-#[m9ҾEU`]ܼ"JH90ؔHޏMyj Xn+r,#Y6/hGYβff QrV( ,ۂZݓAYk0gͪ"!hD2< 1ژj-EèdZJXkw7ҮE[Nb}S.]̼R#}ϩ{Dv JWǙ1bE$ˎBdpOcY~^8hVԂgѺ8g"N},Z B oZLMKyO\|p%$I~PPJXkW7ֲE[l)r}W.']yEň40DHސYI3,7R%Ie˲5d˚` s,=cZoӢ,>tbDjmT&k"#E[DmQ +e+r.]{&«>Sڕ`XTcŒeGYl͠f̠>OkDHj0i`B <><ؕi5Ub ĈJ1t~еbhһZ[)ղ B6[NbۊuK5.\ιuqJ+A?ѿ("zuyzXJ""eGYԲ0Kgyb5t`D%q F,`tYCTt:j:޴h|Ppͪed[lQbt5.\^xEuLAБy "yE%ѫ#pX̱bɲ,nY~3f%ڐi%``{Ϫ85tulkZi`܉!]+UFXVlb-e[Lo9bż+r/ID!}gcxLAjyx)r,:eGYe,E:0`܂cCu48hVWveZB| X~0UPkضn%e*s.+]z~w`@)?W"}@dve0 +̱cɲز0,Yn98K vYm +48h!ZBpqi%=P+ݪkEkV*[ֶҾ)s.]}4 +k?KաyXֱ$ɲ,ɲfa,ׁuj0hl_5سJEC1z['LkQeZ||0jEHl4Z|E\lItK5ȹv%X#G uH=IU0,Xcɲ,bY0˟'YL`2*ə+ܳ+88N $SCHLЎ-,iQ!*#زBg JanUݪy6],{{_MJ.^+:hZIc[kZV#ZֺU&Wί 35&t]͜*jVdUY7kY{`TCqujpuvVg5 :w2aHheZKZJREZ?Reljk[ZWWGpr#a}hɴ}.yb5+VVqY/\mgm0;_4"-]V.}}OZaZzVՈUmrk[*l2 '!'`дkc-Vy Ea5kXZle^UYefYgN ַWmg5k:6Kg1[Z{*-1ZXojn:?z;&XVVƨVjep-k\et%ݕ˯t y$LjWZVXjFb+VYQY~Y{`^:5 F?wlgeg +mnSZ`Z2Zj֪j$ZG׺`LE{4*ZVXjEVSYefaWfO vVm0Mu瞽+&\#9@ظ/FZUbk[Z֢Z׺ꪺkh?8]ߗI"sjy=U&V֑Ume*+ͬ7ef=u]fVr<~ g@hmWZ*o%{|vVj*ZZꊭUmsk[*k]Iv5+zvp#a}l\Ox6끵(2VVVڛYeflfN n6}lo:v^}Diuu~0ZbZ:ZײUUW^#Lh Cb2AՔYXUaiud-:*+ͬՙʬM; ߆ߋ,ポԺoVk[+m}:תVɵ~pVGXp%}U֢Z5V;[Y{ ̪g}={ lguȡJkM1jRZk6ت:ZW\esUU/ @mƺx򯒼ZVUXeb+j+kfeue];r7|lY;Ckiu;j~|S+Z;涵rfmtY[ZV\erUFW]j=8q#`c^R\͝ZVXifVNjY ꬳ~s֘cR+Uo>Ums+eplaLCn4͎?y +Ě7VWdUWVulPguPZÃ[KqοPu|05*jZּj$*r! b5F'OJkQXib+Ynf ʬƱ˳~}[fgup<_쫴_L67VVu|lk[Io-k\esUO]a\X/ҼZVUXĚ7V6{ lfm̬̩vVি>kuUPq|0:?ؙZmvkebk^[ZV\erUUW-2AY135Gd\O?K* Ea5kXjWV{3';j/Y K+sKVr~RLj5U"lV2U6W]0Z~(@4VU:Վie57xqVrj0;6}:.쳴oy|0RFj5VG*ތj2*Zxe_3&d\O$y +Ea+iFdwr/+kudȬgng ]g-t6VVz|zc[umsk[ZW\esl X V˫e_-kQX*kՎee 67wuVn;;C뀥zV`~SR|jշ#V-jֲV*2ꪅW埈1^kRLjӴ(Vb%Վee 7|qVvV`,Gj`cSyKک:AnkU^+[umsk[ZW\esղ^֗a>:V#Ojye`- +kXec6U.t3kufY{`N f: ht?Ys;?TZ};6/ժfmfkuVY[Z*VU&WR]W!k̸ך9.?NjXj%VX]t3y=0S]Y f;)Lg !BܦVRljzlV[Zֲ*2eW#~җa>* 6eVc:~J=[˗j5S_RXԪT+MQV#!V[뭭um-s+UpUɕDWR]ڐaΩ>@z|lVXD`/Yɩ`l~yJvVVUV3UW\WSSS?t\e_XEVu`VYY?5ulPg06|p=1kwŨVaZCتj[jW]Wg$GhԼd5fn56kXȪ f^̙Lf_rhgTZ^չQK j[ZUVnY\jWg0!1G#f=VJzc5#YՙZfqjp/Ϛlgj6:vV ˵VgC2Äj'W3r)8OcasL˻F^+9(Jvc:0 vˬܩ'Yݡ5nj5J J6ֱڪj[$W:ꫭ0Gd̫rXUc7J*ufY_Ϭ:kux~ZnVar[[em-s[ep%U5W;:kLa/72ևf^2ZodVwk/jmf3۝ԠN}[7O |kecɭUo$W] 0&?+d\OJFV.UZYzt~KkV3~/Z aֱUڪ֪$W11KczֲĪod#YYUeunf522,rZ´UV[ep%̮Lz 0Sl#k3z~ډUFVGe%YKe,5ʾPkM^¸qq0ZZV-VU׺jeWw&lMsWe_kUXibUYるꪬ`c3^5ڲ~?V ukcY[j:jwWW}1NӀ903=jr&Vc#+Yie%G{ .vz^,ڴ??KƫZUjVR[*{ uq59 9eׇj_끵*4Z\DVm++ޮ͙jci K_aKVk7ժZn +ZskC0M]Cc}LfF` ++M2J+kPf^Z^շU??؝Z[Ոvmrup\`LLؘ,F` +kXZ"k6dVMY=/Y =_Q;7FVk[Z*ZUϭUW\`LIؘ+iVYXib%VVZYc3o;kcKkV`Z8UkV3ڵʭVo%UkLw I0{\l̕YZ%Vrꮬڍw2+jpv`oZmVȭW25i1W#{* +MrQYͬ2{;Kg6ZmzkuVUϭVo%UoLw l0gZlY Z%V:#Y3k,eս|V.::[[V>J\`LCϴ,ӡ_6XjFVWeulfugVY;mgn}_7oSh|l[[J*zsekX0 =bkL6;j7V6r̪166lg968WZlj^MmJc+V\Iq^ i[w3}|ZKvc_YYJ_u,CimJݭ[WR\iru`"tL_]'Zb/r}f#6gimZ[+ZVWR\irkh03csտXϨ52[YC*kY{ujʖVWj ̶V;j[[*s$jɕˮ ΍3?faUot#c+YY=g;3kvc{pMJNV[][[emr+ zrk`0UccLGj0m$VҍVVOe ,YZ}'[?l5k[ipՓ]] ZMkZ^UJzc[Y=3]f}Z)C[[jV\jWWo{I2s7nΒy3EXƪEjɬlg鬦֨:A!L[+[jV\jWWgyVbAafl̜8Z 6V;ڕ̪Y:kƕMJOjllʭ4jՎ_aMCbflLc;ZU6V.UV`=v>5oj̧V ZkbY[J+-vtekDp|Y?v`XTVf3vf+6:gSkdjNl|ler+4ɕ̎96va+Y++wfpLf:]JkԪmkZ+[ڪr4ɕ]cdsܬ͢.*\e6:2}jpv^nMVj ZVn`oٙ1w#ih{#kseϬtVJkAZꈭvms\}'k/h:XVְͬu־m ZCZ+ֵV[j&WWv/wrlAZ'ֺ:"kHemYmgUVZm|kuVܪW5sl͜$ZYj4kȩAYۦjnkتj+ɭzoՃ+\%&cL,wVXYճuYCXZSaWkb|n\ٵ[p.M1;*XjEֆY:՟ZC[;rVZ] "Cgs,V.ڍY+kSfzVKkPj Z}Օ[$׀ɲWWQsY*kf֘Y :Zتj#Ka|6U;ꅕM#k@eͬY:k njmN̶Vgkeb+Uzoe+F?Jxmd#k@e6,Y1~SZU˭j5H0vNaw7&ְꫬAK3ƶV.6Vr՟]-0Nߐѱcl̦ӑXƪ"k,;ZkClzkxyBdDg@b leɬSEiV!ڪVŵ9FhZ\󍕋=TY+ZꪭFnv/d@CJ?:*밙`o[jWw0OxF09o&XgemujPf>6ZIl՛[kgd0C[omn$FVYYS+mqULokLw@q336׎YʒY'e{Zil՛[m.@d~mͫJ#kSf=۪ک{kuV2U\ : 1v5V-TY̲a@Zݭ[ ͥ5|ꎬ:Tf鬃[jhULou}CgfFmLV5d֑2V=̭lpmh.F@ښ[?15p3kHfڲhժvnu ܠښf5e;+ܐ:[[[K{0Ơٲk0ݔXjD֦kf鬃kjZjVOp m.50I;Ί=ShnhmMwʒYm7#jflm|o~ :jkSp!gG`+Y:+khf J\kb+[[=50,`oeɬ6{VGm֖#mJ;䛝UY2+5U[CKv?Ϯj|d,uBzR:bzrkxq)0rX;܎kё[+68vζ##k?%~R:c`N=l MeɬS5]kuVon .Μ}ՓX=ʒYf7oꋭڦT}g־wUY:/zc6ޚ 6N}q`- ƌ&x%o[jkdpi/ȹ)66ֆ[Y2ȍ~ZCjk* xr6n\Y2njͱ5#mļy4>[rKupX!#ƹy(1V%N#XT:9[|ڱD?x^,"KfCֈ:hq6FMc51[}Çڒ\?Sl][[Ԗl=3=?8v->>}!0&[ OSާ1vtW;<F!zkg?HDm#]F,vy@-?4SGbR\-v|tl][ X ;O3Q[mi.[kO@g ѣ?l?VSvIt_rO}=|(]a}>@G[mϓqO=?%0!cqG\:j92zD?.VzӁv+O.&ya<TCm)xeS3=,ƈ~`ϢvNQX)~9 c89% ᢇrTD✿8|͏^߼|ov'^~u-/7ӷ|?Wwoo;Wz_,gvq?wfϮ.~;7w_}\7˧/nn<\,SG/~w_<(?{/_}qۗ_~曋..o?jſxz+av1y-ŗş<]=<op}S|쳧ۻ뇧ǫۇˇۻrvputu_v6=fg˛}{;|?nopxy={}wsYwOx(>˧[ŋϟszivxwy0{{||-$G{PNJ}X|R?_zμyX||߻Ͽy͗x|֟4U1 _}|^{<2ơ*Sww#~V<nfם̫<]=_R|vWŗ^ϿwWşu8{zqo/@*#O˛ ^|'C==^]=,7Oŷz6+>8fWw7gV༞]<>=|fG3}^/ye(*ŏx\><'P惵ޫnpu`||xxx)O"7Of?e^~?owœfܾ]^߭uppyxw;_(t7OWCa꾸\?c̋=}2뇇˻fz=X[?1t~@//nk#@"_X*>儰|hM9A?awWO7 _<=拟,t31wyx{Ep>ϧ>j{G׫6{vrN?G8*?C şl{=߰\׋}^>ul2V?'>/zo^xW??_p?ٛןūxO/ͫ_j{/^^{5#˯^1G:^~#-߹κ>૷iE'\]駫7Gh>z/_7ߔo]RO_}י⫯?Wciǟǯ^ș/W/_ۗU]k{|Wt;x'_S|8_-}e??ǫ OQ럿Ï>+~.7g>j̿KO׻_eO*?Qe-ǔLPk˾a?+şkW=s{m^aWݮ=7% HwHGyf83BWYpkaV+1!֟{Ak>*Z\^?nE]K\Ẃ^uO_m6Rm}{41lo~} Eٶ3{lඟM1?#/tw-8q8Qt(~HƇ]|oXb~OWoWlVBŅ7_~Z~ ?ա_/^}7}f-.Œ~\|y_u7W7CO>G?*wlGs#W58?}uş\_]]|nΟ>?z].·uz/n_هx#zoϽb8}O?z8LD/xf6^HxB &9 pDlaP,0N ѢVPh +ĈLK(p2&z8=? j1^%g)z蟂3^ȋ_#P?/D/1*(0Tj"EdCZ`.z FO_uAc&!z!ElpZ^8=?TEp2Mu8^ѫw/'=:i+ +-zMJ5.zJ}gKn }=^f`WRiSU6^E`-)z Ê@M'sd<+<@S*@kq.p8^(S.JY^D_8ѫ\k-z} S}$E/kpf,G5 yp׮8gW9Q/Zq^`*xe*(@)+@u).Js^!$z! +VE_!8'}`ל`%CE_3؃E&FE-l#zU v}-`$؏+*CE$>E_W,z / +@#8k,yFpXWZW9D_oD0J- 0uC# + 0]+C): 0EkB/j 0-ѫAp," 0@p\/zQEJU8vjs! pV{4D_GJ69^}8mѫ;p*z]N[$E/i8sS#pWqD_] +<Q^}8^+7p΢(z_D/k>^iċ^)^)D^銞bDEd`gEO*z1OJ P C =\ =V =#J )zL8uO+.fE/E  =5G* 0Bѫ,8ѳWmDO;^\=Al/ze^e`{s6T]EOE/&Ɖ^M#z*zا`E`' ͢WP/6^>/z zؿO p(S@P Uఢg %ఢg 9DO5ы%s8jK=qTWJ=wD/'z^#[`{&'z==}S:ĈAI^bD tE'`EHѓ0Qы"@I ^<LNr/z%z-8S 0! !J ^ETLE*p\g`@=81P3 8sы1Ps98[S98OkV3i8C V3i87ѫiY8+KiY8ы)\38ы)\s8y鉞_8mkb)8a b)8a bSY8IKieY8IKieY8=9h81ы9h81ы9hS8k8k8 kn8 n8 ncz8vѫyqt8jKyqt8jKyqt8^9t#hI8Rы9t#hI8Rы9t#hI8Rы9tcba8F+w\y8:w\y8:w\y8:w\y8.kTDO=^"zHB0SpD*z#PLE +`*D/TS=G$z8" TDO=^"zHB0SpD*zcJLHU +`Zg(D/Q=G!z8 +KD>Q^%zB0-ѳp(i}DLK% +`Zg(D/Q=G!z8 +KD>Q^%zB0-ѳp(i}xD?@ `' X0E,zq 8LQ^(zE/NS=')`ыEO@@ `' X0E,zq 8LQ^(zE/NS=')`ыEO@@ `' X0E,zq 8LQ^(zE/NS=')`ыEO@@ `' X0E,zq 8LQ^(zE/NS=')`ыEO@@ `' X0E,zq 8LQ^(zE/NS=W&H+DEA@ ` L0]s&zY9,LW^+zD/K=a%銞0tEA@e ` L0]s&zY9,LW^+zD/K=a%銞0tEA@e ` L0]s&zY9,LW^+zD/K=a%銞0tEA@e ` L0]s&zY9,LW^+zD/K=a%銞0tEA@e ` L0]s&zY9,LW^+zD/K=a%銞0tEA@e ` L0]s&zY9,LW^+zD/K=a%銞0tEA@e ` L0]s&zY9,LW^+zD/K=a%銞0tEA@e ` gǎiw=kU2~d-;[Uw So WA@L%_uzK2~d-;[Uw So WA@L%_uzK2~d-;[Uw So WA@L%_uzK2~d-;[Uw So WA@L%_uzK2~d-;[Uw So WA@L%_uzK2~d-;[Uw So WA@L%_uzK2~d-;[Uw So WA@L%_uzK2~d-;[Uw So WA@L%_uzK2~d-;[Uw So WA@L%_uzK2~d-;[Uw So WA@L%_uzK2~d-;[Uw So WA@L%_uzK2~d-;[Uw So WA@L%_uzK2~d-;[Uw So WA@L%_uzK2~d-;[Uw So WA@L%_uzK2~d-;[Uw So WA@L%_uzK2~d-;[Uw So WA@L%_uzK2~d-;[Uw So WA@L%_uzK2~d-;[Uw So WA@L%_uzK2~d-;[Uw So WA@L%_uzK2~d-;[Uw So WA@L%_uzK2~d-;[Uw So WA@L%_uzK2~d-;[Uw So WA@L%_uzK2~d-;[Uw So WA@L%_uzK2~d-;[Uw So WA@L%_uzK2~d-;[Uw So WA@L%_uzK2~d-;[Uw So WA@L%_uzK2~d-;[Uw So WA@L%_uzK2~d-;[Uw So WA@L%_uzK2~d-;[Uw So WA@L%_uzK2~d-;[Uw So WA@L%_uzK2~d-;[Uw So WA@L%_uzK2~d-;[Uw So WA@L%_uzK2~d-;[Uw So WA@L%_uzK2~d-;[Uw So WA@L%_uzK2~d-;[Uw So WA@L%_uzK2~d-;[Uw So WA@L%_uzK2~d-;[Uw So WA@L%_uzK2~d-;[Uw So WA@L%_uzK2~d-;[Uw So WA@L%_uzK2~d-;[Uw So WA@L%_uzK2~d-;[Uw So WA@L%_uzK2~d-;[Uw So WA@L%_uzK2~d-;[Uw So WA@L%_uzK2~d-;[Uw So WA@L%_uzK2~d-;[Uw So WA@L%_uzK2~d-;[Uw So WA@L%_uzK2~d-;[Uw So WA@L%_uzK2~d-;[Uw So WA@L%_uzK2~d-;[Uw So WA@L%_uzK2~d-;[Uw So WA@L%_uzK2~d-;[Uw So WA@L%_uzK2~d-;[Uw So WA@L%_uzK2~d-;[Uw So WA@L%_uzK2~d-;[Uw So WA@L%_uzK2~d-;[Uw So WA@L%_uzK2~d-;[Uw So WA@L%_uzK2~d-;[Uw So WA@L%_uzK2~d-;[Uw So WA@L%_uzK2~d-;[Uw So WA@L%_uzK2~d-;[Uw So WA@L%_uzK2~d-;[Uw So WA@L%_uzK2~d-;[Uw So WA@L%_uzK2~d-;[Uw So WA@L%_uzK2~d-;[Uw So WA@L%_uzK2~d-;[Uw So WA@L%_uzK2~d-;[Uw So WA@L%_uzK2~d-;[Uw So WA@L%_uzK2~d-;[Uw So WA@L%_uzK2~d-;[Uw So WA@L%_uzK2~d-;[Uw So WA@L%_uzK2~d-;[Uw So WA@L%_uzK2~d-;[Uw So WA@L%_uzK2~d-;[Uw So WA@L%_uzK2~d-;[Uw So WA@L%_uzK2~d-;[Uw So WA@L%_uzK2~d-;[Uw So WA@L%_uzK2~d-;[Uw So WA@L%_uzK2~d-;[Uw So WA@L%_uzK2~d-;[Uw So WA@`nJDzN٤ɮ:8>5zvdYUwg `WA@%]uzvdYUwg `WA@%]uzvdYUwg `WA@%]uzvdYUwg `WA@%]uzvdYUwg `WA@%]uzvdYUwg `WA@%]uzvdYUwg `WA@%]uzvdYUwg `WA@%]uzvdYUwg `WA@%]uzvdYUwg `WA@%]uzvdYUwg `WA@%]uzvdYUwg `WA@%]uzvdYUwg `WA@%]uzvdYUwg `WA@%]uzvdYUwg `WA@%]uzvdYUwg `WA@%]uzvdYUwg `WA@%]uzvdYUwg `WA@%]uzvdYUwg `WA@%]uzvdYUwg `WA@%]uzvdYUwg `WA@%]uzvdYUwg `WA@%]uzvdYUwg `WA@%]uzvdYUwg `WA@%]uzvdYUwg `WA@%]uzvdYUwg `WA@%]uzvdYUwg `WA@%]uzvdYUwg `WA@%]uzvdYUwg `WA@%]uzvdYUwg `WA@%]uzvdYUwg `WA@%]uzvdYUwg `WA@%]uzvdYUwg `WA@%]uzvdYUwg `WA@%]uzvdYUwg `WA@%]uzvdYUwg `WA@%]uzvdYUwg `WA@%]uzvdYUwg `WA@%]uzvdYUwg `WA@%]uzvdYUwg `WA@%]uzvdYUwg `WA@%]uzvdYUwg `WA@%]uzvdYUwg `WA@%]uzvdYUwg `WA@%]uzvdYUwg `WA@%]uzvdYUwg `WA@%]uzvdYUwg `WA@%]uzvdYUwg `WA@%]uzvdYUwg `WA@%]uzvdYUwg `WA@%]uzvdYUwg `WA@%]uzvdYUwg `WA@%]uzvdYUwg `WA@%]uzvdYUwg `WA@%]uzvdYUwg `WA@%]uzvdYUwg `WA@%]uzvdYUwg `WA@%]uzvdYUwg `WA@%]uzvdYUwg `WA@%]uzvdYUwg `WA@%]uzvdYUwg `WA@%]uzvdYUwg `WA@%]uzvdYUwg `WA@%]uzvdYUwg `WA@%]uzvdYUwg `WA@%]uzvdYUwg `WA@%]uzvdYUwg `WA@%]uzvdYUwg `WA@%]uzvdYUwg `WA@%]uzvdYUwg `WA@%]uzvdYUwg `WA@%]uzvdYUwg `WA@%]uzvdYUwg `WA@%]uzvdYUwg `WA@%]uzvdYUwg `WA@%]uzvdYUwg `WA@%]uzvdYUwg `WA@%]uzvdYUwg `WA@%]uzvdYUwg `WA@%]uzvdYUwg `WA@%]uzvdYUwg `WA@%]uzvdYUwg `WA@%]uzvdYUwg `WA@%]uzvdYUwg `WA@%]uzvdYUwg `WA@%]uzvdYUwg `WA@%]uzvdYUwg `WA@%]uzvdYUwg `WA@%]uzvdYUwg `WA@%]uzvdYUwg `WA@%]uzvdYUwg `WA@%]uzvdYUwg `WA@%]uzvdYUwg `WA@%]uzvdYUwg `WA@%]uzvdYUwg `WA@%]uzvdYUwg `WA@%]uzvdYUwg `WA@%]uzvdYUwg `WA@%]uzvdYUwg `WA@%]uzvdYUwg `WA@%]uzvdYUwg `WA@%]uzvdYUwg `WA@%]uzvdYUwg `WA@%]uzvdYUwg `WA@%]uzvdYUwg `WA@%]uzvdYUwg `WA@%]uzvdYUwg `WA@%]uzvdYUwg `WA@%]uzvdYUwg `WA@%]uzvdYUwg `WA@%]uzvdYUwg `WA@%]uzvdYUwg `WA@%]uzvdYUwg `WA@%]uzvdYUwg `WA@%]uzvdYUwg `WA@%]uzvdYUwg `WA@%]uzvdYUwg `WA@%]uzvdYUwg `WA@%]uzvdYUwg `WA@%]uzvdYUwg `WA@%]uzvdYUwg `WA@%]uzvdYUwg `WA@%]uzvdYUwg `WA@%]uzvdYUwg `WA@%]uzvdYUwg `WA@%]uzvdYUwg `WA@%]uzvdYUwg `WA@%]uzvdYUwg `WA@%]uzvdYUwg `WA@%]uzvdYUwg `WA/w w +oe!_ PF:Uuvߘ?-O~9]u/%+ꆺO;~߆J2>V۫ /[;-yWήpv|Z''5 >>3sgUwQeI}L;V_`WA^}WQW GOT[`WAR}l9X}wG;O+ >>b P:n>p,r]vugK!-uJpEr# ;˩$ULu8p!B; #7PRu,p?WA`WA3-E^})էUwq{O4"P:>0p;WpPRwޡ>ex1>Li\vĹŴCԟt~8K}]uqd7Vk3;g +>Pp3>Q">M8R}+7P1s;c^P.p]W~o_T:p-~[R@p TO|E}j]uE/d0~xY}d]u) ޭ¹7ԇUw/ ~-OOc;UxU՟Yԯ >WԯB~toc_T]cvG.~[)\NRP˩_J U>]}"W^P6ה;7Pk wR>>p +T$w;)_QV;h]~?~vO~XW iwzQ]u;n~D@x8^mJ tivtu2 +Ы몟 K/!QOo 몟 p Uw_Z;g;\H}!u7fS_K|E~~Wb7P_TR? +`WAR? + + +N;*F}]7WOUw%c??^[.~W{R??pcO7x&?<RW_cQgWvx! `]O;QW >pWBuXV?g8[`569_>>~ΕlrQp _>W2o=ρ;`}V:au|4f{7v`UWon6T6}Y.Pzlx`=}h]ၭ /<>o|%d|\m`y`'X6mfsŪvPo/5U`Zo{`y7=j|m,XIp|`a=>pk~cVU' 7?z3pܗXl~lSo#Ncw7`C.`=|?p/aA ^܈X=vQF +sP`.lH}NLMSתw cuz +\.3T|^xNR3Uu +%SUS8Vp\GԛSu +VU8S{|u +WWz7\Na0B}0N_M0ZШYWJuF ;=@Nja/E.0:կ`Fuv +7Tl9.~P5I +w p?u V`][ԯ`u wRWuԉ/CRVS0Na^XYÌw : /`u "^Tz+Q C~bh/`wuN o/uZ ԯ ouf # U0cJM"Wsu ge8GxO+ç7u կ fxOb8G7ë_ 竳gM>J@cZu ?o4կqLd/FOPSjvTzzuV^,Ě]7Թ583kVVnUgج̮NYM}:f]NTԷmUpsWꜛ,+nμ:fv `Mu I)83o%뫳pRGvQ'̢w8:#Q;vW'V8RS5V R_4VP2ιV}:A*9:.XDF}P:`5ujv`j`R`R*`:6`.i.N`"Q.N`9^f` +!^fWb`Gu?Pg[L=xW4 PvWwz^ E=lK U.  |{A1`zOu{pzOu{pzupzcupzcupzo&PM%Oeq}q}™Y[ԃ^U + .NPxO-![8A=BmuzxuzxuzxAupP=6ฺg8p\3T H]5mx[=0Suz` sԝQ;7ԣQwn^R 8S<pyxI=$duD=|uD=|uD=|uz6UW[\n! px px px px px pK= `K= `K= `K= `0NKQ%ScƩ{?1CՄnS NN'`;u;zS ؑnL= SO'x `00zL= SO'` `00zL= SO'` `<0zL7 SO'` `00zL= SO'` `00zL= SO'` `00zL= SO'` `00zL= SO' +?` `00nB=zN= SO'` SO#&90zL= K L=Tu ؖzL=  I=v PN'`;u;zS_Cėz8u/G=`0NKQ%ՓKo$F/0F/0Fz:z:z.z$.z$.z*"z*UW[\n!~S8_?1:鿫3{ONo>@:_A}p'u$D)a=ԉjYSASy).sYԙ^^o>pi3R>yh @>RNVK}`:F${W3x~S8_\}Gdus3չ;o +NyO}_Suꔝ;wu>U xOsL3շ tW)x9_}7uU :תTgP2VS5RV8vW'KꤜF}WSo;qz`/u.,.DY83o%+SpUMT̮N:{ +:̛;o++n[ssWꄛ{/Sg۬Ij.puj $5y6+o73kWqR좾̢NK}Y5;o=:f_Q~V'~Sg~ PS&VCc*u 竳gx~%NU[u _ f8~7Wgp\z8NS=u _e8SxΒ|7u W1\~aT'0BVg0NR0ZvWШ_JQ C~{SaEvQ0ENaFXYü :o`5u PTuԉ/I^VPgp?:养.].[Nva;:Ӆuԯ4VSi9.~\XYfTg̥Nma[E^ЫZQJuF _?@Ngawe/&Ndo>bp:wUM!W's8S9xO3>U8NXpD{T8GK^U\ +o J]SZMMNLq}JNIF{}(P7:zRg,mNC; X_37:U'`Mu ̮RjzWNNN:pou UMOk+7p'u g=Y&zSL`MnU ̨N.{KY0:R<WWFM 0ZJ|w!0NG|7"0BDTEZu X#o 7%p:qxU/sY#{ |N'pP.|^X*P*:J8YV'r.TX:8\hԑ! B &իVzh VaN +L^:H` u0z1`Rze% c?W5,n^:zm{:Ppx@۲ӟ=/I`J =O8LW?0zXD41`)g<O; U?0zX\p` c:O> S?':M?dq`k@={9ܤ> pz8 UD=D}(dKs6P 8A=tG 8A}L i/4NVxD}^ 5C=p?TM>>l'Mz`9`#@ ԧ ˪/V)T^L>V,F}XD=t0p0z`J`b#Y է ԃӨ,R5&PX,>n XV}T=\0z` ` XF +ԧX=PШw)vW_BV/R𥾇ܧޢ[}CBomZޜZpzmW7s;|^~p\-qzUOշ{^L]zC\0V{`XGL z`no8]V_rԋ3XG}P8o`MW;0z`,Zo>(R_~^PW*=R'K w7:\^_pzwR'Ջ \To-pzeSgO +pD :GQo*4zMQg +W; +p:Yu F`_*Pzu"K(\7 W VV~qI T7~y VSw}9ԩ Q| VP{ V7{Y9fUwziSyԙfRxuP7xFWww5)UvYFTuՉR7u]ԹFQwtzu;QTr}Iu#]nuK +>u [ u:! cuNԝiWm3#Npa:?n uV qu#> D 者4s%N\ݞ8_1/uo*u ];ԩ- FCW݉(im^IK݃ELE݀KOX_}QRXYzWUXSw]XXMtC[XGqI^XAnOa[kUdUh[gOeXAjIbXGmC_XMp]\XSsWYXYvQVX_yKSE|EPK)RJWh}ՉMԹ;~32ת{'uԹ`&uu`u{`tuo5I`\ucy`DuWթ`,uK]`u? W73QJu'}mQ1] V0K S70[Pw/෺%\n]cuWJݷԍ|u{nC|Uu8nTqu8RVE稻.OԵ D]5W] Յ*kuInRzܪ M"lD@#2RlAjl.@@l>p,.=,;,.:,84,.7dL5*L.4BL2ZL.1"rL/RL.. , .+ ) .(F &vRl.C@#J"쥮 I]>~Kpvu/u.nu`wu"QQUgaJu+`Gu +WwSR_FQ7TvQ'_RTWg^FTUVV]UwVT\FW7WVS'\PWQg[fRXVPZSwYVYfU7ZfU'YVZSgXVP[fRWQw\PVVS7]FW'VT]UgUVV^FTTWw_RSvQ7`FQ'SR`zu&`GuTQUwbu`wu3nu/u?>uouKu ՍIRfWgLxnNCp:W{& D G}, խ# 5#nNpg\|u/uZԝת7 PoSpԩVwqyu#WTrzu;K`uGE`,uSX_`Du_XY`\ukXS`tuwXM`uXG`&uXA`>u[`VuU`nuO`uI`uC`5u]`MuW`euQ`}uK`0:^%W'2Q,WF`w6p:_>u;VתX\Y_|u3 +xU"NU{-Su$W +G +T.NO9UunT/ Չ 8_7JU:%ת|ܡ^ OC|3pzvW!QoeQ^O{0zvQ`,V;XYtqջ: `5uPo:\̤^2ԉOgs 0zfU`ņ/ +I\u;0:`tuZTo^> X_c zFQ`/<^DRD}ջШ3zV/FܧC8~Zux^M)/v +p:YQsԙ=|NGԛ +p\#:A|WN g:/^\I*_{E +՗FK*R=FQ/U좾xޫX_}QZ0z`5e`:L5  )ճ-S.VP\̤Z,@}XP=z0Fz`Du` (^= ^}T=O[1V_Rdܧ9C=pcrU O' 8G}O=KG>UolpzlV% UP=[}&?A[Ճ;zQ`#:/= T0zXM41`[S=Y7̭^SzCZ`\ '@3lFQz(o0lV?Xp~'Ckկ,| +QY>RO_M4\RG\=C|_DV$ ~L=O;_>`Z l~%m&P: L=js0`n ̤~ԓ'0Uϟ E6U@~{[)pxNԯ s +~KUT_ +X6ܡb/KШYT ka 0z՟54AW'^* |\P1t !tRB !wHB'!T1 E4i@Bh0;(uޙg==~{~߳~I>gMZN``#,"tj0ߖoXzl 졥LXz %Vmhk=(06l4K >K϶}wp,=&ZJ@_cK{@b9om:f[_o;]`IK`k,=>K/A9=I ӽR䁰~.] sba7' Kr3a<ZrR[n傘*n {c0 i907$Cs0LBlU b$fuX`0?-anX;iOb腩Zhu-R@ P8wXՒa!qo 0М K"P ^ԟ;pfP:¡. bP-"fP;P74f,Z0 ¶ZpuX0V `Bc&1!0@6֠Cb(za 5eլJ"Fap@5f 0 Z\v0m@6vaɐC c0 KשּKpȻalXIfjH$x1 C2rJCBa"a^6,o%`3 %Cz 3۪=#j0Pc0 *F! j0 ~~ǩZ= CcP9`gd*Ő@.tB/6*IQˇ,jP醁qgL7T2$Cjp&42_qc|!)nH m@53K C%\*Ap JXT!Mp)Ōa6C1Ő \ +A jC%ȡ +fe2LC1`н`&46Ǎ5,*PIb d`E!j0 Y- e/7ܰ(ȡ M@5ڬ8f(ab0^HrL9E[`NWPC>r2ffhMb I.W6mQC%ґX70`h~2!K!CY aĐBPꖛʉv! nuJQɆڰ# +@0s0 aPC1dj!k>1RY=v!8$ݐڲaa\" bH!] e'?WKoOʈT:r(!dܐR>lX[klY0V >^еPd\cLEy;afgH0fN&!+<^PXT;吅C ِQ6,.`_~PK7dp :NHl DZrpP7n 1+4CdB%C:dH!.XBE:# E9ppqCeodpCZ1jҟkCACpuC7eh]g&!bp{!$j+UI>퐕 "7daÜfXfH2:M^Z@P!*8q¸!YnȳzFA5Վ&FdȊ!  i-R~ukJG~HACY7plXb{mF3 d $l0^Hk!)z\Ei;d`j>!Yn0s@5@wZ& dH bȃAB +e"_22#t>$ҡnR fаab{i =fp']4Ԑ!/p$ |.V*!ݽnῷBnP4 "6=XgYh"3\Z* CJ1Ȅ!\tPh uERt#nH *.eذjAL$ AI\;C LP7d7.CBo!*t7^d7$ِQd54Ch3 '2d$t/\C7-l+TZL񐦃*dPt&!6.6P Їf3G \K  qj!B'|#Lՠ:1EȆ+lPs TefdpS+dpw%B18^ *B~bCy "ԃfyNPC  B*$tU? >\;áClj W0>l:@ D9f:&AU !H?z|* |lG@4A2.Uk{4Q3ej2!CV :\/H.ZpJABԽHI僋iIW*t7nP͆CjC>lPGi5\j54q8Qk{m"]g e=칄2zh(1``sւo YG SsOp4'BAz SS*dA)E5ʰA/6KTta͐3cP&C2vXZ 1B/H.XB!3}o? >\=H;H:rPtaqC z!6j͠W :~!3dN \" N1ȈAC 6|*L(rnO."&>d`A l7y7S + ױp67ņljo|xө գ8fp'] \"bzArƂO YxpAC q`N)t66 Q VOUh`&ALwd0C[l>Sb 2]`cj!Hc"2u0An{[i)̸ܓ:9s7åfGŘLȍ \B B1Ȉ!  \+P}~OȜ<.bD| `g*dA)Es"QT bCeR \f~rF3GjN&SNv1&d0C6d! B']öLקE +BՃL\9p^)̸l7l0+Jd8PÆb]հ!_jD3Ʉ,3wd8 )1Ȅ.H.V#QHϡc"D2u3 8u E6wjQaCb^5 -C.>`É9͐Mȥ 3ؓ Yf7&\2Udc `c쑄 .l,T2ߝEH>\:98 f/Sv]np 0jQȰC#]T u9Pc{2!O9epn`%̩-{.H.VcNxB.ϐDHX.d`!8n0{v i6TQa9 +endstream endobj 70 0 obj <>stream +,6P Йu6Cy4!&LȻ *\"KSP  6|*J*'l/#6.ñǦ`"Rl63 +7l7_lXW5,?BC._i9 H4 $ḏY|4`G  d [!dBOTOnkO"$D2u|7H KI6eC65 +ه4Ga!^Tzk pN6U3dGapc7fḏDZ  >b$?'Ujk"1"|>xp>;.t6 pÆ'Æ"TW(`KlKM4ii&d2f8ԾX$2c 90`G  < B&M[&Ӫ CH[1A{<Ca݇# +0Z PBC +457 1Ñ.$=!C'/0.H-X#>-xz36N%|@z$N<1s"R$ Gֆ nޢ/6Ke5BÊ`"eH`%T1`x_ |(BLxv$AScpJ]LrD! WYТiP4 5@uwkB͐d̐P𰇙# ?_0jB<9e&BAzPᱏG!tOqxJR ~oQuz5\5A0gaf3[1C nKbx#U0^\ZpKA)>%ܭiX !8nn%noQu{ }jlz2ȋ fpN2b# n`rƂK < 6ƃJ$ rBճa:享aS& BClYip2@Ndp X >N:l/ZCA9~aE[! ƃ/ B8nvʆaC\W/ՠ.^F f/4pz3\s1Np|& T-V {F4DH[T9p {'톘 MÆwj\^ 0nD[3\ ɘALdp X 'Ԃm oR/ٟEl>B9p { !E2lUõfW pф3e nAqN>I`P`kB脤 ^r«07??P.|;N9$q q!dC\m}DUõ۪ax +> A]PG~O&2N8d0{ 4s$ v`{ׂm +Oshş5F6|9 f!7l EqZ0lB8*oB7}I3 ;fp'a!I0dg U B&]ZuxZZiQ!)i7qC(QņΓw +W0ːF %Nąf hBo3ؓ ̐%N2b#SN1{Ղ +!SKmZG>T9p0 &7l Bo6#%azQlÉdh+M5[gGqLe2N{ ̈A&  \.Xp2!oߝFEH\:H9pPT"j= -6̨eH(` ÉBCc3uu4 r2jN%|1$ l+NHuo`'Hj"nꐄC9e[m30lPGujYkSDА=俅ށ,@sN2f PO{*_n T-T3ox_El|9Cof]m30lG`! oC/e< 50jDzqb +?&˜.3dȆ ̈CW |)Fp?oU6ߣ'BB|xvP |7$㆐ v!6}Ȱ`!ǫ!Bx@6_nTAdф4LD R ;ɠ!.H-V >;働2vrᠺL .6k,6wp(PZp"81 aҬ3أ iɄ;HrUBm/H-X +!xǖH,*BB|`t8nx$!?]|'/Q Wxp\ :5ޚpF1? E2=P } ?_0 `cBl{V)wӚAAip E6F ]i{?9Q 2 # rqb+H{k¾ dBU2Mb#0.H-V :nTCƈ ƃI:H9H8z8nxnP +"]lpj؉W +Z.N$ N3h(] h^8ć;dBnLdC937bV \*LȢݙlo΢"$ުܼSȸgܤ0g6w- +.Qi5QZV> ծ fo Gɘ/3 *_ n$vL/H.X#W{ߖI'B@zvt𖷘p8 8nx<jC2l# +/QՐ?!(`[p"YL/[V@u9&L R o|0.H.VE񁅍m!I \:AAot7ԲQaF!G~CVx!9aƠl,RЁ?XІE]p`9섃LAS f^yWZ(dA!PB*`F'F ÛNڄ@:;cw2!7&b2G3d` `kB脬 +>V)BAz `$L7l[luHD!T^H(DÃ7' А\@ +fA&m0f0'撥O0dc [ vĠ䂍 +*~$zZ! \=H;H:r`17l006>QYKP9hۅ\@>h'҅pٲ wpo hB.M1̓ vÙg#  2]`c!Bᨏ.d! lqf1!\=vtAS +EZ $`Ca]\k `['* `MH&ԘE/~ܘ(!$l/H.Zp;?FETĂ `8n02&K^"5lPGfCj +F & ih'vf-lyrф3/K>l1H2ȩ)O$\0^S!iKlߚ'E,WB9H8QgS^0mDa=yQf2^k9hv%1:hoAfe8ሁf0+vMȥ 3e$AN%l1|!L/\p:Ȃϖ>*l \*lQ1 bTBQ5 P _$`4oA^jp"̗ܶ 岥j{fp&:90 ΄9*채Jb C |*$XTKPA!)8n0~D3 +67EXlp(b5#xP$5{%(`2h> p k &dҬ3 fxe$D,Ob?]R!mI,`T*!L9 +On:j ?x3:\ȫ.2_k?h5 Q dp"Yh%xqB-o:fk&d`N&d!M9`F >T.XPP L=0TBxPAܸAe63 +6GYT iPk 7(5i4Lm  eKv rm­3W f'i2Ȑ1b k!B_)|u u^b;rP B6[l̗K^kHG  mKB[hpKw[;Vg +~Mm2&$1b{悏$/F;+^Nd? ",6j8IUq2/J/e2dPPG ÏIS 9uK9Nף -lS iфf0cs2$2|TC b(TO]jVĀpO}J"Ae9pFa(dA!KW 'Rvx!'-k ۅkLhh4[궥]h'4s3$ +քl@1Ld0 2dG &T.ZP0_*CBOnA f!fQaC# +T}|js zR 9c@4v8^hKc@Z3 +=91= XⳟuŐW >ӊ7X-J"k_:B7c +JaQa.ȍT0^PdB1:|:r ]l7' Y5P<=!Zyܻ(.d“{K'`4\2hPoAwB[hpKOoa;fd\2|ka`A$B0\B! H U>T8QN7q9p٠ Gj0oCʗ.ːZyA(]4t:QܷL:Q-p¾^-Uj) hBd%C2념 I)$֫fDRv $ ¯Cj07/U (]Q^|6ĊՉ亥4p¾8!'Ny_by;Z5;]3:9pc f̠l1ȄABnol!fyܰQbD(>_Ao/EAG e>jh]$`imu҇']Kyөh`&,b1Ȉ!B_lC8n(! ̫ܽ$߼TW(`(NP]Hwr|lӉ{R 7'Yx8L3eM]K IKi6 C24M/C_ `!B +ow`Ix`!dp.͆)w/×+O;xKl5k p 4O|R&1?d!C( 1TH{*BOdO$A(d]Ȫ|)[Pl_ <k5g!a|heMN4j =tmp8\oTB3o{4O&`&2bH!B +B/B .!:G V}A^.^x?$v]5p>f~I>oY4a ?tbm4é!oG`W 9u2$!B +?lP! _Eɰ-6|˫᭦Nj5'.2jP,ޒn9XO_A n 2<'|3 ]˲MKw4! cY̓ + oP鐆<JkO_C`,Cf'K{5nа +,i 7hpѠ  -HYܜ Fy˚AԘAt2b+ Y. UrC onH6a_lW׫W' ]QC+.lӉ5A[-p"4,44> ф907&l2!/ *+[m!T:\6 I5jxL5ZCv!~7wrzа +I4N' W'3hw?z 8xu8q;iގ~B3|3=7C:f7&”$* :+[l!t:pt7)asꥫ߼(wiPaaBF 92jZ|6̬Ӊt mp߬N[M' f3dw\0^(Zil8H7 ,6$PS +_k5]ȡQCS} $O'5ȉAý}_=h,4! *yid`N&T2bp E+TqLDD!tsF s f|!5]Hy>jZ|6Ӊbpȵ+I ;A9A[<=5ߵ7d^ . i2ȩ1`Hj~;"ia :j6|e]lW/^ {w3a8p (G ɭ˹K}\iNdku{AC} 24 K~]KS L|[*©  VX:֩^Y9y7lַE:lHAކȇ]oj0_8BF e +9y>A4vy: _<#o}m2ۂ O4=Pc,\1`Bۯl*"-lÆpDQ ^k8KvY5]~Xz2]\|b#0}:Q]4-osT}[-p¼я˖f0-1C E0 1PC TVCxiO"BMv2B= ` >ANfа AC'K ߵ+_U a43dC ZBk@$!t6aTߪjTy57ڥ5ď]6Nn]VV!9M6 k|Ww:u]h'7f0 h{+T0 ?5*qC̆}QU U +[k((ܵ|'d`xRO tӉY!ۂL'BChfGq̠C [1p z`(j8T[k(.v5$Uȉ `s4N5eru-H{8!:yկq *B1佰ft8n W\ k D8Hw!+ʭ˸ +9|heXi>45A?'y2oh i0 +C5#ې ew@aoPR ڥ5W!ĵ'ozѾ0rwŸNk~A4ܶKfP'!!- V#|63j0/JeHwR(엫䀢5g![qr `)+ Vz oԃ}8a pB/4e˴ң"b1Ts6|HAb6G˸`( |HPQ\_.*y|$hp;94keD}`9N؅{qb˜!M] th;ݠPĵ@aAw!ը!~ߺL?@aV!G'.] f4bNAyKnAڛp.4%po"6C2f Y1T?nlÆE\tk ܠv! +yR>vio]BO\,5ƚv:qt޷4N AlA~9(|3C A `Pc;$ ٰW?j(OʨA@ԓD{2_O5O\ΟO.5,_aJCDv +_W'A߂[h6[gG dȃ`T¸rPݐgF!jk ׻Qإu$uW!DK azA>y/A~݂L't3|G53doR=n !;Hv!?] o)AsRmA fPc OC a0T Uڅw!ըA][ +?P=_d6J%WVN'kz ܷNi'҅ف͐T2 ҿ{o(lG} + Y(^Wߺ )i}>Qt9@4FW~ztN\;D~:!4k澥D} a ޛȚHj0,cPɆdPO^P5(O֥<ՐOd;-54K ]4O'k>yᾥ|rh [p"YTV 1N^Xs9٠ v2 (.dv.K +)B'',5 hZiex:^ka4v 2=9i,&a1e6 BQC@>vin]UH*d|ޟPXjH>?&$,qrp!\4دbN _W7h[juJ!,AD\gpcZ2 nHbPdːCפra5W>tY[j`6y)Dt¥90P9x=k4N j R/4f' i2 Qb6aJ!5/WDuW!S zI.]$t&䥈XNc+ 4TN'kf 2oih~tv8.Nj3Taly堳]x2\Hn]UH*d~>1u2[j)=|]_vr[U/} 4T*0 *LwC%j5F pүBƧD}'{&ɥK6!`MDNaaeDqғ]YjK s߄\%8Z/O\FCDx![i.?ߝN5HD4[D C07nջ!φZ5 G W! >\Zj(??1{rk<1Jp?qtDo)AW'* p Es7LW>ȷ̳g>F ?>䥆MHބEcr}~{t dD ݫNqldX~/fCQ ~Pdn@V!+}zKRï߬D'`#LFåT4AV_i/\N N5H{~u4d]/D0X Ee>vn]UHu>wc./5;DÕMH6@ GY4|Bwz`/] 6!>Gd47J*vSr: 徥:a_eͨr/P[n8եNױ>a{GVWw' Y4N Ul;*d~>wrV.RMppyBݲYy!4obWO'5 9 K^oj07(Q< B'K/1.RCMUO,la??<>_i+ etB^4e3,SIƫ!;*}ҟO'˸_jx,5 mB߄lh<߃AHVp+ K}:a_L  z 4Tڅ o5Ux>Q^TK N'>A4>)a4{i'pJҐ<_v鄾oY4Éz3,#yPF e|"yߩ_jNMܹE^D])P<䓟?hq}аf_[g=P~\5>t'MH 25.OLA>iψp4+ yߝpd>h:80lf6(QC\}'/ `_jH>?wJ7!UUOpJC%'~2FރO;bvHV鄬4NM0hXKU@j8;R R~)ۄ<A4rڢa5]=Hy/|za¥})9-냆fX7}̫ʨa|½ɥWeN&b2ܹ'x3uyeڃ|~镯~z!Yiߝ/; 5ʠa)_m08jUZj'Nj:<$=|}=ApR#_<1)O;O+ Ӊ?o9>hj5UTCr}J/5c睊MH&dc_%,!Zn\V>v'{[aA}wr:10hhh^ QCz>a?Q,5&d&-w.3vyi4bg=?q;D,h߸0zry~; + eqwbA?K[m'URC[ti&:vz}"syUj ٍ+/Oy~2߃T+JTN4^^a|] K R<& yل|:>aV'ԝ˩GӉhȿq9t2{DDdi><_i(VN'AP5T !;GO䛐&&d:vy}ܹ̣AsyEj 2P]jR?TYiߝ:4,k)ZF R|~"߄ToBc'fܹ\>kg7.×']ld5 ʅ aȨ~>_L_j(6!7!ױSw.5 #0q}yB.O<\xNd}}b%;&q9}|rƥ͍}cfv*V.GN'Nns>ބ|:+>$Rs};\J47 #o; Rݸ|tq)_(.OTރxEb'*/5hH7!7'^lO_0w.u4w.Wr o;4ܸ/O ]AO 2hX7zO^jPMMk }U5$EuU~>Ӑ|2q<Νh'ΑhA 4$ߝ iMK Mȝhr}sij_Υ~}{u'0 僐Bo; >?Wn\f_{AV?<1@34:-5 oB7!ŝ95d;eC@5^)AN凱3 s'剱=YK>oQR÷&><$Aw}r2yqNWz݉'!`̏ᷝnyXalLЍD=h`06j_j>Dd3̝ˁeu'!7Ӊ9ѐtaLqRsƥۃdeAC PnBf_ۄ\\Ƈc7D4&߃L|۩N3 v4'C{%3OK MȉΥ{eC uPC ם,kw0 ~iˋh߃8XysMOmBpAq2Υ~au'!yG evz޸dy}ybw+ K4o-59dUg_wROBN#M42v !N뷝‡o\f_Y9Xy5-5L\޹Lj._w|ri1 LaÎpAm'0}!ƥq9 VadsG*졆WםIy4%DC m:A!v*iPECq/OLAr:h|"݄O|+~}s>-pNI;U}GhLEH=9SLWg'߃\wy߄>Q|qugםOBH 4FC+ҕ!g&iqJZO ݹ>ԐӋN'םLߑ&`GeUH'|Hx!mgFn\ 2?\NIWOBh'bla+A!OB>2Lü44DɪNIH I;ҵO$P~h N?rW5 +/.>JJF7!jN_w* H#|bg.gя\߫Hh]h"= d3 'Qt'j(_w> z$dxG1f|h=7?FWuV}zb!ӷiZ^>Pyݩ$dxGy'L4T>>13`Ͱj4z6WAȏ>YFCL{+Zj?0SxI+;3DG.+PL4W%3 !/vĚ̻>[>qDbc~O>Z=/cߨel{UcPHBL _(j> #]Db\ƾ66fM`#/We?= LC +Ҽvs!{A#@44q3pu6L[4UME6*_~Wv:ohPo;qyb'&_w||bg.h˛x4IHh8$[DԗG.'W5 $7.wa8=Dÿ#Gr3ϵTƶp'#|rpӛ_ƮDC2vG.?=ҿ[`:'!eml Wml dp9r4\m<~s'؏4_>yص\E-F_&V1/~Tb՟_*rmͷi]  7d=˱Wq{M'ƾmgochxN4f 7Pp56x4\r* Ghx׎DG.kL>iQph6hp] D=h8G*7N 2  h8e*~EuD,`7= B gwWO}h"> ~YghxǻhxN4ܓhm2 ډDUWhxP44|hXDCصhxepd42g:~!nE=h8)FëhD"= |zbVi4wk 'p,nDU+;p)h84c%a#>=|*D_;!6DbU ֣:]1~hi4>N53,ΫFPDE4/Vhݳ|S}4k hx_hxpq>lp *Dlht=Eí:6Eó 4#y'q Eϊ;h8h73~>\WF&/}4|hS+GwVgepo ?[gpz4\h%y4?7hXգϭ=㕮xj4j `%n8'NspvODùS#a&fFùgl4|h(N IHwwhѰEÏ&K&>wwL46'nH4گhxH4|hX +hW4ГOD3) { ah`{lᘝh +1h{- $`- oF\ kh8f4'!`{m4<$ԣDb_ۏ OMD닆 g?I4`8ugI;J$4a6Yvb-;m6'oML0hG3RaZw>IDiD~mfh.auagc1hnz05@729NSt@4F4Վ]p!Y%]6c@4F4NW Zv#v7 اͧv&g,uF'h0h؟-uwݱݱ8pzf&jtTtD4F4`fa<eG6p4cԛ!jGhǩ5F&h0h\)e7PuۤN`h!ghl|.46Pӳ4:J4IDiDþjn,6Zvc0dn)RC=BsD nNgӈ=ˮ Z-̏fSTPo,MM`ѰבvM=mz0ˆdpBzS4[ ufib4tD4F4sN޲͖]7f&H u8!kC9BDT(m !!8P]ֲ}:\v㻮.Zgeflp*H S4ݝ'T9MrO`Ѱq[vdhF\v0$]lU ȑtp"f)CoF3apܤ\H84ݰv6,hӈ}ML2((nF0tD6qz?MQ] b:#$ Ap|9IDiD~fi/fձe7tbH8CB$Ix7Ңh0h(k5P6ˮ ^7g|D=FSSO!4!7Ө&(pD4F4c&F^vu,lꧤe͆:1R&C!{ϫ4K4 $4a4 k-.SRzH[G-4DB5?W T=Li&Fi>IDiDHAn岻k!=# {D²͍Q'(uwsPB5?ϫ*S;KkҚt?&aS+.ﲻ?$*̘~yHQjy@u qC/?IDiDÎhee'zae}L}HjN KIy3ES0*@ijfilʆM`ѰR,d+]/j\#!d1j[=Euu#$C+ +_.)MS1L(f~I"L#v9A]]vk$C] -k:ݰV6, qyNn1Dq*apM9Oi:lXogE4C4pvG7-[jݭeβ flB9F򞙢 (mFTCǩe7 IZa`ѰYki!/;qp n |Lˮ|H*4ٰ]Ś#Eyf^(&#tjD4F4l|&A.Mewqn+Vˮ&'JNnl/kӈ]LNn*P, cέW]m斝*Y{Pvw;DU/ pYdDq +TC3J3pD4F4`pƗ1Qy-R-lr8|Fv]}kj@irfO'C8DrB/ sGN+/㔇i |.4IDiDsٲM&ˮvYB9\,; 3x6lw?4,c^2t7D~w{w% (/t&h0hzlCb(e[,+}FZiK#]yO$Cb åX,&*S(8Lnφ"=IDiDöS캭]NheW].2nH3٠|D]vǣppbmew7r8n3R #*`c4u̠H#Ǐ=䩊$C &:(Ttj L#6z]|2TŰeWe7 Gż7FctX>11>Eq)4Baܨ˹w4Pa4p^6swI:T5  Nزӝ77ˮ|w]\0mˮ,eW#҆2l5F c/ iic+DqrӔálh|r{h0hpXXvřh(->rhgٓT~Ҝj֥uE2ST 4Ba~'eWC8q,idyD>X,xzuEyn9D)qSsqi8iԌ(lX$  {5Q>M.;qp,‰C3iC="R fMuirBw! +FOPoݏ %)(м#W`ѰɤL.Wa']8d].qٹr'ղ+&a:XU\!o~&M3/& r #h|qb:aP kLxrӈ E^Mt^pXv;YvI.;1qU n/Ȋl?"mpJ5X= a s'߻(1Ma,գ R  {$4a9l3|>!2Ű鲋]xJtC~F{*-.*p#j9fHudGuU3G0+W >^aF)x M/}ӈǤueל6o&ew# fىǤV.uC|FG%*`:c4j=fuC"Q Osʍ0LaB7Qr c6sә$4a)tٍeW'Ce!<%!>#ţ6H[\nq\1C%iQ\ y\r +Ƀ+Łá8Jl(&h0hXsH6Zv7,]5lHǣ/oxR6>dC>Y?"Ku8.MW)]C +8Aa|8>{q4UAR m$  .|31]* .2d7ijUTeådV^R vl>F&򞝢Uwbg(NP uݪ>>sb]%geWOM)lpaC`jfGcTKA1C:>d)h8  ^&sıP S il(m)L`Ѡe7޲kTkX GbxpZvYvUqrpW٪{%Vs6 'cH݃%:ŶcT+O·uH.b F04|~#Lt(¡a>1+p 9Oiӈh(oܛ%{/qEXvѪtUey#ˮ|Hz3;ZِOV#R8l=X c'~S gj1 +j^Mc\}T9&Cݩ\u + _~OT0Lq:R|Ƿ}$rD4F4qݨ^vW.37/NT/wŲew]Zvi N>$ k +Td=OVG`:j0e1&i]p1&ݩVCf(ո|#W'ʍ,bqC 1; +o~.:$  \vu[L.;fz>#_ /; !IJ{DZv!Cp?#l̆p*a# OV#?lOi~S fcTu~]:w Cn #O_1z0N\8Y%xtᓛsI*{~DiDN]w.gAO≪_vC1|~\vZg=!,;iׅpIjzF*_R4(aC\lM5Q pZW3)坧:Q !r34 ?>_W$5S,nˆE=IULQh0h˲e_M3{OTǣGeXͲC y?[ ds6<ʆ4֯cNH +꾚Hucj>Op( ѪS0 #WXs*S(4K\Q*~bD4F4k9/bمC,;b=N<$npg3R.-`sj8{#y!M'CxO͐8@yʓ<)?y?Q8a +!iéM`pewu?Quܲ{L\v_R.'N-!-WPVG/qQ gncooi]y01Eh T ~~VT +S*4K(1Iw]$  .k e׾-.!{'Ҳ󻮷Z.!<$n7H``uj׽?pvv7F7i]1F)z"jO Q!?Bnꕧu G*OS iv3IMҡh0hɲ|SW>ї.캸S*$ {g]%4T7|S Ⱥ)B?E՞ r|Ya0OݐFi2TwgDiDZβ ȲK&ь3t!2UQ^v_=[vwbC_ױ3]w!pʶco[A eMúfȟ1!ZEw!7Bn~y3k/>Ï4L~wݐFi4=)'`@4F4cUW uWśN2Cr0g#1] {g$4{^džK\iS1$ѝzc}3LQaC.Y$  ^vG-ۻ[3 2C'k\ _5_vA)?q0<"McM|p1Ygn?:Fuyú:w0 * #h52[y~~qJgwCxɆ $ГD4F4oٕW i5 㛉^2<_Je'w]^v>R7N6>"w]PVr5܈j8Gۏȧu3 a]o=4D9op10a0YB7 e6o'K$4aN^l33pP&|<]笹cR Oˮ G|0rU`j8':C> D8O+(̐!7?Լ`j/'7M.V48nRm$]&'iC$4a.]䫉☡x31 [-o. l(qھMw:qPSTV ;aX͐!7?yʋo?h~4pfuWnG) 4&h0hrM~Բ,LU|@,\fPbxf\v.eB9!<$nHWVNdC8YuH!y+.q̜j8q+ͫ )("[\:Q gcT$._MfHbd1|7F j^^rw@i0̒rr6Ooa$vK4NIJKdh 5ixI)iCg?[<#UOVGtݹ|`j87{t8NctX7 Q aW_ 35S0KBِ<^L >ds8q'h0hٲk=V.]feeemyٽ,-;!)tC'j|D7WuuW Ty9ӺqeY]"S_=Wa|+W~n4Ʌ0K{~6Oo]|8h0h8Êe_ú +]q 岻ftٽB,onxL0<$yܐÆ `ucƺ_iG5xZ?aT a2ᕯ|GU qr%wO&];I"L3 ^v2'-㫉p2ct:eH{i^93/WeaxHrMaىl jC~D + `5c;i1zq!~I8+⛉x1!(1!ZEa|D~u_/0Marᐻ E ᰡ3IOґh0z4o]R/{T.1C0 bى`YvYuߙv] {lHWÆ`U9pN>F _j\9w<Kph5C~Lxw@rpôyYJ6d Lmz~=.tcN(wݰ\8 Ij l~D `5Sq+^.j8+1roinX5peԅ!r0 u~$ +bYa8oG)d/ۉWbC{I_vI"L3 ;_v_v=ly_æe$CQ Ū˻./;ΆtaCVQ_K5Ǘc_M: WpX?vȝ1 C8CٹvkLq +fuC;Jοo&'$u?zyj L Yv-nx^M\ o&#qՓޮN<%$ lʆxaCVV%+w1*ooi;pO(7CaKH ϒXu_>g/q5pf$-lF]ΐ^M|_v!Mzٹ#zԲ{Cuo(wݰCR8[-HAOQױso\h>#q2\goҫ qeqzܫVC{!7A1! 8p"xyؐC$ =-˟+Ȳ{D\v.3װeQXvuci٭B7g"ɪxDr + +4sW~9MKwv1rW utx8sp ̈́D=E 3F(Λ ?rӔAtOR>|' t$:D!aˮwlJ.]gϊq٥d%яe#M?$ Vl="Æ`U͗jPTfʯgo W1uwz$+ϐ0Fp)[A _> H .Gu37D~%a4ar!̆A1IUN҇t۬E!]Ɩݧj]$ ~4/pZ<"ÆE~/q/_O5c'QyZ>4ěp!N;s=1!f(P-řrR8JE6cwh0X4nů,>jjٵ&cr٥d'hvere?#XvG$w9XwXvTé;Vc$OǕ1CF@"wT۟1! +#-6_)̒1JE6 $'i)M4w0Ȼ\ve''cŲ{Ȳ_M3e?d'1fٽ%,;))uF G|P.q_N7K1oӺXDxWNݾ 3Fh_E?O,npNl6#wh0T4lٕy[~<,t|5Q7/Q/_]vq׽5_JݐѪ鿡6Qulƨ1Nw%!ayW%+o a5L(lH^65I'9hI].Kònˮ3Wřjx3.3d%!_v.M,B7g$qNV#R6hux+e.3d^v>®.?# dc6HAױW4j_O5ōn7|h3uq 3Ght~+IC7JU6KB!LK&)}´c(󎆱<߲e>6!@ Մ[vabf.xH +VGtV+:V^rWǪNӱ(]gȯ&ǕmT#Sַ!J3' owār$f)pܐQʗı|ELtt&{4LYv7p}|g=lXvax/1W{ˮ ..U7g${D EQ_lpo>Y|}>p a>e| jcx3EN0̐a`~g%ki& Gx:ma;K7IvDѰfȲr}]쾣YvdxF.I-."͗+ʿj8=lz@>#wX +ʯ&ܥ qʻ8epS;8?O/yᐺa%_U ;}Vr ،6C wqYv13!;7t.ƃ+!<#l.?"q^džϙK\X4U XŏM[A:C}Z%b7EQnW !Z8Le7Qj!틓]$/\vՄ)²+N Őa~^\v)B7 h561"6]lp1|2&Ǖ1j=6/.p׽3^2}e-Vl W~E^ǺK\wNT"|bi]y̐-oS;Q8? ؉ S,Qrx8lȓ]tV,TsѰi3teF|F,^L^)]8SMa5u$R7g$ o.6lxnJ_G54C9F&qӺq^ySP _ +'q,Qr:͆Izn1IEo;I`h8X3Ŀ/e쾥Xvp̐LGAZv!uC:n_և `Uo5OŮ{ົT2G$֥{U2jUw!rF͟vā*g)R,x%gCٰ$V*`yE67Yv7_sىɏ.} W {XjBv:f]3R p ^QױWN;15Op_G5#67_V{5wd-ȏw8a(lvanAlE^W Wřj^vZvrxJ +ݐ|6!/z*.qc.>]wsav L)3Ӻ1Cx1uw*?CbzW!OTrb6#fCsоȓI&iީDAg)]:fdHbم]痝{F*݈,o6ulN;1]w/,W:1*noq2Q$Ca V'?L(lvN7IcU`hO3|d>ae@ =ʇ dٹp \6^ǺK\Xj>jX4}v'-Ӻx {ib#fϻ8YF)fooԓsCV% 2 Gjj٥ϕψ+{p23dw ޥXv)H9ݲ `5 ^bMcծ-XQ؄Ӻ'&)C(_q$FIfoЙMX5NҡA@4Xa' ߓe-K&:g[vB/]_v))wC d VӮ.qū߹ӈwp 1 +W >jb8+aH`r6v(c&x=W,(N~m\y؄pmD2hݻg]}D*Vױ +S 'kQ͐i#/>w$H !?9U$f̆? ۿ]?K(=5>z)f=WDá!y=HqAh] β+v_vD6Gjx;|\^.iM5*j8)n1tcoH|ZWp)CFnqJ p%plW`T  DF͐6}=Cwe3Wՙj̰+r7yDVņp/_iG55[A _y)Hp1OQ8sCgȏ_78Y*axI IORw &[4^}FUke{ D{0\fp].w.beȆ$W-W]wa scŝ1*>jȽዟueyuÍbb1rS7iR8Q*Ŏ&iAP@4Xa!_vy q. 7 װ]bٽ[r:$HjP^>fN;TYP3̍QIn1J&vuq bmG4K(l$ŏ^/̓4j VK4Lo a=lr=슻[?=QH?_g\v3ȆzEF\lWjxn"^5#V^La{ yտR.reW>#lpH_?"OQԗӄ/¥Nֱad_ku($vW uS%aHa}ElNҵI:fQ D)g  |cֲ{ܲs kv{g$y:mwyY JU߰vS ˷u3u~r:CrU!b;J)ÆII$հ$. L1 h׹yز&~^v;;ޓ:H!⒯ciQ _N>GR '`fr"ܸN5j7FG&qTn84Ԑ$A?ocIzujp_pLDΛឪeey=geW޲kattױWj24,foQYC&矅rr7Tِ|GtU`FBGoWTů]v:C:lh+ +:]~v/YI5a1fG-Mbq:)*gGaJ 4I>T.ad^@4b v w[o=\v/iݏ-d\vDNp(Gt8X_*~>_VSӰfc?}ouN/&#:0U pP܇\c6CUC{h8k |fxx}IJ+>W.@^M .&ܲjG$wPVWF5AaocnW O(tw47R(ǩ7J2$$'ip`IGReueC-f"vuw?8Xc%.q[||l}m=jX%7C9F񫣛1H_/ ś"us8Kid6 N7I lh挢a v+^M\7ae'¡zFj'Mj_}O5a7c$H +J)O›pX'( QTR|W6Iu'ITzvߓp\pS4LF.|mzzٍo&~e/e74>0)t5}T])Nn iR{Tk5\YLD꿊3hz0h.~ӛe{5ղGXvSG|ؐVWr^J5Sh1z]N3ú iXf)fC>xu5\4C 7 ՉEEM4(xaZޙL^{ٵH#Ryڼ-?0}pNO,w>6!O=tXANQ3C4͆]z٧ewS Fz;A4S{0m]vpu^v('ÿL/2#8l(ګce5tgl}հHkuH|b9$W)C3D>BR 2at:@4q >^3<^+\vT-}4βĮ c7ᦏ~׽hO5,ܢ7Fomy#:C~5![5S$?f(^m5IGo1JcBs4W3].zN,f׽W6:6\|`,:vT3WEZd3l3FuyZ-bZ(TRN?1=ISU`yDd]wewMWGYvݭc vkT6.64p]w pNH~byV#Q!*&:aj{ؠ.$ 9huuj=.]oU6T Sc̩wpuo cOΧ bXTGi'Iq!R|Mp$&w)=e4ˮLXc5P6ulU캟ڰ뾇j8 c~=CƨSM1tgl$-m[4 턣A~|b~ Yw Dae<#_ױ{{ p"n-`7>jƨ_Uwn(<6l9I.lڱh1pfN?FC6ãw&ܲknpeCkp/'а]@qljc;QnԺ 25t2z (t`{EG% +jSQ똁% 7z Ǡ!uJ]T] +:$G1WH >?uWL 2C]3g_Q1%{4AjxWp$*z + Z@0)fhbDƪ6@ djb2̠UA4KwE-)lkPd_i9 s1{L ޞ0CykW-r!]u[8VgjuL34xFGQ}MS +^D "\U0wCxRpNI+vxDb7d{&A u?3M5࿥A%uSC88CFa^^ʼ]a+*|%kkFƱQj0Ů>5+Cfh%ɻ61xojGEKjB aBCjW3do~۲}/vvŮZH}_׺ob"SCǢPI}TڭKqT<Iݡ9#fhޘhH#ov[Yˈ`.ăT{ֺֽ4=ʍUnZL ݌~3M=*(N ^Wmf/)|I_~ѵrh(Rdghkʉg9' ,vau׺% +QCM 7ejf 3gTAe]E ǔp1%uD_,4̑ehot^@[+*ufzŬUv]f'RknD_3m%&|)NC͆ʗNP.v34LYtޖ9π\Żcڵ45들Wej"3C[*bR ~IWUQ4Ph' Kghe +?n!%lU7"L Y$ȠR3RD09hX: 04hQC n;b3 Y|l q_/uе3,gw}d(ņF/7Ԡ / +FMz}*63$=7b7p{.yt'SCףfxuagwJ__$Oi(j4!3dh04^Yv4GfZ:9`Ů6DZхNRBbV`?yC1 z1j`lP. +аp +eh]|jxyF+k3(v}"պ"Yff9?yxLOJ24LSt +V +a4̦:dAvbHZ.vtjm1<`<yK^oGjb+6 - *o6u  O8֭gjk yFUȐĆz/55"V|_)v24L]P)ҝ +f( T^5̓A, uQcdT7PL ÆW/6 !4,a0\A1 LAjݿTP|TdfH<y}FߗTJ ٠Qh0wfh:4,0 pYafXV]u{/k]hdfϨ[4M/5y= RFs wUgJ]|GlbW c%պL +f3 G lxe%41CCߣHt^91PŮZWE wejxg{F ͑{JS5a0Mehxc%4)p|bWE25)?%ߒWХ!diAO2ýU.WZZ&kKjݟwj;25ƴ0C{(5S%tAl +0u}Wa##!| 3g˩|IA|l?f^24LEIhxK 4ĩa6͸ 3(vGejHFfQdNK)t0@= =@üC}L W25$"3CI3Sj6xU 9hx@C6EhX%CCߢa ˖@Ə&\JViYfxI+{#?vZ)I@3,;ϨfK 5`$ qhX"CCoKа +BÒ4, А o^}jX6SC"23ĞȐ~K~I01pma0%IhX" sb0Nk =u⑙a0/)5lK4>CC'`[!ZԺL 03j^>%Sk$53Xh6.4,R Elmhx}H-f OG23LKjL >67|qyuhX-CCbRаMаڹ3U0k23TgZ72j~z'uc̰ƴ *f( {Z×45 ,0~4,ehxEKj@DKٙT~5Ej64 gefKPC |9Am ++a324t7 4`W,<+K]fsR\zԠ%\ J领aa9B3, S|K=żSnA p\a }@ а^)4HQC rS223 ݯu>5|(w&A3)5dw&3, sjfX9I3Ç33%5>DAl7 3,4%hXaicl'Ѷ?S mjutfa65,VE ;K f423W_/ j`lt' +3}ˑCCQMEЫ34`a44,CkٙBYY+0\:tijpjx\ajHe88L2dCfgԻԘg3;@hx^D]4;y"|~/5V(&M M Öf՗405goPm2ܷ2,BGaŜQB;abR^;d@j)jO^ jh  ̰`wgfKaA^g$38[a% AhM24t> k 4,;Gw.y +eDz̀c -fDj]=jxw)5,\B L:H -08a^Ґ`5B4p0C RhX7CCObа"4@J5ؤPV] CDj]sjXj0ib#i)|xBfX~ŕV }}ICQ^$jY͍MCġ @úW i P23C[9ѽZ7 5,R]4ǧV(: "1za(,6Xpxe흳(y;-+qh%CCWcphޯA5VCd-RVRt)j^SG55ҊǩZնr̰bw3.zoQ:K h _Е4쒂UVZaiQ3RpHJ3ش fEj]ʩ]uAG*-Yf 33%5ec`G < Y аE94\Q@u&〆/6 FЪ8V2efvҢ{.A 6׶J ` + <.c43읙7/ixjrH  3ѱi#>4lа}Lj(-hX- jX0:'fX63yѽZ԰ʨa$55dOd Ղ k)a>'0u%ũa85; l`pXgMŭt W@Q:6\.[.\c33$1W'7y:'khV [dfKRcWL:Hv#>1Fh8Vh`wE6 jŌr3gM234Ȍnպc԰E 5˨J hL3uJ12 3df͉>a(5HacVj`OpF2v͘04|RCNԠ )223èR[>԰caJjeE{̰1CC̰:1ڥpPf޼aI N/6 t䒡a} ghxL@;*Bb2j>A̰yf&ѭZW>aX !i1d4x"䲥dw63l[ gϨ/ixjp " +?(4 Bgh3l԰DӓdXjrL֝SA԰6QqjpPt * ^=$$a] (f9`33t%J ,lf Id5M!CH8ricv C'֔NwPl FuL Ga[M R>^UxmYC3fP"3 :- dfK`yi5HlW4,tа-A~c hYBօN2\lE !,cfQk]vV԰AV4ۼFj葬! iACzq3,c13l.aπN՗5[rHԈ "tg !54|*CCcаAöml2jX.%X;+cfX23uNM>aUM 5k!k CCL18- p3/jrHn6u ElAÅ:OihKSj VH (3(d.N { +jؼ“ˎ4.[2|1ld̰uQw×45/I 8I̠(%CH fh|.l + sՐWl3h #ʐ:E G֡ⓗH&O11d7e 2<̰3j DfXo 70456LFn@voюa(]̽66а5@Fh8@M%4%r_ +_-22h" fLօpSÎEZmma=֢]'ԀP&hH,[ƏTIfX1ç3d]Q_԰j@ vDaA\ !6dh1CCwcp6а;@6vЀ>Ҽ>*R͘V0|G 5ca5ea򭆆 PNf afu% J dΎ!Q67q'$Y]6Ї 4а!Cv 2fX53C{щZw9Ժ5P԰O%!yb[!le0Ö3pd333D/=jXGR˯;ˁzmaK GdhZL6h`UZMr^-0A$s_efh+&]%j8B +jlY[ +jRgP=^kH!63A˖;R<32)p|o|F7445Q6 &YWM! dhdPа%B򑦝KNo5IvexefX.3(bܵ{}g 5P~jp.@ñNchJ זAÓF]^(h@wUlصZr}S$ qmW23=jthV(5L '2\PN6̰`ef zL 4B++jap"\s䕭M 4lp`d4\[@WN3pl V%W%xdfh)J j8P>>a}K eC֐5Ln@x8 DԠAG;fQf8) ߀gtKfi5䨁*)و 2՚_A&c3аk԰Yl2pErṴ2+ DJ@ Pg P!4p8Ag@FH9ma' {f801 3 f8᫙"1U`!yD͆h8023I2b +h09E~*k ݌B& 8GdoQܺ&b" U"5SI6԰>-AJ5wp;9 _tNLMߪ)3\ÍdL 5kUkF o}kqK3p|.aа'][F[ 4 df$z-a&S1j +A֐rR!3/k9 3A e`dNXf0h= 3e/gf()5 lnR +L34t! h8, I|Қ(:n6Nf:p=vRga3A ɷkH!:h:%hP˖y4EIc 3rfxhV~Fj/B  +jxWSԀEpâ^Y!CH-_BÙ:а +xR܌,F +[q23è3eaP|je]1dw͆eq"\| pz df+aUG TEdp nI)34t, gJhؿD-4Q]nv)h 3M9XT: Fa ǘjCp5$:y)!˸R7hh(4,AeKi$[na]3a Fߩ|6p6p۸b{n<6 2CNah4CcpLEߜ!bf]L&cU+a -DᜂNp]>'e CigP4h1rk (&jh4)A8-ԉNa˝vEpufҘjXA(pšd.n.͜t K7 Wghh.eh8 x5SRWdVn3{"(3袛G eg:C֐bRPbcDI,NeK4u'{N%f 13 3~S:L k(j=$f/k/A +aFNȠ4[ DhF b2k Jf `533:&N Wp~mO^Zke('҂8!ԉͣ{3,dK. u԰{@ C#VԀlU7\pݬ"h82CCbl0Ãm4$]ne|l E[Z1 dfi~p[.(,5԰|(Py';! ( A!=Ђ-ԋ֠AG1<~G'a!5lNeKn66 8,ȀE .h$# 9hyfhDhػOR*FlSf=3CKj.J!e5kp+q1$#X[ Ս4x"H [0іjTP6fap;j+ẛ9o' )h/CØcpgtp>slˊ>շx +[2fFjpǫc֮^TbڲԀb@Nx Dr7uB#H:Mp"3yGߨa M kG P 70U6ӑK,;ȣpqGp_ 4$aA5ajJSUf { S5WP3 @'/ +mPX1d3tp"48'H)t˖ HaHxG.f0733Ԋ^Qö1j0q@_| l6 ' 4Ih* fhC.pG^s54+>.ɹ\̰EfEwH<^lװ!w)Z2CѐN _/NeKk pxGb3|0]ʢ԰1Qa-Qpw21e[3Kqz[>=а34t&GpUv߅oc#4|\| 7j\u0öF5|PU^vED Pj8Pkwq‰!CYCx[ 5pBm[)eK0h@S'ӑc??0i f2ýqfx"?#=:_T15x͆|npb0u +Ԯ֦.ch(fpNnXt 4*d$rMK'pEf83ècpRM7~ۧ(ujyq!]'7pwY i!=Y?S +z8\ҠL<T!3 baMA FQ`sC [Qjj9h0c}BhrfwLQ64jpSӪyn4CX0U{"N &-5СlE0fx83CpۖRа4'ؠL<[qf 3JpR5|RZJj66n0Ƞvw#a +N=}YndX DK4\ sTQ3;8hpׄ|!dU;h3 $@ffo6@\;3K2FkHx)W(35T(&jhh1I aq-٠ Vpe33ԍR[Jh66αc/}G٦\ٯ(G$n0hopOUаǮr#? jn3%*3ç˘ m$vK j8RbkHkf- +C*'5PL0 +t8a)A~d@Nd Gda,ADTZ 3 Pí@ \$5hCikװ +d b2>xvA  ޶ '첥2u ?P=y3چ((bz}%ݫ2P$ۉ r NoHh8Ba*a ikQ+23x`ef}FjP;yΚ<˭#h؛iR $rҽK0Ç)3Db,C ?Qõ'/ɓk;B 5.q@BOn54h4x*Ȳ;9.RU0޴lyhЀъa5쩨ʦKl l@n0ߕ36VҠ^` .1p34?ڃ(h/Zh3{*h/?w2=S5JNrk +fݘ(5|çd'xI+'oR (ZD!h@<-z24XΟʼnC?B4>pfffb԰M@ B؀3 +m(@UL߾RYA'̑K ehN w;h@%ƭA5+V +İJ>| +[1Þ;w`P1G5l+.e w (đ쒵1H!i4DnN ޶Ԃ8 `DGn(3C<5`aM hذl606~* Mϖ?aqcg 4l3v24L6 !434VBnHk;"dJm@z̰M05>Slg(m⥽BΐNP+"waFCT m '' ŕ*lNla fxc33FpG 5lIԀ ,l*npVHfܡxS24t(F _3pqAh0> +6XYu26:dϠa dfGDjRN^ +kQ\@ M+5HB6n55 yr +A 6h`S'} ;`yt~F5XKiCr؀D웨 2<oQ/14,CøbLpʉxЃ'jTp(g@{d-vqpxfȨ`v }[~,kH (Zɵn4x*H8-#yq_̣( (5K6PbCQ]2PA)6 rRa'CChFk@Fm@.4E8Vp,ֶbuՍ&[GgfX=Q45ikHkKqJ8CJYػL[<ɴ"P o[JаgA-N<,6hP'n5'{~N7DOW/ ?$p53uTm`΁ƴLg@eWԃ0hxĈԊZ^ 'pЀK b4a m a kBjRj}LX؛DYCd@O1_OSCFnߜ '' Z-;R3/$@ hixbӍY) E-Q= Vn僤CH>ry6tR04\bwDKHgO:!nD&`E4] E $H33L2C Yjp /y]bxd +6kjrF#h*HwkDω JՅ3uљPþD h) KF l6 6 7pXqՠmVŴ{UE] @46kFh3h F $JA>Ȁmܚ` b=,3a1D{5HCimPwLܭ.c -diL ܜÉX 'pҙ:c1fx63C 5*ܔs$1Pq/6;ޖQ턧'RBCqEIhxla`(4L}0h,.rF єF(gUK a1jx2 /cbȪAˁ[ -BCFChP떞 +nNE60|tNaC h >6 7p}t"Q `QU@" + z O hp}(Pݺ$0`fulBGa ݈1P//VJ 0x$ i.F7HM' [*$ƛ3$G#$,Nx OcؙEh}j0rHQl@3~Ƈ?UTQ:\26Bý/Qh1kh(7CHQ|BgjF& $SpJfAJKZ 1$;C(9ZH ]6i5 + niU``oN'yJ2uFt#j`sHCˆBbq CQE1\,ťU+a$*4܋Рnc[w'޹/RǒdJ x4ac0hġl.u5 +C34\bAÃLmFch !Xe"q2#g $@31ZjH/^ +WWKGpD o5D]O-'* +endstream endobj 71 0 obj <>stream + TdP=P- CDGx 54!qDşLTs4onixwUm]e, &4w鄄N>"͗34L NOb)#ͱ1`ސ. cVOr҉!RT+nv9dD5-e %zAFT4"Hߠ0xt'u4leg#l S z߀[8y_ig4Aޥ FعDhN:Cr,)(g`f8 `333L4ڥءZjbHO@ YBeVC}hHO'%4-m4uK 4AF bG3z!3C 5 K (l27 4lel4yg #bmtml)ۛtհE#*5mJ1\06gQd:CQ Qjg(xV(O.d ivi[ K6k5j>Q> UaF[&Tŗ^Ƃ% lIa ͣ(x [Kl n(J;'*6vi64Ih034C@S&`H4xNEx m;9ۘTS)gئ2Pp1/,3CjN^ +Ci[=.ɬ -$]j5Oum0Cj:AW'ҍ@_Ղ!˖~G5S1@`fp_\~ӂO^0h w_ +W'j^sM6I2J03%й"'/mS+,O .Հ"jX[:h:ѰXAX4EPA'!ŘᯙFǨ/5! +y"aQPp 3nD4,.c?G. hx4C8" /Ղ'#Ѐ> VۋbCxeYYG/)K65J d WOh!m5ԐBӉ`߲Q #] NẠ33 ]5`(hD#S )9l`?MM5tV34'Ga\ڃ6vs)6OX6Eq4e-063C7bPjХ. nW35%(|i!k +)ICtdA~!b '~ܣ 5p*Q6(+l("(wN$tt#h F Ǝ5.IT )MXf81:5kpbH!k0G(h@dni!eÑVo[oY͵O00dbu"TAFmyw:A 233f 5{*܇ֵt"1t™4H7Hڷ|1vZjeW'nTN$ DfVp:R^([lnrAutv4nՅN"?ghAԁ%q\|QO8n@P)}Kh4Yhu? ?/nt3@D (l0# + E}7c[C f̠tjt"޹^48CHN04cO@D;^;V X&nK ,G*p%ƞg33t, +9'kG(Bڥj5 prՃK +9O4N Ma% 1/>D(h^Ϩft.Ej8W/AI# +l l n2]Uv:WߩA,O8hxXp34(@ 4`hpҨ3z;F!|0& 3vL efjԺR .i@qnwykVLawUI!+Ut}KcmE}ȓ ޶L 334 S| *j8SP̈t@Pyliw? jvIp%iU9hk6chPGa b}5Nr|T¢ ̀ ^@袼!3\1 5߻O. rˊVZk e +9|uh(Nnr2i4(oN!hЋڋR.bjˢ7!lQhl n0vv)!!NIxo\jCH!v2CC @X5xÕ^ E)d^V gpp DS5X1s{8 n -TzI;)V +O#etBA +dh>hoN ʼn -dNH5:zi(4`eTx(E7EYQ;;v~;1 S"a4Q W}!^k5"^4y+ U3h3kZX _#f&8+ь]\Z<ŵV>vrQB6O.c [yKg) +VD(h05@YQ  L/!]Limw=*d ΑԶ 6 -@ä$TF >q0iDe, jWPhVnmZ"3\15xbH%k +A/D\Z إ3xRRVE $ 1g'%D7@)[}'[BI7'p ""H;-34K(l0d PLjw l,y:>۸|W!dEK`'KK( dP DA3%F䝙QI !XbHvkCv\'j j uhN$ t¸AFdѰyF÷*/lN_d~FĨrj(> iD C(EQiSeu/f1N'쌌fd +OFA)}7(<GIbW)EbO*3 ЇG eP <<|:B+dj>?ѮaI;N'ؤ!n-5K&պ?xY-hAg4`tT[9È=q|Q p0!~y;;. RXsڸ|7{UZHuTu;@)m5鷯Af '3-Q+tB OW)'[usbos2֮?1*QCU 6ini^V'ԺTAF!3C1ij0ׅj`alQhl0܀`cLup Vd.Otn 9Gmh_"w`}5h<<ߦ\0Tq3 ʵ AELA5Kk$+Cso´̱}c֥j3! /#h(]N'ޭnrϽߜ<\@hF?`2*hzL-H3PS +C{12~w{ًѐLeWib)W 5jP2Cۏ(P) 5r րR_iw^ pC:<aMgP:H-]M'N'BoyGNnioN %h 33cPXy:(Dyh7PzZdpr- KZ /픡at g iw. ~E4^ )T@hBMH1÷,3ܙшd Bh!wC>.I +j>vSQàPG@ 줧t[ y;ェ(3hvUA'Bdfvc=G 705X'C~4QfP 8r(|"2f=[|N.^24.Ĵty%qf)p"̀gU43 3Cb jPw]-VX[F +#H!V %󉑊t¥gN[UN)-gc':l4QAC!g4hL+ZJ +6L7(8?h> +-3F>_ ivJD^:Hy*CC14<ڹm7;V:Q4o!Pp)&Him np ݌tT!>ZHq"l5qo]Z) +'#5T }I5g' [㿷:A$nψD#AC~FǸ5KZQ!jhQ 9A.\݉ɚ47H#T P私dt8a jKCˆ!6ROP{128fp߅un2\L|Z4dhE!v; dj5H!p&&Ӊ,%#t:[ ZL|efO F j@!j2~rմ%I!c]U$OKUq@CI;Nx& |2ܷfxaNa$1jV/YiGlR톂r`*Es/d_,\V)CCQ81Ky׵JWz@T@J SfEcjP +o[$$W|ܟp˴ %d DA\V|j8V-T㚛h SۖڏS='j:_|a(Dzh7}TQ 9P8(@S3CY֟N"ՆF`ݝe0JK_g0vh%jYjoմ23"P'k (ՠ.RBUOH'{[^[C0RhH AJ%]w'tBA R5nl4TUÉZR!5%!qDC(8,| y0 bv'e|MC +9=DlPOY6hM]bW-:1=zRWc@BJjw(RH +)bx{y3H-]5 uu.`t˜4(C~g +2Ndfm~,ҩl6l@9Qa|$p0Q!@[O_BwӉ2C"g5/'X$'ߟ$ 5S&Y4@ $ZpfDSjppaK7WmP] or Q(\Jxޝ`g`: QNE.o4T 33(&O zi<͈| ZS +Sl ,ԟ'&мP/r7%~"}‰'T6YQ.YGf;3CTAO3O2>x5E SÈ c'BI.\ޝ7nr2HBBP!ht&=G ?pR6F`=qC 12@A0Åٕzh4<ٍ E-hPNsO8Q||k5%/yIѧK% ԲTHwn }T (*Z V5xSsϪ!O ]-jrhd. tv :A2 +2 F㦆5'Z alQf{,E/ljPT5yPL'pﳇ&c2CC[QQg$D t j`Qu5@5|@pr<`4AHg0peefK$+]Հ"jP[w)P۟vLP74$tK4ȅKw'Nd9T4 ';j?&B V/`DzH n0%^Wz7 r:'b'P'r +֌P>a=uP-vkrYQ*`O SO;A }&033-ʩ!2HLJ!El>{OtЩSk'[ b. %^ƻ7i2Ho1ѐ1RÃ@ +j0!Mg=Cr8A1ŗbw NϜss2ad>>Q>ax'nMSI=O't }LUKcQ + r@QՀ2$XO( OSH_N;%O4ZgA@ ;ۅˣ9NNdb d81'5Ry2,E P 8rpQ-2xж N𘾛V< !h-!_wN{l5ǥ+j l8-I_iU=Qd$fm2ý ffYTSCZ *[sB+OO=?!E DE 5+QCu춠JfA %iJ¥;Q2-hnNdfq^ZaCbS +o0`>T]7`t$ ϥ!bTACr}B;A'nKP==!&ҬZu4233/JA(bBRBF|B.]Jv!ܸlT'<i4%_ŦzwBO'3q+o4w4+5Р'Jtg$f-i UӉJ4Cm숂m` T}l)pCQecJEsSfh $Nx ѾW64$'<ޟD36֯ "@r@=+;ЇHԹVڢd>aO@ OSBFテ 24 *O8)w e >w_ʝĸ kdygQE VCj>aڧD tŒ9D ;48%dfHn\F.O  :M<$p. .݉)d!1H!v.Qo6067|` 2r~" +OD" /*-R ).q>UָRwv~rr fHg aLfF̩E')tik7BODX|ybEyA:H{;ti`I;v'jL'ra1Fj`sH+f l\H>]m;D}0f F 4 gK!ԛCiL;uyyfr^OTef]$j_% ?V9{~#)!kO\aԐ˪ >q)tIrv +QdfF𬥆ay Pע冢B7 F7RT(7}=Ͱ9z'h5!Yu%N:u:dm'@ffaī\j(O=!  >1Q`Pn 6.:qI:Hvt! 1S]͆`={F ɭl|\("iU~>tj+cYp1A΋,1FFB蔴gp왙7(rMr҉<QB~2>عln084cBڸ\8A*$wKCjZ cPoKA5Xl`n(K32PA2}{Ӊ{9kG3h`q~B;V=1=m6\.S3dMdfċ\L +'%.S 'V^)s4jhݩ.46 ޹ ih5ȫ58l2H Ԧd(ea:JSCRzBɝ˔QërPb=Wm\:iy2 ]DwcFc.d0oD@SSD D _v% ipj͟rd@0QI s(B`"JH '>p}h}w.U%F vwj !=hm%HǗ':H $ 5NY!FG \K ;l0?W0 1@7mtFFM!5Z d1Srb]K]*@DfizP"j+!ͪp}X>;喼saШaĖisU[6.8qA +I,#5D^  C }'F–HeKO C%)3pefuTAC\95JȻRI;d4j(qwCP5!"z;Z¦Uin\D!Dg]jxΧYfU~d$n(5 `7%kNӻJ6ǼFK8YF eS!j)Ȧa7.Ky"lآEjCH % +?pCQ 9:@\P|2Eߴbm4Ħ/`~ԪQQcoQ'(,5>N7p~[ NTq*3C_QB*%dQRwܮv./ƝK8YJܝVNQ9=>'!d +ɿqmBCDcIälQQ2 fmvCQ 8rpMPTZ  DNvI5DQw\T&n'62230--jJHj|  r}Brw.w%d +"N]EBF܍Kepƥ[@?Ȉj jK95pP 9 ;.` eѐN'>E]hH'R5 4pdffw$!~=>QsIF SrUd02 sjh:= !=o'}m߿޸,Yp+N|@ 86PO؀8ra \3$ mE45[ Qj{7 )D޼Y#k)fKfE-; DZ5N#>佪gy3ʦao\t<#JT67#cM`j>Al3艴N4\:qH4Ė.y>l5j;ҸycТrG%8 7 )'F -7ݠݝBKHGzmˡag.7.C'Ez '24CȴAC\;Pß ?e(CAF7EAcN~FC0 vԪODZ z@opicTqd$dp j3Q zȨw'<`} ET"BSР7.#w5$bXjxg( <^3 pt?B`~[el֕t"KFuOBjHȘ6EԁL)gH2ß331-!-GWDZ}b'bg.4KF ޑRhEn2ACby"NDԠ!R[=l n0`A[%2D +Ol4Ӊ +b;xN0qKQEkR.U66AŴ)Bcm 3oQ @ßݝ%$H'!q;sYhޫ:>E:n'12jrH7ڣl(~ 9:p?U")ԾW7ӉG=hK|¶O"- 5`S!1@ffs4cri 3 4BJa)66Bü=^Am hȞO)j# +l`|77p0]LgdXI!Ndv#EUDAKԀ#{lX `Si!2شm9RaZ +cÝ*h' x* + (4,haN@<4˦W'ʠOqhEԠjDk +,79:+ݵ"H;hܖӉD4O$Z elY3>kā6MOzBM!u; f'  }PQf * ŧޡ!:fP|"jx&zsݠhB#X`JH U/ +9CfD*Y}kUs#А_]jK@zHG p@tɘGpOy:1(`>P  %遦FfDfPYܩtI?TH[1jGl`itفhc`LXG ZhԚO6,kxԒ&RC?U3CdY +H-g zI}t"W.54+CR(ČrS1`w&3Jj4>4Z g4L fF*R0i~x4 ejPN?<ؠ#1d ZhTAh!Hh݈Bqf)fMص 6zAFrC:RаT +а@;ﲛ 4g3:* wpYhx +44#F !~X͆C!5_^ZӉ[ מrIY2d%38LfGMhp\ {n pC 4jaO 4. m4{аP o,pC;,4<,Ocg8Tc2F 0p ;@@eAC^j4אO|"jx.qZN 1|13 ̙fФ RG 4IG4ܣJ1p]vqmbOmа.Cê^qhXay6([l;da_ G4hVCCy!<^"!j=Q29CrF 9CfG2cv3x8Q ?/. Whsz 7а uа2B;$4 5TC[ +hXBB{\ "4lga hqI>s= 4]|4AH{;D M8A7HA-C;}5n4De9h$5Pwʣ̇+)!26MhK =d.&'B @3pvyj73q +րW4,24n k3 3аAv8 h'F MM:ڣoDA?W@`s: _AV2.m4dhh7BFZ 3S"_ts>e&SFb 4:ȄM`\U.4\Z@ù5SO2p} 44@RX@B*aACl҃W&Vch hr>ka}?@ñNy4\tXL5E y>hf3lx + +0;P>3.Rcp:a VCz&ќO*(A2O`Mdf No\N̽/9g]@4,а5 4j KhXA>Q@æ4lma=@G3_Ʒn);jE4ԠV/*60789Xx@X `@b1Cn4'J%5m搙L)a:Mgi\"4oC߽s;6[} ȦaeZ-ue〆Wh=4K4_@çv\p}KܝDT }5O`8n@r \@QraLQB VC5葖iI!S2f"cvRqfdfSTBKuvy"i*S WB%dmWh\zQs_FҞSC.^ƚ 6/cCQᓑ~Fo^!CCQ 孆3_2%12&6r&3C"^$ BgKH\U4ɇWWCÿ$h5 W`.V>>,!Quv.+'|o1 5jD s~2*d$_q͜(ϨV aTMƄ&CT!\ۨd 7.Md !\.—c`hh||byZ6vGZ;F SB,j5# +;`> T!CO?Ѝ<M$& ,iM9l/812a|Ilk*3C?#5vyp2 !#.h@+' Nlp0j˯]O(%$Ir15?Hb$"`0?IdH1ËFsN(J%1ҍ?PjM5BLh2XdS23LAT?AAalqomvg)~r^3?AC#oVbuwB%亁Q^dp<-Oxu! TFPhhY8`TACjHYC.brđ!2 =xpڋKu'NalieqBCGz%d̨aS6j;>JPc>5E7pD2Ɗ͹ڍF"iZ M]٠6b|ȐȗDfEYƧ)I ayKl\޸ jHjHF +xF s'* D Y̭Ԡ Aa` xbu.7FbԠ Sf0u<#C<]23LEkYKCt\q)'hSeHׂ4j\nD$#i%jx8*jVC.]A!>HcI*௙42Y6re`A`L2]k3YVf>Gj3. $i Ź*yr hMlw|ROUx}]5u|bVC~| O t<@ AJjͧsaʘVC 5Lрx`>f T͊M'G8;y Z. (ih&sUjycʍR !BC`Psi'JW^u5B5S[-UOVC15rD3607'$2x>ѓ ]ẓ)d)_>!i'RDfF3ԟNkU i8 Rx;J%O,cc빓UI OK//5'?uQ)A f(47 89x տ 9T„o\F~[/E% f(X:2`: Z4 $ RyA&' 3۩4\q +%E f/]r)d!nD#j(Q`s 0:x0$3ddm1R SP2j/d"L-.]23%J/hP.  4~z,O6.#6 @CSql>(%41Q$@BVC95†6E rPYA +~:F#.VC0}LJfG)ÉȾ^2. Ardmj@Cd2>AJȘ'䶟 음SE|B;IW歆;SЏ5S8hx@@ !'^QZn&Rݐ.+f zՉ U-4NnwM'/תd2vm\ e;R#?ѦfZ |'R252QCbDA6(n@pA 굛Y[7`̖MqttO*U/gь" vv +_.$ *IC\Fq9e2f5t)|O$-|1v3jPCLؐl6D:93 3F8"-~DRa2@͠{Rzi'g~ʓA&v2 % A.Aq)!S])a.l5ؑ X:(!IdxηK9FR:A`m!3C*H:AJg'ڝ ^ΥJS'А\E SX<‹ uI!V_t!SCj|7(8C@f|zs+tlh۲PR6'꼥=)_ŶnvN.'HC}UsC~jެOCyDzR] B6ܠD eYw Q;Cf4XB6eAQAnM` }Қh ey4ߝP.HChH>!'!P\j(Kk~ʼ?!F!O)G!NK a&Udž?G`A~W0r\|(d |z ;-2~3[C3t]h vܱŻ ,x;Q;0dIHgᢉbC Х?Q$ޟ8O[!/5B ņ% }8O;jҲ֖-C29B0:law +[h-1H_/nvv'Kwa9ƓMnDyя3+^-ߟc exzX̥jH!n[AjŹ SԬdžδL!̀TO7'щ`!<INd?Ic`9 UDe9Y];anv*N<>;$5Ԡ'KO'{{U{2Ԡ^v]6ޠ@ F bC \=8?Z db>f=T~Hʲ ,R|Lj&0Cmdk +bt, Ww'N ow>p|ap4D M Dq|bwG![-5YHA\W5X  W.(0 0C>U|LZcl:Y6Zf Dt[BCy25Y];Qd:pa9&UC Ρ~}_*jǽ-48<qWCŖ~ k2AfW358UlnOdswW5Uժ#T4mP+*PCuQar#Tg9 +B2t4뤆ưue#XvYfIuf9-4Yh8b {ͫ^KKw'c>pHCW4]>?a]ZBrAO<1;YW5QVHԥ5ՠj]c Nc o5 178$`kȀ&CR*Xpe3XbYVJ!9LAW' z RAKw' Lˑs5m'U ( _,_.#af2CbڜwA}[/4|V[h([A>yy;;v ѡe|,5({ҹɺR=v]'( Xja5lH-6l"㛐ꬆ+t?#U̐q 4Σf +R=oY[h([ 1ʛ݉AG 5]ZrAOQVH}|^jw5|YjPRE|5̰5dj:X?L}3Կ#d+`ekW60hPoNS,obqS:oYUNi ȡU,n4.RjB.bjyՐ`q A};`9Gѐ\73 }E?L.46Ho R;lws'N(@.5cy0$jOՐdC `0C|DRQɏGU#fW33Nx-+dyOy˪e;ؑ K;1HCU VHqr=¥ +}Ó3 lP/WÐU5ڕ . `~j a:a#d|AmN)H縥tB,4;=gWe*\I?aB1 +إAQ^5P9Tb``á=' fȪOH& Cf>9aoN- 퉆`! ޝg'v'*ni OQHjXjx! = 47' g +Xh([W' qRU\|w$OXVHybrL-5س;w9BQ#5๡'4"LM> |Bi3x'!HkߜSG }^b}db=oAN6`~BB.+cԠ/k(7(7(Թ0:B]׀fYۦlЦ'#`|jhŔ5 ɦf^H4js",{/DdA]dA;y"x*!  A?2  ︥E/}$h udpI'B(c/xыB6(sb?<=6 /aVZE0u>3d_w3N贈sߜ^{p=}ubb44 ;j}na]˥be,u¼AG(PJ[͆ !"?.[U>HF4C !h0-ŵN~tº@zZh [ 1݉qԥK:gr]j'5֐?FJ> 5Z'sXhSBC1[h7Hok1īؽ4t۟G!ˊB z,7(Rڠ(x5Ć!QRkΆ W NE̠[zCœ9q|s"؜(S=YdDA;i,O]ƖTޠK ,dt|$[5|kD +7p6 +f~2z[x@9 5:%[!rsfɻ 9nhH/4$ ڝ!?:u]j]&|dTf0'Mr 4S{ d 1v'ZOORC8 ,= `A뤽aHy3d%jXZؐpC;E|q'dVOFPUUfS Mzh(N[k+]޽NejA -[J3TA; (dq-dlR=AnP.Xn!u5$jcUPFž.''ہGVU}TB EaKy5Y ӖZ'EzR:,4;54'*O] bK ccbb/E0 !Û!KjH԰>aC8D"'cEǣ#:YU}NpK{29aioNx 7 .-48cNޟ4wIEeAaxR.m j2r3u]u5$jXP%'DkM!Z2zU!5C" 3)ohN[/q6')Hk UcUC!6 +|A nPDaEՐaUdCo/RO{|2z9U io 3i4oN؛)ȻNwnsk2Hgd?'jcw.mPsfA֠!#%OaU\ņ5?旞wfud0>\4'?ݜhPSwwmUׅv'6YjP o]lP.= TïP]놎SІērVU}6639l)N!V'qC;А:9OAH 7-4OU-o k!oz[j;u2= mPXc g8B^oWU_ TP+N[BE.p̰&f_2fp @C byڝHO^j0]&K5 P~bRToWTtCH6ǢcT3"fT- ohڜ {BC| ݉fYț{6(m  +3 AoPT](UC4 HCȫ Nad{}gws:9 W/4ԟ + s2rS + f!uXC|9B]VS7엘wPpLA~U~`, o Á=i[^F/4\~a݉K (ԱKkR^P;`]:x\](\;hէm ?-?SNPP'3Ö 9!0ޜPNX-_ճYhh1 +y>}Sb=vif!e f P5%|թ (lDOԿ VneypBAj6' .HepUyˍ@CIlPBBc 0u9x]VT|hϧx|6|L[@2AN!@C9a_NA^*Wn0dS4xwIB^j!4{>B!ޮ]׀TmtJOOLȲ?fp/u'[͉ 啴&]hh2 +pAdBEj7C:/g(PZwzMMM࣑mff + [d0А89ٜud ]ˤűK3 i] 6(c 0 3l| 2z:lG  b +ҿiⅆYHoœ5aw58^j(^r{5ΧOFޅZ9f/u2- y7 47' 9i .8BC,dAQA!]zc 0uB45!~t:jXo|c?|2r/nߺf(} yR9؜ ,4 w޲K Or2A!ߠp/͐9x)kpJǫ䓗a}LɘAXfp09lYP7ACiK愳9! NAfi!ubºk i,k<}@|c a>|0PG֗GE 88a AӖAwܲB4h. +}2z[C>xi.yWCZjo@E|c ?|0RΨ7I_`[;PtޜЛ h-5. +uk! + +s]R?Ca=y Ɯ +66ï<3| qR Ӗ -5{=w)ok!#ॸ5P@N~ `̬'3aG' 34' {h-k6' h. +sA?Ba C#|I\ {@v>|2X7"Hʼn3РN[ {XhhdBڗ5e1 Ð +qҹPǭ R=Lxaafp.f(.hTÖL 4ĮuRUUMA6\h K YHEpR5;0:Ba5H5|Q×Q?NBnR3;l A *6'S/4hhԐڠP'(#XyBC#Ku]CBiG E D%3cfp/u4Ö{St!yS)`a@44Zj x5G(aH +s]I^ Y"6NSf0[\$['!@9Q!!pq.ս +sҌ5G( +ey] 5QEA?R N+U7hPb b +r…RCK`BtokxP溆@ ŅҶޔf(G{: aKyp 4Ӗ 7' m7(|Yc aHyBkO^"7#U`_Р['!@8muJoN4?n?.5Y e0C:G(K|5|0PJ _6CqA'!HDt!9Qur44^j6(.aH>iyҹA_ `QncTA>8 .u4Öd@CT c 0>B5Kg(l5|5fЏTˣK Ⱕ>8!nt @ڲDhh|ߠp]ڷ5Ð>i*'Bi%j ""PfY _fD N ; 4uJNAPak!}KjH@DD7éÖ *}ys>843p@C M6(s{`R! +q]sɓRa*@DDI͠öz6I\P/N8'xrB 4\*i`s"uEØ g!sK3 )P/K̅UZ Cٶ@ G DD*#3  a RAۖu))t:w5\S5Ð>xY^ .y@ .!@D&6<3'EkaK7ds">6(5 iP8/K U5\}hu`aKhRaKup nhP-S FCHvpo,PX/KՐB>V^^fxkq:l^'MbҽA 4\D!͉K +tP/m]((֘f2)13-' aK }pBA*؜j"v[= i yEy>~'[\ i=Cfw"7ޛ6CyyuuACy288aAgiw‰6ޠ5!#Ku]u5yB?Pj suA̋7۶bhns"&XCt:Ba/^w˫!=5r55-̠6f(/~f f^(ҧ-6'AC +w!1 kpL j ""j35C從 ͥN4Ö{;АD*6(*aHu¿A]/-5V_6f8&jē-34Öuxsbt3kC#'sy|(;Q/P2 oo"H}A}>8! /l91>6ؠH>BSI](mJ 6L?"5>-3`tA78l œ5-'^hH-56(jPD.yT@DD2IN(. $`]]\ N$ [mNVK c .yjQ=Ca,԰_y\ E DD73<2<ҺARUgdAmPaȪy5PF  53A DDY/`VfN "-[ 4L97 iKO ; 3KW "57#3PR:T֣hikfH]Tq2͉>\ YzW)F _G DD nΗ>p*j "QK0:aVCG(PjRö7-!P, {v45+p 'hU.5^WCV፨ha ZhhAG DDsmfء"[GtAv!~䥥k""- ԙ!zy<Ͱ=+PђI3-{);3tW{ɓe5<>נ"7S3<@1jkH3aw2!HU v-2@Do0MF2U sppj "i5կVJfiFEMR6?NF DDy Wʕ*3M o).@D4me.3 #%@D]2Rff\9C3RÿV5Pz[n 'j[ + 5WC6UÕQ7jj "=Y-44?B=^L W暴"Wasiՙ![5UCB"ui^pUL=-55ͨ23@D4n0eWi)Pœ=5tK B DD3 +3, #53t2\Pwrijj "Ea4K" 75rnf-ffah5WaG?qhdo sO osh&0g0堆jxnc5|PçQфa!c55!̰3dgpGrjYf1fijx]D @ DDSa1hV O԰O> 3 a jx@^TÇPtaՙaX5QnQf83~fрj$j&j "D̰3L[/" 3,atuj8og5qHK 7qp7@D40/'6u1C&SÝ԰CG55MfX&SQ 6Cjx +3 }T VAI5|5 __f}3|3Y&jxVPQ~  S(Vgbxcq5ܻR /A DD7N 5nPΨ(&70C>B "i  Wh27Ë0 mP, ? mB (քfX o 9PQf01Cf@DWAfEC3|3PjBB @ DD7>fj@ DDvmi~pAPYjkj5lL naw@D4AmpfXFT j_s5-3,75p̰Pj 94>1"fxfXv5QMh֘a̰TnH5>4+"fxe`N \K"^ !V}"eonK3\OjW5f fIi5#j@ D4q*Wjxj " +pfj@ Dg9ͰÖl&j@ Dc7p%0Pj 2ó1 +C rk3|2iff}5Q^ OfxfXM5QNa̐s5Q>l hp 0Pj \vNvaѡ@Dy PPf3j@ D4} 56ai@DS0\B 3`PMf s +5"Ř 3\3,+Ԁh0f[54eoݷ̰k33lpM K +5"phs3/a`UP_&f8 O dPf s 5"Qt5јcaT5xa0Pj Z01C iz3;m{f 3Pfj8/j@ DQ4HP p.ffX`5 Gp-̰Pj a+ԀhbKauP pAp0Pj aq@D&3\3%Ԁhf֘ᢘa%@D33j@ Ds3,6Ԁ0fXp5Qa̰Pj a%Ԁ0fX|5Q/- 7 5"%ژPj [.WecPm<̰ fC 6 +3`Pmf +5"|$@}Pu 3`ՅPu +3`Pu3$fXY5Q0fXi5Qg G/a}@D aš@D- aա@D a@D a@D Pj &a@P53`*C j d5Qe35"3`B egG2ÿaP%Z.(j@ D 3` +B "a@Pj p>@Pj ",j@P9a@Pj "+̀"ԀHv  5" 5?cP ffB f1?b*C fi`?ԀVf 0ԀVf 8ԀVf "ԀVf *ԀVf 2ԀVf :ԀVf !ԀVf )ԀVf 1ԀVf 9ԀVf A5(̀hPj ZM3І@0fC ha@=P + z 5Ň0j@ D 3`-Ԁf c5-8̀Pj Zl3Pϡ@0fC ha@P  5Ņ0 j@ D 3f8/fB hQa@Pт  5ń0 j@ D 343d B ha@#P F 5ه0j@ D33`-Ԁff 4b58̀hPj m3ȡ@40fC ha@P & 5م0Mj@ D3 3`,Ԁff 4a!< & 5ل0Mj@ D3 3`<Ԁff A5 ̀(Pj >̀(Pj <̀(Pj :̀(P +5l 2kj8 5ef ]5ef a5ef e5ef i5ef mB  25 5l 25L 5, fj@ D0͢᧨(0f5|55̀h6@4i3ЌZff 4ϠY0,Ԁ& +3`]5Mf 4Pj ̀h@4z3LC h0fنPѨa@3n5jg3`u`Q0fPHa@oj%j <̀h@4B3"B h0fPa@iIjJ55f Pj 0̀hQ@4X3šND D0-}(0f<5|5Mf UËP\ @4z3bQPQna@ njxPQQ~a@njpC5bs5D0_D0-S(0fŗ;6 +3`ZAR9c3*E D0Y5|5Mf Vþ] Vj8Q{QQ61ҚZ j5 f DP os-@PC>* D ,O5̀z,o5S0f K OI5|5U0Qϡ@ 3`@ 1jդ'pM@5Ùg@D0ņ1e@T~^1f pnp7@4D3 jjv訆wTCᗘʆSÕpG@4D3 Yjxچ0Ѱ k4UcpPR D DE3 ]&jxVPQ2+h@K3`1W 0jpB N%I3$j]B ;Mf1ښ@ D&70z^ t#ۘW6h27Ë0B pf f h5< ͘h @slb3|P혁he +$p @qdn_44Ç1zC 4ff pi_ jضvR(Z[3uZ3<3-p\ Z}mpf D=RPlp,f Zg5\ _1heG4Ï bT GZg9ᝮ^j@ c 1Qf Wa;@ԦLJ@rRN^VûQe6hM 5<5 bm`֋.E wA D5u6 33&kE԰=j i36nߴj'j J43ep*5\55h|3jMpvff }a@hfǖj@ 4MYx o  D5ͰǖUi;ff ZUI^h@cZ3ܬ.fj@ 4nY5fx8f "Q5+j@ Աl*3<3Qj@ 4^ DԲj. *&fxc{a"*B i\3| 3@c D5Ԁh7ïff !C 3`P [fx^[3\35Ԁh3,3U5p dkg64Í1C *O3j / D)Ԁhc'c"jj@ 4DwiS5Hj85ЌZno35\5Mn:f83Q_@6;3(p_@Du@}6>3qZQ C Sw .fx(f A F 427 \@DPS6f8# D4H5PMlDhTnԄfh D_ϵj$j5>4+"fxe`"jjT#Q4̀SZ P69n.p=i]՘2ʲPCPͳQqp DPumf2íf2f Ԁ[9ͰÖl&(j@ ԥUff X5Pr7l@DPm3|2iff Pjv Ofxf B ڄ0њC ^2à 3;nf1%0@MvNv65jVf83Ѩ@M c"1Ԁa@DB D5Pu3 +5 +3`"2@c[$p@DmB Ra@Dn5PͰvmfmҘP 67ff B 21qfx +f 1C 0f x5(@DPca +52a@DU@ea +3\3F5SyQjX|ӛi33N5*(pw@DP wb a"jj@ 4{3l1õ0 P 5មF5U3\ +3Q԰`b`"Pj ZPJ[.PjXe 3 kpQ@DP +[nhPjX]3QPjXY3QPjXU3԰5~fj@ 3`"0ԀV҂pS@DP*ZhPjXA+0p~@DP⛇v D5,<̀PjXt3Q԰c'a"C5,6̀PjXh3Q԰0K2`"5Ԁf D4H5,Q3 f C aaa@DPâ  50 j@ 3`"8Ԁf D4x5,"̀hPjX@3(00f B aa@DPì F 5 hPjm+61Mj@ 3 3`"=Ԁff D4A50p>@DSP DPjY3d00f C aFo4?a"9ԀfjpZ33f IB a& ff ńP, fG@DP hyԐ}3Q&Ԑy3Q6Ԑu3QFԐq3QVԐm3QfԐi3QvԐe3QԐa3QԐ]3QԐY3QԐU3QơԐQ3Q֡ԐM3QԐI3Q3`"A5dP0Mj@ 0$Ԁ&3`"M5Lf D4Pj0̀hV +5 3`"Y`æU\̀(V"j_z.0ej@  +5 ga" C a0Chb"I5f D4Pj/̀hޡFj† j@ TA`2Qơ0F3B a0f et5t05E~0f yPà gb"C a0f E5|^[!0f z3`"Z\R9Z G  ho)3|3 "jgZ WJÆd߭(n-3`@DهPCa@DKmuj}75EѴ[pg>Fhj%j{@D]`f DV?j8;PC󣗨);ԃ~ 5jvjjnf80ß0Q-I _A S  j_) Z  f0tГjjC?! k`"N ~C5t9zv6491340 Z~᫡ VoHg~5÷1QU 뤆n(h h`1-[ ?% -30o1Zh(ݚhm720[ ; +0 DDhjxP?aOi5|S~nwRC6lXjPyԲ30tG oVr- +Sk3l {f6ç>b"ZNjQïbjhta[}nfB oWfx3f "|MøWJEQQ等5~e#i0Q-C u-5l5T?DQ +`C2C[3>nnja"aTפG/3G/k(Ά[k &|3[fkb"jxfjhpr݋ M*𳟹ZfZ DDSN5Qx^6ޢX,ȱћ@D4QPjʮ9zval%CqN@D4yyaz5~8*x~>7hQcjxe?j])][ cC꿲 _wpf "ʮ=NUjFL !m58 ĆdhnySOf7bb"!>^/<_:zb}!62x +{ Pf8^i6jxR[;!8Ѐ 5[ %aS +3|\=(fo#5|QCrCņŲ!ak"rlB^鴁ބ&ofj8R \˦ Mf͆&dښH38G-͈>e 33ԜpXT 'jV÷,5!8DQ9jal@D3˾N DDS}5|Q÷boӾ_k*-6, P5G cѶ @D4a6U5Oqpaņ꿠n8CJ| +4> O DD45Q-B -B <ӟjj†EEņ9-lMĎZ&fxW /2ޘ(FQu j8#>!TvE0| Y_bf]f]ϰeJ3|ӧ|0GK3W- ob`"["G/8d`Cb<О e Sؖ>tژ h6Vÿ7UÍj^mN,Րz2~"l(ҋ (tCͿp-2C|kL^ Gq!:rW˪B SC -6Ɔdh̐gZ|cfxMF.W5챥ޠpLwH5|بzB]lhPdžlPYO[ul¿:1dž0Í0p 9pwoZ Cwk]:!7+VzAoMF 5 eK301^e3ÿc"娆g5Q竪Q - y_.A ք;iM|߱M|BB 8jx}ty͓!=oQx ;zeCrhd,3&q!fc]3"jǗfx6=~W@D4]V@ /tpAÏj8TRZ_ -`j ܰj udh53+U o-p2 3<3m;a"L OjxQj6x(kžLQ ƆvhT,2ȐڙDj\\]xm7|Ё^7Ãl3ܡ0í0$yjW^R'qa}"6PElĆ.nh_8wbg"̠&q؄s=Dqų7fx0Ó1Q姆gjx{͇V<_e]d7Yl(*b{Ca*PK2C5"&+"OafxIfh2R5<_a?W 5OE|>Ea/68DV6T!7DLT/3X[؄=~J;Ձr.5XB jxP+G/5O3lQ j"m!憩N 25?6QtgWGZfOhC }l{a8zCOQ-bC| Y!rn32$v&2ք5Z:Mg-x+^,la'> DD֣.E -PK Oj]a_W ! +u( @d0> e5mM#α yR_ ;b"\G  5OeWJ[bCd"rnd.3ToMcꨥ} znB﷯0 O DD՗.Y 0jYaW]5XCG/8}5[jY^`_-fxw6ý=.l|5U +5<,I^l! ц*64tàrC"C ֙eqr<6!PTW:f(u+3<3Ý1QM;F؝v~“" /l0G/87ؠ^:b/ņp!ʆ`qC !k4C2;2 j2vR_) + spk@Dg#zR 7၅A?Dy^C3ؠ!1gڤCOt8}:2n{!5QP3H}l8qlPUΠF cG-3<0#f40QfǗjPбW[(p'V2ܚ0 h؄:j0ã 3<3ͮp5Gpy^A?z^Y(U`ڢR .t(٦nCr } 3?Z;eԄ:i<6QtROTՙ&(߆TCa;jQ}͓BCڃ - +{Qsf"Ұn!6C - +"YXeÝeyR>Pe3&£W;ܽ W DD5.# (\5Ba{K jp^W/{k¹ZlQD(!q9CkT!C8`!3XfnM jRPG-+Sض"̰1e@DYéJ-Iݥh[ +`'ï2x d /tR[8Cy ,MG-/VI3\3\jtkj|s9}Ҽ_%^m 6X[j2ؠ"͆;l,7xnppv!j Ηs q1zAA?a3[fPք? G ͱ znfjV{͓}CZ Eb٣dڥp\7TCy_Ͼ0Đؗɐޙ-d|kB)G c&,3ܨ4õC3\3@j.pmG/!K~476-UC: jpQ԰!uK!9W< E4sf"PL@ք~4&&n_>Qfdjp.^CrR)nl(U<|(h8HaCb!F"vhE/`3fH-3w@ H53@H}Ҿ\-ƥ1 I ׵ՠ/lЇ(KrRؠ(EOr<|i= +}RODJ6]pҡŸc}*[d0d8!f0;jAI!oa Q8rpCN☁h6F>_U^)m.lp^ O^9E!ņHbZlpR=`v)nACܟl/`@ ޾D9<,^ Ge9oMq`R3X@ʧ.fؐj(y/lQ5rB_!ņ5 +3i(,6ȑHqKnSxnP \9:z.0xb%ľ~,-2Dv&dqZfP-5gZ3(3e.Ӏj\)^`Q- +}S9.6DHo!KRm + C PbsosAx!C\ O/}2 5͠Z pkgMzy f "w}[j(brHyaw"6PnQbCq ڣ(zJAR [6ҀhArB 11أ *$ĭ r,' +&:6\]fhjC6裗nQbCqgC/>eAD]Z7p`C*g/cqxAB "e!rfB @W@CjAN@F&8Cpl ,p-3\3ͳp@ 56C8llQKPPF(r"g^n0nP 6rt:'sf *Ġ} 9YJ2;%dq>4AK9lMX j96!Z3`"7zR)- +wR/6;@ܣx{ r j.,88puDwͅ >bp%,2 3Q4a/3-53HB>6!0Å1@ bgBC: Άr RQCQlK"nH("| CT jAKdg&ʝ DPN@:[q1^πQg5?TjbR>z)!yڢ!yAd9)(wVADz y +kC@"Ԃ  11fA2{dw&K2 &qo\ +3ͻ>z^ؠQ`EaC/b{⮧ '3`6E8,9:<= a+҂Ņ 0g%1؋ b_B=K?΄xiBo_qRN@[8=ZW:p DD75ğ +^C85PnQb4{⮧$>-٠w)r٦nPJ9tPv5 +Z l/0%@ q `M?dmNbg/MCjAN@[c8T&Qh rHV3i`^-rYlw6=)(ʻ +5T3z\nZnܠ$"rtx0z#7?W?Oh)ܖ(Cy/`?K˫2C9lM <6qgk"%f "m`C\ C8l((yHA<"9򮧷:=i6`v)tM9-8pp POϒZ0\( 0K --Ծ}ӇGyiڙ( 2C9)/tR[c8C986^QSs\);Da!ulQP D= +5`ЛL}lS7Hr!*Ai_F#s~! Y`0K 䶄^dPt%a3! bԥ? `y\bA,2}rApLMA 3g& ePN@oMX[ 9 t򞵼\f DD5PCJi9D!n EE9.6WE1J1YWD)Hn0 6kBM88pr0tvzZZ(`{A/0X`K lAKQu& ΄̰\f0֩ 53\ DD9RQ86$!}c}BCņg zm|9Ia9!% +Z  J.X^.1b"C/ep .s mN΄W@e5.tr&8ԯMG-SWG+3+f "_r8?ؠ([;l1 +k ܣ(zR6X/.Ēتp$4BDxHhAqAy!!XdpX&ñ mNřbgb߽K2QN@&IK= otG SW:M`"ַkR`CE!.z!bî..j RQ5`v)rMaSJ?GF %b^`K bP%ǐ fv&exkBnMȓ r!ҽH@D4zUCK}S9ؠ^(<=ӗEq멼"R~7).5ZpPpAAD2CO5ZP\^p|1m`~T,c9P(v&M@ʭ uRpFt DD3?56vHycCEE!OQ9YQ(h:Haإ(RkBSH7 !' ,ZP\`|1X V{Ye9argBW@e105qOkŒ3T DDl58(b Sŝ-b,(shCqE9HA.7n0C F  DJ r:b2c Ar4ZL ϖW@egR'- 7!slJ'@DzVu2|¹!آbx,(hLARyS9`) +_!b_  C {!* %RdG&ʛaD3! fAN@ʷ&SIp;j]s5<] R9Dg/-9ikEqB6HucܥpB7_ Pҡԃl,8\^`[ '~j\dd(aD3! 25Y^䟴@Ʈg DD˫+ qHoA[wAF"= += '"lPrSR g `qA{lIK r:.Q.2}d(0Cqfؙ fA' }2g𮎾@J'@D46TCe0,6EQ\T^ (@dGQ0 6M +K.7m +醓B83R>J;(=h?ppMa 0M _ 긄XdPI2G=PLX 2&քDDx=Ch@D4U{"r;}詼!PFQ D>M Dz .YnPF -R!%7m-H.h/3 Ns Z sb 0CqSqfBL 2;NMGG dY" IH8ֽ2 37c31" +`PHoq ? xss{~#E;Uouꮏ9SM  7-E}wȅ[EAECbC60)="6Tِu)LASFEj"cs_98ޔ`@ C.].XJ.$2z$CؙA3!a H[f& ͪ ߚ@  7=VCZD!k-]4I/m!| DRFS\o ԪT  !oXZp\^(PM2"Cޗhdu&dҕh6g 8 Ae/5^㐵* +ŗTl="GGDd\Hb+7nHnT88HAtP;",! + +Sb*iK"C?hD2 3D [@2C3ZqAvd/l" 6Z2/}_Daox6dCڦP7\$7*28H!Ё@x> $);Q!bA\0^P0c(1Z '\%~M@K&# 3К Le!M@VwgqlDm%̀ r2] qrf!|eQ^O4'"y%7BnTdp98:;(6j,-0%Zؕ`1/a9h13 LoH&2Y5F ݲ>3|f@9@ ن u5^ji%q zFS KaxA*v <!*C" + *0lChKp֗Hd,yh7'Z3AqoZ4 -= vr`K'AP54!`CE!/@DƁԣ{=DdbwlB kLьo?, 4M  2I6wsJ eeJKn;0 N[ C vR*- +R gC\}izq'"y_I!lH8p28FIC](G~_\y!$R!5C6P#_2|@qv&Ze<ʕ=#0 ȍD5 ,4C`C_<{S"2~e\7]"M KP!!A|`@|1 + + A \] 2 `CU E;cf9Ig"~Sf&#c1AzgP "`CE(6e2_ģ `C֥rC*2aR'AIl @%ؔs ! J 3ݜފ߁-4M Ek"gh,K-aAз٢hxDrz],>lA i&!FCCCCEK)+"i#  4@%C1 [.C2fNqgI;MTf ;C6Mڞf@9D "4_EZfZl_}gbz҉HYnn4`  rHt`;D=D>D?DkR?)T iJĵ,dm -2TAA8Ȼ9΄|D 8`A=08Y(dF}.6|/Ev 4ސ R!!A|~0I'BirA +  ڔ]$rCCo2xQvs2%܆Ní ;3 [zɃ EEQhLD`MaaC҃"!G=[!`!hA  ԓwd2Peuhۙh̆Nieڝa$̀ r3sFOܢhlzz+mT686rClSX7m`Au*$]wbB0p!6%xAZdG_R2ȦH%&d>9u%̀ r2U E[blד[H!lx/g)7p¹{ Tp(@rnECAaG,20hS"ClK"C x3'L:&z' JK;3 LQØqȴҴ(^OM6 MRppprCA@z > #:@VX`-J0hSCm/|ӓ-仩 ;):3ԗM  7>ܱ֢,6 >ĆTn6EiTЄC Bb| & +N ʅ IH'U Ԗ/2dHK&[3dr$̀ rc3Q(Eå Ŧ ؐ M!} +^O!TVE)H!!A +C7+,:.P?B`* *1Z0Ld"L d֚An{z0jeEVQ!k{6=Ql7A + qp 9HukA T`0` ɉO eM@VZ ǹ r33V =K艿Yl;ېtب`@5Hdaaǒbm 7}, &|v eX3,AuUCkҢyHSl(PRhTpNE8$9dtvx =Dx‚`ӂ{!{ a?|bh*dH?*D& ښ7 3 ܸLRCmر!oQ QLbC*76E)805C` ht BBԂp `|%\ ܖ"C/@jg"2[h Dmf@])XD18`ZY!JbrCv +*8x89CGCDgB`*/x/0h㯇G'nK"C//(Ȑ:f JA7tҚAnIPCE=Պ gC>Y6v) 7BRtx| ? #L54T , R0h*Pe!C1BKmM& ӗM  7#jQjQT (E6bRH!)r7uԨNET8lA!Q \B*00hWWZ1ĶL_ehؚ!@ jkK-Anoz0nѢ0Cf7 Dd K!Ӻ!6*5-9pAx =HQ + + Q \^^ +)1NN -Eӗӏo~o,0D{f@rޢyH[l "@цjCR qXpN!::;<X&xPAq <bS",\dhM?fd(p&q@"btKDd Kۦ  BBh@~B + +.t\P/hG"$'M j }"%܆і 3!# ՕDvbznA'"#y"M>Á#;8A \xMV \_Ha`)Xb`\dо]0Q!f΄+3hM  78l^@ <ÆKaSxCSp`8UɁkBCCЃ!{)R> + V Z^5[` +Cb%6N\dY0Q̠ 3 BZkf@A8nQD@*"^}7bA \hA%V"%֏nːȠft&&2Cc%̀ r3M -z D v; MasҨpFCB:ģH + + + Q T]BDžT`AK qD.jK"~&3 Lh)3 3`APk(x K Ԧ0nHiTX8<8@tpvxz~ @$D`BBĂjr0h! f!n]!L 3Wfí AVgPLm0lWؐܠm +Fw* Rѡ!!@~BND@("# + G*`H%Z]"!O4031̀ b3E,6T"hARiS7zԨh`x= 8t1W2T R^BBM1pSVW{1"eHdL?*eAWņԣMDVE7h=7*h2RPȁjC>([!`AB ܔՕb[/!ӏ824;`A[Ij.6H:ڐvLK)Ka Ҧ +.8Tr0tv`<Jҵ跙 + + )/T`%Z]2` 2ɐ&t&`AddWC9zlHK)K ҦHn>pppP9P!! h?/TVXP-D.P?PbpEKG b‘!fe&A9BQ'"-!Rr) +7:@rCGCPDT[|`ཐAK V4@m 7E;8 Ce&A9D 6 D`@m +G7$8CC9D:$;<,_*z< +L -0x0𖏡`x-2(~DAa#`AS8GQND٠ ܥrC nHpq 8 E@C!A !1:qV ˅T_)1bm _d0 d(2L+3  H1 9>/ ڥ^Y!C'H@|HG` ה(mZa40L̀ %j.6l:`xqC`fHTst`;<"7^78pB`v< Fx+,$-D.8/P̞ N /aY6 32 r aDŒ6ԶmHl7 m8Cspt`;HQDt*BBB bhF6̀2 r9Pm60K1J!C~Q^'*`@a`0%A1 3  Wa2*3Pq+8p*9D9tvP<*ϙkpT A  P+2h_b2:(3  fZ=l] +Snpnp +-8X8H!r:;(HM LT +X,-hy!zA + %%ӔSdHӏ劉cNAņ~6WY.E^n6lTX8ЌA 1>6~ \bЦ%"CKL$: Egư EA yv*:8HAkboS )0bЦDC TU2fAh6H(7 +S!*r0tP;H%@x?!X-puA^/1خoK"%(C1 ÞeAC ՉȂ fl"lB:ҪP9t;HJW+D "^`7%bhAA?@džbR"sC*8U%'ځo9BzA RSN>6` :OGAg G".E^nh j *;aA z!tbpmja aA bC)7HBܐo*ԭ0t0x =0.6rZ Z\HB{DU fD/1 (3  }{nVnnuJ,Cr])Y ./^P0HOBb !̀  jؗ yAnP7iTT5l1Gȭj‚hpP Q nݗk,kdػ32  G'(l]jºS U8VHՁ |~p'7g!,X-Hy-11%GA9,cCm)EQnw|с ~H7&+T [`{S\+Qè>d@AP6K.EQnvCjCD irx)0|ZbdeAAKʔbX6 n!^pHp0rnہ|`?d(bƳ$,, 1IۗL?  `)7ܐ +8pʁz`>B&7ɄՂx! =6PoKE>2K&t&`Axilp] QQ["Gd¤ЁdB'iK2T0id@AIlj`6ԖR u7F)989QkV̡/*0H Z].X/x0C\3  N# ow) f!S *CnFo +๐{.1db*} ;$  Uer6t)0ӨAGD=Hg H *`0%+;*2TqAyrlrCJ¡*DhփÁI6VX -$.8/4ᓭATdKL$̀ \\Z>UnhNփ!CD#Xg  +/ Az2  Ga@ U8rtvpx=@d8I<)@\^**WdKt&A(5Lbx7CEloI`6&dAT6+0]”Ll eXZ0\^(%a1  go6 zݐ#E*HAQqsc!jp!B C.=  ¥i'6E ?\!CAb Vr&ƂBB |aX G#̀ \ngC0䆬S#s98:!Zq70X M0 2  *!+7 CQr0r`:#>0BB m0UdA뒑l_nh H'CfŃC[c)N Ɗ 2  U4 !rt;$=x@dq2cL!(1 aB_d@A^ 57ˡF 1'1 0Pb`1@A:f6X tHxHzp~słhsz%/Qm AV9n CPŃÄ3h p\ f@A^|V}n*CCg(q{ 1L+2  ȵHոrÐPaJ9 +,(2/DbA lꆬPC&CCiqdB~0k%0/2  /^e74A`1T(sa$zŰod@A^}x-7ЂC!CC!GT=] Mm Aٛ n( +M8$9$:;dzh +b ~(WB 02  /v&a7pP9`P`,-$.Fr@  rIP +>L?V^2  #0 C9Q?YݝU @AƦ#m0FڂdB F ^xbAk -7TPCƥ<ӝ^Ð@Aej!sCQaPC-IYw׹0 AA`CF!CaB 9B cPȀ  |Mu(9vÄ6Ȁ \ppr(PhE4Z^Ā  }_ppprPaR;js{!1  ^l(8dpr8E2Bƅ aP  rr7pѡ~>Kr.^(1  da8r(PhE޸ aO1  ȍȂC R: adh0@  m6-8C1tݖ`AېPCEu:Դ*^hb@A1SPCՇQB 2  *>[ná.!<%{?΃1  0>#p(C}]  P7o1xCj?/UAj3M91~}~ p?(Ay2c=r`w{>~AgO+b@AcÁ__AQ9sBptկ+ SZruN\  7<ؾ\  %WHCAۗ~A606W:! Bj_AA\5\  H_Z +!W  2>  ,  2-  '                                wɣ~KwٗܽAwɗKw]{Ϟw?~᳏N>.<9yw?.;;䏅x/ݙ;? o~2{룗ӳln֛l;%ߢvn7[,W-].6rd>_̻Cff;?-Nٜ vwٖӅ&]f>|v7gՊNOwn\mNS7n6;۞f#}u^N)=zgvGvO#gln묻[zwfen}Zvfbtċ;t=z}ޭjgYt{tŊ^cY,N|y:k].Nl{6_w[ǫ?n:]n]s-fnf{j0]fN;[/3kV5;dJ;<{λ|޽{r=}mD{~Tߥx-t?w?ijjC/|w=ٹ}je|K}{;3A݋vlx̙_o6mi/Yl ~?WgK3讘ow?轱ֽ/|~?6{{X{?y?if|Yyt_v3߅_crY.ςX77"{;ykO^mfy6nwEȗٲ?[[{jnw&l\lOvҽzal؄?-7~Sg[Gj՝hݽKvnޕv;^]}lVlylNwݍ|3;yͻ;:mWa>wڝ1=oܿҝtgw+'oFbwD}jv#z'BӝPtpE| />}e.9?ݭ/D@n KQPsPwo$< Ր=CDݯ5QWEmsuQw%(pe?H.EHw#*Jn{N2tyH-} :^Ͽ|g7 UwU~gR/{Ox[:)8|ӷ{}<>}]*<[{v183oWyƛ& ˞=~'>x$WN^J|[y>o=GQ'{bT{G^}~W=|^O>y]=?}v~/?p#ݻ?|J +endstream endobj 23 0 obj [/ICCBased 35 0 R] endobj 7 0 obj [6 0 R 5 0 R] endobj 72 0 obj <> endobj xref +0 73 +0000000000 65535 f +0000000016 00000 n +0000000156 00000 n +0000040650 00000 n +0000000000 00000 f +0000844047 00000 n +0000844117 00000 n +0001322677 00000 n +0000040701 00000 n +0000041226 00000 n +0000042166 00000 n +0000844653 00000 n +0000271018 00000 n +0000844424 00000 n +0000844540 00000 n +0000842266 00000 n +0000842409 00000 n +0000842552 00000 n +0000842695 00000 n +0000842838 00000 n +0000043951 00000 n +0000044252 00000 n +0000042228 00000 n +0001322642 00000 n +0000043389 00000 n +0000043437 00000 n +0000476551 00000 n +0000068843 00000 n +0000671044 00000 n +0000476614 00000 n +0000044555 00000 n +0000273757 00000 n +0000044618 00000 n +0000068886 00000 n +0000271053 00000 n +0000271108 00000 n +0000273871 00000 n +0000273934 00000 n +0000273964 00000 n +0000274234 00000 n +0000476439 00000 n +0000274307 00000 n +0000500370 00000 n +0000671158 00000 n +0000671221 00000 n +0000671251 00000 n +0000671519 00000 n +0000671592 00000 n +0000843835 00000 n +0000843623 00000 n +0000843411 00000 n +0000843196 00000 n +0000842981 00000 n +0000843076 00000 n +0000843291 00000 n +0000843506 00000 n +0000843718 00000 n +0000843930 00000 n +0000844308 00000 n +0000844339 00000 n +0000844192 00000 n +0000844223 00000 n +0000844727 00000 n +0000845033 00000 n +0000846253 00000 n +0000864797 00000 n +0000930386 00000 n +0000995975 00000 n +0001061564 00000 n +0001127153 00000 n +0001192742 00000 n +0001258331 00000 n +0001322706 00000 n +trailer +<<2FEA11F94FCC9F46A389205296CF4D9C>]>> +startxref +1322895 +%%EOF diff --git a/media/icon.png b/media/icon.png new file mode 100644 index 0000000..8b9c6dd Binary files /dev/null and b/media/icon.png differ diff --git a/media/icon_old.png b/media/icon_old.png new file mode 100644 index 0000000..352f642 Binary files /dev/null and b/media/icon_old.png differ diff --git a/media/main.webp b/media/main.webp new file mode 100644 index 0000000..d21721c Binary files /dev/null and b/media/main.webp differ diff --git a/media/socialicon.png b/media/socialicon.png new file mode 100644 index 0000000..8b9c6dd Binary files /dev/null and b/media/socialicon.png differ diff --git a/media/store.png b/media/store.png new file mode 100644 index 0000000..8b9c6dd Binary files /dev/null and b/media/store.png differ diff --git a/media/supported-managers.svg b/media/supported-managers.svg new file mode 100644 index 0000000..e218480 --- /dev/null +++ b/media/supported-managers.svg @@ -0,0 +1,178 @@ + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
compatibility chartWINGETSCOOPCHOCONPMPIP.net toolPWSH 5pwsh 7CARGOVCPKG
INSTALL AS ADMINISTRATOR
SKIP INTEGRITY CHECKS
INTERACTIVE INSTALLATION
CHOOSE VERSION TO INSTALL
PRERELEASE VERSIONS☑️☑️
CHANGE INSTALL ARCHITECTURE☑️
CHANGE INSTALL SCOPE⚠️☑️
CHANGE INSTALL LOCATION⚠️
CUSTOM SOURCES/INDEXES☑️
DOWNLOAD INSTALLER⚠️
SUPPORTED SINCE VERSION0.1.00.1.01.6.02.0.02.0.02.1.02.2.03.1.13.1.23.1.4
+
+
+
+
diff --git a/package/chocolatey/unigetui/deploy.template.bat b/package/chocolatey/unigetui/deploy.template.bat new file mode 100644 index 0000000..d169beb --- /dev/null +++ b/package/chocolatey/unigetui/deploy.template.bat @@ -0,0 +1,2 @@ +@echo on +cmd /k cpush "unigetui.$VAR1$.nupkg" diff --git a/package/chocolatey/unigetui/tools/chocolateyInstall.template.ps1 b/package/chocolatey/unigetui/tools/chocolateyInstall.template.ps1 new file mode 100644 index 0000000..39f59e1 --- /dev/null +++ b/package/chocolatey/unigetui/tools/chocolateyInstall.template.ps1 @@ -0,0 +1,16 @@ +$ErrorActionPreference = 'Stop' + +$PackageName = 'unigetui' +$Url = 'https://cdn.devolutions.net/download/Devolutions.UniGetUI.win-x64.$VAR1$.exe' + +$PackageArgs = @{ + packageName = $PackageName + url = $Url + fileType = 'exe' + silentArgs = '/VERYSILENT /SUPPRESSMSGBOXES /NORESTART /SP- /NoEdgeWebView /NoVCRedist /NoChocolatey /EnableSystemChocolatey /NoAutoStart' + validExitCodes= @(0, 3010, 1641) + checksum = '$VAR2$' + checksumType = 'sha256' +} + +Install-ChocolateyPackage @PackageArgs diff --git a/package/chocolatey/unigetui/tools/chocolateyUninstall.ps1 b/package/chocolatey/unigetui/tools/chocolateyUninstall.ps1 new file mode 100644 index 0000000..0ee3a77 --- /dev/null +++ b/package/chocolatey/unigetui/tools/chocolateyUninstall.ps1 @@ -0,0 +1,25 @@ +$ErrorActionPreference = 'Stop' + +$PackageArgs = @{ + packageName = $env:ChocolateyPackageName + softwareName = 'unigetui*' + fileType = 'exe' + silentArgs = '/VERYSILENT /SUPPRESSMSGBOXES /NORESTART /SP-' + validExitCodes= @(0, 3010, 1605, 1614, 1641) +} + +[array]$Key = Get-UninstallRegistryKey -SoftwareName $PackageArgs['softwareName'] + +if ($Key.Count -eq 1) { + $Key | % { + $PackageArgs['file'] = "$($_.UninstallString)" + Uninstall-ChocolateyPackage @PackageArgs + } +} elseif ($Key.Count -eq 0) { + Write-Warning "$($PackageArgs['packageName']) has already been uninstalled by other means." +} elseif ($Key.Count -gt 1) { + Write-Warning "$($Key.Count) matches found!" + Write-Warning "To prevent accidental data loss, no programs will be uninstalled." + Write-Warning "Please alert package maintainer the following keys were matched:" + $Key | % { Write-Warning "- $($_.DisplayName)" } +} diff --git a/package/chocolatey/unigetui/unigetui.template.nuspec b/package/chocolatey/unigetui/unigetui.template.nuspec new file mode 100644 index 0000000..e6ddfec --- /dev/null +++ b/package/chocolatey/unigetui/unigetui.template.nuspec @@ -0,0 +1,23 @@ + + + + unigetui + UniGetUI + $VAR1$ + Devolutions Inc. + Devolutions Inc. +

An intuitive GUI to discover, install, update, and uninstall packages from WinGet, Scoop, Chocolatey, npm, Pip, and more. + The main goal of this project is to create an intuitive GUI for the most common CLI package managers for Windows 10 and Windows 11, such as WinGet, Scoop, Chocolatey, npm, Pip, .NET Tool, PowerShell Gallery and Cargo. + https://devolutions.net/unigetui/ + unigetui wingetui cli package-manager windows-10 windows-11 scoop winget chocolatey npm pip dotnet-tool dotnet windows package-manager-interface gui powershell powershell-ui gallery devolutions + Copyright © 2006-2026 + https://devolutions.net/unigetui/release-notes/ + https://github.com/Devolutions/UniGetUI/blob/HEAD/LICENSE + false + https://cdnweb.devolutions.net/web/common/logos/img-devolutions-unigetui-white.svg + + + + + +
diff --git a/scripts/BuildNumber b/scripts/BuildNumber new file mode 100644 index 0000000..3fbd193 --- /dev/null +++ b/scripts/BuildNumber @@ -0,0 +1 @@ +106 \ No newline at end of file diff --git a/scripts/build-chocolatey-package.ps1 b/scripts/build-chocolatey-package.ps1 new file mode 100644 index 0000000..5be3057 --- /dev/null +++ b/scripts/build-chocolatey-package.ps1 @@ -0,0 +1,301 @@ +#!/usr/bin/env pwsh +<# +.SYNOPSIS + Builds a local UniGetUI Chocolatey package. + +.DESCRIPTION + Reproduces the Chocolatey packaging portion of Devolutions/release-notes CI. + By default it sources the installer and checksum from GitHub Releases instead + of OneDrive. It can also build a fresh local x64 installer from the current + checkout and embed that installer into the nupkg for local test-environment + debugging. + +.PARAMETER Version + UniGetUI version to package, for example 2026.1.6. If omitted, the latest + GitHub release is used. + +.PARAMETER OutputPath + Directory where the downloaded assets, generated package files, and final + .nupkg are written. Default: ./output/chocolatey + +.PARAMETER BuildLocalInstaller + Build a fresh local x64 installer from the current checkout and package that + installer into the nupkg instead of using a GitHub release asset. + +.PARAMETER InstallerPath + Use an existing local installer file instead of downloading from GitHub. + The installer is embedded into the generated nupkg. + +.PARAMETER SkipLocalBuildTests + When BuildLocalInstaller is set, skip running tests during the local build. + +.EXAMPLE + ./scripts/build-chocolatey-package.ps1 + +.EXAMPLE + ./scripts/build-chocolatey-package.ps1 -Version 2026.1.6 + +.EXAMPLE + ./scripts/build-chocolatey-package.ps1 -BuildLocalInstaller -Version 2026.1.6 -SkipLocalBuildTests +#> + +[CmdletBinding()] +param( + [string] $Version, + [string] $OutputPath = (Join-Path $PSScriptRoot ".." "output" "chocolatey"), + [switch] $BuildLocalInstaller, + [string] $InstallerPath, + [switch] $SkipLocalBuildTests +) + +$ErrorActionPreference = 'Stop' + +$RepoRoot = (Resolve-Path (Join-Path $PSScriptRoot "..")).Path +$TemplateDir = Join-Path $RepoRoot "package" "chocolatey" "unigetui" +$OutputPath = [System.IO.Path]::GetFullPath($OutputPath) +$DownloadDir = Join-Path $OutputPath "downloads" +$StagingRoot = Join-Path $OutputPath "staging" +$StagingDir = Join-Path $StagingRoot "unigetui" + +function Invoke-GitHubApi { + param( + [Parameter(Mandatory)] + [string] $Uri + ) + + $headers = @{ + 'Accept' = 'application/vnd.github+json' + 'User-Agent' = 'UniGetUI-Chocolatey-Local-Pack' + } + + if ($env:GITHUB_TOKEN) { + $headers['Authorization'] = "Bearer $($env:GITHUB_TOKEN)" + } + + Invoke-RestMethod -Uri $Uri -Headers $headers +} + +function Download-File { + param( + [Parameter(Mandatory)] + [string] $Uri, + + [Parameter(Mandatory)] + [string] $DestinationPath + ) + + $headers = @{ 'User-Agent' = 'UniGetUI-Chocolatey-Local-Pack' } + if ($env:GITHUB_TOKEN) { + $headers['Authorization'] = "Bearer $($env:GITHUB_TOKEN)" + } + + Invoke-WebRequest -Uri $Uri -Headers $headers -OutFile $DestinationPath +} + +function Get-Release { + param( + [string] $RequestedVersion + ) + + if ([string]::IsNullOrWhiteSpace($RequestedVersion)) { + return Invoke-GitHubApi -Uri 'https://api.github.com/repos/Devolutions/UniGetUI/releases/latest' + } + + $tag = if ($RequestedVersion.StartsWith('v')) { $RequestedVersion } else { "v$RequestedVersion" } + $escapedTag = [System.Uri]::EscapeDataString($tag) + return Invoke-GitHubApi -Uri "https://api.github.com/repos/Devolutions/UniGetUI/releases/tags/$escapedTag" +} + +function Get-CurrentPackageVersion { + $assemblyInfoPath = Join-Path $RepoRoot 'src' 'SharedAssemblyInfo.cs' + $versionMatch = Select-String -Path $assemblyInfoPath -Pattern 'AssemblyInformationalVersion\("([^"]+)"\)' + if (-not $versionMatch) { + throw "Could not determine the current package version from $assemblyInfoPath" + } + + return $versionMatch.Matches[0].Groups[1].Value +} + +function Get-ChecksumFromFile { + param( + [Parameter(Mandatory)] + [string] $ChecksumsPath, + + [Parameter(Mandatory)] + [string] $AssetName + ) + + $pattern = "^(?[A-Fa-f0-9]{64})\s+$([regex]::Escape($AssetName))$" + $line = Select-String -Path $ChecksumsPath -Pattern $pattern | Select-Object -First 1 + if (-not $line) { + throw "Could not find a SHA256 for '$AssetName' in $ChecksumsPath" + } + + return $line.Matches[0].Groups['hash'].Value.ToUpperInvariant() +} + +function Require-Command { + param( + [Parameter(Mandatory)] + [string] $Name + ) + + if (-not (Get-Command $Name -ErrorAction SilentlyContinue)) { + throw "Required command '$Name' was not found in PATH." + } +} + +Require-Command -Name 'choco' + +if (-not (Test-Path $TemplateDir)) { + throw "Chocolatey template folder not found: $TemplateDir" +} + +if ($BuildLocalInstaller -and $InstallerPath) { + throw 'BuildLocalInstaller and InstallerPath cannot be used together.' +} + +$useEmbeddedInstaller = $BuildLocalInstaller -or -not [string]::IsNullOrWhiteSpace($InstallerPath) +$installerAssetName = 'UniGetUI.Installer.x64.exe' +$installerUrl = $null +$release = $null + +if ($BuildLocalInstaller) { + $localBuildOutputPath = Join-Path $OutputPath 'local-build' + $buildArgs = @{ + Platform = 'x64' + OutputPath = $localBuildOutputPath + } + + if (-not [string]::IsNullOrWhiteSpace($Version)) { + $buildArgs['Version'] = $Version + } + + if ($SkipLocalBuildTests) { + $buildArgs['SkipTests'] = $true + } + + Write-Host 'Building local UniGetUI installer from the current checkout' + & (Join-Path $PSScriptRoot 'build.ps1') @buildArgs + if ($LASTEXITCODE -ne 0) { + throw "Local installer build failed with exit code $LASTEXITCODE" + } + + $InstallerPath = Join-Path $localBuildOutputPath $installerAssetName + if (-not (Test-Path $InstallerPath)) { + throw "Local installer was not produced at $InstallerPath" + } + + $packageVersion = if ([string]::IsNullOrWhiteSpace($Version)) { Get-CurrentPackageVersion } else { $Version } + Write-Host "Packaging UniGetUI Chocolatey package from local installer $InstallerPath" +} +elseif (-not [string]::IsNullOrWhiteSpace($InstallerPath)) { + $InstallerPath = [System.IO.Path]::GetFullPath($InstallerPath) + if (-not (Test-Path $InstallerPath)) { + throw "InstallerPath was not found: $InstallerPath" + } + + $packageVersion = if ([string]::IsNullOrWhiteSpace($Version)) { Get-CurrentPackageVersion } else { $Version } + Write-Host "Packaging UniGetUI Chocolatey package from local installer $InstallerPath" +} +else { + $release = Get-Release -RequestedVersion $Version + $packageVersion = $release.tag_name.TrimStart('v') + + $installerAsset = $release.assets | Where-Object { $_.name -eq $installerAssetName } | Select-Object -First 1 + if (-not $installerAsset) { + throw "Could not find asset '$installerAssetName' in release $($release.tag_name)" + } + + $checksumsAsset = $release.assets | Where-Object { $_.name -eq 'checksums.txt' } | Select-Object -First 1 + if (-not $checksumsAsset) { + throw "Could not find asset 'checksums.txt' in release $($release.tag_name)" + } + + Write-Host "Packaging UniGetUI Chocolatey package for release $($release.tag_name)" + Write-Host "Installer asset: $($installerAsset.browser_download_url)" + + $installerPath = Join-Path $DownloadDir $installerAsset.name + $checksumsPath = Join-Path $DownloadDir $checksumsAsset.name + + Download-File -Uri $installerAsset.browser_download_url -DestinationPath $installerPath + Download-File -Uri $checksumsAsset.browser_download_url -DestinationPath $checksumsPath + + $sha256 = Get-ChecksumFromFile -ChecksumsPath $checksumsPath -AssetName $installerAsset.name + $installerUrl = $installerAsset.browser_download_url +} + +New-Item -Path $OutputPath -ItemType Directory -Force | Out-Null +New-Item -Path $DownloadDir -ItemType Directory -Force | Out-Null +New-Item -Path $StagingRoot -ItemType Directory -Force | Out-Null + +if (Test-Path $StagingRoot) { + Remove-Item $StagingRoot -Recurse -Force +} + +New-Item -Path $StagingRoot -ItemType Directory -Force | Out-Null +Copy-Item -Path $TemplateDir -Destination $StagingDir -Recurse + +if ($useEmbeddedInstaller) { + $embeddedInstallerName = Split-Path $InstallerPath -Leaf + $embeddedInstallerPath = Join-Path $StagingDir 'tools' $embeddedInstallerName + Copy-Item -Path $InstallerPath -Destination $embeddedInstallerPath -Force + $sha256 = (Get-FileHash -Path $InstallerPath -Algorithm SHA256).Hash.ToUpperInvariant() +} + +$nuspecTemplatePath = Join-Path $StagingDir 'unigetui.template.nuspec' +$installTemplatePath = Join-Path $StagingDir 'tools' 'chocolateyInstall.template.ps1' +$nuspecPath = Join-Path $StagingDir 'unigetui.nuspec' +$installScriptPath = Join-Path $StagingDir 'tools' 'chocolateyInstall.ps1' + +$nuspecContent = (Get-Content $nuspecTemplatePath -Raw).Replace('$VAR1$', $packageVersion) + +if ($useEmbeddedInstaller) { + $nuspecContent = $nuspecContent.Replace( + ' ', + (' ' + "`r`n" + (' ' -f $embeddedInstallerName)) + ) +} + +$installContent = Get-Content $installTemplatePath -Raw + +if ($useEmbeddedInstaller) { + $installContent = $installContent.Replace( + '$Url = ''https://cdn.devolutions.net/download/Devolutions.UniGetUI.win-x64.$VAR1$.exe''', + ('$InstallerPath = Join-Path $PSScriptRoot ''{0}''' -f $embeddedInstallerName) + ) + $installContent = $installContent.Replace(' url = $Url', ' file = $InstallerPath') + $installContent = $installContent -replace "(?m)^\s*checksum\s*=.*\r?\n", '' + $installContent = $installContent -replace "(?m)^\s*checksumType\s*=.*\r?\n", '' +} +else { + $installContent = $installContent.Replace('$VAR2$', $sha256) + $installContent = $installContent.Replace( + "'https://cdn.devolutions.net/download/Devolutions.UniGetUI.win-x64.`$VAR1$.exe'", + "'$installerUrl'" + ) +} + +$installContent = $installContent.Replace('$VAR1$', $packageVersion) + +Set-Content -Path $nuspecPath -Value $nuspecContent -Encoding utf8NoBOM +Set-Content -Path $installScriptPath -Value $installContent -Encoding utf8NoBOM + +Push-Location $StagingDir +try { + & choco pack 'unigetui.nuspec' --outputdirectory $OutputPath + if ($LASTEXITCODE -ne 0) { + throw "choco pack failed with exit code $LASTEXITCODE" + } +} +finally { + Pop-Location +} + +$packagePath = Join-Path $OutputPath "unigetui.$packageVersion.nupkg" +if (-not (Test-Path $packagePath)) { + $packagePath = Get-ChildItem -Path $OutputPath -Filter 'unigetui.*.nupkg' | Sort-Object LastWriteTime -Descending | Select-Object -First 1 -ExpandProperty FullName +} + +Write-Host "SHA256 (installer): $sha256" +Write-Host "Package written to: $packagePath" diff --git a/scripts/build.ps1 b/scripts/build.ps1 new file mode 100644 index 0000000..3d34892 --- /dev/null +++ b/scripts/build.ps1 @@ -0,0 +1,180 @@ +#!/usr/bin/env pwsh +<# +.SYNOPSIS + Builds UniGetUI, produces the published output, and packages artifacts. + +.PARAMETER Configuration + Build configuration (Debug or Release). Default: Release. + +.PARAMETER Platform + Target platform. Default: x64. + +.PARAMETER OutputPath + Directory for final packaged artifacts (zip, installer). Default: ./output + +.PARAMETER SkipTests + Skip running dotnet test before build. + +.PARAMETER SkipInstaller + Skip building the Inno Setup installer. + +.PARAMETER Version + Version string to stamp into the build (e.g. "3.3.7"). If not provided, + the current version from SharedAssemblyInfo.cs is used. + +.PARAMETER MaxInstallerCompression + Use the strongest Inno Setup compression settings for the installer. +#> +[CmdletBinding()] +param( + [string] $Configuration = "Release", + [string] $Platform = "x64", + [string] $OutputPath = (Join-Path $PSScriptRoot ".." "output"), + [switch] $SkipTests, + [switch] $SkipInstaller, + [switch] $MaxInstallerCompression, + [string] $Version +) + +$ErrorActionPreference = 'Stop' + +$RepoRoot = Resolve-Path (Join-Path $PSScriptRoot "..") +$SrcDir = Join-Path $RepoRoot "src" +$WindowsSolution = Join-Path $SrcDir "UniGetUI.Windows.slnx" +$PublishProject = Join-Path $SrcDir "UniGetUI.Avalonia" "UniGetUI.Avalonia.csproj" +$BinDir = Join-Path $RepoRoot "unigetui_bin" +$BuildPropsPath = Join-Path $SrcDir "Directory.Build.props" +[xml] $BuildProps = Get-Content $BuildPropsPath +$PortableTargetFramework = @($BuildProps.Project.PropertyGroup | Where-Object { $_.PortableTargetFramework } | Select-Object -First 1).PortableTargetFramework +$WindowsTargetPlatformVersion = @($BuildProps.Project.PropertyGroup | Where-Object { $_.WindowsTargetPlatformVersion } | Select-Object -First 1).WindowsTargetPlatformVersion + +if ([string]::IsNullOrWhiteSpace($PortableTargetFramework) -or [string]::IsNullOrWhiteSpace($WindowsTargetPlatformVersion)) { + throw "Could not resolve the target framework from $BuildPropsPath" +} + +$TargetFramework = "$PortableTargetFramework-windows$WindowsTargetPlatformVersion" +$PublishDir = Join-Path $SrcDir "UniGetUI.Avalonia" "bin" $Platform $Configuration $TargetFramework "win-$Platform" "publish" + +# --- Version stamping --- +if ($Version) { + Write-Host "Stamping version: $Version" + & (Join-Path $PSScriptRoot "set-version.ps1") -Version $Version +} + +# --- Read version from SharedAssemblyInfo.cs --- +$AssemblyInfoPath = Join-Path $SrcDir "SharedAssemblyInfo.cs" +$VersionMatch = Select-String -Path $AssemblyInfoPath -Pattern 'AssemblyInformationalVersion\("([^"]+)"\)' +$PackageVersion = if ($VersionMatch) { $VersionMatch.Matches[0].Groups[1].Value } else { "0.0.0" } +Write-Host "Building UniGetUI version: $PackageVersion" + +# --- Test --- +if (-not $SkipTests) { + Write-Host "`n=== Running tests ===" -ForegroundColor Cyan + dotnet test $WindowsSolution --verbosity q --nologo --ignore-failed-sources /p:Platform=$Platform + if ($LASTEXITCODE -ne 0) { + throw "Tests failed with exit code $LASTEXITCODE" + } +} + +# --- Build / Publish --- +Write-Host "`n=== Publishing $Configuration|$Platform ===" -ForegroundColor Cyan +dotnet clean $WindowsSolution -v m --nologo /p:Platform=$Platform + +dotnet publish $PublishProject /noLogo /p:Configuration=$Configuration /p:Platform=$Platform -p:RuntimeIdentifier=win-$Platform --ignore-failed-sources -v m +if ($LASTEXITCODE -ne 0) { + throw "dotnet publish Avalonia failed with exit code $LASTEXITCODE" +} + +# --- Stage binaries --- +if (Test-Path $BinDir) { Remove-Item $BinDir -Recurse -Force } +New-Item $BinDir -ItemType Directory | Out-Null +# Move published output into unigetui_bin +Get-ChildItem $PublishDir | Move-Item -Destination $BinDir -Force + +$WindowsAppHostPath = Join-Path $BinDir "UniGetUI.exe" +if (-not (Test-Path $WindowsAppHostPath)) { + throw "Windows app host was not produced at $WindowsAppHostPath" +} + +# Keep smaller symbols for useful local crash source information, and prune oversized ones. +$MaxShippedPdbSizeBytes = 1MB + +$PdbsToRemove = Get-ChildItem $BinDir -Filter "*.pdb" -File | Where-Object { + $_.Length -gt $MaxShippedPdbSizeBytes +} + +if ($PdbsToRemove.Count -gt 0) { + $RemovedPdbBytes = ($PdbsToRemove | Measure-Object -Property Length -Sum).Sum + $PdbsToRemove | Remove-Item -Force + Write-Host ("Removed {0} oversized PDBs above {1:N2} MiB ({2:N2} MiB total)." -f $PdbsToRemove.Count, ($MaxShippedPdbSizeBytes / 1MB), ($RemovedPdbBytes / 1MB)) +} + +# --- Package output --- +if (Test-Path $OutputPath) { Remove-Item $OutputPath -Recurse -Force } +New-Item $OutputPath -ItemType Directory | Out-Null + +$ZipPath = Join-Path $OutputPath "UniGetUI.$Platform.zip" +Write-Host "`n=== Refreshing integrity tree before zip packaging ===" -ForegroundColor Cyan +& (Join-Path $PSScriptRoot "refresh-integrity-tree.ps1") -Path $BinDir -FailOnUnexpectedFiles + +Write-Host "`n=== Creating zip: $ZipPath ===" -ForegroundColor Cyan +Compress-Archive -Path (Join-Path $BinDir "*") -DestinationPath $ZipPath -CompressionLevel Optimal + +# --- Installer (Inno Setup) --- +if (-not $SkipInstaller) { + $IsccPath = $null + # Search common install locations + foreach ($candidate in @( + "${env:ProgramFiles(x86)}\Inno Setup 6\ISCC.exe", + "$env:ProgramFiles\Inno Setup 6\ISCC.exe", + "$env:LOCALAPPDATA\Programs\Inno Setup 6\ISCC.exe" + )) { + if (Test-Path $candidate) { $IsccPath = $candidate; break } + } + + if ($IsccPath) { + Write-Host "`n=== Building installer ===" -ForegroundColor Cyan + $InstallerBaseName = "UniGetUI.Installer.$Platform" + $IssPath = Join-Path $RepoRoot "UniGetUI.iss" + $IssContent = Get-Content $IssPath -Raw + + Write-Host "`n=== Refreshing integrity tree before installer packaging ===" -ForegroundColor Cyan + & (Join-Path $PSScriptRoot "refresh-integrity-tree.ps1") -Path $BinDir -FailOnUnexpectedFiles + + try { + $IssContentNoSign = $IssContent -Replace '(?m)^SignTool=.*$', '; SignTool=azsign (disabled for local build)' + $IssContentNoSign = $IssContentNoSign -Replace '(?m)^SignedUninstaller=yes', 'SignedUninstaller=no' + Set-Content $IssPath $IssContentNoSign -NoNewline + + $IsccArgs = @($IssPath, "/F$InstallerBaseName", "/O$OutputPath") + if ($MaxInstallerCompression) { + Write-Host "Using lzma/ultra64 installer compression." + $IsccArgs = @('/DInstallerCompression=lzma/ultra64') + $IsccArgs + } + + & $IsccPath @IsccArgs + if ($LASTEXITCODE -ne 0) { + throw "Inno Setup failed with exit code $LASTEXITCODE" + } + } + finally { + Set-Content $IssPath $IssContent -NoNewline + } + } else { + Write-Warning "Inno Setup 6 (ISCC.exe) not found — skipping installer build." + } +} + +# --- Checksums --- +Write-Host "`n=== Checksums ===" -ForegroundColor Cyan +$ChecksumFile = Join-Path $OutputPath "checksums.$Platform.txt" +Get-ChildItem $OutputPath -File | Where-Object { $_.Name -notlike "checksums.*.txt" } | ForEach-Object { + $hash = (Get-FileHash $_.FullName -Algorithm SHA256).Hash + "$hash $($_.Name)" | Tee-Object -FilePath $ChecksumFile -Append +} + +# --- Cleanup --- +if (Test-Path $BinDir) { Remove-Item $BinDir -Recurse -Force } + +Write-Host "`n=== Build complete ===" -ForegroundColor Green +Write-Host "Artifacts in: $OutputPath" diff --git a/scripts/export-icon-database-gallery.ps1 b/scripts/export-icon-database-gallery.ps1 new file mode 100644 index 0000000..6cc5e79 --- /dev/null +++ b/scripts/export-icon-database-gallery.ps1 @@ -0,0 +1,306 @@ +#!/usr/bin/env pwsh +<# +.SYNOPSIS + Exports the icon database to a browsable Markdown gallery. + +.DESCRIPTION + Reads WebBasedData/screenshot-database-v2.json and writes a Markdown file + that lists every package with embedded remote icon and screenshot images, + making it easy to review the database in a Markdown preview without + downloading each asset manually. + +.EXAMPLE + ./scripts/export-icon-database-gallery.ps1 + + Writes WebBasedData/screenshot-database-gallery.md. + +.EXAMPLE + ./scripts/export-icon-database-gallery.ps1 -MaxPackages 100 -OutputPath temp/icon-gallery.md + + Writes a gallery for the first 100 package entries to temp/icon-gallery.md. + +.EXAMPLE + ./scripts/export-icon-database-gallery.ps1 -IncludePackageName 'devolutions*' + + Writes a gallery that only includes package names matching the provided + wildcard pattern. + +.EXAMPLE + ./scripts/export-icon-database-gallery.ps1 -IncludePackageName 'remote','rdm' -ExcludePackageName '*agent*' + + Writes a gallery for packages whose names contain remote or rdm, excluding + names that contain agent. +#> + +[CmdletBinding()] +param( + [string] $JsonPath = 'WebBasedData/screenshot-database-v2.json', + [string] $OutputPath = 'WebBasedData/screenshot-database-gallery.md', + [string[]] $IncludePackageName = @(), + [string[]] $ExcludePackageName = @(), + [int] $MaxPackages, + [int] $IconWidth = 96, + [int] $ScreenshotWidth = 360 +) + +Set-StrictMode -Version Latest +$ErrorActionPreference = 'Stop' + +$RepoRoot = [System.IO.Path]::GetFullPath((Join-Path $PSScriptRoot '..')) + +function Resolve-RepoPath { + param( + [Parameter(Mandatory)] + [string] $Path + ) + + if ([System.IO.Path]::IsPathRooted($Path)) { + return [System.IO.Path]::GetFullPath($Path) + } + + return [System.IO.Path]::GetFullPath((Join-Path $RepoRoot $Path)) +} + +function Write-Utf8File { + param( + [Parameter(Mandatory)] + [string] $Path, + + [Parameter(Mandatory)] + [AllowEmptyString()] + [string] $Content + ) + + $directory = Split-Path -Parent $Path + if (-not [string]::IsNullOrWhiteSpace($directory)) { + New-Item -ItemType Directory -Path $directory -Force | Out-Null + } + + $encoding = [System.Text.UTF8Encoding]::new($false) + [System.IO.File]::WriteAllText($Path, $Content, $encoding) +} + +function Read-IconDatabase { + param( + [Parameter(Mandatory)] + [string] $Path + ) + + if (-not (Test-Path -LiteralPath $Path)) { + throw "Icon database file not found: $Path" + } + + $database = Get-Content -LiteralPath $Path -Raw | ConvertFrom-Json -AsHashtable + if (-not ($database -is [System.Collections.IDictionary])) { + throw 'Icon database root must be a JSON object.' + } + + if (-not $database.Contains('icons_and_screenshots')) { + throw 'Icon database is missing icons_and_screenshots.' + } + + if (-not ($database['icons_and_screenshots'] -is [System.Collections.IDictionary])) { + throw 'icons_and_screenshots must be a JSON object.' + } + + return $database +} + +function Normalize-Entry { + param( + [Parameter(Mandatory)] + [System.Collections.IDictionary] $Entry + ) + + if (-not $Entry.Contains('icon') -or $null -eq $Entry['icon']) { + $Entry['icon'] = '' + } + + if (-not $Entry.Contains('images') -or $null -eq $Entry['images']) { + $Entry['images'] = @() + } + + $images = @() + foreach ($image in @($Entry['images'])) { + if ($null -eq $image) { + continue + } + + $value = [string] $image + if ([string]::IsNullOrWhiteSpace($value)) { + continue + } + + $images += $value + } + + $Entry['icon'] = [string] $Entry['icon'] + $Entry['images'] = $images +} + +function Get-MarkdownSafeText { + param( + [Parameter(Mandatory)] + [string] $Value + ) + + return $Value.Replace('&', '&').Replace('<', '<').Replace('>', '>') +} + +function New-RemoteImageMarkup { + param( + [Parameter(Mandatory)] + [string] $Url, + + [Parameter(Mandatory)] + [string] $Alt, + + [Parameter(Mandatory)] + [int] $Width + ) + + $safeAlt = Get-MarkdownSafeText -Value $Alt + $safeUrl = Get-MarkdownSafeText -Value $Url + return ('{1}' -f $safeUrl, $safeAlt, $Width) +} + +function ConvertTo-WildcardPattern { + param( + [Parameter(Mandatory)] + [string] $Value + ) + + $trimmedValue = $Value.Trim() + if ([string]::IsNullOrWhiteSpace($trimmedValue)) { + return $null + } + + if ($trimmedValue.IndexOfAny(@('*', '?')) -ge 0) { + return $trimmedValue + } + + return ('*{0}*' -f $trimmedValue) +} + +function Test-PackageNameMatch { + param( + [Parameter(Mandatory)] + [string] $PackageId, + + [Parameter(Mandatory)] + [string[]] $Patterns + ) + + foreach ($pattern in $Patterns) { + if ($PackageId -like $pattern) { + return $true + } + } + + return $false +} + +$resolvedJsonPath = Resolve-RepoPath -Path $JsonPath +$resolvedOutputPath = Resolve-RepoPath -Path $OutputPath + +$database = Read-IconDatabase -Path $resolvedJsonPath +$entries = $database['icons_and_screenshots'] + +$includePatterns = @( + $IncludePackageName | + ForEach-Object { ConvertTo-WildcardPattern -Value $_ } | + Where-Object { $null -ne $_ } +) +$excludePatterns = @( + $ExcludePackageName | + ForEach-Object { ConvertTo-WildcardPattern -Value $_ } | + Where-Object { $null -ne $_ } +) + +$builder = [System.Text.StringBuilder]::new() +$generatedUtc = [DateTime]::UtcNow.ToString("yyyy-MM-dd HH:mm:ss 'UTC'") +$exportedPackages = 0 + +[void] $builder.AppendLine('# Icon Database Gallery') +[void] $builder.AppendLine() +[void] $builder.AppendLine("Generated from $JsonPath on $generatedUtc.") +[void] $builder.AppendLine() +if ($includePatterns.Count -gt 0) { + [void] $builder.AppendLine(('Included package filters: {0}' -f (($IncludePackageName | Where-Object { -not [string]::IsNullOrWhiteSpace($_) }) -join ', '))) +} +if ($excludePatterns.Count -gt 0) { + [void] $builder.AppendLine(('Excluded package filters: {0}' -f (($ExcludePackageName | Where-Object { -not [string]::IsNullOrWhiteSpace($_) }) -join ', '))) +} +[void] $builder.AppendLine() +[void] $builder.AppendLine('This file is intended for Markdown preview. Click any image to open the original URL.') +[void] $builder.AppendLine() + +$packageCount = 0 +foreach ($packageId in $entries.Keys) { + if ($MaxPackages -gt 0 -and $packageCount -ge $MaxPackages) { + break + } + + if ($packageId -eq '__test_entry_DO_NOT_EDIT_PLEASE') { + continue + } + + if ($includePatterns.Count -gt 0 -and -not (Test-PackageNameMatch -PackageId $packageId -Patterns $includePatterns)) { + continue + } + + if ($excludePatterns.Count -gt 0 -and (Test-PackageNameMatch -PackageId $packageId -Patterns $excludePatterns)) { + continue + } + + $entry = $entries[$packageId] + Normalize-Entry -Entry $entry + + $iconUrl = [string] $entry['icon'] + $images = @($entry['images']) + + [void] $builder.AppendLine(('## {0}' -f $packageId)) + [void] $builder.AppendLine() + + if ([string]::IsNullOrWhiteSpace($iconUrl)) { + [void] $builder.AppendLine('Icon: none') + } + else { + [void] $builder.AppendLine('Icon:') + [void] $builder.AppendLine() + [void] $builder.AppendLine((New-RemoteImageMarkup -Url $iconUrl -Alt "$packageId icon" -Width $IconWidth)) + [void] $builder.AppendLine() + [void] $builder.AppendLine($iconUrl) + } + + [void] $builder.AppendLine() + + if ($images.Count -eq 0) { + [void] $builder.AppendLine('Screenshots: none') + } + else { + [void] $builder.AppendLine(('Screenshots: {0}' -f $images.Count)) + [void] $builder.AppendLine() + + $screenshotIndex = 1 + foreach ($imageUrl in $images) { + [void] $builder.AppendLine(('Screenshot {0}:' -f $screenshotIndex)) + [void] $builder.AppendLine() + [void] $builder.AppendLine((New-RemoteImageMarkup -Url $imageUrl -Alt ('{0} screenshot {1}' -f $packageId, $screenshotIndex) -Width $ScreenshotWidth)) + [void] $builder.AppendLine() + [void] $builder.AppendLine($imageUrl) + [void] $builder.AppendLine() + $screenshotIndex++ + } + } + + [void] $builder.AppendLine('---') + [void] $builder.AppendLine() + $packageCount++ + $exportedPackages++ +} + +[void] $builder.Insert(0, ("Packages exported: {0}`r`n`r`n" -f $exportedPackages)) + +Write-Utf8File -Path $resolvedOutputPath -Content $builder.ToString() +Write-Host "Wrote icon database gallery to $resolvedOutputPath" \ No newline at end of file diff --git a/scripts/generate-integrity-tree.ps1 b/scripts/generate-integrity-tree.ps1 new file mode 100644 index 0000000..5d56abd --- /dev/null +++ b/scripts/generate-integrity-tree.ps1 @@ -0,0 +1,58 @@ +#!/usr/bin/env pwsh +<# +.SYNOPSIS + Generates an IntegrityTree.json file containing SHA256 hashes of all files + in the specified directory. Used at build time; verified at runtime by + UniGetUI.Core.Tools.IntegrityTester. + +.PARAMETER Path + The directory to scan (typically the publish/output directory). + +.PARAMETER MinOutput + Suppress per-file progress output. +#> + +[CmdletBinding()] +param( + [Parameter(Mandatory, Position = 0)] + [string] $Path, + + [switch] $MinOutput +) + +$ErrorActionPreference = 'Stop' + +if (-not (Test-Path $Path -PathType Container)) { + throw "The directory '$Path' does not exist." +} + +$Path = (Resolve-Path $Path).Path +$OutputFileName = 'IntegrityTree.json' +$ScriptName = [System.IO.Path]::GetFileName($PSCommandPath) + +$integrityData = [ordered]@{} + +Get-ChildItem $Path -Recurse -File | ForEach-Object { + $relativePath = $_.FullName.Substring($Path.Length).TrimStart('\', '/') -replace '\\', '/' + + # Skip the output file itself + if ($relativePath -eq $OutputFileName) { return } + + if (-not $MinOutput) { + Write-Host " - Computing SHA256 of $relativePath..." + } + + $hash = (Get-FileHash $_.FullName -Algorithm SHA256).Hash.ToLower() + $integrityData[$relativePath] = $hash +} + +# Sort keys for deterministic output +$sorted = [ordered]@{} +foreach ($key in ($integrityData.Keys | Sort-Object)) { + $sorted[$key] = $integrityData[$key] +} + +$json = $sorted | ConvertTo-Json -Depth 1 +Set-Content (Join-Path $Path $OutputFileName) $json -Encoding utf8NoBOM -NoNewline + +Write-Host "Integrity tree was generated and saved to $Path/$OutputFileName" diff --git a/scripts/get_contributors.ps1 b/scripts/get_contributors.ps1 new file mode 100644 index 0000000..4602da7 --- /dev/null +++ b/scripts/get_contributors.ps1 @@ -0,0 +1,58 @@ +[CmdletBinding()] +param( + [string]$Repository = 'Devolutions/UniGetUI', + [string]$OutputPath +) + +Set-StrictMode -Version Latest +$ErrorActionPreference = 'Stop' + +function Get-RepositoryRoot { + return [System.IO.Path]::GetFullPath((Join-Path $PSScriptRoot '..')) +} + +function Resolve-OutputPath { + if (-not [string]::IsNullOrWhiteSpace($OutputPath)) { + return [System.IO.Path]::GetFullPath($OutputPath) + } + + return Join-Path (Get-RepositoryRoot) 'src\UniGetUI.Core.Data\Assets\Data\Contributors.list' +} + +function Write-Utf8Lines { + param( + [Parameter(Mandatory = $true)] + [string]$Path, + + [Parameter(Mandatory = $true)] + [string[]]$Lines + ) + + $directory = Split-Path -Path $Path -Parent + if (-not [string]::IsNullOrWhiteSpace($directory)) { + New-Item -Path $directory -ItemType Directory -Force | Out-Null + } + + $encoding = [System.Text.UTF8Encoding]::new($false) + [System.IO.File]::WriteAllLines($Path, $Lines, $encoding) +} + +$resolvedOutputPath = Resolve-OutputPath +$contributorsUrl = "https://api.github.com/repos/$Repository/contributors?anon=1&per_page=100" + +try { + Write-Output 'Getting contributors...' + $response = Invoke-RestMethod -Uri $contributorsUrl -Headers @{ 'User-Agent' = 'UniGetUI-Scripts' } + $contributors = @( + $response | + Where-Object { $_.type -eq 'User' -and -not [string]::IsNullOrWhiteSpace($_.login) } | + ForEach-Object { [string]$_.login } + ) + + Write-Utf8Lines -Path $resolvedOutputPath -Lines $contributors + Write-Output "Wrote $($contributors.Count) contributor login(s) to: $resolvedOutputPath" +} +catch { + Write-Error "Failed to fetch contributors: $($_.Exception.Message)" + exit 1 +} \ No newline at end of file diff --git a/scripts/install-git-hooks.ps1 b/scripts/install-git-hooks.ps1 new file mode 100644 index 0000000..54cdc94 --- /dev/null +++ b/scripts/install-git-hooks.ps1 @@ -0,0 +1,8 @@ +$ErrorActionPreference = 'Stop' + +$repoRoot = (Resolve-Path (Join-Path $PSScriptRoot '..')).Path + +git -C $repoRoot config core.hooksPath .githooks + +Write-Host 'Configured git hooks path to .githooks' -ForegroundColor Green +Write-Host 'The pre-commit hook will run dotnet format whitespace on staged files under src.' -ForegroundColor Green \ No newline at end of file diff --git a/scripts/macos/AppIcon.icon/Assets/devolutions-unigetui-icon-fullbleed.svg b/scripts/macos/AppIcon.icon/Assets/devolutions-unigetui-icon-fullbleed.svg new file mode 100644 index 0000000..4d95355 --- /dev/null +++ b/scripts/macos/AppIcon.icon/Assets/devolutions-unigetui-icon-fullbleed.svg @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + diff --git a/scripts/macos/AppIcon.icon/icon.json b/scripts/macos/AppIcon.icon/icon.json new file mode 100644 index 0000000..dffcf2c --- /dev/null +++ b/scripts/macos/AppIcon.icon/icon.json @@ -0,0 +1,52 @@ +{ + "fill" : { + "linear-gradient" : [ + "display-p3:0.10196,0.30196,0.36863,1.00000", + "display-p3:0.20784,0.82353,0.87843,1.00000" + ], + "orientation" : { + "start" : { + "x" : 0.5, + "y" : 0 + }, + "stop" : { + "x" : 0.5, + "y" : 1 + } + } + }, + "groups" : [ + { + "layers" : [ + { + "blend-mode" : "normal", + "glass" : false, + "hidden" : false, + "image-name" : "devolutions-unigetui-icon-fullbleed.svg", + "name" : "devolutions-unigetui-icon", + "position" : { + "scale" : 14.222222, + "translation-in-points" : [ + 0, + 0 + ] + } + } + ], + "shadow" : { + "kind" : "neutral", + "opacity" : 0.5 + }, + "translucency" : { + "enabled" : false, + "value" : 0.5 + } + } + ], + "supported-platforms" : { + "circles" : [ + "watchOS" + ], + "squares" : "shared" + } +} diff --git a/scripts/macos/Entitlements.plist b/scripts/macos/Entitlements.plist new file mode 100644 index 0000000..be8b716 --- /dev/null +++ b/scripts/macos/Entitlements.plist @@ -0,0 +1,14 @@ + + + + + com.apple.security.cs.allow-jit + + com.apple.security.cs.allow-unsigned-executable-memory + + com.apple.security.cs.disable-library-validation + + com.apple.security.cs.allow-dyld-environment-variables + + + diff --git a/scripts/macos/Info.plist b/scripts/macos/Info.plist new file mode 100644 index 0000000..8500518 --- /dev/null +++ b/scripts/macos/Info.plist @@ -0,0 +1,32 @@ + + + + + CFBundleIdentifier + io.github.marticliment.unigetui + CFBundleName + UniGetUI + CFBundleDisplayName + UniGetUI + CFBundleExecutable + UniGetUI + + CFBundleIconName + AppIcon + CFBundleIconFile + UniGetUI + CFBundlePackageType + APPL + CFBundleVersion + @VERSION@ + CFBundleShortVersionString + @VERSION@ + NSHighResolutionCapable + + LSMinimumSystemVersion + 12.0 + NSPrincipalClass + NSApplication + + diff --git a/scripts/macos/UniGetUI.icns b/scripts/macos/UniGetUI.icns new file mode 100644 index 0000000..18432cd Binary files /dev/null and b/scripts/macos/UniGetUI.icns differ diff --git a/scripts/merge-publish-output.ps1 b/scripts/merge-publish-output.ps1 new file mode 100644 index 0000000..c0bed85 --- /dev/null +++ b/scripts/merge-publish-output.ps1 @@ -0,0 +1,86 @@ +#!/usr/bin/env pwsh +<# +.SYNOPSIS + Merges one publish directory into another, allowing only identical file collisions. + +.PARAMETER Source + The publish directory to copy from. + +.PARAMETER Destination + The publish directory to copy into. +#> + +[CmdletBinding()] +param( + [Parameter(Mandatory)] + [string] $Source, + + [Parameter(Mandatory)] + [string] $Destination +) + +$ErrorActionPreference = 'Stop' + +if (-not (Test-Path $Source -PathType Container)) { + throw "Source directory '$Source' does not exist." +} + +if (-not (Test-Path $Destination -PathType Container)) { + throw "Destination directory '$Destination' does not exist." +} + +$Source = (Resolve-Path $Source).Path +$Destination = (Resolve-Path $Destination).Path + +$sourceWinsConflicts = @{ + 'Microsoft.Extensions.DependencyInjection.Abstractions.dll' = $true + 'Microsoft.VisualBasic.dll' = $true + 'Microsoft.Win32.SystemEvents.dll' = $true + 'System.Diagnostics.EventLog.dll' = $true + 'System.Diagnostics.EventLog.Messages.dll' = $true + 'System.Drawing.Common.dll' = $true + 'System.Drawing.dll' = $true + 'System.Private.Windows.Core.dll' = $true + 'System.Security.Cryptography.Pkcs.dll' = $true + 'System.Security.Cryptography.Xml.dll' = $true + 'WindowsBase.dll' = $true +} + +$destinationWinsConflicts = @{ + 'Microsoft.Windows.SDK.NET.dll' = $true + 'WinRT.Runtime.dll' = $true +} + +Get-ChildItem $Source -Recurse -File | ForEach-Object { + $relativePath = $_.FullName.Substring($Source.Length).TrimStart('\', '/') + $destinationPath = Join-Path $Destination $relativePath + $destinationDirectory = Split-Path $destinationPath -Parent + + if (Test-Path $destinationPath -PathType Leaf) { + $sourceHash = (Get-FileHash $_.FullName -Algorithm SHA256).Hash + $destinationHash = (Get-FileHash $destinationPath -Algorithm SHA256).Hash + + if ($sourceHash -ne $destinationHash) { + $fileName = [System.IO.Path]::GetFileName($relativePath) + + if ($sourceWinsConflicts.ContainsKey($fileName)) { + Copy-Item $_.FullName -Destination $destinationPath -Force + return + } + + if ($destinationWinsConflicts.ContainsKey($fileName)) { + return + } + + throw "Publish merge conflict for '$relativePath': source and destination files differ." + } + + return + } + + if (-not (Test-Path $destinationDirectory -PathType Container)) { + New-Item $destinationDirectory -ItemType Directory -Force | Out-Null + } + + Copy-Item $_.FullName -Destination $destinationPath -Force +} \ No newline at end of file diff --git a/scripts/package-linux.ps1 b/scripts/package-linux.ps1 new file mode 100644 index 0000000..26b3ca0 --- /dev/null +++ b/scripts/package-linux.ps1 @@ -0,0 +1,286 @@ +#!/usr/bin/env pwsh +<# +.SYNOPSIS + Creates a .deb or .rpm package from a pre-built binary directory. + +.DESCRIPTION + Builds a native Linux package without requiring Ruby/fpm. + .deb is assembled with tar and ar (binutils). + .rpm is built with rpmbuild (rpm-build). + +.PARAMETER PackageType + Package format to produce: 'deb' or 'rpm'. + +.PARAMETER SourceDir + Directory containing the pre-built binaries to package. + +.PARAMETER OutputPath + Full path to the output package file (e.g. output/unigetui.deb). + +.PARAMETER Version + Package version string, already formatted for the target format: + deb: "2026.1.0" or "2026.1.0~beta1" + rpm: "2026.1.0" + +.PARAMETER Architecture + Target CPU architecture in the format expected by the package type: + deb: amd64 | arm64 + rpm: x86_64 | aarch64 + +.PARAMETER Iteration + RPM Release/iteration field (default: 1). Ignored for .deb. + +.PARAMETER PackageName + Package name (default: unigetui). + +.PARAMETER InstallPrefix + Absolute install directory on the target system (default: /opt/unigetui). + +.PARAMETER Description + One-line package description. + +.PARAMETER Maintainer + Maintainer field value, e.g. "Name ". + +.PARAMETER Url + Homepage / upstream URL. + +.PARAMETER AppExecutableName + Executable filename inside InstallPrefix. + +.PARAMETER LauncherName + Public command name exposed in PATH. + +.PARAMETER IconSourcePath + Source path for the installed desktop icon. +#> + +[CmdletBinding()] +param( + [Parameter(Mandatory)] + [ValidateSet('deb', 'rpm')] + [string] $PackageType, + + [Parameter(Mandatory)] + [string] $SourceDir, + + [Parameter(Mandatory)] + [string] $OutputPath, + + [Parameter(Mandatory)] + [string] $Version, + + [Parameter(Mandatory)] + [string] $Architecture, + + [string] $Iteration = '1', + [string] $PackageName = 'unigetui', + [string] $InstallPrefix = '/opt/unigetui', + [string] $Description = 'UniGetUI - GUI for package managers', + [string] $Maintainer = 'Devolutions Inc. ', + [string] $Url = 'https://github.com/Devolutions/UniGetUI', + [string] $AppExecutableName = 'UniGetUI', + [string] $LauncherName = 'unigetui', + [string] $IconSourcePath = (Join-Path $PSScriptRoot '..' 'src' 'SharedAssets' 'Assets' 'Images' 'icon.png') +) + +$ErrorActionPreference = 'Stop' + +$SourceDir = (Resolve-Path $SourceDir).Path +$OutputPath = [System.IO.Path]::GetFullPath($OutputPath) +$IconSourcePath = (Resolve-Path $IconSourcePath).Path +$OutDir = Split-Path $OutputPath +if ($OutDir) { New-Item -ItemType Directory -Path $OutDir -Force | Out-Null } + +$TmpDir = Join-Path ([System.IO.Path]::GetTempPath()) "pkg-$(New-Guid)" +New-Item -ItemType Directory -Path $TmpDir | Out-Null + +$IconInstallDir = '/usr/share/icons/hicolor/512x512/apps' +$IconTargetName = "$LauncherName.png" +$IconInstallPath = "$IconInstallDir/$IconTargetName" +$DesktopFilePath = "/usr/share/applications/$LauncherName.desktop" +$LauncherPath = "/usr/bin/$LauncherName" + +function New-LinuxIntegrationAssets { + param( + [Parameter(Mandatory)] + [string] $StageRoot + ) + + $payloadDir = Join-Path $StageRoot ($InstallPrefix.TrimStart('/')) + New-Item -ItemType Directory -Path $payloadDir -Force | Out-Null + & /bin/cp -a "$SourceDir/." $payloadDir + if ($LASTEXITCODE -ne 0) { throw "cp (payload staging) exited $LASTEXITCODE" } + + $appExecutableFullPath = Join-Path $payloadDir $AppExecutableName + if (-not (Test-Path $appExecutableFullPath -PathType Leaf)) { + throw "App executable '$AppExecutableName' was not found in package payload '$payloadDir'" + } + + $launcherFullPath = Join-Path $StageRoot $LauncherPath.TrimStart('/') + New-Item -ItemType Directory -Path (Split-Path $launcherFullPath -Parent) -Force | Out-Null + $launcherCommand = 'exec {0}/{1} "$@"' -f $InstallPrefix, $AppExecutableName + $launcherScript = @( + '#!/bin/sh', + $launcherCommand, + '' + ) -join "`n" + [System.IO.File]::WriteAllText($launcherFullPath, $launcherScript) + & chmod 755 $launcherFullPath + if ($LASTEXITCODE -ne 0) { throw "chmod (launcher) exited $LASTEXITCODE" } + + $desktopEntryFullPath = Join-Path $StageRoot $DesktopFilePath.TrimStart('/') + New-Item -ItemType Directory -Path (Split-Path $desktopEntryFullPath -Parent) -Force | Out-Null + $desktopEntry = @( + '[Desktop Entry]', + 'Version=1.0', + 'Type=Application', + 'Name=UniGetUI', + "Comment=$Description", + "Exec=$LauncherPath", + "Icon=$LauncherName", + 'Terminal=false', + 'Categories=System;Utility;', + 'StartupNotify=true', + '' + ) -join "`n" + [System.IO.File]::WriteAllText($desktopEntryFullPath, $desktopEntry) + & chmod 644 $desktopEntryFullPath + if ($LASTEXITCODE -ne 0) { throw "chmod (desktop entry) exited $LASTEXITCODE" } + + $iconFullPath = Join-Path $StageRoot $IconInstallPath.TrimStart('/') + New-Item -ItemType Directory -Path (Split-Path $iconFullPath -Parent) -Force | Out-Null + Copy-Item -Path $IconSourcePath -Destination $iconFullPath -Force + & chmod 644 $iconFullPath + if ($LASTEXITCODE -ne 0) { throw "chmod (icon) exited $LASTEXITCODE" } +} + +try { + # ------------------------------------------------------------------ + # .deb + # Structure: ar archive containing debian-binary, control.tar.gz, data.tar.gz + # Tools required: tar, ar (binutils – pre-installed on Ubuntu runners) + # ------------------------------------------------------------------ + if ($PackageType -eq 'deb') { + # 1. debian-binary (must be the first ar member, content is "2.0\n") + $DebianBinaryPath = Join-Path $TmpDir 'debian-binary' + [System.IO.File]::WriteAllText($DebianBinaryPath, "2.0`n") + + # 2. data.tar.gz – payload and Linux integration assets staged under target paths + $DataStage = Join-Path $TmpDir 'data' + New-LinuxIntegrationAssets -StageRoot $DataStage + + $InstalledSizeKb = [long][System.Math]::Ceiling( + (Get-ChildItem -Recurse -File $DataStage | + Measure-Object -Property Length -Sum).Sum / 1024 + ) + + # 3. control.tar.gz + $ControlDir = Join-Path $TmpDir 'control' + New-Item -ItemType Directory -Path $ControlDir | Out-Null + + # dpkg requires LF line endings and a trailing newline in control files + $ControlLines = @( + "Package: $PackageName", + "Version: $Version", + "Architecture: $Architecture", + "Maintainer: $Maintainer", + "Installed-Size: $InstalledSizeKb", + "Homepage: $Url", + "Description: $Description", + "Priority: optional", + "" + ) + [System.IO.File]::WriteAllText( + (Join-Path $ControlDir 'control'), + ($ControlLines -join "`n") + ) + + $ControlTarPath = Join-Path $TmpDir 'control.tar.gz' + & tar -czf $ControlTarPath -C $ControlDir . + if ($LASTEXITCODE -ne 0) { throw "tar (control) exited $LASTEXITCODE" } + + $DataTarPath = Join-Path $TmpDir 'data.tar.gz' + & tar -czf $DataTarPath -C $DataStage . + if ($LASTEXITCODE -ne 0) { throw "tar (data) exited $LASTEXITCODE" } + + # 4. Assemble .deb with ar + # Member names in the archive must be bare filenames (not paths), + # so Push-Location into TmpDir before invoking ar. + Push-Location $TmpDir + try { + & ar rc $OutputPath 'debian-binary' 'control.tar.gz' 'data.tar.gz' + if ($LASTEXITCODE -ne 0) { throw "ar exited $LASTEXITCODE" } + } + finally { Pop-Location } + } + + # ------------------------------------------------------------------ + # .rpm + # Built with rpmbuild. %install copies from the absolute SourceDir + # into the buildroot so no pre-staged directory tricks are needed. + # Tools required: rpmbuild (rpm-build apt package) + # ------------------------------------------------------------------ + elseif ($PackageType -eq 'rpm') { + $DataStage = Join-Path $TmpDir 'data' + New-LinuxIntegrationAssets -StageRoot $DataStage + + $RpmTop = Join-Path $TmpDir 'rpmbuild' + foreach ($d in 'BUILD', 'BUILDROOT', 'RPMS', 'SOURCES', 'SPECS', 'SRPMS') { + New-Item -ItemType Directory -Path (Join-Path $RpmTop $d) | Out-Null + } + + $SpecPath = Join-Path $RpmTop 'SPECS' "$PackageName.spec" + + # Spec uses LF line endings; here-string keeps them on Linux/macOS + $SpecText = @" +Name: $PackageName +Version: $Version +Release: $Iteration +Summary: $Description +License: GPL-3.0-or-later +URL: $Url + +# The self-contained .NET runtime links against liblttng-ust.so.0, which was +# renamed to .so.1 in newer distros (Fedora 38+). Exclude it so the package +# installs on both old and new releases; .NET ships its own tracing fallback. +%global __requires_exclude ^liblttng-ust\.so + +%description +$Description + +%install +cp -rp $DataStage/. %{buildroot}/ + +%files +%defattr(-,root,root,-) +$InstallPrefix +$LauncherPath +$DesktopFilePath +$IconInstallPath + +%changelog +"@ + [System.IO.File]::WriteAllText($SpecPath, $SpecText) + + & rpmbuild -bb ` + --define "_topdir $RpmTop" ` + --define "_build_name_fmt %%{NAME}-%%{VERSION}-%%{RELEASE}.%%{ARCH}.rpm" ` + --define "__strip /bin/true" ` + --define "__debug_install_post %{nil}" ` + --define "debug_package %{nil}" ` + --target "$Architecture-unknown-linux" ` + $SpecPath + if ($LASTEXITCODE -ne 0) { throw "rpmbuild exited $LASTEXITCODE" } + + $BuiltRpm = Get-ChildItem -Path (Join-Path $RpmTop 'RPMS') -Recurse -Filter '*.rpm' | + Select-Object -First 1 + if (-not $BuiltRpm) { throw "rpmbuild produced no .rpm file" } + Move-Item -Path $BuiltRpm.FullName -Destination $OutputPath -Force + } +} +finally { + Remove-Item -Recurse -Force $TmpDir -ErrorAction SilentlyContinue +} + +Write-Host "Created: $OutputPath" diff --git a/scripts/publish-nativeaot.ps1 b/scripts/publish-nativeaot.ps1 new file mode 100644 index 0000000..d7068c1 --- /dev/null +++ b/scripts/publish-nativeaot.ps1 @@ -0,0 +1,57 @@ +#!/usr/bin/env pwsh +<# +.SYNOPSIS + Publishes UniGetUI as a NativeAOT self-contained Windows build. + +.PARAMETER Configuration + Build configuration. Default: Release. + +.PARAMETER Platform + Target platform. Default: x64. Supported: x64, arm64. + +.PARAMETER OutputPath + Directory for the published output. Default: ./artifacts/nativeaot/win-. + +.PARAMETER PublishProfileName + NativeAOT publish profile name. Default: Win--NativeAot. +#> +[CmdletBinding()] +param( + [string] $Configuration = "Release", + [ValidateSet("x64", "arm64")] + [string] $Platform = "x64", + [string] $OutputPath = (Join-Path (Join-Path $PSScriptRoot "..") "artifacts/nativeaot/win-$Platform"), + [string] $PublishProfileName = "Win-$Platform-NativeAot" +) + +$ErrorActionPreference = 'Stop' + +$RepoRoot = Resolve-Path (Join-Path $PSScriptRoot "..") +$ProjectPath = Join-Path $RepoRoot "src/UniGetUI.Avalonia/UniGetUI.Avalonia.csproj" + +if (Test-Path $OutputPath) { + Remove-Item $OutputPath -Recurse -Force +} + +New-Item $OutputPath -ItemType Directory -Force | Out-Null + +Write-Host "Publishing NativeAOT build for win-$Platform to $OutputPath" -ForegroundColor Cyan + +dotnet publish $ProjectPath ` + --configuration $Configuration ` + --runtime "win-$Platform" ` + --self-contained true ` + --output $OutputPath ` + /m:1 ` + /p:Platform=$Platform ` + /p:PublishProfile=$PublishProfileName ` + /p:TrimmerSingleWarn=false ` + /p:UseSharedCompilation=false ` + --nologo ` + --verbosity minimal + +if ($LASTEXITCODE -ne 0) { + throw "dotnet publish failed with exit code $LASTEXITCODE" +} + +Write-Host "NativeAOT publish complete." -ForegroundColor Green diff --git a/scripts/refresh-integrity-tree.ps1 b/scripts/refresh-integrity-tree.ps1 new file mode 100644 index 0000000..1899f87 --- /dev/null +++ b/scripts/refresh-integrity-tree.ps1 @@ -0,0 +1,48 @@ +#!/usr/bin/env pwsh +<# +.SYNOPSIS + Regenerates IntegrityTree.json and validates it against the current folder contents. + +.PARAMETER Path + The directory whose IntegrityTree.json should be refreshed and validated. + +.PARAMETER FailOnUnexpectedFiles + Fail validation if files exist in the directory tree but are not present in + IntegrityTree.json. +#> + +[CmdletBinding()] +param( + [Parameter(Mandatory, Position = 0)] + [string] $Path, + + [switch] $FailOnUnexpectedFiles +) + +$ErrorActionPreference = 'Stop' + +if (-not (Test-Path $Path -PathType Container)) { + throw "The directory '$Path' does not exist." +} + +$Path = (Resolve-Path $Path).Path +$GenerateScriptPath = Join-Path $PSScriptRoot 'generate-integrity-tree.ps1' +$VerifyScriptPath = Join-Path $PSScriptRoot 'verify-integrity-tree.ps1' + +if (-not (Test-Path $GenerateScriptPath -PathType Leaf)) { + throw "Integrity tree generator not found at '$GenerateScriptPath'." +} + +if (-not (Test-Path $VerifyScriptPath -PathType Leaf)) { + throw "Integrity tree validator not found at '$VerifyScriptPath'." +} + +Write-Host "Refreshing integrity tree in $Path..." +& $GenerateScriptPath -Path $Path -MinOutput + +$ValidationParameters = @{ Path = $Path } +if ($FailOnUnexpectedFiles) { + $ValidationParameters.FailOnUnexpectedFiles = $true +} + +& $VerifyScriptPath @ValidationParameters \ No newline at end of file diff --git a/scripts/set-version.ps1 b/scripts/set-version.ps1 new file mode 100644 index 0000000..012b53f --- /dev/null +++ b/scripts/set-version.ps1 @@ -0,0 +1,97 @@ +#!/usr/bin/env pwsh +<# +.SYNOPSIS + Stamps version information into all required source files. + CI-friendly version stamping script for local builds and CI. + +.PARAMETER Version + Semantic version string, e.g. "3.3.7" or "3.4.0-beta1". + A four-part version (X.X.X.X) is derived automatically for assembly info. +#> + +[CmdletBinding()] +param( + [Parameter(Mandatory)] + [string] $Version +) + +$ErrorActionPreference = 'Stop' + +$RepoRoot = Resolve-Path (Join-Path $PSScriptRoot "..") + +# Derive four-part version: 3.3.7 -> 3.3.7.0, 3.4.0-beta1 -> 3.4.0.0 +$CleanVersion = ($Version -Split '-')[0] # strip prerelease tag +$Parts = $CleanVersion -Split '\.' +while ($Parts.Count -lt 4) { $Parts += '0' } +$FourPartVersion = ($Parts[0..3]) -Join '.' + +Write-Host "Version name : $Version" +Write-Host "Assembly ver : $FourPartVersion" + +# --- Bump build number --- +$BuildNumberFile = Join-Path $PSScriptRoot "BuildNumber" +$BuildNumber = 0 +if (Test-Path $BuildNumberFile) { + $BuildNumber = [int](Get-Content $BuildNumberFile -Raw).Trim() +} +$BuildNumber++ +Set-Content $BuildNumberFile $BuildNumber +Write-Host "Build number : $BuildNumber" + +# --- Helper: replace lines in a file by prefix match --- +function Set-LinesByPrefix { + param( + [string] $FilePath, + [hashtable] $Replacements, + [string] $Encoding = 'utf8BOM' + ) + + if (-not (Test-Path $FilePath)) { + Write-Warning "File not found, skipping: $FilePath" + return + } + + $lines = Get-Content $FilePath -Encoding $Encoding + $output = foreach ($line in $lines) { + $matched = $false + foreach ($prefix in $Replacements.Keys) { + if ($line.TrimStart().StartsWith($prefix)) { + $Replacements[$prefix] + $matched = $true + break + } + } + if (-not $matched) { $line } + } + $output | Set-Content $FilePath -Encoding $Encoding +} + +# --- CoreData.cs --- +Set-LinesByPrefix -FilePath (Join-Path $RepoRoot "src" "UniGetUI.Core.Data" "CoreData.cs") -Replacements @{ + 'public const string VersionName =' = " public const string VersionName = `"$Version`"; // Do not modify this line, use file scripts/set-version.ps1" + 'public const int BuildNumber =' = " public const int BuildNumber = $BuildNumber; // Do not modify this line, use file scripts/set-version.ps1" +} + +# --- SharedAssemblyInfo.cs --- +Set-LinesByPrefix -FilePath (Join-Path $RepoRoot "src" "SharedAssemblyInfo.cs") -Replacements @{ + '[assembly: AssemblyVersion("' = "[assembly: AssemblyVersion(`"$FourPartVersion`")]" + '[assembly: AssemblyFileVersion("' = "[assembly: AssemblyFileVersion(`"$FourPartVersion`")]" + '[assembly: AssemblyInformationalVersion("' = "[assembly: AssemblyInformationalVersion(`"$Version`")]" +} + +# --- UniGetUI.iss --- +Set-LinesByPrefix -FilePath (Join-Path $RepoRoot "UniGetUI.iss") -Replacements @{ + '#define MyAppVersion' = "#define MyAppVersion `"$Version`"" + 'VersionInfoVersion=' = "VersionInfoVersion=$FourPartVersion" + 'VersionInfoProductVersion=' = "VersionInfoProductVersion=$FourPartVersion" +} + +# --- app.manifest (only the assemblyIdentity version, not manifestVersion) --- +$ManifestPath = Join-Path $RepoRoot "src" "UniGetUI" "app.manifest" +if (Test-Path $ManifestPath) { + $content = Get-Content $ManifestPath -Raw -Encoding utf8BOM + $content = $content -Replace '(?s)( + +[CmdletBinding()] +param( + [string] $BinDir, + [string] $InstallerPath, + [string] $FileListPath, + + [Parameter(Mandatory)] + [string] $AzureTenantId, + + [Parameter(Mandatory)] + [string] $KeyVaultUrl, + + [Parameter(Mandatory)] + [string] $ClientId, + + [Parameter(Mandatory)] + [string] $ClientSecret, + + [Parameter(Mandatory)] + [string] $CertificateName, + + [string] $TimestampServer = "http://timestamp.digicert.com", + + [switch] $Install +) + +$ErrorActionPreference = 'Stop' + +# --- Install tools if requested --- +if ($Install) { + Write-Host "Installing code-signing tools..." -ForegroundColor Cyan + dotnet tool install --global AzureSignTool 2>$null + Install-Module -Name Devolutions.Authenticode -Force -Scope CurrentUser 2>$null + + # Trust test code-signing CA + $TestCertsUrl = "https://raw.githubusercontent.com/Devolutions/devolutions-authenticode/master/data/certs" + $CaCertPath = Join-Path $env:TEMP "authenticode-test-ca.crt" + Invoke-WebRequest -Uri "$TestCertsUrl/authenticode-test-ca.crt" -OutFile $CaCertPath + Import-Certificate -FilePath $CaCertPath -CertStoreLocation "cert:\LocalMachine\Root" | Out-Null + Remove-Item $CaCertPath -ErrorAction SilentlyContinue + Write-Host "Code-signing tools installed." +} + +$SignParams = @( + 'sign', + '-kvt', $AzureTenantId, + '-kvu', $KeyVaultUrl, + '-kvi', $ClientId, + '-kvs', $ClientSecret, + '-kvc', $CertificateName, + '-tr', $TimestampServer, + '-v' +) + +function Invoke-BatchSign { + param( + [string[]] $Files + ) + + $Files = $Files | Where-Object { $_ -and (Test-Path $_) } + if (-not $Files -or $Files.Count -eq 0) { + Write-Warning "No files to sign." + return + } + + Write-Host "Signing $($Files.Count) files..." + + # Pass file paths via -ifl so we don't blow past the Windows 32K command-line limit. + $tempListPath = [System.IO.Path]::GetTempFileName() + try { + Set-Content -Path $tempListPath -Value $Files -Encoding utf8 + AzureSignTool @SignParams -ifl $tempListPath + if ($LASTEXITCODE -ne 0) { + throw "AzureSignTool failed with exit code $LASTEXITCODE" + } + } finally { + Remove-Item -Path $tempListPath -ErrorAction SilentlyContinue + } +} + +function Update-IntegrityTree { + param( + [string] $RootPath + ) + + if (-not $RootPath -or -not (Test-Path $RootPath -PathType Container)) { + return + } + + $TreeRefreshScriptPath = Join-Path $PSScriptRoot "refresh-integrity-tree.ps1" + if (-not (Test-Path $TreeRefreshScriptPath -PathType Leaf)) { + Write-Warning "Integrity tree refresh script not found at $TreeRefreshScriptPath" + return + } + + & $TreeRefreshScriptPath -Path $RootPath -FailOnUnexpectedFiles + if ($LASTEXITCODE -ne 0) { + throw "refresh-integrity-tree.ps1 failed with exit code $LASTEXITCODE" + } +} + +# --- Sign binaries in BinDir --- +if ($FileListPath -and (Test-Path $FileListPath)) { + Write-Host "`n=== Signing binaries from list: $FileListPath ===" -ForegroundColor Cyan + $filesToSign = Get-Content $FileListPath | Where-Object { $_ -and ($_ -notmatch '^\s*$') } + Invoke-BatchSign -Files $filesToSign +} elseif ($BinDir -and (Test-Path $BinDir)) { + Write-Host "`n=== Signing binaries in $BinDir ===" -ForegroundColor Cyan + $filesToSign = Get-ChildItem -Path $BinDir -Include @("*.exe", "*.dll") -Recurse + if ($filesToSign.Count -eq 0) { + Write-Warning "No .exe or .dll files found in $BinDir" + } else { + Invoke-BatchSign -Files ($filesToSign | ForEach-Object { $_.FullName }) + Update-IntegrityTree -RootPath $BinDir + Write-Host "Binary signing complete." + } +} + +# --- Sign installer --- +if ($InstallerPath -and (Test-Path $InstallerPath)) { + Write-Host "`n=== Signing installer: $InstallerPath ===" -ForegroundColor Cyan + AzureSignTool @SignParams $InstallerPath + if ($LASTEXITCODE -ne 0) { + throw "AzureSignTool failed for installer with exit code $LASTEXITCODE" + } + Write-Host "Installer signing complete." +} diff --git a/scripts/translation/Export-TranslationBoundaryAlignment.ps1 b/scripts/translation/Export-TranslationBoundaryAlignment.ps1 new file mode 100644 index 0000000..b827bcc --- /dev/null +++ b/scripts/translation/Export-TranslationBoundaryAlignment.ps1 @@ -0,0 +1,146 @@ +[CmdletBinding()] +param( + [string]$RepositoryRoot, + [string]$EnglishFilePath, + [string]$LanguagesDirectory, + [string]$OutputPath +) + +Set-StrictMode -Version Latest +$ErrorActionPreference = 'Stop' + +. (Join-Path $PSScriptRoot 'Languages\TranslationJsonTools.ps1') +. (Join-Path $PSScriptRoot 'Languages\TranslationSourceTools.ps1') + +$resolvedRepositoryRoot = Resolve-TranslationSyncRepositoryRoot -RepositoryRoot $RepositoryRoot +$resolvedEnglishFilePath = Resolve-EnglishLanguageFilePath -ResolvedRepositoryRoot $resolvedRepositoryRoot -EnglishFilePath $EnglishFilePath +$resolvedLanguagesDirectory = if ([string]::IsNullOrWhiteSpace($LanguagesDirectory)) { + Split-Path -Path $resolvedEnglishFilePath -Parent +} +else { + Get-FullPath -Path $LanguagesDirectory +} + +if (-not (Test-Path -Path $resolvedLanguagesDirectory -PathType Container)) { + throw "Languages directory not found: $resolvedLanguagesDirectory" +} + +$englishMap = Read-OrderedJsonMap -Path $resolvedEnglishFilePath +$englishSections = Split-TranslationMapAtBoundary -Map $englishMap +if (-not $englishSections.HasBoundary) { + Write-Output 'The English translation file does not contain a legacy boundary marker. No alignment to export.' + return +} + +$englishActiveOrder = @($englishSections.ActiveMap.Keys) +$englishLegacyOrder = @($englishSections.LegacyMap.Keys) +$englishActiveSet = [System.Collections.Generic.HashSet[string]]::new([System.StringComparer]::Ordinal) +foreach ($key in $englishActiveOrder) { + [void]$englishActiveSet.Add([string]$key) +} + +$englishLegacySet = [System.Collections.Generic.HashSet[string]]::new([System.StringComparer]::Ordinal) +foreach ($key in $englishLegacyOrder) { + [void]$englishLegacySet.Add([string]$key) +} + +$reports = New-Object System.Collections.Generic.List[object] +$languageFiles = Get-ChildItem -Path $resolvedLanguagesDirectory -Filter 'lang_*.json' | Sort-Object Name +foreach ($languageFile in $languageFiles) { + if ($languageFile.FullName -ieq $resolvedEnglishFilePath) { + continue + } + + $languageMap = Read-OrderedJsonMapPermissive -Path $languageFile.FullName + $languageSections = Split-TranslationMapAtBoundary -Map $languageMap + + $missingActiveKeys = New-Object System.Collections.Generic.List[string] + foreach ($key in $englishActiveOrder) { + if (-not $languageMap.Contains($key)) { + $missingActiveKeys.Add([string]$key) + } + } + + $presentActiveInExpectedOrder = New-Object System.Collections.Generic.List[string] + foreach ($key in $englishActiveOrder) { + if ($languageMap.Contains($key)) { + $presentActiveInExpectedOrder.Add([string]$key) + } + } + + $currentActiveInEnglishSet = New-Object System.Collections.Generic.List[string] + $extraActiveKeys = New-Object System.Collections.Generic.List[string] + foreach ($entry in $languageSections.ActiveMap.GetEnumerator()) { + $key = [string]$entry.Key + if ($englishActiveSet.Contains($key)) { + $currentActiveInEnglishSet.Add($key) + } + elseif ($key -cne (Get-TranslationLegacyBoundaryKey)) { + $extraActiveKeys.Add($key) + } + } + + $presentLegacyInExpectedOrder = New-Object System.Collections.Generic.List[string] + foreach ($key in $englishLegacyOrder) { + if ($languageMap.Contains($key)) { + $presentLegacyInExpectedOrder.Add([string]$key) + } + } + + $currentLegacyInEnglishSet = New-Object System.Collections.Generic.List[string] + $extraLegacyKeys = New-Object System.Collections.Generic.List[string] + foreach ($entry in $languageSections.LegacyMap.GetEnumerator()) { + $key = [string]$entry.Key + if ($englishLegacySet.Contains($key)) { + $currentLegacyInEnglishSet.Add($key) + } + else { + $extraLegacyKeys.Add($key) + } + } + + $reportEntry = [pscustomobject]@{ + languageFile = (Get-RepoRelativePath -RepositoryRoot $resolvedRepositoryRoot -FilePath $languageFile.FullName) + hasBoundary = $languageSections.HasBoundary + activeOrderAligned = [System.Linq.Enumerable]::SequenceEqual($currentActiveInEnglishSet.ToArray(), $presentActiveInExpectedOrder.ToArray()) + legacyOrderAligned = [System.Linq.Enumerable]::SequenceEqual($currentLegacyInEnglishSet.ToArray(), $presentLegacyInExpectedOrder.ToArray()) + activeKeyCount = $currentActiveInEnglishSet.Count + legacyKeyCount = $currentLegacyInEnglishSet.Count + missingActiveKeyCount = $missingActiveKeys.Count + extraActiveKeyCount = $extraActiveKeys.Count + extraLegacyKeyCount = $extraLegacyKeys.Count + missingActiveKeys = $missingActiveKeys.ToArray() + extraActiveKeys = $extraActiveKeys.ToArray() + extraLegacyKeys = $extraLegacyKeys.ToArray() + } + + $reports.Add($reportEntry) +} + +$report = [pscustomobject]@{ + generatedAt = (Get-Date).ToString('o') + repositoryRoot = $resolvedRepositoryRoot + englishFile = (Get-RepoRelativePath -RepositoryRoot $resolvedRepositoryRoot -FilePath $resolvedEnglishFilePath) + boundaryKey = Get-TranslationLegacyBoundaryKey + englishActiveKeyCount = $englishActiveOrder.Count + englishLegacyKeyCount = $englishLegacyOrder.Count + languageCount = $reports.Count + languages = $reports.ToArray() +} + +$resolvedOutputPath = if ([string]::IsNullOrWhiteSpace($OutputPath)) { + Join-Path $resolvedRepositoryRoot 'artifacts\translation\translation-boundary-alignment.json' +} +else { + Get-FullPath -Path $OutputPath +} + +New-Utf8File -Path $resolvedOutputPath -Content ($report | ConvertTo-Json -Depth 6) + +Write-Output 'Translation boundary alignment summary' +Write-Output "Repository root: $resolvedRepositoryRoot" +Write-Output "English file: $resolvedEnglishFilePath" +Write-Output "Language files analyzed: $($reports.Count)" +Write-Output "English active keys: $($englishActiveOrder.Count)" +Write-Output "English legacy keys: $($englishLegacyOrder.Count)" +Write-Output "Report: $resolvedOutputPath" \ No newline at end of file diff --git a/scripts/translation/Export-TranslationKeyDiff.ps1 b/scripts/translation/Export-TranslationKeyDiff.ps1 new file mode 100644 index 0000000..e1d1f51 --- /dev/null +++ b/scripts/translation/Export-TranslationKeyDiff.ps1 @@ -0,0 +1,128 @@ +[CmdletBinding()] +param( + [string]$RepositoryRoot, + [string]$TranslationFilePath, + [string]$BeforeRef = 'HEAD~1', + [string]$AfterRef = 'HEAD', + [string]$OutputPath +) + +Set-StrictMode -Version Latest +$ErrorActionPreference = 'Stop' + +. (Join-Path $PSScriptRoot 'Languages\TranslationJsonTools.ps1') +. (Join-Path $PSScriptRoot 'Languages\TranslationSourceTools.ps1') + +$resolvedRepositoryRoot = Resolve-TranslationSyncRepositoryRoot -RepositoryRoot $RepositoryRoot +$resolvedTranslationFilePath = if ([string]::IsNullOrWhiteSpace($TranslationFilePath)) { + Join-Path $resolvedRepositoryRoot 'src\Languages\lang_en.json' +} +else { + Get-FullPath -Path $TranslationFilePath +} + +if (-not (Test-Path -Path $resolvedTranslationFilePath -PathType Leaf)) { + throw "Translation file not found: $resolvedTranslationFilePath" +} + +$relativePath = Get-RepoRelativePath -RepositoryRoot $resolvedRepositoryRoot -FilePath $resolvedTranslationFilePath + +function Get-TranslationMap { + param( + [Parameter(Mandatory = $true)] + [string]$RepoRoot, + + [Parameter(Mandatory = $true)] + [string]$Ref, + + [Parameter(Mandatory = $true)] + [string]$RepoRelativePath, + + [Parameter(Mandatory = $true)] + [string]$ResolvedFilePath + ) + + if ($Ref -in @('WORKTREE', 'CURRENT', 'FILE')) { + return Read-OrderedJsonMap -Path $ResolvedFilePath + } + + $gitObject = '{0}:{1}' -f $Ref, $RepoRelativePath + $content = & git -C $RepoRoot show $gitObject 2>$null + if ($LASTEXITCODE -ne 0) { + throw "Unable to read '$RepoRelativePath' from git ref '$Ref'." + } + + return Convert-JsonContentToOrderedMap -Content ([string]::Join([Environment]::NewLine, @($content))) -Path $gitObject -DetectDuplicates +} + +$beforeMap = Get-TranslationMap -RepoRoot $resolvedRepositoryRoot -Ref $BeforeRef -RepoRelativePath $relativePath -ResolvedFilePath $resolvedTranslationFilePath +$afterMap = Get-TranslationMap -RepoRoot $resolvedRepositoryRoot -Ref $AfterRef -RepoRelativePath $relativePath -ResolvedFilePath $resolvedTranslationFilePath + +$removedKeys = New-Object System.Collections.Generic.List[string] +foreach ($entry in $beforeMap.GetEnumerator()) { + $key = [string]$entry.Key + if (-not $afterMap.Contains($key)) { + $removedKeys.Add($key) + } +} + +$addedKeys = New-Object System.Collections.Generic.List[string] +foreach ($entry in $afterMap.GetEnumerator()) { + $key = [string]$entry.Key + if (-not $beforeMap.Contains($key)) { + $addedKeys.Add($key) + } +} + +$changedValues = New-Object System.Collections.Generic.List[object] +foreach ($entry in $beforeMap.GetEnumerator()) { + $key = [string]$entry.Key + if ($afterMap.Contains($key)) { + $beforeValue = [string]$entry.Value + $afterValue = [string]$afterMap[$key] + if ($beforeValue -cne $afterValue) { + $changedValues.Add([pscustomobject]@{ + Key = $key + Before = $beforeValue + After = $afterValue + }) + } + } +} + +$removedKeysArray = $removedKeys.ToArray() +$addedKeysArray = $addedKeys.ToArray() +$changedValuesArray = $changedValues.ToArray() + +$report = [pscustomobject]@{ + generatedAt = (Get-Date).ToString('o') + repositoryRoot = $resolvedRepositoryRoot + translationFile = $relativePath + beforeRef = $BeforeRef + afterRef = $AfterRef + removedKeyCount = $removedKeys.Count + addedKeyCount = $addedKeys.Count + changedValueCount = $changedValues.Count + removedKeys = $removedKeysArray + addedKeys = $addedKeysArray + changedValues = $changedValuesArray +} + +$resolvedOutputPath = if ([string]::IsNullOrWhiteSpace($OutputPath)) { + Join-Path $resolvedRepositoryRoot ('artifacts\translation\{0}-{1}-to-{2}.json' -f ([IO.Path]::GetFileNameWithoutExtension($relativePath)), (Get-SafeLabel -Value $BeforeRef), (Get-SafeLabel -Value $AfterRef)) +} +else { + Get-FullPath -Path $OutputPath +} + +New-Utf8File -Path $resolvedOutputPath -Content ($report | ConvertTo-Json -Depth 6) + +Write-Output "Translation key diff summary" +Write-Output "Repository root: $resolvedRepositoryRoot" +Write-Output "Translation file: $relativePath" +Write-Output "Before ref: $BeforeRef" +Write-Output "After ref: $AfterRef" +Write-Output "Removed keys: $($removedKeys.Count)" +Write-Output "Added keys: $($addedKeys.Count)" +Write-Output "Changed values: $($changedValues.Count)" +Write-Output "Report: $resolvedOutputPath" \ No newline at end of file diff --git a/scripts/translation/Get-TranslationStatus.ps1 b/scripts/translation/Get-TranslationStatus.ps1 new file mode 100644 index 0000000..75f321e --- /dev/null +++ b/scripts/translation/Get-TranslationStatus.ps1 @@ -0,0 +1,587 @@ +[CmdletBinding()] +param( + [ValidateSet('Table', 'Json', 'Markdown')] + [string]$OutputFormat = 'Table', + + [switch]$IncludeEnglish, + + [switch]$OnlyIncomplete, + + [string]$OutputPath +) + +Set-StrictMode -Version Latest +$ErrorActionPreference = 'Stop' + +Import-Module (Join-Path $PSScriptRoot 'Languages\LanguageData.psm1') -Force +. (Join-Path $PSScriptRoot 'Languages\TranslationJsonTools.ps1') + +function Read-LanguageMap { + param( + [Parameter(Mandatory = $true)] + [string]$Path + ) + + if (-not (Test-Path -Path $Path -PathType Leaf)) { + return (New-OrderedStringMap) + } + + return (Read-OrderedJsonMap -Path $Path) +} + +function Get-LanguageMapSections { + param( + [Parameter(Mandatory = $true)] + [System.Collections.IDictionary]$Map + ) + + $sections = Split-TranslationMapAtBoundary -Map $Map + $fullMap = Join-TranslationMapWithBoundary -ActiveMap $sections.ActiveMap -LegacyMap $sections.LegacyMap + + return [pscustomobject]@{ + HasBoundary = $sections.HasBoundary + FullMap = $fullMap + ActiveMap = $sections.ActiveMap + LegacyMap = $sections.LegacyMap + } +} + +function Get-PercentageNumber { + param( + [AllowNull()] + [object]$Value + ) + + if ($null -eq $Value) { + return $null + } + + $text = [string]$Value + if ([string]::IsNullOrWhiteSpace($text)) { + return $null + } + + $trimmed = $text.Trim() + if ($trimmed.EndsWith('%', [System.StringComparison]::Ordinal)) { + $trimmed = $trimmed.Substring(0, $trimmed.Length - 1) + } + + $result = 0 + if ([int]::TryParse($trimmed, [ref]$result)) { + return $result + } + + return $null +} + +function Get-CompletionPercentage { + param( + [int]$Completed, + [int]$Total + ) + + if ($Total -le 0) { + return 0 + } + + if ($Completed -ge $Total) { + return 100 + } + + $rounded = [int][Math]::Round(($Completed / $Total) * 100, 0, [MidpointRounding]::AwayFromZero) + return [Math]::Min($rounded, 99) +} + +function Test-KnownPlaceholderLocale { + param( + [Parameter(Mandatory = $true)] + [string]$LanguageCode + ) + + return $false +} + +function Test-IntentionalSourceEqualValue { + param( + [Parameter(Mandatory = $true)] + [string]$LanguageCode, + + [Parameter(Mandatory = $true)] + [AllowEmptyString()] + [string]$SourceValue, + + [Parameter(Mandatory = $false)] + [AllowEmptyString()] + [string]$TargetValue = '' + ) + + if ($SourceValue -in @( + 'MSI', + 'MSIX', + 'OK', + 'UniGetUI', + 'UniGetUI - {0} {1}', + 'your@email.com', + '{0}: {1}', + '{0}: {1}, {2}' + )) { + return $true + } + + if ($LanguageCode -ceq 'it' -and $SourceValue -ceq 'No' -and $TargetValue -ceq 'No') { + return $true + } + + if ($LanguageCode -ceq 'ca' -and $SourceValue -ceq $TargetValue -and $SourceValue -in @( + '1 - Errors', + 'Error', + 'Global', + 'Local', + 'Manifest', + 'Manifests', + 'No', + 'Notes:', + 'Text' + )) { + return $true + } + + if ($LanguageCode -ceq 'pt_PT' -and $SourceValue -ceq $TargetValue -and $SourceValue -in @( + 'Global', + 'Local' + )) { + return $true + } + + if ($LanguageCode -ceq 'hr' -and $SourceValue -ceq $TargetValue -and $SourceValue -in @( + 'Manifest', + 'Status', + 'URL' + )) { + return $true + } + + if ($LanguageCode -ceq 'es' -and $SourceValue -ceq $TargetValue -and $SourceValue -in @( + 'Error', + 'Global', + 'Local', + 'No', + 'URL' + )) { + return $true + } + + if ($LanguageCode -ceq 'es-MX' -and $SourceValue -ceq $TargetValue -and $SourceValue -in @( + 'Error', + 'Global', + 'Local', + 'No', + 'URL', + 'Url' + )) { + return $true + } + + if ($LanguageCode -ceq 'fr' -and $SourceValue -ceq $TargetValue -and $SourceValue -in @( + 'Ascendant', + 'Descendant', + 'Global', + 'Local', + 'Portable', + 'Source', + 'Sources', + 'Verbose', + 'Version', + 'installation', + 'option', + 'version {0}', + '{0} minutes' + )) { + return $true + } + + if ($LanguageCode -ceq 'nl' -and $SourceValue -ceq $TargetValue -and $SourceValue -in @( + '1 week', + 'Filters', + 'Manifest', + 'Status', + 'Updates', + 'URL', + 'update', + 'website', + '{0} status' + )) { + return $true + } + + if ($LanguageCode -ceq 'sk' -and $SourceValue -ceq $TargetValue -and $SourceValue -in @( + 'Manifest', + 'Text' + )) { + return $true + } + + if ($LanguageCode -ceq 'de' -and $SourceValue -ceq $TargetValue -and $SourceValue -in @( + 'Global', + 'Manifest', + 'Name', + 'Repository', + 'Start', + 'Status', + 'Text', + 'Updates', + 'URL', + 'Verbose', + 'Version', + 'Version:', + 'optional', + '{package} Installation', + '{package} Update' + )) { + return $true + } + + if ($LanguageCode -ceq 'sv' -and $SourceValue -ceq $TargetValue -and $SourceValue -in @( + 'Global', + 'Manifest', + 'Start', + 'Status', + 'Text', + 'Version', + 'Version:', + 'installation', + 'version {0}', + '{0} installation', + '{0} status', + '{pm} version:' + )) { + return $true + } + + if ($LanguageCode -ceq 'id' -and $SourceValue -ceq $TargetValue -and $SourceValue -in @( + 'Global', + 'Grid', + 'Manifest', + 'Status', + 'URL', + 'Verbose', + '{0} status' + )) { + return $true + } + + if ($LanguageCode -ceq 'fil' -and $SourceValue -ceq $TargetValue -and $SourceValue -in @( + 'Android Subsystem', + 'Default', + 'Error', + 'Global', + 'Grid', + 'Machine | Global', + 'Manifest', + 'OK', + 'Ok', + 'Package', + 'Password', + 'Portable', + 'Portable mode', + 'PreRelease', + 'Repository', + 'Source', + 'Source:', + 'Telemetry', + 'Text', + 'URL', + 'UniGetUI', + 'UniGetUI - {0} {1}', + 'User', + 'Username', + 'Verbose', + 'website', + 'library' + )) { + return $true + } + + return $false +} + +. (Join-Path $PSScriptRoot 'Languages\IntentionalSourceEqualValues.ps1') + +function Get-TranslationStatusRow { + param( + [Parameter(Mandatory = $true)] + [string]$LanguageCode, + + [Parameter(Mandatory = $true)] + [string]$LanguageName, + + [Parameter(Mandatory = $true)] + [System.Collections.IDictionary]$NeutralMap, + + [Parameter(Mandatory = $true)] + [System.Collections.IDictionary]$NeutralLegacyMap, + + [Parameter(Mandatory = $true)] + [System.Collections.IDictionary]$TargetMap, + + [Parameter(Mandatory = $true)] + [System.Collections.IDictionary]$TargetLegacyMap, + + [AllowNull()] + [Nullable[int]]$StoredPercentage, + + [Parameter(Mandatory = $true)] + [bool]$HasFile, + + [Parameter(Mandatory = $true)] + [bool]$HasBoundary + ) + + $totalKeys = $NeutralMap.Count + $missingKeys = 0 + $emptyKeys = 0 + $sourceEqualKeys = 0 + $translatedKeys = 0 + $extraKeys = 0 + + foreach ($entry in $NeutralMap.GetEnumerator()) { + $key = [string]$entry.Key + $sourceValue = if ($null -eq $entry.Value) { '' } else { [string]$entry.Value } + + if (-not $TargetMap.Contains($key)) { + $missingKeys += 1 + continue + } + + $targetValue = if ($null -eq $TargetMap[$key]) { '' } else { [string]$TargetMap[$key] } + if ([string]::IsNullOrWhiteSpace($targetValue)) { + $emptyKeys += 1 + continue + } + + if ($LanguageCode -ne 'en' -and $targetValue -ceq $sourceValue) { + if (Test-IntentionalSourceEqualValue -LanguageCode $LanguageCode -SourceValue $sourceValue -TargetValue $targetValue) { + $translatedKeys += 1 + continue + } + + $sourceEqualKeys += 1 + continue + } + + $translatedKeys += 1 + } + + $knownKeys = [System.Collections.Generic.HashSet[string]]::new([System.StringComparer]::Ordinal) + foreach ($key in $NeutralMap.Keys) { + [void]$knownKeys.Add([string]$key) + } + + foreach ($key in $NeutralLegacyMap.Keys) { + [void]$knownKeys.Add([string]$key) + } + + foreach ($key in $TargetMap.Keys) { + if (-not $knownKeys.Contains([string]$key)) { + $extraKeys += 1 + } + } + + $isKnownPlaceholder = Test-KnownPlaceholderLocale -LanguageCode $LanguageCode + $sourceEqualThreshold = if ($totalKeys -le 0) { + 0 + } + else { + [int][Math]::Max( + [double]($totalKeys - 5), + [Math]::Ceiling($totalKeys * 0.98) + ) + } + + $potentialFallbackRegression = $HasFile -and -not $isKnownPlaceholder -and $sourceEqualKeys -ge $sourceEqualThreshold -and $translatedKeys -le 5 + + $completion = Get-CompletionPercentage -Completed $translatedKeys -Total $totalKeys + $storedText = if ($null -eq $StoredPercentage) { '' } else { '{0}%' -f $StoredPercentage } + $delta = if ($null -eq $StoredPercentage) { $null } else { $completion - $StoredPercentage } + + return [pscustomobject]@{ + Code = $LanguageCode + Language = $LanguageName + HasFile = $HasFile + HasBoundary = $HasBoundary + TotalKeys = $totalKeys + ActiveKeys = $totalKeys + Legacy = $TargetLegacyMap.Count + Translated = $translatedKeys + Missing = $missingKeys + Empty = $emptyKeys + SourceEqual = $sourceEqualKeys + Untranslated = $missingKeys + $emptyKeys + $sourceEqualKeys + Extra = $extraKeys + Completion = '{0}%' -f $completion + CompletionValue = $completion + Stored = $storedText + StoredValue = $StoredPercentage + Delta = $delta + KnownPlaceholder = $isKnownPlaceholder + PotentialFallbackRegression = $potentialFallbackRegression + } +} + +function Convert-RowsToMarkdown { + param( + [Parameter(Mandatory = $true)] + [object[]]$Rows + ) + + $lines = New-Object System.Collections.Generic.List[string] + $lines.Add('| Code | Language | Completion | Stored | Delta | Translated | Missing | Empty | Source Equal | Extra |') + $lines.Add('| :-- | :-- | --: | --: | --: | --: | --: | --: | --: | --: |') + + foreach ($row in $Rows) { + $deltaText = if ($null -eq $row.Delta) { '' } elseif ($row.Delta -gt 0) { '+{0}' -f $row.Delta } else { [string]$row.Delta } + $storedText = if ([string]::IsNullOrWhiteSpace([string]$row.Stored)) { '' } else { [string]$row.Stored } + $lines.Add("| $($row.Code) | $($row.Language) | $($row.Completion) | $storedText | $deltaText | $($row.Translated) | $($row.Missing) | $($row.Empty) | $($row.SourceEqual) | $($row.Extra) |") + } + + return ($lines -join [Environment]::NewLine) +} + +function Write-OutputContent { + param( + [Parameter(Mandatory = $true)] + [AllowEmptyString()] + [string]$Content + ) + + if ([string]::IsNullOrWhiteSpace($OutputPath)) { + Write-Output $Content + return + } + + $resolvedOutputPath = [System.IO.Path]::GetFullPath($OutputPath) + $directory = Split-Path -Path $resolvedOutputPath -Parent + if (-not [string]::IsNullOrWhiteSpace($directory)) { + New-Item -Path $directory -ItemType Directory -Force | Out-Null + } + + $encoding = [System.Text.UTF8Encoding]::new($false) + [System.IO.File]::WriteAllText($resolvedOutputPath, $Content + [Environment]::NewLine, $encoding) + Write-Output "Wrote translation status summary to: $resolvedOutputPath" +} + +function Get-OverviewLines { + param( + [Parameter(Mandatory = $true)] + [object[]]$Rows + ) + + if ($Rows.Count -eq 0) { + return @('Languages: 0', 'Incomplete: 0', 'Fully translated: 0') + } + + $incompleteCount = @($Rows | Where-Object { $_.Untranslated -gt 0 }).Count + $completeCount = @($Rows | Where-Object { $_.Untranslated -eq 0 }).Count + $totalUntranslated = ($Rows | Measure-Object -Property Untranslated -Sum).Sum + $totalMissing = ($Rows | Measure-Object -Property Missing -Sum).Sum + $totalEmpty = ($Rows | Measure-Object -Property Empty -Sum).Sum + $totalSourceEqual = ($Rows | Measure-Object -Property SourceEqual -Sum).Sum + $placeholderRows = @($Rows | Where-Object { $_.KnownPlaceholder }) + $potentialRegressionRows = @($Rows | Where-Object { $_.PotentialFallbackRegression }) + + $lines = New-Object System.Collections.Generic.List[string] + $lines.Add(('Languages: {0}' -f $Rows.Count)) + $lines.Add(('Incomplete: {0}' -f $incompleteCount)) + $lines.Add(('Fully translated: {0}' -f $completeCount)) + $lines.Add(('Outstanding entries: {0} (missing {1}, empty {2}, source-equal {3})' -f $totalUntranslated, $totalMissing, $totalEmpty, $totalSourceEqual)) + + if ($placeholderRows.Count -gt 0) { + $lines.Add(('Known placeholders: {0}' -f (($placeholderRows | ForEach-Object { $_.Code }) -join ', '))) + } + + if ($potentialRegressionRows.Count -gt 0) { + $lines.Add(('Potential fallback regressions: {0}' -f (($potentialRegressionRows | ForEach-Object { $_.Code }) -join ', '))) + } + + return $lines.ToArray() +} + +$languagesDirectory = Get-LanguagesDirectoryPath +$neutralPath = Join-Path $languagesDirectory 'lang_en.json' +if (-not (Test-Path -Path $neutralPath -PathType Leaf)) { + throw "Neutral language file not found: $neutralPath" +} + +$neutralSections = Get-LanguageMapSections -Map (Read-LanguageMap -Path $neutralPath) +$neutralMap = $neutralSections.ActiveMap +$neutralLegacyMap = $neutralSections.LegacyMap +$languageReference = Get-LanguageReference +$storedPercentages = Get-TranslatedPercentages +$rows = New-Object System.Collections.Generic.List[object] + +foreach ($entry in $languageReference.GetEnumerator()) { + $languageCode = [string]$entry.Key + if ($languageCode -eq 'default') { + continue + } + + if (-not $IncludeEnglish.IsPresent -and $languageCode -eq 'en') { + continue + } + + $languageFilePath = Join-Path $languagesDirectory ("lang_{0}.json" -f $languageCode) + $hasFile = Test-Path -Path $languageFilePath -PathType Leaf + $targetSections = if ($hasFile) { Get-LanguageMapSections -Map (Read-LanguageMap -Path $languageFilePath) } else { [pscustomobject]@{ HasBoundary = $false; FullMap = (New-OrderedStringMap); ActiveMap = (New-OrderedStringMap); LegacyMap = (New-OrderedStringMap) } } + $storedPercentage = if ($storedPercentages.Contains($languageCode)) { Get-PercentageNumber -Value $storedPercentages[$languageCode] } elseif ($languageCode -eq 'en') { 100 } else { $null } + + $row = Get-TranslationStatusRow -LanguageCode $languageCode -LanguageName ([string]$entry.Value) -NeutralMap $neutralMap -NeutralLegacyMap $neutralLegacyMap -TargetMap $targetSections.FullMap -TargetLegacyMap $targetSections.LegacyMap -StoredPercentage $storedPercentage -HasFile:$hasFile -HasBoundary:$targetSections.HasBoundary + if ($OnlyIncomplete.IsPresent -and $row.Untranslated -eq 0) { + continue + } + + $rows.Add($row) +} + +$orderedRows = @( + $rows | + Sort-Object @{ Expression = 'CompletionValue'; Descending = $false }, @{ Expression = 'Code'; Descending = $false } +) + +switch ($OutputFormat) { + 'Json' { + $json = if ($orderedRows.Count -eq 0) { + '[]' + } + else { + $orderedRows | ConvertTo-Json -Depth 5 + } + + Write-OutputContent -Content $json + } + 'Markdown' { + $overview = Get-OverviewLines -Rows $orderedRows + $markdownLines = @( + '## Translation Status Overview', + '' + ) + @($overview | ForEach-Object { '- ' + $_ }) + @( + '', + (Convert-RowsToMarkdown -Rows $orderedRows) + ) + $markdown = $markdownLines -join [Environment]::NewLine + Write-OutputContent -Content $markdown + } + default { + $overview = Get-OverviewLines -Rows $orderedRows + $tableText = $orderedRows | + Select-Object Code, Language, Completion, Stored, Delta, Translated, Missing, Empty, SourceEqual, Extra | + Format-Table -AutoSize | + Out-String + $content = (@( + $overview + ) + @( + '', + $tableText.TrimEnd() + )) -join [Environment]::NewLine + Write-OutputContent -Content $content + } +} diff --git a/scripts/translation/Languages/IntentionalSourceEqualValues.ps1 b/scripts/translation/Languages/IntentionalSourceEqualValues.ps1 new file mode 100644 index 0000000..4adf406 --- /dev/null +++ b/scripts/translation/Languages/IntentionalSourceEqualValues.ps1 @@ -0,0 +1,218 @@ +function Test-IntentionalSourceEqualValue { + param( + [Parameter(Mandatory = $true)] + [string]$LanguageCode, + + [Parameter(Mandatory = $true)] + [AllowEmptyString()] + [string]$SourceValue, + + [Parameter(Mandatory = $false)] + [AllowEmptyString()] + [string]$TargetValue = '' + ) + + if ($SourceValue -in @( + 'MSI', + 'MSIX', + 'OK', + 'UniGetUI', + 'UniGetUI - {0} {1}', + 'WinGet COM API', + 'your@email.com', + '{0}: {1}', + '{0}: {1}, {2}' + )) { + return $true + } + + if ($LanguageCode -ceq 'it' -and $SourceValue -ceq 'No' -and $TargetValue -ceq 'No') { + return $true + } + + if ($LanguageCode -ceq 'it' -and $SourceValue -ceq $TargetValue -and $SourceValue -in @( + 'DEBUG BUILD' + )) { + return $true + } + + if ($LanguageCode -ceq 'ca' -and $SourceValue -ceq $TargetValue -and $SourceValue -in @( + '1 - Errors', + 'Error', + 'Global', + 'Local', + 'Manifest', + 'Manifests', + 'No', + 'Notes:', + 'Text' + )) { + return $true + } + + if ($LanguageCode -ceq 'pt_PT' -and $SourceValue -ceq $TargetValue -and $SourceValue -in @( + 'Global', + 'Local' + )) { + return $true + } + + if ($LanguageCode -ceq 'hr' -and $SourceValue -ceq $TargetValue -and $SourceValue -in @( + 'Manifest', + 'Status', + 'URL' + )) { + return $true + } + + if ($LanguageCode -ceq 'es' -and $SourceValue -ceq $TargetValue -and $SourceValue -in @( + 'Error', + 'Global', + 'Local', + 'No', + 'URL' + )) { + return $true + } + + if ($LanguageCode -ceq 'es-MX' -and $SourceValue -ceq $TargetValue -and $SourceValue -in @( + 'Error', + 'Global', + 'Local', + 'No', + 'URL', + 'Url' + )) { + return $true + } + + if ($LanguageCode -ceq 'fr' -and $SourceValue -ceq $TargetValue -and $SourceValue -in @( + 'Ascendant', + 'Descendant', + 'Global', + 'Local', + 'Machine | Global', + 'Navigation', + 'Portable', + 'Source', + 'Sources', + 'Verbose', + 'Version', + 'installation', + 'option', + 'version {0}', + '{0} minutes' + )) { + return $true + } + + if ($LanguageCode -ceq 'nl' -and $SourceValue -ceq $TargetValue -and $SourceValue -in @( + '1 week', + 'Filters', + 'Manifest', + 'Status', + 'Updates', + 'URL', + 'update', + 'website', + '{0} status' + )) { + return $true + } + + if ($LanguageCode -ceq 'sk' -and $SourceValue -ceq $TargetValue -and $SourceValue -in @( + 'Manifest', + 'Text' + )) { + return $true + } + + if ($LanguageCode -ceq 'de' -and $SourceValue -ceq $TargetValue -and $SourceValue -in @( + 'Global', + 'Manifest', + 'Name', + 'Repository', + 'Start', + 'Status', + 'Text', + 'Updates', + 'URL', + 'Verbose', + 'Version', + 'Version:', + 'optional', + '{package} Installation', + '{package} Update' + )) { + return $true + } + + if ($LanguageCode -ceq 'sv' -and $SourceValue -ceq $TargetValue -and $SourceValue -in @( + 'Global', + 'Manifest', + 'Start', + 'Status', + 'Text', + 'Version', + 'Version:', + 'installation', + 'version {0}', + '{0} installation', + '{0} status', + '{pm} version:' + )) { + return $true + } + + if ($LanguageCode -ceq 'id' -and $SourceValue -ceq $TargetValue -and $SourceValue -in @( + 'Global', + 'Grid', + 'Manifest', + 'Status', + 'URL', + 'Verbose', + '{0} status' + )) { + return $true + } + + if ($LanguageCode -ceq 'fil' -and $SourceValue -ceq $TargetValue -and $SourceValue -in @( + 'Android Subsystem', + 'Default', + 'Error', + 'Global', + 'Grid', + 'Machine | Global', + 'Manifest', + 'OK', + 'Ok', + 'Package', + 'Password', + 'Portable', + 'Portable mode', + 'PreRelease', + 'Repository', + 'Source', + 'Source:', + 'Telemetry', + 'Text', + 'URL', + 'UniGetUI', + 'UniGetUI - {0} {1}', + 'User', + 'Username', + 'Verbose', + 'website', + 'library' + )) { + return $true + } + + if ($LanguageCode -ceq 'tl' -and $SourceValue -ceq $TargetValue -and $SourceValue -in @( + 'Machine | Global' + )) { + return $true + } + + return $false +} diff --git a/scripts/translation/Languages/LanguageData.psm1 b/scripts/translation/Languages/LanguageData.psm1 new file mode 100644 index 0000000..88f85d4 --- /dev/null +++ b/scripts/translation/Languages/LanguageData.psm1 @@ -0,0 +1,416 @@ +Set-StrictMode -Version Latest +$ErrorActionPreference = 'Stop' + +$script:ProjectRoot = [System.IO.Path]::GetFullPath((Join-Path $PSScriptRoot '..\..\..')) +$script:LanguageRemap = [ordered]@{ + 'pt-BR' = 'pt_BR' + 'pt-PT' = 'pt_PT' + 'nn-NO' = 'nn' + 'uk' = 'ua' + 'zh-Hans' = 'zh_CN' + 'zh-Hant' = 'zh_TW' +} + +$script:LanguageFlagsRemap = [ordered]@{ + 'af' = 'za' + 'ar' = 'sa' + 'bs' = 'ba' + 'ca' = 'ad' + 'cs' = 'cz' + 'da' = 'dk' + 'el' = 'gr' + 'en' = 'gb' + 'eo' = 'https://upload.wikimedia.org/wikipedia/commons/f/f5/Flag_of_Esperanto.svg' + 'es-MX' = 'mx' + 'et' = 'ee' + 'fa' = 'ir' + 'fil' = 'ph' + 'gl' = 'es' + 'he' = 'il' + 'hi' = 'in' + 'ja' = 'jp' + 'ka' = 'ge' + 'ko' = 'kr' + 'ku' = 'iq' + 'mr' = 'in' + 'nb' = 'no' + 'nn' = 'no' + 'pt_BR' = 'br' + 'pt_PT' = 'pt' + 'si' = 'lk' + 'sr' = 'rs' + 'sv' = 'se' + 'sl' = 'si' + 'ta' = 'in' + 'vi' = 'vn' + 'zh_CN' = 'cn' + 'zh_TW' = 'tw' + 'zh' = 'cn' + 'bn' = 'bd' + 'tg' = 'ph' + 'sq' = 'al' + 'kn' = 'in' + 'sa' = 'in' + 'gu' = 'in' + 'ur' = 'pk' + 'be' = 'by' +} + +function Get-ProjectRoot { + return $script:ProjectRoot +} + +function Get-ContributorsListPath { + return Join-Path (Get-ProjectRoot) 'src\UniGetUI.Core.Data\Assets\Data\Contributors.list' +} + +function Get-TranslatorsJsonPath { + return Join-Path (Get-ProjectRoot) 'src\Languages\Data\Translators.json' +} + +function Get-TranslatedPercentagesJsonPath { + return Join-Path (Get-ProjectRoot) 'src\Languages\Data\TranslatedPercentages.json' +} + +function Get-LanguagesReferenceJsonPath { + return Join-Path (Get-ProjectRoot) 'src\Languages\Data\LanguagesReference.json' +} + +function Get-LanguagesDirectoryPath { + return Join-Path (Get-ProjectRoot) 'src\Languages' +} + +function Read-JsonDictionary { + param( + [Parameter(Mandatory = $true)] + [string]$Path + ) + + if (-not (Test-Path -Path $Path -PathType Leaf)) { + return [ordered]@{} + } + + $content = [System.IO.File]::ReadAllText($Path) + if ([string]::IsNullOrWhiteSpace($content)) { + return [ordered]@{} + } + + $parsed = $content | ConvertFrom-Json -AsHashtable + if ($null -eq $parsed) { + return [ordered]@{} + } + + if (-not ($parsed -is [System.Collections.IDictionary])) { + throw "JSON root must be an object: $Path" + } + + return $parsed +} + +function Get-ContributorsList { + $path = Get-ContributorsListPath + if (-not (Test-Path -Path $path -PathType Leaf)) { + return @() + } + + return @( + Get-Content -Path $path -Encoding UTF8 | + ForEach-Object { $_.Trim() } | + Where-Object { -not [string]::IsNullOrWhiteSpace($_) } + ) +} + +function Get-LanguageCredits { + return Read-JsonDictionary -Path (Get-TranslatorsJsonPath) +} + +function Get-TranslatedPercentages { + return Read-JsonDictionary -Path (Get-TranslatedPercentagesJsonPath) +} + +function Get-LanguageReference { + return Read-JsonDictionary -Path (Get-LanguagesReferenceJsonPath) +} + +function Get-LanguageRemap { + return [ordered]@{} + $script:LanguageRemap +} + +function Get-LanguageFlagsRemap { + return [ordered]@{} + $script:LanguageFlagsRemap +} + +function Get-TranslatorsFromCredits { + param( + [AllowNull()] + [string]$Credits + ) + + if ([string]::IsNullOrWhiteSpace($Credits)) { + return @() + } + + $contributors = Get-ContributorsList + $translatorLookup = @{} + foreach ($translator in ($Credits -split ',')) { + $trimmed = $translator.Trim() + if ([string]::IsNullOrWhiteSpace($trimmed)) { + continue + } + + $wasPrefixed = $trimmed.StartsWith('@', [System.StringComparison]::Ordinal) + if ($wasPrefixed) { + $trimmed = $trimmed.Substring(1) + } + + $link = '' + if ($wasPrefixed -or ($contributors -contains $trimmed)) { + $link = "https://github.com/$trimmed" + } + + $translatorLookup[$trimmed] = [pscustomobject]@{ + name = $trimmed + link = $link + } + } + + return @( + $translatorLookup.Keys | + Sort-Object { $_.ToLowerInvariant() } | + ForEach-Object { $translatorLookup[$_] } + ) +} + +function ConvertTo-TranslatorMarkdown { + param( + [AllowNull()] + [object]$Translators + ) + + if ($null -eq $Translators) { + return '' + } + + $translatorItems = @() + if ($Translators -is [string]) { + $translatorItems = Get-TranslatorsFromCredits -Credits $Translators + } + else { + $translatorItems = @($Translators) + } + + $formatted = foreach ($translator in $translatorItems) { + $name = [string]$translator.name + $link = if ($null -eq $translator.link) { '' } else { [string]$translator.link } + if ([string]::IsNullOrWhiteSpace($link)) { + $name + } + else { + "[$name]($link)" + } + } + + return ($formatted -join ', ') +} + +function Get-LanguageFilePathMap { + param( + [switch]$AbsolutePaths + ) + + $languageReference = Get-LanguageReference + $languagesDirectory = Get-LanguagesDirectoryPath + $result = [ordered]@{} + + foreach ($entry in $languageReference.GetEnumerator()) { + $code = [string]$entry.Key + if ($code -eq 'default') { + continue + } + + $fileName = "lang_$code.json" + $result[$code] = if ($AbsolutePaths.IsPresent) { Join-Path $languagesDirectory $fileName } else { $fileName } + } + + return $result +} + +function Get-MarkdownSupportLangs { + return Get-MarkdownTranslationsTable +} + +function Get-MarkdownTranslationsTable { + param( + [switch]$IncludeZeroPercent, + + [switch]$IncludeLanguageCode, + + [switch]$IncludeFileColumn, + + [bool]$IncludeTranslatedColumn = $true, + + [bool]$IncludeCreditsColumn = $true, + + [string]$MissingCreditsText = '' + ) + + $languageReference = Get-LanguageReference + $translationPercentages = Get-TranslatedPercentages + $languageCredits = Get-LanguageCredits + $flagRemap = Get-LanguageFlagsRemap + $languagesDirectory = Get-LanguagesDirectoryPath + + $lines = New-Object System.Collections.Generic.List[string] + $headers = @('Language') + $alignments = @(':--') + + if ($IncludeLanguageCode.IsPresent) { + $headers += 'Code' + $alignments += ':--' + } + + if ($IncludeTranslatedColumn) { + $headers += 'Translated' + $alignments += ':--' + } + + if ($IncludeFileColumn.IsPresent) { + $headers += 'File' + $alignments += ':--' + } + + if ($IncludeCreditsColumn) { + $headers += 'Contributor(s)' + $alignments += '---' + } + + $lines.Add('| ' + ($headers -join ' | ') + ' |') + $lines.Add('| ' + ($alignments -join ' | ') + ' |') + + foreach ($entry in $languageReference.GetEnumerator()) { + $languageCode = [string]$entry.Key + if ($languageCode -eq 'default') { + continue + } + + $languageFilePath = Join-Path $languagesDirectory ("lang_$languageCode.json") + if (-not (Test-Path -Path $languageFilePath -PathType Leaf)) { + continue + } + + $percentage = if ($translationPercentages.Contains($languageCode)) { [string]$translationPercentages[$languageCode] } else { '100%' } + if ($percentage -eq '0%' -and -not $IncludeZeroPercent.IsPresent) { + continue + } + + $languageName = [string]$entry.Value + $flag = if ($flagRemap.Contains($languageCode)) { [string]$flagRemap[$languageCode] } else { $languageCode } + $credits = '' + if ($IncludeCreditsColumn) { + $credits = if ($languageCredits.Contains($languageCode)) { + ConvertTo-TranslatorMarkdown -Translators $languageCredits[$languageCode] + } + else { + '' + } + + if ([string]::IsNullOrWhiteSpace($credits) -and -not [string]::IsNullOrWhiteSpace($MissingCreditsText)) { + $credits = $MissingCreditsText + } + } + + $flagImageSource = if ([string]$flag -match '^[a-z]+://') { [string]$flag } else { "https://flagcdn.com/$flag.svg" } + + $row = New-Object System.Collections.Generic.List[string] + $row.Add("   $languageName") + + if ($IncludeLanguageCode.IsPresent) { + $row.Add(('`{0}`' -f $languageCode)) + } + + if ($IncludeTranslatedColumn) { + $row.Add($percentage) + } + + if ($IncludeFileColumn.IsPresent) { + $relativeLanguageFilePath = (Join-Path 'src/Languages' ("lang_{0}.json" -f $languageCode)) -replace '\\', '/' + $row.Add("[lang_$languageCode.json]($relativeLanguageFilePath)") + } + + if ($IncludeCreditsColumn) { + $row.Add($credits) + } + + $lines.Add('| ' + ($row -join ' | ') + ' |') + } + + $lines.Add('') + return ($lines -join [Environment]::NewLine) +} + +function Get-TranslationDocumentationMarkdown { + $coverageTable = Get-MarkdownTranslationsTable -IncludeZeroPercent -IncludeLanguageCode -IncludeFileColumn -IncludeCreditsColumn:$false + $contributorsTable = Get-MarkdownTranslationsTable -IncludeZeroPercent -IncludeLanguageCode -IncludeTranslatedColumn:$false + + $sections = @( + '# Translations', + '', + 'UniGetUI includes translations for the languages listed below.', + '', + 'This page lists the supported languages, each locale file, current completion status, and the credited contributors for each translation.', + '', + 'If you would like to help improve a translation or report an issue, please open an issue or submit a pull request.', + '', + 'Translation discussion and coordination also happens in [GitHub discussion #4510](https://github.com/Devolutions/UniGetUI/discussions/4510).', + '', + '## Language Coverage', + '', + $coverageTable.TrimEnd(), + '', + '## Contributors', + '', + 'We are grateful to everyone who contributes translations to UniGetUI. Contributor credits are sourced from [Translators.json](src/Languages/Data/Translators.json). If you would like to be added to or removed from the list for a particular language, please open a pull request.', + '', + $contributorsTable.TrimEnd(), + '', + '## Maintaining Translation Data', + '', + 'The tables in this document are generated from the checked-in translation metadata. Completion is computed against the active English keys in `lang_en.json`; keys below the legacy boundary marker are excluded from the percentage.', + '', + 'To refresh translated percentages, contributor metadata, and this document after locale changes, run:', + '', + '```powershell', + 'pwsh ./scripts/translation/Sync-TranslationMetadata.ps1 -AllLanguages -UpdateTranslationDoc', + '```', + '', + 'To inspect the current status without modifying files, run:', + '', + '```powershell', + 'pwsh ./scripts/translation/Get-TranslationStatus.ps1 -OutputFormat Markdown -OnlyIncomplete', + '```', + '' + ) + + return (($sections -join [Environment]::NewLine) + [Environment]::NewLine) +} + +Export-ModuleMember -Function @( + 'Get-ProjectRoot', + 'Get-ContributorsListPath', + 'Get-TranslatorsJsonPath', + 'Get-TranslatedPercentagesJsonPath', + 'Get-LanguagesReferenceJsonPath', + 'Get-LanguagesDirectoryPath', + 'Get-ContributorsList', + 'Get-LanguageCredits', + 'Get-TranslatedPercentages', + 'Get-LanguageReference', + 'Get-LanguageRemap', + 'Get-LanguageFlagsRemap', + 'Get-TranslatorsFromCredits', + 'ConvertTo-TranslatorMarkdown', + 'Get-MarkdownSupportLangs', + 'Get-MarkdownTranslationsTable', + 'Get-TranslationDocumentationMarkdown', + 'Get-LanguageFilePathMap' +) \ No newline at end of file diff --git a/scripts/translation/Languages/LanguageReference.ps1 b/scripts/translation/Languages/LanguageReference.ps1 new file mode 100644 index 0000000..b7b90e7 --- /dev/null +++ b/scripts/translation/Languages/LanguageReference.ps1 @@ -0,0 +1,19 @@ +[CmdletBinding()] +param( + [switch]$AsJson, + [switch]$AbsolutePaths +) + +Set-StrictMode -Version Latest +$ErrorActionPreference = 'Stop' + +Import-Module (Join-Path $PSScriptRoot 'LanguageData.psm1') -Force + +$languageFileMap = Get-LanguageFilePathMap -AbsolutePaths:$AbsolutePaths.IsPresent + +if ($AsJson.IsPresent) { + $languageFileMap | ConvertTo-Json -Depth 5 + return +} + +$languageFileMap \ No newline at end of file diff --git a/scripts/translation/Languages/TranslationJsonTools.ps1 b/scripts/translation/Languages/TranslationJsonTools.ps1 new file mode 100644 index 0000000..0caabb5 --- /dev/null +++ b/scripts/translation/Languages/TranslationJsonTools.ps1 @@ -0,0 +1,497 @@ +Set-StrictMode -Version Latest + +$script:TranslationLegacyBoundaryKey = '__LEGACY_TRANSLATION_KEYS_BELOW__' +$script:TranslationLegacyBoundaryValue = 'Legacy translation keys below are kept for backward compatibility with older UniGetUI builds. Do not translate or remove yet.' + +function Assert-Command { + param( + [Parameter(Mandatory = $true)] + [string]$Name + ) + + if (-not (Get-Command -Name $Name -ErrorAction SilentlyContinue)) { + throw "Required command not found on PATH: $Name" + } +} + +function Get-FullPath { + param( + [Parameter(Mandatory = $true)] + [string]$Path + ) + + return [System.IO.Path]::GetFullPath($Path) +} + +function New-Utf8File { + param( + [Parameter(Mandatory = $true)] + [string]$Path, + + [Parameter(Mandatory = $true)] + [AllowEmptyString()] + [string]$Content + ) + + $directory = Split-Path -Path $Path -Parent + if (-not [string]::IsNullOrWhiteSpace($directory)) { + New-Item -Path $directory -ItemType Directory -Force | Out-Null + } + + $encoding = [System.Text.UTF8Encoding]::new($false) + [System.IO.File]::WriteAllText($Path, $Content, $encoding) +} + +function New-OrderedStringMap { + return [System.Collections.Specialized.OrderedDictionary]::new([System.StringComparer]::Ordinal) +} + +function Assert-NoDuplicateJsonKeys { + param( + [Parameter(Mandatory = $true)] + [string]$Content, + + [Parameter(Mandatory = $true)] + [string]$Path + ) + + $pattern = [regex]'(?m)^\s*"((?:\\.|[^"])*)"\s*:' + $seen = [System.Collections.Generic.HashSet[string]]::new([System.StringComparer]::Ordinal) + $duplicates = New-Object System.Collections.Generic.List[string] + + foreach ($match in $pattern.Matches($Content)) { + $key = [regex]::Unescape($match.Groups[1].Value) + if (-not $seen.Add($key) -and -not $duplicates.Contains($key)) { + $duplicates.Add($key) + } + } + + if ($duplicates.Count -gt 0) { + throw "JSON file contains duplicate key(s): $($duplicates -join ', '). Path: $Path" + } +} + +function Read-OrderedJsonMap { + param( + [Parameter(Mandatory = $true)] + [string]$Path + ) + + if (-not (Test-Path -Path $Path -PathType Leaf)) { + return (New-OrderedStringMap) + } + + $content = [System.IO.File]::ReadAllText((Get-FullPath -Path $Path)) + return Convert-JsonContentToOrderedMap -Content $content -Path $Path -DetectDuplicates +} + +function Read-OrderedJsonMapPermissive { + param( + [Parameter(Mandatory = $true)] + [string]$Path + ) + + if (-not (Test-Path -Path $Path -PathType Leaf)) { + return (New-OrderedStringMap) + } + + $content = [System.IO.File]::ReadAllText((Get-FullPath -Path $Path)) + return Convert-JsonContentToOrderedMap -Content $content -Path $Path +} + +function Convert-JsonContentToOrderedMap { + param( + [Parameter(Mandatory = $true)] + [AllowEmptyString()] + [string]$Content, + + [Parameter(Mandatory = $true)] + [string]$Path, + + [switch]$DetectDuplicates + ) + + $result = New-OrderedStringMap + if ([string]::IsNullOrWhiteSpace($Content)) { + return $result + } + + if ($DetectDuplicates) { + Assert-NoDuplicateJsonKeys -Content $Content -Path $Path + } + + $document = [System.Text.Json.JsonDocument]::Parse($Content) + try { + if ($document.RootElement.ValueKind -eq [System.Text.Json.JsonValueKind]::Null) { + return $result + } + + if ($document.RootElement.ValueKind -ne [System.Text.Json.JsonValueKind]::Object) { + throw "JSON file must contain a flat object: $Path" + } + + foreach ($property in $document.RootElement.EnumerateObject()) { + if ($property.Value.ValueKind -eq [System.Text.Json.JsonValueKind]::Object -or $property.Value.ValueKind -eq [System.Text.Json.JsonValueKind]::Array) { + throw "JSON file must contain a flat object with string values only: $Path" + } + + if ($property.Value.ValueKind -eq [System.Text.Json.JsonValueKind]::String) { + $result[$property.Name] = $property.Value.GetString() + continue + } + + if ($property.Value.ValueKind -eq [System.Text.Json.JsonValueKind]::Null) { + $result[$property.Name] = '' + continue + } + + $result[$property.Name] = $property.Value.ToString() + } + } + finally { + $document.Dispose() + } + + return $result +} + +function ConvertTo-JsonStringLiteral { + param( + [Parameter(Mandatory = $true)] + [AllowEmptyString()] + [string]$Value + ) + + return ($Value | ConvertTo-Json -Compress) +} + +function Write-OrderedJsonMap { + param( + [Parameter(Mandatory = $true)] + [string]$Path, + + [Parameter(Mandatory = $true)] + [System.Collections.IDictionary]$Map + ) + + $lines = New-Object System.Collections.Generic.List[string] + $lines.Add('{') + + $index = 0 + $count = $Map.Count + foreach ($entry in $Map.GetEnumerator()) { + $index += 1 + $line = ' {0}: {1}' -f (ConvertTo-JsonStringLiteral -Value ([string]$entry.Key)), (ConvertTo-JsonStringLiteral -Value ([string]$entry.Value)) + if ($index -lt $count) { + $line += ',' + } + + $lines.Add($line) + } + + $lines.Add('}') + New-Utf8File -Path $Path -Content (($lines -join "`r`n") + "`r`n") +} + +function Get-TranslationLegacyBoundaryKey { + return $script:TranslationLegacyBoundaryKey +} + +function Get-TranslationLegacyBoundaryValue { + return $script:TranslationLegacyBoundaryValue +} + +function Split-TranslationMapAtBoundary { + param( + [Parameter(Mandatory = $true)] + [System.Collections.IDictionary]$Map + ) + + $boundaryKey = Get-TranslationLegacyBoundaryKey + $activeMap = New-OrderedStringMap + $legacyMap = New-OrderedStringMap + $hasBoundary = $false + $boundaryReached = $false + + foreach ($entry in $Map.GetEnumerator()) { + $key = [string]$entry.Key + $value = [string]$entry.Value + + if ($key -ceq $boundaryKey) { + $hasBoundary = $true + $boundaryReached = $true + continue + } + + if ($boundaryReached) { + $legacyMap[$key] = $value + } + else { + $activeMap[$key] = $value + } + } + + return [pscustomobject]@{ + HasBoundary = $hasBoundary + ActiveMap = $activeMap + LegacyMap = $legacyMap + } +} + +function Join-TranslationMapWithBoundary { + param( + [Parameter(Mandatory = $true)] + [System.Collections.IDictionary]$ActiveMap, + + [Parameter(Mandatory = $true)] + [System.Collections.IDictionary]$LegacyMap, + + [switch]$IncludeBoundary + ) + + $result = New-OrderedStringMap + foreach ($entry in $ActiveMap.GetEnumerator()) { + $result[[string]$entry.Key] = [string]$entry.Value + } + + if ($IncludeBoundary) { + $result[(Get-TranslationLegacyBoundaryKey)] = Get-TranslationLegacyBoundaryValue + } + + foreach ($entry in $LegacyMap.GetEnumerator()) { + $result[[string]$entry.Key] = [string]$entry.Value + } + + return $result +} + +function Test-OrderedStringMapsEqual { + param( + [Parameter(Mandatory = $true)] + [System.Collections.IDictionary]$Left, + + [Parameter(Mandatory = $true)] + [System.Collections.IDictionary]$Right + ) + + if ($Left.Count -ne $Right.Count) { + return $false + } + + $leftEntries = @($Left.GetEnumerator()) + $rightEntries = @($Right.GetEnumerator()) + for ($index = 0; $index -lt $leftEntries.Count; $index += 1) { + if ([string]$leftEntries[$index].Key -cne [string]$rightEntries[$index].Key) { + return $false + } + + if ([string]$leftEntries[$index].Value -cne [string]$rightEntries[$index].Value) { + return $false + } + } + + return $true +} + +function Invoke-CirupJson { + param( + [Parameter(Mandatory = $true)] + [string[]]$Arguments + ) + + Assert-Command -Name 'cirup' + + $output = & cirup @Arguments --output-format json + if ($LASTEXITCODE -ne 0) { + throw "cirup command failed: cirup $($Arguments -join ' ')" + } + + $jsonText = [string]::Join([Environment]::NewLine, @($output)).Trim() + if ([string]::IsNullOrWhiteSpace($jsonText)) { + return @() + } + + $parsed = $jsonText | ConvertFrom-Json -AsHashtable + return @($parsed) +} + +function Get-RepositoryRoot { + param( + [Parameter(Mandatory = $true)] + [string]$WorkingDirectory + ) + + $repoRoot = & git -C $WorkingDirectory rev-parse --show-toplevel + if ($LASTEXITCODE -ne 0 -or [string]::IsNullOrWhiteSpace($repoRoot)) { + throw "Unable to resolve git repository root from '$WorkingDirectory'." + } + + return $repoRoot.Trim() +} + +function Get-RepoRelativePath { + param( + [Parameter(Mandatory = $true)] + [string]$RepositoryRoot, + + [Parameter(Mandatory = $true)] + [string]$FilePath + ) + + $repoRootFull = Get-FullPath -Path $RepositoryRoot + $filePathFull = Get-FullPath -Path $FilePath + $repoRootWithSeparator = $repoRootFull.TrimEnd([System.IO.Path]::DirectorySeparatorChar, [System.IO.Path]::AltDirectorySeparatorChar) + [System.IO.Path]::DirectorySeparatorChar + + if (-not $filePathFull.StartsWith($repoRootWithSeparator, [System.StringComparison]::OrdinalIgnoreCase)) { + throw "File '$filePathFull' is not located under repository root '$repoRootFull'." + } + + return [System.IO.Path]::GetRelativePath($repoRootFull, $filePathFull).Replace('\', '/') +} + +function Get-SafeLabel { + param( + [Parameter(Mandatory = $true)] + [string]$Value + ) + + $safe = $Value -replace '[^A-Za-z0-9._-]+', '-' + $safe = $safe.Trim('-') + if ([string]::IsNullOrWhiteSpace($safe)) { + return 'base' + } + + return $safe +} + +function Get-PatchBaseName { + param( + [Parameter(Mandatory = $true)] + [string]$NeutralJsonPath + ) + + $stem = [System.IO.Path]::GetFileNameWithoutExtension($NeutralJsonPath) + if ($stem -match '^(.*)_en$' -and -not [string]::IsNullOrWhiteSpace($matches[1])) { + return $matches[1] + } + + return $stem +} + +function Get-LanguagesReferencePath { + param( + [Parameter(Mandatory = $true)] + [string]$NeutralJsonPath + ) + + $languagesDirectory = Split-Path -Path (Get-FullPath -Path $NeutralJsonPath) -Parent + return Join-Path $languagesDirectory 'Data\LanguagesReference.json' +} + +function Assert-LanguageCodeKnown { + param( + [Parameter(Mandatory = $true)] + [string]$LanguagesReferencePath, + + [Parameter(Mandatory = $true)] + [string]$LanguageCode + ) + + $referenceMap = Read-OrderedJsonMap -Path $LanguagesReferencePath + if (-not $referenceMap.Contains($LanguageCode)) { + throw "Unknown language code '$LanguageCode'. Expected one of the language codes from $LanguagesReferencePath" + } +} + +function Test-NeedsTranslation { + param( + [Parameter(Mandatory = $true)] + [string]$Key, + + [Parameter(Mandatory = $true)] + [System.Collections.IDictionary]$SourceMap, + + [Parameter(Mandatory = $true)] + [System.Collections.IDictionary]$TargetMap + ) + + if (-not $TargetMap.Contains($Key)) { + return $true + } + + $targetValue = [string]$TargetMap[$Key] + if ([string]::IsNullOrWhiteSpace($targetValue)) { + return $true + } + + return $targetValue -ceq [string]$SourceMap[$Key] +} + +function Get-PlaceholderTokens { + param( + [Parameter(Mandatory = $true)] + [AllowEmptyString()] + [string]$Value + ) + + $tokens = foreach ($match in [regex]::Matches($Value, '\{[A-Za-z0-9_]+(?:,[^}:]+)?(?::[^}]+)?\}')) { + $match.Value + } + + return @($tokens | Sort-Object) +} + +function Get-HtmlTokens { + param( + [Parameter(Mandatory = $true)] + [AllowEmptyString()] + [string]$Value + ) + + $tokens = foreach ($match in [regex]::Matches($Value, ']+?>')) { + $match.Value + } + + return @($tokens | Sort-Object) +} + +function Get-NewlineCount { + param( + [Parameter(Mandatory = $true)] + [AllowEmptyString()] + [string]$Value + ) + + return ([regex]::Matches($Value, "`r`n|`n")).Count +} + +function Assert-TranslationStructure { + param( + [Parameter(Mandatory = $true)] + [AllowEmptyString()] + [string]$SourceValue, + + [Parameter(Mandatory = $true)] + [AllowEmptyString()] + [string]$TranslatedValue, + + [Parameter(Mandatory = $true)] + [string]$Key + ) + + $sourcePlaceholderSignature = (Get-PlaceholderTokens -Value $SourceValue) -join "`n" + $translatedPlaceholderSignature = (Get-PlaceholderTokens -Value $TranslatedValue) -join "`n" + if ($sourcePlaceholderSignature -ne $translatedPlaceholderSignature) { + throw "Placeholder mismatch for key '$Key'." + } + + $sourceHtmlSignature = (Get-HtmlTokens -Value $SourceValue) -join "`n" + $translatedHtmlSignature = (Get-HtmlTokens -Value $TranslatedValue) -join "`n" + if ($sourceHtmlSignature -ne $translatedHtmlSignature) { + throw "HTML fragment mismatch for key '$Key'." + } + + if ((Get-NewlineCount -Value $SourceValue) -ne (Get-NewlineCount -Value $TranslatedValue)) { + throw "Line-break mismatch for key '$Key'." + } +} \ No newline at end of file diff --git a/scripts/translation/Languages/TranslationSourceTools.ps1 b/scripts/translation/Languages/TranslationSourceTools.ps1 new file mode 100644 index 0000000..8675120 --- /dev/null +++ b/scripts/translation/Languages/TranslationSourceTools.ps1 @@ -0,0 +1,323 @@ +Set-StrictMode -Version Latest + +. (Join-Path $PSScriptRoot 'TranslationJsonTools.ps1') + +$script:SupportedSourceExtensions = [System.Collections.Generic.HashSet[string]]::new([System.StringComparer]::OrdinalIgnoreCase) +[void]$script:SupportedSourceExtensions.Add('.cs') +[void]$script:SupportedSourceExtensions.Add('.xaml') +[void]$script:SupportedSourceExtensions.Add('.axaml') + +$script:ExcludedDirectoryNames = [System.Collections.Generic.HashSet[string]]::new([System.StringComparer]::OrdinalIgnoreCase) +foreach ($name in @('.git', '.vs', 'bin', 'obj', 'generated', 'node_modules', 'packages')) { + [void]$script:ExcludedDirectoryNames.Add($name) +} + +function Resolve-TranslationSyncRepositoryRoot { + param( + [string]$RepositoryRoot + ) + + if (-not [string]::IsNullOrWhiteSpace($RepositoryRoot)) { + return Get-FullPath -Path $RepositoryRoot + } + + return [System.IO.Path]::GetFullPath((Join-Path $PSScriptRoot '..\..\..')) +} + +function Resolve-EnglishLanguageFilePath { + param( + [Parameter(Mandatory = $true)] + [string]$ResolvedRepositoryRoot, + + [string]$EnglishFilePath + ) + + if (-not [string]::IsNullOrWhiteSpace($EnglishFilePath)) { + return Get-FullPath -Path $EnglishFilePath + } + + return Join-Path $ResolvedRepositoryRoot 'src\Languages\lang_en.json' +} + +function Test-TranslationSourceFileIncluded { + param( + [Parameter(Mandatory = $true)] + [System.IO.FileInfo]$File, + + [Parameter(Mandatory = $true)] + [string]$ResolvedRepositoryRoot + ) + + if (-not $script:SupportedSourceExtensions.Contains($File.Extension)) { + return $false + } + + $relativePath = [System.IO.Path]::GetRelativePath($ResolvedRepositoryRoot, $File.FullName).Replace('\', '/') + foreach ($segment in $relativePath.Split('/')) { + if ($script:ExcludedDirectoryNames.Contains($segment)) { + return $false + } + } + + if ($relativePath -like 'src/Languages/lang_*.json') { + return $false + } + + return $relativePath.StartsWith('src/', [System.StringComparison]::OrdinalIgnoreCase) +} + +function Get-TranslationSourceFiles { + param( + [Parameter(Mandatory = $true)] + [string]$ResolvedRepositoryRoot + ) + + return @( + Get-ChildItem -Path $ResolvedRepositoryRoot -File -Recurse -ErrorAction SilentlyContinue | + Where-Object { Test-TranslationSourceFileIncluded -File $_ -ResolvedRepositoryRoot $ResolvedRepositoryRoot } | + Sort-Object FullName + ) +} + +function Get-LineNumberFromIndex { + param( + [Parameter(Mandatory = $true)] + [string]$Text, + + [Parameter(Mandatory = $true)] + [int]$Index + ) + + if ($Index -le 0) { + return 1 + } + + return ([regex]::Matches($Text.Substring(0, $Index), "`r`n|`n")).Count + 1 +} + +function Convert-CSharpStringLiteralValue { + param( + [Parameter(Mandatory = $true)] + [string]$Literal + ) + + if ($Literal.StartsWith('@"', [System.StringComparison]::Ordinal)) { + return $Literal.Substring(2, $Literal.Length - 3).Replace('""', '"') + } + + return [regex]::Unescape($Literal.Substring(1, $Literal.Length - 2)) +} + +function Add-TranslationSourceKey { + param( + [Parameter(Mandatory = $true)] + [string]$Key, + + [Parameter(Mandatory = $true)] + [string]$SourcePath, + + [Parameter(Mandatory = $true)] + [int]$LineNumber, + + [Parameter(Mandatory = $true)] + [System.Collections.IList]$KeyOrder, + + [Parameter(Mandatory = $true)] + [System.Collections.IDictionary]$SourcesByKey + ) + + if ([string]::IsNullOrWhiteSpace($Key)) { + return + } + + if (-not $SourcesByKey.Contains($Key)) { + $SourcesByKey[$Key] = New-Object System.Collections.Generic.List[string] + $KeyOrder.Add($Key) + } + + $location = '{0}:{1}' -f $SourcePath.Replace('\', '/'), $LineNumber + $locations = [System.Collections.Generic.List[string]]$SourcesByKey[$Key] + if (-not $locations.Contains($location)) { + $locations.Add($location) + } +} + +function Add-TranslationSourceWarning { + param( + [Parameter(Mandatory = $true)] + [string]$Type, + + [Parameter(Mandatory = $true)] + [string]$SourcePath, + + [Parameter(Mandatory = $true)] + [int]$LineNumber, + + [Parameter(Mandatory = $true)] + [string]$Message, + + [Parameter(Mandatory = $true)] + [System.Collections.IList]$Warnings + ) + + $Warnings.Add([pscustomobject]@{ + Type = $Type + Path = $SourcePath.Replace('\', '/') + Line = $LineNumber + Message = $Message + }) +} + +function Get-CSharpTranslationMatches { + param( + [Parameter(Mandatory = $true)] + [string]$FilePath, + + [Parameter(Mandatory = $true)] + [string]$Content, + + [Parameter(Mandatory = $true)] + [System.Collections.IList]$KeyOrder, + + [Parameter(Mandatory = $true)] + [System.Collections.IDictionary]$SourcesByKey, + + [Parameter(Mandatory = $true)] + [System.Collections.IList]$Warnings + ) + + $literalPattern = [regex]'CoreTools\s*\.\s*(?:Translate|AutoTranslated)\(\s*(?@"(?:[^"]|"")*"|"(?:\\.|[^"\\])*")' + foreach ($match in $literalPattern.Matches($Content)) { + $literal = [string]$match.Groups['literal'].Value + $lineNumber = Get-LineNumberFromIndex -Text $Content -Index $match.Index + Add-TranslationSourceKey -Key (Convert-CSharpStringLiteralValue -Literal $literal) -SourcePath $FilePath -LineNumber $lineNumber -KeyOrder $KeyOrder -SourcesByKey $SourcesByKey + } + + $interpolatedPattern = [regex]'CoreTools\s*\.\s*Translate\(\s*\$@?"' + foreach ($match in $interpolatedPattern.Matches($Content)) { + $lineNumber = Get-LineNumberFromIndex -Text $Content -Index $match.Index + Add-TranslationSourceWarning -Type 'InterpolatedTranslateCall' -SourcePath $FilePath -LineNumber $lineNumber -Message 'Interpolated CoreTools.Translate call is not synchronized automatically.' -Warnings $Warnings + } +} + +function Get-TranslatedTextBlockMatches { + param( + [Parameter(Mandatory = $true)] + [string]$FilePath, + + [Parameter(Mandatory = $true)] + [string]$Content, + + [Parameter(Mandatory = $true)] + [System.Collections.IList]$KeyOrder, + + [Parameter(Mandatory = $true)] + [System.Collections.IDictionary]$SourcesByKey + ) + + $translatedTextBlockPattern = [regex]'<(?[A-Za-z0-9_:.\-]+TranslatedTextBlock)\b[^>]*\bText="(?[^"]*)"' + foreach ($match in $translatedTextBlockPattern.Matches($Content)) { + $lineNumber = Get-LineNumberFromIndex -Text $Content -Index $match.Index + $text = [System.Net.WebUtility]::HtmlDecode([string]$match.Groups['text'].Value) + Add-TranslationSourceKey -Key $text -SourcePath $FilePath -LineNumber $lineNumber -KeyOrder $KeyOrder -SourcesByKey $SourcesByKey + } +} + +function Get-AvaloniaTranslateMarkupMatches { + param( + [Parameter(Mandatory = $true)] + [string]$FilePath, + + [Parameter(Mandatory = $true)] + [string]$Content, + + [Parameter(Mandatory = $true)] + [System.Collections.IList]$KeyOrder, + + [Parameter(Mandatory = $true)] + [System.Collections.IDictionary]$SourcesByKey, + + [Parameter(Mandatory = $true)] + [System.Collections.IList]$Warnings + ) + + $markupPattern = [regex]'\{t:Translate(?[^}]*)\}' + foreach ($match in $markupPattern.Matches($Content)) { + $body = [string]$match.Groups['body'].Value + $trimmedBody = $body.Trim() + $lineNumber = Get-LineNumberFromIndex -Text $Content -Index $match.Index + + if ([string]::IsNullOrWhiteSpace($trimmedBody)) { + Add-TranslationSourceWarning -Type 'EmptyMarkupTranslate' -SourcePath $FilePath -LineNumber $lineNumber -Message 'Empty {t:Translate} markup extension was ignored.' -Warnings $Warnings + continue + } + + $namedMatch = [regex]::Match($trimmedBody, '^Text\s*=\s*(?:''(?[^'']*)''|"(?[^"]*)")$') + if ($namedMatch.Success) { + $value = if ($namedMatch.Groups['single'].Success) { $namedMatch.Groups['single'].Value } else { $namedMatch.Groups['double'].Value } + Add-TranslationSourceKey -Key ([System.Net.WebUtility]::HtmlDecode($value)) -SourcePath $FilePath -LineNumber $lineNumber -KeyOrder $KeyOrder -SourcesByKey $SourcesByKey + continue + } + + Add-TranslationSourceKey -Key ([System.Net.WebUtility]::HtmlDecode($trimmedBody)) -SourcePath $FilePath -LineNumber $lineNumber -KeyOrder $KeyOrder -SourcesByKey $SourcesByKey + } +} + +function Get-TranslationSourceSnapshot { + param( + [string]$RepositoryRoot + ) + + $resolvedRepositoryRoot = Resolve-TranslationSyncRepositoryRoot -RepositoryRoot $RepositoryRoot + $sourceFiles = Get-TranslationSourceFiles -ResolvedRepositoryRoot $resolvedRepositoryRoot + $keyOrder = New-Object System.Collections.Generic.List[string] + $sourcesByKey = [ordered]@{} + $warnings = New-Object System.Collections.Generic.List[object] + + foreach ($file in $sourceFiles) { + $relativePath = [System.IO.Path]::GetRelativePath($resolvedRepositoryRoot, $file.FullName).Replace('\', '/') + $content = [System.IO.File]::ReadAllText($file.FullName) + + switch ($file.Extension.ToLowerInvariant()) { + '.cs' { + Get-CSharpTranslationMatches -FilePath $relativePath -Content $content -KeyOrder $keyOrder -SourcesByKey $sourcesByKey -Warnings $warnings + } + '.xaml' { + Get-TranslatedTextBlockMatches -FilePath $relativePath -Content $content -KeyOrder $keyOrder -SourcesByKey $sourcesByKey + } + '.axaml' { + Get-TranslatedTextBlockMatches -FilePath $relativePath -Content $content -KeyOrder $keyOrder -SourcesByKey $sourcesByKey + Get-AvaloniaTranslateMarkupMatches -FilePath $relativePath -Content $content -KeyOrder $keyOrder -SourcesByKey $sourcesByKey -Warnings $warnings + } + } + } + + $orderedKeyMap = New-OrderedStringMap + foreach ($key in $keyOrder) { + $orderedKeyMap[$key] = $key + } + + $sourceFilePaths = New-Object System.Collections.Generic.List[string] + foreach ($sourceFile in $sourceFiles) { + $sourceFilePaths.Add($sourceFile.FullName) + } + + $warningItems = New-Object System.Collections.Generic.List[object] + foreach ($warning in $warnings) { + $warningItems.Add($warning) + } + + $sourceFileArray = $sourceFilePaths.ToArray() + $keyOrderArray = $keyOrder.ToArray() + $warningArray = $warningItems.ToArray() + + $snapshot = New-Object -TypeName psobject + $snapshot | Add-Member -NotePropertyName RepositoryRoot -NotePropertyValue $resolvedRepositoryRoot + $snapshot | Add-Member -NotePropertyName SourceFiles -NotePropertyValue $sourceFileArray + $snapshot | Add-Member -NotePropertyName KeyOrder -NotePropertyValue $keyOrderArray + $snapshot | Add-Member -NotePropertyName Keys -NotePropertyValue $orderedKeyMap + $snapshot | Add-Member -NotePropertyName SourcesByKey -NotePropertyValue $sourcesByKey + $snapshot | Add-Member -NotePropertyName Warnings -NotePropertyValue $warningArray + + return $snapshot +} diff --git a/scripts/translation/Merge-TranslationDiffBatches.ps1 b/scripts/translation/Merge-TranslationDiffBatches.ps1 new file mode 100644 index 0000000..888eeb5 --- /dev/null +++ b/scripts/translation/Merge-TranslationDiffBatches.ps1 @@ -0,0 +1,39 @@ +[CmdletBinding()] +param( + [Parameter(Mandatory = $true)] + [string]$BatchDir, + + [Parameter(Mandatory = $true)] + [string]$OutputTranslatedPatch +) + +Set-StrictMode -Version Latest +$ErrorActionPreference = 'Stop' + +. (Join-Path $PSScriptRoot 'Languages\TranslationJsonTools.ps1') + +$batchRoot = Get-FullPath -Path $BatchDir +$outputPath = Get-FullPath -Path $OutputTranslatedPatch +$manifestPath = Join-Path $batchRoot 'manifest.json' + +if (-not (Test-Path -Path $manifestPath -PathType Leaf)) { + throw "Batch manifest not found: $manifestPath" +} + +$manifest = Get-Content -Path $manifestPath -Raw | ConvertFrom-Json +$mergedMap = New-OrderedStringMap + +foreach ($batch in @($manifest.batches | Sort-Object batchNumber)) { + $translatedPath = Join-Path $batchRoot ([string]$batch.translated) + if (-not (Test-Path -Path $translatedPath -PathType Leaf)) { + throw "Translated batch file not found: $translatedPath" + } + + $translatedMap = Read-OrderedJsonMap -Path $translatedPath + foreach ($entry in $translatedMap.GetEnumerator()) { + $mergedMap[[string]$entry.Key] = [string]$entry.Value + } +} + +Write-OrderedJsonMap -Path $outputPath -Map $mergedMap +Write-Output "Merged $($manifest.batchCount) translation batch(es) into $outputPath" \ No newline at end of file diff --git a/scripts/translation/Remove-UnusedTranslations.ps1 b/scripts/translation/Remove-UnusedTranslations.ps1 new file mode 100644 index 0000000..ae972b7 --- /dev/null +++ b/scripts/translation/Remove-UnusedTranslations.ps1 @@ -0,0 +1,36 @@ +[CmdletBinding()] +param( + [string]$RepositoryRoot, + [string]$EnglishFilePath +) + +Set-StrictMode -Version Latest +$ErrorActionPreference = 'Stop' + +. (Join-Path $PSScriptRoot 'Languages\TranslationJsonTools.ps1') +. (Join-Path $PSScriptRoot 'Languages\TranslationSourceTools.ps1') + +$resolvedRepositoryRoot = Resolve-TranslationSyncRepositoryRoot -RepositoryRoot $RepositoryRoot +$resolvedEnglishFilePath = Resolve-EnglishLanguageFilePath -ResolvedRepositoryRoot $resolvedRepositoryRoot -EnglishFilePath $EnglishFilePath + +if (-not (Test-Path -Path $resolvedEnglishFilePath -PathType Leaf)) { + throw "English translation file not found: $resolvedEnglishFilePath" +} + +$snapshot = Get-TranslationSourceSnapshot -RepositoryRoot $resolvedRepositoryRoot +$englishTranslations = Read-OrderedJsonMapPermissive -Path $resolvedEnglishFilePath +$extractedKeySet = [System.Collections.Generic.HashSet[string]]::new([System.StringComparer]::Ordinal) +foreach ($key in $snapshot.KeyOrder) { + [void]$extractedKeySet.Add([string]$key) +} + +$unusedKeys = New-Object System.Collections.Generic.List[string] +foreach ($entry in $englishTranslations.GetEnumerator()) { + $key = [string]$entry.Key + if (-not $extractedKeySet.Contains($key)) { + $unusedKeys.Add($key) + Write-Output "Unused key: $key" + } +} + +Write-Output "Scan completed. Checked $(@($snapshot.SourceFiles).Count) file(s); found $($unusedKeys.Count) unused key(s)." \ No newline at end of file diff --git a/scripts/translation/Set-EnglishLegacyBoundary.ps1 b/scripts/translation/Set-EnglishLegacyBoundary.ps1 new file mode 100644 index 0000000..4cc2598 --- /dev/null +++ b/scripts/translation/Set-EnglishLegacyBoundary.ps1 @@ -0,0 +1,92 @@ +[CmdletBinding(SupportsShouldProcess = $true)] +param( + [string]$RepositoryRoot, + [string]$EnglishFilePath, + [string]$LegacyRef = 'HEAD~1', + [switch]$CheckOnly +) + +Set-StrictMode -Version Latest +$ErrorActionPreference = 'Stop' + +. (Join-Path $PSScriptRoot 'Languages\TranslationJsonTools.ps1') +. (Join-Path $PSScriptRoot 'Languages\TranslationSourceTools.ps1') + +$resolvedRepositoryRoot = Resolve-TranslationSyncRepositoryRoot -RepositoryRoot $RepositoryRoot +$resolvedEnglishFilePath = Resolve-EnglishLanguageFilePath -ResolvedRepositoryRoot $resolvedRepositoryRoot -EnglishFilePath $EnglishFilePath + +if (-not (Test-Path -Path $resolvedEnglishFilePath -PathType Leaf)) { + throw "English translation file not found: $resolvedEnglishFilePath" +} + +$relativeEnglishPath = Get-RepoRelativePath -RepositoryRoot $resolvedRepositoryRoot -FilePath $resolvedEnglishFilePath +$gitObject = '{0}:{1}' -f $LegacyRef, $relativeEnglishPath +$legacyContent = & git -C $resolvedRepositoryRoot show $gitObject 2>$null +if ($LASTEXITCODE -ne 0) { + throw "Unable to read '$relativeEnglishPath' from git ref '$LegacyRef'." +} + +$snapshot = Get-TranslationSourceSnapshot -RepositoryRoot $resolvedRepositoryRoot +$currentMap = Read-OrderedJsonMap -Path $resolvedEnglishFilePath +$legacySourceMap = Convert-JsonContentToOrderedMap -Content ([string]::Join([Environment]::NewLine, @($legacyContent))) -Path $gitObject -DetectDuplicates + +$extractedKeySet = [System.Collections.Generic.HashSet[string]]::new([System.StringComparer]::Ordinal) +foreach ($key in $snapshot.KeyOrder) { + [void]$extractedKeySet.Add([string]$key) +} + +$mergedLegacyMap = New-OrderedStringMap +foreach ($entry in $legacySourceMap.GetEnumerator()) { + $key = [string]$entry.Key + if ($key -ceq (Get-TranslationLegacyBoundaryKey)) { + continue + } + + if (-not $extractedKeySet.Contains($key)) { + $mergedLegacyMap[$key] = if ($currentMap.Contains($key)) { [string]$currentMap[$key] } else { [string]$entry.Value } + } +} + +$currentSections = Split-TranslationMapAtBoundary -Map $currentMap +foreach ($entry in $currentSections.LegacyMap.GetEnumerator()) { + $key = [string]$entry.Key + if (-not $mergedLegacyMap.Contains($key)) { + $mergedLegacyMap[$key] = [string]$entry.Value + } +} + +$updatedActiveMap = New-OrderedStringMap +foreach ($key in $snapshot.KeyOrder) { + $updatedActiveMap[$key] = if ($currentMap.Contains($key)) { [string]$currentMap[$key] } else { $key } +} + +$updatedMap = Join-TranslationMapWithBoundary -ActiveMap $updatedActiveMap -LegacyMap $mergedLegacyMap -IncludeBoundary +$hasChanges = -not (Test-OrderedStringMapsEqual -Left $currentMap -Right $updatedMap) + +Write-Output 'English legacy boundary summary' +Write-Output "Repository root: $resolvedRepositoryRoot" +Write-Output "English file: $resolvedEnglishFilePath" +Write-Output "Legacy ref: $LegacyRef" +Write-Output "Active keys: $($updatedActiveMap.Count)" +Write-Output "Legacy keys restored: $($mergedLegacyMap.Count)" +Write-Output "Needs update: $hasChanges" + +if ($CheckOnly) { + if ($hasChanges) { + throw 'English legacy boundary layout is not in the expected state.' + } + + return +} + +if (-not $hasChanges) { + Write-Output '' + Write-Output 'The English file already matches the expected boundary layout.' + return +} + +if ($PSCmdlet.ShouldProcess($resolvedEnglishFilePath, 'Populate the English legacy translation tail')) { + Write-OrderedJsonMap -Path $resolvedEnglishFilePath -Map $updatedMap + Write-Output '' + Write-Output 'The English legacy boundary layout was updated successfully.' +} \ No newline at end of file diff --git a/scripts/translation/Set-TranslationBoundaryOrder.ps1 b/scripts/translation/Set-TranslationBoundaryOrder.ps1 new file mode 100644 index 0000000..774c004 --- /dev/null +++ b/scripts/translation/Set-TranslationBoundaryOrder.ps1 @@ -0,0 +1,138 @@ +[CmdletBinding(SupportsShouldProcess = $true)] +param( + [string]$RepositoryRoot, + [string]$EnglishFilePath, + [string]$LanguagesDirectory, + [string]$InventoryOutputPath, + [switch]$IncludeEnglish, + [switch]$CheckOnly +) + +Set-StrictMode -Version Latest +$ErrorActionPreference = 'Stop' + +. (Join-Path $PSScriptRoot 'Languages\TranslationJsonTools.ps1') +. (Join-Path $PSScriptRoot 'Languages\TranslationSourceTools.ps1') + +$resolvedRepositoryRoot = Resolve-TranslationSyncRepositoryRoot -RepositoryRoot $RepositoryRoot +$resolvedEnglishFilePath = Resolve-EnglishLanguageFilePath -ResolvedRepositoryRoot $resolvedRepositoryRoot -EnglishFilePath $EnglishFilePath +$resolvedLanguagesDirectory = if ([string]::IsNullOrWhiteSpace($LanguagesDirectory)) { + Split-Path -Path $resolvedEnglishFilePath -Parent +} +else { + Get-FullPath -Path $LanguagesDirectory +} + +if (-not (Test-Path -Path $resolvedLanguagesDirectory -PathType Container)) { + throw "Languages directory not found: $resolvedLanguagesDirectory" +} + +$englishMap = Read-OrderedJsonMap -Path $resolvedEnglishFilePath +$englishSections = Split-TranslationMapAtBoundary -Map $englishMap +if (-not $englishSections.HasBoundary) { + Write-Output 'The English translation file does not contain a legacy boundary marker. No reordering needed.' + return +} + +$englishActiveOrder = @($englishSections.ActiveMap.Keys) +$englishLegacyOrder = @($englishSections.LegacyMap.Keys) +$englishKeySet = [System.Collections.Generic.HashSet[string]]::new([System.StringComparer]::Ordinal) +foreach ($key in $englishActiveOrder) { + [void]$englishKeySet.Add([string]$key) +} +foreach ($key in $englishLegacyOrder) { + [void]$englishKeySet.Add([string]$key) +} + +$filesToProcess = Get-ChildItem -Path $resolvedLanguagesDirectory -Filter 'lang_*.json' | Sort-Object Name +if (-not $IncludeEnglish) { + $filesToProcess = @($filesToProcess | Where-Object { $_.FullName -ine $resolvedEnglishFilePath }) +} + +$changedFiles = New-Object System.Collections.Generic.List[string] +$reports = New-Object System.Collections.Generic.List[object] + +foreach ($languageFile in $filesToProcess) { + $languageMap = Read-OrderedJsonMapPermissive -Path $languageFile.FullName + + $activeOutput = New-OrderedStringMap + foreach ($key in $englishActiveOrder) { + if ($languageMap.Contains($key)) { + $activeOutput[$key] = [string]$languageMap[$key] + } + } + + $legacyOutput = New-OrderedStringMap + foreach ($key in $englishLegacyOrder) { + if ($languageMap.Contains($key)) { + $legacyOutput[$key] = [string]$languageMap[$key] + } + } + + $unmappedKeys = New-Object System.Collections.Generic.List[string] + foreach ($entry in $languageMap.GetEnumerator()) { + $key = [string]$entry.Key + if ($key -ceq (Get-TranslationLegacyBoundaryKey)) { + continue + } + + if (-not $englishKeySet.Contains($key)) { + $legacyOutput[$key] = [string]$entry.Value + $unmappedKeys.Add($key) + } + } + + $updatedMap = Join-TranslationMapWithBoundary -ActiveMap $activeOutput -LegacyMap $legacyOutput -IncludeBoundary + $hasChanges = -not (Test-OrderedStringMapsEqual -Left $languageMap -Right $updatedMap) + + if ($hasChanges) { + $changedFiles.Add((Get-RepoRelativePath -RepositoryRoot $resolvedRepositoryRoot -FilePath $languageFile.FullName)) + if (-not $CheckOnly -and $PSCmdlet.ShouldProcess($languageFile.FullName, 'Reorder translation file to the English legacy boundary layout')) { + Write-OrderedJsonMap -Path $languageFile.FullName -Map $updatedMap + } + } + + $reports.Add([pscustomobject]@{ + languageFile = (Get-RepoRelativePath -RepositoryRoot $resolvedRepositoryRoot -FilePath $languageFile.FullName) + changed = $hasChanges + activeKeyCount = $activeOutput.Count + legacyKeyCount = $legacyOutput.Count + unmappedKeyCount = $unmappedKeys.Count + unmappedKeys = $unmappedKeys.ToArray() + }) +} + +if (-not [string]::IsNullOrWhiteSpace($InventoryOutputPath)) { + $resolvedInventoryOutputPath = Get-FullPath -Path $InventoryOutputPath + $report = [pscustomobject]@{ + generatedAt = (Get-Date).ToString('o') + repositoryRoot = $resolvedRepositoryRoot + englishFile = (Get-RepoRelativePath -RepositoryRoot $resolvedRepositoryRoot -FilePath $resolvedEnglishFilePath) + languagesDirectory = (Get-RepoRelativePath -RepositoryRoot $resolvedRepositoryRoot -FilePath $resolvedLanguagesDirectory) + includeEnglish = [bool]$IncludeEnglish + changedFileCount = $changedFiles.Count + changedFiles = $changedFiles.ToArray() + files = $reports.ToArray() + } + + New-Utf8File -Path $resolvedInventoryOutputPath -Content ($report | ConvertTo-Json -Depth 6) +} + +Write-Output 'Translation boundary reorder summary' +Write-Output "Repository root: $resolvedRepositoryRoot" +Write-Output "Languages directory: $resolvedLanguagesDirectory" +Write-Output "Include English: $([bool]$IncludeEnglish)" +Write-Output "Files processed: $(@($filesToProcess).Count)" +Write-Output "Files changed: $($changedFiles.Count)" + +if ($changedFiles.Count -gt 0) { + Write-Output '' + Write-Output 'Changed files:' + foreach ($path in $changedFiles) { + Write-Output (" * {0}" -f $path) + } +} + +if ($CheckOnly -and $changedFiles.Count -gt 0) { + throw 'One or more translation files are not aligned to the English legacy boundary layout.' +} \ No newline at end of file diff --git a/scripts/translation/Split-TranslationDiffBatches.ps1 b/scripts/translation/Split-TranslationDiffBatches.ps1 new file mode 100644 index 0000000..55efefc --- /dev/null +++ b/scripts/translation/Split-TranslationDiffBatches.ps1 @@ -0,0 +1,126 @@ +[CmdletBinding()] +param( + [Parameter(Mandatory = $true)] + [string]$SourcePatch, + + [Parameter(Mandatory = $true)] + [string]$OutputDir, + + [string]$TranslatedPatch, + + [string]$ReferencePatch, + + [ValidateRange(1, 100)] + [int]$BatchSize = 100, + + [switch]$Clean +) + +Set-StrictMode -Version Latest +$ErrorActionPreference = 'Stop' + +. (Join-Path $PSScriptRoot 'Languages\TranslationJsonTools.ps1') + +function New-BatchFileName { + param( + [Parameter(Mandatory = $true)] + [int]$BatchNumber, + + [Parameter(Mandatory = $true)] + [string]$Kind + ) + + return ('batch.{0:D2}.{1}.json' -f $BatchNumber, $Kind) +} + +$sourcePatchPath = Get-FullPath -Path $SourcePatch +$outputRoot = Get-FullPath -Path $OutputDir +$translatedPatchPath = if ([string]::IsNullOrWhiteSpace($TranslatedPatch)) { $null } else { Get-FullPath -Path $TranslatedPatch } +$referencePatchPath = if ([string]::IsNullOrWhiteSpace($ReferencePatch)) { $null } else { Get-FullPath -Path $ReferencePatch } + +if (-not (Test-Path -Path $sourcePatchPath -PathType Leaf)) { + throw "Source patch not found: $sourcePatchPath" +} + +if ($null -ne $translatedPatchPath -and -not (Test-Path -Path $translatedPatchPath -PathType Leaf)) { + throw "Translated patch not found: $translatedPatchPath" +} + +if ($null -ne $referencePatchPath -and -not (Test-Path -Path $referencePatchPath -PathType Leaf)) { + throw "Reference patch not found: $referencePatchPath" +} + +if ($Clean -and (Test-Path -Path $outputRoot)) { + Remove-Item -Path $outputRoot -Recurse -Force +} + +New-Item -Path $outputRoot -ItemType Directory -Force | Out-Null + +$sourceMap = Read-OrderedJsonMap -Path $sourcePatchPath +$translatedMap = if ($null -eq $translatedPatchPath) { New-OrderedStringMap } else { Read-OrderedJsonMap -Path $translatedPatchPath } +$referenceMap = if ($null -eq $referencePatchPath) { New-OrderedStringMap } else { Read-OrderedJsonMap -Path $referencePatchPath } + +$entries = @($sourceMap.GetEnumerator()) +$batchCount = if ($entries.Count -eq 0) { 0 } else { [int][Math]::Ceiling($entries.Count / $BatchSize) } +$manifestBatches = New-Object System.Collections.Generic.List[object] + +for ($batchIndex = 0; $batchIndex -lt $batchCount; $batchIndex += 1) { + $batchNumber = $batchIndex + 1 + $startIndex = $batchIndex * $BatchSize + $endIndexExclusive = [Math]::Min($startIndex + $BatchSize, $entries.Count) + + $batchSourceMap = New-OrderedStringMap + $batchTranslatedMap = New-OrderedStringMap + $batchReferenceMap = New-OrderedStringMap + $batchKeys = New-Object System.Collections.Generic.List[string] + + for ($entryIndex = $startIndex; $entryIndex -lt $endIndexExclusive; $entryIndex += 1) { + $entry = $entries[$entryIndex] + $key = [string]$entry.Key + $value = [string]$entry.Value + + $batchSourceMap[$key] = $value + $batchKeys.Add($key) + + if ($translatedMap.Contains($key)) { + $batchTranslatedMap[$key] = [string]$translatedMap[$key] + } + + if ($referenceMap.Contains($key)) { + $batchReferenceMap[$key] = [string]$referenceMap[$key] + } + } + + $sourceFileName = New-BatchFileName -BatchNumber $batchNumber -Kind 'source' + $translatedFileName = New-BatchFileName -BatchNumber $batchNumber -Kind 'translated' + $referenceFileName = New-BatchFileName -BatchNumber $batchNumber -Kind 'reference' + + Write-OrderedJsonMap -Path (Join-Path $outputRoot $sourceFileName) -Map $batchSourceMap + Write-OrderedJsonMap -Path (Join-Path $outputRoot $translatedFileName) -Map $batchTranslatedMap + Write-OrderedJsonMap -Path (Join-Path $outputRoot $referenceFileName) -Map $batchReferenceMap + + $manifestBatches.Add([pscustomobject]@{ + batchNumber = $batchNumber + keyCount = $batchSourceMap.Count + source = $sourceFileName + translated = $translatedFileName + reference = $referenceFileName + firstKey = if ($batchKeys.Count -gt 0) { $batchKeys[0] } else { $null } + lastKey = if ($batchKeys.Count -gt 0) { $batchKeys[$batchKeys.Count - 1] } else { $null } + }) | Out-Null +} + +$manifest = [pscustomobject]@{ + generatedAt = (Get-Date).ToString('o') + sourcePatch = $sourcePatchPath + translatedPatch = $translatedPatchPath + referencePatch = $referencePatchPath + batchSize = $BatchSize + totalKeys = $sourceMap.Count + batchCount = $batchCount + batches = $manifestBatches.ToArray() +} + +New-Utf8File -Path (Join-Path $outputRoot 'manifest.json') -Content (($manifest | ConvertTo-Json -Depth 6) + "`r`n") + +Write-Output "Created $batchCount translation batch(es) in $outputRoot" diff --git a/scripts/translation/Sync-TranslationMetadata.ps1 b/scripts/translation/Sync-TranslationMetadata.ps1 new file mode 100644 index 0000000..6421ebd --- /dev/null +++ b/scripts/translation/Sync-TranslationMetadata.ps1 @@ -0,0 +1,346 @@ +[CmdletBinding(DefaultParameterSetName = 'Selected', SupportsShouldProcess = $true)] +param( + [Parameter(ParameterSetName = 'Selected', Mandatory = $true)] + [string[]]$LanguageCodes, + + [Parameter(ParameterSetName = 'All')] + [switch]$AllLanguages, + + [switch]$CheckOnly, + + [switch]$UpdateTranslationDoc, + + [switch]$UpdateReadme, + + [string]$ReadmePath = (Join-Path $PSScriptRoot '..\..\README.md'), + + [string]$TranslationDocPath = (Join-Path $PSScriptRoot '..\..\TRANSLATION.md'), + + [string]$TranslatorsPath = (Join-Path $PSScriptRoot '..\..\src\Languages\Data\Translators.json'), + + [string]$TranslatedPercentagesPath = (Join-Path $PSScriptRoot '..\..\src\Languages\Data\TranslatedPercentages.json') +) + +Set-StrictMode -Version Latest +$ErrorActionPreference = 'Stop' + +Import-Module (Join-Path $PSScriptRoot 'Languages\LanguageData.psm1') -Force +. (Join-Path $PSScriptRoot 'Languages\TranslationJsonTools.ps1') + +$script:TranslatorCreditsKey = '0 0 0 Contributors, please add your names/usernames separated by comas (for credit purposes). DO NOT Translate this entry' + +function Read-JsonObject { + param( + [Parameter(Mandatory = $true)] + [string]$Path + ) + + if (-not (Test-Path -Path $Path -PathType Leaf)) { + return [ordered]@{} + } + + $content = [System.IO.File]::ReadAllText($Path) + if ([string]::IsNullOrWhiteSpace($content)) { + return [ordered]@{} + } + + $parsed = $content | ConvertFrom-Json -AsHashtable + if ($null -eq $parsed) { + return [ordered]@{} + } + + if (-not ($parsed -is [System.Collections.IDictionary])) { + throw "JSON root must be an object: $Path" + } + + return $parsed +} + +function ConvertTo-NormalizedJson { + param( + [Parameter(Mandatory = $true)] + [AllowNull()] + [object]$Value + ) + + return ($Value | ConvertTo-Json -Depth 10) +} + +function ConvertTo-TranslatorMetadataJson { + param( + [Parameter(Mandatory = $true)] + [System.Collections.IDictionary]$Map + ) + + $lines = New-Object System.Collections.Generic.List[string] + $lines.Add('{') + + $rootEntries = @($Map.GetEnumerator()) + for ($index = 0; $index -lt $rootEntries.Count; $index++) { + $entry = $rootEntries[$index] + $key = ConvertTo-JsonStringLiteral -Value ([string]$entry.Key) + $translators = @($entry.Value) + $isLastRootEntry = $index -eq ($rootEntries.Count - 1) + + if ($translators.Count -eq 0) { + $line = ' {0}: []' -f $key + if (-not $isLastRootEntry) { + $line += ',' + } + + $lines.Add($line) + continue + } + + $lines.Add(' {0}: [' -f $key) + for ($translatorIndex = 0; $translatorIndex -lt $translators.Count; $translatorIndex++) { + $translator = $translators[$translatorIndex] + $isLastTranslator = $translatorIndex -eq ($translators.Count - 1) + $name = ConvertTo-JsonStringLiteral -Value ([string]$translator['name']) + $link = ConvertTo-JsonStringLiteral -Value ([string]$translator['link']) + + $lines.Add(' {') + $lines.Add(' "name": {0},' -f $name) + $lines.Add(' "link": {0}' -f $link) + + $translatorClosing = ' }' + if (-not $isLastTranslator) { + $translatorClosing += ',' + } + + $lines.Add($translatorClosing) + } + + $rootClosing = ' ]' + if (-not $isLastRootEntry) { + $rootClosing += ',' + } + + $lines.Add($rootClosing) + } + + $lines.Add('}') + return (($lines -join "`r`n") + "`r`n") +} + +function Get-RequestedLanguageCodes { + $languageReference = Get-LanguageReference + $codesToUpdate = @() + + if ($AllLanguages.IsPresent) { + $codesToUpdate = @( + $languageReference.Keys | + Where-Object { $_ -ne 'default' } | + Sort-Object + ) + } + else { + $codesToUpdate = @( + $LanguageCodes | + ForEach-Object { $_.Trim() } | + Where-Object { -not [string]::IsNullOrWhiteSpace($_) } | + Sort-Object -Unique + ) + } + + if ($codesToUpdate.Count -eq 0) { + throw 'No language codes were provided.' + } + + foreach ($code in $codesToUpdate) { + if (-not $languageReference.Contains($code)) { + throw "Unknown language code '$code'." + } + } + + return $codesToUpdate +} + +function Get-ExpectedTranslationPercentages { + param( + [Parameter(Mandatory = $true)] + [string[]]$CodesToUpdate, + + [Parameter(Mandatory = $true)] + [string]$Path + ) + + $includeEnglish = $AllLanguages.IsPresent -or ($CodesToUpdate -contains 'en') + $statusJson = & (Join-Path $PSScriptRoot 'Get-TranslationStatus.ps1') -OutputFormat Json -IncludeEnglish:$includeEnglish + $statusRows = $statusJson | ConvertFrom-Json -AsHashtable + if ($null -eq $statusRows) { + throw 'Could not load translation status data.' + } + + $statusByCode = @{} + foreach ($row in $statusRows) { + $statusByCode[[string]$row.Code] = $row + } + + $storedPercentages = Read-JsonObject -Path $Path + $updatedPercentages = [ordered]@{} + foreach ($entry in $storedPercentages.GetEnumerator()) { + $updatedPercentages[[string]$entry.Key] = [string]$entry.Value + } + + foreach ($code in $CodesToUpdate) { + if (-not $statusByCode.ContainsKey($code)) { + throw "Language code '$code' was not found in the computed translation status." + } + + $updatedPercentages[$code] = [string]$statusByCode[$code].Completion + } + + return $updatedPercentages +} + +function Get-ExpectedTranslatorMetadata { + param( + [Parameter(Mandatory = $true)] + [string[]]$CodesToUpdate, + + [Parameter(Mandatory = $true)] + [string]$Path + ) + + $languagesDirectory = Get-LanguagesDirectoryPath + $englishLanguageFilePath = Join-Path $languagesDirectory 'lang_en.json' + $storedTranslators = Read-JsonObject -Path $Path + $updatedTranslators = [ordered]@{} + foreach ($entry in $storedTranslators.GetEnumerator()) { + $updatedTranslators[[string]$entry.Key] = @($entry.Value) + } + + $englishLanguageMap = Read-OrderedJsonMap -Path $englishLanguageFilePath + $hasCreditsKey = $englishLanguageMap.Contains($script:TranslatorCreditsKey) + + foreach ($code in $CodesToUpdate) { + $languageFilePath = Join-Path $languagesDirectory ("lang_{0}.json" -f $code) + if (-not (Test-Path -Path $languageFilePath -PathType Leaf)) { + throw "Language file not found: $languageFilePath" + } + + $languageMap = Read-OrderedJsonMap -Path $languageFilePath + if (-not $hasCreditsKey -or -not $languageMap.Contains($script:TranslatorCreditsKey)) { + if (-not $updatedTranslators.Contains($code)) { + $updatedTranslators[$code] = @() + } + continue + } + + $englishCreditsSignature = Get-TranslatorCreditsSignature -Credits ([string]$englishLanguageMap[$script:TranslatorCreditsKey]) + $credits = [string]$languageMap[$script:TranslatorCreditsKey] + $creditsSignature = Get-TranslatorCreditsSignature -Credits $credits + $shouldPreserveExisting = $code -ne 'en' -and $creditsSignature -eq $englishCreditsSignature + + if ($shouldPreserveExisting) { + if (-not $updatedTranslators.Contains($code)) { + $updatedTranslators[$code] = @() + } + + Write-Warning "Preserving existing translator metadata for '$code' because its locale credits currently match the English fallback credits." + continue + } + + $updatedTranslators[$code] = @(ConvertTo-TranslatorMetadataEntries -Credits $credits) + } + + return $updatedTranslators +} + +function Get-TranslatorCreditsSignature { + param( + [AllowNull()] + [string]$Credits + ) + + $entries = @(Get-TranslatorsFromCredits -Credits $Credits) + if ($entries.Count -eq 0) { + return '' + } + + return @( + $entries | + ForEach-Object { ([string]$_.name).Trim().ToLowerInvariant() } + ) -join "`n" +} + +function ConvertTo-TranslatorMetadataEntries { + param( + [AllowNull()] + [string]$Credits + ) + + return @( + Get-TranslatorsFromCredits -Credits $Credits | + ForEach-Object { + [ordered]@{ + name = [string]$_.name + link = [string]$_.link + } + } + ) +} + +function Write-TranslationDocumentation { + param( + [Parameter(Mandatory = $true)] + [string]$Path + ) + + New-Utf8File -Path $Path -Content (Get-TranslationDocumentationMarkdown) +} + +$shouldUpdateTranslationDoc = $UpdateTranslationDoc.IsPresent +if ($UpdateReadme.IsPresent) { + Write-Warning 'The -UpdateReadme switch is deprecated. Updating TRANSLATION.md instead.' + $shouldUpdateTranslationDoc = $true +} + +$codesToUpdate = Get-RequestedLanguageCodes +$expectedPercentages = Get-ExpectedTranslationPercentages -CodesToUpdate $codesToUpdate -Path $TranslatedPercentagesPath +$expectedTranslators = Get-ExpectedTranslatorMetadata -CodesToUpdate $codesToUpdate -Path $TranslatorsPath + +$actualPercentages = Read-JsonObject -Path $TranslatedPercentagesPath +$actualTranslators = Read-JsonObject -Path $TranslatorsPath + +$driftedFiles = New-Object System.Collections.Generic.List[string] +if ((ConvertTo-NormalizedJson -Value $actualPercentages) -ne (ConvertTo-NormalizedJson -Value $expectedPercentages)) { + $driftedFiles.Add((Get-TranslatedPercentagesJsonPath)) +} + +if ((ConvertTo-NormalizedJson -Value $actualTranslators) -ne (ConvertTo-NormalizedJson -Value $expectedTranslators)) { + $driftedFiles.Add((Get-TranslatorsJsonPath)) +} + +Write-Output ('Translation metadata scope: ' + ($codesToUpdate -join ', ')) +Write-Output ('Metadata drift detected: ' + $driftedFiles.Count) + +if ($driftedFiles.Count -gt 0) { + foreach ($path in $driftedFiles) { + Write-Output (' * ' + $path) + } +} + +if ($CheckOnly.IsPresent) { + if ($driftedFiles.Count -gt 0) { + throw 'Translation metadata is out of date. Run scripts/translation/Sync-TranslationMetadata.ps1 to refresh it.' + } + + Write-Output 'Translation metadata is up to date.' + return +} + +if ($driftedFiles.Contains((Get-TranslatedPercentagesJsonPath)) -and $PSCmdlet.ShouldProcess($TranslatedPercentagesPath, 'Update translated percentages metadata')) { + New-Utf8File -Path $TranslatedPercentagesPath -Content ((ConvertTo-NormalizedJson -Value $expectedPercentages) + "`r`n") +} + +if ($driftedFiles.Contains((Get-TranslatorsJsonPath)) -and $PSCmdlet.ShouldProcess($TranslatorsPath, 'Update translator metadata')) { + New-Utf8File -Path $TranslatorsPath -Content (ConvertTo-TranslatorMetadataJson -Map $expectedTranslators) +} + +if ($shouldUpdateTranslationDoc -and $PSCmdlet.ShouldProcess($TranslationDocPath, 'Update translation documentation')) { + Write-TranslationDocumentation -Path $TranslationDocPath +} + +Write-Output 'Translation metadata sync completed.' \ No newline at end of file diff --git a/scripts/translation/Sync-TranslationSources.ps1 b/scripts/translation/Sync-TranslationSources.ps1 new file mode 100644 index 0000000..4ddc663 --- /dev/null +++ b/scripts/translation/Sync-TranslationSources.ps1 @@ -0,0 +1,212 @@ +[CmdletBinding(SupportsShouldProcess = $true)] +param( + [string]$RepositoryRoot, + [string]$EnglishFilePath, + [string]$InventoryOutputPath, + [switch]$UseLegacyBoundary, + [switch]$CheckOnly +) + +Set-StrictMode -Version Latest +$ErrorActionPreference = 'Stop' + +. (Join-Path $PSScriptRoot 'Languages\TranslationJsonTools.ps1') +. (Join-Path $PSScriptRoot 'Languages\TranslationSourceTools.ps1') + +$resolvedRepositoryRoot = Resolve-TranslationSyncRepositoryRoot -RepositoryRoot $RepositoryRoot +$resolvedEnglishFilePath = Resolve-EnglishLanguageFilePath -ResolvedRepositoryRoot $resolvedRepositoryRoot -EnglishFilePath $EnglishFilePath + +if (-not (Test-Path -Path $resolvedEnglishFilePath -PathType Leaf)) { + throw "English translation file not found: $resolvedEnglishFilePath" +} + +$snapshot = Get-TranslationSourceSnapshot -RepositoryRoot $resolvedRepositoryRoot +$currentMap = Read-OrderedJsonMapPermissive -Path $resolvedEnglishFilePath +$currentSections = Split-TranslationMapAtBoundary -Map $currentMap +$preserveLegacyBoundary = $UseLegacyBoundary -or $currentSections.HasBoundary + +$extractedKeySet = [System.Collections.Generic.HashSet[string]]::new([System.StringComparer]::Ordinal) +foreach ($key in $snapshot.KeyOrder) { + [void]$extractedKeySet.Add([string]$key) +} + +$currentKeySet = [System.Collections.Generic.HashSet[string]]::new([System.StringComparer]::Ordinal) +foreach ($entry in $currentMap.GetEnumerator()) { + $key = [string]$entry.Key + if ($key -ceq (Get-TranslationLegacyBoundaryKey)) { + continue + } + + [void]$currentKeySet.Add($key) +} + +$missingKeys = New-Object System.Collections.Generic.List[string] +foreach ($key in $snapshot.KeyOrder) { + if (-not $currentKeySet.Contains($key)) { + $missingKeys.Add($key) + } +} + +$unusedKeys = New-Object System.Collections.Generic.List[string] +foreach ($entry in $currentMap.GetEnumerator()) { + $key = [string]$entry.Key + if ($key -ceq (Get-TranslationLegacyBoundaryKey)) { + continue + } + + if (-not $extractedKeySet.Contains($key)) { + $unusedKeys.Add($key) + } +} + +$preservedLegacyMap = New-OrderedStringMap +$misplacedLegacyKeys = New-Object System.Collections.Generic.List[string] +foreach ($entry in $currentSections.ActiveMap.GetEnumerator()) { + $key = [string]$entry.Key + if (-not $extractedKeySet.Contains($key)) { + $misplacedLegacyKeys.Add($key) + } +} + +$activeKeysBelowBoundary = New-Object System.Collections.Generic.List[string] +foreach ($entry in $currentSections.LegacyMap.GetEnumerator()) { + $key = [string]$entry.Key + if ($extractedKeySet.Contains($key)) { + $activeKeysBelowBoundary.Add($key) + } +} + +foreach ($entry in $currentMap.GetEnumerator()) { + $key = [string]$entry.Key + if ($key -ceq (Get-TranslationLegacyBoundaryKey)) { + continue + } + + if (-not $extractedKeySet.Contains($key)) { + $preservedLegacyMap[$key] = [string]$entry.Value + } +} + +$syncedActiveMap = New-OrderedStringMap +foreach ($key in $snapshot.KeyOrder) { + $syncedActiveMap[$key] = if ($currentKeySet.Contains($key)) { [string]$currentMap[$key] } else { $key } +} + +$syncedMap = if ($preserveLegacyBoundary) { + Join-TranslationMapWithBoundary -ActiveMap $syncedActiveMap -LegacyMap $preservedLegacyMap -IncludeBoundary +} +else { + $syncedActiveMap +} + +$hasChanges = -not (Test-OrderedStringMapsEqual -Left $currentMap -Right $syncedMap) + +if (-not [string]::IsNullOrWhiteSpace($InventoryOutputPath)) { + $resolvedInventoryOutputPath = Get-FullPath -Path $InventoryOutputPath + $inventory = [pscustomobject]@{ + generatedAt = (Get-Date).ToString('o') + repositoryRoot = $resolvedRepositoryRoot + englishFile = (Get-RepoRelativePath -RepositoryRoot $resolvedRepositoryRoot -FilePath $resolvedEnglishFilePath) + legacyBoundaryEnabled = $preserveLegacyBoundary + legacyBoundaryPresent = $currentSections.HasBoundary + legacyBoundaryKey = Get-TranslationLegacyBoundaryKey + scannedSourceFileCount = @($snapshot.SourceFiles).Count + extractedKeyCount = @($snapshot.KeyOrder).Count + activeKeyCount = $syncedActiveMap.Count + legacyKeyCount = $preservedLegacyMap.Count + missingKeyCount = $missingKeys.Count + unusedKeyCount = $unusedKeys.Count + misplacedLegacyKeyCount = $misplacedLegacyKeys.Count + activeKeysBelowBoundaryCount = $activeKeysBelowBoundary.Count + warningCount = @($snapshot.Warnings).Count + missingKeys = $missingKeys.ToArray() + unusedKeys = $unusedKeys.ToArray() + legacyKeys = @($preservedLegacyMap.Keys) + misplacedLegacyKeys = $misplacedLegacyKeys.ToArray() + activeKeysBelowBoundary = $activeKeysBelowBoundary.ToArray() + warnings = @($snapshot.Warnings | Sort-Object Path, Line, Type | ForEach-Object { + [pscustomobject]@{ + Path = $_.Path + Line = $_.Line + Type = $_.Type + Message = $_.Message + } + }) + } + + New-Utf8File -Path $resolvedInventoryOutputPath -Content ($inventory | ConvertTo-Json -Depth 6) +} + +Write-Output "Translation source synchronization summary" +Write-Output "Repository root: $resolvedRepositoryRoot" +Write-Output "English file: $resolvedEnglishFilePath" +Write-Output "Legacy boundary enabled: $preserveLegacyBoundary" +Write-Output "Legacy boundary present: $($currentSections.HasBoundary)" +Write-Output "Scanned source files: $(@($snapshot.SourceFiles).Count)" +Write-Output "Extracted keys: $(@($snapshot.KeyOrder).Count)" +Write-Output "Missing English keys: $($missingKeys.Count)" +Write-Output "Unused English keys: $($unusedKeys.Count)" +Write-Output "Legacy English keys: $($preservedLegacyMap.Count)" +Write-Output "Misplaced legacy keys: $($misplacedLegacyKeys.Count)" +Write-Output "Active keys below boundary: $($activeKeysBelowBoundary.Count)" +Write-Output "Warnings: $(@($snapshot.Warnings).Count)" + +if ($missingKeys.Count -gt 0) { + Write-Output '' + Write-Output 'Missing keys to add:' + foreach ($key in $missingKeys) { + Write-Output (" + {0}" -f $key) + } +} + +if ((-not $preserveLegacyBoundary) -and $unusedKeys.Count -gt 0) { + Write-Output '' + Write-Output 'Unused keys to remove:' + foreach ($key in $unusedKeys) { + Write-Output (" - {0}" -f $key) + } +} + +if ($misplacedLegacyKeys.Count -gt 0) { + Write-Output '' + Write-Output 'Legacy keys that should move below the boundary:' + foreach ($key in $misplacedLegacyKeys) { + Write-Output (" v {0}" -f $key) + } +} + +if ($activeKeysBelowBoundary.Count -gt 0) { + Write-Output '' + Write-Output 'Active keys currently below the boundary:' + foreach ($key in $activeKeysBelowBoundary) { + Write-Output (" ^ {0}" -f $key) + } +} + +if (@($snapshot.Warnings).Count -gt 0) { + Write-Output '' + Write-Output 'Warnings:' + foreach ($warning in $snapshot.Warnings | Sort-Object Path, Line, Type) { + Write-Output (" ! {0}:{1} [{2}] {3}" -f $warning.Path, $warning.Line, $warning.Type, $warning.Message) + } +} + +if ($CheckOnly) { + if ($hasChanges) { + throw 'lang_en.json is out of sync with extracted translation sources.' + } + + return +} + +if (-not $hasChanges) { + Write-Output '' + Write-Output 'lang_en.json is already synchronized with extracted source usage.' + return +} + +if ($PSCmdlet.ShouldProcess($resolvedEnglishFilePath, 'Synchronize English translation keys from source usage')) { + Write-OrderedJsonMap -Path $resolvedEnglishFilePath -Map $syncedMap + Write-Output '' + Write-Output 'lang_en.json was synchronized successfully.' +} \ No newline at end of file diff --git a/scripts/translation/Sync-TranslationStatus.ps1 b/scripts/translation/Sync-TranslationStatus.ps1 new file mode 100644 index 0000000..5268f06 --- /dev/null +++ b/scripts/translation/Sync-TranslationStatus.ps1 @@ -0,0 +1,126 @@ +[CmdletBinding(DefaultParameterSetName = 'Selected')] +param( + [Parameter(ParameterSetName = 'Selected', Mandatory = $true)] + [string[]]$LanguageCodes, + + [Parameter(ParameterSetName = 'All')] + [switch]$AllLanguages, + + [switch]$UpdateTranslationDoc, + + [switch]$UpdateReadme, + + [string]$ReadmePath = (Join-Path $PSScriptRoot '..\..\README.md'), + + [string]$TranslationDocPath = (Join-Path $PSScriptRoot '..\..\TRANSLATION.md'), + + [string]$TranslatedPercentagesPath = (Join-Path $PSScriptRoot '..\..\src\Languages\Data\TranslatedPercentages.json') +) + +Set-StrictMode -Version Latest +$ErrorActionPreference = 'Stop' + +Import-Module (Join-Path $PSScriptRoot 'Languages\LanguageData.psm1') -Force + +function Read-JsonObject { + param( + [Parameter(Mandatory = $true)] + [string]$Path + ) + + if (-not (Test-Path -Path $Path -PathType Leaf)) { + return [ordered]@{} + } + + $content = [System.IO.File]::ReadAllText($Path) + if ([string]::IsNullOrWhiteSpace($content)) { + return [ordered]@{} + } + + $parsed = $content | ConvertFrom-Json -AsHashtable + if ($null -eq $parsed) { + return [ordered]@{} + } + + if (-not ($parsed -is [System.Collections.IDictionary])) { + throw "JSON root must be an object: $Path" + } + + return $parsed +} + +function Write-Utf8File { + param( + [Parameter(Mandatory = $true)] + [string]$Path, + + [Parameter(Mandatory = $true)] + [AllowEmptyString()] + [string]$Content + ) + + $encoding = [System.Text.UTF8Encoding]::new($false) + [System.IO.File]::WriteAllText($Path, $Content, $encoding) +} + +function Write-TranslationDocumentation { + param( + [Parameter(Mandatory = $true)] + [string]$Path + ) + + $encoding = [System.Text.UTF8Encoding]::new($false) + [System.IO.File]::WriteAllText($Path, (Get-TranslationDocumentationMarkdown), $encoding) +} + +$shouldUpdateTranslationDoc = $UpdateTranslationDoc.IsPresent +if ($UpdateReadme.IsPresent) { + Write-Warning 'The -UpdateReadme switch is deprecated. Updating TRANSLATION.md instead.' + $shouldUpdateTranslationDoc = $true +} + +$statusJson = & (Join-Path $PSScriptRoot 'Get-TranslationStatus.ps1') -OutputFormat Json +$statusRows = $statusJson | ConvertFrom-Json -AsHashtable +if ($null -eq $statusRows) { + throw 'Could not load translation status data.' +} + +$statusByCode = @{} +foreach ($row in $statusRows) { + $statusByCode[[string]$row.Code] = $row +} + +$codesToUpdate = @() +if ($AllLanguages.IsPresent) { + $codesToUpdate = @($statusByCode.Keys | Sort-Object) +} +else { + $codesToUpdate = @($LanguageCodes | ForEach-Object { $_.Trim() } | Where-Object { -not [string]::IsNullOrWhiteSpace($_) } | Sort-Object -Unique) +} + +if ($codesToUpdate.Count -eq 0) { + throw 'No language codes were provided.' +} + +$storedPercentages = Read-JsonObject -Path $TranslatedPercentagesPath +$updatedPercentages = [ordered]@{} +foreach ($entry in $storedPercentages.GetEnumerator()) { + $updatedPercentages[[string]$entry.Key] = [string]$entry.Value +} + +foreach ($code in $codesToUpdate) { + if (-not $statusByCode.ContainsKey($code)) { + throw "Language code '$code' was not found in the computed translation status." + } + + $updatedPercentages[$code] = [string]$statusByCode[$code].Completion +} + +$percentagesJson = ($updatedPercentages | ConvertTo-Json -Depth 5) +Write-Utf8File -Path $TranslatedPercentagesPath -Content $percentagesJson + +if ($shouldUpdateTranslationDoc) { + Write-TranslationDocumentation -Path $TranslationDocPath +} + +Write-Output ('Updated translation status metadata for: ' + ($codesToUpdate -join ', ')) \ No newline at end of file diff --git a/scripts/translation/Test-TranslationSourceSync.ps1 b/scripts/translation/Test-TranslationSourceSync.ps1 new file mode 100644 index 0000000..b188492 --- /dev/null +++ b/scripts/translation/Test-TranslationSourceSync.ps1 @@ -0,0 +1,143 @@ +Set-StrictMode -Version Latest +$ErrorActionPreference = 'Stop' + +. (Join-Path $PSScriptRoot 'Languages\TranslationJsonTools.ps1') +. (Join-Path $PSScriptRoot 'Languages\TranslationSourceTools.ps1') + +$repoRoot = [System.IO.Path]::GetFullPath((Join-Path $PSScriptRoot '..\..')) +$syncScript = Join-Path $repoRoot 'scripts\translation\Sync-TranslationSources.ps1' + +if (-not (Test-Path -Path $syncScript -PathType Leaf)) { + throw "Sync script not found: $syncScript" +} + +$tempRoot = Join-Path $env:TEMP ('translation-source-sync-{0}' -f [System.Guid]::NewGuid().ToString('N')) + +try { + $sourceDir = Join-Path $tempRoot 'src\Sample' + $languageDir = Join-Path $tempRoot 'src\Languages' + New-Item -Path $sourceDir -ItemType Directory -Force | Out-Null + New-Item -Path $languageDir -ItemType Directory -Force | Out-Null + + New-Utf8File -Path (Join-Path $sourceDir 'Strings.cs') -Content @' +using UniGetUI.Core.Tools; + +namespace Sample; + +internal static class Strings +{ + public static void Use(int value) + { + _ = CoreTools.Translate("Literal from code"); + _ = CoreTools.AutoTranslated("Auto translated literal"); + _ = CoreTools.Translate($"Interpolated {value}"); + } +} +'@ + + New-Utf8File -Path (Join-Path $sourceDir 'View.xaml') -Content @' + + + +'@ + + New-Utf8File -Path (Join-Path $sourceDir 'View.axaml') -Content @' + + + + + + + +'@ + + $englishPath = Join-Path $languageDir 'lang_en.json' + $initialMap = New-OrderedStringMap + $initialMap['Literal from code'] = 'Literal from code' + $initialMap['Obsolete key'] = 'Obsolete key' + Write-OrderedJsonMap -Path $englishPath -Map $initialMap + + $snapshot = Get-TranslationSourceSnapshot -RepositoryRoot $tempRoot + if (@($snapshot.Warnings).Count -ne 1) { + throw "Expected exactly one warning for interpolated CoreTools.Translate, found $(@($snapshot.Warnings).Count)." + } + + $threwOnCheck = $false + try { + & $syncScript -RepositoryRoot $tempRoot -EnglishFilePath $englishPath -CheckOnly | Out-Null + } + catch { + if ($_.Exception.Message -notlike '*out of sync*') { + throw + } + + $threwOnCheck = $true + } + + if (-not $threwOnCheck) { + throw 'Expected check-only mode to detect synchronization differences.' + } + + & $syncScript -RepositoryRoot $tempRoot -EnglishFilePath $englishPath | Out-Null + + $updatedMap = Read-OrderedJsonMap -Path $englishPath + $expectedKeys = @( + 'Literal from code', + 'Auto translated literal', + 'WinUI label', + 'Avalonia header', + 'About UniGetUI', + 'A, B, C' + ) + + if ($updatedMap.Count -ne $expectedKeys.Count) { + throw "Expected $($expectedKeys.Count) synchronized keys, found $($updatedMap.Count)." + } + + foreach ($expectedKey in $expectedKeys) { + if (-not $updatedMap.Contains($expectedKey)) { + throw "Expected synchronized English file to contain key '$expectedKey'." + } + } + + if ($updatedMap.Contains('Obsolete key')) { + throw 'Obsolete key should have been removed during synchronization.' + } + + & $syncScript -RepositoryRoot $tempRoot -EnglishFilePath $englishPath -CheckOnly | Out-Null + + $boundaryKey = Get-TranslationLegacyBoundaryKey + $boundaryMap = New-OrderedStringMap + $boundaryMap['Literal from code'] = 'Literal from code' + $boundaryMap['Obsolete key'] = 'Obsolete key' + Write-OrderedJsonMap -Path $englishPath -Map $boundaryMap + + & $syncScript -RepositoryRoot $tempRoot -EnglishFilePath $englishPath -UseLegacyBoundary | Out-Null + + $boundaryUpdatedMap = Read-OrderedJsonMap -Path $englishPath + $boundarySections = Split-TranslationMapAtBoundary -Map $boundaryUpdatedMap + + if (-not $boundarySections.HasBoundary) { + throw 'Expected the synchronized English file to include the legacy boundary marker.' + } + + if (-not $boundarySections.LegacyMap.Contains('Obsolete key')) { + throw 'Obsolete key should have been preserved below the legacy boundary.' + } + + if ($boundarySections.ActiveMap.Contains('Obsolete key')) { + throw 'Obsolete key should not remain in the active key section.' + } + + if (-not $boundaryUpdatedMap.Contains($boundaryKey)) { + throw 'Expected the legacy boundary marker key to exist in the synchronized English file.' + } + + & $syncScript -RepositoryRoot $tempRoot -EnglishFilePath $englishPath -UseLegacyBoundary -CheckOnly | Out-Null + + Write-Output 'Translation source sync smoke test completed successfully.' +} +finally { + Remove-Item -Path $tempRoot -Recurse -Force -ErrorAction SilentlyContinue +} diff --git a/scripts/translation/Verify-Translations.ps1 b/scripts/translation/Verify-Translations.ps1 new file mode 100644 index 0000000..fd5c9eb --- /dev/null +++ b/scripts/translation/Verify-Translations.ps1 @@ -0,0 +1,322 @@ +[CmdletBinding()] +param( + [string]$LanguagesDirectory +) + +Set-StrictMode -Version Latest +$ErrorActionPreference = 'Stop' + +$simplePlaceholderPattern = '^(?[A-Za-z0-9_]+)(?:,[^}:]+)?(?::[^}]+)?$' +$icuControlPattern = '^(?[A-Za-z0-9_]+)\s*,\s*(?plural|select|selectordinal)\s*,(?[\s\S]*)$' + +function Get-RepositoryRoot { + return [System.IO.Path]::GetFullPath((Join-Path $PSScriptRoot '..\..')) +} + +function Resolve-LanguagesDirectory { + if (-not [string]::IsNullOrWhiteSpace($LanguagesDirectory)) { + return [System.IO.Path]::GetFullPath($LanguagesDirectory) + } + + return Join-Path (Get-RepositoryRoot) 'src\Languages' +} + +function Read-JsonObject { + param( + [Parameter(Mandatory = $true)] + [string]$Path + ) + + $content = [System.IO.File]::ReadAllText($Path) + if ([string]::IsNullOrWhiteSpace($content)) { + return [ordered]@{} + } + + Assert-NoDuplicateJsonKeys -Content $content -Path $Path + + $parsed = $content | ConvertFrom-Json -AsHashtable + if ($null -eq $parsed) { + return [ordered]@{} + } + + if (-not ($parsed -is [System.Collections.IDictionary])) { + throw "JSON root must be an object: $Path" + } + + return $parsed +} + +function Assert-NoDuplicateJsonKeys { + param( + [Parameter(Mandatory = $true)] + [string]$Content, + + [Parameter(Mandatory = $true)] + [string]$Path + ) + + $pattern = [regex]'(?m)^\s*"((?:\\.|[^"])*)"\s*:' + $seen = [System.Collections.Generic.HashSet[string]]::new([System.StringComparer]::Ordinal) + $duplicates = New-Object System.Collections.Generic.List[string] + + foreach ($match in $pattern.Matches($Content)) { + $key = [regex]::Unescape($match.Groups[1].Value) + if (-not $seen.Add($key) -and -not $duplicates.Contains($key)) { + $duplicates.Add($key) + } + } + + if ($duplicates.Count -gt 0) { + throw "JSON file contains duplicate key(s): $($duplicates -join ', '). Path: $Path" + } +} + +function Get-BraceBlock { + param( + [Parameter(Mandatory = $true)] + [string]$Text, + + [Parameter(Mandatory = $true)] + [int]$StartIndex + ) + + if ($Text[$StartIndex] -ne '{') { + throw "Expected '{' at index $StartIndex." + } + + $depth = 0 + for ($index = $StartIndex; $index -lt $Text.Length; $index++) { + if ($Text[$index] -eq '{') { + $depth += 1 + continue + } + + if ($Text[$index] -ne '}') { + continue + } + + $depth -= 1 + if ($depth -eq 0) { + return [pscustomobject]@{ + Content = $Text.Substring($StartIndex + 1, $index - $StartIndex - 1) + EndIndex = $index + } + } + } + + return $null +} + +function Add-TokenCount { + param( + [Parameter(Mandatory = $true)] + [System.Collections.IDictionary]$Counts, + + [Parameter(Mandatory = $true)] + [string]$Token, + + [int]$Amount = 1 + ) + + if ($Counts.Contains($Token)) { + $Counts[$Token] = [int]$Counts[$Token] + $Amount + } + else { + $Counts[$Token] = $Amount + } +} + +function Get-SimplePlaceholderToken { + param( + [Parameter(Mandatory = $true)] + [string]$Content + ) + + $trimmed = $Content.Trim() + if ($trimmed -notmatch $simplePlaceholderPattern) { + return $null + } + + return '{' + $matches.name + '}' +} + +function Get-IcuBranchTokenCounts { + param( + [Parameter(Mandatory = $true)] + [string]$Body + ) + + $maxCounts = [ordered]@{} + $index = 0 + while ($index -lt $Body.Length) { + while ($index -lt $Body.Length -and [char]::IsWhiteSpace($Body[$index])) { + $index += 1 + } + + if ($index -ge $Body.Length) { + break + } + + if ($Body[$index] -eq '{') { + $messageBlock = Get-BraceBlock -Text $Body -StartIndex $index + if ($null -eq $messageBlock) { + $index += 1 + continue + } + + $branchCounts = Get-TokenCounts -Text $messageBlock.Content + foreach ($token in $branchCounts.Keys) { + $branchCount = [int]$branchCounts[$token] + if ($maxCounts.Contains($token)) { + $maxCounts[$token] = [Math]::Max([int]$maxCounts[$token], $branchCount) + } + else { + $maxCounts[$token] = $branchCount + } + } + + $index = $messageBlock.EndIndex + 1 + continue + } + + while ($index -lt $Body.Length -and -not [char]::IsWhiteSpace($Body[$index]) -and $Body[$index] -ne '{') { + $index += 1 + } + } + + return $maxCounts +} + +function Get-TokenCounts { + param( + [AllowEmptyString()] + [string]$Text + ) + + $counts = [ordered]@{} + if ($null -eq $Text) { + return $counts + } + + $index = 0 + while ($index -lt $Text.Length) { + if ($Text[$index] -ne '{') { + $index += 1 + continue + } + + $block = Get-BraceBlock -Text $Text -StartIndex $index + if ($null -eq $block) { + $index += 1 + continue + } + + $content = $block.Content + if ($content.Trim() -match $icuControlPattern) { + $branchCounts = Get-IcuBranchTokenCounts -Body $matches.body + foreach ($token in $branchCounts.Keys) { + Add-TokenCount -Counts $counts -Token $token -Amount ([int]$branchCounts[$token]) + } + } + else { + $token = Get-SimplePlaceholderToken -Content $content + if ($null -ne $token) { + Add-TokenCount -Counts $counts -Token $token + } + } + + $index = $block.EndIndex + 1 + } + + return $counts +} + +function Get-TokenMismatches { + param( + [Parameter(Mandatory = $true)] + [System.Collections.IDictionary]$ExpectedCounts, + + [Parameter(Mandatory = $true)] + [System.Collections.IDictionary]$ActualCounts + ) + + $mismatches = New-Object System.Collections.Generic.List[string] + $allTokens = @($ExpectedCounts.Keys + $ActualCounts.Keys | Sort-Object -Unique) + + foreach ($token in $allTokens) { + $expected = if ($ExpectedCounts.Contains($token)) { [int]$ExpectedCounts[$token] } else { 0 } + $actual = if ($ActualCounts.Contains($token)) { [int]$ActualCounts[$token] } else { 0 } + + if ($expected -eq $actual) { + continue + } + + if ($actual -lt $expected) { + $mismatches.Add("missing $token (expected $expected, found $actual)") + } + else { + $mismatches.Add("unexpected $token (expected $expected, found $actual)") + } + } + + return @($mismatches) +} + +$issues = 0 +$validatedFiles = 0 + +try { + $resolvedLanguagesDirectory = Resolve-LanguagesDirectory + if (-not (Test-Path -Path $resolvedLanguagesDirectory -PathType Container)) { + throw "Languages directory not found: $resolvedLanguagesDirectory" + } + + $languageFiles = Get-ChildItem -Path $resolvedLanguagesDirectory -Filter 'lang_*.json' -File | Sort-Object Name + foreach ($languageFile in $languageFiles) { + try { + $translations = Read-JsonObject -Path $languageFile.FullName + } + catch { + $issues += 1 + Write-Output "[$($languageFile.Name)] Failed to parse JSON: $($_.Exception.Message)" + continue + } + + $validatedFiles += 1 + foreach ($entry in $translations.GetEnumerator()) { + $sourceText = [string]$entry.Key + $translatedText = if ($null -eq $entry.Value) { '' } else { [string]$entry.Value } + + if ([string]::IsNullOrWhiteSpace($translatedText)) { + continue + } + + $expectedCounts = Get-TokenCounts -Text $sourceText + $actualCounts = Get-TokenCounts -Text $translatedText + $mismatches = @(Get-TokenMismatches -ExpectedCounts $expectedCounts -ActualCounts $actualCounts) + + if ($mismatches.Count -eq 0) { + continue + } + + $issues += 1 + Write-Output "[$($languageFile.Name)] Placeholder mismatch for key: $sourceText" + Write-Output " Translation: $translatedText" + foreach ($mismatch in $mismatches) { + Write-Output " $mismatch" + } + } + } + + if ($issues -gt 0) { + Write-Output "Translation verification failed with $issues issue(s)." + exit 1 + } + + Write-Output "Validated $validatedFiles translation file(s); no placeholder issues found." + exit 0 +} +catch { + Write-Error $_.Exception.Message + exit 1 +} diff --git a/scripts/update-icons.ps1 b/scripts/update-icons.ps1 new file mode 100644 index 0000000..0f8d22d --- /dev/null +++ b/scripts/update-icons.ps1 @@ -0,0 +1,410 @@ +#!/usr/bin/env pwsh +<# +.SYNOPSIS + Maintains and validates the checked-in icon database JSON. + +.DESCRIPTION + Treats WebBasedData/screenshot-database-v2.json as the source of truth, + recalculates package_count from the JSON payload, and can validate icon and + screenshot URLs while honoring invalid_urls.txt. + +.EXAMPLE + ./scripts/update-icons.ps1 + + Recomputes package_count and rewrites screenshot-database-v2.json. + +.EXAMPLE + ./scripts/update-icons.ps1 -Validate -MaxPackages 25 + + Validates the first 25 package entries from screenshot-database-v2.json. + +.EXAMPLE + ./scripts/update-icons.ps1 -Validate -AppendInvalidUrls + + Validates all icon and screenshot URLs and appends any new failures to + WebBasedData/invalid_urls.txt. +#> + +[CmdletBinding(DefaultParameterSetName = 'Sync')] +param( + [Parameter(ParameterSetName = 'Sync')] + [switch] $Sync, + + [Parameter(ParameterSetName = 'Validate')] + [switch] $Validate, + + [string] $JsonPath = 'WebBasedData/screenshot-database-v2.json', + [string] $InvalidUrlsPath = 'WebBasedData/invalid_urls.txt', + [switch] $AppendInvalidUrls, + [int] $MaxPackages, + [int] $MaxRetries = 2, + [int] $RetryDelayMilliseconds = 200, + [int] $RequestTimeoutSeconds = 15 +) + +Set-StrictMode -Version Latest +$ErrorActionPreference = 'Stop' + +$RepoRoot = [System.IO.Path]::GetFullPath((Join-Path $PSScriptRoot '..')) + +if (-not $PSBoundParameters.ContainsKey('Sync') -and -not $PSBoundParameters.ContainsKey('Validate')) { + $Sync = $true +} + +function Resolve-RepoPath { + param( + [Parameter(Mandatory)] + [string] $Path + ) + + if ([System.IO.Path]::IsPathRooted($Path)) { + return [System.IO.Path]::GetFullPath($Path) + } + + return [System.IO.Path]::GetFullPath((Join-Path $RepoRoot $Path)) +} + +function Write-Utf8File { + param( + [Parameter(Mandatory)] + [string] $Path, + + [Parameter(Mandatory)] + [AllowEmptyString()] + [string] $Content + ) + + $encoding = [System.Text.UTF8Encoding]::new($false) + [System.IO.File]::WriteAllText($Path, $Content, $encoding) +} + +function Get-ForbiddenUrlSet { + param( + [Parameter(Mandatory)] + [string] $Path + ) + + $lookup = [System.Collections.Generic.HashSet[string]]::new([System.StringComparer]::OrdinalIgnoreCase) + if (-not (Test-Path -LiteralPath $Path)) { + return ,$lookup + } + + foreach ($line in [System.IO.File]::ReadAllLines($Path)) { + $value = $line.Trim() + if ($value.Length -gt 0) { + [void] $lookup.Add($value) + } + } + + return ,$lookup +} + +function ConvertTo-ForbiddenUrlSet { + param( + [AllowNull()] + [object] $Value + ) + + $lookup = [System.Collections.Generic.HashSet[string]]::new([System.StringComparer]::OrdinalIgnoreCase) + if ($null -eq $Value) { + return ,$lookup + } + + foreach ($item in @($Value)) { + if ($null -eq $item) { + continue + } + + $text = [string] $item + if ([string]::IsNullOrWhiteSpace($text)) { + continue + } + + [void] $lookup.Add($text) + } + + return ,$lookup +} + +function Read-IconDatabase { + param( + [Parameter(Mandatory)] + [string] $Path + ) + + if (-not (Test-Path -LiteralPath $Path)) { + throw "Icon database file not found: $Path" + } + + $database = Get-Content -LiteralPath $Path -Raw | ConvertFrom-Json -AsHashtable + if (-not ($database -is [System.Collections.IDictionary])) { + throw 'Icon database root must be a JSON object.' + } + + if (-not $database.Contains('icons_and_screenshots')) { + throw 'Icon database is missing icons_and_screenshots.' + } + + if (-not ($database['icons_and_screenshots'] -is [System.Collections.IDictionary])) { + throw 'icons_and_screenshots must be a JSON object.' + } + + if (-not $database.Contains('package_count')) { + $database['package_count'] = [ordered]@{} + } + + return $database +} + +function Normalize-Entry { + param( + [Parameter(Mandatory)] + [System.Collections.IDictionary] $Entry + ) + + if (-not $Entry.Contains('icon') -or $null -eq $Entry['icon']) { + $Entry['icon'] = '' + } + + if (-not $Entry.Contains('images') -or $null -eq $Entry['images']) { + $Entry['images'] = @() + } + + $images = @() + $seenImages = [System.Collections.Generic.HashSet[string]]::new([System.StringComparer]::Ordinal) + foreach ($image in @($Entry['images'])) { + if ($null -eq $image) { + continue + } + + $trimmedImage = [string] $image + if ([string]::IsNullOrWhiteSpace($trimmedImage)) { + continue + } + + if ($seenImages.Add($trimmedImage)) { + $images += $trimmedImage + } + } + + $Entry['icon'] = [string] $Entry['icon'] + $Entry['images'] = $images +} + +function Update-PackageCount { + param( + [Parameter(Mandatory)] + [System.Collections.IDictionary] $Database, + + [AllowNull()] + [object] $ForbiddenUrls + ) + + $ForbiddenUrls = ConvertTo-ForbiddenUrlSet -Value $ForbiddenUrls + + $entries = $Database['icons_and_screenshots'] + + $total = 0 + $done = 0 + $packagesWithIcon = 0 + $packagesWithScreenshot = 0 + $totalScreenshots = 0 + + foreach ($packageId in $entries.Keys) { + $total++ + $entry = $entries[$packageId] + Normalize-Entry -Entry $entry + + $iconUrl = [string] $entry['icon'] + $validIcon = -not [string]::IsNullOrWhiteSpace($iconUrl) -and -not $ForbiddenUrls.Contains($iconUrl) + + if ($validIcon) { + $done++ + $packagesWithIcon++ + } + + $validScreenshots = @( + $entry['images'] | Where-Object { + -not [string]::IsNullOrWhiteSpace($_) -and -not $ForbiddenUrls.Contains($_) + } + ) + if ($validScreenshots.Count -gt 0) { + $packagesWithScreenshot++ + $totalScreenshots += $validScreenshots.Count + } + } + + $Database['package_count'] = [ordered]@{ + total = $total + done = $done + packages_with_icon = $packagesWithIcon + packages_with_screenshot = $packagesWithScreenshot + total_screenshots = $totalScreenshots + } +} + +function Write-IconDatabase { + param( + [Parameter(Mandatory)] + [System.Collections.IDictionary] $Database, + + [Parameter(Mandatory)] + [string] $Path + ) + + $json = $Database | ConvertTo-Json -Depth 100 + Write-Utf8File -Path $Path -Content $json +} + +function Invoke-UrlRequest { + param( + [Parameter(Mandatory)] + [uri] $Uri, + + [Parameter(Mandatory)] + [System.Net.Http.HttpClient] $Client, + + [Parameter(Mandatory)] + [int] $MaxRetries, + + [Parameter(Mandatory)] + [int] $RetryDelayMilliseconds + ) + + $attempt = 0 + do { + try { + $request = [System.Net.Http.HttpRequestMessage]::new([System.Net.Http.HttpMethod]::Get, $Uri) + $response = $Client.Send($request, [System.Net.Http.HttpCompletionOption]::ResponseHeadersRead) + return $response + } + catch { + if ($attempt -ge $MaxRetries) { + throw + } + + $attempt++ + Start-Sleep -Milliseconds $RetryDelayMilliseconds + } + } while ($true) +} + +function Test-IconUrls { + param( + [Parameter(Mandatory)] + [System.Collections.IDictionary] $Database, + + [AllowNull()] + [object] $ForbiddenUrls, + + [Parameter(Mandatory)] + [string] $InvalidUrlsPath, + + [switch] $AppendInvalidUrls, + [int] $MaxPackages, + [int] $MaxRetries, + [int] $RetryDelayMilliseconds, + [int] $RequestTimeoutSeconds + ) + + $ForbiddenUrls = ConvertTo-ForbiddenUrlSet -Value $ForbiddenUrls + + $client = [System.Net.Http.HttpClient]::new() + $client.Timeout = [TimeSpan]::FromSeconds($RequestTimeoutSeconds) + $client.DefaultRequestHeaders.UserAgent.ParseAdd('UniGetUI-IconValidator/2.0') + + $newInvalidUrls = [System.Collections.Generic.List[string]]::new() + $inspectedPackages = 0 + $testedUrls = 0 + + try { + foreach ($packageId in $Database['icons_and_screenshots'].Keys) { + if ($MaxPackages -gt 0 -and $inspectedPackages -ge $MaxPackages) { + break + } + + $entry = $Database['icons_and_screenshots'][$packageId] + Normalize-Entry -Entry $entry + + $urls = @() + if (-not [string]::IsNullOrWhiteSpace($entry['icon'])) { + $urls += [string] $entry['icon'] + } + $urls += @($entry['images']) + + foreach ($url in $urls) { + if ([string]::IsNullOrWhiteSpace($url) -or $ForbiddenUrls.Contains($url)) { + continue + } + + $testedUrls++ + try { + $response = Invoke-UrlRequest -Uri ([uri] $url) -Client $client -MaxRetries $MaxRetries -RetryDelayMilliseconds $RetryDelayMilliseconds + try { + $statusCode = [int] $response.StatusCode + if ($statusCode -ne 200 -and $statusCode -ne 403) { + [void] $newInvalidUrls.Add($url) + Write-Warning "[$packageId] $url returned HTTP $statusCode" + } + } + finally { + $response.Dispose() + } + } + catch { + [void] $newInvalidUrls.Add($url) + Write-Warning "[$packageId] Failed to fetch $url. $($_.Exception.Message)" + } + } + + $inspectedPackages++ + } + } + finally { + $client.Dispose() + } + + $distinctInvalidUrls = $newInvalidUrls | Select-Object -Unique + if ($AppendInvalidUrls -and $distinctInvalidUrls.Count -gt 0) { + $directory = Split-Path -Parent $InvalidUrlsPath + if (-not [string]::IsNullOrWhiteSpace($directory)) { + New-Item -ItemType Directory -Path $directory -Force | Out-Null + } + + $existing = Get-ForbiddenUrlSet -Path $InvalidUrlsPath + $linesToAppend = @() + foreach ($url in $distinctInvalidUrls) { + if ($existing.Add($url)) { + $linesToAppend += $url + } + } + + if ($linesToAppend.Count -gt 0) { + [System.IO.File]::AppendAllLines( + $InvalidUrlsPath, + $linesToAppend, + [System.Text.UTF8Encoding]::new($false) + ) + } + } + + Write-Host "Packages inspected: $inspectedPackages" + Write-Host "URLs tested: $testedUrls" + Write-Host "New invalid URLs found: $($distinctInvalidUrls.Count)" +} + +$resolvedJsonPath = Resolve-RepoPath -Path $JsonPath +$resolvedInvalidUrlsPath = Resolve-RepoPath -Path $InvalidUrlsPath + +$database = Read-IconDatabase -Path $resolvedJsonPath +$forbiddenUrls = Get-ForbiddenUrlSet -Path $resolvedInvalidUrlsPath + +Update-PackageCount -Database $database -ForbiddenUrls (,$forbiddenUrls) + +if ($Validate) { + Test-IconUrls -Database $database -ForbiddenUrls (,$forbiddenUrls) -InvalidUrlsPath $resolvedInvalidUrlsPath -AppendInvalidUrls:$AppendInvalidUrls -MaxPackages $MaxPackages -MaxRetries $MaxRetries -RetryDelayMilliseconds $RetryDelayMilliseconds -RequestTimeoutSeconds $RequestTimeoutSeconds + return +} + +Write-IconDatabase -Database $database -Path $resolvedJsonPath +Write-Host "Updated icon database counts in $resolvedJsonPath" diff --git a/scripts/verify-integrity-tree.ps1 b/scripts/verify-integrity-tree.ps1 new file mode 100644 index 0000000..211376c --- /dev/null +++ b/scripts/verify-integrity-tree.ps1 @@ -0,0 +1,104 @@ +#!/usr/bin/env pwsh +<# +.SYNOPSIS + Validates a generated IntegrityTree.json against the files in a directory. + +.DESCRIPTION + This mirrors UniGetUI runtime integrity verification and can optionally fail + if the directory contains files that are not listed in IntegrityTree.json. + +.PARAMETER Path + The directory containing IntegrityTree.json and the files to validate. + +.PARAMETER FailOnUnexpectedFiles + Fail validation if files exist in the directory tree but are not present in + IntegrityTree.json. +#> + +[CmdletBinding()] +param( + [Parameter(Mandatory, Position = 0)] + [string] $Path, + + [switch] $FailOnUnexpectedFiles +) + +$ErrorActionPreference = 'Stop' + +if (-not (Test-Path $Path -PathType Container)) { + throw "The directory '$Path' does not exist." +} + +$Path = (Resolve-Path $Path).Path +$IntegrityTreePath = Join-Path $Path 'IntegrityTree.json' + +if (-not (Test-Path $IntegrityTreePath -PathType Leaf)) { + throw "IntegrityTree.json was not found in '$Path'." +} + +$rawData = Get-Content $IntegrityTreePath -Raw + +try { + $data = ConvertFrom-Json $rawData -AsHashtable +} +catch { + throw "IntegrityTree.json is not valid JSON: $($_.Exception.Message)" +} + +if ($null -eq $data) { + throw 'IntegrityTree.json did not deserialize into a JSON object.' +} + +$missingFiles = New-Object System.Collections.Generic.List[string] +$mismatchedFiles = New-Object System.Collections.Generic.List[string] +$unexpectedFiles = New-Object System.Collections.Generic.List[string] + +$expectedFiles = @{} +foreach ($entry in $data.GetEnumerator()) { + $relativePath = [string] $entry.Key + $expectedHash = [string] $entry.Value + $expectedFiles[$relativePath] = $true + + $fullPath = Join-Path $Path $relativePath + if (-not (Test-Path $fullPath -PathType Leaf)) { + $missingFiles.Add($relativePath) + continue + } + + $currentHash = (Get-FileHash $fullPath -Algorithm SHA256).Hash.ToLowerInvariant() + if ($currentHash -ne $expectedHash.ToLowerInvariant()) { + $mismatchedFiles.Add("$relativePath|expected=$expectedHash|got=$currentHash") + } +} + +if ($FailOnUnexpectedFiles) { + Get-ChildItem $Path -Recurse -File | ForEach-Object { + $relativePath = $_.FullName.Substring($Path.Length).TrimStart('\', '/') -replace '\\', '/' + if ($relativePath -eq 'IntegrityTree.json') { + return + } + + if (-not $expectedFiles.ContainsKey($relativePath)) { + $unexpectedFiles.Add($relativePath) + } + } +} + +if ($missingFiles.Count -or $mismatchedFiles.Count -or $unexpectedFiles.Count) { + if ($missingFiles.Count) { + Write-Error "Missing files listed in IntegrityTree.json:`n - $($missingFiles -join "`n - ")" + } + + if ($mismatchedFiles.Count) { + Write-Error "Files with mismatched SHA256 values:`n - $($mismatchedFiles -join "`n - ")" + } + + if ($unexpectedFiles.Count) { + Write-Error "Unexpected files not present in IntegrityTree.json:`n - $($unexpectedFiles -join "`n - ")" + } + + throw 'Integrity tree validation failed.' +} + +$validatedFileCount = $data.Count +Write-Host "Integrity tree validation succeeded for $validatedFileCount file(s) in $Path" \ No newline at end of file diff --git a/src/.editorconfig b/src/.editorconfig new file mode 100644 index 0000000..c2a8f3b --- /dev/null +++ b/src/.editorconfig @@ -0,0 +1,360 @@ +### From: https://github.com/dotnet/aspnetcore/blob/main/.editorconfig +### Last sync: ca1f641 +### Disabled: CA1305, CA2007, IDE0073, IDE0161, SYSLIB1054, csharp_prefer_braces, csharp_style_var_* +### Changed indent_size for XML and JSON +; EditorConfig to support per-solution formatting. +; Use the EditorConfig VS add-in to make this work. +; http://editorconfig.org/ +; +; Here are some resources for what's supported for .NET/C# +; https://kent-boogaart.com/blog/editorconfig-reference-for-c-developers +; https://learn.microsoft.com/visualstudio/ide/editorconfig-code-style-settings-reference +; +; Be **careful** editing this because some of the rules don't support adding a severity level +; For instance if you change to `dotnet_sort_system_directives_first = true:warning` (adding `:warning`) +; then the rule will be silently ignored. + +; This is the default for the codeline. +root = true + +[*] +indent_style = space +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true + +[*.cs] +indent_size = 4 +dotnet_sort_system_directives_first = true + +# Don't use this. qualifier +dotnet_style_qualification_for_field = false:suggestion +dotnet_style_qualification_for_property = false:suggestion + +# use int x = .. over Int32 +dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion + +# use int.MaxValue over Int32.MaxValue +dotnet_style_predefined_type_for_member_access = true:suggestion + +# Require var all the time. +csharp_style_var_for_built_in_types = false +csharp_style_var_when_type_is_apparent = true:suggestion +csharp_style_var_elsewhere = false + +# Disallow throw expressions. +csharp_style_throw_expression = false:suggestion + +# Newline settings +csharp_new_line_before_open_brace = all +csharp_new_line_before_else = true +csharp_new_line_before_catch = true +csharp_new_line_before_finally = true +csharp_new_line_before_members_in_object_initializers = true +csharp_new_line_before_members_in_anonymous_types = true + +# Namespace settings +csharp_style_namespace_declarations = file_scoped + +# Brace settings +csharp_prefer_braces = false # Prefer curly braces even for one line of code + +# name all constant fields using PascalCase +dotnet_naming_rule.constant_fields_should_be_pascal_case.severity = suggestion +dotnet_naming_rule.constant_fields_should_be_pascal_case.symbols = constant_fields +dotnet_naming_rule.constant_fields_should_be_pascal_case.style = pascal_case_style +dotnet_naming_symbols.constant_fields.applicable_kinds = field +dotnet_naming_symbols.constant_fields.required_modifiers = const +dotnet_naming_style.pascal_case_style.capitalization = pascal_case + +# internal and private fields should be _camelCase +dotnet_naming_rule.camel_case_for_private_internal_fields.severity = suggestion +dotnet_naming_rule.camel_case_for_private_internal_fields.symbols = private_internal_fields +dotnet_naming_rule.camel_case_for_private_internal_fields.style = camel_case_underscore_style +dotnet_naming_symbols.private_internal_fields.applicable_kinds = field +dotnet_naming_symbols.private_internal_fields.applicable_accessibilities = private, internal +dotnet_naming_style.camel_case_underscore_style.required_prefix = _ +dotnet_naming_style.camel_case_underscore_style.capitalization = camel_case + +[*.{xml,config,*proj,nuspec,props,resx,targets,yml,tasks}] +indent_size = 4 + +# Xml config files +[*.{props,targets,ruleset,config,nuspec,resx,vsixmanifest,vsct}] +indent_size = 4 + +[*.json] +indent_size = 4 + +[*.{ps1,psm1}] +indent_size = 4 + +[*.sh] +indent_size = 4 +end_of_line = lf + +[*.{razor,cshtml}] +charset = utf-8-bom + +[*.{cs,vb}] + +# SYSLIB1054: Use 'LibraryImportAttribute' instead of 'DllImportAttribute' to generate P/Invoke marshalling code at compile time +# dotnet_diagnostic.SYSLIB1054.severity = warning + +# CA1018: Mark attributes with AttributeUsageAttribute +dotnet_diagnostic.CA1018.severity = warning + +# CA1047: Do not declare protected member in sealed type +dotnet_diagnostic.CA1047.severity = warning + +# CA1305: Specify IFormatProvider +#dotnet_diagnostic.CA1305.severity = warning + +# CA1507: Use nameof to express symbol names +dotnet_diagnostic.CA1507.severity = warning + +# CA1510: Use ArgumentNullException throw helper +dotnet_diagnostic.CA1510.severity = warning + +# CA1511: Use ArgumentException throw helper +dotnet_diagnostic.CA1511.severity = warning + +# CA1512: Use ArgumentOutOfRangeException throw helper +dotnet_diagnostic.CA1512.severity = warning + +# CA1513: Use ObjectDisposedException throw helper +dotnet_diagnostic.CA1513.severity = warning + +# CA1725: Parameter names should match base declaration +dotnet_diagnostic.CA1725.severity = suggestion + +# CA1802: Use literals where appropriate +dotnet_diagnostic.CA1802.severity = warning + +# CA1805: Do not initialize unnecessarily +dotnet_diagnostic.CA1805.severity = warning + +# CA1810: Do not initialize unnecessarily +dotnet_diagnostic.CA1810.severity = warning + +# CA1821: Remove empty Finalizers +dotnet_diagnostic.CA1821.severity = warning + +# CA1822: Make member static +dotnet_diagnostic.CA1822.severity = warning +dotnet_code_quality.CA1822.api_surface = private, internal + +# CA1823: Avoid unused private fields +dotnet_diagnostic.CA1823.severity = warning + +# CA1825: Avoid zero-length array allocations +dotnet_diagnostic.CA1825.severity = warning + +# CA1826: Do not use Enumerable methods on indexable collections. Instead use the collection directly +dotnet_diagnostic.CA1826.severity = suggestion + +# CA1827: Do not use Count() or LongCount() when Any() can be used +dotnet_diagnostic.CA1827.severity = warning + +# CA1828: Do not use CountAsync() or LongCountAsync() when AnyAsync() can be used +dotnet_diagnostic.CA1828.severity = warning + +# CA1829: Use Length/Count property instead of Count() when available +dotnet_diagnostic.CA1829.severity = warning + +# CA1830: Prefer strongly-typed Append and Insert method overloads on StringBuilder +dotnet_diagnostic.CA1830.severity = warning + +# CA1831: Use AsSpan or AsMemory instead of Range-based indexers when appropriate +dotnet_diagnostic.CA1831.severity = warning + +# CA1832: Use AsSpan or AsMemory instead of Range-based indexers when appropriate +dotnet_diagnostic.CA1832.severity = warning + +# CA1833: Use AsSpan or AsMemory instead of Range-based indexers when appropriate +dotnet_diagnostic.CA1833.severity = warning + +# CA1834: Consider using 'StringBuilder.Append(char)' when applicable +dotnet_diagnostic.CA1834.severity = warning + +# CA1835: Prefer the 'Memory'-based overloads for 'ReadAsync' and 'WriteAsync' +dotnet_diagnostic.CA1835.severity = warning + +# CA1836: Prefer IsEmpty over Count +dotnet_diagnostic.CA1836.severity = warning + +# CA1837: Use 'Environment.ProcessId' +dotnet_diagnostic.CA1837.severity = warning + +# CA1838: Avoid 'StringBuilder' parameters for P/Invokes +dotnet_diagnostic.CA1838.severity = warning + +# CA1839: Use 'Environment.ProcessPath' +dotnet_diagnostic.CA1839.severity = warning + +# CA1840: Use 'Environment.CurrentManagedThreadId' +dotnet_diagnostic.CA1840.severity = warning + +# CA1841: Prefer Dictionary.Contains methods +dotnet_diagnostic.CA1841.severity = warning + +# CA1842: Do not use 'WhenAll' with a single task +dotnet_diagnostic.CA1842.severity = warning + +# CA1843: Do not use 'WaitAll' with a single task +dotnet_diagnostic.CA1843.severity = warning + +# CA1844: Provide memory-based overrides of async methods when subclassing 'Stream' +dotnet_diagnostic.CA1844.severity = warning + +# CA1845: Use span-based 'string.Concat' +dotnet_diagnostic.CA1845.severity = warning + +# CA1846: Prefer AsSpan over Substring +dotnet_diagnostic.CA1846.severity = warning + +# CA1847: Use string.Contains(char) instead of string.Contains(string) with single characters +dotnet_diagnostic.CA1847.severity = warning + +# CA1852: Seal internal types +dotnet_diagnostic.CA1852.severity = warning + +# CA1854: Prefer the IDictionary.TryGetValue(TKey, out TValue) method +dotnet_diagnostic.CA1854.severity = warning + +# CA1855: Prefer 'Clear' over 'Fill' +dotnet_diagnostic.CA1855.severity = warning + +# CA1856: Incorrect usage of ConstantExpected attribute +dotnet_diagnostic.CA1856.severity = error + +# CA1857: A constant is expected for the parameter +dotnet_diagnostic.CA1857.severity = warning + +# CA1858: Use 'StartsWith' instead of 'IndexOf' +dotnet_diagnostic.CA1858.severity = warning + +# CA2007: Consider calling ConfigureAwait on the awaited task +# dotnet_diagnostic.CA2007.severity = warning + +# CA2008: Do not create tasks without passing a TaskScheduler +dotnet_diagnostic.CA2008.severity = warning + +# CA2009: Do not call ToImmutableCollection on an ImmutableCollection value +dotnet_diagnostic.CA2009.severity = warning + +# CA2011: Avoid infinite recursion +dotnet_diagnostic.CA2011.severity = warning + +# CA2012: Use ValueTask correctly +dotnet_diagnostic.CA2012.severity = warning + +# CA2013: Do not use ReferenceEquals with value types +dotnet_diagnostic.CA2013.severity = warning + +# CA2014: Do not use stackalloc in loops. +dotnet_diagnostic.CA2014.severity = warning + +# CA2016: Forward the 'CancellationToken' parameter to methods that take one +dotnet_diagnostic.CA2016.severity = warning + +# CA2022: Avoid inexact read with `Stream.Read` +dotnet_diagnostic.CA2022.severity = warning + +# CA2200: Rethrow to preserve stack details +dotnet_diagnostic.CA2200.severity = warning + +# CA2201: Do not raise reserved exception types +dotnet_diagnostic.CA2201.severity = warning + +# CA2208: Instantiate argument exceptions correctly +dotnet_diagnostic.CA2208.severity = warning + +# CA2245: Do not assign a property to itself +dotnet_diagnostic.CA2245.severity = warning + +# CA2246: Assigning symbol and its member in the same statement +dotnet_diagnostic.CA2246.severity = warning + +# CA2249: Use string.Contains instead of string.IndexOf to improve readability. +dotnet_diagnostic.CA2249.severity = warning + +# IDE0005: Remove unnecessary usings +dotnet_diagnostic.IDE0005.severity = suggestion + +# IDE0011: Curly braces to surround blocks of code +dotnet_diagnostic.IDE0011.severity = warning + +# IDE0020: Use pattern matching to avoid is check followed by a cast (with variable) +dotnet_diagnostic.IDE0020.severity = warning + +# IDE0029: Use coalesce expression (non-nullable types) +dotnet_diagnostic.IDE0029.severity = warning + +# IDE0030: Use coalesce expression (nullable types) +dotnet_diagnostic.IDE0030.severity = warning + +# IDE0031: Use null propagation +dotnet_diagnostic.IDE0031.severity = warning + +# IDE0035: Remove unreachable code +dotnet_diagnostic.IDE0035.severity = warning + +# IDE0036: Order modifiers +csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async:suggestion +dotnet_diagnostic.IDE0036.severity = warning + +# IDE0038: Use pattern matching to avoid is check followed by a cast (without variable) +dotnet_diagnostic.IDE0038.severity = warning + +# IDE0043: Format string contains invalid placeholder +dotnet_diagnostic.IDE0043.severity = warning + +# IDE0044: Make field readonly +dotnet_diagnostic.IDE0044.severity = warning + +# IDE0051: Remove unused private members +dotnet_diagnostic.IDE0051.severity = warning + +# IDE0055: All formatting rules +dotnet_diagnostic.IDE0055.severity = suggestion + +# IDE0059: Unnecessary assignment to a value +dotnet_diagnostic.IDE0059.severity = warning + +# IDE0060: Remove unused parameter +dotnet_code_quality_unused_parameters = non_public +dotnet_diagnostic.IDE0060.severity = warning + +# IDE0062: Make local function static +dotnet_diagnostic.IDE0062.severity = warning + +# IDE0073: File header +#dotnet_diagnostic.IDE0073.severity = warning +#file_header_template = Licensed to the .NET Foundation under one or more agreements.\nThe .NET Foundation licenses this file to you under the MIT license. + +# IDE0161: Convert to file-scoped namespace +#dotnet_diagnostic.IDE0161.severity = warning + +# IDE0200: Lambda expression can be removed +dotnet_diagnostic.IDE0200.severity = warning + +# IDE2000: Disallow multiple blank lines +dotnet_style_allow_multiple_blank_lines_experimental = false +dotnet_diagnostic.IDE2000.severity = warning + +# WinUI code-behind relies on XAML-wired event handlers that Roslyn cannot +# reliably see as C# references. +[UniGetUI/**.cs] +dotnet_diagnostic.IDE0051.severity = suggestion +dotnet_diagnostic.IDE0060.severity = suggestion + +[UniGetUI/Controls/SourceManager.xaml.cs] +dotnet_diagnostic.IDE0044.severity = suggestion + +###### End of EditorConfig from dotnet/aspnetcore repository + +### Our rules + +# https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/statements/using +csharp_prefer_simple_using_statement = false diff --git a/src/Directory.Build.props b/src/Directory.Build.props new file mode 100644 index 0000000..8980d46 --- /dev/null +++ b/src/Directory.Build.props @@ -0,0 +1,67 @@ + + + enable + + + 10.0.103 + Devolutions Inc. and the contributors + Devolutions Inc. + enable + + + + net10.0 + 10.0.26100.0 + $(PortableTargetFramework)-windows$(WindowsTargetPlatformVersion) + + + + true + $(PortableTargetFramework);$(WindowsTargetFramework) + $(PortableTargetFramework) + + + + $(SharedTargetFrameworks) + + + + 10.0.19041.0 + 10.0.26100.56 + + + + x64;arm64 + true + false + Debug;Release + + + + false + true + + + + true + true + true + + true + true + + + + latest + true + $(NoWarn);EnableGenerateDocumentationFile + + diff --git a/src/ExternalLibraries.Clipboard/ExternalLibraries.Clipboard.csproj b/src/ExternalLibraries.Clipboard/ExternalLibraries.Clipboard.csproj new file mode 100644 index 0000000..317faf9 --- /dev/null +++ b/src/ExternalLibraries.Clipboard/ExternalLibraries.Clipboard.csproj @@ -0,0 +1,6 @@ + + + $(WindowsTargetFramework) + + + diff --git a/src/ExternalLibraries.Clipboard/WindowsClipboard.cs b/src/ExternalLibraries.Clipboard/WindowsClipboard.cs new file mode 100644 index 0000000..a3a598e --- /dev/null +++ b/src/ExternalLibraries.Clipboard/WindowsClipboard.cs @@ -0,0 +1,170 @@ +using System.ComponentModel; +using System.Runtime.InteropServices; +using System.Text; + +namespace ExternalLibraries.Clipboard +{ + public static class WindowsClipboard + { + private const uint cfUnicodeText = 13; + + public static string? GetText() + { + if (!IsClipboardFormatAvailable(cfUnicodeText)) + { + return null; + } + + TryOpenClipboard(); + + return InnerGet(); + } + + public static void SetText(string text) + { + TryOpenClipboard(); + + InnerSet(text); + } + + private static void InnerSet(string text) + { + EmptyClipboard(); + IntPtr hGlobal = default; + try + { + int bytes = (text.Length + 1) * 2; + hGlobal = Marshal.AllocHGlobal(bytes); + + if (hGlobal == default) + { + ThrowWin32(); + } + + IntPtr target = GlobalLock(hGlobal); + + if (target == default) + { + ThrowWin32(); + } + + try + { + Marshal.Copy(text.ToCharArray(), 0, target, text.Length); + } + finally + { + GlobalUnlock(target); + } + + if (SetClipboardData(cfUnicodeText, hGlobal) == default) + { + ThrowWin32(); + } + + hGlobal = default; + } + finally + { + if (hGlobal != default) + { + Marshal.FreeHGlobal(hGlobal); + } + + CloseClipboard(); + } + } + + private static string? InnerGet() + { + IntPtr handle = default; + + IntPtr pointer = default; + try + { + handle = GetClipboardData(cfUnicodeText); + if (handle == default) + { + return null; + } + + pointer = GlobalLock(handle); + if (pointer == default) + { + return null; + } + + int size = GlobalSize(handle); + byte[] buff = new byte[size]; + + Marshal.Copy(pointer, buff, 0, size); + + return Encoding.Unicode.GetString(buff).TrimEnd('\0'); + } + finally + { + if (pointer != default) + { + GlobalUnlock(handle); + } + + CloseClipboard(); + } + } + + private static void TryOpenClipboard() + { + int num = 10; + while (true) + { + if (OpenClipboard(default)) + { + break; + } + + if (--num == 0) + { + ThrowWin32(); + } + + Thread.Sleep(100); + } + } + + private static void ThrowWin32() + { + throw new Win32Exception(Marshal.GetLastWin32Error()); + } + + [DllImport("User32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool IsClipboardFormatAvailable(uint format); + + [DllImport("User32.dll", SetLastError = true)] + private static extern IntPtr GetClipboardData(uint uFormat); + + [DllImport("user32.dll", SetLastError = true)] + private static extern IntPtr SetClipboardData(uint uFormat, IntPtr data); + + [DllImport("kernel32.dll", SetLastError = true)] + private static extern IntPtr GlobalLock(IntPtr hMem); + + [DllImport("kernel32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool GlobalUnlock(IntPtr hMem); + + [DllImport("user32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool OpenClipboard(IntPtr hWndNewOwner); + + [DllImport("user32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool CloseClipboard(); + + [DllImport("user32.dll")] + private static extern bool EmptyClipboard(); + + [DllImport("Kernel32.dll", SetLastError = true)] + private static extern int GlobalSize(IntPtr hMem); + } +} diff --git a/src/ExternalLibraries.FilePickers/Classes/FileOpenDialogRCW.cs b/src/ExternalLibraries.FilePickers/Classes/FileOpenDialogRCW.cs new file mode 100644 index 0000000..83181b7 --- /dev/null +++ b/src/ExternalLibraries.FilePickers/Classes/FileOpenDialogRCW.cs @@ -0,0 +1,14 @@ +using System.Runtime.InteropServices; +using ExternalLibraries.Pickers.Guids; + +namespace ExternalLibraries.Pickers.Classes; + +// --------------------------------------------------- +// .NET classes representing runtime callable wrappers +[ + ComImport, + ClassInterface(ClassInterfaceType.None), + TypeLibType(TypeLibTypeFlags.FCanCreate), + Guid(CLSIDGuid.FileOpenDialog) +] +internal class FileOpenDialogRCW { } diff --git a/src/ExternalLibraries.FilePickers/Classes/FileSaveDialogRCW.cs b/src/ExternalLibraries.FilePickers/Classes/FileSaveDialogRCW.cs new file mode 100644 index 0000000..ffd05fd --- /dev/null +++ b/src/ExternalLibraries.FilePickers/Classes/FileSaveDialogRCW.cs @@ -0,0 +1,14 @@ +using System.Runtime.InteropServices; +using ExternalLibraries.Pickers.Guids; + +namespace ExternalLibraries.Pickers.Classes; + +// --------------------------------------------------- +// .NET classes representing runtime callable wrappers +[ + ComImport, + ClassInterface(ClassInterfaceType.None), + TypeLibType(TypeLibTypeFlags.FCanCreate), + Guid(CLSIDGuid.FileSaveDialog) +] +internal class FileSaveDialogRCW { } diff --git a/src/ExternalLibraries.FilePickers/Classes/Helper.cs b/src/ExternalLibraries.FilePickers/Classes/Helper.cs new file mode 100644 index 0000000..fe98c22 --- /dev/null +++ b/src/ExternalLibraries.FilePickers/Classes/Helper.cs @@ -0,0 +1,105 @@ +using System.Runtime.InteropServices; +using ExternalLibraries.Pickers.Enums; +using ExternalLibraries.Pickers.Interfaces; +using ExternalLibraries.Pickers.Structures; + +namespace ExternalLibraries.Pickers.Classes; + +internal static class Helper +{ + /// + /// Shows FileOpenDialog. + /// + /// Window handle where dialog should appear. + /// File open dialog options. + /// List of extensions applied on dialog. + /// Path to selected file, folder or empty string. + internal static string ShowOpen(nint windowHandle, FOS fos, List? typeFilters = null) + { + FileOpenDialog dialog = new(); + IShellItem item = null!; + try + { + dialog.SetOptions(fos); + + if (typeFilters is not null) + { + typeFilters.Insert(0, string.Join("; ", typeFilters)); + COMDLG_FILTERSPEC[] filterSpecs = typeFilters + .Select(f => new COMDLG_FILTERSPEC(f)) + .ToArray(); + + dialog.SetFileTypes((uint)filterSpecs.Length, filterSpecs); + } + + if (dialog.Show(windowHandle) != 0) + { + return string.Empty; + } + + dialog.GetResult(out item); + item.GetDisplayName(SIGDN.SIGDN_FILESYSPATH, out string path); + return path; + } + finally + { +#pragma warning disable CA1416 + if (item is not null) + Marshal.ReleaseComObject(item); + Marshal.ReleaseComObject(dialog); +#pragma warning restore CA1416 + } + } + + internal static string ShowSave( + nint windowHandle, + FOS fos, + List? typeFilters = null, + string name = "" + ) + { + FileSaveDialog dialog = new(); + IShellItem item = null!; + try + { + dialog.SetOptions(fos); + + if (typeFilters is not null) + { + COMDLG_FILTERSPEC[] filterSpecs = typeFilters + .Select(f => new COMDLG_FILTERSPEC(f)) + .ToArray(); + + dialog.SetFileTypes((uint)filterSpecs.Length, filterSpecs); + } + + if (!string.IsNullOrEmpty(name)) + { + dialog.SetFileName(name); + } + + if (dialog.Show(windowHandle) != 0) + { + return string.Empty; + } + + dialog.GetResult(out item); + item.GetDisplayName(SIGDN.SIGDN_FILESYSPATH, out string path); + + dialog.GetFileTypeIndex(out uint selection); + string fileExtension = typeFilters?[(int)selection - 1] ?? ".txt"; + if (fileExtension.Length > 0 && fileExtension[0] == '*') + fileExtension = fileExtension.TrimStart('*'); + + return path.Contains(fileExtension) ? path : path + fileExtension; + } + finally + { +#pragma warning disable CA1416 + if (item is not null) + Marshal.ReleaseComObject(item); + Marshal.ReleaseComObject(dialog); +#pragma warning restore CA1416 + } + } +} diff --git a/src/ExternalLibraries.FilePickers/Enums/FDAP.cs b/src/ExternalLibraries.FilePickers/Enums/FDAP.cs new file mode 100644 index 0000000..ff69811 --- /dev/null +++ b/src/ExternalLibraries.FilePickers/Enums/FDAP.cs @@ -0,0 +1,8 @@ +namespace ExternalLibraries.Pickers.Enums; + +// https://learn.microsoft.com/en-us/windows/win32/api/shobjidl_core/ne-shobjidl_core-fdap +internal enum FDAP +{ + FDAP_BOTTOM = 0x00000000, + FDAP_TOP = 0x00000001, +} diff --git a/src/ExternalLibraries.FilePickers/Enums/FDE_OVERWRITE_RESPONSE.cs b/src/ExternalLibraries.FilePickers/Enums/FDE_OVERWRITE_RESPONSE.cs new file mode 100644 index 0000000..4056b05 --- /dev/null +++ b/src/ExternalLibraries.FilePickers/Enums/FDE_OVERWRITE_RESPONSE.cs @@ -0,0 +1,9 @@ +namespace ExternalLibraries.Pickers.Enums; + +// https://learn.microsoft.com/en-us/windows/win32/api/shobjidl_core/ne-shobjidl_core-fde_overwrite_response +internal enum FDE_OVERWRITE_RESPONSE +{ + FDEOR_DEFAULT = 0x00000000, + FDEOR_ACCEPT = 0x00000001, + FDEOR_REFUSE = 0x00000002, +} diff --git a/src/ExternalLibraries.FilePickers/Enums/FDE_SHAREVIOLATION_RESPONSE.cs b/src/ExternalLibraries.FilePickers/Enums/FDE_SHAREVIOLATION_RESPONSE.cs new file mode 100644 index 0000000..0c7cb4d --- /dev/null +++ b/src/ExternalLibraries.FilePickers/Enums/FDE_SHAREVIOLATION_RESPONSE.cs @@ -0,0 +1,9 @@ +namespace ExternalLibraries.Pickers.Enums; + +// https://learn.microsoft.com/en-us/windows/win32/api/shobjidl_core/ne-shobjidl_core-fde_shareviolation_response +internal enum FDE_SHAREVIOLATION_RESPONSE +{ + FDESVR_DEFAULT = 0x00000000, + FDESVR_ACCEPT = 0x00000001, + FDESVR_REFUSE = 0x00000002, +} diff --git a/src/ExternalLibraries.FilePickers/Enums/FOS.cs b/src/ExternalLibraries.FilePickers/Enums/FOS.cs new file mode 100644 index 0000000..3bfb7aa --- /dev/null +++ b/src/ExternalLibraries.FilePickers/Enums/FOS.cs @@ -0,0 +1,27 @@ +namespace ExternalLibraries.Pickers.Enums; + +[Flags] +// https://learn.microsoft.com/ru-ru/windows/win32/api/shobjidl_core/ne-shobjidl_core-_fileopendialogoptions +internal enum FOS : uint +{ + FOS_OVERWRITEPROMPT = 0x00000002, + FOS_STRICTFILETYPES = 0x00000004, + FOS_NOCHANGEDIR = 0x00000008, + FOS_PICKFOLDERS = 0x00000020, + FOS_FORCEFILESYSTEM = 0x00000040, // Ensure that items returned are filesystem items. + FOS_ALLNONSTORAGEITEMS = 0x00000080, // Allow choosing items that have no storage. + FOS_NOVALIDATE = 0x00000100, + FOS_ALLOWMULTISELECT = 0x00000200, + FOS_PATHMUSTEXIST = 0x00000800, + FOS_FILEMUSTEXIST = 0x00001000, + FOS_CREATEPROMPT = 0x00002000, + FOS_SHAREAWARE = 0x00004000, + FOS_NOREADONLYRETURN = 0x00008000, + FOS_NOTESTFILECREATE = 0x00010000, + FOS_HIDEMRUPLACES = 0x00020000, + FOS_HIDEPINNEDPLACES = 0x00040000, + FOS_NODEREFERENCELINKS = 0x00100000, + FOS_DONTADDTORECENT = 0x02000000, + FOS_FORCESHOWHIDDEN = 0x10000000, + FOS_DEFAULTNOMINIMODE = 0x20000000, +} diff --git a/src/ExternalLibraries.FilePickers/Enums/HRESULT.cs b/src/ExternalLibraries.FilePickers/Enums/HRESULT.cs new file mode 100644 index 0000000..3bec281 --- /dev/null +++ b/src/ExternalLibraries.FilePickers/Enums/HRESULT.cs @@ -0,0 +1,10 @@ +namespace ExternalLibraries.Pickers.Enums; + +internal enum HRESULT : long +{ + S_FALSE = 0x0001, + S_OK = 0x0000, + E_INVALIDARG = 0x80070057, + E_OUTOFMEMORY = 0x8007000E, + ERROR_CANCELLED = 0x800704C7, +} diff --git a/src/ExternalLibraries.FilePickers/Enums/SIATTRIBFLAGS.cs b/src/ExternalLibraries.FilePickers/Enums/SIATTRIBFLAGS.cs new file mode 100644 index 0000000..868ce8b --- /dev/null +++ b/src/ExternalLibraries.FilePickers/Enums/SIATTRIBFLAGS.cs @@ -0,0 +1,9 @@ +namespace ExternalLibraries.Pickers.Enums; + +// https://learn.microsoft.com/en-us/windows/win32/api/shobjidl_core/nf-shobjidl_core-ishellitemarray-getattributes +internal enum SIATTRIBFLAGS +{ + SIATTRIBFLAGS_AND = 0x00000001, // if multiple items and the attributes together. + SIATTRIBFLAGS_OR = 0x00000002, // if multiple items or the attributes together. + SIATTRIBFLAGS_APPCOMPAT = 0x00000003, // Call GetAttributes directly on the ShellFolder for multiple attributes +} diff --git a/src/ExternalLibraries.FilePickers/Enums/SIGDN.cs b/src/ExternalLibraries.FilePickers/Enums/SIGDN.cs new file mode 100644 index 0000000..40037cb --- /dev/null +++ b/src/ExternalLibraries.FilePickers/Enums/SIGDN.cs @@ -0,0 +1,15 @@ +namespace ExternalLibraries.Pickers.Enums; + +// https://learn.microsoft.com/en-us/windows/win32/api/shobjidl_core/ne-shobjidl_core-sigdn +internal enum SIGDN : uint +{ + SIGDN_NORMALDISPLAY = 0x00000000, // SHGDN_NORMAL + SIGDN_PARENTRELATIVEPARSING = 0x80018001, // SHGDN_INFOLDER | SHGDN_FORPARSING + SIGDN_DESKTOPABSOLUTEPARSING = 0x80028000, // SHGDN_FORPARSING + SIGDN_PARENTRELATIVEEDITING = 0x80031001, // SHGDN_INFOLDER | SHGDN_FOREDITING + SIGDN_DESKTOPABSOLUTEEDITING = 0x8004c000, // SHGDN_FORPARSING | SHGDN_FORADDRESSBAR + SIGDN_FILESYSPATH = 0x80058000, // SHGDN_FORPARSING + SIGDN_URL = 0x80068000, // SHGDN_FORPARSING + SIGDN_PARENTRELATIVEFORADDRESSBAR = 0x8007c001, // SHGDN_INFOLDER | SHGDN_FORPARSING | SHGDN_FORADDRESSBAR + SIGDN_PARENTRELATIVE = 0x80080001, // SHGDN_INFOLDER +} diff --git a/src/ExternalLibraries.FilePickers/ExternalLibraries.FilePickers.csproj b/src/ExternalLibraries.FilePickers/ExternalLibraries.FilePickers.csproj new file mode 100644 index 0000000..317faf9 --- /dev/null +++ b/src/ExternalLibraries.FilePickers/ExternalLibraries.FilePickers.csproj @@ -0,0 +1,6 @@ + + + $(WindowsTargetFramework) + + + diff --git a/src/ExternalLibraries.FilePickers/FileOpenPicker.cs b/src/ExternalLibraries.FilePickers/FileOpenPicker.cs new file mode 100644 index 0000000..365e393 --- /dev/null +++ b/src/ExternalLibraries.FilePickers/FileOpenPicker.cs @@ -0,0 +1,34 @@ +using ExternalLibraries.Pickers.Classes; +using ExternalLibraries.Pickers.Enums; + +namespace ExternalLibraries.Pickers; + +/// +/// Class responsible for file pick dialog. +/// +public class FileOpenPicker +{ + /// + /// Window handle where dialog should appear. + /// + private readonly IntPtr _windowHandle; + + /// + /// File pick dialog. + /// + /// Window handle where dialog should appear. + public FileOpenPicker(IntPtr windowHandle) + { + _windowHandle = windowHandle; + } + + /// + /// Shows file pick dialog. + /// + /// List of extensions applied on dialog. + /// Path to selected file or empty string. + public string Show(List? typeFilters = null) + { + return Helper.ShowOpen(_windowHandle, FOS.FOS_FORCEFILESYSTEM, typeFilters); + } +} diff --git a/src/ExternalLibraries.FilePickers/FileSavePicker.cs b/src/ExternalLibraries.FilePickers/FileSavePicker.cs new file mode 100644 index 0000000..917ad60 --- /dev/null +++ b/src/ExternalLibraries.FilePickers/FileSavePicker.cs @@ -0,0 +1,36 @@ +using ExternalLibraries.Pickers.Classes; +using ExternalLibraries.Pickers.Enums; + +namespace ExternalLibraries.Pickers; + +/// +/// Class responsible for file pick dialog. +/// +public class FileSavePicker +{ + /// + /// Window handle where dialog should appear. + /// + private readonly IntPtr _windowHandle; + + /// + /// File pick dialog. + /// + /// Window handle where dialog should appear. + public FileSavePicker(IntPtr windowHandle) + { + _windowHandle = windowHandle; + } + + /// + /// Shows file pick dialog. + /// + /// List of extensions applied on dialog. + /// Default name for the file. + /// Path to selected file or empty string. + public string Show(List? typeFilters = null, string defaultName = "") + { + FOS options = FOS.FOS_FORCEFILESYSTEM | FOS.FOS_OVERWRITEPROMPT; + return Helper.ShowSave(_windowHandle, options, typeFilters, defaultName); + } +} diff --git a/src/ExternalLibraries.FilePickers/FolderPicker.cs b/src/ExternalLibraries.FilePickers/FolderPicker.cs new file mode 100644 index 0000000..f241217 --- /dev/null +++ b/src/ExternalLibraries.FilePickers/FolderPicker.cs @@ -0,0 +1,33 @@ +using ExternalLibraries.Pickers.Classes; +using ExternalLibraries.Pickers.Enums; + +namespace ExternalLibraries.Pickers; + +/// +/// Class responsible for folder pick dialog. +/// +public class FolderPicker +{ + /// + /// Window handle where dialog should appear. + /// + private readonly IntPtr _windowHandle; + + /// + /// Folder pick dialog. + /// + /// Window handle where dialog should appear. + public FolderPicker(IntPtr windowHandle) + { + _windowHandle = windowHandle; + } + + /// + /// Shows folder pick dialog. + /// + /// Path to selected folder or empty string. + public string Show() + { + return Helper.ShowOpen(_windowHandle, FOS.FOS_PICKFOLDERS | FOS.FOS_FORCEFILESYSTEM); + } +} diff --git a/src/ExternalLibraries.FilePickers/Guids/CLSIDGuid.cs b/src/ExternalLibraries.FilePickers/Guids/CLSIDGuid.cs new file mode 100644 index 0000000..0e42f31 --- /dev/null +++ b/src/ExternalLibraries.FilePickers/Guids/CLSIDGuid.cs @@ -0,0 +1,9 @@ +namespace ExternalLibraries.Pickers.Guids; + +internal static class CLSIDGuid +{ + public const string FileOpenDialog = "DC1C5A9C-E88A-4dde-A5A1-60F82A20AEF7"; + public const string FileSaveDialog = "C0B4E2F3-BA21-4773-8DBA-335EC946EB8B"; + public const string KnownFolderManager = "4df0c730-df9d-4ae3-9153-aa6b82e9795a"; + public const string ProgressDialog = "F8383852-FCD3-11d1-A6B9-006097DF5BD4"; +} diff --git a/src/ExternalLibraries.FilePickers/Guids/IIDGuid.cs b/src/ExternalLibraries.FilePickers/Guids/IIDGuid.cs new file mode 100644 index 0000000..22e824d --- /dev/null +++ b/src/ExternalLibraries.FilePickers/Guids/IIDGuid.cs @@ -0,0 +1,18 @@ +namespace ExternalLibraries.Pickers.Guids; + +internal static class IIDGuid +{ + public const string IModalWindow = "b4db1657-70d7-485e-8e3e-6fcb5a5c1802"; + public const string IFileDialog = "42f85136-db7e-439c-85f1-e4075d135fc8"; + public const string IFileOpenDialog = "d57c7288-d4ad-4768-be02-9d969532d960"; + public const string IFileSaveDialog = "84bccd23-5fde-4cdb-aea4-af64b83d78ab"; + public const string IFileDialogEvents = "973510DB-7D7F-452B-8975-74A85828D354"; + public const string IFileDialogControlEvents = "36116642-D713-4b97-9B83-7484A9D00433"; + public const string IFileDialogCustomize = "e6fdd21a-163f-4975-9c8c-a69f1ba37034"; + public const string IShellItem = "43826D1E-E718-42EE-BC55-A1E261C37BFE"; + public const string IShellItemArray = "B63EA76D-1F85-456F-A19C-48159EFA858B"; + public const string IKnownFolder = "38521333-6A87-46A7-AE10-0F16706816C3"; + public const string IKnownFolderManager = "44BEAAEC-24F4-4E90-B3F0-23D258FBB146"; + public const string IPropertyStore = "886D8EEB-8CF2-4446-8D02-CDBA1DBDCF99"; + public const string IProgressDialog = "EBBC7C04-315E-11d2-B62F-006097DF5BD4"; +} diff --git a/src/ExternalLibraries.FilePickers/Guids/KFIDGuid.cs b/src/ExternalLibraries.FilePickers/Guids/KFIDGuid.cs new file mode 100644 index 0000000..a959a87 --- /dev/null +++ b/src/ExternalLibraries.FilePickers/Guids/KFIDGuid.cs @@ -0,0 +1,9 @@ +namespace ExternalLibraries.Pickers.Guids; + +internal static class KFIDGuid +{ + public const string ComputerFolder = "0AC0837C-BBF8-452A-850D-79D08E667CA7"; + public const string Favorites = "1777F761-68AD-4D8A-87BD-30B759FA33DD"; + public const string Documents = "FDD39AD0-238F-46AF-ADB4-6C85480369C7"; + public const string Profile = "5E6C858F-0E22-4760-9AFE-EA3317B67173"; +} diff --git a/src/ExternalLibraries.FilePickers/Interfaces/FileOpenDialog.cs b/src/ExternalLibraries.FilePickers/Interfaces/FileOpenDialog.cs new file mode 100644 index 0000000..2284c73 --- /dev/null +++ b/src/ExternalLibraries.FilePickers/Interfaces/FileOpenDialog.cs @@ -0,0 +1,13 @@ +using System.Runtime.InteropServices; +using ExternalLibraries.Pickers.Classes; +using ExternalLibraries.Pickers.Guids; + +namespace ExternalLibraries.Pickers.Interfaces; + +// --------------------------------------------------------- +// Coclass interfaces - designed to "look like" the object +// in the API, so that the 'new' operator can be used in a +// straightforward way. Behind the scenes, the C# compiler +// morphs all 'new CoClass()' calls to 'new CoClassWrapper()' +[ComImport, Guid(IIDGuid.IFileOpenDialog), CoClass(typeof(FileOpenDialogRCW))] +internal interface FileOpenDialog : IFileOpenDialog { } diff --git a/src/ExternalLibraries.FilePickers/Interfaces/FileSaveDialog.cs b/src/ExternalLibraries.FilePickers/Interfaces/FileSaveDialog.cs new file mode 100644 index 0000000..1f8240d --- /dev/null +++ b/src/ExternalLibraries.FilePickers/Interfaces/FileSaveDialog.cs @@ -0,0 +1,13 @@ +using System.Runtime.InteropServices; +using ExternalLibraries.Pickers.Classes; +using ExternalLibraries.Pickers.Guids; + +namespace ExternalLibraries.Pickers.Interfaces; + +// --------------------------------------------------------- +// Coclass interfaces - designed to "look like" the object +// in the API, so that the 'new' operator can be used in a +// straightforward way. Behind the scenes, the C# compiler +// morphs all 'new CoClass()' calls to 'new CoClassWrapper()' +[ComImport, Guid(IIDGuid.IFileSaveDialog), CoClass(typeof(FileSaveDialogRCW))] +internal interface FileSaveDialog : IFileSaveDialog { } diff --git a/src/ExternalLibraries.FilePickers/Interfaces/IFileDialog.cs b/src/ExternalLibraries.FilePickers/Interfaces/IFileDialog.cs new file mode 100644 index 0000000..23a49dd --- /dev/null +++ b/src/ExternalLibraries.FilePickers/Interfaces/IFileDialog.cs @@ -0,0 +1,97 @@ +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using ExternalLibraries.Pickers.Enums; +using ExternalLibraries.Pickers.Guids; +using ExternalLibraries.Pickers.Structures; + +namespace ExternalLibraries.Pickers.Interfaces; + +[ComImport(), Guid(IIDGuid.IFileDialog), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] +internal interface IFileDialog : IModalWindow +{ + // Defined on IModalWindow - repeated here due to requirements of COM interop layer + // -------------------------------------------------------------------------------- + [ + MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), + PreserveSig + ] + new int Show([In] IntPtr parent); + + // IFileDialog-Specific interface members + // -------------------------------------------------------------------------------- + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void SetFileTypes( + [In] uint cFileTypes, + [In, MarshalAs(UnmanagedType.LPArray)] COMDLG_FILTERSPEC[] rgFilterSpec + ); + + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void SetFileTypeIndex([In] uint iFileType); + + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void GetFileTypeIndex(out uint piFileType); + + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void Advise( + [In, MarshalAs(UnmanagedType.Interface)] IFileDialogEvents pfde, + out uint pdwCookie + ); + + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void Unadvise([In] uint dwCookie); + + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void SetOptions([In] FOS fos); + + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void GetOptions(out FOS pfos); + + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void SetDefaultFolder([In, MarshalAs(UnmanagedType.Interface)] IShellItem psi); + + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void SetFolder([In, MarshalAs(UnmanagedType.Interface)] IShellItem psi); + + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void GetFolder([MarshalAs(UnmanagedType.Interface)] out IShellItem ppsi); + + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void GetCurrentSelection([MarshalAs(UnmanagedType.Interface)] out IShellItem ppsi); + + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void SetFileName([In, MarshalAs(UnmanagedType.LPWStr)] string pszName); + + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void GetFileName([MarshalAs(UnmanagedType.LPWStr)] out string pszName); + + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void SetTitle([In, MarshalAs(UnmanagedType.LPWStr)] string pszTitle); + + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void SetOkButtonLabel([In, MarshalAs(UnmanagedType.LPWStr)] string pszText); + + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void SetFileNameLabel([In, MarshalAs(UnmanagedType.LPWStr)] string pszLabel); + + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void GetResult([MarshalAs(UnmanagedType.Interface)] out IShellItem ppsi); + + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void AddPlace([In, MarshalAs(UnmanagedType.Interface)] IShellItem psi, FDAP fdap); + + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void SetDefaultExtension([In, MarshalAs(UnmanagedType.LPWStr)] string pszDefaultExtension); + + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void Close([MarshalAs(UnmanagedType.Error)] int hr); + + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void SetClientGuid([In] ref Guid guid); + + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void ClearClientData(); + + // Not supported: IShellItemFilter is not defined, converting to IntPtr + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void SetFilter([MarshalAs(UnmanagedType.Interface)] IntPtr pFilter); +} diff --git a/src/ExternalLibraries.FilePickers/Interfaces/IFileDialogEvents.cs b/src/ExternalLibraries.FilePickers/Interfaces/IFileDialogEvents.cs new file mode 100644 index 0000000..f1eedde --- /dev/null +++ b/src/ExternalLibraries.FilePickers/Interfaces/IFileDialogEvents.cs @@ -0,0 +1,52 @@ +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using ExternalLibraries.Pickers.Enums; +using ExternalLibraries.Pickers.Guids; + +namespace ExternalLibraries.Pickers.Interfaces; + +[ComImport, Guid(IIDGuid.IFileDialogEvents), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] +internal interface IFileDialogEvents +{ + // NOTE: some of these callbacks are cancelable - returning S_FALSE means that + // the dialog should not proceed (e.g. with closing, changing folder); to + // support this, we need to use the PreserveSig attribute to enable us to return + // the proper HRESULT + [ + MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), + PreserveSig + ] + HRESULT OnFileOk([In, MarshalAs(UnmanagedType.Interface)] IFileDialog pfd); + + [ + MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), + PreserveSig + ] + HRESULT OnFolderChanging( + [In, MarshalAs(UnmanagedType.Interface)] IFileDialog pfd, + [In, MarshalAs(UnmanagedType.Interface)] IShellItem psiFolder + ); + + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void OnFolderChange([In, MarshalAs(UnmanagedType.Interface)] IFileDialog pfd); + + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void OnSelectionChange([In, MarshalAs(UnmanagedType.Interface)] IFileDialog pfd); + + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void OnShareViolation( + [In, MarshalAs(UnmanagedType.Interface)] IFileDialog pfd, + [In, MarshalAs(UnmanagedType.Interface)] IShellItem psi, + out FDE_SHAREVIOLATION_RESPONSE pResponse + ); + + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void OnTypeChange([In, MarshalAs(UnmanagedType.Interface)] IFileDialog pfd); + + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void OnOverwrite( + [In, MarshalAs(UnmanagedType.Interface)] IFileDialog pfd, + [In, MarshalAs(UnmanagedType.Interface)] IShellItem psi, + out FDE_OVERWRITE_RESPONSE pResponse + ); +} diff --git a/src/ExternalLibraries.FilePickers/Interfaces/IFileOpenDialog.cs b/src/ExternalLibraries.FilePickers/Interfaces/IFileOpenDialog.cs new file mode 100644 index 0000000..1d6a9a0 --- /dev/null +++ b/src/ExternalLibraries.FilePickers/Interfaces/IFileOpenDialog.cs @@ -0,0 +1,28 @@ +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using ExternalLibraries.Pickers.Guids; +using ExternalLibraries.Pickers.Structures; + +namespace ExternalLibraries.Pickers.Interfaces; + +[ComImport(), Guid(IIDGuid.IFileOpenDialog), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] +internal interface IFileOpenDialog : IFileDialog +{ + // Defined on IFileDialog - repeated here due to requirements of COM interop layer + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void SetFileTypes([In] uint cFileTypes, [In] ref COMDLG_FILTERSPEC rgFilterSpec); + + // Defined by IFileOpenDialog + // --------------------------------------------------------------------------------- + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void GetResults([MarshalAs(UnmanagedType.Interface)] out IShellItemArray ppenum); + + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void GetSelectedItems([MarshalAs(UnmanagedType.Interface)] out IShellItemArray ppsai); +} + +[ComImport(), Guid(IIDGuid.IFileSaveDialog), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] +internal interface IFileSaveDialog : IFileDialog +{ + // Marker interface for COM interop with IFileSaveDialog. +} diff --git a/src/ExternalLibraries.FilePickers/Interfaces/IModalWindow.cs b/src/ExternalLibraries.FilePickers/Interfaces/IModalWindow.cs new file mode 100644 index 0000000..edc345f --- /dev/null +++ b/src/ExternalLibraries.FilePickers/Interfaces/IModalWindow.cs @@ -0,0 +1,15 @@ +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using ExternalLibraries.Pickers.Guids; + +namespace ExternalLibraries.Pickers.Interfaces; + +[ComImport(), Guid(IIDGuid.IModalWindow), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] +internal interface IModalWindow +{ + [ + MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), + PreserveSig + ] + int Show([In] IntPtr parent); +} diff --git a/src/ExternalLibraries.FilePickers/Interfaces/IShellItem.cs b/src/ExternalLibraries.FilePickers/Interfaces/IShellItem.cs new file mode 100644 index 0000000..cd141e3 --- /dev/null +++ b/src/ExternalLibraries.FilePickers/Interfaces/IShellItem.cs @@ -0,0 +1,38 @@ +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using ExternalLibraries.Pickers.Enums; +using ExternalLibraries.Pickers.Guids; + +namespace ExternalLibraries.Pickers.Interfaces; + +[ComImport, Guid(IIDGuid.IShellItem), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] +internal interface IShellItem +{ + // Not supported: IBindCtx + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void BindToHandler( + [In, MarshalAs(UnmanagedType.Interface)] IntPtr pbc, + [In] ref Guid bhid, + [In] ref Guid riid, + out IntPtr ppv + ); + + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void GetParent([MarshalAs(UnmanagedType.Interface)] out IShellItem ppsi); + + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void GetDisplayName( + [In] SIGDN sigdnName, + [MarshalAs(UnmanagedType.LPWStr)] out string ppszName + ); + + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void GetAttributes([In] uint sfgaoMask, out uint psfgaoAttribs); + + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void Compare( + [In, MarshalAs(UnmanagedType.Interface)] IShellItem psi, + [In] uint hint, + out int piOrder + ); +} diff --git a/src/ExternalLibraries.FilePickers/Interfaces/IShellItemArray.cs b/src/ExternalLibraries.FilePickers/Interfaces/IShellItemArray.cs new file mode 100644 index 0000000..603ecf5 --- /dev/null +++ b/src/ExternalLibraries.FilePickers/Interfaces/IShellItemArray.cs @@ -0,0 +1,47 @@ +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using ExternalLibraries.Pickers.Enums; +using ExternalLibraries.Pickers.Guids; +using ExternalLibraries.Pickers.Structures; + +namespace ExternalLibraries.Pickers.Interfaces; + +[ComImport, Guid(IIDGuid.IShellItemArray), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] +internal interface IShellItemArray +{ + // Not supported: IBindCtx + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void BindToHandler( + [In, MarshalAs(UnmanagedType.Interface)] IntPtr pbc, + [In] ref Guid rbhid, + [In] ref Guid riid, + out IntPtr ppvOut + ); + + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void GetPropertyStore([In] int Flags, [In] ref Guid riid, out IntPtr ppv); + + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void GetPropertyDescriptionList( + [In] ref PROPERTYKEY keyType, + [In] ref Guid riid, + out IntPtr ppv + ); + + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void GetAttributes( + [In] SIATTRIBFLAGS dwAttribFlags, + [In] uint sfgaoMask, + out uint psfgaoAttribs + ); + + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void GetCount(out uint pdwNumItems); + + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void GetItemAt([In] uint dwIndex, [MarshalAs(UnmanagedType.Interface)] out IShellItem ppsi); + + // Not supported: IEnumShellItems (will use GetCount and GetItemAt instead) + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void EnumItems([MarshalAs(UnmanagedType.Interface)] out IntPtr ppenumShellItems); +} diff --git a/src/ExternalLibraries.FilePickers/Structures/COMDLG_FILTERSPEC.cs b/src/ExternalLibraries.FilePickers/Structures/COMDLG_FILTERSPEC.cs new file mode 100644 index 0000000..1807ba6 --- /dev/null +++ b/src/ExternalLibraries.FilePickers/Structures/COMDLG_FILTERSPEC.cs @@ -0,0 +1,25 @@ +using System.Runtime.InteropServices; + +namespace ExternalLibraries.Pickers.Structures; + +[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto, Pack = 4)] +internal struct COMDLG_FILTERSPEC +{ + internal COMDLG_FILTERSPEC(string spec) + { + pszName = spec; + pszSpec = spec; + } + + internal COMDLG_FILTERSPEC(string name, string spec) + { + pszName = name; + pszSpec = spec; + } + + [MarshalAs(UnmanagedType.LPWStr)] + public string pszName; + + [MarshalAs(UnmanagedType.LPWStr)] + public string pszSpec; +} diff --git a/src/ExternalLibraries.FilePickers/Structures/PROPERTYKEY.cs b/src/ExternalLibraries.FilePickers/Structures/PROPERTYKEY.cs new file mode 100644 index 0000000..3729e28 --- /dev/null +++ b/src/ExternalLibraries.FilePickers/Structures/PROPERTYKEY.cs @@ -0,0 +1,10 @@ +using System.Runtime.InteropServices; + +namespace ExternalLibraries.Pickers.Structures; + +[StructLayout(LayoutKind.Sequential, Pack = 4)] +internal struct PROPERTYKEY +{ + public Guid fmtid; + public uint pid; +} diff --git a/src/Languages/Data/LanguagesReference.json b/src/Languages/Data/LanguagesReference.json new file mode 100644 index 0000000..df59caf --- /dev/null +++ b/src/Languages/Data/LanguagesReference.json @@ -0,0 +1,62 @@ +{ + "default": "System language", + "af": "Afrikaans - Afrikaans", + "ar": "Arabic - عربي‎", + "be": "Belarusian - беларуская", + "bg": "Bulgarian - български", + "bn": "Bangla - বাংলা", + "ca": "Catalan - Català", + "cs": "Czech - Čeština", + "da": "Danish - Dansk", + "de": "German - Deutsch", + "el": "Greek - Ελληνικά", + "et": "Estonian - Eesti", + "en": "English - English", + "eo": "Esperanto - Esperanto", + "es": "Spanish - Castellano", + "es-MX": "Spanish (Mexico)", + "fa": "Persian - فارسی‎", + "fi": "Finnish - Suomi", + "fil": "Filipino - Filipino", + "fr": "French - Français", + "gl": "Galician - Galego", + "gu": "Gujarati - ગુજરાતી", + "hi": "Hindi - हिंदी", + "hr": "Croatian - Hrvatski", + "he": "Hebrew - עִבְרִית‎", + "hu": "Hungarian - Magyar", + "it": "Italian - Italiano", + "id": "Indonesian - Bahasa Indonesia", + "ja": "Japanese - 日本語", + "ka": "Georgian - ქართული", + "kn": "Kannada - ಕನ್ನಡ", + "ko": "Korean - 한국어", + "ku": "Kurdish - کوردی", + "lt": "Lithuanian - Lietuvių", + "mk": "Macedonian - Македонски", + "mr": "Marathi - मराठी", + "nb": "Norwegian (bokmål)", + "nn": "Norwegian (nynorsk)", + "nl": "Dutch - Nederlands", + "pl": "Polish - Polski", + "pt_BR": "Portuguese (Brazil)", + "pt_PT": "Portuguese (Portugal)", + "ro": "Romanian - Română", + "ru": "Russian - Русский", + "sa": "Sanskrit - संस्कृत भाषा", + "sk": "Slovak - Slovenčina", + "sr": "Serbian - Srpski", + "sq": "Albanian - Shqip", + "si": "Sinhala - සිංහල", + "sl": "Slovene - Slovenščina", + "sv": "Swedish - Svenska", + "ta": "Tamil - தமிழ்", + "tl": "Tagalog - Tagalog", + "th": "Thai - ภาษาไทย", + "tr": "Turkish - Türkçe", + "uk": "Ukrainian - Українська", + "ur": "Urdu - اردو", + "vi": "Vietnamese - Tiếng Việt", + "zh_CN": "Simplified Chinese (China)", + "zh_TW": "Traditional Chinese (Taiwan)" +} \ No newline at end of file diff --git a/src/Languages/Data/TranslatedPercentages.json b/src/Languages/Data/TranslatedPercentages.json new file mode 100644 index 0000000..7101fa3 --- /dev/null +++ b/src/Languages/Data/TranslatedPercentages.json @@ -0,0 +1,61 @@ +{ + "af": "100%", + "ar": "100%", + "be": "100%", + "bg": "100%", + "bn": "100%", + "da": "100%", + "el": "100%", + "eo": "100%", + "es": "100%", + "es-MX": "100%", + "et": "100%", + "fa": "100%", + "fil": "100%", + "gl": "100%", + "gu": "100%", + "he": "100%", + "hi": "100%", + "hr": "100%", + "hu": "100%", + "id": "100%", + "ja": "100%", + "ka": "100%", + "kn": "100%", + "ko": "100%", + "ku": "100%", + "lt": "100%", + "mk": "100%", + "mr": "100%", + "nb": "100%", + "nn": "100%", + "pt_PT": "100%", + "ru": "100%", + "sa": "100%", + "si": "100%", + "sk": "100%", + "sl": "100%", + "sr": "100%", + "ta": "100%", + "tl": "100%", + "th": "100%", + "tr": "100%", + "uk": "100%", + "ur": "100%", + "ca": "100%", + "cs": "100%", + "de": "100%", + "fi": "100%", + "fr": "100%", + "it": "100%", + "nl": "100%", + "pl": "100%", + "pt_BR": "100%", + "ro": "100%", + "sq": "100%", + "sv": "100%", + "vi": "100%", + "zh_CN": "100%", + "zh_TW": "100%", + "en": "100%" +} diff --git a/src/Languages/Data/Translators.json b/src/Languages/Data/Translators.json new file mode 100644 index 0000000..6fe1ffa --- /dev/null +++ b/src/Languages/Data/Translators.json @@ -0,0 +1,1015 @@ +{ + "af": [ + { + "name": "Hendrik Bezuidenhout", + "link": "" + } + ], + "ar": [ + { + "name": "Abdu11ahAS", + "link": "https://github.com/Abdu11ahAS" + }, + { + "name": "Abdullah-Dev115", + "link": "https://github.com/Abdullah-Dev115" + }, + { + "name": "AbdullahAlousi", + "link": "https://github.com/AbdullahAlousi" + }, + { + "name": "bassuny3003", + "link": "https://github.com/bassuny3003" + }, + { + "name": "DaRandomCube", + "link": "https://github.com/DaRandomCube" + }, + { + "name": "FancyCookin", + "link": "https://github.com/FancyCookin" + }, + { + "name": "IFrxo", + "link": "https://github.com/IFrxo" + }, + { + "name": "mo9a7i", + "link": "https://github.com/mo9a7i" + } + ], + "be": [ + { + "name": "bthos", + "link": "https://github.com/bthos" + } + ], + "bg": [ + { + "name": "Nikolay Naydenov", + "link": "" + }, + { + "name": "Vasil Kolev", + "link": "" + } + ], + "bn": [ + { + "name": "fluentmoheshwar", + "link": "https://github.com/fluentmoheshwar" + }, + { + "name": "itz-rj-here", + "link": "https://github.com/itz-rj-here" + }, + { + "name": "Mushfiq Iqbal Rayon", + "link": "" + }, + { + "name": "Nilavra Bhattacharya", + "link": "" + }, + { + "name": "samiulislamsharan", + "link": "https://github.com/samiulislamsharan" + } + ], + "ca": [ + { + "name": "marticliment", + "link": "https://github.com/marticliment" + } + ], + "cs": [ + { + "name": "mlisko", + "link": "https://github.com/mlisko" + }, + { + "name": "panther7", + "link": "https://github.com/panther7" + }, + { + "name": "xtorlukas", + "link": "https://github.com/xtorlukas" + } + ], + "da": [ + { + "name": "AAUCrisp", + "link": "https://github.com/AAUCrisp" + }, + { + "name": "bstordrup", + "link": "https://github.com/bstordrup" + }, + { + "name": "mikkolukas", + "link": "https://github.com/mikkolukas" + }, + { + "name": "siewers", + "link": "https://github.com/siewers" + }, + { + "name": "yrjarv", + "link": "https://github.com/yrjarv" + } + ], + "de": [ + { + "name": "1270o1", + "link": "https://github.com/1270o1" + }, + { + "name": "AbsolutLeon", + "link": "https://github.com/AbsolutLeon" + }, + { + "name": "alxhu-dev", + "link": "https://github.com/alxhu-dev" + }, + { + "name": "Araxxas", + "link": "https://github.com/Araxxas" + }, + { + "name": "arnowelzel", + "link": "https://github.com/arnowelzel" + }, + { + "name": "CanePlayz", + "link": "https://github.com/CanePlayz" + }, + { + "name": "Datacra5H", + "link": "https://github.com/Datacra5H" + }, + { + "name": "ebnater", + "link": "https://github.com/ebnater" + }, + { + "name": "lucadsign", + "link": "https://github.com/lucadsign" + }, + { + "name": "martinwilco", + "link": "https://github.com/martinwilco" + }, + { + "name": "michaelmairegger", + "link": "https://github.com/michaelmairegger" + }, + { + "name": "Seeloewen", + "link": "https://github.com/Seeloewen" + }, + { + "name": "TheScarfix", + "link": "https://github.com/TheScarfix" + }, + { + "name": "tkohlmeier", + "link": "https://github.com/tkohlmeier" + }, + { + "name": "VfBFan", + "link": "https://github.com/VfBFan" + }, + { + "name": "Xeraox3335", + "link": "https://github.com/Xeraox3335" + }, + { + "name": "yrjarv", + "link": "https://github.com/yrjarv" + } + ], + "el": [ + { + "name": "antwnhsx", + "link": "https://github.com/antwnhsx" + }, + { + "name": "panos78", + "link": "https://github.com/panos78" + }, + { + "name": "seijind", + "link": "https://github.com/seijind" + }, + { + "name": "thunderstrike116", + "link": "https://github.com/thunderstrike116" + }, + { + "name": "wobblerrrgg", + "link": "https://github.com/wobblerrrgg" + } + ], + "en": [ + { + "name": "lucadsign", + "link": "https://github.com/lucadsign" + }, + { + "name": "marticliment", + "link": "https://github.com/marticliment" + }, + { + "name": "ppvnf", + "link": "https://github.com/ppvnf" + } + ], + "es": [ + { + "name": "apazga", + "link": "https://github.com/apazga" + }, + { + "name": "dalbitresb12", + "link": "https://github.com/dalbitresb12" + }, + { + "name": "evaneliasyoung", + "link": "https://github.com/evaneliasyoung" + }, + { + "name": "guplem", + "link": "https://github.com/guplem" + }, + { + "name": "JMoreno97", + "link": "https://github.com/JMoreno97" + }, + { + "name": "marticliment", + "link": "https://github.com/marticliment" + }, + { + "name": "P10Designs", + "link": "https://github.com/P10Designs" + }, + { + "name": "rubnium", + "link": "https://github.com/rubnium" + }, + { + "name": "uKER", + "link": "https://github.com/uKER" + }, + { + "name": "independent-arg", + "link": "https://github.com/independent-arg" + } + ], + "es-MX": [ + { + "name": "apazga", + "link": "https://github.com/apazga" + }, + { + "name": "dalbitresb12", + "link": "https://github.com/dalbitresb12" + }, + { + "name": "evaneliasyoung", + "link": "https://github.com/evaneliasyoung" + }, + { + "name": "guplem", + "link": "https://github.com/guplem" + }, + { + "name": "JMoreno97", + "link": "https://github.com/JMoreno97" + }, + { + "name": "marticliment", + "link": "https://github.com/marticliment" + }, + { + "name": "P10Designs", + "link": "https://github.com/P10Designs" + }, + { + "name": "rubnium", + "link": "https://github.com/rubnium" + }, + { + "name": "uKER", + "link": "https://github.com/uKER" + }, + { + "name": "independent-arg", + "link": "https://github.com/independent-arg" + } + ], + "et": [ + { + "name": "artjom3729", + "link": "https://github.com/artjom3729" + } + ], + "fa": [ + { + "name": "ehinium", + "link": "https://github.com/ehinium" + }, + { + "name": "MobinMardi", + "link": "https://github.com/MobinMardi" + } + ], + "fi": [ + { + "name": "simakuutio", + "link": "https://github.com/simakuutio" + } + ], + "fil": [ + { + "name": "infyProductions", + "link": "https://github.com/infyProductions" + } + ], + "fr": [ + { + "name": "BreatFR", + "link": "" + }, + { + "name": "Entropiness", + "link": "https://github.com/Entropiness" + }, + { + "name": "Evans Costa", + "link": "" + }, + { + "name": "PikPakPik", + "link": "https://github.com/PikPakPik" + }, + { + "name": "Rémi Guerrero", + "link": "" + }, + { + "name": "W1L7dev", + "link": "https://github.com/W1L7dev" + } + ], + "gu": [], + "he": [ + { + "name": "maximunited", + "link": "https://github.com/maximunited" + }, + { + "name": "Oryan Hassidim", + "link": "" + } + ], + "hi": [ + { + "name": "Ashu-r", + "link": "https://github.com/Ashu-r" + }, + { + "name": "atharva_xoxo", + "link": "https://github.com/atharva_xoxo" + }, + { + "name": "satanarious", + "link": "https://github.com/satanarious" + } + ], + "hr": [ + { + "name": "AndrejFeher", + "link": "https://github.com/AndrejFeher" + }, + { + "name": "Ivan Nuić", + "link": "" + }, + { + "name": "Stjepan Treger", + "link": "" + } + ], + "hu": [ + { + "name": "gidano", + "link": "https://github.com/gidano" + } + ], + "id": [ + { + "name": "agrinfauzi", + "link": "https://github.com/agrinfauzi" + }, + { + "name": "arthackrc", + "link": "https://github.com/arthackrc" + }, + { + "name": "joenior", + "link": "https://github.com/joenior" + }, + { + "name": "nrarfn", + "link": "https://github.com/nrarfn" + } + ], + "it": [ + { + "name": "David Senoner", + "link": "" + }, + { + "name": "giacobot", + "link": "https://github.com/giacobot" + }, + { + "name": "maicol07", + "link": "https://github.com/maicol07" + }, + { + "name": "mapi68", + "link": "https://github.com/mapi68" + }, + { + "name": "mrfranza", + "link": "https://github.com/mrfranza" + }, + { + "name": "Rosario Di Mauro", + "link": "" + } + ], + "ja": [ + { + "name": "anmoti", + "link": "https://github.com/anmoti" + }, + { + "name": "BHCrusher1", + "link": "https://github.com/BHCrusher1" + }, + { + "name": "nob-swik", + "link": "https://github.com/nob-swik" + }, + { + "name": "Nobuhiro Shintaku", + "link": "" + }, + { + "name": "sho9029", + "link": "" + }, + { + "name": "tacostea", + "link": "https://github.com/tacostea" + }, + { + "name": "Yuki Takase", + "link": "" + } + ], + "ka": [ + { + "name": "marticliment", + "link": "https://github.com/marticliment" + }, + { + "name": "ppvnf", + "link": "https://github.com/ppvnf" + } + ], + "kn": [ + { + "name": "skanda890", + "link": "https://github.com/skanda890" + } + ], + "ko": [ + { + "name": "VenusGirl", + "link": "https://github.com/VenusGirl" + } + ], + "lt": [ + { + "name": "Džiugas Januševičius", + "link": "" + }, + { + "name": "dziugas1959", + "link": "https://github.com/dziugas1959" + }, + { + "name": "martyn3z", + "link": "https://github.com/martyn3z" + } + ], + "mk": [ + { + "name": "LordDeatHunter", + "link": "" + } + ], + "nb": [ + { + "name": "DandelionSprout", + "link": "https://github.com/DandelionSprout" + }, + { + "name": "mikaelkw", + "link": "https://github.com/mikaelkw" + }, + { + "name": "yrjarv", + "link": "https://github.com/yrjarv" + } + ], + "nl": [ + { + "name": "abbydiode", + "link": "https://github.com/abbydiode" + }, + { + "name": "CateyeNL", + "link": "https://github.com/CateyeNL" + }, + { + "name": "mia-riezebos", + "link": "https://github.com/mia-riezebos" + }, + { + "name": "Stephan-P", + "link": "https://github.com/Stephan-P" + } + ], + "nn": [ + { + "name": "yrjarv", + "link": "https://github.com/yrjarv" + } + ], + "pl": [ + { + "name": "AdiMajsterek", + "link": "https://github.com/AdiMajsterek" + }, + { + "name": "GrzegorzKi", + "link": "https://github.com/GrzegorzKi" + }, + { + "name": "H4qu3r", + "link": "https://github.com/H4qu3r" + }, + { + "name": "ikarmus2001", + "link": "https://github.com/ikarmus2001" + }, + { + "name": "juliazero", + "link": "https://github.com/juliazero" + }, + { + "name": "KamilZielinski", + "link": "https://github.com/KamilZielinski" + }, + { + "name": "kwiateusz", + "link": "https://github.com/kwiateusz" + }, + { + "name": "RegularGvy13", + "link": "https://github.com/RegularGvy13" + }, + { + "name": "szumsky", + "link": "https://github.com/szumsky" + }, + { + "name": "ThePhaseless", + "link": "https://github.com/ThePhaseless" + } + ], + "pt_BR": [ + { + "name": "maisondasilva", + "link": "https://github.com/maisondasilva" + }, + { + "name": "ppvnf", + "link": "https://github.com/ppvnf" + }, + { + "name": "renanalencar", + "link": "https://github.com/renanalencar" + }, + { + "name": "Rodrigo-Matsuura", + "link": "https://github.com/Rodrigo-Matsuura" + }, + { + "name": "thiagojramos", + "link": "https://github.com/thiagojramos" + }, + { + "name": "wanderleihuttel", + "link": "https://github.com/wanderleihuttel" + } + ], + "pt_PT": [ + { + "name": "100Nome", + "link": "https://github.com/100Nome" + }, + { + "name": "NimiGames68", + "link": "https://github.com/NimiGames68" + }, + { + "name": "PoetaGA", + "link": "https://github.com/PoetaGA" + }, + { + "name": "Putocoroa", + "link": "https://github.com/Putocoroa" + }, + { + "name": "Tiago_Ferreira", + "link": "https://github.com/Tiago_Ferreira" + } + ], + "ro": [ + { + "name": "David735453", + "link": "https://github.com/David735453" + }, + { + "name": "lucadsign", + "link": "https://github.com/lucadsign" + }, + { + "name": "SilverGreen93", + "link": "https://github.com/SilverGreen93" + }, + { + "name": "TZACANEL", + "link": "" + } + ], + "ru": [ + { + "name": "Alexander", + "link": "" + }, + { + "name": "bropines", + "link": "https://github.com/bropines" + }, + { + "name": "Denisskas", + "link": "https://github.com/Denisskas" + }, + { + "name": "DvladikD", + "link": "https://github.com/DvladikD" + }, + { + "name": "flatron4eg", + "link": "https://github.com/flatron4eg" + }, + { + "name": "Gleb Saygin", + "link": "" + }, + { + "name": "katrovsky", + "link": "https://github.com/katrovsky" + }, + { + "name": "Sergey", + "link": "" + }, + { + "name": "sklart", + "link": "https://github.com/sklart" + }, + { + "name": "solarscream", + "link": "https://github.com/solarscream" + }, + { + "name": "tapnisu", + "link": "https://github.com/tapnisu" + }, + { + "name": "Vertuhai", + "link": "https://github.com/Vertuhai" + } + ], + "sa": [ + { + "name": "skanda890", + "link": "https://github.com/skanda890" + } + ], + "si": [ + { + "name": "SashikaSandeepa", + "link": "https://github.com/SashikaSandeepa" + }, + { + "name": "Savithu-s3", + "link": "https://github.com/Savithu-s3" + }, + { + "name": "ttheek", + "link": "https://github.com/ttheek" + } + ], + "sk": [ + { + "name": "david-kucera", + "link": "https://github.com/david-kucera" + }, + { + "name": "Luk164", + "link": "https://github.com/Luk164" + } + ], + "sl": [ + { + "name": "rumplin", + "link": "https://github.com/rumplin" + } + ], + "sq": [ + { + "name": "RDN000", + "link": "https://github.com/RDN000" + } + ], + "sr": [ + { + "name": "daVinci13", + "link": "https://github.com/daVinci13" + }, + { + "name": "igorskyflyer", + "link": "https://github.com/igorskyflyer" + }, + { + "name": "momcilovicluka", + "link": "https://github.com/momcilovicluka" + } + ], + "sv": [ + { + "name": "curudel", + "link": "https://github.com/curudel" + }, + { + "name": "Hi-there-how-are-u", + "link": "https://github.com/Hi-there-how-are-u" + }, + { + "name": "kakmonster", + "link": "https://github.com/kakmonster" + }, + { + "name": "umeaboy", + "link": "https://github.com/umeaboy" + } + ], + "ta": [ + { + "name": "nochilli", + "link": "https://github.com/nochilli" + } + ], + "tl": [ + { + "name": "lasersPew", + "link": "" + }, + { + "name": "znarfm", + "link": "https://github.com/znarfm" + } + ], + "th": [ + { + "name": "apaeisara", + "link": "https://github.com/apaeisara" + }, + { + "name": "dulapahv", + "link": "https://github.com/dulapahv" + }, + { + "name": "hanchain", + "link": "https://github.com/hanchain" + }, + { + "name": "rikoprushka", + "link": "https://github.com/rikoprushka" + }, + { + "name": "vestearth", + "link": "https://github.com/vestearth" + } + ], + "tr": [ + { + "name": "ahmetozmtn", + "link": "https://github.com/ahmetozmtn" + }, + { + "name": "anzeralp", + "link": "https://github.com/anzeralp" + }, + { + "name": "BerkeA111", + "link": "https://github.com/BerkeA111" + }, + { + "name": "dogancanyr", + "link": "https://github.com/dogancanyr" + }, + { + "name": "gokberkgs", + "link": "https://github.com/gokberkgs" + } + ], + "uk": [ + { + "name": "Alex Logvin", + "link": "" + }, + { + "name": "Artem Moldovanenko", + "link": "" + }, + { + "name": "Operator404", + "link": "" + }, + { + "name": "Taron-art", + "link": "https://github.com/Taron-art" + }, + { + "name": "Vertuhai", + "link": "https://github.com/Vertuhai" + } + ], + "ur": [ + { + "name": "digitio", + "link": "https://github.com/digitio" + }, + { + "name": "digitpk", + "link": "https://github.com/digitpk" + }, + { + "name": "hamzaharoon1314", + "link": "https://github.com/hamzaharoon1314" + } + ], + "vi": [ + { + "name": "aethervn2309", + "link": "https://github.com/aethervn2309" + }, + { + "name": "legendsjoon", + "link": "https://github.com/legendsjoon" + }, + { + "name": "txavlog", + "link": "https://github.com/txavlog" + }, + { + "name": "vanlongluuly", + "link": "https://github.com/vanlongluuly" + } + ], + "zh_CN": [ + { + "name": "Aaron Liu", + "link": "" + }, + { + "name": "adfnekc", + "link": "https://github.com/adfnekc" + }, + { + "name": "Ardenet", + "link": "https://github.com/Ardenet" + }, + { + "name": "arthurfsy2", + "link": "https://github.com/arthurfsy2" + }, + { + "name": "bai0012", + "link": "https://github.com/bai0012" + }, + { + "name": "BUGP Association", + "link": "" + }, + { + "name": "ciaran", + "link": "" + }, + { + "name": "CnYeSheng", + "link": "" + }, + { + "name": "Cololi", + "link": "" + }, + { + "name": "dongfengweixiao", + "link": "https://github.com/dongfengweixiao" + }, + { + "name": "enKl03B", + "link": "https://github.com/enKl03B" + }, + { + "name": "seanyu0", + "link": "https://github.com/seanyu0" + }, + { + "name": "Sigechaishijie", + "link": "https://github.com/Sigechaishijie" + }, + { + "name": "SpaceTimee", + "link": "https://github.com/SpaceTimee" + }, + { + "name": "xiaopangju", + "link": "https://github.com/xiaopangju" + }, + { + "name": "Yisme", + "link": "" + } + ], + "zh_TW": [ + { + "name": "Aaron Liu", + "link": "" + }, + { + "name": "CnYeSheng", + "link": "https://github.com/CnYeSheng" + }, + { + "name": "Cololi", + "link": "" + }, + { + "name": "enKl03B", + "link": "https://github.com/enKl03B" + }, + { + "name": "Henryliu880922", + "link": "https://github.com/Henryliu880922" + }, + { + "name": "MINAX2U", + "link": "https://github.com/MINAX2U" + }, + { + "name": "StarsShine11904", + "link": "https://github.com/StarsShine11904" + }, + { + "name": "yrctw", + "link": "https://github.com/yrctw" + } + ], + "eo": [], + "gl": [], + "ku": [], + "mr": [] +} diff --git a/src/Languages/lang_af.json b/src/Languages/lang_af.json new file mode 100644 index 0000000..5243dca --- /dev/null +++ b/src/Languages/lang_af.json @@ -0,0 +1,850 @@ +{ + "{0} of {1} operations completed": "{0} van {1} bewerkings voltooi", + "{0} is now {1}": "{0} is nou {1}", + "Enabled": "Geaktiveer", + "Disabled": "Gedeaktiveer", + "Privacy": "Privaatheid", + "Hide my username from the logs": "Versteek my gebruikersnaam in die logboeke", + "Replaces your username with **** in the logs. Restart UniGetUI to also hide it from already-recorded entries.": "Vervang jou gebruikersnaam met **** in die logboeke. Herbegin UniGetUI om dit ook te versteek in reeds-opgetekende inskrywings.", + "Your last update attempt did not complete.": "Jou laaste opdateringspoging is nie voltooi nie.", + "UniGetUI could not confirm whether the update succeeded. Open the log to see what happened.": "UniGetUI kon nie bevestig of die opdatering geslaag het nie. Maak die logboek oop om te sien wat gebeur het.", + "View log": "Bekyk logboek", + "The installer reported success but did not restart UniGetUI.": "Die installeerder het sukses gerapporteer, maar het UniGetUI nie weer begin nie.", + "The installer failed to initialize.": "Die installeerder kon nie inisialiseer nie.", + "Setup was canceled before installation began.": "Opstelling is gekanselleer voordat installasie begin het.", + "A fatal error occurred during the preparation phase.": "'n Fatale fout het tydens die voorbereidingsfase voorgekom.", + "A fatal error occurred during installation.": "'n Fatale fout het tydens installasie voorgekom.", + "Installation was canceled while in progress.": "Installasie is gekanselleer terwyl dit aan die gang was.", + "The installer was terminated by another process.": "Die installeerder is deur 'n ander proses beëindig.", + "The preparation phase determined the installation cannot proceed.": "Die voorbereidingsfase het bepaal dat die installasie nie kan voortgaan nie.", + "The installer could not start. UniGetUI may already be running, or you do not have permission to install.": "Die installeerder kon nie begin nie. UniGetUI loop dalk reeds, of jy het nie toestemming om te installeer nie.", + "Unexpected installer error.": "Onverwagte installeerderfout.", + "We are checking for updates.": "Ons kyk na opdaterings.", + "Please wait": "Wag asseblief", + "Great! You are on the latest version.": "Mooi! Jy het die nuutste weergawe.", + "There are no new UniGetUI versions to be installed": "Daar is geen nuwe UniGetUI weergawes wat geïnstalleer moet word nie", + "UniGetUI version {0} is being downloaded.": "UniGetUI weergawe {0} word afgelaai.", + "This may take a minute or two": "Dit kan 'n minuut of twee neem", + "The installer authenticity could not be verified.": "Die installeerder se egtheid kon nie geverifieer word nie.", + "The update process has been aborted.": "Die opdaterings proses is gestaak.", + "Auto-update is not yet available on this platform.": "Outomatiese opdatering is nog nie op hierdie platform beskikbaar nie.", + "Please update UniGetUI manually.": "Dateer UniGetUI asseblief handmatig op.", + "An error occurred when checking for updates: ": "'n Fout het voorgekom toe daar vir opdaterings gekyk is:", + "The updater could not be launched.": "Die opdateringsprogram kon nie begin word nie.", + "The operating system did not start the installer process.": "Die bedryfstelsel het nie die installeerderproses begin nie.", + "UniGetUI is being updated...": "UniGetUI word opgedateer...", + "Update installed.": "Opdatering geïnstalleer.", + "UniGetUI was updated successfully, but this running copy was not replaced. This usually means you are running a development build. Close this copy and start the newly-installed version to finish.": "UniGetUI is suksesvol opgedateer, maar hierdie lopende kopie is nie vervang nie. Dit beteken gewoonlik dat jy 'n ontwikkelingsbou gebruik. Sluit hierdie kopie en begin die nuut geïnstalleerde weergawe om te voltooi.", + "The update could not be applied.": "Die opdatering kon nie toegepas word nie.", + "Installer exit code {0}: {1}": "Installeerder-afsluitkode {0}: {1}", + "Update cancelled.": "Opdatering gekanselleer.", + "Authentication was cancelled.": "Stawing is gekanselleer.", + "Installer exit code {0}": "Installeerder-afsluitkode {0}", + "Operation in progress": "Opdrag in vordering", + "Please wait...": "Wag asseblief...", + "Success!": "Sukses!", + "Failed": "Misluk", + "An error occurred while processing this package": "'n Fout het voorgekom tydens die verwerking van hierdie pakket", + "Installer": "Installeerder", + "Executable": "Uitvoerbare lêer", + "MSI": "MSI", + "Compressed file": "Saamgeperste lêer", + "MSIX": "MSIX", + "WinGet was repaired successfully": "WinGet is suksesvol herstel", + "It is recommended to restart UniGetUI after WinGet has been repaired": "Dit word aanbeveel om UniGetUI weer te begin nadat Winget herstel is", + "WinGet could not be repaired": "WinGet kon nie herstel word nie", + "An unexpected issue occurred while attempting to repair WinGet. Please try again later": "'n Onverwagte probleem het voorgekom terwyl daar probeer is om Winget te herstel. Probeer asseblief later weer", + "Log in to enable cloud backup": "Meld aan om wolkrugsteun te aktiveer", + "Backup Failed": "Rugsteun het misluk", + "Downloading backup...": "Laai rugsteun af...", + "An update was found!": "'n Opdatering is gevind!", + "{0} can be updated to version {1}": "{0} kan word opgedateer na weergawe {1}", + "Updates found!": "Opdaterings gevind!", + "{0} packages can be updated": "{0} pakkette kan word opgedateer ", + "{0} is being updated to version {1}": "{0} word opgedateer na weergawe {1}", + "{0} packages are being updated": "{0} pakkette is opgedateer", + "You have currently version {0} installed": "Jy het tans weergawe {0} geïnstalleer", + "Desktop shortcut created": "Werkskerm kortpad geskep", + "UniGetUI has detected a new desktop shortcut that can be deleted automatically.": "UniGetUI het 'n nuwe werkskerm kortpad opgespoor wat outomaties uitgevee kan word.", + "{0} desktop shortcuts created": "{0} werkskerm kortpaaie geskep ", + "UniGetUI has detected {0} new desktop shortcuts that can be deleted automatically.": "UniGetUI het bespeur {0} nuwe werkskerm kortpaaie wat outomaties uitgevee kan word.", + "Attention required": "Aandag vereis ", + "Restart required": "Herbegin benodig", + "1 update is available": "1 opdatering is beskikbaar", + "{0} updates are available": "{0} Opdaterings is beskikbaar", + "Everything is up to date": "Alles is op datum", + "Discover Packages": "Vind pakkette", + "Available Updates": "Beskikbare Opdaterings", + "Installed Packages": "Geïnstalleerde pakkette", + "UniGetUI Version {0} by Devolutions": "UniGetUI-weergawe {0} deur Devolutions", + "Show UniGetUI": "Wys UniGetUI", + "Quit": "Verlaat", + "Are you sure?": "Is jy seker?", + "Do you really want to uninstall {0}?": "Wil jy regtig {0} deïnstalleer?", + "Do you really want to uninstall the following {0} packages?": "Wil u die volgende {0} pakkette regtig deïnstalleer?", + "No": "Nee", + "Yes": "Ja", + "Partial": "Gedeeltelik", + "View on UniGetUI": "Kyk op UniGetUI", + "Update": "Opdatering", + "Open UniGetUI": "Maak UniGetUI oop", + "Update all": "Dateer almal op", + "Update now": "Bring op datum nou", + "Installer host changed since the installed version.\n": "Installeerdergasheer het sedert die geïnstalleerde weergawe verander.\n", + "This package is on the queue": "Hierdie pakket is op tou", + "installing": "Installeer", + "updating": "opdatering", + "uninstalling": "deïnstalleering", + "installed": "geïnstalleer", + "Retry": "Herprobeer", + "Install": "Installeer", + "Uninstall": "Deïnstalleer", + "Open": "Oopmaak", + "Operation profile:": "Bewerkingsprofiel:", + "Follow the default options when installing, upgrading or uninstalling this package": "Volg die verstekopsies wanneer hierdie pakket geïnstalleer, opgegradeer of gedeïnstalleer word", + "The following settings will be applied each time this package is installed, updated or removed.": "Die volgende instellings word toegepas elke keer as hierdie pakket geïnstalleer, opgedateer of verwyder word.", + "Version to install:": "Weergawe om te installeer:", + "Architecture to install:": "Argitektuur om te installeer:", + "Installation scope:": "Installasie omvang:", + "Install location:": "Installeer plek", + "Select": "Selekteer", + "Reset": "Herstel ", + "Custom install arguments:": "Pasgemaakte installeer-argumente:", + "Custom update arguments:": "Pasgemaakte opdateer-argumente:", + "Custom uninstall arguments:": "Pasgemaakte deïnstalleer-argumente:", + "Pre-install command:": "Voor-installeer-opdrag:", + "Post-install command:": "Na-installeer-opdrag:", + "Abort install if pre-install command fails": "Staak installasie as die voor-installeer-opdrag misluk", + "Pre-update command:": "Voor-opdateer-opdrag:", + "Post-update command:": "Na-opdateer-opdrag:", + "Abort update if pre-update command fails": "Staak opdatering as die voor-opdateer-opdrag misluk", + "Pre-uninstall command:": "Voor-deïnstalleer-opdrag:", + "Post-uninstall command:": "Na-deïnstalleer-opdrag:", + "Abort uninstall if pre-uninstall command fails": "Staak deïnstallering as die voor-deïnstalleer-opdrag misluk", + "Command-line to run:": "Opdrag-lyn om te loop:", + "Save and close": "Stoor en sluit", + "General": "Algemeen", + "Architecture & Location": "Argitektuur en ligging", + "Command-line": "Opdragreël", + "Close apps": "Sluit toepassings", + "Pre/Post install": "Voor-/na-installasie", + "Select the processes that should be closed before this package is installed, updated or uninstalled.": "Kies die prosesse wat gesluit moet word voordat hierdie pakket geïnstalleer, opgedateer of gedeïnstalleer word.", + "Write here the process names here, separated by commas (,)": "Skryf hier die prosesname, geskei deur kommas (,)", + "Try to kill the processes that refuse to close when requested to": "Probeer die prosesse beëindig wat weier om te sluit wanneer dit versoek word", + "Run as admin": "Laat loop as admin", + "Interactive installation": "Interaktiewe installasie", + "Skip hash check": "Slaan huts kontrole oor", + "Uninstall previous versions when updated": "Deïnstalleer vorige weergawes wanneer opgedateer word", + "Skip minor updates for this package": "Slaan geringe opdaterings oor vir hierdie pakket", + "Automatically update this package": "Dateer hierdie pakket outomaties op", + "{0} installation options": "{0} installasie opsies ", + "Latest": "Nuutste", + "PreRelease": "Voorvrystelling", + "Default": "Standaard", + "Manage ignored updates": "Bestuur geïgnoreerde opdaterings", + "The packages listed here won't be taken in account when checking for updates. Double-click them or click the button on their right to stop ignoring their updates.": "Die pakkette wat hier gelys word, sal nie in ag geneem word wanneer daar vir opdaterings gekyk word nie. Dubbelklik op hulle of klik op die knoppie aan hul regterkant om op te hou om hul opdaterings te ignoreer.", + "Reset list": "Herstel lys", + "Do you really want to reset the ignored updates list? This action cannot be reverted": "Wil jy regtig die lys van geïgnoreerde opdaterings terugstel? Hierdie aksie kan nie ongedaan gemaak word nie", + "No ignored updates": "Geen geïgnoreerde opdaterings nie", + "Package Name": "Pakket Naam", + "Package ID": "Pakket ID", + "Ignored version": "Geïgnoreerde weergawe", + "New version": "Nuwe weergawe", + "Source": "Bron", + "All versions": "Alle weergawes", + "Unknown": "Onbekend", + "Up to date": "Op datum", + "Package {name} from {manager}": "Pakket {name} van {manager}", + "Remove {0} from ignored updates": "Verwyder {0} van geïgnoreerde opdaterings", + "Cancel": "Kanselleer", + "Administrator privileges": "Administrateurs voorregte", + "This operation is running with administrator privileges.": "Hierdie werking word uitgevoer met administrateur regte.", + "Interactive operation": "Interaktiewe werking", + "This operation is running interactively.": "Hierdie operasie loop interaktief.", + "You will likely need to interact with the installer.": "Jy sal waarskynlik met die installeerder moet kommunikeer.", + "Integrity checks skipped": "Integriteits kontroles oorgeslaan", + "Integrity checks will not be performed during this operation.": "Integriteitskontroles sal nie tydens hierdie bewerking uitgevoer word nie.", + "Proceed at your own risk.": "Gaan voort op eie risiko.", + "Close": "Sluit", + "Loading...": "Laai...", + "Installer SHA256": "Installeerder SHA256", + "Homepage": "Tuisblad", + "Author": "Outeur", + "Publisher": "Uitgewer", + "License": "Lisensie", + "Manifest": "Manifesteer", + "Installer Type": "Installeerder Tipe", + "Size": "Grootte", + "Installer URL": "Installeerder URL", + "Last updated:": "Laas opgedateer:", + "Release notes URL": "Vrystelling notas", + "Package details": "Pakket besonderhede", + "Dependencies:": "Afhanklikhede:", + "Release notes": "Vrystelling notas", + "Screenshots": "Skermkiekies", + "This package has no screenshots or is missing the icon? Contribute to UniGetUI by adding the missing icons and screenshots to our open, public database.": "Het hierdie pakket geen skermkiekies nie of ontbreek die ikoon? Dra by tot UniGetUI deur die ontbrekende ikone en skermkiekies by ons oop, openbare databasis te voeg.", + "Version": "Weergawe", + "Install as administrator": "Installeer as administrateur", + "Update to version {0}": "Dateer op na weergawe {0}", + "Installed Version": "Geïnstalleerde Weergawe", + "Update as administrator": "Opdatering as administrateur", + "Interactive update": "Interaktiewe opdatering", + "Uninstall as administrator": "Deïnstalleer as administrateur", + "Interactive uninstall": "Interaktiewe deïnstalleer", + "Uninstall and remove data": "Deïnstalleer en verwyder weg data", + "Not available": "Nie beskikbaar nie", + "Installer SHA512": "Installeerder SHA512", + "Unknown size": "Onbekende grootte", + "No dependencies specified": "Geen afhanklikhede gespesifiseer nie", + "mandatory": "verpligtend", + "optional": "opsioneel", + "UniGetUI {0} is ready to be installed.": "UniGetUI {0} is gereed om geïnstalleer te word.", + "The update process will start after closing UniGetUI": "Die opdatering sproses sal begin nadat UniGetUI toegemaak is", + "UniGetUI has been ran as administrator, which is not recommended. When running UniGetUI as administrator, EVERY operation launched from UniGetUI will have administrator privileges. You can still use the program, but we highly recommend not running UniGetUI with administrator privileges.": "UniGetUI is as administrateur uitgevoer, wat nie aanbeveel word nie. Wanneer UniGetUI as administrateur uitgevoer word, sal ELKE bewerking wat vanuit UniGetUI begin word administrateurregte hê. Jy kan steeds die program gebruik, maar ons beveel sterk aan dat jy nie UniGetUI met administrateurregte uitvoer nie.", + "Share anonymous usage data": "Deel anonieme gebruiks data", + "UniGetUI collects anonymous usage data in order to improve the user experience.": "UniGetUI versamel anonieme gebruiks data om die gebruikers ervaring te verbeter.", + "Accept": "Aanvaar", + "Software Updates": "Sagteware Opdaterings", + "Package Bundles": "Pakket Bondels", + "Settings": "Instellings", + "Package Managers": "Pakketbestuurders", + "UniGetUI Log": "UniGetUI-logboek", + "Package Manager logs": "Pakket Bestuurder logs", + "Operation history": "Opdrag Geskiedenis", + "Help": "Hulp", + "UniGetUI": "UniGetUI", + "You have installed UniGetUI Version {0}": "Jy het UniGetUI weergawe geïnstalleer {0}", + "Disclaimer": "Vrywaring", + "UniGetUI is developed by Devolutions and is not affiliated with any of the compatible package managers.": "UniGetUI word deur Devolutions ontwikkel en is nie geaffilieer met enige van die versoenbare pakketbestuurders nie.", + "UniGetUI wouldn't have been possible without the help of the contributors. Thank you all 🥳": "UniGetUI sou nie moontlik gewees het sonder die hulp van die bydraers nie. Dankie almal 🥳", + "UniGetUI uses the following libraries. Without them, UniGetUI wouldn't have been possible.": "UniGetUI gebruik die volgende biblioteke. Sonder hulle sou UniGetUI nie moontlik gewees het nie.", + "{0} homepage": "{0} tuisblad", + "UniGetUI has been translated to more than 40 languages thanks to the volunteer translators. Thank you 🤝": "UniGetUI is in meer as 40 tale vertaal danksy die vrywillige vertalers. Dankie 🤝", + "Verbose": "Omvattend", + "1 - Errors": "1 - Foute", + "2 - Warnings": "2 - Waarskuwings", + "3 - Information (less)": "3 - Inligting (minder).", + "4 - Information (more)": "4 - Inligting (meer)", + "5 - information (debug)": "5 - Inligting (ontfout)", + "Warning": "Waarskuwing", + "The following settings may pose a security risk, hence they are disabled by default.": "Die volgende instellings kan 'n sekuriteitsrisiko inhou en is daarom by verstek gedeaktiveer.", + "Enable the settings below if and only if you fully understand what they do, and the implications they may have.": "Aktiveer die onderstaande instellings slegs as jy ten volle verstaan wat hulle doen en watter implikasies dit kan hê.", + "The settings will list, in their descriptions, the potential security issues they may have.": "Die instellings sal in hul beskrywings die moontlike sekuriteitskwessies lys wat hulle kan hê.", + "The backup will include the complete list of the installed packages and their installation options. Ignored updates and skipped versions will also be saved.": "Die rugsteun bevat die volledige lys van die geïnstalleerde pakkette en hul installasie opsies. Ignoreerde opdaterings en oorgeslaande weergawes sal ook gestoor word.", + "The backup will NOT include any binary file nor any program's saved data.": "Die rugsteun sal NIE enige binêre lêer of enige program se gestoorde data insluit nie.", + "The size of the backup is estimated to be less than 1MB.": "Die grootte van die rugsteun word geskat op minder as 1 MB.", + "The backup will be performed after login.": "Die rugsteun sal uitgevoer word na aanmelding.", + "{pcName} installed packages": "{pcName} geïnstalleerde pakkette", + "Current status: Not logged in": "Huidige status: Nie aangemeld nie", + "You are logged in as {0} (@{1})": "Jy is aangemeld as {0} (@{1})", + "Nice! Backups will be uploaded to a private gist on your account": "Mooi! Rugsteune sal na 'n private gist in jou rekening opgelaai word", + "Select backup": "Kies rugsteun", + "Settings imported from {0}": "Instellings ingevoer vanaf {0}", + "UniGetUI Settings": "UniGetUI-instellings", + "Settings exported to {0}": "Instellings uitgevoer na {0}", + "UniGetUI settings were reset": "UniGetUI-instellings is teruggestel", + "Allow pre-release versions": "Laat voorvrystelling-weergawes toe", + "Apply": "Pas toe", + "For security reasons, custom command-line arguments are disabled by default. Go to UniGetUI security settings to change this.": "Om veiligheidsredes is pasgemaakte opdragreëlargumente standaard gedeaktiveer. Gaan na UniGetUI se sekuriteitsinstellings om dit te verander.", + "Go to UniGetUI security settings": "Gaan na UniGetUI-sekuriteitsinstellings", + "The following options will be applied by default each time a {0} package is installed, upgraded or uninstalled.": "Die volgende opsies sal by verstek toegepas word elke keer wanneer 'n {0}-pakket geïnstalleer, opgegradeer of gedeïnstalleer word.", + "Package's default": "Pakket se verstek", + "Install location can't be changed for {0} packages": "Installeerligging kan nie vir {0}-pakkette verander word nie", + "The local icon cache currently takes {0} MB": "Die plaaslike ikoon voorlopige geheue neem tans {0} MB", + "Username": "Gebruikers naam", + "Password": "Wagwoord", + "Credentials": "Verwysings", + "It is not guaranteed that the provided credentials will be stored safely": "Daar is geen waarborg dat die verskafte geloofsbriewe veilig gestoor sal word nie", + "Partially": "Gedeeltelik", + "Package manager": "Pakket bestuurder", + "Compatible with proxy": "Versoenbaar met volmag", + "Compatible with authentication": "Versoenbaar met verifiëring", + "Proxy compatibility table": "Volmag versoenbaarheid tabel", + "{0} settings": "{0} instellings", + "{0} status": "{0} stand", + "Default installation options for {0} packages": "Verstek-installeeropsies vir {0}-pakkette", + "Expand version": "Brei weergawe uit", + "The executable file for {0} was not found": "Die uitvoerbare lêer vir {0} is nie gevind nie", + "{pm} is disabled": "{pm} is gedeaktiveer", + "Enable it to install packages from {pm}.": "Stel dit in staat om pakkette vanaf {pm} te installeer.", + "{pm} is enabled and ready to go": "{pm} is geaktiveer en gereed om te begin", + "{pm} version:": "{pm} weergawe:", + "{pm} was not found!": "{pm} is nie gevind nie!", + "You may need to install {pm} in order to use it with UniGetUI.": "Miskien moet jy {pm} installeer om dit met UniGetUI te gebruik.", + "Scoop Installer - UniGetUI": "Scoop se Installer - UniGetUI", + "Scoop Uninstaller - UniGetUI": "Scoop deïnstalleerder - UniGetUI", + "Clearing Scoop cache - UniGetUI": "Skoonmaak van die Scoop se voorlopige geheue - UniGetUI", + "Restart UniGetUI to fully apply changes": "Herbegin UniGetUI om veranderinge volledig toe te pas", + "Restart UniGetUI": "Herbegin UniGetUI", + "Manage {0} sources": "Bestuur {0} bronne", + "Add source": "Voeg bron by", + "Add": "Voegby", + "Source name": "Bronnaam", + "Source URL": "Bron-URL", + "Other": "Ander", + "No minimum age": "Geen minimum ouderdom nie", + "1 day": "'n dag", + "{0} days": "{0} dae", + "Custom...": "Pasgemaak...", + "{0} minutes": "{0} minute", + "1 hour": "'n uur", + "{0} hours": "{0} ure", + "1 week": "'n week", + "Supports release dates": "Ondersteun vrystellingsdatums", + "Release date support per package manager": "Ondersteuning vir vrystellingsdatums per pakketbestuurder", + "Search for packages": "Soek vir pakkette", + "Local": "Plaaslike", + "OK": "Goed", + "Last checked: {0}": "Laas nagegaan: {0}", + "{0} packages were found, {1} of which match the specified filters.": "{0} pakkette is gevind, {1} van die wat ooreenstem met die gespesifiseerde filtreers.", + "{0} selected": "{0} gekies", + "(Last checked: {0})": "(Laas nagegaan: {0})", + "All packages selected": "Alle pakkette gekies", + "Package selection cleared": "Pakketkeuse uitgevee", + "{0}: {1}": "{0}: {1}", + "More info": "Meer inligting", + "GitHub account": "GitHub-rekening", + "Log in with GitHub to enable cloud package backup.": "Meld met GitHub aan om wolk-pakket-rugsteun te aktiveer.", + "More details": "Meer besonderhede", + "Log in": "Meld aan", + "If you have cloud backup enabled, it will be saved as a GitHub Gist on this account": "As jy wolkrugsteun geaktiveer het, sal dit as 'n GitHub Gist in hierdie rekening gestoor word", + "Log out": "Meld af", + "About UniGetUI": "Oor UniGetUI", + "About": "Omtrent", + "Third-party licenses": "Derde party lisensies", + "Contributors": "Bydraers\n", + "Translators": "Vertalers", + "Bundle security report": "Bondel-sekuriteitsverslag", + "The bundle contained restricted content": "Die bundel het beperkte inhoud bevat", + "UniGetUI – Crash Report": "UniGetUI – Omvalverslag", + "UniGetUI has crashed": "UniGetUI het omgeval", + "Help us fix this by sending a crash report to Devolutions. All fields below are optional.": "Help ons om dit reg te maak deur 'n omvalverslag aan Devolutions te stuur. Alle velde hieronder is opsioneel.", + "Email (optional)": "E-pos (opsioneel)", + "your@email.com": "jou@e-pos.com", + "Additional details (optional)": "Bykomende besonderhede (opsioneel)", + "Describe what you were doing when the crash occurred…": "Beskryf wat jy gedoen het toe die omval plaasgevind het…", + "Crash report": "Omvalverslag", + "Don't Send": "Moenie Stuur nie", + "Send Report": "Stuur Verslag", + "Sending…": "Stuur tans…", + "Unsaved changes": "Ongebergde veranderinge", + "You have unsaved changes in the current bundle. Do you want to discard them?": "Jy het ongebergde veranderinge in die huidige bundel. Wil jy hulle verwerp?", + "Discard changes": "Verwerp veranderinge", + "Integrity violation": "Integriteitskending", + "UniGetUI or some of its components are missing or corrupt. It is strongly recommended to reinstall UniGetUI to adress the situation.": "UniGetUI of sommige van sy komponente ontbreek of is korrup. Dit word sterk aanbeveel om UniGetUI weer te installeer om die situasie reg te stel.", + "• Refer to the UniGetUI Logs to get more details regarding the affected file(s)": "• Verwys na die UniGetUI-logboeke vir meer besonderhede oor die betrokke lêer(s)", + "• Integrity checks can be disabled from the Experimental Settings": "• Integriteitskontroles kan vanuit die eksperimentele instellings gedeaktiveer word", + "Manage shortcuts": "Bestuur kortpaaie", + "UniGetUI has detected the following desktop shortcuts which can be removed automatically on future upgrades": "UniGetUI het die volgende werkskerm kortpaaie opgespoor wat outomaties verwyder kan word by toekomstige opgraderings", + "Do you really want to reset this list? This action cannot be reverted.": "Wil jy definitief hierdie lys terugstel? Hierdie aksie kan nie teruggekeer word nie.", + "Desktop shortcuts list": "Werkskerm-snelkoppelingslys", + "Open in explorer": "Maak oop in Verkenner", + "Remove from list": "Verwyder van lys", + "When new shortcuts are detected, delete them automatically instead of showing this dialog.": "Wanneer nuwe kortpaaie bespeur word, skrap hulle outomaties in plaas daarvan om hierdie dialoog te vertoon.", + "Not right now": "Nie nou nie", + "Missing dependency": "Ontbrekende afhanklikheid", + "UniGetUI requires {0} to operate, but it was not found on your system.": "UniGetUI benodig {0} om te werk, maar dit is nie op jou stelsel gevind nie.\n", + "Click on Install to begin the installation process. If you skip the installation, UniGetUI may not work as expected.": "Klik op Installeer om te begin met die installasie proses. As jy die installasie oorslaan, kan UniGetUI nie werk soos verwag nie.", + "Alternatively, you can also install {0} by running the following command in a Windows PowerShell prompt:": "Alternatiewelik kan u ook {0} installeer deur die volgende opdrag in 'n Windows PowerShell aanvraag uit te voer:", + "Install {0}": "Installeer {0}", + "Do not show this dialog again for {0}": "Moenie hierdie dialoog weer wys vir {0} nie", + "Please wait while {0} is being installed. A black window may show up. Please wait until it closes.": "Wag asseblief terwyl {0} geïnstalleer word. 'n Swart venster kan dalk oopmaak. Wag asseblief totdat dit sluit", + "{0} has been installed successfully.": "{0} is suksesvol geïnstalleer.", + "Please click on \"Continue\" to continue": "Klik asseblief op \"Gaan voort\" om voort te gaan", + "Continue": "Gaan voort", + "{0} has been installed successfully. It is recommended to restart UniGetUI to finish the installation": "{0} is suksesvol geïnstalleer. Dit word aanbeveel om UniGetUI te oorbegin om die installasie te voltooi", + "Restart later": "Herbegin later", + "An error occurred:": "'n Fout het voorgekom:", + "Please see the Command-line Output or refer to the Operation History for further information about the issue.": "Raadpleeg asseblief die opdrag reël uitset of verwys na die operasionele geskiedenis vir verdere inligting oor die kwessie.", + "Retry as administrator": "Herprobeer as administrateur ", + "Retry interactively": "Herprobeer interaktief ", + "Retry skipping integrity checks": "Herprobeer om integriteits kontroles oor te slaan", + "Installation options": "Installasie opsies", + "Save": "Stoor", + "UniGetUI collects anonymous usage data with the sole purpose of understanding and improving the user experience.": "UniGetUI versamel anonieme gebruiks data met die uitsluitlike doel om die gebruikers ervaring te verstaan en te verbeter.", + "More details about the shared data and how it will be processed": "Meer besonderhede oor die gedeelde data en hoe dit verwerk sal word", + "Do you accept that UniGetUI collects and sends anonymous usage statistics, with the sole purpose of understanding and improving the user experience?": "Aanvaar jy dat UniGetUI anonieme gebruiks statistieke versamel en stuur, met die uitsluitlike doel om die gebruikers ervaring te verstaan en te verbeter?", + "Decline": "Weier", + "No personal information is collected nor sent, and the collected data is anonimized, so it can't be back-tracked to you.": "Geen persoonlike inligting word ingesamel of gestuur nie, en die versamelde data word geanonimiseer, so dit kan nie na jou teruggestuur word nie.", + "Navigation panel": "Navigasiepaneel", + "Operations": "Bewerkings", + "Toggle operations panel": "Wissel bewerkingspaneel", + "Bulk operations": "Grootmaatbewerkings", + "Retry failed": "Herprobeer misluktes", + "Clear successful": "Vee suksesvolles uit", + "Clear finished": "Vee voltooides uit", + "Cancel all": "Kanselleer alles", + "More": "Meer", + "Toggle navigation panel": "Wissel navigasiepaneel", + "Minimize": "Minimaliseer", + "Maximize": "Maksimaliseer", + "UniGetUI by Devolutions": "UniGetUI deur Devolutions", + "UniGetUI is an application that makes managing your software easier, by providing an all-in-one graphical interface for your command-line package managers.": "UniGetUI is 'n toepassing wat die bestuur van jou sagteware makliker maak deur 'n alles-in-een grafiese koppelvlak vir jou opdrag reël pakket bestuurders te verskaf.", + "Useful links": "Nuttige skakels", + "UniGetUI Homepage": "UniGetUI-tuisblad", + "Report an issue or submit a feature request": "Rapporteer 'n probleem of dien 'n funksie versoek in", + "UniGetUI Repository": "UniGetUI-bewaarplek", + "View GitHub Profile": "Kyk na GitHub profiel", + "UniGetUI License": "UniGetUI Lisensie ", + "Using UniGetUI implies the acceptation of the MIT License": "Die gebruik van UniGetUI impliseer die aanvaarding van die MIT-lisensie", + "Become a translator": "Word 'n vertaler", + "Go back": "Gaan terug", + "Go forward": "Gaan vorentoe", + "Go to home page": "Gaan na tuisblad", + "Reload page": "Herlaai bladsy", + "View page on browser": "Bekyk bladsy op blaaier", + "The built-in browser is not supported on Linux yet.": "Die ingeboude blaaier word nog nie op Linux ondersteun nie.", + "Open in browser": "Maak in blaaier oop", + "Copy to clipboard": "Kopieer na knipbord", + "Export to a file": "Voer uit na 'n lêer", + "Log level:": "Log vlak: ", + "Reload log": "Herlaai log", + "Export log": "Voer logboek uit", + "Text": "Teks", + "Change how operations request administrator rights": "Verander hoe bedryfs versoek administrateur regte raak\n\n", + "Restrictions on package operations": "Beperkings op pakketbewerkings", + "Restrictions on package managers": "Beperkings op pakketbestuurders", + "Restrictions when importing package bundles": "Beperkings wanneer pakketbondels ingevoer word", + "Ask for administrator privileges once for each batch of operations": "Vra een keer vir administrateur regte vir elke bondel bewerkings", + "Ask only once for administrator privileges": "Vra slegs een keer vir administrateurvoorregte", + "Prohibit any kind of Elevation via UniGetUI Elevator or GSudo": "Verbied enige vorm van verhoging via UniGetUI Elevator of GSudo", + "This option WILL cause issues. Any operation incapable of elevating itself WILL FAIL. Install/update/uninstall as administrator will NOT WORK.": "Hierdie opsie SAL probleme veroorsaak. Enige bewerking wat homself nie kan verhoog nie, SAL MISLUK. Installeer, dateer op of deïnstalleer as administrateur SAL NIE WERK NIE.", + "Allow custom command-line arguments": "Laat pasgemaakte opdragreël-argumente toe", + "Custom command-line arguments can change the way in which programs are installed, upgraded or uninstalled, in a way UniGetUI cannot control. Using custom command-lines can break packages. Proceed with caution.": "Pasgemaakte opdragreël-argumente kan die manier waarop programme geïnstalleer, opgegradeer of gedeïnstalleer word verander op 'n manier wat UniGetUI nie kan beheer nie. Die gebruik van pasgemaakte opdragreëls kan pakkette breek. Gaan versigtig voort.", + "Ignore custom pre-install and post-install commands when importing packages from a bundle": "Laat pasgemaakte voor-installeer- en na-installeer-opdragte toe om uitgevoer te word", + "Pre and post install commands will be run before and after a package gets installed, upgraded or uninstalled. Be aware that they may break things unless used carefully": "Voor- en na-installeer-opdragte sal voor en na die installering, opgradering of deïnstallering van 'n pakket uitgevoer word. Wees bewus daarvan dat hulle dinge kan breek as hulle nie versigtig gebruik word nie", + "Allow changing the paths for package manager executables": "Laat toe dat die paaie vir pakketbestuurder-uitvoerbare lêers verander word", + "Turning this on enables changing the executable file used to interact with package managers. While this allows finer-grained customization of your install processes, it may also be dangerous": "As jy dit aanskakel, kan die uitvoerbare lêer wat gebruik word om met pakketbestuurders te werk verander word. Al laat dit fyner aanpassing van jou installasieprosesse toe, kan dit ook gevaarlik wees", + "Allow importing custom command-line arguments when importing packages from a bundle": "Laat die invoer van pasgemaakte opdragreël-argumente toe wanneer pakkette vanaf 'n bondel ingevoer word", + "Malformed command-line arguments can break packages, or even allow a malicious actor to gain privileged execution. Therefore, importing custom command-line arguments is disabled by default": "Wanvormde opdragreël-argumente kan pakkette breek of selfs 'n kwaadwillige akteur toelaat om verhoogde uitvoering te verkry. Daarom is die invoer van pasgemaakte opdragreël-argumente by verstek gedeaktiveer.", + "Allow importing custom pre-install and post-install commands when importing packages from a bundle": "Laat die invoer van pasgemaakte voor-installeer- en na-installeer-opdragte toe wanneer pakkette vanaf 'n bondel ingevoer word", + "Pre and post install commands can do very nasty things to your device, if designed to do so. It can be very dangerous to import the commands from a bundle, unless you trust the source of that package bundle": "Voor- en na-installeer-opdragte kan baie slegte dinge aan jou toestel doen as hulle daarvoor ontwerp is. Dit kan baie gevaarlik wees om hierdie opdragte uit 'n bondel in te voer, tensy jy die bron van daardie pakketbondel vertrou", + "Administrator rights and other dangerous settings": "Administrateurregte en ander gevaarlike instellings", + "Package backup": "Pakket rugsteun", + "Cloud package backup": "Wolk-rugsteun vir pakkette", + "Local package backup": "Plaaslike pakket-rugsteun", + "Local backup advanced options": "Gevorderde plaaslike rugsteunopsies", + "Log in with GitHub": "Meld aan met GitHub", + "Log out from GitHub": "Meld af van GitHub", + "Periodically perform a cloud backup of the installed packages": "Voer periodiek 'n wolkrugsteun van die geïnstalleerde pakkette uit", + "Cloud backup uses a private GitHub Gist to store a list of installed packages": "Wolkrugsteun gebruik 'n private GitHub Gist om 'n lys van geïnstalleerde pakkette te stoor", + "Perform a cloud backup now": "Voer nou 'n wolkrugsteun uit", + "Backup": "Rugsteun", + "Restore a backup from the cloud": "Herstel 'n rugsteun vanuit die wolk", + "Begin the process to select a cloud backup and review which packages to restore": "Begin die proses om 'n wolkrugsteun te kies en te hersien watter pakkette herstel moet word", + "Periodically perform a local backup of the installed packages": "Voer periodiek 'n plaaslike rugsteun van die geïnstalleerde pakkette uit", + "Perform a local backup now": "Voer nou 'n plaaslike rugsteun uit", + "Change backup output directory": "Verander rugsteun lewering lêergids", + "Set a custom backup file name": "Stel 'n pasgemaakte rugsteun lêer naam vas", + "Leave empty for default": "Laat leeg vir standaard", + "Add a timestamp to the backup file names": "Voeg 'n tyd stempel by die rugsteun lêer name", + "Backup and Restore": "Rugsteun en herstel", + "Enable background api (UniGetUI Widgets and Sharing, port 7058)": "Aktiveer agtergrond API (Wingets vir UniGetUI en Deel, Port 7058)", + "Wait for the device to be connected to the internet before attempting to do tasks that require internet connectivity.": "Wag totdat die toestel aan die internet gekoppel is voordat jy probeer om take te verrig wat internet verbinding benodig.", + "Disable the 1-minute timeout for package-related operations": "Deaktiveer die 1-minuut spertydperk vir pakketverwante bewerkings", + "Use installed GSudo instead of UniGetUI Elevator": "Gebruik geïnstalleerde GSudo in plaas van UniGetUI Elevator", + "Use a custom icon and screenshot database URL": "Gebruik 'n pasgemaakte ikoon en 'n skermkiekie databasis URL", + "Enable background CPU Usage optimizations (see Pull Request #3278)": "Aktiveer agtergrond -CPU gebruiks optimalisering (see Pull Request #3278)", + "Perform integrity checks at startup": "Voer integriteitskontroles by opstart uit", + "When batch installing packages from a bundle, install also packages that are already installed": "Wanneer pakkette in bondels geïnstalleer word, installeer ook pakkette wat reeds geïnstalleer is", + "Experimental settings and developer options": "Eksperimentele instellings en ontwikkelaar opsies", + "Show UniGetUI's version and build number on the titlebar.": "Wys UniGetUI se weergawe op die titel balk", + "Language": "Taal", + "UniGetUI updater": "UniGetUI opdatering", + "Telemetry": "Telemetrie", + "Manage UniGetUI settings": "Bestuur UniGetUI instellings", + "Related settings": "Verwante instellings", + "Update UniGetUI automatically": "Dateer UniGetUI outomaties op", + "Check for updates": "Kyk vir opdaterings", + "Install prerelease versions of UniGetUI": "Installeer voor vrystel uitgawe van UniGetUI", + "Manage telemetry settings": "Bestuur telemetrie-instellings", + "Manage": "Bestuur", + "Import settings from a local file": "Voer instellings van 'n plaaslike lêer in", + "Import": "Voer in", + "Export settings to a local file": "Voer instellings uit na 'n plaaslike lêer", + "Export": "Uitvoer", + "Reset UniGetUI": "Herstel UniGetUI", + "User interface preferences": "Voorkeure vir gebruiker koppelvlak", + "Application theme, startup page, package icons, clear successful installs automatically": "Toepassings tema, begin bladsy, pakket ikone, suksesvolle installasies outomaties skoon gemaak", + "General preferences": "Algemene voorkeure", + "UniGetUI display language:": "UniGetUI vertoon taal:", + "System language": "Stelseltaal", + "Is your language missing or incomplete?": "Ontbreek jou taal of is dit onvolledig?", + "Appearance": "Voorkoms ", + "UniGetUI on the background and system tray": "UniGetUI op die agtergrond en stelsel balk", + "Package lists": "Pakket lyste", + "Use classic mode": "Gebruik klassieke modus", + "Restart UniGetUI to apply this change": "Herbegin UniGetUI om hierdie verandering toe te pas", + "The classic UI is disabled for beta testers": "Die klassieke UI is vir beta-toetsers gedeaktiveer", + "Close UniGetUI to the system tray": "Maak dat Unigetui na die stelselbakkie toe gaan", + "Manage UniGetUI autostart behaviour": "Bestuur UniGetUI se outostart-gedrag", + "Show package icons on package lists": "Wys pakket ikone op pakket lyste", + "Clear cache": "Maak voorlopige geheue skoon", + "Select upgradable packages by default": "Selekteer standaard opgradeerbare pakkette", + "Light": "Lig", + "Dark": "Donker", + "Follow system color scheme": "Volg die stelsel kleur skema", + "Application theme:": "Toepassings tema:", + "UniGetUI startup page:": "UniGetUI Begin bladsy:", + "Proxy settings": "Volmag instellings", + "Other settings": "Ander instellings", + "Connect the internet using a custom proxy": "Verbind die internet met behulp van persoonlike volmag", + "Please note that not all package managers may fully support this feature": "Let asseblief daarop dat nie alle pakket bestuurders hierdie funksie ten volle kan ondersteun nie", + "Proxy URL": "Volmag UTL", + "Enter proxy URL here": "Voer hier 'n volmag URL in", + "Authenticate to the proxy with a user and a password": "Meld by die instaanbediener aan met 'n gebruiker en wagwoord", + "Internet and proxy settings": "Internet- en instaanbedienerinstellings", + "Package manager preferences": "Pakket bestuurders se voorkeure", + "Ready": "Gereed", + "Not found": "Nie gevind nie", + "Notification preferences": "Kennisgewing voorkeure", + "Notification types": "Kennisgewing tipes", + "The system tray icon must be enabled in order for notifications to work": "Die stelsel bakkie ikoon moet aangeskakel word om kennisgewings te laat werk", + "Enable UniGetUI notifications": "Aktiveer UniGetUI kennisgewings", + "Show a notification when there are available updates": "Wys 'n kennisgewing wanneer daar beskikbare opdaterings is", + "Show a silent notification when an operation is running": "Wys 'n stil kennisgewing wanneer 'n opdrag loop", + "Show a notification when an operation fails": "Wys 'n kennisgewing aan wanneer 'n opdrag misluk", + "Show a notification when an operation finishes successfully": "Wys 'n kennisgewing wanneer 'n opdrag suksesvol voltooi is", + "Concurrency and execution": "Gelyktydigheid en uitvoering ", + "Automatic desktop shortcut remover": "Outomatiese gebruikskoppelvlak kortpad verwyderaar", + "Choose how many operations should be performed in parallel": "Kies hoeveel bewerkings parallel uitgevoer moet word", + "Clear successful operations from the operation list after a 5 second delay": "Maak suksesvolle operasies van die operasie lys na 5 sekondes vertraging skoon", + "Download operations are not affected by this setting": "Aflaaibewerkings word nie deur hierdie instelling beïnvloed nie", + "You may lose unsaved data": "Jy kan ongestoorde data verloor", + "Ask to delete desktop shortcuts created during an install or upgrade.": "Vra om die kortpaaie van die gebruikskoppelvlak te verwyder wat tydens 'n installasie of opgradering geskep is.", + "Package update preferences": "Voorkeure vir pakket opdatering", + "Update check frequency, automatically install updates, etc.": "Dateer kontrole frekwensie op, installeer opdaterings outomaties, ens.", + "Reduce UAC prompts, elevate installations by default, unlock certain dangerous features, etc.": "Verminder UAC-aanporboodskappe, verhoog installasies by verstek, ontsluit sekere gevaarlike funksies, ens.", + "Package operation preferences": "Voorkeure vir pakket bewerking", + "Enable {pm}": "Aktiveer {pm}", + "Not finding the file you are looking for? Make sure it has been added to path.": "Kan jy nie die lêer kry waarna jy soek nie? Maak seker dit is by PATH gevoeg.", + "Select the executable to be used. The following list shows the executables found by UniGetUI": "Kies die uitvoerbare lêer wat gebruik moet word. Die volgende lys wys die uitvoerbare lêers wat deur UniGetUI gevind is", + "For security reasons, changing the executable file is disabled by default": "Om veiligheidsredes is die verandering van die uitvoerbare lêer by verstek gedeaktiveer", + "Change this": "Verander dit", + "Copy path": "Kopieer pad", + "Current executable file:": "Huidige uitvoerbare lêer:", + "Ignore packages from {pm} when showing a notification about updates": "Ignoreer pakkette van {pm} wanneer jy 'n kennisgewing oor opdaterings toon", + "Update security": "Opdateringsveiligheid", + "Use global setting": "Gebruik globale instelling", + "Minimum age for updates": "Minimum ouderdom vir opdaterings", + "e.g. 10": "bv. 10", + "Custom minimum age (days)": "Pasgemaakte minimum ouderdom (dae)", + "{pm} does not provide release dates for its packages, so this setting will have no effect": "{pm} verskaf nie vrystellingsdatums vir sy pakkette nie, dus sal hierdie instelling geen effek hê nie", + "{pm} only provides release dates for some of its packages, so this setting will only apply to those packages": "{pm} verskaf slegs vrystellingdatums vir sommige van sy pakkette, dus sal hierdie instelling slegs op daardie pakkette van toepassing wees", + "Override the global minimum update age for this package manager": "Oorskryf die globale minimum opdateringsouderdom vir hierdie pakketbestuurder", + "View {0} logs": "Bekyk {0} logs", + "If Python cannot be found or is not listing packages but is installed on the system, ": "As Python nie gevind kan word nie of nie pakkette lys nie maar wel op die stelsel geïnstalleer is, ", + "Advanced options": "Gevorderde opsies ", + "WinGet command-line tool": "WinGet-opdragreëlnutsmiddel", + "Choose which command-line tool UniGetUI uses for WinGet operations when the COM API is not used": "Kies watter opdragreëlnutsmiddel UniGetUI vir WinGet-bewerkings gebruik wanneer die COM API nie gebruik word nie", + "WinGet COM API": "WinGet COM API", + "Choose whether UniGetUI can use the WinGet COM API before falling back to the command-line tool": "Kies of UniGetUI die WinGet COM API kan gebruik voordat dit na die opdragreëlnutsmiddel terugval", + "Reset WinGet": "Herstel WinGet", + "This may help if no packages are listed": "Dit kan help as geen pakkette gelys word nie", + "Force install location parameter when updating packages with custom locations": "Dwing installeer-liggingparameter af wanneer pakkette met pasgemaakte liggings opgedateer word", + "Install Scoop": "Installeer Scoop", + "Uninstall Scoop (and its packages)": "Deïnstalleer Scoop (en sy pakkette)", + "Run cleanup and clear cache": "Laat loop skoonmaak en maak voorlopige geheue skoon", + "Run": "Laat loop", + "Enable Scoop cleanup on launch": "Aktiveer Scoop se opruiming by bekendstelling", + "Default vcpkg triplet": "Standaard vcpkg triplet", + "Change vcpkg root location": "Verander vcpkg se wortelligging", + "Reset vcpkg root location": "Herstel vcpkg-wortelligging", + "Open vcpkg root location": "Open vcpkg-wortelligging", + "Language, theme and other miscellaneous preferences": "Taal, tema en ander diverse voorkeure", + "Show notifications on different events": "Wys kennisgewings oor verskillende gebeure", + "Change how UniGetUI checks and installs available updates for your packages": "Verander hoe UniGetUI kontrol word en installeer die beskikbare updates vir jou pakkette", + "Automatically save a list of all your installed packages to easily restore them.": "Stoor outomaties 'n lys van al jou geïnstalleerde pakkette om dit maklik te herstel.", + "Enable and disable package managers, change default install options, etc.": "Aktiveer en deaktiveer pakketbestuurders, verander verstek-installeeropsies, ens.", + "Internet connection settings": "Internet verbindings instellings", + "Proxy settings, etc.": "Volmag instellings, ens.", + "Beta features and other options that shouldn't be touched": "Beta kenmerke en ander opsies wat nie aangeraak moet word nie", + "Reload sources": "Herlaai bronne", + "Delete source": "Verwyder bron", + "Known sources": "Bekende bronne", + "Update checking": "Kontrole vir opdaterings", + "Automatic updates": "Outomatiese opdaterings", + "Check for package updates periodically": "Kyk periodiek vir pakket opdaterings", + "Check for updates every:": "Kyk vir opdaterings elke:", + "Install available updates automatically": "Installeer beskikbare opdaterings outomaties", + "Do not automatically install updates when the network connection is metered": "Moenie outomaties opdaterings installeer wanneer die netwerkverbinding gemeteerd word nie", + "Do not automatically install updates when the device runs on battery": "Moenie opdaterings outomaties installeer wanneer die toestel op battery loop nie", + "Do not automatically install updates when the battery saver is on": "Moenie outomaties opdaterings installeer wanneer die batterybesparing aan is nie", + "Only show updates that are at least the specified number of days old": "Wys slegs opdaterings wat minstens die gespesifiseerde aantal dae oud is", + "Warn me when the installer URL host changes between the installed version and the new version (WinGet only)": "Waarsku my wanneer die installeerder-URL se gasheer tussen die geïnstalleerde weergawe en die nuwe weergawe verander (slegs WinGet)", + "Change how UniGetUI handles install, update and uninstall operations.": "Verander hoe Unigetui installeer en deïnstalleer van bewerkings hanteer.", + "Navigation": "Navigasie", + "Check for UniGetUI updates": "Kyk vir UniGetUI-opdaterings", + "Quit UniGetUI": "Sluit UniGetUI af", + "Filters": "Filtreer", + "Sources": "Bronne", + "Search for packages to start": "Soek vir pakkette om te begin", + "Select all": "Selekteer alles", + "Clear selection": "Maak seleksie skoon", + "Instant search": "Onmiddellike soektog", + "Distinguish between uppercase and lowercase": "Onderskei tussen hoofletters en kleinletters", + "Ignore special characters": "Ignoreer spesiale karakters", + "Search mode": "Soek modus", + "Both": "Beide", + "Exact match": "Presiese resultaat", + "Show similar packages": "Wys soortgelyke pakkette", + "Loading": "Laai tans", + "Package": "Pakket", + "More options": "Meer opsies", + "Order by:": "Volgorde:", + "Name": "Naam", + "Id": "ID", + "Ascendant": "Opgang", + "Descendant": "Nasaat", + "View modes": "Aansigmodusse", + "Reload": "Herlaai", + "Closed": "Gesluit", + "Ascending": "Stygende", + "Descending": "Dalende", + "{0}: {1}, {2}": "{0}: {1}, {2}", + "Order by": "Sorteer volgens", + "No results were found matching the input criteria": "Geen resultate is gevind wat ooreenstem met die inset kriteria nie", + "No packages were found": "Geen pakkette is gevind nie", + "Loading packages": "Laai pakkette ", + "Skip integrity checks": "Slaan integriteits kontroles oor", + "Download selected installers": "Laai geselekteerde installeerders af", + "Install selection": "Installeer seleksie", + "Install options": "Installeeropsies", + "Add selection to bundle": "Voeg seleksie by bundel", + "Download installer": "Laai installeerder af", + "Uninstall selection": "Deïnstalleer seleksie", + "Uninstall options": "Deïnstalleeropsies", + "Ignore selected packages": "Ignoreer geselekteerde pakkette", + "Open install location": "Maak installeer ligging oop", + "Reinstall package": "Herinstalleer Pakkette", + "Uninstall package, then reinstall it": "Deïnstalleer pakket en installeer dit dan weer", + "Ignore updates for this package": "Ignoreer opdaterings vir hierdie pakket", + "WinGet malfunction detected": "WinGet wanfunksie opgespoor", + "It looks like WinGet is not working properly. Do you want to attempt to repair WinGet?": "Dit lyk asof Winget nie goed werk nie. Wil jy probeer om Winget te herstel?", + "Repair WinGet": "Herstel WinGet", + "Updates will no longer be ignored for {0}": "Opdaterings sal nie meer geïgnoreer word vir {0} nie", + "Updates are now ignored for {0}": "Opdaterings word nou geïgnoreer vir {0}", + "Do not ignore updates for this package anymore": "Moenie meer opdaterings vir hierdie pakket ignoreer nie", + "Add packages or open an existing package bundle": "Voeg pakkette by of open 'n bestaande pakket bundel", + "Add packages to start": "Voeg pakkette by om te begin", + "The current bundle has no packages. Add some packages to get started": "Die huidige bundel het geen pakkette nie. Voeg 'n paar pakkette by om aan die gang te kom", + "New": "Nuut", + "Save as": "Stoor as", + "Create .ps1 script": "Skep .ps1-skrip", + "Remove selection from bundle": "Verwyder seleksie uit bondel", + "Skip hash checks": "Slaan hash kontroles oor", + "The package bundle is not valid": "Die pakket bundel is nie geldig nie", + "The bundle you are trying to load appears to be invalid. Please check the file and try again.": "Die bundel wat jy probeer laai blyk ongeldig te wees. Kontroleer aseblief die lêer en probeer weer.", + "Package bundle": "Pakket bundel", + "Could not create bundle": "Kon nie bondel skep nie", + "The package bundle could not be created due to an error.": "Die pakket bundel kon nie geskep word nie weens 'n fout.", + "Install script": "Installeer-skrip", + "PowerShell script": "PowerShell-skrip", + "The installation script saved to {0}": "Die installasie-skrip is na {0} gestoor", + "An error occurred": "'n Fout het voorgekom", + "An error occurred while attempting to create an installation script:": "'n Fout het voorgekom tydens die poging om 'n installasie-skrip te skep:", + "Hooray! No updates were found.": "Hoera! Geen opdaterings is gevind nie.", + "Uninstall selected packages": "Deïnstalleer geselekteerde pakkette", + "Update selection": "Dateer seleksie op", + "Update options": "Opdateeropsies", + "Uninstall package, then update it": "Deïnstalleer pakket en dateer dit dan op", + "Uninstall package": "Deïnstalleer pakket", + "Skip this version": "Slaan hierdie weergawe oor", + "Pause updates for": "Pouse opdaterings vir", + "User | Local": "Gebruiker | Plaaslik", + "Machine | Global": "Masjien | Globaal", + "The default package manager for Debian/Ubuntu-based Linux distributions.
Contains: Debian/Ubuntu packages": "Die verstekpakketbestuurder vir Debian/Ubuntu-gebaseerde Linux-verspreidings.
Bevat: Debian/Ubuntu-pakkette", + "The Rust package manager.
Contains: Rust libraries and programs written in Rust": "Die Rust pakket bestuurder.
Bevat: \nRust biblioteke en programme wat in Rust geskryf is ", + "The classical package manager for windows. You'll find everything there.
Contains: General Software": "Die klassieke pakket bestuurder vir windows. Jy sal alles daar vind.
Bevat: Algemene sagteware", + "The default package manager for RHEL/Fedora-based Linux distributions.
Contains: RPM packages": "Die verstekpakketbestuurder vir RHEL/Fedora-gebaseerde Linux-verspreidings.
Bevat: RPM-pakkette", + "A repository full of tools and executables designed with Microsoft's .NET ecosystem in mind.
Contains: .NET related tools and scripts": "'n Bewaarplek vol gereedskap en uitvoerbare artikels wat ontwerp is met Microsoft se .NET -ekosisteem in gedagte.
Bevat: .NET -verwante gereedskap en skrifte ", + "The universal Linux package manager for desktop applications.
Contains: Flatpak applications from configured remotes": "Die universele Linux-pakketbestuurder vir werkskermtoepassings.
Bevat: Flatpak-toepassings vanaf gekonfigureerde afstandbronne", + "NuPkg (zipped manifest)": "NuPkg (kompakteer openbaar) ", + "The Missing Package Manager for macOS (or Linux).
Contains: Formulae, Casks": "Die ontbrekende pakketbestuurder vir macOS (of Linux).
Bevat: Formulae, Casks", + "Node JS's package manager. Full of libraries and other utilities that orbit the javascript world
Contains: Node javascript libraries and other related utilities": "Node JS se pakket bestuurder. Vol biblioteke en ander hulpmiddels wat om die javascript-wêreld wentel
Bevat: Node javascript biblioteke en ander verwante hulpmiddels", + "The default package manager for Arch Linux and its derivatives.
Contains: Arch Linux packages": "Die verstekpakketbestuurder vir Arch Linux en sy afgeleides.
Bevat: Arch Linux-pakkette", + "Python's library manager. Full of python libraries and other python-related utilities
Contains: Python libraries and related utilities": "Python se biblioteek bestuurder. Vol python biblioteke en ander Python verwante hulpmiddels
bevat: Python biblioteke en verwante hulpmiddels ", + "PowerShell's package manager. Find libraries and scripts to expand PowerShell capabilities
Contains: Modules, Scripts, Cmdlets": "PowerShell se pakket bestuurder. Vind biblioteke en skrifte om PowerShell vermoëns uit te brei
bevat: modules, skrifte, Cmdlets ", + "extracted": "onttrek", + "Scoop package": "Scoop pakket ", + "Great repository of unknown but useful utilities and other interesting packages.
Contains: Utilities, Command-line programs, General Software (extras bucket required)": "Groot bewaarplek van onbekende, maar nuttige hulpmiddels en ander interessante pakkette.
Bevat: Nuts programme, opdragreël programme, Algemene sagteware (ekstra-houer vereis)", + "The universal Linux package manager by Canonical.
Contains: Snap packages from the Snapcraft store": "Die universele Linux-pakketbestuurder deur Canonical.
Bevat: Snap-pakkette van die Snapcraft-winkel", + "library": "biblioteek", + "feature": "kenmerk", + "A popular C/C++ library manager. Full of C/C++ libraries and other C/C++-related utilities
Contains: C/C++ libraries and related utilities": "'n Gewilde C/C ++ Biblioteekbestuurder. Vol van C/C ++ biblioteke en ander C/C ++-Verwante hulpprogramme
bevat: c/c ++ biblioteke en verwante hulpmiddels ", + "option": "keuse", + "This package cannot be installed from an elevated context.": "Hierdie pakket kan nie vanuit 'n verhoogde konteks geïnstalleer word nie.", + "Please run UniGetUI as a regular user and try again.": "Voer asseblief UniGetUI as \"n gewone gebruiker uit en probeer weer.", + "Please check the installation options for this package and try again": "Gaan asseblief die installasie opsies vir hierdie pakket na en probeer weer", + "Microsoft's official package manager. Full of well-known and verified packages
Contains: General Software, Microsoft Store apps": "Microsoft se amptelike pakketbestuurder. Vol bekende en geverifieerde pakkette
Bevat: Algemene sagteware, Microsoft Store-toepassings", + "Local PC": "Plaaslike PC", + "Android Subsystem": "Android Substelsel", + "Operation on queue (position {0})...": "Opdrag in wagting (posisie {0})...", + "Click here for more details": "Klik hier vir meer besonderhede", + "Operation canceled by user": "Opdrag gekanselleer deur gebruiker", + "Running PreOperation ({0}/{1})...": "PreOperation word uitgevoer ({0}/{1})...", + "PreOperation {0} out of {1} failed, and was tagged as necessary. Aborting...": "PreOperation {0} uit {1} het misluk en is as nodig gemerk. Staak...", + "PreOperation {0} out of {1} finished with result {2}": "PreOperation {0} uit {1} het met resultaat {2} voltooi", + "Starting operation...": "Begin opdrag...", + "Running PostOperation ({0}/{1})...": "PostOperation word uitgevoer ({0}/{1})...", + "PostOperation {0} out of {1} failed, and was tagged as necessary. Aborting...": "PostOperation {0} uit {1} het misluk en is as nodig gemerk. Staak...", + "PostOperation {0} out of {1} finished with result {2}": "PostOperation {0} uit {1} het met resultaat {2} voltooi", + "{package} installer download": "{package} installer word aflaai", + "{0} installer is being downloaded": "{0} installeerder is besig om afgelaai te word", + "Download succeeded": "Aflaai het geslaag", + "{package} installer was downloaded successfully": "{package} installeerder is suksesvol afgelaai", + "Download failed": "Aflaai het misluk", + "{package} installer could not be downloaded": "{package} installeerder kon nie afgelaai word nie", + "{package} Installation": "{package} Installasie", + "{0} is being installed": "{0} word geïnstalleer ", + "Installation succeeded": "Installasie het geslaag", + "{package} was installed successfully": "{package} is suksesvol geïnstalleer", + "Installation failed": "Installasie het misluk", + "{package} could not be installed": "{package} kon nie geïnstalleer word nie", + "{package} Update": "{package} Opdatering", + "Update succeeded": "Opdatering het geslaag", + "{package} was updated successfully": "{package} is suksesvol opgedateer", + "Update failed": "Opdatering het misluk", + "{package} could not be updated": "{package} kon nie opgedateer word nie", + "{package} Uninstall": "{package} deïnstalleer", + "{0} is being uninstalled": "{0} word gedeïnstalleer", + "Uninstall succeeded": "Deïnstalleer het geslaag", + "{package} was uninstalled successfully": "{package} is suksesvol gedeïnstalleer", + "Uninstall failed": "Deïnstalleer het misluk", + "{package} could not be uninstalled": "{package} Kon nie geïnstalleer word nie ", + "Adding source {source}": "Voeg bron by {source}", + "Adding source {source} to {manager}": "Voeg bron by {source} na {manager}", + "Source added successfully": "Bron suksesvol bygevoeg", + "The source {source} was added to {manager} successfully": "Die bron {source} is suksevol bygevoeg na die {manager} ", + "Could not add source": "Kon nie bron byvoeg nie", + "Could not add source {source} to {manager}": "Kon nie die bron {source} by {manager} voeg nie", + "Removing source {source}": "Verwydering bron {source}", + "Removing source {source} from {manager}": "Verwydering bron {source} van {manager}", + "Source removed successfully": "Bron suksesvol verwyder", + "The source {source} was removed from {manager} successfully": "Die bron {source} is suksevol verwyder na die {manager} ", + "Could not remove source": "Kon nie bron verwyder nie", + "Could not remove source {source} from {manager}": "Kon die bron nie {source} van {manager} verwyder nie", + "The package manager \"{0}\" was not found": "Die pakketbestuurder \"{0}\" is nie gevind nie", + "The package manager \"{0}\" is disabled": "Die pakketbestuurder \"{0}\" is gestremd", + "There is an error with the configuration of the package manager \"{0}\"": "Daar is 'n fout met die konfigurasie van die pakket bestuurder \" {0}\"", + "The package \"{0}\" was not found on the package manager \"{1}\"": "Die pakket \"{0}\" is nie op die pakket bestuurder gevind nie \"{1}\"", + "{0} is disabled": "{0} is afgeskakel ", + "{0} weeks": "{0} weke", + "1 month": "1 maand", + "{0} months": "{0} maande", + "Something went wrong": "Iets het verkeerd geloop", + "An interal error occurred. Please view the log for further details.": "'n Interne fout het voorgekom. Kyk asseblief na die logboek vir verdere besonderhede.", + "No applicable installer was found for the package {0}": "Geen toepaslike installeerder is vir die pakket gevind nie{0}", + "Integrity checks will not be performed during this operation": "Integriteits kontroles sal nie tydens hierdie werking uitgevoer word nie", + "This is not recommended.": "Dit word nie aanbeveel nie.", + "Run now": "Laat loop nou", + "Run next": "Laat loop volgende", + "Run last": "Laat loop laaste", + "Show in explorer": "Wys in explorer", + "Checked": "Gemerk", + "Unchecked": "Ongemerk", + "This package is already installed": "Hierdie pakket is reeds geïnstalleer", + "This package can be upgraded to version {0}": "Hierdie pakket kan opgegradeer word na die weergawe {0}", + "Updates for this package are ignored": "Opdaterings vir hierdie pakket word geïgnoreer", + "This package is being processed": "Hierdie pakket word verwerk", + "This package is not available": "Hierdie pakket is nie beskikbaar nie", + "Select the source you want to add:": "Selekteer die bron wat jy wil byvoeg:", + "Source name:": "Bron naam:", + "Source URL:": "Bron URL:", + "An error occurred when adding the source: ": "'n Fout het voorgekom by die toevoeging van die bron:", + "Package management made easy": "Pakket bestuur maklik gemaak", + "version {0}": "weergawe {0}", + "[RAN AS ADMINISTRATOR]": "LAAT LOOP AS ADMINISTRATEUR ", + "Portable mode": "Draagbare modus", + "DEBUG BUILD": "ONTFOUT BOU", + "Here you can change UniGetUI's behaviour regarding the following shortcuts. Checking a shortcut will make UniGetUI delete it if if gets created on a future upgrade. Unchecking it will keep the shortcut intact": "Hier kan jy UniGetUI se gedrag ten opsigte van die volgende kortpaaie verander. As u 'n kortpad nagaan, sal UniGetUI dit uitvee as dit op \"n toekomstige opgradering geskep word. As jy dit ontmerk, sal die kortpad ongeskonde bly", + "Manual scan": "Handmatige skandering", + "Existing shortcuts on your desktop will be scanned, and you will need to pick which ones to keep and which ones to remove.": "Bestaande kortpaaie op jou werkskerm sal geskandeer word, en jy sal nodig het om te kies wat om te hou en wat om te verwyder.", + "Delete?": "Verwyder?", + "I understand": "Ek verstaan", + "Chocolatey setup changed": "Chocolatey-opstelling het verander", + "UniGetUI no longer includes its own private Chocolatey installation. A legacy UniGetUI-managed Chocolatey installation was detected for this user profile, but system Chocolatey was not found. Chocolatey will stay unavailable in UniGetUI until Chocolatey is installed on the system and UniGetUI is restarted. Applications previously installed through UniGetUI's bundled Chocolatey may still appear under other sources such as Local PC or WinGet.": "UniGetUI sluit nie meer sy eie private Chocolatey-installasie in nie. 'n Verouderde UniGetUI-bestuurde Chocolatey-installasie is vir hierdie gebruikersprofiel bespeur, maar stelsel-Chocolatey is nie gevind nie. Chocolatey sal onbeskikbaar bly in UniGetUI totdat Chocolatey op die stelsel geïnstalleer word en UniGetUI herbegin word. Toepassings wat voorheen deur UniGetUI se gebundelde Chocolatey geïnstalleer is, kan steeds onder ander bronne soos Plaaslike Rekenaar of WinGet verskyn.", + "NOTE: This troubleshooter can be disabled from UniGetUI Settings, on the WinGet section": "LET WEL: Hierdie probleem oplosser kan gedeaktiveer word vanaf UniGetUI instellings, op die WinGet afdeling", + "Restart": "Herbegin", + "Are you sure you want to delete all shortcuts?": "Is jy seker dat jy alle kortpaaie wil uitvee?", + "Any new shorcuts created during an install or an update operation will be deleted automatically, instead of showing a confirmation prompt the first time they are detected.": "Enige nuwe kortpaaie wat tydens 'n installasie of 'n opdaterings bewerking geskep is, sal outomaties uitgevee word, in plaas daarvan om die eerste keer dat dit opgespoor word, 'n bevestigings aanporboodskap te wys.", + "Any shorcuts created or modified outside of UniGetUI will be ignored. You will be able to add them via the {0} button.": "Enige koertpaaie wat buite UniGetUI geskep of gewysig is, sal geïgnoreer word. Jy sal dit via die {0}-knoppie kan byvoeg.", + "Are you really sure you want to enable this feature?": "Is jy regtig seker jy wil hierdie kenmerk aktiveer?", + "No new shortcuts were found during the scan.": "Geen nuwe kortpaaie is tydens die skandering gevind nie.", + "How to add packages to a bundle": "Hoe om pakkette by 'n bondel te voeg", + "In order to add packages to a bundle, you will need to: ": "Om pakkette by 'n bundel te voeg, moet jy:", + "1. Navigate to the \"{0}\" or \"{1}\" page.": "1. Navigeer na die bladsy '{0}' of '{1}'.", + "2. Locate the package(s) you want to add to the bundle, and select their leftmost checkbox.": "Soek die pakket(te) wat jy by die bundel wil voeg, en merk die linkerste blokkie daarvan.", + "3. When the packages you want to add to the bundle are selected, find and click the option \"{0}\" on the toolbar.": "3. As die pakkette wat jy by die bundel wil voeg, gekies word, vind en klik op die opsie '{0}' op die werkbalk.", + "4. Your packages will have been added to the bundle. You can continue adding packages, or export the bundle.": "4. Jou pakkette is bygevoeg tot die bundel. Jy kan voortgaan met die toevoeging van pakkette, of die uitvoer van die bundel.", + "Which backup do you want to open?": "Watter rugsteun wil jy oopmaak?", + "Select the backup you want to open. Later, you will be able to review which packages you want to install.": "Kies die rugsteun wat jy wil oopmaak. Later sal jy kan nagaan watter pakkette of programme jy wil herstel.", + "There are ongoing operations. Quitting UniGetUI may cause them to fail. Do you want to continue?": "Daar is deurlopende bedrywighede. As jy UniGetUI toemaak, kan dit misluk. Wil jy voortgaan?", + "UniGetUI or some of its components are missing or corrupt.": "UniGetUI of sommige van sy komponente ontbreek of is korrup.", + "It is strongly recommended to reinstall UniGetUI to adress the situation.": "Dit word sterk aanbeveel om UniGetUI weer te installeer om die situasie aan te spreek.", + "Refer to the UniGetUI Logs to get more details regarding the affected file(s)": "Verwys na die UniGetUI-logboeke vir meer besonderhede oor die betrokke lêer(s)", + "Integrity checks can be disabled from the Experimental Settings": "Integriteitskontroles kan vanuit die eksperimentele instellings gedeaktiveer word", + "Repair UniGetUI": "Herstel UniGetUI", + "Live output": "Regstreekse afvoer", + "This package bundle had some settings that are potentially dangerous, and may be ignored by default.": "Hierdie pakketbondel het sommige instellings gehad wat potensieel gevaarlik is en by verstek geïgnoreer kan word.", + "Entries that show in YELLOW will be IGNORED.": "Inskrywings wat in GEEL vertoon word, sal GEÏGNOREER word.", + "Entries that show in RED will be IMPORTED.": "Inskrywings wat in ROOI vertoon word, sal INGEVOER word.", + "You can change this behavior on UniGetUI security settings.": "Jy kan hierdie gedrag in UniGetUI-sekuriteitsinstellings verander.", + "Open UniGetUI security settings": "Open UniGetUI-sekuriteitsinstellings", + "Should you modify the security settings, you will need to open the bundle again for the changes to take effect.": "As jy die sekuriteitsinstellings verander, sal jy die bondel weer moet oopmaak voordat die veranderinge in werking tree.", + "Details of the report:": "Besonderhede van die verslag:", + "Are you sure you want to create a new package bundle? ": "Is jy seker jy wil 'n nuwe pakket bundel skep?", + "Any unsaved changes will be lost": "Enige ongestoorde veranderinge sal verlore gaan", + "Warning!": "Waarskuwing!", + "For security reasons, custom command-line arguments are disabled by default. Go to UniGetUI security settings to change this. ": "Om veiligheidsredes is pasgemaakte opdragreël-argumente by verstek gedeaktiveer. Gaan na UniGetUI-sekuriteitsinstellings om dit te verander.", + "Change default options": "Verander verstekopsies", + "Ignore future updates for this package": "Ignoreer toekomstige opdaterings vir hierdie pakket\n", + "For security reasons, pre-operation and post-operation scripts are disabled by default. Go to UniGetUI security settings to change this. ": "Om veiligheidsredes is voor- en na-bewerking-skripte by verstek gedeaktiveer. Gaan na UniGetUI-sekuriteitsinstellings om dit te verander.", + "You can define the commands that will be run before or after this package is installed, updated or uninstalled. They will be run on a command prompt, so CMD scripts will work here.": "Jy kan die opdragte definieer wat voor of ná die installering, opdatering of deïnstallering van hierdie pakket uitgevoer sal word. Hulle sal in 'n opdragprompt loop, so CMD-skripte sal hier werk.", + "Change this and unlock": "Verander dit en ontsluit", + "{0} Install options are currently locked because {0} follows the default install options.": "{0} se installeeropsies is tans gesluit omdat {0} die verstek-installeeropsies volg.", + "Unset or unknown": "Ongeset of onbekend", + "This package has no screenshots or is missing the icon? Contrbute to UniGetUI by adding the missing icons and screenshots to our open, public database.": "Hierdie pakket het geen skermkiekies nie of ontbreek die ikoon? Dra by tot UniGgetUI deur die ontbrekende ikone en skermkiekies by ons oop, openbare databasis te voeg.", + "Become a contributor": "Word 'n bydraer", + "Update to {0} available": "Opdatering tot {0} beskikbaar", + "Reinstall": "Herinstalleer", + "Installer not available": "Installeerder nie beskikbaar nie", + "Version:": "Weergawe:", + "UniGetUI Version {0}": "UniGetUI Weergawe {0}", + "Performing backup, please wait...": "Voer rugsteun uit, wag asseblief...", + "An error occurred while logging in: ": "'n Fout het voorgekom tydens aanmelding: ", + "Fetching available backups...": "Haal beskikbare rugsteune op...", + "Done!": "Klaar!", + "The cloud backup has been loaded successfully.": "Die wolkrugsteun is suksesvol gelaai.", + "An error occurred while loading a backup: ": "'n Fout het voorgekom tydens die laai van 'n rugsteun: ", + "Backing up packages to GitHub Gist...": "Rugsteun tans pakkette na GitHub Gist...", + "Backup Successful": "Rugsteun was suksesvol", + "The cloud backup completed successfully.": "Die wolkrugsteun is suksesvol voltooi.", + "Could not back up packages to GitHub Gist: ": "Kon nie pakkette na GitHub Gist rugsteun nie: ", + "It is not guaranteed that the provided credentials will be stored safely, so you may as well not use the credentials of your bank account": "Dit is nie gewaarborg dat die voorsiende bewyse veilig geberg sal word nie, en jy kan ook nie die bewyse van jou bankrekening gebruik nie", + "Enable the automatic WinGet troubleshooter": "Aktiveer die outomatiese WinGet probleem oplosser", + "Add updates that fail with a 'no applicable update found' to the ignored updates list": "Voeg opdaterings by wat misluk met 'geen toepaslike opdatering' by die lys wat geïgnoreer word nie.", + "Invalid selection": "Ongeldige keuse", + "No package was selected": "Geen pakket is gekies nie", + "More than 1 package was selected": "Meer as 1 pakket is gekies", + "List": "Lys", + "Grid": "ruitnet", + "Icons": "Ikone", + "\"{0}\" is a local package and does not have available details": "\"{0}\" is 'n plaaslike pakket en het nie beskikbare besonderhede nie", + "\"{0}\" is a local package and is not compatible with this feature": "\"{0}\" is \"n plaaslike pakket en is nie versoenbaar met hierdie funksie nie", + "Add packages to bundle": "Voeg pakkette by die bundel", + "Preparing packages, please wait...": "Berei pakkette voor, wag asseblief...", + "Loading packages, please wait...": "Laai pakkette, wag asseblief...", + "Saving packages, please wait...": "Stoor pakkette, wag asseblief ...", + "The bundle was created successfully on {0}": "Die bondel is suksesvol geskep op {0}", + "User profile": "Gebruikersprofiel", + "Error": "Fout", + "Log in failed: ": "Aanmelding het misluk: ", + "Log out failed: ": "Afmelding het misluk: ", + "Package backup settings": "Pakket-rugsteuninstellings", + "Manage UniGetUI autostart behaviour from the Settings app": "Bestuur UniGetUI se outostart-gedrag", + "Choose how many operations shoulds be performed in parallel": "Kies hoeveel bewerkings parallel uitgevoer moet word", + "Something went wrong while launching the updater.": "Iets het verkeerd geloop tydens die bekendstelling van die opdaterer.", + "Please try again later": "Probeer asseblief weer later", + "Show the release notes after UniGetUI is updated": "Wys die vrystelling notas nadat UniGetUI opgedateer is" +} diff --git a/src/Languages/lang_ar.json b/src/Languages/lang_ar.json new file mode 100644 index 0000000..5df41a6 --- /dev/null +++ b/src/Languages/lang_ar.json @@ -0,0 +1,850 @@ +{ + "{0} of {1} operations completed": "اكتملت {0} من {1} عملية", + "{0} is now {1}": "{0} أصبح الآن {1}", + "Enabled": "مفعّل", + "Disabled": "معطل", + "Privacy": "الخصوصية", + "Hide my username from the logs": "إخفاء اسم المستخدم الخاص بي من السجلات", + "Replaces your username with **** in the logs. Restart UniGetUI to also hide it from already-recorded entries.": "يستبدل اسم المستخدم الخاص بك بـ **** في السجلات. أعد تشغيل UniGetUI لإخفائه أيضًا من الإدخالات المسجلة مسبقًا.", + "Your last update attempt did not complete.": "لم تكتمل محاولة التحديث الأخيرة.", + "UniGetUI could not confirm whether the update succeeded. Open the log to see what happened.": "تعذّر على UniGetUI تأكيد ما إذا كان التحديث قد نجح. افتح السجل لمعرفة ما حدث.", + "View log": "عرض السجل", + "The installer reported success but did not restart UniGetUI.": "أفاد المثبّت بالنجاح، لكنه لم يُعد تشغيل UniGetUI.", + "The installer failed to initialize.": "فشل المثبّت في التهيئة.", + "Setup was canceled before installation began.": "تم إلغاء الإعداد قبل بدء التثبيت.", + "A fatal error occurred during the preparation phase.": "حدث خطأ فادح أثناء مرحلة التحضير.", + "A fatal error occurred during installation.": "حدث خطأ فادح أثناء التثبيت.", + "Installation was canceled while in progress.": "تم إلغاء التثبيت أثناء تقدمه.", + "The installer was terminated by another process.": "تم إنهاء المثبّت بواسطة عملية أخرى.", + "The preparation phase determined the installation cannot proceed.": "قررت مرحلة التحضير أنه لا يمكن متابعة التثبيت.", + "The installer could not start. UniGetUI may already be running, or you do not have permission to install.": "تعذّر بدء المثبّت. قد يكون UniGetUI قيد التشغيل بالفعل، أو قد لا تكون لديك صلاحية للتثبيت.", + "Unexpected installer error.": "خطأ غير متوقع في المثبّت.", + "We are checking for updates.": "نحن نتحقق من وجود تحديثات.", + "Please wait": "يرجى الإنتظار", + "Great! You are on the latest version.": "رائع! أنت تستخدم الإصدار الأحدث.", + "There are no new UniGetUI versions to be installed": "لا توجد إصدارات جديدة من UniGetUI ليتم تثبيتها\n", + "UniGetUI version {0} is being downloaded.": "جاري تنزيل إصدار UniGetUI {0}.", + "This may take a minute or two": "قد يستغرق هذا دقيقة أو دقيقتين", + "The installer authenticity could not be verified.": "لم يتم التحقق من صحة المثبت.", + "The update process has been aborted.": "لقد تم إلغاء عملية التحديث.", + "Auto-update is not yet available on this platform.": "التحديث التلقائي غير متاح بعد على هذا النظام الأساسي.", + "Please update UniGetUI manually.": "يرجى تحديث UniGetUI يدويًا.", + "An error occurred when checking for updates: ": "حدث خطأ عند البحث عن التحديثات:", + "The updater could not be launched.": "تعذّر تشغيل أداة التحديث.", + "The operating system did not start the installer process.": "لم يقم نظام التشغيل ببدء عملية المثبّت.", + "UniGetUI is being updated...": "جاري تحديث UniGetUI...", + "Update installed.": "تم تثبيت التحديث.", + "UniGetUI was updated successfully, but this running copy was not replaced. This usually means you are running a development build. Close this copy and start the newly-installed version to finish.": "تم تحديث UniGetUI بنجاح، لكن هذه النسخة قيد التشغيل لم يتم استبدالها. يعني هذا عادةً أنك تشغّل إصدار تطوير. أغلق هذه النسخة وابدأ الإصدار المثبّت حديثًا للإكمال.", + "The update could not be applied.": "تعذّر تطبيق التحديث.", + "Installer exit code {0}: {1}": "رمز خروج المثبّت {0}: {1}", + "Update cancelled.": "تم إلغاء التحديث.", + "Authentication was cancelled.": "تم إلغاء المصادقة.", + "Installer exit code {0}": "رمز خروج المثبّت {0}", + "Operation in progress": "العملية قيد التنفيذ", + "Please wait...": "الرجاء الانتظار...", + "Success!": "نجاح!", + "Failed": "فشل", + "An error occurred while processing this package": "حدث خطاُ وقت معالجة هذه الحزمة", + "Installer": "المثبّت", + "Executable": "ملف تنفيذي", + "MSI": "MSI", + "Compressed file": "ملف مضغوط", + "MSIX": "MSIX", + "WinGet was repaired successfully": "تم إصلاح WinGet بنجاح", + "It is recommended to restart UniGetUI after WinGet has been repaired": "يوصى بإعادة تشغيل UniGetUI بعد إصلاح WinGet", + "WinGet could not be repaired": "لم يتم إصلاح WinGet", + "An unexpected issue occurred while attempting to repair WinGet. Please try again later": "حدثت مشكلة غير متوقعة أثناء محاولة إصلاح WinGet. يرجى المحاولة مرة أخرى لاحقًا", + "Log in to enable cloud backup": "سجل الدخول لتفعيل النسخ الاحتياطي السحابي", + "Backup Failed": "فشل النسخ الاحتياطي", + "Downloading backup...": "تنزيل النسخة الإحتياطية...", + "An update was found!": "تم إيجاد تحديث!", + "{0} can be updated to version {1}": "يمكن تحديث {0} إلى الإصدار {1}", + "Updates found!": "تم العثور على تحديثات!", + "{0} packages can be updated": "يمكن تحديث {0} حزم", + "{0} is being updated to version {1}": "يتم تحديث {0} إلى الإصدار {1}", + "{0} packages are being updated": "يتم تحديث {0} حزمة", + "You have currently version {0} installed": "لقد قمت حاليًا بتثبيت الإصدار {0}", + "Desktop shortcut created": "تم إنشاء اختصار سطح المكتب", + "UniGetUI has detected a new desktop shortcut that can be deleted automatically.": "اكتشف UniGetUI اختصارًا جديدًا على سطح المكتب يمكن حذفه تلقائيًا.", + "{0} desktop shortcuts created": "تم إنشاء {0} اختصارا سطح المكتب", + "UniGetUI has detected {0} new desktop shortcuts that can be deleted automatically.": "اكتشف UniGetUI {0} اختصارات سطح مكتب جديدة يمكن حذفها تلقائيًا.", + "Attention required": "مطلوب الانتباه", + "Restart required": "إعادة التشغيل مطلوبة", + "1 update is available": "يوجد تحديث 1 متوفر", + "{0} updates are available": "التحديثات المتاحة: {0}", + "Everything is up to date": "كل شيءٍ مُحدّث", + "Discover Packages": "استكشف الحزم", + "Available Updates": "التحديثات المتاحة", + "Installed Packages": "الحزم المثبتة", + "UniGetUI Version {0} by Devolutions": "UniGetUI الإصدار {0} بواسطة Devolutions", + "Show UniGetUI": "إظهار UniGetUI", + "Quit": "خروج", + "Are you sure?": "هل أنت متأكد؟", + "Do you really want to uninstall {0}?": "هل تريد حقأ إلغاء تثبيت {0}؟", + "Do you really want to uninstall the following {0} packages?": "هل ترغب حقاً بإزالة تثبيت المصادر {0}؟ ", + "No": "لا", + "Yes": "نعم", + "Partial": "جزئي", + "View on UniGetUI": "اعرض على UniGetUI", + "Update": "تحديث", + "Open UniGetUI": "فتح UniGetUI", + "Update all": "تحديث الكل", + "Update now": "تحديث الآن", + "Installer host changed since the installed version.\n": "تغيّر مضيف المثبّت منذ الإصدار المثبّت.\n", + "This package is on the queue": "هذه الحزمة موجودة في قائمة الانتظار", + "installing": "يتم التثبيت", + "updating": "يتم تحديث", + "uninstalling": "يتم إلغاء تثبيت", + "installed": "تم التثبيت", + "Retry": "إعادة المحاولة", + "Install": "تثبيت", + "Uninstall": "إلغاء التثبيت", + "Open": "فتح", + "Operation profile:": "ملف تعريف العملية:", + "Follow the default options when installing, upgrading or uninstalling this package": "اتّباع الخيارات الافتراضية عند تثبيت هذه الحزمة أو ترقيتها أو إلغاء تثبيتها", + "The following settings will be applied each time this package is installed, updated or removed.": "سيتم تطبيق الإعدادات التالية في كل مرة يتم فيها تثبيت هذه الحزمة أو تحديثها أو إزالتها.", + "Version to install:": "الإصدار للتثبيت", + "Architecture to install:": "المعمارية للتثبيت:", + "Installation scope:": "التثبيت scope:", + "Install location:": "مكان التثبيت:", + "Select": "تحديد", + "Reset": "إعادة ضبط", + "Custom install arguments:": "وسائط التثبيت المخصصة:", + "Custom update arguments:": "وسائط التحديث المخصصة:", + "Custom uninstall arguments:": "وسائط إلغاء التثبيت المخصصة:", + "Pre-install command:": "أمر ما قبل التثبيت:", + "Post-install command:": "أمر ما بعد التثبيت:", + "Abort install if pre-install command fails": "إلغاء التثبيت إذا فشل أمر التثبيت المسبق", + "Pre-update command:": "أمر ما قبل التحديث:", + "Post-update command:": "أمر ما بعد التحديث:", + "Abort update if pre-update command fails": "إلغاء التحديث إذا فشل أمر ما قبل التحديث", + "Pre-uninstall command:": "أمر ما قبل إلغاء التثبيت:", + "Post-uninstall command:": "أمر ما بعد إلغاء التثبيت:", + "Abort uninstall if pre-uninstall command fails": "إلغاء أزالة التثبيت إذا فشل أمر ما قبل الإزالة", + "Command-line to run:": "سطر الأوامر للتشغيل:", + "Save and close": "حفظ وإغلاق", + "General": "عام", + "Architecture & Location": "البنية والموقع", + "Command-line": "سطر الأوامر", + "Close apps": "إغلاق التطبيقات", + "Pre/Post install": "ما قبل/ما بعد التثبيت", + "Select the processes that should be closed before this package is installed, updated or uninstalled.": "حدد العمليات التي يجب إغلاقها قبل تثبيت هذه الحزمة أو تحديثها أو إلغاء تثبيتها.", + "Write here the process names here, separated by commas (,)": "اكتب هنا أسماء العمليات، مفصولة بفواصل (,)", + "Try to kill the processes that refuse to close when requested to": "حاول إنهاء العمليات التي ترفض الإغلاق عند طلب ذلك", + "Run as admin": "تشغيل كمسؤول", + "Interactive installation": "تثبيت تفاعلي", + "Skip hash check": "تخطي تحقق hash", + "Uninstall previous versions when updated": "إلغاء تثبيت الإصدارات السابقة عند التحديث", + "Skip minor updates for this package": "تخطي التحديثات البسيطة لهذه الحزمة", + "Automatically update this package": "تحديث هذه الحزمة تلقائيًا", + "{0} installation options": "{0} خيارات التثبيت", + "Latest": "الأخير", + "PreRelease": "إصدار مبدأي", + "Default": "افتراضي", + "Manage ignored updates": "إدارة التحديثات المتجاهلة", + "The packages listed here won't be taken in account when checking for updates. Double-click them or click the button on their right to stop ignoring their updates.": "لن يتم أخذ الحزم المدرجة هنا في الاعتبار عند التحقق من وجود تحديثات. انقر نقرًا مزدوجًا فوقهم أو انقر فوق الزر الموجود على يمينهم للتوقف عن تجاهل تحديثاتهم.", + "Reset list": "إعادة تعيين القائمة", + "Do you really want to reset the ignored updates list? This action cannot be reverted": "هل تريد حقًا إعادة تعيين قائمة التحديثات المتجاهلة؟ لا يمكن التراجع عن هذا الإجراء.", + "No ignored updates": "لا توجد تحديثات متجاهلة", + "Package Name": "اسم الحزمة", + "Package ID": "معرف الحزمة", + "Ignored version": "الإصدار المتجاهل", + "New version": "الإصدار الجديد", + "Source": "المصدر", + "All versions": "كل الإصدارات", + "Unknown": "غير معروف", + "Up to date": "محدثة", + "Package {name} from {manager}": "الحزمة {name} من {manager}", + "Remove {0} from ignored updates": "إزالة {0} من التحديثات المتجاهلة", + "Cancel": "إلغاء", + "Administrator privileges": "صلاحيات المسؤول", + "This operation is running with administrator privileges.": "هذه العملية تعمل بصلاحيات المسؤول", + "Interactive operation": "عملية تفاعلية", + "This operation is running interactively.": "هذه العملية تعمل بشكل تفاعلي.", + "You will likely need to interact with the installer.": "ستحتاج غالباً إلى التفاعل مع المثبت.", + "Integrity checks skipped": "عمليات التحقق من السلامة تم تخطيها", + "Integrity checks will not be performed during this operation.": "لن يتم إجراء عمليات التحقق من السلامة أثناء هذه العملية.", + "Proceed at your own risk.": "التباعة على مسؤوليتك الخاصة.", + "Close": "إغلاق", + "Loading...": "يتم التحميل...", + "Installer SHA256": "SHA256 للمثبت", + "Homepage": "الصفحة الرئيسية", + "Author": "المؤلف", + "Publisher": "الناشر", + "License": "الترخيص", + "Manifest": "القائمة الأساسية", + "Installer Type": "نوع المثبت", + "Size": "الحجم", + "Installer URL": "رابط المثبت", + "Last updated:": "تم التحديث آخر مرة:", + "Release notes URL": "ملاحظات الإصدار URL", + "Package details": "تفاصيل الحزمة", + "Dependencies:": "الاعتماديات:", + "Release notes": "ملاحظات الإصدار", + "Screenshots": "لقطات الشاشة", + "This package has no screenshots or is missing the icon? Contribute to UniGetUI by adding the missing icons and screenshots to our open, public database.": "لا تحتوي هذه الحزمة على لقطات شاشة أو تنقصها الأيقونة؟ ساهم في UniGetUI بإضافة الأيقونات ولقطات الشاشة المفقودة إلى قاعدة بياناتنا المفتوحة والعامة.", + "Version": "الإصدار", + "Install as administrator": "تثبيت كمسؤول", + "Update to version {0}": "التحديث إلى الإصدار {0}", + "Installed Version": "الإصدار المثبت", + "Update as administrator": "تحديث كمسؤول", + "Interactive update": "تحديث تفاعلي", + "Uninstall as administrator": "إلغاء التثبيت كمسؤول", + "Interactive uninstall": "إلغاء تثبيت تفاعلي", + "Uninstall and remove data": "إلغاء التثبيت وإزالة البيانات", + "Not available": "غير متاح", + "Installer SHA512": "SHA512 للمثبت:", + "Unknown size": "حجم غير معروف", + "No dependencies specified": "لم يتم تحديد أي اعتماديات", + "mandatory": "إلزامي", + "optional": "خياري", + "UniGetUI {0} is ready to be installed.": "UniGetUI {0} جاهز للتثبيت.", + "The update process will start after closing UniGetUI": "ستبدأ عملية التحديث بعد إغلاق UniGetUI", + "UniGetUI has been ran as administrator, which is not recommended. When running UniGetUI as administrator, EVERY operation launched from UniGetUI will have administrator privileges. You can still use the program, but we highly recommend not running UniGetUI with administrator privileges.": "تم تشغيل UniGetUI كمسؤول، وهذا غير مستحسن. عند تشغيل UniGetUI كمسؤول، ستحصل كل عملية يتم تشغيلها من UniGetUI على صلاحيات المسؤول. لا يزال بإمكانك استخدام البرنامج، لكننا نوصي بشدة بعدم تشغيل UniGetUI بصلاحيات المسؤول.", + "Share anonymous usage data": "مشاركة بيانات استخدام مجهولة المصدر", + "UniGetUI collects anonymous usage data in order to improve the user experience.": "يقوم UniGetUI بجمع بيانات الاستخدام مجهولة المصدر لتطوير تجربة المستخدم.", + "Accept": "قبول", + "Software Updates": "تحديثات البرامج", + "Package Bundles": "حزم الحزم", + "Settings": "الإعدادات", + "Package Managers": "مدراء الحزم", + "UniGetUI Log": "سجل UniGetUI", + "Package Manager logs": "سجلات نظام إدارة الحزم", + "Operation history": "سجل العمليات", + "Help": "مساعدة", + "UniGetUI": "UniGetUI", + "You have installed UniGetUI Version {0}": "لقد قمت بتثبيت UniGetUI الإصدار {0}", + "Disclaimer": "تنصل (للتوضيح)", + "UniGetUI is developed by Devolutions and is not affiliated with any of the compatible package managers.": "تم تطوير UniGetUI بواسطة Devolutions، وهو غير تابع لأي من مديري الحزم المتوافقين.", + "UniGetUI wouldn't have been possible without the help of the contributors. Thank you all 🥳": "لم يكن من الممكن إنشاء UniGetUI بدون مساعدة المساهمين. شكرًا لكم جميعًا 🥳", + "UniGetUI uses the following libraries. Without them, UniGetUI wouldn't have been possible.": "يستخدم UniGetUI المكتبات التالية. بدونها، لم يكن UniGetUI ممكنًا.", + "{0} homepage": "{0} الصفحة الرئيسية", + "UniGetUI has been translated to more than 40 languages thanks to the volunteer translators. Thank you 🤝": "لقد تمت ترجمة UniGetUI إلى أكثر من 40 لغة بفضل المترجمين المتطوعين. شكرًا لكم 🤝", + "Verbose": "مطوّل", + "1 - Errors": "1- أخطاء", + "2 - Warnings": "2- تحذيرات", + "3 - Information (less)": "3- معلومات (أقل)", + "4 - Information (more)": "4- معلومات (أكثر)", + "5 - information (debug)": "5- معلومات (للمعالجة)", + "Warning": "تحذير", + "The following settings may pose a security risk, hence they are disabled by default.": "قد تشكّل الإعدادات التالية خطرًا أمنيًا، ولذلك تكون معطّلة افتراضيًا.", + "Enable the settings below if and only if you fully understand what they do, and the implications they may have.": "قم بتمكين الإعدادات أدناه فقط إذا كنت تفهم تمامًا ما تفعله والآثار المترتبة عليها.", + "The settings will list, in their descriptions, the potential security issues they may have.": "ستسرد الإعدادات، في أوصافها، المشكلات الأمنية المحتملة التي قد تنطوي عليها.", + "The backup will include the complete list of the installed packages and their installation options. Ignored updates and skipped versions will also be saved.": "لن تتضمن النسخة الاحتياطية أي ملف مصدري أو أي بيانات محفوظة بواسطة برامج.", + "The backup will NOT include any binary file nor any program's saved data.": "لن تتضمن النسخة الاحتياطية أي ملف ثنائي أو أي بيانات محفوظة بواسطة برامج.", + "The size of the backup is estimated to be less than 1MB.": "حجم النسخ الإحتياطي مُقدّر بأن يكون أقل من 1 ميغابايت.", + "The backup will be performed after login.": "سيتم إجراء النسخ الاحتياطي بعد تسجيل الدخول.", + "{pcName} installed packages": "الحزم المثبتة بواسطة {pcName}", + "Current status: Not logged in": "الحالة الحالية: لم يتم تسجيل الدخول", + "You are logged in as {0} (@{1})": "أنت مسجل الدخول باسم {0} (@{1})", + "Nice! Backups will be uploaded to a private gist on your account": "رائع! سيتم رفع النسخ الاحتياطية إلى gist خاص في حسابك", + "Select backup": "حدد نسخة احتياطية", + "Settings imported from {0}": "تم استيراد الإعدادات من {0}", + "UniGetUI Settings": "إعدادات UniGetUI", + "Settings exported to {0}": "تم تصدير الإعدادات إلى {0}", + "UniGetUI settings were reset": "تمت إعادة تعيين إعدادات UniGetUI", + "Allow pre-release versions": "السماح بنسخ ماقبل الاصدار", + "Apply": "تطبيق", + "For security reasons, custom command-line arguments are disabled by default. Go to UniGetUI security settings to change this.": "لأسباب أمنية، تكون وسائط سطر الأوامر المخصصة معطلة افتراضيًا. انتقل إلى إعدادات أمان UniGetUI لتغيير ذلك.", + "Go to UniGetUI security settings": "الانتقال إلى إعدادات أمان UniGetUI", + "The following options will be applied by default each time a {0} package is installed, upgraded or uninstalled.": "سيتم تطبيق الخيارات التالية افتراضيًا في كل مرة يتم فيها تثبيت حزمة {0} أو ترقيتها أو إلغاء تثبيتها.", + "Package's default": "الافتراضي للحزمة", + "Install location can't be changed for {0} packages": "لا يمكن تغيير موقع التثبيت لحزم {0}", + "The local icon cache currently takes {0} MB": "تبلغ مساحة ذاكرة التخزين المؤقتة للرمز المحلي حاليًا {0} ميجا بايت", + "Username": "اسم المستخدم", + "Password": "كلمة المرور", + "Credentials": "بيانات الاعتماد", + "It is not guaranteed that the provided credentials will be stored safely": "ليس مضمونًا أن يتم تخزين بيانات الاعتماد المقدمة بأمان", + "Partially": "جزئياً", + "Package manager": "مدير الحزم", + "Compatible with proxy": "متوافق مع الوكيل", + "Compatible with authentication": "متوافق مع المصادقة", + "Proxy compatibility table": "جدول توافق الوكيل", + "{0} settings": "إعدادات {0}", + "{0} status": "حالة {0}", + "Default installation options for {0} packages": "خيارات التثبيت الافتراضية لحزم {0}", + "Expand version": "الإصدار الكامل", + "The executable file for {0} was not found": "الملف القابل للتنفيذ لـ {0} لم يتم إيجاده", + "{pm} is disabled": "تم تعطيل {pm}", + "Enable it to install packages from {pm}.": "قم بتفعيله لتثبيت الحزم من {pm}.", + "{pm} is enabled and ready to go": "تم تمكين {pm} وهو جاهز للاستخدام", + "{pm} version:": "إصدار {pm}:", + "{pm} was not found!": "لم يتم العثور على {pm}!", + "You may need to install {pm} in order to use it with UniGetUI.": "قد تحتاج إلى تثبيت {pm} حتى تتمكن من استخدامه مع UniGetUI.", + "Scoop Installer - UniGetUI": "UniGetUI - مثبت Scoop", + "Scoop Uninstaller - UniGetUI": "UniGetUI - إلغاء تثبيت Scoop", + "Clearing Scoop cache - UniGetUI": "مسح ذاكرة التخزين المؤقت Scoop لـ UniGetUI", + "Restart UniGetUI to fully apply changes": "أعد تشغيل UniGetUI لتطبيق التغييرات بالكامل", + "Restart UniGetUI": "أعد تشغيل UniGetUI", + "Manage {0} sources": "إدارة {0} من المصادر", + "Add source": "إضافة مصدر", + "Add": "إضافة", + "Source name": "اسم المصدر", + "Source URL": "عنوان URL للمصدر", + "Other": "أخرى", + "No minimum age": "بدون عمر أدنى", + "1 day": "يوم 1", + "{0} days": "{0} أيام", + "Custom...": "مخصص...", + "{0} minutes": "{0} دقائق", + "1 hour": "ساعة واحدة", + "{0} hours": "{0} ساعات", + "1 week": "أسبوع واحد", + "Supports release dates": "يدعم تواريخ الإصدار", + "Release date support per package manager": "دعم تاريخ الإصدار لكل مدير حزم", + "Search for packages": "البحث عن حزم", + "Local": "محلي", + "OK": "حسنًا", + "Last checked: {0}": "آخر فحص: {0}", + "{0} packages were found, {1} of which match the specified filters.": "تم العثور على {0} حزمة، {1} منها تطابق الفلاتر المحددة.", + "{0} selected": " {0}محدد", + "(Last checked: {0})": "(أخر تحقق: {0}) ", + "All packages selected": "تم تحديد جميع الحزم", + "Package selection cleared": "تم مسح تحديد الحزم", + "{0}: {1}": "{0}: {1}", + "More info": "معلومات أكثر", + "GitHub account": "حساب GitHub", + "Log in with GitHub to enable cloud package backup.": "سجّل الدخول باستخدام GitHub لتمكين النسخ الاحتياطي السحابي للحزم.", + "More details": "تفاصيل أكثر", + "Log in": "تسجيل الدخول", + "If you have cloud backup enabled, it will be saved as a GitHub Gist on this account": "إذا كان النسخ الاحتياطي السحابي مفعّلًا، فسيتم حفظه كـ GitHub Gist على هذا الحساب", + "Log out": "تسجيل الخروج", + "About UniGetUI": "حول UniGetUI", + "About": "عنا", + "Third-party licenses": "تراخيص الطرف الثالث", + "Contributors": "المساهمون", + "Translators": "المترجمون", + "Bundle security report": "رزمة تقرير الأمان", + "The bundle contained restricted content": "تحتوي الحزمة على محتوى مقيّد", + "UniGetUI – Crash Report": "UniGetUI – تقرير الأعطال", + "UniGetUI has crashed": "تعطّل UniGetUI", + "Help us fix this by sending a crash report to Devolutions. All fields below are optional.": "ساعدنا في إصلاح هذه المشكلة بإرسال تقرير أعطال إلى Devolutions. جميع الحقول أدناه اختيارية.", + "Email (optional)": "البريد الإلكتروني (اختياري)", + "your@email.com": "your@email.com", + "Additional details (optional)": "تفاصيل إضافية (اختياري)", + "Describe what you were doing when the crash occurred…": "صف ما كنت تفعله عند حدوث العطل…", + "Crash report": "تقرير الأعطال", + "Don't Send": "عدم الإرسال", + "Send Report": "إرسال التقرير", + "Sending…": "جارٍ الإرسال…", + "Unsaved changes": "تغييرات غير محفوظة", + "You have unsaved changes in the current bundle. Do you want to discard them?": "لديك تغييرات غير محفوظة في الحزمة الحالية. هل تريد تجاهلها؟", + "Discard changes": "تجاهل التغييرات", + "Integrity violation": "انتهاك السلامة", + "UniGetUI or some of its components are missing or corrupt. It is strongly recommended to reinstall UniGetUI to adress the situation.": "UniGetUI أو بعض مكوّناته مفقودة أو تالفة. يُوصى بشدة بإعادة تثبيت UniGetUI لمعالجة هذا الأمر.", + "• Refer to the UniGetUI Logs to get more details regarding the affected file(s)": "• ارجع إلى سجلات UniGetUI للحصول على مزيد من التفاصيل حول الملف أو الملفات المتأثرة", + "• Integrity checks can be disabled from the Experimental Settings": "• يمكن تعطيل عمليات التحقق من السلامة من الإعدادات التجريبية", + "Manage shortcuts": "إدارة الاختصارات", + "UniGetUI has detected the following desktop shortcuts which can be removed automatically on future upgrades": "اكتشف UniGetUI اختصارات سطح المكتب التالية والتي يمكن إزالتها تلقائيًا في الترقيات المستقبلية", + "Do you really want to reset this list? This action cannot be reverted.": "هل ترغب فعلاً بإعادة تعيين هذه القائمة؟ هذا الإجراء لا يمكن التراجع عنه.", + "Desktop shortcuts list": "قائمة اختصارات سطح المكتب", + "Open in explorer": "فتح في المستكشف", + "Remove from list": "إزالة من القائمة", + "When new shortcuts are detected, delete them automatically instead of showing this dialog.": "إذا اكتُشِفت اختصارات جديدة، أزلهم تلقائيا بدلا من عرض هذه النافذة", + "Not right now": "ليس الان", + "Missing dependency": "الاعتمادات مفقود", + "UniGetUI requires {0} to operate, but it was not found on your system.": "يتطلب UniGetUI {0} للعمل، ولكن لم يتم العثور عليه على نظامك.", + "Click on Install to begin the installation process. If you skip the installation, UniGetUI may not work as expected.": "انقر فوق \"تثبيت\" لبدء عملية التثبيت. إذا تخطيت عملية التثبيت، فقد لا يعمل UniGetUI بالشكل المتوقع.", + "Alternatively, you can also install {0} by running the following command in a Windows PowerShell prompt:": "بدلا من ذلك، يمكنك تثبيت {0} عن طريق لصق هذا اﻷمر في نافذة powershell", + "Install {0}": "تثبيت {0}", + "Do not show this dialog again for {0}": "لا تعرض مربع الحوار هذا مرة أخرى {0}", + "Please wait while {0} is being installed. A black window may show up. Please wait until it closes.": "يرجى الانتظار أثناء تثبيت {0}. قد تظهر نافذة سوداء. يرجى الانتظار حتى يتم إغلاقها.", + "{0} has been installed successfully.": "تم تثبيت {0} بنجاح.", + "Please click on \"Continue\" to continue": "الرجاء الضغط على \"متابعة\" للمتابعة", + "Continue": "أكمل", + "{0} has been installed successfully. It is recommended to restart UniGetUI to finish the installation": "تم تثبيت {0} بنجاح. يوصى بإعادة تشغيل UniGetUI لإكمال التثبيت", + "Restart later": "إعادة التشغيل لاحقاً", + "An error occurred:": "حدث خطأ:", + "Please see the Command-line Output or refer to the Operation History for further information about the issue.": "يرجى الاطلاع على مخرجات سطر الأوامر أو الرجوع إلى سجل العمليات للحصول على مزيد من المعلومات حول المشكلة.", + "Retry as administrator": "المحاولة كمسؤول", + "Retry interactively": "المحاولة تفاعلياً", + "Retry skipping integrity checks": "إعادة محاولة عمليات التحقق من السلامة التي تم تخطيها", + "Installation options": "خيارات التثبيت", + "Save": "حفظ", + "UniGetUI collects anonymous usage data with the sole purpose of understanding and improving the user experience.": "يقوم UniGetUI بجمع بيانات استخدام مجهولة المصدر لغاية وحيدة وهي فهم وتطوير تجربة المستخدم.", + "More details about the shared data and how it will be processed": "المزيد من التفاصيل عن البيانات التم يتم مشاركتها وكيف سيتم معالجتها", + "Do you accept that UniGetUI collects and sends anonymous usage statistics, with the sole purpose of understanding and improving the user experience?": "هل تقبل أن يقوم UniGetUI بجمع وإرسال إحصائيات استخدام مجهولة الهوية، من أجل فهم وتحسين تجربة المتسخدم فقط؟", + "Decline": "رفض", + "No personal information is collected nor sent, and the collected data is anonimized, so it can't be back-tracked to you.": "لن يتم جمع أو إرسال أية معلومات شخصية، والبيانات التي يتم جمعها ستكون مجهولة المصدر، لذا لا يمكن تتبعها رجوعاً إليك.", + "Navigation panel": "لوحة التنقل", + "Operations": "العمليات", + "Toggle operations panel": "تبديل لوحة العمليات", + "Bulk operations": "عمليات مجمّعة", + "Retry failed": "إعادة محاولة العمليات الفاشلة", + "Clear successful": "مسح العمليات الناجحة", + "Clear finished": "مسح العمليات المنتهية", + "Cancel all": "إلغاء الكل", + "More": "أكثر", + "Toggle navigation panel": "تبديل لوحة التنقل", + "Minimize": "تصغير", + "Maximize": "تكبير", + "UniGetUI by Devolutions": "UniGetUI بواسطة Devolutions", + "UniGetUI is an application that makes managing your software easier, by providing an all-in-one graphical interface for your command-line package managers.": "UniGetUI هو تطبيق يجعل إدارة البرامج الخاصة بك أسهل، من خلال توفير واجهة رسومية شاملة لمديري حزم سطر الأوامر لديك.", + "Useful links": "روابط مفيدة", + "UniGetUI Homepage": "الصفحة الرئيسية لـ UniGetUI", + "Report an issue or submit a feature request": "الإبلاغ عن مشكلة أو تقديم طلب ميزة", + "UniGetUI Repository": "مستودع UniGetUI", + "View GitHub Profile": "عرض ملف GitHub الشخصي ", + "UniGetUI License": "ترخيص UniGetUI", + "Using UniGetUI implies the acceptation of the MIT License": "إن استخدام UniGetUI يعني قبول ترخيص MIT", + "Become a translator": "كن مُترجِماً", + "Go back": "الرجوع للخلف", + "Go forward": "التقدم للأمام", + "Go to home page": "الانتقال إلى الصفحة الرئيسية", + "Reload page": "إعادة تحميل الصفحة", + "View page on browser": "أعرض الصفحة في المتصفح", + "The built-in browser is not supported on Linux yet.": "المتصفح المضمّن غير مدعوم على Linux بعد.", + "Open in browser": "فتح في المتصفح", + "Copy to clipboard": "نسخ إلى الحافظة", + "Export to a file": "تصدير إلى ملف", + "Log level:": "مستوى السجل:", + "Reload log": "إعادة تحميل السجل", + "Export log": "تصدير السجل", + "Text": "نص", + "Change how operations request administrator rights": "تغيير كيفية طلب العمليات لحقوق المسؤول", + "Restrictions on package operations": "قيود على عمليات الحزم", + "Restrictions on package managers": "قيود على مديري الحزم", + "Restrictions when importing package bundles": "قيود عند استيراد باقات الحزم", + "Ask for administrator privileges once for each batch of operations": "اطلب صلاحيات المسؤول مرة واحدة لكل دفعة من العمليات", + "Ask only once for administrator privileges": "السؤال مرة واحد لامتيازات المسؤول", + "Prohibit any kind of Elevation via UniGetUI Elevator or GSudo": "منع أي نوع من الرفع عبر UniGetUI Elevator أو GSudo", + "This option WILL cause issues. Any operation incapable of elevating itself WILL FAIL. Install/update/uninstall as administrator will NOT WORK.": "سيؤدي هذا الخيار بالتأكيد إلى حدوث مشاكل. أي عملية غير قادرة على رفع صلاحياتها بنفسها ستفشل. لن يعمل التثبيت أو التحديث أو إلغاء التثبيت كمسؤول.", + "Allow custom command-line arguments": "السماح بمعاملات سطر الأوامر المخصصة", + "Custom command-line arguments can change the way in which programs are installed, upgraded or uninstalled, in a way UniGetUI cannot control. Using custom command-lines can break packages. Proceed with caution.": "يمكن أن تغيّر وسائط سطر الأوامر المخصصة الطريقة التي يتم بها تثبيت البرامج أو ترقيتها أو إلغاء تثبيتها بطريقة لا يستطيع UniGetUI التحكم بها. قد يؤدي استخدام أسطر أوامر مخصصة إلى إفساد الحزم. تابع بحذر.", + "Ignore custom pre-install and post-install commands when importing packages from a bundle": "السماح بتشغيل أوامر ما قبل التثبيت وما بعده المخصصة", + "Pre and post install commands will be run before and after a package gets installed, upgraded or uninstalled. Be aware that they may break things unless used carefully": "سيتم تشغيل أوامر ما قبل التثبيت وما بعده قبل وبعد تثبيت الحزمة أو ترقيتها أو إلغاء تثبيتها. انتبه إلى أنها قد تتسبب في مشاكل ما لم تُستخدم بحذر", + "Allow changing the paths for package manager executables": "السماح بتغيير المسارات لملفات مدير الحزم التنفيذية", + "Turning this on enables changing the executable file used to interact with package managers. While this allows finer-grained customization of your install processes, it may also be dangerous": "يؤدي تشغيل هذا الخيار إلى تمكين تغيير الملف التنفيذي المستخدم للتعامل مع مديري الحزم. وبينما يتيح هذا تخصيصًا أدق لعمليات التثبيت، فقد يكون خطيرًا أيضًا", + "Allow importing custom command-line arguments when importing packages from a bundle": "السماح باستيراد معاملات سطر الأوامر المخصصة عند استيراد الحزم من رزمة", + "Malformed command-line arguments can break packages, or even allow a malicious actor to gain privileged execution. Therefore, importing custom command-line arguments is disabled by default": "يمكن أن تؤدي وسائط سطر الأوامر غير الصالحة إلى إفساد الحزم، أو حتى السماح لجهة خبيثة بالحصول على تنفيذ بامتيازات مرتفعة. لذلك، يكون استيراد وسائط سطر الأوامر المخصصة معطّلًا افتراضيًا.", + "Allow importing custom pre-install and post-install commands when importing packages from a bundle": "السماح باستيراد أوامر ما قبل التثبيت وما بعده المخصصة عند استيراد الحزم من باقة", + "Pre and post install commands can do very nasty things to your device, if designed to do so. It can be very dangerous to import the commands from a bundle, unless you trust the source of that package bundle": "يمكن لأوامر ما قبل التثبيت وما بعده أن تفعل أشياء سيئة جدًا بجهازك إذا صُممت لذلك. قد يكون استيراد هذه الأوامر من باقة أمرًا خطيرًا جدًا ما لم تكن تثق بمصدر باقة الحزمة تلك", + "Administrator rights and other dangerous settings": "صلاحيات المسؤول وإعدادت خطيرة أخرى", + "Package backup": "النسخة الاحتياطية للحزمة", + "Cloud package backup": "النسخ الاحتياطي السحابي للحزم", + "Local package backup": "النسخ الاحتياطي المحلي للحزم", + "Local backup advanced options": "خيارات متطورة للنسخ الاحتياطية", + "Log in with GitHub": "تسجيل الدخول عن طريق GitHub", + "Log out from GitHub": "تسجيل الخروج عن طريق GitHub", + "Periodically perform a cloud backup of the installed packages": "إجراء نسخ احتياطي سحابي للحزم المثبتة بشكل دوري", + "Cloud backup uses a private GitHub Gist to store a list of installed packages": "تستخدم النسخة الاحتياطية السحابية Gist خاصًا على GitHub لتخزين قائمة الحزم المثبتة", + "Perform a cloud backup now": "إجراء نسخ احتياطي سحابي الآن", + "Backup": "النسخ الإحتياطي", + "Restore a backup from the cloud": "استعادة نسخة احتياطية من السحابة", + "Begin the process to select a cloud backup and review which packages to restore": "بدء عملية اختيار نسخ احتياطي سحابي واختيار أي الحزم سيتم استعادتها", + "Periodically perform a local backup of the installed packages": "إجراء نسخ احتياطي محلي للحزم المثبتة بشكل دوري", + "Perform a local backup now": "إجراء نسخ احتياطي محلي الآن", + "Change backup output directory": "تغيير موقع ملفات النسخ الاحتياطي", + "Set a custom backup file name": "تعيين اسم ملف النسخ الاحتياطي المخصص", + "Leave empty for default": "اتركه فارغًا للإفتراضي", + "Add a timestamp to the backup file names": "إضافة ختم زمني إلى أسماء ملفات النسخ الاحتياطي", + "Backup and Restore": "النسخ الاحتياطي والاستعادة", + "Enable background api (UniGetUI Widgets and Sharing, port 7058)": "تمكين واجهة برمجة التطبيقات الخلفية (أدوات UniGetUI والمشاركة، المنفذ 7058)", + "Wait for the device to be connected to the internet before attempting to do tasks that require internet connectivity.": "انتظار اتصال الجهاز بالانترنت قبل محاولة عمل المهام التي تتطلب اتصالاً بالشبكة.", + "Disable the 1-minute timeout for package-related operations": "تعطيل مهلة الدقيقة الواحدة للعمليات المتعلقة بالحزمة", + "Use installed GSudo instead of UniGetUI Elevator": "استخدم GSudo المثبّت بدلًا من UniGetUI Elevator", + "Use a custom icon and screenshot database URL": "استخدام رابط مخصص لقاعدة بيانات الأيقونات ولقطات الشاشة", + "Enable background CPU Usage optimizations (see Pull Request #3278)": "تفعيل تحسينات استخدام وحدة المعالجة المركزية في الخلفية (انظر الطلب #3278)", + "Perform integrity checks at startup": "إجراء عمليات التحقق من السلامة عند بدء التشغيل", + "When batch installing packages from a bundle, install also packages that are already installed": "عند تثبيت الحزم من باقة دفعةً واحدة، ثبّت أيضًا الحزم المثبتة بالفعل", + "Experimental settings and developer options": "إعدادات تجريبية و خيارات المطور", + "Show UniGetUI's version and build number on the titlebar.": "إظهار نسخة UniGetUI على شرط العنوان", + "Language": "اللغة", + "UniGetUI updater": "محدّث UniGetUI", + "Telemetry": "القياس عن بُعد", + "Manage UniGetUI settings": "إدارة إعدادات UniGetUI", + "Related settings": "إعدادات مرتبطة", + "Update UniGetUI automatically": "تحديث UniGetUI تلقائياً", + "Check for updates": "التحقق من التحديثات", + "Install prerelease versions of UniGetUI": "تثبيت الإصدارات التجريبية من UniGetUI", + "Manage telemetry settings": "إدارة إعدادات القياس عن بعد", + "Manage": "أدِر", + "Import settings from a local file": "إستيراد الإعدادات من ملف محلي", + "Import": "إستيراد", + "Export settings to a local file": "تصدير الإعدادات إلى ملف محلي", + "Export": "تصدير", + "Reset UniGetUI": "إعادة تعيين UniGetUI", + "User interface preferences": "تفضيلات واجهة المستخدم", + "Application theme, startup page, package icons, clear successful installs automatically": "سمة التطبيق، صفحة بدء التشغيل، أيقونات الحزمة، مسح التثبيتات الناجحة تلقائيًا", + "General preferences": "التفضيلات العامة", + "UniGetUI display language:": "لغة عرض UniGetUI:", + "System language": "لغة النظام", + "Is your language missing or incomplete?": "هل لغتك مفقودة أم غير مكتملة؟", + "Appearance": "المظهر", + "UniGetUI on the background and system tray": "UniGetUI في الخلفية وشريط المهام", + "Package lists": "قوائم الحزمة", + "Use classic mode": "استخدام الوضع الكلاسيكي", + "Restart UniGetUI to apply this change": "أعد تشغيل UniGetUI لتطبيق هذا التغيير", + "The classic UI is disabled for beta testers": "واجهة المستخدم الكلاسيكية معطّلة لمختبري الإصدارات التجريبية", + "Close UniGetUI to the system tray": "إغلاق UniGetUI إلى شريط المهام", + "Manage UniGetUI autostart behaviour": "إدارة سلوك بدء UniGetUI تلقائيًا", + "Show package icons on package lists": "إظهار أيقونات الحزمة في قوائم الحزمة", + "Clear cache": "مسح ذاكرة التخزين المؤقت", + "Select upgradable packages by default": "حدد الحزم التي سيتم ترقيتها بشكل افتراضي", + "Light": "فاتح", + "Dark": "داكن", + "Follow system color scheme": "اتباع نمط ألوان النظام", + "Application theme:": "مظهر التطبيق:", + "UniGetUI startup page:": "صفحة بدء تشغيل UniGetUI:", + "Proxy settings": "إعدادات الوكيل", + "Other settings": "إعدادات أخرى", + "Connect the internet using a custom proxy": "الاتصال بشبكة الانترنت باستخدام وكيل مخصص", + "Please note that not all package managers may fully support this feature": "يرجى ملاحظة أنه قد لا يمكن لجميع إدارات الحزمة ان تدعم هذه الخاصية", + "Proxy URL": "عنوان URL الخاص بالوكيل", + "Enter proxy URL here": "أدخل رابط الخادم هنا", + "Authenticate to the proxy with a user and a password": "المصادقة على الوكيل باستخدام اسم مستخدم وكلمة مرور", + "Internet and proxy settings": "إعدادات الإنترنت والوكيل", + "Package manager preferences": "تفضيلات مدير الحزم", + "Ready": "جاهز", + "Not found": "غير موجود", + "Notification preferences": "تفضيلات الإشعارات", + "Notification types": "أنواع التنبيهات", + "The system tray icon must be enabled in order for notifications to work": "يجب تفعيل أيقونة شريط المهام لكي تعمل الإشعارات", + "Enable UniGetUI notifications": "تفعيل إشعارات UniGetUI", + "Show a notification when there are available updates": "إظهار إشعار عند توفر تحديثات", + "Show a silent notification when an operation is running": "إظهار إشعار صامت عند تشغيل عملية ما", + "Show a notification when an operation fails": "إظهار إشعار عند فشل العملية", + "Show a notification when an operation finishes successfully": "إظهار إشعار عند انتهاء العملية بنجاح", + "Concurrency and execution": "التزامن والتنفيذ", + "Automatic desktop shortcut remover": "إزالة اختصار سطح المكتب تلقائيًا", + "Choose how many operations should be performed in parallel": "اختر عدد العمليات التي يجب تنفيذها بالتوازي", + "Clear successful operations from the operation list after a 5 second delay": "مسح العمليات الناجحة من قائمة العمليات بعد 5 ثوانٍ", + "Download operations are not affected by this setting": "عمليات التنزيل لا تتأثر بهذا الإعداد", + "You may lose unsaved data": "قد تفقد بيانات غير محفوظة", + "Ask to delete desktop shortcuts created during an install or upgrade.": "اطلب حذف اختصارات سطح المكتب التي تم إنشاؤها أثناء التثبيت أو الترقية.", + "Package update preferences": "تفضيلات تحديث الحزمة", + "Update check frequency, automatically install updates, etc.": "تردد فحص التحديثات، تثبيت التحديثات تلقائياً، إلخ.", + "Reduce UAC prompts, elevate installations by default, unlock certain dangerous features, etc.": "تقليل مطالبات UAC، ورفع التثبيتات افتراضيًا، وفتح بعض الميزات الخطيرة، وغير ذلك.", + "Package operation preferences": "تفضيلات عملية الحزمة", + "Enable {pm}": "تفعيل {pm}", + "Not finding the file you are looking for? Make sure it has been added to path.": "ألا تجد الملف الذي تبحث عنه؟ تأكد من أنه تمت إضافته إلى المسار.", + "Select the executable to be used. The following list shows the executables found by UniGetUI": "حدد الملف التنفيذي المراد استخدامه. تعرض القائمة التالية الملفات التنفيذية التي عثر عليها UniGetUI", + "For security reasons, changing the executable file is disabled by default": "لدواعٍ أمنية، يكون تغيير الملف التنفيذي معطّلًا افتراضيًا", + "Change this": "تغيير هذا", + "Copy path": "نسخ المسار", + "Current executable file:": "الملف التنفيذي الحالي:", + "Ignore packages from {pm} when showing a notification about updates": "تجاهل الحزم من {pm} عند إظهار إشعار عن التحديث", + "Update security": "أمان التحديثات", + "Use global setting": "استخدام الإعداد العام", + "Minimum age for updates": "الحد الأدنى لعمر التحديثات", + "e.g. 10": "مثلًا 10", + "Custom minimum age (days)": "عمر أدنى مخصص (بالأيام)", + "{pm} does not provide release dates for its packages, so this setting will have no effect": "لا يوفّر {pm} تواريخ إصدار لحزمه، لذا لن يكون لهذا الإعداد أي تأثير", + "{pm} only provides release dates for some of its packages, so this setting will only apply to those packages": "يقدّم {pm} تواريخ إصدار لبعض حِزَمه فقط، لذا سيُطبَّق هذا الإعداد على تلك الحِزَم فحسب", + "Override the global minimum update age for this package manager": "تجاوز الحد الأدنى العام لعمر التحديثات لهذا مدير الحزم", + "View {0} logs": "إظهار {0} سجل", + "If Python cannot be found or is not listing packages but is installed on the system, ": "إذا تعذر العثور على Python أو لم يكن يعرض الحزم رغم أنه مثبت على النظام، ", + "Advanced options": "خيارات متقدمة", + "WinGet command-line tool": "أداة سطر أوامر WinGet", + "Choose which command-line tool UniGetUI uses for WinGet operations when the COM API is not used": "اختر أداة سطر الأوامر التي يستخدمها UniGetUI لعمليات WinGet عندما لا تُستخدم COM API", + "WinGet COM API": "واجهة WinGet COM API", + "Choose whether UniGetUI can use the WinGet COM API before falling back to the command-line tool": "اختر ما إذا كان بإمكان UniGetUI استخدام WinGet COM API قبل الرجوع إلى أداة سطر الأوامر", + "Reset WinGet": "إعادة تعيين WinGet", + "This may help if no packages are listed": "قد يكون هذا مفيدًا إذا لم يتم إدراج أي حزم", + "Force install location parameter when updating packages with custom locations": "فرض معامل موقع التثبيت عند تحديث الحزم ذات المواقع المخصصة", + "Install Scoop": "تثبيت Scoop", + "Uninstall Scoop (and its packages)": "إلغاء تثبيت Scoop (و حزمه)", + "Run cleanup and clear cache": "قم بتشغيل التنظيف ومسح ذاكرة التخزين المؤقت", + "Run": "تشغيل", + "Enable Scoop cleanup on launch": "تفعيل تنظيف Scoop عند البدأ", + "Default vcpkg triplet": "ثلاثية vcpkg الافتراضية", + "Change vcpkg root location": "تغيير موقع جذر vcpkg", + "Reset vcpkg root location": "إعادة تعيين موقع جذر vcpkg", + "Open vcpkg root location": "فتح موقع جذر vcpkg", + "Language, theme and other miscellaneous preferences": "اللغة, المظهر و تفضيلات متنوعة أخرى", + "Show notifications on different events": "إظهار الإشعارات حول الأحداث المختلفة", + "Change how UniGetUI checks and installs available updates for your packages": "تغيير كيفية قيام UniGetUI بالتحقق من التحديثات المتوفرة لحزمك وتثبيتها", + "Automatically save a list of all your installed packages to easily restore them.": "تلقائياً قم بحفظ قائمة لكل حُزمِك المثبتة لاستعادتها بسهولة.", + "Enable and disable package managers, change default install options, etc.": "تمكين مديري الحزم وتعطيلهم، وتغيير خيارات التثبيت الافتراضية، وغير ذلك.", + "Internet connection settings": "إعدادات اتصال الانرنت", + "Proxy settings, etc.": "إعدادات الوكيل، وأخرى.", + "Beta features and other options that shouldn't be touched": "ميزات تجريبية و خيارات أخرى لا يجب لمسها", + "Reload sources": "إعادة تحميل المصادر", + "Delete source": "حذف المصدر", + "Known sources": "المصادر المعروفة", + "Update checking": "التحقق من التحديثات", + "Automatic updates": "التحديثات التلقائية", + "Check for package updates periodically": "البحث عن التحديثات بشكل متكرر", + "Check for updates every:": "البحث عن التحديثات كل:", + "Install available updates automatically": "تثبيت التحديثات المتوفرة تلقائيًا", + "Do not automatically install updates when the network connection is metered": "لا تقم بتثبيت التحديثات تلقائياً عندما يكون اتصال الشبكة محدود", + "Do not automatically install updates when the device runs on battery": "عدم تثبيت التحديثات تلقائيًا عندما يعمل الجهاز على البطارية", + "Do not automatically install updates when the battery saver is on": "لا تقم بتثبيت التحديثات تلقائياً عند تشغيل وضع توفير الطاقة", + "Only show updates that are at least the specified number of days old": "اعرض فقط التحديثات التي مضى عليها على الأقل عدد الأيام المحدد", + "Warn me when the installer URL host changes between the installed version and the new version (WinGet only)": "حذّرني عندما يتغير مضيف رابط المثبّت بين الإصدار المثبّت والإصدار الجديد (WinGet فقط)", + "Change how UniGetUI handles install, update and uninstall operations.": "تغيير كيفية تولي UniGetUI لعمليات التثبيت، التحديث، والإزالة.", + "Navigation": "التنقل", + "Check for UniGetUI updates": "التحقق من تحديثات UniGetUI", + "Quit UniGetUI": "إنهاء UniGetUI", + "Filters": "فرز", + "Sources": "المصادر", + "Search for packages to start": "ابحث عن الحزم للبدء", + "Select all": "تحديد الكل", + "Clear selection": "إزالة التحديد", + "Instant search": "البحث الفوري", + "Distinguish between uppercase and lowercase": "تمييز بين الأحرف الكبيرة والصغيرة", + "Ignore special characters": "تجاهل الأحرف الخاصة", + "Search mode": "وضع البحث", + "Both": "كلاهما", + "Exact match": "تطابق تام\n", + "Show similar packages": "إظهار الحُزم المتشابهة", + "Loading": "جارٍ التحميل", + "Package": "حزمة", + "More options": "المزيد من الخيارات", + "Order by:": "رتب بحسب:", + "Name": "الاسم", + "Id": "معرّف", + "Ascendant": "صعوداً", + "Descendant": "تنازلي", + "View modes": "أوضاع العرض", + "Reload": "إعادة التحميل", + "Closed": "مغلق", + "Ascending": "تصاعدي", + "Descending": "تنازلي", + "{0}: {1}, {2}": "{0}: {1}، {2}", + "Order by": "ترتيب حسب", + "No results were found matching the input criteria": "لم يتم العثور على نتائج مطابقة لمعايير الإدخال", + "No packages were found": "لم يتم العثور على الحُزم", + "Loading packages": "تحميل الحزم", + "Skip integrity checks": "تخطي عمليات التحقق من السلامة", + "Download selected installers": "تحميل المُنصِّب المحدد", + "Install selection": "تثبيت المُحدد", + "Install options": "خيارات التثبيت", + "Add selection to bundle": "إضافة المُحدد إلى الحزمة", + "Download installer": "تحميل المُنصِّب", + "Uninstall selection": "إلغاء تثبيت المحدد", + "Uninstall options": "خيارات إلغاء التثبيت", + "Ignore selected packages": "تجاهل الحزم المحددة", + "Open install location": "فتح موقع التثبيت", + "Reinstall package": "إعادة تثبيت الحزمة", + "Uninstall package, then reinstall it": "أزِل تثبيت الحزمة, ثم أعِد تثبيتها", + "Ignore updates for this package": "تجاهل التحديثات لهذه الحزمة", + "WinGet malfunction detected": "تم اكتشاف خلل في برنامج WinGet", + "It looks like WinGet is not working properly. Do you want to attempt to repair WinGet?": "يبدو أن WinGet لا يعمل بشكل صحيح. هل تريد محاولة إصلاح WinGet؟", + "Repair WinGet": "إصلاح WinGet", + "Updates will no longer be ignored for {0}": "لن يتم تجاهل التحديثات بعد الآن لـ {0}", + "Updates are now ignored for {0}": "يتم الآن تجاهل التحديثات لـ {0}", + "Do not ignore updates for this package anymore": "لا تتجاهل التحديثات الخاصة بهذه الحزمة بعد الآن", + "Add packages or open an existing package bundle": "أضف حزم أو افتح حزمة مسبقة", + "Add packages to start": "أضف حزم للبدء", + "The current bundle has no packages. Add some packages to get started": "لا تحتوي الحزمة الحالية على أي حزم. أضف بعض الحزم للبدء", + "New": "جديد", + "Save as": "حفظ كـ", + "Create .ps1 script": "إنشاء برنامج نصي بصيغة .ps1", + "Remove selection from bundle": "حذف المحدد من الحزمة", + "Skip hash checks": "تخطي عمليات التحقق من hash", + "The package bundle is not valid": "الحزمة غير صالحة", + "The bundle you are trying to load appears to be invalid. Please check the file and try again.": "يبدو أن الحزمة التي تحاول تحميلها غير صالحة. يرجى التحقق من الملف والمحاولة مرة أخرى.", + "Package bundle": "حزمة الحزمة", + "Could not create bundle": "لم يتمكن من إنشاء الحزمة", + "The package bundle could not be created due to an error.": "لم يتم إنشاء حزمة الحزمة بسبب خطأ.", + "Install script": "برنامج نصي للتثبيت", + "PowerShell script": "سكربت PowerShell", + "The installation script saved to {0}": "تم حفظ برنامج التثبيت النصي في {0}", + "An error occurred": "حدث خطأ", + "An error occurred while attempting to create an installation script:": "حدث خطأ عند محاولة انشاء نص تثبيت", + "Hooray! No updates were found.": "يا للسعادة! لم يتم العثور على أية تحديثات!", + "Uninstall selected packages": "إلغاء تثبيت الحزم المحددة", + "Update selection": "تحديث المحدد", + "Update options": "خيارات التحديث", + "Uninstall package, then update it": "أزِل تثبيت الحزمة, ثم حدِثّها", + "Uninstall package": "إلغاء تثبيت الحزمة", + "Skip this version": "تخطي هذه النسخة", + "Pause updates for": "إيقاف التحديثات لـ", + "User | Local": "المستخدم | محلي", + "Machine | Global": "الجهاز | عام", + "The default package manager for Debian/Ubuntu-based Linux distributions.
Contains: Debian/Ubuntu packages": "مدير الحزم الافتراضي لتوزيعات Linux المبنية على Debian/Ubuntu.
يحتوي على: حزم Debian/Ubuntu", + "The Rust package manager.
Contains: Rust libraries and programs written in Rust": "مدير حزمة Rust.
يحتوي على: مكتبات Rust والبرامج المكتوبة بلغة Rust", + "The classical package manager for windows. You'll find everything there.
Contains: General Software": "نظام إدارة الحزم الكلاسيكي لويندوز. ستجد كل شيء هناك.
يحتوي على: برامج عامة ", + "The default package manager for RHEL/Fedora-based Linux distributions.
Contains: RPM packages": "مدير الحزم الافتراضي لتوزيعات Linux المبنية على RHEL/Fedora.
يحتوي على: حزم RPM", + "A repository full of tools and executables designed with Microsoft's .NET ecosystem in mind.
Contains: .NET related tools and scripts": "مستودع مليء بالأدوات والملفات القابلة للتنفيذ المصممة مع وضع نظام Microsoft البيئي .NET في الاعتبار.
يحتوي على: أدوات وبرامج نصية مرتبطة بـ .NET", + "The universal Linux package manager for desktop applications.
Contains: Flatpak applications from configured remotes": "مدير حزم Linux العام لتطبيقات سطح المكتب.
يحتوي على: تطبيقات Flatpak من المصادر البعيدة المكوّنة", + "NuPkg (zipped manifest)": "NuPkg (بيان مضغوط)", + "The Missing Package Manager for macOS (or Linux).
Contains: Formulae, Casks": "مدير الحزم المفقود لنظام macOS (أو Linux).
يحتوي على: Formulae, Casks", + "Node JS's package manager. Full of libraries and other utilities that orbit the javascript world
Contains: Node javascript libraries and other related utilities": "مدير حزم Node JS. مليئة بالمكتبات والأدوات المساعدة الأخرى التي تدور حول عالم جافا سكريبت
تحتوي على: مكتبات Node javascript والأدوات المساعدة الأخرى ذات الصلة ", + "The default package manager for Arch Linux and its derivatives.
Contains: Arch Linux packages": "مدير الحزم الافتراضي لتوزيعة Arch Linux ومشتقاتها.
يحتوي على: حزم Arch Linux", + "Python's library manager. Full of python libraries and other python-related utilities
Contains: Python libraries and related utilities": "مدير مكتبة بايثون. مليء بمكتبات بايثون وأدوات مساعدة أخرى متعلقة بالبايثون
يحتوي على: مكتبات بايثون وأدوات مساعدة متعلقة", + "PowerShell's package manager. Find libraries and scripts to expand PowerShell capabilities
Contains: Modules, Scripts, Cmdlets": "مدير حزم PowerShell. ابحث عن المكتبات والبرامج النصية لتوسيع إمكانيات PowerShell
يحتوي على: وحدات نمطية وبرامج نصية وأدوات أوامر", + "extracted": "تم استخراجه", + "Scoop package": "حزم Scoop", + "Great repository of unknown but useful utilities and other interesting packages.
Contains: Utilities, Command-line programs, General Software (extras bucket required)": "حزمة عظيمة من الأدوات المجهولة ولكن مفيدة، بالإضافة إلى حزمات مثيرة للإهتمام.
تحتوي:
أدوات، سطور أوامر، برامج، وبرمجيات عامة (بحاجة لحاوية إضافية", + "The universal Linux package manager by Canonical.
Contains: Snap packages from the Snapcraft store": "مدير الحزم العالمي لنظام Linux من Canonical.
يحتوي على: حزم Snap من متجر Snapcraft", + "library": "مكتبة", + "feature": "ميزة", + "A popular C/C++ library manager. Full of C/C++ libraries and other C/C++-related utilities
Contains: C/C++ libraries and related utilities": "مدير مكتبات ++C/C شائع الاستخدام. مليء بمكتبات ++C/C وأدوات مساعدة أخرى متعلقة بـ ++C/C
يحتوي على: مكتبات ++C/C وأدوات مساعدة ذات صلة", + "option": "خيار", + "This package cannot be installed from an elevated context.": "لا يمكن تثبيت هذه الحزمة من سياق مرتفع.", + "Please run UniGetUI as a regular user and try again.": "يرجى تشغيل UniGetUI كمستخدم عادي ثم حاول مرة أخرى.", + "Please check the installation options for this package and try again": "يرجى التحقق من خيارات التثبيت لهذه الحزمة ثم المحاولة مرة أخرى", + "Microsoft's official package manager. Full of well-known and verified packages
Contains: General Software, Microsoft Store apps": "مدير الحزم الرسمي لشركة Microsoft. مليئة بالحزم المعروفة والتي تم التحقق منها
تحتوي على: برامج عامة ، تطبيقات متجر مايكروسوفت", + "Local PC": "الكمبيوتر المحلي", + "Android Subsystem": "نظام Android الفرعي", + "Operation on queue (position {0})...": "العملية على قائمة الانتظار (الموضع {0})...", + "Click here for more details": "اضغط هنا للمزيد من التفاصيل", + "Operation canceled by user": "تم إلغاء العملية بواسطة المستخدم", + "Running PreOperation ({0}/{1})...": "جارٍ تشغيل ما قبل العملية ({0}/{1})...", + "PreOperation {0} out of {1} failed, and was tagged as necessary. Aborting...": "فشلت مرحلة ما قبل العملية {0} من أصل {1}، وتم تمييزها على أنها ضرورية. جارٍ الإلغاء...", + "PreOperation {0} out of {1} finished with result {2}": "انتهت مرحلة ما قبل العملية {0} من أصل {1} بالنتيجة {2}", + "Starting operation...": "يجري التسغيل...", + "Running PostOperation ({0}/{1})...": "جارٍ تشغيل ما بعد العملية ({0}/{1})...", + "PostOperation {0} out of {1} failed, and was tagged as necessary. Aborting...": "فشلت مرحلة ما بعد العملية {0} من أصل {1}، وتم تمييزها على أنها ضرورية. جارٍ الإلغاء...", + "PostOperation {0} out of {1} finished with result {2}": "انتهت مرحلة ما بعد العملية {0} من أصل {1} بالنتيجة {2}", + "{package} installer download": "حمّل مثبّت {package}", + "{0} installer is being downloaded": "مثبت {0} قيد التحميل", + "Download succeeded": "تم التحميل بنجاح", + "{package} installer was downloaded successfully": "تم تحميل مثبّت {package} بنجاح", + "Download failed": "فشل التحميل", + "{package} installer could not be downloaded": "لم يتم تحميل مثبّت {package}", + "{package} Installation": "{package} التثبيت", + "{0} is being installed": "جاري تثبيت {0}", + "Installation succeeded": "نجاح التنزيل", + "{package} was installed successfully": "تم تثبيت {package} بنجاح", + "Installation failed": "فشل التنزيل", + "{package} could not be installed": "لم يتم تثبيت {package}", + "{package} Update": "تحديث {package}", + "Update succeeded": "تم التحديث بنجاح", + "{package} was updated successfully": "تم تحديث {package} بنجاح", + "Update failed": "فشل التحديث", + "{package} could not be updated": "لم يتمكن من تحديث {package}", + "{package} Uninstall": "{package} إلغاء التثبيت", + "{0} is being uninstalled": "جاري إلغاء تثبيت {0}", + "Uninstall succeeded": "تم إلغاء التثبيت بنجاح", + "{package} was uninstalled successfully": "تم إلغاء تثبيت {package} بنجاح", + "Uninstall failed": "فشل إلغاء التثبيت", + "{package} could not be uninstalled": "لم يتم إلغاء تثبيت {package}", + "Adding source {source}": "إضافة مصدر {source}", + "Adding source {source} to {manager}": "إضافة المصدر {source} إلى {manager} ", + "Source added successfully": "تم إضافة المصدر بنجاح", + "The source {source} was added to {manager} successfully": "تمت إضافة المصدر {source} إلى {manager} بنجاح", + "Could not add source": "لم يتم إضافة مصدر", + "Could not add source {source} to {manager}": "لم يٌتمكن من إضافة المصدر {source} إلى {manager}", + "Removing source {source}": "إزالة المصدر {source}", + "Removing source {source} from {manager}": "إزالة المصدر {source} من {manager}", + "Source removed successfully": "تم حذف المصدر بنجاح", + "The source {source} was removed from {manager} successfully": "تم إزالة المصدر {source} من {manager} بنجاح", + "Could not remove source": "لم يتم إزالة المصدر", + "Could not remove source {source} from {manager}": "لم تتم إزالة المصدر {source} من {manager}", + "The package manager \"{0}\" was not found": "لم يتم العثور على مدير الحزمة \"{0}\"", + "The package manager \"{0}\" is disabled": "تم تعطيل مدير الحزمة \"{0}\"", + "There is an error with the configuration of the package manager \"{0}\"": "يوجد خطأ في تكوين مدير الحزم \"{0}\"", + "The package \"{0}\" was not found on the package manager \"{1}\"": "لم يتم العثور على الحزمة \"{0}\" في مدير الحزم \"{1}\"", + "{0} is disabled": "{0} غير مفعل", + "{0} weeks": "{0} أسابيع", + "1 month": "شهر واحد", + "{0} months": "{0} أشهر", + "Something went wrong": "حدث خطأ ما", + "An interal error occurred. Please view the log for further details.": "حدث خطأ داخلي. يرجى الاطلاع على السجل لمزيد من التفاصيل.", + "No applicable installer was found for the package {0}": "لم يتم العثور على مثبّت مناسب لهذه الحزمة {0}", + "Integrity checks will not be performed during this operation": "عمليات التحقق من السلامة لن يتم تنفيذها أثناء هذه العملية", + "This is not recommended.": "غير موصى به", + "Run now": "تشغيل الآن", + "Run next": "تشغيل التالي", + "Run last": "تشغيل الأخير", + "Show in explorer": "الإظهار في المستكشف", + "Checked": "محدّد", + "Unchecked": "غير محدّد", + "This package is already installed": "هذه الحزمة مثبتة سابقا ", + "This package can be upgraded to version {0}": "يمكن تحديث هذه الحزمة إلى الإصدار {0}", + "Updates for this package are ignored": "تجاهل التحديثات لهذه الحزمة", + "This package is being processed": "تتم معالجة هذه الحزمة", + "This package is not available": "هذه الحزمة غير متوفرة", + "Select the source you want to add:": "قم تحديد المصدر المُراد إضافته:", + "Source name:": "اسم المصدر:", + "Source URL:": "رابط المصدر:", + "An error occurred when adding the source: ": "حدث خطأ عند إضافة المصدر:", + "Package management made easy": "إدارة الحزم أصبحت سهلة", + "version {0}": "الإصدار {0}", + "[RAN AS ADMINISTRATOR]": "[RAN AS ADMINISTRATOR]", + "Portable mode": "الوضع المتنقل.", + "DEBUG BUILD": "أصدار التصحيح.", + "Here you can change UniGetUI's behaviour regarding the following shortcuts. Checking a shortcut will make UniGetUI delete it if if gets created on a future upgrade. Unchecking it will keep the shortcut intact": "يمكنك هنا تغيير سلوك UniGetUI فيما يتعلق بالاختصارات التالية. سيؤدي تحديد اختصار إلى جعل UniGetUI يحذفه إذا تم إنشاؤه في ترقية مستقبلية. سيؤدي إلغاء تحديده إلى إبقاء الاختصار سليمًا", + "Manual scan": "الفحص اليدوي.", + "Existing shortcuts on your desktop will be scanned, and you will need to pick which ones to keep and which ones to remove.": "الاختصارات الموجودة على سطح المكتب سيتم مسحها، وستحتاج إلى اختيار أيٍّ منها لتبقى وأيٍّ منها لتُحذَف.", + "Delete?": "حذف؟", + "I understand": "أنا أتفهم", + "Chocolatey setup changed": "تم تغيير إعداد Chocolatey", + "UniGetUI no longer includes its own private Chocolatey installation. A legacy UniGetUI-managed Chocolatey installation was detected for this user profile, but system Chocolatey was not found. Chocolatey will stay unavailable in UniGetUI until Chocolatey is installed on the system and UniGetUI is restarted. Applications previously installed through UniGetUI's bundled Chocolatey may still appear under other sources such as Local PC or WinGet.": "لم يعد UniGetUI يتضمن تثبيت Chocolatey الخاص به. تم اكتشاف تثبيت Chocolatey قديم مُدار بواسطة UniGetUI لملف تعريف المستخدم هذا، ولكن لم يتم العثور على Chocolatey على مستوى النظام. سيظل Chocolatey غير متاح في UniGetUI حتى يتم تثبيت Chocolatey على النظام وإعادة تشغيل UniGetUI. قد تظل التطبيقات المثبتة سابقًا عبر Chocolatey المدمج في UniGetUI ظاهرة ضمن مصادر أخرى مثل الكمبيوتر المحلي أو WinGet.", + "NOTE: This troubleshooter can be disabled from UniGetUI Settings, on the WinGet section": "ملاحظة: يمكن تعطيل أداة استكشاف الأخطاء وإصلاحها هذه من إعدادات UniGetUI، في قسم WinGet", + "Restart": "إعادة التشغيل", + "Are you sure you want to delete all shortcuts?": "هل أنت متأكد من أنك تريد حذف جميع الاختصارات؟", + "Any new shorcuts created during an install or an update operation will be deleted automatically, instead of showing a confirmation prompt the first time they are detected.": "أي اختصارات جديدة تُنشأ أثناء عملية تثبيت أو تحديث سيتم حذفها تلقائياً، بدلاً من إظهار إشارة تأكيد في المرة الأولى التي يتم اكتشافها فيها.", + "Any shorcuts created or modified outside of UniGetUI will be ignored. You will be able to add them via the {0} button.": "أيّ اختصارات تُنشأ أو تُعَدّل خارج UniGetUI سيتم تجاهلها. ستتمكن من إضافتها من خلال الزر {0}.", + "Are you really sure you want to enable this feature?": "هل أنت متأكد من أنك تريد تفعيل هذه الخاصية؟", + "No new shortcuts were found during the scan.": "فشل العثور على اختصارات جديدة أثناء الفحص.", + "How to add packages to a bundle": "كيفية إضافة الحزم إلى الباقة", + "In order to add packages to a bundle, you will need to: ": "من أجل إضافة حزم إلى الباقة، ستحتاج إلى:", + "1. Navigate to the \"{0}\" or \"{1}\" page.": "تنقّل إلى صفحة \"{0}\" أو \"{1}\"", + "2. Locate the package(s) you want to add to the bundle, and select their leftmost checkbox.": "2. حدد موقع الحزمة/الحزم التي تريد إضافتها إلى الباقة، وحدد مربع الاختيار أقصى اليسار", + "3. When the packages you want to add to the bundle are selected, find and click the option \"{0}\" on the toolbar.": "3. عندما تكون الحزم التي تريد إضافتها إلى الباقة مُختارة، جِد واصغط الخيار \"{0}\" في شريط الأدوات.", + "4. Your packages will have been added to the bundle. You can continue adding packages, or export the bundle.": "4. سيتم إضافة حزمك إلى الباقة. يمكنك مواصلة إضافة الحزم، أو تصدير الباقة.", + "Which backup do you want to open?": "أي نسخة احتياطية تريد فتحها؟", + "Select the backup you want to open. Later, you will be able to review which packages you want to install.": "حدد النسخة الاحتياطية التي تريد فتحها. ستتمكن لاحقًا من مراجعة الحزم أو البرامج التي تريد استعادتها.", + "There are ongoing operations. Quitting UniGetUI may cause them to fail. Do you want to continue?": "هناك عمليات جارية. قد يؤدي إغلاق UniGetUI إلى فشلها. هل تريد الاستمرار؟", + "UniGetUI or some of its components are missing or corrupt.": "UniGetUI أو بعض مكوّناته مفقودة أو تالفة.", + "It is strongly recommended to reinstall UniGetUI to adress the situation.": "يوصى بشدة بإعادة تثبيت UniGetUI لمعالجة هذا الوضع.", + "Refer to the UniGetUI Logs to get more details regarding the affected file(s)": "ارجع إلى سجلات UniGetUI للحصول على مزيد من التفاصيل حول الملف أو الملفات المتأثرة", + "Integrity checks can be disabled from the Experimental Settings": "يمكن تعطيل عمليات التحقق من السلامة من الإعدادات التجريبية", + "Repair UniGetUI": "إصلاح UniGetUI", + "Live output": "الإخراج المباشر", + "This package bundle had some settings that are potentially dangerous, and may be ignored by default.": "تحتوي باقة الحزم هذه على بعض الإعدادات التي قد تكون خطيرة وقد يتم تجاهلها افتراضيًا.", + "Entries that show in YELLOW will be IGNORED.": "سيتم تجاهل الإدخالات التي تظهر باللون الأصفر.", + "Entries that show in RED will be IMPORTED.": "سيتم استيراد الإدخالات التي تظهر باللون الأحمر.", + "You can change this behavior on UniGetUI security settings.": "يمكنك تغيير هذا السلوك من إعدادات أمان UniGetUI.", + "Open UniGetUI security settings": "افتح إعدادات أمان UniGetUI", + "Should you modify the security settings, you will need to open the bundle again for the changes to take effect.": "إذا عدّلت إعدادات الأمان، فستحتاج إلى فتح الباقة مرة أخرى حتى تدخل التغييرات حيّز التنفيذ.", + "Details of the report:": "تفاصيل التقرير:", + "Are you sure you want to create a new package bundle? ": "هل أنت متأكد من أنك تريد إنشاء حزمة جديدة؟", + "Any unsaved changes will be lost": "أي حزم غير محفوظة ستُفقد", + "Warning!": "تحذير!", + "For security reasons, custom command-line arguments are disabled by default. Go to UniGetUI security settings to change this. ": "لدواعٍ أمنية، تكون وسائط سطر الأوامر المخصصة معطّلة افتراضيًا. انتقل إلى إعدادات أمان UniGetUI لتغيير ذلك.", + "Change default options": "تغيير الخيارات الإفتراضية", + "Ignore future updates for this package": "تجاهل التحديثات المستقبلية لهذه الحزمة", + "For security reasons, pre-operation and post-operation scripts are disabled by default. Go to UniGetUI security settings to change this. ": "لدواعٍ أمنية، تكون البرامج النصية قبل العملية وبعدها معطّلة افتراضيًا. انتقل إلى إعدادات أمان UniGetUI لتغيير ذلك.", + "You can define the commands that will be run before or after this package is installed, updated or uninstalled. They will be run on a command prompt, so CMD scripts will work here.": "يمكنك تحديد الأوامر التي سيتم تشغيلها قبل تثبيت هذه الحزمة أو تحديثها أو إلغاء تثبيتها أو بعد ذلك. سيتم تشغيلها في موجه الأوامر، لذا ستعمل برامج CMD النصية هنا.", + "Change this and unlock": "تغيير هذا والغاء القفل", + "{0} Install options are currently locked because {0} follows the default install options.": "خيارات تثبيت {0} مقفلة حاليًا لأن {0} يتبع خيارات التثبيت الافتراضية.", + "Unset or unknown": "غير معروف أو لم يتم ضبطها", + "This package has no screenshots or is missing the icon? Contrbute to UniGetUI by adding the missing icons and screenshots to our open, public database.": "هل لا تحتوي هذه الحزمة على لقطات شاشة أو تفتقد الرمز؟ ساهم في UniGetUI عن طريق إضافة الأيقونات ولقطات الشاشة المفقودة إلى قاعدة البيانات العامة المفتوحة لدينا.", + "Become a contributor": "كن مساهاً", + "Update to {0} available": "التحديث إلى {0} متاح", + "Reinstall": "إعادة التثبيت", + "Installer not available": "المثبت غير متوفر", + "Version:": "الإصدار:", + "UniGetUI Version {0}": "إصدار UniGetUI {0}", + "Performing backup, please wait...": "يتم النسخ الإحتياطي الآن, يرجى الإنتظار...", + "An error occurred while logging in: ": "حدث خطأ عند تسجيل الدخول", + "Fetching available backups...": "إسترداد النسخ الاحتياطية المتوفرة...", + "Done!": "تم!", + "The cloud backup has been loaded successfully.": "تم تحميل النسخة الاحتياطية السحابية بنجاح.", + "An error occurred while loading a backup: ": "حدث خطأ أثناء تحميل النسخة الإحتياطية:", + "Backing up packages to GitHub Gist...": "يتم النسخ الاحتياطي للحزم الى GitHub Gist...", + "Backup Successful": "نجح النسخ الاحتياطي", + "The cloud backup completed successfully.": "اكتمل النسخ الاحتياطي السحابي بنجاح.", + "Could not back up packages to GitHub Gist: ": "تعذر نسخ الحزم احتياطيًا إلى GitHub Gist: ", + "It is not guaranteed that the provided credentials will be stored safely, so you may as well not use the credentials of your bank account": "ليس مضموناً أن بيانات الاعتماد المقدّمة سيتم حفظها بأمان، لذلك لا تقم باستخدام بيانات حسابك المصرفي", + "Enable the automatic WinGet troubleshooter": "تمكين مستكشف أخطاء WinGet التلقائي", + "Add updates that fail with a 'no applicable update found' to the ignored updates list": "أضف التحديثات التي تفشل بـ \"لا يوجد تحديث قابل للتطبيق\" إلى قائمة التحديثات التي تم تجاهلها", + "Invalid selection": "تحديد غير صالح", + "No package was selected": "لم يتم تحديد أي حزمة", + "More than 1 package was selected": "تم تحديد أكثر من حزمة واحدة", + "List": "قائمة", + "Grid": "شبكة", + "Icons": "أيقونات", + "\"{0}\" is a local package and does not have available details": "\"{0}\" هي حزمة محلية وليس لها تفاصيل متاحة", + "\"{0}\" is a local package and is not compatible with this feature": "\"{0}\" هي حزمة محلية وليست متوافقة مع هذه الخاصية", + "Add packages to bundle": "أضف الحزم إلى الباقة", + "Preparing packages, please wait...": "جاري تحضير الحزم ، يرجى الانتظار...", + "Loading packages, please wait...": "يتم تحميل الحُزم, يرجى الإنتظار...", + "Saving packages, please wait...": "يتم حفظ الحُزم, يرجى الإنتظار...", + "The bundle was created successfully on {0}": "تم إنشاء الباقة بنجاح في {0}", + "User profile": "ملف تعريف المستخدم", + "Error": "خطأ", + "Log in failed: ": "فشل تسجيل الدخول:", + "Log out failed: ": "فشل تسجيل الخروج:", + "Package backup settings": "إعدادات النسخ الاحتياطي للحزم", + "Manage UniGetUI autostart behaviour from the Settings app": "إدارة سلوك التشغيل التلقائي لـ UniGetUI", + "Choose how many operations shoulds be performed in parallel": "اختر عدد العمليات التي يجب تنفيذها بالتوازي", + "Something went wrong while launching the updater.": "لقد حدث خطأ ما أثناء تشغيل برنامج التحديث.", + "Please try again later": "يرجى المحاولة مرة أخرى لاحقًا", + "Show the release notes after UniGetUI is updated": "إظهار ملاحظات الإصدار بعد تحديث UniGetUI" +} diff --git a/src/Languages/lang_be.json b/src/Languages/lang_be.json new file mode 100644 index 0000000..a59d5a4 --- /dev/null +++ b/src/Languages/lang_be.json @@ -0,0 +1,850 @@ +{ + "{0} of {1} operations completed": "Завершана {0} з {1} аперацый", + "{0} is now {1}": "{0} цяпер {1}", + "Enabled": "Уключана", + "Disabled": "Адключана", + "Privacy": "Прыватнасць", + "Hide my username from the logs": "Схаваць маё імя карыстальніка з журналаў", + "Replaces your username with **** in the logs. Restart UniGetUI to also hide it from already-recorded entries.": "Замяняе ваша імя карыстальніка на **** у журналах. Перазапусціце UniGetUI, каб схаваць яго таксама з ужо запісаных запісаў.", + "Your last update attempt did not complete.": "Апошняя спроба абнаўлення не завяршылася.", + "UniGetUI could not confirm whether the update succeeded. Open the log to see what happened.": "UniGetUI не ўдалося пацвердзіць, ці паспяхова завяршылася абнаўленне. Адкрыйце журнал, каб даведацца, што адбылося.", + "View log": "Праглядзець журнал", + "The installer reported success but did not restart UniGetUI.": "Усталёўшчык паведаміў пра поспех, але не перазапусціў UniGetUI.", + "The installer failed to initialize.": "Усталёўшчык не змог ініцыялізавацца.", + "Setup was canceled before installation began.": "Наладжванне было скасавана да пачатку ўсталявання.", + "A fatal error occurred during the preparation phase.": "Падчас падрыхтоўкі адбылася фатальная памылка.", + "A fatal error occurred during installation.": "Падчас усталявання адбылася фатальная памылка.", + "Installation was canceled while in progress.": "Усталяванне было скасавана падчас выканання.", + "The installer was terminated by another process.": "Усталёўшчык быў завершаны іншым працэсам.", + "The preparation phase determined the installation cannot proceed.": "На этапе падрыхтоўкі вызначана, што ўсталяванне не можа працягвацца.", + "The installer could not start. UniGetUI may already be running, or you do not have permission to install.": "Не ўдалося запусціць усталёўшчык. Магчыма, UniGetUI ужо працуе або ў вас няма дазволу на ўсталяванне.", + "Unexpected installer error.": "Нечаканая памылка ўсталёўшчыка.", + "We are checking for updates.": "Ідзе праверка абнаўленняў.", + "Please wait": "Пачакайце", + "Great! You are on the latest version.": "Вы выкарыстоўваеце апошнюю версію.", + "There are no new UniGetUI versions to be installed": "Новых версій UniGetUI няма", + "UniGetUI version {0} is being downloaded.": "Спампоўваецца UniGetUI версіі {0}.", + "This may take a minute or two": "Гэта можа заняць хвіліну-другую", + "The installer authenticity could not be verified.": "Нельга пацвердзіць сапраўднасць усталёўшчыка.", + "The update process has been aborted.": "Працэс абнаўлення спынены.", + "Auto-update is not yet available on this platform.": "Аўтаабнаўленне пакуль недаступнае на гэтай платформе.", + "Please update UniGetUI manually.": "Абнавіце UniGetUI ўручную.", + "An error occurred when checking for updates: ": "Памылка пры праверцы абнаўленняў: ", + "The updater could not be launched.": "Не ўдалося запусціць праграму абнаўлення.", + "The operating system did not start the installer process.": "Аперацыйная сістэма не запусціла працэс усталёўшчыка.", + "UniGetUI is being updated...": "UniGetUI абнаўляецца...", + "Update installed.": "Абнаўленне ўсталявана.", + "UniGetUI was updated successfully, but this running copy was not replaced. This usually means you are running a development build. Close this copy and start the newly-installed version to finish.": "UniGetUI паспяхова абноўлены, але гэты запушчаны экзэмпляр не быў заменены. Звычайна гэта азначае, што вы выкарыстоўваеце зборку для распрацоўкі. Закрыйце гэты экзэмпляр і запусціце новаўсталяваную версію, каб завяршыць.", + "The update could not be applied.": "Не ўдалося ўжыць абнаўленне.", + "Installer exit code {0}: {1}": "Код выхаду ўсталёўшчыка {0}: {1}", + "Update cancelled.": "Абнаўленне скасавана.", + "Authentication was cancelled.": "Аўтэнтыфікацыя скасавана.", + "Installer exit code {0}": "Код выхаду ўсталёўшчыка {0}", + "Operation in progress": "Аперацыя выконваецца", + "Please wait...": "Пачакайце...", + "Success!": "Поспех!", + "Failed": "Няўдала", + "An error occurred while processing this package": "Памылка апрацоўкі гэтага пакета", + "Installer": "Усталёўшчык", + "Executable": "Выканальны файл", + "MSI": "MSI", + "Compressed file": "Сціснуты файл", + "MSIX": "MSIX", + "WinGet was repaired successfully": "WinGet паспяхова адноўлены", + "It is recommended to restart UniGetUI after WinGet has been repaired": "Рэкамендуецца перазапусціць UniGetUI пасля рамонту WinGet", + "WinGet could not be repaired": "WinGet не ўдалося аднавіць", + "An unexpected issue occurred while attempting to repair WinGet. Please try again later": "Нечаканая праблема пры спробе аднавіць WinGet. Паспрабуйце пазней", + "Log in to enable cloud backup": "Увайдзіце, каб уключыць воблачную копію", + "Backup Failed": "Памылка стварэння рэзервовай копіі", + "Downloading backup...": "Спампоўка рэзервовай копіі...", + "An update was found!": "Знойдзена абнаўленне!", + "{0} can be updated to version {1}": "{0} можна абнавіць да версіі {1}", + "Updates found!": "Знойдзены абнаўленні!", + "{0} packages can be updated": "{0} пакета(ў) можна абнавіць", + "{0} is being updated to version {1}": "{0} абнаўляецца да версіі {1}", + "{0} packages are being updated": "{0} пакетаў абнаўляюцца", + "You have currently version {0} installed": "Зараз усталявана версія {0}", + "Desktop shortcut created": "Створаны ярлык на працоўным стале", + "UniGetUI has detected a new desktop shortcut that can be deleted automatically.": "Выяўлены новы ярлык - можна аўтаматычна выдаліць.", + "{0} desktop shortcuts created": "Створана ярлыкоў: {0}", + "UniGetUI has detected {0} new desktop shortcuts that can be deleted automatically.": "Выяўлена {0} новых ярлыкоў для аўтавылучэння.", + "Attention required": "Патрабуецца ўвага", + "Restart required": "Патрабуецца перазапуск", + "1 update is available": "Даступнае 1 абнаўленне", + "{0} updates are available": "Даступна абнаўленняў: {0}", + "Everything is up to date": "Усё актуальна", + "Discover Packages": "Пошук пакетаў", + "Available Updates": "Даступныя абнаўленні", + "Installed Packages": "Усталяваныя пакеты", + "UniGetUI Version {0} by Devolutions": "UniGetUI версіі {0} ад Devolutions", + "Show UniGetUI": "Паказаць UniGetUI", + "Quit": "Выхад", + "Are you sure?": "Вы ўпэўнены?", + "Do you really want to uninstall {0}?": "Выдаліць {0}?", + "Do you really want to uninstall the following {0} packages?": "Выдаліць наступныя {0} пакетаў?", + "No": "Не", + "Yes": "Так", + "Partial": "Часткова", + "View on UniGetUI": "Прагляд у UniGetUI", + "Update": "Абнавіць", + "Open UniGetUI": "Адкрыць UniGetUI", + "Update all": "Абнавіць усё", + "Update now": "Абнавіць зараз", + "Installer host changed since the installed version.\n": "Хост усталёўшчыка змяніўся ў параўнанні з усталяванай версіяй.\n", + "This package is on the queue": "Пакет у чарзе", + "installing": "усталёўваецца", + "updating": "абнаўляецца", + "uninstalling": "выдаляецца", + "installed": "усталявана", + "Retry": "Паўтарыць", + "Install": "Усталяваць", + "Uninstall": "Выдаліць", + "Open": "Адкрыць", + "Operation profile:": "Профіль аперацыі:", + "Follow the default options when installing, upgrading or uninstalling this package": "Выкарыстоўваць налады па змаўчанні для ўсталявання/абнаўлення/выдалення гэтага пакета", + "The following settings will be applied each time this package is installed, updated or removed.": "Наступныя налады прымяняюцца для кожнага ўсталявання/абнаўлення/выдалення пакета.", + "Version to install:": "Версія для ўсталявання:", + "Architecture to install:": "Архітэктура для ўсталявання:", + "Installation scope:": "Ахоп усталявання:", + "Install location:": "Месца ўсталявання:", + "Select": "Абраць", + "Reset": "Скід", + "Custom install arguments:": "Уласныя аргументы ўсталявання:", + "Custom update arguments:": "Уласныя аргументы абнаўлення:", + "Custom uninstall arguments:": "Уласныя аргументы выдалення:", + "Pre-install command:": "Каманда перад усталяваннем:", + "Post-install command:": "Каманда пасля ўсталявання:", + "Abort install if pre-install command fails": "Скасаваць устаноўку ў выпадку памылкі ў падрыхтоўчай камандзе", + "Pre-update command:": "Каманда перад абнаўленнем:", + "Post-update command:": "Каманда пасля абнаўлення:", + "Abort update if pre-update command fails": "Скасаваць абнауленне ў выпадку памылкі ў падрыхтоўчай камандзе", + "Pre-uninstall command:": "Каманда перад выдаленнем:", + "Post-uninstall command:": "Каманда пасля выдалення:", + "Abort uninstall if pre-uninstall command fails": "Скасаваць выдаленне ў выпадку памылкі ў падрыхтоўчай камандзе", + "Command-line to run:": "Каманда для запуску:", + "Save and close": "Захаваць і закрыць", + "General": "Агульнае", + "Architecture & Location": "Архітэктура і размяшчэнне", + "Command-line": "Камандны радок", + "Close apps": "Закрыць праграмы", + "Pre/Post install": "Перад/пасля ўсталявання", + "Select the processes that should be closed before this package is installed, updated or uninstalled.": "Абярыце працэсы, якія трэба закрыць перад усталяваннем/абнаўленнем/выдаленнем пакета.", + "Write here the process names here, separated by commas (,)": "Упішыце назвы працэсаў праз коску", + "Try to kill the processes that refuse to close when requested to": "Паспрабаваць забіць працэсы, якія не закрываюцца", + "Run as admin": "Запусціць як адміністратар", + "Interactive installation": "Інтэрактыўнае ўсталяванне", + "Skip hash check": "Прапусціць праверку хэша", + "Uninstall previous versions when updated": "Выдаляць старыя версіі пры абнаўленні", + "Skip minor updates for this package": "Прапускаць дробныя абнаўленні для пакета", + "Automatically update this package": "Аўтаматычна абнаўляць гэты пакет", + "{0} installation options": "Параметры ўсталявання {0}", + "Latest": "Апошняя", + "PreRelease": "Перадрэліз", + "Default": "Па змаўчанні", + "Manage ignored updates": "Рэгуляваць ігнараваныя абнаўленні", + "The packages listed here won't be taken in account when checking for updates. Double-click them or click the button on their right to stop ignoring their updates.": "Пакеты ў спісе ігнаруюцца пры праверцы абнаўленняў. Падвойны клік або кнопка справа - спыніць ігнараванне.", + "Reset list": "Скінуць спіс", + "Do you really want to reset the ignored updates list? This action cannot be reverted": "Вы сапраўды хочаце скінуць спіс ігнараваных абнаўленняў? Гэтае дзеянне нельга будзе скасаваць", + "No ignored updates": "Няма ігнараваных абнаўленняў", + "Package Name": "Назва пакета", + "Package ID": "ID пакета", + "Ignored version": "Ігнараваная версія", + "New version": "Новая версія", + "Source": "Крыніца", + "All versions": "Усе версіі", + "Unknown": "Невядома", + "Up to date": "Актуальна", + "Package {name} from {manager}": "Пакет {name} з {manager}", + "Remove {0} from ignored updates": "Выдаліць {0} з ігнараваных абнаўленняў", + "Cancel": "Скасаваць", + "Administrator privileges": "Паўнамоцтвы адміністратара", + "This operation is running with administrator privileges.": "Аперацыя працуе з правамі адміністратара.", + "Interactive operation": "Інтэрактыўная аперацыя", + "This operation is running interactively.": "Аперацыя працуе ў інтэрактыўным рэжыме.", + "You will likely need to interact with the installer.": "Магчыма спатрэбіцца ўзаемадзеянне з усталёўшчыкам.", + "Integrity checks skipped": "Праверкі цэласнасці прапушчаны", + "Integrity checks will not be performed during this operation.": "Праверкі цэласнасці не будуць выконвацца падчас гэтай аперацыі.", + "Proceed at your own risk.": "Працягвайце на ўласную рызыку.", + "Close": "Закрыць", + "Loading...": "Загрузка...", + "Installer SHA256": "SHA256 усталёўшчыка", + "Homepage": "Хатняя старонка", + "Author": "Аўтар", + "Publisher": "Выдавец", + "License": "Ліцэнзія", + "Manifest": "Маніфест", + "Installer Type": "Тып усталёўшчыка", + "Size": "Памер", + "Installer URL": "URL усталёўшчыка", + "Last updated:": "Апошняе абнаўленне:", + "Release notes URL": "URL нататак выпуску", + "Package details": "Падрабязнасці пакета", + "Dependencies:": "Залежнасці:", + "Release notes": "Нататкі выпуску", + "Screenshots": "Скрыншоты", + "This package has no screenshots or is missing the icon? Contribute to UniGetUI by adding the missing icons and screenshots to our open, public database.": "У гэтага пакета няма скрыншотаў або адсутнічае іконка? Дапамажыце UniGetUI, дадаўшы адсутныя іконкі і скрыншоты ў нашу адкрытую публічную базу даных.", + "Version": "Версія", + "Install as administrator": "Усталяваць як адміністратар", + "Update to version {0}": "Абнавіць да версіі {0}", + "Installed Version": "Усталяваная версія", + "Update as administrator": "Абнавіць як адміністратар", + "Interactive update": "Інтэрактыўнае абнаўленне", + "Uninstall as administrator": "Выдаліць як адміністратар", + "Interactive uninstall": "Інтэрактыўнае выдаленне", + "Uninstall and remove data": "Выдаліць і даныя", + "Not available": "Недаступна", + "Installer SHA512": "SHA512 усталёўшчыка", + "Unknown size": "Невядомы памер", + "No dependencies specified": "Залежнасці не зададзены", + "mandatory": "абавязкова", + "optional": "неабавязкова", + "UniGetUI {0} is ready to be installed.": "UniGetUI {0} гатовы да ўсталявання.", + "The update process will start after closing UniGetUI": "Абнаўленне пачнецца пасля закрыцця UniGetUI", + "UniGetUI has been ran as administrator, which is not recommended. When running UniGetUI as administrator, EVERY operation launched from UniGetUI will have administrator privileges. You can still use the program, but we highly recommend not running UniGetUI with administrator privileges.": "UniGetUI быў запушчаны з правамі адміністратара, што не рэкамендуецца. Пры запуску UniGetUI з правамі адміністратара КОЖНАЯ аперацыя, запушчаная з UniGetUI, будзе мець правы адміністратара. Вы ўсё яшчэ можаце карыстацца праграмай, але мы настойліва рэкамендуем не запускаць UniGetUI з правамі адміністратара.", + "Share anonymous usage data": "Дзяліцца ананімнымі данымі выкарыстання", + "UniGetUI collects anonymous usage data in order to improve the user experience.": "UniGetUI збірае ананімныя даныя для паляпшэння UX.", + "Accept": "Прыняць", + "Software Updates": "Абнаўленні", + "Package Bundles": "Наборы пакетаў", + "Settings": "Налады", + "Package Managers": "Мэнэджары пакетаў", + "UniGetUI Log": "Лог UniGetUI", + "Package Manager logs": "Логі мэнэджара пакетаў", + "Operation history": "Гісторыя аперацый", + "Help": "Дапамога", + "UniGetUI": "UniGetUI", + "You have installed UniGetUI Version {0}": "Вы ўсталявалі UniGetUI версіі {0}", + "Disclaimer": "Адмова ад адказнасці", + "UniGetUI is developed by Devolutions and is not affiliated with any of the compatible package managers.": "UniGetUI распрацоўваецца Devolutions і не звязаны ні з адным з сумяшчальных менеджараў пакетаў.", + "UniGetUI wouldn't have been possible without the help of the contributors. Thank you all 🥳": "UniGetUI быў бы немагчымы без дапамогі ўсіх удзельнікаў. Дзякуй вам 🥳", + "UniGetUI uses the following libraries. Without them, UniGetUI wouldn't have been possible.": "UniGetUI выкарыстоўвае наступныя бібліятэкі - без іх ён немагчымы.", + "{0} homepage": "Сайт {0}", + "UniGetUI has been translated to more than 40 languages thanks to the volunteer translators. Thank you 🤝": "UniGetUI перакладзены на больш чым 40 моў дзякуючы валанцёрам. Дзякуй 🤝", + "Verbose": "Падрабязна", + "1 - Errors": "1 - Збоі", + "2 - Warnings": "2 - Папярэджанні", + "3 - Information (less)": "3 - Інфармацыя (менш)", + "4 - Information (more)": "4 - Інфармацыя (больш)", + "5 - information (debug)": "5 - Інфармацыя (адладка)", + "Warning": "Папярэджанне", + "The following settings may pose a security risk, hence they are disabled by default.": "Наступныя налады рызыкоўныя - адключаны па змаўчанні.", + "Enable the settings below if and only if you fully understand what they do, and the implications they may have.": "Уключайце ніжэйшыя параметры ТОЛЬКІ калі разумееце іх наступствы і рызыкі.", + "The settings will list, in their descriptions, the potential security issues they may have.": "Апісанні налад паказваюць магчымыя рызыкі бяспекі.", + "The backup will include the complete list of the installed packages and their installation options. Ignored updates and skipped versions will also be saved.": "Рэзервовая копія утрымлівае спіс усталяваных пакетаў і іх параметры. Таксама ігнараваныя абнаўленні і прапушчаныя версіі.", + "The backup will NOT include any binary file nor any program's saved data.": "Рэзервовая копію НЕ ўключае ні бінарныя файлы ні даныя праграм.", + "The size of the backup is estimated to be less than 1MB.": "Памер рэзерву меркавана менш за 1 МБ.", + "The backup will be performed after login.": "Рэзервовая копію будзе створаны пасля ўваходу.", + "{pcName} installed packages": "Пакеты на {pcName}", + "Current status: Not logged in": "Статус: не ўвайшлі", + "You are logged in as {0} (@{1})": "Вы ўвайшлі як {0} (@{1})", + "Nice! Backups will be uploaded to a private gist on your account": "Цудоўна! Рэзервовыя копіі будуць загружаныя ў прыватны gist вашага акаўнта", + "Select backup": "Абраць рэзервовую копію", + "Settings imported from {0}": "Налады імпартаваны з {0}", + "UniGetUI Settings": "Налады UniGetUI", + "Settings exported to {0}": "Налады экспартаваны ў {0}", + "UniGetUI settings were reset": "Налады UniGetUI скінуты", + "Allow pre-release versions": "Дазволіць папярэднія версіі", + "Apply": "Ужыць", + "For security reasons, custom command-line arguments are disabled by default. Go to UniGetUI security settings to change this.": "З меркаванняў бяспекі карыстальніцкія аргументы каманднага радка па змаўчанні адключаны. Каб змяніць гэта, перайдзіце ў налады бяспекі UniGetUI.", + "Go to UniGetUI security settings": "Адкрыць налады бяспекі UniGetUI", + "The following options will be applied by default each time a {0} package is installed, upgraded or uninstalled.": "Наступныя параметры па змаўчанні для кожнага ўсталявання/абнаўлення/выдалення пакета {0}.", + "Package's default": "Па змаўчанні пакета", + "Install location can't be changed for {0} packages": "Месца ўсталявання нельга змяніць для пакетаў {0}", + "The local icon cache currently takes {0} MB": "Лакальны кэш ікон займае {0} МБ", + "Username": "Імя карыстальніка", + "Password": "Пароль", + "Credentials": "Уліковыя даныя", + "It is not guaranteed that the provided credentials will be stored safely": "Няма гарантыі, што прадастаўленыя ўліковыя даныя будуць захоўвацца бяспечна", + "Partially": "Часткова", + "Package manager": "Мэнэджар пакетаў", + "Compatible with proxy": "Сумяшчальна з проксі", + "Compatible with authentication": "Сумяшчальна з аўтэнтыфікацыяй", + "Proxy compatibility table": "Табліца сумяшчальнасці проксі", + "{0} settings": "Налады {0}", + "{0} status": "Статус {0}", + "Default installation options for {0} packages": "Параметры ўсталявання па змаўчанні для пакетаў {0}", + "Expand version": "Разгарнуць версію", + "The executable file for {0} was not found": "Выканальны файл {0} не знойдзены", + "{pm} is disabled": "{pm} адключаны", + "Enable it to install packages from {pm}.": "Уключыце, каб усталёўваць пакеты з {pm}.", + "{pm} is enabled and ready to go": "{pm} уключаны і гатовы", + "{pm} version:": "Версія {pm}:", + "{pm} was not found!": "{pm} не знойдзены!", + "You may need to install {pm} in order to use it with UniGetUI.": "Магчыма трэба ўсталяваць {pm} для выкарыстання з UniGetUI.", + "Scoop Installer - UniGetUI": "Усталёўшчык Scoop - UniGetUI", + "Scoop Uninstaller - UniGetUI": "Выдаленне Scoop - UniGetUI", + "Clearing Scoop cache - UniGetUI": "Ачыстка кэша Scoop - UniGetUI", + "Restart UniGetUI to fully apply changes": "Перазапусціце UniGetUI, каб цалкам прымяніць змены", + "Restart UniGetUI": "Перазапусціць UniGetUI", + "Manage {0} sources": "Рэгуляваць {0} крыніцы", + "Add source": "Дадаць крыніцу", + "Add": "Дадаць", + "Source name": "Назва крыніцы", + "Source URL": "URL крыніцы", + "Other": "Іншае", + "No minimum age": "Без мінімальнага ўзросту", + "1 day": "1 дзень", + "{0} days": "{0} дзён", + "Custom...": "Уласны...", + "{0} minutes": "{0} хвілін", + "1 hour": "1 гадзіна", + "{0} hours": "{0} гадзін", + "1 week": "1 тыдзень", + "Supports release dates": "Падтрымлівае даты выпуску", + "Release date support per package manager": "Падтрымка дат выпуску для кожнага мэнэджара пакетаў", + "Search for packages": "Пошук пакетаў", + "Local": "Лакальна", + "OK": "OK", + "Last checked: {0}": "Апошняя праверка: {0}", + "{0} packages were found, {1} of which match the specified filters.": "Знойдзена {0} пакетаў, {1} адпавядае фільтрам.", + "{0} selected": "Абрана {0}", + "(Last checked: {0})": "(Апошняя праверка: {0})", + "All packages selected": "Усе пакеты абраны", + "Package selection cleared": "Выбар пакетаў ачышчаны", + "{0}: {1}": "{0}: {1}", + "More info": "Больш інфармацыі", + "GitHub account": "Акаўнт GitHub", + "Log in with GitHub to enable cloud package backup.": "Увайдзіце праз GitHub, каб уключыць воблачную копію пакетаў.", + "More details": "Больш падрабязнасцей", + "Log in": "Увайсці", + "If you have cloud backup enabled, it will be saved as a GitHub Gist on this account": "Калі ўключана воблачная копія, яна захоўваецца як GitHub Gist гэтага акаўнта", + "Log out": "Выйсці", + "About UniGetUI": "Аб UniGetUI", + "About": "Аб праграме", + "Third-party licenses": "Ліцэнзіі трэціх бакоў", + "Contributors": "Удзельнікі", + "Translators": "Перакладчыкі", + "Bundle security report": "Справаздача бяспекі набора", + "The bundle contained restricted content": "Набор утрымліваў абмежаваны змест", + "UniGetUI – Crash Report": "UniGetUI – Справаздача аб аварыі", + "UniGetUI has crashed": "UniGetUI аварыйна завяршыўся", + "Help us fix this by sending a crash report to Devolutions. All fields below are optional.": "Дапамажыце выправіць гэта, адправіўшы справаздачу аб аварыі ў Devolutions. Усе палі ніжэй неабавязковыя.", + "Email (optional)": "Электронная пошта (неабавязкова)", + "your@email.com": "ваш@email.com", + "Additional details (optional)": "Дадатковыя падрабязнасці (неабавязкова)", + "Describe what you were doing when the crash occurred…": "Апішыце, што вы рабілі, калі адбылася аварыя…", + "Crash report": "Справаздача аб аварыі", + "Don't Send": "Не адпраўляць", + "Send Report": "Адправіць справаздачу", + "Sending…": "Адпраўка…", + "Unsaved changes": "Незахаваныя змены", + "You have unsaved changes in the current bundle. Do you want to discard them?": "У бягучым наборы ёсць незахаваныя змены. Хочаце іх адкінуць?", + "Discard changes": "Адкінуць змены", + "Integrity violation": "Парушэнне цэласнасці", + "UniGetUI or some of its components are missing or corrupt. It is strongly recommended to reinstall UniGetUI to adress the situation.": "UniGetUI або некаторыя яго кампаненты адсутнічаюць ці пашкоджаныя. Настойліва рэкамендуецца пераўсталяваць UniGetUI, каб выправіць сітуацыю.", + "• Refer to the UniGetUI Logs to get more details regarding the affected file(s)": "• Глядзіце логі UniGetUI для падрабязнасцей пра файл(ы)", + "• Integrity checks can be disabled from the Experimental Settings": "• Праверкі цэласнасці можна адключыць у эксперыментальных наладах", + "Manage shortcuts": "Рэгуляваць цэтлікі", + "UniGetUI has detected the following desktop shortcuts which can be removed automatically on future upgrades": "Знойдзены ярлыкі, якія можна аўтаматычна выдаляць у будучыні", + "Do you really want to reset this list? This action cannot be reverted.": "Скід спісу незваротны. Працягнуць?", + "Desktop shortcuts list": "Спіс ярлыкоў на працоўным стале", + "Open in explorer": "Адкрыць у Правадніку", + "Remove from list": "Выдаліць са спісу", + "When new shortcuts are detected, delete them automatically instead of showing this dialog.": "Пры выяўленні новых ярлыкоў - выдаляць без дыялогу", + "Not right now": "Не цяпер", + "Missing dependency": "Адсутнічае залежнасць", + "UniGetUI requires {0} to operate, but it was not found on your system.": "Для працы патрабуецца {0}, але яго не знойдзена.", + "Click on Install to begin the installation process. If you skip the installation, UniGetUI may not work as expected.": "Націсніце Усталяваць, каб пачаць. Калі прапусціце, UniGetUI можа працаваць некарэктна.", + "Alternatively, you can also install {0} by running the following command in a Windows PowerShell prompt:": "Таксама можна ўсталяваць {0} праз наступную каманду ў PowerShell:", + "Install {0}": "Усталяваць {0}", + "Do not show this dialog again for {0}": "Больш не паказваць гэта акно на {0}", + "Please wait while {0} is being installed. A black window may show up. Please wait until it closes.": "Пачакайце пакуль усталёўваецца {0}. Можа з'явіцца чорнае (ці сіняе) акно. Пачакайце пакуль яно закрыецца.", + "{0} has been installed successfully.": "{0} паспяхова ўсталяваны.", + "Please click on \"Continue\" to continue": "Націсніце \"Працягнуць\" каб працягнуць", + "Continue": "Працягнуць", + "{0} has been installed successfully. It is recommended to restart UniGetUI to finish the installation": "{0} усталяваны. Рэкамендуецца перазапусціць UniGetUI", + "Restart later": "Перазапусціць пазней", + "An error occurred:": "Адбылася памылка:", + "Please see the Command-line Output or refer to the Operation History for further information about the issue.": "Глядзіце вывад каманднага радка або звярніцеся да гісторыі аперацый, каб атрымаць больш звестак пра праблему.", + "Retry as administrator": "Паўтарыць як адміністратар", + "Retry interactively": "Паўтарыць інтэрактыўна", + "Retry skipping integrity checks": "Паўтарыць без праверкі цэласнасці", + "Installation options": "Параметры ўсталявання", + "Save": "Захаваць", + "UniGetUI collects anonymous usage data with the sole purpose of understanding and improving the user experience.": "UniGetUI збірае ананімныя даныя толькі дзеля паляпшэння UX.", + "More details about the shared data and how it will be processed": "Больш пра даные і іх апрацоўку", + "Do you accept that UniGetUI collects and sends anonymous usage statistics, with the sole purpose of understanding and improving the user experience?": "Пагаджаецеся на збор ананімнай статыстыкі для паляпшэння UX?", + "Decline": "Адхіліць", + "No personal information is collected nor sent, and the collected data is anonimized, so it can't be back-tracked to you.": "Асабістыя даныя не збіраюцца; усё ананімізавана і не прывязана да вас", + "Navigation panel": "Панэль навігацыі", + "Operations": "Аперацыі", + "Toggle operations panel": "Пераключыць панэль аперацый", + "Bulk operations": "Масавыя аперацыі", + "Retry failed": "Паўтарыць няўдалыя", + "Clear successful": "Ачысціць паспяховыя", + "Clear finished": "Ачысціць завершаныя", + "Cancel all": "Скасаваць усё", + "More": "Болей", + "Toggle navigation panel": "Пераключыць панэль навігацыі", + "Minimize": "Згарнуць", + "Maximize": "Разгарнуць", + "UniGetUI by Devolutions": "UniGetUI ад Devolutions", + "UniGetUI is an application that makes managing your software easier, by providing an all-in-one graphical interface for your command-line package managers.": "UniGetUI дазваляе лягчэй кіраваць праграмным забеспячэннем праз адзіны графічны інтэрфейс для каманднага радка менеджараў пакетаў.", + "Useful links": "Карысныя спасылкі", + "UniGetUI Homepage": "Хатняя старонка UniGetUI", + "Report an issue or submit a feature request": "Паведаміць пра памылку або прапанаваць функцыю", + "UniGetUI Repository": "Рэпазіторый UniGetUI", + "View GitHub Profile": "Прагляд профілю GitHub", + "UniGetUI License": "Ліцэнзія UniGetUI", + "Using UniGetUI implies the acceptation of the MIT License": "Выкарыстанне UniGetUI азначае прыняцце ліцэнзіі MIT", + "Become a translator": "Стаць перакладчыкам", + "Go back": "Назад", + "Go forward": "Наперад", + "Go to home page": "На хатнюю старонку", + "Reload page": "Перазагрузіць старонку", + "View page on browser": "Адкрыць у браўзеры", + "The built-in browser is not supported on Linux yet.": "Убудаваны браўзер пакуль не падтрымліваецца ў Linux.", + "Open in browser": "Адкрыць у браўзеры", + "Copy to clipboard": "Капіяваць у буфер", + "Export to a file": "Экспартаваць у файл", + "Log level:": "Узровень лагавання:", + "Reload log": "Перазагрузіць лог", + "Export log": "Экспартаваць лог", + "Text": "Тэкст", + "Change how operations request administrator rights": "Змяніць спосаб запыту правоў адміністратара", + "Restrictions on package operations": "Абмежаванні аперацый пакетаў", + "Restrictions on package managers": "Абмежаванні для мэнэджараў пакетаў", + "Restrictions when importing package bundles": "Абмежаванні імпарту набораў", + "Ask for administrator privileges once for each batch of operations": "Запытваць правы адміністратара адзін раз на партыю аперацый", + "Ask only once for administrator privileges": "Запытаць толькі раз", + "Prohibit any kind of Elevation via UniGetUI Elevator or GSudo": "Забараніць павышэнне прывілеяў праз UniGetUI Elevator або GSudo", + "This option WILL cause issues. Any operation incapable of elevating itself WILL FAIL. Install/update/uninstall as administrator will NOT WORK.": "Гэта опцыя выкліча праблемы. Аперацыі без самапазняцця будуць ПАДАЛЕ. Устал./абнаўл./выдал. як адміністратар НЕ ПРАЦУЕ.", + "Allow custom command-line arguments": "Дазволіць ўвод уласных аргументаў каманднага радка", + "Custom command-line arguments can change the way in which programs are installed, upgraded or uninstalled, in a way UniGetUI cannot control. Using custom command-lines can break packages. Proceed with caution.": "Уласныя аргументы могуць змяніць працэс усталявання/абнаўлення/выдалення. Будзьце асцярожныя - гэта можа сапсаваць пакеты.", + "Ignore custom pre-install and post-install commands when importing packages from a bundle": "Дазволіць выкананне карыстальніцкіх каманд перад і пасля ўсталявання пры імпарце пакетаў з набору", + "Pre and post install commands will be run before and after a package gets installed, upgraded or uninstalled. Be aware that they may break things unless used carefully": "Скрыпты запускаюцца да і пасля ўсталявання / абнаўлення / выдалення і могуць пашкодзіць сістэму", + "Allow changing the paths for package manager executables": "Дазволіць змяняць шляхі для выканальных файлаў менеджара пакетаў", + "Turning this on enables changing the executable file used to interact with package managers. While this allows finer-grained customization of your install processes, it may also be dangerous": "Уключэнне дазваляе змяняць выканальны файл для мэнэджараў - гнутка, але небяспечна", + "Allow importing custom command-line arguments when importing packages from a bundle": "Дазволіць імпарт уласных аргументаў каманднага радка пры імпарце пакетаў з набору", + "Malformed command-line arguments can break packages, or even allow a malicious actor to gain privileged execution. Therefore, importing custom command-line arguments is disabled by default": "Няправільныя аргументы каманднага радка могуць пашкодзіць пакеты або нават дазволіць злоўмысніку атрымаць прывілеяваны доступ. Таму імпарт карыстальніцкіх аргументаў каманднага радка па змаўчанні адключаны.", + "Allow importing custom pre-install and post-install commands when importing packages from a bundle": "Дазволіць імпарт перад- і паслякамандаў пры імпарце з набора", + "Pre and post install commands can do very nasty things to your device, if designed to do so. It can be very dangerous to import the commands from a bundle, unless you trust the source of that package bundle": "Каманды перад і пасля ўстаноўкі могуць быць небяспечныя. Імпартуйце толькі з давераных крыніц.", + "Administrator rights and other dangerous settings": "Правы адміністратара і іншыя небяспечныя налады", + "Package backup": "Рэзерваванне пакетаў", + "Cloud package backup": "Воблачная копія пакетаў", + "Local package backup": "Лакальнае рэзерваванне пакетаў", + "Local backup advanced options": "Пашыраныя параметры лакальнага рэзерву", + "Log in with GitHub": "Увайсці праз GitHub", + "Log out from GitHub": "Выйсці з GitHub", + "Periodically perform a cloud backup of the installed packages": "Перыядычна ствараць воблачную копію спіса ўсталяваных пакетаў", + "Cloud backup uses a private GitHub Gist to store a list of installed packages": "Воблачная копія выкарыстоўвае прыватны GitHub Gist для спісу ўсталяваных пакетаў", + "Perform a cloud backup now": "Стварыць воблачную копію зараз", + "Backup": "Рэзервовае капіраванне", + "Restore a backup from the cloud": "Аднавіць з воблачная копіі", + "Begin the process to select a cloud backup and review which packages to restore": "Пачаць выбар воблачнай копіі і перагляд пакетаў для аднаўлення", + "Periodically perform a local backup of the installed packages": "Перыядычна ствараць лакальную копію пакетаў", + "Perform a local backup now": "Стварыць лакальную копію зараз", + "Change backup output directory": "Змяніць каталог для рэзервовай копіі", + "Set a custom backup file name": "Задаць уласную назву файла рэзерву", + "Leave empty for default": "Пакіньце пустым для значэння па змаўчанні", + "Add a timestamp to the backup file names": "Дабаўляць адзнаку часу ў назвы файлаў рэзервовай копіі", + "Backup and Restore": "Копія і аднаўленне", + "Enable background api (UniGetUI Widgets and Sharing, port 7058)": "Уключыць фонавы API (віджэты і абмен UniGetUI, порт 7058)", + "Wait for the device to be connected to the internet before attempting to do tasks that require internet connectivity.": "Чакаць злучэння з інтэрнэтам перад сеткавымі задачамі", + "Disable the 1-minute timeout for package-related operations": "Адключыць 1-хвілінны таймаўт аперацый", + "Use installed GSudo instead of UniGetUI Elevator": "Выкарыстоўваць усталяваны GSudo замест Elevator", + "Use a custom icon and screenshot database URL": "Уласны URL базы ікон і скрыншотаў", + "Enable background CPU Usage optimizations (see Pull Request #3278)": "Уключыць аптымізацыю выкарыстання CPU у фоне (гл. Pull Request #3278)", + "Perform integrity checks at startup": "Правяраць цэласнасць пры запуску", + "When batch installing packages from a bundle, install also packages that are already installed": "Пры пакетным усталяванні таксама ўсталёўваць ужо ўсталяваныя пакеты", + "Experimental settings and developer options": "Эксперыментальныя і распрацоўніцкія налады", + "Show UniGetUI's version and build number on the titlebar.": "Паказваць версію UniGetUI ў загалоўку", + "Language": "Мова", + "UniGetUI updater": "Абнаўляльнік UniGetUI", + "Telemetry": "Тэлеметрыя", + "Manage UniGetUI settings": "Рэгуляваць налады UniGetUI", + "Related settings": "Звязаныя налады", + "Update UniGetUI automatically": "Аўтаабнаўляць UniGetUI", + "Check for updates": "Праверыць абнаўленні", + "Install prerelease versions of UniGetUI": "Усталёўваць перадрэлізныя версіі UniGetUI", + "Manage telemetry settings": "Рэгуляваць тэлеметрыю", + "Manage": "Кіраванне", + "Import settings from a local file": "Імпартаваць налады з лакальнага файла", + "Import": "Імпарт", + "Export settings to a local file": "Экспартаваць налады ў лакальны файл", + "Export": "Экспарт", + "Reset UniGetUI": "Скінуць UniGetUI", + "User interface preferences": "Налады інтэрфейсу", + "Application theme, startup page, package icons, clear successful installs automatically": "Тэма, стартавая старонка, іконкі пакетаў, аўтаачыстка ўдалых аперацый", + "General preferences": "Агульныя налады", + "UniGetUI display language:": "Мова інтэрфейсу UniGetUI:", + "System language": "Мова сістэмы", + "Is your language missing or incomplete?": "Вашай мовы няма або яна няпоўная?", + "Appearance": "Выгляд", + "UniGetUI on the background and system tray": "UniGetUI у фоне і трэі", + "Package lists": "Спісы пакетаў", + "Use classic mode": "Выкарыстоўваць класічны рэжым", + "Restart UniGetUI to apply this change": "Перазапусціце UniGetUI, каб ужыць гэтае змяненне", + "The classic UI is disabled for beta testers": "Класічны інтэрфейс адключаны для бэта-тэстараў", + "Close UniGetUI to the system tray": "Згарнуць UniGetUI у трэй", + "Manage UniGetUI autostart behaviour": "Кіраванне аўтазапускам UniGetUI", + "Show package icons on package lists": "Паказваць іконкі ў спісах", + "Clear cache": "Ачысціць кэш", + "Select upgradable packages by default": "Абраць абнаўляльныя пакеты па змаўчанні", + "Light": "Светлая", + "Dark": "Цёмная", + "Follow system color scheme": "Сачыць за сістэмнай колеравай схемай", + "Application theme:": "Тэма праграммы:", + "UniGetUI startup page:": "Стартавая старонка UniGetUI:", + "Proxy settings": "Налады проксі", + "Other settings": "Іншыя налады", + "Connect the internet using a custom proxy": "Злучацца праз уласны проксі", + "Please note that not all package managers may fully support this feature": "Не ўсе мэнэджары пакетаў падтрымліваюць гэтую функцыю", + "Proxy URL": "URL проксі", + "Enter proxy URL here": "Увядзіце URL проксі тут", + "Authenticate to the proxy with a user and a password": "Аўтэнтыфікавацца на проксі з дапамогай імя карыстальніка і пароля", + "Internet and proxy settings": "Налады інтэрнэту і проксі", + "Package manager preferences": "Налады мэнэджара пакетаў", + "Ready": "Гатова", + "Not found": "Не знойдзена", + "Notification preferences": "Налады апавяшчэнняў", + "Notification types": "Тыпы апавяшчэнняў", + "The system tray icon must be enabled in order for notifications to work": "Для апавяшчэнняў трэба уключыць значок у трэі", + "Enable UniGetUI notifications": "Уключыць апавяшчэнні UniGetUI", + "Show a notification when there are available updates": "Паказваць апавяшчэнне пра даступныя абнаўленні", + "Show a silent notification when an operation is running": "Паказваць ціхае апавяшчэнне падчас аперацыі", + "Show a notification when an operation fails": "Паказваць апавяшчэнне пры няўдалай аперацыі", + "Show a notification when an operation finishes successfully": "Паказваць апавяшчэнне пра ўдалую аперацыю", + "Concurrency and execution": "Паралелізм і выкананне", + "Automatic desktop shortcut remover": "Аўтавылучэнне ярлыкоў на працоўным стале", + "Choose how many operations should be performed in parallel": "Выберыце, колькі аперацый трэба выконваць паралельна", + "Clear successful operations from the operation list after a 5 second delay": "Выдаляць удалыя аперацыі праз 5 секунд", + "Download operations are not affected by this setting": "На спампоўкі гэта не ўплывае", + "You may lose unsaved data": "Можаце страціць незахаваныя даныя", + "Ask to delete desktop shortcuts created during an install or upgrade.": "Пытаць аб выдаленні ярлыкоў, створаных падчас усталявання/абнаўлення.", + "Package update preferences": "Налады абнаўлення пакетаў", + "Update check frequency, automatically install updates, etc.": "Частата праверкі, аўтаабнаўленні і інш.", + "Reduce UAC prompts, elevate installations by default, unlock certain dangerous features, etc.": "Менш UAC акон, падняцце правоў па змаўчанні, разблакаванне рызыкоўных функцый", + "Package operation preferences": "Налады аперацый пакетаў", + "Enable {pm}": "Уключыць {pm}", + "Not finding the file you are looking for? Make sure it has been added to path.": "Не знаходзіце файл? Праверце, што шлях дададзены ў PATH.", + "Select the executable to be used. The following list shows the executables found by UniGetUI": "Абярыце выканальны файл. Ніжэй спіс знойдзеных UniGetUI файлаў", + "For security reasons, changing the executable file is disabled by default": "З меркаванняў бяспекі змена выканальнага файла адключана па змаўчанні", + "Change this": "Змяніць гэта", + "Copy path": "Капіяваць шлях", + "Current executable file:": "Бягучы выканальны файл:", + "Ignore packages from {pm} when showing a notification about updates": "Ігнараваць пакеты з {pm} у апавяшчэннях пра абнаўленні", + "Update security": "Бяспека абнаўленняў", + "Use global setting": "Выкарыстоўваць глабальную наладу", + "Minimum age for updates": "Мінімальны ўзрост абнаўленняў", + "e.g. 10": "напрыклад, 10", + "Custom minimum age (days)": "Уласны мінімальны ўзрост (у днях)", + "{pm} does not provide release dates for its packages, so this setting will have no effect": "{pm} не падае даты выпуску для сваіх пакетаў, таму гэты параметр не будзе мець эфекту", + "{pm} only provides release dates for some of its packages, so this setting will only apply to those packages": "{pm} падае даты выпуску толькі для некаторых сваіх пакетаў, таму гэтыя налады будуць ужытыя толькі да тых пакетаў", + "Override the global minimum update age for this package manager": "Перавызначыць глабальны мінімальны ўзрост абнаўленняў для гэтага мэнэджара пакетаў", + "View {0} logs": "Прагляд логаў {0}", + "If Python cannot be found or is not listing packages but is installed on the system, ": "Калі Python не ўдаецца знайсці або ён не паказвае пакеты, але ўсталяваны ў сістэме, ", + "Advanced options": "Дадатковыя налады", + "WinGet command-line tool": "Інструмент каманднага радка WinGet", + "Choose which command-line tool UniGetUI uses for WinGet operations when the COM API is not used": "Выберыце, які інструмент каманднага радка UniGetUI будзе выкарыстоўваць для аперацый WinGet, калі COM API не выкарыстоўваецца", + "WinGet COM API": "WinGet COM API", + "Choose whether UniGetUI can use the WinGet COM API before falling back to the command-line tool": "Выберыце, ці можа UniGetUI выкарыстоўваць COM API WinGet перад пераходам да інструмента каманднага радка", + "Reset WinGet": "Скінуць WinGet", + "This may help if no packages are listed": "Можа дапамагчы, калі пакеты не адлюстроўваюцца", + "Force install location parameter when updating packages with custom locations": "Прымусова выкарыстоўваць параметр месца ўсталявання пры абнаўленні пакетаў з карыстальніцкімі шляхамі", + "Install Scoop": "Усталяваць Scoop", + "Uninstall Scoop (and its packages)": "Выдаліць Scoop (і яго пакеты)", + "Run cleanup and clear cache": "Ачысціць і скінуць кэш", + "Run": "Запусціць", + "Enable Scoop cleanup on launch": "Уключыць ачыстку Scoop пры запуску", + "Default vcpkg triplet": "Трыплет vcpkg па змаўчанні", + "Change vcpkg root location": "Змяніць каранёвы каталог vcpkg", + "Reset vcpkg root location": "Скінуць каранёвы каталог vcpkg", + "Open vcpkg root location": "Адкрыць каранёвы каталог vcpkg", + "Language, theme and other miscellaneous preferences": "Мова, тэма і іншыя налады", + "Show notifications on different events": "Паказваць апавяшчэнні пры розных падзеях", + "Change how UniGetUI checks and installs available updates for your packages": "Змяніць як UniGetUI правярае і ўсталёўвае абнаўленні", + "Automatically save a list of all your installed packages to easily restore them.": "Аўтаматычна захоўваць спіс усталяваных пакетаў для хуткага аднаўлення.", + "Enable and disable package managers, change default install options, etc.": "Уключэнне / выключэнне мэнэджараў пакетаў, змена параметраў усталявання па змаўчанні і інш.", + "Internet connection settings": "Налады падключэння да Інтэрнэту", + "Proxy settings, etc.": "Налады проксі і інш.", + "Beta features and other options that shouldn't be touched": "Бэта-функцыі і іншыя рызыкоўныя налады", + "Reload sources": "Перазагрузіць крыніцы", + "Delete source": "Выдаліць крыніцу", + "Known sources": "Вядомыя крыніцы", + "Update checking": "Праверка абнаўленняў", + "Automatic updates": "Аўтаабнаўленні", + "Check for package updates periodically": "Перыядычна правяраць абнаўленні пакетаў", + "Check for updates every:": "Правяраць абнаўленні кожныя:", + "Install available updates automatically": "Аўтаматычна ўсталёўваць даступныя абнаўленні", + "Do not automatically install updates when the network connection is metered": "Не ўсталёўваць аўтаабнаўленні пры лімітаванавай сетцы", + "Do not automatically install updates when the device runs on battery": "Не ўсталёўваць аўтаабнаўленні пры працы ад батарэі", + "Do not automatically install updates when the battery saver is on": "Не ўсталёўваць аўтаабнаўленні пры рэжыме эканоміі", + "Only show updates that are at least the specified number of days old": "Паказваць толькі абнаўленні, якім не менш за зададзеную колькасць дзён", + "Warn me when the installer URL host changes between the installed version and the new version (WinGet only)": "Папярэджваць, калі хост URL усталёўшчыка змяняецца паміж усталяванай і новай версіяй (толькі WinGet)", + "Change how UniGetUI handles install, update and uninstall operations.": "Змяніць як UniGetUI апрацоўвае ўсталяванні, абнаўленні і выдаленні.", + "Navigation": "Навігацыя", + "Check for UniGetUI updates": "Правяраць абнаўленні UniGetUI", + "Quit UniGetUI": "Выйсці з UniGetUI", + "Filters": "Фільтры", + "Sources": "Крыніцы", + "Search for packages to start": "Пачніце з пошуку пакетаў", + "Select all": "Абраць усё", + "Clear selection": "Ачысціць выбар", + "Instant search": "Імгненны пошук", + "Distinguish between uppercase and lowercase": "Адрозніваць вялікія і малыя літары", + "Ignore special characters": "Ігнараваць спецзнакі", + "Search mode": "Рэжым пошуку", + "Both": "Назва і ID пакета", + "Exact match": "Дакладнае супадзенне", + "Show similar packages": "Паказаць падобныя пакеты", + "Loading": "Загрузка", + "Package": "Пакет", + "More options": "Дадатковыя параметры", + "Order by:": "Упарадкаванне:", + "Name": "Назва", + "Id": "ID", + "Ascendant": "Па ўзрастанні", + "Descendant": "Па змяншэнні", + "View modes": "Рэжымы прагляду", + "Reload": "Перазагрузіць", + "Closed": "Закрыта", + "Ascending": "Па ўзрастанні", + "Descending": "Па змяншэнні", + "{0}: {1}, {2}": "{0}: {1}, {2}", + "Order by": "Упарадкаваць па", + "No results were found matching the input criteria": "Няма вынікаў па крытэрыях", + "No packages were found": "Пакеты не былі знойдзены", + "Loading packages": "Загрузка пакетаў", + "Skip integrity checks": "Прапусціць праверку цэласнасці", + "Download selected installers": "Спампаваць выбраныя ўсталёўшчыкі", + "Install selection": "Усталяваць выбранае", + "Install options": "Параметры ўсталявання", + "Add selection to bundle": "Дадаць выбраныя ў набор", + "Download installer": "Спампаваць усталёўшчык", + "Uninstall selection": "Выдаліць выбранае", + "Uninstall options": "Параметры выдалення", + "Ignore selected packages": "Ігнараваць выбраныя пакеты", + "Open install location": "Адкрыць месца ўсталявання", + "Reinstall package": "Пераўсталяваць пакет", + "Uninstall package, then reinstall it": "Выдаліць і пераўсталяваць", + "Ignore updates for this package": "Ігнараваць абнаўленні гэтага пакета", + "WinGet malfunction detected": "Выяўлена няспраўнасць WinGet", + "It looks like WinGet is not working properly. Do you want to attempt to repair WinGet?": "Падобна WinGet працуе няправільна. Паспрабаваць адрамантаваць?", + "Repair WinGet": "Аднавіць WinGet", + "Updates will no longer be ignored for {0}": "Абнаўленні {0} больш не будуць ігнаравацца", + "Updates are now ignored for {0}": "Абнаўленні {0} цяпер ігнаруюцца", + "Do not ignore updates for this package anymore": "Больш не ігнараваць абнаўленні гэтага пакета", + "Add packages or open an existing package bundle": "Дадаць пакеты або адкрыць набор пакетаў", + "Add packages to start": "Дадайце пакеты каб пачаць", + "The current bundle has no packages. Add some packages to get started": "У наборы няма пакетаў. Дадайце некалькі для пачатку", + "New": "Новы", + "Save as": "Захаваць як", + "Create .ps1 script": "Стварыць .ps1 скрыпт", + "Remove selection from bundle": "Выдаліць выбранае з набора", + "Skip hash checks": "Прапускаць праверкі хэша", + "The package bundle is not valid": "Набор пакетаў несапраўдны", + "The bundle you are trying to load appears to be invalid. Please check the file and try again.": "Набор, які вы адкрываеце, хібны. Праверце файл і паўторыце.", + "Package bundle": "Набор пакетаў", + "Could not create bundle": "Немагчыма стварыць набор", + "The package bundle could not be created due to an error.": "Немагчыма стварыць набор пакетаў з-за памылкі.", + "Install script": "Скрыпт усталявання", + "PowerShell script": "Скрыпт PowerShell", + "The installation script saved to {0}": "Скрыпт усталявання захаваны ў {0}", + "An error occurred": "Адбылася памылка", + "An error occurred while attempting to create an installation script:": "Памылка пры стварэнні скрыпту ўсталявання:", + "Hooray! No updates were found.": "Нарэшце! Абнаўленняў не знойдзена.", + "Uninstall selected packages": "Выдаліць выбраныя пакеты", + "Update selection": "Абнавіць выбранае", + "Update options": "Параметры абнаўлення", + "Uninstall package, then update it": "Выдаліць і абнавіць", + "Uninstall package": "Выдаліць пакет", + "Skip this version": "Прапусціць гэтую версію", + "Pause updates for": "Прыпыніць абнаўленні на", + "User | Local": "Карыстальнік | Лакальна", + "Machine | Global": "Камп’ютар | Глабальна", + "The default package manager for Debian/Ubuntu-based Linux distributions.
Contains: Debian/Ubuntu packages": "Стандартны мэнэджар пакетаў для дыстрыбутываў Linux на аснове Debian/Ubuntu.
Змяшчае: Пакеты Debian/Ubuntu", + "The Rust package manager.
Contains: Rust libraries and programs written in Rust": "Мэнэджар пакетаў Rust.
Змяшчае: Бібліятэкі і праграмы на Rust", + "The classical package manager for windows. You'll find everything there.
Contains: General Software": "Класічны мэнэджар пакетаў для Windows. Тут ёсць усё.
Змяшчае: Праграмы агульнага прызначэння", + "The default package manager for RHEL/Fedora-based Linux distributions.
Contains: RPM packages": "Стандартны мэнэджар пакетаў для дыстрыбутываў Linux на аснове RHEL/Fedora.
Змяшчае: Пакеты RPM", + "A repository full of tools and executables designed with Microsoft's .NET ecosystem in mind.
Contains: .NET related tools and scripts": "Рэпазітарый інструментаў і выканальных файлаў для экасістэмы Microsoft .NET.
Змяшчае: Інструменты і сцэнарыі .NET", + "The universal Linux package manager for desktop applications.
Contains: Flatpak applications from configured remotes": "Універсальны мэнэджар пакетаў Linux для настольных праграм.
Змяшчае: Праграмы Flatpak з наладжаных аддаленых крыніц", + "NuPkg (zipped manifest)": "NuPkg (заціснуты маніфест)", + "The Missing Package Manager for macOS (or Linux).
Contains: Formulae, Casks": "Мэнэджар пакетаў, якога не хапала для macOS (або Linux).
Змяшчае: Formulae, Casks", + "Node JS's package manager. Full of libraries and other utilities that orbit the javascript world
Contains: Node javascript libraries and other related utilities": "Мэнэджар пакетаў Node JS. Бібліятэкі і ўтыліты JS
Змяшчае: JS бібліятэкі і ўтыліты", + "The default package manager for Arch Linux and its derivatives.
Contains: Arch Linux packages": "Стандартны мэнэджар пакетаў для Arch Linux і яго вытворных.
Змяшчае: Пакеты Arch Linux", + "Python's library manager. Full of python libraries and other python-related utilities
Contains: Python libraries and related utilities": "Мэнэджар бібліятэк Python. Бібліятэкі і ўтыліты Python
Змяшчае: Бібліятэкі і ўтыліты Python", + "PowerShell's package manager. Find libraries and scripts to expand PowerShell capabilities
Contains: Modules, Scripts, Cmdlets": "Мэнэджар пакетаў PowerShell. Бібліятэкі і скрыпты для пашырэння
Змяшчае: Модулі, скрыпты, Cmdlet", + "extracted": "распакавана", + "Scoop package": "Пакет Scoop", + "Great repository of unknown but useful utilities and other interesting packages.
Contains: Utilities, Command-line programs, General Software (extras bucket required)": "Выдатны рэпазітарый карысных утыліт і цікавых пакетаў.
Змяшчае: Утыліты, камандныя праграмы, праграмнае забеспячэнне (патрабуецца extras bucket)", + "The universal Linux package manager by Canonical.
Contains: Snap packages from the Snapcraft store": "Універсальны мэнэджар пакетаў Linux ад Canonical.
Змяшчае: Пакеты Snap з крамы Snapcraft", + "library": "бібліятэка", + "feature": "функцыя", + "A popular C/C++ library manager. Full of C/C++ libraries and other C/C++-related utilities
Contains: C/C++ libraries and related utilities": "Папулярны мэнэджар бібліятэк C/C++. Мноства бібліятэк і ўтыліт C/C++
Змяшчае: Бібліятэкі і ўтыліты C/C++", + "option": "параметр", + "This package cannot be installed from an elevated context.": "Пакет нельга ўсталяваць з павышанага кантэксту.", + "Please run UniGetUI as a regular user and try again.": "Запусціце UniGetUI як звычайны карыстальнік і паспрабуйце зноў.", + "Please check the installation options for this package and try again": "Праверце параметры ўсталявання гэтага пакета і паўторыце", + "Microsoft's official package manager. Full of well-known and verified packages
Contains: General Software, Microsoft Store apps": "Афіцыйны мэнэджар пакетаў Microsoft. Мноства вядомых правераных пакетаў
Змяшчае: Праграмы агульнага прызначэння, праграмы з Microsoft Store", + "Local PC": "Мясцовы ПК", + "Android Subsystem": "Падсістэма Android", + "Operation on queue (position {0})...": "Аперацыя ў чарзе (пазіцыя {0})...", + "Click here for more details": "Падрабязнасці тут", + "Operation canceled by user": "Аперацыя скасавана карыстальнікам", + "Running PreOperation ({0}/{1})...": "Выконваецца PreOperation ({0}/{1})...", + "PreOperation {0} out of {1} failed, and was tagged as necessary. Aborting...": "PreOperation {0} з {1} завяршылася памылкай і была пазначаная як абавязковая. Скасаванне...", + "PreOperation {0} out of {1} finished with result {2}": "PreOperation {0} з {1} завершана з вынікам {2}", + "Starting operation...": "Запуск аперацыі...", + "Running PostOperation ({0}/{1})...": "Выконваецца PostOperation ({0}/{1})...", + "PostOperation {0} out of {1} failed, and was tagged as necessary. Aborting...": "PostOperation {0} з {1} завяршылася памылкай і была пазначаная як абавязковая. Скасаванне...", + "PostOperation {0} out of {1} finished with result {2}": "PostOperation {0} з {1} завершана з вынікам {2}", + "{package} installer download": "Спампоўка усталёўшчыка {package}", + "{0} installer is being downloaded": "Спампоўваецца ўсталёўшчык {0}", + "Download succeeded": "Спампоўванне завершана ўдала", + "{package} installer was downloaded successfully": "Усталёўшчык {package} паспяхова спампаваны", + "Download failed": "Спампоўка не ўдалася", + "{package} installer could not be downloaded": "Немагчыма спампаваць усталёўшчык {package}", + "{package} Installation": "Усталяванне {package}", + "{0} is being installed": "{0} усталёўваецца", + "Installation succeeded": "Усталяванне завершана ўдала", + "{package} was installed successfully": "{package} паспяхова ўсталяваны", + "Installation failed": "Усталяванне не ўдалося", + "{package} could not be installed": "Немагчыма ўсталяваць {package}", + "{package} Update": "Абнаўленне {package}", + "Update succeeded": "Абнаўленне завершана ўдала", + "{package} was updated successfully": "{package} паспяхова абноўлены", + "Update failed": "Абнаўленне не ўдалося", + "{package} could not be updated": "Немагчыма абнавіць {package}", + "{package} Uninstall": "Выдаленне {package}", + "{0} is being uninstalled": "{0} выдаляецца", + "Uninstall succeeded": "Выдаленне завершана ўдала", + "{package} was uninstalled successfully": "{package} паспяхова выдалены", + "Uninstall failed": "Выдаленне не ўдалося", + "{package} could not be uninstalled": "Немагчыма выдаліць {package}", + "Adding source {source}": "Дадаецца крыніца {source}", + "Adding source {source} to {manager}": "Дадаецца крыніца {source} у {manager}", + "Source added successfully": "Крыніца паспяхова дададзена", + "The source {source} was added to {manager} successfully": "Крыніца {source} паспяхова дададзена ў {manager}", + "Could not add source": "Немагчыма дадаць крыніцу", + "Could not add source {source} to {manager}": "Немагчыма дадаць крыніцу {source} у {manager}", + "Removing source {source}": "Выдаленне крыніцы {source}", + "Removing source {source} from {manager}": "Выдаленне {source} з {manager}", + "Source removed successfully": "Крыніца паспяхова выдалена", + "The source {source} was removed from {manager} successfully": "Крыніца {source} паспяхова выдалена з {manager}", + "Could not remove source": "Немагчыма выдаліць крыніцу", + "Could not remove source {source} from {manager}": "Немагчыма выдаліць {source} з {manager}", + "The package manager \"{0}\" was not found": "Мэнэджар \"{0}\" не знойдзены", + "The package manager \"{0}\" is disabled": "Мэнэджар \"{0}\" адключаны", + "There is an error with the configuration of the package manager \"{0}\"": "Памылка канфігурацыі мэнэджара \"{0}\"", + "The package \"{0}\" was not found on the package manager \"{1}\"": "Пакет \"{0}\" не знойдзены ў мэнэджары \"{1}\"", + "{0} is disabled": "{0} адключаны", + "{0} weeks": "{0} тыдняў", + "1 month": "1 месяц", + "{0} months": "{0} месяцаў", + "Something went wrong": "Нешта пайшло не так", + "An interal error occurred. Please view the log for further details.": "Унутраная памылка. Прагледзьце журнал для падрабязнасцей.", + "No applicable installer was found for the package {0}": "Не знойдзена адпаведнага ўсталёўшчыка для пакета {0}", + "Integrity checks will not be performed during this operation": "Праверкі цэласнасці не будуць выконвацца для гэтай аперацыі", + "This is not recommended.": "Не рэкамендуецца.", + "Run now": "Запусціць цяпер", + "Run next": "Запусціць наступным", + "Run last": "Запусціць апошнім", + "Show in explorer": "Паказаць у провадніку", + "Checked": "Пазначана", + "Unchecked": "Не пазначана", + "This package is already installed": "Пакет ужо ўсталяваны", + "This package can be upgraded to version {0}": "Пакет можна абнавіць да версіі {0}", + "Updates for this package are ignored": "Абнаўленні гэтага пакета ігнаруюцца", + "This package is being processed": "Пакет апрацоўваецца", + "This package is not available": "Пакет недаступны", + "Select the source you want to add:": "Абярыце крыніцу для дадання:", + "Source name:": "Назва крыніцы:", + "Source URL:": "URL крыніцы:", + "An error occurred when adding the source: ": "Памылка пры даданні крыніцы: ", + "Package management made easy": "Кіраванне пакетамі стала прасцей", + "version {0}": "версія {0}", + "[RAN AS ADMINISTRATOR]": "[ЗАПУСК АДМІНІСТРАТАРА]", + "Portable mode": "Партатыўны рэжым", + "DEBUG BUILD": "АДЛАДАЧНАЯ ЗБОРКА", + "Here you can change UniGetUI's behaviour regarding the following shortcuts. Checking a shortcut will make UniGetUI delete it if if gets created on a future upgrade. Unchecking it will keep the shortcut intact": "Тут можна змяніць паводзіны адносна ярлыкоў. Адзначаныя ярлыкі будуць аўтавыдалены пры будучых абнаўленнях, іншыя будуць захаваны.", + "Manual scan": "Ручное сканаванне", + "Existing shortcuts on your desktop will be scanned, and you will need to pick which ones to keep and which ones to remove.": "Існыя ярлыкі на працоўным стале будуць прасканіраваны; выберыце, якія пакінуць, а якія выдаліць.", + "Delete?": "Выдаліць?", + "I understand": "Я разумею", + "Chocolatey setup changed": "Канфігурацыя Chocolatey змянілася", + "UniGetUI no longer includes its own private Chocolatey installation. A legacy UniGetUI-managed Chocolatey installation was detected for this user profile, but system Chocolatey was not found. Chocolatey will stay unavailable in UniGetUI until Chocolatey is installed on the system and UniGetUI is restarted. Applications previously installed through UniGetUI's bundled Chocolatey may still appear under other sources such as Local PC or WinGet.": "UniGetUI больш не ўключае ўласную ўсталёўку Chocolatey. Для гэтага профілю карыстальніка выяўлена старая ўсталёўка Chocolatey, кіраваная UniGetUI, але сістэмны Chocolatey не знойдзены. Chocolatey будзе недаступны ў UniGetUI, пакуль яго не ўсталююць у сістэме і UniGetUI не будзе перазапушчаны. Праграмы, раней усталяваныя праз убудаваны Chocolatey UniGetUI, могуць усё яшчэ з'яўляцца ў іншых крыніцах, такіх як Мясцовы ПК або WinGet.", + "NOTE: This troubleshooter can be disabled from UniGetUI Settings, on the WinGet section": "ЗАЎВАГА: гэты сродак можна адключыць у наладах UniGetUI (раздзел WinGet)", + "Restart": "Перазапуск", + "Are you sure you want to delete all shortcuts?": "Выдаліць усе ярлыкі?", + "Any new shorcuts created during an install or an update operation will be deleted automatically, instead of showing a confirmation prompt the first time they are detected.": "Новыя ярлыкі, створаныя падчас усталявання або абнаўлення, будуць аўтаматычна выдалены без пацвярджэння.", + "Any shorcuts created or modified outside of UniGetUI will be ignored. You will be able to add them via the {0} button.": "Ярлыкі, створаныя або змененыя па-за UniGetUI, будуць ігнаравацца. Можна дадаць іх праз кнопку {0}.", + "Are you really sure you want to enable this feature?": "Сапраўды ўключыць гэтую функцыю?", + "No new shortcuts were found during the scan.": "Падчас сканавання новых ярлыкоў не знойдзена.", + "How to add packages to a bundle": "Як дадаць пакеты ў набор", + "In order to add packages to a bundle, you will need to: ": "Каб дадаць пакеты ў набор неабходна: ", + "1. Navigate to the \"{0}\" or \"{1}\" page.": "1. Перайдзіце на старонку \"{0}\" або \"{1}\".", + "2. Locate the package(s) you want to add to the bundle, and select their leftmost checkbox.": "2. Знайдзіце пакет(ы), якія жадаеце дадаць у набор, і пастаўце птушку ў самым левым слупку.", + "3. When the packages you want to add to the bundle are selected, find and click the option \"{0}\" on the toolbar.": "3. Пасля выбару пакетаў знайдзіце і націсніце \"{0}\" на панэлі інструментаў.", + "4. Your packages will have been added to the bundle. You can continue adding packages, or export the bundle.": "4. Вашы пакеты будуць дададзены ў набор. Можна працягваць дадаваць пакеты або экспартаваць набор.", + "Which backup do you want to open?": "Якую рэзервовую копію загрузіць?", + "Select the backup you want to open. Later, you will be able to review which packages you want to install.": "Абярыце копію, якую хочаце загрузіць. Пазней будзе магчымасць вызначыць, якія пакеты аднавіць.", + "There are ongoing operations. Quitting UniGetUI may cause them to fail. Do you want to continue?": "Ёсць актыўныя аперацыі. Выхад можа выклікаць іх памылку. Працягнуць?", + "UniGetUI or some of its components are missing or corrupt.": "UniGetUI або яго кампаненты адсутнічаюць/пашкоджаны.", + "It is strongly recommended to reinstall UniGetUI to adress the situation.": "Настойліва раім перавсталяваць UniGetUI для вырашэння праблемы.", + "Refer to the UniGetUI Logs to get more details regarding the affected file(s)": "Глядзіце логі UniGetUI для падрабязнасцей пра файл(ы)", + "Integrity checks can be disabled from the Experimental Settings": "Праверкі цэласнасці можна адключыць у эксперыментальных наладах", + "Repair UniGetUI": "Аднавіць UniGetUI", + "Live output": "Жывы вывад", + "This package bundle had some settings that are potentially dangerous, and may be ignored by default.": "Набор меў патэнцыйна небяспечныя налады - яны могуць ігнаравацца.", + "Entries that show in YELLOW will be IGNORED.": "Радкі ЖОЎТАГА колеру будуць ІГНАРАВАНЫ.", + "Entries that show in RED will be IMPORTED.": "Радкі ЧЫРВОНАГА колеру будуць ІМПАРТАВАНЫ.", + "You can change this behavior on UniGetUI security settings.": "Паводзіны можна змяніць у наладах бяспекі UniGetUI.", + "Open UniGetUI security settings": "Адкрыць налады бяспекі UniGetUI", + "Should you modify the security settings, you will need to open the bundle again for the changes to take effect.": "Пасля змены налад бяспекі зноў адкрыйце набор для прымянення.", + "Details of the report:": "Падрабязнасці справаздачы:", + "Are you sure you want to create a new package bundle? ": "Стварыць новы набор пакетаў? ", + "Any unsaved changes will be lost": "Незахаваныя змены будуць страчаныя", + "Warning!": "Увага!", + "For security reasons, custom command-line arguments are disabled by default. Go to UniGetUI security settings to change this. ": "З меркаванняў бяспекі ўласныя аргументы адключаны. Змяніце ў наладах бяспекі UniGetUI.", + "Change default options": "Змяніць налады па змаўчанні", + "Ignore future updates for this package": "Ігнараваць будучыя абнаўленні пакета", + "For security reasons, pre-operation and post-operation scripts are disabled by default. Go to UniGetUI security settings to change this. ": "З меркаванняў бяспекі перад- і пасляскрыпты адключаны. Змяніце ў наладах бяспекі UniGetUI.", + "You can define the commands that will be run before or after this package is installed, updated or uninstalled. They will be run on a command prompt, so CMD scripts will work here.": "Можна задаць каманды да і пасля ўсталявання/абнаўлення/выдалення. Запускаюцца ў CMD.", + "Change this and unlock": "Змяніць і разблакаваць", + "{0} Install options are currently locked because {0} follows the default install options.": "{0} Налады ўсталёўкі заблакаваныя, бо для {0} выкарыстоўваюцца налады па змаўчанні.", + "Unset or unknown": "Не зададзена / невядома", + "This package has no screenshots or is missing the icon? Contrbute to UniGetUI by adding the missing icons and screenshots to our open, public database.": "Няма ікон або скрыншотаў? Дадайце іх у публічную базу UniGetUI.", + "Become a contributor": "Стаць удзельнікам", + "Update to {0} available": "Даступна абнаўленне да {0}", + "Reinstall": "Пераўсталяваць", + "Installer not available": "Усталёўшчык недаступны", + "Version:": "Версія:", + "UniGetUI Version {0}": "UniGetUI версія {0}", + "Performing backup, please wait...": "Стварэнне рэзерву, пачакайце...", + "An error occurred while logging in: ": "Памылка ўваходу: ", + "Fetching available backups...": "Атрыманне даступных рэзервовых копій...", + "Done!": "Гатова!", + "The cloud backup has been loaded successfully.": "Воблачная копію паспяхова загружана.", + "An error occurred while loading a backup: ": "Памылка пры загрузцы рэзервовай копіі: ", + "Backing up packages to GitHub Gist...": "Адпраўка рэзервовай копіі пакетаў у GitHub Gist...", + "Backup Successful": "Рэзервовая копія створана ўдала", + "The cloud backup completed successfully.": "Воблачная копію паспяхова створана.", + "Could not back up packages to GitHub Gist: ": "Немагчыма зрабіць рэзервовую копію ў GitHub Gist: ", + "It is not guaranteed that the provided credentials will be stored safely, so you may as well not use the credentials of your bank account": "Няма гарантый бяспечнага захавання ўліковых даных - не выкарыстоўвайце важныя (банкаўскія) даныя", + "Enable the automatic WinGet troubleshooter": "Уключыць аўтаматычны сродак выпраўлення WinGet", + "Add updates that fail with a 'no applicable update found' to the ignored updates list": "Дадаваць абнаўленні з памылкай 'няма адпаведнага абнаўлення' у спіс ігнараваных", + "Invalid selection": "Няправільны выбар", + "No package was selected": "Не выбрана ніводнага пакета", + "More than 1 package was selected": "Выбрана больш за адзін пакет", + "List": "Спіс", + "Grid": "Сетка", + "Icons": "Іконкі", + "\"{0}\" is a local package and does not have available details": "\"{0}\" - лакальны пакет, падрабязнасці недаступныя", + "\"{0}\" is a local package and is not compatible with this feature": "\"{0}\" - лакальны пакет і ён не падтрымлівае гэтую функцыю", + "Add packages to bundle": "Дадаць пакеты ў набор", + "Preparing packages, please wait...": "Падрыхтоўка пакетаў, пачакайце...", + "Loading packages, please wait...": "Загрузка пакетаў, пачакайце...", + "Saving packages, please wait...": "Захаванне пакетаў, пачакайце...", + "The bundle was created successfully on {0}": "Набор паспяхова створаны ў {0}", + "User profile": "Профіль карыстальніка", + "Error": "Памылка", + "Log in failed: ": "Памылка ўваходу: ", + "Log out failed: ": "Не ўдалося выйсці: ", + "Package backup settings": "Налады рэзервовай копіі пакетаў", + "Manage UniGetUI autostart behaviour from the Settings app": "Кіраванне аўтазапускам UniGetUI", + "Choose how many operations shoulds be performed in parallel": "Выберыце, колькі аперацый трэба выконваць паралельна", + "Something went wrong while launching the updater.": "Памылка пры запуску абнаўлення.", + "Please try again later": "Паспрабуйце пазней", + "Show the release notes after UniGetUI is updated": "Паказваць нататкі выпуску пасля абнаўлення UniGetUI" +} diff --git a/src/Languages/lang_bg.json b/src/Languages/lang_bg.json new file mode 100644 index 0000000..9ca77eb --- /dev/null +++ b/src/Languages/lang_bg.json @@ -0,0 +1,850 @@ +{ + "{0} of {1} operations completed": "Завършени са {0} от {1} операции", + "{0} is now {1}": "{0} вече е {1}", + "Enabled": "Активирано", + "Disabled": "Изключено", + "Privacy": "Поверителност", + "Hide my username from the logs": "Скрий потребителското ми име от дневниците", + "Replaces your username with **** in the logs. Restart UniGetUI to also hide it from already-recorded entries.": "Заменя потребителското ви име с **** в дневниците. Рестартирайте UniGetUI, за да го скриете и от вече записаните записи.", + "Your last update attempt did not complete.": "Последният ви опит за актуализация не завърши.", + "UniGetUI could not confirm whether the update succeeded. Open the log to see what happened.": "UniGetUI не можа да потвърди дали актуализацията е успешна. Отворете дневника, за да видите какво се е случило.", + "View log": "Преглед на дневника", + "The installer reported success but did not restart UniGetUI.": "Инсталаторът отчете успех, но не рестартира UniGetUI.", + "The installer failed to initialize.": "Инсталаторът не можа да се инициализира.", + "Setup was canceled before installation began.": "Инсталацията беше отменена преди да започне.", + "A fatal error occurred during the preparation phase.": "Възникна фатална грешка по време на фазата на подготовка.", + "A fatal error occurred during installation.": "Възникна фатална грешка по време на инсталацията.", + "Installation was canceled while in progress.": "Инсталацията беше отменена, докато беше в ход.", + "The installer was terminated by another process.": "Инсталаторът беше прекратен от друг процес.", + "The preparation phase determined the installation cannot proceed.": "Фазата на подготовка установи, че инсталацията не може да продължи.", + "The installer could not start. UniGetUI may already be running, or you do not have permission to install.": "Инсталаторът не можа да стартира. UniGetUI може вече да работи или да нямате разрешение за инсталиране.", + "Unexpected installer error.": "Неочаквана грешка на инсталатора.", + "We are checking for updates.": "Проверяваме за актуализации.", + "Please wait": "Моля, изчкайте", + "Great! You are on the latest version.": "Чудесно! Вие сте с най-новата версия.", + "There are no new UniGetUI versions to be installed": "Няма нови версии на UniGetUI за инсталиране", + "UniGetUI version {0} is being downloaded.": "UniGetUI версия {0} се изтегля.", + "This may take a minute or two": "Това може да отнеме една, две минути", + "The installer authenticity could not be verified.": "Автентичността на инсталатора не можа да бъде потвърдена.", + "The update process has been aborted.": "Процесът на актуализиране беше прекъснат.", + "Auto-update is not yet available on this platform.": "Автоматичното актуализиране все още не е налично на тази платформа.", + "Please update UniGetUI manually.": "Моля, актуализирайте UniGetUI ръчно.", + "An error occurred when checking for updates: ": "Възникна грешка при проверка за актуализации:", + "The updater could not be launched.": "Програмата за актуализиране не можа да бъде стартирана.", + "The operating system did not start the installer process.": "Операционната система не стартира процеса на инсталатора.", + "UniGetUI is being updated...": "UniGetUI се актуализира...", + "Update installed.": "Актуализацията е инсталирана.", + "UniGetUI was updated successfully, but this running copy was not replaced. This usually means you are running a development build. Close this copy and start the newly-installed version to finish.": "UniGetUI беше актуализиран успешно, но това работещо копие не беше заменено. Това обикновено означава, че използвате версия за разработка. Затворете това копие и стартирайте новоинсталираната версия, за да завършите.", + "The update could not be applied.": "Актуализацията не можа да бъде приложена.", + "Installer exit code {0}: {1}": "Код за изход на инсталатора {0}: {1}", + "Update cancelled.": "Актуализацията е отменена.", + "Authentication was cancelled.": "Удостоверяването е отменено.", + "Installer exit code {0}": "Код за изход на инсталатора {0}", + "Operation in progress": "Изпълнява се операция", + "Please wait...": "Моля изчакайте...", + "Success!": "Успешно!", + "Failed": "Неуспешно", + "An error occurred while processing this package": "Грешка при обработката на този пакет", + "Installer": "Инсталатор", + "Executable": "Изпълним файл", + "MSI": "MSI", + "Compressed file": "Компресиран файл", + "MSIX": "MSIX", + "WinGet was repaired successfully": "WinGet беше поправен успешно", + "It is recommended to restart UniGetUI after WinGet has been repaired": "Препоръчително е да рестартирате UniGetUI след поправяне на WinGet.", + "WinGet could not be repaired": "WinGet не можа да бъде поправен", + "An unexpected issue occurred while attempting to repair WinGet. Please try again later": "Възникна неочакван проблем при опит за поправка на WinGet. Моля, опитайте отново по-късно.", + "Log in to enable cloud backup": "Влезте, за да активирате архивирането в облака", + "Backup Failed": "Резервнито копие е неуспешно", + "Downloading backup...": "Изтегляне на резервното копие...", + "An update was found!": "Намерена е актуализация!", + "{0} can be updated to version {1}": "{0} може да бъде актуализиран до версия {1}", + "Updates found!": "Намерени са актуализации!", + "{0} packages can be updated": "{0} пакета могат да се актуализират", + "{0} is being updated to version {1}": "{0} се актуализира до версия {1}", + "{0} packages are being updated": "{0} пакета се актуализират", + "You have currently version {0} installed": "В момента имате инсталирана версия {0}", + "Desktop shortcut created": "Създаден е пряк път на работния плот", + "UniGetUI has detected a new desktop shortcut that can be deleted automatically.": "UniGetUI откри нов пряк път на работния плот, който може да бъде изтрит автоматично.", + "{0} desktop shortcuts created": "Създадени са {0} преки пътища на работния плот", + "UniGetUI has detected {0} new desktop shortcuts that can be deleted automatically.": "UniGetUI откри {0} нови преки пътища на работния плот, които могат да бъдат изтрити автоматично.", + "Attention required": "Обърнете внимание", + "Restart required": "Нужно е рестрартиране", + "1 update is available": "Налична е 1 актуализация", + "{0} updates are available": "Налични са {0} актуализации", + "Everything is up to date": "Всичко е актуално", + "Discover Packages": "Откриване на пакети", + "Available Updates": "Налични актуализации", + "Installed Packages": "Инсталирани пакети", + "UniGetUI Version {0} by Devolutions": "Версия {0} на UniGetUI от Devolutions", + "Show UniGetUI": "Показване на UniGetUI", + "Quit": "Изход", + "Are you sure?": "Сигурни ли сте?", + "Do you really want to uninstall {0}?": "Наистина ли искате да деинсталирате {0}?", + "Do you really want to uninstall the following {0} packages?": "Наистина ли искате да деинсталирате следните {0} пакети?", + "No": "Не", + "Yes": "Да", + "Partial": "Частично", + "View on UniGetUI": "Преглед в UniGetUI", + "Update": "Актуализиране", + "Open UniGetUI": "Отвори UniGetUI", + "Update all": "Актуализиране на всички", + "Update now": "Актуализирай сега", + "Installer host changed since the installed version.\n": "Хостът на инсталатора се е променил след инсталираната версия.\n", + "This package is on the queue": "Този пакет е в опашката", + "installing": "инсталиране", + "updating": "актуализиране", + "uninstalling": "деинсталиране", + "installed": "инсталиран", + "Retry": "Нов опит", + "Install": "Инсталиране", + "Uninstall": "Деинсталиране", + "Open": "Отвори", + "Operation profile:": "Профил на операцията:", + "Follow the default options when installing, upgrading or uninstalling this package": "Следвайте опциите по подразбиране, когато инсталирате, надграждате или деинсталирате този пакет", + "The following settings will be applied each time this package is installed, updated or removed.": "Следните настройки ще се прилагат всеки път, когато този пакет бъде инсталиран, актуализиран или премахнат.", + "Version to install:": "Версия за инсталиране:", + "Architecture to install:": "Архитектура за инсталиране:", + "Installation scope:": "Обхват на инсталацията:", + "Install location:": "Място на инсталиране:", + "Select": "Избор", + "Reset": "Нулиране", + "Custom install arguments:": "Аргументи за персонализирано инсталиране:", + "Custom update arguments:": "Аргументи за персонализирано деинсталиране:", + "Custom uninstall arguments:": "Аргументи за персонализирано деинсталиране:", + "Pre-install command:": "Команда за предварителна инсталация:", + "Post-install command:": "Команда след инсталиране:", + "Abort install if pre-install command fails": "Прекратяване на инсталирането, ако командата за предварителна инсталация е неуспешна", + "Pre-update command:": "Команда за предварителна актуализация:", + "Post-update command:": "Команда след актуализация:", + "Abort update if pre-update command fails": "Прекратяване на актуализацията, ако командата за предварително актуализиране е неуспешна", + "Pre-uninstall command:": "Команда за предварителна деинсталация:", + "Post-uninstall command:": "Команда след деинсталиране:", + "Abort uninstall if pre-uninstall command fails": "Прекратяване на деинсталирането, ако командата за предварително деинсталиране е неуспешна", + "Command-line to run:": "Команден ред за изпълнение:", + "Save and close": "Запази и затвори", + "General": "Общи", + "Architecture & Location": "Архитектура и местоположение", + "Command-line": "Команден ред", + "Close apps": "Затваряне на приложенията", + "Pre/Post install": "Преди/след инсталиране", + "Select the processes that should be closed before this package is installed, updated or uninstalled.": "Изберете процесите, които трябва да бъдат затворени, преди този пакет да бъде инсталиран, актуализиран или деинсталиран.", + "Write here the process names here, separated by commas (,)": "Напишете тук имената на процесите, разделени със запетаи (,)", + "Try to kill the processes that refuse to close when requested to": "Опитайте се да прекратите процесите, които отказват да се затворят, когато бъдат поискани", + "Run as admin": "Стартиране като администратор", + "Interactive installation": "Интерактивна инсталация", + "Skip hash check": "Пропускане проверката на хеша", + "Uninstall previous versions when updated": "Деинсталирайте предишни версии, когато актуализирате", + "Skip minor updates for this package": "Пропускане на малки актуализации за този пакет", + "Automatically update this package": "Автоматично актуализиране на този пакет", + "{0} installation options": "{0} опции за инсталиране", + "Latest": "Последна", + "PreRelease": "Ранно издаване", + "Default": "По подразбиране", + "Manage ignored updates": "Управление на игнорираните актуализации", + "The packages listed here won't be taken in account when checking for updates. Double-click them or click the button on their right to stop ignoring their updates.": "Пакетите, изброени тук, няма да бъдат взети предвид при проверката за актуализации. Щракнете двукратно върху тях или щракнете върху бутона отдясно, за да спрете игнорирането на техните актуализации.", + "Reset list": "Нулиране на списъка", + "Do you really want to reset the ignored updates list? This action cannot be reverted": "Наистина ли искате да нулирате списъка с игнорирани актуализации? Това действие не може да бъде отменено", + "No ignored updates": "Няма игнорирани актуализации", + "Package Name": "Име на пакета", + "Package ID": "ID на пакета", + "Ignored version": "Игнорирана версия", + "New version": "Нова версия", + "Source": "Източник", + "All versions": "Всички версии", + "Unknown": "Неизвестна", + "Up to date": "Актуално", + "Package {name} from {manager}": "Пакет {name} от {manager}", + "Remove {0} from ignored updates": "Премахване на {0} от игнорираните актуализации", + "Cancel": "Отмяна", + "Administrator privileges": "Администраторски привилегии", + "This operation is running with administrator privileges.": "Тази операция се изпълнява с администраторски права.", + "Interactive operation": "Интерактивна инсталация", + "This operation is running interactively.": "Тази операция се изпълнява интерактивно.", + "You will likely need to interact with the installer.": "Вероятно ще трябва да взаимодействате с инсталатора.", + "Integrity checks skipped": "Пропуснати проверки за целостта", + "Integrity checks will not be performed during this operation.": "Проверките за целостта няма да бъдат извършени по време на тази операция.", + "Proceed at your own risk.": "Продължете на свой собствен риск.", + "Close": "Затвори", + "Loading...": "Зареждане...", + "Installer SHA256": "SHA256 инсталатор", + "Homepage": "Уебсайт", + "Author": "Автор", + "Publisher": "Издател", + "License": "Лиценз", + "Manifest": "Манифест", + "Installer Type": "Тип инсталатор", + "Size": "Размер", + "Installer URL": "Линк към инсталатора", + "Last updated:": "Последна актуализация:", + "Release notes URL": "Бележки за изданието на URL адрес", + "Package details": "Подробности за пакета", + "Dependencies:": "Зависимости:", + "Release notes": "Бележки към изданието", + "Screenshots": "Скрийншотове", + "This package has no screenshots or is missing the icon? Contribute to UniGetUI by adding the missing icons and screenshots to our open, public database.": "Този пакет няма скрийншотове или липсва иконата? Допринесете за UniGetUI, като добавите липсващите икони и скрийншотове към нашата отворена, публична база данни.", + "Version": "Версия", + "Install as administrator": "Инсталиране като администратор", + "Update to version {0}": "Актуализиране до версия {0}", + "Installed Version": "Инсталирана версия", + "Update as administrator": "Актуализиране като администратор", + "Interactive update": "Интерактивна актуализация", + "Uninstall as administrator": "Деинсталиране като администратор", + "Interactive uninstall": "Интерактивна деинсталация", + "Uninstall and remove data": "Деинсталиране и премахване на данните", + "Not available": "Не е наличен", + "Installer SHA512": "SHA512 инсталатор", + "Unknown size": "Неизвестен размер", + "No dependencies specified": "Няма посочени зависимости", + "mandatory": "задължително", + "optional": "по избор", + "UniGetUI {0} is ready to be installed.": "UniGetUI {0} е готов за инсталиране.", + "The update process will start after closing UniGetUI": "Процесът на актуализиране ще започне след затваряне на UniGetUI", + "UniGetUI has been ran as administrator, which is not recommended. When running UniGetUI as administrator, EVERY operation launched from UniGetUI will have administrator privileges. You can still use the program, but we highly recommend not running UniGetUI with administrator privileges.": "UniGetUI е стартиран като администратор, което не се препоръчва. Когато UniGetUI се изпълнява като администратор, ВСЯКА операция, стартирана от UniGetUI, ще има администраторски права. Все още можете да използвате програмата, но силно препоръчваме да не стартирате UniGetUI с администраторски права.", + "Share anonymous usage data": "Споделяне на анонимни данни за употреба", + "UniGetUI collects anonymous usage data in order to improve the user experience.": "UniGetUI събира анонимни данни за употреба, за да подобри потребителското изживяване.", + "Accept": "Приеми", + "Software Updates": "Софтуерни актуализации", + "Package Bundles": "Пакетирани пакети", + "Settings": "Настройки", + "Package Managers": "Мениджъри на пакети", + "UniGetUI Log": "Дневник на UniGetUI", + "Package Manager logs": "Дневник на мениджърът на пакети", + "Operation history": "История на операциите", + "Help": "Помощ", + "UniGetUI": "UniGetUI", + "You have installed UniGetUI Version {0}": "Инсталирали сте UniGetUI версия {0}", + "Disclaimer": "Отказ от отговорност", + "UniGetUI is developed by Devolutions and is not affiliated with any of the compatible package managers.": "UniGetUI е разработен от Devolutions и не е свързан с нито един от съвместимите мениджъри на пакети.", + "UniGetUI wouldn't have been possible without the help of the contributors. Thank you all 🥳": "UniGetUI нямаше да е възможен без помощта на сътрудниците. Благодаря на всички 🥳", + "UniGetUI uses the following libraries. Without them, UniGetUI wouldn't have been possible.": "UniGetUI използва следните библиотеки. Без тях UniGetUI нямаше да е възможен.", + "{0} homepage": "Начална страница {0}", + "UniGetUI has been translated to more than 40 languages thanks to the volunteer translators. Thank you 🤝": "UniGetUI е преведен на повече от 40 езика благодарение на преводачите-доброволци. Благодарим ви 🤝", + "Verbose": "Подробно", + "1 - Errors": "1 - Грешки", + "2 - Warnings": "2 - Предупреждения", + "3 - Information (less)": "3 - Информация (по-малко)", + "4 - Information (more)": "4 - Информация (още)", + "5 - information (debug)": "5 - информация (отстраняване на грешки)", + "Warning": "Внимание", + "The following settings may pose a security risk, hence they are disabled by default.": "Следните настройки могат да представляват риск за сигурността, поради което са деактивирани по подразбиране.", + "Enable the settings below if and only if you fully understand what they do, and the implications they may have.": "Активирайте настройките по-долу, само ако напълно разбирате какво правят и какви последици могат да имат.", + "The settings will list, in their descriptions, the potential security issues they may have.": "В описанията на настройките ще бъдат изброени потенциалните проблеми със сигурността, които може да имат.", + "The backup will include the complete list of the installed packages and their installation options. Ignored updates and skipped versions will also be saved.": "Архивирането ще включва пълния списък с инсталираните пакети и техните опции за инсталиране. Игнорираните актуализации и пропуснатите версии също ще бъдат запазени.", + "The backup will NOT include any binary file nor any program's saved data.": "Резервното копие НЯМА да включва двоичен файл, нито запазени данни на която и да е програма.", + "The size of the backup is estimated to be less than 1MB.": "Размерът на архивното копие се оценява да е под 1MB.", + "The backup will be performed after login.": "Архивирането ще се извърши след влизане в системата.", + "{pcName} installed packages": "{pcName} инсталира пакети", + "Current status: Not logged in": "Текущ статус: Не сте влезли", + "You are logged in as {0} (@{1})": "Влезли сте като {0} (@{1})", + "Nice! Backups will be uploaded to a private gist on your account": "Чудесно! Резервните копия ще бъдат качени в частен gist във вашия акаунт.", + "Select backup": "Изберете архив", + "Settings imported from {0}": "Настройките са импортирани от {0}", + "UniGetUI Settings": "Настройки на UniGetUI", + "Settings exported to {0}": "Настройките са експортирани в {0}", + "UniGetUI settings were reset": "Настройките на UniGetUI бяха нулирани", + "Allow pre-release versions": "Разрешаване на предварителни версии", + "Apply": "Приложи", + "For security reasons, custom command-line arguments are disabled by default. Go to UniGetUI security settings to change this.": "От съображения за сигурност персонализираните аргументи на командния ред са изключени по подразбиране. Отидете в настройките за сигурност на UniGetUI, за да промените това.", + "Go to UniGetUI security settings": "Отидете на настройките за сигурност на UniGetUI", + "The following options will be applied by default each time a {0} package is installed, upgraded or uninstalled.": "Следните опции ще се прилагат по подразбиране всеки път, когато {0} пакет бъде инсталиран, надстроен или деинсталиран.", + "Package's default": "Пакет по подразбиране", + "Install location can't be changed for {0} packages": "Местоположението за инсталиране не може да бъде променено за {0} пакета", + "The local icon cache currently takes {0} MB": "Локалният кеш на иконите в момента заема {0} MB", + "Username": "Потребителско име", + "Password": "Парола", + "Credentials": "Пълномощия", + "It is not guaranteed that the provided credentials will be stored safely": "Не е гарантирано, че предоставените идентификационни данни ще бъдат съхранявани безопасно", + "Partially": "Частично", + "Package manager": "Мениджър на пакети", + "Compatible with proxy": "Съвместим с прокси сървър", + "Compatible with authentication": "Съвместим с удостоверяване", + "Proxy compatibility table": "Таблица за съвместимост на прокси сървъри", + "{0} settings": "{0} настройки", + "{0} status": "Състояние на {0}", + "Default installation options for {0} packages": "Опции за инсталиране по подразбиране за {0} пакети", + "Expand version": "Разгъване на версията", + "The executable file for {0} was not found": "Изпълнимият файл за {0} не е намерен", + "{pm} is disabled": "{pm} е деактивирано", + "Enable it to install packages from {pm}.": "Активирайте го, за да инсталира пакети от {pm}.", + "{pm} is enabled and ready to go": "{pm} е активирано и готово за употреба", + "{pm} version:": "версия {pm}:", + "{pm} was not found!": "{pm} не беше намерен!", + "You may need to install {pm} in order to use it with UniGetUI.": "Може да се наложи да инсталирате {pm}, за да го използвате с UniGetUI.", + "Scoop Installer - UniGetUI": "Scoop инсталатор - UniGetUI", + "Scoop Uninstaller - UniGetUI": "Scoop деинсталатор - UniGetUI", + "Clearing Scoop cache - UniGetUI": "Изчистване на Scoop кеша - UniGetUI", + "Restart UniGetUI to fully apply changes": "Рестартирайте UniGetUI, за да приложите напълно промените", + "Restart UniGetUI": "Рестартирай UniGetUI", + "Manage {0} sources": "Управление на {0} източника", + "Add source": "Добави източник ", + "Add": "Добави", + "Source name": "Име на източника", + "Source URL": "URL адрес на източника", + "Other": "Друго", + "No minimum age": "Без минимален срок", + "1 day": "1 ден", + "{0} days": "{0} дена", + "Custom...": "Персонализирано...", + "{0} minutes": "{0} минути", + "1 hour": "1 час", + "{0} hours": "{0} часа", + "1 week": "1 седмица", + "Supports release dates": "Поддържа дати на издаване", + "Release date support per package manager": "Поддръжка на дати на издаване по мениджър на пакети", + "Search for packages": "Търсене на пакети", + "Local": "Локален", + "OK": "ОК", + "Last checked: {0}": "Последна проверка: {0}", + "{0} packages were found, {1} of which match the specified filters.": "Намерени са {0} пакета, {1} от които отговарят на посочените филтри.", + "{0} selected": "Избрани са {0}", + "(Last checked: {0})": "(Последна проверка: {0})", + "All packages selected": "Всички пакети са избрани", + "Package selection cleared": "Изборът на пакети е изчистен", + "{0}: {1}": "{0}: {1}", + "More info": "Повече информация", + "GitHub account": "GitHub акаунт", + "Log in with GitHub to enable cloud package backup.": "Влезте с GitHub, за да активирате архивирането на пакети в облака.", + "More details": "Още подробности", + "Log in": "Вход", + "If you have cloud backup enabled, it will be saved as a GitHub Gist on this account": "Ако имате активирано архивиране в облака, то ще бъде запазено като GitHub Gist файл в този акаунт.", + "Log out": "Изход", + "About UniGetUI": "Относно UniGetUI", + "About": "Относно", + "Third-party licenses": "Лицензи на трети страни", + "Contributors": "Сътрудници", + "Translators": "Преводачи", + "Bundle security report": "Доклад за сигурността на пакета", + "The bundle contained restricted content": "Пакетът съдържаше ограничено съдържание", + "UniGetUI – Crash Report": "UniGetUI – Доклад за срив", + "UniGetUI has crashed": "UniGetUI се срина", + "Help us fix this by sending a crash report to Devolutions. All fields below are optional.": "Помогнете ни да отстраним проблема, като изпратите доклад за срив до Devolutions. Всички полета по-долу са по избор.", + "Email (optional)": "Имейл (по избор)", + "your@email.com": "your@email.com", + "Additional details (optional)": "Допълнителни подробности (по избор)", + "Describe what you were doing when the crash occurred…": "Опишете какво правехте, когато възникна сривът…", + "Crash report": "Доклад за срив", + "Don't Send": "Не изпращай", + "Send Report": "Изпрати доклада", + "Sending…": "Изпращане…", + "Unsaved changes": "Незапазени промени", + "You have unsaved changes in the current bundle. Do you want to discard them?": "Имате незапазени промени в текущия пакет. Искате ли да ги отхвърлите?", + "Discard changes": "Отхвърли промените", + "Integrity violation": "Нарушение на целостта", + "UniGetUI or some of its components are missing or corrupt. It is strongly recommended to reinstall UniGetUI to adress the situation.": "UniGetUI или някои от неговите компоненти липсват или са повредени. Силно се препоръчва да преинсталирате UniGetUI, за да отстраните проблема.", + "• Refer to the UniGetUI Logs to get more details regarding the affected file(s)": "• Вижте лог файловете на UniGetUI, за да получите повече подробности относно засегнатите файлове.", + "• Integrity checks can be disabled from the Experimental Settings": "• Проверките за целостта могат да бъдат деактивирани от експерименталните настройки", + "Manage shortcuts": "Управление на преките пътища", + "UniGetUI has detected the following desktop shortcuts which can be removed automatically on future upgrades": "UniGetUI откри нов пряк път на работния плот, който може да бъде изтрит автоматично.", + "Do you really want to reset this list? This action cannot be reverted.": "Наистина ли искате да нулирате този списък? Това действието не може да бъде отменено.", + "Desktop shortcuts list": "Списък с преки пътища на работния плот", + "Open in explorer": "Отвори в Explorer", + "Remove from list": "Премахване от списъка", + "When new shortcuts are detected, delete them automatically instead of showing this dialog.": "Когато бъдат открити нови преки пътища, те да се изтриват автоматично, вместо да се показва този диалогов прозорец.", + "Not right now": "Не точно сега", + "Missing dependency": "Липсва зависимост", + "UniGetUI requires {0} to operate, but it was not found on your system.": "UniGetUI изисква {0}, за да работи, но не е намерен във вашата система.", + "Click on Install to begin the installation process. If you skip the installation, UniGetUI may not work as expected.": "Кликнете върху „Инсталиране“, за да започнете процеса на инсталиране. Ако пропуснете инсталацията, UniGetUI може да не работи както се очаква.", + "Alternatively, you can also install {0} by running the following command in a Windows PowerShell prompt:": "Като алтернатива, можете да инсталирате \n{0}\nкато изпълните следната команда в командния ред на Windows PowerShell:", + "Install {0}": "Инсталиране на {0}", + "Do not show this dialog again for {0}": "Не показвай този диалогов прозорец отново за {0}", + "Please wait while {0} is being installed. A black window may show up. Please wait until it closes.": "Моля, изчакайте, докато {0} се инсталира. Може да се появи черен прозорец. Моля, изчакайте, докато се затвори.", + "{0} has been installed successfully.": "{0} е инсталиран успешно.", + "Please click on \"Continue\" to continue": "Моля, кликнете върху „Продължи“, за да продължите", + "Continue": "Продължи", + "{0} has been installed successfully. It is recommended to restart UniGetUI to finish the installation": "{0} е инсталиран успешно. Препоръчително е да рестартирате UniGetUI, за да завършите инсталацията.", + "Restart later": "Да се рестартира по-късно", + "An error occurred:": "Възникна грешка:", + "Please see the Command-line Output or refer to the Operation History for further information about the issue.": "Моля, вижте изхода от командния ред или вижте историята на операциите за допълнителна информация относно проблема.", + "Retry as administrator": "Опитай отново като администратор", + "Retry interactively": "Опитайте отново интерактивно", + "Retry skipping integrity checks": "Опитайте да пропуснете проверките за целостта", + "Installation options": "Инсталационни настройки", + "Save": "Запази", + "UniGetUI collects anonymous usage data with the sole purpose of understanding and improving the user experience.": "UniGetUI събира анонимни данни за употреба с единствената цел да разбере и подобри потребителското изживяване.", + "More details about the shared data and how it will be processed": "Повече подробности за споделените данни и как те ще бъдат обработвани", + "Do you accept that UniGetUI collects and sends anonymous usage statistics, with the sole purpose of understanding and improving the user experience?": "Приемате ли, че UniGetUI събира и изпраща анонимни статистически данни за употреба, с единствената цел да разбере и подобри потребителското изживяване?", + "Decline": "Отказ", + "No personal information is collected nor sent, and the collected data is anonimized, so it can't be back-tracked to you.": "Не се събира и не се изпраща лична информация, а събраните данни са анонимизирани, така че не могат да бъдат проследени обратно до вас.", + "Navigation panel": "Навигационен панел", + "Operations": "Операции", + "Toggle operations panel": "Превключване на панела с операции", + "Bulk operations": "Масови операции", + "Retry failed": "Повторен опит за неуспешните", + "Clear successful": "Изчистване на успешните", + "Clear finished": "Изчистване на завършените", + "Cancel all": "Отмяна на всички", + "More": "Още", + "Toggle navigation panel": "Превключи навигационния панел", + "Minimize": "Минимизирай", + "Maximize": "Максимизирай", + "UniGetUI by Devolutions": "UniGetUI от Devolutions", + "UniGetUI is an application that makes managing your software easier, by providing an all-in-one graphical interface for your command-line package managers.": "UniGetUI е приложение, което улеснява управлението на вашия софтуер, като предоставя графичен интерфейс „всичко в едно“ за вашите мениджъри на пакети от командния ред.", + "Useful links": "Полезни връзки", + "UniGetUI Homepage": "Начална страница на UniGetUI", + "Report an issue or submit a feature request": "Съобщете за проблем или изпратете заявка за функция", + "UniGetUI Repository": "Хранилище на UniGetUI", + "View GitHub Profile": "Преглед на профила в GitHub", + "UniGetUI License": "Лиценз на UniGetUI", + "Using UniGetUI implies the acceptation of the MIT License": "Използването на UniGetUI предполага приемането на лиценза на MIT", + "Become a translator": "Станете преводач", + "Go back": "Назад", + "Go forward": "Напред", + "Go to home page": "Към началната страница", + "Reload page": "Презареждане на страницата", + "View page on browser": "Отваряне на страницата в браузър", + "The built-in browser is not supported on Linux yet.": "Вграденият браузър все още не се поддържа в Linux.", + "Open in browser": "Отваряне в браузър", + "Copy to clipboard": "Копирай в клипбоарда", + "Export to a file": "Експортирай във файл", + "Log level:": "Ниво на дневника:", + "Reload log": "Презареждане на лога", + "Export log": "Експортиране на дневника", + "Text": "Текст", + "Change how operations request administrator rights": "Промяна на начина, по който операциите изискват администраторски права", + "Restrictions on package operations": "Ограничения върху операциите с пакети", + "Restrictions on package managers": "Ограничения за мениджърите на пакети", + "Restrictions when importing package bundles": "Ограничения при импортиране на пакети", + "Ask for administrator privileges once for each batch of operations": "Питайте за администраторски права веднъж за всяка партида от операции", + "Ask only once for administrator privileges": "Попитайте само веднъж за администраторски права", + "Prohibit any kind of Elevation via UniGetUI Elevator or GSudo": "Забранете всякакъв вид актуализации чрез UniGetUI Elevator или GSudo", + "This option WILL cause issues. Any operation incapable of elevating itself WILL FAIL. Install/update/uninstall as administrator will NOT WORK.": "Тази опция ЩЕ причини проблеми. Всяка операция, която не може да се издигне, ЩЕ СЕ ПРОВАЛИ. Инсталирането/актуализирането/деинсталирането като администратор НЯМА да работи.", + "Allow custom command-line arguments": "Разрешаване на персонализирани аргументи от командния ред", + "Custom command-line arguments can change the way in which programs are installed, upgraded or uninstalled, in a way UniGetUI cannot control. Using custom command-lines can break packages. Proceed with caution.": "Персонализираните аргументи на командния ред могат да променят начина, по който програмите се инсталират, надграждат или деинсталират, по начин, който UniGetUI не може да контролира. Използването на персонализирани командни редове може да повреди пакетите. Действайте внимателно.", + "Ignore custom pre-install and post-install commands when importing packages from a bundle": "Игнориране на персонализираните команди преди и след инсталиране при импортиране на пакети от пакет", + "Pre and post install commands will be run before and after a package gets installed, upgraded or uninstalled. Be aware that they may break things unless used carefully": "Командите преди и след инсталирането ще се изпълняват преди и след инсталирането, надграждането или деинсталирането на пакет. Имайте предвид, че те могат да повредят системата, ако не се използват внимателно.", + "Allow changing the paths for package manager executables": "Разрешаване на промяна на пътищата за изпълними файлове на мениджъра на пакети", + "Turning this on enables changing the executable file used to interact with package managers. While this allows finer-grained customization of your install processes, it may also be dangerous": "Включването на това позволява промяна на изпълнимия файл, използван за взаимодействие с мениджърите на пакети. Въпреки че това позволява по-фина персонализация на инсталационните процеси, може да бъде и опасно", + "Allow importing custom command-line arguments when importing packages from a bundle": "Разрешаване на импортиране на персонализирани аргументи от командния ред при импортиране на пакети", + "Malformed command-line arguments can break packages, or even allow a malicious actor to gain privileged execution. Therefore, importing custom command-line arguments is disabled by default": "Неправилно оформените аргументи от командния ред могат да повредят пакетите или дори да позволят на злонамерен участник да получи привилегировано изпълнение. Следователно, импортирането на персонализирани аргументи от командния ред е деактивирано по подразбиране.", + "Allow importing custom pre-install and post-install commands when importing packages from a bundle": "Разрешаване на импортиране на персонализирани команди преди и след инсталиране при импортиране на пакети", + "Pre and post install commands can do very nasty things to your device, if designed to do so. It can be very dangerous to import the commands from a bundle, unless you trust the source of that package bundle": "Командите преди и след инсталирането могат да причинят много неприятни неща на вашето устройство, ако са предназначени за това. Може да бъде много опасно да импортирате командите от пакет, освен ако не се доверявате на източника на този пакет.", + "Administrator rights and other dangerous settings": "Администраторски права и други опасни настройки", + "Package backup": "Архивиране на пакета", + "Cloud package backup": "Архивиране на пакетите в облака", + "Local package backup": "Локално архивиране на пакети", + "Local backup advanced options": "Разширени опции за локално архивиране", + "Log in with GitHub": "Влезте с GitHub", + "Log out from GitHub": "Изход от GitHub", + "Periodically perform a cloud backup of the installed packages": "Периодично правете облачно архивиране на инсталираните пакети", + "Cloud backup uses a private GitHub Gist to store a list of installed packages": "Облачното архивиране използва частен GitHub Gist, за да съхранява списък с инсталирани пакети", + "Perform a cloud backup now": "Направете архивиране в облака сега", + "Backup": "Резервно копие", + "Restore a backup from the cloud": "Възстановяване на резервно копие от облака", + "Begin the process to select a cloud backup and review which packages to restore": "Започнете процеса за избор на облачно архивиране и прегледайте кои пакети да възстановите", + "Periodically perform a local backup of the installed packages": "Периодично правете локално архивиране на инсталираните пакети", + "Perform a local backup now": "Извършете локално архивиране сега", + "Change backup output directory": "Смяна на директорията на архивното копие", + "Set a custom backup file name": "Задаване на персонализирано име на архивния файл", + "Leave empty for default": "Стартиране на подпроцеса...", + "Add a timestamp to the backup file names": "Добавете времева маркировка към имената на файловете за архивиране", + "Backup and Restore": "Резервнито копие и възстановяване", + "Enable background api (UniGetUI Widgets and Sharing, port 7058)": "Активиране на фоновия API (UniGetUI Widgets и Sharing, порт 7058)", + "Wait for the device to be connected to the internet before attempting to do tasks that require internet connectivity.": "Изчакайте устройството да се свърже с интернет, преди да се опитате да извършите задачи, които изискват интернет връзка.", + "Disable the 1-minute timeout for package-related operations": "Деактивирайте 1-минутното изчакване за операции, свързани с пакети", + "Use installed GSudo instead of UniGetUI Elevator": "Използвайте инсталиран GSudo вместо UniGetUI Elevator", + "Use a custom icon and screenshot database URL": "Използвайте персонализирана икона и URL адрес за базата данни за екранни снимки", + "Enable background CPU Usage optimizations (see Pull Request #3278)": "Активирайте оптимизациите за използване на процесора във фонов режим (вижте Заявка #3278)", + "Perform integrity checks at startup": "Извършвайте проверка за целостта при стартиране", + "When batch installing packages from a bundle, install also packages that are already installed": "При пакетно инсталиране на пакети, инсталирайте също и пакети, които вече са инсталирани", + "Experimental settings and developer options": "Експериментални настройки и опции за разработчици", + "Show UniGetUI's version and build number on the titlebar.": "Показване на версията и номера на компилацията на UniGetUI в заглавната лента.", + "Language": "Език", + "UniGetUI updater": "Актуализация на UniGetUI", + "Telemetry": "Телеметрия", + "Manage UniGetUI settings": "Управление на настройките на UniGetUI", + "Related settings": "Свързани настройки", + "Update UniGetUI automatically": "Автоматично актуализиране на UniGetUI", + "Check for updates": "Проверете за актуализации", + "Install prerelease versions of UniGetUI": "Инсталирайте предварителни версии на UniGetUI", + "Manage telemetry settings": "Управление на настройките на телеметрията", + "Manage": "Управление", + "Import settings from a local file": "Импортиране на настройки от локален файл", + "Import": "Импортиране", + "Export settings to a local file": "Експортирай избраните пакети в локален файл", + "Export": "Експортирай", + "Reset UniGetUI": "Нулиране на UniGetUI", + "User interface preferences": "Настройки на потребителския интерфейс", + "Application theme, startup page, package icons, clear successful installs automatically": "Тема на приложението, начална страница, икони на пакети, автоматично изчистване на успешни инсталации", + "General preferences": "Общи настройки", + "UniGetUI display language:": "Език на показване на UniGetUI:", + "System language": "Системен език", + "Is your language missing or incomplete?": "Вашият език липсва или е непълен?", + "Appearance": "Външен вид", + "UniGetUI on the background and system tray": "UniGetUI във фонов режим и системна област", + "Package lists": "Списъци с пакети", + "Use classic mode": "Използване на класически режим", + "Restart UniGetUI to apply this change": "Рестартирайте UniGetUI, за да приложите тази промяна", + "The classic UI is disabled for beta testers": "Класическият интерфейс е изключен за бета тестерите", + "Close UniGetUI to the system tray": "Затвори UniGetUI в системния трей", + "Manage UniGetUI autostart behaviour": "Управление на поведението за автоматично стартиране на UniGetUI", + "Show package icons on package lists": "Показване на икони в списъците с пакети", + "Clear cache": "Изчистване на кеша", + "Select upgradable packages by default": "Избиране на надграждаеми пакети по подразбиране", + "Light": "Светла", + "Dark": "Тъмна", + "Follow system color scheme": "Следване на цветовата схема на системата", + "Application theme:": "Тема на приложението:", + "UniGetUI startup page:": "Стартова страница на UniGetUI:", + "Proxy settings": "Настройки на прокси сървъра", + "Other settings": "Други настройки", + "Connect the internet using a custom proxy": "Свържете се с интернет, използвайки персонализиран прокси сървър", + "Please note that not all package managers may fully support this feature": "Моля, обърнете внимание, че не всички мениджъри на пакети може да поддържат напълно тази функция", + "Proxy URL": "URL адрес на прокси сървър", + "Enter proxy URL here": "Въведете URL адрес на прокси сървъра тук", + "Authenticate to the proxy with a user and a password": "Удостоверяване пред прокси сървъра с потребител и парола", + "Internet and proxy settings": "Настройки за интернет и прокси сървър", + "Package manager preferences": "Настройки на мениджърът на пакети", + "Ready": "Готов", + "Not found": "Не е намерен", + "Notification preferences": "Предпочитания за известия", + "Notification types": "Видове известия", + "The system tray icon must be enabled in order for notifications to work": "Иконата в системния трей трябва да е активирана, за да работят известията", + "Enable UniGetUI notifications": "Включи UniGetUI известията", + "Show a notification when there are available updates": "Показване на известие при наличие на актуализации", + "Show a silent notification when an operation is running": "Показване на тихо известие, когато се изпълнява операция", + "Show a notification when an operation fails": "Показване на известие при неуспешна операция", + "Show a notification when an operation finishes successfully": "Показване на известие при успешно завършване на операция", + "Concurrency and execution": "Паралелност и изпълнение", + "Automatic desktop shortcut remover": "Автоматично премахване на преки пътища от работния плот", + "Choose how many operations should be performed in parallel": "Изберете колко операции да се изпълняват паралелно", + "Clear successful operations from the operation list after a 5 second delay": "Изчистване на успешни операции от списъка с операции след 5-секундно забавяне", + "Download operations are not affected by this setting": "Операциите за изтегляне не се влияят от тази настройка", + "You may lose unsaved data": "Може да загубите незапазени данни", + "Ask to delete desktop shortcuts created during an install or upgrade.": "Поискайте изтриване на преките пътища на работния плот, създадени по време на инсталиране или надстройка.", + "Package update preferences": "Предпочитания за актуализиране на пакети", + "Update check frequency, automatically install updates, etc.": "Честота на проверка на актуализациите, автоматично инсталиране на актуализации и др.", + "Reduce UAC prompts, elevate installations by default, unlock certain dangerous features, etc.": "Намалете UAC подканите, повишете инсталациите по подразбиране, отключете определени опасни функции и др.", + "Package operation preferences": "Предпочитания за работа с пакети", + "Enable {pm}": "Включи {pm}", + "Not finding the file you are looking for? Make sure it has been added to path.": "Не намирате файла, който търсите? Уверете се, че е добавен към пътя.", + "Select the executable to be used. The following list shows the executables found by UniGetUI": "Изберете изпълним файл, който ще се използва. Следният списък показва изпълнимите файлове, намерени от UniGetUI.", + "For security reasons, changing the executable file is disabled by default": "От съображения за сигурност, промяната на изпълнимия файл е деактивирана по подразбиране.", + "Change this": "Промени това", + "Copy path": "Копиране на пътя", + "Current executable file:": "Текущ изпълним файл:", + "Ignore packages from {pm} when showing a notification about updates": "Игнориране на пакети от {pm} при показване на известие за актуализации", + "Update security": "Сигурност на актуализациите", + "Use global setting": "Използване на глобалната настройка", + "Minimum age for updates": "Минимален срок за актуализации", + "e.g. 10": "напр. 10", + "Custom minimum age (days)": "Персонализиран минимален срок (дни)", + "{pm} does not provide release dates for its packages, so this setting will have no effect": "{pm} не предоставя дати на издаване за пакетите си, така че тази настройка няма да има ефект", + "{pm} only provides release dates for some of its packages, so this setting will only apply to those packages": "{pm} предоставя дати на издаване само за някои от пакетите си, така че тази настройка ще се прилага само за тях", + "Override the global minimum update age for this package manager": "Замяна на глобалния минимален срок за актуализации за този мениджър на пакети", + "View {0} logs": "Преглед на {0} лог файлове", + "If Python cannot be found or is not listing packages but is installed on the system, ": "Ако Python не може да бъде намерен или не показва пакети, но е инсталиран на системата, ", + "Advanced options": "Разширени опции", + "WinGet command-line tool": "Инструмент от командния ред на WinGet", + "Choose which command-line tool UniGetUI uses for WinGet operations when the COM API is not used": "Изберете кой инструмент от командния ред UniGetUI да използва за операции с WinGet, когато COM API не се използва", + "WinGet COM API": "WinGet COM API", + "Choose whether UniGetUI can use the WinGet COM API before falling back to the command-line tool": "Изберете дали UniGetUI може да използва WinGet COM API, преди да премине към инструмента от командния ред", + "Reset WinGet": "Нулиране на WinGet", + "This may help if no packages are listed": "Това може да помогне, ако не са изброени пакети", + "Force install location parameter when updating packages with custom locations": "Принудително задаване на параметъра за местоположение при актуализиране на пакети с персонализирани местоположения", + "Install Scoop": "Инсталиране на Scoop", + "Uninstall Scoop (and its packages)": "Деинсталиране на Scoop (и неговите пакети)", + "Run cleanup and clear cache": "Изпълнете почистване и изчистете кеша", + "Run": "Стартирай", + "Enable Scoop cleanup on launch": "Активиране на Scoop cleanup при стартиране", + "Default vcpkg triplet": "Подразбиране vcpkg triplet", + "Change vcpkg root location": "Промяна на местоположението на корена на vcpkg", + "Reset vcpkg root location": "Нулиране на основното местоположение на vcpkg", + "Open vcpkg root location": "Отваряне на основното местоположение на vcpkg", + "Language, theme and other miscellaneous preferences": "Език, тема и други предпочитания", + "Show notifications on different events": "Показване на известия за различни събития", + "Change how UniGetUI checks and installs available updates for your packages": "Променете начина, по който UniGetUI проверява и инсталира наличните актуализации за вашите пакети", + "Automatically save a list of all your installed packages to easily restore them.": "Автоматично запазване на списък с всички инсталирани пакети, за да ги възстановите лесно.", + "Enable and disable package managers, change default install options, etc.": "Активиране и деактивиране на мениджъри на пакети, промяна на опциите за инсталиране по подразбиране и др.", + "Internet connection settings": "Интерактивна актуализация", + "Proxy settings, etc.": "Настройки на прокси сървъра и др.", + "Beta features and other options that shouldn't be touched": "Бета функции и други опции, които не трябва да се пипат", + "Reload sources": "Презареждане на източниците", + "Delete source": "Изтриване на източника", + "Known sources": "Известни източници", + "Update checking": "Проверка за актуализации", + "Automatic updates": "Автоматични актуализации", + "Check for package updates periodically": "Периодично проверяване за актуализации на пакети", + "Check for updates every:": "Проверяване за актуализации на всеки:", + "Install available updates automatically": "Автоматично инсталиране на наличните актуализации", + "Do not automatically install updates when the network connection is metered": "Не инсталирайте автоматично актуализации, когато мрежовата връзка е с ограничено потребление", + "Do not automatically install updates when the device runs on battery": "Не инсталирайте автоматично актуализации, когато устройството работи на батерия", + "Do not automatically install updates when the battery saver is on": "Не инсталирайте автоматично актуализации, когато режимът за пестене на батерията е включен", + "Only show updates that are at least the specified number of days old": "Показвай само актуализации, които са поне на посочения брой дни", + "Warn me when the installer URL host changes between the installed version and the new version (WinGet only)": "Предупреждавай ме, когато хостът на URL адреса на инсталатора се промени между инсталираната и новата версия (само за WinGet)", + "Change how UniGetUI handles install, update and uninstall operations.": "Променете начина, по който UniGetUI обработва операциите при инсталиране, актуализиране и деинсталиране.", + "Navigation": "Навигация", + "Check for UniGetUI updates": "Проверка за актуализации на UniGetUI", + "Quit UniGetUI": "Изход от UniGetUI", + "Filters": "Филтри", + "Sources": "Източници", + "Search for packages to start": "За да започнете, потърсете пакети", + "Select all": "Маркиране на всички", + "Clear selection": "Изчисти избора", + "Instant search": "Незабавно търсене", + "Distinguish between uppercase and lowercase": "Разграничавай големи от малки букви", + "Ignore special characters": "Игнориране на специални символи", + "Search mode": "Режим на търсене", + "Both": "И двата", + "Exact match": "Точно съвпадение", + "Show similar packages": "Показване на подобни пакети", + "Loading": "Зареждане", + "Package": "Пакет", + "More options": "Още опции", + "Order by:": "Подреди по:", + "Name": "Име", + "Id": "Идентификационен номер", + "Ascendant": "Асцендент", + "Descendant": "Потомък", + "View modes": "Режими на изглед", + "Reload": "Презареждане", + "Closed": "Затворено", + "Ascending": "Възходящо", + "Descending": "Низходящо", + "{0}: {1}, {2}": "{0}: {1}, {2}", + "Order by": "Подреди по", + "No results were found matching the input criteria": "Не бяха намерени резултати, съответстващи на въведените критерии", + "No packages were found": "Не бяха намерени пакети", + "Loading packages": "Зареждане на пакети", + "Skip integrity checks": "Пропускане на проверките за цялостност", + "Download selected installers": "Изтегляне на избрани инсталатори", + "Install selection": "Инсталиране на маркираните", + "Install options": "Опции за инсталиране", + "Add selection to bundle": "Добавяне на селекция към групата", + "Download installer": "Изтегляне на инсталатора", + "Uninstall selection": "Деинсталиране на избраното", + "Uninstall options": "Опции за деинсталиране", + "Ignore selected packages": "Игнориране на избраните пакети", + "Open install location": "Отваряне на мястото за инсталиране", + "Reinstall package": "Преинсталиране на пакет", + "Uninstall package, then reinstall it": "Деинсталиране на пакета, и тогава инсталиране наново", + "Ignore updates for this package": "Игнориране на актуализации за този пакет", + "WinGet malfunction detected": "Открита е неизправност в WinGet", + "It looks like WinGet is not working properly. Do you want to attempt to repair WinGet?": "Изглежда, че WinGet не работи правилно. Искате ли да опитате да го поправите?", + "Repair WinGet": "Поправка на WinGet", + "Updates will no longer be ignored for {0}": "Актуализациите вече няма да бъдат игнорирани за {0}", + "Updates are now ignored for {0}": "Актуализациите вече са игнорирани за {0}", + "Do not ignore updates for this package anymore": "Не игнорирайте повече актуализациите за този пакет", + "Add packages or open an existing package bundle": "Отваряне на пакет или съществуващ такъв ", + "Add packages to start": "Добавете пакети, за да започнете", + "The current bundle has no packages. Add some packages to get started": "Текущият пакет няма пакети. Добавете няколко пакета, за да започнете.", + "New": "Нов", + "Save as": "Запази като", + "Create .ps1 script": "Създаване на .ps1 скрипт", + "Remove selection from bundle": "Премахване на селекцията от пакета", + "Skip hash checks": "Пропускане на проверките за хеш", + "The package bundle is not valid": "Пакетът не е валиден", + "The bundle you are trying to load appears to be invalid. Please check the file and try again.": "Пакетът, който се опитвате да заредите, изглежда е невалиден. Моля, проверете файла и опитайте отново.", + "Package bundle": "Пакетиране на пакет", + "Could not create bundle": "Не можа да се създаде пакет", + "The package bundle could not be created due to an error.": "Пакетът не можа да бъде създаден поради грешка.", + "Install script": "Скрипт за инсталиране", + "PowerShell script": "PowerShell скрипт", + "The installation script saved to {0}": "Инсталационният скрипт е запазен в {0}", + "An error occurred": "Възникна грешка", + "An error occurred while attempting to create an installation script:": "Възникна грешка при опит за създаване на инсталационен скрипт:", + "Hooray! No updates were found.": "Ура! Няма намерени актуализации!", + "Uninstall selected packages": "Деинсталиране на избраните пакети", + "Update selection": "Актуализация за на селектираните", + "Update options": "Опции за актуализиране", + "Uninstall package, then update it": "Деинсталиране на пакета, и тогава актуализиция", + "Uninstall package": "Деинсталиране на пакета", + "Skip this version": "Пропускане на тази версия", + "Pause updates for": "Пауза на актуализациите за", + "User | Local": "Потребител | Локално", + "Machine | Global": "Компютър | Глобално", + "The default package manager for Debian/Ubuntu-based Linux distributions.
Contains: Debian/Ubuntu packages": "Мениджърът на пакети по подразбиране за Linux дистрибуции, базирани на Debian/Ubuntu.
Съдържа: пакети за Debian/Ubuntu", + "The Rust package manager.
Contains: Rust libraries and programs written in Rust": "Мениджърът на пакети Rust.
Съдържа: Rust библиотеки и програми, написани на Rust", + "The classical package manager for windows. You'll find everything there.
Contains: General Software": "Оригиналния мениджър за пакети за Windows. Има всичко.
Съдържа: Общ софтуер", + "The default package manager for RHEL/Fedora-based Linux distributions.
Contains: RPM packages": "Мениджърът на пакети по подразбиране за Linux дистрибуции, базирани на RHEL/Fedora.
Съдържа: RPM пакети", + "A repository full of tools and executables designed with Microsoft's .NET ecosystem in mind.
Contains: .NET related tools and scripts": "Хранилище, пълно с инструменти и изпълними файлове, проектирано за екосистемата на .NET на Microsoft.
Съдържа: .NET инструменти и скриптове", + "The universal Linux package manager for desktop applications.
Contains: Flatpak applications from configured remotes": "Универсалният мениджър на пакети за Linux за настолни приложения.
Съдържа: Flatpak приложения от конфигурирани отдалечени хранилища", + "NuPkg (zipped manifest)": "NuPkg (компактен манифест)", + "The Missing Package Manager for macOS (or Linux).
Contains: Formulae, Casks": "Липсващият мениджър на пакети за macOS (или Linux).
Съдържа: Formulae, Casks", + "Node JS's package manager. Full of libraries and other utilities that orbit the javascript world
Contains: Node javascript libraries and other related utilities": "Мениджърът на пакети на Node JS. Е пълен с библиотеки и други помощни програми, които обикалят света на JavaScript.
Съдържа: Библиотеки на Node JavaScript и други свързани помощни програми", + "The default package manager for Arch Linux and its derivatives.
Contains: Arch Linux packages": "Мениджърът на пакети по подразбиране за Arch Linux и неговите производни.
Съдържа: пакети за Arch Linux", + "Python's library manager. Full of python libraries and other python-related utilities
Contains: Python libraries and related utilities": "Мениджър на библиотеки за Python. Съдържа библиотеки за Python и други инструменти, свързани с Python.
Съдържа: библиотеки за Python и свързану инструменти", + "PowerShell's package manager. Find libraries and scripts to expand PowerShell capabilities
Contains: Modules, Scripts, Cmdlets": "Мениджърът на пакети на PowerShell. Намерете библиотеки и скриптове за разширяване на възможностите на PowerShell
Съдържа: Modules, Scripts, Cmdlets", + "extracted": "извлечен", + "Scoop package": "Пакет на Scoop", + "Great repository of unknown but useful utilities and other interesting packages.
Contains: Utilities, Command-line programs, General Software (extras bucket required)": "Чудесно хранилище на малко известни, но полезни инструменти и други интересни пакети.
Съдръжание: Инструменти, програми за командния ред, общ софтуер (изисква кофата \"extras\")", + "The universal Linux package manager by Canonical.
Contains: Snap packages from the Snapcraft store": "Универсалният мениджър на пакети за Linux от Canonical.
Съдържа: Snap пакети от магазина Snapcraft", + "library": "библиотека", + "feature": "функция", + "A popular C/C++ library manager. Full of C/C++ libraries and other C/C++-related utilities
Contains: C/C++ libraries and related utilities": "Популярен мениджър на C/C++ библиотеки. Пълен с C/C++ библиотеки и други C/C++-свързани помощни програми
Съдържа: C/C++ библиотеки и свързани помощни програми", + "option": "опция", + "This package cannot be installed from an elevated context.": "Този пакет не може да бъде инсталиран от повишен контекст.", + "Please run UniGetUI as a regular user and try again.": "Моля, стартирайте UniGetUI като обикновен потребител и опитайте отново.", + "Please check the installation options for this package and try again": "Моля, проверете опциите за инсталиране на този пакет и опитайте отново.", + "Microsoft's official package manager. Full of well-known and verified packages
Contains: General Software, Microsoft Store apps": "Официалният мениждър за пакети на Microsoft. Съдържа добре известни и проверени пакети
Съдържа: общ софтуер, пакети от Microsoft Store", + "Local PC": "Локален ПК", + "Android Subsystem": "Подсистема на Android", + "Operation on queue (position {0})...": "Операция на опашката (позиция {0})...", + "Click here for more details": "Кликнете тук за повече подробности", + "Operation canceled by user": "Операцията е прекъсната от потребителя", + "Running PreOperation ({0}/{1})...": "Изпълнява се PreOperation ({0}/{1})...", + "PreOperation {0} out of {1} failed, and was tagged as necessary. Aborting...": "PreOperation {0} от {1} се провали и беше отбелязана като необходима. Прекратяване...", + "PreOperation {0} out of {1} finished with result {2}": "PreOperation {0} от {1} завърши с резултат {2}", + "Starting operation...": "Стартиране на операцията...", + "Running PostOperation ({0}/{1})...": "Изпълнява се PostOperation ({0}/{1})...", + "PostOperation {0} out of {1} failed, and was tagged as necessary. Aborting...": "PostOperation {0} от {1} се провали и беше отбелязана като необходима. Прекратяване...", + "PostOperation {0} out of {1} finished with result {2}": "PostOperation {0} от {1} завърши с резултат {2}", + "{package} installer download": "изтегляне на инсталатора на {package}", + "{0} installer is being downloaded": "Инсталаторът на {0} се изтегля", + "Download succeeded": "Изтеглянето е успешно", + "{package} installer was downloaded successfully": "Инсталаторът на {package} беше изтеглен успешно", + "Download failed": "Изтеглянето беше неуспешно", + "{package} installer could not be downloaded": "Инсталаторът на {package} не можа да бъде изтеглен", + "{package} Installation": "Инсталация на {package}", + "{0} is being installed": "Инсталаторът на {0} се изтегля", + "Installation succeeded": "Инсталацията е успешна", + "{package} was installed successfully": "{package} беше инсталиран успешно", + "Installation failed": "Инсталацията не бе успешна", + "{package} could not be installed": "{package} не можа да бъде инсталиран", + "{package} Update": "Актуализация на {package}", + "Update succeeded": "Актуализацията е успешна", + "{package} was updated successfully": "{package} беше актуализиран успешно", + "Update failed": "Актуализацията е неуспешна", + "{package} could not be updated": "{package} не можа да бъде актуализиран", + "{package} Uninstall": "Деинсталиране на {package}", + "{0} is being uninstalled": "{0} се деинсталира", + "Uninstall succeeded": "Деинсталирането е успешно", + "{package} was uninstalled successfully": "{package} беше деинсталиран успешно", + "Uninstall failed": "Неуспешно деинсталиране", + "{package} could not be uninstalled": "{package} не можа да бъде деинсталиран", + "Adding source {source}": "Добавете източник {source}", + "Adding source {source} to {manager}": "Добавете източник {source} към {manager}", + "Source added successfully": "Източника беше добавен успешно", + "The source {source} was added to {manager} successfully": "Източникът {source} беше успешно добавен към {manager}", + "Could not add source": "Не можа да се добави източника", + "Could not add source {source} to {manager}": "Не можа да се добави източник {source} към {manager}", + "Removing source {source}": "Премахване на източника {source}", + "Removing source {source} from {manager}": "Премахване на източника {source} от {manager}", + "Source removed successfully": "Източникът е премахнат успешно", + "The source {source} was removed from {manager} successfully": "Източникът {source} беше успешно премахнат от {manager}", + "Could not remove source": "Източникът не можа да бъде премахнат", + "Could not remove source {source} from {manager}": "Не можа да се премахне източникът {source} от {manager}", + "The package manager \"{0}\" was not found": "Мениджърът на пакети „{0}“ не е намерен", + "The package manager \"{0}\" is disabled": "Мениджърът на пакети „{0}“ е деактивиран", + "There is an error with the configuration of the package manager \"{0}\"": "Възникна грешка в конфигурацията на мениджъра на пакети „{0}“", + "The package \"{0}\" was not found on the package manager \"{1}\"": "Пакетът „{0}“ не е намерен в мениджъра на пакети „{1}“", + "{0} is disabled": "{0} е деактивиран", + "{0} weeks": "{0} седмици", + "1 month": "1 месец", + "{0} months": "{0} месеца", + "Something went wrong": "Нещо се обърка", + "An interal error occurred. Please view the log for further details.": "Възникна вътрешна грешка. Моля, вижте лога за повече подробности.", + "No applicable installer was found for the package {0}": "Не е намерен подходящ инсталатор за пакета {0}", + "Integrity checks will not be performed during this operation": "Проверки за целостта няма да се извършват по време на тази операция", + "This is not recommended.": "Това не се препоръчва.", + "Run now": "Стартирай сега", + "Run next": "Стартирай следващия", + "Run last": "Стартирай последния", + "Show in explorer": "Показване в експлорър", + "Checked": "Отметнато", + "Unchecked": "Неотметнато", + "This package is already installed": "Този пакет е вече инсталиран", + "This package can be upgraded to version {0}": "Този пакет може да бъде надстроен до версия {0}", + "Updates for this package are ignored": "Актуализациите за този пакет се игнорират", + "This package is being processed": "Този пакет се обработва", + "This package is not available": "Този пакет не е наличен", + "Select the source you want to add:": "Изберете източника, който искате да добавите:", + "Source name:": "Име на източника:", + "Source URL:": "URL на източника:", + "An error occurred when adding the source: ": "Възникна грешка при добавянето на източника:", + "Package management made easy": "Управлението на пакети е лесно", + "version {0}": "версия {0}", + "[RAN AS ADMINISTRATOR]": "[ИЗПЪЛНЯВАШ КАТО АДМИНИСТРАТОР]", + "Portable mode": "Преносим режим", + "DEBUG BUILD": "ОТЛАДЪЧНА КОМПИЛАЦИЯ", + "Here you can change UniGetUI's behaviour regarding the following shortcuts. Checking a shortcut will make UniGetUI delete it if if gets created on a future upgrade. Unchecking it will keep the shortcut intact": "Тук можете да промените поведението на UniGetUI по отношение на следните преки пътища. Отметването на пряк път ще накара UniGetUI да го изтрие, ако бъде създаден при бъдеща надстройка. Премахването на отметката ще запази прякия път непокътнат.", + "Manual scan": "Ръчно сканиране", + "Existing shortcuts on your desktop will be scanned, and you will need to pick which ones to keep and which ones to remove.": "Съществуващите преки пътища на вашия работен плот ще бъдат сканирани и ще трябва да изберете кои да запазите и кои да премахнете.", + "Delete?": "Да се изтрие ли?", + "I understand": "Разбирам", + "Chocolatey setup changed": "Настройката на Chocolatey е променена", + "UniGetUI no longer includes its own private Chocolatey installation. A legacy UniGetUI-managed Chocolatey installation was detected for this user profile, but system Chocolatey was not found. Chocolatey will stay unavailable in UniGetUI until Chocolatey is installed on the system and UniGetUI is restarted. Applications previously installed through UniGetUI's bundled Chocolatey may still appear under other sources such as Local PC or WinGet.": "UniGetUI вече не включва собствена частна инсталация на Chocolatey. Беше открита наследена инсталация на Chocolatey, управлявана от UniGetUI, за този потребителски профил, но системният Chocolatey не беше намерен. Chocolatey ще остане недостъпен в UniGetUI, докато Chocolatey не бъде инсталиран в системата и UniGetUI не бъде рестартиран. Приложения, инсталирани преди това чрез вградения Chocolatey на UniGetUI, все още може да се показват в други източници като Локален компютър или WinGet.", + "NOTE: This troubleshooter can be disabled from UniGetUI Settings, on the WinGet section": "ЗАБЕЛЕЖКА: Този инструмент за отстраняване на неизправности може да бъде деактивиран от настройките на UniGetUI, в секцията WinGet", + "Restart": "Рестартиране", + "Are you sure you want to delete all shortcuts?": "Сигурни ли сте, че искате да изтриете всички преки пътища?", + "Any new shorcuts created during an install or an update operation will be deleted automatically, instead of showing a confirmation prompt the first time they are detected.": "Всички нови преки пътища, създадени по време на инсталиране или актуализиране, ще бъдат изтрити автоматично, вместо да се показва подкана за потвърждение при първото им откриване.", + "Any shorcuts created or modified outside of UniGetUI will be ignored. You will be able to add them via the {0} button.": "Всички преки пътища, създадени или променени извън UniGetUI, ще бъдат игнорирани. Ще можете да ги добавите чрез бутона \n{0}.", + "Are you really sure you want to enable this feature?": "Наистина ли сте сигурни, че искате да активирате тази функция?", + "No new shortcuts were found during the scan.": "По време на сканирането не бяха открити нови преки пътища.", + "How to add packages to a bundle": "Как да добавя пакети към пакет", + "In order to add packages to a bundle, you will need to: ": "За да добавите пакети към пакет, ще трябва:", + "1. Navigate to the \"{0}\" or \"{1}\" page.": "1. Отидете на страницата „{0}“ или „{1}“.", + "2. Locate the package(s) you want to add to the bundle, and select their leftmost checkbox.": "2. Намерете пакета(ите), които искате да добавите, и изберете най-лявото им квадратче за отметка.", + "3. When the packages you want to add to the bundle are selected, find and click the option \"{0}\" on the toolbar.": "3. Когато пакетите, които искате да добавите, са избрани, намерете и щракнете върху опцията „{0}“ в лентата с инструменти.", + "4. Your packages will have been added to the bundle. You can continue adding packages, or export the bundle.": "4. Вашите пакети ще бъдат добавени. Можете да продължите да добавяте пакети или да ги експортирате.", + "Which backup do you want to open?": "Кой резервен файл искате да отворите?", + "Select the backup you want to open. Later, you will be able to review which packages you want to install.": "Изберете резервното копие, което искате да отворите. По-късно ще можете да прегледате кои пакети искате да инсталирате.", + "There are ongoing operations. Quitting UniGetUI may cause them to fail. Do you want to continue?": "Има текущи операции. Излизането от UniGetUI може да доведе до неуспех. Искате ли да продължите?", + "UniGetUI or some of its components are missing or corrupt.": "UniGetUI или някои от неговите компоненти липсват или са повредени.", + "It is strongly recommended to reinstall UniGetUI to adress the situation.": "Силно се препоръчва да инсталирате UniGetUI, за да разрешите ситуацията.", + "Refer to the UniGetUI Logs to get more details regarding the affected file(s)": "Вижте лог файловете на UniGetUI, за да получите повече подробности относно засегнатите файлове.", + "Integrity checks can be disabled from the Experimental Settings": "Проверките за целостта могат да бъдат деактивирани от експерименталните настройки", + "Repair UniGetUI": "Поправка на UniGetUI", + "Live output": "Представяне на живо", + "This package bundle had some settings that are potentially dangerous, and may be ignored by default.": "Този пакет има някои настройки, които са потенциално опасни и могат да бъдат игнорирани по подразбиране.", + "Entries that show in YELLOW will be IGNORED.": "Записите, които се показват в ЖЪЛТО, ще бъдат ИГНОРИРАНИ.", + "Entries that show in RED will be IMPORTED.": "Записите, които се показват в ЧЕРВЕНО, ще бъдат ИМПОРТИРАНИ.", + "You can change this behavior on UniGetUI security settings.": "Можете да промените това поведение в настройките за сигурност на UniGetUI.", + "Open UniGetUI security settings": "Отворете настройките за сигурност на UniGetUI", + "Should you modify the security settings, you will need to open the bundle again for the changes to take effect.": "Ако промените настройките за сигурност, ще трябва да отворите пакета отново, за да влязат в сила промените.", + "Details of the report:": "Подробности за доклада:", + "Are you sure you want to create a new package bundle? ": "Сигурни ли сте, че искате да създадете нов пакет?", + "Any unsaved changes will be lost": "Всички незапазени промени ще бъдат загубени", + "Warning!": "Внимание!", + "For security reasons, custom command-line arguments are disabled by default. Go to UniGetUI security settings to change this. ": "От съображения за сигурност, персонализираните аргументи на командния ред са деактивирани по подразбиране. Отидете в настройките за сигурност на UniGetUI, за да промените това.", + "Change default options": "Промяна на опциите по подразбиране", + "Ignore future updates for this package": "Игнориране на бъдещи актуализации за този пакет", + "For security reasons, pre-operation and post-operation scripts are disabled by default. Go to UniGetUI security settings to change this. ": "От съображения за сигурност, скриптовете преди и след операцията са деактивирани по подразбиране. Отидете в настройките за сигурност на UniGetUI, за да промените това.", + "You can define the commands that will be run before or after this package is installed, updated or uninstalled. They will be run on a command prompt, so CMD scripts will work here.": "Можете да дефинирате командите, които ще се изпълняват преди или след инсталирането, актуализирането или деинсталирането на този пакет. Те ще се изпълняват в командния ред, така че CMD скриптовете ще работят тук.", + "Change this and unlock": "Променете това и отключете", + "{0} Install options are currently locked because {0} follows the default install options.": "{0} Опциите за инсталиране са заключени в момента, защото {0} следва опциите за инсталиране по подразбиране.", + "Unset or unknown": "Незададено или неизвестно", + "This package has no screenshots or is missing the icon? Contrbute to UniGetUI by adding the missing icons and screenshots to our open, public database.": "Този пакет няма скрийншотове или липсва иконата? Допринесете за UniGetUI, като добавите липсващите икони и скрийншотове към нашата отворена, публична база данни.", + "Become a contributor": "Станете сътрудник", + "Update to {0} available": "Налична е актуализация до {0}", + "Reinstall": "Преинсталирайте", + "Installer not available": "Инсталатора не е наличен", + "Version:": "Версия:", + "UniGetUI Version {0}": "Версия на UniGetUI {0}", + "Performing backup, please wait...": "Извършва се архивиране, моля изчакайте...", + "An error occurred while logging in: ": "Възникна грешка при влизане:", + "Fetching available backups...": "Извличане на наличните резервни копия...", + "Done!": "Готово!", + "The cloud backup has been loaded successfully.": "Архивирането в облака е заредено успешно.", + "An error occurred while loading a backup: ": "Възникна грешка при зареждане на резервното копие:", + "Backing up packages to GitHub Gist...": "Резервно копе на пакетите в GitHub Gist...", + "Backup Successful": "Резервнито копие е успешно", + "The cloud backup completed successfully.": "Архивирането в облака завърши успешно.", + "Could not back up packages to GitHub Gist: ": "Не можа да се създаде резервно копие на пакетите в GitHub Gist:", + "It is not guaranteed that the provided credentials will be stored safely, so you may as well not use the credentials of your bank account": "Не е гарантирано, че предоставените идентификационни данни ще бъдат съхранени безопасно, така че е по-добре да не използвате идентификационните данни на банковата си сметка.", + "Enable the automatic WinGet troubleshooter": "Активирайте автоматичния инструмент за отстраняване на неизправности с WinGet", + "Add updates that fail with a 'no applicable update found' to the ignored updates list": "Добавете актуализации, които са неуспешни с „няма намерена приложима актуализация“, към списъка с игнорирани актуализации.", + "Invalid selection": "Невалиден избор", + "No package was selected": "Не е избран пакет", + "More than 1 package was selected": "Избран е повече от 1 пакет", + "List": "Списък", + "Grid": "Решетка", + "Icons": "Икони", + "\"{0}\" is a local package and does not have available details": "\"{0}\" е локален пакет и няма налични подробности", + "\"{0}\" is a local package and is not compatible with this feature": "„{0}“ е локален пакет и не е съвместим с тази функция", + "Add packages to bundle": "Добавяне на пакет към съществуващ", + "Preparing packages, please wait...": "Подготвяме пакетите, моля изчакайте...", + "Loading packages, please wait...": "Зареждане на пакети, моля изчакайте...", + "Saving packages, please wait...": "Запазване на пакетите, моля изчакайте...", + "The bundle was created successfully on {0}": "Пакетът е създаден успешно на {0}", + "User profile": "Потребителски профил", + "Error": "Грешка", + "Log in failed: ": "Влизането не бе успешно:", + "Log out failed: ": "Неуспешен изход:", + "Package backup settings": "Настройки за архивиране на пакети", + "Manage UniGetUI autostart behaviour from the Settings app": "Управление на поведението при автоматично стартиране на UniGetUI", + "Choose how many operations shoulds be performed in parallel": "Изберете колко операции да се извършват паралелно", + "Something went wrong while launching the updater.": "Нещо се обърка при стартирането на програмата за актуализиране.", + "Please try again later": "Опитайте отново по-късно", + "Show the release notes after UniGetUI is updated": "Показване на бележките към изданието след актуализиране на UniGetUI" +} diff --git a/src/Languages/lang_bn.json b/src/Languages/lang_bn.json new file mode 100644 index 0000000..e45a74a --- /dev/null +++ b/src/Languages/lang_bn.json @@ -0,0 +1,850 @@ +{ + "{0} of {1} operations completed": "{1}টির মধ্যে {0}টি অপারেশন সম্পন্ন হয়েছে", + "{0} is now {1}": "{0} এখন {1}", + "Enabled": "সক্ষম", + "Disabled": "অক্ষম", + "Privacy": "গোপনীয়তা", + "Hide my username from the logs": "লগ থেকে আমার ব্যবহারকারীর নাম লুকান", + "Replaces your username with **** in the logs. Restart UniGetUI to also hide it from already-recorded entries.": "লগে আপনার ব্যবহারকারীর নাম **** দিয়ে প্রতিস্থাপন করে। ইতিমধ্যে রেকর্ড করা এন্ট্রিগুলি থেকেও এটি লুকানোর জন্য UniGetUI পুনরায় চালু করুন।", + "Your last update attempt did not complete.": "আপনার সর্বশেষ আপডেটের চেষ্টা সম্পূর্ণ হয়নি।", + "UniGetUI could not confirm whether the update succeeded. Open the log to see what happened.": "UniGetUI আপডেটটি সফল হয়েছে কি না তা নিশ্চিত করতে পারেনি। কী ঘটেছে দেখতে লগ খুলুন।", + "View log": "লগ দেখুন", + "The installer reported success but did not restart UniGetUI.": "ইনস্টলার সাফল্যের কথা জানিয়েছে, কিন্তু UniGetUI পুনরায় চালু করেনি।", + "The installer failed to initialize.": "ইনস্টলার আরম্ভ করতে ব্যর্থ হয়েছে।", + "Setup was canceled before installation began.": "ইনস্টলেশন শুরু হওয়ার আগেই সেটআপ বাতিল করা হয়েছে।", + "A fatal error occurred during the preparation phase.": "প্রস্তুতি পর্যায়ে একটি গুরুতর ত্রুটি ঘটেছে।", + "A fatal error occurred during installation.": "ইনস্টলেশনের সময় একটি গুরুতর ত্রুটি ঘটেছে।", + "Installation was canceled while in progress.": "চলমান অবস্থায় ইনস্টলেশন বাতিল করা হয়েছে।", + "The installer was terminated by another process.": "অন্য একটি প্রক্রিয়া দ্বারা ইনস্টলার বন্ধ করা হয়েছে।", + "The preparation phase determined the installation cannot proceed.": "প্রস্তুতি পর্যায়ে নির্ধারিত হয়েছে যে ইনস্টলেশন এগিয়ে নেওয়া যাবে না।", + "The installer could not start. UniGetUI may already be running, or you do not have permission to install.": "ইনস্টলার শুরু করা যায়নি। UniGetUI ইতিমধ্যেই চলমান থাকতে পারে, অথবা ইনস্টল করার অনুমতি আপনার নেই।", + "Unexpected installer error.": "অপ্রত্যাশিত ইনস্টলার ত্রুটি।", + "We are checking for updates.": "আমরা আপডেটের জন্য চেক করছি।", + "Please wait": "অনুগ্রহপূর্বক অপেক্ষা করুন", + "Great! You are on the latest version.": "দুর্দান্ত! আপনি সর্বশেষ সংস্করণে আছেন।", + "There are no new UniGetUI versions to be installed": "ইনস্টল করার জন্য কোন নতুন UniGetUI সংস্করণ নেই", + "UniGetUI version {0} is being downloaded.": "UniGetUI সংস্করণ {0} ডাউনলোড করা হচ্ছে।", + "This may take a minute or two": "এতে এক বা দুই মিনিট সময় লাগতে পারে", + "The installer authenticity could not be verified.": "ইনস্টলারের সত্যতা যাচাই করা যায়নি।", + "The update process has been aborted.": "আপডেট প্রক্রিয়া বাতিল করা হয়েছে।", + "Auto-update is not yet available on this platform.": "এই প্ল্যাটফর্মে স্বয়ংক্রিয় আপডেট এখনও উপলব্ধ নয়।", + "Please update UniGetUI manually.": "অনুগ্রহ করে UniGetUI ম্যানুয়ালি আপডেট করুন।", + "An error occurred when checking for updates: ": "আপডেটের জন্য পরীক্ষা করার সময় একটি ত্রুটি ঘটেছেঃ", + "The updater could not be launched.": "আপডেটার চালু করা যায়নি।", + "The operating system did not start the installer process.": "অপারেটিং সিস্টেম ইনস্টলার প্রক্রিয়া শুরু করেনি।", + "UniGetUI is being updated...": "UniGetUI আপডেট করা হচ্ছে...", + "Update installed.": "আপডেট ইনস্টল করা হয়েছে।", + "UniGetUI was updated successfully, but this running copy was not replaced. This usually means you are running a development build. Close this copy and start the newly-installed version to finish.": "UniGetUI সফলভাবে আপডেট হয়েছে, কিন্তু চলমান এই কপিটি প্রতিস্থাপিত হয়নি। সাধারণত এর অর্থ আপনি একটি ডেভেলপমেন্ট বিল্ড চালাচ্ছেন। শেষ করতে এই কপিটি বন্ধ করুন এবং নতুন ইনস্টল করা সংস্করণটি শুরু করুন।", + "The update could not be applied.": "আপডেট প্রয়োগ করা যায়নি।", + "Installer exit code {0}: {1}": "ইনস্টলার প্রস্থান কোড {0}: {1}", + "Update cancelled.": "আপডেট বাতিল করা হয়েছে।", + "Authentication was cancelled.": "প্রমাণীকরণ বাতিল করা হয়েছে।", + "Installer exit code {0}": "ইনস্টলার প্রস্থান কোড {0}", + "Operation in progress": "অপারেশন চলছে", + "Please wait...": "একটু অপেক্ষা করুন...", + "Success!": "সাফল্য!", + "Failed": "ব্যর্থ হয়েছে", + "An error occurred while processing this package": "এই প্যাকেজটি প্রক্রিয়া করার সময় একটি ত্রুটি ঘটেছে", + "Installer": "ইনস্টলার", + "Executable": "এক্সিকিউটেবল", + "MSI": "MSI", + "Compressed file": "সংকুচিত ফাইল", + "MSIX": "MSIX", + "WinGet was repaired successfully": "WinGet সফলভাবে মেরামত করা হয়েছে", + "It is recommended to restart UniGetUI after WinGet has been repaired": "WinGet মেরামত করার পর UniGetUI পুনরায় চালু করার সুপারিশ করা হয়", + "WinGet could not be repaired": "WinGet মেরামত করা যায়নি", + "An unexpected issue occurred while attempting to repair WinGet. Please try again later": "WinGet মেরামত করার চেষ্টা করার সময় একটি অপ্রত্যাশিত সমস্যা ঘটেছে। অনুগ্রহ করে পরে আবার চেষ্টা করুন", + "Log in to enable cloud backup": "ক্লাউড ব্যাকআপ সক্ষম করতে লগ ইন করুন", + "Backup Failed": "ব্যাকআপ ব্যর্থ হয়েছে", + "Downloading backup...": "ব্যাকআপ ডাউনলোড করা হচ্ছে...", + "An update was found!": "একটি আপডেট পাওয়া গেছে!", + "{0} can be updated to version {1}": "{0} সংস্করণ {1}-এ আপডেট করা যেতে পারে", + "Updates found!": "আপডেট পাওয়া গেছে!", + "{0} packages can be updated": "{0}টি প্যাকেজ আপডেট করা যেতে পারে", + "{0} is being updated to version {1}": "{0} সংস্করণ {1}-এ আপডেট করা হচ্ছে", + "{0} packages are being updated": "{0}টি প্যাকেজ আপডেট করা হচ্ছে", + "You have currently version {0} installed": "আপনার বর্তমানে সংস্করণ {0} ইনস্টল করা আছে", + "Desktop shortcut created": "ডেস্কটপ শর্টকাট তৈরি করা হয়েছে", + "UniGetUI has detected a new desktop shortcut that can be deleted automatically.": "UniGetUI একটি নতুন ডেস্কটপ শর্টকাট সনাক্ত করেছে যা স্বয়ংক্রিয়ভাবে মুছে ফেলা যেতে পারে।", + "{0} desktop shortcuts created": "{0} ডেস্কটপ শর্টকাট তৈরি করা হয়েছে", + "UniGetUI has detected {0} new desktop shortcuts that can be deleted automatically.": "UniGetUI {0}টি নতুন ডেস্কটপ শর্টকাট সনাক্ত করেছে যা স্বয়ংক্রিয়ভাবে মুছে ফেলা যেতে পারে।", + "Attention required": "মনোযোগ প্রয়োজন", + "Restart required": "রিস্টার্ট প্রয়োজন", + "1 update is available": "১ টি আপডেট উপলব্ধ", + "{0} updates are available": "{0}টি আপডেট উপলব্ধ", + "Everything is up to date": "সবকিছু আপ টু ডেট", + "Discover Packages": "প্যাকেজ আবিষ্কার করুন", + "Available Updates": "উপলব্ধ আপডেট", + "Installed Packages": "ইনস্টল করা প্যাকেজ", + "UniGetUI Version {0} by Devolutions": "Devolutions-এর UniGetUI সংস্করণ {0}", + "Show UniGetUI": "UniGetUI দেখান", + "Quit": "বন্ধ করুন", + "Are you sure?": "আপনি কি নিশ্চিত?", + "Do you really want to uninstall {0}?": "আপনি কি {0} আনইনষ্টল করতে চান?", + "Do you really want to uninstall the following {0} packages?": "আপনি কি সত্যিই নিম্নলিখিত {0} প্যাকেজগুলি আনইনস্টল করতে চান?", + "No": "না", + "Yes": "হ্যাঁ", + "Partial": "আংশিক", + "View on UniGetUI": "UniGetUI-তে দেখুন", + "Update": "হালনাগাদ", + "Open UniGetUI": "UniGetUI খুলুন", + "Update all": "সব হালনাগাদ করুন", + "Update now": "এখনই আপডেট করুন", + "Installer host changed since the installed version.\n": "ইনস্টল করা সংস্করণের পর থেকে ইনস্টলার হোস্ট পরিবর্তিত হয়েছে।\n", + "This package is on the queue": "এই প্যাকেজ সারিতে আছে", + "installing": "ইনস্টল করা হচ্ছে", + "updating": "আপডেট করা হচ্ছে", + "uninstalling": "আনইনস্টল করা হচ্ছে", + "installed": "ইনস্টল করা হয়েছে", + "Retry": "পুনরায় চেষ্টা করা", + "Install": "ইনস্টল", + "Uninstall": "আনইনস্টল", + "Open": "খোলা", + "Operation profile:": "অপারেশন প্রোফাইল:", + "Follow the default options when installing, upgrading or uninstalling this package": "এই প্যাকেজটি ইনস্টল, আপগ্রেড বা আনইনস্টল করার সময় ডিফল্ট বিকল্পগুলি অনুসরণ করুন", + "The following settings will be applied each time this package is installed, updated or removed.": "এই প্যাকেজটি ইনস্টল করা, আপডেট করা বা সরানো হলে নিম্নলিখিত সেটিংস প্রয়োগ করা হবে।", + "Version to install:": "ইনস্টল করার জন্য সংস্করণঃ", + "Architecture to install:": "ইনস্টল করার জন্য আর্কিটেকচারঃ", + "Installation scope:": "ইনস্টলেশন সুযোগ:", + "Install location:": "ইন্টলের জায়গাঃ", + "Select": "নির্বাচন করুন", + "Reset": "রিসেট করুন", + "Custom install arguments:": "কাস্টম ইনস্টল আর্গুমেন্ট:", + "Custom update arguments:": "কাস্টম আপডেট আর্গুমেন্ট:", + "Custom uninstall arguments:": "কাস্টম আনইনস্টল আর্গুমেন্ট:", + "Pre-install command:": "প্রাক-ইনস্টল কমান্ড:", + "Post-install command:": "পোস্ট-ইনস্টল কমান্ড:", + "Abort install if pre-install command fails": "প্রাক-ইনস্টল কমান্ড ব্যর্থ হলে ইনস্টল বাতিল করুন", + "Pre-update command:": "প্রাক-আপডেট কমান্ড:", + "Post-update command:": "পোস্ট-আপডেট কমান্ড:", + "Abort update if pre-update command fails": "প্রাক-আপডেট কমান্ড ব্যর্থ হলে আপডেট বাতিল করুন", + "Pre-uninstall command:": "প্রাক-আনইনস্টল কমান্ড:", + "Post-uninstall command:": "পোস্ট-আনইনস্টল কমান্ড:", + "Abort uninstall if pre-uninstall command fails": "প্রাক-আনইনস্টল কমান্ড ব্যর্থ হলে আনইনস্টল বাতিল করুন", + "Command-line to run:": "চালাতে কমান্ড-লাইন:", + "Save and close": "সংরক্ষণ করেন এবং বন্ধ করেন", + "General": "সাধারণ", + "Architecture & Location": "আর্কিটেকচার ও অবস্থান", + "Command-line": "কমান্ড-লাইন", + "Close apps": "অ্যাপগুলো বন্ধ করুন", + "Pre/Post install": "প্রাক/পরবর্তী ইনস্টল", + "Select the processes that should be closed before this package is installed, updated or uninstalled.": "এই প্যাকেজটি ইনস্টল, আপডেট বা আনইনস্টল করার আগে বন্ধ করা উচিত এমন প্রক্রিয়াগুলি নির্বাচন করুন।", + "Write here the process names here, separated by commas (,)": "এখানে প্রক্রিয়ার নাম লিখুন, কমা (,) দ্বারা পৃথক করা", + "Try to kill the processes that refuse to close when requested to": "অনুরোধ করলে বন্ধ করতে অস্বীকার করে এমন প্রক্রিয়াগুলি বন্ধ করার চেষ্টা করুন", + "Run as admin": "এডমিনিস্ট্রেটর হিসেবে চালান", + "Interactive installation": "ইন্টারেক্টিভ ইনস্টলেশন", + "Skip hash check": "হ্যাশ চেক করা বাদ দিন", + "Uninstall previous versions when updated": "আপডেট করার সময় পূর্ববর্তী সংস্করণ আনইনস্টল করুন", + "Skip minor updates for this package": "এই প্যাকেজের জন্য ছোট আপডেটগুলি এড়িয়ে যান", + "Automatically update this package": "স্বয়ংক্রিয়ভাবে এই প্যাকেজটি আপডেট করুন", + "{0} installation options": "{0} ইনস্টলেশন বিকল্প", + "Latest": "সর্বশেষ", + "PreRelease": "প্রি-রিলিজ", + "Default": "ডিফল্ট", + "Manage ignored updates": "উপেক্ষা করা আপডেটগুলি পরিচালনা করুন", + "The packages listed here won't be taken in account when checking for updates. Double-click them or click the button on their right to stop ignoring their updates.": "আপডেটের জন্য চেক করার সময় এখানে তালিকাভুক্ত প্যাকেজগুলি অ্যাকাউন্টে নেওয়া হবে না। তাদের আপডেট উপেক্ষা করা বন্ধ করতে তাদের ডাবল-ক্লিক করুন বা তাদের ডানদিকের বোতামটি ক্লিক করুন।", + "Reset list": "তালিকা রিসেট করুন", + "Do you really want to reset the ignored updates list? This action cannot be reverted": "আপনি কি সত্যিই উপেক্ষিত আপডেটের তালিকাটি রিসেট করতে চান? এই পদক্ষেপটি পূর্বাবস্থায় ফেরানো যাবে না", + "No ignored updates": "কোনো উপেক্ষিত আপডেট নেই", + "Package Name": "প্যাকেজের নাম", + "Package ID": "প্যাকেজ আইডি", + "Ignored version": "উপেক্ষিত সংস্করণ", + "New version": "নতুন সংস্করণ", + "Source": "উৎস", + "All versions": "সকল ভার্সন", + "Unknown": "অজানা", + "Up to date": "আপ টু ডেট", + "Package {name} from {manager}": "{manager} থেকে {name} প্যাকেজ", + "Remove {0} from ignored updates": "উপেক্ষিত আপডেট থেকে {0} সরান", + "Cancel": "বাতিল", + "Administrator privileges": "প্রশাসকের বিশেষাধিকার", + "This operation is running with administrator privileges.": "এই অপারেশনটি প্রশাসকের বিশেষাধিকার সহ চলছে।", + "Interactive operation": "ইন্টারেক্টিভ অপারেশন", + "This operation is running interactively.": "এই অপারেশনটি ইন্টারেক্টিভভাবে চলছে।", + "You will likely need to interact with the installer.": "আপনার সম্ভবত ইনস্টলারের সাথে মিথস্ক্রিয়া করতে হবে।", + "Integrity checks skipped": "অখণ্ডতা পরীক্ষা এড়িয়ে গেছে", + "Integrity checks will not be performed during this operation.": "এই অপারেশনের সময় অখণ্ডতা পরীক্ষা করা হবে না।", + "Proceed at your own risk.": "আপনার নিজের ঝুঁকিতে এগিয়ে যান।", + "Close": "বন্ধ", + "Loading...": "লোড হচ্ছে...", + "Installer SHA256": "ইনস্টলার SHA256", + "Homepage": "ওয়েবসাইট", + "Author": "লেখক", + "Publisher": "প্রকাশক", + "License": "লাইসেন্স", + "Manifest": "উদ্ভাসিত", + "Installer Type": "ইনস্টলার প্রকার", + "Size": "আকার", + "Installer URL": "ইনস্টলার URL", + "Last updated:": "সর্বশেষ সংষ্করণঃ", + "Release notes URL": "রিলিজ নোট URL", + "Package details": "প্যাকেজ বিবরণ", + "Dependencies:": "নির্ভরতা:", + "Release notes": "অব্যাহতি পত্র", + "Screenshots": "স্ক্রিনশট", + "This package has no screenshots or is missing the icon? Contribute to UniGetUI by adding the missing icons and screenshots to our open, public database.": "এই প্যাকেজের কোনো স্ক্রিনশট নেই বা আইকন অনুপস্থিত? আমাদের উন্মুক্ত, পাবলিক ডাটাবেসে অনুপস্থিত আইকন এবং স্ক্রিনশট যোগ করে UniGetUI-তে অবদান রাখুন।", + "Version": "সংস্করণ", + "Install as administrator": "এডমিনিস্ট্রেটর হিসেবে ইনস্টল করুন", + "Update to version {0}": "{0} সংস্করণে আপডেট করুন", + "Installed Version": "ইনস্টল করা সংস্করণ", + "Update as administrator": "এডমিনিস্ট্রেটর হিসেবে আপডেট করুন", + "Interactive update": "ইন্টারেক্টিভ আপডেট", + "Uninstall as administrator": "এডমিনিস্ট্রেটর হিসেবে আনইনস্টল করুন ", + "Interactive uninstall": "ইন্টারেক্টিভ আনইনস্টল", + "Uninstall and remove data": "আনইনস্টল এবং ডেটা অপসারণ", + "Not available": "পাওয়া যায়নি", + "Installer SHA512": "ইনস্টলার SHA512", + "Unknown size": "অজানা সাইজ", + "No dependencies specified": "কোন নির্ভরতা নির্দিষ্ট করা হয়নি", + "mandatory": "বাধ্যতামূলক", + "optional": "ঐচ্ছিক", + "UniGetUI {0} is ready to be installed.": "UniGetUI {0} ইনস্টল করার জন্য প্রস্তুত।", + "The update process will start after closing UniGetUI": "UniGetUI বন্ধ করার পরে আপডেট প্রক্রিয়া শুরু হবে", + "UniGetUI has been ran as administrator, which is not recommended. When running UniGetUI as administrator, EVERY operation launched from UniGetUI will have administrator privileges. You can still use the program, but we highly recommend not running UniGetUI with administrator privileges.": "UniGetUI প্রশাসক হিসেবে চালানো হয়েছে, যা সুপারিশ করা হয় না। UniGetUI-কে প্রশাসক হিসেবে চালালে UniGetUI থেকে শুরু করা প্রতিটি অপারেশন প্রশাসকের অনুমতি পাবে। আপনি এখনও প্রোগ্রামটি ব্যবহার করতে পারেন, তবে আমরা জোরালোভাবে সুপারিশ করি যে UniGetUI-কে প্রশাসক হিসেবে চালাবেন না।", + "Share anonymous usage data": "নিরাপদ ব্যবহার ডেটা শেয়ার করুন", + "UniGetUI collects anonymous usage data in order to improve the user experience.": "UniGetUI ব্যবহারকারীর অভিজ্ঞতা উন্নত করার জন্য নিরাপদ ব্যবহার ডেটা সংগ্রহ করে।", + "Accept": "গ্রহণ করুন", + "Software Updates": "সফটওয়্যার আপডেট", + "Package Bundles": "প্যাকেজ বান্ডিল", + "Settings": "সেটিংস", + "Package Managers": "প্যাকেজ ম্যানেজার", + "UniGetUI Log": "UniGetUI লগ", + "Package Manager logs": "প্যাকেজ ম্যানেজার লগ", + "Operation history": "অপারেশন ইতিহাস", + "Help": "সাহায্য", + "UniGetUI": "UniGetUI", + "You have installed UniGetUI Version {0}": "আপনি UniGetUI সংস্করণ {0} ইনস্টল করেছেন", + "Disclaimer": "দাবিত্যাগ", + "UniGetUI is developed by Devolutions and is not affiliated with any of the compatible package managers.": "UniGetUI Devolutions দ্বারা তৈরি এবং সামঞ্জস্যপূর্ণ কোনো প্যাকেজ ম্যানেজারের সঙ্গে সম্পৃক্ত নয়।", + "UniGetUI wouldn't have been possible without the help of the contributors. Thank you all 🥳": "অবদানকারীদের সাহায্য ছাড়া UniGetUI সম্ভব হত না। সবাইকে ধন্যবাদ 🥳", + "UniGetUI uses the following libraries. Without them, UniGetUI wouldn't have been possible.": "UniGetUI নিম্নলিখিত লাইব্রেরি ব্যবহার করে। এগুলি ছাড়া UniGetUI সম্ভব হত না।", + "{0} homepage": "{0} হোমপেজ", + "UniGetUI has been translated to more than 40 languages thanks to the volunteer translators. Thank you 🤝": "স্বেচ্ছাসেবক অনুবাদকদের ধন্যবাদ জানাতে UniGetUI ৪০-এর বেশি ভাষায় অনুবাদ করা হয়েছে। ধন্যবাদ 🤝", + "Verbose": "বর্ণনামূলক", + "1 - Errors": "১ - ত্রুটি", + "2 - Warnings": "২ - সতর্কতা", + "3 - Information (less)": "৩ - তথ্য (কম)", + "4 - Information (more)": "৪ - তথ্য (আরো)", + "5 - information (debug)": "৫ - তথ্য (ডিবাগ)", + "Warning": "সতর্কতা", + "The following settings may pose a security risk, hence they are disabled by default.": "নিম্নলিখিত সেটিংসগুলি নিরাপত্তা ঝুঁকি তৈরি করতে পারে, তাই সেগুলি ডিফল্টরূপে অক্ষম করা আছে।", + "Enable the settings below if and only if you fully understand what they do, and the implications they may have.": "নিম্নলিখিত সেটিংসগুলি সক্ষম করুন যদি এবং শুধুমাত্র যদি আপনি সম্পূর্ণরূপে বুঝেন যে তারা কী করে এবং তারা যে প্রভাব ফেলতে পারে।", + "The settings will list, in their descriptions, the potential security issues they may have.": "সেটিংসগুলি তাদের বর্ণনায় সম্ভাব্য নিরাপত্তা সমস্যাগুলি তালিকাভুক্ত করবে।", + "The backup will include the complete list of the installed packages and their installation options. Ignored updates and skipped versions will also be saved.": "ব্যাকআপ ইনস্টল করা প্যাকেজের সম্পূর্ণ তালিকা এবং তাদের ইনস্টলেশন বিকল্পগুলি অন্তর্ভুক্ত করবে। উপেক্ষিত আপডেট এবং এড়িয়ে যাওয়া সংস্করণগুলিও সংরক্ষণ করা হবে।", + "The backup will NOT include any binary file nor any program's saved data.": "ব্যাকআপে কোনও বাইনারি ফাইল বা কোনও প্রোগ্রামের সংরক্ষিত ডেটা অন্তর্ভুক্ত থাকবে না।", + "The size of the backup is estimated to be less than 1MB.": "ব্যাকআপের আকার 1MB এর কম বলে অনুমান করা হয়।", + "The backup will be performed after login.": "ব্যাকআপ লগইন করার পরে সঞ্চালিত হবে।", + "{pcName} installed packages": "{pcName} ইনস্টল করা প্যাকেজ", + "Current status: Not logged in": "বর্তমান স্থিতি: লগ ইন করা হয়নি", + "You are logged in as {0} (@{1})": "আপনি {0} (@{1}) হিসাবে লগ ইন করেছেন", + "Nice! Backups will be uploaded to a private gist on your account": "চমৎকার! ব্যাকআপগুলি আপনার অ্যাকাউন্টে একটি ব্যক্তিগত gist-এ আপলোড করা হবে", + "Select backup": "ব্যাকআপ নির্বাচন করুন", + "Settings imported from {0}": "{0} থেকে সেটিংস আমদানি করা হয়েছে", + "UniGetUI Settings": "UniGetUI সেটিংস", + "Settings exported to {0}": "{0}-এ সেটিংস রপ্তানি করা হয়েছে", + "UniGetUI settings were reset": "UniGetUI সেটিংস রিসেট করা হয়েছে", + "Allow pre-release versions": "প্রি-রিলিজ সংস্করণের অনুমতি দিন", + "Apply": "প্রয়োগ করুন", + "For security reasons, custom command-line arguments are disabled by default. Go to UniGetUI security settings to change this.": "নিরাপত্তাজনিত কারণে কাস্টম কমান্ড-লাইন আর্গুমেন্ট ডিফল্টরূপে নিষ্ক্রিয় থাকে। এটি পরিবর্তন করতে UniGetUI নিরাপত্তা সেটিংসে যান।", + "Go to UniGetUI security settings": "UniGetUI নিরাপত্তা সেটিংসে যান", + "The following options will be applied by default each time a {0} package is installed, upgraded or uninstalled.": "প্রতিটি পর্যায়ে নিম্নলিখিত বিকল্পগুলি ডিফল্টরূপে প্রয়োগ করা হবে যখন একটি {0} প্যাকেজ ইনস্টল, আপগ্রেড বা আনইনস্টল করা হয়।", + "Package's default": "প্যাকেজের ডিফল্ট", + "Install location can't be changed for {0} packages": "{0} প্যাকেজের জন্য ইনস্টল অবস্থান পরিবর্তন করা যায় না", + "The local icon cache currently takes {0} MB": "স্থানীয় আইকন ক্যাশ বর্তমানে {0} MB নেয়", + "Username": "ব্যবহারকারীর নাম", + "Password": "পাসওয়ার্ড", + "Credentials": "প্রশংসাপত্র", + "It is not guaranteed that the provided credentials will be stored safely": "প্রদত্ত শংসাপত্রগুলি নিরাপদে সংরক্ষিত হবে তার কোনো নিশ্চয়তা নেই", + "Partially": "আংশিকভাবে", + "Package manager": "প্যাকেজ ম্যানেজার", + "Compatible with proxy": "প্রক্সির সাথে সামঞ্জস্যপূর্ণ", + "Compatible with authentication": "প্রমাণীকরণের সাথে সামঞ্জস্যপূর্ণ", + "Proxy compatibility table": "প্রক্সি সামঞ্জস্য টেবিল", + "{0} settings": "{0} সেটিংস", + "{0} status": "{0} অবস্থা", + "Default installation options for {0} packages": "{0} প্যাকেজের জন্য ডিফল্ট ইনস্টলেশন বিকল্প", + "Expand version": "সংস্করণ প্রসারিত করুন", + "The executable file for {0} was not found": "{0} এর জন্য এক্সিকিউটেবল ফাইল পাওয়া যায়নি", + "{pm} is disabled": "{pm} অক্ষম করা আছে", + "Enable it to install packages from {pm}.": "{pm} থেকে প্যাকেজ ইনস্টল করতে এটি সক্ষম করুন।", + "{pm} is enabled and ready to go": "{pm} সক্ষম এবং যেতে প্রস্তুত", + "{pm} version:": "{pm} সংস্করণ:", + "{pm} was not found!": "{pm} পাওয়া যায়নি!", + "You may need to install {pm} in order to use it with UniGetUI.": "UniGetUI-এর সাথে এটি ব্যবহার করার জন্য আপনার {pm} ইনস্টল করতে হতে পারে।", + "Scoop Installer - UniGetUI": "স্কুপ ইনস্টলার - UniGetUI", + "Scoop Uninstaller - UniGetUI": "স্কুপ আনইনস্টলার - UniGetUI", + "Clearing Scoop cache - UniGetUI": "স্কুপ ক্যাশে সাফ করা হচ্ছে - UniGetUI", + "Restart UniGetUI to fully apply changes": "পরিবর্তনগুলি পুরোপুরি প্রয়োগ করতে UniGetUI পুনরায় চালু করুন", + "Restart UniGetUI": "UniGetUI পুনরায় চালু করুন", + "Manage {0} sources": "{0}টি উৎস পরিচালনা করুন৷", + "Add source": "উৎস যোগ করুন", + "Add": "যুক্ত করুন", + "Source name": "উৎসের নাম", + "Source URL": "উৎস URL", + "Other": "অন্যান্য", + "No minimum age": "কোনো ন্যূনতম সময়সীমা নেই", + "1 day": "১ দিন", + "{0} days": "{0} দিন", + "Custom...": "কাস্টম...", + "{0} minutes": "{0} মিনিট", + "1 hour": "১ ঘন্টা", + "{0} hours": "{0} ঘণ্টা", + "1 week": "১ সপ্তাহ", + "Supports release dates": "রিলিজ তারিখ সমর্থন করে", + "Release date support per package manager": "প্রতিটি প্যাকেজ ম্যানেজারের রিলিজ তারিখ সমর্থন", + "Search for packages": "প্যাকেজ অনুসন্ধান করুন", + "Local": "স্থানীয়", + "OK": "ঠিক আছে", + "Last checked: {0}": "সর্বশেষ পরীক্ষা করা হয়েছে: {0}", + "{0} packages were found, {1} of which match the specified filters.": "{1} প্যাকেজ পাওয়া গেছে যার মধ্যে {0}টি নির্দিষ্ট ফিল্টারগুলির সাথে মেলে।", + "{0} selected": "{0} নির্বাচিত", + "(Last checked: {0})": "(শেষ পরীক্ষা করা হয়েছেঃ {0})", + "All packages selected": "সমস্ত প্যাকেজ নির্বাচিত", + "Package selection cleared": "প্যাকেজ নির্বাচন পরিষ্কার করা হয়েছে", + "{0}: {1}": "{0}: {1}", + "More info": "আরও তথ্য", + "GitHub account": "GitHub অ্যাকাউন্ট", + "Log in with GitHub to enable cloud package backup.": "ক্লাউড প্যাকেজ ব্যাকআপ সক্ষম করতে GitHub দিয়ে লগ ইন করুন।", + "More details": "আরো বিস্তারিত", + "Log in": "লগ ইন করুন", + "If you have cloud backup enabled, it will be saved as a GitHub Gist on this account": "যদি আপনার ক্লাউড ব্যাকআপ সক্ষম থাকে তবে এটি এই অ্যাকাউন্টে একটি GitHub Gist হিসাবে সংরক্ষিত হবে", + "Log out": "লগ আউট করুন", + "About UniGetUI": "UniGetUI সম্পর্কে", + "About": "সম্পর্কিত", + "Third-party licenses": "তৃতীয় পক্ষের লাইসেন্স", + "Contributors": "অবদানকারী", + "Translators": "অনুবাদক", + "Bundle security report": "বান্ডেল নিরাপত্তা রিপোর্ট", + "The bundle contained restricted content": "বান্ডিলে সীমাবদ্ধ কনটেন্ট ছিল", + "UniGetUI – Crash Report": "UniGetUI – ক্র্যাশ রিপোর্ট", + "UniGetUI has crashed": "UniGetUI ক্র্যাশ হয়েছে", + "Help us fix this by sending a crash report to Devolutions. All fields below are optional.": "Devolutions-এ একটি ক্র্যাশ রিপোর্ট পাঠিয়ে আমাদের এটি ঠিক করতে সাহায্য করুন। নিচের সব ক্ষেত্র ঐচ্ছিক।", + "Email (optional)": "ইমেইল (ঐচ্ছিক)", + "your@email.com": "your@email.com", + "Additional details (optional)": "অতিরিক্ত বিবরণ (ঐচ্ছিক)", + "Describe what you were doing when the crash occurred…": "ক্র্যাশ ঘটার সময় আপনি কী করছিলেন তা বর্ণনা করুন…", + "Crash report": "ক্র্যাশ রিপোর্ট", + "Don't Send": "পাঠাবেন না", + "Send Report": "রিপোর্ট পাঠান", + "Sending…": "পাঠানো হচ্ছে…", + "Unsaved changes": "অসংরক্ষিত পরিবর্তন", + "You have unsaved changes in the current bundle. Do you want to discard them?": "বর্তমান বান্ডিলে আপনার অসংরক্ষিত পরিবর্তন রয়েছে। আপনি কি সেগুলো বাতিল করতে চান?", + "Discard changes": "পরিবর্তন বাতিল করুন", + "Integrity violation": "অখণ্ডতা লঙ্ঘন", + "UniGetUI or some of its components are missing or corrupt. It is strongly recommended to reinstall UniGetUI to adress the situation.": "UniGetUI বা এর কিছু উপাদান অনুপস্থিত বা ক্ষতিগ্রস্ত। পরিস্থিতি সমাধানের জন্য UniGetUI পুনরায় ইনস্টল করার জোরালো সুপারিশ করা হচ্ছে।", + "• Refer to the UniGetUI Logs to get more details regarding the affected file(s)": "• প্রভাবিত ফাইলগুলির বিষয়ে আরও বিবরণ পেতে UniGetUI লগস দেখুন", + "• Integrity checks can be disabled from the Experimental Settings": "• অখণ্ডতা পরীক্ষা পরীক্ষামূলক সেটিংস থেকে অক্ষম করা যেতে পারে", + "Manage shortcuts": "শর্টকাটস পরিচালনা করুন", + "UniGetUI has detected the following desktop shortcuts which can be removed automatically on future upgrades": "UniGetUI নিম্নলিখিত ডেস্কটপ শর্টকাটগুলি সনাক্ত করেছে যা ভবিষ্যতের আপগ্রেডে স্বয়ংক্রিয়ভাবে সরানো যেতে পারে", + "Do you really want to reset this list? This action cannot be reverted.": "আপনি কি সত্যিই এই তালিকাটি রিসেট করতে চান? এই পদক্ষেপটি পূর্বাবস্থায় ফেরানো যায় না।", + "Desktop shortcuts list": "ডেস্কটপ শর্টকাটের তালিকা", + "Open in explorer": "এক্সপ্লোরারে খুলুন", + "Remove from list": "তালিকা থেকে বাদ দিন", + "When new shortcuts are detected, delete them automatically instead of showing this dialog.": "যখন নতুন শর্টকাটগুলি সনাক্ত করা হয় তখন এই সংলাপটি দেখানোর পরিবর্তে সেগুলিকে স্বয়ংক্রিয়ভাবে মুছে ফেলুন।", + "Not right now": "এখনই না", + "Missing dependency": "অনুপস্থিত নির্ভরতা", + "UniGetUI requires {0} to operate, but it was not found on your system.": "UniGetUI অপারেট করার জন্য {0} প্রয়োজন কিন্তু এটি আপনার সিস্টেমে পাওয়া যায়নি।", + "Click on Install to begin the installation process. If you skip the installation, UniGetUI may not work as expected.": "ইনস্টলেশন প্রক্রিয়া শুরু করতে Install এ ক্লিক করুন। আপনি ইনস্টলেশন এড়িয়ে গেলে, UniGetUI আশানুরূপ কাজ নাও করতে পারে।", + "Alternatively, you can also install {0} by running the following command in a Windows PowerShell prompt:": "বিকল্পভাবে, আপনি নিম্নলিখিত কমান্ড Windows PowerShell প্রম্পটে চালিয়ে {0} ইনস্টল করতে পারেন:", + "Install {0}": "{0} ইনস্টল করুন", + "Do not show this dialog again for {0}": "{0} এর জন্য এই সংলাপটি আর দেখাবেন না", + "Please wait while {0} is being installed. A black window may show up. Please wait until it closes.": "{0} ইনস্টল করা হচ্ছে এমন অবস্থায় অপেক্ষা করুন। একটি কালো (বা নীল) উইন্ডো দেখা দিতে পারে। এটি বন্ধ হওয়া পর্যন্ত অপেক্ষা করুন।", + "{0} has been installed successfully.": "{0} সফলভাবে ইনস্টল করা হয়েছে।", + "Please click on \"Continue\" to continue": "চালিয়ে যেতে অনুগ্রহ করে \"চালিয়ে যান\" এ ক্লিক করুন", + "Continue": "চালিয়ে যান", + "{0} has been installed successfully. It is recommended to restart UniGetUI to finish the installation": "{0} সফলভাবে ইনস্টল করা হয়েছে। ইনস্টলেশন সম্পূর্ণ করতে UniGetUI পুনরায় চালু করার সুপারিশ করা হয়", + "Restart later": "পরে পুনরায় আরম্ভ করুন", + "An error occurred:": "একটি ত্রুটি ঘটেছেঃ", + "Please see the Command-line Output or refer to the Operation History for further information about the issue.": "অনুগ্রহ করে কমান্ড-লাইন আউটপুট দেখুন বা সমস্যা সম্পর্কে আরও তথ্যের জন্য অপারেশন ইতিহাস পড়ুন।", + "Retry as administrator": "প্রশাসক হিসাবে পুনরায় চেষ্টা করুন", + "Retry interactively": "ইন্টারেক্টিভভাবে পুনরায় চেষ্টা করুন", + "Retry skipping integrity checks": "অখণ্ডতা পরীক্ষা এড়িয়ে পুনরায় চেষ্টা করুন", + "Installation options": "ইনস্টলেশন বিকল্প", + "Save": "সংরক্ষণ করুন", + "UniGetUI collects anonymous usage data with the sole purpose of understanding and improving the user experience.": "UniGetUI ব্যবহারকারীর অভিজ্ঞতা বোঝা এবং উন্নত করার একমাত্র উদ্দেশ্যে নিরাপদ ব্যবহার ডেটা সংগ্রহ করে।", + "More details about the shared data and how it will be processed": "শেয়ার করা ডেটা এবং এটি কীভাবে প্রক্রিয়া করা হবে তা সম্পর্কে আরও বিবরণ", + "Do you accept that UniGetUI collects and sends anonymous usage statistics, with the sole purpose of understanding and improving the user experience?": "আপনি কি মেনে চলেন যে UniGetUI ব্যবহারকারীর অভিজ্ঞতা বোঝা এবং উন্নত করার একমাত্র উদ্দেশ্যে নিরাপদ ব্যবহার পরিসংখ্যান সংগ্রহ এবং পাঠায়?", + "Decline": "অস্বীকার করুন", + "No personal information is collected nor sent, and the collected data is anonimized, so it can't be back-tracked to you.": "কোনো ব্যক্তিগত তথ্য সংগ্রহ বা প্রেরণ করা হয় না এবং সংগৃহীত ডেটা অননামকৃত করা হয়, তাই এটি আপনার কাছে ফিরিয়ে আনা যায় না।", + "Navigation panel": "নেভিগেশন প্যানেল", + "Operations": "অপারেশনসমূহ", + "Toggle operations panel": "অপারেশন প্যানেল টগল করুন", + "Bulk operations": "বাল্ক অপারেশন", + "Retry failed": "ব্যর্থগুলো পুনরায় চেষ্টা করুন", + "Clear successful": "সফলগুলো পরিষ্কার করুন", + "Clear finished": "সমাপ্তগুলো পরিষ্কার করুন", + "Cancel all": "সব বাতিল করুন", + "More": "আরও", + "Toggle navigation panel": "নেভিগেশন প্যানেল টগল করুন", + "Minimize": "মিনিমাইজ", + "Maximize": "ম্যাক্সিমাইজ", + "UniGetUI by Devolutions": "Devolutions-এর UniGetUI", + "UniGetUI is an application that makes managing your software easier, by providing an all-in-one graphical interface for your command-line package managers.": "UniGetUI একটি অ্যাপ্লিকেশন যা আপনার কমান্ড-লাইন প্যাকেজ ম্যানেজারগুলির জন্য একটি সর্বাত্মক গ্রাফিক্যাল ইন্টারফেস প্রদান করে আপনার সফ্টওয়্যার পরিচালনা সহজ করে।", + "Useful links": "দরকারি লিঙ্কগুলি", + "UniGetUI Homepage": "UniGetUI হোমপেজ", + "Report an issue or submit a feature request": "একটি সমস্যা রিপোর্ট করুন বা একটি বৈশিষ্ট্য অনুরোধ জমা দিন", + "UniGetUI Repository": "UniGetUI রিপোজিটরি", + "View GitHub Profile": "GitHub প্রোফাইল দেখুন", + "UniGetUI License": "UniGetUI লাইসেন্স", + "Using UniGetUI implies the acceptation of the MIT License": "UniGetUI ব্যবহার করা MIT লাইসেন্স গ্রহণ করার অন্তর্দৃষ্টি দেয়", + "Become a translator": "একজন অনুবাদক হন", + "Go back": "পেছনে যান", + "Go forward": "সামনে যান", + "Go to home page": "হোম পেজে যান", + "Reload page": "পৃষ্ঠা পুনরায় লোড করুন", + "View page on browser": "ব্রাউজারে পৃষ্ঠা দেখুন", + "The built-in browser is not supported on Linux yet.": "বিল্ট-ইন ব্রাউজারটি এখনও Linux-এ সমর্থিত নয়।", + "Open in browser": "ব্রাউজারে খুলুন", + "Copy to clipboard": "ক্লিপবোর্ডে কপি করুন", + "Export to a file": "একটি ফাইলে রপ্তানি করুন", + "Log level:": "লগ লেভেলঃ", + "Reload log": "লগ পুনরায় লোড করুন", + "Export log": "লগ রপ্তানি করুন", + "Text": "পাঠ্য", + "Change how operations request administrator rights": "অপারেশনগুলি কীভাবে প্রশাসকের অধিকার অনুরোধ করে তা পরিবর্তন করুন", + "Restrictions on package operations": "প্যাকেজ অপারেশনগুলির বিধিনিষেধ", + "Restrictions on package managers": "প্যাকেজ ম্যানেজারগুলির বিধিনিষেধ", + "Restrictions when importing package bundles": "প্যাকেজ বান্ডিল আমদানি করার সময় বিধিনিষেধ", + "Ask for administrator privileges once for each batch of operations": "প্রতিটি ব্যাচের অপারেশনের জন্য একবার প্রশাসকের সুবিধার জন্য জিজ্ঞাসা করুন", + "Ask only once for administrator privileges": "প্রশাসকের বিশেষাধিকারের জন্য শুধুমাত্র একবার জিজ্ঞাসা করুন", + "Prohibit any kind of Elevation via UniGetUI Elevator or GSudo": "UniGetUI এলিভেটর বা GSudo এর মাধ্যমে যেকোনো ধরনের উচ্চতা নিষিদ্ধ করুন", + "This option WILL cause issues. Any operation incapable of elevating itself WILL FAIL. Install/update/uninstall as administrator will NOT WORK.": "এই বিকল্পটি সমস্যা সৃষ্টি করবে। নিজেকে উন্নত করতে অক্ষম যেকোনো অপারেশন ব্যর্থ হবে। প্রশাসক হিসাবে ইনস্টল/আপডেট/আনইনস্টল কাজ করবে না।", + "Allow custom command-line arguments": "কাস্টম কমান্ড-লাইন আর্গুমেন্টের অনুমতি দিন", + "Custom command-line arguments can change the way in which programs are installed, upgraded or uninstalled, in a way UniGetUI cannot control. Using custom command-lines can break packages. Proceed with caution.": "কাস্টম কমান্ড-লাইন আর্গুমেন্ট প্রোগ্রামগুলি ইনস্টল, আপগ্রেড বা আনইনস্টল করার উপায় পরিবর্তন করতে পারে এমনভাবে যা UniGetUI নিয়ন্ত্রণ করতে পারে না। কাস্টম কমান্ড-লাইন ব্যবহার করে প্যাকেজগুলি ভেঙে ফেলা যেতে পারে। সতর্কতার সাথে এগিয়ে যান।", + "Ignore custom pre-install and post-install commands when importing packages from a bundle": "চালাতে কাস্টম প্রাক-ইনস্টল এবং পোস্ট-ইনস্টল কমান্ড অনুমতি দিন", + "Pre and post install commands will be run before and after a package gets installed, upgraded or uninstalled. Be aware that they may break things unless used carefully": "প্রাক এবং পোস্ট ইনস্টল কমান্ডগুলি একটি প্যাকেজ ইনস্টল, আপগ্রেড বা আনইনস্টল হওয়ার আগে এবং পরে চালানো হয়। সতর্ক থাকুন যে সাবধানে ব্যবহার না করলে তারা জিনিসগুলি ভেঙে ফেলতে পারে", + "Allow changing the paths for package manager executables": "প্যাকেজ ম্যানেজার এক্সিকিউটেবলের পথ পরিবর্তন করার অনুমতি দিন", + "Turning this on enables changing the executable file used to interact with package managers. While this allows finer-grained customization of your install processes, it may also be dangerous": "এটি চালু করা প্যাকেজ ম্যানেজারগুলির সাথে মিথস্ক্রিয়া করার জন্য ব্যবহৃত এক্সিকিউটেবল ফাইল পরিবর্তন করার অনুমতি দেয়। যদিও এটি আপনার ইনস্টল প্রক্রিয়াগুলির সূক্ষ্মতর কাস্টমাইজেশনের অনুমতি দেয়, এটি বিপজ্জনকও হতে পারে", + "Allow importing custom command-line arguments when importing packages from a bundle": "বান্ডেল থেকে প্যাকেজ আমদানি করার সময় কাস্টম কমান্ড-লাইন আর্গুমেন্ট আমদানি করার অনুমতি দিন", + "Malformed command-line arguments can break packages, or even allow a malicious actor to gain privileged execution. Therefore, importing custom command-line arguments is disabled by default": "বিকৃত কমান্ড-লাইন আর্গুমেন্ট প্যাকেজগুলি ভেঙে ফেলতে পারে বা একজন ক্ষতিকর অভিনেতাকে সুবিধাপ্রাপ্ত এক্সিকিউশন পেতে দিতে পারে। তাই কাস্টম কমান্ড-লাইন আর্গুমেন্ট আমদানি ডিফল্টরূপে অক্ষম করা আছে।", + "Allow importing custom pre-install and post-install commands when importing packages from a bundle": "বান্ডেল থেকে প্যাকেজ আমদানি করার সময় কাস্টম প্রাক-ইনস্টল এবং পোস্ট-ইনস্টল কমান্ড আমদানি করার অনুমতি দিন", + "Pre and post install commands can do very nasty things to your device, if designed to do so. It can be very dangerous to import the commands from a bundle, unless you trust the source of that package bundle": "প্রাক এবং পোস্ট ইনস্টল কমান্ডগুলি আপনার ডিভাইসে অত্যন্ত নৃশংস কাজ করতে পারে যদি তা করার জন্য ডিজাইন করা হয়। বান্ডেল থেকে কমান্ডগুলি আমদানি করা অত্যন্ত বিপজ্জনক হতে পারে যদি না আপনি সেই প্যাকেজ বান্ডেলের উৎসকে বিশ্বাস করেন", + "Administrator rights and other dangerous settings": "প্রশাসকের অধিকার এবং অন্যান্য বিপজ্জনক সেটিংস", + "Package backup": "প্যাকেজ ব্যাকআপ", + "Cloud package backup": "ক্লাউড প্যাকেজ ব্যাকআপ", + "Local package backup": "স্থানীয় প্যাকেজ ব্যাকআপ", + "Local backup advanced options": "স্থানীয় ব্যাকআপ উন্নত বিকল্প", + "Log in with GitHub": "GitHub দিয়ে লগ ইন করুন", + "Log out from GitHub": "GitHub থেকে লগ আউট করুন", + "Periodically perform a cloud backup of the installed packages": "পর্যায়ক্রমে ইনস্টল করা প্যাকেজগুলির একটি ক্লাউড ব্যাকআপ সম্পাদন করুন", + "Cloud backup uses a private GitHub Gist to store a list of installed packages": "ক্লাউড ব্যাকআপ ইনস্টল করা প্যাকেজের তালিকা সংরক্ষণ করতে একটি ব্যক্তিগত GitHub Gist ব্যবহার করে", + "Perform a cloud backup now": "এখনই একটি ক্লাউড ব্যাকআপ সম্পাদন করুন", + "Backup": "ব্যাকআপ", + "Restore a backup from the cloud": "ক্লাউড থেকে একটি ব্যাকআপ পুনরুদ্ধার করুন", + "Begin the process to select a cloud backup and review which packages to restore": "একটি ক্লাউড ব্যাকআপ নির্বাচন করার প্রক্রিয়া শুরু করুন এবং কোন প্যাকেজ পুনরুদ্ধার করতে হবে তা পর্যালোচনা করুন", + "Periodically perform a local backup of the installed packages": "পর্যায়ক্রমে ইনস্টল করা প্যাকেজগুলির একটি স্থানীয় ব্যাকআপ সম্পাদন করুন", + "Perform a local backup now": "এখনই একটি স্থানীয় ব্যাকআপ সম্পাদন করুন", + "Change backup output directory": "ব্যাকআপ আউটপুট ডিরেক্টরি পরিবর্তন করুন", + "Set a custom backup file name": "একটি কাস্টম ব্যাকআপ ফাইলের নাম সেট করুন", + "Leave empty for default": "ডিফল্টের জন্য খালি ছেড়ে দিন", + "Add a timestamp to the backup file names": "ব্যাকআপ ফাইলের নামগুলিতে একটি টাইমস্ট্যাম্প যোগ করুন", + "Backup and Restore": "ব্যাকআপ এবং পুনরুদ্ধার", + "Enable background api (UniGetUI Widgets and Sharing, port 7058)": "ব্যাকগ্রাউন্ড এপিআই সক্ষম করুন (UniGetUI উইজেট এবং শেয়ারিং, পোর্ট 7058)", + "Wait for the device to be connected to the internet before attempting to do tasks that require internet connectivity.": "ইন্টারনেট সংযোগের প্রয়োজনীয় কাজগুলি করার চেষ্টা করার আগে ডিভাইসটি ইন্টারনেটে সংযুক্ত হওয়ার জন্য অপেক্ষা করুন।", + "Disable the 1-minute timeout for package-related operations": "প্যাকেজ-সম্পর্কিত অপারেশনের জন্য ১-মিনিটের সময়সীমা অক্ষম করুন", + "Use installed GSudo instead of UniGetUI Elevator": "UniGetUI এলিভেটরের পরিবর্তে ইনস্টল করা GSudo ব্যবহার করুন", + "Use a custom icon and screenshot database URL": "একটি কাস্টম আইকন এবং স্ক্রিনশট ডাটাবেস URL ব্যবহার করুন", + "Enable background CPU Usage optimizations (see Pull Request #3278)": "পটভূমি CPU ব্যবহার অপটিমাইজেশন সক্ষম করুন (Pull Request #3278 দেখুন)", + "Perform integrity checks at startup": "স্টার্টআপে অখণ্ডতা পরীক্ষা সম্পাদন করুন", + "When batch installing packages from a bundle, install also packages that are already installed": "বান্ডেল থেকে প্যাকেজগুলি ব্যাচ ইনস্টল করার সময় ইতিমধ্যে ইনস্টল করা প্যাকেজগুলিও ইনস্টল করুন", + "Experimental settings and developer options": "পরীক্ষামূলক সেটিংস এবং ডেভেলপার বিকল্প", + "Show UniGetUI's version and build number on the titlebar.": "টাইটেলবারে UniGetUI-এর সংস্করণ প্রদর্শন করুন", + "Language": "ভাষা", + "UniGetUI updater": "UniGetUI আপডেটার", + "Telemetry": "টেলিমেট্রি", + "Manage UniGetUI settings": "UniGetUI সেটিংস পরিচালনা করুন", + "Related settings": "সম্পর্কিত সেটিংস", + "Update UniGetUI automatically": "স্বয়ংক্রিয়ভাবে UniGetUI হালনাগাদ করুন", + "Check for updates": "আপডেটের জন্য চেক করুন", + "Install prerelease versions of UniGetUI": "UniGetUI-এর প্রি-রিলিজ সংস্করণ ইনস্টল করুন", + "Manage telemetry settings": "টেলিমেট্রি সেটিংস পরিচালনা করুন", + "Manage": "পরিচালনা করুন", + "Import settings from a local file": "একটি স্থানীয় ফাইল থেকে সেটিংস আমদানি করুন", + "Import": "আমদানি", + "Export settings to a local file": "একটি স্থানীয় ফাইলে সেটিংস রপ্তানি করুন", + "Export": "রপ্তানি", + "Reset UniGetUI": "UniGetUI রিসেট করুন", + "User interface preferences": "ব্যবহারকারীর ইন্টারফেস পছন্দসমূহ", + "Application theme, startup page, package icons, clear successful installs automatically": "অ্যাপ্লিকেশন থিম, স্টার্টআপ পৃষ্ঠা, প্যাকেজ আইকন, স্বয়ংক্রিয়ভাবে সফল ইনস্টল পরিষ্কার করুন", + "General preferences": "সাধারণ পছন্দ", + "UniGetUI display language:": "UniGetUI ভাষা প্রদর্শন:", + "System language": "সিস্টেমের ভাষা", + "Is your language missing or incomplete?": "আপনার ভাষা অনুপস্থিত বা অসম্পূর্ণ?", + "Appearance": "উপস্থিতি", + "UniGetUI on the background and system tray": "পটভূমিতে এবং সিস্টেম ট্রেতে UniGetUI", + "Package lists": "প্যাকেজ তালিকা", + "Use classic mode": "ক্লাসিক মোড ব্যবহার করুন", + "Restart UniGetUI to apply this change": "এই পরিবর্তন প্রয়োগ করতে UniGetUI পুনরায় চালু করুন", + "The classic UI is disabled for beta testers": "বিটা পরীক্ষকদের জন্য ক্লাসিক UI নিষ্ক্রিয় করা হয়েছে", + "Close UniGetUI to the system tray": "UniGetUI সিস্টেম ট্রেতে বন্ধ করুন", + "Manage UniGetUI autostart behaviour": "UniGetUI-এর স্বয়ংক্রিয় চালু হওয়ার আচরণ পরিচালনা করুন", + "Show package icons on package lists": "প্যাকেজ তালিকায় প্যাকেজ আইকন দেখান", + "Clear cache": "ক্যাশ পরিষ্কার করুন", + "Select upgradable packages by default": "ডিফল্টরূপে আপগ্রেডযোগ্য প্যাকেজ নির্বাচন করুন", + "Light": "আলো", + "Dark": "অন্ধকার", + "Follow system color scheme": "সিস্টেমের রঙের স্কিম অনুসরণ করুন", + "Application theme:": "অ্যাপ্লিকেশন থিমঃ", + "UniGetUI startup page:": "UniGetUI স্টার্টআপ পৃষ্ঠা:", + "Proxy settings": "প্রক্সি সেটিংস", + "Other settings": "অন্যান্য সেটিংস", + "Connect the internet using a custom proxy": "কাস্টম প্রক্সি ব্যবহার করে ইন্টারনেটে সংযোগ করুন", + "Please note that not all package managers may fully support this feature": "অনুগ্রহ করে মনে রাখবেন যে সমস্ত প্যাকেজ ম্যানেজার এই বৈশিষ্ট্যটি সম্পূর্ণরূপে সমর্থন করতে পারে না", + "Proxy URL": "প্রক্সি URL", + "Enter proxy URL here": "এখানে প্রক্সি URL লিখুন", + "Authenticate to the proxy with a user and a password": "একটি ব্যবহারকারীর নাম এবং পাসওয়ার্ড দিয়ে প্রক্সিতে প্রমাণীকরণ করুন", + "Internet and proxy settings": "ইন্টারনেট ও প্রক্সি সেটিংস", + "Package manager preferences": "প্যাকেজ ম্যানেজার পছন্দ", + "Ready": "প্রস্তুত", + "Not found": "খুঁজে পাওয়া যায়নি", + "Notification preferences": "বিজ্ঞপ্তি পছন্দ", + "Notification types": "বিজ্ঞপ্তি প্রকার", + "The system tray icon must be enabled in order for notifications to work": "বিজ্ঞপ্তি কাজ করার জন্য সিস্টেম ট্রে আইকন সক্ষম করা আবশ্যক", + "Enable UniGetUI notifications": "UniGetUI বিজ্ঞপ্তি সক্ষম করুন", + "Show a notification when there are available updates": "আপডেট পাওয়া গেলে একটি বিজ্ঞপ্তি দেখান", + "Show a silent notification when an operation is running": "অপারেশন চলাকালীন একটি নীরব বিজ্ঞপ্তি দেখান", + "Show a notification when an operation fails": "অপারেশন ব্যর্থ হলে একটি বিজ্ঞপ্তি দেখান", + "Show a notification when an operation finishes successfully": "একটি অপারেশন সফলভাবে শেষ হলে একটি বিজ্ঞপ্তি দেখান", + "Concurrency and execution": "সমসাময়িকতা এবং বাস্তবায়ন", + "Automatic desktop shortcut remover": "স্বয়ংক্রিয় ডেস্কটপ শর্টকাট অপসারণকারী", + "Choose how many operations should be performed in parallel": "কতগুলো অপারেশন সমান্তরালে চালানো হবে তা নির্বাচন করুন", + "Clear successful operations from the operation list after a 5 second delay": "৫ সেকেন্ডের বিলম্বের পরে অপারেশন তালিকা থেকে সফল অপারেশন পরিষ্কার করুন", + "Download operations are not affected by this setting": "ডাউনলোড অপারেশন এই সেটিংদ্বারা প্রভাবিত হয় না", + "You may lose unsaved data": "আপনি সংরক্ষিত ডেটা হারাতে পারেন", + "Ask to delete desktop shortcuts created during an install or upgrade.": "ইনস্টল বা আপগ্রেড করার সময় তৈরি করা ডেস্কটপ শর্টকাট মুছে ফেলার জন্য জিজ্ঞাসা করুন।", + "Package update preferences": "প্যাকেজ আপডেট পছন্দ", + "Update check frequency, automatically install updates, etc.": "আপডেট পরীক্ষার ফ্রিকোয়েন্সি, স্বয়ংক্রিয়ভাবে আপডেট ইনস্টল করুন ইত্যাদি।", + "Reduce UAC prompts, elevate installations by default, unlock certain dangerous features, etc.": "UAC প্রম্পটগুলি হ্রাস করুন, ডিফল্টরূপে ইনস্টলেশনগুলি উন্নত করুন, নির্দিষ্ট বিপজ্জনক বৈশিষ্ট্যগুলি আনলক করুন ইত্যাদি।", + "Package operation preferences": "প্যাকেজ অপারেশন পছন্দ", + "Enable {pm}": "{pm} চালু করুন", + "Not finding the file you are looking for? Make sure it has been added to path.": "আপনি যে ফাইলটি খুঁজছেন তা খুঁজে পাচ্ছেন না? নিশ্চিত করুন যে এটি পাথে যোগ করা হয়েছে।", + "Select the executable to be used. The following list shows the executables found by UniGetUI": "ব্যবহার করার জন্য এক্সিকিউটেবল নির্বাচন করুন। নিম্নলিখিত তালিকা UniGetUI দ্বারা পাওয়া এক্সিকিউটেবলগুলি দেখায়", + "For security reasons, changing the executable file is disabled by default": "নিরাপত্তার কারণে, এক্সিকিউটেবল ফাইল পরিবর্তন ডিফল্টরূপে অক্ষম করা আছে", + "Change this": "এটি পরিবর্তন করুন", + "Copy path": "পাথ কপি করুন", + "Current executable file:": "বর্তমান এক্সিকিউটেবল ফাইল:", + "Ignore packages from {pm} when showing a notification about updates": "আপডেটের বিষয়ে বিজ্ঞপ্তি দেখানোর সময় {pm} থেকে প্যাকেজ উপেক্ষা করুন", + "Update security": "আপডেট নিরাপত্তা", + "Use global setting": "গ্লোবাল সেটিং ব্যবহার করুন", + "Minimum age for updates": "আপডেটের ন্যূনতম বয়স", + "e.g. 10": "যেমন 10", + "Custom minimum age (days)": "কাস্টম ন্যূনতম বয়স (দিন)", + "{pm} does not provide release dates for its packages, so this setting will have no effect": "{pm} তার প্যাকেজগুলোর জন্য রিলিজ তারিখ দেয় না, তাই এই সেটিংটির কোনো প্রভাব হবে না", + "{pm} only provides release dates for some of its packages, so this setting will only apply to those packages": "{pm} শুধুমাত্র এর কিছু প্যাকেজের জন্য রিলিজের তারিখ প্রদান করে, তাই এই সেটিং কেবল সেই প্যাকেজগুলোর জন্যই প্রযোজ্য হবে", + "Override the global minimum update age for this package manager": "এই প্যাকেজ ম্যানেজারের জন্য গ্লোবাল ন্যূনতম আপডেট-বয়স ওভাররাইড করুন", + "View {0} logs": "{0} লগ দেখুন", + "If Python cannot be found or is not listing packages but is installed on the system, ": "যদি Python খুঁজে না পাওয়া যায় অথবা প্যাকেজ তালিকা না দেখায় কিন্তু সিস্টেমে ইনস্টল থাকে, ", + "Advanced options": "উন্নত বিকল্প", + "WinGet command-line tool": "WinGet কমান্ড-লাইন টুল", + "Choose which command-line tool UniGetUI uses for WinGet operations when the COM API is not used": "COM API ব্যবহার না করা হলে WinGet অপারেশনের জন্য UniGetUI কোন কমান্ড-লাইন টুল ব্যবহার করবে তা নির্বাচন করুন", + "WinGet COM API": "WinGet COM API", + "Choose whether UniGetUI can use the WinGet COM API before falling back to the command-line tool": "কমান্ড-লাইন টুলে ফিরে যাওয়ার আগে UniGetUI WinGet COM API ব্যবহার করতে পারবে কি না তা নির্বাচন করুন", + "Reset WinGet": "WinGet রিসেট করুন", + "This may help if no packages are listed": "যদি কোন প্যাকেজ তালিকাভুক্ত না হয় তবে এটি সাহায্য করতে পারে", + "Force install location parameter when updating packages with custom locations": "কাস্টম অবস্থান সহ প্যাকেজ আপডেট করার সময় ইনস্টল অবস্থান প্যারামিটার জোর করুন", + "Install Scoop": "স্কুপ ইনস্টল করুন", + "Uninstall Scoop (and its packages)": "স্কুপ আনইনস্টল করুন (এবং এর প্যাকেজ)", + "Run cleanup and clear cache": "পরিষ্কার চালান এবং ক্যাশে পরিষ্কার করুন", + "Run": "চালান", + "Enable Scoop cleanup on launch": "লঞ্চের সময় Scoop ক্লিনআপ সক্ষম করুন", + "Default vcpkg triplet": "ডিফল্ট vcpkg ট্রিপলেট", + "Change vcpkg root location": "vcpkg রুট অবস্থান পরিবর্তন করুন", + "Reset vcpkg root location": "vcpkg রুট অবস্থান রিসেট করুন", + "Open vcpkg root location": "vcpkg রুট অবস্থান খুলুন", + "Language, theme and other miscellaneous preferences": "ভাষা, থিম এবং অন্যান্য বিবিধ পছন্দ", + "Show notifications on different events": "অপারেশন চলাকালীন একটি নীরব বিজ্ঞপ্তি দেখান", + "Change how UniGetUI checks and installs available updates for your packages": "UniGetUI কীভাবে আপনার প্যাকেজগুলির জন্য উপলব্ধ আপডেটগুলি পরীক্ষা করে এবং ইনস্টল করে তা পরিবর্তন করুন", + "Automatically save a list of all your installed packages to easily restore them.": "সহজেই পুনরুদ্ধার করতে আপনার সমস্ত ইনস্টল করা প্যাকেজগুলির একটি তালিকা স্বয়ংক্রিয়ভাবে সংরক্ষণ করুন।", + "Enable and disable package managers, change default install options, etc.": "প্যাকেজ ম্যানেজার সক্ষম এবং অক্ষম করুন, ডিফল্ট ইনস্টলেশন বিকল্প পরিবর্তন করুন ইত্যাদি।", + "Internet connection settings": "ইন্টারনেট সংযোগ সেটিংস", + "Proxy settings, etc.": "প্রক্সি সেটিংস ইত্যাদি।", + "Beta features and other options that shouldn't be touched": "বেটা বৈশিষ্ট্যগুলো এবং অন্যান্য বিকল্পগুলি যা স্পর্শ করা উচিত হবে না।", + "Reload sources": "উৎস পুনরায় লোড করুন", + "Delete source": "উৎস মুছুন", + "Known sources": "পরিচিত উৎস", + "Update checking": "আপডেট পরীক্ষা", + "Automatic updates": "স্বয়ংক্রিয় আপডেট", + "Check for package updates periodically": "পর্যায়ক্রমে প্যাকেজ আপডেট চেক করুন", + "Check for updates every:": "প্রতিটি আপডেটের জন্য চেক করুনঃ", + "Install available updates automatically": "স্বয়ংক্রিয়ভাবে উপলব্ধ আপডেট ইনস্টল করুন", + "Do not automatically install updates when the network connection is metered": "নেটওয়ার্ক সংযোগ পরিমাপযুক্ত হলে স্বয়ংক্রিয়ভাবে আপডেট ইনস্টল করবেন না", + "Do not automatically install updates when the device runs on battery": "ডিভাইসটি ব্যাটারিতে চলার সময় স্বয়ংক্রিয়ভাবে আপডেট ইনস্টল করবেন না", + "Do not automatically install updates when the battery saver is on": "ব্যাটারি সেভার চালু থাকলে সয়ংক্রিয়ভাবে আপডেট ইনস্টল করবেন না", + "Only show updates that are at least the specified number of days old": "শুধুমাত্র সেই আপডেটগুলো দেখান যেগুলো অন্তত নির্দিষ্ট সংখ্যক দিন পুরোনো", + "Warn me when the installer URL host changes between the installed version and the new version (WinGet only)": "ইনস্টল করা সংস্করণ এবং নতুন সংস্করণের মধ্যে ইনস্টলার URL হোস্ট পরিবর্তিত হলে আমাকে সতর্ক করুন (শুধুমাত্র WinGet)", + "Change how UniGetUI handles install, update and uninstall operations.": "UniGetUI কীভাবে ইনস্টল, আপডেট এবং আনইনস্টল অপারেশন পরিচালনা করে তা পরিবর্তন করুন।", + "Navigation": "নেভিগেশন", + "Check for UniGetUI updates": "UniGetUI আপডেটের জন্য চেক করুন", + "Quit UniGetUI": "UniGetUI বন্ধ করুন", + "Filters": "ফিল্টার", + "Sources": "সূত্র", + "Search for packages to start": "শুরু করার জন্য প্যাকেজ অনুসন্ধান করুন", + "Select all": "সব নির্বাচন করুন", + "Clear selection": "নির্বাচন পরিষ্কার করুন", + "Instant search": "তাৎক্ষণিক অনুসন্ধান", + "Distinguish between uppercase and lowercase": "বড় হাতের এবং ছোট হাতের অক্ষরের মধ্যে পার্থক্য করুন", + "Ignore special characters": "বিশেষ অক্ষরগুলো উপেক্ষা করুন", + "Search mode": "অনুসন্ধান মোড", + "Both": "উভয়", + "Exact match": "খাপে খাপ", + "Show similar packages": "অনুরূপ প্যাকেজ দেখান", + "Loading": "লোড হচ্ছে", + "Package": "প্যাকেজ", + "More options": "আরও বিকল্প", + "Order by:": "অর্ডার করুন:", + "Name": "নাম", + "Id": "আইড", + "Ascendant": "আরোহী", + "Descendant": "বংশধর", + "View modes": "দেখার মোড", + "Reload": "পুনরায় লোড করুন", + "Closed": "বন্ধ", + "Ascending": "ঊর্ধ্বক্রম", + "Descending": "অবরোহী", + "{0}: {1}, {2}": "{0}: {1}, {2}", + "Order by": "ক্রমানুসারে", + "No results were found matching the input criteria": "ইনপুট মানদণ্ডের সাথে মেলে এমন কোনো ফলাফল পাওয়া যায়নি", + "No packages were found": "কোন প্যাকেজ পাওয়া যায়নি", + "Loading packages": "প্যাকেজ লোড হচ্ছে", + "Skip integrity checks": "অখণ্ডতা পরীক্ষা এড়িয়ে যান", + "Download selected installers": "নির্বাচিত ইনস্টলারগুলি ডাউনলোড করুন", + "Install selection": "ইনস্টল নির্বাচন করুন", + "Install options": "ইনস্টল বিকল্প", + "Add selection to bundle": "বান্ডেলে নির্বাচন যোগ করুন", + "Download installer": "ইনস্টলার ডাউনলোড করুন", + "Uninstall selection": "আনইনস্টল নির্বাচন", + "Uninstall options": "আনইনস্টল বিকল্প", + "Ignore selected packages": "নির্বাচিত প্যাকেজ উপেক্ষা করুন", + "Open install location": "ইনস্টল অবস্থান খুলুন", + "Reinstall package": "প্যাকেজ পুনরায় ইনস্টল করুন", + "Uninstall package, then reinstall it": "প্যাকেজ আনইনস্টল করুন, তারপর এটি পুনরায় ইনস্টল করুন", + "Ignore updates for this package": "এই প্যাকেজের আপডেট উপেক্ষা করুন", + "WinGet malfunction detected": "WinGet ত্রুটি সনাক্ত করা হয়েছে", + "It looks like WinGet is not working properly. Do you want to attempt to repair WinGet?": "দেখে মনে হচ্ছে WinGet সঠিকভাবে কাজ করছে না। আপনি WinGet মেরামত করার চেষ্টা করতে চান?", + "Repair WinGet": "WinGet মেরামত করুন", + "Updates will no longer be ignored for {0}": "{0} এর জন্য আপডেট আর উপেক্ষা করা হবে না", + "Updates are now ignored for {0}": "{0} এর জন্য আপডেট এখন উপেক্ষা করা হচ্ছে", + "Do not ignore updates for this package anymore": "এই প্যাকেজের জন্য আর আপডেট উপেক্ষা করবেন না", + "Add packages or open an existing package bundle": "প্যাকেজ যোগ করুন বা একটি বিদ্যমান প্যাকেজ বান্ডিল খুলুন", + "Add packages to start": "শুরু করতে প্যাকেজ যোগ করুন", + "The current bundle has no packages. Add some packages to get started": "বর্তমান বান্ডেলে কোনো প্যাকেজ নেই। শুরু করতে কিছু প্যাকেজ যোগ করুন", + "New": "নতুন", + "Save as": "এই হিসাবে সংরক্ষণ করুন", + "Create .ps1 script": ".ps1 স্ক্রিপ্ট তৈরি করুন", + "Remove selection from bundle": "বান্ডেল থেকে নির্বাচন সরান", + "Skip hash checks": "হ্যাশ পরীক্ষা এড়িয়ে যান", + "The package bundle is not valid": "প্যাকেজ বান্ডিল বৈধ নয়", + "The bundle you are trying to load appears to be invalid. Please check the file and try again.": "আপনি যে বান্ডেলটি লোড করার চেষ্টা করছেন তা অবৈধ মনে হচ্ছে। ফাইলটি পরীক্ষা করুন এবং আবার চেষ্টা করুন।", + "Package bundle": "প্যাকেজ বান্ডিল", + "Could not create bundle": "বান্ডিল তৈরি করা যায়নি", + "The package bundle could not be created due to an error.": "একটি ত্রুটির কারণে প্যাকেজ বান্ডিল তৈরি করা যায়নি।", + "Install script": "ইনস্টল স্ক্রিপ্ট", + "PowerShell script": "PowerShell স্ক্রিপ্ট", + "The installation script saved to {0}": "ইনস্টলেশন স্ক্রিপ্ট {0}-তে সংরক্ষিত", + "An error occurred": "একটি ত্রুটি ঘটেছে", + "An error occurred while attempting to create an installation script:": "ইনস্টলেশন স্ক্রিপ্ট তৈরি করার চেষ্টা করার সময় একটি ত্রুটি ঘটেছে:", + "Hooray! No updates were found.": "কোনো নতুন আপডেট পাওয়া যায়নি!", + "Uninstall selected packages": "নির্বাচিত প্যাকেজ আনইনস্টল করুন", + "Update selection": "আপডেট নির্বাচন", + "Update options": "আপডেট বিকল্প", + "Uninstall package, then update it": "প্যাকেজ আনইনস্টল করুন, তারপর এটি আপডেট করুন", + "Uninstall package": "প্যাকেজ আনইনস্টল করুন", + "Skip this version": "এই সংস্করণে এড়িয়ে যান", + "Pause updates for": "এর জন্য আপডেট স্থগিত করুন", + "User | Local": "ব্যবহারকারী | স্থানীয়", + "Machine | Global": "মেশিন | গ্লোবাল", + "The default package manager for Debian/Ubuntu-based Linux distributions.
Contains: Debian/Ubuntu packages": "Debian/Ubuntu-ভিত্তিক Linux ডিস্ট্রিবিউশনের ডিফল্ট প্যাকেজ ম্যানেজার।
অন্তর্ভুক্ত: Debian/Ubuntu প্যাকেজ", + "The Rust package manager.
Contains: Rust libraries and programs written in Rust": "Rust প্যাকেজ ম্যানেজার।
অন্তর্ভুক্ত: Rust লাইব্রেরি এবং Rust-এ লেখা প্রোগ্রাম", + "The classical package manager for windows. You'll find everything there.
Contains: General Software": "উইন্ডোজের জন্য ক্লাসিক্যাল প্যাকেজ ম্যানেজার। আপনি সেখানে সবকিছু পাবেন.
ধারণ করে: সাধারণ সফ্টওয়্যার", + "The default package manager for RHEL/Fedora-based Linux distributions.
Contains: RPM packages": "RHEL/Fedora-ভিত্তিক Linux ডিস্ট্রিবিউশনের ডিফল্ট প্যাকেজ ম্যানেজার।
অন্তর্ভুক্ত: RPM প্যাকেজ", + "A repository full of tools and executables designed with Microsoft's .NET ecosystem in mind.
Contains: .NET related tools and scripts": "মাইক্রোসফটের .NET ইকোসিস্টেমকে মাথায় রেখে ডিজাইন করা টুলস এবং এক্সিকিউটেবলে পূর্ণ একটি ভান্ডার।
এতে রয়েছে: .NET সম্পর্কিত টুল এবং স্ক্রিপ্ট", + "The universal Linux package manager for desktop applications.
Contains: Flatpak applications from configured remotes": "ডেস্কটপ অ্যাপ্লিকেশনের জন্য সার্বজনীন Linux প্যাকেজ ম্যানেজার।
অন্তর্ভুক্ত: কনফিগার করা রিমোট থেকে Flatpak অ্যাপ্লিকেশন", + "NuPkg (zipped manifest)": "NuPkg (জিপ করা ম্যানিফেস্ট)", + "The Missing Package Manager for macOS (or Linux).
Contains: Formulae, Casks": "macOS (বা Linux)-এর জন্য অনুপস্থিত প্যাকেজ ম্যানেজার।
রয়েছে: Formulae, Casks", + "Node JS's package manager. Full of libraries and other utilities that orbit the javascript world
Contains: Node javascript libraries and other related utilities": "নোড জেএস এর প্যাকেজ ম্যানেজার। লাইব্রেরি এবং অন্যান্য ইউটিলিটি পূর্ণ যা জাভাস্ক্রিপ্ট বিশ্বকে প্রদক্ষিণ করে
এতে রয়েছে: নোড জাভাস্ক্রিপ্ট লাইব্রেরি এবং অন্যান্য সম্পর্কিত ইউটিলিটিগুলি", + "The default package manager for Arch Linux and its derivatives.
Contains: Arch Linux packages": "Arch Linux এবং এর ডেরিভেটিভগুলোর ডিফল্ট প্যাকেজ ম্যানেজার।
অন্তর্ভুক্ত: Arch Linux প্যাকেজ", + "Python's library manager. Full of python libraries and other python-related utilities
Contains: Python libraries and related utilities": "পাইথনের লাইব্রেরি ম্যানেজার। পাইথন লাইব্রেরি এবং অন্যান্য পাইথন-সম্পর্কিত ইউটিলিটিগুলিতে পরিপূর্ণ
অন্তর্ভুক্ত: পাইথন লাইব্রেরি এবং সম্পর্কিত ইউটিলিটিগুলি", + "PowerShell's package manager. Find libraries and scripts to expand PowerShell capabilities
Contains: Modules, Scripts, Cmdlets": "পাওয়ারশেলের প্যাকেজ ম্যানেজার। PowerShell ক্ষমতা প্রসারিত করতে লাইব্রেরি এবং স্ক্রিপ্ট খুঁজুন
অন্তর্ভুক্তঃ মডিউল, স্ক্রিপ্ট, Cmdlets", + "extracted": "আহরণ করা", + "Scoop package": "স্কুপ প্যাকেজ", + "Great repository of unknown but useful utilities and other interesting packages.
Contains: Utilities, Command-line programs, General Software (extras bucket required)": "অজানা কিন্তু দরকারী ইউটিলিটি এবং অন্যান্য আকর্ষণীয় প্যাকেজগুলির দুর্দান্ত সংগ্রহস্থল৷
অন্তর্ভুক্ত: ইউটিলিটি, কমান্ড-লাইন প্রোগ্রাম, সাধারণ সফ্টওয়্যার (অতিরিক্ত বাকেট প্রয়োজন)", + "The universal Linux package manager by Canonical.
Contains: Snap packages from the Snapcraft store": "Canonical-এর তৈরি সার্বজনীন Linux প্যাকেজ ম্যানেজার।
অন্তর্ভুক্ত: Snapcraft স্টোর থেকে Snap প্যাকেজ", + "library": "লাইব্রেরি", + "feature": "বৈশিষ্ট্য", + "A popular C/C++ library manager. Full of C/C++ libraries and other C/C++-related utilities
Contains: C/C++ libraries and related utilities": "একটি জনপ্রিয় C/C++ লাইব্রেরি ম্যানেজার। C/C++ লাইব্রেরি এবং অন্যান্য C/C++ সম্পর্কিত ইউটিলিটিতে পূর্ণ
অন্তর্ভুক্ত: C/C++ লাইব্রেরি এবং সম্পর্কিত ইউটিলিটি", + "option": "বিকল্প", + "This package cannot be installed from an elevated context.": "এই প্যাকেজটি একটি উচ্চ প্রসঙ্গ থেকে ইনস্টল করা যায় না।", + "Please run UniGetUI as a regular user and try again.": "অনুগ্রহ করে UniGetUI একটি নিয়মিত ব্যবহারকারী হিসাবে চালান এবং আবার চেষ্টা করুন।", + "Please check the installation options for this package and try again": "এই প্যাকেজের জন্য ইনস্টলেশন বিকল্পগুলি পরীক্ষা করুন এবং আবার চেষ্টা করুন", + "Microsoft's official package manager. Full of well-known and verified packages
Contains: General Software, Microsoft Store apps": "মাইক্রোসফটের অফিসিয়াল প্যাকেজ ম্যানেজার। সুপরিচিত এবং যাচাইকৃত প্যাকেজে পূর্ণ
অন্তর্ভুক্ত: সাধারণ সফটওয়্যার, মাইক্রোসফ্ট স্টোর অ্যাপস", + "Local PC": "স্থানীয় পিসি", + "Android Subsystem": "অ্যান্ড্রয়েড সাবসিস্টেম", + "Operation on queue (position {0})...": "সারিতে অপারেশন (অবস্থান {0})...", + "Click here for more details": "আরও বিবরণের জন্য এখানে ক্লিক করুন", + "Operation canceled by user": "ব্যবহারকারী দ্বারা অপারেশন বাতিল করা হয়েছে", + "Running PreOperation ({0}/{1})...": "PreOperation চলছে ({0}/{1})...", + "PreOperation {0} out of {1} failed, and was tagged as necessary. Aborting...": "{1}-এর মধ্যে PreOperation {0} ব্যর্থ হয়েছে এবং এটিকে প্রয়োজনীয় হিসেবে চিহ্নিত করা ছিল। বাতিল করা হচ্ছে...", + "PreOperation {0} out of {1} finished with result {2}": "{1}-এর মধ্যে PreOperation {0} {2} ফলাফল নিয়ে শেষ হয়েছে", + "Starting operation...": "অপারেশন শুরু হচ্ছে...", + "Running PostOperation ({0}/{1})...": "PostOperation চলছে ({0}/{1})...", + "PostOperation {0} out of {1} failed, and was tagged as necessary. Aborting...": "{1}-এর মধ্যে PostOperation {0} ব্যর্থ হয়েছে এবং এটিকে প্রয়োজনীয় হিসেবে চিহ্নিত করা ছিল। বাতিল করা হচ্ছে...", + "PostOperation {0} out of {1} finished with result {2}": "{1}-এর মধ্যে PostOperation {0} {2} ফলাফল নিয়ে শেষ হয়েছে", + "{package} installer download": "{package} ইনস্টলার ডাউনলোড", + "{0} installer is being downloaded": "{0} ইনস্টলার ডাউনলোড করা হচ্ছে", + "Download succeeded": "ডাউনলোড সফল হয়েছে", + "{package} installer was downloaded successfully": "{package} ইনস্টলার সফলভাবে ডাউনলোড করা হয়েছে", + "Download failed": "ডাউনলোড ব্যর্থ হয়েছে", + "{package} installer could not be downloaded": "{package} ইনস্টলার ডাউনলোড করা যায়নি", + "{package} Installation": "{package} ইনস্টলেশন", + "{0} is being installed": "{0} ইনস্টল করা হচ্ছে", + "Installation succeeded": "ইনস্টলেশন সফল হয়েছে", + "{package} was installed successfully": "{package} সফলভাবে ইনস্টল করা হয়েছে", + "Installation failed": "ইনস্টলেশন ব্যর্থ হয়েছে", + "{package} could not be installed": "{package} ইনস্টল করা যায়নি", + "{package} Update": "{package} আপডেট", + "Update succeeded": "আপডেট সফল হয়েছে", + "{package} was updated successfully": "{package} সফলভাবে আপডেট করা হয়েছে", + "Update failed": "আপডেট ব্যর্থ হয়েছে", + "{package} could not be updated": "{package} আপডেট করা যায়নি", + "{package} Uninstall": "{package} আনইনস্টল", + "{0} is being uninstalled": "{0} আনইনস্টল করা হচ্ছে", + "Uninstall succeeded": "আনইনস্টল সফল হয়েছে৷", + "{package} was uninstalled successfully": "{package} সফলভাবে আনইনস্টল করা হয়েছে", + "Uninstall failed": "আনইনস্টল ব্যর্থ হয়েছে৷", + "{package} could not be uninstalled": "{package} আনইনস্টল করা যায়নি", + "Adding source {source}": "{source} যোগ করা হচ্ছে", + "Adding source {source} to {manager}": "{manager}-এ {source} যোগ করা হচ্ছে", + "Source added successfully": "উৎস সফলভাবে যোগ করা হয়েছে", + "The source {source} was added to {manager} successfully": "উৎস {source} সফলভাবে {manager}-এ যোগ করা হয়েছে", + "Could not add source": "উৎস যোগ করা যায়নি", + "Could not add source {source} to {manager}": "{manager}-এ {source} যোগ করা যায়নি", + "Removing source {source}": "{source} সরানো হচ্ছে", + "Removing source {source} from {manager}": "{manager} থেকে উৎস {source} সরানো হচ্ছে", + "Source removed successfully": "উৎস সফলভাবে সরানো হয়েছে", + "The source {source} was removed from {manager} successfully": "উৎস {source} সফলভাবে {manager} থেকে সরানো হয়েছে", + "Could not remove source": "উৎস সরানো যায়নি", + "Could not remove source {source} from {manager}": "{manager} থেকে উৎস {source} সরানো যায়নি", + "The package manager \"{0}\" was not found": "প্যাকেজ ম্যানেজার \"{0}\" পাওয়া যায়নি", + "The package manager \"{0}\" is disabled": "প্যাকেজ ম্যানেজার \"{0}\" অক্ষম করা আছে", + "There is an error with the configuration of the package manager \"{0}\"": "প্যাকেজ ম্যানেজার \"{0}\"-এর কনফিগারেশনে একটি ত্রুটি রয়েছে", + "The package \"{0}\" was not found on the package manager \"{1}\"": "প্যাকেজ \"{0}\" প্যাকেজ ম্যানেজার \"{1}\"-এ পাওয়া যায়নি", + "{0} is disabled": "{0} বন্ধ রয়েছে", + "{0} weeks": "{0} সপ্তাহ", + "1 month": "১ মাস", + "{0} months": "{0} মাস", + "Something went wrong": "কিছু ভুল হয়েছে", + "An interal error occurred. Please view the log for further details.": "একটি অভ্যন্তরীণ ত্রুটি ঘটেছে. আরো বিস্তারিত জানার জন্য লগ দেখুন.", + "No applicable installer was found for the package {0}": "{0} প্যাকেজের জন্য কোন প্রযোজ্য ইনস্টলার পাওয়া যায়নি", + "Integrity checks will not be performed during this operation": "এই অপারেশনের সময় অখণ্ডতা পরীক্ষা সম্পাদিত হবে না", + "This is not recommended.": "এটি সুপারিশ করা হয় না।", + "Run now": "এখনই চালান", + "Run next": "পরবর্তীতে চালান", + "Run last": "শেষে চালান", + "Show in explorer": "এক্সপ্লোরারে দেখান", + "Checked": "চেক করা", + "Unchecked": "আনচেক করা", + "This package is already installed": "এই প্যাকেজ ইতিমধ্যে ইনস্টল করা আছে", + "This package can be upgraded to version {0}": "এই প্যাকেজটি {0} সংস্করণে আপগ্রেড করা যেতে পারে", + "Updates for this package are ignored": "এই প্যাকেজের জন্য আপডেট উপেক্ষা করা হয়", + "This package is being processed": "এই প্যাকেজ প্রক্রিয়া করা হচ্ছে", + "This package is not available": "এই প্যাকেজটি উপলব্ধ নয়", + "Select the source you want to add:": "আপনি যে উৎসটি যোগ করতে চান তা নির্বাচন করুনঃ", + "Source name:": "উৎসের নামঃ", + "Source URL:": "উৎস URL", + "An error occurred when adding the source: ": "উৎস যোগ করার সময় একটি ত্রুটি ঘটেছেঃ", + "Package management made easy": "প্যাকেজ পরিচালনা সহজ করা হয়েছে", + "version {0}": "সংস্করণ {0}", + "[RAN AS ADMINISTRATOR]": "প্রশাসক হিসাবে চালানো হয়েছে", + "Portable mode": "পোর্টেবল মোড\n", + "DEBUG BUILD": "ডিবাগ বিল্ড", + "Here you can change UniGetUI's behaviour regarding the following shortcuts. Checking a shortcut will make UniGetUI delete it if if gets created on a future upgrade. Unchecking it will keep the shortcut intact": "এখানে আপনি নিম্নলিখিত শর্টকাটগুলির বিষয়ে UniGetUI-এর আচরণ পরিবর্তন করতে পারেন। একটি শর্টকাট চেক করা UniGetUI-কে ভবিষ্যতের আপগ্রেডে এটি তৈরি হলে মুছে ফেলতে বাধ্য করবে। এটি আনচেক করলে শর্টকাটটি অক্ষুণ্ণ থাকবে", + "Manual scan": "ম্যানুয়াল স্ক্যান", + "Existing shortcuts on your desktop will be scanned, and you will need to pick which ones to keep and which ones to remove.": "আপনার ডেস্কটপের বিদ্যমান শর্টকাটগুলি স্ক্যান করা হবে এবং আপনি কোনগুলি রাখতে এবং কোনগুলি সরাতে হবে তা বেছে নিতে হবে।", + "Delete?": "মুছবেন?", + "I understand": "আমি বুঝেছি", + "Chocolatey setup changed": "Chocolatey সেটআপ পরিবর্তন হয়েছে", + "UniGetUI no longer includes its own private Chocolatey installation. A legacy UniGetUI-managed Chocolatey installation was detected for this user profile, but system Chocolatey was not found. Chocolatey will stay unavailable in UniGetUI until Chocolatey is installed on the system and UniGetUI is restarted. Applications previously installed through UniGetUI's bundled Chocolatey may still appear under other sources such as Local PC or WinGet.": "UniGetUI আর তার নিজস্ব প্রাইভেট Chocolatey ইনস্টলেশন অন্তর্ভুক্ত করে না। এই ব্যবহারকারী প্রোফাইলের জন্য একটি পুরানো UniGetUI-পরিচালিত Chocolatey ইনস্টলেশন সনাক্ত করা হয়েছে, কিন্তু সিস্টেম Chocolatey পাওয়া যায়নি। সিস্টেমে Chocolatey ইনস্টল করা এবং UniGetUI পুনরায় চালু করা না হওয়া পর্যন্ত Chocolatey UniGetUI-তে অনুপলব্ধ থাকবে। UniGetUI-এর বান্ডিলড Chocolatey-এর মাধ্যমে পূর্বে ইনস্টল করা অ্যাপ্লিকেশনগুলি এখনও অন্যান্য উৎস যেমন স্থানীয় পিসি বা WinGet-এর অধীনে দেখা যেতে পারে।", + "NOTE: This troubleshooter can be disabled from UniGetUI Settings, on the WinGet section": "নোট: এই সমস্যা নির্ণায়ক UniGetUI সেটিংস থেকে WinGet বিভাগে অক্ষম করা যেতে পারে", + "Restart": "পুনরায় চালু করুন", + "Are you sure you want to delete all shortcuts?": "আপনি কি সমস্ত শর্টকাট মুছতে চান?", + "Any new shorcuts created during an install or an update operation will be deleted automatically, instead of showing a confirmation prompt the first time they are detected.": "ইনস্টল বা আপডেট অপারেশনের সময় তৈরি করা নতুন শর্টকাটগুলি স্বয়ংক্রিয়ভাবে মুছে ফেলা হবে, প্রথমবার সনাক্ত করা হলে নিশ্চিতকরণ প্রম্পট দেখানোর পরিবর্তে।", + "Any shorcuts created or modified outside of UniGetUI will be ignored. You will be able to add them via the {0} button.": "UniGetUI-এর বাইরে তৈরি বা পরিবর্তিত যেকোনো শর্টকাট উপেক্ষা করা হবে। আপনি {0} বোতামের মাধ্যমে সেগুলি যোগ করতে পারবেন।", + "Are you really sure you want to enable this feature?": "আপনি সত্যিই এই বৈশিষ্ট্যটি সক্ষম করতে চান?", + "No new shortcuts were found during the scan.": "স্ক্যানের সময় কোন নতুন শর্টকাট পাওয়া যায়নি।", + "How to add packages to a bundle": "বান্ডেলে প্যাকেজ যোগ করার উপায়", + "In order to add packages to a bundle, you will need to: ": "বান্ডেলে প্যাকেজ যোগ করতে আপনার প্রয়োজন হবে: ", + "1. Navigate to the \"{0}\" or \"{1}\" page.": "১. \"{0}\" বা \"{1}\" পৃষ্ঠায় নেভিগেট করুন।", + "2. Locate the package(s) you want to add to the bundle, and select their leftmost checkbox.": "২. বান্ডেলে যোগ করতে চান এমন প্যাকেজ খুঁজুন এবং তাদের সবচেয়ে বাঁদিকের চেকবক্স নির্বাচন করুন।", + "3. When the packages you want to add to the bundle are selected, find and click the option \"{0}\" on the toolbar.": "৩. বান্ডেলে যোগ করতে চান এমন প্যাকেজগুলি নির্বাচন করা হলে, টুলবারে \"{0}\" বিকল্পটি খুঁজুন এবং ক্লিক করুন।", + "4. Your packages will have been added to the bundle. You can continue adding packages, or export the bundle.": "৪. আপনার প্যাকেজগুলি বান্ডেলে যোগ করা হবে। আপনি প্যাকেজ যোগ করা চালিয়ে যেতে পারেন বা বান্ডেলটি রপ্তানি করতে পারেন।", + "Which backup do you want to open?": "আপনি কোন ব্যাকআপটি খুলতে চান?", + "Select the backup you want to open. Later, you will be able to review which packages you want to install.": "আপনি যে ব্যাকআপটি খুলতে চান তা নির্বাচন করুন। পরে, আপনি কোন প্যাকেজ/প্রোগ্রাম পুনরুদ্ধার করতে চান তা পর্যালোচনা করতে পারবেন।", + "There are ongoing operations. Quitting UniGetUI may cause them to fail. Do you want to continue?": "চলমান অভিযান চলছে। UniGetUI ত্যাগ করা তাদের ব্যর্থ হতে পারে। আপনি কি চালিয়ে যেতে চান?", + "UniGetUI or some of its components are missing or corrupt.": "UniGetUI বা এর কিছু উপাদান অনুপস্থিত বা দুর্নীতিগ্রস্ত।", + "It is strongly recommended to reinstall UniGetUI to adress the situation.": "পরিস্থিতি সমাধানের জন্য UniGetUI পুনরায় ইনস্টল করার দৃঢ় সুপারিশ করা হয়।", + "Refer to the UniGetUI Logs to get more details regarding the affected file(s)": "প্রভাবিত ফাইলগুলির বিষয়ে আরও বিবরণ পেতে UniGetUI লগস দেখুন", + "Integrity checks can be disabled from the Experimental Settings": "অখণ্ডতা পরীক্ষা পরীক্ষামূলক সেটিংস থেকে অক্ষম করা যেতে পারে", + "Repair UniGetUI": "UniGetUI মেরামত করুন", + "Live output": "লাইভ আউটপুট", + "This package bundle had some settings that are potentially dangerous, and may be ignored by default.": "এই প্যাকেজ বান্ডেলে সম্ভাব্য বিপজ্জনক কিছু সেটিংস ছিল এবং ডিফল্টরূপে উপেক্ষা করা যেতে পারে।", + "Entries that show in YELLOW will be IGNORED.": "হলুদ রঙে দেখানো প্রবিষ্টিগুলি উপেক্ষা করা হবে।", + "Entries that show in RED will be IMPORTED.": "লাল রঙে দেখানো প্রবিষ্টিগুলি আমদানি করা হবে।", + "You can change this behavior on UniGetUI security settings.": "আপনি UniGetUI নিরাপত্তা সেটিংসে এই আচরণ পরিবর্তন করতে পারেন।", + "Open UniGetUI security settings": "UniGetUI নিরাপত্তা সেটিংস খুলুন", + "Should you modify the security settings, you will need to open the bundle again for the changes to take effect.": "যদি আপনি নিরাপত্তা সেটিংস পরিবর্তন করেন তবে পরিবর্তনগুলি কার্যকর হওয়ার জন্য আপনাকে বান্ডেলটি আবার খুলতে হবে।", + "Details of the report:": "রিপোর্টের বিবরণ:", + "Are you sure you want to create a new package bundle? ": "আপনি কি একটি নতুন প্যাকেজ বান্ডিল তৈরি করতে চান? ", + "Any unsaved changes will be lost": "সংরক্ষিত না করা কোনো পরিবর্তন হারিয়ে যাবে", + "Warning!": "সতর্কতা!", + "For security reasons, custom command-line arguments are disabled by default. Go to UniGetUI security settings to change this. ": "নিরাপত্তার কারণে, কাস্টম কমান্ড-লাইন আর্গুমেন্ট ডিফল্টরূপে অক্ষম করা আছে। এটি পরিবর্তন করতে UniGetUI নিরাপত্তা সেটিংসে যান। ", + "Change default options": "ডিফল্ট বিকল্প পরিবর্তন করুন", + "Ignore future updates for this package": "এই প্যাকেজের জন্য ভবিষ্যতের আপডেটগুলি উপেক্ষা করুন", + "For security reasons, pre-operation and post-operation scripts are disabled by default. Go to UniGetUI security settings to change this. ": "নিরাপত্তার কারণে, প্রাক-অপারেশন এবং পোস্ট-অপারেশন স্ক্রিপ্টগুলি ডিফল্টরূপে অক্ষম করা আছে। এটি পরিবর্তন করতে UniGetUI নিরাপত্তা সেটিংসে যান। ", + "You can define the commands that will be run before or after this package is installed, updated or uninstalled. They will be run on a command prompt, so CMD scripts will work here.": "আপনি এমন কমান্ডগুলি সংজ্ঞায়িত করতে পারেন যা এই প্যাকেজটি ইনস্টল, আপডেট বা আনইনস্টল করার আগে বা পরে চালানো হবে। তারা একটি কমান্ড প্রম্পটে চালানো হবে তাই CMD স্ক্রিপ্টগুলি এখানে কাজ করবে।", + "Change this and unlock": "এটি পরিবর্তন করুন এবং আনলক করুন", + "{0} Install options are currently locked because {0} follows the default install options.": "{0} ইনস্টল বিকল্পগুলি বর্তমানে লক করা আছে কারণ {0} ডিফল্ট ইনস্টল বিকল্পগুলি অনুসরণ করে।", + "Unset or unknown": "আনসেট বা অজানা", + "This package has no screenshots or is missing the icon? Contrbute to UniGetUI by adding the missing icons and screenshots to our open, public database.": "এই প্যাকেজের কোন স্ক্রিনশট নেই বা আইকনটি নেই? আমাদের উন্মুক্ত, পাবলিক ডাটাবেসে অনুপস্থিত আইকন এবং স্ক্রিনশট যোগ করে UniGetUI-তে অবদান রাখুন।", + "Become a contributor": "অবদানকারী হয়ে উঠুন", + "Update to {0} available": "{0} এর আপডেট উপলব্ধ", + "Reinstall": "পুনরায় ইনস্টল করুন", + "Installer not available": "ইনস্টলার উপলব্ধ নয়", + "Version:": "সংস্করণ:", + "UniGetUI Version {0}": "UniGetUI সংস্করণ {0}", + "Performing backup, please wait...": "ব্যাকআপ করা হচ্ছে, অনুগ্রহ করে অপেক্ষা করুন...", + "An error occurred while logging in: ": "লগ ইন করার সময় একটি ত্রুটি ঘটেছে: ", + "Fetching available backups...": "উপলব্ধ ব্যাকআপ আনা হচ্ছে...", + "Done!": "সম্পন্ন!", + "The cloud backup has been loaded successfully.": "ক্লাউড ব্যাকআপ সফলভাবে লোড করা হয়েছে।", + "An error occurred while loading a backup: ": "ব্যাকআপ লোড করার সময় একটি ত্রুটি ঘটেছে: ", + "Backing up packages to GitHub Gist...": "GitHub Gist-এ প্যাকেজ ব্যাকআপ করা হচ্ছে...", + "Backup Successful": "ব্যাকআপ সফল", + "The cloud backup completed successfully.": "ক্লাউড ব্যাকআপ সফলভাবে সম্পন্ন হয়েছে।", + "Could not back up packages to GitHub Gist: ": "GitHub Gist-এ প্যাকেজ ব্যাকআপ করা যায়নি: ", + "It is not guaranteed that the provided credentials will be stored safely, so you may as well not use the credentials of your bank account": "প্রদান করা প্রশংসাপত্রগুলি নিরাপদে সংরক্ষিত হওয়ার গ্যারান্টি নেই, তাই আপনি আপনার ব্যাংক অ্যাকাউন্টের প্রশংসাপত্র ব্যবহার করতে পারেন না", + "Enable the automatic WinGet troubleshooter": "স্বয়ংক্রিয় WinGet সমস্যা নির্ণয় সক্ষম করুন", + "Add updates that fail with a 'no applicable update found' to the ignored updates list": "\" কোন প্রযোজ্য আপডেট পাওয়া যায়নি\" দিয়ে ব্যর্থ হওয়া আপডেটগুলি উপেক্ষা করা আপডেটগুলির তালিকায় যোগ করুন।", + "Invalid selection": "অবৈধ নির্বাচন", + "No package was selected": "কোনো প্যাকেজ নির্বাচিত হয়নি", + "More than 1 package was selected": "১টিরও বেশি প্যাকেজ নির্বাচন করা হয়েছে", + "List": "তালিকা", + "Grid": "গ্রিড", + "Icons": "আইকন", + "\"{0}\" is a local package and does not have available details": "\"{0}\" একটি স্থানীয় প্যাকেজ এবং বিস্তারিত তথ্য উপলব্ধ নেই", + "\"{0}\" is a local package and is not compatible with this feature": "\"{0}\" একটি স্থানীয় প্যাকেজ এবং এই বৈশিষ্ট্যের সাথে সামঞ্জস্যপূর্ণ নয়", + "Add packages to bundle": "বান্ডেলে প্যাকেজ যোগ করুন", + "Preparing packages, please wait...": "প্যাকেজ প্রস্তুত করা হচ্ছে, অনুগ্রহ করে অপেক্ষা করুন...", + "Loading packages, please wait...": "প্যাকেজ লোড হচ্ছে, অনুগ্রহ করে অপেক্ষা করুন...", + "Saving packages, please wait...": "প্যাকেজ সংরক্ষণ করা হচ্ছে, অনুগ্রহ করে অপেক্ষা করুন...", + "The bundle was created successfully on {0}": "বান্ডেলটি {0}-এ সফলভাবে তৈরি করা হয়েছে", + "User profile": "ব্যবহারকারী প্রোফাইল", + "Error": "ত্রুটি", + "Log in failed: ": "লগ ইন ব্যর্থ: ", + "Log out failed: ": "লগ আউট ব্যর্থ: ", + "Package backup settings": "প্যাকেজ ব্যাকআপ সেটিংস", + "Manage UniGetUI autostart behaviour from the Settings app": "UniGetUI-এর স্বয়ংক্রিয় চালু হওয়ার আচরণ পরিচালনা করুন", + "Choose how many operations shoulds be performed in parallel": "কতগুলো অপারেশন সমান্তরালে চালানো হবে তা নির্বাচন করুন", + "Something went wrong while launching the updater.": "আপডেটার চালু করার সময় কিছু ভুল হয়েছে।", + "Please try again later": "অনুগ্রহ করে পরে আবার চেষ্টা করুন", + "Show the release notes after UniGetUI is updated": "UniGetUI আপডেট হওয়ার পর রিলিজ নোট দেখান" +} diff --git a/src/Languages/lang_ca.json b/src/Languages/lang_ca.json new file mode 100644 index 0000000..b59ff0f --- /dev/null +++ b/src/Languages/lang_ca.json @@ -0,0 +1,850 @@ +{ + "{0} of {1} operations completed": "{0} de {1} operacions completades", + "{0} is now {1}": "{0} ara és {1}", + "Enabled": "Activat", + "Disabled": "Desactivat", + "Privacy": "Privadesa", + "Hide my username from the logs": "Amaga el meu nom d'usuari dels registres", + "Replaces your username with **** in the logs. Restart UniGetUI to also hide it from already-recorded entries.": "Substitueix el vostre nom d'usuari per **** als registres. Reinicieu l'UniGetUI per amagar-lo també de les entrades ja registrades.", + "Your last update attempt did not complete.": "El darrer intent d'actualització no s'ha completat.", + "UniGetUI could not confirm whether the update succeeded. Open the log to see what happened.": "L'UniGetUI no ha pogut confirmar si l'actualització ha tingut èxit. Obriu el registre per veure què ha passat.", + "View log": "Mostra el registre", + "The installer reported success but did not restart UniGetUI.": "L'instal·lador ha informat que l'operació ha estat correcta, però no ha reiniciat l'UniGetUI.", + "The installer failed to initialize.": "L'instal·lador no s'ha pogut inicialitzar.", + "Setup was canceled before installation began.": "La configuració s'ha cancel·lat abans que comencés la instal·lació.", + "A fatal error occurred during the preparation phase.": "S'ha produït un error fatal durant la fase de preparació.", + "A fatal error occurred during installation.": "S'ha produït un error fatal durant la instal·lació.", + "Installation was canceled while in progress.": "La instal·lació s'ha cancel·lat mentre estava en curs.", + "The installer was terminated by another process.": "Un altre procés ha finalitzat l'instal·lador.", + "The preparation phase determined the installation cannot proceed.": "La fase de preparació ha determinat que la instal·lació no pot continuar.", + "The installer could not start. UniGetUI may already be running, or you do not have permission to install.": "No s'ha pogut iniciar l'instal·lador. Pot ser que l'UniGetUI ja s'estigui executant o que no tingueu permís per instal·lar.", + "Unexpected installer error.": "Error inesperat de l'instal·lador.", + "We are checking for updates.": "Estem cercant actualitzacions.", + "Please wait": "Si us plau, espereu", + "Great! You are on the latest version.": "Fantàstic! Esteu a la darrera versió.", + "There are no new UniGetUI versions to be installed": "No hi ha noves versions de l'UniGetUI disponibles", + "UniGetUI version {0} is being downloaded.": "Estem descarregant l'UniGetUI versió {0}", + "This may take a minute or two": "Això pot trigar un parell de minuts", + "The installer authenticity could not be verified.": "No s'ha pogut verificar l'autenticitat de l'instal·lador.", + "The update process has been aborted.": "S'ha avortat l'actualització", + "Auto-update is not yet available on this platform.": "L'actualització automàtica encara no està disponible en aquesta plataforma.", + "Please update UniGetUI manually.": "Actualitzeu l'UniGetUI manualment.", + "An error occurred when checking for updates: ": "Hi ha hagut un error quan es cercaven les actualitzacions: ", + "The updater could not be launched.": "No s'ha pogut iniciar l'actualitzador.", + "The operating system did not start the installer process.": "El sistema operatiu no ha iniciat el procés de l'instal·lador.", + "UniGetUI is being updated...": "Estem actualitzant l'UniGetUI...", + "Update installed.": "Actualització instal·lada.", + "UniGetUI was updated successfully, but this running copy was not replaced. This usually means you are running a development build. Close this copy and start the newly-installed version to finish.": "L'UniGetUI s'ha actualitzat correctament, però aquesta còpia en execució no s'ha substituït. Normalment això vol dir que esteu executant una compilació de desenvolupament. Tanqueu aquesta còpia i inicieu la versió acabada d'instal·lar per finalitzar.", + "The update could not be applied.": "No s'ha pogut aplicar l'actualització.", + "Installer exit code {0}: {1}": "Codi de sortida de l'instal·lador {0}: {1}", + "Update cancelled.": "Actualització cancel·lada.", + "Authentication was cancelled.": "S'ha cancel·lat l'autenticació.", + "Installer exit code {0}": "Codi de sortida de l'instal·lador {0}", + "Operation in progress": "Operacions en progrés", + "Please wait...": "Si us plau espereu...", + "Success!": "Èxit!", + "Failed": "Hi ha hagut un error", + "An error occurred while processing this package": "Hi ha hagut un error al processar aquest paquet", + "Installer": "Instal·lador", + "Executable": "Fitxer executable", + "MSI": "MSI", + "Compressed file": "Fitxer comprimit", + "MSIX": "MSIX", + "WinGet was repaired successfully": "S'ha reparat el WinGet correctament.", + "It is recommended to restart UniGetUI after WinGet has been repaired": "Es recomana reiniciar l'UniGetUI un cop s'ha reparat el WinGet", + "WinGet could not be repaired": "No s'ha pogut reparar el WinGet", + "An unexpected issue occurred while attempting to repair WinGet. Please try again later": "Hi ha hagut un error durant la reparació del WinGet. Proveu-ho més tard", + "Log in to enable cloud backup": "Inicieu la sessió per a activar la còpia de seguretat al núvol", + "Backup Failed": "La còpia de seguretat ha fallat", + "Downloading backup...": "Descarregant la còpia...", + "An update was found!": "S'ha trobat una actualització!", + "{0} can be updated to version {1}": "{0} es pot actualitzar a la versió {1}", + "Updates found!": "S'han trobat actualitzacions!", + "{0} packages can be updated": "Es poden actualitzar {0} paquets", + "{0} is being updated to version {1}": "{0} s'està actualitzant a la versió {1}", + "{0} packages are being updated": "{0} estan sent actualitzats", + "You have currently version {0} installed": "Actualment teniu instal·lada la versió {0}", + "Desktop shortcut created": "Drecera creada a l'escriptori", + "UniGetUI has detected a new desktop shortcut that can be deleted automatically.": "L'UniGetUI ha detectat que s'ha creat 1 nova drecera a l'escriptori que es pot eliminar automàticament.", + "{0} desktop shortcuts created": "S'han creat {0} dreceres a l'escriptori", + "UniGetUI has detected {0} new desktop shortcuts that can be deleted automatically.": "L'UniGetUI ha detectat que s'han creat {0} noves dreceres a l'escriptori que es poden eliminar automàticament.", + "Attention required": "Es requereix atenció", + "Restart required": "Reinici requerit", + "1 update is available": "Hi ha 1 actualització disponible", + "{0} updates are available": "Hi ha {0} actualitzacions disponibles", + "Everything is up to date": "Tot està al dia", + "Discover Packages": "Descobrir programari", + "Available Updates": "Actualitzacions disponibles", + "Installed Packages": "Programari instal·lat", + "UniGetUI Version {0} by Devolutions": "UniGetUI versió {0} de Devolutions", + "Show UniGetUI": "Mostra l'UniGetUI", + "Quit": "Tanca", + "Are you sure?": "N'esteu segur/a?", + "Do you really want to uninstall {0}?": "Realment voleu desinstal·lar el {0}?", + "Do you really want to uninstall the following {0} packages?": "Voleu desinstal·lar els següents {0} paquets?", + "No": "No", + "Yes": "Sí", + "Partial": "Parcial", + "View on UniGetUI": "Mostra a l'UniGetUI", + "Update": "Actualitza", + "Open UniGetUI": "Obre l'UniGetUI", + "Update all": "Actualitza-ho tot", + "Update now": "Actualitza ara", + "Installer host changed since the installed version.\n": "L'amfitrió de l'instal·lador ha canviat respecte de la versió instal·lada.\n", + "This package is on the queue": "Aquest paquet està a la cua", + "installing": "instal·lant", + "updating": "actualitzant", + "uninstalling": "desinstal·lant", + "installed": "instal·lat", + "Retry": "Reintentar", + "Install": "Instal·la", + "Uninstall": "Desinstal·la", + "Open": "Obre", + "Operation profile:": "Perfil d'operació:", + "Follow the default options when installing, upgrading or uninstalling this package": "Segueix les opcions per defecte quan s'instal·li, s'actualitzi o es desinstal·li aquest paquet", + "The following settings will be applied each time this package is installed, updated or removed.": "Les següents opcions s'aplicaran cada cop que aquest paquet s'instal·li, s'actualitzi o es desinstal·li.", + "Version to install:": "Versió a instal·lar:", + "Architecture to install:": "Arquitectura a instal·lar:", + "Installation scope:": "Entorn d'instal·lació:", + "Install location:": "Ubicació d'instal·lació:", + "Select": "Sel·lecciona", + "Reset": "Reseteja", + "Custom install arguments:": "Arguments d'instal·lació personalitzats", + "Custom update arguments:": "Arguments d'actualització personalitzats", + "Custom uninstall arguments:": "Arguments de desinstal·lació personalitzats", + "Pre-install command:": "Comanda de pre-instal·lació:", + "Post-install command:": "Comanda de post-instal·lació:", + "Abort install if pre-install command fails": "Avorta la instal·lació si la comanda de pre-instal·lació falla", + "Pre-update command:": "Comanda de pre-actualització:", + "Post-update command:": "Comanda de post-actualització:", + "Abort update if pre-update command fails": "Avorta l'actualització si la comanda de pre-actualització falla", + "Pre-uninstall command:": "Comanda de pre-desinstal·lació:", + "Post-uninstall command:": "Comanda de post-desinstal·lació:", + "Abort uninstall if pre-uninstall command fails": "Avorta la desinstal·lació si la comanda de pre-desinstal·lació falla", + "Command-line to run:": "Línia de comandes a executar:", + "Save and close": "Desa i tanca", + "General": "Configuració general", + "Architecture & Location": "Arquitectura i ubicació", + "Command-line": "Línia d'ordres", + "Close apps": "Tanca aplicacions", + "Pre/Post install": "Pre/Postinstal·lació", + "Select the processes that should be closed before this package is installed, updated or uninstalled.": "Seleccioneu els processos que s'haurien de tancar abans que aquest paquet s'instal·li, s'actualitzi o es desinstal·li.", + "Write here the process names here, separated by commas (,)": "Escriviu aquí els noms dels processos, separats per comes (,)", + "Try to kill the processes that refuse to close when requested to": "Intenta matar els processos que refusen tancar-se quan se'ls demani.", + "Run as admin": "Executa com a administrador", + "Interactive installation": "Instal·lació interactiva", + "Skip hash check": "No comprovis el hash", + "Uninstall previous versions when updated": "Desinstal·la les versions anteriors en actualitzar", + "Skip minor updates for this package": "Salta't les actualitzacions menors d'aquest paquet", + "Automatically update this package": "Actualitza aquest paquet automàticament", + "{0} installation options": "Opcions d'instal·lació del {0}", + "Latest": "Darrera", + "PreRelease": "PreLlançament", + "Default": "Per defecte", + "Manage ignored updates": "Administra les actualitzacions ignorades", + "The packages listed here won't be taken in account when checking for updates. Double-click them or click the button on their right to stop ignoring their updates.": "Els paquets mostrats aquí no es tindran en compte quan es comprovi si hi ha actualitzacions disponibles. Cliqueu-los dos cops o premeu el botó de la seva dreta per a deixar d'ignorar-ne les actualitzacions.", + "Reset list": "Reseteja la llista", + "Do you really want to reset the ignored updates list? This action cannot be reverted": "Realment voleu restablir la llista d'actualitzacions ignorades? Aquesta acció no es pot desfer.", + "No ignored updates": "No hi ha actualitzacions ignorades", + "Package Name": "Nom del paquet", + "Package ID": "Identificador del paquet", + "Ignored version": "Versió ignorada", + "New version": "Nova versió", + "Source": "Origen", + "All versions": "Totes les versions", + "Unknown": "Desconegut", + "Up to date": "Al dia", + "Package {name} from {manager}": "Paquet {name} de {manager}", + "Remove {0} from ignored updates": "Suprimeix {0} de les actualitzacions ignorades", + "Cancel": "Cancel·la", + "Administrator privileges": "Drets d'administrador", + "This operation is running with administrator privileges.": "Aquesta operació s'està executant amb privilegis d'administrador.", + "Interactive operation": "Operació interactiva", + "This operation is running interactively.": "Aquesta operació s'està executant de forma interactiva.", + "You will likely need to interact with the installer.": "Segurament haureu d'interactuar amb l'instal·lador.", + "Integrity checks skipped": "Comprovacions d'integritat omeses", + "Integrity checks will not be performed during this operation.": "No es faran comprovacions d'integritat durant aquesta operació.", + "Proceed at your own risk.": "Continueu sota la vostra responsabilitat", + "Close": "Tanca", + "Loading...": "Carregant...", + "Installer SHA256": "SHA256 de l'instal·lador", + "Homepage": "Lloc web", + "Author": "Autor/a", + "Publisher": "Publicador", + "License": "Llicència", + "Manifest": "Manifest", + "Installer Type": "Tipus d'instal·lador", + "Size": "Mida", + "Installer URL": "Enllaç de l'instal·lador", + "Last updated:": "Actualitzat per darrer cop:", + "Release notes URL": "Enllaç de les notes de publicació", + "Package details": "Detalls del paquet", + "Dependencies:": "Dependències:", + "Release notes": "Notes de publicació", + "Screenshots": "Captures de pantalla", + "This package has no screenshots or is missing the icon? Contribute to UniGetUI by adding the missing icons and screenshots to our open, public database.": "Aquest paquet no té captures de pantalla o li falta la icona? Contribuïu a UniGetUI afegint les icones i captures de pantalla que falten a la nostra base de dades oberta i pública.", + "Version": "Versió", + "Install as administrator": "Instal·la com a administrador", + "Update to version {0}": "Actualitza a la versió {0}", + "Installed Version": "Versió instal·lada", + "Update as administrator": "Actualitza com a administrador", + "Interactive update": "Actualització interactiva", + "Uninstall as administrator": "Desinstal·la com a administrador", + "Interactive uninstall": "Desinstal·lació interactiva", + "Uninstall and remove data": "Desinstal·la i elimina'n les dades", + "Not available": "No disponible", + "Installer SHA512": "SHA512 de l'instal·lador", + "Unknown size": "Mida desconeguda", + "No dependencies specified": "No s'han especificat dependències", + "mandatory": "obligatori", + "optional": "opcional", + "UniGetUI {0} is ready to be installed.": "L'UniGetUI {0} està llest per a ser instal·lat", + "The update process will start after closing UniGetUI": "El procés d'actualització començarà en tancar l'UniGetUI", + "UniGetUI has been ran as administrator, which is not recommended. When running UniGetUI as administrator, EVERY operation launched from UniGetUI will have administrator privileges. You can still use the program, but we highly recommend not running UniGetUI with administrator privileges.": "L'UniGetUI s'ha executat com a administrador, cosa que no es recomana. Quan l'UniGetUI s'executa com a administrador, TOTES les operacions iniciades des de l'UniGetUI tindran privilegis d'administrador. Encara podeu utilitzar el programa, però recomanem fermament no executar l'UniGetUI amb privilegis d'administrador.", + "Share anonymous usage data": "Comparteix dades d'ús anònimes", + "UniGetUI collects anonymous usage data in order to improve the user experience.": "L'UniGetUI recull dades d'ús anònimes amb la finalitat de millorar l'experiència de l'usuari.", + "Accept": "Acceptar", + "Software Updates": "Actualitzacions", + "Package Bundles": "Col·leccions de paquets", + "Settings": "Configuració", + "Package Managers": "Admin. de Paquets", + "UniGetUI Log": "Registre de l'UniGetUI", + "Package Manager logs": "Registre dels administradors de paquets", + "Operation history": "Historial d'operacions", + "Help": "Ajuda", + "UniGetUI": "UniGetUI", + "You have installed UniGetUI Version {0}": "Teniu instal·lat l'UniGetUI versió {0}", + "Disclaimer": "Exempció de responsabilitat", + "UniGetUI is developed by Devolutions and is not affiliated with any of the compatible package managers.": "L'UniGetUI està desenvolupat per Devolutions i no està afiliat a cap dels administradors de paquets compatibles.", + "UniGetUI wouldn't have been possible without the help of the contributors. Thank you all 🥳": "L'UniGetUI no hagués estat possible sense l'ajuda dels contribuïdors. Moltes gràcies a tots 🥳", + "UniGetUI uses the following libraries. Without them, UniGetUI wouldn't have been possible.": "L'UniGetUI utilitza les següents llibreries. Sense elles, l'UniGetUI no hagués estat possible.", + "{0} homepage": "lloc web de {0}", + "UniGetUI has been translated to more than 40 languages thanks to the volunteer translators. Thank you 🤝": "L'UniGetUI ha estat traduit a més de 40 idiomes gràcies als traductors voluntaris. Gràcies 🤝", + "Verbose": "Verbós", + "1 - Errors": "1 - Errors", + "2 - Warnings": "2 - Advertències", + "3 - Information (less)": "3 - Informació (menys)", + "4 - Information (more)": "4 - Informació (més)", + "5 - information (debug)": "5 - Informació (depuració)", + "Warning": "Atenció", + "The following settings may pose a security risk, hence they are disabled by default.": "Les opcions següents poden representar un risc de seguretat, raó per la qual s'han desactivat per seguretat", + "Enable the settings below if and only if you fully understand what they do, and the implications they may have.": "Activeu les opcions de sota SI I NOMÉS SI enteneu què fan, i les implicacions i perills que poden comportar.", + "The settings will list, in their descriptions, the potential security issues they may have.": "Les opcions mostraran, en les seves descripcions, els perills potencials que pot representar activar-les.", + "The backup will include the complete list of the installed packages and their installation options. Ignored updates and skipped versions will also be saved.": "La còpia inclourà una llista completa dels paquets instal·lats i de les seves respectives opcions d'instal·lació. Les actualitzacions ignorades i les versions saltades també es desaran.", + "The backup will NOT include any binary file nor any program's saved data.": "La còpia no inclourà cap tipus de fitxers binaris o dades de cap programa.", + "The size of the backup is estimated to be less than 1MB.": "La mida estimada de la còpia serà de menys d'1 MB.", + "The backup will be performed after login.": "La còpia es realitzarà després de l'inici de sessió", + "{pcName} installed packages": "Paquets instal·lats de {pcName}", + "Current status: Not logged in": "Estat: no s'ha iniciat la sessió", + "You are logged in as {0} (@{1})": "Heu iniciat la sessió com a {0} (@{1})", + "Nice! Backups will be uploaded to a private gist on your account": "Fantàstic! Les còpies de seguretat es carregaran en un Gist privat al vostre compte", + "Select backup": "Seleccioneu una còpia", + "Settings imported from {0}": "Configuració importada de {0}", + "UniGetUI Settings": "Configuració de l'UniGetUI", + "Settings exported to {0}": "Configuració exportada a {0}", + "UniGetUI settings were reset": "La configuració d'UniGetUI s'ha restablert", + "Allow pre-release versions": "Permet versions de prellançament", + "Apply": "Aplica", + "For security reasons, custom command-line arguments are disabled by default. Go to UniGetUI security settings to change this.": "Per motius de seguretat, els arguments personalitzats de la línia d'ordres estan desactivats per defecte. Aneu a la configuració de seguretat de l'UniGetUI per canviar-ho.", + "Go to UniGetUI security settings": "Configuració de seguretat de l'UniGetUI", + "The following options will be applied by default each time a {0} package is installed, upgraded or uninstalled.": "Les opcions següents s'aplicaran per defecte cada cop que un paquet del {0} s'instal·li, s'acualitzi o es desinstal·li.", + "Package's default": "Predeterminat del paquet", + "Install location can't be changed for {0} packages": "La ubicació d'instal·lació no es pot canviar per els paquets del {0}", + "The local icon cache currently takes {0} MB": "La memòria cau d'icones actualment ocupa {0} MB", + "Username": "Nom d'usuari", + "Password": "Contrasenya", + "Credentials": "Credencials", + "It is not guaranteed that the provided credentials will be stored safely": "No es garanteix que les credencials proporcionades s'emmagatzemin de manera segura", + "Partially": "Parcialment", + "Package manager": "Administrador de paquets", + "Compatible with proxy": "Compatible amb el proxy", + "Compatible with authentication": "Compatible amb l'autenticació", + "Proxy compatibility table": "Taula de compatibilitat amb Proxy", + "{0} settings": "Configuració del {0}", + "{0} status": "Estat del {0}", + "Default installation options for {0} packages": "Opcions d'instal·lació per defecte pels paquets del {0}", + "Expand version": "Mostra la versió", + "The executable file for {0} was not found": "El fitxer executable del {0} no s'ha trobat", + "{pm} is disabled": "{pm} està desactivat", + "Enable it to install packages from {pm}.": "Activeu-lo per a instal·lar paquets del {pm}.", + "{pm} is enabled and ready to go": "{pm} està activat i a punt", + "{pm} version:": "Versió del {pm}: ", + "{pm} was not found!": "No s'ha trobat el {pm}!", + "You may need to install {pm} in order to use it with UniGetUI.": "Potser heu d'instal·lar el {pm} si el voleu utilitzar a través l'UniGetUI.", + "Scoop Installer - UniGetUI": "Instal·lador de l'Scoop - UniGetUI", + "Scoop Uninstaller - UniGetUI": "Desinstal·lador de l'Scoop - UniGetUI", + "Clearing Scoop cache - UniGetUI": "Netejant la memòria cau de l'Scoop - UniGetUI", + "Restart UniGetUI to fully apply changes": "Reinicieu l'UniGetUI per aplicar completament els canvis", + "Restart UniGetUI": "Reinicia l'UniGetUI", + "Manage {0} sources": "Administra les fonts del {0}", + "Add source": "Afegeix una font", + "Add": "Afegeix", + "Source name": "Nom de la font", + "Source URL": "URL de la font", + "Other": "Una altra", + "No minimum age": "Sense antiguitat mínima", + "1 day": "1 dia", + "{0} days": "{0} dies", + "Custom...": "Personalitzat...", + "{0} minutes": "{0} minuts", + "1 hour": "1 hora", + "{0} hours": "{0} hores", + "1 week": "1 setmana", + "Supports release dates": "Admet dates de llançament", + "Release date support per package manager": "Compatibilitat amb dates de llançament per gestor de paquets", + "Search for packages": "Cerqueu paquets", + "Local": "Local", + "OK": "D'acord", + "Last checked: {0}": "Última comprovació: {0}", + "{0} packages were found, {1} of which match the specified filters.": "S'han trobat {1} paquets, {0} dels quals s'ajusten als filtres establerts.", + "{0} selected": "{0} seleccionats", + "(Last checked: {0})": "(Comprovat per darrer cop: {0})", + "All packages selected": "Tots els paquets seleccionats", + "Package selection cleared": "Selecció de paquets esborrada", + "{0}: {1}": "{0}: {1}", + "More info": "Més detalls", + "GitHub account": "Compte de GitHub", + "Log in with GitHub to enable cloud package backup.": "Inicieu la sessió amb el GitHub per a activar la còpia de seguretat al núvol", + "More details": "Més detalls", + "Log in": "Inicia la sessió", + "If you have cloud backup enabled, it will be saved as a GitHub Gist on this account": "Si heu activat la còpia de seguretat al núvol, aquesta es desarà en un Gist de GitHub privat en aquest compte.", + "Log out": "Tanca la sessió", + "About UniGetUI": "Sobre l'UniGetUI", + "About": "Sobre", + "Third-party licenses": "Llicències de tercers", + "Contributors": "Contribuïdors", + "Translators": "Traductors", + "Bundle security report": "Informe de seguretat de la col·lecció de paquets", + "The bundle contained restricted content": "La col·lecció contenia contingut restringit", + "UniGetUI – Crash Report": "UniGetUI – Informe d'error", + "UniGetUI has crashed": "UniGetUI s'ha bloquejat", + "Help us fix this by sending a crash report to Devolutions. All fields below are optional.": "Ajudeu-nos a solucionar-ho enviant un informe d'error a Devolutions. Tots els camps següents són opcionals.", + "Email (optional)": "Correu electrònic (opcional)", + "your@email.com": "el.teu@correu.com", + "Additional details (optional)": "Detalls addicionals (opcional)", + "Describe what you were doing when the crash occurred…": "Descriviu què estàveu fent quan es va produir l'error…", + "Crash report": "Informe d'error", + "Don't Send": "No enviïs", + "Send Report": "Envia l'informe", + "Sending…": "Enviant…", + "Unsaved changes": "Canvis sense desar", + "You have unsaved changes in the current bundle. Do you want to discard them?": "Hi ha canvis sense desar a la col·lecció actual. Voleu descartar-los?", + "Discard changes": "Descarta els canvis", + "Integrity violation": "Infracció d'integritat", + "UniGetUI or some of its components are missing or corrupt. It is strongly recommended to reinstall UniGetUI to adress the situation.": "L'UniGetUI o alguns dels seus components falten o estan malmesos. Es recomana fermament reinstal·lar l'UniGetUI per solucionar aquesta situació.", + "• Refer to the UniGetUI Logs to get more details regarding the affected file(s)": "• Veieu el registre de l'UniGetUI per a obtenir més detalls sobre el(s) fitxer(s) afectat(s)", + "• Integrity checks can be disabled from the Experimental Settings": "• Les comprovacions d'identitat es poden desactivar des de la configuració experimental", + "Manage shortcuts": "Administrar les dreceres", + "UniGetUI has detected the following desktop shortcuts which can be removed automatically on future upgrades": "L'UniGetUI ha detectat les següents dreceres a l'escriptori que es poden eliminar automàticament durant les actualitzacions", + "Do you really want to reset this list? This action cannot be reverted.": "Realment voleu resetejar aquesta llista? Aquesta acció no es pot desfer.", + "Desktop shortcuts list": "Llista de dreceres d'escriptori", + "Open in explorer": "Obre a l'Explorador", + "Remove from list": "Treu de la llista", + "When new shortcuts are detected, delete them automatically instead of showing this dialog.": "Quan es trobin noves icones, elimina-les automàticament en comptes de mostrar aquest quadre de diàleg.", + "Not right now": "Ara no", + "Missing dependency": "Fa falta una dependència", + "UniGetUI requires {0} to operate, but it was not found on your system.": "L'UniGetUI necessita el {0} per a funcionar, però aquest no ha estat trobat al sistema.", + "Click on Install to begin the installation process. If you skip the installation, UniGetUI may not work as expected.": "Cliqueu a Instal·lar per a començar el procés d'instal·lació. Si no instal·leu la dependència, l'UniGetUI podria no funcionar bé.", + "Alternatively, you can also install {0} by running the following command in a Windows PowerShell prompt:": "Alternativament, també es pot instal·lar el {0} executant la següent comanda en una línia de comandes del Windows PowerShell:", + "Install {0}": "Instal·la el {0}", + "Do not show this dialog again for {0}": "No mostris mai aquest diàleg per al {0}", + "Please wait while {0} is being installed. A black window may show up. Please wait until it closes.": "Si us plau, espereu mentre el {0} s'instal·la. Pot aparèixer una finestra negra (o blava). Espereu a que es tanqui.", + "{0} has been installed successfully.": "El {0} s'ha instal·lat correctament.", + "Please click on \"Continue\" to continue": "Cliqueu \"Continuar\" per a continuar", + "Continue": "Continuar", + "{0} has been installed successfully. It is recommended to restart UniGetUI to finish the installation": "El {0} s'ha instal·lat correctament. Es recomana reiniciar l'UniGetUI per a acabar la instal·lació", + "Restart later": "Reincia més tard", + "An error occurred:": "Hi ha hagut un error:", + "Please see the Command-line Output or refer to the Operation History for further information about the issue.": "Veieu la Sortida de la línia de comandes o l'historial d'operacions per a més detalls sobre l'error.", + "Retry as administrator": "Torna a provar-ho com a administrador", + "Retry interactively": "Torna a provar-ho de forma interactiva", + "Retry skipping integrity checks": "Torna a provar-ho sense comprovacions d'integritat", + "Installation options": "Opcions d'instal·lació", + "Save": "Desa", + "UniGetUI collects anonymous usage data with the sole purpose of understanding and improving the user experience.": "L'UniGetUI recull dades d'ús anònimes amb la única finalitat d'entendre i millorar l'experiència de l'usuari.", + "More details about the shared data and how it will be processed": "Més detalls sobre com es processen les dades recollides", + "Do you accept that UniGetUI collects and sends anonymous usage statistics, with the sole purpose of understanding and improving the user experience?": "Accepteu que l'UniGetUI reculli i enviï dades d'ús anònimes, amb l'únic propòsit d'entendre i millorar l'experiència de l'ususari?", + "Decline": "Declinar", + "No personal information is collected nor sent, and the collected data is anonimized, so it can't be back-tracked to you.": "No es recull ni s'envia informació personal, i la informació recollida s'anonimitza, de forma que no es pot relacionar amb tu.", + "Navigation panel": "Panell de navegació", + "Operations": "Operacions", + "Toggle operations panel": "Mostra o amaga el panell d'operacions", + "Bulk operations": "Operacions massives", + "Retry failed": "Reintenta les fallides", + "Clear successful": "Esborra les correctes", + "Clear finished": "Esborra les finalitzades", + "Cancel all": "Cancel·la-ho tot", + "More": "Més", + "Toggle navigation panel": "Mostra o amaga el panell de navegació", + "Minimize": "Minimitza", + "Maximize": "Maximitza", + "UniGetUI by Devolutions": "UniGetUI de Devolutions", + "UniGetUI is an application that makes managing your software easier, by providing an all-in-one graphical interface for your command-line package managers.": "L'UniGetUI és una aplicació que facilita l'administració de software, oferint una interfície gràfica unificada per als administradors de paquets més coneguts.", + "Useful links": "Enllaços útils", + "UniGetUI Homepage": "Pàgina principal de l'UniGetUI", + "Report an issue or submit a feature request": "Informeu d'un problema o suggeriu una característica nova", + "UniGetUI Repository": "Repositori de l'UniGetUI", + "View GitHub Profile": "Perfil de GitHub", + "UniGetUI License": "Llicència de l'UniGetUI", + "Using UniGetUI implies the acceptation of the MIT License": "Usar l'UniGetUI implica l'acceptació de la llicència MIT", + "Become a translator": "Fer-se traductor", + "Go back": "Torna enrere", + "Go forward": "Avança", + "Go to home page": "Ves a la pàgina d'inici", + "Reload page": "Torna a carregar la pàgina", + "View page on browser": "Mostra al navegador", + "The built-in browser is not supported on Linux yet.": "El navegador integrat encara no és compatible amb Linux.", + "Open in browser": "Obre al navegador", + "Copy to clipboard": "Copia al porta-retalls", + "Export to a file": "Exporta a un fitxer", + "Log level:": "Nivell del registre:", + "Reload log": "Recarrega el registre", + "Export log": "Exporta el registre", + "Text": "Text", + "Change how operations request administrator rights": "Canvieu com les operacions demanen drets d'administrador", + "Restrictions on package operations": "Restriccions a les operacions amb paquets", + "Restrictions on package managers": "Restriccions als administradors de paquets", + "Restrictions when importing package bundles": "Restriccions a l'importar col·leccions de paquets", + "Ask for administrator privileges once for each batch of operations": "Demana drets d'administrador per a cada grup d'operacions", + "Ask only once for administrator privileges": "Pregunta només un cop per als permisos d'administrador", + "Prohibit any kind of Elevation via UniGetUI Elevator or GSudo": "Prohibeix qualsevol tipus d'elevació mitjançant l'UniGetUI Elevator o el GSudo ", + "This option WILL cause issues. Any operation incapable of elevating itself WILL FAIL. Install/update/uninstall as administrator will NOT WORK.": "Aquesta opció causarà problemes. Qualsevol operació que no es pugui autoelevar FALLARÀ. Les opcions instal·la/actualitza/desinstal·la com a administrador NO FUNCIONARAN.", + "Allow custom command-line arguments": "Permet arguments personalitzats de la línia d'ordres", + "Custom command-line arguments can change the way in which programs are installed, upgraded or uninstalled, in a way UniGetUI cannot control. Using custom command-lines can break packages. Proceed with caution.": "Els arguments de línia d'ordres personalitzats poden canviar la manera com s'instal·len, s'actualitzen o es desinstal·len els programes, d'una manera que UniGetUI no pot controlar. L'ús de línies d'ordres personalitzades pot trencar els paquets. Procediu amb precaució.", + "Ignore custom pre-install and post-install commands when importing packages from a bundle": "Permet que s'executin comandes personalitzades de pre-instal·lació i post-instal·lació", + "Pre and post install commands will be run before and after a package gets installed, upgraded or uninstalled. Be aware that they may break things unless used carefully": "Les ordres prèvies i posteriors a la instal·lació s'executaran abans i després que s'instal·li, s'actualitzi o s'instal·li un paquet. Tingueu en compte que poden trencar coses si no s'utilitzen amb cura.", + "Allow changing the paths for package manager executables": "Permeteu canviar els fitxers executables dels administradors de paquets", + "Turning this on enables changing the executable file used to interact with package managers. While this allows finer-grained customization of your install processes, it may also be dangerous": "Activar això permetrà canviar el fitxer executable a través del qual l'UniGetUI interactua i es comunica amb els administradors de paquets. Mentre que això permet modificar millor els processos d'instal·lació, també pot resultar perillós.", + "Allow importing custom command-line arguments when importing packages from a bundle": "Permet la importació d'arguments personalitzats de la línia d'ordres en importar paquets d'una col·lecció", + "Malformed command-line arguments can break packages, or even allow a malicious actor to gain privileged execution. Therefore, importing custom command-line arguments is disabled by default": "Els arguments de línia d'ordres amb format incorrecte poden trencar els paquets o fins i tot permetre que un actor maliciós obtingui una execució privilegiada. Per tant, la importació d'arguments de línia d'ordres personalitzats està desactivada per defecte.", + "Allow importing custom pre-install and post-install commands when importing packages from a bundle": "Permeteu la importació de comandes de pre-instal·lació i post-instal·lació quan s'importin paquets des d'una col·lecció de paquets", + "Pre and post install commands can do very nasty things to your device, if designed to do so. It can be very dangerous to import the commands from a bundle, unless you trust the source of that package bundle": "Les ordres prèvies i posteriors a la instal·lació poden fer coses molt desagradables al vostre dispositiu, si estan dissenyades per fer-ho. Pot ser molt perillós importar les ordres des d'un paquet, tret que confieu en la font d'aquest paquet.", + "Administrator rights and other dangerous settings": "Drets d'administrador i altres configuracions perilloses", + "Package backup": "Còpia de seguretat dels paquets", + "Cloud package backup": "Còpia de seguretat al núvol", + "Local package backup": "Còpia de seguretat local", + "Local backup advanced options": "Opcions avançades de la còpia local", + "Log in with GitHub": "Inicieu la sessió amb el GitHub", + "Log out from GitHub": "Tanca la sessió del GitHub", + "Periodically perform a cloud backup of the installed packages": "Fes una còpia al núvol periòdica dels paquets instal·lats ", + "Cloud backup uses a private GitHub Gist to store a list of installed packages": "La còpia de seguretat al núvol utilitza un GitHub Gist privat per a desar-hi la llista de paquets que teniu instal·lats a l'ordinador", + "Perform a cloud backup now": "Fes una còpia al núvol ara", + "Backup": "Fes la còpia", + "Restore a backup from the cloud": "Restaura una còpia de seguretat del núvol", + "Begin the process to select a cloud backup and review which packages to restore": "Comença el procés de selecció i revisió de quins paquets s'ha de restaurar", + "Periodically perform a local backup of the installed packages": "Fes una còpia local periòdica dels paquets instal·lats", + "Perform a local backup now": "Fes una còpia local ara", + "Change backup output directory": "Canvia el directori de sortida de la còpia", + "Set a custom backup file name": "Nom del fitxer de la còpia de seguretat", + "Leave empty for default": "Deixeu-ho buit per al valor predeterminat", + "Add a timestamp to the backup file names": "Afegeix la data i l'hora als noms de les còpies de seguretat", + "Backup and Restore": "Còpia de seguretat i restauració", + "Enable background api (UniGetUI Widgets and Sharing, port 7058)": "Activa la API de rerefons, (Widgets for UniGetUI i Compartició de paquets, port 7058)", + "Wait for the device to be connected to the internet before attempting to do tasks that require internet connectivity.": "Espereu a que el dispositiu estigui connectat a internet abans d'intentar cap tasca que requereixi connexió a internet.", + "Disable the 1-minute timeout for package-related operations": "Desactiva el temps màxim d'1 minut per a les tasques de llistar paquets", + "Use installed GSudo instead of UniGetUI Elevator": "Utilitza el GSudo instal·lat en comptes de l'UniGetUI Elevator", + "Use a custom icon and screenshot database URL": "Utilitza una base de dades d'icones i captures de pantalla personalitzades", + "Enable background CPU Usage optimizations (see Pull Request #3278)": "Activa les optimitzacions de CPU en rerefons (veieu Pull Request #3278)", + "Perform integrity checks at startup": "Fes una comprovació d'identitat a l'inici", + "When batch installing packages from a bundle, install also packages that are already installed": "Quan s'instal·lin paquets en bloc des d'una col·lecció, instal·la també els paquets que ja estiguin instal·lats. ", + "Experimental settings and developer options": "Configuracions experimentals i altres opcions de desenvolupador", + "Show UniGetUI's version and build number on the titlebar.": "Mostra la versió de l'UniGetUI a la barra de títol", + "Language": "Idioma", + "UniGetUI updater": "Actualitzador de l'UniGetUI", + "Telemetry": "Telemetria", + "Manage UniGetUI settings": "Administra la configuració de l'UniGetUI", + "Related settings": "Configuració relacionada", + "Update UniGetUI automatically": "Actualitza l'UniGetUI automàticament", + "Check for updates": "Cerca actualitzacions", + "Install prerelease versions of UniGetUI": "Instal·la versions de previsualització (no estables) de l'UniGetUI", + "Manage telemetry settings": "Administra la configuració de la telemetria", + "Manage": "Administra", + "Import settings from a local file": "Importa les preferències des d'un fitxer", + "Import": "Importa", + "Export settings to a local file": "Exporta les preferències a un fitxer", + "Export": "Exporta", + "Reset UniGetUI": "Reseteja l'UniGetUI", + "User interface preferences": "Preferències de l'interfície d'usuari", + "Application theme, startup page, package icons, clear successful installs automatically": "Tema de l'aplicació, pàgina d'inici, icones als paquets, neteja les instal·lacions exitoses automàticament", + "General preferences": "Preferències generals", + "UniGetUI display language:": "Idioma de l'UniGetUI:", + "System language": "Idioma del sistema", + "Is your language missing or incomplete?": "Falta el vostre idioma o la traducció està incompleta?", + "Appearance": "Aparença", + "UniGetUI on the background and system tray": "L'UniGetUI al rerefons i safata del sistema", + "Package lists": "Llistes de paquets", + "Use classic mode": "Utilitza el mode clàssic", + "Restart UniGetUI to apply this change": "Reinicieu l'UniGetUI per aplicar aquest canvi", + "The classic UI is disabled for beta testers": "La interfície clàssica està desactivada per als provadors beta", + "Close UniGetUI to the system tray": "Tanca l'UniGetUI a la safata del sistema", + "Manage UniGetUI autostart behaviour": "Gestiona el comportament d'inici automàtic de l'UniGetUI", + "Show package icons on package lists": "Mostra les icones dels paquets a la llista dels paquets", + "Clear cache": "Neteja la memòria cau", + "Select upgradable packages by default": "Selecciona els paquets actualitzables per defecte", + "Light": "Clar", + "Dark": "Fosc", + "Follow system color scheme": "Segueix l'esquema de colors del sistema", + "Application theme:": "Tema de l'aplicació:", + "UniGetUI startup page:": "Pàgina d'inici de l'UniGetUI", + "Proxy settings": "Configuració del Proxy", + "Other settings": "Altres configuracions", + "Connect the internet using a custom proxy": "Connecta't a internet mitjaçant un proxy o servidor intermediari personalitzats", + "Please note that not all package managers may fully support this feature": "Nota: alguns administradors de paquets poden no ser del tot compatibles amb aquesta característica", + "Proxy URL": "URL del proxy", + "Enter proxy URL here": "Escriviu l'URL del proxy aquí", + "Authenticate to the proxy with a user and a password": "Autentiqueu-vos al servidor intermediari amb un usuari i una contrasenya", + "Internet and proxy settings": "Configuració d'Internet i del servidor intermediari", + "Package manager preferences": "Preferències dels administradors de paquets", + "Ready": "A punt", + "Not found": "No trobat", + "Notification preferences": "Preferències de les notificacions", + "Notification types": "Tipus de notificacions", + "The system tray icon must be enabled in order for notifications to work": "L'icona de la safata del sistema ha d'estar activada per a que funcionin les notificacions", + "Enable UniGetUI notifications": "Activa les notificacions de l'UniGetUI", + "Show a notification when there are available updates": "Mostra una notificació quan s'hagin trobat actualitzacions", + "Show a silent notification when an operation is running": "Mostra una notificació silenciosa quan s'estigui executant una operació", + "Show a notification when an operation fails": "Mostra una notificació quan una operació falli", + "Show a notification when an operation finishes successfully": "Mostra una notificació quan una operació acabi satisfactòriament", + "Concurrency and execution": "Concurrència i execució", + "Automatic desktop shortcut remover": "Eliminador automàtic de dreceres de l'escriptori", + "Choose how many operations should be performed in parallel": "Trieu quantes operacions s'han de fer en paral·lel", + "Clear successful operations from the operation list after a 5 second delay": "Treu de la llista les operacions exitoses automàticament cap de 5 segons", + "Download operations are not affected by this setting": "Les operacions de descàrrega no es veuran afectades per aquesta opció", + "You may lose unsaved data": "És possible que es perdin dades no desades.", + "Ask to delete desktop shortcuts created during an install or upgrade.": "Pregunta si eliminar les noves dreceres de l'escriptori creades durant una instal·lació o actualització.", + "Package update preferences": "Preferències d'actualització dels paquets", + "Update check frequency, automatically install updates, etc.": "Frequència de comprovació de les actualitzacions, instal·la automàticament les actualitzacions, etc.", + "Reduce UAC prompts, elevate installations by default, unlock certain dangerous features, etc.": "Redueix els missatges d'UAC, eleva instal·lacions per defecte, desbloqueja característiques perilloses de l'UniGetUI, etc.", + "Package operation preferences": "Preferències de les operacions dels paquets", + "Enable {pm}": "Activa el {pm}", + "Not finding the file you are looking for? Make sure it has been added to path.": "No trobes el que busques? Assegura't que el fitxer està afegit al camí (PATH)", + "Select the executable to be used. The following list shows the executables found by UniGetUI": "Sel·lecciona l'executable a utilitzar. La següent llista mostra els fitxers executables trobats per l'UniGetUI", + "For security reasons, changing the executable file is disabled by default": "Per raons de seguretat, l'opció de canviar el fitxer executable està desactivada", + "Change this": "Canviar això", + "Copy path": "Copia el camí", + "Current executable file:": "Fitxer executable actual:", + "Ignore packages from {pm} when showing a notification about updates": "Ignora els paquets del {pm} quan es notifiquin les actualitzacions disponibles", + "Update security": "Seguretat de les actualitzacions", + "Use global setting": "Utilitza la configuració global", + "Minimum age for updates": "Antiguitat mínima de les actualitzacions", + "e.g. 10": "p. ex. 10", + "Custom minimum age (days)": "Antiguitat mínima personalitzada (dies)", + "{pm} does not provide release dates for its packages, so this setting will have no effect": "{pm} no proporciona dates de llançament per als seus paquets, de manera que aquesta configuració no tindrà cap efecte", + "{pm} only provides release dates for some of its packages, so this setting will only apply to those packages": "{pm} només proporciona dates de publicació per a alguns dels seus paquets, així que aquesta opció només s'aplicarà a aquells paquets", + "Override the global minimum update age for this package manager": "Substitueix l'antiguitat mínima global de les actualitzacions per a aquest gestor de paquets", + "View {0} logs": "Mostra el registre del {0}", + "If Python cannot be found or is not listing packages but is installed on the system, ": "Si no es troba Python o no llista paquets però està instal·lat al sistema, ", + "Advanced options": "Opcions avançades", + "WinGet command-line tool": "Eina de línia d'ordres del WinGet", + "Choose which command-line tool UniGetUI uses for WinGet operations when the COM API is not used": "Trieu quina eina de línia d'ordres utilitza UniGetUI per a les operacions de WinGet quan no s'utilitza la COM API", + "WinGet COM API": "API COM del WinGet", + "Choose whether UniGetUI can use the WinGet COM API before falling back to the command-line tool": "Trieu si UniGetUI pot utilitzar la COM API de WinGet abans de recórrer a l'eina de línia d'ordres", + "Reset WinGet": "Reseteja el WinGet", + "This may help if no packages are listed": "Això pot ajudar si no es mostren paquetsa les llistes", + "Force install location parameter when updating packages with custom locations": "Forca el paràmetre d'ubicació quan s'actualitzin paquets amb ubicacions personalitzades", + "Install Scoop": "Instal·la l'Scoop", + "Uninstall Scoop (and its packages)": "Desinstal·la l'Scoop (i les seves aplicacions)", + "Run cleanup and clear cache": "Executa la neteja i buida la memòria cau", + "Run": "Executa", + "Enable Scoop cleanup on launch": "Activa la comanda scoop cleanup en iniciar", + "Default vcpkg triplet": "Triplet per defecte del vcpkg", + "Change vcpkg root location": "Canvia la ubicació arrel del vcpkg", + "Reset vcpkg root location": "Restableix la ubicació arrel de vcpkg", + "Open vcpkg root location": "Obre la ubicació arrel de vcpkg", + "Language, theme and other miscellaneous preferences": "Idioma, tema i altres preferències miscel·lànies", + "Show notifications on different events": "Mostra notificacions en diferents situacions", + "Change how UniGetUI checks and installs available updates for your packages": "Canviar com l'UniGetUI comprova i instal·la les actualizacions dels paquets", + "Automatically save a list of all your installed packages to easily restore them.": "Desa automàticament una llista de tots els paquets instal·lats per a restaurar-los fàcilment.", + "Enable and disable package managers, change default install options, etc.": "Activa i desactiva administradors de paquets, opcions d'instal·lació per defecte, etc.", + "Internet connection settings": "Preferències de la connexió a internet", + "Proxy settings, etc.": "Configuració del Proxy, etc.", + "Beta features and other options that shouldn't be touched": "Característiques beta i altres opcions que no s'haurien de tocar", + "Reload sources": "Torna a carregar les fonts", + "Delete source": "Suprimeix la font", + "Known sources": "Fonts conegudes", + "Update checking": "Comprovació d'actualitzacions", + "Automatic updates": "Actualitzacions automàtiques", + "Check for package updates periodically": "Cerca actualitzacions dels paquets periòdicament", + "Check for updates every:": "Cerca actualitzacions cada:", + "Install available updates automatically": "Instal·la de forma automàtica totes les actualitzacions disponibles", + "Do not automatically install updates when the network connection is metered": "No instal·lar automàticament les actualitzacions quan la connexió a internet sigui d'ús mesurat", + "Do not automatically install updates when the device runs on battery": "No instal·lis automàticament les actualitzacions quan l'ordinador no estigui connectat a la corrent", + "Do not automatically install updates when the battery saver is on": "No instal·lar automàticament les actualitzacions quan l'estalviador de bateria estigui activat", + "Only show updates that are at least the specified number of days old": "Mostra només les actualitzacions que tinguin com a mínim el nombre de dies especificat", + "Warn me when the installer URL host changes between the installed version and the new version (WinGet only)": "Avisa'm quan l'amfitrió de l'URL de l'instal·lador canviï entre la versió instal·lada i la nova versió (només WinGet)", + "Change how UniGetUI handles install, update and uninstall operations.": "Canvieu com l'UniGetUI instal·la, actualitza i desinstal·la els paquets.", + "Navigation": "Navegació", + "Check for UniGetUI updates": "Comprova si hi ha actualitzacions de l'UniGetUI", + "Quit UniGetUI": "Surt de l'UniGetUI", + "Filters": "Filtres", + "Sources": "Fonts", + "Search for packages to start": "Cerqueu paquets per a començar", + "Select all": "Selecciona-ho tot", + "Clear selection": "Neteja la selecció", + "Instant search": "Cerca instantània", + "Distinguish between uppercase and lowercase": "Distingeix entre majúscules i minúscules", + "Ignore special characters": "Ignora els caràcters especials", + "Search mode": "Mode de cerca", + "Both": "Ambdós", + "Exact match": "Coincidència exacta", + "Show similar packages": "Mostra paquets similars", + "Loading": "Carregant", + "Package": "Paquet", + "More options": "Més opcions", + "Order by:": "Ordena per:", + "Name": "Nom", + "Id": "ID", + "Ascendant": "Ascendent", + "Descendant": "Descendent", + "View modes": "Modes de visualització", + "Reload": "Torna a carregar", + "Closed": "Tancat", + "Ascending": "Ascendent", + "Descending": "Descendent", + "{0}: {1}, {2}": "{0}: {1}, {2}", + "Order by": "Ordena per", + "No results were found matching the input criteria": "No s'han trobat resultats que compleixin amb els filtres establerts", + "No packages were found": "No s'han trobat paquets", + "Loading packages": "Carregant paquets", + "Skip integrity checks": "Salta les comprovacions d'integritat", + "Download selected installers": "Descarrega els instal·ladors seleccionats", + "Install selection": "Instal·la la selecció", + "Install options": "Opcions d'instal·lació", + "Add selection to bundle": "Afegeix la selecció a la col·lecció", + "Download installer": "Descarrega l'instal·lador", + "Uninstall selection": "Desinstal·la la selecció", + "Uninstall options": "Opcions de desinstal·lació", + "Ignore selected packages": "Ignora els paquets seleccionats", + "Open install location": "Obre la ubicació d'instal·lació", + "Reinstall package": "Reinstal·la el paquet", + "Uninstall package, then reinstall it": "Desinstal·la el paquet, després reinstal·la'l", + "Ignore updates for this package": "Ignora'n les actualitzacions", + "WinGet malfunction detected": "S'ha detectat un funcionament incorrecte del WinGet", + "It looks like WinGet is not working properly. Do you want to attempt to repair WinGet?": "Sembla que el WinGet no està funcionant correctament. Voleu intentar reparar-lo?", + "Repair WinGet": "Repara el WinGet", + "Updates will no longer be ignored for {0}": "Ja no s'ignoraran les actualitzacions per a {0}", + "Updates are now ignored for {0}": "Ara s'ignoren les actualitzacions per a {0}", + "Do not ignore updates for this package anymore": "No ignoreu més les actualitzacions d'aquest paquet", + "Add packages or open an existing package bundle": "Afegiu paquets o obriu una col·lecció", + "Add packages to start": "Afegiu paquets per a començar", + "The current bundle has no packages. Add some packages to get started": "La col·lecció actual no té paquets. Afegiu-ne per a començar", + "New": "Nou", + "Save as": "Desa com", + "Create .ps1 script": "Crea un script .ps1", + "Remove selection from bundle": "Treu la selecció de la col·lecció", + "Skip hash checks": "Ignora les verificacions de hash", + "The package bundle is not valid": "La col·lecció de paquets no és vàlida", + "The bundle you are trying to load appears to be invalid. Please check the file and try again.": "La col·lecció que esteu intentant obrir sembla invàlida. Comproveu el fitxer i torneu-ho a provar.", + "Package bundle": "Col·lecció de paquets", + "Could not create bundle": "No s'ha pogut crear la col·lecció", + "The package bundle could not be created due to an error.": "No s'ha pogut crear la col·lecció a causa d'un error.", + "Install script": "Script d'instal·lació", + "PowerShell script": "Script de PowerShell", + "The installation script saved to {0}": "L'script d'instal·lació s'ha desat correctament a {0}", + "An error occurred": "Hi ha hagut un error", + "An error occurred while attempting to create an installation script:": "Ha ocorregut un error quan es creava l'script d'instal·lació", + "Hooray! No updates were found.": "Visca! No s'han trobat actualitzacions!", + "Uninstall selected packages": "Desinstal·la els paquets seleccionats", + "Update selection": "Actualitza la selecció", + "Update options": "Opcions d'actualització", + "Uninstall package, then update it": "Desinstal·la el paquet, després actualitza'l", + "Uninstall package": "Desinstal·la el paquet", + "Skip this version": "Salta aquesta versió", + "Pause updates for": "Atura les actualitzacions durant", + "User | Local": "Usuari | Local", + "Machine | Global": "Màquina | Global", + "The default package manager for Debian/Ubuntu-based Linux distributions.
Contains: Debian/Ubuntu packages": "El gestor de paquets predeterminat per a distribucions Linux basades en Debian/Ubuntu.
Conté: paquets de Debian/Ubuntu", + "The Rust package manager.
Contains: Rust libraries and programs written in Rust": "L'administrador de paquets del Rust.
Conté: Llibreries i binaris escrits en rust", + "The classical package manager for windows. You'll find everything there.
Contains: General Software": "L'administrador de paquets clàssic del Windows. Hi trobareu de tot.
Conté: Programari general", + "The default package manager for RHEL/Fedora-based Linux distributions.
Contains: RPM packages": "El gestor de paquets predeterminat per a distribucions Linux basades en RHEL/Fedora.
Conté: paquets RPM", + "A repository full of tools and executables designed with Microsoft's .NET ecosystem in mind.
Contains: .NET related tools and scripts": "Un repositori ple d'eines i executables dissenyats amb l'ecosistema .NET de Microsoft
Conté: Eines i scripts relacionats amb .NET", + "The universal Linux package manager for desktop applications.
Contains: Flatpak applications from configured remotes": "L'administrador de paquets universal de Linux per a aplicacions d'escriptori.
Conté: aplicacions Flatpak dels remots configurats", + "NuPkg (zipped manifest)": "NuPkg (manifest comprimit)", + "The Missing Package Manager for macOS (or Linux).
Contains: Formulae, Casks": "El gestor de paquets que faltava per al macOS (o Linux).
Conté: Formulae, Casks", + "Node JS's package manager. Full of libraries and other utilities that orbit the javascript world
Contains: Node javascript libraries and other related utilities": "L'administrador de paquets del Node JS. Ple de llibreries i d'altres utilitats que orbiten al voltant del mon de Javascript.
Conté: Llibreries de Node i altres utilitats relacionades", + "The default package manager for Arch Linux and its derivatives.
Contains: Arch Linux packages": "El gestor de paquets predeterminat per a Arch Linux i els seus derivats.
Conté: paquets d'Arch Linux", + "Python's library manager. Full of python libraries and other python-related utilities
Contains: Python libraries and related utilities": "L'administrador de llibreries de Python. Ple de llibreries i d'altres utilitats relacionades.
Conté: Llibreries de Python i altres utilitats", + "PowerShell's package manager. Find libraries and scripts to expand PowerShell capabilities
Contains: Modules, Scripts, Cmdlets": "L'administrador de paquets del PowerShell. Trobeu llibreries i scripts que us permetran expandir les capacitats del PowerShell
Conté: Mòduls, scripts i Cmdlets", + "extracted": "extret", + "Scoop package": "Paquet de l'Scoop", + "Great repository of unknown but useful utilities and other interesting packages.
Contains: Utilities, Command-line programs, General Software (extras bucket required)": "Repositori ple d'utilitats menys populars però immensament útils i d'altres paquets interessants.
Conté: Utilitats, Programari de línia de comandes, Programari general (requereix el bucket extras)", + "The universal Linux package manager by Canonical.
Contains: Snap packages from the Snapcraft store": "El gestor de paquets universal de Linux de Canonical.
Conté: paquets Snap de la botiga Snapcraft", + "library": "llibreria", + "feature": "característica", + "A popular C/C++ library manager. Full of C/C++ libraries and other C/C++-related utilities
Contains: C/C++ libraries and related utilities": "Un popular administrador de llibreries de C/C++.
Conté llibreries per a C i C++, així com altres utilitats útils durant el procés de desenvolupament en C i C++", + "option": "opció", + "This package cannot be installed from an elevated context.": "Aquest paquet no es pot instal·lar des d'un context d'Administrador", + "Please run UniGetUI as a regular user and try again.": "Executeu l'UniGetUI com a usuari estàndard i proveu-ho de nou", + "Please check the installation options for this package and try again": "Comproveu les opcions d'instal·lació d'aquest paquet i proveu-ho de nou", + "Microsoft's official package manager. Full of well-known and verified packages
Contains: General Software, Microsoft Store apps": "L'administrador de paquets de Microsoft. Ple de programari conegut i verificat.
Conté: Programari general, Aplicacions de la Microsoft Store", + "Local PC": "Aquest ordinador", + "Android Subsystem": "Subsistema Android", + "Operation on queue (position {0})...": "Operació a la cua (posició {0})...", + "Click here for more details": "Cliqueu per a més detalls", + "Operation canceled by user": "Operació cancel·lada per l'usuari", + "Running PreOperation ({0}/{1})...": "S'està executant la preoperació ({0}/{1})...", + "PreOperation {0} out of {1} failed, and was tagged as necessary. Aborting...": "La preoperació {0} de {1} ha fallat i estava marcada com a necessària. S'està avortant...", + "PreOperation {0} out of {1} finished with result {2}": "La preoperació {0} de {1} ha acabat amb el resultat {2}", + "Starting operation...": "Començant operació...", + "Running PostOperation ({0}/{1})...": "S'està executant la postoperació ({0}/{1})...", + "PostOperation {0} out of {1} failed, and was tagged as necessary. Aborting...": "La postoperació {0} de {1} ha fallat i estava marcada com a necessària. S'està avortant...", + "PostOperation {0} out of {1} finished with result {2}": "La postoperació {0} de {1} ha acabat amb el resultat {2}", + "{package} installer download": "Descàrrega de l'instal·lador del {package}", + "{0} installer is being downloaded": "S'està descarregant l'instal·lador del {0}", + "Download succeeded": "Descàrrega completada amb èxit", + "{package} installer was downloaded successfully": "L'instal·lador del {package} s'ha descarregar correctament", + "Download failed": "La descàrrega ha fallat", + "{package} installer could not be downloaded": "No s'ha pogut descarregar l'instal·lador del {package}", + "{package} Installation": "Instal·lació del {package}", + "{0} is being installed": "S'està instal·lant el {0}", + "Installation succeeded": "La instal·lació s'ha completat amb èxit", + "{package} was installed successfully": "{package} s'ha instal·lat correctament", + "Installation failed": "La instal·lació ha fallat", + "{package} could not be installed": "No s'ha pogut instal·lar el {package}", + "{package} Update": "Actualització del {package}", + "Update succeeded": "L'actualització s'ha completat correctament", + "{package} was updated successfully": "{package} s'ha actualitzat correctament", + "Update failed": "L'actualització ha fallat", + "{package} could not be updated": "No s'ha pogut actuailtzar el {package}", + "{package} Uninstall": "Desinstal·lació del {package}", + "{0} is being uninstalled": "S'està desinstal·lant el {0}", + "Uninstall succeeded": "La desinstal·lació s'ha completat correctament", + "{package} was uninstalled successfully": "{package} s'ha desinstal·lat correctament", + "Uninstall failed": "La desinstal·lació ha fallat", + "{package} could not be uninstalled": "No s'ha pogut desinstal·lar el {package}", + "Adding source {source}": "Afegint font {source}", + "Adding source {source} to {manager}": "Afegint la font {source} al {manager}", + "Source added successfully": "S'ha afegit la font correctament", + "The source {source} was added to {manager} successfully": "La font {source} s'ha afegit al {manager} correctament", + "Could not add source": "No s'ha pogut afegir la font", + "Could not add source {source} to {manager}": "No s'ha pogut afegir la font {source} al {manager}", + "Removing source {source}": "Eliminant la font {source}", + "Removing source {source} from {manager}": "Eliminant la font {source} del {manager}", + "Source removed successfully": "S'ha eliminat la font correctament", + "The source {source} was removed from {manager} successfully": "La font {source} s'ha eliminat del {manager} correctament", + "Could not remove source": "No s'ha pogut eliminar la font", + "Could not remove source {source} from {manager}": "No s'ha pogut eliminar la font {source} del {manager}", + "The package manager \"{0}\" was not found": "No s'ha trobat l'administrador de paquets \"{0}\"", + "The package manager \"{0}\" is disabled": "L'administrador de paquets \"{0}\" està desactivat", + "There is an error with the configuration of the package manager \"{0}\"": "Hi ha un error a la configuració de l'administrador de paquets \"{0}\"", + "The package \"{0}\" was not found on the package manager \"{1}\"": "No s'ha trobat el paquet \"{0}\" a l'administrador de paquets \"{1}\"", + "{0} is disabled": "El {0} està desactivat", + "{0} weeks": "{0} setmanes", + "1 month": "1 mes", + "{0} months": "{0} mesos", + "Something went wrong": "Alguna cosa no ha anat bé", + "An interal error occurred. Please view the log for further details.": "Hi ha hagut un error intern. Veieu el registre per a més detalls", + "No applicable installer was found for the package {0}": "No s'ha trobat cap instal·lador aplicable per al paquet {0}", + "Integrity checks will not be performed during this operation": "No es farà cap comprovació d'integritat durant aquesta operació", + "This is not recommended.": "Això no es recomana.", + "Run now": "Executa ara", + "Run next": "Executa a continuació", + "Run last": "Executa la darrera", + "Show in explorer": "Mostra a l'explorador", + "Checked": "Marcat", + "Unchecked": "Desmarcat", + "This package is already installed": "Aquest paquet ja està instal·lat", + "This package can be upgraded to version {0}": "Aquest paquet es pot actualitzar a la versió {0}", + "Updates for this package are ignored": "S'ignoren les actualitzacions d'aquest paquet", + "This package is being processed": "S'està processant aquest paquet", + "This package is not available": "Aquest paquet no està disponible", + "Select the source you want to add:": "Seleccioneu la font a afegir:", + "Source name:": "Nom de la font:", + "Source URL:": "Enllaç de la font:", + "An error occurred when adding the source: ": "Hi ha hagut un error quan s'afegia la font: ", + "Package management made easy": "L'administració de paquets, feta fàcil", + "version {0}": "versió {0}", + "[RAN AS ADMINISTRATOR]": "EXECUTAT COM A ADMINISTRADOR", + "Portable mode": "Mode portàtil", + "DEBUG BUILD": "COMPILACIÓ DE DEPURACIÓ", + "Here you can change UniGetUI's behaviour regarding the following shortcuts. Checking a shortcut will make UniGetUI delete it if if gets created on a future upgrade. Unchecking it will keep the shortcut intact": "Aquí podeu canviar el funcionament de l'UniGetUI pel que fa a les següents dreceres. Seleccionar una drecera farà que l'UniGetUI l'elimini si mai es crea durant una actualització. Desseleccionar-la farà que la drecera no s'elimini", + "Manual scan": "Escaneig manual", + "Existing shortcuts on your desktop will be scanned, and you will need to pick which ones to keep and which ones to remove.": "Les dreceres existents al vostre escriptori s'escanejaran, i podreu escollir quines s'han de mantenir i quines s'han d'eliminar", + "Delete?": "Eliminar?", + "I understand": "Ho entenc", + "Chocolatey setup changed": "La configuració de Chocolatey ha canviat", + "UniGetUI no longer includes its own private Chocolatey installation. A legacy UniGetUI-managed Chocolatey installation was detected for this user profile, but system Chocolatey was not found. Chocolatey will stay unavailable in UniGetUI until Chocolatey is installed on the system and UniGetUI is restarted. Applications previously installed through UniGetUI's bundled Chocolatey may still appear under other sources such as Local PC or WinGet.": "UniGetUI ja no inclou la seva pròpia instal·lació privada de Chocolatey. S'ha detectat una instal·lació heredada de Chocolatey gestionada per UniGetUI per a aquest perfil d'usuari, però no s'ha trobat Chocolatey al sistema. Chocolatey romandrà no disponible a UniGetUI fins que Chocolatey s'instal·li al sistema i es reiniciï UniGetUI. Les aplicacions instal·lades anteriorment mitjançant el Chocolatey inclòs a UniGetUI encara poden aparèixer sota altres fonts com PC local o WinGet.", + "NOTE: This troubleshooter can be disabled from UniGetUI Settings, on the WinGet section": "NOTA: Aquest solucionador de problemes es pot desactivar des de la configuració de l'UniGetUI, a la secció del WinGet", + "Restart": "Reinicia", + "Are you sure you want to delete all shortcuts?": "Realment voleu eliminar totes les dreceres?", + "Any new shorcuts created during an install or an update operation will be deleted automatically, instead of showing a confirmation prompt the first time they are detected.": "Qualsevol icona creada durant una instal·lació o una actualització s'eliminarà automàticament, en comptes de mostrar un diàleg de confirmació el primer cop que es detecti.", + "Any shorcuts created or modified outside of UniGetUI will be ignored. You will be able to add them via the {0} button.": "Qualsevol icona creada o modificada fora de l'UniGetUI s'ignorarà. Les podreu afegir mitjançant el botó d' {0}", + "Are you really sure you want to enable this feature?": "Realment voleu activar aquesta característica?", + "No new shortcuts were found during the scan.": "No s'han trobat noves dreceres durant l'escaneig.", + "How to add packages to a bundle": "Com afegir paquets a la col·lecció", + "In order to add packages to a bundle, you will need to: ": "Per a afegir paquets a la col·lecció, haureu de: ", + "1. Navigate to the \"{0}\" or \"{1}\" page.": "1. Navegueu a la pàgina de \"{0}\" o \"{1}\"", + "2. Locate the package(s) you want to add to the bundle, and select their leftmost checkbox.": "2. Escolliu el(s) paquet(s) que volgueu afegir a la col·lecció, i seleccioneu-ne la casella de l'esquerra.", + "3. When the packages you want to add to the bundle are selected, find and click the option \"{0}\" on the toolbar.": "3. Quan els paqueta que volgueu afegir estiguin seleccionats, cliqueu l'opció \"{0}\" a la barra d'eines.", + "4. Your packages will have been added to the bundle. You can continue adding packages, or export the bundle.": "4. Els paquets ja s'hauràn afegit a la col·lecció. Podeu exportar la col·lecció o afegir més paquets", + "Which backup do you want to open?": "Quina còpia de seguretat voleu obrir?", + "Select the backup you want to open. Later, you will be able to review which packages you want to install.": "Seleccioneu la còpia que voleu obrir. Més endavant podreu revisar quins paquets/programes voleu restaurar.", + "There are ongoing operations. Quitting UniGetUI may cause them to fail. Do you want to continue?": "Hi ha operacions en execució. Tancar l'UniGetUI pot provocar que fallin o es cancel·lin. Voleu continuar?", + "UniGetUI or some of its components are missing or corrupt.": "L'UniGetUI o algun dels seus components falta o s'ha corromput.", + "It is strongly recommended to reinstall UniGetUI to adress the situation.": "Es recomana fortament que reinstal·leu l'UniGetUI per a arreglar la situació.", + "Refer to the UniGetUI Logs to get more details regarding the affected file(s)": "Veieu el registre de l'UniGetUI per a obtenir més detalls sobre el(s) fitxer(s) afectat(s)", + "Integrity checks can be disabled from the Experimental Settings": "Les comprovacions d'identitat es poden desactivar des de la configuració experimental", + "Repair UniGetUI": "Repara l'UniGetUI", + "Live output": "Sortida en viu", + "This package bundle had some settings that are potentially dangerous, and may be ignored by default.": "Aquesta col·lecció de paquets té algunes configuracions que són potencialment perilloses, i és possible que aquestes siguin ignorades.", + "Entries that show in YELLOW will be IGNORED.": "Les entrades mostrades en GROC seran IGNORADES", + "Entries that show in RED will be IMPORTED.": "Les entrades que es mostren en VERMELL seran IMPORTADES", + "You can change this behavior on UniGetUI security settings.": "Podeu canviar aquest comportament a la configuració de seguretat de l'UniGetUI.", + "Open UniGetUI security settings": "Obre la configuració de seguretat de l'UniGetUI", + "Should you modify the security settings, you will need to open the bundle again for the changes to take effect.": "Si modifiqueu alguna de les opcions de seguretat haureu de tornar a obrir la col·lecció per a que els canvis facin efecte.", + "Details of the report:": "Detalls de l'informe:", + "Are you sure you want to create a new package bundle? ": "Realment voleu crear una col·lecció nova?", + "Any unsaved changes will be lost": "Es perdrà qualsevol canvi no desat", + "Warning!": "Atenció!", + "For security reasons, custom command-line arguments are disabled by default. Go to UniGetUI security settings to change this. ": "Per raons de seguretat, els arguments de línia de comandes personalitzats estan desactivats. Aneu a la configuració de seguretat de l'UniGetUI per a canviar això.", + "Change default options": "Canvia les opcions per defecte", + "Ignore future updates for this package": "Ignora les actualitzacions futures d'aquest paquet", + "For security reasons, pre-operation and post-operation scripts are disabled by default. Go to UniGetUI security settings to change this. ": "Per raons de seguretat, els scripts de pre-operació i post-operació estan desactivats per defecte. Aneu a la configuració de seguretat de l'UniGetUI per a canviar això.", + "You can define the commands that will be run before or after this package is installed, updated or uninstalled. They will be run on a command prompt, so CMD scripts will work here.": "Podeu definir les comandes que s'executaran abans i/o després de que s'instal·li, s'actualitzi o es desinstal·li aquest paquet. Les comandes s'executaran en un Command Prompt, pel que els scripts de CMD funcionaran aquí.", + "Change this and unlock": "Canvia i desbloqueja", + "{0} Install options are currently locked because {0} follows the default install options.": "Les opcions d'instal·lació del {0} estan bloquejades perquè el {0} segueix les opcions d'instal·lació per defecte.", + "Unset or unknown": "No especificada o desconeguda", + "This package has no screenshots or is missing the icon? Contrbute to UniGetUI by adding the missing icons and screenshots to our open, public database.": "Aquest paquet no té icona o li falten imatges? Contribuïu a l'UniGetUI afegint la icona i imatges que faltin a la base de dades pública i oberta de l'UniGetUI.", + "Become a contributor": "Fer-se contribuïdor", + "Update to {0} available": "Actualització a {0} disponible", + "Reinstall": "Reinstal·la", + "Installer not available": "Instal·lador no disponible", + "Version:": "Versió:", + "UniGetUI Version {0}": "UniGetUI Versió {0}", + "Performing backup, please wait...": "Desant la còpia de seguretat, si us plau espereu...", + "An error occurred while logging in: ": "Hi ha hagut un error en iniciar sessió:", + "Fetching available backups...": "Carregant les còpies disponibles...", + "Done!": "Fet!", + "The cloud backup has been loaded successfully.": "La còpia de seguretat s'ha carregat correctament", + "An error occurred while loading a backup: ": "Hi ha hagut un error en carregar la còpia de seguretat:", + "Backing up packages to GitHub Gist...": "Fent una còpia de seguretat dels paquets a GitHub Gist...", + "Backup Successful": "S'ha completat la còpia", + "The cloud backup completed successfully.": "La còpia de seguretat s'ha completat correctament.", + "Could not back up packages to GitHub Gist: ": "No s'ha pogut completar la còpia al GitHub Gist", + "It is not guaranteed that the provided credentials will be stored safely, so you may as well not use the credentials of your bank account": "No podem garantir que les credencials donades es desin de forma segura, així que millor que no poseu aquí la contrasenya del vostre banc", + "Enable the automatic WinGet troubleshooter": "Activa el solucionador de problemes automàtic del WinGet", + "Add updates that fail with a 'no applicable update found' to the ignored updates list": "Afegiu qualsevol actualització que falli amb l'error 'No aplica' a la llista d'acttualitzacions ignorades", + "Invalid selection": "Selecció invàlida", + "No package was selected": "No s'ha seleccionat cap paquet", + "More than 1 package was selected": "S'ha seleccionat més d'un paquet", + "List": "Llista", + "Grid": "Graella", + "Icons": "Icones", + "\"{0}\" is a local package and does not have available details": "\"{0}\" és un paquet local i no té detalls disponibles", + "\"{0}\" is a local package and is not compatible with this feature": "\"{0}\" és un paquet local i no és compatible amb aquesta característica", + "Add packages to bundle": "Afegiu paquets a la col·lecció", + "Preparing packages, please wait...": "Preparant els paquets, si us plau espereu...", + "Loading packages, please wait...": "Carregant els paquets...", + "Saving packages, please wait...": "Desant els paquets, espereu si us plau...", + "The bundle was created successfully on {0}": "La col·lecció s'ha desat correctament a {0}", + "User profile": "Perfil d'usuari", + "Error": "Error", + "Log in failed: ": "Ha fallat l'inici de sessió:", + "Log out failed: ": "Ha fallat el tancament de sessió:", + "Package backup settings": "Configuració de la còpia de seguretat", + "Manage UniGetUI autostart behaviour from the Settings app": "Gestiona el comportament d'inici automàtic de l'UniGetUI", + "Choose how many operations shoulds be performed in parallel": "Trieu quantes operacions s'han de fer en paral·lel", + "Something went wrong while launching the updater.": "Quelcom ha anat malament en executar l'actualitzador.", + "Please try again later": "Proveu-ho més tard", + "Show the release notes after UniGetUI is updated": "Mostra les notes de publicació després d'actualitzar UniGetUI" +} diff --git a/src/Languages/lang_cs.json b/src/Languages/lang_cs.json new file mode 100644 index 0000000..ba0a883 --- /dev/null +++ b/src/Languages/lang_cs.json @@ -0,0 +1,850 @@ +{ + "{0} of {1} operations completed": "Dokončeno {0} z {1} operací", + "{0} is now {1}": "{0} je nyní {1}", + "Enabled": "Povoleno", + "Disabled": "Vypnuto", + "Privacy": "Soukromí", + "Hide my username from the logs": "Skrýt mé uživatelské jméno z protokolů", + "Replaces your username with **** in the logs. Restart UniGetUI to also hide it from already-recorded entries.": "Nahradí vaše uživatelské jméno znaky **** v protokolech. Restartujte UniGetUI, abyste ho skryli i z již zaznamenaných záznamů.", + "Your last update attempt did not complete.": "Váš poslední pokus o aktualizaci nebyl dokončen.", + "UniGetUI could not confirm whether the update succeeded. Open the log to see what happened.": "UniGetUI nemohl ověřit, zda aktualizace proběhla úspěšně. Otevřete protokol a zjistěte, co se stalo.", + "View log": "Zobrazit protokol", + "The installer reported success but did not restart UniGetUI.": "Instalační program ohlásil úspěch, ale nerestartoval UniGetUI.", + "The installer failed to initialize.": "Instalační program se nepodařilo inicializovat.", + "Setup was canceled before installation began.": "Instalace byla zrušena před zahájením instalace.", + "A fatal error occurred during the preparation phase.": "Během přípravné fáze došlo k závažné chybě.", + "A fatal error occurred during installation.": "Během instalace došlo k závažné chybě.", + "Installation was canceled while in progress.": "Instalace byla zrušena v průběhu.", + "The installer was terminated by another process.": "Instalační program byl ukončen jiným procesem.", + "The preparation phase determined the installation cannot proceed.": "Přípravná fáze zjistila, že instalace nemůže pokračovat.", + "The installer could not start. UniGetUI may already be running, or you do not have permission to install.": "Instalační program se nepodařilo spustit. UniGetUI již možná běží, nebo nemáte oprávnění k instalaci.", + "Unexpected installer error.": "Neočekávaná chyba instalačního programu.", + "We are checking for updates.": "Kontrolujeme aktualizace.", + "Please wait": "Prosím vyčkejte", + "Great! You are on the latest version.": "Skvělé! Máte nejnovější verzi.", + "There are no new UniGetUI versions to be installed": "Neexistují žádné nové verze UniGetUI, které by bylo třeba nainstalovat", + "UniGetUI version {0} is being downloaded.": "Stahuje se verze UniGetUI {0}", + "This may take a minute or two": "Může to trvat minutu nebo dvě.", + "The installer authenticity could not be verified.": "Pravost instalačního programu nebylo možné ověřit.", + "The update process has been aborted.": "Aktualizační proces byl přerušen.", + "Auto-update is not yet available on this platform.": "Automatická aktualizace zatím není na této platformě dostupná.", + "Please update UniGetUI manually.": "Aktualizujte prosím UniGetUI ručně.", + "An error occurred when checking for updates: ": "Nastala chyba při kontrole aktualizací:", + "The updater could not be launched.": "Aktualizační program se nepodařilo spustit.", + "The operating system did not start the installer process.": "Operační systém nespustil proces instalačního programu.", + "UniGetUI is being updated...": "UniGetUI je aktualizován...", + "Update installed.": "Aktualizace nainstalována.", + "UniGetUI was updated successfully, but this running copy was not replaced. This usually means you are running a development build. Close this copy and start the newly-installed version to finish.": "UniGetUI byl úspěšně aktualizován, ale tato spuštěná kopie nebyla nahrazena. To obvykle znamená, že používáte vývojové sestavení. Zavřete tuto kopii a spusťte nově nainstalovanou verzi, abyste dokončili aktualizaci.", + "The update could not be applied.": "Aktualizaci se nepodařilo použít.", + "Installer exit code {0}: {1}": "Ukončovací kód instalačního programu {0}: {1}", + "Update cancelled.": "Aktualizace zrušena.", + "Authentication was cancelled.": "Ověření bylo zrušeno.", + "Installer exit code {0}": "Ukončovací kód instalačního programu {0}", + "Operation in progress": "Probíhají operace", + "Please wait...": "Prosím vyčkejte...", + "Success!": "Úspěch!", + "Failed": "Selhání", + "An error occurred while processing this package": "Při zpracování tohoto balíčku došlo k chybě", + "Installer": "Instalátor", + "Executable": "Spustitelný soubor", + "MSI": "MSI", + "Compressed file": "Komprimovaný soubor", + "MSIX": "MSIX", + "WinGet was repaired successfully": "WinGet byl úspěšně opraven", + "It is recommended to restart UniGetUI after WinGet has been repaired": "Po opravě WinGet se doporučuje restartovat aplikaci UniGetUI", + "WinGet could not be repaired": "WinGet se nepodařilo opravit", + "An unexpected issue occurred while attempting to repair WinGet. Please try again later": "Při pokusu o opravu WinGet došlo k neočekávanému problému. Zkuste to prosím později", + "Log in to enable cloud backup": "Přihlašte se pro zapnutí zálohování do cloudu", + "Backup Failed": "Zálohování selhalo", + "Downloading backup...": "Stahování zálohy...", + "An update was found!": "Byla nalezena aktualizace!", + "{0} can be updated to version {1}": "{0} může být aktualizován na verzi {1}", + "Updates found!": "Nalezeny aktualizace!", + "{0} packages can be updated": "{0} balíčků může být aktualizováno", + "{0} is being updated to version {1}": "{0} se aktualizuje na verzi {1}", + "{0} packages are being updated": "{0} balíčků jsou aktualizovány", + "You have currently version {0} installed": "Aktuálně máte nainstalovanou verzi {0}", + "Desktop shortcut created": "Vytvoření zástupce na ploše", + "UniGetUI has detected a new desktop shortcut that can be deleted automatically.": "UniGetUI zjistil nového zástupce na ploše, který může být automaticky odstraněn.", + "{0} desktop shortcuts created": "{0} vytvořených zástupců na ploše", + "UniGetUI has detected {0} new desktop shortcuts that can be deleted automatically.": "UniGetUI zjistil {0} nových zástupců na ploše, které lze automaticky odstranit.", + "Attention required": "Nutná pozornost", + "Restart required": "Vyžadován restart", + "1 update is available": "1 dostupná aktualizace", + "{0} updates are available": "Je dostupných {0} aktualizací.", + "Everything is up to date": "Vše je aktuální", + "Discover Packages": "Procházet balíčky", + "Available Updates": "Dostupné aktualizace", + "Installed Packages": "Místní balíčky", + "UniGetUI Version {0} by Devolutions": "UniGetUI verze {0} od společnosti Devolutions", + "Show UniGetUI": "Zobrazit UniGetUI", + "Quit": "Ukončit", + "Are you sure?": "Jste si jistí?", + "Do you really want to uninstall {0}?": "Opravdu chcete odinstalovat {0}?", + "Do you really want to uninstall the following {0} packages?": "Opravdu chceš odinstalovat následujících {0} balíčků?", + "No": "Ne", + "Yes": "Ano", + "Partial": "Částečně", + "View on UniGetUI": "Zobrazit v UniGetUI", + "Update": "Aktualizovat", + "Open UniGetUI": "Otevřít UniGetUI", + "Update all": "Aktualizovat vše", + "Update now": "Aktualizovat nyní", + "Installer host changed since the installed version.\n": "Hostitel instalačního programu se od nainstalované verze změnil.\n", + "This package is on the queue": "Tento balíček je ve frontě", + "installing": "instaluji", + "updating": "aktualizuji", + "uninstalling": "odinstaluji", + "installed": "nainstalováno", + "Retry": "Zkusit znovu", + "Install": "Nainstalovat", + "Uninstall": "Odinstalovat", + "Open": "Otevřít", + "Operation profile:": "Profil operace:", + "Follow the default options when installing, upgrading or uninstalling this package": "Při instalaci, aktualizaci nebo odinstalaci tohoto balíčku postupujte podle výchozích možností.", + "The following settings will be applied each time this package is installed, updated or removed.": "Následující nastavení se použijí při každé instalaci, aktualizaci nebo odebrání tohoto balíčku.", + "Version to install:": "Verze:", + "Architecture to install:": "Architektura:", + "Installation scope:": "Rozsah instalace:", + "Install location:": "Umístění instalace:", + "Select": "Vybrat", + "Reset": "Obnovit", + "Custom install arguments:": "Vlastní argumenty pro instalaci:", + "Custom update arguments:": "Vlastní argumenty pro aktualizaci:", + "Custom uninstall arguments:": "Vlastní argumenty pro odinstalaci:", + "Pre-install command:": "Příkaz před instalací:", + "Post-install command:": "Příkaz po instalaci:", + "Abort install if pre-install command fails": "Přerušit instalaci, pokud předinstalační příkaz selže", + "Pre-update command:": "Příkaz před aktualizací:", + "Post-update command:": "Příkaz po aktualizaci:", + "Abort update if pre-update command fails": "Přerušit aktualizaci, pokud předinstalační příkaz selže", + "Pre-uninstall command:": "Příkaz před odinstalací:", + "Post-uninstall command:": "Příkaz po odinstalaci:", + "Abort uninstall if pre-uninstall command fails": "Přerušit odinstalaci, pokud předinstalační příkaz selže", + "Command-line to run:": "Příkazový řádek pro spuštění:", + "Save and close": "Uložit a zavřít", + "General": "Obecné", + "Architecture & Location": "Architektura a umístění", + "Command-line": "Příkazový řádek", + "Close apps": "Zavřít aplikace", + "Pre/Post install": "Před/po instalaci", + "Select the processes that should be closed before this package is installed, updated or uninstalled.": "Vyberte procesy, které by měly být ukončeny před instalací, aktualizací nebo odinstalací tohoto balíčku.", + "Write here the process names here, separated by commas (,)": "Zde napište názvy procesů oddělené čárkami (,).", + "Try to kill the processes that refuse to close when requested to": "Pokuste se ukončit procesy, které se odmítají zavřít, když je to požadováno.", + "Run as admin": "Spustit jako správce", + "Interactive installation": "Interaktivní instalace", + "Skip hash check": "Přeskočit kontrolní součet", + "Uninstall previous versions when updated": "Odinstalování předchozích verzí po aktualizaci", + "Skip minor updates for this package": "Přeskočení drobných aktualizací tohoto balíčku", + "Automatically update this package": "Automaticky aktualizovat tento balíček", + "{0} installation options": "{0} možnosti instalace", + "Latest": "Poslední", + "PreRelease": "Předběžná verze", + "Default": "Výchozí", + "Manage ignored updates": "Spravovat ignorované aktualizace", + "The packages listed here won't be taken in account when checking for updates. Double-click them or click the button on their right to stop ignoring their updates.": "Uvedené balíčky nebudou při kontrole aktualizací brány v úvahu. Poklepejte na ně nebo klikněte na tlačítko vpravo, abyste přestali ignorovat jejich aktualizace.", + "Reset list": "Obnovit seznam", + "Do you really want to reset the ignored updates list? This action cannot be reverted": "Opravdu chcete obnovit seznam ignorovaných aktualizací? Tuto akci nelze vrátit zpět", + "No ignored updates": "Žádné ignorované aktualizace", + "Package Name": "Název balíčku", + "Package ID": "ID balíčku", + "Ignored version": "Ignorovaná verze", + "New version": "Nová verze", + "Source": "Zdroj", + "All versions": "Všechny verze", + "Unknown": "Neznámé", + "Up to date": "Aktuální", + "Package {name} from {manager}": "Balíček {name} z {manager}", + "Remove {0} from ignored updates": "Odebrat {0} z ignorovaných aktualizací", + "Cancel": "Zrušit", + "Administrator privileges": "Oprávnění správce", + "This operation is running with administrator privileges.": "Tato operace je spuštěna s oprávněním správce.", + "Interactive operation": "Interaktivní operace", + "This operation is running interactively.": "Tento operace je spuštěna interaktivně.", + "You will likely need to interact with the installer.": "Pravděpodobně budete muset s instalátorem interagovat.", + "Integrity checks skipped": "Kontrola integrity přeskočena", + "Integrity checks will not be performed during this operation.": "Během této operace nebudou provedeny kontroly integrity.", + "Proceed at your own risk.": "Pokračujte na vlastní nebezpečí.", + "Close": "Zavřít", + "Loading...": "Načítání...", + "Installer SHA256": "SHA256", + "Homepage": "Domovská stránka", + "Author": "Autor", + "Publisher": "Vydavatel", + "License": "Licence", + "Manifest": "Manifest balíčku", + "Installer Type": "Typ instalátoru", + "Size": "Velikost", + "Installer URL": "URL", + "Last updated:": "Poslední aktualizace:", + "Release notes URL": "URL Poznámek k vydání", + "Package details": "Podrobnosti", + "Dependencies:": "Závislosti:", + "Release notes": "Poznámky k vydání", + "Screenshots": "Snímky obrazovky", + "This package has no screenshots or is missing the icon? Contribute to UniGetUI by adding the missing icons and screenshots to our open, public database.": "Tento balíček nemá žádné snímky obrazovky nebo mu chybí ikona? Přispějte do UniGetUI přidáním chybějících ikon a snímků obrazovky do naší otevřené veřejné databáze.", + "Version": "Verze", + "Install as administrator": "Instalovat jako správce", + "Update to version {0}": "Aktualizovat na verzi {0}", + "Installed Version": "Nainstalovaná verze", + "Update as administrator": "Aktualizovat jako správce", + "Interactive update": "Interaktivní aktualizace", + "Uninstall as administrator": "Odinstalovat jako správce", + "Interactive uninstall": "Interaktivní odinstalace", + "Uninstall and remove data": "Odinstalovat a odstranit data", + "Not available": "Nedostupné", + "Installer SHA512": "SHA512", + "Unknown size": "Neznámá velikost", + "No dependencies specified": "Nejsou uvedeny žádné závislosti", + "mandatory": "povinné", + "optional": "volitelné", + "UniGetUI {0} is ready to be installed.": "UniGetUI {0} je připraven k instalaci.", + "The update process will start after closing UniGetUI": "Aktualizace začne po zavření UniGetUI", + "UniGetUI has been ran as administrator, which is not recommended. When running UniGetUI as administrator, EVERY operation launched from UniGetUI will have administrator privileges. You can still use the program, but we highly recommend not running UniGetUI with administrator privileges.": "UniGetUI byl spuštěn jako správce, což se nedoporučuje. Když spouštíte UniGetUI jako správce, KAŽDÁ operace spuštěná z UniGetUI bude mít oprávnění správce. Program můžete stále používat, ale důrazně doporučujeme nespouštět UniGetUI s oprávněními správce.", + "Share anonymous usage data": "Sdílení anonymních dat o používání", + "UniGetUI collects anonymous usage data in order to improve the user experience.": "UniGetUI shromažďuje anonymní údaje o používání za účelem zlepšení uživatelského komfortu.", + "Accept": "Přijmout", + "Software Updates": "Aktualizace softwaru", + "Package Bundles": "Sady balíčků", + "Settings": "Nastavení", + "Package Managers": "Správci balíčků", + "UniGetUI Log": "UniGetUI protokol", + "Package Manager logs": "Protokoly správce balíčků", + "Operation history": "Historie operací", + "Help": "Nápověda", + "UniGetUI": "UniGetUI", + "You have installed UniGetUI Version {0}": "Je nainstalován UniGetUI verze {0}", + "Disclaimer": "Upozornění", + "UniGetUI is developed by Devolutions and is not affiliated with any of the compatible package managers.": "UniGetUI je vyvíjeno společností Devolutions a není přidruženo k žádnému z kompatibilních správců balíčků.", + "UniGetUI wouldn't have been possible without the help of the contributors. Thank you all 🥳": "UniGetUI by nebylo možné vytvořit bez pomoci přispěvatelů. Děkuji Vám všem 🥳", + "UniGetUI uses the following libraries. Without them, UniGetUI wouldn't have been possible.": "UniGetUI používá následující knihovny. Bez nich by UniGetUI nebyl možný.", + "{0} homepage": "{0} domovská stránka", + "UniGetUI has been translated to more than 40 languages thanks to the volunteer translators. Thank you 🤝": "UniGetUI byl díky dobrovolným překladatelům přeložen do více než 40 jazyků. Děkujeme 🤝", + "Verbose": "Podrobný výstup", + "1 - Errors": "1 - Chyby", + "2 - Warnings": "2 - Varování", + "3 - Information (less)": "3 - Informace (méně)", + "4 - Information (more)": "4 - Informace (více)", + "5 - information (debug)": "5 - Informace (ladění)", + "Warning": "Upozornění", + "The following settings may pose a security risk, hence they are disabled by default.": "Následující nastavení mohou představovat bezpečnostní riziko, proto jsou ve výchozím nastavení zakázána.", + "Enable the settings below if and only if you fully understand what they do, and the implications they may have.": "Níže uvedená nastavení povolte, POKUD A POUZE POKUD plně chápete, k čemu slouží a jaké mohou mít důsledky a nebezpečí.", + "The settings will list, in their descriptions, the potential security issues they may have.": "V popisu nastavení budou uvedeny potenciální bezpečnostní problémy, které mohou mít.", + "The backup will include the complete list of the installed packages and their installation options. Ignored updates and skipped versions will also be saved.": "Záloha bude obsahovat kompletní seznam nainstalovaných balíčků a možnosti jejich instalace. Uloženy budou také ignorované aktualizace a přeskočené verze.", + "The backup will NOT include any binary file nor any program's saved data.": "Záloha NEBUDE obsahovat binární soubory ani uložená data programů.", + "The size of the backup is estimated to be less than 1MB.": "Velikost zálohy se odhaduje na méně než 1 MB.", + "The backup will be performed after login.": "Zálohování se provede po přihlášení.", + "{pcName} installed packages": "{pcName} nainstalované balíčky", + "Current status: Not logged in": "Současný stav: Nepřihlášen", + "You are logged in as {0} (@{1})": "jste přihlášen jako {0} (@{1})", + "Nice! Backups will be uploaded to a private gist on your account": "Hezky! Zálohy budou nahrány do soukromého gistu na vašem účtu.", + "Select backup": "Výběr zálohy", + "Settings imported from {0}": "Nastavení importováno z {0}", + "UniGetUI Settings": "Nastavení UniGetUI", + "Settings exported to {0}": "Nastavení exportováno do {0}", + "UniGetUI settings were reset": "Nastavení UniGetUI bylo obnoveno", + "Allow pre-release versions": "Povolit předběžné verze", + "Apply": "Použít", + "For security reasons, custom command-line arguments are disabled by default. Go to UniGetUI security settings to change this.": "Z bezpečnostních důvodů jsou vlastní argumenty příkazového řádku ve výchozím nastavení zakázány. Chcete-li to změnit, přejděte do nastavení zabezpečení UniGetUI.", + "Go to UniGetUI security settings": "Přejděte do nastavení zabezpečení UniGetUI", + "The following options will be applied by default each time a {0} package is installed, upgraded or uninstalled.": "Při každé instalaci, aktualizaci nebo odinstalaci balíčku {0} se ve výchozím nastavení použijí následující možnosti.", + "Package's default": "Výchozí nastavení balíčku", + "Install location can't be changed for {0} packages": "Umístění instalace nelze změnit pro {0} balíčků", + "The local icon cache currently takes {0} MB": "Mezipaměť ikonek aktuálně zabírá {0} MB", + "Username": "Uživatelské jméno", + "Password": "Heslo", + "Credentials": "Přihlašovací údaje", + "It is not guaranteed that the provided credentials will be stored safely": "Není zaručeno, že poskytnuté přihlašovací údaje budou uloženy bezpečně", + "Partially": "Částečně", + "Package manager": "Správce balíčků", + "Compatible with proxy": "Kompatibilní s proxy", + "Compatible with authentication": "Kompatibilní s ověřením", + "Proxy compatibility table": "Tabulka kompatibility proxy serverů", + "{0} settings": "{0} nastavení", + "{0} status": "{0} stav", + "Default installation options for {0} packages": "Výchozí možnosti instalace {0} balíčků", + "Expand version": "Rozbalit verze", + "The executable file for {0} was not found": "Spustitelný soubor pro {0} nebyl nalezen", + "{pm} is disabled": "{pm} je vypnuto", + "Enable it to install packages from {pm}.": "Povolte jej pro instalaci balíčků z {pm}.", + "{pm} is enabled and ready to go": "{pm} je povolen a připraven k použití", + "{pm} version:": "{pm} verze:", + "{pm} was not found!": "{pm} nebyl nalezen!", + "You may need to install {pm} in order to use it with UniGetUI.": "Může být nutné nainstalovat {pm} pro použití s UniGetUI.", + "Scoop Installer - UniGetUI": "Scoop instalátor - UniGetUI", + "Scoop Uninstaller - UniGetUI": "Scoop odinstalátor - UniGetUI", + "Clearing Scoop cache - UniGetUI": "Mazání mezipaměti Scoop - UniGetUI", + "Restart UniGetUI to fully apply changes": "Restartujte UniGetUI, aby se změny plně projevily", + "Restart UniGetUI": "Restartovat UniGetUI", + "Manage {0} sources": "Správa zdrojů {0}", + "Add source": "Přidat zdroj", + "Add": "Přidat", + "Source name": "Název zdroje", + "Source URL": "URL zdroje", + "Other": "Ostatní", + "No minimum age": "Bez minimálního stáří", + "1 day": "den", + "{0} days": "{0} dnů", + "Custom...": "Vlastní...", + "{0} minutes": "{0} minut", + "1 hour": "hodina", + "{0} hours": "{0} hodin", + "1 week": "1 týden", + "Supports release dates": "Podporuje data vydání", + "Release date support per package manager": "Podpora dat vydání podle správce balíčků", + "Search for packages": "Vyhledávání balíčků", + "Local": "Místní", + "OK": "OK", + "Last checked: {0}": "Naposledy zkontrolováno: {0}", + "{0} packages were found, {1} of which match the specified filters.": "Bylo nalezeno {0} balíčků, z nichž {1} vyhovuje zadaným filtrům.\n", + "{0} selected": "{0} vybráno", + "(Last checked: {0})": "(Naposledy zkontrolováno: {0})", + "All packages selected": "Všechny balíčky vybrány", + "Package selection cleared": "Výběr balíčků vymazán", + "{0}: {1}": "{0}: {1}", + "More info": "Více informací", + "GitHub account": "Účet GitHub", + "Log in with GitHub to enable cloud package backup.": "Přihlašte se pomocí GitHub pro zapnutí zálohování balíčků do cloudu.", + "More details": "Více informací", + "Log in": "Přihlásit se", + "If you have cloud backup enabled, it will be saved as a GitHub Gist on this account": "Pokud máte povoleno zálohování do cloudu, bude na tomto účtu uložen jako GitHub Gist.", + "Log out": "Odhlásit se", + "About UniGetUI": "O aplikaci UniGetUI", + "About": "O aplikaci", + "Third-party licenses": "Licence třetích stran", + "Contributors": "Přispěvatelé", + "Translators": "Překladatelé", + "Bundle security report": "Zpráva o zabezpečení sady", + "The bundle contained restricted content": "Sada obsahovala omezený obsah", + "UniGetUI – Crash Report": "UniGetUI – Hlášení o pádu", + "UniGetUI has crashed": "UniGetUI spadlo", + "Help us fix this by sending a crash report to Devolutions. All fields below are optional.": "Pomozte nám to opravit odesláním hlášení o pádu do Devolutions. Všechna pole níže jsou volitelná.", + "Email (optional)": "E-mail (volitelné)", + "your@email.com": "vas@email.cz", + "Additional details (optional)": "Další podrobnosti (volitelné)", + "Describe what you were doing when the crash occurred…": "Popište, co jste dělali, když k pádu došlo…", + "Crash report": "Hlášení o pádu", + "Don't Send": "Neodesílat", + "Send Report": "Odeslat hlášení", + "Sending…": "Odesílání…", + "Unsaved changes": "Neuložené změny", + "You have unsaved changes in the current bundle. Do you want to discard them?": "V aktuální sadě máte neuložené změny. Chcete je zahodit?", + "Discard changes": "Zahodit změny", + "Integrity violation": "Porušení integrity", + "UniGetUI or some of its components are missing or corrupt. It is strongly recommended to reinstall UniGetUI to adress the situation.": "UniGetUI nebo některé jeho součásti chybí či jsou poškozené. Důrazně doporučujeme přeinstalovat UniGetUI, aby se situace vyřešila.", + "• Refer to the UniGetUI Logs to get more details regarding the affected file(s)": "• Podívejte se do protokolů UniGetUI pro získání více podrobností o postižených souborech", + "• Integrity checks can be disabled from the Experimental Settings": "• Kontrolu integrity lze zakázat v Experimentálním nastavení", + "Manage shortcuts": "Spravovat zástupce", + "UniGetUI has detected the following desktop shortcuts which can be removed automatically on future upgrades": "UniGetUI zjistil následující zástupce na ploše, které lze při budoucích aktualizacích automaticky odstranit", + "Do you really want to reset this list? This action cannot be reverted.": "Opravdu chcete tento seznam obnovit? Tuto akci nelze vrátit zpět.", + "Desktop shortcuts list": "Seznam zástupců na ploše", + "Open in explorer": "Otevřít v Průzkumníku", + "Remove from list": "Odstranit ze seznamu", + "When new shortcuts are detected, delete them automatically instead of showing this dialog.": "Když jsou detekovány nové zkratky, automaticky je smazat, místo aby se zobrazovalo toto dialogové okno.", + "Not right now": "Teď ne", + "Missing dependency": "Chybějící závislost", + "UniGetUI requires {0} to operate, but it was not found on your system.": "UniGetUI vyžaduje ke své činnosti {0}, ale ve vašem systému nebyl nalezen.", + "Click on Install to begin the installation process. If you skip the installation, UniGetUI may not work as expected.": "Klepnutím na tlačítko Instalace zahájíte proces instalace. Pokud instalaci přeskočíte, nemusí UniGetUI fungovat dle očekávání.", + "Alternatively, you can also install {0} by running the following command in a Windows PowerShell prompt:": "Alternativně můžete také nainstalovat {0} spuštěním následujícího příkazu v příkazovém řádku prostředí Windows PowerShell:", + "Install {0}": "Nainstalovat {0}", + "Do not show this dialog again for {0}": "Nezobrazujte znovu tento dialog pro {0}", + "Please wait while {0} is being installed. A black window may show up. Please wait until it closes.": "Počkejte prosím, než se nainstaluje {0}. Může se zobrazit černé (nebo modré) okno. Vyčkejte, dokud se nezavře.", + "{0} has been installed successfully.": "{0} byl úspěšně nainstalován.", + "Please click on \"Continue\" to continue": "Pro pokračování klikněte na \"Pokračovat\"", + "Continue": "Pokračovat", + "{0} has been installed successfully. It is recommended to restart UniGetUI to finish the installation": "{0} bylo úspěšně nainstalováno. Je doporučeno restartovat UniGetUI pro dokončení instalace.", + "Restart later": "Restartovat později", + "An error occurred:": "Nastala chyba:", + "Please see the Command-line Output or refer to the Operation History for further information about the issue.": "Další informace o problému naleznete ve výstupu příkazového řádku nebo v Historii operací.", + "Retry as administrator": "Zkusit znovu jako správce", + "Retry interactively": "Zkusit znovu interaktivně", + "Retry skipping integrity checks": "Zkusit znovu bez kontroly integrity", + "Installation options": "Volby instalace", + "Save": "Uložit", + "UniGetUI collects anonymous usage data with the sole purpose of understanding and improving the user experience.": "UniGetUI shromažďuje anonymní údaje o používání pouze za účelem pochopení a zlepšení uživatelských zkušeností.", + "More details about the shared data and how it will be processed": "Více podrobnosti o sdílených údajích a způsobu jejich zpracování", + "Do you accept that UniGetUI collects and sends anonymous usage statistics, with the sole purpose of understanding and improving the user experience?": "Souhlasíte s tím, že UniGetUI shromažďuje a odesílá anonymní statistiky o používání, a to výhradně za účelem pochopení a zlepšení uživatelských zkušeností?", + "Decline": "Odmítnout", + "No personal information is collected nor sent, and the collected data is anonimized, so it can't be back-tracked to you.": "Nejsou shromažďovány ani odesílány osobní údaje a shromážděné údaje jsou anonymizovány, takže je nelze zpětně vysledovat.", + "Navigation panel": "Navigační panel", + "Operations": "Operace", + "Toggle operations panel": "Přepnout panel operací", + "Bulk operations": "Hromadné operace", + "Retry failed": "Zkusit selhané znovu", + "Clear successful": "Vymazat úspěšné", + "Clear finished": "Vymazat dokončené", + "Cancel all": "Zrušit vše", + "More": "Více", + "Toggle navigation panel": "Přepnout navigační panel", + "Minimize": "Minimalizovat", + "Maximize": "Maximalizovat", + "UniGetUI by Devolutions": "UniGetUI od společnosti Devolutions", + "UniGetUI is an application that makes managing your software easier, by providing an all-in-one graphical interface for your command-line package managers.": "UniGetUI je aplikace, která usnadňuje správu softwaru tím, že poskytuje grafické rozhraní pro správce balíčků příkazového řádku.", + "Useful links": "Užitečné odkazy", + "UniGetUI Homepage": "Domovská stránka UniGetUI", + "Report an issue or submit a feature request": "Nahlásit problém nebo odešli požadavek na funkci", + "UniGetUI Repository": "Repozitář UniGetUI", + "View GitHub Profile": "Zobrazit GitHub profil", + "UniGetUI License": "UniGetUI Licence", + "Using UniGetUI implies the acceptation of the MIT License": "Používání UniGetUI znamená souhlas s licencí MIT.", + "Become a translator": "Staňte se překladatelem", + "Go back": "Přejít zpět", + "Go forward": "Přejít vpřed", + "Go to home page": "Přejít na domovskou stránku", + "Reload page": "Znovu načíst stránku", + "View page on browser": "Zobrazit stránku v prohlížeči", + "The built-in browser is not supported on Linux yet.": "Vestavěný prohlížeč zatím není v Linuxu podporován.", + "Open in browser": "Otevřít v prohlížeči", + "Copy to clipboard": "Zkopírovat do schránky", + "Export to a file": "Exportovat do souboru", + "Log level:": "Úroveň protokolu:", + "Reload log": "Znovu načíst protokol", + "Export log": "Exportovat protokol", + "Text": "Textový", + "Change how operations request administrator rights": "Změna způsobu, jakým operace vyžadují oprávnění správce", + "Restrictions on package operations": "Omezení operací s balíčky", + "Restrictions on package managers": "Omezení správců balíčků", + "Restrictions when importing package bundles": "Omezení při importu balíčků", + "Ask for administrator privileges once for each batch of operations": "Požádat o oprávnění správce pro každou operaci", + "Ask only once for administrator privileges": "Požádat o oprávnění správce pouze jednou", + "Prohibit any kind of Elevation via UniGetUI Elevator or GSudo": "Zákaz jakéhokoli povýšení pomocí UniGetUI Elevator nebo GSudo", + "This option WILL cause issues. Any operation incapable of elevating itself WILL FAIL. Install/update/uninstall as administrator will NOT WORK.": "Tato možnost bude způsobovat problémy. Jakákoli operace, která se nedokáže sama povýšit, selže. Instalace/aktualizace/odinstalace jako správce NEBUDE FUNGOVAT.", + "Allow custom command-line arguments": "Povolit vlastní argumenty příkazového řádku", + "Custom command-line arguments can change the way in which programs are installed, upgraded or uninstalled, in a way UniGetUI cannot control. Using custom command-lines can break packages. Proceed with caution.": "Vlastní argumenty příkazového řádku mohou změnit způsob, jakým jsou programy instalovány, aktualizovány nebo odinstalovány, způsobem, který UniGetUI nemůže kontrolovat. Použití vlastních příkazových řádků může poškodit balíčky. Postupujte opatrně.", + "Ignore custom pre-install and post-install commands when importing packages from a bundle": "Povolit spuštění vlastních příkazů před instalací a po instalaci", + "Pre and post install commands will be run before and after a package gets installed, upgraded or uninstalled. Be aware that they may break things unless used carefully": "Příkazy před a po instalaci budou spuštěny před a po instalaci, aktualizaci nebo odinstalaci balíčku. Uvědomte si, že mohou věci poškodit, pokud nebudou použity opatrně.", + "Allow changing the paths for package manager executables": "Povolit změnu cest pro spustitelné soubory správce balíčků", + "Turning this on enables changing the executable file used to interact with package managers. While this allows finer-grained customization of your install processes, it may also be dangerous": "Zapnutí této funkce umožňuje změnit spustitelný soubor používaný pro interakci se správci balíčků. To sice umožňuje jemnější přizpůsobení instalačních procesů, ale může to být také nebezpečné", + "Allow importing custom command-line arguments when importing packages from a bundle": "Povolit import vlastních argumentů příkazového řádku při importování balíčků ze sady", + "Malformed command-line arguments can break packages, or even allow a malicious actor to gain privileged execution. Therefore, importing custom command-line arguments is disabled by default": "Nesprávně formátované argumenty příkazového řádku mohou poškodit balíčky nebo dokonce umožnit útočníkovi získat privilegované spouštění. Proto je import vlastních argumentů příkazového řádku ve výchozím nastavení zakázán.", + "Allow importing custom pre-install and post-install commands when importing packages from a bundle": "Povolit import vlastních předinstalačních a poinstalačních příkazů při importu balíčků ze sady", + "Pre and post install commands can do very nasty things to your device, if designed to do so. It can be very dangerous to import the commands from a bundle, unless you trust the source of that package bundle": "Příkazy před a po instalaci mohou způsobit velmi nepříjemné věci vašemu zařízení, pokud jsou k tomu navrženy. Může být velmi nebezpečné importovat příkazy ze sady, pokud nedůvěřujete zdroji této sady balíčků.", + "Administrator rights and other dangerous settings": "Oprávnění správce a další nebezpečná nastavení", + "Package backup": "Záloha balíčku", + "Cloud package backup": "Zálohování balíčků v cloudu", + "Local package backup": "Místní zálohování balíčků", + "Local backup advanced options": "Pokročilé možnosti místního zálohování", + "Log in with GitHub": "Přihlásit se pomocí GitHubu", + "Log out from GitHub": "Odhlásit se z GitHubu", + "Periodically perform a cloud backup of the installed packages": "Pravidelně provádět cloudovou zálohu nainstalovaných balíčků", + "Cloud backup uses a private GitHub Gist to store a list of installed packages": "Cloudové zálohování používá soukromý Gist GitHub k uložení seznamu nainstalovaných balíčků.", + "Perform a cloud backup now": "Provést zálohování do cloudu nyní", + "Backup": "Zálohovat", + "Restore a backup from the cloud": "Obnova zálohy z cloudu", + "Begin the process to select a cloud backup and review which packages to restore": "Zahájení procesu výběru cloudové zálohy a přezkoumání balíčků, které mají být obnoveny.", + "Periodically perform a local backup of the installed packages": "Pravidelně provádět místní zálohu nainstalovaných balíčků", + "Perform a local backup now": "Provést místní zálohování nyní", + "Change backup output directory": "Změnit výstupní adresář zálohy", + "Set a custom backup file name": "Vlastní název pro soubor zálohy", + "Leave empty for default": "Nechat prázdné pro výchozí", + "Add a timestamp to the backup file names": "Přidat časové razítko (timestamp) do názvu souboru zálohy", + "Backup and Restore": "Zálohování a obnovení", + "Enable background api (UniGetUI Widgets and Sharing, port 7058)": "Povolit api na pozadí (Widgets pro UniGetUI a Sdílení, port 7058)", + "Wait for the device to be connected to the internet before attempting to do tasks that require internet connectivity.": "Před prováděním úkolů, které vyžadují připojení k internetu, počkejte, až bude zařízení připojeno k internetu.", + "Disable the 1-minute timeout for package-related operations": "Vypnutí minutového limitu pro operace související s balíčky", + "Use installed GSudo instead of UniGetUI Elevator": "Použít nainstalovaný GSudo místo UniGetUI Elevator", + "Use a custom icon and screenshot database URL": "Použít vlastní URL databáze pro ikonky a screenshoty", + "Enable background CPU Usage optimizations (see Pull Request #3278)": "Povolení optimalizace využití procesoru na pozadí (viz Pull Request #3278)", + "Perform integrity checks at startup": "Provést kontrolu integrity při spuštění", + "When batch installing packages from a bundle, install also packages that are already installed": "Při dávkové instalaci balíčků ze sady nainstalovat i balíčky, které jsou již nainstalovány.", + "Experimental settings and developer options": "Experimentální nastavení a vývojářské možnosti", + "Show UniGetUI's version and build number on the titlebar.": "Zobrazit verzi UniGetUI v záhlaví okna", + "Language": "Jazyk", + "UniGetUI updater": "Aktualizace UniGetUI", + "Telemetry": "Telemetrie", + "Manage UniGetUI settings": "Správa nastavení UniGetUI", + "Related settings": "Související nastavení", + "Update UniGetUI automatically": "Automaticky aktualizovat UniGetUI", + "Check for updates": "Zkontrolovat aktualizace", + "Install prerelease versions of UniGetUI": "Instalovat předběžné verze UniGetUI", + "Manage telemetry settings": "Spravovat nastavení telemetrie", + "Manage": "Správa", + "Import settings from a local file": "Importovat nastavení ze souboru", + "Import": "Importovat", + "Export settings to a local file": "Exportovat nastavení do souboru", + "Export": "Exportovat", + "Reset UniGetUI": "Obnovit UniGetUI", + "User interface preferences": "Vlastnosti uživatelského rozhraní", + "Application theme, startup page, package icons, clear successful installs automatically": "Motiv aplikace, úvodní stránka, ikony balíčků, automatické vymazání úspěšných instalací", + "General preferences": "Obecné vlastnosti", + "UniGetUI display language:": "Jazyk UniGetUI", + "System language": "Jazyk systému", + "Is your language missing or incomplete?": "Chybí váš jazyk nebo není úplný?", + "Appearance": "Vzhled", + "UniGetUI on the background and system tray": "UniGetUI v pozadí a systémové liště", + "Package lists": "Seznamy balíčků", + "Use classic mode": "Použít klasický režim", + "Restart UniGetUI to apply this change": "Restartujte UniGetUI, aby se tato změna projevila", + "The classic UI is disabled for beta testers": "Klasické uživatelské rozhraní je pro beta testery vypnuté", + "Close UniGetUI to the system tray": "Zavírat UniGetUI do systémové lišty", + "Manage UniGetUI autostart behaviour": "Spravovat chování automatického spouštění UniGetUI", + "Show package icons on package lists": "Zobrazit ikonky balíčků na seznamu balíčků", + "Clear cache": "Vyčistit mezipaměť", + "Select upgradable packages by default": "Vždy vybrat aktualizovatelné balíčky", + "Light": "Světlý", + "Dark": "Tmavý", + "Follow system color scheme": "Dle systému", + "Application theme:": "Motiv aplikace:", + "UniGetUI startup page:": "Při spuštění UniGetUI zobrazit:", + "Proxy settings": "Nastavení proxy serveru", + "Other settings": "Ostatní nastavení", + "Connect the internet using a custom proxy": "Připojte se na internet pomocí vlastní proxy", + "Please note that not all package managers may fully support this feature": "Upozorňujeme, že ne všichni správci balíčků mohou tuto funkci plně podporovat.", + "Proxy URL": "URL proxy serveru", + "Enter proxy URL here": "Zde zadejte URL proxy serveru", + "Authenticate to the proxy with a user and a password": "Ověřit se vůči proxy pomocí uživatele a hesla", + "Internet and proxy settings": "Nastavení internetu a proxy", + "Package manager preferences": "Nastavení správce balíčků", + "Ready": "Připraveno", + "Not found": "Nenalezeno", + "Notification preferences": "Předvolby oznámení", + "Notification types": "Typy oznámení", + "The system tray icon must be enabled in order for notifications to work": "Aby oznámení fungovala, musí být povolena ikona na systémové liště.", + "Enable UniGetUI notifications": "Zapnout oznámení UniGetUI", + "Show a notification when there are available updates": "Zobrazit oznámení, pokud jsou dostupné aktualizace", + "Show a silent notification when an operation is running": "Zobrazit tichá oznámení při běžící operaci", + "Show a notification when an operation fails": "Zobrazit oznámení po selhání operace", + "Show a notification when an operation finishes successfully": "Zobrazit oznámení po úspěšném dokončení operace", + "Concurrency and execution": "Souběžnost a provádění", + "Automatic desktop shortcut remover": "Automatické mazání zástupců z plochy", + "Choose how many operations should be performed in parallel": "Vyberte, kolik operací se má provádět souběžně", + "Clear successful operations from the operation list after a 5 second delay": "Vymazat úspěšné operace po 5 sekundách ze seznamu operací", + "Download operations are not affected by this setting": "Toto nastavení nemá vliv na operace stahování", + "You may lose unsaved data": "Může dojít ke ztrátě neuložených dat", + "Ask to delete desktop shortcuts created during an install or upgrade.": "Zeptat se na smazání zástupců na ploše vytvořených během instalace nebo aktualizace", + "Package update preferences": "Předvolby aktualizace balíčků", + "Update check frequency, automatically install updates, etc.": "Frekvence kontroly aktualizací, automatická instalace aktualizací atd.", + "Reduce UAC prompts, elevate installations by default, unlock certain dangerous features, etc.": "Omezení výzev UAC, zvýšení úrovně výchozí instalace, odemčení některých nebezpečných funkcí atd.", + "Package operation preferences": "Předvolby operací s balíčky", + "Enable {pm}": "Zapnout {pm}", + "Not finding the file you are looking for? Make sure it has been added to path.": "Nenašli jste hledaný soubor? Zkontrolujte, zda byl přidán do cesty.", + "Select the executable to be used. The following list shows the executables found by UniGetUI": "Vyberte spustitelný soubor, který chcete použít. Následující seznam obsahuje spustitelné soubory nalezené UniGetUI.", + "For security reasons, changing the executable file is disabled by default": "Změna spustitelného souboru je ve výchozím nastavení z bezpečnostních důvodů zakázána.", + "Change this": "Změnit toto", + "Copy path": "Kopírovat cestu", + "Current executable file:": "Aktuálně spustitelný soubor:", + "Ignore packages from {pm} when showing a notification about updates": "Ignorovat balíčky z {pm} při zobrazení oznámení o aktualizacích", + "Update security": "Zabezpečení aktualizací", + "Use global setting": "Použít globální nastavení", + "Minimum age for updates": "Minimální stáří aktualizací", + "e.g. 10": "např. 10", + "Custom minimum age (days)": "Vlastní minimální stáří (dny)", + "{pm} does not provide release dates for its packages, so this setting will have no effect": "{pm} neposkytuje data vydání svých balíčků, takže toto nastavení nebude mít žádný vliv", + "{pm} only provides release dates for some of its packages, so this setting will only apply to those packages": "{pm} poskytuje data vydání pouze pro některé své balíčky, takže toto nastavení se bude týkat pouze těchto balíčků", + "Override the global minimum update age for this package manager": "Přepsat globální minimální stáří aktualizací pro tohoto správce balíčků", + "View {0} logs": "Zobrazit {0} protokoly", + "If Python cannot be found or is not listing packages but is installed on the system, ": "Pokud nelze Python najít nebo nezobrazuje balíčky, ale je v systému nainstalován, ", + "Advanced options": "Pokročilé možnosti", + "WinGet command-line tool": "Nástroj příkazového řádku WinGet", + "Choose which command-line tool UniGetUI uses for WinGet operations when the COM API is not used": "Zvolte, který nástroj příkazového řádku má UniGetUI používat pro operace WinGet, když se nepoužívá COM API", + "WinGet COM API": "WinGet COM API", + "Choose whether UniGetUI can use the WinGet COM API before falling back to the command-line tool": "Zvolte, zda může UniGetUI použít COM API WinGet před návratem k nástroji příkazového řádku", + "Reset WinGet": "Obnovit WinGet", + "This may help if no packages are listed": "Toto může pomoci, když se balíčky nezobrazují", + "Force install location parameter when updating packages with custom locations": "Vynutit parametr umístění instalace při aktualizaci balíčků s vlastními umístěními", + "Install Scoop": "Nainstalovat Scoop", + "Uninstall Scoop (and its packages)": "Odinstalovat Scoop (a jeho balíčky)", + "Run cleanup and clear cache": "Spustit čištění a vymazat mezipaměť", + "Run": "Spustit", + "Enable Scoop cleanup on launch": "Zapnout pročištění Scoopu po spuštění", + "Default vcpkg triplet": "Výchozí vcpkg triplet", + "Change vcpkg root location": "Změnit umístění kořene vcpkg", + "Reset vcpkg root location": "Obnovit kořenové umístění vcpkg", + "Open vcpkg root location": "Otevřít kořenové umístění vcpkg", + "Language, theme and other miscellaneous preferences": "Lokalizace, motivy a další různé vlastnosti", + "Show notifications on different events": "Zobrazit oznámení o různých událostech", + "Change how UniGetUI checks and installs available updates for your packages": "Změňte, jak UniGetUI kontroluje a instaluje dostupné aktualizace pro vaše balíčky", + "Automatically save a list of all your installed packages to easily restore them.": "Automatické uložení seznamu všech nainstalovaných balíčků pro jejich snadné obnovení", + "Enable and disable package managers, change default install options, etc.": "Povolení a zakázání správců balíčků, změna výchozích možností instalace atd.", + "Internet connection settings": "Nastavení připojení k internetu", + "Proxy settings, etc.": "Nastavení proxy serveru atd.", + "Beta features and other options that shouldn't be touched": "Testovací funkce a další vlastnosti, na které byste neměli sahat", + "Reload sources": "Znovu načíst zdroje", + "Delete source": "Smazat zdroj", + "Known sources": "Známé zdroje", + "Update checking": "Kontrola aktualizací", + "Automatic updates": "Automatické aktualizace", + "Check for package updates periodically": "Pravidelně kontrolovat aktualizace", + "Check for updates every:": "Kontrolovat aktualizace každých:", + "Install available updates automatically": "Automaticky instalovat dostupné aktualizace", + "Do not automatically install updates when the network connection is metered": "Neinstalovat aktualizace, pokud je síťové připojení účtováno po objemu dat", + "Do not automatically install updates when the device runs on battery": "Neinstalovat aktualizace, pokud zařízení běží na baterii", + "Do not automatically install updates when the battery saver is on": "Neinstalovat aktualizace, pokud je zapnutý spořič energie", + "Only show updates that are at least the specified number of days old": "Zobrazovat pouze aktualizace, které jsou alespoň zadaný počet dní staré", + "Warn me when the installer URL host changes between the installed version and the new version (WinGet only)": "Upozornit mě, když se hostitel URL instalačního programu změní mezi nainstalovanou a novou verzí (pouze WinGet)", + "Change how UniGetUI handles install, update and uninstall operations.": "Změňte způsob, jakým UniGetUI zpracovává operace instalace, aktualizace a odinstalace.", + "Navigation": "Navigace", + "Check for UniGetUI updates": "Kontrolovat aktualizace UniGetUI", + "Quit UniGetUI": "Ukončit UniGetUI", + "Filters": "Filtry", + "Sources": "Zdroje", + "Search for packages to start": "Pro výpis balíčků začněte vyhledávat", + "Select all": "Vybrat vše", + "Clear selection": "Zrušit výběr", + "Instant search": "Živé hledání", + "Distinguish between uppercase and lowercase": "Rozlišovat velké a malé písmena", + "Ignore special characters": "Ignorovat speciální znaky", + "Search mode": "Režim vyhledávání", + "Both": "Oba", + "Exact match": "Přesná shoda", + "Show similar packages": "Podobné balíčky", + "Loading": "Načítání", + "Package": "Balíček", + "More options": "Další možnosti", + "Order by:": "Seřadit podle:", + "Name": "Název", + "Id": "ID", + "Ascendant": "Vzestupně", + "Descendant": "Sestupně", + "View modes": "Režimy zobrazení", + "Reload": "Znovu načíst", + "Closed": "Zavřeno", + "Ascending": "Vzestupně", + "Descending": "Sestupně", + "{0}: {1}, {2}": "{0}: {1}, {2}", + "Order by": "Seřadit podle", + "No results were found matching the input criteria": "Nebyl nalezen žádný výsledek splňující kritéria", + "No packages were found": "Žádné balíčky nebyly nalezeny", + "Loading packages": "Načítání balíčků", + "Skip integrity checks": "Přeskočit kontrolu integrity", + "Download selected installers": "Stáhnout vybrané instalační programy", + "Install selection": "Nainstalovat vybrané", + "Install options": "Možnosti instalace", + "Add selection to bundle": "Přidat výběr do sady", + "Download installer": "Stáhnout instalátor", + "Uninstall selection": "Odinstalovat vybrané", + "Uninstall options": "Možnosti odinstalace", + "Ignore selected packages": "Ignorovat vybrané balíčky", + "Open install location": "Otevřít umístění instalace", + "Reinstall package": "Přeinstalovat balíček", + "Uninstall package, then reinstall it": "Odinstalovat balíček a poté znovu nainstalovat", + "Ignore updates for this package": "Ignorovat aktualizace pro tento balíček", + "WinGet malfunction detected": "Zjištěna porucha WinGet", + "It looks like WinGet is not working properly. Do you want to attempt to repair WinGet?": "Vypadá to, že program WinGet nefunguje správně. Chcete se pokusit WinGet opravit?", + "Repair WinGet": "Opravit WinGet", + "Updates will no longer be ignored for {0}": "Aktualizace pro {0} již nebudou ignorovány", + "Updates are now ignored for {0}": "Aktualizace pro {0} jsou nyní ignorovány", + "Do not ignore updates for this package anymore": "Neignorovat aktualizace tohoto balíčku", + "Add packages or open an existing package bundle": "Přidat balíčky nebo otevřít stávající sadu balíčků", + "Add packages to start": "Přidejte balíčky", + "The current bundle has no packages. Add some packages to get started": "Aktuální sada neobsahuje žádné balíčky. Přidejte nějaké balíčky a začněte", + "New": "Nové", + "Save as": "Uložit jako", + "Create .ps1 script": "Vytvořit skript .ps1", + "Remove selection from bundle": "Odstranit výběr ze sady", + "Skip hash checks": "Přeskočit kontrolní součet", + "The package bundle is not valid": "Sada balíčků není platná", + "The bundle you are trying to load appears to be invalid. Please check the file and try again.": "Sadu, kterou se snažíte načíst, se zdá být neplatná. Zkontrolujte prosím soubor a zkuste to znovu.", + "Package bundle": "Sada balíčku", + "Could not create bundle": "Sadu se nepodařilo vytvořit", + "The package bundle could not be created due to an error.": "Sada balíčků se nepodařilo vytvořit z důvodu chyby.", + "Install script": "Instalační skript", + "PowerShell script": "Skript PowerShell", + "The installation script saved to {0}": "Instalační skript uložen do {0}", + "An error occurred": "Nastala chyba", + "An error occurred while attempting to create an installation script:": "Při pokusu o vytvoření instalačního skriptu došlo k chybě:", + "Hooray! No updates were found.": "Juchů! Nejsou žádné aktualizace!", + "Uninstall selected packages": "Odinstalovat vybrané balíčky", + "Update selection": "Aktualizovat vybrané", + "Update options": "Možnosti aktualizace", + "Uninstall package, then update it": "Odinstalovat balíček a poté jej aktualizovat", + "Uninstall package": "Odinstalovat balíček", + "Skip this version": "Přeskočit tuto verzi", + "Pause updates for": "Pozastavit aktualizace na", + "User | Local": "Uživatel | Místní", + "Machine | Global": "Počítač | Globální", + "The default package manager for Debian/Ubuntu-based Linux distributions.
Contains: Debian/Ubuntu packages": "Výchozí správce balíčků pro distribuce Linuxu založené na Debian/Ubuntu.
Obsahuje: balíčky Debian/Ubuntu", + "The Rust package manager.
Contains: Rust libraries and programs written in Rust": "Správce balíčků Rust.
Obsahuje: Knihovny a programy napsané v Rust", + "The classical package manager for windows. You'll find everything there.
Contains: General Software": "Klasický správce balíčků pro Windows. Najdete v něm vše.
Obsahuje: Obecný software", + "The default package manager for RHEL/Fedora-based Linux distributions.
Contains: RPM packages": "Výchozí správce balíčků pro distribuce Linuxu založené na RHEL/Fedora.
Obsahuje: balíčky RPM", + "A repository full of tools and executables designed with Microsoft's .NET ecosystem in mind.
Contains: .NET related tools and scripts": "Repozitář plný nástrojů a spustitelných souborů navržených s ohledem na ekosystém .NET společnosti Microsoft.
Obsahuje: .NET související nástroje a skripty\n", + "The universal Linux package manager for desktop applications.
Contains: Flatpak applications from configured remotes": "Univerzální správce balíčků pro desktopové aplikace v Linuxu.
Obsahuje: aplikace Flatpak z nakonfigurovaných vzdálených zdrojů", + "NuPkg (zipped manifest)": "NuPkg (zazipovaný manifest)", + "The Missing Package Manager for macOS (or Linux).
Contains: Formulae, Casks": "Chybějící správce balíčků pro macOS (nebo Linux).
Obsahuje: Formulae, Casks", + "Node JS's package manager. Full of libraries and other utilities that orbit the javascript world
Contains: Node javascript libraries and other related utilities": "Správce balíčků Node.js, je plný knihoven a dalších nástrojů, které týkají světa javascriptu.
Obsahuje: Knihovny a další související nástroje pro Node.js", + "The default package manager for Arch Linux and its derivatives.
Contains: Arch Linux packages": "Výchozí správce balíčků pro Arch Linux a jeho odvozeniny.
Obsahuje: balíčky Arch Linux", + "Python's library manager. Full of python libraries and other python-related utilities
Contains: Python libraries and related utilities": "Správce knihoven Pythonu a dalších nástrojů souvisejících s Pythonem.
Obsahuje: Knihovny Pythonu a související nástroje", + "PowerShell's package manager. Find libraries and scripts to expand PowerShell capabilities
Contains: Modules, Scripts, Cmdlets": "PowerShell správce balíčků. Hledání knihoven a skriptů k rozšíření PowerShell schopností
Obsahuje: Moduly, Skripty, Cmdlets\n", + "extracted": "extrahováno", + "Scoop package": "Scoop balíček", + "Great repository of unknown but useful utilities and other interesting packages.
Contains: Utilities, Command-line programs, General Software (extras bucket required)": "Obsáhlý repozitář neznámých, ale přesto užitečných nástrojů a dalších zajímavých balíčků.
Obsahuje: Nástroje, programy příkazové řádky a obecný software (nuné extra repozitáře)", + "The universal Linux package manager by Canonical.
Contains: Snap packages from the Snapcraft store": "Univerzální správce balíčků pro Linux od Canonical.
Obsahuje: balíčky Snap z obchodu Snapcraft", + "library": "knihovna", + "feature": "funkce", + "A popular C/C++ library manager. Full of C/C++ libraries and other C/C++-related utilities
Contains: C/C++ libraries and related utilities": "Oblíbený správce knihoven v jazyce C/C++. Plný knihoven a dalších nástrojů souvisejících s C/C++.
Obsahuje: C/C++ knihovny a související nástroje", + "option": "možnost", + "This package cannot be installed from an elevated context.": "Tento balíček nelze nainstalovat z kontextu výše.", + "Please run UniGetUI as a regular user and try again.": "Spusťte UniGetUI jako běžný uživatel a zkuste to znovu.", + "Please check the installation options for this package and try again": "Zkontrolujte prosím možnosti instalace tohoto balíčku a zkuste to znovu", + "Microsoft's official package manager. Full of well-known and verified packages
Contains: General Software, Microsoft Store apps": "Oficiální správce balíčků od Microsoftu, plný dobře známých a oveřených programů
Obsahuje: Obecný software a aplikace z Microsoft Store", + "Local PC": "Místní počítač", + "Android Subsystem": "Subsystém Android", + "Operation on queue (position {0})...": "Operace v pořadí (pozice {0})...", + "Click here for more details": "Klikněte zde pro více informací", + "Operation canceled by user": "Operace zrušena uživatelem", + "Running PreOperation ({0}/{1})...": "Spouští se PreOperation ({0}/{1})...", + "PreOperation {0} out of {1} failed, and was tagged as necessary. Aborting...": "PreOperation {0} z {1} selhala a byla označena jako nezbytná. Přerušuje se...", + "PreOperation {0} out of {1} finished with result {2}": "PreOperation {0} z {1} skončila s výsledkem {2}", + "Starting operation...": "Spouštění operace...", + "Running PostOperation ({0}/{1})...": "Spouští se PostOperation ({0}/{1})...", + "PostOperation {0} out of {1} failed, and was tagged as necessary. Aborting...": "PostOperation {0} z {1} selhala a byla označena jako nezbytná. Přerušuje se...", + "PostOperation {0} out of {1} finished with result {2}": "PostOperation {0} z {1} skončila s výsledkem {2}", + "{package} installer download": "Stáhnout instalační program {package}", + "{0} installer is being downloaded": "Stahuje se instalační program {0}", + "Download succeeded": "Úspěšně staženo", + "{package} installer was downloaded successfully": "Instalační program {package} byl úspěšně stažen", + "Download failed": "Stažení se nezdařilo", + "{package} installer could not be downloaded": "Instalační program {package} se nepodařilo stáhnout", + "{package} Installation": "Instalace {package}", + "{0} is being installed": "{0} je instalováno", + "Installation succeeded": "Úspěšně nainstalováno", + "{package} was installed successfully": "{package} byl úspěšně nainstalován", + "Installation failed": "Instalace selhala", + "{package} could not be installed": "{package} nemohl být nainstalován", + "{package} Update": "Aktualizace {package}", + "Update succeeded": "Úspěšně aktualizováno", + "{package} was updated successfully": "{package} byl úspěšně aktualizován", + "Update failed": "Aktualizace selhala", + "{package} could not be updated": "{package} nemohl být aktualizován", + "{package} Uninstall": "Odinstalace {package}", + "{0} is being uninstalled": "{0} je odinstalován", + "Uninstall succeeded": "Úspěšně odinstalováno", + "{package} was uninstalled successfully": "{package} byl úspěšně odinstalován", + "Uninstall failed": "Odinstalace selhala", + "{package} could not be uninstalled": "{package} nemohl být odinstalován", + "Adding source {source}": "Přidávání zdroje {source}", + "Adding source {source} to {manager}": "Přidávání zdroje {source} do {manager}", + "Source added successfully": "Zdroj byl úspěšně přidán", + "The source {source} was added to {manager} successfully": "Zdroj {source} byl úspěšně přidán do {manager}", + "Could not add source": "Nepodařilo se přidat zdroj", + "Could not add source {source} to {manager}": "Nepodařilo se přidat zdroj {source} do {manager}", + "Removing source {source}": "Odstraňování zdroje {source}", + "Removing source {source} from {manager}": "Odebírání zdroje {source} z {manager}", + "Source removed successfully": "Zdroj byl úspěšně odebrán", + "The source {source} was removed from {manager} successfully": "Zdroj {source} byl úspěšně odebrán z {manager}", + "Could not remove source": "Nepodařilo se odstranit zdroj", + "Could not remove source {source} from {manager}": "Nepodařilo se odebrat zdroj {source} z {manager}", + "The package manager \"{0}\" was not found": "Správce balíčků \"{0}\" nebyl nalezen", + "The package manager \"{0}\" is disabled": "Správce balíčků \"{0}\" je vypnutý", + "There is an error with the configuration of the package manager \"{0}\"": "Došlo k chybě v konfiguraci správce balíčků „{0}“", + "The package \"{0}\" was not found on the package manager \"{1}\"": "Balíček „{0}“ nebyl nalezen ve správci balíčků „{1}“", + "{0} is disabled": "{0} je vypnuto", + "{0} weeks": "{0} týdnů", + "1 month": "1 měsíc", + "{0} months": "{0} měsíců", + "Something went wrong": "Něco se pokazilo", + "An interal error occurred. Please view the log for further details.": "Došlo k interní chybě. Další podrobnosti naleznete v protokolu.", + "No applicable installer was found for the package {0}": "Pro balíček {0} nebyl nalezen žádný použitelný instalační program.", + "Integrity checks will not be performed during this operation": "Kontrola integrity se při této operaci neprovádí.", + "This is not recommended.": "Toto se nedoporučuje.", + "Run now": "Spustit hned", + "Run next": "Spustit jako další", + "Run last": "Spustit jako poslední", + "Show in explorer": "Zobrazit v průzkumníkovi", + "Checked": "Zaškrtnuto", + "Unchecked": "Nezaškrtnuto", + "This package is already installed": "Tento balíček je již nainstalován", + "This package can be upgraded to version {0}": "Tento balíček může být aktualizován na verzi {0}", + "Updates for this package are ignored": "Aktulizace tohoto balíčku jsou ignorovány", + "This package is being processed": "Tento balíček se zpracovává", + "This package is not available": "Tento balíček je nedostupný", + "Select the source you want to add:": "Vyber zdroj, který chceš přidat:", + "Source name:": "Název zdroje:", + "Source URL:": "URL zdroje:", + "An error occurred when adding the source: ": "Nastala chyba při přidávání zdroje:", + "Package management made easy": "Snadná správa balíčků", + "version {0}": "verze {0}", + "[RAN AS ADMINISTRATOR]": "SPUŠTĚNO JAKO SPRÁVCE", + "Portable mode": "Přenosný režim", + "DEBUG BUILD": "LADICÍ SESTAVENÍ", + "Here you can change UniGetUI's behaviour regarding the following shortcuts. Checking a shortcut will make UniGetUI delete it if if gets created on a future upgrade. Unchecking it will keep the shortcut intact": "Zde můžete změnit chování rozhraní UniGetUI, pokud jde o následující zkratky. Zaškrtnutí zástupce způsobí, že jej UniGetUI odstraní, pokud bude vytvořen při budoucí aktualizaci. Zrušením zaškrtnutí zůstane zástupce nedotčen", + "Manual scan": "Manuální skenování", + "Existing shortcuts on your desktop will be scanned, and you will need to pick which ones to keep and which ones to remove.": "Stávající zástupci na ploše budou prohledáni a budete muset vybrat, které z nich chcete zachovat a které odstranit.", + "Delete?": "Smazat?", + "I understand": "Rozumím", + "Chocolatey setup changed": "Nastavení Chocolatey bylo změněno", + "UniGetUI no longer includes its own private Chocolatey installation. A legacy UniGetUI-managed Chocolatey installation was detected for this user profile, but system Chocolatey was not found. Chocolatey will stay unavailable in UniGetUI until Chocolatey is installed on the system and UniGetUI is restarted. Applications previously installed through UniGetUI's bundled Chocolatey may still appear under other sources such as Local PC or WinGet.": "UniGetUI již neobsahuje vlastní soukromou instalaci Chocolatey. Pro tento uživatelský profil byla zjištěna starší instalace Chocolatey spravovaná aplikací UniGetUI, ale systémový Chocolatey nebyl nalezen. Chocolatey zůstane v UniGetUI nedostupné, dokud nebude Chocolatey nainstalováno v systému a UniGetUI nebude restartováno. Aplikace dříve nainstalované prostřednictvím přibaleného Chocolatey v UniGetUI se mohou stále zobrazovat pod jinými zdroji, jako je Místní počítač nebo WinGet.", + "NOTE: This troubleshooter can be disabled from UniGetUI Settings, on the WinGet section": "Poznámka: Toto řešení problémů může být vypnuto z nastavení UnigetUI v sekci WinGet", + "Restart": "Restartovat", + "Are you sure you want to delete all shortcuts?": "Opravdu chcete odstranit všechny zkratky?", + "Any new shorcuts created during an install or an update operation will be deleted automatically, instead of showing a confirmation prompt the first time they are detected.": "Všechny nové zkratky vytvořené během instalace nebo aktualizace budou automaticky odstraněny, místo aby se při jejich prvním zjištění zobrazil potvrzovací dotaz.", + "Any shorcuts created or modified outside of UniGetUI will be ignored. You will be able to add them via the {0} button.": "Zkratky vytvořené nebo upravené mimo rozhraní UniGetUI budou ignorovány. Budete je moci přidat pomocí tlačítka {0}.", + "Are you really sure you want to enable this feature?": "Opravdu chcete tuto funkci povolit?", + "No new shortcuts were found during the scan.": "Při kontrole nebyly nalezeny žádné nové zkratky.", + "How to add packages to a bundle": "Jak přidat balíčky do sady", + "In order to add packages to a bundle, you will need to: ": "Chcete-li přidat balíčky do sady, musíte: ", + "1. Navigate to the \"{0}\" or \"{1}\" page.": "1. Přejděte na stránku „{0}“ nebo „{1}“.", + "2. Locate the package(s) you want to add to the bundle, and select their leftmost checkbox.": "2. Vyhledejte balíčky, který chcete přidat do balíčku, a zaškrtněte jejich políčko vlevo.", + "3. When the packages you want to add to the bundle are selected, find and click the option \"{0}\" on the toolbar.": "3. Po výběru balíčků, které chcete přidat do balíčku, vyhledejte na panelu nástrojů možnost „{0}“ a klikněte na ni.", + "4. Your packages will have been added to the bundle. You can continue adding packages, or export the bundle.": "4. Vaše balíčky budou přidány do balíčku. Můžete pokračovat v přidávání balíčků nebo balíček exportovat.", + "Which backup do you want to open?": "Kterou zálohu chcete otevřít?", + "Select the backup you want to open. Later, you will be able to review which packages you want to install.": "Vyberte zálohu, kterou chcete otevřít. Později budete moci zkontrolovat, které balíčky/programy chcete obnovit.", + "There are ongoing operations. Quitting UniGetUI may cause them to fail. Do you want to continue?": "Stále se provádí operace. Ukončení UniGetUI může způsobit jejich selhání. Chcete i přesto pokračovat?\n", + "UniGetUI or some of its components are missing or corrupt.": "UniGetUI nebo některé z jeho komponent chybí nebo jsou poškozené.", + "It is strongly recommended to reinstall UniGetUI to adress the situation.": "Důrazně se doporučuje přeinstalovat UniGetUI k vyřešení této situace.", + "Refer to the UniGetUI Logs to get more details regarding the affected file(s)": "Podívejte se do protokolů UniGetUI pro získání více podrobností o postižených souborech", + "Integrity checks can be disabled from the Experimental Settings": "Kontrolu integrity lze zakázat v Experimentálním nastavení", + "Repair UniGetUI": "Opravit UniGetUI", + "Live output": "Živý výstup", + "This package bundle had some settings that are potentially dangerous, and may be ignored by default.": "Tato sada balíčků obsahoval některá potenciálně nebezpečná nastavení, která mohou být ve výchozím nastavení ignorována.", + "Entries that show in YELLOW will be IGNORED.": "Záznamy, které se zobrazí žlutě, budou IGNOROVÁNY.", + "Entries that show in RED will be IMPORTED.": "Záznamy, které se zobrazí červeně, budou IMPORTOVÁNY.", + "You can change this behavior on UniGetUI security settings.": "Toto chování můžete změnit v nastavení zabezpečení UniGetUI.", + "Open UniGetUI security settings": "Otevřete nastavení zabezpečení UniGetUI", + "Should you modify the security settings, you will need to open the bundle again for the changes to take effect.": "Pokud změníte nastavení zabezpečení, budete muset sadu znovu otevřít, aby se změny projevily.", + "Details of the report:": "Podrobnosti zprávy:", + "Are you sure you want to create a new package bundle? ": "Opravdu chcete vytvořit novou sadu balíčků?", + "Any unsaved changes will be lost": "Neuložené změny budou ztraceny", + "Warning!": "Varování!", + "For security reasons, custom command-line arguments are disabled by default. Go to UniGetUI security settings to change this. ": "Z bezpečnostních důvodů jsou vlastní argumenty příkazového řádku ve výchozím nastavení zakázány. Chcete-li to změnit, přejděte do nastavení zabezpečení UniGetUI.", + "Change default options": "Změnit výchozí možnosti", + "Ignore future updates for this package": "Ignorovat budoucí aktualizace tohoto balíčku", + "For security reasons, pre-operation and post-operation scripts are disabled by default. Go to UniGetUI security settings to change this. ": "Z bezpečnostních důvodů jsou předoperační a pooperační skripty ve výchozím nastavení zakázány. Chcete-li to změnit, přejděte do nastavení zabezpečení UniGetUI.", + "You can define the commands that will be run before or after this package is installed, updated or uninstalled. They will be run on a command prompt, so CMD scripts will work here.": "Můžete definovat příkazy, které budou spuštěny před nebo po instalaci, aktualizaci nebo odinstalaci tohoto balíčku. Budou spuštěny v příkazovém řádku, takže zde budou fungovat skripty CMD.", + "Change this and unlock": "Změnit toto a odemknout", + "{0} Install options are currently locked because {0} follows the default install options.": "{0} možnosti instalace jsou v současné době uzamčeny, protože {0} se řídí výchozími možnostmi instalace.", + "Unset or unknown": "Nenastaveno nebo neznámo", + "This package has no screenshots or is missing the icon? Contrbute to UniGetUI by adding the missing icons and screenshots to our open, public database.": "Chybí tomuto balíčku snímky obrazovky nebo ikonka? Přispějte do UniGetUI přidáním chybějících ikonek a snímků obrazovky do naší otevřené, veřejné databáze.", + "Become a contributor": "Staňte se přispěvatelem", + "Update to {0} available": "Je dostupná aktualizace na {0}", + "Reinstall": "Přeinstalovat", + "Installer not available": "Instalační program není dostupný", + "Version:": "Verze:", + "UniGetUI Version {0}": "UniGetUI verze {0}", + "Performing backup, please wait...": "Provádím zálohu, prosím vyčkejte...", + "An error occurred while logging in: ": "Při přihlašování došlo k chybě:", + "Fetching available backups...": "Načítání dostupných záloh...", + "Done!": "Hotovo!", + "The cloud backup has been loaded successfully.": "Cloudová záloha byla úspěšně načtena.", + "An error occurred while loading a backup: ": "Při načítání zálohy došlo k chybě:", + "Backing up packages to GitHub Gist...": "Zálohování balíčků na GitHub Gist...", + "Backup Successful": "Zálohování proběhlo úspěšně", + "The cloud backup completed successfully.": "Zálohování do cloudu bylo úspěšně dokončeno.", + "Could not back up packages to GitHub Gist: ": "Nepodařilo se zálohovat balíčky na GitHub Gist:", + "It is not guaranteed that the provided credentials will be stored safely, so you may as well not use the credentials of your bank account": "Není zaručeno, že poskytnuté přihlašovací údaje budou bezpečně uloženy, takže nepoužívej přihlašovací údaje k vašemu bankovnímu účtu.", + "Enable the automatic WinGet troubleshooter": "Zapnout automatické řešení problémů WinGet", + "Add updates that fail with a 'no applicable update found' to the ignored updates list": "Přidat aktualizace, které selžou s hlášením „nebyla nalezena žádná použitelná aktualizace“, do seznamu ignorovaných aktualizací.", + "Invalid selection": "Neplatný výběr", + "No package was selected": "Nebyl vybrán žádný balíček", + "More than 1 package was selected": "Byl vybrán víc než 1 balíček", + "List": "Seznam", + "Grid": "Mřížka", + "Icons": "Ikony", + "\"{0}\" is a local package and does not have available details": "\"{0}\" je lokální balíček a nemá dostupné detaily", + "\"{0}\" is a local package and is not compatible with this feature": "\"{0}\" je lokální balíček a není kompatibilní s touto funkcí", + "Add packages to bundle": "Přidat balíčky do sady", + "Preparing packages, please wait...": "Příprava balíčků, prosím vyčkejte...", + "Loading packages, please wait...": "Načítání balíčků, prosím vyčkejte...", + "Saving packages, please wait...": "Ukládání balíčků, prosím vyčkejte...", + "The bundle was created successfully on {0}": "Balíček byl úspěšně vytvořen do {0}", + "User profile": "Uživatelský profil", + "Error": "Chyba", + "Log in failed: ": "Příhlašování selhalo.", + "Log out failed: ": "Odhlášení se nezdařilo:", + "Package backup settings": "Nastavení zálohování balíčku", + "Manage UniGetUI autostart behaviour from the Settings app": "Spravovat chování automatického spouštění UniGetUI", + "Choose how many operations shoulds be performed in parallel": "Vyberte, kolik operací se má provádět souběžně", + "Something went wrong while launching the updater.": "Při spouštění aktualizace se něco pokazilo.", + "Please try again later": "Zkuste to prosím později", + "Show the release notes after UniGetUI is updated": "Zobrazit poznámky k vydání po aktualizaci UniGetUI" +} diff --git a/src/Languages/lang_da.json b/src/Languages/lang_da.json new file mode 100644 index 0000000..263ea32 --- /dev/null +++ b/src/Languages/lang_da.json @@ -0,0 +1,850 @@ +{ + "{0} of {1} operations completed": "{0} af {1} handlinger fuldført", + "{0} is now {1}": "{0} er nu {1}", + "Enabled": "Aktiveret", + "Disabled": "Deaktiveret", + "Privacy": "Privatliv", + "Hide my username from the logs": "Skjul mit brugernavn fra logfilerne", + "Replaces your username with **** in the logs. Restart UniGetUI to also hide it from already-recorded entries.": "Erstatter dit brugernavn med **** i logfilerne. Genstart UniGetUI for også at skjule det fra allerede registrerede poster.", + "Your last update attempt did not complete.": "Dit seneste opdateringsforsøg blev ikke fuldført.", + "UniGetUI could not confirm whether the update succeeded. Open the log to see what happened.": "UniGetUI kunne ikke bekræfte, om opdateringen lykkedes. Åbn loggen for at se, hvad der skete.", + "View log": "Vis log", + "The installer reported success but did not restart UniGetUI.": "Installationsprogrammet meldte, at installationen lykkedes, men genstartede ikke UniGetUI.", + "The installer failed to initialize.": "Installationsprogrammet kunne ikke initialiseres.", + "Setup was canceled before installation began.": "Installationen blev annulleret, før den begyndte.", + "A fatal error occurred during the preparation phase.": "Der opstod en fatal fejl under forberedelsesfasen.", + "A fatal error occurred during installation.": "Der opstod en fatal fejl under installationen.", + "Installation was canceled while in progress.": "Installationen blev annulleret, mens den var i gang.", + "The installer was terminated by another process.": "Installationsprogrammet blev afsluttet af en anden proces.", + "The preparation phase determined the installation cannot proceed.": "Forberedelsesfasen fastslog, at installationen ikke kan fortsætte.", + "The installer could not start. UniGetUI may already be running, or you do not have permission to install.": "Installationsprogrammet kunne ikke starte. UniGetUI kører muligvis allerede, eller du har ikke tilladelse til at installere.", + "Unexpected installer error.": "Uventet fejl i installationsprogrammet.", + "We are checking for updates.": "Vi søger efter opdateringer.", + "Please wait": "Vent venligst", + "Great! You are on the latest version.": "Fantastisk! Du har den seneste version.", + "There are no new UniGetUI versions to be installed": "Der er ikke nogen nye UniGetUI versioner til installation.", + "UniGetUI version {0} is being downloaded.": "UniGetUI version {0} bliver downloaded.", + "This may take a minute or two": "Det kan tage et minut eller to", + "The installer authenticity could not be verified.": "Installationsprogrammets ægthed kunne ikke verificeres.", + "The update process has been aborted.": "Opdateringsprocessen er blevet afbrudt.", + "Auto-update is not yet available on this platform.": "Automatisk opdatering er endnu ikke tilgængelig på denne platform.", + "Please update UniGetUI manually.": "Opdater UniGetUI manuelt.", + "An error occurred when checking for updates: ": "Der skete en fejl under søgning efter opdateringer:", + "The updater could not be launched.": "Opdateringsprogrammet kunne ikke startes.", + "The operating system did not start the installer process.": "Operativsystemet startede ikke installationsprocessen.", + "UniGetUI is being updated...": "UniGetUI bliver opdateret...", + "Update installed.": "Opdatering installeret.", + "UniGetUI was updated successfully, but this running copy was not replaced. This usually means you are running a development build. Close this copy and start the newly-installed version to finish.": "UniGetUI blev opdateret, men denne kørende kopi blev ikke erstattet. Det betyder normalt, at du kører en udviklingsversion. Luk denne kopi, og start den nyinstallerede version for at færdiggøre.", + "The update could not be applied.": "Opdateringen kunne ikke anvendes.", + "Installer exit code {0}: {1}": "Installationsprogrammets afslutningskode {0}: {1}", + "Update cancelled.": "Opdatering annulleret.", + "Authentication was cancelled.": "Godkendelse blev annulleret.", + "Installer exit code {0}": "Installationsprogrammets afslutningskode {0}", + "Operation in progress": "Handling i gang", + "Please wait...": "Vent venligst...", + "Success!": "Succes!", + "Failed": "Fejlet", + "An error occurred while processing this package": "Der skete en fejl ved kørsel af denne pakke", + "Installer": "Installationsprogram", + "Executable": "Eksekverbar fil", + "MSI": "MSI", + "Compressed file": "Komprimeret fil", + "MSIX": "MSIX", + "WinGet was repaired successfully": "WinGet blev repareret med success", + "It is recommended to restart UniGetUI after WinGet has been repaired": "Det anbefales at genstarte UniGetUI efter WinGet er blevet repareret", + "WinGet could not be repaired": "WinGet kunne ikke repareres", + "An unexpected issue occurred while attempting to repair WinGet. Please try again later": "Et uventet problem opstod under forsøget på at reparere WinGet. Prøv igen senere.", + "Log in to enable cloud backup": "Log på for at aktivere cloud backup", + "Backup Failed": "Backup fejlede", + "Downloading backup...": "Downloader backup...", + "An update was found!": "Fundet en opdatering.", + "{0} can be updated to version {1}": "{0} kan opdateres til version {1}", + "Updates found!": "Opdateringer fundet!", + "{0} packages can be updated": "{0} pakker kan blive opdateret", + "{0} is being updated to version {1}": "{0} bliver opdateret til version {1}", + "{0} packages are being updated": "{0} pakker der bliver opdateret", + "You have currently version {0} installed": "Nuværende installerede version: {0}", + "Desktop shortcut created": "Skrivebordsgenvej oprettet", + "UniGetUI has detected a new desktop shortcut that can be deleted automatically.": "UniGetUI har opdaget en ny skrivebordsgenvej, som kan slettes automatisk.", + "{0} desktop shortcuts created": "{0} skrivebordsgenveje oprettet", + "UniGetUI has detected {0} new desktop shortcuts that can be deleted automatically.": "UniGetUI har opdaget {0} nye skrivebordsgenveje, som kan fjernes automatisk.", + "Attention required": "Opmærksomhed kræves", + "Restart required": "Genstart påkrævet", + "1 update is available": "1 opdatering tilgængelig", + "{0} updates are available": "{0} opdateringer tilgængelige", + "Everything is up to date": "Alt er opdateret", + "Discover Packages": "Søg efter pakker", + "Available Updates": "Tilgængelige opdateringer", + "Installed Packages": "Installerede pakker", + "UniGetUI Version {0} by Devolutions": "UniGetUI version {0} af Devolutions", + "Show UniGetUI": "Vis UniGetUI", + "Quit": "Afslut", + "Are you sure?": "Er du sikker?", + "Do you really want to uninstall {0}?": "Ønsker du virkelig at afinstallere {0}?", + "Do you really want to uninstall the following {0} packages?": "Ønsker du virkelig at afinstallere følgende {0} pakker?", + "No": "Nej", + "Yes": "Ja", + "Partial": "Delvis", + "View on UniGetUI": "Se på UniGetUI", + "Update": "Opdatér", + "Open UniGetUI": "Åbn UniGetUI", + "Update all": "Opdatér alle", + "Update now": "Opdater nu", + "Installer host changed since the installed version.\n": "Installationsprogrammets vært er ændret siden den installerede version.\n", + "This package is on the queue": "Denne pakke er ikke i køen", + "installing": "installere", + "updating": "opdaterer", + "uninstalling": "afinstallerer", + "installed": "installeret", + "Retry": "Prøv igen", + "Install": "Installer", + "Uninstall": "Afinstallér", + "Open": "Åben", + "Operation profile:": "Operationsprofil:", + "Follow the default options when installing, upgrading or uninstalling this package": "Følg standardmulighederne ved installation, opgradering eller afinstallation af denne pakke", + "The following settings will be applied each time this package is installed, updated or removed.": "Disse indstillinger vil blive anvendt hver gang denne pakke installeres, opdateres eller fjernes.", + "Version to install:": "Version til installation", + "Architecture to install:": "Installation af arkitektur:", + "Installation scope:": "Installationsomfang:", + "Install location:": "Installations placering", + "Select": "Vælg", + "Reset": "Nulstil", + "Custom install arguments:": "Brugerdefinerede installations argumenter:", + "Custom update arguments:": "Brugerdefinerede opdaterings argumenter:", + "Custom uninstall arguments:": "Brugerdefinerede afinstallations argumenter:", + "Pre-install command:": "Pre-install kommando:", + "Post-install command:": "Post-install kommando:", + "Abort install if pre-install command fails": "Afbryd installation hvis kommandoen før installation mislykkes", + "Pre-update command:": "Pre-update kommando:", + "Post-update command:": "Post-update kommando:", + "Abort update if pre-update command fails": "Afbryd opdatering hvis kommandoen før opdatering mislykkes", + "Pre-uninstall command:": "Pre-uninstall kommando:", + "Post-uninstall command:": "Post-uninstall kommando:", + "Abort uninstall if pre-uninstall command fails": "Afbryd afinstallation hvis kommandoen før afinstallation mislykkes", + "Command-line to run:": "Kommandolinje til kørsel:", + "Save and close": "Gem og luk", + "General": "Generelt", + "Architecture & Location": "Arkitektur og placering", + "Command-line": "Kommandolinje", + "Close apps": "Luk apps", + "Pre/Post install": "Før/efter installation", + "Select the processes that should be closed before this package is installed, updated or uninstalled.": "Vælg de processer, der skal lukkes, før denne pakke installeres, opdateres eller afinstalleres.", + "Write here the process names here, separated by commas (,)": "Skriv her processnavnene, adskilt af kommaer (,)", + "Try to kill the processes that refuse to close when requested to": "Forsøg at dræbe processerne, der nægter at lukke når der anmodes om det", + "Run as admin": "Kør som administrator", + "Interactive installation": "Interaktiv installation", + "Skip hash check": "Spring over hash check", + "Uninstall previous versions when updated": "Afinstaller tidligere versioner når opdateret", + "Skip minor updates for this package": "Spring mindre opdateringer over for denne pakke", + "Automatically update this package": "Opdater denne pakke automatisk", + "{0} installation options": "{0} installerings muligheder", + "Latest": "Senest:", + "PreRelease": "Præ-release", + "Default": "Standard", + "Manage ignored updates": "Administrer ignorerede opdateringer", + "The packages listed here won't be taken in account when checking for updates. Double-click them or click the button on their right to stop ignoring their updates.": "Pakkerne listet her vil ikke blive taget i betragtning ved søgning efter opdateringer. Dobbeltklik på dem eller klik på knappen til højre for dem for at stoppe med at ignorere deres opdateringer.", + "Reset list": "Nulstil liste", + "Do you really want to reset the ignored updates list? This action cannot be reverted": "Vil du virkelig nulstille listen over ignorerede opdateringer? Denne handling kan ikke fortrydes", + "No ignored updates": "Ingen ignorerede opdateringer", + "Package Name": "Pakke navn", + "Package ID": "Pakke ID", + "Ignored version": "Ignoreret version", + "New version": "Ny version", + "Source": "Kilde", + "All versions": "Alle versioner", + "Unknown": "Ukendt", + "Up to date": "Opdateret", + "Package {name} from {manager}": "Pakke {name} fra {manager}", + "Remove {0} from ignored updates": "Fjern {0} fra ignorerede opdateringer", + "Cancel": "Annuller", + "Administrator privileges": "Administratorrettigheder", + "This operation is running with administrator privileges.": "Handlingen kører med administratorrettigheder.", + "Interactive operation": "Interaktiv operation", + "This operation is running interactively.": "Handlingen kører interaktivt.", + "You will likely need to interact with the installer.": "Du vil sandsynligvis være nødt til at interagere med installationsprogrammet.", + "Integrity checks skipped": "Integritetstjek sprunget over", + "Integrity checks will not be performed during this operation.": "Integritetstjek udføres ikke under denne handling.", + "Proceed at your own risk.": "Fortsæt på egen risiko.", + "Close": "Luk", + "Loading...": "Indlæser...", + "Installer SHA256": "Installationsprogram SHA256", + "Homepage": "Startside", + "Author": "Udvikler", + "Publisher": "Udgiver", + "License": "Licens", + "Manifest": "Manifestfil", + "Installer Type": "Installationstype", + "Size": "Størrelse", + "Installer URL": "Installationsprogram-URL", + "Last updated:": "Senest opdateret:", + "Release notes URL": "Releasenotes URL", + "Package details": "Pakke detaljer", + "Dependencies:": "Afhængigheder:", + "Release notes": "Releasenotes", + "Screenshots": "Skærmbilleder", + "This package has no screenshots or is missing the icon? Contribute to UniGetUI by adding the missing icons and screenshots to our open, public database.": "Denne pakke har ingen skærmbilleder, eller ikonet mangler. Bidrag til UniGetUI ved at tilføje de manglende ikoner og skærmbilleder til vores åbne, offentlige database.", + "Version": "Udgave", + "Install as administrator": "Installér som administrator", + "Update to version {0}": "Opdater til version {0}", + "Installed Version": "Installeret Version", + "Update as administrator": "Opdatér som administrator", + "Interactive update": "Interaktiv opdatering", + "Uninstall as administrator": "Afinstallér som administrator", + "Interactive uninstall": "Interaktiv afinstallation", + "Uninstall and remove data": "Afinstaller og fjern data", + "Not available": "Ikke tilgængelig", + "Installer SHA512": "Installationsprogram SHA512", + "Unknown size": "Ukendt størrelse", + "No dependencies specified": "Ingen afhængigheder specificeret", + "mandatory": "obligatorisk", + "optional": "valgfrit", + "UniGetUI {0} is ready to be installed.": "UniGetUI {0} er klar til at blive installeret.", + "The update process will start after closing UniGetUI": "Opdateringsprocessen vil starte efter UniGetUI bliver lukket", + "UniGetUI has been ran as administrator, which is not recommended. When running UniGetUI as administrator, EVERY operation launched from UniGetUI will have administrator privileges. You can still use the program, but we highly recommend not running UniGetUI with administrator privileges.": "UniGetUI er blevet kørt som administrator, hvilket ikke anbefales. Når UniGetUI køres som administrator, vil ALLE handlinger startet fra UniGetUI have administratorrettigheder. Du kan stadig bruge programmet, men vi anbefaler kraftigt ikke at køre UniGetUI med administratorrettigheder.", + "Share anonymous usage data": "Del anonym brugsdata", + "UniGetUI collects anonymous usage data in order to improve the user experience.": "UniGetUI indsamler anonyme brugsdata for at forbedre brugeroplevelsen.", + "Accept": "Accepter", + "Software Updates": "Pakke opdateringer", + "Package Bundles": "Pakke samlinger", + "Settings": "Indstillinger", + "Package Managers": "Pakkemanagere", + "UniGetUI Log": "UniGetUI-log", + "Package Manager logs": "Pakkemanager logs", + "Operation history": "Handlingshistorik", + "Help": "Hjælp", + "UniGetUI": "UniGetUI", + "You have installed UniGetUI Version {0}": "Installeret UniGetUI version er {0}", + "Disclaimer": "Ansvarsfraskrivelse", + "UniGetUI is developed by Devolutions and is not affiliated with any of the compatible package managers.": "UniGetUI er udviklet af Devolutions og er ikke tilknyttet nogen af de kompatible pakkemanagere.", + "UniGetUI wouldn't have been possible without the help of the contributors. Thank you all 🥳": "UniGetUI ville ikke have været mulig uden støtten fra vores hjælpere. Tak til jer alle 🥳", + "UniGetUI uses the following libraries. Without them, UniGetUI wouldn't have been possible.": "UniGetUI bruger følgende biblioteker. Uden dem ville UniGetUI ikke have været mulig.", + "{0} homepage": "{0} startside", + "UniGetUI has been translated to more than 40 languages thanks to the volunteer translators. Thank you 🤝": "UniGetUI er oversat til mere end 40 sprog takket være de frivillige oversættere. Mange tak 🤝", + "Verbose": "Udførlig", + "1 - Errors": "1 fejl", + "2 - Warnings": "2 - Advarsler", + "3 - Information (less)": "3 - Information (mindre)", + "4 - Information (more)": "4 - Information (mere)", + "5 - information (debug)": "5 - Information (fejlsøgning)", + "Warning": "Advarsel", + "The following settings may pose a security risk, hence they are disabled by default.": "Følgende indstillinger kan udgøre en sikkerhedsrisiko, og er derfor deaktiveret som standard.", + "Enable the settings below if and only if you fully understand what they do, and the implications they may have.": "Aktiver nedenstående indstillinger HVIS OG KUN HVIS du fuldt ud forstår hvad de gør, og de implikationer og farer de kan indebære.", + "The settings will list, in their descriptions, the potential security issues they may have.": "Indstillingerne vil liste de potentielle sikkerhedsproblemer, de kan have, i deres beskrivelser.", + "The backup will include the complete list of the installed packages and their installation options. Ignored updates and skipped versions will also be saved.": "Sikkerhedskopien vil indeholde den fulde liste over de installerede pakker og deres installationsindstillinger. Ignorerede opdateringer og oversprungne versioner vil også blive gemt.", + "The backup will NOT include any binary file nor any program's saved data.": "Sikkerhedskopien vil IKKE indeholde nogle binære filer eller nogle programmers gemte data.", + "The size of the backup is estimated to be less than 1MB.": "Størrelsen af sikkerhedskopien estimeres til at være mindre end 1MB.", + "The backup will be performed after login.": "Backup vil blive udført efter login.", + "{pcName} installed packages": "{pcName} installerede pakker", + "Current status: Not logged in": "Nuværende status: Ikke logget på", + "You are logged in as {0} (@{1})": "Du er logget på som {0} (@{1})", + "Nice! Backups will be uploaded to a private gist on your account": "Rigtig godt! Backups vil blive uploadet til en privat gist på din konto", + "Select backup": "Vælg backup", + "Settings imported from {0}": "Indstillinger importeret fra {0}", + "UniGetUI Settings": "UniGetUI-indstillinger", + "Settings exported to {0}": "Indstillinger eksporteret til {0}", + "UniGetUI settings were reset": "UniGetUI-indstillinger blev nulstillet", + "Allow pre-release versions": "Tillad pre-release versioner", + "Apply": "Anvend", + "For security reasons, custom command-line arguments are disabled by default. Go to UniGetUI security settings to change this.": "Af sikkerhedsmæssige årsager er brugerdefinerede kommandolinjeargumenter deaktiveret som standard. Gå til UniGetUIs sikkerhedsindstillinger for at ændre dette.", + "Go to UniGetUI security settings": "Gå til UniGetUI sikkerhedsindstillinger", + "The following options will be applied by default each time a {0} package is installed, upgraded or uninstalled.": "Følgende muligheder vil blive anvendt som standard hver gang en {0} pakke installeres, opgraderes eller afinstalleres.", + "Package's default": "Pakkens standard", + "Install location can't be changed for {0} packages": "Installationslokation kan ikke ændres for {0} pakker", + "The local icon cache currently takes {0} MB": "Den lokale ikon-cache fylder lige nu {0} MB", + "Username": "Brugernavn", + "Password": "Adgangskode", + "Credentials": "Log-på oplysninger", + "It is not guaranteed that the provided credentials will be stored safely": "Det er ikke garanteret, at de angivne legitimationsoplysninger opbevares sikkert", + "Partially": "Delvist", + "Package manager": "Pakkemanager", + "Compatible with proxy": "Kompatibel med proxy", + "Compatible with authentication": "Kompatibel med autentificering", + "Proxy compatibility table": "Proxy kompatibilitetstabel", + "{0} settings": "{0} indstillinger", + "{0} status": "{0}-tilstand", + "Default installation options for {0} packages": "Standardinstallationsmuligheder for {0} pakker", + "Expand version": "Udvid version", + "The executable file for {0} was not found": "Den eksekverbare fil for {0} blev ikke fundet", + "{pm} is disabled": "{pm} er deaktiveret", + "Enable it to install packages from {pm}.": "Aktiver det for at installere pakker fra {pm}.", + "{pm} is enabled and ready to go": "{pm} er aktiveret og klar til brug", + "{pm} version:": "{pm} udgave:", + "{pm} was not found!": "{pm} blev ikke fundet!", + "You may need to install {pm} in order to use it with UniGetUI.": "Installation af {pm} er nødvendig, for at kunne bruge det med UniGetUI.", + "Scoop Installer - UniGetUI": "Scoop Installere - UniGetUI", + "Scoop Uninstaller - UniGetUI": "Scoop Afinstallere - UniGetUI", + "Clearing Scoop cache - UniGetUI": "Fjerner Scoop cache - UniGetUI", + "Restart UniGetUI to fully apply changes": "Genstart UniGetUI for at anvende ændringerne fuldt ud", + "Restart UniGetUI": "Genstart UniGetUI", + "Manage {0} sources": "Administrer {0} kilder", + "Add source": "Tilføj kilde", + "Add": "Tilføj", + "Source name": "Kildenavn", + "Source URL": "Kilde-URL", + "Other": "Andre", + "No minimum age": "Ingen minimumsalder", + "1 day": "1 dag", + "{0} days": "{0} dage", + "Custom...": "Brugerdefineret...", + "{0} minutes": "{0} minutter", + "1 hour": "1 time", + "{0} hours": "{0} timer", + "1 week": "1 uge", + "Supports release dates": "Understøtter udgivelsesdatoer", + "Release date support per package manager": "Understøttelse af udgivelsesdatoer pr. pakkemanager", + "Search for packages": "Søg efter pakker", + "Local": "Lokal", + "OK": "OK", + "Last checked: {0}": "Sidst tjekket: {0}", + "{0} packages were found, {1} of which match the specified filters.": "{0} pakker fundet, {1} matchede det specificerede filter.", + "{0} selected": "{0} valgt", + "(Last checked: {0})": "(Sidst tjekket: {0})", + "All packages selected": "Alle pakker valgt", + "Package selection cleared": "Pakkevalg ryddet", + "{0}: {1}": "{0}: {1}", + "More info": "Mere info", + "GitHub account": "GitHub-konto", + "Log in with GitHub to enable cloud package backup.": "Log på med GitHub for at aktivere cloud pakke backup.", + "More details": "Flere detaljer", + "Log in": "Log på", + "If you have cloud backup enabled, it will be saved as a GitHub Gist on this account": "Hvis du har cloud backup aktiveret, gemmes det som en GitHub Gist på denne konto", + "Log out": "Log af", + "About UniGetUI": "Om UniGetUI", + "About": "Om", + "Third-party licenses": "Tredjepartslicenser", + "Contributors": "Bidragydere", + "Translators": "Oversættere", + "Bundle security report": "Pakkesamlings sikkerhedsrapport", + "The bundle contained restricted content": "Samlingen indeholdt begrænset indhold", + "UniGetUI – Crash Report": "UniGetUI – Nedbrudsrapport", + "UniGetUI has crashed": "UniGetUI er gået ned", + "Help us fix this by sending a crash report to Devolutions. All fields below are optional.": "Hjælp os med at løse dette ved at sende en nedbrudsrapport til Devolutions. Alle felter nedenfor er valgfrie.", + "Email (optional)": "E-mail (valgfrit)", + "your@email.com": "din@email.com", + "Additional details (optional)": "Yderligere detaljer (valgfrit)", + "Describe what you were doing when the crash occurred…": "Beskriv hvad du lavede, da nedbruddet skete…", + "Crash report": "Nedbrudsrapport", + "Don't Send": "Send ikke", + "Send Report": "Send rapport", + "Sending…": "Sender…", + "Unsaved changes": "Ikke-gemte ændringer", + "You have unsaved changes in the current bundle. Do you want to discard them?": "Du har ikke-gemte ændringer i den aktuelle samling. Vil du kassere dem?", + "Discard changes": "Kassér ændringer", + "Integrity violation": "Integritetsbrud", + "UniGetUI or some of its components are missing or corrupt. It is strongly recommended to reinstall UniGetUI to adress the situation.": "UniGetUI eller nogle af dets komponenter mangler eller er beskadigede. Det anbefales kraftigt at geninstallere UniGetUI for at afhjælpe situationen.", + "• Refer to the UniGetUI Logs to get more details regarding the affected file(s)": "• Se UniGetUI Logs for at få flere detaljer vedrørende de berørte fil(er)", + "• Integrity checks can be disabled from the Experimental Settings": "• Integritetstjek kan deaktiveres fra Eksperimentelle Indstillinger", + "Manage shortcuts": "Administrer genveje", + "UniGetUI has detected the following desktop shortcuts which can be removed automatically on future upgrades": "UniGetUI har opdaget følgende skrivebordsgenveje, som kan fjernes automatisk ved fremtidige opgraderinger", + "Do you really want to reset this list? This action cannot be reverted.": "Ønsker du virkelig at nulstille denne liste? Handlingen kan ikke føres tilbage.", + "Desktop shortcuts list": "Liste over skrivebordsgenveje", + "Open in explorer": "Åbn i Stifinder", + "Remove from list": "Fjern fra liste", + "When new shortcuts are detected, delete them automatically instead of showing this dialog.": "Når nye genveje detekteres, skal du slette dem automatisk i stedet for at vise denne dialog.", + "Not right now": "Ikke lige nu", + "Missing dependency": "Manglende afhængighed", + "UniGetUI requires {0} to operate, but it was not found on your system.": "UniGetUI kræver {0} for at fungere, men det blev ikke fundet på dit system.", + "Click on Install to begin the installation process. If you skip the installation, UniGetUI may not work as expected.": "Klik på Installer for at starte installationsprocessen. Hvis du springer installationen over, vil UniGetUI muligvis ikke virke som forventet.", + "Alternatively, you can also install {0} by running the following command in a Windows PowerShell prompt:": "Alternative kan du også installere {0} ved at afvikle følgende kommando i en Windows PowerShell prompt:", + "Install {0}": "Installer {0}", + "Do not show this dialog again for {0}": "Vis ikke denne dialog igen for {0}", + "Please wait while {0} is being installed. A black window may show up. Please wait until it closes.": "Vent mens {0} bliver installeret. Et sort (eller blåt) vindue kan dukke up. Vent venligst på at det lukker.", + "{0} has been installed successfully.": "{0} er blevet installeret med success.", + "Please click on \"Continue\" to continue": "Klik på \"Fortsæt\" for at fortsætte", + "Continue": "Fortsæt", + "{0} has been installed successfully. It is recommended to restart UniGetUI to finish the installation": "{0} er blevet installeret med success. Det anbefales at genstarte UniGetUI for at færdiggøre installation", + "Restart later": "Genstart senere", + "An error occurred:": "Der opstod en fejl:", + "Please see the Command-line Output or refer to the Operation History for further information about the issue.": "Se Kommandolinje Output eller i Handlingshistorikken for yderligere information om dette problem.", + "Retry as administrator": "Prøv igen som administrator", + "Retry interactively": "Prøv igen som interaktiv", + "Retry skipping integrity checks": "Prøv oversprungne integritetstjek igen", + "Installation options": "Installations muligheder", + "Save": "Gem", + "UniGetUI collects anonymous usage data with the sole purpose of understanding and improving the user experience.": "UniGetUI indsamler anonyme brugsdata med det ene formåle at forstå og forbedre brugeroplevelsen.", + "More details about the shared data and how it will be processed": "Flere detaljer om delte data og hvordan det bliver behandled", + "Do you accept that UniGetUI collects and sends anonymous usage statistics, with the sole purpose of understanding and improving the user experience?": "Accepterer du, at UniGetUI indsamler og sender anonyme brugsstatistikker med det ene formål at forstå og forbedre brugeroplevelsen?", + "Decline": "Afvis", + "No personal information is collected nor sent, and the collected data is anonimized, so it can't be back-tracked to you.": "Ingen personlig information bliver indsamlet eller sendt, og den indsamlede data bliver anonymiseret, så det ikke kan spores tilbage til dig.", + "Navigation panel": "Navigationspanel", + "Operations": "Operationer", + "Toggle operations panel": "Vis/skjul handlingspanelet", + "Bulk operations": "Massehandlinger", + "Retry failed": "Prøv mislykkede igen", + "Clear successful": "Ryd vellykkede", + "Clear finished": "Ryd afsluttede", + "Cancel all": "Annuller alle", + "More": "Mere", + "Toggle navigation panel": "Vis/skjul navigationspanel", + "Minimize": "Minimer", + "Maximize": "Maksimer", + "UniGetUI by Devolutions": "UniGetUI af Devolutions", + "UniGetUI is an application that makes managing your software easier, by providing an all-in-one graphical interface for your command-line package managers.": "UniGetUI er en applikation, som gør adminstrationen af din software lettere ved at levere et alt-i-et grafisk brugergrænseflade til dine kommandolinje pakkemanagere.", + "Useful links": "Nyttige links", + "UniGetUI Homepage": "UniGetUI-hjemmeside", + "Report an issue or submit a feature request": "Rapporter et issue eller send et ønske om en ny feature", + "UniGetUI Repository": "UniGetUI-arkiv", + "View GitHub Profile": "Se GitHub Profil", + "UniGetUI License": "UniGetUI Licens", + "Using UniGetUI implies the acceptation of the MIT License": "Brug af UniGetUI betyder accept af MIT licensen", + "Become a translator": "Bidrag selv til oversættelse", + "Go back": "Gå tilbage", + "Go forward": "Gå fremad", + "Go to home page": "Gå til startsiden", + "Reload page": "Genindlæs side", + "View page on browser": "Vis side i browser", + "The built-in browser is not supported on Linux yet.": "Den indbyggede browser understøttes endnu ikke på Linux.", + "Open in browser": "Åbn i browser", + "Copy to clipboard": "Kopier til udklipsholder", + "Export to a file": "Eksporter til fil", + "Log level:": "Log-niveau:", + "Reload log": "Genindlæs log", + "Export log": "Eksporter log", + "Text": "Tekst", + "Change how operations request administrator rights": "Ændre hvordan operationer anmoder om administrator-rettigheder", + "Restrictions on package operations": "Begrænsninger på pakkeoperationer", + "Restrictions on package managers": "Begrænsninger på pakkemanagere", + "Restrictions when importing package bundles": "Begrænsninger ved import af pakkesamlinger", + "Ask for administrator privileges once for each batch of operations": "Anmod om administrator rettigheder én gang, for hver samling af operationer", + "Ask only once for administrator privileges": "Spørg kun én gang om administrator-rettigheder", + "Prohibit any kind of Elevation via UniGetUI Elevator or GSudo": "Forbyd enhver form for elevation via UniGetUI Elevator eller GSudo", + "This option WILL cause issues. Any operation incapable of elevating itself WILL FAIL. Install/update/uninstall as administrator will NOT WORK.": "Denne mulighed VIL forårsage problemer. Enhver operation, der ikke kan elevere sig selv, VIL FEJLE. Installation/opdatering/afinstallation som administrator virker IKKE.", + "Allow custom command-line arguments": "Tillad brugerdefinerede kommandolinje argumenter", + "Custom command-line arguments can change the way in which programs are installed, upgraded or uninstalled, in a way UniGetUI cannot control. Using custom command-lines can break packages. Proceed with caution.": "Brugerdefinerede kommandolinje argumenter kan ændre den måde, programmer installeres, opgraderes eller afinstalleres på, på en måde UniGetUI ikke kan kontrollere. Brug af brugerdefinerede kommandolinjer kan ødelægge pakker. Fortsæt med forsigtighed.", + "Ignore custom pre-install and post-install commands when importing packages from a bundle": "Tillad brugerdefinerede pre-install og post-install kommandoer til at blive kørt", + "Pre and post install commands will be run before and after a package gets installed, upgraded or uninstalled. Be aware that they may break things unless used carefully": "Pre- og post-install kommandoer vil blive kørt før og efter en pakke installeres, opgraderes eller afinstalleres. Vær opmærksom på, at de kan ødelægge ting, medmindre de bruges med forsigtighed", + "Allow changing the paths for package manager executables": "Tillad ændring af stier for pakkemanager programmer", + "Turning this on enables changing the executable file used to interact with package managers. While this allows finer-grained customization of your install processes, it may also be dangerous": "Hvis du slår dette til, kan du ændre den eksekverbare fil, der bruges til at interagere med pakkemanagere. Selvom dette giver mulighed for mere finkornet tilpasning af dine installationsprocesser, kan det også være farligt", + "Allow importing custom command-line arguments when importing packages from a bundle": "Tillad import af brugerdefinerede kommandolinje argumenter når pakker importeres fra en samling", + "Malformed command-line arguments can break packages, or even allow a malicious actor to gain privileged execution. Therefore, importing custom command-line arguments is disabled by default": "Malformerede kommandolinje argumenter kan ødelægge pakker, eller endda tillade en ondsindet aktør at få privilegeret udførelse. Derfor er import af brugerdefinerede kommandolinje argumenter deaktiveret som standard.", + "Allow importing custom pre-install and post-install commands when importing packages from a bundle": "Tillad import af brugerdefinerede pre-install og post-install kommandoer når pakker importeres fra en samling", + "Pre and post install commands can do very nasty things to your device, if designed to do so. It can be very dangerous to import the commands from a bundle, unless you trust the source of that package bundle": "Pre- og post-install kommandoer kan gøre meget uhyggelige ting med din enhed, hvis de er designet til det. Det kan være meget farligt at importere kommandoerne fra en samling, medmindre du stoler på kilden til denne pakkesamling", + "Administrator rights and other dangerous settings": "Administrator-rettigheder og andre farlige indstillinger", + "Package backup": "Pakkebackup", + "Cloud package backup": "Cloud pakke backup", + "Local package backup": "Lokal pakke backup", + "Local backup advanced options": "Avancerede muligheder for lokal backup", + "Log in with GitHub": "Log på med GitHub", + "Log out from GitHub": "Log af fra GitHub", + "Periodically perform a cloud backup of the installed packages": "Udfør periodisk en cloud backup af installerede pakker", + "Cloud backup uses a private GitHub Gist to store a list of installed packages": "Cloud backup bruger en privat GitHub Gist til at gemme en liste over installerede pakker", + "Perform a cloud backup now": "Udfør en cloud backup nu", + "Backup": "Sikkerhedskopi", + "Restore a backup from the cloud": "Gendan en backup fra skyen", + "Begin the process to select a cloud backup and review which packages to restore": "Begynd processen til at vælge en cloud backup og gennemse hvilke pakker der skal gendannes", + "Periodically perform a local backup of the installed packages": "Udfør periodisk en lokal backup af installerede pakker", + "Perform a local backup now": "Udfør en lokal backup nu", + "Change backup output directory": "Ændre mappe for backup filer", + "Set a custom backup file name": "Vælg backup filnavn", + "Leave empty for default": "Efterlad blankt for standardindstilling", + "Add a timestamp to the backup file names": "Tilføj tidsstempel til backup filnavne", + "Backup and Restore": "Backup og Gendannelse", + "Enable background api (UniGetUI Widgets and Sharing, port 7058)": "Aktiver baggrunds-API (Widgets til UniGetUI og Deling, port 7058)", + "Wait for the device to be connected to the internet before attempting to do tasks that require internet connectivity.": "Vent på, at enheden er forbundet til internettet, før der forsøges på at gøre noget, som kræver internetforbindelse.", + "Disable the 1-minute timeout for package-related operations": "Deaktiver 1-minuts timeout for pakkerelaterede operationer", + "Use installed GSudo instead of UniGetUI Elevator": "Brug installeret GSudo i stedet for UniGetUI Elevator", + "Use a custom icon and screenshot database URL": "Brug brugerdefineret ikon og screenshot database URL", + "Enable background CPU Usage optimizations (see Pull Request #3278)": "Aktiver baggrunds CPU-brug optimeringer (se Pull Request #3278)", + "Perform integrity checks at startup": "Udfør integritetstjek ved opstart", + "When batch installing packages from a bundle, install also packages that are already installed": "Ved batch installation af pakker fra en samling, installer også pakker, der allerede er installeret", + "Experimental settings and developer options": "Eksperimentelle indstillinger samt udviklerindstillinger", + "Show UniGetUI's version and build number on the titlebar.": "Vis UniGetUI's version på titellinjen", + "Language": "Sprog", + "UniGetUI updater": "UniGetUI opdaterer", + "Telemetry": "Telemetri", + "Manage UniGetUI settings": "Administrer UniGetUI indstillinger", + "Related settings": "Relaterede indstillinger", + "Update UniGetUI automatically": "Opdatér UniGetUI automatisk", + "Check for updates": "Søg efter opdateringer", + "Install prerelease versions of UniGetUI": "Installer præ-release versioner af UniGetUI", + "Manage telemetry settings": "Administrer telemetriindstillinger", + "Manage": "Administrer", + "Import settings from a local file": "Importer indstillinger fra fil", + "Import": "Importer", + "Export settings to a local file": "Eksporter indstillinger til en fil", + "Export": "Eksporter", + "Reset UniGetUI": "Nulstil UniGetUI", + "User interface preferences": "Brugerflade indstillinger", + "Application theme, startup page, package icons, clear successful installs automatically": "Applikationstema, startside, pakkeikoner, fjern successfulde installationer automatisk", + "General preferences": "Generelle indstillinger", + "UniGetUI display language:": "UniGetUI Sprog", + "System language": "Systemsprog", + "Is your language missing or incomplete?": "Mangler dit sprog (helt eller delvist)?", + "Appearance": "Udseende", + "UniGetUI on the background and system tray": "UniGetUI i baggrunden og systembakken", + "Package lists": "Pakkelister", + "Use classic mode": "Brug klassisk tilstand", + "Restart UniGetUI to apply this change": "Genstart UniGetUI for at anvende denne ændring", + "The classic UI is disabled for beta testers": "Den klassiske brugerflade er deaktiveret for betatestere", + "Close UniGetUI to the system tray": "Luk UniGetUI til systembakken", + "Manage UniGetUI autostart behaviour": "Administrer UniGetUIs autostartadfærd", + "Show package icons on package lists": "Vis pakkeikoner på pakkelister", + "Clear cache": "Tøm cache", + "Select upgradable packages by default": "Vælg opgraderbare pakker som standard", + "Light": "Lys", + "Dark": "Mørk", + "Follow system color scheme": "Følg styresystemets farvetema", + "Application theme:": "Program udseende:", + "UniGetUI startup page:": "UniGetUI startside:", + "Proxy settings": "Proxy indstillinger", + "Other settings": "Andre indstillinger", + "Connect the internet using a custom proxy": "Forbind internettet ved hjælp af en brugerdefineret proxy", + "Please note that not all package managers may fully support this feature": "Bemærk, at ikke alle pakkemanagere fuldt ud kan understøtte denne funktion", + "Proxy URL": "Proxy-URL", + "Enter proxy URL here": "Indtast proxy URL her", + "Authenticate to the proxy with a user and a password": "Autentificer over for proxyen med et brugernavn og en adgangskode", + "Internet and proxy settings": "Internet- og proxyindstillinger", + "Package manager preferences": "Pakkemanager indstillinger", + "Ready": "Klar", + "Not found": "Ikke fundet", + "Notification preferences": "Notifikationspræferencer", + "Notification types": "Notifikationstyper", + "The system tray icon must be enabled in order for notifications to work": "Systemtray ikonen skal aktiveres for at notifikationer fungerer", + "Enable UniGetUI notifications": "Aktiver UniGetUI notifikationer", + "Show a notification when there are available updates": "Vis notifikation når der er tilgængelige opdateringer", + "Show a silent notification when an operation is running": "Vis en lydløs notifikation når en handling kører", + "Show a notification when an operation fails": "Vis en notifikation når en handling mislykkes", + "Show a notification when an operation finishes successfully": "Vis en notifikation når en handling gennemføres med success", + "Concurrency and execution": "Samtidighed og udførelse", + "Automatic desktop shortcut remover": "Automatisk skrivebordsgenvej-fjerner", + "Choose how many operations should be performed in parallel": "Vælg, hvor mange handlinger der skal udføres parallelt", + "Clear successful operations from the operation list after a 5 second delay": "Fjern succesfulde operationer fra operationslisten med 5 sekunders forsinkelse", + "Download operations are not affected by this setting": "Download-operationer påvirkes ikke af denne indstilling", + "You may lose unsaved data": "Du mister muligvis ikke-gemte data", + "Ask to delete desktop shortcuts created during an install or upgrade.": "Spørg om at slette skrivebordsgenveje oprettet under en installation eller opgradering.", + "Package update preferences": "Pakke opdaterings præferencer", + "Update check frequency, automatically install updates, etc.": "Opdateringstjek frekvens, installer opdateringer automatisk osv.", + "Reduce UAC prompts, elevate installations by default, unlock certain dangerous features, etc.": "Reducér UAC prompte, elevér installationer som standard, lås visse farlige funktioner op osv.", + "Package operation preferences": "Pakkeoperations præferencer", + "Enable {pm}": "Aktiver {pm}", + "Not finding the file you are looking for? Make sure it has been added to path.": "Finder du ikke den fil, du leder efter? Sørg for, at den er blevet tilføjet til sti.", + "Select the executable to be used. The following list shows the executables found by UniGetUI": "Vælg den eksekverbare fil der skal bruges. Følgende liste viser de eksekverbare filer fundet af UniGetUI", + "For security reasons, changing the executable file is disabled by default": "Af sikkerhedsmæssige årsager er ændring af den eksekverbare fil deaktiveret som standard", + "Change this": "Ændre dette", + "Copy path": "Kopiér sti", + "Current executable file:": "Aktuel eksekverbar fil:", + "Ignore packages from {pm} when showing a notification about updates": "Ignorer pakker fra {pm} når der vises en notifikation om opdateringer", + "Update security": "Opdateringssikkerhed", + "Use global setting": "Brug global indstilling", + "Minimum age for updates": "Minimumsalder for opdateringer", + "e.g. 10": "f.eks. 10", + "Custom minimum age (days)": "Brugerdefineret minimumsalder (dage)", + "{pm} does not provide release dates for its packages, so this setting will have no effect": "{pm} angiver ikke udgivelsesdatoer for sine pakker, så denne indstilling har ingen effekt", + "{pm} only provides release dates for some of its packages, so this setting will only apply to those packages": "{pm} angiver kun udgivelsesdatoer for nogle af sine pakker, så denne indstilling gælder kun for disse pakker", + "Override the global minimum update age for this package manager": "Tilsidesæt den globale minimumsalder for opdateringer for denne pakkemanager", + "View {0} logs": "Vis {0} logfiler", + "If Python cannot be found or is not listing packages but is installed on the system, ": "Hvis Python ikke kan findes eller ikke viser pakker, men er installeret på systemet, ", + "Advanced options": "Avancerede muligheder", + "WinGet command-line tool": "WinGet-kommandolinjeværktøj", + "Choose which command-line tool UniGetUI uses for WinGet operations when the COM API is not used": "Vælg hvilket kommandolinjeværktøj UniGetUI bruger til WinGet-handlinger, når COM API'en ikke bruges", + "WinGet COM API": "WinGet COM API", + "Choose whether UniGetUI can use the WinGet COM API before falling back to the command-line tool": "Vælg om UniGetUI kan bruge WinGet COM API'en, før der faldes tilbage til kommandolinjeværktøjet", + "Reset WinGet": "Nulstil WinGet", + "This may help if no packages are listed": "Det kan hjælpe, hvis der ikke listes nogle pakker", + "Force install location parameter when updating packages with custom locations": "Tving installationslokations parameter når du opdaterer pakker med brugerdefinerede lokationer", + "Install Scoop": "Installer Scoop", + "Uninstall Scoop (and its packages)": "Afinstaller Scoop (og dets pakker)", + "Run cleanup and clear cache": "Kør oprydning og ryd cache", + "Run": "Kør", + "Enable Scoop cleanup on launch": "Aktiver Scoop-oprydning ved programstart", + "Default vcpkg triplet": "Standard vcpkg triplet", + "Change vcpkg root location": "Skift vcpkg-rodplacering", + "Reset vcpkg root location": "Nulstil vcpkg-rodplacering", + "Open vcpkg root location": "Åbn vcpkg-rodplacering", + "Language, theme and other miscellaneous preferences": "Sprog, tema og forskellige andre indstillinger", + "Show notifications on different events": "Vis notifikationer ved forskellige hændelser", + "Change how UniGetUI checks and installs available updates for your packages": "Bestem hvordan UniGetUI søger efter og installerer tilgængelige opdateringer for dine pakker", + "Automatically save a list of all your installed packages to easily restore them.": "Gem automatisk en liste af dine installerede pakker til genoprettelse.", + "Enable and disable package managers, change default install options, etc.": "Aktivér og deaktivér pakkemanagere, ændre standardinstallationsmuligheder osv.", + "Internet connection settings": "Internetforbindelsesindstillinger", + "Proxy settings, etc.": "Proxy indstillinger osv.", + "Beta features and other options that shouldn't be touched": "Beta funktionaliteter og andre indstillinger der ikke burde røres", + "Reload sources": "Genindlæs kilder", + "Delete source": "Slet kilde", + "Known sources": "Kendte kilder", + "Update checking": "Opdateringstjek", + "Automatic updates": "Automatiske opdateringer", + "Check for package updates periodically": "Søg efter pakke opdateringer periodisk", + "Check for updates every:": "Søg efter opdateringer hver:", + "Install available updates automatically": "Installer tilgængelige opdateringer automatisk", + "Do not automatically install updates when the network connection is metered": "Installer ikke automatisk opdateringer når netværksforbindelsen er målt", + "Do not automatically install updates when the device runs on battery": "Installer ikke automatisk opdateringer når enheden kører på batteri", + "Do not automatically install updates when the battery saver is on": "Installer ikke automatisk opdateringer når batteribesparelse er tændt", + "Only show updates that are at least the specified number of days old": "Vis kun opdateringer, der er mindst det angivne antal dage gamle", + "Warn me when the installer URL host changes between the installed version and the new version (WinGet only)": "Advar mig, når værten for installationsprogrammets URL ændres mellem den installerede version og den nye version (kun WinGet)", + "Change how UniGetUI handles install, update and uninstall operations.": "Ændre hvordan UniGetUI håndterer installations-, opdaterings- og afinstallationsoperationer.", + "Navigation": "Navigering", + "Check for UniGetUI updates": "Søg efter UniGetUI-opdateringer", + "Quit UniGetUI": "Afslut UniGetUI", + "Filters": "Filtre", + "Sources": "Kilder", + "Search for packages to start": "Søg efter pakker for at komme i gang", + "Select all": "Vælg alle", + "Clear selection": "Ryd markeringer", + "Instant search": "Øjeblikkelig søgning", + "Distinguish between uppercase and lowercase": "Forskel på store- & små bogstaver", + "Ignore special characters": "Ignorer særlige bogstaver/tegn", + "Search mode": "Søge tilstand", + "Both": "Begge", + "Exact match": "Nøjagtigt match", + "Show similar packages": "Vis lignende pakker", + "Loading": "Indlæser", + "Package": "Pakke", + "More options": "Flere muligheder", + "Order by:": "Sortering:", + "Name": "Navn", + "Id": "ID", + "Ascendant": "Stigende", + "Descendant": "Faldende", + "View modes": "Visningstilstande", + "Reload": "Genindlæs", + "Closed": "Lukket", + "Ascending": "Stigende", + "Descending": "Faldende", + "{0}: {1}, {2}": "{0}: {1}, {2}", + "Order by": "Sortér efter", + "No results were found matching the input criteria": "Ingen resultater fundet der opfylder valgte kriterier", + "No packages were found": "Ingen pakker blev fundet", + "Loading packages": "Indlæser pakker", + "Skip integrity checks": "Spring integritetstjeks over", + "Download selected installers": "Download valgte installationsprogrammer", + "Install selection": "Installer valgte", + "Install options": "Installationsmuligheder", + "Add selection to bundle": "Tilføj til samling", + "Download installer": "Download installationsprogram", + "Uninstall selection": "Afinstallationsvalg", + "Uninstall options": "Afinstallationsmuligheder", + "Ignore selected packages": "Ignorer valgte pakker", + "Open install location": "Åbn installationslokation", + "Reinstall package": "Geninstaller pakke", + "Uninstall package, then reinstall it": "Afinstaller valgte pakke, og så geninstaller den", + "Ignore updates for this package": "Ignorer opdateringer for denne pakke", + "WinGet malfunction detected": "WinGet-fejl fundet", + "It looks like WinGet is not working properly. Do you want to attempt to repair WinGet?": "Det ser ud til, at WinGet ikke fungerer ordentligt. Ønsker du at forsøge at reparere WinGet?", + "Repair WinGet": "Reparer WinGet", + "Updates will no longer be ignored for {0}": "Opdateringer vil ikke længere blive ignoreret for {0}", + "Updates are now ignored for {0}": "Opdateringer ignoreres nu for {0}", + "Do not ignore updates for this package anymore": "Ignorer ikke opdateringer for denne pakke mere", + "Add packages or open an existing package bundle": "Tilføj pakker eller åben en eksisterende pakke samling", + "Add packages to start": "Tilføj pakker til start", + "The current bundle has no packages. Add some packages to get started": "Den nuværende samling har ikke nogle pakker. Tilføj nogle pakker for at komme i gang", + "New": "Ny", + "Save as": "Gem som", + "Create .ps1 script": "Opret .ps1 script", + "Remove selection from bundle": "Fjern valgte fra samling", + "Skip hash checks": "Spring hash-tjeks over", + "The package bundle is not valid": "Pakkesamlingen er ikke gyldig", + "The bundle you are trying to load appears to be invalid. Please check the file and try again.": "Samlingen, du prøver at indlæse, ser ud til at være ugyldig. Tjek filen og prøv igen.", + "Package bundle": "Pakke samling", + "Could not create bundle": "Kunne ikke oprette samlingen", + "The package bundle could not be created due to an error.": "Pakkesamlingen kunne ikke oprettes på grund af en fejl.", + "Install script": "Installationsscript", + "PowerShell script": "PowerShell-script", + "The installation script saved to {0}": "Installationscriptet gemmet på {0}", + "An error occurred": "Der skete en fejl", + "An error occurred while attempting to create an installation script:": "Der opstod en fejl under forsøget på at oprette et installationsscript:", + "Hooray! No updates were found.": "Ingen opdateringer fundet.", + "Uninstall selected packages": "Afinstaller valgte pakker", + "Update selection": "Opdateringsvalg", + "Update options": "Opdateringsmuligheder", + "Uninstall package, then update it": "Afinstaller valgte pakke, og så opdater den (hvordan fungere det?)", + "Uninstall package": "Afinstaller pakke", + "Skip this version": "Spring denne version over", + "Pause updates for": "Pausér opdateringer for", + "User | Local": "Bruger | Lokal", + "Machine | Global": "Maskine | Global", + "The default package manager for Debian/Ubuntu-based Linux distributions.
Contains: Debian/Ubuntu packages": "Standardpakkehåndteringen til Debian/Ubuntu-baserede Linux-distributioner.
Indeholder: Debian/Ubuntu-pakker", + "The Rust package manager.
Contains: Rust libraries and programs written in Rust": "Rust pakkemanageren.
Indeholder: Rust biblioteker og programmer skrevet i Rust", + "The classical package manager for windows. You'll find everything there.
Contains: General Software": "Windows' egen Pakkemanager, hvor du kan finde det meste.
Indeholder:Generel software", + "The default package manager for RHEL/Fedora-based Linux distributions.
Contains: RPM packages": "Standardpakkehåndteringen til RHEL/Fedora-baserede Linux-distributioner.
Indeholder: RPM-pakker", + "A repository full of tools and executables designed with Microsoft's .NET ecosystem in mind.
Contains: .NET related tools and scripts": "En samling af værktøjer og programmer til brug i Microsoft's .NET økosystem.
Indeholder .NET relaterede værktøjer og scripts", + "The universal Linux package manager for desktop applications.
Contains: Flatpak applications from configured remotes": "Den universelle Linux-pakkemanager til skrivebordsprogrammer.
Indeholder: Flatpak-programmer fra konfigurerede fjernkilder", + "NuPkg (zipped manifest)": "NuPkg (zippet manifest)", + "The Missing Package Manager for macOS (or Linux).
Contains: Formulae, Casks": "Den manglende pakkemanager til macOS (eller Linux).
Indeholder: Formulae, Casks", + "Node JS's package manager. Full of libraries and other utilities that orbit the javascript world
Contains: Node javascript libraries and other related utilities": "Node JS's pakkemanager. Fuld af biblioteker og andre værktøjer, som omkranser Javascript verdenen
Indeholder: Node Javascript biblioteker og andre relaterede værktøjer", + "The default package manager for Arch Linux and its derivatives.
Contains: Arch Linux packages": "Standardpakkehåndteringen til Arch Linux og dets derivater.
Indeholder: Arch Linux-pakker", + "Python's library manager. Full of python libraries and other python-related utilities
Contains: Python libraries and related utilities": "Python's biblioteksmanager. Fuld af python biblioteker og andre pythonrelaterede værktøjer
Indeholder: Python biblioteker og andre relaterede værktøjer", + "PowerShell's package manager. Find libraries and scripts to expand PowerShell capabilities
Contains: Modules, Scripts, Cmdlets": "PowerShell's pakkemanager. Find biblioteker og scripts til at udvide mulighederne i PowerShell
Indeholder: Moduler, Scripts, Cmdlets", + "extracted": "pakket ud", + "Scoop package": "Scoop pakke", + "Great repository of unknown but useful utilities and other interesting packages.
Contains: Utilities, Command-line programs, General Software (extras bucket required)": "Fantastisk lager af ukendte, men brugbare værktøjer og andre interessante pakker.
Indeholder: Værktøjer, Kommandolinje programmer. Gemerel software (ekstra samling påkrævet)", + "The universal Linux package manager by Canonical.
Contains: Snap packages from the Snapcraft store": "Den universelle Linux-pakkehåndtering fra Canonical.
Indeholder: Snap-pakker fra Snapcraft-butikken", + "library": "bibliotek", + "feature": "funktion", + "A popular C/C++ library manager. Full of C/C++ libraries and other C/C++-related utilities
Contains: C/C++ libraries and related utilities": "En populær C/C++ biblioteksmanager. Fuld af C/C++ biblioteker og andre C/C++ relaterede værktøjer
Indeholder: C/C++ biblioteker og relaterede værktøjer", + "option": "indstilling", + "This package cannot be installed from an elevated context.": "Denne pakke kan ikke installeres fra en kontekst med forhøjede rettigheder.", + "Please run UniGetUI as a regular user and try again.": "Kør UniGetUI som almindelig bruger og prøv igen.", + "Please check the installation options for this package and try again": "Kontroller installationsindstillingerne for denne pakke og prøv igen", + "Microsoft's official package manager. Full of well-known and verified packages
Contains: General Software, Microsoft Store apps": "Microsofts officielle pakkemanager. Fuld af velkendte og verificerede pakker
Indeholder: Generel software, Microsoft Store apps", + "Local PC": "Lokal PC", + "Android Subsystem": "Android-undersystem", + "Operation on queue (position {0})...": "Handling er i kø (position {0})...", + "Click here for more details": "Klik her for yderligere detaljer", + "Operation canceled by user": "Handlingen blev annulleret af bruger", + "Running PreOperation ({0}/{1})...": "Kører PreOperation ({0}/{1})...", + "PreOperation {0} out of {1} failed, and was tagged as necessary. Aborting...": "PreOperation {0} ud af {1} mislykkedes og var markeret som nødvendig. Afbryder...", + "PreOperation {0} out of {1} finished with result {2}": "PreOperation {0} ud af {1} blev afsluttet med resultatet {2}", + "Starting operation...": "Starter handling...", + "Running PostOperation ({0}/{1})...": "Kører PostOperation ({0}/{1})...", + "PostOperation {0} out of {1} failed, and was tagged as necessary. Aborting...": "PostOperation {0} ud af {1} mislykkedes og var markeret som nødvendig. Afbryder...", + "PostOperation {0} out of {1} finished with result {2}": "PostOperation {0} ud af {1} blev afsluttet med resultatet {2}", + "{package} installer download": "{package} installationsprogram download", + "{0} installer is being downloaded": "{0} installationsprogram bliver downloaded", + "Download succeeded": "Download lykkedes", + "{package} installer was downloaded successfully": "{package} installationsprogram blev downloaded med success", + "Download failed": "Download mislykkedes", + "{package} installer could not be downloaded": "{package} installationsprogram kunne ikke downloades", + "{package} Installation": "{package} installation", + "{0} is being installed": "{0} bliver installeret", + "Installation succeeded": "Installation gennemført", + "{package} was installed successfully": "Installation af {package} gennemført", + "Installation failed": "Installation fejlede", + "{package} could not be installed": "{package} kunne ikke installeres", + "{package} Update": "{package} opdatering", + "Update succeeded": "Opdatering gennemført", + "{package} was updated successfully": "{package} opdatering gennemført", + "Update failed": "Opdatering fejlet", + "{package} could not be updated": "{package} kunne ikke opdateres", + "{package} Uninstall": "{package} afinstallation", + "{0} is being uninstalled": "{0} bliver afinstalleret", + "Uninstall succeeded": "Afinstallation gennemført", + "{package} was uninstalled successfully": "Afinstallation af {package} gennemført", + "Uninstall failed": "Afinstallering fejlede", + "{package} could not be uninstalled": "{package} kunne ikke afinstalleres", + "Adding source {source}": "Tilføjer kilden {source}", + "Adding source {source} to {manager}": "Tilføjer kilde {source} til {manager}", + "Source added successfully": "Kilde blev tilføjet med success", + "The source {source} was added to {manager} successfully": "Kilden {source} blev tilføjet til {manager} med success", + "Could not add source": "Kunne ikke tilføje kilde", + "Could not add source {source} to {manager}": "Kunne ikke tilføje kilde {source} til {manager}", + "Removing source {source}": "Fjerner kilde {source}", + "Removing source {source} from {manager}": "Fjerner kilde {source} fra {manager}", + "Source removed successfully": "Kilden blev fjernet med success", + "The source {source} was removed from {manager} successfully": "Kilden {source} blev fjernet fra {manager} med success", + "Could not remove source": "Kunne ikke fjerne kilde", + "Could not remove source {source} from {manager}": "Kunne ikke fjerne kilde {source} fra {manager}", + "The package manager \"{0}\" was not found": "Pakkemanageren \"{0}\" blev ikke fundet", + "The package manager \"{0}\" is disabled": "Pakkemanageren \"{0}\" er deaktiveret", + "There is an error with the configuration of the package manager \"{0}\"": "Der er en fejl i konfigurationen af pakkemanageren \"{0}\"", + "The package \"{0}\" was not found on the package manager \"{1}\"": "Pakken \"{0}\" blev ikke fundet via pakkemanager \"{1}\"", + "{0} is disabled": "{0} er slået fra", + "{0} weeks": "{0} uger", + "1 month": "1 måned", + "{0} months": "{0} måneder", + "Something went wrong": "Noget gik galt", + "An interal error occurred. Please view the log for further details.": "En intern fejl opstod. Se i loggen for flere detaljer.", + "No applicable installer was found for the package {0}": "Der blev ikke fundet noget relevant installationsprogram til pakken {0}", + "Integrity checks will not be performed during this operation": "Integritetstjek vil ikke blive udført under denne operation", + "This is not recommended.": "Dette er ikke anbefalet.", + "Run now": "Kør nu", + "Run next": "Kør næste", + "Run last": "Kør sidste", + "Show in explorer": "Vis i stifinder", + "Checked": "Markeret", + "Unchecked": "Ikke markeret", + "This package is already installed": "Denne pakke er allerede installeret", + "This package can be upgraded to version {0}": "Denne pakke kan opgraderes til version {0}", + "Updates for this package are ignored": "Opdateringer til denne pakker bliver ignoreret", + "This package is being processed": "Denne pakke bliver behandlet", + "This package is not available": "Denne pakke er ikke tilgængelig", + "Select the source you want to add:": "Vælg kilden du vil tilføje:", + "Source name:": "Kilde navn:", + "Source URL:": "Kilde URL:", + "An error occurred when adding the source: ": "Der skete en fejl under tilføjelsen af kilden:", + "Package management made easy": "Pakkeadministration gjort let", + "version {0}": "udgave {0}", + "[RAN AS ADMINISTRATOR]": "KØRTE SOM ADMINISTRATOR", + "Portable mode": "Portabel tilstand\n", + "DEBUG BUILD": "DEBUG-BUILD", + "Here you can change UniGetUI's behaviour regarding the following shortcuts. Checking a shortcut will make UniGetUI delete it if if gets created on a future upgrade. Unchecking it will keep the shortcut intact": "Her kan du ændre UniGetUI's opførsel vedrørende følgende genveje. Markering af en genvej vil få UniGetUI til at slette den, hvis den oprettes under en fremtidig opgradering. Afmarkering af den vil beholde genvejen.", + "Manual scan": "Manuel scanning", + "Existing shortcuts on your desktop will be scanned, and you will need to pick which ones to keep and which ones to remove.": "Eksisterende genveje på dit skrivebord vil blive scannet, og du vil være nødt til at vælge hvilke, der skal beholdes og hvilke, der skal fjernes.", + "Delete?": "Slet?", + "I understand": "Accepter", + "Chocolatey setup changed": "Chocolatey-opsætning ændret", + "UniGetUI no longer includes its own private Chocolatey installation. A legacy UniGetUI-managed Chocolatey installation was detected for this user profile, but system Chocolatey was not found. Chocolatey will stay unavailable in UniGetUI until Chocolatey is installed on the system and UniGetUI is restarted. Applications previously installed through UniGetUI's bundled Chocolatey may still appear under other sources such as Local PC or WinGet.": "UniGetUI inkluderer ikke længere sin egen private Chocolatey-installation. En ældre UniGetUI-administreret Chocolatey-installation blev fundet for denne brugerprofil, men system-Chocolatey blev ikke fundet. Chocolatey vil forblive utilgængelig i UniGetUI, indtil Chocolatey er installeret på systemet, og UniGetUI genstartes. Programmer, der tidligere er installeret via UniGetUI's medfølgende Chocolatey, kan stadig vises under andre kilder som Lokal PC eller WinGet.", + "NOTE: This troubleshooter can be disabled from UniGetUI Settings, on the WinGet section": "BEMÆRK: Denne problemløser kan deaktiveres fra UniGetUI Indstillinger i WinGet sektionen", + "Restart": "Genstart", + "Are you sure you want to delete all shortcuts?": "Er du sikker på, du vil slette alle genveje?", + "Any new shorcuts created during an install or an update operation will be deleted automatically, instead of showing a confirmation prompt the first time they are detected.": "Nye genveje oprettet under en installations- eller opdateringsoperation vil blive slettet automatisk i stedet for at bede om bekræftelse første gang, de bliver detekteret.", + "Any shorcuts created or modified outside of UniGetUI will be ignored. You will be able to add them via the {0} button.": "Genveje oprettet eller ændret uden for UniGetUI vil blive ignoreret. Du kan tilføje dem via {0} knappen.", + "Are you really sure you want to enable this feature?": "Er du virkelig sikker på, du ønsker at aktivere denne funktion?", + "No new shortcuts were found during the scan.": "Ingen nye genveje blev fundet under scanningstiden.", + "How to add packages to a bundle": "Hvordan tilføjes pakker til en samling", + "In order to add packages to a bundle, you will need to: ": "For at føje pakker til en samling, er du nødt til:", + "1. Navigate to the \"{0}\" or \"{1}\" page.": "1. Naviger til \"{0}\" eller \"{1}\" siden.", + "2. Locate the package(s) you want to add to the bundle, and select their leftmost checkbox.": "2. Lokaliser de(n) pakke(r), du ønsker at tilføje til samlingen og vælg checkboksen længst til venstre.", + "3. When the packages you want to add to the bundle are selected, find and click the option \"{0}\" on the toolbar.": "3. Når pakkerne, du ønsker at tilføje til samlingen, er valgt, finder du indstillingen \"{0}\" på værktøjslinjen og klikker på den.", + "4. Your packages will have been added to the bundle. You can continue adding packages, or export the bundle.": "4. Dine pakker vil være tilføjet til samlingen. Du kan fortsætte med at tilføje pakker eller eksportere samlingen.", + "Which backup do you want to open?": "Hvilken backup ønsker du at åbne?", + "Select the backup you want to open. Later, you will be able to review which packages you want to install.": "Vælg den backup, du vil åbne. Senere vil du kunne gennemse hvilke pakker du vil installere.", + "There are ongoing operations. Quitting UniGetUI may cause them to fail. Do you want to continue?": "Der er igangværende handlinger. Afslutning af UniGetUI kan betyde, at de mislykkes. Ønsker du at fortsætte?", + "UniGetUI or some of its components are missing or corrupt.": "UniGetUI eller nogle af dets komponenter mangler eller er beskadigede.", + "It is strongly recommended to reinstall UniGetUI to adress the situation.": "Det anbefales stærkt at geninstallere UniGetUI for at løse situationen.", + "Refer to the UniGetUI Logs to get more details regarding the affected file(s)": "Se UniGetUI Logs for at få flere detaljer vedrørende de berørte fil(er)", + "Integrity checks can be disabled from the Experimental Settings": "Integritetstjek kan deaktiveres fra Eksperimentelle Indstillinger", + "Repair UniGetUI": "Reparer UniGetUI", + "Live output": "Live-output", + "This package bundle had some settings that are potentially dangerous, and may be ignored by default.": "Denne pakkesamling havde nogle indstillinger, der er potentielt farlige, og kan blive ignoreret som standard.", + "Entries that show in YELLOW will be IGNORED.": "Indlæg der vises i GUL vil blive IGNORERET.", + "Entries that show in RED will be IMPORTED.": "Indlæg der vises i RØD vil blive IMPORTERET.", + "You can change this behavior on UniGetUI security settings.": "Du kan ændre denne opførsel i UniGetUI sikkerhedsindstillinger.", + "Open UniGetUI security settings": "Åbn UniGetUI sikkerhedsindstillinger", + "Should you modify the security settings, you will need to open the bundle again for the changes to take effect.": "Hvis du ændrer sikkerhedsindstillingerne, skal du åbne samlingen igen, for at ændringerne træder i kraft.", + "Details of the report:": "Detaljer om rapporten:", + "Are you sure you want to create a new package bundle? ": "Er du sikker på, at du vil oprette en ny pakkesamling?", + "Any unsaved changes will be lost": "Alle ikke-gemte ændringer vil blive mistet.", + "Warning!": "Advarsel!", + "For security reasons, custom command-line arguments are disabled by default. Go to UniGetUI security settings to change this. ": "Af sikkerhedsmæssige årsager er brugerdefinerede kommandolinje argumenter deaktiveret som standard. Gå til UniGetUI sikkerhedsindstillinger for at ændre dette. ", + "Change default options": "Ændre standardmuligheder", + "Ignore future updates for this package": "Ignorer fremtidige opdateringer til denne pakke", + "For security reasons, pre-operation and post-operation scripts are disabled by default. Go to UniGetUI security settings to change this. ": "Af sikkerhedsmæssige årsager er pre-operation og post-operation scripts deaktiveret som standard. Gå til UniGetUI sikkerhedsindstillinger for at ændre dette. ", + "You can define the commands that will be run before or after this package is installed, updated or uninstalled. They will be run on a command prompt, so CMD scripts will work here.": "Du kan definere de kommandoer, der vil blive kørt før eller efter denne pakke installeres, opdateres eller afinstalleres. De køres på en kommandoprompt, så CMD-scripts virker her.", + "Change this and unlock": "Ændre dette og lås op", + "{0} Install options are currently locked because {0} follows the default install options.": "{0} Installationsmuligheder er i øjeblikket låste, fordi {0} følger standardinstallationsmulighederne.", + "Unset or unknown": "Ikke angivet eller ukendt", + "This package has no screenshots or is missing the icon? Contrbute to UniGetUI by adding the missing icons and screenshots to our open, public database.": "Denne pakke har ingen skærmbilleder eller mangler ikonet? Bidrag til UniGetUI ved at tilføje manglende ikoner og skærmbilleder til vores åbne, offentlige database.", + "Become a contributor": "Bidrag selv til udviklingen", + "Update to {0} available": "Opdatering til {0} tilgængelig", + "Reinstall": "Geninstaller", + "Installer not available": "Installationsprogram er ikke tilgængeligt", + "Version:": "Udgave:", + "UniGetUI Version {0}": "UniGetUI version {0}", + "Performing backup, please wait...": "Laver backup, vent venligst...", + "An error occurred while logging in: ": "Der opstod en fejl under login: ", + "Fetching available backups...": "Henter tilgængelige backups...", + "Done!": "Færdig!", + "The cloud backup has been loaded successfully.": "Cloud backuppen er blevet indlæst med succes.", + "An error occurred while loading a backup: ": "Der opstod en fejl under indlæsning af en sikkerhedskopi: ", + "Backing up packages to GitHub Gist...": "Laver backup af pakker til GitHub Gist...", + "Backup Successful": "Backup vellykket", + "The cloud backup completed successfully.": "Cloud backuppen blev gennemført med succes.", + "Could not back up packages to GitHub Gist: ": "Kunne ikke lave backup af pakker til GitHub Gist: ", + "It is not guaranteed that the provided credentials will be stored safely, so you may as well not use the credentials of your bank account": "Det er ikke garanteret, at de leverede legitimationsoplysninger bliver gemt sikkert, så du kan lige så godt ikke bruge legitimationsoplysningerne fra din bankkonto", + "Enable the automatic WinGet troubleshooter": "Aktiver den automatiske WinGet problemløser", + "Add updates that fail with a 'no applicable update found' to the ignored updates list": "Tilføj opdateringer, som mislykkes med en 'ingen relevante opdateriinger fundet' til listen over ignorerede opdateringer", + "Invalid selection": "Ugyldigt valg", + "No package was selected": "Ingen pakke blev valgt", + "More than 1 package was selected": "Mere end 1 pakke blev valgt", + "List": "Listevisning", + "Grid": "Gittervisning", + "Icons": "Ikoner", + "\"{0}\" is a local package and does not have available details": "\"{0}\" er en lokal pakke og har ikke tilgængelige detaljer", + "\"{0}\" is a local package and is not compatible with this feature": "\"{0}\" er en lokal pakke og er ikke kompatibel med denne funktion", + "Add packages to bundle": "Tilføj pakker til samling", + "Preparing packages, please wait...": "Klargøre pakker, vent venligst...", + "Loading packages, please wait...": "Indlæser pakker, vent venligst...", + "Saving packages, please wait...": "Gemmer pakker, vent venligst...", + "The bundle was created successfully on {0}": "Samlingen blev skabt med succes på {0}", + "User profile": "Brugerprofil", + "Error": "Fejl", + "Log in failed: ": "Login fejlede: ", + "Log out failed: ": "Logoff fejlede: ", + "Package backup settings": "Pakke backup indstillinger", + "Manage UniGetUI autostart behaviour from the Settings app": "Administrer UniGetUI's autostartadfærd", + "Choose how many operations shoulds be performed in parallel": "Vælg hvor mange handlinger der skal udføres parallelt", + "Something went wrong while launching the updater.": "Noget gik galt ved afviklingen af opdateringen.", + "Please try again later": "Prøv igen senere", + "Show the release notes after UniGetUI is updated": "Vis releasenotes efter UniGetUI er opdateret" +} diff --git a/src/Languages/lang_de.json b/src/Languages/lang_de.json new file mode 100644 index 0000000..666c0cf --- /dev/null +++ b/src/Languages/lang_de.json @@ -0,0 +1,850 @@ +{ + "{0} of {1} operations completed": "{0} von {1} Vorgängen abgeschlossen", + "{0} is now {1}": "{0} ist jetzt {1}", + "Enabled": "Aktiviert", + "Disabled": "Deaktiviert", + "Privacy": "Datenschutz", + "Hide my username from the logs": "Meinen Benutzernamen in den Protokollen ausblenden", + "Replaces your username with **** in the logs. Restart UniGetUI to also hide it from already-recorded entries.": "Ersetzt Ihren Benutzernamen in den Protokollen durch ****. Starten Sie UniGetUI neu, um ihn auch in bereits aufgezeichneten Einträgen auszublenden.", + "Your last update attempt did not complete.": "Ihr letzter Aktualisierungsversuch wurde nicht abgeschlossen.", + "UniGetUI could not confirm whether the update succeeded. Open the log to see what happened.": "UniGetUI konnte nicht bestätigen, ob das Update erfolgreich war. Öffnen Sie das Protokoll, um zu sehen, was passiert ist.", + "View log": "Protokoll anzeigen", + "The installer reported success but did not restart UniGetUI.": "Das Installationsprogramm hat Erfolg gemeldet, UniGetUI jedoch nicht neu gestartet.", + "The installer failed to initialize.": "Das Installationsprogramm konnte nicht initialisiert werden.", + "Setup was canceled before installation began.": "Setup wurde abgebrochen, bevor die Installation begann.", + "A fatal error occurred during the preparation phase.": "Während der Vorbereitungsphase ist ein schwerwiegender Fehler aufgetreten.", + "A fatal error occurred during installation.": "Während der Installation ist ein schwerwiegender Fehler aufgetreten.", + "Installation was canceled while in progress.": "Die Installation wurde während der Ausführung abgebrochen.", + "The installer was terminated by another process.": "Das Installationsprogramm wurde von einem anderen Prozess beendet.", + "The preparation phase determined the installation cannot proceed.": "Die Vorbereitungsphase hat festgestellt, dass die Installation nicht fortgesetzt werden kann.", + "The installer could not start. UniGetUI may already be running, or you do not have permission to install.": "Das Installationsprogramm konnte nicht gestartet werden. UniGetUI wird möglicherweise bereits ausgeführt oder Sie haben keine Berechtigung zur Installation.", + "Unexpected installer error.": "Unerwarteter Fehler des Installationsprogramms.", + "We are checking for updates.": "Es wird nach Updates gesucht.", + "Please wait": "Bitte warten", + "Great! You are on the latest version.": "Sehr gut! Sie haben die neueste Version.", + "There are no new UniGetUI versions to be installed": "Es sind keine neueren Versionen von UniGetUI verfügbar.", + "UniGetUI version {0} is being downloaded.": "UniGetUI-Version {0} wird heruntergeladen.", + "This may take a minute or two": "Dies kann ein oder zwei Minuten dauern.", + "The installer authenticity could not be verified.": "Die Echtheit der Installationsdatei konnte nicht überprüft werden.", + "The update process has been aborted.": "Der Update-Vorgang wurde abgebrochen.", + "Auto-update is not yet available on this platform.": "Automatische Updates sind auf dieser Plattform noch nicht verfügbar.", + "Please update UniGetUI manually.": "Bitte aktualisieren Sie UniGetUI manuell.", + "An error occurred when checking for updates: ": "Ein Fehler ist aufgetreten beim Überprüfen von Updates:", + "The updater could not be launched.": "Der Updater konnte nicht gestartet werden.", + "The operating system did not start the installer process.": "Das Betriebssystem hat den Installationsprozess nicht gestartet.", + "UniGetUI is being updated...": "UniGetUI wird aktualisiert...", + "Update installed.": "Update installiert.", + "UniGetUI was updated successfully, but this running copy was not replaced. This usually means you are running a development build. Close this copy and start the newly-installed version to finish.": "UniGetUI wurde erfolgreich aktualisiert, aber diese laufende Kopie wurde nicht ersetzt. Dies bedeutet in der Regel, dass Sie einen Entwicklungsbuild ausführen. Schließen Sie diese Kopie und starten Sie die neu installierte Version, um den Vorgang abzuschließen.", + "The update could not be applied.": "Das Update konnte nicht angewendet werden.", + "Installer exit code {0}: {1}": "Exitcode des Installationsprogramms {0}: {1}", + "Update cancelled.": "Update abgebrochen.", + "Authentication was cancelled.": "Authentifizierung wurde abgebrochen.", + "Installer exit code {0}": "Exitcode des Installationsprogramms {0}", + "Operation in progress": "Vorgang läuft", + "Please wait...": "Bitte warten...", + "Success!": "Fertig!", + "Failed": "Fehlgeschlagen", + "An error occurred while processing this package": "Fehler beim Verarbeiten des Pakets", + "Installer": "Installationsprogramm", + "Executable": "Ausführbare Datei", + "MSI": "MSI", + "Compressed file": "Komprimierte Datei", + "MSIX": "MSIX", + "WinGet was repaired successfully": "WinGet wurde erfolgreich repariert", + "It is recommended to restart UniGetUI after WinGet has been repaired": "Es wird empfohlen, UniGetUI nach der Reparatur von WinGet neu zu starten", + "WinGet could not be repaired": "WinGet konnte nicht repariert werden", + "An unexpected issue occurred while attempting to repair WinGet. Please try again later": "Beim Versuch, WinGet zu reparieren, ist ein unerwartetes Problem aufgetreten. Bitte versuchen Sie es später erneut", + "Log in to enable cloud backup": "Anmelden, um die Cloud-Sicherung zu aktivieren", + "Backup Failed": "Sicherung fehlgeschlagen", + "Downloading backup...": "Sicherung wird heruntergeladen...", + "An update was found!": "Ein Update wurde gefunden!", + "{0} can be updated to version {1}": "{0} kann auf Version {1} aktualisiert werden", + "Updates found!": "Updates gefunden!", + "{0} packages can be updated": "{0} Pakete können aktualisiert werden", + "{0} is being updated to version {1}": "{0} wird auf Version {1} aktualisiert", + "{0} packages are being updated": "{0} Pakete werden aktualisiert", + "You have currently version {0} installed": "Sie haben aktuell die Version {0} installiert", + "Desktop shortcut created": "Desktopverknüpfung angelegt", + "UniGetUI has detected a new desktop shortcut that can be deleted automatically.": "UniGetUI hat eine automatisch entfernbare Desktopverknüpfung gefunden.", + "{0} desktop shortcuts created": "{0} Desktopverknüpfungen angelegt", + "UniGetUI has detected {0} new desktop shortcuts that can be deleted automatically.": "UniGetUI hat {0} automatisch entfernbare Desktopverknüpfungen gefunden.", + "Attention required": "Aufmerksamkeit erforderlich", + "Restart required": "Neustart erforderlich", + "1 update is available": "1 Update verfügbar", + "{0} updates are available": "{0} Updates verfügbar", + "Everything is up to date": "Alles ist auf dem neuesten Stand", + "Discover Packages": "Pakete suchen", + "Available Updates": "Verfügbare Updates", + "Installed Packages": "Installierte Pakete", + "UniGetUI Version {0} by Devolutions": "UniGetUI Version {0} von Devolutions", + "Show UniGetUI": "UniGetUI anzeigen", + "Quit": "Beenden", + "Are you sure?": "Sind Sie sich sicher?", + "Do you really want to uninstall {0}?": "Möchten Sie wirklich {0} deinstallieren?", + "Do you really want to uninstall the following {0} packages?": "Möchten Sie wirklich die folgenden {0} Pakete deinstallieren?", + "No": "Nein", + "Yes": "Ja", + "Partial": "Teilweise", + "View on UniGetUI": "Auf UniGetUI ansehen", + "Update": "Aktualisieren", + "Open UniGetUI": "UniGetUI öffnen", + "Update all": "Alles aktualisieren", + "Update now": "Jetzt aktualisieren", + "Installer host changed since the installed version.\n": "Der Host des Installationsprogramms hat sich seit der installierten Version geändert.\n", + "This package is on the queue": "Dieses Paket befindet sich in der Warteschlange", + "installing": "installiere", + "updating": "aktualisiere", + "uninstalling": "deinstallieren", + "installed": "installiert", + "Retry": "Erneut versuchen", + "Install": "Installieren", + "Uninstall": "Deinstallieren", + "Open": "Öffnen", + "Operation profile:": "Vorgangsprofil:", + "Follow the default options when installing, upgrading or uninstalling this package": "Die Standardoptionen verwenden, wenn dieses Paket installiert, aktualisiert oder deinstalliert wird.", + "The following settings will be applied each time this package is installed, updated or removed.": "Die folgenden Einstellungen werden jedes Mal angewendet, wenn dieses Paket installiert, aktualisiert oder entfernt wird.", + "Version to install:": "Zu installierende Version:", + "Architecture to install:": "Zu installierende Architektur:", + "Installation scope:": "Installationsumgebung:", + "Install location:": "Installationsort:", + "Select": "Auswählen", + "Reset": "Zurücksetzen", + "Custom install arguments:": "Benutzerdefinierte Installationsargumente:", + "Custom update arguments:": "Benutzerdefinierte Aktualisierungsargumente:", + "Custom uninstall arguments:": "Benutzerdefinierte Deinstallationsargumente:", + "Pre-install command:": "Befehl vor der Installation:", + "Post-install command:": "Befehl nach der Installation:", + "Abort install if pre-install command fails": "Installation abbrechen, falls der Vorinstallationsbefehl fehlschlägt", + "Pre-update command:": "Befehl vor der Aktualisierung:", + "Post-update command:": "Befehl nach der Aktualisierung:", + "Abort update if pre-update command fails": "Aktualisierung abbrechen, wenn der Voraktualisierungsbefehl fehlschlägt", + "Pre-uninstall command:": "Befehl vor der Deinstallation:", + "Post-uninstall command:": "Befehl nach der Deinstallation:", + "Abort uninstall if pre-uninstall command fails": "Deinstallation abbrechen, wenn der Vorinstallationsbefehl fehlschlägt", + "Command-line to run:": "Auszuführende Befehlszeile:", + "Save and close": "Speichern und schließen", + "General": "Allgemein", + "Architecture & Location": "Architektur & Speicherort", + "Command-line": "Befehlszeile", + "Close apps": "Apps schließen", + "Pre/Post install": "Vor-/Nachinstallation", + "Select the processes that should be closed before this package is installed, updated or uninstalled.": "Wählen Sie die Prozesse aus, die geschlossen werden sollen, bevor dieses Paket installiert, aktualisiert oder deinstalliert wird.", + "Write here the process names here, separated by commas (,)": "Geben Sie hier die Prozessnamen ein, getrennt durch Kommas (,)", + "Try to kill the processes that refuse to close when requested to": "Prozesse nach Möglichkeit zwangsweise beenden, wenn sie sich nicht ordnungsgemäß schließen lassen.", + "Run as admin": "Als Administrator ausführen", + "Interactive installation": "Interaktiv installieren", + "Skip hash check": "Hash-Prüfung überspringen", + "Uninstall previous versions when updated": "Frühere Versionen nach der Aktualisierung deinstallieren", + "Skip minor updates for this package": "Kleinere Updates für dieses Paket überspringen", + "Automatically update this package": "Dieses Paket automatisch aktualisieren", + "{0} installation options": "Installationsoptionen für {0}", + "Latest": "Neueste", + "PreRelease": "Vorabversion", + "Default": "Standard", + "Manage ignored updates": "Ignorierte Updates verwalten", + "The packages listed here won't be taken in account when checking for updates. Double-click them or click the button on their right to stop ignoring their updates.": "Die hier aufgeführten Pakete werden bei der Suche nach Updates nicht berücksichtigt. Doppelklicken Sie auf die Updates oder klicken Sie auf die Schaltfläche rechts neben ihnen, um ihre Updates nicht mehr zu ignorieren.", + "Reset list": "Liste zurücksetzen", + "Do you really want to reset the ignored updates list? This action cannot be reverted": "Möchten Sie die Liste der ignorierten Updates wirklich zurücksetzen? Diese Aktion kann nicht rückgängig gemacht werden", + "No ignored updates": "Keine ignorierten Updates", + "Package Name": "Paketname", + "Package ID": "Paket-ID", + "Ignored version": "Ignorierte Version", + "New version": "Neue Version", + "Source": "Quelle", + "All versions": "Alle Versionen", + "Unknown": "Unbekannt", + "Up to date": "Aktuell", + "Package {name} from {manager}": "Paket {name} von {manager}", + "Remove {0} from ignored updates": "{0} von ignorierten Updates entfernen", + "Cancel": "Abbrechen", + "Administrator privileges": "Administratorrechte", + "This operation is running with administrator privileges.": "Dieser Vorgang wird mit Administratorrechten ausgeführt.", + "Interactive operation": "Interaktiver Vorgang", + "This operation is running interactively.": "Dieser Vorgang wird interaktiv durchgeführt.", + "You will likely need to interact with the installer.": "Sie werden wahrscheinlich mit der Installation interagieren müssen.", + "Integrity checks skipped": "Integritätsüberprüfungen übersprungen", + "Integrity checks will not be performed during this operation.": "Während dieses Vorgangs werden keine Integritätsprüfungen durchgeführt.", + "Proceed at your own risk.": "Fortfahren auf eigenes Risiko", + "Close": "Schließen", + "Loading...": "Laden...", + "Installer SHA256": "Installations-SHA256", + "Homepage": "Startseite", + "Author": "Autor", + "Publisher": "Herausgeber", + "License": "Lizenz", + "Manifest": "Manifest", + "Installer Type": "Installations-Typ", + "Size": "Größe", + "Installer URL": "Installations-URL", + "Last updated:": "Zuletzt aktualisiert:", + "Release notes URL": "Versionshinweise-URL", + "Package details": "Paketdetails", + "Dependencies:": "Abhängigkeiten:", + "Release notes": "Versionshinweise", + "Screenshots": "Bildschirmfotos", + "This package has no screenshots or is missing the icon? Contribute to UniGetUI by adding the missing icons and screenshots to our open, public database.": "Dieses Paket hat keine Screenshots oder es fehlt das Symbol? Unterstützen Sie UniGetUI, indem Sie die fehlenden Symbole und Screenshots zu unserer offenen, öffentlichen Datenbank hinzufügen.", + "Version": "Version", + "Install as administrator": "Als Administrator installieren", + "Update to version {0}": "Update auf Version {0}", + "Installed Version": "Installierte Version:", + "Update as administrator": "Als Administrator aktualisieren", + "Interactive update": "Interaktiv aktualisieren", + "Uninstall as administrator": "Als Administrator deinstallieren", + "Interactive uninstall": "Interaktiv deinstallieren", + "Uninstall and remove data": "Deinstallieren und Daten entfernen", + "Not available": "Nicht verfügbar", + "Installer SHA512": "Installations-SHA512", + "Unknown size": "Unbekannte Größe", + "No dependencies specified": "Keine Abhängigkeiten angegeben", + "mandatory": "obligatorisch", + "optional": "optional", + "UniGetUI {0} is ready to be installed.": "UniGetUI-Version {0} ist bereit zur Installation.", + "The update process will start after closing UniGetUI": "Das Update wird nach dem Beenden von UniGetUI durchgeführt.", + "UniGetUI has been ran as administrator, which is not recommended. When running UniGetUI as administrator, EVERY operation launched from UniGetUI will have administrator privileges. You can still use the program, but we highly recommend not running UniGetUI with administrator privileges.": "UniGetUI wurde als Administrator ausgeführt, was nicht empfohlen wird. Wenn UniGetUI als Administrator ausgeführt wird, wird JEDER von UniGetUI gestartete Vorgang mit Administratorrechten ausgeführt. Sie können das Programm weiterhin verwenden, wir empfehlen jedoch dringend, UniGetUI nicht mit Administratorrechten auszuführen.", + "Share anonymous usage data": "Anonyme Nutzungsdaten teilen", + "UniGetUI collects anonymous usage data in order to improve the user experience.": "UniGetUI sammelt anonyme Nutzungsdaten, um die Nutzererfahrung zu verbessern.", + "Accept": "Akzeptieren", + "Software Updates": "Software-Updates", + "Package Bundles": "Paketbündel", + "Settings": "Einstellungen", + "Package Managers": "Paketmanager", + "UniGetUI Log": "UniGetUI-Protokoll", + "Package Manager logs": "Paketmanager-Protokolle", + "Operation history": "Vorgangsverlauf", + "Help": "Hilfe", + "UniGetUI": "UniGetUI", + "You have installed UniGetUI Version {0}": "Sie haben die UniGetUI-Version {0} installiert.", + "Disclaimer": "Haftungsausschluss", + "UniGetUI is developed by Devolutions and is not affiliated with any of the compatible package managers.": "UniGetUI wird von Devolutions entwickelt und steht in keiner Verbindung zu einem der kompatiblen Paketmanager.", + "UniGetUI wouldn't have been possible without the help of the contributors. Thank you all 🥳": "UniGetUI wäre ohne die Hilfe der Mitwirkenden nicht möglich gewesen. Vielen Dank an alle 🥳", + "UniGetUI uses the following libraries. Without them, UniGetUI wouldn't have been possible.": "UniGetUI verwendet die folgenden Bibliotheken, ohne die UniGetUI nicht realisierbar gewesen wäre.", + "{0} homepage": "{0} Homepage", + "UniGetUI has been translated to more than 40 languages thanks to the volunteer translators. Thank you 🤝": "UniGetUI wurde dank freiwilliger Übersetzer in mehr als 40 Sprachen übersetzt. Vielen Dank 🤝", + "Verbose": "Verbose", + "1 - Errors": "1 – Fehler", + "2 - Warnings": "2 – Warnungen", + "3 - Information (less)": "3 – Informationen (weniger)", + "4 - Information (more)": "4 – Informationen (mehr)", + "5 - information (debug)": "5 – Informationen (Debug)", + "Warning": "Warnung", + "The following settings may pose a security risk, hence they are disabled by default.": "Die folgenden Einstellungen können ein Sicherheitsrisiko darstellen und sind daher standardmäßig deaktiviert.", + "Enable the settings below if and only if you fully understand what they do, and the implications they may have.": "Aktivieren Sie die nachstehenden Einstellungen nur, WENN UND NUR WENN Sie sich über deren Funktion und die damit verbundenen Auswirkungen und Gefahren im Klaren sind.", + "The settings will list, in their descriptions, the potential security issues they may have.": "In den Beschreibungen der Einstellungen werden deren potenzielle Sicherheitsprobleme aufgeführt.", + "The backup will include the complete list of the installed packages and their installation options. Ignored updates and skipped versions will also be saved.": "Die Sicherung enthält eine vollständige Liste der installierten Pakete und deren Installationsoptionen. Ignorierte Updates und übersprungene Versionen werden ebenfalls gesichert.", + "The backup will NOT include any binary file nor any program's saved data.": "Die Sicherung enthält keine ausführbaren Dateien oder Programmdaten.", + "The size of the backup is estimated to be less than 1MB.": "Die voraussichtliche Größe der Sicherung beträgt weniger als 1 MB.", + "The backup will be performed after login.": "Die Sicherung wird nach der Anmeldung ausgeführt.", + "{pcName} installed packages": "{pcName} installierte Pakete", + "Current status: Not logged in": "Aktueller Status: Nicht angemeldet", + "You are logged in as {0} (@{1})": "Sie sind angemeldet als {0} (@{1})", + "Nice! Backups will be uploaded to a private gist on your account": "Super! Die Sicherungen werden in einen privaten Gist auf Ihrem Konto hochgeladen", + "Select backup": "Sicherung auswählen", + "Settings imported from {0}": "Einstellungen importiert von {0}", + "UniGetUI Settings": "UniGetUI-Einstellungen", + "Settings exported to {0}": "Einstellungen exportiert nach {0}", + "UniGetUI settings were reset": "UniGetUI-Einstellungen wurden zurückgesetzt", + "Allow pre-release versions": "Vorabversionen zulassen", + "Apply": "Anwenden", + "For security reasons, custom command-line arguments are disabled by default. Go to UniGetUI security settings to change this.": "Aus Sicherheitsgründen sind benutzerdefinierte Befehlszeilenargumente standardmäßig deaktiviert. Gehen Sie zu den UniGetUI-Sicherheitseinstellungen, um dies zu ändern.", + "Go to UniGetUI security settings": "Zu den UniGetUI-Sicherheitseinstellungen gehen", + "The following options will be applied by default each time a {0} package is installed, upgraded or uninstalled.": "Die folgenden Optionen werden standardmäßig angewendet, wenn ein {0}-Paket installiert, aktualisiert oder deinstalliert wird.", + "Package's default": "Standardeinstellung des Pakets", + "Install location can't be changed for {0} packages": "Der Installationsort kann für {0} Pakete nicht geändert werden", + "The local icon cache currently takes {0} MB": "Der lokale Symbol-Cache belegt zur Zeit {0} MB", + "Username": "Benutzername", + "Password": "Passwort", + "Credentials": "Anmeldedaten", + "It is not guaranteed that the provided credentials will be stored safely": "Es kann nicht garantiert werden, dass die angegebenen Anmeldedaten sicher gespeichert werden", + "Partially": "Teilweise", + "Package manager": "Paketmanager", + "Compatible with proxy": "Kompatibel mit Proxy", + "Compatible with authentication": "Kompatibel mit Authentifizierung", + "Proxy compatibility table": "Proxy-Kompatibilitätstabelle", + "{0} settings": "{0}-Einstellungen", + "{0} status": "{0}-Status", + "Default installation options for {0} packages": "Standardinstallationsoptionen für {0}-Pakete", + "Expand version": "Version erweitern", + "The executable file for {0} was not found": "Die ausführbare Datei für {0} wurde nicht gefunden.", + "{pm} is disabled": "{pm} ist deaktiviert", + "Enable it to install packages from {pm}.": "Aktivieren, um Pakete von {pm} zu installieren.", + "{pm} is enabled and ready to go": "{pm} ist aktiviert und bereit", + "{pm} version:": "{pm}-Version:", + "{pm} was not found!": "{pm} wurde nicht gefunden", + "You may need to install {pm} in order to use it with UniGetUI.": "Sie müssen möglicherweise {pm} installieren, um es mit UniGetUI verwenden zu können.", + "Scoop Installer - UniGetUI": "Scoop-Installer – UniGetUI", + "Scoop Uninstaller - UniGetUI": "Scoop-Uninstaller – UniGetUI", + "Clearing Scoop cache - UniGetUI": "Scoop-Cache leeren – UniGetUI", + "Restart UniGetUI to fully apply changes": "Starten Sie UniGetUI neu, um die Änderungen vollständig anzuwenden", + "Restart UniGetUI": "UniGetUI neu starten", + "Manage {0} sources": "{0}-Quellen verwalten", + "Add source": "Quelle hinzufügen", + "Add": "Hinzufügen", + "Source name": "Quellenname", + "Source URL": "Quell-URL", + "Other": "Andere", + "No minimum age": "Kein Mindestalter", + "1 day": "1 Tag", + "{0} days": "{0} Tage", + "Custom...": "Benutzerdefiniert...", + "{0} minutes": "{0} Minuten", + "1 hour": "1 Stunde", + "{0} hours": "{0} Stunden", + "1 week": "1 Woche", + "Supports release dates": "Unterstützt Veröffentlichungsdaten", + "Release date support per package manager": "Unterstützung von Veröffentlichungsdaten pro Paketmanager", + "Search for packages": "Nach Paketen suchen", + "Local": "Lokal", + "OK": "OK", + "Last checked: {0}": "Zuletzt überprüft: {0}", + "{0} packages were found, {1} of which match the specified filters.": "Es wurden {0} Pakete gefunden, von denen {1} den festgelegten Filtern entsprechen.", + "{0} selected": "{0} ausgewählt", + "(Last checked: {0})": "(Letzte Überprüfung: {0})", + "All packages selected": "Alle Pakete ausgewählt", + "Package selection cleared": "Paketauswahl aufgehoben", + "{0}: {1}": "{0}: {1}", + "More info": "Mehr Infos", + "GitHub account": "GitHub-Konto", + "Log in with GitHub to enable cloud package backup.": "Bei GitHub anmelden, um die Cloud-Paketsicherung zu aktivieren.", + "More details": "Mehr Details", + "Log in": "Anmelden", + "If you have cloud backup enabled, it will be saved as a GitHub Gist on this account": "Wenn Sie die Cloud-Sicherung aktiviert haben, wird sie als GitHub Gist auf diesem Konto gespeichert", + "Log out": "Abmelden", + "About UniGetUI": "Über UniGetUI", + "About": "Über", + "Third-party licenses": "Drittanbieterlizenzen", + "Contributors": "Mitwirkende", + "Translators": "Übersetzer", + "Bundle security report": "Bündel-Sicherheitsbericht", + "The bundle contained restricted content": "Das Bündel enthielt eingeschränkte Inhalte", + "UniGetUI – Crash Report": "UniGetUI – Absturzbericht", + "UniGetUI has crashed": "UniGetUI ist abgestürzt", + "Help us fix this by sending a crash report to Devolutions. All fields below are optional.": "Helfen Sie uns, dieses Problem zu beheben, indem Sie einen Absturzbericht an Devolutions senden. Alle untenstehenden Felder sind optional.", + "Email (optional)": "E-Mail (optional)", + "your@email.com": "ihre@email.de", + "Additional details (optional)": "Zusätzliche Details (optional)", + "Describe what you were doing when the crash occurred…": "Beschreiben Sie, was Sie getan haben, als der Absturz aufgetreten ist…", + "Crash report": "Absturzbericht", + "Don't Send": "Nicht senden", + "Send Report": "Bericht senden", + "Sending…": "Wird gesendet…", + "Unsaved changes": "Nicht gespeicherte Änderungen", + "You have unsaved changes in the current bundle. Do you want to discard them?": "Sie haben nicht gespeicherte Änderungen im aktuellen Bündel. Möchten Sie sie verwerfen?", + "Discard changes": "Änderungen verwerfen", + "Integrity violation": "Integritätsverletzung", + "UniGetUI or some of its components are missing or corrupt. It is strongly recommended to reinstall UniGetUI to adress the situation.": "UniGetUI oder einige seiner Komponenten fehlen oder sind beschädigt. Es wird dringend empfohlen, UniGetUI neu zu installieren, um das Problem zu beheben.", + "• Refer to the UniGetUI Logs to get more details regarding the affected file(s)": "• Weitere Informationen zu den betroffenen Dateien finden Sie in den UniGetUI-Protokollen.", + "• Integrity checks can be disabled from the Experimental Settings": "• Integritätsprüfungen können in den experimentellen Einstellungen deaktiviert werden.", + "Manage shortcuts": "Verknüpfungen verwalten", + "UniGetUI has detected the following desktop shortcuts which can be removed automatically on future upgrades": "UniGetUI hat folgende Desktopverknüpfungen gefunden, die beim nächsten Update automatisch entfernt werden können", + "Do you really want to reset this list? This action cannot be reverted.": "Möchten Sie wirklich diese Liste zurücksetzen? Diese Aktion kann nicht rückgängig getan werden.", + "Desktop shortcuts list": "Desktop-Verknüpfungsliste", + "Open in explorer": "Im Explorer öffnen", + "Remove from list": "Aus der Liste entfernen", + "When new shortcuts are detected, delete them automatically instead of showing this dialog.": "Wenn neue Verknüpfungen erkannt werden, diese automatisch löschen, anstatt diesen Dialog anzuzeigen.", + "Not right now": "Momentan nicht", + "Missing dependency": "Fehlende Abhängigkeit", + "UniGetUI requires {0} to operate, but it was not found on your system.": "UniGetUI benötigt {0}, es konnte aber auf Ihrem System nicht gefunden werden.", + "Click on Install to begin the installation process. If you skip the installation, UniGetUI may not work as expected.": "Klicken Sie auf Installieren, um den Installationsprozess zu starten. Wenn Sie die Installation überspringen, funktioniert UniGetUI möglicherweise nicht wie erwartet.", + "Alternatively, you can also install {0} by running the following command in a Windows PowerShell prompt:": "Alternativ können Sie auch {0} mit dem Ausführen des folgenden Befehls in einer Windows PowerShell-Eingabeaufforderung installieren:", + "Install {0}": "{0} installieren", + "Do not show this dialog again for {0}": "Diesen Dialog für {0} nicht mehr anzeigen", + "Please wait while {0} is being installed. A black window may show up. Please wait until it closes.": "Bitte warten, während {0} installiert wird. Möglicherweise erscheint ein schwarzes Fenster. Bitte warten Sie, bis es sich schließt.", + "{0} has been installed successfully.": "{0} wurde erfolgreich installiert.", + "Please click on \"Continue\" to continue": "Bitte klicken Sie auf „Weiter“, um fortzufahren", + "Continue": "Weiter", + "{0} has been installed successfully. It is recommended to restart UniGetUI to finish the installation": "{0} wurde erfolgreich installiert. Es wird empfohlen, UniGetUI neu zu starten, um die Installation abzuschließen.", + "Restart later": "Später neu starten", + "An error occurred:": "Ein Fehler ist aufgetreten:", + "Please see the Command-line Output or refer to the Operation History for further information about the issue.": "Bitte prüfen Sie die Kommandozeilen-Ausgabe oder schauen Sie im Vorgangsverlauf nach, um weitere Informationen über den Fehler zu erhalten.", + "Retry as administrator": "Erneut als Administrator versuchen", + "Retry interactively": "Interaktiv erneut versuchen", + "Retry skipping integrity checks": "Erneut versuchen und dabei Integritätsprüfungen überspringen", + "Installation options": "Installationsoptionen", + "Save": "Speichern", + "UniGetUI collects anonymous usage data with the sole purpose of understanding and improving the user experience.": "UniGetUI sammelt anonyme Nutzungsdaten mit dem alleinigen Ziel, das Nutzererlebnis zu verstehen und zu verbessern.", + "More details about the shared data and how it will be processed": "Mehr Details über die geteilten Daten und wie sie verarbeitet werden", + "Do you accept that UniGetUI collects and sends anonymous usage statistics, with the sole purpose of understanding and improving the user experience?": "Sind Sie damit einverstanden, dass UniGetUI anonyme Nutzungsstatistiken sammelt und übermittelt, mit dem alleinigen Zweck, die Nutzererfahrung zu verstehen und zu verbessern?", + "Decline": "Ablehnen", + "No personal information is collected nor sent, and the collected data is anonimized, so it can't be back-tracked to you.": "Persönliche Daten werden weder gesammelt noch gesendet, und die gesammelten Daten sind anonymisiert, sodass sie nicht zu Ihnen zurückverfolgt werden können.", + "Navigation panel": "Navigationsbereich", + "Operations": "Vorgänge", + "Toggle operations panel": "Vorgangsbereich ein-/ausblenden", + "Bulk operations": "Massenvorgänge", + "Retry failed": "Fehlgeschlagene erneut versuchen", + "Clear successful": "Erfolgreiche entfernen", + "Clear finished": "Abgeschlossene entfernen", + "Cancel all": "Alle abbrechen", + "More": "Mehr", + "Toggle navigation panel": "Navigationsbereich umschalten", + "Minimize": "Minimieren", + "Maximize": "Maximieren", + "UniGetUI by Devolutions": "UniGetUI von Devolutions", + "UniGetUI is an application that makes managing your software easier, by providing an all-in-one graphical interface for your command-line package managers.": "UniGetUI ist eine Anwendung, die das Verwalten Ihrer Software vereinfacht, indem sie eine vollumfängliche Oberfläche für Ihre Kommandozeilen-Paketmanager bereitstellt.", + "Useful links": "Nützliche Links", + "UniGetUI Homepage": "UniGetUI-Homepage", + "Report an issue or submit a feature request": "Ein Problem melden oder eine Funktionsanfrage stellen", + "UniGetUI Repository": "UniGetUI-Repository", + "View GitHub Profile": "GitHub-Profil öffnen", + "UniGetUI License": "UniGetUI-Lizenz", + "Using UniGetUI implies the acceptation of the MIT License": "Die Verwendung von UniGetUI impliziert die Zustimmung zur MIT-Lizenz", + "Become a translator": "Werden Sie Übersetzer", + "Go back": "Zurück", + "Go forward": "Vorwärts", + "Go to home page": "Zur Startseite", + "Reload page": "Seite neu laden", + "View page on browser": "Seite im Browser öffnen", + "The built-in browser is not supported on Linux yet.": "Der integrierte Browser wird unter Linux noch nicht unterstützt.", + "Open in browser": "Im Browser öffnen", + "Copy to clipboard": "In Zwischenablage kopieren", + "Export to a file": "Als Datei exportieren", + "Log level:": "Protokollebene:", + "Reload log": "Protokoll neu laden", + "Export log": "Protokoll exportieren", + "Text": "Text", + "Change how operations request administrator rights": "Festlegen, wie Vorgänge Administratorrechte anfordern", + "Restrictions on package operations": "Beschränkungen für Paketvorgänge", + "Restrictions on package managers": "Beschränkungen für Paketmanager", + "Restrictions when importing package bundles": "Beschränkungen beim Import von Paketbündeln", + "Ask for administrator privileges once for each batch of operations": "Nur einmal nach Administratorrechten für jeden Stapel von Vorgängen fragen", + "Ask only once for administrator privileges": "Nur einmal nach Administratorrechten fragen", + "Prohibit any kind of Elevation via UniGetUI Elevator or GSudo": "Jede Art von Berechtigungserhöhung über UniGetUI-Elevator oder GSudo verbieten", + "This option WILL cause issues. Any operation incapable of elevating itself WILL FAIL. Install/update/uninstall as administrator will NOT WORK.": "Diese Option WIRD Probleme verursachen. Jeder Vorgang, der nicht in der Lage ist, sich selbst zu erhöhen, WIRD FEHLSCHLAGEN. Installieren/Aktualisieren/Deinstallieren als Administrator wird NICHT FUNKTIONIEREN.", + "Allow custom command-line arguments": "Benutzerdefinierte Befehlszeilenargumente zulassen", + "Custom command-line arguments can change the way in which programs are installed, upgraded or uninstalled, in a way UniGetUI cannot control. Using custom command-lines can break packages. Proceed with caution.": "Benutzerdefinierte Befehlszeilenargumente können die Art und Weise ändern, wie Programme installiert, aktualisiert oder deinstalliert werden, und zwar in einer Weise, die UniGetUI nicht kontrollieren kann. Die Verwendung benutzerdefinierter Befehlszeilen kann Pakete beschädigen. Gehen Sie daher mit Vorsicht vor.", + "Ignore custom pre-install and post-install commands when importing packages from a bundle": "Benutzerdefinierte Vor- und Nachinstallationsbefehle beim Importieren von Paketen aus einem Bündel ignorieren", + "Pre and post install commands will be run before and after a package gets installed, upgraded or uninstalled. Be aware that they may break things unless used carefully": "Vor und Nachinstallationsbefehle werden vor und nach der Installation, Aktualisierung oder Deinstallation eines Pakets ausgeführt. Beachten Sie, dass sie zu Problemen führen können, wenn sie nicht sorgfältig verwendet werden.", + "Allow changing the paths for package manager executables": "Ändern der Pfade für ausführbare Dateien des Paketmanagers zulassen", + "Turning this on enables changing the executable file used to interact with package managers. While this allows finer-grained customization of your install processes, it may also be dangerous": "Wenn Sie diese Option aktivieren, können Sie die ausführbare Datei ändern, die zur Interaktion mit Paketmanagern verwendet wird. Dies ermöglicht eine feinere Anpassung Ihrer Installationsprozesse, kann jedoch sicherheitsgefährdend sein.", + "Allow importing custom command-line arguments when importing packages from a bundle": "Das Importieren von benutzerdefinierten Befehlszeilenargumenten beim Importieren von Paketen aus einem Bündel erlauben", + "Malformed command-line arguments can break packages, or even allow a malicious actor to gain privileged execution. Therefore, importing custom command-line arguments is disabled by default": "Fehlerhafte Befehlszeilenargumente können Pakete beschädigen oder sogar einem böswilligen Akteur die Ausführung mit erhöhten Rechten ermöglichen. Daher ist das Importieren benutzerdefinierter Befehlszeilenargumente standardmäßig deaktiviert.", + "Allow importing custom pre-install and post-install commands when importing packages from a bundle": "Das Importieren von benutzerdefinierten Vor- und Nachinstallationsbefehlen beim Importieren von Paketen aus einem Bündel erlauben", + "Pre and post install commands can do very nasty things to your device, if designed to do so. It can be very dangerous to import the commands from a bundle, unless you trust the source of that package bundle": "Vor und Nachinstallationsbefehle können Ihrem System erheblichen Schaden zufügen, wenn sie entsprechend programmiert sind. Es kann sehr riskant sein, Befehle aus einem Bündel zu importieren, es sei denn, Sie vertrauen der Quelle dieses Paketbündels.", + "Administrator rights and other dangerous settings": "Administratorrechte und andere riskante Einstellungen", + "Package backup": "Paketsicherung", + "Cloud package backup": "Cloud-Paketsicherung", + "Local package backup": "Lokale Paketsicherung", + "Local backup advanced options": "Erweiterte Optionen für die lokale Sicherung", + "Log in with GitHub": "Bei GitHub anmelden", + "Log out from GitHub": "Von GitHub abmelden", + "Periodically perform a cloud backup of the installed packages": "Regelmäßig eine Cloud-Sicherung der installierten Pakete durchführen", + "Cloud backup uses a private GitHub Gist to store a list of installed packages": "Die Cloud-Sicherung verwendet ein privates GitHub Gist, um eine Liste der installierten Pakete zu speichern.", + "Perform a cloud backup now": "Jetzt eine Cloud-Sicherung durchführen", + "Backup": "Sichern", + "Restore a backup from the cloud": "Eine Sicherung aus der Cloud wiederherstellen", + "Begin the process to select a cloud backup and review which packages to restore": "Starten Sie den Vorgang, um eine Cloud Sicherung auszuwählen und überprüfen Sie, welche Pakete wiederhergestellt werden sollen.", + "Periodically perform a local backup of the installed packages": "Regelmäßig eine lokale Sicherung der installierten Pakete durchführen", + "Perform a local backup now": "Jetzt eine lokale Sicherung durchführen", + "Change backup output directory": "Sicherungsverzeichnis ändern", + "Set a custom backup file name": "Einen benutzerdefinierten Dateinamen für Sicherungen festlegen", + "Leave empty for default": "Leer lassen für Standard", + "Add a timestamp to the backup file names": "Zeitstempel an den Sicherungsdateinamen anhängen", + "Backup and Restore": "Sichern und Wiederherstellen", + "Enable background api (UniGetUI Widgets and Sharing, port 7058)": "Hintergrund-API aktivieren (UniGetUI-Widgets und -Zugriff, Port 7058)", + "Wait for the device to be connected to the internet before attempting to do tasks that require internet connectivity.": "Mit der Ausführung von Aufgaben, die eine Internetverbindung erfordern, warten, bis das Gerät mit dem Internet verbunden ist.", + "Disable the 1-minute timeout for package-related operations": "Einminütige Zeitüberschreitung für paketbezogene Vorgänge deaktivieren", + "Use installed GSudo instead of UniGetUI Elevator": "Installiertes GSudo anstelle des UniGetUI-Elevators verwenden", + "Use a custom icon and screenshot database URL": "Benutzerdefinierte Datenbank-URL für Symbole und Screenshots verwenden", + "Enable background CPU Usage optimizations (see Pull Request #3278)": "Optimierungen der Hintergrund-CPU-Auslastung aktivieren (siehe Pull Request #3278)", + "Perform integrity checks at startup": "Beim Start Integritätsprüfungen durchführen", + "When batch installing packages from a bundle, install also packages that are already installed": "Bei der Batch-Installation von Paketen aus einem Bündel auch Pakete installieren, die bereits installiert sind.", + "Experimental settings and developer options": "Experimentelle und Entwickleroptionen", + "Show UniGetUI's version and build number on the titlebar.": "UniGetUI-Version und Build-Nummer in der Titelleiste anzeigen", + "Language": "Sprache", + "UniGetUI updater": "UniGetUI-Updater", + "Telemetry": "Telemetrie", + "Manage UniGetUI settings": "UniGetUI-Einstellungen verwalten", + "Related settings": "Verwandte Einstellungen", + "Update UniGetUI automatically": "UniGetUI automatisch aktualisieren", + "Check for updates": "Nach Updates suchen", + "Install prerelease versions of UniGetUI": "Auch Vorabversionen von UniGetUI installieren", + "Manage telemetry settings": "Telemetrieeinstellungen verwalten", + "Manage": "Verwalten", + "Import settings from a local file": "Einstellungen aus lokaler Datei importieren", + "Import": "Importieren", + "Export settings to a local file": "Einstellungen in lokale Datei exportieren", + "Export": "Exportieren", + "Reset UniGetUI": "UniGetUI zurücksetzen", + "User interface preferences": "Bedienoberfläche", + "Application theme, startup page, package icons, clear successful installs automatically": "Farbschema, Startseite, Paketsymbole, erfolgreiche Installationen automatisch leeren", + "General preferences": "Allgemeines", + "UniGetUI display language:": "UniGetUI-Anzeigesprache:", + "System language": "Systemsprache", + "Is your language missing or incomplete?": "Fehlt Ihre Sprache oder ist diese unvollständig?", + "Appearance": "Darstellung", + "UniGetUI on the background and system tray": "UniGetUI im Hintergrund und Infobereich", + "Package lists": "Paketlisten", + "Use classic mode": "Klassischen Modus verwenden", + "Restart UniGetUI to apply this change": "Starten Sie UniGetUI neu, um diese Änderung anzuwenden", + "The classic UI is disabled for beta testers": "Die klassische Benutzeroberfläche ist für Betatester deaktiviert", + "Close UniGetUI to the system tray": "UniGetUI nach dem Schließen im Infobereich anzeigen", + "Manage UniGetUI autostart behaviour": "Autostartverhalten von UniGetUI verwalten", + "Show package icons on package lists": "Paketsymbole in Paketlisten anzeigen", + "Clear cache": "Cache leeren", + "Select upgradable packages by default": "Pakete mit Updates automatisch auswählen", + "Light": "Hell", + "Dark": "Dunkel", + "Follow system color scheme": "Farbschema des Systems verwenden", + "Application theme:": "Farbschema:", + "UniGetUI startup page:": "UniGetUI-Startseite:", + "Proxy settings": "Proxy-Einstellungen", + "Other settings": "Weitere Einstellungen", + "Connect the internet using a custom proxy": "Über einen benutzerdefinierten Proxy mit dem Internet verbinden", + "Please note that not all package managers may fully support this feature": "Bitte beachten Sie, dass nicht alle Paketmanager diese Funktion vollständig unterstützen.", + "Proxy URL": "Proxy-URL", + "Enter proxy URL here": "Proxy-URL hier eingeben", + "Authenticate to the proxy with a user and a password": "Am Proxy mit Benutzername und Passwort authentifizieren", + "Internet and proxy settings": "Internet- und Proxy-Einstellungen", + "Package manager preferences": "Paketmanager-Einstellungen", + "Ready": "Bereit", + "Not found": "Nicht gefunden", + "Notification preferences": "Benachrichtigungen", + "Notification types": "Benachrichtigungstypen", + "The system tray icon must be enabled in order for notifications to work": "Das Symbol im Infobereich muss aktiviert sein, damit die Benachrichtigungen funktionieren.", + "Enable UniGetUI notifications": "UniGetUI-Benachrichtigungen aktivieren", + "Show a notification when there are available updates": "Benachrichtigung anzeigen, wenn Updates verfügbar sind", + "Show a silent notification when an operation is running": "Stille Benachrichtigung anzeigen, wenn ein Vorgang ausgeführt wird", + "Show a notification when an operation fails": "Benachrichtigung anzeigen, wenn ein Vorgang fehlschlägt", + "Show a notification when an operation finishes successfully": "Benachrichtigung anzeigen, wenn ein Vorgang erfolgreich abgeschlossen wurde", + "Concurrency and execution": "Parallele Ausführung", + "Automatic desktop shortcut remover": "Desktopverknüpfung automatisch entfernen", + "Choose how many operations should be performed in parallel": "Wählen Sie aus, wie viele Vorgänge parallel ausgeführt werden sollen", + "Clear successful operations from the operation list after a 5 second delay": "Erfolgreiche Vorgänge nach einer Verzögerung von 5 Sekunden aus der Liste entfernen", + "Download operations are not affected by this setting": "Download-Vorgänge sind von dieser Einstellung nicht betroffen", + "You may lose unsaved data": "Sie können nicht gespeicherte Daten verlieren", + "Ask to delete desktop shortcuts created during an install or upgrade.": "Nach Löschen von Desktopverknüpfungen fragen, die während einer Installation oder eines Upgrades erstellt wurden.", + "Package update preferences": "Paketupdates", + "Update check frequency, automatically install updates, etc.": "Update-Prüfintervall, automatische Updates usw.", + "Reduce UAC prompts, elevate installations by default, unlock certain dangerous features, etc.": "Benutzerkontensteuerung-Eingabeaufforderungen reduzieren, Installationen standardmäßig mit erhöhten Berechtigungen ausführen, bestimmte riskante Funktionen freischalten usw.", + "Package operation preferences": "Paketvorgänge", + "Enable {pm}": "{pm} aktivieren", + "Not finding the file you are looking for? Make sure it has been added to path.": "Sie können die gesuchte Datei nicht finden? Stellen Sie sicher, dass sie zum Pfad hinzugefügt wurde.", + "Select the executable to be used. The following list shows the executables found by UniGetUI": "Wählen Sie die auszuführende Datei aus. Die folgende Liste zeigt die von UniGetUI gefundenen ausführbaren Dateien.", + "For security reasons, changing the executable file is disabled by default": "Aus Sicherheitsgründen ist das Ändern der ausführbaren Datei standardmäßig deaktiviert.", + "Change this": "Dies ändern", + "Copy path": "Pfad kopieren", + "Current executable file:": "Aktuelle ausführbare Datei:", + "Ignore packages from {pm} when showing a notification about updates": "Pakete von {pm} ignorieren, wenn eine Benachrichtigung über Updates angezeigt wird", + "Update security": "Update-Sicherheit", + "Use global setting": "Globale Einstellung verwenden", + "Minimum age for updates": "Mindestalter für Updates", + "e.g. 10": "z. B. 10", + "Custom minimum age (days)": "Benutzerdefiniertes Mindestalter (Tage)", + "{pm} does not provide release dates for its packages, so this setting will have no effect": "{pm} stellt keine Veröffentlichungsdaten für seine Pakete bereit, daher hat diese Einstellung keine Wirkung", + "{pm} only provides release dates for some of its packages, so this setting will only apply to those packages": "{pm} stellt nur für einige seiner Pakete Veröffentlichungsdaten bereit, daher gilt diese Einstellung nur für diese Pakete", + "Override the global minimum update age for this package manager": "Das globale Mindestalter für Updates für diesen Paketmanager überschreiben", + "View {0} logs": "{0}-Protokolle anzeigen", + "If Python cannot be found or is not listing packages but is installed on the system, ": "Wenn Python nicht gefunden werden kann oder keine Pakete auflistet, aber auf dem System installiert ist, ", + "Advanced options": "Erweiterte Optionen", + "WinGet command-line tool": "WinGet-Befehlszeilentool", + "Choose which command-line tool UniGetUI uses for WinGet operations when the COM API is not used": "Wählen Sie aus, welches Befehlszeilentool UniGetUI für WinGet-Vorgänge verwendet, wenn die COM API nicht verwendet wird", + "WinGet COM API": "WinGet COM API", + "Choose whether UniGetUI can use the WinGet COM API before falling back to the command-line tool": "Wählen Sie aus, ob UniGetUI die WinGet COM API verwenden kann, bevor auf das Befehlszeilentool zurückgegriffen wird", + "Reset WinGet": "WinGet zurücksetzen", + "This may help if no packages are listed": "Dies kann hilfreich sein, wenn keine Pakete aufgelistet sind", + "Force install location parameter when updating packages with custom locations": "Parameter für den Installationsort beim Aktualisieren von Paketen mit benutzerdefinierten Speicherorten erzwingen", + "Install Scoop": "Scoop installieren", + "Uninstall Scoop (and its packages)": "Scoop deinstallieren (inkl. aller Pakete)", + "Run cleanup and clear cache": "Bereinigung ausführen und Cache leeren", + "Run": "Ausführen", + "Enable Scoop cleanup on launch": "Bereinigung von Scoop beim Start aktivieren", + "Default vcpkg triplet": "Standard vcpkg-Triplett", + "Change vcpkg root location": "vcpkg-Stammspeicherort ändern", + "Reset vcpkg root location": "vcpkg-Stammverzeichnis zurücksetzen", + "Open vcpkg root location": "vcpkg-Stammverzeichnis öffnen", + "Language, theme and other miscellaneous preferences": "Sprache und andere Einstellungen", + "Show notifications on different events": "Benachrichtigungen über verschiedene Ereignisse anzeigen", + "Change how UniGetUI checks and installs available updates for your packages": "Legen Sie fest, wie UniGetUI nach verfügbaren Updates für Ihre Pakete sucht und installiert", + "Automatically save a list of all your installed packages to easily restore them.": "Automatisch eine Liste von allen installierten Paketen speichern, um sie einfacher wiederherzustellen", + "Enable and disable package managers, change default install options, etc.": "Paketmanager aktivieren und deaktivieren, Standardinstallationsoptionen ändern usw.", + "Internet connection settings": "Internetverbindung", + "Proxy settings, etc.": "Proxy-Einstellungen usw.", + "Beta features and other options that shouldn't be touched": "Beta-Funktionen und andere Optionen, die nicht geändert werden sollten", + "Reload sources": "Quellen neu laden", + "Delete source": "Quelle löschen", + "Known sources": "Bekannte Quellen", + "Update checking": "Update-Prüfintervall", + "Automatic updates": "Automatische Updates", + "Check for package updates periodically": "Regelmäßig nach Paketupdates suchen", + "Check for updates every:": "Nach Updates suchen alle:", + "Install available updates automatically": "Verfügbare Updates automatisch installieren", + "Do not automatically install updates when the network connection is metered": "Updates nicht automatisch installieren, wenn die Netzwerkverbindung getaktet ist", + "Do not automatically install updates when the device runs on battery": "Updates nicht automatisch installieren, wenn das Gerät im Akkubetrieb läuft", + "Do not automatically install updates when the battery saver is on": "Updates nicht automatisch installieren, wenn der Energiesparmodus aktiviert ist", + "Only show updates that are at least the specified number of days old": "Nur Updates anzeigen, die mindestens die angegebene Anzahl von Tagen alt sind", + "Warn me when the installer URL host changes between the installed version and the new version (WinGet only)": "Warnen, wenn sich der Host der Installations-URL zwischen der installierten Version und der neuen Version ändert (nur WinGet)", + "Change how UniGetUI handles install, update and uninstall operations.": "Festlegen, wie UniGetUI Installations-, Aktualisierungs- und Deinstallationsvorgänge durchführt.", + "Navigation": "Navigationselemente", + "Check for UniGetUI updates": "Nach Updates für UniGetUI suchen", + "Quit UniGetUI": "UniGetUI beenden", + "Filters": "Filter", + "Sources": "Quellen", + "Search for packages to start": "Nach Paketen suchen, um zu starten", + "Select all": "Alle auswählen", + "Clear selection": "Auswahl aufheben", + "Instant search": "Schnellsuche", + "Distinguish between uppercase and lowercase": "Groß/Kleinschreibung beachten", + "Ignore special characters": "Sonderzeichen ignorieren", + "Search mode": "Suchmodus", + "Both": "Beide", + "Exact match": "Exakter Treffer", + "Show similar packages": "Ähnliche Pakete anzeigen", + "Loading": "Laden", + "Package": "Paket", + "More options": "Weitere Optionen", + "Order by:": "Sortieren nach:", + "Name": "Name", + "Id": "ID", + "Ascendant": "Aufsteigend", + "Descendant": "Absteigend", + "View modes": "Ansichtsmodi", + "Reload": "Neu laden", + "Closed": "Geschlossen", + "Ascending": "Aufsteigend", + "Descending": "Absteigend", + "{0}: {1}, {2}": "{0}: {1}, {2}", + "Order by": "Sortieren nach", + "No results were found matching the input criteria": "Es wurden keine Ergebnisse gefunden, die den eingegebenen Kriterien entsprechen.", + "No packages were found": "Keine Pakete gefunden", + "Loading packages": "Pakete werden geladen...", + "Skip integrity checks": "Integritätsprüfungen überspringen", + "Download selected installers": "Ausgewählte Installationsdateien herunterladen", + "Install selection": "Auswahl installieren", + "Install options": "Installationsoptionen", + "Add selection to bundle": "Auswahl zum Bündel hinzufügen", + "Download installer": "Installationsdatei herunterladen", + "Uninstall selection": "Auswahl deinstallieren", + "Uninstall options": "Deinstallationsoptionen", + "Ignore selected packages": "Ausgewählte Pakete ignorieren", + "Open install location": "Installationsort öffnen", + "Reinstall package": "Paket neu installieren", + "Uninstall package, then reinstall it": "Paket deinstallieren, dann neu installieren", + "Ignore updates for this package": "Updates für dieses Paket ignorieren", + "WinGet malfunction detected": "WinGet-Fehler erkannt", + "It looks like WinGet is not working properly. Do you want to attempt to repair WinGet?": "WinGet scheint nicht richtig zu funktionieren. Möchten Sie versuchen, WinGet zu reparieren?", + "Repair WinGet": "WinGet reparieren", + "Updates will no longer be ignored for {0}": "Updates werden für {0} nicht mehr ignoriert", + "Updates are now ignored for {0}": "Updates werden jetzt für {0} ignoriert", + "Do not ignore updates for this package anymore": "Updates für dieses Paket nicht mehr ignorieren", + "Add packages or open an existing package bundle": "Pakete hinzufügen oder ein vorhandenes Paketbündel öffnen", + "Add packages to start": "Zum starten Pakete hinzufügen", + "The current bundle has no packages. Add some packages to get started": "Das aktuelle Bündel enthält keine Pakete. Fügen Sie ein paar Pakete hinzu, um zu beginnen.", + "New": "Neu", + "Save as": "Speichern unter", + "Create .ps1 script": ".ps1-Skript erstellen", + "Remove selection from bundle": "Auswahl aus Bündel entfernen", + "Skip hash checks": "Hash-Prüfungen überspringen", + "The package bundle is not valid": "Das Paketbündel ist ungültig", + "The bundle you are trying to load appears to be invalid. Please check the file and try again.": "Das Bündel, das Sie versuchen zu laden, scheint ungültig zu sein. Bitte überprüfen Sie die Datei und versuchen Sie es erneut.", + "Package bundle": "Paketbündel", + "Could not create bundle": "Bündel konnte nicht erstellt werden", + "The package bundle could not be created due to an error.": "Das Paketbündel konnte aufgrund eines Fehlers nicht erstellt werden.", + "Install script": "Installationsskript", + "PowerShell script": "PowerShell-Skript", + "The installation script saved to {0}": "Das Installationsskript wurde gespeichert unter {0}", + "An error occurred": "Ein Fehler ist aufgetreten", + "An error occurred while attempting to create an installation script:": "Beim Versuch, ein Installationsskript zu erstellen, ist ein Fehler aufgetreten:", + "Hooray! No updates were found.": "Hurra! Es wurden keine Updates gefunden.", + "Uninstall selected packages": "Ausgewählte Pakete deinstallieren", + "Update selection": "Auswahl aktualisieren", + "Update options": "Aktualisierungsoptionen", + "Uninstall package, then update it": "Paket deinstallieren, dann aktualisieren", + "Uninstall package": "Paket deinstallieren", + "Skip this version": "Diese Version überspringen", + "Pause updates for": "Updates aussetzen für", + "User | Local": "Benutzer | Lokal", + "Machine | Global": "Computer | Global", + "The default package manager for Debian/Ubuntu-based Linux distributions.
Contains: Debian/Ubuntu packages": "Der Standard-Paketmanager für Debian-/Ubuntu-basierte Linux-Distributionen.
Enthält: Debian-/Ubuntu-Pakete", + "The Rust package manager.
Contains: Rust libraries and programs written in Rust": "Der Rust-Paketmanager.
Enthält: Rust-Bibliotheken und in Rust geschriebene Programme.", + "The classical package manager for windows. You'll find everything there.
Contains: General Software": "Der klassische Paketmanager für Windows. Dort finden Sie alles.
Enthält: Allgemeine Software", + "The default package manager for RHEL/Fedora-based Linux distributions.
Contains: RPM packages": "Der Standard-Paketmanager für RHEL-/Fedora-basierte Linux-Distributionen.
Enthält: RPM-Pakete", + "A repository full of tools and executables designed with Microsoft's .NET ecosystem in mind.
Contains: .NET related tools and scripts": "Ein Repository mit Tools und ausführbaren Dateien, designt für das .NET-Ökosystem von Microsoft.
Enthält: .NET-bezogene Tools und Skripte", + "The universal Linux package manager for desktop applications.
Contains: Flatpak applications from configured remotes": "Der universelle Linux-Paketmanager für Desktop-Anwendungen.
Enthält: Flatpak-Anwendungen aus konfigurierten Remotes", + "NuPkg (zipped manifest)": "NuPkg (komprimiertes Manifest)", + "The Missing Package Manager for macOS (or Linux).
Contains: Formulae, Casks": "Der fehlende Paketmanager für macOS (oder Linux).
Enthält: Formulae, Casks", + "Node JS's package manager. Full of libraries and other utilities that orbit the javascript world
Contains: Node javascript libraries and other related utilities": "Node.js-Paketmanager. Enthält viele Bibliotheken und andere Dienstprogramme aus der JavaScript-Welt.
Enthält: Node JavaScript-Bibliotheken und andere zugehörige Dienstprogramme", + "The default package manager for Arch Linux and its derivatives.
Contains: Arch Linux packages": "Der Standard-Paketmanager für Arch Linux und seine Derivate.
Enthält: Arch-Linux-Pakete", + "Python's library manager. Full of python libraries and other python-related utilities
Contains: Python libraries and related utilities": "Paketmanager von Python. Enthält viele Python-Bibliotheken und andere mit Python verwandte Dienstprogramme.
Enthält: Python-Bibliotheken und zugehörige Dienstprogramme", + "PowerShell's package manager. Find libraries and scripts to expand PowerShell capabilities
Contains: Modules, Scripts, Cmdlets": "PowerShell-Paketmanager. Finden Sie Bibliotheken und Skripte zur Erweiterung der PowerShell-Funktionen.
Enthält: Module, Skripte, Cmdlets", + "extracted": "extrahiert", + "Scoop package": "Scoop-Paket", + "Great repository of unknown but useful utilities and other interesting packages.
Contains: Utilities, Command-line programs, General Software (extras bucket required)": "Große Sammlung nützlicher Tools und anderer interessanter Pakete.
Enthält: Utilities, Befehlszeilenprogramme, allgemeine Software (Zusatzpaket erforderlich)", + "The universal Linux package manager by Canonical.
Contains: Snap packages from the Snapcraft store": "Der universelle Linux-Paketmanager von Canonical.
Enthält: Snap-Pakete aus dem Snapcraft Store", + "library": "Bibliothek", + "feature": "Besonderheit", + "A popular C/C++ library manager. Full of C/C++ libraries and other C/C++-related utilities
Contains: C/C++ libraries and related utilities": "Eine beliebte C/C++-Bibliotheksverwaltung. Voller C/C++ Bibliotheken und anderen C/C++ zugehörigen Werkzeugen.
Enthält: C/C++-Bibliotheken und zugehörige Werkzeuge", + "option": "Option", + "This package cannot be installed from an elevated context.": "Das Paket kann nicht mit erhöhten Rechten (als Administrator) installiert werden.", + "Please run UniGetUI as a regular user and try again.": "Starten Sie bitte UniGetUI als normaler Benutzer und versuchen Sie es noch einmal.", + "Please check the installation options for this package and try again": "Prüfen Sie bitte die Installationsoptionen des Pakets und versuchen Sie es noch einmal", + "Microsoft's official package manager. Full of well-known and verified packages
Contains: General Software, Microsoft Store apps": "Offizieller Paketmanager von Microsoft. Enthält viele bekannte und verifizierte Pakete.
Enthält: Allgemeine Software, Microsoft Store-Apps", + "Local PC": "Lokaler PC", + "Android Subsystem": "Android-Subsystem", + "Operation on queue (position {0})...": "Vorgang in Warteschlange (Position {0})...", + "Click here for more details": "Hier klicken für mehr Details", + "Operation canceled by user": "Vorgang vom Benutzer abgebrochen", + "Running PreOperation ({0}/{1})...": "PreOperation wird ausgeführt ({0}/{1})...", + "PreOperation {0} out of {1} failed, and was tagged as necessary. Aborting...": "PreOperation {0} von {1} ist fehlgeschlagen und als erforderlich markiert. Abbruch...", + "PreOperation {0} out of {1} finished with result {2}": "PreOperation {0} von {1} wurde mit dem Ergebnis {2} abgeschlossen", + "Starting operation...": "Vorgang starten...", + "Running PostOperation ({0}/{1})...": "PostOperation wird ausgeführt ({0}/{1})...", + "PostOperation {0} out of {1} failed, and was tagged as necessary. Aborting...": "PostOperation {0} von {1} ist fehlgeschlagen und als erforderlich markiert. Abbruch...", + "PostOperation {0} out of {1} finished with result {2}": "PostOperation {0} von {1} wurde mit dem Ergebnis {2} abgeschlossen", + "{package} installer download": "{package}-Installationsdatei wird heruntergeladen", + "{0} installer is being downloaded": "{0}-Installationsdatei wird heruntergeladen", + "Download succeeded": "Download erfolgreich", + "{package} installer was downloaded successfully": "{package}-Installationsdatei wurde erfolgreich heruntergeladen", + "Download failed": "Download fehlgeschlagen", + "{package} installer could not be downloaded": "{package}-Installationsdatei konnte nicht heruntergeladen werden", + "{package} Installation": "{package} Installation", + "{0} is being installed": "{0} wird installiert", + "Installation succeeded": "Installation erfolgreich", + "{package} was installed successfully": "{package} wurde erfolgreich installiert", + "Installation failed": "Installation fehlgeschlagen", + "{package} could not be installed": "{package} konnte nicht installiert werden", + "{package} Update": "{package} Update", + "Update succeeded": "Update erfolgreich", + "{package} was updated successfully": "{package} wurde erfolgreich aktualisiert", + "Update failed": "Update fehlgeschlagen", + "{package} could not be updated": "{package} konnte nicht aktualisiert werden", + "{package} Uninstall": "{package} Deinstallation", + "{0} is being uninstalled": "{0} wird deinstalliert", + "Uninstall succeeded": "Erfolgreich deinstalliert", + "{package} was uninstalled successfully": "{package} wurde erfolgreich deinstalliert", + "Uninstall failed": "Deinstallieren fehlgeschlagen", + "{package} could not be uninstalled": "{package} konnte nicht deinstalliert werden", + "Adding source {source}": "Quelle {source} hinzufügen", + "Adding source {source} to {manager}": "Quelle {source} wird zu {manager} hinzugefügt", + "Source added successfully": "Quelle erfolgreich hinzugefügt", + "The source {source} was added to {manager} successfully": "Die Quelle {source} wurde erfolgreich zu {manager} hinzugefügt", + "Could not add source": "Konnte Quelle nicht hinzufügen", + "Could not add source {source} to {manager}": "Quelle {source} konnte nicht zu {manager} hinzugefügt werden", + "Removing source {source}": "Quelle {source} entfernen", + "Removing source {source} from {manager}": "Quelle {source} aus {manager} entfernen", + "Source removed successfully": "Quelle erfolgreich entfernt", + "The source {source} was removed from {manager} successfully": "Die Quelle {source} wurde erfolgreich von {manager} entfernt", + "Could not remove source": "Konnte Quelle nicht entfernen", + "Could not remove source {source} from {manager}": "Quelle {source} konnte nicht von {manager} entfernt werden", + "The package manager \"{0}\" was not found": "Paketmanager „{0}“ wurde nicht gefunden", + "The package manager \"{0}\" is disabled": "Paketmanager „{0}“ ist deaktiviert", + "There is an error with the configuration of the package manager \"{0}\"": "Es liegt ein Fehler in der Konfiguration des Paketmanagers „{0}“ vor", + "The package \"{0}\" was not found on the package manager \"{1}\"": "Das Paket „{0}“ wurde nicht im Paketmanager „{1}“ gefunden", + "{0} is disabled": "{0} ist deaktiviert", + "{0} weeks": "{0} Wochen", + "1 month": "1 Monat", + "{0} months": "{0} Monate", + "Something went wrong": "Etwas ist schiefgelaufen", + "An interal error occurred. Please view the log for further details.": "Ein interner Fehler ist aufgetreten. Bitte sehen Sie sich das Protokoll für weitere Details an.", + "No applicable installer was found for the package {0}": "Es wurde keine geeignete Installationsdatei für das Paket {0} gefunden", + "Integrity checks will not be performed during this operation": "Integritätsprüfungen werden nicht während dieses Vorgangs ausgeführt", + "This is not recommended.": "Dies ist nicht empfohlen.", + "Run now": "Jetzt ausführen", + "Run next": "Als Nächstes ausführen", + "Run last": "Als Letztes ausführen", + "Show in explorer": "In Explorer anzeigen", + "Checked": "Ausgewählt", + "Unchecked": "Nicht ausgewählt", + "This package is already installed": "Dieses Paket wurde bereits installiert", + "This package can be upgraded to version {0}": "Dieses Paket kann auf Version {0} aktualisiert werden", + "Updates for this package are ignored": "Updates für dieses Paket werden ignoriert", + "This package is being processed": "Dieses Paket wird verarbeitet", + "This package is not available": "Dieses Paket ist nicht verfügbar", + "Select the source you want to add:": "Wählen Sie die Quelle, die hinzugefügt werden soll:", + "Source name:": "Name der Quelle:", + "Source URL:": "URL der Quelle:", + "An error occurred when adding the source: ": "Ein Fehler ist aufgetreten beim hinzufügen folgender Quelle:", + "Package management made easy": "Paketverwaltung leicht gemacht", + "version {0}": "Version {0}", + "[RAN AS ADMINISTRATOR]": "ALS ADMINISTRATOR AUSGEFÜHRT", + "Portable mode": "Portabler Modus", + "DEBUG BUILD": "DEBUG-BUILD", + "Here you can change UniGetUI's behaviour regarding the following shortcuts. Checking a shortcut will make UniGetUI delete it if if gets created on a future upgrade. Unchecking it will keep the shortcut intact": "Hier können Sie das Verhalten von UniGetUI bezüglich der folgenden Verknüpfungen ändern. Wenn Sie ein Häkchen setzen, wird UniGetUI die Verknüpfung löschen, wenn sie bei einem zukünftigen Upgrade erstellt wird. Wenn Sie das Häkchen entfernen, bleibt die Verknüpfung bestehen.", + "Manual scan": "Manueller Scan", + "Existing shortcuts on your desktop will be scanned, and you will need to pick which ones to keep and which ones to remove.": "Vorhandene Verknüpfungen auf Ihrem Desktop werden gescannt, und Sie müssen auswählen, welche Sie behalten und welche Sie entfernen möchten.", + "Delete?": "Löschen?", + "I understand": "Ich verstehe", + "Chocolatey setup changed": "Chocolatey-Konfiguration geändert", + "UniGetUI no longer includes its own private Chocolatey installation. A legacy UniGetUI-managed Chocolatey installation was detected for this user profile, but system Chocolatey was not found. Chocolatey will stay unavailable in UniGetUI until Chocolatey is installed on the system and UniGetUI is restarted. Applications previously installed through UniGetUI's bundled Chocolatey may still appear under other sources such as Local PC or WinGet.": "UniGetUI enthält keine eigene private Chocolatey-Installation mehr. Eine ältere, von UniGetUI verwaltete Chocolatey-Installation wurde für dieses Benutzerprofil erkannt, aber systemweites Chocolatey wurde nicht gefunden. Chocolatey bleibt in UniGetUI nicht verfügbar, bis Chocolatey auf dem System installiert und UniGetUI neu gestartet wird. Anwendungen, die zuvor über das mitgelieferte Chocolatey von UniGetUI installiert wurden, können weiterhin unter anderen Quellen wie Lokaler PC oder WinGet erscheinen.", + "NOTE: This troubleshooter can be disabled from UniGetUI Settings, on the WinGet section": "HINWEIS: Diese Funktion zur Fehlersuche kann in den Paketmanager-Einstellungen im Abschnitt „WinGet“ deaktiviert werden.", + "Restart": "Neu starten", + "Are you sure you want to delete all shortcuts?": "Möchten Sie wirklich alle Verknüpfungen löschen?", + "Any new shorcuts created during an install or an update operation will be deleted automatically, instead of showing a confirmation prompt the first time they are detected.": "Alle neuen Verknüpfungen, die während einer Installation oder einer Aktualisierung erstellt werden, werden automatisch gelöscht, anstatt beim ersten Erkennen der Verknüpfungen eine Bestätigungsaufforderung anzuzeigen.", + "Any shorcuts created or modified outside of UniGetUI will be ignored. You will be able to add them via the {0} button.": "Alle Verknüpfungen, die außerhalb von UniGetUI erstellt oder geändert wurden, werden ignoriert. Sie werden sie über die Schaltfläche {0} hinzufügen können.", + "Are you really sure you want to enable this feature?": "Möchten Sie diese Funktion wirklich aktivieren?", + "No new shortcuts were found during the scan.": "Während des Scans wurden keine neuen Verknüpfungen gefunden.", + "How to add packages to a bundle": "So fügen Sie Pakete zu einem Bündel hinzu", + "In order to add packages to a bundle, you will need to: ": "Um Pakete zu einem Bündel hinzuzufügen, müssen Sie Folgendes tun:", + "1. Navigate to the \"{0}\" or \"{1}\" page.": "1. Navigieren Sie zu der Seite „{0}“ oder „{1}“.", + "2. Locate the package(s) you want to add to the bundle, and select their leftmost checkbox.": "2. Suchen Sie das/die Paket(e), das/die Sie dem Bundle hinzufügen möchten, und wählen Sie das Kontrollkästchen ganz links aus.", + "3. When the packages you want to add to the bundle are selected, find and click the option \"{0}\" on the toolbar.": "3. Wenn die Pakete, die Sie dem Bündel hinzufügen möchten, ausgewählt sind, klicken Sie in der Symbolleiste auf die Option „{0}“.", + "4. Your packages will have been added to the bundle. You can continue adding packages, or export the bundle.": "4. Ihre Pakete wurden nun dem Bündel hinzugefügt. Sie können weitere Pakete hinzufügen oder das Bündel exportieren.", + "Which backup do you want to open?": "Welche Sicherung möchten Sie öffnen?", + "Select the backup you want to open. Later, you will be able to review which packages you want to install.": "Wählen Sie die Sicherung aus, die Sie öffnen möchten. Später können Sie überprüfen, welche Pakete/Programme Sie wiederherstellen möchten.", + "There are ongoing operations. Quitting UniGetUI may cause them to fail. Do you want to continue?": "Laufende Vorgänge gefunden. Wenn Sie UniGetUI beenden, können diese fehlschlagen. Möchten Sie fortfahren?", + "UniGetUI or some of its components are missing or corrupt.": "UniGetUI oder einige seiner Komponenten fehlen oder sind beschädigt.", + "It is strongly recommended to reinstall UniGetUI to adress the situation.": "Es wird dringend empfohlen, UniGetUI neu zu installieren, um das Problem zu beheben.", + "Refer to the UniGetUI Logs to get more details regarding the affected file(s)": "Weitere Informationen zu den betroffenen Dateien finden Sie in den UniGetUI-Protokollen.", + "Integrity checks can be disabled from the Experimental Settings": "Integritätsprüfungen können in den experimentellen Einstellungen deaktiviert werden.", + "Repair UniGetUI": "UniGetUI reparieren", + "Live output": "Live-Ausgabe", + "This package bundle had some settings that are potentially dangerous, and may be ignored by default.": "Dieses Paketbündel enthielt Einstellungen, die potenziell riskant sind und standardmäßig ignoriert werden können.", + "Entries that show in YELLOW will be IGNORED.": "Einträge, die in GELB angezeigt werden, werden IGNORIERT.", + "Entries that show in RED will be IMPORTED.": "Einträge, die in ROT angezeigt werden, werden IMPORTIERT.", + "You can change this behavior on UniGetUI security settings.": "Sie können dieses Verhalten in den UniGetUI-Sicherheitseinstellungen ändern.", + "Open UniGetUI security settings": "UniGetUI-Sicherheitseinstellungen öffnen", + "Should you modify the security settings, you will need to open the bundle again for the changes to take effect.": "Sollten Sie die Sicherheitseinstellungen ändern, müssen Sie das Bündel erneut öffnen, damit die Änderungen wirksam werden.", + "Details of the report:": "Berichtsdetails:", + "Are you sure you want to create a new package bundle? ": "Sind Sie sicher, dass Sie ein neues Paketbündel erstellen möchten?", + "Any unsaved changes will be lost": "Nicht gesicherte Änderungen gehen verloren", + "Warning!": "Warnung!", + "For security reasons, custom command-line arguments are disabled by default. Go to UniGetUI security settings to change this. ": "Aus Sicherheitsgründen sind benutzerdefinierte Kommandozeilenargumente standardmäßig deaktiviert. Gehen Sie zu den UniGetUI-Sicherheitseinstellungen, um dies zu ändern.", + "Change default options": "Standardoptionen ändern", + "Ignore future updates for this package": "Zukünftige Updates für dieses Paket ignorieren", + "For security reasons, pre-operation and post-operation scripts are disabled by default. Go to UniGetUI security settings to change this. ": "Aus Sicherheitsgründen sind die Skripte vor und nach der Operation standardmäßig deaktiviert. Gehen Sie zu den UniGetUI-Sicherheitseinstellungen, um dies zu ändern.", + "You can define the commands that will be run before or after this package is installed, updated or uninstalled. They will be run on a command prompt, so CMD scripts will work here.": "Sie können die Befehle festlegen, die vor oder nach der Installation, Aktualisierung oder Deinstallation dieses Pakets ausgeführt werden. Sie werden in einer Eingabeaufforderung ausgeführt, sodass CMD-Skripte hier funktionieren.", + "Change this and unlock": "Dies ändern und entsperren", + "{0} Install options are currently locked because {0} follows the default install options.": "Die Installationsoptionen von {0} sind derzeit gesperrt, da {0} den Standardinstallationsoptionen folgt.", + "Unset or unknown": "Nicht festgelegt oder unbekannt", + "This package has no screenshots or is missing the icon? Contrbute to UniGetUI by adding the missing icons and screenshots to our open, public database.": "Dieses Paket hat keine Screenshots oder es fehlt ein Symbol? Unterstützen Sie UniGetUI, indem Sie die fehlenden Symbole und Screenshots zu unserer offenen, öffentlichen Datenbank hinzufügen.", + "Become a contributor": "Werden Sie Mitwirkender", + "Update to {0} available": "Update auf {0} verfügbar", + "Reinstall": "Neu installieren", + "Installer not available": "Installationsdatei nicht verfügbar", + "Version:": "Version:", + "UniGetUI Version {0}": "UniGetUI-Version {0}", + "Performing backup, please wait...": "Sicherung wird erstellt, bitte warten...", + "An error occurred while logging in: ": "Beim Anmelden ist ein Fehler aufgetreten:", + "Fetching available backups...": "Verfügbare Sicherungen abrufen...", + "Done!": "Fertig!", + "The cloud backup has been loaded successfully.": "Die Cloud-Sicherung wurde erfolgreich geladen.", + "An error occurred while loading a backup: ": "Beim Laden einer Sicherung ist ein Fehler aufgetreten:", + "Backing up packages to GitHub Gist...": "Pakete werden auf GitHub Gist gesichert...", + "Backup Successful": "Sicherung erfolgreich", + "The cloud backup completed successfully.": "Die Cloud-Sicherung wurde erfolgreich abgeschlossen.", + "Could not back up packages to GitHub Gist: ": "Die Pakete konnten nicht auf GitHub Gist gesichert werden:", + "It is not guaranteed that the provided credentials will be stored safely, so you may as well not use the credentials of your bank account": "Es kann nicht garantiert werden, dass die angegebenen Anmeldedaten sicher gespeichert werden. Verwenden Sie daher besser nicht die Zugangsdaten Ihres Bankkontos.", + "Enable the automatic WinGet troubleshooter": "Automatische WinGet-Fehlerbehebung aktivieren", + "Add updates that fail with a 'no applicable update found' to the ignored updates list": "Updates, die mit der Meldung „kein anwendbares Update gefunden“ fehlschlagen, zur Liste der ignorierten Updates hinzufügen.", + "Invalid selection": "Ungültige Auswahl", + "No package was selected": "Es wurde kein Paket ausgewählt.", + "More than 1 package was selected": "Es wurde mehr als ein Paket ausgewählt.", + "List": "Liste", + "Grid": "Raster", + "Icons": "Symbole", + "\"{0}\" is a local package and does not have available details": "„{0}“ ist ein lokales Paket und hat keine verfügbaren Details", + "\"{0}\" is a local package and is not compatible with this feature": "„{0}“ ist ein lokales Paket und ist mit dieser Funktion nicht kompatibel", + "Add packages to bundle": "Pakete zum Bündel hinzufügen", + "Preparing packages, please wait...": "Pakete werden vorbereitet, bitte warten...", + "Loading packages, please wait...": "Pakete werden geladen, bitte warten...", + "Saving packages, please wait...": "Pakete werden gesichert, bitte warten...", + "The bundle was created successfully on {0}": "Das Bündel wurde erfolgreich gespeichert unter {0}", + "User profile": "Benutzerprofil", + "Error": "Fehler", + "Log in failed: ": "Anmeldung fehlgeschlagen:", + "Log out failed: ": "Abmeldung fehlgeschlagen:", + "Package backup settings": "Einstellungen für die Paketsicherung", + "Manage UniGetUI autostart behaviour from the Settings app": "Autostartverhalten von UniGetUI verwalten", + "Choose how many operations shoulds be performed in parallel": "Wählen Sie aus, wie viele Vorgänge parallel ausgeführt werden sollen", + "Something went wrong while launching the updater.": "Beim Updater-Start lief etwas schief.", + "Please try again later": "Versuchen Sie es bitte später noch einmal", + "Show the release notes after UniGetUI is updated": "Versionshinweise anzeigen, nachdem UniGetUI aktualisiert wurde" +} diff --git a/src/Languages/lang_el.json b/src/Languages/lang_el.json new file mode 100644 index 0000000..3eadc1f --- /dev/null +++ b/src/Languages/lang_el.json @@ -0,0 +1,850 @@ +{ + "{0} of {1} operations completed": "{0} από {1} λειτουργίες ολοκληρώθηκαν", + "{0} is now {1}": "Το {0} είναι τώρα {1}", + "Enabled": "Ενεργό", + "Disabled": "Ανενεργό", + "Privacy": "Απόρρητο", + "Hide my username from the logs": "Απόκρυψη του ονόματος χρήστη μου από τα αρχεία καταγραφής", + "Replaces your username with **** in the logs. Restart UniGetUI to also hide it from already-recorded entries.": "Αντικαθιστά το όνομα χρήστη σας με **** στα αρχεία καταγραφής. Επανεκκινήστε το UniGetUI για να το αποκρύψετε και από τις ήδη καταγεγραμμένες εγγραφές.", + "Your last update attempt did not complete.": "Η τελευταία προσπάθεια ενημέρωσης δεν ολοκληρώθηκε.", + "UniGetUI could not confirm whether the update succeeded. Open the log to see what happened.": "Το UniGetUI δεν μπόρεσε να επιβεβαιώσει αν η ενημέρωση πέτυχε. Ανοίξτε το αρχείο καταγραφής για να δείτε τι συνέβη.", + "View log": "Προβολή αρχείου καταγραφής", + "The installer reported success but did not restart UniGetUI.": "Το πρόγραμμα εγκατάστασης ανέφερε επιτυχία, αλλά δεν επανεκκίνησε το UniGetUI.", + "The installer failed to initialize.": "Το πρόγραμμα εγκατάστασης απέτυχε να αρχικοποιηθεί.", + "Setup was canceled before installation began.": "Η διαδικασία εγκατάστασης ακυρώθηκε πριν ξεκινήσει.", + "A fatal error occurred during the preparation phase.": "Παρουσιάστηκε μοιραίο σφάλμα κατά τη φάση προετοιμασίας.", + "A fatal error occurred during installation.": "Παρουσιάστηκε μοιραίο σφάλμα κατά την εγκατάσταση.", + "Installation was canceled while in progress.": "Η εγκατάσταση ακυρώθηκε ενώ βρισκόταν σε εξέλιξη.", + "The installer was terminated by another process.": "Το πρόγραμμα εγκατάστασης τερματίστηκε από άλλη διεργασία.", + "The preparation phase determined the installation cannot proceed.": "Η φάση προετοιμασίας διαπίστωσε ότι η εγκατάσταση δεν μπορεί να συνεχιστεί.", + "The installer could not start. UniGetUI may already be running, or you do not have permission to install.": "Δεν ήταν δυνατή η εκκίνηση του προγράμματος εγκατάστασης. Το UniGetUI μπορεί να εκτελείται ήδη ή να μην έχετε άδεια για εγκατάσταση.", + "Unexpected installer error.": "Μη αναμενόμενο σφάλμα προγράμματος εγκατάστασης.", + "We are checking for updates.": "Ελέγχουμε για αναβαθμίσεις.", + "Please wait": "Παρακαλώ περιμένετε", + "Great! You are on the latest version.": "Τέλεια! Έχετε την πιο πρόσφατη έκδοση.", + "There are no new UniGetUI versions to be installed": "Δεν υπάρχουν νέες εκδόσεις UniGetUI για εγκατάσταση", + "UniGetUI version {0} is being downloaded.": "Η έκδοση {0} του UniGetUI λαμβάνεται.", + "This may take a minute or two": "Αυτό μπορεί να πάρει ένα ή δύο λεπτά", + "The installer authenticity could not be verified.": "Η αυθεντικότητα του προγράμματος εγκατάστασης δεν επιβεβαιώνεται.", + "The update process has been aborted.": "Η διαδικασία ενημέρωση έχει ακυρωθεί.", + "Auto-update is not yet available on this platform.": "Η αυτόματη ενημέρωση δεν είναι ακόμη διαθέσιμη σε αυτήν την πλατφόρμα.", + "Please update UniGetUI manually.": "Ενημερώστε το UniGetUI μη αυτόματα.", + "An error occurred when checking for updates: ": "Παρουσιάστηκε σφάλμα κατά τον έλεγχο για ενημερώσεις:", + "The updater could not be launched.": "Δεν ήταν δυνατή η εκκίνηση του προγράμματος ενημέρωσης.", + "The operating system did not start the installer process.": "Το λειτουργικό σύστημα δεν εκκίνησε τη διεργασία του προγράμματος εγκατάστασης.", + "UniGetUI is being updated...": "Το UniGetUI έχει ενημερωθεί...", + "Update installed.": "Η ενημέρωση εγκαταστάθηκε.", + "UniGetUI was updated successfully, but this running copy was not replaced. This usually means you are running a development build. Close this copy and start the newly-installed version to finish.": "Το UniGetUI ενημερώθηκε με επιτυχία, αλλά αυτό το εκτελούμενο αντίγραφο δεν αντικαταστάθηκε. Αυτό συνήθως σημαίνει ότι εκτελείτε μια έκδοση ανάπτυξης. Κλείστε αυτό το αντίγραφο και ξεκινήστε τη νέα εγκατεστημένη έκδοση για να ολοκληρώσετε.", + "The update could not be applied.": "Δεν ήταν δυνατή η εφαρμογή της ενημέρωσης.", + "Installer exit code {0}: {1}": "Κωδικός εξόδου προγράμματος εγκατάστασης {0}: {1}", + "Update cancelled.": "Η ενημέρωση ακυρώθηκε.", + "Authentication was cancelled.": "Ο έλεγχος ταυτότητας ακυρώθηκε.", + "Installer exit code {0}": "Κωδικός εξόδου προγράμματος εγκατάστασης {0}", + "Operation in progress": "Η εργασία είναι σε εξέλιξη", + "Please wait...": "Παρακαλώ περιμένετε...", + "Success!": "Επιτυχία!", + "Failed": "Απέτυχε", + "An error occurred while processing this package": "Παρουσιάστηκε σφάλμα κατά την επεξεργασία αυτού του πακέτου", + "Installer": "Πρόγραμμα εγκατάστασης", + "Executable": "Εκτελέσιμο αρχείο", + "MSI": "MSI", + "Compressed file": "Συμπιεσμένο αρχείο", + "MSIX": "MSIX", + "WinGet was repaired successfully": "Το WinGet επισκευάστηκε επιτυχώς", + "It is recommended to restart UniGetUI after WinGet has been repaired": "Προτείνεται η επανεκκίνηση του UniGetUI μετά την επισκευή του WinGet", + "WinGet could not be repaired": "Το WinGet δεν μπορεί να επισκευαστεί", + "An unexpected issue occurred while attempting to repair WinGet. Please try again later": "Παρουσιάστηκε μη αναμενόμενο θέμα κατά την προσπάθεια επιδιόρθωσης του WinGet. Δοκιμάστε ξανά αργότερα", + "Log in to enable cloud backup": "Συνδεθείτε για να ενεργοποιήσετε τη δημιουργία αντιγράφων ασφαλείας στο cloud", + "Backup Failed": "Η δημιουργία αντιγράφων ασφαλείας απέτυχε", + "Downloading backup...": "Λήψη αντιγράφου ασφαλείας...", + "An update was found!": "Βρέθηκε ενημέρωση!", + "{0} can be updated to version {1}": "Το {0} μπορεί να ενημερωθεί στην έκδοση {1}", + "Updates found!": "Βρέθηκαν ενημερώσεις!", + "{0} packages can be updated": "{0} πακέτα μπορούν να ενημερωθούν", + "{0} is being updated to version {1}": "Το {0} ενημερώνεται στην έκδοση {1}", + "{0} packages are being updated": "{0} πακέτα ενημερώνονται", + "You have currently version {0} installed": "Αυτήν τη στιγμή έχετε εγκαταστήσει την έκδοση {0}", + "Desktop shortcut created": "Η συντόμευση στην επιφάνεια εργασίας δημιουργήθηκε", + "UniGetUI has detected a new desktop shortcut that can be deleted automatically.": "Το UniGetUI ανίχνευσε μια νέα συντόμευση επιφάνειας εργασίας που μπορεί να διαγραφεί αυτόματα.", + "{0} desktop shortcuts created": "{0} συντομεύσεις επιφάνειας εργασίας δημιουργήθηκαν", + "UniGetUI has detected {0} new desktop shortcuts that can be deleted automatically.": "Το UniGetUI ανίχνευσε {0} νέες συντομεύσεις επιφάνειας εργασίας που μπορούν να διαγραφούν αυτόματα.", + "Attention required": "Απαιτείται προσοχή", + "Restart required": "Απαιτείται επανεκκίνηση", + "1 update is available": "1 ενημέρωση είναι διαθέσιμη", + "{0} updates are available": "{0} ενημερώσεις είναι διαθέσιμες", + "Everything is up to date": "Ολα είναι ενημερωμένα", + "Discover Packages": "Εξερεύνηση Πακέτων", + "Available Updates": "Διαθέσιμες Ενημερώσεις", + "Installed Packages": "Εγκατεστημένα Πακέτα", + "UniGetUI Version {0} by Devolutions": "Έκδοση UniGetUI {0} από τη Devolutions", + "Show UniGetUI": "Εμφάνιση του UniGetUI", + "Quit": "Έξοδος", + "Are you sure?": "Σίγουρα;", + "Do you really want to uninstall {0}?": "Θέλετε σίγουρα να απεγκαταστήσετε το {0};", + "Do you really want to uninstall the following {0} packages?": "Θέλετε πραγματικά να απεγκαταστήσετε τα ακόλουθα {0} πακέτα;", + "No": "Όχι", + "Yes": "Ναι", + "Partial": "Μερικά", + "View on UniGetUI": "Δείτε το στο UniGetUI", + "Update": "Ενημέρωση", + "Open UniGetUI": "Άνοιγμα UniGetUI", + "Update all": "Ενημέρωση όλων", + "Update now": "Ενημέρωση τώρα", + "Installer host changed since the installed version.\n": "Ο κεντρικός υπολογιστής του προγράμματος εγκατάστασης έχει αλλάξει από την εγκατεστημένη έκδοση.\n", + "This package is on the queue": "Αυτό το πακέτο είναι στην ουρά", + "installing": "εγκατάσταση", + "updating": "ενημέρωση", + "uninstalling": "απεγκατάσταση", + "installed": "εγκατεστημένο", + "Retry": "Επανάληψη", + "Install": "Εγκατάσταση", + "Uninstall": "Απεγκατάσταση", + "Open": "Άνοιγμα", + "Operation profile:": "Προφίλ λειτουργίας:", + "Follow the default options when installing, upgrading or uninstalling this package": "Παρακολούθηση των προεπιλεγμένων επιλογών κατά την εγκατάσταση, την αναβάθμιση ή την απεγκατάσταση αυτού του πακέτου", + "The following settings will be applied each time this package is installed, updated or removed.": "Οι ακόλουθες ρυθμίσεις θα εφαρμόζονται κάθε φορά που αυτό το πακέτο εγκαθίσταται, ενημερώνεται ή απομακρύνεται.", + "Version to install:": "Έκδοση για εγκατάσταση:", + "Architecture to install:": "Αρχιτεκτονική για εγκατάσταση:", + "Installation scope:": "Σκοπός εγκατάστασης:", + "Install location:": "Τοποθεσία εγκατάστασης:", + "Select": "Επιλογή", + "Reset": "Επαναφορά", + "Custom install arguments:": "Προσαρμοσμένα ορίσματα εγκατάστασης:", + "Custom update arguments:": "Προσαρμοσμένα ορίσματα ενημέρωσης:", + "Custom uninstall arguments:": "Προσαρμοσμένα ορίσματα απεγκατάστασης:", + "Pre-install command:": "Εντολή πριν την εγκατάσταση:", + "Post-install command:": "Εντολή μετά την εγκατάσταση:", + "Abort install if pre-install command fails": "Διακοπή εγκατάστασης εάν η εντολή πριν την εγκατάσταση αποτύχει", + "Pre-update command:": "Εντολή πριν την ενημέρωση:", + "Post-update command:": "Εντολή μετά την ενημέρωση:", + "Abort update if pre-update command fails": "Διακοπή εγκατάστασης εάν η εντολή πριν την ενημέρωση αποτύχει", + "Pre-uninstall command:": "Εντολή πριν την απεγκατάσταση:", + "Post-uninstall command:": "Εντολή μετά την απεγκατάσταση:", + "Abort uninstall if pre-uninstall command fails": "Διακοπή απεγκατάστασης εάν η εντολή πριν την απεγκατάσταση αποτύχει", + "Command-line to run:": "Γραμμή εντολών για εκτέλεση:", + "Save and close": "Αποθήκευση και κλείσιμο", + "General": "Γενικά", + "Architecture & Location": "Αρχιτεκτονική & Τοποθεσία", + "Command-line": "Γραμμή εντολών", + "Close apps": "Κλείσιμο εφαρμογών", + "Pre/Post install": "Πριν/Μετά την εγκατάσταση", + "Select the processes that should be closed before this package is installed, updated or uninstalled.": "Επιλέξτε τις διεργασίες που θα πρέπει να κλείσουν πριν από την εγκατάσταση, την ενημέρωση ή την απεγκατάσταση αυτού του πακέτου.", + "Write here the process names here, separated by commas (,)": "Γράψτε εδώ τα ονόματα των διεργασιών, διαχωρισμένα με κόμματα (,)", + "Try to kill the processes that refuse to close when requested to": "Προσπάθεια αναγκαστικού τερματισμού των διεργασιών που αρνούνται να κλείσουν όταν τους ζητηθεί", + "Run as admin": "Εκτέλεση ως διαχειριστής", + "Interactive installation": "Διαδραστική εγκατάσταση", + "Skip hash check": "Αγνόηση ελέγχου hash", + "Uninstall previous versions when updated": "Απεγκατάσταση προηγούμενων εκδόσεων κατά την ενημέρωση", + "Skip minor updates for this package": "Αγνόηση μικροενημερώσεων για αυτό το πακέτο", + "Automatically update this package": "Αυτόματη ενημέρωση αυτού του πακέτου", + "{0} installation options": "{0} επιλογές εγκατάστασης", + "Latest": "Τελευταία", + "PreRelease": "Προδημοσίευση", + "Default": "Προεπιλογή", + "Manage ignored updates": "Διαχείριση αγνοημένων ενημερώσεων", + "The packages listed here won't be taken in account when checking for updates. Double-click them or click the button on their right to stop ignoring their updates.": "Τα πακέτα στη λίστα δε θα ληφθούν υπόψη κατά τον έλεγχο για ενημερώσεις. Πατήστε τα διπλά ή πατήστε στο κουμπί στα δεξιά τους για να σταματήσετε να αγνοείτε τις ενημερώσεις τους.", + "Reset list": "Επαναφορά λίστας", + "Do you really want to reset the ignored updates list? This action cannot be reverted": "Θέλετε σίγουρα να επαναφέρετε τη λίστα αγνοημένων ενημερώσεων; Αυτή η ενέργεια δεν μπορεί να αναιρεθεί", + "No ignored updates": "Δεν υπάρχουν αγνοημένες ενημερώσεις", + "Package Name": "Όνομα Πακέτου", + "Package ID": "Ταυτότητα Πακέτου", + "Ignored version": "Αγνοημένη εκδοση", + "New version": "Νέα έκδοση", + "Source": "Προέλευση", + "All versions": "Ολες οι εκδόσεις", + "Unknown": "Άγνωστο", + "Up to date": "Ενημερωμένο", + "Package {name} from {manager}": "Πακέτο {name} από {manager}", + "Remove {0} from ignored updates": "Αφαίρεση του {0} από τις ενημερώσεις που αγνοούνται", + "Cancel": "Άκυρο", + "Administrator privileges": "Δικαιώματα διαχειριστή", + "This operation is running with administrator privileges.": "Αυτή η λειτουργία εκτελείται με δικαιώματα διαχειριστή.", + "Interactive operation": "Διαδραστική λειτουργία", + "This operation is running interactively.": "Αυτή η λειτουργία εκτελείται με αλληλεπίδραση.", + "You will likely need to interact with the installer.": "Πιθανόν, να χρειαστείτε να αλληλεπιδράσετε με το πρόγραμμα εγκατάστασης", + "Integrity checks skipped": "Οι έλεγχοι ακεραιότητας αγνοήθηκαν", + "Integrity checks will not be performed during this operation.": "Δεν θα πραγματοποιηθούν έλεγχοι ακεραιότητας κατά τη διάρκεια αυτής της λειτουργίας.", + "Proceed at your own risk.": "Συνεχίστε με δική σας ευθύνη.", + "Close": "Κλείσιμο", + "Loading...": "Φόρτωση...", + "Installer SHA256": "Πρόγραμμα εγκατάστασης SHA256", + "Homepage": "Ιστοσελίδα", + "Author": "Εκδότης", + "Publisher": "Εκδότης", + "License": "Άδεια", + "Manifest": "Μανιφέστο", + "Installer Type": "Τύπος προγράμματος εγκατάστασης", + "Size": "Μέγεθος", + "Installer URL": "URL προγράμματος εγκατάστασης", + "Last updated:": "Τελευταία ενημέρωση:", + "Release notes URL": "Διεύθυνση URL σημειώσεων έκδοσης", + "Package details": "Λεπτομέρειες πακέτου", + "Dependencies:": "Εξαρτήσεις:", + "Release notes": "Σημειώσεις έκδοσης", + "Screenshots": "Στιγμιότυπα οθόνης", + "This package has no screenshots or is missing the icon? Contribute to UniGetUI by adding the missing icons and screenshots to our open, public database.": "Αυτό το πακέτο δεν έχει στιγμιότυπα οθόνης ή λείπει το εικονίδιο; Συνεισφέρετε στο UniGetUI προσθέτοντας τα εικονίδια και τα στιγμιότυπα οθόνης που λείπουν στην ανοικτή, δημόσια βάση δεδομένων μας.", + "Version": "Εκδοση", + "Install as administrator": "Εγκατάσταση ως διαχειριστής", + "Update to version {0}": "Ενημέρωση στην έκδοση {0}", + "Installed Version": "Εγκατεστημένη Έκδοση", + "Update as administrator": "Ενημέρωση ως διαχειριστής", + "Interactive update": "Διαδραστική ενημέρωση", + "Uninstall as administrator": "Απεγκατάσταση ως διαχειριστής", + "Interactive uninstall": "Διαδραστική απεγκατάσταση", + "Uninstall and remove data": "Απεγκατάσταση και κατάργηση δεδομένων", + "Not available": "Μη διαθέσιμο", + "Installer SHA512": "Πρόγραμμα εγκατάστασης SHA512", + "Unknown size": "Αγνωστο μέγεθος", + "No dependencies specified": "Δεν έχουν καθοριστεί εξαρτήσεις", + "mandatory": "επιτακτικό", + "optional": "προαιρετικό", + "UniGetUI {0} is ready to be installed.": "Το UniGetUI {0} είναι έτοιμο για εγκατάσταση.", + "The update process will start after closing UniGetUI": "Η διαδικασία ενημέρωσης θα εκκινήσει μετά το κλείσιμο του UniGetUI", + "UniGetUI has been ran as administrator, which is not recommended. When running UniGetUI as administrator, EVERY operation launched from UniGetUI will have administrator privileges. You can still use the program, but we highly recommend not running UniGetUI with administrator privileges.": "Το UniGetUI εκτελέστηκε ως διαχειριστής, κάτι που δεν συνιστάται. Όταν το UniGetUI εκτελείται ως διαχειριστής, ΚΑΘΕ λειτουργία που ξεκινά από το UniGetUI θα έχει δικαιώματα διαχειριστή. Μπορείτε να συνεχίσετε να χρησιμοποιείτε το πρόγραμμα, αλλά συνιστούμε ανεπιφύλακτα να μην εκτελείτε το UniGetUI με δικαιώματα διαχειριστή.", + "Share anonymous usage data": "Κοινή χρήση ανώνυμων δεδομένων χρήσης", + "UniGetUI collects anonymous usage data in order to improve the user experience.": "Το UniGetUI συλλέγει ανώνυμα δεδομένα χρήσης ώστε να βελτιώσει την εμπειρία του χρήστη.", + "Accept": "Αποδοχή", + "Software Updates": "Ενημερώσεις Εφαρμογών", + "Package Bundles": "Συλλογές πακέτων", + "Settings": "Ρυθμίσεις", + "Package Managers": "Διαχειριστές πακέτων", + "UniGetUI Log": "Αρχείο καταγραφής UniGetUI", + "Package Manager logs": "Αρχεία καταγραφής διαχειριστή πακέτων", + "Operation history": "Ιστορικό εργασιών", + "Help": "Βοήθεια", + "UniGetUI": "UniGetUI", + "You have installed UniGetUI Version {0}": "Έχετε εγκατεστημένη την έκδοση {0} του UniGetUI", + "Disclaimer": "Δήλωση αποποίησης ευθυνών", + "UniGetUI is developed by Devolutions and is not affiliated with any of the compatible package managers.": "Το UniGetUI αναπτύσσεται από τη Devolutions και δεν συνδέεται με κανέναν από τους συμβατούς διαχειριστές πακέτων.", + "UniGetUI wouldn't have been possible without the help of the contributors. Thank you all 🥳": "Το UniGetUI δε θα ήταν δυνατό χωρίς τη βοήθεια των συνεισφερόντων. Σας ευχαριστώ όλους 🥳", + "UniGetUI uses the following libraries. Without them, UniGetUI wouldn't have been possible.": "Το UniGetUI χρησιμοποιεί τις ακόλουθες βιβλιοθήκες. Χωρίς αυτές, το UniGetUI δε θα υπήρχε.", + "{0} homepage": "Αρχική σελίδα {0}", + "UniGetUI has been translated to more than 40 languages thanks to the volunteer translators. Thank you 🤝": "Το UniGetUI έχει μεταφραστεί σε περισσότερες από 40 γλώσσες χάρη στους εθελοντές μεταφραστές. Ευχαριστώ 🤝", + "Verbose": "Πολύλογος", + "1 - Errors": "1 - Σφάλματα", + "2 - Warnings": "2 - Προειδοποιήσεις", + "3 - Information (less)": "3 - Πληροφορίες (λιγότερες)", + "4 - Information (more)": "4 - Πληροφορίες (περισσότερες)", + "5 - information (debug)": "5 - πληροφορίες (εντοπισμός σφαλμάτων)", + "Warning": "Προειδοποίηση", + "The following settings may pose a security risk, hence they are disabled by default.": "Οι ακόλουθες ρυθμίσεις ενδέχεται να θέτουν σε κίνδυνο την ασφάλεια, επομένως είναι απενεργοποιημένες από προεπιλογή.", + "Enable the settings below if and only if you fully understand what they do, and the implications they may have.": "Ενεργοποιήστε τις παρακάτω ρυθμίσεις αν και μόνο αν κατανοείτε πλήρως τι κάνουν και τις πιθανές επιπτώσεις τους.", + "The settings will list, in their descriptions, the potential security issues they may have.": "Οι ρυθμίσεις θα αναφέρουν, στις περιγραφές τους, τα πιθανά προβλήματα ασφαλείας που ενδέχεται να έχουν.", + "The backup will include the complete list of the installed packages and their installation options. Ignored updates and skipped versions will also be saved.": "Το αντίγραφο ασφαλείας θα περιλαμβάνει την πλήρη λίστα των εγκατεστημένων πακέτων και τις επιλογές εγκατάστασής τους. Οι ενημερώσεις που αγνοήθηκαν και οι εκδόσεις που παραλήφθηκαν θα αποθηκευτούν επίσης.", + "The backup will NOT include any binary file nor any program's saved data.": "Το αντίγραφο ασφαλείας ΔΕΝ θα περιλαμβάνει κανένα δυαδικό αρχείο ούτε αποθηκευμένα δεδομένα οποιουδήποτε προγράμματος.", + "The size of the backup is estimated to be less than 1MB.": "Το μέγεθος του αντιγράφου ασφαλείας εκτιμάται ότι είναι μικρότερο από 1 MB.", + "The backup will be performed after login.": "Το αντίγραφο ασφαλείας θα δημιουργηθεί κατά τη σύνδεση.", + "{pcName} installed packages": "Εγκατεστημένα πακέτα στο {pcName}", + "Current status: Not logged in": "Τρέχουσα κατάσταση: Δεν έχετε συνδεθεί", + "You are logged in as {0} (@{1})": "Εχετε συνδεθεί ως {0} (@{1})", + "Nice! Backups will be uploaded to a private gist on your account": "Ωραία! Τα αντίγραφα ασφαλείας θα μεταφορτωθούν σε ένα ιδιωτικό gist στον λογαριασμό σας.", + "Select backup": "Επιλέξτε αντίγραφο ασφαλείας", + "Settings imported from {0}": "Οι ρυθμίσεις εισήχθησαν από το {0}", + "UniGetUI Settings": "Ρυθμίσεις UniGetUI", + "Settings exported to {0}": "Οι ρυθμίσεις εξήχθησαν στο {0}", + "UniGetUI settings were reset": "Οι ρυθμίσεις του UniGetUI επαναφέρθηκαν", + "Allow pre-release versions": "Να επιτρέπονται pre-release εκδόσεις ", + "Apply": "Εφαρμογή", + "For security reasons, custom command-line arguments are disabled by default. Go to UniGetUI security settings to change this.": "Για λόγους ασφαλείας, τα προσαρμοσμένα ορίσματα γραμμής εντολών είναι απενεργοποιημένα από προεπιλογή. Μεταβείτε στις ρυθμίσεις ασφαλείας του UniGetUI για να το αλλάξετε.", + "Go to UniGetUI security settings": "Μετάβαση στις ρυθμίσεις ασφαλείας του UniGetUI", + "The following options will be applied by default each time a {0} package is installed, upgraded or uninstalled.": "Οι ακόλουθες επιλογές θα εφαρμόζονται από προεπιλογή κάθε φορά που εγκαθίσταται, αναβαθμίζεται ή απεγκαθίσταται ένα πακέτο {0}.", + "Package's default": "Προεπιλογή πακέτου", + "Install location can't be changed for {0} packages": "Η τοποθεσία εγκατάστασης δεν μπορεί να αλλάξει για {0} πακέτα", + "The local icon cache currently takes {0} MB": "Η τρέχουσα τοπική μνήμη cache εικονιδίων καταλαμβάνει {0} MB", + "Username": "Όνομα χρήστη", + "Password": "Κωδικός πρόσβασης", + "Credentials": "Διαπιστευτήρια", + "It is not guaranteed that the provided credentials will be stored safely": "Δεν είναι εγγυημένο ότι τα παρεχόμενα διαπιστευτήρια θα αποθηκευτούν με ασφάλεια", + "Partially": "Τμηματικά", + "Package manager": "Διαχειριστής πακέτων", + "Compatible with proxy": "Συμβατό με διακομιστή", + "Compatible with authentication": "Συμβατό με πιστοποίηση", + "Proxy compatibility table": "Πίνακας συμβατότητας διακομιστή", + "{0} settings": "{0} ρυθμίσεις", + "{0} status": "{0} κατάσταση", + "Default installation options for {0} packages": "Προεπιλεγμένες επιλογές εγκατάστασης για {0} πακέτα", + "Expand version": "Έκδοση επέκτασης", + "The executable file for {0} was not found": "Το εκτελέσιμο αρχείο για {0} δεν βρέθηκε", + "{pm} is disabled": "Το {pm} είναι απενεργοποιημένο", + "Enable it to install packages from {pm}.": "Ενεργοποίηση για εγκατάσταση πακέτων από {pm}.", + "{pm} is enabled and ready to go": "Το {pm} είναι ενεργοποιημένο και έτοιμο για χρήση", + "{pm} version:": "Εκδοση {pm}:", + "{pm} was not found!": "Το {pm} δεν βρέθηκε!", + "You may need to install {pm} in order to use it with UniGetUI.": "Ίσως χρειαστεί να εγκαταστήσετε το {pm} για να το χρησιμοποιήσετε με το UniGetUI.", + "Scoop Installer - UniGetUI": "Πρόγραμμα εγκατάστασης Scoop - UniGetUI", + "Scoop Uninstaller - UniGetUI": "Πρόγραμμα απεγκατάστασης Scoop - UniGetUI", + "Clearing Scoop cache - UniGetUI": "Εκκαθάριση μνήμης cache του Scoop - UniGetUI", + "Restart UniGetUI to fully apply changes": "Επανεκκινήστε το UniGetUI για να εφαρμοστούν πλήρως οι αλλαγές", + "Restart UniGetUI": "Επανεκκίνηση του UniGetUI", + "Manage {0} sources": "Διαχείριση προελεύσεων {0}", + "Add source": "Προσθήκη προέλευσης", + "Add": "Προσθήκη", + "Source name": "Όνομα προέλευσης", + "Source URL": "URL προέλευσης", + "Other": "Άλλο", + "No minimum age": "Χωρίς ελάχιστο όριο ηλικίας", + "1 day": "1 ημέρα", + "{0} days": "{0} ημέρες", + "Custom...": "Προσαρμοσμένο...", + "{0} minutes": "{0} λεπτά", + "1 hour": "1 ώρα", + "{0} hours": "{0} ώρες", + "1 week": "1 εβδομάδα", + "Supports release dates": "Υποστηρίζει ημερομηνίες έκδοσης", + "Release date support per package manager": "Υποστήριξη ημερομηνιών έκδοσης ανά διαχειριστή πακέτων", + "Search for packages": "Αναζήτηση πακέτων", + "Local": "Τοπικό", + "OK": "ΕΝΤΆΞΕΙ", + "Last checked: {0}": "Τελευταίος έλεγχος: {0}", + "{0} packages were found, {1} of which match the specified filters.": "Βρέθηκαν {0} πακέτα, {1} από τα οποία ταιριάζουν με τα καθορισμένα φίλτρα.", + "{0} selected": "{0} επιλεγμένα", + "(Last checked: {0})": "(Τελευταίος έλεγχος: {0})", + "All packages selected": "Επιλέχθηκαν όλα τα πακέτα", + "Package selection cleared": "Η επιλογή πακέτων εκκαθαρίστηκε", + "{0}: {1}": "{0}: {1}", + "More info": "Περισσότερες πληροφορίες", + "GitHub account": "Λογαριασμός GitHub", + "Log in with GitHub to enable cloud package backup.": "Συνδεθείτε με το GitHub για να ενεργοποιήσετε τη δημιουργία αντιγράφων ασφαλείας πακέτων στο cloud.", + "More details": "Περισσότερες λεπτομέρειες", + "Log in": "Σύνδεση", + "If you have cloud backup enabled, it will be saved as a GitHub Gist on this account": "Εάν έχετε ενεργοποιήσει τη δημιουργία αντιγράφων ασφαλείας στο cloud, θα αποθηκευτεί ως GitHub Gist σε αυτόν τον λογαριασμό.", + "Log out": "Αποσύνδεση", + "About UniGetUI": "Σχετικά με το UniGetUI", + "About": "Σχετικά", + "Third-party licenses": "Αδειες τρίτων", + "Contributors": "Συνεισφέροντες", + "Translators": "Μεταφραστές", + "Bundle security report": "Αναφορά ασφαλείας συλλογής", + "The bundle contained restricted content": "Η συλλογή περιείχε περιορισμένο περιεχόμενο", + "UniGetUI – Crash Report": "UniGetUI – Αναφορά σφάλματος", + "UniGetUI has crashed": "Το UniGetUI κατέρρευσε", + "Help us fix this by sending a crash report to Devolutions. All fields below are optional.": "Βοηθήστε μας να το διορθώσουμε στέλνοντας μια αναφορά σφάλματος στη Devolutions. Όλα τα παρακάτω πεδία είναι προαιρετικά.", + "Email (optional)": "Email (προαιρετικό)", + "your@email.com": "your@email.com", + "Additional details (optional)": "Πρόσθετες λεπτομέρειες (προαιρετικό)", + "Describe what you were doing when the crash occurred…": "Περιγράψτε τι κάνατε όταν παρουσιάστηκε το σφάλμα…", + "Crash report": "Αναφορά σφάλματος", + "Don't Send": "Να μην σταλεί", + "Send Report": "Αποστολή αναφοράς", + "Sending…": "Αποστολή…", + "Unsaved changes": "Μη αποθηκευμένες αλλαγές", + "You have unsaved changes in the current bundle. Do you want to discard them?": "Υπάρχουν μη αποθηκευμένες αλλαγές στην τρέχουσα συλλογή. Θέλετε να τις απορρίψετε;", + "Discard changes": "Απόρριψη αλλαγών", + "Integrity violation": "Παραβίαση ακεραιότητας", + "UniGetUI or some of its components are missing or corrupt. It is strongly recommended to reinstall UniGetUI to adress the situation.": "Το UniGetUI ή ορισμένα από τα στοιχεία του λείπουν ή είναι κατεστραμμένα. Συνιστάται ανεπιφύλακτα να εγκαταστήσετε ξανά το UniGetUI για να αντιμετωπίσετε την κατάσταση.", + "• Refer to the UniGetUI Logs to get more details regarding the affected file(s)": "• Ανατρέξτε στα αρχεία καταγραφής UniGetUI για να λάβετε περισσότερες λεπτομέρειες σχετικά με τα αρχεία που επηρεάζονται.", + "• Integrity checks can be disabled from the Experimental Settings": "• Οι έλεγχοι ακεραιότητας μπορούν να απενεργοποιηθούν από τις πειραματικές ρυθμίσεις", + "Manage shortcuts": "Διαχείριση συντομεύσεων", + "UniGetUI has detected the following desktop shortcuts which can be removed automatically on future upgrades": "Το UniGetUI ανίχνευσε τις ακόλουθες συντομεύσεις επιφάνειας εργασίας που μπορούν να απομακρυνθούν αυτόματα σε μελλοντικές αναβαθμίσεις", + "Do you really want to reset this list? This action cannot be reverted.": "Θέλετε να επαναφέρεται αυτή τη λίστα; Αυτή η ενέργεια δεν είναι αναστρέψιμη.", + "Desktop shortcuts list": "Λίστα συντομεύσεων επιφάνειας εργασίας", + "Open in explorer": "Άνοιγμα στην Εξερεύνηση", + "Remove from list": "Απομάκρυνση από τη λίστα", + "When new shortcuts are detected, delete them automatically instead of showing this dialog.": "Όταν νέες συντομεύσεις ανιχνεύονται θα διαγράφονται αυτόματα αντί για εμφάνιση αυτού του παραθύρου.", + "Not right now": "Οχι ακριβώς τώρα", + "Missing dependency": "Απολεσθείσα εξάρτηση", + "UniGetUI requires {0} to operate, but it was not found on your system.": "Το UniGetUI απαιτεί {0} για να λειτουργήσει αλλά δεν βρέθηκε στο σύστημά σας.", + "Click on Install to begin the installation process. If you skip the installation, UniGetUI may not work as expected.": "Πατήστε στο κουμπί Εγκατάσταση για έναρξη της διαδικασίας εγκατάστασης. Αν παραλείψετε την εγκατάσταση, το UniGetUI ίσως δεν λειτουργεί όπως αναμένεται.", + "Alternatively, you can also install {0} by running the following command in a Windows PowerShell prompt:": "Εναλλακτικά, μπορείτε να εγκαταστήσετε το {0} εκτελόντας την ακόλουθη εντολή στο Windows PowerShell:", + "Install {0}": "Εγκατάσταση {0} ", + "Do not show this dialog again for {0}": "Μην εμφανίσετε ξανά αυτό το παράθυρο για το {0}", + "Please wait while {0} is being installed. A black window may show up. Please wait until it closes.": "Περιμένετε όσο γίνεται εγκατάσταση του {0}. Μπορεί να εμφανιστεί ένα μαύρο παράθυρο. Περιμένετε μέχρι να κλείσει.", + "{0} has been installed successfully.": "Το {0} εγκαταστάθηκε με επιτυχία", + "Please click on \"Continue\" to continue": "Πατήστε στο «Συνέχεια» για να συνεχίσετε", + "Continue": "Συνέχεια", + "{0} has been installed successfully. It is recommended to restart UniGetUI to finish the installation": "Το {0} εγκαταστάθηκε με επιτυχία. Συνιστάται η επανεκκίνηση του UniGetUI για την ολοκλήρωση της εγκατάστασης", + "Restart later": "Επανεκκίνηση αργότερα", + "An error occurred:": "Παρουσιάστηκε σφάλμα:", + "Please see the Command-line Output or refer to the Operation History for further information about the issue.": "Δείτε τον Κώδικα της Γραμμής Εντολών ή ανατρέξτε στο Ιστορικό Εργασιών για περισσότερες πληροφορίες σχετικά με το ζήτημα.", + "Retry as administrator": "Επανάληψη ως διαχειριστής", + "Retry interactively": "Διαδραστική επανάληψη", + "Retry skipping integrity checks": "Επανάληψη αγνοώντας ελέγχους ακεραιότητας", + "Installation options": "Επιλογές εγκατάστασης", + "Save": "Αποθήκευση", + "UniGetUI collects anonymous usage data with the sole purpose of understanding and improving the user experience.": "Το UniGetUI συλλέγει ανώνυμα δεδομένα χρήσης με μοναδικό σκοπό κατανόησης και βελτίωσης της εμπειρίας χρήσης.", + "More details about the shared data and how it will be processed": "Περισσότερες λεπτομέρειες σχετικά με τα κοινόχρηστα δεδομένα και πως θα επεξεργαστούν", + "Do you accept that UniGetUI collects and sends anonymous usage statistics, with the sole purpose of understanding and improving the user experience?": "Αποδέχεστε ότι το UniGetUI συλλέγει και αποστέλλει ανώνυμα στατιστικά στοιχεία χρήσης, με μοναδικό σκοπό την κατανόηση και τη βελτίωση της εμπειρίας χρήστη;", + "Decline": "Απόρριψη", + "No personal information is collected nor sent, and the collected data is anonimized, so it can't be back-tracked to you.": "Καμιά προσωπική πληροφορία δε συλλέγεται ούτε αποστέλλεται και τα συλλεχθέντα δεδομένα είναι ανώνυμα, έτσι δεν μπορούν να αντιστοιχιστούν με εσάς.", + "Navigation panel": "Πίνακας πλοήγησης", + "Operations": "Εργασίες", + "Toggle operations panel": "Εμφάνιση/απόκρυψη πίνακα λειτουργιών", + "Bulk operations": "Μαζικές λειτουργίες", + "Retry failed": "Επανάληψη αποτυχημένων", + "Clear successful": "Εκκαθάριση επιτυχημένων", + "Clear finished": "Εκκαθάριση ολοκληρωμένων", + "Cancel all": "Ακύρωση όλων", + "More": "Περισσότερα", + "Toggle navigation panel": "Εναλλαγή πίνακα περιήγησης", + "Minimize": "Ελαχιστοποίηση", + "Maximize": "Μεγιστοποίηση", + "UniGetUI by Devolutions": "UniGetUI από τη Devolutions", + "UniGetUI is an application that makes managing your software easier, by providing an all-in-one graphical interface for your command-line package managers.": "Το UniGetUI είναι μια εφαρμογή που διευκολύνει τη διαχείριση του λογισμικού σας, παρέχοντας ένα γραφικό περιβάλλον χρήστη όλα σε ένα για τους διαχειριστές πακέτων γραμμής εντολών σας.", + "Useful links": "Χρήσιμοι σύνδεσμοι", + "UniGetUI Homepage": "Αρχική σελίδα του UniGetUI", + "Report an issue or submit a feature request": "Αναφέρετε ένα πρόβλημα ή υποβάλετε ένα αίτημα νέου χαρακτηριστικού", + "UniGetUI Repository": "Αποθετήριο UniGetUI", + "View GitHub Profile": "Προβολή προφίλ στο GitHub", + "UniGetUI License": "Αδεια UniGetUI", + "Using UniGetUI implies the acceptation of the MIT License": "Η χρήση του UniGetUI συνεπάγεται την αποδοχή της άδειας MIT", + "Become a translator": "Γίνετε μεταφραστής", + "Go back": "Πίσω", + "Go forward": "Μπροστά", + "Go to home page": "Μετάβαση στην αρχική σελίδα", + "Reload page": "Επαναφόρτωση σελίδας", + "View page on browser": "Προβολή σελίδας στο πρόγραμμα περιήγησης", + "The built-in browser is not supported on Linux yet.": "Το ενσωματωμένο πρόγραμμα περιήγησης δεν υποστηρίζεται ακόμα στο Linux.", + "Open in browser": "Άνοιγμα στο πρόγραμμα περιήγησης", + "Copy to clipboard": "Αντιγραφή στο πρόχειρο", + "Export to a file": "Εξαγωγή σε αρχείο", + "Log level:": "Επίπεδο καταγραφής:", + "Reload log": "Επαναφόρτωση αρχείου καταγραφής", + "Export log": "Εξαγωγή αρχείου καταγραφής", + "Text": "Κείμενο", + "Change how operations request administrator rights": "Αλλαγή του τρόπου αίτησης για δικαιώματα διαχειριστή", + "Restrictions on package operations": "Περιορισμοί στις λειτουργίες πακέτων", + "Restrictions on package managers": "Περιορισμοί στους διαχειριστές πακέτων", + "Restrictions when importing package bundles": "Περιορισμοί κατά την εισαγωγή συλλογών", + "Ask for administrator privileges once for each batch of operations": "Ερώτημα για δικαιώματα διαχειριστή μία φορά για κάθε δέσμη εργασιών", + "Ask only once for administrator privileges": "Ερώτηση μόνο μια φορά για δικαιώματα διαχειριστή", + "Prohibit any kind of Elevation via UniGetUI Elevator or GSudo": "Αποτροπή οποιουδήποτε είδους αύξησης των δικαιωμάτων μέσω του UniGetUI Elevator ή του GSudo", + "This option WILL cause issues. Any operation incapable of elevating itself WILL FAIL. Install/update/uninstall as administrator will NOT WORK.": "Αυτή η επιλογή ΘΑ προκαλέσει προβλήματα. Οποιαδήποτε λειτουργία δεν μπορεί να λάβει αυξημένα δικαιώματα μόνη της ΘΑ ΑΠΟΤΥΧΕΙ. Η εγκατάσταση/ενημέρωση/απεγκατάσταση ως διαχειριστής ΔΕΝ θα λειτουργήσει.", + "Allow custom command-line arguments": "Να επιτρέπονται προσαρμοσμένα ορίσματα γραμμής εντολών", + "Custom command-line arguments can change the way in which programs are installed, upgraded or uninstalled, in a way UniGetUI cannot control. Using custom command-lines can break packages. Proceed with caution.": "Τα προσαρμοσμένα ορίσματα γραμμής εντολών μπορούν να αλλάξουν τον τρόπο με τον οποίο εγκαθίστανται, αναβαθμίζονται ή απεγκαθίστανται τα προγράμματα, με τρόπο που το UniGetUI δεν μπορεί να ελέγξει. Η χρήση προσαρμοσμένων γραμμών εντολών μπορεί να προκαλέσει προβλήματα στα πακέτα. Προχωρήστε με προσοχή.", + "Ignore custom pre-install and post-install commands when importing packages from a bundle": "Να επιτρέπεται η εκτέλεση προσαρμοσμένων εντολών πριν και μετά την εγκατάσταση κατά την εισαγωγή πακέτων από συλλογή", + "Pre and post install commands will be run before and after a package gets installed, upgraded or uninstalled. Be aware that they may break things unless used carefully": "Οι εντολές πριν και μετά την εγκατάσταση θα εκτελούνται πριν και μετά την εγκατάσταση, την αναβάθμιση ή την απεγκατάσταση ενός πακέτου. Λάβετε υπόψη ότι ενδέχεται να προκαλέσουν βλάβη, εκτός εάν χρησιμοποιηθούν προσεκτικά.", + "Allow changing the paths for package manager executables": "Να επιτρέπεται αλλαγή των διαδρομών για τα εκτελέσιμα αρχεία του διαχειριστή πακέτων", + "Turning this on enables changing the executable file used to interact with package managers. While this allows finer-grained customization of your install processes, it may also be dangerous": "Η ενεργοποίηση αυτής της επιλογής επιτρέπει την αλλαγή του εκτελέσιμου αρχείου που χρησιμοποιείται για την αλληλεπίδραση με τους διαχειριστές πακέτων. Ενώ αυτό επιτρέπει την πιο λεπτομερή προσαρμογή των διαδικασιών εγκατάστασης, μπορεί επίσης να είναι επικίνδυνο.", + "Allow importing custom command-line arguments when importing packages from a bundle": "Να επιτρέπεται η εισαγωγή προσαρμοσμένων ορισμάτων γραμμής εντολών κατά την εισαγωγή πακέτων από μια συλλογή", + "Malformed command-line arguments can break packages, or even allow a malicious actor to gain privileged execution. Therefore, importing custom command-line arguments is disabled by default": "Τα λανθασμένα μορφοποιημένα ορίσματα γραμμής εντολών μπορούν να προκαλέσουν βλάβη στα πακέτα ή ακόμα και να επιτρέψουν σε έναν κακόβουλο παράγοντα να αποκτήσει προνομιακή εκτέλεση. Επομένως, η εισαγωγή προσαρμοσμένων ορισμάτων γραμμής εντολών είναι απενεργοποιημένη από προεπιλογή.", + "Allow importing custom pre-install and post-install commands when importing packages from a bundle": "Επιτρέψτε την εισαγωγή προσαρμοσμένων εντολών πριν και μετά την εγκατάσταση κατά την εισαγωγή πακέτων από μια συλλογή", + "Pre and post install commands can do very nasty things to your device, if designed to do so. It can be very dangerous to import the commands from a bundle, unless you trust the source of that package bundle": "Οι εντολές πριν και μετά την εγκατάσταση μπορούν να κάνουν πολύ άσχημα πράγματα στη συσκευή σας, εάν έχουν σχεδιαστεί για αυτό. Μπορεί να είναι πολύ επικίνδυνο να εισάγετε τις εντολές από μια συλλογή, εκτός αν εμπιστεύεστε την πηγή αυτής της συλλογής.", + "Administrator rights and other dangerous settings": "Δικαιώματα διαχειριστή και άλλες επικίνδυνες ρυθμίσεις", + "Package backup": "Αντίγραφο ασφαλείας πακέτου", + "Cloud package backup": "Αντίγραφο ασφαλείας πακέτων στο cloud", + "Local package backup": "Τοπικά αντίγραφο ασφαλείας πακέτων", + "Local backup advanced options": "Προηγμένες επιλογές τοπικών αντιγράφων ασφαλείας", + "Log in with GitHub": "Σύνδεση με GitHub", + "Log out from GitHub": "Αποσύνδεση από το GitHub", + "Periodically perform a cloud backup of the installed packages": "Περιοδική δημιουργία αντιγράφων ασφαλείας των εγκατεστημένων πακέτων στο cloud", + "Cloud backup uses a private GitHub Gist to store a list of installed packages": "Το backup στο cloud χρησιμοποιεί ένα ιδιωτικό GitHub Gist για την αποθήκευση μιας λίστας εγκατεστημένων πακέτων.", + "Perform a cloud backup now": "Δημιουργία ενός αντιγράφου ασφαλείας στο cloud τώρα ", + "Backup": "Aντίγραφο ασφαλείας", + "Restore a backup from the cloud": "Επαναφορά ενός αντιγράφου ασφαλείας από το cloud", + "Begin the process to select a cloud backup and review which packages to restore": "Ξεκινήστε τη διαδικασία επιλογής ενός αντιγράφου ασφαλείας στο cloud και ελέγξτε ποια πακέτα θα επαναφέρετε", + "Periodically perform a local backup of the installed packages": "Περιοδική δημιουργία τοπικών αντιγράφων ασφαλείας των εγκατεστημένων πακέτων", + "Perform a local backup now": "Δημιουργία ενός τοπικού αντιγράφου ασφαλείας τώρα ", + "Change backup output directory": "Αλλαγή φακέλου εξαγωγής αντιγράφου ασφαλείας", + "Set a custom backup file name": "Ορίστε ένα προσαρμοσμένο όνομα αρχείου αντιγράφου ασφαλείας", + "Leave empty for default": "Αφήστε το κενό για προεπιλογή", + "Add a timestamp to the backup file names": "Προσθήκη χρονοσφραγίδας στα ονόματα των αρχείων αντιγράφων ασφαλείας", + "Backup and Restore": "Αντίγραφα ασφαλείας και επαναφορά", + "Enable background api (UniGetUI Widgets and Sharing, port 7058)": "Ενεργοποίηση API παρασκηνίου (Widgets για UniGetUI και Κοινή Χρήση, θύρα 7058)", + "Wait for the device to be connected to the internet before attempting to do tasks that require internet connectivity.": "Περιμένετε να συνδεθεί η συσκευή στο διαδίκτυο πριν επιχειρήσετε να κάνετε εργασίες που απαιτούν σύνδεση στο Διαδίκτυο.", + "Disable the 1-minute timeout for package-related operations": "Απενεργοποίηση χρονικού ορίου 1 λεπτού για λειτουργίες που σχετίζονται με πακέτα", + "Use installed GSudo instead of UniGetUI Elevator": "Χρήση του εγκατεστημένου GSudo αντί για το UniGetUI Elevator", + "Use a custom icon and screenshot database URL": "Χρήση διεύθυνσης URL προσαρμοσμένης βάσης δεδομένων για εικονίδια και στιγμιότυπα οθόνης", + "Enable background CPU Usage optimizations (see Pull Request #3278)": "Ενεργοποίηση βελτιστοποιήσεων χρήσης CPU υποβάθρου (δείτε το Αίτημα #3278)", + "Perform integrity checks at startup": "Εκτέλεση ελέγχων ακεραιότητας κατά την εκκίνηση", + "When batch installing packages from a bundle, install also packages that are already installed": "Κατά την μαζική εγκατάσταση πακέτων από μια συλλογή, εγκαταστήστε επίσης πακέτα που είναι ήδη εγκατεστημένα", + "Experimental settings and developer options": "Πειραματικές ρυθμίσεις και επιλογές για προγραμματιστές", + "Show UniGetUI's version and build number on the titlebar.": "Προβολή της έκδοσης του UniGetUI στη γραμμή τίτλου", + "Language": "Γλώσσα", + "UniGetUI updater": "Αναβαθμιστής UniGetUI", + "Telemetry": "Τηλεμετρία", + "Manage UniGetUI settings": "Διαχείριση ρυθμίσεων UniGetUI", + "Related settings": "Σχετικές ρυθμίσεις", + "Update UniGetUI automatically": "Αυτόματη ενημέρωση UniGetUI", + "Check for updates": "Έλεγχος για ενημερώσεις", + "Install prerelease versions of UniGetUI": "Εγκατάσταση προδημοσιευμένων εκδόσεων του UniGetUI", + "Manage telemetry settings": "Διαχείριση ρυθμίσεων τηλεμετρίας", + "Manage": "Διαχείριση", + "Import settings from a local file": "Εισαγωγή ρυθμίσεων απο τοπικό αρχείο", + "Import": "Εισαγωγή", + "Export settings to a local file": "Εξαγωγή ρυθμίσεων σε τοπικό αρχείο", + "Export": "Εξαγωγή", + "Reset UniGetUI": "Επαναφορά του UniGetUI", + "User interface preferences": "Προτιμήσεις περιβάλλοντος χρήστη", + "Application theme, startup page, package icons, clear successful installs automatically": "Θέμα εφαρμογής, σελίδα εκκίνησης, εικονίδια πακέτου, εκκαθάριση επιτυχών εγκαταστάσεων αυτόματα", + "General preferences": "Γενικές προτιμήσεις", + "UniGetUI display language:": "Γλώσσα εμφάνισης UniGetUI:", + "System language": "Γλώσσα συστήματος", + "Is your language missing or incomplete?": "Η γλώσσα σας λείπει ή είναι ημιτελής;", + "Appearance": "Εμφάνιση", + "UniGetUI on the background and system tray": "Το UniGetUI στο υπόβαθρο και στη γραμμή εργασιών", + "Package lists": "Λίστες πακέτων", + "Use classic mode": "Χρήση κλασικής λειτουργίας", + "Restart UniGetUI to apply this change": "Επανεκκινήστε το UniGetUI για να εφαρμοστεί αυτή η αλλαγή", + "The classic UI is disabled for beta testers": "Το κλασικό περιβάλλον χρήστη είναι απενεργοποιημένο για τους δοκιμαστές beta", + "Close UniGetUI to the system tray": "Κλείσιμο του UniGetUI στη γραμμή εργασιών", + "Manage UniGetUI autostart behaviour": "Διαχείριση συμπεριφοράς αυτόματης εκκίνησης του UniGetUI", + "Show package icons on package lists": "Εμφάνιση εικονιδίων πακέτων στις λίστες πακέτων", + "Clear cache": "Εκκαθάριση μνήμης cache", + "Select upgradable packages by default": "Επιλογή αναβαθμίσιμων πακέτων από προεπιλογή", + "Light": "Φωτεινό", + "Dark": "Σκοτεινό", + "Follow system color scheme": "Χρήση χρωμάτων συστήματος", + "Application theme:": "Θέμα εφαρμογής:", + "UniGetUI startup page:": "Σελίδα έναρξης του UniGetUI:", + "Proxy settings": "Ρυθμίσεις διακομιστή", + "Other settings": "Άλλες ρυθμίσεις", + "Connect the internet using a custom proxy": "Σύνδεση στο διαδίκτυο με χρήση προσαρμοσμένου διακομιστή", + "Please note that not all package managers may fully support this feature": "Σημειώστε ότι αυτό το το χαρακτηριστικό δεν υποστηρίζεται πλήρως από όλους τους διαχειριστές πακέτων", + "Proxy URL": "URL διακομιστή", + "Enter proxy URL here": "Εισαγωγή URL διακομιστή εδώ", + "Authenticate to the proxy with a user and a password": "Έλεγχος ταυτότητας στον διακομιστή μεσολάβησης με όνομα χρήστη και κωδικό πρόσβασης", + "Internet and proxy settings": "Ρυθμίσεις διαδικτύου και διακομιστή μεσολάβησης", + "Package manager preferences": "Προτιμήσεις διαχειριστή πακέτων", + "Ready": "Ετοιμο", + "Not found": "Δεν βρέθηκε", + "Notification preferences": "Προτιμήσεις ειδοποιήσεων", + "Notification types": "Τύποι ειδοποιήσεων", + "The system tray icon must be enabled in order for notifications to work": "Το εικονίδιο στη γραμμή εργασιών πρέπει να ενεργοποιηθεί ώστε να δουλεύουν οι ειδοποιήσεις", + "Enable UniGetUI notifications": "Ενεργοποίηση ειδοποιήσεων UniGetUI", + "Show a notification when there are available updates": "Εμφάνιση ειδοποίησης όταν υπάρχουν διαθέσιμες ενημερώσεις", + "Show a silent notification when an operation is running": "Εμφάνιση σιωπηλής ειδοποίησης όταν εκτελείται μια λειτουργία", + "Show a notification when an operation fails": "Εμφάνιση ειδοποίησης όταν μια λειτουργία αποτυγχάνει", + "Show a notification when an operation finishes successfully": "Εμφάνιση ειδοποίησης όταν μια λειτουργία ολοκληρώνεται επιτυχώς", + "Concurrency and execution": "Συγχρονισμός και εκτέλεση", + "Automatic desktop shortcut remover": "Αυτόματο πρόγραμμα απομάκρυνσης συντόμευσης επιφάνειας εργασίας", + "Choose how many operations should be performed in parallel": "Επιλέξτε πόσες λειτουργίες πρέπει να εκτελούνται παράλληλα", + "Clear successful operations from the operation list after a 5 second delay": "Εκκαθάριση επιτυχώς ολοκληρωμένων λειτουργιών από τη λίστα λειτουργιών μετά από καθυστέρηση 5 δευτερολέπτων", + "Download operations are not affected by this setting": "Οι λειτουργίες λήψης δεν επηρεάζονται από αυτή τη ρύθμιση", + "You may lose unsaved data": "Ενδέχεται να χάσετε μη αποθηκευμένα δεδομένα", + "Ask to delete desktop shortcuts created during an install or upgrade.": "Ερώτηση πριν τη διαγραφή των συντομεύσεων επιφάνειας εργασίας που δημιουργήθηκαν κατά την εγκατάσταση ή την αναβάθμιση.", + "Package update preferences": "Προτιμήσεις ενημέρωσης πακέτου", + "Update check frequency, automatically install updates, etc.": "Συχνότητα ελέγχου για ενημερώσεις, αυτόματη εγκατάσταση ενημερώσεων κλπ.", + "Reduce UAC prompts, elevate installations by default, unlock certain dangerous features, etc.": "Μείωση των προτροπών UAC, αύξηση των δικαιωμάτων των εγκαταστάσεων από προεπιλογή, ξεκλείδωμα ορισμένων επικίνδυνων λειτουργιών κ.λπ.", + "Package operation preferences": "Προτιμήσεις λειτουργίας πακέτου", + "Enable {pm}": "Ενεργοποίηση {pm}", + "Not finding the file you are looking for? Make sure it has been added to path.": "Δεν βρίσκετε το αρχείο που ψάχνετε; Βεβαιωθείτε ότι έχει προστεθεί στη διαδρομή.", + "Select the executable to be used. The following list shows the executables found by UniGetUI": "Επιλέξτε το εκτελέσιμο αρχείο που θα χρησιμοποιηθεί. Η ακόλουθη λίστα εμφανίζει τα εκτελέσιμα αρχεία που βρέθηκαν από το UniGetUI", + "For security reasons, changing the executable file is disabled by default": "Για λόγους ασφαλείας, η αλλαγή του εκτελέσιμου αρχείου είναι απενεργοποιημένη από προεπιλογή.", + "Change this": "Αλλαγή αυτού", + "Copy path": "Αντιγραφή διαδρομής", + "Current executable file:": "Τρέχον εκτελέσιμο αρχείο:", + "Ignore packages from {pm} when showing a notification about updates": "Αγνόηση πακέτων από το {pm} όταν εμφανίζεται ειδοποίηση για ενημερώσεις", + "Update security": "Ασφάλεια ενημερώσεων", + "Use global setting": "Χρήση καθολικής ρύθμισης", + "Minimum age for updates": "Ελάχιστη ηλικία για ενημερώσεις", + "e.g. 10": "π.χ. 10", + "Custom minimum age (days)": "Προσαρμοσμένη ελάχιστη ηλικία (ημέρες)", + "{pm} does not provide release dates for its packages, so this setting will have no effect": "Το {pm} δεν παρέχει ημερομηνίες έκδοσης για τα πακέτα του, επομένως αυτή η ρύθμιση δεν θα έχει κανένα αποτέλεσμα", + "{pm} only provides release dates for some of its packages, so this setting will only apply to those packages": "Το {pm} παρέχει ημερομηνίες κυκλοφορίας μόνο για ορισμένα από τα πακέτα του, οπότε αυτή η ρύθμιση θα εφαρμοστεί μόνο σε αυτά τα πακέτα", + "Override the global minimum update age for this package manager": "Παράκαμψη της καθολικής ελάχιστης ηλικίας ενημέρωσης για αυτόν τον διαχειριστή πακέτων", + "View {0} logs": "Δείτε {0} καταγραφές", + "If Python cannot be found or is not listing packages but is installed on the system, ": "Αν δεν είναι δυνατός ο εντοπισμός του Python ή δεν εμφανίζει πακέτα αλλά είναι εγκατεστημένο στο σύστημα, ", + "Advanced options": "Επιλογές για προχωρημένους", + "WinGet command-line tool": "Εργαλείο γραμμής εντολών WinGet", + "Choose which command-line tool UniGetUI uses for WinGet operations when the COM API is not used": "Επιλέξτε ποιο εργαλείο γραμμής εντολών θα χρησιμοποιεί το UniGetUI για λειτουργίες WinGet όταν δεν χρησιμοποιείται το COM API", + "WinGet COM API": "WinGet COM API", + "Choose whether UniGetUI can use the WinGet COM API before falling back to the command-line tool": "Επιλέξτε αν το UniGetUI μπορεί να χρησιμοποιεί το WinGet COM API πριν επιστρέψει στο εργαλείο γραμμής εντολών", + "Reset WinGet": "Επαναφορά του WinGet", + "This may help if no packages are listed": "Αυτό μπορεί να βοηθήσει αν κανένα πακέτο δεν εμφανίζεται", + "Force install location parameter when updating packages with custom locations": "Εξαναγκασμός παραμέτρου τοποθεσίας εγκατάστασης κατά την ενημέρωση πακέτων με προσαρμοσμένες τοποθεσίες", + "Install Scoop": "Εγκατάσταση Scoop", + "Uninstall Scoop (and its packages)": "Απεγκατάσταση του Scoop (και των πακέτων του)", + "Run cleanup and clear cache": "Εκτέλεση εκκαθάρισης και διαγραφή της μνήμης cache", + "Run": "Εκτέλεση", + "Enable Scoop cleanup on launch": "Ενεργοποίηση εκκαθάρισης Scoop κατά την εκκίνηση", + "Default vcpkg triplet": "Προεπιλεγμένο vcpkg triplet", + "Change vcpkg root location": "Αλλαγή τοποθεσίας ρίζας του vcpkg", + "Reset vcpkg root location": "Επαναφορά θέσης ρίζας vcpkg", + "Open vcpkg root location": "Άνοιγμα θέσης ρίζας vcpkg", + "Language, theme and other miscellaneous preferences": "Γλώσσα, θέμα και διάφορες άλλες προτιμήσεις", + "Show notifications on different events": "Εμφάνιση ειδοποιήσεων για διαφορετικά συμβάντα", + "Change how UniGetUI checks and installs available updates for your packages": "Αλλαγή του τρόπου με τον οποίο το UniGetUI ελέγχει και εγκαθιστά τις διαθέσιμες ενημερώσεις για τα πακέτα σας", + "Automatically save a list of all your installed packages to easily restore them.": "Αυτόματη αποθήκευση λίστας με όλα τα εγκατεστημένα πακέτα σας για εύκολη επαναφορά τους.", + "Enable and disable package managers, change default install options, etc.": "Ενεργοποίηση και απενεργοποίηση διαχειριστών πακέτων, αλλαγή προεπιλεγμένων επιλογών εγκατάστασης κ.λπ.", + "Internet connection settings": "Ρυθμίσεις σύνδεσης στο διαδίκτυο", + "Proxy settings, etc.": "Ρυθμίσεις διακομιστή κλπ.", + "Beta features and other options that shouldn't be touched": "Δοκιμαστικές λειτουργίες και άλλες ρυθμίσεις που δε θα έπρεπε να αγγιχτούν", + "Reload sources": "Επαναφόρτωση πηγών", + "Delete source": "Διαγραφή πηγής", + "Known sources": "Γνωστές πηγές", + "Update checking": "Ελεγχος για ενημερώσεις", + "Automatic updates": "Αυτόματες ενημερώσεις", + "Check for package updates periodically": "Περιοδικός έλεγχος για ενημερώσεις πακέτων", + "Check for updates every:": "Έλεγχος για ενημερώσεις κάθε:", + "Install available updates automatically": "Αυτόματη εγκατάσταση διαθέσιμων ενημερώσεων", + "Do not automatically install updates when the network connection is metered": "Να μη γίνεται αυτόματη εγκατάσταση ενημερώσεων όταν η σύνδεση στο διαδίκτυο είναι περιορισμένη", + "Do not automatically install updates when the device runs on battery": "Να μη γίνεται αυτόματη εγκατάσταση ενημερώσεων όταν η συσκευή είναι σε λειτουργία μπαταρίας", + "Do not automatically install updates when the battery saver is on": "Να μη γίνεται αυτόματη εγκατάσταση ενημερώσεων όταν η εξοικονόμηση μπαταρίας είναι ενεργή", + "Only show updates that are at least the specified number of days old": "Εμφάνιση μόνο ενημερώσεων που έχουν ηλικία τουλάχιστον τον καθορισμένο αριθμό ημερών", + "Warn me when the installer URL host changes between the installed version and the new version (WinGet only)": "Να προειδοποιούμαι όταν ο κεντρικός υπολογιστής της διεύθυνσης URL του προγράμματος εγκατάστασης αλλάζει μεταξύ της εγκατεστημένης έκδοσης και της νέας έκδοσης (μόνο WinGet)", + "Change how UniGetUI handles install, update and uninstall operations.": "Αλλαγή του χειρισμού της εγκατάστασης, της ενημέρωσης και της απεγκατάστασης από το UniGetUI.", + "Navigation": "Πλοήγηση", + "Check for UniGetUI updates": "Έλεγχος για ενημερώσεις του UniGetUI", + "Quit UniGetUI": "Έξοδος από το UniGetUI", + "Filters": "Φίλτρα", + "Sources": "Προελεύσεις", + "Search for packages to start": "Αναζήτηση πακέτων για εκκίνηση", + "Select all": "Επιλογή όλων", + "Clear selection": "Εκκαθάριση επιλογής", + "Instant search": "Αμεση αναζήτηση", + "Distinguish between uppercase and lowercase": "Διάκριση πεζών - κεφαλαίων", + "Ignore special characters": "Αγνόηση ειδικών χαρακτήρων", + "Search mode": "Λειτουργία αναζήτησης", + "Both": "Και τα δύο", + "Exact match": "Ακριβές ταίριασμα", + "Show similar packages": "Εμφάνιση παρόμοιων πακέτων", + "Loading": "Φόρτωση", + "Package": "Πακέτο", + "More options": "Περισσότερες επιλογές", + "Order by:": "Ταξινόμηση κατά:", + "Name": "Όνομα", + "Id": "Ταυτότητα", + "Ascendant": "Πρωτεύων", + "Descendant": "Απόγονος", + "View modes": "Λειτουργίες προβολής", + "Reload": "Επαναφόρτωση", + "Closed": "Κλειστό", + "Ascending": "Αύξουσα", + "Descending": "Φθίνουσα", + "{0}: {1}, {2}": "{0}: {1}, {2}", + "Order by": "Ταξινόμηση κατά", + "No results were found matching the input criteria": "Δε βρέθηκαν αποτελέσματα που να ταιριάζουν με αυτά τα κριτήρια", + "No packages were found": "Δε βρέθηκαν πακέτα", + "Loading packages": "Φόρτωση πακέτων", + "Skip integrity checks": "Αγνόηση ελέγχων ακεραιότητας", + "Download selected installers": "Λήψη επιλεγμένων προγραμμάτων εγκατάστασης", + "Install selection": "Εγκατάσταση επιλογής", + "Install options": "Επιλογές εγκατάστασης", + "Add selection to bundle": "Προσθήκη επιλογής στη συλλογή", + "Download installer": "Λήψη προγράμματος εγκατάστασης", + "Uninstall selection": "Απεγκατάσταση επιλεγμένων", + "Uninstall options": "Επιλογές απεγκατάστασης", + "Ignore selected packages": "Αγνόηση επιλεγμένων πακέτων", + "Open install location": "Ανοιγμα τοποθεσίας εγκατάστασης", + "Reinstall package": "Επανεγκατάσταση πακέτου", + "Uninstall package, then reinstall it": "Απεγκατάσταση πακέτου, μετά εγκατάσταση αυτού ξανά", + "Ignore updates for this package": "Αγνόηση ενημερώσεων για αυτό το πακέτο", + "WinGet malfunction detected": "Ανιχνεύτηκε δυσλειτουργία του WinGet", + "It looks like WinGet is not working properly. Do you want to attempt to repair WinGet?": "Φαίνεται ότι το WinGet δεν λειτουργεί σωστά. Θέλετε να δοκιμάσετε να επιδιορθώσετε το WinGet;", + "Repair WinGet": "Επισκευή του WinGet", + "Updates will no longer be ignored for {0}": "Οι ενημερώσεις δεν θα αγνοούνται πλέον για το {0}", + "Updates are now ignored for {0}": "Οι ενημερώσεις αγνοούνται τώρα για το {0}", + "Do not ignore updates for this package anymore": "Μην αγνοείτε πλέον ενημερώσεις για αυτό το πακέτο", + "Add packages or open an existing package bundle": "Προσθήκη πακέτων ή άνοιγμα υπάρχουσας συλλογής πακέτων", + "Add packages to start": "Προσθήκη πακέτων για εκκίνηση", + "The current bundle has no packages. Add some packages to get started": "Η τρέχουσα συλλογή δεν έχει πακέτα. Προσθέστε ορισμένα πακέτα για να ξεκινήσετε", + "New": "Νέο", + "Save as": "Αποθήκευση ως", + "Create .ps1 script": "Δημιουργία .ps1 script", + "Remove selection from bundle": "Απομάκρυνση επιλογής από τη συλλογή", + "Skip hash checks": "Αγνόηση ελέγχων hash", + "The package bundle is not valid": "Η συλλογή πακέτων δεν είναι έγκυρη", + "The bundle you are trying to load appears to be invalid. Please check the file and try again.": "Η συλλογή που προσπαθείτε να φορτώσετε φαίνεται να μην είναι έγκυρη. Ελέγξτε το αρχείο και δοκιμάστε ξανά.", + "Package bundle": "Συλλογή πακέτων", + "Could not create bundle": "Αδύνατη η δημιουργία της συλλογής", + "The package bundle could not be created due to an error.": "Η συλλογή πακέτων δεν μπορεί να δημιουργηθεί λόγω σφάλματος.", + "Install script": "Εγκατάσταση script", + "PowerShell script": "Σενάριο PowerShell", + "The installation script saved to {0}": "Το script εγκατάστασης αποθηκεύτηκε στο {0}", + "An error occurred": "Παρουσιάστηκε σφάλμα", + "An error occurred while attempting to create an installation script:": "Παρουσιάστηκε σφάλμα κατά την προσπάθεια δημιουργίας ενός script εγκατάστασης:", + "Hooray! No updates were found.": "Συγχαρητήρια! Δε βρέθηκαν ενημερώσεις!", + "Uninstall selected packages": "Απεγκατάσταση επιλεγμένων πακέτων", + "Update selection": "Ενημέρωση επιλεγμένων", + "Update options": "Επιλογές ενημέρωσης", + "Uninstall package, then update it": "Απεγκατάσταση πακέτου, μετά ενημέρωση αυτού", + "Uninstall package": "Απεγκατάσταση πακέτου", + "Skip this version": "Αγνόηση αυτής της έκδοσης", + "Pause updates for": "Παύση ενημερώσεων για", + "User | Local": "Χρήστης | Τοπικό", + "Machine | Global": "Υπολογιστής | Καθολικό", + "The default package manager for Debian/Ubuntu-based Linux distributions.
Contains: Debian/Ubuntu packages": "Ο προεπιλεγμένος διαχειριστής πακέτων για διανομές Linux βασισμένες σε Debian/Ubuntu.
Περιέχει: πακέτα Debian/Ubuntu", + "The Rust package manager.
Contains: Rust libraries and programs written in Rust": "Ο διαχειριστής πακέτων Rust.
Περιέχει: βιβλιοθήκες και προγράμματα Rust γραμμένα σε Rust", + "The classical package manager for windows. You'll find everything there.
Contains: General Software": "Ο κλασικός διαχειριστής πακέτων για windows. Θα βρείτε τα πάντα εκεί.
Περιέχει: Γενικό λογισμικό", + "The default package manager for RHEL/Fedora-based Linux distributions.
Contains: RPM packages": "Ο προεπιλεγμένος διαχειριστής πακέτων για διανομές Linux βασισμένες σε RHEL/Fedora.
Περιέχει: πακέτα RPM", + "A repository full of tools and executables designed with Microsoft's .NET ecosystem in mind.
Contains: .NET related tools and scripts": "Ενα αποθετήριο γεμάτο εργαλεία και εκτελέσιμα αρχεία σχεδιασμένο με βάση το οικοσύστημα .NET της Microsoft.
Περιέχει: Εργαλεία και κώδικες σχετικά με το .NET", + "The universal Linux package manager for desktop applications.
Contains: Flatpak applications from configured remotes": "Ο καθολικός διαχειριστής πακέτων Linux για εφαρμογές επιφάνειας εργασίας.
Περιέχει: εφαρμογές Flatpak από διαμορφωμένες απομακρυσμένες πηγές", + "NuPkg (zipped manifest)": "NuPkg (συμπιεσμένο manifest)", + "The Missing Package Manager for macOS (or Linux).
Contains: Formulae, Casks": "Ο ελλείπων διαχειριστής πακέτων για macOS (ή Linux).
Περιέχει: Formulae, Casks", + "Node JS's package manager. Full of libraries and other utilities that orbit the javascript world
Contains: Node javascript libraries and other related utilities": "Διαχειριστής πακέτων του Node JS. Γεμάτος βιβλιοθήκες και άλλα βοηθητικά προγράμματα σε τροχιά γύρω από τον κόσμο της javascript
Περιέχει: Βιβλιοθήκες Node javascript και άλλα σχετικά βοηθητικά προγράμματα", + "The default package manager for Arch Linux and its derivatives.
Contains: Arch Linux packages": "Ο προεπιλεγμένος διαχειριστής πακέτων για το Arch Linux και τα παράγωγά του.
Περιέχει: πακέτα Arch Linux", + "Python's library manager. Full of python libraries and other python-related utilities
Contains: Python libraries and related utilities": "Διαχειριστής βιβλιοθηκών της Python. Γεμάτος με βιβλιοθήκες της python και άλλα βοηθητικά προγράμματα που σχετίζονται με την python
Περιέχει: Βιβλιοθήκες Python και σχετικά βοηθητικά προγράμματα", + "PowerShell's package manager. Find libraries and scripts to expand PowerShell capabilities
Contains: Modules, Scripts, Cmdlets": "Διαχειριστής πακέτων του PowerShell. Βρείτε βιβλιοθήκες και κώδικες για να επεκτείνετε τις δυνατότητες του PowerShell
Περιέχει: Ενότητες, Κώδικες, Σύνολα εντολών", + "extracted": "αποσυμπιεσμένο", + "Scoop package": "Πακέτο Scoop", + "Great repository of unknown but useful utilities and other interesting packages.
Contains: Utilities, Command-line programs, General Software (extras bucket required)": "Εξαιρετικό αποθετήριο άγνωστων αλλά χρήσιμων βοηθητικών προγραμμάτων και άλλων ενδιαφερόντων πακέτων.
Περιέχει: Βοηθητικά προγράμματα, Προγράμματα γραμμής εντολών, Γενικό λογισμικό (απαιτείται επιπλέον πακέτο)", + "The universal Linux package manager by Canonical.
Contains: Snap packages from the Snapcraft store": "Ο καθολικός διαχειριστής πακέτων Linux από την Canonical.
Περιέχει: πακέτα Snap από το κατάστημα Snapcraft", + "library": "βιβλιοθήκη", + "feature": "χαρακτηριστικό", + "A popular C/C++ library manager. Full of C/C++ libraries and other C/C++-related utilities
Contains: C/C++ libraries and related utilities": "Ενας δημοφιλής διαχειριστής βιβλιοθήκης C/C++. Πλήρεις βιβλιοθήκες C/C++ και άλλα βοηθητικά προγράμματα που σχετίζονται με C/C++
Περιέχει: Βιβλιοθήκες C/C++ και σχετικά βοηθητικά προγράμματα", + "option": "επιλογή", + "This package cannot be installed from an elevated context.": "Αυτό το πακέτο δεν μπορεί να εγκατασταθεί από περιεχόμενο με αυξημένα δικαιώματα.", + "Please run UniGetUI as a regular user and try again.": "Εκτελέστε το UniGetUI ως κανονικός χρήστης και δοκιμάστε ξανά.", + "Please check the installation options for this package and try again": "Ελέγξτε τις επιλογές εγκατάστασης για αυτό το πακέτο και δοκιμάστε ξανά", + "Microsoft's official package manager. Full of well-known and verified packages
Contains: General Software, Microsoft Store apps": "Επίσημος διαχειριστής πακέτων της Microsoft. Γεμάτο γνωστά και επαληθευμένα πακέτα
Περιέχει: Γενικό Λογισμικό, εφαρμογές Microsoft Store", + "Local PC": "Τοπικός υπολογιστής", + "Android Subsystem": "Υποσύστημα Android", + "Operation on queue (position {0})...": "Η εργασία είναι σε σειρά προτεραιότητας (θέση {0})...", + "Click here for more details": "Πατήστε εδώ για περισσότερες λεπτομέρειες", + "Operation canceled by user": "Η λειτουργία ακυρώθηκε από τον χρήστη", + "Running PreOperation ({0}/{1})...": "Εκτέλεση PreOperation ({0}/{1})...", + "PreOperation {0} out of {1} failed, and was tagged as necessary. Aborting...": "Το PreOperation {0} από {1} απέτυχε και είχε επισημανθεί ως απαραίτητο. Ματαίωση...", + "PreOperation {0} out of {1} finished with result {2}": "Το PreOperation {0} από {1} ολοκληρώθηκε με αποτέλεσμα {2}", + "Starting operation...": "Εκκίνηση λειτουργίας...", + "Running PostOperation ({0}/{1})...": "Εκτέλεση PostOperation ({0}/{1})...", + "PostOperation {0} out of {1} failed, and was tagged as necessary. Aborting...": "Το PostOperation {0} από {1} απέτυχε και είχε επισημανθεί ως απαραίτητο. Ματαίωση...", + "PostOperation {0} out of {1} finished with result {2}": "Το PostOperation {0} από {1} ολοκληρώθηκε με αποτέλεσμα {2}", + "{package} installer download": "Το πρόγραμμα εγκατάστασης {package} λαμβάνεται", + "{0} installer is being downloaded": "{0} πρόγραμμα εγκατάστασης λαμβάνεται", + "Download succeeded": "Η λήψη ολοκληρώθηκε επιτυχώς", + "{package} installer was downloaded successfully": "Το πρόγραμμα εγκατάστασης {package} ελήφθη επιτυχώς", + "Download failed": "Η λήψη δεν ολοκληρώθηκε", + "{package} installer could not be downloaded": "Το πρόγραμμα εγκατάστασης {package} δεν ελήφθει", + "{package} Installation": "Εγκατάσταση {package}", + "{0} is being installed": "Το {0} εγκαθίσταται", + "Installation succeeded": "Η εγκατάσταση ολοκληρώθηκε επιτυχώς", + "{package} was installed successfully": "Το {package} εγκαταστάθηκε με επιτυχία", + "Installation failed": "Η εγκατάσταση απέτυχε", + "{package} could not be installed": "Δεν ήταν δυνατή η εγκατάσταση του {package}", + "{package} Update": "Ενημέρωση {package}", + "Update succeeded": "Η ενημέρωση έγινε με επιτυχία", + "{package} was updated successfully": "Το {package} ενημερώθηκε με επιτυχία", + "Update failed": "Η ενημέρωση απέτυχε", + "{package} could not be updated": "Δεν ήταν δυνατή η ενημέρωση του {package}", + "{package} Uninstall": "Απεγκατάσταση {package}", + "{0} is being uninstalled": "Το {0} απεγκαθίσταται", + "Uninstall succeeded": "Η απεγκατάσταση έγινε με επιτυχία", + "{package} was uninstalled successfully": "Το {package} απεγκαταστάθηκε με επιτυχία", + "Uninstall failed": "Η απεγκατάσταση απέτυχε", + "{package} could not be uninstalled": "Δεν ήταν δυνατή η απεγκατάσταση του {package}", + "Adding source {source}": "Προσθήκη προέλευσης {source}", + "Adding source {source} to {manager}": "Προσθήκη προέλευσης {source} στο {manager}", + "Source added successfully": "Η προέλευση προστέθηκε επιτυχώς", + "The source {source} was added to {manager} successfully": "Η προέλευση {source} προστέθηκε στο {manager} με επιτυχία", + "Could not add source": "Δεν ήταν δυνατή η προσθήκη προέλευσης", + "Could not add source {source} to {manager}": "Αδύνατη η προσθήκη προέλευσης {source} στο {manager}", + "Removing source {source}": "Απομάκρυνση προέλευσης {source}", + "Removing source {source} from {manager}": "Απομάκρυνση της πηγής {source} από το {manager}", + "Source removed successfully": "Η απομάκρυνση της προέλευσης ολοκληρώθηκε επιτυχώς", + "The source {source} was removed from {manager} successfully": "Η προέλευση {source} αφαιρέθηκε από το {manager} με επιτυχία", + "Could not remove source": "Αδύνατη η απομάκρυνση προέλευσης", + "Could not remove source {source} from {manager}": "Αδύνατη η απομάκρυνση της προέλευσης {source} από το {manager}", + "The package manager \"{0}\" was not found": "Ο διαχειριστής πακέτων «{0}» δεν βρέθηκε", + "The package manager \"{0}\" is disabled": "Ο διαχειριστής πακέτων «{0}» είναι απενεργοποιημένος", + "There is an error with the configuration of the package manager \"{0}\"": "Υπάρχει ένα σφάλμα με τις ρυθμίσεις του διαχειριστή πακέτων «{0}»", + "The package \"{0}\" was not found on the package manager \"{1}\"": "Το πακέτο «{0}» δεν βρέθηκε στον διαχειριστή πακέτων «{1}»", + "{0} is disabled": "Το {0} είναι απενεργοποιημένο", + "{0} weeks": "{0} εβδομάδες", + "1 month": "1 μήνας", + "{0} months": "{0} μήνες", + "Something went wrong": "Κάτι πήγε στραβά", + "An interal error occurred. Please view the log for further details.": "Παρουσιάστηκε εσωτερικό σφάλμα. Δείτε το αρχείο καταγραφής για περισσότερες λεπτομέρειες.", + "No applicable installer was found for the package {0}": "Δεν βρέθηκε κατάλληλο πρόγραμμα εγκατάστασης για το πακέτο {0}", + "Integrity checks will not be performed during this operation": "Οι έλεγχοι ακεραιότητας δε θα πραγματοποιηθούν σε αυτή τη λειτουργία", + "This is not recommended.": "Αυτό δεν προτείνεται.", + "Run now": "Εκτέλεση τώρα", + "Run next": "Εκτέλεσης επόμενης", + "Run last": "Εκτέλεση τελευταίας", + "Show in explorer": "Εμφάνιση στον εξερευνητή", + "Checked": "Επιλεγμένο", + "Unchecked": "Μη επιλεγμένο", + "This package is already installed": "Αυτό το πακέτο είναι ήδη εγκατεστημένο", + "This package can be upgraded to version {0}": "Αυτό το πακέτο μπορεί να αναβαθμιστεί στην έκδοση {0}", + "Updates for this package are ignored": "Οι ενημερώσεις γι' αυτό το πακέτο αγνοούνται", + "This package is being processed": "Αυτό το πακέτο είναι υπο επεξεργασία", + "This package is not available": "Αυτό το πακέτο δεν είναι διαθέσιμο", + "Select the source you want to add:": "Επιλογή προέλευσης που θέλετε να προσθέσετε:", + "Source name:": "Όνομα προέλευσης:", + "Source URL:": "Διεύθυνση URL προέλευσης:", + "An error occurred when adding the source: ": "Παρουσιάστηκε ένα σφάλμα κατά την προσθήκη της προέλευσης:", + "Package management made easy": "Η διαχείριση πακέτων έγινε εύκολη", + "version {0}": "έκδοση {0}", + "[RAN AS ADMINISTRATOR]": "ΕΚΤΕΛΕΣΗ ΩΣ ΔΙΑΧΕΙΡΙΣΤΗΣ", + "Portable mode": "Λειτουργία Portable (φορητή)", + "DEBUG BUILD": "ΔΟΜΗ ΑΠΟΣΦΑΛΜΑΤΩΣΗΣ", + "Here you can change UniGetUI's behaviour regarding the following shortcuts. Checking a shortcut will make UniGetUI delete it if if gets created on a future upgrade. Unchecking it will keep the shortcut intact": "Εδώ μπορείτε να αλλάξετε τη συμπεριφορά του UniGetUI αναφορικά με τις ακόλουθες συντομεύσεις. Ο έλεγχος μιας συντόμευσης θα κάνει το UniGetUI να τη διαγράψει αν δημιουργηθεί σε μελλοντική αναβάθμιση. Ο μή έλεγχός της θα διατηρήσεις τη συντόμευση ανέπαφη", + "Manual scan": "Χειροκίνητη σάρωση", + "Existing shortcuts on your desktop will be scanned, and you will need to pick which ones to keep and which ones to remove.": "Οι υπάρχουσες συντομεύσεις στην επιφάνεια εργασίας σας θα σαρωθούν και θα πρέπει να επιλέξετε ποιες θα διατηρήσετε και ποιες θα απομακρύνετε.", + "Delete?": "Διαγραφή;", + "I understand": "Το κατάλαβα", + "Chocolatey setup changed": "Η ρύθμιση του Chocolatey άλλαξε", + "UniGetUI no longer includes its own private Chocolatey installation. A legacy UniGetUI-managed Chocolatey installation was detected for this user profile, but system Chocolatey was not found. Chocolatey will stay unavailable in UniGetUI until Chocolatey is installed on the system and UniGetUI is restarted. Applications previously installed through UniGetUI's bundled Chocolatey may still appear under other sources such as Local PC or WinGet.": "Το UniGetUI δεν περιλαμβάνει πλέον τη δική του ιδιωτική εγκατάσταση Chocolatey. Εντοπίστηκε μια παλαιά εγκατάσταση Chocolatey που διαχειριζόταν το UniGetUI για αυτό το προφίλ χρήστη, αλλά δεν βρέθηκε εγκατάσταση Chocolatey στο σύστημα. Το Chocolatey θα παραμείνει μη διαθέσιμο στο UniGetUI μέχρι να εγκατασταθεί το Chocolatey στο σύστημα και να γίνει επανεκκίνηση του UniGetUI. Οι εφαρμογές που εγκαταστάθηκαν προηγουμένως μέσω του ενσωματωμένου Chocolatey του UniGetUI ενδέχεται να εξακολουθούν να εμφανίζονται σε άλλες πηγές, όπως ο Τοπικός Υπολογιστής ή το WinGet.", + "NOTE: This troubleshooter can be disabled from UniGetUI Settings, on the WinGet section": "ΣΗΜΕΙΩΣΗ: Το πρόγραμμα αντιμετώπισης προβλημάτων μπορεί να απενεργοποιηθεί από τις ρυθμίσεις του UniGetUI, στον τομέα WinGet", + "Restart": "Επανεκκίνηση", + "Are you sure you want to delete all shortcuts?": "Θέλετε να διαγράψετε όλες τις συντομεύσεις;", + "Any new shorcuts created during an install or an update operation will be deleted automatically, instead of showing a confirmation prompt the first time they are detected.": "Οποιαδήποτε νέα συντόμευση που δημιουργήθηκε σε εγκατάσταση ή ενημέρωση θα διαγραφεί αυτόματα αντί της εμφάνισης επιβεβαίωσης την πρώτη φορά που θα ανιχνευτούν.", + "Any shorcuts created or modified outside of UniGetUI will be ignored. You will be able to add them via the {0} button.": "Οποιεσδήποτε συντομεύσεις που δημιουργήθηκαν ή τροποποιήθηκαν εκτός του UniGetUI θα αγνοηθούν. Θα μπορέσετε να τις προσθέσετε μέσω του κουμπιού {0}.", + "Are you really sure you want to enable this feature?": "Θέλετε πραγματικά να ενεργοποιήσετε αυτό το χαρακτηριστικό;", + "No new shortcuts were found during the scan.": "Δεν βρέθηκαν νέες συντομεύσεις κατά τη σάρωση.", + "How to add packages to a bundle": "Πώς να προσθέσετε πακέτα σε συλλογή", + "In order to add packages to a bundle, you will need to: ": "Για την προσθήκη πακέτων σε συλλογή, θα χρειαστείτε:", + "1. Navigate to the \"{0}\" or \"{1}\" page.": "1. Πλοηγειθείτε στη σελίδα «{0}» ή στη «{1}».", + "2. Locate the package(s) you want to add to the bundle, and select their leftmost checkbox.": "2. Εντοπίστε το(α) πακέτο(α) που θέλετε να προσθέσετε στη συλλογή και επιλογή του(ων) με το αριστερό πλαίσιο ελέγχου", + "3. When the packages you want to add to the bundle are selected, find and click the option \"{0}\" on the toolbar.": "3. Όταν τα πακέτα που θέλετε να προσθέσετε στη συλλογή επιλέγονται, βρείτε και πατήστε την επιλογή «{0}» στη γραμμή εργαλείων.", + "4. Your packages will have been added to the bundle. You can continue adding packages, or export the bundle.": "4. Τα πακέτα σας θα έχουν προστεθεί στη συλλογή. Μπορείτε να συνεχίσετε να προσθέτετε πακέτα ή να εξάγετε τη συλλογή.", + "Which backup do you want to open?": "Ποιο αντίγραφο ασφαλείας θέλετε να ανοίξετε;", + "Select the backup you want to open. Later, you will be able to review which packages you want to install.": "Επιλέξτε το αντίγραφο ασφαλείας που θέλετε να ανοίξετε. Αργότερα, θα μπορείτε να ελέγξετε ποια πακέτα θέλετε να εγκαταστήσετε.", + "There are ongoing operations. Quitting UniGetUI may cause them to fail. Do you want to continue?": "Υπάρχουν εργασίες σε εξέλιξη. Η διακοπή του UniGetUI μπορεί να προκαλέσει την αποτυχία τους. Θέλετε να συνεχίσετε;", + "UniGetUI or some of its components are missing or corrupt.": "Το UniGetUI ή ορισμένα από τα στοιχεία του λείπουν ή είναι κατεστραμμένα.", + "It is strongly recommended to reinstall UniGetUI to adress the situation.": "Συνιστάται ανεπιφύλακτα να επανεγκαταστήσετε το UniGetUI για να αντιμετωπίσετε το πρόβλημα.", + "Refer to the UniGetUI Logs to get more details regarding the affected file(s)": "Ανατρέξτε στα αρχεία καταγραφής UniGetUI για να λάβετε περισσότερες λεπτομέρειες σχετικά με τα αρχεία που επηρεάζονται.", + "Integrity checks can be disabled from the Experimental Settings": "Οι έλεγχοι ακεραιότητας μπορούν να απενεργοποιηθούν από τις πειραματικές ρυθμίσεις", + "Repair UniGetUI": "Επισκευή του UniGetUI", + "Live output": "Κώδικας σε πραγματικό χρόνο", + "This package bundle had some settings that are potentially dangerous, and may be ignored by default.": "Αυτή η συλλογή είχε ορισμένες ρυθμίσεις που είναι δυνητικά επικίνδυνες και ενδέχεται να αγνοηθεί από προεπιλογή.", + "Entries that show in YELLOW will be IGNORED.": "Οι καταχωρήσεις που εμφανίζονται με ΚΙΤΡΙΝΟ θα ΑΓΝΟΗΘΟΥΝ.", + "Entries that show in RED will be IMPORTED.": "Οι καταχωρήσεις που εμφανίζονται με ΚΟΚΚΙΝΟ θα ΕΙΣΑΓΟΝΤΑΙ.", + "You can change this behavior on UniGetUI security settings.": "Μπορείτε να αλλάξετε αυτήν τη συμπεριφορά στις ρυθμίσεις ασφαλείας του UniGetUI.", + "Open UniGetUI security settings": "Ανοιγμα ρυθμίσεων ασφαλείας UniGetUI", + "Should you modify the security settings, you will need to open the bundle again for the changes to take effect.": "Σε περίπτωση που τροποποιήσετε τις ρυθμίσεις ασφαλείας, θα χρειαστεί να ανοίξετε ξανά τη συλλογή για να ισχύσουν οι αλλαγές.", + "Details of the report:": "Λεπτομέρειες της αναφοράς:", + "Are you sure you want to create a new package bundle? ": "Θέλετε να δημιουργήσετε νέα συλλογή πακέτων;", + "Any unsaved changes will be lost": "Όλες οι μη αποθηκευμένες αλλαγές θα χαθούν", + "Warning!": "Προειδοποίηση!", + "For security reasons, custom command-line arguments are disabled by default. Go to UniGetUI security settings to change this. ": "Για λόγους ασφαλείας, τα προσαρμοσμένα ορίσματα γραμμής εντολών είναι απενεργοποιημένα από προεπιλογή. Μεταβείτε στις ρυθμίσεις ασφαλείας του UniGetUI για να το αλλάξετε αυτό.", + "Change default options": "Αλλαγή προεπιλεγμένων επιλογών", + "Ignore future updates for this package": "Αγνόηση μελλοντικών ενημερώσεων για αυτό το πακέτο", + "For security reasons, pre-operation and post-operation scripts are disabled by default. Go to UniGetUI security settings to change this. ": "Για λόγους ασφαλείας, τα scripts πριν και μετά τη λειτουργία είναι απενεργοποιημένα από προεπιλογή. Μεταβείτε στις ρυθμίσεις ασφαλείας του UniGetUI για να το αλλάξετε αυτό.", + "You can define the commands that will be run before or after this package is installed, updated or uninstalled. They will be run on a command prompt, so CMD scripts will work here.": "Μπορείτε να ορίσετε τις εντολές που θα εκτελούνται πριν ή μετά την εγκατάσταση, την ενημέρωση ή την απεγκατάσταση αυτού του πακέτου. Θα εκτελούνται σε μια γραμμή εντολών, επομένως τα CMD scripts θα λειτουργούν εδώ.", + "Change this and unlock": "Αλλαγή αυτού και ξεκλείδωμα", + "{0} Install options are currently locked because {0} follows the default install options.": "{0} Οι επιλογές εγκατάστασης είναι αυτήν τη στιγμή κλειδωμένες επειδή το {0} ακολουθεί τις προεπιλεγμένες επιλογές εγκατάστασης.", + "Unset or unknown": "Μη ορισμένο ή άγνωστο", + "This package has no screenshots or is missing the icon? Contrbute to UniGetUI by adding the missing icons and screenshots to our open, public database.": "Αυτό το πακέτο δεν έχει στιγμιότυπα οθόνης ή λείπει το εικονίδιο; Συνεισφέρετε στο UniGetUI προσθέτοντας τα εικονίδια και τα στιγμιότυπα οθόνης που λείπουν στην ανοιχτή, δημόσια βάση δεδομένων μας.", + "Become a contributor": "Γίνετε συνεισφέρων", + "Update to {0} available": "Υπάρχει διαθέσιμη ενημέρωση για το {0}", + "Reinstall": "Επανεγκατάσταση", + "Installer not available": "Το πρόγραμμα εγκατάστασης δεν είναι διαθέσιμο", + "Version:": "Εκδοση:", + "UniGetUI Version {0}": "UniGetUI Εκδοση {0}", + "Performing backup, please wait...": "Δημιουργία αντιγράφου ασφαλείας, παρακαλώ περιμένετε...", + "An error occurred while logging in: ": "Παρουσιάστηκε σφάλμα κατά τη σύνδεση:", + "Fetching available backups...": "Ανάκτηση διαθέσιμων αντιγράφων ασφαλείας...", + "Done!": "Εγινε!", + "The cloud backup has been loaded successfully.": "Το αντίγραφο ασφαλείας από το cloud φορτώθηκε με επιτυχία.", + "An error occurred while loading a backup: ": "Παρουσιάστηκε σφάλμα κατά τη φόρτωση ενός αντιγράφου ασφαλείας:", + "Backing up packages to GitHub Gist...": "Δημιουργία αντιγράφων ασφαλείας πακέτων στο GitHub Gist...", + "Backup Successful": "Η δημιουργία αντιγράφων ασφαλείας ολοκληρώθηκε με επιτυχία", + "The cloud backup completed successfully.": "Η δημιουργία αντιγράφων ασφαλείας στο cloud ολοκληρώθηκε με επιτυχία.", + "Could not back up packages to GitHub Gist: ": "Δεν ήταν δυνατή η δημιουργία αντιγράφων ασφαλείας πακέτων στο GitHub Gist:", + "It is not guaranteed that the provided credentials will be stored safely, so you may as well not use the credentials of your bank account": "Δεν υπάρχει εγγύηση ότι τα παρεχόμενα διαπιστευτήρια θα αποθηκευτούν ασφαλώς, έτσι μπορείτε να μην χρησιμοποιήσετε τα διαπιστευτήρια του τραπεζικού σας λογαριασμού", + "Enable the automatic WinGet troubleshooter": "Ενεργοποίηση του προγράμματος αυτόματης αντιμετώπισης προβλημάτων του WinGet", + "Add updates that fail with a 'no applicable update found' to the ignored updates list": "Προσθήκη ενημερώσεων που απέτυχαν με την ετικέτα «δε βρέθηκε καμιά ενημέρωση εφαρμογής» στη λίστα αγνόησης ενημερώσεων", + "Invalid selection": "Μη έγκυρη επιλογή", + "No package was selected": "Δεν επιλέχθηκε κανένα πακέτο", + "More than 1 package was selected": "Επιλέχθηκαν περισσότερα από 1 πακέτα", + "List": "Λίστα", + "Grid": "Πλέγμα", + "Icons": "Εικονίδια", + "\"{0}\" is a local package and does not have available details": "Το «{0}» είναι ένα τοπικό πακέτο και δεν έχει διαθέσιμες λεπτομέρειες", + "\"{0}\" is a local package and is not compatible with this feature": "Το «{0}» είναι ένα τοπικό πακέτο και δεν είναι συμβατό με αυτό το χαρακτηριστικό", + "Add packages to bundle": "Προσθήκη πακέτων στη συλλογή", + "Preparing packages, please wait...": "Προετοιμασία πακέτων, παρακαλώ περιμένετε...", + "Loading packages, please wait...": "Φόρτωση πακέτων, παρακαλώ περιμένετε...", + "Saving packages, please wait...": "Αποθήκευση πακέτων, παρακαλώ περιμένετε...", + "The bundle was created successfully on {0}": "Η συλλογή δημιουργήθηκε με επιτυχία στις {0}", + "User profile": "Προφίλ χρήστη", + "Error": "Σφάλμα", + "Log in failed: ": "Η σύνδεση απέτυχε:", + "Log out failed: ": "Η αποσύνδεση απέτυχε:", + "Package backup settings": "Ρυθμίσεις αντιγράφου ασφαλείας πακέτου", + "Manage UniGetUI autostart behaviour from the Settings app": "Διαχείριση συμπεριφοράς αυτόματης εκκίνησης του UniGetUI", + "Choose how many operations shoulds be performed in parallel": "Επιλέξτε πόσες λειτουργίες πρέπει να εκτελούνται παράλληλα", + "Something went wrong while launching the updater.": "Κάτι πήγε στραβά κατά το άνοιγμα του προγράμματος ενημέρωσης.", + "Please try again later": "Δοκιμάστε ξανά αργότερα", + "Show the release notes after UniGetUI is updated": "Εμφάνιση σημειώσεων έκδοσης μετά την ενημέρωση του UniGetUI" +} diff --git a/src/Languages/lang_en.json b/src/Languages/lang_en.json new file mode 100644 index 0000000..232ab1d --- /dev/null +++ b/src/Languages/lang_en.json @@ -0,0 +1,858 @@ +{ + "Navigation menu:": "Navigation menu:", + "Automatic": "Automatic", + "Docked open": "Docked open", + "Sliding overlay": "Sliding overlay", + "{0} of {1} operations completed": "{0} of {1} operations completed", + "{0} is now {1}": "{0} is now {1}", + "Enabled": "Enabled", + "Disabled": "Disabled", + "Privacy": "Privacy", + "Hide my username from the logs": "Hide my username from the logs", + "Replaces your username with **** in the logs. Restart UniGetUI to also hide it from already-recorded entries.": "Replaces your username with **** in the logs. Restart UniGetUI to also hide it from already-recorded entries.", + "Your last update attempt did not complete.": "Your last update attempt did not complete.", + "UniGetUI could not confirm whether the update succeeded. Open the log to see what happened.": "UniGetUI could not confirm whether the update succeeded. Open the log to see what happened.", + "View log": "View log", + "The installer reported success but did not restart UniGetUI.": "The installer reported success but did not restart UniGetUI.", + "The installer failed to initialize.": "The installer failed to initialize.", + "Setup was canceled before installation began.": "Setup was canceled before installation began.", + "A fatal error occurred during the preparation phase.": "A fatal error occurred during the preparation phase.", + "A fatal error occurred during installation.": "A fatal error occurred during installation.", + "Installation was canceled while in progress.": "Installation was canceled while in progress.", + "The installer was terminated by another process.": "The installer was terminated by another process.", + "The preparation phase determined the installation cannot proceed.": "The preparation phase determined the installation cannot proceed.", + "The installer could not start. UniGetUI may already be running, or you do not have permission to install.": "The installer could not start. UniGetUI may already be running, or you do not have permission to install.", + "Unexpected installer error.": "Unexpected installer error.", + "We are checking for updates.": "We are checking for updates.", + "Please wait": "Please wait", + "Great! You are on the latest version.": "Great! You are on the latest version.", + "There are no new UniGetUI versions to be installed": "There are no new UniGetUI versions to be installed", + "UniGetUI version {0} is being downloaded.": "UniGetUI version {0} is being downloaded.", + "This may take a minute or two": "This may take a minute or two", + "The installer authenticity could not be verified.": "The installer authenticity could not be verified.", + "The update process has been aborted.": "The update process has been aborted.", + "Auto-update is not yet available on this platform.": "Auto-update is not yet available on this platform.", + "Please update UniGetUI manually.": "Please update UniGetUI manually.", + "An error occurred when checking for updates: ": "An error occurred when checking for updates: ", + "The updater could not be launched.": "The updater could not be launched.", + "The operating system did not start the installer process.": "The operating system did not start the installer process.", + "UniGetUI is being updated...": "UniGetUI is being updated...", + "Update installed.": "Update installed.", + "UniGetUI was updated successfully, but this running copy was not replaced. This usually means you are running a development build. Close this copy and start the newly-installed version to finish.": "UniGetUI was updated successfully, but this running copy was not replaced. This usually means you are running a development build. Close this copy and start the newly-installed version to finish.", + "The update could not be applied.": "The update could not be applied.", + "Installer exit code {0}: {1}": "Installer exit code {0}: {1}", + "Update cancelled.": "Update cancelled.", + "Authentication was cancelled.": "Authentication was cancelled.", + "Installer exit code {0}": "Installer exit code {0}", + "Operation in progress": "Operation in progress", + "Please wait...": "Please wait...", + "Success!": "Success!", + "Failed": "Failed", + "An error occurred while processing this package": "An error occurred while processing this package", + "Installer": "Installer", + "Executable": "Executable", + "MSI": "MSI", + "Compressed file": "Compressed file", + "MSIX": "MSIX", + "WinGet was repaired successfully": "WinGet was repaired successfully", + "It is recommended to restart UniGetUI after WinGet has been repaired": "It is recommended to restart UniGetUI after WinGet has been repaired", + "WinGet could not be repaired": "WinGet could not be repaired", + "An unexpected issue occurred while attempting to repair WinGet. Please try again later": "An unexpected issue occurred while attempting to repair WinGet. Please try again later", + "Log in to enable cloud backup": "Log in to enable cloud backup", + "Backup Failed": "Backup Failed", + "Downloading backup...": "Downloading backup...", + "An update was found!": "An update was found!", + "{0} can be updated to version {1}": "{0} can be updated to version {1}", + "Updates found!": "Updates found!", + "{0} packages can be updated": "{0} packages can be updated", + "{0} is being updated to version {1}": "{0} is being updated to version {1}", + "{0} packages are being updated": "{0} packages are being updated", + "You have currently version {0} installed": "You have currently version {0} installed", + "Desktop shortcut created": "Desktop shortcut created", + "UniGetUI has detected a new desktop shortcut that can be deleted automatically.": "UniGetUI has detected a new desktop shortcut that can be deleted automatically.", + "{0} desktop shortcuts created": "{0} desktop shortcuts created", + "UniGetUI has detected {0} new desktop shortcuts that can be deleted automatically.": "UniGetUI has detected {0} new desktop shortcuts that can be deleted automatically.", + "Attention required": "Attention required", + "Restart required": "Restart required", + "1 update is available": "1 update is available", + "{0} updates are available": "{0} updates are available", + "Everything is up to date": "Everything is up to date", + "Discover Packages": "Discover Packages", + "Available Updates": "Available Updates", + "Installed Packages": "Installed Packages", + "UniGetUI Version {0} by Devolutions": "UniGetUI Version {0} by Devolutions", + "Show UniGetUI": "Show UniGetUI", + "Quit": "Quit", + "Are you sure?": "Are you sure?", + "Do you really want to uninstall {0}?": "Do you really want to uninstall {0}?", + "Do you really want to uninstall the following {0} packages?": "Do you really want to uninstall the following {0} packages?", + "No": "No", + "Yes": "Yes", + "Partial": "Partial", + "View on UniGetUI": "View on UniGetUI", + "Update": "Update", + "Open UniGetUI": "Open UniGetUI", + "Update all": "Update all", + "Update now": "Update now", + "Installer host changed since the installed version.\n": "Installer host changed since the installed version.\n", + "This package is on the queue": "This package is on the queue", + "installing": "installing", + "updating": "updating", + "uninstalling": "uninstalling", + "installed": "installed", + "Retry": "Retry", + "Install": "Install", + "Uninstall": "Uninstall", + "Open": "Open", + "Operation profile:": "Operation profile:", + "Follow the default options when installing, upgrading or uninstalling this package": "Follow the default options when installing, upgrading or uninstalling this package", + "The following settings will be applied each time this package is installed, updated or removed.": "The following settings will be applied each time this package is installed, updated or removed.", + "Version to install:": "Version to install:", + "Architecture to install:": "Architecture to install:", + "Installation scope:": "Installation scope:", + "Install location:": "Install location:", + "Select": "Select", + "Reset": "Reset", + "Custom install arguments:": "Custom install arguments:", + "Custom update arguments:": "Custom update arguments:", + "Custom uninstall arguments:": "Custom uninstall arguments:", + "These fields are independent: an argument set for Install won't apply to Update or Uninstall, and vice versa.": "These fields are independent: an argument set for Install won't apply to Update or Uninstall, and vice versa.", + "Copy install arguments to update and uninstall": "Copy install arguments to update and uninstall", + "Pre-install command:": "Pre-install command:", + "Post-install command:": "Post-install command:", + "Abort install if pre-install command fails": "Abort install if pre-install command fails", + "Pre-update command:": "Pre-update command:", + "Post-update command:": "Post-update command:", + "Abort update if pre-update command fails": "Abort update if pre-update command fails", + "Pre-uninstall command:": "Pre-uninstall command:", + "Post-uninstall command:": "Post-uninstall command:", + "Abort uninstall if pre-uninstall command fails": "Abort uninstall if pre-uninstall command fails", + "Command-line to run:": "Command-line to run:", + "Save and close": "Save and close", + "General": "General", + "Architecture & Location": "Architecture & Location", + "Command-line": "Command-line", + "Close apps": "Close apps", + "Pre/Post install": "Pre/Post install", + "Select the processes that should be closed before this package is installed, updated or uninstalled.": "Select the processes that should be closed before this package is installed, updated or uninstalled.", + "Write here the process names here, separated by commas (,)": "Write here the process names here, separated by commas (,)", + "Try to kill the processes that refuse to close when requested to": "Try to kill the processes that refuse to close when requested to", + "Run as admin": "Run as admin", + "Interactive installation": "Interactive installation", + "Skip hash check": "Skip hash check", + "Uninstall previous versions when updated": "Uninstall previous versions when updated", + "Skip minor updates for this package": "Skip minor updates for this package", + "Automatically update this package": "Automatically update this package", + "{0} installation options": "{0} installation options", + "Latest": "Latest", + "PreRelease": "PreRelease", + "Default": "Default", + "Manage ignored updates": "Manage ignored updates", + "The packages listed here won't be taken in account when checking for updates. Double-click them or click the button on their right to stop ignoring their updates.": "The packages listed here won't be taken in account when checking for updates. Double-click them or click the button on their right to stop ignoring their updates.", + "Reset list": "Reset list", + "Do you really want to reset the ignored updates list? This action cannot be reverted": "Do you really want to reset the ignored updates list? This action cannot be reverted", + "No ignored updates": "No ignored updates", + "Package Name": "Package Name", + "Package ID": "Package ID", + "Ignored version": "Ignored version", + "New version": "New version", + "Source": "Source", + "All versions": "All versions", + "Unknown": "Unknown", + "Up to date": "Up to date", + "Package {name} from {manager}": "Package {name} from {manager}", + "Remove {0} from ignored updates": "Remove {0} from ignored updates", + "Cancel": "Cancel", + "Administrator privileges": "Administrator privileges", + "This operation is running with administrator privileges.": "This operation is running with administrator privileges.", + "Interactive operation": "Interactive operation", + "This operation is running interactively.": "This operation is running interactively.", + "You will likely need to interact with the installer.": "You will likely need to interact with the installer.", + "Integrity checks skipped": "Integrity checks skipped", + "Integrity checks will not be performed during this operation.": "Integrity checks will not be performed during this operation.", + "Proceed at your own risk.": "Proceed at your own risk.", + "Close": "Close", + "Loading...": "Loading...", + "Installer SHA256": "Installer SHA256", + "Homepage": "Homepage", + "Author": "Author", + "Publisher": "Publisher", + "License": "License", + "Manifest": "Manifest", + "Installer Type": "Installer Type", + "Size": "Size", + "Installer URL": "Installer URL", + "Last updated:": "Last updated:", + "Release notes URL": "Release notes URL", + "Package details": "Package details", + "Dependencies:": "Dependencies:", + "Release notes": "Release notes", + "Screenshots": "Screenshots", + "This package has no screenshots or is missing the icon? Contribute to UniGetUI by adding the missing icons and screenshots to our open, public database.": "This package has no screenshots or is missing the icon? Contribute to UniGetUI by adding the missing icons and screenshots to our open, public database.", + "Version": "Version", + "Install as administrator": "Install as administrator", + "Update to version {0}": "Update to version {0}", + "Installed Version": "Installed Version", + "Update as administrator": "Update as administrator", + "Interactive update": "Interactive update", + "Uninstall as administrator": "Uninstall as administrator", + "Interactive uninstall": "Interactive uninstall", + "Uninstall and remove data": "Uninstall and remove data", + "Not available": "Not available", + "Installer SHA512": "Installer SHA512", + "Unknown size": "Unknown size", + "No dependencies specified": "No dependencies specified", + "mandatory": "mandatory", + "optional": "optional", + "UniGetUI {0} is ready to be installed.": "UniGetUI {0} is ready to be installed.", + "The update process will start after closing UniGetUI": "The update process will start after closing UniGetUI", + "UniGetUI has been ran as administrator, which is not recommended. When running UniGetUI as administrator, EVERY operation launched from UniGetUI will have administrator privileges. You can still use the program, but we highly recommend not running UniGetUI with administrator privileges.": "UniGetUI has been ran as administrator, which is not recommended. When running UniGetUI as administrator, EVERY operation launched from UniGetUI will have administrator privileges. You can still use the program, but we highly recommend not running UniGetUI with administrator privileges.", + "Share anonymous usage data": "Share anonymous usage data", + "UniGetUI collects anonymous usage data in order to improve the user experience.": "UniGetUI collects anonymous usage data in order to improve the user experience.", + "Accept": "Accept", + "Software Updates": "Software Updates", + "Package Bundles": "Package Bundles", + "Settings": "Settings", + "Package Managers": "Package Managers", + "UniGetUI Log": "UniGetUI Log", + "Package Manager logs": "Package Manager logs", + "Operation history": "Operation history", + "Help": "Help", + "UniGetUI": "UniGetUI", + "You have installed UniGetUI Version {0}": "You have installed UniGetUI Version {0}", + "Disclaimer": "Disclaimer", + "UniGetUI is developed by Devolutions and is not affiliated with any of the compatible package managers.": "UniGetUI is developed by Devolutions and is not affiliated with any of the compatible package managers.", + "UniGetUI wouldn't have been possible without the help of the contributors. Thank you all 🥳": "UniGetUI wouldn't have been possible without the help of the contributors. Thank you all 🥳", + "UniGetUI uses the following libraries. Without them, UniGetUI wouldn't have been possible.": "UniGetUI Uses the following libraries. Without them, UniGetUI wouldn't have been possible.", + "{0} homepage": "{0} homepage", + "UniGetUI has been translated to more than 40 languages thanks to the volunteer translators. Thank you 🤝": "UniGetUI has been translated to more than 40 languages thanks to the volunteer translators. Thank you 🤝", + "Verbose": "Verbose", + "1 - Errors": "1 - Errors", + "2 - Warnings": "2 - Warnings", + "3 - Information (less)": "3 - Information (less)", + "4 - Information (more)": "4 - Information (more)", + "5 - information (debug)": "5 - Information (debug)", + "Warning": "Warning", + "The following settings may pose a security risk, hence they are disabled by default.": "The following settings may pose a security risk, hence they are disabled by default.", + "Enable the settings below if and only if you fully understand what they do, and the implications they may have.": "Enable the settings below IF AND ONLY IF you fully understand what they do, and the implications and dangers they may involve.", + "The settings will list, in their descriptions, the potential security issues they may have.": "The settings will list, in their descriptions, the potential security issues they may have.", + "The backup will include the complete list of the installed packages and their installation options. Ignored updates and skipped versions will also be saved.": "The backup will include the complete list of the installed packages and their installation options. Ignored updates and skipped versions will also be saved.", + "The backup will NOT include any binary file nor any program's saved data.": "The backup will NOT include any binary file nor any program's saved data.", + "The size of the backup is estimated to be less than 1MB.": "The size of the backup is estimated to be less than 1MB.", + "The backup will be performed after login.": "The backup will be performed after login.", + "{pcName} installed packages": "{pcName} installed packages", + "Current status: Not logged in": "Current status: Not logged in", + "You are logged in as {0} (@{1})": "You are logged in as {0} (@{1})", + "Nice! Backups will be uploaded to a private gist on your account": "Nice! Backups will be uploaded to a private gist on your account", + "Select backup": "Select backup", + "Settings imported from {0}": "Settings imported from {0}", + "UniGetUI Settings": "UniGetUI Settings", + "Settings exported to {0}": "Settings exported to {0}", + "UniGetUI settings were reset": "UniGetUI settings were reset", + "Allow pre-release versions": "Allow pre-release versions", + "Apply": "Apply", + "For security reasons, custom command-line arguments are disabled by default. Go to UniGetUI security settings to change this.": "For security reasons, custom command-line arguments are disabled by default. Go to UniGetUI security settings to change this.", + "Go to UniGetUI security settings": "Go to UniGetUI security settings", + "The following options will be applied by default each time a {0} package is installed, upgraded or uninstalled.": "The following options will be applied by default each time a {0} package is installed, upgraded or uninstalled.", + "Package's default": "Package's default", + "Install location can't be changed for {0} packages": "Install location can't be changed for {0} packages", + "The local icon cache currently takes {0} MB": "The local icon cache currently takes {0} MB", + "Username": "Username", + "Password": "Password", + "Credentials": "Credentials", + "It is not guaranteed that the provided credentials will be stored safely": "It is not guaranteed that the provided credentials will be stored safely", + "Partially": "Partially", + "Package manager": "Package manager", + "Compatible with proxy": "Compatible with proxy", + "Compatible with authentication": "Compatible with authentication", + "Proxy compatibility table": "Proxy compatibility table", + "{0} settings": "{0} settings", + "{0} status": "{0} status", + "Default installation options for {0} packages": "Default installation options for {0} packages", + "Expand version": "Expand version", + "The executable file for {0} was not found": "The executable file for {0} was not found", + "{pm} is disabled": "{pm} is disabled", + "Enable it to install packages from {pm}.": "Enable it to install packages from {pm}.", + "{pm} is enabled and ready to go": "{pm} is enabled and ready to go", + "{pm} version:": "{pm} version:", + "{pm} was not found!": "{pm} was not found!", + "You may need to install {pm} in order to use it with UniGetUI.": "You may need to install {pm} in order to use it with UniGetUI.", + "Scoop Installer - UniGetUI": "Scoop Installer - UniGetUI", + "Scoop Uninstaller - UniGetUI": "Scoop Uninstaller - UniGetUI", + "Clearing Scoop cache - UniGetUI": "Clearing Scoop cache - UniGetUI", + "Restart UniGetUI to fully apply changes": "Restart UniGetUI to fully apply changes", + "Restart UniGetUI": "Restart UniGetUI", + "Manage {0} sources": "Manage {0} sources", + "Add source": "Add source", + "Add": "Add", + "Source name": "Source name", + "Source URL": "Source URL", + "Other": "Other", + "No minimum age": "No minimum age", + "1 day": "a day", + "{0} days": "{0} days", + "Custom...": "Custom...", + "{0} minutes": "{0} minutes", + "1 hour": "an hour", + "{0} hours": "{0} hours", + "1 week": "1 week", + "Supports release dates": "Supports release dates", + "Release date support per package manager": "Release date support per package manager", + "Search for packages": "Search for packages", + "Local": "Local", + "OK": "OK", + "Last checked: {0}": "Last checked: {0}", + "{0} packages were found, {1} of which match the specified filters.": "{0} packages were found, {1} of which match the specified filters.", + "{0} selected": "{0} selected", + "(Last checked: {0})": "(Last checked: {0})", + "All packages selected": "All packages selected", + "Package selection cleared": "Package selection cleared", + "{0}: {1}": "{0}: {1}", + "More info": "More info", + "GitHub account": "GitHub account", + "Log in with GitHub to enable cloud package backup.": "Log in with GitHub to enable cloud package backup.", + "More details": "More details", + "Log in": "Log in", + "If you have cloud backup enabled, it will be saved as a GitHub Gist on this account": "If you have cloud backup enabled, it will be saved as a GitHub Gist on this account", + "Log out": "Log out", + "About UniGetUI": "About UniGetUI", + "About": "About", + "Third-party licenses": "Third-party licenses", + "Contributors": "Contributors", + "Translators": "Translators", + "Bundle security report": "Bundle security report", + "The bundle contained restricted content": "The bundle contained restricted content", + "UniGetUI – Crash Report": "UniGetUI – Crash Report", + "UniGetUI has crashed": "UniGetUI has crashed", + "Help us fix this by sending a crash report to Devolutions. All fields below are optional.": "Help us fix this by sending a crash report to Devolutions. All fields below are optional.", + "Email (optional)": "Email (optional)", + "your@email.com": "your@email.com", + "Additional details (optional)": "Additional details (optional)", + "Describe what you were doing when the crash occurred…": "Describe what you were doing when the crash occurred…", + "Crash report": "Crash report", + "Don't Send": "Don't Send", + "Send Report": "Send Report", + "Sending…": "Sending…", + "Unsaved changes": "Unsaved changes", + "You have unsaved changes in the current bundle. Do you want to discard them?": "You have unsaved changes in the current bundle. Do you want to discard them?", + "Discard changes": "Discard changes", + "Integrity violation": "Integrity violation", + "UniGetUI or some of its components are missing or corrupt. It is strongly recommended to reinstall UniGetUI to adress the situation.": "UniGetUI or some of its components are missing or corrupt. It is strongly recommended to reinstall UniGetUI to adress the situation.", + "• Refer to the UniGetUI Logs to get more details regarding the affected file(s)": "• Refer to the UniGetUI Logs to get more details regarding the affected file(s)", + "• Integrity checks can be disabled from the Experimental Settings": "• Integrity checks can be disabled from the Experimental Settings", + "Manage shortcuts": "Manage shortcuts", + "UniGetUI has detected the following desktop shortcuts which can be removed automatically on future upgrades": "UniGetUI has detected the following desktop shortcuts which can be removed automatically on future upgrades", + "Do you really want to reset this list? This action cannot be reverted.": "Do you really want to reset this list? This action cannot be reverted.", + "Desktop shortcuts list": "Desktop shortcuts list", + "Open in explorer": "Open in explorer", + "Remove from list": "Remove from list", + "When new shortcuts are detected, delete them automatically instead of showing this dialog.": "When new shortcuts are detected, delete them automatically instead of showing this dialog.", + "Not right now": "Not right now", + "Missing dependency": "Missing dependency", + "UniGetUI requires {0} to operate, but it was not found on your system.": "UniGetUI requires {0} to operate, but it was not found on your system.", + "Click on Install to begin the installation process. If you skip the installation, UniGetUI may not work as expected.": "Click on Install to begin the installation process. If you skip the installation, UniGetUI may not work as expected.", + "Alternatively, you can also install {0} by running the following command in a Windows PowerShell prompt:": "Alternatively, you can also install {0} by running the following command in a Windows PowerShell prompt:", + "Install {0}": "Install {0}", + "Do not show this dialog again for {0}": "Do not show this dialog again for {0}", + "Please wait while {0} is being installed. A black window may show up. Please wait until it closes.": "Please wait while {0} is being installed. A black (or blue) window may show up. Please wait until it closes.", + "{0} has been installed successfully.": "{0} has been installed successfully.", + "Please click on \"Continue\" to continue": "Please click on \"Continue\" to continue", + "Continue": "Continue", + "{0} has been installed successfully. It is recommended to restart UniGetUI to finish the installation": "{0} has been installed successfully. It is recommended to restart UniGetUI to finish the installation", + "Restart later": "Restart later", + "An error occurred:": "An error occurred:", + "Please see the Command-line Output or refer to the Operation History for further information about the issue.": "Please see the Command-line Output or refer to the Operation History for further information about the issue.", + "Retry as administrator": "Retry as administrator", + "Retry interactively": "Retry interactively", + "Retry skipping integrity checks": "Retry skipping integrity checks", + "Installation options": "Installation options", + "Save": "Save", + "UniGetUI collects anonymous usage data with the sole purpose of understanding and improving the user experience.": "UniGetUI collects anonymous usage data with the sole purpose of understanding and improving the user experience.", + "More details about the shared data and how it will be processed": "More details about the shared data and how it will be processed", + "Do you accept that UniGetUI collects and sends anonymous usage statistics, with the sole purpose of understanding and improving the user experience?": "Do you accept that UniGetUI collects and sends anonymous usage statistics, with the sole purpose of understanding and improving the user experience?", + "Decline": "Decline", + "No personal information is collected nor sent, and the collected data is anonimized, so it can't be back-tracked to you.": "No personal information is collected nor sent, and the collected data is anonimized, so it can't be back-tracked to you.", + "Navigation panel": "Navigation panel", + "Operations": "Operations", + "Toggle operations panel": "Toggle operations panel", + "Bulk operations": "Bulk operations", + "Retry failed": "Retry failed", + "Clear successful": "Clear successful", + "Clear finished": "Clear finished", + "Cancel all": "Cancel all", + "More": "More", + "Toggle navigation panel": "Toggle navigation panel", + "Minimize": "Minimize", + "Maximize": "Maximize", + "UniGetUI by Devolutions": "UniGetUI by Devolutions", + "UniGetUI is an application that makes managing your software easier, by providing an all-in-one graphical interface for your command-line package managers.": "UniGetUI is an application that makes managing your software easier, by providing an all-in-one graphical interface for your command-line package managers.", + "Useful links": "Useful links", + "UniGetUI Homepage": "UniGetUI Homepage", + "Report an issue or submit a feature request": "Report an issue or submit a feature request", + "UniGetUI Repository": "UniGetUI Repository", + "View GitHub Profile": "View GitHub Profile", + "UniGetUI License": "UniGetUI License", + "Using UniGetUI implies the acceptation of the MIT License": "Using UniGetUI implies the acceptance of the MIT License", + "Become a translator": "Become a translator", + "Go back": "Go back", + "Go forward": "Go forward", + "Go to home page": "Go to home page", + "Reload page": "Reload page", + "View page on browser": "View page on browser", + "The built-in browser is not supported on Linux yet.": "The built-in browser is not supported on Linux yet.", + "Open in browser": "Open in browser", + "Copy to clipboard": "Copy to clipboard", + "Export to a file": "Export to a file", + "Log level:": "Log level:", + "Reload log": "Reload log", + "Export log": "Export log", + "Text": "Text", + "Change how operations request administrator rights": "Change how operations request administrator rights", + "Restrictions on package operations": "Restrictions on package operations", + "Restrictions on package managers": "Restrictions on package managers", + "Restrictions when importing package bundles": "Restrictions when importing package bundles", + "Ask for administrator privileges once for each batch of operations": "Ask for administrator privileges once for each batch of operations", + "Ask only once for administrator privileges": "Ask only once for administrator privileges", + "Prohibit any kind of Elevation via UniGetUI Elevator or GSudo": "Prohibit any kind of Elevation via UniGetUI Elevator or GSudo", + "This option WILL cause issues. Any operation incapable of elevating itself WILL FAIL. Install/update/uninstall as administrator will NOT WORK.": "This option WILL cause issues. Any operation incapable of elevating itself WILL FAIL. Install/update/uninstall as administrator will NOT WORK.", + "Allow custom command-line arguments": "Allow custom command-line arguments", + "Custom command-line arguments can change the way in which programs are installed, upgraded or uninstalled, in a way UniGetUI cannot control. Using custom command-lines can break packages. Proceed with caution.": "Custom command-line arguments can change the way in which programs are installed, upgraded or uninstalled, in a way UniGetUI cannot control. Using custom command-lines can break packages. Proceed with caution.", + "Ignore custom pre-install and post-install commands when importing packages from a bundle": "Ignore custom pre-install and post-install commands when importing packages from a bundle", + "Pre and post install commands will be run before and after a package gets installed, upgraded or uninstalled. Be aware that they may break things unless used carefully": "Pre and post install commands will be run before and after a package gets installed, upgraded or uninstalled. Be aware that they may break things unless used carefully", + "Allow changing the paths for package manager executables": "Allow changing the paths for package manager executables", + "Turning this on enables changing the executable file used to interact with package managers. While this allows finer-grained customization of your install processes, it may also be dangerous": "Turning this on enables changing the executable file used to interact with package managers. While this allows finer-grained customization of your install processes, it may also be dangerous", + "Allow importing custom command-line arguments when importing packages from a bundle": "Allow importing custom command-line arguments when importing packages from a bundle", + "Malformed command-line arguments can break packages, or even allow a malicious actor to gain privileged execution. Therefore, importing custom command-line arguments is disabled by default": "Malformed command-line arguments can break packages, or even allow a malicious actor to gain privileged execution. Therefore, importing custom command-line arguments is disabled by default.", + "Allow importing custom pre-install and post-install commands when importing packages from a bundle": "Allow importing custom pre-install and post-install commands when importing packages from a bundle", + "Pre and post install commands can do very nasty things to your device, if designed to do so. It can be very dangerous to import the commands from a bundle, unless you trust the source of that package bundle": "Pre and post install commands can do very nasty things to your device, if designed to do so. It can be very dangerous to import the commands from a bundle, unless you trust the source of that package bundle", + "Administrator rights and other dangerous settings": "Administrator rights and other dangerous settings", + "Package backup": "Package backup", + "Cloud package backup": "Cloud package backup", + "Local package backup": "Local package backup", + "Local backup advanced options": "Local backup advanced options", + "Log in with GitHub": "Log in with GitHub", + "Log out from GitHub": "Log out from GitHub", + "Periodically perform a cloud backup of the installed packages": "Periodically perform a cloud backup of the installed packages", + "Cloud backup uses a private GitHub Gist to store a list of installed packages": "Cloud backup uses a private GitHub Gist to store a list of installed packages", + "Perform a cloud backup now": "Perform a cloud backup now", + "Backup": "Backup", + "Restore a backup from the cloud": "Restore a backup from the cloud", + "Begin the process to select a cloud backup and review which packages to restore": "Begin the process to select a cloud backup and review which packages to restore", + "Periodically perform a local backup of the installed packages": "Periodically perform a local backup of the installed packages", + "Perform a local backup now": "Perform a local backup now", + "Change backup output directory": "Change backup output directory", + "Set a custom backup file name": "Set a custom backup file name", + "Leave empty for default": "Leave empty for default", + "Add a timestamp to the backup file names": "Add a timestamp to the backup file names", + "Backup and Restore": "Backup and Restore", + "Enable background api (UniGetUI Widgets and Sharing, port 7058)": "Enable background API (Widgets for UniGetUI and Sharing, port 7058)", + "Wait for the device to be connected to the internet before attempting to do tasks that require internet connectivity.": "Wait for the device to be connected to the internet before attempting to do tasks that require internet connectivity.", + "Disable the 1-minute timeout for package-related operations": "Disable the 1-minute timeout for package-related operations", + "Use installed GSudo instead of UniGetUI Elevator": "Use installed GSudo instead of UniGetUI Elevator", + "Use a custom icon and screenshot database URL": "Use a custom icon and screenshot database URL", + "Enable background CPU Usage optimizations (see Pull Request #3278)": "Enable background CPU usage optimizations (see Pull Request #3278)", + "Perform integrity checks at startup": "Perform integrity checks at startup", + "When batch installing packages from a bundle, install also packages that are already installed": "When batch installing packages from a bundle, install also packages that are already installed", + "Experimental settings and developer options": "Experimental settings and developer options", + "Show UniGetUI's version and build number on the titlebar.": "Show UniGetUI's version on the titlebar", + "Language": "Language", + "UniGetUI updater": "UniGetUI updater", + "Telemetry": "Telemetry", + "Manage UniGetUI settings": "Manage UniGetUI settings", + "Related settings": "Related settings", + "Update UniGetUI automatically": "Update UniGetUI automatically", + "Check for updates": "Check for updates", + "Install prerelease versions of UniGetUI": "Install prerelease versions of UniGetUI", + "Manage telemetry settings": "Manage telemetry settings", + "Manage": "Manage", + "Import settings from a local file": "Import settings from a local file", + "Import": "Import", + "Export settings to a local file": "Export settings to a local file", + "Export": "Export", + "Reset UniGetUI": "Reset UniGetUI", + "User interface preferences": "User interface preferences", + "Application theme, startup page, package icons, clear successful installs automatically": "Application theme, startup page, package icons, clear successful installs automatically", + "General preferences": "General preferences", + "UniGetUI display language:": "UniGetUI display language:", + "System language": "System language", + "Is your language missing or incomplete?": "Is your language missing or incomplete?", + "Appearance": "Appearance", + "Rendering": "Rendering", + "Automatically switch to software rendering when Windows has no hardware GPU": "Automatically switch to software rendering when Windows has no hardware GPU", + "UniGetUI on the background and system tray": "UniGetUI on the background and system tray", + "Package lists": "Package lists", + "Use classic mode": "Use classic mode", + "Restart UniGetUI to apply this change": "Restart UniGetUI to apply this change", + "The classic UI is disabled for beta testers": "The classic UI is disabled for beta testers", + "Close UniGetUI to the system tray": "Close UniGetUI to the system tray", + "Manage UniGetUI autostart behaviour": "Manage UniGetUI autostart behaviour", + "Show package icons on package lists": "Show package icons on package lists", + "Clear cache": "Clear cache", + "Select upgradable packages by default": "Select upgradable packages by default", + "Light": "Light", + "Dark": "Dark", + "Follow system color scheme": "Follow system color scheme", + "Application theme:": "Application theme:", + "UniGetUI startup page:": "UniGetUI startup page:", + "Proxy settings": "Proxy settings", + "Other settings": "Other settings", + "Connect the internet using a custom proxy": "Connect the internet using a custom proxy", + "Please note that not all package managers may fully support this feature": "Please note that not all package managers may fully support this feature", + "Proxy URL": "Proxy URL", + "Enter proxy URL here": "Enter proxy URL here", + "Authenticate to the proxy with a user and a password": "Authenticate to the proxy with a user and a password", + "Internet and proxy settings": "Internet and proxy settings", + "Package manager preferences": "Package manager preferences", + "Ready": "Ready", + "Not found": "Not found", + "Notification preferences": "Notification preferences", + "Notification types": "Notification types", + "The system tray icon must be enabled in order for notifications to work": "The system tray icon must be enabled in order for notifications to work", + "Enable UniGetUI notifications": "Enable UniGetUI notifications", + "Show a notification when there are available updates": "Show a notification when there are available updates", + "Show a silent notification when an operation is running": "Show a silent notification when an operation is running", + "Show a notification when an operation fails": "Show a notification when an operation fails", + "Show a notification when an operation finishes successfully": "Show a notification when an operation finishes successfully", + "Concurrency and execution": "Concurrency and execution", + "Automatic desktop shortcut remover": "Automatic desktop shortcut remover", + "Choose how many operations should be performed in parallel": "Choose how many operations should be performed in parallel", + "Clear successful operations from the operation list after a 5 second delay": "Clear successful operations from the operation list after a 5 second delay", + "Download operations are not affected by this setting": "Download operations are not affected by this setting", + "You may lose unsaved data": "You may lose unsaved data", + "Ask to delete desktop shortcuts created during an install or upgrade.": "Ask to delete desktop shortcuts created during an install or upgrade.", + "Package update preferences": "Package update preferences", + "Update check frequency, automatically install updates, etc.": "Update check frequency, automatically install updates, etc.", + "Reduce UAC prompts, elevate installations by default, unlock certain dangerous features, etc.": "Reduce UAC prompts, elevate installations by default, unlock certain dangerous features, etc.", + "Package operation preferences": "Package operation preferences", + "Enable {pm}": "Enable {pm}", + "Not finding the file you are looking for? Make sure it has been added to path.": "Not finding the file you are looking for? Make sure it has been added to path.", + "Select the executable to be used. The following list shows the executables found by UniGetUI": "Select the executable to be used. The following list shows the executables found by UniGetUI", + "For security reasons, changing the executable file is disabled by default": "For security reasons, changing the executable file is disabled by default", + "Change this": "Change this", + "Copy path": "Copy path", + "Current executable file:": "Current executable file:", + "Ignore packages from {pm} when showing a notification about updates": "Ignore packages from {pm} when showing a notification about updates", + "Update security": "Update security", + "Use global setting": "Use global setting", + "Minimum age for updates": "Minimum age for updates", + "e.g. 10": "e.g. 10", + "Custom minimum age (days)": "Custom minimum age (days)", + "{pm} does not provide release dates for its packages, so this setting will have no effect": "{pm} does not provide release dates for its packages, so this setting will have no effect", + "{pm} only provides release dates for some of its packages, so this setting will only apply to those packages": "{pm} only provides release dates for some of its packages, so this setting will only apply to those packages", + "Override the global minimum update age for this package manager": "Override the global minimum update age for this package manager", + "View {0} logs": "View {0} logs", + "If Python cannot be found or is not listing packages but is installed on the system, ": "If Python cannot be found or is not listing packages but is installed on the system, ", + "Advanced options": "Advanced options", + "WinGet command-line tool": "WinGet command-line tool", + "Choose which command-line tool UniGetUI uses for WinGet operations when the COM API is not used": "Choose which command-line tool UniGetUI uses for WinGet operations when the COM API is not used", + "WinGet COM API": "WinGet COM API", + "Choose whether UniGetUI can use the WinGet COM API before falling back to the command-line tool": "Choose whether UniGetUI can use the WinGet COM API before falling back to the command-line tool", + "Reset WinGet": "Reset WinGet", + "This may help if no packages are listed": "This may help if no packages are listed", + "Force install location parameter when updating packages with custom locations": "Force install location parameter when updating packages with custom locations", + "Install Scoop": "Install Scoop", + "Uninstall Scoop (and its packages)": "Uninstall Scoop (and its packages)", + "Run cleanup and clear cache": "Run cleanup and clear cache", + "Run": "Run", + "Enable Scoop cleanup on launch": "Enable Scoop cleanup on launch", + "Default vcpkg triplet": "Default vcpkg triplet", + "Change vcpkg root location": "Change vcpkg root location", + "Reset vcpkg root location": "Reset vcpkg root location", + "Open vcpkg root location": "Open vcpkg root location", + "Language, theme and other miscellaneous preferences": "Language, theme and other miscellaneous preferences", + "Show notifications on different events": "Show notifications on different events", + "Change how UniGetUI checks and installs available updates for your packages": "Change how UniGetUI checks and installs available updates for your packages", + "Automatically save a list of all your installed packages to easily restore them.": "Automatically save a list of all your installed packages to easily restore them.", + "Enable and disable package managers, change default install options, etc.": "Enable and disable package managers, change default install options, etc.", + "Internet connection settings": "Internet connection settings", + "Proxy settings, etc.": "Proxy settings, etc.", + "Beta features and other options that shouldn't be touched": "Beta features and other options that shouldn't be touched", + "Reload sources": "Reload sources", + "Delete source": "Delete source", + "Known sources": "Known sources", + "Update checking": "Update checking", + "Automatic updates": "Automatic updates", + "Check for package updates periodically": "Check for package updates periodically", + "Check for updates every:": "Check for updates every:", + "Install available updates automatically": "Install available updates automatically", + "Do not automatically install updates when the network connection is metered": "Do not automatically install updates when the network connection is metered", + "Do not automatically install updates when the device runs on battery": "Do not automatically install updates when the device runs on battery", + "Do not automatically install updates when the battery saver is on": "Do not automatically install updates when the battery saver is on", + "Only show updates that are at least the specified number of days old": "Only show updates that are at least the specified number of days old", + "Warn me when the installer URL host changes between the installed version and the new version (WinGet only)": "Warn me when the installer URL host changes between the installed version and the new version (WinGet only)", + "Change how UniGetUI handles install, update and uninstall operations.": "Change how UniGetUI handles install, update and uninstall operations.", + "Navigation": "Navigation", + "Check for UniGetUI updates": "Check for UniGetUI updates", + "Quit UniGetUI": "Quit UniGetUI", + "Filters": "Filters", + "Sources": "Sources", + "Search for packages to start": "Search for packages to start", + "Select all": "Select all", + "Clear selection": "Clear selection", + "Instant search": "Instant search", + "Distinguish between uppercase and lowercase": "Distinguish between uppercase and lowercase", + "Ignore special characters": "Ignore special characters", + "Search mode": "Search mode", + "Both": "Both", + "Exact match": "Exact match", + "Show similar packages": "Show similar packages", + "Loading": "Loading", + "Package": "Package", + "More options": "More options", + "Order by:": "Order by:", + "Name": "Name", + "Id": "Id", + "Ascendant": "Ascendant", + "Descendant": "Descendant", + "View modes": "View modes", + "Reload": "Reload", + "Closed": "Closed", + "Ascending": "Ascending", + "Descending": "Descending", + "{0}: {1}, {2}": "{0}: {1}, {2}", + "Order by": "Order by", + "No results were found matching the input criteria": "No results were found matching the input criteria", + "No packages were found": "No packages were found", + "Loading packages": "Loading packages", + "Skip integrity checks": "Skip integrity checks", + "Download selected installers": "Download selected installers", + "Install selection": "Install selection", + "Install options": "Install options", + "Add selection to bundle": "Add selection to bundle", + "Download installer": "Download installer", + "Uninstall selection": "Uninstall selection", + "Uninstall options": "Uninstall options", + "Ignore selected packages": "Ignore selected packages", + "Open install location": "Open install location", + "Reinstall package": "Reinstall package", + "Uninstall package, then reinstall it": "Uninstall package, then reinstall it", + "Ignore updates for this package": "Ignore updates for this package", + "WinGet malfunction detected": "WinGet malfunction detected", + "It looks like WinGet is not working properly. Do you want to attempt to repair WinGet?": "It looks like WinGet is not working properly. Do you want to attempt to repair WinGet?", + "Repair WinGet": "Repair WinGet", + "Updates will no longer be ignored for {0}": "Updates will no longer be ignored for {0}", + "Updates are now ignored for {0}": "Updates are now ignored for {0}", + "Do not ignore updates for this package anymore": "Do not ignore updates for this package anymore", + "Add packages or open an existing package bundle": "Add packages or open an existing package bundle", + "Add packages to start": "Add packages to start", + "The current bundle has no packages. Add some packages to get started": "The current bundle has no packages. Add some packages to get started", + "New": "New", + "Save as": "Save as", + "Create .ps1 script": "Create .ps1 script", + "Remove selection from bundle": "Remove selection from bundle", + "Skip hash checks": "Skip hash checks", + "The package bundle is not valid": "The package bundle is not valid", + "The bundle you are trying to load appears to be invalid. Please check the file and try again.": "The bundle you are trying to load appears to be invalid. Please check the file and try again.", + "Package bundle": "Package bundle", + "Could not create bundle": "Could not create bundle", + "The package bundle could not be created due to an error.": "The package bundle could not be created due to an error.", + "Install script": "Install script", + "PowerShell script": "PowerShell script", + "The installation script saved to {0}": "The installation script saved to {0}", + "An error occurred": "An error occurred", + "An error occurred while attempting to create an installation script:": "An error occurred while attempting to create an installation script:", + "Hooray! No updates were found.": "Hooray! No updates were found.", + "Uninstall selected packages": "Uninstall selected packages", + "Update selection": "Update selection", + "Update options": "Update options", + "Uninstall package, then update it": "Uninstall package, then update it", + "Uninstall package": "Uninstall package", + "Skip this version": "Skip this version", + "Pause updates for": "Pause updates for", + "User | Local": "User | Local", + "Machine | Global": "Machine | Global", + "The default package manager for Debian/Ubuntu-based Linux distributions.
Contains: Debian/Ubuntu packages": "The default package manager for Debian/Ubuntu-based Linux distributions.
Contains: Debian/Ubuntu packages", + "The Rust package manager.
Contains: Rust libraries and programs written in Rust": "The Rust package manager.
Contains: Rust libraries and programs written in Rust", + "The classical package manager for windows. You'll find everything there.
Contains: General Software": "The classic package manager for Windows. You'll find everything there.
Contains: General Software", + "The default package manager for RHEL/Fedora-based Linux distributions.
Contains: RPM packages": "The default package manager for RHEL/Fedora-based Linux distributions.
Contains: RPM packages", + "A repository full of tools and executables designed with Microsoft's .NET ecosystem in mind.
Contains: .NET related tools and scripts": "A repository full of tools and executables designed with Microsoft's .NET ecosystem in mind.
Contains: .NET related tools and scripts", + "The universal Linux package manager for desktop applications.
Contains: Flatpak applications from configured remotes": "The universal Linux package manager for desktop applications.
Contains: Flatpak applications from configured remotes", + "NuPkg (zipped manifest)": "NuPkg (zipped manifest)", + "The Missing Package Manager for macOS (or Linux).
Contains: Formulae, Casks": "The Missing Package Manager for macOS (or Linux).
Contains: Formulae, Casks", + "Node JS's package manager. Full of libraries and other utilities that orbit the javascript world
Contains: Node javascript libraries and other related utilities": "Node JS's package manager. Full of libraries and other utilities that orbit the javascript world
Contains: Node javascript libraries and other related utilities", + "The default package manager for Arch Linux and its derivatives.
Contains: Arch Linux packages": "The default package manager for Arch Linux and its derivatives.
Contains: Arch Linux packages", + "Python's library manager. Full of python libraries and other python-related utilities
Contains: Python libraries and related utilities": "Python's library manager. Full of python libraries and other python-related utilities
Contains: Python libraries and related utilities", + "PowerShell's package manager. Find libraries and scripts to expand PowerShell capabilities
Contains: Modules, Scripts, Cmdlets": "PowerShell's package manager. Find libraries and scripts to expand PowerShell capabilities
Contains: Modules, Scripts, Cmdlets", + "extracted": "extracted", + "Scoop package": "Scoop package", + "Great repository of unknown but useful utilities and other interesting packages.
Contains: Utilities, Command-line programs, General Software (extras bucket required)": "Great repository of unknown but useful utilities and other interesting packages.
Contains: Utilities, Command-line programs, General Software (extras bucket required)", + "The universal Linux package manager by Canonical.
Contains: Snap packages from the Snapcraft store": "The universal Linux package manager by Canonical.
Contains: Snap packages from the Snapcraft store", + "library": "library", + "feature": "feature", + "A popular C/C++ library manager. Full of C/C++ libraries and other C/C++-related utilities
Contains: C/C++ libraries and related utilities": "A popular C/C++ library manager. Full of C/C++ libraries and other C/C++-related utilities
Contains: C/C++ libraries and related utilities", + "option": "option", + "This package cannot be installed from an elevated context.": "This package cannot be installed from an elevated context.", + "Please run UniGetUI as a regular user and try again.": "Please run UniGetUI as a regular user and try again.", + "Please check the installation options for this package and try again": "Please check the installation options for this package and try again", + "Microsoft's official package manager. Full of well-known and verified packages
Contains: General Software, Microsoft Store apps": "Microsoft's official package manager. Full of well-known and verified packages
Contains: General Software, Microsoft Store apps", + "Local PC": "Local PC", + "Android Subsystem": "Android Subsystem", + "Operation on queue (position {0})...": "Operation on queue (position {0})...", + "Click here for more details": "Click here for more details", + "Operation canceled by user": "Operation canceled by user", + "Running PreOperation ({0}/{1})...": "Running PreOperation ({0}/{1})...", + "PreOperation {0} out of {1} failed, and was tagged as necessary. Aborting...": "PreOperation {0} out of {1} failed, and was tagged as necessary. Aborting...", + "PreOperation {0} out of {1} finished with result {2}": "PreOperation {0} out of {1} finished with result {2}", + "Starting operation...": "Starting operation...", + "Running PostOperation ({0}/{1})...": "Running PostOperation ({0}/{1})...", + "PostOperation {0} out of {1} failed, and was tagged as necessary. Aborting...": "PostOperation {0} out of {1} failed, and was tagged as necessary. Aborting...", + "PostOperation {0} out of {1} finished with result {2}": "PostOperation {0} out of {1} finished with result {2}", + "{package} installer download": "{package} installer download", + "{0} installer is being downloaded": "{0} installer is being downloaded", + "Download succeeded": "Download succeeded", + "{package} installer was downloaded successfully": "{package} installer was downloaded successfully", + "Download failed": "Download failed", + "{package} installer could not be downloaded": "{package} installer could not be downloaded", + "{package} Installation": "{package} Installation", + "{0} is being installed": "{0} is being installed", + "Installation succeeded": "Installation succeeded", + "{package} was installed successfully": "{package} was installed successfully", + "Installation failed": "Installation failed", + "{package} could not be installed": "{package} could not be installed", + "{package} Update": "{package} Update", + "Update succeeded": "Update succeeded", + "{package} was updated successfully": "{package} was updated successfully", + "Update failed": "Update failed", + "{package} could not be updated": "{package} could not be updated", + "{package} Uninstall": "{package} Uninstall", + "{0} is being uninstalled": "{0} is being uninstalled", + "Uninstall succeeded": "Uninstall succeeded", + "{package} was uninstalled successfully": "{package} was uninstalled successfully", + "Uninstall failed": "Uninstall failed", + "{package} could not be uninstalled": "{package} could not be uninstalled", + "Adding source {source}": "Adding source {source}", + "Adding source {source} to {manager}": "Adding source {source} to {manager}", + "Source added successfully": "Source added successfully", + "The source {source} was added to {manager} successfully": "The source {source} was added to {manager} successfully", + "Could not add source": "Could not add source", + "Could not add source {source} to {manager}": "Could not add source {source} to {manager}", + "Removing source {source}": "Removing source {source}", + "Removing source {source} from {manager}": "Removing source {source} from {manager}", + "Source removed successfully": "Source removed successfully", + "The source {source} was removed from {manager} successfully": "The source {source} was removed from {manager} successfully", + "Could not remove source": "Could not remove source", + "Could not remove source {source} from {manager}": "Could not remove source {source} from {manager}", + "The package manager \"{0}\" was not found": "The package manager \"{0}\" was not found", + "The package manager \"{0}\" is disabled": "The package manager \"{0}\" is disabled", + "There is an error with the configuration of the package manager \"{0}\"": "There is an error with the configuration of the package manager \"{0}\"", + "The package \"{0}\" was not found on the package manager \"{1}\"": "The package \"{0}\" was not found on the package manager \"{1}\"", + "{0} is disabled": "{0} is disabled", + "{0} weeks": "{0} weeks", + "1 month": "1 month", + "{0} months": "{0} months", + "Something went wrong": "Something went wrong", + "An interal error occurred. Please view the log for further details.": "An internal error occurred. Please view the log for further details.", + "No applicable installer was found for the package {0}": "No applicable installer was found for the package {0}", + "Integrity checks will not be performed during this operation": "Integrity checks will not be performed during this operation", + "This is not recommended.": "This is not recommended.", + "Run now": "Run now", + "Run next": "Run next", + "Run last": "Run last", + "Show in explorer": "Show in explorer", + "Checked": "Checked", + "Unchecked": "Unchecked", + "This package is already installed": "This package is already installed", + "This package can be upgraded to version {0}": "This package can be upgraded to version {0}", + "Updates for this package are ignored": "Updates for this package are ignored", + "This package is being processed": "This package is being processed", + "This package is not available": "This package is not available", + "Select the source you want to add:": "Select the source you want to add:", + "Source name:": "Source name:", + "Source URL:": "Source URL:", + "An error occurred when adding the source: ": "An error occurred when adding the source: ", + "Package management made easy": "Package management made easy", + "version {0}": "version {0}", + "[RAN AS ADMINISTRATOR]": "RAN AS ADMINISTRATOR", + "Portable mode": "Portable mode\n", + "DEBUG BUILD": "DEBUG BUILD", + "Here you can change UniGetUI's behaviour regarding the following shortcuts. Checking a shortcut will make UniGetUI delete it if if gets created on a future upgrade. Unchecking it will keep the shortcut intact": "Here you can change UniGetUI's behaviour regarding the following shortcuts. Checking a shortcut will make UniGetUI delete it if gets created on a future upgrade. Unchecking it will keep the shortcut intact", + "Manual scan": "Manual scan", + "Existing shortcuts on your desktop will be scanned, and you will need to pick which ones to keep and which ones to remove.": "Existing shortcuts on your desktop will be scanned, and you will need to pick which ones to keep and which ones to remove.", + "Delete?": "Delete?", + "I understand": "I understand", + "Chocolatey setup changed": "Chocolatey setup changed", + "UniGetUI no longer includes its own private Chocolatey installation. A legacy UniGetUI-managed Chocolatey installation was detected for this user profile, but system Chocolatey was not found. Chocolatey will stay unavailable in UniGetUI until Chocolatey is installed on the system and UniGetUI is restarted. Applications previously installed through UniGetUI's bundled Chocolatey may still appear under other sources such as Local PC or WinGet.": "UniGetUI no longer includes its own private Chocolatey installation. A legacy UniGetUI-managed Chocolatey installation was detected for this user profile, but system Chocolatey was not found. Chocolatey will stay unavailable in UniGetUI until Chocolatey is installed on the system and UniGetUI is restarted. Applications previously installed through UniGetUI's bundled Chocolatey may still appear under other sources such as Local PC or WinGet.", + "NOTE: This troubleshooter can be disabled from UniGetUI Settings, on the WinGet section": "NOTE: This troubleshooter can be disabled from UniGetUI Settings, on the WinGet section", + "Restart": "Restart", + "Are you sure you want to delete all shortcuts?": "Are you sure you want to delete all shortcuts?", + "Any new shorcuts created during an install or an update operation will be deleted automatically, instead of showing a confirmation prompt the first time they are detected.": "Any new shortcuts created during an install or an update operation will be deleted automatically, instead of showing a confirmation prompt the first time they are detected.", + "Any shorcuts created or modified outside of UniGetUI will be ignored. You will be able to add them via the {0} button.": "Any shorcuts created or modified outside of UniGetUI will be ignored. You will be able to add them via the {0} button.", + "Are you really sure you want to enable this feature?": "Are you really sure you want to enable this feature?", + "No new shortcuts were found during the scan.": "No new shortcuts were found during the scan.", + "How to add packages to a bundle": "How to add packages to a bundle", + "In order to add packages to a bundle, you will need to: ": "In order to add packages to a bundle, you will need to: ", + "1. Navigate to the \"{0}\" or \"{1}\" page.": "1. Navigate to the \"{0}\" or \"{1}\" page.", + "2. Locate the package(s) you want to add to the bundle, and select their leftmost checkbox.": "2. Locate the package(s) you want to add to the bundle, and select their leftmost checkbox.", + "3. When the packages you want to add to the bundle are selected, find and click the option \"{0}\" on the toolbar.": "3. When the packages you want to add to the bundle are selected, find and click the option \"{0}\" on the toolbar.", + "4. Your packages will have been added to the bundle. You can continue adding packages, or export the bundle.": "4. Your packages will have been added to the bundle. You can continue adding packages, or export the bundle.", + "Which backup do you want to open?": "Which backup do you want to open?", + "Select the backup you want to open. Later, you will be able to review which packages you want to install.": "Select the backup you want to open. Later, you will be able to review which packages/programs you want to restore.", + "There are ongoing operations. Quitting UniGetUI may cause them to fail. Do you want to continue?": "There are ongoing operations. Quitting UniGetUI may cause them to fail. Do you want to continue?", + "UniGetUI or some of its components are missing or corrupt.": "UniGetUI or some of its components are missing or corrupt.", + "It is strongly recommended to reinstall UniGetUI to adress the situation.": "It is strongly recommended to reinstall UniGetUI to address the situation.", + "Refer to the UniGetUI Logs to get more details regarding the affected file(s)": "Refer to the UniGetUI Logs to get more details regarding the affected file(s)", + "Integrity checks can be disabled from the Experimental Settings": "Integrity checks can be disabled from the Experimental Settings", + "Repair UniGetUI": "Repair UniGetUI", + "Live output": "Live output", + "This package bundle had some settings that are potentially dangerous, and may be ignored by default.": "This package bundle had some settings that are potentially dangerous, and may be ignored by default.", + "Entries that show in YELLOW will be IGNORED.": "Entries that show in YELLOW will be IGNORED.", + "Entries that show in RED will be IMPORTED.": "Entries that show in RED will be IMPORTED.", + "You can change this behavior on UniGetUI security settings.": "You can change this behavior on UniGetUI security settings.", + "Open UniGetUI security settings": "Open UniGetUI security settings", + "Should you modify the security settings, you will need to open the bundle again for the changes to take effect.": "Should you modify the security settings, you will need to open the bundle again for the changes to take effect.", + "Details of the report:": "Details of the report:", + "Are you sure you want to create a new package bundle? ": "Are you sure you want to create a new package bundle? ", + "Any unsaved changes will be lost": "Any unsaved changes will be lost", + "Warning!": "Warning!", + "For security reasons, custom command-line arguments are disabled by default. Go to UniGetUI security settings to change this. ": "For security reasons, custom command-line arguments are disabled by default. Go to UniGetUI security settings to change this. ", + "Change default options": "Change default options", + "Ignore future updates for this package": "Ignore future updates for this package", + "For security reasons, pre-operation and post-operation scripts are disabled by default. Go to UniGetUI security settings to change this. ": "For security reasons, pre-operation and post-operation scripts are disabled by default. Go to UniGetUI security settings to change this. ", + "You can define the commands that will be run before or after this package is installed, updated or uninstalled. They will be run on a command prompt, so CMD scripts will work here.": "You can define the commands that will be run before or after this package is installed, updated or uninstalled. They will be run on a command prompt, so CMD scripts will work here.", + "Change this and unlock": "Change this and unlock", + "{0} Install options are currently locked because {0} follows the default install options.": "{0} Install options are currently locked because {0} follows the default install options.", + "Unset or unknown": "Unset or unknown", + "This package has no screenshots or is missing the icon? Contrbute to UniGetUI by adding the missing icons and screenshots to our open, public database.": "This package has no screenshots or is missing the icon? Contribute to UniGetUI by adding the missing icons and screenshots to our open, public database.", + "Become a contributor": "Become a contributor", + "Update to {0} available": "Update to {0} available", + "Reinstall": "Reinstall", + "Installer not available": "Installer not available", + "Version:": "Version:", + "UniGetUI Version {0}": "UniGetUI Version {0}", + "Performing backup, please wait...": "Performing backup, please wait...", + "An error occurred while logging in: ": "An error occurred while logging in: ", + "Fetching available backups...": "Fetching available backups...", + "Done!": "Done!", + "The cloud backup has been loaded successfully.": "The cloud backup has been loaded successfully.", + "An error occurred while loading a backup: ": "An error occurred while loading a backup: ", + "Backing up packages to GitHub Gist...": "Backing up packages to GitHub Gist...", + "Backup Successful": "Backup successful", + "The cloud backup completed successfully.": "The cloud backup completed successfully.", + "Could not back up packages to GitHub Gist: ": "Could not back up packages to GitHub Gist: ", + "It is not guaranteed that the provided credentials will be stored safely, so you may as well not use the credentials of your bank account": "It is not guaranteed that the provided credentials will be stored safely, so you may as well not use the credentials of your bank account", + "Enable the automatic WinGet troubleshooter": "Enable the automatic WinGet troubleshooter", + "Add updates that fail with a 'no applicable update found' to the ignored updates list": "Add updates that fail with 'no applicable update found' to the ignored updates list.", + "Invalid selection": "Invalid selection", + "No package was selected": "No package was selected", + "More than 1 package was selected": "More than 1 package was selected", + "List": "List", + "Grid": "Grid", + "Icons": "Icons", + "\"{0}\" is a local package and does not have available details": "\"{0}\" is a local package and does not have available details", + "\"{0}\" is a local package and is not compatible with this feature": "\"{0}\" is a local package and is not compatible with this feature", + "Add packages to bundle": "Add packages to bundle", + "Preparing packages, please wait...": "Preparing packages, please wait...", + "Loading packages, please wait...": "Loading packages, please wait...", + "Saving packages, please wait...": "Saving packages, please wait...", + "The bundle was created successfully on {0}": "The bundle was created successfully on {0}", + "User profile": "User profile", + "Error": "Error", + "Log in failed: ": "Log in failed: ", + "Log out failed: ": "Log out failed: ", + "Package backup settings": "Package backup settings", + "Show the release notes after UniGetUI is updated": "Show the release notes after UniGetUI is updated", + "Operations completed": "Operations completed", + "Operations finished with errors": "Operations finished with errors", + "{0} of {1} succeeded, {2} failed": "{0} of {1} succeeded, {2} failed", + "Show an in-app summary toast when a batch of operations finishes": "Show an in-app summary toast when a batch of operations finishes" +} diff --git a/src/Languages/lang_eo.json b/src/Languages/lang_eo.json new file mode 100644 index 0000000..e0cfc3a --- /dev/null +++ b/src/Languages/lang_eo.json @@ -0,0 +1,850 @@ +{ + "{0} of {1} operations completed": "{0} el {1} operacioj plenumitaj", + "{0} is now {1}": "{0} nun estas {1}", + "Enabled": "Ŝaltita", + "Disabled": "Malŝaltita", + "Privacy": "Privateco", + "Hide my username from the logs": "Kaŝi mian uzantnomon el la protokoloj", + "Replaces your username with **** in the logs. Restart UniGetUI to also hide it from already-recorded entries.": "Anstataŭigas vian uzantnomon per **** en la protokoloj. Restartigu UniGetUI por kaŝi ĝin ankaŭ el jam registritaj enskriboj.", + "Your last update attempt did not complete.": "Via lasta ĝisdatiga provo ne finiĝis.", + "UniGetUI could not confirm whether the update succeeded. Open the log to see what happened.": "UniGetUI ne povis konfirmi ĉu la ĝisdatigo sukcesis. Malfermu la protokolon por vidi kio okazis.", + "View log": "Vidi protokolon", + "The installer reported success but did not restart UniGetUI.": "La instalilo raportis sukceson sed ne restartigis UniGetUI.", + "The installer failed to initialize.": "La instalilo malsukcesis komenciĝi.", + "Setup was canceled before installation began.": "La instalado estis nuligita antaŭ ol ĝi komenciĝis.", + "A fatal error occurred during the preparation phase.": "Fatala eraro okazis dum la prepara fazo.", + "A fatal error occurred during installation.": "Fatala eraro okazis dum instalado.", + "Installation was canceled while in progress.": "La instalado estis nuligita dum ĝi estis en progreso.", + "The installer was terminated by another process.": "La instalilo estis ĉesigita de alia procezo.", + "The preparation phase determined the installation cannot proceed.": "La prepara fazo determinis, ke la instalado ne povas daŭri.", + "The installer could not start. UniGetUI may already be running, or you do not have permission to install.": "La instalilo ne povis starti. UniGetUI eble jam ruliĝas, aŭ vi ne havas permeson instali.", + "Unexpected installer error.": "Neatendita instalila eraro.", + "We are checking for updates.": "Ni kontrolas ĝisdatigojn.", + "Please wait": "Bonvolu atendi", + "Great! You are on the latest version.": "Bonege! Vi jam uzas la plej novan version.", + "There are no new UniGetUI versions to be installed": "Ne estas novaj versioj de UniGetUI por instali", + "UniGetUI version {0} is being downloaded.": "UniGetUI-versio {0} estas elŝutata.", + "This may take a minute or two": "Tio povas daŭri unu aŭ du minutojn", + "The installer authenticity could not be verified.": "La aŭtentikeco de la instalilo ne povis esti kontrolita.", + "The update process has been aborted.": "La ĝisdatiga procezo estis ĉesigita.", + "Auto-update is not yet available on this platform.": "Aŭtomata ĝisdatigo ankoraŭ ne disponeblas sur ĉi tiu platformo.", + "Please update UniGetUI manually.": "Bonvolu ĝisdatigi UniGetUI permane.", + "An error occurred when checking for updates: ": "Eraro okazis dum kontrolado de ĝisdatigoj: ", + "The updater could not be launched.": "La ĝisdatigilo ne povis esti lanĉita.", + "The operating system did not start the installer process.": "La operaciumo ne startigis la instalilan procezon.", + "UniGetUI is being updated...": "UniGetUI estas ĝisdatigata...", + "Update installed.": "Ĝisdatigo instalita.", + "UniGetUI was updated successfully, but this running copy was not replaced. This usually means you are running a development build. Close this copy and start the newly-installed version to finish.": "UniGetUI estis ĝisdatigita sukcese, sed ĉi tiu rulanta kopio ne estis anstataŭigita. Tio kutime signifas, ke vi rulas disvolvan version. Fermu ĉi tiun kopion kaj startigu la nove instalitan version por fini.", + "The update could not be applied.": "La ĝisdatigo ne povis esti aplikita.", + "Installer exit code {0}: {1}": "Elirkodo de instalilo {0}: {1}", + "Update cancelled.": "Ĝisdatigo nuligita.", + "Authentication was cancelled.": "Aŭtentikigo estis nuligita.", + "Installer exit code {0}": "Elirkodo de instalilo {0}", + "Operation in progress": "Operacio en progreso", + "Please wait...": "Bonvolu atendi...", + "Success!": "Sukceso!", + "Failed": "Malsukcesis", + "An error occurred while processing this package": "Okazis eraro dum traktado de ĉi tiu pakaĵo", + "Installer": "Instalilo", + "Executable": "Rulebla dosiero", + "MSI": "MSI", + "Compressed file": "Kunpremita dosiero", + "MSIX": "MSIX", + "WinGet was repaired successfully": "WinGet estis riparita sukcese", + "It is recommended to restart UniGetUI after WinGet has been repaired": "Oni rekomendas restartigi UniGetUI post kiam WinGet estis riparita", + "WinGet could not be repaired": "WinGet ne povis esti riparita", + "An unexpected issue occurred while attempting to repair WinGet. Please try again later": "Neatendita problemo okazis dum provo ripari WinGet. Bonvolu reprovi poste", + "Log in to enable cloud backup": "Ensalutu por ebligi nuban sekurkopion", + "Backup Failed": "Sekurkopio malsukcesis", + "Downloading backup...": "Elŝutante sekurkopion...", + "An update was found!": "Troviĝis ĝisdatigo!", + "{0} can be updated to version {1}": "{0} povas esti ĝisdatigita al versio {1}", + "Updates found!": "Ĝisdatigoj trovitaj!", + "{0} packages can be updated": "{0} pakaĵoj povas esti ĝisdatigitaj", + "{0} is being updated to version {1}": "{0} estas ĝisdatigata al versio {1}", + "{0} packages are being updated": "{0} pakaĵoj estas ĝisdatigataj", + "You have currently version {0} installed": "Vi nuntempe havas version {0} instalitan", + "Desktop shortcut created": "Labortabla ŝparvojo kreita", + "UniGetUI has detected a new desktop shortcut that can be deleted automatically.": "UniGetUI detektis novan labortablan ŝparvojon, kiu povas esti forigita aŭtomate.", + "{0} desktop shortcuts created": "{0} labortablaj ŝparvojoj kreitaj", + "UniGetUI has detected {0} new desktop shortcuts that can be deleted automatically.": "UniGetUI detektis {0} novajn labortablajn ŝparvojojn, kiuj povas esti forigitaj aŭtomate.", + "Attention required": "Atento bezonata", + "Restart required": "Restartigo bezonata", + "1 update is available": "1 ĝisdatigo disponeblas", + "{0} updates are available": "{0} ĝisdatigoj disponeblas", + "Everything is up to date": "Ĉio estas ĝisdata", + "Discover Packages": "Malkovri pakaĵojn", + "Available Updates": "Disponeblaj ĝisdatigoj", + "Installed Packages": "Instalitaj pakaĵoj", + "UniGetUI Version {0} by Devolutions": "UniGetUI Versio {0} de Devolutions", + "Show UniGetUI": "Montri UniGetUI", + "Quit": "Eliri", + "Are you sure?": "Ĉu vi certas?", + "Do you really want to uninstall {0}?": "Ĉu vi vere volas malinstali {0}?", + "Do you really want to uninstall the following {0} packages?": "Ĉu vi vere volas malinstali la jenajn {0} pakaĵojn?", + "No": "Ne", + "Yes": "Jes", + "Partial": "Parta", + "View on UniGetUI": "Vidi en UniGetUI", + "Update": "Ĝisdatigi", + "Open UniGetUI": "Malfermi UniGetUI", + "Update all": "Ĝisdatigi ĉiujn", + "Update now": "Ĝisdatigi nun", + "Installer host changed since the installed version.\n": "La gastiganto de la instalilo ŝanĝiĝis ekde la instalita versio.\n", + "This package is on the queue": "Ĉi tiu pakaĵo estas en la vico", + "installing": "instalado", + "updating": "ĝisdatigado", + "uninstalling": "malinstalado", + "installed": "instalita", + "Retry": "Reprovi", + "Install": "Instali", + "Uninstall": "Malinstali", + "Open": "Malfermi", + "Operation profile:": "Operacia profilo:", + "Follow the default options when installing, upgrading or uninstalling this package": "Sekvu la defaŭltajn opciojn dum instalado, ĝisdatigo aŭ malinstalo de ĉi tiu pakaĵo", + "The following settings will be applied each time this package is installed, updated or removed.": "La jenaj agordoj estos aplikataj ĉiufoje kiam ĉi tiu pakaĵo estas instalata, ĝisdatigata aŭ forigata.", + "Version to install:": "Versio por instali:", + "Architecture to install:": "Arkitekturo por instali:", + "Installation scope:": "Instala amplekso:", + "Install location:": "Instala loko:", + "Select": "Elekti", + "Reset": "Restarigi", + "Custom install arguments:": "Propraj argumentoj por instalado:", + "Custom update arguments:": "Propraj argumentoj por ĝisdatigo:", + "Custom uninstall arguments:": "Propraj argumentoj por malinstalo:", + "Pre-install command:": "Antaŭinstala komando:", + "Post-install command:": "Postinstala komando:", + "Abort install if pre-install command fails": "Nuligi instaladon se la antaŭinstala komando malsukcesas", + "Pre-update command:": "Antaŭĝisdatiga komando:", + "Post-update command:": "Postĝisdatiga komando:", + "Abort update if pre-update command fails": "Nuligi ĝisdatigon se la antaŭĝisdatiga komando malsukcesas", + "Pre-uninstall command:": "Antaŭmalinstala komando:", + "Post-uninstall command:": "Postmalinstala komando:", + "Abort uninstall if pre-uninstall command fails": "Nuligi malinstalon se la antaŭmalinstala komando malsukcesas", + "Command-line to run:": "Komandlinio por ruli:", + "Save and close": "Konservi kaj fermi", + "General": "Ĝenerala", + "Architecture & Location": "Arkitekturo kaj loko", + "Command-line": "Komandlinio", + "Close apps": "Fermi aplikaĵojn", + "Pre/Post install": "Antaŭ/Post instalado", + "Select the processes that should be closed before this package is installed, updated or uninstalled.": "Elektu la procezojn, kiuj devus esti fermitaj antaŭ ol ĉi tiu pakaĵo estos instalita, ĝisdatigita aŭ malinstalita.", + "Write here the process names here, separated by commas (,)": "Skribu ĉi tie la nomojn de la procezoj, apartigitajn per komoj (,)", + "Try to kill the processes that refuse to close when requested to": "Provu ĉesigi la procezojn, kiuj rifuzas fermiĝi laŭpete", + "Run as admin": "Ruli kiel administranto", + "Interactive installation": "Interaga instalado", + "Skip hash check": "Preterlasi haŝkontrolon", + "Uninstall previous versions when updated": "Malinstali antaŭajn versiojn dum ĝisdatigo", + "Skip minor updates for this package": "Preterlasi etajn ĝisdatigojn por ĉi tiu pakaĵo", + "Automatically update this package": "Aŭtomate ĝisdatigi ĉi tiun pakaĵon", + "{0} installation options": "{0} instalaj opcioj", + "Latest": "Plej nova", + "PreRelease": "Antaŭeldono", + "Default": "Defaŭlta", + "Manage ignored updates": "Administri ignoratajn ĝisdatigojn", + "The packages listed here won't be taken in account when checking for updates. Double-click them or click the button on their right to stop ignoring their updates.": "La ĉi tie listigitaj pakaĵoj ne estos konsiderataj dum kontrolo pri ĝisdatigoj. Duoble alklaku ilin aŭ alklaku la butonon dekstre por ĉesi ignori iliajn ĝisdatigojn.", + "Reset list": "Restarigi liston", + "Do you really want to reset the ignored updates list? This action cannot be reverted": "Ĉu vi vere volas restarigi la liston de ignorataj ĝisdatigoj? Ĉi tiu ago ne povas esti malfarita", + "No ignored updates": "Neniuj ignorataj ĝisdatigoj", + "Package Name": "Pakaĵa nomo", + "Package ID": "Pakaĵa ID", + "Ignored version": "Ignorata versio", + "New version": "Nova versio", + "Source": "Fonto", + "All versions": "Ĉiuj versioj", + "Unknown": "Nekonata", + "Up to date": "Ĝisdata", + "Package {name} from {manager}": "Pakaĵo {name} de {manager}", + "Remove {0} from ignored updates": "Forigi {0} el ignorataj ĝisdatigoj", + "Cancel": "Nuligi", + "Administrator privileges": "Administrantaj privilegioj", + "This operation is running with administrator privileges.": "Ĉi tiu operacio ruliĝas kun administrantaj privilegioj.", + "Interactive operation": "Interaga operacio", + "This operation is running interactively.": "Ĉi tiu operacio ruliĝas interage.", + "You will likely need to interact with the installer.": "Vi probable devos interagi kun la instalilo.", + "Integrity checks skipped": "Integrecaj kontroloj preterlasitaj", + "Integrity checks will not be performed during this operation.": "Integrecaj kontroloj ne estos faritaj dum ĉi tiu operacio.", + "Proceed at your own risk.": "Daŭrigu je via propra risko.", + "Close": "Fermi", + "Loading...": "Ŝargante...", + "Installer SHA256": "Instalila SHA256", + "Homepage": "Hejmpaĝo", + "Author": "Aŭtoro", + "Publisher": "Eldoninto", + "License": "Permesilo", + "Manifest": "Manifesto", + "Installer Type": "Tipo de instalilo", + "Size": "Grandeco", + "Installer URL": "URL de instalilo", + "Last updated:": "Laste ĝisdatigita:", + "Release notes URL": "URL de eldonaj notoj", + "Package details": "Detaloj de pako", + "Dependencies:": "Dependecoj:", + "Release notes": "Eldonaj notoj", + "Screenshots": "Ekrankopioj", + "This package has no screenshots or is missing the icon? Contribute to UniGetUI by adding the missing icons and screenshots to our open, public database.": "Ĉi tiu pakaĵo ne havas ekrankopiojn aŭ mankas la ikono? Kontribuu al UniGetUI aldonante la mankantajn ikonojn kaj ekrankopiojn al nia malferma, publika datumbazo.", + "Version": "Versio", + "Install as administrator": "Instali kiel administranto", + "Update to version {0}": "Ĝisdatigi al versio {0}", + "Installed Version": "Instalita versio", + "Update as administrator": "Ĝisdatigi kiel administranto", + "Interactive update": "Interaga ĝisdatigo", + "Uninstall as administrator": "Malinstali kiel administranto", + "Interactive uninstall": "Interaga malinstalo", + "Uninstall and remove data": "Malinstali kaj forigi datumojn", + "Not available": "Ne disponebla", + "Installer SHA512": "SHA512 de instalilo", + "Unknown size": "Nekonata grandeco", + "No dependencies specified": "Neniuj dependecoj specifitaj", + "mandatory": "deviga", + "optional": "laŭvola", + "UniGetUI {0} is ready to be installed.": "UniGetUI {0} pretas esti instalita.", + "The update process will start after closing UniGetUI": "La ĝisdatiga procezo komenciĝos post fermo de UniGetUI", + "UniGetUI has been ran as administrator, which is not recommended. When running UniGetUI as administrator, EVERY operation launched from UniGetUI will have administrator privileges. You can still use the program, but we highly recommend not running UniGetUI with administrator privileges.": "UniGetUI estis rulita kiel administranto, kio ne estas rekomendinda. Kiam UniGetUI ruliĝas kiel administranto, ĈIU operacio lanĉita el UniGetUI havos administrajn privilegiojn. Vi ankoraŭ povas uzi la programon, sed ni forte rekomendas ne ruli UniGetUI kun administraj privilegioj.", + "Share anonymous usage data": "Kunhavigi anonimajn uzdatumojn", + "UniGetUI collects anonymous usage data in order to improve the user experience.": "UniGetUI kolektas anonimajn uzdatumojn por plibonigi la uzantosperton.", + "Accept": "Akcepti", + "Software Updates": "Programaraj ĝisdatigoj", + "Package Bundles": "Pakaĵfaskoj", + "Settings": "Agordoj", + "Package Managers": "Pakaĵadministriloj", + "UniGetUI Log": "Protokolo de UniGetUI", + "Package Manager logs": "Protokoloj de pakaĵadministriloj", + "Operation history": "Historio de operacioj", + "Help": "Helpo", + "UniGetUI": "UniGetUI", + "You have installed UniGetUI Version {0}": "Vi instalis UniGetUI-version {0}", + "Disclaimer": "Malgarantio", + "UniGetUI is developed by Devolutions and is not affiliated with any of the compatible package managers.": "UniGetUI estas disvolvita de Devolutions kaj ne estas aligita kun iu ajn el la kongruaj pakaĵadministriloj.", + "UniGetUI wouldn't have been possible without the help of the contributors. Thank you all 🥳": "UniGetUI ne estus ebla sen la helpo de la kontribuantoj. Dankon al vi ĉiuj 🥳", + "UniGetUI uses the following libraries. Without them, UniGetUI wouldn't have been possible.": "UniGetUI uzas la jenajn bibliotekojn. Sen ili, UniGetUI ne estus ebla.", + "{0} homepage": "Hejmpaĝo de {0}", + "UniGetUI has been translated to more than 40 languages thanks to the volunteer translators. Thank you 🤝": "UniGetUI estis tradukita al pli ol 40 lingvoj danke al la volontulaj tradukistoj. Dankon 🤝", + "Verbose": "Detala", + "1 - Errors": "1 - Eraroj", + "2 - Warnings": "2 - Avertoj", + "3 - Information (less)": "3 - Informoj (malpli)", + "4 - Information (more)": "4 - Informoj (pli)", + "5 - information (debug)": "5 - Informoj (sencimigo)", + "Warning": "Averto", + "The following settings may pose a security risk, hence they are disabled by default.": "La jenaj agordoj povas prezenti sekurecan riskon, tial ili estas malŝaltitaj defaŭlte.", + "Enable the settings below if and only if you fully understand what they do, and the implications they may have.": "Enŝaltu la subajn agordojn nur kaj nur se vi plene komprenas kion ili faras kaj la sekvojn, kiujn ili povas havi.", + "The settings will list, in their descriptions, the potential security issues they may have.": "La agordoj listigos en siaj priskriboj la eblajn sekurecajn problemojn, kiujn ili povas havi.", + "The backup will include the complete list of the installed packages and their installation options. Ignored updates and skipped versions will also be saved.": "La sekurkopio inkluzivos la kompletan liston de la instalitaj pakoj kaj iliajn instalajn opciojn. Ignoritaj ĝisdatigoj kaj preterlasitaj versioj ankaŭ estos konservitaj.", + "The backup will NOT include any binary file nor any program's saved data.": "La sekurkopio NE inkluzivos ajnan duuman dosieron nek la konservitajn datumojn de iu programo.", + "The size of the backup is estimated to be less than 1MB.": "La grandeco de la sekurkopio laŭtakse estos malpli ol 1MB.", + "The backup will be performed after login.": "La sekurkopio estos farita post ensaluto.", + "{pcName} installed packages": "Instalitaj pakoj de {pcName}", + "Current status: Not logged in": "Nuna stato: Ne ensalutinta", + "You are logged in as {0} (@{1})": "Vi estas ensalutinta kiel {0} (@{1})", + "Nice! Backups will be uploaded to a private gist on your account": "Bone! Sekurkopioj estos alŝutitaj al privata gist en via konto", + "Select backup": "Elekti sekurkopion", + "Settings imported from {0}": "Agordoj importitaj el {0}", + "UniGetUI Settings": "Agordoj de UniGetUI", + "Settings exported to {0}": "Agordoj eksportitaj al {0}", + "UniGetUI settings were reset": "La agordoj de UniGetUI estis restarigitaj", + "Allow pre-release versions": "Permesi antaŭeldonajn versiojn", + "Apply": "Apliki", + "For security reasons, custom command-line arguments are disabled by default. Go to UniGetUI security settings to change this.": "Pro sekurecaj kialoj, propraj komandliniaj argumentoj estas malŝaltitaj defaŭlte. Iru al la sekurecaj agordoj de UniGetUI por ŝanĝi tion.", + "Go to UniGetUI security settings": "Iri al la sekurecaj agordoj de UniGetUI", + "The following options will be applied by default each time a {0} package is installed, upgraded or uninstalled.": "La jenaj opcioj estos aplikataj defaŭlte ĉiufoje kiam pako de {0} estas instalata, ĝisdatigata aŭ malinstalata.", + "Package's default": "Defaŭlto de la pako", + "Install location can't be changed for {0} packages": "Instala loko ne povas esti ŝanĝita por pakoj de {0}", + "The local icon cache currently takes {0} MB": "La loka piktograma kaŝmemoro nun okupas {0} MB", + "Username": "Uzantnomo", + "Password": "Pasvorto", + "Credentials": "Akreditaĵoj", + "It is not guaranteed that the provided credentials will be stored safely": "Ne estas garantiite, ke la provizitaj akreditaĵoj estos sekure konservitaj", + "Partially": "Parte", + "Package manager": "Pakaĵadministrilo", + "Compatible with proxy": "Kongrua kun prokurilo", + "Compatible with authentication": "Kongrua kun aŭtentikigo", + "Proxy compatibility table": "Tabelo de kongrueco kun prokuriloj", + "{0} settings": "Agordoj de {0}", + "{0} status": "Stato de {0}", + "Default installation options for {0} packages": "Defaŭltaj instalaj opcioj por pakoj de {0}", + "Expand version": "Malfaldi version", + "The executable file for {0} was not found": "La plenumebla dosiero por {0} ne estis trovita", + "{pm} is disabled": "{pm} estas malŝaltita", + "Enable it to install packages from {pm}.": "Enŝaltu ĝin por instali pakojn el {pm}.", + "{pm} is enabled and ready to go": "{pm} estas enŝaltita kaj preta por uzo", + "{pm} version:": "Versio de {pm}:", + "{pm} was not found!": "{pm} ne estis trovita!", + "You may need to install {pm} in order to use it with UniGetUI.": "Vi eble bezonos instali {pm} por uzi ĝin kun UniGetUI.", + "Scoop Installer - UniGetUI": "Instalilo de Scoop - UniGetUI", + "Scoop Uninstaller - UniGetUI": "Malinstalilo de Scoop - UniGetUI", + "Clearing Scoop cache - UniGetUI": "Malplenigado de la kaŝmemoro de Scoop - UniGetUI", + "Restart UniGetUI to fully apply changes": "Restartigu UniGetUI por plene apliki la ŝanĝojn", + "Restart UniGetUI": "Restartigi UniGetUI", + "Manage {0} sources": "Administri fontojn de {0}", + "Add source": "Aldoni fonton", + "Add": "Aldoni", + "Source name": "Nomo de fonto", + "Source URL": "URL de fonto", + "Other": "Alia", + "No minimum age": "Neniu minimuma aĝo", + "1 day": "1 tago", + "{0} days": "{0} tagoj", + "Custom...": "Propra...", + "{0} minutes": "{0} minutoj", + "1 hour": "unu horo", + "{0} hours": "{0} horoj", + "1 week": "1 semajno", + "Supports release dates": "Subtenas eldondatojn", + "Release date support per package manager": "Subteno de eldondatoj laŭ pakadministrilo", + "Search for packages": "Serĉi pakaĵojn", + "Local": "Loka", + "OK": "OK", + "Last checked: {0}": "Laste kontrolite: {0}", + "{0} packages were found, {1} of which match the specified filters.": "Troviĝis {0} pakaĵoj, el kiuj {1} kongruas kun la specifitaj filtriloj.", + "{0} selected": "{0} elektitaj", + "(Last checked: {0})": "(Laste kontrolite: {0})", + "All packages selected": "Ĉiuj pakaĵoj elektitaj", + "Package selection cleared": "Pakaĵelekto forigita", + "{0}: {1}": "{0}: {1}", + "More info": "Pliaj informoj", + "GitHub account": "GitHub-konto", + "Log in with GitHub to enable cloud package backup.": "Ensalutu per GitHub por ebligi nuban sekurkopion de pakaĵoj.", + "More details": "Pliaj detaloj", + "Log in": "Ensaluti", + "If you have cloud backup enabled, it will be saved as a GitHub Gist on this account": "Se vi havas ebligitan nuban sekurkopion, ĝi estos konservita kiel GitHub Gist en ĉi tiu konto", + "Log out": "Elsaluti", + "About UniGetUI": "Pri UniGetUI", + "About": "Pri", + "Third-party licenses": "Licencoj de triaj", + "Contributors": "Kontribuantoj", + "Translators": "Tradukantoj", + "Bundle security report": "Sekureca raporto de pakaĵaro", + "The bundle contained restricted content": "La pakaĵaro enhavis limigitan enhavon", + "UniGetUI – Crash Report": "UniGetUI – Kraŝraporto", + "UniGetUI has crashed": "UniGetUI kraŝis", + "Help us fix this by sending a crash report to Devolutions. All fields below are optional.": "Helpu nin ripari ĉi tion sendante kraŝraporton al Devolutions. Ĉiuj subaj kampoj estas laŭvolaj.", + "Email (optional)": "Retpoŝto (laŭvola)", + "your@email.com": "via@retpoŝto.com", + "Additional details (optional)": "Pliaj detaloj (laŭvola)", + "Describe what you were doing when the crash occurred…": "Priskribu kion vi faris kiam la kraŝo okazis…", + "Crash report": "Kraŝraporto", + "Don't Send": "Ne sendi", + "Send Report": "Sendi raporton", + "Sending…": "Sendado…", + "Unsaved changes": "Nekonservitaj ŝanĝoj", + "You have unsaved changes in the current bundle. Do you want to discard them?": "Vi havas nekonservitajn ŝanĝojn en la nuna pakaĵaro. Ĉu vi volas forĵeti ilin?", + "Discard changes": "Forĵeti ŝanĝojn", + "Integrity violation": "Integreca malobservo", + "UniGetUI or some of its components are missing or corrupt. It is strongly recommended to reinstall UniGetUI to adress the situation.": "UniGetUI aŭ kelkaj el ĝiaj komponantoj mankas aŭ estas difektitaj. Estas forte rekomendite reinstali UniGetUI por trakti la situacion.", + "• Refer to the UniGetUI Logs to get more details regarding the affected file(s)": "• Rigardu la protokolojn de UniGetUI por ricevi pliajn detalojn pri la tuŝitaj dosieroj", + "• Integrity checks can be disabled from the Experimental Settings": "• Integrecaj kontroloj povas esti malŝaltitaj en la Eksperimentaj agordoj", + "Manage shortcuts": "Administri ŝparvojojn", + "UniGetUI has detected the following desktop shortcuts which can be removed automatically on future upgrades": "UniGetUI detektis la jenajn labortablajn ŝparvojojn, kiuj povas esti aŭtomate forigitaj dum estontaj ĝisdatigoj", + "Do you really want to reset this list? This action cannot be reverted.": "Ĉu vi vere volas reagordi ĉi tiun liston? Ĉi tiu ago ne povas esti malfarita.", + "Desktop shortcuts list": "Listo de labortablaj ŝparvojoj", + "Open in explorer": "Malfermi en Esplorilo", + "Remove from list": "Forigi el listo", + "When new shortcuts are detected, delete them automatically instead of showing this dialog.": "Kiam novaj ŝparvojoj estas detektitaj, forigu ilin aŭtomate anstataŭ montri ĉi tiun dialogon.", + "Not right now": "Ne nun", + "Missing dependency": "Mankanta dependaĵo", + "UniGetUI requires {0} to operate, but it was not found on your system.": "UniGetUI bezonas {0} por funkcii, sed ĝi ne estis trovita en via sistemo.", + "Click on Install to begin the installation process. If you skip the installation, UniGetUI may not work as expected.": "Alklaku Instali por komenci la instaladon. Se vi preterlasos la instaladon, UniGetUI eble ne funkcios kiel atendite.", + "Alternatively, you can also install {0} by running the following command in a Windows PowerShell prompt:": "Alternative, vi ankaŭ povas instali {0} rulante la jenan komandon en Windows PowerShell-fenestro:", + "Install {0}": "Instali {0}", + "Do not show this dialog again for {0}": "Ne montru ĉi tiun dialogon denove por {0}", + "Please wait while {0} is being installed. A black window may show up. Please wait until it closes.": "Bonvolu atendi dum {0} estas instalata. Nigra fenestro eble aperos. Bonvolu atendi ĝis ĝi fermiĝos.", + "{0} has been installed successfully.": "{0} estis instalita sukcese.", + "Please click on \"Continue\" to continue": "Bonvolu alklaki \"Daŭrigi\" por pluiri", + "Continue": "Daŭrigi", + "{0} has been installed successfully. It is recommended to restart UniGetUI to finish the installation": "{0} estis instalita sukcese. Oni rekomendas restartigi UniGetUI por fini la instaladon", + "Restart later": "Restartigi poste", + "An error occurred:": "Okazis eraro:", + "Please see the Command-line Output or refer to the Operation History for further information about the issue.": "Bonvolu vidi la komandlinian eligon aŭ konsulti la historion de operacioj por pliaj informoj pri la problemo.", + "Retry as administrator": "Reprovi kiel administranto", + "Retry interactively": "Reprovi interage", + "Retry skipping integrity checks": "Reprovi sen integreckontroloj", + "Installation options": "Instalaj opcioj", + "Save": "Konservi", + "UniGetUI collects anonymous usage data with the sole purpose of understanding and improving the user experience.": "UniGetUI kolektas anonimajn uzdatumojn kun la sola celo kompreni kaj plibonigi la uzantosperton.", + "More details about the shared data and how it will be processed": "Pliaj detaloj pri la kunhavataj datumoj kaj kiel ili estos prilaborataj", + "Do you accept that UniGetUI collects and sends anonymous usage statistics, with the sole purpose of understanding and improving the user experience?": "Ĉu vi akceptas, ke UniGetUI kolektu kaj sendu anonimajn uzostatistikojn kun la sola celo kompreni kaj plibonigi la uzantosperton?", + "Decline": "Malakcepti", + "No personal information is collected nor sent, and the collected data is anonimized, so it can't be back-tracked to you.": "Neniuj personaj informoj estas kolektataj nek sendataj, kaj la kolektitaj datumoj estas anonimigitaj, do ili ne povas esti spuritaj reen al vi.", + "Navigation panel": "Naviga panelo", + "Operations": "Operacioj", + "Toggle operations panel": "Montri aŭ kaŝi la operacian panelon", + "Bulk operations": "Amasaj operacioj", + "Retry failed": "Reprovi malsukcesintajn", + "Clear successful": "Forigi sukcesajn", + "Clear finished": "Forigi finiĝintajn", + "Cancel all": "Nuligi ĉiujn", + "More": "Pli", + "Toggle navigation panel": "Montri aŭ kaŝi la navigan panelon", + "Minimize": "Minimumigi", + "Maximize": "Maksimumigi", + "UniGetUI by Devolutions": "UniGetUI de Devolutions", + "UniGetUI is an application that makes managing your software easier, by providing an all-in-one graphical interface for your command-line package managers.": "UniGetUI estas aplikaĵo, kiu faciligas la administradon de via programaro, provizante tute-en-unu grafikan interfacon por viaj komandliniaj pakadministriloj.", + "Useful links": "Utilaj ligiloj", + "UniGetUI Homepage": "Hejmpaĝo de UniGetUI", + "Report an issue or submit a feature request": "Raporti problemon aŭ sendi peton pri nova funkcio", + "UniGetUI Repository": "Deponejo de UniGetUI", + "View GitHub Profile": "Vidi GitHub-profilon", + "UniGetUI License": "Licenco de UniGetUI", + "Using UniGetUI implies the acceptation of the MIT License": "Uzi UniGetUI implicas akcepton de la MIT-licenco", + "Become a translator": "Fariĝi tradukanto", + "Go back": "Iri reen", + "Go forward": "Iri antaŭen", + "Go to home page": "Iri al la hejmpaĝo", + "Reload page": "Reŝargi paĝon", + "View page on browser": "Vidi paĝon en retumilo", + "The built-in browser is not supported on Linux yet.": "La enkonstruita retumilo ankoraŭ ne estas subtenata en Linux.", + "Open in browser": "Malfermi en retumilo", + "Copy to clipboard": "Kopii al tondujo", + "Export to a file": "Eksporti al dosiero", + "Log level:": "Nivelo de protokolo:", + "Reload log": "Reŝargi protokolon", + "Export log": "Eksporti protokolon", + "Text": "Teksto", + "Change how operations request administrator rights": "Ŝanĝi kiel operacioj petas administrajn rajtojn", + "Restrictions on package operations": "Limigoj pri pakoperacioj", + "Restrictions on package managers": "Limigoj pri pakadministriloj", + "Restrictions when importing package bundles": "Limigoj dum importado de pakfaskoj", + "Ask for administrator privileges once for each batch of operations": "Peti administrajn rajtojn unufoje por ĉiu aro da operacioj", + "Ask only once for administrator privileges": "Peti administrajn rajtojn nur unufoje", + "Prohibit any kind of Elevation via UniGetUI Elevator or GSudo": "Malpermesi ĉian altigon per UniGetUI Elevator aŭ GSudo", + "This option WILL cause issues. Any operation incapable of elevating itself WILL FAIL. Install/update/uninstall as administrator will NOT WORK.": "Ĉi tiu opcio JA kaŭzos problemojn. Ĉiu operacio nekapabla mem altiĝi MALSUKCESOS. Instali/ĝisdatigi/malinstali kiel administranto NE FUNKCIOS.", + "Allow custom command-line arguments": "Permesi proprajn komandliniajn argumentojn", + "Custom command-line arguments can change the way in which programs are installed, upgraded or uninstalled, in a way UniGetUI cannot control. Using custom command-lines can break packages. Proceed with caution.": "Propraj komandliniaj argumentoj povas ŝanĝi la manieron, laŭ kiu programoj estas instalataj, ĝisdatigataj aŭ malinstalataj, tiel ke UniGetUI ne povas tion regi. Uzi proprajn komandliniajn argumentojn povas rompi pakaĵojn. Procedu singarde.", + "Ignore custom pre-install and post-install commands when importing packages from a bundle": "Ignori proprajn antaŭinstalajn kaj postinstalajn komandojn dum importado de pakaĵoj el fasko", + "Pre and post install commands will be run before and after a package gets installed, upgraded or uninstalled. Be aware that they may break things unless used carefully": "Antaŭinstalaj kaj postinstalaj komandoj estos rulataj antaŭ kaj post kiam pakaĵo estas instalata, ĝisdatigata aŭ malinstalata. Konsciu, ke ili povas rompi aferojn, krom se uzataj singarde", + "Allow changing the paths for package manager executables": "Permesi ŝanĝi la vojojn al la ruleblaj dosieroj de pakadministriloj", + "Turning this on enables changing the executable file used to interact with package managers. While this allows finer-grained customization of your install processes, it may also be dangerous": "Ŝalti ĉi tion ebligas ŝanĝi la ruleblan dosieron uzatan por interagi kun pakadministriloj. Kvankam tio permesas pli detalan agordon de viaj instalaj procezoj, ĝi ankaŭ povas esti danĝera", + "Allow importing custom command-line arguments when importing packages from a bundle": "Permesi importi proprajn komandliniajn argumentojn dum importado de pakaĵoj el fasko", + "Malformed command-line arguments can break packages, or even allow a malicious actor to gain privileged execution. Therefore, importing custom command-line arguments is disabled by default": "Misformitaj komandliniaj argumentoj povas rompi pakaĵojn, aŭ eĉ ebligi al malica aganto akiri privilegian plenumon. Tial importado de propraj komandliniaj argumentoj estas defaŭlte malŝaltita.", + "Allow importing custom pre-install and post-install commands when importing packages from a bundle": "Permesi importi proprajn antaŭinstalajn kaj postinstalajn komandojn dum importado de pakaĵoj el fasko", + "Pre and post install commands can do very nasty things to your device, if designed to do so. It can be very dangerous to import the commands from a bundle, unless you trust the source of that package bundle": "Antaŭinstalaj kaj postinstalaj komandoj povas fari tre malagrablajn aferojn al via aparato, se ili estas tiel desegnitaj. Povas esti tre danĝere importi la komandojn el fasko, krom se vi fidas la fonton de tiu pakfasko", + "Administrator rights and other dangerous settings": "Administraj rajtoj kaj aliaj danĝeraj agordoj", + "Package backup": "Sekurkopio de pakaĵoj", + "Cloud package backup": "Nuba sekurkopio de pakaĵoj", + "Local package backup": "Loka sekurkopio de pakaĵoj", + "Local backup advanced options": "Altnivelaj opcioj por loka sekurkopio", + "Log in with GitHub": "Ensaluti per GitHub", + "Log out from GitHub": "Elsaluti el GitHub", + "Periodically perform a cloud backup of the installed packages": "Periode fari nuban sekurkopion de la instalitaj pakaĵoj", + "Cloud backup uses a private GitHub Gist to store a list of installed packages": "Nuba sekurkopio uzas privatan GitHub Gist por konservi liston de instalitaj pakaĵoj", + "Perform a cloud backup now": "Fari nuban sekurkopion nun", + "Backup": "Sekurkopio", + "Restore a backup from the cloud": "Restarigi sekurkopion el la nubo", + "Begin the process to select a cloud backup and review which packages to restore": "Komenci la procezon por elekti nuban sekurkopion kaj revizii, kiujn pakaĵojn restarigi", + "Periodically perform a local backup of the installed packages": "Periode fari lokan sekurkopion de la instalitaj pakaĵoj", + "Perform a local backup now": "Fari lokan sekurkopion nun", + "Change backup output directory": "Ŝanĝi la eligan dosierujon de sekurkopioj", + "Set a custom backup file name": "Agordi propran nomon de sekurkopia dosiero", + "Leave empty for default": "Lasu malplena por la defaŭlto", + "Add a timestamp to the backup file names": "Aldoni tempomarkon al la nomoj de sekurkopiaj dosieroj", + "Backup and Restore": "Sekurkopio kaj restarigo", + "Enable background api (UniGetUI Widgets and Sharing, port 7058)": "Ebligi fonan API-on (fenestraĵoj de UniGetUI kaj kunhavigo, pordo 7058)", + "Wait for the device to be connected to the internet before attempting to do tasks that require internet connectivity.": "Atendi ĝis la aparato estos konektita al la interreto antaŭ ol provi fari taskojn, kiuj postulas interretan konekteblecon.", + "Disable the 1-minute timeout for package-related operations": "Malŝalti la 1-minutan templimon por pakaĵ-rilataj operacioj", + "Use installed GSudo instead of UniGetUI Elevator": "Uzi instalitan GSudo anstataŭ UniGetUI Elevator", + "Use a custom icon and screenshot database URL": "Uzi propran URL-on por la datumbazo de ikonoj kaj ekrankopioj", + "Enable background CPU Usage optimizations (see Pull Request #3278)": "Ebligi fonajn optimumigojn de CPU-uzo (vidu Pull Request #3278)", + "Perform integrity checks at startup": "Fari integrecajn kontrolojn je lanĉo", + "When batch installing packages from a bundle, install also packages that are already installed": "Kiam amase instalas pakaĵojn el fasko, instalu ankaŭ pakaĵojn, kiuj jam estas instalitaj", + "Experimental settings and developer options": "Eksperimentaj agordoj kaj programistaj opcioj", + "Show UniGetUI's version and build number on the titlebar.": "Montri la version de UniGetUI en la titolbreto.", + "Language": "Lingvo", + "UniGetUI updater": "Ĝisdatigilo de UniGetUI", + "Telemetry": "Telemetrio", + "Manage UniGetUI settings": "Administri la agordojn de UniGetUI", + "Related settings": "Rilataj agordoj", + "Update UniGetUI automatically": "Aŭtomate ĝisdatigi UniGetUI", + "Check for updates": "Kontroli ĝisdatigojn", + "Install prerelease versions of UniGetUI": "Instali antaŭeldonajn versiojn de UniGetUI", + "Manage telemetry settings": "Administri agordojn pri telemetrio", + "Manage": "Administri", + "Import settings from a local file": "Importi agordojn el loka dosiero", + "Import": "Importi", + "Export settings to a local file": "Eksporti agordojn al loka dosiero", + "Export": "Eksporti", + "Reset UniGetUI": "Restarigi UniGetUI", + "User interface preferences": "Preferoj de la uzantinterfaco", + "Application theme, startup page, package icons, clear successful installs automatically": "Aplika temo, lanĉpaĝo, pakaĵikonoj, aŭtomate forigi sukcesajn instaladojn", + "General preferences": "Ĝeneralaj preferoj", + "UniGetUI display language:": "Montra lingvo de UniGetUI:", + "System language": "Sistema lingvo", + "Is your language missing or incomplete?": "Ĉu via lingvo mankas aŭ estas nekompleta?", + "Appearance": "Aspekto", + "UniGetUI on the background and system tray": "UniGetUI en la fono kaj sistempleto", + "Package lists": "Pakaĵlistoj", + "Use classic mode": "Uzi klasikan reĝimon", + "Restart UniGetUI to apply this change": "Restartigu UniGetUI por apliki ĉi tiun ŝanĝon", + "The classic UI is disabled for beta testers": "La klasika uzantinterfaco estas malŝaltita por beta-testantoj", + "Close UniGetUI to the system tray": "Fermi UniGetUI al la sistempleto", + "Manage UniGetUI autostart behaviour": "Administri la aŭtolanĉan konduton de UniGetUI", + "Show package icons on package lists": "Montri pakaĵikonojn en pakaĵlistoj", + "Clear cache": "Malplenigi kaŝmemoron", + "Select upgradable packages by default": "Defaŭlte elekti ĝisdatigeblajn pakaĵojn", + "Light": "Hela", + "Dark": "Malhela", + "Follow system color scheme": "Sekvi la sisteman kolorskemon", + "Application theme:": "Aplika temo:", + "UniGetUI startup page:": "Lanĉpaĝo de UniGetUI:", + "Proxy settings": "Prokurilaj agordoj", + "Other settings": "Aliaj agordoj", + "Connect the internet using a custom proxy": "Konekti al la interreto per propra prokurilo", + "Please note that not all package managers may fully support this feature": "Bonvolu rimarki, ke ne ĉiuj pakaĵadministriloj plene subtenas ĉi tiun funkcion", + "Proxy URL": "URL de prokurilo", + "Enter proxy URL here": "Enigu la URL-on de la prokurilo ĉi tie", + "Authenticate to the proxy with a user and a password": "Aŭtentikigu vin ĉe la prokurilo per uzantnomo kaj pasvorto", + "Internet and proxy settings": "Interretaj kaj prokurilaj agordoj", + "Package manager preferences": "Preferoj de pakaĵadministriloj", + "Ready": "Preta", + "Not found": "Ne trovita", + "Notification preferences": "Preferoj pri sciigoj", + "Notification types": "Tipoj de sciigoj", + "The system tray icon must be enabled in order for notifications to work": "La sistempleta piktogramo devas esti ebligita por ke sciigoj funkciu", + "Enable UniGetUI notifications": "Ebligi sciigojn de UniGetUI", + "Show a notification when there are available updates": "Montri sciigon kiam estas disponeblaj ĝisdatigoj", + "Show a silent notification when an operation is running": "Montri silentan sciigon kiam operacio ruliĝas", + "Show a notification when an operation fails": "Montri sciigon kiam operacio malsukcesas", + "Show a notification when an operation finishes successfully": "Montri sciigon kiam operacio sukcese finiĝas", + "Concurrency and execution": "Samtempeco kaj plenumo", + "Automatic desktop shortcut remover": "Aŭtomata forigilo de labortablaj ŝparvojoj", + "Choose how many operations should be performed in parallel": "Elekti kiom da operacioj devas esti faritaj paralele", + "Clear successful operations from the operation list after a 5 second delay": "Forigi sukcesajn operaciojn el la operacilisto post 5-sekunda prokrasto", + "Download operations are not affected by this setting": "Elŝutaj operacioj ne estas trafitaj de ĉi tiu agordo", + "You may lose unsaved data": "Vi eble perdos nekonservitajn datumojn", + "Ask to delete desktop shortcuts created during an install or upgrade.": "Demandi pri forigo de labortablaj ŝparvojoj kreitaj dum instalado aŭ ĝisdatigo.", + "Package update preferences": "Preferoj pri pakaĵaj ĝisdatigoj", + "Update check frequency, automatically install updates, etc.": "Ofteco de ĝisdatigkontroloj, aŭtomata instalado de ĝisdatigoj, ktp.", + "Reduce UAC prompts, elevate installations by default, unlock certain dangerous features, etc.": "Malpliigi UAC-instigojn, defaŭlte altigi instaladojn, malŝlosi iujn danĝerajn funkciojn, ktp.", + "Package operation preferences": "Preferoj pri pakaĵaj operacioj", + "Enable {pm}": "Ebligi {pm}", + "Not finding the file you are looking for? Make sure it has been added to path.": "Ĉu vi ne trovas la dosieron, kiun vi serĉas? Certigu, ke ĝi estis aldonita al Path.", + "Select the executable to be used. The following list shows the executables found by UniGetUI": "Elektu la uzotan plenumeblan dosieron. La jena listo montras la plenumeblajn dosierojn trovitajn de UniGetUI", + "For security reasons, changing the executable file is disabled by default": "Pro sekurecaj kialoj, ŝanĝi la plenumeblan dosieron estas defaŭlte malebligita", + "Change this": "Ŝanĝi tion", + "Copy path": "Kopii vojon", + "Current executable file:": "Nuna plenumebla dosiero:", + "Ignore packages from {pm} when showing a notification about updates": "Ignori pakaĵojn de {pm} dum montrado de sciigo pri ĝisdatigoj", + "Update security": "Ĝisdatiga sekureco", + "Use global setting": "Uzi ĝeneralan agordon", + "Minimum age for updates": "Minimuma aĝo por ĝisdatigoj", + "e.g. 10": "ekz. 10", + "Custom minimum age (days)": "Propra minimuma aĝo (tagoj)", + "{pm} does not provide release dates for its packages, so this setting will have no effect": "{pm} ne provizas eldondatojn por siaj pakaĵoj, do ĉi tiu agordo ne havos efikon", + "{pm} only provides release dates for some of its packages, so this setting will only apply to those packages": "{pm} provizas eldondatojn nur por kelkaj el siaj pakaĵoj, do ĉi tiu agordo aplikiĝos nur al tiuj pakaĵoj", + "Override the global minimum update age for this package manager": "Superregi la ĝeneralan minimuman aĝon de ĝisdatigoj por ĉi tiu pakaĵadministrilo", + "View {0} logs": "Vidi la protokolojn de {0}", + "If Python cannot be found or is not listing packages but is installed on the system, ": "Se Python ne troveblas aŭ ne listigas pakaĵojn sed estas instalita en la sistemo, ", + "Advanced options": "Altnivelaj opcioj", + "WinGet command-line tool": "WinGet-komandlinia ilo", + "Choose which command-line tool UniGetUI uses for WinGet operations when the COM API is not used": "Elektu kiun komandlinian ilon UniGetUI uzas por WinGet-operacioj kiam la COM API ne estas uzata", + "WinGet COM API": "WinGet COM API", + "Choose whether UniGetUI can use the WinGet COM API before falling back to the command-line tool": "Elektu ĉu UniGetUI povas uzi la WinGet COM API antaŭ ol retropaŝi al la komandlinia ilo", + "Reset WinGet": "Restarigi WinGet", + "This may help if no packages are listed": "Tio povas helpi se neniuj pakaĵoj estas listigitaj", + "Force install location parameter when updating packages with custom locations": "Devigi la parametron de instala loko dum ĝisdatigo de pakaĵoj kun propraj lokoj", + "Install Scoop": "Instali Scoop", + "Uninstall Scoop (and its packages)": "Malinstali Scoop (kaj ĝiajn pakaĵojn)", + "Run cleanup and clear cache": "Ruli purigon kaj malplenigi kaŝmemoron", + "Run": "Ruli", + "Enable Scoop cleanup on launch": "Ebligi purigon de Scoop ĉe lanĉo", + "Default vcpkg triplet": "Defaŭlta vcpkg-triplo", + "Change vcpkg root location": "Ŝanĝi la radikan lokon de vcpkg", + "Reset vcpkg root location": "Restarigi la radikan lokon de vcpkg", + "Open vcpkg root location": "Malfermi la radikan lokon de vcpkg", + "Language, theme and other miscellaneous preferences": "Lingvo, temo kaj aliaj diversaj preferoj", + "Show notifications on different events": "Montri sciigojn por diversaj eventoj", + "Change how UniGetUI checks and installs available updates for your packages": "Ŝanĝi kiel UniGetUI kontrolas kaj instalas disponeblajn ĝisdatigojn por viaj pakaĵoj", + "Automatically save a list of all your installed packages to easily restore them.": "Aŭtomate konservi liston de ĉiuj viaj instalitaj pakaĵoj por facile restarigi ilin.", + "Enable and disable package managers, change default install options, etc.": "Ebligi kaj malebligi pakaĵadministrilojn, ŝanĝi defaŭltajn instalajn opciojn, ktp.", + "Internet connection settings": "Agordoj de interreta konekto", + "Proxy settings, etc.": "Prokurilaj agordoj, ktp.", + "Beta features and other options that shouldn't be touched": "Betaaj funkcioj kaj aliaj opcioj, kiujn oni ne tuŝu", + "Reload sources": "Reŝargi fontojn", + "Delete source": "Forigi fonton", + "Known sources": "Konataj fontoj", + "Update checking": "Kontrolado de ĝisdatigoj", + "Automatic updates": "Aŭtomataj ĝisdatigoj", + "Check for package updates periodically": "Periode kontroli ĝisdatigojn de pakaĵoj", + "Check for updates every:": "Kontroli ĝisdatigojn ĉiun:", + "Install available updates automatically": "Aŭtomate instali disponeblajn ĝisdatigojn", + "Do not automatically install updates when the network connection is metered": "Ne aŭtomate instali ĝisdatigojn kiam la retkonekto estas laŭmezura", + "Do not automatically install updates when the device runs on battery": "Ne aŭtomate instali ĝisdatigojn kiam la aparato funkcias per baterio", + "Do not automatically install updates when the battery saver is on": "Ne aŭtomate instali ĝisdatigojn kiam energiŝpara reĝimo estas ŝaltita", + "Only show updates that are at least the specified number of days old": "Montri nur ĝisdatigojn, kiuj estas almenaŭ la specifita nombro da tagoj malnovaj", + "Warn me when the installer URL host changes between the installed version and the new version (WinGet only)": "Avertu min kiam la gastiganto de la instalila URL ŝanĝiĝas inter la instalita versio kaj la nova versio (nur WinGet)", + "Change how UniGetUI handles install, update and uninstall operations.": "Ŝanĝi kiel UniGetUI traktas instalajn, ĝisdatigajn kaj malinstalajn operaciojn.", + "Navigation": "Navigado", + "Check for UniGetUI updates": "Kontroli ĝisdatigojn de UniGetUI", + "Quit UniGetUI": "Eliri el UniGetUI", + "Filters": "Filtriloj", + "Sources": "Fontoj", + "Search for packages to start": "Serĉu pakaĵojn por komenci", + "Select all": "Elekti ĉiujn", + "Clear selection": "Forigi elekton", + "Instant search": "Tuja serĉo", + "Distinguish between uppercase and lowercase": "Distingi inter majuskloj kaj minuskloj", + "Ignore special characters": "Ignori specialajn signojn", + "Search mode": "Serĉreĝimo", + "Both": "Ambaŭ", + "Exact match": "Ekzakta kongruo", + "Show similar packages": "Montri similajn pakaĵojn", + "Loading": "Ŝargado", + "Package": "Pakaĵo", + "More options": "Pli da opcioj", + "Order by:": "Ordigi laŭ:", + "Name": "Nomo", + "Id": "ID", + "Ascendant": "Kreskanta", + "Descendant": "Malkreskanta", + "View modes": "Vidaj reĝimoj", + "Reload": "Reŝargi", + "Closed": "Fermita", + "Ascending": "Kreskanta", + "Descending": "Malkreskanta", + "{0}: {1}, {2}": "{0}: {1}, {2}", + "Order by": "Ordigi laŭ", + "No results were found matching the input criteria": "Neniuj rezultoj estis trovitaj kongruaj kun la enigaj kriterioj", + "No packages were found": "Neniuj pakaĵoj estis trovitaj", + "Loading packages": "Ŝargado de pakaĵoj", + "Skip integrity checks": "Preterlasi integrecajn kontrolojn", + "Download selected installers": "Elŝuti elektitajn instalilojn", + "Install selection": "Instali elekton", + "Install options": "Instalaj opcioj", + "Add selection to bundle": "Aldoni elekton al pakaĵaro", + "Download installer": "Elŝuti instalilon", + "Uninstall selection": "Malinstali elekton", + "Uninstall options": "Malinstalaj opcioj", + "Ignore selected packages": "Ignori elektitajn pakaĵojn", + "Open install location": "Malfermi instalan lokon", + "Reinstall package": "Reinstali pakaĵon", + "Uninstall package, then reinstall it": "Malinstali pakaĵon, poste reinstali ĝin", + "Ignore updates for this package": "Ignori ĝisdatigojn por ĉi tiu pakaĵo", + "WinGet malfunction detected": "Misfunkcio de WinGet detektita", + "It looks like WinGet is not working properly. Do you want to attempt to repair WinGet?": "Ŝajnas, ke WinGet ne funkcias ĝuste. Ĉu vi volas provi ripari WinGet?", + "Repair WinGet": "Ripari WinGet", + "Updates will no longer be ignored for {0}": "Ĝisdatigoj ne plu estos ignorataj por {0}", + "Updates are now ignored for {0}": "Ĝisdatigoj nun estas ignorataj por {0}", + "Do not ignore updates for this package anymore": "Ne plu ignori ĝisdatigojn por ĉi tiu pakaĵo", + "Add packages or open an existing package bundle": "Aldoni pakaĵojn aŭ malfermi ekzistantan pakaĵaron", + "Add packages to start": "Aldonu pakaĵojn por komenci", + "The current bundle has no packages. Add some packages to get started": "La nuna pakaĵaro enhavas neniujn pakaĵojn. Aldonu kelkajn pakaĵojn por komenci", + "New": "Nova", + "Save as": "Konservi kiel", + "Create .ps1 script": "Krei .ps1-skripton", + "Remove selection from bundle": "Forigi elekton el pakaĵaro", + "Skip hash checks": "Preterlasi haŝkontrolojn", + "The package bundle is not valid": "La pakaĵaro ne estas valida", + "The bundle you are trying to load appears to be invalid. Please check the file and try again.": "La pakaĵaro, kiun vi provas ŝargi, ŝajnas esti nevalida. Bonvolu kontroli la dosieron kaj reprovi.", + "Package bundle": "Pakaĵaro", + "Could not create bundle": "Ne eblis krei pakaĵaron", + "The package bundle could not be created due to an error.": "La pakaĵaro ne povis esti kreita pro eraro.", + "Install script": "Instala skripto", + "PowerShell script": "PowerShell-skripto", + "The installation script saved to {0}": "La instala skripto estis konservita en {0}", + "An error occurred": "Okazis eraro", + "An error occurred while attempting to create an installation script:": "Eraro okazis dum provo krei instalan skripton:", + "Hooray! No updates were found.": "Hura! Neniuj ĝisdatigoj estis trovitaj.", + "Uninstall selected packages": "Malinstali elektitajn pakaĵojn", + "Update selection": "Ĝisdatigi elekton", + "Update options": "Ĝisdatigaj opcioj", + "Uninstall package, then update it": "Malinstali pakaĵon, poste ĝisdatigi ĝin", + "Uninstall package": "Malinstali pakaĵon", + "Skip this version": "Preterlasi ĉi tiun version", + "Pause updates for": "Paŭzigi ĝisdatigojn por", + "User | Local": "Uzanto | Loka", + "Machine | Global": "Maŝino | Ĉiea", + "The default package manager for Debian/Ubuntu-based Linux distributions.
Contains: Debian/Ubuntu packages": "La defaŭlta pakaĵadministrilo por Debian/Ubuntu-bazitaj Linux-distribuoj.
Enhavas: Debian/Ubuntu-pakaĵojn", + "The Rust package manager.
Contains: Rust libraries and programs written in Rust": "La pakaĵadministrilo por Rust.
Enhavas: Rust-bibliotekojn kaj programojn verkitajn en Rust", + "The classical package manager for windows. You'll find everything there.
Contains: General Software": "La klasika pakaĵadministrilo por Windows. Vi trovos ĉion tie.
Enhavas: Ĝeneralan programaron", + "The default package manager for RHEL/Fedora-based Linux distributions.
Contains: RPM packages": "La defaŭlta pakaĵadministrilo por RHEL/Fedora-bazitaj Linux-distribuoj.
Enhavas: RPM-pakaĵojn", + "A repository full of tools and executables designed with Microsoft's .NET ecosystem in mind.
Contains: .NET related tools and scripts": "Deponejo plena je iloj kaj ruleblaj dosieroj desegnitaj kun la .NET-ekosistemo de Microsoft en menso.
Enhavas: .NET-rilatajn ilojn kaj skriptojn", + "The universal Linux package manager for desktop applications.
Contains: Flatpak applications from configured remotes": "La universala Linux-pakaĵadministrilo por labortablaj aplikaĵoj.
Enhavas: Flatpak-aplikaĵojn el agorditaj foraj deponejoj", + "NuPkg (zipped manifest)": "NuPkg (zipita manifesto)", + "The Missing Package Manager for macOS (or Linux).
Contains: Formulae, Casks": "La mankanta pakaĵadministrilo por macOS (aŭ Linux).
Enhavas: Formulae, Casks", + "Node JS's package manager. Full of libraries and other utilities that orbit the javascript world
Contains: Node javascript libraries and other related utilities": "La pakaĵadministrilo de Node JS. Plena je bibliotekoj kaj aliaj utilaĵoj, kiuj rondiras ĉirkaŭ la mondo de JavaScript
Enhavas: Node-JavaScript-bibliotekojn kaj aliajn rilatajn utilaĵojn", + "The default package manager for Arch Linux and its derivatives.
Contains: Arch Linux packages": "La defaŭlta pakaĵadministrilo por Arch Linux kaj ĝiaj derivaĵoj.
Enhavas: Arch Linux-pakaĵojn", + "Python's library manager. Full of python libraries and other python-related utilities
Contains: Python libraries and related utilities": "La bibliotekadministrilo de Python. Plena je Python-bibliotekoj kaj aliaj utilaĵoj rilataj al Python
Enhavas: Python-bibliotekojn kaj rilatajn utilaĵojn", + "PowerShell's package manager. Find libraries and scripts to expand PowerShell capabilities
Contains: Modules, Scripts, Cmdlets": "La pakaĵadministrilo de PowerShell. Trovu bibliotekojn kaj skriptojn por vastigi la kapablojn de PowerShell
Enhavas: Modulojn, skriptojn, Cmdlets", + "extracted": "eltirita", + "Scoop package": "Scoop-pakaĵo", + "Great repository of unknown but useful utilities and other interesting packages.
Contains: Utilities, Command-line programs, General Software (extras bucket required)": "Bonega deponejo de nekonataj sed utilaj iloj kaj aliaj interesaj pakaĵoj.
Enhavas: Ilojn, komandliniajn programojn, ĝeneralan programaron (extras bucket necesas)", + "The universal Linux package manager by Canonical.
Contains: Snap packages from the Snapcraft store": "La universala Linux-pakaĵadministrilo de Canonical.
Enhavas: Snap-pakaĵojn el la Snapcraft-vendejo", + "library": "biblioteko", + "feature": "trajto", + "A popular C/C++ library manager. Full of C/C++ libraries and other C/C++-related utilities
Contains: C/C++ libraries and related utilities": "Populara C/C++-bibliotekadministrilo. Plena je C/C++-bibliotekoj kaj aliaj utilaĵoj rilataj al C/C++
Enhavas: C/C++-bibliotekojn kaj rilatajn utilaĵojn", + "option": "opcio", + "This package cannot be installed from an elevated context.": "Ĉi tiu pakaĵo ne povas esti instalita en altigita kunteksto.", + "Please run UniGetUI as a regular user and try again.": "Bonvolu ruli UniGetUI kiel ordinara uzanto kaj reprovi.", + "Please check the installation options for this package and try again": "Bonvolu kontroli la instalajn opciojn por ĉi tiu pakaĵo kaj reprovi", + "Microsoft's official package manager. Full of well-known and verified packages
Contains: General Software, Microsoft Store apps": "La oficiala pakaĵadministrilo de Microsoft. Plena je konataj kaj kontrolitaj pakaĵoj
Enhavas: Ĝeneralan programaron, aplikaĵojn de Microsoft Store", + "Local PC": "Loka komputilo", + "Android Subsystem": "Android-subsistemo", + "Operation on queue (position {0})...": "Operacio en la vico (pozicio {0})...", + "Click here for more details": "Alklaku ĉi tie por pliaj detaloj", + "Operation canceled by user": "Operacio nuligita de la uzanto", + "Running PreOperation ({0}/{1})...": "Rulas PreOperation ({0}/{1})...", + "PreOperation {0} out of {1} failed, and was tagged as necessary. Aborting...": "PreOperation {0} el {1} malsukcesis kaj estis markita kiel necesa. Ĉesigas...", + "PreOperation {0} out of {1} finished with result {2}": "PreOperation {0} el {1} finiĝis kun rezulto {2}", + "Starting operation...": "Komencas operacion...", + "Running PostOperation ({0}/{1})...": "Rulas PostOperation ({0}/{1})...", + "PostOperation {0} out of {1} failed, and was tagged as necessary. Aborting...": "PostOperation {0} el {1} malsukcesis kaj estis markita kiel necesa. Ĉesigas...", + "PostOperation {0} out of {1} finished with result {2}": "PostOperation {0} el {1} finiĝis kun rezulto {2}", + "{package} installer download": "Elŝuto de la instalilo de {package}", + "{0} installer is being downloaded": "La instalilo de {0} estas elŝutata", + "Download succeeded": "Elŝuto sukcesis", + "{package} installer was downloaded successfully": "La instalilo de {package} estis sukcese elŝutita", + "Download failed": "Elŝuto malsukcesis", + "{package} installer could not be downloaded": "La instalilo de {package} ne povis esti elŝutita", + "{package} Installation": "Instalado de {package}", + "{0} is being installed": "{0} estas instalata", + "Installation succeeded": "Instalado sukcesis", + "{package} was installed successfully": "{package} estis sukcese instalita", + "Installation failed": "Instalado malsukcesis", + "{package} could not be installed": "{package} ne povis esti instalita", + "{package} Update": "Ĝisdatigo de {package}", + "Update succeeded": "Ĝisdatigo sukcesis", + "{package} was updated successfully": "{package} estis sukcese ĝisdatigita", + "Update failed": "Ĝisdatigo malsukcesis", + "{package} could not be updated": "{package} ne povis esti ĝisdatigita", + "{package} Uninstall": "Malinstalado de {package}", + "{0} is being uninstalled": "{0} estas malinstalata", + "Uninstall succeeded": "Malinstalado sukcesis", + "{package} was uninstalled successfully": "{package} estis sukcese malinstalita", + "Uninstall failed": "Malinstalado malsukcesis", + "{package} could not be uninstalled": "{package} ne povis esti malinstalita", + "Adding source {source}": "Aldonante fonton {source}", + "Adding source {source} to {manager}": "Aldonante fonton {source} al {manager}", + "Source added successfully": "Fonto sukcese aldonita", + "The source {source} was added to {manager} successfully": "La fonto {source} estis sukcese aldonita al {manager}", + "Could not add source": "Ne eblis aldoni la fonton", + "Could not add source {source} to {manager}": "Ne eblis aldoni fonton {source} al {manager}", + "Removing source {source}": "Forigante fonton {source}", + "Removing source {source} from {manager}": "Forigante fonton {source} el {manager}", + "Source removed successfully": "Fonto sukcese forigita", + "The source {source} was removed from {manager} successfully": "La fonto {source} estis sukcese forigita el {manager}", + "Could not remove source": "Ne eblis forigi la fonton", + "Could not remove source {source} from {manager}": "Ne eblis forigi fonton {source} el {manager}", + "The package manager \"{0}\" was not found": "La pakaĵadministrilo \"{0}\" ne estis trovita", + "The package manager \"{0}\" is disabled": "La pakaĵadministrilo \"{0}\" estas malŝaltita", + "There is an error with the configuration of the package manager \"{0}\"": "Estas eraro en la agordo de la pakaĵadministrilo \"{0}\"", + "The package \"{0}\" was not found on the package manager \"{1}\"": "La pakaĵo \"{0}\" ne estis trovita en la pakaĵadministrilo \"{1}\"", + "{0} is disabled": "{0} estas malŝaltita", + "{0} weeks": "{0} semajnoj", + "1 month": "1 monato", + "{0} months": "{0} monatoj", + "Something went wrong": "Io misfunkciis", + "An interal error occurred. Please view the log for further details.": "Okazis interna eraro. Bonvolu vidi la protokolon por pliaj detaloj.", + "No applicable installer was found for the package {0}": "Neniu aplikebla instalilo estis trovita por la pakaĵo {0}", + "Integrity checks will not be performed during this operation": "Integreckontroloj ne estos faritaj dum ĉi tiu operacio", + "This is not recommended.": "Tio ne estas rekomendinda.", + "Run now": "Ruli nun", + "Run next": "Ruli sekve", + "Run last": "Ruli laste", + "Show in explorer": "Montri en Esplorilo", + "Checked": "Markita", + "Unchecked": "Nemarkita", + "This package is already installed": "Ĉi tiu pakaĵo jam estas instalita", + "This package can be upgraded to version {0}": "Ĉi tiu pakaĵo povas esti ĝisdatigita al versio {0}", + "Updates for this package are ignored": "Ĝisdatigoj por ĉi tiu pakaĵo estas ignorataj", + "This package is being processed": "Ĉi tiu pakaĵo estas prilaborata", + "This package is not available": "Ĉi tiu pakaĵo ne estas disponebla", + "Select the source you want to add:": "Elektu la fonton, kiun vi volas aldoni:", + "Source name:": "Nomo de la fonto:", + "Source URL:": "URL de la fonto:", + "An error occurred when adding the source: ": "Okazis eraro dum aldono de la fonto: ", + "Package management made easy": "Facila pakaĵadministrado", + "version {0}": "versio {0}", + "[RAN AS ADMINISTRATOR]": "[RULIGITA KIEL ADMINISTRANTO]", + "Portable mode": "Portebla reĝimo\n", + "DEBUG BUILD": "SENCIMIGA KONSTRUO", + "Here you can change UniGetUI's behaviour regarding the following shortcuts. Checking a shortcut will make UniGetUI delete it if if gets created on a future upgrade. Unchecking it will keep the shortcut intact": "Ĉi tie vi povas ŝanĝi la konduton de UniGetUI rilate al la jenaj ŝparvojoj. Marki ŝparvojon igos UniGetUI forigi ĝin se ĝi kreiĝos dum estonta ĝisdatigo. Malmarki ĝin konservos la ŝparvojon netuŝita.", + "Manual scan": "Mana skanado", + "Existing shortcuts on your desktop will be scanned, and you will need to pick which ones to keep and which ones to remove.": "Ekzistantaj ŝparvojoj sur via labortablo estos skanitaj, kaj vi devos elekti kiujn konservi kaj kiujn forigi.", + "Delete?": "Ĉu forigi?", + "I understand": "Mi komprenas", + "Chocolatey setup changed": "Agordo de Chocolatey ŝanĝiĝis", + "UniGetUI no longer includes its own private Chocolatey installation. A legacy UniGetUI-managed Chocolatey installation was detected for this user profile, but system Chocolatey was not found. Chocolatey will stay unavailable in UniGetUI until Chocolatey is installed on the system and UniGetUI is restarted. Applications previously installed through UniGetUI's bundled Chocolatey may still appear under other sources such as Local PC or WinGet.": "UniGetUI ne plu inkluzivas sian propran privatan instalaĵon de Chocolatey. Malnova instalaĵo de Chocolatey administrita de UniGetUI estis detektita por ĉi tiu uzantprofilo, sed sistema Chocolatey ne estis trovita. Chocolatey restos nedisponebla en UniGetUI ĝis Chocolatey estos instalita en la sistemo kaj UniGetUI estos restartigita. Aplikaĵoj antaŭe instalitaj per la inkluzivita Chocolatey de UniGetUI eble ankoraŭ aperos sub aliaj fontoj kiel Loka komputilo aŭ WinGet.", + "NOTE: This troubleshooter can be disabled from UniGetUI Settings, on the WinGet section": "RIMARKO: Ĉi tiu problemosolvilo povas esti malŝaltita en UniGetUI-agordoj, en la sekcio WinGet", + "Restart": "Restartigi", + "Are you sure you want to delete all shortcuts?": "Ĉu vi certas, ke vi volas forigi ĉiujn ŝparvojojn?", + "Any new shorcuts created during an install or an update operation will be deleted automatically, instead of showing a confirmation prompt the first time they are detected.": "Ĉiuj novaj ŝparvojoj kreitaj dum instalado aŭ ĝisdatigo estos forigitaj aŭtomate, anstataŭ montri konfirman inviton kiam ili unuafoje estas detektitaj.", + "Any shorcuts created or modified outside of UniGetUI will be ignored. You will be able to add them via the {0} button.": "Ĉiuj ŝparvojoj kreitaj aŭ modifitaj ekster UniGetUI estos ignorataj. Vi povos aldoni ilin per la butono {0}.", + "Are you really sure you want to enable this feature?": "Ĉu vi vere certas, ke vi volas ebligi ĉi tiun funkcion?", + "No new shortcuts were found during the scan.": "Neniuj novaj ŝparvojoj estis trovitaj dum la skanado.", + "How to add packages to a bundle": "Kiel aldoni pakaĵojn al pakaĵaro", + "In order to add packages to a bundle, you will need to: ": "Por aldoni pakaĵojn al pakaĵaro, vi devos: ", + "1. Navigate to the \"{0}\" or \"{1}\" page.": "1. Iru al la paĝo \"{0}\" aŭ \"{1}\".", + "2. Locate the package(s) you want to add to the bundle, and select their leftmost checkbox.": "2. Trovu la pakaĵojn, kiujn vi volas aldoni al la pakaĵaro, kaj elektu ilian plej maldekstran markobutonon.", + "3. When the packages you want to add to the bundle are selected, find and click the option \"{0}\" on the toolbar.": "3. Kiam la pakaĵoj, kiujn vi volas aldoni al la pakaĵaro, estas elektitaj, trovu kaj alklaku la opcion \"{0}\" en la ilobreto.", + "4. Your packages will have been added to the bundle. You can continue adding packages, or export the bundle.": "4. Viaj pakaĵoj estos aldonitaj al la pakaĵaro. Vi povas daŭrigi aldoni pakaĵojn aŭ eksporti la pakaĵaron.", + "Which backup do you want to open?": "Kiun sekurkopion vi volas malfermi?", + "Select the backup you want to open. Later, you will be able to review which packages you want to install.": "Elektu la sekurkopion, kiun vi volas malfermi. Poste vi povos revizii kiujn pakaĵojn vi volas instali.", + "There are ongoing operations. Quitting UniGetUI may cause them to fail. Do you want to continue?": "Estas daŭrantaj operacioj. Eliri el UniGetUI povas kaŭzi ilian malsukceson. Ĉu vi volas daŭrigi?", + "UniGetUI or some of its components are missing or corrupt.": "UniGetUI aŭ kelkaj el ĝiaj komponantoj mankas aŭ estas difektitaj.", + "It is strongly recommended to reinstall UniGetUI to adress the situation.": "Estas forte rekomendite reinstali UniGetUI por solvi la situacion.", + "Refer to the UniGetUI Logs to get more details regarding the affected file(s)": "Rigardu la protokolojn de UniGetUI por ricevi pliajn detalojn pri la tuŝitaj dosieroj", + "Integrity checks can be disabled from the Experimental Settings": "Integrecaj kontroloj povas esti malŝaltitaj en la Eksperimentaj agordoj", + "Repair UniGetUI": "Ripari UniGetUI", + "Live output": "Rekta eligo", + "This package bundle had some settings that are potentially dangerous, and may be ignored by default.": "Ĉi tiu pakaĵaro havis kelkajn agordojn, kiuj estas eble danĝeraj, kaj ili eble estos ignorataj defaŭlte.", + "Entries that show in YELLOW will be IGNORED.": "Eroj montrataj en FLAVA estos IGNORATAJ.", + "Entries that show in RED will be IMPORTED.": "Eroj montrataj en RUĜA estos IMPORTITAJ.", + "You can change this behavior on UniGetUI security settings.": "Vi povas ŝanĝi ĉi tiun konduton en la sekurecaj agordoj de UniGetUI.", + "Open UniGetUI security settings": "Malfermi la sekurecajn agordojn de UniGetUI", + "Should you modify the security settings, you will need to open the bundle again for the changes to take effect.": "Se vi modifos la sekurecajn agordojn, vi devos remalfermi la pakaĵaron por ke la ŝanĝoj efektiviĝu.", + "Details of the report:": "Detaloj de la raporto:", + "Are you sure you want to create a new package bundle? ": "Ĉu vi certas, ke vi volas krei novan pakaĵaron? ", + "Any unsaved changes will be lost": "Ĉiuj nekonservitaj ŝanĝoj perdiĝos", + "Warning!": "Averto!", + "For security reasons, custom command-line arguments are disabled by default. Go to UniGetUI security settings to change this. ": "Pro sekurecaj kialoj, propraj komandliniaj argumentoj estas malŝaltitaj defaŭlte. Iru al la sekurecaj agordoj de UniGetUI por ŝanĝi tion. ", + "Change default options": "Ŝanĝi la defaŭltajn opciojn", + "Ignore future updates for this package": "Ignori estontajn ĝisdatigojn por ĉi tiu pakaĵo", + "For security reasons, pre-operation and post-operation scripts are disabled by default. Go to UniGetUI security settings to change this. ": "Pro sekurecaj kialoj, antaŭoperaciaj kaj postoperaciaj skriptoj estas malŝaltitaj defaŭlte. Iru al la sekurecaj agordoj de UniGetUI por ŝanĝi tion. ", + "You can define the commands that will be run before or after this package is installed, updated or uninstalled. They will be run on a command prompt, so CMD scripts will work here.": "Vi povas difini la komandojn, kiuj ruliĝos antaŭ aŭ post kiam ĉi tiu pakaĵo estos instalita, ĝisdatigita aŭ malinstalita. Ili ruliĝos en komandlinia fenestro, do CMD-skriptoj funkcios ĉi tie.", + "Change this and unlock": "Ŝanĝi tion kaj malŝlosi", + "{0} Install options are currently locked because {0} follows the default install options.": "La instalaj opcioj de {0} estas nuntempe ŝlositaj ĉar {0} sekvas la defaŭltajn instalajn opciojn.", + "Unset or unknown": "Nedifinita aŭ nekonata", + "This package has no screenshots or is missing the icon? Contrbute to UniGetUI by adding the missing icons and screenshots to our open, public database.": "Ĉi tiu pakaĵo ne havas ekrankopiojn aŭ mankas la ikono? Kontribuu al UniGetUI aldonante la mankantajn ikonojn kaj ekrankopiojn al nia malferma, publika datumbazo.", + "Become a contributor": "Fariĝi kontribuanto", + "Update to {0} available": "Ĝisdatigo al {0} disponeblas", + "Reinstall": "Reinstali", + "Installer not available": "Instalilo ne disponeblas", + "Version:": "Versio:", + "UniGetUI Version {0}": "UniGetUI versio {0}", + "Performing backup, please wait...": "Sekurkopiado okazas, bonvolu atendi...", + "An error occurred while logging in: ": "Okazis eraro dum ensaluto: ", + "Fetching available backups...": "Ŝargante disponeblajn sekurkopiojn...", + "Done!": "Farite!", + "The cloud backup has been loaded successfully.": "La nuba sekurkopio estis ŝargita sukcese.", + "An error occurred while loading a backup: ": "Okazis eraro dum ŝargado de sekurkopio: ", + "Backing up packages to GitHub Gist...": "Sekurkopiante pakaĵojn al GitHub Gist...", + "Backup Successful": "Sekurkopio sukcesis", + "The cloud backup completed successfully.": "La nuba sekurkopio finiĝis sukcese.", + "Could not back up packages to GitHub Gist: ": "Ne eblis fari sekurkopion de la pakaĵoj al GitHub Gist: ", + "It is not guaranteed that the provided credentials will be stored safely, so you may as well not use the credentials of your bank account": "Ne estas garantiite, ke la provizitaj ensalutdatumoj estos konservitaj sekure, do prefere ne uzu la ensalutdatumojn de via banka konto", + "Enable the automatic WinGet troubleshooter": "Ebligi la aŭtomatan WinGet-problemsolvilon", + "Add updates that fail with a 'no applicable update found' to the ignored updates list": "Aldoni ĝisdatigojn, kiuj malsukcesas kun 'no applicable update found', al la listo de ignorataj ĝisdatigoj.", + "Invalid selection": "Nevalida elekto", + "No package was selected": "Neniu pakaĵo estis elektita", + "More than 1 package was selected": "Pli ol 1 pakaĵo estis elektita", + "List": "Listo", + "Grid": "Krado", + "Icons": "Ikonoj", + "\"{0}\" is a local package and does not have available details": "\"{0}\" estas loka pakaĵo kaj ne havas disponeblajn detalojn", + "\"{0}\" is a local package and is not compatible with this feature": "\"{0}\" estas loka pakaĵo kaj ne kongruas kun ĉi tiu funkcio", + "Add packages to bundle": "Aldoni pakaĵojn al la pakaĵaro", + "Preparing packages, please wait...": "Pakaĵoj estas preparataj, bonvolu atendi...", + "Loading packages, please wait...": "Pakaĵoj estas ŝargataj, bonvolu atendi...", + "Saving packages, please wait...": "Pakaĵoj estas konservataj, bonvolu atendi...", + "The bundle was created successfully on {0}": "La pakaĵaro estis sukcese kreita en {0}", + "User profile": "Uzantprofilo", + "Error": "Eraro", + "Log in failed: ": "Ensaluto malsukcesis: ", + "Log out failed: ": "Elsaluto malsukcesis: ", + "Package backup settings": "Agordoj de sekurkopio de pakaĵoj", + "Manage UniGetUI autostart behaviour from the Settings app": "Administri la aŭtolanĉan konduton de UniGetUI", + "Choose how many operations shoulds be performed in parallel": "Elektu kiom da operacioj estu plenumataj paralele", + "Something went wrong while launching the updater.": "Io misfunkciis dum lanĉo de la ĝisdatigilo.", + "Please try again later": "Bonvolu reprovi poste", + "Show the release notes after UniGetUI is updated": "Montri la eldonajn notojn post kiam UniGetUI estas ĝisdatigita" +} diff --git a/src/Languages/lang_es-MX.json b/src/Languages/lang_es-MX.json new file mode 100644 index 0000000..53cc8c1 --- /dev/null +++ b/src/Languages/lang_es-MX.json @@ -0,0 +1,846 @@ +{ + "{0} of {1} operations completed": "{0} de {1} operaciones completadas", + "{0} is now {1}": "{0} ahora es {1}", + "Enabled": "Habilitado", + "Disabled": "Deshabilitado", + "Privacy": "Privacidad", + "Hide my username from the logs": "Ocultar mi nombre de usuario de los registros", + "Replaces your username with **** in the logs. Restart UniGetUI to also hide it from already-recorded entries.": "Reemplaza tu nombre de usuario con **** en los registros. Reinicia UniGetUI para ocultarlo también en las entradas ya registradas.", + "Your last update attempt did not complete.": "Tu último intento de actualización no se completó.", + "UniGetUI could not confirm whether the update succeeded. Open the log to see what happened.": "UniGetUI no pudo confirmar si la actualización tuvo éxito. Abre el registro para ver qué ocurrió.", + "View log": "Ver registro", + "The installer reported success but did not restart UniGetUI.": "El instalador informó éxito, pero no reinició UniGetUI.", + "The installer failed to initialize.": "El instalador no pudo inicializarse.", + "Setup was canceled before installation began.": "La configuración se canceló antes de que comenzara la instalación.", + "A fatal error occurred during the preparation phase.": "Ocurrió un error fatal durante la fase de preparación.", + "A fatal error occurred during installation.": "Ocurrió un error fatal durante la instalación.", + "Installation was canceled while in progress.": "La instalación se canceló mientras estaba en curso.", + "The installer was terminated by another process.": "El instalador fue terminado por otro proceso.", + "The preparation phase determined the installation cannot proceed.": "La fase de preparación determinó que la instalación no puede continuar.", + "The installer could not start. UniGetUI may already be running, or you do not have permission to install.": "El instalador no pudo iniciarse. Es posible que UniGetUI ya se esté ejecutando o que no tengas permisos para instalar.", + "Unexpected installer error.": "Error inesperado del instalador.", + "We are checking for updates.": "Estamos buscando actualizaciones.", + "Please wait": "Por favor, espera", + "Great! You are on the latest version.": "¡Genial! Tienes la última versión.", + "There are no new UniGetUI versions to be installed": "No hay nuevas versiones de UniGetUI para instalar", + "UniGetUI version {0} is being downloaded.": "Se está descargando la versión {0} de UniGetUI.", + "This may take a minute or two": "Esto puede tardar un minuto o dos", + "The installer authenticity could not be verified.": "No se pudo verificar la autenticidad del instalador.", + "The update process has been aborted.": "El proceso de actualización ha sido abortado.", + "Auto-update is not yet available on this platform.": "La actualización automática aún no está disponible en esta plataforma.", + "Please update UniGetUI manually.": "Por favor, actualiza UniGetUI manualmente.", + "An error occurred when checking for updates: ": "Ocurrió un error al buscar actualizaciones: ", + "The updater could not be launched.": "No se pudo iniciar el actualizador.", + "The operating system did not start the installer process.": "El sistema operativo no inició el proceso del instalador.", + "UniGetUI is being updated...": "UniGetUI se está actualizando...", + "Update installed.": "Actualización instalada.", + "UniGetUI was updated successfully, but this running copy was not replaced. This usually means you are running a development build. Close this copy and start the newly-installed version to finish.": "UniGetUI se actualizó correctamente, pero esta copia en ejecución no fue reemplazada. Esto suele significar que estás ejecutando una versión de desarrollo. Cierra esta copia e inicia la versión recién instalada para finalizar.", + "The update could not be applied.": "No se pudo aplicar la actualización.", + "Installer exit code {0}: {1}": "Código de salida del instalador {0}: {1}", + "Update cancelled.": "Actualización cancelada.", + "Authentication was cancelled.": "La autenticación fue cancelada.", + "Installer exit code {0}": "Código de salida del instalador {0}", + "Operation in progress": "Operación en curso", + "Please wait...": "Por favor, espera...", + "Success!": "¡Éxito!", + "Failed": "Fallido", + "An error occurred while processing this package": "Ocurrió un error al procesar este paquete", + "Installer": "Instalador", + "Executable": "Ejecutable", + "MSI": "MSI", + "Compressed file": "Archivo comprimido", + "MSIX": "MSIX", + "WinGet was repaired successfully": "WinGet se reparó correctamente", + "It is recommended to restart UniGetUI after WinGet has been repaired": "Se recomienda reiniciar UniGetUI después de haber reparado WinGet", + "WinGet could not be repaired": "No se pudo reparar WinGet", + "An unexpected issue occurred while attempting to repair WinGet. Please try again later": "Ocurrió un problema inesperado al intentar reparar WinGet. Por favor, inténtalo más tarde", + "Log in to enable cloud backup": "Inicia sesión para habilitar el respaldo en la nube", + "Backup Failed": "Error en el respaldo", + "Downloading backup...": "Descargando respaldo...", + "An update was found!": "¡Se encontró una actualización!", + "{0} can be updated to version {1}": "{0} puede actualizarse a la versión {1}", + "Updates found!": "¡Actualizaciones encontradas!", + "{0} packages can be updated": "{0} paquetes pueden actualizarse", + "{0} is being updated to version {1}": "{0} se está actualizando a la versión {1}", + "{0} packages are being updated": "{0} paquetes se están actualizando", + "You have currently version {0} installed": "Tienes instalada la versión {0}", + "Desktop shortcut created": "Acceso directo al escritorio creado", + "UniGetUI has detected a new desktop shortcut that can be deleted automatically.": "UniGetUI ha detectado un nuevo acceso directo al escritorio que puede eliminarse automáticamente.", + "{0} desktop shortcuts created": "{0} accesos directos al escritorio creados", + "UniGetUI has detected {0} new desktop shortcuts that can be deleted automatically.": "UniGetUI ha detectado {0} nuevos accesos directos al escritorio que pueden eliminarse automáticamente.", + "Attention required": "Se requiere atención", + "Restart required": "Se requiere reiniciar", + "1 update is available": "Hay 1 actualización disponible", + "{0} updates are available": "Hay {0} actualizaciones disponibles", + "Everything is up to date": "Todo está actualizado", + "Discover Packages": "Descubrir paquetes", + "Available Updates": "Actualizaciones disponibles", + "Installed Packages": "Paquetes instalados", + "UniGetUI Version {0} by Devolutions": "UniGetUI Versión {0} por Devolutions", + "Show UniGetUI": "Mostrar UniGetUI", + "Quit": "Salir", + "Are you sure?": "¿Estás seguro?", + "Do you really want to uninstall {0}?": "¿Realmente quieres desinstalar {0}?", + "Do you really want to uninstall the following {0} packages?": "¿Realmente quieres desinstalar los siguientes {0} paquetes?", + "No": "No", + "Yes": "Sí", + "Partial": "Parcial", + "View on UniGetUI": "Ver en UniGetUI", + "Update": "Actualizar", + "Open UniGetUI": "Abrir UniGetUI", + "Update all": "Actualizar todo", + "Update now": "Actualizar ahora", + "Installer host changed since the installed version.\n": "El host del instalador ha cambiado desde la versión instalada.\n", + "This package is on the queue": "Este paquete está en cola", + "installing": "instalando", + "updating": "actualizando", + "uninstalling": "desinstalando", + "installed": "instalado", + "Retry": "Reintentar", + "Install": "Instalar", + "Uninstall": "Desinstalar", + "Open": "Abrir", + "Operation profile:": "Perfil de operación:", + "Follow the default options when installing, upgrading or uninstalling this package": "Seguir las opciones predeterminadas al instalar, actualizar o desinstalar este paquete", + "The following settings will be applied each time this package is installed, updated or removed.": "Los siguientes ajustes se aplicarán cada vez que este paquete se instale, actualice o elimine.", + "Version to install:": "Versión a instalar:", + "Architecture to install:": "Arquitectura a instalar:", + "Installation scope:": "Ámbito de instalación:", + "Install location:": "Ubicación de instalación:", + "Select": "Seleccionar", + "Reset": "Restablecer", + "Custom install arguments:": "Argumentos de instalación personalizados:", + "Custom update arguments:": "Argumentos de actualización personalizados:", + "Custom uninstall arguments:": "Argumentos de desinstalación personalizados:", + "Pre-install command:": "Comando de preinstalación:", + "Post-install command:": "Comando de postinstalación:", + "Abort install if pre-install command fails": "Abortar instalación si el comando de preinstalación falla", + "Pre-update command:": "Comando de preactualización:", + "Post-update command:": "Comando de postactualización:", + "Abort update if pre-update command fails": "Abortar actualización si el comando de preactualización falla", + "Pre-uninstall command:": "Comando de predesinstalación:", + "Post-uninstall command:": "Comando de postdesinstalación:", + "Abort uninstall if pre-uninstall command fails": "Abortar desinstalación si el comando de predesinstalación falla", + "Command-line to run:": "Línea de comandos a ejecutar:", + "Save and close": "Guardar y cerrar", + "General": "General", + "Architecture & Location": "Arquitectura y ubicación", + "Command-line": "Línea de comandos", + "Close apps": "Cerrar aplicaciones", + "Pre/Post install": "Pre/Post instalación", + "Select the processes that should be closed before this package is installed, updated or uninstalled.": "Selecciona los procesos que deben cerrarse antes de que este paquete se instale, actualice o desinstale.", + "Write here the process names here, separated by commas (,)": "Escribe aquí los nombres de los procesos, separados por comas (,)", + "Try to kill the processes that refuse to close when requested to": "Intentar forzar el cierre de los procesos que se nieguen a cerrarse", + "Run as admin": "Ejecutar como administrador", + "Interactive installation": "Instalación interactiva", + "Skip hash check": "Omitir comprobación de hash", + "Uninstall previous versions when updated": "Desinstalar versiones anteriores al actualizar", + "Skip minor updates for this package": "Omitir actualizaciones menores para este paquete", + "Automatically update this package": "Actualizar automáticamente este paquete", + "{0} installation options": "{0} opciones de instalación", + "Latest": "Última", + "PreRelease": "Prelanzamiento", + "Default": "Predeterminado", + "Manage ignored updates": "Administrar actualizaciones ignoradas", + "The packages listed here won't be taken in account when checking for updates. Double-click them or click the button on their right to stop ignoring their updates.": "Los paquetes enumerados aquí no se tendrán en cuenta al buscar actualizaciones. Haz doble clic en ellos o haz clic en el botón de la derecha para dejar de ignorar sus actualizaciones.", + "Reset list": "Restablecer lista", + "Do you really want to reset the ignored updates list? This action cannot be reverted": "¿Realmente quieres restablecer la lista de actualizaciones ignoradas? Esta acción no se puede deshacer", + "No ignored updates": "No hay actualizaciones ignoradas", + "Package Name": "Nombre del paquete", + "Package ID": "ID del paquete", + "Ignored version": "Versión ignorada", + "New version": "Nueva versión", + "Source": "Fuente", + "All versions": "Todas las versiones", + "Unknown": "Desconocido", + "Up to date": "Actualizado", + "Package {name} from {manager}": "Paquete {name} de {manager}", + "Remove {0} from ignored updates": "Eliminar {0} de las actualizaciones ignoradas", + "Cancel": "Cancelar", + "Administrator privileges": "Privilegios de administrador", + "This operation is running with administrator privileges.": "Esta operación se está ejecutando con privilegios de administrador.", + "Interactive operation": "Operación interactiva", + "This operation is running interactively.": "Esta operación se está ejecutando de forma interactiva.", + "You will likely need to interact with the installer.": "Es probable que necesites interactuar con el instalador.", + "Integrity checks skipped": "Comprobaciones de integridad omitidas", + "Integrity checks will not be performed during this operation.": "No se realizarán comprobaciones de integridad durante esta operación.", + "Proceed at your own risk.": "Proceda bajo su propio riesgo.", + "Close": "Cerrar", + "Loading...": "Cargando...", + "Installer SHA256": "SHA256 del instalador", + "Homepage": "Página principal", + "Author": "Autor", + "Publisher": "Editor", + "License": "Licencia", + "Manifest": "Manifiesto", + "Installer Type": "Tipo de instalador", + "Size": "Tamaño", + "Installer URL": "URL del instalador", + "Last updated:": "Última actualización:", + "Release notes URL": "URL de las notas de la versión", + "Package details": "Detalles del paquete", + "Dependencies:": "Dependencias:", + "Release notes": "Notas de la versión", + "Screenshots": "Capturas de pantalla", + "This package has no screenshots or is missing the icon? Contribute to UniGetUI by adding the missing icons and screenshots to our open, public database.": "¿Este paquete no tiene capturas de pantalla o le falta el icono? Contribuye a UniGetUI añadiendo los iconos y capturas faltantes a nuestra base de datos pública y abierta.", + "Version": "Versión", + "Install as administrator": "Instalar como administrador", + "Update to version {0}": "Actualizar a la versión {0}", + "Installed Version": "Versión instalada", + "Update as administrator": "Actualizar como administrador", + "Interactive update": "Actualización interactiva", + "Uninstall as administrator": "Desinstalar como administrador", + "Interactive uninstall": "Desinstalación interactiva", + "Uninstall and remove data": "Desinstalar y eliminar datos", + "Not available": "No disponible", + "Installer SHA512": "SHA512 del instalador", + "Unknown size": "Tamaño desconocido", + "No dependencies specified": "No se han especificado dependencias", + "mandatory": "obligatorio", + "optional": "opcional", + "UniGetUI {0} is ready to be installed.": "UniGetUI {0} está listo para ser instalado.", + "The update process will start after closing UniGetUI": "El proceso de actualización comenzará después de cerrar UniGetUI", + "UniGetUI has been ran as administrator, which is not recommended. When running UniGetUI as administrator, EVERY operation launched from UniGetUI will have administrator privileges. You can still use the program, but we highly recommend not running UniGetUI with administrator privileges.": "UniGetUI se ha ejecutado como administrador, lo cual no es recomendable. Al ejecutar UniGetUI como administrador, TODA operación lanzada desde UniGetUI tendrá privilegios de administrador. Aún puedes usar el programa, pero recomendamos encarecidamente no ejecutar UniGetUI con privilegios de administrador.", + "Share anonymous usage data": "Compartir datos de uso anónimos", + "UniGetUI collects anonymous usage data in order to improve the user experience.": "UniGetUI recopila datos de uso anónimos para mejorar la experiencia del usuario.", + "Accept": "Aceptar", + "Software Updates": "Actualizaciones de software", + "Package Bundles": "Lotes de paquetes", + "Settings": "Configuración", + "Package Managers": "Gestores de paquetes", + "UniGetUI Log": "Registro de UniGetUI", + "Package Manager logs": "Registros del gestor de paquetes", + "Operation history": "Historial de operaciones", + "Help": "Ayuda", + "UniGetUI": "UniGetUI", + "You have installed UniGetUI Version {0}": "Has instalado UniGetUI Versión {0}", + "Disclaimer": "Descargo de responsabilidad", + "UniGetUI is developed by Devolutions and is not affiliated with any of the compatible package managers.": "UniGetUI es desarrollado por Devolutions y no está afiliado a ninguno de los gestores de paquetes compatibles.", + "UniGetUI wouldn't have been possible without the help of the contributors. Thank you all 🥳": "UniGetUI no habría sido posible sin la ayuda de los colaboradores. Gracias a todos 🥳", + "UniGetUI uses the following libraries. Without them, UniGetUI wouldn't have been possible.": "UniGetUI utiliza las siguientes librerías. Sin ellas, UniGetUI no habría sido posible.", + "{0} homepage": "Página principal de {0}", + "UniGetUI has been translated to more than 40 languages thanks to the volunteer translators. Thank you 🤝": "UniGetUI ha sido traducido a más de 40 idiomas gracias a los traductores voluntarios. Gracias 🤝", + "Verbose": "Detallado", + "1 - Errors": "1 - Errores", + "2 - Warnings": "2 - Advertencias", + "3 - Information (less)": "3 - Información (menos)", + "4 - Information (more)": "4 - Información (más)", + "5 - information (debug)": "5 - Información (depuración)", + "Warning": "Advertencia", + "The following settings may pose a security risk, hence they are disabled by default.": "Los siguientes ajustes pueden suponer un riesgo de seguridad, por lo que están deshabilitados por defecto.", + "Enable the settings below if and only if you fully understand what they do, and the implications they may have.": "Habilita los ajustes a continuación SÓLO SI entiendes completamente qué hacen y las implicaciones y peligros que pueden conllevar.", + "The settings will list, in their descriptions, the potential security issues they may have.": "Los ajustes enumerarán, en sus descripciones, los posibles problemas de seguridad que puedan tener.", + "The backup will include the complete list of the installed packages and their installation options. Ignored updates and skipped versions will also be saved.": "El respaldo incluirá la lista completa de los paquetes instalados y sus opciones de instalación. También se guardarán las actualizaciones ignoradas y las versiones omitidas.", + "The backup will NOT include any binary file nor any program's saved data.": "El respaldo NO incluirá ningún archivo binario ni datos guardados de ningún programa.", + "The size of the backup is estimated to be less than 1MB.": "Se estima que el tamaño del respaldo es inferior a 1 MB.", + "The backup will be performed after login.": "El respaldo se realizará después de iniciar sesión.", + "{pcName} installed packages": "Paquetes instalados en {pcName}", + "Current status: Not logged in": "Estado actual: No se ha iniciado sesión", + "You are logged in as {0} (@{1})": "Has iniciado sesión como {0} (@{1})", + "Nice! Backups will be uploaded to a private gist on your account": "¡Genial! Los respaldos se subirán a un Gist privado en tu cuenta", + "Select backup": "Seleccionar respaldo", + "Settings imported from {0}": "Configuración importada desde {0}", + "UniGetUI Settings": "Configuración de UniGetUI", + "Settings exported to {0}": "Configuración exportada a {0}", + "UniGetUI settings were reset": "La configuración de UniGetUI ha sido restablecida", + "Allow pre-release versions": "Permitir versiones preliminares", + "Apply": "Aplicar", + "For security reasons, custom command-line arguments are disabled by default. Go to UniGetUI security settings to change this.": "Por razones de seguridad, los argumentos de línea de comandos personalizados están deshabilitados por defecto. Ve a la configuración de seguridad de UniGetUI para cambiar esto.", + "Go to UniGetUI security settings": "Ir a la configuración de seguridad de UniGetUI", + "The following options will be applied by default each time a {0} package is installed, upgraded or uninstalled.": "Las siguientes opciones se aplicarán por defecto cada vez que se instale, actualice o desinstale un paquete de {0}.", + "Package's default": "Predeterminado del paquete", + "Install location can't be changed for {0} packages": "La ubicación de instalación no se puede cambiar para los paquetes de {0}", + "The local icon cache currently takes {0} MB": "La caché de iconos local ocupa actualmente {0} MB", + "Username": "Nombre de usuario", + "Password": "Contraseña", + "Credentials": "Credenciales", + "It is not guaranteed that the provided credentials will be stored safely": "No se garantiza que las credenciales proporcionadas se almacenen de forma segura", + "Partially": "Parcialmente", + "Package manager": "Gestor de paquetes", + "Compatible with proxy": "Compatible con proxy", + "Compatible with authentication": "Compatible con autenticación", + "Proxy compatibility table": "Tabla de compatibilidad de proxy", + "{0} settings": "Configuración de {0}", + "{0} status": "Estado de {0}", + "Default installation options for {0} packages": "Opciones de instalación predeterminadas para paquetes de {0}", + "Expand version": "Expandir versión", + "The executable file for {0} was not found": "No se encontró el archivo ejecutable de {0}", + "{pm} is disabled": "{pm} está deshabilitado", + "Enable it to install packages from {pm}.": "Habilítalo para instalar paquetes de {pm}.", + "{pm} is enabled and ready to go": "{pm} está habilitado y listo", + "{pm} version:": "Versión de {pm}:", + "{pm} was not found!": "¡No se encontró {pm}!", + "You may need to install {pm} in order to use it with UniGetUI.": "Es posible que necesites instalar {pm} para poder usarlo con UniGetUI.", + "Scoop Installer - UniGetUI": "Instalador de Scoop - UniGetUI", + "Scoop Uninstaller - UniGetUI": "Desinstalador de Scoop - UniGetUI", + "Clearing Scoop cache - UniGetUI": "Limpiando caché de Scoop - UniGetUI", + "Restart UniGetUI to fully apply changes": "Reinicia UniGetUI para aplicar los cambios completamente", + "Restart UniGetUI": "Reiniciar UniGetUI", + "Manage {0} sources": "Administrar fuentes de {0}", + "Add source": "Agregar fuente", + "Add": "Agregar", + "Source name": "Nombre de la fuente", + "Source URL": "URL de la fuente", + "Other": "Otro", + "No minimum age": "Sin antigüedad mínima", + "1 day": "1 día", + "{0} days": "{0} días", + "Custom...": "Personalizado...", + "{0} minutes": "{0} minutos", + "1 hour": "1 hora", + "{0} hours": "{0} horas", + "1 week": "1 semana", + "Supports release dates": "Soporta fechas de lanzamiento", + "Release date support per package manager": "Soporte de fecha de lanzamiento por gestor de paquetes", + "Search for packages": "Buscar paquetes", + "Local": "Local", + "OK": "Aceptar", + "Last checked: {0}": "Última comprobación: {0}", + "{0} packages were found, {1} of which match the specified filters.": "Se encontraron {0} paquetes, de los cuales {1} coinciden con los filtros especificados.", + "{0} selected": "{0} seleccionado(s)", + "(Last checked: {0})": "(Última comprobación: {0})", + "All packages selected": "Todos los paquetes seleccionados", + "Package selection cleared": "Selección de paquetes borrada", + "{0}: {1}": "{0}: {1}", + "More info": "Más información", + "GitHub account": "Cuenta de GitHub", + "Log in with GitHub to enable cloud package backup.": "Inicia sesión con GitHub para habilitar el respaldo de paquetes en la nube.", + "More details": "Más detalles", + "Log in": "Iniciar sesión", + "If you have cloud backup enabled, it will be saved as a GitHub Gist on this account": "Si tienes habilitado el respaldo en la nube, se guardará como un Gist de GitHub en esta cuenta", + "Log out": "Cerrar sesión", + "About UniGetUI": "Acerca de UniGetUI", + "About": "Acerca de", + "Third-party licenses": "Licencias de terceros", + "Contributors": "Colaboradores", + "Translators": "Traductores", + "Bundle security report": "Informe de seguridad del lote", + "The bundle contained restricted content": "El lote contenía contenido restringido", + "UniGetUI – Crash Report": "UniGetUI – Informe de errores", + "UniGetUI has crashed": "UniGetUI se cerró inesperadamente", + "Help us fix this by sending a crash report to Devolutions. All fields below are optional.": "Ayúdanos a solucionarlo enviando un informe de error a Devolutions. Todos los campos a continuación son opcionales.", + "Email (optional)": "Correo electrónico (opcional)", + "your@email.com": "tu@correo.com", + "Additional details (optional)": "Detalles adicionales (opcional)", + "Describe what you were doing when the crash occurred…": "Describe qué estabas haciendo cuando ocurrió el error…", + "Crash report": "Informe de error", + "Don't Send": "No enviar", + "Send Report": "Enviar informe", + "Sending…": "Enviando…", + "Unsaved changes": "Cambios sin guardar", + "You have unsaved changes in the current bundle. Do you want to discard them?": "Tienes cambios sin guardar en el lote actual. ¿Quieres descartarlos?", + "Discard changes": "Descartar cambios", + "Integrity violation": "Violación de integridad", + "UniGetUI or some of its components are missing or corrupt. It is strongly recommended to reinstall UniGetUI to adress the situation.": "UniGetUI o algunos de sus componentes faltan o están corruptos. Se recomienda encarecidamente reinstalar UniGetUI para solucionar la situación.", + "• Refer to the UniGetUI Logs to get more details regarding the affected file(s)": "• Consulta los registros de UniGetUI para obtener más detalles sobre el archivo o archivos afectados", + "• Integrity checks can be disabled from the Experimental Settings": "• Las comprobaciones de integridad se pueden deshabilitar en los Ajustes Experimentales", + "Manage shortcuts": "Administrar accesos directos", + "UniGetUI has detected the following desktop shortcuts which can be removed automatically on future upgrades": "UniGetUI ha detectado los siguientes accesos directos al escritorio que pueden eliminarse automáticamente en futuras actualizaciones", + "Do you really want to reset this list? This action cannot be reverted.": "¿Realmente quieres restablecer esta lista? Esta acción no se puede deshacer.", + "Desktop shortcuts list": "Lista de accesos directos al escritorio", + "Open in explorer": "Abrir en el explorador", + "Remove from list": "Eliminar de la lista", + "When new shortcuts are detected, delete them automatically instead of showing this dialog.": "Cuando se detecten nuevos accesos directos, elimínalos automáticamente en lugar de mostrar este diálogo.", + "Not right now": "Ahora no", + "Missing dependency": "Dependencia faltante", + "UniGetUI requires {0} to operate, but it was not found on your system.": "UniGetUI requiere {0} para funcionar, pero no se encontró en tu sistema.", + "Click on Install to begin the installation process. If you skip the installation, UniGetUI may not work as expected.": "Haz clic en Instalar para comenzar el proceso de instalación. Si omites la instalación, es posible que UniGetUI no funcione como se espera.", + "Alternatively, you can also install {0} by running the following command in a Windows PowerShell prompt:": "Alternativamente, también puedes instalar {0} ejecutando el siguiente comando en un símbolo del sistema de Windows PowerShell:", + "Install {0}": "Instalar {0}", + "Do not show this dialog again for {0}": "No volver a mostrar este diálogo para {0}", + "Please wait while {0} is being installed. A black window may show up. Please wait until it closes.": "Por favor, espera mientras se instala {0}. Puede que aparezca una ventana negra (o azul). Por favor, espera hasta que se cierre.", + "{0} has been installed successfully.": "{0} se ha instalado correctamente.", + "Please click on \"Continue\" to continue": "Por favor, haz clic en \"Continuar\" para seguir", + "Continue": "Continuar", + "{0} has been installed successfully. It is recommended to restart UniGetUI to finish the installation": "{0} se ha instalado correctamente. Se recomienda reiniciar UniGetUI para finalizar la instalación", + "Restart later": "Reiniciar más tarde", + "An error occurred:": "Ocurrió un error:", + "Please see the Command-line Output or refer to the Operation History for further information about the issue.": "Consulta la salida de la línea de comandos o el historial de operaciones para obtener más información sobre el problema.", + "Retry as administrator": "Reintentar como administrador", + "Retry interactively": "Reintentar interactivamente", + "Retry skipping integrity checks": "Reintentar omitiendo las comprobaciones de integridad", + "Installation options": "Opciones de instalación", + "Save": "Guardar", + "UniGetUI collects anonymous usage data with the sole purpose of understanding and improving the user experience.": "UniGetUI recopila datos de uso anónimos con el único propósito de comprender y mejorar la experiencia del usuario.", + "More details about the shared data and how it will be processed": "Más detalles sobre los datos compartidos y cómo serán procesados", + "Do you accept that UniGetUI collects and sends anonymous usage statistics, with the sole purpose of understanding and improving the user experience?": "¿Aceptas que UniGetUI recopile y envíe estadísticas de uso anónimas, con el único propósito de comprender y mejorar la experiencia del usuario?", + "Decline": "Rechazar", + "No personal information is collected nor sent, and the collected data is anonimized, so it can't be back-tracked to you.": "No se recopila ni se envía información personal, y los datos recopilados son anónimos, por lo que no pueden rastrearse hasta ti.", + "Navigation panel": "Panel de navegación", + "Operations": "Operaciones", + "Toggle operations panel": "Alternar panel de operaciones", + "Bulk operations": "Operaciones masivas", + "Retry failed": "Reintentar fallidos", + "Clear successful": "Limpiar exitosos", + "Clear finished": "Limpiar finalizados", + "Cancel all": "Cancelar todo", + "More": "Más", + "Toggle navigation panel": "Alternar panel de navegación", + "Minimize": "Minimizar", + "Maximize": "Maximizar", + "UniGetUI by Devolutions": "UniGetUI por Devolutions", + "UniGetUI is an application that makes managing your software easier, by providing an all-in-one graphical interface for your command-line package managers.": "UniGetUI es una aplicación que facilita la gestión de tu software, proporcionando una interfaz gráfica todo en uno para tus gestores de paquetes de línea de comandos.", + "Useful links": "Enlaces útiles", + "UniGetUI Homepage": "Página principal de UniGetUI", + "Report an issue or submit a feature request": "Informar de un problema o solicitar una funcionalidad", + "UniGetUI Repository": "Repositorio de UniGetUI", + "View GitHub Profile": "Ver perfil de GitHub", + "UniGetUI License": "Licencia de UniGetUI", + "Using UniGetUI implies the acceptation of the MIT License": "El uso de UniGetUI implica la aceptación de la Licencia MIT", + "Become a translator": "Convertirse en traductor", + "Go back": "Ir atrás", + "Go forward": "Ir adelante", + "Go to home page": "Ir a la página de inicio", + "Reload page": "Recargar página", + "View page on browser": "Ver página en el navegador", + "The built-in browser is not supported on Linux yet.": "El navegador integrado aún no es compatible con Linux.", + "Open in browser": "Abrir en el navegador", + "Copy to clipboard": "Copiar al portapapeles", + "Export to a file": "Exportar a un archivo", + "Log level:": "Nivel de registro:", + "Reload log": "Recargar registro", + "Export log": "Exportar registro", + "Text": "Texto", + "Change how operations request administrator rights": "Cambiar cómo las operaciones solicitan derechos de administrador", + "Restrictions on package operations": "Restricciones en las operaciones de paquetes", + "Restrictions on package managers": "Restricciones en los gestores de paquetes", + "Restrictions when importing package bundles": "Restricciones al importar lotes de paquetes", + "Ask for administrator privileges once for each batch of operations": "Solicitar privilegios de administrador una vez por cada lote de operaciones", + "Ask only once for administrator privileges": "Solicitar privilegios de administrador solo una vez", + "Prohibit any kind of Elevation via UniGetUI Elevator or GSudo": "Prohibir cualquier tipo de elevación a través de UniGetUI Elevator o GSudo", + "This option WILL cause issues. Any operation incapable of elevating itself WILL FAIL. Install/update/uninstall as administrator will NOT WORK.": "Esta opción CAUSARÁ problemas. Cualquier operación incapaz de elevarse a sí misma FALLARÁ. Instalar/actualizar/desinstalar como administrador NO FUNCIONARÁ.", + "Allow custom command-line arguments": "Permitir argumentos de línea de comandos personalizados", + "Custom command-line arguments can change the way in which programs are installed, upgraded or uninstalled, in a way UniGetUI cannot control. Using custom command-lines can break packages. Proceed with caution.": "Los argumentos de línea de comandos personalizados pueden cambiar la forma en que se instalan, actualizan o desinstalan los programas, de una manera que UniGetUI no puede controlar. El uso de líneas de comandos personalizadas puede romper los paquetes. Procede con precaución.", + "Ignore custom pre-install and post-install commands when importing packages from a bundle": "Ignorar comandos personalizados de preinstalación y postinstalación al importar paquetes de un lote", + "Pre and post install commands will be run before and after a package gets installed, upgraded or uninstalled. Be aware that they may break things unless used carefully": "Los comandos de pre y postinstalación se ejecutarán antes y después de que un paquete se instale, actualice o desinstale. Ten en cuenta que pueden romper cosas si no se usan con cuidado", + "Allow changing the paths for package manager executables": "Permitir cambiar las rutas de los ejecutables del gestor de paquetes", + "Turning this on enables changing the executable file used to interact with package managers. While this allows finer-grained customization of your install processes, it may also be dangerous": "Al activar esto, se permite cambiar el archivo ejecutable utilizado para interactuar con los gestores de paquetes. Aunque esto permite una personalización más detallada de tus procesos de instalación, también puede ser peligroso", + "Allow importing custom command-line arguments when importing packages from a bundle": "Permitir la importación de argumentos de línea de comandos personalizados al importar paquetes de un lote", + "Malformed command-line arguments can break packages, or even allow a malicious actor to gain privileged execution. Therefore, importing custom command-line arguments is disabled by default": "Los argumentos de línea de comandos mal formados pueden romper los paquetes, o incluso permitir que un actor malicioso obtenga una ejecución privilegiada. Por lo tanto, la importación de argumentos de línea de comandos personalizados está deshabilitada por defecto", + "Allow importing custom pre-install and post-install commands when importing packages from a bundle": "Permitir la importación de comandos personalizados de preinstalación y postinstalación al importar paquetes de un lote", + "Pre and post install commands can do very nasty things to your device, if designed to do so. It can be very dangerous to import the commands from a bundle, unless you trust the source of that package bundle": "Los comandos de pre y postinstalación pueden hacer cosas muy desagradables en tu dispositivo si están diseñados para ello. Puede ser muy peligroso importar comandos de un lote, a menos que confíes en la fuente de dicho lote de paquetes", + "Administrator rights and other dangerous settings": "Derechos de administrador y otros ajustes peligrosos", + "Package backup": "Respaldo de paquetes", + "Cloud package backup": "Respaldo de paquetes en la nube", + "Local package backup": "Respaldo de paquetes local", + "Local backup advanced options": "Opciones avanzadas de respaldo local", + "Log in with GitHub": "Iniciar sesión con GitHub", + "Log out from GitHub": "Cerrar sesión en GitHub", + "Periodically perform a cloud backup of the installed packages": "Realizar periódicamente un respaldo en la nube de los paquetes instalados", + "Cloud backup uses a private GitHub Gist to store a list of installed packages": "El respaldo en la nube utiliza un Gist privado de GitHub para almacenar una lista de los paquetes instalados", + "Perform a cloud backup now": "Realizar un respaldo en la nube ahora", + "Backup": "Respaldo", + "Restore a backup from the cloud": "Restaurar un respaldo de la nube", + "Begin the process to select a cloud backup and review which packages to restore": "Comenzar el proceso para seleccionar un respaldo en la nube y revisar qué paquetes restaurar", + "Periodically perform a local backup of the installed packages": "Realizar periódicamente un respaldo local de los paquetes instalados", + "Perform a local backup now": "Realizar un respaldo local ahora", + "Change backup output directory": "Cambiar el directorio de salida del respaldo", + "Set a custom backup file name": "Establecer un nombre de archivo de respaldo personalizado", + "Leave empty for default": "Dejar vacío para el predeterminado", + "Add a timestamp to the backup file names": "Añadir una marca de tiempo a los nombres de los archivos de respaldo", + "Backup and Restore": "Respaldo y restauración", + "Enable background api (UniGetUI Widgets and Sharing, port 7058)": "Habilitar API en segundo plano (Widgets de UniGetUI y Compartir, puerto 7058)", + "Wait for the device to be connected to the internet before attempting to do tasks that require internet connectivity.": "Esperar a que el dispositivo esté conectado a internet antes de intentar realizar tareas que requieran conectividad a internet.", + "Disable the 1-minute timeout for package-related operations": "Deshabilitar el tiempo de espera de 1 minuto para las operaciones relacionadas con paquetes", + "Use installed GSudo instead of UniGetUI Elevator": "Usar GSudo instalado en lugar de UniGetUI Elevator", + "Use a custom icon and screenshot database URL": "Usar una URL personalizada para la base de datos de iconos y capturas de pantalla", + "Enable background CPU Usage optimizations (see Pull Request #3278)": "Habilitar optimizaciones de uso de CPU en segundo plano (ver Pull Request #3278)", + "Perform integrity checks at startup": "Realizar comprobaciones de integridad al iniciar", + "When batch installing packages from a bundle, install also packages that are already installed": "Al instalar paquetes en lote desde un lote, instalar también los paquetes que ya estén instalados", + "Experimental settings and developer options": "Ajustes experimentales y opciones de desarrollador", + "Show UniGetUI's version and build number on the titlebar.": "Mostrar la versión de UniGetUI en la barra de título", + "Language": "Idioma", + "UniGetUI updater": "Actualizador de UniGetUI", + "Telemetry": "Telemetría", + "Manage UniGetUI settings": "Administrar la configuración de UniGetUI", + "Related settings": "Ajustes relacionados", + "Update UniGetUI automatically": "Actualizar UniGetUI automáticamente", + "Check for updates": "Buscar actualizaciones", + "Install prerelease versions of UniGetUI": "Instalar versiones preliminares de UniGetUI", + "Manage telemetry settings": "Administrar ajustes de telemetría", + "Manage": "Administrar", + "Import settings from a local file": "Importar configuración desde un archivo local", + "Import": "Importar", + "Export settings to a local file": "Exportar configuración a un archivo local", + "Export": "Exportar", + "Reset UniGetUI": "Restablecer UniGetUI", + "User interface preferences": "Preferencias de la interfaz de usuario", + "Application theme, startup page, package icons, clear successful installs automatically": "Tema de la aplicación, página de inicio, iconos de paquetes, limpiar instalaciones exitosas automáticamente", + "General preferences": "Preferencias generales", + "UniGetUI display language:": "Idioma de visualización de UniGetUI:", + "System language": "Idioma del sistema", + "Is your language missing or incomplete?": "¿Falta tu idioma o está incompleto?", + "Appearance": "Apariencia", + "UniGetUI on the background and system tray": "UniGetUI en segundo plano y en la bandeja del sistema", + "Package lists": "Listas de paquetes", + "Use classic mode": "Usar modo clásico", + "Restart UniGetUI to apply this change": "Reinicia UniGetUI para aplicar este cambio", + "The classic UI is disabled for beta testers": "La interfaz clásica está deshabilitada para los probadores beta", + "Close UniGetUI to the system tray": "Cerrar UniGetUI en la bandeja del sistema", + "Manage UniGetUI autostart behaviour": "Administrar el comportamiento de inicio automático de UniGetUI", + "Show package icons on package lists": "Mostrar iconos de paquetes en las listas de paquetes", + "Clear cache": "Limpiar caché", + "Select upgradable packages by default": "Seleccionar paquetes actualizables por defecto", + "Light": "Claro", + "Dark": "Oscuro", + "Follow system color scheme": "Seguir el esquema de colores del sistema", + "Application theme:": "Tema de la aplicación:", + "UniGetUI startup page:": "Página de inicio de UniGetUI:", + "Proxy settings": "Ajustes de proxy", + "Other settings": "Otros ajustes", + "Connect the internet using a custom proxy": "Conectarse a internet usando un proxy personalizado", + "Please note that not all package managers may fully support this feature": "Ten en cuenta que es posible que no todos los gestores de paquetes admitan completamente esta función", + "Proxy URL": "URL del proxy", + "Enter proxy URL here": "Introduce la URL del proxy aquí", + "Authenticate to the proxy with a user and a password": "Autenticarse en el proxy con un usuario y una contraseña", + "Internet and proxy settings": "Ajustes de internet y proxy", + "Package manager preferences": "Preferencias del gestor de paquetes", + "Ready": "Listo", + "Not found": "No encontrado", + "Notification preferences": "Preferencias de notificación", + "Notification types": "Tipos de notificación", + "The system tray icon must be enabled in order for notifications to work": "El icono de la bandeja del sistema debe estar habilitado para que las notificaciones funcionen", + "Enable UniGetUI notifications": "Habilitar notificaciones de UniGetUI", + "Show a notification when there are available updates": "Mostrar una notificación cuando haya actualizaciones disponibles", + "Show a silent notification when an operation is running": "Mostrar una notificación silenciosa cuando una operación esté en curso", + "Show a notification when an operation fails": "Mostrar una notificación cuando una operación falle", + "Show a notification when an operation finishes successfully": "Mostrar una notificación cuando una operación finalice con éxito", + "Concurrency and execution": "Concurrencia y ejecución", + "Automatic desktop shortcut remover": "Eliminador automático de accesos directos al escritorio", + "Choose how many operations should be performed in parallel": "Elige cuántas operaciones deben realizarse en paralelo", + "Clear successful operations from the operation list after a 5 second delay": "Limpiar las operaciones exitosas de la lista de operaciones tras un retraso de 5 segundos", + "Download operations are not affected by this setting": "Las operaciones de descarga no se ven afectadas por este ajuste", + "You may lose unsaved data": "Puedes perder datos no guardados", + "Ask to delete desktop shortcuts created during an install or upgrade.": "Preguntar si se deben eliminar los accesos directos al escritorio creados durante una instalación o actualización.", + "Package update preferences": "Preferencias de actualización de paquetes", + "Update check frequency, automatically install updates, etc.": "Frecuencia de comprobación de actualizaciones, instalar actualizaciones automáticamente, etc.", + "Reduce UAC prompts, elevate installations by default, unlock certain dangerous features, etc.": "Reducir avisos de UAC, elevar instalaciones por defecto, desbloquear ciertas funciones peligrosas, etc.", + "Package operation preferences": "Preferencias de operación de paquetes", + "Enable {pm}": "Habilitar {pm}", + "Not finding the file you are looking for? Make sure it has been added to path.": "¿No encuentras el archivo que buscas? Asegúrate de que haya sido agregado al PATH.", + "Select the executable to be used. The following list shows the executables found by UniGetUI": "Selecciona el ejecutable que se utilizará. La siguiente lista muestra los ejecutables encontrados por UniGetUI", + "For security reasons, changing the executable file is disabled by default": "Por razones de seguridad, el cambio del archivo ejecutable está deshabilitado por defecto", + "Change this": "Cambiar esto", + "Copy path": "Copiar ruta", + "Current executable file:": "Archivo ejecutable actual:", + "Ignore packages from {pm} when showing a notification about updates": "Ignorar paquetes de {pm} al mostrar una notificación sobre actualizaciones", + "Update security": "Seguridad de actualización", + "Use global setting": "Usar ajuste global", + "Minimum age for updates": "Antigüedad mínima para actualizaciones", + "e.g. 10": "ej. 10", + "Custom minimum age (days)": "Antigüedad mínima personalizada (días)", + "{pm} does not provide release dates for its packages, so this setting will have no effect": "{pm} no proporciona fechas de lanzamiento para sus paquetes, por lo que este ajuste no tendrá efecto", + "{pm} only provides release dates for some of its packages, so this setting will only apply to those packages": "{pm} solo proporciona fechas de lanzamiento para algunos de sus paquetes, por lo que este ajuste solo se aplicará a esos paquetes", + "Override the global minimum update age for this package manager": "Anular la antigüedad mínima de actualización global para este gestor de paquetes", + "View {0} logs": "Ver registros de {0}", + "If Python cannot be found or is not listing packages but is installed on the system, ": "Si no se encuentra Python o no enumera los paquetes pero está instalado en el sistema, ", + "Advanced options": "Opciones avanzadas", + "WinGet command-line tool": "Herramienta de línea de comandos de WinGet", + "Choose which command-line tool UniGetUI uses for WinGet operations when the COM API is not used": "Elige qué herramienta de línea de comandos utiliza UniGetUI para las operaciones de WinGet cuando no se utiliza la API COM", + "WinGet COM API": "API COM de WinGet", + "Choose whether UniGetUI can use the WinGet COM API before falling back to the command-line tool": "Elige si UniGetUI puede usar la API COM de WinGet antes de recurrir a la herramienta de línea de comandos", + "Reset WinGet": "Restablecer WinGet", + "This may help if no packages are listed": "Esto puede ayudar si no se enumeran paquetes", + "Force install location parameter when updating packages with custom locations": "Forzar el parámetro de ubicación de instalación al actualizar paquetes con ubicaciones personalizadas", + "Install Scoop": "Instalar Scoop", + "Uninstall Scoop (and its packages)": "Desinstalar Scoop (y sus paquetes)", + "Run cleanup and clear cache": "Ejecutar limpieza y borrar caché", + "Run": "Ejecutar", + "Enable Scoop cleanup on launch": "Habilitar la limpieza de Scoop al iniciar", + "Default vcpkg triplet": "Triplet de vcpkg predeterminado", + "Change vcpkg root location": "Cambiar la ubicación raíz de vcpkg", + "Reset vcpkg root location": "Restablecer la ubicación raíz de vcpkg", + "Open vcpkg root location": "Abrir la ubicación raíz de vcpkg", + "Language, theme and other miscellaneous preferences": "Idioma, tema y otras preferencias misceláneas", + "Show notifications on different events": "Mostrar notificaciones en diferentes eventos", + "Change how UniGetUI checks and installs available updates for your packages": "Cambia la forma en que UniGetUI busca e instala las actualizaciones disponibles para tus paquetes", + "Automatically save a list of all your installed packages to easily restore them.": "Guarda automáticamente una lista de todos tus paquetes instalados para restaurarlos fácilmente.", + "Enable and disable package managers, change default install options, etc.": "Habilitar y deshabilitar gestores de paquetes, cambiar opciones de instalación predeterminadas, etc.", + "Internet connection settings": "Ajustes de conexión a internet", + "Proxy settings, etc.": "Ajustes de proxy, etc.", + "Beta features and other options that shouldn't be touched": "Funciones beta y otras opciones que no deberían tocarse", + "Reload sources": "Recargar fuentes", + "Delete source": "Eliminar fuente", + "Known sources": "Fuentes conocidas", + "Update checking": "Comprobación de actualizaciones", + "Automatic updates": "Actualizaciones automáticas", + "Check for package updates periodically": "Buscar actualizaciones de paquetes periódicamente", + "Check for updates every:": "Buscar actualizaciones cada:", + "Install available updates automatically": "Instalar actualizaciones disponibles automáticamente", + "Do not automatically install updates when the network connection is metered": "No instalar actualizaciones automáticamente cuando la conexión de red sea limitada", + "Do not automatically install updates when the device runs on battery": "No instalar actualizaciones automáticamente cuando el dispositivo funcione con batería", + "Do not automatically install updates when the battery saver is on": "No instalar actualizaciones automáticamente cuando el ahorrador de batería esté activado", + "Only show updates that are at least the specified number of days old": "Mostrar solo actualizaciones que tengan al menos el número de días especificado", + "Warn me when the installer URL host changes between the installed version and the new version (WinGet only)": "Avisarme cuando el host de la URL del instalador cambie entre la versión instalada y la nueva versión (solo WinGet)", + "Change how UniGetUI handles install, update and uninstall operations.": "Cambia la forma en que UniGetUI gestiona las operaciones de instalación, actualización y desinstalación.", + "Navigation": "Navegación", + "Check for UniGetUI updates": "Buscar actualizaciones de UniGetUI", + "Quit UniGetUI": "Salir de UniGetUI", + "Filters": "Filtros", + "Sources": "Fuentes", + "Search for packages to start": "Busca paquetes para comenzar", + "Select all": "Seleccionar todo", + "Clear selection": "Limpiar selección", + "Instant search": "Búsqueda instantánea", + "Distinguish between uppercase and lowercase": "Distinguir entre mayúsculas y minúsculas", + "Ignore special characters": "Ignorar caracteres especiales", + "Search mode": "Modo de búsqueda", + "Both": "Ambos", + "Exact match": "Coincidencia exacta", + "Show similar packages": "Mostrar paquetes similares", + "Loading": "Cargando", + "Package": "Paquete", + "More options": "Más opciones", + "Order by:": "Ordenar por:", + "Name": "Nombre", + "Id": "ID", + "Ascendant": "Ascendente", + "Descendant": "Descendente", + "View modes": "Modos de vista", + "Reload": "Recargar", + "Closed": "Cerrado", + "Ascending": "Ascendente", + "Descending": "Descendente", + "{0}: {1}, {2}": "{0}: {1}, {2}", + "Order by": "Ordenar por", + "No results were found matching the input criteria": "No se encontraron resultados que coincidan con los criterios de entrada", + "No packages were found": "No se encontraron paquetes", + "Loading packages": "Cargando paquetes", + "Skip integrity checks": "Omitir comprobaciones de integridad", + "Download selected installers": "Descargar instaladores seleccionados", + "Install selection": "Instalar selección", + "Install options": "Opciones de instalación", + "Add selection to bundle": "Agregar selección al lote", + "Download installer": "Descargar instalador", + "Uninstall selection": "Desinstalar selección", + "Uninstall options": "Opciones de desinstalación", + "Ignore selected packages": "Ignorar paquetes seleccionados", + "Open install location": "Abrir ubicación de instalación", + "Reinstall package": "Reinstalar paquete", + "Uninstall package, then reinstall it": "Desinstalar paquete y luego reinstalarlo", + "Ignore updates for this package": "Ignorar actualizaciones para este paquete", + "WinGet malfunction detected": "Se detectó un mal funcionamiento de WinGet", + "It looks like WinGet is not working properly. Do you want to attempt to repair WinGet?": "Parece que WinGet no está funcionando correctamente. ¿Quieres intentar reparar WinGet?", + "Repair WinGet": "Reparar WinGet", + "Updates will no longer be ignored for {0}": "Las actualizaciones ya no se ignorarán para {0}", + "Updates are now ignored for {0}": "Las actualizaciones ahora se ignoran para {0}", + "Do not ignore updates for this package anymore": "No ignorar más las actualizaciones para este paquete", + "Add packages or open an existing package bundle": "Agregar paquetes o abrir un lote de paquetes existente", + "Add packages to start": "Agrega paquetes para comenzar", + "The current bundle has no packages. Add some packages to get started": "El lote actual no tiene paquetes. Agrega algunos paquetes para empezar", + "New": "Nuevo", + "Save as": "Guardar como", + "Create .ps1 script": "Crear script .ps1", + "Remove selection from bundle": "Eliminar selección del lote", + "Skip hash checks": "Omitir comprobaciones de hash", + "The package bundle is not valid": "El lote de paquetes no es válido", + "The bundle you are trying to load appears to be invalid. Please check the file and try again.": "El lote que intentas cargar parece ser inválido. Por favor, revisa el archivo e inténtalo de nuevo.", + "Package bundle": "Lote de paquetes", + "Could not create bundle": "No se pudo crear el lote", + "The package bundle could not be created due to an error.": "El lote de paquetes no se pudo crear debido a un error.", + "Install script": "Script de instalación", + "PowerShell script": "Script de PowerShell", + "The installation script saved to {0}": "El script de instalación se guardó en {0}", + "An error occurred": "Ocurrió un error", + "An error occurred while attempting to create an installation script:": "Ocurrió un error al intentar crear un script de instalación:", + "Hooray! No updates were found.": "¡Hurra! No se encontraron actualizaciones.", + "Uninstall selected packages": "Desinstalar paquetes seleccionados", + "Update selection": "Actualizar selección", + "Update options": "Opciones de actualización", + "Uninstall package, then update it": "Desinstalar paquete y luego actualizarlo", + "Uninstall package": "Desinstalar paquete", + "Skip this version": "Omitir esta versión", + "Pause updates for": "Pausar actualizaciones por", + "User | Local": "Usuario | Local", + "Machine | Global": "Máquina | Global", + "The default package manager for Debian/Ubuntu-based Linux distributions.
Contains: Debian/Ubuntu packages": "El gestor de paquetes predeterminado para distribuciones de Linux basadas en Debian/Ubuntu.
Contiene: paquetes de Debian/Ubuntu", + "The Rust package manager.
Contains: Rust libraries and programs written in Rust": "El gestor de paquetes de Rust.
Contiene: librerías de Rust y programas escritos en Rust", + "The classical package manager for windows. You'll find everything there.
Contains: General Software": "El gestor de paquetes clásico para Windows. Encontrarás de todo allí.
Contiene: Software general", + "The default package manager for RHEL/Fedora-based Linux distributions.
Contains: RPM packages": "El gestor de paquetes predeterminado para distribuciones de Linux basadas en RHEL/Fedora.
Contiene: paquetes RPM", + "A repository full of tools and executables designed with Microsoft's .NET ecosystem in mind.
Contains: .NET related tools and scripts": "Un repositorio lleno de herramientas y ejecutables diseñados pensando en el ecosistema .NET de Microsoft.
Contiene: herramientas y scripts relacionados con .NET", + "The universal Linux package manager for desktop applications.
Contains: Flatpak applications from configured remotes": "El gestor de paquetes universal de Linux para aplicaciones de escritorio.
Contiene: aplicaciones Flatpak de remotos configurados", + "NuPkg (zipped manifest)": "NuPkg (manifiesto comprimido)", + "The Missing Package Manager for macOS (or Linux).
Contains: Formulae, Casks": "El gestor de paquetes que faltaba para macOS (o Linux).
Contiene: Formulae, Casks", + "Node JS's package manager. Full of libraries and other utilities that orbit the javascript world
Contains: Node javascript libraries and other related utilities": "El gestor de paquetes de Node JS. Lleno de librerías y otras utilidades del mundo de Javascript
Contiene: librerías de Node javascript y otras utilidades relacionadas", + "The default package manager for Arch Linux and its derivatives.
Contains: Arch Linux packages": "El gestor de paquetes predeterminado para Arch Linux y sus derivados.
Contiene: paquetes de Arch Linux", + "Python's library manager. Full of python libraries and other python-related utilities
Contains: Python libraries and related utilities": "El gestor de librerías de Python. Lleno de librerías de python y otras utilidades relacionadas con python
Contiene: librerías de Python y utilidades relacionadas", + "PowerShell's package manager. Find libraries and scripts to expand PowerShell capabilities
Contains: Modules, Scripts, Cmdlets": "El gestor de paquetes de PowerShell. Encuentra librerías y scripts para expandir las capacidades de PowerShell
Contiene: Módulos, Scripts, Cmdlets", + "extracted": "extraído", + "Scoop package": "paquete de Scoop", + "Great repository of unknown but useful utilities and other interesting packages.
Contains: Utilities, Command-line programs, General Software (extras bucket required)": "Gran repositorio de utilidades desconocidas pero útiles y otros paquetes interesantes.
Contiene: Utilidades, programas de línea de comandos, software general (requiere el bucket extras)", + "The universal Linux package manager by Canonical.
Contains: Snap packages from the Snapcraft store": "El gestor de paquetes universal de Linux de Canonical.
Contiene: paquetes Snap de la tienda Snapcraft", + "library": "librería", + "feature": "funcionalidad", + "A popular C/C++ library manager. Full of C/C++ libraries and other C/C++-related utilities
Contains: C/C++ libraries and related utilities": "Un popular gestor de librerías de C/C++. Lleno de librerías de C/C++ y otras utilidades relacionadas con C/C++
Contiene: librerías de C/C++ y utilidades relacionadas", + "option": "opción", + "This package cannot be installed from an elevated context.": "Este paquete no puede instalarse desde un contexto elevado.", + "Please run UniGetUI as a regular user and try again.": "Por favor, ejecuta UniGetUI como un usuario normal e inténtalo de nuevo.", + "Please check the installation options for this package and try again": "Por favor, revisa las opciones de instalación de este paquete e inténtalo de nuevo", + "Microsoft's official package manager. Full of well-known and verified packages
Contains: General Software, Microsoft Store apps": "El gestor de paquetes oficial de Microsoft. Lleno de paquetes conocidos y verificados
Contiene: Software general, aplicaciones de Microsoft Store", + "Local PC": "PC Local", + "Android Subsystem": "Subsistema de Android", + "Operation on queue (position {0})...": "Operación en cola (posición {0})...", + "Click here for more details": "Haz clic aquí para más detalles", + "Operation canceled by user": "Operación cancelada por el usuario", + "Running PreOperation ({0}/{1})...": "Ejecutando PreOperación ({0}/{1})...", + "PreOperation {0} out of {1} failed, and was tagged as necessary. Aborting...": "La PreOperación {0} de {1} falló y estaba marcada como necesaria. Abortando...", + "PreOperation {0} out of {1} finished with result {2}": "La PreOperación {0} de {1} finalizó con el resultado {2}", + "Starting operation...": "Iniciando operación...", + "Running PostOperation ({0}/{1})...": "Ejecutando PostOperación ({0}/{1})...", + "PostOperation {0} out of {1} failed, and was tagged as necessary. Aborting...": "La PostOperación {0} de {1} falló y estaba marcada como necesaria. Abortando...", + "PostOperation {0} out of {1} finished with result {2}": "La PostOperación {0} de {1} finalizó con el resultado {2}", + "{package} installer download": "Descarga del instalador de {package}", + "{0} installer is being downloaded": "Se está descargando el instalador de {0}", + "Download succeeded": "Descarga exitosa", + "{package} installer was downloaded successfully": "El instalador de {package} se descargó correctamente", + "Download failed": "Descarga fallida", + "{package} installer could not be downloaded": "No se pudo descargar el instalador de {package}", + "{package} Installation": "Instalación de {package}", + "{0} is being installed": "{0} se está instalando", + "Installation succeeded": "Instalación exitosa", + "{package} was installed successfully": "{package} se instaló correctamente", + "Installation failed": "Instalación fallida", + "{package} could not be installed": "No se pudo instalar {package}", + "{package} Update": "Actualización de {package}", + "Update succeeded": "Actualización exitosa", + "{package} was updated successfully": "{package} se actualizó correctamente", + "Update failed": "Actualización fallida", + "{package} could not be updated": "No se pudo actualizar {package}", + "{package} Uninstall": "Desinstalación de {package}", + "{0} is being uninstalled": "{0} se está desinstalando", + "Uninstall succeeded": "Desinstalación exitosa", + "{package} was uninstalled successfully": "{package} se desinstaló correctamente", + "Uninstall failed": "Desinstalación fallida", + "{package} could not be uninstalled": "No se pudo desinstalar {package}", + "Adding source {source}": "Agregando fuente {source}", + "Adding source {source} to {manager}": "Agregando fuente {source} a {manager}", + "Source added successfully": "Fuente agregada correctamente", + "The source {source} was added to {manager} successfully": "La fuente {source} se agregó a {manager} correctamente", + "Could not add source": "No se pudo agregar la fuente", + "Could not add source {source} to {manager}": "No se pudo agregar la fuente {source} a {manager}", + "Removing source {source}": "Eliminando fuente {source}", + "Removing source {source} from {manager}": "Eliminando fuente {source} de {manager}", + "Source removed successfully": "Fuente eliminada correctamente", + "The source {source} was removed from {manager} successfully": "La fuente {source} se eliminó de {manager} correctamente", + "Could not remove source": "No se pudo eliminar la fuente", + "Could not remove source {source} from {manager}": "No se pudo eliminar la fuente {source} de {manager}", + "The package manager \"{0}\" was not found": "No se encontró el gestor de paquetes \"{0}\"", + "The package manager \"{0}\" is disabled": "El gestor de paquetes \"{0}\" está deshabilitado", + "There is an error with the configuration of the package manager \"{0}\"": "Hay un error con la configuración del gestor de paquetes \"{0}\"", + "The package \"{0}\" was not found on the package manager \"{1}\"": "No se encontró el paquete \"{0}\" en el gestor de paquetes \"{1}\"", + "{0} is disabled": "{0} está deshabilitado", + "{0} weeks": "{0} semanas", + "1 month": "1 mes", + "{0} months": "{0} meses", + "Something went wrong": "Algo salió mal", + "An interal error occurred. Please view the log for further details.": "Ocurrió un error interno. Por favor, consulta el registro para más detalles.", + "No applicable installer was found for the package {0}": "No se encontró ningún instalador aplicable para el paquete {0}", + "Integrity checks will not be performed during this operation": "No se realizarán comprobaciones de integridad durante esta operación", + "This is not recommended.": "Esto no es recomendable.", + "Run now": "Ejecutar ahora", + "Run next": "Ejecutar siguiente", + "Run last": "Ejecutar último", + "Show in explorer": "Mostrar en el explorador", + "Checked": "Marcado", + "Unchecked": "Desmarcado", + "This package is already installed": "Este paquete ya está instalado", + "This package can be upgraded to version {0}": "Este paquete puede actualizarse a la versión {0}", + "Updates for this package are ignored": "Las actualizaciones de este paquete se ignoran", + "This package is being processed": "Este paquete se está procesando", + "This package is not available": "Este paquete no está disponible", + "Select the source you want to add:": "Selecciona la fuente que quieres agregar:", + "Source name:": "Nombre de la fuente:", + "Source URL:": "URL de la fuente:", + "An error occurred when adding the source: ": "Ocurrió un error al agregar la fuente: ", + "Package management made easy": "Gestión de paquetes simplificada", + "version {0}": "versión {0}", + "[RAN AS ADMINISTRATOR]": "[EJECUTADO COMO ADMINISTRADOR]", + "Portable mode": "Modo portátil\n", + "DEBUG BUILD": "VERSIÓN DE DEPURACIÓN", + "Here you can change UniGetUI's behaviour regarding the following shortcuts. Checking a shortcut will make UniGetUI delete it if if gets created on a future upgrade. Unchecking it will keep the shortcut intact": "Aquí puedes cambiar el comportamiento de UniGetUI respecto a los siguientes accesos directos. Marcar un acceso directo hará que UniGetUI lo elimine si se crea en una futura actualización. Desmarcarlo mantendrá el acceso directo intacto", + "Manual scan": "Escaneo manual", + "Existing shortcuts on your desktop will be scanned, and you will need to pick which ones to keep and which ones to remove.": "Se escanearán los accesos directos existentes en tu escritorio y tendrás que elegir cuáles mantener y cuáles eliminar.", + "Delete?": "¿Eliminar?", + "I understand": "Entiendo", + "Chocolatey setup changed": "La configuración de Chocolatey ha cambiado", + "UniGetUI no longer includes its own private Chocolatey installation. A legacy UniGetUI-managed Chocolatey installation was detected for this user profile, but system Chocolatey was not found. Chocolatey will stay unavailable in UniGetUI until Chocolatey is installed on the system and UniGetUI is restarted. Applications previously installed through UniGetUI's bundled Chocolatey may still appear under other sources such as Local PC or WinGet.": "UniGetUI ya no incluye su propia instalación privada de Chocolatey. Se detectó una instalación de Chocolatey heredada gestionada por UniGetUI para este perfil de usuario, pero no se encontró Chocolatey en el sistema. Chocolatey seguirá no estando disponible en UniGetUI hasta que Chocolatey se instale en el sistema y se reinicie UniGetUI. Las aplicaciones instaladas previamente a través del Chocolatey incluido en UniGetUI pueden seguir apareciendo en otras fuentes como PC Local o WinGet.", + "NOTE: This troubleshooter can be disabled from UniGetUI Settings, on the WinGet section": "NOTA: Este solucionador de problemas se puede deshabilitar en la Configuración de UniGetUI, en la sección de WinGet", + "Restart": "Reiniciar", + "Are you sure you want to delete all shortcuts?": "¿Estás seguro de que quieres eliminar todos los accesos directos?", + "Any new shorcuts created during an install or an update operation will be deleted automatically, instead of showing a confirmation prompt the first time they are detected.": "Cualquier nuevo acceso directo creado durante una instalación o actualización se eliminará automáticamente, en lugar de mostrar un aviso de confirmación la primera vez que se detecten.", + "Any shorcuts created or modified outside of UniGetUI will be ignored. You will be able to add them via the {0} button.": "Cualquier acceso directo creado o modificado fuera de UniGetUI será ignorado. Podrás agregarlos a través del botón {0}.", + "Are you really sure you want to enable this feature?": "¿Realmente estás seguro de que quieres habilitar esta función?", + "No new shortcuts were found during the scan.": "No se encontraron nuevos accesos directos durante el escaneo.", + "How to add packages to a bundle": "Cómo agregar paquetes a un lote", + "In order to add packages to a bundle, you will need to: ": "Para agregar paquetes a un lote, deberás:", + "1. Navigate to the \"{0}\" or \"{1}\" page.": "1. Navegar a la página \"{0}\" o \"{1}\".", + "2. Locate the package(s) you want to add to the bundle, and select their leftmost checkbox.": "2. Localizar el paquete o paquetes que quieras agregar al lote y seleccionar la casilla de verificación situada más a la izquierda.", + "3. When the packages you want to add to the bundle are selected, find and click the option \"{0}\" on the toolbar.": "3. Cuando los paquetes que quieras agregar al lote estén seleccionados, busca y haz clic en la opción \"{0}\" de la barra de herramientas.", + "4. Your packages will have been added to the bundle. You can continue adding packages, or export the bundle.": "4. Tus paquetes habrán sido agregados al lote. Puedes continuar agregando paquetes o exportar el lote.", + "Which backup do you want to open?": "¿Qué respaldo quieres abrir?", + "Select the backup you want to open. Later, you will be able to review which packages you want to install.": "Selecciona el respaldo que quieras abrir. Más adelante, podrás revisar qué paquetes/programas quieres restaurar.", + "There are ongoing operations. Quitting UniGetUI may cause them to fail. Do you want to continue?": "Hay operaciones en curso. Salir de UniGetUI puede hacer que fallen. ¿Quieres continuar?", + "UniGetUI or some of its components are missing or corrupt.": "UniGetUI o algunos de sus componentes faltan o están corruptos.", + "It is strongly recommended to reinstall UniGetUI to adress the situation.": "Se recomienda encarecidamente reinstalar UniGetUI para solucionar la situación.", + "Refer to the UniGetUI Logs to get more details regarding the affected file(s)": "Consulta los registros de UniGetUI para obtener más detalles sobre el archivo o archivos afectados", + "Integrity checks can be disabled from the Experimental Settings": "Las comprobaciones de integridad se pueden deshabilitar en los Ajustes Experimentales", + "Repair UniGetUI": "Reparar UniGetUI", + "Live output": "Salida en vivo", + "This package bundle had some settings that are potentially dangerous, and may be ignored by default.": "Este lote de paquetes tenía algunos ajustes potencialmente peligrosos y pueden ser ignorados por defecto.", + "Entries that show in YELLOW will be IGNORED.": "Las entradas que aparezcan en AMARILLO serán IGNORADAS.", + "Entries that show in RED will be IMPORTED.": "Las entradas que aparezcan en ROJO serán IMPORTADAS.", + "You can change this behavior on UniGetUI security settings.": "Puedes cambiar este comportamiento en los ajustes de seguridad de UniGetUI.", + "Open UniGetUI security settings": "Abrir ajustes de seguridad de UniGetUI", + "Should you modify the security settings, you will need to open the bundle again for the changes to take effect.": "Si modificas los ajustes de seguridad, tendrás que abrir el lote de nuevo para que los cambios surtan efecto.", + "Details of the report:": "Detalles del informe:", + "Are you sure you want to create a new package bundle? ": "¿Estás seguro de que quieres crear un nuevo lote de paquetes? ", + "Any unsaved changes will be lost": "Cualquier cambio no guardado se perderá", + "Warning!": "¡Advertencia!", + "For security reasons, custom command-line arguments are disabled by default. Go to UniGetUI security settings to change this. ": "Por razones de seguridad, los argumentos de línea de comandos personalizados están deshabilitados por defecto. Ve a los ajustes de seguridad de UniGetUI para cambiar esto. ", + "Change default options": "Cambiar opciones predeterminadas", + "Ignore future updates for this package": "Ignorar futuras actualizaciones para este paquete", + "For security reasons, pre-operation and post-operation scripts are disabled by default. Go to UniGetUI security settings to change this. ": "Por razones de seguridad, los scripts de preoperación y postoperación están deshabilitados por defecto. Ve a los ajustes de seguridad de UniGetUI para cambiar esto. ", + "You can define the commands that will be run before or after this package is installed, updated or uninstalled. They will be run on a command prompt, so CMD scripts will work here.": "Puedes definir los comandos que se ejecutarán antes o después de que este paquete se instale, actualice o desinstale. Se ejecutarán en un símbolo del sistema, por lo que los scripts de CMD funcionarán aquí.", + "Change this and unlock": "Cambiar esto y desbloquear", + "{0} Install options are currently locked because {0} follows the default install options.": "Las opciones de instalación de {0} están bloqueadas actualmente porque {0} sigue las opciones de instalación predeterminadas.", + "Unset or unknown": "No establecido o desconocido", + "This package has no screenshots or is missing the icon? Contrbute to UniGetUI by adding the missing icons and screenshots to our open, public database.": "¿Este paquete no tiene capturas de pantalla o le falta el icono? Contribuye a UniGetUI agregando los iconos y capturas faltantes a nuestra base de datos pública y abierta.", + "Become a contributor": "Convertirse en colaborador", + "Update to {0} available": "Actualización a {0} disponible", + "Reinstall": "Reinstalar", + "Installer not available": "Instalador no disponible", + "Version:": "Versión:", + "UniGetUI Version {0}": "UniGetUI Versión {0}", + "Performing backup, please wait...": "Realizando respaldo, por favor espera...", + "An error occurred while logging in: ": "Ocurrió un error al iniciar sesión: ", + "Fetching available backups...": "Obteniendo respaldos disponibles...", + "Done!": "¡Hecho!", + "The cloud backup has been loaded successfully.": "El respaldo en la nube se ha cargado correctamente.", + "An error occurred while loading a backup: ": "Ocurrió un error al cargar un respaldo: ", + "Backing up packages to GitHub Gist...": "Respaldando paquetes en GitHub Gist...", + "Backup Successful": "Respaldo exitoso", + "The cloud backup completed successfully.": "El respaldo en la nube se completó correctamente.", + "Could not back up packages to GitHub Gist: ": "No se pudieron respaldar los paquetes en GitHub Gist: ", + "It is not guaranteed that the provided credentials will be stored safely, so you may as well not use the credentials of your bank account": "No se garantiza que las credenciales proporcionadas se almacenen de forma segura, por lo que es mejor no usar las credenciales de tu cuenta bancaria", + "Enable the automatic WinGet troubleshooter": "Habilitar el solucionador de problemas automático de WinGet", + "Add updates that fail with a 'no applicable update found' to the ignored updates list": "Agregar a la lista de actualizaciones ignoradas aquellas que fallen con el mensaje 'no se encontró ninguna actualización aplicable'.", + "Invalid selection": "Selección inválida", + "No package was selected": "No se seleccionó ningún paquete", + "More than 1 package was selected": "Se seleccionó más de 1 paquete", + "List": "Lista", + "Grid": "Cuadrícula", + "Icons": "Iconos", + "\"{0}\" is a local package and does not have available details": "\"{0}\" es un paquete local y no tiene detalles disponibles", + "\"{0}\" is a local package and is not compatible with this feature": "\"{0}\" es un paquete local y no es compatible con esta función", + "Add packages to bundle": "Agregar paquetes al lote", + "Preparing packages, please wait...": "Preparando paquetes, por favor espera...", + "Loading packages, please wait...": "Cargando paquetes, por favor espera...", + "Saving packages, please wait...": "Guardando paquetes, por favor espera...", + "The bundle was created successfully on {0}": "El lote se creó correctamente el {0}", + "User profile": "Perfil de usuario", + "Error": "Error", + "Log in failed: ": "Error al iniciar sesión: ", + "Log out failed: ": "Error al cerrar sesión: ", + "Package backup settings": "Ajustes de respaldo de paquetes", + "Show the release notes after UniGetUI is updated": "Mostrar las notas de la versión después de actualizar UniGetUI" +} diff --git a/src/Languages/lang_es.json b/src/Languages/lang_es.json new file mode 100644 index 0000000..ee69db7 --- /dev/null +++ b/src/Languages/lang_es.json @@ -0,0 +1,846 @@ +{ + "{0} of {1} operations completed": "{0} de {1} operaciones completadas", + "{0} is now {1}": "{0} ahora es {1}", + "Enabled": "Habilitado", + "Disabled": "Deshabilitado", + "Privacy": "Privacidad", + "Hide my username from the logs": "Ocultar mi nombre de usuario en los registros", + "Replaces your username with **** in the logs. Restart UniGetUI to also hide it from already-recorded entries.": "Sustituye tu nombre de usuario por **** en los registros. Reinicia UniGetUI para ocultarlo también en las entradas ya registradas.", + "Your last update attempt did not complete.": "Tu último intento de actualización no se completó.", + "UniGetUI could not confirm whether the update succeeded. Open the log to see what happened.": "UniGetUI no pudo confirmar si la actualización tuvo éxito. Abre el registro para ver qué ocurrió.", + "View log": "Ver registro", + "The installer reported success but did not restart UniGetUI.": "El instalador informó que tuvo éxito, pero no reinició UniGetUI.", + "The installer failed to initialize.": "El instalador no se pudo inicializar.", + "Setup was canceled before installation began.": "La configuración se canceló antes de que comenzara la instalación.", + "A fatal error occurred during the preparation phase.": "Se produjo un error fatal durante la fase de preparación.", + "A fatal error occurred during installation.": "Se produjo un error fatal durante la instalación.", + "Installation was canceled while in progress.": "La instalación se canceló mientras estaba en curso.", + "The installer was terminated by another process.": "El instalador fue terminado por otro proceso.", + "The preparation phase determined the installation cannot proceed.": "La fase de preparación determinó que la instalación no puede continuar.", + "The installer could not start. UniGetUI may already be running, or you do not have permission to install.": "El instalador no pudo iniciarse. Es posible que UniGetUI ya se esté ejecutando o que no tengas permisos para instalar.", + "Unexpected installer error.": "Error inesperado del instalador.", + "We are checking for updates.": "Estamos buscando actualizaciones.", + "Please wait": "Por favor, espera", + "Great! You are on the latest version.": "¡Genial! Tienes la última versión.", + "There are no new UniGetUI versions to be installed": "No hay nuevas versiones de UniGetUI para instalar", + "UniGetUI version {0} is being downloaded.": "Se está descargando la versión {0} de UniGetUI.", + "This may take a minute or two": "Esto puede tardar un minuto o dos", + "The installer authenticity could not be verified.": "No se pudo verificar la autenticidad del instalador.", + "The update process has been aborted.": "El proceso de actualización ha sido abortado.", + "Auto-update is not yet available on this platform.": "La actualización automática aún no está disponible en esta plataforma.", + "Please update UniGetUI manually.": "Por favor, actualiza UniGetUI manualmente.", + "An error occurred when checking for updates: ": "Se ha producido un error al buscar actualizaciones: ", + "The updater could not be launched.": "No se pudo iniciar el actualizador.", + "The operating system did not start the installer process.": "El sistema operativo no inició el proceso del instalador.", + "UniGetUI is being updated...": "UniGetUI se está actualizando...", + "Update installed.": "Actualización instalada.", + "UniGetUI was updated successfully, but this running copy was not replaced. This usually means you are running a development build. Close this copy and start the newly-installed version to finish.": "UniGetUI se actualizó correctamente, pero esta copia en ejecución no fue reemplazada. Esto suele significar que estás ejecutando una versión de desarrollo. Cierra esta copia e inicia la versión recién instalada para finalizar.", + "The update could not be applied.": "No se pudo aplicar la actualización.", + "Installer exit code {0}: {1}": "Código de salida del instalador {0}: {1}", + "Update cancelled.": "Actualización cancelada.", + "Authentication was cancelled.": "La autenticación fue cancelada.", + "Installer exit code {0}": "Código de salida del instalador {0}", + "Operation in progress": "Operación en curso", + "Please wait...": "Por favor, espera...", + "Success!": "¡Éxito!", + "Failed": "Fallido", + "An error occurred while processing this package": "Se ha producido un error al procesar este paquete", + "Installer": "Instalador", + "Executable": "Ejecutable", + "MSI": "MSI", + "Compressed file": "Archivo comprimido", + "MSIX": "MSIX", + "WinGet was repaired successfully": "WinGet se ha reparado correctamente", + "It is recommended to restart UniGetUI after WinGet has been repaired": "Se recomienda reiniciar UniGetUI después de haber reparado WinGet", + "WinGet could not be repaired": "No se pudo reparar WinGet", + "An unexpected issue occurred while attempting to repair WinGet. Please try again later": "Se ha producido un problema inesperado al intentar reparar WinGet. Por favor, inténtalo más tarde", + "Log in to enable cloud backup": "Inicia sesión para habilitar la copia de seguridad en la nube", + "Backup Failed": "Copia de seguridad fallida", + "Downloading backup...": "Descargando copia de seguridad...", + "An update was found!": "¡Se ha encontrado una actualización!", + "{0} can be updated to version {1}": "{0} puede actualizarse a la versión {1}", + "Updates found!": "¡Actualizaciones encontradas!", + "{0} packages can be updated": "{0} paquetes pueden actualizarse", + "{0} is being updated to version {1}": "{0} se está actualizando a la versión {1}", + "{0} packages are being updated": "{0} paquetes se están actualizando", + "You have currently version {0} installed": "Tienes instalada la versión {0}", + "Desktop shortcut created": "Acceso directo al escritorio creado", + "UniGetUI has detected a new desktop shortcut that can be deleted automatically.": "UniGetUI ha detectado un nuevo acceso directo al escritorio que puede eliminarse automáticamente.", + "{0} desktop shortcuts created": "{0} accesos directos al escritorio creados", + "UniGetUI has detected {0} new desktop shortcuts that can be deleted automatically.": "UniGetUI ha detectado {0} nuevos accesos directos al escritorio que pueden eliminarse automáticamente.", + "Attention required": "Se requiere atención", + "Restart required": "Se requiere reiniciar", + "1 update is available": "Hay 1 actualización disponible", + "{0} updates are available": "Hay {0} actualizaciones disponibles", + "Everything is up to date": "Todo está actualizado", + "Discover Packages": "Descubrir paquetes", + "Available Updates": "Actualizaciones disponibles", + "Installed Packages": "Paquetes instalados", + "UniGetUI Version {0} by Devolutions": "UniGetUI Versión {0} por Devolutions", + "Show UniGetUI": "Mostrar UniGetUI", + "Quit": "Salir", + "Are you sure?": "¿Estás seguro?", + "Do you really want to uninstall {0}?": "¿Realmente quieres desinstalar {0}?", + "Do you really want to uninstall the following {0} packages?": "¿Realmente quieres desinstalar los siguientes {0} paquetes?", + "No": "No", + "Yes": "Sí", + "Partial": "Parcial", + "View on UniGetUI": "Ver en UniGetUI", + "Update": "Actualizar", + "Open UniGetUI": "Abrir UniGetUI", + "Update all": "Actualizar todo", + "Update now": "Actualizar ahora", + "Installer host changed since the installed version.\n": "El host del instalador ha cambiado desde la versión instalada.\n", + "This package is on the queue": "Este paquete está en cola", + "installing": "instalando", + "updating": "actualizando", + "uninstalling": "desinstalando", + "installed": "instalado", + "Retry": "Reintentar", + "Install": "Instalar", + "Uninstall": "Desinstalar", + "Open": "Abrir", + "Operation profile:": "Perfil de operación:", + "Follow the default options when installing, upgrading or uninstalling this package": "Seguir las opciones predeterminadas al instalar, actualizar o desinstalar este paquete", + "The following settings will be applied each time this package is installed, updated or removed.": "Los siguientes ajustes se aplicarán cada vez que este paquete se instale, actualice o elimine.", + "Version to install:": "Versión a instalar:", + "Architecture to install:": "Arquitectura a instalar:", + "Installation scope:": "Ámbito de instalación:", + "Install location:": "Ubicación de instalación:", + "Select": "Seleccionar", + "Reset": "Restablecer", + "Custom install arguments:": "Argumentos de instalación personalizados:", + "Custom update arguments:": "Argumentos de actualización personalizados:", + "Custom uninstall arguments:": "Argumentos de desinstalación personalizados:", + "Pre-install command:": "Comando de preinstalación:", + "Post-install command:": "Comando de postinstalación:", + "Abort install if pre-install command fails": "Abortar instalación si el comando de preinstalación falla", + "Pre-update command:": "Comando de preactualización:", + "Post-update command:": "Comando de postactualización:", + "Abort update if pre-update command fails": "Abortar actualización si el comando de preactualización falla", + "Pre-uninstall command:": "Comando de predesinstalación:", + "Post-uninstall command:": "Comando de postdesinstalación:", + "Abort uninstall if pre-uninstall command fails": "Abortar desinstalación si el comando de predesinstalación falla", + "Command-line to run:": "Línea de comandos a ejecutar:", + "Save and close": "Guardar y cerrar", + "General": "General", + "Architecture & Location": "Arquitectura y ubicación", + "Command-line": "Línea de comandos", + "Close apps": "Cerrar aplicaciones", + "Pre/Post install": "Pre/Post instalación", + "Select the processes that should be closed before this package is installed, updated or uninstalled.": "Selecciona los procesos que deben cerrarse antes de que este paquete se instale, actualice o desinstale.", + "Write here the process names here, separated by commas (,)": "Escribe aquí los nombres de los procesos, separados por comas (,)", + "Try to kill the processes that refuse to close when requested to": "Intentar forzar el cierre de los procesos que se nieguen a cerrarse", + "Run as admin": "Ejecutar como administrador", + "Interactive installation": "Instalación interactiva", + "Skip hash check": "Omitir comprobación de hash", + "Uninstall previous versions when updated": "Desinstalar versiones anteriores al actualizar", + "Skip minor updates for this package": "Omitir actualizaciones menores para este paquete", + "Automatically update this package": "Actualizar automáticamente este paquete", + "{0} installation options": "{0} opciones de instalación", + "Latest": "Última", + "PreRelease": "Preliminar", + "Default": "Predeterminado", + "Manage ignored updates": "Gestionar actualizaciones ignoradas", + "The packages listed here won't be taken in account when checking for updates. Double-click them or click the button on their right to stop ignoring their updates.": "Los paquetes enumerados aquí no se tendrán en cuenta al buscar actualizaciones. Haz doble clic en ellos o haz clic en el botón de la derecha para dejar de ignorar sus actualizaciones.", + "Reset list": "Restablecer lista", + "Do you really want to reset the ignored updates list? This action cannot be reverted": "¿Realmente quieres restablecer la lista de actualizaciones ignoradas? Esta acción no se puede deshacer", + "No ignored updates": "No hay actualizaciones ignoradas", + "Package Name": "Nombre del paquete", + "Package ID": "ID del paquete", + "Ignored version": "Versión ignorada", + "New version": "Nueva versión", + "Source": "Fuente", + "All versions": "Todas las versiones", + "Unknown": "Desconocido", + "Up to date": "Actualizado", + "Package {name} from {manager}": "Paquete {name} de {manager}", + "Remove {0} from ignored updates": "Eliminar {0} de las actualizaciones ignoradas", + "Cancel": "Cancelar", + "Administrator privileges": "Privilegios de administrador", + "This operation is running with administrator privileges.": "Esta operación se está ejecutando con privilegios de administrador.", + "Interactive operation": "Operación interactiva", + "This operation is running interactively.": "Esta operación se está ejecutando de forma interactiva.", + "You will likely need to interact with the installer.": "Es probable que necesites interactuar con el instalador.", + "Integrity checks skipped": "Comprobaciones de integridad omitidas", + "Integrity checks will not be performed during this operation.": "No se realizarán comprobaciones de integridad durante esta operación.", + "Proceed at your own risk.": "Procede bajo tu propio riesgo.", + "Close": "Cerrar", + "Loading...": "Cargando...", + "Installer SHA256": "SHA256 del instalador", + "Homepage": "Página principal", + "Author": "Autor", + "Publisher": "Editor", + "License": "Licencia", + "Manifest": "Manifiesto", + "Installer Type": "Tipo de instalador", + "Size": "Tamaño", + "Installer URL": "URL del instalador", + "Last updated:": "Última actualización:", + "Release notes URL": "URL de las notas de la versión", + "Package details": "Detalles del paquete", + "Dependencies:": "Dependencias:", + "Release notes": "Notas de la versión", + "Screenshots": "Capturas de pantalla", + "This package has no screenshots or is missing the icon? Contribute to UniGetUI by adding the missing icons and screenshots to our open, public database.": "¿Este paquete no tiene capturas de pantalla o le falta el icono? Contribuye a UniGetUI añadiendo los iconos y capturas faltantes a nuestra base de datos pública y abierta.", + "Version": "Versión", + "Install as administrator": "Instalar como administrador", + "Update to version {0}": "Actualizar a la versión {0}", + "Installed Version": "Versión instalada", + "Update as administrator": "Actualizar como administrador", + "Interactive update": "Actualización interactiva", + "Uninstall as administrator": "Desinstalar como administrador", + "Interactive uninstall": "Desinstalación interactiva", + "Uninstall and remove data": "Desinstalar y eliminar datos", + "Not available": "No disponible", + "Installer SHA512": "SHA512 del instalador", + "Unknown size": "Tamaño desconocido", + "No dependencies specified": "No se han especificado dependencias", + "mandatory": "obligatorio", + "optional": "opcional", + "UniGetUI {0} is ready to be installed.": "UniGetUI {0} está listo para ser instalado.", + "The update process will start after closing UniGetUI": "El proceso de actualización comenzará después de cerrar UniGetUI", + "UniGetUI has been ran as administrator, which is not recommended. When running UniGetUI as administrator, EVERY operation launched from UniGetUI will have administrator privileges. You can still use the program, but we highly recommend not running UniGetUI with administrator privileges.": "UniGetUI se ha ejecutado como administrador, lo cual no es recomendable. Al ejecutar UniGetUI como administrador, TODA operación lanzada desde UniGetUI tendrá privilegios de administrador. Aún puedes usar el programa, pero recomendamos encarecidamente no ejecutar UniGetUI con privilegios de administrador.", + "Share anonymous usage data": "Compartir datos de uso anónimos", + "UniGetUI collects anonymous usage data in order to improve the user experience.": "UniGetUI recopila datos de uso anónimos para mejorar la experiencia del usuario.", + "Accept": "Aceptar", + "Software Updates": "Actualizaciones de software", + "Package Bundles": "Lotes de paquetes", + "Settings": "Configuración", + "Package Managers": "Gestores de paquetes", + "UniGetUI Log": "Registro de UniGetUI", + "Package Manager logs": "Registros del gestor de paquetes", + "Operation history": "Historial de operaciones", + "Help": "Ayuda", + "UniGetUI": "UniGetUI", + "You have installed UniGetUI Version {0}": "Has instalado UniGetUI Versión {0}", + "Disclaimer": "Aviso legal", + "UniGetUI is developed by Devolutions and is not affiliated with any of the compatible package managers.": "UniGetUI es desarrollado por Devolutions y no está afiliado a ninguno de los gestores de paquetes compatibles.", + "UniGetUI wouldn't have been possible without the help of the contributors. Thank you all 🥳": "UniGetUI no habría sido posible sin la ayuda de los colaboradores. Gracias a todos 🥳", + "UniGetUI uses the following libraries. Without them, UniGetUI wouldn't have been possible.": "UniGetUI utiliza las siguientes librerías. Sin ellas, UniGetUI no habría sido posible.", + "{0} homepage": "Página principal de {0}", + "UniGetUI has been translated to more than 40 languages thanks to the volunteer translators. Thank you 🤝": "UniGetUI ha sido traducido a más de 40 idiomas gracias a los traductores voluntarios. Gracias 🤝", + "Verbose": "Detallado", + "1 - Errors": "1 - Errores", + "2 - Warnings": "2 - Advertencias", + "3 - Information (less)": "3 - Información (menos)", + "4 - Information (more)": "4 - Información (más)", + "5 - information (debug)": "5 - Información (depuración)", + "Warning": "Advertencia", + "The following settings may pose a security risk, hence they are disabled by default.": "Los siguientes ajustes pueden suponer un riesgo de seguridad, por lo que están deshabilitados por defecto.", + "Enable the settings below if and only if you fully understand what they do, and the implications they may have.": "Habilita los ajustes a continuación SÓLO SI entiendes completamente qué hacen y las implicaciones y peligros que pueden conllevar.", + "The settings will list, in their descriptions, the potential security issues they may have.": "Los ajustes enumerarán, en sus descripciones, los posibles problemas de seguridad que puedan tener.", + "The backup will include the complete list of the installed packages and their installation options. Ignored updates and skipped versions will also be saved.": "La copia de seguridad incluirá la lista completa de los paquetes instalados y sus opciones de instalación. También se guardarán las actualizaciones ignoradas y las versiones omitidas.", + "The backup will NOT include any binary file nor any program's saved data.": "La copia de seguridad NO incluirá ningún archivo binario ni datos guardados de ningún programa.", + "The size of the backup is estimated to be less than 1MB.": "Se estima que el tamaño de la copia de seguridad es inferior a 1 MB.", + "The backup will be performed after login.": "La copia de seguridad se realizará después de iniciar sesión.", + "{pcName} installed packages": "Paquetes instalados en {pcName}", + "Current status: Not logged in": "Estado actual: No se ha iniciado sesión", + "You are logged in as {0} (@{1})": "Has iniciado sesión como {0} (@{1})", + "Nice! Backups will be uploaded to a private gist on your account": "¡Genial! Las copias de seguridad se subirán a un Gist privado en tu cuenta", + "Select backup": "Seleccionar copia de seguridad", + "Settings imported from {0}": "Configuración importada desde {0}", + "UniGetUI Settings": "Configuración de UniGetUI", + "Settings exported to {0}": "Configuración exportada a {0}", + "UniGetUI settings were reset": "La configuración de UniGetUI ha sido restablecida", + "Allow pre-release versions": "Permitir versiones preliminares", + "Apply": "Aplicar", + "For security reasons, custom command-line arguments are disabled by default. Go to UniGetUI security settings to change this.": "Por razones de seguridad, los argumentos de línea de comandos personalizados están deshabilitados por defecto. Ve a la configuración de seguridad de UniGetUI para cambiar esto.", + "Go to UniGetUI security settings": "Ir a la configuración de seguridad de UniGetUI", + "The following options will be applied by default each time a {0} package is installed, upgraded or uninstalled.": "Las siguientes opciones se aplicarán por defecto cada vez que se instale, actualice o desinstale un paquete de {0}.", + "Package's default": "Predeterminado del paquete", + "Install location can't be changed for {0} packages": "La ubicación de instalación no se puede cambiar para los paquetes de {0}", + "The local icon cache currently takes {0} MB": "La caché de iconos local ocupa actualmente {0} MB", + "Username": "Nombre de usuario", + "Password": "Contraseña", + "Credentials": "Credenciales", + "It is not guaranteed that the provided credentials will be stored safely": "No se garantiza que las credenciales proporcionadas se almacenen de forma segura", + "Partially": "Parcialmente", + "Package manager": "Gestor de paquetes", + "Compatible with proxy": "Compatible con proxy", + "Compatible with authentication": "Compatible con autenticación", + "Proxy compatibility table": "Tabla de compatibilidad de proxy", + "{0} settings": "Configuración de {0}", + "{0} status": "Estado de {0}", + "Default installation options for {0} packages": "Opciones de instalación predeterminadas para paquetes de {0}", + "Expand version": "Expandir versión", + "The executable file for {0} was not found": "No se encontró el archivo ejecutable de {0}", + "{pm} is disabled": "{pm} está deshabilitado", + "Enable it to install packages from {pm}.": "Habilítalo para instalar paquetes de {pm}.", + "{pm} is enabled and ready to go": "{pm} está habilitado y listo", + "{pm} version:": "Versión de {pm}:", + "{pm} was not found!": "¡No se encontró {pm}!", + "You may need to install {pm} in order to use it with UniGetUI.": "Es posible que necesites instalar {pm} para poder usarlo con UniGetUI.", + "Scoop Installer - UniGetUI": "Instalador de Scoop - UniGetUI", + "Scoop Uninstaller - UniGetUI": "Desinstalador de Scoop - UniGetUI", + "Clearing Scoop cache - UniGetUI": "Limpiando caché de Scoop - UniGetUI", + "Restart UniGetUI to fully apply changes": "Reinicia UniGetUI para aplicar los cambios completamente", + "Restart UniGetUI": "Reiniciar UniGetUI", + "Manage {0} sources": "Gestionar fuentes de {0}", + "Add source": "Añadir fuente", + "Add": "Añadir", + "Source name": "Nombre de la fuente", + "Source URL": "URL de la fuente", + "Other": "Otro", + "No minimum age": "Sin antigüedad mínima", + "1 day": "un día", + "{0} days": "{0} días", + "Custom...": "Personalizado...", + "{0} minutes": "{0} minutos", + "1 hour": "una hora", + "{0} hours": "{0} horas", + "1 week": "1 semana", + "Supports release dates": "Soporta fechas de lanzamiento", + "Release date support per package manager": "Soporte de fecha de lanzamiento por gestor de paquetes", + "Search for packages": "Buscar paquetes", + "Local": "Local", + "OK": "Aceptar", + "Last checked: {0}": "Última comprobación: {0}", + "{0} packages were found, {1} of which match the specified filters.": "Se encontraron {0} paquetes, de los cuales {1} coinciden con los filtros especificados.", + "{0} selected": "{0} seleccionado(s)", + "(Last checked: {0})": "(Última comprobación: {0})", + "All packages selected": "Todos los paquetes seleccionados", + "Package selection cleared": "Selección de paquetes borrada", + "{0}: {1}": "{0}: {1}", + "More info": "Más información", + "GitHub account": "Cuenta de GitHub", + "Log in with GitHub to enable cloud package backup.": "Inicia sesión con GitHub para habilitar la copia de seguridad de paquetes en la nube.", + "More details": "Más detalles", + "Log in": "Iniciar sesión", + "If you have cloud backup enabled, it will be saved as a GitHub Gist on this account": "Si tienes habilitada la copia de seguridad en la nube, se guardará como un Gist de GitHub en esta cuenta", + "Log out": "Cerrar sesión", + "About UniGetUI": "Acerca de UniGetUI", + "About": "Acerca de", + "Third-party licenses": "Licencias de terceros", + "Contributors": "Colaboradores", + "Translators": "Traductores", + "Bundle security report": "Informe de seguridad del lote", + "The bundle contained restricted content": "El lote contenía contenido restringido", + "UniGetUI – Crash Report": "UniGetUI – Informe de errores", + "UniGetUI has crashed": "UniGetUI se ha cerrado inesperadamente", + "Help us fix this by sending a crash report to Devolutions. All fields below are optional.": "Ayúdanos a solucionarlo enviando un informe de error a Devolutions. Todos los campos a continuación son opcionales.", + "Email (optional)": "Correo electrónico (opcional)", + "your@email.com": "tu@correo.com", + "Additional details (optional)": "Detalles adicionales (opcional)", + "Describe what you were doing when the crash occurred…": "Describe qué estabas haciendo cuando ocurrió el error…", + "Crash report": "Informe de error", + "Don't Send": "No enviar", + "Send Report": "Enviar informe", + "Sending…": "Enviando…", + "Unsaved changes": "Cambios sin guardar", + "You have unsaved changes in the current bundle. Do you want to discard them?": "Tienes cambios sin guardar en el lote actual. ¿Quieres descartarlos?", + "Discard changes": "Descartar cambios", + "Integrity violation": "Violación de integridad", + "UniGetUI or some of its components are missing or corrupt. It is strongly recommended to reinstall UniGetUI to adress the situation.": "UniGetUI o algunos de sus componentes faltan o están corruptos. Se recomienda encarecidamente reinstalar UniGetUI para solucionar la situación.", + "• Refer to the UniGetUI Logs to get more details regarding the affected file(s)": "• Consulta los registros de UniGetUI para obtener más detalles sobre el archivo o archivos afectados", + "• Integrity checks can be disabled from the Experimental Settings": "• Las comprobaciones de integridad se pueden deshabilitar en los Ajustes Experimentales", + "Manage shortcuts": "Gestionar accesos directos", + "UniGetUI has detected the following desktop shortcuts which can be removed automatically on future upgrades": "UniGetUI ha detectado los siguientes accesos directos al escritorio que pueden eliminarse automáticamente en futuras actualizaciones", + "Do you really want to reset this list? This action cannot be reverted.": "¿Realmente quieres restablecer esta lista? Esta acción no se puede deshacer.", + "Desktop shortcuts list": "Lista de accesos directos al escritorio", + "Open in explorer": "Abrir en el explorador", + "Remove from list": "Eliminar de la lista", + "When new shortcuts are detected, delete them automatically instead of showing this dialog.": "Cuando se detecten nuevos accesos directos, elimínalos automáticamente en lugar de mostrar este diálogo.", + "Not right now": "Ahora no", + "Missing dependency": "Dependencia faltante", + "UniGetUI requires {0} to operate, but it was not found on your system.": "UniGetUI requiere {0} para funcionar, pero no se encontró en tu sistema.", + "Click on Install to begin the installation process. If you skip the installation, UniGetUI may not work as expected.": "Haz clic en Instalar para comenzar el proceso de instalación. Si omites la instalación, es posible que UniGetUI no funcione como se espera.", + "Alternatively, you can also install {0} by running the following command in a Windows PowerShell prompt:": "Alternativamente, también puedes instalar {0} ejecutando el siguiente comando en un símbolo del sistema de Windows PowerShell:", + "Install {0}": "Instalar {0}", + "Do not show this dialog again for {0}": "No volver a mostrar este diálogo para {0}", + "Please wait while {0} is being installed. A black window may show up. Please wait until it closes.": "Por favor, espera mientras se instala {0}. Puede que aparezca una ventana negra (o azul). Por favor, espera hasta que se cierre.", + "{0} has been installed successfully.": "{0} se ha instalado correctamente.", + "Please click on \"Continue\" to continue": "Por favor, haz clic en \"Continuar\" para seguir", + "Continue": "Continuar", + "{0} has been installed successfully. It is recommended to restart UniGetUI to finish the installation": "{0} se ha instalado correctamente. Se recomienda reiniciar UniGetUI para finalizar la instalación", + "Restart later": "Reiniciar más tarde", + "An error occurred:": "Se ha producido un error:", + "Please see the Command-line Output or refer to the Operation History for further information about the issue.": "Consulta la salida de la línea de comandos o el historial de operaciones para obtener más información sobre el problema.", + "Retry as administrator": "Reintentar como administrador", + "Retry interactively": "Reintentar interactivamente", + "Retry skipping integrity checks": "Reintentar omitiendo las comprobaciones de integridad", + "Installation options": "Opciones de instalación", + "Save": "Guardar", + "UniGetUI collects anonymous usage data with the sole purpose of understanding and improving the user experience.": "UniGetUI recopila datos de uso anónimos con el único propósito de comprender y mejorar la experiencia del usuario.", + "More details about the shared data and how it will be processed": "Más detalles sobre los datos compartidos y cómo serán procesados", + "Do you accept that UniGetUI collects and sends anonymous usage statistics, with the sole purpose of understanding and improving the user experience?": "¿Aceptas que UniGetUI recopile y envíe estadísticas de uso anónimas, con el único propósito de comprender y mejorar la experiencia del usuario?", + "Decline": "Rechazar", + "No personal information is collected nor sent, and the collected data is anonimized, so it can't be back-tracked to you.": "No se recopila ni se envía información personal, y los datos recopilados son anónimos, por lo que no pueden rastrearse hasta ti.", + "Navigation panel": "Panel de navegación", + "Operations": "Operaciones", + "Toggle operations panel": "Alternar panel de operaciones", + "Bulk operations": "Operaciones masivas", + "Retry failed": "Reintentar fallidos", + "Clear successful": "Limpiar exitosos", + "Clear finished": "Limpiar finalizados", + "Cancel all": "Cancelar todo", + "More": "Más", + "Toggle navigation panel": "Alternar panel de navegación", + "Minimize": "Minimizar", + "Maximize": "Maximizar", + "UniGetUI by Devolutions": "UniGetUI por Devolutions", + "UniGetUI is an application that makes managing your software easier, by providing an all-in-one graphical interface for your command-line package managers.": "UniGetUI es una aplicación que facilita la gestión de tu software, proporcionando una interfaz gráfica todo en uno para tus gestores de paquetes de línea de comandos.", + "Useful links": "Enlaces útiles", + "UniGetUI Homepage": "Página principal de UniGetUI", + "Report an issue or submit a feature request": "Informar de un problema o solicitar una funcionalidad", + "UniGetUI Repository": "Repositorio de UniGetUI", + "View GitHub Profile": "Ver perfil de GitHub", + "UniGetUI License": "Licencia de UniGetUI", + "Using UniGetUI implies the acceptation of the MIT License": "El uso de UniGetUI implica la aceptación de la Licencia MIT", + "Become a translator": "Convertirse en traductor", + "Go back": "Ir atrás", + "Go forward": "Ir adelante", + "Go to home page": "Ir a la página de inicio", + "Reload page": "Recargar página", + "View page on browser": "Ver página en el navegador", + "The built-in browser is not supported on Linux yet.": "El navegador integrado aún no es compatible con Linux.", + "Open in browser": "Abrir en el navegador", + "Copy to clipboard": "Copiar al portapapeles", + "Export to a file": "Exportar a un archivo", + "Log level:": "Nivel de registro:", + "Reload log": "Recargar registro", + "Export log": "Exportar registro", + "Text": "Texto", + "Change how operations request administrator rights": "Cambiar cómo las operaciones solicitan derechos de administrador", + "Restrictions on package operations": "Restricciones en las operaciones de paquetes", + "Restrictions on package managers": "Restricciones en los gestores de paquetes", + "Restrictions when importing package bundles": "Restricciones al importar lotes de paquetes", + "Ask for administrator privileges once for each batch of operations": "Solicitar privilegios de administrador una vez por cada lote de operaciones", + "Ask only once for administrator privileges": "Solicitar privilegios de administrador solo una vez", + "Prohibit any kind of Elevation via UniGetUI Elevator or GSudo": "Prohibir cualquier tipo de elevación a través de UniGetUI Elevator o GSudo", + "This option WILL cause issues. Any operation incapable of elevating itself WILL FAIL. Install/update/uninstall as administrator will NOT WORK.": "Esta opción CAUSARÁ problemas. Cualquier operación incapaz de elevarse a sí misma FALLARÁ. Instalar/actualizar/desinstalar como administrador NO FUNCIONARÁ.", + "Allow custom command-line arguments": "Permitir argumentos de línea de comandos personalizados", + "Custom command-line arguments can change the way in which programs are installed, upgraded or uninstalled, in a way UniGetUI cannot control. Using custom command-lines can break packages. Proceed with caution.": "Los argumentos de línea de comandos personalizados pueden cambiar la forma en que se instalan, actualizan o desinstalan los programas, de una manera que UniGetUI no puede controlar. El uso de líneas de comandos personalizadas puede romper los paquetes. Procede con precaución.", + "Ignore custom pre-install and post-install commands when importing packages from a bundle": "Ignorar comandos personalizados de preinstalación y postinstalación al importar paquetes de un lote", + "Pre and post install commands will be run before and after a package gets installed, upgraded or uninstalled. Be aware that they may break things unless used carefully": "Los comandos de pre y postinstalación se ejecutarán antes y después de que un paquete se instale, actualice o desinstale. Ten en cuenta que pueden romper cosas si no se usan con cuidado", + "Allow changing the paths for package manager executables": "Permitir cambiar las rutas de los ejecutables del gestor de paquetes", + "Turning this on enables changing the executable file used to interact with package managers. While this allows finer-grained customization of your install processes, it may also be dangerous": "Al activar esto, se permite cambiar el archivo ejecutable utilizado para interactuar con los gestores de paquetes. Aunque esto permite una personalización más detallada de tus procesos de instalación, también puede ser peligroso", + "Allow importing custom command-line arguments when importing packages from a bundle": "Permitir la importación de argumentos de línea de comandos personalizados al importar paquetes de un lote", + "Malformed command-line arguments can break packages, or even allow a malicious actor to gain privileged execution. Therefore, importing custom command-line arguments is disabled by default": "Los argumentos de línea de comandos mal formados pueden romper los paquetes, o incluso permitir que un actor malicioso obtenga una ejecución privilegiada. Por lo tanto, la importación de argumentos de línea de comandos personalizados está deshabilitada por defecto", + "Allow importing custom pre-install and post-install commands when importing packages from a bundle": "Permitir la importación de comandos personalizados de preinstalación y postinstalación al importar paquetes de un lote", + "Pre and post install commands can do very nasty things to your device, if designed to do so. It can be very dangerous to import the commands from a bundle, unless you trust the source of that package bundle": "Los comandos de pre y postinstalación pueden hacer cosas muy desagradables en tu dispositivo si están diseñados para ello. Puede ser muy peligroso importar comandos de un lote, a menos que confíes en la fuente de dicho lote de paquetes", + "Administrator rights and other dangerous settings": "Derechos de administrador y otros ajustes peligrosos", + "Package backup": "Copia de seguridad de paquetes", + "Cloud package backup": "Copia de seguridad de paquetes en la nube", + "Local package backup": "Copia de seguridad de paquetes local", + "Local backup advanced options": "Opciones avanzadas de copia de seguridad local", + "Log in with GitHub": "Iniciar sesión con GitHub", + "Log out from GitHub": "Cerrar sesión en GitHub", + "Periodically perform a cloud backup of the installed packages": "Realizar periódicamente una copia de seguridad en la nube de los paquetes instalados", + "Cloud backup uses a private GitHub Gist to store a list of installed packages": "La copia de seguridad en la nube utiliza un Gist privado de GitHub para almacenar una lista de los paquetes instalados", + "Perform a cloud backup now": "Realizar una copia de seguridad en la nube ahora", + "Backup": "Copia de seguridad", + "Restore a backup from the cloud": "Restaurar una copia de seguridad de la nube", + "Begin the process to select a cloud backup and review which packages to restore": "Comenzar el proceso para seleccionar una copia de seguridad en la nube y revisar qué paquetes restaurar", + "Periodically perform a local backup of the installed packages": "Realizar periódicamente una copia de seguridad local de los paquetes instalados", + "Perform a local backup now": "Realizar una copia de seguridad local ahora", + "Change backup output directory": "Cambiar el directorio de salida de la copia de seguridad", + "Set a custom backup file name": "Establecer un nombre de archivo de copia de seguridad personalizado", + "Leave empty for default": "Dejar vacío para el predeterminado", + "Add a timestamp to the backup file names": "Añadir una marca de tiempo a los nombres de los archivos de copia de seguridad", + "Backup and Restore": "Copia de seguridad y restauración", + "Enable background api (UniGetUI Widgets and Sharing, port 7058)": "Habilitar API en segundo plano (Widgets de UniGetUI y Compartir, puerto 7058)", + "Wait for the device to be connected to the internet before attempting to do tasks that require internet connectivity.": "Esperar a que el dispositivo esté conectado a internet antes de intentar realizar tareas que requieran conectividad a internet.", + "Disable the 1-minute timeout for package-related operations": "Deshabilitar el tiempo de espera de 1 minuto para las operaciones relacionadas con paquetes", + "Use installed GSudo instead of UniGetUI Elevator": "Usar GSudo instalado en lugar de UniGetUI Elevator", + "Use a custom icon and screenshot database URL": "Usar una URL personalizada para la base de datos de iconos y capturas de pantalla", + "Enable background CPU Usage optimizations (see Pull Request #3278)": "Habilitar optimizaciones de uso de CPU en segundo plano (ver Pull Request #3278)", + "Perform integrity checks at startup": "Realizar comprobaciones de integridad al iniciar", + "When batch installing packages from a bundle, install also packages that are already installed": "Al instalar paquetes en lote desde un lote, instalar también los paquetes que ya estén instalados", + "Experimental settings and developer options": "Ajustes experimentales y opciones de desarrollador", + "Show UniGetUI's version and build number on the titlebar.": "Mostrar la versión de UniGetUI en la barra de título", + "Language": "Idioma", + "UniGetUI updater": "Actualizador de UniGetUI", + "Telemetry": "Telemetría", + "Manage UniGetUI settings": "Gestionar la configuración de UniGetUI", + "Related settings": "Ajustes relacionados", + "Update UniGetUI automatically": "Actualizar UniGetUI automáticamente", + "Check for updates": "Buscar actualizaciones", + "Install prerelease versions of UniGetUI": "Instalar versiones preliminares de UniGetUI", + "Manage telemetry settings": "Gestionar ajustes de telemetría", + "Manage": "Gestionar", + "Import settings from a local file": "Importar configuración desde un archivo local", + "Import": "Importar", + "Export settings to a local file": "Exportar configuración a un archivo local", + "Export": "Exportar", + "Reset UniGetUI": "Restablecer UniGetUI", + "User interface preferences": "Preferencias de la interfaz de usuario", + "Application theme, startup page, package icons, clear successful installs automatically": "Tema de la aplicación, página de inicio, iconos de paquetes, limpiar instalaciones exitosas automáticamente", + "General preferences": "Preferencias generales", + "UniGetUI display language:": "Idioma de visualización de UniGetUI:", + "System language": "Idioma del sistema", + "Is your language missing or incomplete?": "¿Falta tu idioma o está incompleto?", + "Appearance": "Apariencia", + "UniGetUI on the background and system tray": "UniGetUI en segundo plano y en la bandeja del sistema", + "Package lists": "Listas de paquetes", + "Use classic mode": "Usar modo clásico", + "Restart UniGetUI to apply this change": "Reinicia UniGetUI para aplicar este cambio", + "The classic UI is disabled for beta testers": "La interfaz clásica está deshabilitada para los probadores beta", + "Close UniGetUI to the system tray": "Cerrar UniGetUI en la bandeja del sistema", + "Manage UniGetUI autostart behaviour": "Gestionar el comportamiento de inicio automático de UniGetUI", + "Show package icons on package lists": "Mostrar iconos de paquetes en las listas de paquetes", + "Clear cache": "Limpiar caché", + "Select upgradable packages by default": "Seleccionar paquetes actualizables por defecto", + "Light": "Claro", + "Dark": "Oscuro", + "Follow system color scheme": "Seguir el esquema de colores del sistema", + "Application theme:": "Tema de la aplicación:", + "UniGetUI startup page:": "Página de inicio de UniGetUI:", + "Proxy settings": "Ajustes de proxy", + "Other settings": "Otros ajustes", + "Connect the internet using a custom proxy": "Conectarse a internet usando un proxy personalizado", + "Please note that not all package managers may fully support this feature": "Ten en cuenta que es posible que no todos los gestores de paquetes admitan completamente esta función", + "Proxy URL": "URL del proxy", + "Enter proxy URL here": "Introduce la URL del proxy aquí", + "Authenticate to the proxy with a user and a password": "Autenticarse en el proxy con un usuario y una contraseña", + "Internet and proxy settings": "Ajustes de internet y proxy", + "Package manager preferences": "Preferencias del gestor de paquetes", + "Ready": "Listo", + "Not found": "No encontrado", + "Notification preferences": "Preferencias de notificación", + "Notification types": "Tipos de notificación", + "The system tray icon must be enabled in order for notifications to work": "El icono de la bandeja del sistema debe estar habilitado para que las notificaciones funcionen", + "Enable UniGetUI notifications": "Habilitar notificaciones de UniGetUI", + "Show a notification when there are available updates": "Mostrar una notificación cuando haya actualizaciones disponibles", + "Show a silent notification when an operation is running": "Mostrar una notificación silenciosa cuando una operación esté en curso", + "Show a notification when an operation fails": "Mostrar una notificación cuando una operación falle", + "Show a notification when an operation finishes successfully": "Mostrar una notificación cuando una operación finalice con éxito", + "Concurrency and execution": "Concurrencia y ejecución", + "Automatic desktop shortcut remover": "Eliminador automático de accesos directos al escritorio", + "Choose how many operations should be performed in parallel": "Elige cuántas operaciones deben realizarse en paralelo", + "Clear successful operations from the operation list after a 5 second delay": "Limpiar las operaciones exitosas de la lista de operaciones tras un retraso de 5 segundos", + "Download operations are not affected by this setting": "Las operaciones de descarga no se ven afectadas por este ajuste", + "You may lose unsaved data": "Puedes perder datos no guardados", + "Ask to delete desktop shortcuts created during an install or upgrade.": "Preguntar si se deben eliminar los accesos directos al escritorio creados durante una instalación o actualización.", + "Package update preferences": "Preferencias de actualización de paquetes", + "Update check frequency, automatically install updates, etc.": "Frecuencia de comprobación de actualizaciones, instalar actualizaciones automáticamente, etc.", + "Reduce UAC prompts, elevate installations by default, unlock certain dangerous features, etc.": "Reducir los avisos de UAC, elevar las instalaciones por defecto, desbloquear ciertas funciones peligrosas, etc.", + "Package operation preferences": "Preferencias de operación de paquetes", + "Enable {pm}": "Habilitar {pm}", + "Not finding the file you are looking for? Make sure it has been added to path.": "¿No encuentras el archivo que buscas? Asegúrate de que haya sido añadido al PATH.", + "Select the executable to be used. The following list shows the executables found by UniGetUI": "Selecciona el ejecutable que se utilizará. La siguiente lista muestra los ejecutables encontrados por UniGetUI", + "For security reasons, changing the executable file is disabled by default": "Por razones de seguridad, el cambio del archivo ejecutable está deshabilitado por defecto", + "Change this": "Cambiar esto", + "Copy path": "Copiar ruta", + "Current executable file:": "Archivo ejecutable actual:", + "Ignore packages from {pm} when showing a notification about updates": "Ignorar paquetes de {pm} al mostrar una notificación sobre actualizaciones", + "Update security": "Seguridad de actualización", + "Use global setting": "Usar ajuste global", + "Minimum age for updates": "Antigüedad mínima para actualizaciones", + "e.g. 10": "ej. 10", + "Custom minimum age (days)": "Antigüedad mínima personalizada (días)", + "{pm} does not provide release dates for its packages, so this setting will have no effect": "{pm} no proporciona fechas de lanzamiento para sus paquetes, por lo que este ajuste no tendrá efecto", + "{pm} only provides release dates for some of its packages, so this setting will only apply to those packages": "{pm} solo proporciona fechas de lanzamiento para algunos de sus paquetes, por lo que este ajuste solo se aplicará a esos paquetes", + "Override the global minimum update age for this package manager": "Anular la antigüedad mínima de actualización global para este gestor de paquetes", + "View {0} logs": "Ver registros de {0}", + "If Python cannot be found or is not listing packages but is installed on the system, ": "Si no se encuentra Python o no enumera los paquetes pero está instalado en el sistema, ", + "Advanced options": "Opciones avanzadas", + "WinGet command-line tool": "Herramienta de línea de comandos de WinGet", + "Choose which command-line tool UniGetUI uses for WinGet operations when the COM API is not used": "Elige qué herramienta de línea de comandos utiliza UniGetUI para las operaciones de WinGet cuando no se utiliza la API COM", + "WinGet COM API": "API COM de WinGet", + "Choose whether UniGetUI can use the WinGet COM API before falling back to the command-line tool": "Elige si UniGetUI puede usar la API COM de WinGet antes de recurrir a la herramienta de línea de comandos", + "Reset WinGet": "Restablecer WinGet", + "This may help if no packages are listed": "Esto puede ayudar si no se enumeran paquetes", + "Force install location parameter when updating packages with custom locations": "Forzar el parámetro de ubicación de instalación al actualizar paquetes con ubicaciones personalizadas", + "Install Scoop": "Instalar Scoop", + "Uninstall Scoop (and its packages)": "Desinstalar Scoop (y sus paquetes)", + "Run cleanup and clear cache": "Ejecutar limpieza y borrar caché", + "Run": "Ejecutar", + "Enable Scoop cleanup on launch": "Habilitar la limpieza de Scoop al iniciar", + "Default vcpkg triplet": "Triplet de vcpkg predeterminado", + "Change vcpkg root location": "Cambiar la ubicación raíz de vcpkg", + "Reset vcpkg root location": "Restablecer la ubicación raíz de vcpkg", + "Open vcpkg root location": "Abrir la ubicación raíz de vcpkg", + "Language, theme and other miscellaneous preferences": "Idioma, tema y otras preferencias misceláneas", + "Show notifications on different events": "Mostrar notificaciones en diferentes eventos", + "Change how UniGetUI checks and installs available updates for your packages": "Cambia la forma en que UniGetUI busca e instala las actualizaciones disponibles para tus paquetes", + "Automatically save a list of all your installed packages to easily restore them.": "Guarda automáticamente una lista de todos tus paquetes instalados para restaurarlos fácilmente.", + "Enable and disable package managers, change default install options, etc.": "Habilitar y deshabilitar gestores de paquetes, cambiar opciones de instalación predeterminadas, etc.", + "Internet connection settings": "Ajustes de conexión a internet", + "Proxy settings, etc.": "Ajustes de proxy, etc.", + "Beta features and other options that shouldn't be touched": "Funciones beta y otras opciones que no deberían tocarse", + "Reload sources": "Recargar fuentes", + "Delete source": "Eliminar fuente", + "Known sources": "Fuentes conocidas", + "Update checking": "Comprobación de actualizaciones", + "Automatic updates": "Actualizaciones automáticas", + "Check for package updates periodically": "Buscar actualizaciones de paquetes periódicamente", + "Check for updates every:": "Buscar actualizaciones cada:", + "Install available updates automatically": "Instalar actualizaciones disponibles automáticamente", + "Do not automatically install updates when the network connection is metered": "No instalar actualizaciones automáticamente cuando la conexión de red sea limitada", + "Do not automatically install updates when the device runs on battery": "No instalar actualizaciones automáticamente cuando el dispositivo funcione con batería", + "Do not automatically install updates when the battery saver is on": "No instalar actualizaciones automáticamente cuando el ahorrador de batería esté activado", + "Only show updates that are at least the specified number of days old": "Mostrar solo actualizaciones que tengan al menos el número de días especificado", + "Warn me when the installer URL host changes between the installed version and the new version (WinGet only)": "Avisarme cuando el host de la URL del instalador cambie entre la versión instalada y la nueva versión (solo WinGet)", + "Change how UniGetUI handles install, update and uninstall operations.": "Cambia la forma en que UniGetUI gestiona las operaciones de instalación, actualización y desinstalación.", + "Navigation": "Navegación", + "Check for UniGetUI updates": "Buscar actualizaciones de UniGetUI", + "Quit UniGetUI": "Salir de UniGetUI", + "Filters": "Filtros", + "Sources": "Fuentes", + "Search for packages to start": "Busca paquetes para comenzar", + "Select all": "Seleccionar todo", + "Clear selection": "Limpiar selección", + "Instant search": "Búsqueda instantánea", + "Distinguish between uppercase and lowercase": "Distinguir entre mayúsculas y minúsculas", + "Ignore special characters": "Ignorar caracteres especiales", + "Search mode": "Modo de búsqueda", + "Both": "Ambos", + "Exact match": "Coincidencia exacta", + "Show similar packages": "Mostrar paquetes similares", + "Loading": "Cargando", + "Package": "Paquete", + "More options": "Más opciones", + "Order by:": "Ordenar por:", + "Name": "Nombre", + "Id": "ID", + "Ascendant": "Ascendente", + "Descendant": "Descendente", + "View modes": "Modos de vista", + "Reload": "Recargar", + "Closed": "Cerrado", + "Ascending": "Ascendente", + "Descending": "Descendente", + "{0}: {1}, {2}": "{0}: {1}, {2}", + "Order by": "Ordenar por", + "No results were found matching the input criteria": "No se encontraron resultados que coincidan con los criterios de entrada", + "No packages were found": "No se encontraron paquetes", + "Loading packages": "Cargando paquetes", + "Skip integrity checks": "Omitir comprobaciones de integridad", + "Download selected installers": "Descargar instaladores seleccionados", + "Install selection": "Instalar selección", + "Install options": "Opciones de instalación", + "Add selection to bundle": "Añadir selección al lote", + "Download installer": "Descargar instalador", + "Uninstall selection": "Desinstalar selección", + "Uninstall options": "Opciones de desinstalación", + "Ignore selected packages": "Ignorar paquetes seleccionados", + "Open install location": "Abrir ubicación de instalación", + "Reinstall package": "Reinstalar paquete", + "Uninstall package, then reinstall it": "Desinstalar paquete y luego reinstalarlo", + "Ignore updates for this package": "Ignorar actualizaciones para este paquete", + "WinGet malfunction detected": "Se ha detectado un mal funcionamiento de WinGet", + "It looks like WinGet is not working properly. Do you want to attempt to repair WinGet?": "Parece que WinGet no está funcionando correctamente. ¿Quieres intentar reparar WinGet?", + "Repair WinGet": "Reparar WinGet", + "Updates will no longer be ignored for {0}": "Las actualizaciones ya no se ignorarán para {0}", + "Updates are now ignored for {0}": "Las actualizaciones ahora se ignoran para {0}", + "Do not ignore updates for this package anymore": "No ignorar más las actualizaciones para este paquete", + "Add packages or open an existing package bundle": "Añadir paquetes o abrir un lote de paquetes existente", + "Add packages to start": "Añade paquetes para comenzar", + "The current bundle has no packages. Add some packages to get started": "El lote actual no tiene paquetes. Añade algunos paquetes para empezar", + "New": "Nuevo", + "Save as": "Guardar como", + "Create .ps1 script": "Crear script .ps1", + "Remove selection from bundle": "Eliminar selección del lote", + "Skip hash checks": "Omitir comprobaciones de hash", + "The package bundle is not valid": "El lote de paquetes no es válido", + "The bundle you are trying to load appears to be invalid. Please check the file and try again.": "El lote que intentas cargar parece ser inválido. Por favor, comprueba el archivo e inténtalo de nuevo.", + "Package bundle": "Lote de paquetes", + "Could not create bundle": "No se pudo crear el lote", + "The package bundle could not be created due to an error.": "El lote de paquetes no se pudo crear debido a un error.", + "Install script": "Script de instalación", + "PowerShell script": "Script de PowerShell", + "The installation script saved to {0}": "El script de instalación se guardó en {0}", + "An error occurred": "Se ha producido un error", + "An error occurred while attempting to create an installation script:": "Se ha producido un error al intentar crear un script de instalación:", + "Hooray! No updates were found.": "¡Hurra! No se encontraron actualizaciones.", + "Uninstall selected packages": "Desinstalar paquetes seleccionados", + "Update selection": "Actualizar selección", + "Update options": "Opciones de actualización", + "Uninstall package, then update it": "Desinstalar paquete y luego actualizarlo", + "Uninstall package": "Desinstalar paquete", + "Skip this version": "Omitir esta versión", + "Pause updates for": "Pausar actualizaciones durante", + "User | Local": "Usuario | Local", + "Machine | Global": "Máquina | Global", + "The default package manager for Debian/Ubuntu-based Linux distributions.
Contains: Debian/Ubuntu packages": "El gestor de paquetes predeterminado para distribuciones de Linux basadas en Debian/Ubuntu.
Contiene: paquetes de Debian/Ubuntu", + "The Rust package manager.
Contains: Rust libraries and programs written in Rust": "El gestor de paquetes de Rust.
Contiene: librerías de Rust y programas escritos en Rust", + "The classical package manager for windows. You'll find everything there.
Contains: General Software": "El gestor de paquetes clásico para Windows. Encontrarás de todo allí.
Contiene: Software general", + "The default package manager for RHEL/Fedora-based Linux distributions.
Contains: RPM packages": "El gestor de paquetes predeterminado para distribuciones de Linux basadas en RHEL/Fedora.
Contiene: paquetes RPM", + "A repository full of tools and executables designed with Microsoft's .NET ecosystem in mind.
Contains: .NET related tools and scripts": "Un repositorio lleno de herramientas y ejecutables diseñados pensando en el ecosistema .NET de Microsoft.
Contiene: herramientas y scripts relacionados con .NET", + "The universal Linux package manager for desktop applications.
Contains: Flatpak applications from configured remotes": "El gestor de paquetes universal de Linux para aplicaciones de escritorio.
Contiene: aplicaciones Flatpak de remotos configurados", + "NuPkg (zipped manifest)": "NuPkg (manifiesto comprimido)", + "The Missing Package Manager for macOS (or Linux).
Contains: Formulae, Casks": "El gestor de paquetes que faltaba para macOS (o Linux).
Contiene: Formulae, Casks", + "Node JS's package manager. Full of libraries and other utilities that orbit the javascript world
Contains: Node javascript libraries and other related utilities": "El gestor de paquetes de Node JS. Lleno de librerías y otras utilidades que orbitan el mundo de javascript
Contiene: librerías de Node javascript y otras utilidades relacionadas", + "The default package manager for Arch Linux and its derivatives.
Contains: Arch Linux packages": "El gestor de paquetes predeterminado para Arch Linux y sus derivados.
Contiene: paquetes de Arch Linux", + "Python's library manager. Full of python libraries and other python-related utilities
Contains: Python libraries and related utilities": "El gestor de librerías de Python. Lleno de librerías de python y otras utilidades relacionadas con python
Contiene: librerías de Python y utilidades relacionadas", + "PowerShell's package manager. Find libraries and scripts to expand PowerShell capabilities
Contains: Modules, Scripts, Cmdlets": "El gestor de paquetes de PowerShell. Encuentra librerías y scripts para expandir las capacidades de PowerShell
Contiene: Módulos, Scripts, Cmdlets", + "extracted": "extraído", + "Scoop package": "paquete de Scoop", + "Great repository of unknown but useful utilities and other interesting packages.
Contains: Utilities, Command-line programs, General Software (extras bucket required)": "Gran repositorio de utilidades desconocidas pero útiles y otros paquetes interesantes.
Contiene: Utilidades, programas de línea de comandos, software general (requiere el bucket extras)", + "The universal Linux package manager by Canonical.
Contains: Snap packages from the Snapcraft store": "El gestor de paquetes universal de Linux de Canonical.
Contiene: paquetes Snap de la tienda Snapcraft", + "library": "librería", + "feature": "funcionalidad", + "A popular C/C++ library manager. Full of C/C++ libraries and other C/C++-related utilities
Contains: C/C++ libraries and related utilities": "Un popular gestor de librerías de C/C++. Lleno de librerías de C/C++ y otras utilidades relacionadas con C/C++
Contiene: librerías de C/C++ y utilidades relacionadas", + "option": "opción", + "This package cannot be installed from an elevated context.": "Este paquete no puede instalarse desde un contexto elevado.", + "Please run UniGetUI as a regular user and try again.": "Por favor, ejecuta UniGetUI como un usuario normal e inténtalo de nuevo.", + "Please check the installation options for this package and try again": "Por favor, comprueba las opciones de instalación de este paquete e inténtalo de nuevo", + "Microsoft's official package manager. Full of well-known and verified packages
Contains: General Software, Microsoft Store apps": "El gestor de paquetes oficial de Microsoft. Lleno de paquetes conocidos y verificados
Contiene: Software general, aplicaciones de Microsoft Store", + "Local PC": "PC Local", + "Android Subsystem": "Subsistema de Android", + "Operation on queue (position {0})...": "Operación en cola (posición {0})...", + "Click here for more details": "Haz clic aquí para más detalles", + "Operation canceled by user": "Operación cancelada por el usuario", + "Running PreOperation ({0}/{1})...": "Ejecutando PreOperación ({0}/{1})...", + "PreOperation {0} out of {1} failed, and was tagged as necessary. Aborting...": "La PreOperación {0} de {1} falló y estaba marcada como necesaria. Abortando...", + "PreOperation {0} out of {1} finished with result {2}": "La PreOperación {0} de {1} finalizó con el resultado {2}", + "Starting operation...": "Iniciando operación...", + "Running PostOperation ({0}/{1})...": "Ejecutando PostOperación ({0}/{1})...", + "PostOperation {0} out of {1} failed, and was tagged as necessary. Aborting...": "La PostOperación {0} de {1} falló y estaba marcada como necesaria. Abortando...", + "PostOperation {0} out of {1} finished with result {2}": "La PostOperación {0} de {1} finalizó con el resultado {2}", + "{package} installer download": "Descarga del instalador de {package}", + "{0} installer is being downloaded": "Se está descargando el instalador de {0}", + "Download succeeded": "Descarga exitosa", + "{package} installer was downloaded successfully": "El instalador de {package} se descargó correctamente", + "Download failed": "Descarga fallida", + "{package} installer could not be downloaded": "No se pudo descargar el instalador de {package}", + "{package} Installation": "Instalación de {package}", + "{0} is being installed": "{0} se está instalando", + "Installation succeeded": "Instalación exitosa", + "{package} was installed successfully": "{package} se instaló correctamente", + "Installation failed": "Instalación fallida", + "{package} could not be installed": "No se pudo instalar {package}", + "{package} Update": "Actualización de {package}", + "Update succeeded": "Actualización exitosa", + "{package} was updated successfully": "{package} se actualizó correctamente", + "Update failed": "Actualización fallida", + "{package} could not be updated": "No se pudo actualizar {package}", + "{package} Uninstall": "Desinstalación de {package}", + "{0} is being uninstalled": "{0} se está desinstalando", + "Uninstall succeeded": "Desinstalación exitosa", + "{package} was uninstalled successfully": "{package} se desinstaló correctamente", + "Uninstall failed": "Desinstalación fallida", + "{package} could not be uninstalled": "No se pudo desinstalar {package}", + "Adding source {source}": "Añadiendo fuente {source}", + "Adding source {source} to {manager}": "Añadiendo fuente {source} a {manager}", + "Source added successfully": "Fuente añadida correctamente", + "The source {source} was added to {manager} successfully": "La fuente {source} se añadió a {manager} correctamente", + "Could not add source": "No se pudo añadir la fuente", + "Could not add source {source} to {manager}": "No se pudo añadir la fuente {source} a {manager}", + "Removing source {source}": "Eliminando fuente {source}", + "Removing source {source} from {manager}": "Eliminando fuente {source} de {manager}", + "Source removed successfully": "Fuente eliminada correctamente", + "The source {source} was removed from {manager} successfully": "La fuente {source} se eliminó de {manager} correctamente", + "Could not remove source": "No se pudo eliminar la fuente", + "Could not remove source {source} from {manager}": "No se pudo eliminar la fuente {source} de {manager}", + "The package manager \"{0}\" was not found": "No se encontró el gestor de paquetes \"{0}\"", + "The package manager \"{0}\" is disabled": "El gestor de paquetes \"{0}\" está deshabilitado", + "There is an error with the configuration of the package manager \"{0}\"": "Hay un error con la configuración del gestor de paquetes \"{0}\"", + "The package \"{0}\" was not found on the package manager \"{1}\"": "No se encontró el paquete \"{0}\" en el gestor de paquetes \"{1}\"", + "{0} is disabled": "{0} está deshabilitado", + "{0} weeks": "{0} semanas", + "1 month": "1 mes", + "{0} months": "{0} meses", + "Something went wrong": "Algo salió mal", + "An interal error occurred. Please view the log for further details.": "Se ha producido un error interno. Por favor, consulta el registro para más detalles.", + "No applicable installer was found for the package {0}": "No se encontró ningún instalador aplicable para el paquete {0}", + "Integrity checks will not be performed during this operation": "No se realizarán comprobaciones de integridad durante esta operación", + "This is not recommended.": "Esto no es recomendable.", + "Run now": "Ejecutar ahora", + "Run next": "Ejecutar siguiente", + "Run last": "Ejecutar último", + "Show in explorer": "Mostrar en el explorador", + "Checked": "Marcado", + "Unchecked": "Desmarcado", + "This package is already installed": "Este paquete ya está instalado", + "This package can be upgraded to version {0}": "Este paquete puede actualizarse a la versión {0}", + "Updates for this package are ignored": "Las actualizaciones de este paquete están siendo ignoradas", + "This package is being processed": "Este paquete se está procesando", + "This package is not available": "Este paquete no está disponible", + "Select the source you want to add:": "Selecciona la fuente que quieres añadir:", + "Source name:": "Nombre de la fuente:", + "Source URL:": "URL de la fuente:", + "An error occurred when adding the source: ": "Se ha producido un error al añadir la fuente: ", + "Package management made easy": "La gestión de paquetes ahora es fácil", + "version {0}": "versión {0}", + "[RAN AS ADMINISTRATOR]": "[EJECUTADO COMO ADMINISTRADOR]", + "Portable mode": "Modo portátil\n", + "DEBUG BUILD": "VERSIÓN DE DEPURACIÓN", + "Here you can change UniGetUI's behaviour regarding the following shortcuts. Checking a shortcut will make UniGetUI delete it if if gets created on a future upgrade. Unchecking it will keep the shortcut intact": "Aquí puedes cambiar el comportamiento de UniGetUI respecto a los siguientes accesos directos. Marcar un acceso directo hará que UniGetUI lo elimine si se crea en una futura actualización. Desmarcarlo mantendrá el acceso directo intacto", + "Manual scan": "Escaneo manual", + "Existing shortcuts on your desktop will be scanned, and you will need to pick which ones to keep and which ones to remove.": "Se escanearán los accesos directos existentes en tu escritorio y tendrás que elegir cuáles mantener y cuáles eliminar.", + "Delete?": "¿Eliminar?", + "I understand": "Entiendo", + "Chocolatey setup changed": "La configuración de Chocolatey ha cambiado", + "UniGetUI no longer includes its own private Chocolatey installation. A legacy UniGetUI-managed Chocolatey installation was detected for this user profile, but system Chocolatey was not found. Chocolatey will stay unavailable in UniGetUI until Chocolatey is installed on the system and UniGetUI is restarted. Applications previously installed through UniGetUI's bundled Chocolatey may still appear under other sources such as Local PC or WinGet.": "UniGetUI ya no incluye su propia instalación privada de Chocolatey. Se ha detectado una instalación de Chocolatey heredada gestionada por UniGetUI para este perfil de usuario, pero no se encontró Chocolatey en el sistema. Chocolatey seguirá no estando disponible en UniGetUI hasta que Chocolatey se instale en el sistema y se reinicie UniGetUI. Las aplicaciones instaladas previamente a través del Chocolatey incluido en UniGetUI pueden seguir apareciendo en otras fuentes como PC Local o WinGet.", + "NOTE: This troubleshooter can be disabled from UniGetUI Settings, on the WinGet section": "NOTA: Este solucionador de problemas se puede deshabilitar en la Configuración de UniGetUI, en la sección de WinGet", + "Restart": "Reiniciar", + "Are you sure you want to delete all shortcuts?": "¿Estás seguro de que quieres eliminar todos los accesos directos?", + "Any new shorcuts created during an install or an update operation will be deleted automatically, instead of showing a confirmation prompt the first time they are detected.": "Cualquier nuevo acceso directo creado durante una operación de instalación o actualización se eliminará automáticamente, en lugar de mostrar un aviso de confirmación la primera vez que se detecten.", + "Any shorcuts created or modified outside of UniGetUI will be ignored. You will be able to add them via the {0} button.": "Cualquier acceso directo creado o modificado fuera de UniGetUI será ignorado. Podrás añadirlos a través del botón {0}.", + "Are you really sure you want to enable this feature?": "¿Estás realmente seguro de que quieres habilitar esta función?", + "No new shortcuts were found during the scan.": "No se encontraron nuevos accesos directos durante el escaneo.", + "How to add packages to a bundle": "Cómo añadir paquetes a un lote", + "In order to add packages to a bundle, you will need to: ": "Para añadir paquetes a un lote, deberás:", + "1. Navigate to the \"{0}\" or \"{1}\" page.": "1. Navegar a la página \"{0}\" o \"{1}\".", + "2. Locate the package(s) you want to add to the bundle, and select their leftmost checkbox.": "2. Localizar el paquete o paquetes que quieras añadir al lote y seleccionar la casilla de verificación situada más a la izquierda.", + "3. When the packages you want to add to the bundle are selected, find and click the option \"{0}\" on the toolbar.": "3. Cuando los paquetes que quieras añadir al lote estén seleccionados, busca y haz clic en la opción \"{0}\" de la barra de herramientas.", + "4. Your packages will have been added to the bundle. You can continue adding packages, or export the bundle.": "4. Tus paquetes habrán sido añadidos al lote. Puedes continuar añadiendo paquetes o exportar el lote.", + "Which backup do you want to open?": "¿Qué copia de seguridad quieres abrir?", + "Select the backup you want to open. Later, you will be able to review which packages you want to install.": "Selecciona la copia de seguridad que quieras abrir. Más adelante, podrás revisar qué paquetes/programas quieres restaurar.", + "There are ongoing operations. Quitting UniGetUI may cause them to fail. Do you want to continue?": "Hay operaciones en curso. Salir de UniGetUI puede hacer que fallen. ¿Quieres continuar?", + "UniGetUI or some of its components are missing or corrupt.": "UniGetUI o algunos de sus componentes faltan o están corruptos.", + "It is strongly recommended to reinstall UniGetUI to adress the situation.": "Se recomienda encarecidamente reinstalar UniGetUI para solucionar la situación.", + "Refer to the UniGetUI Logs to get more details regarding the affected file(s)": "Consulta los registros de UniGetUI para obtener más detalles sobre el archivo o archivos afectados", + "Integrity checks can be disabled from the Experimental Settings": "Las comprobaciones de integridad se pueden deshabilitar en los Ajustes Experimentales", + "Repair UniGetUI": "Reparar UniGetUI", + "Live output": "Salida en vivo", + "This package bundle had some settings that are potentially dangerous, and may be ignored by default.": "Este lote de paquetes tenía algunos ajustes potencialmente peligrosos y pueden ser ignorados por defecto.", + "Entries that show in YELLOW will be IGNORED.": "Las entradas que aparezcan en AMARILLO serán IGNORADAS.", + "Entries that show in RED will be IMPORTED.": "Las entradas que aparezcan en ROJO serán IMPORTADAS.", + "You can change this behavior on UniGetUI security settings.": "Puedes cambiar este comportamiento en los ajustes de seguridad de UniGetUI.", + "Open UniGetUI security settings": "Abrir ajustes de seguridad de UniGetUI", + "Should you modify the security settings, you will need to open the bundle again for the changes to take effect.": "Si modificas los ajustes de seguridad, tendrás que abrir el lote de nuevo para que los cambios surtan efecto.", + "Details of the report:": "Detalles del informe:", + "Are you sure you want to create a new package bundle? ": "¿Estás seguro de que quieres crear un nuevo lote de paquetes? ", + "Any unsaved changes will be lost": "Cualquier cambio no guardado se perderá", + "Warning!": "¡Advertencia!", + "For security reasons, custom command-line arguments are disabled by default. Go to UniGetUI security settings to change this. ": "Por razones de seguridad, los argumentos de línea de comandos personalizados están deshabilitados por defecto. Ve a los ajustes de seguridad de UniGetUI para cambiar esto. ", + "Change default options": "Cambiar opciones predeterminadas", + "Ignore future updates for this package": "Ignorar futuras actualizaciones para este paquete", + "For security reasons, pre-operation and post-operation scripts are disabled by default. Go to UniGetUI security settings to change this. ": "Por razones de seguridad, los scripts de preoperación y postoperación están deshabilitados por defecto. Ve a los ajustes de seguridad de UniGetUI para cambiar esto. ", + "You can define the commands that will be run before or after this package is installed, updated or uninstalled. They will be run on a command prompt, so CMD scripts will work here.": "Puedes definir los comandos que se ejecutarán antes o después de que este paquete se instale, actualice o desinstale. Se ejecutarán en un símbolo del sistema, por lo que los scripts de CMD funcionarán aquí.", + "Change this and unlock": "Cambiar esto y desbloquear", + "{0} Install options are currently locked because {0} follows the default install options.": "Las opciones de instalación de {0} están bloqueadas actualmente porque {0} sigue las opciones de instalación predeterminadas.", + "Unset or unknown": "No establecido o desconocido", + "This package has no screenshots or is missing the icon? Contrbute to UniGetUI by adding the missing icons and screenshots to our open, public database.": "¿Este paquete no tiene capturas de pantalla o le falta el icono? Contribuye a UniGetUI añadiendo los iconos y capturas faltantes a nuestra base de datos pública y abierta.", + "Become a contributor": "Convertirse en colaborador", + "Update to {0} available": "Actualización a {0} disponible", + "Reinstall": "Reinstalar", + "Installer not available": "Instalador no disponible", + "Version:": "Versión:", + "UniGetUI Version {0}": "UniGetUI Versión {0}", + "Performing backup, please wait...": "Realizando copia de seguridad, por favor espera...", + "An error occurred while logging in: ": "Se ha producido un error al iniciar sesión: ", + "Fetching available backups...": "Obteniendo copias de seguridad disponibles...", + "Done!": "¡Hecho!", + "The cloud backup has been loaded successfully.": "La copia de seguridad en la nube se ha cargado correctamente.", + "An error occurred while loading a backup: ": "Se ha producido un error al cargar una copia de seguridad: ", + "Backing up packages to GitHub Gist...": "Copiando paquetes a GitHub Gist...", + "Backup Successful": "Copia de seguridad realizada con éxito", + "The cloud backup completed successfully.": "La copia de seguridad en la nube se completó correctamente.", + "Could not back up packages to GitHub Gist: ": "No se pudieron copiar los paquetes a GitHub Gist: ", + "It is not guaranteed that the provided credentials will be stored safely, so you may as well not use the credentials of your bank account": "No se garantiza que las credenciales proporcionadas se almacenen de forma segura, por lo que es mejor no usar las credenciales de tu cuenta bancaria", + "Enable the automatic WinGet troubleshooter": "Habilitar el solucionador de problemas automático de WinGet", + "Add updates that fail with a 'no applicable update found' to the ignored updates list": "Añadir a la lista de actualizaciones ignoradas aquellas que fallen con el mensaje 'no se encontró ninguna actualización aplicable'.", + "Invalid selection": "Selección inválida", + "No package was selected": "No se ha seleccionado ningún paquete", + "More than 1 package was selected": "Se ha seleccionado más de 1 paquete", + "List": "Lista", + "Grid": "Cuadrícula", + "Icons": "Iconos", + "\"{0}\" is a local package and does not have available details": "\"{0}\" es un paquete local y no tiene detalles disponibles", + "\"{0}\" is a local package and is not compatible with this feature": "\"{0}\" es un paquete local y no es compatible con esta función", + "Add packages to bundle": "Añadir paquetes al lote", + "Preparing packages, please wait...": "Preparando paquetes, por favor espera...", + "Loading packages, please wait...": "Cargando paquetes, por favor espera...", + "Saving packages, please wait...": "Guardando paquetes, por favor espera...", + "The bundle was created successfully on {0}": "El lote se creó correctamente el {0}", + "User profile": "Perfil de usuario", + "Error": "Error", + "Log in failed: ": "Error al iniciar sesión: ", + "Log out failed: ": "Error al cerrar sesión: ", + "Package backup settings": "Ajustes de copia de seguridad de paquetes", + "Show the release notes after UniGetUI is updated": "Mostrar las notas de la versión después de actualizar UniGetUI" +} diff --git a/src/Languages/lang_et.json b/src/Languages/lang_et.json new file mode 100644 index 0000000..b0a67cf --- /dev/null +++ b/src/Languages/lang_et.json @@ -0,0 +1,850 @@ +{ + "{0} of {1} operations completed": "{0} toimingut {1}-st lõpetatud", + "{0} is now {1}": "{0} on nüüd {1}", + "Enabled": "Lubatud", + "Disabled": "Keelatud", + "Privacy": "Privaatsus", + "Hide my username from the logs": "Peida minu kasutajanimi logidest", + "Replaces your username with **** in the logs. Restart UniGetUI to also hide it from already-recorded entries.": "Asendab logides sinu kasutajanime sümbolitega ****. Taaskäivita UniGetUI, et peita see ka juba salvestatud kirjetest.", + "Your last update attempt did not complete.": "Teie viimane uuendamiskatse ei jõudnud lõpule.", + "UniGetUI could not confirm whether the update succeeded. Open the log to see what happened.": "UniGetUI ei saanud kinnitada, kas uuendamine õnnestus. Avage logi, et näha, mis juhtus.", + "View log": "Vaata logi", + "The installer reported success but did not restart UniGetUI.": "Paigaldaja teatas õnnestumisest, kuid ei taaskäivitanud UniGetUI-d.", + "The installer failed to initialize.": "Paigaldaja lähtestamine nurjus.", + "Setup was canceled before installation began.": "Seadistus tühistati enne paigaldamise algust.", + "A fatal error occurred during the preparation phase.": "Ettevalmistusetapis ilmnes kriitiline tõrge.", + "A fatal error occurred during installation.": "Paigaldamise ajal ilmnes kriitiline tõrge.", + "Installation was canceled while in progress.": "Paigaldamine tühistati selle toimumise ajal.", + "The installer was terminated by another process.": "Teine protsess lõpetas paigaldaja töö.", + "The preparation phase determined the installation cannot proceed.": "Ettevalmistusetapis tuvastati, et paigaldamist ei saa jätkata.", + "The installer could not start. UniGetUI may already be running, or you do not have permission to install.": "Paigaldajat ei saanud käivitada. UniGetUI võib juba töötada või teil pole paigaldamiseks õigusi.", + "Unexpected installer error.": "Ootamatu paigaldaja tõrge.", + "We are checking for updates.": "Me kontrollime uuendusi.", + "Please wait": "Palun oodake", + "Great! You are on the latest version.": "Suurepärane! Sul on uusim versioon.", + "There are no new UniGetUI versions to be installed": "Uusi UniGetUI versioone pole paigaldamiseks", + "UniGetUI version {0} is being downloaded.": "UniGetUI versiooni {0} laaditakse alla.", + "This may take a minute or two": "See võib võtta ühe või kahe minuti", + "The installer authenticity could not be verified.": "Paigaldaja autentsust ei õnnestunud kontrollida.", + "The update process has been aborted.": "Uuendamise protsess oli katkestatud", + "Auto-update is not yet available on this platform.": "Automaatne uuendamine pole sellel platvormil veel saadaval.", + "Please update UniGetUI manually.": "Palun uuendage UniGetUI-d käsitsi.", + "An error occurred when checking for updates: ": "Uuenduste kontrollimisel tekkis viga:", + "The updater could not be launched.": "Uuendajat ei saanud käivitada.", + "The operating system did not start the installer process.": "Operatsioonisüsteem ei käivitanud paigaldaja protsessi.", + "UniGetUI is being updated...": "UniGetUI uuendatakse...", + "Update installed.": "Uuendus paigaldatud.", + "UniGetUI was updated successfully, but this running copy was not replaced. This usually means you are running a development build. Close this copy and start the newly-installed version to finish.": "UniGetUI uuendati edukalt, kuid seda töötavat koopiat ei asendatud. Tavaliselt tähendab see, et kasutate arendusversiooni. Lõpetamiseks sulgege see koopia ja käivitage äsja paigaldatud versioon.", + "The update could not be applied.": "Uuendust ei saanud rakendada.", + "Installer exit code {0}: {1}": "Paigaldaja väljumiskood {0}: {1}", + "Update cancelled.": "Uuendamine tühistati.", + "Authentication was cancelled.": "Autentimine tühistati.", + "Installer exit code {0}": "Paigaldaja väljumiskood {0}", + "Operation in progress": "Toiming on käimas", + "Please wait...": "Palun oodake...", + "Success!": "Õnnestus!", + "Failed": "Ebaõnnestus", + "An error occurred while processing this package": "Selle paketi töötlemisel tekkis viga", + "Installer": "Paigaldaja", + "Executable": "Käivitatav fail", + "MSI": "MSI", + "Compressed file": "Tihendatud fail", + "MSIX": "MSIX", + "WinGet was repaired successfully": "WinGet parandati edukalt", + "It is recommended to restart UniGetUI after WinGet has been repaired": "Pärast WinGeti parandamist on soovitatav UniGetUI taaskäivitada", + "WinGet could not be repaired": "WinGetit ei saanud parandada", + "An unexpected issue occurred while attempting to repair WinGet. Please try again later": "WinGeti parandamise katsel tekkis ootamatu probleem. Palun proovige hiljem uuesti", + "Log in to enable cloud backup": "Logige sisse, et lubada pilvevarundus", + "Backup Failed": "Varukoopia ebaõnnestus", + "Downloading backup...": "Varukoopiafaili allalaadimine...", + "An update was found!": "Uuendus on leitud!", + "{0} can be updated to version {1}": "{0} saab uuendada versioonini {1}", + "Updates found!": "Uuendused leitud!", + "{0} packages can be updated": "{0} paketti saab uuendada", + "{0} is being updated to version {1}": "{0} uuendatakse versioonini {1}", + "{0} packages are being updated": "{0} paketti uuendatakse", + "You have currently version {0} installed": "Praegune rakenduse versioon on {0}", + "Desktop shortcut created": "Töölaua otsetee loodud", + "UniGetUI has detected a new desktop shortcut that can be deleted automatically.": "UniGetUI tuvasta uue töölaua otsetee, mida saab automaatselt kustutada.", + "{0} desktop shortcuts created": "{0} töölaua otseteed loodud", + "UniGetUI has detected {0} new desktop shortcuts that can be deleted automatically.": "UniGetUI tuvastas {0} uut töölaua otseteed, mida saab automaatselt kustutada.", + "Attention required": "Tähelepanu nõutud", + "Restart required": "Taaskäivitamine on vajalik", + "1 update is available": "Üks uuendus on kättesaadav", + "{0} updates are available": "{0} {0, plural, one {uuendus} few {uuendust} other {uuendust}} on kättesaadaval", + "Everything is up to date": "Kõik on ajakohane", + "Discover Packages": "Uurige pakette", + "Available Updates": "Kättesaadavad uuendused", + "Installed Packages": "Paigaldatud paketid", + "UniGetUI Version {0} by Devolutions": "UniGetUI versioon {0}, autor Devolutions", + "Show UniGetUI": "Näita UniGetUI", + "Quit": "Välju", + "Are you sure?": "Olete kindel?", + "Do you really want to uninstall {0}?": "Kas te tõesti soovite eemaldada {0}?", + "Do you really want to uninstall the following {0} packages?": "Kas te tõesti soovite eemaldada {0, plural, one {järgmine pakett} few {järgmised {0} paketid} other {järgmised {0} paketid}}?", + "No": "Ei", + "Yes": "Jah", + "Partial": "Osaline", + "View on UniGetUI": "Vaata UniGetUI-l", + "Update": "Uuenda", + "Open UniGetUI": "Ava UniGetUI", + "Update all": "Uuenda kõik", + "Update now": "Uuenda koheselt", + "Installer host changed since the installed version.\n": "Paigaldaja host on pärast paigaldatud versiooni muutunud.\n", + "This package is on the queue": "See pakett on järjekorras", + "installing": "paigaldatakse", + "updating": "uuendatakse", + "uninstalling": "eemaldatakse", + "installed": "paigaldatud", + "Retry": "Proovi uuesti", + "Install": "Paigalda", + "Uninstall": "Eemalda", + "Open": "Ava", + "Operation profile:": "Toiminguprofiil:", + "Follow the default options when installing, upgrading or uninstalling this package": "Järgi paketi paigaldamisel, uuendamisel või eemaldamisel vaikimisi valikuid.", + "The following settings will be applied each time this package is installed, updated or removed.": "Järgmisi seadeid rakendatakse iga kord, kui see pakett on paigaldatud, uuendatud või eemaldatud.", + "Version to install:": "Versioon paigaldamiseks:", + "Architecture to install:": "Paigaldamisarhitektuur:", + "Installation scope:": "Paigaldamise ulatus:", + "Install location:": "Paigaldamiskoht:", + "Select": "Vali", + "Reset": "Lähtesta", + "Custom install arguments:": "Kohandatud paigaldamise argumendid:", + "Custom update arguments:": "Kohandatud uuendamise argumendid:", + "Custom uninstall arguments:": "Kohandatud eemaldamise argumendid:", + "Pre-install command:": "Paigaldus-eelne käsk:", + "Post-install command:": "Paigaldus-järgne käsk:", + "Abort install if pre-install command fails": "Katkesta paigaldamine kui eelnev käsk nurjub", + "Pre-update command:": "Uuenduse-eelne käsk:", + "Post-update command:": "Uuenduse-järgne käsk:", + "Abort update if pre-update command fails": "Katkesta uuendamine kui eelnev käsk nurjub", + "Pre-uninstall command:": "Eemaldamise eelne käsk:", + "Post-uninstall command:": "Eemaldamise järgne käsk:", + "Abort uninstall if pre-uninstall command fails": "Katkesta eemaldamine kui eelnev käsk nurjub", + "Command-line to run:": "Käitatav käsurea rida:", + "Save and close": "Salvesta ja sule", + "General": "Üldine", + "Architecture & Location": "Arhitektuur ja asukoht", + "Command-line": "Käsurida", + "Close apps": "Sule rakendused", + "Pre/Post install": "Enne/pärast paigaldamist", + "Select the processes that should be closed before this package is installed, updated or uninstalled.": "Valige protsessid, mis tuleb sulgeda enne selle paketi paigaldamist, uuendamist või eemaldamist.", + "Write here the process names here, separated by commas (,)": "Kirjutage siia protsesside nimed, eraldatuna komadega (,)", + "Try to kill the processes that refuse to close when requested to": "Proovige tappa protsessid, mis keelduvad sulgemast, kui seda palutakse", + "Run as admin": "Käivita administraatorina", + "Interactive installation": "Interaktiivne paigaldus", + "Skip hash check": "Jäta räsikontroll vahele", + "Uninstall previous versions when updated": "Eemalda eelmised versioonid pärast uuendamist", + "Skip minor updates for this package": "Jäta väiksemad uuendused selle paketi jaoks vahele", + "Automatically update this package": "Uuenda seda paketti automaatselt", + "{0} installation options": "{0} paigaldamise seaded", + "Latest": "Uusim", + "PreRelease": "EeelVäljalaske", + "Default": "Vaikimisi", + "Manage ignored updates": "Halda eiratavaid uuendusi", + "The packages listed here won't be taken in account when checking for updates. Double-click them or click the button on their right to stop ignoring their updates.": "Siin loetletud pakette ei võeta arvesse uuenduste kontrollimisel. Topeltvajutage neid või vajutage nende paremal olevat nuppu, et lõpetada nende uuenduste ignoreerimine.", + "Reset list": "Lähtesta nimekiri", + "Do you really want to reset the ignored updates list? This action cannot be reverted": "Kas soovite tõesti eiratud uuenduste loendi lähtestada? Seda toimingut ei saa tagasi võtta.", + "No ignored updates": "Eiratud uuendusi pole", + "Package Name": "Paketi nimetus", + "Package ID": "Paketi ID", + "Ignored version": "Eiratav versioon", + "New version": "Uus versioon", + "Source": "Allikas", + "All versions": "Kõik versioonid", + "Unknown": "Teadmata", + "Up to date": "Ajakohane", + "Package {name} from {manager}": "Pakett {name} haldurilt {manager}", + "Remove {0} from ignored updates": "Eemalda {0} eiratud uuendustest", + "Cancel": "Tühista", + "Administrator privileges": "Administraatori õigused", + "This operation is running with administrator privileges.": "See toiming käivitatakse administraatori õigustega.", + "Interactive operation": "Interaktiivne toiming", + "This operation is running interactively.": "See toiming käivitatakse interaktiivselt.", + "You will likely need to interact with the installer.": "Tõenäoliselt peate paigaldajat kasutama.", + "Integrity checks skipped": "Terviklikkusekontrollid vahele jäetud", + "Integrity checks will not be performed during this operation.": "Selle toimingu ajal terviklusekontrolle ei tehta.", + "Proceed at your own risk.": "Jätkake omal vastutusel.", + "Close": "Sule", + "Loading...": "Laeb...", + "Installer SHA256": "Paigaldaja SHA256", + "Homepage": "kodulehekülg", + "Author": "Looja", + "Publisher": "Kirjastaja", + "License": "Litsents", + "Manifest": "Manifest", + "Installer Type": "Paigaldaja tüüp", + "Size": "Suurus", + "Installer URL": "Paigaldaja URL", + "Last updated:": "Viimati uuendatud:", + "Release notes URL": "Väljalase märkmete URL", + "Package details": "Paketi info", + "Dependencies:": "Sõltuvused:", + "Release notes": "Väljalase märkmed", + "Screenshots": "Kuvatõmmised", + "This package has no screenshots or is missing the icon? Contribute to UniGetUI by adding the missing icons and screenshots to our open, public database.": "Kas sellel paketil pole kuvatõmmiseid või puudub selle ikoon? Panusta UniGetUI-sse, lisades puuduvad ikoonid ja kuvatõmmised meie avatud avalikku andmebaasi.", + "Version": "Versioon", + "Install as administrator": "Paigalda administraatori nimelt", + "Update to version {0}": "Uuenda versioonile {0}", + "Installed Version": "Paigaldatud versioon:", + "Update as administrator": "Uuenda administraatorina", + "Interactive update": "Interaktiivne uuendus", + "Uninstall as administrator": "Eemalda administraatorina", + "Interactive uninstall": "Interaktiivne kustutamine", + "Uninstall and remove data": "Eemalda ja kustuta andmed", + "Not available": "Pole saadaval", + "Installer SHA512": "Paigaldaja SHA512", + "Unknown size": "Teadmata suurus", + "No dependencies specified": "Sõltuvused pole märgitud", + "mandatory": "kohustuslik", + "optional": "valikuline", + "UniGetUI {0} is ready to be installed.": "UniGetUI {0} on paigaldamiseks valmis.", + "The update process will start after closing UniGetUI": "Uuendamisprotsess algab UniGetUI sulgemise järel", + "UniGetUI has been ran as administrator, which is not recommended. When running UniGetUI as administrator, EVERY operation launched from UniGetUI will have administrator privileges. You can still use the program, but we highly recommend not running UniGetUI with administrator privileges.": "UniGetUI on käivitatud administraatorina, mis ei ole soovitatav. Kui käivitate UniGetUI administraatorina, on KÕIGIL UniGetUI-st käivitatud toimingutel administraatoriõigused. Saate programmi endiselt kasutada, kuid soovitame tungivalt UniGetUI-d mitte administraatoriõigustega käivitada.", + "Share anonymous usage data": "Jaga anonüümset kasutusstatistikat", + "UniGetUI collects anonymous usage data in order to improve the user experience.": "UniGetUI kogub kasutaja kogemuse parandamiseks anonüümset kasutusstatistikat.", + "Accept": "Nõustu", + "Software Updates": "Tarkvara uuendused", + "Package Bundles": "Pakettide kimbud", + "Settings": "Seaded", + "Package Managers": "Paketihaldurid", + "UniGetUI Log": "UniGetUI logi", + "Package Manager logs": "Paketihalduri logid", + "Operation history": "Toiminguajalugu", + "Help": "Abi", + "UniGetUI": "UniGetUI", + "You have installed UniGetUI Version {0}": "Te olete paigaldanud UniGetUI versiooni {0}", + "Disclaimer": "Lahtiütlus", + "UniGetUI is developed by Devolutions and is not affiliated with any of the compatible package managers.": "UniGetUI-d arendab Devolutions ja see ei ole seotud ühegi ühilduva paketihalduriga.", + "UniGetUI wouldn't have been possible without the help of the contributors. Thank you all 🥳": "UniGetUI poleks olnud võimalik ilma panustajate abita. Tänan teid kõiki 🥳", + "UniGetUI uses the following libraries. Without them, UniGetUI wouldn't have been possible.": "UniGetUI kasutab järgmisi teeke. Ilma nendeta ei oleks UniGetUI võimalik.", + "{0} homepage": "{0} kodulehekülg", + "UniGetUI has been translated to more than 40 languages thanks to the volunteer translators. Thank you 🤝": "Tänu vabatahtlikele tõlkijatele on UniGetUI tõlgitud rohkem kui 40 keelde. Tänan teid 🤝", + "Verbose": "Paljusõnaline", + "1 - Errors": "1 - Vead", + "2 - Warnings": "2 - Hoiatused", + "3 - Information (less)": "3 - Teave (vähem)", + "4 - Information (more)": "4 - Teave (rohkem)", + "5 - information (debug)": "5 - teave (silumine)", + "Warning": "Hoiatus", + "The following settings may pose a security risk, hence they are disabled by default.": "Järgmised seaded võivad kujutada endast turvariski, seega on need vaikimisi keelatud.", + "Enable the settings below if and only if you fully understand what they do, and the implications they may have.": "Lubage alltoodud seaded siis ja ainult siis, kui te täielikult mõistate, mida need teevad, ja milliseid tagajärgi neil võib olla.", + "The settings will list, in their descriptions, the potential security issues they may have.": "Seaded loetlevad nende kirjeldustes, millised turvalisuse probleemid neil võivad olla.", + "The backup will include the complete list of the installed packages and their installation options. Ignored updates and skipped versions will also be saved.": "Varukoopia sisaldab paigaldatud pakettide täielikku loendit ja nende paigaldamisvõimalusi. Salvestatakse ka ignoreeritud uuendusi ja vahele jäetud versioone.", + "The backup will NOT include any binary file nor any program's saved data.": "Varukoopia EI sisalda ühtegi binaarfaili ega programmi salvestatud andmeid.", + "The size of the backup is estimated to be less than 1MB.": "Varukoopia suurus on hinnanguliselt alla 1MB.", + "The backup will be performed after login.": "Varukoopia tehakse pärast sisselogimist.", + "{pcName} installed packages": "{pcName} paigaldatud paketid", + "Current status: Not logged in": "Praegune olek: pole sisse logitud", + "You are logged in as {0} (@{1})": "Te olete sisse logitud kui {0} (@{1})", + "Nice! Backups will be uploaded to a private gist on your account": "Tore! Varukoopiad laaditakse üles teie konto privaatsesse gisti.", + "Select backup": "Valige varundus", + "Settings imported from {0}": "Seaded imporditud kohast {0}", + "UniGetUI Settings": "UniGetUI seaded", + "Settings exported to {0}": "Seaded eksporditud kohta {0}", + "UniGetUI settings were reset": "UniGetUI seaded on lähtestatud", + "Allow pre-release versions": "Luba väljalaske-eelsed versioonid", + "Apply": "Rakenda", + "For security reasons, custom command-line arguments are disabled by default. Go to UniGetUI security settings to change this.": "Turvakaalutlustel on kohandatud käsureaargumendid vaikimisi keelatud. Selle muutmiseks avage UniGetUI turvaseaded.", + "Go to UniGetUI security settings": "Avage UniGetUI turvaseaded", + "The following options will be applied by default each time a {0} package is installed, upgraded or uninstalled.": "Järgmised valikud rakendatakse vaikimisi iga kord, kui {0} pakett paigaldatakse, uuendatakse või eemaldatakse.", + "Package's default": "Paketi vaikepositsioon", + "Install location can't be changed for {0} packages": "Paigaldamiskohta ei saa muuta {0} pakettides", + "The local icon cache currently takes {0} MB": "Kohalik ikoonide vahemälu võtab praegu {0} MB", + "Username": "Kasutajanimi", + "Password": "Parool", + "Credentials": "Kasutajatunnused", + "It is not guaranteed that the provided credentials will be stored safely": "Pole garanteeritud, et esitatud mandaadid salvestatakse turvaliselt.", + "Partially": "Osaliselt", + "Package manager": "Pakettihaldur", + "Compatible with proxy": "Ühilduv puhverservega", + "Compatible with authentication": "Ühilduv autentimisega", + "Proxy compatibility table": "Puhvri ühilduvustabel", + "{0} settings": "{0} seaded", + "{0} status": "{0} olek", + "Default installation options for {0} packages": "Vaikimisi paigaldamise seaded {0} pakettide jaoks", + "Expand version": "Laienda versioon", + "The executable file for {0} was not found": "Käivitatavat faili {0} jaoks ei leitud", + "{pm} is disabled": "{pm} on keelatud", + "Enable it to install packages from {pm}.": "Luba see pakettide paigaldamiseks {pm}-st.", + "{pm} is enabled and ready to go": "{pm} on lubatud ja valmis", + "{pm} version:": "{pm} versioon:", + "{pm} was not found!": "{pm} ei leitud!", + "You may need to install {pm} in order to use it with UniGetUI.": "Peate võib-olla paigaldama {pm}, et seda UniGetUI-ga kasutada.", + "Scoop Installer - UniGetUI": "Scoopi paigaldaja - UniGetUI", + "Scoop Uninstaller - UniGetUI": "Scoopi eemaldaja - UniGetUI", + "Clearing Scoop cache - UniGetUI": "Scoop'i vahemälu kustutamine - UniGetUI", + "Restart UniGetUI to fully apply changes": "Muudatuste täielikuks rakendamiseks taaskäivitage UniGetUI", + "Restart UniGetUI": "Taaskäivita UniGetUI", + "Manage {0} sources": "Halda {0} allikat", + "Add source": "Lisa allikas", + "Add": "Lisa", + "Source name": "Allika nimi", + "Source URL": "Allika URL", + "Other": "Muu", + "No minimum age": "Minimaalne vanus puudub", + "1 day": "Üks päev", + "{0} days": "{0} {0, plural,\n=0 {päeva}\none {päev}\nother {päeva}\n}", + "Custom...": "Kohandatud...", + "{0} minutes": "{0} {0, plural,\n=0 {minutit}\none {minut}\nother {minutit}\n}", + "1 hour": "Üks tund", + "{0} hours": "{0} {0, plural,\n=0 {tundi}\none {tund}\nother {tundi}\n}", + "1 week": "Üks nädal", + "Supports release dates": "Toetab väljalaskekuupäevi", + "Release date support per package manager": "Väljalaskekuupäevade tugi paketihalduri kaupa", + "Search for packages": "Otsi paketid", + "Local": "Lokaalne", + "OK": "Okei", + "Last checked: {0}": "Viimati kontrollitud: {0}", + "{0} packages were found, {1} of which match the specified filters.": "{0} {0, plural,\n=0 {paketti on leitud}\none {pakett on leitud}\nother {paketti on leitud}}, millest {1} {1, plural,\n=0 {vastavad}\none {vastab}\nother {vastavad}} määratud filtrile", + "{0} selected": "{0} valitud", + "(Last checked: {0})": "(Viimati kontrollitud: {0})", + "All packages selected": "Kõik paketid valitud", + "Package selection cleared": "Paketi valik tühjendatud", + "{0}: {1}": "{0}: {1}", + "More info": "Lisainfo", + "GitHub account": "GitHubi konto", + "Log in with GitHub to enable cloud package backup.": "Logige sisse GitHub-ga, et lubada pilvepaketikambaaeg.", + "More details": "Rohkem detaile", + "Log in": "Logi sisse", + "If you have cloud backup enabled, it will be saved as a GitHub Gist on this account": "Kui teil on pilvevarundus aktiveeritud, salvestatakse see GitHub Gistina sellele kontole.", + "Log out": "Logi välja", + "About UniGetUI": "UniGetUI teave", + "About": "Rakendusest", + "Third-party licenses": "Kolmandate osapoolte litsentsid", + "Contributors": "Panustajad", + "Translators": "Tõlkijad", + "Bundle security report": "Kimbu turvaseadused aruanne", + "The bundle contained restricted content": "Kogum sisaldas piiratud sisu", + "UniGetUI – Crash Report": "UniGetUI – kokkujooksmise aruanne", + "UniGetUI has crashed": "UniGetUI jooksis kokku", + "Help us fix this by sending a crash report to Devolutions. All fields below are optional.": "Aidake meil seda parandada, saates kokkujooksmise aruande Devolutionsile. Kõik allolevad väljad on valikulised.", + "Email (optional)": "E-post (valikuline)", + "your@email.com": "teie@email.com", + "Additional details (optional)": "Lisainfo (valikuline)", + "Describe what you were doing when the crash occurred…": "Kirjeldage, mida te tegite, kui kokkujooksmine toimus…", + "Crash report": "Kokkujooksmise aruanne", + "Don't Send": "Ära saada", + "Send Report": "Saada aruanne", + "Sending…": "Saatmine…", + "Unsaved changes": "Salvestamata muudatused", + "You have unsaved changes in the current bundle. Do you want to discard them?": "Praeguses kogumis on salvestamata muudatusi. Kas soovite neist loobuda?", + "Discard changes": "Loobu muudatustest", + "Integrity violation": "Terviklikkuse rikkumine", + "UniGetUI or some of its components are missing or corrupt. It is strongly recommended to reinstall UniGetUI to adress the situation.": "UniGetUI või mõni selle komponent puudub või on rikutud. Olukorra lahendamiseks on tungivalt soovitatav UniGetUI uuesti paigaldada.", + "• Refer to the UniGetUI Logs to get more details regarding the affected file(s)": "• Viidake UniGetUI logidele, et saada rohkem teavet mõjutatud faili(de) kohta", + "• Integrity checks can be disabled from the Experimental Settings": "• Terviklikkusekontrolle saab keelata Eksperimentaal Seadetest", + "Manage shortcuts": "Halda otseteid", + "UniGetUI has detected the following desktop shortcuts which can be removed automatically on future upgrades": "UniGetUI tootas järgmisi töölauale otseteed, mida saab tulevaste uuenduste puhul automaatselt eemaldada", + "Do you really want to reset this list? This action cannot be reverted.": "Kas te tõesti soovite seda loendit lähtestada? Seda toimingut ei saa tagasi pöörata.", + "Desktop shortcuts list": "Töölaua otseteede nimekiri", + "Open in explorer": "Ava Exploreris", + "Remove from list": "Eemalda nimekirjast", + "When new shortcuts are detected, delete them automatically instead of showing this dialog.": "Kui uued otseteed tuvastatakse, kustutatakse nad automaatselt selle dialoogi kuvamise asemel.", + "Not right now": "Mitte praegu", + "Missing dependency": "Puudub sõltuvus", + "UniGetUI requires {0} to operate, but it was not found on your system.": "UniGetUI töötamiseks on vaja {0}, kuid seda ei leitud teie süsteemist.", + "Click on Install to begin the installation process. If you skip the installation, UniGetUI may not work as expected.": "Paigaldamisprotsessi alustamiseks vajutage nuppu \"Paigalda\". Kui jätate paigalduse vahele, ei pruugi UniGetUI töötada ootuspäraselt.", + "Alternatively, you can also install {0} by running the following command in a Windows PowerShell prompt:": "Teise võimalusena saate paigaldada {0}, käivitades järgmise käsu Windows PowerShelli kujul:", + "Install {0}": "Paigalda {0}", + "Do not show this dialog again for {0}": "Ära näita seda dialoogi enam {0} jaoks", + "Please wait while {0} is being installed. A black window may show up. Please wait until it closes.": "Palun oodake, kuni {0} paigaldub. Võib ilmneda must (või sinine) aken. Palun oodake selle sulgemiseni.", + "{0} has been installed successfully.": "{0} oli edukalt paigaldatud", + "Please click on \"Continue\" to continue": "Klõpsake \"Jätka\" jätkamiseks", + "Continue": "Jätka", + "{0} has been installed successfully. It is recommended to restart UniGetUI to finish the installation": "{0} on paigaldatud edukalt. On soovitatav UniGetUI taaskäivitada paigaldamise lõpuleviimiseks", + "Restart later": "Taaskäivita hiljem", + "An error occurred:": "Tekkis viga:", + "Please see the Command-line Output or refer to the Operation History for further information about the issue.": "Palun vaadake käsurea väljundit või vaadake probleemi kohta lisateavet toiminguajaloost.", + "Retry as administrator": "Proovige administraatorina uuesti", + "Retry interactively": "Proovige interaktiivselt uuesti", + "Retry skipping integrity checks": "Proovige terviklikkuskontrollide vahele jättes uuesti", + "Installation options": "Paigaldamise seaded", + "Save": "Salvesta", + "UniGetUI collects anonymous usage data with the sole purpose of understanding and improving the user experience.": "UniGetUI kogub anonüümset kasutusstatistika ainuüksi kasutajakogemuse mõistmise ja parandamise eesmärgil.", + "More details about the shared data and how it will be processed": "Lisaandmed jagatud andmete ja nende töötlemise kohta", + "Do you accept that UniGetUI collects and sends anonymous usage statistics, with the sole purpose of understanding and improving the user experience?": "Kas nõustute, et UniGetUI kogub ja saadab anonüümseid kasutamisstatistikaid, mille ainus eesmärk on kasutajakogemuse mõistmine ja parandamine?", + "Decline": "Keeldu", + "No personal information is collected nor sent, and the collected data is anonimized, so it can't be back-tracked to you.": "Isikuandmeid ei koguta ega saadeta ja kogutud andmetele on antud pseudonüüm, nii et neid ei saa tagasi jäljendada.", + "Navigation panel": "Navigeerimispaneel", + "Operations": "Toimingud", + "Toggle operations panel": "Kuva/peida toimingute paneel", + "Bulk operations": "Hulgitoimingud", + "Retry failed": "Proovi ebaõnnestunuid uuesti", + "Clear successful": "Eemalda õnnestunud", + "Clear finished": "Eemalda lõpetatud", + "Cancel all": "Tühista kõik", + "More": "Rohkem", + "Toggle navigation panel": "Lülita navigeerimispaneel sisse või välja", + "Minimize": "Minimeeri", + "Maximize": "Maksimeeri", + "UniGetUI by Devolutions": "UniGetUI autor Devolutions", + "UniGetUI is an application that makes managing your software easier, by providing an all-in-one graphical interface for your command-line package managers.": "UniGetUI on rakendus, mis muudab teie tarkvara haldamise lihtsamaks, pakkudes ühte graafilist kasutajaliidest teie käsurea packagemanageritele.", + "Useful links": "Kasulikud lingid", + "UniGetUI Homepage": "UniGetUI koduleht", + "Report an issue or submit a feature request": "Teatage probleemist või esitage funktsiooni taotlus", + "UniGetUI Repository": "UniGetUI hoidla", + "View GitHub Profile": "Kuva GitHub profiili", + "UniGetUI License": "UniGetUI litsents", + "Using UniGetUI implies the acceptation of the MIT License": "UniGetUI kasutades nõustute MIT litsentsiga", + "Become a translator": "Saage tõlkijaks", + "Go back": "Mine tagasi", + "Go forward": "Mine edasi", + "Go to home page": "Mine avalehele", + "Reload page": "Laadi leht uuesti", + "View page on browser": "Vaata lehekülge brauseris", + "The built-in browser is not supported on Linux yet.": "Sisseehitatud brauserit Linuxis veel ei toetata.", + "Open in browser": "Ava brauseris", + "Copy to clipboard": "Kopeeri lõikepuhvrisse", + "Export to a file": "Ekspordi faili", + "Log level:": "Logide tase:", + "Reload log": "Laadi logid uuesti", + "Export log": "Ekspordi logi", + "Text": "Tekst", + "Change how operations request administrator rights": "Muuda, kuidas toimingud nõuavad administraatori õiguseid", + "Restrictions on package operations": "Pakettide toimingute piirangud", + "Restrictions on package managers": "Packagemanagerite piirangud", + "Restrictions when importing package bundles": "Pakettide kimbu impordi piirangud", + "Ask for administrator privileges once for each batch of operations": "Küsi administraatori õigused üks kord iga toimingupartii kohta", + "Ask only once for administrator privileges": "Küsi administraatori õiguseid vaid üks kord", + "Prohibit any kind of Elevation via UniGetUI Elevator or GSudo": "Keelusta iga tüüpi tõstmine UniGetUI Elevatori või GStudoga", + "This option WILL cause issues. Any operation incapable of elevating itself WILL FAIL. Install/update/uninstall as administrator will NOT WORK.": "See valik PÕHJUSTAB probleeme. Iga toiming, mis ei saa end tõsta FAIL. Paigaldus/uuendamine/eemaldamine administraatorina EI TÖÖTA.", + "Allow custom command-line arguments": "Luba kohandatud käsurea argumendid", + "Custom command-line arguments can change the way in which programs are installed, upgraded or uninstalled, in a way UniGetUI cannot control. Using custom command-lines can break packages. Proceed with caution.": "Kohandatud käsurea argumendid võivad muuta viisi, kuidas programmid paigaldatakse, uuendatakse või eemaldatakse, nii et UniGetUI ei saa kontrolli. Kohandatud käsujoonte kasutamine võib pakette rikuda. Toimige ettevaatusega.", + "Ignore custom pre-install and post-install commands when importing packages from a bundle": "Luba kohandatud enne ja pärast paigaldamise käskude täitmine", + "Pre and post install commands will be run before and after a package gets installed, upgraded or uninstalled. Be aware that they may break things unless used carefully": "Enne ja pärast paigaldamist käske käivitatakse enne ja pärast paketi paigaldamist, uuendamist või eemaldamist. Olge teadlik, et need võivad asju rikuda, kui neid ei kasutata ettevaatusega", + "Allow changing the paths for package manager executables": "Luba paketihalduri käivitatavate failide teede muutmine", + "Turning this on enables changing the executable file used to interact with package managers. While this allows finer-grained customization of your install processes, it may also be dangerous": "Selle sisselülitamine võimaldab muuta käivitatavat faili, mida käsutatakse packagemanagerite aineks. Kuigi see võimaldab paigaldusprotsesside peenmalt kohandamist, võib see olla ka ohtlik", + "Allow importing custom command-line arguments when importing packages from a bundle": "Luba kohandatud käsurea argumentide importimine pakettide impordi ajal kimbust", + "Malformed command-line arguments can break packages, or even allow a malicious actor to gain privileged execution. Therefore, importing custom command-line arguments is disabled by default": "Vigased käsurea argumendid võivad pakette rikuda või isegi lubada pahavaretel kasutajatel saada õigustatud täitmist. Seega on kohandatud käsurea argumentide importimine vaikimisi keelatud.", + "Allow importing custom pre-install and post-install commands when importing packages from a bundle": "Luba kohandatud eelse ja järelse paigaldamise käskude importimine pakettide impordi ajal kimbust", + "Pre and post install commands can do very nasty things to your device, if designed to do so. It can be very dangerous to import the commands from a bundle, unless you trust the source of that package bundle": "Enne ja pärast paigaldamist käskude võib teha teie seadmele väga halbu asju, kui selline on nende eesmärk. Käskude importimine kimbust võib olla väga ohtlik, kui te ei usalda selle pakettide kimbu allikat", + "Administrator rights and other dangerous settings": "Administraatori õigused ja muud ohtlikud seaded", + "Package backup": "Paketi varundus", + "Cloud package backup": "Pilvepaketikambaaeg", + "Local package backup": "Lokaalse paketi varundus", + "Local backup advanced options": "Lokaalse varukoopia täpsemad valikud", + "Log in with GitHub": "Logi sisse GitHub-ga", + "Log out from GitHub": "Logi välja GitHubi", + "Periodically perform a cloud backup of the installed packages": "Teostage perioodiliselt paigaldatud pakettide pilvevarundus", + "Cloud backup uses a private GitHub Gist to store a list of installed packages": "Pilvevarundus kasutab privaatset GitHub Gisti paigaldatud pakettide loendi salvestamiseks", + "Perform a cloud backup now": "Teostage pilvevarundus kohe", + "Backup": "Loo varukoopia", + "Restore a backup from the cloud": "Taastage varundus pilves", + "Begin the process to select a cloud backup and review which packages to restore": "Alustage pilvevarukoopiast valimine ja vaadake, milliseid pakette taastada", + "Periodically perform a local backup of the installed packages": "Teostage perioodiliselt kohalik varundus paigaldatud pakettidest", + "Perform a local backup now": "Teostage kohalik varundus kohe", + "Change backup output directory": "Muuda varukoopiaväljundi kataloog", + "Set a custom backup file name": "Määra kohandatud varukoopiafaili nimi", + "Leave empty for default": "Jäta tühjaks vaikimisi jaoks", + "Add a timestamp to the backup file names": "Lisa ajatempel varukoopiafailinimedele", + "Backup and Restore": "Varukoopia ja taastumine", + "Enable background api (UniGetUI Widgets and Sharing, port 7058)": "Lülita tausta API sisse (UniGetUI vidinad ja jagamine, port 7058)", + "Wait for the device to be connected to the internet before attempting to do tasks that require internet connectivity.": "Oodake, kuni seade ühendub internet'iga, enne kui proovite ülesandeid, mis nõuavad interneti-ühendust.", + "Disable the 1-minute timeout for package-related operations": "Keelustan 1-minutilise aja piirangu pakettide operatsioonidele", + "Use installed GSudo instead of UniGetUI Elevator": "Kasuta paigaldatud GSudot UniGetUI Lifti asemel", + "Use a custom icon and screenshot database URL": "Kasuta kohandatud ikooni ja kuvatõmmiste andmebaasi URL-i", + "Enable background CPU Usage optimizations (see Pull Request #3278)": "Luba tausta CPU kasutuse optimiseerimised (vaata Pull Request #3278)", + "Perform integrity checks at startup": "Teostage käivitamisel terviklikkuskontrolle", + "When batch installing packages from a bundle, install also packages that are already installed": "Kui paigaldatakse mitu paketti kimbust, paigalda ka need paketid, mis on juba paigaldatud", + "Experimental settings and developer options": "Eksperimentaalsed seaded ja tarkvaraarendaja säted", + "Show UniGetUI's version and build number on the titlebar.": "Näita UniGetUI versiooni tiitliribal", + "Language": "Keel", + "UniGetUI updater": "UniGetUI uuendaja", + "Telemetry": "Telemetriaandmete", + "Manage UniGetUI settings": "Halda UniGetUI seadeid", + "Related settings": "Seotud seaded", + "Update UniGetUI automatically": "Uuenda UniGetUI automaatselt", + "Check for updates": "Kontrolli uuendusi", + "Install prerelease versions of UniGetUI": "Paigalda UniGetUI väljalaske-eelsed versioonid", + "Manage telemetry settings": "Halda telemetriaandmete seadeid", + "Manage": "Halda", + "Import settings from a local file": "Impordi seaded failist", + "Import": "Impordi", + "Export settings to a local file": "Ekspordi seaded faili", + "Export": "Ekspordi", + "Reset UniGetUI": "Lähtesta UniGetUI", + "User interface preferences": "Kasutajaliidese eelistused", + "Application theme, startup page, package icons, clear successful installs automatically": "Rakenduse teema, käivitamisleht, paketi ikoonid, kustuta edukad paigaldused automaatselt", + "General preferences": "Üldised seaded", + "UniGetUI display language:": "UniGetUI kuvamiskeel:", + "System language": "Süsteemi keel", + "Is your language missing or incomplete?": "Kas teie keel on puudu või puudulik?", + "Appearance": "Välimus", + "UniGetUI on the background and system tray": "UniGetUI taustale ja tegumiriidale", + "Package lists": "Pakettide nimekirjad", + "Use classic mode": "Kasuta klassikalist režiimi", + "Restart UniGetUI to apply this change": "Selle muudatuse rakendamiseks taaskäivita UniGetUI", + "The classic UI is disabled for beta testers": "Klassikaline kasutajaliides on beetatestijatele keelatud", + "Close UniGetUI to the system tray": "Sule UniGetUI tegumiribi", + "Manage UniGetUI autostart behaviour": "Halda UniGetUI automaatse käivitumise käitumist", + "Show package icons on package lists": "Näita paketi ikoonid pakettide nimekirjades", + "Clear cache": "Tühjenda vahemälu", + "Select upgradable packages by default": "Vaikimisi valige täienduspakettid", + "Light": "Hele", + "Dark": "Tume", + "Follow system color scheme": "Järgi süsteemi värviskeemi", + "Application theme:": "Rakenduse teema:", + "UniGetUI startup page:": "UniGetUI käivituslehekülg:", + "Proxy settings": "Puhvri seaded", + "Other settings": "Muud seaded", + "Connect the internet using a custom proxy": "Internet'i ühendamine kohandatud puhvri abil", + "Please note that not all package managers may fully support this feature": "Pange tähele, et mitte kõik packagemanagerid ei pruugi seda funktsiooni täielikult toetada", + "Proxy URL": "Puhvri URL", + "Enter proxy URL here": "Sisestage puhvri URL siin", + "Authenticate to the proxy with a user and a password": "Autendi puhverserveris kasutajanime ja parooliga", + "Internet and proxy settings": "Interneti- ja puhverserveri seaded", + "Package manager preferences": "Paketihalduri eelistused", + "Ready": "Valmis", + "Not found": "Ei leitud", + "Notification preferences": "Teavitamise eelistused", + "Notification types": "Teavituste tüübid", + "The system tray icon must be enabled in order for notifications to work": "Tegumiriba ikoon tuleb lubada, et teavitused töötaksid", + "Enable UniGetUI notifications": "Lülita sisse UniGetUI teavitused", + "Show a notification when there are available updates": "Näita teate, kui saadaolevad uuendused", + "Show a silent notification when an operation is running": "Näita vaikiv teavitus toimingu käivitamisel", + "Show a notification when an operation fails": "Näita teavitus, kui toiming ebaõnnestub", + "Show a notification when an operation finishes successfully": "Näita teatis, kui toiming lõpeb edukalt", + "Concurrency and execution": "Samaaegne ja täitmine", + "Automatic desktop shortcut remover": "Automaatne töölauakohase otsetee eemaldaja", + "Choose how many operations should be performed in parallel": "Valige, mitu toimingut tuleks paralleelselt teha", + "Clear successful operations from the operation list after a 5 second delay": "Puhasta edukad operatsioonid operatsioonide loendist 5 sekundi viivitusega", + "Download operations are not affected by this setting": "Allalaadimistoiminguid see säte ei mõjuta", + "You may lose unsaved data": "Te võite kaotada salvestamata andmeid", + "Ask to delete desktop shortcuts created during an install or upgrade.": "Küsi, kas kustutada töölauakohase paigaldamise või uuendamise ajal loodud otseteed.", + "Package update preferences": "Paketi uuendamise eelistused", + "Update check frequency, automatically install updates, etc.": "Uuendamise kontrollimise sagedus, automaatne uuenduste paigaldamine jms", + "Reduce UAC prompts, elevate installations by default, unlock certain dangerous features, etc.": "Vähendage UAC-kutseid, tõstke paigaldusi vaikimisi, avage teatud ohtlikkuid funktsioone jne", + "Package operation preferences": "Paketi toimingute eelistused", + "Enable {pm}": "Luba {pm}", + "Not finding the file you are looking for? Make sure it has been added to path.": "Ei leia otsitavat faili? Veenduge, et see on lisatud PATHi.", + "Select the executable to be used. The following list shows the executables found by UniGetUI": "Valige kasutatav käivitatav fail. Järgmine nimekirja näitab UniGetUI-ga leitud käivitatavaid faile", + "For security reasons, changing the executable file is disabled by default": "Turvalisuse huvides on käivitatava faili muutmine vaikimisi keelatud", + "Change this": "Muuda seda", + "Copy path": "Kopeeri tee", + "Current executable file:": "Praegune käivitatav fail:", + "Ignore packages from {pm} when showing a notification about updates": "Eira pakette {pm}-st, kui näidatakse teavitust uuenduste kohta", + "Update security": "Uuenduste turvalisus", + "Use global setting": "Kasuta globaalset sätet", + "Minimum age for updates": "Uuenduste minimaalne vanus", + "e.g. 10": "nt 10", + "Custom minimum age (days)": "Kohandatud minimaalne vanus (päevades)", + "{pm} does not provide release dates for its packages, so this setting will have no effect": "{pm} ei paku oma pakettidele väljalaskekuupäevi, seega see säte ei avalda mõju.", + "{pm} only provides release dates for some of its packages, so this setting will only apply to those packages": "{pm} pakub väljaandekuupäevi ainult mõnele oma paketile, seega rakendub see säte ainult nendele pakettidele", + "Override the global minimum update age for this package manager": "Alista selle paketihalduri jaoks globaalne uuenduste minimaalne vanus", + "View {0} logs": "Kuva {0} logid", + "If Python cannot be found or is not listing packages but is installed on the system, ": "Kui Pythonit ei leita või see ei kuva pakette, kuid on süsteemi paigaldatud, ", + "Advanced options": "Täpsemad valikud", + "WinGet command-line tool": "WinGeti käsureatööriist", + "Choose which command-line tool UniGetUI uses for WinGet operations when the COM API is not used": "Valige, millist käsureatööriista UniGetUI kasutab WinGeti toiminguteks, kui COM API-t ei kasutata", + "WinGet COM API": "WinGeti COM API", + "Choose whether UniGetUI can use the WinGet COM API before falling back to the command-line tool": "Valige, kas UniGetUI võib enne käsureatööriistale tagasilangemist kasutada WinGeti COM API-t", + "Reset WinGet": "Lähtesta WinGet", + "This may help if no packages are listed": "See võib aidata, kui pakette pole loetletud", + "Force install location parameter when updating packages with custom locations": "Jõusta paigaldamisasukohate parameetrit kohandatud asukohaga pakettide uuendamisel", + "Install Scoop": "Paigalda Scoop", + "Uninstall Scoop (and its packages)": "Eemalda Scoop (ja selle paketid)", + "Run cleanup and clear cache": "Käivita puhastus ja puhasta vahemälu", + "Run": "Käivita", + "Enable Scoop cleanup on launch": "Luba Scoopi puhastamine käivitamisel", + "Default vcpkg triplet": "Vaikimisi vcpkg kolmainsamblik", + "Change vcpkg root location": "Muuda vcpkg juurasukohta", + "Reset vcpkg root location": "Lähtesta vcpkg juurkataloog", + "Open vcpkg root location": "Ava vcpkg juurkataloog", + "Language, theme and other miscellaneous preferences": "Keel, teema ja muud eelistused", + "Show notifications on different events": "Näita teavitusi erinevatel sündmustel", + "Change how UniGetUI checks and installs available updates for your packages": "Muuda, kuidas UniGetUI kontrollib ja paigaldab pakettide saadaolevaid uuendusi", + "Automatically save a list of all your installed packages to easily restore them.": "Salvesta automaatselt kõigi paigaldatud pakettide loend, et neid hõlpsasti taastada.", + "Enable and disable package managers, change default install options, etc.": "Luba ja keela paketihaldurid, muuda vaikimisi paigaldamise seadeid jne", + "Internet connection settings": "Internet'i ühenduse seaded", + "Proxy settings, etc.": "Puhvri seaded jne", + "Beta features and other options that shouldn't be touched": "Beetaversiooni funktsioonid ja muud seadused, mida ei tohiks puutuda", + "Reload sources": "Laadi allikad uuesti", + "Delete source": "Kustuta allikas", + "Known sources": "Teadaolevad allikad", + "Update checking": "Uuenduse kontroll", + "Automatic updates": "Automaatsed uuendused", + "Check for package updates periodically": "Kontrolli pakettide uuendusi perioodiliselt", + "Check for updates every:": "Kontrolli uuendusi iga:", + "Install available updates automatically": "Paigalda saadaolevad uuendused automaatselt", + "Do not automatically install updates when the network connection is metered": "Ära paigalda uuendusi automaatselt, kui võrguühendus on piiratud", + "Do not automatically install updates when the device runs on battery": "Ära paigalda uuendusi automaatselt, kui seade käib akul", + "Do not automatically install updates when the battery saver is on": "Ära paigalda uuendusi automaatselt, kui aku sääst on sisse lülitatud", + "Only show updates that are at least the specified number of days old": "Kuva ainult uuendused, mis on vähemalt määratud arvu päevi vanad", + "Warn me when the installer URL host changes between the installed version and the new version (WinGet only)": "Hoiata mind, kui paigaldaja URL-i host muutub paigaldatud versiooni ja uue versiooni vahel (ainult WinGet)", + "Change how UniGetUI handles install, update and uninstall operations.": "Muuda, kuidas UniGetUI käsitleb paigaldamise, uuendamise ja eemaldamise toiminguid.", + "Navigation": "Navigeerimine", + "Check for UniGetUI updates": "Kontrolli UniGetUI uuendusi", + "Quit UniGetUI": "Välju UniGetUI-st", + "Filters": "Filtrid", + "Sources": "Allikad:", + "Search for packages to start": "Alusta pakettide otsing", + "Select all": "Vali kõik", + "Clear selection": "Eemalda valik", + "Instant search": "Kohene otsimine", + "Distinguish between uppercase and lowercase": "Erista suur- ja väiketähte", + "Ignore special characters": "Eira erimärke", + "Search mode": "Otsimisviis", + "Both": "Mõlemad", + "Exact match": "Täpne vaste", + "Show similar packages": "Näita sarnaseid pakette", + "Loading": "Laadimine", + "Package": "Pakett", + "More options": "Rohkem valikuid", + "Order by:": "Järjestamine:", + "Name": "Nimi", + "Id": "ID", + "Ascendant": "Kasvav", + "Descendant": "Laskuv", + "View modes": "Kuvarežiimid", + "Reload": "Laadi uuesti", + "Closed": "Suletud", + "Ascending": "Kasvav", + "Descending": "Kahanev", + "{0}: {1}, {2}": "{0}: {1}, {2}", + "Order by": "Järjesta", + "No results were found matching the input criteria": "Sisendkriteeriumidele vastavaid tulemusi ei leitud", + "No packages were found": "Pakette pole leitud", + "Loading packages": "Pakettide laadimine", + "Skip integrity checks": "Jäta terviklikkuse kontroll vahele", + "Download selected installers": "Laadi alla valitud paigaldajad", + "Install selection": "Paigalda valik", + "Install options": "Paigaldamise seaded", + "Add selection to bundle": "Lisa valik kimpu", + "Download installer": "Laadi alla paigaldaja", + "Uninstall selection": "Eemalda valik", + "Uninstall options": "Eemaldamise seaded", + "Ignore selected packages": "Eira valituid pakette", + "Open install location": "Ava paigaldamisasukoht", + "Reinstall package": "Paigalda pakett uuesti", + "Uninstall package, then reinstall it": "Kustuta pakett, siis paigalda see uuesti", + "Ignore updates for this package": "Eira selle paketi uuendusi", + "WinGet malfunction detected": "WinGeti häire avastatud", + "It looks like WinGet is not working properly. Do you want to attempt to repair WinGet?": "Näib, et WinGet ei tööta korralikult. Kas soovite proovida WinGetit parandada?", + "Repair WinGet": "Paranda WinGet", + "Updates will no longer be ignored for {0}": "Uuendusi ei eirata enam paketi {0} jaoks", + "Updates are now ignored for {0}": "Uuendusi eiratakse nüüd paketi {0} jaoks", + "Do not ignore updates for this package anymore": "Eira enam selle paketi uuendusi", + "Add packages or open an existing package bundle": "Lisa paketid või ava olemasolev paketikomplekt", + "Add packages to start": "Lisa paketid alustamiseks", + "The current bundle has no packages. Add some packages to get started": "Käesolevas kimbus pole pakette. Lisage mõned paketid, et alustada", + "New": "Uus", + "Save as": "Salvesta kui", + "Create .ps1 script": "Loo .ps1 skript", + "Remove selection from bundle": "Kustuta valik kimbust", + "Skip hash checks": "Jäta räsikontrollid vahele", + "The package bundle is not valid": "Pakettide kimp pole kehtiv", + "The bundle you are trying to load appears to be invalid. Please check the file and try again.": "Kimp, mida proovite laadida, näib olevat sobimatu. Kontrollige faili ja proovige uuesti.", + "Package bundle": "Pakettide kimp", + "Could not create bundle": "Kimbu loomine nurjus", + "The package bundle could not be created due to an error.": "Pakettide kimbu loomine nurjus vea tõttu", + "Install script": "Paigaldamise skript", + "PowerShell script": "PowerShelli skript", + "The installation script saved to {0}": "Paigaldamise skript salvestati {0}-sse", + "An error occurred": "Tekkis viga:", + "An error occurred while attempting to create an installation script:": "Paigaldamisskripti loomisel tekkis viga:", + "Hooray! No updates were found.": "Hurraa! Uuendusi pole leitud.", + "Uninstall selected packages": "Kustuta valitud paketid", + "Update selection": "Uuenda valik", + "Update options": "Uuendamise valikud", + "Uninstall package, then update it": "Eemalda pakett, siis uuenda see", + "Uninstall package": "Eemalda pakett", + "Skip this version": "Jäta versioon vahele", + "Pause updates for": "Peata uuendused", + "User | Local": "Kasutaja | Kohalik", + "Machine | Global": "Masin | Globaalne", + "The default package manager for Debian/Ubuntu-based Linux distributions.
Contains: Debian/Ubuntu packages": "Debian/Ubuntu-põhiste Linuxi distributsioonide vaikepaketihaldur.
Sisaldab: Debian/Ubuntu pakette", + "The Rust package manager.
Contains: Rust libraries and programs written in Rust": "Rusti packagemanager.
Sisaldab: Rustis kirjutatud Rusti teegid ja programmid", + "The classical package manager for windows. You'll find everything there.
Contains: General Software": "Windowsi klassikaline paketihaldur. Leiate sealt kõik.
Sisaldab: Üldine tarkvara", + "The default package manager for RHEL/Fedora-based Linux distributions.
Contains: RPM packages": "RHEL/Fedora-põhiste Linuxi distributsioonide vaikepaketihaldur.
Sisaldab: RPM pakette", + "A repository full of tools and executables designed with Microsoft's .NET ecosystem in mind.
Contains: .NET related tools and scripts": "Repositoorium, mis on täis Microsofti .NET ökosüsteemi silmas pidades loodud tööriistu ja käivitatavaid faile.
Sisaldab: .NETiga seotud tööriistu ja skripte", + "The universal Linux package manager for desktop applications.
Contains: Flatpak applications from configured remotes": "Universaalne Linuxi paketihaldur töölauarakendustele.
Sisaldab: Flatpaki rakendusi seadistatud kaugallikatest", + "NuPkg (zipped manifest)": "NuPkg (tihendatud manifest)", + "The Missing Package Manager for macOS (or Linux).
Contains: Formulae, Casks": "Puuduv paketihaldur macOS-ile (või Linuxile).
Sisaldab: Formulae, Casks", + "Node JS's package manager. Full of libraries and other utilities that orbit the javascript world
Contains: Node javascript libraries and other related utilities": "Node JS-i packagemanager. Täis teeke ja muud utiliite, mis orbiidist JavaScript-i maailm
Sisaldab: Node JavaScript teegid ja muud seotud utiliidid", + "The default package manager for Arch Linux and its derivatives.
Contains: Arch Linux packages": "Arch Linuxi ja selle tuletiste vaikepaketihaldur.
Sisaldab: Arch Linuxi pakette", + "Python's library manager. Full of python libraries and other python-related utilities
Contains: Python libraries and related utilities": "Pythoni teekide haldur. Täis Pythoni teeke ja muud Pythoniga seotud utiliite
Sisaldab: Pythoni teegid ja seotud utiliidid", + "PowerShell's package manager. Find libraries and scripts to expand PowerShell capabilities
Contains: Modules, Scripts, Cmdlets": "PowerShelli paketihaldur. Leia teegid ja skriptid PowerShelli võimaluste laiendamiseks
Sisaldab: Moodulid, skriptid, käsulauakohased utiliidid", + "extracted": "ekstraktitud", + "Scoop package": "Scoopi pakett", + "Great repository of unknown but useful utilities and other interesting packages.
Contains: Utilities, Command-line programs, General Software (extras bucket required)": "Suur teadmus tundmatute kuid kasulike tööstuste ja muude huvitavate pakettide kohta.
Sisaldab: Utiliidid, käsurea programmid, üldine tarkvara (nõutav lisade anumat)", + "The universal Linux package manager by Canonical.
Contains: Snap packages from the Snapcraft store": "Canonicali universaalne Linuxi paketihaldur.
Sisaldab: Snap-pakette Snapcrafti poest", + "library": "teek", + "feature": "funktsioon", + "A popular C/C++ library manager. Full of C/C++ libraries and other C/C++-related utilities
Contains: C/C++ libraries and related utilities": "Populaarne C/C++ teekide haldur. Täis C/C++ teeke ja muud C/C++-ga seotud utiliite
Sisaldab: C/C++ teekid ja seotud utiliidid", + "option": "valik", + "This package cannot be installed from an elevated context.": "Seda paketti ei saa tõstmiskontekstist paigaldada.", + "Please run UniGetUI as a regular user and try again.": "Palun käivitage UniGetUI tavakasutajana ja proovige uuesti.", + "Please check the installation options for this package and try again": "Kontrollige selle paketi paigaldamise seadeid ja proovige uuesti", + "Microsoft's official package manager. Full of well-known and verified packages
Contains: General Software, Microsoft Store apps": "Microsofti ametlik packagemanager. Täis tuntud ja kontrollitud pakettidega
Sisaldab: Üldine tarkvara, Microsoft Store rakendused", + "Local PC": "See arvuti", + "Android Subsystem": "Androidi alamsüsteem", + "Operation on queue (position {0})...": "Toiming järjekorras (positsioon {0})...", + "Click here for more details": "Klõpsake siin rohkema teabe saamiseks", + "Operation canceled by user": "Toiming tühistatud kasutaja poolt ", + "Running PreOperation ({0}/{1})...": "Käivitatud eeltoimingud ({0}/{1})...", + "PreOperation {0} out of {1} failed, and was tagged as necessary. Aborting...": "Eeltoiming {0}/{1} nurjus ja oli märgitud vajalikuks. Katkestan...", + "PreOperation {0} out of {1} finished with result {2}": "Eeltoiming {0}/{1} lõppes tulemusega {2}", + "Starting operation...": "Toimingu käivitamine...", + "Running PostOperation ({0}/{1})...": "Käivitan PostOperation ({0}/{1})...", + "PostOperation {0} out of {1} failed, and was tagged as necessary. Aborting...": "PostOperation {0}/{1} nurjus ja oli märgitud vajalikuks. Katkestan...", + "PostOperation {0} out of {1} finished with result {2}": "PostOperation {0}/{1} lõppes tulemusega {2}", + "{package} installer download": "{package} paigaldaja allalaadimine", + "{0} installer is being downloaded": "{0} paigaldaja laaditakse alla", + "Download succeeded": "Allalaadimine õnnestus", + "{package} installer was downloaded successfully": "{package} paigaldaja laaditi edukalt", + "Download failed": "Allalaadimine ebaõnnestus", + "{package} installer could not be downloaded": "{package} paigaldajat ei saanud alla laadida", + "{package} Installation": "{package} paigaldus", + "{0} is being installed": "{0} paigaldatakse", + "Installation succeeded": "Paigaldamine õnnestus", + "{package} was installed successfully": "{package} oli edukalt paigaldatud", + "Installation failed": "Paigaldamine ebaõnnestus", + "{package} could not be installed": "{package} paigaldamine nurjus", + "{package} Update": "{package} uuendamine", + "Update succeeded": "Uuendamine õnnestus", + "{package} was updated successfully": "{package} oli edukalt uuendatud", + "Update failed": "Uuendamine ebaõnnestus", + "{package} could not be updated": "{package} uuendamine nurjus", + "{package} Uninstall": "Eemalda {package}", + "{0} is being uninstalled": "{0} eemaldatakse", + "Uninstall succeeded": "Eemaldamine õnnestus", + "{package} was uninstalled successfully": "{package} oli edukalt eemaldatud", + "Uninstall failed": "Eemaldamine ebaõnnestus", + "{package} could not be uninstalled": "{package} eemaldamine nurjus", + "Adding source {source}": "Allika {source} lisamine", + "Adding source {source} to {manager}": "Allika {source} lisamine {manager}`isse", + "Source added successfully": "Allikas lisatud edukalt", + "The source {source} was added to {manager} successfully": "Allikas {source} oli lisatud {manager}isse edukalt", + "Could not add source": "Allika lisamine nurjus", + "Could not add source {source} to {manager}": "Allika {source} {manager}'isse lisamine nurjus", + "Removing source {source}": "Allika {source} eemaldamine", + "Removing source {source} from {manager}": "Allika {source} eemaldamine {manager}-st", + "Source removed successfully": "Allikas eemaldatud edukalt", + "The source {source} was removed from {manager} successfully": "Allikas {source} eemaldati {manager}-st edukalt", + "Could not remove source": "Allika eemaldamine nurjus", + "Could not remove source {source} from {manager}": "Allika {source} {manager}'ist eemaldamine nurjus", + "The package manager \"{0}\" was not found": "Paketihaldurit \"{0}\" ei leitud", + "The package manager \"{0}\" is disabled": "Paketihaldur \"{0}\" on keelatud", + "There is an error with the configuration of the package manager \"{0}\"": "Paketihalduris \"{0}\" konfiguratsioonis esineb viga", + "The package \"{0}\" was not found on the package manager \"{1}\"": "Paketti \"{0}\" ei leitud paketihalduris \"{1}\"", + "{0} is disabled": "{0} on välja lülitatud", + "{0} weeks": "{0} nädalat", + "1 month": "1 kuu", + "{0} months": "{0} kuud", + "Something went wrong": "Miski läks valesti", + "An interal error occurred. Please view the log for further details.": "Tekkis sisemineviga. Lisateabe saamiseks vaadake logi.", + "No applicable installer was found for the package {0}": "Paketile {0} ei leitud sobivat paigaldajat", + "Integrity checks will not be performed during this operation": "Selle toimingu ajal ei tehta terviklikkusekontrolli", + "This is not recommended.": "Seda ei soovitata.", + "Run now": "Käivita nüüd", + "Run next": "Käivita järgmine", + "Run last": "Käivita viimane", + "Show in explorer": "Näita uurijas", + "Checked": "Märgitud", + "Unchecked": "Märkimata", + "This package is already installed": "See pakett on juba paigaldatud", + "This package can be upgraded to version {0}": "Seda paketti saab uuendada versioonile {0}", + "Updates for this package are ignored": "Selle paketi uuendused on eiratud", + "This package is being processed": "Seda paketti töödeldakse", + "This package is not available": "See pakett pole saadaval", + "Select the source you want to add:": "Valige allikas, mida soovite lisada", + "Source name:": "Allika nimetus:", + "Source URL:": "Allika URL:", + "An error occurred when adding the source: ": "Allika lisamisel tekkis viga:", + "Package management made easy": "Pakettide haldamine on lihtne", + "version {0}": "versioon {0}", + "[RAN AS ADMINISTRATOR]": "[KÄIVITATUD ADMINISTRAATORINA]", + "Portable mode": "Kaasaskantav režiim", + "DEBUG BUILD": "SILUMISE KOOSTAMINE", + "Here you can change UniGetUI's behaviour regarding the following shortcuts. Checking a shortcut will make UniGetUI delete it if if gets created on a future upgrade. Unchecking it will keep the shortcut intact": "Siin saate muuta UniGetUI käitumist järgmiste otseteede osas. Otsetee märkimine kustutab UniGetUI selle tulevase uuendamise korral. Märke eemaldamine jätab otsetee puutumata.", + "Manual scan": "Käsitsi skaneerimine", + "Existing shortcuts on your desktop will be scanned, and you will need to pick which ones to keep and which ones to remove.": "Teie töölaual olemasolevaid otseteid skannitakse ja peate valima, millised jätta ja millised eemaldada.", + "Delete?": "Kustuta?", + "I understand": "Saan aru", + "Chocolatey setup changed": "Chocolatey seadistus muutus", + "UniGetUI no longer includes its own private Chocolatey installation. A legacy UniGetUI-managed Chocolatey installation was detected for this user profile, but system Chocolatey was not found. Chocolatey will stay unavailable in UniGetUI until Chocolatey is installed on the system and UniGetUI is restarted. Applications previously installed through UniGetUI's bundled Chocolatey may still appear under other sources such as Local PC or WinGet.": "UniGetUI ei sisalda enam oma privaatset Chocolatey paigaldust. Selle kasutajaprofiili jaoks tuvastati pärandvaraks olev UniGetUI hallatav Chocolatey paigaldus, kuid süsteemne Chocolatey ei leitud. Chocolatey jääb UniGetUI-s kättesaamatuks, kuni Chocolatey on süsteemi paigaldatud ja UniGetUI taaskäivitatud. Varem UniGetUI kaasasoleva Chocolatey kaudu paigaldatud rakendused võivad endiselt ilmuda teiste allikate all, nagu Kohalik arvuti või WinGet.", + "NOTE: This troubleshooter can be disabled from UniGetUI Settings, on the WinGet section": "MÄRKUS: seda tõrkeotsijat saab keelata UniGetUI seadetes WinGeti osas", + "Restart": "Taaskäivita", + "Are you sure you want to delete all shortcuts?": "Kas olete kindel, et soovite kustutada kõik otseteed?", + "Any new shorcuts created during an install or an update operation will be deleted automatically, instead of showing a confirmation prompt the first time they are detected.": "Kõik installimise või värskendamise ajal loodud uued otseteed kustutatakse automaatselt ja esmakordsel tuvastamisel ei kuvata kinnitusteadet.", + "Any shorcuts created or modified outside of UniGetUI will be ignored. You will be able to add them via the {0} button.": "Kõik väljaspool UniGetUI-d loodud või muudetud otseteed ignoreeritakse. Saate need lisada nupu {0} kaudu.", + "Are you really sure you want to enable this feature?": "Kas te olete tõesti kindel, et soovite lubada seda funktsiooni?", + "No new shortcuts were found during the scan.": "Skaneerimise ajal ei leitud uusi otseteid.", + "How to add packages to a bundle": "Kuidas lisada paketid kimpu", + "In order to add packages to a bundle, you will need to: ": "Selleks, et lisada paketid kimpu, te peate:", + "1. Navigate to the \"{0}\" or \"{1}\" page.": "1. Minge leheküljele \"{0}\" või \"{1}\".", + "2. Locate the package(s) you want to add to the bundle, and select their leftmost checkbox.": "2. Leidke paketid, mida soovite kimpu lisada, ning valige vasakpool linnuke.", + "3. When the packages you want to add to the bundle are selected, find and click the option \"{0}\" on the toolbar.": "3. Kui paketid, mida soovite kimpu lisada, on valitud, leidke ja vajutage nupp \"{0}\" tööristaribal.", + "4. Your packages will have been added to the bundle. You can continue adding packages, or export the bundle.": "4. Te paketid saavad kimpu lisatud. Te saate jätkata pakettide lisamist või eksportida kimp.", + "Which backup do you want to open?": "Millist varundust soovite avada?", + "Select the backup you want to open. Later, you will be able to review which packages you want to install.": "Valige varundus, mida soovite avada. Hiljem saate vaadata, milliseid pakette soovite paigaldada.", + "There are ongoing operations. Quitting UniGetUI may cause them to fail. Do you want to continue?": "Käimas on toimingud. UniGetUI-ist väljumine võib põhjustada nende ebaõnnestumist. Kas Te tahate jätkata?", + "UniGetUI or some of its components are missing or corrupt.": "UniGetUI või mõned selle komponendid on puudu või kahjustunud.", + "It is strongly recommended to reinstall UniGetUI to adress the situation.": "On tungivalt soovitatav UniGetUI taaspaigaldada, et lahendada olukord.", + "Refer to the UniGetUI Logs to get more details regarding the affected file(s)": "Viidake UniGetUI logidele, et saada rohkem teavet mõjutatud faili(de) kohta", + "Integrity checks can be disabled from the Experimental Settings": "Terviklikkusekontrolle saab keelata Eksperimentaal Seadetest", + "Repair UniGetUI": "Paranda UniGetUI", + "Live output": "Reaalajas väljund", + "This package bundle had some settings that are potentially dangerous, and may be ignored by default.": "Sellel pakettide kimbul olid osad seaded, mis võivad olla ohtlikud ja mida võib vaikimisi eirata.", + "Entries that show in YELLOW will be IGNORED.": "KOLLASE värviga kirjed IGNOREERITAKSE.", + "Entries that show in RED will be IMPORTED.": "PUNASE värviga kirjed IMPORDITAKSE.", + "You can change this behavior on UniGetUI security settings.": "Saate seda käitumist muuta UniGetUI turvaseadetes.", + "Open UniGetUI security settings": "Ava UniGetUI turvaseaded", + "Should you modify the security settings, you will need to open the bundle again for the changes to take effect.": "Kui muudate turvaseadeid, peate kimbu uuesti avama, et muudatused jõustuksid.", + "Details of the report:": "Aruande üksikasjad:", + "Are you sure you want to create a new package bundle? ": "Kas olete kindel, et soovite luua uue pakettide kimbu?", + "Any unsaved changes will be lost": "Kõik salvestamata muudatused lähevad kaduma", + "Warning!": "Hoiatus!", + "For security reasons, custom command-line arguments are disabled by default. Go to UniGetUI security settings to change this. ": "Turvalisuse huvides on kohandatud käsurea argumendid vaikimisi keelatud. Avage UniGetUI turvaseaded, et seda muuta.", + "Change default options": "Muuda vaikimisi seadeid", + "Ignore future updates for this package": "Eira selle paketi tulevasi uuendusi", + "For security reasons, pre-operation and post-operation scripts are disabled by default. Go to UniGetUI security settings to change this. ": "Turvalisuse huvides on enne ja pärast toimingu skriptid vaikimisi keelatud. Avage UniGetUI turvaseaded, et seda muuta.", + "You can define the commands that will be run before or after this package is installed, updated or uninstalled. They will be run on a command prompt, so CMD scripts will work here.": "Saate määrata käsud, mis käivitatakse enne või pärast selle paketi paigaldamist, uuendamist või eemaldamist. Need käivitatakse käsurealt, seega töötavad siin CMD-skriptid.", + "Change this and unlock": "Muuda ja ava", + "{0} Install options are currently locked because {0} follows the default install options.": "{0} paigaldamise sätted on praegu lukustatud, sest {0} järgib vaikimisi paigalduse seadeid.", + "Unset or unknown": "Määramata või teadmata", + "This package has no screenshots or is missing the icon? Contrbute to UniGetUI by adding the missing icons and screenshots to our open, public database.": "Kas sellel paketil pole ekraanipilte või puudub ikoon? Aita kaasa UniGetUI-le, lisades puuduolevad ikoonid ja pildid meie avatud avalikku andmebaasi.", + "Become a contributor": "Saa panustajaks", + "Update to {0} available": "{0} uuendus leitud", + "Reinstall": "Paigalda uuesti", + "Installer not available": "Paigaldaja pole saadaval", + "Version:": "Versioon:", + "UniGetUI Version {0}": "UniGetUI versioon {0}", + "Performing backup, please wait...": "Toimub varundamine, palun oodake...", + "An error occurred while logging in: ": "Sisselogimise ajal tekkis viga:", + "Fetching available backups...": "Saadaolevate varukoopiafailide herimine...", + "Done!": "Valmis!", + "The cloud backup has been loaded successfully.": "Pilvevarundus laaditi edukalt.", + "An error occurred while loading a backup: ": "Varukoopiafaili laadimise ajal tekkis viga:", + "Backing up packages to GitHub Gist...": "Pakettide varundamine GitHub Gisti...", + "Backup Successful": "Varukoopia õnnestus", + "The cloud backup completed successfully.": "Pilvevarundus lõpetati edukalt.", + "Could not back up packages to GitHub Gist: ": "Pakettide varundamine GitHub Gisti nurjus:", + "It is not guaranteed that the provided credentials will be stored safely, so you may as well not use the credentials of your bank account": "Ei ole tagatud, et esitatud kasutajatunnused salvestatakse turvaliselt, seega võite sama hästi mitte kasutada oma pangakonto kasutajatunnuseid", + "Enable the automatic WinGet troubleshooter": "Luba automaatne WinGeti tõrkeotsija", + "Add updates that fail with a 'no applicable update found' to the ignored updates list": "Lisa ebaõnnestunud uuendused, mille puhul kuvatakse teade \"sobivat uuendust ei leitud\", ignoreeritavate uuenduste loendisse", + "Invalid selection": "Sobimatu valik", + "No package was selected": "Ühtegi paketti pole valitud", + "More than 1 package was selected": "Valiti rohkem kui 1 pakett", + "List": "Nimekiri", + "Grid": "Ruudustik", + "Icons": "Ikoonid", + "\"{0}\" is a local package and does not have available details": "\"{0}\" on lokaalne pakett, selle üksikasjad ei ole kättesaadavad", + "\"{0}\" is a local package and is not compatible with this feature": "\"{0}\" on lokaalne pakett, see ei toeta seda funktsiooni", + "Add packages to bundle": "Lisa paketid kimpu", + "Preparing packages, please wait...": "Pakettide ettevalmistamine, palun oodake...", + "Loading packages, please wait...": "Pakettide laadimine, palun oodake...", + "Saving packages, please wait...": "Pakettide salvestamine, palun oodake...", + "The bundle was created successfully on {0}": "Kimp loodi edukalt {0}-l", + "User profile": "Kasutajaprofiil", + "Error": "Viga", + "Log in failed: ": "Sisselogimine nurjus:", + "Log out failed: ": "Väljalogimine nurjus:", + "Package backup settings": "Paketi varundamise seaded", + "Manage UniGetUI autostart behaviour from the Settings app": "Halda UniGetUI automaatkäivituse käitumist", + "Choose how many operations shoulds be performed in parallel": "Valige, mitu toimingut tehakse paralleelselt", + "Something went wrong while launching the updater.": "Uuendaja käivitamisel mingi asi ebaõnnestus.", + "Please try again later": "Proovige hiljem uuesti", + "Show the release notes after UniGetUI is updated": "Kuva väljalaske märkmed pärast UniGetUI uuendamist" +} diff --git a/src/Languages/lang_fa.json b/src/Languages/lang_fa.json new file mode 100644 index 0000000..a111aab --- /dev/null +++ b/src/Languages/lang_fa.json @@ -0,0 +1,850 @@ +{ + "{0} of {1} operations completed": "{0} از {1} عملیات تکمیل شد", + "{0} is now {1}": "{0} اکنون {1} است", + "Enabled": "فعال", + "Disabled": "غیرفعال", + "Privacy": "حریم خصوصی", + "Hide my username from the logs": "پنهان کردن نام کاربری من از گزارش‌ها", + "Replaces your username with **** in the logs. Restart UniGetUI to also hide it from already-recorded entries.": "نام کاربری شما را در گزارش‌ها با **** جایگزین می‌کند. برای پنهان کردن آن در ورودی‌های ثبت‌شده قبلی نیز، UniGetUI را مجددا راه اندازی کنید.", + "Your last update attempt did not complete.": "آخرین تلاش شما برای به‌روزرسانی کامل نشد.", + "UniGetUI could not confirm whether the update succeeded. Open the log to see what happened.": "UniGetUI نتوانست تأیید کند که به‌روزرسانی موفق بوده است یا نه. برای دیدن آنچه رخ داده، گزارش را باز کنید.", + "View log": "مشاهده گزارش", + "The installer reported success but did not restart UniGetUI.": "نصب‌کننده موفقیت را گزارش کرد، اما UniGetUI را دوباره راه‌اندازی نکرد.", + "The installer failed to initialize.": "نصب‌کننده نتوانست راه‌اندازی اولیه شود.", + "Setup was canceled before installation began.": "راه‌اندازی پیش از شروع نصب لغو شد.", + "A fatal error occurred during the preparation phase.": "در مرحله آماده‌سازی یک خطای مرگبار رخ داد.", + "A fatal error occurred during installation.": "در حین نصب یک خطای مرگبار رخ داد.", + "Installation was canceled while in progress.": "نصب در حین انجام لغو شد.", + "The installer was terminated by another process.": "نصب‌کننده توسط فرایند دیگری خاتمه یافت.", + "The preparation phase determined the installation cannot proceed.": "مرحله آماده‌سازی تشخیص داد که نصب نمی‌تواند ادامه پیدا کند.", + "The installer could not start. UniGetUI may already be running, or you do not have permission to install.": "نصب‌کننده نتوانست شروع شود. ممکن است UniGetUI از قبل در حال اجرا باشد، یا شما مجوز نصب نداشته باشید.", + "Unexpected installer error.": "خطای غیرمنتظره نصب‌کننده.", + "We are checking for updates.": "ما در حال بررسی به‌روزرسانی‌ها هستیم.", + "Please wait": "لطفا صبر کنید", + "Great! You are on the latest version.": "عالیه! برنامه شما آخرین نسخه هست.", + "There are no new UniGetUI versions to be installed": "هیچ نسخه جدید UniGetUI برای نصب وجود ندارد", + "UniGetUI version {0} is being downloaded.": "نسخه {0} UniGetUI در حال دانلود است.", + "This may take a minute or two": "این ممکن است یک یا دو دقیقه طول بکشد", + "The installer authenticity could not be verified.": "اصالت نصب‌کننده قابل تأیید نیست.", + "The update process has been aborted.": "فرآیند به‌روزرسانی متوقف شد.", + "Auto-update is not yet available on this platform.": "به‌روزرسانی خودکار هنوز در این پلتفرم در دسترس نیست.", + "Please update UniGetUI manually.": "لطفاً UniGetUI را به‌صورت دستی به‌روزرسانی کنید.", + "An error occurred when checking for updates: ": "یک خطا درحین چک کردن برای به روزرسانی رخ داد:", + "The updater could not be launched.": "به‌روزرسان نتوانست اجرا شود.", + "The operating system did not start the installer process.": "سیستم‌عامل فرایند نصب‌کننده را شروع نکرد.", + "UniGetUI is being updated...": "UniGetUI در حال به‌روزرسانی است...", + "Update installed.": "به‌روزرسانی نصب شد.", + "UniGetUI was updated successfully, but this running copy was not replaced. This usually means you are running a development build. Close this copy and start the newly-installed version to finish.": "UniGetUI با موفقیت به‌روزرسانی شد، اما این نسخهٔ در حال اجرا جایگزین نشد. این معمولاً به این معنی است که از یک نسخهٔ توسعه استفاده می‌کنید. برای تکمیل، این نسخه را ببندید و نسخهٔ تازه نصب‌شده را اجرا کنید.", + "The update could not be applied.": "به‌روزرسانی قابل اعمال نبود.", + "Installer exit code {0}: {1}": "کد خروج نصب‌کننده {0}: {1}", + "Update cancelled.": "به‌روزرسانی لغو شد.", + "Authentication was cancelled.": "احراز هویت لغو شد.", + "Installer exit code {0}": "کد خروج نصب‌کننده {0}", + "Operation in progress": "عملیات در حال انجام", + "Please wait...": "لطفا صبر کنید...\n", + "Success!": "موفقیت!", + "Failed": "شکست خورد", + "An error occurred while processing this package": "یک خطا درحال پردازش این بسته رخ داد:", + "Installer": "نصب‌کننده", + "Executable": "فایل اجرایی", + "MSI": "MSI", + "Compressed file": "فایل فشرده", + "MSIX": "MSIX", + "WinGet was repaired successfully": "WinGet با موفقیت تعمیر شد", + "It is recommended to restart UniGetUI after WinGet has been repaired": "توصیه می‌شود پس از تعمیر WinGet، UniGetUI را مجدداً راه‌اندازی کنید.", + "WinGet could not be repaired": "WinGet قابل تعمیر نبود", + "An unexpected issue occurred while attempting to repair WinGet. Please try again later": "هنگام تلاش برای تعمیر WinGet، مشکلی غیرمنتظره رخ داد. لطفاً بعداً دوباره امتحان کنید.", + "Log in to enable cloud backup": "برای فعالسازی پشتیبان ابری وارد شوید", + "Backup Failed": "پشتیبان گیری شکست خورد", + "Downloading backup...": "درحال دانلود پشتیبان...", + "An update was found!": "یک به روز رسانی پیدا شد!", + "{0} can be updated to version {1}": "{0} قابل به‌روزرسانی به نسخه {1} است", + "Updates found!": "به روز رسانی پیدا شد!", + "{0} packages can be updated": "{0} بسته را می توان به روز کرد\n", + "{0} is being updated to version {1}": "{0} در حال به‌روزرسانی به نسخه {1} است", + "{0} packages are being updated": "{0} بسته در حال به روز رسانی است", + "You have currently version {0} installed": "شما در حال حاضر نسخه {0} نصب دارید", + "Desktop shortcut created": "میانبر به دسکتاپ اضافه شد", + "UniGetUI has detected a new desktop shortcut that can be deleted automatically.": "UniGetUI میانبر جدید دسکتاپی تشخیص داده که می‌تواند به طور خودکار حذف شود.", + "{0} desktop shortcuts created": "{0} میانبر دسکتاپ ایجاد شد", + "UniGetUI has detected {0} new desktop shortcuts that can be deleted automatically.": "UniGetUI {0} میانبر جدید دسکتاپ تشخیص داده که می‌توانند به طور خودکار حذف شوند.", + "Attention required": "توجه! توجه!", + "Restart required": "راه اندازی مجدد لازم است", + "1 update is available": "۱ به روزرسانی در دسترس است", + "{0} updates are available": "به روز رسانی های موجود: {0}", + "Everything is up to date": "همه چیز به روز است", + "Discover Packages": "کاوش بسته ها", + "Available Updates": "به روزرسانی ها موجود است", + "Installed Packages": "بسته های نصب شده", + "UniGetUI Version {0} by Devolutions": "UniGetUI نسخهٔ {0} توسط Devolutions", + "Show UniGetUI": "نمایش UniGetUI", + "Quit": "خروج", + "Are you sure?": "ایا مطمئن هستید؟", + "Do you really want to uninstall {0}?": "آیا واقعاً می خواهید {0} را حذف کنید؟", + "Do you really want to uninstall the following {0} packages?": "آیا واقعا می خواهید تا این {0} بسته ها را حذف کنید؟", + "No": "خیر", + "Yes": "بله", + "Partial": "جزئی", + "View on UniGetUI": "مشاهده در UniGetUI", + "Update": "به روز رسانی", + "Open UniGetUI": "باز کردن UniGetUI", + "Update all": "همه را بروز رسانی کن", + "Update now": "اکنون بروزرسانی کن", + "Installer host changed since the installed version.\n": "میزبان نصب‌کننده نسبت به نسخهٔ نصب‌شده تغییر کرده است.\n", + "This package is on the queue": "این بسته در صف است", + "installing": "در حال نصب", + "updating": "در حال بروز رسانی\n", + "uninstalling": "در حال حذف", + "installed": "نصب شده است", + "Retry": "تلاش مجدد", + "Install": "نصب", + "Uninstall": "حدف برنامه", + "Open": "باز کن", + "Operation profile:": "پروفایل فرآیند:", + "Follow the default options when installing, upgrading or uninstalling this package": "هنگام نصب، بروزرسانی، یا حذف نصب این بسته از تنظیمات پیشفرض پیروی کن", + "The following settings will be applied each time this package is installed, updated or removed.": "هر بار که این بسته نصب، به‌روزرسانی یا حذف شود، تنظیمات زیر اعمال می‌شوند.", + "Version to install:": "نسخه برای نصب:", + "Architecture to install:": "معماری برای نصب:", + "Installation scope:": "مقیاس نصب:", + "Install location:": "محل نصب:", + "Select": "انتخاب", + "Reset": "بازنشانی", + "Custom install arguments:": "آرگومان های سفارشی نصب:", + "Custom update arguments:": "آرگومان های سفارشی بروزرسانی:", + "Custom uninstall arguments:": "آرگومان های سفارشی حذف نصب:", + "Pre-install command:": "دستور قبل-نصب:", + "Post-install command:": "دستور هنگام نصب:", + "Abort install if pre-install command fails": "اگر اجرای دستور پیش-نیاز نصب شکست خورد، نصب انجام نشه", + "Pre-update command:": "دستور قبل-بروزرسانی:", + "Post-update command:": "دستور هنگام بروزرسانی:", + "Abort update if pre-update command fails": "اگر اجرای دستور پیش نیاز آپدیت شکست خورد، آپدیت انجام نشه", + "Pre-uninstall command:": "دستور قبل-حذف-نصب:", + "Post-uninstall command:": "دستور هنگام حذف نصب:", + "Abort uninstall if pre-uninstall command fails": "اگر اجرای دستور پیش نیاز حذف نصب شکست خورد، حذف نصب انجام نشه", + "Command-line to run:": "فرمان برای اجرا:", + "Save and close": "ذخیره و بستن", + "General": "عمومی", + "Architecture & Location": "معماری و محل", + "Command-line": "خط فرمان", + "Close apps": "بستن برنامه‌ها", + "Pre/Post install": "پیش‌نصب/پس‌نصب", + "Select the processes that should be closed before this package is installed, updated or uninstalled.": "پروسه هایی که بهتره قبل از نصب، بروزرسانی یا حذف نصب این بسته، پایان داده بشن رو انتخاب کن", + "Write here the process names here, separated by commas (,)": "نام پروسه ها رو اینجا بنویس، بصورت جدا شده با کاما (,)", + "Try to kill the processes that refuse to close when requested to": "سعی کن پروسه هایی که درخواست پایان یافتن رو رد میکنن، به اجبار پایان بدی", + "Run as admin": "اجرا به عنوان ادمین", + "Interactive installation": "نصب تعاملی", + "Skip hash check": "رد کردن بررسی Hash", + "Uninstall previous versions when updated": "حذف نصب نسخه های قبلی هنگامی که بروزرسانی شدند", + "Skip minor updates for this package": "به‌روزرسانی‌های جزئی این بسته را نادیده بگیر", + "Automatically update this package": "این بسته را به‌صورت خودکار به‌روزرسانی کن", + "{0} installation options": "{0} گزینه های نصب", + "Latest": "آخرین", + "PreRelease": "پیش انتشار", + "Default": "پیش‌فرض ", + "Manage ignored updates": "مدیریت بروزرسانی های نادیده گرفته شده", + "The packages listed here won't be taken in account when checking for updates. Double-click them or click the button on their right to stop ignoring their updates.": "بسته‌های فهرست‌شده اینجا هنگام بررسی به‌روزرسانی‌ها در نظر گرفته نمی‌شوند. برای متوقف کردن نادیده گرفتن به‌روزرسانی آن‌ها، روی هر کدام دوبار کلیک کنید یا دکمه سمت راست‌شان را بزنید.", + "Reset list": "بازنشانی لیست", + "Do you really want to reset the ignored updates list? This action cannot be reverted": "آیا واقعاً می‌خواهید فهرست به‌روزرسانی‌های نادیده‌گرفته‌شده را بازنشانی کنید؟ این عمل قابل بازگشت نیست", + "No ignored updates": "هیچ به‌روزرسانی نادیده‌گرفته‌شده‌ای وجود ندارد", + "Package Name": "نام بسته\n\n", + "Package ID": "شناسه (ID) بسته", + "Ignored version": "نسخه های نادیده گرفته شده", + "New version": "نسخه جدید", + "Source": "منبع", + "All versions": "همه‌ی نسخه ها", + "Unknown": "ناشناخته", + "Up to date": "به‌روز", + "Package {name} from {manager}": "بسته {name} از {manager}", + "Remove {0} from ignored updates": "حذف {0} از به‌روزرسانی‌های نادیده‌گرفته‌شده", + "Cancel": "لغو", + "Administrator privileges": "دسترسی امتیازات ادمین", + "This operation is running with administrator privileges.": "این عملیات با دسترسی های ادمین در حال اجرا است.", + "Interactive operation": "عملیات تعاملی", + "This operation is running interactively.": "این عملیات به صورت تعاملی در حال اجرا است.", + "You will likely need to interact with the installer.": "احتمالاً نیاز خواهید داشت با نصب‌کننده تعامل کنید.", + "Integrity checks skipped": "بررسی‌های یکپارچگی رد شد", + "Integrity checks will not be performed during this operation.": "در طول این عملیات، بررسی‌های یکپارچگی انجام نخواهند شد.", + "Proceed at your own risk.": "با مسئولیت خود ادامه دهید.", + "Close": "بستن", + "Loading...": "بارگذاری...", + "Installer SHA256": "SHA256 نصب کننده", + "Homepage": "صفحه اصلی", + "Author": "سازنده", + "Publisher": "منتشر کننده", + "License": "مجوز", + "Manifest": "مشخصه", + "Installer Type": "نوع نصب کننده", + "Size": "حجم", + "Installer URL": "لینک (URL) نصب کننده", + "Last updated:": "اخرین به روز رسانی:", + "Release notes URL": "آدرس URL یادداشت های نسخه انتشار", + "Package details": "جزئیات بسته", + "Dependencies:": "وابستگی ها:", + "Release notes": "یادداشت های انتشار", + "Screenshots": "تصاویر صفحه", + "This package has no screenshots or is missing the icon? Contribute to UniGetUI by adding the missing icons and screenshots to our open, public database.": "این بسته تصویر صفحه‌ای ندارد یا آیکن آن موجود نیست؟ با افزودن آیکن‌ها و تصاویر صفحهٔ گمشده به پایگاه دادهٔ باز و عمومی ما، در UniGetUI مشارکت کنید.", + "Version": "نسخه", + "Install as administrator": "به عنوان ادمین نصب کنید", + "Update to version {0}": "به‌روزرسانی به نسخه {0}", + "Installed Version": "نسخه نصب شده", + "Update as administrator": "بروزرسانی به عنوان ادمین", + "Interactive update": "به روز رسانی تعاملی", + "Uninstall as administrator": "حدف برنامه به عنوان ادمین", + "Interactive uninstall": "حدف برنامه به صورت تعاملی", + "Uninstall and remove data": "حذف و پاک کردن داده‌ها", + "Not available": "در دسترس نیست", + "Installer SHA512": "SHA512 نصب کننده", + "Unknown size": "اندازه نامشخص", + "No dependencies specified": "وابستگی ای مشخص نشده", + "mandatory": "ضروری", + "optional": "اختیاری", + "UniGetUI {0} is ready to be installed.": "UniGetUI {0} آماده نصب است.", + "The update process will start after closing UniGetUI": "فرآیند به‌روزرسانی پس از بستن UniGetUI شروع خواهد شد", + "UniGetUI has been ran as administrator, which is not recommended. When running UniGetUI as administrator, EVERY operation launched from UniGetUI will have administrator privileges. You can still use the program, but we highly recommend not running UniGetUI with administrator privileges.": "UniGetUI به‌صورت مدیر سیستم اجرا شده است که توصیه نمی‌شود. وقتی UniGetUI را به‌صورت مدیر سیستم اجرا می‌کنید، همهٔ عملیات‌هایی که از UniGetUI شروع می‌شوند دارای دسترسی مدیر سیستم خواهند بود. همچنان می‌توانید از برنامه استفاده کنید، اما اکیداً توصیه می‌کنیم UniGetUI را با دسترسی مدیر سیستم اجرا نکنید.", + "Share anonymous usage data": "به‌اشتراک‌گذاری داده‌های استفاده به‌صورت ناشناس", + "UniGetUI collects anonymous usage data in order to improve the user experience.": "UniGetUI داده‌های استفاده ناشناس جمع‌آوری می‌کند تا تجربه کاربری را بهبود بخشد.", + "Accept": "تایید", + "Software Updates": "بروزرسانی های نرم افزار", + "Package Bundles": "باندل های بسته", + "Settings": "تنظیمات", + "Package Managers": "مدیران بسته", + "UniGetUI Log": "گزارش UniGetUI", + "Package Manager logs": "لاگ های مدیریت بسته", + "Operation history": "تاریخچه عملیات", + "Help": "راهنما", + "UniGetUI": "UniGetUI", + "You have installed UniGetUI Version {0}": "شما UniGetUI نسخه {0} نصب کرده‌اید", + "Disclaimer": "توجه", + "UniGetUI is developed by Devolutions and is not affiliated with any of the compatible package managers.": "UniGetUI توسط Devolutions توسعه داده شده و وابسته به هیچ‌یک از مدیران بستهٔ سازگار نیست.", + "UniGetUI wouldn't have been possible without the help of the contributors. Thank you all 🥳": "UniGetUI بدون کمک مشارکت کنندگان ممکن نبود. ممنون از همه 🥳", + "UniGetUI uses the following libraries. Without them, UniGetUI wouldn't have been possible.": "UniGetUI از کتابخانه های زیر استفاده می کند. بدون آنها، UniGetUI ممکن نبود.", + "{0} homepage": "{0} صفحه اصلی", + "UniGetUI has been translated to more than 40 languages thanks to the volunteer translators. Thank you 🤝": "UniGetUI به لطف مترجمان داوطلب به بیش از 40 زبان ترجمه شده است. ممنون 🤝", + "Verbose": "مفصل", + "1 - Errors": "1 - خطاها", + "2 - Warnings": "۲ - هشدارها", + "3 - Information (less)": "۳ - اطلاعات (کمتر)", + "4 - Information (more)": "۴ - اطلاعات (بیشتر)", + "5 - information (debug)": "۵ - اطلاعات (اشکال یابی)", + "Warning": "هشدار", + "The following settings may pose a security risk, hence they are disabled by default.": "تنظیمات زیر ممکنه ریسک امنیتی ایجاد کنند، بنابراین بصورت پیشفرض غیرفعال شده اند.", + "Enable the settings below if and only if you fully understand what they do, and the implications they may have.": "تنظیمات زیر را تنها و فقط زمانی که میدانید چیکار میکنند، و چه خطر هایی را زمینه سازی میکنند، فعال کنید.", + "The settings will list, in their descriptions, the potential security issues they may have.": "تنظیمات لیست خواهند شد، در توضیحاتشان، مشکلات جدی امنیتی که ممکنه داشته باشن.", + "The backup will include the complete list of the installed packages and their installation options. Ignored updates and skipped versions will also be saved.": "بک آپ شامل فهرست کامل بسته‌های نصب شده و گزینه‌های نصب آن‌ها خواهد بود. به‌روزرسانی‌های نادیده گرفته شده و نسخه‌های رد شده نیز ذخیره می‌شوند.", + "The backup will NOT include any binary file nor any program's saved data.": "نسخه پشتیبان شامل هیچ فایل باینری یا داده های ذخیره شده هیچ برنامه ای نمی شود.", + "The size of the backup is estimated to be less than 1MB.": "اندازه بک آپ تخمین زده می‌شود کمتر از 1 مگابایت باشد.", + "The backup will be performed after login.": "بک آپ گیری پس از ورود انجام خواهد شد.", + "{pcName} installed packages": "بسته‌های نصب شده {pcName}", + "Current status: Not logged in": "وضعیت فعلی: کاربر وارد نشده", + "You are logged in as {0} (@{1})": "شما به عنوان {0} (@{1} ) وارد شده اید", + "Nice! Backups will be uploaded to a private gist on your account": "خوبه! پشتیبان ها به یک gist خصوصی روی حساب شما آپلود خواهند شد", + "Select backup": "انتخاب پشتیبان", + "Settings imported from {0}": "تنظیمات از {0} وارد شد", + "UniGetUI Settings": "تنظیمات UniGetUI", + "Settings exported to {0}": "تنظیمات به {0} صادر شد", + "UniGetUI settings were reset": "تنظیمات UniGetUI بازنشانی شد", + "Allow pre-release versions": "اجازه نسخه های پیش از انتشار داده شود", + "Apply": "اعمال", + "For security reasons, custom command-line arguments are disabled by default. Go to UniGetUI security settings to change this.": "به دلایل امنیتی، آرگومان‌های سفارشی خط فرمان به‌طور پیش‌فرض غیرفعال هستند. برای تغییر این مورد به تنظیمات امنیتی UniGetUI بروید.", + "Go to UniGetUI security settings": "برو به تنظیمات امنیتی UniGetUI", + "The following options will be applied by default each time a {0} package is installed, upgraded or uninstalled.": "هربار که یک {0} بسته نصب، بروزرسانی یا حذف نصب شد تنظیمات زیر بصورت پیشفرض اعمال میشوند.", + "Package's default": "پیشفرض بسته", + "Install location can't be changed for {0} packages": "محل نصب نمیتواند برای {0} بسته(ها) تغییر کند", + "The local icon cache currently takes {0} MB": "حافظه پنهان آیکون محلی در حال حاضر {0} مگابایت فضا اشغال کرده است", + "Username": "نام کاربری", + "Password": "رمز عبور", + "Credentials": "اطلاعات ورود", + "It is not guaranteed that the provided credentials will be stored safely": "تضمینی وجود ندارد که اطلاعات ورود ارائه‌شده به‌صورت امن ذخیره شوند", + "Partially": "تا حدی", + "Package manager": "مدیر بسته", + "Compatible with proxy": "سازگار با پروکسی", + "Compatible with authentication": "سازگار با احراز هویت", + "Proxy compatibility table": "جدول سازگاری پروکسی", + "{0} settings": "{0} تنظیمات", + "{0} status": "{0} وضعیت", + "Default installation options for {0} packages": "تنظیمات نصب پیشفرض برای {0} بسته(ها)", + "Expand version": "تکامل نسخه", + "The executable file for {0} was not found": "فایل اجرایی برای {0} یافت نشد", + "{pm} is disabled": "{pm} غیرفعال است", + "Enable it to install packages from {pm}.": "آن را برای نصب بسته‌ها از {pm} فعال کنید.", + "{pm} is enabled and ready to go": "{pm} فعال و آماده به کار است", + "{pm} version:": "نسخه {pm}:", + "{pm} was not found!": "{pm} یافت نشد!", + "You may need to install {pm} in order to use it with UniGetUI.": "ممکن است نیاز داشته باشید {pm} را نصب کنید تا بتوانید آن را با UniGetUI استفاده کنید.", + "Scoop Installer - UniGetUI": "نصب‌کننده UniGetUI - Scoop", + "Scoop Uninstaller - UniGetUI": "حذف کننده UniGetUI - Scoop", + "Clearing Scoop cache - UniGetUI": "پاک کردن حافظه پنهان UniGetUI - Scoop", + "Restart UniGetUI to fully apply changes": "برای اعمال کامل تغییرات، UniGetUI را دوباره راه‌اندازی کنید", + "Restart UniGetUI": "UniGetUI را مجددا راه اندازی کنید", + "Manage {0} sources": "منابع {0} را مدیریت کنید", + "Add source": "افزودن منبع", + "Add": "اضافه کردن", + "Source name": "نام منبع", + "Source URL": "نشانی منبع", + "Other": "دیگر", + "No minimum age": "بدون حداقل مدت", + "1 day": "۱ روز", + "{0} days": "{0} روز", + "Custom...": "سفارشی...", + "{0} minutes": "{0} دقیقه", + "1 hour": "۱ ساعت", + "{0} hours": "{0} ساعت", + "1 week": "۱ هفته", + "Supports release dates": "از تاریخ انتشار پشتیبانی می‌کند", + "Release date support per package manager": "پشتیبانی از تاریخ انتشار برای هر مدیر بسته", + "Search for packages": "جستجوی بسته ها", + "Local": "محلی", + "OK": "OK", + "Last checked: {0}": "آخرین بررسی: {0}", + "{0} packages were found, {1} of which match the specified filters.": " {0} بسته یافت شد، که {1} از آن‌ها با فیلترهای مشخص شده مطابقت دارند.", + "{0} selected": "{0} انتخاب شد", + "(Last checked: {0})": "(آخرین بررسی: {0})", + "All packages selected": "همه بسته‌ها انتخاب شدند", + "Package selection cleared": "انتخاب بسته‌ها پاک شد", + "{0}: {1}": "{0}: {1}", + "More info": "اطلاعات بیشتر", + "GitHub account": "حساب GitHub", + "Log in with GitHub to enable cloud package backup.": "با Github وارد شوید تا پشتیبان ابری فعال شود.", + "More details": "جزئیات بیشتر", + "Log in": "ورود کاربر", + "If you have cloud backup enabled, it will be saved as a GitHub Gist on this account": "اگر شما پشتیبان گیری ابری را فعال کرده باشید، بصورت Github Gist روی این اکانت ذخیره خواهد شد", + "Log out": "خروج کاربر", + "About UniGetUI": "درباره UniGetUI", + "About": "درباره", + "Third-party licenses": "مجوزهای نرم‌افزارهای جانبی", + "Contributors": "مشارکت کنندگان", + "Translators": "مترجم ها", + "Bundle security report": "گزارش امنیت مجموعه", + "The bundle contained restricted content": "بسته شامل محتوای محدودشده بود", + "UniGetUI – Crash Report": "UniGetUI – گزارش خرابی", + "UniGetUI has crashed": "UniGetUI از کار افتاد", + "Help us fix this by sending a crash report to Devolutions. All fields below are optional.": "با ارسال گزارش خرابی به Devolutions به ما در رفع این مشکل کمک کنید. همه فیلدهای زیر اختیاری هستند.", + "Email (optional)": "ایمیل (اختیاری)", + "your@email.com": "your@email.com", + "Additional details (optional)": "جزئیات اضافی (اختیاری)", + "Describe what you were doing when the crash occurred…": "توضیح دهید هنگام وقوع خرابی چه کاری انجام می‌دادید…", + "Crash report": "گزارش خرابی", + "Don't Send": "ارسال نکن", + "Send Report": "ارسال گزارش", + "Sending…": "در حال ارسال…", + "Unsaved changes": "تغییرات ذخیره‌نشده", + "You have unsaved changes in the current bundle. Do you want to discard them?": "در بستهٔ فعلی تغییرات ذخیره‌نشده دارید. می‌خواهید آن‌ها را نادیده بگیرید؟", + "Discard changes": "نادیده گرفتن تغییرات", + "Integrity violation": "نقض یکپارچگی", + "UniGetUI or some of its components are missing or corrupt. It is strongly recommended to reinstall UniGetUI to adress the situation.": "UniGetUI یا برخی از اجزای آن گم شده یا خراب هستند. اکیداً توصیه می‌شود برای رفع این وضعیت، UniGetUI را دوباره نصب کنید.", + "• Refer to the UniGetUI Logs to get more details regarding the affected file(s)": "• به لاگ های UniGetUI رجوع شود برای جزئیات بیشتر درمورد فایل(های) تحت تاثیر", + "• Integrity checks can be disabled from the Experimental Settings": "• بررسی های یکپارچگی از طریق تنظیمات آزمایشی میتونن غیرفعال بشن", + "Manage shortcuts": "مدیریت میانبرها", + "UniGetUI has detected the following desktop shortcuts which can be removed automatically on future upgrades": "UniGetUI میانبرهای دسکتاپ زیر را تشخیص داده که می‌توانند در ارتقاهای آینده به طور خودکار حذف شوند", + "Do you really want to reset this list? This action cannot be reverted.": "آیا واقعاً می‌خواهید این فهرست را بازنشانی کنید؟ این عمل قابل بازگشت نیست.", + "Desktop shortcuts list": "فهرست میانبرهای دسکتاپ", + "Open in explorer": "باز کردن در اکسپلورر", + "Remove from list": "حذف از لیست", + "When new shortcuts are detected, delete them automatically instead of showing this dialog.": "هنگام تشخیص میانبرهای جدید، آن‌ها را به طور خودکار حذف کنید به جای نمایش این دیالوگ.", + "Not right now": "الان نه", + "Missing dependency": "عدم وجود نیازمندی", + "UniGetUI requires {0} to operate, but it was not found on your system.": "UniGetUI برای کار کردن به {0} نیاز دارد، اما در سیستم شما یافت نشد.", + "Click on Install to begin the installation process. If you skip the installation, UniGetUI may not work as expected.": "برای شروع نصب، روی «نصب» کلیک کنید. اگر نصب را رد کنید، ممکن است UniGetUI به درستی کار نکند.", + "Alternatively, you can also install {0} by running the following command in a Windows PowerShell prompt:": "یا به‌صورت جایگزین، می‌توانید {0} را با اجرای دستور زیر در محیط Windows PowerShell نصب کنید:", + "Install {0}": "نصب {0}", + "Do not show this dialog again for {0}": "این دیالوگ را دوباره برای {0} نشان نده", + "Please wait while {0} is being installed. A black window may show up. Please wait until it closes.": "لطفاً صبر کنید تا {0} نصب شود. ممکن است پنجره سیاه (یا آبی) ظاهر شود. لطفاً صبر کنید تا بسته شود.", + "{0} has been installed successfully.": "{0} با موفقیت نصب شد.", + "Please click on \"Continue\" to continue": "لطفا برای ادامه روی \"ادامه\" کلیک کنید", + "Continue": "ادامه بده", + "{0} has been installed successfully. It is recommended to restart UniGetUI to finish the installation": "{0} با موفقیت نصب شد. توصیه می‌شود برای تکمیل نصب، UniGetUI را راه‌اندازی مجدد کنید", + "Restart later": "بعداً راه‌اندازی مجدد کن", + "An error occurred:": "خطایی رخ داد:", + "Please see the Command-line Output or refer to the Operation History for further information about the issue.": "لطفاً خروجی خط فرمان را ببینید یا برای اطلاعات بیشتر در مورد این مشکل به سابقه عملیات مراجعه کنید.", + "Retry as administrator": "تلاش مجدد به عنوان ادمین", + "Retry interactively": "تلاش مجدد تعاملی", + "Retry skipping integrity checks": "تلاش مجدد با رد کردن بررسی‌های یکپارچگی", + "Installation options": "گزینه های نصب", + "Save": "ذخیره", + "UniGetUI collects anonymous usage data with the sole purpose of understanding and improving the user experience.": "UniGetUI داده‌های استفاده ناشناس را با هدف صرف درک و بهبود تجربه کاربری جمع‌آوری می‌کند.", + "More details about the shared data and how it will be processed": "جزئیات بیشتر درباره داده‌های اشتراکی و نحوه پردازش آن‌ها", + "Do you accept that UniGetUI collects and sends anonymous usage statistics, with the sole purpose of understanding and improving the user experience?": "آیا قبول دارید که UniGetUI آمار استفاده ناشناس جمع‌آوری و ارسال کند، با هدف تنها درک و بهبود تجربه کاربری؟", + "Decline": "رد کردن", + "No personal information is collected nor sent, and the collected data is anonimized, so it can't be back-tracked to you.": "هیچ اطلاعات شخصی جمع‌آوری یا ارسال نمی‌شود و داده‌های جمع‌آوری شده ناشناس‌سازی شده‌اند، بنابراین قابل ردیابی به شما نیستند.", + "Navigation panel": "پنل ناوبری", + "Operations": "عملیات", + "Toggle operations panel": "تغییر وضعیت پنل عملیات", + "Bulk operations": "عملیات گروهی", + "Retry failed": "تلاش مجدد برای موارد ناموفق", + "Clear successful": "پاک کردن موارد موفق", + "Clear finished": "پاک کردن موارد پایان‌یافته", + "Cancel all": "لغو همه", + "More": "بیشتر", + "Toggle navigation panel": "نمایش/پنهان کردن پنل ناوبری", + "Minimize": "کمینه‌سازی", + "Maximize": "بیشینه‌سازی", + "UniGetUI by Devolutions": "UniGetUI توسط Devolutions", + "UniGetUI is an application that makes managing your software easier, by providing an all-in-one graphical interface for your command-line package managers.": "UniGetUI برنامه‌ای است که مدیریت نرم‌افزار شما را با ارائه یک رابط گرافیکی همه‌جانبه برای مدیران بسته خط فرمان شما آسان‌تر می‌کند.", + "Useful links": "لینک های مفید ", + "UniGetUI Homepage": "صفحه اصلی UniGetUI", + "Report an issue or submit a feature request": "گزارش یک مشکل یا ارسال درخواست ویژگی", + "UniGetUI Repository": "مخزن UniGetUI", + "View GitHub Profile": "مشاهده پروفایل GitHub", + "UniGetUI License": "لایسنس UniGetUI", + "Using UniGetUI implies the acceptation of the MIT License": "استفاده از UniGetUI به معنای پذیرش مجوز MIT است", + "Become a translator": "مترجم شوید", + "Go back": "بازگشت", + "Go forward": "جلو رفتن", + "Go to home page": "رفتن به صفحه اصلی", + "Reload page": "بارگذاری مجدد صفحه", + "View page on browser": "نمایش صفحه در مرورگر", + "The built-in browser is not supported on Linux yet.": "مرورگر داخلی هنوز در Linux پشتیبانی نمی‌شود.", + "Open in browser": "باز کردن در مرورگر", + "Copy to clipboard": "کپی به کلیپ بورد", + "Export to a file": "استخراج به یک فایل", + "Log level:": "سطح گزارش:", + "Reload log": "بارگیری مجدد گزارش", + "Export log": "خروجی گرفتن از گزارش", + "Text": "متن", + "Change how operations request administrator rights": "تغییر نحوهٔ درخواست مجوز ادمین برای عملیات ها", + "Restrictions on package operations": "محدودیت ها روی عملیات بسته ها", + "Restrictions on package managers": "محدودیت ها روی مدیران بسته ها", + "Restrictions when importing package bundles": "محدودیت ها هنگام ورود باندل بسته ها", + "Ask for administrator privileges once for each batch of operations": "هر بار که یک عملیات batch اتفاق می افتد برای دسترسی ادمین درخواست کن", + "Ask only once for administrator privileges": "فقط یکبار دسترسی مدیر سیستم درخواست شود", + "Prohibit any kind of Elevation via UniGetUI Elevator or GSudo": "از هرنوع افزایش سطح دسترسی با افزاینده UniGetUI یا GSudo جلوگیری کن", + "This option WILL cause issues. Any operation incapable of elevating itself WILL FAIL. Install/update/uninstall as administrator will NOT WORK.": "این تنظیم باعث مشکلاتی میشه. هر فرآیند نامتناسب با افزایش سطح دسترسی خودش شکست خواهد خورد. نصب/بروزرسانی/حذف نصب بعنوان ادمین سیستم کار نخواهد کرد.", + "Allow custom command-line arguments": "اجازه ورودی های سفارشی خط فرمان داده شود", + "Custom command-line arguments can change the way in which programs are installed, upgraded or uninstalled, in a way UniGetUI cannot control. Using custom command-lines can break packages. Proceed with caution.": "آرگومان های سفارشی خط فرمان میتوانند روش تشخیص برنامه های نصب شده، آپدیت شده یا حذف شده را به گونه ای تغییر دهند که UniGetUI نتواند کنترل کند. استفاده از خط فرمان های سفارشی میتواند بسته ها را خراب کند. با ملاحظه و دقت ادامه دهید.", + "Ignore custom pre-install and post-install commands when importing packages from a bundle": "اجازه بده فرمان‌های سفارشی پیش از نصب و پس از نصب اجرا شوند", + "Pre and post install commands will be run before and after a package gets installed, upgraded or uninstalled. Be aware that they may break things unless used carefully": "دستورات قبل و موقع نصب هنگامی که بسته ای نصب، بروزرسانی یا حذف نصب شود، اجرا خواهند شد. مراقب باشید چرا که میتوانند همه چیز را خراب کنند مگر اینکه با دقت استفاده شوند", + "Allow changing the paths for package manager executables": "اجازه تغییر مسیر ها برای فایل های اجرایی پکیج منیجر", + "Turning this on enables changing the executable file used to interact with package managers. While this allows finer-grained customization of your install processes, it may also be dangerous": "فعال کردن این، تغییر دادن فایل قابل اجرای استفاده شده برای تعامل با مدیران بسته رو ممکن میکنه. درحالی که این سفارشی سازی دقیق تر پروسه های نصب رو ممکن میکنه، ولی میتونه خطرناک هم باشه", + "Allow importing custom command-line arguments when importing packages from a bundle": "اجازه ورودی های سفارشی خط فرمان هنگام ورود بسته ها از مجموعه داده شود", + "Malformed command-line arguments can break packages, or even allow a malicious actor to gain privileged execution. Therefore, importing custom command-line arguments is disabled by default": "آرگومان های نادرست خط فرمان میتونن بسته ها رو خراب کنند، یا حتی به یک بدافزار دسترسی اجرا بدهند. بنابراین، ورود آرگومان های شخصی سازی شده خط فرمان بصورت پیشفرض غیرفعال شده است", + "Allow importing custom pre-install and post-install commands when importing packages from a bundle": "اجازه ورود پیش نیاز سفارشی و فرمان های مرحله نصب هنگام ورود بسته ها از مجموعه داده شود", + "Pre and post install commands can do very nasty things to your device, if designed to do so. It can be very dangerous to import the commands from a bundle, unless you trust the source of that package bundle": "دستورات قبل و هنگام نصب میتوانند کارهای ناپسندی با دستگاه شما انجام دهند، این میتونه خیلی خطرناک باشه که دستورات رو از باندل وارد کنی مگر اینکه منبع اون باندل بسته مورد اعتمادت باشه.", + "Administrator rights and other dangerous settings": "دسترسی های مدیر سیستم و دیگر تنظیمات خطرناک", + "Package backup": "بک آپ بسته", + "Cloud package backup": "پشتیبان گیری بسته ابری", + "Local package backup": "پشتیبان بسته محلی", + "Local backup advanced options": "تنظیمات پیشرفته پشتیبان محلی", + "Log in with GitHub": "با Github وارد شوید", + "Log out from GitHub": "خروج از Github", + "Periodically perform a cloud backup of the installed packages": "بصورت دوره ای از بسته های نصب شده پشتیبان ابری بگیر", + "Cloud backup uses a private GitHub Gist to store a list of installed packages": "پشتیبان گیری ابری از یک Github Gist خصوصی استفاده میکنه تا لیست بسته های نصب شده رو ذخیره کنه", + "Perform a cloud backup now": "الان پشتیبان ابری بگیر", + "Backup": "پشتیبان گیری", + "Restore a backup from the cloud": "بازگردانی یک پشتیبان از ابر", + "Begin the process to select a cloud backup and review which packages to restore": "شروع فرآیند انتخاب پشتیبان ابری و بازبینی بسته ها برای بازگردانی", + "Periodically perform a local backup of the installed packages": "بصورت دوره ای از بسته های نصب شده پشتیبان محلی بگیر", + "Perform a local backup now": "الان پشتیبان محلی بگیر", + "Change backup output directory": "محل جاگذاری پشتیبان گیری را تغییر بده", + "Set a custom backup file name": "تنظیم یک نام فایل بک آپ شخصی سازی شده", + "Leave empty for default": "پیش فرض خالی بگذارید", + "Add a timestamp to the backup file names": " یک مهره زمانی به اسم فایل پشتیبان گیری اضافه شود", + "Backup and Restore": "پشتیبان گیری و بازگردانی", + "Enable background api (UniGetUI Widgets and Sharing, port 7058)": "فعال کردن api پس زمینه (UniGetUI Widgets and Sharing، پورت 7058)", + "Wait for the device to be connected to the internet before attempting to do tasks that require internet connectivity.": "قبل از تلاش برای انجام کارهایی که نیاز به اتصال اینترنت دارند، منتظر بمانید تا دستگاه به اینترنت متصل شود.", + "Disable the 1-minute timeout for package-related operations": "غیرفعال‌کردن زمان‌توقف ۱ دقیقه‌ای برای عملیات مرتبط با بسته‌ها", + "Use installed GSudo instead of UniGetUI Elevator": "برای افزایش سطح دسترسی، بجای افزاینده UniGetUI از GSudo نصب شده استفاده کن", + "Use a custom icon and screenshot database URL": "استفاده از URL پایگاه داده آیکون و تصویر شخصی سازی شده", + "Enable background CPU Usage optimizations (see Pull Request #3278)": "فعال کردن بهینه‌سازی‌های استفاده از CPU در پس‌زمینه (Pull Request #3278 را ببینید)", + "Perform integrity checks at startup": "بررسی سلامت و یکپارچگی هنگام شروع برنامه انجام شود", + "When batch installing packages from a bundle, install also packages that are already installed": "وقتی بسته ها رو بصورت دسته ای از یک باندل نصب میکنی، بسته هایی که از قبل نصب بودن هم نصب کن.", + "Experimental settings and developer options": "تنظیمات ازمایشی و گزینه های توسعه دهنده", + "Show UniGetUI's version and build number on the titlebar.": "نمایش نسخه UniGetUI در نوار عنوان", + "Language": "زبان", + "UniGetUI updater": "به‌روزرسان UniGetUI", + "Telemetry": "تله‌متری", + "Manage UniGetUI settings": "مدیریت تنظیمات UniGetUI", + "Related settings": "تنظیمات مرتبط", + "Update UniGetUI automatically": "به‌روزرسانی خودکار UniGetUI", + "Check for updates": "بررسی برای به‌روز رسانی ها", + "Install prerelease versions of UniGetUI": "نصب نسخه‌های پیش‌انتشار UniGetUI", + "Manage telemetry settings": "مدیریت تنظیمات تله‌متری", + "Manage": "مدیریت", + "Import settings from a local file": "وارد کردن تنظیمات از یک فایل محلی", + "Import": "وارد کردن", + "Export settings to a local file": "استخراج تنظیمات از یک فایل محلی", + "Export": "استخراج", + "Reset UniGetUI": "بازنشانی UniGetUI", + "User interface preferences": "تنظیمات رابط کاربری", + "Application theme, startup page, package icons, clear successful installs automatically": " تم برنامه، صفحهٔ شروع، آیکون‌های بسته‌ها، پاک‌سازی خودکار نصب‌های موفق", + "General preferences": "تنظیمات دلخواه کلی", + "UniGetUI display language:": "زبان نمایشی UniGetUI:", + "System language": "زبان سیستم", + "Is your language missing or incomplete?": "آیا زبان شما گم شده است یا ناقص است؟", + "Appearance": "ظاهر", + "UniGetUI on the background and system tray": "UniGetUI در پس‌زمینه و نوار سیستم", + "Package lists": "لیست‌های بسته", + "Use classic mode": "استفاده از حالت کلاسیک", + "Restart UniGetUI to apply this change": "برای اعمال این تغییر، UniGetUI را دوباره راه‌اندازی کنید", + "The classic UI is disabled for beta testers": "رابط کاربری کلاسیک برای آزمایش‌کنندگان بتا غیرفعال است", + "Close UniGetUI to the system tray": "بستن UniGetUI و انتقال به نوار سیستم", + "Manage UniGetUI autostart behaviour": "مدیریت رفتار شروع خودکار UniGetUI", + "Show package icons on package lists": "نمایش آیکون‌های بسته در لیست‌های بسته", + "Clear cache": "پاک کردن حافظه پنهان", + "Select upgradable packages by default": "بسته‌های قابل ارتقا را به طور پیش‌فرض انتخاب کنید", + "Light": "روشن", + "Dark": "تیره", + "Follow system color scheme": "پیروی از طرح رنگ سیستم", + "Application theme:": "تم برنامه:", + "UniGetUI startup page:": "صفحه راه‌اندازی UniGetUI:", + "Proxy settings": "تنظیمات پروکسی", + "Other settings": "تنظیمات دیگر", + "Connect the internet using a custom proxy": "اتصال اینترنت با استفاده از پروکسی سفارشی", + "Please note that not all package managers may fully support this feature": "لطفاً توجه داشته باشید که همه مدیران بسته ممکن است کاملاً از این ویژگی پشتیبانی نکنند", + "Proxy URL": "URL پروکسی", + "Enter proxy URL here": "URL پروکسی را اینجا وارد کنید", + "Authenticate to the proxy with a user and a password": "برای پراکسی با نام کاربری و گذرواژه احراز هویت کنید", + "Internet and proxy settings": "تنظیمات اینترنت و پراکسی", + "Package manager preferences": "تنظیمات مدیریت بسته", + "Ready": "آماده", + "Not found": "پیدا نشد\n", + "Notification preferences": "تنظیمات اعلان", + "Notification types": "انواع اعلان", + "The system tray icon must be enabled in order for notifications to work": "آیکون نوار سیستم باید فعال باشد تا اعلان‌ها کار کنند", + "Enable UniGetUI notifications": "فعال سازی اعلان های UniGetUI", + "Show a notification when there are available updates": "در صورت وجود بروزرسانی یک اعلان نشان داده شود ", + "Show a silent notification when an operation is running": "نمایش اعلان بی‌صدا هنگام اجرای عملیات", + "Show a notification when an operation fails": "نمایش اعلان هنگام شکست عملیات", + "Show a notification when an operation finishes successfully": "نمایش اعلان هنگام اتمام موفق عملیات", + "Concurrency and execution": "همزمانی و اجرا", + "Automatic desktop shortcut remover": "حذف‌کنندهٔ خودکار میان‌برهای دسکتاپ", + "Choose how many operations should be performed in parallel": "انتخاب کنید چند عملیات به‌صورت موازی انجام شوند", + "Clear successful operations from the operation list after a 5 second delay": "عملیات های موفق پس از ۵ ثانیه تاخیر از فهرست عملیات پاک می‌شوند", + "Download operations are not affected by this setting": "این مورد روی عملیات دانلود تاثیر ندارد", + "You may lose unsaved data": "ممکنه شما داده های ذخیره نشده رو از دست بدهید", + "Ask to delete desktop shortcuts created during an install or upgrade.": "درخواست تأیید برای حذف میان‌برهای دسکتاپ هنگام نصب یا به‌روزرسانی", + "Package update preferences": "تنظیمات به‌روزرسانی بسته", + "Update check frequency, automatically install updates, etc.": "فرکانس بررسی به‌روزرسانی، نصب خودکار به‌روزرسانی‌ها و غیره.", + "Reduce UAC prompts, elevate installations by default, unlock certain dangerous features, etc.": "اعلانات کنترل سطح دسترسی کاربر(UAC) رو کاهش بده، افزایش سطح دسترسی نصب رو بصورت پیشفرض افزایش بده، قفل ویژگی های مشخص خطرناک و امثالهم رو باز کن.", + "Package operation preferences": "تنظیمات عملیات بسته", + "Enable {pm}": "فعال کردن {pm}", + "Not finding the file you are looking for? Make sure it has been added to path.": "فایلی که دنبالشی رو پیدا نکردی؟ مطمئن شو به مسیر اضافه شده باشه.", + "Select the executable to be used. The following list shows the executables found by UniGetUI": "فایل اجرایی مورد استفاده را انتخاب کنید. فهرست زیر فایل‌های اجرایی پیدا شده توسط UniGetUI را نشان می‌دهد", + "For security reasons, changing the executable file is disabled by default": "برای دلایل امنیتی، تغییر فایل اجرایی بصورت پیشفرض غیرفعال شده است", + "Change this": "این رو تغییر بده", + "Copy path": "کپی مسیر", + "Current executable file:": "فایل اجرایی فعلی:", + "Ignore packages from {pm} when showing a notification about updates": "نادیده گرفتن بسته‌ها از {pm} هنگام نمایش اعلان درباره به‌روزرسانی‌ها", + "Update security": "امنیت به‌روزرسانی", + "Use global setting": "استفاده از تنظیمات سراسری", + "Minimum age for updates": "حداقل عمر به‌روزرسانی‌ها", + "e.g. 10": "مثلاً 10", + "Custom minimum age (days)": "حداقل عمر سفارشی (روز)", + "{pm} does not provide release dates for its packages, so this setting will have no effect": "{pm} برای بسته‌های خود تاریخ انتشار ارائه نمی‌کند، بنابراین این تنظیم اثری نخواهد داشت", + "{pm} only provides release dates for some of its packages, so this setting will only apply to those packages": "{pm} تنها برای برخی از بسته\bهای خود تاریخ انتشار را ارائه می\bدهد، بنابراین این تنظیم فقط برای آن بسته\bها اعمال خواهد شد", + "Override the global minimum update age for this package manager": "برای این مدیر بسته، حداقل عمر سراسری به‌روزرسانی را بازنویسی کن", + "View {0} logs": "مشاهده لاگ‌های {0}", + "If Python cannot be found or is not listing packages but is installed on the system, ": "اگر Python پیدا نمی‌شود یا با اینکه روی سیستم نصب است بسته‌ها را فهرست نمی‌کند، ", + "Advanced options": "تنظیمات پیشرفته", + "WinGet command-line tool": "ابزار خط فرمان WinGet", + "Choose which command-line tool UniGetUI uses for WinGet operations when the COM API is not used": "انتخاب کنید وقتی از COM API استفاده نمی‌شود، UniGetUI برای عملیات WinGet از کدام ابزار خط فرمان استفاده کند", + "WinGet COM API": "رابط COM API WinGet", + "Choose whether UniGetUI can use the WinGet COM API before falling back to the command-line tool": "انتخاب کنید آیا UniGetUI می‌تواند پیش از بازگشت به ابزار خط فرمان از WinGet COM API استفاده کند یا نه", + "Reset WinGet": "بازنشانی WinGet", + "This may help if no packages are listed": "این ممکن است کمک کند اگر هیچ بسته‌ای فهرست نشده", + "Force install location parameter when updating packages with custom locations": "هنگام به‌روزرسانی بسته‌هایی با مکان‌های سفارشی، پارامتر محل نصب را اجباری کن", + "Install Scoop": "نصب Scoop", + "Uninstall Scoop (and its packages)": "حذف Scoop (و بسته های آن)", + "Run cleanup and clear cache": "اجرای پاک‌سازی و پاک کردن کش", + "Run": "اجرا", + "Enable Scoop cleanup on launch": "فعال کردن پاکسازی Scoop هنگام راه اندازی ", + "Default vcpkg triplet": "سه‌تایی پیش‌فرض vcpkg", + "Change vcpkg root location": "تغییر محل ریشه vcpkg", + "Reset vcpkg root location": "بازنشانی محل ریشه vcpkg", + "Open vcpkg root location": "باز کردن محل ریشه vcpkg", + "Language, theme and other miscellaneous preferences": "زبان، تم و تنظیمات گوناگون دیگر ", + "Show notifications on different events": "نمایش اعلان‌ها در رویدادهای مختلف", + "Change how UniGetUI checks and installs available updates for your packages": "نحوهٔ بررسی و نصب به‌روزرسانی‌های موجود برای بسته‌های شما توسط UniGetUI را تغییر دهید", + "Automatically save a list of all your installed packages to easily restore them.": "به صورت خودکار یک لیست از همه ی بسته های نصب شده ذخیره کن تا بتوانید به آسانی آن ها را برگردانید.", + "Enable and disable package managers, change default install options, etc.": "فعالسازی و غیرفعالسازی مدیر های بسته، تغییر تنظیمات نصب پیشفرض و غیره.", + "Internet connection settings": "تنظیمات اتصال اینترنت", + "Proxy settings, etc.": "تنظیمات پروکسی و غیره.", + "Beta features and other options that shouldn't be touched": "امکانات بتا و گزینه‌های دیگر که نباید تغییر داده شوند", + "Reload sources": "بارگذاری مجدد منابع", + "Delete source": "حذف منبع", + "Known sources": "منابع شناخته‌شده", + "Update checking": "بررسی به‌روزرسانی‌ها", + "Automatic updates": "به‌روزرسانی‌های خودکار", + "Check for package updates periodically": "به‌روزرسانی‌های بسته را به صورت دوره‌ای بررسی کن", + "Check for updates every:": "یافتن به روز رسانی در هر:", + "Install available updates automatically": "به‌روزرسانی‌های موجود را به‌طور خودکار نصب کن", + "Do not automatically install updates when the network connection is metered": "هنگامی که اتصال شبکه محدود است، به‌روزرسانی‌ها را به طور خودکار نصب نکن", + "Do not automatically install updates when the device runs on battery": "هنگامی که دستگاه با باتری کار می‌کند، به‌روزرسانی‌ها را به‌طور خودکار نصب نکن", + "Do not automatically install updates when the battery saver is on": "هنگامی که صرفه‌جویی باتری روشن است، به‌روزرسانی‌ها را به طور خودکار نصب نکن", + "Only show updates that are at least the specified number of days old": "فقط به‌روزرسانی‌هایی را نشان بده که دست‌کم به تعداد روزهای مشخص‌شده قدیمی باشند", + "Warn me when the installer URL host changes between the installed version and the new version (WinGet only)": "اگر میزبان URL نصب‌کننده بین نسخهٔ نصب‌شده و نسخهٔ جدید تغییر کرد، به من هشدار بده (فقط WinGet)", + "Change how UniGetUI handles install, update and uninstall operations.": "تغییر نحوهٔ عملکرد UniGetUI در نصب، به‌روزرسانی و حذف", + "Navigation": "ناوبری", + "Check for UniGetUI updates": "بررسی به‌روزرسانی‌های UniGetUI", + "Quit UniGetUI": "خروج از UniGetUI", + "Filters": "فیلتر ها", + "Sources": "منابع", + "Search for packages to start": "جستجو بسته ها برای شروع", + "Select all": "انتخاب همه", + "Clear selection": "پاک کردن انتخاب شده ها", + "Instant search": "جستجوی فوری\n", + "Distinguish between uppercase and lowercase": "تمایز بین حروف کوچک و بزرگ", + "Ignore special characters": "نادیده گرفتن کاراکتر های خاص", + "Search mode": "حالت جستجو", + "Both": "هر دو", + "Exact match": "تطابق کامل", + "Show similar packages": "نمایش بسته های مشابه", + "Loading": "در حال بارگذاری", + "Package": "بسته", + "More options": "گزینه‌های بیشتر", + "Order by:": "مرتب‌سازی بر اساس:", + "Name": "نام", + "Id": "شناسه", + "Ascendant": "بالا رونده", + "Descendant": "پایین رونده", + "View modes": "حالت‌های نمایش", + "Reload": "بارگذاری مجدد", + "Closed": "بسته شده", + "Ascending": "صعودی", + "Descending": "نزولی", + "{0}: {1}, {2}": "{0}: {1}، {2}", + "Order by": "مرتب‌سازی بر اساس", + "No results were found matching the input criteria": "هیچ نتیجه ای مطابق با معیارهای ورودی یافت نشد", + "No packages were found": "هیچ بسته ای پیدا نشد", + "Loading packages": "در حال بارگیری بسته ها", + "Skip integrity checks": "چشم پوشی از بررسی های یکپارچگی", + "Download selected installers": "دانلود نصب کننده های انتخاب شده", + "Install selection": "نصب انتخاب شده ها", + "Install options": "تنظیمات نصب", + "Add selection to bundle": "اضافه کردن انتخاب شده ها به مجموعه", + "Download installer": "بارگیری نصب کننده", + "Uninstall selection": "حذف نصب انتخاب شده ها", + "Uninstall options": "تنظیمات حذف نصب", + "Ignore selected packages": "نادیده گرفتن بسته های انتخاب شده", + "Open install location": "باز کردن مکان نصب", + "Reinstall package": "بازنصب بسته", + "Uninstall package, then reinstall it": "حذف بسته و سپس دوباره نصب کردن آن", + "Ignore updates for this package": "نادیده گرفتن بروزرسانی های این بسته", + "WinGet malfunction detected": "نقص عملکرد WinGet تشخیص داده شد", + "It looks like WinGet is not working properly. Do you want to attempt to repair WinGet?": "به نظر می‌رسد WinGet به درستی کار نمی‌کند. می‌خواهید تلاش کنید WinGet را تعمیر کنید؟", + "Repair WinGet": "تعمیر WinGet", + "Updates will no longer be ignored for {0}": "به‌روزرسانی‌ها دیگر برای {0} نادیده گرفته نخواهند شد", + "Updates are now ignored for {0}": "به‌روزرسانی‌ها اکنون برای {0} نادیده گرفته می‌شوند", + "Do not ignore updates for this package anymore": "دیگر به‌روزرسانی‌های این بسته را نادیده نگیرید", + "Add packages or open an existing package bundle": "اضافه کردن بسته ها یا باز کردن بسته مجموعه موجود", + "Add packages to start": "اضافه کردن بسته ها برای شروع", + "The current bundle has no packages. Add some packages to get started": "باندل فعلی هیچ بسته ای ندارد. برای شروع چند بسته اضافه کنید", + "New": "جدید", + "Save as": "ذخیره در", + "Create .ps1 script": "ایجاد اسکریپت .ps1", + "Remove selection from bundle": "حذف انتخاب شده ها از باندل", + "Skip hash checks": "رد کردن بررسی‌های Hash", + "The package bundle is not valid": "مجموعه بسته معتبر نیست", + "The bundle you are trying to load appears to be invalid. Please check the file and try again.": "مجموعه‌ای که سعی می‌کنید بارگذاری کنید نامعتبر به نظر می‌رسد. لطفاً فایل را بررسی کرده و دوباره تلاش کنید.", + "Package bundle": "باندل بسته", + "Could not create bundle": "امکان ایجاد بسته وجود ندارد", + "The package bundle could not be created due to an error.": "مجموعه بسته به دلیل خطا ایجاد نشد.", + "Install script": "اسکریپت نصب", + "PowerShell script": "اسکریپت PowerShell", + "The installation script saved to {0}": "اسکریپت نصب در {0} ذخیره شد", + "An error occurred": "یک خطا رخ داده است", + "An error occurred while attempting to create an installation script:": "هنگام تلاش برای ایجاد اسکریپت نصب، خطایی رخ داد:", + "Hooray! No updates were found.": "هورا! هیچ به روز رسانی پیدا نشد!", + "Uninstall selected packages": "حذف بسته های انتخاب شده", + "Update selection": "بروزرسانی انتخاب شده ها", + "Update options": "تنظیمات بروزرسانی", + "Uninstall package, then update it": "حذف بسته و سپس به روز رسانی آن", + "Uninstall package": "حذف بسته", + "Skip this version": "رد کردن این نسخه", + "Pause updates for": "توقف بروزرسانی ها برای", + "User | Local": "کاربر | محلی", + "Machine | Global": "دستگاه | سراسری", + "The default package manager for Debian/Ubuntu-based Linux distributions.
Contains: Debian/Ubuntu packages": "مدیر بسته پیش‌فرض برای توزیع‌های لینوکس مبتنی بر Debian/Ubuntu.
شامل: بسته‌های Debian/Ubuntu", + "The Rust package manager.
Contains: Rust libraries and programs written in Rust": "مدیر بسته Rust.
شامل: کتابخانه‌های Rust و برنامه‌های نوشته شده در Rust", + "The classical package manager for windows. You'll find everything there.
Contains: General Software": "مدیر بسته کلاسیک برای ویندوز. همه چیز را آنجا پیدا خواهید کرد.
شامل: نرم افزار عمومی", + "The default package manager for RHEL/Fedora-based Linux distributions.
Contains: RPM packages": "مدیر بسته پیش‌فرض برای توزیع‌های لینوکس مبتنی بر RHEL/Fedora.
شامل: بسته‌های RPM", + "A repository full of tools and executables designed with Microsoft's .NET ecosystem in mind.
Contains: .NET related tools and scripts": "یک مخزن پر از ابزار ها و فایل های اجرایی طراحی شده با در نظر گرفتن اکوسیستم مایکروسافت دات نت.
دارای: ابزار ها و اسکریپت های مربوط به دات نت\n", + "The universal Linux package manager for desktop applications.
Contains: Flatpak applications from configured remotes": "مدیر بستهٔ جهانی Linux برای برنامه‌های دسکتاپ.
شامل: برنامه‌های Flatpak از راه‌دورهای پیکربندی‌شده", + "NuPkg (zipped manifest)": "NuPkg (مشخصات فشرده شده)", + "The Missing Package Manager for macOS (or Linux).
Contains: Formulae, Casks": "مدیر بستهٔ گمشده برای macOS (یا Linux).
شامل: Formulae, Casks", + "Node JS's package manager. Full of libraries and other utilities that orbit the javascript world
Contains: Node javascript libraries and other related utilities": "مدیر بسته Node JS. پر از کتابخانه ها و سایر ابزارهای کاربردی که در مدار جهان جاوا اسکریپت می گردند
شامل: کتابخانه های جاوا اسکریپت گره و سایر ابزارهای مرتبط", + "The default package manager for Arch Linux and its derivatives.
Contains: Arch Linux packages": "مدیر بسته پیش‌فرض برای Arch Linux و مشتقات آن.
شامل: بسته‌های Arch Linux", + "Python's library manager. Full of python libraries and other python-related utilities
Contains: Python libraries and related utilities": "مدیر کتابخانه پایتون پر از کتابخانه‌های پایتون و سایر ابزارهای مرتبط با پایتون
شامل: کتابخانه‌های پایتون و ابزارهای مرتبط", + "PowerShell's package manager. Find libraries and scripts to expand PowerShell capabilities
Contains: Modules, Scripts, Cmdlets": "مدیر بسته PowerShell. یافتن کتابخانه ها و اسکریپت ها برای گسترش قابلیت های PowerShell
شامل: ماژول ها، اسکریپت ها، Cmdlet ها", + "extracted": "استخراج شده", + "Scoop package": "بسته Scoop", + "Great repository of unknown but useful utilities and other interesting packages.
Contains: Utilities, Command-line programs, General Software (extras bucket required)": "مخزن عالی از ابزارهای ناشناخته اما کاربردی و بسته‌های جالب دیگر.
شامل: ابزارها، برنامه‌های خط فرمان، نرم‌افزارهای عمومی (نیازمند extras bucket) ", + "The universal Linux package manager by Canonical.
Contains: Snap packages from the Snapcraft store": "مدیر بسته جهانی لینوکس توسط Canonical.
شامل: بسته‌های Snap از فروشگاه Snapcraft", + "library": "کتابخانه", + "feature": "ویژگی", + "A popular C/C++ library manager. Full of C/C++ libraries and other C/C++-related utilities
Contains: C/C++ libraries and related utilities": "یک برنامه مدیریتی محبوب برای کتابخانه‌های C/C++. پر از کتابخانه‌ها و ابزارهای مرتبط با C/C++
شامل می‌شود: کتابخانه‌ها و ابزارهای C/C++ ", + "option": "گزینه", + "This package cannot be installed from an elevated context.": "این بسته نمی‌تواند از محیط ارتقا یافته نصب شود.", + "Please run UniGetUI as a regular user and try again.": "لطفاً UniGetUI را به عنوان کاربر عادی اجرا کرده و دوباره تلاش کنید.", + "Please check the installation options for this package and try again": "لطفاً گزینه‌های نصب این بسته را بررسی کرده و دوباره تلاش کنید", + "Microsoft's official package manager. Full of well-known and verified packages
Contains: General Software, Microsoft Store apps": "مدیر بسته رسمی مایکروسافت. پر از بسته های شناخته شده و تأیید شده
شامل: نرم افزار عمومی، برنامه های فروشگاه مایکروسافت", + "Local PC": "کامپیوتر محلی", + "Android Subsystem": "محیط اندروید تحت ویندوز", + "Operation on queue (position {0})...": "عملیات در صف (موقعیت {0})...", + "Click here for more details": "برای اطلاعات بیشتر کلیک کنید", + "Operation canceled by user": "عملیات توسط کاربر لغو شد", + "Running PreOperation ({0}/{1})...": "در حال اجرای PreOperation ({0}/{1})...", + "PreOperation {0} out of {1} failed, and was tagged as necessary. Aborting...": "PreOperation {0} از {1} ناموفق بود و به‌عنوان ضروری علامت‌گذاری شده بود. در حال لغو...", + "PreOperation {0} out of {1} finished with result {2}": "PreOperation {0} از {1} با نتیجهٔ {2} پایان یافت", + "Starting operation...": "شروع عملیات...", + "Running PostOperation ({0}/{1})...": "در حال اجرای PostOperation ({0}/{1})...", + "PostOperation {0} out of {1} failed, and was tagged as necessary. Aborting...": "PostOperation {0} از {1} ناموفق بود و به‌عنوان ضروری علامت‌گذاری شده بود. در حال لغو...", + "PostOperation {0} out of {1} finished with result {2}": "PostOperation {0} از {1} با نتیجهٔ {2} پایان یافت", + "{package} installer download": "دانلود نصب‌کننده بسته {package}", + "{0} installer is being downloaded": "{0} در حال نصب است", + "Download succeeded": "بارگیری با موفقیت انجام شد", + "{package} installer was downloaded successfully": "نصب کننده بسته {package} با موفقیت دانلود شد", + "Download failed": "دانلود ناموفق", + "{package} installer could not be downloaded": "نصب کننده بسته {package} دانلود نشد", + "{package} Installation": "پروسه نصب بسته {package}", + "{0} is being installed": "{0} در حال نصب است", + "Installation succeeded": "نصب با موفقیت انجام شد", + "{package} was installed successfully": "{package} با موفقیت نصب شد", + "Installation failed": "نصب انجام نشد", + "{package} could not be installed": "بسته {package} نصب نمیشود", + "{package} Update": "به روز رسانی بسته {package}", + "Update succeeded": "بروزرسانی با موفقیت انجام شد", + "{package} was updated successfully": "بسته {package} با موفقیت به روز رسانی شد", + "Update failed": "بروزرسانی شکست خورد", + "{package} could not be updated": "بسته {package} به روز رسانی نمیشود", + "{package} Uninstall": "حذف بسته {package}", + "{0} is being uninstalled": "{0} در حال حذف است", + "Uninstall succeeded": "حذف موفقیت آمیز بود", + "{package} was uninstalled successfully": "بسته {package} با موفقیت حذف شد", + "Uninstall failed": "حذف ناموفق", + "{package} could not be uninstalled": "بسته {package} حذف نمیشود", + "Adding source {source}": "در حال اضافه کردن منبع {source}", + "Adding source {source} to {manager}": "درحال اضافه منبع {source} به {manager}.", + "Source added successfully": "منبع با موفقیت اضافه شد", + "The source {source} was added to {manager} successfully": "منبع {source} با موفقیت به {manager} اضافه شد", + "Could not add source": "افزودن منبع صورت نگرفت", + "Could not add source {source} to {manager}": "نتوانستیم منبع {source} را به {manager} اضافه کنیم", + "Removing source {source}": "حذف منبع {source}", + "Removing source {source} from {manager}": "در حال حذف منبع {source} از {manager}", + "Source removed successfully": "منبع با موفقیت حذف شد", + "The source {source} was removed from {manager} successfully": "منبع {source} با موفقیت از {manager} حذف شد", + "Could not remove source": "حذف منبع صورت نگرفت", + "Could not remove source {source} from {manager}": "نتوانستیم منبع {source} را از {manager} حذف کنیم", + "The package manager \"{0}\" was not found": "مدیر بسته \"{0}\" یافت نشد", + "The package manager \"{0}\" is disabled": "مدیر بسته \"{0}\" غیرفعال است", + "There is an error with the configuration of the package manager \"{0}\"": "خطایی در پیکربندی مدیر بسته \"{0}\" وجود دارد", + "The package \"{0}\" was not found on the package manager \"{1}\"": "بسته \"{0}\" در مدیر بسته \"{1}\" یافت نشد", + "{0} is disabled": "{0} تا غیر فعال شده است", + "{0} weeks": "{0} هفته", + "1 month": "۱ ماه", + "{0} months": "{0} ماه", + "Something went wrong": "مشکلی پیش آمد", + "An interal error occurred. Please view the log for further details.": "یک خطای داخلی رخ داد. لطفا برای اطلاعات بیشتر لاگ را نگاه کنید.", + "No applicable installer was found for the package {0}": "هیچ نصب‌کننده قابل اعمالی برای بسته {0} یافت نشد", + "Integrity checks will not be performed during this operation": "بررسی‌های یکپارچگی در طول این عملیات انجام نخواهد شد", + "This is not recommended.": "این توصیه نمی‌شود.", + "Run now": "الان اجرا کن", + "Run next": "بعد از این اجرا کن", + "Run last": "در آخر اجرا کن", + "Show in explorer": "نمایش در اکسپلورر", + "Checked": "علامت‌خورده", + "Unchecked": "بدون علامت", + "This package is already installed": "این بسته قبلاً نصب شده است", + "This package can be upgraded to version {0}": "این بسته قابل ارتقا به نسخه {0} است", + "Updates for this package are ignored": "بروزرسانی های این بسته نادیده گرفته شود ", + "This package is being processed": "این بسته در حال پردازش است", + "This package is not available": "این بسته در دسترس نیست", + "Select the source you want to add:": "منبعی را که می خواهید اضافه کنید انتخاب کنید:", + "Source name:": "نام منبع:", + "Source URL:": "آدرس URL منبع:", + "An error occurred when adding the source: ": "یک خطا درحین اضافه کردن منبع رخ داد:", + "Package management made easy": "مدیریت بسته آسان شد", + "version {0}": "نسخه {0}", + "[RAN AS ADMINISTRATOR]": "[به عنوان ادمین اجرا شد]", + "Portable mode": "حالت قابل حمل", + "DEBUG BUILD": "نسخه دیباگ", + "Here you can change UniGetUI's behaviour regarding the following shortcuts. Checking a shortcut will make UniGetUI delete it if if gets created on a future upgrade. Unchecking it will keep the shortcut intact": "اینجا می‌توانید رفتار UniGetUI را در مورد میانبرهای زیر تغییر دهید. علامت زدن یک میانبر باعث می‌شود UniGetUI آن را حذف کند اگر در ارتقای آینده ایجاد شود. برداشتن علامت آن را دست نخورده نگه می‌دارد", + "Manual scan": "اسکن دستی", + "Existing shortcuts on your desktop will be scanned, and you will need to pick which ones to keep and which ones to remove.": "میان‌برهای موجود روی دسکتاپ شما اسکن می‌شوند و باید انتخاب کنید کدام را نگه دارید و کدام را حذف کنید", + "Delete?": "حذف؟", + "I understand": "فهمیدم", + "Chocolatey setup changed": "تنظیمات Chocolatey تغییر کرد", + "UniGetUI no longer includes its own private Chocolatey installation. A legacy UniGetUI-managed Chocolatey installation was detected for this user profile, but system Chocolatey was not found. Chocolatey will stay unavailable in UniGetUI until Chocolatey is installed on the system and UniGetUI is restarted. Applications previously installed through UniGetUI's bundled Chocolatey may still appear under other sources such as Local PC or WinGet.": "UniGetUI دیگر شامل نصب اختصاصی Chocolatey خود نمی‌شود. یک نصب Chocolatey قدیمی مدیریت‌شده توسط UniGetUI برای این پروفایل کاربری شناسایی شد، اما Chocolatey سیستمی یافت نشد. Chocolatey تا زمانی که روی سیستم نصب نشود و UniGetUI مجدداً راه‌اندازی نشود، در UniGetUI در دسترس نخواهد بود. برنامه‌هایی که قبلاً از طریق Chocolatey همراه UniGetUI نصب شده‌اند، ممکن است همچنان در منابع دیگر مانند Local PC یا WinGet نمایش داده شوند.", + "NOTE: This troubleshooter can be disabled from UniGetUI Settings, on the WinGet section": "توجه: این عیب‌یاب را می‌توان از تنظیمات UniGetUI، در بخش WinGet غیرفعال کرد", + "Restart": "راه‌اندازی مجدد", + "Are you sure you want to delete all shortcuts?": "آیا مطمئن هستید که می‌خواهید همهٔ میان‌برها را حذف کنید؟", + "Any new shorcuts created during an install or an update operation will be deleted automatically, instead of showing a confirmation prompt the first time they are detected.": "میان‌برهای جدیدی که هنگام نصب یا به‌روزرسانی ایجاد می‌شوند، بدون نمایش پیغام تأیید، به‌صورت خودکار حذف خواهند شد", + "Any shorcuts created or modified outside of UniGetUI will be ignored. You will be able to add them via the {0} button.": "هر میان‌بری که خارج از UniGetUI ایجاد یا ویرایش شده باشد، نادیده گرفته می‌شود. می‌توانید آن‌ها را از طریق دکمهٔ {0} اضافه کنید", + "Are you really sure you want to enable this feature?": "آیا مطمئن هستید که این قابلیت فعال شود؟", + "No new shortcuts were found during the scan.": "هنگام اسکن، هیچ میان‌بر جدیدی پیدا نشد.", + "How to add packages to a bundle": "نحوه افزودن بسته‌ها به مجموعه", + "In order to add packages to a bundle, you will need to: ": "برای افزودن بسته‌ها به مجموعه، باید: ", + "1. Navigate to the \"{0}\" or \"{1}\" page.": "۱. به صفحه {0} یا {1} بروید", + "2. Locate the package(s) you want to add to the bundle, and select their leftmost checkbox.": "۲. بسته (های) مورد نظر برای افزودن به مجموعه را انتخاب کرده و تیک سمت چپ آن‌ها را بزنید", + "3. When the packages you want to add to the bundle are selected, find and click the option \"{0}\" on the toolbar.": "۳. وقتی بسته‌هایی که می‌خواهید به مجموعه اضافه کنید را انتخاب کردید، گزینه {0} را از نوار ابزار انتخاب کنید", + "4. Your packages will have been added to the bundle. You can continue adding packages, or export the bundle.": "۴. بسته‌های شما به مجموعه اضافه شده‌اند. می‌توانید به اضافه کردن بسته‌های بیشتر ادامه دهید یا مجموعه را از برنامه خارج کنید", + "Which backup do you want to open?": "کدوم پشتیبان رو میخوای باز کنی؟", + "Select the backup you want to open. Later, you will be able to review which packages you want to install.": "پشتیبانی که میخوای باز کنی رو انتخاب کن. بعدش، میتونی بسته/برنامه ای که میخوای رو بازگردانی کنی", + "There are ongoing operations. Quitting UniGetUI may cause them to fail. Do you want to continue?": "برخی عملیات در حال انجام هستند. بستن UniGetUI ممکن است باعث شکست آن‌ها شود. آیا مایلید ادامه دهید؟", + "UniGetUI or some of its components are missing or corrupt.": "برخی از کامپوننت های UniGetUI یا کل آن از دست رفته یا خراب شده اند.", + "It is strongly recommended to reinstall UniGetUI to adress the situation.": "نصب مجدد UniGetUI عمیقا پیشنهاد میشه تا وضعیت آدرس دهی بشه.", + "Refer to the UniGetUI Logs to get more details regarding the affected file(s)": "به لاگ های UniGetUI رجوع شود برای جزئیات بیشتر درمورد فایل(های) تحت تاثیر", + "Integrity checks can be disabled from the Experimental Settings": "بررسی های یکپارچگی از طریق تنظیمات آزمایشی میتونن غیرفعال بشن", + "Repair UniGetUI": "تعمیر UniGetUI", + "Live output": "خروجی بلادرنگ", + "This package bundle had some settings that are potentially dangerous, and may be ignored by default.": "این باندل بسته تنظیماتی داشت که خطرناک هستند، و شاید بصورت پیش فرض مردود بشن.", + "Entries that show in YELLOW will be IGNORED.": "ورودی های زرد رنگ پشت سر گذاشته خواهند شد.", + "Entries that show in RED will be IMPORTED.": "ورودی های قرمز رنگ وارد خواهند شد.", + "You can change this behavior on UniGetUI security settings.": "شما میتوانید این رفتار را در تنظیمات امنیتی UniGetUI تغییر دهید.", + "Open UniGetUI security settings": "باز کردن تنظیمات امنیتی UniGetUI", + "Should you modify the security settings, you will need to open the bundle again for the changes to take effect.": "اگه تنظیمات رو تغییر بدی، برای اینکه تغییرات موثر واقع بشن لازمه باندل رو دوباره باز کنی.", + "Details of the report:": "جزئیات گزارش:", + "Are you sure you want to create a new package bundle? ": "از ایجاد مجموعهٔ جدید بسته‌ها مطمئن هستید؟", + "Any unsaved changes will be lost": "تغییرات ذخیره‌نشده از بین خواهند رفت", + "Warning!": "هشدار!", + "For security reasons, custom command-line arguments are disabled by default. Go to UniGetUI security settings to change this. ": "برای دلایل امنیتی، آرگومان های سفارشی خط فرمان بصورت پیشفرض غیرفعال شده اند. برای تغییر این مورد به تنظیمات امنیتی UniGetUI بروید.", + "Change default options": "تغییر تنظیمات پیشفرض", + "Ignore future updates for this package": "نادیده گرفتن بروزرسانی های آینده این بسته", + "For security reasons, pre-operation and post-operation scripts are disabled by default. Go to UniGetUI security settings to change this. ": "برای دلایل امنیتی، اسکریپت های پیش عملیات و هنگام عملیات بصورت پیشفرض غیرفعال شده اند. برای تغییر این مورد به تنظیمات امنیتی UniGetUI بروید.", + "You can define the commands that will be run before or after this package is installed, updated or uninstalled. They will be run on a command prompt, so CMD scripts will work here.": "شما میتوانید دستوراتی را مشخص کنید که قبل یا بعد از نصب، بروزرسانی یا حذف نصب این بسته اجرا شوند. آنها روی یک Command Prompt ذخیره خواهند شد، بنابراین اسکریپت های CMD اینجا کار خواهند کرد.", + "Change this and unlock": "این رو تغییر بده و فعال کن", + "{0} Install options are currently locked because {0} follows the default install options.": "{0} تنظیمات نصب درحال حاضر قفل هستند چون {0} از تنظیمات پیشفرض نصب پیروی میکند.", + "Unset or unknown": "تنظیم نشده یا ناشناخته", + "This package has no screenshots or is missing the icon? Contrbute to UniGetUI by adding the missing icons and screenshots to our open, public database.": "این بسته اسکرین‌شات یا آیکن ندارد؟ با اضافه کردن آیکن‌ها و اسکرین‌شات‌های گم‌شده به پایگاه‌داده عمومی و آزاد UniGetUI در بهبود آن مشارکت کنید.", + "Become a contributor": "یک شریک شوید", + "Update to {0} available": "بروزرسانی به {0} موجود است", + "Reinstall": "نصب مجدد", + "Installer not available": "نصب کننده در دسترس نیست", + "Version:": "نسخه:", + "UniGetUI Version {0}": "UniGetUI نسخه {0}", + "Performing backup, please wait...": "در حال انجام بک آپ گیری، لطفاً صبر کنید...", + "An error occurred while logging in: ": "یک خطا هنگام ورود کاربر رخ داد:", + "Fetching available backups...": "درحال بررسی پشتیبان های در درسترس...", + "Done!": "انجام شد!", + "The cloud backup has been loaded successfully.": "پشتیبان ابر با موفقیت لود شد.", + "An error occurred while loading a backup: ": "یک خطا هنگام اجرای فایل پشتیبان رخ داد:", + "Backing up packages to GitHub Gist...": "درحال پشتیبان گیری بسته ها به Github Gist...", + "Backup Successful": "پشتیبان گیری با موفقیت انجام شد", + "The cloud backup completed successfully.": "پشتیبان گیری ابر با موفقیت به پایان رسید.", + "Could not back up packages to GitHub Gist: ": "پشتیبان گیری بسته ها به Github Gist انجام نشد:", + "It is not guaranteed that the provided credentials will be stored safely, so you may as well not use the credentials of your bank account": "تضمینی وجود ندارد که اطلاعات ورود ارائه‌شده به‌صورت ایمن ذخیره شوند، پس بهتر است از اطلاعات حساب بانکی خود استفاده نکنید.", + "Enable the automatic WinGet troubleshooter": "فعال کردن عیب‌یاب خودکار WinGet", + "Add updates that fail with a 'no applicable update found' to the ignored updates list": "به‌روزرسانی‌هایی که با خطای «به‌روزرسانی سازگاری پیدا نشد» شکست می‌خورند را به فهرست به‌روزرسانی‌های نادیده‌گرفته‌شده اضافه کن", + "Invalid selection": "انتخاب نامعتبر", + "No package was selected": "هیچ بسته‌ای انتخاب نشد", + "More than 1 package was selected": "بیش از ۱ بسته انتخاب شد", + "List": "لیست", + "Grid": "شبکه", + "Icons": "آیکون‌ها", + "\"{0}\" is a local package and does not have available details": "{0} یک بسته محلی است و اطلاعاتی برای آن در دسترس نیست", + "\"{0}\" is a local package and is not compatible with this feature": "{0} یک بسته محلی است و با این قابلیت سازگار نیست", + "Add packages to bundle": "افزودن بسته ها به مجموعه", + "Preparing packages, please wait...": "در حال آماده سازی بسته ها، لطفا صبر کنید...", + "Loading packages, please wait...": "در حال بارگیری بسته ها، لطفا صبر کنید...", + "Saving packages, please wait...": "در حال ذخیره بسته ها، لطفا صبر کنید...", + "The bundle was created successfully on {0}": "مجموعه با موفقیت در {0} ایجاد شد", + "User profile": "نمایهٔ کاربر", + "Error": "خطا", + "Log in failed: ": "ورود کاربر شکست خورد:", + "Log out failed: ": "خروج کاربر شکست خورد:", + "Package backup settings": "تنظیمات پشتیبان گیری بسته", + "Manage UniGetUI autostart behaviour from the Settings app": "مدیریت رفتار اجرای خودکار UniGetUI", + "Choose how many operations shoulds be performed in parallel": "انتخاب کنید چند عملیات به‌صورت هم‌زمان انجام شوند", + "Something went wrong while launching the updater.": "هنگام اجرای به‌روزرسان، مشکلی پیش آمد.", + "Please try again later": "لطفاً بعداً دوباره تلاش کنید", + "Show the release notes after UniGetUI is updated": "نمایش یادداشت‌های انتشار پس از به‌روزرسانی UniGetUI" +} diff --git a/src/Languages/lang_fi.json b/src/Languages/lang_fi.json new file mode 100644 index 0000000..9c17d39 --- /dev/null +++ b/src/Languages/lang_fi.json @@ -0,0 +1,850 @@ +{ + "{0} of {1} operations completed": "{0}/{1} toimintoa valmistunut", + "{0} is now {1}": "{0} on nyt {1}", + "Enabled": "Käytössä", + "Disabled": "Pois käytöstä", + "Privacy": "Tietosuoja", + "Hide my username from the logs": "Piilota käyttäjänimeni lokeista", + "Replaces your username with **** in the logs. Restart UniGetUI to also hide it from already-recorded entries.": "Korvaa käyttäjänimesi lokeissa merkeillä ****. Uudelleenkäynnistä UniGetUI piilottaaksesi sen myös jo tallennetuista merkinnöistä.", + "Your last update attempt did not complete.": "Viimeisin päivitysyrityksesi ei valmistunut.", + "UniGetUI could not confirm whether the update succeeded. Open the log to see what happened.": "UniGetUI ei voinut varmistaa, onnistuiko päivitys. Avaa loki nähdäksesi, mitä tapahtui.", + "View log": "Näytä loki", + "The installer reported success but did not restart UniGetUI.": "Asennusohjelma ilmoitti onnistumisesta, mutta ei käynnistänyt UniGetUI:ta uudelleen.", + "The installer failed to initialize.": "Asennusohjelman alustaminen epäonnistui.", + "Setup was canceled before installation began.": "Asennus peruttiin ennen kuin asennus alkoi.", + "A fatal error occurred during the preparation phase.": "Valmisteluvaiheessa tapahtui vakava virhe.", + "A fatal error occurred during installation.": "Asennuksen aikana tapahtui vakava virhe.", + "Installation was canceled while in progress.": "Asennus peruttiin sen ollessa käynnissä.", + "The installer was terminated by another process.": "Toinen prosessi lopetti asennusohjelman.", + "The preparation phase determined the installation cannot proceed.": "Valmisteluvaiheessa todettiin, ettei asennusta voida jatkaa.", + "The installer could not start. UniGetUI may already be running, or you do not have permission to install.": "Asennusohjelmaa ei voitu käynnistää. UniGetUI saattaa olla jo käynnissä, tai sinulla ei ole oikeutta asentaa.", + "Unexpected installer error.": "Odottamaton asennusohjelman virhe.", + "We are checking for updates.": "Tarkistamme päivityksiä.", + "Please wait": "Ole hyvä ja odota", + "Great! You are on the latest version.": "Hienoa! Käytössä tuorein versio.", + "There are no new UniGetUI versions to be installed": "Uusia UniGetUI-versioita ei ole asennettavissa", + "UniGetUI version {0} is being downloaded.": "UniGetUI-versiota {0} ladataan.", + "This may take a minute or two": "Tämä voi kestää muutaman minuutin", + "The installer authenticity could not be verified.": "Asennusohjelman aitoutta ei voitu varmistaa.", + "The update process has been aborted.": "Päivitysprosessi on keskeytetty.", + "Auto-update is not yet available on this platform.": "Automaattinen päivitys ei ole vielä saatavilla tällä alustalla.", + "Please update UniGetUI manually.": "Päivitä UniGetUI manuaalisesti.", + "An error occurred when checking for updates: ": "Tapahtui virhe tarkistaessa päivityksiä:", + "The updater could not be launched.": "Päivitysohjelmaa ei voitu käynnistää.", + "The operating system did not start the installer process.": "Käyttöjärjestelmä ei käynnistänyt asennusohjelman prosessia.", + "UniGetUI is being updated...": "UniGetUI päivitetään...", + "Update installed.": "Päivitys asennettu.", + "UniGetUI was updated successfully, but this running copy was not replaced. This usually means you are running a development build. Close this copy and start the newly-installed version to finish.": "UniGetUI päivitettiin onnistuneesti, mutta tätä käynnissä olevaa kopiota ei korvattu. Tämä tarkoittaa yleensä, että käytössä on kehitysversio. Viimeistele sulkemalla tämä kopio ja käynnistämällä juuri asennettu versio.", + "The update could not be applied.": "Päivitystä ei voitu ottaa käyttöön.", + "Installer exit code {0}: {1}": "Asennusohjelman lopetuskoodi {0}: {1}", + "Update cancelled.": "Päivitys peruttu.", + "Authentication was cancelled.": "Todennus peruttiin.", + "Installer exit code {0}": "Asennusohjelman lopetuskoodi {0}", + "Operation in progress": "Toiminta käynnissä", + "Please wait...": "Ole hyvä ja odota...", + "Success!": "Onnistui!", + "Failed": "Epäonnistui", + "An error occurred while processing this package": "Tätä pakettia käsiteltäessä tapahtui virhe", + "Installer": "Asennusohjelma", + "Executable": "Suoritettava tiedosto", + "MSI": "MSI", + "Compressed file": "Pakattu tiedosto", + "MSIX": "MSIX", + "WinGet was repaired successfully": "WinGet korjattiin onnistuneesti", + "It is recommended to restart UniGetUI after WinGet has been repaired": "On suositeltavaa käynnistää UniGetUI uudelleen WinGetin korjauksen jälkeen", + "WinGet could not be repaired": "WinGetiä ei voitu korjata", + "An unexpected issue occurred while attempting to repair WinGet. Please try again later": "Odottamaton ongelma tapahtui yritettäessä korjata WinGetiä. Yritä myöhemmin uudelleen", + "Log in to enable cloud backup": "Kirjaudu sisään ottaaksesi käyttöön pilvivarmuuskopioinnin", + "Backup Failed": "Varmuuskopiointi epäonnistui", + "Downloading backup...": "Ladataan varmuuskopiota...", + "An update was found!": "Päivitys löytyi!", + "{0} can be updated to version {1}": "{0} voidaan päivittää versioon {1}", + "Updates found!": "Päivityksiä löytyi!", + "{0} packages can be updated": "{0} paketit voidaan päivittää", + "{0} is being updated to version {1}": "{0} päivitetty versioon {1}", + "{0} packages are being updated": "{0} paketit päivitetään", + "You have currently version {0} installed": "Sinulla on tällä hetkellä asennettuna versio {0}", + "Desktop shortcut created": "Työpöytä pikakuvake luotu", + "UniGetUI has detected a new desktop shortcut that can be deleted automatically.": "UniGetUI on havainnut uuden työpöydän pikakuvakkeen, joka voidaan poistaa automaattisesti.", + "{0} desktop shortcuts created": "{0} työpöydän pikakuvaketta luotu", + "UniGetUI has detected {0} new desktop shortcuts that can be deleted automatically.": "UniGetUI on havainnut {0} uutta työpöydän pikakuvaketta, jotka voidaan poistaa automaattisesti.", + "Attention required": "Huomiota tarvitaan", + "Restart required": "Uudelleenkäynnistys vaaditaan", + "1 update is available": "1 päivitys valmiina", + "{0} updates are available": "{0} päivitystä on saatavilla", + "Everything is up to date": "Kaikki on ajantasalla", + "Discover Packages": "Tutustu Paketteihin", + "Available Updates": "Saatavilla olevat päivitykset", + "Installed Packages": "Asennetut Paketit", + "UniGetUI Version {0} by Devolutions": "UniGetUI versio {0}, Devolutions", + "Show UniGetUI": "Näytä UniGetUI", + "Quit": "Poistu", + "Are you sure?": "Oletko varma?", + "Do you really want to uninstall {0}?": "Haluatko todella poistaa sovelluksen {0}?", + "Do you really want to uninstall the following {0} packages?": "Haluatko todella poistaa seuraavat {0} paketit?", + "No": "Ei", + "Yes": "Kyllä", + "Partial": "Osittainen", + "View on UniGetUI": "Näytä UniGetUI:ssa", + "Update": "Päivitä", + "Open UniGetUI": "Avaa UniGetUI", + "Update all": "Päivitä kaikki", + "Update now": "Päivitä nyt", + "Installer host changed since the installed version.\n": "Asennusohjelman isäntä on muuttunut asennetusta versiosta.\n", + "This package is on the queue": "Tämä paketti on jonossa", + "installing": "asennetaan", + "updating": "päivitetään", + "uninstalling": "poistetaan asennusta", + "installed": "asennettu", + "Retry": "Uudelleen", + "Install": "Asenna", + "Uninstall": "Poista asennus", + "Open": "Avaa", + "Operation profile:": "Toimintaprofiili:", + "Follow the default options when installing, upgrading or uninstalling this package": "Noudata oletusasetuksia tämän paketin asennuksen, päivityksen tai poiston yhteydessä", + "The following settings will be applied each time this package is installed, updated or removed.": "Seuraavat asetukset otetaan käyttöön aina, kun tämä paketti asennetaan, päivitetään tai poistetaan.", + "Version to install:": "Asennettava versio:", + "Architecture to install:": "Asennuksen arkkitehtuuri:", + "Installation scope:": "Asennuslaajuus:", + "Install location:": "Asenna sijaintiin:", + "Select": "Valitse", + "Reset": "Nollaa", + "Custom install arguments:": "Mukautetun asennuksen argumentit:", + "Custom update arguments:": "Mukautetut päivitysargumentit:", + "Custom uninstall arguments:": "Mukautetut asennuksen poistoargumentit:", + "Pre-install command:": "Esiasennuskomento:", + "Post-install command:": "Asennuksen jälkeinen komento:", + "Abort install if pre-install command fails": "Keskeytä asennus, jos esiasennuskomento epäonnistuu", + "Pre-update command:": "Päivitystä edeltävä komento:", + "Post-update command:": "Päivityksen jälkeinen komento:", + "Abort update if pre-update command fails": "Keskeytä päivitys, jos päivitystä edeltävä komento epäonnistuu", + "Pre-uninstall command:": "Asennuksen poistoa edeltävä komento:", + "Post-uninstall command:": "Asennuksen poiston jälkeinen komento:", + "Abort uninstall if pre-uninstall command fails": "Keskeytä asennuksen poisto, jos asennuksen poistoa edeltävä komento epäonnistuu", + "Command-line to run:": "Suoritettava komentorivi:", + "Save and close": "Tallenna ja sulje", + "General": "Yleiset", + "Architecture & Location": "Arkkitehtuuri ja sijainti", + "Command-line": "Komentorivi", + "Close apps": "Sulje sovellukset", + "Pre/Post install": "Ennen/jälkeen asennusta", + "Select the processes that should be closed before this package is installed, updated or uninstalled.": "Valitse prosessit, jotka tulisi sulkea ennen tämän paketin asentamista, päivittämistä tai poistamista.", + "Write here the process names here, separated by commas (,)": "Kirjoita tähän prosessien nimet pilkuilla (,) erotettuina.", + "Try to kill the processes that refuse to close when requested to": "Yritä lopettaa prosessit, jotka kieltäytyvät sulkeutumasta pyydettäessä", + "Run as admin": "Suorita ylläpitäjänä", + "Interactive installation": "Interaktiivinen asennus", + "Skip hash check": "Ohita hash-tarkistus", + "Uninstall previous versions when updated": "Poista aiemmat versiot päivitettäessä", + "Skip minor updates for this package": "Ohita tämän paketin pienet muutokset", + "Automatically update this package": "Päivitä tämä paketti automaattisesti", + "{0} installation options": "{0} asennuksen vaihtoehdot", + "Latest": "Viimeisin", + "PreRelease": "Esijulkaisu", + "Default": "Oletus", + "Manage ignored updates": "Hallinnoi ohitettuja päivityksiä", + "The packages listed here won't be taken in account when checking for updates. Double-click them or click the button on their right to stop ignoring their updates.": "Tässä lueteltuja paketteja ei oteta huomioon päivityksiä tarkistettaessa. Kaksoisnapsauta niitä tai napsauta niiden oikealla puolella olevaa painiketta lopettaaksesi niiden päivitysten huomioimisen.", + "Reset list": "Nollaa lista", + "Do you really want to reset the ignored updates list? This action cannot be reverted": "Haluatko varmasti nollata ohitettujen päivitysten luettelon? Tätä toimintoa ei voi kumota", + "No ignored updates": "Ei ohitettuja päivityksiä", + "Package Name": "Paketin nimi", + "Package ID": "Paketin ID", + "Ignored version": "Ohitetut versiot", + "New version": "Uusi versio", + "Source": "Lähde", + "All versions": "Kaikki versiot", + "Unknown": "Tuntematon", + "Up to date": "Ajantasalla", + "Package {name} from {manager}": "Paketti {name} lähteestä {manager}", + "Remove {0} from ignored updates": "Poista {0} ohitetuista päivityksistä", + "Cancel": "Peru", + "Administrator privileges": "Järjestelmänvalvojan oikeudet", + "This operation is running with administrator privileges.": "Tämä toiminto on käynnissä järjestelmänvalvojan oikeuksilla.", + "Interactive operation": "Interaktiivinen toiminta", + "This operation is running interactively.": "Tämä toiminto ajetaan interaktiivisesti.", + "You will likely need to interact with the installer.": "Sinun on todennäköisesti oltava vuorovaikutuksessa asennusohjelman kanssa.", + "Integrity checks skipped": "Eheystarkastukset ohitettiin", + "Integrity checks will not be performed during this operation.": "Eheystarkistuksia ei suoriteta tämän toimenpiteen aikana.", + "Proceed at your own risk.": "Jatka omalla vastuullasi.", + "Close": "Sulje", + "Loading...": "Ladataan...", + "Installer SHA256": "Asennusohjelman SHA256", + "Homepage": "Kotisivu", + "Author": "Tekijä", + "Publisher": "Julkaisija", + "License": "Lisenssi", + "Manifest": "Ilmentymä", + "Installer Type": "Asennusohjelman tyyppi", + "Size": "Koko", + "Installer URL": "Asennusohjelman URL", + "Last updated:": "Viimeisin päivitys:", + "Release notes URL": "Julkaisutiedot URL", + "Package details": "Paketin yksityiskohdat", + "Dependencies:": "Riippuvaisuudet:", + "Release notes": "Julkaisutiedot", + "Screenshots": "Kuvakaappaukset", + "This package has no screenshots or is missing the icon? Contribute to UniGetUI by adding the missing icons and screenshots to our open, public database.": "Puuttuuko tältä paketilta kuvakaappauksia tai kuvake? Auta UniGetUI:ta lisäämällä puuttuvat kuvakkeet ja kuvakaappaukset avoimeen, julkiseen tietokantaamme.", + "Version": "Versio", + "Install as administrator": "Asenna järjestelmänvalvojana", + "Update to version {0}": "Päivitetty versioon {0}", + "Installed Version": "Asennettu versio", + "Update as administrator": "Päivitä järjestelmänvalvojana", + "Interactive update": "Interaktiivinen päivitys", + "Uninstall as administrator": "Poista asennus järjestelmänvalvojana", + "Interactive uninstall": "Interaktiivinen asennuksen purku", + "Uninstall and remove data": "Poista asennus ja poista tietoja", + "Not available": "Ei saatavilla", + "Installer SHA512": "Asennusohjelman SHA512", + "Unknown size": "Tuntematon koko", + "No dependencies specified": "Riippuvaisuuksia ei määritelty", + "mandatory": "pakollinen", + "optional": "valinnainen", + "UniGetUI {0} is ready to be installed.": "UniGetUI {0} on valmis asennettavaksi.", + "The update process will start after closing UniGetUI": "Päivitysprosessi alkaa UniGetUI:n sulkemisen jälkeen", + "UniGetUI has been ran as administrator, which is not recommended. When running UniGetUI as administrator, EVERY operation launched from UniGetUI will have administrator privileges. You can still use the program, but we highly recommend not running UniGetUI with administrator privileges.": "UniGetUI:ta on suoritettu järjestelmänvalvojana, mitä ei suositella. Kun UniGetUI:ta suoritetaan järjestelmänvalvojana, KAIKILLA UniGetUI:sta käynnistetyillä toiminnoilla on järjestelmänvalvojan oikeudet. Voit silti käyttää ohjelmaa, mutta suosittelemme vahvasti, ettet suorita UniGetUI:ta järjestelmänvalvojan oikeuksilla.", + "Share anonymous usage data": "Jaa anonyymiä käyttötietoa", + "UniGetUI collects anonymous usage data in order to improve the user experience.": "UniGetUI kerää anonyymejä käyttötietoja parantaakseen käyttökokemusta.", + "Accept": "Hyväksy", + "Software Updates": "Ohjelmistopäivitykset", + "Package Bundles": "Pakettiniput", + "Settings": "Asetukset", + "Package Managers": "Paketinhallinnat", + "UniGetUI Log": "UniGetUI-loki", + "Package Manager logs": "Paketinhallinta logit", + "Operation history": "Toimintojen historia", + "Help": "Ohjeet", + "UniGetUI": "UniGetUI", + "You have installed UniGetUI Version {0}": "Asennettu UniGetUI versio: {0}", + "Disclaimer": "Vastuuvapauslauseke", + "UniGetUI is developed by Devolutions and is not affiliated with any of the compatible package managers.": "UniGetUI:n kehittäjä on Devolutions, eikä se ole sidoksissa yhteenkään yhteensopivaan paketinhallintaohjelmaan.", + "UniGetUI wouldn't have been possible without the help of the contributors. Thank you all 🥳": "UniGetUI ei olisi ollut mahdollinen ilman avustajien apua. Kiitos kaikille 🥳", + "UniGetUI uses the following libraries. Without them, UniGetUI wouldn't have been possible.": "UniGetUI käyttää seuraavia kirjastoja. Ilman niitä UniGetUI ei olisi ollut mahdollinen.", + "{0} homepage": "{0} kotisivu", + "UniGetUI has been translated to more than 40 languages thanks to the volunteer translators. Thank you 🤝": "UniGetUI on käännetty yli 40 kielelle vapaaehtoisten kääntäjien ansiosta. Kiitos 🤝", + "Verbose": "Monisanainen", + "1 - Errors": "1 - Virheet", + "2 - Warnings": "2 - Varoitukset", + "3 - Information (less)": "3 - Tietoja (vähemmän)", + "4 - Information (more)": "4 - Tietoja (enemmän)", + "5 - information (debug)": "5 - Tietoja (debug)", + "Warning": "Varoitus", + "The following settings may pose a security risk, hence they are disabled by default.": "Seuraavat asetukset voivat aiheuttaa tietoturvariskin, joten ne ovat oletusarvoisesti poissa käytöstä.", + "Enable the settings below if and only if you fully understand what they do, and the implications they may have.": "Ota alla olevat asetukset käyttöön vain ja ainoastaan, jos ymmärrät täysin niiden toiminnot ja mahdolliset seuraukset.", + "The settings will list, in their descriptions, the potential security issues they may have.": "Asetusten kuvauksissa luetellaan mahdolliset tietoturvaongelmat, joita niillä saattaa olla.", + "The backup will include the complete list of the installed packages and their installation options. Ignored updates and skipped versions will also be saved.": "Varmuuskopio sisältää täydellisen luettelon asennetuista paketeista ja niiden asennusvaihtoehdoista. Myös ohitetut päivitykset ja ohitetut versiot tallennetaan.", + "The backup will NOT include any binary file nor any program's saved data.": "Varmuuskopio EI sisällä binääritiedostoja eikä minkään ohjelman tallennettuja tietoja.", + "The size of the backup is estimated to be less than 1MB.": "Varmuuskopion koon arvioidaan olevan alle 1 Mt.", + "The backup will be performed after login.": "Varmuuskopiointi suoritetaan kirjautumisen jälkeen.", + "{pcName} installed packages": "{pcName} asensi paketteja", + "Current status: Not logged in": "Nykyinen tila: ei kirjautunut", + "You are logged in as {0} (@{1})": "Olet kirjautunut sisään nimellä {0} (@{1})", + "Nice! Backups will be uploaded to a private gist on your account": "Hienoa! Varmuuskopiot ladataan tilisi yksityiseen Gist-kansioon.", + "Select backup": "Valitse varmuuskopio", + "Settings imported from {0}": "Asetukset tuotu kohteesta {0}", + "UniGetUI Settings": "UniGetUI-asetukset", + "Settings exported to {0}": "Asetukset viety kohteeseen {0}", + "UniGetUI settings were reset": "UniGetUI-asetukset nollattiin", + "Allow pre-release versions": "Salli esijulkaisuversiot", + "Apply": "Käytä", + "For security reasons, custom command-line arguments are disabled by default. Go to UniGetUI security settings to change this.": "Tietoturvasyistä mukautetut komentoriviargumentit ovat oletusarvoisesti poissa käytöstä. Muuta tätä UniGetUI:n turvallisuusasetuksissa.", + "Go to UniGetUI security settings": "Siirry UniGetUI turvallisuus asetuksiin", + "The following options will be applied by default each time a {0} package is installed, upgraded or uninstalled.": "Seuraavat asetukset otetaan käyttöön oletusarvoisesti aina, kun {0}-paketti asennetaan, päivitetään tai poistetaan.", + "Package's default": "Pakettien oletukset", + "Install location can't be changed for {0} packages": "Asennussijaintia ei voi muuttaa {0} paketille", + "The local icon cache currently takes {0} MB": "Paikallinen ikoni välimuisti vie tilaa {0} MB", + "Username": "Käyttäjätunnus", + "Password": "Salasana", + "Credentials": "Valtuustiedot", + "It is not guaranteed that the provided credentials will be stored safely": "Ei voida taata, että annetut kirjautumistiedot tallennetaan turvallisesti", + "Partially": "Osittain", + "Package manager": "Pakettien hallinta", + "Compatible with proxy": "Yhteensopiva välityspalvelimen kanssa", + "Compatible with authentication": "Yhteensopiva autentikoinnin kanssa", + "Proxy compatibility table": "Välityspalvelimen yhteensopivuustaulukko", + "{0} settings": "{0} asetukset", + "{0} status": "{0} tila", + "Default installation options for {0} packages": "Oletusasennusvaihtoehdot {0} paketille", + "Expand version": "Laajenna versio", + "The executable file for {0} was not found": "Suoritettavaa tiedostoa kohteelle {0} ei löytynyt", + "{pm} is disabled": "{pm} ei ole käytössä", + "Enable it to install packages from {pm}.": "Ota se käyttöön, jos haluat asentaa paketteja kohteesta {pm}.", + "{pm} is enabled and ready to go": "{pm} on käytössä ja valmis käyttöön", + "{pm} version:": "{pm} versio:", + "{pm} was not found!": "{pm} ei löytynyt!", + "You may need to install {pm} in order to use it with UniGetUI.": "Sinun on ehkä asennettava {pm} käyttääksesi sitä UniGetUI:n kanssa.", + "Scoop Installer - UniGetUI": "Scoop asennusohjelma - UniGetUI", + "Scoop Uninstaller - UniGetUI": "Scoop asennuksen poisto - UniGetUI", + "Clearing Scoop cache - UniGetUI": "Scoop-välimuistin tyhjennys - UniGetUI ", + "Restart UniGetUI to fully apply changes": "Käynnistä UniGetUI uudelleen, jotta muutokset tulevat kokonaan voimaan", + "Restart UniGetUI": "Uudelleenkäynnistä UniGetUI", + "Manage {0} sources": "Hallinnoi {0} lähteitä", + "Add source": "Lisää lähde", + "Add": "Lisäys", + "Source name": "Lähteen nimi", + "Source URL": "Lähteen URL-osoite", + "Other": "Muut", + "No minimum age": "Ei vähimmäisikää", + "1 day": "1 päivä", + "{0} days": "{0} päivää", + "Custom...": "Mukautettu...", + "{0} minutes": "{0} minuuttia", + "1 hour": "1 tunti", + "{0} hours": "{0} tuntia", + "1 week": "1 viikko", + "Supports release dates": "Tukee julkaisupäiviä", + "Release date support per package manager": "Julkaisupäivätuki pakettienhallinnoittain", + "Search for packages": "Hae paketteja", + "Local": "Paikallinen", + "OK": "OK", + "Last checked: {0}": "Viimeksi tarkistettu: {0}", + "{0} packages were found, {1} of which match the specified filters.": "Löytyi {0} pakettia, joista {1} vastaa määritettyjä suodattimia.", + "{0} selected": "{0} valittu", + "(Last checked: {0})": "(Viimeksi tarkistettu: {0})", + "All packages selected": "Kaikki paketit valittu", + "Package selection cleared": "Pakettivalinta tyhjennetty", + "{0}: {1}": "{0}: {1}", + "More info": "Lisää tietoa", + "GitHub account": "GitHub-tili", + "Log in with GitHub to enable cloud package backup.": "Kirjaudu sisään GitHubilla ottaaksesi käyttöön pilvipakettien varmuuskopioinnin.", + "More details": "Lisää yksityiskohtia", + "Log in": "Kirjaudu", + "If you have cloud backup enabled, it will be saved as a GitHub Gist on this account": "Jos pilvivarmuuskopiointi on käytössä, se tallennetaan GitHub Gist -tiedostona tälle tilille.", + "Log out": "Uloskirjaudu", + "About UniGetUI": "Tietoja UniGetUI:sta", + "About": "Tietoja", + "Third-party licenses": "Kolmannen osapuolen lisenssit", + "Contributors": "Osallistujat", + "Translators": "Kääntäjät", + "Bundle security report": "Paketin turvallisuusraportti", + "The bundle contained restricted content": "Paketti sisälsi rajoitettua sisältöä", + "UniGetUI – Crash Report": "UniGetUI – Kaatumisraportti", + "UniGetUI has crashed": "UniGetUI on kaatunut", + "Help us fix this by sending a crash report to Devolutions. All fields below are optional.": "Auta meitä korjaamaan tämä lähettämällä kaatumisraportti Devolutionsille. Kaikki alla olevat kentät ovat valinnaisia.", + "Email (optional)": "Sähköposti (valinnainen)", + "your@email.com": "sinun@sahkoposti.fi", + "Additional details (optional)": "Lisätiedot (valinnainen)", + "Describe what you were doing when the crash occurred…": "Kuvaile mitä teit kun kaatuminen tapahtui…", + "Crash report": "Kaatumisraportti", + "Don't Send": "Älä lähetä", + "Send Report": "Lähetä raportti", + "Sending…": "Lähetetään…", + "Unsaved changes": "Tallentamattomat muutokset", + "You have unsaved changes in the current bundle. Do you want to discard them?": "Nykyisessä paketissa on tallentamattomia muutoksia. Haluatko hylätä ne?", + "Discard changes": "Hylkää muutokset", + "Integrity violation": "Eheysrikkomus", + "UniGetUI or some of its components are missing or corrupt. It is strongly recommended to reinstall UniGetUI to adress the situation.": "UniGetUI tai jotkin sen osat puuttuvat tai ovat vioittuneet. On erittäin suositeltavaa asentaa UniGetUI uudelleen tilanteen korjaamiseksi.", + "• Refer to the UniGetUI Logs to get more details regarding the affected file(s)": "• Katso UniGetUI-lokeista lisätietoja kyseisistä tiedostoista.", + "• Integrity checks can be disabled from the Experimental Settings": "• Eheystarkistukset voidaan poistaa käytöstä kokeellisista asetuksista.", + "Manage shortcuts": "Hallitse pikanäppäimiä", + "UniGetUI has detected the following desktop shortcuts which can be removed automatically on future upgrades": "UniGetUI on havainnut seuraavat työpöydän pikakuvakkeet, jotka voidaan poistaa automaattisesti tulevien päivitysten yhteydessä", + "Do you really want to reset this list? This action cannot be reverted.": "Haluatko todella nollata tämän luettelon? Tätä toimintoa ei voi peruuttaa.", + "Desktop shortcuts list": "Työpöydän pikakuvakkeiden luettelo", + "Open in explorer": "Avaa resurssienhallinnassa", + "Remove from list": "Poista listalta", + "When new shortcuts are detected, delete them automatically instead of showing this dialog.": "Kun uusia pikakuvakkeita havaitaan, poista ne automaattisesti tämän valintaikkunan näyttämisen sijaan.", + "Not right now": "Ei juuri nyt", + "Missing dependency": "Riippuvuus puuttuu", + "UniGetUI requires {0} to operate, but it was not found on your system.": "UniGetUI vaatii {0} toimiakseen, mutta sitä ei löytynyt järjestelmästäsi.", + "Click on Install to begin the installation process. If you skip the installation, UniGetUI may not work as expected.": "Napsauta Asenna aloittaaksesi asennusprosessin. Jos ohitat asennuksen, UniGetUI ei välttämättä toimi odotetulla tavalla.", + "Alternatively, you can also install {0} by running the following command in a Windows PowerShell prompt:": "Vaihtoehtoisesti voit myös asentaa sovelluksen {0} suorittamalla seuraavan komennon Windows PowerShell -kehotteessa:", + "Install {0}": "Asenna {0}", + "Do not show this dialog again for {0}": "Älä näytä tätä valintaikkunaa uudelleen kohteelle {0}", + "Please wait while {0} is being installed. A black window may show up. Please wait until it closes.": "Odota, kun {0} asennetaan. Näkyviin saattaa tulla musta ikkuna. Odota, kunnes se sulkeutuu.", + "{0} has been installed successfully.": "{0} on asennettu onnistuneesti.", + "Please click on \"Continue\" to continue": "Napsauta \"Jatka\" jatkaaksesi", + "Continue": "Jatka", + "{0} has been installed successfully. It is recommended to restart UniGetUI to finish the installation": "{0} on asennettu onnistuneesti. On suositeltavaa käynnistää UniGetUI uudelleen asennuksen viimeistelemiseksi", + "Restart later": "Uudelleenkäynnistä myöhemmin", + "An error occurred:": "Tapahtui virhe:", + "Please see the Command-line Output or refer to the Operation History for further information about the issue.": "Katso komentorivilähdöstä tai käyttöhistoriasta saadaksesi lisätietoja ongelmasta.", + "Retry as administrator": "Yritä uudelleen järjestelmänvalvojana", + "Retry interactively": "Yritä uudelleen interaktiivisesti", + "Retry skipping integrity checks": "Yritä uudelleen ohittaa eheystarkistukset", + "Installation options": "Asennusvaihtoehdot", + "Save": "Tallenna", + "UniGetUI collects anonymous usage data with the sole purpose of understanding and improving the user experience.": "UniGetUI kerää anonyymejä käyttötietoja, joiden ainoa tarkoitus on ymmärtää ja parantaa käyttökokemusta.", + "More details about the shared data and how it will be processed": "Lisätietoja jaetuista tiedoista ja niiden käsittelystä", + "Do you accept that UniGetUI collects and sends anonymous usage statistics, with the sole purpose of understanding and improving the user experience?": "Hyväksytkö että UniGetUI kerää ja lähettää anonyymejä käyttötilastoja, joiden ainoa tarkoitus on ymmärtää ja parantaa käyttökokemusta?", + "Decline": "Hylkää", + "No personal information is collected nor sent, and the collected data is anonimized, so it can't be back-tracked to you.": "Henkilökohtaisia ​​tietoja ei kerätä eikä lähetetä, ja kerätyt tiedot anonymisoidaan, joten niitä ei voida palauttaa sinulle.", + "Navigation panel": "Navigointipaneeli", + "Operations": "Toiminnot", + "Toggle operations panel": "Näytä tai piilota toimintopaneeli", + "Bulk operations": "Joukkotoiminnot", + "Retry failed": "Yritä epäonnistuneita uudelleen", + "Clear successful": "Tyhjennä onnistuneet", + "Clear finished": "Tyhjennä valmistuneet", + "Cancel all": "Peru kaikki", + "More": "Lisää", + "Toggle navigation panel": "Näytä tai piilota siirtymispaneeli", + "Minimize": "Pienennä", + "Maximize": "Suurenna", + "UniGetUI by Devolutions": "UniGetUI, Devolutions", + "UniGetUI is an application that makes managing your software easier, by providing an all-in-one graphical interface for your command-line package managers.": "UniGetUI on sovellus, joka helpottaa ohjelmistojen hallintaa tarjoamalla all-in-one graafisen käyttöliittymän komentorivipakettien hallintaa varten.", + "Useful links": "Hyödyllisiä linkkejä", + "UniGetUI Homepage": "UniGetUI:n kotisivu", + "Report an issue or submit a feature request": "Ilmoita ongelmasta tai lähetä ominaisuuspyyntö", + "UniGetUI Repository": "UniGetUI:n lähdekoodivarasto", + "View GitHub Profile": "Näytä GitHub profiili", + "UniGetUI License": "UniGetUI Lisenssi", + "Using UniGetUI implies the acceptation of the MIT License": "UniGetUI:n käyttö edellyttää MIT-lisenssin hyväksymistä", + "Become a translator": "Liity kääntäjäksi", + "Go back": "Siirry taaksepäin", + "Go forward": "Siirry eteenpäin", + "Go to home page": "Siirry etusivulle", + "Reload page": "Lataa sivu uudelleen", + "View page on browser": "Näytä sivu selaimessa", + "The built-in browser is not supported on Linux yet.": "Sisäänrakennettua selainta ei vielä tueta Linuxissa.", + "Open in browser": "Avaa selaimessa", + "Copy to clipboard": "Kopioi leikepöydälle", + "Export to a file": "Vie tiedostoon", + "Log level:": "Lokin taso:", + "Reload log": "Lataa loki uudelleen", + "Export log": "Vie loki", + "Text": "Teksti", + "Change how operations request administrator rights": "Muuta tapaa, jolla toiminnot pyytävät järjestelmänvalvojan oikeuksia", + "Restrictions on package operations": "Pakettitoimintojen rajoitukset", + "Restrictions on package managers": "Pakettienhallinnan rajoitukset", + "Restrictions when importing package bundles": "Pakettikokoelmien tuonnin rajoitukset", + "Ask for administrator privileges once for each batch of operations": "Pyydä järjestelmänvalvojan oikeuksia kerran jokaista toimintosarjaa kohden", + "Ask only once for administrator privileges": "Kysy järjestelmänvalvojan oikeuksia vain kerran", + "Prohibit any kind of Elevation via UniGetUI Elevator or GSudo": "Estä kaikenlainen korkeuden nostaminen UniGetUI Elevator- tai GSudo-toiminnolla", + "This option WILL cause issues. Any operation incapable of elevating itself WILL FAIL. Install/update/uninstall as administrator will NOT WORK.": "Tämä vaihtoehto aiheuttaa ongelmia. Mikä tahansa toiminto, joka ei pysty itseään korottamaan, EPÄONNISTUU. Asennus/päivitys/poisto järjestelmänvalvojana EI TOIMI.", + "Allow custom command-line arguments": "Salli mukautetut komentoriviargumentit", + "Custom command-line arguments can change the way in which programs are installed, upgraded or uninstalled, in a way UniGetUI cannot control. Using custom command-lines can break packages. Proceed with caution.": "Mukautetut komentoriviargumentit voivat muuttaa ohjelmien asennus-, päivitys- tai poistotapaa tavalla, jota UniGetUI ei voi hallita. Mukautettujen komentorivien käyttö voi rikkoa paketteja. Toimi varoen.", + "Ignore custom pre-install and post-install commands when importing packages from a bundle": "Salli mukautettujen ennen ja jälkeen asennuksen suoritettavien komentojen ajaminen", + "Pre and post install commands will be run before and after a package gets installed, upgraded or uninstalled. Be aware that they may break things unless used carefully": "Asennusta edeltävät ja sen jälkeiset komennot suoritetaan ennen paketin asentamista, päivittämistä tai poistamista ja sen jälkeen. Huomaa, että ne voivat rikkoa järjestelmän, ellei niitä käytetä huolellisesti.", + "Allow changing the paths for package manager executables": "Salli pakettienhallinnan suoritettavien tiedostojen polkujen muuttaminen", + "Turning this on enables changing the executable file used to interact with package managers. While this allows finer-grained customization of your install processes, it may also be dangerous": "Tämän ottaminen käyttöön mahdollistaa pakettienhallinnan kanssa vuorovaikutuksessa käytettävän suoritettavan tiedoston muuttamisen. Vaikka tämä mahdollistaa asennusprosessien tarkemman mukauttamisen, se voi olla myös vaarallista.", + "Allow importing custom command-line arguments when importing packages from a bundle": "Salli mukautettujen komentoriviargumenttien tuonti paketteja tuotaessa kokoelmasta", + "Malformed command-line arguments can break packages, or even allow a malicious actor to gain privileged execution. Therefore, importing custom command-line arguments is disabled by default": "Väärin muotoillut komentoriviargumentit voivat rikkoa paketteja tai jopa antaa pahantahtoiselle toimijalle etuoikeuden suoritukseen. Siksi mukautettujen komentoriviargumenttien tuonti on oletusarvoisesti poistettu käytöstä.", + "Allow importing custom pre-install and post-install commands when importing packages from a bundle": "Salli mukautettujen asennusta edeltävien ja asennuksen jälkeisten komentojen tuonti paketteja tuotaessa kokoelmasta", + "Pre and post install commands can do very nasty things to your device, if designed to do so. It can be very dangerous to import the commands from a bundle, unless you trust the source of that package bundle": "Asennusta edeltävät ja sen jälkeiset komennot voivat tehdä laitteellesi erittäin ikäviä asioita, jos ne on suunniteltu tekemään niin. Komentojen tuominen paketista voi olla erittäin vaarallista, ellet luota kyseisen kokoelman lähteeseen.", + "Administrator rights and other dangerous settings": "Järjestelmänvalvojan oikeudet ja muut vaaralliset asetukset", + "Package backup": "Pakettien varmuuskopio", + "Cloud package backup": "Pilvipaketin varmuuskopiointi", + "Local package backup": "Paikallinen pakkettien varmuuskopio", + "Local backup advanced options": "Paikallisen varmuuskopion laajemmat asetukset", + "Log in with GitHub": "Kirjaudu GitHubilla", + "Log out from GitHub": "Uloskirjaudu GitHubista", + "Periodically perform a cloud backup of the installed packages": "Suorita asennettujen pakettien pilvivarmuuskopiointi säännöllisesti", + "Cloud backup uses a private GitHub Gist to store a list of installed packages": "Pilvivarmuuskopiointi käyttää yksityistä GitHub Gist -tiedostoa asennettujen pakettien luettelon tallentamiseen.", + "Perform a cloud backup now": "Suorita pilvivarmuuskopio nyt", + "Backup": "Varmuuskopioi", + "Restore a backup from the cloud": "Palauta varmuuskopio pilvestä", + "Begin the process to select a cloud backup and review which packages to restore": "Aloita pilvivarmuuskopion valintaprosessi ja tarkista palautettavat paketit", + "Periodically perform a local backup of the installed packages": "Suorita säännöllisesti paikallinen varmuuskopio asennetuista paketeista", + "Perform a local backup now": "Suorita paikallinen varmuuskopio nyt", + "Change backup output directory": "Muuta varmuuskopion tulostushakemistoa", + "Set a custom backup file name": "Aseta mukautettu varmuuskopiotiedoston nimi", + "Leave empty for default": "Jätä tyhjäksi oletuksena", + "Add a timestamp to the backup file names": "Lisää aikaleima varmuuskopioiden nimiin", + "Backup and Restore": "Varmuuskopiointi ja palautus", + "Enable background api (UniGetUI Widgets and Sharing, port 7058)": "Ota taustasovellusliittymä käyttöön (UniGetUI-widgetit ja jakaminen, portti 7058)", + "Wait for the device to be connected to the internet before attempting to do tasks that require internet connectivity.": "Odota, että laite muodostaa yhteyden Internetiin, ennen kuin yrität tehdä tehtäviä, jotka edellyttävät Internet-yhteyttä.", + "Disable the 1-minute timeout for package-related operations": "Poista käytöstä minuutin aikakatkaisu pakettikohtaisissa toimissa", + "Use installed GSudo instead of UniGetUI Elevator": "Käytä asennettua GSudoa UniGetUI Elevator -sovelluksen sijaan", + "Use a custom icon and screenshot database URL": "Käytä mukautettua kuvaketta ja kuvakaappausten tietokannan URL-osoitetta", + "Enable background CPU Usage optimizations (see Pull Request #3278)": "Ota käyttöön taustaprosessorin käytön optimoinnit (katso Pull Request #3278)", + "Perform integrity checks at startup": "Suorita eheystarkistukset käynnistyksen yhteydessä", + "When batch installing packages from a bundle, install also packages that are already installed": "Kun asennat paketteja eränä kokoelmasta, asennetaan myös jo asennetut paketit", + "Experimental settings and developer options": "Kokeelliset asetukset ja kehittäjävaihtoehdot", + "Show UniGetUI's version and build number on the titlebar.": "Näytä UniGetUI:n versio ja koontiversion numero otsikkorivillä.", + "Language": "Kieli", + "UniGetUI updater": "UniGetUI päivitysohjelma", + "Telemetry": "Telemetria", + "Manage UniGetUI settings": "Hallinnoi UniGetUI-asetuksia", + "Related settings": "Aiheeseen liittyvät asetukset", + "Update UniGetUI automatically": "Päivitä UniGetUI automaattisesti", + "Check for updates": "Tarkista päivitykset", + "Install prerelease versions of UniGetUI": "Asenna UniGetUI:n esiversioita", + "Manage telemetry settings": "Hallitse telemetria asetuksia", + "Manage": "Hallitse", + "Import settings from a local file": "Tuo asetukset paikallisesta tiedostosta", + "Import": "Tuonti", + "Export settings to a local file": "Vie asetukset paikalliseen tiedostoon", + "Export": "Vienti", + "Reset UniGetUI": "Nollaa UniGetUI", + "User interface preferences": "Käyttöliittymä asetukset", + "Application theme, startup page, package icons, clear successful installs automatically": "Sovelluksen teema, aloitussivu, pakettikuvakkeet, tyhjennä onnistuneet asennukset automaattisesti", + "General preferences": "Yleiset asetukset", + "UniGetUI display language:": "UniGetUI näytettävä kieli:", + "System language": "Järjestelmän kieli", + "Is your language missing or incomplete?": "Puuttuuko käännöksesi vai onko se puutteellinen?", + "Appearance": "Ulkonäkö", + "UniGetUI on the background and system tray": "UniGetUI taustalla ja ilmaisinalueella", + "Package lists": "Pakettilista", + "Use classic mode": "Käytä perinteistä tilaa", + "Restart UniGetUI to apply this change": "Käynnistä UniGetUI uudelleen ottaaksesi tämän muutoksen käyttöön", + "The classic UI is disabled for beta testers": "Perinteinen käyttöliittymä ei ole käytössä beetatestaajille", + "Close UniGetUI to the system tray": "Pienennä UniGetUI ilmoitusalueelle", + "Manage UniGetUI autostart behaviour": "Hallinnoi UniGetUI:n automaattisen käynnistyksen toimintaa", + "Show package icons on package lists": "Näytä paketin ikonit pakettilistassa", + "Clear cache": "Tyhjennä välimuisti", + "Select upgradable packages by default": "Valitse oletuksena päivitettävät paketit", + "Light": "Vaalea", + "Dark": "Tumma", + "Follow system color scheme": "Seuraa järjestelmän värimaailmaa", + "Application theme:": "Sovelluksen teema:", + "UniGetUI startup page:": "UniGetUI aloitussivu:", + "Proxy settings": "Välityspalvelimen asetukset", + "Other settings": "Muut asetukset", + "Connect the internet using a custom proxy": "Yhdistä Internetiin mukautetun välityspalvelimen avulla", + "Please note that not all package managers may fully support this feature": "Huomaa, että kaikki paketinhallintaohjelmat eivät välttämättä tue tätä ominaisuutta täysin", + "Proxy URL": "Välityspalvelimen URL-osoite", + "Enter proxy URL here": "Kirjoita välityspalvelimen URL-osoite tähän", + "Authenticate to the proxy with a user and a password": "Todenna välityspalvelimeen käyttäjätunnuksella ja salasanalla", + "Internet and proxy settings": "Internet- ja välityspalvelinasetukset", + "Package manager preferences": "Paketinhallinnan asetukset", + "Ready": "Valmis", + "Not found": "Ei löytynyt", + "Notification preferences": "Ilmoitusasetukset", + "Notification types": "Ilmoitustyypit", + "The system tray icon must be enabled in order for notifications to work": "Ilmaisinalueen kuvakkeen on oltava käytössä, jotta ilmoitukset toimivat", + "Enable UniGetUI notifications": "Ota UniGetUI-ilmoitukset käyttöön", + "Show a notification when there are available updates": "Näytä ilmoitus, kun päivityksiä on saatavilla", + "Show a silent notification when an operation is running": "Näytä äänetön ilmoitus, kun toiminto on käynnissä", + "Show a notification when an operation fails": "Näytä ilmoitus, kun toiminto epäonnistuu", + "Show a notification when an operation finishes successfully": "Näytä ilmoitus, kun toiminto päättyy onnistuneesti", + "Concurrency and execution": "Samanaikaisuus ja toteutus", + "Automatic desktop shortcut remover": "Automaattinen työpöydän pikakuvakkeiden poisto", + "Choose how many operations should be performed in parallel": "Valitse, kuinka monta toimintoa suoritetaan rinnakkain", + "Clear successful operations from the operation list after a 5 second delay": "Poista onnistuneet toiminnot toimintoluettelosta 5 sekunnin viiveen jälkeen", + "Download operations are not affected by this setting": "Tämä asetus ei vaikuta lataustoimintoihin", + "You may lose unsaved data": "Tallentamaton tieto voi kadota", + "Ask to delete desktop shortcuts created during an install or upgrade.": "Pyydä poistamaan asennuksen tai päivityksen aikana luodut työpöydän pikakuvakkeet.", + "Package update preferences": "Paketin päivityksen asetukset", + "Update check frequency, automatically install updates, etc.": "Päivitysten tarkistustiheys, päivitysten automaattinen asennus jne.", + "Reduce UAC prompts, elevate installations by default, unlock certain dangerous features, etc.": "Vähennä käyttäjien valvonnan kehotteita, nosta asennuksia oletusarvoisesti, avaa tiettyjä vaarallisia ominaisuuksia jne.", + "Package operation preferences": "Paketin toiminnan asetukset", + "Enable {pm}": "Ota käyttöön {pm}", + "Not finding the file you are looking for? Make sure it has been added to path.": "Eikö etsimääsi tiedostoa löydy? Varmista, että se on lisätty polkuun.", + "Select the executable to be used. The following list shows the executables found by UniGetUI": "Valitse käytettävä suoritettava tiedosto. Seuraavassa luettelossa näkyvät UniGetUI:n löytämät suoritettavat tiedostot.", + "For security reasons, changing the executable file is disabled by default": "Turvallisuussyistä suoritettavan tiedoston muuttaminen on oletuksena poistettu käytöstä.", + "Change this": "Muuta tämä", + "Copy path": "Kopioi polku", + "Current executable file:": "Nykyinen suoritettava tiedosto:", + "Ignore packages from {pm} when showing a notification about updates": "Ohita paketit alkaen {pm}, kun näet ilmoituksen päivityksistä", + "Update security": "Päivitysturvallisuus", + "Use global setting": "Käytä yleistä asetusta", + "Minimum age for updates": "Päivitysten vähimmäisikä", + "e.g. 10": "esim. 10", + "Custom minimum age (days)": "Mukautettu vähimmäisikä (päivää)", + "{pm} does not provide release dates for its packages, so this setting will have no effect": "{pm} ei tarjoa paketeilleen julkaisupäiviä, joten tällä asetuksella ei ole vaikutusta", + "{pm} only provides release dates for some of its packages, so this setting will only apply to those packages": "{pm} antaa julkaisupäivämäärät vain joillekin paketeilleen, joten tämä asetus koskee vain niitä paketteja", + "Override the global minimum update age for this package manager": "Ohita tämän pakettienhallinnan yleinen päivitysten vähimmäisikä", + "View {0} logs": "Näytä {0} lokit", + "If Python cannot be found or is not listing packages but is installed on the system, ": "Jos Pythonia ei löydy tai se ei listaa paketteja, vaikka se on asennettu järjestelmään, ", + "Advanced options": "Lisäasetukset", + "WinGet command-line tool": "WinGet-komentorivityökalu", + "Choose which command-line tool UniGetUI uses for WinGet operations when the COM API is not used": "Valitse, mitä komentorivityökalua UniGetUI käyttää WinGet-toimintoihin, kun COM API ei ole käytössä", + "WinGet COM API": "WinGet COM API", + "Choose whether UniGetUI can use the WinGet COM API before falling back to the command-line tool": "Valitse, voiko UniGetUI käyttää WinGetin COM API:a ennen komentorivityökaluun palaamista", + "Reset WinGet": "Nollaa UniGetUI", + "This may help if no packages are listed": "Tämä voi auttaa, jos luettelossa ei ole paketteja", + "Force install location parameter when updating packages with custom locations": "Pakota asennussijaintiparametri päivitettäessä paketteja, joissa on mukautettuja sijainteja", + "Install Scoop": "Asenna Scoop", + "Uninstall Scoop (and its packages)": "Poista Scoop (ja sen paketit)", + "Run cleanup and clear cache": "Suorita puhdistus ja tyhjennä välimuisti", + "Run": "Suorita", + "Enable Scoop cleanup on launch": "Ota Scoop-puhdistus käyttöön käynnistyksen yhteydessä", + "Default vcpkg triplet": "Oletus vcpkg tripletti", + "Change vcpkg root location": "Muuta vcpkg:n juurisijaintia", + "Reset vcpkg root location": "Palauta vcpkg-juurisijainti", + "Open vcpkg root location": "Avaa vcpkg-juurisijainti", + "Language, theme and other miscellaneous preferences": "Kieli, teema ja muista sekalaisia asetuksia", + "Show notifications on different events": "Näytä ilmoitukset eri tapahtumista", + "Change how UniGetUI checks and installs available updates for your packages": "Muuta tapaa, jolla UniGetUI tarkistaa ja asentaa paketteihisi saatavilla olevat päivitykset", + "Automatically save a list of all your installed packages to easily restore them.": "Tallenna automaattisesti luettelo kaikista asennetuista paketeista, jotta voit palauttaa ne helposti.", + "Enable and disable package managers, change default install options, etc.": "Ota käyttöön ja poista käytöstä pakettienhallinnan toimintoja, muuta oletusasennusasetuksia jne.", + "Internet connection settings": "Internet-yhteyden asetukset", + "Proxy settings, etc.": "Välityspalvelimen asetukset jne", + "Beta features and other options that shouldn't be touched": "Beta-ominaisuudet ja muut vaihtoehdot, joihin ei pidä koskea", + "Reload sources": "Lataa lähteet uudelleen", + "Delete source": "Poista lähde", + "Known sources": "Tunnetut lähteet", + "Update checking": "Päivitysten tarkistus", + "Automatic updates": "Automaattiset päivitykset", + "Check for package updates periodically": "Tarkista pakettipäivitykset säännöllisesti", + "Check for updates every:": "Tarkista päivitykset joka:", + "Install available updates automatically": "Asenna saatavilla olevat päivitykset automaattisesti", + "Do not automatically install updates when the network connection is metered": "Älä asenna päivityksiä automaattisesti, kun verkkoyhteys on mitattu", + "Do not automatically install updates when the device runs on battery": "Älä asenna päivityksiä automaattisesti, kun laite toimii akkuvirralla", + "Do not automatically install updates when the battery saver is on": "Älä asenna päivityksiä automaattisesti, kun virransäästö on päällä", + "Only show updates that are at least the specified number of days old": "Näytä vain päivitykset, jotka ovat vähintään määritetyn määrän päiviä vanhoja", + "Warn me when the installer URL host changes between the installed version and the new version (WinGet only)": "Varoita, kun asennusohjelman URL-osoitteen isäntä muuttuu asennetun version ja uuden version välillä (vain WinGet)", + "Change how UniGetUI handles install, update and uninstall operations.": "Muuta tapaa, jolla UniGetUI käsittelee asennus-, päivitys- ja asennuksen poistotoiminnot.", + "Navigation": "Navigointi", + "Check for UniGetUI updates": "Tarkista UniGetUI-päivitykset", + "Quit UniGetUI": "Sulje UniGetUI", + "Filters": "Suodattimet", + "Sources": "Lähteet", + "Search for packages to start": "Hae paketteja aloittaaksesi", + "Select all": "Valitse kaikki", + "Clear selection": "Tyhjennä valinta", + "Instant search": "Välitön haku", + "Distinguish between uppercase and lowercase": "Erotetaan isot ja pienet kirjaimet", + "Ignore special characters": "Jätä erikoismerkit huomioimatta", + "Search mode": "Hakutila", + "Both": "Molemmat", + "Exact match": "Täydellinen osuma", + "Show similar packages": "Näytä samankaltaiset paketit", + "Loading": "Ladataan", + "Package": "Paketti", + "More options": "Lisää vaihtoehtoja", + "Order by:": "Järjestä mukaan:", + "Name": "Nimi", + "Id": "ID", + "Ascendant": "Nouseva", + "Descendant": "Laskeva", + "View modes": "Näkymätilat", + "Reload": "Lataa uudelleen", + "Closed": "Suljettu", + "Ascending": "Nouseva", + "Descending": "Laskeva", + "{0}: {1}, {2}": "{0}: {1}, {2}", + "Order by": "Järjestä", + "No results were found matching the input criteria": "Syöttöehtoja vastaavia tuloksia ei löytynyt", + "No packages were found": "Paketteja ei löytynyt", + "Loading packages": "Ladataan paketteja", + "Skip integrity checks": "Ohita eheystarkastukset", + "Download selected installers": "Lataa valitut asennusohjelmat", + "Install selection": "Asenna valitut", + "Install options": "Asennus vaihtoehdot", + "Add selection to bundle": "Lisää valittu pakettiin", + "Download installer": "Lataa asennusohjelma", + "Uninstall selection": "Poista valitut", + "Uninstall options": "Asennuksen poiston vaihtoehdot", + "Ignore selected packages": "Jätä valitut paketit huomioimatta", + "Open install location": "Avaa asennussijainti", + "Reinstall package": "Paketin uudelleenasennus", + "Uninstall package, then reinstall it": "Poista paketin asennus ja uudelleen asenna se", + "Ignore updates for this package": "Jätä tämän paketin päivitykset huomioimatta", + "WinGet malfunction detected": "WinGet-vika havaittu", + "It looks like WinGet is not working properly. Do you want to attempt to repair WinGet?": "WinGet ei näyttäisi toimivan oikein Haluatko yrittää Wingetin korjausta?", + "Repair WinGet": "Korjaa WinGet", + "Updates will no longer be ignored for {0}": "Päivityksiä ei enää ohiteta paketille {0}", + "Updates are now ignored for {0}": "Päivitykset ohitetaan nyt paketille {0}", + "Do not ignore updates for this package anymore": "Älä ohita tämän paketin päivityksiä enää", + "Add packages or open an existing package bundle": "Lisää paketteja tai avaa olemassaoleva pakettinippu", + "Add packages to start": "Lisää paketteja aloittaaksesi", + "The current bundle has no packages. Add some packages to get started": "Nykyinen nippu ei sisällä paketteja. Aloita lisäämällä paketteja", + "New": "Uusi", + "Save as": "Tallenna nimellä", + "Create .ps1 script": "Luo .ps1 skripti", + "Remove selection from bundle": "Poista valinta nipusta", + "Skip hash checks": "Ohita hash-tarkistukset", + "The package bundle is not valid": "Pakettinippu ei kelpaa", + "The bundle you are trying to load appears to be invalid. Please check the file and try again.": "Paketti, jota yrität ladata, näyttää olevan virheellinen. Tarkista tiedosto ja yritä uudelleen.", + "Package bundle": "Pakettinippu", + "Could not create bundle": "Nippua ei voitu luoda", + "The package bundle could not be created due to an error.": "Pakettinippua ei voitu luoda virheen takia.", + "Install script": "Asennus skripti", + "PowerShell script": "PowerShell-komentosarja", + "The installation script saved to {0}": "Asennusskripti tallennettiin kohteeseen {0}", + "An error occurred": "Tapahtui virhe", + "An error occurred while attempting to create an installation script:": "Asennusskriptin luomisessa tapahtui virhe:", + "Hooray! No updates were found.": "Hurraa! Päivityksiä ei löytynyt.", + "Uninstall selected packages": "Poista valitut paketit", + "Update selection": "Päivitä valitut", + "Update options": "Päivitys valinnat", + "Uninstall package, then update it": "Poista paketti ja päivitä se", + "Uninstall package": "Poista paketin asennus", + "Skip this version": "Ohita tämä versio", + "Pause updates for": "Keskeytä päivitykset", + "User | Local": "Käyttäjä | Paikallinen", + "Machine | Global": "Tietokone | Yleinen", + "The default package manager for Debian/Ubuntu-based Linux distributions.
Contains: Debian/Ubuntu packages": "Oletuspaketinhallinta Debian/Ubuntu-pohjaisille Linux-jakeluille.
Sisältää: Debian/Ubuntu-paketit", + "The Rust package manager.
Contains: Rust libraries and programs written in Rust": "Rust-paketinhallinta.
Sisältää: Rust-kirjastot ja Rust-kielellä kirjoitetut ohjelmat", + "The classical package manager for windows. You'll find everything there.
Contains: General Software": "Klassinen pakettien hallinta Windowsille. Sieltä löydät kaiken.
Sisältää: Yleiset ohjelmistot\n", + "The default package manager for RHEL/Fedora-based Linux distributions.
Contains: RPM packages": "Oletuspaketinhallinta RHEL/Fedora-pohjaisille Linux-jakeluille.
Sisältää: RPM-paketit", + "A repository full of tools and executables designed with Microsoft's .NET ecosystem in mind.
Contains: .NET related tools and scripts": "Arkisto täynnä työkaluja ja suoritettavia tiedostoja, jotka on suunniteltu Microsoftin .NET-ekosysteemiä silmällä pitäen.
Sisältää: .NETiin liittyvät työkalut ja komentosarjat", + "The universal Linux package manager for desktop applications.
Contains: Flatpak applications from configured remotes": "Yleiskäyttöinen Linux-paketinhallinta työpöytäsovelluksille.
Sisältää: Flatpak-sovellukset määritetyistä etäkohteista", + "NuPkg (zipped manifest)": "NuPkg (pakattu luettelo)", + "The Missing Package Manager for macOS (or Linux).
Contains: Formulae, Casks": "Puuttuva paketinhallinta macOS:lle (tai Linuxille).
Sisältää: Formulae, Casks", + "Node JS's package manager. Full of libraries and other utilities that orbit the javascript world
Contains: Node javascript libraries and other related utilities": "Node JS:n paketinhallinta. Täynnä kirjastoja ja muita apuohjelmia, jotka kiertävät JavaScript-maailmaa.
Sisältää: Node JS ja muut niihin liittyvät apuohjelmat", + "The default package manager for Arch Linux and its derivatives.
Contains: Arch Linux packages": "Oletuspaketinhallinta Arch Linuxille ja sen johdannaisille.
Sisältää: Arch Linux -paketit", + "Python's library manager. Full of python libraries and other python-related utilities
Contains: Python libraries and related utilities": "Pythonin kirjaston johtaja. Täynnä python-kirjastoja ja muita python-apuohjelmia
Sisältää:Python-kirjastot ja niihin liittyvät apuohjelmat", + "PowerShell's package manager. Find libraries and scripts to expand PowerShell capabilities
Contains: Modules, Scripts, Cmdlets": "PowerShellin paketinhallinta. Etsi kirjastoja ja komentosarjoja laajentaaksesi PowerShell-ominaisuuksia.
Sisältää: Moduulit, Komentosarjat, Cmdletit", + "extracted": "purettu", + "Scoop package": "Scoop paketti", + "Great repository of unknown but useful utilities and other interesting packages.
Contains: Utilities, Command-line programs, General Software (extras bucket required)": "Suuri kokoelma vähemmän tunnettuja, mutta hyödyllisiä apuohjelmia ja muita mielenkiintoisia paketteja.
Sisältää: apuohjelmat, komentoriviohjelmat, yleiset ohjelmistot (vaatii lisäpaketin)", + "The universal Linux package manager by Canonical.
Contains: Snap packages from the Snapcraft store": "Canonicalin yleinen Linux-paketinhallinta.
Sisältää: Snap-paketit Snapcraft-kaupasta", + "library": "kirjasto", + "feature": "ominaisuus", + "A popular C/C++ library manager. Full of C/C++ libraries and other C/C++-related utilities
Contains: C/C++ libraries and related utilities": "Suosittu C/C++-kirjastonhallinta. Täynnä C/C++-kirjastoja ja muita C/C++:aan liittyviä apuohjelmia
Sisältää: C/C++-kirjastot ja niihin liittyvät apuohjelmat", + "option": "vaihtoehto", + "This package cannot be installed from an elevated context.": "Tätä pakettia ei voi asentaa korotetusta sisällöstä.", + "Please run UniGetUI as a regular user and try again.": "Suorita UniGetUI tavallisena käyttäjänä ja yritä uudelleen.", + "Please check the installation options for this package and try again": "Tarkista tämän paketin asennusvaihtoehdot ja yritä uudelleen", + "Microsoft's official package manager. Full of well-known and verified packages
Contains: General Software, Microsoft Store apps": "Microsoftin virallinen paketinhallinta. Täynnä tunnettuja ja vahvistettuja paketteja
Sisältää: Yleiset ohjelmistot, Microsoft Store -sovellukset", + "Local PC": "Paikallinen PC", + "Android Subsystem": "Android-alijärjestelmä", + "Operation on queue (position {0})...": "Toiminto jonossa (järjestysnumero {0})...", + "Click here for more details": "Napsauta tätä saadaksesi lisätietoja", + "Operation canceled by user": "Toiminto keskeytetty käyttäjän toimesta", + "Running PreOperation ({0}/{1})...": "Suoritetaan PreOperation ({0}/{1})...", + "PreOperation {0} out of {1} failed, and was tagged as necessary. Aborting...": "PreOperation {0}/{1} epäonnistui ja se merkittiin pakolliseksi. Keskeytetään...", + "PreOperation {0} out of {1} finished with result {2}": "PreOperation {0}/{1} päättyi tulokseen {2}", + "Starting operation...": "Aloitetaan toiminto...", + "Running PostOperation ({0}/{1})...": "Suoritetaan PostOperation ({0}/{1})...", + "PostOperation {0} out of {1} failed, and was tagged as necessary. Aborting...": "PostOperation {0}/{1} epäonnistui ja se merkittiin pakolliseksi. Keskeytetään...", + "PostOperation {0} out of {1} finished with result {2}": "PostOperation {0}/{1} päättyi tulokseen {2}", + "{package} installer download": "{package} asennusohjelma ladattu", + "{0} installer is being downloaded": "{0} asennusohjelmaa ladataan", + "Download succeeded": "Lataus onnistui", + "{package} installer was downloaded successfully": "{package} asennusohjelma ladattiin onnistuneesti", + "Download failed": "Lataus epäonnistui", + "{package} installer could not be downloaded": "{package} asennusohjelmaa ei voitu ladata", + "{package} Installation": "{package} Asennus", + "{0} is being installed": "{0} ollaan asentamassa", + "Installation succeeded": "Asennus onnistui", + "{package} was installed successfully": "{package} on asennettu onnistuneesti", + "Installation failed": "Asennus epäonnistui", + "{package} could not be installed": "{package} ei voitu asentaa", + "{package} Update": "{package} Päivitys", + "Update succeeded": "Päivitys onnistui", + "{package} was updated successfully": "{package} päivitettiin onnistuneesti", + "Update failed": "Päivitys epäonnistui", + "{package} could not be updated": "{package} päivitys ei onnistu", + "{package} Uninstall": "{package} Asennuksen poisto", + "{0} is being uninstalled": "{0} asennusta poistetaan", + "Uninstall succeeded": "Asennuksen poisto onnistui", + "{package} was uninstalled successfully": "{package} on poistettu onnistuneesti", + "Uninstall failed": "Asennuksen poisto epäonnistui", + "{package} could not be uninstalled": "{package} asennusta ei voitu poistaa", + "Adding source {source}": "Lisätään lähde {source}", + "Adding source {source} to {manager}": "Lisätään lähde {source}: {manager}", + "Source added successfully": "Lähde lisätty onnistuneesti", + "The source {source} was added to {manager} successfully": "Lähde {source} lisättiin hallintaohjelmaan {manager} onnistuneesti", + "Could not add source": "Lähdettä ei voitu lisätä", + "Could not add source {source} to {manager}": "Lähdettä {source} ei voitu lisätä hakemistoon {manager}", + "Removing source {source}": "Poistetaan lähde {source}", + "Removing source {source} from {manager}": "Poistetaan lähdettä {source} {manager}:sta", + "Source removed successfully": "Lähde poistettu onnistuneesti", + "The source {source} was removed from {manager} successfully": "Lähde {source} poistettiin käyttäjältä {manager} onnistuneesti", + "Could not remove source": "Lähdettä ei voitu poistaa", + "Could not remove source {source} from {manager}": "Lähdettä {source} ei voitu poistaa {manager}:sta", + "The package manager \"{0}\" was not found": "Paketinhallintaa \"{0}\" ei löytynyt", + "The package manager \"{0}\" is disabled": "Paketinhallinta \"{0}\" on poistettu käytöstä", + "There is an error with the configuration of the package manager \"{0}\"": "Paketinhallinnan \"{0}\" määrityksessä on virhe", + "The package \"{0}\" was not found on the package manager \"{1}\"": "Pakettia \"{0}\" ei löytynyt paketinhallinnasta \"{1}\"", + "{0} is disabled": "{0} on poistettu käytöstä", + "{0} weeks": "{0} viikkoa", + "1 month": "1 kuukausi", + "{0} months": "{0} kuukautta", + "Something went wrong": "Jotain meni pieleen", + "An interal error occurred. Please view the log for further details.": "Tapahtui sisäinen virhe. Katso lisätietoja lokista.", + "No applicable installer was found for the package {0}": "Paketille {0} ei löytynyt sopivaa asennusohjelmaa", + "Integrity checks will not be performed during this operation": "Eheystarkastuksia ei suoriteta tämän toiminnon aikana", + "This is not recommended.": "Tätä ei suositella", + "Run now": "Suorita nyt", + "Run next": "Suorita seuraava", + "Run last": "Suorita viimeinen", + "Show in explorer": "Näytä explorerissa", + "Checked": "Valittu", + "Unchecked": "Ei valittu", + "This package is already installed": "Tämä paketti on jo asennettu", + "This package can be upgraded to version {0}": "Tämä paketti voidaan päivittää versioon {0}", + "Updates for this package are ignored": "Tämän paketin päivitykset ohitetaan", + "This package is being processed": "Tätä pakettia käsitellään", + "This package is not available": "Tämä paketti ei ole saatavilla", + "Select the source you want to add:": "Valitse lähde, jonka haluat lisätä:", + "Source name:": "Lähteen nimi:", + "Source URL:": "Lähde URL:", + "An error occurred when adding the source: ": "Tapahtui virhe lisätessä lähdettä: ", + "Package management made easy": "Pakettien hallinta tehty helpoksi", + "version {0}": "versio {0}", + "[RAN AS ADMINISTRATOR]": "AJETTU JÄRJESTELMÄNVALVOJANA", + "Portable mode": "Itsenäinen tila", + "DEBUG BUILD": "DEBUG VERSIO", + "Here you can change UniGetUI's behaviour regarding the following shortcuts. Checking a shortcut will make UniGetUI delete it if if gets created on a future upgrade. Unchecking it will keep the shortcut intact": "Täällä voit muuttaa UniGetUI:n käyttäytymistä seuraavien pikanäppäinten suhteen. Pikakuvakkeen tarkistaminen saa UniGetUI:n poistamaan sen, jos se luodaan tulevassa päivityksessä. Jos poistat valinnan, pikakuvake pysyy ennallaan", + "Manual scan": "Manuaalinen skannaus", + "Existing shortcuts on your desktop will be scanned, and you will need to pick which ones to keep and which ones to remove.": "Työpöydälläsi olevat pikakuvakkeet tarkistetaan, ja sinun on valittava, mitkä niistä haluat säilyttää ja mitkä poistaa.", + "Delete?": "Poistetaanko?", + "I understand": "Ymmärrän", + "Chocolatey setup changed": "Chocolatey-asennus muuttui", + "UniGetUI no longer includes its own private Chocolatey installation. A legacy UniGetUI-managed Chocolatey installation was detected for this user profile, but system Chocolatey was not found. Chocolatey will stay unavailable in UniGetUI until Chocolatey is installed on the system and UniGetUI is restarted. Applications previously installed through UniGetUI's bundled Chocolatey may still appear under other sources such as Local PC or WinGet.": "UniGetUI ei enää sisällä omaa yksityistä Chocolatey-asennusta. Tälle käyttäjäprofiilille havaittiin vanha UniGetUI:n hallinnoima Chocolatey-asennus, mutta järjestelmän Chocolateyta ei löytynyt. Chocolatey pysyy käyttökelvottomana UniGetUI:ssä, kunnes Chocolatey asennetaan järjestelmään ja UniGetUI käynnistetään uudelleen. Aiemmin UniGetUI:n mukana tulleen Chocolateyn kautta asennetut sovellukset saattavat silti näkyä muissa lähteissä, kuten Paikallinen tietokone tai WinGet.", + "NOTE: This troubleshooter can be disabled from UniGetUI Settings, on the WinGet section": "HUOMAUTUS: Tämä vianmääritys voidaan poistaa käytöstä UniGetUI-asetuksista WinGet-osiossa", + "Restart": "Uudelleen käynnistä", + "Are you sure you want to delete all shortcuts?": "Haluatko varmasti poistaa kaikki pikakuvakkeet?", + "Any new shorcuts created during an install or an update operation will be deleted automatically, instead of showing a confirmation prompt the first time they are detected.": "Kaikki asennuksen tai päivityksen aikana luodut uudet pikakuvakkeet poistetaan automaattisesti sen sijaan, että näkyisi vahvistuskehote, kun ne havaitaan ensimmäisen kerran.", + "Any shorcuts created or modified outside of UniGetUI will be ignored. You will be able to add them via the {0} button.": "Kaikki UniGetUI:n ulkopuolella luodut tai muokatut pikakuvakkeet ohitetaan. Voit lisätä ne {0}-painikkeella.", + "Are you really sure you want to enable this feature?": "Oletko todella varma, että haluat ottaa tämän ominaisuuden käyttöön?", + "No new shortcuts were found during the scan.": "Tarkistuksen aikana ei löytynyt uusia pikakuvakkeita.", + "How to add packages to a bundle": "Kuinka lisätä paketteja nippuun", + "In order to add packages to a bundle, you will need to: ": "Jotta voit lisätä paketteja nippuun, sinun pitää:", + "1. Navigate to the \"{0}\" or \"{1}\" page.": "1. Siirry sivulle \"{0}\" tai \"{1}\".", + "2. Locate the package(s) you want to add to the bundle, and select their leftmost checkbox.": "2. Etsi paketit, jotka haluat lisätä nippuun, ja valitse niiden vasemmanpuoleisin valintaruutu.", + "3. When the packages you want to add to the bundle are selected, find and click the option \"{0}\" on the toolbar.": "3. Kun paketit, jotka haluat lisätä nippuun, on valittu, etsi työkalupalkista vaihtoehto \"{0}\" ja napsauta sitä.", + "4. Your packages will have been added to the bundle. You can continue adding packages, or export the bundle.": "4. Pakettisi on lisätty nippuun. Voit jatkaa pakettien lisäämistä tai viedä paketin.", + "Which backup do you want to open?": "Minkä varmuuskopion haluat avata?", + "Select the backup you want to open. Later, you will be able to review which packages you want to install.": "Valitse avattava varmuuskopio. Myöhemmin voit tarkistaa, mitkä paketit haluat asentaa.", + "There are ongoing operations. Quitting UniGetUI may cause them to fail. Do you want to continue?": "Toimintaa on meneillään. UniGetUI:n sulkeminen voi aiheuttaa niiden epäonnistumisen. Haluatko jatkaa?", + "UniGetUI or some of its components are missing or corrupt.": "UniGetUI tai jotkin sen komponenteista puuttuvat tai ovat vioittuneet.", + "It is strongly recommended to reinstall UniGetUI to adress the situation.": "On erittäin suositeltavaa asentaa UniGetUI uudelleen tilanteen korjaamiseksi.", + "Refer to the UniGetUI Logs to get more details regarding the affected file(s)": "Katso UniGetUI-lokeista lisätietoja kyseisistä tiedostoista.", + "Integrity checks can be disabled from the Experimental Settings": "Eheystarkistukset voidaan poistaa käytöstä kokeellisista asetuksista.", + "Repair UniGetUI": "Korjaa UniGetUI", + "Live output": "Live-tulostus", + "This package bundle had some settings that are potentially dangerous, and may be ignored by default.": "Tässä pakettikokoelmassa oli joitakin mahdollisesti vaarallisia asetuksia, jotka saatetaan oletusarvoisesti jättää huomiotta.", + "Entries that show in YELLOW will be IGNORED.": "KELTAISELLA näkyviä merkintöjä EI KÄSITELLÄ.", + "Entries that show in RED will be IMPORTED.": "PUNAISELLA merkityt TUODAAN.", + "You can change this behavior on UniGetUI security settings.": "Voit muuttaa tätä UniGetUI-tietoturva-asetuksissa.", + "Open UniGetUI security settings": "Avaa UniGetUI turvallisuus asetukset", + "Should you modify the security settings, you will need to open the bundle again for the changes to take effect.": "Jos muutat suojausasetuksia, sinun on avattava paketti uudelleen, jotta muutokset tulevat voimaan.", + "Details of the report:": "Raportin tiedot:", + "Are you sure you want to create a new package bundle? ": "Haluatko varmasti luoda uuden pakettinipun?", + "Any unsaved changes will be lost": "Kaikki tallentamattomat muutokset menetetään", + "Warning!": "Varoitus!", + "For security reasons, custom command-line arguments are disabled by default. Go to UniGetUI security settings to change this. ": "Turvallisuussyistä mukautetut komentoriviargumentit on oletusarvoisesti poistettu käytöstä. Voit muuttaa tätä UniGetUI:n suojausasetuksissa.", + "Change default options": "Muuta oletusasetuksia", + "Ignore future updates for this package": "Jätä tulevaisuuden päivitykset tälle paketille huomioimatta", + "For security reasons, pre-operation and post-operation scripts are disabled by default. Go to UniGetUI security settings to change this. ": "Turvallisuussyistä operaatiota edeltävät ja sen jälkeiset komentosarjat on oletusarvoisesti poistettu käytöstä. Voit muuttaa tätä UniGetUI:n suojausasetuksissa.", + "You can define the commands that will be run before or after this package is installed, updated or uninstalled. They will be run on a command prompt, so CMD scripts will work here.": "Voit määrittää komennot, jotka suoritetaan ennen tämän paketin asentamista, päivittämistä tai poistamista tai sen jälkeen. Ne suoritetaan komentokehotteessa, joten CMD-komentosarjat toimivat tässä.", + "Change this and unlock": "Vaihda tämä ja avaa lukitus", + "{0} Install options are currently locked because {0} follows the default install options.": "{0} Asennusvaihtoehdot ovat tällä hetkellä lukittuja, koska {0} noudattaa oletusasennusvaihtoehtoja.", + "Unset or unknown": "Ei asetettu tai tuntematon", + "This package has no screenshots or is missing the icon? Contrbute to UniGetUI by adding the missing icons and screenshots to our open, public database.": "Tässä paketissa ei ole kuvakaappauksia tai siitä puuttuu kuvake? Auta UniGetUI:ta lisäämällä puuttuvat kuvakkeet ja kuvakaappaukset avoimeen julkiseen tietokantaamme.", + "Become a contributor": "Liity jakelijaksi", + "Update to {0} available": "{0} päivitys saatavilla", + "Reinstall": "Uudelleen asenna", + "Installer not available": "Asennusohjelmaa ei saatavilla", + "Version:": "Versio:", + "UniGetUI Version {0}": "UniGetUI Versio {0}", + "Performing backup, please wait...": "Suoritetaan varmuuskopiointia, odota hetki...", + "An error occurred while logging in: ": "Kirjautumisessa tapahtui virhe:", + "Fetching available backups...": "Haetaan saatavilla olevia varmuuskopioita...", + "Done!": "Valmis!", + "The cloud backup has been loaded successfully.": "Pilvivarmuuskopio on ladattu onnistuneesti.", + "An error occurred while loading a backup: ": "Varmuuskopiota ladattaessa tapahtui virhe:", + "Backing up packages to GitHub Gist...": "Pakettien varmuuskopiointi GitHub Gistille...", + "Backup Successful": "Varmuuskopiointi onnistui", + "The cloud backup completed successfully.": "Pilvivarmuuskopiointi onnistui.", + "Could not back up packages to GitHub Gist: ": "Pakettien varmuuskopiointi GitHub Gist -palveluun epäonnistui:", + "It is not guaranteed that the provided credentials will be stored safely, so you may as well not use the credentials of your bank account": "Ei ole taattua, että toimitetut tunnistetiedot säilytetään turvallisesti, joten et voi yhtä hyvin olla käyttämättä pankkitilisi tunnuksia", + "Enable the automatic WinGet troubleshooter": "Ota käyttöön automaattinen WinGet-vianmääritys", + "Add updates that fail with a 'no applicable update found' to the ignored updates list": "Lisää ohitettujen päivitysten luetteloon päivitykset, jotka epäonnistuvat, kun ilmoitus ei löydy", + "Invalid selection": "Virheellinen valinta", + "No package was selected": "Yhtään pakettia ei ole valittu", + "More than 1 package was selected": "Useampi kuin yksi paketti on valittu", + "List": "Lista", + "Grid": "Ruudukko", + "Icons": "Ikonit", + "\"{0}\" is a local package and does not have available details": "\"{0}\" on paikallinen paketti, eikä siinä ole saatavilla tietoja", + "\"{0}\" is a local package and is not compatible with this feature": "\"{0}\" on paikallinen paketti, eikä se ole yhteensopiva tämän ominaisuuden kanssa", + "Add packages to bundle": "Lisää paketti nippuun", + "Preparing packages, please wait...": "Valmistellaan paketteja, odota hetki...", + "Loading packages, please wait...": "Ladataan paketteja, odota hetki...", + "Saving packages, please wait...": "Tallennetaan paketteja, odota hetki...", + "The bundle was created successfully on {0}": "Kokoelma luotiin onnistuneesti {0}", + "User profile": "Käyttäjäprofiili", + "Error": "Virhe", + "Log in failed: ": "Kirjautuminen epäonnistui:", + "Log out failed: ": "Uloskirjautuminen epäonnistui:", + "Package backup settings": "Pakettien varmuuskopiointiasetukset", + "Manage UniGetUI autostart behaviour from the Settings app": "Hallitse UniGetUI:n automaattisen käynnistyksen toimintaa", + "Choose how many operations shoulds be performed in parallel": "Valitse, kuinka monta toimintoa suoritetaan rinnakkain", + "Something went wrong while launching the updater.": "Jotain meni pieleen päivitystä käynnistettäessä.", + "Please try again later": "Kokeile myöhemmin uudelleen", + "Show the release notes after UniGetUI is updated": "Näytä julkaisutiedot, kun UniGetUI on päivitetty" +} diff --git a/src/Languages/lang_fil.json b/src/Languages/lang_fil.json new file mode 100644 index 0000000..4f3ba0c --- /dev/null +++ b/src/Languages/lang_fil.json @@ -0,0 +1,850 @@ +{ + "{0} of {1} operations completed": "{0} sa {1} na operasyon ang nakumpleto", + "{0} is now {1}": "Ang {0} ay {1} na ngayon", + "Enabled": "Pinagana", + "Disabled": "Naka-disable", + "Privacy": "Privacy", + "Hide my username from the logs": "Itago ang aking username sa mga log", + "Replaces your username with **** in the logs. Restart UniGetUI to also hide it from already-recorded entries.": "Pinapalitan ang iyong username ng **** sa mga log. I-restart ang UniGetUI upang itago rin ito sa mga naka-record na entry.", + "Your last update attempt did not complete.": "Hindi nakumpleto ang huli mong pagtatangkang mag-update.", + "UniGetUI could not confirm whether the update succeeded. Open the log to see what happened.": "Hindi makumpirma ng UniGetUI kung matagumpay ang update. Buksan ang log para makita kung ano ang nangyari.", + "View log": "Tingnan ang log", + "The installer reported success but did not restart UniGetUI.": "Nag-ulat ng tagumpay ang installer ngunit hindi na-restart ang UniGetUI.", + "The installer failed to initialize.": "Nabigong mag-initialize ang installer.", + "Setup was canceled before installation began.": "Kinansela ang setup bago nagsimula ang pag-install.", + "A fatal error occurred during the preparation phase.": "Nagkaroon ng malubhang error sa yugto ng paghahanda.", + "A fatal error occurred during installation.": "Nagkaroon ng malubhang error habang nag-i-install.", + "Installation was canceled while in progress.": "Kinansela ang pag-install habang isinasagawa.", + "The installer was terminated by another process.": "Tinapos ng ibang proseso ang installer.", + "The preparation phase determined the installation cannot proceed.": "Natukoy sa yugto ng paghahanda na hindi maaaring magpatuloy ang pag-install.", + "The installer could not start. UniGetUI may already be running, or you do not have permission to install.": "Hindi masimulan ang installer. Maaaring tumatakbo na ang UniGetUI, o wala kang pahintulot na mag-install.", + "Unexpected installer error.": "Hindi inaasahang error sa installer.", + "We are checking for updates.": "Sinusuri namin ang mga update.", + "Please wait": "Mangyaring maghintay", + "Great! You are on the latest version.": "Mahusay! Ikaw ay nasa pinakabagong bersyon.", + "There are no new UniGetUI versions to be installed": "Walang mga bagong bersyon ng UniGetUI na mai-install", + "UniGetUI version {0} is being downloaded.": "Dina-download ang bersyon ng UniGetUI {0}.", + "This may take a minute or two": "Maaaring tumagal ito ng isang minuto o dalawa", + "The installer authenticity could not be verified.": "Hindi ma-verify ang pagiging tunay ng installer.", + "The update process has been aborted.": "Na-abort ang proseso ng pag-update.", + "Auto-update is not yet available on this platform.": "Hindi pa available ang auto-update sa platform na ito.", + "Please update UniGetUI manually.": "Paki-update nang manu-mano ang UniGetUI.", + "An error occurred when checking for updates: ": "Nagkaroon ng error habang tumitingin ng mga update:", + "The updater could not be launched.": "Hindi mailunsad ang updater.", + "The operating system did not start the installer process.": "Hindi sinimulan ng operating system ang proseso ng installer.", + "UniGetUI is being updated...": "Ina-update ang UniGetUI...", + "Update installed.": "Na-install ang update.", + "UniGetUI was updated successfully, but this running copy was not replaced. This usually means you are running a development build. Close this copy and start the newly-installed version to finish.": "Matagumpay na na-update ang UniGetUI, ngunit hindi napalitan ang kasalukuyang tumatakbong kopyang ito. Karaniwan itong nangangahulugang nagpapatakbo ka ng development build. Isara ang kopyang ito at simulan ang bagong na-install na bersyon upang matapos.", + "The update could not be applied.": "Hindi mailapat ang update.", + "Installer exit code {0}: {1}": "Exit code ng installer {0}: {1}", + "Update cancelled.": "Kinansela ang update.", + "Authentication was cancelled.": "Kinansela ang pagpapatunay.", + "Installer exit code {0}": "Exit code ng installer {0}", + "Operation in progress": "Kasalukuyang isinasagawa ang operasyon", + "Please wait...": "Mangyaring maghintay...", + "Success!": "Matagumpay!", + "Failed": "Nabigo", + "An error occurred while processing this package": "Nagkaroon ng error habang pinoproseso ang package na ito", + "Installer": "Pang-install", + "Executable": "Maipapatakbong file", + "MSI": "MSI", + "Compressed file": "Naka-compress na file", + "MSIX": "MSIX", + "WinGet was repaired successfully": "Matagumpay na naayos ang WinGet", + "It is recommended to restart UniGetUI after WinGet has been repaired": "Inirerekomenda na i-restart ang UniGetUI pagkatapos ayusin ang WinGet", + "WinGet could not be repaired": "Hindi ma-repair ang WinGet", + "An unexpected issue occurred while attempting to repair WinGet. Please try again later": "Isang hindi inaasahang isyu ang naganap habang sinusubukang ayusin ang WinGet. Pakisubukang muli mamaya", + "Log in to enable cloud backup": "Mag-log in para mapagana ang cloud backup", + "Backup Failed": "Nabigo ang Pag-Backup", + "Downloading backup...": "Dina-download ang backup...", + "An update was found!": "May nahanap na update!", + "{0} can be updated to version {1}": "Maaaring ma-update ang {0} sa bersyon {1}", + "Updates found!": "Nahanap ang mga update!", + "{0} packages can be updated": "Maaaring ma-update ang {0} (na) mga package", + "{0} is being updated to version {1}": "Ang {0} ay ina-update sa bersyon {1}", + "{0} packages are being updated": "{0} (na) package ay ina-update", + "You have currently version {0} installed": "Kasalukuyan kang naka-install na bersyon {0}.", + "Desktop shortcut created": "Nagawa ang desktop shortcut", + "UniGetUI has detected a new desktop shortcut that can be deleted automatically.": "Nakakita ang UniGetUI ng bagong desktop shortcut na maaaring awtomatikong tanggalin.", + "{0} desktop shortcuts created": "{0} (na) desktop shortcut ang nagawa", + "UniGetUI has detected {0} new desktop shortcuts that can be deleted automatically.": "Nakakita ang UniGetUI ng {0} bagong desktop shortcut na maaaring awtomatikong tanggalin.", + "Attention required": "Kailangan ng atensyon", + "Restart required": "Kinakailangang i-restart", + "1 update is available": "1 update ang available", + "{0} updates are available": "{0} (na) mga update ay available", + "Everything is up to date": "Ang lahat ay napapanahon", + "Discover Packages": "Tumuklas ng mga package", + "Available Updates": "Available na Mga Update", + "Installed Packages": "Mga Naka-install na Package", + "UniGetUI Version {0} by Devolutions": "Bersyon ng UniGetUI {0} ng Devolutions", + "Show UniGetUI": "Ipakita ng UniGetUI", + "Quit": "Lumabas", + "Are you sure?": "Sigurado ka ba?", + "Do you really want to uninstall {0}?": "Gusto mo ba talagang i-uninstall ang {0}?", + "Do you really want to uninstall the following {0} packages?": "Gusto mo ba talagang i-uninstall ang mga sumusunod na {0} na package?", + "No": "Hindi", + "Yes": "Oo", + "Partial": "Bahagya", + "View on UniGetUI": "Tignan sa UniGetUI", + "Update": "I-update", + "Open UniGetUI": "Buksan ang UniGetUI", + "Update all": "I-update lahat", + "Update now": "I-update ngayon", + "Installer host changed since the installed version.\n": "Nagbago ang host ng installer mula noong naka-install na bersyon.\n", + "This package is on the queue": "Ang package na ito ay nasa queue", + "installing": "nag-iinstall", + "updating": "nag-a-update", + "uninstalling": "nag-uninstall", + "installed": "na-install na", + "Retry": "Subukan muli", + "Install": "I-install", + "Uninstall": "I-uninstall", + "Open": "Buksan", + "Operation profile:": "Profile ng operasyon:", + "Follow the default options when installing, upgrading or uninstalling this package": "Sundan ang mga default na opsyon sa pag-install, pag-upgrade o pag-uninstall ng package na ito", + "The following settings will be applied each time this package is installed, updated or removed.": "Ilalapat ang mga sumusunod na setting sa tuwing mai-install, maa-update o maalis ang package na ito.", + "Version to install:": "Bersyon na i-install:", + "Architecture to install:": "Arkitekturang i-install:", + "Installation scope:": "Saklaw ng pag-install:", + "Install location:": "Lokasyon ng pag-install:", + "Select": "Pumili", + "Reset": "I-reset", + "Custom install arguments:": "Custom na argumento sa pag-install:", + "Custom update arguments:": "Custom na argumento sa pag-update:", + "Custom uninstall arguments:": "Custom na argumento sa pag-uninstall:", + "Pre-install command:": "Command bago mag-install:", + "Post-install command:": "Command pagkatapos ng pag-install:", + "Abort install if pre-install command fails": "Ihinto ang pag-install kapag ang command ng pre-install ay nabigo", + "Pre-update command:": "Command bago ang pag-update:", + "Post-update command:": "Command pagkatapos ng pag-update:", + "Abort update if pre-update command fails": "Ihinto ang pag-update kapag ang command ng pre-update ay nabigo", + "Pre-uninstall command:": "Command bago mag-uninstall:", + "Post-uninstall command:": "Command pagkatapos ng pag-uninstall:", + "Abort uninstall if pre-uninstall command fails": "Ihinto ang pag-uninstall kapag ang command ng pre-uninstall ay nabigo", + "Command-line to run:": "Command-line na patakbuhin:", + "Save and close": "I-save at isara", + "General": "Pangkalahatan", + "Architecture & Location": "Arkitektura at Lokasyon", + "Command-line": "Linya ng command", + "Close apps": "Isara ang mga app", + "Pre/Post install": "Bago/Pagkatapos ng pag-install", + "Select the processes that should be closed before this package is installed, updated or uninstalled.": "Piliin ang mga prosesong dapat isara bago i-install, i-update o i-uninstall ang package na ito.", + "Write here the process names here, separated by commas (,)": "Isulat dito ang mga pangalan ng mga proseso dito, pinaghihiwalay ng kuwit (,)", + "Try to kill the processes that refuse to close when requested to": "Subukang patayin ang mga prosesong tumatangging magsara kapag hiniling", + "Run as admin": "Magpatakbo bilang admin", + "Interactive installation": "Interactive na pag-install", + "Skip hash check": "Laktawan ang pagsusuri ng hash", + "Uninstall previous versions when updated": "I-uninstall ang mga nakaraang bersyon kapag na-update", + "Skip minor updates for this package": "Laktawan ang mga minor na update para sa package na ito", + "Automatically update this package": "Awtomatikong i-update ang package na ito", + "{0} installation options": "Mga opsyon sa pag-install ng {0}", + "Latest": "Pinakabago", + "PreRelease": "PreRelease", + "Default": "Default", + "Manage ignored updates": "Pamahalaan ang mga hindi pinapansin na update", + "The packages listed here won't be taken in account when checking for updates. Double-click them or click the button on their right to stop ignoring their updates.": "Ang mga package na nakalista dito ay hindi isasaalang-alang kapag tumitingin ng mga update. I-double-click ang mga ito o i-click ang button sa kanilang kanan upang ihinto ang pagbalewala sa kanilang mga update.", + "Reset list": "I-reset ang listahan", + "Do you really want to reset the ignored updates list? This action cannot be reverted": "Gusto mo ba talagang i-reset ang listahan ng mga binalewalang update? Hindi na maibabalik ang pagkilos na ito.", + "No ignored updates": "Walang binalewalang update", + "Package Name": "Pangalan ng Package", + "Package ID": "ID ng Package", + "Ignored version": "Binalewala ang bersyon", + "New version": "Bagong Bersyon", + "Source": "Source", + "All versions": "Lahat ng bersyon", + "Unknown": "Hindi kilala", + "Up to date": "Napapanahon", + "Package {name} from {manager}": "Package {name} mula sa {manager}", + "Remove {0} from ignored updates": "Alisin ang {0} sa mga binalewalang update", + "Cancel": "Kanselahin", + "Administrator privileges": "Mga pribilehiyo ng administrator", + "This operation is running with administrator privileges.": "Ang operasyong ito ay tumatakbo nang may mga pribilehiyo ng administrator.", + "Interactive operation": "Interactive na operasyon", + "This operation is running interactively.": "Interactive na tumatakbo ang operasyong ito.", + "You will likely need to interact with the installer.": "Malamang na kakailanganin mong makipag-iteract sa installer.", + "Integrity checks skipped": "Nilaktawan ang mga pagsusuri sa integridad", + "Integrity checks will not be performed during this operation.": "Hindi isasagawa ang mga pagsusuri sa integridad sa operasyong ito.", + "Proceed at your own risk.": "Magpatuloy sa sarili mong pananagutan.", + "Close": "Isara", + "Loading...": "Naglo-load...", + "Installer SHA256": "SHA256 ng installer", + "Homepage": "website", + "Author": "May-akda", + "Publisher": "Tagapaglathala:", + "License": "Lisensya", + "Manifest": "Manifest", + "Installer Type": "Uri ng Installer", + "Size": "Laki", + "Installer URL": "Uri ng Installer", + "Last updated:": "Huling na-update:", + "Release notes URL": "URL ng mga release note", + "Package details": "Mga detalye ng package", + "Dependencies:": "Mga kinakailangan:", + "Release notes": "Mga release note", + "Screenshots": "Mga screenshot", + "This package has no screenshots or is missing the icon? Contribute to UniGetUI by adding the missing icons and screenshots to our open, public database.": "Walang mga screenshot ang package na ito o nawawala ang icon? Mag-ambag sa UniGetUI sa pamamagitan ng pagdaragdag ng mga nawawalang icon at screenshot sa aming bukas at pampublikong database.", + "Version": "Bersyon", + "Install as administrator": "I-install bilang administator", + "Update to version {0}": "Update sa bersyon {0}", + "Installed Version": "Naka-install na Bersyon", + "Update as administrator": "I-update bilang administrator", + "Interactive update": "Interactive na pag-update", + "Uninstall as administrator": "I-uninstall bilang administrator", + "Interactive uninstall": "Interactive na pag-uninstall", + "Uninstall and remove data": "I-uninstall at alisin ang data", + "Not available": "Hindi available", + "Installer SHA512": "SHA512 ng installer", + "Unknown size": "Hindi kilalang laki", + "No dependencies specified": "Walang tinukoy na kinakailangan", + "mandatory": "kinakailangan", + "optional": "opsyonal", + "UniGetUI {0} is ready to be installed.": "Handa nang i-install ang UniGetUI {0}.", + "The update process will start after closing UniGetUI": "Magsisimula ang proseso ng pag-update pagkatapos isara ang UniGetUI", + "UniGetUI has been ran as administrator, which is not recommended. When running UniGetUI as administrator, EVERY operation launched from UniGetUI will have administrator privileges. You can still use the program, but we highly recommend not running UniGetUI with administrator privileges.": "Ang UniGetUI ay pinatakbo bilang administrator, na hindi inirerekomenda. Kapag pinatakbo mo ang UniGetUI bilang administrator, BAWAT operasyong ilulunsad mula sa UniGetUI ay magkakaroon ng mga pribilehiyo ng administrator. Magagamit mo pa rin ang programa, ngunit mahigpit naming inirerekomenda na huwag patakbuhin ang UniGetUI nang may mga pribilehiyo ng administrator.", + "Share anonymous usage data": "Ibahagi ang hindi kilalang data ng paggamit", + "UniGetUI collects anonymous usage data in order to improve the user experience.": "Kinokolekta ng UniGetUI ang hindi kilalang data ng paggamit upang mapabuti ang karanasan ng user.", + "Accept": "Tanggapin", + "Software Updates": "Mga Software Update", + "Package Bundles": "Mga Bundle ng Package", + "Settings": "Mga Setting", + "Package Managers": "Mga Package Manager", + "UniGetUI Log": "Log ng UniGetUI", + "Package Manager logs": "Mga log ng Package Manager", + "Operation history": "Kasaysayan ng operasyon", + "Help": "Tulong", + "UniGetUI": "UniGetUI", + "You have installed UniGetUI Version {0}": "Naka-install ang Bersyon ng UniGetUI {0}", + "Disclaimer": "Paalala", + "UniGetUI is developed by Devolutions and is not affiliated with any of the compatible package managers.": "Ang UniGetUI ay binuo ng Devolutions at hindi kaakibat ng alinman sa mga compatible na package manager.", + "UniGetUI wouldn't have been possible without the help of the contributors. Thank you all 🥳": "Hindi magiging posible ang UniGetUI kung wala ang tulong ng mga kontribyutor. Salamat sa inyong lahat 🥳", + "UniGetUI uses the following libraries. Without them, UniGetUI wouldn't have been possible.": "Ginagamit ng UniGetUI ang mga sumusunod na library. Kung wala sila, hindi magiging posible ang UniGetUI.", + "{0} homepage": "Homepage ng {0}", + "UniGetUI has been translated to more than 40 languages thanks to the volunteer translators. Thank you 🤝": "Ang UniGetUI ay isinalin sa higit sa 40 mga wika salamat sa mga boluntaryong tagasalin. Salamat 🤝", + "Verbose": "Verbose", + "1 - Errors": "1 - Mga Error", + "2 - Warnings": "2 - Mga Babala", + "3 - Information (less)": "3 - Impormasyon (mas kaunti)", + "4 - Information (more)": "4 - Impormasyon (higit pa)", + "5 - information (debug)": "5 - Impormasyon (debug)", + "Warning": "Babala", + "The following settings may pose a security risk, hence they are disabled by default.": "Ang mga sumusunod na setting ay maaaring magdulot ng panganib sa seguridad, kaya hindi pinagana ang mga ito bilang default.", + "Enable the settings below if and only if you fully understand what they do, and the implications they may have.": "Paganahin ang mga setting sa ibaba KUNG AT LAMANG KUNG lubusan mong nauunawaan ang kanilang ginagawa, at ang mga implikasyon at panganib na maaaring kasangkot sa kanila.", + "The settings will list, in their descriptions, the potential security issues they may have.": "Ililista ng mga setting, sa kanilang mga paglalarawan, ang mga potensyal na isyu sa seguridad na maaaring mayroon sila.", + "The backup will include the complete list of the installed packages and their installation options. Ignored updates and skipped versions will also be saved.": "Kasama sa backup ang kumpletong listahan ng mga naka-install na package at ang kanilang mga opsyon sa pag-install. Mase-save din ang mga binalewalang update at nilaktawan na bersyon.", + "The backup will NOT include any binary file nor any program's saved data.": "HINDI isasama sa backup ang anumang binary file o anumang naka-save na data ng program.", + "The size of the backup is estimated to be less than 1MB.": "Ang laki ng backup ay tinatantya na mas mababa sa 1MB.", + "The backup will be performed after login.": "Ang backup ay isasagawa pagkatapos mag-login.", + "{pcName} installed packages": "Mga naka-install na package ng {pcName}", + "Current status: Not logged in": "Kasalukuyang katayuan: Hindi naka-log in", + "You are logged in as {0} (@{1})": "Naka-log in ka bilang {0} (@{1})", + "Nice! Backups will be uploaded to a private gist on your account": "Ayos! Ang mga backup ay ia-upload sa pribadong gist sa iyong account", + "Select backup": "Pumili ng backup", + "Settings imported from {0}": "Na-import ang mga setting mula sa {0}", + "UniGetUI Settings": "Mga Setting ng UniGetUI", + "Settings exported to {0}": "Na-export ang mga setting sa {0}", + "UniGetUI settings were reset": "Na-reset ang mga setting ng UniGetUI", + "Allow pre-release versions": "Payagan ang mga pre-release na bersyon", + "Apply": "Ilapat", + "For security reasons, custom command-line arguments are disabled by default. Go to UniGetUI security settings to change this.": "Dahil sa mga kadahilanang pangseguridad, ang mga custom na argumento sa command-line ay naka-disable bilang default. Pumunta sa mga setting ng seguridad ng UniGetUI upang baguhin ito.", + "Go to UniGetUI security settings": "Pumunta sa setting ng seguridad ng UniGetUI", + "The following options will be applied by default each time a {0} package is installed, upgraded or uninstalled.": "Ang mga sumusunod na opsyon ay ilalapat bilang default sa tuwing ang isang {0} na package ay na-install, na-upgrade o na-uninstall.", + "Package's default": "Default ng package", + "Install location can't be changed for {0} packages": "Hindi mababago ang lokasyon ng pag-install para sa {0} na package", + "The local icon cache currently takes {0} MB": "Ang cache ng lokal na icon ay kasalukuyang nasa {0} MB", + "Username": "Username", + "Password": "Password", + "Credentials": "Mga kredensyal", + "It is not guaranteed that the provided credentials will be stored safely": "Hindi ginagarantiya na ligtas na maiimbak ang mga ibinigay na kredensyal", + "Partially": "Bahagyang", + "Package manager": "Tagapamahala ng package", + "Compatible with proxy": "Compatible sa proxy", + "Compatible with authentication": "Compatible na may authentication", + "Proxy compatibility table": "Compatability table ng proxy", + "{0} settings": "mga setting ng {0}", + "{0} status": "Katayuan ng {0}", + "Default installation options for {0} packages": "Default na opyson sa pag-install para sa {0} na package", + "Expand version": "Palawakin ang bersyon", + "The executable file for {0} was not found": "Ang executable na file para sa {0} ay hindi nahanap", + "{pm} is disabled": "{pm} ay naka-disable", + "Enable it to install packages from {pm}.": "Paganahin itong mag-install ng mga package mula sa {pm}.", + "{pm} is enabled and ready to go": "{pm} ay naka-enable at handa na", + "{pm} version:": "Bersyon ng {pm}:", + "{pm} was not found!": "Hindi mahanap ang {pm}!", + "You may need to install {pm} in order to use it with UniGetUI.": "Maaaring kailanganin mong i-install ang {pm} upang magamit ito sa UniGetUI.", + "Scoop Installer - UniGetUI": "Installer ng Scoop - UniGetUI", + "Scoop Uninstaller - UniGetUI": "Uninstaller ng Scoop - UniGetUI", + "Clearing Scoop cache - UniGetUI": "Linilinis ang Scoop cache - UniGetUI", + "Restart UniGetUI to fully apply changes": "I-restart ang UniGetUI upang ganap na mailapat ang mga pagbabago", + "Restart UniGetUI": "I-restart ang UniGetUI", + "Manage {0} sources": "Pamahalaan ang {0} mga source", + "Add source": "Magdagdag ng source", + "Add": "Idagdag", + "Source name": "Pangalan ng source", + "Source URL": "URL ng source", + "Other": "Iba pa", + "No minimum age": "Walang minimum na tagal", + "1 day": "kada araw", + "{0} days": "{0} na araw", + "Custom...": "Pasadya...", + "{0} minutes": "{0} (na) minuto", + "1 hour": "kada oras", + "{0} hours": "{0} (na) oras", + "1 week": "1 linggo", + "Supports release dates": "Sinusuportahan ang mga petsa ng release", + "Release date support per package manager": "Suporta sa petsa ng release ayon sa package manager", + "Search for packages": "Maghanap ng mga package", + "Local": "Lokal", + "OK": "OK", + "Last checked: {0}": "Huling sinuri: {0}", + "{0} packages were found, {1} of which match the specified filters.": "{0} (na) package ang nahanap, {1} kung saan tumutugma sa tinukoy na mga filter.", + "{0} selected": "{0} na napili", + "(Last checked: {0})": "(Huling sinuri: {0})", + "All packages selected": "Napili ang lahat ng package", + "Package selection cleared": "Na-clear ang pagpili ng package", + "{0}: {1}": "{0}: {1}", + "More info": "Higit pang impormasyon", + "GitHub account": "Account sa GitHub", + "Log in with GitHub to enable cloud package backup.": "Mag-log in gamit ang GitHub para mapagana ang pag-backup ng cloud package", + "More details": "Higit pang mga detalye", + "Log in": "Mag-log in", + "If you have cloud backup enabled, it will be saved as a GitHub Gist on this account": "Kung napagana ang cloud backup, ito ay ise-save bilang isang GitHub Gist sa account na ito", + "Log out": "Mag-log out", + "About UniGetUI": "Tungkol sa UniGetUI", + "About": "Patungkol", + "Third-party licenses": "Mga lisensya ng third-party", + "Contributors": "Mga kontribyutor", + "Translators": "Mga tagasalin", + "Bundle security report": "Ulat sa seguridad ng bundle", + "The bundle contained restricted content": "Naglaman ang bundle ng pinaghihigpitang nilalaman", + "UniGetUI – Crash Report": "Ulat ng pag-crash ng UniGetUI", + "UniGetUI has crashed": "Nag-crash ang UniGetUI", + "Help us fix this by sending a crash report to Devolutions. All fields below are optional.": "Tulungan kaming ayusin ito sa pamamagitan ng pagpapadala ng crash report sa Devolutions. Opsyonal ang lahat ng field sa ibaba.", + "Email (optional)": "Email (opsyonal)", + "your@email.com": "your@email.com", + "Additional details (optional)": "Karagdagang mga detalye (opsyonal)", + "Describe what you were doing when the crash occurred…": "Ilarawan kung ano ang ginagawa mo nang mangyari ang pag-crash…", + "Crash report": "Ulat ng pag-crash", + "Don't Send": "Huwag Ipadala", + "Send Report": "Ipadala ang Report", + "Sending…": "Ipinapadala…", + "Unsaved changes": "Mga hindi na-save na pagbabago", + "You have unsaved changes in the current bundle. Do you want to discard them?": "May mga hindi na-save na pagbabago sa kasalukuyang bundle. Gusto mo bang huwag i-save ang mga ito?", + "Discard changes": "Huwag i-save ang mga pagbabago", + "Integrity violation": "Paglabag sa integridad", + "UniGetUI or some of its components are missing or corrupt. It is strongly recommended to reinstall UniGetUI to adress the situation.": "Nawawala o sira ang UniGetUI o ilan sa mga bahagi nito. Mahigpit na inirerekomendang muling i-install ang UniGetUI upang matugunan ang sitwasyon.", + "• Refer to the UniGetUI Logs to get more details regarding the affected file(s)": "• Sumangguni sa mga log ng UniGetUI para makakuha ng higit pang mga detalye tungkol sa (mga) apektadong file", + "• Integrity checks can be disabled from the Experimental Settings": "• Maaaring i-disable ang mga pagsusuri sa integridad mula sa Mga Pang-eksperimento Setting", + "Manage shortcuts": "Pamahalaan ang mga shortcut", + "UniGetUI has detected the following desktop shortcuts which can be removed automatically on future upgrades": "Natukoy ng UniGetUI ang mga sumusunod na desktop shortcut na maaaring awtomatikong alisin sa mga pag-upgrade sa hinaharap", + "Do you really want to reset this list? This action cannot be reverted.": "Gusto mo ba talagang i-reset ang listahang ito? Hindi na maibabalik ang pagkilos na ito.", + "Desktop shortcuts list": "Listahan ng mga desktop shortcut", + "Open in explorer": "Buksan sa explorer", + "Remove from list": "Alisin sa listahan", + "When new shortcuts are detected, delete them automatically instead of showing this dialog.": "Kapag may nakitang mga bagong shortcut, awtomatikong tanggalin ang mga ito sa halip na ipakita ang dialog na ito.", + "Not right now": "Hindi sa ngayon", + "Missing dependency": "Nawawalang kinakailangan", + "UniGetUI requires {0} to operate, but it was not found on your system.": "Kinakailangan ng UniGetUI ang {0} upang gumana, ngunit hindi ito nahanap sa iyong system.", + "Click on Install to begin the installation process. If you skip the installation, UniGetUI may not work as expected.": "Mag-click sa I-install upang simulan ang proseso ng pag-install. Kung lalaktawan mo ang pag-install, maaaring hindi gumana ang UniGetUI gaya ng inaasahan.", + "Alternatively, you can also install {0} by running the following command in a Windows PowerShell prompt:": "Bilang kahalili, maaari mo ring i-install ang {0} sa pamamagitan ng pagpapatakbo ng sumusunod na command sa isang prompt ng Windows PowerShell:", + "Install {0}": "I-install ang {0}", + "Do not show this dialog again for {0}": "Huwag ipakita muli ang dialog na ito para sa {0}", + "Please wait while {0} is being installed. A black window may show up. Please wait until it closes.": "Mangyaring maghintay habang ini-install ang {0}. Maaaring lumabas ang isang itim (o asul) na window. Pakihintay hanggang sa magsara ito.", + "{0} has been installed successfully.": "Matagumpay na na-install ang {0}.", + "Please click on \"Continue\" to continue": "Mangyaring mag-click sa \"Magpatuloy\" upang magpatuloy", + "Continue": "Magpatuloy", + "{0} has been installed successfully. It is recommended to restart UniGetUI to finish the installation": "Matagumpay na na-install ang {0}. Inirerekomenda na i-restart ang UniGetUI upang matapos ang pag-install", + "Restart later": "I-restart mamaya", + "An error occurred:": "May naganap na error", + "Please see the Command-line Output or refer to the Operation History for further information about the issue.": "Pakitingnan ang Output ng Command-line o sumangguni sa Kasaysayan ng Operasyon para sa karagdagang impormasyon tungkol sa isyu.", + "Retry as administrator": "Subukang muli bilang administrator", + "Retry interactively": "Subukang muli nang interactive", + "Retry skipping integrity checks": "Subukang laktawan ang mga pagsusuri sa integridad", + "Installation options": "Mga opsyon sa pag-install", + "Save": "I-save", + "UniGetUI collects anonymous usage data with the sole purpose of understanding and improving the user experience.": "Kinokolekta ng UniGetUI ang hindi kilalang data ng paggamit na may tanging layunin ng pag-unawa at pagpapabuti ng karanasan ng user.", + "More details about the shared data and how it will be processed": "Higit pang mga detalye tungkol sa nakabahaging data at kung paano ito ipoproseso", + "Do you accept that UniGetUI collects and sends anonymous usage statistics, with the sole purpose of understanding and improving the user experience?": "Tinatanggap mo ba na ang UniGetUI ay nangongolekta at nagpapadala ng mga hindi kilalang istatistika ng paggamit, na may tanging layunin na maunawaan at mapabuti ang karanasan ng user?", + "Decline": "Tanggihan", + "No personal information is collected nor sent, and the collected data is anonimized, so it can't be back-tracked to you.": "Walang personal na impormasyon ang kinokolekta o ipinadala, at ang nakolektang data ay hindi nagpapakilala, kaya hindi ito maibabalik sa iyo.", + "Navigation panel": "Panel ng nabigasyon", + "Operations": "Mga Operasyon", + "Toggle operations panel": "I-toggle ang panel ng mga operasyon", + "Bulk operations": "Maramihang operasyon", + "Retry failed": "Subukang muli ang mga nabigo", + "Clear successful": "I-clear ang matagumpay", + "Clear finished": "I-clear ang natapos", + "Cancel all": "Kanselahin lahat", + "More": "Higit pa", + "Toggle navigation panel": "Ipakita/itago ang navigation panel", + "Minimize": "I-minimize", + "Maximize": "I-maximize", + "UniGetUI by Devolutions": "UniGetUI ng Devolutions", + "UniGetUI is an application that makes managing your software easier, by providing an all-in-one graphical interface for your command-line package managers.": "Ang UniGetUI ay isang aplikasyon na nagpapadali sa pamamahala ng iyong software, sa pamamagitan ng pagbibigay ng isahang graphical na interface para sa iyong mga command-line package manager.", + "Useful links": "Mga kapaki-pakinabang na link", + "UniGetUI Homepage": "Homepage ng UniGetUI", + "Report an issue or submit a feature request": "Mag-ulat ng isyu o magsumite ng kahilingan sa feature", + "UniGetUI Repository": "Repository ng UniGetUI", + "View GitHub Profile": "Tingnan ang GitHub Profile", + "UniGetUI License": "Lisensya ng UniGetUI", + "Using UniGetUI implies the acceptation of the MIT License": "Ang paggamit ng UniGetUI ay nagpapahiwatig ng pagtanggap ng MIT License", + "Become a translator": "Maging isang tagasalin", + "Go back": "Bumalik", + "Go forward": "Sumulong", + "Go to home page": "Pumunta sa home page", + "Reload page": "I-reload ang pahina", + "View page on browser": "Tingnan ang page sa browser", + "The built-in browser is not supported on Linux yet.": "Hindi pa sinusuportahan ang built-in na browser sa Linux.", + "Open in browser": "Buksan sa browser", + "Copy to clipboard": "Kopyahin sa clipboard", + "Export to a file": "I-export sa isang file", + "Log level:": "Antas ng log:", + "Reload log": "I-reload ang log", + "Export log": "I-export ang log", + "Text": "Text", + "Change how operations request administrator rights": "Baguhin kung paano humihiling ang mga pagpapatakbo ng mga karapatan ng administrator", + "Restrictions on package operations": "Mga restriksyon sa mga operasyon ng package", + "Restrictions on package managers": "Mga restriksyon sa mga package manager", + "Restrictions when importing package bundles": "Mga restriksyon kung nag-iimport ng mga package bundle", + "Ask for administrator privileges once for each batch of operations": "Humingi ng mga pribilehiyo ng administrator nang isang beses para sa bawat batch ng mga operasyon", + "Ask only once for administrator privileges": "Isang beses lang humingi ng mga pribilehiyo ng administrator", + "Prohibit any kind of Elevation via UniGetUI Elevator or GSudo": "Ipagbawal ang anumang uri ng Elevation sa pamamagitan ng UniGetUI Elevator o GSudo", + "This option WILL cause issues. Any operation incapable of elevating itself WILL FAIL. Install/update/uninstall as administrator will NOT WORK.": "Ang opsyon na ito ay MAGDUDULOT ng mga isyu. Ang anumang operasyon na hindi kayang i-elevate ang sarili ay MABIGO. Ang pag-install/pag-update/pag-uninstall bilang administrator ay HINDI GAGANA.", + "Allow custom command-line arguments": "Payagan ang mga custom na argumento sa command-line", + "Custom command-line arguments can change the way in which programs are installed, upgraded or uninstalled, in a way UniGetUI cannot control. Using custom command-lines can break packages. Proceed with caution.": "Maaaring baguhin ng mga custom na argumento sa command-line ang paraan ng pag-install, pag-upgrade o pag-uninstall ng mga program, sa paraang hindi makontrol ng UniGetUI. Ang paggamit ng mga custom na command-line ay maaaring masira ang mga package. Magpatuloy nang may pag-iingat.", + "Ignore custom pre-install and post-install commands when importing packages from a bundle": "Payagan ang pagpapatakbo ng mga custom na pre-install at post-install na command", + "Pre and post install commands will be run before and after a package gets installed, upgraded or uninstalled. Be aware that they may break things unless used carefully": "Ang mga command bago at pagkatapos ay patatakbuhin bago at pagkatapos ma-install, ma-upgrade o ma-uninstall ang isang package. Magkaroon ng kamalayan na maaari silang masira ang mga bagay maliban kung ginamit nang maingat", + "Allow changing the paths for package manager executables": "Payagan ang pagpapalit ng mga path para sa mga executable ng package manager", + "Turning this on enables changing the executable file used to interact with package managers. While this allows finer-grained customization of your install processes, it may also be dangerous": "Ang pag-on nito ay nagbibigay-daan sa pagbabago ng executable file na ginagamit para makipag-ugnayan sa mga package manager. Bagama't pinapayagan nito ang mas pinong pag-customize ng iyong mga proseso sa pag-install, maaari rin itong mapanganib", + "Allow importing custom command-line arguments when importing packages from a bundle": "Payagan ang pag-import ng mga custom na arguemento ng command-line kapag nag-i-import ng mga package mula sa bundle", + "Malformed command-line arguments can break packages, or even allow a malicious actor to gain privileged execution. Therefore, importing custom command-line arguments is disabled by default": "Maaaring masira ng mga maling argumento sa command-line ang mga package, o payagan ang isang malisyosong aktor na makakuha ng privileged execution. Samakatuwid, ang pag-import ng mga custom na argumento sa command-line ay hindi pinagana bilang default", + "Allow importing custom pre-install and post-install commands when importing packages from a bundle": "Payagan ang pag-import ng custom na pre-install at post-install na command kapag nag-i-import ng mga package mula sa bundle", + "Pre and post install commands can do very nasty things to your device, if designed to do so. It can be very dangerous to import the commands from a bundle, unless you trust the source of that package bundle": "Ang mga command bago at pagkatapos ng pag-install ay maaaring gumawa ng mga napakasamang bagay sa iyong device, kung idinisenyo upang gawin ito. Maaaring lubhang mapanganib ang pag-import ng mga command mula sa isang bundle, maliban kung pinagkakatiwalaan mo ang pinagmulan ng bundle ng package na iyon", + "Administrator rights and other dangerous settings": "Mga karapatan ng administrator at iba pang mga mapanganib na setting", + "Package backup": "I-backup ang package", + "Cloud package backup": "Cloud backup ng package", + "Local package backup": "Pag-backup ng lokal na package", + "Local backup advanced options": "Mga advanced na opsyon sa Lokal na backup", + "Log in with GitHub": "Mag-log in gamit ang GitHub", + "Log out from GitHub": "Mag-log out sa Github", + "Periodically perform a cloud backup of the installed packages": "Pana-panahong magsagawa ng cloud backup ng mga naka-install na package", + "Cloud backup uses a private GitHub Gist to store a list of installed packages": "Ang Cloud backup ay gumagamit ng pribadong GitHub Gist para makatago ng listahan ng mga na-install na package", + "Perform a cloud backup now": "Magsagawa ng cloud backup ngayon", + "Backup": "I-backup", + "Restore a backup from the cloud": "I-restore ang backup mula sa cloud", + "Begin the process to select a cloud backup and review which packages to restore": "Simulan ang proseso na pumili ng cloud backup at i-review anong package ang i-restore", + "Periodically perform a local backup of the installed packages": "Pana-panahong magsagawa ng lokal na backup ng mga naka-install na package", + "Perform a local backup now": "Magsagawa ng lokal na backup ngayon", + "Change backup output directory": "Baguhin ang backup na directory ng output", + "Set a custom backup file name": "Magtakda ng custom na backup na pangalan ng file", + "Leave empty for default": "Iwanang walang laman para sa default", + "Add a timestamp to the backup file names": "Magdagdag ng timestamp sa mga pangalan ng mga backup file", + "Backup and Restore": "Pag-backup at Pag-restore", + "Enable background api (UniGetUI Widgets and Sharing, port 7058)": "Paganahin ang background API (Mga Widget para sa UniGetUI at Pagbabahagi, port 7058)", + "Wait for the device to be connected to the internet before attempting to do tasks that require internet connectivity.": "Hintaying makakonekta ang device sa internet bago subukang gawin ang mga gawain na nangangailangan ng koneksyon sa internet.", + "Disable the 1-minute timeout for package-related operations": "I-disable ang 1 minutong timeout para sa mga operasyong nauugnay sa package", + "Use installed GSudo instead of UniGetUI Elevator": "Gamitin ang na-install na GSudo sa halip ng UniGetUI Elevator", + "Use a custom icon and screenshot database URL": "Gumamit ng custom na icon at URL ng database ng screenshot", + "Enable background CPU Usage optimizations (see Pull Request #3278)": "Paganahin ang mga pag-optimize sa paggamit ng CPU sa background (tingnan ang Pull Request #3278)", + "Perform integrity checks at startup": "Magsagawa ng mga pagsusuri sa integridad sa pagsisimula", + "When batch installing packages from a bundle, install also packages that are already installed": "Kapag batch ang pag-install ng mga package mula sa isang bundle, i-install din ang mga na-install na mga package", + "Experimental settings and developer options": "Mga pang-eksperimentong setting at mga opsyon sa developer", + "Show UniGetUI's version and build number on the titlebar.": "Ipakita ang bersyon ng UniGetUI sa title bar", + "Language": "Wika", + "UniGetUI updater": "Taga-update ng UniGetUI", + "Telemetry": "Telemetry", + "Manage UniGetUI settings": "Pamahalaan ang mga setting ng UniGetUI", + "Related settings": "Mga kaugnay na setting", + "Update UniGetUI automatically": "Awtomatikong i-update ang UniGetUI", + "Check for updates": "Tingnan ang mga update", + "Install prerelease versions of UniGetUI": "Mag-install ng mga prerelease na bersyon ng UniGetUI", + "Manage telemetry settings": "Pamahalaan ang mga setting ng telemetry", + "Manage": "Pamahalaan", + "Import settings from a local file": "Mag-import ng mga setting mula sa isang lokal na file", + "Import": "I-import", + "Export settings to a local file": "I-export ang mga setting sa isang lokal na file", + "Export": "I-export", + "Reset UniGetUI": "I-reset ang UniGetUI", + "User interface preferences": "Mga kagustuhan sa interface ng user", + "Application theme, startup page, package icons, clear successful installs automatically": "Tema ng aplikasyon, startup page, mga icon ng package, awtomatikong i-clear ang matagumpay na pag-install", + "General preferences": "Pangkalahatang kagustuhan", + "UniGetUI display language:": "Ipinapakitang wika ng UniGetUI:", + "System language": "Wika ng sistema", + "Is your language missing or incomplete?": "Nawawala ba o hindi kumpleto ang iyong wika?", + "Appearance": "Hitsura", + "UniGetUI on the background and system tray": "UniGetUI sa background at system tray", + "Package lists": "Mga listahan ng package", + "Use classic mode": "Gamitin ang classic mode", + "Restart UniGetUI to apply this change": "I-restart ang UniGetUI upang ilapat ang pagbabagong ito", + "The classic UI is disabled for beta testers": "Hindi pinagana ang klasikong UI para sa mga beta tester", + "Close UniGetUI to the system tray": "Isara ang UniGetUI sa system tray", + "Manage UniGetUI autostart behaviour": "Pamahalaan ang gawi ng autostart ng UniGetUI", + "Show package icons on package lists": "Ipakita ang mga icon ng package sa mga listahan ng package", + "Clear cache": "Linisin ang cache", + "Select upgradable packages by default": "Pumili ng mga naa-upgrade na package bilang default", + "Light": "Malinawag", + "Dark": "Madilim", + "Follow system color scheme": "Sundin ang scheme ng kulay ng system", + "Application theme:": "Tema ng aplikasyon:", + "UniGetUI startup page:": "Startup page ng UniGetUI:", + "Proxy settings": "Mga setting ng proxy", + "Other settings": "Iba pang mga setting", + "Connect the internet using a custom proxy": "Kumonekta sa internet gamit ang isang custom na proxy", + "Please note that not all package managers may fully support this feature": "Pakitandaan na hindi lahat ng package manager ay maaaring ganap na suportahan ang feature na ito", + "Proxy URL": "URL ng proxy", + "Enter proxy URL here": "Ilagay ang proxy URL dito", + "Authenticate to the proxy with a user and a password": "Mag-authenticate sa proxy gamit ang user at password", + "Internet and proxy settings": "Mga setting ng internet at proxy", + "Package manager preferences": "Mga kagustuhan sa mga package manager", + "Ready": "Handa", + "Not found": "Hindi mahanap", + "Notification preferences": "Mga kagustuhan sa notification", + "Notification types": "Mga uri ng notification", + "The system tray icon must be enabled in order for notifications to work": "Dapat na pinagana ang icon ng system tray upang gumana ang mga notification", + "Enable UniGetUI notifications": "Paganahin ang mga notification ng UniGetUI", + "Show a notification when there are available updates": "Magpakita ng notification kapag may mga available na update", + "Show a silent notification when an operation is running": "Magpakita ng tahimik na notification kapag tumatakbo ang isang operasyon", + "Show a notification when an operation fails": "Magpakita ng notification kapag nabigo ang isang operasyon", + "Show a notification when an operation finishes successfully": "Magpakita ng notification kapag matagumpay na natapos ang isang operasyon", + "Concurrency and execution": "Concurrency at pag-execute", + "Automatic desktop shortcut remover": "Awtomatikong pagtanggal ng desktop shortcut", + "Choose how many operations should be performed in parallel": "Piliin kung ilang operasyon ang dapat isagawa nang sabay-sabay", + "Clear successful operations from the operation list after a 5 second delay": "Linisin ang matagumpay na operasyon mula sa listahan ng operasyon pagkatapos ng 5 segundong pagkaantala", + "Download operations are not affected by this setting": "Ang mga operasyon sa pag-download ay hindi apektado ng setting na ito", + "You may lose unsaved data": "Maaari kang mawalan ng hindi na-save na data", + "Ask to delete desktop shortcuts created during an install or upgrade.": "Hilingin na tanggalin ang mga desktop shortcut na ginawa sa panahon ng pag-install o pag-upgrade.", + "Package update preferences": "Mga kagustuhan sa pag-update ng package", + "Update check frequency, automatically install updates, etc.": "I-update ang dalas ng pagsusuri, awtomatikong mag-install ng mga update, atbp.", + "Reduce UAC prompts, elevate installations by default, unlock certain dangerous features, etc.": "Bawasan ang mga UAC prompt, itaas ang mga pag-install bilang default, i-unlock ang ilang partikular na mapanganib na feature, atbp.", + "Package operation preferences": "Mga kagustuhan sa pagpapatakbo ng package", + "Enable {pm}": "Paganahin {pm}", + "Not finding the file you are looking for? Make sure it has been added to path.": "Hindi mahanap ang file na hinahanap mo? Tiyaking naidagdag ito sa path.", + "Select the executable to be used. The following list shows the executables found by UniGetUI": "Piliin ang executable na gagamitin. Ipinapakita ng sumusunod na listahan ang mga executable na natagpuan ng UniGetUI", + "For security reasons, changing the executable file is disabled by default": "Dahil sa mga kadahilanang pangseguridad, ang pagpapalit ng executable file ay hindi pinapagana bilang default.", + "Change this": "Palitan ito", + "Copy path": "Kopyahin ang path", + "Current executable file:": "Kasalukuyang executable file:", + "Ignore packages from {pm} when showing a notification about updates": "Huwag pansinin ang mga package mula {pm} kapag nagpapakita ng notification tungkol sa mga update", + "Update security": "Seguridad sa pag-update", + "Use global setting": "Gamitin ang global na setting", + "Minimum age for updates": "Minimum na tagal para sa mga update", + "e.g. 10": "hal. 10", + "Custom minimum age (days)": "Custom na minimum na tagal (araw)", + "{pm} does not provide release dates for its packages, so this setting will have no effect": "Hindi nagbibigay ang {pm} ng mga petsa ng release para sa mga package nito, kaya walang epekto ang setting na ito", + "{pm} only provides release dates for some of its packages, so this setting will only apply to those packages": "Ang {pm} ay nagbibigay lamang ng petsa ng paglabas para sa ilan sa mga pakete nito, kaya ang setting na ito ay mailalapat lamang sa mga pakete na iyon", + "Override the global minimum update age for this package manager": "I-override ang global na minimum na tagal ng update para sa package manager na ito", + "View {0} logs": "Tingnan ang {0} (na) log", + "If Python cannot be found or is not listing packages but is installed on the system, ": "Kung hindi mahanap ang Python o hindi nito naililista ang mga package ngunit naka-install ito sa system, ", + "Advanced options": "Mga advanced na opsyon", + "WinGet command-line tool": "Command-line tool ng WinGet", + "Choose which command-line tool UniGetUI uses for WinGet operations when the COM API is not used": "Piliin kung aling command-line tool ang gagamitin ng UniGetUI para sa mga operasyon ng WinGet kapag hindi ginagamit ang COM API", + "WinGet COM API": "WinGet COM API", + "Choose whether UniGetUI can use the WinGet COM API before falling back to the command-line tool": "Piliin kung maaaring gamitin ng UniGetUI ang WinGet COM API bago bumalik sa command-line tool", + "Reset WinGet": "I-reset ang WinGet", + "This may help if no packages are listed": "Maaaring makatulong ito kung walang nakalistang mga package", + "Force install location parameter when updating packages with custom locations": "Pilitin ang parameter ng lokasyon ng pag-install kapag nag-a-update ng mga package na may custom na lokasyon", + "Install Scoop": "I-install ang Scoop", + "Uninstall Scoop (and its packages)": "I-uninstall ang Scoop (at ang mga package nito)", + "Run cleanup and clear cache": "Patakbuhin ang paglilinis at linisin ang cache", + "Run": "Magpatakbo", + "Enable Scoop cleanup on launch": "Paganahin ang paglilinis ng Scoop sa pagbubukas", + "Default vcpkg triplet": "Default na vcpkg triplet", + "Change vcpkg root location": "Baguhin ang root na lokasyon ng vcpkg", + "Reset vcpkg root location": "I-reset ang root location ng vcpkg", + "Open vcpkg root location": "Buksan ang root location ng vcpkg", + "Language, theme and other miscellaneous preferences": "Wika, tema at iba pang mga kagustuhan", + "Show notifications on different events": "Ipakita ang mga abiso sa iba't ibang mga kaganapan", + "Change how UniGetUI checks and installs available updates for your packages": "Baguhin kung paano sinusuri at ini-install ng UniGetUI ang mga available na update para sa iyong mga package", + "Automatically save a list of all your installed packages to easily restore them.": "Awtomatikong i-save ang isang listahan ng lahat ng iyong naka-install na mga package upang madaling maibalik ang mga ito.", + "Enable and disable package managers, change default install options, etc.": "Paganahin at di paganahin ang mga package manager, palitan ang default na opsyon sa pag-install, atbp.", + "Internet connection settings": "Mga setting ng koneksyon sa internet", + "Proxy settings, etc.": "Mga setting ng proxy, atbp.", + "Beta features and other options that shouldn't be touched": "Mga beta feature at iba pang opsyon na hindi dapat pakialaman", + "Reload sources": "I-reload ang mga source", + "Delete source": "Tanggalin ang source", + "Known sources": "Mga kilalang source", + "Update checking": "Sinisuri ang update", + "Automatic updates": "Mga automatic na update", + "Check for package updates periodically": "Suriin ang mga pag-update ng package sa pana-panahon", + "Check for updates every:": "Tingnan ang mga update kada:", + "Install available updates automatically": "Awtomatikong i-install ang mga available na update", + "Do not automatically install updates when the network connection is metered": "Huwag awtomatikong mag-install ng mga update kapag ang koneksyon sa network ay nakametro", + "Do not automatically install updates when the device runs on battery": "Huwag awtomatikong mag-install ng mga update kapag ang device ay tumatakbo sa battery", + "Do not automatically install updates when the battery saver is on": "Huwag awtomatikong mag-install ng mga update kapag naka-on ang battery saver", + "Only show updates that are at least the specified number of days old": "Ipakita lamang ang mga update na hindi bababa sa tinukoy na bilang ng araw na ang nakalipas", + "Warn me when the installer URL host changes between the installed version and the new version (WinGet only)": "Babalaan ako kapag nagbago ang host ng URL ng installer sa pagitan ng naka-install na bersyon at ng bagong bersyon (WinGet lang)", + "Change how UniGetUI handles install, update and uninstall operations.": "Baguhin kung paano pinangangasiwaan ng UniGetUI ang pag-install, pag-update at pag-uninstall ng mga operasyon.", + "Navigation": "Nabigasyon", + "Check for UniGetUI updates": "Tingnan kung may mga update sa UniGetUI", + "Quit UniGetUI": "Lumabas sa UniGetUI", + "Filters": "Mga filter", + "Sources": "Mga Source", + "Search for packages to start": "Maghanap ng mga package upang magsimula", + "Select all": "Piliin lahat", + "Clear selection": "I-clear ang mga napili", + "Instant search": "Mabilisang paghahanap", + "Distinguish between uppercase and lowercase": "Magkaiba sa pagitan ng\nuppercase at lowercase", + "Ignore special characters": "Huwag pansinin ang mga espesyal na character", + "Search mode": "Mode ng paghahanap", + "Both": "Pareho", + "Exact match": "Eksaktong tugma", + "Show similar packages": "Magkatulad na mga package", + "Loading": "Naglo-load", + "Package": "Package", + "More options": "Higit pang mga opsyon", + "Order by:": "Mag-order sa pamamagitan ng:", + "Name": "Pangalan", + "Id": "ID", + "Ascendant": "Ayos na pataas", + "Descendant": "Ayos na pababa", + "View modes": "Mga mode ng view", + "Reload": "I-reload", + "Closed": "Sarado", + "Ascending": "Pataas", + "Descending": "Pababa", + "{0}: {1}, {2}": "{0}: {1}, {2}", + "Order by": "Ayusin ayon sa", + "No results were found matching the input criteria": "Walang nahanap (na) mga resulta na tumutugma sa pamantayan sa pag-input", + "No packages were found": "Walang nahanap na mga package", + "Loading packages": "Naglo-load ng mga package", + "Skip integrity checks": "Laktawan ang mga pagsusuri sa integridad", + "Download selected installers": "I-download ang mga napiling installer", + "Install selection": "I-install ang mga napili", + "Install options": "Mga opsyon sa install", + "Add selection to bundle": "Magdagdag ng seleksyon sa bundle", + "Download installer": "I-download ang installer", + "Uninstall selection": "Napiling i-uninstall", + "Uninstall options": "Mga opsyon sa pag-uninstall", + "Ignore selected packages": "Huwag pansinin ang mga napiling package", + "Open install location": "Buksan ang lokasyon ng pag-install", + "Reinstall package": "I-reinstall ang package", + "Uninstall package, then reinstall it": "I-uninstall ang package, pagkatapos ay i-reinstall ito", + "Ignore updates for this package": "Huwag pansinin ang mga update para sa mga napiling package", + "WinGet malfunction detected": "May nakitang malfunction ng WinGet", + "It looks like WinGet is not working properly. Do you want to attempt to repair WinGet?": "Mukhang hindi gumagana nang maayos ang WinGet. Gusto mo bang subukang ayusin ang WinGet?", + "Repair WinGet": "Ayusin ang WinGet", + "Updates will no longer be ignored for {0}": "Hindi na babalewalain ang mga update para sa {0}", + "Updates are now ignored for {0}": "Binabalewalaan na ang mga update para sa {0}", + "Do not ignore updates for this package anymore": "Huwag nang balewalain ang mga update para sa package na ito", + "Add packages or open an existing package bundle": "Magdagdag ng mga package o magbukas ng umiiral nang package bundle", + "Add packages to start": "Magdagdag ng mga package upang magsimula", + "The current bundle has no packages. Add some packages to get started": "Ang kasalukuyang bundle ay walang mga package. Magdagdag ng ilang mga package upang makapagsimula", + "New": "Bago", + "Save as": "I-save bilang", + "Create .ps1 script": "Gumawa ng .ps1 script", + "Remove selection from bundle": "Alisin ang napili sa bundle", + "Skip hash checks": "Laktawan ang mga pagsusuri ng hash", + "The package bundle is not valid": "Ang package bundle ay hindi wasto", + "The bundle you are trying to load appears to be invalid. Please check the file and try again.": "Mukhang di-wasto ang bundle na sinusubukan mong i-load. Pakisuri ang file at subukang muli.", + "Package bundle": "Bundle ng package", + "Could not create bundle": "Hindi makagawa ng bundle", + "The package bundle could not be created due to an error.": "Hindi magawa ang package bundle dahil sa isang error.", + "Install script": "Script ng pag-install", + "PowerShell script": "Script ng PowerShell", + "The installation script saved to {0}": "Ang script ng pag-install ay na-save sa {0}", + "An error occurred": "May naganap na error", + "An error occurred while attempting to create an installation script:": "May naganap na error habang sinusubukang ginagawa ang script ng pag-install:", + "Hooray! No updates were found.": "Hooray! Walang nahanap (na) mga update.", + "Uninstall selected packages": "I-uninstall ang mga napiling package", + "Update selection": "Napiling i-update", + "Update options": "Mga opsyon sa pag-update", + "Uninstall package, then update it": "I-uninstall ang package, pagkatapos ay i-update ito", + "Uninstall package": "I-uninstall ang package", + "Skip this version": "Laktawan ang bersyon na ito", + "Pause updates for": "I-pause ang mga update hanggang", + "User | Local": "User | Lokal", + "Machine | Global": "Machine | Global", + "The default package manager for Debian/Ubuntu-based Linux distributions.
Contains: Debian/Ubuntu packages": "Ang default na package manager para sa mga distribusyon ng Linux na batay sa Debian/Ubuntu.
Naglalaman ng: Mga package ng Debian/Ubuntu", + "The Rust package manager.
Contains: Rust libraries and programs written in Rust": "Ang Rust package manager.
Naglalaman ng: Mga Rust na library at program na nakasulat sa Rust", + "The classical package manager for windows. You'll find everything there.
Contains: General Software": "Ang klasikong manager ng package para sa Windows. Makikita mo ang lahat doon.
Naglalaman ng: Pangkalahatang Software", + "The default package manager for RHEL/Fedora-based Linux distributions.
Contains: RPM packages": "Ang default na package manager para sa mga distribusyon ng Linux na batay sa RHEL/Fedora.
Naglalaman ng: Mga RPM package", + "A repository full of tools and executables designed with Microsoft's .NET ecosystem in mind.
Contains: .NET related tools and scripts": "Isang repository na puno ng mga tool at executable na idinisenyo nang nasa isip ang .NET ecosystem ng Microsoft.
Naglalaman ng: Mga tool at script na nauugnay sa .NET", + "The universal Linux package manager for desktop applications.
Contains: Flatpak applications from configured remotes": "Ang pangkalahatang package manager ng Linux para sa mga desktop application.
Naglalaman ng: Mga Flatpak application mula sa mga naka-configure na remote", + "NuPkg (zipped manifest)": "NuPkg (naka-zip na manifest)", + "The Missing Package Manager for macOS (or Linux).
Contains: Formulae, Casks": "Ang Nawawalang Package Manager para sa macOS (o Linux).
Naglalaman ng: Formulae, Casks", + "Node JS's package manager. Full of libraries and other utilities that orbit the javascript world
Contains: Node javascript libraries and other related utilities": "Ang manager ng package ng Node JS. Puno ng mga library at iba pang mga utility na umiikot sa mundo ng javascript
Naglalaman ng: Mga library ng javascript ng node at iba pang nauugnay na mga utility", + "The default package manager for Arch Linux and its derivatives.
Contains: Arch Linux packages": "Ang default na package manager para sa Arch Linux at mga derivative nito.
Naglalaman ng: Mga package ng Arch Linux", + "Python's library manager. Full of python libraries and other python-related utilities
Contains: Python libraries and related utilities": "Tagapamahala ng library ng Python. Puno ng mga library ng python at iba pang mga kagamitang nauugnay sa python
Naglalaman ng: Mga library ng Python at mga nauugnay na kagamitan", + "PowerShell's package manager. Find libraries and scripts to expand PowerShell capabilities
Contains: Modules, Scripts, Cmdlets": "Package manager ng PowerShell. Maghanap ng mga library at script para palawakin ang mga kakayahan ng PowerShell
Naglalaman ng: Mga Module, Script, Cmdlet", + "extracted": "na-extract na", + "Scoop package": "Package ng scoop", + "Great repository of unknown but useful utilities and other interesting packages.
Contains: Utilities, Command-line programs, General Software (extras bucket required)": "Mahusay na imbakan ng hindi alam ngunit kapaki-pakinabang na mga utility at iba pang kawili-wiling mga package.
Naglalaman ng: Mga Utility, Command-line program, Pangkalahatang Software (kinakailangan ng extras na bucket)", + "The universal Linux package manager by Canonical.
Contains: Snap packages from the Snapcraft store": "Ang universal na package manager ng Linux mula sa Canonical.
Naglalaman ng: Mga Snap package mula sa Snapcraft store", + "library": "library", + "feature": "katangian", + "A popular C/C++ library manager. Full of C/C++ libraries and other C/C++-related utilities
Contains: C/C++ libraries and related utilities": "Isang sikat na C/C++ library manager. Puno ng mga library ng C/C++ at iba pang mga utility nauugnay sa C/C++
Naglalaman ng: Mga library ng C/C++ at mga nauugnay na utility", + "option": "opsyon", + "This package cannot be installed from an elevated context.": "Hindi ma-install ang package na ito mula sa isang na-elevate na konteksto.", + "Please run UniGetUI as a regular user and try again.": "Mangyaring patakbuhin ang UniGetUI bilang isang regular na user at subukang muli.", + "Please check the installation options for this package and try again": "Pakisuri ang mga opsyon sa pag-install para sa package na ito at subukang muli", + "Microsoft's official package manager. Full of well-known and verified packages
Contains: General Software, Microsoft Store apps": "Opisyal na manager ng package ng Microsoft. Puno ng mga kilalang at na-verify na package
Naglalaman ng: Pangkalahatang Software, Mga app ng Microsoft Store", + "Local PC": "Lokal na PC", + "Android Subsystem": "Android Subsystem", + "Operation on queue (position {0})...": "Operasyon sa queue (posisyon {0})...", + "Click here for more details": "Mag-click dito para sa higit pang mga detalye", + "Operation canceled by user": "Kinansela ng user ang operasyon", + "Running PreOperation ({0}/{1})...": "Pinapatakbo ang PreOperation ({0}/{1})...", + "PreOperation {0} out of {1} failed, and was tagged as necessary. Aborting...": "Nabigo ang PreOperation {0} sa {1}, at minarkahang kinakailangan. Ina-abort...", + "PreOperation {0} out of {1} finished with result {2}": "Natapos ang PreOperation {0} sa {1} na may resultang {2}", + "Starting operation...": "Sinisimulan ang operasyon...", + "Running PostOperation ({0}/{1})...": "Pinapatakbo ang PostOperation ({0}/{1})...", + "PostOperation {0} out of {1} failed, and was tagged as necessary. Aborting...": "Nabigo ang PostOperation {0} sa {1}, at minarkahang kinakailangan. Ina-abort...", + "PostOperation {0} out of {1} finished with result {2}": "Natapos ang PostOperation {0} sa {1} na may resultang {2}", + "{package} installer download": "Pag-download ng installer ng {package}", + "{0} installer is being downloaded": "Ang {0} installer ay dina-download", + "Download succeeded": "Nagtagumpay ang pag-download", + "{package} installer was downloaded successfully": "Matagumpay na na-download ang installer ng {package}", + "Download failed": "Nabigo ang pag-download", + "{package} installer could not be downloaded": "Hindi ma-download ang installer ng {package}", + "{package} Installation": "Pag-install ng {package}", + "{0} is being installed": "Ini-install ang {0}", + "Installation succeeded": "Nagtagumpay ang pag-install", + "{package} was installed successfully": "Matagumpay na na-install ang {package}", + "Installation failed": "Nabigo ang pag-install", + "{package} could not be installed": "Hindi ma-install ang {package}", + "{package} Update": "Pag-update ng {package}", + "Update succeeded": "Nagtagumpay ang pag-update", + "{package} was updated successfully": "Matagumpay na na-update ang {package}", + "Update failed": "Nabigo ang pag-update", + "{package} could not be updated": "Hindi ma-update ang {package}", + "{package} Uninstall": "Pag-uninstall ng {package}", + "{0} is being uninstalled": "Ina-uninstall ang {0}", + "Uninstall succeeded": "Nagtagumpay ang pag-uninstall", + "{package} was uninstalled successfully": "Matagumpay na na-uninstall ang {package}", + "Uninstall failed": "Nabigo ang pag-uninstall", + "{package} could not be uninstalled": "Hindi ma-uninstall ang {package}", + "Adding source {source}": "Pagdaragdag ng source {source}", + "Adding source {source} to {manager}": "Pagdaragdag ng source {source} sa {manager}", + "Source added successfully": "Matagumpay na naidagdag ang source", + "The source {source} was added to {manager} successfully": "Ang source {source} ay matagumpay na naidagdag sa {manager}.", + "Could not add source": "Hindi maidagdag ang source", + "Could not add source {source} to {manager}": "Hindi maidagdag ang source {source} sa {manager}", + "Removing source {source}": "Inaalis ang source {source}", + "Removing source {source} from {manager}": "Inaalis ang source {source} mula sa {manager}", + "Source removed successfully": "Matagumpay na naalis ang source", + "The source {source} was removed from {manager} successfully": "Matagumpay na naalis ang source {source} mula sa {manager}.", + "Could not remove source": "Hindi maalis ang source", + "Could not remove source {source} from {manager}": "Hindi maalis ang source {source} mula sa {manager}", + "The package manager \"{0}\" was not found": "Ang manager ng package na \"{0}\" ay hindi nahanap", + "The package manager \"{0}\" is disabled": "Ang manager ng package na \"{0}\" ay naka-disable", + "There is an error with the configuration of the package manager \"{0}\"": "Mayroong error sa configuration ng package manager na \"{0}\"", + "The package \"{0}\" was not found on the package manager \"{1}\"": "Ang package na \"{0}\" ay hindi nahanap sa package manager na \"{1}\"", + "{0} is disabled": "{0} ay naka-disable", + "{0} weeks": "{0} (na) linggo", + "1 month": "1 buwan", + "{0} months": "{0} (na) buwan", + "Something went wrong": "Nagkaroon ng problema", + "An interal error occurred. Please view the log for further details.": "May naganap na internal na error. Pakitingnan ang log para sa karagdagang detalye.", + "No applicable installer was found for the package {0}": "Walang nahanap na naaangkop na installer para sa package na {0}", + "Integrity checks will not be performed during this operation": "Ang mga pagsusuri sa integridad ay hindi isasagawa sa panahon ng operasyong ito", + "This is not recommended.": "Hindi ito inirerekomenda.", + "Run now": "Patakbuhin ngayon", + "Run next": "Patakbuhin susunod", + "Run last": "Huling patakbuhin", + "Show in explorer": "Ipakita sa explorer", + "Checked": "Naka-check", + "Unchecked": "Hindi naka-check", + "This package is already installed": "Naka-install na ang package na ito", + "This package can be upgraded to version {0}": "Maaaring i-upgrade ang package na ito sa bersyon {0}", + "Updates for this package are ignored": "Binabalewala ang mga update para sa package na ito", + "This package is being processed": "Pinoproseso ang package na ito", + "This package is not available": "Hindi available ang package na ito", + "Select the source you want to add:": "Piliin ang source na gusto mong idagdag:", + "Source name:": "Pangalan ng source:", + "Source URL:": "URL ng Source:", + "An error occurred when adding the source: ": "Nagkaroon ng error nang idagdag ang source:", + "Package management made easy": "Pinadali ang pamamahala ng package", + "version {0}": "bersyon {0}", + "[RAN AS ADMINISTRATOR]": "PINATAKBO BILANG ADMINISTRATOR", + "Portable mode": "Portable na mode\n", + "DEBUG BUILD": "Build na pang-debug", + "Here you can change UniGetUI's behaviour regarding the following shortcuts. Checking a shortcut will make UniGetUI delete it if if gets created on a future upgrade. Unchecking it will keep the shortcut intact": "Dito mo mababago ang kilos ng UniGetUI patungkol sa mga sumusunod na shortcut. Ang pag-check sa isang shortcut ay magbubura nito kung ito ay gagawin sa isang pag-upgrade sa hinaharap. Ang pag-uncheck dito ay magpapanatili ang shortcut.", + "Manual scan": "Mano-manong i-scan", + "Existing shortcuts on your desktop will be scanned, and you will need to pick which ones to keep and which ones to remove.": "Ii-scan ang mga kasalukuyang shortcut sa iyong desktop, at kakailanganin mong pumili kung alin ang dapat panatilihin at kung alin ang aalisin.", + "Delete?": "Tanggalin?", + "I understand": "Naiintindihan ko", + "Chocolatey setup changed": "Nagbago ang setup ng Chocolatey", + "UniGetUI no longer includes its own private Chocolatey installation. A legacy UniGetUI-managed Chocolatey installation was detected for this user profile, but system Chocolatey was not found. Chocolatey will stay unavailable in UniGetUI until Chocolatey is installed on the system and UniGetUI is restarted. Applications previously installed through UniGetUI's bundled Chocolatey may still appear under other sources such as Local PC or WinGet.": "Hindi na kasama sa UniGetUI ang sarili nitong pribadong pag-install ng Chocolatey. May nakitang legacy na pag-install ng Chocolatey na pinamamahalaan ng UniGetUI para sa user profile na ito, ngunit hindi nahanap ang system Chocolatey. Mananatiling hindi available ang Chocolatey sa UniGetUI hanggang ma-install ang Chocolatey sa system at ma-restart ang UniGetUI. Ang mga application na dating na-install sa pamamagitan ng naka-bundle na Chocolatey ng UniGetUI ay maaaring lumitaw pa rin sa ibang mga source tulad ng Local PC o WinGet.", + "NOTE: This troubleshooter can be disabled from UniGetUI Settings, on the WinGet section": "TANDAAN: Maaaring hindi paganahin ang troubleshooter na ito mula sa Mga Setting ng UniGetUI, sa seksyong WinGet", + "Restart": "I-reset", + "Are you sure you want to delete all shortcuts?": "Sigurado ka bang gusto mong tanggalin ang lahat ng mga shortcut?", + "Any new shorcuts created during an install or an update operation will be deleted automatically, instead of showing a confirmation prompt the first time they are detected.": "Awtomatikong made-delete ang anumang mga bagong shortcut na ginawa sa panahon ng pag-install o pagpapatakbo ng pag-update, sa halip na magpakita ng prompt ng kumpirmasyon sa unang pagkakataong matukoy ang mga ito.", + "Any shorcuts created or modified outside of UniGetUI will be ignored. You will be able to add them via the {0} button.": "Ang anumang mga shortcut na ginawa o binago sa labas ng UniGetUI ay hindi papansinin. Magagawa mong idagdag ang mga ito sa pamamagitan ng button na {0}.", + "Are you really sure you want to enable this feature?": "Sigurado ka bang gusto mong paganahin ang feature na ito?", + "No new shortcuts were found during the scan.": "Walang nahanap na mga bagong shortcut sa pag-scan.", + "How to add packages to a bundle": "Paano magdagdag ng mga package sa isang bundle", + "In order to add packages to a bundle, you will need to: ": "Upang magdagdag ng mga package sa isang bundle, kakailanganin mong:", + "1. Navigate to the \"{0}\" or \"{1}\" page.": "1. Mag-navigate sa \"{0}\" o \"{1}\" na pahina.", + "2. Locate the package(s) you want to add to the bundle, and select their leftmost checkbox.": "2. Hanapin ang (mga) package na gusto mong idagdag sa bundle, at piliin ang kanilang pinakakaliwang checkbox.", + "3. When the packages you want to add to the bundle are selected, find and click the option \"{0}\" on the toolbar.": "3. Kapag napili ang mga package na gusto mong idagdag sa bundle, hanapin at i-click ang opsyong \"{0}\" sa toolbar.", + "4. Your packages will have been added to the bundle. You can continue adding packages, or export the bundle.": "4. Ang iyong mga package ay naidagdag na sa bundle. Maaari kang magpatuloy sa pagdaragdag ng mga package, o i-export ang bundle.", + "Which backup do you want to open?": "Anong backup ang gusto mong buksan?", + "Select the backup you want to open. Later, you will be able to review which packages you want to install.": "Piliin ang backup na gusto mong buksan. Sa ibang pagkakataon, magagawa mong suriin kung aling mga package/program ang gusto mong i-restore.", + "There are ongoing operations. Quitting UniGetUI may cause them to fail. Do you want to continue?": "May mga patuloy na operasyon. Ang paghinto sa UniGetUI ay maaaring maging sanhi ng pagkabigo sa kanila. Gusto mo bang magpatuloy?", + "UniGetUI or some of its components are missing or corrupt.": "Ang UniGetUI o ang ilan sa mga bahagi nito ay nawawala o na-corrupt.", + "It is strongly recommended to reinstall UniGetUI to adress the situation.": "Lubos na inirerekomendang ang pag-reinstall ng UniGetUI upang matugunan ang sitwasyon.", + "Refer to the UniGetUI Logs to get more details regarding the affected file(s)": "Sumangguni sa mga log ng UniGetUI para makakuha ng higit pang mga detalye tungkol sa (mga) apektadong file", + "Integrity checks can be disabled from the Experimental Settings": "Maaaring i-disable ang mga pagsusuri sa integridad mula sa Mga Pang-eksperimento Setting", + "Repair UniGetUI": "Ayusin ang UniGetUI", + "Live output": "Live na output", + "This package bundle had some settings that are potentially dangerous, and may be ignored by default.": "Ang package bundle na ito ay may ilang mga setting na potensyal na mapanganib, at maaaring balewalain bilang default.", + "Entries that show in YELLOW will be IGNORED.": "Ang mga entry na makikita sa DILAW ay HINDI PAPANSININ.", + "Entries that show in RED will be IMPORTED.": "Ang mga entry na makikita sa PULA ay I-IMPORT.", + "You can change this behavior on UniGetUI security settings.": "Maaari mong baguhin ang gawi na ito sa mga setting ng seguridad ng UniGetUI.", + "Open UniGetUI security settings": "Buksan ang mga setting ng seguridad ng UniGetUI", + "Should you modify the security settings, you will need to open the bundle again for the changes to take effect.": "Kung babaguhin mo ang mga setting ng seguridad, kakailanganin mong buksan muli ang bundle para magkabisa ang mga pagbabago.", + "Details of the report:": "Mga detalye ng report:", + "Are you sure you want to create a new package bundle? ": "Sigurado ka bang gusto mong gumawa ng bagong package bundle?", + "Any unsaved changes will be lost": "Mawawala ang anumang hindi na-save na pagbabago", + "Warning!": "Babala!", + "For security reasons, custom command-line arguments are disabled by default. Go to UniGetUI security settings to change this. ": "Dahil sa mga kadahilanang pangseguridad, ang mga custom na argumento sa command-line ay di-pinagana ng default. Pumunta sa mga setting ng seguridad sa UniGetUI para palitan ito.", + "Change default options": "Baguhin ang mga default na opsyon", + "Ignore future updates for this package": "Huwag pansinin ang mga update sa hinaharap para sa package na ito", + "For security reasons, pre-operation and post-operation scripts are disabled by default. Go to UniGetUI security settings to change this. ": "Dahil sa mga kadahilanang pangseguridad, ang mga script ng pre-operation at post-operation ay di-pinagana ng default. Pumunta sa mga setting ng seguridad sa UniGetUI para palitan ito.", + "You can define the commands that will be run before or after this package is installed, updated or uninstalled. They will be run on a command prompt, so CMD scripts will work here.": "Maaari mong tukuyin ang mga command na patatakbuhin bago o pagkatapos ma-install, ma-update o ma-uninstall ang package na ito. Tatakbo ang mga ito sa command prompt, kaya gagana rito ang mga CMD script.", + "Change this and unlock": "Palitan ito at i-unlock", + "{0} Install options are currently locked because {0} follows the default install options.": "Kasalukuyang naka-lock ang mga opsyon sa pag-install ng {0} dahil sinusunod ng {0} ang mga default na opsyon sa pag-install.", + "Unset or unknown": "Hindi nakatakda o hindi alam", + "This package has no screenshots or is missing the icon? Contrbute to UniGetUI by adding the missing icons and screenshots to our open, public database.": "Ang package na ito ay walang mga screenshot o nawawala ang icon? Mag-ambag sa UniGetUI sa pamamagitan ng pagdaragdag ng mga nawawalang icon at screenshot sa aming bukas, pampublikong database.", + "Become a contributor": "Maging isang kontribyutor", + "Update to {0} available": "Available ang update sa {0}.", + "Reinstall": "I-reinstall", + "Installer not available": "Hindi available ang installer", + "Version:": "Bersyon:", + "UniGetUI Version {0}": "Bersyon ng UniGetUI {0}", + "Performing backup, please wait...": "Nagsasagawa ng backup, mangyaring maghintay...", + "An error occurred while logging in: ": "Nakaroon ng error habang naglalog-in:", + "Fetching available backups...": "Kinukuha ang mga available na backup...", + "Done!": "Tapos na!", + "The cloud backup has been loaded successfully.": "Matagumpay na na-load ang cloud backup.", + "An error occurred while loading a backup: ": "Nagkaroon ng error habang niloload ang backup:", + "Backing up packages to GitHub Gist...": "Bina-backup ang mga package sa GitHub Gist...", + "Backup Successful": "Matagumpay ang Pag-Backup", + "The cloud backup completed successfully.": "Matagumpay na nakumpleto ang cloud backup.", + "Could not back up packages to GitHub Gist: ": "Hindi ma-back up ang mga package sa GitHub Gist:", + "It is not guaranteed that the provided credentials will be stored safely, so you may as well not use the credentials of your bank account": "Hindi garantisadong ligtas na maiimbak ang mga ibinigay na kredensyal, kaya maaari mo ring hindi gamitin ang mga kredensyal ng iyong bank account", + "Enable the automatic WinGet troubleshooter": "Paganahin ang awtomatikong WinGet troubleshooter", + "Add updates that fail with a 'no applicable update found' to the ignored updates list": "Idagdag ang mga update na nabigo na may 'walang nahanap na naaangkop na update' sa listahan ng mga hindi pinansin na update.", + "Invalid selection": "Hindi wastong pagpili", + "No package was selected": "Walang napiling package", + "More than 1 package was selected": "Mahigit 1 package ang napili", + "List": "Listahan", + "Grid": "Grid", + "Icons": "Mga icon", + "\"{0}\" is a local package and does not have available details": "\"{0}\" ay isang lokal na package at ay walang magagamit na mga detalye", + "\"{0}\" is a local package and is not compatible with this feature": "\"{0}\" ay isang lokal na package at hindi compatible sa feature na ito", + "Add packages to bundle": "Magdagdag ng mga package sa bundle", + "Preparing packages, please wait...": "Inihahanda ang mga package, mangyaring maghintay...", + "Loading packages, please wait...": "Naglo-load ng mga package, mangyaring maghintay...", + "Saving packages, please wait...": "Sine-save ang mga package, mangyaring maghintay...", + "The bundle was created successfully on {0}": "Matagumpay na nalikha ang bundle noong {0}", + "User profile": "Profile ng user", + "Error": "Error", + "Log in failed: ": "Bigong mag-log in:", + "Log out failed: ": "Bigong mag-log out:", + "Package backup settings": "Mga setting ng pag-backup ng package", + "Manage UniGetUI autostart behaviour from the Settings app": "Pamahalaan ang awtomatikong pagsisimula ng UniGetUI", + "Choose how many operations shoulds be performed in parallel": "Piliin kung ilang operasyon ang dapat isagawa nang sabay-sabay", + "Something went wrong while launching the updater.": "Nagkaroon ng problema habang pinapatakbo ang updater.", + "Please try again later": "Pakisubukang muli mamaya", + "Show the release notes after UniGetUI is updated": "Ipakita ang mga release note pagkatapos ma-update ang UniGetUI" +} diff --git a/src/Languages/lang_fr.json b/src/Languages/lang_fr.json new file mode 100644 index 0000000..98b38c4 --- /dev/null +++ b/src/Languages/lang_fr.json @@ -0,0 +1,850 @@ +{ + "{0} of {1} operations completed": "{0} opérations sur {1} terminées", + "{0} is now {1}": "{0} est maintenant {1}", + "Enabled": "Activé", + "Disabled": "Désactivé", + "Privacy": "Confidentialité", + "Hide my username from the logs": "Masquer mon nom d'utilisateur dans les journaux", + "Replaces your username with **** in the logs. Restart UniGetUI to also hide it from already-recorded entries.": "Remplace votre nom d'utilisateur par **** dans les journaux. Redémarrez UniGetUI pour le masquer également dans les entrées déjà enregistrées.", + "Your last update attempt did not complete.": "Votre dernière tentative de mise à jour ne s'est pas terminée.", + "UniGetUI could not confirm whether the update succeeded. Open the log to see what happened.": "UniGetUI n'a pas pu confirmer si la mise à jour a réussi. Ouvrez le journal pour voir ce qui s'est passé.", + "View log": "Afficher le journal", + "The installer reported success but did not restart UniGetUI.": "L'installateur a indiqué que l'opération a réussi, mais n'a pas redémarré UniGetUI.", + "The installer failed to initialize.": "L'installateur n'a pas pu s'initialiser.", + "Setup was canceled before installation began.": "L'installation a été annulée avant de commencer.", + "A fatal error occurred during the preparation phase.": "Une erreur fatale s'est produite pendant la phase de préparation.", + "A fatal error occurred during installation.": "Une erreur fatale s'est produite pendant l'installation.", + "Installation was canceled while in progress.": "L'installation a été annulée alors qu'elle était en cours.", + "The installer was terminated by another process.": "L'installateur a été arrêté par un autre processus.", + "The preparation phase determined the installation cannot proceed.": "La phase de préparation a déterminé que l'installation ne peut pas continuer.", + "The installer could not start. UniGetUI may already be running, or you do not have permission to install.": "L'installateur n'a pas pu démarrer. UniGetUI est peut-être déjà en cours d'exécution, ou vous ne disposez pas des autorisations nécessaires pour l'installer.", + "Unexpected installer error.": "Erreur inattendue de l'installateur.", + "We are checking for updates.": "Nous vérifions les mises à jour.", + "Please wait": "Veuillez patienter", + "Great! You are on the latest version.": "Génial ! Vous utilisez la dernière version.", + "There are no new UniGetUI versions to be installed": "Il n'y a pas de nouvelle version d'UniGetUI à installer.", + "UniGetUI version {0} is being downloaded.": "La version {0} d'UniGetUI est en cours de téléchargement.", + "This may take a minute or two": "Cela peut prendre une minute ou deux", + "The installer authenticity could not be verified.": "L'authenticité de l'installateur n'a pas pu être vérifiée.", + "The update process has been aborted.": "Le processus de mise à jour a été interrompu.", + "Auto-update is not yet available on this platform.": "La mise à jour automatique n'est pas encore disponible sur cette plateforme.", + "Please update UniGetUI manually.": "Veuillez mettre à jour UniGetUI manuellement.", + "An error occurred when checking for updates: ": "Une erreur s'est produite lors de la vérification des mises à jour :", + "The updater could not be launched.": "L'outil de mise à jour n'a pas pu être lancé.", + "The operating system did not start the installer process.": "Le système d'exploitation n'a pas démarré le processus d'installation.", + "UniGetUI is being updated...": "UniGetUI est en cours de mise à jour...", + "Update installed.": "Mise à jour installée.", + "UniGetUI was updated successfully, but this running copy was not replaced. This usually means you are running a development build. Close this copy and start the newly-installed version to finish.": "UniGetUI a été mis à jour avec succès, mais cette copie en cours d'exécution n'a pas été remplacée. Cela signifie généralement que vous utilisez une version de développement. Fermez cette copie et lancez la version nouvellement installée pour terminer.", + "The update could not be applied.": "La mise à jour n'a pas pu être appliquée.", + "Installer exit code {0}: {1}": "Code de sortie de l'installateur {0} : {1}", + "Update cancelled.": "Mise à jour annulée.", + "Authentication was cancelled.": "L'authentification a été annulée.", + "Installer exit code {0}": "Code de sortie de l'installateur {0}", + "Operation in progress": "Opération en cours", + "Please wait...": "Veuillez patienter...", + "Success!": "Succès !", + "Failed": "Échec", + "An error occurred while processing this package": "Une erreur s'est produite lors du traitement du paquet", + "Installer": "Installateur", + "Executable": "Exécutable", + "MSI": "MSI", + "Compressed file": "Fichier compressé", + "MSIX": "MSIX", + "WinGet was repaired successfully": "WinGet a été réparé avec succès", + "It is recommended to restart UniGetUI after WinGet has been repaired": "Il est recommandé de redémarrer UniGetUI après que WinGet a été réparé", + "WinGet could not be repaired": "WinGet n'a pas pu être réparé", + "An unexpected issue occurred while attempting to repair WinGet. Please try again later": "Une problème inattendu s'est produit lors de la tentative de réparation de WinGet. Veuillez réessayer plus tard.", + "Log in to enable cloud backup": "Connectez-vous pour activer la sauvegarde dans le cloud", + "Backup Failed": "La sauvegarde a échoué", + "Downloading backup...": "Téléchargement de la sauvegarde...", + "An update was found!": "Une mise à jour a été trouvée !", + "{0} can be updated to version {1}": "{0} peut être mis à jour vers la version {1}", + "Updates found!": "Mises à jour trouvées !", + "{0} packages can be updated": "{0} paquets peuvent être mis à jour", + "{0} is being updated to version {1}": "{0} est en cours de mise à jour vers la version {1}", + "{0} packages are being updated": "{0} paquets sont en cours de mise à jour", + "You have currently version {0} installed": "Vous avez actuellement la version {0} installée", + "Desktop shortcut created": "Raccourci sur le bureau créé", + "UniGetUI has detected a new desktop shortcut that can be deleted automatically.": "UniGetUI a détecté un nouveau raccourci sur le bureau qui peut être supprimé automatiquement.", + "{0} desktop shortcuts created": "{0} raccourci(s) sur le bureau créé(s)", + "UniGetUI has detected {0} new desktop shortcuts that can be deleted automatically.": "UniGetUI a détecté {0} nouveau(x) raccourci(s) sur le bureau pouvant être supprimé(s) automatiquement.", + "Attention required": "Attention requise", + "Restart required": "Redémarrage requis", + "1 update is available": "1 mise à jour est disponible", + "{0} updates are available": "{0} mises à jour sont disponibles", + "Everything is up to date": "Tout est à jour", + "Discover Packages": "Découvrir des paquets", + "Available Updates": "Mises à jour disponibles", + "Installed Packages": "Paquets installés", + "UniGetUI Version {0} by Devolutions": "UniGetUI version {0} par Devolutions", + "Show UniGetUI": "Afficher UniGetUI", + "Quit": "Quitter", + "Are you sure?": "Êtes-vous sûr ?", + "Do you really want to uninstall {0}?": "Voulez-vous vraiment désinstaller {0} ?", + "Do you really want to uninstall the following {0} packages?": "Voulez-vous vraiment désinstaller les {0} paquets suivants ?", + "No": "Non", + "Yes": "Oui", + "Partial": "Partiel", + "View on UniGetUI": "Voir sur UniGetUI", + "Update": "Mettre à jour", + "Open UniGetUI": "Ouvrir UniGetUI", + "Update all": "Tout mettre à jour", + "Update now": "Mettre à jour maintenant", + "Installer host changed since the installed version.\n": "L'hôte de l'installateur a changé depuis la version installée.\n", + "This package is on the queue": "Ce paquet est dans la fil d'attente", + "installing": "installation en cours", + "updating": "Mise à jour en cours", + "uninstalling": "désinstallation en cours", + "installed": "installé", + "Retry": "Réessayer", + "Install": "Installer", + "Uninstall": "Désinstaller", + "Open": "Ouvrir", + "Operation profile:": "Profil de l'opération :", + "Follow the default options when installing, upgrading or uninstalling this package": "Suivez les options par défaut lors de l'installation, de la mise à niveau ou de la désinstallation de ce logiciel.", + "The following settings will be applied each time this package is installed, updated or removed.": "Les paramètres suivants seront appliqués à chaque fois que ce paquet sera installé, mis à jour ou supprimé.", + "Version to install:": "Version à installer :", + "Architecture to install:": "Architecture à installer :", + "Installation scope:": "Portée de l'installation", + "Install location:": "Emplacement d'installation :", + "Select": "Sélectionner", + "Reset": "Réinitialiser", + "Custom install arguments:": "Arguments d'installation personnalisés :", + "Custom update arguments:": "Arguments de mise à jour personnalisés :", + "Custom uninstall arguments:": "Arguments de désinstallation personnalisés :", + "Pre-install command:": "Commande de pré-installation :", + "Post-install command:": "Commande de post-installation :", + "Abort install if pre-install command fails": "Abandonner l'installation si la commande de pré-installation échoue", + "Pre-update command:": "Commande de pré-mise à jour :", + "Post-update command:": "Commande de post-mise à jour :", + "Abort update if pre-update command fails": "Abandonner la mise à jour si la commande de pré-mise à jour échoue", + "Pre-uninstall command:": "Commande de pré-désinstallation :", + "Post-uninstall command:": "Commande de post-désinstallation :", + "Abort uninstall if pre-uninstall command fails": "Abandonner la désinstallation si la commande de pré-désinstallation échoue", + "Command-line to run:": "Ligne de commande à exécuter :", + "Save and close": "Enregistrer et fermer", + "General": "Général", + "Architecture & Location": "Architecture et emplacement", + "Command-line": "Ligne de commande", + "Close apps": "Fermer les applications", + "Pre/Post install": "Pré/post-installation", + "Select the processes that should be closed before this package is installed, updated or uninstalled.": "Sélectionnez les processus qui doivent être fermés avant l'installation, la mise à jour ou la désinstallation de ce paquet.", + "Write here the process names here, separated by commas (,)": "Saisissez ici les noms des processus, séparés par des virgules (,)", + "Try to kill the processes that refuse to close when requested to": "Essayer de tuer les processus qui refusent de se fermer lorsqu'on le leur demande.", + "Run as admin": "Exécuter en tant qu'administrateur", + "Interactive installation": "Installation interactive", + "Skip hash check": "Passer la vérification du hachage", + "Uninstall previous versions when updated": "Désinstaller les versions précédentes lors de la mise à jour", + "Skip minor updates for this package": "Ignorer les mises à jour mineures pour ce paquet", + "Automatically update this package": "Mettre à jour automatiquement ce package", + "{0} installation options": "Options d'installation de {0}", + "Latest": "Dernière", + "PreRelease": "Préversion", + "Default": "Par défaut", + "Manage ignored updates": "Gérer les mises à jour ignorées", + "The packages listed here won't be taken in account when checking for updates. Double-click them or click the button on their right to stop ignoring their updates.": "Les paquets listés ici ne seront pas pris en compte lors de la vérification des mises à jour. Double-cliquez dessus ou cliquez sur le bouton à leur droite pour ne plus ignorer leurs mises à jour.", + "Reset list": "Réinitialiser la liste", + "Do you really want to reset the ignored updates list? This action cannot be reverted": "Voulez-vous vraiment réinitialiser la liste des mises à jour ignorées ? Cette action ne peut pas être annulée.", + "No ignored updates": "Aucune mise à jour ignorée", + "Package Name": "Nom du paquet", + "Package ID": "ID du paquet", + "Ignored version": "Version ignorée", + "New version": "Nouvelle version", + "Source": "Source", + "All versions": "Toutes les versions", + "Unknown": "Inconnu", + "Up to date": "À jour", + "Package {name} from {manager}": "Paquet {name} de {manager}", + "Remove {0} from ignored updates": "Retirer {0} des mises à jour ignorées", + "Cancel": "Annuler", + "Administrator privileges": "Privilèges d'administrateur", + "This operation is running with administrator privileges.": "Cette opération est exécutée avec les privilèges d'administrateur.", + "Interactive operation": "Fonctionnement interactif", + "This operation is running interactively.": "Cette opération s'exécute de manière interactive.", + "You will likely need to interact with the installer.": "Vous devrez probablement interagir avec le programme d'installation.", + "Integrity checks skipped": "Contrôles d'intégrité ignorés", + "Integrity checks will not be performed during this operation.": "Les contrôles d'intégrité ne seront pas effectués pendant cette opération.", + "Proceed at your own risk.": "Procédez à vos propres risques.", + "Close": "Fermer", + "Loading...": "Chargement...", + "Installer SHA256": "SHA256 de l'installateur", + "Homepage": "Page d'accueil", + "Author": "Auteur", + "Publisher": "Éditeur", + "License": "Licence", + "Manifest": "Manifeste", + "Installer Type": "Type d'installateur", + "Size": "Taille", + "Installer URL": "URL de l'installateur", + "Last updated:": "Dernière date de mise à jour :", + "Release notes URL": "URL des notes de version", + "Package details": "Détails du paquet", + "Dependencies:": "Dépendances :", + "Release notes": "Notes de publication", + "Screenshots": "Captures d’écran", + "This package has no screenshots or is missing the icon? Contribute to UniGetUI by adding the missing icons and screenshots to our open, public database.": "Ce paquet n’a pas de captures d’écran ou l’icône est manquante ? Contribuez à UniGetUI en ajoutant les icônes et captures d’écran manquantes à notre base de données ouverte et publique.", + "Version": "Version", + "Install as administrator": "Installer en tant qu'administrateur", + "Update to version {0}": "Mettre à jour vers la version {0}", + "Installed Version": "Version installée", + "Update as administrator": "Mettre à jour en tant qu'administrateur", + "Interactive update": "Mise à jour interactive", + "Uninstall as administrator": "Désinstaller en tant qu'administrateur", + "Interactive uninstall": "Désinstallation interactive", + "Uninstall and remove data": "Désinstaller et supprimer les données", + "Not available": "Non disponible", + "Installer SHA512": "SHA512 de l'installateur", + "Unknown size": "Taille inconnue", + "No dependencies specified": "Aucune dépendance spécifiée", + "mandatory": "obligatoire", + "optional": "optionnel", + "UniGetUI {0} is ready to be installed.": "UniGetUI {0} est prêt à être installé.", + "The update process will start after closing UniGetUI": "Le processus de mise à jour démarrera après la fermeture d'UniGetUI", + "UniGetUI has been ran as administrator, which is not recommended. When running UniGetUI as administrator, EVERY operation launched from UniGetUI will have administrator privileges. You can still use the program, but we highly recommend not running UniGetUI with administrator privileges.": "UniGetUI a été exécuté en tant qu'administrateur, ce qui n'est pas recommandé. Lorsque UniGetUI est exécuté en tant qu'administrateur, TOUTE opération lancée depuis UniGetUI disposera des privilèges d'administrateur. Vous pouvez toujours utiliser le programme, mais nous vous recommandons vivement de ne pas exécuter UniGetUI avec des privilèges d'administrateur.", + "Share anonymous usage data": "Partager les données d'utilisation anonymes", + "UniGetUI collects anonymous usage data in order to improve the user experience.": "UniGetUI recueille des données d'utilisation anonymes afin d'améliorer l'expérience utilisateur.", + "Accept": "Accepter", + "Software Updates": "Mises à jour", + "Package Bundles": "Lots de paquets", + "Settings": "Paramètres", + "Package Managers": "Gestionnaires de paquets", + "UniGetUI Log": "Journal d'UniGetUI", + "Package Manager logs": "Journaux du gestionnaire de paquets", + "Operation history": "Historique des opérations", + "Help": "Aide", + "UniGetUI": "UniGetUI", + "You have installed UniGetUI Version {0}": "Vous avez installé UniGetUI Version {0}", + "Disclaimer": "Avertissement", + "UniGetUI is developed by Devolutions and is not affiliated with any of the compatible package managers.": "UniGetUI est développé par Devolutions et n’est affilié à aucun des gestionnaires de paquets compatibles.", + "UniGetUI wouldn't have been possible without the help of the contributors. Thank you all 🥳": "UniGetUI n'aurait pas été possible sans l'aide des contributeurs. Merci à tous 🥳", + "UniGetUI uses the following libraries. Without them, UniGetUI wouldn't have been possible.": "UniGetUI utilise les bibliothèques suivantes. Sans elles, UniGetUI n'aurait pas pu exister.", + "{0} homepage": "Page d'accueil de {0}", + "UniGetUI has been translated to more than 40 languages thanks to the volunteer translators. Thank you 🤝": "UniGetUI a été traduit dans plus de 40 langues grâce aux traducteurs bénévoles. Merci 🤝", + "Verbose": "Verbose", + "1 - Errors": "1 - Erreurs", + "2 - Warnings": "2 - Avertissements", + "3 - Information (less)": "3 - Information (moins)", + "4 - Information (more)": "4 - Information (plus)", + "5 - information (debug)": "5 - Information (débogage)", + "Warning": "Avertissement", + "The following settings may pose a security risk, hence they are disabled by default.": "Les paramètres suivants peuvent présenter un risque pour la sécurité, c'est pourquoi ils sont désactivés par défaut.", + "Enable the settings below if and only if you fully understand what they do, and the implications they may have.": "Activez les paramètres ci-dessous SI ET SEULEMENT SI vous comprenez parfaitement ce qu'ils font, ainsi que les implications et les dangers qu'ils peuvent impliquer.", + "The settings will list, in their descriptions, the potential security issues they may have.": "Les paramètres énumèrent, dans leur description, les problèmes de sécurité potentiels qu'ils peuvent présenter.", + "The backup will include the complete list of the installed packages and their installation options. Ignored updates and skipped versions will also be saved.": "La sauvegarde inclura la liste complète des paquets installés, ainsi que leurs options d'installation. Les mises à jour et versions ignorées seront également sauvegardées.", + "The backup will NOT include any binary file nor any program's saved data.": "La sauvegarde n'inclura PAS de fichier binaire ni de données sauvegardées par un programme.", + "The size of the backup is estimated to be less than 1MB.": "La taille de la sauvegarde est estimée à moins de 1 Mo.", + "The backup will be performed after login.": "La sauvegarde sera exécutée après la connexion.", + "{pcName} installed packages": "Paquets installés sur {pcName}", + "Current status: Not logged in": "Statut actuel : Non connecté", + "You are logged in as {0} (@{1})": "Vous êtes connecté en tant que {0} (@{1})", + "Nice! Backups will be uploaded to a private gist on your account": "Super ! Les sauvegardes seront téléchargées dans un Gist privé de votre compte.", + "Select backup": "Sélectionner la sauvegarde", + "Settings imported from {0}": "Paramètres importés depuis {0}", + "UniGetUI Settings": "Paramètres d'UniGetUI", + "Settings exported to {0}": "Paramètres exportés vers {0}", + "UniGetUI settings were reset": "Les paramètres de UniGetUI ont été réinitialisés", + "Allow pre-release versions": "Autoriser les pré-versions", + "Apply": "Appliquer", + "For security reasons, custom command-line arguments are disabled by default. Go to UniGetUI security settings to change this.": "Pour des raisons de sécurité, les arguments de ligne de commande personnalisés sont désactivés par défaut. Accédez aux paramètres de sécurité d'UniGetUI pour modifier cela.", + "Go to UniGetUI security settings": "Aller dans les paramètres de sécurité d'UniGetUI", + "The following options will be applied by default each time a {0} package is installed, upgraded or uninstalled.": "Les options suivantes seront appliquées par défaut chaque fois qu'un paquet {0} est installé, mis à niveau ou désinstallé.", + "Package's default": "Valeur par défaut du paquet", + "Install location can't be changed for {0} packages": "L'emplacement d'installation ne peut pas être modifié pour {0} paquets", + "The local icon cache currently takes {0} MB": "Le cache des icônes occupe actuellement {0} Mo", + "Username": "Nom d'utilisateur", + "Password": "Mot de passe", + "Credentials": "Informations d'identification", + "It is not guaranteed that the provided credentials will be stored safely": "Il n'est pas garanti que les identifiants fournis seront stockés de manière sécurisée", + "Partially": "Partiellement", + "Package manager": "Gestionnaire de paquets", + "Compatible with proxy": "Compatible avec le proxy", + "Compatible with authentication": "Compatible avec l'authentification", + "Proxy compatibility table": "Tableau de compatibilité des proxys", + "{0} settings": "Réglages de {0}", + "{0} status": "Statut de {0} ", + "Default installation options for {0} packages": "Options d'installation par défaut pour {0} paquets", + "Expand version": "Afficher la version", + "The executable file for {0} was not found": "Le fichier exécutable de {0} n'a pas été trouvé", + "{pm} is disabled": "{pm} est désactivé", + "Enable it to install packages from {pm}.": "Activer ceci pour installer les paquets depuis {pm}.", + "{pm} is enabled and ready to go": "{pm} est activé et prêt à être utilisé", + "{pm} version:": "Version de {pm} :", + "{pm} was not found!": "{pm} n'a pas été trouvé !", + "You may need to install {pm} in order to use it with UniGetUI.": "Il est possible que vous ayez besoin d'installer {pm} pour pouvoir l'utiliser avec UniGetUI.", + "Scoop Installer - UniGetUI": "Installateur de Scoop - UniGetUI", + "Scoop Uninstaller - UniGetUI": "Déinstallateur de Scoop - UniGetUI", + "Clearing Scoop cache - UniGetUI": "Vidage du cache de Scoop - UniGetUI", + "Restart UniGetUI to fully apply changes": "Redémarrer UniGetUI pour appliquer entièrement les modifications", + "Restart UniGetUI": "Redémarrer UniGetUI", + "Manage {0} sources": "Gérer les sources {0}", + "Add source": "Ajouter une source", + "Add": "Ajouter", + "Source name": "Nom de la source", + "Source URL": "URL de la source", + "Other": "Autre", + "No minimum age": "Aucun âge minimum", + "1 day": "1 jour", + "{0} days": "{0} jours", + "Custom...": "Personnalisé...", + "{0} minutes": "{0} minutes", + "1 hour": "1 heure", + "{0} hours": "{0} heures", + "1 week": "1 semaine", + "Supports release dates": "Prend en charge les dates de publication", + "Release date support per package manager": "Prise en charge des dates de publication par gestionnaire de paquets", + "Search for packages": "Rechercher des paquets", + "Local": "Local", + "OK": "OK", + "Last checked: {0}": "Dernière vérification : {0}", + "{0} packages were found, {1} of which match the specified filters.": "{0} paquets ont été trouvés, {1} d'entre eux correspond·ent aux filtres spécifiés.", + "{0} selected": "{0} sélectionné", + "(Last checked: {0})": "(Dernière vérification : {0})", + "All packages selected": "Tous les paquets sélectionnés", + "Package selection cleared": "Sélection de paquets effacée", + "{0}: {1}": "{0} : {1}", + "More info": "Plus d'informations", + "GitHub account": "Compte GitHub", + "Log in with GitHub to enable cloud package backup.": "Connectez-vous à GitHub pour activer la sauvegarde des paquets dans le cloud.", + "More details": "Plus de détails", + "Log in": "Connexion", + "If you have cloud backup enabled, it will be saved as a GitHub Gist on this account": "Si vous avez activé la sauvegarde dans le cloud, il sera sauvegardé en tant que Gist GitHub sur ce compte.", + "Log out": "Déconnexion", + "About UniGetUI": "À propos d'UniGetUI", + "About": "À propos", + "Third-party licenses": "Licences tiers", + "Contributors": "Contributeurs", + "Translators": "Traducteurs", + "Bundle security report": "Rapport de sécurité du lot", + "The bundle contained restricted content": "Le bundle contenait du contenu restreint", + "UniGetUI – Crash Report": "UniGetUI – Rapport de plantage", + "UniGetUI has crashed": "UniGetUI a planté", + "Help us fix this by sending a crash report to Devolutions. All fields below are optional.": "Aidez-nous à corriger ce problème en envoyant un rapport de plantage à Devolutions. Tous les champs ci-dessous sont facultatifs.", + "Email (optional)": "E-mail (facultatif)", + "your@email.com": "votre@email.com", + "Additional details (optional)": "Détails supplémentaires (facultatif)", + "Describe what you were doing when the crash occurred…": "Décrivez ce que vous faisiez lorsque le plantage s’est produit…", + "Crash report": "Rapport de plantage", + "Don't Send": "Ne pas envoyer", + "Send Report": "Envoyer le rapport", + "Sending…": "Envoi en cours…", + "Unsaved changes": "Modifications non enregistrées", + "You have unsaved changes in the current bundle. Do you want to discard them?": "Vous avez des modifications non enregistrées dans le bundle actuel. Voulez-vous les ignorer ?", + "Discard changes": "Ignorer les modifications", + "Integrity violation": "Violation d’intégrité", + "UniGetUI or some of its components are missing or corrupt. It is strongly recommended to reinstall UniGetUI to adress the situation.": "UniGetUI ou certains de ses composants sont manquants ou corrompus. Il est fortement recommandé de réinstaller UniGetUI pour remédier à la situation.", + "• Refer to the UniGetUI Logs to get more details regarding the affected file(s)": "• Consultez les journaux UniGetUI pour obtenir plus de détails sur les fichiers concernés.", + "• Integrity checks can be disabled from the Experimental Settings": "• Les contrôles d'intégrité peuvent être désactivés à partir des paramètres expérimentaux", + "Manage shortcuts": "Gérer les raccourcis", + "UniGetUI has detected the following desktop shortcuts which can be removed automatically on future upgrades": "UniGetUI a détecté les raccourcis sur le bureau suivants qui peuvent être supprimés automatiquement lors de futures mises à jours", + "Do you really want to reset this list? This action cannot be reverted.": "Voulez-vous vraiment réinitialiser cette liste ? Cette action ne peut pas être annulée.", + "Desktop shortcuts list": "Liste des raccourcis du bureau", + "Open in explorer": "Ouvrir dans l'Explorateur", + "Remove from list": "Supprimer de la liste", + "When new shortcuts are detected, delete them automatically instead of showing this dialog.": "Lorsque de nouveaux raccourcis sont détectés, supprimez-les automatiquement au lieu d'afficher cette boîte de dialogue.", + "Not right now": "Pas maintenant", + "Missing dependency": "Dépendance manquante", + "UniGetUI requires {0} to operate, but it was not found on your system.": "UniGetUI à besoin de {0} pour fonctionner, mais il n'a pas été trouvé sur votre système.", + "Click on Install to begin the installation process. If you skip the installation, UniGetUI may not work as expected.": "Cliquez sur Installer pour commencer le processus d'installation. Si vous passez l'installation, UniGetUI risque de ne pas fonctionner comme prévu.", + "Alternatively, you can also install {0} by running the following command in a Windows PowerShell prompt:": "Autrement, vous pouvez également installer {0} en exécutant la commande suivante dans une invite Windows PowerShell :", + "Install {0}": "Installer {0}", + "Do not show this dialog again for {0}": "Ne plus afficher cette boîte de dialogue pour {0}", + "Please wait while {0} is being installed. A black window may show up. Please wait until it closes.": "Veuillez patienter pendant l'installation de {0}. Une fenêtre noire peut s'afficher. Veuillez patienter jusqu'à ce qu'elle se ferme.", + "{0} has been installed successfully.": "{0} a été installé avec succès", + "Please click on \"Continue\" to continue": "Veuillez cliquer sur \"Continuer\" pour continuer", + "Continue": "Continuer", + "{0} has been installed successfully. It is recommended to restart UniGetUI to finish the installation": "{0} a été installé avec succès. Il est recommandé de redémarrer UniGetUI pour terminer l'installation.", + "Restart later": "Redémarrer plus tard", + "An error occurred:": "Une erreur s'est produite :", + "Please see the Command-line Output or refer to the Operation History for further information about the issue.": "Consultez la sortie de la ligne de commande ou référez-vous à l'historique des opérations pour plus d'informations sur le problème.", + "Retry as administrator": "Réessayer en tant qu'administrateur", + "Retry interactively": "Réessayer de manière interactive", + "Retry skipping integrity checks": "Réessayer en ignorant les contrôles d'intégrité", + "Installation options": "Options d'installation", + "Save": "Enregistrer", + "UniGetUI collects anonymous usage data with the sole purpose of understanding and improving the user experience.": "UniGetUI recueille des données d'utilisation anonymes dans le seul but de comprendre et d'améliorer l'expérience utilisateur.", + "More details about the shared data and how it will be processed": "Plus de détails sur les données partagées et la manière dont elles seront traitées", + "Do you accept that UniGetUI collects and sends anonymous usage statistics, with the sole purpose of understanding and improving the user experience?": "Acceptez-vous que UniGetUI recueille et envoie des statistiques d'utilisation anonymes, dans le seul but de comprendre et d'améliorer l'expérience utilisateur ?", + "Decline": "Refuser", + "No personal information is collected nor sent, and the collected data is anonimized, so it can't be back-tracked to you.": "Aucune information personnelle n'est collectée ni envoyée, et les données collectées sont anonymisées, de sorte qu'il est impossible de remonter jusqu'à vous.", + "Navigation panel": "Panneau de navigation", + "Operations": "Opérations", + "Toggle operations panel": "Afficher/masquer le panneau des opérations", + "Bulk operations": "Opérations par lot", + "Retry failed": "Réessayer les échecs", + "Clear successful": "Effacer les opérations réussies", + "Clear finished": "Effacer les opérations terminées", + "Cancel all": "Tout annuler", + "More": "Plus", + "Toggle navigation panel": "Afficher/masquer le panneau de navigation", + "Minimize": "Réduire", + "Maximize": "Agrandir", + "UniGetUI by Devolutions": "UniGetUI par Devolutions", + "UniGetUI is an application that makes managing your software easier, by providing an all-in-one graphical interface for your command-line package managers.": "UniGetUI est une application qui vous permet de gérer vos logiciels plus facilement, en fournissant une interface graphique tout-en-un pour vos gestionnaires de paquets en ligne de commandes.", + "Useful links": "Liens utiles", + "UniGetUI Homepage": "Page d'accueil d'UniGetUI", + "Report an issue or submit a feature request": "Signaler un problème ou soumettre une demande de fonctionnalité", + "UniGetUI Repository": "Dépôt d'UniGetUI", + "View GitHub Profile": "Voir le profil GitHub", + "UniGetUI License": "Licence de UniGetUI", + "Using UniGetUI implies the acceptation of the MIT License": "Utiliser UniGetUI implique l'acceptation de la licence MIT (MIT License)", + "Become a translator": "Devenir un traducteur", + "Go back": "Retour", + "Go forward": "Avancer", + "Go to home page": "Aller à la page d’accueil", + "Reload page": "Recharger la page", + "View page on browser": "Voir la page dans le navigateur", + "The built-in browser is not supported on Linux yet.": "Le navigateur intégré n’est pas encore pris en charge sous Linux.", + "Open in browser": "Ouvrir dans le navigateur", + "Copy to clipboard": "Copier dans le presse-papiers", + "Export to a file": "Exporter dans un fichier", + "Log level:": "Niveau de journalisation :", + "Reload log": "Recharger les journaux", + "Export log": "Exporter le journal", + "Text": "Texte", + "Change how operations request administrator rights": "Modifier la façon dont les opérations demandent des droits d'administrateur", + "Restrictions on package operations": "Restrictions sur les opérations sur les paquets", + "Restrictions on package managers": "Restrictions sur les gestionnaires de paquets", + "Restrictions when importing package bundles": "Restrictions lors de l'importation de lots de paquets", + "Ask for administrator privileges once for each batch of operations": "Demander les privilèges d'administrateur une seule fois pour chaque lot d'opérations", + "Ask only once for administrator privileges": "Ne demander qu'une seule fois les privilèges d'administrateur", + "Prohibit any kind of Elevation via UniGetUI Elevator or GSudo": "Interdire toute forme d'élévation via UniGetUI Elevator ou GSudo", + "This option WILL cause issues. Any operation incapable of elevating itself WILL FAIL. Install/update/uninstall as administrator will NOT WORK.": "Cette option ENTRAINERA des problèmes. Toute opération incapable de s'élever elle-même échouera. L'installation/mise à jour/désinstallation en tant qu'administrateur NE FONCTIONNE PAS.", + "Allow custom command-line arguments": "Autoriser les arguments de ligne de commande personnalisés", + "Custom command-line arguments can change the way in which programs are installed, upgraded or uninstalled, in a way UniGetUI cannot control. Using custom command-lines can break packages. Proceed with caution.": "Les arguments de ligne de commande personnalisés peuvent modifier la manière dont les programmes sont installés, mis à jour ou désinstallés, d'une manière qu'UniGetUI ne peut pas contrôler. Leur utilisation peut endommager les paquets. Soyez prudent.", + "Ignore custom pre-install and post-install commands when importing packages from a bundle": "Autoriser l'exécution de commandes personnalisées avant et après l'installation", + "Pre and post install commands will be run before and after a package gets installed, upgraded or uninstalled. Be aware that they may break things unless used carefully": "Les commandes de pré-installation et de post-installation seront exécutées avant et après l'installation, la mise à niveau ou la désinstallation d'un paquet. Attention : elles peuvent endommager des éléments si elles ne sont pas utilisées avec précaution.", + "Allow changing the paths for package manager executables": "Permettre de modifier les chemins d'accès aux exécutables du gestionnaire de paquets", + "Turning this on enables changing the executable file used to interact with package managers. While this allows finer-grained customization of your install processes, it may also be dangerous": "Activer cette option permet de modifier le fichier exécutable utilisé pour interagir avec les gestionnaires de paquets. Bien que cela permette une personnalisation plus fine de vos processus d'installation, cela peut également s'avérer dangereux", + "Allow importing custom command-line arguments when importing packages from a bundle": "Autoriser l'importation d'arguments de ligne de commande personnalisés lors de l'importation de packages à partir d'un bundle", + "Malformed command-line arguments can break packages, or even allow a malicious actor to gain privileged execution. Therefore, importing custom command-line arguments is disabled by default": "Des arguments de ligne de commande mal formés peuvent endommager les paquets, voire permettre à un acteur malveillant d'obtenir une exécution privilégiée. Par conséquent, l'importation d'arguments de ligne de commande personnalisés est désactivée par défaut.", + "Allow importing custom pre-install and post-install commands when importing packages from a bundle": "Permettre l'importation de commandes de pré-installation et de post-installation personnalisées lors de l'importation de paquets par lot", + "Pre and post install commands can do very nasty things to your device, if designed to do so. It can be very dangerous to import the commands from a bundle, unless you trust the source of that package bundle": "Les commandes pré et post-installation peuvent avoir des conséquences néfastes sur votre appareil, si elles sont conçues pour cela. Importer les commandes d'un bundle peut être très dangereux, sauf si vous faites confiance à la source de ce bundle.", + "Administrator rights and other dangerous settings": "Droits d'administrateur et autres paramètres dangereux", + "Package backup": "Sauvegarde du paquet", + "Cloud package backup": "Sauvegarde des paquets dans le cloud", + "Local package backup": "Sauvegarde locale des paquets", + "Local backup advanced options": "Options avancées de la sauvegarde locale", + "Log in with GitHub": "Se connecter avec GitHub", + "Log out from GitHub": "Se déconnecter de GitHub", + "Periodically perform a cloud backup of the installed packages": "Effectuer périodiquement une sauvegarde dans le cloud des paquets installés", + "Cloud backup uses a private GitHub Gist to store a list of installed packages": "La sauvegarde dans le cloud utilise une Gist GitHub privée pour stocker la liste des paquets installés.", + "Perform a cloud backup now": "Effectuer une sauvegarde dans le cloud maintenant", + "Backup": "Sauvegarder", + "Restore a backup from the cloud": "Restaurer une sauvegarde à partir du cloud", + "Begin the process to select a cloud backup and review which packages to restore": "Commencer le processus de sélection d'une sauvegarde dans le cloud et examiner les paquets à restaurer.", + "Periodically perform a local backup of the installed packages": "Effectuer une sauvegarde locale périodique des paquets installés.", + "Perform a local backup now": "Effectuer une sauvegarde locale maintenant", + "Change backup output directory": "Modifier le répertoire de la sauvegarde", + "Set a custom backup file name": "Définir un nom de fichier de sauvegarde personnalisé", + "Leave empty for default": "Laisser vide pour utiliser la valeur par défaut", + "Add a timestamp to the backup file names": "Ajouter un horodatage aux noms des fichiers de sauvegarde", + "Backup and Restore": "Sauvegarde et restauration", + "Enable background api (UniGetUI Widgets and Sharing, port 7058)": "Activer l'API en arrière-plan (Widgets et Partage UniGetUI, port 7058) ", + "Wait for the device to be connected to the internet before attempting to do tasks that require internet connectivity.": "Attendez que l'appareil soit connecté à Internet avant d'effectuer des tâches nécessitant une connexion à Internet", + "Disable the 1-minute timeout for package-related operations": "Désactiver le délai d'attente de 1 minute pour les opérations liées aux paquets", + "Use installed GSudo instead of UniGetUI Elevator": "Utiliser GSudo (si installé) à la place du UniGetUI Elevator", + "Use a custom icon and screenshot database URL": "Utiliser une base de données d'icônes et de captures d'écran personnalisées", + "Enable background CPU Usage optimizations (see Pull Request #3278)": "Activation des optimisations de l'utilisation du CPU en arrière-plan (voir Pull Request #3278)", + "Perform integrity checks at startup": "Effectuer des contrôles d'intégrité au démarrage", + "When batch installing packages from a bundle, install also packages that are already installed": "Lors de l'installation de paquets par lot, réinstaller les paquets déjà installés", + "Experimental settings and developer options": "Paramètres expérimentaux et options pour les développeurs", + "Show UniGetUI's version and build number on the titlebar.": "Afficher la version d'UniGetUI dans la barre de titre", + "Language": "Langue", + "UniGetUI updater": "Mise à jour d'UniGetUI", + "Telemetry": "Télémétrie", + "Manage UniGetUI settings": "Gérer les paramètres d'UniGetUI", + "Related settings": "Paramètres associés", + "Update UniGetUI automatically": "Mettre à jour UniGetUI automatiquement", + "Check for updates": "Vérifier les mises à jour", + "Install prerelease versions of UniGetUI": "Installer les préversions d'UniGetUI", + "Manage telemetry settings": "Gérer les paramètres de télémétrie", + "Manage": "Gérer", + "Import settings from a local file": "Importer les paramètres depuis un fichier local", + "Import": "Importer", + "Export settings to a local file": "Exporter les paramètres dans un fichier local", + "Export": "Exporter", + "Reset UniGetUI": "Réinitialiser UniGetUI", + "User interface preferences": "Paramètres de l'interface utilisateur", + "Application theme, startup page, package icons, clear successful installs automatically": "Thème de l'application, page de démarrage, icônes des paquets, nettoyage automatique des installations réussies", + "General preferences": "Paramètres généraux", + "UniGetUI display language:": "Langue d'affichage de UniGetUI :", + "System language": "Langue du système", + "Is your language missing or incomplete?": "Votre langue est-elle manquante ou incomplète ?", + "Appearance": "Apparence", + "UniGetUI on the background and system tray": "UniGetUI en arrière-plan et dans la barre des tâches", + "Package lists": "Listes de paquets", + "Use classic mode": "Utiliser le mode classique", + "Restart UniGetUI to apply this change": "Redémarrez UniGetUI pour appliquer cette modification", + "The classic UI is disabled for beta testers": "L’interface classique est désactivée pour les testeurs bêta", + "Close UniGetUI to the system tray": "Fermer UniGetUI dans la barre d'état système", + "Manage UniGetUI autostart behaviour": "Gérer le comportement du démarrage automatique d'UniGetUI", + "Show package icons on package lists": "Afficher les icônes des paquets dans la liste des paquets", + "Clear cache": "Vider le cache", + "Select upgradable packages by default": "Sélectionner les paquets à mettre à jour par défaut", + "Light": "Clair", + "Dark": "Sombre", + "Follow system color scheme": "Synchroniser avec le thème du système", + "Application theme:": "Thème de l'application :", + "UniGetUI startup page:": "Page de démarrage d'UniGetUI :", + "Proxy settings": "Paramètres du proxy", + "Other settings": "Autres paramètres", + "Connect the internet using a custom proxy": "Se connecter à Internet à l'aide d'un proxy personnalisé", + "Please note that not all package managers may fully support this feature": "Veuillez noter que tous les gestionnaires de paquets ne prennent pas toujours en charge cette fonctionnalité", + "Proxy URL": "URL du proxy", + "Enter proxy URL here": "Entrez l'URL du proxy ici", + "Authenticate to the proxy with a user and a password": "S'authentifier auprès du proxy avec un nom d'utilisateur et un mot de passe", + "Internet and proxy settings": "Paramètres Internet et du proxy", + "Package manager preferences": "Gestionnaires de paquets", + "Ready": "Prêt", + "Not found": "Non trouvé", + "Notification preferences": "Préférences de notification", + "Notification types": "Types de notification", + "The system tray icon must be enabled in order for notifications to work": "L'icône de la barre d'état système doit être activée pour que les notifications fonctionnent", + "Enable UniGetUI notifications": "Activer les notifications de UniGetUI", + "Show a notification when there are available updates": "Afficher une notification quand des mises à jour sont disponibles", + "Show a silent notification when an operation is running": "Afficher une notification silencieuse lorsqu'une opération est en cours", + "Show a notification when an operation fails": "Afficher une notification lorsqu'une opération échoue", + "Show a notification when an operation finishes successfully": "Afficher une notification lorsqu'une opération se termine avec succès", + "Concurrency and execution": "Concurrence et exécution", + "Automatic desktop shortcut remover": "Suppression automatique des raccourcis sur le bureau", + "Choose how many operations should be performed in parallel": "Choisir le nombre d'opérations à effectuer en parallèle", + "Clear successful operations from the operation list after a 5 second delay": "Effacer les opérations réussies de la liste des opérations après un délai de 5 secondes", + "Download operations are not affected by this setting": "Les opérations de téléchargement ne sont pas affectées par ce paramètre", + "You may lose unsaved data": "Vous risquez de perdre des données non enregistrées", + "Ask to delete desktop shortcuts created during an install or upgrade.": "Demander la suppression des raccourcis sur le bureau créés lors d'une installation ou d'une mise à jour", + "Package update preferences": "Préférences de mise à jour des paquets", + "Update check frequency, automatically install updates, etc.": "Fréquence de vérification des mises à jour, installation automatique des mises à jour, etc.", + "Reduce UAC prompts, elevate installations by default, unlock certain dangerous features, etc.": "Réduire les invites UAC, élever les installations par défaut, déverrouiller certaines fonctionnalités dangereuses, etc.", + "Package operation preferences": "Préférences de fonctionnement des paquets", + "Enable {pm}": "Activer {pm}", + "Not finding the file you are looking for? Make sure it has been added to path.": "Vous ne trouvez pas le fichier que vous cherchez ? Assurez-vous qu'il a été ajouté au chemin d'accès.", + "Select the executable to be used. The following list shows the executables found by UniGetUI": "Sélectionnez l'exécutable à utiliser. La liste suivante répertorie les exécutables trouvés par UniGetUI", + "For security reasons, changing the executable file is disabled by default": "Pour des raisons de sécurité, la modification du fichier exécutable est désactivée par défaut.", + "Change this": "Modifier ceci", + "Copy path": "Copier le chemin", + "Current executable file:": "Fichier exécutable actuel :", + "Ignore packages from {pm} when showing a notification about updates": "Ignorer les paquets de {pm} lors de l'affichage d'une notification de mise à jour", + "Update security": "Sécurité des mises à jour", + "Use global setting": "Utiliser le paramètre global", + "Minimum age for updates": "Âge minimum des mises à jour", + "e.g. 10": "p. ex. 10", + "Custom minimum age (days)": "Âge minimum personnalisé (jours)", + "{pm} does not provide release dates for its packages, so this setting will have no effect": "{pm} ne fournit pas de dates de publication pour ses paquets, cette option n'aura donc aucun effet", + "{pm} only provides release dates for some of its packages, so this setting will only apply to those packages": "{pm} ne fournit des dates de publication que pour certains de ses paquets, cette option ne s'appliquera donc qu'à ces paquets", + "Override the global minimum update age for this package manager": "Remplacer l'âge minimum global des mises à jour pour ce gestionnaire de paquets", + "View {0} logs": "Voir les journaux de {0}", + "If Python cannot be found or is not listing packages but is installed on the system, ": "Si Python est introuvable ou n'affiche pas les paquets alors qu'il est installé sur le système, ", + "Advanced options": "Options avancées", + "WinGet command-line tool": "Outil en ligne de commande WinGet", + "Choose which command-line tool UniGetUI uses for WinGet operations when the COM API is not used": "Choisissez l’outil en ligne de commande qu’UniGetUI utilise pour les opérations WinGet lorsque l’API COM n’est pas utilisée", + "WinGet COM API": "API COM de WinGet", + "Choose whether UniGetUI can use the WinGet COM API before falling back to the command-line tool": "Choisissez si UniGetUI peut utiliser l’API COM de WinGet avant de revenir à l’outil en ligne de commande", + "Reset WinGet": "Réinitialiser WinGet", + "This may help if no packages are listed": "ceci peut aider si aucun paquet n'est listé", + "Force install location parameter when updating packages with custom locations": "Forcer le paramètre d'emplacement d'installation lors de la mise à jour des packages avec des emplacements personnalisés", + "Install Scoop": "Installer Scoop", + "Uninstall Scoop (and its packages)": "Désinstaller Scoop (et ses paquets)", + "Run cleanup and clear cache": "Exécuter un nettoyage et vider le cache", + "Run": "Exécuter", + "Enable Scoop cleanup on launch": "Activer le nettoyage de Scoop au démarrage", + "Default vcpkg triplet": "Triplet vcpkg par défaut", + "Change vcpkg root location": "Modifier l'emplacement racine de vcpkg", + "Reset vcpkg root location": "Réinitialiser l’emplacement racine de vcpkg", + "Open vcpkg root location": "Ouvrir l’emplacement racine de vcpkg", + "Language, theme and other miscellaneous preferences": "Langue, thème et autres préférences diverses", + "Show notifications on different events": "Afficher des notifications sur différents événements", + "Change how UniGetUI checks and installs available updates for your packages": "Modifier comment UniGetUI vérifie et installe les mises à jour disponibles pour vos paquets", + "Automatically save a list of all your installed packages to easily restore them.": "Enregistrer automatiquement une liste de tous les paquets installés pour les restaurer facilement", + "Enable and disable package managers, change default install options, etc.": "Activer et désactiver les gestionnaires de paquets, modifier les options d'installation par défaut, etc.", + "Internet connection settings": "Paramètres de connexion Internet", + "Proxy settings, etc.": "Paramètres du proxy, etc.", + "Beta features and other options that shouldn't be touched": "Fonctionnalités bêta et autres options qui ne devraient pas être modifiées", + "Reload sources": "Recharger les sources", + "Delete source": "Supprimer la source", + "Known sources": "Sources connues", + "Update checking": "Vérification des mises à jour", + "Automatic updates": "Mises à jour automatiques", + "Check for package updates periodically": "Vérifier les mises à jour des paquets périodiquement", + "Check for updates every:": "Vérifier les mises à jour toutes les :", + "Install available updates automatically": "Installer automatiquement les mises à jour disponibles", + "Do not automatically install updates when the network connection is metered": "Ne pas installer automatiquement les mises à jour lorsque la connexion réseau est mesurée", + "Do not automatically install updates when the device runs on battery": "Ne pas installer automatiquement les mises à jour lorsque l'appareil fonctionne sur batterie", + "Do not automatically install updates when the battery saver is on": "Ne pas installer automatiquement les mises à jour lorsque l'économiseur de batterie est activé", + "Only show updates that are at least the specified number of days old": "Afficher uniquement les mises à jour âgées d'au moins le nombre de jours indiqué", + "Warn me when the installer URL host changes between the installed version and the new version (WinGet only)": "M'avertir lorsque l'hôte de l'URL de l'installateur change entre la version installée et la nouvelle version (WinGet uniquement)", + "Change how UniGetUI handles install, update and uninstall operations.": "Modifier la façon dont UniGetUI gère les opérations d'installation, de mise à jour et de désinstallation.", + "Navigation": "Navigation", + "Check for UniGetUI updates": "Rechercher des mises à jour d'UniGetUI", + "Quit UniGetUI": "Quitter UniGetUI", + "Filters": "Filtres", + "Sources": "Sources", + "Search for packages to start": "Rechercher des paquets pour démarrer", + "Select all": "Tout sélectionner", + "Clear selection": "Effacer la sélection", + "Instant search": "Recherche instantanée", + "Distinguish between uppercase and lowercase": "Faire la distinction entre les majuscules et les minuscules", + "Ignore special characters": "Ignorer les caractères spéciaux", + "Search mode": "Mode de recherche", + "Both": "Les deux", + "Exact match": "Correspondance exacte", + "Show similar packages": "Afficher des paquets similaires", + "Loading": "Chargement", + "Package": "Paquet", + "More options": "Plus d’options", + "Order by:": "Trier par :", + "Name": "Nom", + "Id": "ID", + "Ascendant": "Ascendant", + "Descendant": "Descendant", + "View modes": "Modes d’affichage", + "Reload": "Recharger", + "Closed": "Fermé", + "Ascending": "Ascendant", + "Descending": "Descendant", + "{0}: {1}, {2}": "{0} : {1}, {2}", + "Order by": "Trier par", + "No results were found matching the input criteria": "Aucun résultat correspondant aux critères n'a été trouvé", + "No packages were found": "Aucun paquet n'a été trouvé", + "Loading packages": "Chargement des paquets", + "Skip integrity checks": "Passer les vérifications d'intégrité", + "Download selected installers": "Télécharger les installeurs sélectionnés", + "Install selection": "Installer la sélection", + "Install options": "Options d'installation", + "Add selection to bundle": "Ajouter la sélection à un lot", + "Download installer": "Télécharger l'installateur", + "Uninstall selection": "Désinstaller la sélection", + "Uninstall options": "Options de désinstallation", + "Ignore selected packages": "Ignorer les paquets sélectionnés", + "Open install location": "Ouvrir l'emplacement d'installation", + "Reinstall package": "Réinstaller le paquet", + "Uninstall package, then reinstall it": "Désinstaller le paquet, puis le réinstaller", + "Ignore updates for this package": "Ignorer les mises à jour pour ce paquet", + "WinGet malfunction detected": "Dysfonctionnement de WinGet détecté", + "It looks like WinGet is not working properly. Do you want to attempt to repair WinGet?": "Il semblerait que WinGet ne fonctionne pas correctement. Voulez-vous essayer de réparer WinGet ?", + "Repair WinGet": "Réparer WinGet", + "Updates will no longer be ignored for {0}": "Les mises à jour ne seront plus ignorées pour {0}", + "Updates are now ignored for {0}": "Les mises à jour sont désormais ignorées pour {0}", + "Do not ignore updates for this package anymore": "Ne plus ignorer les mises à jour de ce paquet", + "Add packages or open an existing package bundle": "Ajouter des paquets ou ouvrir un lot de paquets existant", + "Add packages to start": "Ajouter des paquets pour commencer", + "The current bundle has no packages. Add some packages to get started": "Le lot actuel ne contient aucun paquet. Ajoutez quelques paquets pour commencer", + "New": "Nouveau", + "Save as": "Enregistrer sous", + "Create .ps1 script": "Créer un script .ps1", + "Remove selection from bundle": "Retirer la sélection du lot", + "Skip hash checks": "Passer les vérifications du hachage", + "The package bundle is not valid": "Le lot de paquets n'est pas valide", + "The bundle you are trying to load appears to be invalid. Please check the file and try again.": "Le lot que vous essayez de charger semble être invalide. Veuillez vérifier le fichier et réessayer.", + "Package bundle": "Lot de paquets", + "Could not create bundle": "Impossible de créer un lot", + "The package bundle could not be created due to an error.": "Le lot de paquets n'a pas pu être créé en raison d'une erreur", + "Install script": "Script d'installation", + "PowerShell script": "Script PowerShell", + "The installation script saved to {0}": "Le script d'installation enregistré dans {0}", + "An error occurred": "Une erreur s'est produite", + "An error occurred while attempting to create an installation script:": "Une erreur s'est produite lors de la création d'un script d'installation :", + "Hooray! No updates were found.": "Félicitations ! Toutes vos applications sont à jour !", + "Uninstall selected packages": "Désinstaller les paquets sélectionnés", + "Update selection": "Mettre à jour la sélection", + "Update options": "Options de mise à jour", + "Uninstall package, then update it": "Désinstaller le paquet, puis le mettre à jour", + "Uninstall package": "Désinstaller le paquet", + "Skip this version": "Ignorer cette version", + "Pause updates for": "Suspendre les mises à jour pour", + "User | Local": "Utilisateur | Local", + "Machine | Global": "Machine | Global", + "The default package manager for Debian/Ubuntu-based Linux distributions.
Contains: Debian/Ubuntu packages": "Le gestionnaire de paquets par défaut pour les distributions Linux basées sur Debian/Ubuntu.
Contient : Paquets Debian/Ubuntu", + "The Rust package manager.
Contains: Rust libraries and programs written in Rust": "Le gestionnaire de paquets de Rust.
Contient : Bibliothèques Rust et programmes écrits en Rust", + "The classical package manager for windows. You'll find everything there.
Contains: General Software": "Le gestionnaire de paquets classique pour Windows. Vous y trouverez tout.
Contient : Logiciels généraux", + "The default package manager for RHEL/Fedora-based Linux distributions.
Contains: RPM packages": "Le gestionnaire de paquets par défaut pour les distributions Linux basées sur RHEL/Fedora.
Contient : Paquets RPM", + "A repository full of tools and executables designed with Microsoft's .NET ecosystem in mind.
Contains: .NET related tools and scripts": "Un dépôt plein d'outils et d'exécutables conçus pour l'écosystème Microsoft .NET.
Contient : Outils et scripts liés à .NET", + "The universal Linux package manager for desktop applications.
Contains: Flatpak applications from configured remotes": "Le gestionnaire de paquets Linux universel pour les applications de bureau.
Contient : Applications Flatpak provenant des dépôts distants configurés", + "NuPkg (zipped manifest)": "NuPkg (manifeste compressé)", + "The Missing Package Manager for macOS (or Linux).
Contains: Formulae, Casks": "Le gestionnaire de paquets manquant pour macOS (ou Linux).
Contient : Formulae, Casks", + "Node JS's package manager. Full of libraries and other utilities that orbit the javascript world
Contains: Node javascript libraries and other related utilities": "Le gestionnaire de paquets de Node JS. Plein de bibliothèques et d'autres utilitaires qui tournent autour du monde de JavaScript.
Contient : Bibliothèques JavaScript Node et autres utilitaires associés", + "The default package manager for Arch Linux and its derivatives.
Contains: Arch Linux packages": "Le gestionnaire de paquets par défaut pour Arch Linux et ses dérivés.
Contient : Paquets Arch Linux", + "Python's library manager. Full of python libraries and other python-related utilities
Contains: Python libraries and related utilities": "Le gestionnaire de bibliothèques de Python. Plein de bibliothèques Python et d'autres utilitaires liés à Python.
Contient : Bibliothèques Python et autres utilitaires associés", + "PowerShell's package manager. Find libraries and scripts to expand PowerShell capabilities
Contains: Modules, Scripts, Cmdlets": "Le gestionnaire de paquets de PowerShell. Bibliothèques et scripts pour étendre les capacités de PowerShell.
Contient : Modules, Scripts, Cmdlets", + "extracted": "extrait", + "Scoop package": "Paquet Scoop", + "Great repository of unknown but useful utilities and other interesting packages.
Contains: Utilities, Command-line programs, General Software (extras bucket required)": "Excellent dépôt d'utilitaires peu connus mais utiles et d'autres paquets intéressants.
Contient : Utilitaires, Programmes en ligne de commande, Logiciels généraux (bucket extras requis)", + "The universal Linux package manager by Canonical.
Contains: Snap packages from the Snapcraft store": "Le gestionnaire de paquets universel pour Linux par Canonical.
Contient : Paquets Snap du Snapcraft store", + "library": "bibliothèque", + "feature": "fonctionnalité", + "A popular C/C++ library manager. Full of C/C++ libraries and other C/C++-related utilities
Contains: C/C++ libraries and related utilities": "Un gestionnaire populaire de bibliothèques C/C++. Plein de bibliothèques C/C++ et d'autres utilitaires liés à C/C++.
Contient : Bibliothèques C/C++ et utilitaires liés", + "option": "option", + "This package cannot be installed from an elevated context.": "Ce paquet ne peut pas être installé avec une élévation de privilèges d'administrateur.", + "Please run UniGetUI as a regular user and try again.": "Veuillez exécuter UniGetUI en tant qu'utilisateur standard et réessayer.", + "Please check the installation options for this package and try again": "Veuillez vérifier les options d'installation de ce paquet et réessayer", + "Microsoft's official package manager. Full of well-known and verified packages
Contains: General Software, Microsoft Store apps": "Le gestionnaire de paquets officiel de Microsoft. Rempli de paquets bien connus et vérifiés.
Contient : Logiciels généraux, Applications du Microsoft Store.", + "Local PC": "PC local", + "Android Subsystem": "Sous-système Android", + "Operation on queue (position {0})...": "Opération dans la file d'attente (position {0})...", + "Click here for more details": "Cliquez ici pour plus de détails", + "Operation canceled by user": "Opération annulée par l'utilisateur", + "Running PreOperation ({0}/{1})...": "Exécution de PreOperation ({0}/{1})...", + "PreOperation {0} out of {1} failed, and was tagged as necessary. Aborting...": "PreOperation {0} sur {1} a échoué et était marquée comme nécessaire. Abandon...", + "PreOperation {0} out of {1} finished with result {2}": "PreOperation {0} sur {1} s'est terminée avec le résultat {2}", + "Starting operation...": "Démarrage de l'opération...", + "Running PostOperation ({0}/{1})...": "Exécution de PostOperation ({0}/{1})...", + "PostOperation {0} out of {1} failed, and was tagged as necessary. Aborting...": "PostOperation {0} sur {1} a échoué et était marquée comme nécessaire. Abandon...", + "PostOperation {0} out of {1} finished with result {2}": "PostOperation {0} sur {1} s'est terminée avec le résultat {2}", + "{package} installer download": "Téléchargement du programme d'installation de {package}", + "{0} installer is being downloaded": "Le programme d'installation {0} est en cours de téléchargement", + "Download succeeded": "Téléchargement réussi", + "{package} installer was downloaded successfully": "Le programme d'installation de {package} a été téléchargé avec succès", + "Download failed": "Téléchargement échoué", + "{package} installer could not be downloaded": "Le programme d'installation de {package} n'a pas pu être téléchargé", + "{package} Installation": "Installation de {package}", + "{0} is being installed": "{0} est en cours d'installation", + "Installation succeeded": "Installation réussie", + "{package} was installed successfully": "{package} a été installé avec succès", + "Installation failed": "Échec de l'installation", + "{package} could not be installed": "{package} n'a pas pu être installé", + "{package} Update": "Mise à jour de {package}", + "Update succeeded": "Mise à jour réussie", + "{package} was updated successfully": "{package} a été mis à jour avec succès", + "Update failed": "Échec de la mise à jour", + "{package} could not be updated": "{package} n'a pas pu être mis à jour", + "{package} Uninstall": "Désinstallation de {package}", + "{0} is being uninstalled": "{0} est en cours de désinstallation", + "Uninstall succeeded": "Désinstallation réussie", + "{package} was uninstalled successfully": "{package} a été désinstallé avec succès", + "Uninstall failed": "Échec de la désinstallation", + "{package} could not be uninstalled": "{package} n'a pas pu être désinstallé", + "Adding source {source}": "Ajouter la source {source}", + "Adding source {source} to {manager}": "Ajouter la source {source} à {manager}", + "Source added successfully": "Source ajoutée avec succès", + "The source {source} was added to {manager} successfully": "La source {source} a été ajouté à {manager} avec succès", + "Could not add source": "Impossible d'ajouter une source", + "Could not add source {source} to {manager}": "Impossible d'ajouter la source {source} à {manager}", + "Removing source {source}": "Suppression de la source {source}", + "Removing source {source} from {manager}": "Suppression de la source {source} de {manager}", + "Source removed successfully": "Source supprimée avec succès", + "The source {source} was removed from {manager} successfully": "La source {source} a été supprimé de {manager} avec succès", + "Could not remove source": "Impossible de supprimer la source", + "Could not remove source {source} from {manager}": "Impossible de supprimer la source {source} de {manager}", + "The package manager \"{0}\" was not found": "Le gestionnaire de paquets \"{0}\" n'a pas été trouvé", + "The package manager \"{0}\" is disabled": "Le gestionnaire de paquets \"{0}\" est désactivé", + "There is an error with the configuration of the package manager \"{0}\"": "Il y a une erreur avec la configuration du gestionnaire de paquets \"{0}\"", + "The package \"{0}\" was not found on the package manager \"{1}\"": "Le paquet \"{0}\" n'a pas été trouvé dans le gestionnaire de paquets \"{1}\"", + "{0} is disabled": "{0} est désactivé(e)", + "{0} weeks": "{0} semaines", + "1 month": "1 mois", + "{0} months": "{0} mois", + "Something went wrong": "Quelque chose ne s'est pas passé comme prévu", + "An interal error occurred. Please view the log for further details.": "Une erreur interne s'est produite. Veuillez consulter les journaux pour plus de détails.", + "No applicable installer was found for the package {0}": "Aucun programme d'installation applicable n'a été trouvé pour le paquet {0}", + "Integrity checks will not be performed during this operation": "Les contrôles d'intégrité ne seront pas effectués pendant cette opération", + "This is not recommended.": "Ceci n'est pas recommandé.", + "Run now": "Lancer maintenant", + "Run next": "Lancer le prochain", + "Run last": "Lancer le dernier", + "Show in explorer": "Afficher dans l'explorateur", + "Checked": "Coché", + "Unchecked": "Décoché", + "This package is already installed": "Ce paquet est déjà installé", + "This package can be upgraded to version {0}": "Ce paquet peut être mis à jour vers la version {0}", + "Updates for this package are ignored": "Les mises à jour pour ce paquet sont ignorées", + "This package is being processed": "Ce paquet est en cours de traitement", + "This package is not available": "Ce paquet n'est pas disponible", + "Select the source you want to add:": "Sélectionner la source que vous voulez ajouter :", + "Source name:": "Nom de la source :", + "Source URL:": "URL source :", + "An error occurred when adding the source: ": "Une erreur s'est produite lors de l'ajout de la source :", + "Package management made easy": "Gestion des paquets facilitée", + "version {0}": "version {0}", + "[RAN AS ADMINISTRATOR]": "EXÉCUTÉ EN TANT QU'ADMINISTRATEUR", + "Portable mode": "Mode portable\n", + "DEBUG BUILD": "VERSION DE DÉBOGAGE", + "Here you can change UniGetUI's behaviour regarding the following shortcuts. Checking a shortcut will make UniGetUI delete it if if gets created on a future upgrade. Unchecking it will keep the shortcut intact": "Ici vous pouvez changer le comportement d'UniGetUI en ce qui concerne les raccourcis suivants. En cochant un raccourci, UniGetUI le supprimera s'il est créé lors d'une prochaine mise à jour. Si vous ne le cochez pas, cela conservera le raccourci intact.", + "Manual scan": "Analyse manuelle", + "Existing shortcuts on your desktop will be scanned, and you will need to pick which ones to keep and which ones to remove.": "Les raccourcis existants sur votre bureau seront analysés et vous devrez choisir ceux qui doivent être conservés et ceux qui doivent être supprimés.", + "Delete?": "Supprimer ?", + "I understand": "Je comprends", + "Chocolatey setup changed": "La configuration de Chocolatey a changé", + "UniGetUI no longer includes its own private Chocolatey installation. A legacy UniGetUI-managed Chocolatey installation was detected for this user profile, but system Chocolatey was not found. Chocolatey will stay unavailable in UniGetUI until Chocolatey is installed on the system and UniGetUI is restarted. Applications previously installed through UniGetUI's bundled Chocolatey may still appear under other sources such as Local PC or WinGet.": "UniGetUI n’inclut plus sa propre installation privée de Chocolatey. Une ancienne installation de Chocolatey gérée par UniGetUI a été détectée pour ce profil utilisateur, mais Chocolatey n’a pas été trouvé au niveau du système. Chocolatey restera indisponible dans UniGetUI tant que Chocolatey n’est pas installé sur le système et que UniGetUI n’est pas redémarré. Les applications précédemment installées via le Chocolatey intégré à UniGetUI peuvent toujours apparaître sous d’autres sources telles que PC local ou WinGet.", + "NOTE: This troubleshooter can be disabled from UniGetUI Settings, on the WinGet section": "NOTE : Ce programme de dépannage peut être désactivé depuis les paramètres d'UniGetUI, dans la section WinGet", + "Restart": "Redémarrer", + "Are you sure you want to delete all shortcuts?": "Êtes-vous sûr de vouloir supprimer tous les raccourcis ?", + "Any new shorcuts created during an install or an update operation will be deleted automatically, instead of showing a confirmation prompt the first time they are detected.": "Tout nouveau raccourci créé lors d'une installation ou d'une mise à jour sera automatiquement supprimé, au lieu d'afficher une demande de confirmation la première fois qu'il est détecté.", + "Any shorcuts created or modified outside of UniGetUI will be ignored. You will be able to add them via the {0} button.": "Tout raccourci créé ou modifié en dehors d'UniGetUI sera ignoré. Vous pourrez les ajouter via le bouton {0} pour les ajouter.", + "Are you really sure you want to enable this feature?": "Êtes-vous vraiment sûr de vouloir activer cette fonction ?", + "No new shortcuts were found during the scan.": "Aucun nouveau raccourci n'a été trouvé au cours de l'analyse.", + "How to add packages to a bundle": "Comment ajouter des paquets à un lot", + "In order to add packages to a bundle, you will need to: ": "Pour ajouter des paquets à un lot, vous devez : ", + "1. Navigate to the \"{0}\" or \"{1}\" page.": "1. Naviguez jusqu'à la page \"{0}\" ou \"{1}\" .", + "2. Locate the package(s) you want to add to the bundle, and select their leftmost checkbox.": "2. Localisez le(s) paquet(s) que vous souhaitez ajouter au lot et cochez leur case la plus à gauche.", + "3. When the packages you want to add to the bundle are selected, find and click the option \"{0}\" on the toolbar.": "3. Lorsque les paquets que vous souhaitez ajouter au lot sont sélectionnés, recherchez et cliquez sur l'option \"{0}\" dans la barre d'outils.", + "4. Your packages will have been added to the bundle. You can continue adding packages, or export the bundle.": "4. Vos paquets auront été ajoutés au lot. Vous pouvez continuer à ajouter des paquets ou exporter le lot.", + "Which backup do you want to open?": "Quelle sauvegarde voulez-vous ouvrir ?", + "Select the backup you want to open. Later, you will be able to review which packages you want to install.": "Sélectionnez la sauvegarde que vous souhaitez ouvrir. Plus tard, vous pourrez revoir les paquets/programmes que vous souhaitez restaurer.", + "There are ongoing operations. Quitting UniGetUI may cause them to fail. Do you want to continue?": "Il y a des opérations en cours. Quitter UniGetUI pourrait les faire échouer. Voulez-vous continuer ?", + "UniGetUI or some of its components are missing or corrupt.": "UniGetUI ou certains de ses composants sont manquants ou corrompus.", + "It is strongly recommended to reinstall UniGetUI to adress the situation.": "Il est fortement recommandé de réinstaller UniGetUI pour remédier à la situation.", + "Refer to the UniGetUI Logs to get more details regarding the affected file(s)": "Consultez les journaux UniGetUI pour obtenir plus de détails sur les fichiers concernés.", + "Integrity checks can be disabled from the Experimental Settings": "Les contrôles d'intégrité peuvent être désactivés à partir des paramètres expérimentaux", + "Repair UniGetUI": "Réparer UniGetUI", + "Live output": "Sortie en temps réel", + "This package bundle had some settings that are potentially dangerous, and may be ignored by default.": "Ce lot de paquets contient des paramètres potentiellement dangereux qui peuvent être ignorés par défaut.", + "Entries that show in YELLOW will be IGNORED.": "Les entrées qui apparaissent en JAUNE seront IGNORÉES.", + "Entries that show in RED will be IMPORTED.": "Les entrées qui apparaissent en ROUGE seront IMPORTÉES.", + "You can change this behavior on UniGetUI security settings.": "Vous pouvez modifier ce comportement dans les paramètres de sécurité d'UniGetUI.", + "Open UniGetUI security settings": "Ouvrir les paramètres de sécurité d'UniGetUI", + "Should you modify the security settings, you will need to open the bundle again for the changes to take effect.": "Si vous modifiez les paramètres de sécurité, vous devrez ouvrir à nouveau le lot pour que les modifications soient prises en compte.", + "Details of the report:": "Détails du rapport :", + "Are you sure you want to create a new package bundle? ": "Êtes-vous sûr de vouloir créer un nouveau lot de paquets ?", + "Any unsaved changes will be lost": "Toute modification non enregistrée sera perdue", + "Warning!": "Attention !", + "For security reasons, custom command-line arguments are disabled by default. Go to UniGetUI security settings to change this. ": "Pour des raisons de sécurité, les arguments de ligne de commande personnalisés sont désactivés par défaut. Allez dans les paramètres de sécurité d'UniGetUI pour changer cela.", + "Change default options": "Modifier les options par défaut", + "Ignore future updates for this package": "Ignorer les futures mises à jour pour ce paquet", + "For security reasons, pre-operation and post-operation scripts are disabled by default. Go to UniGetUI security settings to change this. ": "Pour des raisons de sécurité, les scripts de pré-opération et de post-opération sont désactivés par défaut. Allez dans les paramètres de sécurité d'UniGetUI pour changer cela.", + "You can define the commands that will be run before or after this package is installed, updated or uninstalled. They will be run on a command prompt, so CMD scripts will work here.": "Vous pouvez définir les commandes qui seront exécutées avant ou après l'installation, la mise à jour ou la désinstallation de ce paquet. Elles seront exécutées dans une invite de commande, de sorte que les scripts CMD fonctionneront ici.", + "Change this and unlock": "Modifier ceci et déverrouiller", + "{0} Install options are currently locked because {0} follows the default install options.": "Les options d'installation de {0} sont actuellement bloquées parce que {0} suit les options d'installation par défaut.", + "Unset or unknown": "Non défini ou inconnu", + "This package has no screenshots or is missing the icon? Contrbute to UniGetUI by adding the missing icons and screenshots to our open, public database.": "Ce paquet n'a pas de capture d'écran ou l'icône est manquante ? Contribuez à UniGetUI en ajoutant les icônes manquantes et les captures d'écran à notre base de données ouverte et publique.", + "Become a contributor": "Devenir un contributeur", + "Update to {0} available": "Mise à jour vers {0} disponible", + "Reinstall": "Réinstaller", + "Installer not available": "L'installateur n'est pas disponible", + "Version:": "Version :", + "UniGetUI Version {0}": "Version {0} d'UniGetUI", + "Performing backup, please wait...": "Sauvegarde en cours, veuillez patienter...", + "An error occurred while logging in: ": "Une erreur s'est produite lors de la connexion :", + "Fetching available backups...": "Recherche des sauvegardes disponibles...", + "Done!": "Terminé !", + "The cloud backup has been loaded successfully.": "La sauvegarde dans le cloud a été chargée avec succès.", + "An error occurred while loading a backup: ": "Une erreur s'est produite lors du chargement d'une sauvegarde :", + "Backing up packages to GitHub Gist...": "Sauvegarde des paquets sur GitHub Gist...", + "Backup Successful": "La sauvegarde a réussi", + "The cloud backup completed successfully.": "La sauvegarde dans le cloud s'est terminée avec succès.", + "Could not back up packages to GitHub Gist: ": "Impossible de sauvegarder les paquets sur GitHub Gist :", + "It is not guaranteed that the provided credentials will be stored safely, so you may as well not use the credentials of your bank account": "Il n'est pas garanti que les informations d'identification fournies seront stockées en toute sécurité. Vous pouvez donc tout aussi bien ne pas utiliser les informations d'identification de votre compte bancaire.", + "Enable the automatic WinGet troubleshooter": "Activer le dépannage automatique de WinGet", + "Add updates that fail with a 'no applicable update found' to the ignored updates list": "Ajouter les mises à jour qui échouent avec un message « aucune mise à jour applicable trouvée » à la liste des mises à jour ignorées.", + "Invalid selection": "Sélection invalide", + "No package was selected": "Aucun package n'a été sélectionné", + "More than 1 package was selected": "Plus d'un package a été sélectionné", + "List": "Liste", + "Grid": "Grille", + "Icons": "Icônes", + "\"{0}\" is a local package and does not have available details": "\"{0}\" est un paquet local et n'a pas de détails disponibles.", + "\"{0}\" is a local package and is not compatible with this feature": "\"{0}\" est un paquet local et n'est pas compatible avec cette fonctionnalité", + "Add packages to bundle": "Ajouter des paquets au lot", + "Preparing packages, please wait...": "Préparation des paquets, veuillez patienter...", + "Loading packages, please wait...": "Chargement des paquets, veuillez patienter...", + "Saving packages, please wait...": "Enregistrement des paquets, veuillez patienter...", + "The bundle was created successfully on {0}": "Le lot a été créé avec succès sur {0}", + "User profile": "Profil utilisateur", + "Error": "Erreur", + "Log in failed: ": "Échec de la connexion :", + "Log out failed: ": "Échec de la déconnexion :", + "Package backup settings": "Paramètres de sauvegarde des paquets", + "Manage UniGetUI autostart behaviour from the Settings app": "Gérer le comportement de démarrage automatique de UniGetUI", + "Choose how many operations shoulds be performed in parallel": "Choisissez combien d'opérations doivent être effectuées en parallèle", + "Something went wrong while launching the updater.": "Un problème s'est produit lors du lancement de l'outil de mise à jour.", + "Please try again later": "Veuillez réessayer plus tard", + "Show the release notes after UniGetUI is updated": "Afficher les notes de publication après la mise à jour de UniGetUI" +} diff --git a/src/Languages/lang_gl.json b/src/Languages/lang_gl.json new file mode 100644 index 0000000..5a18ab0 --- /dev/null +++ b/src/Languages/lang_gl.json @@ -0,0 +1,850 @@ +{ + "{0} of {1} operations completed": "{0} de {1} operacións completadas", + "{0} is now {1}": "{0} agora é {1}", + "Enabled": "Activado", + "Disabled": "Desactivado", + "Privacy": "Privacidade", + "Hide my username from the logs": "Ocultar o meu nome de usuario nos rexistros", + "Replaces your username with **** in the logs. Restart UniGetUI to also hide it from already-recorded entries.": "Substitúe o teu nome de usuario por **** nos rexistros. Reinicia UniGetUI para ocultalo tamén nas entradas xa rexistradas.", + "Your last update attempt did not complete.": "O seu último intento de actualización non se completou.", + "UniGetUI could not confirm whether the update succeeded. Open the log to see what happened.": "UniGetUI non puido confirmar se a actualización se completou correctamente. Abra o rexistro para ver que ocorreu.", + "View log": "Ver rexistro", + "The installer reported success but did not restart UniGetUI.": "O instalador indicou que se completou correctamente, pero non reiniciou UniGetUI.", + "The installer failed to initialize.": "O instalador non se puido inicializar.", + "Setup was canceled before installation began.": "O asistente de instalación cancelouse antes de que comezase a instalación.", + "A fatal error occurred during the preparation phase.": "Produciuse un erro fatal durante a fase de preparación.", + "A fatal error occurred during installation.": "Produciuse un erro fatal durante a instalación.", + "Installation was canceled while in progress.": "A instalación cancelouse mentres estaba en curso.", + "The installer was terminated by another process.": "O instalador foi finalizado por outro proceso.", + "The preparation phase determined the installation cannot proceed.": "A fase de preparación determinou que a instalación non pode continuar.", + "The installer could not start. UniGetUI may already be running, or you do not have permission to install.": "Non se puido iniciar o instalador. Pode que UniGetUI xa estea en execución ou que non teña permiso para instalar.", + "Unexpected installer error.": "Erro inesperado do instalador.", + "We are checking for updates.": "Estamos comprobando se hai actualizacións.", + "Please wait": "Agarda, por favor", + "Great! You are on the latest version.": "Xenial! Tes a versión máis recente.", + "There are no new UniGetUI versions to be installed": "Non hai novas versións de UniGetUI para instalar", + "UniGetUI version {0} is being downloaded.": "Estase descargando UniGetUI versión {0}.", + "This may take a minute or two": "Isto pode levar un ou dous minutos", + "The installer authenticity could not be verified.": "Non foi posible verificar a autenticidade do instalador.", + "The update process has been aborted.": "O proceso de actualización foi abortado.", + "Auto-update is not yet available on this platform.": "A actualización automática aínda non está dispoñible nesta plataforma.", + "Please update UniGetUI manually.": "Actualice UniGetUI manualmente.", + "An error occurred when checking for updates: ": "Produciuse un erro ao comprobar as actualizacións: ", + "The updater could not be launched.": "Non se puido iniciar o actualizador.", + "The operating system did not start the installer process.": "O sistema operativo non iniciou o proceso do instalador.", + "UniGetUI is being updated...": "UniGetUI estase actualizando...", + "Update installed.": "Actualización instalada.", + "UniGetUI was updated successfully, but this running copy was not replaced. This usually means you are running a development build. Close this copy and start the newly-installed version to finish.": "UniGetUI actualizouse correctamente, pero esta copia en execución non foi substituída. Isto adoita significar que está a executar unha compilación de desenvolvemento. Peche esta copia e inicie a versión recentemente instalada para rematar.", + "The update could not be applied.": "Non se puido aplicar a actualización.", + "Installer exit code {0}: {1}": "Código de saída do instalador {0}: {1}", + "Update cancelled.": "Actualización cancelada.", + "Authentication was cancelled.": "Cancelouse a autenticación.", + "Installer exit code {0}": "Código de saída do instalador {0}", + "Operation in progress": "Operación en progreso", + "Please wait...": "Agarde...", + "Success!": "Éxito!", + "Failed": "Fallou", + "An error occurred while processing this package": "Produciuse un erro ao procesar este paquete", + "Installer": "Instalador", + "Executable": "Ficheiro executable", + "MSI": "MSI", + "Compressed file": "Ficheiro comprimido", + "MSIX": "MSIX", + "WinGet was repaired successfully": "WinGet reparouse correctamente", + "It is recommended to restart UniGetUI after WinGet has been repaired": "Recoméndase reiniciar UniGetUI despois de reparar WinGet", + "WinGet could not be repaired": "Non se puido reparar WinGet", + "An unexpected issue occurred while attempting to repair WinGet. Please try again later": "Produciuse un problema inesperado ao tentar reparar WinGet. Téntao de novo máis tarde", + "Log in to enable cloud backup": "Inicie sesión para activar a copia de seguranza na nube", + "Backup Failed": "A copia de seguranza fallou", + "Downloading backup...": "Descargando a copia de seguranza...", + "An update was found!": "Atopouse unha actualización!", + "{0} can be updated to version {1}": "{0} pódese actualizar á versión {1}", + "Updates found!": "Atopáronse actualizacións!", + "{0} packages can be updated": "{0} paquetes pódense actualizar", + "{0} is being updated to version {1}": "Estase actualizando {0} á versión {1}", + "{0} packages are being updated": "Estanse actualizando {0} paquetes", + "You have currently version {0} installed": "Ten instalada actualmente a versión {0}", + "Desktop shortcut created": "Creouse o atallo do escritorio", + "UniGetUI has detected a new desktop shortcut that can be deleted automatically.": "UniGetUI detectou un novo atallo do escritorio que se pode eliminar automaticamente.", + "{0} desktop shortcuts created": "Creáronse {0} atallos do escritorio", + "UniGetUI has detected {0} new desktop shortcuts that can be deleted automatically.": "UniGetUI detectou {0} novos atallos do escritorio que se poden eliminar automaticamente.", + "Attention required": "Requírese atención", + "Restart required": "Requírese reinicio", + "1 update is available": "Hai 1 actualización dispoñible", + "{0} updates are available": "Hai {0} actualizacións dispoñibles", + "Everything is up to date": "Todo está ao día", + "Discover Packages": "Descubrir paquetes", + "Available Updates": "Actualizacións dispoñibles", + "Installed Packages": "Paquetes instalados", + "UniGetUI Version {0} by Devolutions": "UniGetUI versión {0} de Devolutions", + "Show UniGetUI": "Mostrar UniGetUI", + "Quit": "Saír", + "Are you sure?": "Está seguro?", + "Do you really want to uninstall {0}?": "Realmente quere desinstalar {0}?", + "Do you really want to uninstall the following {0} packages?": "Realmente quere desinstalar os seguintes {0} paquetes?", + "No": "Non", + "Yes": "Si", + "Partial": "Parcial", + "View on UniGetUI": "Ver en UniGetUI", + "Update": "Actualizar", + "Open UniGetUI": "Abrir UniGetUI", + "Update all": "Actualizar todo", + "Update now": "Actualizar agora", + "Installer host changed since the installed version.\n": "O host do instalador cambiou desde a versión instalada.\n", + "This package is on the queue": "Este paquete está na cola", + "installing": "instalando", + "updating": "actualizando", + "uninstalling": "desinstalando", + "installed": "instalado", + "Retry": "Reintentar", + "Install": "Instalar", + "Uninstall": "Desinstalar", + "Open": "Abrir", + "Operation profile:": "Perfil da operación:", + "Follow the default options when installing, upgrading or uninstalling this package": "Siga as opcións predeterminadas ao instalar, actualizar ou desinstalar este paquete", + "The following settings will be applied each time this package is installed, updated or removed.": "A seguinte configuración aplicarase cada vez que este paquete se instale, actualice ou elimine.", + "Version to install:": "Versión para instalar:", + "Architecture to install:": "Arquitectura para instalar:", + "Installation scope:": "Ámbito da instalación:", + "Install location:": "Localización da instalación:", + "Select": "Seleccionar", + "Reset": "Restablecer", + "Custom install arguments:": "Argumentos personalizados de instalación:", + "Custom update arguments:": "Argumentos personalizados de actualización:", + "Custom uninstall arguments:": "Argumentos personalizados de desinstalación:", + "Pre-install command:": "Comando previo á instalación:", + "Post-install command:": "Comando posterior á instalación:", + "Abort install if pre-install command fails": "Abortar a instalación se falla o comando previo á instalación", + "Pre-update command:": "Comando previo á actualización:", + "Post-update command:": "Comando posterior á actualización:", + "Abort update if pre-update command fails": "Abortar a actualización se falla o comando previo á actualización", + "Pre-uninstall command:": "Comando previo á desinstalación:", + "Post-uninstall command:": "Comando posterior á desinstalación:", + "Abort uninstall if pre-uninstall command fails": "Abortar a desinstalación se falla o comando previo á desinstalación", + "Command-line to run:": "Liña de ordes para executar:", + "Save and close": "Gardar e pechar", + "General": "Xeral", + "Architecture & Location": "Arquitectura e localización", + "Command-line": "Liña de ordes", + "Close apps": "Pechar aplicacións", + "Pre/Post install": "Pre/Post instalación", + "Select the processes that should be closed before this package is installed, updated or uninstalled.": "Selecciona os procesos que deberían pecharse antes de instalar, actualizar ou desinstalar este paquete.", + "Write here the process names here, separated by commas (,)": "Escribe aquí os nomes dos procesos, separados por comas (,)", + "Try to kill the processes that refuse to close when requested to": "Tentar finalizar os procesos que se negan a pecharse cando se lles solicita", + "Run as admin": "Executar como administrador", + "Interactive installation": "Instalación interactiva", + "Skip hash check": "Omitir a comprobación do hash", + "Uninstall previous versions when updated": "Desinstalar as versións anteriores ao actualizar", + "Skip minor updates for this package": "Omitir as actualizacións menores deste paquete", + "Automatically update this package": "Actualizar este paquete automaticamente", + "{0} installation options": "Opcións de instalación de {0}", + "Latest": "Última", + "PreRelease": "Prelanzamento", + "Default": "Predeterminado", + "Manage ignored updates": "Xestionar as actualizacións ignoradas", + "The packages listed here won't be taken in account when checking for updates. Double-click them or click the button on their right to stop ignoring their updates.": "Os paquetes listados aquí non se terán en conta ao comprobar actualizacións. Faga dobre clic neles ou prema no botón da dereita para deixar de ignorar as súas actualizacións.", + "Reset list": "Restablecer lista", + "Do you really want to reset the ignored updates list? This action cannot be reverted": "Realmente quere restablecer a lista de actualizacións ignoradas? Esta acción non se pode desfacer", + "No ignored updates": "Non hai actualizacións ignoradas", + "Package Name": "Nome do paquete", + "Package ID": "ID do paquete", + "Ignored version": "Versión ignorada", + "New version": "Nova versión", + "Source": "Orixe", + "All versions": "Todas as versións", + "Unknown": "Descoñecido", + "Up to date": "Actualizado", + "Package {name} from {manager}": "Paquete {name} de {manager}", + "Remove {0} from ignored updates": "Eliminar {0} das actualizacións ignoradas", + "Cancel": "Cancelar", + "Administrator privileges": "Privilexios de administrador", + "This operation is running with administrator privileges.": "Esta operación estase executando con privilexios de administrador.", + "Interactive operation": "Operación interactiva", + "This operation is running interactively.": "Esta operación estase executando de forma interactiva.", + "You will likely need to interact with the installer.": "Probablemente terá que interactuar co instalador.", + "Integrity checks skipped": "Omitíronse as comprobacións de integridade", + "Integrity checks will not be performed during this operation.": "Non se realizarán comprobacións de integridade durante esta operación.", + "Proceed at your own risk.": "Continúe baixo a súa responsabilidade.", + "Close": "Pechar", + "Loading...": "Cargando...", + "Installer SHA256": "SHA256 do instalador", + "Homepage": "Páxina principal", + "Author": "Autor", + "Publisher": "Publicador", + "License": "Licenza", + "Manifest": "Manifesto", + "Installer Type": "Tipo de instalador", + "Size": "Tamaño", + "Installer URL": "URL do instalador", + "Last updated:": "Última actualización:", + "Release notes URL": "URL das notas da versión", + "Package details": "Detalles do paquete", + "Dependencies:": "Dependencias:", + "Release notes": "Notas da versión", + "Screenshots": "Capturas de pantalla", + "This package has no screenshots or is missing the icon? Contribute to UniGetUI by adding the missing icons and screenshots to our open, public database.": "Este paquete non ten capturas de pantalla ou fáltalle a icona? Contribúa a UniGetUI engadindo as iconas e capturas de pantalla que faltan á nosa base de datos aberta e pública.", + "Version": "Versión", + "Install as administrator": "Instalar como administrador", + "Update to version {0}": "Actualizar á versión {0}", + "Installed Version": "Versión instalada", + "Update as administrator": "Actualizar como administrador", + "Interactive update": "Actualización interactiva", + "Uninstall as administrator": "Desinstalar como administrador", + "Interactive uninstall": "Desinstalación interactiva", + "Uninstall and remove data": "Desinstalar e eliminar os datos", + "Not available": "Non dispoñible", + "Installer SHA512": "SHA512 do instalador", + "Unknown size": "Tamaño descoñecido", + "No dependencies specified": "Non se especificaron dependencias", + "mandatory": "obrigatorio", + "optional": "opcional", + "UniGetUI {0} is ready to be installed.": "UniGetUI {0} está listo para instalarse.", + "The update process will start after closing UniGetUI": "O proceso de actualización iniciarase despois de pechar UniGetUI", + "UniGetUI has been ran as administrator, which is not recommended. When running UniGetUI as administrator, EVERY operation launched from UniGetUI will have administrator privileges. You can still use the program, but we highly recommend not running UniGetUI with administrator privileges.": "UniGetUI executouse como administrador, o que non se recomenda. Ao executar UniGetUI como administrador, TODAS as operacións iniciadas desde UniGetUI terán privilexios de administrador. Aínda pode usar o programa, pero recomendámoslle encarecidamente non executar UniGetUI con privilexios de administrador.", + "Share anonymous usage data": "Compartir datos de uso anónimos", + "UniGetUI collects anonymous usage data in order to improve the user experience.": "UniGetUI recolle datos de uso anónimos para mellorar a experiencia de usuario.", + "Accept": "Aceptar", + "Software Updates": "Actualizacións de software", + "Package Bundles": "Conxuntos de paquetes", + "Settings": "Configuración", + "Package Managers": "Xestores de paquetes", + "UniGetUI Log": "Rexistro de UniGetUI", + "Package Manager logs": "Rexistros dos xestores de paquetes", + "Operation history": "Historial de operacións", + "Help": "Axuda", + "UniGetUI": "UniGetUI", + "You have installed UniGetUI Version {0}": "Instalou UniGetUI versión {0}", + "Disclaimer": "Exención de responsabilidade", + "UniGetUI is developed by Devolutions and is not affiliated with any of the compatible package managers.": "UniGetUI está desenvolvido por Devolutions e non está afiliado a ningún dos xestores de paquetes compatibles.", + "UniGetUI wouldn't have been possible without the help of the contributors. Thank you all 🥳": "UniGetUI non sería posible sen a axuda dos colaboradores. Grazas a todos 🥳", + "UniGetUI uses the following libraries. Without them, UniGetUI wouldn't have been possible.": "UniGetUI usa as seguintes bibliotecas. Sen elas, UniGetUI non sería posible.", + "{0} homepage": "Páxina principal de {0}", + "UniGetUI has been translated to more than 40 languages thanks to the volunteer translators. Thank you 🤝": "UniGetUI traduciuse a máis de 40 idiomas grazas aos tradutores voluntarios. Grazas 🤝", + "Verbose": "Detallado", + "1 - Errors": "1 - Erros", + "2 - Warnings": "2 - Avisos", + "3 - Information (less)": "3 - Información (menos)", + "4 - Information (more)": "4 - Información (máis)", + "5 - information (debug)": "5 - Información (depuración)", + "Warning": "Aviso", + "The following settings may pose a security risk, hence they are disabled by default.": "Os seguintes axustes poden supoñer un risco de seguranza, polo que están desactivados por defecto.", + "Enable the settings below if and only if you fully understand what they do, and the implications they may have.": "Active os axustes seguintes se e só se entende completamente o que fan e as implicacións que poden ter.", + "The settings will list, in their descriptions, the potential security issues they may have.": "Os axustes indicarán, nas súas descricións, os posibles problemas de seguranza que poden ter.", + "The backup will include the complete list of the installed packages and their installation options. Ignored updates and skipped versions will also be saved.": "A copia de seguranza incluirá a lista completa dos paquetes instalados e as súas opcións de instalación. Tamén se gardarán as actualizacións ignoradas e as versións omitidas.", + "The backup will NOT include any binary file nor any program's saved data.": "A copia de seguranza NON incluirá ningún ficheiro binario nin os datos gardados de ningún programa.", + "The size of the backup is estimated to be less than 1MB.": "Estímase que o tamaño da copia de seguranza será inferior a 1 MB.", + "The backup will be performed after login.": "A copia de seguranza realizarase despois de iniciar sesión.", + "{pcName} installed packages": "Paquetes instalados en {pcName}", + "Current status: Not logged in": "Estado actual: sesión non iniciada", + "You are logged in as {0} (@{1})": "Iniciou sesión como {0} (@{1})", + "Nice! Backups will be uploaded to a private gist on your account": "Xenial! As copias de seguranza cargaranse nun gist privado da súa conta", + "Select backup": "Seleccionar copia de seguranza", + "Settings imported from {0}": "Axustes importados de {0}", + "UniGetUI Settings": "Axustes de UniGetUI", + "Settings exported to {0}": "Axustes exportados a {0}", + "UniGetUI settings were reset": "Os axustes de UniGetUI restableceronse", + "Allow pre-release versions": "Permitir versións preliminares", + "Apply": "Aplicar", + "For security reasons, custom command-line arguments are disabled by default. Go to UniGetUI security settings to change this.": "Por motivos de seguranza, os argumentos personalizados da liña de comandos están desactivados por defecto. Vaia aos axustes de seguranza de UniGetUI para cambialo.", + "Go to UniGetUI security settings": "Ir aos axustes de seguranza de UniGetUI", + "The following options will be applied by default each time a {0} package is installed, upgraded or uninstalled.": "As seguintes opcións aplicaranse por defecto cada vez que se instale, actualice ou desinstale un paquete de {0}.", + "Package's default": "Predeterminado do paquete", + "Install location can't be changed for {0} packages": "A localización de instalación non se pode cambiar para os paquetes de {0}", + "The local icon cache currently takes {0} MB": "A caché local de iconas ocupa actualmente {0} MB", + "Username": "Nome de usuario", + "Password": "Contrasinal", + "Credentials": "Credenciais", + "It is not guaranteed that the provided credentials will be stored safely": "Non se garante que as credenciais proporcionadas se almacenen de forma segura", + "Partially": "Parcialmente", + "Package manager": "Xestor de paquetes", + "Compatible with proxy": "Compatible con proxy", + "Compatible with authentication": "Compatible con autenticación", + "Proxy compatibility table": "Táboa de compatibilidade con proxy", + "{0} settings": "Axustes de {0}", + "{0} status": "Estado de {0}", + "Default installation options for {0} packages": "Opcións de instalación predeterminadas para os paquetes de {0}", + "Expand version": "Expandir versión", + "The executable file for {0} was not found": "Non se atopou o ficheiro executable de {0}", + "{pm} is disabled": "{pm} está desactivado", + "Enable it to install packages from {pm}.": "Actíveo para instalar paquetes de {pm}.", + "{pm} is enabled and ready to go": "{pm} está activado e listo para usar", + "{pm} version:": "Versión de {pm}:", + "{pm} was not found!": "Non se atopou {pm}!", + "You may need to install {pm} in order to use it with UniGetUI.": "Pode que necesite instalar {pm} para usalo con UniGetUI.", + "Scoop Installer - UniGetUI": "Instalador de Scoop - UniGetUI", + "Scoop Uninstaller - UniGetUI": "Desinstalador de Scoop - UniGetUI", + "Clearing Scoop cache - UniGetUI": "Limpando a caché de Scoop - UniGetUI", + "Restart UniGetUI to fully apply changes": "Reinicie UniGetUI para aplicar completamente os cambios", + "Restart UniGetUI": "Reiniciar UniGetUI", + "Manage {0} sources": "Xestionar fontes de {0}", + "Add source": "Engadir fonte", + "Add": "Engadir", + "Source name": "Nome da fonte", + "Source URL": "URL da fonte", + "Other": "Outro", + "No minimum age": "Sen antigüidade mínima", + "1 day": "1 día", + "{0} days": "{0} días", + "Custom...": "Personalizado...", + "{0} minutes": "{0} minutos", + "1 hour": "unha hora", + "{0} hours": "{0} horas", + "1 week": "1 semana", + "Supports release dates": "Admite datas de lanzamento", + "Release date support per package manager": "Compatibilidade con datas de lanzamento por xestor de paquetes", + "Search for packages": "Buscar paquetes", + "Local": "Local (equipo)", + "OK": "Aceptar", + "Last checked: {0}": "Última comprobación: {0}", + "{0} packages were found, {1} of which match the specified filters.": "Atopáronse {0} paquetes, dos que {1} coinciden cos filtros especificados.", + "{0} selected": "{0} seleccionados", + "(Last checked: {0})": "(Última comprobación: {0})", + "All packages selected": "Seleccionáronse todos os paquetes", + "Package selection cleared": "Limpouse a selección de paquetes", + "{0}: {1}": "{0}: {1}", + "More info": "Máis información", + "GitHub account": "Conta de GitHub", + "Log in with GitHub to enable cloud package backup.": "Inicia sesión con GitHub para activar a copia de seguridade na nube dos paquetes.", + "More details": "Máis detalles", + "Log in": "Iniciar sesión", + "If you have cloud backup enabled, it will be saved as a GitHub Gist on this account": "Se a copia de seguridade na nube está activada, gardarase como un GitHub Gist nesta conta", + "Log out": "Pechar sesión", + "About UniGetUI": "Acerca de UniGetUI", + "About": "Acerca de", + "Third-party licenses": "Licenzas de terceiros", + "Contributors": "Colaboradores", + "Translators": "Tradutores", + "Bundle security report": "Informe de seguridade do lote", + "The bundle contained restricted content": "O lote contiña contido restrinxido", + "UniGetUI – Crash Report": "UniGetUI – Informe de fallo", + "UniGetUI has crashed": "UniGetUI fallou", + "Help us fix this by sending a crash report to Devolutions. All fields below are optional.": "Axúdenos a solucionalo enviando un informe de fallo a Devolutions. Todos os campos a continuación son opcionais.", + "Email (optional)": "Correo electrónico (opcional)", + "your@email.com": "teu@correo.com", + "Additional details (optional)": "Detalles adicionais (opcional)", + "Describe what you were doing when the crash occurred…": "Describa o que estaba facendo cando se produciu o fallo…", + "Crash report": "Informe de fallo", + "Don't Send": "Non enviar", + "Send Report": "Enviar informe", + "Sending…": "Enviando…", + "Unsaved changes": "Cambios sen gardar", + "You have unsaved changes in the current bundle. Do you want to discard them?": "Tes cambios sen gardar no lote actual. Queres descartalos?", + "Discard changes": "Descartar os cambios", + "Integrity violation": "Violación da integridade", + "UniGetUI or some of its components are missing or corrupt. It is strongly recommended to reinstall UniGetUI to adress the situation.": "Falta UniGetUI ou algún dos seus compoñentes, ou están danados. Recoméndase encarecidamente reinstalar UniGetUI para resolver a situación.", + "• Refer to the UniGetUI Logs to get more details regarding the affected file(s)": "• Consulta os rexistros de UniGetUI para obter máis detalles sobre o(s) ficheiro(s) afectado(s)", + "• Integrity checks can be disabled from the Experimental Settings": "• As comprobacións de integridade pódense desactivar na Configuración experimental", + "Manage shortcuts": "Xestionar accesos directos", + "UniGetUI has detected the following desktop shortcuts which can be removed automatically on future upgrades": "UniGetUI detectou os seguintes accesos directos do escritorio que se poden eliminar automaticamente en futuras actualizacións", + "Do you really want to reset this list? This action cannot be reverted.": "Queres realmente restablecer esta lista? Esta acción non se pode desfacer.", + "Desktop shortcuts list": "Lista de atallos do escritorio", + "Open in explorer": "Abrir no explorador", + "Remove from list": "Eliminar da lista", + "When new shortcuts are detected, delete them automatically instead of showing this dialog.": "Cando se detecten novos accesos directos, elimínaos automaticamente en vez de mostrar este diálogo.", + "Not right now": "Agora non", + "Missing dependency": "Dependencia que falta", + "UniGetUI requires {0} to operate, but it was not found on your system.": "UniGetUI require {0} para funcionar, pero non se atopou no teu sistema.", + "Click on Install to begin the installation process. If you skip the installation, UniGetUI may not work as expected.": "Fai clic en Instalar para comezar o proceso de instalación. Se omites a instalación, é posible que UniGetUI non funcione como se espera.", + "Alternatively, you can also install {0} by running the following command in a Windows PowerShell prompt:": "Como alternativa, tamén podes instalar {0} executando o seguinte comando nunha ventá de Windows PowerShell:", + "Install {0}": "Instalar {0}", + "Do not show this dialog again for {0}": "Non volver mostrar este diálogo para {0}", + "Please wait while {0} is being installed. A black window may show up. Please wait until it closes.": "Agarda mentres se instala {0}. Pode aparecer unha xanela negra (ou azul). Agarda ata que se peche.", + "{0} has been installed successfully.": "{0} instalouse correctamente.", + "Please click on \"Continue\" to continue": "Fai clic en \"Continuar\" para continuar", + "Continue": "Continuar", + "{0} has been installed successfully. It is recommended to restart UniGetUI to finish the installation": "{0} instalouse correctamente. Recoméndase reiniciar UniGetUI para completar a instalación", + "Restart later": "Reiniciar máis tarde", + "An error occurred:": "Produciuse un erro:", + "Please see the Command-line Output or refer to the Operation History for further information about the issue.": "Consulta a Saída da liña de comandos ou o Historial de operacións para obter máis información sobre o problema.", + "Retry as administrator": "Tentar de novo como administrador", + "Retry interactively": "Tentar de novo de forma interactiva", + "Retry skipping integrity checks": "Tentar de novo omitindo as comprobacións de integridade", + "Installation options": "Opcións de instalación", + "Save": "Gardar", + "UniGetUI collects anonymous usage data with the sole purpose of understanding and improving the user experience.": "UniGetUI recolle datos de uso anónimos co único propósito de comprender e mellorar a experiencia de usuario.", + "More details about the shared data and how it will be processed": "Máis detalles sobre os datos compartidos e como se procesarán", + "Do you accept that UniGetUI collects and sends anonymous usage statistics, with the sole purpose of understanding and improving the user experience?": "Aceptas que UniGetUI recolla e envíe estatísticas de uso anónimas, co único propósito de comprender e mellorar a experiencia de usuario?", + "Decline": "Rexeitar", + "No personal information is collected nor sent, and the collected data is anonimized, so it can't be back-tracked to you.": "Non se recolle nin se envía información persoal, e os datos recollidos están anonimizados, polo que non se poden rastrexar ata ti.", + "Navigation panel": "Panel de navegación", + "Operations": "Operacións", + "Toggle operations panel": "Alternar o panel de operacións", + "Bulk operations": "Operacións en lote", + "Retry failed": "Reintentar as fallidas", + "Clear successful": "Limpar as correctas", + "Clear finished": "Limpar as finalizadas", + "Cancel all": "Cancelar todo", + "More": "Máis", + "Toggle navigation panel": "Mostrar ou ocultar o panel de navegación", + "Minimize": "Minimizar", + "Maximize": "Maximizar", + "UniGetUI by Devolutions": "UniGetUI de Devolutions", + "UniGetUI is an application that makes managing your software easier, by providing an all-in-one graphical interface for your command-line package managers.": "UniGetUI é unha aplicación que facilita a xestión do software, ofrecendo unha interface gráfica todo en un para os xestores de paquetes de liña de comandos.", + "Useful links": "Ligazóns útiles", + "UniGetUI Homepage": "Páxina principal de UniGetUI", + "Report an issue or submit a feature request": "Informar dun problema ou enviar unha solicitude de nova funcionalidade", + "UniGetUI Repository": "Repositorio de UniGetUI", + "View GitHub Profile": "Ver o perfil de GitHub", + "UniGetUI License": "Licenza de UniGetUI", + "Using UniGetUI implies the acceptation of the MIT License": "Usar UniGetUI implica a aceptación da licenza MIT", + "Become a translator": "Convértete en tradutor", + "Go back": "Ir atrás", + "Go forward": "Ir adiante", + "Go to home page": "Ir á páxina de inicio", + "Reload page": "Recargar páxina", + "View page on browser": "Ver a páxina no navegador", + "The built-in browser is not supported on Linux yet.": "O navegador integrado aínda non é compatible con Linux.", + "Open in browser": "Abrir no navegador", + "Copy to clipboard": "Copiar ao portapapeis", + "Export to a file": "Exportar a un ficheiro", + "Log level:": "Nivel de rexistro:", + "Reload log": "Recargar rexistro", + "Export log": "Exportar rexistro", + "Text": "Texto", + "Change how operations request administrator rights": "Cambiar como as operacións solicitan permisos de administrador", + "Restrictions on package operations": "Restricións nas operacións de paquetes", + "Restrictions on package managers": "Restricións nos xestores de paquetes", + "Restrictions when importing package bundles": "Restricións ao importar lotes de paquetes", + "Ask for administrator privileges once for each batch of operations": "Solicitar privilexios de administrador unha vez por cada lote de operacións", + "Ask only once for administrator privileges": "Solicitar privilexios de administrador só unha vez", + "Prohibit any kind of Elevation via UniGetUI Elevator or GSudo": "Prohibir calquera tipo de elevación mediante UniGetUI Elevator ou GSudo", + "This option WILL cause issues. Any operation incapable of elevating itself WILL FAIL. Install/update/uninstall as administrator will NOT WORK.": "Esta opción CAUSARÁ problemas. Calquera operación que non poida elevarse por si mesma FALLARÁ. Instalar/actualizar/desinstalar como administrador NON FUNCIONARÁ.", + "Allow custom command-line arguments": "Permitir argumentos personalizados da liña de comandos", + "Custom command-line arguments can change the way in which programs are installed, upgraded or uninstalled, in a way UniGetUI cannot control. Using custom command-lines can break packages. Proceed with caution.": "Os argumentos personalizados da liña de comandos poden cambiar a forma en que se instalan, actualizan ou desinstalan os programas, dun xeito que UniGetUI non pode controlar. O uso de liñas de comandos personalizadas pode causar fallos nos paquetes. Procede con cautela.", + "Ignore custom pre-install and post-install commands when importing packages from a bundle": "Ignorar os comandos personalizados previos e posteriores á instalación ao importar paquetes desde un lote", + "Pre and post install commands will be run before and after a package gets installed, upgraded or uninstalled. Be aware that they may break things unless used carefully": "Os comandos previos e posteriores á instalación executaranse antes e despois de que un paquete se instale, actualice ou desinstale. Ten en conta que poden causar problemas se non se usan con coidado", + "Allow changing the paths for package manager executables": "Permitir cambiar as rutas dos executables dos xestores de paquetes", + "Turning this on enables changing the executable file used to interact with package managers. While this allows finer-grained customization of your install processes, it may also be dangerous": "Ao activar isto, permítese cambiar o ficheiro executable usado para interactuar cos xestores de paquetes. Aínda que isto permite unha personalización máis detallada dos procesos de instalación, tamén pode ser perigoso", + "Allow importing custom command-line arguments when importing packages from a bundle": "Permitir importar argumentos personalizados da liña de comandos ao importar paquetes desde un lote", + "Malformed command-line arguments can break packages, or even allow a malicious actor to gain privileged execution. Therefore, importing custom command-line arguments is disabled by default": "Os argumentos da liña de comandos malformados poden causar fallos nos paquetes, ou incluso permitir que un actor malicioso obteña execución privilexiada. Por iso, a importación de argumentos personalizados da liña de comandos está desactivada por defecto", + "Allow importing custom pre-install and post-install commands when importing packages from a bundle": "Permitir importar comandos personalizados previos e posteriores á instalación ao importar paquetes desde un lote", + "Pre and post install commands can do very nasty things to your device, if designed to do so. It can be very dangerous to import the commands from a bundle, unless you trust the source of that package bundle": "Os comandos previos e posteriores á instalación poden facer cousas moi prexudiciais no dispositivo, se están deseñados para iso. Pode ser moi perigoso importar os comandos desde un lote, a menos que se confíe na orixe dese lote de paquetes", + "Administrator rights and other dangerous settings": "Permisos de administrador e outras configuracións perigosas", + "Package backup": "Copia de seguridade de paquetes", + "Cloud package backup": "Copia de seguridade na nube dos paquetes", + "Local package backup": "Copia de seguridade local dos paquetes", + "Local backup advanced options": "Opcións avanzadas da copia de seguridade local", + "Log in with GitHub": "Iniciar sesión con GitHub", + "Log out from GitHub": "Pechar sesión en GitHub", + "Periodically perform a cloud backup of the installed packages": "Realizar periodicamente unha copia de seguridade na nube dos paquetes instalados", + "Cloud backup uses a private GitHub Gist to store a list of installed packages": "A copia de seguridade na nube usa un GitHub Gist privado para gardar unha lista dos paquetes instalados", + "Perform a cloud backup now": "Realizar agora unha copia de seguridade na nube", + "Backup": "Copia de seguridade", + "Restore a backup from the cloud": "Restaurar unha copia de seguridade desde a nube", + "Begin the process to select a cloud backup and review which packages to restore": "Iniciar o proceso para seleccionar unha copia de seguridade na nube e revisar que paquetes restaurar", + "Periodically perform a local backup of the installed packages": "Realizar periodicamente unha copia de seguridade local dos paquetes instalados", + "Perform a local backup now": "Realizar agora unha copia de seguridade local", + "Change backup output directory": "Cambiar o directorio de destino da copia de seguridade", + "Set a custom backup file name": "Establecer un nome personalizado para o ficheiro de copia de seguridade", + "Leave empty for default": "Deixar baleiro para usar o predeterminado", + "Add a timestamp to the backup file names": "Engadir unha marca temporal aos nomes dos ficheiros de copia de seguridade", + "Backup and Restore": "Copia de seguridade e restauración", + "Enable background api (UniGetUI Widgets and Sharing, port 7058)": "Activar a API en segundo plano (Widgets de UniGetUI e Sharing, porto 7058)", + "Wait for the device to be connected to the internet before attempting to do tasks that require internet connectivity.": "Agardar a que o dispositivo estea conectado a internet antes de tentar realizar tarefas que requiran conexión a internet.", + "Disable the 1-minute timeout for package-related operations": "Desactivar o tempo límite de 1 minuto para as operacións relacionadas con paquetes", + "Use installed GSudo instead of UniGetUI Elevator": "Usar o GSudo instalado en vez de UniGetUI Elevator", + "Use a custom icon and screenshot database URL": "Usar un URL personalizado para a base de datos de iconas e capturas de pantalla", + "Enable background CPU Usage optimizations (see Pull Request #3278)": "Activar as optimizacións de uso da CPU en segundo plano (consulta a Pull Request #3278)", + "Perform integrity checks at startup": "Realizar comprobacións de integridade ao iniciar", + "When batch installing packages from a bundle, install also packages that are already installed": "Ao instalar paquetes en lote desde un conxunto, instalar tamén os paquetes que xa están instalados", + "Experimental settings and developer options": "Configuración experimental e opcións de desenvolvedor", + "Show UniGetUI's version and build number on the titlebar.": "Mostrar a versión de UniGetUI na barra de título.", + "Language": "Idioma", + "UniGetUI updater": "Actualizador de UniGetUI", + "Telemetry": "Telemetría", + "Manage UniGetUI settings": "Xestionar a configuración de UniGetUI", + "Related settings": "Configuración relacionada", + "Update UniGetUI automatically": "Actualizar UniGetUI automaticamente", + "Check for updates": "Comprobar actualizacións", + "Install prerelease versions of UniGetUI": "Instalar versións preliminares de UniGetUI", + "Manage telemetry settings": "Xestionar a configuración da telemetría", + "Manage": "Xestionar", + "Import settings from a local file": "Importar a configuración desde un ficheiro local", + "Import": "Importar", + "Export settings to a local file": "Exportar a configuración a un ficheiro local", + "Export": "Exportar", + "Reset UniGetUI": "Restablecer UniGetUI", + "User interface preferences": "Preferencias da interface de usuario", + "Application theme, startup page, package icons, clear successful installs automatically": "Tema da aplicación, páxina de inicio, iconas dos paquetes, limpar automaticamente as instalacións completadas correctamente", + "General preferences": "Preferencias xerais", + "UniGetUI display language:": "Idioma da interface de UniGetUI:", + "System language": "Idioma do sistema", + "Is your language missing or incomplete?": "Falta o teu idioma ou está incompleto?", + "Appearance": "Aparencia", + "UniGetUI on the background and system tray": "UniGetUI en segundo plano e na bandexa do sistema", + "Package lists": "Listas de paquetes", + "Use classic mode": "Usar o modo clásico", + "Restart UniGetUI to apply this change": "Reinicie UniGetUI para aplicar este cambio", + "The classic UI is disabled for beta testers": "A interface clásica está desactivada para os probadores beta", + "Close UniGetUI to the system tray": "Pechar UniGetUI na bandexa do sistema", + "Manage UniGetUI autostart behaviour": "Xestionar o comportamento de inicio automático de UniGetUI", + "Show package icons on package lists": "Mostrar iconas dos paquetes nas listas de paquetes", + "Clear cache": "Limpar a caché", + "Select upgradable packages by default": "Seleccionar por defecto os paquetes actualizables", + "Light": "Claro", + "Dark": "Escuro", + "Follow system color scheme": "Seguir o esquema de cores do sistema", + "Application theme:": "Tema da aplicación:", + "UniGetUI startup page:": "Páxina de inicio de UniGetUI:", + "Proxy settings": "Configuración do proxy", + "Other settings": "Outras opcións", + "Connect the internet using a custom proxy": "Conectarse a internet usando un proxy personalizado", + "Please note that not all package managers may fully support this feature": "Ten en conta que non todos os xestores de paquetes poden admitir completamente esta función", + "Proxy URL": "URL do proxy", + "Enter proxy URL here": "Introduce aquí a URL do proxy", + "Authenticate to the proxy with a user and a password": "Autenticarse no proxy cun usuario e un contrasinal", + "Internet and proxy settings": "Configuración de internet e do proxy", + "Package manager preferences": "Preferencias dos xestores de paquetes", + "Ready": "Listo", + "Not found": "Non atopado", + "Notification preferences": "Preferencias de notificacións", + "Notification types": "Tipos de notificación", + "The system tray icon must be enabled in order for notifications to work": "A icona da bandexa do sistema debe estar activada para que as notificacións funcionen", + "Enable UniGetUI notifications": "Activar as notificacións de UniGetUI", + "Show a notification when there are available updates": "Mostrar unha notificación cando haxa actualizacións dispoñibles", + "Show a silent notification when an operation is running": "Mostrar unha notificación silenciosa cando unha operación estea en execución", + "Show a notification when an operation fails": "Mostrar unha notificación cando falle unha operación", + "Show a notification when an operation finishes successfully": "Mostrar unha notificación cando unha operación remate correctamente", + "Concurrency and execution": "Concorrencia e execución", + "Automatic desktop shortcut remover": "Eliminador automático de accesos directos do escritorio", + "Choose how many operations should be performed in parallel": "Escoller cantas operacións se deben realizar en paralelo", + "Clear successful operations from the operation list after a 5 second delay": "Eliminar da lista de operacións as operacións completadas correctamente tras un atraso de 5 segundos", + "Download operations are not affected by this setting": "As operacións de descarga non se ven afectadas por esta configuración", + "You may lose unsaved data": "Podes perder datos sen gardar", + "Ask to delete desktop shortcuts created during an install or upgrade.": "Preguntar se se deben eliminar os accesos directos do escritorio creados durante unha instalación ou actualización.", + "Package update preferences": "Preferencias de actualización de paquetes", + "Update check frequency, automatically install updates, etc.": "Frecuencia de comprobación de actualizacións, instalación automática de actualizacións, etc.", + "Reduce UAC prompts, elevate installations by default, unlock certain dangerous features, etc.": "Reducir os avisos do UAC, elevar as instalacións por defecto, desbloquear determinadas funcións perigosas, etc.", + "Package operation preferences": "Preferencias das operacións de paquetes", + "Enable {pm}": "Activar {pm}", + "Not finding the file you are looking for? Make sure it has been added to path.": "Non atopas o ficheiro que procuras? Asegúrate de que se engadiu ao PATH.", + "Select the executable to be used. The following list shows the executables found by UniGetUI": "Selecciona o executábel que se vai usar. A seguinte lista mostra os executábeis atopados por UniGetUI", + "For security reasons, changing the executable file is disabled by default": "Por razóns de seguridade, cambiar o ficheiro executábel está desactivado por defecto", + "Change this": "Cambiar isto", + "Copy path": "Copiar ruta", + "Current executable file:": "Ficheiro executábel actual:", + "Ignore packages from {pm} when showing a notification about updates": "Ignorar os paquetes de {pm} ao mostrar unha notificación sobre actualizacións", + "Update security": "Seguridade das actualizacións", + "Use global setting": "Usar a configuración global", + "Minimum age for updates": "Antigüidade mínima das actualizacións", + "e.g. 10": "p. ex. 10", + "Custom minimum age (days)": "Antigüidade mínima personalizada (días)", + "{pm} does not provide release dates for its packages, so this setting will have no effect": "{pm} non fornece datas de lanzamento para os seus paquetes, polo que esta configuración non terá efecto", + "{pm} only provides release dates for some of its packages, so this setting will only apply to those packages": "{pm} só proporciona datas de publicación para algúns dos seus paquetes, polo que esta opción só se aplicará a eses paquetes", + "Override the global minimum update age for this package manager": "Substituír a antigüidade mínima global das actualizacións para este xestor de paquetes", + "View {0} logs": "Ver os rexistros de {0}", + "If Python cannot be found or is not listing packages but is installed on the system, ": "Se non se atopa Python ou non está a listar paquetes pero está instalado no sistema, ", + "Advanced options": "Opcións avanzadas", + "WinGet command-line tool": "Ferramenta de liña de ordes de WinGet", + "Choose which command-line tool UniGetUI uses for WinGet operations when the COM API is not used": "Escolla que ferramenta de liña de ordes usa UniGetUI para as operacións de WinGet cando non se usa a COM API", + "WinGet COM API": "API COM de WinGet", + "Choose whether UniGetUI can use the WinGet COM API before falling back to the command-line tool": "Escolla se UniGetUI pode usar a COM API de WinGet antes de recorrer á ferramenta de liña de ordes", + "Reset WinGet": "Restablecer WinGet", + "This may help if no packages are listed": "Isto pode axudar se non se listan paquetes", + "Force install location parameter when updating packages with custom locations": "Forzar o parámetro de localización de instalación ao actualizar paquetes con localizacións personalizadas", + "Install Scoop": "Instalar Scoop", + "Uninstall Scoop (and its packages)": "Desinstalar Scoop (e os seus paquetes)", + "Run cleanup and clear cache": "Executar a limpeza e limpar a caché", + "Run": "Executar", + "Enable Scoop cleanup on launch": "Activar a limpeza de Scoop ao iniciar", + "Default vcpkg triplet": "Triplete predeterminado de vcpkg", + "Change vcpkg root location": "Cambiar a localización raíz de vcpkg", + "Reset vcpkg root location": "Restablecer a localización raíz de vcpkg", + "Open vcpkg root location": "Abrir a localización raíz de vcpkg", + "Language, theme and other miscellaneous preferences": "Idioma, tema e outras preferencias diversas", + "Show notifications on different events": "Mostrar notificacións en distintos eventos", + "Change how UniGetUI checks and installs available updates for your packages": "Cambiar como UniGetUI comproba e instala as actualizacións dispoñibles para os teus paquetes", + "Automatically save a list of all your installed packages to easily restore them.": "Gardar automaticamente unha lista de todos os paquetes instalados para poder restauralos facilmente.", + "Enable and disable package managers, change default install options, etc.": "Activar e desactivar xestores de paquetes, cambiar as opcións predeterminadas de instalación, etc.", + "Internet connection settings": "Configuración da conexión a Internet", + "Proxy settings, etc.": "Configuración do proxy, etc.", + "Beta features and other options that shouldn't be touched": "Funcións beta e outras opcións que non se deberían tocar", + "Reload sources": "Recargar orixes", + "Delete source": "Eliminar orixe", + "Known sources": "Orixes coñecidas", + "Update checking": "Comprobación de actualizacións", + "Automatic updates": "Actualizacións automáticas", + "Check for package updates periodically": "Comprobar periodicamente as actualizacións dos paquetes", + "Check for updates every:": "Comprobar actualizacións cada:", + "Install available updates automatically": "Instalar automaticamente as actualizacións dispoñibles", + "Do not automatically install updates when the network connection is metered": "Non instalar automaticamente as actualizacións cando a conexión de rede sexa de uso medido", + "Do not automatically install updates when the device runs on battery": "Non instalar automaticamente as actualizacións cando o dispositivo estea funcionando con batería", + "Do not automatically install updates when the battery saver is on": "Non instalar automaticamente as actualizacións cando o aforro de batería estea activado", + "Only show updates that are at least the specified number of days old": "Mostrar só as actualizacións que teñan polo menos o número especificado de días de antigüidade", + "Warn me when the installer URL host changes between the installed version and the new version (WinGet only)": "Avisarme cando o host do URL do instalador cambie entre a versión instalada e a nova versión (só WinGet)", + "Change how UniGetUI handles install, update and uninstall operations.": "Cambiar como UniGetUI xestiona as operacións de instalación, actualización e desinstalación.", + "Navigation": "Navegación", + "Check for UniGetUI updates": "Comprobar se hai actualizacións de UniGetUI", + "Quit UniGetUI": "Saír de UniGetUI", + "Filters": "Filtros", + "Sources": "Fontes", + "Search for packages to start": "Busca paquetes para comezar", + "Select all": "Seleccionar todo", + "Clear selection": "Limpar a selección", + "Instant search": "Busca instantánea", + "Distinguish between uppercase and lowercase": "Distinguir entre maiúsculas e minúsculas", + "Ignore special characters": "Ignorar os caracteres especiais", + "Search mode": "Modo de busca", + "Both": "Ambos", + "Exact match": "Coincidencia exacta", + "Show similar packages": "Mostrar paquetes semellantes", + "Loading": "Cargando", + "Package": "Paquete", + "More options": "Máis opcións", + "Order by:": "Ordenar por:", + "Name": "Nome", + "Id": "ID", + "Ascendant": "Ascendente", + "Descendant": "Descendente", + "View modes": "Modos de visualización", + "Reload": "Recargar", + "Closed": "Pechado", + "Ascending": "Ascendente", + "Descending": "Descendente", + "{0}: {1}, {2}": "{0}: {1}, {2}", + "Order by": "Ordenar por", + "No results were found matching the input criteria": "Non se atoparon resultados que coincidan cos criterios introducidos", + "No packages were found": "Non se atoparon paquetes", + "Loading packages": "Cargando paquetes", + "Skip integrity checks": "Omitir as comprobacións de integridade", + "Download selected installers": "Descargar os instaladores seleccionados", + "Install selection": "Instalar a selección", + "Install options": "Opcións de instalación", + "Add selection to bundle": "Engadir a selección ao lote", + "Download installer": "Descargar o instalador", + "Uninstall selection": "Desinstalar a selección", + "Uninstall options": "Opcións de desinstalación", + "Ignore selected packages": "Ignorar os paquetes seleccionados", + "Open install location": "Abrir a localización da instalación", + "Reinstall package": "Reinstalar o paquete", + "Uninstall package, then reinstall it": "Desinstalar o paquete e despois reinstalalo", + "Ignore updates for this package": "Ignorar as actualizacións deste paquete", + "WinGet malfunction detected": "Detectouse un fallo de WinGet", + "It looks like WinGet is not working properly. Do you want to attempt to repair WinGet?": "Parece que WinGet non está a funcionar correctamente. Queres intentar reparar WinGet?", + "Repair WinGet": "Reparar WinGet", + "Updates will no longer be ignored for {0}": "As actualizacións xa non se ignorarán para {0}", + "Updates are now ignored for {0}": "As actualizacións agora ignóranse para {0}", + "Do not ignore updates for this package anymore": "Deixar de ignorar as actualizacións deste paquete", + "Add packages or open an existing package bundle": "Engadir paquetes ou abrir un lote de paquetes existente", + "Add packages to start": "Engadir paquetes para comezar", + "The current bundle has no packages. Add some packages to get started": "O lote actual non ten paquetes. Engade algúns paquetes para comezar", + "New": "Novo", + "Save as": "Gardar como", + "Create .ps1 script": "Crear un script .ps1", + "Remove selection from bundle": "Eliminar a selección do lote", + "Skip hash checks": "Omitir as comprobacións de hash", + "The package bundle is not valid": "O lote de paquetes non é válido", + "The bundle you are trying to load appears to be invalid. Please check the file and try again.": "O lote que intentas cargar parece non ser válido. Comproba o ficheiro e téntao de novo.", + "Package bundle": "Lote de paquetes", + "Could not create bundle": "Non se puido crear o lote", + "The package bundle could not be created due to an error.": "Non se puido crear o lote de paquetes debido a un erro.", + "Install script": "Script de instalación", + "PowerShell script": "Script de PowerShell", + "The installation script saved to {0}": "O script de instalación gardouse en {0}", + "An error occurred": "Produciuse un erro", + "An error occurred while attempting to create an installation script:": "Produciuse un erro ao tentar crear un script de instalación:", + "Hooray! No updates were found.": "Hurra! Non se atoparon actualizacións.", + "Uninstall selected packages": "Desinstalar os paquetes seleccionados", + "Update selection": "Actualizar a selección", + "Update options": "Opcións de actualización", + "Uninstall package, then update it": "Desinstalar o paquete e despois actualizalo", + "Uninstall package": "Desinstalar o paquete", + "Skip this version": "Omitir esta versión", + "Pause updates for": "Pausar as actualizacións durante", + "User | Local": "Usuario | Local", + "Machine | Global": "Máquina | Global", + "The default package manager for Debian/Ubuntu-based Linux distributions.
Contains: Debian/Ubuntu packages": "O xestor de paquetes predeterminado para distribucións Linux baseadas en Debian/Ubuntu.
Contén: Paquetes de Debian/Ubuntu", + "The Rust package manager.
Contains: Rust libraries and programs written in Rust": "O xestor de paquetes de Rust.
Contén: Bibliotecas de Rust e programas escritos en Rust", + "The classical package manager for windows. You'll find everything there.
Contains: General Software": "O xestor de paquetes clásico para Windows. Atoparás de todo alí.
Contén: Software xeral", + "The default package manager for RHEL/Fedora-based Linux distributions.
Contains: RPM packages": "O xestor de paquetes predeterminado para distribucións Linux baseadas en RHEL/Fedora.
Contén: Paquetes RPM", + "A repository full of tools and executables designed with Microsoft's .NET ecosystem in mind.
Contains: .NET related tools and scripts": "Un repositorio cheo de ferramentas e executables deseñados pensando no ecosistema .NET de Microsoft.
Contén: Ferramentas e scripts relacionados con .NET", + "The universal Linux package manager for desktop applications.
Contains: Flatpak applications from configured remotes": "O xestor universal de paquetes de Linux para aplicacións de escritorio.
Contén: aplicacións Flatpak dos remotos configurados", + "NuPkg (zipped manifest)": "NuPkg (manifesto comprimido)", + "The Missing Package Manager for macOS (or Linux).
Contains: Formulae, Casks": "O xestor de paquetes que lle faltaba a macOS (ou a Linux).
Contén: Fórmulas, Casks", + "Node JS's package manager. Full of libraries and other utilities that orbit the javascript world
Contains: Node javascript libraries and other related utilities": "O xestor de paquetes de Node JS. Cheo de bibliotecas e outras utilidades que orbitan o mundo de JavaScript
Contén: Bibliotecas JavaScript de Node e outras utilidades relacionadas", + "The default package manager for Arch Linux and its derivatives.
Contains: Arch Linux packages": "O xestor de paquetes predeterminado para Arch Linux e os seus derivados.
Contén: Paquetes de Arch Linux", + "Python's library manager. Full of python libraries and other python-related utilities
Contains: Python libraries and related utilities": "O xestor de bibliotecas de Python. Cheo de bibliotecas de Python e doutras utilidades relacionadas con Python
Contén: Bibliotecas de Python e utilidades relacionadas", + "PowerShell's package manager. Find libraries and scripts to expand PowerShell capabilities
Contains: Modules, Scripts, Cmdlets": "O xestor de paquetes de PowerShell. Atopa bibliotecas e scripts para ampliar as capacidades de PowerShell
Contén: Módulos, scripts, cmdlets", + "extracted": "extraído", + "Scoop package": "paquete de Scoop", + "Great repository of unknown but useful utilities and other interesting packages.
Contains: Utilities, Command-line programs, General Software (extras bucket required)": "Gran repositorio de utilidades descoñecidas pero útiles e doutros paquetes interesantes.
Contén: Utilidades, programas de liña de comandos, software xeral (requírese o bucket extras)", + "The universal Linux package manager by Canonical.
Contains: Snap packages from the Snapcraft store": "O xestor de paquetes universal de Linux de Canonical.
Contén: Paquetes Snap da tenda Snapcraft", + "library": "biblioteca", + "feature": "característica", + "A popular C/C++ library manager. Full of C/C++ libraries and other C/C++-related utilities
Contains: C/C++ libraries and related utilities": "Un popular xestor de bibliotecas de C/C++. Cheo de bibliotecas de C/C++ e doutras utilidades relacionadas con C/C++
Contén: Bibliotecas de C/C++ e utilidades relacionadas", + "option": "opción", + "This package cannot be installed from an elevated context.": "Este paquete non pode instalarse desde un contexto elevado.", + "Please run UniGetUI as a regular user and try again.": "Executa UniGetUI como usuario normal e téntao de novo.", + "Please check the installation options for this package and try again": "Comproba as opcións de instalación deste paquete e téntao de novo", + "Microsoft's official package manager. Full of well-known and verified packages
Contains: General Software, Microsoft Store apps": "O xestor de paquetes oficial de Microsoft. Cheo de paquetes coñecidos e verificados
Contén: Software xeral, aplicacións de Microsoft Store", + "Local PC": "PC local", + "Android Subsystem": "Subsistema Android", + "Operation on queue (position {0})...": "Operación na cola (posición {0})...", + "Click here for more details": "Fai clic aquí para máis detalles", + "Operation canceled by user": "Operación cancelada polo usuario", + "Running PreOperation ({0}/{1})...": "Executando PreOperation ({0}/{1})...", + "PreOperation {0} out of {1} failed, and was tagged as necessary. Aborting...": "PreOperation {0} de {1} fallou e estaba marcada como necesaria. Abortando...", + "PreOperation {0} out of {1} finished with result {2}": "PreOperation {0} de {1} rematou co resultado {2}", + "Starting operation...": "Iniciando operación...", + "Running PostOperation ({0}/{1})...": "Executando PostOperation ({0}/{1})...", + "PostOperation {0} out of {1} failed, and was tagged as necessary. Aborting...": "PostOperation {0} de {1} fallou e estaba marcada como necesaria. Abortando...", + "PostOperation {0} out of {1} finished with result {2}": "PostOperation {0} de {1} rematou co resultado {2}", + "{package} installer download": "Descarga do instalador de {package}", + "{0} installer is being downloaded": "Estase descargando o instalador de {0}", + "Download succeeded": "Descarga completada correctamente", + "{package} installer was downloaded successfully": "O instalador de {package} descargouse correctamente", + "Download failed": "Fallou a descarga", + "{package} installer could not be downloaded": "Non foi posible descargar o instalador de {package}", + "{package} Installation": "Instalación de {package}", + "{0} is being installed": "Estase instalando {0}", + "Installation succeeded": "Instalación completada correctamente", + "{package} was installed successfully": "{package} instalouse correctamente", + "Installation failed": "Fallou a instalación", + "{package} could not be installed": "Non foi posible instalar {package}", + "{package} Update": "Actualización de {package}", + "Update succeeded": "Actualización completada correctamente", + "{package} was updated successfully": "{package} actualizouse correctamente", + "Update failed": "Fallou a actualización", + "{package} could not be updated": "Non foi posible actualizar {package}", + "{package} Uninstall": "Desinstalación de {package}", + "{0} is being uninstalled": "Estase desinstalando {0}", + "Uninstall succeeded": "Desinstalación completada correctamente", + "{package} was uninstalled successfully": "{package} desinstalouse correctamente", + "Uninstall failed": "Fallou a desinstalación", + "{package} could not be uninstalled": "Non foi posible desinstalar {package}", + "Adding source {source}": "Engadindo a fonte {source}", + "Adding source {source} to {manager}": "Engadindo a fonte {source} a {manager}", + "Source added successfully": "Fonte engadida correctamente", + "The source {source} was added to {manager} successfully": "A fonte {source} engadiuse a {manager} correctamente", + "Could not add source": "Non foi posible engadir a fonte", + "Could not add source {source} to {manager}": "Non foi posible engadir a fonte {source} a {manager}", + "Removing source {source}": "Eliminando a fonte {source}", + "Removing source {source} from {manager}": "Eliminando a fonte {source} de {manager}", + "Source removed successfully": "Fonte eliminada correctamente", + "The source {source} was removed from {manager} successfully": "A fonte {source} eliminouse de {manager} correctamente", + "Could not remove source": "Non foi posible eliminar a fonte", + "Could not remove source {source} from {manager}": "Non foi posible eliminar a fonte {source} de {manager}", + "The package manager \"{0}\" was not found": "Non se atopou o xestor de paquetes \"{0}\"", + "The package manager \"{0}\" is disabled": "O xestor de paquetes \"{0}\" está desactivado", + "There is an error with the configuration of the package manager \"{0}\"": "Hai un erro na configuración do xestor de paquetes \"{0}\"", + "The package \"{0}\" was not found on the package manager \"{1}\"": "O paquete \"{0}\" non se atopou no xestor de paquetes \"{1}\"", + "{0} is disabled": "{0} está desactivado", + "{0} weeks": "{0} semanas", + "1 month": "1 mes", + "{0} months": "{0} meses", + "Something went wrong": "Algo saíu mal", + "An interal error occurred. Please view the log for further details.": "Produciuse un erro interno. Consulta o rexistro para máis detalles.", + "No applicable installer was found for the package {0}": "Non se atopou ningún instalador aplicable para o paquete {0}", + "Integrity checks will not be performed during this operation": "Non se realizarán comprobacións de integridade durante esta operación", + "This is not recommended.": "Isto non se recomenda.", + "Run now": "Executar agora", + "Run next": "Executar a continuación", + "Run last": "Executar ao final", + "Show in explorer": "Mostrar no explorador", + "Checked": "Marcado", + "Unchecked": "Desmarcado", + "This package is already installed": "Este paquete xa está instalado", + "This package can be upgraded to version {0}": "Este paquete pode actualizarse á versión {0}", + "Updates for this package are ignored": "As actualizacións deste paquete están ignoradas", + "This package is being processed": "Este paquete estase procesando", + "This package is not available": "Este paquete non está dispoñible", + "Select the source you want to add:": "Selecciona a fonte que queres engadir:", + "Source name:": "Nome da fonte:", + "Source URL:": "URL da fonte:", + "An error occurred when adding the source: ": "Produciuse un erro ao engadir a fonte: ", + "Package management made easy": "Xestión de paquetes sinxela", + "version {0}": "versión {0}", + "[RAN AS ADMINISTRATOR]": "[EXECUTADO COMO ADMINISTRADOR]", + "Portable mode": "Modo portátil\n", + "DEBUG BUILD": "COMPILACIÓN DE DEPURACIÓN", + "Here you can change UniGetUI's behaviour regarding the following shortcuts. Checking a shortcut will make UniGetUI delete it if if gets created on a future upgrade. Unchecking it will keep the shortcut intact": "Aquí podes cambiar o comportamento de UniGetUI con respecto aos seguintes atallos. Se marcas un atallo, UniGetUI eliminararao se se crea nunha futura actualización. Se o desmarcas, o atallo conservarase", + "Manual scan": "Análise manual", + "Existing shortcuts on your desktop will be scanned, and you will need to pick which ones to keep and which ones to remove.": "Analizaranse os atallos existentes no teu escritorio e terás que escoller cales queres conservar e cales queres eliminar.", + "Delete?": "Eliminar?", + "I understand": "Entendo", + "Chocolatey setup changed": "A configuración de Chocolatey cambiou", + "UniGetUI no longer includes its own private Chocolatey installation. A legacy UniGetUI-managed Chocolatey installation was detected for this user profile, but system Chocolatey was not found. Chocolatey will stay unavailable in UniGetUI until Chocolatey is installed on the system and UniGetUI is restarted. Applications previously installed through UniGetUI's bundled Chocolatey may still appear under other sources such as Local PC or WinGet.": "UniGetUI xa non inclúe a súa propia instalación privada de Chocolatey. Detectouse unha instalación de Chocolatey herdada xestionada por UniGetUI para este perfil de usuario, pero non se atopou Chocolatey no sistema. Chocolatey permanecerá non dispoñible en UniGetUI ata que Chocolatey se instale no sistema e se reinicie UniGetUI. As aplicacións instaladas previamente a través do Chocolatey incluído en UniGetUI aínda poden aparecer baixo outras orixes como PC local ou WinGet.", + "NOTE: This troubleshooter can be disabled from UniGetUI Settings, on the WinGet section": "NOTA: Este solucionador de problemas pódese desactivar na Configuración de UniGetUI, na sección de WinGet", + "Restart": "Reiniciar", + "Are you sure you want to delete all shortcuts?": "Seguro que queres eliminar todos os atallos?", + "Any new shorcuts created during an install or an update operation will be deleted automatically, instead of showing a confirmation prompt the first time they are detected.": "Calquera atallo novo creado durante unha instalación ou unha actualización eliminarase automaticamente, en vez de mostrar unha mensaxe de confirmación a primeira vez que se detecte.", + "Any shorcuts created or modified outside of UniGetUI will be ignored. You will be able to add them via the {0} button.": "Ignoraranse os atallos creados ou modificados fóra de UniGetUI. Poderás engadilos mediante o botón {0}.", + "Are you really sure you want to enable this feature?": "Seguro de verdade que queres activar esta función?", + "No new shortcuts were found during the scan.": "Non se atopou ningún atallo novo durante a análise.", + "How to add packages to a bundle": "Como engadir paquetes a un lote", + "In order to add packages to a bundle, you will need to: ": "Para engadir paquetes a un lote, terás que: ", + "1. Navigate to the \"{0}\" or \"{1}\" page.": "1. Vai á páxina \"{0}\" ou \"{1}\".", + "2. Locate the package(s) you want to add to the bundle, and select their leftmost checkbox.": "2. Localiza o(s) paquete(s) que queres engadir ao lote e selecciona a súa caixa da esquerda.", + "3. When the packages you want to add to the bundle are selected, find and click the option \"{0}\" on the toolbar.": "3. Cando estean seleccionados os paquetes que queres engadir ao lote, busca e fai clic na opción \"{0}\" da barra de ferramentas.", + "4. Your packages will have been added to the bundle. You can continue adding packages, or export the bundle.": "4. Os teus paquetes xa estarán engadidos ao lote. Podes seguir engadindo paquetes ou exportar o lote.", + "Which backup do you want to open?": "Que copia de seguranza queres abrir?", + "Select the backup you want to open. Later, you will be able to review which packages you want to install.": "Selecciona a copia de seguranza que queres abrir. Máis tarde poderás revisar que paquetes queres restaurar.", + "There are ongoing operations. Quitting UniGetUI may cause them to fail. Do you want to continue?": "Hai operacións en curso. Saír de UniGetUI pode facer que fallen. Queres continuar?", + "UniGetUI or some of its components are missing or corrupt.": "UniGetUI ou algún dos seus compoñentes non está ou está danado.", + "It is strongly recommended to reinstall UniGetUI to adress the situation.": "Recoméndase encarecidamente reinstalar UniGetUI para resolver a situación.", + "Refer to the UniGetUI Logs to get more details regarding the affected file(s)": "Consulta os rexistros de UniGetUI para obter máis detalles sobre o(s) ficheiro(s) afectado(s)", + "Integrity checks can be disabled from the Experimental Settings": "As comprobacións de integridade pódense desactivar na Configuración experimental", + "Repair UniGetUI": "Reparar UniGetUI", + "Live output": "Saída en directo", + "This package bundle had some settings that are potentially dangerous, and may be ignored by default.": "Este lote de paquetes tiña algunhas opcións potencialmente perigosas e poden ignorarse de maneira predeterminada.", + "Entries that show in YELLOW will be IGNORED.": "As entradas que aparezan en AMARELO serán IGNORADAS.", + "Entries that show in RED will be IMPORTED.": "As entradas que aparezan en VERMELLO serán IMPORTADAS.", + "You can change this behavior on UniGetUI security settings.": "Podes cambiar este comportamento na configuración de seguranza de UniGetUI.", + "Open UniGetUI security settings": "Abrir a configuración de seguranza de UniGetUI", + "Should you modify the security settings, you will need to open the bundle again for the changes to take effect.": "Se modificas a configuración de seguranza, terás que volver abrir o lote para que os cambios teñan efecto.", + "Details of the report:": "Detalles do informe:", + "Are you sure you want to create a new package bundle? ": "Seguro que queres crear un novo lote de paquetes? ", + "Any unsaved changes will be lost": "Perderanse os cambios non gardados", + "Warning!": "Aviso!", + "For security reasons, custom command-line arguments are disabled by default. Go to UniGetUI security settings to change this. ": "Por motivos de seguranza, os argumentos personalizados da liña de comandos están desactivados de maneira predeterminada. Vai á configuración de seguranza de UniGetUI para cambialo. ", + "Change default options": "Cambiar as opcións predeterminadas", + "Ignore future updates for this package": "Ignorar futuras actualizacións deste paquete", + "For security reasons, pre-operation and post-operation scripts are disabled by default. Go to UniGetUI security settings to change this. ": "Por motivos de seguranza, os scripts previos e posteriores á operación están desactivados de maneira predeterminada. Vai á configuración de seguranza de UniGetUI para cambialo. ", + "You can define the commands that will be run before or after this package is installed, updated or uninstalled. They will be run on a command prompt, so CMD scripts will work here.": "Podes definir os comandos que se executarán antes ou despois de instalar, actualizar ou desinstalar este paquete. Executaranse nun símbolo do sistema, polo que os scripts de CMD funcionarán aquí.", + "Change this and unlock": "Cambia isto e desbloquea", + "{0} Install options are currently locked because {0} follows the default install options.": "As opcións de instalación de {0} están bloqueadas neste momento porque {0} segue as opcións de instalación predeterminadas.", + "Unset or unknown": "Sen definir ou descoñecido", + "This package has no screenshots or is missing the icon? Contrbute to UniGetUI by adding the missing icons and screenshots to our open, public database.": "Este paquete non ten capturas de pantalla ou falta a icona? Contribúe a UniGetUI engadindo as iconas e capturas de pantalla que faltan á nosa base de datos aberta e pública.", + "Become a contributor": "Faite colaborador", + "Update to {0} available": "Actualización a {0} dispoñible", + "Reinstall": "Reinstalar", + "Installer not available": "Instalador non dispoñible", + "Version:": "Versión:", + "UniGetUI Version {0}": "Versión de UniGetUI {0}", + "Performing backup, please wait...": "Realizando a copia de seguranza, agarda...", + "An error occurred while logging in: ": "Produciuse un erro ao iniciar sesión: ", + "Fetching available backups...": "Obtendo as copias de seguranza dispoñibles...", + "Done!": "Feito!", + "The cloud backup has been loaded successfully.": "A copia de seguranza na nube cargouse correctamente.", + "An error occurred while loading a backup: ": "Produciuse un erro ao cargar unha copia de seguranza: ", + "Backing up packages to GitHub Gist...": "Facendo unha copia de seguranza dos paquetes en GitHub Gist...", + "Backup Successful": "Copia de seguranza realizada correctamente", + "The cloud backup completed successfully.": "A copia de seguranza na nube completouse correctamente.", + "Could not back up packages to GitHub Gist: ": "Non se puido crear a copia de seguranza dos paquetes en GitHub Gist: ", + "It is not guaranteed that the provided credentials will be stored safely, so you may as well not use the credentials of your bank account": "Non se garante que as credenciais proporcionadas se vaian almacenar de forma segura, así que mellor non uses as credenciais da túa conta bancaria", + "Enable the automatic WinGet troubleshooter": "Activar o solucionador automático de problemas de WinGet", + "Add updates that fail with a 'no applicable update found' to the ignored updates list": "Engadir á lista de actualizacións ignoradas as actualizacións que fallan con 'no applicable update found'.", + "Invalid selection": "Selección non válida", + "No package was selected": "Non se seleccionou ningún paquete", + "More than 1 package was selected": "Seleccionouse máis de 1 paquete", + "List": "Lista", + "Grid": "Grella", + "Icons": "Iconas", + "\"{0}\" is a local package and does not have available details": "\"{0}\" é un paquete local e non ten detalles dispoñibles", + "\"{0}\" is a local package and is not compatible with this feature": "\"{0}\" é un paquete local e non é compatible con esta función", + "Add packages to bundle": "Engadir paquetes ao lote", + "Preparing packages, please wait...": "Preparando os paquetes, agarde...", + "Loading packages, please wait...": "Cargando os paquetes, agarde...", + "Saving packages, please wait...": "Gardando os paquetes, agarde...", + "The bundle was created successfully on {0}": "O lote creouse correctamente en {0}", + "User profile": "Perfil de usuario", + "Error": "Erro", + "Log in failed: ": "Fallou o inicio de sesión: ", + "Log out failed: ": "Fallou o peche de sesión: ", + "Package backup settings": "Configuración da copia de seguranza de paquetes", + "Manage UniGetUI autostart behaviour from the Settings app": "Xestionar o comportamento de inicio automático de UniGetUI", + "Choose how many operations shoulds be performed in parallel": "Escolle cantas operacións se deben realizar en paralelo", + "Something went wrong while launching the updater.": "Algo saíu mal ao iniciar o actualizador.", + "Please try again later": "Téntao de novo máis tarde", + "Show the release notes after UniGetUI is updated": "Mostrar as notas da versión despois de actualizar UniGetUI" +} diff --git a/src/Languages/lang_gu.json b/src/Languages/lang_gu.json new file mode 100644 index 0000000..9a6dbb2 --- /dev/null +++ b/src/Languages/lang_gu.json @@ -0,0 +1,850 @@ +{ + "{0} of {1} operations completed": "{1} માંથી {0} ક્રિયાઓ પૂર્ણ થઈ", + "{0} is now {1}": "{0} હવે {1} છે", + "Enabled": "સક્રિય", + "Disabled": "નિષ્ક્રિય", + "Privacy": "ગોપનીયતા", + "Hide my username from the logs": "લોગમાંથી મારું વપરાશકર્તાનામ છુપાવો", + "Replaces your username with **** in the logs. Restart UniGetUI to also hide it from already-recorded entries.": "લોગમાં તમારા વપરાશકર્તાનામને **** થી બદલે છે. પહેલેથી નોંધાયેલી એન્ટ્રીઓમાંથી પણ તેને છુપાવવા માટે UniGetUI ફરી શરૂ કરો.", + "Your last update attempt did not complete.": "તમારા છેલ્લા અપડેટનો પ્રયાસ પૂર્ણ થયો નહીં.", + "UniGetUI could not confirm whether the update succeeded. Open the log to see what happened.": "UniGetUI અપડેટ સફળ થયું કે નહીં તેની પુષ્ટિ કરી શક્યું નથી. શું થયું તે જોવા માટે લોગ ખોલો.", + "View log": "લોગ જુઓ", + "The installer reported success but did not restart UniGetUI.": "સ્થાપકે સફળતા દર્શાવી પરંતુ UniGetUI ફરી શરૂ કર્યું નથી.", + "The installer failed to initialize.": "સ્થાપક પ્રારંભ કરવામાં નિષ્ફળ ગયો.", + "Setup was canceled before installation began.": "સ્થાપન શરૂ થાય તે પહેલાં સેટઅપ રદ કરવામાં આવ્યું.", + "A fatal error occurred during the preparation phase.": "તૈયારી તબક્કા દરમિયાન ગંભીર ભૂલ આવી.", + "A fatal error occurred during installation.": "સ્થાપન દરમિયાન ગંભીર ભૂલ આવી.", + "Installation was canceled while in progress.": "સ્થાપન ચાલુ હોય ત્યારે રદ કરવામાં આવ્યું.", + "The installer was terminated by another process.": "સ્થાપક બીજી પ્રક્રિયા દ્વારા સમાપ્ત કરવામાં આવ્યો.", + "The preparation phase determined the installation cannot proceed.": "તૈયારી તબક્કાએ નક્કી કર્યું કે સ્થાપન આગળ વધી શકતું નથી.", + "The installer could not start. UniGetUI may already be running, or you do not have permission to install.": "સ્થાપક શરૂ થઈ શક્યો નથી. UniGetUI કદાચ પહેલેથી ચાલી રહ્યું છે, અથવા તમને સ્થાપિત કરવાની પરવાનગી નથી.", + "Unexpected installer error.": "અનપેક્ષિત સ્થાપક ભૂલ.", + "We are checking for updates.": "અમે updates તપાસી રહ્યા છીએ.", + "Please wait": "કૃપા કરીને રાહ જુઓ", + "Great! You are on the latest version.": "બહુ સારું! તમે તાજેતરની આવૃત્તિ પર છો.", + "There are no new UniGetUI versions to be installed": "install કરવા માટે UniGetUI ની કોઈ નવી versions નથી", + "UniGetUI version {0} is being downloaded.": "UniGetUI version {0} download થઈ રહ્યું છે.", + "This may take a minute or two": "આમાં એક-બે મિનિટ લાગી શકે છે", + "The installer authenticity could not be verified.": "installer ની authenticity ચકાસી શકાઈ નથી.", + "The update process has been aborted.": "update process બંધ કરી દેવાઈ છે.", + "Auto-update is not yet available on this platform.": "આ પ્લેટફોર્મ પર આપમેળે અપડેટ હજી ઉપલબ્ધ નથી.", + "Please update UniGetUI manually.": "કૃપા કરીને UniGetUI ને મેન્યુઅલી અપડેટ કરો.", + "An error occurred when checking for updates: ": "અપડેટ્સ માટે તપાસ કરતી વખતે એક ભૂલ આવી:", + "The updater could not be launched.": "અપડેટર શરૂ કરી શકાયો નથી.", + "The operating system did not start the installer process.": "ઓપરેટિંગ સિસ્ટમે સ્થાપક પ્રક્રિયા શરૂ કરી નથી.", + "UniGetUI is being updated...": "UniGetUI update થઈ રહ્યું છે...", + "Update installed.": "અપડેટ સ્થાપિત થયું.", + "UniGetUI was updated successfully, but this running copy was not replaced. This usually means you are running a development build. Close this copy and start the newly-installed version to finish.": "UniGetUI સફળતાપૂર્વક અપડેટ થયું, પરંતુ ચાલતી આ નકલ બદલાઈ નથી. સામાન્ય રીતે તેનો અર્થ છે કે તમે ડેવલપમેન્ટ બિલ્ડ ચલાવી રહ્યા છો. પૂર્ણ કરવા માટે આ નકલ બંધ કરો અને નવી સ્થાપિત આવૃત્તિ શરૂ કરો.", + "The update could not be applied.": "અપડેટ લાગુ કરી શકાયું નથી.", + "Installer exit code {0}: {1}": "સ્થાપક એક્ઝિટ કોડ {0}: {1}", + "Update cancelled.": "અપડેટ રદ થયું.", + "Authentication was cancelled.": "પ્રમાણીકરણ રદ થયું.", + "Installer exit code {0}": "સ્થાપક એક્ઝિટ કોડ {0}", + "Operation in progress": "operation ચાલુ છે", + "Please wait...": "કૃપા કરીને રાહ જુઓ...", + "Success!": "સફળતા!", + "Failed": "નિષ્ફળ", + "An error occurred while processing this package": "આ પેકેજની પ્રક્રિયા કરતી વખતે એક ભૂલ આવી", + "Installer": "સ્થાપક", + "Executable": "એક્ઝિક્યુટેબલ", + "MSI": "MSI", + "Compressed file": "સંકુચિત ફાઇલ", + "MSIX": "MSIX", + "WinGet was repaired successfully": "WinGet સફળતાપૂર્વક repair થયું", + "It is recommended to restart UniGetUI after WinGet has been repaired": "WinGet repair થયા પછી UniGetUI restart કરવાની ભલામણ થાય છે", + "WinGet could not be repaired": "WinGet repair થઈ શક્યું નથી", + "An unexpected issue occurred while attempting to repair WinGet. Please try again later": "WinGet સમારકામ કરવાનો પ્રયાસ કરતી વખતે અનપેક્ષિત સમસ્યા આવી. કૃપા કરીને પછી ફરી પ્રયાસ કરો", + "Log in to enable cloud backup": "cloud backup સક્રિય કરવા માટે Log in કરો", + "Backup Failed": "બેકઅપ નિષ્ફળ ગયું", + "Downloading backup...": "બેકઅપ download થઈ રહી છે...", + "An update was found!": "અપડેટ મળ્યું!", + "{0} can be updated to version {1}": "{0} ને version {1} સુધી update કરી શકાય છે", + "Updates found!": "Updates મળ્યા!", + "{0} packages can be updated": "{0} packages update થઈ શકે છે", + "{0} is being updated to version {1}": "{0} version {1} સુધી update થઈ રહ્યું છે", + "{0} packages are being updated": "{0} packages update થઈ રહ્યા છે", + "You have currently version {0} installed": "તમારા પાસે હાલમાં version {0} install છે", + "Desktop shortcut created": "Desktop shortcut બનાવાયો", + "UniGetUI has detected a new desktop shortcut that can be deleted automatically.": "UniGetUI એ એક નવી desktop shortcut શોધી છે જેને આપમેળે delete કરી શકાય છે.", + "{0} desktop shortcuts created": "{0} desktop shortcuts બનાવાઈ", + "UniGetUI has detected {0} new desktop shortcuts that can be deleted automatically.": "UniGetUI એ {0} નવી desktop shortcuts શોધી છે જેને આપમેળે delete કરી શકાય છે.", + "Attention required": "ધ્યાન જરૂરી", + "Restart required": "Restart જરૂરી છે", + "1 update is available": "1 અપડેટ ઉપલબ્ધ છે", + "{0} updates are available": "{0} updates ઉપલબ્ધ છે", + "Everything is up to date": "બધું update છે", + "Discover Packages": "પેકેજો શોધો", + "Available Updates": "ઉપલબ્ધ સુધારાઓ", + "Installed Packages": "સ્થાપિત પેકેજો", + "UniGetUI Version {0} by Devolutions": "Devolutions દ્વારા UniGetUI સંસ્કરણ {0}", + "Show UniGetUI": "UniGetUI બતાવો", + "Quit": "બહાર નીકળો", + "Are you sure?": "શું તમને ખાતરી છે?", + "Do you really want to uninstall {0}?": "શું તમે ખરેખર {0} uninstall કરવા માંગો છો?", + "Do you really want to uninstall the following {0} packages?": "શું તમે ખરેખર નીચેના {0} packages uninstall કરવા માંગો છો?", + "No": "ના", + "Yes": "હા", + "Partial": "આંશિક", + "View on UniGetUI": "UniGetUI પર જુઓ", + "Update": "અપડેટ", + "Open UniGetUI": "UniGetUI ખોલો", + "Update all": "બધું update કરો", + "Update now": "હવે update કરો", + "Installer host changed since the installed version.\n": "સ્થાપિત આવૃત્તિથી સ્થાપક હોસ્ટ બદલાઈ ગયો છે.\n", + "This package is on the queue": "આ package queue માં છે", + "installing": "install થઈ રહ્યું છે", + "updating": "update થઈ રહ્યું છે", + "uninstalling": "uninstall થઈ રહ્યું છે", + "installed": "install થયું", + "Retry": "ફરી પ્રયાસ કરો", + "Install": "સ્થાપિત કરો", + "Uninstall": "અનઇન્સ્ટોલ કરો", + "Open": "ખોલો", + "Operation profile:": "પ્રક્રિયા પ્રોફાઇલ:", + "Follow the default options when installing, upgrading or uninstalling this package": "આ package install, upgrade અથવા uninstall કરતી વખતે ડિફૉલ્ટ options અનુસરો", + "The following settings will be applied each time this package is installed, updated or removed.": "દર વખતે આ package install, update અથવા remove થાય ત્યારે નીચેની settings લાગુ થશે.", + "Version to install:": "install કરવાની version:", + "Architecture to install:": "સ્થાપનાની સંરચના", + "Installation scope:": "સ્થાપન વિસ્તાર:", + "Install location:": "સ્થાપન સ્થાન:", + "Select": "પસંદ કરો", + "Reset": "Reset કરો", + "Custom install arguments:": "custom install arguments:", + "Custom update arguments:": "custom update arguments:", + "Custom uninstall arguments:": "custom uninstall arguments:", + "Pre-install command:": "સ્થાપન પહેલાંનો આદેશ:", + "Post-install command:": "સ્થાપન પછીનો આદેશ:", + "Abort install if pre-install command fails": "pre-install command નિષ્ફળ જાય તો સ્થાપન રદ કરો", + "Pre-update command:": "અપડેટ પહેલાંનો આદેશ:", + "Post-update command:": "અપડેટ પછીનો આદેશ:", + "Abort update if pre-update command fails": "pre-update command નિષ્ફળ જાય તો અપડેટ રદ કરો", + "Pre-uninstall command:": "અનઇન્સ્ટોલ પહેલાંનો આદેશ:", + "Post-uninstall command:": "અનઇન્સ્ટોલ પછીનો આદેશ:", + "Abort uninstall if pre-uninstall command fails": "pre-uninstall command નિષ્ફળ જાય તો uninstall રદ કરો", + "Command-line to run:": "ચાલાવવાનો command-line:", + "Save and close": "સાચવો અને બંધ કરો", + "General": "સામાન્ય", + "Architecture & Location": "આર્કિટેક્ચર અને સ્થાન", + "Command-line": "કમાન્ડ-લાઇન", + "Close apps": "એપ્સ બંધ કરો", + "Pre/Post install": "સ્થાપન પહેલાં/પછી", + "Select the processes that should be closed before this package is installed, updated or uninstalled.": "આ package install, update અથવા uninstall થાય તે પહેલાં બંધ કરવાના processes પસંદ કરો.", + "Write here the process names here, separated by commas (,)": "અહીં process names comma (,) વડે અલગ કરીને લખો", + "Try to kill the processes that refuse to close when requested to": "જ્યારે બંધ કરવા કહેવામાં આવે ત્યારે બંધ થવાથી ઇનકાર કરતી processes ને kill કરવાનો પ્રયાસ કરો", + "Run as admin": "admin તરીકે ચલાવો", + "Interactive installation": "પરસ્પરક્રિયાત્મક સ્થાપન", + "Skip hash check": "hash check છોડો", + "Uninstall previous versions when updated": "update થયા પછી અગાઉની versions uninstall કરો", + "Skip minor updates for this package": "આ package માટે minor updates છોડો", + "Automatically update this package": "આ પેકેજ આપમેળે અપડેટ કરો", + "{0} installation options": "{0} સ્થાપન વિકલ્પો", + "Latest": "તાજેતરનું", + "PreRelease": "પૂર્વ-પ્રકાશન", + "Default": "ડિફૉલ્ટ", + "Manage ignored updates": "ignored updates સંચાલન કરો", + "The packages listed here won't be taken in account when checking for updates. Double-click them or click the button on their right to stop ignoring their updates.": "અહીં સૂચિબદ્ધ packages ને updates તપાસતી વખતે ધ્યાનમાં લેવામાં આવશે નહીં. તેમના updates ને ignore કરવાનું બંધ કરવા માટે packages પર double-click કરો અથવા તેમની જમણી બાજુના button પર click કરો.", + "Reset list": "યાદી reset કરો", + "Do you really want to reset the ignored updates list? This action cannot be reverted": "શું તમે ખરેખર અવગણાયેલા updates ની યાદી reset કરવા માંગો છો? આ action પાછું ફેરવી શકાતું નથી", + "No ignored updates": "કોઈ અવગણાયેલા updates નથી", + "Package Name": "પેકેજ નામ", + "Package ID": "પેકેજ ID", + "Ignored version": "ignored આવૃત્તિ", + "New version": "નવી આવૃત્તિ", + "Source": "સ્ત્રોત", + "All versions": "બધી આવૃત્તિઓ", + "Unknown": "અજ્ઞાત", + "Up to date": "તાજું", + "Package {name} from {manager}": "{manager} માંથી પેકેજ {name}", + "Remove {0} from ignored updates": "અવગણાયેલા અપડેટ્સમાંથી {0} દૂર કરો", + "Cancel": "રદ્દ", + "Administrator privileges": "સંચાલક વિશેષાધિકારો", + "This operation is running with administrator privileges.": "આ operation administrator privileges સાથે ચાલી રહી છે.", + "Interactive operation": "પરસ્પરક્રિયાત્મક પ્રક્રિયા", + "This operation is running interactively.": "આ operation interactive રીતે ચાલી રહી છે.", + "You will likely need to interact with the installer.": "તમને સંભવિત રીતે installer સાથે interact કરવાની જરૂર પડશે.", + "Integrity checks skipped": "Integrity checks skip કરવામાં આવી", + "Integrity checks will not be performed during this operation.": "આ પ્રક્રિયા દરમિયાન Integrity checks કરવામાં આવશે નહીં.", + "Proceed at your own risk.": "તમારા જોખમે આગળ વધો.", + "Close": "બંધ કરો", + "Loading...": "load થઈ રહ્યું છે...", + "Installer SHA256": "સ્થાપક SHA256", + "Homepage": "મુખ્ય પૃષ્ઠ", + "Author": "લેખક", + "Publisher": "પ્રકાશક", + "License": "લાઇસન્સ", + "Manifest": "મેનિફેસ્ટ", + "Installer Type": "સ્થાપક પ્રકાર", + "Size": "કદ", + "Installer URL": "સ્થાપક URL", + "Last updated:": "છેલ્લે update થયું:", + "Release notes URL": "પ્રકાશન નોંધો URL", + "Package details": "પેકેજ વિગતો", + "Dependencies:": "નિર્ભરતાઓ:", + "Release notes": "પ્રકાશન નોંધો", + "Screenshots": "સ્ક્રીનશોટ", + "This package has no screenshots or is missing the icon? Contribute to UniGetUI by adding the missing icons and screenshots to our open, public database.": "આ પેકેજમાં કોઈ સ્ક્રીનશોટ નથી અથવા આઇકન ખૂટે છે? ખૂટતા આઇકન અને સ્ક્રીનશોટ અમારી ખુલ્લી, જાહેર ડેટાબેઝમાં ઉમેરીને UniGetUI માં યોગદાન આપો.", + "Version": "આવૃત્તિ", + "Install as administrator": "administrator તરીકે install કરો", + "Update to version {0}": "version {0} સુધી update કરો", + "Installed Version": "Installed આવૃત્તિ", + "Update as administrator": "administrator તરીકે update કરો", + "Interactive update": "પરસ્પરક્રિયાત્મક update", + "Uninstall as administrator": "administrator તરીકે uninstall કરો", + "Interactive uninstall": "પરસ્પરક્રિયાત્મક uninstall", + "Uninstall and remove data": "uninstall કરો અને data દૂર કરો", + "Not available": "ઉપલબ્ધ નથી", + "Installer SHA512": "સ્થાપક SHA512", + "Unknown size": "અજ્ઞાત કદ", + "No dependencies specified": "કોઈ dependencies નિર્ધારિત નથી", + "mandatory": "ફરજિયાત", + "optional": "વૈકલ્પિક", + "UniGetUI {0} is ready to be installed.": "UniGetUI {0} install કરવા માટે તૈયાર છે.", + "The update process will start after closing UniGetUI": "UniGetUI બંધ થયા પછી update process શરૂ થશે", + "UniGetUI has been ran as administrator, which is not recommended. When running UniGetUI as administrator, EVERY operation launched from UniGetUI will have administrator privileges. You can still use the program, but we highly recommend not running UniGetUI with administrator privileges.": "UniGetUI administrator તરીકે ચલાવવામાં આવ્યું છે, જે ભલામણ કરાતું નથી. UniGetUI ને administrator તરીકે ચલાવતી વખતે UniGetUI માંથી શરૂ થતી દરેક operation ને administrator privileges મળશે. તમે હજી પણ program નો ઉપયોગ કરી શકો છો, પરંતુ અમે UniGetUI ને administrator privileges સાથે ન ચલાવવાની ભારપૂર્વક ભલામણ કરીએ છીએ.", + "Share anonymous usage data": "anonymous usage data share કરો", + "UniGetUI collects anonymous usage data in order to improve the user experience.": "UniGetUI user experience સુધારવા માટે anonymous usage data એકત્રિત કરે છે.", + "Accept": "સ્વીકારો", + "Software Updates": "સોફ્ટવેર અપડેટ્સ", + "Package Bundles": "પેકેજ બંડલ્સ", + "Settings": "સેટિંગ્સ", + "Package Managers": "પેકેજ મેનેજર્સ", + "UniGetUI Log": "UniGetUI લોગ", + "Package Manager logs": "પેકેજ મેનેજર logs", + "Operation history": "operation history", + "Help": "મદદ", + "UniGetUI": "UniGetUI", + "You have installed UniGetUI Version {0}": "તમે UniGetUI Version {0} install કર્યું છે", + "Disclaimer": "અસ્વીકાર", + "UniGetUI is developed by Devolutions and is not affiliated with any of the compatible package managers.": "UniGetUI Devolutions દ્વારા વિકસાવવામાં આવ્યું છે અને તે કોઈપણ સુસંગત પેકેજ મેનેજરો સાથે સંકળાયેલું નથી.", + "UniGetUI wouldn't have been possible without the help of the contributors. Thank you all 🥳": "contributors ની મદદ વગર UniGetUI શક્ય ન હોત. તમે સૌનો આભાર 🥳", + "UniGetUI uses the following libraries. Without them, UniGetUI wouldn't have been possible.": "UniGetUI નીચેની libraries નો ઉપયોગ કરે છે. તેમના વગર UniGetUI શક્ય ન હોત.", + "{0} homepage": "{0} મુખ્ય પૃષ્ઠ", + "UniGetUI has been translated to more than 40 languages thanks to the volunteer translators. Thank you 🤝": "સ્વયંસેવક translators ના કારણે UniGetUI નો અનુવાદ 40 થી વધુ ભાષાઓમાં થયો છે. આભાર 🤝", + "Verbose": "વિગતવાર", + "1 - Errors": "1 - ભૂલો", + "2 - Warnings": "2 - ચેતવણીઓ", + "3 - Information (less)": "3 - માહિતી (ઓછી)", + "4 - Information (more)": "4 - માહિતી (વધુ)", + "5 - information (debug)": "5 - માહિતી (debug)", + "Warning": "ચેતવણી", + "The following settings may pose a security risk, hence they are disabled by default.": "નીચેની settings security risk ઉભો કરી શકે છે, તેથી તે ડિફૉલ્ટ રીતે નિષ્ક્રિય છે.", + "Enable the settings below if and only if you fully understand what they do, and the implications they may have.": "નીચે આપેલી settings માત્ર ત્યારે જ સક્રિય કરો જો તમે તેઓ શું કરે છે તે સંપૂર્ણપણે સમજો છો અને તેમાં કયા અસરો હોઈ શકે છે.", + "The settings will list, in their descriptions, the potential security issues they may have.": "settings તેમની descriptions માં સંભવિત security issues ની યાદી બતાવશે.", + "The backup will include the complete list of the installed packages and their installation options. Ignored updates and skipped versions will also be saved.": "backup માં installed packages અને તેમની installation options ની સંપૂર્ણ યાદી શામેલ હશે. ignored updates અને skipped versions પણ સાચવવામાં આવશે.", + "The backup will NOT include any binary file nor any program's saved data.": "backup માં કોઈ binary file અથવા કોઈ program નું saved data શામેલ નહીં હોય.", + "The size of the backup is estimated to be less than 1MB.": "backup નું કદ 1MB થી ઓછું હોવાનો અંદાજ છે.", + "The backup will be performed after login.": "backup login પછી કરવામાં આવશે.", + "{pcName} installed packages": "{pcName} પર installed packages", + "Current status: Not logged in": "વર્તમાન સ્થિતિ: login થયેલ નથી", + "You are logged in as {0} (@{1})": "તમે {0} (@{1}) તરીકે logged in છો", + "Nice! Backups will be uploaded to a private gist on your account": "સરસ! backups તમારા account પર private gist માં upload થશે", + "Select backup": "backup પસંદ કરો", + "Settings imported from {0}": "{0} માંથી સેટિંગ્સ આયાત કરવામાં આવી", + "UniGetUI Settings": "UniGetUI સેટિંગ્સ", + "Settings exported to {0}": "સેટિંગ્સ {0} માં નિકાસ કરવામાં આવી", + "UniGetUI settings were reset": "UniGetUI સેટિંગ્સ રીસેટ કરવામાં આવી", + "Allow pre-release versions": "pre-release આવૃત્તિઓને મંજૂરી આપો", + "Apply": "લાગુ કરો", + "For security reasons, custom command-line arguments are disabled by default. Go to UniGetUI security settings to change this.": "સુરક્ષા કારણોસર, custom command-line arguments ડિફૉલ્ટ રીતે નિષ્ક્રિય છે. આ બદલવા માટે UniGetUI security settings માં જાઓ.", + "Go to UniGetUI security settings": "UniGetUI security settings માં જાઓ", + "The following options will be applied by default each time a {0} package is installed, upgraded or uninstalled.": "દર વખતે {0} package install, upgrade અથવા uninstall થાય ત્યારે નીચેના options ડિફૉલ્ટ રીતે લાગુ થશે.", + "Package's default": "Package નું default", + "Install location can't be changed for {0} packages": "{0} packages માટે install location બદલી શકાતું નથી", + "The local icon cache currently takes {0} MB": "local icon cache હાલમાં {0} MB લે છે", + "Username": "વપરાશકર્તા નામ", + "Password": "પાસવર્ડ", + "Credentials": "પ્રમાણપત્રો", + "It is not guaranteed that the provided credentials will be stored safely": "આપેલ credentials સુરક્ષિત રીતે સંગ્રહિત થશે તેની ખાતરી નથી", + "Partially": "આંશિક રીતે", + "Package manager": "પેકેજ મેનેજર", + "Compatible with proxy": "proxy સાથે સુસંગત", + "Compatible with authentication": "authentication સાથે સુસંગત", + "Proxy compatibility table": "પ્રોક્સી સુસંગતતા કોષ્ટક", + "{0} settings": "{0} સેટિંગ્સ", + "{0} status": "{0} સ્થિતિ", + "Default installation options for {0} packages": "{0} packages માટે ડિફૉલ્ટ installation options", + "Expand version": "આવૃત્તિ વિસ્તૃત કરો", + "The executable file for {0} was not found": "{0} માટે executable file મળી નથી", + "{pm} is disabled": "{pm} નિષ્ક્રિય છે", + "Enable it to install packages from {pm}.": "તેને {pm} માંથી packages install કરવા માટે સક્રિય કરો.", + "{pm} is enabled and ready to go": "{pm} સક્રિય છે અને તૈયાર છે", + "{pm} version:": "{pm} આવૃત્તિ:", + "{pm} was not found!": "{pm} મળ્યું નથી!", + "You may need to install {pm} in order to use it with UniGetUI.": "UniGetUI સાથે તેનો ઉપયોગ કરવા માટે તમને {pm} install કરવાની જરૂર પડી શકે છે.", + "Scoop Installer - UniGetUI": "Scoop સ્થાપક - UniGetUI", + "Scoop Uninstaller - UniGetUI": "Scoop અનઇન્સ્ટોલર - UniGetUI", + "Clearing Scoop cache - UniGetUI": "Scoop cache સાફ થઈ રહી છે - UniGetUI", + "Restart UniGetUI to fully apply changes": "ફેરફારો સંપૂર્ણપણે લાગુ કરવા માટે UniGetUI restart કરો", + "Restart UniGetUI": "UniGetUI restart કરો", + "Manage {0} sources": "{0} sources સંચાલન કરો", + "Add source": "સ્ત્રોત ઉમેરો", + "Add": "ઉમેરો", + "Source name": "સ્ત્રોત નામ", + "Source URL": "સ્ત્રોત URL", + "Other": "અન્ય", + "No minimum age": "કોઈ ન્યૂનતમ અવધિ નહીં", + "1 day": "૧ દિવસ", + "{0} days": "{0} દિવસ", + "Custom...": "કસ્ટમ...", + "{0} minutes": "{0} મિનિટ", + "1 hour": "૧ કલાક", + "{0} hours": "{0} કલાક", + "1 week": "૧ અઠવાડિયું", + "Supports release dates": "release dates ને સપોર્ટ કરે છે", + "Release date support per package manager": "દર package manager માટે release date સપોર્ટ", + "Search for packages": "packages શોધો", + "Local": "સ્થાનિક", + "OK": "ઠીક છે", + "Last checked: {0}": "છેલ્લે તપાસ્યું: {0}", + "{0} packages were found, {1} of which match the specified filters.": "{1} packages મળ્યા, જેમાંથી {0} નિર્દિષ્ટ filters સાથે મેળ ખાતા હતા.", + "{0} selected": "{0} પસંદ થયું", + "(Last checked: {0})": "(છેલ્લે ચકાસાયેલ: {0})", + "All packages selected": "બધા પેકેજો પસંદ કરવામાં આવ્યા", + "Package selection cleared": "પેકેજ પસંદગી સાફ કરવામાં આવી", + "{0}: {1}": "{0}: {1}", + "More info": "વધુ માહિતી", + "GitHub account": "GitHub એકાઉન્ટ", + "Log in with GitHub to enable cloud package backup.": "cloud package backup સક્રિય કરવા માટે GitHub સાથે Log in કરો.", + "More details": "વધુ વિગતો", + "Log in": "Log in કરો", + "If you have cloud backup enabled, it will be saved as a GitHub Gist on this account": "જો તમે cloud backup સક્રિય કર્યું હોય, તો તે આ account પર GitHub Gist તરીકે સાચવવામાં આવશે", + "Log out": "Log out કરો", + "About UniGetUI": "UniGetUI વિશે", + "About": "વિશે", + "Third-party licenses": "તૃતીય-પક્ષ લાઇસન્સ", + "Contributors": "યોગદાનકારો", + "Translators": "અનુવાદકો", + "Bundle security report": "બંડલ સુરક્ષા અહેવાલ", + "The bundle contained restricted content": "bundle માં પ્રતિબંધિત સામગ્રી હતી", + "UniGetUI – Crash Report": "UniGetUI – ક્રેશ રિપોર્ટ", + "UniGetUI has crashed": "UniGetUI ક્રેશ થયું", + "Help us fix this by sending a crash report to Devolutions. All fields below are optional.": "Devolutions ને ક્રેશ રિપોર્ટ મોકલીને અમને આ ઠીક કરવામાં મદદ કરો. નીચેના બધા ફીલ્ડ વૈકલ્પિક છે.", + "Email (optional)": "ઇમેઇલ (વૈકલ્પિક)", + "your@email.com": "your@email.com", + "Additional details (optional)": "વધારાની વિગતો (વૈકલ્પિક)", + "Describe what you were doing when the crash occurred…": "ક્રેશ થયો ત્યારે તમે શું કરી રહ્યા હતા તેનું વર્ણન કરો…", + "Crash report": "ક્રેશ રિપોર્ટ", + "Don't Send": "મોકલશો નહીં", + "Send Report": "રિપોર્ટ મોકલો", + "Sending…": "મોકલી રહાં છે…", + "Unsaved changes": "અસાચવાયેલા ફેરફારો", + "You have unsaved changes in the current bundle. Do you want to discard them?": "હાલના bundle માં તમારા unsaved changes છે. શું તમે તેને રદ કરવા માંગો છો?", + "Discard changes": "ફેરફારો રદ કરો", + "Integrity violation": "અખંડિતતા ઉલ્લંઘન", + "UniGetUI or some of its components are missing or corrupt. It is strongly recommended to reinstall UniGetUI to adress the situation.": "UniGetUI અથવા તેના કેટલાક ઘટકો ખૂટે છે અથવા બગડેલા છે. આ સ્થિતિને સુધારવા માટે UniGetUI ફરીથી સ્થાપિત કરવાની ભારપૂર્વક ભલામણ કરવામાં આવે છે.", + "• Refer to the UniGetUI Logs to get more details regarding the affected file(s)": "• અસરગ્રસ્ત file(s) વિશે વધુ વિગતો મેળવવા માટે UniGetUI Logs જુઓ", + "• Integrity checks can be disabled from the Experimental Settings": "• Integrity checks ને Experimental Settings માંથી નિષ્ક્રિય કરી શકાય છે", + "Manage shortcuts": "shortcuts સંચાલન કરો", + "UniGetUI has detected the following desktop shortcuts which can be removed automatically on future upgrades": "UniGetUI એ નીચેની desktop shortcuts શોધી છે જેને future upgrades દરમિયાન આપમેળે દૂર કરી શકાય છે", + "Do you really want to reset this list? This action cannot be reverted.": "શું તમે ખરેખર આ list reset કરવા માંગો છો? આ action પાછું ફેરવી શકાતું નથી.", + "Desktop shortcuts list": "ડેસ્કટોપ શોર્ટકટ્સ યાદી", + "Open in explorer": "Explorer માં ખોલો", + "Remove from list": "યાદીમાંથી દૂર કરો", + "When new shortcuts are detected, delete them automatically instead of showing this dialog.": "નવી shortcuts શોધાય ત્યારે આ dialog બતાવવાને બદલે તેને આપમેળે delete કરો.", + "Not right now": "હમણાં નહીં", + "Missing dependency": "dependency ખૂટે છે", + "UniGetUI requires {0} to operate, but it was not found on your system.": "UniGetUI ને કામ કરવા માટે {0} જરૂરી છે, પરંતુ તે તમારા system પર મળ્યું નથી.", + "Click on Install to begin the installation process. If you skip the installation, UniGetUI may not work as expected.": "સ્થાપન પ્રક્રિયા શરૂ કરવા માટે Install પર ક્લિક કરો. જો તમે સ્થાપન ટાળો, તો UniGetUI અપેક્ષા મુજબ કામ ન કરે.", + "Alternatively, you can also install {0} by running the following command in a Windows PowerShell prompt:": "વૈકલ્પિક રીતે, તમે Windows PowerShell prompt માં નીચેનો command ચલાવીને {0} સ્થાપિત કરી શકો છો:", + "Install {0}": "{0} install કરો", + "Do not show this dialog again for {0}": "{0} માટે આ dialog ફરીથી બતાવશો નહીં", + "Please wait while {0} is being installed. A black window may show up. Please wait until it closes.": "{0} install થઈ રહ્યું હોય ત્યારે કૃપા કરીને રાહ જુઓ. કાળી window દેખાઈ શકે છે. તે બંધ થાય ત્યાં સુધી રાહ જુઓ.", + "{0} has been installed successfully.": "{0} સફળતાપૂર્વક install થયું છે.", + "Please click on \"Continue\" to continue": "આગળ વધવા માટે \"Continue\" પર ક્લિક કરો", + "Continue": "આગળ વધો", + "{0} has been installed successfully. It is recommended to restart UniGetUI to finish the installation": "{0} સફળતાપૂર્વક install થયું છે. installation પૂર્ણ કરવા માટે UniGetUI restart કરવાની ભલામણ કરવામાં આવે છે", + "Restart later": "પછી restart કરો", + "An error occurred:": "ભૂલ આવી:", + "Please see the Command-line Output or refer to the Operation History for further information about the issue.": "સમસ્યા વિશે વધુ માહિતી માટે Command-line Output જુઓ અથવા Operation History નો સંદર્ભ લો.", + "Retry as administrator": "administrator તરીકે ફરી પ્રયાસ કરો", + "Retry interactively": "interactive રીતે ફરી પ્રયાસ કરો", + "Retry skipping integrity checks": "integrity checks skip કરીને ફરી પ્રયાસ કરો", + "Installation options": "સ્થાપન વિકલ્પો", + "Save": "સાચવો", + "UniGetUI collects anonymous usage data with the sole purpose of understanding and improving the user experience.": "UniGetUI user experience ને સમજવા અને સુધારવા માટેના એકમાત્ર હેતુથી anonymous usage data એકત્રિત કરે છે.", + "More details about the shared data and how it will be processed": "શેર કરેલા data વિશે અને તેને કેવી રીતે process કરવામાં આવશે તે વિશે વધુ વિગતો", + "Do you accept that UniGetUI collects and sends anonymous usage statistics, with the sole purpose of understanding and improving the user experience?": "UniGetUI વપરાશકર્તા અનુભવને સમજવા અને સુધારવા માટે માત્ર anonymous usage statistics એકત્ર કરે છે અને મોકલે છે, તે તમે સ્વીકારો છો?", + "Decline": "નકારો", + "No personal information is collected nor sent, and the collected data is anonimized, so it can't be back-tracked to you.": "કોઈ વ્યક્તિગત માહિતી એકત્રિત કે મોકલવામાં આવતી નથી, અને એકત્રિત data અનામી બનાવવામાં આવે છે, તેથી તેને તમારી સુધી trace કરી શકાતું નથી.", + "Navigation panel": "નેવિગેશન પેનલ", + "Operations": "ઓપરેશન્સ", + "Toggle operations panel": "પ્રક્રિયાઓ પેનલ ટૉગલ કરો", + "Bulk operations": "સામૂહિક પ્રક્રિયાઓ", + "Retry failed": "નિષ્ફળ થયેલાઓનો ફરી પ્રયાસ કરો", + "Clear successful": "સફળ થયેલાઓ સાફ કરો", + "Clear finished": "પૂર્ણ થયેલાઓ સાફ કરો", + "Cancel all": "બધું રદ કરો", + "More": "વધુ", + "Toggle navigation panel": "navigation panel ટૉગલ કરો", + "Minimize": "ન્યૂનતમ કરો", + "Maximize": "મહત્તમ કરો", + "UniGetUI by Devolutions": "Devolutions દ્વારા UniGetUI", + "UniGetUI is an application that makes managing your software easier, by providing an all-in-one graphical interface for your command-line package managers.": "UniGetUI એક application છે જે તમારા command-line package managers માટે all-in-one graphical interface આપી તમારા software ને મેનેજ કરવાનું સરળ બનાવે છે.", + "Useful links": "ઉપયોગી links", + "UniGetUI Homepage": "UniGetUI મુખ્ય પૃષ્ઠ", + "Report an issue or submit a feature request": "issue report કરો અથવા feature request મોકલો", + "UniGetUI Repository": "UniGetUI રિપોઝિટરી", + "View GitHub Profile": "GitHub Profile જુઓ", + "UniGetUI License": "UniGetUI લાઇસન્સ", + "Using UniGetUI implies the acceptation of the MIT License": "UniGetUI નો ઉપયોગ કરવાથી MIT License સ્વીકાર્ય ગણાશે", + "Become a translator": "અનુવાદક બનો", + "Go back": "પાછા જાઓ", + "Go forward": "આગળ જાઓ", + "Go to home page": "હોમ પેજ પર જાઓ", + "Reload page": "પેજ ફરીથી લોડ કરો", + "View page on browser": "browser માં page જુઓ", + "The built-in browser is not supported on Linux yet.": "બિલ્ટ-ઇન બ્રાઉઝર હજુ Linux પર સમર્થિત નથી.", + "Open in browser": "બ્રાઉઝરમાં ખોલો", + "Copy to clipboard": "clipboard પર નકલ કરો", + "Export to a file": "ફાઇલમાં નિકાસ કરો", + "Log level:": "log level:", + "Reload log": "log ફરી load કરો", + "Export log": "log નિકાસ કરો", + "Text": "લખાણ", + "Change how operations request administrator rights": "પ્રક્રિયાઓ સંચાલક અધિકારો કેવી રીતે માંગે છે તે બદલો", + "Restrictions on package operations": "package operations પર પ્રતિબંધો", + "Restrictions on package managers": "package managers પર પ્રતિબંધો", + "Restrictions when importing package bundles": "package bundles import કરતી વખતે પ્રતિબંધો", + "Ask for administrator privileges once for each batch of operations": "દરેક બેચની કામગીરી માટે એકવાર સંચાલક વિશેષાધિકારો માટે પૂછો", + "Ask only once for administrator privileges": "સંચાલક વિશેષાધિકારો માટે ફક્ત એકવાર પૂછો", + "Prohibit any kind of Elevation via UniGetUI Elevator or GSudo": "UniGetUI Elevator અથવા GSudo દ્વારા કોઈપણ પ્રકારના Elevation પર પ્રતિબંધ મૂકો", + "This option WILL cause issues. Any operation incapable of elevating itself WILL FAIL. Install/update/uninstall as administrator will NOT WORK.": "આ option ચોક્કસ સમસ્યાઓ ઊભી કરશે. જે operation પોતે elevate ન થઈ શકે તે નિષ્ફળ જશે. Install/update/uninstall as administrator કામ નહીં કરે.", + "Allow custom command-line arguments": "કસ્ટમ command-line arguments ને મંજૂરી આપો", + "Custom command-line arguments can change the way in which programs are installed, upgraded or uninstalled, in a way UniGetUI cannot control. Using custom command-lines can break packages. Proceed with caution.": "custom command-line arguments એ રીતે ફેરફાર કરી શકે છે કે જેમાં programs install, upgrade અથવા uninstall થાય છે, અને UniGetUI તેને નિયંત્રિત કરી શકતું નથી. custom command-lines નો ઉપયોગ packages ને બગાડી શકે છે. સાવચેત આગળ વધો.", + "Ignore custom pre-install and post-install commands when importing packages from a bundle": "bundle માંથી packages import કરતી વખતે custom pre-install અને post-install commands ચલાવવાની મંજૂરી આપો", + "Pre and post install commands will be run before and after a package gets installed, upgraded or uninstalled. Be aware that they may break things unless used carefully": "Pre અને post install commands package install, upgrade અથવા uninstall થાય તે પહેલાં અને પછી ચલાવવામાં આવશે. સાવચેત રહો, કારણ કે કાળજીપૂર્વક ઉપયોગ ન કરવામાં આવે તો તે વસ્તુઓ બગાડી શકે છે", + "Allow changing the paths for package manager executables": "પેકેજ મેનેજર executables ના path બદલવાની મંજૂરી આપો", + "Turning this on enables changing the executable file used to interact with package managers. While this allows finer-grained customization of your install processes, it may also be dangerous": "આને ચાલુ કરવાથી package managers સાથે કામ કરવા માટે વપરાતી executable file બદલી શકાય છે. આ તમારા install processes ને વધુ સૂક્ષ્મ રીતે customize કરવાની મંજૂરી આપે છે, પરંતુ તે જોખમી પણ હોઈ શકે છે", + "Allow importing custom command-line arguments when importing packages from a bundle": "બંડલમાંથી પેકેજ આયાત કરતી વખતે કસ્ટમ command-line arguments આયાત કરવાની મંજૂરી આપો", + "Malformed command-line arguments can break packages, or even allow a malicious actor to gain privileged execution. Therefore, importing custom command-line arguments is disabled by default": "ખોટા command-line arguments packages ને બગાડી શકે છે, અથવા કોઈ દુર્ભાવનાપૂર્ણ actor ને privileged execution આપી શકે છે. તેથી custom command-line arguments આયાત કરવું ડિફૉલ્ટ રીતે નિષ્ક્રિય છે.", + "Allow importing custom pre-install and post-install commands when importing packages from a bundle": "બંડલમાંથી પેકેજ આયાત કરતી વખતે કસ્ટમ pre-install અને post-install commands આયાત કરવાની મંજૂરી આપો", + "Pre and post install commands can do very nasty things to your device, if designed to do so. It can be very dangerous to import the commands from a bundle, unless you trust the source of that package bundle": "Pre અને post install commands તમારા device સાથે ખૂબ નુકસાનકારક કામો કરી શકે છે, જો તે એ હેતુ માટે બનાવવામાં આવ્યા હોય. bundle માંથી commands import કરવું ખૂબ જોખમી હોઈ શકે છે, જ્યાં સુધી તમે તે package bundle ના source પર trust ન કરો", + "Administrator rights and other dangerous settings": "સંચાલક અધિકારો અને અન્ય જોખમભર્યા settings", + "Package backup": "પેકેજ બેકઅપ", + "Cloud package backup": "cloud package backup", + "Local package backup": "સ્થાનિક package backup", + "Local backup advanced options": "સ્થાનિક backup advanced options", + "Log in with GitHub": "GitHub સાથે Log in કરો", + "Log out from GitHub": "GitHub માંથી Log out કરો", + "Periodically perform a cloud backup of the installed packages": "નિયમિત અંતરે installed packages નો cloud backup કરો", + "Cloud backup uses a private GitHub Gist to store a list of installed packages": "cloud backup સ્થાપિત પેકેજોની સૂચિ સંગ્રહવા માટે ખાનગી GitHub Gist નો ઉપયોગ કરે છે", + "Perform a cloud backup now": "હમણાં cloud backup કરો", + "Backup": "બેકઅપ", + "Restore a backup from the cloud": "cloud માંથી backup પુનઃસ્થાપિત કરો", + "Begin the process to select a cloud backup and review which packages to restore": "cloud backup પસંદ કરવા અને કયા પેકેજોને પુનઃસ્થાપિત કરવા તે સમીક્ષા કરવાની પ્રક્રિયા શરૂ કરો", + "Periodically perform a local backup of the installed packages": "નિયમિત અંતરે installed packages નો local backup કરો", + "Perform a local backup now": "હમણાં local backup કરો", + "Change backup output directory": "બેકઅપ output directory બદલો", + "Set a custom backup file name": "custom backup file name સેટ કરો", + "Leave empty for default": "ડિફૉલ્ટ માટે ખાલી રાખો", + "Add a timestamp to the backup file names": "બેકઅપ ફાઇલ નામોમાં ટાઇમસ્ટેમ્પ ઉમેરો", + "Backup and Restore": "બેકઅપ અને પુનઃસ્થાપન", + "Enable background api (UniGetUI Widgets and Sharing, port 7058)": "background API સક્રિય કરો (UniGetUI Widgets અને Sharing, port 7058)", + "Wait for the device to be connected to the internet before attempting to do tasks that require internet connectivity.": "internet connectivity જરૂરી હોય તેવી tasks કરવાનો પ્રયાસ કરતા પહેલાં device internet સાથે જોડાય ત્યાં સુધી રાહ જુઓ.", + "Disable the 1-minute timeout for package-related operations": "package સંબંધિત operations માટે 1-minute timeout નિષ્ક્રિય કરો", + "Use installed GSudo instead of UniGetUI Elevator": "UniGetUI Elevator ની બદલે installed GSudo વાપરો", + "Use a custom icon and screenshot database URL": "custom icon અને screenshot database URL વાપરો", + "Enable background CPU Usage optimizations (see Pull Request #3278)": "background CPU usage optimizations સક્રિય કરો (Pull Request #3278 જુઓ)", + "Perform integrity checks at startup": "startup સમયે integrity checks કરો", + "When batch installing packages from a bundle, install also packages that are already installed": "bundle માંથી batch install કરતી વખતે પહેલેથી install થયેલા packages પણ install કરો", + "Experimental settings and developer options": "પરીક્ષણાત્મક settings અને developer options", + "Show UniGetUI's version and build number on the titlebar.": "titlebar પર UniGetUI નું version અને build number બતાવો.", + "Language": "ભાષા", + "UniGetUI updater": "UniGetUI અપડેટર", + "Telemetry": "ટેલિમેટ્રી", + "Manage UniGetUI settings": "UniGetUI settings સંચાલન કરો", + "Related settings": "સંબંધિત settings", + "Update UniGetUI automatically": "UniGetUI ને આપમેળે update કરો", + "Check for updates": "અપડેટ્સ માટે તપાસો", + "Install prerelease versions of UniGetUI": "UniGetUI ની prerelease આવૃત્તિઓ install કરો", + "Manage telemetry settings": "telemetry settings સંચાલન કરો", + "Manage": "સંચાલન કરો", + "Import settings from a local file": "સ્થાનિક ફાઇલમાંથી settings આયાત કરો", + "Import": "આયાત કરો", + "Export settings to a local file": "settings ને સ્થાનિક ફાઇલમાં નિકાસ કરો", + "Export": "નિકાસ કરો", + "Reset UniGetUI": "UniGetUI reset કરો", + "User interface preferences": "વપરાશકર્તા ઇન્ટરફેસ પસંદગીઓ", + "Application theme, startup page, package icons, clear successful installs automatically": "એપ્લિકેશન થીમ, startup page, package icons, સફળ સ્થાપનો આપમેળે સાફ કરો", + "General preferences": "સામાન્ય પસંદગીઓ", + "UniGetUI display language:": "UniGetUI દર્શાવવાની ભાષા:", + "System language": "સિસ્ટમ ભાષા", + "Is your language missing or incomplete?": "શું તમારી ભાષા ખૂટે છે અથવા અધૂરી છે?", + "Appearance": "દેખાવ", + "UniGetUI on the background and system tray": "background અને system tray માં UniGetUI", + "Package lists": "પેકેજ યાદીઓ", + "Use classic mode": "ક્લાસિક મોડ વાપરો", + "Restart UniGetUI to apply this change": "આ ફેરફાર લાગુ કરવા માટે UniGetUI ફરી શરૂ કરો", + "The classic UI is disabled for beta testers": "બીટા પરીક્ષકો માટે ક્લાસિક UI અક્ષમ છે", + "Close UniGetUI to the system tray": "UniGetUI ને system tray માં બંધ કરો", + "Manage UniGetUI autostart behaviour": "UniGetUI autostart વર્તન સંચાલિત કરો", + "Show package icons on package lists": "package lists માં package icons બતાવો", + "Clear cache": "cache સાફ કરો", + "Select upgradable packages by default": "ડિફૉલ્ટ રીતે upgradable packages પસંદ કરો", + "Light": "હળવું", + "Dark": "અંધારું", + "Follow system color scheme": "system color scheme અનુસરો", + "Application theme:": "એપ્લિકેશન થીમ:", + "UniGetUI startup page:": "UniGetUI પ્રારંભ પાનું:", + "Proxy settings": "પ્રોક્સી સેટિંગ્સ", + "Other settings": "અન્ય settings", + "Connect the internet using a custom proxy": "કસ્ટમ proxy નો ઉપયોગ કરીને ઇન્ટરનેટ સાથે જોડાઓ", + "Please note that not all package managers may fully support this feature": "કૃપા કરીને નોંધો કે બધા package managers આ feature ને સંપૂર્ણપણે support ન કરતાં હોય શકે", + "Proxy URL": "પ્રોક્સી URL", + "Enter proxy URL here": "અહીં proxy URL દાખલ કરો", + "Authenticate to the proxy with a user and a password": "વપરાશકર્તા અને પાસવર્ડ સાથે proxy પર authenticate કરો", + "Internet and proxy settings": "internet અને proxy settings", + "Package manager preferences": "પેકેજ મેનેજર પસંદગીઓ", + "Ready": "તૈયાર", + "Not found": "મળ્યું નથી", + "Notification preferences": "સૂચના પસંદગીઓ", + "Notification types": "સૂચનાના પ્રકારો", + "The system tray icon must be enabled in order for notifications to work": "notifications કામ કરે તે માટે system tray icon સક્રિય હોવો જરૂરી છે", + "Enable UniGetUI notifications": "UniGetUI notifications સક્રિય કરો", + "Show a notification when there are available updates": "ઉપલબ્ધ updates હોય ત્યારે notification બતાવો", + "Show a silent notification when an operation is running": "operation ચાલી રહી હોય ત્યારે silent notification બતાવો", + "Show a notification when an operation fails": "operation નિષ્ફળ જાય ત્યારે notification બતાવો", + "Show a notification when an operation finishes successfully": "operation સફળતાપૂર્વક પૂર્ણ થાય ત્યારે notification બતાવો", + "Concurrency and execution": "સમકાલીનતા અને અમલીકરણ", + "Automatic desktop shortcut remover": "આપમેળે desktop shortcut દૂર કરનાર", + "Choose how many operations should be performed in parallel": "કેટલી કામગીરીઓ સમકાળે કરવામાં આવે તે પસંદ કરો", + "Clear successful operations from the operation list after a 5 second delay": "5 સેકંડના વિલંબ પછી કામગીરી સૂચિમાંથી સફળ કામગીરી સાફ કરો", + "Download operations are not affected by this setting": "આ setting થી download operations અસરગ્રસ્ત થતા નથી", + "You may lose unsaved data": "તમે unsaved data ગુમાવી શકો છો", + "Ask to delete desktop shortcuts created during an install or upgrade.": "સ્થાપન અથવા upgrade દરમિયાન બનેલા desktop shortcuts કાઢવા માટે પૂછો.", + "Package update preferences": "પેકેજ અપડેટ પસંદગીઓ", + "Update check frequency, automatically install updates, etc.": "update તપાસવાની આવર્તન, updates આપમેળે install કરો, વગેરે.", + "Reduce UAC prompts, elevate installations by default, unlock certain dangerous features, etc.": "UAC prompts ઓછા કરો, installations ને ડિફૉલ્ટ તરીકે elevate કરો, ચોક્કસ જોખમી features unlock કરો, વગેરે.", + "Package operation preferences": "પેકેજ પ્રક્રિયા પસંદગીઓ", + "Enable {pm}": "{pm} સક્રિય કરો", + "Not finding the file you are looking for? Make sure it has been added to path.": "તમે શોધી રહ્યા છો તેવી file મળતી નથી? ખાતરી કરો કે તે path માં ઉમેરાઈ છે.", + "Select the executable to be used. The following list shows the executables found by UniGetUI": "ઉપયોગ કરવાની executable પસંદ કરો. નીચેની યાદી UniGetUI દ્વારા મળેલી executables બતાવે છે", + "For security reasons, changing the executable file is disabled by default": "સુરક્ષા કારણોસર, executable file બદલવું મૂળભૂત રીતે નિષ્ક્રિય છે", + "Change this": "આ બદલો", + "Copy path": "પાથ કૉપિ કરો", + "Current executable file:": "વર્તમાન executable ફાઇલ:", + "Ignore packages from {pm} when showing a notification about updates": "updates અંગે notification બતાવતી વખતે {pm} ના packages ignore કરો", + "Update security": "અપડેટ સુરક્ષા", + "Use global setting": "global setting વાપરો", + "Minimum age for updates": "updates માટે ન્યૂનતમ અવધિ", + "e.g. 10": "દા.ત. 10", + "Custom minimum age (days)": "કસ્ટમ ન્યૂનતમ અવધિ (દિવસ)", + "{pm} does not provide release dates for its packages, so this setting will have no effect": "{pm} તેના packages માટે release dates આપતું નથી, તેથી આ setting નો કોઈ પ્રભાવ નહીં થાય", + "{pm} only provides release dates for some of its packages, so this setting will only apply to those packages": "{pm} તેના કેટલાક પેકેજો માટે જ રિલીઝ તારીખો પ્રદાન કરે છે, તેથી આ સેટિંગ ફક્ત તે પેકેજો પર જ લાગુ થશે", + "Override the global minimum update age for this package manager": "આ package manager માટે global minimum update age override કરો", + "View {0} logs": "{0} logs જુઓ", + "If Python cannot be found or is not listing packages but is installed on the system, ": "જો Python મળી ન આવે અથવા packages સૂચિબદ્ધ ન કરતું હોય છતાં system પર installed હોય, ", + "Advanced options": "ઉન્નત વિકલ્પો", + "WinGet command-line tool": "WinGet કમાન્ડ-લાઇન સાધન", + "Choose which command-line tool UniGetUI uses for WinGet operations when the COM API is not used": "COM API વપરાતી ન હોય ત્યારે WinGet પ્રક્રિયાઓ માટે UniGetUI કયું command-line tool વાપરે તે પસંદ કરો", + "WinGet COM API": "WinGet COM API", + "Choose whether UniGetUI can use the WinGet COM API before falling back to the command-line tool": "command-line tool પર પાછા વળતા પહેલાં UniGetUI WinGet COM API વાપરી શકે કે નહીં તે પસંદ કરો", + "Reset WinGet": "WinGet reset કરો", + "This may help if no packages are listed": "જો કોઈ packages સૂચિબદ્ધ ન હોય તો આ મદદરૂપ થઈ શકે છે", + "Force install location parameter when updating packages with custom locations": "custom locations સાથે packages update કરતી વખતે install location parameter force કરો", + "Install Scoop": "Scoop install કરો", + "Uninstall Scoop (and its packages)": "Scoop (અને તેના packages) uninstall કરો", + "Run cleanup and clear cache": "cleanup ચલાવો અને cache સાફ કરો", + "Run": "ચલાવો", + "Enable Scoop cleanup on launch": "launch વખતે Scoop cleanup સક્રિય કરો", + "Default vcpkg triplet": "ડિફૉલ્ટ vcpkg triplet", + "Change vcpkg root location": "vcpkg root સ્થાન બદલો", + "Reset vcpkg root location": "vcpkg રૂટ સ્થાન રીસેટ કરો", + "Open vcpkg root location": "vcpkg રૂટ સ્થાન ખોલો", + "Language, theme and other miscellaneous preferences": "ભાષા, theme અને અન્ય વિવિધ preferences", + "Show notifications on different events": "વિવિધ ઘટનાઓ પર notifications બતાવો", + "Change how UniGetUI checks and installs available updates for your packages": "UniGetUI તમારા પેકેજો માટે ઉપલબ્ધ અપડેટ્સ કેવી રીતે તપાસે અને સ્થાપિત કરે છે તે બદલો", + "Automatically save a list of all your installed packages to easily restore them.": "તેઓને સરળતાથી પુન:સંગ્રહ કરવા માટે તમારા બધા સ્થાપિત થયેલ પેકેજોની યાદીને આપમેળે સંગ્રહો.", + "Enable and disable package managers, change default install options, etc.": "પેકેજ મેનેજર સક્રિય અને નિષ્ક્રિય કરો, ડિફૉલ્ટ install options બદલો, વગેરે.", + "Internet connection settings": "ઇન્ટરનેટ જોડાણ settings", + "Proxy settings, etc.": "Proxy settings, વગેરે.", + "Beta features and other options that shouldn't be touched": "beta features અને અન્ય વિકલ્પો જેને સ્પર્શવા ન જોઈએ", + "Reload sources": "સ્ત્રોતો ફરીથી લોડ કરો", + "Delete source": "સ્ત્રોત કાઢી નાખો", + "Known sources": "જાણીતા સ્ત્રોતો", + "Update checking": "update તપાસ", + "Automatic updates": "આપમેળે અપડેટ્સ", + "Check for package updates periodically": "પેકેજ અપડેટ્સ સમયાંતરે તપાસો", + "Check for updates every:": "દરેક વખતે અપડેટ્સ માટે તપાસો:", + "Install available updates automatically": "ઉપલબ્ધ updates આપમેળે install કરો", + "Do not automatically install updates when the network connection is metered": "network connection metered હોય ત્યારે updates આપમેળે install કરશો નહીં", + "Do not automatically install updates when the device runs on battery": "device battery પર ચાલી રહ્યું હોય ત્યારે updates આપમેળે install કરશો નહીં", + "Do not automatically install updates when the battery saver is on": "battery saver ચાલુ હોય ત્યારે updates આપમેળે install કરશો નહીં", + "Only show updates that are at least the specified number of days old": "માત્ર તે updates બતાવો જે ઓછામાં ઓછા નિર્દિષ્ટ દિવસ જેટલા જૂના હોય", + "Warn me when the installer URL host changes between the installed version and the new version (WinGet only)": "સ્થાપિત આવૃત્તિ અને નવી આવૃત્તિ વચ્ચે સ્થાપક URL હોસ્ટ બદલાય ત્યારે મને ચેતવો (માત્ર WinGet)", + "Change how UniGetUI handles install, update and uninstall operations.": "UniGetUI install, update અને uninstall પ્રક્રિયાઓને કેવી રીતે સંભાળે છે તે બદલો.", + "Navigation": "નેવિગેશન", + "Check for UniGetUI updates": "UniGetUI અપડેટ્સ માટે તપાસો", + "Quit UniGetUI": "UniGetUI બંધ કરો", + "Filters": "filters", + "Sources": "સ્ત્રોતો", + "Search for packages to start": "શરૂ કરવા માટે packages શોધો", + "Select all": "બધું પસંદ કરો", + "Clear selection": "પસંદગી સાફ કરો", + "Instant search": "તાત્કાલિક search", + "Distinguish between uppercase and lowercase": "uppercase અને lowercase વચ્ચેનો ફરક ઓળખો", + "Ignore special characters": "વિશેષ અક્ષરો ignore કરો", + "Search mode": "શોધ સ્થિતિ", + "Both": "બંને", + "Exact match": "સટીક match", + "Show similar packages": "સમાન packages બતાવો", + "Loading": "લોડ થઈ રહ્યું છે", + "Package": "પેકેજ", + "More options": "વધુ વિકલ્પો", + "Order by:": "આ મુજબ ક્રમબદ્ધ કરો:", + "Name": "નામ", + "Id": "ઓળખ", + "Ascendant": "આરોહી", + "Descendant": "ઉતરતા ક્રમમાં", + "View modes": "દૃશ્ય મોડ્સ", + "Reload": "ફરીથી લોડ કરો", + "Closed": "બંધ", + "Ascending": "ચડતો ક્રમ", + "Descending": "ઉતરતો ક્રમ", + "{0}: {1}, {2}": "{0}: {1}, {2}", + "Order by": "ક્રમ", + "No results were found matching the input criteria": "input criteria સાથે મેળ ખાતા કોઈ પરિણામો મળ્યા નથી", + "No packages were found": "કોઈ packages મળ્યા નથી", + "Loading packages": "packages load થઈ રહ્યા છે", + "Skip integrity checks": "integrity checks છોડો", + "Download selected installers": "પસંદ કરેલા installers download કરો", + "Install selection": "selection install કરો", + "Install options": "સ્થાપન વિકલ્પો", + "Add selection to bundle": "બંડલમાં પસંદગી ઉમેરો", + "Download installer": "installer download કરો", + "Uninstall selection": "selection uninstall કરો", + "Uninstall options": "અનઇન્સ્ટોલ વિકલ્પો", + "Ignore selected packages": "પસંદ કરેલા packages ignore કરો", + "Open install location": "install location ખોલો", + "Reinstall package": "package ફરી install કરો", + "Uninstall package, then reinstall it": "package uninstall કરો, પછી તેને ફરી install કરો", + "Ignore updates for this package": "આ package માટે updates ignore કરો", + "WinGet malfunction detected": "WinGet માં ખામી મળી", + "It looks like WinGet is not working properly. Do you want to attempt to repair WinGet?": "લાગે છે કે WinGet યોગ્ય રીતે કામ કરતું નથી. શું તમે WinGet repair કરવાનો પ્રયાસ કરવા માંગો છો?", + "Repair WinGet": "WinGet repair કરો", + "Updates will no longer be ignored for {0}": "{0} માટે અપડેટ્સ હવે અવગણવામાં આવશે નહીં", + "Updates are now ignored for {0}": "{0} માટે અપડેટ્સ હવે અવગણવામાં આવે છે", + "Do not ignore updates for this package anymore": "આ package માટે updates હવે આગળથી ignore કરશો નહીં", + "Add packages or open an existing package bundle": "પેકેજ ઉમેરો અથવા અસ્તિત્વમાં રહેલ પેકેજ બંડલ ખોલો", + "Add packages to start": "શરૂ કરવા માટે પેકેજ ઉમેરો", + "The current bundle has no packages. Add some packages to get started": "હાલના bundle માં કોઈ packages નથી. શરૂઆત કરવા માટે થોડાં packages ઉમેરો", + "New": "નવું", + "Save as": "આ રીતે સાચવો", + "Create .ps1 script": ".ps1 script બનાવો", + "Remove selection from bundle": "bundle માંથી selection દૂર કરો", + "Skip hash checks": "hash checks છોડો", + "The package bundle is not valid": "package bundle માન્ય નથી", + "The bundle you are trying to load appears to be invalid. Please check the file and try again.": "તમે load કરવાનો પ્રયાસ કરી રહ્યા છો તે bundle અમાન્ય લાગે છે. કૃપા કરીને file તપાસો અને ફરી પ્રયાસ કરો.", + "Package bundle": "પેકેજ બંડલ", + "Could not create bundle": "બંડલ બનાવી શકાયું નહીં", + "The package bundle could not be created due to an error.": "ભૂલને કારણે package bundle બનાવી શકાયું નથી.", + "Install script": "સ્થાપન script", + "PowerShell script": "PowerShell સ્ક્રિપ્ટ", + "The installation script saved to {0}": "installation script {0} માં સાચવાઈ", + "An error occurred": "એક ભૂલ થઈ છે", + "An error occurred while attempting to create an installation script:": "સ્થાપન script બનાવવાના પ્રયાસ દરમિયાન ભૂલ આવી:", + "Hooray! No updates were found.": "શાનદાર! કોઈ updates મળ્યા નથી.", + "Uninstall selected packages": "પસંદ કરેલા packages uninstall કરો", + "Update selection": "selection update કરો", + "Update options": "અપડેટ વિકલ્પો", + "Uninstall package, then update it": "package uninstall કરો, પછી તેને update કરો", + "Uninstall package": "package uninstall કરો", + "Skip this version": "આ આવૃત્તિ છોડો", + "Pause updates for": "આ સમય માટે updates pause કરો", + "User | Local": "વપરાશકર્તા | સ્થાનિક", + "Machine | Global": "મશીન | વૈશ્વિક", + "The default package manager for Debian/Ubuntu-based Linux distributions.
Contains: Debian/Ubuntu packages": "Debian/Ubuntu-આધારિત Linux વિતરણો માટે ડિફૉલ્ટ પેકેજ મેનેજર.
સમાવે છે: Debian/Ubuntu પેકેજો", + "The Rust package manager.
Contains: Rust libraries and programs written in Rust": "Rust package manager.
સમાવે છે: Rust libraries અને Rust માં લખાયેલા programs", + "The classical package manager for windows. You'll find everything there.
Contains: General Software": "Windows માટેનો પરંપરાગત package manager. તમને ત્યાં બધું મળશે.
સમાવે છે: General Software", + "The default package manager for RHEL/Fedora-based Linux distributions.
Contains: RPM packages": "RHEL/Fedora-આધારિત Linux વિતરણો માટે ડિફૉલ્ટ પેકેજ મેનેજર.
સમાવે છે: RPM પેકેજો", + "A repository full of tools and executables designed with Microsoft's .NET ecosystem in mind.
Contains: .NET related tools and scripts": "માઇક્રોસોફ્ટના ડોટ નેટ ઇકોસિસ્ટમને ધ્યાનમાં રાખીને રચાયેલ સાધનો અને એક્ઝેક્યુટેબલ્સથી ભરેલો ભંડાર.
સમાવે છે: .NET સંબંધિત સાધનો અને સ્ક્રિપ્ટો", + "The universal Linux package manager for desktop applications.
Contains: Flatpak applications from configured remotes": "ડેસ્કટોપ એપ્લિકેશનો માટેનું સર્વવ્યાપક Linux પેકેજ મેનેજર.
સમાવે છે: ગોઠવેલ રિમોટ્સમાંથી Flatpak એપ્લિકેશનો", + "NuPkg (zipped manifest)": "NuPkg (ઝિપ કરેલ મેનિફેસ્ટ)", + "The Missing Package Manager for macOS (or Linux).
Contains: Formulae, Casks": "macOS (અથવા Linux) માટેનો Missing Package Manager.
સમાવે છે: Formulae, Casks", + "Node JS's package manager. Full of libraries and other utilities that orbit the javascript world
Contains: Node javascript libraries and other related utilities": "Node JS નો package manager. javascript દુનિયામાં ફરતી libraries અને અન્ય utilities થી ભરેલો
સમાવે છે: Node javascript libraries અને અન્ય સંબંધિત utilities", + "The default package manager for Arch Linux and its derivatives.
Contains: Arch Linux packages": "Arch Linux અને તેના ડેરિવેટિવ્ઝ માટે ડિફૉલ્ટ પેકેજ મેનેજર.
સમાવે છે: Arch Linux પેકેજો", + "Python's library manager. Full of python libraries and other python-related utilities
Contains: Python libraries and related utilities": "Python નો library manager. python libraries અને અન્ય python સંબંધિત utilities થી ભરેલો
સમાવે છે: Python libraries અને સંબંધિત utilities", + "PowerShell's package manager. Find libraries and scripts to expand PowerShell capabilities
Contains: Modules, Scripts, Cmdlets": "PowerShell નો package manager. PowerShell ક્ષમતાઓ વધારવા માટે libraries અને scripts શોધો
સમાવે છે: Modules, Scripts, Cmdlets", + "extracted": "extract થયું", + "Scoop package": "Scoop પેકેજ", + "Great repository of unknown but useful utilities and other interesting packages.
Contains: Utilities, Command-line programs, General Software (extras bucket required)": "અજાણી પરંતુ ઉપયોગી utilities અને અન્ય રસપ્રદ packages નું ઉત્તમ repository.
સમાવે છે: Utilities, Command-line programs, General Software (extras bucket આવશ્યક)", + "The universal Linux package manager by Canonical.
Contains: Snap packages from the Snapcraft store": "Canonical દ્વારા સાર્વત્રિક Linux પેકેજ મેનેજર.
સમાવે છે: Snapcraft store ના Snap પેકેજો", + "library": "લાઇબ્રેરી", + "feature": "સુવિધા", + "A popular C/C++ library manager. Full of C/C++ libraries and other C/C++-related utilities
Contains: C/C++ libraries and related utilities": "લોકપ્રિય C/C++ લાઇબ્રેરી મેનેજર. C/C++ લાઇબ્રેરીઓ અને અન્ય C/C++ સંબંધિત utilities થી ભરેલો
સમાવે છે: C/C++ લાઇબ્રેરીઓ અને સંબંધિત utilities", + "option": "વિકલ્પ", + "This package cannot be installed from an elevated context.": "આ package elevated context માંથી install થઈ શકતું નથી.", + "Please run UniGetUI as a regular user and try again.": "કૃપા કરીને UniGetUI ને regular user તરીકે ચલાવો અને ફરી પ્રયાસ કરો.", + "Please check the installation options for this package and try again": "આ package માટે installation options તપાસો અને ફરી પ્રયાસ કરો", + "Microsoft's official package manager. Full of well-known and verified packages
Contains: General Software, Microsoft Store apps": "Microsoft નો સત્તાવાર package manager. જાણીતા અને verified packages થી ભરેલો
સમાવે છે: General Software, Microsoft Store apps", + "Local PC": "સ્થાનિક PC", + "Android Subsystem": "એન્ડ્રોઇડ સબસિસ્ટમ", + "Operation on queue (position {0})...": "queue માં operation (position {0})...", + "Click here for more details": "વધુ વિગતો માટે અહીં ક્લિક કરો", + "Operation canceled by user": "user દ્વારા operation રદ કરવામાં આવ્યું", + "Running PreOperation ({0}/{1})...": "PreOperation ચલાવી રહ્યું છે ({0}/{1})...", + "PreOperation {0} out of {1} failed, and was tagged as necessary. Aborting...": "{1} માંથી PreOperation {0} નિષ્ફળ ગયું અને તેને જરૂરી તરીકે ચિહ્નિત કરવામાં આવ્યું હતું. બંધ કરી રહ્યું છે...", + "PreOperation {0} out of {1} finished with result {2}": "{1} માંથી PreOperation {0} {2} પરિણામ સાથે પૂર્ણ થયું", + "Starting operation...": "operation શરૂ થઈ રહી છે...", + "Running PostOperation ({0}/{1})...": "PostOperation ચલાવી રહ્યું છે ({0}/{1})...", + "PostOperation {0} out of {1} failed, and was tagged as necessary. Aborting...": "{1} માંથી PostOperation {0} નિષ્ફળ ગયું અને તેને જરૂરી તરીકે ચિહ્નિત કરવામાં આવ્યું હતું. બંધ કરી રહ્યું છે...", + "PostOperation {0} out of {1} finished with result {2}": "{1} માંથી PostOperation {0} {2} પરિણામ સાથે પૂર્ણ થયું", + "{package} installer download": "{package} સ્થાપક ડાઉનલોડ", + "{0} installer is being downloaded": "{0} installer download થઈ રહ્યો છે", + "Download succeeded": "Download સફળ થયું", + "{package} installer was downloaded successfully": "{package} installer સફળતાપૂર્વક download થયો", + "Download failed": "Download નિષ્ફળ ગયું", + "{package} installer could not be downloaded": "{package} installer download થઈ શક્યો નથી", + "{package} Installation": "{package} સ્થાપન", + "{0} is being installed": "{0} install થઈ રહ્યું છે", + "Installation succeeded": "Installation સફળ થઈ", + "{package} was installed successfully": "{package} સફળતાપૂર્વક install થયું", + "Installation failed": "Installation નિષ્ફળ ગઈ", + "{package} could not be installed": "{package} install થઈ શક્યું નથી", + "{package} Update": "{package} અપડેટ", + "Update succeeded": "Update સફળ થયું", + "{package} was updated successfully": "{package} સફળતાપૂર્વક update થયું", + "Update failed": "Update નિષ્ફળ ગયું", + "{package} could not be updated": "{package} update થઈ શક્યું નથી", + "{package} Uninstall": "{package} અનઇન્સ્ટોલ", + "{0} is being uninstalled": "{0} uninstall થઈ રહ્યું છે", + "Uninstall succeeded": "uninstall સફળ થયું", + "{package} was uninstalled successfully": "{package} સફળતાપૂર્વક uninstall થયું", + "Uninstall failed": "uninstall નિષ્ફળ ગયું", + "{package} could not be uninstalled": "{package} uninstall થઈ શક્યું નથી", + "Adding source {source}": "સ્ત્રોત {source} ઉમેરાઈ રહ્યો છે", + "Adding source {source} to {manager}": "{manager} માં સ્ત્રોત {source} ઉમેરાઈ રહ્યો છે", + "Source added successfully": "Source સફળતાપૂર્વક ઉમેરાયો", + "The source {source} was added to {manager} successfully": "source {source} સફળતાપૂર્વક {manager} માં ઉમેરાયો", + "Could not add source": "સ્ત્રોત ઉમેરવામાં આવ્યો નહીં", + "Could not add source {source} to {manager}": "{manager} માં {source} સ્ત્રોત ઉમેરવામાં આવ્યો નહીં", + "Removing source {source}": "source {source} દૂર કરી રહ્યા છીએ", + "Removing source {source} from {manager}": "{manager} માંથી source {source} દૂર કરી રહ્યા છીએ", + "Source removed successfully": "Source સફળતાપૂર્વક દૂર થયો", + "The source {source} was removed from {manager} successfully": "source {source} સફળતાપૂર્વક {manager} માંથી દૂર થયો", + "Could not remove source": "સ્ત્રોત દૂર કરી શકાયો નહીં", + "Could not remove source {source} from {manager}": "{manager} માંથી {source} સ્ત્રોત દૂર કરી શકાયો નહીં", + "The package manager \"{0}\" was not found": "package manager \"{0}\" મળ્યો નથી", + "The package manager \"{0}\" is disabled": "package manager \"{0}\" નિષ્ક્રિય છે", + "There is an error with the configuration of the package manager \"{0}\"": "package manager \"{0}\" ની configuration માં ભૂલ છે", + "The package \"{0}\" was not found on the package manager \"{1}\"": "package manager \"{1}\" પર package \"{0}\" મળ્યું નથી", + "{0} is disabled": "{0} નિષ્ક્રિય છે", + "{0} weeks": "{0} અઠવાડિયા", + "1 month": "1 મહિનો", + "{0} months": "{0} મહિના", + "Something went wrong": "કંઈક ખોટું થયું", + "An interal error occurred. Please view the log for further details.": "આંતરીક ભૂલ આવી. વધુ વિગતો માટે કૃપા કરીને લોગ જુઓ.", + "No applicable installer was found for the package {0}": "package {0} માટે કોઈ યોગ્ય installer મળ્યો નથી", + "Integrity checks will not be performed during this operation": "આ operation દરમિયાન Integrity checks કરવામાં આવશે નહીં", + "This is not recommended.": "આ ભલામણ કરેલું નથી.", + "Run now": "હમણાં ચલાવો", + "Run next": "આગળ ચલાવો", + "Run last": "છેલ્લે ચલાવો", + "Show in explorer": "explorer માં બતાવો", + "Checked": "ચિહ્નિત", + "Unchecked": "અચિહ્નિત", + "This package is already installed": "આ package પહેલેથી install છે", + "This package can be upgraded to version {0}": "આ package ને version {0} સુધી upgrade કરી શકાય છે", + "Updates for this package are ignored": "આ package માટેના updates ignore કરવામાં આવ્યા છે", + "This package is being processed": "આ package process થઈ રહ્યું છે", + "This package is not available": "આ package ઉપલબ્ધ નથી", + "Select the source you want to add:": "તમે ઉમેરવા માંગતા source ને પસંદ કરો:", + "Source name:": "સ્ત્રોત નામ:", + "Source URL:": "સ્ત્રોત URL:", + "An error occurred when adding the source: ": "સ્ત્રોત ઉમેરતી વખતે એક ભૂલ આવી:", + "Package management made easy": "Package management સરળ બનાવ્યું", + "version {0}": "આવૃત્તિ {0}", + "[RAN AS ADMINISTRATOR]": "[ADMINISTRATOR તરીકે ચલાવવામાં આવ્યું]", + "Portable mode": "પોર્ટેબલ મોડ ", + "DEBUG BUILD": "DEBUG build", + "Here you can change UniGetUI's behaviour regarding the following shortcuts. Checking a shortcut will make UniGetUI delete it if if gets created on a future upgrade. Unchecking it will keep the shortcut intact": "અહીં તમે નીચેની shortcuts અંગે UniGetUI નું વર્તન બદલી શકો છો. shortcut ને check કરવાથી જો તે future upgrade દરમિયાન બને તો UniGetUI તેને delete કરશે. તેને uncheck કરવાથી shortcut યથાવત રહેશે", + "Manual scan": "હાથથી scan", + "Existing shortcuts on your desktop will be scanned, and you will need to pick which ones to keep and which ones to remove.": "તમારા desktop પરની હાલની shortcuts scan કરવામાં આવશે, અને તમે કઈ રાખવી અને કઈ દૂર કરવી તે પસંદ કરવું પડશે.", + "Delete?": "કાઢી નાખવું?", + "I understand": "હું સમજું છું", + "Chocolatey setup changed": "Chocolatey સેટઅપ બદલાયું", + "UniGetUI no longer includes its own private Chocolatey installation. A legacy UniGetUI-managed Chocolatey installation was detected for this user profile, but system Chocolatey was not found. Chocolatey will stay unavailable in UniGetUI until Chocolatey is installed on the system and UniGetUI is restarted. Applications previously installed through UniGetUI's bundled Chocolatey may still appear under other sources such as Local PC or WinGet.": "UniGetUI હવે પોતાનું ખાનગી Chocolatey ઇન્સ્ટોલેશન સામેલ કરતું નથી. આ વપરાશકર્તા પ્રોફાઇલ માટે UniGetUI-સંચાલિત Chocolatey ઇન્સ્ટોલેશન મળ્યું, પરંતુ સિસ્ટમ Chocolatey મળ્યું નથી. સિસ્ટમ પર Chocolatey ઇન્સ્ટોલ થાય અને UniGetUI ફરીથી શરૂ થાય ત્યાં સુધી Chocolatey UniGetUI માં અનુપલબ્ધ રહેશે. UniGetUI ના બંડલ્ડ Chocolatey દ્વારા અગાઉ ઇન્સ્ટોલ કરેલી એપ્લિકેશનો હજુ પણ Local PC અથવા WinGet જેવા અન્ય સ્ત્રોતો હેઠળ દેખાઈ શકે છે.", + "NOTE: This troubleshooter can be disabled from UniGetUI Settings, on the WinGet section": "નોંધ: આ troubleshooter ને UniGetUI Settings ના WinGet વિભાગમાંથી નિષ્ક્રિય કરી શકાય છે", + "Restart": "Restart કરો", + "Are you sure you want to delete all shortcuts?": "શું તમે બધા shortcuts કાઢી નાખવા માંગો છો?", + "Any new shorcuts created during an install or an update operation will be deleted automatically, instead of showing a confirmation prompt the first time they are detected.": "સ્થાપન અથવા અપડેટ પ્રક્રિયા દરમ્યાન બનેલા નવા shortcuts પહેલી વાર શોધાય ત્યારે પુષ્ટિ prompt બતાવવાના બદલે આપમેળે કાઢી નાખવામાં આવશે.", + "Any shorcuts created or modified outside of UniGetUI will be ignored. You will be able to add them via the {0} button.": "UniGetUI બહાર બનાવેલા અથવા ફેરફાર કરેલા shortcuts અવગણવામાં આવશે. તમે તેમને {0} બટન દ્વારા ઉમેરી શકશો.", + "Are you really sure you want to enable this feature?": "શું તમે આ સુવિધા સક્રિય કરવા માટે ખરેખર નિશ્ચિત છો?", + "No new shortcuts were found during the scan.": "scan દરમિયાન કોઈ નવી shortcuts મળી નથી.", + "How to add packages to a bundle": "bundle માં packages કેવી રીતે ઉમેરવા", + "In order to add packages to a bundle, you will need to: ": "bundle માં packages ઉમેરવા માટે, તમને આવું કરવું પડશે: ", + "1. Navigate to the \"{0}\" or \"{1}\" page.": "1. \"{0}\" અથવા \"{1}\" પૃષ્ઠ પર જાઓ.", + "2. Locate the package(s) you want to add to the bundle, and select their leftmost checkbox.": "2. બંડલમાં ઉમેરવા માંગતા પેકેજ(ઓ) શોધો અને તેમનો ડાબી બાજુનો checkbox પસંદ કરો.", + "3. When the packages you want to add to the bundle are selected, find and click the option \"{0}\" on the toolbar.": "3. જ્યારે બંડલમાં ઉમેરવાના પેકેજ પસંદ થઈ જાય, ત્યારે toolbar પર \"{0}\" વિકલ્પ શોધીને ક્લિક કરો.", + "4. Your packages will have been added to the bundle. You can continue adding packages, or export the bundle.": "4. તમારા પેકેજો બંડલમાં ઉમેરાઈ જશે. તમે વધુ પેકેજ ઉમેરતા રહી શકો છો અથવા બંડલને નિકાસ કરી શકો છો.", + "Which backup do you want to open?": "તમે કયો backup ખોલવા માંગો છો?", + "Select the backup you want to open. Later, you will be able to review which packages you want to install.": "તમે ખોલવા માંગતા backup ને પસંદ કરો. પછી તમે કયા packages install કરવા છે તે સમીક્ષા કરી શકશો.", + "There are ongoing operations. Quitting UniGetUI may cause them to fail. Do you want to continue?": "operations ચાલુ છે. UniGetUI બંધ કરવાથી તે નિષ્ફળ જઈ શકે છે. શું તમે આગળ વધવા માંગો છો?", + "UniGetUI or some of its components are missing or corrupt.": "UniGetUI અથવા તેના કેટલાક components ખૂટે છે અથવા બગડેલા છે.", + "It is strongly recommended to reinstall UniGetUI to adress the situation.": "આ પરિસ્થિતિને સુધારવા માટે UniGetUI ને ફરી install કરવાની મજબૂત ભલામણ થાય છે.", + "Refer to the UniGetUI Logs to get more details regarding the affected file(s)": "અસરગ્રસ્ત file(s) વિશે વધુ વિગતો મેળવવા માટે UniGetUI Logs જુઓ", + "Integrity checks can be disabled from the Experimental Settings": "Integrity checks ને Experimental Settings માંથી નિષ્ક્રિય કરી શકાય છે", + "Repair UniGetUI": "UniGetUI repair કરો", + "Live output": "live output", + "This package bundle had some settings that are potentially dangerous, and may be ignored by default.": "આ package bundle માં કેટલીક settings હતી જે સંભવિત રીતે જોખમી છે, અને ડિફૉલ્ટ રીતે તેને અવગણવામાં આવી શકે છે.", + "Entries that show in YELLOW will be IGNORED.": "YELLOW માં દેખાતી entries IGNORED થશે.", + "Entries that show in RED will be IMPORTED.": "RED માં દેખાતી entries IMPORTED થશે.", + "You can change this behavior on UniGetUI security settings.": "તમે આ વર્તન UniGetUI security settings માં બદલી શકો છો.", + "Open UniGetUI security settings": "UniGetUI security settings ખોલો", + "Should you modify the security settings, you will need to open the bundle again for the changes to take effect.": "જો તમે security settings માં ફેરફાર કરો, તો બદલાવો લાગુ થવા માટે તમને bundle ફરી ખોલવું પડશે.", + "Details of the report:": "રિપોર્ટની વિગતો:", + "Are you sure you want to create a new package bundle? ": "શું તમે નવું પેકેજ બંડલ બનાવવું છે તેની ખાતરી છે? ", + "Any unsaved changes will be lost": "સાચવાયેલા નથી એવા બધા ફેરફારો ગુમાશે", + "Warning!": "ચેતવણી!", + "For security reasons, custom command-line arguments are disabled by default. Go to UniGetUI security settings to change this. ": "સુરક્ષા કારણોસર, custom command-line arguments મૂળભૂત રીતે નિષ્ક્રિય છે. આ બદલવા માટે UniGetUI security settings માં જાઓ. ", + "Change default options": "મૂળભૂત વિકલ્પો બદલો", + "Ignore future updates for this package": "આ package માટે ભવિષ્યના updates ignore કરો", + "For security reasons, pre-operation and post-operation scripts are disabled by default. Go to UniGetUI security settings to change this. ": "સુરક્ષા કારણોસર, pre-operation અને post-operation scripts મૂળભૂત રીતે નિષ્ક્રિય છે. આ બદલવા માટે UniGetUI security settings માં જાઓ. ", + "You can define the commands that will be run before or after this package is installed, updated or uninstalled. They will be run on a command prompt, so CMD scripts will work here.": "આ package install, update અથવા uninstall થાય તે પહેલાં અથવા પછી ચલાવવાની commands તમે નિર્ધારિત કરી શકો છો. તે command prompt પર ચાલશે, તેથી CMD scripts અહીં કામ કરશે.", + "Change this and unlock": "આ બદલો અને unlock કરો", + "{0} Install options are currently locked because {0} follows the default install options.": "{0} ના Install options હાલમાં lock છે કારણ કે {0} ડિફૉલ્ટ install options અનુસરે છે.", + "Unset or unknown": "unset અથવા અજ્ઞાત", + "This package has no screenshots or is missing the icon? Contrbute to UniGetUI by adding the missing icons and screenshots to our open, public database.": "આ package માં screenshots નથી કે icon ખૂટે છે? અમારી ખુલ્લી જાહેર database માં ખૂટતા icons અને screenshots ઉમેરીને UniGetUI માં યોગદાન આપો.", + "Become a contributor": "ફાળો આપનાર બનો", + "Update to {0} available": "{0} માટે update ઉપલબ્ધ છે", + "Reinstall": "ફરી install કરો", + "Installer not available": "Installer ઉપલબ્ધ નથી", + "Version:": "આવૃત્તિ:", + "UniGetUI Version {0}": "UniGetUI આવૃત્તિ {0}", + "Performing backup, please wait...": "backup થઈ રહ્યું છે, કૃપા કરીને રાહ જુઓ...", + "An error occurred while logging in: ": "લોગિન કરતી વખતે ભૂલ આવી: ", + "Fetching available backups...": "ઉપલબ્ધ backups લાવી રહ્યા છીએ...", + "Done!": "પૂર્ણ થયું!", + "The cloud backup has been loaded successfully.": "cloud backup સફળતાપૂર્વક load થયું છે.", + "An error occurred while loading a backup: ": "બેકઅપ લોડ કરતી વખતે ભૂલ આવી: ", + "Backing up packages to GitHub Gist...": "પેકેજો GitHub Gist પર બેકઅપ થઈ રહ્યા છે...", + "Backup Successful": "બેકઅપ સફળ થયું", + "The cloud backup completed successfully.": "cloud backup સફળતાપૂર્વક પૂર્ણ થયું.", + "Could not back up packages to GitHub Gist: ": "પેકેજોને GitHub Gist પર બેકઅપ કરી શક્યા નહીં: ", + "It is not guaranteed that the provided credentials will be stored safely, so you may as well not use the credentials of your bank account": "આપેલ credentials સુરક્ષિત રીતે store થશે તેની કોઈ ખાતરી નથી, તેથી તમારા bank account ના credentials નો ઉપયોગ ન કરવો વધુ સારું છે", + "Enable the automatic WinGet troubleshooter": "આપમેળે WinGet troubleshooter સક્રિય કરો", + "Add updates that fail with a 'no applicable update found' to the ignored updates list": "'no applicable update found' થી નિષ્ફળ ગયેલા અપડેટ્સને અવગણાયેલા અપડેટ્સની યાદીમાં ઉમેરો", + "Invalid selection": "અમાન્ય selection", + "No package was selected": "કોઈ package પસંદ કરવામાં આવ્યો નથી", + "More than 1 package was selected": "1 કરતાં વધુ package પસંદ કરવામાં આવ્યા હતા", + "List": "યાદી", + "Grid": "ગ્રિડ", + "Icons": "આઇકન્સ", + "\"{0}\" is a local package and does not have available details": "\"{0}\" સ્થાનિક પેકેજ છે અને તેની વિગતો ઉપલબ્ધ નથી", + "\"{0}\" is a local package and is not compatible with this feature": "\"{0}\" સ્થાનિક પેકેજ છે અને આ સુવિધા સાથે સુસંગત નથી", + "Add packages to bundle": "બંડલમાં પેકેજ ઉમેરો", + "Preparing packages, please wait...": "packages તૈયાર થઈ રહ્યા છે, કૃપા કરીને રાહ જુઓ...", + "Loading packages, please wait...": "packages load થઈ રહ્યા છે, કૃપા કરીને રાહ જુઓ...", + "Saving packages, please wait...": "packages સાચવી રહ્યા છીએ, કૃપા કરીને રાહ જુઓ...", + "The bundle was created successfully on {0}": "bundle સફળતાપૂર્વક {0} પર બનાવાયું", + "User profile": "વપરાશકર્તા પ્રોફાઇલ", + "Error": "ભૂલ", + "Log in failed: ": "Log in નિષ્ફળ: ", + "Log out failed: ": "Log out નિષ્ફળ: ", + "Package backup settings": "પેકેજ બેકઅપ સેટિંગ્સ", + "Manage UniGetUI autostart behaviour from the Settings app": "UniGetUI autostart વર્તન સંચાલિત કરો", + "Choose how many operations shoulds be performed in parallel": "કેટલી operations parallel માં ચલાવવી તે પસંદ કરો", + "Something went wrong while launching the updater.": "updater launch કરતી વખતે કંઈક ખોટું થયું.", + "Please try again later": "કૃપા કરીને પછી ફરી પ્રયાસ કરો", + "Show the release notes after UniGetUI is updated": "UniGetUI અપડેટ થયા પછી પ્રકાશન નોંધો બતાવો" +} diff --git a/src/Languages/lang_he.json b/src/Languages/lang_he.json new file mode 100644 index 0000000..151f53d --- /dev/null +++ b/src/Languages/lang_he.json @@ -0,0 +1,850 @@ +{ + "{0} of {1} operations completed": "{0} מתוך {1} פעולות הושלמו", + "{0} is now {1}": "{0} הוא כעת {1}", + "Enabled": "מופעל", + "Disabled": "מושבת", + "Privacy": "פרטיות", + "Hide my username from the logs": "הסתר את שם המשתמש שלי מהיומנים", + "Replaces your username with **** in the logs. Restart UniGetUI to also hide it from already-recorded entries.": "מחליף את שם המשתמש שלך ב-**** ביומנים. הפעל מחדש את UniGetUI כדי להסתיר אותו גם מרשומות שכבר נרשמו.", + "Your last update attempt did not complete.": "ניסיון העדכון האחרון שלך לא הושלם.", + "UniGetUI could not confirm whether the update succeeded. Open the log to see what happened.": "UniGetUI לא הצליח לאשר אם העדכון הצליח. פתח את היומן כדי לראות מה קרה.", + "View log": "הצג יומן", + "The installer reported success but did not restart UniGetUI.": "המתקין דיווח על הצלחה אך לא הפעיל מחדש את UniGetUI.", + "The installer failed to initialize.": "המתקין לא הצליח לאתחל.", + "Setup was canceled before installation began.": "ההתקנה בוטלה לפני שהתחילה.", + "A fatal error occurred during the preparation phase.": "אירעה שגיאה חמורה בשלב ההכנה.", + "A fatal error occurred during installation.": "אירעה שגיאה חמורה במהלך ההתקנה.", + "Installation was canceled while in progress.": "ההתקנה בוטלה בזמן שהייתה בעיצומה.", + "The installer was terminated by another process.": "המתקין הופסק על ידי תהליך אחר.", + "The preparation phase determined the installation cannot proceed.": "שלב ההכנה קבע שלא ניתן להמשיך בהתקנה.", + "The installer could not start. UniGetUI may already be running, or you do not have permission to install.": "המתקין לא הצליח להתחיל. ייתכן ש-UniGetUI כבר פועל, או שאין לך הרשאה להתקין.", + "Unexpected installer error.": "שגיאת מתקין בלתי צפויה.", + "We are checking for updates.": "אנו בודקים אם קיימים עדכונים.", + "Please wait": "המתן בבקשה", + "Great! You are on the latest version.": "מעולה! אתה משתמש בגרסה העדכנית ביותר.", + "There are no new UniGetUI versions to be installed": "אין גרסאות חדשות של UniGetUI להתקנה", + "UniGetUI version {0} is being downloaded.": "UniGetUI גרסה {0} מורדת כעת.", + "This may take a minute or two": "זה עשוי לקחת דקה או שתיים", + "The installer authenticity could not be verified.": "לא ניתן לאמת את אותנטיות המתקין.", + "The update process has been aborted.": "תהליך העדכון בוטל.", + "Auto-update is not yet available on this platform.": "עדכון אוטומטי עדיין אינו זמין בפלטפורמה זו.", + "Please update UniGetUI manually.": "אנא עדכן את UniGetUI באופן ידני.", + "An error occurred when checking for updates: ": "אירעה שגיאה בעת בדיקת עדכונים:", + "The updater could not be launched.": "לא ניתן היה להפעיל את המעדכן.", + "The operating system did not start the installer process.": "מערכת ההפעלה לא התחילה את תהליך המתקין.", + "UniGetUI is being updated...": "UniGetUI מתעדכן...", + "Update installed.": "העדכון הותקן.", + "UniGetUI was updated successfully, but this running copy was not replaced. This usually means you are running a development build. Close this copy and start the newly-installed version to finish.": "UniGetUI עודכן בהצלחה, אך העותק הפועל הזה לא הוחלף. בדרך כלל משמעות הדבר היא שאתה מפעיל גרסת פיתוח. סגור את העותק הזה והפעל את הגרסה שהותקנה זה עתה כדי לסיים.", + "The update could not be applied.": "לא ניתן היה להחיל את העדכון.", + "Installer exit code {0}: {1}": "קוד יציאה של המתקין {0}: {1}", + "Update cancelled.": "העדכון בוטל.", + "Authentication was cancelled.": "האימות בוטל.", + "Installer exit code {0}": "קוד יציאה של המתקין {0}", + "Operation in progress": "הפעולה בעיצומה", + "Please wait...": "המתן בבקשה...", + "Success!": "הצליח!", + "Failed": "שגיאה", + "An error occurred while processing this package": "אירעה שגיאה במהלך עיבוד החבילה הזו", + "Installer": "מתקין", + "Executable": "קובץ הפעלה", + "MSI": "MSI", + "Compressed file": "קובץ דחוס", + "MSIX": "MSIX", + "WinGet was repaired successfully": "WinGet תוקן בהצלחה", + "It is recommended to restart UniGetUI after WinGet has been repaired": "מומלץ להפעיל מחדש את UniGetUI לאחר תיקון WinGet", + "WinGet could not be repaired": "לא ניתן היה לתקן את WinGet", + "An unexpected issue occurred while attempting to repair WinGet. Please try again later": "התרחשה בעיה בלתי צפויה בעת ניסיון לתקן את WinGet. אנא נסה שוב מאוחר יותר", + "Log in to enable cloud backup": "התחבר כדי להפעיל גיבוי ענן", + "Backup Failed": "הגיבוי נכשל", + "Downloading backup...": "מוריד גיבוי...", + "An update was found!": "נמצא עדכון!", + "{0} can be updated to version {1}": "ניתן לעדכן את {0} לגרסה {1}", + "Updates found!": "נמצאו עדכונים!", + "{0} packages can be updated": "עדכון זמין עבור {0} חבילות", + "{0} is being updated to version {1}": "{0} מתעדכן לגרסה {1}", + "{0} packages are being updated": "מעדכן {0} חבילות", + "You have currently version {0} installed": "כרגע מותקנת גרסה {0}", + "Desktop shortcut created": "נוצר קיצור דרך בשולחן העבודה", + "UniGetUI has detected a new desktop shortcut that can be deleted automatically.": "UniGetUI זיהה קיצור דרך חדש בשולחן העבודה שניתן למחוק אוטומטית.", + "{0} desktop shortcuts created": "נוצרו {0} קיצורי דרך בשולחן העבודה", + "UniGetUI has detected {0} new desktop shortcuts that can be deleted automatically.": "UniGetUI זיהה {0} קיצורי דרך חדשים בשולחן העבודה שניתן למחוק אוטומטית.", + "Attention required": "נדרשת תשומת לב", + "Restart required": "נדרשת הפעלה מחדש", + "1 update is available": "1 עדכון קיים", + "{0} updates are available": "{0} עדכונים זמינים", + "Everything is up to date": "הכל מעודכן", + "Discover Packages": "גלה חבילות", + "Available Updates": "עדכונים זמינים", + "Installed Packages": "חבילות מותקנות", + "UniGetUI Version {0} by Devolutions": "UniGetUI גרסה {0} מאת Devolutions", + "Show UniGetUI": "הצג את UniGetUI", + "Quit": "צא", + "Are you sure?": "האם אתה בטוח?", + "Do you really want to uninstall {0}?": "האם אתה בטוח שאתה רוצה להסיר את {0}?", + "Do you really want to uninstall the following {0} packages?": "האם אתה באמת רוצה להסיר את ההתקנה של {0} החבילות הבאות?", + "No": "לא", + "Yes": "כן", + "Partial": "חלקי", + "View on UniGetUI": "הצג ב-UniGetUI", + "Update": "עדכון", + "Open UniGetUI": "פתח את UniGetUI", + "Update all": "עדכן הכל", + "Update now": "עדכן כעת", + "Installer host changed since the installed version.\n": "מארח המתקין השתנה מאז הגרסה המותקנת.\n", + "This package is on the queue": "החבילה הזו נמצאת בתור", + "installing": "מתקין", + "updating": "מעדכן", + "uninstalling": "מסיר התקנה", + "installed": "מותקנת", + "Retry": "נסה שוב", + "Install": "התקן", + "Uninstall": "הסר", + "Open": "פתח", + "Operation profile:": "פרופיל פעולה:", + "Follow the default options when installing, upgrading or uninstalling this package": "עקוב אחר האפשרויות ברירת המחדל בעת התקנה, שדרוג או הסרת התקנה של חבילה זו", + "The following settings will be applied each time this package is installed, updated or removed.": "ההגדרות הבאות יחולו בכל פעם שהחבילה הזו תותקן, תעודכן או תוסר.", + "Version to install:": "גרסה להתקנה:", + "Architecture to install:": "ארכיטקטורה להתקנה: ", + "Installation scope:": "היקף התקנה:", + "Install location:": "מיקום ההתקנה:", + "Select": "בחר", + "Reset": "אפס", + "Custom install arguments:": "ארגומנטים מותאמים להתקנה:", + "Custom update arguments:": "ארגומנטים מותאמים לעדכון:", + "Custom uninstall arguments:": "ארגומנטים מותאמים להסרת התקנה:", + "Pre-install command:": "פקודת טרום-התקנה:", + "Post-install command:": "פקודת פוסט-התקנה:", + "Abort install if pre-install command fails": "בטל התקנה אם פקודת טרום-התקנה נכשלת", + "Pre-update command:": "פקודת טרום-עדכון:", + "Post-update command:": "פקודת פוסט-עדכון:", + "Abort update if pre-update command fails": "בטל עדכון אם פקודת טרום-עדכון נכשלת", + "Pre-uninstall command:": "פקודת טרום-הסרה:", + "Post-uninstall command:": "פקודת פוסט-הסרה:", + "Abort uninstall if pre-uninstall command fails": "בטל הסרת התקנה אם פקודת טרום-הסרה נכשלת", + "Command-line to run:": "פקודה להרצה:", + "Save and close": "שמור וסגור", + "General": "כללי", + "Architecture & Location": "ארכיטקטורה ומיקום", + "Command-line": "שורת פקודה", + "Close apps": "סגור יישומים", + "Pre/Post install": "לפני/אחרי התקנה", + "Select the processes that should be closed before this package is installed, updated or uninstalled.": "בחר את התהליכים שיש לסגור לפני החבילה מותקנת, מתעדכנת או מוסרת.", + "Write here the process names here, separated by commas (,)": "כתוב כאן את שמות התהליכים, מופרדים בפסיקים (,)", + "Try to kill the processes that refuse to close when requested to": "נסה להרג את התהליכים המסרבים להיסגר כאשר נדרש מהם", + "Run as admin": "הפעל כמנהל מערכת", + "Interactive installation": "התקנה אינטראקטיבית", + "Skip hash check": "דלג על בדיקת הגיבוב", + "Uninstall previous versions when updated": "הסר גרסאות קודמות בעדכון", + "Skip minor updates for this package": "דלג על עדכונים מינוריים עבור חבילה זו", + "Automatically update this package": "עדכן חבילה זו באופן אוטומטי", + "{0} installation options": "{0} אפשרויות התקנה", + "Latest": "עדכנית ביותר", + "PreRelease": "טרום שחרור", + "Default": "ברירת מחדל", + "Manage ignored updates": "נהל עדכונים שהמערכת מתעלמת מהם", + "The packages listed here won't be taken in account when checking for updates. Double-click them or click the button on their right to stop ignoring their updates.": "החבילות המפורטות כאן לא יילקחו בחשבון בעת ​​בדיקת עדכונים. לחץ עליהם פעמיים או לחץ על הכפתור בצד ימין שלהם כדי להפסיק להתעלם מהעדכונים שלהם.", + "Reset list": "אפס רשימה", + "Do you really want to reset the ignored updates list? This action cannot be reverted": "האם אתה בטוח שברצונך לאפס את רשימת העדכונים שהתעלמת מהם? לא ניתן לבטל פעולה זו", + "No ignored updates": "אין עדכונים שהתעלמת מהם", + "Package Name": "שם החבילה", + "Package ID": "מזהה החבילה", + "Ignored version": "גרסה חסומה", + "New version": "גרסה חדשה", + "Source": "מקור", + "All versions": "כל הגירסאות", + "Unknown": "לא ידוע", + "Up to date": "מעודכן", + "Package {name} from {manager}": "חבילה {name} מ-{manager}", + "Remove {0} from ignored updates": "הסר את {0} מעדכונים שהתעלמו מהם", + "Cancel": "ביטול", + "Administrator privileges": "הרשאות מנהל", + "This operation is running with administrator privileges.": "פעולה זו פועלת עם הרשאות מנהל מערכת.", + "Interactive operation": "הפעלה אינטראקטיבית", + "This operation is running interactively.": "פעולה זו פועלת באינטראקטיביות.", + "You will likely need to interact with the installer.": "כנראה שתצטרך לבצע פעולות עם המתקין.", + "Integrity checks skipped": "בדיקות תקינות דוולגו", + "Integrity checks will not be performed during this operation.": "בדיקות תקינות לא יבוצעו במהלך פעולה זו.", + "Proceed at your own risk.": "המשך על אחריותך בלבד.", + "Close": "סגירה", + "Loading...": "טוען...", + "Installer SHA256": "התקנה SHA256", + "Homepage": "דף הבית", + "Author": "מחבר", + "Publisher": "מפרסם", + "License": "רישיון", + "Manifest": "מניפסט", + "Installer Type": "סוג תוכנת התקנה", + "Size": "גודל", + "Installer URL": "כתובת האתר של המתקין", + "Last updated:": "עודכן לאחרונה:", + "Release notes URL": "כתובת האתר של הערות גרסה", + "Package details": "פרטי החבילה", + "Dependencies:": "תלויות:", + "Release notes": "הערות שחרור", + "Screenshots": "צילומי מסך", + "This package has no screenshots or is missing the icon? Contribute to UniGetUI by adding the missing icons and screenshots to our open, public database.": "לחבילה זו אין צילומי מסך או שחסר לה הסמל? תרמו ל-UniGetUI על ידי הוספת הסמלים וצילומי המסך החסרים למסד הנתונים הפתוח והציבורי שלנו.", + "Version": "גרסה", + "Install as administrator": "התקן כמנהל מערכת", + "Update to version {0}": "עדכן לגרסה {0}", + "Installed Version": "גרסה מותקנת", + "Update as administrator": "עדכן כמנהל", + "Interactive update": "עדכון אינטרקטיבי", + "Uninstall as administrator": "הסר כמנהל מערכת", + "Interactive uninstall": "הסרת התקנה אינטראקטיבית", + "Uninstall and remove data": "הסר התקנה והסר נתונים", + "Not available": "לא זמין", + "Installer SHA512": "התקנה SHA512", + "Unknown size": "גודל לא ידוע", + "No dependencies specified": "לא צוינו תלויות", + "mandatory": "חובה", + "optional": "אופציונלי", + "UniGetUI {0} is ready to be installed.": "UniGetUI {0} מוכן להתקנה.", + "The update process will start after closing UniGetUI": "תהליך העדכון יתחיל לאחר סגירת UniGetUI", + "UniGetUI has been ran as administrator, which is not recommended. When running UniGetUI as administrator, EVERY operation launched from UniGetUI will have administrator privileges. You can still use the program, but we highly recommend not running UniGetUI with administrator privileges.": "UniGetUI הופעל כמנהל מערכת, וזה אינו מומלץ. כאשר UniGetUI פועל כמנהל מערכת, כל פעולה שמופעלת ממנו תקבל הרשאות מנהל. עדיין ניתן להשתמש בתוכנית, אך אנו ממליצים בחום לא להפעיל את UniGetUI כמנהל מערכת.", + "Share anonymous usage data": "שתף נתוני שימוש אנונימיים", + "UniGetUI collects anonymous usage data in order to improve the user experience.": "UniGetUI אוסף נתוני שימוש אנונימיים על מנת לשפר את חוויית המשתמש.", + "Accept": "מאשר", + "Software Updates": "עדכוני תוכנה", + "Package Bundles": "צרורות חבילות", + "Settings": "הגדרות", + "Package Managers": "מנהלי החבילות", + "UniGetUI Log": "יומן UniGetUI", + "Package Manager logs": "קבצי יומן רישום של מנהל החבילות", + "Operation history": "הסטוריית פעולות", + "Help": "עזרה", + "UniGetUI": "UniGetUI", + "You have installed UniGetUI Version {0}": "התקנת את גירסת UniGetUI {0}", + "Disclaimer": "כתב ויתור", + "UniGetUI is developed by Devolutions and is not affiliated with any of the compatible package managers.": "UniGetUI פותח על ידי Devolutions ואינו משויך לאף אחד ממנהלי החבילות התואמים.", + "UniGetUI wouldn't have been possible without the help of the contributors. Thank you all 🥳": "UniGetUI לא היה קורה ללא עזרת התורמים. תודה לכולכם 🥳", + "UniGetUI uses the following libraries. Without them, UniGetUI wouldn't have been possible.": "UniGetUI משתמש בספריות הבאות. בלעדיהם, UniGetUI לא היה אפשרי.", + "{0} homepage": "דף הבית של {0}", + "UniGetUI has been translated to more than 40 languages thanks to the volunteer translators. Thank you 🤝": "UniGetUI תורגם ליותר מ-40 שפות הודות למתרגמים המתנדבים. תודה לך 🤝", + "Verbose": "מפורט", + "1 - Errors": "1 - שגיאות", + "2 - Warnings": "2 - התראות", + "3 - Information (less)": "3 - מידע (מקוצר)", + "4 - Information (more)": "4 - מידע (מורחב)", + "5 - information (debug)": "5 - מידע (דיבאג)", + "Warning": "אזהרה", + "The following settings may pose a security risk, hence they are disabled by default.": "ההגדרות הבאות עשויות להיות סיכון אבטחה, ולכן הן מושבתות כברירת מחדל.", + "Enable the settings below if and only if you fully understand what they do, and the implications they may have.": "אפשר את ההגדרות למטה רק אם אתה מבין בהחלט מה הן עושות והמשמעויות שהן עלולות להיות להן.", + "The settings will list, in their descriptions, the potential security issues they may have.": "ההגדרות יוצגו בתיאור שלהן בבעיות הביטחוניות הפוטנציאליות שלהן.", + "The backup will include the complete list of the installed packages and their installation options. Ignored updates and skipped versions will also be saved.": "הגיבוי יכלול את הרשימה המלאה של החבילות המותקנות ואפשרויות ההתקנה שלהן. גם עדכונים שהתעלמו מהם וגרסאות שדילגתם יישמרו.", + "The backup will NOT include any binary file nor any program's saved data.": "הגיבוי לא יכלול שום קובץ בינארי או נתונים שנשמרו של כל תוכנה.", + "The size of the backup is estimated to be less than 1MB.": "גודל הגיבוי מוערך בפחות מ-1MB.", + "The backup will be performed after login.": "הגיבוי יתבצע לאחר הכניסה.", + "{pcName} installed packages": "חבילות מותקנות של {pcName}", + "Current status: Not logged in": "מצב נוכחי: לא מחובר", + "You are logged in as {0} (@{1})": "אתה מחובר כ-{0} (@{1})", + "Nice! Backups will be uploaded to a private gist on your account": "נהדר! גיבויים יועלו לגיסט פרטי בחשבון שלך", + "Select backup": "בחר גיבוי", + "Settings imported from {0}": "הגדרות יובאו מ-{0}", + "UniGetUI Settings": "הגדרות UniGetUI", + "Settings exported to {0}": "הגדרות יוצאו אל {0}", + "UniGetUI settings were reset": "הגדרות UniGetUI אופסו", + "Allow pre-release versions": "אפשר גירסאות קדם-הפצה", + "Apply": "החל", + "For security reasons, custom command-line arguments are disabled by default. Go to UniGetUI security settings to change this.": "מטעמי אבטחה, ארגומנטים מותאמים אישית של שורת הפקודה מושבתים כברירת מחדל. עבור להגדרות האבטחה של UniGetUI כדי לשנות זאת.", + "Go to UniGetUI security settings": "עבור אל הגדרות האבטחה של UniGetUI", + "The following options will be applied by default each time a {0} package is installed, upgraded or uninstalled.": "האפשרויות הבאות יחולו כברירת מחדל בכל פעם שחבילה {0} מותקנת, משודרגת או מוסרת.", + "Package's default": "ברירת מחדל של חבילה", + "Install location can't be changed for {0} packages": "מיקום ההתקנה אינו יכול להשתנות עבור חבילות {0}", + "The local icon cache currently takes {0} MB": "מטמון הסמלים המקומי תופס כעת {0} MB", + "Username": "שם-משתמש", + "Password": "סיסמה", + "Credentials": "פרטי התחברות", + "It is not guaranteed that the provided credentials will be stored safely": "לא מובטח שפרטי ההתחברות שסופקו יישמרו באופן בטוח", + "Partially": "באופן חלקי", + "Package manager": "מנהל החבילה", + "Compatible with proxy": "תואם לפרוקסי", + "Compatible with authentication": "תואם לאימות", + "Proxy compatibility table": "טבלת תאימות פרוקסי", + "{0} settings": "הגדרות {0}", + "{0} status": "סטטוס {0}", + "Default installation options for {0} packages": "אפשרויות התקנה ברירת מחדל עבור חבילות {0}", + "Expand version": "מידע גרסה", + "The executable file for {0} was not found": "לא נמצא קובץ ההפעלה עבור {0}", + "{pm} is disabled": "{pm} מושבת", + "Enable it to install packages from {pm}.": "אפשר אותו להתקין חבילות מ-{pm}.", + "{pm} is enabled and ready to go": "{pm} מופעל ומוכן להפעלה", + "{pm} version:": "{pm} גרסה:", + "{pm} was not found!": "{pm} לא נמצא!", + "You may need to install {pm} in order to use it with UniGetUI.": "ייתכן שתצטרך להתקין את {pm} כדי להשתמש בו עם UniGetUI.", + "Scoop Installer - UniGetUI": "מתקין סקופ - UniGetUI", + "Scoop Uninstaller - UniGetUI": "מסיר Scoop – UniGetUI", + "Clearing Scoop cache - UniGetUI": "ניקוי מטמון Scoop - UniGetUI", + "Restart UniGetUI to fully apply changes": "הפעל מחדש את UniGetUI כדי להחיל את השינויים במלואם", + "Restart UniGetUI": "הפעל מחדש את UniGetUI", + "Manage {0} sources": "נהל {0} מקורות", + "Add source": "הוסף מקור", + "Add": "הוסף", + "Source name": "שם המקור", + "Source URL": "כתובת המקור", + "Other": "אחר", + "No minimum age": "ללא גיל מינימלי", + "1 day": "יום אחד", + "{0} days": "{0} ימים", + "Custom...": "מותאם אישית...", + "{0} minutes": "{0} דקות", + "1 hour": "שעה אחת", + "{0} hours": "{0} שעות", + "1 week": "שבוע אחד", + "Supports release dates": "תומך בתאריכי שחרור", + "Release date support per package manager": "תמיכה בתאריכי שחרור לפי מנהל חבילות", + "Search for packages": "חפש חבילות", + "Local": "מקומי", + "OK": "אישור", + "Last checked: {0}": "בדיקה אחרונה: {0}", + "{0} packages were found, {1} of which match the specified filters.": "נמצאו {0} חבילות, {1} מהן תואמות למסננים שצוינו.", + "{0} selected": "נבחר{0} ", + "(Last checked: {0})": "(נבדק לאחרונה: {0})", + "All packages selected": "כל החבילות נבחרו", + "Package selection cleared": "בחירת החבילות נוקתה", + "{0}: {1}": "{0}: {1}", + "More info": "מידע נוסף", + "GitHub account": "חשבון GitHub", + "Log in with GitHub to enable cloud package backup.": "התחבר עם GitHub כדי להפעיל גיבוי חבילות ענן.", + "More details": "פרטים נוספים", + "Log in": "כניסה", + "If you have cloud backup enabled, it will be saved as a GitHub Gist on this account": "אם הפעלת גיבוי בענן, הוא יישמר כ-GitHub Gist בחשבון זה", + "Log out": "התנתק", + "About UniGetUI": "אודות UniGetUI", + "About": "אודות", + "Third-party licenses": "רישיונות צד שלישי", + "Contributors": "תורמים", + "Translators": "מתרגמים", + "Bundle security report": "דוח אבטחה לצרור", + "The bundle contained restricted content": "הצרור הכיל תוכן מוגבל", + "UniGetUI – Crash Report": "UniGetUI – דוח קריסה", + "UniGetUI has crashed": "UniGetUI קרס", + "Help us fix this by sending a crash report to Devolutions. All fields below are optional.": "עזור לנו לתקן זאת על ידי שליחת דוח קריסה ל-Devolutions. כל השדות להלן הם אופציונליים.", + "Email (optional)": "דוא\"ל (אופציונלי)", + "your@email.com": "your@email.com", + "Additional details (optional)": "פרטים נוספים (אופציונלי)", + "Describe what you were doing when the crash occurred…": "תאר מה עשית כשהקריסה התרחשה…", + "Crash report": "דוח קריסה", + "Don't Send": "אל תשלח", + "Send Report": "שלח דוח", + "Sending…": "שולח…", + "Unsaved changes": "שינויים שלא נשמרו", + "You have unsaved changes in the current bundle. Do you want to discard them?": "יש שינויים שלא נשמרו בצרור הנוכחי. האם ברצונך לבטל אותם?", + "Discard changes": "בטל שינויים", + "Integrity violation": "הפרת תקינות", + "UniGetUI or some of its components are missing or corrupt. It is strongly recommended to reinstall UniGetUI to adress the situation.": "UniGetUI או חלק מרכיביו חסרים או פגומים. מומלץ מאוד להתקין מחדש את UniGetUI כדי לטפל במצב.", + "• Refer to the UniGetUI Logs to get more details regarding the affected file(s)": "• עיין ביומני הרישום של UniGetUI כדי לקבל פרטים נוספים בנוגע לקבצים המושפעים", + "• Integrity checks can be disabled from the Experimental Settings": "• בדיקות תקינות יכולות להיות מושבתות מהגדרות הניסיוניות", + "Manage shortcuts": "נהל קיצורי דרך", + "UniGetUI has detected the following desktop shortcuts which can be removed automatically on future upgrades": "UniGetUI זיהה את קיצורי הדרך הבאים שניתן להסיר אוטומטית בעדכונים עתידיים", + "Do you really want to reset this list? This action cannot be reverted.": "האם אתה בטוח שברצונך לאפס רשימה זו? פעולה זו אינה ניתנת לביטול.", + "Desktop shortcuts list": "רשימת קיצורי דרך בשולחן העבודה", + "Open in explorer": "פתח בסייר הקבצים", + "Remove from list": "הסר מהרשימה", + "When new shortcuts are detected, delete them automatically instead of showing this dialog.": "כאשר מתגלים קיצורי דרך חדשים, הם יימחקו אוטומטית במקום להציג תיבת דו-שיח זו.", + "Not right now": "לא כעת", + "Missing dependency": "חבילת תלות חסרה", + "UniGetUI requires {0} to operate, but it was not found on your system.": "UniGetUI דורש את {0} כדי לפעול, אך לא נמצא במערכת שלך.", + "Click on Install to begin the installation process. If you skip the installation, UniGetUI may not work as expected.": "לחץ על התקן כדי להתחיל את תהליך ההתקנה. אם תדלג על ההתקנה, יתכן ש-, UniGetUI לא יעבוד כראוי. ", + "Alternatively, you can also install {0} by running the following command in a Windows PowerShell prompt:": "לחלופין, אתה יכול גם להתקין {0} על ידי הפעלת הפקודה הבאה ב- Windows PowerShell:", + "Install {0}": "התקן {0}", + "Do not show this dialog again for {0}": "אל תציג חלון זה שוב עבור {0}", + "Please wait while {0} is being installed. A black window may show up. Please wait until it closes.": "נא להמתין בזמן ש-{0} מותקן. ייתכן שיופיע חלון שחור. יש להמתין עד לסגירתו.", + "{0} has been installed successfully.": "{0} הותקן בהצלחה.", + "Please click on \"Continue\" to continue": "אנא לחץ על \"המשך\" כדי להמשיך", + "Continue": "המשך", + "{0} has been installed successfully. It is recommended to restart UniGetUI to finish the installation": "{0} הותקן בהצלחה. מומלץ להפעיל מחדש את UniGetUI כדי להשלים את ההתקנה", + "Restart later": "הפעל מחדש מאוחר יותר", + "An error occurred:": "אירעה שגיאה:", + "Please see the Command-line Output or refer to the Operation History for further information about the issue.": "אנא עיין בפלט שורת הפקודה או עיין בהסטוריית המבצעים למידע נוסף על הבעיה.", + "Retry as administrator": "נסה שוב כמנהל מערכת", + "Retry interactively": "נסה שוב באינטראקטיביות", + "Retry skipping integrity checks": "נסה שוב תוך דילוג על בדיקות תקינות", + "Installation options": "אפשרויות התקנה", + "Save": "שמור", + "UniGetUI collects anonymous usage data with the sole purpose of understanding and improving the user experience.": "UniGetUI אוסף נתוני שימוש אנונימיים אך ורק לצורך הבנת חוויית המשתמש ושיפורה.", + "More details about the shared data and how it will be processed": "פרטים נוספים על הנתונים המשותפים ואופן עיבודם", + "Do you accept that UniGetUI collects and sends anonymous usage statistics, with the sole purpose of understanding and improving the user experience?": "האם אתה מסכים ש-UniGetUI יאסוף וישלח נתוני שימוש אנונימיים, אך ורק לצורך הבנת חוויית המשתמש ושיפורה?", + "Decline": "דחה", + "No personal information is collected nor sent, and the collected data is anonimized, so it can't be back-tracked to you.": "מידע אישי לא נאסף או נשלח, והנתונים שנאספים הם אנונימיים, ואינם מקושרים אליך.", + "Navigation panel": "חלונית ניווט", + "Operations": "פעולות", + "Toggle operations panel": "הצג/הסתר את לוח הפעולות", + "Bulk operations": "פעולות מרובות", + "Retry failed": "נסה שוב פעולות שנכשלו", + "Clear successful": "נקה פעולות שהצליחו", + "Clear finished": "נקה פעולות שהסתיימו", + "Cancel all": "בטל הכל", + "More": "עוד", + "Toggle navigation panel": "הצג או הסתר את חלונית הניווט", + "Minimize": "מזער", + "Maximize": "הגדל", + "UniGetUI by Devolutions": "UniGetUI מאת Devolutions", + "UniGetUI is an application that makes managing your software easier, by providing an all-in-one graphical interface for your command-line package managers.": "UniGetUI הוא יישום שמקל על ניהול התוכנה שלך, על ידי מתן ממשק גרפי הכל-באחד עבור מנהלי חבילות שורת הפקודה שלך.", + "Useful links": "קישורים שימושיים", + "UniGetUI Homepage": "דף הבית של UniGetUI", + "Report an issue or submit a feature request": "דווח על בעיה או שלח בקשה לתכונה", + "UniGetUI Repository": "מאגר UniGetUI", + "View GitHub Profile": "הצג את פרופיל GitHub", + "UniGetUI License": "רישיון UniGetUI", + "Using UniGetUI implies the acceptation of the MIT License": "שימוש ב-UniGetUI מרמז על קבלת רישיון MIT", + "Become a translator": "הפוך למתרגם", + "Go back": "חזור אחורה", + "Go forward": "המשך קדימה", + "Go to home page": "עבור לדף הבית", + "Reload page": "טען מחדש את הדף", + "View page on browser": "צפה בדף בדפדפן", + "The built-in browser is not supported on Linux yet.": "הדפדפן המובנה אינו נתמך עדיין ב-Linux.", + "Open in browser": "פתח בדפדפן", + "Copy to clipboard": "העתק ללוח", + "Export to a file": "יצא לקובץ", + "Log level:": "רמת יומן:", + "Reload log": "טען מחדש קובץ יומן רישום", + "Export log": "ייצא יומן", + "Text": "טֶקסט", + "Change how operations request administrator rights": "שינוי האופן שבו פעולות מבקשות הרשאות מנהל מערכת", + "Restrictions on package operations": "הגבלות על פעולות חבילה", + "Restrictions on package managers": "הגבלות על מנהלי חבילות", + "Restrictions when importing package bundles": "הגבלות בעת ייבוא צרורות חבילות", + "Ask for administrator privileges once for each batch of operations": "בקש הרשאות מנהל פעם אחת עבור כל אצווה של פעולות", + "Ask only once for administrator privileges": "בקש פעם אחת בלבד הרשאות מנהל מערכת", + "Prohibit any kind of Elevation via UniGetUI Elevator or GSudo": "אסור על כל סוג של הרמה דרך UniGetUI Elevator או GSudo", + "This option WILL cause issues. Any operation incapable of elevating itself WILL FAIL. Install/update/uninstall as administrator will NOT WORK.": "אפשרות זו תגרום לבעיות. כל פעולה שאינה מסוגלת להרימנה עצמה תיכשל. התקנה/עדכון/הסרה כמנהל מערכת לא יפעלו.", + "Allow custom command-line arguments": "אפשר ארגומנטים מותאמים אישית של שורת הפקודה\n", + "Custom command-line arguments can change the way in which programs are installed, upgraded or uninstalled, in a way UniGetUI cannot control. Using custom command-lines can break packages. Proceed with caution.": "ארגומנטים מותאמים אישית של שורת הפקודה יכולים לשנות את הדרך שבה התוכנים מותקנים, מתעדכנים או מוסרים, באופן ש-UniGetUI אינו יכול לשלוט. שימוש בשורות פקודה מותאמות אישית עלול לגרום נזק לחבילות. יש לפעול בזהירות.", + "Ignore custom pre-install and post-install commands when importing packages from a bundle": "אפשר להפעיל פקודות מותאמות אישית לפני ואחרי ההתקנה בעת ייבוא חבילות מצרור", + "Pre and post install commands will be run before and after a package gets installed, upgraded or uninstalled. Be aware that they may break things unless used carefully": "פקודות טרום ופוסט התקנה ירוצו לפני ואחרי חבילה מותקנת, מתעדכנת או מוסרת. שים לב שהן עלולות לשבור דברים אלא אם משתמשים בהן בזהירות", + "Allow changing the paths for package manager executables": "אפשר שינוי נתיבים לקבצי הפעלה של מנהלי חבילות", + "Turning this on enables changing the executable file used to interact with package managers. While this allows finer-grained customization of your install processes, it may also be dangerous": "הדלקה של זה מאפשרת שינוי קובץ ההפעלה המשמש לביצוע עם מנהלי חבילות. בעוד זה מאפשר התאמת אישית פרטנית יותר לתהליכי ההתקנה שלך, זה עלול גם להיות מסוכן", + "Allow importing custom command-line arguments when importing packages from a bundle": "אפשר ייבוא ארגומנטים מותאמים אישית של שורת הפקודה בעת ייבוא חבילות מצרור", + "Malformed command-line arguments can break packages, or even allow a malicious actor to gain privileged execution. Therefore, importing custom command-line arguments is disabled by default": "ארגומנטים שגויים של שורת פקודה יכולים לשבור חבילות או אפילו לאפשר לגורם זדוני לקבל ביצוע מוגבה. לכן, ייבוא ארגומנטים מותאמים אישית של שורת פקודה מושבת כברירת מחדל", + "Allow importing custom pre-install and post-install commands when importing packages from a bundle": "אפשר ייבוא פקודות טרום-התקנה ופוסט-התקנה מותאמות אישית בעת ייבוא חבילות מצרור", + "Pre and post install commands can do very nasty things to your device, if designed to do so. It can be very dangerous to import the commands from a bundle, unless you trust the source of that package bundle": "פקודות טרום ואחרי התקנה יכולות לעשות דברים רעים מאוד למכשיר שלך, אם הן תוכננו לעשות זאת. זה יכול להיות מאוד מסוכן לייבא את הפקודות מצרור, אלא אם אתה סומך על מקור הצרור.", + "Administrator rights and other dangerous settings": "הרשאות מנהל והגדרות מסוכנות אחרות", + "Package backup": "גיבוי חבילות", + "Cloud package backup": "גיבוי חבילות בענן", + "Local package backup": "גיבוי חבילות מקומי", + "Local backup advanced options": "אפשרויות מתקדמות לגיבוי מקומי", + "Log in with GitHub": "התחבר באמצעות GitHub", + "Log out from GitHub": "התנתק מ-GitHub", + "Periodically perform a cloud backup of the installed packages": "בצע מעת לעת גיבוי ענן של החבילות המותקנות", + "Cloud backup uses a private GitHub Gist to store a list of installed packages": "גיבוי בענן משתמש ב-GitHub Gist פרטי כדי לאחסן רשימה של חבילות מותקנות", + "Perform a cloud backup now": "בצע גיבוי ענן כעת", + "Backup": "גיבוי", + "Restore a backup from the cloud": "שחזר גיבוי מהענן", + "Begin the process to select a cloud backup and review which packages to restore": "התחל בתהליך לבחירת גיבוי ענן ובדוק אילו חבילות לשחזר", + "Periodically perform a local backup of the installed packages": "בצע מעת לעת גיבוי מקומי של החבילות המותקנות", + "Perform a local backup now": "בצע גיבוי מקומי כעת", + "Change backup output directory": "שנה את ספריית פלט הגיבוי", + "Set a custom backup file name": "הגדר שם קובץ גיבוי מותאם אישית", + "Leave empty for default": "השאר ריק לברירת המחדל", + "Add a timestamp to the backup file names": "הוסף חותמת זמן לשמות קבצי הגיבוי", + "Backup and Restore": "גיבוי ושחזור", + "Enable background api (UniGetUI Widgets and Sharing, port 7058)": "אפשר API רקע (UniGetUI Widgets and Sharing, פורט 7058)", + "Wait for the device to be connected to the internet before attempting to do tasks that require internet connectivity.": "המתן לחיבור המכשיר לאינטרנט לפני ניסיון לבצע משימות הדורשות חיבור לרשת.", + "Disable the 1-minute timeout for package-related operations": "השבת את מגבלת הזמן של דקה אחת לפעולות הקשורות לחבילות", + "Use installed GSudo instead of UniGetUI Elevator": "השתמש ב-GSudo המותקן במקום UniGetUI Elevator", + "Use a custom icon and screenshot database URL": "השתמש בסמל מותאם אישית ובכתובת אתר של מסד נתונים צילומי מסך", + "Enable background CPU Usage optimizations (see Pull Request #3278)": "הפעל אופטימיזציות רקע לשימוש ב-CPU (ראה Pull Request #3278)", + "Perform integrity checks at startup": "בצע בדיקות תקינות בעת ההפעלה", + "When batch installing packages from a bundle, install also packages that are already installed": "בעת התקנה בכמות גדולה של חבילות מצרור, התקן גם חבילות שכבר מותקנות", + "Experimental settings and developer options": "הגדרות ניסיוניות ואפשרויות למפתחים ", + "Show UniGetUI's version and build number on the titlebar.": "הצג את גרסת UniGetUI בשורת הכותרת", + "Language": "שפה", + "UniGetUI updater": "עדכון UniGetUI", + "Telemetry": "טלמטריה", + "Manage UniGetUI settings": "נהל הגדרות UniGetUI", + "Related settings": "הגדרות קשורות", + "Update UniGetUI automatically": "עדכן את UniGetUI באופן אוטומטי", + "Check for updates": "בדוק עדכונים", + "Install prerelease versions of UniGetUI": "התקן גרסאות קדם של UniGetUI", + "Manage telemetry settings": "נהל הגדרות טלמטריה", + "Manage": "ניהול", + "Import settings from a local file": "יבא הגדרות מקובץ מקומי", + "Import": "יבא", + "Export settings to a local file": "יצא הגדרות לקובץ מקומי", + "Export": "יצא", + "Reset UniGetUI": "אפס את UniGetUI", + "User interface preferences": "העדפות ממשק משתמש", + "Application theme, startup page, package icons, clear successful installs automatically": "ערכת נושא, דף פתיחה, סמלי חבילות, ניקוי התקנות מוצלחות באופן אוטומטי", + "General preferences": "העדפות כלליות", + "UniGetUI display language:": "שפת התצוגה של UniGetUI:", + "System language": "שפת המערכת", + "Is your language missing or incomplete?": "האם השפה שלך חסרה או לא שלמה?", + "Appearance": "מראה ותחושה", + "UniGetUI on the background and system tray": "UniGetUI ברקע ובמגש המערכת", + "Package lists": "רשימות חבילות", + "Use classic mode": "השתמש במצב קלאסי", + "Restart UniGetUI to apply this change": "הפעל מחדש את UniGetUI כדי להחיל שינוי זה", + "The classic UI is disabled for beta testers": "ממשק המשתמש הקלאסי מושבת עבור בודקי בטא", + "Close UniGetUI to the system tray": "מזער את UniGetUI למגש המערכת", + "Manage UniGetUI autostart behaviour": "נהל את אופן ההפעלה האוטומטית של UniGetUI", + "Show package icons on package lists": "הצג סמלי חבילות ברשימות חבילות", + "Clear cache": "נקה מטמון", + "Select upgradable packages by default": "בחר חבילות הניתנות לשדרוג כברירת מחדל", + "Light": "בהיר", + "Dark": "כהה", + "Follow system color scheme": "עקוב אחר צבעי המערכת", + "Application theme:": "ערכת נושא:", + "UniGetUI startup page:": "דף הפתיחה של UniGetUI:", + "Proxy settings": "הגדרות Proxy", + "Other settings": "הגדרות אחרות", + "Connect the internet using a custom proxy": "התחבר לאינטרנט באמצעות Proxy מותאם אישית", + "Please note that not all package managers may fully support this feature": "שימו לב שלא כל מנהלי החבילות עשויים לתמוך בתכונה זו באופן מלא", + "Proxy URL": "כתובת Proxy", + "Enter proxy URL here": "הזן כאן כתובת URL של Proxy", + "Authenticate to the proxy with a user and a password": "הזדהה מול שרת ה-Proxy באמצעות שם משתמש וסיסמה", + "Internet and proxy settings": "הגדרות אינטרנט ו-Proxy", + "Package manager preferences": "העדפות של מנהל החבילות", + "Ready": "מוכן", + "Not found": "לא נמצא", + "Notification preferences": "העדפות הודעות", + "Notification types": "סוגי התראות", + "The system tray icon must be enabled in order for notifications to work": "יש להפעיל את סמל המגש כדי שההתראות יעבדו", + "Enable UniGetUI notifications": "אפשר הודעות של UniGetUI", + "Show a notification when there are available updates": "הצג התראה כאשר ישנם עדכונים זמינים", + "Show a silent notification when an operation is running": "הצג התראה שקטה כאשר פעולה מתבצעת", + "Show a notification when an operation fails": "הצג התראה כאשר פעולה נכשלת ", + "Show a notification when an operation finishes successfully": "הצג התראה כאשר פעולה מסתיימת בהצלחה", + "Concurrency and execution": "מקביליות וביצוע", + "Automatic desktop shortcut remover": "מסיר קיצורי דרך אוטומטי", + "Choose how many operations should be performed in parallel": "בחר כמה פעולות יבוצעו במקביל", + "Clear successful operations from the operation list after a 5 second delay": "נקה פעולות שהצליחו מרשימת הפעולות לאחר השהייה של 5 שניות", + "Download operations are not affected by this setting": "פעולות הורדה אינן מושפעות מהגדרה זו", + "You may lose unsaved data": "אתה עלול לאבד נתונים שלא נשמרו", + "Ask to delete desktop shortcuts created during an install or upgrade.": "בקש למחוק קיצורי דרך שנוצרו בשולחן העבודה במהלך התקנה או עדכון.", + "Package update preferences": "העדפות עדכון חבילה", + "Update check frequency, automatically install updates, etc.": "תדירות בדיקת עדכונים, התקנה אוטומטית של עדכונים ועוד.", + "Reduce UAC prompts, elevate installations by default, unlock certain dangerous features, etc.": "הפחת הודעות UAC, הרף התקנות כברירת מחדל, בטל נעילה של תכונות מסוכנות מסוימות וכו'.", + "Package operation preferences": "העדפות פעולת החבילה", + "Enable {pm}": "אפשר {pm}", + "Not finding the file you are looking for? Make sure it has been added to path.": "לא מוצא את הקובץ שאתה מחפש? וודא שהוא נוסף לנתיב.", + "Select the executable to be used. The following list shows the executables found by UniGetUI": "בחר את קובץ ההפעלה שיש להשתמש בו. הרשימה הבאה מציגה את קבצי ההפעלה שנמצאו על ידי UniGetUI", + "For security reasons, changing the executable file is disabled by default": "מסיבות אבטחה, שינוי קובץ ההפעלה מושבת כברירת מחדל", + "Change this": "שנה זאת", + "Copy path": "העתק נתיב", + "Current executable file:": "קובץ ההפעלה הנוכחי:", + "Ignore packages from {pm} when showing a notification about updates": "התעלם מחבילות מ-{pm} בעת הצגת התראה על עדכונים", + "Update security": "אבטחת עדכונים", + "Use global setting": "השתמש בהגדרה הגלובלית", + "Minimum age for updates": "גיל מינימלי לעדכונים", + "e.g. 10": "למשל 10", + "Custom minimum age (days)": "גיל מינימלי מותאם אישית (בימים)", + "{pm} does not provide release dates for its packages, so this setting will have no effect": "{pm} אינו מספק תאריכי שחרור עבור החבילות שלו, לכן להגדרה זו לא תהיה השפעה", + "{pm} only provides release dates for some of its packages, so this setting will only apply to those packages": "{pm} מספק תאריכי שחרור רק לחלק מהחבילות שלו, ולכן הגדרה זו תחול רק על אותן חבילות", + "Override the global minimum update age for this package manager": "עקוף את גיל העדכון המינימלי הגלובלי עבור מנהל חבילות זה", + "View {0} logs": "הצג לוגים של {0}", + "If Python cannot be found or is not listing packages but is installed on the system, ": "אם לא ניתן למצוא את Python או שהוא אינו מציג חבילות למרות שהוא מותקן במערכת, ", + "Advanced options": "אפשרויות מתקדמות", + "WinGet command-line tool": "כלי שורת הפקודה של WinGet", + "Choose which command-line tool UniGetUI uses for WinGet operations when the COM API is not used": "בחר באיזה כלי שורת פקודה UniGetUI ישתמש עבור פעולות WinGet כאשר לא נעשה שימוש ב-COM API", + "WinGet COM API": "COM API של WinGet", + "Choose whether UniGetUI can use the WinGet COM API before falling back to the command-line tool": "בחר אם UniGetUI יכול להשתמש ב-COM API של WinGet לפני מעבר לכלי שורת הפקודה", + "Reset WinGet": "אפס את WinGet", + "This may help if no packages are listed": "פעולה זו עשויה לעזור אם אין חבילות שמופיעות", + "Force install location parameter when updating packages with custom locations": "אכוף את פרמטר מיקום ההתקנה בעת עדכון חבילות עם מיקומים מותאמים אישית", + "Install Scoop": "התקן Scoop", + "Uninstall Scoop (and its packages)": "הסר את Scoop (ואת החבילות שלו)", + "Run cleanup and clear cache": "הפעל ניקוי ונקה מטמון", + "Run": "הרץ", + "Enable Scoop cleanup on launch": "אפשר ניקוי Scoop בעליה", + "Default vcpkg triplet": "הגדרת ברירת מחדל של vcpkg triplet", + "Change vcpkg root location": "שנה את מיקום השורש של vcpkg", + "Reset vcpkg root location": "אפס את מיקום שורש vcpkg", + "Open vcpkg root location": "פתח את מיקום שורש vcpkg", + "Language, theme and other miscellaneous preferences": "שפה, ערכת נושא והעדפות שונות אחרות", + "Show notifications on different events": "הצג התראות על אירועים שונים", + "Change how UniGetUI checks and installs available updates for your packages": "שנה את האופן שבו UniGetUI בודק ומתקין עדכונים זמינים עבור החבילות שלך", + "Automatically save a list of all your installed packages to easily restore them.": "שמור אוטומטית רשימה של כל החבילות המותקנות שלך כדי לשחזר אותן בקלות.", + "Enable and disable package managers, change default install options, etc.": "אפשר או השבת מנהלי חבילות, שנה אפשרויות התקנה ברירת מחדל וכו'.", + "Internet connection settings": "הגדרות חיבור לאינטרנט", + "Proxy settings, etc.": "הגדרות Proxy, ועוד.", + "Beta features and other options that shouldn't be touched": "תכונות בטא ואפשרויות אחרות שאסור לגעת בהן", + "Reload sources": "טען מחדש מקורות", + "Delete source": "מחק מקור", + "Known sources": "מקורות ידועים", + "Update checking": "בדיקת עדכונים", + "Automatic updates": "עדכונים אוטומטיים", + "Check for package updates periodically": "חפש עדכונים לחבילה מעת לעת", + "Check for updates every:": "חפש עדכונים כל:", + "Install available updates automatically": "התקן עדכונים זמינים באופן אוטומטי", + "Do not automatically install updates when the network connection is metered": "אל תתקין עדכונים באופן אוטומטי כאשר חיבור הרשת מוגדר כמוגבל", + "Do not automatically install updates when the device runs on battery": "אל תתקין עדכונים באופן אוטומטי כאשר המכשיר פועל על סוללה", + "Do not automatically install updates when the battery saver is on": "אל תתקין עדכונים באופן אוטומטי כאשר חיסכון בסוללה מופעל", + "Only show updates that are at least the specified number of days old": "הצג רק עדכונים שגילם לפחות מספר הימים שצוין", + "Warn me when the installer URL host changes between the installed version and the new version (WinGet only)": "הזהר אותי כאשר מארח כתובת ה-URL של המתקין משתנה בין הגרסה המותקנת לגרסה החדשה (WinGet בלבד)", + "Change how UniGetUI handles install, update and uninstall operations.": "שנה את האופן שבו UniGetUI מטפל בפעולות התקנה, עדכון והסרה.", + "Navigation": "ניווט", + "Check for UniGetUI updates": "בדוק אם קיימים עדכונים ל-UniGetUI", + "Quit UniGetUI": "צא מ-UniGetUI", + "Filters": "מסננים", + "Sources": "מקורות", + "Search for packages to start": "חפש חבילות כדי להתחיל", + "Select all": "בחר הכל", + "Clear selection": "ניקוי בחירה", + "Instant search": "חיפוש מיידי", + "Distinguish between uppercase and lowercase": "הבחנה בין אותיות רישיות לאותיות קטנות", + "Ignore special characters": "התעלם מתווים מיוחדים", + "Search mode": "מצב חיפוש", + "Both": "שניהם", + "Exact match": "התאמה מדוייקת", + "Show similar packages": "הצג חבילות דומות", + "Loading": "טוען", + "Package": "חבילה", + "More options": "אפשרויות נוספות", + "Order by:": "מיין לפי:", + "Name": "שם", + "Id": "מזהה", + "Ascendant": "בסדר עולה", + "Descendant": "בסדר יורד", + "View modes": "מצבי תצוגה", + "Reload": "טען מחדש", + "Closed": "סגור", + "Ascending": "סדר עולה", + "Descending": "סדר יורד", + "{0}: {1}, {2}": "{0}: {1}, {2}", + "Order by": "מיין לפי", + "No results were found matching the input criteria": "לא נמצאו תוצאות התואמות את קריטריוני הקלט", + "No packages were found": "לא נמצאו חבילות", + "Loading packages": "טוען חבילות", + "Skip integrity checks": "דלג על בדיקות תקינות", + "Download selected installers": "הורד מתקינים נבחרים", + "Install selection": "בחירת התקנה", + "Install options": "אפשרויות התקנה", + "Add selection to bundle": "הוסף בחירה לצרור", + "Download installer": "הורד את תוכנית ההתקנה", + "Uninstall selection": "בחירת הסרה", + "Uninstall options": "אפשרויות הסרה", + "Ignore selected packages": "התעלם מהחבילות המסומנות", + "Open install location": "פתח מיקום התקנה", + "Reinstall package": "התקן מחדש את החבילה", + "Uninstall package, then reinstall it": "הסר את החבילה ולאחר מכן התקן אותה מחדש", + "Ignore updates for this package": "התעלם מעדכונים עבור חבילה זו", + "WinGet malfunction detected": "זוהתה תקלה ב-WinGet", + "It looks like WinGet is not working properly. Do you want to attempt to repair WinGet?": "נראה ש-WinGet אינו פועל כראוי. האם ברצונך לנסות לתקן את WinGet?", + "Repair WinGet": "תקן את WinGet", + "Updates will no longer be ignored for {0}": "עדכונים לא יתעלמו עוד עבור {0}", + "Updates are now ignored for {0}": "עדכונים מתעלמים כעת עבור {0}", + "Do not ignore updates for this package anymore": "אל תתעלם יותר מעדכונים עבור חבילה זו", + "Add packages or open an existing package bundle": "הוסף חבילות או פתח צרור חבילות קיים", + "Add packages to start": "הוסף חבילות כדי להתחיל", + "The current bundle has no packages. Add some packages to get started": "הצרור הנוכחי ריק. הוסף חבילות כדי להתחיל", + "New": "חדש", + "Save as": "שמור בשם", + "Create .ps1 script": "צור קובץ Script של .ps1\n", + "Remove selection from bundle": "הסר את הבחירה מהצרור", + "Skip hash checks": "דלג על בדיקות גיבוב", + "The package bundle is not valid": "צרור החבילות אינו תקף", + "The bundle you are trying to load appears to be invalid. Please check the file and try again.": "הצרור שאתה מנסה לטעון נראה לא תקין. בדוק את הקובץ ונסה שוב.", + "Package bundle": "צרור חבילות", + "Could not create bundle": "לא ניתן ליצור צרור חבילות", + "The package bundle could not be created due to an error.": "לא ניתן היה ליצור את צרור החבילות עקב שגיאה.", + "Install script": "Script התקנה", + "PowerShell script": "סקריפט PowerShell", + "The installation script saved to {0}": "קובץ ה-Script של ההתקנה נשמר ל-{0}", + "An error occurred": "אירעה שגיאה", + "An error occurred while attempting to create an installation script:": "אירעה שגיאה בעת ניסיון ליצור קובץ Script להתקנה:", + "Hooray! No updates were found.": "הידד! לא נמצאו עדכונים!", + "Uninstall selected packages": "הסר את החבילות המסומנות", + "Update selection": "עדכון בחירות", + "Update options": "אפשרויות עדכון", + "Uninstall package, then update it": "הסר את החבילה ולאחר מכן עדכן אותה", + "Uninstall package": "הסר חבילה", + "Skip this version": "דלג על גרסה זו", + "Pause updates for": "השהה עדכונים ל-", + "User | Local": "משתמש | מקומי", + "Machine | Global": "מחשב | גלובלי", + "The default package manager for Debian/Ubuntu-based Linux distributions.
Contains: Debian/Ubuntu packages": "מנהל החבילות המוגדר כברירת מחדל עבור הפצות לינוקס מבוססות Debian/Ubuntu.
מכיל: חבילות Debian/Ubuntu", + "The Rust package manager.
Contains: Rust libraries and programs written in Rust": "מנהל החבילות של Rust.
מכיל: ספריות Rust ותוכנות שנכתבו ב-Rust", + "The classical package manager for windows. You'll find everything there.
Contains: General Software": "מנהל החבילות הקלאסי עבור Windows. תמצא שם הכל.
מכיל: תוכנה כללית", + "The default package manager for RHEL/Fedora-based Linux distributions.
Contains: RPM packages": "מנהל החבילות המוגדר כברירת מחדל עבור הפצות לינוקס מבוססות RHEL/Fedora.
מכיל: חבילות RPM", + "A repository full of tools and executables designed with Microsoft's .NET ecosystem in mind.
Contains: .NET related tools and scripts": "מאגר מלא של כלים וקובצי הפעלה שתוכננו מתוך מחשבה על מערכת האקולוגית .NET של Microsoft.
מכיל: כלים וסקריפטים הקשורים ל-.NET", + "The universal Linux package manager for desktop applications.
Contains: Flatpak applications from configured remotes": "מנהל החבילות האוניברסלי של Linux עבור יישומי שולחן עבודה.
מכיל: יישומי Flatpak ממקורות מרוחקים מוגדרים", + "NuPkg (zipped manifest)": "NuPkg (מניפסט מכווץ)", + "The Missing Package Manager for macOS (or Linux).
Contains: Formulae, Casks": "מנהל החבילות החסר עבור macOS (או Linux).
מכיל: Formulae, Casks", + "Node JS's package manager. Full of libraries and other utilities that orbit the javascript world
Contains: Node javascript libraries and other related utilities": "מנהל החבילות של Node JS. מלא ספריות וכלי עזר אחרים המקיפים את עולם javascript.
מכיל: ספריות Node JS וכלי עזר קשורים אחרים\n", + "The default package manager for Arch Linux and its derivatives.
Contains: Arch Linux packages": "מנהל החבילות המוגדר כברירת מחדל עבור Arch Linux והנגזרות שלו.
מכיל: חבילות Arch Linux", + "Python's library manager. Full of python libraries and other python-related utilities
Contains: Python libraries and related utilities": "מנהל הספרייה של Python. ספריות Python רבות וכלי עזר אחרים הקשורים ל- Python
מכיל: ספריות Python וכלי עזר קשורים", + "PowerShell's package manager. Find libraries and scripts to expand PowerShell capabilities
Contains: Modules, Scripts, Cmdlets": "מנהל החבילות של PowerShell. מצא ספריות וסקריפטים כדי להרחיב את יכולות PowerShell
מכיל: מודולים, סקריפטים, Cmdlets", + "extracted": "מחולץ", + "Scoop package": "חבילת Scoop", + "Great repository of unknown but useful utilities and other interesting packages.
Contains: Utilities, Command-line programs, General Software (extras bucket required)": "מאגר נהדר של כלי עזר לא ידועים אך שימושיים וחבילות מעניינות אחרות.
מכיל: כלי עזר, תוכניות שורת פקודה, תוכנה כללית (נדרשת דלי תוספות)", + "The universal Linux package manager by Canonical.
Contains: Snap packages from the Snapcraft store": "מנהל החבילות האוניברסלי של Linux מבית Canonical.
מכיל: חבילות Snap מחנות Snapcraft", + "library": "ספרייה", + "feature": "תכונה", + "A popular C/C++ library manager. Full of C/C++ libraries and other C/C++-related utilities
Contains: C/C++ libraries and related utilities": "מנהל חבילות פופולרי עבור ספריות C/C++. כולל ספריות C/C++ וכלים נוספים הקשורים ל-C/C++
מכיל: ספריות C/C++ וכלים נלווים", + "option": "אפשרות", + "This package cannot be installed from an elevated context.": "לא ניתן להתקין חבילה זו מתוך הקשר מוגבה.", + "Please run UniGetUI as a regular user and try again.": "הפעל את UniGetUI כמשתמש רגיל ונסה שוב.", + "Please check the installation options for this package and try again": "בדוק את אפשרויות ההתקנה של חבילה זו ונסה שוב", + "Microsoft's official package manager. Full of well-known and verified packages
Contains: General Software, Microsoft Store apps": "מנהל החבילות הרשמי של מיקרוסופט. מלא בחבילות ידועות ומאומתות
מכיל: תוכנה כללית, אפליקציות Microsoft Store", + "Local PC": "PC מקומי", + "Android Subsystem": "תת-מערכת אנדרואיד", + "Operation on queue (position {0})...": "פעולה בתור (מיקום {0})...", + "Click here for more details": "לחץ כאן למידע נוסף", + "Operation canceled by user": "הפעולה בוטלה על ידי המשתמש", + "Running PreOperation ({0}/{1})...": "מריץ PreOperation ({0}/{1})...", + "PreOperation {0} out of {1} failed, and was tagged as necessary. Aborting...": "PreOperation {0} מתוך {1} נכשל וסומן כחיוני. מבטל...", + "PreOperation {0} out of {1} finished with result {2}": "PreOperation {0} מתוך {1} הסתיים עם התוצאה {2}", + "Starting operation...": "מתחיל פעולה...", + "Running PostOperation ({0}/{1})...": "מריץ PostOperation ({0}/{1})...", + "PostOperation {0} out of {1} failed, and was tagged as necessary. Aborting...": "PostOperation {0} מתוך {1} נכשל וסומן כחיוני. מבטל...", + "PostOperation {0} out of {1} finished with result {2}": "PostOperation {0} מתוך {1} הסתיים עם התוצאה {2}", + "{package} installer download": "הורדת מתקין {package}", + "{0} installer is being downloaded": "המתקין של {0} מורד כעת", + "Download succeeded": "ההורדה הצליחה", + "{package} installer was downloaded successfully": "המתקין של {package} הורד בהצלחה", + "Download failed": "ההורדה נכשלה", + "{package} installer could not be downloaded": "לא ניתן להוריד את המתקין של {package}", + "{package} Installation": "{package} התקנה", + "{0} is being installed": "{0} מותקן כעת", + "Installation succeeded": "ההתקנה הצליחה", + "{package} was installed successfully": "{package} הותקן בהצלחה", + "Installation failed": "ההתקנה נכשלה", + "{package} could not be installed": "לא ניתן היה להתקין את {package}", + "{package} Update": "{package} עדכון", + "Update succeeded": "העדכון הצליח", + "{package} was updated successfully": "{package} עודכן בהצלחה", + "Update failed": "עדכון נכשל", + "{package} could not be updated": "לא ניתן היה לעדכן את {package}", + "{package} Uninstall": "{package} הסרת ההתקנה", + "{0} is being uninstalled": "{0} מוסר כעת", + "Uninstall succeeded": "הסרת ההתקנה הצליחה", + "{package} was uninstalled successfully": "ההתקנה של {package} הוסרה בהצלחה", + "Uninstall failed": "הסרת ההתקנה נכשלה", + "{package} could not be uninstalled": "לא ניתן היה להסיר את ההתקנה של {package}", + "Adding source {source}": "מוסיף מקור {source}", + "Adding source {source} to {manager}": "מוסיף מקור {source} ל-{manager}", + "Source added successfully": "המקור נוסף בהצלחה", + "The source {source} was added to {manager} successfully": "המקור {source} נוסף ל-{manager} בהצלחה", + "Could not add source": "לא ניתן להוסיף מקור", + "Could not add source {source} to {manager}": "לא ניתן להוסיף את המקור {source} ל-{manager}", + "Removing source {source}": "מסיר מקור {source}", + "Removing source {source} from {manager}": "מסיר את המקור {source} מ-{manager}", + "Source removed successfully": "המקור הוסר בהצלחה", + "The source {source} was removed from {manager} successfully": "המקור {source} הוסר מ-{manager} בהצלחה", + "Could not remove source": "לא ניתן להסיר מקור", + "Could not remove source {source} from {manager}": "לא ניתן להסיר את המקור {source} מ-{manager}", + "The package manager \"{0}\" was not found": "מנהל החבילות \"{0}\" לא נמצא", + "The package manager \"{0}\" is disabled": "מנהל החבילות \"{0}\" מושבת", + "There is an error with the configuration of the package manager \"{0}\"": "יש שגיאה בהגדרות של מנהל החבילות \"{0}\"", + "The package \"{0}\" was not found on the package manager \"{1}\"": "החבילה \"{0}\" לא נמצאה במנהל החבילות \"{1}\"", + "{0} is disabled": "{0} בלתי אפשרי", + "{0} weeks": "{0} שבועות", + "1 month": "חודש", + "{0} months": "{0} חודשים", + "Something went wrong": "משהו השתבש", + "An interal error occurred. Please view the log for further details.": "אירעה שגיאה פנימית. אנא עיין ביומן לפרטים נוספים.", + "No applicable installer was found for the package {0}": "לא נמצא מתקין מתאים עבור החבילה {0}", + "Integrity checks will not be performed during this operation": "בדיקות תקינות לא יתבצעו במהלך פעולה זו", + "This is not recommended.": "אין זה מומלץ.", + "Run now": "הפעל כעת", + "Run next": "הפעל הבא", + "Run last": "הפעל אחרון", + "Show in explorer": "הצג בסייר", + "Checked": "מסומן", + "Unchecked": "לא מסומן", + "This package is already installed": "חבילה זו כבר מותקנת", + "This package can be upgraded to version {0}": "חבילה זו ניתנת לשדרוג לגרסה {0}", + "Updates for this package are ignored": "עדכונים עבור חבילה זו נחסמו", + "This package is being processed": "חבילה זו נמצאת בעיבוד", + "This package is not available": "חבילה זו אינה זמינה", + "Select the source you want to add:": "בחר את המקור שברצונך להוסיף:", + "Source name:": "שם המקור:", + "Source URL:": "כתובת אתר מקור:", + "An error occurred when adding the source: ": "אירעה שגיאה בעת הוספת המקור:", + "Package management made easy": "ניהול חבילות בקלות", + "version {0}": "גרסה {0}", + "[RAN AS ADMINISTRATOR]": "[רץ כמנהל]", + "Portable mode": "מצב נייד", + "DEBUG BUILD": "גירסת ניפוי שגיאות", + "Here you can change UniGetUI's behaviour regarding the following shortcuts. Checking a shortcut will make UniGetUI delete it if if gets created on a future upgrade. Unchecking it will keep the shortcut intact": "כאן תוכל לשנות את אופן הפעולה של UniGetUI בנוגע לקיצורי הדרך הבאים. סימון קיצור דרך יגרום ל-UniGetUI למחוק אותו אם ייווצר בעתיד בעדכון. ביטול הסימון ישמור עליו ללא שינוי.", + "Manual scan": "סריקה ידנית", + "Existing shortcuts on your desktop will be scanned, and you will need to pick which ones to keep and which ones to remove.": "קיצורי הדרך הקיימים בשולחן העבודה שלך ייסרקו, ותצטרך לבחור אילו לשמור ואילו להסיר.", + "Delete?": "למחוק?", + "I understand": "אני מבין", + "Chocolatey setup changed": "הגדרת Chocolatey השתנתה", + "UniGetUI no longer includes its own private Chocolatey installation. A legacy UniGetUI-managed Chocolatey installation was detected for this user profile, but system Chocolatey was not found. Chocolatey will stay unavailable in UniGetUI until Chocolatey is installed on the system and UniGetUI is restarted. Applications previously installed through UniGetUI's bundled Chocolatey may still appear under other sources such as Local PC or WinGet.": "UniGetUI כבר לא כולל התקנת Chocolatey פרטית משלו. זוהתה התקנת Chocolatey ישנה שנוהלה על ידי UniGetUI עבור פרופיל משתמש זה, אך Chocolatey מערכתי לא נמצא. Chocolatey ימשיך להיות לא זמין ב-UniGetUI עד שתתבצע התקנת Chocolatey במערכת ו-UniGetUI יופעל מחדש. יישומים שהותקנו בעבר דרך Chocolatey המצורף של UniGetUI עשויים עדיין להופיע תחת מקורות אחרים כגון מחשב מקומי או WinGet.", + "NOTE: This troubleshooter can be disabled from UniGetUI Settings, on the WinGet section": "הערה: ניתן להשבית את פתרון הבעיות הזה מהגדרות UniGetUI, בסעיף WinGet", + "Restart": "הפעל מחדש", + "Are you sure you want to delete all shortcuts?": "האם אתה בטוח שברצונך למחוק את כל קיצורי הדרך?", + "Any new shorcuts created during an install or an update operation will be deleted automatically, instead of showing a confirmation prompt the first time they are detected.": "כל קיצור דרך חדש שיווצר במהלך התקנה או עדכון יימחק אוטומטית, במקום להציג הודעת אישור בפעם הראשונה שהוא מזוהה.", + "Any shorcuts created or modified outside of UniGetUI will be ignored. You will be able to add them via the {0} button.": "כל קיצור דרך שנוצר או נערך מחוץ ל-UniGetUI ייבדל. תוכל להוסיף אותם באמצעות כפתור {0}.", + "Are you really sure you want to enable this feature?": "האם אתה בטוח שברצונך להפעיל תכונה זו?", + "No new shortcuts were found during the scan.": "לא נמצאו קיצורי דרך חדשים במהלך הסריקה.", + "How to add packages to a bundle": "כיצד להוסיף חבילות לצרור", + "In order to add packages to a bundle, you will need to: ": "כדי להוסיף חבילות לצרור, עליך:", + "1. Navigate to the \"{0}\" or \"{1}\" page.": "1. עבור אל הדף \"{0}\" או \"{1}\".", + "2. Locate the package(s) you want to add to the bundle, and select their leftmost checkbox.": "2. אתר את החבילה/ות שברצונך להוסיף לצרור ובחר את תיבת הסימון השמאלית ביותר שלהן.", + "3. When the packages you want to add to the bundle are selected, find and click the option \"{0}\" on the toolbar.": "3. לאחר שבחרת את החבילות שברצונך להוסיף לצרור, אתר ולחץ על האפשרות \"{0}\" בסרגל הכלים.", + "4. Your packages will have been added to the bundle. You can continue adding packages, or export the bundle.": "4. החבילות שלך נוספו לצרור. תוכל להמשיך להוסיף חבילות או לייצא את הצרור.", + "Which backup do you want to open?": "איזה גיבוי אתה רוצה לפתוח?", + "Select the backup you want to open. Later, you will be able to review which packages you want to install.": "בחר את הגיבוי שאתה רוצה לפתוח. מאוחר יותר, תוכל לבדוק אילו חבילות אתה רוצה להתקין.", + "There are ongoing operations. Quitting UniGetUI may cause them to fail. Do you want to continue?": "יש פעולות שוטפות. יציאה מ-UniGetUI עלולה לגרום להם להיכשל. האם אתה רוצה להמשיך?", + "UniGetUI or some of its components are missing or corrupt.": "UniGetUI או חלק מרכיביו חסרים או פגומים.", + "It is strongly recommended to reinstall UniGetUI to adress the situation.": "מומלץ בחום להתקין מחדש את UniGetUI כדי לטפל בסיטואציה.", + "Refer to the UniGetUI Logs to get more details regarding the affected file(s)": "עיין ביומני הרישום של UniGetUI כדי לקבל פרטים נוספים בנוגע לקבצים המושפעים", + "Integrity checks can be disabled from the Experimental Settings": "בדיקות תקינות יכולות להיות מושבתות מהגדרות הניסיוניות", + "Repair UniGetUI": "תקן את UniGetUI", + "Live output": "פלט זמן אמת", + "This package bundle had some settings that are potentially dangerous, and may be ignored by default.": "צרור החבילות של חבילה זו הכיל הגדרות שעשויות להיות מסוכנות, ואולי יתעלמה ממנו כברירת מחדל.", + "Entries that show in YELLOW will be IGNORED.": "ערכים שמוצגים בצהוב יתעלמו.", + "Entries that show in RED will be IMPORTED.": "ערכים שמוצגים באדום ייובאו.", + "You can change this behavior on UniGetUI security settings.": "אתה יכול לשנות התנהגות זו בהגדרות האבטחה של UniGetUI.", + "Open UniGetUI security settings": "פתח הגדרות אבטחה של UniGetUI", + "Should you modify the security settings, you will need to open the bundle again for the changes to take effect.": "אם תשנה את הגדרות האבטחה, תצטרך לפתוח את הצרור מחדש כדי שהשינויים ייכנסו לתוקף.", + "Details of the report:": "פרטי הדוח:", + "Are you sure you want to create a new package bundle? ": "האם אתה בטוח שברצונך ליצור צרור חבילות חדש?", + "Any unsaved changes will be lost": "כל שינוי שלא יישמר יתבטל", + "Warning!": "אזהרה!", + "For security reasons, custom command-line arguments are disabled by default. Go to UniGetUI security settings to change this. ": "מסיבות אבטחה, ארגומנטים מותאמים אישית של שורת הפקודה מושבתים כברירת מחדל. עבור אל הגדרות האבטחה של UniGetUI כדי לשנות זאת.", + "Change default options": "שנה אפשרויות ברירת מחדל", + "Ignore future updates for this package": "התעלם מעדכוני תכונות לחבילה זו", + "For security reasons, pre-operation and post-operation scripts are disabled by default. Go to UniGetUI security settings to change this. ": "מסיבות אבטחה, סקריפטים של לפני פעולה ואחרי פעולה מושבתים כברירת מחדל. עבור אל הגדרות האבטחה של UniGetUI כדי לשנות זאת.", + "You can define the commands that will be run before or after this package is installed, updated or uninstalled. They will be run on a command prompt, so CMD scripts will work here.": "אתה יכול להגדיר פקודות שירוצו לפני או אחרי התקנה, עדכון או הסרה של חבילה זו. הן תרוצנה בשורת פקודה, כך ש-scripts של CMD יעבדו כאן.", + "Change this and unlock": "שנה זאת ובטל נעילה", + "{0} Install options are currently locked because {0} follows the default install options.": "אפשרויות התקנה של {0} נעלוות כרגע כי {0} עוקב אחר אפשרויות התקנה ברירת מחדל.", + "Unset or unknown": "לא מוגדר או לא ידוע", + "This package has no screenshots or is missing the icon? Contrbute to UniGetUI by adding the missing icons and screenshots to our open, public database.": "לחבילה הזו אין צילומי מסך או שחסר לו הסמל? תרום ל-UniGetUI על ידי הוספת הסמלים וצילומי המסך החסרים למסד הנתונים הפתוח והציבורי שלנו.", + "Become a contributor": "הפוך לתורם", + "Update to {0} available": "עדכון לגרסה{0} זמין", + "Reinstall": "התקן מחדש", + "Installer not available": "תוכנית ההתקנה אינה זמינה", + "Version:": "גרסה:", + "UniGetUI Version {0}": "UniGetUI גרסה {0}", + "Performing backup, please wait...": "מבצע גיבוי, אנא המתן...", + "An error occurred while logging in: ": "אירעה שגיאה במהלך הכניסה:", + "Fetching available backups...": "מושך גיבויים זמינים...", + "Done!": "הסתיים!", + "The cloud backup has been loaded successfully.": "גיבוי הענן נטען בהצלחה.", + "An error occurred while loading a backup: ": "אירעה שגיאה במהלך טעינת גיבוי:", + "Backing up packages to GitHub Gist...": "גיבוי חבילות ל-GitHub Gist...", + "Backup Successful": "הגיבוי הצליח", + "The cloud backup completed successfully.": "גיבוי הענן הושלם בהצלחה.", + "Could not back up packages to GitHub Gist: ": "לא היתה אפשרות לגבות חבילות ב- GitHub Gist: ", + "It is not guaranteed that the provided credentials will be stored safely, so you may as well not use the credentials of your bank account": "לא מובטח שהפרטים שסיפקת יאוחסנו בצורה בטוחה, לכן עדיף שלא תשתמש בפרטי החשבון הבנקאי שלך", + "Enable the automatic WinGet troubleshooter": "הפעל את פותר הבעיות האוטומטי של WinGet", + "Add updates that fail with a 'no applicable update found' to the ignored updates list": "הוסף עדכונים שנכשלים עם 'לא נמצא עדכון מתאים' לרשימת העדכונים שהמערכת תתעלם מהם", + "Invalid selection": "בחירה לא חוקית", + "No package was selected": "לא נבחרה חבילה", + "More than 1 package was selected": "נבחרה יותר מחבילה אחת", + "List": "רשימה", + "Grid": "רשת", + "Icons": "סמלים", + "\"{0}\" is a local package and does not have available details": "\"{0}\" היא חבילה מקומית, ואין לה פרטים זמינים", + "\"{0}\" is a local package and is not compatible with this feature": "\"{0}\" היא חבילה מקומית, ואינה תואמת לתכונה זו", + "Add packages to bundle": "הוסף חבילות לצרור", + "Preparing packages, please wait...": "מכין חבילות, אנא המתן...", + "Loading packages, please wait...": "טוען חבילות, אנא המתן...", + "Saving packages, please wait...": "שומר חבילות, אנא המתן...", + "The bundle was created successfully on {0}": "הצרור נוצר בהצלחה ב-{0}", + "User profile": "פרופיל משתמש", + "Error": "שגיאה", + "Log in failed: ": "הכניסה נכשלה:", + "Log out failed: ": "היציאה נכשלה:", + "Package backup settings": "הגדרות גיבוי חבילות", + "Manage UniGetUI autostart behaviour from the Settings app": "נהל את אופן ההפעלה האוטומטית של UniGetUI", + "Choose how many operations shoulds be performed in parallel": "בחר כמה פעולות יבוצעו במקביל", + "Something went wrong while launching the updater.": "משהו השתבש בעת הפעלת המעדכן.", + "Please try again later": "נסה שוב מאוחר יותר", + "Show the release notes after UniGetUI is updated": "הצג את הערות השחרור לאחר עדכון UniGetUI" +} diff --git a/src/Languages/lang_hi.json b/src/Languages/lang_hi.json new file mode 100644 index 0000000..aa4328d --- /dev/null +++ b/src/Languages/lang_hi.json @@ -0,0 +1,850 @@ +{ + "{0} of {1} operations completed": "{1} में से {0} कार्य पूर्ण हुए", + "{0} is now {1}": "{0} अब {1} है", + "Enabled": "सक्षम", + "Disabled": "अक्षम", + "Privacy": "गोपनीयता", + "Hide my username from the logs": "लॉग से मेरा उपयोगकर्ता नाम छिपाएँ", + "Replaces your username with **** in the logs. Restart UniGetUI to also hide it from already-recorded entries.": "लॉग में आपके उपयोगकर्ता नाम को **** से बदल देता है। पहले से दर्ज की गई प्रविष्टियों से भी इसे छिपाने के लिए UniGetUI को पुनः आरंभ करें।", + "Your last update attempt did not complete.": "आपका पिछला अपडेट प्रयास पूरा नहीं हुआ।", + "UniGetUI could not confirm whether the update succeeded. Open the log to see what happened.": "UniGetUI यह पुष्टि नहीं कर सका कि अपडेट सफल हुआ या नहीं। क्या हुआ यह देखने के लिए लॉग खोलें।", + "View log": "लॉग देखें", + "The installer reported success but did not restart UniGetUI.": "इंस्टॉलर ने सफलता रिपोर्ट की, लेकिन UniGetUI को पुनःआरंभ नहीं किया।", + "The installer failed to initialize.": "इंस्टॉलर प्रारंभ करने में विफल रहा।", + "Setup was canceled before installation began.": "इंस्टॉलेशन शुरू होने से पहले सेटअप रद्द कर दिया गया।", + "A fatal error occurred during the preparation phase.": "तैयारी चरण के दौरान एक गंभीर त्रुटि हुई।", + "A fatal error occurred during installation.": "इंस्टॉलेशन के दौरान एक गंभीर त्रुटि हुई।", + "Installation was canceled while in progress.": "इंस्टॉलेशन प्रगति में रहते हुए रद्द कर दिया गया।", + "The installer was terminated by another process.": "इंस्टॉलर को किसी अन्य प्रक्रिया ने समाप्त कर दिया।", + "The preparation phase determined the installation cannot proceed.": "तैयारी चरण ने निर्धारित किया कि इंस्टॉलेशन आगे नहीं बढ़ सकता।", + "The installer could not start. UniGetUI may already be running, or you do not have permission to install.": "इंस्टॉलर शुरू नहीं हो सका। UniGetUI पहले से चल रहा हो सकता है, या आपके पास इंस्टॉल करने की अनुमति नहीं है।", + "Unexpected installer error.": "अनपेक्षित इंस्टॉलर त्रुटि।", + "We are checking for updates.": "हम अपडेट्स चेक कर रहे हैं।", + "Please wait": "कृपया प्रतीक्षा करें", + "Great! You are on the latest version.": "बहुत बढ़िया! आप लेटेस्ट वर्शन पर हैं।", + "There are no new UniGetUI versions to be installed": "इंस्टॉल करने के लिए कोई नया यूनीगेटयूआई वर्शन उपलब्ध नहीं है।", + "UniGetUI version {0} is being downloaded.": "यूनिगेटयूआई संस्करण {0} डाउनलोड किया जा रहा है।", + "This may take a minute or two": "इसमें एक या दो मिनट लग सकते हैं।", + "The installer authenticity could not be verified.": "इंस्टॉलर की असलियत सत्यापित नहीं की जा सकी।", + "The update process has been aborted.": "अपडेट प्रक्रिया रद्द कर दी गई है।", + "Auto-update is not yet available on this platform.": "इस प्लेटफ़ॉर्म पर ऑटो-अपडेट अभी उपलब्ध नहीं है।", + "Please update UniGetUI manually.": "कृपया UniGetUI को मैन्युअल रूप से अपडेट करें।", + "An error occurred when checking for updates: ": "अपडेट चेक करते समय एक एरर आया:", + "The updater could not be launched.": "अपडेटर लॉन्च नहीं किया जा सका।", + "The operating system did not start the installer process.": "ऑपरेटिंग सिस्टम ने इंस्टॉलर प्रक्रिया शुरू नहीं की।", + "UniGetUI is being updated...": "यूनीगेटयूआई अपडेट हो रहा है...", + "Update installed.": "अपडेट इंस्टॉल हो गया।", + "UniGetUI was updated successfully, but this running copy was not replaced. This usually means you are running a development build. Close this copy and start the newly-installed version to finish.": "UniGetUI सफलतापूर्वक अपडेट हो गया, लेकिन यह चल रही कॉपी प्रतिस्थापित नहीं की गई। आमतौर पर इसका मतलब है कि आप डेवलपमेंट बिल्ड चला रहे हैं। समाप्त करने के लिए इस कॉपी को बंद करें और नया इंस्टॉल किया गया संस्करण शुरू करें।", + "The update could not be applied.": "अपडेट लागू नहीं किया जा सका।", + "Installer exit code {0}: {1}": "इंस्टॉलर निकास कोड {0}: {1}", + "Update cancelled.": "अपडेट रद्द किया गया।", + "Authentication was cancelled.": "प्रमाणीकरण रद्द किया गया।", + "Installer exit code {0}": "इंस्टॉलर निकास कोड {0}", + "Operation in progress": "ऑपरेशन प्रगति पर है", + "Please wait...": "कृपया प्रतीक्षा करें...", + "Success!": "सफलता!", + "Failed": "असफल", + "An error occurred while processing this package": "इस पैकेज को प्रोसेस करते समय एक एरर आया", + "Installer": "इंस्टॉलर", + "Executable": "एक्ज़ीक्यूटेबल", + "MSI": "MSI", + "Compressed file": "संपीड़ित फ़ाइल", + "MSIX": "MSIX", + "WinGet was repaired successfully": "विनगेट सफलतापूर्वक मरम्मत की गई", + "It is recommended to restart UniGetUI after WinGet has been repaired": "विनगेट के रिपेयर होने के बाद यूनीगेटयूआई को रीस्टार्ट करने की सलाह दी जाती है।", + "WinGet could not be repaired": "विनगेट मरम्मत नहीं की जा सकी", + "An unexpected issue occurred while attempting to repair WinGet. Please try again later": "विंगेट को ठीक करने की कोशिश करते समय एक अनचाही समस्या आई। कृपया बाद में फिर से कोशिश करें।", + "Log in to enable cloud backup": "क्लाउड बैकअप चालू करने के लिए लॉग इन करें", + "Backup Failed": "बैकअप विफल", + "Downloading backup...": "बैकअप डाउनलोड हो रहा है...", + "An update was found!": "एक अपडेट मिला!", + "{0} can be updated to version {1}": "{0} को संस्करण {1} तक अपडेट किया जा सकता है", + "Updates found!": "अपडेट मिले!", + "{0} packages can be updated": "{0} पैकेज अद्यतन किया जा सकता है", + "{0} is being updated to version {1}": "{0} को संस्करण {1} में अपडेट किया जा रहा है", + "{0} packages are being updated": "{0} पैकेज अपडेट किए जा रहे हैं", + "You have currently version {0} installed": "आपके पास वर्तमान में संस्करण {0} इंस्टॉल है", + "Desktop shortcut created": "डेस्कटॉप शॉर्टकट बनाया गया", + "UniGetUI has detected a new desktop shortcut that can be deleted automatically.": "यूनीगेटयूआई ने एक नया डेस्कटॉप शॉर्टकट डिटेक्ट किया है जिसे ऑटोमैटिकली डिलीट किया जा सकता है।", + "{0} desktop shortcuts created": "{0} डेस्कटॉप शॉर्टकट बनाए गए", + "UniGetUI has detected {0} new desktop shortcuts that can be deleted automatically.": "यूनीगेटयूआई ने पता लगाया है {0} नए डेस्कटॉप शॉर्टकट जिन्हें अपने आप डिलीट किया जा सकता है।", + "Attention required": "ध्यान देने की आवश्यकता", + "Restart required": "पुनरारंभ करना आवश्यक है", + "1 update is available": "1 अपडेट उपलब्ध है", + "{0} updates are available": "{0} अपडेट उपलब्ध हैं", + "Everything is up to date": "सब कुछ अप टू डेट है", + "Discover Packages": "पैकेज खोजें", + "Available Updates": "उपलब्ध अद्यतन", + "Installed Packages": "स्थापित पैकेज", + "UniGetUI Version {0} by Devolutions": "Devolutions द्वारा UniGetUI संस्करण {0}", + "Show UniGetUI": "UniGetUI दिखाएं", + "Quit": "बंद करें", + "Are you sure?": "क्या आप निश्चित हैं?", + "Do you really want to uninstall {0}?": "क्या आप वाकई {0} की स्थापना रद्द करना चाहते हैं?", + "Do you really want to uninstall the following {0} packages?": "क्या आप सच में नीचे दिए गए {0} पैकेज को अनइंस्टॉल करना चाहते हैं?", + "No": "नहीं", + "Yes": "हाँ", + "Partial": "आंशिक", + "View on UniGetUI": "यूनीगेटयूआई पर देखें", + "Update": "अपडेट", + "Open UniGetUI": "यूनीगेटयूआई खोलें", + "Update all": "सभी अपडेट करें", + "Update now": "अब अपडेट करें", + "Installer host changed since the installed version.\n": "इंस्टॉल किए गए संस्करण के बाद से इंस्टॉलर होस्ट बदल गया है।\n", + "This package is on the queue": "यह पैकेज पंक्ति में है।", + "installing": "स्थापना", + "updating": "अपडेट किया जा रहा है", + "uninstalling": "स्थापना रद्द हो रही है", + "installed": "स्थापित", + "Retry": "पुन: प्रयास करें", + "Install": "स्थापित करें", + "Uninstall": "स्थापना रद्द करें", + "Open": "खोलें", + "Operation profile:": "ऑपरेशन प्रोफ़ाइल:", + "Follow the default options when installing, upgrading or uninstalling this package": "इस पैकेज को इंस्टॉल, अपग्रेड या अनइंस्टॉल करते समय डिफ़ॉल्ट ऑप्शन को फ़ॉलो करें", + "The following settings will be applied each time this package is installed, updated or removed.": "हर बार जब यह पैकेज इंस्टॉल, अपडेट या हटाया जाएगा, तो ये सेटिंग्स लागू होंगी।", + "Version to install:": "संस्करण स्थापित करने के लिए:", + "Architecture to install:": "इंस्टॉल करने के लिए आर्किटेक्चर:", + "Installation scope:": "स्थापना गुंजाइश:", + "Install location:": "इंस्टॉल करने की जगह:", + "Select": "चुनें", + "Reset": "रीसेट", + "Custom install arguments:": "कस्टम इंस्टॉल तर्क:", + "Custom update arguments:": "कस्टम अपडेट तर्क:", + "Custom uninstall arguments:": "कस्टम अनइंस्टॉल तर्क:", + "Pre-install command:": "पूर्व-स्थापना आदेश:", + "Post-install command:": "स्थापना के बाद आदेश:", + "Abort install if pre-install command fails": "यदि पूर्व-इंस्टॉल आदेश विफल हो जाए तो इंस्टॉलेशन निरस्त करें", + "Pre-update command:": "पूर्व-अद्यतन आदेश:", + "Post-update command:": "अद्यतन के बाद आदेश:", + "Abort update if pre-update command fails": "यदि पूर्व-अद्यतन आदेश विफल हो जाए तो अद्यतन निरस्त करें", + "Pre-uninstall command:": "पूर्व-अनइंस्टॉल आदेश:", + "Post-uninstall command:": "अनइंस्टॉल के बाद आदेश:", + "Abort uninstall if pre-uninstall command fails": "यदि पूर्व-अनइंस्टॉल आदेश विफल हो जाए तो अनइंस्टॉल निरस्त करें", + "Command-line to run:": "चलाने के लिए कमांड-लाइन:", + "Save and close": "सहेज लें और बंद करें", + "General": "सामान्य", + "Architecture & Location": "आर्किटेक्चर और स्थान", + "Command-line": "कमांड-लाइन", + "Close apps": "ऐप्स बंद करें", + "Pre/Post install": "पूर्व/पश्चात स्थापना", + "Select the processes that should be closed before this package is installed, updated or uninstalled.": "उन प्रोसेस को चुनें जिन्हें इस पैकेज को इंस्टॉल, अपडेट या अनइंस्टॉल करने से पहले बंद कर देना चाहिए।", + "Write here the process names here, separated by commas (,)": "प्रोसेस के नाम यहां लिखें, उन्हें कॉमा (,) से अलग करें", + "Try to kill the processes that refuse to close when requested to": "उन प्रोसेस को बंद करने की कोशिश करें जो रिक्वेस्ट करने पर बंद नहीं होते हैं", + "Run as admin": "\nप्रशासक के रूप में चलाएँ", + "Interactive installation": "इंटरएक्टिव स्थापना", + "Skip hash check": "हैश चैक छोड़ दें", + "Uninstall previous versions when updated": "अपडेट होने पर पिछले वर्शन को अनइंस्टॉल करें।", + "Skip minor updates for this package": "इस पैकेज के लिए छोटे अपडेट छोड़ें", + "Automatically update this package": "इस पैकेज को स्वचालित रूप से अपडेट करें", + "{0} installation options": "{0} इंस्टॉलेशन विकल्प", + "Latest": "नवीनतम", + "PreRelease": "प्री-रिलीज़", + "Default": " पूर्व निर्धारित मूल्य", + "Manage ignored updates": "उपेक्षित अपडेट प्रबंधित करें", + "The packages listed here won't be taken in account when checking for updates. Double-click them or click the button on their right to stop ignoring their updates.": "अद्यतनों के लिए जाँच करते समय यहाँ सूचीबद्ध पैकेजों को ध्यान में नहीं रखा जाएगा। उनके अद्यतनों को नज़रअंदाज़ करना बंद करने के लिए उन पर डबल-क्लिक करें या उनकी दाईं ओर स्थित बटन क्लिक करें।", + "Reset list": "सूची रीसेट करें", + "Do you really want to reset the ignored updates list? This action cannot be reverted": "क्या आप वाकई उपेक्षित अपडेट की सूची रीसेट करना चाहते हैं? यह क्रिया वापस नहीं की जा सकती।", + "No ignored updates": "कोई उपेक्षित अपडेट नहीं", + "Package Name": "पैकेज का नाम", + "Package ID": "पैकेज आईडी", + "Ignored version": "उपेक्षित संस्करण", + "New version": "नया संस्करण", + "Source": "स्रोत", + "All versions": "सभी संस्करण", + "Unknown": "अज्ञात", + "Up to date": "अप टू डेट", + "Package {name} from {manager}": "{manager} से पैकेज {name}", + "Remove {0} from ignored updates": "{0} को उपेक्षित अपडेट से हटाएं", + "Cancel": "रद्द करें", + "Administrator privileges": "\nप्रशासक के विशेषाधिकार", + "This operation is running with administrator privileges.": "यह ऑपरेशन एडमिनिस्ट्रेटर प्रिविलेज के साथ चल रहा है।", + "Interactive operation": "इंटरैक्टिव संचालन", + "This operation is running interactively.": "यह ऑपरेशन इंटरैक्टिव तरीके से चल रहा है।", + "You will likely need to interact with the installer.": "संभवतः आपको इंस्टॉलर के साथ इंटरैक्ट करना पड़ेगा।", + "Integrity checks skipped": "अखंडता जांच छोड़ दी गई", + "Integrity checks will not be performed during this operation.": "इस ऑपरेशन के दौरान अखंडता जाँच नहीं की जाएगी।", + "Proceed at your own risk.": "अपने जोख़िम पर आगे बढ़ें।", + "Close": "बंद करें", + "Loading...": "\nलोड हो रहा है...", + "Installer SHA256": "इंस्टॉलर SHA256", + "Homepage": "\nहोमपेज", + "Author": "\nलेखक", + "Publisher": "प्रचारक", + "License": "लाइसेंस", + "Manifest": "मैनिफेस्ट", + "Installer Type": "इंस्टॉलर प्रकार", + "Size": "आकार", + "Installer URL": "इंस्टॉलर यू आर एल", + "Last updated:": "आखरी अपडेट:", + "Release notes URL": "रिलीज़ नोट्स URL", + "Package details": "पैकेज के ब्यौरे", + "Dependencies:": "निर्भरताएँ:", + "Release notes": "रिलीज नोट्स", + "Screenshots": "स्क्रीनशॉट", + "This package has no screenshots or is missing the icon? Contribute to UniGetUI by adding the missing icons and screenshots to our open, public database.": "इस पैकेज में कोई स्क्रीनशॉट नहीं है या आइकन गायब है? हमारे खुले, सार्वजनिक डेटाबेस में गायब आइकन और स्क्रीनशॉट जोड़कर UniGetUI में योगदान दें।", + "Version": "संस्करण", + "Install as administrator": "प्रशासक के रूप में स्थापना करें", + "Update to version {0}": "संस्करण {0} को अपडेट करें", + "Installed Version": "स्थापित संस्करण", + "Update as administrator": "प्रशासक के रूप में अपडेट करें", + "Interactive update": "इंटरएक्टिव अपडेट", + "Uninstall as administrator": "प्रशासक के रूप में स्थापना रद्द करें", + "Interactive uninstall": "इंटरएक्टिव स्थापना रद्द", + "Uninstall and remove data": "अनइंस्टॉल करें और डेटा हटाएं", + "Not available": "उपलब्ध नहीं है", + "Installer SHA512": "इंस्टॉलर SHA512", + "Unknown size": "अज्ञात आकार", + "No dependencies specified": "कोई निर्भरता निर्दिष्ट नहीं", + "mandatory": "अनिवार्य", + "optional": "वैकल्पिक", + "UniGetUI {0} is ready to be installed.": "यूनीगेटयूआई {0} इंस्टॉल होने के लिए तैयार है।", + "The update process will start after closing UniGetUI": "यूनीगेटयूआई बंद करने के बाद अपडेट प्रोसेस शुरू हो जाएगा।", + "UniGetUI has been ran as administrator, which is not recommended. When running UniGetUI as administrator, EVERY operation launched from UniGetUI will have administrator privileges. You can still use the program, but we highly recommend not running UniGetUI with administrator privileges.": "UniGetUI को व्यवस्थापक के रूप में चलाया गया है, जिसकी अनुशंसा नहीं की जाती। UniGetUI को व्यवस्थापक के रूप में चलाने पर UniGetUI से शुरू की गई हर कार्रवाई को व्यवस्थापक अधिकार मिलेंगे। आप फिर भी प्रोग्राम का उपयोग कर सकते हैं, लेकिन हम ज़ोरदार अनुशंसा करते हैं कि UniGetUI को व्यवस्थापक अधिकारों के साथ न चलाएँ।", + "Share anonymous usage data": "अनाम उपयोग डेटा साझा करें", + "UniGetUI collects anonymous usage data in order to improve the user experience.": "यूनीगेटयूआई यूज़र एक्सपीरियंस को बेहतर बनाने के लिए गुमनाम यूसेज डेटा इकट्ठा करता है।", + "Accept": "स्वीकार", + "Software Updates": "\nसॉफ्टवेयर अपडेट", + "Package Bundles": "पैकेज बंडल", + "Settings": "सेटिंग्स", + "Package Managers": "पैकेज प्रबंधक", + "UniGetUI Log": "UniGetUI लॉग", + "Package Manager logs": "पैकेज प्रबंधक लॉग", + "Operation history": "ऑपरेशन इतिहास", + "Help": "सहायता", + "UniGetUI": "UniGetUI", + "You have installed UniGetUI Version {0}": "आपने UniGetUI संस्करण {0} इंस्टॉल किया है", + "Disclaimer": "अस्वीकरण", + "UniGetUI is developed by Devolutions and is not affiliated with any of the compatible package managers.": "UniGetUI को Devolutions द्वारा विकसित किया गया है और यह किसी भी संगत पैकेज मैनेजर से संबद्ध नहीं है।", + "UniGetUI wouldn't have been possible without the help of the contributors. Thank you all 🥳": "योगदानकर्ताओं की मदद के बिना UniGetUI संभव नहीं होता। आप सभी का धन्यवाद 🥳", + "UniGetUI uses the following libraries. Without them, UniGetUI wouldn't have been possible.": "UniGetUI निम्नलिखित लाइब्रेरीज़ का उपयोग करता है। इनके बिना UniGetUI संभव नहीं होता।", + "{0} homepage": "{0} होमपेज", + "UniGetUI has been translated to more than 40 languages thanks to the volunteer translators. Thank you 🤝": "स्वयंसेवी अनुवादकों की बदौलत UniGetUI का 40 से अधिक भाषाओं में अनुवाद किया गया है। धन्यवाद 🤝", + "Verbose": "विस्तृत", + "1 - Errors": "1 - त्रुटि", + "2 - Warnings": "2 - चेतावनियाँ", + "3 - Information (less)": "3 - जानकारी (कमतर)", + "4 - Information (more)": "4 - जानकारी (अधिक)", + "5 - information (debug)": "5 - जानकारी (डिबग)", + "Warning": "चेतावनी", + "The following settings may pose a security risk, hence they are disabled by default.": "नीचे दी गई सेटिंग्स से सिक्योरिटी रिस्क हो सकता है, इसलिए वे डिफ़ॉल्ट रूप से डिसेबल हैं।", + "Enable the settings below if and only if you fully understand what they do, and the implications they may have.": "नीचे दी गई सेटिंग्स को तभी चालू करें जब आप पूरी तरह से समझते हों कि वे क्या करती हैं, और उनसे क्या असर और खतरे हो सकते हैं।", + "The settings will list, in their descriptions, the potential security issues they may have.": "सेटिंग्स अपनी जानकारी में उन संभावित सुरक्षा समस्याओं को बताएंगी जो उनमें हो सकती हैं।", + "The backup will include the complete list of the installed packages and their installation options. Ignored updates and skipped versions will also be saved.": "बैकअप में इंस्टॉल किए गए पैकेज और उनके इंस्टॉलेशन ऑप्शन की पूरी लिस्ट होगी। इग्नोर किए गए अपडेट और स्किप किए गए वर्शन भी सेव हो जाएंगे।", + "The backup will NOT include any binary file nor any program's saved data.": "बैकअप में कोई बाइनरी फ़ाइल या किसी प्रोग्राम का सेव किया गया डेटा शामिल नहीं होगा।", + "The size of the backup is estimated to be less than 1MB.": "बैकअप का साइज़ 1 एमबी से कम होने का अनुमान है।", + "The backup will be performed after login.": "लॉगिन के बाद बैकअप किया जाएगा।", + "{pcName} installed packages": "{pcName} पर इंस्टॉल किए गए पैकेज", + "Current status: Not logged in": "अभी की स्थिति: लॉग इन नहीं है", + "You are logged in as {0} (@{1})": "आप {0} (@{1}) के रूप में लॉग इन हैं", + "Nice! Backups will be uploaded to a private gist on your account": "बढ़िया! बैकअप आपके अकाउंट पर एक प्राइवेट गिस्‍ट में अपलोड हो जाएंगे", + "Select backup": "बैकअप चुनें", + "Settings imported from {0}": "{0} से सेटिंग्स आयात की गईं", + "UniGetUI Settings": "UniGetUI सेटिंग्स", + "Settings exported to {0}": "{0} में सेटिंग्स निर्यात की गईं", + "UniGetUI settings were reset": "UniGetUI सेटिंग्स रीसेट कर दी गईं", + "Allow pre-release versions": "प्री-रिलीज़ वर्शन की अनुमति दें", + "Apply": "लागू करें", + "For security reasons, custom command-line arguments are disabled by default. Go to UniGetUI security settings to change this.": "सुरक्षा कारणों से कस्टम कमांड-लाइन तर्क डिफ़ॉल्ट रूप से अक्षम हैं। इसे बदलने के लिए UniGetUI की सुरक्षा सेटिंग्स पर जाएँ।", + "Go to UniGetUI security settings": "यूनीगेटयूआई सिक्योरिटी सेटिंग्स पर जाएं", + "The following options will be applied by default each time a {0} package is installed, upgraded or uninstalled.": "हर बार एक {0} पैकेज इंस्टॉल, अपग्रेड या अनइंस्टॉल होने पर ये ऑप्शन डिफ़ॉल्ट रूप से लागू हो जाएंगे", + "Package's default": "पैकेज का डिफ़ॉल्ट", + "Install location can't be changed for {0} packages": "इंस्टॉल की जगह नहीं बदली जा सकती {0} पैकेजों के लिए", + "The local icon cache currently takes {0} MB": "लोकल आइकन कैश अभी {0} एमबी लेता है", + "Username": "यूज़रनेम", + "Password": "पासवर्ड", + "Credentials": "साख", + "It is not guaranteed that the provided credentials will be stored safely": "यह सुनिश्चित नहीं है कि दिए गए क्रेडेंशियल सुरक्षित रूप से संग्रहीत किए जाएँगे", + "Partially": "आंशिक रूप से", + "Package manager": "पैकेज प्रबंधक", + "Compatible with proxy": "प्रॉक्सी के साथ संगत", + "Compatible with authentication": "प्रमाणीकरण के साथ संगत", + "Proxy compatibility table": "प्रॉक्सी संगतता तालिका", + "{0} settings": "{0} सेटिंग्स", + "{0} status": "{0} स्थिति", + "Default installation options for {0} packages": "डिफ़ॉल्ट इंस्टॉलेशन {0} पैकेज के लिए विकल्प", + "Expand version": "संस्करण का विस्तार करें", + "The executable file for {0} was not found": "{0} के लिए एक्ज़ीक्यूटेबल फ़ाइल नहीं मिला था", + "{pm} is disabled": "{pm} अक्षम है", + "Enable it to install packages from {pm}.": "इसे पैकेज इंस्टॉल करने के लिए इनेबल करें {pm}", + "{pm} is enabled and ready to go": "{pm} सक्षम है और उपयोग के लिए तैयार है", + "{pm} version:": "{pm} संस्करण:", + "{pm} was not found!": "{pm} नहीं मिला!", + "You may need to install {pm} in order to use it with UniGetUI.": "UniGetUI के साथ इसका उपयोग करने के लिए आपको {pm} इंस्टॉल करना पड़ सकता है।", + "Scoop Installer - UniGetUI": "स्कूप इंस्टॉलर - यूनीगेटयूआई", + "Scoop Uninstaller - UniGetUI": "स्कूप अनइंस्टालर - यूनीगेटयूआई", + "Clearing Scoop cache - UniGetUI": "स्कूप कैश साफ़ करना - यूनीगेटयूआई", + "Restart UniGetUI to fully apply changes": "परिवर्तनों को पूरी तरह लागू करने के लिए UniGetUI पुनःआरंभ करें", + "Restart UniGetUI": "यूनीगेटयूआई पुनःआरंभ करें", + "Manage {0} sources": "{0} स्रोतों का प्रबंधन करें", + "Add source": "स्रोत जोड़ें", + "Add": "जोड़ो", + "Source name": "स्रोत का नाम", + "Source URL": "स्रोत URL", + "Other": "अन्य", + "No minimum age": "कोई न्यूनतम आयु नहीं", + "1 day": "1 दिन", + "{0} days": "{0} दिन", + "Custom...": "कस्टम...", + "{0} minutes": "{0} मिनट", + "1 hour": "1 घंटा", + "{0} hours": "{0} घंटे", + "1 week": "1 सप्ताह", + "Supports release dates": "रिलीज़ तिथियों का समर्थन करता है", + "Release date support per package manager": "प्रत्येक पैकेज प्रबंधक के लिए रिलीज़ तिथि समर्थन", + "Search for packages": "पैकेज खोजें", + "Local": "स्थानीय", + "OK": "ठीक", + "Last checked: {0}": "अंतिम जाँच: {0}", + "{0} packages were found, {1} of which match the specified filters.": "{0} पैकेज मिले, जिनमें से {1} निर्दिष्ट फ़िल्टरों से मेल खाते हैं।", + "{0} selected": "{0} चुना गया", + "(Last checked: {0})": "(अंतिम बार जांचा गया: {0})", + "All packages selected": "सभी पैकेज चयनित", + "Package selection cleared": "पैकेज चयन साफ़ किया गया", + "{0}: {1}": "{0}: {1}", + "More info": "और जानकारी", + "GitHub account": "GitHub खाता", + "Log in with GitHub to enable cloud package backup.": "क्लाउड पैकेज बैकअप चालू करने के लिए गिटहब से लॉग इन करें।", + "More details": "अधिक जानकारी", + "Log in": "लॉग इन करें", + "If you have cloud backup enabled, it will be saved as a GitHub Gist on this account": "अगर आपने क्लाउड बैकअप चालू किया है, तो यह इस अकाउंट पर गिटहब गिस्ट के तौर पर सेव हो जाएगा।", + "Log out": "लॉग आउट", + "About UniGetUI": "UniGetUI के बारे में", + "About": "के बारे में", + "Third-party licenses": "तृतीय-पक्ष लाइसेंस", + "Contributors": "\nयोगदानकर्ता", + "Translators": "\nअनुवादक", + "Bundle security report": "बंडल सुरक्षा प्रतिवेदन", + "The bundle contained restricted content": "बंडल में प्रतिबंधित सामग्री थी", + "UniGetUI – Crash Report": "UniGetUI – क्रैश रिपोर्ट", + "UniGetUI has crashed": "UniGetUI क्रैश हो गया है", + "Help us fix this by sending a crash report to Devolutions. All fields below are optional.": "Devolutions को क्रैश रिपोर्ट भेजकर इसे ठीक करने में हमारी मदद करें। नीचे दिए गए सभी फ़ील्ड वैकल्पिक हैं।", + "Email (optional)": "ईमेल (वैकल्पिक)", + "your@email.com": "your@email.com", + "Additional details (optional)": "अतिरिक्त विवरण (वैकल्पिक)", + "Describe what you were doing when the crash occurred…": "क्रैश होने के समय आप क्या कर रहे थे, वर्णन करें…", + "Crash report": "क्रैश रिपोर्ट", + "Don't Send": "न भेजें", + "Send Report": "रिपोर्ट भेजें", + "Sending…": "भेजा जा रहा है…", + "Unsaved changes": "असहेजे गए परिवर्तन", + "You have unsaved changes in the current bundle. Do you want to discard them?": "वर्तमान बंडल में आपके असहेजे गए परिवर्तन हैं। क्या आप उन्हें त्यागना चाहते हैं?", + "Discard changes": "परिवर्तन त्यागें", + "Integrity violation": "अखंडता उल्लंघन", + "UniGetUI or some of its components are missing or corrupt. It is strongly recommended to reinstall UniGetUI to adress the situation.": "UniGetUI या इसके कुछ घटक गायब हैं या खराब हैं। स्थिति को ठीक करने के लिए UniGetUI को फिर से इंस्टॉल करने की कड़ी अनुशंसा की जाती है।", + "• Refer to the UniGetUI Logs to get more details regarding the affected file(s)": "• प्रभावित फ़ाइल(फ़ाइलों) के बारे में अधिक जानकारी प्राप्त करने के लिए यूनीगेटयूआई लॉग देखें", + "• Integrity checks can be disabled from the Experimental Settings": "• एक्सपेरिमेंटल सेटिंग्स से इंटीग्रिटी चेक को डिसेबल किया जा सकता है", + "Manage shortcuts": "शॉर्टकट प्रबंधित करें", + "UniGetUI has detected the following desktop shortcuts which can be removed automatically on future upgrades": "यूनीगेटयूआई ने निम्नलिखित डेस्कटॉप शॉर्टकट का पता लगाया है जिन्हें भविष्य के अपग्रेड में अपने आप हटाया जा सकता है।", + "Do you really want to reset this list? This action cannot be reverted.": "क्या आप सच में इस लिस्ट को रीसेट करना चाहते हैं? यह एक्शन वापस नहीं किया जा सकता।", + "Desktop shortcuts list": "डेस्कटॉप शॉर्टकट सूची", + "Open in explorer": "एक्सप्लोरर में खोलें", + "Remove from list": "सूची से हटाएँ", + "When new shortcuts are detected, delete them automatically instead of showing this dialog.": "जब नए शॉर्टकट डिटेक्ट हों, तो यह डायलॉग दिखाने के बजाय उन्हें अपने आप डिलीट कर दें।", + "Not right now": "अभी नहीं", + "Missing dependency": "गुम निर्भरता", + "UniGetUI requires {0} to operate, but it was not found on your system.": "यूनीगेटयूआई को काम करने के लिए {0} की ज़रूरत है, लेकिन यह आपके सिस्टम पर नहीं मिला।", + "Click on Install to begin the installation process. If you skip the installation, UniGetUI may not work as expected.": "इंस्टॉलेशन प्रोसेस शुरू करने के लिए इंस्टॉल पर क्लिक करें। अगर आप इंस्टॉलेशन स्किप करते हैं, तो यूनीगेटयूआई उम्मीद के मुताबिक काम नहीं कर सकता है।", + "Alternatively, you can also install {0} by running the following command in a Windows PowerShell prompt:": "वैकल्पिक रूप से, Windows PowerShell प्रॉम्प्ट में निम्न कमांड चलाकर आप {0} स्थापित कर सकते हैं।", + "Install {0}": "{0} स्थापित करना", + "Do not show this dialog again for {0}": "इस डायलॉग को दोबारा न दिखाएं {0}", + "Please wait while {0} is being installed. A black window may show up. Please wait until it closes.": "कृपया प्रतीक्षा करें जब {0} स्थापित किया जा रहा है। एक काली (या नीली) विंडो दिखाई दे सकती है। कृपया इसके बंद होने तक प्रतीक्षा करें।", + "{0} has been installed successfully.": "{0} सफलतापूर्वक इंस्टॉल हो गया है।", + "Please click on \"Continue\" to continue": "कृपया जारी रखने के लिए \"जारी रखें\" पर क्लिक करें", + "Continue": "जारी रखना", + "{0} has been installed successfully. It is recommended to restart UniGetUI to finish the installation": "{0} सफलतापूर्वक इंस्टॉल हो गया है। इंस्टॉलेशन पूरा करने के लिए UniGetUI को पुनः प्रारंभ करने की सलाह दी जाती है।", + "Restart later": "बाद में पुनः आरंभ करें", + "An error occurred:": "एक त्रुटि हुई:", + "Please see the Command-line Output or refer to the Operation History for further information about the issue.": "कृपया समस्या के बारे में अधिक जानकारी के लिए कमांड-लाइन आउटपुट देखें या ऑपरेशन इतिहास देखें।", + "Retry as administrator": "व्यवस्थापक के रूप में पुनः प्रयास करें", + "Retry interactively": "सहभागितापूर्ण तरीके से पुनः प्रयास करें", + "Retry skipping integrity checks": "अखंडता जांच को छोड़कर पुनः प्रयास करें", + "Installation options": "स्थापना विकल्प", + "Save": "सहेजें", + "UniGetUI collects anonymous usage data with the sole purpose of understanding and improving the user experience.": "यूनीगेटयूआई यूज़र एक्सपीरियंस को समझने और बेहतर बनाने के एकमात्र मकसद से गुमनाम यूसेज डेटा इकट्ठा करता है।", + "More details about the shared data and how it will be processed": "शेयर किए गए डेटा और उसे कैसे प्रोसेस किया जाएगा, इसके बारे में ज़्यादा जानकारी", + "Do you accept that UniGetUI collects and sends anonymous usage statistics, with the sole purpose of understanding and improving the user experience?": "क्या आप मानते हैं कि यूनीगेटयूआई सिर्फ़ यूज़र एक्सपीरियंस को समझने और बेहतर बनाने के मकसद से, बिना नाम बताए इस्तेमाल के आंकड़े इकट्ठा करता है और भेजता है?", + "Decline": "अस्वीकार", + "No personal information is collected nor sent, and the collected data is anonimized, so it can't be back-tracked to you.": "कोई भी पर्सनल जानकारी इकट्ठा या भेजी नहीं जाती है, और इकट्ठा किया गया डेटा गुमनाम रहता है, इसलिए इसे आप तक वापस नहीं लाया जा सकता।", + "Navigation panel": "नेविगेशन पैनल", + "Operations": "ऑपरेशन", + "Toggle operations panel": "ऑपरेशन पैनल टॉगल करें", + "Bulk operations": "सामूहिक ऑपरेशन", + "Retry failed": "विफल ऑपरेशन फिर से आज़माएँ", + "Clear successful": "सफल ऑपरेशन साफ़ करें", + "Clear finished": "पूर्ण हुए ऑपरेशन साफ़ करें", + "Cancel all": "सभी रद्द करें", + "More": "अधिक", + "Toggle navigation panel": "नेविगेशन पैनल टॉगल करें", + "Minimize": "छोटा करें", + "Maximize": "बड़ा करें", + "UniGetUI by Devolutions": "Devolutions द्वारा UniGetUI", + "UniGetUI is an application that makes managing your software easier, by providing an all-in-one graphical interface for your command-line package managers.": "UniGetUI एक ऐसा अनुप्रयोग है जो आपके कमांड-लाइन पैकेज मैनेजरों के लिए ऑल-इन-वन ग्राफिकल इंटरफ़ेस देकर आपके सॉफ़्टवेयर को प्रबंधित करना आसान बनाता है।", + "Useful links": "उपयोगी लिंक", + "UniGetUI Homepage": "UniGetUI होमपेज", + "Report an issue or submit a feature request": "किसी समस्या की रिपोर्ट करें या सुविधा का अनुरोध सबमिट करें", + "UniGetUI Repository": "UniGetUI रिपॉज़िटरी", + "View GitHub Profile": "गिटहब प्रोफ़ाइल देखें", + "UniGetUI License": "यूनीगेटयूआई लाइसेंस", + "Using UniGetUI implies the acceptation of the MIT License": "यूनीगेटयूआई का इस्तेमाल करने का मतलब है MIT लाइसेंस को स्वीकार करना।", + "Become a translator": "अनुवादक बनें", + "Go back": "पीछे जाएं", + "Go forward": "आगे जाएं", + "Go to home page": "होम पेज पर जाएं", + "Reload page": "पेज पुनः लोड करें", + "View page on browser": "पेज को ब्राउज़र में देखें", + "The built-in browser is not supported on Linux yet.": "बिल्ट-इन ब्राउज़र अभी Linux पर समर्थित नहीं है।", + "Open in browser": "ब्राउज़र में खोलें", + "Copy to clipboard": "क्लिपबोर्ड पर प्रतिलिपि करें", + "Export to a file": "फ़ाइल में निर्यात करें", + "Log level:": "लॉग स्तर:", + "Reload log": "लॉग पुनः लोड करें", + "Export log": "लॉग निर्यात करें", + "Text": "लेखन", + "Change how operations request administrator rights": "ऑपरेशन एडमिनिस्ट्रेटर अधिकारों का अनुरोध कैसे करते हैं, इसे बदलें", + "Restrictions on package operations": "पैकेज संचालन पर प्रतिबंध", + "Restrictions on package managers": "पैकेज प्रबंधकों पर प्रतिबंध", + "Restrictions when importing package bundles": "पैकेज बंडल आयात करते समय प्रतिबंध", + "Ask for administrator privileges once for each batch of operations": "हर ऑपरेशन के बैच के लिए एक बार एडमिनिस्ट्रेटर प्रिविलेज मांगें", + "Ask only once for administrator privileges": "एडमिनिस्ट्रेटर प्रिविलेज के लिए सिर्फ़ एक बार पूछें", + "Prohibit any kind of Elevation via UniGetUI Elevator or GSudo": "यूनीगेटयूआई एलेवेटर या जीसुडो के माध्यम से किसी भी प्रकार के उन्नयन पर रोक लगाएं", + "This option WILL cause issues. Any operation incapable of elevating itself WILL FAIL. Install/update/uninstall as administrator will NOT WORK.": "इस ऑप्शन से दिक्कतें आएंगी। कोई भी ऑपरेशन जो खुद को एलिवेट नहीं कर पाएगा, वह फेल हो जाएगा। एडमिनिस्ट्रेटर के तौर पर इंस्टॉल/अपडेट/अनइंस्टॉल काम नहीं करेगा।", + "Allow custom command-line arguments": "कस्टम कमांड-लाइन तर्कों की अनुमति दें", + "Custom command-line arguments can change the way in which programs are installed, upgraded or uninstalled, in a way UniGetUI cannot control. Using custom command-lines can break packages. Proceed with caution.": "कस्टम कमांड-लाइन आर्गुमेंट प्रोग्राम को इंस्टॉल, अपग्रेड या अनइंस्टॉल करने का तरीका बदल सकते हैं, जिसे यूनीगेटयूआई कंट्रोल नहीं कर सकता। कस्टम कमांड-लाइन इस्तेमाल करने से पैकेज खराब हो सकते हैं। सावधानी से आगे बढ़ें।", + "Ignore custom pre-install and post-install commands when importing packages from a bundle": "बंडल से पैकेज इंपोर्ट करते समय कस्टम प्री-इंस्टॉल और पोस्ट-इंस्टॉल कमांड चलाने की अनुमति दें", + "Pre and post install commands will be run before and after a package gets installed, upgraded or uninstalled. Be aware that they may break things unless used carefully": "प्री और पोस्ट इंस्टॉल कमांड किसी पैकेज के इंस्टॉल, अपग्रेड या अनइंस्टॉल होने से पहले और बाद में चलाए जाएँगे। ध्यान रखें कि अगर सावधानी से इस्तेमाल न किया जाए तो ये चीज़ें खराब कर सकते हैं।", + "Allow changing the paths for package manager executables": "पैकेज प्रबंधक निष्पादनयोग्य के लिए पथ बदलने की अनुमति दें", + "Turning this on enables changing the executable file used to interact with package managers. While this allows finer-grained customization of your install processes, it may also be dangerous": "इसे चालू करने से पैकेज मैनेजर के साथ इंटरैक्ट करने के लिए इस्तेमाल होने वाली एग्जीक्यूटेबल फ़ाइल को बदलना संभव हो जाता है। हालांकि इससे आपके इंस्टॉल प्रोसेस को ज़्यादा बारीकी से कस्टमाइज़ किया जा सकता है, लेकिन यह खतरनाक भी हो सकता है।", + "Allow importing custom command-line arguments when importing packages from a bundle": "बंडल से पैकेज आयात करते समय कस्टम कमांड-लाइन तर्कों को आयात करने की अनुमति दें", + "Malformed command-line arguments can break packages, or even allow a malicious actor to gain privileged execution. Therefore, importing custom command-line arguments is disabled by default": "खराब कमांड-लाइन आर्गुमेंट पैकेज को तोड़ सकते हैं, या किसी गलत इरादे वाले एक्टर को खास एग्जीक्यूशन पाने की इजाज़त भी दे सकते हैं। इसलिए, कस्टम कमांड-लाइन आर्गुमेंट इंपोर्ट करना डिफ़ॉल्ट रूप से डिसेबल होता है।", + "Allow importing custom pre-install and post-install commands when importing packages from a bundle": "बंडल से पैकेज आयात करते समय कस्टम प्री-इंस्टॉल और पोस्ट-इंस्टॉल कमांड आयात करने की अनुमति दें", + "Pre and post install commands can do very nasty things to your device, if designed to do so. It can be very dangerous to import the commands from a bundle, unless you trust the source of that package bundle": "प्री और पोस्ट इंस्टॉलेशन कमांड आपके डिवाइस के लिए बहुत खतरनाक हो सकते हैं, अगर उन्हें ऐसा करने के लिए डिज़ाइन किया गया हो। किसी बंडल से कमांड इम्पोर्ट करना बहुत खतरनाक हो सकता है, जब तक कि आपको उस पैकेज बंडल के स्रोत पर भरोसा न हो।", + "Administrator rights and other dangerous settings": "व्यवस्थापक अधिकार और अन्य खतरनाक सेटिंग्स", + "Package backup": "पैकेज बैकअप", + "Cloud package backup": "क्लाउड पैकेज बैकअप", + "Local package backup": "स्थानीय पैकेज बैकअप", + "Local backup advanced options": "स्थानीय बैकअप उन्नत विकल्प", + "Log in with GitHub": "गिटहब से लॉग इन करें", + "Log out from GitHub": "गिटहब से लॉग आउट करें", + "Periodically perform a cloud backup of the installed packages": "समय-समय पर स्थापित पैकेज का क्लाउड बैकअप लें", + "Cloud backup uses a private GitHub Gist to store a list of installed packages": "क्लाउड बैकअप इंस्टॉल किए गए पैकेज की लिस्ट स्टोर करने के लिए एक प्राइवेट गिटहब गिस्ट का इस्तेमाल करता है", + "Perform a cloud backup now": "अभी क्लाउड बैकअप करें", + "Backup": "बैकअप", + "Restore a backup from the cloud": "क्लाउड से बैकअप पुनर्स्थापित करें", + "Begin the process to select a cloud backup and review which packages to restore": "क्लाउड बैकअप चुनने का प्रोसेस शुरू करें और देखें कि कौन से पैकेज रिस्टोर करने हैं", + "Periodically perform a local backup of the installed packages": "समय-समय पर स्थापित पैकेज का स्थानीय बैकअप लें", + "Perform a local backup now": "अभी स्थानीय बैकअप करें", + "Change backup output directory": "बैकअप आउटपुट डायरेक्टरी बदलें", + "Set a custom backup file name": "एक कस्टम बैकअप फ़ाइल नाम सेट करें", + "Leave empty for default": "डिफ़ॉल्ट के लिए खाली छोड़ दें", + "Add a timestamp to the backup file names": "बैकअप फ़ाइल नामों में टाइमस्टैम्प जोड़ें", + "Backup and Restore": "बैकअप और पुनर्स्थापना", + "Enable background api (UniGetUI Widgets and Sharing, port 7058)": "बैकग्राउंड एपीआई चालू करें (यूनीगेटयूआई और शेयरिंग के लिए विजेट, पोर्ट 7058)", + "Wait for the device to be connected to the internet before attempting to do tasks that require internet connectivity.": "इंटरनेट कनेक्टिविटी वाले काम करने से पहले डिवाइस के इंटरनेट से कनेक्ट होने का इंतज़ार करें।", + "Disable the 1-minute timeout for package-related operations": "पैकेज से जुड़े ऑपरेशन के लिए 1-मिनट का टाइमआउट बंद करें", + "Use installed GSudo instead of UniGetUI Elevator": "यूनीगेटयूआई एलिवेटर के बजाय इंस्टॉल किए गए जीसुडो का उपयोग करें", + "Use a custom icon and screenshot database URL": "एक कस्टम आइकन और स्क्रीनशॉट डेटाबेस यूआरएल का उपयोग करें", + "Enable background CPU Usage optimizations (see Pull Request #3278)": "बैकग्राउंड सीपीयू यूसेज ऑप्टिमाइज़ेशन चालू करें (पुल रिक्वेस्ट #3278 देखें)", + "Perform integrity checks at startup": "स्टार्टअप पर अखंडता जांच करें", + "When batch installing packages from a bundle, install also packages that are already installed": "जब किसी बंडल से पैकेज बैच में इंस्टॉल कर रहे हों, तो उन पैकेज को भी इंस्टॉल करें जो पहले से इंस्टॉल हैं।", + "Experimental settings and developer options": "प्रायोगिक सेटिंग्स और डेवलपर विकल्प", + "Show UniGetUI's version and build number on the titlebar.": "टाइटल बार पर यूनीगेटयूआई वर्शन दिखाएँ", + "Language": "भाषा", + "UniGetUI updater": "यूनिगेटयूआई अपडेटर", + "Telemetry": "टेलीमेटरी", + "Manage UniGetUI settings": "यूनीगेटयूआई सेटिंग्स प्रबंधित करें", + "Related settings": "संबंधित सेटिंग्स", + "Update UniGetUI automatically": "UniGetUI को स्वचालित रूप से अपडेट करें", + "Check for updates": "अद्यतन के लिए जाँच", + "Install prerelease versions of UniGetUI": "यूनीगेटयूआई के प्री-रिलीज़ वर्शन इंस्टॉल करें", + "Manage telemetry settings": "टेलीमेट्री सेटिंग्स प्रबंधित करें", + "Manage": "प्रबंधित करना", + "Import settings from a local file": "लोकल फ़ाइल से सेटिंग्स इंपोर्ट करें", + "Import": "आयात", + "Export settings to a local file": "सेटिंग्स को लोकल फ़ाइल में एक्सपोर्ट करें", + "Export": "एक्सपोर्ट", + "Reset UniGetUI": "यूनीगेटयूआई रीसेट करें", + "User interface preferences": "उपयोगकर्ता इंटरफ़ेस प्राथमिकताएँ", + "Application theme, startup page, package icons, clear successful installs automatically": "एप्लिकेशन थीम, स्टार्टअप पेज, पैकेज आइकन, सफल इंस्टॉल को ऑटोमैटिकली क्लियर करें", + "General preferences": "सामान्य प्राथमिकताएं", + "UniGetUI display language:": "UniGetUI की प्रदर्शन भाषा", + "System language": "सिस्टम भाषा", + "Is your language missing or incomplete?": "क्या आपकी भाषा गायब है या अधूरी है?", + "Appearance": "उपस्थिति", + "UniGetUI on the background and system tray": "यूनीगेटयूआई बैकग्राउंड और सिस्टम ट्रे पर है।", + "Package lists": "पैकेज सूचियाँ", + "Use classic mode": "क्लासिक मोड का उपयोग करें", + "Restart UniGetUI to apply this change": "इस बदलाव को लागू करने के लिए UniGetUI पुनः आरंभ करें", + "The classic UI is disabled for beta testers": "बीटा परीक्षकों के लिए क्लासिक UI अक्षम है", + "Close UniGetUI to the system tray": "यूनीगेटयूआई को सिस्टम ट्रे में बंद करें", + "Manage UniGetUI autostart behaviour": "UniGetUI के ऑटोस्टार्ट व्यवहार को प्रबंधित करें", + "Show package icons on package lists": "पैकेज लिस्ट पर पैकेज आइकन दिखाएँ", + "Clear cache": "कैश को साफ़ करें", + "Select upgradable packages by default": "डिफ़ॉल्ट रूप से अपग्रेड करने योग्य पैकेज चुनें", + "Light": "लाइट", + "Dark": "डार्क", + "Follow system color scheme": "सिस्टम कलर स्कीम का पालन करें", + "Application theme:": "एप्लीकेशन थीम:", + "UniGetUI startup page:": "यूनीगेटयूआई स्टार्टअप पेज:", + "Proxy settings": "प्रॉक्सी सेटिंग्स", + "Other settings": "अन्य सेटिंग्स", + "Connect the internet using a custom proxy": "कस्टम प्रॉक्सी का इस्तेमाल करके इंटरनेट कनेक्ट करें", + "Please note that not all package managers may fully support this feature": "कृपया ध्यान दें कि सभी पैकेज प्रबंधक इस सुविधा का पूर्णतः समर्थन नहीं कर सकते हैं", + "Proxy URL": "प्रॉक्सी URL", + "Enter proxy URL here": "प्रॉक्सी URL यहां डालें", + "Authenticate to the proxy with a user and a password": "उपयोगकर्ता नाम और पासवर्ड के साथ प्रॉक्सी में प्रमाणीकरण करें", + "Internet and proxy settings": "इंटरनेट और प्रॉक्सी सेटिंग्स", + "Package manager preferences": "पैकेज प्रबंधक वरीयताएँ", + "Ready": "तैयार", + "Not found": "नहीं मिला", + "Notification preferences": "अधिसूचना प्राथमिकताएँ", + "Notification types": "अधिसूचना प्रकार", + "The system tray icon must be enabled in order for notifications to work": "नोटिफ़िकेशन काम करने के लिए सिस्टम ट्रे आइकन इनेबल होना चाहिए।", + "Enable UniGetUI notifications": "UniGetUI सूचनाएं सक्षम करें", + "Show a notification when there are available updates": "अपडेट उपलब्ध होने पर सूचना दिखाएं", + "Show a silent notification when an operation is running": "जब कोई ऑपरेशन चल रहा हो तो साइलेंट नोटिफ़िकेशन दिखाएँ", + "Show a notification when an operation fails": "जब कोई ऑपरेशन फेल हो जाए तो नोटिफिकेशन दिखाएं", + "Show a notification when an operation finishes successfully": "जब कोई ऑपरेशन सफलतापूर्वक पूरा हो जाए तो एक नोटिफ़िकेशन दिखाएँ", + "Concurrency and execution": "समवर्तीता और निष्पादन", + "Automatic desktop shortcut remover": "स्वचालित डेस्कटॉप शॉर्टकट रिमूवर ", + "Choose how many operations should be performed in parallel": "चुनें कि कितने ऑपरेशन समानांतर रूप से किए जाने चाहिए", + "Clear successful operations from the operation list after a 5 second delay": "5 सेकंड की देरी के बाद ऑपरेशन लिस्ट से सफल ऑपरेशन को हटा दें", + "Download operations are not affected by this setting": "इस सेटिंग से डाउनलोड ऑपरेशन पर कोई असर नहीं पड़ता है", + "You may lose unsaved data": "आपका बिना सहेजा गया डेटा खो सकता है", + "Ask to delete desktop shortcuts created during an install or upgrade.": "इंस्टॉल या अपग्रेड के दौरान बनाए गए डेस्कटॉप शॉर्टकट को डिलीट करने के लिए कहें।", + "Package update preferences": "पैकेज अद्यतन प्राथमिकताएँ", + "Update check frequency, automatically install updates, etc.": "अपडेट चेक करने की फ़्रीक्वेंसी, अपडेट को ऑटोमैटिकली इंस्टॉल करना, वगैरह।", + "Reduce UAC prompts, elevate installations by default, unlock certain dangerous features, etc.": "यूएसी प्रॉम्प्ट को कम करें, डिफ़ॉल्ट रूप से इंस्टॉलेशन को बढ़ाएं, कुछ खतरनाक सुविधाओं को अनलॉक करें, आदि।", + "Package operation preferences": "पैकेज संचालन प्राथमिकताएँ", + "Enable {pm}": "{pm} सक्षम करें", + "Not finding the file you are looking for? Make sure it has been added to path.": "आपको जो फ़ाइल चाहिए वह नहीं मिल रही है? सुनिश्चित करें कि इसे पाथ (Path) में जोड़ दिया गया है।", + "Select the executable to be used. The following list shows the executables found by UniGetUI": "इस्तेमाल करने के लिए एग्जीक्यूटेबल चुनें। नीचे दी गई लिस्ट में यूनीगेटयूआई को मिले एग्जीक्यूटेबल दिखाए गए हैं।", + "For security reasons, changing the executable file is disabled by default": "सुरक्षा कारणों से, एग्जीक्यूटेबल फ़ाइल बदलना डिफ़ॉल्ट रूप से डिसेबल होता है", + "Change this": "इसे बदलें", + "Copy path": "पथ कॉपी करें", + "Current executable file:": "अभी की एग्जीक्यूटेबल फ़ाइल:", + "Ignore packages from {pm} when showing a notification about updates": "अपडेट के बारे में सूचना दिखाते समय {pm} से पैकेज को अनदेखा करें", + "Update security": "अपडेट सुरक्षा", + "Use global setting": "वैश्विक सेटिंग का उपयोग करें", + "Minimum age for updates": "अपडेट के लिए न्यूनतम आयु", + "e.g. 10": "उदा. 10", + "Custom minimum age (days)": "कस्टम न्यूनतम आयु (दिन)", + "{pm} does not provide release dates for its packages, so this setting will have no effect": "{pm} अपने पैकेजों के लिए रिलीज़ तिथियाँ प्रदान नहीं करता, इसलिए इस सेटिंग का कोई प्रभाव नहीं होगा", + "{pm} only provides release dates for some of its packages, so this setting will only apply to those packages": "{pm} केवल अपने कुछ पैकेजों के लिए रिलीज़ की तारीखें प्रदान करता है, इसलिए यह सेटिंग केवल उन्हीं पैकेजों पर लागू होगी", + "Override the global minimum update age for this package manager": "इस पैकेज प्रबंधक के लिए वैश्विक न्यूनतम अपडेट आयु को ओवरराइड करें", + "View {0} logs": "लॉग {0} देखें", + "If Python cannot be found or is not listing packages but is installed on the system, ": "यदि Python नहीं मिल रहा है या पैकेज सूचीबद्ध नहीं कर रहा है लेकिन सिस्टम पर स्थापित है, ", + "Advanced options": "उन्नत विकल्प", + "WinGet command-line tool": "WinGet कमांड-लाइन टूल", + "Choose which command-line tool UniGetUI uses for WinGet operations when the COM API is not used": "चुनें कि COM API का उपयोग न होने पर UniGetUI WinGet ऑपरेशन के लिए कौन सा कमांड-लाइन टूल उपयोग करे", + "WinGet COM API": "WinGet COM API", + "Choose whether UniGetUI can use the WinGet COM API before falling back to the command-line tool": "चुनें कि कमांड-लाइन टूल पर वापस जाने से पहले UniGetUI WinGet COM API का उपयोग कर सकता है या नहीं", + "Reset WinGet": "विनगेट रीसेट करें", + "This may help if no packages are listed": "अगर कोई पैकेज लिस्ट में नहीं दिख रहा है तो यह मदद कर सकता है।", + "Force install location parameter when updating packages with custom locations": "कस्टम स्थान वाले पैकेज अपडेट करते समय इंस्टॉल लोकेशन पैरामीटर को अनिवार्य करें", + "Install Scoop": "स्कूप स्थापित करें", + "Uninstall Scoop (and its packages)": "स्कूप (और उसके पैकेज) की स्थापना रद्द करें", + "Run cleanup and clear cache": "क्लीनअप चलाएं और कैश साफ़ करें", + "Run": "चलाएँ", + "Enable Scoop cleanup on launch": "लॉन्च होने पर स्कूप क्लीनअप सक्षम करें", + "Default vcpkg triplet": "डिफ़ॉल्ट वीसीपीकेजी ट्रिपलेट", + "Change vcpkg root location": "vcpkg रूट स्थान बदलें", + "Reset vcpkg root location": "vcpkg रूट स्थान रीसेट करें", + "Open vcpkg root location": "vcpkg रूट स्थान खोलें", + "Language, theme and other miscellaneous preferences": "भाषा, थीम और अन्य विविध प्राथमिकताएं", + "Show notifications on different events": "अलग-अलग इवेंट पर नोटिफ़िकेशन दिखाएँ", + "Change how UniGetUI checks and installs available updates for your packages": "यूनीगेटयूआई आपके पैकेज के लिए उपलब्ध अपडेट को कैसे चेक और इंस्टॉल करता है, इसे बदलें", + "Automatically save a list of all your installed packages to easily restore them.": "अपने सभी इंस्टॉल किए गए पैकेज की लिस्ट ऑटोमैटिकली सेव करें ताकि उन्हें आसानी से रिस्टोर किया जा सके।", + "Enable and disable package managers, change default install options, etc.": "पैकेज मैनेजर को चालू और बंद करें, डिफ़ॉल्ट इंस्टॉल ऑप्शन बदलें, वगैरह।", + "Internet connection settings": "इंटरनेट कनेक्शन सेटिंग्स", + "Proxy settings, etc.": "प्रॉक्सी सेटिंग्स, आदि.", + "Beta features and other options that shouldn't be touched": "बीटा सुविधाएँ और अन्य विकल्प जिन्हें छुआ नहीं जाना चाहिए", + "Reload sources": "स्रोत पुनः लोड करें", + "Delete source": "स्रोत हटाएं", + "Known sources": "ज्ञात स्रोत", + "Update checking": "अपडेट की जाँच हो रही है", + "Automatic updates": "स्वचालित अद्यतन", + "Check for package updates periodically": "समय-समय पर पैकेज अपडेट की जांच करें", + "Check for updates every:": "अपडेट की जांच करें हर:", + "Install available updates automatically": "उपलब्ध अपडेट अपने आप इंस्टॉल करें", + "Do not automatically install updates when the network connection is metered": "नेटवर्क कनेक्शन मीटर्ड होने पर अपडेट ऑटोमैटिकली इंस्टॉल न करें", + "Do not automatically install updates when the device runs on battery": "जब डिवाइस बैटरी पर चल रहा हो, तो अपडेट अपने आप इंस्टॉल न करें", + "Do not automatically install updates when the battery saver is on": "बैटरी सेवर चालू होने पर अपडेट अपने आप इंस्टॉल न करें", + "Only show updates that are at least the specified number of days old": "केवल वे अपडेट दिखाएँ जो कम से कम निर्धारित दिनों जितने पुराने हों", + "Warn me when the installer URL host changes between the installed version and the new version (WinGet only)": "जब इंस्टॉल किए गए संस्करण और नए संस्करण के बीच इंस्टॉलर URL होस्ट बदलता है तो मुझे चेतावनी दें (केवल WinGet)", + "Change how UniGetUI handles install, update and uninstall operations.": "यूनीगेटयूआई इंस्टॉल, अपडेट और अनइंस्टॉल ऑपरेशन को कैसे हैंडल करता है, इसे बदलें।", + "Navigation": "नेविगेशन", + "Check for UniGetUI updates": "UniGetUI अपडेट की जाँच करें", + "Quit UniGetUI": "UniGetUI बंद करें", + "Filters": "फिल्टर", + "Sources": "स्रोत", + "Search for packages to start": "पैकेज खोजना शुरू करें", + "Select all": "सभी चुने", + "Clear selection": "चयन साफ़ करें", + "Instant search": "त्वरित खोज", + "Distinguish between uppercase and lowercase": "अपरकेस और लोअरकेस में अंतर करें", + "Ignore special characters": "विशेष वर्णों को अनदेखा करें", + "Search mode": "खोज मोड", + "Both": "दोनों", + "Exact match": "सटीक मिलन", + "Show similar packages": "समान पैकेज दिखाएँ", + "Loading": "लोड हो रहा है", + "Package": "पैकेज", + "More options": "अधिक विकल्प", + "Order by:": "इसके अनुसार क्रमबद्ध करें:", + "Name": "नाम", + "Id": "पहचान", + "Ascendant": "प्रबल", + "Descendant": "वंशज", + "View modes": "दृश्य मोड", + "Reload": "पुनः लोड करें", + "Closed": "बंद", + "Ascending": "आरोही", + "Descending": "अवरोही", + "{0}: {1}, {2}": "{0}: {1}, {2}", + "Order by": "इसके अनुसार क्रमबद्ध करें", + "No results were found matching the input criteria": "इनपुट क्राइटेरिया से मैच करते हुए कोई रिज़ल्ट नहीं मिला", + "No packages were found": "कोई पैकेज नहीं मिला", + "Loading packages": "पैकेज लोड करना", + "Skip integrity checks": "अखंडता जांच छोड़ें", + "Download selected installers": "चयनित इंस्टॉलर डाउनलोड करें", + "Install selection": "चयन स्थापित करें", + "Install options": "इंस्टॉल विकल्प", + "Add selection to bundle": "चयन को बंडल में जोड़ें", + "Download installer": "इंस्टॉलर डाउनलोड करें", + "Uninstall selection": "चयन को अनइंस्टॉल करें", + "Uninstall options": "अनइंस्टॉल विकल्प", + "Ignore selected packages": "चयनित पैकेजों पर ध्यान न दें", + "Open install location": "इंस्टॉल स्थान खोलें", + "Reinstall package": "पैकेज पुनः स्थापित करें", + "Uninstall package, then reinstall it": "पैकेज को अनइंस्टॉल करें, फिर उसे दोबारा इंस्टॉल करें।", + "Ignore updates for this package": "इस पैकेज के अपडेट को नज़रअंदाज़ करें", + "WinGet malfunction detected": "विनगेट खराबी का पता चला", + "It looks like WinGet is not working properly. Do you want to attempt to repair WinGet?": "ऐसा लगता है कि विनगेट ठीक से काम नहीं कर रहा है. क्या आप विनगेट को ठीक करने की कोशिश करना चाहते हैं?", + "Repair WinGet": "विनगेट की मरम्मत करें", + "Updates will no longer be ignored for {0}": "{0} के लिए अपडेट अब उपेक्षित नहीं रहेंगे", + "Updates are now ignored for {0}": "{0} के लिए अपडेट अब उपेक्षित हैं", + "Do not ignore updates for this package anymore": "इस पैकेज के अपडेट को अब और नज़रअंदाज़ न करें", + "Add packages or open an existing package bundle": "पैकेज जोड़ें या मौजूदा पैकेज बंडल खोलें", + "Add packages to start": "पैकेजों को प्रारंभ में जोड़ें", + "The current bundle has no packages. Add some packages to get started": "अभी के बंडल में कोई पैकेज नहीं है। शुरू करने के लिए कुछ पैकेज जोड़ें", + "New": "नया", + "Save as": "इस रूप में सहेजें", + "Create .ps1 script": ".ps1 स्क्रिप्ट बनाएँ", + "Remove selection from bundle": "बंडल से चयन हटाएँ", + "Skip hash checks": "हैश जाँच छोड़ें", + "The package bundle is not valid": "पैकेज बंडल मान्य नहीं है", + "The bundle you are trying to load appears to be invalid. Please check the file and try again.": "आप जो बंडल लोड करने की कोशिश कर रहे हैं, वह इनवैलिड लग रहा है। कृपया फ़ाइल चेक करें और फिर से कोशिश करें।", + "Package bundle": "पैकेज बंडल", + "Could not create bundle": "बंडल नहीं बनाया जा सका", + "The package bundle could not be created due to an error.": "एक एरर के कारण पैकेज बंडल नहीं बनाया जा सका।", + "Install script": "स्क्रिप्ट स्थापित करें", + "PowerShell script": "PowerShell स्क्रिप्ट", + "The installation script saved to {0}": "इंस्टॉलेशन स्क्रिप्ट को {0} में सेव किया गया", + "An error occurred": "एक त्रुटि हुई", + "An error occurred while attempting to create an installation script:": "इंस्टॉलेशन स्क्रिप्ट बनाने की कोशिश करते समय एक एरर आया:", + "Hooray! No updates were found.": "\nवाह! कोई अपडेट नहीं मिला!", + "Uninstall selected packages": "चुने पैकेज की स्थापना रद्द करें", + "Update selection": "चयन अपडेट करें", + "Update options": "अपडेट विकल्प", + "Uninstall package, then update it": "पैकेज को अनइंस्टॉल करें, फिर उसे अपडेट करें।", + "Uninstall package": "\nपैकेज की स्थापना रद्द करें", + "Skip this version": "इस संस्करण को छोड़ दें", + "Pause updates for": "इसके लिए अपडेट रोकें", + "User | Local": "उपयोगकर्ता | स्थानीय", + "Machine | Global": "मशीन | वैश्विक", + "The default package manager for Debian/Ubuntu-based Linux distributions.
Contains: Debian/Ubuntu packages": "Debian/Ubuntu-आधारित Linux वितरणों के लिए डिफ़ॉल्ट पैकेज प्रबंधक।
शामिल हैं: Debian/Ubuntu पैकेज", + "The Rust package manager.
Contains: Rust libraries and programs written in Rust": "रस्ट पैकेज मैनेजर.
निहित: रस्ट लाइब्रेरी और रस्ट में लिखे गए प्रोग्राम", + "The classical package manager for windows. You'll find everything there.
Contains: General Software": "विंडोज़ के लिए क्लासिक पैकेज मैनेजर. आपको वहां सब कुछ मिलेगा.
निहित: सामान्य सॉफ्टवेयर", + "The default package manager for RHEL/Fedora-based Linux distributions.
Contains: RPM packages": "RHEL/Fedora-आधारित Linux वितरणों के लिए डिफ़ॉल्ट पैकेज प्रबंधक।
शामिल हैं: RPM पैकेज", + "A repository full of tools and executables designed with Microsoft's .NET ecosystem in mind.
Contains: .NET related tools and scripts": "Microsoft के .NET पारिस्थितिकी तंत्र को ध्यान में रखकर डिज़ाइन किए गए टूल और एक्ज़ीक्यूटेबल्स से भरा एक संग्रह।\nइसमें शामिल हैं:\n.NET से संबंधित टूल और स्क्रिप्ट", + "The universal Linux package manager for desktop applications.
Contains: Flatpak applications from configured remotes": "डेस्कटॉप अनुप्रयोगों के लिए सार्वभौमिक Linux पैकेज प्रबंधक।
शामिल हैं: कॉन्फ़िगर किए गए रिमोट्स से Flatpak अनुप्रयोग", + "NuPkg (zipped manifest)": "NuPkg (ज़िप्ड मैनिफ़ेस्ट)", + "The Missing Package Manager for macOS (or Linux).
Contains: Formulae, Casks": "macOS (या Linux) के लिए Missing Package Manager.
शामिल है: Formulae, Casks", + "Node JS's package manager. Full of libraries and other utilities that orbit the javascript world
Contains: Node javascript libraries and other related utilities": "Node JS का पैकेज मैनेजर। जावास्क्रिप्ट की दुनिया में मौजूद लाइब्रेरी और दूसरी यूटिलिटी से भरा हुआ
में निहित: नोड जावास्क्रिप्ट लाइब्रेरी और अन्य संबंधित उपयोगिताएँ", + "The default package manager for Arch Linux and its derivatives.
Contains: Arch Linux packages": "Arch Linux और इसके व्युत्पन्नों के लिए डिफ़ॉल्ट पैकेज प्रबंधक।
शामिल हैं: Arch Linux पैकेज", + "Python's library manager. Full of python libraries and other python-related utilities
Contains: Python libraries and related utilities": "पायथन लाइब्रेरी मैनेजर। पायथन लाइब्रेरीज़ और अन्य पायथन-संबंधित उपयोगिताओं से भरपूर
निहित: पायथन लाइब्रेरी और संबंधित उपयोगिताएँ", + "PowerShell's package manager. Find libraries and scripts to expand PowerShell capabilities
Contains: Modules, Scripts, Cmdlets": "पावरशेल का पैकेज प्रबंधक। पावरशेल की क्षमताओं का विस्तार करने के लिए लाइब्रेरी और स्क्रिप्ट खोजें
निहित: मॉड्यूल, स्क्रिप्ट, कमांडलेट", + "extracted": "निकाला गया", + "Scoop package": "स्कूप पैकेज", + "Great repository of unknown but useful utilities and other interesting packages.
Contains: Utilities, Command-line programs, General Software (extras bucket required)": "अनजान लेकिन काम की यूटिलिटीज़ और दूसरे दिलचस्प पैकेज का शानदार रिपॉजिटरी।
रोकना: यूटिलिटीज़, कमांड-लाइन प्रोग्राम, जनरल सॉफ्टवेयर (एक्स्ट्रा बकेट ज़रूरी है) ", + "The universal Linux package manager by Canonical.
Contains: Snap packages from the Snapcraft store": "Canonical द्वारा सार्वभौमिक Linux पैकेज प्रबंधक।
शामिल हैं: Snapcraft store से Snap पैकेज", + "library": "लाइब्रेरी", + "feature": "सुविधा", + "A popular C/C++ library manager. Full of C/C++ libraries and other C/C++-related utilities
Contains: C/C++ libraries and related utilities": "एक लोकप्रिय C/C++ लाइब्रेरी मैनेजर। C/C++ लाइब्रेरी और अन्य C/C++-संबंधित उपयोगिताओं से भरपूर।\nइसमें शामिल हैं:\nC/C++ लाइब्रेरी और संबंधित उपयोगिताएँ", + "option": "विकल्प", + "This package cannot be installed from an elevated context.": "इस पैकेज को एलिवेटेड कॉन्टेक्स्ट से इंस्टॉल नहीं किया जा सकता।", + "Please run UniGetUI as a regular user and try again.": "कृपया यूनीगेटयूआई को नियमित उपयोगकर्ता के रूप में चलाएँ और पुनः प्रयास करें।", + "Please check the installation options for this package and try again": "कृपया इस पैकेज के लिए स्थापना विकल्प जांचें और पुनः प्रयास करें", + "Microsoft's official package manager. Full of well-known and verified packages
Contains: General Software, Microsoft Store apps": "माइक्रोसॉफ्ट का ऑफिशियल पैकेज मैनेजर। जाने-माने और वेरिफाइड पैकेज से भरा हुआ।
में निहित: सामान्य सॉफ़्टवेयर, माइक्रोसॉफ्ट स्टोर ऐप्स", + "Local PC": "स्थानीय पी.सी", + "Android Subsystem": "एंड्रॉइड सबसिस्टम", + "Operation on queue (position {0})...": "कतार पर ऑपरेशन (स्थिति {0})...", + "Click here for more details": "अधिक जानकारी के लिए यहां क्लिक करें", + "Operation canceled by user": "उपयोगकर्ता द्वारा ऑपरेशन रद्द कर दिया गया", + "Running PreOperation ({0}/{1})...": "PreOperation चल रहा है ({0}/{1})...", + "PreOperation {0} out of {1} failed, and was tagged as necessary. Aborting...": "{1} में से PreOperation {0} विफल हुआ, और उसे आवश्यक के रूप में चिह्नित किया गया था। निरस्त किया जा रहा है...", + "PreOperation {0} out of {1} finished with result {2}": "{1} में से PreOperation {0} परिणाम {2} के साथ समाप्त हुआ", + "Starting operation...": "ऑपरेशन शुरू हो रहा है...", + "Running PostOperation ({0}/{1})...": "PostOperation चल रहा है ({0}/{1})...", + "PostOperation {0} out of {1} failed, and was tagged as necessary. Aborting...": "{1} में से PostOperation {0} विफल हुआ, और उसे आवश्यक के रूप में चिह्नित किया गया था। निरस्त किया जा रहा है...", + "PostOperation {0} out of {1} finished with result {2}": "{1} में से PostOperation {0} परिणाम {2} के साथ समाप्त हुआ", + "{package} installer download": "{package} इंस्टॉलर डाउनलोड", + "{0} installer is being downloaded": "{0} इंस्टॉलर डाउनलोड किया जा रहा है", + "Download succeeded": "डाउनलोड सफल रहा", + "{package} installer was downloaded successfully": "{package} इंस्टॉलर सफलतापूर्वक डाउनलोड हो गया", + "Download failed": "डाउनलोड विफल", + "{package} installer could not be downloaded": "{package} इंस्टॉलर डाउनलोड नहीं हो सका", + "{package} Installation": "{package} इंस्टॉलेशन", + "{0} is being installed": "{0} इंस्टॉल किया जा रहा है", + "Installation succeeded": "स्थापना सफल रही", + "{package} was installed successfully": "{package} सफलतापूर्वक इंस्टॉल हो गया", + "Installation failed": "स्थापना विफल", + "{package} could not be installed": "{package} इंस्टॉल नहीं हो सका", + "{package} Update": "{package} अपडेट", + "Update succeeded": "अपडेट सफल रहा", + "{package} was updated successfully": "{package} सफलतापूर्वक अपडेट हो गया", + "Update failed": "अपडेट विफल रहे", + "{package} could not be updated": "{package} अपडेट नहीं हो सका", + "{package} Uninstall": "{package} अनइंस्टॉल", + "{0} is being uninstalled": "{0} अनइंस्टॉल किया जा रहा है", + "Uninstall succeeded": "अनइंस्टॉल सफल रहा", + "{package} was uninstalled successfully": "{package} सफलतापूर्वक अनइंस्टॉल हो गया", + "Uninstall failed": "अनइंस्टॉल विफल रहा", + "{package} could not be uninstalled": "{package} अनइंस्टॉल नहीं हो सका", + "Adding source {source}": "स्रोत {source} जोड़ा जा रहा है।", + "Adding source {source} to {manager}": "स्रोत {source}{manager}जोड़ना", + "Source added successfully": "स्रोत सफलतापूर्वक जोड़ा गया", + "The source {source} was added to {manager} successfully": "स्रोत {source} को {manager} में जोड़ा गया", + "Could not add source": "स्रोत नहीं जोड़ा जा सका", + "Could not add source {source} to {manager}": "स्रोत नहीं जोड़ा जा सका{source} को {manager} के साथ", + "Removing source {source}": "{source}स्रोत हटाना", + "Removing source {source} from {manager}": "{manager} से {source}स्रोत हटाना", + "Source removed successfully": "स्रोत सफलतापूर्वक हटा दिया गया", + "The source {source} was removed from {manager} successfully": "{manager} से स्रोत {source} को सफलतापूर्वक हटा दिया गया", + "Could not remove source": "स्रोत हटाया नहीं जा सका", + "Could not remove source {source} from {manager}": "स्रोत {source} हटाया नहीं जा सका {manager} से", + "The package manager \"{0}\" was not found": "पैकेज प्रबंधक {0} नहीं मिला था", + "The package manager \"{0}\" is disabled": "पैकेज प्रबंधक {0} अक्षम है", + "There is an error with the configuration of the package manager \"{0}\"": "पैकेज प्रबंधक \"{0}\" के कॉन्फ़िगरेशन में कोई गड़बड़ी है।", + "The package \"{0}\" was not found on the package manager \"{1}\"": "पैकेज {0} पैकेज पैकेज मैनेजर {1} पर नहीं मिला", + "{0} is disabled": "{0} अक्षम है", + "{0} weeks": "{0} सप्ताह", + "1 month": "1 महीना", + "{0} months": "{0} महीने", + "Something went wrong": "कुछ गलत हो गया", + "An interal error occurred. Please view the log for further details.": "एक आंतरिक त्रुटि हुई। कृपया अधिक जानकारी के लिए लॉग देखें", + "No applicable installer was found for the package {0}": "{0} पैकेज के लिए कोई लागू इंस्टॉलर नहीं मिला", + "Integrity checks will not be performed during this operation": "इस ऑपरेशन के दौरान इंटीग्रिटी चेक नहीं किए जाएंगे", + "This is not recommended.": "इसकी सलाह नहीं दी जाती है।", + "Run now": "अब चलाएँ", + "Run next": "अगला भाग चलाएँ", + "Run last": "अन्त में चलाएं", + "Show in explorer": "एक्सप्लोरर में दिखाएँ", + "Checked": "चेक किया गया", + "Unchecked": "अनचेक किया गया", + "This package is already installed": "यह पैकेज पहले से ही इंस्टॉल है", + "This package can be upgraded to version {0}": "इस पैकेज को {0} वर्जन में अपडेट किया जा सकता है।", + "Updates for this package are ignored": "इस पैकेज के लिए अपडेट को अनदेखा किया जाता है।", + "This package is being processed": "यह पैकेज पहले से ही प्रसंस्कृत है", + "This package is not available": "यह पैकेज उपलब्ध नहीं है", + "Select the source you want to add:": "वह सोर्स चुनें जिसे आप जोड़ना चाहते हैं:", + "Source name:": "स्रोत का नाम:", + "Source URL:": "स्रोत यूआरएल:", + "An error occurred when adding the source: ": "स्रोत जोड़ते समय एक त्रुटि हुई:", + "Package management made easy": "पैकेज संचालन आसान हो गया", + "version {0}": "संस्करण {0}", + "[RAN AS ADMINISTRATOR]": "[व्यवस्थापक के रूप में चलाया गया]", + "Portable mode": "पोर्टेबल मोड\n", + "DEBUG BUILD": "डीबग बिल्ड", + "Here you can change UniGetUI's behaviour regarding the following shortcuts. Checking a shortcut will make UniGetUI delete it if if gets created on a future upgrade. Unchecking it will keep the shortcut intact": "यहां आप नीचे दिए गए शॉर्टकट के बारे में यूनीगेटयूआई का बिहेवियर बदल सकते हैं। किसी शॉर्टकट को चेक करने पर, अगर भविष्य में अपग्रेड पर वह बनता है, तो यूनीगेटयूआई उसे डिलीट कर देगा। इसे अनचेक करने से शॉर्टकट बना रहेगा।", + "Manual scan": "हस्तचालित स्कैन\n", + "Existing shortcuts on your desktop will be scanned, and you will need to pick which ones to keep and which ones to remove.": "आपके डेस्कटॉप पर मौजूद शॉर्टकट स्कैन किए जाएंगे, और आपको चुनना होगा कि कौन से रखने हैं और कौन से हटाने हैं।", + "Delete?": "हटाएँ?", + "I understand": "मैं समझता हूँ", + "Chocolatey setup changed": "Chocolatey सेटअप बदल गया है", + "UniGetUI no longer includes its own private Chocolatey installation. A legacy UniGetUI-managed Chocolatey installation was detected for this user profile, but system Chocolatey was not found. Chocolatey will stay unavailable in UniGetUI until Chocolatey is installed on the system and UniGetUI is restarted. Applications previously installed through UniGetUI's bundled Chocolatey may still appear under other sources such as Local PC or WinGet.": "UniGetUI में अब अपना निजी Chocolatey इंस्टॉलेशन शामिल नहीं है। इस उपयोगकर्ता प्रोफ़ाइल के लिए UniGetUI-प्रबंधित पुराना Chocolatey इंस्टॉलेशन पाया गया, लेकिन सिस्टम Chocolatey नहीं मिला। जब तक सिस्टम पर Chocolatey इंस्टॉल नहीं किया जाता और UniGetUI पुनः प्रारंभ नहीं किया जाता, तब तक Chocolatey UniGetUI में अनुपलब्ध रहेगा। UniGetUI के बंडल किए गए Chocolatey के माध्यम से पहले इंस्टॉल किए गए एप्लिकेशन अभी भी अन्य स्रोतों जैसे Local PC या WinGet के अंतर्गत दिखाई दे सकते हैं।", + "NOTE: This troubleshooter can be disabled from UniGetUI Settings, on the WinGet section": "नोट: इस ट्रबलशूटर को विनगेट सेक्शन में यूनीगेटयूआई सेटिंग्स से डिसेबल किया जा सकता है।", + "Restart": "पुनःआरंभ करें", + "Are you sure you want to delete all shortcuts?": "क्या आप वाकई सभी शॉर्टकट डिलीट करना चाहते हैं?", + "Any new shorcuts created during an install or an update operation will be deleted automatically, instead of showing a confirmation prompt the first time they are detected.": "इंस्टॉल या अपडेट ऑपरेशन के दौरान बनाए गए कोई भी नए शॉर्टकट अपने आप डिलीट हो जाएंगे, और पहली बार पता चलने पर कन्फर्मेशन प्रॉम्प्ट नहीं दिखेगा।", + "Any shorcuts created or modified outside of UniGetUI will be ignored. You will be able to add them via the {0} button.": "यूनीगेटयूआई के बाहर बनाए गए या बदले गए किसी भी शॉर्टकट को इग्नोर कर दिया जाएगा। आप उन्हें {0} बटन से जोड़ पाएंगे।", + "Are you really sure you want to enable this feature?": "क्या आप वाकई इस फ़ीचर को चालू करना चाहते हैं?", + "No new shortcuts were found during the scan.": "स्कैन के दौरान कोई नई शॉर्टकट नहीं मिली।", + "How to add packages to a bundle": "बंडल में पैकेज कैसे जोड़ें", + "In order to add packages to a bundle, you will need to: ": "बंडल में पैकेज जोड़ने के लिए, आपको ये करना होगा:", + "1. Navigate to the \"{0}\" or \"{1}\" page.": "\"{0}\" या \"{1}\" पेज पर जाएँ", + "2. Locate the package(s) you want to add to the bundle, and select their leftmost checkbox.": "2. उस पैकेज (या पैकेजों) को खोजें जिसे आप बंडल में जोड़ना चाहते हैं, और उनके सबसे बाएँ स्थित चेकबॉक्स को चुनें।", + "3. When the packages you want to add to the bundle are selected, find and click the option \"{0}\" on the toolbar.": "3. जब आप बंडल में जोड़ने के लिए पैकेज चुन लेते हैं, तो टूलबार पर \"{0}\" विकल्प को खोजें और उस पर क्लिक करें।", + "4. Your packages will have been added to the bundle. You can continue adding packages, or export the bundle.": "4. आपके पैकेज बंडल में जोड़ दिए गए हैं। आप पैकेज जोड़ना जारी रख सकते हैं, या बंडल को एक्सपोर्ट कर सकते हैं।", + "Which backup do you want to open?": "आप कौन सा बैकअप खोलना चाहते हैं?", + "Select the backup you want to open. Later, you will be able to review which packages you want to install.": "वह बैकअप चुनें जिसे आप खोलना चाहते हैं। बाद में, आप देख पाएँगे कि आप कौन से पैकेज/प्रोग्राम रिस्टोर करना चाहते हैं।", + "There are ongoing operations. Quitting UniGetUI may cause them to fail. Do you want to continue?": "ऑपरेशन चल रहे हैं। यूनीगेटयूआई बंद करने से वे फेल हो सकते हैं। क्या आप जारी रखना चाहते हैं?", + "UniGetUI or some of its components are missing or corrupt.": "यूनीगेटयूआई या इसके कुछ कंपोनेंट गायब हैं या खराब हो गए हैं।", + "It is strongly recommended to reinstall UniGetUI to adress the situation.": "इस स्थिति को ठीक करने के लिए यूनीगेटयूआई को फिर से इंस्टॉल करने की सलाह दी जाती है।", + "Refer to the UniGetUI Logs to get more details regarding the affected file(s)": "प्रभावित फ़ाइल(फ़ाइलों) के बारे में अधिक जानकारी प्राप्त करने के लिए यूनीगेटयूआई लॉग देखें", + "Integrity checks can be disabled from the Experimental Settings": "एक्सपेरिमेंटल सेटिंग्स से इंटीग्रिटी चेक को डिसेबल किया जा सकता है", + "Repair UniGetUI": "यूनीगेटयूआई की मरम्मत करें", + "Live output": "लाइव आउटपुट", + "This package bundle had some settings that are potentially dangerous, and may be ignored by default.": "इस पैकेज बंडल में कुछ ऐसी सेटिंग्स थीं जो संभावित रूप से खतरनाक हैं, और जिन्हें डिफ़ॉल्ट रूप से अनदेखा किया जा सकता है।", + "Entries that show in YELLOW will be IGNORED.": "जो एंट्री पीला रंग में दिखेंगी उन्हें अनदेखा कर दिया जाएगा।", + "Entries that show in RED will be IMPORTED.": "जो एंट्री लाल रंग में दिखेंगी, उन्हें आयातित कर दिया जाएगा।", + "You can change this behavior on UniGetUI security settings.": "आप इस व्यवहार को UniGetUI सुरक्षा सेटिंग्स में बदल सकते हैं।", + "Open UniGetUI security settings": "यूनीगेटयूआई सुरक्षा सेटिंग्स खोलें", + "Should you modify the security settings, you will need to open the bundle again for the changes to take effect.": "अगर आप सिक्योरिटी सेटिंग्स में बदलाव करते हैं, तो बदलाव लागू होने के लिए आपको बंडल को फिर से खोलना होगा।", + "Details of the report:": "रिपोर्ट का विवरण:", + "Are you sure you want to create a new package bundle? ": "क्या आप वाकई एक नया पैकेज बंडल बनाना चाहते हैं?", + "Any unsaved changes will be lost": "कोई भी बिना सेव किए गए बदलाव खो जाएँगे", + "Warning!": "चेतावनी!", + "For security reasons, custom command-line arguments are disabled by default. Go to UniGetUI security settings to change this. ": "सुरक्षा कारणों से, कस्टम कमांड-लाइन आर्गुमेंट डिफ़ॉल्ट रूप से डिसेबल होते हैं। इसे बदलने के लिए यूनीगेटयूआई सुरक्षा सेटिंग्स पर जाएं।", + "Change default options": "डिफ़ॉल्ट विकल्प बदलें", + "Ignore future updates for this package": "इस पैकेज के लिए भविष्य के अपडेट पर ध्यान न दें", + "For security reasons, pre-operation and post-operation scripts are disabled by default. Go to UniGetUI security settings to change this. ": "सुरक्षा कारणों से, प्री-ऑपरेशन और पोस्ट-ऑपरेशन स्क्रिप्ट डिफ़ॉल्ट रूप से डिसेबल होती हैं। इसे बदलने के लिए यूनीगेटयूआई सुरक्षा सेटिंग्स पर जाएं।", + "You can define the commands that will be run before or after this package is installed, updated or uninstalled. They will be run on a command prompt, so CMD scripts will work here.": "आप उन कमांडों को परिभाषित कर सकते हैं जो इस पैकेज के इंस्टॉल, अपडेट या अनइंस्टॉल होने से पहले या बाद में चलेंगी। उन्हें कमांड प्रॉम्प्ट में चलाया जाएगा, इसलिए CMD स्क्रिप्ट यहाँ काम करेंगी।", + "Change this and unlock": "इसे बदलें और अनलॉक करें", + "{0} Install options are currently locked because {0} follows the default install options.": "{0} इंस्टॉल विकल्प फिलहाल लॉक हैं क्योंकि {0} डिफ़ॉल्ट इंस्टॉल विकल्पों का पालन करता है।", + "Unset or unknown": "अनसेट या अज्ञात", + "This package has no screenshots or is missing the icon? Contrbute to UniGetUI by adding the missing icons and screenshots to our open, public database.": "इस पैकेज में कोई स्क्रीनशॉट नहीं है या आइकन गायब है? हमारे ओपन, पब्लिक डेटाबेस में गायब आइकन और स्क्रीनशॉट जोड़कर यूनीगेटयूआई में योगदान दें।", + "Become a contributor": "योगदानकर्ता बनें", + "Update to {0} available": "{0} में अपडेट उपलब्ध है", + "Reinstall": "दोबारा इंस्टॉल करें", + "Installer not available": "इंस्टॉलर उपलब्ध नहीं है", + "Version:": "संस्करण:", + "UniGetUI Version {0}": "UniGetUI संस्करण {0}", + "Performing backup, please wait...": "बैकअप किया जा रहा है, कृपया प्रतीक्षा करें...", + "An error occurred while logging in: ": "लॉग इन करते समय एक एरर आया:", + "Fetching available backups...": "उपलब्ध बैकअप लाए जा रहे हैं...", + "Done!": "हो गया!", + "The cloud backup has been loaded successfully.": "क्लाउड बैकअप सफलतापूर्वक लोड हो गया है।", + "An error occurred while loading a backup: ": "बैकअप लोड करते समय एक एरर आया:", + "Backing up packages to GitHub Gist...": "गिटहब गिस्ट पर पैकेज का बैकअप लिया जा रहा है...", + "Backup Successful": "बैकअप सफल", + "The cloud backup completed successfully.": "क्लाउड बैकअप सफलतापूर्वक पूरा हो गया।", + "Could not back up packages to GitHub Gist: ": "गिटहब गिस्ट पर पैकेज का बैकअप नहीं लिया जा सका:", + "It is not guaranteed that the provided credentials will be stored safely, so you may as well not use the credentials of your bank account": "इस बात की गारंटी नहीं है कि दिए गए क्रेडेंशियल सुरक्षित रूप से स्टोर किए जाएंगे, इसलिए बेहतर होगा कि आप अपने बैंक अकाउंट के क्रेडेंशियल का इस्तेमाल न करें।", + "Enable the automatic WinGet troubleshooter": "ऑटोमैटिक विनगेट ट्रबलशूटर चालू करें", + "Add updates that fail with a 'no applicable update found' to the ignored updates list": "'कोई लागू अद्यतन नहीं मिला' त्रुटि के साथ विफल अद्यतनों को अनदेखे अद्यतन सूची में जोड़ें", + "Invalid selection": "अमान्य चयन", + "No package was selected": "कोई पैकेज नहीं चुना गया", + "More than 1 package was selected": "1 से अधिक पैकेज चुने गए", + "List": "सूची", + "Grid": "ग्रिड", + "Icons": "आइकन", + "\"{0}\" is a local package and does not have available details": "\"{0}\" एक स्थानीय पैकेज है और इसके विवरण उपलब्ध नहीं हैं", + "\"{0}\" is a local package and is not compatible with this feature": "\"{0}\" एक लोकल पैकेज है और इस सुविधा के साथ अनुकूल नहीं है", + "Add packages to bundle": "पैकेजों को बंडल में जोड़ें", + "Preparing packages, please wait...": "पैकेज तैयार हो रहे हैं, कृपया प्रतीक्षा करें...", + "Loading packages, please wait...": "पैकेज लोड हो रहे हैं, कृपया इंतज़ार करें...", + "Saving packages, please wait...": "पैकेज सेव कर रहे हैं, कृपया इंतज़ार करें...", + "The bundle was created successfully on {0}": "बंडल सफलतापूर्वक {0} में बनाया गया", + "User profile": "उपयोगकर्ता प्रोफ़ाइल", + "Error": "एरर", + "Log in failed: ": "लॉगिन विफल रहा:", + "Log out failed: ": "लॉग आउट विफल:", + "Package backup settings": "पैकेज बैकअप सेटिंग्स", + "Manage UniGetUI autostart behaviour from the Settings app": "UniGetUI के ऑटोस्टार्ट व्यवहार को प्रबंधित करें", + "Choose how many operations shoulds be performed in parallel": "चुनें कि कितनी कार्रवाइयाँ समानांतर में की जानी चाहिए", + "Something went wrong while launching the updater.": "अपडेटर लॉन्च करते समय कुछ गलत हो गई।", + "Please try again later": "कृपया बाद में पुन: प्रयास करें", + "Show the release notes after UniGetUI is updated": "UniGetUI अपडेट होने के बाद रिलीज नोट्स दिखाएं" +} diff --git a/src/Languages/lang_hr.json b/src/Languages/lang_hr.json new file mode 100644 index 0000000..9379372 --- /dev/null +++ b/src/Languages/lang_hr.json @@ -0,0 +1,850 @@ +{ + "{0} of {1} operations completed": "Dovršeno {0} od {1} operacija", + "{0} is now {1}": "{0} je sada {1}", + "Enabled": "Omogućeno", + "Disabled": "Onemogućeno", + "Privacy": "Privatnost", + "Hide my username from the logs": "Sakrij moje korisničko ime iz zapisnika", + "Replaces your username with **** in the logs. Restart UniGetUI to also hide it from already-recorded entries.": "Zamjenjuje vaše korisničko ime s **** u zapisnicima. Ponovno pokrenite UniGetUI kako biste ga sakrili i iz već zabilježenih unosa.", + "Your last update attempt did not complete.": "Vaš posljednji pokušaj ažuriranja nije dovršen.", + "UniGetUI could not confirm whether the update succeeded. Open the log to see what happened.": "UniGetUI nije mogao potvrditi je li ažuriranje uspjelo. Otvorite zapisnik da biste vidjeli što se dogodilo.", + "View log": "Prikaži zapisnik", + "The installer reported success but did not restart UniGetUI.": "Instalacijski program prijavio je uspjeh, ali nije ponovno pokrenuo UniGetUI.", + "The installer failed to initialize.": "Instalacijski program nije se uspio inicijalizirati.", + "Setup was canceled before installation began.": "Postavljanje je otkazano prije početka instalacije.", + "A fatal error occurred during the preparation phase.": "Došlo je do fatalne pogreške tijekom faze pripreme.", + "A fatal error occurred during installation.": "Došlo je do fatalne pogreške tijekom instalacije.", + "Installation was canceled while in progress.": "Instalacija je otkazana dok je bila u tijeku.", + "The installer was terminated by another process.": "Instalacijski program prekinuo je drugi proces.", + "The preparation phase determined the installation cannot proceed.": "Faza pripreme utvrdila je da se instalacija ne može nastaviti.", + "The installer could not start. UniGetUI may already be running, or you do not have permission to install.": "Instalacijski program nije se mogao pokrenuti. UniGetUI je možda već pokrenut ili nemate dopuštenje za instalaciju.", + "Unexpected installer error.": "Neočekivana pogreška instalacijskog programa.", + "We are checking for updates.": "Provjeravamo ažuriranja.", + "Please wait": "Molim pričekajte", + "Great! You are on the latest version.": "Odlično! Imate najnoviju verziju.", + "There are no new UniGetUI versions to be installed": "Nema novih verzija UniGetUI-ja za instaliranje", + "UniGetUI version {0} is being downloaded.": "UniGetUI verzija {0} se preuzima.", + "This may take a minute or two": "Ovo može potrajati minutu ili dvije", + "The installer authenticity could not be verified.": "Autentičnost instalacijskog programa nije mogla biti potvrđena.", + "The update process has been aborted.": "Proces ažuriranja je prekinut.", + "Auto-update is not yet available on this platform.": "Automatsko ažuriranje još nije dostupno na ovoj platformi.", + "Please update UniGetUI manually.": "Ažurirajte UniGetUI ručno.", + "An error occurred when checking for updates: ": "Došlo je do pogreške prilikom provjere ažuriranja: ", + "The updater could not be launched.": "Program za ažuriranje nije se mogao pokrenuti.", + "The operating system did not start the installer process.": "Operacijski sustav nije pokrenuo proces instalacijskog programa.", + "UniGetUI is being updated...": "UniGetUI se ažurira...", + "Update installed.": "Ažuriranje je instalirano.", + "UniGetUI was updated successfully, but this running copy was not replaced. This usually means you are running a development build. Close this copy and start the newly-installed version to finish.": "UniGetUI je uspješno ažuriran, ali ova pokrenuta kopija nije zamijenjena. To obično znači da koristite razvojnu verziju. Zatvorite ovu kopiju i pokrenite novoinstaliranu verziju da biste dovršili postupak.", + "The update could not be applied.": "Ažuriranje se nije moglo primijeniti.", + "Installer exit code {0}: {1}": "Izlazni kod instalacijskog programa {0}: {1}", + "Update cancelled.": "Ažuriranje je otkazano.", + "Authentication was cancelled.": "Autentifikacija je otkazana.", + "Installer exit code {0}": "Izlazni kod instalacijskog programa {0}", + "Operation in progress": "Operacija u tijeku", + "Please wait...": "Molimo pričekajte...", + "Success!": "Uspjeh!", + "Failed": "Neuspješno", + "An error occurred while processing this package": "Došlo je do pogreške prilikom obrade ovog paketa", + "Installer": "Instalacijski program", + "Executable": "Izvršna datoteka", + "MSI": "MSI", + "Compressed file": "Komprimirana datoteka", + "MSIX": "MSIX", + "WinGet was repaired successfully": "WinGet je uspješno popravljen", + "It is recommended to restart UniGetUI after WinGet has been repaired": "Preporučuje se ponovno pokretanje UniGetUI-ja nakon što je WinGet popravljen.", + "WinGet could not be repaired": "WinGet se nije mogao popraviti", + "An unexpected issue occurred while attempting to repair WinGet. Please try again later": "Došlo je do neočekivanog problema prilikom pokušaja popravka WinGet-a. Pokušajte ponovno kasnije.", + "Log in to enable cloud backup": "Prijavite se da biste omogućili sigurnosno kopiranje u oblak", + "Backup Failed": "Sigurnosno kopiranje nije uspjelo", + "Downloading backup...": "Preuzimanje sigurnosnih kopija...", + "An update was found!": "Pronađeno je ažuriranje!", + "{0} can be updated to version {1}": "{0} može se ažurirati na verziju {1}", + "Updates found!": "Pronađena ažuriranja!", + "{0} packages can be updated": "{0} paketa se može ažurirati", + "{0} is being updated to version {1}": "{0} ažurira se na verziju {1}", + "{0} packages are being updated": "{0} paketa se ažurira", + "You have currently version {0} installed": "Trenutno imate instaliranu verziju {0}", + "Desktop shortcut created": "Stvoren je prečac na radnoj površini", + "UniGetUI has detected a new desktop shortcut that can be deleted automatically.": "UniGetUI je otkrio novi prečac na radnoj površini koji se može automatski izbrisati.", + "{0} desktop shortcuts created": "{0} stvoreni prečaci na radnoj površini", + "UniGetUI has detected {0} new desktop shortcuts that can be deleted automatically.": "UniGetUI je otkrio {0} nove prečace na radnoj površini koji se mogu automatski izbrisati.", + "Attention required": "Potrebna je pažnja", + "Restart required": "Potrebno ponovno pokretanje", + "1 update is available": "Dostupno je 1 ažuriranje", + "{0} updates are available": "{0} ažuriranja je dostupno", + "Everything is up to date": "Sve je ažurirano", + "Discover Packages": "Otkrijte pakete", + "Available Updates": "Dostupna ažuriranja", + "Installed Packages": "Instalirani paketi", + "UniGetUI Version {0} by Devolutions": "UniGetUI verzija {0} tvrtke Devolutions", + "Show UniGetUI": "Prikaži UniGetUI", + "Quit": "Zatvori", + "Are you sure?": "Jeste li sigurni?", + "Do you really want to uninstall {0}?": "Želite li stvarno deinstalirati {0}?", + "Do you really want to uninstall the following {0} packages?": "Želite li zaista deinstalirati sljedeće pakete {0}?", + "No": "Ne", + "Yes": "Da", + "Partial": "Djelomično", + "View on UniGetUI": "Pogledajte na UniGetUI-ju", + "Update": "Ažuriraj", + "Open UniGetUI": "Otvori UniGetUI", + "Update all": "Ažuriraj sve", + "Update now": "Ažuriraj sada", + "Installer host changed since the installed version.\n": "Host instalacijskog programa promijenio se od instalirane verzije.\n", + "This package is on the queue": "Ovaj paket je u redu čekanja", + "installing": "instaliranje", + "updating": "ažuriranje", + "uninstalling": "deinstaliranje", + "installed": "instalirano", + "Retry": "Pokušaj ponovo", + "Install": "Instalirati", + "Uninstall": "Deinstaliraj", + "Open": "Otvori", + "Operation profile:": "Profil rada:", + "Follow the default options when installing, upgrading or uninstalling this package": "Slijedite zadane opcije prilikom instalacije, nadogradnje ili de-instalacije ovog paketa", + "The following settings will be applied each time this package is installed, updated or removed.": "Sljedeće postavke bit će primijenjene svaki put kada se ovaj paket instalira, ažurira ili ukloni.", + "Version to install:": "Verzija za instaliranje:", + "Architecture to install:": "Arhitektura za instalaciju:", + "Installation scope:": "Opseg instalacije:", + "Install location:": "Mjesto instalacije:", + "Select": "Odaberi", + "Reset": "Resetiraj", + "Custom install arguments:": "Argumenti prilagođene instalacije:", + "Custom update arguments:": "Argumenti prilagođene nadogradnje:", + "Custom uninstall arguments:": "Prilagođeni argumenti deinstalacije:", + "Pre-install command:": "Naredba pred instalacije:", + "Post-install command:": "Naredba nakon instalacije:", + "Abort install if pre-install command fails": "Prekini instalaciju ukoliko je prilikom pred-instalacijske naredbe došlo do greške", + "Pre-update command:": "Naredba prije ažuriranja:", + "Post-update command:": "Naredba nakon ažuriranja:", + "Abort update if pre-update command fails": "Prekini ažuriranje ukoliko je prilikom naredbe pred ažuriranja došlo do greške", + "Pre-uninstall command:": "Naredba prije de-instalacije:", + "Post-uninstall command:": "Naredba nakon de-instalacije:", + "Abort uninstall if pre-uninstall command fails": "Prekini de-instalaciju ukoliko je prilikom de-instalacijske naredbe došlo do greške", + "Command-line to run:": "Naredbeni redak za pokretanje:", + "Save and close": "Spremi i zatvori", + "General": "Općenito", + "Architecture & Location": "Arhitektura i lokacija", + "Command-line": "Naredbeni redak", + "Close apps": "Zatvori aplikacije", + "Pre/Post install": "Prije/Nakon instalacije", + "Select the processes that should be closed before this package is installed, updated or uninstalled.": "Odaberite procese koji bi trebali biti zatvoreni prije instalacije, ažuriranja ili de-instalacije ovog paketa.", + "Write here the process names here, separated by commas (,)": "Ovdje napišite nazive procesa, odvojene zarezima (,)", + "Try to kill the processes that refuse to close when requested to": "Pokušajte ubiti procese koji odbijaju zatvaranje kada se to zatraži", + "Run as admin": "Pokreni kao administrator", + "Interactive installation": "Interaktivna instalacija", + "Skip hash check": "Preskoči provjeru hasha", + "Uninstall previous versions when updated": "Deinstalirajte prethodne verzije nakon ažuriranja", + "Skip minor updates for this package": "Preskoči manja ažuriranja za ovaj paket", + "Automatically update this package": "Automatski ažuriraj ovaj paket", + "{0} installation options": "opcije instalacije {0}", + "Latest": "Najnovije", + "PreRelease": "Pred-izdanje", + "Default": "Zadano", + "Manage ignored updates": "Upravljanje zanemarenim ažuriranjima", + "The packages listed here won't be taken in account when checking for updates. Double-click them or click the button on their right to stop ignoring their updates.": "Ovdje navedeni paketi neće biti uzeti u obzir prilikom provjere ažuriranja. Dvaput kliknite na njih ili kliknite gumb s njihove desne strane da prestanete ignorirati njihova ažuriranja.", + "Reset list": "Resetiraj popis", + "Do you really want to reset the ignored updates list? This action cannot be reverted": "Želite li zaista resetirati popis zanemarenih ažuriranja? Ova se radnja ne može poništiti", + "No ignored updates": "Nema zanemarenih ažuriranja", + "Package Name": "Naziv paketa", + "Package ID": "ID paketa", + "Ignored version": "Zanemarena verzija", + "New version": "Nova verzija", + "Source": "Izvor", + "All versions": "Sve verzije", + "Unknown": "Nepoznato", + "Up to date": "Ažurno", + "Package {name} from {manager}": "Paket {name} iz {manager}", + "Remove {0} from ignored updates": "Ukloni {0} iz ignoriranih ažuriranja", + "Cancel": "Odustani", + "Administrator privileges": "Administratorske ovlasti", + "This operation is running with administrator privileges.": "Ova se operacija izvodi s administratorskim ovlastima.", + "Interactive operation": "Interaktivni rad", + "This operation is running interactively.": "Ova operacija se izvodi interaktivno.", + "You will likely need to interact with the installer.": "Vjerojatno ćete morati imati interakciju s instalacijskim programom. ", + "Integrity checks skipped": "Provjere integriteta preskočene", + "Integrity checks will not be performed during this operation.": "Provjere integriteta neće se izvršavati tijekom ove operacije.", + "Proceed at your own risk.": "Nastavite na vlastitu odgovornost.", + "Close": "Zatvori", + "Loading...": "Učitavanje...", + "Installer SHA256": "Instalacijski program SHA256", + "Homepage": "Početna stranica", + "Author": "Autor", + "Publisher": "Izdavač", + "License": "Licenca", + "Manifest": "Manifest", + "Installer Type": "Vrsta instalacijskog programa", + "Size": "Veličina", + "Installer URL": "URL instalacijskog programa", + "Last updated:": "Zadnje ažuriranje:", + "Release notes URL": "URL napomena o izdanju", + "Package details": "Detalji paketa", + "Dependencies:": "Zavisnosti:", + "Release notes": "Napomene o izdanju", + "Screenshots": "Snimke zaslona", + "This package has no screenshots or is missing the icon? Contribute to UniGetUI by adding the missing icons and screenshots to our open, public database.": "Ovaj paket nema snimki zaslona ili mu nedostaje ikona? Doprinesite UniGetUI-ju dodavanjem ikona i snimki zaslona koje nedostaju u našu otvorenu, javnu bazu podataka.", + "Version": "Verzija", + "Install as administrator": "Instalirajte kao administrator", + "Update to version {0}": "Ažurirajte na verziju {0}", + "Installed Version": "Instalirana verzija", + "Update as administrator": "Ažurirajte kao administrator", + "Interactive update": "Interaktivno ažuriranje", + "Uninstall as administrator": "Deinstaliraj kao administrator", + "Interactive uninstall": "Interaktivna de-instalacija", + "Uninstall and remove data": "Deinstalirajte i uklonite podatke", + "Not available": "Nedostupno", + "Installer SHA512": "Instalacijski program SHA512", + "Unknown size": "Nepoznata veličina", + "No dependencies specified": "Nema navedenih zavisnosti", + "mandatory": "obavezno", + "optional": "opcija", + "UniGetUI {0} is ready to be installed.": "UniGetUI {0} je spreman za instalaciju.", + "The update process will start after closing UniGetUI": "Proces ažuriranja započet će nakon zatvaranja UniGetUI-ja", + "UniGetUI has been ran as administrator, which is not recommended. When running UniGetUI as administrator, EVERY operation launched from UniGetUI will have administrator privileges. You can still use the program, but we highly recommend not running UniGetUI with administrator privileges.": "UniGetUI je pokrenut kao administrator, što se ne preporučuje. Kada UniGetUI pokrećete kao administrator, SVAKA operacija pokrenuta iz UniGetUI-ja imat će administratorske ovlasti. Program i dalje možete koristiti, ali snažno preporučujemo da UniGetUI ne pokrećete s administratorskim ovlastima.", + "Share anonymous usage data": "Dijelite anonimne podatke o korištenju", + "UniGetUI collects anonymous usage data in order to improve the user experience.": "UniGetUI prikuplja anonimne podatke o korištenju kako bi poboljšao korisničko iskustvo.", + "Accept": "Prihvati", + "Software Updates": "Ažuriranja softvera", + "Package Bundles": "Skupovi paketa", + "Settings": "Postavke", + "Package Managers": "Upravitelji paketa", + "UniGetUI Log": "UniGetUI zapisnik", + "Package Manager logs": "Dnevnici upravitelja paketa", + "Operation history": "Povijest operacija", + "Help": "Pomoć", + "UniGetUI": "UniGetUI", + "You have installed UniGetUI Version {0}": "Instalirali ste UniGetUI verziju {0}", + "Disclaimer": "Izjava o odgovornosti", + "UniGetUI is developed by Devolutions and is not affiliated with any of the compatible package managers.": "UniGetUI razvija Devolutions i nije povezan ni s jednim od kompatibilnih upravitelja paketa.", + "UniGetUI wouldn't have been possible without the help of the contributors. Thank you all 🥳": "UniGetUI ne bi bio moguć bez pomoći suradnika. Hvala svima 🥳", + "UniGetUI uses the following libraries. Without them, UniGetUI wouldn't have been possible.": "UniGetUI koristi sljedeće biblioteke. Bez njih, UniGetUI ne bi bio moguć.", + "{0} homepage": "{0} početna stranica", + "UniGetUI has been translated to more than 40 languages thanks to the volunteer translators. Thank you 🤝": "UniGetUI je preveden na više od 40 jezika zahvaljujući volonterima prevoditeljima. Hvala vam 🤝", + "Verbose": "Opširno", + "1 - Errors": "1 - Greške", + "2 - Warnings": "2 - Upozorenja", + "3 - Information (less)": "3 - Informacije (manje)", + "4 - Information (more)": "4 - Informacije (više)", + "5 - information (debug)": "5 - Informacije (debugiranje)", + "Warning": "Upozorenje", + "The following settings may pose a security risk, hence they are disabled by default.": "Sljedeće postavke mogu predstavljati sigurnosni rizik, stoga su prema zadanim postavkama onemogućene.", + "Enable the settings below if and only if you fully understand what they do, and the implications they may have.": "Omogućite postavke ispod AKO I SAMO AKO u potpunosti razumijete što rade, te posljedice i opasnosti koje mogu uključivati.", + "The settings will list, in their descriptions, the potential security issues they may have.": "U opisima postavki navedeni su potencijalni sigurnosni problemi koje mogu imati.", + "The backup will include the complete list of the installed packages and their installation options. Ignored updates and skipped versions will also be saved.": "Sigurnosna kopija će uključivati potpuni popis instaliranih paketa i njihovih opcija instalacije. Ignorirana ažuriranja i preskočene verzije također će biti spremljene.", + "The backup will NOT include any binary file nor any program's saved data.": "Sigurnosna kopija NEĆE sadržavati binarne datoteke niti spremljene podatke programa.", + "The size of the backup is estimated to be less than 1MB.": "Procjenjuje se da je veličina sigurnosne kopije manja od 1 MB.", + "The backup will be performed after login.": "Sigurnosna kopija će se izvršiti nakon prijave.", + "{pcName} installed packages": "{pcName} instalirani paketi", + "Current status: Not logged in": "Trenutni status: Niste prijavljeni", + "You are logged in as {0} (@{1})": "Prijavljeni ste kao {0} (@{1})", + "Nice! Backups will be uploaded to a private gist on your account": "Odlično! Sigurnosne kopije bit će prenesene u privatni gist na vašem računu.", + "Select backup": "Odaberi sigurnosnu kopiju", + "Settings imported from {0}": "Postavke uvezene iz {0}", + "UniGetUI Settings": "Postavke UniGetUI-ja", + "Settings exported to {0}": "Postavke izvezene u {0}", + "UniGetUI settings were reset": "Postavke UniGetUI-ja su resetirane", + "Allow pre-release versions": "Dozvoli verzije pred-izdanja", + "Apply": "Primjeni", + "For security reasons, custom command-line arguments are disabled by default. Go to UniGetUI security settings to change this.": "Iz sigurnosnih razloga prilagođeni argumenti naredbenog retka prema zadanim su postavkama onemogućeni. Idite u sigurnosne postavke UniGetUI-ja da biste to promijenili.", + "Go to UniGetUI security settings": "Idite na sigurnosne postavke UniGetUI-ja", + "The following options will be applied by default each time a {0} package is installed, upgraded or uninstalled.": "Sljedeće opcije će se primjenjivati prema zadanim postavkama svaki put kada se {0} paket instalira, nadogradi ili deinstalira.", + "Package's default": "Zadane postavke paketa", + "Install location can't be changed for {0} packages": "Lokacija instalacije ne može se promijeniti za pakete {0}", + "The local icon cache currently takes {0} MB": "Lokalna pred memorija ikona trenutno zauzima {0} MB", + "Username": "Korisničko ime", + "Password": "Lozinka", + "Credentials": "Vjerodajnice", + "It is not guaranteed that the provided credentials will be stored safely": "Nije zajamčeno da će navedene vjerodajnice biti pohranjene na siguran način", + "Partially": "Djelomično", + "Package manager": "Upravitelj paketima", + "Compatible with proxy": "Kompatibilan s proxy-jem", + "Compatible with authentication": "Kompatibilno s autentifikacijom", + "Proxy compatibility table": "Tablica kompatibilnosti proxyja", + "{0} settings": "{0} postavki", + "{0} status": "status {0}", + "Default installation options for {0} packages": "Zadane mogućnosti instalacije za pakete {0}", + "Expand version": "Proširi verziju", + "The executable file for {0} was not found": "Izvršna datoteka za {0} nije pronađena", + "{pm} is disabled": "{pm} je onemogućen", + "Enable it to install packages from {pm}.": "Omogućite instaliranje paketa iz {pm}", + "{pm} is enabled and ready to go": "{pm} je omogućen i spreman za ići", + "{pm} version:": "{pm} verzija:", + "{pm} was not found!": "{pm} nije pronađen!", + "You may need to install {pm} in order to use it with UniGetUI.": "Možda ćete morati instalirati {pm} kako biste ga mogli koristiti s UniGetUI-jem.", + "Scoop Installer - UniGetUI": "Instalacijski program Scoop - UniGetUI", + "Scoop Uninstaller - UniGetUI": "Program za de-instalaciju Scoop-a - UniGetUI", + "Clearing Scoop cache - UniGetUI": "Brisanje Scoop pred-memorije - UniGetUI", + "Restart UniGetUI to fully apply changes": "Ponovno pokrenite UniGetUI da biste u potpunosti primijenili promjene", + "Restart UniGetUI": "Ponovno pokrenite UniGetUI", + "Manage {0} sources": "Upravljanje {0} izvorima", + "Add source": "Dodaj izvor", + "Add": "Dodaj", + "Source name": "Naziv izvora", + "Source URL": "URL izvora", + "Other": "Ostalo", + "No minimum age": "Bez minimalne starosti", + "1 day": "1 dan", + "{0} days": "{0} dana", + "Custom...": "Prilagođeno...", + "{0} minutes": "{0} minuta", + "1 hour": "1 sat", + "{0} hours": "{0} sati", + "1 week": "1 tjedan", + "Supports release dates": "Podržava datume izdanja", + "Release date support per package manager": "Podrška za datume izdanja po upravitelju paketa", + "Search for packages": "Traži pakete", + "Local": "Lokalno", + "OK": "U redu", + "Last checked: {0}": "Posljednja provjera: {0}", + "{0} packages were found, {1} of which match the specified filters.": "Pronađeno je {0} paketa, {1} koji odgovara navedenim filterima.", + "{0} selected": "{0} odabrano", + "(Last checked: {0})": "(Posljednja provjera: {0})", + "All packages selected": "Svi paketi odabrani", + "Package selection cleared": "Odabir paketa poništen", + "{0}: {1}": "{0}: {1}", + "More info": "Više informacija", + "GitHub account": "GitHub račun", + "Log in with GitHub to enable cloud package backup.": "Prijavite se putem GitHub-a kako biste omogućili sigurnosnu kopiju paketa u oblaku.", + "More details": "Više detalja", + "Log in": "Prijava", + "If you have cloud backup enabled, it will be saved as a GitHub Gist on this account": "Ako imate omogućenu sigurnosnu kopiju u oblaku, bit će spremljena kao GitHub Gist datoteka na ovom računu.", + "Log out": "Odjava", + "About UniGetUI": "O UniGetUI-ju", + "About": "O aplikaciji", + "Third-party licenses": "Licence trećih strana", + "Contributors": "Suradnici", + "Translators": "Prevoditelji", + "Bundle security report": "Sigurnosno izvješće skupa paketa", + "The bundle contained restricted content": "Skup paketa sadržavao je ograničeni sadržaj", + "UniGetUI – Crash Report": "UniGetUI – Izvješće o padu", + "UniGetUI has crashed": "UniGetUI se srušio", + "Help us fix this by sending a crash report to Devolutions. All fields below are optional.": "Pomozite nam popraviti ovo slanjem izvješća o padu na Devolutions. Sva polja u nastavku su neobavezna.", + "Email (optional)": "E-pošta (neobavezno)", + "your@email.com": "vašeime@email.com", + "Additional details (optional)": "Dodatni detalji (neobavezno)", + "Describe what you were doing when the crash occurred…": "Opišite što ste radili kada se pad dogodio…", + "Crash report": "Izvješće o padu", + "Don't Send": "Nemoj poslati", + "Send Report": "Pošalji izvješće", + "Sending…": "Slanje…", + "Unsaved changes": "Nespremljene promjene", + "You have unsaved changes in the current bundle. Do you want to discard them?": "Imate nespremljene promjene u trenutačnom skupu paketa. Želite li ih odbaciti?", + "Discard changes": "Odbaci promjene", + "Integrity violation": "Povreda integriteta", + "UniGetUI or some of its components are missing or corrupt. It is strongly recommended to reinstall UniGetUI to adress the situation.": "UniGetUI ili neke njegove komponente nedostaju ili su oštećene. Preporučuje se ponovna instalacija UniGetUI-ja kako bi se riješila situacija.", + "• Refer to the UniGetUI Logs to get more details regarding the affected file(s)": "• Za više detalja o pogođenim datotekama pogledajte UniGetUI zapisnike.", + "• Integrity checks can be disabled from the Experimental Settings": "• Provjere integriteta mogu se onemogućiti u eksperimentalnim postavkama", + "Manage shortcuts": "Upravljanje prečicama", + "UniGetUI has detected the following desktop shortcuts which can be removed automatically on future upgrades": "UniGetUI je otkrio sljedeće prečace na radnoj površini koji se mogu automatski ukloniti prilikom budućih nadogradnji", + "Do you really want to reset this list? This action cannot be reverted.": "Želite li zaista resetirati ovaj popis? Ova se radnja ne može poništiti.", + "Desktop shortcuts list": "Popis prečaca na radnoj površini", + "Open in explorer": "Otvori u Exploreru", + "Remove from list": "Ukloni s popisa", + "When new shortcuts are detected, delete them automatically instead of showing this dialog.": "Kada se otkriju novi prečaci, automatski ih izbriši umjesto prikazivanja ovog dijaloga.", + "Not right now": "Ne sada", + "Missing dependency": "Nedostajuća zavisnost", + "UniGetUI requires {0} to operate, but it was not found on your system.": "UniGetUI zahtijeva {0} za rad, ali nije pronađen na vašem sustavu.", + "Click on Install to begin the installation process. If you skip the installation, UniGetUI may not work as expected.": "Kliknite na Instaliraj za početak postupka instalacije. Ako preskočite instalaciju, UniGetUI možda neće raditi kako je očekivano", + "Alternatively, you can also install {0} by running the following command in a Windows PowerShell prompt:": "Alternativno, {0} možete instalirati i pokretanjem sljedeće naredbe u Windows PowerShell:", + "Install {0}": "Instaliraj {0}", + "Do not show this dialog again for {0}": "Ne prikazuj ovaj dijalog ponovno za {0}", + "Please wait while {0} is being installed. A black window may show up. Please wait until it closes.": "Molim pričekajte dok se {0} instalira. Može se pojaviti crni (ili plavi) prozor. Pričekajte da se zatvori.", + "{0} has been installed successfully.": "{0} je uspješno instaliran.", + "Please click on \"Continue\" to continue": "Molimo kliknite na \"Nastavi\" za nastavak", + "Continue": "Nastavi", + "{0} has been installed successfully. It is recommended to restart UniGetUI to finish the installation": "{0} je uspješno instaliran. Preporučuje se ponovno pokretanje UniGetUI-ja kako bi se instalacija dovršila.", + "Restart later": "Ponovno pokretanje kasnije", + "An error occurred:": "Došlo je do pogreške:", + "Please see the Command-line Output or refer to the Operation History for further information about the issue.": "Za više informacija o problemu pogledajte izlaz naredbenog retka ili pogledajte povijest operacija.", + "Retry as administrator": "Pokušajte ponovno kao administrator", + "Retry interactively": "Pokušaj ponovno interaktivno", + "Retry skipping integrity checks": "Pokušaj ponovno uz preskakanje provjera integriteta", + "Installation options": "Mogućnosti instalacije", + "Save": "Spremi", + "UniGetUI collects anonymous usage data with the sole purpose of understanding and improving the user experience.": "UniGetUI prikuplja anonimne podatke o korištenju s jedinom svrhom razumijevanja i poboljšanja korisničkog iskustva.", + "More details about the shared data and how it will be processed": "Više detalja o dijeljenim podacima i načinu njihove obrade", + "Do you accept that UniGetUI collects and sends anonymous usage statistics, with the sole purpose of understanding and improving the user experience?": "Prihvaćate li da UniGetUI prikuplja i šalje anonimne statistike korištenja, s jedinom svrhom razumijevanja i poboljšanja korisničkog iskustva?", + "Decline": "Odbij", + "No personal information is collected nor sent, and the collected data is anonimized, so it can't be back-tracked to you.": "Ne prikupljaju se niti se šalju osobni podaci, a prikupljeni podaci su anonimizirani, tako da se ne mogu koristiti da vas se identificira.", + "Navigation panel": "Navigacijska ploča", + "Operations": "Operacije", + "Toggle operations panel": "Prikaži/sakrij ploču operacija", + "Bulk operations": "Skupne operacije", + "Retry failed": "Ponovi neuspjele", + "Clear successful": "Očisti uspješne", + "Clear finished": "Očisti dovršene", + "Cancel all": "Otkaži sve", + "More": "Više", + "Toggle navigation panel": "Prikaži/sakrij navigacijsku ploču", + "Minimize": "Minimiziraj", + "Maximize": "Maksimiziraj", + "UniGetUI by Devolutions": "UniGetUI tvrtke Devolutions", + "UniGetUI is an application that makes managing your software easier, by providing an all-in-one graphical interface for your command-line package managers.": "UniGetUI je aplikacija koja olakšava upravljanje vašim softverom pružajući sveobuhvatno grafičko sučelje za vaše upravitelje paketa iz naredbenog retka.", + "Useful links": "Korisni linkovi", + "UniGetUI Homepage": "Početna stranica UniGetUI-ja", + "Report an issue or submit a feature request": "Prijavi problem ili pošalji zahtjev za značajku", + "UniGetUI Repository": "Repozitorij UniGetUI-ja", + "View GitHub Profile": "Pogledajte profil na GitHub-u", + "UniGetUI License": "UniGetUI licenca", + "Using UniGetUI implies the acceptation of the MIT License": "Korištenjem UniGetUI-ja podrazumijevate prihvaćanje MIT licence", + "Become a translator": "Postanite prevodilac", + "Go back": "Idi natrag", + "Go forward": "Idi naprijed", + "Go to home page": "Idi na početnu stranicu", + "Reload page": "Ponovno učitaj stranicu", + "View page on browser": "Pogledajte stranicu u pregledniku", + "The built-in browser is not supported on Linux yet.": "Ugrađeni preglednik još nije podržan na Linuxu.", + "Open in browser": "Otvori u pregledniku", + "Copy to clipboard": "Kopirati u međuspremnik", + "Export to a file": "Izvoz u datoteku", + "Log level:": "Razina zapisnika:", + "Reload log": "Ponovno učitaj dnevnik", + "Export log": "Izvezi zapisnik", + "Text": "Tekst", + "Change how operations request administrator rights": "Promjena načina na koji operacije zahtijevaju administratorska prava", + "Restrictions on package operations": "Ograničenja paketnih operacija", + "Restrictions on package managers": "Ograničenja za upravitelje paketa", + "Restrictions when importing package bundles": "Ograničenja pri uvozu skupova paketa", + "Ask for administrator privileges once for each batch of operations": "Zatražite administratorske ovlasti jednom za svaku grupu operacija", + "Ask only once for administrator privileges": "Samo jednom pitaj za administratorske privilegije", + "Prohibit any kind of Elevation via UniGetUI Elevator or GSudo": "Zabrani bilo kakvu vrstu elevacije putem UniGetUI Elevatora ili GSudo-a", + "This option WILL cause issues. Any operation incapable of elevating itself WILL FAIL. Install/update/uninstall as administrator will NOT WORK.": "Ova opcija ĆE uzrokovati probleme. Bilo koja operacija koja ne može sama sebe podići NEĆE USPJETI. Instaliranje/ažuriranje/deinstaliranje kao administrator NEĆE RADITI.", + "Allow custom command-line arguments": "Dozvoli prilagođene argumente naredbenog retka", + "Custom command-line arguments can change the way in which programs are installed, upgraded or uninstalled, in a way UniGetUI cannot control. Using custom command-lines can break packages. Proceed with caution.": "Prilagođeni argumenti naredbenog retka mogu promijeniti način na koji se programi instaliraju, nadograđuju ili deinstaliraju na način koji UniGetUI ne može kontrolirati. Korištenje prilagođenih naredbenih redaka može oštetiti pakete. Nastavite s oprezom.", + "Ignore custom pre-install and post-install commands when importing packages from a bundle": "Zanemari prilagođene naredbe prije i poslije instalacije pri uvozu paketa iz skupa", + "Pre and post install commands will be run before and after a package gets installed, upgraded or uninstalled. Be aware that they may break things unless used carefully": "Naredbe prije i poslije instalacije izvršavat će se prije i nakon instalacije, nadogradnje ili de-instalacije paketa. Imajte na umu da mogu uzrokovati probleme ako se ne koriste pažljivo", + "Allow changing the paths for package manager executables": "Dozvoli promjenu putanja za izvršne datoteke upravitelja paketa", + "Turning this on enables changing the executable file used to interact with package managers. While this allows finer-grained customization of your install processes, it may also be dangerous": "Uključivanjem ove opcije omogućuje se promjena izvršne datoteke koja se koristi za interakciju s upraviteljima paketa. Iako to omogućuje preciznije prilagođavanje vaših instalacijskih procesa, može biti i opasno.", + "Allow importing custom command-line arguments when importing packages from a bundle": "Dopusti uvoz prilagođenih argumenata naredbenog retka prilikom uvoza paketa iz skupova paketa", + "Malformed command-line arguments can break packages, or even allow a malicious actor to gain privileged execution. Therefore, importing custom command-line arguments is disabled by default": "Neispravno oblikovani argumenti naredbenog retka mogu oštetiti pakete ili čak omogućiti zlonamjernom akteru da dobije privilegirano izvršavanje. Stoga je uvoz prilagođenih argumenata naredbenog retka onemogućen prema zadanim postavkama", + "Allow importing custom pre-install and post-install commands when importing packages from a bundle": "Dozvoli uvoz prilagođenih argumenata naredbenog retka prilikom uvoza paketa iz skupa paketa", + "Pre and post install commands can do very nasty things to your device, if designed to do so. It can be very dangerous to import the commands from a bundle, unless you trust the source of that package bundle": "Naredbe prije i poslije instalacije mogu učiniti vrlo loše stvari vašem uređaju, ako su za to dizajnirane. Uvoz naredbi iz paketa može biti vrlo opasan, osim ako ne vjerujete izvoru tog paketa.", + "Administrator rights and other dangerous settings": "Administratorska prava i ostale opasne postavke", + "Package backup": "Sigurnosna kopija paketa", + "Cloud package backup": "Sigurnosna kopija paketa u oblak", + "Local package backup": "Sigurnosna kopija lokalnog paketa", + "Local backup advanced options": "Napredne opcije lokalnog sigurnosnog kopiranja", + "Log in with GitHub": "Prijava pomoću GitHub-a", + "Log out from GitHub": "Odjava s GitHub-a", + "Periodically perform a cloud backup of the installed packages": "Povremeno napravite sigurnosnu kopiju instaliranih paketa u oblaku ", + "Cloud backup uses a private GitHub Gist to store a list of installed packages": "Sigurnosna kopija u oblak koristi privatni GitHub Gist za pohranu popisa instaliranih paketa", + "Perform a cloud backup now": "Napravite sigurnosnu kopiju u oblaku odmah", + "Backup": "Sigurnosno kopiranje", + "Restore a backup from the cloud": "Vratite sigurnosnu kopiju iz oblaka", + "Begin the process to select a cloud backup and review which packages to restore": "Započnite postupak odabira sigurnosne kopije u oblaku i pregledajte koje pakete treba vratit", + "Periodically perform a local backup of the installed packages": "Povremeno napravite lokalnu sigurnosnu kopiju instaliranih paketa", + "Perform a local backup now": "Napravite lokalnu sigurnosnu kopiju odmah", + "Change backup output directory": "Promijenite putanju mape za sigurnosne kopije", + "Set a custom backup file name": "Postavite prilagođeni naziv datoteke sigurnosne kopije", + "Leave empty for default": "Ostavite prazno za zadane vrijednosti", + "Add a timestamp to the backup file names": "Dodajte vremensku oznaku nazivima datoteka sigurnosnih kopija", + "Backup and Restore": "Sigurnosno kopiranje i oporavak", + "Enable background api (UniGetUI Widgets and Sharing, port 7058)": "Omogući API u pozadini (Widgeti za UniGetUI i dijeljenje, port 7058)", + "Wait for the device to be connected to the internet before attempting to do tasks that require internet connectivity.": "Pričekajte da se uređaj poveže s internetom prije nego što pokušate izvršiti zadatke koji zahtijevaju internetsku vezu.", + "Disable the 1-minute timeout for package-related operations": "Onemogućite vremensko ograničenje od 1 minute za operacije povezane s paketima", + "Use installed GSudo instead of UniGetUI Elevator": "Koristite instalirani GSudo umjesto UniGetUI Elevatora", + "Use a custom icon and screenshot database URL": "Koristite prilagođenu ikonu i URL baze podataka snimaka zaslona", + "Enable background CPU Usage optimizations (see Pull Request #3278)": "Omogući optimizacije korištenja CPU-a u pozadini (vidi Pull Request #3278)", + "Perform integrity checks at startup": "Izvršite provjere integriteta pri pokretanju", + "When batch installing packages from a bundle, install also packages that are already installed": "Prilikom grupne instalacije paketa iz skupa paketa, instalirajte i pakete koji su već instalirani", + "Experimental settings and developer options": "Eksperimentalne postavke i mogućnosti za programere", + "Show UniGetUI's version and build number on the titlebar.": "Prikaži verziju UniGetUI-ja na naslovnoj traci", + "Language": "Jezik", + "UniGetUI updater": "UniGetUI ažurirač", + "Telemetry": "Telemetrija", + "Manage UniGetUI settings": "Upravljanje postavkama UniGetUI-ja", + "Related settings": "Povezane postavke", + "Update UniGetUI automatically": "Ažurirajte UniGetUI automatski", + "Check for updates": "Provjeri dostupnost ažuriranja", + "Install prerelease versions of UniGetUI": "Instalirajte pred-izdane verzije UniGetUI-ja", + "Manage telemetry settings": "Upravljanje postavkama telemetrije", + "Manage": "Upravljaj", + "Import settings from a local file": "Uvezi postavke iz lokalne datoteke", + "Import": "Uvoz", + "Export settings to a local file": "Izvezi postavke u lokalnu datoteku", + "Export": "Izvoz", + "Reset UniGetUI": "Resetiraj UniGetUI", + "User interface preferences": "Postavke korisničkog sučelja", + "Application theme, startup page, package icons, clear successful installs automatically": "Tema aplikacije, početna stranica, ikone paketa, automatsko brisanje uspješnih instalacija", + "General preferences": "Opće postavke", + "UniGetUI display language:": "UniGetUI jezik prikaza:", + "System language": "Jezik sustava", + "Is your language missing or incomplete?": "Nedostaje li vaš jezik ili je nepotpun?", + "Appearance": "Izgled", + "UniGetUI on the background and system tray": "UniGetUI na pozadini i u sistemskoj traci", + "Package lists": "Popis paketa", + "Use classic mode": "Koristi klasični način rada", + "Restart UniGetUI to apply this change": "Ponovno pokrenite UniGetUI kako biste primijenili ovu promjenu", + "The classic UI is disabled for beta testers": "Klasično korisničko sučelje onemogućeno je za beta testere", + "Close UniGetUI to the system tray": "Zatvorite UniGetUI u sistemsku traku", + "Manage UniGetUI autostart behaviour": "Upravljanje ponašanjem automatskog pokretanja UniGetUI-ja", + "Show package icons on package lists": "Prikaži ikone paketa na popisima paketa", + "Clear cache": "Očisti predmemoriju", + "Select upgradable packages by default": "Odaberite nadogradive pakete kao zadane postavke", + "Light": "Svjetlo", + "Dark": "Tamno", + "Follow system color scheme": "Slijedite shemu boja sustava", + "Application theme:": "Tema aplikacije:", + "UniGetUI startup page:": "Početna stranica UniGetUI-ja:", + "Proxy settings": "Postavke proxy-a", + "Other settings": "Ostale postavke", + "Connect the internet using a custom proxy": "Spojite se na internet pomoću prilagođenog proxy-ja", + "Please note that not all package managers may fully support this feature": "Imajte na umu da ne podržavaju svi upravitelji paketa u potpunosti ovu značajku", + "Proxy URL": "URL proxy poslužitelja", + "Enter proxy URL here": "Ovdje unesite proxy URL", + "Authenticate to the proxy with a user and a password": "Autentificiraj se na proxy pomoću korisničkog imena i lozinke", + "Internet and proxy settings": "Postavke interneta i proxyja", + "Package manager preferences": "Postavke upravitelja paketa", + "Ready": "Spremno", + "Not found": "Nije pronađeno", + "Notification preferences": "Postavke obavijesti", + "Notification types": "Vrste obavijesti", + "The system tray icon must be enabled in order for notifications to work": "Ikona u programskoj traci mora biti omogućena da bi obavijesti radile", + "Enable UniGetUI notifications": "Omogući UniGetUI obavijesti", + "Show a notification when there are available updates": "Prikaži obavijest kada postoje dostupna ažuriranja", + "Show a silent notification when an operation is running": "Prikaži tihu obavijest kada je operacija u tijeku", + "Show a notification when an operation fails": "Prikaži obavijest kada operacija ne uspije", + "Show a notification when an operation finishes successfully": "Prikaži obavijest kada operacija uspješno završi", + "Concurrency and execution": "Podudarnost i izvođenje", + "Automatic desktop shortcut remover": "Automatsko uklanjanje prečica s radne površine", + "Choose how many operations should be performed in parallel": "Odaberite koliko se operacija treba izvoditi paralelno", + "Clear successful operations from the operation list after a 5 second delay": "Obriši uspješne operacije s popisa operacija nakon 5 sekundi odgode", + "Download operations are not affected by this setting": "Ova postavka ne utječe na operacije preuzimanja", + "You may lose unsaved data": "Možete izgubiti ne spremljene podatke", + "Ask to delete desktop shortcuts created during an install or upgrade.": "Pitaj za brisanje prečaca na radnoj površini stvorenih tijekom instalacije ili nadogradnje.", + "Package update preferences": "Postavke ažuriranja paketa", + "Update check frequency, automatically install updates, etc.": "Učestalost provjere ažuriranja, automatsko instaliranje ažuriranja itd.", + "Reduce UAC prompts, elevate installations by default, unlock certain dangerous features, etc.": "Smanjite UAC upite, podignite instalacije prema zadanim postavkama, otključajte određene opasne značajke itd.", + "Package operation preferences": "Postavke rada paketa", + "Enable {pm}": "Omogući {pm}", + "Not finding the file you are looking for? Make sure it has been added to path.": "Ne možete pronaći datoteku koju tražite? Provjerite je li dodana u putanju.", + "Select the executable to be used. The following list shows the executables found by UniGetUI": "Odaberite program koji želite koristiti. Sljedeći popis prikazuje programe koje je pronašao UniGetUI", + "For security reasons, changing the executable file is disabled by default": "Iz sigurnosnih razloga, promjena izvršne datoteke je prema zadanim postavkama onemogućena", + "Change this": "Promijeni ovo", + "Copy path": "Kopiraj putanju", + "Current executable file:": "Trenutna izvršna datoteka:", + "Ignore packages from {pm} when showing a notification about updates": "Zanemari pakete iz {pm} prilikom prikazivanja obavijesti o ažuriranjima", + "Update security": "Sigurnost ažuriranja", + "Use global setting": "Koristi globalnu postavku", + "Minimum age for updates": "Minimalna starost ažuriranja", + "e.g. 10": "npr. 10", + "Custom minimum age (days)": "Prilagođena minimalna starost (dani)", + "{pm} does not provide release dates for its packages, so this setting will have no effect": "{pm} ne pruža datume izdanja za svoje pakete pa ova postavka neće imati učinka", + "{pm} only provides release dates for some of its packages, so this setting will only apply to those packages": "{pm} pruža datume izdanja samo za neke od svojih paketa, pa će se ova postavka primijeniti samo na te pakete", + "Override the global minimum update age for this package manager": "Zamijeni globalnu minimalnu starost ažuriranja za ovog upravitelja paketa", + "View {0} logs": "Pregledaj {0} zapisnike", + "If Python cannot be found or is not listing packages but is installed on the system, ": "Ako Python nije moguće pronaći ili ne prikazuje pakete, ali je instaliran na sustavu, ", + "Advanced options": "Napredne opcije", + "WinGet command-line tool": "WinGet alat naredbenog retka", + "Choose which command-line tool UniGetUI uses for WinGet operations when the COM API is not used": "Odaberite koji alat naredbenog retka UniGetUI koristi za WinGet operacije kada se ne koristi COM API", + "WinGet COM API": "WinGet COM API", + "Choose whether UniGetUI can use the WinGet COM API before falling back to the command-line tool": "Odaberite može li UniGetUI koristiti WinGet COM API prije povratka na alat naredbenog retka", + "Reset WinGet": "Resetiraj WinGet", + "This may help if no packages are listed": "Ovo može pomoći ako nisu navedeni paketi", + "Force install location parameter when updating packages with custom locations": "Prisilno koristi parametar lokacije instalacije pri ažuriranju paketa s prilagođenim lokacijama", + "Install Scoop": "Instalirajte Scoop", + "Uninstall Scoop (and its packages)": "Deinstaliraj Scoop (i njegove pakete)", + "Run cleanup and clear cache": "Pokreni čišćenje i obriši pred-memoriju", + "Run": "Pokreni", + "Enable Scoop cleanup on launch": "Omogući Scoop čišćenje pri pokretanju", + "Default vcpkg triplet": "Zadani vcpkg triplet", + "Change vcpkg root location": "Promijeni lokaciju korijenskog direktorija vcpkg-a", + "Reset vcpkg root location": "Resetiraj korijensku lokaciju vcpkg-a", + "Open vcpkg root location": "Otvori korijensku lokaciju vcpkg-a", + "Language, theme and other miscellaneous preferences": "Jezik, tema i ostale razne postavke", + "Show notifications on different events": "Prikaz obavijesti o različitim događajima", + "Change how UniGetUI checks and installs available updates for your packages": "Promijenite način na koji UniGetUI provjerava i instalira dostupna ažuriranja za vaše pakete", + "Automatically save a list of all your installed packages to easily restore them.": "Automatski spremi popis svih instaliranih paketa kako bi ih se lako vratilo.", + "Enable and disable package managers, change default install options, etc.": "Omogućite i onemogućite upravitelje paketa, promijenite zadane opcije instalacije itd.", + "Internet connection settings": "Postavke internetske veze", + "Proxy settings, etc.": "Postavke proxy-a, itd.", + "Beta features and other options that shouldn't be touched": "Beta značajke i druge opcije koje se ne smiju dirati", + "Reload sources": "Ponovno učitaj izvore", + "Delete source": "Izbriši izvor", + "Known sources": "Poznati izvori", + "Update checking": "Provjera ažuriranja", + "Automatic updates": "Automatska ažuriranja", + "Check for package updates periodically": "Povremeno provjerite ažuriranja paketa", + "Check for updates every:": "Provjerite ima li ažuriranja svakih:", + "Install available updates automatically": "Automatski instalirajte dostupna ažuriranja", + "Do not automatically install updates when the network connection is metered": "Ne instaliraj automatski ažuriranja kada je mrežna veza ograničena", + "Do not automatically install updates when the device runs on battery": "Ne instaliraj automatski ažuriranja kada uređaj radi na bateriji", + "Do not automatically install updates when the battery saver is on": "Ne instaliraj automatski ažuriranja kada je uključena ušteda baterije", + "Only show updates that are at least the specified number of days old": "Prikaži samo ažuriranja koja su stara najmanje navedeni broj dana", + "Warn me when the installer URL host changes between the installed version and the new version (WinGet only)": "Upozori me kada se host URL-a instalacijskog programa promijeni između instalirane i nove verzije (samo WinGet)", + "Change how UniGetUI handles install, update and uninstall operations.": "Promijenite način na koji UniGetUI odrađuje operacije instalacije, ažuriranja te de-instalacije", + "Navigation": "Navigacija", + "Check for UniGetUI updates": "Provjeri ažuriranja za UniGetUI", + "Quit UniGetUI": "Izađi iz UniGetUI-ja", + "Filters": "Filteri", + "Sources": "Izvori", + "Search for packages to start": "Za početak, pretražite pakete", + "Select all": "Odaberi sve", + "Clear selection": "Očisti odabir", + "Instant search": "Instant pretraga", + "Distinguish between uppercase and lowercase": "Razlikuj velika i mala slova", + "Ignore special characters": "Zanemari posebne znakove", + "Search mode": "Način traženja", + "Both": "Oboje", + "Exact match": "Točno podudaranje", + "Show similar packages": "Prikaži slične paketa", + "Loading": "Učitavanje", + "Package": "Paket", + "More options": "Više opcija", + "Order by:": "Poredaj po:", + "Name": "Naziv", + "Id": "ID", + "Ascendant": "Uzlazno", + "Descendant": "Silazno", + "View modes": "Načini prikaza", + "Reload": "Ponovno učitaj", + "Closed": "Zatvoreno", + "Ascending": "Uzlazno", + "Descending": "Silazno", + "{0}: {1}, {2}": "{0}: {1}, {2}", + "Order by": "Sortiraj po", + "No results were found matching the input criteria": "Nisu pronađeni rezultati koji odgovaraju ulaznim kriterijima", + "No packages were found": "Paketi nisu pronađeni", + "Loading packages": "Učitavanje paketa", + "Skip integrity checks": "Preskoči provjere integriteta", + "Download selected installers": "Preuzmite odabrane programe za instalaciju", + "Install selection": "Instalirajte odabir", + "Install options": "Mogućnosti instalacije", + "Add selection to bundle": "Dodaj odabir u skup paketa", + "Download installer": "Preuzmite instalacijski program", + "Uninstall selection": "Odabir de-instalacije", + "Uninstall options": "Opcije de-instalacije", + "Ignore selected packages": "Ignorirajte odabrane pakete", + "Open install location": "Otvori mjesto instalacije", + "Reinstall package": "Ponovno instalirajte paket", + "Uninstall package, then reinstall it": "Deinstalirajte paket, a zatim ga ponovno instalirajte", + "Ignore updates for this package": "Ignorirajte ažuriranja za ovaj paket", + "WinGet malfunction detected": "Otkriven kvar WinGet-a", + "It looks like WinGet is not working properly. Do you want to attempt to repair WinGet?": "Djeluje da WinGet ne radi ispravno. Želite li pokušati popraviti WinGet?", + "Repair WinGet": "Popravi WinGet", + "Updates will no longer be ignored for {0}": "Ažuriranja više neće biti ignorirana za {0}", + "Updates are now ignored for {0}": "Ažuriranja su sada ignorirana za {0}", + "Do not ignore updates for this package anymore": "Ne ignorirajte više ažuriranja za ovaj paket", + "Add packages or open an existing package bundle": "Dodajte pakete ili otvorite postojeći skup paketa", + "Add packages to start": "Dodajte pakete za početak", + "The current bundle has no packages. Add some packages to get started": "Trenutni skup paketa nema paketa. Dodajte nekoliko paketa za početak.", + "New": "Novo", + "Save as": "Spremi kao", + "Create .ps1 script": "Izradi .ps1 skriptu", + "Remove selection from bundle": "Ukloni odabir iz paketa", + "Skip hash checks": "Preskoči hash provjere", + "The package bundle is not valid": "Skup paketa nije valjan", + "The bundle you are trying to load appears to be invalid. Please check the file and try again.": "Skup paketa je uspješno kreiran. Čini se da paket koji pokušavate učitati nije valjan. Provjerite datoteku i pokušajte ponovno.", + "Package bundle": "Skupovi paketa", + "Could not create bundle": "Nije moguće izraditi skupa paketa", + "The package bundle could not be created due to an error.": "Skup paketa nije moguće stvoriti zbog pogreške.", + "Install script": "Instaliraj skriptu", + "PowerShell script": "PowerShell skripta", + "The installation script saved to {0}": "Instalacijska skripta spremljena je u {0}", + "An error occurred": "Došlo je do pogreške", + "An error occurred while attempting to create an installation script:": "Došlo je do pogreške prilikom pokušaja stvaranja instalacijske skripte:", + "Hooray! No updates were found.": "Hura! Nema ažuriranja!", + "Uninstall selected packages": "Deinstaliraj odabrane pakete", + "Update selection": "Ažuriraj odabir", + "Update options": "Opcije ažuriranja", + "Uninstall package, then update it": "Deinstalirajte paket, a zatim ga ažurirajte", + "Uninstall package": "Deinstaliraj paket", + "Skip this version": "Preskoči ovu verziju", + "Pause updates for": "Pauziraj ažuriranja za", + "User | Local": "Korisnik | Lokalno", + "Machine | Global": "Računalo | Globalno", + "The default package manager for Debian/Ubuntu-based Linux distributions.
Contains: Debian/Ubuntu packages": "Zadani upravitelj paketa za distribucije Linuxa temeljene na Debian/Ubuntuu.
Sadrži: Debian/Ubuntu pakete", + "The Rust package manager.
Contains: Rust libraries and programs written in Rust": "Upravitelj paketa Rust.
Sadrži: Rust biblioteke i programe napisane u Rustu-", + "The classical package manager for windows. You'll find everything there.
Contains: General Software": "Klasični upravitelj paketa za Windows. Sve ćete tamo pronaći.
Sadrži: Opći softver", + "The default package manager for RHEL/Fedora-based Linux distributions.
Contains: RPM packages": "Zadani upravitelj paketa za distribucije Linuxa temeljene na RHEL/Fedori.
Sadrži: RPM pakete", + "A repository full of tools and executables designed with Microsoft's .NET ecosystem in mind.
Contains: .NET related tools and scripts": "Repozitorij pun alata i izvršnih programa dizajniran sa Microsoft .NET ekosustavom u ideji.
Sadrži: .NET povezane alate i skripte", + "The universal Linux package manager for desktop applications.
Contains: Flatpak applications from configured remotes": "Univerzalni upravitelj paketa za Linux aplikacije za radnu površinu.
Sadrži: Flatpak aplikacije iz konfiguriranih udaljenih izvora", + "NuPkg (zipped manifest)": "NuPkg (zipani manifest)", + "The Missing Package Manager for macOS (or Linux).
Contains: Formulae, Casks": "Paketni upravitelj koji nedostaje za macOS (ili Linux).
Sadrži: Formulae, Casks", + "Node JS's package manager. Full of libraries and other utilities that orbit the javascript world
Contains: Node javascript libraries and other related utilities": "Node JS upravitelj paketa. Pun biblioteka i drugih uslužnih programa koji kruže svijetom Javascripta
Sadrži: Javascript biblioteke i druge srodne uslužne programe", + "The default package manager for Arch Linux and its derivatives.
Contains: Arch Linux packages": "Zadani upravitelj paketa za Arch Linux i njegove derivate.
Sadrži: Arch Linux pakete", + "Python's library manager. Full of python libraries and other python-related utilities
Contains: Python libraries and related utilities": "Python upravitelj paketa. Pun python biblioteka i drugih uslužnih programa povezanih s Pythonom
Sadrži: Python biblioteke i srodnih uslužnih programa", + "PowerShell's package manager. Find libraries and scripts to expand PowerShell capabilities
Contains: Modules, Scripts, Cmdlets": "PowerShell-ov upravitelj paketa. Pronađite biblioteke i skripte za proširenje PowerShell mogućnosti.
Sadrži: Module, Skripte, Cmdlets", + "extracted": "izvučeno", + "Scoop package": "Scoop paket", + "Great repository of unknown but useful utilities and other interesting packages.
Contains: Utilities, Command-line programs, General Software (extras bucket required)": "Sjajno skladište nepoznatih, ali korisnih uslužnih programa i drugih zanimljivih paketa.
Sadrži: Uslužne programe, programe naredbenog retka, opći softver (potrebno je dodatno spremište)", + "The universal Linux package manager by Canonical.
Contains: Snap packages from the Snapcraft store": "Univerzalni upravitelj paketa za Linux od Canonicala.
Sadrži: Snap pakete iz Snapcraft trgovine", + "library": "biblioteka", + "feature": "značajka", + "A popular C/C++ library manager. Full of C/C++ libraries and other C/C++-related utilities
Contains: C/C++ libraries and related utilities": "Popularni upravitelj biblioteka za C/C++. Puni C/C++ biblioteka i drugih alata povezanih s C/C++.\nSadrži: C/C++ biblioteke i povezane alate.", + "option": "opcija", + "This package cannot be installed from an elevated context.": "Ovaj paket se ne može instalirati iz povišenog konteksta.", + "Please run UniGetUI as a regular user and try again.": "Molimo pokrenite UniGetUI kao običan korisnik i pokušajte ponovno.", + "Please check the installation options for this package and try again": "Molimo provjerite opcije instalacije za ovaj paket i pokušajte ponovno", + "Microsoft's official package manager. Full of well-known and verified packages
Contains: General Software, Microsoft Store apps": "Microsoftov službeni upravitelj paketa. Pun dobro poznatih i provjerenih paketa
Sadrži: Opći softver, aplikacije Microsoft Storea", + "Local PC": "Lokalno računalo", + "Android Subsystem": "Android podsustav", + "Operation on queue (position {0})...": "Operacija u redu čekanja (pozicija {0})...", + "Click here for more details": "Kliknite ovdje za više detalja", + "Operation canceled by user": "Operaciju je otkazao korisnik", + "Running PreOperation ({0}/{1})...": "Izvršavanje PreOperation ({0}/{1})...", + "PreOperation {0} out of {1} failed, and was tagged as necessary. Aborting...": "PreOperation {0} od {1} nije uspio i označen je kao obavezan. Prekidam...", + "PreOperation {0} out of {1} finished with result {2}": "PreOperation {0} od {1} završio je s rezultatom {2}", + "Starting operation...": "Pokretanje operacije...", + "Running PostOperation ({0}/{1})...": "Izvršavanje PostOperation ({0}/{1})...", + "PostOperation {0} out of {1} failed, and was tagged as necessary. Aborting...": "PostOperation {0} od {1} nije uspio i označen je kao obavezan. Prekidam...", + "PostOperation {0} out of {1} finished with result {2}": "PostOperation {0} od {1} završio je s rezultatom {2}", + "{package} installer download": "preuzimanje instalacijskog programa {package}", + "{0} installer is being downloaded": "instalacijski program {0} se preuzima", + "Download succeeded": "Preuzimanje uspješno", + "{package} installer was downloaded successfully": "Instalacijski program {package} je uspješno preuzet", + "Download failed": "Preuzimanje neuspješno", + "{package} installer could not be downloaded": "instalacijski program {package} nije moguće preuzeti", + "{package} Installation": "{package} Instalacija", + "{0} is being installed": "{0} se instalira", + "Installation succeeded": "Uspješna instalacija", + "{package} was installed successfully": "{package} je uspješno instaliran", + "Installation failed": "Instalacija neuspješna", + "{package} could not be installed": "{package} nije moguće instalirati", + "{package} Update": "{package} Ažuriranje", + "Update succeeded": "Ažuriranje uspjelo", + "{package} was updated successfully": "{package} je uspješno ažuriran ", + "Update failed": "Ažuriranje nije uspjelo", + "{package} could not be updated": "{package} nije moguće ažurirati", + "{package} Uninstall": "{package} Deinstaliranje", + "{0} is being uninstalled": "{0} se deinstalira", + "Uninstall succeeded": "De-instalacija je uspjela", + "{package} was uninstalled successfully": "{package} je uspješno deinstaliran", + "Uninstall failed": "Deinstalirajte neuspješna", + "{package} could not be uninstalled": "{package} nije moguće deinstalirati", + "Adding source {source}": "Dodavanje izvora {source}", + "Adding source {source} to {manager}": "Dodavanje izvora {source} u {manager}", + "Source added successfully": "Izvor uspješno dodan", + "The source {source} was added to {manager} successfully": "Izvor {source} je uspješno dodan u {manager}", + "Could not add source": "Nije moguće dodati izvor", + "Could not add source {source} to {manager}": "Nije moguće dodavanje izvora {source} u {manager}", + "Removing source {source}": "Uklanjanje izvora {source}", + "Removing source {source} from {manager}": "Uklanjanje izvora {source} iz {manager}", + "Source removed successfully": "Izvor uspješno uklonjen", + "The source {source} was removed from {manager} successfully": "Izvor {source} je uspješno uklonjen iz {manager}", + "Could not remove source": "Nije moguće ukloniti izvor", + "Could not remove source {source} from {manager}": "Nije moguće ukloniti izvor {source} iz {manager}", + "The package manager \"{0}\" was not found": "Upravitelj paketa \"{0}\" nije pronađen", + "The package manager \"{0}\" is disabled": "Upravitelj paketa \"{0}\" je onemogućen", + "There is an error with the configuration of the package manager \"{0}\"": "Došlo je do pogreške u konfiguraciji upravitelja paketa \"{0}\"", + "The package \"{0}\" was not found on the package manager \"{1}\"": "Paket \"{0}\" nije pronađen u upravitelju paketa \"{1}\"", + "{0} is disabled": "{0} je onemogućen", + "{0} weeks": "{0} tjedana", + "1 month": "1 mjesec", + "{0} months": "{0} mjeseci", + "Something went wrong": "Nešto nije u redu", + "An interal error occurred. Please view the log for further details.": "Došlo je do interne pogreške. Za više informacija pogledajte zapisnik.", + "No applicable installer was found for the package {0}": "Nije pronađen odgovarajući instalacijski program za paket {0}", + "Integrity checks will not be performed during this operation": "Provjere integriteta neće se provoditi tijekom ove operacije", + "This is not recommended.": "Ovo se ne preporučuje.", + "Run now": "Pokreni odmah", + "Run next": "Pokreni sljedeće", + "Run last": "Pokreni zadnje", + "Show in explorer": "Prikaži u exploreru", + "Checked": "Označeno", + "Unchecked": "Neoznačeno", + "This package is already installed": "Ovaj paket je već instaliran", + "This package can be upgraded to version {0}": "Ovaj paket se može nadograditi na verziju {0}", + "Updates for this package are ignored": "Ažuriranja za ovaj paket se ignoriraju", + "This package is being processed": "Ovaj paket se obrađuje", + "This package is not available": "Ovaj paket nije dostupan", + "Select the source you want to add:": "Odaberite izvor koji želite dodati:", + "Source name:": "Naziv izvora:", + "Source URL:": "Izvorni URL:", + "An error occurred when adding the source: ": "Došlo je do pogreške prilikom dodavanja izvora: ", + "Package management made easy": "Olakšano upravljanje paketima", + "version {0}": "verzija {0}", + "[RAN AS ADMINISTRATOR]": "POKRENUTO KAO ADMINISTRATOR", + "Portable mode": "Prijenosni način rada", + "DEBUG BUILD": "DEBUG VERZIJA", + "Here you can change UniGetUI's behaviour regarding the following shortcuts. Checking a shortcut will make UniGetUI delete it if if gets created on a future upgrade. Unchecking it will keep the shortcut intact": "Ovdje možete promijeniti ponašanje UniGetUI-ja u vezi sa sljedećim prečacima. Označavanjem prečaca - UniGetUI će ga izbrisati ako se stvori prilikom buduće nadogradnje. Poništavanjem odabira - prečac će ostati netaknut.", + "Manual scan": "Ručno skeniranje", + "Existing shortcuts on your desktop will be scanned, and you will need to pick which ones to keep and which ones to remove.": "Postojeći prečaci na vašoj radnoj površini bit će skenirani i morati ćete odabrati koje ćete zadržati, a koje ukloniti.", + "Delete?": "Obrisati?", + "I understand": "Razumijem", + "Chocolatey setup changed": "Postavke Chocolateyja su promijenjene", + "UniGetUI no longer includes its own private Chocolatey installation. A legacy UniGetUI-managed Chocolatey installation was detected for this user profile, but system Chocolatey was not found. Chocolatey will stay unavailable in UniGetUI until Chocolatey is installed on the system and UniGetUI is restarted. Applications previously installed through UniGetUI's bundled Chocolatey may still appear under other sources such as Local PC or WinGet.": "UniGetUI više ne uključuje vlastitu privatnu instalaciju Chocolateyja. Otkrivena je naslijeđena instalacija Chocolateyja kojom upravlja UniGetUI za ovaj korisnički profil, ali sistemski Chocolatey nije pronađen. Chocolatey će ostati nedostupan u UniGetUI-ju dok se Chocolatey ne instalira na sustav i UniGetUI se ponovno pokrene. Aplikacije prethodno instalirane putem ugrađenog Chocolateyja u UniGetUI-ju mogu se i dalje pojavljivati pod drugim izvorima kao što su Lokalno računalo ili WinGet.", + "NOTE: This troubleshooter can be disabled from UniGetUI Settings, on the WinGet section": "NAPOMENA: Ovaj alat za rješavanje problema može se onemogućiti u postavkama UniGetUI-ja, u odjeljku WinGet", + "Restart": "Ponovno pokretanje", + "Are you sure you want to delete all shortcuts?": "Jeste li sigurni da želite izbrisati sve prečace?", + "Any new shorcuts created during an install or an update operation will be deleted automatically, instead of showing a confirmation prompt the first time they are detected.": "Svi novi prečaci stvoreni tijekom instalacije ili ažuriranja bit će automatski izbrisani, bez prikazivanja upita za potvrdu pri prvom otkrivanju.", + "Any shorcuts created or modified outside of UniGetUI will be ignored. You will be able to add them via the {0} button.": "Svi prečaci kreirani ili izmijenjeni izvan UniGetUI-ja bit će ignorirani. Moći ćete ih dodati putem gumba {0}.", + "Are you really sure you want to enable this feature?": "Jeste li zaista sigurni da želite omogućiti ovu značajku?", + "No new shortcuts were found during the scan.": "Tijekom skeniranja nisu pronađeni novi prečaci.", + "How to add packages to a bundle": "Kako dodati pakete u skup paketa", + "In order to add packages to a bundle, you will need to: ": "Da biste dodali pakete u skup paketa, trebat će vam:", + "1. Navigate to the \"{0}\" or \"{1}\" page.": "1. Idite na stranicu \"{0}\" ili \"{1}\".", + "2. Locate the package(s) you want to add to the bundle, and select their leftmost checkbox.": "2. Pronađite paket(e) koje želite dodati u skup paketa i označite njihov potvrdni okvir krajnje lijevo.", + "3. When the packages you want to add to the bundle are selected, find and click the option \"{0}\" on the toolbar.": "3. Kada su paketi koje želite dodati u skup paketa odabrani, pronađite i kliknite opciju \"{0}\" na alatnoj traci.", + "4. Your packages will have been added to the bundle. You can continue adding packages, or export the bundle.": "4. Vaši paketi su dodani u skup paketa. Možete nastaviti dodavati pakete ili izvesti skup paketa.", + "Which backup do you want to open?": "Koju sigurnosnu kopiju želite otvoriti?", + "Select the backup you want to open. Later, you will be able to review which packages you want to install.": "Odaberite sigurnosnu kopiju koju želite otvoriti. Kasnije ćete moći pregledati koje pakete/programe želite vratiti.", + "There are ongoing operations. Quitting UniGetUI may cause them to fail. Do you want to continue?": "Postoje operacije u tijeku. Izlazak iz UniGetUI-ja može uzrokovati njihov neuspjeh. Želite li nastaviti?", + "UniGetUI or some of its components are missing or corrupt.": "UniGetUI ili neke njegove komponente nedostaju ili su oštećene.", + "It is strongly recommended to reinstall UniGetUI to adress the situation.": "Preporučuje se ponovna instalacija UniGetUI-ja kako bi se riješila situacija.", + "Refer to the UniGetUI Logs to get more details regarding the affected file(s)": "Za više detalja o pogođenim datotekama pogledajte UniGetUI zapisnike.", + "Integrity checks can be disabled from the Experimental Settings": "Provjere integriteta mogu se onemogućiti u eksperimentalnim postavkama", + "Repair UniGetUI": "Popravi UniGetUI", + "Live output": "Izlaz u stvarnom vremenu", + "This package bundle had some settings that are potentially dangerous, and may be ignored by default.": "Ovaj paketni skup imao je neke postavke koje su potencijalno opasne i mogu se prema zadanim postavkama zanemariti.", + "Entries that show in YELLOW will be IGNORED.": "Unosi koji su označeni ŽUTOM bojom bit će ZANEMARENI.", + "Entries that show in RED will be IMPORTED.": "Unosi koji se prikazuju CRVENOM bojom bit će UVEŽENI.", + "You can change this behavior on UniGetUI security settings.": "Ovo ponašanje možete promijeniti u sigurnosnim postavkama UniGetUI-ja.", + "Open UniGetUI security settings": "Otvorite sigurnosne postavke UniGetUI-ja", + "Should you modify the security settings, you will need to open the bundle again for the changes to take effect.": "Ako promijenite sigurnosne postavke, morat ćete ponovno otvoriti paket da bi promjene stupile na snagu.", + "Details of the report:": "Pojedinosti izvješća:", + "Are you sure you want to create a new package bundle? ": "Jeste li sigurni da želite stvoriti novi skup paketa?", + "Any unsaved changes will be lost": "Sve nespremljene promjene bit će izgubljene", + "Warning!": "Upozorenje!", + "For security reasons, custom command-line arguments are disabled by default. Go to UniGetUI security settings to change this. ": "Iz sigurnosnih razloga, prilagođeni argumenti naredbenog retka su prema zadanim postavkama onemogućeni. Idite u sigurnosne postavke UniGetUI-ja da biste to promijenili.", + "Change default options": "Promijenite zadane opcije", + "Ignore future updates for this package": "Ignorirajte buduća ažuriranja za ovaj paket", + "For security reasons, pre-operation and post-operation scripts are disabled by default. Go to UniGetUI security settings to change this. ": "Iz sigurnosnih razloga, skripte prije i poslije operacije su prema zadanim postavkama onemogućene. Idite u sigurnosne postavke UniGetUI-ja da biste to promijenili.", + "You can define the commands that will be run before or after this package is installed, updated or uninstalled. They will be run on a command prompt, so CMD scripts will work here.": "Možete definirati naredbe koje će se izvršavati prije ili nakon instalacije, ažuriranja ili de-instalacije ovog paketa. Izvršavat će se u naredbenom retku, tako da će CMD skripte ovdje raditi.", + "Change this and unlock": "Promijeni ovo te otključaj", + "{0} Install options are currently locked because {0} follows the default install options.": "{0} Opcije instalacije su trenutno zaključane jer {0} slijedi zadane opcije instalacije.", + "Unset or unknown": "Nepostavljeno ili nepoznato", + "This package has no screenshots or is missing the icon? Contrbute to UniGetUI by adding the missing icons and screenshots to our open, public database.": "Ovaj paket nema snimki zaslona ili mu nedostaje ikona? Doprinesite UniGetUI-ju dodavanjem ikona i snimaka zaslona koje nedostaju u našu otvorenu, javnu bazu podataka.", + "Become a contributor": "Postanite suradnik", + "Update to {0} available": "Dostupno ažuriranje na {0}", + "Reinstall": "Ponovna instalacija", + "Installer not available": "Instalacijski program nedostupan", + "Version:": "Verzija:", + "UniGetUI Version {0}": "UniGetUI verzija {0}", + "Performing backup, please wait...": "Izvodi se sigurnosna kopija, pričekajte...", + "An error occurred while logging in: ": "Došlo je do pogreške prilikom prijave:", + "Fetching available backups...": "Dohvaćanje dostupnih sigurnosnih kopija...", + "Done!": "Gotovo!", + "The cloud backup has been loaded successfully.": "Sigurnosna kopija u oblaku uspješno je učitana.", + "An error occurred while loading a backup: ": "Došlo je do pogreške prilikom učitavanja sigurnosne kopije:", + "Backing up packages to GitHub Gist...": "Sigurnosno kopiranje paketa na GitHub Gist...", + "Backup Successful": "Sigurnosno kopiranje uspješno", + "The cloud backup completed successfully.": "Sigurnosna kopija u oblaku uspješno je dovršena.", + "Could not back up packages to GitHub Gist: ": "Nije moguće sigurnosno kopiranje paketa na GitHub Gist...", + "It is not guaranteed that the provided credentials will be stored safely, so you may as well not use the credentials of your bank account": "Nije zajamčeno da će uneseni podaci za prijavu biti sigurno pohranjeni, stoga ne biste trebali koristiti podatke za svoj bankovni račun.", + "Enable the automatic WinGet troubleshooter": "Omogućite automatski alat za rješavanje problema s WinGetom", + "Add updates that fail with a 'no applicable update found' to the ignored updates list": "Dodajte ažuriranja koja ne uspiju s porukom 'nije pronađeno primjenjivo ažuriranje' na popis zanemarenih ažuriranja.", + "Invalid selection": "Nevažeći odabir", + "No package was selected": "Nijedan paket nije odabran", + "More than 1 package was selected": "Odabrano je više od 1 paketa", + "List": "Popis", + "Grid": "Rešetka", + "Icons": "Ikone", + "\"{0}\" is a local package and does not have available details": "\"{0}\" je lokalni paket i nema dostupnih detalja", + "\"{0}\" is a local package and is not compatible with this feature": "\"{0}\" je lokalni paket i nije kompatibilan s ovom značajkom", + "Add packages to bundle": "Dodaj pakete u skup paketa", + "Preparing packages, please wait...": "Pripremamo pakete, molimo pričekajte...", + "Loading packages, please wait...": "Učitavanje paketa, molimo pričekajte...", + "Saving packages, please wait...": "Spremanje paketa, molimo pričekajte...", + "The bundle was created successfully on {0}": "Skup paketa je uspješno izrađen na {0}", + "User profile": "Korisnički profil", + "Error": "Greška", + "Log in failed: ": "Prijava neuspješna:", + "Log out failed: ": "Odjava neuspješna: ", + "Package backup settings": "Postavke sigurnosne kopije paketa", + "Manage UniGetUI autostart behaviour from the Settings app": "Upravljanje ponašanjem automatskog pokretanja UniGetUI-ja", + "Choose how many operations shoulds be performed in parallel": "Odaberite koliko se operacija treba izvršavati paralelno", + "Something went wrong while launching the updater.": "Došlo je do pogreške prilikom pokretanja ažuriranja.", + "Please try again later": "Molim pokušajte ponovno kasnije", + "Show the release notes after UniGetUI is updated": "Prikaži napomene o izdanju nakon ažuriranja UniGetUI-a" +} diff --git a/src/Languages/lang_hu.json b/src/Languages/lang_hu.json new file mode 100644 index 0000000..ebb80c3 --- /dev/null +++ b/src/Languages/lang_hu.json @@ -0,0 +1,850 @@ +{ + "{0} of {1} operations completed": "{1} műveletből {0} fejeződött be", + "{0} is now {1}": "{0} most {1}", + "Enabled": "Engedélyezve", + "Disabled": "Kikapcsolva", + "Privacy": "Adatvédelem", + "Hide my username from the logs": "Felhasználónevem elrejtése a naplókból", + "Replaces your username with **** in the logs. Restart UniGetUI to also hide it from already-recorded entries.": "A felhasználónevét ****-ra cseréli a naplókban. Indítsa újra a UniGetUI-t, hogy a már rögzített bejegyzésekből is elrejtse.", + "Your last update attempt did not complete.": "A legutóbbi frissítési kísérlet nem fejeződött be.", + "UniGetUI could not confirm whether the update succeeded. Open the log to see what happened.": "Az UniGetUI nem tudta megerősíteni, hogy a frissítés sikeres volt-e. Nyissa meg a naplót, hogy megnézze, mi történt.", + "View log": "Napló megtekintése", + "The installer reported success but did not restart UniGetUI.": "A telepítő sikeres telepítést jelzett, de nem indította újra az UniGetUI-t.", + "The installer failed to initialize.": "A telepítő inicializálása nem sikerült.", + "Setup was canceled before installation began.": "A telepítés megkezdése előtt megszakították a beállítást.", + "A fatal error occurred during the preparation phase.": "Végzetes hiba történt az előkészítési fázisban.", + "A fatal error occurred during installation.": "Végzetes hiba történt a telepítés során.", + "Installation was canceled while in progress.": "A telepítést menet közben megszakították.", + "The installer was terminated by another process.": "A telepítőt egy másik folyamat leállította.", + "The preparation phase determined the installation cannot proceed.": "Az előkészítési fázis megállapította, hogy a telepítés nem folytatható.", + "The installer could not start. UniGetUI may already be running, or you do not have permission to install.": "A telepítő nem tudott elindulni. Lehet, hogy az UniGetUI már fut, vagy nincs jogosultsága a telepítéshez.", + "Unexpected installer error.": "Váratlan telepítőhiba.", + "We are checking for updates.": "Ellenőrizzük a frissítéseket.", + "Please wait": "Kis türelmet", + "Great! You are on the latest version.": "Nagyszerű! Ön a legújabb verziót használja.", + "There are no new UniGetUI versions to be installed": "Nincsenek új UniGetUI verziók, amelyeket telepíteni kellene", + "UniGetUI version {0} is being downloaded.": "Az UniGetUI {0} verziójának letöltése folyamatban van.", + "This may take a minute or two": "Ez egy-két percet vehet igénybe", + "The installer authenticity could not be verified.": "A telepítő hitelességét nem sikerült ellenőrizni.", + "The update process has been aborted.": "A frissítési folyamat megszakadt.", + "Auto-update is not yet available on this platform.": "Az automatikus frissítés még nem érhető el ezen a platformon.", + "Please update UniGetUI manually.": "Kérjük, frissítse kézzel az UniGetUI-t.", + "An error occurred when checking for updates: ": "Hiba történt a frissítések ellenőrzése során:", + "The updater could not be launched.": "A frissítő nem indítható el.", + "The operating system did not start the installer process.": "Az operációs rendszer nem indította el a telepítő folyamatot.", + "UniGetUI is being updated...": "Az UniGetUI frissül...", + "Update installed.": "A frissítés telepítve.", + "UniGetUI was updated successfully, but this running copy was not replaced. This usually means you are running a development build. Close this copy and start the newly-installed version to finish.": "Az UniGetUI sikeresen frissült, de ez a futó példány nem lett lecserélve. Ez általában azt jelenti, hogy fejlesztői buildet futtat. A befejezéshez zárja be ezt a példányt, és indítsa el az újonnan telepített verziót.", + "The update could not be applied.": "A frissítés nem alkalmazható.", + "Installer exit code {0}: {1}": "Telepítő kilépési kódja {0}: {1}", + "Update cancelled.": "Frissítés megszakítva.", + "Authentication was cancelled.": "A hitelesítést megszakították.", + "Installer exit code {0}": "Telepítő kilépési kódja {0}", + "Operation in progress": "Folyamatban lévő művelet", + "Please wait...": "Kis türelmet...", + "Success!": "Sikerült!", + "Failed": "Sikertelen", + "An error occurred while processing this package": "Hiba történt a csomag feldolgozása során", + "Installer": "Telepítő", + "Executable": "Végrehajtható fájl", + "MSI": "MSI", + "Compressed file": "Tömörített fájl", + "MSIX": "MSIX", + "WinGet was repaired successfully": "A WinGet sikeresen javítva lett", + "It is recommended to restart UniGetUI after WinGet has been repaired": "A WinGet javítása után ajánlott az UniGetUI újraindítása.", + "WinGet could not be repaired": "A WinGet nem javítható", + "An unexpected issue occurred while attempting to repair WinGet. Please try again later": "Váratlan probléma merült fel a WinGet javítási kísérlete során. Próbálja később újra", + "Log in to enable cloud backup": "Jelentkezzen be a felhőalapú biztonsági mentés engedélyezéséhez", + "Backup Failed": "A biztonsági mentés nem sikerült", + "Downloading backup...": "Bizt. mentés letöltése...", + "An update was found!": "Találtunk egy frissítést!", + "{0} can be updated to version {1}": "{0} frissíthető {1} verzióra.", + "Updates found!": "Frissítés található!", + "{0} packages can be updated": "{0} csomag frissíthető", + "{0} is being updated to version {1}": "{0} frissül az {1} verzióra.", + "{0} packages are being updated": "{0} csomag frissül", + "You have currently version {0} installed": "Jelenleg a {0} verzió van telepítve", + "Desktop shortcut created": "Asztali parancsikon létrehozva", + "UniGetUI has detected a new desktop shortcut that can be deleted automatically.": "Az UniGetUI egy új asztali parancsikont észlelt, amely auto. törölhető.", + "{0} desktop shortcuts created": "{0} asztali parancsikonok létrehozva", + "UniGetUI has detected {0} new desktop shortcuts that can be deleted automatically.": "Az UniGetUI Az UniGetUI {0} új asztali parancsikont észlelt, amelyek automatikusan törölhetők.", + "Attention required": "Figyelmet igényel", + "Restart required": "Újraindítás szükséges", + "1 update is available": "1 frissítés érhető el", + "{0} updates are available": "{0} frissítés áll rendelkezésre", + "Everything is up to date": "Minden naprakész", + "Discover Packages": "Csomagok felfedezése", + "Available Updates": "Elérhető frissítések", + "Installed Packages": "Telepített Csomagok", + "UniGetUI Version {0} by Devolutions": "UniGetUI {0} verzió – Devolutions", + "Show UniGetUI": "UniGetUI megjelenítése", + "Quit": "Kilépés", + "Are you sure?": "Biztos benne?", + "Do you really want to uninstall {0}?": "Biztosan el akarja távolítani a következőt: {0}?", + "Do you really want to uninstall the following {0} packages?": "Tényleg szeretné eltávolítani a következő {0} csomagot?", + "No": "Nem", + "Yes": "Igen", + "Partial": "Részleges", + "View on UniGetUI": "Megtekintés az Unigetui-n", + "Update": "Frissítés", + "Open UniGetUI": "Az UniGetUI megnyitása", + "Update all": "Az összes frissítése", + "Update now": "Frissítés most", + "Installer host changed since the installed version.\n": "A telepítő gazdagépe megváltozott a telepített verzió óta.\n", + "This package is on the queue": "Ez a csomag várólistán van", + "installing": "telepítés", + "updating": "frissítés", + "uninstalling": "eltávolítás", + "installed": "telepítve", + "Retry": "Újra", + "Install": "Telepítés", + "Uninstall": "Eltávolítás", + "Open": "Megnyit", + "Operation profile:": "Műveleti profil:", + "Follow the default options when installing, upgrading or uninstalling this package": "Kövesse az alapért. beállításokat a csomag telepítésekor, frissítésekor vagy eltávolításakor.", + "The following settings will be applied each time this package is installed, updated or removed.": "A következő beállítások minden egyes alkalommal alkalmazásra kerülnek, amikor a csomag telepítése, frissítése vagy eltávolítása megtörténik.", + "Version to install:": "Telepítendő verzió:", + "Architecture to install:": "Telepítendő architektúra:", + "Installation scope:": "Scope telepítés:", + "Install location:": "Telepítés helye:", + "Select": "Kiválasztás", + "Reset": "Újrakezd", + "Custom install arguments:": "Egyéni telepítési argumentumok:", + "Custom update arguments:": "Egyéni frissítési argumentumok:", + "Custom uninstall arguments:": "Egyéni eltávolítási argumentumok:", + "Pre-install command:": "Telepítés előtti parancs:", + "Post-install command:": "Telepítés utáni parancs:", + "Abort install if pre-install command fails": "A telepítés megszakítása, ha a telepítést megelőző parancs sikertelenül működik", + "Pre-update command:": "Frissítés előtti parancs:", + "Post-update command:": "Frissítés utáni parancs:", + "Abort update if pre-update command fails": "A frissítés megszakítása, ha a frissítést megelőző parancs sikertelenül működik", + "Pre-uninstall command:": "Eltávolítás előtti parancs:", + "Post-uninstall command:": "Eltávolítás utáni parancs:", + "Abort uninstall if pre-uninstall command fails": "Az eltávolítás megszakítása, ha az eltávolítás előtti parancs sikertelen", + "Command-line to run:": "Futtatandó parancssor:", + "Save and close": "Mentés és bezárás", + "General": "Általános", + "Architecture & Location": "Architektúra és hely", + "Command-line": "Parancssor", + "Close apps": "Alkalmazások bezárása", + "Pre/Post install": "Telepítés előtt/után", + "Select the processes that should be closed before this package is installed, updated or uninstalled.": "Válassza ki azokat a folyamatokat, amelyeket a csomag telepítése, frissítése vagy eltávolítása előtt le kell zárni.", + "Write here the process names here, separated by commas (,)": "Írja ide a folyamatok neveit vesszővel (,) elválasztva.", + "Try to kill the processes that refuse to close when requested to": "Próbálja meg leállítani azokat a folyamatokat, amelyek nem hajlandóak bezárni, amikor erre kérik őket.", + "Run as admin": "Futtatás rendszergazdaként", + "Interactive installation": "Interaktív telepítés", + "Skip hash check": "Hash ellenőrzés kihagyása", + "Uninstall previous versions when updated": "A korábbi verziók eltávolítása frissítéskor", + "Skip minor updates for this package": "Kisebb frissítések kihagyása ehhez a csomaghoz", + "Automatically update this package": "A csomag automatikus frissítése", + "{0} installation options": "{0} telepítési lehetőségek", + "Latest": "Legújabb", + "PreRelease": "Korai kiadás", + "Default": "Alapértelmezett", + "Manage ignored updates": "Ignorált frissítések kezelése", + "The packages listed here won't be taken in account when checking for updates. Double-click them or click the button on their right to stop ignoring their updates.": "Az itt felsorolt csomagokat nem veszi figyelembe a rendszer a frissítések keresésekor. Kattintson rájuk duplán, vagy kattintson a jobb oldali gombra, ha nem szeretné tovább figyelmen kívül hagyni a frissítéseiket.\n", + "Reset list": "Lista alapra állítása", + "Do you really want to reset the ignored updates list? This action cannot be reverted": "Biztosan vissza szeretné állítani a figyelmen kívül hagyott frissítések listáját? Ez a művelet nem vonható vissza.", + "No ignored updates": "Nincsenek figyelmen kívül hagyott frissítések", + "Package Name": "Csomagnév", + "Package ID": "Csomag azonosító", + "Ignored version": "Figyelmen kívül hagyott verzió", + "New version": "Új verzió", + "Source": "Forrás", + "All versions": "Minden változat", + "Unknown": "Ismeretlen", + "Up to date": "Naprakész", + "Package {name} from {manager}": "{name} csomag a(z) {manager} kezelőből", + "Remove {0} from ignored updates": "{0} eltávolítása a figyelmen kívül hagyott frissítések közül", + "Cancel": "Mégse", + "Administrator privileges": "Rendszergazdai jogosultságok", + "This operation is running with administrator privileges.": "Ez a művelet rendszergazdai jogosultságokkal fut.", + "Interactive operation": "Interaktív műveletek", + "This operation is running interactively.": "Ez a művelet interaktívan fut.", + "You will likely need to interact with the installer.": "Valószínűleg rá kell pillantani a telepítőre.", + "Integrity checks skipped": "Kihagyott integritás ellenőrzések", + "Integrity checks will not be performed during this operation.": "Az integritás-ellenőrzések a művelet során nem lesznek végrehajtva.", + "Proceed at your own risk.": "Saját felelősségére folytassa.", + "Close": "Bezár", + "Loading...": "Betöltés...", + "Installer SHA256": "SHA256 telepítő", + "Homepage": "Honlap", + "Author": "Szerző", + "Publisher": "Kiadó", + "License": "Licenc", + "Manifest": "Jegyzék", + "Installer Type": "Telepítő típusa", + "Size": "Méret", + "Installer URL": "Telepítő URL", + "Last updated:": "Utolsó frissítés:", + "Release notes URL": "Kiadási megjegyzések URL", + "Package details": "A csomag részletei", + "Dependencies:": "Függőségek:", + "Release notes": "Kiadási megjegyzések", + "Screenshots": "Képernyőképek", + "This package has no screenshots or is missing the icon? Contribute to UniGetUI by adding the missing icons and screenshots to our open, public database.": "Ez a csomag nem rendelkezik képernyőképekkel, vagy hiányzik az ikonja? Segítsen az UniGetUI-nak a hiányzó ikonok és képernyőképek hozzáadásával a nyílt, nyilvános adatbázisunkhoz.", + "Version": "Verzió", + "Install as administrator": "Telepítés rendszergazdaként", + "Update to version {0}": "Frissítés a {0} verzióra", + "Installed Version": "Telepített verzió", + "Update as administrator": "Frissítés rendszergazdaként", + "Interactive update": "Interaktív frissítés", + "Uninstall as administrator": "Eltávolítás rendszergazdaként", + "Interactive uninstall": "Interaktív eltávolítás", + "Uninstall and remove data": "Eltávolítás és adatok eltávolítása", + "Not available": "Nem érhető el", + "Installer SHA512": "Telepítő SHA512", + "Unknown size": "Ismeretlen méret", + "No dependencies specified": "Nincsenek megadott függőségek", + "mandatory": "kötelező", + "optional": "lehetőség", + "UniGetUI {0} is ready to be installed.": "Az UniGetUI {0} készen áll a telepítésre.", + "The update process will start after closing UniGetUI": "A frissítési folyamat az UniGetUI bezárása után kezdődik.", + "UniGetUI has been ran as administrator, which is not recommended. When running UniGetUI as administrator, EVERY operation launched from UniGetUI will have administrator privileges. You can still use the program, but we highly recommend not running UniGetUI with administrator privileges.": "Az UniGetUI rendszergazdaként lett elindítva, ami nem ajánlott. Ha az UniGetUI rendszergazdaként fut, az UniGetUI-ból indított MINDEN művelet rendszergazdai jogosultságokkal fog futni. A programot továbbra is használhatja, de nyomatékosan javasoljuk, hogy ne futtassa az UniGetUI-t rendszergazdai jogosultságokkal.", + "Share anonymous usage data": "Névtelen használati adatok megosztása", + "UniGetUI collects anonymous usage data in order to improve the user experience.": "Az UniGetUI anonim használati adatokat gyűjt a felhasználói élmény javítása érdekében.", + "Accept": "Elfogad", + "Software Updates": "Szoftver frissítések", + "Package Bundles": "Csomag kötegek", + "Settings": "Beállítások", + "Package Managers": "Csomagkezelők", + "UniGetUI Log": "UniGetUI napló", + "Package Manager logs": "Csomagkezelő naplók", + "Operation history": "Műveleti előzmények", + "Help": "Súgó", + "UniGetUI": "UniGetUI", + "You have installed UniGetUI Version {0}": "Ön telepítette a UniGetUI {0} verzióját.", + "Disclaimer": "Nyilatkozat", + "UniGetUI is developed by Devolutions and is not affiliated with any of the compatible package managers.": "A UniGetUI-t a Devolutions fejleszti, és nem áll kapcsolatban egyik kompatibilis csomagkezelővel sem.", + "UniGetUI wouldn't have been possible without the help of the contributors. Thank you all 🥳": "A UniGetUI nem jöhetett volna létre a közreműködők segítsége nélkül. Köszönjük mindenkinek 🥳", + "UniGetUI uses the following libraries. Without them, UniGetUI wouldn't have been possible.": "A UniGetUI a következő könyvtárakat használja. Ezek nélkül a UniGetUI nem jöhetett volna létre.", + "{0} homepage": "{0} honlap", + "UniGetUI has been translated to more than 40 languages thanks to the volunteer translators. Thank you 🤝": "A UniGetUI-t több mint 40 nyelvre fordították le az önkéntes fordítóknak köszönhetően. Köszönöm 🤝", + "Verbose": "Bővebben", + "1 - Errors": "Hibák", + "2 - Warnings": "Figyelmeztetések", + "3 - Information (less)": "Információ (kevesebb)", + "4 - Information (more)": "Információ (több)", + "5 - information (debug)": "Információ (hibakeresés)", + "Warning": "Figyelmeztetés", + "The following settings may pose a security risk, hence they are disabled by default.": "A következő beállítások biztonsági kockázatot jelenthetnek, ezért alapértelmezés szerint le vannak tiltva.", + "Enable the settings below if and only if you fully understand what they do, and the implications they may have.": "Az alábbi beállításokat AKKOR ÉS CSAK IS AKKOR engedélyezze, ha teljesen tisztában van azzal, hogy mit tesznek, és milyen következményekkel és veszélyekkel járhatnak.", + "The settings will list, in their descriptions, the potential security issues they may have.": "A beállítások a leírásukban felsorolják a lehetséges biztonsági problémákat.", + "The backup will include the complete list of the installed packages and their installation options. Ignored updates and skipped versions will also be saved.": "A biztonsági mentés tartalmazza a telepített csomagok teljes listáját és a telepítési beállításokat. A figyelmen kívül hagyott frissítések és kihagyott verziók is mentésre kerülnek.\n", + "The backup will NOT include any binary file nor any program's saved data.": "A biztonsági mentés NEM tartalmaz semmilyen bináris fájlt vagy program mentett adatait.", + "The size of the backup is estimated to be less than 1MB.": "A biztonsági mentés becsült mérete kevesebb, mint 1 MB.", + "The backup will be performed after login.": "A biztonsági mentés a bejelentkezés után történik.", + "{pcName} installed packages": "{pcName} telepített csomagok", + "Current status: Not logged in": "Jelenlegi állapot: Nincs bejelentkezve", + "You are logged in as {0} (@{1})": "Ön be van jelentkezve, mint {0} (@{1} )", + "Nice! Backups will be uploaded to a private gist on your account": "Szép! A biztonsági mentések feltöltődnek a fiókod privát listájára.", + "Select backup": "Biztonsági mentés kiválasztása", + "Settings imported from {0}": "Beállítások importálva innen: {0}", + "UniGetUI Settings": "UniGetUI beállítások", + "Settings exported to {0}": "Beállítások exportálva ide: {0}", + "UniGetUI settings were reset": "A UniGetUI beállításai visszaállítva", + "Allow pre-release versions": "Engedélyezze az előzetes kiadású verziókat", + "Apply": "Alkalmaz", + "For security reasons, custom command-line arguments are disabled by default. Go to UniGetUI security settings to change this.": "Biztonsági okokból az egyéni parancssori argumentumok alapértelmezés szerint le vannak tiltva. Ennek módosításához nyissa meg az UniGetUI biztonsági beállításait.", + "Go to UniGetUI security settings": "Lépjen az UniGetUI biztonsági beállításaihoz", + "The following options will be applied by default each time a {0} package is installed, upgraded or uninstalled.": "A következő beállítások alapértelmezés szerint minden alkalommal alkalmazásra kerülnek, amikor egy {0} csomag telepítése, frissítése vagy eltávolítása történik.", + "Package's default": "A csomag alapértelmezett", + "Install location can't be changed for {0} packages": "A telepítési hely nem módosítható {0} csomag esetében", + "The local icon cache currently takes {0} MB": "A helyi ikon gyorsítótár jelenleg {0} MB helyet foglal el.", + "Username": "Felhasználónév", + "Password": "Jelszó", + "Credentials": "Ajánlások", + "It is not guaranteed that the provided credentials will be stored safely": "Nem garantálható, hogy a megadott hitelesítő adatok biztonságosan lesznek tárolva", + "Partially": "Részben", + "Package manager": "Csomagkezelő", + "Compatible with proxy": "Kompatibilitás proxy-val", + "Compatible with authentication": "Kompatibilitás hitelesítéssel", + "Proxy compatibility table": "Proxy kompatibilitási táblázat", + "{0} settings": "{0} beállítások", + "{0} status": "{0} állapot", + "Default installation options for {0} packages": "{0} csomag alapért. telepítési beállításai", + "Expand version": "Bővített változat", + "The executable file for {0} was not found": "A {0} futtatható fájlja nem található", + "{pm} is disabled": "{pm} le van tiltva", + "Enable it to install packages from {pm}.": "Engedélyezze a csomagok telepítéséhez innen {pm}.", + "{pm} is enabled and ready to go": "{pm} engedélyezve van, és használatra kész", + "{pm} version:": "{pm} verzió:", + "{pm} was not found!": "{pm} nem található!", + "You may need to install {pm} in order to use it with UniGetUI.": "Lehet, hogy telepítenie kell a {pm}-t, hogy a UniGetUI-val használni tudja.", + "Scoop Installer - UniGetUI": "Scoop telepítő - UniGetUI", + "Scoop Uninstaller - UniGetUI": "Scoop eltávolító - UniGetUI", + "Clearing Scoop cache - UniGetUI": "Scoop gyorsítótár törlése - UniGetUI", + "Restart UniGetUI to fully apply changes": "A módosítások teljes alkalmazásához indítsa újra az UniGetUI-t", + "Restart UniGetUI": "Az UniGetUI újraindítása", + "Manage {0} sources": "{0} források kezelése", + "Add source": "Forrás hozzáadása", + "Add": "Hozzáadás", + "Source name": "Forrás neve", + "Source URL": "Forrás URL-je", + "Other": "Egyéb", + "No minimum age": "Nincs minimális kor", + "1 day": "1 nap", + "{0} days": "{0} nap", + "Custom...": "Egyéni...", + "{0} minutes": "{0} perc", + "1 hour": "1 óra", + "{0} hours": "{0} óra", + "1 week": "1 hét", + "Supports release dates": "Támogatja a kiadási dátumokat", + "Release date support per package manager": "Kiadási dátum támogatása csomagkezelőnként", + "Search for packages": "Csomagok keresése", + "Local": "Helyi", + "OK": "OK", + "Last checked: {0}": "Utolsó ellenőrzés: {0}", + "{0} packages were found, {1} of which match the specified filters.": "{0} csomagot találtunk, amelyek közül {1} megfelel a megadott szűrőknek.", + "{0} selected": "{0} kiválasztva", + "(Last checked: {0})": "(Utolsó ellenőrzés: {0})", + "All packages selected": "Minden csomag kiválasztva", + "Package selection cleared": "Csomagkijelölés törölve", + "{0}: {1}": "{0}: {1}", + "More info": "Több infó", + "GitHub account": "GitHub-fiók", + "Log in with GitHub to enable cloud package backup.": "Jelentkezzen be a GitHub-bal a felhőalapú csomag bizt. mentés engedélyezéséhez.", + "More details": "További részletek", + "Log in": "Bejelentkezés", + "If you have cloud backup enabled, it will be saved as a GitHub Gist on this account": "Ha engedélyezte a felhőalapú mentést, akkor az egy GitHub Gist-ként lesz elmentve ezen a fiókon.", + "Log out": "Kijelentkezés", + "About UniGetUI": "Az UniGetUI-ról", + "About": "Rólunk", + "Third-party licenses": "Harmadik fél licencei", + "Contributors": "Közreműködők", + "Translators": "Fordítók", + "Bundle security report": "Köteg-biztonsági jelentés", + "The bundle contained restricted content": "A csomagköteg korlátozott tartalmat tartalmazott", + "UniGetUI – Crash Report": "UniGetUI – Összeomlási jelentés", + "UniGetUI has crashed": "A UniGetUI összeomlott", + "Help us fix this by sending a crash report to Devolutions. All fields below are optional.": "Segítsen nekünk a hiba javításában egy összeomlási jelentés küldésével a Devolutions számára. Az alábbi mezők mindegyike opcionális.", + "Email (optional)": "E-mail (opcionális)", + "your@email.com": "pelda@email.com", + "Additional details (optional)": "További részletek (opcionális)", + "Describe what you were doing when the crash occurred…": "Írja le, mit csinált, amikor az összeomlás történt…", + "Crash report": "Összeomlási jelentés", + "Don't Send": "Ne küldje el", + "Send Report": "Jelentés küldése", + "Sending…": "Küldés…", + "Unsaved changes": "Nem mentett módosítások", + "You have unsaved changes in the current bundle. Do you want to discard them?": "Nem mentett módosításai vannak a jelenlegi csomagkötegben. Szeretné elvetni őket?", + "Discard changes": "Módosítások elvetése", + "Integrity violation": "Integritássértés", + "UniGetUI or some of its components are missing or corrupt. It is strongly recommended to reinstall UniGetUI to adress the situation.": "Az UniGetUI vagy egyes összetevői hiányoznak vagy sérültek. Erősen ajánlott az UniGetUI újratelepítése a helyzet megoldásához.", + "• Refer to the UniGetUI Logs to get more details regarding the affected file(s)": "• Az érintett fájl(okk)al kapcsolatos további részletekért lásd az UniGetUI naplófájlokat", + "• Integrity checks can be disabled from the Experimental Settings": "• Az integritás-ellenőrzések letilthatók a Kísérleti beállítások menüpontban", + "Manage shortcuts": "A parancsikonok kezelése", + "UniGetUI has detected the following desktop shortcuts which can be removed automatically on future upgrades": "Az UniGetUI a következő asztali parancsikonokat észlelte, amelyek a jövőbeni frissítések során auto. eltávolíthatók", + "Do you really want to reset this list? This action cannot be reverted.": "Tényleg alaphelyzetbe állítja ezt a listát? Ezt a műveletet nem lehet visszavonni.", + "Desktop shortcuts list": "Asztali parancsikonok listája", + "Open in explorer": "Megnyitás az Intézőben", + "Remove from list": "Eltávolítás a listáról", + "When new shortcuts are detected, delete them automatically instead of showing this dialog.": "Mikor új parancsikonokat észlel, autom. törli ezeket ahelyett, hogy megjelenítené ezt a párbeszédpanelt.", + "Not right now": "Most nem.", + "Missing dependency": "Hiányzó függőség", + "UniGetUI requires {0} to operate, but it was not found on your system.": "Az UniGetUI működéséhez {0} szükséges, de nem találtuk meg a rendszerében.", + "Click on Install to begin the installation process. If you skip the installation, UniGetUI may not work as expected.": "Kattintson a Telepítés gombra a telepítési folyamat megkezdéséhez. Ha kihagyja a telepítést előfordulhat, hogy az UniGetUI nem a várt módon fog működni.", + "Alternatively, you can also install {0} by running the following command in a Windows PowerShell prompt:": "Alternatívaként a(z) {0} telepítése a Windows PowerShell-ben a következő parancs futtatásával is elvégezhető:", + "Install {0}": "{0} telepítése", + "Do not show this dialog again for {0}": "Ne jelenítse meg ezt a {0} párbeszédpanelt újra", + "Please wait while {0} is being installed. A black window may show up. Please wait until it closes.": "Kérjük, várjon, amíg {0} telepítése folyamatban van. Egy fekete ablak jelenhet meg. Kis türelmet, amíg bezáródik.", + "{0} has been installed successfully.": "{0} sikeresen telepítve.", + "Please click on \"Continue\" to continue": "A folytatáshoz kattintson a \"Folytatás\" gombra", + "Continue": "Folytatás", + "{0} has been installed successfully. It is recommended to restart UniGetUI to finish the installation": "{0} sikeresen telepítve. A telepítés befejezéséhez ajánlott újraindítani az UniGetUI-t.", + "Restart later": "Újraindítás később", + "An error occurred:": "Hiba történt:", + "Please see the Command-line Output or refer to the Operation History for further information about the issue.": "A problémával kapcsolatos további információkért tekintse meg a parancssori kimenetet, vagy olvassa el a Műveleti előzményeket.", + "Retry as administrator": "Újabb próba rendszergazdaként", + "Retry interactively": "Újabb próba interaktívan", + "Retry skipping integrity checks": "Kihagyott integritás ellenőrzések megismétlése", + "Installation options": "Telepítési lehetőségek", + "Save": "Ment", + "UniGetUI collects anonymous usage data with the sole purpose of understanding and improving the user experience.": "Az UniGetUI anonim használati adatokat gyűjt, kizárólag azzal a céllal, hogy megértse és javítsa a felhasználói élményt.", + "More details about the shared data and how it will be processed": "További részletek a megosztott adatokról és azok feldolgozásának módjáról", + "Do you accept that UniGetUI collects and sends anonymous usage statistics, with the sole purpose of understanding and improving the user experience?": "Elfogadja, hogy az UniGetUI anonim használati statisztikákat gyűjt és küld, kizárólag a felhasználói élmény megértése és javítása céljából?", + "Decline": "Elutasít", + "No personal information is collected nor sent, and the collected data is anonimized, so it can't be back-tracked to you.": "Nem gyűjtünk és nem küldünk személyes adatokat. Az összegyűjtött adatokat anonimizáljuk, így nem lehet visszavezetni Önhöz.", + "Navigation panel": "Navigációs panel", + "Operations": "Műveletek", + "Toggle operations panel": "Műveleti panel váltása", + "Bulk operations": "Tömeges műveletek", + "Retry failed": "Sikertelenek újrapróbálása", + "Clear successful": "Sikeresek törlése", + "Clear finished": "Befejezettek törlése", + "Cancel all": "Összes megszakítása", + "More": "További", + "Toggle navigation panel": "Navigációs panel váltása", + "Minimize": "Kis méretre állítás", + "Maximize": "Maximalizálás", + "UniGetUI by Devolutions": "UniGetUI – Devolutions", + "UniGetUI is an application that makes managing your software easier, by providing an all-in-one graphical interface for your command-line package managers.": "A UniGetUI egy olyan alkalmazás, amely megkönnyíti a szoftverek kezelését, mivel egy minden egyben grafikus felületet biztosít a parancssori csomagkezelők számára.\n", + "Useful links": "Hasznos linkek", + "UniGetUI Homepage": "UniGetUI honlapja", + "Report an issue or submit a feature request": "Jelentsen be egy problémát, vagy küldjön be egy funkció kérést", + "UniGetUI Repository": "UniGetUI adattára", + "View GitHub Profile": "GitHub profil megtekintése", + "UniGetUI License": "UniGetUI licenc", + "Using UniGetUI implies the acceptation of the MIT License": "A UniGetUI használata magában foglalja az MIT-licenc elfogadását", + "Become a translator": "Legyen fordító", + "Go back": "Vissza", + "Go forward": "Előre", + "Go to home page": "Ugrás a kezdőlapra", + "Reload page": "Oldal újratöltése", + "View page on browser": "Megtekintés böngészőben", + "The built-in browser is not supported on Linux yet.": "A beépített böngésző Linuxon még nem támogatott.", + "Open in browser": "Megnyitás böngészőben", + "Copy to clipboard": "Másol a vágólapra", + "Export to a file": "Exportál egy fájlba", + "Log level:": "Napló szint:", + "Reload log": "Napló újratöltése", + "Export log": "Napló exportálása", + "Text": "Szöveg", + "Change how operations request administrator rights": "A műveletek rendszergazdai jog igénylési módjának változtatása", + "Restrictions on package operations": "A csomagműveletekre vonatkozó korlátozások", + "Restrictions on package managers": "A csomagkezelőkre vonatkozó korlátozások", + "Restrictions when importing package bundles": "Korlátozások csomagkötegek importálásakor", + "Ask for administrator privileges once for each batch of operations": "Minden műveletköteghez egyszer kérjen rendszergazdai jogosultságot.", + "Ask only once for administrator privileges": "Csak egyszer kérjen rendszergazdai jogosultságokat", + "Prohibit any kind of Elevation via UniGetUI Elevator or GSudo": "Tiltsa meg az UniGetUI Elevator vagy GSudo segítségével történő bármilyen kiemelkedést", + "This option WILL cause issues. Any operation incapable of elevating itself WILL FAIL. Install/update/uninstall as administrator will NOT WORK.": "Ez az opció problémákat fog okozni. Minden olyan művelet, amely nem képes magát kiemelni, SIKERTELEN lesz. A rendszergazdaként történő telepítés/frissítés/eltávolítás NEM FOG MŰKÖDNI.", + "Allow custom command-line arguments": "Egyéni parancssori argumentumok engedélyezése", + "Custom command-line arguments can change the way in which programs are installed, upgraded or uninstalled, in a way UniGetUI cannot control. Using custom command-lines can break packages. Proceed with caution.": "Az egyéni parancssori argumentumok megváltoztathatják a programok telepítésének, frissítésének vagy eltávolításának módját, amit az UniGetUI nem tud ellenőrizni. Az egyéni parancssorok használata megrongálhatja a csomagokat. Kérjük, óvatosan járjon el.", + "Ignore custom pre-install and post-install commands when importing packages from a bundle": "Az egyéni telepítés előtti és utáni parancsok figyelmen kívül hagyása a csomagok kötegből történő importálásakor", + "Pre and post install commands will be run before and after a package gets installed, upgraded or uninstalled. Be aware that they may break things unless used carefully": "A telepítés előtti és utáni parancsok a csomag telepítése, frissítése vagy eltávolítása előtt és után futnak. Ne feledje, hogy ezek a parancsok óvatlan használat esetén károsíthatják a rendszert", + "Allow changing the paths for package manager executables": "Lehetővé teszi a csomagkezelő futtatható fájljainak elérési útvonal módosítását", + "Turning this on enables changing the executable file used to interact with package managers. While this allows finer-grained customization of your install processes, it may also be dangerous": "Ennek bekapcsolása lehetővé teszi a csomagkezelőkkel való interakcióhoz használt futtatható fájl megváltoztatását. Ez lehetővé teszi a telepítési folyamatok finomabb testreszabását, de veszélyes is lehet.", + "Allow importing custom command-line arguments when importing packages from a bundle": "Engedélyezze az egyéni parancssori argumentumok importálását, amikor csomagokat importál egy kötegből.", + "Malformed command-line arguments can break packages, or even allow a malicious actor to gain privileged execution. Therefore, importing custom command-line arguments is disabled by default": "A hibás parancssori argumentumok megrongálhatják a csomagokat, vagy akár lehetővé tehetik egy rosszindulatú szereplő számára, hogy kiváltságos végrehajtási jogokat szerezzen. Ezért az egyéni parancssori argumentumok importálása alapértelmezés szerint le van tiltva", + "Allow importing custom pre-install and post-install commands when importing packages from a bundle": "Egyéni előtelepítési és utótelepítési parancsok importálásának engedélyezése csomagok csomagból történő importálása esetén", + "Pre and post install commands can do very nasty things to your device, if designed to do so. It can be very dangerous to import the commands from a bundle, unless you trust the source of that package bundle": "A telepítés előtti és utáni parancsok nagyon kellemetlen dolgokat tehetnek a készülékkel, ha erre tervezték őket. Nagyon veszélyes lehet a parancsokat egy csomagból importálni, hacsak nem bízik a csomag forrásában", + "Administrator rights and other dangerous settings": "Rendszergazdai jogok és egyéb veszélyes beállítások", + "Package backup": "Csomag biztonsági mentése", + "Cloud package backup": "Felhőbeni csomag biztonsági mentés", + "Local package backup": "Helyi csomag biztonsági mentés", + "Local backup advanced options": "Helyi biztonsági mentés speciális beállításai", + "Log in with GitHub": "Bejelentkezés GitHub-fiókkal", + "Log out from GitHub": "Kijelentkezés a GitHubról", + "Periodically perform a cloud backup of the installed packages": "Rendszeresen végezzen felhő mentést a telepített csomagokról", + "Cloud backup uses a private GitHub Gist to store a list of installed packages": "A felhőmentés egy privát GitHub Gist-et használ a telepített csomagok listájának tárolására.", + "Perform a cloud backup now": "Végezzen felhőmentést most", + "Backup": "Biztonsági mentés", + "Restore a backup from the cloud": "Biztonsági mentés visszaállítása a felhőből", + "Begin the process to select a cloud backup and review which packages to restore": "Kezdje el a folyamatot a felhőalapú bizt. mentés kiválasztásához és a visszaállítandó csomagok áttekintéséhez.", + "Periodically perform a local backup of the installed packages": "Rendszeresen készítsen helyi biztonsági mentést a telepített csomagokról.", + "Perform a local backup now": "Helyi bizt. mentés végrehajtása most", + "Change backup output directory": "A biztonsági mentés kimeneti könyvtárának módosítása", + "Set a custom backup file name": "Egyéni mentési fájlnév beállítása", + "Leave empty for default": "Alapértékhez hagyja üresen", + "Add a timestamp to the backup file names": "Időbélyegző hozzáadása a mentési fájlnevekhez", + "Backup and Restore": "Bizt. mentés és Helyreállítás", + "Enable background api (UniGetUI Widgets and Sharing, port 7058)": "A háttér api engedélyezése (UniGetUI Widgets and Sharing, 7058-as port)", + "Wait for the device to be connected to the internet before attempting to do tasks that require internet connectivity.": "Várja meg, amíg a készülék csatlakozik az internethez, mielőtt kapcsolatot igénylő feladatokat próbálna végrehajtani.", + "Disable the 1-minute timeout for package-related operations": "Az 1 perces időkorlát kikapcsolása a csomaggal kapcsolatos műveleteknél", + "Use installed GSudo instead of UniGetUI Elevator": "A telepített GSudo használata az UniGetUI Elevator helyett", + "Use a custom icon and screenshot database URL": "Egyéni ikon és képernyőkép adatbázis URL használata", + "Enable background CPU Usage optimizations (see Pull Request #3278)": "Engedélyezze a CPU háttérben használat optimalizálását", + "Perform integrity checks at startup": "Integritás ellenőrzés végrehajtása indításkor", + "When batch installing packages from a bundle, install also packages that are already installed": "A csomagok kötegelt telepítésekor a már telepített csomagokat is telepíti.", + "Experimental settings and developer options": "Kísérleti beállítások és fejlesztői lehetőségek", + "Show UniGetUI's version and build number on the titlebar.": "Az UniGetUI-verzió megjelenítése a címsoron", + "Language": "Nyelv", + "UniGetUI updater": "UniGetUI frissítő", + "Telemetry": "Telemetria", + "Manage UniGetUI settings": "UniGetUI beállítások kezelése", + "Related settings": "Kapcsolódó beállítások", + "Update UniGetUI automatically": "A UniGetUI automatikus frissítése", + "Check for updates": "Frissítések ellenőrzése", + "Install prerelease versions of UniGetUI": "Az UniGetUI előzetes verzióinak telepítése", + "Manage telemetry settings": "Telemetriai beállítások kezelése", + "Manage": "Kezelés", + "Import settings from a local file": "Beállítások importálása helyi fájlból", + "Import": "Importálás", + "Export settings to a local file": "Beállítások exportálása helyi fájlba", + "Export": "Exportálás", + "Reset UniGetUI": "UniGetUI alapra állítása", + "User interface preferences": "A felhasználói felület beállításai", + "Application theme, startup page, package icons, clear successful installs automatically": "Alkalmazás téma, kezdőlap, csomag ikonok, sikeres telepítések automatikus törlése", + "General preferences": "Általános preferenciák", + "UniGetUI display language:": "UniGetUI megjelenítési nyelve:", + "System language": "Rendszernyelv", + "Is your language missing or incomplete?": "Hiányzik vagy hiányos az Ön nyelve?", + "Appearance": "Megjelenés", + "UniGetUI on the background and system tray": "UniGetUI a háttérben és a tálcán", + "Package lists": "Csomag listák", + "Use classic mode": "Klasszikus mód használata", + "Restart UniGetUI to apply this change": "Indítsa újra az UniGetUI-t a módosítás alkalmazásához", + "The classic UI is disabled for beta testers": "A klasszikus felület le van tiltva a bétatesztelők számára", + "Close UniGetUI to the system tray": "Az UniGetUI bezárása a tálcára", + "Manage UniGetUI autostart behaviour": "Az UniGetUI automatikus indítási viselkedésének kezelése", + "Show package icons on package lists": "Csomag ikonok megjelenítése a csomaglistákon", + "Clear cache": "Gyors.tár törlése", + "Select upgradable packages by default": "Alapértelmezés szerint frissíthető csomagok kiválasztása", + "Light": "Világos", + "Dark": "Sötét", + "Follow system color scheme": "Kövesse a rendszer színsémáját", + "Application theme:": "Alkalmazás téma:", + "UniGetUI startup page:": "UniGetUI kezdőlap:", + "Proxy settings": "Proxy beállításai", + "Other settings": "Egyéb beállítások", + "Connect the internet using a custom proxy": "Csatlakozás az internethez egyéni proxy használatával", + "Please note that not all package managers may fully support this feature": "Vegye figyelembe, hogy nem minden csomagkezelő támogatja teljes mértékben ezt a funkciót.", + "Proxy URL": "Proxy URL-cím", + "Enter proxy URL here": "Adja meg a Proxy URL-t", + "Authenticate to the proxy with a user and a password": "Hitelesítés a proxyn felhasználónévvel és jelszóval", + "Internet and proxy settings": "Internet- és proxybeállítások", + "Package manager preferences": "Csomagkezelő preferenciái", + "Ready": "Kész", + "Not found": "Nem található", + "Notification preferences": "Értesítési beállítások", + "Notification types": "Értesítés típusai", + "The system tray icon must be enabled in order for notifications to work": "Az értesítések működéséhez engedélyezni kell a tálcaikont.", + "Enable UniGetUI notifications": "UniGetUI értesítések engedélyezése", + "Show a notification when there are available updates": "Értesítés megjelenítése, ha elérhető frissítések vannak", + "Show a silent notification when an operation is running": "Csendes értesítés megjelenítése, amikor egy művelet fut", + "Show a notification when an operation fails": "Értesítés megjelenítése, ha egy művelet sikertelen", + "Show a notification when an operation finishes successfully": "Értesítés megjelenítése, ha egy művelet sikeresen befejeződik", + "Concurrency and execution": "Egyidejűség és végrehajtás", + "Automatic desktop shortcut remover": "Automatikus asztali parancsikon eltávolító", + "Choose how many operations should be performed in parallel": "Válassza ki, hány művelet fusson párhuzamosan", + "Clear successful operations from the operation list after a 5 second delay": "A sikeres műveletek törlése a műveleti listából 5 mp késleltetés után.", + "Download operations are not affected by this setting": "A letöltési műveleteket ez a beállítás nem befolyásolja", + "You may lose unsaved data": "Elveszítheti a nem mentett adatokat", + "Ask to delete desktop shortcuts created during an install or upgrade.": "A telepítés vagy frissítés során létrehozott asztali parancsikonok törlésének kérése.", + "Package update preferences": "Csomag frissítési preferenciái", + "Update check frequency, automatically install updates, etc.": "Frissítések ellenőrz. gyakorisága, frissítések autom. telepítése, stb.", + "Reduce UAC prompts, elevate installations by default, unlock certain dangerous features, etc.": "Az UAC-kérelmek csökkentése, a telepítések alapértelmezett kiemelése, bizonyos veszélyes funkciók feloldása stb.", + "Package operation preferences": "Csomag működési preferenciái", + "Enable {pm}": "{pm} engedélyezése", + "Not finding the file you are looking for? Make sure it has been added to path.": "Nem találja a keresett fájlt? Győződjön meg róla, hogy hozzáadta az elérési útvonalhoz.", + "Select the executable to be used. The following list shows the executables found by UniGetUI": "Válassza ki a használni kívánt végrehajtható fájlt. Az alábbi lista az UniGetUI által talált végrehajtható fájlokat tartalmazza", + "For security reasons, changing the executable file is disabled by default": "Biztonsági okokból a futtatható fájl módosítása alapértelmezés szerint le van tiltva.", + "Change this": "Változtassa meg ezt", + "Copy path": "Útvonal másolása", + "Current executable file:": "Jelenlegi futtatható fájl:", + "Ignore packages from {pm} when showing a notification about updates": "A {pm} csomagok figyelmen kívül hagyása a frissítésekről szóló értesítés megjelenítésekor", + "Update security": "Frissítési biztonság", + "Use global setting": "Globális beállítás használata", + "Minimum age for updates": "A frissítések minimális életkora", + "e.g. 10": "pl. 10", + "Custom minimum age (days)": "Egyéni minimális életkor (nap)", + "{pm} does not provide release dates for its packages, so this setting will have no effect": "{pm} nem biztosít kiadási dátumot a csomagjaihoz, ezért ennek a beállításnak nem lesz hatása", + "{pm} only provides release dates for some of its packages, so this setting will only apply to those packages": "A(z) {pm} csak néhány csomagjához ad meg kiadási dátumot, ezért ez a beállítás csak ezekre a csomagokra lesz érvényes", + "Override the global minimum update age for this package manager": "A globális minimális frissítési életkor felülbírálása ennél a csomagkezelőnél", + "View {0} logs": "{0} naplók megtekintése", + "If Python cannot be found or is not listing packages but is installed on the system, ": "Ha a Python nem található, vagy nem listáz csomagokat, de telepítve van a rendszeren, ", + "Advanced options": "Haladó beállítások", + "WinGet command-line tool": "WinGet parancssori eszköz", + "Choose which command-line tool UniGetUI uses for WinGet operations when the COM API is not used": "Válassza ki, melyik parancssori eszközt használja az UniGetUI a WinGet-műveletekhez, ha a COM API nincs használatban", + "WinGet COM API": "WinGet COM API", + "Choose whether UniGetUI can use the WinGet COM API before falling back to the command-line tool": "Válassza ki, hogy az UniGetUI használhatja-e a WinGet COM API-t, mielőtt visszatérne a parancssori eszközhöz", + "Reset WinGet": "WinGet alapra állítása", + "This may help if no packages are listed": "Ez segíthet, ha nincsenek csomagok a listában", + "Force install location parameter when updating packages with custom locations": "A telepítési hely paraméterének kényszerítése az egyéni helyre telepített csomagok frissítésekor", + "Install Scoop": "Scoop telepítés", + "Uninstall Scoop (and its packages)": "A Scoop (és csomagjai) eltávolítása", + "Run cleanup and clear cache": "Futtassa a tisztítást és törölje a gyorsítótárat", + "Run": "Futtat", + "Enable Scoop cleanup on launch": "Scoop tisztítás engedélyezése indításkor", + "Default vcpkg triplet": "Alapértelmezett vcpkg triplet", + "Change vcpkg root location": "A vcpkg gyökérhelyének módosítása", + "Reset vcpkg root location": "A vcpkg gyökérkönyvtár helyének visszaállítása", + "Open vcpkg root location": "A vcpkg gyökérkönyvtár megnyitása", + "Language, theme and other miscellaneous preferences": "Nyelv, téma és más egyéb beállítások", + "Show notifications on different events": "Értesítések megjelenítése különböző eseményekről", + "Change how UniGetUI checks and installs available updates for your packages": "Az UniGetUI csomagok elérhető frissítései ellenőrzésének és telepítési módjának módosítása", + "Automatically save a list of all your installed packages to easily restore them.": "Autom. elmenti az összes telepített csomag listáját, hogy könnyen visszaállíthassa azokat.", + "Enable and disable package managers, change default install options, etc.": "Csomagkezelők engedélyezése és letiltása, alapért. telepítési beállítások módosítása, stb.", + "Internet connection settings": "Internet kapcsolat beállításai", + "Proxy settings, etc.": "Proxy beállítások, stb.", + "Beta features and other options that shouldn't be touched": "Béta funkciók és egyéb opciók, amelyekhez nem szabadna hozzányúlni", + "Reload sources": "Források újratöltése", + "Delete source": "Forrás törlése", + "Known sources": "Ismert források", + "Update checking": "Frissítés ellenőrzése", + "Automatic updates": "Autom. frissítések", + "Check for package updates periodically": "Rendszeresen ellenőrizze a csomag frissítéseit", + "Check for updates every:": "Ellenőrzés gyakorisága:", + "Install available updates automatically": "A rendelkezésre álló frissítések automatikus telepítése", + "Do not automatically install updates when the network connection is metered": "Ne telepítse autom. a frissítéseket, ha a hálózati kapcsolat nem korlátlan.", + "Do not automatically install updates when the device runs on battery": "Ne telepítsen autom. frissítéseket, amikor az eszköz akkuról üzemel", + "Do not automatically install updates when the battery saver is on": "Ne telepítse autom. a frissítéseket, ha az akkukímélő funkció be van kapcsolva.", + "Only show updates that are at least the specified number of days old": "Csak azokat a frissítéseket jelenítse meg, amelyek legalább a megadott számú naposak", + "Warn me when the installer URL host changes between the installed version and the new version (WinGet only)": "Figyelmeztessen, ha a telepítő URL-jének gazdagépe megváltozik a telepített és az új verzió között (csak WinGet esetén)", + "Change how UniGetUI handles install, update and uninstall operations.": "Módosíthatja, hogy az UniGetUI miként kezelje a telepítési, frissítési és eltávolítási műveleteket.", + "Navigation": "Navigáció", + "Check for UniGetUI updates": "UniGetUI-frissítések keresése", + "Quit UniGetUI": "Kilépés az UniGetUI-ból", + "Filters": "Szűrők", + "Sources": "Források", + "Search for packages to start": "Csomagok keresése a kezdéshez", + "Select all": "Mindet kiválaszt", + "Clear selection": "Kiválasztás törlése", + "Instant search": "Azonnali keresés", + "Distinguish between uppercase and lowercase": "Tegyen különbséget a kis- és nagybetűk között", + "Ignore special characters": "Speciális karakterek figyelmen kívül hagyása", + "Search mode": "Keresési mód", + "Both": "Mindkettő", + "Exact match": "Pontos egyezés", + "Show similar packages": "Hasonló csomagok megjelenítése", + "Loading": "Betöltés", + "Package": "Csomag", + "More options": "További lehetőségek", + "Order by:": "Rendezés:", + "Name": "Név", + "Id": "Azonosító", + "Ascendant": "Növekvő", + "Descendant": "Utód", + "View modes": "Nézetmódok", + "Reload": "Újratöltés", + "Closed": "Bezárva", + "Ascending": "Növekvő", + "Descending": "Csökkenő", + "{0}: {1}, {2}": "{0}: {1}, {2}", + "Order by": "Rendezés", + "No results were found matching the input criteria": "Nincs találat a beviteli feltételeknek megfelelő eredményre", + "No packages were found": "Nem találtunk csomagokat", + "Loading packages": "Csomagok betöltése", + "Skip integrity checks": "Integritás ellenőrzések kihagyása", + "Download selected installers": "Kiválasztott telepítők letöltése", + "Install selection": "Telepítés kiválasztása", + "Install options": "Telepítési lehetőségek", + "Add selection to bundle": "Kijelölés hozzáadása a köteghez", + "Download installer": "Telepítő letöltése", + "Uninstall selection": "Kiválasztott eltávolítása", + "Uninstall options": "Eltávolítás lehetőségei", + "Ignore selected packages": "Kiválasztott csomagok figyelmen kívül hagyása", + "Open install location": "Telepítés helyének megnyitása", + "Reinstall package": "Csomag újratelepítés", + "Uninstall package, then reinstall it": "Távolítsa el a csomagot, majd telepítse újra", + "Ignore updates for this package": "Hagyja figyelmen kívül a csomag frissítéseit", + "WinGet malfunction detected": "WinGet hibás működés észlelve", + "It looks like WinGet is not working properly. Do you want to attempt to repair WinGet?": "Úgy tűnik, a WinGet nem működik megfelelően. Megpróbálja kijavítani a WinGet-et?", + "Repair WinGet": "WinGet javítása", + "Updates will no longer be ignored for {0}": "A frissítések többé nem lesznek figyelmen kívül hagyva a következőnél: {0}", + "Updates are now ignored for {0}": "A frissítések mostantól figyelmen kívül vannak hagyva a következőnél: {0}", + "Do not ignore updates for this package anymore": "Többé ne hagyja figyelmen kívül a csomag frissítéseit", + "Add packages or open an existing package bundle": "\nCsomagok hozzáadása vagy egy meglévő csomag köteg megnyitása", + "Add packages to start": "Adjon hozzá csomagokat az indításhoz", + "The current bundle has no packages. Add some packages to get started": "Az aktuális köteg nem tartalmaz csomagokat. A kezdéshez adjon hozzá néhány csomagot", + "New": "Új", + "Save as": "Ment, mint", + "Create .ps1 script": ".ps1 szkript létrehozása", + "Remove selection from bundle": "A kiválasztás eltávolítása a kötegből", + "Skip hash checks": "Hash ellenőrzések kihagyása", + "The package bundle is not valid": "A csomag köteg nem érvényes", + "The bundle you are trying to load appears to be invalid. Please check the file and try again.": "A köteg amelyet be akar tölteni, érvénytelennek tűnik. Ellenőrizze a fájlt, és próbálja meg újra.", + "Package bundle": "Csomag köteg", + "Could not create bundle": "Nem sikerült létrehozni a köteget", + "The package bundle could not be created due to an error.": "A csomag köteget hiba miatt nem sikerült létrehozni.", + "Install script": "Telepítő script", + "PowerShell script": "PowerShell-szkript", + "The installation script saved to {0}": "A telepítő szkript mentve a következő helyre: {0}", + "An error occurred": "Hiba történt", + "An error occurred while attempting to create an installation script:": "Hiba történt a telepítési szkript létrehozása közben:", + "Hooray! No updates were found.": "Minden rendben! Nincs több frissítés!", + "Uninstall selected packages": "A kiválasztott csomagok eltávolítása", + "Update selection": "Kiválasztott frissítése", + "Update options": "Frissítés lehetőségei", + "Uninstall package, then update it": "Távolítsa el a csomagot, majd frissítse azt", + "Uninstall package": "Csomag eltávolítása", + "Skip this version": "Hagyja ki ezt a verziót", + "Pause updates for": "Frissítései szüneteltetése", + "User | Local": "Felhasználó | Helyi", + "Machine | Global": "Gép | Globális", + "The default package manager for Debian/Ubuntu-based Linux distributions.
Contains: Debian/Ubuntu packages": "Az alapértelmezett csomagkezelő Debian/Ubuntu-alapú Linux disztribúciókhoz.
Tartalmaz: Debian/Ubuntu csomagok", + "The Rust package manager.
Contains: Rust libraries and programs written in Rust": "A Rust csomagkezelő.
Tartalma: Rust könyvtárak és Rust nyelven írt programok ", + "The classical package manager for windows. You'll find everything there.
Contains: General Software": "\nA klasszikus csomagkezelő Windowshoz. Mindent megtalálsz benne.
Tartalma: Általános szoftverek", + "The default package manager for RHEL/Fedora-based Linux distributions.
Contains: RPM packages": "Az alapértelmezett csomagkezelő RHEL/Fedora-alapú Linux disztribúciókhoz.
Tartalmaz: RPM csomagok", + "A repository full of tools and executables designed with Microsoft's .NET ecosystem in mind.
Contains: .NET related tools and scripts": "A Microsoft .NET ökoszisztémára tervezett eszközök és futtatható fájlok tárháza.
Tatalma: .NET kapcsolódó eszközök és szkriptek\n", + "The universal Linux package manager for desktop applications.
Contains: Flatpak applications from configured remotes": "Az asztali alkalmazások univerzális Linux csomagkezelője.
Tartalmaz: Flatpak alkalmazások konfigurált távoli forrásokból", + "NuPkg (zipped manifest)": "NuPkg (tömörített manifeszt)", + "The Missing Package Manager for macOS (or Linux).
Contains: Formulae, Casks": "A hiányzó csomagkezelő macOS-hez (vagy Linuxhoz).
Tartalmaz: Formulae, Casks", + "Node JS's package manager. Full of libraries and other utilities that orbit the javascript world
Contains: Node javascript libraries and other related utilities": "A Node JS csomagkezelője. Tele van könyvtárakkal és egyéb segédprogramokkal, amelyek a javascript világában keringenek
Tartalma: Node javascript könyvtárak és egyéb kapcsolódó segédprogramok", + "The default package manager for Arch Linux and its derivatives.
Contains: Arch Linux packages": "Az alapértelmezett csomagkezelő az Arch Linux és származékai számára.
Tartalmaz: Arch Linux csomagok", + "Python's library manager. Full of python libraries and other python-related utilities
Contains: Python libraries and related utilities": "A Python könyvtárkezelője. Tele van python könyvtárakkal és egyéb pythonhoz kapcsolódó segédprogramokkal
Tartalma: Python könyvtárak és kapcsolódó segédprogramok", + "PowerShell's package manager. Find libraries and scripts to expand PowerShell capabilities
Contains: Modules, Scripts, Cmdlets": "A PowerShell csomagkezelője. A PowerShell képességeit bővítő könyvtárak és szkriptek keresése
Tartalma: Modulok, szkriptek, parancsfájlok\n", + "extracted": "kivont", + "Scoop package": "Scoop csomag", + "Great repository of unknown but useful utilities and other interesting packages.
Contains: Utilities, Command-line programs, General Software (extras bucket required)": "Ismeretlen, de hasznos segédprogramok és más érdekes csomagok nagyszerű tárháza.
Tartalma: Segédprogramok, Parancssoros programok, Általános szoftverek (extra bucket szükséges)", + "The universal Linux package manager by Canonical.
Contains: Snap packages from the Snapcraft store": "A Canonical univerzális Linux csomagkezelője.
Tartalmaz: Snap csomagok a Snapcraft áruházból", + "library": "könyvtár", + "feature": "funkció", + "A popular C/C++ library manager. Full of C/C++ libraries and other C/C++-related utilities
Contains: C/C++ libraries and related utilities": "Egy népszerű C/C++ könyvtár kezelő. Tele van C/C++ könyvtárakkal és egyéb C/C++hoz kapcsolódó segésprogramokkal
Tartalma: C/C++ könyvtárak és kapcsolódó segépdprogramok", + "option": "opció", + "This package cannot be installed from an elevated context.": "Ez a csomag nem telepíthető emelt szintű környezetből.", + "Please run UniGetUI as a regular user and try again.": "Kérjük futtassa az UniGetUI-t normál felhasználóként, és próbálja meg újra.", + "Please check the installation options for this package and try again": "Kérjük ellenőrizze a csomag telepítési beállításait, és próbálja meg újra.", + "Microsoft's official package manager. Full of well-known and verified packages
Contains: General Software, Microsoft Store apps": "A Microsoft hivatalos csomagkezelője. Tele van jól ismert és ellenőrzött csomagokkal
Tartalma: <Általános szoftverek, Microsoft Store alkalmazások
.", + "Local PC": "Helyi PC", + "Android Subsystem": "Android Alrendszer", + "Operation on queue (position {0})...": "A művelet a várólistán ({0}. pozíció)...", + "Click here for more details": "Kattintson további részletekért", + "Operation canceled by user": "Felhasználó által törölt művelet", + "Running PreOperation ({0}/{1})...": "A PreOperation futtatása ({0}/{1})...", + "PreOperation {0} out of {1} failed, and was tagged as necessary. Aborting...": "A(z) {1}-ből {0}. PreOperation meghiúsult, és szükségesként volt megjelölve. Megszakítás...", + "PreOperation {0} out of {1} finished with result {2}": "A(z) {1}-ből {0}. PreOperation {2} eredménnyel fejeződött be", + "Starting operation...": "Művelet indítása...", + "Running PostOperation ({0}/{1})...": "A PostOperation futtatása ({0}/{1})...", + "PostOperation {0} out of {1} failed, and was tagged as necessary. Aborting...": "A(z) {1}-ből {0}. PostOperation meghiúsult, és szükségesként volt megjelölve. Megszakítás...", + "PostOperation {0} out of {1} finished with result {2}": "A(z) {1}-ből {0}. PostOperation {2} eredménnyel fejeződött be", + "{package} installer download": "{package} a telepítő letöltése", + "{0} installer is being downloaded": "{0} telepítő letöltése folyamatban van", + "Download succeeded": "A letöltés sikeres volt", + "{package} installer was downloaded successfully": "{package} a telepítő sikeresen letöltődött", + "Download failed": "Sikertelen letöltés", + "{package} installer could not be downloaded": "{package} a telepítőt nem lehetett letölteni", + "{package} Installation": "{package} Telepítés", + "{0} is being installed": "{0} telepítés alatt áll", + "Installation succeeded": "A telepítés sikeres volt", + "{package} was installed successfully": "{package} telepítése sikeresen megtörtént", + "Installation failed": "Sikertelen telepítés", + "{package} could not be installed": "{package} nem tudott települni", + "{package} Update": "{package} Frissítés", + "Update succeeded": "A frissítés sikeres volt", + "{package} was updated successfully": "{package} sikeresen frissítve", + "Update failed": "A frissítés sikertelen", + "{package} could not be updated": "{package} nem tudott frissülni", + "{package} Uninstall": "{package} Eltávolítás", + "{0} is being uninstalled": "{0} eltávolításra kerül", + "Uninstall succeeded": "Az eltávolítás sikeres volt", + "{package} was uninstalled successfully": "{package} eltávolítása sikeresen megtörtént", + "Uninstall failed": "Az eltávolítás sikertelen", + "{package} could not be uninstalled": "{package} nem lehetett eltávolítani", + "Adding source {source}": "Forrás hozzáadása {source}", + "Adding source {source} to {manager}": "Forrás hozzáadása {source} ide {manager}", + "Source added successfully": "Forrás sikeresen hozzáadva", + "The source {source} was added to {manager} successfully": "A forrás {source} sikeresen hozzá lett adva {manager}.", + "Could not add source": "Nem tudta felvenni a forrást", + "Could not add source {source} to {manager}": "Nem sikerült hozzáadni a forrást {source} a kezelőhöz {manager}", + "Removing source {source}": "Forrás eltávolítása {source}", + "Removing source {source} from {manager}": "A forrás {source} eltávolítása innen {manager}", + "Source removed successfully": "Forrás sikeresen eltávolítva", + "The source {source} was removed from {manager} successfully": "A {source} forrás sikeresen eltávolítva innen {manager}", + "Could not remove source": "Nem tudta eltávolítani a forrást", + "Could not remove source {source} from {manager}": "Nem sikerült eltávolítani a forrást {source} a kezelőből {manager}", + "The package manager \"{0}\" was not found": "A \"{0}\" csomagkezelőt nem találtuk meg.", + "The package manager \"{0}\" is disabled": "A \"{0}\" csomagkezelő le van tiltva", + "There is an error with the configuration of the package manager \"{0}\"": "Hiba van a \"{0}\" csomagkezelő konfigurációjával.", + "The package \"{0}\" was not found on the package manager \"{1}\"": "A \"{0}\" csomagot nem találta a \"{1}\" csomagkezelő.", + "{0} is disabled": "{0} le van tiltva", + "{0} weeks": "{0} hét", + "1 month": "1 hónap", + "{0} months": "{0} hónap", + "Something went wrong": "Valami nincs rendben", + "An interal error occurred. Please view the log for further details.": "Belső hiba történt. További részletekért tekintse meg a naplót.", + "No applicable installer was found for the package {0}": "Nem találtunk megfelelő telepítőt a {0} csomaghoz", + "Integrity checks will not be performed during this operation": "A művelet során nem kerül sor integritás ellenőrzésekre.", + "This is not recommended.": "Ez nem ajánlott.", + "Run now": "Futtatás most", + "Run next": "Futtatás következőnek", + "Run last": "Futtatás utoljára", + "Show in explorer": "Megjelenítés a keresőben", + "Checked": "Bejelölve", + "Unchecked": "Nincs bejelölve", + "This package is already installed": "Ez a csomag már telepítve van", + "This package can be upgraded to version {0}": "Ez a csomag frissíthető a {0} verzióra.", + "Updates for this package are ignored": "A csomag frissítései figyelmen kívül maradnak", + "This package is being processed": "Ez a csomag feldolgozás alatt áll", + "This package is not available": "Ez a csomag nem elérhető", + "Select the source you want to add:": "Válassza ki a hozzáadni kívánt forrást:", + "Source name:": "Forrás neve:", + "Source URL:": "Forrás URL:", + "An error occurred when adding the source: ": "Hiba történt a forrás hozzáadásakor:", + "Package management made easy": "Csomagkezelés egyszerűen", + "version {0}": "verzió {0}", + "[RAN AS ADMINISTRATOR]": "RENDSZERGAZDAKÉNT FUTOTT", + "Portable mode": "Hordozható mód", + "DEBUG BUILD": "HIBAKERESŐ VERZIÓ", + "Here you can change UniGetUI's behaviour regarding the following shortcuts. Checking a shortcut will make UniGetUI delete it if if gets created on a future upgrade. Unchecking it will keep the shortcut intact": "Itt módosíthatja az UniGetUI viselkedését a következő parancsikonokkal kapcsolatban. Ha bejelöl egy parancsikont, akkor az UniGetUI törölni fogja azt, ha egy későbbi frissítéskor létrejön. Ha nem jelöli ki, a parancsikon érintetlenül marad.", + "Manual scan": "Kézi vizsgálat", + "Existing shortcuts on your desktop will be scanned, and you will need to pick which ones to keep and which ones to remove.": "Az asztalon meglévő parancsikonok átvizsgálásra kerülnek és ki kell választania, melyiket szeretné megtartani vagy eltávolítani.", + "Delete?": "Törli?", + "I understand": "Megértettem", + "Chocolatey setup changed": "A Chocolatey beállítása megváltozott", + "UniGetUI no longer includes its own private Chocolatey installation. A legacy UniGetUI-managed Chocolatey installation was detected for this user profile, but system Chocolatey was not found. Chocolatey will stay unavailable in UniGetUI until Chocolatey is installed on the system and UniGetUI is restarted. Applications previously installed through UniGetUI's bundled Chocolatey may still appear under other sources such as Local PC or WinGet.": "A UniGetUI többé nem tartalmaz saját privát Chocolatey-telepítést. Egy korábbi, UniGetUI által kezelt Chocolatey-telepítés észlelve lett ennél a felhasználói profilnál, de a rendszerszintű Chocolatey nem található. A Chocolatey mindaddig nem lesz elérhető a UniGetUI-ban, amíg a Chocolatey telepítésre nem kerül a rendszerre és a UniGetUI újra nem indul. A korábban a UniGetUI beépített Chocolatey-jával telepített alkalmazások továbbra is megjelenhetnek más forrásokban, például a Helyi PC-ben vagy a WinGet-ben.", + "NOTE: This troubleshooter can be disabled from UniGetUI Settings, on the WinGet section": "MEGJEGYZÉS: Ez a hibaelhárító kikapcsolható az UniGetUI beállításai között, a WinGet szakaszban.", + "Restart": "Újraindítás", + "Are you sure you want to delete all shortcuts?": "Biztos, hogy az összes parancsikont törölni szeretné?", + "Any new shorcuts created during an install or an update operation will be deleted automatically, instead of showing a confirmation prompt the first time they are detected.": "A telepítés vagy frissítés során létrehozott új parancsikonok auto. törlődnek, ahelyett, hogy az első észlelésükkor megerősítést kérnének.", + "Any shorcuts created or modified outside of UniGetUI will be ignored. You will be able to add them via the {0} button.": "Az UniGetUI-n kívül létrehozott vagy módosított parancsikonok figyelmen kívül maradnak. Ezeket a {0} gombon keresztül tudja majd hozzáadni.", + "Are you really sure you want to enable this feature?": "Tényleg biztosan engedélyezni szeretné ezt a funkciót?", + "No new shortcuts were found during the scan.": "A vizsgálat során nem találtunk új parancsikonokat.", + "How to add packages to a bundle": "Csomagok hozzáadása egy köteghez", + "In order to add packages to a bundle, you will need to: ": "Ahhoz, hogy csomagokat adjon hozzá egy köteghez, a következőkre van szüksége:", + "1. Navigate to the \"{0}\" or \"{1}\" page.": "1. Navigáljon a \"{0}\" vagy \"{1}\" oldalra.", + "2. Locate the package(s) you want to add to the bundle, and select their leftmost checkbox.": "2. Keresse meg a köteghez hozzáadni kívánt csomago(ka)t, és jelölje be a bal oldali jelölőnégyzetet.", + "3. When the packages you want to add to the bundle are selected, find and click the option \"{0}\" on the toolbar.": "3. Amikor a köteghez hozzáadni kívánt csomagok ki vannak jelölve, keresse meg az eszköztáron a \"{0}\" opciót, és kattintson rá.", + "4. Your packages will have been added to the bundle. You can continue adding packages, or export the bundle.": "4. A köteghez hozzáadásra kerülnek a csomagok. Folytathatja a csomagok hozzáadását, vagy exportálhatja a csomagot.", + "Which backup do you want to open?": "Melyik biztonsági mentést szeretné megnyitni?", + "Select the backup you want to open. Later, you will be able to review which packages you want to install.": "Válassza ki a megnyitni kívánt biztonsági másolatot. Később áttekintheti, hogy mely csomagokat/programokat szeretné visszaállítani.", + "There are ongoing operations. Quitting UniGetUI may cause them to fail. Do you want to continue?": "Folyamatban vannak műveletek. A UniGetUI elhagyása ezek meghibásodását okozhatja. Folytatni szeretné?", + "UniGetUI or some of its components are missing or corrupt.": "Az UniGetUI vagy annak egyes összetevői hiányoznak vagy sérültek.", + "It is strongly recommended to reinstall UniGetUI to adress the situation.": "Erősen ajánlott az UniGetUI újratelepítése a probléma megoldása érdekében.", + "Refer to the UniGetUI Logs to get more details regarding the affected file(s)": "Az érintett fájl(okk)al kapcsolatos további részletekért lásd az UniGetUI naplófájlokat", + "Integrity checks can be disabled from the Experimental Settings": "Az integritás-ellenőrzések letilthatók a Kísérleti beállítások menüpontban", + "Repair UniGetUI": "Az UniGetUI javítása", + "Live output": "Élő kimenet", + "This package bundle had some settings that are potentially dangerous, and may be ignored by default.": "Ez a csomag köteg tartalmazott néhány potenciálisan veszélyes beállítást, amelyeket alapértelmezés szerint figyelmen kívül lehet hagyni.", + "Entries that show in YELLOW will be IGNORED.": "A SÁRGA színnel jelölt bejegyzések figyelmen kívül maradnak.", + "Entries that show in RED will be IMPORTED.": "A PIROS bejegyzések IMPORTÁLVA lesznek.", + "You can change this behavior on UniGetUI security settings.": "Ezt a viselkedést megváltoztathatja az UniGetUI biztonsági beállításainál.", + "Open UniGetUI security settings": "UniGetUI biztonsági beállítások megnyitása", + "Should you modify the security settings, you will need to open the bundle again for the changes to take effect.": "Ha módosítja a biztonsági beállításokat, újra meg kell nyitnia a csomagot, hogy a módosítások hatályba lépjenek.", + "Details of the report:": "A jelentés részletei:", + "Are you sure you want to create a new package bundle? ": "Biztos, hogy új csomag köteget szeretne létrehozni?", + "Any unsaved changes will be lost": "Minden el nem mentett módosítás elveszik", + "Warning!": "Figyelem!", + "For security reasons, custom command-line arguments are disabled by default. Go to UniGetUI security settings to change this. ": "Biztonsági okokból az egyéni parancssori argumentumok alapértelmezés szerint le vannak tiltva. Ennek megváltoztatásához lépjen az UniGetUI biztonsági beállításaihoz.", + "Change default options": "Alapért. beállítások módosítása", + "Ignore future updates for this package": "A csomag jövőbeli frissítéseit hagyja figyelmen kívül", + "For security reasons, pre-operation and post-operation scripts are disabled by default. Go to UniGetUI security settings to change this. ": "Biztonsági okokból a művelet előtti és utáni szkriptek alapértelmezés szerint le vannak tiltva. Ennek megváltoztatásához lépjen az UniGetUI biztonsági beállításaihoz.", + "You can define the commands that will be run before or after this package is installed, updated or uninstalled. They will be run on a command prompt, so CMD scripts will work here.": "Meghatározhatja azokat a parancsokat, amelyek a csomag telepítése, frissítése vagy eltávolítása előtt vagy után futnak. Ezek a parancsok egy parancssorban fognak futni, így a CMD szkriptek itt is működni fognak.", + "Change this and unlock": "Változtassa meg és oldja fel ezt", + "{0} Install options are currently locked because {0} follows the default install options.": " {0} telepítési beállításai jelenleg zárolva vannak, mivel {0} követi az alapért. telepítési beállításokat.", + "Unset or unknown": "Be nem állított vagy ismeretlen", + "This package has no screenshots or is missing the icon? Contrbute to UniGetUI by adding the missing icons and screenshots to our open, public database.": "Ez a csomag nem rendelkezik képernyőképekkel, esetleg hiányzik az ikon? Segítsen a UniGetUI-nak a hiányzó ikonok és képernyőképek hozzáadásával a nyílt, nyilvános adatbázisunkhoz.\n", + "Become a contributor": "Legyen közreműködő", + "Update to {0} available": "Frissítés - {0} elérhető", + "Reinstall": "Újratelepítés", + "Installer not available": "Telepítő nem érhető el", + "Version:": "Verzió:", + "UniGetUI Version {0}": "UniGetUI verzió {0}", + "Performing backup, please wait...": "Biztonsági mentés végrehajtása, kis türelmet...", + "An error occurred while logging in: ": "Hiba történt a bejelentkezés során:", + "Fetching available backups...": "Elérhető biztonsági mentések lekérése...", + "Done!": "Kész!", + "The cloud backup has been loaded successfully.": "A felhőalapú biztonsági mentés sikeresen betöltődött.", + "An error occurred while loading a backup: ": "Hiba történt a biztonsági mentés betöltése közben:", + "Backing up packages to GitHub Gist...": "Csomagok bizt. mentése a GitHub Gistre...", + "Backup Successful": "A biztonsági mentés sikeres", + "The cloud backup completed successfully.": "A felhőalapú biztonsági mentés sikeresen befejeződött.", + "Could not back up packages to GitHub Gist: ": "Nem sikerült biztonsági másolatot készíteni a csomagokról a GitHub Gistre:", + "It is not guaranteed that the provided credentials will be stored safely, so you may as well not use the credentials of your bank account": "Nem garantált, hogy a megadott hitelesítő adatokat biztonságosan tárolják, így akár ne is használja a bankszámlája hitelesítő adatait.", + "Enable the automatic WinGet troubleshooter": "Az autom. WinGet hibaelhárítás engedélyezése", + "Add updates that fail with a 'no applicable update found' to the ignored updates list": "A 'nem található megfelelő frissítés' hibaüzenettel sikertelen frissítések hozzáadása a figyelmen kívül hagyott frissítések listájához", + "Invalid selection": "Érvénytelen kijelölés", + "No package was selected": "Nincs kiválasztva csomag", + "More than 1 package was selected": "Több mint 1 csomag lett kiválasztva", + "List": "Lista", + "Grid": "Rács", + "Icons": "Ikonok", + "\"{0}\" is a local package and does not have available details": "\"{0}\" egy helyi csomag és nem rendelkezik elérhető részletekkel", + "\"{0}\" is a local package and is not compatible with this feature": "\"{0}\" egy helyi csomag, és nem kompatibilis ezzel a funkcióval.", + "Add packages to bundle": "Csomagok hozzáadása a köteghez", + "Preparing packages, please wait...": "Csomagok előkészítése, kis türelmet...", + "Loading packages, please wait...": "Csomagok betöltése, kis türelmet...", + "Saving packages, please wait...": "Csomagok mentése, kis türelmet...", + "The bundle was created successfully on {0}": "A csomag sikeresen létrehozásra került itt {0}", + "User profile": "Felhasználói profil", + "Error": "Hiba", + "Log in failed: ": "Sikertelen bejelentkezés:", + "Log out failed: ": "A kijelentkezés sikertelen:", + "Package backup settings": "Csomag bizt. mentés beállításai", + "Manage UniGetUI autostart behaviour from the Settings app": "A UniGetUI automatikus indításának kezelése", + "Choose how many operations shoulds be performed in parallel": "Válassza ki, hány művelet fusson párhuzamosan", + "Something went wrong while launching the updater.": "Valamilyen hiba történt a frissítő indítása közben.", + "Please try again later": "Kérjük próbálja később újra", + "Show the release notes after UniGetUI is updated": "Kiadási megjegyzések megjelenítése a UniGetUI frissítése után" +} diff --git a/src/Languages/lang_id.json b/src/Languages/lang_id.json new file mode 100644 index 0000000..ca741ac --- /dev/null +++ b/src/Languages/lang_id.json @@ -0,0 +1,850 @@ +{ + "{0} of {1} operations completed": "{0} dari {1} operasi selesai", + "{0} is now {1}": "{0} sekarang menjadi {1}", + "Enabled": "Diaktifkan", + "Disabled": "Dinonaktifkan", + "Privacy": "Privasi", + "Hide my username from the logs": "Sembunyikan nama pengguna saya dari log", + "Replaces your username with **** in the logs. Restart UniGetUI to also hide it from already-recorded entries.": "Mengganti nama pengguna Anda dengan **** di log. Mulai ulang UniGetUI untuk menyembunyikannya juga dari entri yang sudah tercatat.", + "Your last update attempt did not complete.": "Upaya pembaruan terakhir Anda tidak selesai.", + "UniGetUI could not confirm whether the update succeeded. Open the log to see what happened.": "UniGetUI tidak dapat memastikan apakah pembaruan berhasil. Buka log untuk melihat apa yang terjadi.", + "View log": "Lihat log", + "The installer reported success but did not restart UniGetUI.": "Pemasang melaporkan berhasil, tetapi tidak memulai ulang UniGetUI.", + "The installer failed to initialize.": "Pemasang gagal diinisialisasi.", + "Setup was canceled before installation began.": "Penyiapan dibatalkan sebelum instalasi dimulai.", + "A fatal error occurred during the preparation phase.": "Terjadi kesalahan fatal selama tahap persiapan.", + "A fatal error occurred during installation.": "Terjadi kesalahan fatal selama instalasi.", + "Installation was canceled while in progress.": "Instalasi dibatalkan saat sedang berlangsung.", + "The installer was terminated by another process.": "Pemasang dihentikan oleh proses lain.", + "The preparation phase determined the installation cannot proceed.": "Tahap persiapan menentukan bahwa instalasi tidak dapat dilanjutkan.", + "The installer could not start. UniGetUI may already be running, or you do not have permission to install.": "Pemasang tidak dapat dimulai. UniGetUI mungkin sudah berjalan, atau Anda tidak memiliki izin untuk memasang.", + "Unexpected installer error.": "Kesalahan pemasang tak terduga.", + "We are checking for updates.": "Kami sedang memeriksa pembaruan.", + "Please wait": "Harap tunggu", + "Great! You are on the latest version.": "Hebat! Anda sudah menggunakan versi terbaru.", + "There are no new UniGetUI versions to be installed": "Tidak ada versi UniGetUI baru yang akan diinstal", + "UniGetUI version {0} is being downloaded.": "Versi UniGetUI {0} sedang diunduh.", + "This may take a minute or two": "Ini mungkin memerlukan waktu satu atau dua menit", + "The installer authenticity could not be verified.": "Keaslian penginstal tidak dapat diverifikasi.", + "The update process has been aborted.": "Proses pembaruan telah dibatalkan.", + "Auto-update is not yet available on this platform.": "Pembaruan otomatis belum tersedia di platform ini.", + "Please update UniGetUI manually.": "Silakan perbarui UniGetUI secara manual.", + "An error occurred when checking for updates: ": "Terjadi kesalahan saat memeriksa pembaruan: ", + "The updater could not be launched.": "Pembaru tidak dapat diluncurkan.", + "The operating system did not start the installer process.": "Sistem operasi tidak memulai proses pemasang.", + "UniGetUI is being updated...": "UniGetUI sedang diperbarui...", + "Update installed.": "Pembaruan terpasang.", + "UniGetUI was updated successfully, but this running copy was not replaced. This usually means you are running a development build. Close this copy and start the newly-installed version to finish.": "UniGetUI berhasil diperbarui, tetapi salinan yang sedang berjalan ini tidak diganti. Ini biasanya berarti Anda menjalankan build pengembangan. Tutup salinan ini dan mulai versi yang baru dipasang untuk menyelesaikan.", + "The update could not be applied.": "Pembaruan tidak dapat diterapkan.", + "Installer exit code {0}: {1}": "Kode keluar pemasang {0}: {1}", + "Update cancelled.": "Pembaruan dibatalkan.", + "Authentication was cancelled.": "Autentikasi dibatalkan.", + "Installer exit code {0}": "Kode keluar pemasang {0}", + "Operation in progress": "Operasi sedang berlangsung", + "Please wait...": "Harap tunggu...", + "Success!": "Sukses!", + "Failed": "Gagal", + "An error occurred while processing this package": "Terjadi kesalahan saat memproses paket ini", + "Installer": "Pemasang", + "Executable": "File eksekusi", + "MSI": "MSI", + "Compressed file": "File terkompresi", + "MSIX": "MSIX", + "WinGet was repaired successfully": "WinGet berhasil diperbaiki", + "It is recommended to restart UniGetUI after WinGet has been repaired": "Disarankan untuk memulai ulang UniGetUI setelah WinGet diperbaiki", + "WinGet could not be repaired": "WinGet tidak dapat diperbaiki", + "An unexpected issue occurred while attempting to repair WinGet. Please try again later": "Masalah tak terduga terjadi saat mencoba memperbaiki WinGet. Silakan coba lagi nanti", + "Log in to enable cloud backup": "Masuk untuk mengaktifkan pencadangan cloud", + "Backup Failed": "Pencadangan Gagal", + "Downloading backup...": "Mengunduh cadangan...", + "An update was found!": "Pembaruan ditemukan!", + "{0} can be updated to version {1}": "{0} dapat diperbarui ke versi {1}", + "Updates found!": "Pembaruan ditemukan!", + "{0} packages can be updated": "{0} paket dapat diperbarui", + "{0} is being updated to version {1}": "{0} sedang diperbarui ke versi {1}", + "{0} packages are being updated": "{0} paket sedang diperbarui", + "You have currently version {0} installed": "Anda saat ini memiliki versi {0} yang terinstal", + "Desktop shortcut created": "Pintasan desktop dibuat", + "UniGetUI has detected a new desktop shortcut that can be deleted automatically.": "UniGetUI telah mendeteksi pintasan desktop baru yang dapat dihapus secara otomatis.", + "{0} desktop shortcuts created": "{0} pintasan desktop dibuat", + "UniGetUI has detected {0} new desktop shortcuts that can be deleted automatically.": "UniGetUI telah mendeteksi {0} pintasan desktop baru yang dapat dihapus secara otomatis.", + "Attention required": "Perlu perhatian", + "Restart required": "Mulai ulang diperlukan", + "1 update is available": "1 pembaruan tersedia", + "{0} updates are available": "{0} pembaruan tersedia", + "Everything is up to date": "Semua sudah diperbarui", + "Discover Packages": "Temukan Paket", + "Available Updates": "Pembaruan Tersedia", + "Installed Packages": "Paket Terpasang", + "UniGetUI Version {0} by Devolutions": "UniGetUI Versi {0} oleh Devolutions", + "Show UniGetUI": "Tampilkan UniGetUI", + "Quit": "Keluar", + "Are you sure?": "Apakah Anda yakin?", + "Do you really want to uninstall {0}?": "Yakin ingin mencopot {0}?", + "Do you really want to uninstall the following {0} packages?": "Yakin ingin mencopot {0} paket berikut?", + "No": "Tidak", + "Yes": "Ya", + "Partial": "Sebagian", + "View on UniGetUI": "Lihat di UniGetUI", + "Update": "Perbarui", + "Open UniGetUI": "Buka UniGetUI", + "Update all": "Perbarui semua", + "Update now": "Perbarui sekarang", + "Installer host changed since the installed version.\n": "Host pemasang berubah sejak versi yang terpasang.\n", + "This package is on the queue": "Paket ini ada dalam antrean", + "installing": "sedang menginstal", + "updating": "memperbarui", + "uninstalling": "sedang menghapus instalasi", + "installed": "terinstal", + "Retry": "Coba lagi", + "Install": "Pasang", + "Uninstall": "Hapus instalasi", + "Open": "Buka", + "Operation profile:": "Profil operasi:", + "Follow the default options when installing, upgrading or uninstalling this package": "Ikuti opsi default saat instalasi, pembaruan, atau menghapus paket ini", + "The following settings will be applied each time this package is installed, updated or removed.": "Pengaturan berikut akan diterapkan setiap kali paket ini diinstal, diperbarui, atau dihapus.", + "Version to install:": "Versi untuk dipasang:", + "Architecture to install:": "Arsitektur yang akan diinstal:", + "Installation scope:": "Lingkup pemasangan:", + "Install location:": "Lokasi pemasangan:", + "Select": "Pilih", + "Reset": "Atur ulang", + "Custom install arguments:": "Argumen penginstalan khusus:", + "Custom update arguments:": "Argumen pembaruan khusus:", + "Custom uninstall arguments:": "Argumen hapus instalan khusus:", + "Pre-install command:": "Perintah pra-instalasi:", + "Post-install command:": "Perintah pasca-instalasi:", + "Abort install if pre-install command fails": "Batalkan instalasi jika perintah pra-instalasi gagal", + "Pre-update command:": "Perintah pra-pembaruan:", + "Post-update command:": "Perintah pasca-pembaruan:", + "Abort update if pre-update command fails": "Batalkan pembaruan jika perintah pra-pembaruan gagal", + "Pre-uninstall command:": "Perintah pra-penghapusan instalasi:", + "Post-uninstall command:": "Perintah pasca-penghapusan instalasi:", + "Abort uninstall if pre-uninstall command fails": "Batalkan penghapusan jika perintah pra-penghapusan gagal", + "Command-line to run:": "Perintah yang akan dijalankan:", + "Save and close": "Simpan dan tutup", + "General": "Umum", + "Architecture & Location": "Arsitektur & Lokasi", + "Command-line": "Baris perintah", + "Close apps": "Tutup aplikasi", + "Pre/Post install": "Pra/Pasca-instalasi", + "Select the processes that should be closed before this package is installed, updated or uninstalled.": "Pilih proses yang harus ditutup sebelum paket ini diinstal, diperbarui, atau dihapus.", + "Write here the process names here, separated by commas (,)": "Tuliskan nama proses di sini, dipisahkan dengan koma (,)", + "Try to kill the processes that refuse to close when requested to": "Cobalah untuk mematikan proses yang menolak untuk menutup ketika diminta", + "Run as admin": "Jalankan sebagai admin", + "Interactive installation": "Pemasangan interaktif", + "Skip hash check": "Lewati pemeriksaan hash", + "Uninstall previous versions when updated": "Hapus instalan versi sebelumnya saat diperbarui", + "Skip minor updates for this package": "Lewati pembaruan minor untuk paket ini", + "Automatically update this package": "Perbarui paket ini secara otomatis", + "{0} installation options": "{0} opsi instalasi", + "Latest": "Terbaru", + "PreRelease": "PraRilis", + "Default": "Bawaan", + "Manage ignored updates": "Kelola pembaruan yang diabaikan", + "The packages listed here won't be taken in account when checking for updates. Double-click them or click the button on their right to stop ignoring their updates.": "Paket-paket yang terdaftar di sini tidak akan diperhitungkan saat memeriksa pembaruan. Klik dua kali pada mereka atau klik tombol di sebelah kanan mereka untuk berhenti mengabaikan pembaruan mereka.", + "Reset list": "Atur ulang daftar", + "Do you really want to reset the ignored updates list? This action cannot be reverted": "Yakin ingin mengatur ulang daftar pembaruan yang diabaikan? Tindakan ini tidak dapat dibatalkan", + "No ignored updates": "Tidak ada pembaruan yang diabaikan", + "Package Name": "Nama Paket", + "Package ID": "ID Paket", + "Ignored version": "Versi yang diabaikan", + "New version": "Versi baru", + "Source": "Sumber", + "All versions": "Semua versi", + "Unknown": "Tidak diketahui", + "Up to date": "Sudah terbaru", + "Package {name} from {manager}": "Paket {name} dari {manager}", + "Remove {0} from ignored updates": "Hapus {0} dari pembaruan yang diabaikan", + "Cancel": "Batal", + "Administrator privileges": "Hak administrator", + "This operation is running with administrator privileges.": "Operasi ini berjalan dengan hak istimewa administrator.", + "Interactive operation": "Operasi interaktif", + "This operation is running interactively.": "Operasi ini sedang berjalan secara interaktif.", + "You will likely need to interact with the installer.": "Anda mungkin perlu berinteraksi dengan penginstal.", + "Integrity checks skipped": "Pemeriksaan integritas dilewati", + "Integrity checks will not be performed during this operation.": "Pemeriksaan integritas tidak akan dilakukan selama operasi ini.", + "Proceed at your own risk.": "Lanjutkan dengan risiko Anda sendiri.", + "Close": "Tutup", + "Loading...": "Memuat...", + "Installer SHA256": "SHA256 Pemasang", + "Homepage": "Beranda", + "Author": "Penulis", + "Publisher": "Penerbit", + "License": "Lisensi", + "Manifest": "Manifes", + "Installer Type": "Tipe Pemasang", + "Size": "Ukuran", + "Installer URL": "URL Pemasang", + "Last updated:": "Terakhir diperbarui:", + "Release notes URL": "URL catatan rilis", + "Package details": "Detail paket", + "Dependencies:": "Dependensi:", + "Release notes": "Catatan rilis", + "Screenshots": "Tangkapan layar", + "This package has no screenshots or is missing the icon? Contribute to UniGetUI by adding the missing icons and screenshots to our open, public database.": "Paket ini tidak memiliki tangkapan layar atau ikonnya hilang? Berkontribusilah ke UniGetUI dengan menambahkan ikon dan tangkapan layar yang hilang ke database publik terbuka kami.", + "Version": "Versi", + "Install as administrator": "Pasang sebagai administrator", + "Update to version {0}": "Perbarui ke versi {0}", + "Installed Version": "Versi Terpasang", + "Update as administrator": "Perbarui sebagai administrator", + "Interactive update": "Pembaruan interaktif", + "Uninstall as administrator": "Hapus instalasi sebagai administrator", + "Interactive uninstall": "Copot pemasangan interaktif", + "Uninstall and remove data": "Hapus instalasi dan hapus data", + "Not available": "Tidak tersedia", + "Installer SHA512": "SHA512 Pemasang", + "Unknown size": "Ukuran tidak diketahui", + "No dependencies specified": "Tidak ada dependensi yang ditentukan", + "mandatory": "wajib", + "optional": "opsional", + "UniGetUI {0} is ready to be installed.": "UniGetUI {0} siap untuk dipasang.", + "The update process will start after closing UniGetUI": "Proses pembaruan akan dimulai setelah menutup UniGetUI", + "UniGetUI has been ran as administrator, which is not recommended. When running UniGetUI as administrator, EVERY operation launched from UniGetUI will have administrator privileges. You can still use the program, but we highly recommend not running UniGetUI with administrator privileges.": "UniGetUI telah dijalankan sebagai administrator, yang tidak disarankan. Saat menjalankan UniGetUI sebagai administrator, SETIAP operasi yang dijalankan dari UniGetUI akan memiliki hak administrator. Anda tetap dapat menggunakan program ini, tetapi kami sangat menyarankan agar tidak menjalankan UniGetUI dengan hak administrator.", + "Share anonymous usage data": "Bagikan data penggunaan anonim", + "UniGetUI collects anonymous usage data in order to improve the user experience.": "UniGetUI mengumpulkan data penggunaan anonim untuk meningkatkan pengalaman pengguna.", + "Accept": "Terima", + "Software Updates": "Pembaruan perangkat lunak", + "Package Bundles": "Bundel Paket", + "Settings": "Pengaturan", + "Package Managers": "Manajer Paket", + "UniGetUI Log": "Log UniGetUI", + "Package Manager logs": "Log Manajer Paket", + "Operation history": "Riwayat operasi", + "Help": "Bantuan", + "UniGetUI": "UniGetUI", + "You have installed UniGetUI Version {0}": "Anda telah menginstal UniGetUI Versi {0}", + "Disclaimer": "Penafian", + "UniGetUI is developed by Devolutions and is not affiliated with any of the compatible package managers.": "UniGetUI dikembangkan oleh Devolutions dan tidak berafiliasi dengan manajer paket kompatibel mana pun.", + "UniGetUI wouldn't have been possible without the help of the contributors. Thank you all 🥳": "UniGetUI tidak akan mungkin ada tanpa bantuan kontributor. Terima kasih semua 🥳", + "UniGetUI uses the following libraries. Without them, UniGetUI wouldn't have been possible.": "UniGetUI menggunakan pustaka berikut. Tanpa pustaka ini, UniGetUI tidak akan mungkin ada.", + "{0} homepage": "{0} halaman utama", + "UniGetUI has been translated to more than 40 languages thanks to the volunteer translators. Thank you 🤝": "UniGetUI telah diterjemahkan ke lebih dari 40 bahasa berkat para penerjemah sukarelawan. Terima kasih 🤝", + "Verbose": "Rincian", + "1 - Errors": "1 - Kesalahan", + "2 - Warnings": "2 - Peringatan", + "3 - Information (less)": "3 - Informasi (sedikit)", + "4 - Information (more)": "4 - Informasi (lebih banyak)", + "5 - information (debug)": "5 - Informasi (debug)", + "Warning": "Peringatan", + "The following settings may pose a security risk, hence they are disabled by default.": "Pengaturan berikut ini dapat menimbulkan risiko keamanan, oleh karena itu pengaturan ini dinonaktifkan secara default.", + "Enable the settings below if and only if you fully understand what they do, and the implications they may have.": "Aktifkan pengaturan di bawah ini JIKA DAN HANYA JIKA Anda memahami sepenuhnya apa yang dilakukannya, dan implikasinya.", + "The settings will list, in their descriptions, the potential security issues they may have.": "Pengaturan akan mencantumkan, dalam deskripsinya, potensi masalah keamanan yang mungkin terjadi.", + "The backup will include the complete list of the installed packages and their installation options. Ignored updates and skipped versions will also be saved.": "Cadangan akan mencakup daftar lengkap paket yang terinstal dan opsi instalasinya. Pembaruan yang diabaikan dan versi yang dilewati juga akan disimpan.", + "The backup will NOT include any binary file nor any program's saved data.": "Cadangan TIDAK akan mencakup file biner atau data yang disimpan oleh program.", + "The size of the backup is estimated to be less than 1MB.": "Ukuran cadangan diperkirakan kurang dari 1MB.", + "The backup will be performed after login.": "Cadangan akan dilakukan setelah login.", + "{pcName} installed packages": "Paket yang terpasang di {pcName}", + "Current status: Not logged in": "Status saat ini: Belum masuk", + "You are logged in as {0} (@{1})": "Anda masuk sebagai {0} (@{1})", + "Nice! Backups will be uploaded to a private gist on your account": "Bagus! Cadangan akan diunggah ke Gist pribadi di akun Anda", + "Select backup": "Pilih cadangan", + "Settings imported from {0}": "Pengaturan diimpor dari {0}", + "UniGetUI Settings": "Pengaturan UniGetUI", + "Settings exported to {0}": "Pengaturan diekspor ke {0}", + "UniGetUI settings were reset": "Pengaturan UniGetUI telah direset", + "Allow pre-release versions": "Izinkan versi pra-rilis", + "Apply": "Terapkan", + "For security reasons, custom command-line arguments are disabled by default. Go to UniGetUI security settings to change this.": "Demi keamanan, argumen baris perintah khusus dinonaktifkan secara default. Buka pengaturan keamanan UniGetUI untuk mengubahnya.", + "Go to UniGetUI security settings": "Buka pengaturan keamanan UniGetUI", + "The following options will be applied by default each time a {0} package is installed, upgraded or uninstalled.": "Opsi berikut ini akan diterapkan secara default setiap kali paket {0} diinstal, diperbarui, atau dihapus.", + "Package's default": "Paket bawaan", + "Install location can't be changed for {0} packages": "Lokasi penginstalan tidak dapat diubah untuk paket {0}", + "The local icon cache currently takes {0} MB": "Cache ikon lokal saat ini memakan {0} MB", + "Username": "Nama pengguna", + "Password": "Kata sandi", + "Credentials": "Kredensial", + "It is not guaranteed that the provided credentials will be stored safely": "Tidak ada jaminan bahwa kredensial yang diberikan akan disimpan dengan aman", + "Partially": "Sebagian", + "Package manager": "Manajer paket", + "Compatible with proxy": "Kompatibel dengan proxy", + "Compatible with authentication": "Kompatibel dengan autentikasi", + "Proxy compatibility table": "Tabel kompatibilitas proxy", + "{0} settings": "{0} pengaturan", + "{0} status": "Status {0}", + "Default installation options for {0} packages": "Opsi penginstalan default untuk paket {0}", + "Expand version": "Perluas versi", + "The executable file for {0} was not found": "File eksekusi untuk {0} tidak ditemukan", + "{pm} is disabled": "{pm} dinonaktifkan", + "Enable it to install packages from {pm}.": "Aktifkan untuk menginstal paket dari {pm}.", + "{pm} is enabled and ready to go": "{pm} diaktifkan dan siap digunakan", + "{pm} version:": "Versi {pm}:", + "{pm} was not found!": "{pm} tidak ditemukan!", + "You may need to install {pm} in order to use it with UniGetUI.": "Anda mungkin perlu menginstal {pm} untuk menggunakannya dengan UniGetUI.", + "Scoop Installer - UniGetUI": "Instalasi Scoop - UniGetUI", + "Scoop Uninstaller - UniGetUI": "Penghapus Instalasi Scoop - UniGetUI", + "Clearing Scoop cache - UniGetUI": "Membersihkan cache Scoop - UniGetUI", + "Restart UniGetUI to fully apply changes": "Mulai ulang UniGetUI untuk menerapkan perubahan sepenuhnya", + "Restart UniGetUI": "Mulai ulang UniGetUI", + "Manage {0} sources": "Kelola sumber {0}", + "Add source": "Tambah sumber", + "Add": "Tambah", + "Source name": "Nama sumber", + "Source URL": "URL sumber", + "Other": "Lainnya", + "No minimum age": "Tanpa usia minimum", + "1 day": "1 hari", + "{0} days": "{0} hari", + "Custom...": "Kustom...", + "{0} minutes": "{0} menit", + "1 hour": "1 jam", + "{0} hours": "{0} jam", + "1 week": "1 minggu", + "Supports release dates": "Mendukung tanggal rilis", + "Release date support per package manager": "Dukungan tanggal rilis per manajer paket", + "Search for packages": "Cari paket", + "Local": "Lokal", + "OK": "OK", + "Last checked: {0}": "Terakhir diperiksa: {0}", + "{0} packages were found, {1} of which match the specified filters.": "{0} paket ditemukan, {1} di antaranya cocok dengan filter yang ditentukan.", + "{0} selected": "{0} dipilih", + "(Last checked: {0})": "(Terakhir diperiksa: {0})", + "All packages selected": "Semua paket dipilih", + "Package selection cleared": "Pilihan paket dihapus", + "{0}: {1}": "{0}: {1}", + "More info": "Info lebih lanjut", + "GitHub account": "Akun GitHub", + "Log in with GitHub to enable cloud package backup.": "Masuk dengan GitHub untuk mengaktifkan pencadangan paket cloud.", + "More details": "Detail lainnya", + "Log in": "Masuk", + "If you have cloud backup enabled, it will be saved as a GitHub Gist on this account": "Jika Anda mengaktifkan pencadangan cloud, pencadangan akan disimpan sebagai GitHub Gist di akun ini", + "Log out": "Keluar", + "About UniGetUI": "Tentang UniGetUI", + "About": "Tentang", + "Third-party licenses": "Lisensi pihak ketiga", + "Contributors": "Kontributor", + "Translators": "Penerjemah", + "Bundle security report": "Laporan keamanan bundel", + "The bundle contained restricted content": "Bundel berisi konten yang dibatasi", + "UniGetUI – Crash Report": "UniGetUI – Laporan Kerusakan", + "UniGetUI has crashed": "UniGetUI mengalami kerusakan", + "Help us fix this by sending a crash report to Devolutions. All fields below are optional.": "Bantu kami memperbaikinya dengan mengirimkan laporan kerusakan ke Devolutions. Semua kolom di bawah ini bersifat opsional.", + "Email (optional)": "Email (opsional)", + "your@email.com": "your@email.com", + "Additional details (optional)": "Detail tambahan (opsional)", + "Describe what you were doing when the crash occurred…": "Jelaskan apa yang Anda lakukan saat kerusakan terjadi…", + "Crash report": "Laporan kerusakan", + "Don't Send": "Jangan Kirim", + "Send Report": "Kirim Laporan", + "Sending…": "Mengirim…", + "Unsaved changes": "Perubahan belum disimpan", + "You have unsaved changes in the current bundle. Do you want to discard them?": "Anda memiliki perubahan yang belum disimpan dalam bundel saat ini. Apakah Anda ingin membuangnya?", + "Discard changes": "Buang perubahan", + "Integrity violation": "Pelanggaran integritas", + "UniGetUI or some of its components are missing or corrupt. It is strongly recommended to reinstall UniGetUI to adress the situation.": "UniGetUI atau beberapa komponennya hilang atau rusak. Sangat disarankan untuk menginstal ulang UniGetUI untuk mengatasi situasi ini.", + "• Refer to the UniGetUI Logs to get more details regarding the affected file(s)": "• Lihat Log UniGetUI untuk mendapatkan rincian lebih lanjut mengenai file yang terpengaruh", + "• Integrity checks can be disabled from the Experimental Settings": "• Pemeriksaan integritas dapat dinonaktifkan dari Pengaturan Eksperimental", + "Manage shortcuts": "Kelola pintasan", + "UniGetUI has detected the following desktop shortcuts which can be removed automatically on future upgrades": "UniGetUI telah mendeteksi pintasan desktop berikut yang dapat dihapus secara otomatis pada pembaruan mendatang", + "Do you really want to reset this list? This action cannot be reverted.": "Yakin ingin mengatur ulang daftar ini? Tindakan ini tidak dapat dibatalkan.", + "Desktop shortcuts list": "Daftar pintasan desktop", + "Open in explorer": "Buka di Explorer", + "Remove from list": "Hapus dari daftar", + "When new shortcuts are detected, delete them automatically instead of showing this dialog.": "Saat pintasan baru terdeteksi, hapus pintasan secara otomatis alih-alih menampilkan dialog ini.", + "Not right now": "Tidak sekarang", + "Missing dependency": "Ketergantungan hilang", + "UniGetUI requires {0} to operate, but it was not found on your system.": "UniGetUI membutuhkan {0} untuk beroperasi, tetapi tidak ditemukan di sistem Anda.", + "Click on Install to begin the installation process. If you skip the installation, UniGetUI may not work as expected.": "Klik Instal untuk memulai proses instalasi. Jika Anda melewatinya, UniGetUI mungkin tidak berfungsi sebagaimana mestinya.", + "Alternatively, you can also install {0} by running the following command in a Windows PowerShell prompt:": "Sebagai alternatif, Anda juga dapat menginstal {0} dengan menjalankan perintah berikut di jendela PowerShell Windows:", + "Install {0}": "Pasang {0}", + "Do not show this dialog again for {0}": "Jangan tampilkan dialog ini lagi untuk {0}", + "Please wait while {0} is being installed. A black window may show up. Please wait until it closes.": "Harap tunggu saat {0} sedang diinstal. Mungkin akan muncul jendela hitam (atau biru). Tunggu hingga jendela tersebut tertutup.", + "{0} has been installed successfully.": "{0} telah terinstal dengan sukses.", + "Please click on \"Continue\" to continue": "Silakan klik \"Lanjutkan\" untuk melanjutkan", + "Continue": "Lanjutkan", + "{0} has been installed successfully. It is recommended to restart UniGetUI to finish the installation": "{0} telah terinstal dengan sukses. Disarankan untuk me-restart UniGetUI untuk menyelesaikan instalasi", + "Restart later": "Mulai ulang nanti", + "An error occurred:": "Terjadi kesalahan:", + "Please see the Command-line Output or refer to the Operation History for further information about the issue.": "Lihat Output Baris Perintah atau Riwayat Operasi untuk informasi lebih lanjut tentang masalah ini.", + "Retry as administrator": "Coba lagi sebagai administrator", + "Retry interactively": "Coba lagi secara interaktif", + "Retry skipping integrity checks": "Coba lagi dengan melewati pemeriksaan integritas", + "Installation options": "Opsi pemasangan", + "Save": "Simpan", + "UniGetUI collects anonymous usage data with the sole purpose of understanding and improving the user experience.": "UniGetUI mengumpulkan data penggunaan anonim dengan tujuan tunggal untuk memahami dan meningkatkan pengalaman pengguna.", + "More details about the shared data and how it will be processed": "Informasi lebih lanjut tentang data yang dibagikan dan bagaimana data tersebut diproses", + "Do you accept that UniGetUI collects and sends anonymous usage statistics, with the sole purpose of understanding and improving the user experience?": "Apakah Anda menyetujui bahwa UniGetUI mengumpulkan dan mengirim statistik penggunaan anonim untuk memahami dan meningkatkan pengalaman pengguna?", + "Decline": "Tolak", + "No personal information is collected nor sent, and the collected data is anonimized, so it can't be back-tracked to you.": "Tidak ada informasi pribadi yang dikumpulkan atau dikirim, dan data yang dikumpulkan dianonimkan sehingga tidak dapat ditelusuri kembali kepada Anda.", + "Navigation panel": "Panel navigasi", + "Operations": "Operasi", + "Toggle operations panel": "Alihkan panel operasi", + "Bulk operations": "Operasi massal", + "Retry failed": "Coba ulang yang gagal", + "Clear successful": "Hapus yang berhasil", + "Clear finished": "Hapus yang selesai", + "Cancel all": "Batalkan semua", + "More": "Lainnya", + "Toggle navigation panel": "Tampilkan/sembunyikan panel navigasi", + "Minimize": "Minimalkan", + "Maximize": "Maksimalkan", + "UniGetUI by Devolutions": "UniGetUI oleh Devolutions", + "UniGetUI is an application that makes managing your software easier, by providing an all-in-one graphical interface for your command-line package managers.": "UniGetUI adalah aplikasi yang memudahkan pengelolaan perangkat lunak Anda, dengan menyediakan antarmuka grafis serba ada untuk pengelola paket baris perintah Anda.", + "Useful links": "Tautan berguna", + "UniGetUI Homepage": "Beranda UniGetUI", + "Report an issue or submit a feature request": "Laporkan masalah atau ajukan permintaan fitur", + "UniGetUI Repository": "Repositori UniGetUI", + "View GitHub Profile": "Lihat Profil GitHub", + "UniGetUI License": "Lisensi UniGetUI", + "Using UniGetUI implies the acceptation of the MIT License": "Menggunakan UniGetUI berarti menerima Lisensi MIT", + "Become a translator": "Jadilah penerjemah", + "Go back": "Kembali", + "Go forward": "Maju", + "Go to home page": "Ke halaman beranda", + "Reload page": "Muat ulang halaman", + "View page on browser": "Lihat halaman di browser", + "The built-in browser is not supported on Linux yet.": "Browser bawaan belum didukung di Linux.", + "Open in browser": "Buka di browser", + "Copy to clipboard": "Salin ke papan klip", + "Export to a file": "Ekspor ke berkas", + "Log level:": "Tingkat log:", + "Reload log": "Muat ulang log", + "Export log": "Ekspor log", + "Text": "Teks", + "Change how operations request administrator rights": "Ubah bagaimana operasi meminta hak administrator", + "Restrictions on package operations": "Pembatasan operasi paket", + "Restrictions on package managers": "Pembatasan pada manajer paket", + "Restrictions when importing package bundles": "Pembatasan saat mengimpor bundel paket", + "Ask for administrator privileges once for each batch of operations": "Minta hak administrator satu kali untuk setiap kelompok operasi", + "Ask only once for administrator privileges": "Tanyakan hanya sekali untuk mendapatkan hak istimewa administrator", + "Prohibit any kind of Elevation via UniGetUI Elevator or GSudo": "Melarang segala jenis Elevasi melalui UniGetUI Elevator atau GSudo", + "This option WILL cause issues. Any operation incapable of elevating itself WILL FAIL. Install/update/uninstall as administrator will NOT WORK.": "Opsi ini AKAN menyebabkan masalah. Operasi apa pun yang tidak mampu elevasi dirinya sendiri AKAN GAGAL. Instal/perbarui/hapus sebagai administrator TIDAK AKAN BERFUNGSI.", + "Allow custom command-line arguments": "Mengizinkan argumen perintah khusus", + "Custom command-line arguments can change the way in which programs are installed, upgraded or uninstalled, in a way UniGetUI cannot control. Using custom command-lines can break packages. Proceed with caution.": "Argumen perintah khusus dapat mengubah cara program diinstal, diupgrade, atau dihapus, dengan cara yang tidak dapat dikontrol oleh UniGetUI. Menggunakan perintah khusus dapat merusak paket. Lanjutkan dengan hati-hati.", + "Ignore custom pre-install and post-install commands when importing packages from a bundle": "Izinkan perintah pra-instalasi dan pasca-instalasi khusus dijalankan", + "Pre and post install commands will be run before and after a package gets installed, upgraded or uninstalled. Be aware that they may break things unless used carefully": "Perintah pra dan pasca instalasi akan dijalankan sebelum dan sesudah sebuah paket diinstal, diupgrade, atau dihapus. Ketahuilah bahwa perintah-perintah tersebut dapat merusak kecuali jika digunakan dengan hati-hati", + "Allow changing the paths for package manager executables": "Izinkan mengubah jalur eksekusi untuk manajer paket", + "Turning this on enables changing the executable file used to interact with package managers. While this allows finer-grained customization of your install processes, it may also be dangerous": "Dengan mengaktifkannya, Anda dapat mengubah file yang dapat dieksekusi yang digunakan untuk berinteraksi dengan manajer paket. Meskipun hal ini memungkinkan penyesuaian yang lebih baik pada proses instalasi Anda, hal ini juga dapat berbahaya", + "Allow importing custom command-line arguments when importing packages from a bundle": "Izinkan mengimpor argumen perintah khusus saat mengimpor paket dari bundel", + "Malformed command-line arguments can break packages, or even allow a malicious actor to gain privileged execution. Therefore, importing custom command-line arguments is disabled by default": "Argumen perintah yang salah dapat merusak paket, atau bahkan memungkinkan aktor jahat untuk mendapatkan hak eksekusi istimewa. Oleh karena itu, mengimpor argumen perintah khusus dinonaktifkan secara default", + "Allow importing custom pre-install and post-install commands when importing packages from a bundle": "Izinkan mengimpor perintah pra-instal dan pasca-instal khusus saat mengimpor paket dari bundel", + "Pre and post install commands can do very nasty things to your device, if designed to do so. It can be very dangerous to import the commands from a bundle, unless you trust the source of that package bundle": "Perintah pra dan pasca instalasi dapat melakukan hal-hal yang sangat buruk pada perangkat Anda, jika memang dirancang untuk itu. Akan sangat berbahaya untuk mengimpor perintah dari sebuah paket, kecuali jika Anda mempercayai sumber paket tersebut", + "Administrator rights and other dangerous settings": "Hak Administrator dan pengaturan lanjutan", + "Package backup": "Cadangan paket", + "Cloud package backup": "Pencadangan paket cloud", + "Local package backup": "Pencadangan paket lokal", + "Local backup advanced options": "Opsi lanjutan pencadangan lokal", + "Log in with GitHub": "Masuk dengan GitHub", + "Log out from GitHub": "Keluar dari GitHub", + "Periodically perform a cloud backup of the installed packages": "Lakukan pencadangan cloud secara berkala dari paket yang diinstal", + "Cloud backup uses a private GitHub Gist to store a list of installed packages": "Pencadangan cloud menggunakan GitHub Gist pribadi untuk menyimpan daftar paket yang diinstal", + "Perform a cloud backup now": "Lakukan pencadangan cloud sekarang", + "Backup": "Cadangan", + "Restore a backup from the cloud": "Memulihkan cadangan dari cloud", + "Begin the process to select a cloud backup and review which packages to restore": "Mulai proses untuk memilih cadangan cloud dan tinjau paket mana yang akan dipulihkan", + "Periodically perform a local backup of the installed packages": "Lakukan pencadangan lokal secara berkala dari paket yang terinstal", + "Perform a local backup now": "Lakukan pencadangan lokal sekarang", + "Change backup output directory": "Ubah direktori keluaran cadangan", + "Set a custom backup file name": "Atur nama file cadangan kustom", + "Leave empty for default": "Biarkan kosong untuk bawaan", + "Add a timestamp to the backup file names": "Tambahkan penanda waktu pada nama file cadangan", + "Backup and Restore": "Pencadangan dan Pemulihan", + "Enable background api (UniGetUI Widgets and Sharing, port 7058)": "Aktifkan API latar belakang (Widget dan Berbagi UniGetUI, port 7058)", + "Wait for the device to be connected to the internet before attempting to do tasks that require internet connectivity.": "Tunggu perangkat terhubung ke internet sebelum mencoba melakukan tugas yang memerlukan koneksi internet.", + "Disable the 1-minute timeout for package-related operations": "Nonaktifkan batas waktu 1 menit untuk operasi terkait paket", + "Use installed GSudo instead of UniGetUI Elevator": "Gunakan GSudo yang terinstal sebagai pengganti UniGetUI Elevator", + "Use a custom icon and screenshot database URL": "Gunakan URL database ikon dan tangkapan layar kustom", + "Enable background CPU Usage optimizations (see Pull Request #3278)": "Aktifkan optimasi penggunaan CPU di latar belakang (lihat Pull Request #3278)", + "Perform integrity checks at startup": "Melakukan pemeriksaan integritas saat memulai", + "When batch installing packages from a bundle, install also packages that are already installed": "Saat menginstal paket dari bundel, instal juga paket yang sudah terinstal", + "Experimental settings and developer options": "Pengaturan eksperimental dan opsi pengembang", + "Show UniGetUI's version and build number on the titlebar.": "Tampilkan versi UniGetUI pada judul", + "Language": "Bahasa", + "UniGetUI updater": "Pembaruan UniGetUI", + "Telemetry": "Telemetri", + "Manage UniGetUI settings": "Kelola pengaturan UniGetUI", + "Related settings": "Pengaturan terkait", + "Update UniGetUI automatically": "Perbarui UniGetUI secara otomatis", + "Check for updates": "Periksa pembaruan", + "Install prerelease versions of UniGetUI": "Pasang versi pra-rilis UniGetUI", + "Manage telemetry settings": "Kelola pengaturan telemetri", + "Manage": "Kelola", + "Import settings from a local file": "Impor pengaturan dari berkas lokal", + "Import": "Impor", + "Export settings to a local file": "Ekspor pengaturan ke berkas lokal", + "Export": "Ekspor", + "Reset UniGetUI": "Atur ulang UniGetUI", + "User interface preferences": "Preferensi antarmuka pengguna", + "Application theme, startup page, package icons, clear successful installs automatically": "Tema aplikasi, halaman awal, ikon paket, bersihkan instalasi yang berhasil secara otomatis", + "General preferences": "Preferensi umum", + "UniGetUI display language:": "Bahasa tampilan UniGetUI:", + "System language": "Bahasa sistem", + "Is your language missing or incomplete?": "Apakah bahasa Anda tidak tersedia atau belum lengkap?", + "Appearance": "Tampilan", + "UniGetUI on the background and system tray": "UniGetUI di latar belakang dan area sistem", + "Package lists": "Daftar paket", + "Use classic mode": "Gunakan mode klasik", + "Restart UniGetUI to apply this change": "Mulai ulang UniGetUI untuk menerapkan perubahan ini", + "The classic UI is disabled for beta testers": "UI klasik dinonaktifkan untuk penguji beta", + "Close UniGetUI to the system tray": "Tutup UniGetUI ke tray sistem", + "Manage UniGetUI autostart behaviour": "Kelola perilaku mulai otomatis UniGetUI", + "Show package icons on package lists": "Tampilkan ikon paket di daftar paket", + "Clear cache": "Bersihkan cache", + "Select upgradable packages by default": "Pilih paket yang dapat diperbarui secara default", + "Light": "Terang", + "Dark": "Gelap", + "Follow system color scheme": "Ikuti skema warna sistem", + "Application theme:": "Tema aplikasi:", + "UniGetUI startup page:": "Halaman awal UniGetUI:", + "Proxy settings": "Pengaturan proxy", + "Other settings": "Pengaturan lainnya", + "Connect the internet using a custom proxy": "Hubungkan internet menggunakan proxy kustom", + "Please note that not all package managers may fully support this feature": "Harap dicatat bahwa tidak semua manajer paket mendukung fitur ini sepenuhnya", + "Proxy URL": "URL Proxy", + "Enter proxy URL here": "Masukkan URL proxy di sini", + "Authenticate to the proxy with a user and a password": "Autentikasi ke proxy dengan nama pengguna dan kata sandi", + "Internet and proxy settings": "Pengaturan internet dan proxy", + "Package manager preferences": "Preferensi manajer paket", + "Ready": "Siap", + "Not found": "Tidak ditemukan", + "Notification preferences": "Preferensi notifikasi", + "Notification types": "Jenis notifikasi", + "The system tray icon must be enabled in order for notifications to work": "Ikon baki sistem harus diaktifkan agar pemberitahuan dapat bekerja", + "Enable UniGetUI notifications": "Aktifkan notifikasi UniGetUI", + "Show a notification when there are available updates": "Tampilkan pemberitahuan saat ada pembaruan yang tersedia", + "Show a silent notification when an operation is running": "Tampilkan pemberitahuan diam saat operasi sedang berjalan", + "Show a notification when an operation fails": "Tampilkan pemberitahuan saat operasi gagal", + "Show a notification when an operation finishes successfully": "Tampilkan pemberitahuan saat operasi selesai dengan sukses", + "Concurrency and execution": "Konkuren dan eksekusi", + "Automatic desktop shortcut remover": "Penghapus pintasan desktop otomatis", + "Choose how many operations should be performed in parallel": "Pilih berapa banyak operasi yang harus dilakukan secara paralel", + "Clear successful operations from the operation list after a 5 second delay": "Hapus operasi yang berhasil dari daftar setelah jeda 5 detik", + "Download operations are not affected by this setting": "Operasi pengunduhan tidak terpengaruh oleh pengaturan ini", + "You may lose unsaved data": "Anda mungkin akan kehilangan data yang belum disimpan", + "Ask to delete desktop shortcuts created during an install or upgrade.": "Tanyakan untuk menghapus pintasan desktop yang dibuat selama instalasi atau pembaruan.", + "Package update preferences": "Preferensi pembaruan paket", + "Update check frequency, automatically install updates, etc.": "Frekuensi pemeriksaan pembaruan, instal pembaruan secara otomatis, dll.", + "Reduce UAC prompts, elevate installations by default, unlock certain dangerous features, etc.": "Kurangi permintaan UAC, tingkatkan penginstalan secara default, buka kunci fitur lanjutan tertentu, dll.", + "Package operation preferences": "Preferensi operasi paket", + "Enable {pm}": "Aktifkan {pm}", + "Not finding the file you are looking for? Make sure it has been added to path.": "Tidak menemukan file yang Anda cari? Pastikan file tersebut telah ditambahkan ke PATH.", + "Select the executable to be used. The following list shows the executables found by UniGetUI": "Pilih file yang dapat dieksekusi untuk digunakan. Daftar berikut menampilkan file yang dapat dieksekusi yang ditemukan oleh UniGetUI", + "For security reasons, changing the executable file is disabled by default": "Untuk alasan keamanan, perubahan pada file yang dapat dieksekusi dinonaktifkan secara default", + "Change this": "Ubah ini", + "Copy path": "Salin jalur", + "Current executable file:": "File yang dapat dieksekusi saat ini:", + "Ignore packages from {pm} when showing a notification about updates": "Abaikan paket dari {pm} saat menampilkan notifikasi pembaruan", + "Update security": "Keamanan pembaruan", + "Use global setting": "Gunakan pengaturan global", + "Minimum age for updates": "Usia minimum untuk pembaruan", + "e.g. 10": "mis. 10", + "Custom minimum age (days)": "Usia minimum kustom (hari)", + "{pm} does not provide release dates for its packages, so this setting will have no effect": "{pm} tidak menyediakan tanggal rilis untuk paketnya, jadi pengaturan ini tidak akan berpengaruh", + "{pm} only provides release dates for some of its packages, so this setting will only apply to those packages": "{pm} hanya menyediakan tanggal rilis untuk beberapa paketnya, jadi pengaturan ini hanya akan berlaku untuk paket tersebut", + "Override the global minimum update age for this package manager": "Ganti usia minimum pembaruan global untuk manajer paket ini", + "View {0} logs": "Lihat {0} log", + "If Python cannot be found or is not listing packages but is installed on the system, ": "Jika Python tidak dapat ditemukan atau tidak menampilkan daftar paket tetapi terinstal di sistem, ", + "Advanced options": "Opsi lanjutan", + "WinGet command-line tool": "Alat baris perintah WinGet", + "Choose which command-line tool UniGetUI uses for WinGet operations when the COM API is not used": "Pilih alat baris perintah yang digunakan UniGetUI untuk operasi WinGet saat COM API tidak digunakan", + "WinGet COM API": "WinGet COM API", + "Choose whether UniGetUI can use the WinGet COM API before falling back to the command-line tool": "Pilih apakah UniGetUI dapat menggunakan WinGet COM API sebelum beralih ke alat baris perintah", + "Reset WinGet": "Atur ulang WinGet", + "This may help if no packages are listed": "Ini mungkin membantu jika tidak ada paket yang terdaftar", + "Force install location parameter when updating packages with custom locations": "Paksa parameter lokasi instalasi saat memperbarui paket dengan lokasi khusus", + "Install Scoop": "Pasang Scoop", + "Uninstall Scoop (and its packages)": "Hapus instalasi Scoop (dan paket-paketnya)", + "Run cleanup and clear cache": "Jalankan pembersihan dan bersihkan cache", + "Run": "Jalankan", + "Enable Scoop cleanup on launch": "Aktifkan pembersihan Scoop saat dijalankan", + "Default vcpkg triplet": "Triplet vcpkg default", + "Change vcpkg root location": "Ubah lokasi root vcpkg", + "Reset vcpkg root location": "Reset lokasi root vcpkg", + "Open vcpkg root location": "Buka lokasi root vcpkg", + "Language, theme and other miscellaneous preferences": "Bahasa, tema, dan preferensi lainnya", + "Show notifications on different events": "Tampilkan pemberitahuan pada berbagai acara", + "Change how UniGetUI checks and installs available updates for your packages": "Ubah cara UniGetUI memeriksa dan menginstal pembaruan yang tersedia untuk paket Anda", + "Automatically save a list of all your installed packages to easily restore them.": "Simpan daftar semua paket terinstal secara otomatis untuk memudahkan pemulihan.", + "Enable and disable package managers, change default install options, etc.": "Mengaktifkan dan menonaktifkan manajer paket, mengubah opsi penginstalan default, dll.", + "Internet connection settings": "Pengaturan koneksi internet", + "Proxy settings, etc.": "Pengaturan proxy, dan lainnya.", + "Beta features and other options that shouldn't be touched": "Fitur beta dan opsi lainnya yang sebaiknya tidak diubah", + "Reload sources": "Muat ulang sumber", + "Delete source": "Hapus sumber", + "Known sources": "Sumber yang diketahui", + "Update checking": "Periksa pembaruan", + "Automatic updates": "Pembaruan otomatis", + "Check for package updates periodically": "Periksa pembaruan paket secara berkala", + "Check for updates every:": "Periksa pembaruan setiap:", + "Install available updates automatically": "Pasang pembaruan yang tersedia secara otomatis", + "Do not automatically install updates when the network connection is metered": "Jangan instal pembaruan otomatis saat koneksi internet terbatas", + "Do not automatically install updates when the device runs on battery": "Jangan menginstal pembaruan secara otomatis saat perangkat menggunakan daya baterai", + "Do not automatically install updates when the battery saver is on": "Jangan instal pembaruan secara otomatis saat penghemat baterai aktif", + "Only show updates that are at least the specified number of days old": "Hanya tampilkan pembaruan yang setidaknya berusia sesuai jumlah hari yang ditentukan", + "Warn me when the installer URL host changes between the installed version and the new version (WinGet only)": "Peringatkan saya saat host URL pemasang berubah antara versi terpasang dan versi baru (hanya WinGet)", + "Change how UniGetUI handles install, update and uninstall operations.": "Ubah cara UniGetUI menangani operasi instalasi, pembaruan, dan pencopotan.", + "Navigation": "Navigasi", + "Check for UniGetUI updates": "Periksa pembaruan UniGetUI", + "Quit UniGetUI": "Keluar dari UniGetUI", + "Filters": "Filter", + "Sources": "Sumber", + "Search for packages to start": "Cari paket untuk memulai", + "Select all": "Pilih semua", + "Clear selection": "Hapus pilihan", + "Instant search": "Pencarian instan", + "Distinguish between uppercase and lowercase": "Bedakan antara huruf besar dan kecil", + "Ignore special characters": "Abaikan karakter khusus", + "Search mode": "Mode pencarian", + "Both": "Keduanya", + "Exact match": "Pencocokan tepat", + "Show similar packages": "Tampilkan paket serupa", + "Loading": "Memuat", + "Package": "Paket", + "More options": "Opsi lainnya", + "Order by:": "Urutkan berdasarkan:", + "Name": "Nama", + "Id": "ID", + "Ascendant": "Naik", + "Descendant": "Turunan", + "View modes": "Mode tampilan", + "Reload": "Muat ulang", + "Closed": "Ditutup", + "Ascending": "Menaik", + "Descending": "Menurun", + "{0}: {1}, {2}": "{0}: {1}, {2}", + "Order by": "Urutkan berdasarkan", + "No results were found matching the input criteria": "Tidak ditemukan hasil yang sesuai dengan kriteria", + "No packages were found": "Tidak ditemukan paket", + "Loading packages": "Memuat paket", + "Skip integrity checks": "Lewati pemeriksaan integritas", + "Download selected installers": "Unduh penginstal terpilih", + "Install selection": "Pasang pilihan", + "Install options": "Opsi penginstalan", + "Add selection to bundle": "Tambahkan pilihan ke bundel", + "Download installer": "Unduh pemasang", + "Uninstall selection": "Pilihan pencopotan pemasangan", + "Uninstall options": "Opsi penghapusan instalan", + "Ignore selected packages": "Abaikan paket yang dipilih", + "Open install location": "Buka lokasi instalasi", + "Reinstall package": "Pasang ulang paket", + "Uninstall package, then reinstall it": "Hapus instalasi paket, lalu pasang ulang", + "Ignore updates for this package": "Abaikan pembaruan untuk paket ini", + "WinGet malfunction detected": "Kerusakan WinGet terdeteksi", + "It looks like WinGet is not working properly. Do you want to attempt to repair WinGet?": "Sepertinya WinGet tidak berfungsi dengan baik. Apakah Anda ingin mencoba memperbaikinya?", + "Repair WinGet": "Perbaiki WinGet", + "Updates will no longer be ignored for {0}": "Pembaruan tidak lagi diabaikan untuk {0}", + "Updates are now ignored for {0}": "Pembaruan sekarang diabaikan untuk {0}", + "Do not ignore updates for this package anymore": "Jangan abaikan pembaruan untuk paket ini lagi", + "Add packages or open an existing package bundle": "Tambahkan paket atau buka bundel paket yang sudah ada", + "Add packages to start": "Tambahkan paket ke awal", + "The current bundle has no packages. Add some packages to get started": "Paket saat ini tidak memiliki paket. Tambahkan beberapa paket untuk memulai", + "New": "Baru", + "Save as": "Simpan sebagai", + "Create .ps1 script": "Buat skrip .ps1", + "Remove selection from bundle": "Hapus pemilihan dari bundle", + "Skip hash checks": "Lewati pemeriksaan hash", + "The package bundle is not valid": "Paket bundle tidak valid", + "The bundle you are trying to load appears to be invalid. Please check the file and try again.": "Paket yang Anda coba muat tampaknya tidak valid. Harap periksa file dan coba lagi.", + "Package bundle": "Bundel paket", + "Could not create bundle": "Tidak dapat membuat bundel", + "The package bundle could not be created due to an error.": "Paket bundle tidak dapat dibuat karena kesalahan.", + "Install script": "Skrip instalasi", + "PowerShell script": "Skrip PowerShell", + "The installation script saved to {0}": "Skrip instalasi disimpan ke {0}", + "An error occurred": "Terjadi kesalahan", + "An error occurred while attempting to create an installation script:": "Terjadi kesalahan saat mencoba membuat skrip instalasi:", + "Hooray! No updates were found.": "Hore! Tidak ada pembaruan yang ditemukan.", + "Uninstall selected packages": "Hapus instalasi paket yang dipilih", + "Update selection": "Pilihan pembaruan", + "Update options": "Opsi pembaruan", + "Uninstall package, then update it": "Hapus instalasi paket, lalu perbarui", + "Uninstall package": "Hapus instalasi paket", + "Skip this version": "Lewati versi ini", + "Pause updates for": "Jeda pembaruan untuk", + "User | Local": "Pengguna | Lokal", + "Machine | Global": "Mesin | Global", + "The default package manager for Debian/Ubuntu-based Linux distributions.
Contains: Debian/Ubuntu packages": "Manajer paket bawaan untuk distribusi Linux berbasis Debian/Ubuntu.
Berisi: Paket Debian/Ubuntu", + "The Rust package manager.
Contains: Rust libraries and programs written in Rust": "Manajer paket Rust.
Berisi: Pustaka Rust dan program yang ditulis dalam Rust", + "The classical package manager for windows. You'll find everything there.
Contains: General Software": "Manajer paket klasik untuk Windows. Anda akan menemukan segalanya di sana.
Berisi: Perangkat Lunak Umum", + "The default package manager for RHEL/Fedora-based Linux distributions.
Contains: RPM packages": "Manajer paket bawaan untuk distribusi Linux berbasis RHEL/Fedora.
Berisi: Paket RPM", + "A repository full of tools and executables designed with Microsoft's .NET ecosystem in mind.
Contains: .NET related tools and scripts": "Repositori penuh dengan alat dan file eksekusi yang dirancang untuk ekosistem Microsoft .NET.
Berisi: alat dan skrip terkait .NET", + "The universal Linux package manager for desktop applications.
Contains: Flatpak applications from configured remotes": "Manajer paket Linux universal untuk aplikasi desktop.
Berisi: aplikasi Flatpak dari remote yang dikonfigurasi", + "NuPkg (zipped manifest)": "NuPkg (manifest terkompresi)", + "The Missing Package Manager for macOS (or Linux).
Contains: Formulae, Casks": "Manajer Paket yang Hilang untuk macOS (atau Linux).
Berisi: Formulae, Casks", + "Node JS's package manager. Full of libraries and other utilities that orbit the javascript world
Contains: Node javascript libraries and other related utilities": "Manajer paket Node JS. Berisi berbagai pustaka dan utilitas di ekosistem JavaScript
Berisi: Pustaka JavaScript Node dan utilitas terkait lainnya", + "The default package manager for Arch Linux and its derivatives.
Contains: Arch Linux packages": "Manajer paket bawaan untuk Arch Linux dan turunannya.
Berisi: Paket Arch Linux", + "Python's library manager. Full of python libraries and other python-related utilities
Contains: Python libraries and related utilities": "Pengelola pustaka Python. Penuh dengan pustaka Python dan utilitas terkait Python lainnya
Berisi: Pustaka Python dan utilitas terkait", + "PowerShell's package manager. Find libraries and scripts to expand PowerShell capabilities
Contains: Modules, Scripts, Cmdlets": "Manajer paket PowerShell. Temukan pustaka dan skrip untuk memperluas kemampuan PowerShell
Berisi: Modul, Skrip, Cmdlet", + "extracted": "diekstrak", + "Scoop package": "Paket Scoop", + "Great repository of unknown but useful utilities and other interesting packages.
Contains: Utilities, Command-line programs, General Software (extras bucket required)": "Repositori hebat berisi utilitas yang tidak dikenal namun berguna dan paket menarik lainnya.
Berisi: Utilitas, Program baris perintah, Perangkat lunak umum (memerlukan extras bucket)", + "The universal Linux package manager by Canonical.
Contains: Snap packages from the Snapcraft store": "Manajer paket Linux universal oleh Canonical.
Berisi: Paket Snap dari toko Snapcraft", + "library": "pustaka", + "feature": "fitur", + "A popular C/C++ library manager. Full of C/C++ libraries and other C/C++-related utilities
Contains: C/C++ libraries and related utilities": "Manajer pustaka C/C++ yang populer. Berisi banyak pustaka C/C++ dan utilitas terkait lainnya
Berisi: pustaka dan utilitas C/C++", + "option": "pilihan", + "This package cannot be installed from an elevated context.": "Paket ini tidak dapat diinstal dari konteks yang ditinggikan.", + "Please run UniGetUI as a regular user and try again.": "Jalankan UniGetUI sebagai pengguna biasa dan coba lagi.", + "Please check the installation options for this package and try again": "Periksa opsi instalasi untuk paket ini dan coba lagi", + "Microsoft's official package manager. Full of well-known and verified packages
Contains: General Software, Microsoft Store apps": "Manajer paket resmi Microsoft. Berisi banyak paket populer dan telah diverifikasi
Berisi: Perangkat Lunak Umum, Aplikasi Microsoft Store", + "Local PC": "PC Lokal", + "Android Subsystem": "Subsistem Android", + "Operation on queue (position {0})...": "Operasi dalam antrean (posisi {0})...", + "Click here for more details": "Klik di sini untuk detail lebih lanjut", + "Operation canceled by user": "Operasi dibatalkan oleh pengguna", + "Running PreOperation ({0}/{1})...": "Menjalankan PreOperation ({0}/{1})...", + "PreOperation {0} out of {1} failed, and was tagged as necessary. Aborting...": "PreOperation {0} dari {1} gagal, dan ditandai sebagai wajib. Membatalkan...", + "PreOperation {0} out of {1} finished with result {2}": "PreOperation {0} dari {1} selesai dengan hasil {2}", + "Starting operation...": "Memulai operasi...", + "Running PostOperation ({0}/{1})...": "Menjalankan PostOperation ({0}/{1})...", + "PostOperation {0} out of {1} failed, and was tagged as necessary. Aborting...": "PostOperation {0} dari {1} gagal, dan ditandai sebagai wajib. Membatalkan...", + "PostOperation {0} out of {1} finished with result {2}": "PostOperation {0} dari {1} selesai dengan hasil {2}", + "{package} installer download": "Unduh penginstal {package}", + "{0} installer is being downloaded": "Penginstal {0} sedang diunduh", + "Download succeeded": "Unduhan berhasil", + "{package} installer was downloaded successfully": "Penginstal {package} berhasil diunduh", + "Download failed": "Unduhan gagal", + "{package} installer could not be downloaded": "Penginstal {package} tidak dapat diunduh", + "{package} Installation": "Instalasi {package}", + "{0} is being installed": "{0} sedang diinstal", + "Installation succeeded": "Pemasangan berhasil", + "{package} was installed successfully": "{package} berhasil dipasang", + "Installation failed": "Pemasangan gagal", + "{package} could not be installed": "{package} tidak dapat diinstal", + "{package} Update": "{package} Pembaruan", + "Update succeeded": "Pembaruan berhasil", + "{package} was updated successfully": "{package} berhasil diperbarui", + "Update failed": "Pembaruan gagal", + "{package} could not be updated": "{package} tidak dapat diperbarui", + "{package} Uninstall": "Hapus Instalasi {package}", + "{0} is being uninstalled": "{0} sedang dihapus instalasi", + "Uninstall succeeded": "Hapus instalasi berhasil", + "{package} was uninstalled successfully": "{package} berhasil dihapus", + "Uninstall failed": "Hapus instalasi gagal", + "{package} could not be uninstalled": "{package} tidak dapat dihapus", + "Adding source {source}": "Menambahkan sumber {source}", + "Adding source {source} to {manager}": "Menambahkan sumber {source} ke {manager}", + "Source added successfully": "Sumber berhasil ditambahkan", + "The source {source} was added to {manager} successfully": "Sumber {source} berhasil ditambahkan ke {manager}", + "Could not add source": "Tidak dapat menambahkan sumber", + "Could not add source {source} to {manager}": "Tidak dapat menambahkan sumber {source} ke {manager}", + "Removing source {source}": "Menghapus sumber {source}", + "Removing source {source} from {manager}": "Menghapus sumber {source} dari {manager}", + "Source removed successfully": "Sumber berhasil dihapus", + "The source {source} was removed from {manager} successfully": "Sumber {source} berhasil dihapus dari {manager}", + "Could not remove source": "Tidak dapat menghapus sumber", + "Could not remove source {source} from {manager}": "Tidak dapat menghapus sumber {source} dari {manager}", + "The package manager \"{0}\" was not found": "Manajer paket \"{0}\" tidak ditemukan", + "The package manager \"{0}\" is disabled": "Manajer paket \"{0}\" dinonaktifkan", + "There is an error with the configuration of the package manager \"{0}\"": "Terjadi kesalahan dengan konfigurasi manajer paket \"{0}\"", + "The package \"{0}\" was not found on the package manager \"{1}\"": "Paket \"{0}\" tidak ditemukan di manajer paket \"{1}\"", + "{0} is disabled": "{0} dinonaktifkan", + "{0} weeks": "{0} minggu", + "1 month": "1 bulan", + "{0} months": "{0} bulan", + "Something went wrong": "Terjadi kesalahan", + "An interal error occurred. Please view the log for further details.": "Terjadi kesalahan internal. Silakan lihat log untuk detail lebih lanjut.", + "No applicable installer was found for the package {0}": "Tidak ditemukan penginstal yang sesuai untuk paket {0}", + "Integrity checks will not be performed during this operation": "Pemeriksaan integritas tidak akan dilakukan selama operasi ini", + "This is not recommended.": "Ini tidak disarankan.", + "Run now": "Jalankan sekarang", + "Run next": "Jalankan berikutnya", + "Run last": "Jalankan terakhir", + "Show in explorer": "Tampilkan di explorer", + "Checked": "Dicentang", + "Unchecked": "Tidak dicentang", + "This package is already installed": "Paket ini sudah terinstal", + "This package can be upgraded to version {0}": "Paket ini dapat ditingkatkan ke versi {0}", + "Updates for this package are ignored": "Pembaruan untuk paket ini diabaikan", + "This package is being processed": "Paket ini sedang diproses", + "This package is not available": "Paket ini tidak tersedia", + "Select the source you want to add:": "Pilih sumber yang ingin Anda tambahkan:", + "Source name:": "Nama sumber:", + "Source URL:": "URL sumber:", + "An error occurred when adding the source: ": "Terjadi kesalahan saat menambahkan sumber: ", + "Package management made easy": "Manajemen paket menjadi mudah", + "version {0}": "versi {0}", + "[RAN AS ADMINISTRATOR]": "[Dijalankan SEBAGAI ADMINISTRATOR]", + "Portable mode": "Mode portabel", + "DEBUG BUILD": "VERSI DEBUG", + "Here you can change UniGetUI's behaviour regarding the following shortcuts. Checking a shortcut will make UniGetUI delete it if if gets created on a future upgrade. Unchecking it will keep the shortcut intact": "Di sini Anda dapat mengubah perilaku UniGetUI terkait pintasan berikut. Mencentang pintasan akan membuat UniGetUI menghapusnya jika dibuat pada peningkatan di masa mendatang. Menghapus centang akan membuat pintasan tetap utuh", + "Manual scan": "Pemindaian manual", + "Existing shortcuts on your desktop will be scanned, and you will need to pick which ones to keep and which ones to remove.": "Shortcut yang ada di desktop Anda akan dipindai, dan Anda harus memilih mana yang akan disimpan dan mana yang akan dihapus.", + "Delete?": "Hapus?", + "I understand": "Saya mengerti", + "Chocolatey setup changed": "Pengaturan Chocolatey berubah", + "UniGetUI no longer includes its own private Chocolatey installation. A legacy UniGetUI-managed Chocolatey installation was detected for this user profile, but system Chocolatey was not found. Chocolatey will stay unavailable in UniGetUI until Chocolatey is installed on the system and UniGetUI is restarted. Applications previously installed through UniGetUI's bundled Chocolatey may still appear under other sources such as Local PC or WinGet.": "UniGetUI tidak lagi menyertakan instalasi Chocolatey privatnya sendiri. Instalasi Chocolatey warisan yang dikelola UniGetUI terdeteksi untuk profil pengguna ini, tetapi Chocolatey sistem tidak ditemukan. Chocolatey akan tetap tidak tersedia di UniGetUI sampai Chocolatey diinstal pada sistem dan UniGetUI dimulai ulang. Aplikasi yang sebelumnya diinstal melalui Chocolatey bawaan UniGetUI mungkin masih muncul di bawah sumber lain seperti PC Lokal atau WinGet.", + "NOTE: This troubleshooter can be disabled from UniGetUI Settings, on the WinGet section": "CATATAN: Pemecah masalah ini dapat dinonaktifkan dari Pengaturan UniGetUI, di bagian WinGet", + "Restart": "Mulai ulang", + "Are you sure you want to delete all shortcuts?": "Apakah Anda yakin ingin menghapus semua pintasan?", + "Any new shorcuts created during an install or an update operation will be deleted automatically, instead of showing a confirmation prompt the first time they are detected.": "Setiap pintasan baru yang dibuat selama instalasi atau pembaruan akan dihapus secara otomatis, alih-alih menampilkan konfirmasi saat pertama kali terdeteksi.", + "Any shorcuts created or modified outside of UniGetUI will be ignored. You will be able to add them via the {0} button.": "Setiap pintasan yang dibuat atau diubah di luar UniGetUI akan diabaikan. Anda dapat menambahkannya melalui tombol {0}.", + "Are you really sure you want to enable this feature?": "Apakah Anda yakin ingin mengaktifkan fitur ini?", + "No new shortcuts were found during the scan.": "Tidak ada pintasan baru yang ditemukan selama pemindaian.", + "How to add packages to a bundle": "Cara menambahkan paket ke bundel", + "In order to add packages to a bundle, you will need to: ": "Untuk menambahkan paket ke bundel, Anda harus:", + "1. Navigate to the \"{0}\" or \"{1}\" page.": "1. Buka halaman \"{0}\" atau \"{1}\".", + "2. Locate the package(s) you want to add to the bundle, and select their leftmost checkbox.": "2. Temukan paket yang ingin Anda tambahkan ke bundel, lalu centang kotak paling kiri.", + "3. When the packages you want to add to the bundle are selected, find and click the option \"{0}\" on the toolbar.": "3. Setelah paket yang ingin ditambahkan ke bundel dipilih, klik opsi \"{0}\" di toolbar.", + "4. Your packages will have been added to the bundle. You can continue adding packages, or export the bundle.": "4. Paket Anda telah ditambahkan ke bundel. Anda dapat menambahkan lebih banyak paket atau mengekspor bundel.", + "Which backup do you want to open?": "Cadangan mana yang ingin Anda buka?", + "Select the backup you want to open. Later, you will be able to review which packages you want to install.": "Pilih cadangan yang ingin Anda buka. Kemudian, Anda akan dapat meninjau paket/program mana yang ingin Anda pulihkan.", + "There are ongoing operations. Quitting UniGetUI may cause them to fail. Do you want to continue?": "Ada operasi yang sedang berjalan. Menutup UniGetUI dapat menyebabkan mereka gagal. Apakah Anda ingin melanjutkan?", + "UniGetUI or some of its components are missing or corrupt.": "UniGetUI atau beberapa komponennya hilang atau rusak.", + "It is strongly recommended to reinstall UniGetUI to adress the situation.": "Sangat disarankan untuk menginstal ulang UniGetUI untuk mengatasi situasi ini.", + "Refer to the UniGetUI Logs to get more details regarding the affected file(s)": "Lihat Log UniGetUI untuk mendapatkan rincian lebih lanjut mengenai file yang terpengaruh", + "Integrity checks can be disabled from the Experimental Settings": "Pemeriksaan integritas dapat dinonaktifkan dari Pengaturan Eksperimental", + "Repair UniGetUI": "Perbaiki UniGetUI", + "Live output": "Output langsung", + "This package bundle had some settings that are potentially dangerous, and may be ignored by default.": "Paket bundel ini memiliki beberapa pengaturan yang berpotensi berbahaya, dan dapat diabaikan secara default.", + "Entries that show in YELLOW will be IGNORED.": "Entri yang ditampilkan dalam warna KUNING akan DIABAIKAN.", + "Entries that show in RED will be IMPORTED.": "Entri yang berwarna MERAH akan DIIMPOR.", + "You can change this behavior on UniGetUI security settings.": "Anda dapat mengubah perilaku ini pada pengaturan keamanan UniGetUI.", + "Open UniGetUI security settings": "Buka pengaturan keamanan UniGetUI", + "Should you modify the security settings, you will need to open the bundle again for the changes to take effect.": "Jika Anda mengubah pengaturan keamanan, Anda harus membuka bundel lagi agar perubahan dapat diterapkan.", + "Details of the report:": "Detail laporan:", + "Are you sure you want to create a new package bundle? ": "Apakah Anda yakin ingin membuat bundel paket baru? ", + "Any unsaved changes will be lost": "Perubahan yang belum disimpan akan hilang", + "Warning!": "Peringatan!", + "For security reasons, custom command-line arguments are disabled by default. Go to UniGetUI security settings to change this. ": "Untuk alasan keamanan, argumen baris perintah khusus dinonaktifkan secara default. Buka pengaturan keamanan UniGetUI untuk mengubahnya.", + "Change default options": "Ubah opsi bawaan", + "Ignore future updates for this package": "Abaikan pembaruan mendatang untuk paket ini", + "For security reasons, pre-operation and post-operation scripts are disabled by default. Go to UniGetUI security settings to change this. ": "Untuk alasan keamanan, skrip pra-operasi dan pasca-operasi dinonaktifkan secara default. Buka pengaturan keamanan UniGetUI untuk mengubahnya.", + "You can define the commands that will be run before or after this package is installed, updated or uninstalled. They will be run on a command prompt, so CMD scripts will work here.": "Anda dapat menentukan perintah yang akan dijalankan sebelum atau sesudah paket ini diinstal, diperbarui, atau dihapus. Perintah-perintah tersebut akan dijalankan pada command prompt, jadi skrip CMD akan bekerja di sini.", + "Change this and unlock": "Ubah ini dan buka kunci", + "{0} Install options are currently locked because {0} follows the default install options.": "{0} Opsi penginstalan saat ini terkunci karena {0} mengikuti opsi penginstalan default.", + "Unset or unknown": "Tidak disetel atau tidak diketahui", + "This package has no screenshots or is missing the icon? Contrbute to UniGetUI by adding the missing icons and screenshots to our open, public database.": "Paket ini tidak memiliki tangkapan layar atau ikon yang hilang? Berkontribusilah ke UniGetUI dengan menambahkan ikon dan tangkapan layar yang hilang ke database publik terbuka kami.", + "Become a contributor": "Jadilah kontributor", + "Update to {0} available": "Pembaruan ke {0} tersedia", + "Reinstall": "Pasang ulang", + "Installer not available": "Pemasang tidak tersedia", + "Version:": "Versi:", + "UniGetUI Version {0}": "UniGetUI Versi {0}", + "Performing backup, please wait...": "Sedang melakukan cadangan, harap tunggu...", + "An error occurred while logging in: ": "Terjadi kesalahan saat masuk:", + "Fetching available backups...": "Mengambil cadangan yang tersedia...", + "Done!": "Selesai!", + "The cloud backup has been loaded successfully.": "Cadangan cloud telah berhasil dimuat.", + "An error occurred while loading a backup: ": "Terjadi kesalahan saat memuat cadangan:", + "Backing up packages to GitHub Gist...": "Mencadangkan paket ke GitHub Gist...", + "Backup Successful": "Pencadangan Berhasil", + "The cloud backup completed successfully.": "Pencadangan cloud berhasil diselesaikan.", + "Could not back up packages to GitHub Gist: ": "Tidak dapat mencadangkan paket ke GitHub Gist:", + "It is not guaranteed that the provided credentials will be stored safely, so you may as well not use the credentials of your bank account": "Tidak dijamin bahwa kredensial yang diberikan akan disimpan dengan aman, jadi sebaiknya jangan gunakan kredensial akun bank Anda", + "Enable the automatic WinGet troubleshooter": "Aktifkan pemecah masalah WinGet otomatis", + "Add updates that fail with a 'no applicable update found' to the ignored updates list": "Tambahkan pembaruan yang gagal dengan pesan 'tidak ditemukan pembaruan yang sesuai' ke daftar yang diabaikan", + "Invalid selection": "Pilihan tidak valid", + "No package was selected": "Tidak ada paket yang dipilih", + "More than 1 package was selected": "Lebih dari 1 paket dipilih", + "List": "Daftar", + "Grid": "Kisi", + "Icons": "Ikon", + "\"{0}\" is a local package and does not have available details": "\"{0}\" adalah paket lokal dan tidak memiliki detail yang tersedia", + "\"{0}\" is a local package and is not compatible with this feature": "\"{0}\" adalah paket lokal dan tidak kompatibel dengan fitur ini", + "Add packages to bundle": "Tambahkan paket ke bundel", + "Preparing packages, please wait...": "Menyiapkan paket, harap tunggu...", + "Loading packages, please wait...": "Memuat paket, harap tunggu...", + "Saving packages, please wait...": "Menyimpan paket, harap tunggu...", + "The bundle was created successfully on {0}": "Paket telah dibuat dengan sukses pada {0}", + "User profile": "Profil pengguna", + "Error": "Kesalahan", + "Log in failed: ": "Gagal masuk:", + "Log out failed: ": "Logout gagal:", + "Package backup settings": "Pengaturan pencadangan paket", + "Manage UniGetUI autostart behaviour from the Settings app": "Kelola perilaku mulai otomatis UniGetUI", + "Choose how many operations shoulds be performed in parallel": "Pilih berapa banyak operasi yang harus dilakukan secara paralel", + "Something went wrong while launching the updater.": "Terjadi kesalahan saat meluncurkan pembaru.", + "Please try again later": "Silakan coba lagi nanti", + "Show the release notes after UniGetUI is updated": "Tampilkan catatan rilis setelah UniGetUI diperbarui" +} diff --git a/src/Languages/lang_it.json b/src/Languages/lang_it.json new file mode 100644 index 0000000..c988973 --- /dev/null +++ b/src/Languages/lang_it.json @@ -0,0 +1,850 @@ +{ + "{0} of {1} operations completed": "{0} di {1} operazioni completate", + "{0} is now {1}": "{0} è ora {1}", + "Enabled": "Abilitato", + "Disabled": "Disabilitato", + "Privacy": "Privacy", + "Hide my username from the logs": "Nascondi il mio nome utente dai log", + "Replaces your username with **** in the logs. Restart UniGetUI to also hide it from already-recorded entries.": "Sostituisce il tuo nome utente con **** nei log. Riavvia UniGetUI per nasconderlo anche dalle voci già registrate.", + "Your last update attempt did not complete.": "L'ultimo tentativo di aggiornamento non è stato completato.", + "UniGetUI could not confirm whether the update succeeded. Open the log to see what happened.": "UniGetUI non ha potuto confermare se l'aggiornamento è riuscito. Apri il log per vedere cosa è successo.", + "View log": "Visualizza log", + "The installer reported success but did not restart UniGetUI.": "Il programma di installazione ha segnalato il completamento, ma non ha riavviato UniGetUI.", + "The installer failed to initialize.": "Il programma di installazione non è riuscito a inizializzarsi.", + "Setup was canceled before installation began.": "L'installazione guidata è stata annullata prima dell'inizio dell'installazione.", + "A fatal error occurred during the preparation phase.": "Si è verificato un errore irreversibile durante la fase di preparazione.", + "A fatal error occurred during installation.": "Si è verificato un errore irreversibile durante l'installazione.", + "Installation was canceled while in progress.": "L'installazione è stata annullata mentre era in corso.", + "The installer was terminated by another process.": "Il programma di installazione è stato terminato da un altro processo.", + "The preparation phase determined the installation cannot proceed.": "La fase di preparazione ha stabilito che l'installazione non può proseguire.", + "The installer could not start. UniGetUI may already be running, or you do not have permission to install.": "Il programma di installazione non è riuscito ad avviarsi. UniGetUI potrebbe essere già in esecuzione oppure potresti non disporre dell'autorizzazione per installare.", + "Unexpected installer error.": "Errore imprevisto del programma di installazione.", + "We are checking for updates.": "Stiamo verificando gli aggiornamenti.", + "Please wait": "Attendi", + "Great! You are on the latest version.": "Ottimo! Sei all'ultima versione.", + "There are no new UniGetUI versions to be installed": "Non ci sono nuove versioni di UniGetUI da installare", + "UniGetUI version {0} is being downloaded.": "È in fase di scaricamento la versione {0} di UniGetUI.", + "This may take a minute or two": "L'operazione potrebbe richiedere un minuto o due", + "The installer authenticity could not be verified.": "Non è stato possibile verificare l'autenticità del programma di installazione.", + "The update process has been aborted.": "Il processo di aggiornamento è stato interrotto.", + "Auto-update is not yet available on this platform.": "L'aggiornamento automatico non è ancora disponibile su questa piattaforma.", + "Please update UniGetUI manually.": "Aggiorna UniGetUI manualmente.", + "An error occurred when checking for updates: ": "Si è verificato un errore durante il controllo degli aggiornamenti: ", + "The updater could not be launched.": "Non è stato possibile avviare il programma di aggiornamento.", + "The operating system did not start the installer process.": "Il sistema operativo non ha avviato il processo del programma di installazione.", + "UniGetUI is being updated...": "UniGetUI è in fase di aggiornamento...", + "Update installed.": "Aggiornamento installato.", + "UniGetUI was updated successfully, but this running copy was not replaced. This usually means you are running a development build. Close this copy and start the newly-installed version to finish.": "UniGetUI è stato aggiornato correttamente, ma questa copia in esecuzione non è stata sostituita. Di solito ciò significa che stai eseguendo una build di sviluppo. Chiudi questa copia e avvia la versione appena installata per completare l'operazione.", + "The update could not be applied.": "Non è stato possibile applicare l'aggiornamento.", + "Installer exit code {0}: {1}": "Codice di uscita del programma di installazione {0}: {1}", + "Update cancelled.": "Aggiornamento annullato.", + "Authentication was cancelled.": "Autenticazione annullata.", + "Installer exit code {0}": "Codice di uscita del programma di installazione {0}", + "Operation in progress": "Operazione in corso", + "Please wait...": "Attendi...", + "Success!": "Perfetto!", + "Failed": "Non riuscito", + "An error occurred while processing this package": "Si è verificato un errore durante l'elaborazione di questo pacchetto", + "Installer": "Programma di installazione", + "Executable": "Eseguibile", + "MSI": "MSI", + "Compressed file": "File compresso", + "MSIX": "MSIX", + "WinGet was repaired successfully": "WinGet è stato riparato correttamente", + "It is recommended to restart UniGetUI after WinGet has been repaired": "Si consiglia di riavviare UniGetUI dopo che WinGet è stato riparato", + "WinGet could not be repaired": "WinGet non può essere riparato", + "An unexpected issue occurred while attempting to repair WinGet. Please try again later": "Si è verificato un problema imprevisto durante il tentativo di riparare WinGet. Riprova più tardi", + "Log in to enable cloud backup": "Accedi per abilitare il backup su cloud", + "Backup Failed": "Backup non riuscito", + "Downloading backup...": "Scaricamento del backup...", + "An update was found!": "È stato trovato un aggiornamento!", + "{0} can be updated to version {1}": "{0} può essere aggiornato alla versione {1}", + "Updates found!": "Aggiornamenti trovati!", + "{0} packages can be updated": "{0} pacchetti possono essere aggiornati", + "{0} is being updated to version {1}": "{0} è in fase di aggiornamento alla versione {1}", + "{0} packages are being updated": "{0} pacchetti sono in fase di aggiornamento", + "You have currently version {0} installed": "Attualmente hai installata la versione {0}", + "Desktop shortcut created": "Collegamento sul desktop creato", + "UniGetUI has detected a new desktop shortcut that can be deleted automatically.": "UniGetUI ha rilevato un nuovo collegamento sul desktop che può essere eliminato automaticamente.", + "{0} desktop shortcuts created": "{0} collegamenti sul desktop creati", + "UniGetUI has detected {0} new desktop shortcuts that can be deleted automatically.": "UniGetUI ha rilevato {0} nuovi collegamenti sul desktop che possono essere eliminati automaticamente.", + "Attention required": "È richiesta attenzione", + "Restart required": "Riavvio richiesto", + "1 update is available": "È disponibile 1 aggiornamento", + "{0} updates are available": "Sono disponibili {0} aggiornamenti", + "Everything is up to date": "Tutto aggiornato", + "Discover Packages": "Ricerca pacchetti", + "Available Updates": "Aggiornamenti disponibili", + "Installed Packages": "Pacchetti installati", + "UniGetUI Version {0} by Devolutions": "UniGetUI Versione {0} di Devolutions", + "Show UniGetUI": "Mostra UniGetUI", + "Quit": "Esci", + "Are you sure?": "Sei sicuro?", + "Do you really want to uninstall {0}?": "Vuoi veramente disinstallare {0}?", + "Do you really want to uninstall the following {0} packages?": "Vuoi davvero disinstallare i seguenti {0} pacchetti?", + "No": "No", + "Yes": "Sì", + "Partial": "Parziale", + "View on UniGetUI": "Visualizza su UniGetUI", + "Update": "Aggiorna", + "Open UniGetUI": "Apri UniGetUI", + "Update all": "Aggiorna tutto", + "Update now": "Aggiorna adesso", + "Installer host changed since the installed version.\n": "L'host del programma di installazione è cambiato rispetto alla versione installata.\n", + "This package is on the queue": "Questo pacchetto è in coda", + "installing": "installazione", + "updating": "aggiornamento", + "uninstalling": "disinstallazione", + "installed": "installato", + "Retry": "Riprova", + "Install": "Installa", + "Uninstall": "Disinstalla", + "Open": "Apri", + "Operation profile:": "Profilo operativo:", + "Follow the default options when installing, upgrading or uninstalling this package": "Segui le opzioni predefinite durante l'installazione, l'aggiornamento o la disinstallazione di questo pacchetto", + "The following settings will be applied each time this package is installed, updated or removed.": "Le seguenti impostazioni verranno applicate ogni volta che il pacchetto viene installato, aggiornato o rimosso.", + "Version to install:": "Versione da installare:", + "Architecture to install:": "Architettura da installare:", + "Installation scope:": "Modalità di installazione:", + "Install location:": "Percorso di installazione:", + "Select": "Seleziona", + "Reset": "Reimposta", + "Custom install arguments:": "Argomenti di installazione personalizzati:", + "Custom update arguments:": "Argomenti di aggiornamento personalizzati:", + "Custom uninstall arguments:": "Argomenti di disinstallazione personalizzati:", + "Pre-install command:": "Comando pre-installazione:", + "Post-install command:": "Comando post-installazione:", + "Abort install if pre-install command fails": "Interrompi l'installazione se il comando di pre-installazione fallisce", + "Pre-update command:": "Comando pre-aggiornamento:", + "Post-update command:": "Comando post-aggiornamento:", + "Abort update if pre-update command fails": "Interrompi l'aggiornamento se il comando di pre-aggiornamento fallisce", + "Pre-uninstall command:": "Comando pre-disinstallazione:", + "Post-uninstall command:": "Comando post-disinstallazione:", + "Abort uninstall if pre-uninstall command fails": "Interrompi la disinstallazione se il comando di pre-disinstallazione fallisce", + "Command-line to run:": "Riga di comando per eseguire:", + "Save and close": "Salva e chiudi", + "General": "Generale", + "Architecture & Location": "Architettura e posizione", + "Command-line": "Riga di comando", + "Close apps": "Chiudi app", + "Pre/Post install": "Pre/Post installazione", + "Select the processes that should be closed before this package is installed, updated or uninstalled.": "Seleziona i processi che devono essere chiusi prima che questo pacchetto venga installato, aggiornato o disinstallato.", + "Write here the process names here, separated by commas (,)": "Scrivi qui i nomi dei processi, separati da virgole (,)", + "Try to kill the processes that refuse to close when requested to": "Prova a fermare i processi che rifiutano di chiudersi quando richiesto", + "Run as admin": "Esegui come amministratore", + "Interactive installation": "Installazione interattiva", + "Skip hash check": "Salta controllo hash", + "Uninstall previous versions when updated": "Disinstalla le versioni precedenti quando aggiorni", + "Skip minor updates for this package": "Salta aggiornamenti minori per questo pacchetto", + "Automatically update this package": "Aggiorna automaticamente questo pacchetto", + "{0} installation options": "Opzioni di installazione di {0}", + "Latest": "Più recente", + "PreRelease": "Versione di sviluppo", + "Default": "Predefinito", + "Manage ignored updates": "Gestisci aggiornamenti ignorati", + "The packages listed here won't be taken in account when checking for updates. Double-click them or click the button on their right to stop ignoring their updates.": "I pacchetti elencati qui non verranno presi in considerazione durante il controllo degli aggiornamenti. Fai doppio clic su di essi o fai clic sul pulsante alla loro destra per non ignorare gli aggiornamenti.", + "Reset list": "Reimposta elenco", + "Do you really want to reset the ignored updates list? This action cannot be reverted": "Vuoi davvero reimpostare l'elenco degli aggiornamenti ignorati? Questa azione non può essere annullata", + "No ignored updates": "Nessun aggiornamento ignorato", + "Package Name": "Nome pacchetto", + "Package ID": "ID pacchetto", + "Ignored version": "Versione ignorata", + "New version": "Nuova versione", + "Source": "Sorgente", + "All versions": "Tutte le versioni", + "Unknown": "Sconosciuto", + "Up to date": "Aggiornato", + "Package {name} from {manager}": "Pacchetto {name} da {manager}", + "Remove {0} from ignored updates": "Rimuovi {0} dagli aggiornamenti ignorati", + "Cancel": "Annulla", + "Administrator privileges": "Privilegi di amministratore", + "This operation is running with administrator privileges.": "Questa operazione viene eseguita con privilegi di amministratore.", + "Interactive operation": "Operazione interattiva", + "This operation is running interactively.": "Questa operazione viene eseguita in modo interattivo.", + "You will likely need to interact with the installer.": "Probabilmente sarà necessario interagire con il programma di installazione.", + "Integrity checks skipped": "Controlli di integrità saltati", + "Integrity checks will not be performed during this operation.": "I controlli di integrità non verranno eseguiti durante questa operazione.", + "Proceed at your own risk.": "Procedi a tuo rischio e pericolo.", + "Close": "Chiudi", + "Loading...": "Caricamento...", + "Installer SHA256": "SHA256 installer", + "Homepage": "Pagina iniziale", + "Author": "Autore", + "Publisher": "Editore", + "License": "Licenza", + "Manifest": "Manifesto", + "Installer Type": "Tipo installer", + "Size": "Dimensioni", + "Installer URL": "URL installer", + "Last updated:": "Ultimo aggiornamento:", + "Release notes URL": "URL note sulla versione", + "Package details": "Dettagli pacchetto", + "Dependencies:": "Dipendenze:", + "Release notes": "Note sulla versione", + "Screenshots": "Screenshot", + "This package has no screenshots or is missing the icon? Contribute to UniGetUI by adding the missing icons and screenshots to our open, public database.": "Questo pacchetto non contiene screenshot o manca dell'icona? Contribuisci a UniGetUI aggiungendo le icone e gli screenshot mancanti al nostro database pubblico e aperto.", + "Version": "Versione", + "Install as administrator": "Installa come amministratore", + "Update to version {0}": "Aggiorna alla versione {0}", + "Installed Version": "Versione installata", + "Update as administrator": "Aggiorna come amministratore", + "Interactive update": "Aggiornamento interattivo", + "Uninstall as administrator": "Disinstalla come amministratore", + "Interactive uninstall": "Disinstallazione interattiva", + "Uninstall and remove data": "Disinstalla e rimuovi dati", + "Not available": "Non disponibile", + "Installer SHA512": "SHA512 installer", + "Unknown size": "Dimensioni sconosciute", + "No dependencies specified": "Nessuna dipendenza specificata", + "mandatory": "obbligatorio", + "optional": "opzionale", + "UniGetUI {0} is ready to be installed.": "UniGetUI {0} è pronto per essere installato.", + "The update process will start after closing UniGetUI": "Il processo di aggiornamento inizierà dopo la chiusura di UniGetUI", + "UniGetUI has been ran as administrator, which is not recommended. When running UniGetUI as administrator, EVERY operation launched from UniGetUI will have administrator privileges. You can still use the program, but we highly recommend not running UniGetUI with administrator privileges.": "UniGetUI è stato eseguito come amministratore, cosa non consigliata. Quando esegui UniGetUI come amministratore, OGNI operazione avviata da UniGetUI avrà privilegi di amministratore. Puoi comunque usare il programma, ma consigliamo vivamente di non eseguire UniGetUI con privilegi di amministratore.", + "Share anonymous usage data": "Condividi dati di utilizzo anonimi", + "UniGetUI collects anonymous usage data in order to improve the user experience.": "UniGetUI raccoglie dati di utilizzo anonimi per migliorare l'esperienza dell'utente.", + "Accept": "Accetta", + "Software Updates": "Aggiorna pacchetti", + "Package Bundles": "Raccolte pacchetti", + "Settings": "Impostazioni", + "Package Managers": "Gestori pacchetti", + "UniGetUI Log": "Log di UniGetUI", + "Package Manager logs": "Log gestore pacchetti", + "Operation history": "Cronologia operazioni", + "Help": "Aiuto", + "UniGetUI": "UniGetUI", + "You have installed UniGetUI Version {0}": "Hai installato la versione {0} di UniGetUI", + "Disclaimer": "Esclusione di responsabilità", + "UniGetUI is developed by Devolutions and is not affiliated with any of the compatible package managers.": "UniGetUI è sviluppato da Devolutions e non è affiliato ad alcuno dei gestori di pacchetti compatibili.", + "UniGetUI wouldn't have been possible without the help of the contributors. Thank you all 🥳": "UniGetUI non sarebbe stato possibile senza l'aiuto dei collaboratori. Grazie a tutti 🥳", + "UniGetUI uses the following libraries. Without them, UniGetUI wouldn't have been possible.": "UniGetUI si avvale delle seguenti librerie. Senza di esse, UniGetUI non sarebbe stato realizzabile.", + "{0} homepage": "Sito web di {0}", + "UniGetUI has been translated to more than 40 languages thanks to the volunteer translators. Thank you 🤝": "UniGetUI è stato tradotto in oltre 40 lingue da traduttori volontari. Un grande grazie a tutti 🤝", + "Verbose": "Verboso", + "1 - Errors": "1 - Errori", + "2 - Warnings": "2 - Avvertimenti", + "3 - Information (less)": "3 - Informazioni (meno)", + "4 - Information (more)": "4 - Informazioni (più)", + "5 - information (debug)": "5 - informazioni (debug)", + "Warning": "Attenzione", + "The following settings may pose a security risk, hence they are disabled by default.": "Le seguenti impostazioni potrebbero rappresentare un rischio per la sicurezza, pertanto sono disabilitate per impostazione predefinita.", + "Enable the settings below if and only if you fully understand what they do, and the implications they may have.": "Abilita le impostazioni sottostanti solo se hai compreso completamente a cosa servono e quali implicazioni potrebbero avere.", + "The settings will list, in their descriptions, the potential security issues they may have.": "Le impostazioni elencheranno, nelle loro descrizioni, i potenziali problemi di sicurezza che si potrebbero presentare.", + "The backup will include the complete list of the installed packages and their installation options. Ignored updates and skipped versions will also be saved.": "Il backup includerà l'elenco completo dei pacchetti installati e le relative opzioni di installazione. Verranno salvati anche gli aggiornamenti ignorati e le versioni saltate.", + "The backup will NOT include any binary file nor any program's saved data.": "Il backup NON includerà alcun file binario né dati salvati del programma.", + "The size of the backup is estimated to be less than 1MB.": "La dimensione del backup sarà inferiore a 1 MB.", + "The backup will be performed after login.": "Il backup verrà eseguito dopo l'accesso.", + "{pcName} installed packages": "Pacchetti installati su {pcName}", + "Current status: Not logged in": "Stato attuale: Non connesso", + "You are logged in as {0} (@{1})": "Hai effettuato l'accesso come {0} (@{1})", + "Nice! Backups will be uploaded to a private gist on your account": "Perfetto! I backup verranno caricati su un gist privato sul tuo account.", + "Select backup": "Seleziona backup", + "Settings imported from {0}": "Impostazioni importate da {0}", + "UniGetUI Settings": "Impostazioni di UniGetUI", + "Settings exported to {0}": "Impostazioni esportate in {0}", + "UniGetUI settings were reset": "Le impostazioni di UniGetUI sono state reimpostate", + "Allow pre-release versions": "Consenti le versioni di sviluppo", + "Apply": "Applica", + "For security reasons, custom command-line arguments are disabled by default. Go to UniGetUI security settings to change this.": "Per motivi di sicurezza, gli argomenti personalizzati della riga di comando sono disabilitati per impostazione predefinita. Vai alle impostazioni di sicurezza di UniGetUI per modificare questa opzione.", + "Go to UniGetUI security settings": "Vai alle impostazioni di sicurezza di UniGetUI", + "The following options will be applied by default each time a {0} package is installed, upgraded or uninstalled.": "Le seguenti opzioni verranno applicate per impostazione predefinita ogni volta che un pacchetto {0} viene installato, aggiornato o disinstallato.", + "Package's default": "Predefinito del pacchetto", + "Install location can't be changed for {0} packages": "Il percorso di installazione non può essere modificato per i pacchetti {0}", + "The local icon cache currently takes {0} MB": "La cache delle icone locali occupa attualmente {0} MB", + "Username": "Nome utente", + "Password": "Password di accesso", + "Credentials": "Credenziali", + "It is not guaranteed that the provided credentials will be stored safely": "Non è garantito che le credenziali fornite vengano archiviate in modo sicuro", + "Partially": "Parzialmente", + "Package manager": "Gestore pacchetti", + "Compatible with proxy": "Compatibile con proxy", + "Compatible with authentication": "Compatibile con autenticazione", + "Proxy compatibility table": "Tabella di compatibilità dei proxy", + "{0} settings": "Impostazioni {0}", + "{0} status": "Stato {0}", + "Default installation options for {0} packages": "Opzioni di installazione predefinite per i pacchetti {0}", + "Expand version": "Espandi versione", + "The executable file for {0} was not found": "Il file eseguibile per {0} non è stato trovato", + "{pm} is disabled": "{pm} è disabilitato", + "Enable it to install packages from {pm}.": "Abilita per installare pacchetti da {pm}.", + "{pm} is enabled and ready to go": "{pm} è abilitato e pronto per l'uso", + "{pm} version:": "Versione di {pm}:", + "{pm} was not found!": "{pm} non è stato trovato!", + "You may need to install {pm} in order to use it with UniGetUI.": "Potrebbe essere necessario installare {pm} per poterlo utilizzare con UniGetUI.", + "Scoop Installer - UniGetUI": "Programma di installazione di Scoop: UniGetUI", + "Scoop Uninstaller - UniGetUI": "Programma di disinstallazione di Scoop: UniGetUI", + "Clearing Scoop cache - UniGetUI": "Svuotamento cache di Scoop: UniGetUI", + "Restart UniGetUI to fully apply changes": "Riavvia UniGetUI per applicare completamente le modifiche", + "Restart UniGetUI": "Riavvia UniGetUI", + "Manage {0} sources": "Gestisci {0} sorgenti", + "Add source": "Aggiungi sorgente", + "Add": "Aggiungi", + "Source name": "Nome sorgente", + "Source URL": "URL sorgente", + "Other": "Altro", + "No minimum age": "Nessuna età minima", + "1 day": "1 giorno", + "{0} days": "{0} giorni", + "Custom...": "Personalizzato...", + "{0} minutes": "{0} minuti", + "1 hour": "1 ora", + "{0} hours": "{0} ore", + "1 week": "1 settimana", + "Supports release dates": "Supporta le date di rilascio", + "Release date support per package manager": "Supporto delle date di rilascio per ogni gestore di pacchetti", + "Search for packages": "Ricerca pacchetti", + "Local": "Locale", + "OK": "OK", + "Last checked: {0}": "Ultimo controllo: {0}", + "{0} packages were found, {1} of which match the specified filters.": "Sono stati trovati {0} pacchetti, {1} dei quali corrispondono ai filtri specificati.", + "{0} selected": "{0} selezionati", + "(Last checked: {0})": "(Ultimo controllo: {0})", + "All packages selected": "Tutti i pacchetti selezionati", + "Package selection cleared": "Selezione dei pacchetti cancellata", + "{0}: {1}": "{0}: {1}", + "More info": "Più informazioni", + "GitHub account": "Account GitHub", + "Log in with GitHub to enable cloud package backup.": "Accedi con GitHub per abilitare il backup dei pacchetti sul cloud.", + "More details": "Più dettagli", + "Log in": "Accesso", + "If you have cloud backup enabled, it will be saved as a GitHub Gist on this account": "Se hai abilitato il backup sul cloud, verrà salvato come GitHub Gist su questo account", + "Log out": "Disconnessione", + "About UniGetUI": "Informazioni su UniGetUI", + "About": "Informazioni su", + "Third-party licenses": "Licenze di terze parti", + "Contributors": "Collaboratori", + "Translators": "Traduttori", + "Bundle security report": "Rapporto sulla sicurezza delle raccolte", + "The bundle contained restricted content": "La raccolta conteneva contenuti soggetti a restrizioni", + "UniGetUI – Crash Report": "UniGetUI – Segnalazione di errore", + "UniGetUI has crashed": "UniGetUI si è bloccato", + "Help us fix this by sending a crash report to Devolutions. All fields below are optional.": "Aiutaci a risolvere il problema inviando una segnalazione di errore a Devolutions. Tutti i campi sottostanti sono facoltativi.", + "Email (optional)": "Email (facoltativo)", + "your@email.com": "tua@email.com", + "Additional details (optional)": "Dettagli aggiuntivi (facoltativo)", + "Describe what you were doing when the crash occurred…": "Descrivi cosa stavi facendo quando si è verificato l'errore…", + "Crash report": "Segnalazione di errore", + "Don't Send": "Non inviare", + "Send Report": "Invia segnalazione", + "Sending…": "Invio in corso…", + "Unsaved changes": "Modifiche non salvate", + "You have unsaved changes in the current bundle. Do you want to discard them?": "Sono presenti modifiche non salvate nella raccolta corrente. Vuoi scartarle?", + "Discard changes": "Scarta modifiche", + "Integrity violation": "Violazione dell'integrità", + "UniGetUI or some of its components are missing or corrupt. It is strongly recommended to reinstall UniGetUI to adress the situation.": "UniGetUI o alcuni dei suoi componenti sono mancanti o danneggiati. Si consiglia vivamente di reinstallare UniGetUI per risolvere la situazione.", + "• Refer to the UniGetUI Logs to get more details regarding the affected file(s)": "• Fai riferimento ai log di UniGetUI per ottenere maggiori dettagli sui file interessati", + "• Integrity checks can be disabled from the Experimental Settings": "• I controlli di integrità possono essere disabilitati dalle Impostazioni sperimentali", + "Manage shortcuts": "Gestisci collegamenti", + "UniGetUI has detected the following desktop shortcuts which can be removed automatically on future upgrades": "UniGetUI ha rilevato i seguenti collegamenti sul desktop che possono essere rimossi automaticamente durante gli aggiornamenti futuri", + "Do you really want to reset this list? This action cannot be reverted.": "Vuoi davvero reimpostare questo elenco? Questa azione non può essere annullata.", + "Desktop shortcuts list": "Elenco collegamenti sul desktop", + "Open in explorer": "Apri in Esplora file", + "Remove from list": "Rimuovi dall'elenco", + "When new shortcuts are detected, delete them automatically instead of showing this dialog.": "Quando vengono rilevati nuovi collegamenti, questi vengono eliminati automaticamente anziché visualizzare questa finestra di dialogo.", + "Not right now": "Non adesso", + "Missing dependency": "Dipendenza mancante", + "UniGetUI requires {0} to operate, but it was not found on your system.": "UniGetUI richiede {0} per funzionare, ma non è stato trovato sul tuo sistema.", + "Click on Install to begin the installation process. If you skip the installation, UniGetUI may not work as expected.": "Fai clic su Installa per avviare il processo di installazione. Se salti l'installazione, UniGetUI potrebbe non funzionare come previsto.", + "Alternatively, you can also install {0} by running the following command in a Windows PowerShell prompt:": "In alternativa, puoi anche installare {0} eseguendo il seguente comando in un prompt di Windows PowerShell:", + "Install {0}": "Installa {0}", + "Do not show this dialog again for {0}": "Non mostrare più questa finestra di dialogo per {0}", + "Please wait while {0} is being installed. A black window may show up. Please wait until it closes.": "Attendi mentre {0} viene installato. Potrebbe apparire una finestra nera. Attendi che si chiuda.", + "{0} has been installed successfully.": "{0} è stato installato correttamente.", + "Please click on \"Continue\" to continue": "Fai clic su \"Continua\" per continuare", + "Continue": "Continua", + "{0} has been installed successfully. It is recommended to restart UniGetUI to finish the installation": "{0} è stato installato correttamente. Si consiglia di riavviare UniGetUI per completare l'installazione", + "Restart later": "Riavvia più tardi", + "An error occurred:": "Si è verificato un errore:", + "Please see the Command-line Output or refer to the Operation History for further information about the issue.": "Per ulteriori informazioni sul problema, consulta l'output della riga di comando o fai riferimento alla cronologia delle operazioni.", + "Retry as administrator": "Riprova come amministratore", + "Retry interactively": "Riprova in modo interattivo", + "Retry skipping integrity checks": "Riprova saltando i controlli di integrità", + "Installation options": "Opzioni installazione", + "Save": "Salva", + "UniGetUI collects anonymous usage data with the sole purpose of understanding and improving the user experience.": "UniGetUI raccoglie dati di utilizzo anonimi con l'unico scopo di comprendere e migliorare l'esperienza dell'utente.", + "More details about the shared data and how it will be processed": "Maggiori dettagli sui dati condivisi e su come verranno elaborati", + "Do you accept that UniGetUI collects and sends anonymous usage statistics, with the sole purpose of understanding and improving the user experience?": "Accetti che UniGetUI raccolga e invii statistiche anonime sull'utilizzo, con l'unico scopo di comprendere e migliorare l'esperienza dell'utente?", + "Decline": "Rifiuta", + "No personal information is collected nor sent, and the collected data is anonimized, so it can't be back-tracked to you.": "Non vengono raccolte né inviate informazioni personali e i dati raccolti vengono resi anonimi, quindi non è possibile risalire alla tua identità.", + "Navigation panel": "Pannello di navigazione", + "Operations": "Operazioni", + "Toggle operations panel": "Attiva/disattiva il pannello delle operazioni", + "Bulk operations": "Operazioni in blocco", + "Retry failed": "Riprova le operazioni non riuscite", + "Clear successful": "Cancella le operazioni riuscite", + "Clear finished": "Cancella le operazioni terminate", + "Cancel all": "Annulla tutto", + "More": "Altro", + "Toggle navigation panel": "Mostra/nascondi pannello di navigazione", + "Minimize": "Minimizza", + "Maximize": "Massimizza", + "UniGetUI by Devolutions": "UniGetUI di Devolutions", + "UniGetUI is an application that makes managing your software easier, by providing an all-in-one graphical interface for your command-line package managers.": "UniGetUI è un'applicazione che semplifica la gestione del software, fornendo un'unica interfaccia grafica per i gestori di pacchetti da riga di comando.", + "Useful links": "Link utili", + "UniGetUI Homepage": "Sito web di UniGetUI", + "Report an issue or submit a feature request": "Segnala un problema o invia una richiesta di funzionalità", + "UniGetUI Repository": "Repository di UniGetUI", + "View GitHub Profile": "Visualizza profilo GitHub", + "UniGetUI License": "Licenza di UniGetUI", + "Using UniGetUI implies the acceptation of the MIT License": "L'utilizzo di UniGetUI implica l'accettazione della Licenza MIT", + "Become a translator": "Diventa un traduttore", + "Go back": "Indietro", + "Go forward": "Avanti", + "Go to home page": "Vai alla pagina iniziale", + "Reload page": "Ricarica pagina", + "View page on browser": "Visualizza pagina sul browser", + "The built-in browser is not supported on Linux yet.": "Il browser integrato non è ancora supportato su Linux.", + "Open in browser": "Apri nel browser", + "Copy to clipboard": "Copia negli appunti", + "Export to a file": "Esporta in un file", + "Log level:": "Livello di log:", + "Reload log": "Ricarica log", + "Export log": "Esporta log", + "Text": "Testo", + "Change how operations request administrator rights": "Modifica il modo in cui le operazioni richiedono i diritti di amministratore", + "Restrictions on package operations": "Restrizioni sulle operazioni dei pacchetti", + "Restrictions on package managers": "Restrizioni sui gestori di pacchetti", + "Restrictions when importing package bundles": "Restrizioni durante l'importazione delle raccolte pacchetti", + "Ask for administrator privileges once for each batch of operations": "Richiedi una sola volta i privilegi di amministratore per ogni operazione in serie", + "Ask only once for administrator privileges": "Richiedi solo una volta i privilegi di amministratore", + "Prohibit any kind of Elevation via UniGetUI Elevator or GSudo": "Vieta qualsiasi tipo di elevazione tramite UniGetUI Elevator o GSudo", + "This option WILL cause issues. Any operation incapable of elevating itself WILL FAIL. Install/update/uninstall as administrator will NOT WORK.": "Questa opzione CAUSERÀ problemi. Qualsiasi operazione che non sia in grado di elevare i propri privilegi FALLIRÀ. Installare/aggiornare/disinstallare come amministratore NON FUNZIONERÀ.", + "Allow custom command-line arguments": "Consenti argomenti personalizzati della riga di comando", + "Custom command-line arguments can change the way in which programs are installed, upgraded or uninstalled, in a way UniGetUI cannot control. Using custom command-lines can break packages. Proceed with caution.": "Gli argomenti personalizzati della riga di comando possono modificare il modo in cui i programmi vengono installati, aggiornati o disinstallati, in un modo che UniGetUI non può controllare. L'utilizzo di righe di comando personalizzate può danneggiare i pacchetti. Procedi con cautela.", + "Ignore custom pre-install and post-install commands when importing packages from a bundle": "Ignora i comandi di pre-installazione e post-installazione personalizzati quando importi pacchetti da una raccolta", + "Pre and post install commands will be run before and after a package gets installed, upgraded or uninstalled. Be aware that they may break things unless used carefully": "I comandi pre e post installazione verranno eseguiti prima e dopo l'installazione, l'aggiornamento o la disinstallazione di un pacchetto. Si prega di notare che potrebbero causare problemi se non utilizzati con attenzione.", + "Allow changing the paths for package manager executables": "Consenti la modifica dei percorsi per gli eseguibili del gestore pacchetti", + "Turning this on enables changing the executable file used to interact with package managers. While this allows finer-grained customization of your install processes, it may also be dangerous": "Attivando questa opzione è possibile modificare il file eseguibile utilizzato per interagire con i gestori di pacchetti. Sebbene ciò consenta una personalizzazione più precisa dei processi di installazione, potrebbe anche essere pericoloso.", + "Allow importing custom command-line arguments when importing packages from a bundle": "Consenti l'importazione di argomenti personalizzati dalla riga di comando durante l'importazione di pacchetti da una raccolta", + "Malformed command-line arguments can break packages, or even allow a malicious actor to gain privileged execution. Therefore, importing custom command-line arguments is disabled by default": "Argomenti della riga di comando non validi possono danneggiare i pacchetti o persino consentire a un malintenzionato di ottenere privilegi di esecuzione. Pertanto, l'importazione di argomenti della riga di comando personalizzati è disabilitata per impostazione predefinita.", + "Allow importing custom pre-install and post-install commands when importing packages from a bundle": "Consenti l'importazione di comandi pre-installazione e post-installazione personalizzati durante l'importazione di pacchetti da una raccolta", + "Pre and post install commands can do very nasty things to your device, if designed to do so. It can be very dangerous to import the commands from a bundle, unless you trust the source of that package bundle": "I comandi pre e post installazione possono avere effetti molto dannosi sul dispositivo, se progettati per questo scopo. Può essere molto pericoloso importare i comandi da una raccolta, a meno che non ci si fidi della sorgente di quel pacchetto.", + "Administrator rights and other dangerous settings": "Diritti di amministratore e altre impostazioni pericolose", + "Package backup": "Backup pacchetto", + "Cloud package backup": "Backup dei pacchetti sul cloud", + "Local package backup": "Backup locale del pacchetto", + "Local backup advanced options": "Opzioni avanzate del backup locale", + "Log in with GitHub": "Accedi con GitHub", + "Log out from GitHub": "Disconnessione da GitHub", + "Periodically perform a cloud backup of the installed packages": "Esegui periodicamente un backup sul cloud dei pacchetti installati", + "Cloud backup uses a private GitHub Gist to store a list of installed packages": "Il backup sul cloud utilizza un GitHub Gist privato per archiviare un elenco dei pacchetti installati", + "Perform a cloud backup now": "Esegui subito un backup sul cloud", + "Backup": "Esegui backup", + "Restore a backup from the cloud": "Ripristina un backup dal cloud", + "Begin the process to select a cloud backup and review which packages to restore": "Inizia il processo per selezionare un backup dal cloud e rivedere quali pacchetti ripristinare", + "Periodically perform a local backup of the installed packages": "Esegui periodicamente un backup locale dei pacchetti installati", + "Perform a local backup now": "Esegui subito un backup locale", + "Change backup output directory": "Modifica cartella di destinazione del backup", + "Set a custom backup file name": "Personalizza nome del file di backup", + "Leave empty for default": "Lascia vuoto per impostazione predefinita", + "Add a timestamp to the backup file names": "Aggiungi data e ora ai nomi dei file di backup", + "Backup and Restore": "Backup e ripristino", + "Enable background api (UniGetUI Widgets and Sharing, port 7058)": "Abilita API in background (widget e condivisione UniGetUI, porta 7058)", + "Wait for the device to be connected to the internet before attempting to do tasks that require internet connectivity.": "Attendi che il dispositivo sia connesso a Internet prima di provare a svolgere attività che richiedono la connettività Internet.", + "Disable the 1-minute timeout for package-related operations": "Disabilita il timeout di 1 minuto per le operazioni relative al pacchetto", + "Use installed GSudo instead of UniGetUI Elevator": "Usa GSudo installato invece di UniGetUI Elevator", + "Use a custom icon and screenshot database URL": "Usa icona personalizzata e URL dal database screenshot", + "Enable background CPU Usage optimizations (see Pull Request #3278)": "Abilita le ottimizzazioni dell'utilizzo della CPU in background (vedi Pull Request #3278)", + "Perform integrity checks at startup": "Esegui controlli di integrità all'avvio", + "When batch installing packages from a bundle, install also packages that are already installed": "Quando si installano in batch i pacchetti da una raccolta, installa anche i pacchetti già installati", + "Experimental settings and developer options": "Impostazioni sperimentali e opzioni sviluppatore", + "Show UniGetUI's version and build number on the titlebar.": "Mostra la versione e il numero di build di UniGetUI sulla barra del titolo.", + "Language": "Lingua", + "UniGetUI updater": "Programma di aggiornamento di UniGetUI", + "Telemetry": "Telemetria", + "Manage UniGetUI settings": "Gestisci le impostazioni di UniGetUI", + "Related settings": "Impostazioni correlate", + "Update UniGetUI automatically": "Aggiorna UniGetUI automaticamente", + "Check for updates": "Controlla aggiornamenti", + "Install prerelease versions of UniGetUI": "Installa le versioni di sviluppo di UniGetUI", + "Manage telemetry settings": "Gestisci le impostazioni di telemetria", + "Manage": "Gestisci", + "Import settings from a local file": "Importa impostazioni da un file locale", + "Import": "Importa", + "Export settings to a local file": "Esporta impostazioni in un file locale", + "Export": "Esporta", + "Reset UniGetUI": "Reimposta UniGetUI", + "User interface preferences": "Preferenze dell'interfaccia utente", + "Application theme, startup page, package icons, clear successful installs automatically": "Tema dell'applicazione, pagina di avvio, icone del pacchetto, cancella automaticamente le installazioni riuscite", + "General preferences": "Preferenze generali", + "UniGetUI display language:": "Lingua di visualizzazione di UniGetUI:", + "System language": "Lingua di sistema", + "Is your language missing or incomplete?": "La tua lingua manca o è incompleta?", + "Appearance": "Aspetto", + "UniGetUI on the background and system tray": "UniGetUI in background e nella barra delle applicazioni", + "Package lists": "Elenchi pacchetti", + "Use classic mode": "Usa modalità classica", + "Restart UniGetUI to apply this change": "Riavvia UniGetUI per applicare questa modifica", + "The classic UI is disabled for beta testers": "L'interfaccia classica è disabilitata per i beta tester", + "Close UniGetUI to the system tray": "Chiudi UniGetUI nella barra delle applicazioni", + "Manage UniGetUI autostart behaviour": "Gestisci il comportamento di avvio automatico di UniGetUI", + "Show package icons on package lists": "Mostra icone dei pacchetti negli elenchi dei pacchetti", + "Clear cache": "Svuota cache", + "Select upgradable packages by default": "Seleziona pacchetti aggiornabili per impostazione predefinita", + "Light": "Chiaro", + "Dark": "Scuro", + "Follow system color scheme": "Segui schema dei colori di sistema", + "Application theme:": "Tema applicazione:", + "UniGetUI startup page:": "Pagina di avvio di UniGetUI:", + "Proxy settings": "Impostazioni proxy", + "Other settings": "Altre impostazioni", + "Connect the internet using a custom proxy": "Connettiti a Internet utilizzando un proxy personalizzato", + "Please note that not all package managers may fully support this feature": "Tieni presente che non tutti i gestori di pacchetti potrebbero supportare completamente questa funzionalità", + "Proxy URL": "URL proxy", + "Enter proxy URL here": "Inserisci qui l'URL del proxy", + "Authenticate to the proxy with a user and a password": "Autentica il proxy con un nome utente e una password", + "Internet and proxy settings": "Impostazioni Internet e proxy", + "Package manager preferences": "Preferenze del gestore pacchetti", + "Ready": "Pronto", + "Not found": "Non trovato", + "Notification preferences": "Preferenze di notifica", + "Notification types": "Tipi di notifica", + "The system tray icon must be enabled in order for notifications to work": "L'icona della barra delle applicazioni deve essere abilitata affinché le notifiche funzionino", + "Enable UniGetUI notifications": "Abilita notifiche di UniGetUI", + "Show a notification when there are available updates": "Mostra una notifica quando ci sono aggiornamenti disponibili", + "Show a silent notification when an operation is running": "Mostra una notifica silenziosa quando un'operazione è in esecuzione", + "Show a notification when an operation fails": "Mostra una notifica quando un'operazione non riesce", + "Show a notification when an operation finishes successfully": "Mostra una notifica quando un'operazione viene completata correttamente", + "Concurrency and execution": "Concorrenza ed esecuzione", + "Automatic desktop shortcut remover": "Rimozione automatica dei collegamenti dal desktop", + "Choose how many operations should be performed in parallel": "Scegli quante operazioni devono essere eseguite in parallelo", + "Clear successful operations from the operation list after a 5 second delay": "Cancella le operazioni riuscite dall'elenco delle operazioni dopo un ritardo di 5 secondi", + "Download operations are not affected by this setting": "Le operazioni di scaricamento non sono influenzate da questa impostazione", + "You may lose unsaved data": "Potresti perdere i dati non salvati", + "Ask to delete desktop shortcuts created during an install or upgrade.": "Richiedi di eliminare i collegamenti sul desktop creati durante un'installazione o un aggiornamento.", + "Package update preferences": "Preferenze di aggiornamento dei pacchetti", + "Update check frequency, automatically install updates, etc.": "Aggiorna la frequenza di controllo, installa automaticamente gli aggiornamenti, ecc.", + "Reduce UAC prompts, elevate installations by default, unlock certain dangerous features, etc.": "Riduci le richieste UAC, eleva le installazioni per impostazione predefinita, sblocca determinate funzionalità pericolose e altro", + "Package operation preferences": "Preferenze per le operazioni sui pacchetti", + "Enable {pm}": "Abilita {pm}", + "Not finding the file you are looking for? Make sure it has been added to path.": "Non trovi il file che stai cercando? Assicurati che sia stato aggiunto al percorso.", + "Select the executable to be used. The following list shows the executables found by UniGetUI": "Seleziona l'eseguibile da utilizzare. L'elenco seguente mostra gli eseguibili trovati da UniGetUI", + "For security reasons, changing the executable file is disabled by default": "Per motivi di sicurezza, la modifica del file eseguibile è disabilitata per impostazione predefinita", + "Change this": "Modifica questo", + "Copy path": "Copia percorso", + "Current executable file:": "File eseguibile attuale:", + "Ignore packages from {pm} when showing a notification about updates": "Ignora i pacchetti da {pm} quando viene mostrata una notifica sugli aggiornamenti", + "Update security": "Sicurezza degli aggiornamenti", + "Use global setting": "Usa l'impostazione globale", + "Minimum age for updates": "Età minima degli aggiornamenti", + "e.g. 10": "ad es. 10", + "Custom minimum age (days)": "Età minima personalizzata (giorni)", + "{pm} does not provide release dates for its packages, so this setting will have no effect": "{pm} non fornisce date di rilascio per i suoi pacchetti, quindi questa impostazione non avrà alcun effetto", + "{pm} only provides release dates for some of its packages, so this setting will only apply to those packages": "{pm} fornisce le date di rilascio solo per alcuni dei suoi pacchetti, quindi questa impostazione si applicherà solo a quei pacchetti", + "Override the global minimum update age for this package manager": "Sostituisci l'età minima globale degli aggiornamenti per questo gestore di pacchetti", + "View {0} logs": "Visualizza {0} log", + "If Python cannot be found or is not listing packages but is installed on the system, ": "Se Python non viene trovato o non elenca i pacchetti ma è installato nel sistema, ", + "Advanced options": "Opzioni avanzate", + "WinGet command-line tool": "Strumento da riga di comando WinGet", + "Choose which command-line tool UniGetUI uses for WinGet operations when the COM API is not used": "Scegli quale strumento da riga di comando UniGetUI usa per le operazioni di WinGet quando non viene usata la COM API", + "WinGet COM API": "API COM di WinGet", + "Choose whether UniGetUI can use the WinGet COM API before falling back to the command-line tool": "Scegli se UniGetUI può usare la COM API di WinGet prima di ricorrere allo strumento da riga di comando", + "Reset WinGet": "Reimposta WinGet", + "This may help if no packages are listed": "Questo può essere d'aiuto se i pacchetti non sono elencati", + "Force install location parameter when updating packages with custom locations": "Forza il parametro di posizione di installazione quando aggiorni pacchetti con posizioni personalizzate", + "Install Scoop": "Installa Scoop", + "Uninstall Scoop (and its packages)": "Disinstalla Scoop (e i suoi pacchetti)", + "Run cleanup and clear cache": "Esegui pulizia e svuota cache", + "Run": "Esegui", + "Enable Scoop cleanup on launch": "Abilita pulizia di Scoop all'avvio", + "Default vcpkg triplet": "Triplet predefinito di vcpkg", + "Change vcpkg root location": "Cambia il percorso radice di vcpkg", + "Reset vcpkg root location": "Reimposta posizione radice di vcpkg", + "Open vcpkg root location": "Apri posizione radice di vcpkg", + "Language, theme and other miscellaneous preferences": "Lingua, tema e altre preferenze", + "Show notifications on different events": "Mostra notifiche su diversi eventi", + "Change how UniGetUI checks and installs available updates for your packages": "Modifica il modo in cui UniGetUI controlla e installa gli aggiornamenti disponibili per i tuoi pacchetti", + "Automatically save a list of all your installed packages to easily restore them.": "Salva automaticamente un elenco di tutti i pacchetti installati per ripristinarli facilmente.", + "Enable and disable package managers, change default install options, etc.": "Abilita e disabilita i gestori di pacchetti, modifica le opzioni di installazione predefinite e altro", + "Internet connection settings": "Impostazioni connessione Internet", + "Proxy settings, etc.": "Impostazioni proxy e altro", + "Beta features and other options that shouldn't be touched": "Funzionalità beta e altre opzioni che non dovrebbero essere toccate", + "Reload sources": "Ricarica sorgenti", + "Delete source": "Elimina sorgente", + "Known sources": "Sorgenti conosciute", + "Update checking": "Controllo degli aggiornamenti", + "Automatic updates": "Aggiornamenti automatici", + "Check for package updates periodically": "Controlla periodicamente gli aggiornamenti dei pacchetti", + "Check for updates every:": "Controlla aggiornamenti ogni:", + "Install available updates automatically": "Installa automaticamente gli aggiornamenti disponibili", + "Do not automatically install updates when the network connection is metered": "Non installare automaticamente gli aggiornamenti quando la connessione di rete è a consumo", + "Do not automatically install updates when the device runs on battery": "Non installare automaticamente gli aggiornamenti quando il dispositivo funziona a batteria", + "Do not automatically install updates when the battery saver is on": "Non installare automaticamente gli aggiornamenti quando il risparmio batteria è attivo", + "Only show updates that are at least the specified number of days old": "Mostra solo gli aggiornamenti che hanno almeno il numero di giorni specificato", + "Warn me when the installer URL host changes between the installed version and the new version (WinGet only)": "Avvisami quando l'host dell'URL del programma di installazione cambia tra la versione installata e la nuova versione (solo WinGet)", + "Change how UniGetUI handles install, update and uninstall operations.": "Modifica il modo in cui UniGetUI gestisce le operazioni di installazione, aggiornamento e disinstallazione.", + "Navigation": "Navigazione", + "Check for UniGetUI updates": "Verifica aggiornamenti di UniGetUI", + "Quit UniGetUI": "Esci da UniGetUI", + "Filters": "Filtri", + "Sources": "Sorgenti", + "Search for packages to start": "Cerca pacchetti per iniziare", + "Select all": "Seleziona tutto", + "Clear selection": "Cancella selezione", + "Instant search": "Ricerca istantanea", + "Distinguish between uppercase and lowercase": "Distingui tra maiuscole e minuscole", + "Ignore special characters": "Ignora caratteri speciali", + "Search mode": "Modalità di ricerca", + "Both": "Entrambi", + "Exact match": "Corrispondenza esatta", + "Show similar packages": "Mostra pacchetti simili", + "Loading": "Caricamento", + "Package": "Pacchetto", + "More options": "Altre opzioni", + "Order by:": "Ordina per:", + "Name": "Nome", + "Id": "ID", + "Ascendant": "Ascendente", + "Descendant": "Discendente", + "View modes": "Modalità di visualizzazione", + "Reload": "Ricarica", + "Closed": "Chiuso", + "Ascending": "Crescente", + "Descending": "Decrescente", + "{0}: {1}, {2}": "{0}: {1}, {2}", + "Order by": "Ordina per", + "No results were found matching the input criteria": "Nessun risultato corrispondente ai criteri di ricerca", + "No packages were found": "Nessun pacchetto trovato", + "Loading packages": "Caricamento pacchetti", + "Skip integrity checks": "Salta controlli di integrità", + "Download selected installers": "Scarica programmi di installazione selezionati", + "Install selection": "Installa selezione", + "Install options": "Opzioni di installazione", + "Add selection to bundle": "Aggiungi selezione alla raccolta", + "Download installer": "Scarica programma di installazione", + "Uninstall selection": "Disinstalla selezione", + "Uninstall options": "Opzioni di disinstallazione", + "Ignore selected packages": "Ignora pacchetti selezionati", + "Open install location": "Apri posizione di installazione", + "Reinstall package": "Reinstalla pacchetto", + "Uninstall package, then reinstall it": "Disinstalla e reinstalla pacchetto", + "Ignore updates for this package": "Ignora aggiornamenti per questo pacchetto", + "WinGet malfunction detected": "Malfunzionamento di WinGet rilevato", + "It looks like WinGet is not working properly. Do you want to attempt to repair WinGet?": "Sembra che WinGet non funzioni correttamente. Vuoi provare a riparare WinGet?", + "Repair WinGet": "Ripara WinGet", + "Updates will no longer be ignored for {0}": "Gli aggiornamenti non verranno più ignorati per {0}", + "Updates are now ignored for {0}": "Gli aggiornamenti vengono ora ignorati per {0}", + "Do not ignore updates for this package anymore": "Non ignorare più gli aggiornamenti per questo pacchetto", + "Add packages or open an existing package bundle": "Aggiungi pacchetti o apri una raccolta di pacchetti esistente", + "Add packages to start": "Aggiungi pacchetti per iniziare", + "The current bundle has no packages. Add some packages to get started": "La raccolta attuale non ha pacchetti. Aggiungi alcuni pacchetti per iniziare.", + "New": "Nuovo", + "Save as": "Salva come", + "Create .ps1 script": "Crea script .ps1", + "Remove selection from bundle": "Rimuovi selezione dalla raccolta", + "Skip hash checks": "Salta controlli hash", + "The package bundle is not valid": "La raccolta di pacchetti non è valida", + "The bundle you are trying to load appears to be invalid. Please check the file and try again.": "La raccolta che stai tentando di caricare sembra non essere valida. Controlla il file e riprova.", + "Package bundle": "Raccolta pacchetti", + "Could not create bundle": "Impossibile creare la raccolta", + "The package bundle could not be created due to an error.": "Non è stato possibile creare la raccolta di pacchetti a causa di un errore.", + "Install script": "Script di installazione", + "PowerShell script": "Script PowerShell", + "The installation script saved to {0}": "Lo script di installazione è stato salvato in {0}", + "An error occurred": "Si è verificato un errore", + "An error occurred while attempting to create an installation script:": "Si è verificato un errore durante il tentativo di creare uno script di installazione:", + "Hooray! No updates were found.": "Evviva! Non ci sono aggiornamenti!", + "Uninstall selected packages": "Disinstalla pacchetti selezionati", + "Update selection": "Aggiorna selezione", + "Update options": "Opzioni di aggiornamento", + "Uninstall package, then update it": "Disinstalla e aggiorna pacchetto", + "Uninstall package": "Disinstalla pacchetto", + "Skip this version": "Salta questa versione", + "Pause updates for": "Sospendi aggiornamenti per", + "User | Local": "Utente | Locale", + "Machine | Global": "Computer | Globale", + "The default package manager for Debian/Ubuntu-based Linux distributions.
Contains: Debian/Ubuntu packages": "Il gestore di pacchetti predefinito per le distribuzioni Linux basate su Debian/Ubuntu.
Contiene: pacchetti Debian/Ubuntu", + "The Rust package manager.
Contains: Rust libraries and programs written in Rust": "Il gestore pacchetti Rust.
Contiene: librerie e programmi Rust scritti in Rust", + "The classical package manager for windows. You'll find everything there.
Contains: General Software": "Il classico gestore pacchetti per Windows. Qui troverai di tutto.
Contiene: software generico", + "The default package manager for RHEL/Fedora-based Linux distributions.
Contains: RPM packages": "Il gestore di pacchetti predefinito per le distribuzioni Linux basate su RHEL/Fedora.
Contiene: pacchetti RPM", + "A repository full of tools and executables designed with Microsoft's .NET ecosystem in mind.
Contains: .NET related tools and scripts": "Un repository pieno di strumenti ed eseguibili progettati pensando all'ecosistema .NET di Microsoft.
Contiene: strumenti e script relativi a .NET", + "The universal Linux package manager for desktop applications.
Contains: Flatpak applications from configured remotes": "Il gestore di pacchetti Linux universale per applicazioni desktop.
Contiene: applicazioni Flatpak dai remoti configurati", + "NuPkg (zipped manifest)": "NuPkg (manifesto compresso)", + "The Missing Package Manager for macOS (or Linux).
Contains: Formulae, Casks": "Il gestore di pacchetti che mancava per macOS (o Linux).
Contiene: Formulae, Casks", + "Node JS's package manager. Full of libraries and other utilities that orbit the javascript world
Contains: Node javascript libraries and other related utilities": "Il gestore pacchetti di Node JS. Pieno di librerie e altre strumenti che orbitano attorno al mondo javascript.
Contiene: librerie javascript Node e altri strumenti correlati", + "The default package manager for Arch Linux and its derivatives.
Contains: Arch Linux packages": "Il gestore di pacchetti predefinito per Arch Linux e le sue derivate.
Contiene: pacchetti Arch Linux", + "Python's library manager. Full of python libraries and other python-related utilities
Contains: Python libraries and related utilities": "Il gestore libreria di Python. Pieno di librerie Python e altri strumenti relativi a Python.
Contiene: librerie Python e strumenti correlati", + "PowerShell's package manager. Find libraries and scripts to expand PowerShell capabilities
Contains: Modules, Scripts, Cmdlets": "Il gestore pacchetti di PowerShell. Trova librerie e script per espandere le funzionalità di PowerShell.
Contiene: moduli, script, cmdlet", + "extracted": "estratto", + "Scoop package": "Pacchetto Scoop", + "Great repository of unknown but useful utilities and other interesting packages.
Contains: Utilities, Command-line programs, General Software (extras bucket required)": "Ottimo repository di strumenti sconosciuti ma utili e altri pacchetti interessanti.
Contiene: strumenti, programmi a riga di comando, software generici (è necessario un bucket extra)", + "The universal Linux package manager by Canonical.
Contains: Snap packages from the Snapcraft store": "Il gestore di pacchetti universale per Linux di Canonical.
Contiene: pacchetti Snap dallo store Snapcraft", + "library": "libreria", + "feature": "caratteristica", + "A popular C/C++ library manager. Full of C/C++ libraries and other C/C++-related utilities
Contains: C/C++ libraries and related utilities": "Un popolare gestore di librerie C/C++. Pieno di librerie C/C++ e altre utilità correlate a C/C++
Contiene: librerie C/C++ e utilità correlate", + "option": "opzione", + "This package cannot be installed from an elevated context.": "Questo pacchetto non può essere installato da un contesto elevato.", + "Please run UniGetUI as a regular user and try again.": "Esegui UniGetUI come utente normale e riprova.", + "Please check the installation options for this package and try again": "Controlla le opzioni di installazione per questo pacchetto e riprova", + "Microsoft's official package manager. Full of well-known and verified packages
Contains: General Software, Microsoft Store apps": "Il gestore pacchetti ufficiale di Microsoft. Pieno di pacchetti noti e verificati.
Contiene: software generico, app dal Microsoft Store", + "Local PC": "PC locale", + "Android Subsystem": "Sottosistema Android", + "Operation on queue (position {0})...": "Operazione in coda (posizione {0})...", + "Click here for more details": "Fai clic qui per maggiori dettagli", + "Operation canceled by user": "Operazione annullata dall'utente", + "Running PreOperation ({0}/{1})...": "Esecuzione di PreOperation ({0}/{1})...", + "PreOperation {0} out of {1} failed, and was tagged as necessary. Aborting...": "La PreOperation {0} di {1} non è riuscita ed era contrassegnata come necessaria. Interruzione...", + "PreOperation {0} out of {1} finished with result {2}": "La PreOperation {0} di {1} è terminata con risultato {2}", + "Starting operation...": "Avvio dell'operazione...", + "Running PostOperation ({0}/{1})...": "Esecuzione di PostOperation ({0}/{1})...", + "PostOperation {0} out of {1} failed, and was tagged as necessary. Aborting...": "La PostOperation {0} di {1} non è riuscita ed era contrassegnata come necessaria. Interruzione...", + "PostOperation {0} out of {1} finished with result {2}": "La PostOperation {0} di {1} è terminata con risultato {2}", + "{package} installer download": "Scarica il programma di installazione {package}", + "{0} installer is being downloaded": "Programma di installazione {0} in fase di scaricamento", + "Download succeeded": "Scaricamento riuscito", + "{package} installer was downloaded successfully": "Il programma di installazione {package} è stato scaricato correttamente", + "Download failed": "Scaricamento non riuscito", + "{package} installer could not be downloaded": "Impossibile scaricare il programma di installazione {package}", + "{package} Installation": "Installazione di {package}", + "{0} is being installed": "{0} è in fase di installazione", + "Installation succeeded": "Installazione riuscita", + "{package} was installed successfully": "{package} è stato installato correttamente", + "Installation failed": "Installazione non riuscita", + "{package} could not be installed": "Impossibile installare {package}", + "{package} Update": "Aggiornamento di {package}", + "Update succeeded": "Aggiornamento riuscito", + "{package} was updated successfully": "{package} è stato aggiornato correttamente", + "Update failed": "Aggiornamento non riuscito", + "{package} could not be updated": "Impossibile aggiornare {package}", + "{package} Uninstall": "Disinstallazione di {package}", + "{0} is being uninstalled": "{0} è in fase di disinstallazione", + "Uninstall succeeded": "Disinstallazione riuscita", + "{package} was uninstalled successfully": "{package} è stato disinstallato correttamente", + "Uninstall failed": "Disinstallazione non riuscita", + "{package} could not be uninstalled": "Impossibile disinstallare {package}", + "Adding source {source}": "Aggiunta sorgente {source}", + "Adding source {source} to {manager}": "Aggiunta sorgente {source} a {manager}", + "Source added successfully": "Sorgente aggiunta correttamente", + "The source {source} was added to {manager} successfully": "La sorgente {source} è stata aggiunta a {manager} correttamente", + "Could not add source": "Impossibile aggiungere la sorgente", + "Could not add source {source} to {manager}": "Impossibile aggiungere la sorgente {source} a {manager}", + "Removing source {source}": "Rimozione della sorgente {source}", + "Removing source {source} from {manager}": "Rimozione sorgente {source} da {manager}", + "Source removed successfully": "Sorgente rimossa correttamente", + "The source {source} was removed from {manager} successfully": "La sorgente {source} è stata rimossa da {manager} correttamente", + "Could not remove source": "Impossibile rimuovere la sorgente", + "Could not remove source {source} from {manager}": "Impossibile rimuovere la sorgente {source} da {manager}", + "The package manager \"{0}\" was not found": "Il gestore pacchetti \"{0}\" non è stato trovato", + "The package manager \"{0}\" is disabled": "Il gestore pacchetti \"{0}\" è disabilitato", + "There is an error with the configuration of the package manager \"{0}\"": "C'è un errore nella configurazione del gestore pacchetti \"{0}\"", + "The package \"{0}\" was not found on the package manager \"{1}\"": "Il pacchetto \"{0}\" non è stato trovato nel gestore pacchetti \"{1}\"", + "{0} is disabled": "{0} è disabilitato", + "{0} weeks": "{0} settimane", + "1 month": "1 mese", + "{0} months": "{0} mesi", + "Something went wrong": "Si è verificato un errore", + "An interal error occurred. Please view the log for further details.": "Si è verificato un errore interno. Visualizza il log per ulteriori dettagli.", + "No applicable installer was found for the package {0}": "Non è stato trovato alcun programma di installazione applicabile per il pacchetto {0}", + "Integrity checks will not be performed during this operation": "Durante questa operazione non verranno eseguiti controlli di integrità", + "This is not recommended.": "Questa operazione non è consigliata.", + "Run now": "Esegui adesso", + "Run next": "Esegui il successivo", + "Run last": "Esegui l'ultimo", + "Show in explorer": "Mostra in Explorer", + "Checked": "Selezionato", + "Unchecked": "Deselezionato", + "This package is already installed": "Questo pacchetto è già installato", + "This package can be upgraded to version {0}": "Questo pacchetto può essere aggiornato alla versione {0}", + "Updates for this package are ignored": "Gli aggiornamenti per questo pacchetto vengono ignorati", + "This package is being processed": "Questo pacchetto è in fase di elaborazione", + "This package is not available": "Questo pacchetto non è disponibile", + "Select the source you want to add:": "Seleziona la sorgente che desideri aggiungere:", + "Source name:": "Nome sorgente:", + "Source URL:": "URL sorgente:", + "An error occurred when adding the source: ": "Si è verificato un errore durante l'aggiunta della sorgente: ", + "Package management made easy": "Gestione dei pacchetti semplificata", + "version {0}": "versione {0}", + "[RAN AS ADMINISTRATOR]": "[ESEGUITO COME AMMINISTRATORE]", + "Portable mode": "Modalità portatile", + "DEBUG BUILD": "DEBUG BUILD", + "Here you can change UniGetUI's behaviour regarding the following shortcuts. Checking a shortcut will make UniGetUI delete it if if gets created on a future upgrade. Unchecking it will keep the shortcut intact": "Qui puoi modificare il comportamento di UniGetUI relativamente ai collegamenti seguenti. Selezionando un collegamento UniGetUI lo eliminerà se verrà creato in un futuro aggiornamento. Deselezionandolo, il collegamento rimarrà intatto", + "Manual scan": "Scansione manuale", + "Existing shortcuts on your desktop will be scanned, and you will need to pick which ones to keep and which ones to remove.": "Verranno analizzati i collegamenti presenti sul desktop e sarà necessario scegliere quali mantenere e quali rimuovere.", + "Delete?": "Eliminare?", + "I understand": "Capisco", + "Chocolatey setup changed": "Configurazione di Chocolatey modificata", + "UniGetUI no longer includes its own private Chocolatey installation. A legacy UniGetUI-managed Chocolatey installation was detected for this user profile, but system Chocolatey was not found. Chocolatey will stay unavailable in UniGetUI until Chocolatey is installed on the system and UniGetUI is restarted. Applications previously installed through UniGetUI's bundled Chocolatey may still appear under other sources such as Local PC or WinGet.": "UniGetUI non include più la propria installazione privata di Chocolatey. È stata rilevata un'installazione legacy di Chocolatey gestita da UniGetUI per questo profilo utente, ma Chocolatey di sistema non è stato trovato. Chocolatey rimarrà non disponibile in UniGetUI fino a quando Chocolatey non sarà installato nel sistema e UniGetUI non sarà riavviato. Le applicazioni precedentemente installate tramite il Chocolatey integrato di UniGetUI potrebbero ancora apparire sotto altre sorgenti come PC locale o WinGet.", + "NOTE: This troubleshooter can be disabled from UniGetUI Settings, on the WinGet section": "NOTA: questo strumento di risoluzione dei problemi può essere disabilitato dalle impostazioni di UniGetUI, nella sezione WinGet", + "Restart": "Riavvia", + "Are you sure you want to delete all shortcuts?": "Vuoi davvero eliminare tutti i collegamenti?", + "Any new shorcuts created during an install or an update operation will be deleted automatically, instead of showing a confirmation prompt the first time they are detected.": "Tutti i nuovi collegamenti creati durante un'installazione o un'operazione di aggiornamento verranno eliminati automaticamente, anziché visualizzare una richiesta di conferma la prima volta che vengono rilevati.", + "Any shorcuts created or modified outside of UniGetUI will be ignored. You will be able to add them via the {0} button.": "Tutti i collegamenti creati o modificati al di fuori di UniGetUI saranno ignorati. Potrai aggiungerli tramite il pulsante {0}.", + "Are you really sure you want to enable this feature?": "Sei davvero sicuro di voler abilitare questa funzione?", + "No new shortcuts were found during the scan.": "Durante la scansione non sono stati trovati nuovi collegamenti.", + "How to add packages to a bundle": "Come aggiungere pacchetti a una raccolta", + "In order to add packages to a bundle, you will need to: ": "Per aggiungere pacchetti a una raccolta, è necessario: ", + "1. Navigate to the \"{0}\" or \"{1}\" page.": "1. Vai alla pagina \"{0}\" o \"{1}\".", + "2. Locate the package(s) you want to add to the bundle, and select their leftmost checkbox.": "2. Individua i pacchetti che desideri aggiungere alla raccolta e seleziona la casella di controllo più a sinistra.", + "3. When the packages you want to add to the bundle are selected, find and click the option \"{0}\" on the toolbar.": "3. Dopo aver selezionato i pacchetti che vuoi aggiungere alla raccolta, trova e fai clic sull'opzione \"{0}\" sulla barra degli strumenti.", + "4. Your packages will have been added to the bundle. You can continue adding packages, or export the bundle.": "4. I tuoi pacchetti saranno stati aggiunti alla raccolta. Puoi continuare ad aggiungere pacchetti o esportare la raccolta.", + "Which backup do you want to open?": "Quale backup vuoi aprire?", + "Select the backup you want to open. Later, you will be able to review which packages you want to install.": "Seleziona il backup che desideri aprire. In seguito, potrai controllare quali pacchetti desideri installare.", + "There are ongoing operations. Quitting UniGetUI may cause them to fail. Do you want to continue?": "Ci sono operazioni in corso. L'uscita da UniGetUI potrebbe causare il loro errore. Vuoi continuare?", + "UniGetUI or some of its components are missing or corrupt.": "UniGetUI o alcuni dei suoi componenti sono mancanti o danneggiati.", + "It is strongly recommended to reinstall UniGetUI to adress the situation.": "Si consiglia vivamente di reinstallare UniGetUI per risolvere il problema.", + "Refer to the UniGetUI Logs to get more details regarding the affected file(s)": "Fai riferimento ai log di UniGetUI per ottenere maggiori dettagli sui file interessati", + "Integrity checks can be disabled from the Experimental Settings": "I controlli di integrità possono essere disabilitati dalle Impostazioni sperimentali", + "Repair UniGetUI": "Ripara UniGetUI", + "Live output": "Output in tempo reale", + "This package bundle had some settings that are potentially dangerous, and may be ignored by default.": "Questo pacchetto contiene alcune impostazioni potenzialmente pericolose che potrebbero essere ignorate per impostazione predefinita.", + "Entries that show in YELLOW will be IGNORED.": "Le voci visualizzate in GIALLO verranno IGNORATE.", + "Entries that show in RED will be IMPORTED.": "Le voci visualizzate in ROSSO verranno IMPORTATE.", + "You can change this behavior on UniGetUI security settings.": "È possibile modificare questo comportamento nelle impostazioni di sicurezza di UniGetUI.", + "Open UniGetUI security settings": "Apri le impostazioni di sicurezza di UniGetUI", + "Should you modify the security settings, you will need to open the bundle again for the changes to take effect.": "Se modifichi le impostazioni di sicurezza, dovrai aprire nuovamente la raccolta affinché le modifiche abbiano effetto.", + "Details of the report:": "Dettagli del rapporto:", + "Are you sure you want to create a new package bundle? ": "Sei sicuro di voler creare una nuova raccolta di pacchetti? ", + "Any unsaved changes will be lost": "Tutte le modifiche non salvate andranno perse", + "Warning!": "Attenzione!", + "For security reasons, custom command-line arguments are disabled by default. Go to UniGetUI security settings to change this. ": "Per motivi di sicurezza, gli argomenti personalizzati della riga di comando sono disabilitati per impostazione predefinita. Per modificare questa impostazione, vai alle impostazioni di sicurezza di UniGetUI. ", + "Change default options": "Modifica le opzioni predefinite", + "Ignore future updates for this package": "Ignora aggiornamenti futuri per questo pacchetto", + "For security reasons, pre-operation and post-operation scripts are disabled by default. Go to UniGetUI security settings to change this. ": "Per motivi di sicurezza, gli script pre-operazione e post-operazione sono disabilitati per impostazione predefinita. Per modificare questa impostazione, vai alle impostazioni di sicurezza di UniGetUI. ", + "You can define the commands that will be run before or after this package is installed, updated or uninstalled. They will be run on a command prompt, so CMD scripts will work here.": "È possibile definire i comandi che verranno eseguiti prima o dopo l'installazione, l'aggiornamento o la disinstallazione di questo pacchetto. Verranno eseguiti su un prompt dei comandi, quindi gli script CMD funzioneranno qui.", + "Change this and unlock": "Modifica questo e sblocca", + "{0} Install options are currently locked because {0} follows the default install options.": "Le opzioni di installazione di {0} sono attualmente bloccate perché {0} segue le opzioni di installazione predefinite.", + "Unset or unknown": "Non impostato o sconosciuto", + "This package has no screenshots or is missing the icon? Contrbute to UniGetUI by adding the missing icons and screenshots to our open, public database.": "Questo pacchetto non contiene screenshot o manca dell'icona? Contribuisci a UniGetUI aggiungendo le icone e gli screenshot mancanti al nostro database pubblico e aperto.", + "Become a contributor": "Diventa un collaboratore", + "Update to {0} available": "Aggiornamento a {0} disponibile", + "Reinstall": "Reinstalla", + "Installer not available": "Programma di installazione non disponibile", + "Version:": "Versione:", + "UniGetUI Version {0}": "UniGetUI versione {0}", + "Performing backup, please wait...": "Esecuzione del backup, attendi...", + "An error occurred while logging in: ": "Si è verificato un errore durante l'accesso: ", + "Fetching available backups...": "Recupero dei backup disponibili...", + "Done!": "Fatto!", + "The cloud backup has been loaded successfully.": "Il backup sul cloud è stato caricato correttamente.", + "An error occurred while loading a backup: ": "Si è verificato un errore durante il caricamento di un backup: ", + "Backing up packages to GitHub Gist...": "Backup dei pacchetti su GitHub Gist...", + "Backup Successful": "Backup riuscito", + "The cloud backup completed successfully.": "Backup sul cloud completato correttamente.", + "Could not back up packages to GitHub Gist: ": "Impossibile eseguire il backup dei pacchetti su GitHub Gist: ", + "It is not guaranteed that the provided credentials will be stored safely, so you may as well not use the credentials of your bank account": "Non è garantito che le credenziali fornite verranno conservate in modo sicuro, quindi potresti anche non utilizzare le credenziali del tuo conto bancario", + "Enable the automatic WinGet troubleshooter": "Abilita risoluzione automatica dei problemi di WinGet", + "Add updates that fail with a 'no applicable update found' to the ignored updates list": "Aggiungi gli aggiornamenti che non riescono con un \"nessun aggiornamento applicabile trovato\" all'elenco degli aggiornamenti ignorati", + "Invalid selection": "Selezione non valida", + "No package was selected": "Nessun pacchetto selezionato", + "More than 1 package was selected": "È stato selezionato più di 1 pacchetto", + "List": "Elenco", + "Grid": "Griglia", + "Icons": "Icone", + "\"{0}\" is a local package and does not have available details": "\"{0}\" è un pacchetto locale e non ha dettagli disponibili", + "\"{0}\" is a local package and is not compatible with this feature": "\"{0}\" è un pacchetto locale e non è compatibile con questa funzionalità", + "Add packages to bundle": "Aggiungi pacchetti alla raccolta", + "Preparing packages, please wait...": "Preparazione dei pacchetti, attendi...", + "Loading packages, please wait...": "Caricamento dei pacchetti, attendi...", + "Saving packages, please wait...": "Salvataggio dei pacchetti, attendi...", + "The bundle was created successfully on {0}": "La raccolta è stata creata correttamente il {0}", + "User profile": "Profilo utente", + "Error": "Errore", + "Log in failed: ": "Accesso non riuscito: ", + "Log out failed: ": "Disconnessione non riuscita: ", + "Package backup settings": "Impostazioni di backup del pacchetto", + "Manage UniGetUI autostart behaviour from the Settings app": "Gestisci il comportamento di avvio automatico di UniGetUI", + "Choose how many operations shoulds be performed in parallel": "Scegli quante operazioni devono essere eseguite in parallelo", + "Something went wrong while launching the updater.": "Si è verificato un problema durante l'avvio del programma di aggiornamento.", + "Please try again later": "Riprova più tardi", + "Show the release notes after UniGetUI is updated": "Mostra le note sulla versione dopo l'aggiornamento di UniGetUI" +} diff --git a/src/Languages/lang_ja.json b/src/Languages/lang_ja.json new file mode 100644 index 0000000..6cb8033 --- /dev/null +++ b/src/Languages/lang_ja.json @@ -0,0 +1,850 @@ +{ + "{0} of {1} operations completed": "{1}件中{0}件のパッケージ操作が完了しました", + "{0} is now {1}": "{0}は{1}になりました", + "Enabled": "有効", + "Disabled": "無効", + "Privacy": "プライバシー", + "Hide my username from the logs": "ログにユーザー名を表示しない", + "Replaces your username with **** in the logs. Restart UniGetUI to also hide it from already-recorded entries.": "ログ内のユーザー名を****に置き換えます。すでに記録されたログからも非表示にするには、UniGetUIを再起動する必要があります。", + "Your last update attempt did not complete.": "前回のアップデート試行は完了しませんでした。", + "UniGetUI could not confirm whether the update succeeded. Open the log to see what happened.": "UniGetUIはアップデートが成功したか確認できませんでした。何が起きたか確認するにはログを開いてください。", + "View log": "ログを表示", + "The installer reported success but did not restart UniGetUI.": "インストーラーは成功を報告しましたが、UniGetUIを再起動しませんでした。", + "The installer failed to initialize.": "インストーラーの初期化に失敗しました。", + "Setup was canceled before installation began.": "セットアップはインストール開始前にキャンセルされました。", + "A fatal error occurred during the preparation phase.": "準備フェーズ中に致命的なエラーが発生しました。", + "A fatal error occurred during installation.": "インストール中に致命的なエラーが発生しました。", + "Installation was canceled while in progress.": "インストール中にキャンセルされました。", + "The installer was terminated by another process.": "インストーラーは別のプロセスによって終了されました。", + "The preparation phase determined the installation cannot proceed.": "準備フェーズでインストールを続行できないと判断されました。", + "The installer could not start. UniGetUI may already be running, or you do not have permission to install.": "インストーラーを起動できませんでした。UniGetUIが既に実行中であるか、インストール権限がありません。", + "Unexpected installer error.": "予期しないインストーラーエラーです。", + "We are checking for updates.": "アップデートを確認しています。", + "Please wait": "お待ちください", + "Great! You are on the latest version.": "素晴らしい!最新のバージョンです。", + "There are no new UniGetUI versions to be installed": "インストール可能なUniGetUIの新しいバージョンはありません", + "UniGetUI version {0} is being downloaded.": "UniGetUIバージョン{0}をダウンロードしています。", + "This may take a minute or two": "1~2分かかる場合があります", + "The installer authenticity could not be verified.": "インストーラーの信頼性を確認できませんでした。", + "The update process has been aborted.": "更新プロセスは中止されました。", + "Auto-update is not yet available on this platform.": "このプラットフォームでは自動アップデートはまだ利用できません。", + "Please update UniGetUI manually.": "UniGetUIを手動でアップデートしてください。", + "An error occurred when checking for updates: ": "アップデートの確認中にエラーが発生しました:", + "The updater could not be launched.": "アップデーターを起動できませんでした。", + "The operating system did not start the installer process.": "OSがインストーラープロセスを開始しませんでした。", + "UniGetUI is being updated...": "UniGetUIを更新中です...", + "Update installed.": "アップデートをインストールしました。", + "UniGetUI was updated successfully, but this running copy was not replaced. This usually means you are running a development build. Close this copy and start the newly-installed version to finish.": "UniGetUIは正常にアップデートされましたが、現在実行中のアプリは置き換えられませんでした。これは通常、開発ビルドを実行していることを意味します。完了するには、実行中のアプリを閉じて新しくインストールされたバージョンを起動してください。", + "The update could not be applied.": "アップデートを適用できませんでした。", + "Installer exit code {0}: {1}": "インストーラー終了コード{0}: {1}", + "Update cancelled.": "アップデートがキャンセルされました。", + "Authentication was cancelled.": "認証がキャンセルされました。", + "Installer exit code {0}": "インストーラー終了コード{0}", + "Operation in progress": "パッケージ操作を実行中", + "Please wait...": "お待ちください...", + "Success!": "成功!", + "Failed": "失敗しました", + "An error occurred while processing this package": "パッケージの処理中にエラーが発生しました", + "Installer": "インストーラー", + "Executable": "実行ファイル", + "MSI": "MSI", + "Compressed file": "圧縮ファイル", + "MSIX": "MSIX", + "WinGet was repaired successfully": "WinGetは正常に修復されました", + "It is recommended to restart UniGetUI after WinGet has been repaired": "WinGetが修復されたらUniGetUIを再起動することをお勧めします", + "WinGet could not be repaired": "WinGetを修復できませんでした", + "An unexpected issue occurred while attempting to repair WinGet. Please try again later": "WinGetの修復中に予期しないエラーが発生しました。後で再試行してください。", + "Log in to enable cloud backup": "クラウドバックアップを有効にするには、ログインしてください", + "Backup Failed": "バックアップに失敗しました", + "Downloading backup...": "バックアップをダウンロードしています...", + "An update was found!": "アップデートが見つかりました!", + "{0} can be updated to version {1}": "{0}をバージョン{1}にアップデートできます", + "Updates found!": "アップデートが見つかりました!", + "{0} packages can be updated": "{0}件のパッケージがアップデートできます", + "{0} is being updated to version {1}": "{0}をバージョン{1}にアップデート中", + "{0} packages are being updated": "{0}件のパッケージをアップデート中", + "You have currently version {0} installed": "現在、バージョン{0}がインストールされています", + "Desktop shortcut created": "デスクトップショートカットを作成しました", + "UniGetUI has detected a new desktop shortcut that can be deleted automatically.": "UniGetUIは、自動的に削除できる新しいデスクトップショートカットを検出しました。", + "{0} desktop shortcuts created": "デスクトップにショートカットが{0}個作成されました。", + "UniGetUI has detected {0} new desktop shortcuts that can be deleted automatically.": "UniGetUIは、自動的に削除可能な{0}個の新しいデスクトップショートカットを検出しました。", + "Attention required": "注意が必要", + "Restart required": "再起動が必要", + "1 update is available": "1つのアップデートが利用可能です", + "{0} updates are available": "{0}件のアップデートが利用可能です", + "Everything is up to date": "すべて最新", + "Discover Packages": "パッケージを探す", + "Available Updates": "利用可能なアップデート", + "Installed Packages": "インストール済みパッケージ", + "UniGetUI Version {0} by Devolutions": "UniGetUI バージョン{0} by Devolutions", + "Show UniGetUI": "UniGetUIを表示", + "Quit": "終了", + "Are you sure?": "よろしいですか?", + "Do you really want to uninstall {0}?": "本当に{0}をアンインストールしますか?", + "Do you really want to uninstall the following {0} packages?": "以下の{0}件のパッケージを本当にアンインストールしますか?", + "No": "いいえ", + "Yes": "はい", + "Partial": "一部対応", + "View on UniGetUI": "UniGetUIで見る", + "Update": "アップデート", + "Open UniGetUI": "UniGetUIを開く", + "Update all": "すべてアップデート", + "Update now": "今すぐアップデート", + "Installer host changed since the installed version.\n": "インストーラーのホストがインストール済みバージョンから変更されています。\n", + "This package is on the queue": "このパッケージはキューで順番を待っています", + "installing": "インストール中", + "updating": "アップデート中", + "uninstalling": "アンインストール中", + "installed": "インストール済み", + "Retry": "リトライ", + "Install": "インストール", + "Uninstall": "アンインストール", + "Open": "開く", + "Operation profile:": "パッケージ操作プロファイル:", + "Follow the default options when installing, upgrading or uninstalling this package": "インストール・アップデート・アンインストール時にデフォルト設定を適用", + "The following settings will be applied each time this package is installed, updated or removed.": "以下の設定は、このパッケージのインストール・アップデート・アンインストール時に適用されます。", + "Version to install:": "対象バージョン:", + "Architecture to install:": "対象アーキテクチャ:", + "Installation scope:": "スコープ:", + "Install location:": "インストール先:", + "Select": "選択", + "Reset": "リセット", + "Custom install arguments:": "カスタムインストール引数:", + "Custom update arguments:": "カスタムアップデート引数:", + "Custom uninstall arguments:": "カスタムアンインストール引数:", + "Pre-install command:": "インストール前コマンド:", + "Post-install command:": "インストール後コマンド:", + "Abort install if pre-install command fails": "インストール前コマンドが失敗した場合はインストールを中止する", + "Pre-update command:": "アップデート前コマンド:", + "Post-update command:": "アップデート後コマンド:", + "Abort update if pre-update command fails": "アップデート前コマンドが失敗した場合は更新を中止する", + "Pre-uninstall command:": "アンインストール前コマンド:", + "Post-uninstall command:": "アンインストール後コマンド:", + "Abort uninstall if pre-uninstall command fails": "アンインストール前のコマンドが失敗した場合はアンインストールを中止する", + "Command-line to run:": "実行するコマンドライン:", + "Save and close": "保存して閉じる", + "General": "一般", + "Architecture & Location": "アーキテクチャとインストール先", + "Command-line": "コマンドライン", + "Close apps": "終了させるアプリ", + "Pre/Post install": "インストール前/後", + "Select the processes that should be closed before this package is installed, updated or uninstalled.": "インストール・アップデート・アンインストール時に事前に終了させる必要があるプロセスを選択してください。", + "Write here the process names here, separated by commas (,)": "プロセス名をカンマ(,)で区切って入力してください。", + "Try to kill the processes that refuse to close when requested to": "終了しないプロセスを強制終了する", + "Run as admin": "管理者として実行", + "Interactive installation": "対話型インストール", + "Skip hash check": "ハッシュチェックを行わない", + "Uninstall previous versions when updated": "アップデート時に以前のバージョンをアンインストールする", + "Skip minor updates for this package": "マイナーアップデートを除外", + "Automatically update this package": "自動的にアップデートする", + "{0} installation options": "{0}インストール詳細設定", + "Latest": "最新", + "PreRelease": "先行リリース版", + "Default": "デフォルト", + "Manage ignored updates": "除外したパッケージの管理", + "The packages listed here won't be taken in account when checking for updates. Double-click them or click the button on their right to stop ignoring their updates.": "以下のパッケージは、アップデート対象から除外されます。除外を解除するには、ダブルクリックするか、右側にあるボタンをクリックしてください。", + "Reset list": "リストをクリア", + "Do you really want to reset the ignored updates list? This action cannot be reverted": "アップデート対象から除外したパッケージ一覧を本当にリセットしますか?この操作は元に戻せません", + "No ignored updates": "アップデート対象から除外されたパッケージはありません", + "Package Name": "パッケージ名", + "Package ID": "パッケージID", + "Ignored version": "無視されたバージョン", + "New version": "新しいバージョン", + "Source": "ソース", + "All versions": "すべてのバージョン", + "Unknown": "不明", + "Up to date": "最新の状態", + "Package {name} from {manager}": "{manager}のパッケージ{name}", + "Remove {0} from ignored updates": "{0}を除外リストから削除", + "Cancel": "キャンセル", + "Administrator privileges": "管理者権限", + "This operation is running with administrator privileges.": "このパッケージ操作は管理者権限で実行されています。", + "Interactive operation": "対話型パッケージ操作", + "This operation is running interactively.": "このパッケージ操作は対話型で実行されています。", + "You will likely need to interact with the installer.": "インストーラーと対話する必要がある可能性があります。", + "Integrity checks skipped": "整合性チェックをスキップ", + "Integrity checks will not be performed during this operation.": "このパッケージ操作では整合性チェックは実行されません。", + "Proceed at your own risk.": "自己責任で進めてください。", + "Close": "閉じる", + "Loading...": "読み込み中...", + "Installer SHA256": "インストーラーSHA256", + "Homepage": "ホームページ", + "Author": "作者", + "Publisher": "パブリッシャー", + "License": "ライセンス", + "Manifest": "マニフェスト", + "Installer Type": "インストーラー種類", + "Size": "サイズ", + "Installer URL": "インストーラーURL", + "Last updated:": "最終更新:", + "Release notes URL": "リリースノートURL", + "Package details": "パッケージの詳細", + "Dependencies:": "依存関係:", + "Release notes": "リリースノート", + "Screenshots": "スクリーンショット", + "This package has no screenshots or is missing the icon? Contribute to UniGetUI by adding the missing icons and screenshots to our open, public database.": "アイコンやスクリーンショットが未登録です。オープンデータベースにデータを追加して、UniGetUIの改善にご協力ください。", + "Version": "バージョン", + "Install as administrator": "管理者としてインストール", + "Update to version {0}": "バージョン{0}にアップデート", + "Installed Version": "インストールされているバージョン", + "Update as administrator": "管理者としてアップデート", + "Interactive update": "対話型アップデート", + "Uninstall as administrator": "管理者としてアンインストール", + "Interactive uninstall": "対話型アンインストール", + "Uninstall and remove data": "アンインストールしてデータを削除", + "Not available": "利用不可", + "Installer SHA512": "インストーラーSHA512", + "Unknown size": "サイズ不明", + "No dependencies specified": "依存関係が指定されていません", + "mandatory": "必須", + "optional": "オプション", + "UniGetUI {0} is ready to be installed.": "UniGetUI{0}のインストールの準備が完了しました。", + "The update process will start after closing UniGetUI": "UniGetUIを閉じると、アップデートが開始されます。", + "UniGetUI has been ran as administrator, which is not recommended. When running UniGetUI as administrator, EVERY operation launched from UniGetUI will have administrator privileges. You can still use the program, but we highly recommend not running UniGetUI with administrator privileges.": "非推奨:UniGetUIが管理者権限で実行されています。UniGetUIを管理者として実行すると、UniGetUIから起動されるすべての操作に管理者権限が付与されます。このまま使用することはできますが、管理者権限でUniGetUIを実行しないことを強く推奨します。", + "Share anonymous usage data": "匿名利用状況データの共有", + "UniGetUI collects anonymous usage data in order to improve the user experience.": "UniGetUIは、ユーザー体験向上のため、匿名で使用状況データを収集しています。", + "Accept": "同意する", + "Software Updates": "ソフトウェアアップデート", + "Package Bundles": "パッケージバンドル", + "Settings": "設定", + "Package Managers": "パッケージマネージャー", + "UniGetUI Log": "UniGetUI ログ", + "Package Manager logs": "パッケージマネージャーのログ", + "Operation history": "パッケージ操作のログ", + "Help": "ヘルプ", + "UniGetUI": "UniGetUI", + "You have installed UniGetUI Version {0}": "UniGetUIバージョン{0}がインストールされています", + "Disclaimer": "免責事項", + "UniGetUI is developed by Devolutions and is not affiliated with any of the compatible package managers.": "UniGetUIはDevolutionsによって開発されており、対応するいずれのパッケージマネージャーとも提携していません。", + "UniGetUI wouldn't have been possible without the help of the contributors. Thank you all 🥳": "UniGetUIはコントリビューター(貢献者)の助けがなければ実現しなかったでしょう。皆様ありがとうございます🥳", + "UniGetUI uses the following libraries. Without them, UniGetUI wouldn't have been possible.": "UniGetUIは以下のライブラリを使用しています。これらのライブラリがなければUniGetUIは存在しなかったでしょう。", + "{0} homepage": "{0} ホームページ", + "UniGetUI has been translated to more than 40 languages thanks to the volunteer translators. Thank you 🤝": "UniGetUIは翻訳ボランティアの皆さんにより40以上の言語に翻訳されてきました。ありがとうございます🤝", + "Verbose": "詳細", + "1 - Errors": "1 - エラー", + "2 - Warnings": "2 - 警告", + "3 - Information (less)": "3 - 情報(概要)", + "4 - Information (more)": "4 - 情報(詳細)", + "5 - information (debug)": "5 - 情報(デバッグ)", + "Warning": "警告", + "The following settings may pose a security risk, hence they are disabled by default.": "以下の設定はセキュリティ上のリスクを伴うため、デフォルトでは無効になっています。", + "Enable the settings below if and only if you fully understand what they do, and the implications they may have.": "機能の挙動とシステムへの影響を完全に把握している場合を除き、有効にしないでください。", + "The settings will list, in their descriptions, the potential security issues they may have.": "なお、想定されるセキュリティ上の危険性については各設定項目をご覧ください。", + "The backup will include the complete list of the installed packages and their installation options. Ignored updates and skipped versions will also be saved.": "バックアップ対象:インストール済みパッケージ(詳細設定含む)の完全なリスト、除外・スキップしたバージョン", + "The backup will NOT include any binary file nor any program's saved data.": "バックアップ対象外:実行ファイル、プログラムの保存データ", + "The size of the backup is estimated to be less than 1MB.": "推定サイズ:1MB未満", + "The backup will be performed after login.": "実行タイミング:ログイン後", + "{pcName} installed packages": "{pcName}にインストールされたパッケージ", + "Current status: Not logged in": "現在のステータス:未ログイン", + "You are logged in as {0} (@{1})": "{0}(@{1})としてログイン中", + "Nice! Backups will be uploaded to a private gist on your account": "完了です!バックアップはプライベートGistにアップロードされます", + "Select backup": "バックアップを選択", + "Settings imported from {0}": "{0}から設定をインポートしました", + "UniGetUI Settings": "UniGetUI設定", + "Settings exported to {0}": "{0}に設定をエクスポートしました", + "UniGetUI settings were reset": "UniGetUIの設定がリセットされました", + "Allow pre-release versions": "プレリリース版を許可する", + "Apply": "適用する", + "For security reasons, custom command-line arguments are disabled by default. Go to UniGetUI security settings to change this.": "セキュリティ上の理由により、カスタムコマンドライン引数は既定で無効になっています。変更するにはUniGetUIのセキュリティ設定を開いてください。", + "Go to UniGetUI security settings": "UniGetUIのセキュリティ設定を開く", + "The following options will be applied by default each time a {0} package is installed, upgraded or uninstalled.": "{0}パッケージをインストール・アップデート・アンインストールする際、以下の詳細設定がデフォルトとして自動的に適用されます。", + "Package's default": "パッケージのデフォルト", + "Install location can't be changed for {0} packages": "{0}パッケージのインストール場所を変更できません", + "The local icon cache currently takes {0} MB": "アイコンのキャッシュ:{0} MB 使用中", + "Username": "ユーザー名", + "Password": "パスワード", + "Credentials": "資格情報", + "It is not guaranteed that the provided credentials will be stored safely": "入力された認証情報が、安全に保存される保証はありません", + "Partially": "部分的に", + "Package manager": "パッケージマネージャー", + "Compatible with proxy": "プロキシ対応", + "Compatible with authentication": "認証対応", + "Proxy compatibility table": "プロキシ対応状況", + "{0} settings": "{0}設定", + "{0} status": "{0}のステータス", + "Default installation options for {0} packages": "{0}パッケージのデフォルトのインストール詳細設定", + "Expand version": "バージョンを表示", + "The executable file for {0} was not found": "{0}の実行ファイルが見つかりませんでした", + "{pm} is disabled": "{pm}:無効", + "Enable it to install packages from {pm}.": "{pm}からパッケージをインストールするには有効にしてください", + "{pm} is enabled and ready to go": "{pm}:有効(利用可能)", + "{pm} version:": "{pm}バージョン:", + "{pm} was not found!": "{pm}が見つかりませんでした!", + "You may need to install {pm} in order to use it with UniGetUI.": "UniGetUIで使用するには、{pm}のインストールが必要です。", + "Scoop Installer - UniGetUI": "Scoopインストーラー - UniGetUI", + "Scoop Uninstaller - UniGetUI": "Scoopアンインストーラー - UniGetUI", + "Clearing Scoop cache - UniGetUI": "Scoopのキャッシュ消去 - UniGetUI", + "Restart UniGetUI to fully apply changes": "変更を完全に反映するにはUniGetUIを再起動してください", + "Restart UniGetUI": "UniGetUIを再起動", + "Manage {0} sources": "{0}のソース管理", + "Add source": "ソースを追加", + "Add": "追加", + "Source name": "ソース名", + "Source URL": "ソース URL", + "Other": "その他", + "No minimum age": "最低保留期間なし", + "1 day": "1日", + "{0} days": "{0}日", + "Custom...": "カスタム...", + "{0} minutes": "{0}分", + "1 hour": "1時間", + "{0} hours": "{0}時間", + "1 week": "1週間", + "Supports release dates": "対応状況", + "Release date support per package manager": "パッケージマネージャー別のリリース日対応状況", + "Search for packages": "パッケージの検索", + "Local": "ローカル", + "OK": "OK", + "Last checked: {0}": "最終確認:{0}", + "{0} packages were found, {1} of which match the specified filters.": "{0}件のパッケージが見つかり、うち{1}件がフィルターに一致しました。", + "{0} selected": "{0}件選択中", + "(Last checked: {0})": "(最終確認日時:{0})", + "All packages selected": "すべてのパッケージを選択しました", + "Package selection cleared": "パッケージの選択を解除しました", + "{0}: {1}": "{0}:{1}", + "More info": "詳細情報", + "GitHub account": "GitHub アカウント", + "Log in with GitHub to enable cloud package backup.": "クラウドバックアップを有効にするには、GitHubでログインしてください。", + "More details": "詳細情報", + "Log in": "ログイン", + "If you have cloud backup enabled, it will be saved as a GitHub Gist on this account": "クラウドバックアップが有効になっている場合は、GitHub Gistとして保存されます。", + "Log out": "ログアウト", + "About UniGetUI": "UniGetUIについて", + "About": "情報", + "Third-party licenses": "サードパーティー・ライセンス", + "Contributors": "貢献者", + "Translators": "翻訳者", + "Bundle security report": "バンドルセキュリティレポート", + "The bundle contained restricted content": "バンドルに制限された内容が含まれていました", + "UniGetUI – Crash Report": "UniGetUI – クラッシュレポート", + "UniGetUI has crashed": "UniGetUIがクラッシュしました", + "Help us fix this by sending a crash report to Devolutions. All fields below are optional.": "クラッシュレポートをDevolutionsに送信して修正にご協力ください。以下のフィールドはすべて任意です。", + "Email (optional)": "メールアドレス(任意)", + "your@email.com": "your@email.com", + "Additional details (optional)": "追加の詳細(任意)", + "Describe what you were doing when the crash occurred…": "クラッシュが発生した時に何をしていたか説明してください…", + "Crash report": "クラッシュレポート", + "Don't Send": "送信しない", + "Send Report": "レポートを送信", + "Sending…": "送信中…", + "Unsaved changes": "未保存の変更", + "You have unsaved changes in the current bundle. Do you want to discard them?": "現在のバンドルに未保存の変更があります。破棄しますか?", + "Discard changes": "変更を破棄", + "Integrity violation": "整合性違反", + "UniGetUI or some of its components are missing or corrupt. It is strongly recommended to reinstall UniGetUI to adress the situation.": "UniGetUIまたはその一部のコンポーネントが見つからないか破損しています。この状況に対処するには、UniGetUIを再インストールすることを強く推奨します。", + "• Refer to the UniGetUI Logs to get more details regarding the affected file(s)": "• 影響を受けたファイルに関する詳細を確認するには、UniGetUI ログを参照してください。", + "• Integrity checks can be disabled from the Experimental Settings": "• 整合性チェックは「実験的設定」から無効にできます。", + "Manage shortcuts": "ショートカットの自動削除設定", + "UniGetUI has detected the following desktop shortcuts which can be removed automatically on future upgrades": "今後のアップデート時に自動削除可能なデスクトップショートカットが検出されました", + "Do you really want to reset this list? This action cannot be reverted.": "このリストを本当にリセットしますか?この操作は元に戻せません。", + "Desktop shortcuts list": "デスクトップショートカット一覧", + "Open in explorer": "エクスプローラーで開く", + "Remove from list": "リストから削除", + "When new shortcuts are detected, delete them automatically instead of showing this dialog.": "新しいショートカットが検出された場合、このダイアログを表示せずに自動的に削除する", + "Not right now": "あとで", + "Missing dependency": "必要な依存関係が見つかりません", + "UniGetUI requires {0} to operate, but it was not found on your system.": "UniGetUIには{0}が必要ですが、お使いのシステムで見つかりませんでした。", + "Click on Install to begin the installation process. If you skip the installation, UniGetUI may not work as expected.": "インストール処理を開始するには [インストール] をクリックします。インストールをスキップする場合は、UniGetUIが想定通りに動作しない可能性があります。", + "Alternatively, you can also install {0} by running the following command in a Windows PowerShell prompt:": "あるいは、Windows PowerShellプロンプトで以下のコマンドを実行して{0}をインストールすることもできます。", + "Install {0}": "{0}をインストール", + "Do not show this dialog again for {0}": "今後{0}のダイアログを再表示しない", + "Please wait while {0} is being installed. A black window may show up. Please wait until it closes.": "{0}のインストールが完了するまでお待ちください。黒いウィンドウが表示される場合があります。そのウィンドウが閉じるまでお待ちください。", + "{0} has been installed successfully.": "{0}は正常にインストールされました。", + "Please click on \"Continue\" to continue": "「続行」をクリックして、続行してください。", + "Continue": "続行", + "{0} has been installed successfully. It is recommended to restart UniGetUI to finish the installation": "{0}が正常にインストールされました。インストールを完了するため、UniGetUIを再起動することをおすすめします。", + "Restart later": "後で再起動する", + "An error occurred:": "エラーが発生しました:", + "Please see the Command-line Output or refer to the Operation History for further information about the issue.": "この問題に関する詳細はコマンドライン出力か、パッケージ操作ログをご覧ください", + "Retry as administrator": "管理者として再試行", + "Retry interactively": "対話的に再試行する", + "Retry skipping integrity checks": "再試行時に整合性チェックをスキップする", + "Installation options": "インストール詳細設定", + "Save": "保存", + "UniGetUI collects anonymous usage data with the sole purpose of understanding and improving the user experience.": "UniGetUIは、ユーザーエクスペリエンスの向上を目的に、個人を特定できない匿名化された利用データを収集します。", + "More details about the shared data and how it will be processed": "共有データと処理方法の詳細はこちら", + "Do you accept that UniGetUI collects and sends anonymous usage statistics, with the sole purpose of understanding and improving the user experience?": "UniGetUIが、ユーザーエクスペリエンス向上のため、匿名の利用統計を収集・送信することに同意しますか?", + "Decline": "拒否", + "No personal information is collected nor sent, and the collected data is anonimized, so it can't be back-tracked to you.": "個人情報の収集や送信は一切行っておらず、収集されたデータは匿名化されているため、お客様個人を特定することはできません。", + "Navigation panel": "ナビゲーションパネル", + "Operations": "パッケージ操作", + "Toggle operations panel": "操作パネルの表示/非表示", + "Bulk operations": "一括パッケージ操作", + "Retry failed": "失敗した項目を再試行", + "Clear successful": "成功した項目をクリア", + "Clear finished": "完了した項目をクリア", + "Cancel all": "すべてキャンセル", + "More": "その他", + "Toggle navigation panel": "ナビゲーションパネルの表示を切り替える", + "Minimize": "最小化", + "Maximize": "最大化", + "UniGetUI by Devolutions": "UniGetUI by Devolutions", + "UniGetUI is an application that makes managing your software easier, by providing an all-in-one graphical interface for your command-line package managers.": "UniGetUIはコマンドライン・パッケージマネージャーに代わり一体化したGUIによって、ソフトウェアの管理をより簡単にするアプリケーションです。", + "Useful links": "関連リンク", + "UniGetUI Homepage": "UniGetUI ホームページ", + "Report an issue or submit a feature request": "不具合報告・機能の要望提出", + "UniGetUI Repository": "UniGetUI リポジトリ", + "View GitHub Profile": "GitHub プロフィールを表示", + "UniGetUI License": "UniGetUI ライセンス", + "Using UniGetUI implies the acceptation of the MIT License": "UniGetUIを使用する場合、MITライセンスに同意したことになります", + "Become a translator": "翻訳者になる", + "Go back": "戻る", + "Go forward": "進む", + "Go to home page": "ホームページに移動", + "Reload page": "ページを再読み込み", + "View page on browser": "ページをブラウザーで表示する", + "The built-in browser is not supported on Linux yet.": "組み込みブラウザーは、Linuxではまだサポートされていません。", + "Open in browser": "ブラウザーで開く", + "Copy to clipboard": "クリップボードにコピー", + "Export to a file": "ファイルにエクスポート", + "Log level:": "ログレベル:", + "Reload log": "ログの再読み込み", + "Export log": "ログをエクスポート", + "Text": "テキスト", + "Change how operations request administrator rights": "管理者権限の要求に関する挙動の変更", + "Restrictions on package operations": "パッケージ操作の制限", + "Restrictions on package managers": "パッケージマネージャーの制限", + "Restrictions when importing package bundles": "パッケージバンドルをインポートする際の制限", + "Ask for administrator privileges once for each batch of operations": "パッケージ操作のバッチごとに1回だけ管理者権限を要求する", + "Ask only once for administrator privileges": "管理者権限の要求を1回のみにする", + "Prohibit any kind of Elevation via UniGetUI Elevator or GSudo": "UniGetUI Elevator または GSudo による権限昇格を禁止する", + "This option WILL cause issues. Any operation incapable of elevating itself WILL FAIL. Install/update/uninstall as administrator will NOT WORK.": "エラーの原因となるため推奨されません。\n単独で権限昇格を行えないすべてのパッケージ操作が失敗するため、管理者としてのインストール・アップデート・アンインストールが動作しなくなります。", + "Allow custom command-line arguments": "カスタムコマンドライン引数を許可する", + "Custom command-line arguments can change the way in which programs are installed, upgraded or uninstalled, in a way UniGetUI cannot control. Using custom command-lines can break packages. Proceed with caution.": "カスタムコマンドライン引数によって、プログラムのインストール、アップグレード、アンインストールの方法がUniGetUIでは制御できない形で変更されることがあります。カスタムコマンドライン引数を使用するとパッケージが破損する可能性があります。慎重に操作してください。", + "Ignore custom pre-install and post-install commands when importing packages from a bundle": "バンドルからパッケージをインポートする際に、カスタムのインストール前後コマンドを無視する", + "Pre and post install commands will be run before and after a package gets installed, upgraded or uninstalled. Be aware that they may break things unless used carefully": "インストール前およびインストール後のコマンドは、パッケージのインストール、アップグレード、アンインストールの前後に実行されます。慎重に使用しないと問題を引き起こす可能性があります。", + "Allow changing the paths for package manager executables": "パッケージマネージャー実行ファイルのパスの変更を許可する", + "Turning this on enables changing the executable file used to interact with package managers. While this allows finer-grained customization of your install processes, it may also be dangerous": "これをオンにすると、パッケージマネージャーとのやり取りに使用する実行ファイルを変更できるようになります。これによりインストールプロセスをより細かくカスタマイズできるようになりますが、危険な場合もあります。", + "Allow importing custom command-line arguments when importing packages from a bundle": "バンドルからパッケージをインポートする際に、カスタムコマンドライン引数のインポートを許可する", + "Malformed command-line arguments can break packages, or even allow a malicious actor to gain privileged execution. Therefore, importing custom command-line arguments is disabled by default": "不正なコマンドライン引数はパッケージを破損させたり、悪意のある攻撃者が昇格した権限で実行を行うことを可能にする場合があります。そのため、カスタムコマンドライン引数のインポートはデフォルトで無効になっています。", + "Allow importing custom pre-install and post-install commands when importing packages from a bundle": "バンドルからパッケージをインポートする際に、インストール前およびインストール後のカスタムコマンドのインポートを許可する。", + "Pre and post install commands can do very nasty things to your device, if designed to do so. It can be very dangerous to import the commands from a bundle, unless you trust the source of that package bundle": "インストール前後のコマンドは、もし悪意を持って設計されていれば、あなたのデバイスに非常に悪質な影響を与える可能性があります。パッケージバンドルのソースを信頼しない限り、そこからコマンドをインポートするのは非常に危険です。", + "Administrator rights and other dangerous settings": "管理者権限や危険な設定", + "Package backup": "パッケージ一覧のバックアップ", + "Cloud package backup": "クラウドバックアップ", + "Local package backup": "ローカルバックアップ", + "Local backup advanced options": "ローカルバックアップの詳細設定", + "Log in with GitHub": "GitHubでログイン", + "Log out from GitHub": "GitHubからログアウト", + "Periodically perform a cloud backup of the installed packages": "クラウドバックアップを定期的に実行", + "Cloud backup uses a private GitHub Gist to store a list of installed packages": "現在インストールされているパッケージ一覧を、GitHubのプライベートGistを使用して自動でバックアップします", + "Perform a cloud backup now": "今すぐクラウドバックアップを実行する", + "Backup": "バックアップ", + "Restore a backup from the cloud": "クラウドからバックアップを復元する", + "Begin the process to select a cloud backup and review which packages to restore": "クラウドバックアップを選択し、復元するパッケージを確認するプロセスを開始します", + "Periodically perform a local backup of the installed packages": "ローカルバックアップを定期的に実行", + "Perform a local backup now": "今すぐローカルバックアップを実行する", + "Change backup output directory": "バックアップの保存先", + "Set a custom backup file name": "バックアップのファイル名", + "Leave empty for default": "通常は空欄にしてください", + "Add a timestamp to the backup file names": "バックアップのファイル名にタイムスタンプを含める", + "Backup and Restore": "バックアップと復元", + "Enable background api (UniGetUI Widgets and Sharing, port 7058)": "バックグラウンドAPIを有効にする(UniGetUI Widgetsと共有機能用、7058番ポート)", + "Wait for the device to be connected to the internet before attempting to do tasks that require internet connectivity.": "デバイスがインターネットに接続されるまでインターネット接続を必要とするタスクを実行しない", + "Disable the 1-minute timeout for package-related operations": "パッケージ関連の操作における1分間のタイムアウトを無効にする", + "Use installed GSudo instead of UniGetUI Elevator": "UniGetUI Elevator の代わりに、インストールされた GSudo を使用する", + "Use a custom icon and screenshot database URL": "アイコンとスクリーンショットにカスタムデータベースを使用する", + "Enable background CPU Usage optimizations (see Pull Request #3278)": "バックグラウンドCPU使用率の最適化を有効にする(プルリクエスト #3278 を参照)", + "Perform integrity checks at startup": "起動時に整合性チェックを実行する", + "When batch installing packages from a bundle, install also packages that are already installed": "バンドルからパッケージを一括インストールする際、既にインストールされているパッケージもインストールする", + "Experimental settings and developer options": "実験的な設定と開発者向け設定", + "Show UniGetUI's version and build number on the titlebar.": "タイトルバーにUniGetUIのバージョンとビルド番号を表示する", + "Language": "言語", + "UniGetUI updater": "UniGetUI 更新設定", + "Telemetry": "利用状況データ", + "Manage UniGetUI settings": "UniGetUI設定を管理する", + "Related settings": "関連設定", + "Update UniGetUI automatically": "UniGetUIを自動アップデートする", + "Check for updates": "アップデートの確認", + "Install prerelease versions of UniGetUI": "プレリリース版のUniGetUIをインストールする", + "Manage telemetry settings": "利用状況データの設定", + "Manage": "管理", + "Import settings from a local file": "ファイルから設定をインポート", + "Import": "インポート", + "Export settings to a local file": "設定をファイルにエクスポート", + "Export": "エクスポート", + "Reset UniGetUI": "UniGetUIをリセット", + "User interface preferences": "UI設定", + "Application theme, startup page, package icons, clear successful installs automatically": "テーマカラーやアイコン表示、インストール成功時のログ自動削除など", + "General preferences": "全般設定", + "UniGetUI display language:": "UniGetUIの表示言語:", + "System language": "システムの言語", + "Is your language missing or incomplete?": "ご希望の言語が見当たらない、または不完全ですか?", + "Appearance": "外観", + "UniGetUI on the background and system tray": "UniGetUIのシステムトレイ常駐とスタートアップ起動", + "Package lists": "パッケージ一覧", + "Use classic mode": "クラシック モードを使用する", + "Restart UniGetUI to apply this change": "この変更を適用するには UniGetUIを再起動してください", + "The classic UI is disabled for beta testers": "ベータテスター向けにはクラシック UI が無効になっています", + "Close UniGetUI to the system tray": "UniGetUIをシステムトレイに常駐させる", + "Manage UniGetUI autostart behaviour": "スタートアップ起動の設定画面を開く", + "Show package icons on package lists": "パッケージ一覧でパッケージのアイコンを表示する", + "Clear cache": "キャッシュのクリア", + "Select upgradable packages by default": "アップデート可能なパッケージをデフォルトで選択する", + "Light": "ライトテーマ", + "Dark": "ダークテーマ", + "Follow system color scheme": "システムのカラーモードに従う", + "Application theme:": "テーマカラー:", + "UniGetUI startup page:": "起動時に表示する画面:", + "Proxy settings": "プロキシ設定", + "Other settings": "その他の設定", + "Connect the internet using a custom proxy": "カスタムプロキシを使用してインターネットに接続する", + "Please note that not all package managers may fully support this feature": "一部パッケージマネージャーでは、正しく動作しない場合があります", + "Proxy URL": "プロキシURL", + "Enter proxy URL here": "ここにプロキシURLを入力してください", + "Authenticate to the proxy with a user and a password": "ユーザー名とパスワードでプロキシ認証を行う", + "Internet and proxy settings": "インターネットとプロキシの設定", + "Package manager preferences": "パッケージマネージャーの管理", + "Ready": "利用可能", + "Not found": "未検出", + "Notification preferences": "通知設定", + "Notification types": "通知の種類", + "The system tray icon must be enabled in order for notifications to work": "通知を表示するには、システムトレイの常駐を有効にする必要があります", + "Enable UniGetUI notifications": "UniGetUIの通知を有効にする", + "Show a notification when there are available updates": "利用可能なアップデートがある時に通知する", + "Show a silent notification when an operation is running": "パッケージ操作の開始時にサイレント通知する", + "Show a notification when an operation fails": "パッケージ操作が失敗した時に通知する", + "Show a notification when an operation finishes successfully": "パッケージ操作が正常に終了した時に通知する", + "Concurrency and execution": "並行処理と実行", + "Automatic desktop shortcut remover": "デスクトップショートカットの自動削除", + "Choose how many operations should be performed in parallel": "同時に実行するパッケージ操作数", + "Clear successful operations from the operation list after a 5 second delay": "成功したパッケージ操作を5秒後に一覧から消去する", + "Download operations are not affected by this setting": "ダウンロード操作はこの設定の影響を受けません", + "You may lose unsaved data": "保存されていないデータが失われる可能性があります", + "Ask to delete desktop shortcuts created during an install or upgrade.": "インストール・アップデート時にデスクトップショートカットの作成を検出し、削除の確認ダイアログを表示する", + "Package update preferences": "パッケージの更新設定", + "Update check frequency, automatically install updates, etc.": "アップデートの確認間隔、自動インストールなど", + "Reduce UAC prompts, elevate installations by default, unlock certain dangerous features, etc.": "UACプロンプトの軽減やインストールの常時昇格、セキュリティ上のリスクが高い設定の有効化など", + "Package operation preferences": "パッケージ操作の設定", + "Enable {pm}": "{pm}を有効化", + "Not finding the file you are looking for? Make sure it has been added to path.": "探しているファイルが見つかりませんか?パスに追加されていることを確認してください。", + "Select the executable to be used. The following list shows the executables found by UniGetUI": "使用する実行ファイルを選択してください。以下はUniGetUIによって検出された実行ファイルです", + "For security reasons, changing the executable file is disabled by default": "セキュリティ上の理由から、実行ファイルの変更はデフォルトで無効になっています。", + "Change this": "変更する", + "Copy path": "パスをコピー", + "Current executable file:": "現在の実行ファイル:", + "Ignore packages from {pm} when showing a notification about updates": "{pm}のパッケージをアップデート通知の対象から除外する", + "Update security": "アップデートのセキュリティ", + "Use global setting": "グローバル設定を使用", + "Minimum age for updates": "アップデートの最低保留期間", + "e.g. 10": "例:10", + "Custom minimum age (days)": "カスタム最低保留期間(日)", + "{pm} does not provide release dates for its packages, so this setting will have no effect": "{pm}ではパッケージのリリース日が提供されないため、この設定は機能しません。", + "{pm} only provides release dates for some of its packages, so this setting will only apply to those packages": "{pm}ではリリース日が提供されている一部のパッケージのみ適用されます", + "Override the global minimum update age for this package manager": "グローバル設定の最低保留期間を上書きする", + "View {0} logs": "{0} ログを表示", + "If Python cannot be found or is not listing packages but is installed on the system, ": "Pythonが見つからない、またはパッケージを一覧表示できないものの、システムにインストールされている場合は、", + "Advanced options": "高度な設定", + "WinGet command-line tool": "WinGetコマンドラインツール", + "Choose which command-line tool UniGetUI uses for WinGet operations when the COM API is not used": "COM APIを使用しない場合に、UniGetUIがWinGetのパッケージ操作に使用するコマンドラインツールを選択します", + "WinGet COM API": "WinGet COM API", + "Choose whether UniGetUI can use the WinGet COM API before falling back to the command-line tool": "コマンドラインツールへのフォールバック前に、WinGet COM APIの利用を試みるかどうか", + "Reset WinGet": "WinGetの初期化", + "This may help if no packages are listed": "パッケージがリストに表示されない場合に実行してください", + "Force install location parameter when updating packages with custom locations": "アップデート時にカスタムインストール先のパラメーター付与を維持する", + "Install Scoop": "Scoopのインストール", + "Uninstall Scoop (and its packages)": "Scoop(およびScoopパッケージ)のアンインストール", + "Run cleanup and clear cache": "クリーンアップとキャッシュ消去を実行する", + "Run": "実行", + "Enable Scoop cleanup on launch": "起動時にScoopのクリーンアップを有効化", + "Default vcpkg triplet": "デフォルトのvcpkgトリプレット", + "Change vcpkg root location": "vcpkgのルートの場所を変更する", + "Reset vcpkg root location": "vcpkgのルートパスをリセット", + "Open vcpkg root location": "vcpkgのルートパスを開く", + "Language, theme and other miscellaneous preferences": "言語やテーマなど", + "Show notifications on different events": "アップデート状況などを通知します", + "Change how UniGetUI checks and installs available updates for your packages": "インストール・アップデート・アンインストール時のパッケージ操作の挙動など", + "Automatically save a list of all your installed packages to easily restore them.": "インストール済みパッケージ一覧を自動保存し、いつでも元の環境へ復元できるようにします。", + "Enable and disable package managers, change default install options, etc.": "パッケージマネージャーの有効化・無効化や、既定のインストール設定の変更など", + "Internet connection settings": "インターネットの接続設定", + "Proxy settings, etc.": "プロキシ設定など", + "Beta features and other options that shouldn't be touched": "開発中の機能や非推奨の高度な設定など", + "Reload sources": "ソースを再読み込み", + "Delete source": "ソースを削除", + "Known sources": "既知のソース", + "Update checking": "アップデート確認", + "Automatic updates": "自動更新", + "Check for package updates periodically": "定期的にパッケージのアップデートを確認する", + "Check for updates every:": "アップデートの確認間隔:", + "Install available updates automatically": "利用可能なアップデートを自動的にインストールする", + "Do not automatically install updates when the network connection is metered": "ネットワーク接続が従量制の場合は、自動的にアップデートをインストールしない", + "Do not automatically install updates when the device runs on battery": "バッテリーで動作している場合は、アップデートを自動的にインストールしない", + "Do not automatically install updates when the battery saver is on": "バッテリーセーバーが有効な場合は、アップデートを自動的にインストールしない", + "Only show updates that are at least the specified number of days old": "リリース日から指定した日数以上経過したアップデートのみ表示します", + "Warn me when the installer URL host changes between the installed version and the new version (WinGet only)": "インストーラーURLのホスト変更時に警告を表示(WinGetのみ)", + "Change how UniGetUI handles install, update and uninstall operations.": "インストール・アップデート・アンインストール時のパッケージ操作の挙動など", + "Navigation": "ナビゲーション", + "Check for UniGetUI updates": "UniGetUIのアップデートを確認", + "Quit UniGetUI": "UniGetUIを終了", + "Filters": "フィルター", + "Sources": "ソース", + "Search for packages to start": "パッケージを検索してください", + "Select all": "すべて選択", + "Clear selection": "選択を解除", + "Instant search": "インクリメンタル検索", + "Distinguish between uppercase and lowercase": "大文字と小文字を区別", + "Ignore special characters": "特殊文字を無視", + "Search mode": "検索モード", + "Both": "両方", + "Exact match": "完全一致", + "Show similar packages": "類似パッケージ", + "Loading": "読み込み中", + "Package": "パッケージ", + "More options": "その他のオプション", + "Order by:": "並べ替え:", + "Name": "名称", + "Id": "ID", + "Ascendant": "昇順", + "Descendant": "降順", + "View modes": "表示モード", + "Reload": "再読み込み", + "Closed": "閉じました", + "Ascending": "昇順", + "Descending": "降順", + "{0}: {1}, {2}": "{0}:{1}, {2}", + "Order by": "並び替え", + "No results were found matching the input criteria": "入力された条件に一致する結果は見つかりませんでした", + "No packages were found": "パッケージが見つかりませんでした", + "Loading packages": "パッケージを読み込み中", + "Skip integrity checks": "整合性の検証をスキップ", + "Download selected installers": "選択したインストーラをダウンロード", + "Install selection": "選択したパッケージをインストール", + "Install options": "インストールの詳細設定", + "Add selection to bundle": "選択したパッケージをバンドルに追加", + "Download installer": "インストーラーをダウンロード", + "Uninstall selection": "選択したパッケージをアンインストール", + "Uninstall options": "アンインストールの詳細設定", + "Ignore selected packages": "選択したパッケージを除外", + "Open install location": "インストール場所を開く", + "Reinstall package": "パッケージを再インストール", + "Uninstall package, then reinstall it": "パッケージをアンインストールしてから再インストール", + "Ignore updates for this package": "アップデート対象から除外する", + "WinGet malfunction detected": "WinGetの不具合を検出しました", + "It looks like WinGet is not working properly. Do you want to attempt to repair WinGet?": "WinGetが正常に動作していないようです。WinGet の修復を試みますか?", + "Repair WinGet": "WinGetの修復", + "Updates will no longer be ignored for {0}": "{0}のアップデートは除外を解除しました", + "Updates are now ignored for {0}": "{0}のアップデートを除外するようにしました", + "Do not ignore updates for this package anymore": "アップデート対象からの除外を解除する", + "Add packages or open an existing package bundle": "パッケージを追加するか、既存のパッケージバンドルを開きます", + "Add packages to start": "パッケージを追加してください", + "The current bundle has no packages. Add some packages to get started": "パッケージを追加して、バンドルの利用を始めましょう", + "New": "新規", + "Save as": "名前を付けて保存", + "Create .ps1 script": ".ps1スクリプトを作成", + "Remove selection from bundle": "選択したパッケージをバンドルから削除", + "Skip hash checks": "ハッシュチェックをスキップする", + "The package bundle is not valid": "パッケージバンドルが無効です", + "The bundle you are trying to load appears to be invalid. Please check the file and try again.": "無効なバンドルが読み込まれました。ファイルを確認し、もう一度お試しください。", + "Package bundle": "パッケージバンドル", + "Could not create bundle": "バンドルを作成できませんでした", + "The package bundle could not be created due to an error.": "エラーのためパッケージ バンドルを作成できませんでした。", + "Install script": "インストールスクリプト", + "PowerShell script": "PowerShellスクリプト", + "The installation script saved to {0}": "インストールスクリプトは{0}に保存されました", + "An error occurred": "エラーが発生しました", + "An error occurred while attempting to create an installation script:": "インストールスクリプトの作成中にエラーが発生しました:", + "Hooray! No updates were found.": "アップデートは見つかりませんでした!", + "Uninstall selected packages": "選択したパッケージをアンインストール", + "Update selection": "選択したパッケージをアップデート", + "Update options": "アップデートの詳細設定", + "Uninstall package, then update it": "パッケージをアンインストールしてからアップデート", + "Uninstall package": "パッケージをアンインストール", + "Skip this version": "このバージョンをスキップする", + "Pause updates for": "更新を一時停止", + "User | Local": "ユーザー | ローカル", + "Machine | Global": "マシン | グローバル", + "The default package manager for Debian/Ubuntu-based Linux distributions.
Contains: Debian/Ubuntu packages": "Debian/UbuntuベースのLinuxディストリビューション向けの標準パッケージマネージャーです。
対象:Debian/Ubuntuパッケージ", + "The Rust package manager.
Contains: Rust libraries and programs written in Rust": "Rust用パッケージマネージャーです。
対象:Rustで書かれたRustのライブラリ、プログラム\n", + "The classical package manager for windows. You'll find everything there.
Contains: General Software": "Windows用の旧来の定番パッケージマネージャーです。あらゆるパッケージが網羅されています。
対象:一般ソフトウェア", + "The default package manager for RHEL/Fedora-based Linux distributions.
Contains: RPM packages": "RHEL/FedoraベースのLinuxディストリビューション向けの標準パッケージマネージャーです。
対象:RPMパッケージ", + "A repository full of tools and executables designed with Microsoft's .NET ecosystem in mind.
Contains: .NET related tools and scripts": "Microsoft .NET向けの開発ツールや実行ファイルが豊富に揃うリポジトリです。
対象:.NET関連のツール、スクリプト", + "The universal Linux package manager for desktop applications.
Contains: Flatpak applications from configured remotes": "デスクトップアプリ向けの汎用Linuxパッケージマネージャーです。
対象:登録されたリポジトリのFlatpakアプリ", + "NuPkg (zipped manifest)": "NuPkg(zip圧縮されたマニフェストファイル)", + "The Missing Package Manager for macOS (or Linux).
Contains: Formulae, Casks": "macOS/Linux用定番パッケージマネージャー。
対象:Formulae、Casksなど", + "Node JS's package manager. Full of libraries and other utilities that orbit the javascript world
Contains: Node javascript libraries and other related utilities": "Node.js用パッケージマネージャーです。JavaScript環境のあらゆるライブラリやユーティリティが揃っています。
対象:Node.jsのJavaScriptライブラリおよびその他の関連ユーティリティ", + "The default package manager for Arch Linux and its derivatives.
Contains: Arch Linux packages": "Arch Linuxベースのディストリビューション向けの標準パッケージマネージャーです。
対象:Arch Linuxパッケージ", + "Python's library manager. Full of python libraries and other python-related utilities
Contains: Python libraries and related utilities": "Python用ライブラリマネージャーです。各種ライブラリおよび関連ユーティリティが豊富に揃っています。
対象:Pythonライブラリ、関連ユーティリティ", + "PowerShell's package manager. Find libraries and scripts to expand PowerShell capabilities
Contains: Modules, Scripts, Cmdlets": "PowerShell用パッケージマネージャーです。機能を拡張するライブラリやスクリプトが用意されています。
対象:モジュール、スクリプト、コマンドレット\n", + "extracted": "抽出された", + "Scoop package": "Scoopパッケージ", + "Great repository of unknown but useful utilities and other interesting packages.
Contains: Utilities, Command-line programs, General Software (extras bucket required)": "マイナーながら実用的なユーティリティツールが豊富に揃う優れたリポジトリです。
対象:ユーティリティ、コマンドラインプログラム、一般ソフトウェア(追加バケットが必要)", + "The universal Linux package manager by Canonical.
Contains: Snap packages from the Snapcraft store": "Canonicalの汎用Linuxパッケージマネージャーです。
対象:SnapcraftストアからのSnapパッケージ", + "library": "ライブラリ", + "feature": "機能", + "A popular C/C++ library manager. Full of C/C++ libraries and other C/C++-related utilities
Contains: C/C++ libraries and related utilities": "C/C++用定番ライブラリマネージャーです。豊富なライブラリと関連のユーティリティが揃っています。
対象:C/C++ライブラリ、関連ユーティリティ", + "option": "オプション", + "This package cannot be installed from an elevated context.": "このパッケージは管理者権限で実行された環境からインストールできません。", + "Please run UniGetUI as a regular user and try again.": "UniGetUIを一般ユーザーとして実行し、もう一度お試しください。", + "Please check the installation options for this package and try again": "このパッケージのインストール詳細設定を確認し、再度お試しください。", + "Microsoft's official package manager. Full of well-known and verified packages
Contains: General Software, Microsoft Store apps": "Microsoft公式のパッケージマネージャーです。知名度が高く検証済みのパッケージが豊富に揃っています。
対象:一般ソフトウェア、Microsoft Storeアプリなど", + "Local PC": "ローカルPC", + "Android Subsystem": "Androidサブシステム", + "Operation on queue (position {0})...": "順番を待っています(キューの{0}番目)...", + "Click here for more details": "詳細についてはここをクリックしてください", + "Operation canceled by user": "パッケージ操作はユーザーによってキャンセルされました", + "Running PreOperation ({0}/{1})...": "PreOperationを実行中({0}/{1})...", + "PreOperation {0} out of {1} failed, and was tagged as necessary. Aborting...": "PreOperation {1}件中{0}件目が失敗し、必須としてマークされていたため、中止しています...", + "PreOperation {0} out of {1} finished with result {2}": "PreOperation {1}件中{0}件目が結果{2}で完了しました", + "Starting operation...": "パッケージ操作を開始しています...", + "Running PostOperation ({0}/{1})...": "PostOperation を実行中({0}/{1})...", + "PostOperation {0} out of {1} failed, and was tagged as necessary. Aborting...": "PostOperation {1}件中{0}件目が失敗し、必須としてマークされていたため、中止しています...", + "PostOperation {0} out of {1} finished with result {2}": "PostOperation {1}件中{0}件目が結果{2}で完了しました", + "{package} installer download": "{package}インストーラーのダウンロード", + "{0} installer is being downloaded": "{0}インストーラをダウンロードしています", + "Download succeeded": "ダウンロード成功", + "{package} installer was downloaded successfully": "{package}インストーラーが正常にダウンロードされました", + "Download failed": "ダウンロードに失敗しました", + "{package} installer could not be downloaded": "{package}インストーラーをダウンロードできませんでした", + "{package} Installation": "{package}のインストール", + "{0} is being installed": "{0}をインストール中", + "Installation succeeded": "インストール成功", + "{package} was installed successfully": "{package} は正常にインストールされました", + "Installation failed": "インストール失敗", + "{package} could not be installed": "{package} をインストールできませんでした", + "{package} Update": "{package} のアップデート", + "Update succeeded": "アップデートに成功しました", + "{package} was updated successfully": "{package} は正常にアップデートされました", + "Update failed": "アップデートに失敗しました", + "{package} could not be updated": "{package} をアップデートできませんでした", + "{package} Uninstall": "{package} のアンインストール", + "{0} is being uninstalled": "{0}をアンインストール中", + "Uninstall succeeded": "アンインストールに成功しました", + "{package} was uninstalled successfully": "{package} は正常にアンインストールされました", + "Uninstall failed": "アンインストールに失敗しました", + "{package} could not be uninstalled": "{package} をアンインストールできませんでした", + "Adding source {source}": "ソース{source}を追加", + "Adding source {source} to {manager}": "ソース{source}を{manager}に追加しています", + "Source added successfully": "ソースが正常に追加されました", + "The source {source} was added to {manager} successfully": "ソース{source}が{manager}に正常に追加されました", + "Could not add source": "ソースを追加できませんでした", + "Could not add source {source} to {manager}": "ソース{source}を{manager}に追加できませんでした", + "Removing source {source}": "ソース{source}の削除", + "Removing source {source} from {manager}": "ソース{source}を{manager}から削除しています", + "Source removed successfully": "ソースが正常に削除されました", + "The source {source} was removed from {manager} successfully": "ソース{source}が{manager}から無事に削除されました", + "Could not remove source": "ソースを削除できませんでした", + "Could not remove source {source} from {manager}": "{manager}からソース{source}を削除できませんでした", + "The package manager \"{0}\" was not found": "パッケージマネージャー「{0}」が見つかりませんでした", + "The package manager \"{0}\" is disabled": "パッケージマネージャー「{0}」は無効です", + "There is an error with the configuration of the package manager \"{0}\"": "パッケージ マネージャー「{0}」の構成にエラーがあります", + "The package \"{0}\" was not found on the package manager \"{1}\"": "パッケージ「{0}」はパッケージマネージャー「{1}」で見つかりませんでした。", + "{0} is disabled": "{0}は無効です", + "{0} weeks": "{0}週間", + "1 month": "1か月", + "{0} months": "{0}か月", + "Something went wrong": "問題が発生しました", + "An interal error occurred. Please view the log for further details.": "内部エラーが発生しました。詳細についてはログを確認してください。", + "No applicable installer was found for the package {0}": "パッケージ{0}に適用可能なインストーラーが見つかりませんでした", + "Integrity checks will not be performed during this operation": "このパッケージ操作中は整合性チェックは実行されません", + "This is not recommended.": "推奨されません。", + "Run now": "今すぐ実行", + "Run next": "次に実行", + "Run last": "最後に実行", + "Show in explorer": "エクスプローラーで表示", + "Checked": "チェック済み", + "Unchecked": "未チェック", + "This package is already installed": "このパッケージはすでにインストールされています", + "This package can be upgraded to version {0}": "このパッケージはバージョン{0}にアップグレードできます", + "Updates for this package are ignored": "このパッケージはアップデート対象から除外されています", + "This package is being processed": "このパッケージはインストール作業中です", + "This package is not available": "このパッケージは利用できません", + "Select the source you want to add:": "追加したいソースを選択してください:", + "Source name:": "ソース名:", + "Source URL:": "ソース URL:", + "An error occurred when adding the source: ": "ソースの追加時にエラーが発生しました:", + "Package management made easy": "パッケージ管理を簡単に", + "version {0}": "バージョン {0}", + "[RAN AS ADMINISTRATOR]": "管理者として実行", + "Portable mode": "ポータブルモード", + "DEBUG BUILD": "デバッグビルド", + "Here you can change UniGetUI's behaviour regarding the following shortcuts. Checking a shortcut will make UniGetUI delete it if if gets created on a future upgrade. Unchecking it will keep the shortcut intact": "以下のショートカットに関するUniGetUIの動作を設定できます。チェックを入れると、今後、アップデートと同時に作成されるショートカットが自動的に削除されます。チェックを外すと、削除されずに維持されます", + "Manual scan": "手動スキャン", + "Existing shortcuts on your desktop will be scanned, and you will need to pick which ones to keep and which ones to remove.": "デスクトップ上の既存のショートカットがスキャンされ、保持するショートカットと削除するショートカットを選択する必要があります。", + "Delete?": "消去しますか?", + "I understand": "了解", + "Chocolatey setup changed": "Chocolateyのセットアップが変更されました", + "UniGetUI no longer includes its own private Chocolatey installation. A legacy UniGetUI-managed Chocolatey installation was detected for this user profile, but system Chocolatey was not found. Chocolatey will stay unavailable in UniGetUI until Chocolatey is installed on the system and UniGetUI is restarted. Applications previously installed through UniGetUI's bundled Chocolatey may still appear under other sources such as Local PC or WinGet.": "UniGetUIには独自のChocolateyインストールが含まれなくなりました。このユーザープロファイルで従来のUniGetUI管理のChocolateyインストールが検出されましたが、システムにChocolateyが見つかりませんでした。ChocolateyをシステムにインストールしてUniGetUIを再起動するまで、UniGetUIではChocolateyを使用できません。以前UniGetUIにバンドルされたChocolateyでインストールされたアプリケーションは、ローカル PCやWinGetなどの他のソースに表示される場合があります。", + "NOTE: This troubleshooter can be disabled from UniGetUI Settings, on the WinGet section": "注意:このトラブルシューティングは、UniGetUI設定のWinGetセクションから無効にすることができます。", + "Restart": "再起動", + "Are you sure you want to delete all shortcuts?": "すべてのショートカットを削除してもよろしいですか?", + "Any new shorcuts created during an install or an update operation will be deleted automatically, instead of showing a confirmation prompt the first time they are detected.": "今後、インストール・アップデート時にデスクトップショートカットの作成が新しく検出された場合、毎回確認ダイアログを表示させず、自動的に削除する", + "Any shorcuts created or modified outside of UniGetUI will be ignored. You will be able to add them via the {0} button.": "UniGetUIの外部で作成または変更されたショートカットは無視されます。{0}ボタンから追加できます。", + "Are you really sure you want to enable this feature?": "この機能を有効にしてもよろしいですか?", + "No new shortcuts were found during the scan.": "スキャン中に新しいショートカットは見つかりませんでした。", + "How to add packages to a bundle": "バンドルにパッケージを追加する方法", + "In order to add packages to a bundle, you will need to: ": "バンドルにパッケージを追加するには、次の手順が必要です。", + "1. Navigate to the \"{0}\" or \"{1}\" page.": "1.「{0}」または「{1}」ページに移動します。", + "2. Locate the package(s) you want to add to the bundle, and select their leftmost checkbox.": "2.バンドルに追加するパッケージを探して、左端のチェックボックスをオンにします。", + "3. When the packages you want to add to the bundle are selected, find and click the option \"{0}\" on the toolbar.": "3.バンドルに追加するパッケージを選択したら、ツールバーでオプション「{0}」を見つけてクリックします。", + "4. Your packages will have been added to the bundle. You can continue adding packages, or export the bundle.": "4.パッケージがバンドルに追加されます。\nパッケージの追加を続けるか、バンドルをエクスポートしてください。", + "Which backup do you want to open?": "どのバックアップを開きますか?", + "Select the backup you want to open. Later, you will be able to review which packages you want to install.": "開きたいバックアップを選択してください。後で、復元したいパッケージ/プログラムを確認できます。", + "There are ongoing operations. Quitting UniGetUI may cause them to fail. Do you want to continue?": "パッケージ操作が実行中です。UniGetUIを終了させると、パッケージ操作が失敗する可能性があります。本当によろしいですか?", + "UniGetUI or some of its components are missing or corrupt.": "UniGetUIまたはそのコンポーネントの一部が見つからないか破損しています。", + "It is strongly recommended to reinstall UniGetUI to adress the situation.": "この状況を解決するため、UniGetUIの再インストールを強くおすすめします。", + "Refer to the UniGetUI Logs to get more details regarding the affected file(s)": "影響を受けたファイルに関する詳細を確認するには、UniGetUI ログを参照してください。", + "Integrity checks can be disabled from the Experimental Settings": "整合性チェックは「実験的設定」から無効にできます。", + "Repair UniGetUI": "UniGetUIの修復", + "Live output": "ライブ出力", + "This package bundle had some settings that are potentially dangerous, and may be ignored by default.": "このパッケージバンドルには潜在的に危険な設定がいくつかあり、デフォルトでは無視される可能性があります。", + "Entries that show in YELLOW will be IGNORED.": "黄色で表示されるエントリは無視されます。", + "Entries that show in RED will be IMPORTED.": "赤で表示されるエントリはインポートされます。", + "You can change this behavior on UniGetUI security settings.": "この動作はUniGetUIのセキュリティ設定で変更できます。", + "Open UniGetUI security settings": "UniGetUIのセキュリティ設定を開く", + "Should you modify the security settings, you will need to open the bundle again for the changes to take effect.": "セキュリティ設定を変更した場合、変更を反映させるためには、再度バンドルを開く必要があります。", + "Details of the report:": "レポートの詳細:", + "Are you sure you want to create a new package bundle? ": "新しいパッケージバンドルを作成しますか?", + "Any unsaved changes will be lost": "保存されていないすべての変更は失われます", + "Warning!": "警告!", + "For security reasons, custom command-line arguments are disabled by default. Go to UniGetUI security settings to change this. ": "セキュリティ上の理由から、カスタムコマンドライン引数はデフォルトで無効になっています。これを変更するには、UniGetUIのセキュリティ設定に移動してください。", + "Change default options": "デフォルト設定を開く", + "Ignore future updates for this package": "将来のアップデートを除外", + "For security reasons, pre-operation and post-operation scripts are disabled by default. Go to UniGetUI security settings to change this. ": "セキュリティ上の理由から、パッケージ操作前およびパッケージ操作後のスクリプトはデフォルトで無効になっています。これを変更するには、UniGetUIのセキュリティ設定にアクセスしてください。", + "You can define the commands that will be run before or after this package is installed, updated or uninstalled. They will be run on a command prompt, so CMD scripts will work here.": "インストール・アップデート・アンインストール時の前後に実行するコマンドを設定できます。コマンドはコマンドプロンプトで実行されるため、CMD スクリプトを使用できます。", + "Change this and unlock": "この設定を変更する", + "{0} Install options are currently locked because {0} follows the default install options.": "{0}にはデフォルトの詳細設定が適用されているため、{0}の詳細設定は個別に変更できません。", + "Unset or unknown": "未設定または不明", + "This package has no screenshots or is missing the icon? Contrbute to UniGetUI by adding the missing icons and screenshots to our open, public database.": "アイコンやスクリーンショットが未登録です。オープンデータベースにデータを追加して、UniGetUIの改善にご協力ください。", + "Become a contributor": "コミュニティに貢献する", + "Update to {0} available": "{0}へのアップデートが利用可能です", + "Reinstall": "再インストール", + "Installer not available": "インストーラーが利用できません", + "Version:": "バージョン:", + "UniGetUI Version {0}": "UniGetUIバージョン{0}", + "Performing backup, please wait...": "バックアップ中です。お待ち下さい…", + "An error occurred while logging in: ": "ログイン中にエラーが発生しました:", + "Fetching available backups...": "利用可能なバックアップを取得しています...", + "Done!": "完了!", + "The cloud backup has been loaded successfully.": "クラウドバックアップが正常に読み込まれました。", + "An error occurred while loading a backup: ": "バックアップの読み込み中にエラーが発生しました:", + "Backing up packages to GitHub Gist...": "パッケージをGitHub Gistにバックアップしています...", + "Backup Successful": "バックアップ成功", + "The cloud backup completed successfully.": "クラウドバックアップが正常に完了しました。", + "Could not back up packages to GitHub Gist: ": "パッケージをGitHub Gistにバックアップできませんでした:", + "It is not guaranteed that the provided credentials will be stored safely, so you may as well not use the credentials of your bank account": "入力された認証情報が安全に保存される保証はありません。そのため、銀行口座のパスワードなど、極めて重要な認証情報は入力しないことを強く推奨します。", + "Enable the automatic WinGet troubleshooter": "自動WinGetトラブルシューティングツールを有効化", + "Add updates that fail with a 'no applicable update found' to the ignored updates list": "「適用可能な更新が見つかりません」というエラーで失敗したパッケージをアップデート対象から除外する", + "Invalid selection": "無効な選択", + "No package was selected": "パッケージが選択されていません", + "More than 1 package was selected": "複数のパッケージが選択されました", + "List": "一覧", + "Grid": "グリッド", + "Icons": "アイコン", + "\"{0}\" is a local package and does not have available details": "「{0}」はローカルパッケージであり、利用可能な詳細がありません", + "\"{0}\" is a local package and is not compatible with this feature": "「{0}」はローカルパッケージであり、この機能と互換性がありません", + "Add packages to bundle": "バンドルにパッケージを追加する", + "Preparing packages, please wait...": "パッケージを準備しています。お待ち下さい…", + "Loading packages, please wait...": "パッケージを読み込んでいます。お待ち下さい…", + "Saving packages, please wait...": "パッケージを保存しています。お待ち下さい…", + "The bundle was created successfully on {0}": "バンドルは{0}に正常に作成されました", + "User profile": "ユーザープロファイル", + "Error": "エラー", + "Log in failed: ": "ログインに失敗しました:", + "Log out failed: ": "ログアウトに失敗しました:", + "Package backup settings": "パッケージ一覧のバックアップ設定", + "Manage UniGetUI autostart behaviour from the Settings app": "設定アプリからUniGetUIの自動起動の挙動を変更", + "Choose how many operations shoulds be performed in parallel": "同時に実行するパッケージ操作数", + "Something went wrong while launching the updater.": "アップデーターの起動中に問題が発生しました。", + "Please try again later": "あとでもう一度お試しください。", + "Show the release notes after UniGetUI is updated": "UniGetUIの更新後にリリースノートを表示する" +} diff --git a/src/Languages/lang_ka.json b/src/Languages/lang_ka.json new file mode 100644 index 0000000..733e6f9 --- /dev/null +++ b/src/Languages/lang_ka.json @@ -0,0 +1,850 @@ +{ + "{0} of {1} operations completed": "{1}-დან {0} ოპერაცია დასრულდა", + "{0} is now {1}": "{0} ახლა არის {1}", + "Enabled": "ჩართული", + "Disabled": "გამორთული", + "Privacy": "კონფიდენციალურობა", + "Hide my username from the logs": "მომხმარებლის სახელის დამალვა ჟურნალებიდან", + "Replaces your username with **** in the logs. Restart UniGetUI to also hide it from already-recorded entries.": "ჩაანაცვლებს თქვენს მომხმარებლის სახელს **** სიმბოლოებით ჟურნალებში. გადატვირთეთ UniGetUI, რომ ის უკვე ჩაწერილ ჩანაწერებშიც დაიმალოს.", + "Your last update attempt did not complete.": "თქვენი ბოლო განახლების მცდელობა არ დასრულებულა.", + "UniGetUI could not confirm whether the update succeeded. Open the log to see what happened.": "UniGetUI-მ ვერ დაადასტურა, წარმატებით დასრულდა თუ არა განახლება. გახსენით ჟურნალი, რომ ნახოთ, რა მოხდა.", + "View log": "ჟურნალის ნახვა", + "The installer reported success but did not restart UniGetUI.": "ინსტალატორმა წარმატება დააფიქსირა, მაგრამ UniGetUI ხელახლა არ გაუშვა.", + "The installer failed to initialize.": "ინსტალატორის ინიციალიზაცია ვერ მოხერხდა.", + "Setup was canceled before installation began.": "დაყენება გაუქმდა ინსტალაციის დაწყებამდე.", + "A fatal error occurred during the preparation phase.": "მომზადების ეტაპზე ფატალური შეცდომა მოხდა.", + "A fatal error occurred during installation.": "ინსტალაციისას ფატალური შეცდომა მოხდა.", + "Installation was canceled while in progress.": "ინსტალაცია მიმდინარეობისას გაუქმდა.", + "The installer was terminated by another process.": "ინსტალატორი სხვა პროცესმა შეწყვიტა.", + "The preparation phase determined the installation cannot proceed.": "მომზადების ეტაპზე დადგინდა, რომ ინსტალაცია ვერ გაგრძელდება.", + "The installer could not start. UniGetUI may already be running, or you do not have permission to install.": "ინსტალატორის გაშვება ვერ მოხერხდა. შესაძლოა UniGetUI უკვე გაშვებულია, ან ინსტალაციის ნებართვა არ გაქვთ.", + "Unexpected installer error.": "ინსტალატორის მოულოდნელი შეცდომა.", + "We are checking for updates.": "ვამოწმებთ განახლებებს.", + "Please wait": "გთხოვთ მოიცადოთ", + "Great! You are on the latest version.": "მშვენიერი! თქვენ უახლეს ვერსიაზე ხართ.", + "There are no new UniGetUI versions to be installed": "არ არის UniGetUI-ის ახალი ვერსიები", + "UniGetUI version {0} is being downloaded.": "მიმდინარეობს UniGetUI-ის {0} ვერსიის ჩამოტვირთვა.", + "This may take a minute or two": "ამას ერთი-ორი წუთი დაჭირდება", + "The installer authenticity could not be verified.": "ვერ გადამოწმდა ინსტალატორის აუთენტურობა", + "The update process has been aborted.": "განახლების პროცესი შეწყვეტილ იქნა", + "Auto-update is not yet available on this platform.": "ავტომატური განახლება ამ პლატფორმაზე ჯერ ხელმისაწვდომი არ არის.", + "Please update UniGetUI manually.": "გთხოვთ, UniGetUI ხელით განაახლოთ.", + "An error occurred when checking for updates: ": "შეცდომა დაფიქსირდა განახლებების შემოწმებისას:", + "The updater could not be launched.": "განახლების პროგრამის გაშვება ვერ მოხერხდა.", + "The operating system did not start the installer process.": "ოპერაციულმა სისტემამ ინსტალატორის პროცესი არ გაუშვა.", + "UniGetUI is being updated...": "მიმდინარეობს UniGetUI-ის განახლება...", + "Update installed.": "განახლება დაინსტალირდა.", + "UniGetUI was updated successfully, but this running copy was not replaced. This usually means you are running a development build. Close this copy and start the newly-installed version to finish.": "UniGetUI წარმატებით განახლდა, მაგრამ ამჟამად გაშვებული ასლი არ ჩანაცვლდა. ეს ჩვეულებრივ ნიშნავს, რომ დეველოპერულ build-ს იყენებთ. დასასრულებლად დახურეთ ეს ასლი და გაუშვით ახლად დაინსტალირებული ვერსია.", + "The update could not be applied.": "განახლების გამოყენება ვერ მოხერხდა.", + "Installer exit code {0}: {1}": "ინსტალატორის გამოსვლის კოდი {0}: {1}", + "Update cancelled.": "განახლება გაუქმდა.", + "Authentication was cancelled.": "ავთენტიფიკაცია გაუქმდა.", + "Installer exit code {0}": "ინსტალატორის გამოსვლის კოდი {0}", + "Operation in progress": "მიმდინარეობს ოპერაცია", + "Please wait...": "გთხოვთ მოიცადოთ...", + "Success!": "წარმატება!", + "Failed": "ჩაიშალა", + "An error occurred while processing this package": "შეცდომა დაფიქსირდა ამ პაკეტის დამუშავებისას", + "Installer": "ინსტალატორი", + "Executable": "შესრულებადი ფაილი", + "MSI": "MSI", + "Compressed file": "შეკუმშული ფაილი", + "MSIX": "MSIX", + "WinGet was repaired successfully": "WinGet წარმატებით შეკეთდა", + "It is recommended to restart UniGetUI after WinGet has been repaired": "რეკომენდებულია თავიდან გაუშვათ UniGetUI მას შემდეგ რაც შეკეთდა WinGet ", + "WinGet could not be repaired": "შეუძლებელია WinGet-ის შეკეთება", + "An unexpected issue occurred while attempting to repair WinGet. Please try again later": "გაუთვალისწინებელი პრობლემა დაფიქსირდა WinGet-ის შეკეთებისას. გთხოვთ მოგვიანებით ცადეთ", + "Log in to enable cloud backup": "ღრუბლოვანი ბექაფისთვის საჭიროა შესვლა", + "Backup Failed": "ბექაფი ჩაიშალა", + "Downloading backup...": "ბექაფის ჩამოტვირთვა...", + "An update was found!": "ნაპოვნია განახლება!", + "{0} can be updated to version {1}": "{0} შესაძლებელია განახლდეს {1} ვერსიამდე", + "Updates found!": "ნაპოვნია განახლებები!", + "{0} packages can be updated": "შესაძლებელი {0} პაკეტის განახლება", + "{0} is being updated to version {1}": "{0} ახლდება {1} ვერსიამდე", + "{0} packages are being updated": "მიმდინარეობს {0} პაკეტის განახლება", + "You have currently version {0} installed": "თქვენი მიმდინარე ვერსიაა {0}", + "Desktop shortcut created": "შეიქმნა მალსახმობი სამუშაო მაგიდაზე", + "UniGetUI has detected a new desktop shortcut that can be deleted automatically.": "UniGetUI-მ აღმოაჩინა დესკტოპის ახალი მალსახმობი, რომელიც შეიძლება ავტომატურად წაიშალოს.", + "{0} desktop shortcuts created": "{0} სამუშაო მაგიდაზე შეიქმნა მალსახმობი", + "UniGetUI has detected {0} new desktop shortcuts that can be deleted automatically.": "UniGetUI-მ აღმოაჩინა {0} ახალი დესკტოპის მალსახმობები, რომლებიც შეიძლება ავტომატურად წაიშალოს.", + "Attention required": "საჭიროა ყურადღება", + "Restart required": "საჭიროა გადატვირთვა", + "1 update is available": "ხელმისაწვდომია 1 განახლება", + "{0} updates are available": "ხელმისაწვდომა {0} განახლება", + "Everything is up to date": "ყველაფერი განახლებულია", + "Discover Packages": "აღმოაჩინეთ პაკეტები", + "Available Updates": "ხელმისაწვდომი განახლებები", + "Installed Packages": "დაყენებული პაკეტები", + "UniGetUI Version {0} by Devolutions": "UniGetUI ვერსია {0} Devolutions-ისგან", + "Show UniGetUI": "UniGetUI-ის ჩვენება", + "Quit": "გასვლა", + "Are you sure?": "დარწმუნებული ხართ?", + "Do you really want to uninstall {0}?": "ნამდვილად გსურთ წაშალოთ {0}?", + "Do you really want to uninstall the following {0} packages?": "ნამდვილად გსურთ წაშალოთ შემდეგი პაკეტები {0} ?", + "No": "არა", + "Yes": "კი", + "Partial": "ნაწილობრივ", + "View on UniGetUI": "UniGetUI-ში ნახვა", + "Update": "განახლება", + "Open UniGetUI": "UniGetUI-ის გახსნა", + "Update all": "ყველას განახლება", + "Update now": "ახლა განახლება", + "Installer host changed since the installed version.\n": "ინსტალატორის ჰოსტი შეიცვალა დაინსტალირებულ ვერსიასთან შედარებით.\n", + "This package is on the queue": "პაკეტი რიგშია", + "installing": "ინსტალირდება", + "updating": "ახლდება", + "uninstalling": "დეინსტალაცია", + "installed": "დაინსტალირდა", + "Retry": "ხელახლა ცდა", + "Install": "ინსტალაცია", + "Uninstall": "წაშლა", + "Open": "გახსნა", + "Operation profile:": "ოპერაციის პროფილი:", + "Follow the default options when installing, upgrading or uninstalling this package": "მიყვეით ანგულისხმევ პარამეტრებს ამ პაკეტის ინსტალაციისას, განახლებისას ან დეინსტალაციისას", + "The following settings will be applied each time this package is installed, updated or removed.": "შემდეგი პარამეტრები იქნება გამოყენები ყოველ ჯერზე ამ პაკეტის დაყენებისას, განახლებისას ან წაშლისას.", + "Version to install:": "დასაყენებელი ვერსია:", + "Architecture to install:": "დასაინსტალირებელი არქიტექტურა:", + "Installation scope:": "ინსტალაციის ფარგლები:", + "Install location:": "ინსტალაციის ლოკაცია:", + "Select": "შერჩევა", + "Reset": "რესეტი", + "Custom install arguments:": "მორგებული ინსტალაციის არგუმენტები:", + "Custom update arguments:": "მორგებული განახლების არგუმენტები:", + "Custom uninstall arguments:": "მორგებული დეინსტალაციის არგუმენტები:", + "Pre-install command:": "პრე ინსტალაციის ბრძანება:", + "Post-install command:": "პოსტ ინსტალაციის ბრძანება:", + "Abort install if pre-install command fails": "ინსტალაციის შეწყვეტა პრე-ინსტალაციის ბრძანების ჩაშლისას", + "Pre-update command:": "პრე განახლების ბრძანება:", + "Post-update command:": "პოსტ განახლების ბრძანება:", + "Abort update if pre-update command fails": "განახლების შეწყვეტა პრე-განახლების ბრძანების ჩაშლისას", + "Pre-uninstall command:": "პრე დეინსტალაციის ბრძანება:", + "Post-uninstall command:": "პოსტ დეინსტალაციის ბრძანება:", + "Abort uninstall if pre-uninstall command fails": "დეინსტალაციის შეწყვეტა პრე-დეინსტალაციის ბრძანების ჩაშლისას", + "Command-line to run:": "ბრძანების ზოლში გაეშვება:", + "Save and close": "შენახვა და დახურვა", + "General": "ზოგადი", + "Architecture & Location": "არქიტექტურა და მდებარეობა", + "Command-line": "ბრძანების ზოლი", + "Close apps": "აპების დახურვა", + "Pre/Post install": "ინსტალაციამდე/შემდეგ", + "Select the processes that should be closed before this package is installed, updated or uninstalled.": "შეარჩიეთ პროცესები, რომლებიც უნდა დაიხუროს მანამ სანამ ეს პაკეტი დაინსტალირდება, განახლდება ან დეინსტალირდება.", + "Write here the process names here, separated by commas (,)": "აქ შეიყვანეთ პროცესების სახელები, გამოყავით მძიმეებით (,)", + "Try to kill the processes that refuse to close when requested to": "პროცესების ძალისმიერად გათიშვის ცდა, რომლებიც არ ითიშება მოთხოვნისას", + "Run as admin": "ადმინისტრატორით გაშვება", + "Interactive installation": "ინტერაქტიული ინსტალაცია", + "Skip hash check": "ჰეშის შემოწმების გამოტოვება", + "Uninstall previous versions when updated": "განახლებისას წინა ვერსიების დეინსტალაცია", + "Skip minor updates for this package": "მინორული განახლებების გამოტოვება ამ პაკეტისთვის", + "Automatically update this package": "ამ პაკეტის ავტომატური განახლება", + "{0} installation options": "{0} ინსტალაციის პარამეტრები", + "Latest": "უახლესი", + "PreRelease": "პრერელიზი", + "Default": "ნაგულისხმევი", + "Manage ignored updates": "იგნორირებული განახლებების მართვა", + "The packages listed here won't be taken in account when checking for updates. Double-click them or click the button on their right to stop ignoring their updates.": "აქ ჩამოთვლილი პაკეტები არ იქნება გათვალისწინებული განახლებების შემოწმებისას. ორჯერ დაწკაპეთ მათზე ან ღილაკზე მარჯვნივ რომ შეტყვიტოთ მათი განახლებების იგნორირება.", + "Reset list": "სიის რესეტი", + "Do you really want to reset the ignored updates list? This action cannot be reverted": "ნამდვილად გსურთ იგნორირებული განახლებების სიის განულება? ეს მოქმედება ვერ გაუქმდება", + "No ignored updates": "იგნორირებული განახლებები არ არის", + "Package Name": "პაკეტის სახელი", + "Package ID": "პაკეტის ID", + "Ignored version": "იგნორირებული ვერსია", + "New version": "ახალი ვერსია", + "Source": "წყარო", + "All versions": "ყველა ვერსია", + "Unknown": "უცნობი", + "Up to date": "განახლებულია", + "Package {name} from {manager}": "პაკეტი {name} {manager}-დან", + "Remove {0} from ignored updates": "{0}-ის წაშლა იგნორირებული განახლებებიდან", + "Cancel": "გაუქმება", + "Administrator privileges": "ადმინისტრატორის პრივილეგიები", + "This operation is running with administrator privileges.": "ეს ოპერაცია ადმინისტრატორის პრივილეგიებით ეშვება.", + "Interactive operation": "ინტერაქტიული ოპერაცია", + "This operation is running interactively.": "ეს ოპერაცია ინტერაქტიულად ეშვება.", + "You will likely need to interact with the installer.": "თვენ შესაძლოა ინსტალატორთან ინტერაქცია მოგიწიოთ", + "Integrity checks skipped": "ინტეგრულობის შემოწმება გამოტოვებულია", + "Integrity checks will not be performed during this operation.": "ამ ოპერაციის დროს ინტეგრულობის შემოწმება არ შესრულდება.", + "Proceed at your own risk.": "გააგრძელეთ საკუთარი რისკის ფასად.", + "Close": "დახურვა", + "Loading...": "ჩატვირთვა...", + "Installer SHA256": "ინსტალატორის SHA256", + "Homepage": "სათაო გვერდი", + "Author": "ავტორი", + "Publisher": "გამომცემი", + "License": "ლიცენზია", + "Manifest": "მანიფესტი", + "Installer Type": "ინსტალატორის ტიპი", + "Size": "ზომა", + "Installer URL": "ინსტალატორის URL", + "Last updated:": "ბოლო განახლება:", + "Release notes URL": "რელიზის ჩანაწერების URL", + "Package details": "პაკეტის დეტალები", + "Dependencies:": "დამოკიდებულებები:", + "Release notes": "რელიზის ჩანაწერები", + "Screenshots": "ეკრანის სურათები", + "This package has no screenshots or is missing the icon? Contribute to UniGetUI by adding the missing icons and screenshots to our open, public database.": "ამ პაკეტს ეკრანის სურათები არ აქვს ან ხატულა აკლია? წვლილი შეიტანეთ UniGetUI-ში, დაამატეთ დაკარგული ხატულები და ეკრანის სურათები ჩვენს ღია, საჯარო მონაცემთა ბაზაში.", + "Version": "ვერსია", + "Install as administrator": "ადმინისტრატორის უფლებებით ინსტალაცია", + "Update to version {0}": "განახლება {0} ვერსიამდე", + "Installed Version": "დაყენებული პაკეტები", + "Update as administrator": "ადმინისტრატორით განახლება", + "Interactive update": "ინტერაქტიული განახლება", + "Uninstall as administrator": "დეინსტალაცია ადმინისტრატორის უფლებებით", + "Interactive uninstall": "ინტერაქტიული წაშლა", + "Uninstall and remove data": "დეინსტალაცია და მონაცემების წაშლა", + "Not available": "მიუწვდომელია", + "Installer SHA512": "ინსტალატორის SHA256", + "Unknown size": "უცნობი ზომა", + "No dependencies specified": "არ არის მითითებული დამოკიდებულებები", + "mandatory": "სავალდებულო", + "optional": "არასავალდებულო", + "UniGetUI {0} is ready to be installed.": "UniGetUI {0} მზად არის ინსტალაციისთვის.", + "The update process will start after closing UniGetUI": "განახლების პროცესი დაიწყება UniGetUI-ის დახურვის შემდეგ", + "UniGetUI has been ran as administrator, which is not recommended. When running UniGetUI as administrator, EVERY operation launched from UniGetUI will have administrator privileges. You can still use the program, but we highly recommend not running UniGetUI with administrator privileges.": "UniGetUI გაშვებულია ადმინისტრატორის უფლებებით, რაც რეკომენდებული არ არის. UniGetUI-ის ადმინისტრატორით გაშვებისას, UniGetUI-დან დაწყებულ ყველა ოპერაციას ადმინისტრატორის უფლებები ექნება. პროგრამის გამოყენება მაინც შეგიძლიათ, მაგრამ მკაცრად გირჩევთ, UniGetUI ადმინისტრატორის უფლებებით არ გაუშვათ.", + "Share anonymous usage data": "ანონიმური მოხმარების მონაცემების გაზიარება", + "UniGetUI collects anonymous usage data in order to improve the user experience.": "UniGetUI აგროვებს ანონიმური გამოყენების მონაცემებს მომხმარებლის გამოცდილების გასაუმჯობესებლად.", + "Accept": "მიღება", + "Software Updates": "პროგრამების განახლებები", + "Package Bundles": "პაკეტების კრებულები", + "Settings": "პარამეტრები", + "Package Managers": "პაკეტების მენეჯერები", + "UniGetUI Log": "UniGetUI-ის ჟურნალი", + "Package Manager logs": "პაკეტების მენეჯერის ჟურნალები", + "Operation history": "ოპერაციის ისტორია", + "Help": "დახმარება", + "UniGetUI": "UniGetUI", + "You have installed UniGetUI Version {0}": "თქვენ დააყენეთ UniGetUI-ის {0} ვერსია", + "Disclaimer": "პასუხისმგებლობის უარყოფა", + "UniGetUI is developed by Devolutions and is not affiliated with any of the compatible package managers.": "UniGetUI შემუშავებულია Devolutions-ის მიერ და არ არის დაკავშირებული რომელიმე თავსებად პაკეტების მენეჯერთან.", + "UniGetUI wouldn't have been possible without the help of the contributors. Thank you all 🥳": "UniGetUI-ის არსებობა შეუძლებელი იქნებოდა შემომწირველების დახმარების გარეშე. მადლობა თქვენ 🥳", + "UniGetUI uses the following libraries. Without them, UniGetUI wouldn't have been possible.": "UniGetUI იყენებს შემდეგ ბიბლიოთეკებს. მათ გარეშე UniGetUI-ს არსებობა შეუძლებელი იქნებოდა.", + "{0} homepage": "{0} მთავარი გვერდი", + "UniGetUI has been translated to more than 40 languages thanks to the volunteer translators. Thank you 🤝": "UniGetUI თარგმნილია 40-ზე მეტ ენაზე მოხალისეების მიერ. მადლობა 🤝", + "Verbose": "უფრო ინფორმატიული", + "1 - Errors": "1 - შეცდომა", + "2 - Warnings": "2 - გაფრთხილება", + "3 - Information (less)": "3 - ინფორმაცია (ნაკლები)", + "4 - Information (more)": "4 - ინფორმაცია (მეტი)", + "5 - information (debug)": "5 - ინფორმაცია (დებაგი)", + "Warning": "გაფრთხილება", + "The following settings may pose a security risk, hence they are disabled by default.": "შემდეგი პარამეტრები შეიცავს შესაძლო უსაფრთხოების რისკებს, ამიტომაც ისინი გამორთულია ნაგულისხმევად.", + "Enable the settings below if and only if you fully understand what they do, and the implications they may have.": "ჩართეთ ქვემოთ მოცემული პარამეტრები მხოლოდ იმ შემთხვევაში, თუ სრულად გესმით მათი მოქმედების პრინციპი, ასევე მათი შესაძლო შედეგები და საფრთხეები.", + "The settings will list, in their descriptions, the potential security issues they may have.": "აღწერებში იქნება ამ პარამეტრების სია და მათი პოტენციური უსაფრთხოების პრობლემები.", + "The backup will include the complete list of the installed packages and their installation options. Ignored updates and skipped versions will also be saved.": "ბექაფი შეიცავდეს იქნება დაყენებული პაკეტების სრულ სიას და მათი ინსტალაციის პარამეტრებს. იგნორირებული განახლებები და გამოტივებული ვერსიებიც კი შენახული იქნება.", + "The backup will NOT include any binary file nor any program's saved data.": "ბექაფში არ იქნება არანაირი ბინარული ფაილი და არც პროგრამის მიერ შენახული მონაცემები.", + "The size of the backup is estimated to be less than 1MB.": "ბექაფის მოსალოდნელი ზომა 1 მბ-ზე ნაკლებია", + "The backup will be performed after login.": "ბექაფი სისტემაში შესვლის შემდეგ შესრულდება", + "{pcName} installed packages": "{pcName} დაყენებული პაკეტები", + "Current status: Not logged in": "მიმდინარე სტატუსი: არ არის შესული", + "You are logged in as {0} (@{1})": "თქვენ შესული ხართ როგორც {0} (@{1})", + "Nice! Backups will be uploaded to a private gist on your account": "მშვენიერი! ბექაფები აიტვირთება პრივატულ gist-ში თქვენს ანგარიშზე", + "Select backup": "შეარჩიეთ ბექაფი", + "Settings imported from {0}": "პარამეტრები იმპორტირებულია {0}-დან", + "UniGetUI Settings": "UniGetUI-ის პარამეტრები", + "Settings exported to {0}": "პარამეტრები ექსპორტირებულია {0}-ში", + "UniGetUI settings were reset": "UniGetUI-ის პარამეტრები დარესეტდა", + "Allow pre-release versions": "პრერელიზ ვერსიების დაშვება", + "Apply": "გამოყენება", + "For security reasons, custom command-line arguments are disabled by default. Go to UniGetUI security settings to change this.": "უსაფრთხოების მიზეზებიდან გამომდინარე, მორგებული ბრძანების სტრიქონის არგუმენტები ნაგულისხმევად გამორთულია. ამის შესაცვლელად გადადით UniGetUI-ის უსაფრთხოების პარამეტრებში.", + "Go to UniGetUI security settings": "UniGetUI-ის უსაფრთხოების პარამეტრებზე გადასვლა", + "The following options will be applied by default each time a {0} package is installed, upgraded or uninstalled.": "შემდეგი პარამეტრები იქნება გამოყენებული ნაგულისხმევად ყოველ ჯერზე {0} პაკეტის ინსტალაციისას, განახლებისას ან დეინსტალაციისას.", + "Package's default": "პაკეტის ნაგულისხმევი", + "Install location can't be changed for {0} packages": "ინსტალაციის ლოკაცია ვერ შეიცვლება {0} პაკეტებისთვის", + "The local icon cache currently takes {0} MB": "ლოკალური ხატულების ქეში ახლა იკავებს {0} მბ-ს", + "Username": "მომხმარებლის სახელი", + "Password": "პაროლი", + "Credentials": "ანგარიშის მონაცემები", + "It is not guaranteed that the provided credentials will be stored safely": "არ არის გარანტირებული, რომ მითითებული ავტორიზაციის მონაცემები უსაფრთხოდ შეინახება", + "Partially": "ნაწილობრივ", + "Package manager": "პაკეტების მმართველი", + "Compatible with proxy": "თავსებადია პროქსისთან", + "Compatible with authentication": "თავსებადია აუთენტიფიკაციასთან", + "Proxy compatibility table": "პროქსის თავსებადობის ცხრილი", + "{0} settings": "{0}-ის პარამეტრები", + "{0} status": "{0} სტატუსი", + "Default installation options for {0} packages": "ნაგულისმევი ინსტალაციის პარამერები {0} პაკეტებისთვის", + "Expand version": "ვერსიის გაშლა", + "The executable file for {0} was not found": "ვერ მოიძებნა {0}-ის გამშვები ფაილი", + "{pm} is disabled": "{pm} გამორთულია", + "Enable it to install packages from {pm}.": "პაკეტების {pm}-დან ინსტალაციის ჩართვა.", + "{pm} is enabled and ready to go": "{pm} ჩართულია და მზად არის გასაშვებად", + "{pm} version:": "{pm} ვერსია:", + "{pm} was not found!": "{pm} ვერ იქნა ნაპოვნი!", + "You may need to install {pm} in order to use it with UniGetUI.": "თქვენ შესაძლოა დაგჭირდეთ {pm} იმისთვის, რომ UniGetUI-თ ისარგებლოთ.", + "Scoop Installer - UniGetUI": "Scoop ინსტალატორი - UniGetUI", + "Scoop Uninstaller - UniGetUI": "Scoop დეინსტალატორი - UniGetUI", + "Clearing Scoop cache - UniGetUI": "Scoop-ის ქეშის გაწმენდა - UniGetUI", + "Restart UniGetUI to fully apply changes": "ცვლილებების სრულად ასამოქმედებლად გადატვირთეთ UniGetUI", + "Restart UniGetUI": "UniGetUI-ის გადატვირთვა", + "Manage {0} sources": "{0} წყაროების მართვა", + "Add source": "წყაროს დამატება", + "Add": "დამატება", + "Source name": "წყაროს სახელი", + "Source URL": "წყაროს URL", + "Other": "სხვა", + "No minimum age": "მინიმალური ასაკის გარეშე", + "1 day": "1 დღე", + "{0} days": "{0} დღე", + "Custom...": "მორგებული...", + "{0} minutes": "{0} წუთი", + "1 hour": "1 საათი", + "{0} hours": "{0} საათი", + "1 week": "1 კვირა", + "Supports release dates": "მხარს უჭერს რელიზის თარიღებს", + "Release date support per package manager": "რელიზის თარიღების მხარდაჭერა პაკეტების მენეჯერების მიხედვით", + "Search for packages": "პაკეტების ძიება", + "Local": "ლოკალური", + "OK": "OK", + "Last checked: {0}": "ბოლო შემოწმება: {0}", + "{0} packages were found, {1} of which match the specified filters.": "ნაპოვნია {0} პაკეტი, {1} შეესაბამება მითითებულ ფილტრებს.", + "{0} selected": "{0} მონიშნულია", + "(Last checked: {0})": "(ბოლო შემოწმება: {0})", + "All packages selected": "ყველა პაკეტი მონიშნულია", + "Package selection cleared": "პაკეტების მონიშვნა გაწმენდილია", + "{0}: {1}": "{0}: {1}", + "More info": "მეტი ინფო", + "GitHub account": "GitHub ანგარიში", + "Log in with GitHub to enable cloud package backup.": "შედით GitHub-ით, რომ ჩართოთ პაკეტების ღრუბლოვანი ბექაფი", + "More details": "მეტი დეტალი", + "Log in": "შესვლა", + "If you have cloud backup enabled, it will be saved as a GitHub Gist on this account": "თუ გაქვთ ღრუბლოვანი ბექაფი ჩართული ის შეინახება GitHub Gist-ის სახით ამ ანგარიშზე", + "Log out": "გამოსვლა", + "About UniGetUI": "UniGetUI-ის შესახებ", + "About": "შესახებ", + "Third-party licenses": "მესამე-მხარის ლიცენზიები", + "Contributors": "კონტრიბუტორები", + "Translators": "მთარგმნელები", + "Bundle security report": "კრებულის უსაფრთხოების რეპორტი", + "The bundle contained restricted content": "კრებული შეიცავდა შეზღუდულ შინაარსს", + "UniGetUI – Crash Report": "UniGetUI – ავარიის ანგარიში", + "UniGetUI has crashed": "UniGetUI-ს ავარია მოხდა", + "Help us fix this by sending a crash report to Devolutions. All fields below are optional.": "დაგვეხმარეთ ამის გამოსწორებაში ავარიის ანგარიშის Devolutions-ში გაგზავნით. ყველა ველი ქვემოთ არასავალდებულოა.", + "Email (optional)": "ელფოსტა (არასავალდებულო)", + "your@email.com": "your@email.com", + "Additional details (optional)": "დამატებითი დეტალები (არასავალდებულო)", + "Describe what you were doing when the crash occurred…": "აღწერეთ რას აკეთებდით ავარიის მომენტში…", + "Crash report": "ავარიის ანგარიში", + "Don't Send": "არ გაგზავნო", + "Send Report": "ანგარიშის გაგზავნა", + "Sending…": "იგზავნება…", + "Unsaved changes": "შეუნახავი ცვლილებები", + "You have unsaved changes in the current bundle. Do you want to discard them?": "მიმდინარე კრებულში გაქვთ შეუნახავი ცვლილებები. გსურთ მათი გაუქმება?", + "Discard changes": "ცვლილებების გაუქმება", + "Integrity violation": "ინტეგრულობის დარღვევა", + "UniGetUI or some of its components are missing or corrupt. It is strongly recommended to reinstall UniGetUI to adress the situation.": "UniGetUI ან მისი ზოგიერთი კომპონენტი აკლია ან დაზიანებულია. მდგომარეობის გამოსასწორებლად მკაცრად რეკომენდებულია UniGetUI-ის ხელახლა დაყენება.", + "• Refer to the UniGetUI Logs to get more details regarding the affected file(s)": "• ჩახედეთ UniGetUI-ის ჟურნალში, რომ გაიგოთ მეტი ინფორმაცია მონაწილე ფაილ(ებ)ის შესახებ.", + "• Integrity checks can be disabled from the Experimental Settings": "• ინტეგრულების შემოწმება შეგიძლიათ გამორთოთ ექსპერიმენტული პარამეტრებიდან", + "Manage shortcuts": "მალსახმობების მართვა", + "UniGetUI has detected the following desktop shortcuts which can be removed automatically on future upgrades": "UniGetUI-მ აღმოაჩინა შემდეგი დესკტოპის მალსახმობები, რომლებიც შეიძლება ავტომატურად წაიშალოს მომავალი განახლებებისას", + "Do you really want to reset this list? This action cannot be reverted.": "რეალურად გსურთ ამ სიის დარესეტება? ეს მოქმედება უკან არ ბრუნდება.", + "Desktop shortcuts list": "სამუშაო მაგიდის მალსახმობების სია", + "Open in explorer": "ექსპლორერში გახსნა", + "Remove from list": "სიიდან წაშლა", + "When new shortcuts are detected, delete them automatically instead of showing this dialog.": "ახალი მალსახმობების აღმოჩენისას, ამ დიალოგის ჩვენების ნაცვლად ავტომატურად წაშალეთ ისინი.", + "Not right now": "ახლა არა", + "Missing dependency": "აკლია დამოკიდებულება", + "UniGetUI requires {0} to operate, but it was not found on your system.": "UniGetUI მოითხოვს {0} მუშაობისთვის, მაგრამ ის არ მოიძებნა თქვენს სისტემაში.", + "Click on Install to begin the installation process. If you skip the installation, UniGetUI may not work as expected.": "დაწკაპეთ ინსტალაციაზე, რომ დაიწყოს ინსტალაციის პროცესი. თუ გამოტოვებთ ინსტალაცია, UniGetUI შესაძლოა არ იმუშაოს გამართულად", + "Alternatively, you can also install {0} by running the following command in a Windows PowerShell prompt:": "ალტერნატიულად, თქვენ ასევე შეგიძლიათ დააყენოთ {0} Windows PowerShell-ში შემდეგი ბრძანების გაშვებით:", + "Install {0}": "{0}-ის ინსტალაცია", + "Do not show this dialog again for {0}": "არ მაჩვენო ეს დიალოგი {0}-მდე", + "Please wait while {0} is being installed. A black window may show up. Please wait until it closes.": "მოიცადეთ სანამ {0} დაყენდება. შესაძლოა გამოჩნდეს შავი (ან ლურჯი) ფანჯარა. დაელოდეთ სანამ არ დაიხურება.", + "{0} has been installed successfully.": "{0} წარმატებით დაინსტალირდა", + "Please click on \"Continue\" to continue": "გთხოვთ დაწკაპოთ \"გაგრძელება\" რომ გაგრძელდეს", + "Continue": "გაგრძელება", + "{0} has been installed successfully. It is recommended to restart UniGetUI to finish the installation": "{0} წარმატებით დაყენდა. რეკომენდებულია UniGetUI-ის ხელახლა გაშვება ინსტალაციის დასრულებისთვის", + "Restart later": "მოგვიანებით გადატვირთვა", + "An error occurred:": "დაფიქსირდა შეცდომა", + "Please see the Command-line Output or refer to the Operation History for further information about the issue.": "გთხოვთ ნახლოთ ბრძანების ზოლის გამოსავალი ან ოპერაციების ისტორია პრობლემის შესახებ მეტი ინფორმაციის გასაგებად.", + "Retry as administrator": "ხელახლა ცდა როგორც ადმინისტრატორი", + "Retry interactively": "ხელახლა ცდა ინტერაქტიულად", + "Retry skipping integrity checks": "იტეგრულობის შემოწმების გამოტოვების ხელახლა ცდა", + "Installation options": "ინსტალაციის პარამეტრები", + "Save": "შენახვა", + "UniGetUI collects anonymous usage data with the sole purpose of understanding and improving the user experience.": "UniGetUI აგროვებს ანონიმური გამოყენების მონაცემებს მომხმარებლის გამოცდილების გაგებისა და გაუმჯობესების მიზნით.", + "More details about the shared data and how it will be processed": "დამატებითი ინფორმაცია გაზიარებული ინფორმაციიდან და როგორ იქნება გამოიყენებული ის", + "Do you accept that UniGetUI collects and sends anonymous usage statistics, with the sole purpose of understanding and improving the user experience?": "ეთანხმებით თუ არა, რომ UniGetUI აგროვებს და აგზავნის გამოყენების ანონიმურ სტატისტიკას, მხოლოდ მომხმარებლის გამოცდილების გაგებისა და გაუმჯობესების მიზნით?", + "Decline": "უარყოფა", + "No personal information is collected nor sent, and the collected data is anonimized, so it can't be back-tracked to you.": "არანაირი პერსონალური მონაცემი არ გროვდება და არც გადაიცემა, დაგროვილი ინფორმაცია ანონიმურია ისე, რომ არ უთითებს თქვენზე.", + "Navigation panel": "ნავიგაციის პანელი", + "Operations": "ოპერაციები", + "Toggle operations panel": "ოპერაციების პანელის გადართვა", + "Bulk operations": "მასობრივი ოპერაციები", + "Retry failed": "ჩაშლილების ხელახლა ცდა", + "Clear successful": "წარმატებულების გასუფთავება", + "Clear finished": "დასრულებულების გასუფთავება", + "Cancel all": "ყველას გაუქმება", + "More": "მეტი", + "Toggle navigation panel": "ნავიგაციის პანელის გადართვა", + "Minimize": "ჩაკეცვა", + "Maximize": "გადიდება", + "UniGetUI by Devolutions": "UniGetUI Devolutions-ისგან", + "UniGetUI is an application that makes managing your software easier, by providing an all-in-one graphical interface for your command-line package managers.": "UniGetUI არის აპლიკაცია, რომელიც გიადვილებთ პროგრამული უზრუნველყოფის მათვას, ეს მიიღწევა ყველა-ერთში გრაფიკული ინფტერფეისის საშუალებით თქვენი ბრძანების ზოლის პაკეტების მენეჯერებისთვის.", + "Useful links": "სასარგებლო ბმულები", + "UniGetUI Homepage": "UniGetUI ვებ-საიტი", + "Report an issue or submit a feature request": "შეგვატყობინეთ პრობლემის შესახებ ან შემოგვთავაზეთ იდეა", + "UniGetUI Repository": "UniGetUI-ის რეპოზიტორია", + "View GitHub Profile": "GitHub-ის პროფილის ნახვა", + "UniGetUI License": "UniGetUI-ის ლიცენზია", + "Using UniGetUI implies the acceptation of the MIT License": "UniGetUI-ის გამოყენება ნიშნავს MIT ლიცენზიის მიღებას", + "Become a translator": "გახდი მთარგმნელი", + "Go back": "უკან დაბრუნება", + "Go forward": "წინ გადასვლა", + "Go to home page": "მთავარ გვერდზე გადასვლა", + "Reload page": "გვერდის გადატვირთვა", + "View page on browser": "გვერდის ბრაუზერში ნახვა", + "The built-in browser is not supported on Linux yet.": "ჩაშენებული ბრაუზერი Linux-ზე ჯერ არ არის მხარდაჭერილი.", + "Open in browser": "ბრაუზერში გახსნა", + "Copy to clipboard": "გაცვლის ბუფერში კოპირება", + "Export to a file": "ფაილში ექსპორტი", + "Log level:": "ჟურნალის დონე:", + "Reload log": "ჟურნალის ხელახლა ჩატვირთვა", + "Export log": "ჟურნალის ექსპორტი", + "Text": "ტექსტი", + "Change how operations request administrator rights": "შეცვალეთ, თუ როგორ ითხოვენ ოპერაციები ადმინისტრატორის უფლებებს", + "Restrictions on package operations": "პაკეტებზე ოპერაციების შეზღუდვები", + "Restrictions on package managers": "პაკეტების მმართველების შეზღუდვები", + "Restrictions when importing package bundles": "შეზღუდვები პაკეტების კრებული იმპორტირებისას", + "Ask for administrator privileges once for each batch of operations": "ადმინისტრატორის პრივილეგიების მოთხოვნა მხოლოდ ერჯერადად ოპერაციების ჯგუფის გაშვებისას", + "Ask only once for administrator privileges": "ადმინისტრატორის უფლებების მხოლოდ ერთხელ მოთხოვნა", + "Prohibit any kind of Elevation via UniGetUI Elevator or GSudo": "ნებისმიერი ელევაციის დაბლოკვა UniGetUI Elevator ან GSudo-ს საშუალებით", + "This option WILL cause issues. Any operation incapable of elevating itself WILL FAIL. Install/update/uninstall as administrator will NOT WORK.": "ეს პარამეტრი პრობლემებს გამოიწვევს. ნებისმიერი ოპერაცია, რომელიც ვერ შეძლებს თავისით ელევაციას ჩაიშლება. ინსტალაცია/განახლება/დეინსტალაცია ადმინისტრატორის უფლებებით არ იმუშავებს", + "Allow custom command-line arguments": "მორგებული ბრძანების ზოლის არგუმენტების დაშვება", + "Custom command-line arguments can change the way in which programs are installed, upgraded or uninstalled, in a way UniGetUI cannot control. Using custom command-lines can break packages. Proceed with caution.": "მორგებულ ბრძანების არგუმენტებს შეუძლია შეცვალოს პროცესი რომლითაც პროგრამები ინსტალირდება, ახლდება ან დეინსტალირდება ისე, რომ UniGetUI ვერ შეძლებს მის კონტროლ. მორგებულ ბრძანების არგუმენტებს შეუძლია პაკეტების დაზიანება. გამოიყენეთ სიფრთხილის ზომების დაცვით.", + "Ignore custom pre-install and post-install commands when importing packages from a bundle": "მორგებული პრეინსტალაციისა და პოსტინსტალაციის ბრძანებების გაშვების დაშვება", + "Pre and post install commands will be run before and after a package gets installed, upgraded or uninstalled. Be aware that they may break things unless used carefully": "პრე და პოსტ ინსტალაციის ბრძანებები გაეშვება პაკეტის ინსტალაციამდე, შემდეგ, განახლებისას ან დეინსტალაციისას. გაითვალისწინეთ, რომ ამას შეუძლია ზიანის მოტანა თუ არ გამოვიყენებთ სიფთხილის დაცვით.", + "Allow changing the paths for package manager executables": "პაკეტების მმართველების გამშვებ ფაილების მისმართების ცვლილების დაშვება", + "Turning this on enables changing the executable file used to interact with package managers. While this allows finer-grained customization of your install processes, it may also be dangerous": "ამის ჩართვით თქვენ ნებას რთავ გამოყენებულ იქნას შეცვლილი გამშვები ფაილები პაკეტების მმართველებთან მუშაობისთვის. ეს მოგცემთ უფრო მეტ მორგებადობას და ფუნქციონალს ინსტალაცისაც თუმცა არის საშიშიც", + "Allow importing custom command-line arguments when importing packages from a bundle": "მორგებული ბრძანების ზოლის არგუმენტების იმპორტირების დაშვება პაკეტების კრებულიდან იმპორტისას", + "Malformed command-line arguments can break packages, or even allow a malicious actor to gain privileged execution. Therefore, importing custom command-line arguments is disabled by default": "არასწორად შედგენილ ბრძანების არგუმენტებს შეუძლია პაკეტების დაზიანება ან თუნდაც ბოროტმოქმედს მისცეს პრივილეგირებული შესრულების უფლება. ამიტომაც მორგებული ბრძანების არგუმენტების იმპორტირება ნაგულისხმევად გამორთულია", + "Allow importing custom pre-install and post-install commands when importing packages from a bundle": "მორგებული პრეინსტალაციის და პოსტ ინსტალაციის ბრძანებების იმპორტირების დაშვება პაკეტების კრებულიდან იმპორტისას", + "Pre and post install commands can do very nasty things to your device, if designed to do so. It can be very dangerous to import the commands from a bundle, unless you trust the source of that package bundle": "პრე და პოსტ ინსტალაციის ბრძანებებს შეულძია ზიანის მიყენება, თუ არასწორად არის შედგენილი. ეს შესაძლოა ძალიან საშიში იყოს კრებულიდან მათი იმპორტირება თუ თქვენ არ ენდობით პაკეტების კრებულის მომწოდებელს.", + "Administrator rights and other dangerous settings": "ადმინისტრატორის უფლებები და სხვა საშიში პარამეტრები", + "Package backup": "პაკეტის ბექაფი", + "Cloud package backup": "პაკეტების ღრუბლოვანი ბექაფი", + "Local package backup": "პაკეტების ლოკალური ბექაფი", + "Local backup advanced options": "ლოკალური ბექაფის დამატებითი პარამეტრები", + "Log in with GitHub": "GitHub-ით შესვლა", + "Log out from GitHub": "GitHub-დან გამოსვლა", + "Periodically perform a cloud backup of the installed packages": "პერიოდულად შექმენი დაყენებული პაკეტების ღრუბლოვანი ბექაფი", + "Cloud backup uses a private GitHub Gist to store a list of installed packages": "ღღუბლოვანი ბექაფი იყენებს პრივატულ GitHub Gist-ს, რომ შეინახოს დაყენებული პაკეტების სია", + "Perform a cloud backup now": "ღრუბლოვანი ბექაფის ახლა გაშვება", + "Backup": "ბექაფი", + "Restore a backup from the cloud": "ბექაფის ღრუბლიდან აღდგენა", + "Begin the process to select a cloud backup and review which packages to restore": "ღღუბლოვანი ბექაფის შერჩევის პროცესის დაწყება და აღსადგენი პაკეტების მიმოხილვა", + "Periodically perform a local backup of the installed packages": "დაყენებული პაკეტების ბექაფის პერიოდულად შესრულება", + "Perform a local backup now": "ლოკალური ბექაფის ახლა გაშვება", + "Change backup output directory": "ბექაფის დირექტორიის შეცვლა", + "Set a custom backup file name": "მიუთითეთ ბექაფის ფაილის მორგებული სახელი", + "Leave empty for default": "დატოვეთ ცარიელი ნაგულისხმევად", + "Add a timestamp to the backup file names": "ბექაფის ფაილების სახელებზე დროის ანაბეჭდის დამატება", + "Backup and Restore": "ბექაფი და აღდგენა", + "Enable background api (UniGetUI Widgets and Sharing, port 7058)": "ფონური API-ის ჩართვა (UniGetUI-ის ვიჯეტები და გაზიარება, პორტი 7058)", + "Wait for the device to be connected to the internet before attempting to do tasks that require internet connectivity.": "მოცდა სანამ მოწყობილობა დაუკავშირდება ინტერნეტს მანამ სანამ მოხდება ინტერნეტთან დაკავშირების საჭიროების მქონე ამოცანების შესრულება.", + "Disable the 1-minute timeout for package-related operations": "ოპერაციებისთვის 1 წუთიანი პაკეტებთან დაკავშირებული ვადის გამორთვა", + "Use installed GSudo instead of UniGetUI Elevator": "GSudo-ს გამოყენება UniGetUI Elevator-ის ნაცვლად", + "Use a custom icon and screenshot database URL": "მორგებული ხატულებისა და სქრინშოტების მონაცემთა ბაზის URL", + "Enable background CPU Usage optimizations (see Pull Request #3278)": "CPU-ს ფონური მოხმარების ოპტიმიზაციის ჩართვა (იხილეთ Pull Request #3278)", + "Perform integrity checks at startup": "ინტეგრულობის შემოწმება გაშვებისას", + "When batch installing packages from a bundle, install also packages that are already installed": "პაკეტების კრებულიდან ერთდროულად დაყენებისას დაყენდეს უკვე დაყენებული პაკეტებიც", + "Experimental settings and developer options": "ექსპერიმენტული პარამეტრები და დეველოპერის ოფციები", + "Show UniGetUI's version and build number on the titlebar.": "UniGetUI-ს ვერსიის ჩვენება სათაურის ზოლში", + "Language": "ენა", + "UniGetUI updater": "UniGetUI განმაახლებელი", + "Telemetry": "ტელემეტრია", + "Manage UniGetUI settings": "UniGetUI-ის პარამეტრების მართვა", + "Related settings": "დაკავშირებული პარამეტრები", + "Update UniGetUI automatically": "UniGetUI ავტომატური განახლება", + "Check for updates": "განახლებების შემოწმება", + "Install prerelease versions of UniGetUI": "UniGetUI-ის პრერელიზების ინსტალაცია", + "Manage telemetry settings": "ტელემეტრიის პარამეტრების მართვა", + "Manage": "მართვა", + "Import settings from a local file": "პარამეტრების ლოკალური ფაილიდან იმპორტი", + "Import": "იმპორტი", + "Export settings to a local file": "პარამეტრების ლოკალურ ფაილში ექსპორტი", + "Export": "ექსპორტი", + "Reset UniGetUI": "UniGetUI-ის დარესეტება", + "User interface preferences": "სამომხმარებლო ინტერფეისის პარამეტრები", + "Application theme, startup page, package icons, clear successful installs automatically": "აპლიკაციის თემა, სასტარტო გვერდი, პაკეტების ხატულები, წარმატებული ინსტალაციების ავტომატურად წაშლა", + "General preferences": "ზოგადი პარამეტრები", + "UniGetUI display language:": "UniGetUI-ის ინტერფეისის ენა:", + "System language": "სისტემის ენა", + "Is your language missing or incomplete?": "თქვენი ენა არ არის ან დაუსრულებელია?", + "Appearance": "იერსახე", + "UniGetUI on the background and system tray": "UniGetUI ფონურ რეჟიმში და სისტემური პანელი", + "Package lists": "პაკეტების სიები", + "Use classic mode": "კლასიკური რეჟიმის გამოყენება", + "Restart UniGetUI to apply this change": "ამ ცვლილების გამოსაყენებლად გადატვირთეთ UniGetUI", + "The classic UI is disabled for beta testers": "კლასიკური მომხმარებლის ინტერფეისი გამორთულია ბეტა ტესტერებისთვის", + "Close UniGetUI to the system tray": "UniGetUI-ის სისტემურ პანელში ჩახურვა", + "Manage UniGetUI autostart behaviour": "UniGetUI-ის ავტომატური გაშვების ქცევის მართვა", + "Show package icons on package lists": "პაკეტის ხატულების ჩვენება პაკეტების სიებში", + "Clear cache": "ქეშის გაწმენდა", + "Select upgradable packages by default": "განახლებადი პაკეტების ნაგულისხმევად შერჩევა", + "Light": "ნათლი", + "Dark": "მუქი", + "Follow system color scheme": "სისტემური ფერთა სქემის მიდევნება", + "Application theme:": "აპლიკაციის თემა:", + "UniGetUI startup page:": "UniGetUI გაშვების გვერდი:", + "Proxy settings": "პროქსის პარამეტრები", + "Other settings": "სხვა პარამეტრები", + "Connect the internet using a custom proxy": "ინტერნეტთან მორგებული პროქსით პასუხი", + "Please note that not all package managers may fully support this feature": "გაითვალისწინეთ, რომ ყველა პაკეტების მენეჯერს შესაძლოა არ ქონდეთ ამ ფუნქციის სრული მხარდაჭერა", + "Proxy URL": "პროქსის URL", + "Enter proxy URL here": "შეიყვანეთ პროქსის URL აქ", + "Authenticate to the proxy with a user and a password": "პროქსიზე ავტორიზაცია მომხმარებლის სახელით და პაროლით", + "Internet and proxy settings": "ინტერნეტისა და პროქსის პარამეტრები", + "Package manager preferences": "პაკეტების მენეჯერის პარამეტრები", + "Ready": "მზადაა", + "Not found": "არ არის ნაპოვნი", + "Notification preferences": "შეტყობინებების პარამეტრები", + "Notification types": "შეტყობინებების ტიპები", + "The system tray icon must be enabled in order for notifications to work": "სისტემური პანელის ხატულა უნდა იყოს ჩართული შეტყობინებების მუშაობისთვის", + "Enable UniGetUI notifications": "UniGetUI-ის შეტყობინებების ჩართვა", + "Show a notification when there are available updates": "შეტყობინების ჩვენება როცა ხელმისაწვდომია განახლებები", + "Show a silent notification when an operation is running": "ჩუმი შეტყობინების ჩვენება როცა მიმდინარეობს ოპერაცია", + "Show a notification when an operation fails": "შეტყობინების ჩვენება ოპერაციის ჩაშლისას", + "Show a notification when an operation finishes successfully": "შეტყობინების ჩვენება ოპერაციის წარმატებულად დასრულებისას", + "Concurrency and execution": "კონკურენცია და გაშვება", + "Automatic desktop shortcut remover": "ავტომატური სამუშაო მაგიდის მალსახმობების წამშლელი", + "Choose how many operations should be performed in parallel": "აირჩიეთ, რამდენი ოპერაცია უნდა შესრულდეს პარალელურად", + "Clear successful operations from the operation list after a 5 second delay": "წარმატებული ოპერაციების სიიდან ამოღება 5 წამიანი დაყოვნების შემდეგ", + "Download operations are not affected by this setting": "ეს პარამეტრი არ მოქმედებს ჩამოტვირთვის ოპერაციებზე", + "You may lose unsaved data": "თქვენ შესაძლოა დაკარგოთ შეუნახავი მონაცემები", + "Ask to delete desktop shortcuts created during an install or upgrade.": "სამუშაო მაგიდის მალსახმობების წაშლის მოთხოვნა ინსტალაციის ან განახლებისას", + "Package update preferences": "პაკეტის განახლების პარამეტრები", + "Update check frequency, automatically install updates, etc.": "განახლებების შემოწმების სიხშირე, განახლებების ავტომატური ინსტალაცია და სხვ.", + "Reduce UAC prompts, elevate installations by default, unlock certain dangerous features, etc.": "UAC დიალოგების შემცირება, ინსტალაციების ელევაცია ნაგულისხმევად, ზოგიერთი საშიში ფუნქციის ჩართვა და ა.შ.", + "Package operation preferences": "პაკეტის ოპერაციის პარამეტრები", + "Enable {pm}": "ჩართვა {pm}", + "Not finding the file you are looking for? Make sure it has been added to path.": "ვერ პოულობ ფაილს რომელსაც ეძებ? დარწმუნდი, რომ ის დამატებულია path-ში.", + "Select the executable to be used. The following list shows the executables found by UniGetUI": "აირჩიეთ გამოსაყენებელი გამშვები ფაილი. ქვემოთ მოცემული სია აჩვენებს UniGetUI-ის მიერ ნაპოვნ გამშვებ ფაილებს", + "For security reasons, changing the executable file is disabled by default": "უსაფრთხოების მიზეზებიდან გამომდინარე გამშვები ფაილის შეცვლა ნაგულისხმევად გამორთულია", + "Change this": "შეცვალე ეს", + "Copy path": "მისამართის კოპირება", + "Current executable file:": "მიმდინარე გამშვები ფაილი:", + "Ignore packages from {pm} when showing a notification about updates": "პაკეტების განახლებების იგნორირება შეტყობინებებში {pm} რეპოზიტორიიდან", + "Update security": "განახლებების უსაფრთხოება", + "Use global setting": "გლობალური პარამეტრის გამოყენება", + "Minimum age for updates": "განახლებების მინიმალური ასაკი", + "e.g. 10": "მაგ. 10", + "Custom minimum age (days)": "მორგებული მინიმალური ასაკი (დღეებში)", + "{pm} does not provide release dates for its packages, so this setting will have no effect": "{pm} არ აწვდის თავისი პაკეტებისთვის რელიზის თარიღებს, ამიტომ ამ პარამეტრს ეფექტი არ ექნება", + "{pm} only provides release dates for some of its packages, so this setting will only apply to those packages": "{pm} გამოშვების თარიღებს მხოლოდ ზოგიერთი თავისი პაკეტისთვის გვაწვდის, ამიტომ ეს პარამეტრი მხოლოდ ამ პაკეტებზე გავრცელდება", + "Override the global minimum update age for this package manager": "ამ პაკეტების მენეჯერისთვის გლობალური მინიმალური განახლების ასაკის გადაფარვა", + "View {0} logs": "{0} ჟურნალის ნახვა", + "If Python cannot be found or is not listing packages but is installed on the system, ": "თუ Python ვერ მოიძებნა ან არ აჩვენებს პაკეტებს, თუმცა სისტემაში დაყენებულია, ", + "Advanced options": "გაფართოებული ოფციები", + "WinGet command-line tool": "WinGet-ის ბრძანების ხაზის ხელსაწყო", + "Choose which command-line tool UniGetUI uses for WinGet operations when the COM API is not used": "აირჩიეთ, რომელ ბრძანების ხაზის ხელსაწყოს გამოიყენებს UniGetUI WinGet ოპერაციებისთვის, როდესაც COM API არ გამოიყენება", + "WinGet COM API": "WinGet COM API", + "Choose whether UniGetUI can use the WinGet COM API before falling back to the command-line tool": "აირჩიეთ, შეუძლია თუ არა UniGetUI-ს WinGet COM API-ის გამოყენება ბრძანების ხაზის ხელსაწყოზე გადასვლამდე", + "Reset WinGet": "WinGet-ის დარესეტება", + "This may help if no packages are listed": "ეს შეიძლება დაგეხმაროთ, თუ პაკეტები არ არის ჩამოთვლილი", + "Force install location parameter when updating packages with custom locations": "მორგებული მდებარეობის მქონე პაკეტების განახლებისას ინსტალაციის მდებარეობის პარამეტრის იძულებით გამოყენება", + "Install Scoop": "Scoop-ის ინსტალაცია", + "Uninstall Scoop (and its packages)": "Scoop-ის (და მისი პაკეტების) დეინსტალაცია", + "Run cleanup and clear cache": "გაწმენდისა და ქეშის გასუფთავების გაშვება", + "Run": "გაშვება", + "Enable Scoop cleanup on launch": "Scoop-ის გასუფთავების ჩართვა გაშვებისას", + "Default vcpkg triplet": "vcpkg-ის ნაგულისხმევი ტრიპლეტი", + "Change vcpkg root location": "vcpkg-ის ძირეული მდებარეობის შეცვლა", + "Reset vcpkg root location": "vcpkg-ის ძირეული მდებარეობის დარესეტება", + "Open vcpkg root location": "vcpkg-ის ძირეული მდებარეობის გახსნა", + "Language, theme and other miscellaneous preferences": "ენა, თემა და სხვა დამატებითი პარამეტრები", + "Show notifications on different events": "შეტყობინებების ჩვენება სხვა და სხვა მოვლენებისთვის", + "Change how UniGetUI checks and installs available updates for your packages": "შეცვალე თუ როგორ ამოწმებს და აყენებს UniGetUI ხელმისაწვდომ განახლებებს თქვენი პაკეტებისთვის", + "Automatically save a list of all your installed packages to easily restore them.": "დაყენებული პაკეტების სიის ავტომატურად შენახვა მათი მარტივი აღდგენისათვის.", + "Enable and disable package managers, change default install options, etc.": "პაკეტების მმართველების ჩართვა და გამორთვა, ნაგილისხმევი ინსტალაციის პარამეტრების შეცვლა და ა. შ.", + "Internet connection settings": "ინტერნეტთან კავშირის პარამეტრები", + "Proxy settings, etc.": "პროქსის პარამეტრები, სხვ.", + "Beta features and other options that shouldn't be touched": "ბეტა ფუნქციონალი და სხვა პარამეტრები, რომლებსაც ხელი არ უნდა ახლოთ", + "Reload sources": "წყაროების გადატვირთვა", + "Delete source": "წყაროს წაშლა", + "Known sources": "ცნობილი წყაროები", + "Update checking": "განახლებების შემოწმება", + "Automatic updates": "ავტომატური განახლებები", + "Check for package updates periodically": "პაკეტის განახლების პერიოდული შემოწმება", + "Check for updates every:": "განახლებების შემოწმება ყოველ:", + "Install available updates automatically": "ხელმისაწვდომი განახლებების ავტომატური ინსტალაცია", + "Do not automatically install updates when the network connection is metered": "არ დაყენდეს ავტომატური განახლებები, როცა ქსელთან კავშირი ლიმიტირებულია (დეპოზიტი)", + "Do not automatically install updates when the device runs on battery": "არ დააყენო განახლებები ავტომატურად, როცა მოწყობილობა ბატარეაზე მუშაობს", + "Do not automatically install updates when the battery saver is on": "არ დაყენდეს განახლებები ავვტომატურად აკუმლატორის დაზოგვის რეჟიმში ", + "Only show updates that are at least the specified number of days old": "აჩვენეთ მხოლოდ ის განახლებები, რომელთა ასაკიც მინიმუმ მითითებული დღეების რაოდენობაა", + "Warn me when the installer URL host changes between the installed version and the new version (WinGet only)": "გამაფრთხილეთ, როდესაც ინსტალატორის URL-ის ჰოსტი შეიცვლება დაინსტალირებულ ვერსიასა და ახალ ვერსიას შორის (მხოლოდ WinGet)", + "Change how UniGetUI handles install, update and uninstall operations.": "შეცვალეთ თუ როგორ შეასრულებს UniGetUI ინსტალაციის, განახლების და დეინსტალაციის ოპერაციებს.", + "Navigation": "ნავიგაცია", + "Check for UniGetUI updates": "UniGetUI-ის განახლებების შემოწმება", + "Quit UniGetUI": "UniGetUI-დან გასვლა", + "Filters": "ფილტრები", + "Sources": "წყაროები", + "Search for packages to start": "დაწყებისთვის მოძებნეთ პაკეტები", + "Select all": "ყველას მონიშვნა", + "Clear selection": "მონიშვნის გაწმენდა", + "Instant search": "სწრაფი ძიება", + "Distinguish between uppercase and lowercase": "განასხვავე დიდსა და პატარა რეგისტრს შორის", + "Ignore special characters": "სპეციალური სიმბოლოების იგნორირება", + "Search mode": "ძიების რეჟიმი", + "Both": "ორივე", + "Exact match": "ზუსტი თანხვედრა", + "Show similar packages": "მსგავსი პაკეტების ჩვენება", + "Loading": "ჩატვირთვა", + "Package": "პაკეტი", + "More options": "მეტი პარამეტრი", + "Order by:": "დალაგება:", + "Name": "სახელი", + "Id": "ID", + "Ascendant": "ასცენდენტი", + "Descendant": "დესცენდენტი", + "View modes": "ნახვის რეჟიმები", + "Reload": "გადატვირთვა", + "Closed": "დახურული", + "Ascending": "აღმავალი", + "Descending": "დაღმავალი", + "{0}: {1}, {2}": "{0}: {1}, {2}", + "Order by": "დალაგება", + "No results were found matching the input criteria": "შევანილი კრიტერიუმებით არ იქნა ნაპოვნი არაფერი", + "No packages were found": "პაკეტები არ არის ნაპოვნი", + "Loading packages": "პაკეტების ჩატვირთვა", + "Skip integrity checks": "ინტეგრულობის შემოწმების გამოტოვება", + "Download selected installers": "შერჩეული ინსტალატორების ჩამოტვირთვა", + "Install selection": "შერჩეულების ინსტალაცია", + "Install options": "ინსტალაციის პარამეტრები", + "Add selection to bundle": "მონიშვნის კრებულში დამატება", + "Download installer": "ინსტალატორის ჩამოტვირთვა", + "Uninstall selection": "მონიშნულის დეინსტალაცია", + "Uninstall options": "დეინსტალაციის პარამეტრები", + "Ignore selected packages": "მონიშნული პაკეტების იგნორირება", + "Open install location": "ინსტალაციის ლოკაციის გახსნა", + "Reinstall package": "პაკეტის ხელახალი ინსტალაცია", + "Uninstall package, then reinstall it": "პაკეტის დეინსტალაცია და ხელახლა ინსტალაცია", + "Ignore updates for this package": "ამ პაკეტის განახლებების იგნორირება", + "WinGet malfunction detected": "დაფიქსირდა WinGet-ის გაუმართაობა", + "It looks like WinGet is not working properly. Do you want to attempt to repair WinGet?": "როგორც ჩანს WinGet არ მუშაობს გამართულად. გსურთ სცადოთ WinGet-ის შეკეთება?", + "Repair WinGet": "WinGet-ის შეკეთება", + "Updates will no longer be ignored for {0}": "განახლებები აღარ იქნება იგნორირებული {0}-სთვის", + "Updates are now ignored for {0}": "განახლებები ახლა იგნორირებულია {0}-სთვის", + "Do not ignore updates for this package anymore": "არ დაიგნორდეს განახლებები ამ პაკეტისთვის მომავალში", + "Add packages or open an existing package bundle": "დაამატეთ პაკეტები ან გახსენით არსებული პაკეტების კრებული", + "Add packages to start": "დაამატეთ პაკეტები დასაწყებად", + "The current bundle has no packages. Add some packages to get started": "მიმდინარე კრებულში არ არის პაკეტები. დაამატე რამდენიმე პაკეტი რომ დავიწყოთ", + "New": "ახალი", + "Save as": "შენახვა როგორც", + "Create .ps1 script": ".ps1 სკრიპტის შექმნა", + "Remove selection from bundle": "მონიშნულის კრებულიდან წაშლა", + "Skip hash checks": "ჰეშის შემოწმების გამოტოვება", + "The package bundle is not valid": "პაკეტების კრებული არ არის ვალიდური", + "The bundle you are trying to load appears to be invalid. Please check the file and try again.": "კრებული, რომლის ჩატვირთვაც გსურთ არ არის ვალიდური. შეამოწმეთ ფაილი და ხელახლა ცადეთ.", + "Package bundle": "პაკეტის კრებული", + "Could not create bundle": "კრებული ვერ შეიქმნა", + "The package bundle could not be created due to an error.": "პაკეტების კრებული ვერ შეიქმნა შეცდომის გამო.", + "Install script": "ინსტალაციის სკრიპტი", + "PowerShell script": "PowerShell სკრიპტი", + "The installation script saved to {0}": "ინსტალაციის სკრიპტი შენახულია აქ: {0}", + "An error occurred": "დაფიქსირდა შეცდომა", + "An error occurred while attempting to create an installation script:": "შეცდომა დაფიქსირდა ინსტალაციის სკრიპტის შექმნის მცდელობისას:", + "Hooray! No updates were found.": "ვაშა! განახლებები არ არის ნაპოვნი.", + "Uninstall selected packages": "შერჩეული პაკეტების დეინსტალაცია", + "Update selection": "მონიშნულის განახლება", + "Update options": "განახლების პარამეტრები", + "Uninstall package, then update it": "პაკეტის დეინსტალაცია და შემდგომ მისი განახლება", + "Uninstall package": "პაკეტის დეინსტალაცია", + "Skip this version": "ვერსიის გამოტოვება", + "Pause updates for": "განახლებების დაპაუზება", + "User | Local": "მომხმარებელი | ლოკალური", + "Machine | Global": "კომპიუტერი | გლობალური", + "The default package manager for Debian/Ubuntu-based Linux distributions.
Contains: Debian/Ubuntu packages": "ნაგულისხმევი პაკეტების მენეჯერი Debian/Ubuntu-ზე დაფუძნებული Linux დისტრიბუციებისთვის.
შეიცავს: Debian/Ubuntu პაკეტებს", + "The Rust package manager.
Contains: Rust libraries and programs written in Rust": "Rust-ის პაკეტების მმართველი.
შეიცავს: Rust-ის ბიბლიოთეკებსა და Rust-ზე დაწერილ პროგრამებს", + "The classical package manager for windows. You'll find everything there.
Contains: General Software": "კლასიკური პაკეტების მენეჯერი Windows-ისთვის. თქვენ იქ ყველაფერს იპოვით.
შეიცავს: ზოგად პროგრამებს", + "The default package manager for RHEL/Fedora-based Linux distributions.
Contains: RPM packages": "ნაგულისხმევი პაკეტების მენეჯერი RHEL/Fedora-ზე დაფუძნებული Linux დისტრიბუციებისთვის.
შეიცავს: RPM პაკეტებს", + "A repository full of tools and executables designed with Microsoft's .NET ecosystem in mind.
Contains: .NET related tools and scripts": "რეპოზიტორია სავსე ინსტრუმენტბითა და გამშვები ფაილებით Microsoft .NET ეკოსისტემისთვის.
შეიცავს: .NET-თან დაკავშირებულ ინსტრუმენტებსა და სკრიპტებს", + "The universal Linux package manager for desktop applications.
Contains: Flatpak applications from configured remotes": "უნივერსალური Linux პაკეტების მენეჯერი დესკტოპის აპლიკაციებისთვის.
შეიცავს: Flatpak აპლიკაციებს კონფიგურირებული დისტანციური წყაროებიდან", + "NuPkg (zipped manifest)": "NuPkg (დაზიპული მანიფესტი)", + "The Missing Package Manager for macOS (or Linux).
Contains: Formulae, Casks": "პაკეტების ის მენეჯერი, რომელიც macOS-ს (ან Linux-ს) აკლდა.
შეიცავს: Formulae, Casks", + "Node JS's package manager. Full of libraries and other utilities that orbit the javascript world
Contains: Node javascript libraries and other related utilities": "Node JS პაკეტების მართველი. სავსეა ბიბლიოთეკებითა და უტილიტებით javascript-ის სამყაროდან
შეიჩავს: Node javascript ბიბლიოთეკებს და სხვა შესაბამის უტილიტებს", + "The default package manager for Arch Linux and its derivatives.
Contains: Arch Linux packages": "ნაგულისხმევი პაკეტების მენეჯერი Arch Linux-ისა და მისი წარმოებულებისთვის.
შეიცავს: Arch Linux პაკეტებს", + "Python's library manager. Full of python libraries and other python-related utilities
Contains: Python libraries and related utilities": "Python-ის ბიბლიოთეკების მმართველი. სავსეა პითონის ბიბლიოთეკებით და სხვა მასთან დაკავშირებული უტილიტებით
შეიცავს: Python-ის ბიბლიოთეკებსა და შესაბამის უტილიტებს", + "PowerShell's package manager. Find libraries and scripts to expand PowerShell capabilities
Contains: Modules, Scripts, Cmdlets": "PowerShell-ის პაკეტების მმართველი. იპოვეთ ბიბლიოთეკები და სკრიპტები რომ გააფართოოთ PowerShell-ის შესაძლებლობები
შეიცავს: მოდულებს, სკრიპტებს, ქომადლეტებს", + "extracted": "გამოარქივდა", + "Scoop package": "Scoop-ის პაკეტი", + "Great repository of unknown but useful utilities and other interesting packages.
Contains: Utilities, Command-line programs, General Software (extras bucket required)": "მშვენიერი რეპოზიტორია უცნობი მაგრამ სასარგებლო უტილიტებითა და სხვა საინტერესო პაკეტებით.
შეიცავს: უტილიტებს, ბრძანების ზოლის პროგრამებს, ზოგად პროგრამებს (საჭიროა extras კრებული)", + "The universal Linux package manager by Canonical.
Contains: Snap packages from the Snapcraft store": "უნივერსალური Linux პაკეტების მენეჯერი Canonical-ისგან.
შეიცავს: Snap პაკეტებს Snapcraft მაღაზიიდან", + "library": "ბიბლიოთეკა", + "feature": "ფუნქცია", + "A popular C/C++ library manager. Full of C/C++ libraries and other C/C++-related utilities
Contains: C/C++ libraries and related utilities": "პოპულარული C/C++ ბიბლიოთეკების მმართველი. სავსეა C/C++ ბიბლიოთეკებით და სხვა მასთან დაკავშირებული უტილიტებით.
შეიცავს: C/C++ ბიბლიოთეკებს და შესაბამის უტილიტებს", + "option": "ოფცია", + "This package cannot be installed from an elevated context.": "ეს პაკეტი ვერ დაყენდება ადმინისტრატორის პრივილეგიებით.", + "Please run UniGetUI as a regular user and try again.": "გთხოვთ გაუშვათ UniGetUI როგორც ჩვეულებრივმა მომხმარებელმა და ხელახლა ცადეთ.", + "Please check the installation options for this package and try again": "შეამოწმეთ ინსტალაციის პარამეტრები ამ პაკეტისთვის და ხელახლა ცადეთ", + "Microsoft's official package manager. Full of well-known and verified packages
Contains: General Software, Microsoft Store apps": "Microsoft-ის ოფიციალური პაკეტების მენეჯერი. სავსეა ცნობილი და გადამოწმებული პაკეტებით
შეიცავს: ზოგად პროგრამებს, აპებს Microsoft Store-დან", + "Local PC": "ლოკალური კომპიუტერი", + "Android Subsystem": "Android ქვესისტემა", + "Operation on queue (position {0})...": "ოპერაცია რიგშია (პოზიცია {0})...", + "Click here for more details": "დაწკაპეთ აქ მეტი დეტალისთვის", + "Operation canceled by user": "ოპერაცია მომხმარებელმა გააუქმა", + "Running PreOperation ({0}/{1})...": "მიმდინარეობს PreOperation ({0}/{1})...", + "PreOperation {0} out of {1} failed, and was tagged as necessary. Aborting...": "{1}-დან აუცილებელად მონიშნული PreOperation {0} ჩაიშალა. შეწყვეტა...", + "PreOperation {0} out of {1} finished with result {2}": "{1}-დან PreOperation {0} დასრულდა შედეგით {2}", + "Starting operation...": "ოპერაციების გაშვება...", + "Running PostOperation ({0}/{1})...": "მიმდინარეობს PostOperation ({0}/{1})...", + "PostOperation {0} out of {1} failed, and was tagged as necessary. Aborting...": "{1}-დან აუცილებელად მონიშნული PostOperation {0} ჩაიშალა. შეწყვეტა...", + "PostOperation {0} out of {1} finished with result {2}": "{1}-დან PostOperation {0} დასრულდა შედეგით {2}", + "{package} installer download": "{package}-ის ინსტალატორის ჩამოტვირთვა", + "{0} installer is being downloaded": "იტვირთება {0}-ის ინსტალატორი", + "Download succeeded": "წარმატებით ჩამოიტვირთა", + "{package} installer was downloaded successfully": "{package}-ის ინსტალატორი წარმატებით ჩამოიტვირთა", + "Download failed": "ჩამოტვირთვა ჩაიშალა", + "{package} installer could not be downloaded": "ვერ ხერხდება {package}-ის ინსტალატორის ჩამოტვირთვა ", + "{package} Installation": "{package} ინსტალაცია", + "{0} is being installed": "ინსტალირდება {0}", + "Installation succeeded": "ინსტალაცია წარმატებით განხორციელდა", + "{package} was installed successfully": "{package} წარმატებით დაინსტალირდა", + "Installation failed": "ინსტალაცია ჩაიშალა", + "{package} could not be installed": "{package}-ის ინსტალაცია შეუძლებელია", + "{package} Update": "{package} განახლება", + "Update succeeded": "განახლება წარმატებულად დასრულდა", + "{package} was updated successfully": "{package} წარმატებით განახლდა", + "Update failed": "განახლება ჩაიშალა", + "{package} could not be updated": "{package}-ის განახლება შეუძლებელია", + "{package} Uninstall": "{package} დეინსტალაცია", + "{0} is being uninstalled": "{0} დეინსტალირდება", + "Uninstall succeeded": "დეინსტალაცია წარმატებით დასრულდა", + "{package} was uninstalled successfully": "{package} წარმატებით წაიშალა", + "Uninstall failed": "დეინსტალაცია ჩაიშალა", + "{package} could not be uninstalled": "{package}-ის დეინსტალაცია შეუძლებელია", + "Adding source {source}": "{source} წყაროს დამატება", + "Adding source {source} to {manager}": "{source} წყაროს დამატება {manager}-ში", + "Source added successfully": "წყარო წარმატებით დაემატა", + "The source {source} was added to {manager} successfully": "წყარო {source} წარმატებით დაემატა {manager}-ში", + "Could not add source": "წყარო ვერ დაემატა", + "Could not add source {source} to {manager}": "წყარო {source} ვერ დაემატა {manager}-ში", + "Removing source {source}": "{source} წყაროს წაშლა", + "Removing source {source} from {manager}": "{source} წყაროს წაშლა {manager}-დან", + "Source removed successfully": "წყარო წარმატებით წაიშალა", + "The source {source} was removed from {manager} successfully": "წყარო {source} წარმატებით ამოიშალა {manager}-დან", + "Could not remove source": "წყარო ვერ წაიშალა", + "Could not remove source {source} from {manager}": "ვერ წაიშალა {source} წყარო {manager}-დან", + "The package manager \"{0}\" was not found": "პაკეტების მენეჯერი \"{0}\" ვერ იქნა ნაპოვნი", + "The package manager \"{0}\" is disabled": "პაკეტების მენეჯერი \"{0}\" გამორთულია", + "There is an error with the configuration of the package manager \"{0}\"": "შეცდომაა \"{0}\" პაკეტების მმართველის კონფიგურაციაში", + "The package \"{0}\" was not found on the package manager \"{1}\"": "პაკეტი\"{0}\" არ იქნა ნაპოვნი \"{1}\" პაკეტების მენეჯერში", + "{0} is disabled": "{0} გამორთულია", + "{0} weeks": "{0} კვირა", + "1 month": "1 თვე", + "{0} months": "{0} თვე", + "Something went wrong": "რაღაც ჩაიშალა", + "An interal error occurred. Please view the log for further details.": "დაფიქსირდა შიდა შეცდომა. დამატებითი დეტალებისთვის გთხოვთ ნახოთ ჟურნალი.", + "No applicable installer was found for the package {0}": "არ არის შესაბამისი ინსტალატორი ნაპოვნი {0} პაკეტისთვის", + "Integrity checks will not be performed during this operation": "ამ ოპერაციისას არ მოხდება ინტეგრულობის შემოწმება", + "This is not recommended.": "ეს არ არის რეკომენდებული.", + "Run now": "ახლა გაშვება", + "Run next": "შემდეგის გაშვება", + "Run last": "ბოლოს გაშვება", + "Show in explorer": "ექსპლორერში ჩვენება", + "Checked": "მონიშნული", + "Unchecked": "მოუნიშნავი", + "This package is already installed": "ეს პაკეტი უკვე დაყენებულია", + "This package can be upgraded to version {0}": "ამ პაკეტის განახლება შესაძლებელია {0} ვერსიამდე", + "Updates for this package are ignored": "ამ პაკეტის განახლებები იგნორირებულია", + "This package is being processed": "მიმდინარეობს პაკეტის დამუშავება", + "This package is not available": "ეს პაკეტი არ არის ხელმისაწვდომი", + "Select the source you want to add:": "შეარჩიეთ წყაროები, რომლების დამატებაც გინდათ:", + "Source name:": "წყაროს სახელი:", + "Source URL:": "წყაროს URL:", + "An error occurred when adding the source: ": "დაფიქსირდა შეცდომა წყაროს დამატებისას:", + "Package management made easy": "გამარტივებული პაკეტების მართვა", + "version {0}": "ვერსია {0}", + "[RAN AS ADMINISTRATOR]": "ადმინისტრატორით გაშვება", + "Portable mode": "პორტატული რეჟიმი", + "DEBUG BUILD": "დებაგ ანაწყობი", + "Here you can change UniGetUI's behaviour regarding the following shortcuts. Checking a shortcut will make UniGetUI delete it if if gets created on a future upgrade. Unchecking it will keep the shortcut intact": "აქ შეგიძლიათ შეცვალოთ UniGetUI-ის ქცევა შემდეგ მალსახმობებთან მიმართებაში. მალსახმობის მონიშვნით UniGetUI წაშლის მათ იმ შემთხვევაში თუ მომავალი განახლებისას შეიქმნებიან. მონიშვნის მოხსნა დატოვებს მალსახმობს ხელუხლებლად.", + "Manual scan": "ხელით სკანირება", + "Existing shortcuts on your desktop will be scanned, and you will need to pick which ones to keep and which ones to remove.": "მოხდება სამუშაო მაგიდაზე არსებული მალსახმობების სკანირება და თქვენ დაგჭირდებათ შერჩევა თუ რომელი დატოვოთ და რომელი წაშალოთ.", + "Delete?": "წაიშალოს?", + "I understand": "გასაგებია", + "Chocolatey setup changed": "Chocolatey-ის კონფიგურაცია შეიცვალა", + "UniGetUI no longer includes its own private Chocolatey installation. A legacy UniGetUI-managed Chocolatey installation was detected for this user profile, but system Chocolatey was not found. Chocolatey will stay unavailable in UniGetUI until Chocolatey is installed on the system and UniGetUI is restarted. Applications previously installed through UniGetUI's bundled Chocolatey may still appear under other sources such as Local PC or WinGet.": "UniGetUI აღარ მოიცავს Chocolatey-ის საკუთარ კერძო ინსტალაციას. ამ მომხმარებლის პროფილისთვის აღმოჩნდა UniGetUI-ით მართული Chocolatey-ის ძველი ინსტალაცია, მაგრამ სისტემაში Chocolatey ვერ მოიძებნა. Chocolatey მიუწვდომელი დარჩება UniGetUI-ში, სანამ Chocolatey არ დაინსტალირდება სისტემაში და UniGetUI არ გადაიტვირთება. პროგრამები, რომლებიც ადრე UniGetUI-ის ჩაშენებული Chocolatey-ით იყო დაყენებული, შეიძლება მაინც გამოჩნდნენ სხვა წყაროებში, როგორიცაა ლოკალური კომპიუტერი ან WinGet.", + "NOTE: This troubleshooter can be disabled from UniGetUI Settings, on the WinGet section": "შენიშვნა: ეს პრობლემების გადამჭრელი შეგიძლიათ გამორთოთ UniGetUI-ის პარამეტრებიდან, WinGet სექციაში.", + "Restart": "გადატვირთვა", + "Are you sure you want to delete all shortcuts?": "დარწმუნებული ხართ, რომ გინდათ წაშალოთ ყველა მალსახმობი?", + "Any new shorcuts created during an install or an update operation will be deleted automatically, instead of showing a confirmation prompt the first time they are detected.": "ინსტალაციის ან განახლების ოპერაციის დროს შექმნილი ნებისმიერი ახალი მალსახმობი ავტომატურად წაიშლება, ნაცვლად იმისა, რომ პირველად აღმოჩენისას გამოჩნდეს დადასტურების მოთხოვნა.", + "Any shorcuts created or modified outside of UniGetUI will be ignored. You will be able to add them via the {0} button.": "UniGetUI-ის გარეთ შექმნილი ან შეცვლილი მალსახმობი იგნორირებული იქნება. მათ დამატებას {0} ღილაკის საშუალებით შეძლებთ.", + "Are you really sure you want to enable this feature?": "დარწმუნებული ხართ, რომ გსურთ ამ ფუნქციის ჩართვა?", + "No new shortcuts were found during the scan.": "სკანირებისას არ იქნა ნაპოვნი ახალი მალსახმობები.", + "How to add packages to a bundle": "როგორ დავამატოთ პაკეტი კრებულში", + "In order to add packages to a bundle, you will need to: ": "იმისთვის, რომ დაამატოთ პაკეტები კრებულში საჭიროა:", + "1. Navigate to the \"{0}\" or \"{1}\" page.": "1. გადადით {0} ან {1} გვერდზე.", + "2. Locate the package(s) you want to add to the bundle, and select their leftmost checkbox.": "2. მოძებნეთ პაკეტი(ები) რომლბეიც გინდათ დაამატოთ კრებულში, და მონიშნეთ მათ გასწვრი ყველაზე მარცხენა თოლია.", + "3. When the packages you want to add to the bundle are selected, find and click the option \"{0}\" on the toolbar.": "3. როდესაც შეარჩევთ პაკეტებს, რომელთა დამატება გსურთ კრებულში, იპოვეთ და დააწკაპუნეთ ოფციაზე \"{0}\" ხელსაწყოთა პანელზე.", + "4. Your packages will have been added to the bundle. You can continue adding packages, or export the bundle.": "4. თქვენი პაკეტები დაემატება კრებულს. შეგიძლიათ გააგრძელოთ პაკეტების დამატება, ან კრებულის ექსპორტი.", + "Which backup do you want to open?": "რომელი ბექაფის გახსნა გსურთ?", + "Select the backup you want to open. Later, you will be able to review which packages you want to install.": "შეარჩიეთ ბექაფი რომლის გახსნაც გსურთ. მოგივანებით თქვენ შეძლებთ განიხილოთ თუ რომელი პაკეტების/პროგრამების აღგენა გსურთ.", + "There are ongoing operations. Quitting UniGetUI may cause them to fail. Do you want to continue?": "მიმდინარეობს ოერაციები. UniGetUI-ის დახურვა მათ ჩაშლას გამოიწვევს. გსურთ გარძელება?", + "UniGetUI or some of its components are missing or corrupt.": "UniGetUI ან მისი ზოგიერთი კომპონენტი ვერ იქნა ნაპოვნი ან დაზიანებულია.", + "It is strongly recommended to reinstall UniGetUI to adress the situation.": "ამ სიტუაციაში დიდწილად რეკომენდებულია UniGetUI-ის ხელახლა ინსტალაცია", + "Refer to the UniGetUI Logs to get more details regarding the affected file(s)": "ჩახედეთ UniGetUI-ის ჟურნალში, რომ გაიგოთ მეტი ინფორმაცია მონაწილე ფაილ(ებ)ის შესახებ.", + "Integrity checks can be disabled from the Experimental Settings": "ინტეგრულების შემოწმება შეგიძლიათ გამორთოთ ექსპერიმენტული პარამეტრებიდან", + "Repair UniGetUI": "UniGetUI-ის შეკეთება", + "Live output": "პირდაპირი გამოსავალი", + "This package bundle had some settings that are potentially dangerous, and may be ignored by default.": "პაკეტების ეს კრებული შეიცავს ზოგიერთ პარამეტრს, რომლებიც პოტენციურად საშიშია და შესაძლოა ინგორირებულ იქნას ნაგულისხმევად.", + "Entries that show in YELLOW will be IGNORED.": "ყვითლად მონიშნული ჩანაწერები იგნორირებული იქნება.", + "Entries that show in RED will be IMPORTED.": "წითლად მონიშნული ჩანაწერები იმპორტირებული იქნება.", + "You can change this behavior on UniGetUI security settings.": "თქვენ შეგიძლიათ ამის შეცვლა UniGetUI-ის უსაფრთხოების პარამეტრებში.", + "Open UniGetUI security settings": "UniGetUI-ის უსაფრთხოების პარამეტრების გახსნა", + "Should you modify the security settings, you will need to open the bundle again for the changes to take effect.": "თუ უსაფრთხოების პარამეტრებს შეცვლით, ცვლილებების ძალაში შესასვლელად კრებულის ხელახლა გახსნა დაგჭირდებათ.", + "Details of the report:": "რეპორტის დეტალები:", + "Are you sure you want to create a new package bundle? ": "დარწმუნებული ხართ, რომ გინდათ ახალი პაკეტების კრებულის შექმნა?", + "Any unsaved changes will be lost": "ნებისმიერი შეუნახავი ცვლილება დაიკარგება", + "Warning!": "გაფრთხილება!", + "For security reasons, custom command-line arguments are disabled by default. Go to UniGetUI security settings to change this. ": "უსაფრთხოების მიზეზებიდან გამომდინარე მორგებული ბრძანების არგუმენტები ნაგულისხმევად გამორთულია. შესაცვლელად გადადით UniGetUI-ის უსაფრთხოების პარამეტრებზე.", + "Change default options": "ნაგულისხმევი პარამეტრების შეცვლა", + "Ignore future updates for this package": "ამ პაკეტის მომავალი განახლებებსი იგნორირება", + "For security reasons, pre-operation and post-operation scripts are disabled by default. Go to UniGetUI security settings to change this. ": "უსაფრთხოების მიზეზებიდან გამომდინარე პოსტ ოპერაციული და პრე ოპერაციული სკრიპტები ნაგულისხმევად გამორთულია. შესაცვლელად გადადით UniGetUI-ის უსაფრთხოების პარამეტრებზე.", + "You can define the commands that will be run before or after this package is installed, updated or uninstalled. They will be run on a command prompt, so CMD scripts will work here.": "თქვენ შეგიძლიათ განსაზღვროთ ბძანებები, რომლებიც გაეშვება პაკეტის ინსტალაციის განახლების და დეინსტალაციის დაწყებამდე ან შემდეგ. ბრძანებები ტერმინალში გაეშვება, ასე რომ შეგიძლიათ CMD სკრიპტების გამოყენებაც.", + "Change this and unlock": "შეცვალე ეს და განბლოკე", + "{0} Install options are currently locked because {0} follows the default install options.": "{0} ინსტალაციის პარამეტრები ამჟამად დაბლოკილია იმიტომ, რომ {0} იყენებს ნაგულისმევ ინსტალაციის პარამეტრებს.", + "Unset or unknown": "არ არის მითითებული ან უცნობია", + "This package has no screenshots or is missing the icon? Contrbute to UniGetUI by adding the missing icons and screenshots to our open, public database.": "ამ პაკეტს არ აქვს სქრინშოტები ან აკლია ხატულა? შეიტანეთ წვლილი UniGetUI-ში დაკარგული ხატულების და სქრინშოტების დამატებით ჩვენს ღია, საჯარო მონაცემთა ბაზაში.", + "Become a contributor": "გახდი მონაწილე", + "Update to {0} available": "ხელმისაწვდომია განახლება {0}-მდე", + "Reinstall": "ხელახალი ინსტალაცია", + "Installer not available": "ინსტალატორი არ არის ხელმისაწვდომი", + "Version:": "ვერსია:", + "UniGetUI Version {0}": "UniGetUI ვერსია {0}", + "Performing backup, please wait...": "ბექაფის შექმნა, გთხოვთ მოიცადოთ...", + "An error occurred while logging in: ": "შეცდომა შესვლისას:", + "Fetching available backups...": "ხელმისაწვდომი ბექაფების ჩამოტვირთვა...", + "Done!": "დასრულდა!", + "The cloud backup has been loaded successfully.": "ღრუბლოვანი ბექაფი წარმატებით ჩაიტვირთა.", + "An error occurred while loading a backup: ": "შეცდომა ბექაფის ჩატვირთვისას:", + "Backing up packages to GitHub Gist...": "პაკეტების ბექაფი GitHub Gist-ში...", + "Backup Successful": "წარმატებული ბექაფი", + "The cloud backup completed successfully.": "ღღუბლოვანი ბექაფი წარმატებით დასრულდა.", + "Could not back up packages to GitHub Gist: ": "ვერ შევნიახე პაკეტების ბეაფი GitHub Gist-ში: ", + "It is not guaranteed that the provided credentials will be stored safely, so you may as well not use the credentials of your bank account": "გარანტირებული არ არის, რომ მოწოდებული ანგარიშები უსაფრთხოდ შეინახება, ასე რომ თქვენ შეიძლება ასევე არ გამოიყენოთ თქვენი საბანკო ანგარიშის მონაცემები", + "Enable the automatic WinGet troubleshooter": "WinGet-ის ავტომატური შემკეთებლის ჩართვა", + "Add updates that fail with a 'no applicable update found' to the ignored updates list": "განახლებების რომლებიც ჩაიშალა 'შესაძლო განახლებები ვერ მოიძებნა' ინგორირებული განახლებების სიაში დამატება", + "Invalid selection": "არასწორი მონიშვნა", + "No package was selected": "არცერთი პაკეტი არ არის მონიშნული", + "More than 1 package was selected": "მონიშნულია 1-ზე მეტი პაკეტი", + "List": "სია", + "Grid": "ბადე", + "Icons": "ხატულები", + "\"{0}\" is a local package and does not have available details": "\"{0}\" ლოკალური პაკეტია და არ აქვს ხელმისაწვდომი დეტალები", + "\"{0}\" is a local package and is not compatible with this feature": "\"{0}\" ლოკლაური პაკეტია და არ არის თავსებადი ამ ფუნქციასთან", + "Add packages to bundle": "პაკეტების კრებულში დამატება", + "Preparing packages, please wait...": "პაკეტების მომზადება, გთხოვთ მოიცადოთ...", + "Loading packages, please wait...": "პაკეტების ჩატვირთვა, გთხოვთ მოიცადოთ...", + "Saving packages, please wait...": "პაკეტების შენახვა, გთხოვთ მოიცადოთ...", + "The bundle was created successfully on {0}": "კრებული წარმატებით შეიქმნა {0}-ში", + "User profile": "მომხმარებლის პროფილი", + "Error": "შეცდომა", + "Log in failed: ": "შესვლა ჩაიშალა:", + "Log out failed: ": "გამოსვლა ჩაიშალა:", + "Package backup settings": "პაკეტის ბექაფის პარამეტრები", + "Manage UniGetUI autostart behaviour from the Settings app": "UniGetUI-ის ავტომატური გაშვების ქცევის მართვა", + "Choose how many operations shoulds be performed in parallel": "აირჩიეთ, რამდენი ოპერაცია უნდა შესრულდეს პარალელურად", + "Something went wrong while launching the updater.": "რაღაც ჩაიშალა განმაახლებლის გაშვებისას", + "Please try again later": "გთხოვთ სცადოთ მოგვიანებით", + "Show the release notes after UniGetUI is updated": "რელიზის ჩანაწერების ჩვენება UniGetUI-ის განახლების შემდეგ" +} diff --git a/src/Languages/lang_kn.json b/src/Languages/lang_kn.json new file mode 100644 index 0000000..c303ae9 --- /dev/null +++ b/src/Languages/lang_kn.json @@ -0,0 +1,850 @@ +{ + "{0} of {1} operations completed": "{1} ರಲ್ಲಿ {0} ಕಾರ್ಯಾಚರಣೆಗಳು ಪೂರ್ಣಗೊಂಡಿವೆ", + "{0} is now {1}": "{0} ಈಗ {1} ಆಗಿದೆ", + "Enabled": "ಸಕ್ರಿಯಗೊಂಡಿದೆ", + "Disabled": "ಅಚೇತನಗೊಂಡಿದೆ", + "Privacy": "ಗೌಪ್ಯತೆ", + "Hide my username from the logs": "ಲಾಗ್‌ಗಳಿಂದ ನನ್ನ ಬಳಕೆದಾರ ಹೆಸರನ್ನು ಮರೆಮಾಡಿ", + "Replaces your username with **** in the logs. Restart UniGetUI to also hide it from already-recorded entries.": "ಲಾಗ್‌ಗಳಲ್ಲಿ ನಿಮ್ಮ ಬಳಕೆದಾರ ಹೆಸರನ್ನು **** ನಿಂದ ಬದಲಾಯಿಸುತ್ತದೆ. ಈಗಾಗಲೇ ದಾಖಲಾದ ನಮೂದುಗಳಿಂದಲೂ ಅದನ್ನು ಮರೆಮಾಡಲು UniGetUI ಅನ್ನು ಮರುಪ್ರಾರಂಭಿಸಿ.", + "Your last update attempt did not complete.": "ನಿಮ್ಮ ಹಿಂದಿನ update ಪ್ರಯತ್ನ ಪೂರ್ಣಗೊಳ್ಳಲಿಲ್ಲ.", + "UniGetUI could not confirm whether the update succeeded. Open the log to see what happened.": "update ಯಶಸ್ವಿಯಾಯಿತೇ ಎಂದು UniGetUI ದೃಢೀಕರಿಸಲು ಸಾಧ್ಯವಾಗಲಿಲ್ಲ. ಏನಾಯಿತು ಎಂಬುದನ್ನು ನೋಡಲು log ತೆರೆಯಿರಿ.", + "View log": "log ವೀಕ್ಷಿಸಿ", + "The installer reported success but did not restart UniGetUI.": "installer ಯಶಸ್ಸು ವರದಿ ಮಾಡಿದೆ, ಆದರೆ UniGetUI ಅನ್ನು ಮರುಪ್ರಾರಂಭಿಸಲಿಲ್ಲ.", + "The installer failed to initialize.": "installer ಆರಂಭಗೊಳ್ಳಲು ವಿಫಲವಾಯಿತು.", + "Setup was canceled before installation began.": "installation ಪ್ರಾರಂಭವಾಗುವ ಮೊದಲು setup ರದ್ದುಗೊಂಡಿತು.", + "A fatal error occurred during the preparation phase.": "ಸಿದ್ಧತಾ ಹಂತದಲ್ಲಿ ಗಂಭೀರ ದೋಷ ಸಂಭವಿಸಿದೆ.", + "A fatal error occurred during installation.": "installation ಸಮಯದಲ್ಲಿ ಗಂಭೀರ ದೋಷ ಸಂಭವಿಸಿದೆ.", + "Installation was canceled while in progress.": "installation ನಡೆಯುತ್ತಿರುವಾಗ ರದ್ದುಗೊಂಡಿತು.", + "The installer was terminated by another process.": "installer ಅನ್ನು ಮತ್ತೊಂದು process ಕೊನೆಗೊಳಿಸಿದೆ.", + "The preparation phase determined the installation cannot proceed.": "installation ಮುಂದುವರಿಯಲು ಸಾಧ್ಯವಿಲ್ಲ ಎಂದು ಸಿದ್ಧತಾ ಹಂತ ನಿರ್ಧರಿಸಿದೆ.", + "The installer could not start. UniGetUI may already be running, or you do not have permission to install.": "installer ಪ್ರಾರಂಭಿಸಲಾಗಲಿಲ್ಲ. UniGetUI ಈಗಾಗಲೇ ಚಾಲನೆಯಲ್ಲಿರಬಹುದು, ಅಥವಾ install ಮಾಡಲು ನಿಮಗೆ ಅನುಮತಿ ಇರದಿರಬಹುದು.", + "Unexpected installer error.": "ಅನಿರೀಕ್ಷಿತ installer ದೋಷ.", + "We are checking for updates.": "ನಾವು updates ಪರಿಶೀಲಿಸುತ್ತಿದ್ದೇವೆ.", + "Please wait": "ದಯವಿಟ್ಟು ನಿರೀಕ್ಷಿಸಿ", + "Great! You are on the latest version.": "ಅದ್ಭುತ! ನೀವು ಇತ್ತೀಚಿನ ಆವೃತ್ತಿಯಲ್ಲಿದ್ದೀರಿ.", + "There are no new UniGetUI versions to be installed": "ಸ್ಥಾಪಿಸಲು ಯಾವುದೇ ಹೊಸ UniGetUI versions ಇಲ್ಲ", + "UniGetUI version {0} is being downloaded.": "UniGetUI version {0} download ಆಗುತ್ತಿದೆ.", + "This may take a minute or two": "ಇದಕ್ಕೆ ಒಂದು ಅಥವಾ ಎರಡು ನಿಮಿಷಗಳು ಹಿಡಿಯಬಹುದು", + "The installer authenticity could not be verified.": "installer ನ ಪ್ರಾಮಾಣಿಕತೆಯನ್ನು ಪರಿಶೀಲಿಸಲು ಸಾಧ್ಯವಾಗಲಿಲ್ಲ.", + "The update process has been aborted.": "update ಪ್ರಕ್ರಿಯೆಯನ್ನು ರದ್ದುಗೊಳಿಸಲಾಗಿದೆ.", + "Auto-update is not yet available on this platform.": "ಈ platform ನಲ್ಲಿ auto-update ಇನ್ನೂ ಲಭ್ಯವಿಲ್ಲ.", + "Please update UniGetUI manually.": "ದಯವಿಟ್ಟು UniGetUI ಅನ್ನು ಕೈಯಾರೆ update ಮಾಡಿ.", + "An error occurred when checking for updates: ": "ನವೀಕರಣಗಳನ್ನು ಪರಿಶೀಲಿಸುವಾಗ ದೋಷ ಸಂಭವಿಸಿದೆ", + "The updater could not be launched.": "updater ಅನ್ನು ಪ್ರಾರಂಭಿಸಲಾಗಲಿಲ್ಲ.", + "The operating system did not start the installer process.": "operating system installer process ಅನ್ನು ಪ್ರಾರಂಭಿಸಲಿಲ್ಲ.", + "UniGetUI is being updated...": "UniGetUI update ಆಗುತ್ತಿದೆ...", + "Update installed.": "update install ಆಗಿದೆ.", + "UniGetUI was updated successfully, but this running copy was not replaced. This usually means you are running a development build. Close this copy and start the newly-installed version to finish.": "UniGetUI ಯಶಸ್ವಿಯಾಗಿ update ಆಗಿದೆ, ಆದರೆ ಚಾಲನೆಯಲ್ಲಿರುವ ಈ copy ಬದಲಾಯಿಸಲ್ಪಟ್ಟಿಲ್ಲ. ಸಾಮಾನ್ಯವಾಗಿ ಇದರಿಂದ ನೀವು development build ನಡೆಸುತ್ತಿರುವಿರಿ ಎಂದರ್ಥ. ಪೂರ್ಣಗೊಳಿಸಲು ಈ copy ಮುಚ್ಚಿ, ಹೊಸದಾಗಿ install ಆದ version ಪ್ರಾರಂಭಿಸಿ.", + "The update could not be applied.": "update ಅನ್ನು ಅನ್ವಯಿಸಲಾಗಲಿಲ್ಲ.", + "Installer exit code {0}: {1}": "ಇನ್‌ಸ್ಟಾಲರ್ ನಿರ್ಗಮನ ಕೋಡ್ {0}: {1}", + "Update cancelled.": "update ರದ್ದುಗೊಂಡಿದೆ.", + "Authentication was cancelled.": "ದೃಢೀಕರಣ ರದ್ದುಗೊಂಡಿದೆ.", + "Installer exit code {0}": "ಇನ್‌ಸ್ಟಾಲರ್ ನಿರ್ಗಮನ ಕೋಡ್ {0}", + "Operation in progress": "ಕಾರ್ಯಾಚರಣೆ ಪ್ರಗತಿಯಲ್ಲಿದೆ", + "Please wait...": "ದಯವಿಟ್ಟು ನಿರೀಕ್ಷಿಸಿ...", + "Success!": "ಯಶಸ್ಸು!", + "Failed": "ವಿಫಲವಾಗಿದೆ", + "An error occurred while processing this package": "ಈ ಪ್ಯಾಕೇಜ್ ಅನ್ನು ಪ್ರಕ್ರಿಯೆಗೊಳಿಸುವಾಗ ದೋಷ ಸಂಭವಿಸಿದೆ", + "Installer": "ಇನ್‌ಸ್ಟಾಲರ್", + "Executable": "ಕಾರ್ಯಗತಗೊಳಿಸಬಹುದಾದ ಫೈಲ್", + "MSI": "MSI", + "Compressed file": "ಸಂಕುಚಿತ ಫೈಲ್", + "MSIX": "MSIX", + "WinGet was repaired successfully": "WinGet ಯಶಸ್ವಿಯಾಗಿ ಸರಿಪಡಿಸಲಾಗಿದೆ", + "It is recommended to restart UniGetUI after WinGet has been repaired": "WinGet ಸರಿಪಡಿಸಿದ ನಂತರ UniGetUI ಅನ್ನು ಮರುಪ್ರಾರಂಭಿಸುವುದು ಶಿಫಾರಸು ಮಾಡಲಾಗಿದೆ", + "WinGet could not be repaired": "WinGet ಅನ್ನು ಸರಿಪಡಿಸಲಾಗಲಿಲ್ಲ", + "An unexpected issue occurred while attempting to repair WinGet. Please try again later": "WinGet ಅನ್ನು ದುರಸ್ತಿ ಮಾಡಲು ಪ್ರಯತ್ನಿಸುವಾಗ ಅನಿರೀಕ್ಷಿತ ಸಮಸ್ಯೆ ಸಂಭವಿಸಿದೆ. ದಯವಿಟ್ಟು ನಂತರ ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ", + "Log in to enable cloud backup": "Cloud backup ಸಕ್ರಿಯಗೊಳಿಸಲು ಲಾಗಿನ್ ಮಾಡಿ", + "Backup Failed": "ಬ್ಯಾಕಪ್ ವಿಫಲವಾಗಿದೆ", + "Downloading backup...": "backup ಡೌನ್‌ಲೋಡ್ ಆಗುತ್ತಿದೆ...", + "An update was found!": "ನವೀಕರಣ ಕಂಡುಬಂದಿದೆ!", + "{0} can be updated to version {1}": "{0} ಅನ್ನು version {1} ಗೆ update ಮಾಡಬಹುದು", + "Updates found!": "updates ಕಂಡುಬಂದಿವೆ!", + "{0} packages can be updated": "{0} packages update ಮಾಡಬಹುದು", + "{0} is being updated to version {1}": "{0} ಅನ್ನು version {1} ಗೆ update ಮಾಡಲಾಗುತ್ತಿದೆ", + "{0} packages are being updated": "{0} packages update ಆಗುತ್ತಿವೆ", + "You have currently version {0} installed": "ನಿಮ್ಮಲ್ಲಿ ಪ್ರಸ್ತುತ version {0} install ಆಗಿದೆ", + "Desktop shortcut created": "Desktop shortcut ರಚಿಸಲಾಗಿದೆ", + "UniGetUI has detected a new desktop shortcut that can be deleted automatically.": "UniGetUI ಸ್ವಯಂಚಾಲಿತವಾಗಿ ಅಳಿಸಬಹುದಾದ ಹೊಸ desktop shortcut ಅನ್ನು ಪತ್ತೆಹಚ್ಚಿದೆ.", + "{0} desktop shortcuts created": "{0} desktop shortcuts ರಚಿಸಲಾಗಿದೆ", + "UniGetUI has detected {0} new desktop shortcuts that can be deleted automatically.": "ಸ್ವಯಂಚಾಲಿತವಾಗಿ ಅಳಿಸಬಹುದಾದ {0} ಹೊಸ desktop shortcuts ಗಳನ್ನು UniGetUI ಪತ್ತೆಹಚ್ಚಿದೆ.", + "Attention required": "ಗಮನ ಅಗತ್ಯವಿದೆ", + "Restart required": "ಮರುಪ್ರಾರಂಭ ಅಗತ್ಯವಿದೆ", + "1 update is available": "1 ನವೀಕರಣ ಲಭ್ಯವಿದೆ", + "{0} updates are available": "{0} updates ಲಭ್ಯವಿವೆ", + "Everything is up to date": "ಎಲ್ಲವೂ ನವೀಕೃತವಾಗಿದೆ", + "Discover Packages": "ಪ್ಯಾಕೇಜ್‌ಗಳನ್ನು ಕಂಡುಹಿಡಿಯಿರಿ", + "Available Updates": "ಲಭ್ಯವಿರುವ ನವೀಕರಣಗಳು", + "Installed Packages": "ಸ್ಥಾಪಿತ ಪ್ಯಾಕೇಜ್‌ಗಳು", + "UniGetUI Version {0} by Devolutions": "Devolutions ನಿಂದ UniGetUI ಆವೃತ್ತಿ {0}", + "Show UniGetUI": "UniGetUI ತೋರಿಸಿ", + "Quit": "ನಿರ್ಗಮಿಸಿ", + "Are you sure?": "ನೀವು ಖಚಿತವಾಗಿ ಇದೀರಾ?", + "Do you really want to uninstall {0}?": "ನೀವು ನಿಜವಾಗಿಯೂ {0} ಅನ್ನು ಅನ್‌ಇನ್‌ಸ್ಟಾಲ್ ಮಾಡಲು ಬಯಸುವಿರಾ?", + "Do you really want to uninstall the following {0} packages?": "ಕೆಳಗಿನ {0} ಪ್ಯಾಕೇಜ್‌ಗಳನ್ನು ನಿಜವಾಗಿಯೂ ಅನ್‌ಇನ್‌ಸ್ಟಾಲ್ ಮಾಡಲು ಬಯಸುವಿರಾ?", + "No": "ಇಲ್ಲ", + "Yes": "ಹೌದು", + "Partial": "ಭಾಗಶಃ", + "View on UniGetUI": "UniGetUI ನಲ್ಲಿ ನೋಡಿ", + "Update": "ನವೀಕರಿಸಿ", + "Open UniGetUI": "UniGetUI ತೆರೆಯಿರಿ", + "Update all": "ಎಲ್ಲವನ್ನೂ update ಮಾಡಿ", + "Update now": "ಈಗ update ಮಾಡಿ", + "Installer host changed since the installed version.\n": "install ಆಗಿರುವ version ನಂತರ installer host ಬದಲಾಗಿದೆ.\n", + "This package is on the queue": "ಈ package queue ಯಲ್ಲಿದೆ", + "installing": "ಸ್ಥಾಪಿಸಲಾಗುತ್ತಿದೆ", + "updating": "ನವೀಕರಿಸಲಾಗುತ್ತಿದೆ", + "uninstalling": "ಅನ್‌ಇನ್‌ಸ್ಟಾಲ್ ಮಾಡಲಾಗುತ್ತಿದೆ", + "installed": "ಸ್ಥಾಪಿಸಲಾಗಿದೆ", + "Retry": "ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ", + "Install": "ಸ್ಥಾಪಿಸಿ", + "Uninstall": "ಅನ್‌ಇನ್‌ಸ್ಟಾಲ್ ಮಾಡಿ", + "Open": "ತೆರೆಯಿರಿ", + "Operation profile:": "ಕಾರ್ಯಾಚರಣೆ profile:", + "Follow the default options when installing, upgrading or uninstalling this package": "ಈ ಪ್ಯಾಕೇಜ್ ಅನ್ನು ಸ್ಥಾಪಿಸುವಾಗ, upgrade ಮಾಡುವಾಗ ಅಥವಾ uninstall ಮಾಡುವಾಗ default options ಅನ್ನು ಅನುಸರಿಸಿ", + "The following settings will be applied each time this package is installed, updated or removed.": "ಈ package install, update ಅಥವಾ remove ಆಗುವ ಪ್ರತಿಸಾರಿ ಕೆಳಗಿನ settings ಅನ್ವಯಿಸಲಾಗುತ್ತದೆ.", + "Version to install:": "ಸ್ಥಾಪಿಸಬೇಕಾದ version:", + "Architecture to install:": "ಸ್ಥಾಪಿಸಲು ವಾಸ್ತುಶಿಲ್ಪ:", + "Installation scope:": "ಸ್ಥಾಪನಾ ವ್ಯಾಪ್ತಿ:", + "Install location:": "ಸ್ಥಾಪನಾ ಸ್ಥಳ:", + "Select": "ಆಯ್ಕೆಮಾಡಿ", + "Reset": "ಮರುಹೊಂದಿಸಿ", + "Custom install arguments:": "ಕಸ್ಟಮ್ ಸ್ಥಾಪನಾ ಆರ್ಗ್ಯುಮೆಂಟ್‌ಗಳು:", + "Custom update arguments:": "ಕಸ್ಟಮ್ ನವೀಕರಣ ಆರ್ಗ್ಯುಮೆಂಟ್‌ಗಳು:", + "Custom uninstall arguments:": "ಕಸ್ಟಮ್ ಅನ್‌ಇನ್‌ಸ್ಟಾಲ್ ಆರ್ಗ್ಯುಮೆಂಟ್‌ಗಳು:", + "Pre-install command:": "ಸ್ಥಾಪನೆಗೂ ಮುಂಚಿನ command:", + "Post-install command:": "ಸ್ಥಾಪನೆಯ ನಂತರದ command:", + "Abort install if pre-install command fails": "pre-install command ವಿಫಲವಾದರೆ ಸ್ಥಾಪನೆಯನ್ನು ನಿಲ್ಲಿಸಿ", + "Pre-update command:": "update ಮುಂಚಿನ command:", + "Post-update command:": "update ನಂತರದ command:", + "Abort update if pre-update command fails": "pre-update command ವಿಫಲವಾದರೆ ನವೀಕರಣವನ್ನು ನಿಲ್ಲಿಸಿ", + "Pre-uninstall command:": "uninstall ಮುಂಚಿನ command:", + "Post-uninstall command:": "uninstall ನಂತರದ command:", + "Abort uninstall if pre-uninstall command fails": "pre-uninstall command ವಿಫಲವಾದರೆ ಅಸ್ಥಾಪನೆಯನ್ನು ನಿಲ್ಲಿಸಿ", + "Command-line to run:": "ನಡೆಯಬೇಕಾದ command-line:", + "Save and close": "ಉಳಿಸಿ ಮತ್ತು ಮುಚ್ಚಿ", + "General": "ಸಾಮಾನ್ಯ", + "Architecture & Location": "ವಾಸ್ತುಶಿಲ್ಪ ಮತ್ತು ಸ್ಥಳ", + "Command-line": "ಕಮಾಂಡ್-ಲೈನ್", + "Close apps": "ಅಪ್ಲಿಕೇಶನ್‌ಗಳನ್ನು ಮುಚ್ಚಿ", + "Pre/Post install": "ಸ್ಥಾಪನೆಗೂ ಮೊದಲು/ನಂತರ", + "Select the processes that should be closed before this package is installed, updated or uninstalled.": "ಈ ಪ್ಯಾಕೇಜ್ ಸ್ಥಾಪನೆ, ನವೀಕರಣ ಅಥವಾ uninstall ಆಗುವ ಮೊದಲು ಮುಚ್ಚಬೇಕಾದ processes ಗಳನ್ನು ಆಯ್ಕೆಮಾಡಿ.", + "Write here the process names here, separated by commas (,)": "process ಹೆಸರುಗಳನ್ನು ಇಲ್ಲಿ commas (,) ಮೂಲಕ ಬೇರ್ಪಡಿಸಿ ಬರೆಯಿರಿ", + "Try to kill the processes that refuse to close when requested to": "ಮುಚ್ಚುವಂತೆ ಕೇಳಿದಾಗ ನಿರಾಕರಿಸುವ processes ಗಳನ್ನು ಕೊಲ್ಲಲು ಪ್ರಯತ್ನಿಸಿ", + "Run as admin": "admin ಆಗಿ ಚಾಲನೆ ಮಾಡಿ", + "Interactive installation": "Interactive ಸ್ಥಾಪನೆ", + "Skip hash check": "hash check ಬಿಟ್ಟುಬಿಡಿ", + "Uninstall previous versions when updated": "update ಆದಾಗ ಹಿಂದಿನ versions ಗಳನ್ನು uninstall ಮಾಡಿ", + "Skip minor updates for this package": "ಈ ಪ್ಯಾಕೇಜ್‌ಗೆ ಸಣ್ಣ ನವೀಕರಣಗಳನ್ನು ಬಿಟ್ಟುಬಿಡಿ", + "Automatically update this package": "ಈ ಪ್ಯಾಕೇಜ್ ಅನ್ನು ಸ್ವಯಂಚಾಲಿತವಾಗಿ ನವೀಕರಿಸಿ", + "{0} installation options": "{0} installation ಆಯ್ಕೆಗಳು", + "Latest": "ಇತ್ತೀಚಿನ", + "PreRelease": "ಪ್ರೀರಿಲೀಸ್", + "Default": "ಡೀಫಾಲ್ಟ್", + "Manage ignored updates": "ನಿರ್ಲಕ್ಷ್ಯಗೊಳಿಸಲಾದ ನವೀಕರಣಗಳನ್ನು ನಿರ್ವಹಿಸಿ", + "The packages listed here won't be taken in account when checking for updates. Double-click them or click the button on their right to stop ignoring their updates.": "ಇಲ್ಲಿ ಪಟ್ಟಿ ಮಾಡಲಾದ package ಗಳನ್ನು updates ಪರಿಶೀಲಿಸುವಾಗ ಗಣನೆಗೆ ತೆಗೆದುಕೊಳ್ಳಲಾಗುವುದಿಲ್ಲ. ಅವುಗಳ updates ಅನ್ನು ನಿರ್ಲಕ್ಷಿಸುವುದನ್ನು ನಿಲ್ಲಿಸಲು ಅವುಗಳ ಮೇಲೆ double-click ಮಾಡಿ ಅಥವಾ ಬಲಭಾಗದ button ಮೇಲೆ click ಮಾಡಿ.", + "Reset list": "ಪಟ್ಟಿಯನ್ನು ಮರುಹೊಂದಿಸಿ", + "Do you really want to reset the ignored updates list? This action cannot be reverted": "ನೀವು ನಿಜವಾಗಿಯೂ ನಿರ್ಲಕ್ಷಿಸಲಾದ ನವೀಕರಣಗಳ ಪಟ್ಟಿಯನ್ನು ಮರುಹೊಂದಿಸಲು ಬಯಸುವಿರಾ? ಈ ಕ್ರಿಯೆಯನ್ನು ಹಿಂದಿರುಗಿಸಲಾಗುವುದಿಲ್ಲ", + "No ignored updates": "ಯಾವುದೇ ನಿರ್ಲಕ್ಷಿತ ನವೀಕರಣಗಳಿಲ್ಲ", + "Package Name": "ಪ್ಯಾಕೇಜ್ ಹೆಸರು", + "Package ID": "ಪ್ಯಾಕೇಜ್ ID", + "Ignored version": "ನಿರ್ಲಕ್ಷಿತ ಆವೃತ್ತಿ", + "New version": "ಹೊಸ ಆವೃತ್ತಿ", + "Source": "ಮೂಲ", + "All versions": "ಎಲ್ಲಾ ಆವೃತ್ತಿಗಳು", + "Unknown": "ಅಪರಿಚಿತ", + "Up to date": "ನವೀಕರಿತವಾಗಿದೆ", + "Package {name} from {manager}": "{manager} ನಿಂದ ಪ್ಯಾಕೇಜ್ {name}", + "Remove {0} from ignored updates": "ನಿರ್ಲಕ್ಷಿತ ನವೀಕರಣಗಳಿಂದ {0} ಅನ್ನು ತೆಗೆದುಹಾಕಿ", + "Cancel": "ರದ್ದುಮಾಡಿ", + "Administrator privileges": "ನಿರ್ವಾಹಕ ಹಕ್ಕುಗಳು", + "This operation is running with administrator privileges.": "ಈ ಕಾರ್ಯಾಚರಣೆ administrator privileges ಜೊತೆ ನಡೆಯುತ್ತಿದೆ.", + "Interactive operation": "Interactive ಕಾರ್ಯಾಚರಣೆ", + "This operation is running interactively.": "ಈ ಕಾರ್ಯಾಚರಣೆ ಪರಸ್ಪರಕ್ರಿಯಾತ್ಮಕವಾಗಿ ನಡೆಯುತ್ತಿದೆ.", + "You will likely need to interact with the installer.": "ನೀವು installer ಜೊತೆ ಸಂವಹನ ನಡೆಸಬೇಕಾಗುವ ಸಾಧ್ಯತೆ ಇದೆ.", + "Integrity checks skipped": "Integrity checks ಬಿಟ್ಟುಕೊಡಲಾಗಿದೆ", + "Integrity checks will not be performed during this operation.": "ಈ ಕಾರ್ಯಾಚರಣೆಯ ವೇಳೆ integrity checks ನಡೆಸಲಾಗುವುದಿಲ್ಲ.", + "Proceed at your own risk.": "ನಿಮ್ಮ ಸ್ವಂತ ಜವಾಬ್ದಾರಿಯಲ್ಲಿ ಮುಂದುವರಿಯಿರಿ.", + "Close": "ಮುಚ್ಚಿ", + "Loading...": "Load ಆಗುತ್ತಿದೆ...", + "Installer SHA256": "ಇನ್‌ಸ್ಟಾಲರ್ SHA256", + "Homepage": "ಮುಖಪುಟ", + "Author": "ಲೇಖಕ", + "Publisher": "ಪ್ರಕಾಶಕ", + "License": "ಪರವಾನಗಿ", + "Manifest": "ಮ್ಯಾನಿಫೆಸ್ಟ್", + "Installer Type": "Installer ಪ್ರಕಾರ", + "Size": "ಗಾತ್ರ", + "Installer URL": "ಇನ್‌ಸ್ಟಾಲರ್ URL", + "Last updated:": "ಕೊನೆಯಾಗಿ ನವೀಕರಿಸಲಾಗಿದೆ:", + "Release notes URL": "ಬಿಡುಗಡೆ ಟಿಪ್ಪಣಿಗಳ URL", + "Package details": "ಪ್ಯಾಕೇಜ್ ವಿವರಗಳು", + "Dependencies:": "ಆಧಾರಗಳು:", + "Release notes": "ಬಿಡುಗಡೆ ಟಿಪ್ಪಣಿಗಳು", + "Screenshots": "ಸ್ಕ್ರೀನ್‌ಶಾಟ್‌ಗಳು", + "This package has no screenshots or is missing the icon? Contribute to UniGetUI by adding the missing icons and screenshots to our open, public database.": "ಈ ಪ್ಯಾಕೇಜ್‌ಗೆ ಯಾವುದೇ ಸ್ಕ್ರೀನ್‌ಶಾಟ್‌ಗಳಿಲ್ಲ ಅಥವಾ ಐಕಾನ್ ಕಾಣೆಯಾಗಿದೆಯೇ? ಕಾಣೆಯಾದ ಐಕಾನ್‌ಗಳು ಮತ್ತು ಸ್ಕ್ರೀನ್‌ಶಾಟ್‌ಗಳನ್ನು ನಮ್ಮ ಮುಕ್ತ, ಸಾರ್ವಜನಿಕ ಡೇಟಾಬೇಸ್‌ಗೆ ಸೇರಿಸುವ ಮೂಲಕ UniGetUI ಗೆ ಕೊಡುಗೆ ನೀಡಿ.", + "Version": "ಆವೃತ್ತಿ", + "Install as administrator": "ನಿರ್ವಾಹಕರಾಗಿ ಸ್ಥಾಪಿಸಿ", + "Update to version {0}": "version {0} ಗೆ update ಮಾಡಿ", + "Installed Version": "ಸ್ಥಾಪಿತ ಆವೃತ್ತಿ", + "Update as administrator": "administrator ಆಗಿ update ಮಾಡಿ", + "Interactive update": "Interactive ನವೀಕರಣ", + "Uninstall as administrator": "administrator ಆಗಿ uninstall ಮಾಡಿ", + "Interactive uninstall": "Interactive ಅನ್‌ಇನ್‌ಸ್ಟಾಲ್", + "Uninstall and remove data": "uninstall ಮಾಡಿ ಮತ್ತು data ತೆಗೆದುಹಾಕಿ", + "Not available": "ಲಭ್ಯವಿಲ್ಲ", + "Installer SHA512": "ಇನ್‌ಸ್ಟಾಲರ್ SHA512", + "Unknown size": "ಅಪರಿಚಿತ ಗಾತ್ರ", + "No dependencies specified": "ಯಾವುದೇ ಅವಲಂಬನೆಗಳನ್ನು ಸೂಚಿಸಲಾಗಿಲ್ಲ", + "mandatory": "ಕಡ್ಡಾಯ", + "optional": "ಐಚ್ಛಿಕ", + "UniGetUI {0} is ready to be installed.": "UniGetUI {0} install ಆಗಲು ಸಿದ್ಧವಾಗಿದೆ.", + "The update process will start after closing UniGetUI": "UniGetUI ಮುಚ್ಚಿದ ನಂತರ update ಪ್ರಕ್ರಿಯೆ ಪ್ರಾರಂಭವಾಗುತ್ತದೆ", + "UniGetUI has been ran as administrator, which is not recommended. When running UniGetUI as administrator, EVERY operation launched from UniGetUI will have administrator privileges. You can still use the program, but we highly recommend not running UniGetUI with administrator privileges.": "UniGetUI ಅನ್ನು administrator ಆಗಿ ಚಾಲನೆ ಮಾಡಲಾಗಿದೆ, ಇದು ಶಿಫಾರಸು ಮಾಡಲಾಗುವುದಿಲ್ಲ. UniGetUI ಅನ್ನು administrator ಆಗಿ ನಡೆಸಿದಾಗ, UniGetUI ಯಿಂದ ಆರಂಭವಾಗುವ ಪ್ರತಿಯೊಂದು ಕಾರ್ಯಾಚರಣೆಯೂ administrator privileges ಹೊಂದಿರುತ್ತದೆ. ನೀವು ಇನ್ನೂ ಪ್ರೋಗ್ರಾಂ ಬಳಸಬಹುದು, ಆದರೆ UniGetUI ಅನ್ನು administrator privileges ಜೊತೆ ನಡೆಸಬಾರದೆಂದು ನಾವು ಬಲವಾಗಿ ಶಿಫಾರಸು ಮಾಡುತ್ತೇವೆ.", + "Share anonymous usage data": "ಅನಾಮಧೇಯ ಬಳಕೆ ಡೇಟಾವನ್ನು ಹಂಚಿಕೊಳ್ಳಿ", + "UniGetUI collects anonymous usage data in order to improve the user experience.": "ಬಳಕೆದಾರ ಅನುಭವವನ್ನು ಉತ್ತಮಗೊಳಿಸಲು UniGetUI ಅನಾಮಧೇಯ ಬಳಕೆ ಡೇಟಾವನ್ನು ಸಂಗ್ರಹಿಸುತ್ತದೆ.", + "Accept": "ಸ್ವೀಕರಿಸಿ", + "Software Updates": "Software ನವೀಕರಣಗಳು", + "Package Bundles": "ಪ್ಯಾಕೇಜ್ bundles", + "Settings": "settings", + "Package Managers": "ಪ್ಯಾಕೇಜ್ ಮ್ಯಾನೇಜರ್‌ಗಳು", + "UniGetUI Log": "UniGetUI ಲಾಗ್", + "Package Manager logs": "Package Manager ದಾಖಲೆಗಳು", + "Operation history": "ಕಾರ್ಯಾಚರಣೆ ಇತಿಹಾಸ", + "Help": "ಸಹಾಯ", + "UniGetUI": "UniGetUI", + "You have installed UniGetUI Version {0}": "ನೀವು UniGetUI Version {0} install ಮಾಡಿದ್ದಾರೆ", + "Disclaimer": "ಘೋಷಣೆ", + "UniGetUI is developed by Devolutions and is not affiliated with any of the compatible package managers.": "UniGetUI ಅನ್ನು Devolutions ಅಭಿವೃದ್ಧಿಪಡಿಸಿದೆ ಮತ್ತು ಇದು ಯಾವುದೇ ಹೊಂದಾಣಿಕೆಯ ಪ್ಯಾಕೇಜ್ ಮ್ಯಾನೇಜರ್‌ಗಳೊಂದಿಗೆ ಸಂಯೋಜಿತವಾಗಿಲ್ಲ.", + "UniGetUI wouldn't have been possible without the help of the contributors. Thank you all 🥳": "contributors ಗಳ ಸಹಾಯವಿಲ್ಲದೆ UniGetUI ಸಾಧ್ಯವಾಗುತ್ತಿರಲಿಲ್ಲ. ಎಲ್ಲರಿಗೂ ಧನ್ಯವಾದಗಳು 🥳", + "UniGetUI uses the following libraries. Without them, UniGetUI wouldn't have been possible.": "UniGetUI ಕೆಳಗಿನ libraries ಗಳನ್ನು ಬಳಸುತ್ತದೆ. ಅವುಗಳಿಲ್ಲದೆ UniGetUI ಸಾಧ್ಯವಾಗುತ್ತಿರಲಿಲ್ಲ.", + "{0} homepage": "{0} ಮುಖಪುಟ", + "UniGetUI has been translated to more than 40 languages thanks to the volunteer translators. Thank you 🤝": "ಸ್ವಯಂಸೇವಕ ಅನುವಾದಕರಿಂದ UniGetUI ಅನ್ನು 40 ಕ್ಕೂ ಹೆಚ್ಚು ಭಾಷೆಗಳಿಗೆ ಅನುವಾದಿಸಲಾಗಿದೆ. ಧನ್ಯವಾದಗಳು 🤝", + "Verbose": "ವಿವರವಾದ", + "1 - Errors": "1 - ದೋಷಗಳು", + "2 - Warnings": "2 - ಎಚ್ಚರಿಕೆಗಳು", + "3 - Information (less)": "3 - ಮಾಹಿತಿ (ಕಡಿಮೆ)", + "4 - Information (more)": "4 - ಮಾಹಿತಿ (ಹೆಚ್ಚು)", + "5 - information (debug)": "5 - ಮಾಹಿತಿ (ಡಿಬಗ್)", + "Warning": "ಎಚ್ಚರಿಕೆ", + "The following settings may pose a security risk, hence they are disabled by default.": "ಕೆಳಗಿನ settings security risk ಉಂಟುಮಾಡಬಹುದು, ಆದ್ದರಿಂದ ಅವು default ಆಗಿ ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ.", + "Enable the settings below if and only if you fully understand what they do, and the implications they may have.": "ಕೆಳಗಿನ settings ಏನು ಮಾಡುತ್ತವೆ ಮತ್ತು ಅವುಗಳಿಂದಾಗುವ ಪರಿಣಾಮಗಳನ್ನು ನೀವು ಸಂಪೂರ್ಣವಾಗಿ ಅರ್ಥಮಾಡಿಕೊಂಡಿದ್ದರೆ ಮಾತ್ರ ಅವನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಿ.", + "The settings will list, in their descriptions, the potential security issues they may have.": "settings ಗಳ ವಿವರಣೆಯಲ್ಲಿ ಅವುಗಳಿಗೆ ಇರಬಹುದಾದ ಭದ್ರತಾ ಸಮಸ್ಯೆಗಳ ಪಟ್ಟಿಯನ್ನು ನೀಡಲಾಗುತ್ತದೆ.", + "The backup will include the complete list of the installed packages and their installation options. Ignored updates and skipped versions will also be saved.": "backup ನಲ್ಲಿ installed packages ಗಳ ಸಂಪೂರ್ಣ ಪಟ್ಟಿಯೂ ಮತ್ತು ಅವುಗಳ installation options ಕೂಡ ಸೇರಿರುತ್ತದೆ. ignored updates ಮತ್ತು skipped versions ಕೂಡ ಉಳಿಸಲಾಗುತ್ತದೆ.", + "The backup will NOT include any binary file nor any program's saved data.": "backup ನಲ್ಲಿ ಯಾವುದೇ binary file ಅಥವಾ ಯಾವುದೇ program ನ saved data ಸೇರಿರುವುದಿಲ್ಲ.", + "The size of the backup is estimated to be less than 1MB.": "backup ಗಾತ್ರವು 1MB ಕ್ಕಿಂತ ಕಡಿಮೆ ಎಂದು ಅಂದಾಜಿಸಲಾಗಿದೆ.", + "The backup will be performed after login.": "login ನಂತರ backup ನಡೆಸಲಾಗುತ್ತದೆ.", + "{pcName} installed packages": "{pcName} ನಲ್ಲಿ install ಆಗಿರುವ packages", + "Current status: Not logged in": "ಪ್ರಸ್ತುತ ಸ್ಥಿತಿ: ಲಾಗಿನ್ ಆಗಿಲ್ಲ", + "You are logged in as {0} (@{1})": "ನೀವು {0} (@{1}) ಆಗಿ login ಆಗಿದ್ದೀರಿ", + "Nice! Backups will be uploaded to a private gist on your account": "ಚೆನ್ನಾಗಿದೆ! Backups ನಿಮ್ಮ ಖಾತೆಯ ಖಾಸಗಿ gist ಗೆ ಅಪ್‌ಲೋಡ್ ಆಗುತ್ತದೆ", + "Select backup": "backup ಆಯ್ಕೆಮಾಡಿ", + "Settings imported from {0}": "{0} ನಿಂದ settings ಆಮದು ಮಾಡಲಾಗಿದೆ", + "UniGetUI Settings": "UniGetUI ಸೆಟ್ಟಿಂಗ್‌ಗಳು", + "Settings exported to {0}": "{0} ಗೆ settings ರಫ್ತು ಮಾಡಲಾಗಿದೆ", + "UniGetUI settings were reset": "UniGetUI settings ಮರುಹೊಂದಿಸಲಾಗಿದೆ", + "Allow pre-release versions": "pre-release ಆವೃತ್ತಿಗಳಿಗೆ ಅನುಮತಿಸಿ", + "Apply": "ಅನ್ವಯಿಸಿ", + "For security reasons, custom command-line arguments are disabled by default. Go to UniGetUI security settings to change this.": "ಭದ್ರತಾ ಕಾರಣಗಳಿಂದ, custom command-line arguments ಅನ್ನು default ಆಗಿ ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ. ಇದನ್ನು ಬದಲಾಯಿಸಲು UniGetUI security settings ಗೆ ಹೋಗಿ.", + "Go to UniGetUI security settings": "UniGetUI ಭದ್ರತಾ ಸೆಟ್ಟಿಂಗ್‌ಗಳಿಗೆ ಹೋಗಿ", + "The following options will be applied by default each time a {0} package is installed, upgraded or uninstalled.": "{0} package install, upgrade ಅಥವಾ uninstall ಆಗುವ ಪ್ರತಿಸಾರಿ ಕೆಳಗಿನ ಆಯ್ಕೆಗಳು default ಆಗಿ ಅನ್ವಯಿಸಲಾಗುತ್ತದೆ.", + "Package's default": "ಪ್ಯಾಕೇಜ್‌ನ default", + "Install location can't be changed for {0} packages": "{0} ಪ್ಯಾಕೇಜ್‌ಗಳಿಗಾಗಿ ಸ್ಥಾಪನಾ ಸ್ಥಳವನ್ನು ಬದಲಾಯಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ", + "The local icon cache currently takes {0} MB": "ಸ್ಥಳೀಯ icon cache ಪ್ರಸ್ತುತ {0} MB ಜಾಗ ಬಳಸುತ್ತಿದೆ", + "Username": "username", + "Password": "ಗುಪ್ತಪದ", + "Credentials": "ಪರಿಚಯ ವಿವರಗಳು", + "It is not guaranteed that the provided credentials will be stored safely": "ಒದಗಿಸಿದ credentials ಸುರಕ್ಷಿತವಾಗಿ ಸಂಗ್ರಹಿಸಲ್ಪಡುವುದಕ್ಕೆ ಖಾತರಿ ಇಲ್ಲ", + "Partially": "ಭಾಗಶಃ", + "Package manager": "ಪ್ಯಾಕೇಜ್ manager", + "Compatible with proxy": "proxy ಜೊತೆಗೆ ಹೊಂದಿಕೊಳ್ಳುತ್ತದೆ", + "Compatible with authentication": "ದೃಢೀಕರಣದೊಂದಿಗೆ ಹೊಂದಿಕೊಳ್ಳುತ್ತದೆ", + "Proxy compatibility table": "Proxy ಹೊಂದಾಣಿಕೆ ಪಟ್ಟಿಕೆ", + "{0} settings": "{0} ಸೆಟ್ಟಿಂಗ್‌ಗಳು", + "{0} status": "{0} ಸ್ಥಿತಿ", + "Default installation options for {0} packages": "{0} ಪ್ಯಾಕೇಜ್‌ಗಳ ಡೀಫಾಲ್ಟ್ ಸ್ಥಾಪನಾ ಆಯ್ಕೆಗಳು", + "Expand version": "ಆವೃತ್ತಿಯನ್ನು ವಿಸ್ತರಿಸಿ", + "The executable file for {0} was not found": "{0} ಗಾಗಿ executable file ಕಂಡುಬಂದಿಲ್ಲ", + "{pm} is disabled": "{pm} ನಿಷ್ಕ್ರಿಯವಾಗಿದೆ", + "Enable it to install packages from {pm}.": "{pm} ನಿಂದ ಪ್ಯಾಕೇಜ್‌ಗಳನ್ನು ಸ್ಥಾಪಿಸಲು ಇದನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಿ.", + "{pm} is enabled and ready to go": "{pm} ಸಕ್ರಿಯವಾಗಿದೆ ಮತ್ತು ಸಿದ್ಧವಾಗಿದೆ", + "{pm} version:": "{pm} ಆವೃತ್ತಿ:", + "{pm} was not found!": "{pm} ಕಂಡುಬಂದಿಲ್ಲ!", + "You may need to install {pm} in order to use it with UniGetUI.": "{pm} ಅನ್ನು UniGetUI ಜೊತೆಗೆ ಬಳಸಲು ನೀವು ಅದನ್ನು install ಮಾಡಬೇಕಾಗಬಹುದು.", + "Scoop Installer - UniGetUI": "Scoop ಸ್ಥಾಪಕ - UniGetUI", + "Scoop Uninstaller - UniGetUI": "Scoop ಅನ್‌ಇನ್‌ಸ್ಟಾಲರ್ - UniGetUI", + "Clearing Scoop cache - UniGetUI": "Scoop ಕ್ಯಾಶೆ ತೆರವುಗೊಳಿಸಲಾಗುತ್ತಿದೆ - UniGetUI", + "Restart UniGetUI to fully apply changes": "ಬದಲಾವಣೆಗಳನ್ನು ಸಂಪೂರ್ಣವಾಗಿ ಅನ್ವಯಿಸಲು UniGetUI ಅನ್ನು ಮರುಪ್ರಾರಂಭಿಸಿ", + "Restart UniGetUI": "UniGetUI ಅನ್ನು ಮರುಪ್ರಾರಂಭಿಸಿ", + "Manage {0} sources": "{0} sources ಅನ್ನು ನಿರ್ವಹಿಸಿ", + "Add source": "ಮೂಲವನ್ನು ಸೇರಿಸಿ", + "Add": "ಸೇರಿಸಿ", + "Source name": "ಮೂಲದ ಹೆಸರು", + "Source URL": "ಮೂಲ URL", + "Other": "ಇತರೆ", + "No minimum age": "ಕನಿಷ್ಠ ವಯಸ್ಸಿಲ್ಲ", + "1 day": "1 ದಿನ", + "{0} days": "{0} ದಿನಗಳು", + "Custom...": "ಕಸ್ಟಮ್...", + "{0} minutes": "{0} ನಿಮಿಷಗಳು", + "1 hour": "1 ಗಂಟೆ", + "{0} hours": "{0} ಗಂಟೆಗಳು", + "1 week": "1 ವಾರ", + "Supports release dates": "ಬಿಡುಗಡೆ ದಿನಾಂಕಗಳನ್ನು ಬೆಂಬಲಿಸುತ್ತದೆ", + "Release date support per package manager": "ಪ್ರತಿ package manager ಗೆ ಬಿಡುಗಡೆ ದಿನಾಂಕ ಬೆಂಬಲ", + "Search for packages": "ಪ್ಯಾಕೇಜ್‌ಗಳನ್ನು ಹುಡುಕಿ", + "Local": "ಸ್ಥಳೀಯ", + "OK": "ಸರಿ", + "Last checked: {0}": "ಕೊನೆಯ ಪರಿಶೀಲನೆ: {0}", + "{0} packages were found, {1} of which match the specified filters.": "{0} packages ಕಂಡುಬಂದಿವೆ, ಅವುಗಳಲ್ಲಿ {1} ನಿರ್ದಿಷ್ಟ filters ಗೆ ಹೊಂದುತ್ತವೆ.", + "{0} selected": "{0} ಆಯ್ಕೆಮಾಡಲಾಗಿದೆ", + "(Last checked: {0})": "(ಕೊನೆಯದಾಗಿ ಪರಿಶೀಲಿಸಲಾಗಿದೆ: {0})", + "All packages selected": "ಎಲ್ಲಾ ಪ್ಯಾಕೇಜ್‌ಗಳನ್ನು ಆಯ್ಕೆಮಾಡಲಾಗಿದೆ", + "Package selection cleared": "ಪ್ಯಾಕೇಜ್ ಆಯ್ಕೆಯನ್ನು ತೆರವುಗೊಳಿಸಲಾಗಿದೆ", + "{0}: {1}": "{0}: {1}", + "More info": "ಇನ್ನಷ್ಟು ಮಾಹಿತಿ", + "GitHub account": "GitHub ಖಾತೆ", + "Log in with GitHub to enable cloud package backup.": "Cloud package backup ಸಕ್ರಿಯಗೊಳಿಸಲು GitHub ಬಳಸಿ ಲಾಗಿನ್ ಮಾಡಿ.", + "More details": "ಇನ್ನಷ್ಟು ವಿವರಗಳು", + "Log in": "ಲಾಗಿನ್ ಮಾಡಿ", + "If you have cloud backup enabled, it will be saved as a GitHub Gist on this account": "ನೀವು cloud backup ಅನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಿದ್ದರೆ, ಅದು ಈ ಖಾತೆಯಲ್ಲಿ GitHub Gist ಆಗಿ ಉಳಿಸಲಾಗುತ್ತದೆ", + "Log out": "ಲಾಗ್ ಔಟ್ ಮಾಡಿ", + "About UniGetUI": "UniGetUI ಬಗ್ಗೆ", + "About": "ಬಗ್ಗೆ", + "Third-party licenses": "ಮೂರನೇ ಪಕ್ಷದ ಪರವಾನಗಿಗಳು", + "Contributors": "ಸಹಯೋಗಿಗಳು", + "Translators": "ಅನುವಾದಕರು", + "Bundle security report": "ಬಂಡಲ್ ಭದ್ರತಾ ವರದಿ", + "The bundle contained restricted content": "bundle ನಲ್ಲಿ ನಿರ್ಬಂಧಿತ ವಿಷಯವಿತ್ತು", + "UniGetUI – Crash Report": "UniGetUI – ಕ್ರ್ಯಾಶ್ ವರದಿ", + "UniGetUI has crashed": "UniGetUI ಕ್ರ್ಯಾಶ್ ಆಗಿದೆ", + "Help us fix this by sending a crash report to Devolutions. All fields below are optional.": "Devolutions ಗೆ ಕ್ರ್ಯಾಶ್ ವರದಿಯನ್ನು ಕಳುಹಿಸುವ ಮೂಲಕ ಇದನ್ನು ಸರಿಪಡಿಸಲು ನಮಗೆ ಸಹಾಯ ಮಾಡಿ. ಕೆಳಗಿನ ಎಲ್ಲಾ ಕ್ಷೇತ್ರಗಳು ಐಚ್ಛಿಕವಾಗಿವೆ.", + "Email (optional)": "ಇಮೇಲ್ (ಐಚ್ಛಿಕ)", + "your@email.com": "your@email.com", + "Additional details (optional)": "ಹೆಚ್ಚುವರಿ ವಿವರಗಳು (ಐಚ್ಛಿಕ)", + "Describe what you were doing when the crash occurred…": "ಕ್ರ್ಯಾಶ್ ಸಂಭವಿಸಿದಾಗ ನೀವು ಏನು ಮಾಡುತ್ತಿದ್ದಿರಿ ಎಂದು ವಿವರಿಸಿ…", + "Crash report": "ಕ್ರ್ಯಾಶ್ ವರದಿ", + "Don't Send": "ಕಳುಹಿಸಬೇಡಿ", + "Send Report": "ವರದಿ ಕಳುಹಿಸಿ", + "Sending…": "ಕಳುಹಿಸಲಾಗುತ್ತಿದೆ…", + "Unsaved changes": "ಉಳಿಸದ ಬದಲಾವಣೆಗಳು", + "You have unsaved changes in the current bundle. Do you want to discard them?": "ಪ್ರಸ್ತುತ bundle ನಲ್ಲಿ ಉಳಿಸದ ಬದಲಾವಣೆಗಳಿವೆ. ಅವನ್ನು ತ್ಯಜಿಸಲು ಬಯಸುವಿರಾ?", + "Discard changes": "ಬದಲಾವಣೆಗಳನ್ನು ತ್ಯಜಿಸಿ", + "Integrity violation": "ಅಖಂಡತೆ ಉಲ್ಲಂಘನೆ", + "UniGetUI or some of its components are missing or corrupt. It is strongly recommended to reinstall UniGetUI to adress the situation.": "UniGetUI ಅಥವಾ ಅದರ ಕೆಲವು ಘಟಕಗಳು ಕಾಣೆಯಾಗಿವೆ ಅಥವಾ ದೋಷಗೊಂಡಿವೆ. ಪರಿಸ್ಥಿತಿಯನ್ನು ಸರಿಪಡಿಸಲು UniGetUI ಅನ್ನು ಮರುಸ್ಥಾಪಿಸುವುದನ್ನು ಬಲವಾಗಿ ಶಿಫಾರಸು ಮಾಡಲಾಗುತ್ತದೆ.", + "• Refer to the UniGetUI Logs to get more details regarding the affected file(s)": "• ಪ್ರಭಾವಿತ file(s) ಬಗ್ಗೆ ಹೆಚ್ಚಿನ ವಿವರಗಳಿಗಾಗಿ UniGetUI Logs ಅನ್ನು ನೋಡಿ", + "• Integrity checks can be disabled from the Experimental Settings": "• Integrity checks ಅನ್ನು Experimental Settings ನಿಂದ ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಬಹುದು", + "Manage shortcuts": "shortcuts ಅನ್ನು ನಿರ್ವಹಿಸಿ", + "UniGetUI has detected the following desktop shortcuts which can be removed automatically on future upgrades": "ಭವಿಷ್ಯದ upgrades ಗಳಲ್ಲಿ ಸ್ವಯಂಚಾಲಿತವಾಗಿ ತೆಗೆದುಹಾಕಬಹುದಾದ ಕೆಳಗಿನ desktop shortcuts ಗಳನ್ನು UniGetUI ಪತ್ತೆಹಚ್ಚಿದೆ", + "Do you really want to reset this list? This action cannot be reverted.": "ನೀವು ನಿಜವಾಗಿಯೂ ಈ ಪಟ್ಟಿಯನ್ನು reset ಮಾಡಲು ಬಯಸುವಿರಾ? ಈ ಕ್ರಿಯೆಯನ್ನು ಹಿಂದಿರುಗಿಸಲಾಗುವುದಿಲ್ಲ.", + "Desktop shortcuts list": "Desktop shortcuts ಪಟ್ಟಿ", + "Open in explorer": "Explorer ನಲ್ಲಿ ತೆರೆಯಿರಿ", + "Remove from list": "ಪಟ್ಟಿಯಿಂದ ತೆಗೆದುಹಾಕಿ", + "When new shortcuts are detected, delete them automatically instead of showing this dialog.": "ಹೊಸ shortcuts ಪತ್ತೆಯಾದಾಗ, ಈ dialog ತೋರಿಸುವುದಕ್ಕೆ ಬದಲು ಅವುಗಳನ್ನು ಸ್ವಯಂಚಾಲಿತವಾಗಿ ಅಳಿಸಿ.", + "Not right now": "ಈಗ ಬೇಡ", + "Missing dependency": "ಕಾಣೆಯಾದ ಅವಲಂಬನೆ", + "UniGetUI requires {0} to operate, but it was not found on your system.": "UniGetUI ಕಾರ್ಯನಿರ್ವಹಿಸಲು {0} ಅಗತ್ಯವಿದೆ, ಆದರೆ ಅದು ನಿಮ್ಮ system ನಲ್ಲಿ ಕಂಡುಬಂದಿಲ್ಲ.", + "Click on Install to begin the installation process. If you skip the installation, UniGetUI may not work as expected.": "ಸ್ಥಾಪನೆ ಪ್ರಕ್ರಿಯೆಯನ್ನು ಪ್ರಾರಂಭಿಸಲು ಸ್ಥಾಪನೆ ಮೇಲೆ ಕ್ಲಿಕ್ ಮಾಡಿ. ನೀವು ಸ್ಥಾಪನೆಯನ್ನು ಬಿಟ್ಟುಹೋದರೆ, UniGetUI ನಿರೀಕ್ಷಿತ ರೀತಿಯಲ್ಲಿ ಕಾರ್ಯನಿರ್ವಹಿಸದಿರಬಹುದು", + "Alternatively, you can also install {0} by running the following command in a Windows PowerShell prompt:": "ವೈಕಲ್ಪಿಕವಾಗಿ, Windows PowerShell prompt ನಲ್ಲಿ ಕೆಳಗಿನ command ಅನ್ನು ನಡೆಸಿ {0} ಅನ್ನು ಸ್ಥಾಪಿಸಬಹುದು:", + "Install {0}": "{0} ಅನ್ನು ಸ್ಥಾಪಿಸಿ", + "Do not show this dialog again for {0}": "{0} ಗಾಗಿ ಈ ಸಂವಾದವನ್ನು ಮತ್ತೆ ತೋರಿಸಬೇಡಿ", + "Please wait while {0} is being installed. A black window may show up. Please wait until it closes.": "{0} ಸ್ಥಾಪಿಸಲಾಗುತ್ತಿರುವಾಗ ದಯವಿಟ್ಟು ನಿರೀಕ್ಷಿಸಿ. ಕಪ್ಪು ಬಣ್ಣದ ಕಿಟಕಿ ಕಾಣಿಸಬಹುದು. ಅದು ಮುಚ್ಚುವವರೆಗೆ ದಯವಿಟ್ಟು ನಿರೀಕ್ಷಿಸಿ.", + "{0} has been installed successfully.": "{0} ಯಶಸ್ವಿಯಾಗಿ install ಆಗಿದೆ.", + "Please click on \"Continue\" to continue": "ಮುಂದುವರಿಸಲು \"Continue\" ಮೇಲೆ ಕ್ಲಿಕ್ ಮಾಡಿ", + "Continue": "ಮುಂದುವರಿಸಿ", + "{0} has been installed successfully. It is recommended to restart UniGetUI to finish the installation": "{0} ಯಶಸ್ವಿಯಾಗಿ install ಆಗಿದೆ. installation ಪೂರ್ಣಗೊಳಿಸಲು UniGetUI ಮರುಪ್ರಾರಂಭಿಸುವುದು ಶಿಫಾರಸು ಮಾಡಲಾಗಿದೆ", + "Restart later": "ನಂತರ ಮರುಪ್ರಾರಂಭಿಸಿ", + "An error occurred:": "ದೋಷ ಸಂಭವಿಸಿದೆ:", + "Please see the Command-line Output or refer to the Operation History for further information about the issue.": "ಸಮಸ್ಯೆಯ ಬಗ್ಗೆ ಹೆಚ್ಚಿನ ಮಾಹಿತಿಗಾಗಿ Command-line Output ನೋಡಿ ಅಥವಾ Operation History ಅನ್ನು ಪರಿಶೀಲಿಸಿ.", + "Retry as administrator": "administrator ಆಗಿ ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ", + "Retry interactively": "ಪರಸ್ಪರಕ್ರಿಯಾತ್ಮಕವಾಗಿ ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ", + "Retry skipping integrity checks": "integrity checks ಬಿಟ್ಟುಕೊಟ್ಟು ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ", + "Installation options": "ಸ್ಥಾಪನಾ ಆಯ್ಕೆಗಳು", + "Save": "ಉಳಿಸಿ", + "UniGetUI collects anonymous usage data with the sole purpose of understanding and improving the user experience.": "ಬಳಕೆದಾರ ಅನುಭವವನ್ನು ಅರ್ಥಮಾಡಿಕೊಳ್ಳಲು ಮತ್ತು ಉತ್ತಮಗೊಳಿಸಲು ಮಾತ್ರ UniGetUI ಅನಾಮಧೇಯ ಬಳಕೆ ಡೇಟಾವನ್ನು ಸಂಗ್ರಹಿಸುತ್ತದೆ.", + "More details about the shared data and how it will be processed": "ಹಂಚಿಕೊಳ್ಳಲಾದ ಡೇಟಾ ಮತ್ತು ಅದನ್ನು ಹೇಗೆ ಸಂಸ್ಕರಿಸಲಾಗುತ್ತದೆ ಎಂಬುದರ ಬಗ್ಗೆ ಇನ್ನಷ್ಟು ವಿವರಗಳು", + "Do you accept that UniGetUI collects and sends anonymous usage statistics, with the sole purpose of understanding and improving the user experience?": "ಬಳಕೆದಾರ ಅನುಭವವನ್ನು ಅರ್ಥಮಾಡಿಕೊಳ್ಳಲು ಮತ್ತು ಸುಧಾರಿಸಲು ಮಾತ್ರ UniGetUI ಅನಾಮಧೇಯ ಬಳಕೆ ಅಂಕಿಅಂಶಗಳನ್ನು ಸಂಗ್ರಹಿಸಿ ಕಳುಹಿಸುವುದನ್ನು ನೀವು ಒಪ್ಪುತ್ತೀರಾ?", + "Decline": "ನಿರಾಕರಿಸಿ", + "No personal information is collected nor sent, and the collected data is anonimized, so it can't be back-tracked to you.": "ಯಾವುದೇ ವೈಯಕ್ತಿಕ ಮಾಹಿತಿಯನ್ನು ಸಂಗ್ರಹಿಸಲಾಗುವುದಿಲ್ಲ ಅಥವಾ ಕಳುಹಿಸಲಾಗುವುದಿಲ್ಲ, ಮತ್ತು ಸಂಗ್ರಹಿಸಲಾದ ಡೇಟಾವನ್ನು ಅನಾಮಧೇಯಗೊಳಿಸಲಾಗಿದೆ, ಆದ್ದರಿಂದ ಅದನ್ನು ನಿಮ್ಮವರೆಗೆ ಹಿಂಬಾಲಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ.", + "Navigation panel": "ನ್ಯಾವಿಗೇಶನ್ ಪ್ಯಾನಲ್", + "Operations": "ಕಾರ್ಯಾಚರಣೆಗಳು", + "Toggle operations panel": "ಕಾರ್ಯಾಚರಣೆಗಳ ಪ್ಯಾನೆಲ್ ಅನ್ನು ಟಾಗಲ್ ಮಾಡಿ", + "Bulk operations": "ಸಾಮೂಹಿಕ ಕಾರ್ಯಾಚರಣೆಗಳು", + "Retry failed": "ವಿಫಲವಾದವುಗಳನ್ನು ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ", + "Clear successful": "ಯಶಸ್ವಿಯಾದವುಗಳನ್ನು ತೆರವುಗೊಳಿಸಿ", + "Clear finished": "ಮುಗಿದವುಗಳನ್ನು ತೆರವುಗೊಳಿಸಿ", + "Cancel all": "ಎಲ್ಲವನ್ನೂ ರದ್ದುಗೊಳಿಸಿ", + "More": "ಇನ್ನಷ್ಟು", + "Toggle navigation panel": "ಸಂಚಲನ ಪ್ಯಾನೆಲ್ ಅನ್ನು ಟಾಗಲ್ ಮಾಡಿ", + "Minimize": "ಸಣ್ಣಗೊಳಿಸಿ", + "Maximize": "ದೊಡ್ಡಗೊಳಿಸಿ", + "UniGetUI by Devolutions": "Devolutions ನಿಂದ UniGetUI", + "UniGetUI is an application that makes managing your software easier, by providing an all-in-one graphical interface for your command-line package managers.": "ನಿಮ್ಮ command-line package managers ಗಾಗಿ all-in-one graphical interface ಒದಗಿಸುವ ಮೂಲಕ ನಿಮ್ಮ software ನಿರ್ವಹಣೆಯನ್ನು ಸುಲಭಗೊಳಿಸುವ application UniGetUI ಆಗಿದೆ.", + "Useful links": "ಉಪಯುಕ್ತ links", + "UniGetUI Homepage": "UniGetUI ಮುಖಪುಟ", + "Report an issue or submit a feature request": "ಸಮಸ್ಯೆಯನ್ನು ವರದಿ ಮಾಡಿ ಅಥವಾ feature request ಸಲ್ಲಿಸಿ", + "UniGetUI Repository": "UniGetUI ರೆಪೊಸಿಟರಿ", + "View GitHub Profile": "GitHub profile ನೋಡಿ", + "UniGetUI License": "UniGetUI ಪರವಾನಗಿ", + "Using UniGetUI implies the acceptation of the MIT License": "UniGetUI ಬಳಕೆ ಮಾಡುವುದರಿಂದ MIT ಪರವಾನಗಿಯನ್ನು ಸ್ವೀಕರಿಸಿರುವಂತೆ ಆಗುತ್ತದೆ", + "Become a translator": "ಅನುವಾದಕರಾಗಿ", + "Go back": "ಹಿಂದೆ ಹೋಗಿ", + "Go forward": "ಮುಂದೆ ಹೋಗಿ", + "Go to home page": "ಮುಖಪುಟಕ್ಕೆ ಹೋಗಿ", + "Reload page": "ಪುಟವನ್ನು ಮರುಲೋಡ್ ಮಾಡಿ", + "View page on browser": "browser ನಲ್ಲಿ page ನೋಡಿ", + "The built-in browser is not supported on Linux yet.": "ಅಂತರ್ನಿರ್ಮಿತ ಬ್ರೌಸರ್ Linux ನಲ್ಲಿ ಇನ್ನೂ ಬೆಂಬಲಿತವಾಗಿಲ್ಲ.", + "Open in browser": "ಬ್ರೌಸರ್‌ನಲ್ಲಿ ತೆರೆಯಿರಿ", + "Copy to clipboard": "ಕ್ಲಿಪ್‌ಬೋರ್ಡ್‌ಗೆ ನಕಲಿಸಿ", + "Export to a file": "file ಗೆ ರಫ್ತು ಮಾಡಿ", + "Log level:": "Log ಮಟ್ಟ:", + "Reload log": "log ಅನ್ನು ಮರುಲೋಡ್ ಮಾಡಿ", + "Export log": "ಲಾಗ್ ರಫ್ತು ಮಾಡಿ", + "Text": "ಪಠ್ಯ", + "Change how operations request administrator rights": "ಕಾರ್ಯಾಚರಣೆಗಳು ನಿರ್ವಾಹಕ ಹಕ್ಕುಗಳನ್ನು ಹೇಗೆ ಕೇಳುತ್ತವೆ ಎಂಬುದನ್ನು ಬದಲಿಸಿ", + "Restrictions on package operations": "package operations ಮೇಲಿನ ನಿರ್ಬಂಧಗಳು", + "Restrictions on package managers": "package managers ಮೇಲಿನ ನಿರ್ಬಂಧಗಳು", + "Restrictions when importing package bundles": "package bundles ಅನ್ನು import ಮಾಡುವಾಗ ಇರುವ ನಿರ್ಬಂಧಗಳು", + "Ask for administrator privileges once for each batch of operations": "ಪ್ರತಿ ಬ್ಯಾಚ್ ಕಾರ್ಯಾಚರಣೆಗಳಿಗೆ ನಿರ್ವಾಹಕ ಹಕ್ಕುಗಳನ್ನು ಒಮ್ಮೆ ಕೇಳಿ", + "Ask only once for administrator privileges": "ನಿರ್ವಾಹಕ ಹಕ್ಕುಗಳನ್ನು ಒಮ್ಮೆ ಮಾತ್ರ ಕೇಳಿ", + "Prohibit any kind of Elevation via UniGetUI Elevator or GSudo": "UniGetUI Elevator ಅಥವಾ GSudo ಮೂಲಕ ಯಾವುದೇ ವಿಧದ Elevation ಅನ್ನು ನಿಷೇಧಿಸಿ", + "This option WILL cause issues. Any operation incapable of elevating itself WILL FAIL. Install/update/uninstall as administrator will NOT WORK.": "ಈ ಆಯ್ಕೆ ಖಂಡಿತವಾಗಿಯೂ ಸಮಸ್ಯೆ ಉಂಟುಮಾಡುತ್ತದೆ. ತನ್ನಷ್ಟಕ್ಕೆ elevation ಪಡೆಯಲಾಗದ ಯಾವುದೇ ಕಾರ್ಯಾಚರಣೆ ವಿಫಲವಾಗುತ್ತದೆ. administrator ಆಗಿ install/update/uninstall ಕೆಲಸ ಮಾಡುವುದಿಲ್ಲ.", + "Allow custom command-line arguments": "ಕಸ್ಟಮ್ command-line arguments ಗೆ ಅನುಮತಿಸಿ", + "Custom command-line arguments can change the way in which programs are installed, upgraded or uninstalled, in a way UniGetUI cannot control. Using custom command-lines can break packages. Proceed with caution.": "ಕಸ್ಟಮ್ command-line ಆರ್ಗ್ಯುಮೆಂಟ್‌ಗಳು UniGetUI ನಿಯಂತ್ರಣದಲ್ಲಿರದ ರೀತಿಯಲ್ಲಿ ಪ್ರೋಗ್ರಾಂಗಳನ್ನು ಸ್ಥಾಪಿಸುವ, ನವೀಕರಿಸುವ ಅಥವಾ ಅನ್‌ಇನ್‌ಸ್ಟಾಲ್ ಮಾಡುವ ವಿಧಾನವನ್ನು ಬದಲಾಯಿಸಬಹುದು. ಕಸ್ಟಮ್ command-lines ಬಳಕೆ ಪ್ಯಾಕೇಜ್‌ಗಳನ್ನು ಹಾಳುಮಾಡಬಹುದು. ಎಚ್ಚರಿಕೆಯಿಂದ ಮುಂದುವರಿಯಿರಿ.", + "Ignore custom pre-install and post-install commands when importing packages from a bundle": "ಬಂಡಲ್‌ನಿಂದ ಪ್ಯಾಕೇಜ್‌ಗಳನ್ನು ಆಮದು ಮಾಡುವಾಗ ಕಸ್ಟಮ್ pre-install ಮತ್ತು post-install command ಗಳನ್ನು ನಿರ್ಲಕ್ಷಿಸಿ", + "Pre and post install commands will be run before and after a package gets installed, upgraded or uninstalled. Be aware that they may break things unless used carefully": "ಪ್ಯಾಕೇಜ್ ಸ್ಥಾಪನೆ, ನವೀಕರಣ ಅಥವಾ ಅನ್‌ಇನ್‌ಸ್ಟಾಲ್ ಆಗುವ ಮೊದಲು ಮತ್ತು ನಂತರ pre ಮತ್ತು post install commands ಕಾರ್ಯಗೊಳಿಸಲಾಗುತ್ತದೆ. ಜಾಗ್ರತೆಯಿಂದ ಬಳಸದೆ ಇದ್ದರೆ ಅವು ಸಮಸ್ಯೆ ಉಂಟುಮಾಡಬಹುದು ಎಂಬುದನ್ನು ಗಮನದಲ್ಲಿಡಿ.", + "Allow changing the paths for package manager executables": "ಪ್ಯಾಕೇಜ್ ಮ್ಯಾನೇಜರ್ executable ಗಳ ದಾರಿಗಳನ್ನು ಬದಲಾಯಿಸಲು ಅನುಮತಿಸಿ", + "Turning this on enables changing the executable file used to interact with package managers. While this allows finer-grained customization of your install processes, it may also be dangerous": "ಇದನ್ನು on ಮಾಡಿದರೆ package managers ಜೊತೆ ಸಂಪರ್ಕಿಸಲು ಬಳಸುವ executable file ಅನ್ನು ಬದಲಾಯಿಸಲು ಅನುಮತಿಸುತ್ತದೆ. ಇದರಿಂದ ನಿಮ್ಮ install processes ಗಳನ್ನು ಇನ್ನಷ್ಟು ಸೂಕ್ಷ್ಮವಾಗಿ customize ಮಾಡಬಹುದು, ಆದರೆ ಇದು ಅಪಾಯಕಾರಿ ಕೂಡ ಆಗಿರಬಹುದು.", + "Allow importing custom command-line arguments when importing packages from a bundle": "ಬಂಡಲ್‌ನಿಂದ ಪ್ಯಾಕೇಜ್‌ಗಳನ್ನು ಆಮದು ಮಾಡುವಾಗ ಕಸ್ಟಮ್ command-line arguments ಗಳನ್ನು ಆಮದು ಮಾಡಲು ಅನುಮತಿಸಿ", + "Malformed command-line arguments can break packages, or even allow a malicious actor to gain privileged execution. Therefore, importing custom command-line arguments is disabled by default": "ತಪ್ಪಾಗಿ ರೂಪಿಸಲಾದ command-line arguments ಪ್ಯಾಕೇಜ್‌ಗಳನ್ನು ಹಾಳುಮಾಡಬಹುದು, ಅಥವಾ ದುರುದ್ದೇಶಿ ವ್ಯಕ್ತಿಗೆ ಉನ್ನತ ಅಧಿಕಾರದ ನಿರ್ವಹಣೆಯನ್ನು ಪಡೆಯಲು ಸಹ ಅವಕಾಶ ನೀಡಬಹುದು. ಆದ್ದರಿಂದ custom command-line arguments ಆಮದು ಮಾಡುವಿಕೆ default ಆಗಿ ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ.", + "Allow importing custom pre-install and post-install commands when importing packages from a bundle": "ಬಂಡಲ್‌ನಿಂದ ಪ್ಯಾಕೇಜ್‌ಗಳನ್ನು ಆಮದು ಮಾಡುವಾಗ ಕಸ್ಟಮ್ pre-install ಮತ್ತು post-install command ಗಳನ್ನು ಆಮದು ಮಾಡಲು ಅನುಮತಿಸಿ", + "Pre and post install commands can do very nasty things to your device, if designed to do so. It can be very dangerous to import the commands from a bundle, unless you trust the source of that package bundle": "Pre ಮತ್ತು post install commands ಹಾಗೆ ರೂಪಿಸಲಾದರೆ ನಿಮ್ಮ ಸಾಧನಕ್ಕೆ ತುಂಬಾ ಕೆಟ್ಟದ್ದನ್ನು ಮಾಡಬಹುದು. ಆ package bundle ನ ಮೂಲವನ್ನು ನೀವು ನಂಬದಿದ್ದರೆ bundle ನಿಂದ commands ಆಮದು ಮಾಡುವುದು ಬಹಳ ಅಪಾಯಕಾರಿ.", + "Administrator rights and other dangerous settings": "ನಿರ್ವಾಹಕ ಹಕ್ಕುಗಳು ಮತ್ತು ಇತರೆ ಅಪಾಯಕಾರಿ ಸೆಟ್ಟಿಂಗ್‌ಗಳು", + "Package backup": "ಪ್ಯಾಕೇಜ್ backup", + "Cloud package backup": "cloud ಪ್ಯಾಕೇಜ್ ಬ್ಯಾಕಪ್", + "Local package backup": "ಸ್ಥಳೀಯ package backup", + "Local backup advanced options": "ಸ್ಥಳೀಯ backup ಉನ್ನತ ಆಯ್ಕೆಗಳು", + "Log in with GitHub": "GitHub ಬಳಸಿ ಲಾಗಿನ್ ಮಾಡಿ", + "Log out from GitHub": "GitHub ನಿಂದ ಲಾಗ್ ಔಟ್ ಮಾಡಿ", + "Periodically perform a cloud backup of the installed packages": "ಸ್ಥಾಪಿತ ಪ್ಯಾಕೇಜ್‌ಗಳ cloud backup ಅನ್ನು ಅವಧಿ ಅವಧಿಯಲ್ಲಿ ನಡೆಸಿ", + "Cloud backup uses a private GitHub Gist to store a list of installed packages": "ಸ್ಥಾಪಿತ ಪ್ಯಾಕೇಜ್‌ಗಳ ಪಟ್ಟಿಯನ್ನು ಸಂಗ್ರಹಿಸಲು cloud ಬ್ಯಾಕಪ್ ಖಾಸಗಿ GitHub Gist ಅನ್ನು ಬಳಸುತ್ತದೆ", + "Perform a cloud backup now": "ಈಗ cloud backup ನಡೆಸಿ", + "Backup": "ಬ್ಯಾಕಪ್", + "Restore a backup from the cloud": "cloud ನಿಂದ backup ಅನ್ನು ಮರುಸ್ಥಾಪಿಸಿ", + "Begin the process to select a cloud backup and review which packages to restore": "cloud ಬ್ಯಾಕಪ್ ಅನ್ನು ಆಯ್ಕೆಮಾಡಿ ಮರುಸ್ಥಾಪಿಸಬೇಕಾದ ಪ್ಯಾಕೇಜ್‌ಗಳನ್ನು ಪರಿಶೀಲಿಸುವ ಪ್ರಕ್ರಿಯೆಯನ್ನು ಪ್ರಾರಂಭಿಸಿ", + "Periodically perform a local backup of the installed packages": "ಸ್ಥಾಪಿತ ಪ್ಯಾಕೇಜ್‌ಗಳ local backup ಅನ್ನು ಅವಧಿ ಅವಧಿಯಲ್ಲಿ ನಡೆಸಿ", + "Perform a local backup now": "ಈಗ local backup ನಡೆಸಿ", + "Change backup output directory": "ಬ್ಯಾಕಪ್ ಔಟ್‌ಪುಟ್ ಡೈರೆಕ್ಟರಿಯನ್ನು ಬದಲಾಯಿಸಿ", + "Set a custom backup file name": "custom backup file name ಒಂದನ್ನು ಹೊಂದಿಸಿ", + "Leave empty for default": "Default ಗಾಗಿ ಖಾಲಿ ಬಿಡಿ", + "Add a timestamp to the backup file names": "ಬ್ಯಾಕಪ್ ಫೈಲ್ ಹೆಸರುಗಳಿಗೆ ಟೈಮ್‌ಸ್ಟ್ಯಾಂಪ್ ಸೇರಿಸಿ", + "Backup and Restore": "ಬ್ಯಾಕಪ್ ಮತ್ತು ಮರುಸ್ಥಾಪನೆ", + "Enable background api (UniGetUI Widgets and Sharing, port 7058)": "background api (UniGetUI Widgets and Sharing, port 7058) ಅನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಿ", + "Wait for the device to be connected to the internet before attempting to do tasks that require internet connectivity.": "internet ಸಂಪರ್ಕ ಅಗತ್ಯವಿರುವ ಕಾರ್ಯಗಳನ್ನು ಮಾಡಲು ಪ್ರಯತ್ನಿಸುವ ಮೊದಲು ಸಾಧನವು internet ಗೆ ಸಂಪರ್ಕಗೊಂಡಿರುವುದನ್ನು ಕಾಯಿರಿ.", + "Disable the 1-minute timeout for package-related operations": "ಪ್ಯಾಕೇಜ್ ಸಂಬಂಧಿತ ಕಾರ್ಯಗಳಿಗೆ 1-ನಿಮಿಷ timeout ಅನ್ನು ಅಚೇತನಗೊಳಿಸಿ", + "Use installed GSudo instead of UniGetUI Elevator": "UniGetUI Elevator ಬದಲು installed GSudo ಬಳಸಿ", + "Use a custom icon and screenshot database URL": "custom icon ಮತ್ತು screenshot database URL ಬಳಸಿ", + "Enable background CPU Usage optimizations (see Pull Request #3278)": "background CPU Usage optimizations ಅನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಿ (Pull Request #3278 ನೋಡಿ)", + "Perform integrity checks at startup": "ಆರಂಭದಲ್ಲಿ integrity checks ನಡೆಸಿ", + "When batch installing packages from a bundle, install also packages that are already installed": "bundle ಇಂದ batch install ಮಾಡುವಾಗ, ಈಗಾಗಲೇ install ಆಗಿರುವ packages ಗಳನ್ನೂ install ಮಾಡಿ", + "Experimental settings and developer options": "ಪ್ರಾಯೋಗಿಕ settings ಮತ್ತು developer ಆಯ್ಕೆಗಳು", + "Show UniGetUI's version and build number on the titlebar.": "titlebar ನಲ್ಲಿ UniGetUI ಯ version ಮತ್ತು build number ತೋರಿಸಿ.", + "Language": "ಭಾಷೆ", + "UniGetUI updater": "UniGetUI ನವೀಕರಣಕಾರ", + "Telemetry": "ಟೆಲಿಮೆಟ್ರಿ", + "Manage UniGetUI settings": "UniGetUI settings ಅನ್ನು ನಿರ್ವಹಿಸಿ", + "Related settings": "ಸಂಬಂಧಿತ settings", + "Update UniGetUI automatically": "UniGetUI ಅನ್ನು ಸ್ವಯಂಚಾಲಿತವಾಗಿ update ಮಾಡಿ", + "Check for updates": "ನವೀಕರಣಗಳನ್ನು ಪರಿಶೀಲಿಸಿ", + "Install prerelease versions of UniGetUI": "UniGetUI ಯ prerelease ಆವೃತ್ತಿಗಳನ್ನು ಸ್ಥಾಪಿಸಿ", + "Manage telemetry settings": "telemetry settings ಅನ್ನು ನಿರ್ವಹಿಸಿ", + "Manage": "ನಿರ್ವಹಿಸಿ", + "Import settings from a local file": "ಸ್ಥಳೀಯ ಫೈಲ್‌ನಿಂದ ಸೆಟ್ಟಿಂಗ್‌ಗಳನ್ನು ಆಮದು ಮಾಡಿ", + "Import": "ಆಮದು", + "Export settings to a local file": "settings ಅನ್ನು local file ಗೆ ರಫ್ತು ಮಾಡಿ", + "Export": "ರಫ್ತು ಮಾಡಿ", + "Reset UniGetUI": "UniGetUI ಅನ್ನು ಮರುಹೊಂದಿಸಿ", + "User interface preferences": "user interface ಆದ್ಯತೆಗಳು", + "Application theme, startup page, package icons, clear successful installs automatically": "ಅಪ್ಲಿಕೇಶನ್ ಥೀಮ್, ಪ್ರಾರಂಭ ಪುಟ, ಪ್ಯಾಕೇಜ್ ಚಿಹ್ನೆಗಳು, ಯಶಸ್ವಿ ಸ್ಥಾಪನೆಗಳನ್ನು ಸ್ವಯಂಚಾಲಿತವಾಗಿ ತೆರವುಗೊಳಿಸಿ", + "General preferences": "ಸಾಮಾನ್ಯ ಆದ್ಯತೆಗಳು", + "UniGetUI display language:": "UniGetUI ಪ್ರದರ್ಶನ ಭಾಷೆ:", + "System language": "ಸಿಸ್ಟಂ ಭಾಷೆ", + "Is your language missing or incomplete?": "ನಿಮ್ಮ ಭಾಷೆ ಕಾಣೆಯಾಗಿದೆ ಅಥವಾ ಅಪೂರ್ಣವಾಗಿದೆಯೇ?", + "Appearance": "ದೃಶ್ಯರೂಪ", + "UniGetUI on the background and system tray": "background ಮತ್ತು system tray ಯಲ್ಲಿ UniGetUI", + "Package lists": "ಪ್ಯಾಕೇಜ್ ಪಟ್ಟಿಗಳು", + "Use classic mode": "ಕ್ಲಾಸಿಕ್ ಮೋಡ್ ಬಳಸಿ", + "Restart UniGetUI to apply this change": "ಈ ಬದಲಾವಣೆಯನ್ನು ಅನ್ವಯಿಸಲು UniGetUI ಅನ್ನು ಮರುಪ್ರಾರಂಭಿಸಿ", + "The classic UI is disabled for beta testers": "ಬೀಟಾ ಪರೀಕ್ಷಕರಿಗಾಗಿ ಕ್ಲಾಸಿಕ್ UI ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ", + "Close UniGetUI to the system tray": "UniGetUI ಅನ್ನು system tray ಗೆ ಮುಚ್ಚಿ", + "Manage UniGetUI autostart behaviour": "UniGetUI autostart ವರ್ತನೆಯನ್ನು ನಿರ್ವಹಿಸಿ", + "Show package icons on package lists": "package lists ನಲ್ಲಿ package icons ತೋರಿಸಿ", + "Clear cache": "ಕ್ಯಾಶೆ ತೆರವುಗೊಳಿಸಿ", + "Select upgradable packages by default": "default ಆಗಿ upgrade ಮಾಡಬಹುದಾದ ಪ್ಯಾಕೇಜ್‌ಗಳನ್ನು ಆಯ್ಕೆಮಾಡಿ", + "Light": "ಬೆಳಕು", + "Dark": "ಗಾಢ", + "Follow system color scheme": "system color scheme ಅನ್ನು ಅನುಸರಿಸಿ", + "Application theme:": "ಅಪ್ಲಿಕೇಶನ್ ಥೀಮ್:", + "UniGetUI startup page:": "UniGetUI ಪ್ರಾರಂಭ ಪುಟ:", + "Proxy settings": "ಪ್ರಾಕ್ಸಿ settings", + "Other settings": "ಇತರೆ settings", + "Connect the internet using a custom proxy": "ಕಸ್ಟಮ್ proxy ಬಳಸಿ ಇಂಟರ್ನೆಟ್‌ಗೆ ಸಂಪರ್ಕಿಸಿರಿ", + "Please note that not all package managers may fully support this feature": "ಎಲ್ಲಾ package managers ಗಳು ಈ ವೈಶಿಷ್ಟ್ಯವನ್ನು ಸಂಪೂರ್ಣವಾಗಿ ಬೆಂಬಲಿಸದೇ ಇರಬಹುದು ಎಂಬುದನ್ನು ದಯವಿಟ್ಟು ಗಮನಿಸಿ", + "Proxy URL": "ಪ್ರಾಕ್ಸಿ URL", + "Enter proxy URL here": "proxy URL ಅನ್ನು ಇಲ್ಲಿ ನಮೂದಿಸಿ", + "Authenticate to the proxy with a user and a password": "proxy ಗೆ ಬಳಕೆದಾರ ಮತ್ತು password ಮೂಲಕ ದೃಢೀಕರಿಸಿ", + "Internet and proxy settings": "internet ಮತ್ತು proxy settings", + "Package manager preferences": "ಪ್ಯಾಕೇಜ್ manager ಆದ್ಯತೆಗಳು", + "Ready": "ಸಿದ್ಧವಾಗಿದೆ", + "Not found": "ಕಂಡುಬಂದಿಲ್ಲ", + "Notification preferences": "ಅಧಿಸೂಚನೆ ಆದ್ಯತೆಗಳು", + "Notification types": "ಅಧಿಸೂಚನೆ ಪ್ರಕಾರಗಳು", + "The system tray icon must be enabled in order for notifications to work": "notifications ಕಾರ್ಯನಿರ್ವಹಿಸಲು system tray icon ಸಕ್ರಿಯವಾಗಿರಬೇಕು", + "Enable UniGetUI notifications": "UniGetUI notifications ಅನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಿ", + "Show a notification when there are available updates": "ಲಭ್ಯವಿರುವ ನವೀಕರಣಗಳು ಇರುವಾಗ ಅಧಿಸೂಚನೆ ತೋರಿಸಿ", + "Show a silent notification when an operation is running": "ಕಾರ್ಯಾಚರಣೆ ನಡೆಯುತ್ತಿರುವಾಗ ಮೌನ ಅಧಿಸೂಚನೆ ತೋರಿಸಿ", + "Show a notification when an operation fails": "ಕಾರ್ಯಾಚರಣೆ ವಿಫಲವಾದಾಗ ಅಧಿಸೂಚನೆ ತೋರಿಸಿ", + "Show a notification when an operation finishes successfully": "ಕಾರ್ಯಾಚರಣೆ ಯಶಸ್ವಿಯಾಗಿ ಪೂರ್ಣಗೊಂಡಾಗ ಅಧಿಸೂಚನೆ ತೋರಿಸಿ", + "Concurrency and execution": "ಸಮಾಂತರತೆ ಮತ್ತು ಕಾರ್ಯಗತಗೊಳಿಕೆ", + "Automatic desktop shortcut remover": "ಸ್ವಯಂಚಾಲಿತ desktop shortcut ತೆಗೆಯುವಿಕೆ", + "Choose how many operations should be performed in parallel": "ಸಮಾಂತರವಾಗಿ ಎಷ್ಟು ಕಾರ್ಯಾಚರಣೆಗಳನ್ನು ನಡೆಸಬೇಕು ಎಂದು ಆಯ್ಕೆಮಾಡಿ", + "Clear successful operations from the operation list after a 5 second delay": "5 ಸೆಕೆಂಡ್ ವಿಳಂಬದ ನಂತರ ಕಾರ್ಯಾಚರಣೆಗಳ ಪಟ್ಟಿಯಿಂದ ಯಶಸ್ವಿ ಕಾರ್ಯಾಚರಣೆಗಳನ್ನು ತೆರವುಗೊಳಿಸಿ", + "Download operations are not affected by this setting": "ಡೌನ್‌ಲೋಡ್ ಕಾರ್ಯಗಳು ಈ setting ನಿಂದ ಪ್ರಭಾವಿತವಾಗುವುದಿಲ್ಲ", + "You may lose unsaved data": "ಉಳಿಸದ data ಕಳೆದುಕೊಳ್ಳಬಹುದು", + "Ask to delete desktop shortcuts created during an install or upgrade.": "ಸ್ಥಾಪನೆ ಅಥವಾ ಅಪ್‌ಗ್ರೇಡ್ ಸಮಯದಲ್ಲಿ ರಚಿಸಲಾದ desktop shortcuts ಗಳನ್ನು ಅಳಿಸಲು ಕೇಳಿ.", + "Package update preferences": "ಪ್ಯಾಕೇಜ್ ನವೀಕರಣ ಆದ್ಯತೆಗಳು", + "Update check frequency, automatically install updates, etc.": "update ಪರಿಶೀಲನೆಯ ಅವಧಿ, updates ಗಳನ್ನು ಸ್ವಯಂಚಾಲಿತವಾಗಿ install ಮಾಡುವುದು, ಇತ್ಯಾದಿ.", + "Reduce UAC prompts, elevate installations by default, unlock certain dangerous features, etc.": "UAC prompts ಅನ್ನು ಕಡಿಮೆ ಮಾಡಿ, default ಆಗಿ installations ಗೆ elevation ನೀಡಿ, ಕೆಲವು ಅಪಾಯಕಾರಿ ವೈಶಿಷ್ಟ್ಯಗಳನ್ನು ಅನ್‌ಲಾಕ್ ಮಾಡಿ, ಇತ್ಯಾದಿ.", + "Package operation preferences": "ಪ್ಯಾಕೇಜ್ ಕಾರ್ಯಾಚರಣೆ ಆದ್ಯತೆಗಳು", + "Enable {pm}": "{pm} ಅನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಿ", + "Not finding the file you are looking for? Make sure it has been added to path.": "ನೀವು ಹುಡುಕುತ್ತಿರುವ file ಸಿಗುತ್ತಿಲ್ಲವೇ? ಅದು path ಗೆ ಸೇರಿಸಲಾಗಿದೆ ಎಂಬುದನ್ನು ಖಚಿತಪಡಿಸಿಕೊಳ್ಳಿ.", + "Select the executable to be used. The following list shows the executables found by UniGetUI": "ಬಳಸಬೇಕಾದ executable ಆಯ್ಕೆಮಾಡಿ. ಕೆಳಗಿನ ಪಟ್ಟಿಯಲ್ಲಿ UniGetUI ಕಂಡುಹಿಡಿದ executables ತೋರಿಸಲಾಗಿದೆ", + "For security reasons, changing the executable file is disabled by default": "ಭದ್ರತಾ ಕಾರಣಗಳಿಂದ executable file ಬದಲಿಸುವುದು default ಆಗಿ ನಿಷ್ಕ್ರಿಯವಾಗಿದೆ", + "Change this": "ಇದನ್ನು ಬದಲಿಸಿ", + "Copy path": "ಮಾರ್ಗವನ್ನು ನಕಲಿಸಿ", + "Current executable file:": "ಪ್ರಸ್ತುತ ಕಾರ್ಯಗತಗೊಳಿಸಬಹುದಾದ ಕಡತ:", + "Ignore packages from {pm} when showing a notification about updates": "ನವೀಕರಣಗಳ ಬಗ್ಗೆ ಅಧಿಸೂಚನೆ ತೋರಿಸುವಾಗ {pm} ನಿಂದ ಬಂದ ಪ್ಯಾಕೇಜ್‌ಗಳನ್ನು ನಿರ್ಲಕ್ಷಿಸಿ", + "Update security": "ನವೀಕರಣ ಭದ್ರತೆ", + "Use global setting": "global setting ಬಳಸಿ", + "Minimum age for updates": "ನವೀಕರಣಗಳ ಕನಿಷ್ಠ ವಯಸ್ಸು", + "e.g. 10": "ಉದಾ. 10", + "Custom minimum age (days)": "custom ಕನಿಷ್ಠ ವಯಸ್ಸು (ದಿನಗಳು)", + "{pm} does not provide release dates for its packages, so this setting will have no effect": "{pm} ತನ್ನ packages ಗಳಿಗೆ ಬಿಡುಗಡೆ ದಿನಾಂಕಗಳನ್ನು ಒದಗಿಸುವುದಿಲ್ಲ, ಆದ್ದರಿಂದ ಈ setting ಗೆ ಯಾವುದೇ ಪರಿಣಾಮ ಇರುವುದಿಲ್ಲ", + "{pm} only provides release dates for some of its packages, so this setting will only apply to those packages": "{pm} ತನ್ನ ಕೆಲವು ಪ್ಯಾಕೇಜ್\bಗಳಿಗೆ ಮಾತ್ರ ಬಿಡುಗಡೆಯ ದಿನಾಂಕಗಳನ್ನು ಒದಗಿಸುತ್ತದೆ, ಆದ್ದರಿಂದ ಈ ಸೆಟ್ಟಿಂಗ್ ಆ ಪ್ಯಾಕೇಜ್\bಗಳಿಗೆ ಮಾತ್ರ ಅನ್ವಯವಾಗುತ್ತದೆ", + "Override the global minimum update age for this package manager": "ಈ package manager ಗಾಗಿ global minimum update age ಅನ್ನು override ಮಾಡಿ", + "View {0} logs": "{0} logs ನೋಡಿ", + "If Python cannot be found or is not listing packages but is installed on the system, ": "Python ಕಂಡುಬರದಿದ್ದರೆ ಅಥವಾ packages ಗಳನ್ನು ಪಟ್ಟಿ ಮಾಡದಿದ್ದರೂ ಅದು system ನಲ್ಲಿ ಸ್ಥಾಪಿತವಾಗಿದ್ದರೆ, ", + "Advanced options": "ಮುನ್ನಡೆದ ಆಯ್ಕೆಗಳು", + "WinGet command-line tool": "WinGet ಆಜ್ಞಾ ಸಾಲಿನ ಸಾಧನ", + "Choose which command-line tool UniGetUI uses for WinGet operations when the COM API is not used": "COM API ಬಳಸದಾಗ WinGet ಕಾರ್ಯಾಚರಣೆಗಳಿಗೆ UniGetUI ಯಾವ ಕಮಾಂಡ್-ಲೈನ್ ಉಪಕರಣವನ್ನು ಬಳಸಬೇಕು ಎಂದು ಆಯ್ಕೆಮಾಡಿ", + "WinGet COM API": "WinGet COM API", + "Choose whether UniGetUI can use the WinGet COM API before falling back to the command-line tool": "ಕಮಾಂಡ್-ಲೈನ್ ಉಪಕರಣಕ್ಕೆ ಹಿಂದಿರುಗುವ ಮೊದಲು UniGetUI WinGet COM API ಅನ್ನು ಬಳಸಬಹುದೇ ಎಂಬುದನ್ನು ಆಯ್ಕೆಮಾಡಿ", + "Reset WinGet": "WinGet ಅನ್ನು ಮರುಹೊಂದಿಸಿ", + "This may help if no packages are listed": "ಯಾವುದೇ packages ಪಟ್ಟಿ ಮಾಡದಿದ್ದರೆ ಇದು ಸಹಾಯ ಮಾಡಬಹುದು", + "Force install location parameter when updating packages with custom locations": "custom locations ಇರುವ ಪ್ಯಾಕೇಜ್‌ಗಳನ್ನು update ಮಾಡುವಾಗ install location parameter ಅನ್ನು ಬಲವಂತವಾಗಿ ಬಳಸಿ", + "Install Scoop": "Scoop ಅನ್ನು ಸ್ಥಾಪಿಸಿ", + "Uninstall Scoop (and its packages)": "Scoop (ಮತ್ತು ಅದರ packages) ಅನ್ನು uninstall ಮಾಡಿ", + "Run cleanup and clear cache": "cleanup ನಡೆಸಿ ಮತ್ತು cache ತೆರವುಗೊಳಿಸಿ", + "Run": "ಚಾಲನೆ ಮಾಡಿ", + "Enable Scoop cleanup on launch": "launch ಸಮಯದಲ್ಲಿ Scoop cleanup ಅನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಿ", + "Default vcpkg triplet": "ಡೀಫಾಲ್ಟ್ vcpkg triplet", + "Change vcpkg root location": "vcpkg root ಸ್ಥಳವನ್ನು ಬದಲಾಯಿಸಿ", + "Reset vcpkg root location": "vcpkg ಮೂಲ ಸ್ಥಳವನ್ನು ಮರುಹೊಂದಿಸಿ", + "Open vcpkg root location": "vcpkg ಮೂಲ ಸ್ಥಳವನ್ನು ತೆರೆಯಿರಿ", + "Language, theme and other miscellaneous preferences": "ಭಾಷೆ, theme ಮತ್ತು ಇತರ miscellaneous preferences", + "Show notifications on different events": "ವಿಭಿನ್ನ ಘಟನೆಗಳ ಸಂದರ್ಭದಲ್ಲಿ ಅಧಿಸೂಚನೆಗಳನ್ನು ತೋರಿಸಿ", + "Change how UniGetUI checks and installs available updates for your packages": "ನಿಮ್ಮ ಪ್ಯಾಕೇಜ್‌ಗಳಿಗಾಗಿ ಲಭ್ಯವಿರುವ ನವೀಕರಣಗಳನ್ನು UniGetUI ಹೇಗೆ ಪರಿಶೀಲಿಸುತ್ತದೆ ಮತ್ತು ಸ್ಥಾಪಿಸುತ್ತದೆ ಎಂಬುದನ್ನು ಬದಲಾಯಿಸಿ", + "Automatically save a list of all your installed packages to easily restore them.": "ನಿಮ್ಮ ಎಲ್ಲಾ ಸ್ಥಾಪಿತ ಪ್ಯಾಕೇಜ್‌ಗಳ ಪಟ್ಟಿಯನ್ನು ಸ್ವಯಂಚಾಲಿತವಾಗಿ ಉಳಿಸಿ ಮತ್ತು ಅವುಗಳನ್ನು ಸುಲಭವಾಗಿ ಪುನಃಸ್ಥಾಪಿಸಿ.", + "Enable and disable package managers, change default install options, etc.": "package managers ಅನ್ನು ಸಕ್ರಿಯ ಮತ್ತು ಅಚೇತನಗೊಳಿಸಿ, ಡೀಫಾಲ್ಟ್ ಸ್ಥಾಪನಾ ಆಯ್ಕೆಗಳನ್ನು ಬದಲಿಸಿ, ಇತ್ಯಾದಿ", + "Internet connection settings": "Internet ಸಂಪರ್ಕ settings", + "Proxy settings, etc.": "Proxy settings, ಇತ್ಯಾದಿ.", + "Beta features and other options that shouldn't be touched": "ಬೀಟಾ ವೈಶಿಷ್ಟ್ಯಗಳು ಮತ್ತು ಸ್ಪರ್ಶಿಸಬಾರದ ಇತರ ಆಯ್ಕೆಗಳು", + "Reload sources": "ಮೂಲಗಳನ್ನು ಮರುಲೋಡ್ ಮಾಡಿ", + "Delete source": "ಮೂಲವನ್ನು ಅಳಿಸಿ", + "Known sources": "ತಿಳಿದಿರುವ ಮೂಲಗಳು", + "Update checking": "update ಪರಿಶೀಲನೆ", + "Automatic updates": "ಸ್ವಯಂಚಾಲಿತ ನವೀಕರಣಗಳು", + "Check for package updates periodically": "ಪ್ಯಾಕೇಜ್ ನವೀಕರಣಗಳನ್ನು ನಿಯಮಿತವಾಗಿ ಪರಿಶೀಲಿಸಿ", + "Check for updates every:": "ಪ್ರತಿ: ನವೀಕರಣಗಳನ್ನು ಪರಿಶೀಲಿಸಿ", + "Install available updates automatically": "ಲಭ್ಯವಿರುವ ನವೀಕರಣಗಳನ್ನು ಸ್ವಯಂಚಾಲಿತವಾಗಿ ಸ್ಥಾಪಿಸಿ", + "Do not automatically install updates when the network connection is metered": "network connection metered ಆಗಿರುವಾಗ ನವೀಕರಣಗಳನ್ನು ಸ್ವಯಂಚಾಲಿತವಾಗಿ ಸ್ಥಾಪಿಸಬೇಡಿ", + "Do not automatically install updates when the device runs on battery": "ಸಾಧನವು ಬ್ಯಾಟರಿಯಲ್ಲಿ ಕಾರ್ಯನಿರ್ವಹಿಸುವಾಗ ನವೀಕರಣಗಳನ್ನು ಸ್ವಯಂಚಾಲಿತವಾಗಿ ಸ್ಥಾಪಿಸಬೇಡಿ", + "Do not automatically install updates when the battery saver is on": "battery saver ಆನ್ ಆಗಿರುವಾಗ ನವೀಕರಣಗಳನ್ನು ಸ್ವಯಂಚಾಲಿತವಾಗಿ ಸ್ಥಾಪಿಸಬೇಡಿ", + "Only show updates that are at least the specified number of days old": "ಸೂಚಿಸಲಾದ ದಿನಗಳ ಸಂಖ್ಯೆಗೆ ಸಮಾನ ಅಥವಾ ಅದಕ್ಕಿಂತ ಹಳೆಯ ನವೀಕರಣಗಳನ್ನು ಮಾತ್ರ ತೋರಿಸಿ", + "Warn me when the installer URL host changes between the installed version and the new version (WinGet only)": "install ಆಗಿರುವ version ಮತ್ತು ಹೊಸ version ನಡುವೆ installer URL host ಬದಲಾದಾಗ ನನಗೆ ಎಚ್ಚರಿಸಿ (WinGet ಮಾತ್ರ)", + "Change how UniGetUI handles install, update and uninstall operations.": "UniGetUI ಸ್ಥಾಪನೆ, ನವೀಕರಣ ಮತ್ತು ಅಸ್ಥಾಪನಾ ಕಾರ್ಯಾಚರಣೆಗಳನ್ನು ಹೇಗೆ ನಿರ್ವಹಿಸುತ್ತದೆ ಎಂಬುದನ್ನು ಬದಲಿಸಿ.", + "Navigation": "ನ್ಯಾವಿಗೇಶನ್", + "Check for UniGetUI updates": "UniGetUI updates ಪರಿಶೀಲಿಸಿ", + "Quit UniGetUI": "UniGetUI ನಿಂದ ನಿರ್ಗಮಿಸಿ", + "Filters": "ಫಿಲ್ಟರ್‌ಗಳು", + "Sources": "ಮೂಲಗಳು", + "Search for packages to start": "ಪ್ರಾರಂಭಿಸಲು ಪ್ಯಾಕೇಜ್‌ಗಳನ್ನು ಹುಡುಕಿ", + "Select all": "ಎಲ್ಲವನ್ನೂ ಆಯ್ಕೆಮಾಡಿ", + "Clear selection": "ಆಯ್ಕೆಯನ್ನು ತೆರವುಗೊಳಿಸಿ", + "Instant search": "ತಕ್ಷಣದ ಹುಡುಕಾಟ", + "Distinguish between uppercase and lowercase": "ದೊಡ್ಡ ಅಕ್ಷರ ಮತ್ತು ಸಣ್ಣ ಅಕ್ಷರಗಳ ನಡುವಿನ ಭೇದವನ್ನು ಗುರುತಿಸಿ", + "Ignore special characters": "ವಿಶೇಷ ಅಕ್ಷರಗಳನ್ನು ನಿರ್ಲಕ್ಷಿಸಿ", + "Search mode": "ಹುಡುಕಾಟ mode", + "Both": "ಎರಡೂ", + "Exact match": "ಸೂಕ್ಷ್ಮ ಹೊಂದಿಕೆ", + "Show similar packages": "ಸಮಾನ ಪ್ಯಾಕೇಜ್‌ಗಳನ್ನು ತೋರಿಸಿ", + "Loading": "ಲೋಡ್ ಆಗುತ್ತಿದೆ", + "Package": "ಪ್ಯಾಕೇಜ್", + "More options": "ಇನ್ನಷ್ಟು ಆಯ್ಕೆಗಳು", + "Order by:": "ಕ್ರಮಗೊಳಿಸುವ ವಿಧಾನ:", + "Name": "ಹೆಸರು", + "Id": "ಗುರುತು", + "Ascendant": "ಆರೋಹಣ", + "Descendant": "ಅವರೋಹಿ", + "View modes": "ವೀಕ್ಷಣೆ ಮೋಡ್‌ಗಳು", + "Reload": "ಮರುಲೋಡ್", + "Closed": "ಮುಚ್ಚಲಾಗಿದೆ", + "Ascending": "ಆರೋಹಣ", + "Descending": "ಅವರೋಹಣ", + "{0}: {1}, {2}": "{0}: {1}, {2}", + "Order by": "ಕ್ರಮಪಡಿಸಿ", + "No results were found matching the input criteria": "ನಮೂದಿಸಿದ ಮಾನದಂಡಗಳಿಗೆ ಹೊಂದುವ ಯಾವುದೇ ಫಲಿತಾಂಶಗಳು ಕಂಡುಬಂದಿಲ್ಲ", + "No packages were found": "ಯಾವುದೇ ಪ್ಯಾಕೇಜ್‌ಗಳು ಕಂಡುಬಂದಿಲ್ಲ", + "Loading packages": "ಪ್ಯಾಕೇಜ್‌ಗಳು load ಆಗುತ್ತಿವೆ", + "Skip integrity checks": "integrity checks ಬಿಟ್ಟುಬಿಡಿ", + "Download selected installers": "ಆಯ್ದ installers ಡೌನ್‌ಲೋಡ್ ಮಾಡಿ", + "Install selection": "ಆಯ್ಕೆಯನ್ನು ಸ್ಥಾಪಿಸಿ", + "Install options": "ಸ್ಥಾಪನಾ ಆಯ್ಕೆಗಳು", + "Add selection to bundle": "ಬಂಡಲ್‌ಗೆ ವಿಭಾಗವನ್ನು ಸೇರಿಸಿ", + "Download installer": "installer ಡೌನ್‌ಲೋಡ್ ಮಾಡಿ", + "Uninstall selection": "ಆಯ್ಕೆಯನ್ನು uninstall ಮಾಡಿ", + "Uninstall options": "uninstall ಆಯ್ಕೆಗಳು", + "Ignore selected packages": "ಆಯ್ದ ಪ್ಯಾಕೇಜ್‌ಗಳನ್ನು ನಿರ್ಲಕ್ಷಿಸಿ", + "Open install location": "install ಸ್ಥಳವನ್ನು ತೆರೆಯಿರಿ", + "Reinstall package": "ಪ್ಯಾಕೇಜ್ ಅನ್ನು ಮರುಸ್ಥಾಪಿಸಿ", + "Uninstall package, then reinstall it": "package uninstall ಮಾಡಿ, ನಂತರ ಅದನ್ನು reinstall ಮಾಡಿ", + "Ignore updates for this package": "ಈ ಪ್ಯಾಕೇಜ್‌ನ ನವೀಕರಣಗಳನ್ನು ನಿರ್ಲಕ್ಷಿಸಿ", + "WinGet malfunction detected": "WinGet ದೋಷ ಪತ್ತೆಯಾಗಿದೆ", + "It looks like WinGet is not working properly. Do you want to attempt to repair WinGet?": "WinGet ಸರಿಯಾಗಿ ಕೆಲಸ ಮಾಡುತ್ತಿಲ್ಲವೆಂದು ಕಾಣುತ್ತದೆ. WinGet ಅನ್ನು ಸರಿಪಡಿಸಲು ಪ್ರಯತ್ನಿಸಲು ಬಯಸುವಿರಾ?", + "Repair WinGet": "WinGet ಅನ್ನು ಸರಿಪಡಿಸಿ", + "Updates will no longer be ignored for {0}": "{0} ಗೆ ನವೀಕರಣಗಳನ್ನು ಇನ್ನು ಮುಂದೆ ನಿರ್ಲಕ್ಷಿಸಲಾಗುವುದಿಲ್ಲ", + "Updates are now ignored for {0}": "{0} ಗೆ ನವೀಕರಣಗಳನ್ನು ಈಗ ನಿರ್ಲಕ್ಷಿಸಲಾಗಿದೆ", + "Do not ignore updates for this package anymore": "ಈ ಪ್ಯಾಕೇಜ್‌ನ ನವೀಕರಣಗಳನ್ನು ಇನ್ನು ಮುಂದೆ ನಿರ್ಲಕ್ಷಿಸಬೇಡಿ", + "Add packages or open an existing package bundle": "ಪ್ಯಾಕೇಜ್‌ಗಳನ್ನು ಸೇರಿಸಿ ಅಥವಾ ಇರುವ ಪ್ಯಾಕೇಜ್ ಬಂಡಲ್ ಅನ್ನು ತೆರೆಯಿರಿ", + "Add packages to start": "ಪ್ರಾರಂಭಿಸಲು ಪ್ಯಾಕೇಜ್‌ಗಳನ್ನು ಸೇರಿಸಿ", + "The current bundle has no packages. Add some packages to get started": "ಪ್ರಸ್ತುತ bundle ನಲ್ಲಿ ಯಾವುದೇ ಪ್ಯಾಕೇಜ್‌ಗಳಿಲ್ಲ. ಪ್ರಾರಂಭಿಸಲು ಕೆಲವು ಪ್ಯಾಕೇಜ್‌ಗಳನ್ನು ಸೇರಿಸಿ", + "New": "ಹೊಸದು", + "Save as": "ಹಾಗೆ ಉಳಿಸಿ", + "Create .ps1 script": ".ps1 ಸ್ಕ್ರಿಪ್ಟ್ ರಚಿಸಿ", + "Remove selection from bundle": "ಆಯ್ಕೆಯನ್ನು bundle ನಿಂದ ತೆಗೆದುಹಾಕಿ", + "Skip hash checks": "hash checks ಬಿಟ್ಟುಬಿಡಿ", + "The package bundle is not valid": "package bundle ಮಾನ್ಯವಲ್ಲ", + "The bundle you are trying to load appears to be invalid. Please check the file and try again.": "ನೀವು load ಮಾಡಲು ಪ್ರಯತ್ನಿಸುತ್ತಿರುವ bundle ಅಮಾನ್ಯವಾಗಿದೆ ಎಂದು ಕಾಣುತ್ತದೆ. ದಯವಿಟ್ಟು file ಪರಿಶೀಲಿಸಿ ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ.", + "Package bundle": "ಪ್ಯಾಕೇಜ್ bundle", + "Could not create bundle": "ಬಂಡಲ್ ರಚಿಸಲು ಸಾಧ್ಯವಾಗಲಿಲ್ಲ", + "The package bundle could not be created due to an error.": "ದೋಷದಿಂದ package bundle ರಚಿಸಲಾಗಲಿಲ್ಲ.", + "Install script": "ಸ್ಥಾಪನಾ script", + "PowerShell script": "PowerShell ಸ್ಕ್ರಿಪ್ಟ್", + "The installation script saved to {0}": "installation script ಅನ್ನು {0} ಗೆ ಉಳಿಸಲಾಗಿದೆ", + "An error occurred": "ದೋಷ ಸಂಭವಿಸಿದೆ", + "An error occurred while attempting to create an installation script:": "ಸ್ಥಾಪನಾ script ರಚಿಸಲು ಪ್ರಯತ್ನಿಸುವಾಗ ದೋಷ ಸಂಭವಿಸಿದೆ:", + "Hooray! No updates were found.": "ಹುರ್ರೇ! ಯಾವುದೇ ನವೀಕರಣಗಳು ಕಂಡುಬಂದಿಲ್ಲ.", + "Uninstall selected packages": "ಆಯ್ಕೆಮಾಡಿದ packages ಗಳನ್ನು uninstall ಮಾಡಿ", + "Update selection": "ಆಯ್ಕೆಯನ್ನು update ಮಾಡಿ", + "Update options": "update ಆಯ್ಕೆಗಳು", + "Uninstall package, then update it": "package uninstall ಮಾಡಿ, ನಂತರ ಅದನ್ನು update ಮಾಡಿ", + "Uninstall package": "package ಅನ್ನು uninstall ಮಾಡಿ", + "Skip this version": "ಈ version ಬಿಟ್ಟುಬಿಡಿ", + "Pause updates for": "ನವೀಕರಣಗಳನ್ನು ಇಷ್ಟು ಕಾಲ ವಿರಮಿಸಿ", + "User | Local": "ಬಳಕೆದಾರ | ಸ್ಥಳೀಯ", + "Machine | Global": "ಯಂತ್ರ | ಜಾಗತಿಕ", + "The default package manager for Debian/Ubuntu-based Linux distributions.
Contains: Debian/Ubuntu packages": "Debian/Ubuntu-ಆಧಾರಿತ Linux ವಿತರಣೆಗಳಿಗೆ ಡೀಫಾಲ್ಟ್ ಪ್ಯಾಕೇಜ್ ಮ್ಯಾನೇಜರ್.
ಒಳಗೊಂಡಿದೆ: Debian/Ubuntu ಪ್ಯಾಕೇಜ್‌ಗಳು", + "The Rust package manager.
Contains: Rust libraries and programs written in Rust": "Rust package manager.
ಒಳಗೊಂಡಿರುವುದು: Rust libraries ಮತ್ತು Rust ನಲ್ಲಿ ಬರೆಯಲ್ಪಟ್ಟ programs", + "The classical package manager for windows. You'll find everything there.
Contains: General Software": "windows ಗಾಗಿ ಸಾಂಪ್ರದಾಯಿಕ package manager. ಅಲ್ಲಿ ನೀವು ಎಲ್ಲವನ್ನೂ ಕಾಣಬಹುದು.
ಒಳಗೊಂಡಿರುವುದು: General Software", + "The default package manager for RHEL/Fedora-based Linux distributions.
Contains: RPM packages": "RHEL/Fedora-ಆಧಾರಿತ Linux ವಿತರಣೆಗಳಿಗೆ ಡೀಫಾಲ್ಟ್ ಪ್ಯಾಕೇಜ್ ಮ್ಯಾನೇಜರ್.
ಒಳಗೊಂಡಿದೆ: RPM ಪ್ಯಾಕೇಜ್‌ಗಳು", + "A repository full of tools and executables designed with Microsoft's .NET ecosystem in mind.
Contains: .NET related tools and scripts": "Microsoft ನ .NET ಪರಿಸರವ್ಯವಸ್ಥೆಯನ್ನು ಗಮನದಲ್ಲಿಟ್ಟುಕೊಂಡು ರೂಪಿಸಲಾದ tools ಮತ್ತು executables ಗಳಿಂದ ತುಂಬಿರುವ repository.
ಒಳಗೊಂಡಿದೆ: .NET ಸಂಬಂಧಿತ tools ಮತ್ತು scripts", + "The universal Linux package manager for desktop applications.
Contains: Flatpak applications from configured remotes": "ಡೆಸ್ಕ್‌ಟಾಪ್ ಅನ್ವಯಿಕೆಗಳಿಗಾಗಿ ಸಾರ್ವತ್ರಿಕ Linux ಪ್ಯಾಕೇಜ್ ಮ್ಯಾನೇಜರ್.
ಒಳಗೊಂಡಿದೆ: ಕಾನ್ಫಿಗರ್ ಮಾಡಿದ ರಿಮೋಟ್‌ಗಳಿಂದ Flatpak ಅನ್ವಯಿಕೆಗಳು", + "NuPkg (zipped manifest)": "NuPkg (zip ಮಾಡಿದ manifest)", + "The Missing Package Manager for macOS (or Linux).
Contains: Formulae, Casks": "macOS (ಅಥವಾ Linux) ಗಾಗಿ ಇಲ್ಲದಿರುವ package manager.
ಇದರಲ್ಲಿ ಇರುವವು: Formulae, Casks", + "Node JS's package manager. Full of libraries and other utilities that orbit the javascript world
Contains: Node javascript libraries and other related utilities": "Node JS ನ package manager. javascript ಜಗತ್ತನ್ನು ಸುತ್ತುವರಿದ libraries ಮತ್ತು ಇತರ utilities ಗಳಿಂದ ತುಂಬಿದೆ
ಒಳಗೊಂಡಿರುವುದು: Node javascript libraries ಮತ್ತು ಇತರ ಸಂಬಂಧಿತ utilities", + "The default package manager for Arch Linux and its derivatives.
Contains: Arch Linux packages": "Arch Linux ಮತ್ತು ಅದರ ಉತ್ಪನ್ನಗಳಿಗೆ ಡೀಫಾಲ್ಟ್ ಪ್ಯಾಕೇಜ್ ಮ್ಯಾನೇಜರ್.
ಒಳಗೊಂಡಿದೆ: Arch Linux ಪ್ಯಾಕೇಜ್‌ಗಳು", + "Python's library manager. Full of python libraries and other python-related utilities
Contains: Python libraries and related utilities": "Python ನ library manager. python libraries ಮತ್ತು python ಗೆ ಸಂಬಂಧಿತ ಇತರ utilities ಗಳಿಂದ ತುಂಬಿದೆ
ಒಳಗೊಂಡಿರುವುದು: Python libraries ಮತ್ತು ಸಂಬಂಧಿತ utilities", + "PowerShell's package manager. Find libraries and scripts to expand PowerShell capabilities
Contains: Modules, Scripts, Cmdlets": "PowerShell ನ package manager. PowerShell ಸಾಮರ್ಥ್ಯಗಳನ್ನು ವಿಸ್ತರಿಸಲು libraries ಮತ್ತು scripts ಕಂಡುಹಿಡಿಯಿರಿ
ಒಳಗೊಂಡಿರುವುದು: Modules, Scripts, Cmdlets", + "extracted": "ಹೊರತೆಗೆದಿದೆ", + "Scoop package": "Scoop ಪ್ಯಾಕೇಜ್", + "Great repository of unknown but useful utilities and other interesting packages.
Contains: Utilities, Command-line programs, General Software (extras bucket required)": "ಅಪರಿಚಿತ ಆದರೆ ಉಪಯುಕ್ತ utilities ಮತ್ತು ಇತರೆ ಆಸಕ್ತಿದಾಯಕ ಪ್ಯಾಕೇಜ್‌ಗಳ ಉತ್ತಮ repository.
ಒಳಗೊಂಡಿದೆ: Utilities, command-line ಕಾರ್ಯಕ್ರಮಗಳು, ಸಾಮಾನ್ಯ software (extras bucket ಅಗತ್ಯ)", + "The universal Linux package manager by Canonical.
Contains: Snap packages from the Snapcraft store": "Canonical ನಿಂದ ಸಾರ್ವತ್ರಿಕ Linux ಪ್ಯಾಕೇಜ್ ಮ್ಯಾನೇಜರ್.
ಒಳಗೊಂಡಿದೆ: Snapcraft ಅಂಗಡಿಯಿಂದ Snap ಪ್ಯಾಕೇಜ್‌ಗಳು", + "library": "ಗ್ರಂಥಾಲಯ", + "feature": "ವೈಶಿಷ್ಟ್ಯ", + "A popular C/C++ library manager. Full of C/C++ libraries and other C/C++-related utilities
Contains: C/C++ libraries and related utilities": "ಜನಪ್ರಿಯ C/C++ ಲೈಬ್ರರಿ ನಿರ್ವಾಹಕ. C/C++ ಲೈಬ್ರರಿಗಳು ಮತ್ತು ಇತರೆ C/C++ ಸಂಬಂಧಿತ ಉಪಯುಕ್ತಿಗಳಿಂದ ತುಂಬಿದೆ
ಒಳಗೊಂಡಿದೆ: C/C++ ಲೈಬ್ರರಿಗಳು ಮತ್ತು ಸಂಬಂಧಿತ ಉಪಯುಕ್ತಿಗಳು", + "option": "ಆಯ್ಕೆ", + "This package cannot be installed from an elevated context.": "ಈ package ಅನ್ನು elevated context ಇಂದ install ಮಾಡಲಾಗುವುದಿಲ್ಲ.", + "Please run UniGetUI as a regular user and try again.": "UniGetUI ಅನ್ನು ಸಾಮಾನ್ಯ ಬಳಕೆದಾರರಂತೆ ಚಲಾಯಿಸಿ ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ.", + "Please check the installation options for this package and try again": "ದಯವಿಟ್ಟು ಈ ಪ್ಯಾಕೇಜ್‌ನ installation options ಪರಿಶೀಲಿಸಿ ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ", + "Microsoft's official package manager. Full of well-known and verified packages
Contains: General Software, Microsoft Store apps": "Microsoft ನ ಅಧಿಕೃತ package manager. ಪ್ರಸಿದ್ಧ ಮತ್ತು ಪರಿಶೀಲಿತ ಪ್ಯಾಕೇಜ್‌ಗಳಿಂದ ತುಂಬಿದೆ
ಒಳಗೊಂಡಿರುವುದು: ಸಾಮಾನ್ಯ software, Microsoft Store apps", + "Local PC": "ಸ್ಥಳೀಯ PC", + "Android Subsystem": "ಆಂಡ್ರಾಯ್ಡ್ ಉಪವ್ಯವಸ್ಥೆ", + "Operation on queue (position {0})...": "queue ಯಲ್ಲಿರುವ ಕಾರ್ಯಾಚರಣೆ (ಸ್ಥಾನ {0})...", + "Click here for more details": "ಹೆಚ್ಚಿನ ವಿವರಗಳಿಗಾಗಿ ಇಲ್ಲಿ ಕ್ಲಿಕ್ ಮಾಡಿ", + "Operation canceled by user": "ಕಾರ್ಯಾಚರಣೆ ಬಳಕೆದಾರರಿಂದ ರದ್ದುಗೊಂಡಿತು", + "Running PreOperation ({0}/{1})...": "PreOperation ({0}/{1}) ನಡೆಯುತ್ತಿದೆ...", + "PreOperation {0} out of {1} failed, and was tagged as necessary. Aborting...": "{1} ನಲ್ಲಿ {0}ನೇ PreOperation ವಿಫಲವಾಯಿತು ಮತ್ತು ಅಗತ್ಯವೆಂದು ಗುರುತಿಸಲ್ಪಟ್ಟಿತ್ತು. ರದ್ದುಗೊಳಿಸಲಾಗುತ್ತಿದೆ...", + "PreOperation {0} out of {1} finished with result {2}": "{1} ನಲ್ಲಿ {0}ನೇ PreOperation {2} ಫಲಿತಾಂಶದೊಂದಿಗೆ ಪೂರ್ಣಗೊಂಡಿತು", + "Starting operation...": "ಕಾರ್ಯಾಚರಣೆ ಪ್ರಾರಂಭಗೊಳ್ಳುತ್ತಿದೆ...", + "Running PostOperation ({0}/{1})...": "PostOperation ({0}/{1}) ನಡೆಯುತ್ತಿದೆ...", + "PostOperation {0} out of {1} failed, and was tagged as necessary. Aborting...": "{1} ನಲ್ಲಿ {0}ನೇ PostOperation ವಿಫಲವಾಯಿತು ಮತ್ತು ಅಗತ್ಯವೆಂದು ಗುರುತಿಸಲ್ಪಟ್ಟಿತ್ತು. ರದ್ದುಗೊಳಿಸಲಾಗುತ್ತಿದೆ...", + "PostOperation {0} out of {1} finished with result {2}": "{1} ನಲ್ಲಿ {0}ನೇ PostOperation {2} ಫಲಿತಾಂಶದೊಂದಿಗೆ ಪೂರ್ಣಗೊಂಡಿತು", + "{package} installer download": "{package} ಇನ್‌ಸ್ಟಾಲರ್ ಡೌನ್‌ಲೋಡ್", + "{0} installer is being downloaded": "{0} installer download ಆಗುತ್ತಿದೆ", + "Download succeeded": "ಡೌನ್‌ಲೋಡ್ ಯಶಸ್ವಿಯಾಯಿತು", + "{package} installer was downloaded successfully": "{package} installer ಯಶಸ್ವಿಯಾಗಿ download ಆಗಿದೆ", + "Download failed": "ಡೌನ್‌ಲೋಡ್ ವಿಫಲವಾಗಿದೆ", + "{package} installer could not be downloaded": "{package} installer download ಮಾಡಲಾಗಲಿಲ್ಲ", + "{package} Installation": "{package} ಸ್ಥಾಪನೆ", + "{0} is being installed": "{0} install ಆಗುತ್ತಿದೆ", + "Installation succeeded": "ಸ್ಥಾಪನೆ ಯಶಸ್ವಿಯಾಗಿದೆ", + "{package} was installed successfully": "{package} ಯಶಸ್ವಿಯಾಗಿ install ಆಗಿದೆ", + "Installation failed": "ಸ್ಥಾಪನೆ ವಿಫಲವಾಗಿದೆ", + "{package} could not be installed": "{package} install ಮಾಡಲಾಗಲಿಲ್ಲ", + "{package} Update": "{package} ನವೀಕರಣ", + "Update succeeded": "update ಯಶಸ್ವಿಯಾಯಿತು", + "{package} was updated successfully": "{package} ಯಶಸ್ವಿಯಾಗಿ update ಆಗಿದೆ", + "Update failed": "update ವಿಫಲವಾಗಿದೆ", + "{package} could not be updated": "{package} update ಮಾಡಲಾಗಲಿಲ್ಲ", + "{package} Uninstall": "{package} ಅನ್‌ಇನ್‌ಸ್ಟಾಲ್", + "{0} is being uninstalled": "{0} uninstall ಆಗುತ್ತಿದೆ", + "Uninstall succeeded": "uninstall ಯಶಸ್ವಿಯಾಯಿತು", + "{package} was uninstalled successfully": "{package} ಯಶಸ್ವಿಯಾಗಿ uninstall ಆಗಿದೆ", + "Uninstall failed": "uninstall ವಿಫಲವಾಗಿದೆ", + "{package} could not be uninstalled": "{package} uninstall ಮಾಡಲಾಗಲಿಲ್ಲ", + "Adding source {source}": "ಮೂಲ {source} ಅನ್ನು ಸೇರಿಸಲಾಗುತ್ತಿದೆ", + "Adding source {source} to {manager}": "{manager} ಗೆ ಮೂಲ {source} ಅನ್ನು ಸೇರಿಸಲಾಗುತ್ತಿದೆ", + "Source added successfully": "source ಯಶಸ್ವಿಯಾಗಿ ಸೇರಿಸಲಾಗಿದೆ", + "The source {source} was added to {manager} successfully": "source {source} ಅನ್ನು {manager} ಗೆ ಯಶಸ್ವಿಯಾಗಿ ಸೇರಿಸಲಾಗಿದೆ", + "Could not add source": "ಮೂಲವನ್ನು ಸೇರಿಸಲು ಸಾಧ್ಯವಾಗಲಿಲ್ಲ", + "Could not add source {source} to {manager}": "{manager} ಗೆ {source} ಮೂಲವನ್ನು ಸೇರಿಸಲು ಸಾಧ್ಯವಾಗಲಿಲ್ಲ", + "Removing source {source}": "source {source} ಅನ್ನು ತೆಗೆದುಹಾಕಲಾಗುತ್ತಿದೆ", + "Removing source {source} from {manager}": "{manager} ನಿಂದ source {source} ಅನ್ನು ತೆಗೆದುಹಾಕಲಾಗುತ್ತಿದೆ", + "Source removed successfully": "source ಯಶಸ್ವಿಯಾಗಿ ತೆಗೆದುಹಾಕಲಾಗಿದೆ", + "The source {source} was removed from {manager} successfully": "source {source} ಅನ್ನು {manager} ಇಂದ ಯಶಸ್ವಿಯಾಗಿ ತೆಗೆದುಹಾಕಲಾಗಿದೆ", + "Could not remove source": "ಮೂಲವನ್ನು ತೆಗೆದುಹಾಕಲು ಸಾಧ್ಯವಾಗಲಿಲ್ಲ", + "Could not remove source {source} from {manager}": "{manager} ಯಿಂದ {source} ಮೂಲವನ್ನು ತೆಗೆದುಹಾಕಲು ಸಾಧ್ಯವಾಗಲಿಲ್ಲ", + "The package manager \"{0}\" was not found": "package manager \"{0}\" ಕಂಡುಬಂದಿಲ್ಲ", + "The package manager \"{0}\" is disabled": "package manager \"{0}\" ನಿಷ್ಕ್ರಿಯವಾಗಿದೆ", + "There is an error with the configuration of the package manager \"{0}\"": "package manager \"{0}\" ನ configuration ನಲ್ಲಿ ದೋಷವಿದೆ", + "The package \"{0}\" was not found on the package manager \"{1}\"": "\"{0}\" package manager \"{1}\" ನಲ್ಲಿ ಕಂಡುಬಂದಿಲ್ಲ", + "{0} is disabled": "{0} ನಿಷ್ಕ್ರಿಯವಾಗಿದೆ", + "{0} weeks": "{0} ವಾರಗಳು", + "1 month": "1 ತಿಂಗಳು", + "{0} months": "{0} ತಿಂಗಳುಗಳು", + "Something went wrong": "ಏನೋ ತಪ್ಪಾಗಿದೆ", + "An interal error occurred. Please view the log for further details.": "ಆಂತರಿಕ ದೋಷ ಸಂಭವಿಸಿದೆ. ಹೆಚ್ಚಿನ ವಿವರಗಳಿಗಾಗಿ ಲಾಗ್ ಅನ್ನು ವೀಕ್ಷಿಸಿ.", + "No applicable installer was found for the package {0}": "ಪ್ಯಾಕೇಜ್ {0} ಗಾಗಿ ಅನ್ವಯಿಸುವ installer ಕಂಡುಬಂದಿಲ್ಲ", + "Integrity checks will not be performed during this operation": "ಈ ಕಾರ್ಯಾಚರಣೆಯ ವೇಳೆ Integrity checks ನಡೆಸಲಾಗುವುದಿಲ್ಲ", + "This is not recommended.": "ಇದು ಶಿಫಾರಸು ಮಾಡಲಾಗುವುದಿಲ್ಲ.", + "Run now": "ಈಗ ಚಾಲನೆ ಮಾಡಿ", + "Run next": "ಮುಂದಿನದಾಗಿ ಚಾಲನೆ ಮಾಡಿ", + "Run last": "ಕೊನೆಯಲ್ಲಿ ಚಾಲನೆ ಮಾಡಿ", + "Show in explorer": "explorer ನಲ್ಲಿ ತೋರಿಸಿ", + "Checked": "ಗುರುತಿಸಲಾಗಿದೆ", + "Unchecked": "ಗುರುತಿಸಲಾಗಿಲ್ಲ", + "This package is already installed": "ಈ package ಈಗಾಗಲೇ ಸ್ಥಾಪಿಸಲಾಗಿದೆ", + "This package can be upgraded to version {0}": "ಈ package ಅನ್ನು version {0} ಗೆ upgrade ಮಾಡಬಹುದು", + "Updates for this package are ignored": "ಈ package ಗಾಗಿ updates ನಿರ್ಲಕ್ಷಿಸಲಾಗಿದೆ", + "This package is being processed": "ಈ package ಪ್ರಕ್ರಿಯೆಯಲ್ಲಿದೆ", + "This package is not available": "ಈ package ಲಭ್ಯವಿಲ್ಲ", + "Select the source you want to add:": "ನೀವು ಸೇರಿಸಲು ಬಯಸುವ source ಆಯ್ಕೆಮಾಡಿ:", + "Source name:": "source ಹೆಸರು:", + "Source URL:": "ಮೂಲ URL:", + "An error occurred when adding the source: ": "ಮೂಲವನ್ನು ಸೇರಿಸುವಾಗ ದೋಷ ಸಂಭವಿಸಿದೆ:", + "Package management made easy": "ಪ್ಯಾಕೇಜ್ ನಿರ್ವಹಣೆಯನ್ನು ಸುಲಭಗೊಳಿಸಲಾಗಿದೆ", + "version {0}": "ಆವೃತ್ತಿ {0}", + "[RAN AS ADMINISTRATOR]": "[ADMINISTRATOR ಆಗಿ ಚಾಲನೆ ಮಾಡಲಾಗಿದೆ]", + "Portable mode": "ಪೋರ್ಟೆಬಲ್ ಮೋಡ್\n", + "DEBUG BUILD": "DEBUG build", + "Here you can change UniGetUI's behaviour regarding the following shortcuts. Checking a shortcut will make UniGetUI delete it if if gets created on a future upgrade. Unchecking it will keep the shortcut intact": "ಇಲ್ಲಿ ನೀವು ಕೆಳಗಿನ shortcuts ಕುರಿತು UniGetUI ನ ನಡೆನುಡಿಯನ್ನು ಬದಲಾಯಿಸಬಹುದು. ಒಂದು shortcut ಅನ್ನು ಗುರುತಿಸಿದರೆ, ಭವಿಷ್ಯದ upgrade ವೇಳೆ ಅದು ರಚಿಸಲ್ಪಟ್ಟರೆ UniGetUI ಅದನ್ನು ಅಳಿಸುತ್ತದೆ. ಗುರುತನ್ನು ತೆಗೆಯುವುದರಿಂದ shortcut ಹಾಗೆಯೇ ಉಳಿಯುತ್ತದೆ.", + "Manual scan": "ಕೈಯಾರೆ ಪರಿಶೀಲನೆ", + "Existing shortcuts on your desktop will be scanned, and you will need to pick which ones to keep and which ones to remove.": "ನಿಮ್ಮ desktop‌ನಲ್ಲಿರುವ ಈಗಿರುವ shortcuts ಪರಿಶೀಲಿಸಲಾಗುತ್ತದೆ, ಮತ್ತು ಯಾವುದನ್ನು ಉಳಿಸಬೇಕು ಹಾಗೂ ಯಾವುದನ್ನು ತೆಗೆದುಹಾಕಬೇಕು ಎಂಬುದನ್ನು ನೀವು ಆಯ್ಕೆ ಮಾಡಬೇಕು.", + "Delete?": "ಅಳಿಸಬೇಕೆ?", + "I understand": "ನಾನು ಅರ್ಥಮಾಡಿಕೊಂಡಿದ್ದೇನೆ", + "Chocolatey setup changed": "Chocolatey ಸೆಟಪ್ ಬದಲಾಗಿದೆ", + "UniGetUI no longer includes its own private Chocolatey installation. A legacy UniGetUI-managed Chocolatey installation was detected for this user profile, but system Chocolatey was not found. Chocolatey will stay unavailable in UniGetUI until Chocolatey is installed on the system and UniGetUI is restarted. Applications previously installed through UniGetUI's bundled Chocolatey may still appear under other sources such as Local PC or WinGet.": "UniGetUI ಇನ್ನು ಮುಂದೆ ತನ್ನದೇ ಆದ ಖಾಸಗಿ Chocolatey ಅಳವಡಿಕೆಯನ್ನು ಒಳಗೊಂಡಿಲ್ಲ. ಈ ಬಳಕೆದಾರ ಪ್ರೊಫೈಲ್‌ಗಾಗಿ ಹಳೆಯ UniGetUI-ನಿರ್ವಹಿತ Chocolatey ಅಳವಡಿಕೆಯನ್ನು ಪತ್ತೆಹಚ್ಚಲಾಗಿದೆ, ಆದರೆ ಸಿಸ್ಟಮ್ Chocolatey ಕಂಡುಬಂದಿಲ್ಲ. ಸಿಸ್ಟಮ್‌ನಲ್ಲಿ Chocolatey ಅನ್ನು ಸ್ಥಾಪಿಸಿ UniGetUI ಅನ್ನು ಮರುಪ್ರಾರಂಭಿಸುವವರೆಗೆ Chocolatey UniGetUI ಯಲ್ಲಿ ಲಭ್ಯವಿರುವುದಿಲ್ಲ. UniGetUI ಯ ಅಂತರ್ನಿರ್ಮಿತ Chocolatey ಮೂಲಕ ಈ ಹಿಂದೆ ಸ್ಥಾಪಿಸಲಾದ ಅಪ್ಲಿಕೇಶನ್‌ಗಳು Local PC ಅಥವಾ WinGet ನಂತಹ ಇತರ ಮೂಲಗಳಲ್ಲಿ ಇನ್ನೂ ಕಾಣಿಸಬಹುದು.", + "NOTE: This troubleshooter can be disabled from UniGetUI Settings, on the WinGet section": "ಸೂಚನೆ: ಈ troubleshooter ಅನ್ನು UniGetUI Settings ನ WinGet ವಿಭಾಗದಿಂದ ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಬಹುದು", + "Restart": "ಮರುಪ್ರಾರಂಭಿಸಿ", + "Are you sure you want to delete all shortcuts?": "ಎಲ್ಲ shortcuts ಗಳನ್ನು ಅಳಿಸಲು ನೀವು ಖಚಿತವಾಗಿದ್ದೀರಾ?", + "Any new shorcuts created during an install or an update operation will be deleted automatically, instead of showing a confirmation prompt the first time they are detected.": "ಸ್ಥಾಪನೆ ಅಥವಾ ನವೀಕರಣ ಕಾರ್ಯಾಚರಣೆ ವೇಳೆ ರಚಿಸಲಾದ ಯಾವುದೇ ಹೊಸ shortcuts ಮೊದಲ ಬಾರಿ ಪತ್ತೆಯಾದಾಗ ದೃಢೀಕರಣ prompt ತೋರಿಸುವ ಬದಲು ಸ್ವಯಂಚಾಲಿತವಾಗಿ ಅಳಿಸಲಾಗುತ್ತದೆ.", + "Any shorcuts created or modified outside of UniGetUI will be ignored. You will be able to add them via the {0} button.": "UniGetUI ಹೊರಗೆ ರಚಿಸಲಾದ ಅಥವಾ ಬದಲಾಯಿಸಲಾದ ಯಾವುದೇ shortcuts ಗಳನ್ನು ನಿರ್ಲಕ್ಷಿಸಲಾಗುತ್ತದೆ. ನೀವು ಅವನ್ನು {0} ಬಟನ್ ಮೂಲಕ ಸೇರಿಸಬಹುದು.", + "Are you really sure you want to enable this feature?": "ಈ ವೈಶಿಷ್ಟ್ಯವನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಲು ನೀವು ಖಚಿತವಾಗಿಯೂ ಬಯಸುವಿರಾ?", + "No new shortcuts were found during the scan.": "ಪರಿಶೀಲನೆಯ ವೇಳೆ ಯಾವುದೇ ಹೊಸ shortcuts ಕಂಡುಬಂದಿಲ್ಲ.", + "How to add packages to a bundle": "ಬಂಡಲ್‌ಗೆ ಪ್ಯಾಕೇಜ್‌ಗಳನ್ನು ಹೇಗೆ ಸೇರಿಸುವುದು", + "In order to add packages to a bundle, you will need to: ": "ಬಂಡಲ್‌ಗೆ ಪ್ಯಾಕೇಜ್‌ಗಳನ್ನು ಸೇರಿಸಲು, ನೀವು ಈ ಹಂತಗಳನ್ನು ಅನುಸರಿಸಬೇಕು: ", + "1. Navigate to the \"{0}\" or \"{1}\" page.": "1. \"{0}\" ಅಥವಾ \"{1}\" ಪುಟಕ್ಕೆ ಹೋಗಿ.", + "2. Locate the package(s) you want to add to the bundle, and select their leftmost checkbox.": "2. ನೀವು ಬಂಡಲ್‌ಗೆ ಸೇರಿಸಬೇಕಾದ ಪ್ಯಾಕೇಜ್(ಗಳು) ಅನ್ನು ಕಂಡುಹಿಡಿದು, ಅವುಗಳ ಎಡಭಾಗದ checkbox ಅನ್ನು ಆಯ್ಕೆಮಾಡಿ.", + "3. When the packages you want to add to the bundle are selected, find and click the option \"{0}\" on the toolbar.": "3. ನೀವು ಬಂಡಲ್‌ಗೆ ಸೇರಿಸಬೇಕಾದ ಪ್ಯಾಕೇಜ್‌ಗಳನ್ನು ಆಯ್ಕೆ ಮಾಡಿದ ನಂತರ, toolbar ನಲ್ಲಿ \"{0}\" ಆಯ್ಕೆಯನ್ನು ಕಂಡು ಕ್ಲಿಕ್ ಮಾಡಿ.", + "4. Your packages will have been added to the bundle. You can continue adding packages, or export the bundle.": "4. ನಿಮ್ಮ ಪ್ಯಾಕೇಜ್‌ಗಳು ಬಂಡಲ್‌ಗೆ ಸೇರಿಸಲ್ಪಟ್ಟಿರುತ್ತವೆ. ನೀವು ಇನ್ನಷ್ಟು ಪ್ಯಾಕೇಜ್‌ಗಳನ್ನು ಸೇರಿಸಬಹುದು ಅಥವಾ ಬಂಡಲ್ ಅನ್ನು ರಫ್ತು ಮಾಡಬಹುದು.", + "Which backup do you want to open?": "ನೀವು ಯಾವ backup ತೆರೆಯಲು ಬಯಸುತ್ತೀರಿ?", + "Select the backup you want to open. Later, you will be able to review which packages you want to install.": "ನೀವು ತೆರೆಯಬೇಕಾದ backup ಆಯ್ಕೆಮಾಡಿ. ನಂತರ ನೀವು ಯಾವ ಪ್ಯಾಕೇಜ್‌ಗಳನ್ನು ಸ್ಥಾಪಿಸಬೇಕು ಎಂಬುದನ್ನು ಪರಿಶೀಲಿಸಲು ಸಾಧ್ಯವಾಗುತ್ತದೆ.", + "There are ongoing operations. Quitting UniGetUI may cause them to fail. Do you want to continue?": "ಪ್ರಸ್ತುತ ಕಾರ್ಯಾಚರಣೆಗಳು ನಡೆಯುತ್ತಿವೆ. UniGetUI ನಿಂದ ನಿರ್ಗಮಿಸಿದರೆ ಅವು ವಿಫಲವಾಗಬಹುದು. ನೀವು ಮುಂದುವರಿಯಲು ಬಯಸುವಿರಾ?", + "UniGetUI or some of its components are missing or corrupt.": "UniGetUI ಅಥವಾ ಅದರ ಕೆಲವು components ಕಾಣೆಯಾಗಿವೆ ಅಥವಾ ಹಾಳಾಗಿವೆ.", + "It is strongly recommended to reinstall UniGetUI to adress the situation.": "ಈ ಪರಿಸ್ಥಿತಿಯನ್ನು ಸರಿಪಡಿಸಲು UniGetUI ಅನ್ನು ಮರುಸ್ಥಾಪಿಸುವುದು ತೀವ್ರವಾಗಿ ಶಿಫಾರಸು ಮಾಡಲಾಗಿದೆ.", + "Refer to the UniGetUI Logs to get more details regarding the affected file(s)": "ಪ್ರಭಾವಿತ file(s) ಬಗ್ಗೆ ಹೆಚ್ಚಿನ ವಿವರಗಳಿಗಾಗಿ UniGetUI Logs ಅನ್ನು ನೋಡಿ", + "Integrity checks can be disabled from the Experimental Settings": "Integrity checks ಅನ್ನು Experimental Settings ನಿಂದ ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಬಹುದು", + "Repair UniGetUI": "UniGetUI ಅನ್ನು ಸರಿಪಡಿಸಿ", + "Live output": "ನೇರ output", + "This package bundle had some settings that are potentially dangerous, and may be ignored by default.": "ಈ package bundle ನಲ್ಲಿ ಕೆಲವು settings ಅಪಾಯಕಾರಿ ಆಗಿರಬಹುದು, ಮತ್ತು ಅವುಗಳನ್ನು default ಆಗಿ ನಿರ್ಲಕ್ಷಿಸಬಹುದು.", + "Entries that show in YELLOW will be IGNORED.": "YELLOW ಬಣ್ಣದಲ್ಲಿ ತೋರಿಸಲಾದ entries IGNORE ಆಗುತ್ತವೆ.", + "Entries that show in RED will be IMPORTED.": "RED ಬಣ್ಣದಲ್ಲಿ ತೋರಿಸಲಾದ entries IMPORT ಆಗುತ್ತವೆ.", + "You can change this behavior on UniGetUI security settings.": "ಈ ವರ್ತನೆಯನ್ನು UniGetUI security settings ನಲ್ಲಿ ಬದಲಾಯಿಸಬಹುದು.", + "Open UniGetUI security settings": "UniGetUI security settings ತೆರೆಯಿರಿ", + "Should you modify the security settings, you will need to open the bundle again for the changes to take effect.": "ನೀವು security settings ಬದಲಿಸಿದರೆ, ಬದಲಾವಣೆಗಳು ಪರಿಣಾಮ ಬೀರುವಂತೆ bundle ಅನ್ನು ಮತ್ತೆ ತೆರೆಯಬೇಕಾಗುತ್ತದೆ.", + "Details of the report:": "ವರದಿಯ ವಿವರಗಳು:", + "Are you sure you want to create a new package bundle? ": "ಹೊಸ ಪ್ಯಾಕೇಜ್ ಬಂಡಲ್ ರಚಿಸಲು ನೀವು ಖಚಿತವಾಗಿದ್ದೀರಾ? ", + "Any unsaved changes will be lost": "ಉಳಿಸದ ಯಾವುದೇ ಬದಲಾವಣೆಗಳು ಕಳೆದುಹೋಗುತ್ತವೆ", + "Warning!": "ಎಚ್ಚರಿಕೆ!", + "For security reasons, custom command-line arguments are disabled by default. Go to UniGetUI security settings to change this. ": "ಭದ್ರತಾ ಕಾರಣಗಳಿಂದ custom command-line arguments default ಆಗಿ ನಿಷ್ಕ್ರಿಯವಾಗಿವೆ. ಇದನ್ನು ಬದಲಾಯಿಸಲು UniGetUI security settings ಗೆ ಹೋಗಿ. ", + "Change default options": "ಡೀಫಾಲ್ಟ್ ಆಯ್ಕೆಗಳನ್ನು ಬದಲಿಸಿ", + "Ignore future updates for this package": "ಈ ಪ್ಯಾಕೇಜ್‌ಗೆ ಬರುವ ಭವಿಷ್ಯದ ನವೀಕರಣಗಳನ್ನು ನಿರ್ಲಕ್ಷಿಸಿ", + "For security reasons, pre-operation and post-operation scripts are disabled by default. Go to UniGetUI security settings to change this. ": "ಭದ್ರತಾ ಕಾರಣಗಳಿಂದ pre-operation ಮತ್ತು post-operation scripts default ಆಗಿ ನಿಷ್ಕ್ರಿಯವಾಗಿವೆ. ಇದನ್ನು ಬದಲಾಯಿಸಲು UniGetUI security settings ಗೆ ಹೋಗಿ. ", + "You can define the commands that will be run before or after this package is installed, updated or uninstalled. They will be run on a command prompt, so CMD scripts will work here.": "ಈ package install, update ಅಥವಾ uninstall ಆಗುವ ಮೊದಲು ಅಥವಾ ನಂತರ ನಡೆಸಲಾಗುವ commands ಗಳನ್ನು ನೀವು ನಿರ್ಧರಿಸಬಹುದು. ಅವು command prompt ನಲ್ಲಿ ನಡೆಯುತ್ತವೆ, ಆದ್ದರಿಂದ CMD scripts ಇಲ್ಲಿ ಕೆಲಸ ಮಾಡುತ್ತವೆ.", + "Change this and unlock": "ಇದನ್ನು ಬದಲಿಸಿ ಮತ್ತು ಅನ್ಲಾಕ್ ಮಾಡಿ", + "{0} Install options are currently locked because {0} follows the default install options.": "{0} default install options ಅನುಸರಿಸುವುದರಿಂದ {0} install options ಪ್ರಸ್ತುತ lock ಆಗಿವೆ.", + "Unset or unknown": "unset ಅಥವಾ ಅಪರಿಚಿತ", + "This package has no screenshots or is missing the icon? Contrbute to UniGetUI by adding the missing icons and screenshots to our open, public database.": "ಈ package ನಲ್ಲಿ screenshots ಇಲ್ಲವೇ ಅಥವಾ icon ಕಾಣೆಯೇ? ನಮ್ಮ open, public database ಗೆ ಕಾಣೆಯಾದ icons ಮತ್ತು screenshots ಸೇರಿಸಿ UniGetUI ಗೆ ಕೊಡುಗೆ ನೀಡಿ.", + "Become a contributor": "ಒಂದು ಸಹಾಯಕನಾಗಿ", + "Update to {0} available": "{0} ಗೆ update ಲಭ್ಯವಿದೆ", + "Reinstall": "ಮರುಸ್ಥಾಪಿಸಿ", + "Installer not available": "Installer ಲಭ್ಯವಿಲ್ಲ", + "Version:": "ಆವೃತ್ತಿ:", + "UniGetUI Version {0}": "UniGetUI ಆವೃತ್ತಿ {0}", + "Performing backup, please wait...": "backup ನಡೆಸಲಾಗುತ್ತಿದೆ, ದಯವಿಟ್ಟು ನಿರೀಕ್ಷಿಸಿ...", + "An error occurred while logging in: ": "ಲಾಗಿನ್ ಮಾಡುವಾಗ ದೋಷ ಸಂಭವಿಸಿದೆ: ", + "Fetching available backups...": "ಲಭ್ಯವಿರುವ backups ಅನ್ನು ಪಡೆದುಕೊಳ್ಳುತ್ತಿದೆ...", + "Done!": "ಮುಗಿದಿದೆ!", + "The cloud backup has been loaded successfully.": "cloud backup ಯಶಸ್ವಿಯಾಗಿ load ಆಗಿದೆ.", + "An error occurred while loading a backup: ": "ಬ್ಯಾಕಪ್ ಅನ್ನು ಲೋಡ್ ಮಾಡುವಾಗ ದೋಷ ಸಂಭವಿಸಿದೆ: ", + "Backing up packages to GitHub Gist...": "ಪ್ಯಾಕೇಜ್‌ಗಳನ್ನು GitHub Gist ಗೆ ಬ್ಯಾಕಪ್ ಮಾಡಲಾಗುತ್ತಿದೆ...", + "Backup Successful": "ಬ್ಯಾಕಪ್ ಯಶಸ್ವಿಯಾಗಿದೆ", + "The cloud backup completed successfully.": "cloud backup ಯಶಸ್ವಿಯಾಗಿ ಪೂರ್ಣಗೊಂಡಿತು.", + "Could not back up packages to GitHub Gist: ": "ಪ್ಯಾಕೇಜ್‌ಗಳನ್ನು GitHub Gist ಗೆ ಬ್ಯಾಕಪ್ ಮಾಡಲು ಸಾಧ್ಯವಾಗಲಿಲ್ಲ: ", + "It is not guaranteed that the provided credentials will be stored safely, so you may as well not use the credentials of your bank account": "ನೀಡಲಾದ credentials ಸುರಕ್ಷಿತವಾಗಿ ಸಂಗ್ರಹಿಸಲಾಗುತ್ತದೆ ಎಂಬ ಭರವಸೆ ಇಲ್ಲ, ಆದ್ದರಿಂದ ನಿಮ್ಮ ಬ್ಯಾಂಕ್ ಖಾತೆಯ credentials ಅನ್ನು ಬಳಸದಿರುವುದೇ ಉತ್ತಮ.", + "Enable the automatic WinGet troubleshooter": "ಸ್ವಯಂಚಾಲಿತ WinGet troubleshooter ಅನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಿ", + "Add updates that fail with a 'no applicable update found' to the ignored updates list": "'no applicable update found' ಎಂದು ವಿಫಲವಾಗುವ ನವೀಕರಣಗಳನ್ನು ನಿರ್ಲಕ್ಷಿತ ನವೀಕರಣಗಳ ಪಟ್ಟಿಗೆ ಸೇರಿಸಿ", + "Invalid selection": "ಅಮಾನ್ಯ ಆಯ್ಕೆ", + "No package was selected": "ಯಾವುದೇ ಪ್ಯಾಕೇಜ್ ಆಯ್ಕೆ ಮಾಡಲಾಗಿಲ್ಲ", + "More than 1 package was selected": "1 ಕ್ಕಿಂತ ಹೆಚ್ಚು ಪ್ಯಾಕೇಜ್ ಆಯ್ಕೆ ಮಾಡಲಾಗಿದೆ", + "List": "ಪಟ್ಟಿ", + "Grid": "ಜಾಲಕ", + "Icons": "ಚಿಹ್ನೆಗಳು", + "\"{0}\" is a local package and does not have available details": "\"{0}\" ಒಂದು ಸ್ಥಳೀಯ ಪ್ಯಾಕೇಜ್ ಆಗಿದ್ದು ಲಭ್ಯವಿರುವ ವಿವರಗಳಿಲ್ಲ", + "\"{0}\" is a local package and is not compatible with this feature": "\"{0}\" ಒಂದು ಸ್ಥಳೀಯ ಪ್ಯಾಕೇಜ್ ಆಗಿದ್ದು ಈ ವೈಶಿಷ್ಟ್ಯಕ್ಕೆ ಹೊಂದಿಕೆಯಾಗುವುದಿಲ್ಲ", + "Add packages to bundle": "ಬಂಡಲ್‌ಗೆ ಪ್ಯಾಕೇಜ್‌ಗಳನ್ನು ಸೇರಿಸಿ", + "Preparing packages, please wait...": "ಪ್ಯಾಕೇಜ್‌ಗಳನ್ನು ಸಿದ್ಧಪಡಿಸಲಾಗುತ್ತಿದೆ, ದಯವಿಟ್ಟು ನಿರೀಕ್ಷಿಸಿ...", + "Loading packages, please wait...": "ಪ್ಯಾಕೇಜ್‌ಗಳು load ಆಗುತ್ತಿವೆ, ದಯವಿಟ್ಟು ನಿರೀಕ್ಷಿಸಿ...", + "Saving packages, please wait...": "ಪ್ಯಾಕೇಜ್‌ಗಳನ್ನು ಉಳಿಸಲಾಗುತ್ತಿದೆ, ದಯವಿಟ್ಟು ನಿರೀಕ್ಷಿಸಿ...", + "The bundle was created successfully on {0}": "{0} ನಲ್ಲಿ bundle ಯಶಸ್ವಿಯಾಗಿ ರಚಿಸಲಾಗಿದೆ", + "User profile": "ಬಳಕೆದಾರ ಪ್ರೊಫೈಲ್", + "Error": "ದೋಷ", + "Log in failed: ": "ಲಾಗಿನ್ ವಿಫಲವಾಗಿದೆ: ", + "Log out failed: ": "ಲಾಗ್ ಔಟ್ ವಿಫಲವಾಗಿದೆ: ", + "Package backup settings": "ಪ್ಯಾಕೇಜ್ backup settings", + "Manage UniGetUI autostart behaviour from the Settings app": "UniGetUI ಸ್ವಯಂಪ್ರಾರಂಭ ವರ್ತನೆಯನ್ನು ನಿರ್ವಹಿಸಿ", + "Choose how many operations shoulds be performed in parallel": "ಎಷ್ಟು ಕಾರ್ಯಾಚರಣೆಗಳನ್ನು ಸಮಾಂತರವಾಗಿ ನಡೆಸಬೇಕು ಎಂದು ಆಯ್ಕೆಮಾಡಿ", + "Something went wrong while launching the updater.": "updater ಆರಂಭಿಸುವಾಗ ಏನೋ ತಪ್ಪಾಗಿದೆ.", + "Please try again later": "ದಯವಿಟ್ಟು ನಂತರ ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ", + "Show the release notes after UniGetUI is updated": "UniGetUI ಅಪ್‌ಡೇಟ್ ಆದ ನಂತರ ಬಿಡುಗಡೆ ಟಿಪ್ಪಣಿಗಳನ್ನು ತೋರಿಸಿ" +} diff --git a/src/Languages/lang_ko.json b/src/Languages/lang_ko.json new file mode 100644 index 0000000..a50215b --- /dev/null +++ b/src/Languages/lang_ko.json @@ -0,0 +1,846 @@ +{ + "{0} of {1} operations completed": "{1}개 작업 중 {0}개 완료됨", + "{0} is now {1}": "{0}이(가) 이제 {1}입니다", + "Enabled": "사용", + "Disabled": "사용 안 함", + "Privacy": "개인정보 보호", + "Hide my username from the logs": "로그에서 내 사용자 이름 숨기기", + "Replaces your username with **** in the logs. Restart UniGetUI to also hide it from already-recorded entries.": "로그에서 사용자 이름을 ****로 대체합니다. 이미 기록된 항목에서도 숨기려면 UniGetUI를 다시 시작하세요.", + "Your last update attempt did not complete.": "마지막 업데이트 시도가 완료되지 않았습니다.", + "UniGetUI could not confirm whether the update succeeded. Open the log to see what happened.": "UniGetUI는 업데이트가 성공했는지 확인할 수 없습니다. 로그를 열어 무슨 일이 일어났는지 확인하세요.", + "View log": "로그 보기", + "The installer reported success but did not restart UniGetUI.": "설치 프로그램이 성공을 보고했지만 UniGetUI를 재시작하지 않았습니다.", + "The installer failed to initialize.": "설치 프로그램을 초기화하지 못했습니다.", + "Setup was canceled before installation began.": "설치가 시작되기 전에 설치가 취소되었습니다.", + "A fatal error occurred during the preparation phase.": "준비 단계에서 치명적인 오류가 발생했습니다.", + "A fatal error occurred during installation.": "설치 중 치명적인 오류가 발생했습니다.", + "Installation was canceled while in progress.": "진행 중에 설치가 취소되었습니다.", + "The installer was terminated by another process.": "설치 프로그램이 다른 프로세스에 의해 종료되었습니다.", + "The preparation phase determined the installation cannot proceed.": "준비 단계에서 설치를 진행할 수 없다고 판단했습니다.", + "The installer could not start. UniGetUI may already be running, or you do not have permission to install.": "설치 프로그램을 시작할 수 없습니다. UniGetUI가 이미 실행 중이거나 설치 권한이 없을 수 있습니다.", + "Unexpected installer error.": "예기치 않은 설치 프로그램 오류입니다.", + "We are checking for updates.": "업데이트를 확인하고 있습니다.", + "Please wait": "잠시만 기다려주세요", + "Great! You are on the latest version.": "좋아요! 최신 버전입니다.", + "There are no new UniGetUI versions to be installed": "설치할 새로운 UniGetUI 버전이 없습니다", + "UniGetUI version {0} is being downloaded.": "UniGetUI 버전 {0}이(가) 다운로드되고 있습니다.", + "This may take a minute or two": "이것은 1~2분 정도 걸릴 수 있습니다", + "The installer authenticity could not be verified.": "설치 프로그램의 진위 여부를 확인할 수 없습니다.", + "The update process has been aborted.": "업데이트 프로세스가 중단되었습니다.", + "Auto-update is not yet available on this platform.": "이 플랫폼에서는 아직 자동 업데이트를 사용할 수 없습니다.", + "Please update UniGetUI manually.": "UniGetUI를 수동으로 업데이트해 주세요.", + "An error occurred when checking for updates: ": "업데이트를 확인하는 동안 오류가 발생했습니다: ", + "The updater could not be launched.": "업데이트 프로그램을 실행할 수 없습니다.", + "The operating system did not start the installer process.": "운영 체제가 설치 프로그램 프로세스를 시작하지 않았습니다.", + "UniGetUI is being updated...": "UniGetUI가 업데이트되고 있습니다...", + "Update installed.": "업데이트가 설치되었습니다.", + "UniGetUI was updated successfully, but this running copy was not replaced. This usually means you are running a development build. Close this copy and start the newly-installed version to finish.": "UniGetUI가 성공적으로 업데이트되었지만 이 실행 중인 복사본은 교체되지 않았습니다. 이는 일반적으로 개발 빌드를 실행 중임을 의미합니다. 이 복사본을 닫고 새로 설치된 버전을 시작하여 완료하세요.", + "The update could not be applied.": "업데이트를 적용할 수 없습니다.", + "Installer exit code {0}: {1}": "설치 프로그램 종료 코드 {0}: {1}", + "Update cancelled.": "업데이트가 취소되었습니다.", + "Authentication was cancelled.": "인증이 취소되었습니다.", + "Installer exit code {0}": "설치 프로그램 종료 코드 {0}", + "Operation in progress": "작업 진행 중", + "Please wait...": "잠시만 기다려주세요...", + "Success!": "성공!", + "Failed": "실패", + "An error occurred while processing this package": "이 패키지를 처리하는 동안 오류가 발생했습니다", + "Installer": "설치 프로그램", + "Executable": "실행 파일", + "MSI": "MSI", + "Compressed file": "압축 파일", + "MSIX": "MSIX", + "WinGet was repaired successfully": "WinGet을 성공적으로 복구했습니다", + "It is recommended to restart UniGetUI after WinGet has been repaired": "WinGet 복구 후에는 UniGetUI를 다시 시작할 것을 권장합니다", + "WinGet could not be repaired": "WinGet을 복구할 수 없습니다", + "An unexpected issue occurred while attempting to repair WinGet. Please try again later": "WinGet을 복구하는 동안 예기치 않은 문제가 발생했습니다. 나중에 다시 시도해 주세요", + "Log in to enable cloud backup": "클라우드 백업을 활성화하려면 로그인하세요", + "Backup Failed": "백업 실패", + "Downloading backup...": "백업을 다운로드하는 중...", + "An update was found!": "업데이트를 찾았습니다!", + "{0} can be updated to version {1}": "{0}을(를) {1} 버전으로 업데이트할 수 있습니다.", + "Updates found!": "업데이트를 찾았습니다!", + "{0} packages can be updated": "패키지 {0}개 업데이트 가능", + "{0} is being updated to version {1}": "{0}을(를) 버전 {1} (으)로 업데이트하는 중입니다", + "{0} packages are being updated": "패키지 {0}개 업데이트 중", + "You have currently version {0} installed": "현재 {0} 버전이 설치되어 있습니다", + "Desktop shortcut created": "바탕 화면 바로 가기 만듦", + "UniGetUI has detected a new desktop shortcut that can be deleted automatically.": "UniGetUI가 자동으로 삭제할 수 있는 새 바탕 화면 바로 가기를 감지했습니다.", + "{0} desktop shortcuts created": "{0} 바탕 화면 바로가기 생성됨", + "UniGetUI has detected {0} new desktop shortcuts that can be deleted automatically.": "UniGetUI가 자동으로 삭제할 수 있는 {0}개의 새 바탕 화면 바로 가기를 감지했습니다.", + "Attention required": "주의 필요", + "Restart required": "다시 시작 필요", + "1 update is available": "1개의 업데이트 사용 가능", + "{0} updates are available": "{0} 업데이트 사용 가능", + "Everything is up to date": "모두 최신 상태입니다", + "Discover Packages": "패키지 찾아보기", + "Available Updates": "사용 가능한 업데이트", + "Installed Packages": "설치된 패키지", + "UniGetUI Version {0} by Devolutions": "Devolutions 제공 UniGetUI 버전 {0}", + "Show UniGetUI": "UniGetUI 창 표시", + "Quit": "종료", + "Are you sure?": "확실합니까?", + "Do you really want to uninstall {0}?": "{0}을(를) 제거하시겠습니까?", + "Do you really want to uninstall the following {0} packages?": "다음 {0} 패키지를 정말로 제거하시겠습니까?", + "No": "아니요", + "Yes": "예", + "Partial": "부분적", + "View on UniGetUI": "UniGetUI에서 보기", + "Update": "업데이트", + "Open UniGetUI": "UniGetUI 열기", + "Update all": "모두 업데이트", + "Update now": "지금 업데이트", + "Installer host changed since the installed version.\n": "설치된 버전 이후로 설치 호스트가 변경되었습니다.\n", + "This package is on the queue": "이 패키지는 대기열에 있습니다", + "installing": "설치 중", + "updating": "업데이트 중", + "uninstalling": "제거 중", + "installed": "설치됨", + "Retry": "다시 시도", + "Install": "설치", + "Uninstall": "제거", + "Open": "열기", + "Operation profile:": "운영 프로필:", + "Follow the default options when installing, upgrading or uninstalling this package": "이 패키지를 설치, 업그레이드 또는 제거할 때 기본 옵션을 따릅니다", + "The following settings will be applied each time this package is installed, updated or removed.": "이 패키지를 설치, 업데이트 또는 제거할 때마다 다음 설정이 적용됩니다.", + "Version to install:": "설치할 버전:", + "Architecture to install:": "설치할 아키텍처:", + "Installation scope:": "설치 범위:", + "Install location:": "설치 위치:", + "Select": "선택", + "Reset": "초기화", + "Custom install arguments:": "사용자 지정 설치 인수:", + "Custom update arguments:": "사용자 지정 업데이트 인수:", + "Custom uninstall arguments:": "사용자 지정 제거 인수:", + "Pre-install command:": "설치 전 명령:", + "Post-install command:": "설치 후 명령:", + "Abort install if pre-install command fails": "설치 전 명령이 실패하면 설치 중단", + "Pre-update command:": "업데이트 전 명령:", + "Post-update command:": "업데이트 후 명령:", + "Abort update if pre-update command fails": "업데이트 전 명령이 실패하면 업데이트 중단", + "Pre-uninstall command:": "제거 전 명령:", + "Post-uninstall command:": "제거 후 명령:", + "Abort uninstall if pre-uninstall command fails": "제거 전 명령이 실패하면 제거 중지", + "Command-line to run:": "실행할 명령줄:", + "Save and close": "저장하고 닫기", + "General": "일반", + "Architecture & Location": "아키텍처 및 위치", + "Command-line": "명령줄", + "Close apps": "앱 닫기", + "Pre/Post install": "설치 전/후", + "Select the processes that should be closed before this package is installed, updated or uninstalled.": "이 패키지를 설치, 업데이트 또는 제거하기 전에 닫아야 할 프로세스를 선택합니다.", + "Write here the process names here, separated by commas (,)": "여기에 프로세스 이름을 쉼표로 구분하여 작성하세요 (, )", + "Try to kill the processes that refuse to close when requested to": "요청 시 종료를 거부하는 프로세스를 제거해 보세요", + "Run as admin": "관리자 권한으로 실행", + "Interactive installation": "대화형 설치", + "Skip hash check": "해시 검사 건너뛰기", + "Uninstall previous versions when updated": "업데이트 시 이전 버전 제거", + "Skip minor updates for this package": "이 패키지의 마이너 업데이트 건너뛰기", + "Automatically update this package": "이 패키지를 자동으로 업데이트", + "{0} installation options": "{0} 설치 옵션", + "Latest": "최신", + "PreRelease": "사전 릴리스", + "Default": "기본값", + "Manage ignored updates": "무시된 업데이트 관리", + "The packages listed here won't be taken in account when checking for updates. Double-click them or click the button on their right to stop ignoring their updates.": "여기에 나열된 패키지는 업데이트를 확인할 때 고려되지 않습니다. 업데이트 무시를 중지하려면 해당 항목을 두 번 클릭하거나 오른쪽에 있는 버튼을 클릭하세요.", + "Reset list": "목록 초기화", + "Do you really want to reset the ignored updates list? This action cannot be reverted": "무시된 업데이트 목록을 정말로 초기화하시겠습니까? 이 작업은 되돌릴 수 없습니다.", + "No ignored updates": "무시된 업데이트 없음", + "Package Name": "패키지 이름", + "Package ID": "패키지 ID", + "Ignored version": "무시된 버전", + "New version": "새 버전", + "Source": "공급자", + "All versions": "모든 버전", + "Unknown": "알 수 없음", + "Up to date": "최신 상태", + "Package {name} from {manager}": "{manager}의 패키지 {name}", + "Remove {0} from ignored updates": "무시된 업데이트에서 {0} 제거", + "Cancel": "취소", + "Administrator privileges": "관리자 권한", + "This operation is running with administrator privileges.": "이 작업은 관리자 권한으로 실행 중입니다.", + "Interactive operation": "대화형 작업", + "This operation is running interactively.": "이 작업은 대화형으로 실행 중입니다.", + "You will likely need to interact with the installer.": "설치 프로그램과 상호 작용이 필요할 수 있습니다.", + "Integrity checks skipped": "무결성 검사 건너뜀", + "Integrity checks will not be performed during this operation.": "이 작업 중에는 무결성 검사가 수행되지 않습니다.", + "Proceed at your own risk.": "모든 책임은 사용자에게 있습니다.", + "Close": "닫기", + "Loading...": "불러오는 중...", + "Installer SHA256": "설치 프로그램의 SHA256", + "Homepage": "홈페이지", + "Author": "작성자", + "Publisher": "게시자", + "License": "라이선스", + "Manifest": "매니페스트", + "Installer Type": "설치 프로그램 유형", + "Size": "크기", + "Installer URL": "설치 프로그램 URL", + "Last updated:": "마지막 업데이트:", + "Release notes URL": "릴리스 노트 URL", + "Package details": "패키지 세부 정보", + "Dependencies:": "종속성:", + "Release notes": "릴리스 노트", + "Screenshots": "스크린샷", + "This package has no screenshots or is missing the icon? Contribute to UniGetUI by adding the missing icons and screenshots to our open, public database.": "이 패키지에 스크린샷이 없거나 아이콘이 누락되었나요? 누락된 아이콘과 스크린샷을 공개 데이터베이스에 추가하여 UniGetUI에 기여해 주세요.", + "Version": "버전", + "Install as administrator": "관리자 권한으로 설치", + "Update to version {0}": "{0} 버전으로 업데이트", + "Installed Version": "설치된 버전", + "Update as administrator": "관리자 권한으로 업데이트", + "Interactive update": "대화형 업데이트", + "Uninstall as administrator": "관리자 권한으로 제거", + "Interactive uninstall": "대화형 제거", + "Uninstall and remove data": "제거 및 데이터 삭제", + "Not available": "사용할 수 없음", + "Installer SHA512": "설치 프로그램의 SHA512", + "Unknown size": "알 수 없는 크기", + "No dependencies specified": "종속성이 지정되지 않았습니다", + "mandatory": "의무적", + "optional": "선택적", + "UniGetUI {0} is ready to be installed.": "UniGetUI {0} 설치가 준비되었습니다.", + "The update process will start after closing UniGetUI": "UniGetUI가 닫힌 후에 업데이트 프로세스가 시작됩니다", + "UniGetUI has been ran as administrator, which is not recommended. When running UniGetUI as administrator, EVERY operation launched from UniGetUI will have administrator privileges. You can still use the program, but we highly recommend not running UniGetUI with administrator privileges.": "UniGetUI가 관리자 권한으로 실행되었으며, 이는 권장되지 않습니다. UniGetUI를 관리자 권한으로 실행하면 UniGetUI에서 시작한 모든 작업이 관리자 권한으로 실행됩니다. 프로그램은 계속 사용할 수 있지만, UniGetUI를 관리자 권한으로 실행하지 않는 것을 강력히 권장합니다.", + "Share anonymous usage data": "익명 사용 데이터 공유", + "UniGetUI collects anonymous usage data in order to improve the user experience.": "UniGetUI는 사용자 경험을 개선하기 위해 익명 사용 데이터를 수집합니다.", + "Accept": "수락", + "Software Updates": "소프트웨어 업데이트", + "Package Bundles": "패키지 번들", + "Settings": "설정", + "Package Managers": "패키지 관리자", + "UniGetUI Log": "UniGetUI 로그", + "Package Manager logs": "패키지 관리자 로그", + "Operation history": "작업 기록", + "Help": "도움말", + "UniGetUI": "UniGetUI", + "You have installed UniGetUI Version {0}": "UniGetUI {0} 버전을 설치했습니다.", + "Disclaimer": "면책 조항", + "UniGetUI is developed by Devolutions and is not affiliated with any of the compatible package managers.": "UniGetUI는 Devolutions에서 개발하며, 호환되는 어떤 패키지 관리자와도 제휴 관계가 없습니다.", + "UniGetUI wouldn't have been possible without the help of the contributors. Thank you all 🥳": "UniGetUI는 기여자들의 도움 없이는 불가능했을 것입니다. 모두들 감사합니다🥳", + "UniGetUI uses the following libraries. Without them, UniGetUI wouldn't have been possible.": "UniGetUI는 다음 라이브러리를 사용합니다. 그것들 없이는 UniGetUI가 존재할 수 없습니다.", + "{0} homepage": "{0} 홈페이지", + "UniGetUI has been translated to more than 40 languages thanks to the volunteer translators. Thank you 🤝": "UniGetUI는 자원봉사 번역가들 덕분에 40개 이상의 언어로 번역되었습니다. 감사합니다 🤝", + "Verbose": "세부 정보", + "1 - Errors": "1 - 오류", + "2 - Warnings": "2 - 경고", + "3 - Information (less)": "3 - 정보 (더 적게)", + "4 - Information (more)": "4 - 정보 (더 많이)", + "5 - information (debug)": "5 - 정보 (디버그)", + "Warning": "경고", + "The following settings may pose a security risk, hence they are disabled by default.": "다음 설정은 보안 위험을 초래할 수 있으므로 기본적으로 비활성화됩니다.", + "Enable the settings below if and only if you fully understand what they do, and the implications they may have.": "아래 설정을 활성화하려면 해당 설정이 무엇을 하는지, 그리고 그로 인해 발생할 수 있는 영향과 위험을 완전히 이해해야만 합니다.", + "The settings will list, in their descriptions, the potential security issues they may have.": "설정은 설명에 잠재적인 보안 문제를 나열할 것입니다.", + "The backup will include the complete list of the installed packages and their installation options. Ignored updates and skipped versions will also be saved.": "백업에는 설치된 패키지의 전체 목록과 해당 설치 옵션이 포함됩니다. 무시된 업데이트와 건너뛴 버전도 저장됩니다.", + "The backup will NOT include any binary file nor any program's saved data.": "백업에는 바이너리 파일이나 프로그램의 저장 데이터가 포함되지 않습니다.", + "The size of the backup is estimated to be less than 1MB.": "백업 크기는 1MB 미만으로 예상됩니다.", + "The backup will be performed after login.": "로그인 후 백업이 수행됩니다.", + "{pcName} installed packages": "{pcName} 설치된 패키지", + "Current status: Not logged in": "현재 상태: 로그인되지 않음", + "You are logged in as {0} (@{1})": "{0} (@{1})으로 로그인했습니다", + "Nice! Backups will be uploaded to a private gist on your account": "좋습니다! 백업은 귀하의 계정의 비공개 gist에 업로드됩니다", + "Select backup": "백업 선택", + "Settings imported from {0}": "{0}에서 설정을 가져왔습니다", + "UniGetUI Settings": "UniGetUI 설정", + "Settings exported to {0}": "{0}(으)로 설정을 내보냈습니다", + "UniGetUI settings were reset": "UniGetUI 설정이 초기화되었습니다", + "Allow pre-release versions": "사전 릴리스 버전 허용", + "Apply": "적용", + "For security reasons, custom command-line arguments are disabled by default. Go to UniGetUI security settings to change this.": "보안상의 이유로 사용자 지정 명령줄 인수는 기본적으로 비활성화되어 있습니다. 이를 변경하려면 UniGetUI 보안 설정으로 이동하세요.", + "Go to UniGetUI security settings": "UniGetUI 보안 설정으로 이동", + "The following options will be applied by default each time a {0} package is installed, upgraded or uninstalled.": "다음 옵션은 {0} 패키지가 설치, 업그레이드 또는 제거될 때마다 기본적으로 적용됩니다.", + "Package's default": "패키지의 기본값", + "Install location can't be changed for {0} packages": "{0} 패키지에 대해 설치 위치를 변경할 수 없습니다", + "The local icon cache currently takes {0} MB": "로컬 아이콘 캐시가 {0} MB를 차지하고 있습니다", + "Username": "사용자 이름", + "Password": "암호", + "Credentials": "자격 증명", + "It is not guaranteed that the provided credentials will be stored safely": "제공된 자격 증명이 안전하게 저장된다고 보장할 수 없습니다", + "Partially": "부분적", + "Package manager": "패키지 관리자", + "Compatible with proxy": "프록시 호환 여부", + "Compatible with authentication": "인증 호환 여부", + "Proxy compatibility table": "프록시 호환성 표", + "{0} settings": "{0} 설정", + "{0} status": "{0} 상태", + "Default installation options for {0} packages": "{0} 패키지의 기본 설치 옵션", + "Expand version": "버전 확장", + "The executable file for {0} was not found": "{0}에 대한 실행 파일을 찾을 수 없습니다.", + "{pm} is disabled": "{pm}이(가) 꺼져있습니다", + "Enable it to install packages from {pm}.": "{pm}에서 패키지를 설치하도록 활성화합니다.", + "{pm} is enabled and ready to go": "{pm}이(가) 켜져있어 사용할 준비가 되었습니다", + "{pm} version:": "{pm} 버전:", + "{pm} was not found!": "{pm}을(를) 찾을 수 없습니다!", + "You may need to install {pm} in order to use it with UniGetUI.": "UniGetUI로 사용하려면 {pm}을(를) 설치해야 할 수 있습니다.", + "Scoop Installer - UniGetUI": "Scoop 설치 프로그램 - UniGetUI", + "Scoop Uninstaller - UniGetUI": "Scoop 제거 프로그램 - UniGetUI", + "Clearing Scoop cache - UniGetUI": "Scoop 캐시 지우기 - UniGetUI", + "Restart UniGetUI to fully apply changes": "변경 사항을 완전히 적용하려면 UniGetUI를 다시 시작하세요", + "Restart UniGetUI": "UniGet 다시 시작", + "Manage {0} sources": "{0} 소스 관리", + "Add source": "소스 추가", + "Add": "추가", + "Source name": "소스 이름", + "Source URL": "소스 URL", + "Other": "기타", + "No minimum age": "최소 기간 없음", + "1 day": "1일", + "{0} days": "{0} 일", + "Custom...": "사용자 지정...", + "{0} minutes": "{0} 분", + "1 hour": "1시간", + "{0} hours": "{0} 시간", + "1 week": "1주", + "Supports release dates": "릴리스 날짜 지원", + "Release date support per package manager": "패키지 관리자별 릴리스 날짜 지원", + "Search for packages": "패키지 검색", + "Local": "로컬", + "OK": "확인", + "Last checked: {0}": "마지막 확인: {0}", + "{0} packages were found, {1} of which match the specified filters.": "{0}개의 패키지가 발견되었으며, 그 중 {1}개는 지정된 필터와 일치합니다.", + "{0} selected": "{0}개 ​선택됨", + "(Last checked: {0})": "(마지막 확인 날짜: {0})", + "All packages selected": "모든 패키지가 선택됨", + "Package selection cleared": "패키지 선택이 해제됨", + "{0}: {1}": "{0}: {1}", + "More info": "자세한 정보", + "GitHub account": "GitHub 계정", + "Log in with GitHub to enable cloud package backup.": "클라우드 패키지 백업을 활성화하려면 GitHub에 로그인하세요.", + "More details": "자세한 정보", + "Log in": "로그인", + "If you have cloud backup enabled, it will be saved as a GitHub Gist on this account": "클라우드 백업을 활성화하면 이 계정에 GitHub Gist로 저장됩니다", + "Log out": "로그 아웃", + "About UniGetUI": "UniGetUI 정보", + "About": "정보", + "Third-party licenses": "타사 라이선스", + "Contributors": "기여자", + "Translators": "번역가", + "Bundle security report": "번들 보안 보고서", + "The bundle contained restricted content": "이 번들에는 제한된 콘텐츠가 포함되어 있습니다", + "UniGetUI – Crash Report": "UniGetUI – 충돌 보고서", + "UniGetUI has crashed": "UniGetUI에 오류가 발생했습니다", + "Help us fix this by sending a crash report to Devolutions. All fields below are optional.": "Devolutions에 충돌 보고서를 보내 이 문제를 해결할 수 있도록 도와주세요. 아래의 모든 필드는 선택 사항입니다.", + "Email (optional)": "이메일 (선택 사항)", + "your@email.com": "your@email.com", + "Additional details (optional)": "추가 세부 정보 (선택 사항)", + "Describe what you were doing when the crash occurred…": "충돌이 발생했을 때 무엇을 하고 있었는지 설명해 주세요…", + "Crash report": "충돌 보고서", + "Don't Send": "보내지 않기", + "Send Report": "보고서 보내기", + "Sending…": "보내는 중…", + "Unsaved changes": "저장되지 않은 변경 사항", + "You have unsaved changes in the current bundle. Do you want to discard them?": "현재 번들에 저장되지 않은 변경 사항이 있습니다. 버리시겠습니까?", + "Discard changes": "변경 사항 버리기", + "Integrity violation": "무결성 위반", + "UniGetUI or some of its components are missing or corrupt. It is strongly recommended to reinstall UniGetUI to adress the situation.": "UniGetUI 또는 일부 구성 요소가 없거나 손상되었습니다. 이 문제를 해결하려면 UniGetUI를 다시 설치하는 것이 강력히 권장됩니다.", + "• Refer to the UniGetUI Logs to get more details regarding the affected file(s)": "• 영향을 받은 파일에 대한 자세한 내용은 UniGetUI 로그를 참조하세요", + "• Integrity checks can be disabled from the Experimental Settings": "• 무결성 검사는 실험 설정에서 비활성화할 수 있습니다", + "Manage shortcuts": "바로 가기 관리", + "UniGetUI has detected the following desktop shortcuts which can be removed automatically on future upgrades": "UniGetUI가 향후 업그레이드 시 자동으로 제거할 수 있는 바탕 화면 바로 가기를 다음과 같이 감지했습니다", + "Do you really want to reset this list? This action cannot be reverted.": "정말로 이 목록을 초기화하시겠습니까? 이 동작은 되돌릴 수 없습니다.", + "Desktop shortcuts list": "바탕 화면 바로 가기 목록", + "Open in explorer": "탐색기에서 열기", + "Remove from list": "목록에서 제거", + "When new shortcuts are detected, delete them automatically instead of showing this dialog.": "새 바로 가기가 감지되면 이 대화 상자를 표시하지 않고 자동으로 삭제합니다.", + "Not right now": "지금은 아님", + "Missing dependency": "누락된 의존성", + "UniGetUI requires {0} to operate, but it was not found on your system.": "UniGetUI가 작업을 실행하려면 {0}이(가) 필요하지만 시스템에서 찾을 수 없습니다.", + "Click on Install to begin the installation process. If you skip the installation, UniGetUI may not work as expected.": "설치 버튼을 눌러 설치 프로세스를 시작하세요. 설치를 건너뛰면 UniGetUI가 예상대로 작동하지 않을 수 있습니다.", + "Alternatively, you can also install {0} by running the following command in a Windows PowerShell prompt:": "또는 Windows PowerShell 프롬프트에서 다음 명령을 실행하여 {0}을(를) 설치할 수도 있습니다:", + "Install {0}": "{0} 설치", + "Do not show this dialog again for {0}": "{0}에 대해 이 대화 상자를 다시 표시 안 함", + "Please wait while {0} is being installed. A black window may show up. Please wait until it closes.": "{0}을(를) 설치하는 동안 잠시만 기다려주세요. 검은(또는 파란) 창이 표시될 수 있습니다. 닫힐 때까지 기다려주세요.", + "{0} has been installed successfully.": "{0}을(를) 성공적으로 설치했습니다.", + "Please click on \"Continue\" to continue": "계속하려면 \"계속\"을 클릭하세요", + "Continue": "계속", + "{0} has been installed successfully. It is recommended to restart UniGetUI to finish the installation": "{0}이(가) 성공적으로 설치되었습니다. 설치를 완료하려면 UniGetUI를 다시 시작하기를 권장합니다", + "Restart later": "나중에 다시 시작", + "An error occurred:": "오류가 발생했습니다:", + "Please see the Command-line Output or refer to the Operation History for further information about the issue.": "이 문제에 대한 자세한 내용은 [명령줄 출력]을 참조하거나 [작업 기록]을 참조하세요.", + "Retry as administrator": "관리자 권한으로 다시 시도", + "Retry interactively": "대화형 다시 시도", + "Retry skipping integrity checks": "건너뛴 무결성 검사 다시 시도", + "Installation options": "설치 옵션", + "Save": "저장", + "UniGetUI collects anonymous usage data with the sole purpose of understanding and improving the user experience.": "UniGetUI는 오로지 사용자 경험을 이해 및 개선하기 위해 익명 사용 통계를 수집합니다.", + "More details about the shared data and how it will be processed": "공유 데이터 및 처리 방식에 대한 자세한 정보", + "Do you accept that UniGetUI collects and sends anonymous usage statistics, with the sole purpose of understanding and improving the user experience?": "사용자 경험을 이해 및 개선하기 위해 UniGetUI가 익명 사용 통계를 수집하고 보내도록 허용하시겠습니까?", + "Decline": "거부", + "No personal information is collected nor sent, and the collected data is anonimized, so it can't be back-tracked to you.": "개인 사용자 정보는 수집되지도 전송되지 않으며 역추적할 수 없도록 익명 처리되어 수집됩니다.", + "Navigation panel": "탐색 패널", + "Operations": "작업", + "Toggle operations panel": "작업 패널 전환", + "Bulk operations": "일괄 작업", + "Retry failed": "실패한 작업 다시 시도", + "Clear successful": "성공한 작업 지우기", + "Clear finished": "완료된 작업 지우기", + "Cancel all": "모두 취소", + "More": "자세히 보기", + "Toggle navigation panel": "탐색 패널 전환", + "Minimize": "최소화", + "Maximize": "최대화", + "UniGetUI by Devolutions": "Devolutions 제공 UniGetUI", + "UniGetUI is an application that makes managing your software easier, by providing an all-in-one graphical interface for your command-line package managers.": "UniGetUI는 명령줄 패키지 관리자에게 올인원 그래픽 인터페이스를 제공하여 소프트웨어 관리를 더 쉽게 해주는 응용 프로그램입니다.", + "Useful links": "유용한 링크", + "UniGetUI Homepage": "UniGetUI 홈페이지", + "Report an issue or submit a feature request": "문제 신고 또는 기능 요청 제출", + "UniGetUI Repository": "UniGetUI 저장소", + "View GitHub Profile": "GitHub 프로필 보기", + "UniGetUI License": "UniGetUI 라이선스", + "Using UniGetUI implies the acceptation of the MIT License": "UniGetUI를 사용하는 것은 MIT 라이선스에 동의하는 것입니다", + "Become a translator": "번역가", + "Go back": "뒤로 가기", + "Go forward": "앞으로 가기", + "Go to home page": "홈페이지로 이동", + "Reload page": "페이지 새로고침", + "View page on browser": "브라우저에서 페이지 보기", + "The built-in browser is not supported on Linux yet.": "기본 제공 브라우저는 아직 Linux에서 지원되지 않습니다.", + "Open in browser": "브라우저에서 열기", + "Copy to clipboard": "클립보드에 복사", + "Export to a file": "파일로 내보내기", + "Log level:": "로그 수준:", + "Reload log": "로그 다시 불러오기", + "Export log": "로그 내보내기", + "Text": "텍스트", + "Change how operations request administrator rights": "작업이 관리자 권한을 요청하는 방식 설정", + "Restrictions on package operations": "패키지 작업에 대한 제한 사항", + "Restrictions on package managers": "패키지 관리자에 대한 제한 사항", + "Restrictions when importing package bundles": "패키지 번들을 가져올 때의 제한 사항", + "Ask for administrator privileges once for each batch of operations": "각 작업 배치마다 한 번씩 관리자 권한 요청", + "Ask only once for administrator privileges": "관리자 권한을 한 번만 요청", + "Prohibit any kind of Elevation via UniGetUI Elevator or GSudo": "UniGetUI Elevator 또는 GSudo를 통한 모든 종류의 권한 상승 금지", + "This option WILL cause issues. Any operation incapable of elevating itself WILL FAIL. Install/update/uninstall as administrator will NOT WORK.": "이 옵션은 문제를 일으킬 수 있습니다. 스스로 권한을 상승시킬 수 없는 작업은 실패합니다. 관리자 권한으로 설치/업데이트/제거해도 작동하지 않습니다.", + "Allow custom command-line arguments": "사용자 지정 명령줄 인수 허용", + "Custom command-line arguments can change the way in which programs are installed, upgraded or uninstalled, in a way UniGetUI cannot control. Using custom command-lines can break packages. Proceed with caution.": "사용자 지정 명령줄 인수는 UniGetUI가 제어할 수 없는 방식으로 프로그램 설치, 업그레이드 또는 제거 방식을 변경할 수 있습니다. 사용자 지정 명령줄을 사용하면 패키지가 손상될 수 있습니다. 주의해서 진행하세요.", + "Ignore custom pre-install and post-install commands when importing packages from a bundle": "번들에서 패키지를 가져올 때 사용자 지정 설치 전 및 설치 후 명령 실행 허용", + "Pre and post install commands will be run before and after a package gets installed, upgraded or uninstalled. Be aware that they may break things unless used carefully": "패키지가 설치, 업그레이드 또는 제거되기 전후에 사전 및 사후 설치 명령이 실행됩니다. 신중하게 사용하지 않으면 문제가 발생할 수 있다는 점에 유의하세요", + "Allow changing the paths for package manager executables": "패키지 관리자 실행 파일의 경로 변경 허용", + "Turning this on enables changing the executable file used to interact with package managers. While this allows finer-grained customization of your install processes, it may also be dangerous": "이 기능을 켜면 패키지 관리자와 상호 작용하는 데 사용되는 실행 파일을 변경할 수 있습니다. 이렇게 하면 설치 프로세스를 세부적으로 사용자 지정할 수 있지만 위험할 수도 있습니다", + "Allow importing custom command-line arguments when importing packages from a bundle": "번들에서 패키지를 가져올 때 사용자 지정 명령줄 인수 가져오기 허용", + "Malformed command-line arguments can break packages, or even allow a malicious actor to gain privileged execution. Therefore, importing custom command-line arguments is disabled by default": "잘못된 형식의 명령줄 인수는 패키지를 깨거나 악의적인 행위자가 권한 있는 실행을 얻도록 허용할 수 있습니다. 따라서 사용자 지정 명령줄 인수를 가져오는 것은 기본적으로 비활성화되어 있습니다", + "Allow importing custom pre-install and post-install commands when importing packages from a bundle": "번들에서 패키지를 가져올 때 사용자 지정 설치 전 및 설치 후 명령 가져오기 허용", + "Pre and post install commands can do very nasty things to your device, if designed to do so. It can be very dangerous to import the commands from a bundle, unless you trust the source of that package bundle": "설치 전 및 설치 후 명령어는 장치에 매우 불쾌한 영향을 미칠 수 있습니다. 패키지 번들의 출처를 신뢰하지 않는 한 번들에서 명령어를 가져오는 것은 매우 위험할 수 있습니다", + "Administrator rights and other dangerous settings": "관리자 권한 및 기타 위험한 설정", + "Package backup": "패키지 백업", + "Cloud package backup": "클라우드 패키지 백업", + "Local package backup": "로컬 패키지 백업", + "Local backup advanced options": "로컬 백업 고급 옵션", + "Log in with GitHub": "GitHub 로그인", + "Log out from GitHub": "GitHub에서 로그아웃", + "Periodically perform a cloud backup of the installed packages": "설치된 패키지의 클라우드 백업을 주기적으로 수행", + "Cloud backup uses a private GitHub Gist to store a list of installed packages": "클라우드 백업은 개인 GitHub Gist를 사용하여 설치된 패키지 목록을 저장합니다", + "Perform a cloud backup now": "지금 클라우드 백업 수행", + "Backup": "백업", + "Restore a backup from the cloud": "클라우드에서 백업 복원", + "Begin the process to select a cloud backup and review which packages to restore": "프로세스를 시작하여 클라우드 백업을 선택하고 복원할 패키지 검토", + "Periodically perform a local backup of the installed packages": "설치된 패키지의 로컬 백업을 주기적으로 수행", + "Perform a local backup now": "지금 로컬 백업 수행", + "Change backup output directory": "백업 출력 디렉터리 변경", + "Set a custom backup file name": "사용자 지정 백업 파일 이름 설정", + "Leave empty for default": "공백은 기본값", + "Add a timestamp to the backup file names": "백업 파일 이름에 타임스탬프 추가", + "Backup and Restore": "백업 및 복원", + "Enable background api (UniGetUI Widgets and Sharing, port 7058)": "백그라운드 API 사용 (UniGetUI 위젯 및 공유, 포트 7058)", + "Wait for the device to be connected to the internet before attempting to do tasks that require internet connectivity.": "인터넷 연결이 필요한 작업을 수행하기 전에 장치가 인터넷에 연결될 때까지 기다리기.", + "Disable the 1-minute timeout for package-related operations": "패키지 관련 작업에서 1분 시간 제한 끄기", + "Use installed GSudo instead of UniGetUI Elevator": "UniGetUI Elevator 대신 설치된 GSudo 사용", + "Use a custom icon and screenshot database URL": "사용자 지정 아이콘 및 스크린샷 데이터베이스 URL 사용", + "Enable background CPU Usage optimizations (see Pull Request #3278)": "백그라운드 CPU 사용량 최적화 (풀 리퀘스트 #3278 참조)", + "Perform integrity checks at startup": "시작 시 무결성 검사 수행", + "When batch installing packages from a bundle, install also packages that are already installed": "번들에서 패키지를 일괄 설치할 때 이미 설치된 패키지도 함께 설치", + "Experimental settings and developer options": "실험적 설정 및 개발자 옵션", + "Show UniGetUI's version and build number on the titlebar.": "UniGetUI의 버전과 빌드 번호를 제목 표시줄에 표시합니다.", + "Language": "언어", + "UniGetUI updater": "UniGetUI 업데이트 프로그램", + "Telemetry": "진단", + "Manage UniGetUI settings": "UniGetUI 설정 관리", + "Related settings": "관련 설정", + "Update UniGetUI automatically": "자동으로 UniGetUI 업데이트", + "Check for updates": "업데이트 확인", + "Install prerelease versions of UniGetUI": "UniGetUI의 사전 릴리스 버전 설치", + "Manage telemetry settings": "진단 설정 관리", + "Manage": "관리", + "Import settings from a local file": "로컬 파일에서 설정 가져오기", + "Import": "가져오기", + "Export settings to a local file": "로컬 파일로 설정 내보내기", + "Export": "내보내기", + "Reset UniGetUI": "UniGetUI 초기화", + "User interface preferences": "사용자 인터페이스 환경 설정", + "Application theme, startup page, package icons, clear successful installs automatically": "응용 프로그램 테마, 시작 페이지, 패키지 아이콘, 성공한 설치 자동으로 지우기", + "General preferences": "일반 환경 설정", + "UniGetUI display language:": "UniGetUI 표시 언어:", + "System language": "시스템 언어", + "Is your language missing or incomplete?": "언어가 누락되었거나 불완전합니까?", + "Appearance": "모양", + "UniGetUI on the background and system tray": "백그라운드 및 시스템 트레이의 UniGetUI", + "Package lists": "패키지 목록", + "Use classic mode": "클래식 모드 사용", + "Restart UniGetUI to apply this change": "이 변경 사항을 적용하려면 UniGetUI를 다시 시작하세요", + "The classic UI is disabled for beta testers": "베타 테스터에게는 클래식 UI가 비활성화되어 있습니다", + "Close UniGetUI to the system tray": "시스템 트레이에 UniGetUI 닫기", + "Manage UniGetUI autostart behaviour": "UniGetUI 자동 시작 동작 관리", + "Show package icons on package lists": "패키지 목록에 패키지 아이콘 표시", + "Clear cache": "캐시 지우기", + "Select upgradable packages by default": "기본적으로 업그레이드 가능한 패키지 선택", + "Light": "밝은 테마", + "Dark": "어두운 테마", + "Follow system color scheme": "시스템 색상 구성표 따르기", + "Application theme:": "응용 프로그램 테마:", + "UniGetUI startup page:": "UniGetUI 시작 페이지:", + "Proxy settings": "프록시 설정", + "Other settings": "기타 설정", + "Connect the internet using a custom proxy": "사용자 지정 프록시를 사용하여 인터넷 연결", + "Please note that not all package managers may fully support this feature": "모든 패키지 관리자가 이 기능을 완전히 지원하는 것은 아닙니다", + "Proxy URL": "프록시 URL", + "Enter proxy URL here": "여기에 프록시 URL 입력", + "Authenticate to the proxy with a user and a password": "사용자 이름과 비밀번호로 프록시에 인증", + "Internet and proxy settings": "인터넷 및 프록시 설정", + "Package manager preferences": "패키지 관리자 환경 설정", + "Ready": "준비 완료", + "Not found": "찾을 수 없음", + "Notification preferences": "알림 환경 설정", + "Notification types": "알림 종류", + "The system tray icon must be enabled in order for notifications to work": "알림이 작동하려면 시스템 트레이 아이콘을 켜야 합니다", + "Enable UniGetUI notifications": "UniGetUI 알림 켜기", + "Show a notification when there are available updates": "사용 가능한 업데이트가 있을 때 알림 표시", + "Show a silent notification when an operation is running": "작업 실행 중일 때 조용한 알림 표시", + "Show a notification when an operation fails": "작업 실패 시 알림 표시", + "Show a notification when an operation finishes successfully": "작업이 성공적으로 완료되면 알림 표시", + "Concurrency and execution": "동시성 및 실행", + "Automatic desktop shortcut remover": "바탕 화면 바로 가기 자동 제거", + "Choose how many operations should be performed in parallel": "병렬로 수행할 작업 수 선택", + "Clear successful operations from the operation list after a 5 second delay": "성공한 작업을 작업 목록에서 5초 후에 지우기", + "Download operations are not affected by this setting": "다운로드 작업은 이 설정에 영향을 받지 않습니다", + "You may lose unsaved data": "저장되지 않은 데이터를 잃을 수 있습니다", + "Ask to delete desktop shortcuts created during an install or upgrade.": "설치 또는 업그레이드 중에 생성된 바탕 화면 바로 가기를 삭제할지 묻습니다.", + "Package update preferences": "패키지 업데이트 환경 설정", + "Update check frequency, automatically install updates, etc.": "업데이트 주기적 확인, 업데이트 자동 설치 등", + "Reduce UAC prompts, elevate installations by default, unlock certain dangerous features, etc.": "UAC 프롬프트 감소, 기본 설치 업그레이드, 특정 위험한 기능 잠금 해제 등.", + "Package operation preferences": "패키지 작업 환경 설정", + "Enable {pm}": "{pm} 사용함", + "Not finding the file you are looking for? Make sure it has been added to path.": "찾고 있는 파일을 찾지 못했나요? 경로에 파일이 추가되었는지 확인하세요.", + "Select the executable to be used. The following list shows the executables found by UniGetUI": "사용할 실행 파일을 선택합니다. 다음 목록은 UniGetUI에서 찾은 실행 파일을 보여줍니다", + "For security reasons, changing the executable file is disabled by default": "보안상의 이유로 실행 파일을 변경하는 것은 기본적으로 비활성화되어 있습니다", + "Change this": "이 항목 변경", + "Copy path": "경로 복사", + "Current executable file:": "현재 실행 파일:", + "Ignore packages from {pm} when showing a notification about updates": "업데이트 알림을 표시할 때 {pm}에서 패키지 무시", + "Update security": "업데이트 보안", + "Use global setting": "전역 설정 사용", + "Minimum age for updates": "업데이트 최소 기간", + "e.g. 10": "예시: 10", + "Custom minimum age (days)": "사용자 지정 최소 기간(일)", + "{pm} does not provide release dates for its packages, so this setting will have no effect": "{pm}은(는) 패키지의 릴리스 날짜를 제공하지 않으므로 이 설정은 적용되지 않습니다", + "{pm} only provides release dates for some of its packages, so this setting will only apply to those packages": "{pm}은(는) 일부 패키지에 대해서만 출시일을 제공하므로 이 설정은 해당 패키지에만 적용됩니다", + "Override the global minimum update age for this package manager": "이 패키지 관리자에 대해 전역 최소 업데이트 기간 설정 재정의", + "View {0} logs": "{0} 로그 보기", + "If Python cannot be found or is not listing packages but is installed on the system, ": "Python을 찾을 수 없거나 시스템에 설치되어 있는데도 패키지 목록이 표시되지 않는 경우, ", + "Advanced options": "고급 옵션", + "WinGet command-line tool": "WinGet 명령줄 도구", + "Choose which command-line tool UniGetUI uses for WinGet operations when the COM API is not used": "COM API를 사용하지 않을 때 UniGetUI가 WinGet 작업에 사용할 명령줄 도구를 선택합니다", + "WinGet COM API": "WinGet COM API", + "Choose whether UniGetUI can use the WinGet COM API before falling back to the command-line tool": "명령줄 도구로 대체하기 전에 UniGetUI가 WinGet COM API를 사용할 수 있는지 선택합니다", + "Reset WinGet": "WinGet 재설정", + "This may help if no packages are listed": "패키지가 표시되지 않으면 도움이 될 수 있습니다", + "Force install location parameter when updating packages with custom locations": "사용자 지정 위치의 패키지를 업데이트할 때 설치 위치 매개 변수 강제 사용", + "Install Scoop": "Scoop 설치", + "Uninstall Scoop (and its packages)": "Scoop 제거 및 Scoop으로 설치된 패키지 제거", + "Run cleanup and clear cache": "정리 실행 및 캐시 지우기", + "Run": "실행", + "Enable Scoop cleanup on launch": "프로그램 실행 시 Scoop 정리", + "Default vcpkg triplet": "기본 vcpkg triplet", + "Change vcpkg root location": "vcpkg 루트 위치 변경", + "Reset vcpkg root location": "vcpkg 루트 위치 재설정", + "Open vcpkg root location": "vcpkg 루트 위치 열기", + "Language, theme and other miscellaneous preferences": "언어, 테마 및 기타 환경 설정", + "Show notifications on different events": "다양한 이벤트에 대한 알림 표시", + "Change how UniGetUI checks and installs available updates for your packages": "UniGetUI가 사용 가능한 업데이트를 확인하고 설치하는 방식을 설정", + "Automatically save a list of all your installed packages to easily restore them.": "설치된 모든 패키지 목록을 자동으로 저장하여 쉽게 복원할 수 있습니다.", + "Enable and disable package managers, change default install options, etc.": "패키지 관리자 활성화 및 비활성화, 기본 설치 옵션 변경 등", + "Internet connection settings": "인터넷 연결 설정", + "Proxy settings, etc.": "프록시 설정 등", + "Beta features and other options that shouldn't be touched": "베타 기능 및 건드리지 말아야 할 기타 옵션", + "Reload sources": "소스 새로고침", + "Delete source": "소스 삭제", + "Known sources": "알려진 소스", + "Update checking": "업데이트 확인", + "Automatic updates": "자동 업데이트", + "Check for package updates periodically": "주기적으로 패키지 업데이트 확인", + "Check for updates every:": "업데이트 확인 빈도:", + "Install available updates automatically": "사용 가능한 업데이트 자동으로 설치", + "Do not automatically install updates when the network connection is metered": "데이터 통신 연결 네트워크에서 자동 업데이트 안 함", + "Do not automatically install updates when the device runs on battery": "장치가 배터리로 작동할 때 자동으로 업데이트 설치 안 함", + "Do not automatically install updates when the battery saver is on": "배터리 절약 모드(절전 모드)가 켜져 있을 때 자동 업데이트 안 함", + "Only show updates that are at least the specified number of days old": "지정한 일수 이상 지난 업데이트만 표시", + "Warn me when the installer URL host changes between the installed version and the new version (WinGet only)": "설치된 버전과 새 버전 간에 설치 URL 호스트가 변경될 때 경고 표시 (WinGet 전용)", + "Change how UniGetUI handles install, update and uninstall operations.": "UniGetUI가 설치, 업데이트 및 제거 작업을 처리하는 방식을 변경합니다.", + "Navigation": "탐색", + "Check for UniGetUI updates": "UniGetUI 업데이트 확인", + "Quit UniGetUI": "UniGetUI 종료", + "Filters": "필터", + "Sources": "공급자", + "Search for packages to start": "시작할 패키지 검색", + "Select all": "모두 선택", + "Clear selection": "모두 선택 해제", + "Instant search": "즉시 검색", + "Distinguish between uppercase and lowercase": "대문자와 소문자 구분", + "Ignore special characters": "특수 문자 무시", + "Search mode": "검색 모드", + "Both": "모두", + "Exact match": "정확히 일치", + "Show similar packages": "유사한 패키지 표시", + "Loading": "로딩 중", + "Package": "패키지", + "More options": "더 많은 옵션", + "Order by:": "정렬:", + "Name": "이름", + "Id": "아이디", + "Ascendant": "오름차순", + "Descendant": "내림차순", + "View modes": "보기 모드", + "Reload": "새로고침", + "Closed": "닫힘", + "Ascending": "오름차순", + "Descending": "내림차순", + "{0}: {1}, {2}": "{0}: {1}, {2}", + "Order by": "정렬 기준", + "No results were found matching the input criteria": "입력 기준과 일치하는 결과를 찾을 수 없습니다", + "No packages were found": "패키지를 찾을 수 없습니다", + "Loading packages": "패키지 불러오는 중", + "Skip integrity checks": "무결성 검사 건너뛰기", + "Download selected installers": "선택한 설치 프로그램 다운로드", + "Install selection": "설치 항목 선택", + "Install options": "설치 옵션", + "Add selection to bundle": "번들에 선택 항목 추가", + "Download installer": "설치 프로그램 다운로드", + "Uninstall selection": "선택 항목 제거", + "Uninstall options": "제거 옵션", + "Ignore selected packages": "선택한 패키지 무시", + "Open install location": "설치 위치 열기", + "Reinstall package": "패키지 재설치", + "Uninstall package, then reinstall it": "패키지 제거 후 재설치", + "Ignore updates for this package": "이 패키지에 대한 업데이트 무시", + "WinGet malfunction detected": "WinGet 부조 감지됨", + "It looks like WinGet is not working properly. Do you want to attempt to repair WinGet?": "WinGet이 올바르게 작동하지 않는 것 같습니다. WinGet 복구를 시도하시겠어요?", + "Repair WinGet": "WinGet 복구", + "Updates will no longer be ignored for {0}": "{0}에 대한 업데이트가 더 이상 무시되지 않습니다", + "Updates are now ignored for {0}": "{0}에 대한 업데이트가 이제 무시됩니다", + "Do not ignore updates for this package anymore": "이 패키지에 대한 업데이트 무시 안 함", + "Add packages or open an existing package bundle": "패키지 추가 또는 기존 패키지 번들 열기", + "Add packages to start": "시작에 패키지 추가", + "The current bundle has no packages. Add some packages to get started": "현재 번들에 패키지가 없습니다. 시작하려면 몇 가지 패키지를 추가하세요", + "New": "새로 만들기", + "Save as": "다른 이름으로 저장", + "Create .ps1 script": ".ps1 스크립트 생성", + "Remove selection from bundle": "번들에서 선택 항목 제거", + "Skip hash checks": "해시 검사 건너뛰기", + "The package bundle is not valid": "패키지 번들이 유효하지 않습니다", + "The bundle you are trying to load appears to be invalid. Please check the file and try again.": "불러오려는 번들이 유효하지 않은 것으로 보입니다. 파일을 확인하고 다시 시도해주세요.", + "Package bundle": "패키지 번들", + "Could not create bundle": "번들을 만들 수 없습니다", + "The package bundle could not be created due to an error.": "오류로 인해 패키지 번들을 만들 수 없습니다.", + "Install script": "설치 스크립트", + "PowerShell script": "PowerShell 스크립트", + "The installation script saved to {0}": "{0}에 저장된 설치 스크립트", + "An error occurred": "오류가 발생했습니다", + "An error occurred while attempting to create an installation script:": "설치 스크립트를 생성하는 동안 오류가 발생했습니다:", + "Hooray! No updates were found.": "만세! 업데이트가 발견되지 않았습니다.", + "Uninstall selected packages": "선택한 패키지 제거", + "Update selection": "선택 항목 업데이트", + "Update options": "업데이트 옵션", + "Uninstall package, then update it": "패키지 제거 후 업데이트", + "Uninstall package": "패키지 제거", + "Skip this version": "이 버전 건너뛰기", + "Pause updates for": "업데이트 일시 중지", + "User | Local": "사용자 | 로컬", + "Machine | Global": "머신 | 전역", + "The default package manager for Debian/Ubuntu-based Linux distributions.
Contains: Debian/Ubuntu packages": "Debian/Ubuntu 기반 Linux 배포판의 기본 패키지 관리자입니다.
포함: Debian/Ubuntu 패키지", + "The Rust package manager.
Contains: Rust libraries and programs written in Rust": "Rust의 패키지 관리자입니다.
포함 내용: Rust로 작성된 Rust 라이브러리 및 프로그램", + "The classical package manager for windows. You'll find everything there.
Contains: General Software": "Windows용 클래식 패키지 관리자. 뭐든지 찾을 수 있습니다.
포함 내용: 일반 소프트웨어", + "The default package manager for RHEL/Fedora-based Linux distributions.
Contains: RPM packages": "RHEL/Fedora 기반 Linux 배포판의 기본 패키지 관리자입니다.
포함: RPM 패키지", + "A repository full of tools and executables designed with Microsoft's .NET ecosystem in mind.
Contains: .NET related tools and scripts": "Microsoft의 .NET 생태계를 염두에 두고 설계된 도구와 실행 파일로 가득한 저장소입니다.
포함 내용: .NET 관련 도구 및 스크립트", + "The universal Linux package manager for desktop applications.
Contains: Flatpak applications from configured remotes": "데스크톱 응용 프로그램용 범용 Linux 패키지 관리자입니다.
포함 항목: 구성된 원격 저장소의 Flatpak 응용 프로그램", + "NuPkg (zipped manifest)": "NuPkg (압축된 매니페스트)", + "The Missing Package Manager for macOS (or Linux).
Contains: Formulae, Casks": "macOS (또는 Linux)를 위한 없어서는 안 될 패키지 관리자입니다.
포함 항목: Formulae, Casks", + "Node JS's package manager. Full of libraries and other utilities that orbit the javascript world
Contains: Node javascript libraries and other related utilities": "Node JS의 패키지 관리자. 자바스크립트와 관련된 라이브러리와 기타 유틸리티로 가득합니다.
포함 내용: 노드 자바스크립트 라이브러리 및 기타 관련 유틸리티", + "The default package manager for Arch Linux and its derivatives.
Contains: Arch Linux packages": "Arch Linux 및 그 파생 배포판의 기본 패키지 관리자입니다.
포함: Arch Linux 패키지", + "Python's library manager. Full of python libraries and other python-related utilities
Contains: Python libraries and related utilities": "Python 라이브러리 관리자. Python 라이브러리 및 기타 Python 관련 유틸리티가 가득합니다
포함 내용: Python 라이브러리 및 관련 유틸리티", + "PowerShell's package manager. Find libraries and scripts to expand PowerShell capabilities
Contains: Modules, Scripts, Cmdlets": "PowerShell의 패키지 관리자. PowerShell 기능을 확장할 라이브러리 및 스크립트를 찾아보세요.
포함 내용: 모듈, 스크립트, Cmdlet", + "extracted": "압축 해제됨", + "Scoop package": "Scoop 패키지", + "Great repository of unknown but useful utilities and other interesting packages.
Contains: Utilities, Command-line programs, General Software (extras bucket required)": "알려지지 않았지만 유용한 유틸리티 및 기타 흥미로운 패키지의 훌륭한 저장소입니다.
포함: 유틸리티, 명령줄 프로그램, 일반 소프트웨어 (추가 버킷 필요)/b>", + "The universal Linux package manager by Canonical.
Contains: Snap packages from the Snapcraft store": "Canonical의 범용 Linux 패키지 관리자입니다.
포함: Snapcraft 스토어의 Snap 패키지", + "library": "라이브러리", + "feature": "기능", + "A popular C/C++ library manager. Full of C/C++ libraries and other C/C++-related utilities
Contains: C/C++ libraries and related utilities": "인기 있는 C/C++ 라이브러리 관리자입니다. C/C++ 라이브러리 및 기타 C/C++ 관련 유틸리티로 가득합니다.
포함 내용: C/C++ 라이브러리 및 관련 유틸리티", + "option": "옵션", + "This package cannot be installed from an elevated context.": "이 패키지는 권한 상승된 컨텍스트에서는 설치할 수 없습니다.", + "Please run UniGetUI as a regular user and try again.": "UniGetUI를 일반 사용자로 실행하고 다시 시도해주세요.", + "Please check the installation options for this package and try again": "이 패키지의 설치 옵션을 확인하고 다시 시도해주세요", + "Microsoft's official package manager. Full of well-known and verified packages
Contains: General Software, Microsoft Store apps": "Microsoft 공식 패키지 관리자입니다. 잘 알려지고 검증된 패키지로 구성되어 있습니다.
포함: 일반 소프트웨어, Microsoft Store 앱", + "Local PC": "로컬 PC", + "Android Subsystem": "Android 하위 시스템", + "Operation on queue (position {0})...": "작업 대기 중(위치 {0})...", + "Click here for more details": "여기를 눌러 자세한 정보 확인", + "Operation canceled by user": "사용자가 작업을 취소했습니다", + "Running PreOperation ({0}/{1})...": "PreOperation 실행 중 ({0}/{1})...", + "PreOperation {0} out of {1} failed, and was tagged as necessary. Aborting...": "{1}개 중 PreOperation {0}이(가) 실패했고 필수로 지정되어 있어 중단합니다...", + "PreOperation {0} out of {1} finished with result {2}": "{1}개 중 PreOperation {0}이(가) 결과 {2}(으)로 완료되었습니다", + "Starting operation...": "작업 시작 중...", + "Running PostOperation ({0}/{1})...": "PostOperation 실행 중 ({0}/{1})...", + "PostOperation {0} out of {1} failed, and was tagged as necessary. Aborting...": "{1}개 중 PostOperation {0}이(가) 실패했고 필수로 지정되어 있어 중단합니다...", + "PostOperation {0} out of {1} finished with result {2}": "{1}개 중 PostOperation {0}이(가) 결과 {2}(으)로 완료되었습니다", + "{package} installer download": "{package} 설치 프로그램 다운로드", + "{0} installer is being downloaded": "{0} 설치 프로그램을 다운로드하고 있습니다", + "Download succeeded": "다운로드 성공", + "{package} installer was downloaded successfully": "{package} 설치 프로그램을 성공적으로 다운로드했습니다", + "Download failed": "다운로드 실패", + "{package} installer could not be downloaded": "{package} 설치 프로그램을 다운로드할 수 없습니다", + "{package} Installation": "{package} 설치", + "{0} is being installed": "{0}을(를) 설치하고 있습니다", + "Installation succeeded": "설치 성공", + "{package} was installed successfully": "{package}을(를) 성공적으로 설치했습니다", + "Installation failed": "설치 실패", + "{package} could not be installed": "{package}을(를) 설치할 수 없습니다.", + "{package} Update": "{package} 업데이트", + "Update succeeded": "업데이트 성공", + "{package} was updated successfully": "{package}을(를) 성공적으로 업데이트했습니다", + "Update failed": "업데이트 실패", + "{package} could not be updated": "{package}를 업데이트할 수 없습니다", + "{package} Uninstall": "{package} 제거", + "{0} is being uninstalled": "{0}을(를) 제거하고 있습니다", + "Uninstall succeeded": "제거 성공", + "{package} was uninstalled successfully": "{package}을(를) 성공적으로 제거했습니다", + "Uninstall failed": "제거 실패", + "{package} could not be uninstalled": "{package}을(를) 제거할 수 없습니다", + "Adding source {source}": "{source} 소스 추가", + "Adding source {source} to {manager}": "{manager}에 {source} 소스 추가", + "Source added successfully": "공급자를 성공적으로 추가했습니다", + "The source {source} was added to {manager} successfully": "공급자 {source}을(를) {manager}에 성공적으로 추가했습니다", + "Could not add source": "소스를 추가할 수 없습니다", + "Could not add source {source} to {manager}": "{manager}에 {source} 소스를 추가할 수 없습니다", + "Removing source {source}": "{source} 소스 제거", + "Removing source {source} from {manager}": "{manager}에서 {source} 소스 제거", + "Source removed successfully": "공급자를 성공적으로 제거했습니다", + "The source {source} was removed from {manager} successfully": "공급자 {source}을(를) {manager}에서 성공적으로 제거했습니다", + "Could not remove source": "소스를 제거할 수 없습니다", + "Could not remove source {source} from {manager}": "{manager}에서 {source} 소스를 제거할 수 없습니다", + "The package manager \"{0}\" was not found": "패키지 관리자 \"{0}\"을(를) 찾을 수 없습니다.", + "The package manager \"{0}\" is disabled": "패키지 관리자 \"{0}\"이(가) 꺼져 있습니다.", + "There is an error with the configuration of the package manager \"{0}\"": "패키지 관리자 \"{0}\" 구성에 오류가 발생했습니다.", + "The package \"{0}\" was not found on the package manager \"{1}\"": "패키지 관리자 \"{1}\"에서 \"{0}\" 패키지를 찾을 수 없습니다.", + "{0} is disabled": "{0}이(가) 비활성화 됨", + "{0} weeks": "{0}주", + "1 month": "1개월", + "{0} months": "{0}개월", + "Something went wrong": "문제가 발생했습니다", + "An interal error occurred. Please view the log for further details.": "내부 오류가 발생했습니다. 자세한 내용은 로그를 확인하세요.", + "No applicable installer was found for the package {0}": "패키지 {0}에 적용 가능한 설치 프로그램을 찾을 수 없습니다.", + "Integrity checks will not be performed during this operation": "이 작업 중에는 무결성 검사가 수행되지 않습니다", + "This is not recommended.": "권장하지 않습니다.", + "Run now": "지금 실행", + "Run next": "다음 항목 실행", + "Run last": "마지막 실행", + "Show in explorer": "탐색기에 표시", + "Checked": "체크됨", + "Unchecked": "체크 해제됨", + "This package is already installed": "이 패키지는 이미 설치되어 있습니다", + "This package can be upgraded to version {0}": "이 패키지는 {0} 버전으로 업그레이드할 수 있습니다.", + "Updates for this package are ignored": "이 패키지에 대한 업데이트 무시", + "This package is being processed": "이 패키지는 처리 중입니다", + "This package is not available": "이 패키지는 사용할 수 없습니다", + "Select the source you want to add:": "추가하고 싶은 소스를 선택하세요:", + "Source name:": "공급자 이름:", + "Source URL:": "공급자 URL:", + "An error occurred when adding the source: ": "소스를 추가하는 동안 오류가 발생했습니다: ", + "Package management made easy": "패키지 관리가 더욱 쉬워졌습니다", + "version {0}": "버전 {0}", + "[RAN AS ADMINISTRATOR]": "관리자로 실행", + "Portable mode": "포터블 모드", + "DEBUG BUILD": "디버그 빌드", + "Here you can change UniGetUI's behaviour regarding the following shortcuts. Checking a shortcut will make UniGetUI delete it if if gets created on a future upgrade. Unchecking it will keep the shortcut intact": "여기에서 다음 단축키에 대한 UniGetUI의 동작을 변경할 수 있습니다. 단축키를 선택하면 향후 업그레이드 시 생성된 경우 UniGetUI가 이를 삭제합니다. 선택을 해제하면 단축키가 그대로 유지됩니다", + "Manual scan": "수동 검사", + "Existing shortcuts on your desktop will be scanned, and you will need to pick which ones to keep and which ones to remove.": "바탕 화면에 이미 존재하는 바로 가기를 스캔하며, 어떤 바로 가기를 유지하고 어떤 바로 가기를 제거할 지 골라야 합니다.", + "Delete?": "삭제할까요?", + "I understand": "알겠습니다", + "Chocolatey setup changed": "Chocolatey 설정이 변경되었습니다", + "UniGetUI no longer includes its own private Chocolatey installation. A legacy UniGetUI-managed Chocolatey installation was detected for this user profile, but system Chocolatey was not found. Chocolatey will stay unavailable in UniGetUI until Chocolatey is installed on the system and UniGetUI is restarted. Applications previously installed through UniGetUI's bundled Chocolatey may still appear under other sources such as Local PC or WinGet.": "UniGetUI는 더 이상 자체 Chocolatey 설치를 포함하지 않습니다. 이 사용자 프로필에서 레거시 UniGetUI 관리 Chocolatey 설치가 감지되었지만 시스템 Chocolatey를 찾을 수 없습니다. 시스템에 Chocolatey를 설치하고 UniGetUI를 다시 시작할 때까지 UniGetUI에서 Chocolatey를 사용할 수 없습니다. UniGetUI에 번들된 Chocolatey를 통해 이전에 설치된 응용 프로그램은 로컬 PC 또는 WinGet과 같은 다른 소스에 계속 표시될 수 있습니다.", + "NOTE: This troubleshooter can be disabled from UniGetUI Settings, on the WinGet section": "참고: 이 문제 해결사는 WinGet 섹션의 UniGetUI 설정에서 비활성화할 수 있습니다", + "Restart": "다시 시작", + "Are you sure you want to delete all shortcuts?": "모든 바로 가기를 삭제하시겠습니까?", + "Any new shorcuts created during an install or an update operation will be deleted automatically, instead of showing a confirmation prompt the first time they are detected.": "설치 또는 업데이트 작업 중에 생성된 새 단축키는 처음 감지되었을 때 확인 메시지가 표시되지 않고 자동으로 삭제됩니다.", + "Any shorcuts created or modified outside of UniGetUI will be ignored. You will be able to add them via the {0} button.": "UniGetUI 외부에서 생성되거나 수정된 단축키는 무시됩니다. {0} 버튼을 통해 단축키를 추가할 수 있습니다.", + "Are you really sure you want to enable this feature?": "이 기능을 정말로 켜시겠습니까?", + "No new shortcuts were found during the scan.": "검사 중에 새로운 바로가기가 발견되지 않았습니다.", + "How to add packages to a bundle": "번들에 패키지를 추가하는 방법", + "In order to add packages to a bundle, you will need to: ": "패키지를 번들에 추가하려면 다음이 필요합니다: ", + "1. Navigate to the \"{0}\" or \"{1}\" page.": "1. \"{0}\" 또는 \"{1}\" 페이지로 탐색하세요.", + "2. Locate the package(s) you want to add to the bundle, and select their leftmost checkbox.": "2. 번들에 추가하려는 패키지의 위치를 지정하고 가장 왼쪽의 선택란을 선택하세요.", + "3. When the packages you want to add to the bundle are selected, find and click the option \"{0}\" on the toolbar.": "3. 번들에 추가하려는 패키지가 선택되면 도구 모음에서 \"{0}\" 옵션을 찾아 클릭하세요.", + "4. Your packages will have been added to the bundle. You can continue adding packages, or export the bundle.": "4. 패키지가 번들에 추가되었습니다. 계속해서 패키지를 추가하거나 번들을 내보낼 수 있습니다.", + "Which backup do you want to open?": "어떤 백업을 열고 싶으신가요?", + "Select the backup you want to open. Later, you will be able to review which packages you want to install.": "열 백업을 선택합니다. 나중에 복원하려는 패키지/프로그램을 검토할 수 있습니다.", + "There are ongoing operations. Quitting UniGetUI may cause them to fail. Do you want to continue?": "진행 중인 작업이 있습니다. UniGetUI를 끝내면 작업이 실패할 수 있습니다. 계속할까요?", + "UniGetUI or some of its components are missing or corrupt.": "UniGetUI 또는 일부 구성 요소가 누락되었거나 손상되었습니다.", + "It is strongly recommended to reinstall UniGetUI to adress the situation.": "이 문제를 해결하기 위해 UniGetUI를 재설치하는 것을 강력히 권장합니다.", + "Refer to the UniGetUI Logs to get more details regarding the affected file(s)": "영향을 받은 파일에 대한 자세한 내용은 UniGetUI 로그를 참조하세요", + "Integrity checks can be disabled from the Experimental Settings": "무결성 검사는 실험 설정에서 비활성화할 수 있습니다", + "Repair UniGetUI": "UniGetUI 복구", + "Live output": "실시간 출력", + "This package bundle had some settings that are potentially dangerous, and may be ignored by default.": "이 패키지 번들에는 잠재적으로 위험할 수 있는 몇 가지 설정이 포함되어 있으며, 기본적으로 무시될 수 있습니다.", + "Entries that show in YELLOW will be IGNORED.": "노란색으로 표시된 항목은 무시됩니다.", + "Entries that show in RED will be IMPORTED.": "빨간색으로 표시된 항목은 가져오기됩니다.", + "You can change this behavior on UniGetUI security settings.": "UniGetUI 보안 설정에서 이 동작을 변경할 수 있습니다.", + "Open UniGetUI security settings": "UniGetUI 보안 설정 열기", + "Should you modify the security settings, you will need to open the bundle again for the changes to take effect.": "보안 설정을 수정한 경우 변경 사항을 적용하려면 번들을 다시 열어야 합니다.", + "Details of the report:": "보고서의 세부 사항:", + "Are you sure you want to create a new package bundle? ": "새 패키지 번들을 만드시겠습니까? ", + "Any unsaved changes will be lost": "저장하지 않은 모든 변경 내용이 손실됩니다.", + "Warning!": "경고!", + "For security reasons, custom command-line arguments are disabled by default. Go to UniGetUI security settings to change this. ": "보안상의 이유로 사용자 지정 명령줄 인수는 기본적으로 비활성화되어 있습니다. 이를 변경하려면 UniGetUI 보안 설정으로 이동하세요. ", + "Change default options": "기본 옵션 변경", + "Ignore future updates for this package": "이 패키지에 대한 향후 업데이트 무시", + "For security reasons, pre-operation and post-operation scripts are disabled by default. Go to UniGetUI security settings to change this. ": "보안상의 이유로 사전 및 사후 스크립트는 기본적으로 비활성화되어 있습니다. 이를 변경하려면 UniGetUI 보안 설정으로 이동하세요. ", + "You can define the commands that will be run before or after this package is installed, updated or uninstalled. They will be run on a command prompt, so CMD scripts will work here.": "이 패키지가 설치, 업데이트 또는 제거되기 전이나 후에 실행될 명령어를 정의할 수 있습니다. 명령 프롬프트에서 실행되므로 CMD 스크립트는 여기에서 작동합니다.", + "Change this and unlock": "이것을 변경하고 잠금 해제", + "{0} Install options are currently locked because {0} follows the default install options.": "{0} 설치 옵션은 현재 잠겨 있습니다. {0}은 기본 설치 옵션을 따르기 때문입니다.", + "Unset or unknown": "설정 안 됨 또는 알 수 없음", + "This package has no screenshots or is missing the icon? Contrbute to UniGetUI by adding the missing icons and screenshots to our open, public database.": "이 패키지가 스크린샷 또는 아이콘이 없나요? 우리의 오픈 및 공용 데이터베이스에 누락된 아이콘 및 스크린샷을 추가하여 UniGetUI에 기여하세요.", + "Become a contributor": "기여자 되기", + "Update to {0} available": "{0}(으)로 업데이트 가능", + "Reinstall": "재설치", + "Installer not available": "설치 프로그램을 사용할 수 없음", + "Version:": "버전:", + "UniGetUI Version {0}": "UniGetUI 버전 {0}", + "Performing backup, please wait...": "백업을 수행하는 중. 잠시만 기다려주세요...", + "An error occurred while logging in: ": "로그인하는 동안 오류가 발생했습니다: ", + "Fetching available backups...": "사용 가능한 백업을 가져오는 중...", + "Done!": "완료!", + "The cloud backup has been loaded successfully.": "클라우드 백업이 성공적으로 로드되었습니다.", + "An error occurred while loading a backup: ": "백업을 로드하는 동안 오류가 발생했습니다: ", + "Backing up packages to GitHub Gist...": "GitHub Gist에 패키지 백업 중...", + "Backup Successful": "백업 성공", + "The cloud backup completed successfully.": "클라우드 백업이 성공적으로 완료되었습니다.", + "Could not back up packages to GitHub Gist: ": "GitHub Gist에 패키지를 백업할 수 없습니다: ", + "It is not guaranteed that the provided credentials will be stored safely, so you may as well not use the credentials of your bank account": "제공된 자격 증명이 안전하게 저장될 것이라는 보장이 없으므로 은행 계좌의 자격 증명을 사용하지 않는 것이 좋습니다", + "Enable the automatic WinGet troubleshooter": "WinGet 문제 해결사 자동으로 켜기", + "Add updates that fail with a 'no applicable update found' to the ignored updates list": "'해당 업데이트를 찾을 수 없음'으로 실패한 업데이트를 무시된 업데이트 목록에 추가합니다.", + "Invalid selection": "잘못된 선택", + "No package was selected": "선택된 패키지가 없습니다", + "More than 1 package was selected": "두 개 이상의 패키지가 선택되었습니다", + "List": "목록", + "Grid": "격자", + "Icons": "아이콘", + "\"{0}\" is a local package and does not have available details": "\"{0}\"은 로컬 패키지이며 사용 가능한 세부 정보가 없습니다", + "\"{0}\" is a local package and is not compatible with this feature": "\"{0}\"은 로컬 패키지이며 이 기능과 호환되지 않습니다", + "Add packages to bundle": "번들에 패키지 추가", + "Preparing packages, please wait...": "패키지 준비 중, 잠시만 기다려주세요...", + "Loading packages, please wait...": "패키지를 불러오는 중입니다. 잠시만 기다려주세요...", + "Saving packages, please wait...": "패키지 저장 중. 잠시만 기다려주세요...", + "The bundle was created successfully on {0}": "{0}에 번들이 성공적으로 생성되었습니다", + "User profile": "사용자 프로필", + "Error": "오류", + "Log in failed: ": "로그인 실패: ", + "Log out failed: ": "로그아웃 실패: ", + "Package backup settings": "패키지 백업 설정", + "Show the release notes after UniGetUI is updated": "UniGetUI 업데이트 후 릴리스 노트 표시" +} diff --git a/src/Languages/lang_ku.json b/src/Languages/lang_ku.json new file mode 100644 index 0000000..05d1c41 --- /dev/null +++ b/src/Languages/lang_ku.json @@ -0,0 +1,850 @@ +{ + "{0} of {1} operations completed": "{0} ji {1} kiryaran temam bûn", + "{0} is now {1}": "{0} ئێستا {1}ە", + "Enabled": "چالاک", + "Disabled": "ناچالاک", + "Privacy": "Nepenîtî", + "Hide my username from the logs": "Navê bikarhênerê min ji têketinan veşêre", + "Replaces your username with **** in the logs. Restart UniGetUI to also hide it from already-recorded entries.": "Navê te yê bikarhêner di têketinan de bi **** diguherîne. UniGetUI ji nû ve bide destpêkirin da ku ew ji navnîşeyên jixwe-tomarkirî jî were veşartin.", + "Your last update attempt did not complete.": "دوایین هەوڵی نوێکردنەوەکەت تەواو نەبوو.", + "UniGetUI could not confirm whether the update succeeded. Open the log to see what happened.": "UniGetUI نەیتوانی دڵنیابێت کە نوێکردنەوەکە سەرکەوتوو بوو یان نا. تۆمارەکە بکەرەوە بۆ بینینی ئەوەی چی ڕوویداوە.", + "View log": "تۆمار ببینە", + "The installer reported success but did not restart UniGetUI.": "دامەزرێنەرەکە سەرکەوتنی ڕاپۆرت کرد، بەڵام UniGetUIی دووبارە دەست پێ نەکردەوە.", + "The installer failed to initialize.": "دامەزرێنەرەکە لە دەستپێکردن شکستی هێنا.", + "Setup was canceled before installation began.": "ڕێکخستنەکە پێش دەستپێکردنی دامەزراندن هەڵوەشێندرایەوە.", + "A fatal error occurred during the preparation phase.": "لە قۆناغی ئامادەکردندا هەڵەیەکی کوشندە ڕوویدا.", + "A fatal error occurred during installation.": "لە کاتی دامەزراندندا هەڵەیەکی کوشندە ڕوویدا.", + "Installation was canceled while in progress.": "دامەزراندن لە کاتی جێبەجێکردندا هەڵوەشێندرایەوە.", + "The installer was terminated by another process.": "دامەزرێنەرەکە لەلایەن پرۆسەیەکی ترەوە کۆتایی پێهێنرا.", + "The preparation phase determined the installation cannot proceed.": "قۆناغی ئامادەکردن دیاری کرد کە دامەزراندن ناتوانێت بەردەوام بێت.", + "The installer could not start. UniGetUI may already be running, or you do not have permission to install.": "دامەزرێنەرەکە نەیتوانی دەست پێ بکات. لەوانەیە UniGetUI پێشتر لە کاردابێت، یان مۆڵەتی دامەزراندنت نەبێت.", + "Unexpected installer error.": "هەڵەیەکی چاوەڕواننەکراوی دامەزرێنەر.", + "We are checking for updates.": "لە پشکنینی نوێکردنەوەداین.", + "Please wait": "تکایە چاوەڕێ بکە", + "Great! You are on the latest version.": "زۆر باشە! تۆ لەسەر دوا وەشانیت.", + "There are no new UniGetUI versions to be installed": "هیچ وەشانی نوێی UniGetUI نییە بۆ ئەوەی دابمەزرێت", + "UniGetUI version {0} is being downloaded.": "UniGetUI وەشانی {0} دادەگیرێت.", + "This may take a minute or two": "ئەمە لەوانەیە یەک یان دوو خولەک بخایەنێت", + "The installer authenticity could not be verified.": "ڕەسەنایەتی دامەزرێنەرەکە نەکرا پشتڕاست بکرێتەوە.", + "The update process has been aborted.": "پرۆسەی نوێکردنەوە واز لێهێنرا.", + "Auto-update is not yet available on this platform.": "نوێکردنەوەی خۆکار هێشتا لەسەر ئەم پلاتفۆرمە بەردەست نییە.", + "Please update UniGetUI manually.": "تکایە UniGetUI بە دەستی نوێ بکەرەوە.", + "An error occurred when checking for updates: ": "کاتێک بۆ نوێکردنەوە پشکنین دەکرا هەڵەیەک ڕوویدا: ", + "The updater could not be launched.": "نەکرا نوێکەرەوەکە دەست پێ بکرێت.", + "The operating system did not start the installer process.": "سیستەمی کارپێکردن پرۆسەی دامەزرێنەرەکەی دەست پێ نەکرد.", + "UniGetUI is being updated...": "UniGetUI نوێ دەکرێتەوە...", + "Update installed.": "نوێکردنەوە دامەزرا.", + "UniGetUI was updated successfully, but this running copy was not replaced. This usually means you are running a development build. Close this copy and start the newly-installed version to finish.": "UniGetUI بە سەرکەوتوویی نوێکرایەوە، بەڵام ئەم کۆپییەی ئێستا لە کاردایە نەگۆڕدرا. ئەمە زۆرجار واتە وەشانێکی پەرەپێدان بەکاردەهێنیت. ئەم کۆپییە دابخە و وەشانی تازە-دامەزراو دەست پێ بکە بۆ تەواوکردن.", + "The update could not be applied.": "نەکرا نوێکردنەوەکە جێبەجێ بکرێت.", + "Installer exit code {0}: {1}": "کۆدی دەرچوونی دامەزرێنەر {0}: {1}", + "Update cancelled.": "نوێکردنەوە هەڵوەشێندرایەوە.", + "Authentication was cancelled.": "ڕەسەنایەتیپێدان هەڵوەشێندرایەوە.", + "Installer exit code {0}": "کۆدی دەرچوونی دامەزرێنەر {0}", + "Operation in progress": "کردار لە جێبەجێکردندایە", + "Please wait...": "تکایە چاوەڕێ بکە...", + "Success!": "سەرکەوتوو بوو!", + "Failed": "شکستی هێنا", + "An error occurred while processing this package": "لە کاتی پرۆسەکردنی ئەم پاکێجە هەڵەیەک ڕوویدا", + "Installer": "دامەزرێنەر", + "Executable": "پەڕگەی جێبەجێکراو", + "MSI": "MSI", + "Compressed file": "پەڕگەی پەستاندراو", + "MSIX": "MSIX", + "WinGet was repaired successfully": "WinGet بە سەرکەوتوویی چاک کرایەوە", + "It is recommended to restart UniGetUI after WinGet has been repaired": "پێشنیار دەکرێت دوای چاککردنەوەی WinGet، UniGetUI دووبارە دەست پێ بکەیت", + "WinGet could not be repaired": "نەکرا WinGet چاک بکرێتەوە", + "An unexpected issue occurred while attempting to repair WinGet. Please try again later": "کێشەیەکی چاوەڕواننەکراو کاتێک هەوڵ دەدرا WinGet چاک بکرێتەوە ڕوویدا. تکایە دواتر دووبارە هەوڵ بدەوە", + "Log in to enable cloud backup": "بچۆرە ژوورەوە بۆ چالاککردنی پاشەکەوتی هەور", + "Backup Failed": "پاشەکەوتکردن شکستی هێنا", + "Downloading backup...": "پاشەکەوت دادەبەزێت...", + "An update was found!": "نوێکردنەوەیەک دۆزرایەوە!", + "{0} can be updated to version {1}": "{0} دەتوانرێت بۆ وەشانی {1} نوێ بکرێتەوە", + "Updates found!": "نوێکردنەوە دۆزرایەوە!", + "{0} packages can be updated": "{0} پاکێج دەتوانرێت نوێ بکرێتەوە", + "{0} is being updated to version {1}": "{0} بۆ وەشانی {1} نوێ دەکرێتەوە", + "{0} packages are being updated": "{0} پەکەج نوێ دەکرێنەوە", + "You have currently version {0} installed": "ئێستا وەشانی {0}ت دامەزراوە", + "Desktop shortcut created": "کورتڕێی سەر مێز دروست کرا", + "UniGetUI has detected a new desktop shortcut that can be deleted automatically.": "UniGetUI کورتڕێیەکی نوێی سەر مێزی دۆزییەوە کە دەتوانرێت بە شێوەی خۆکار بسڕدرێتەوە.", + "{0} desktop shortcuts created": "{0} کورتڕێی سەر مێز دروست کرا", + "UniGetUI has detected {0} new desktop shortcuts that can be deleted automatically.": "UniGetUI {0} کورتڕێی نوێی سەر مێزی دۆزییەوە کە دەتوانرێت بە شێوەی خۆکار بسڕدرێنەوە.", + "Attention required": "پێویستی بە سەرنجدان هەیە", + "Restart required": "پێویستی بە دەستپێکردنەوە هەیە", + "1 update is available": "1 نوێکردنەوە بەردەستە", + "{0} updates are available": "{0} نوێکردنەوە بەردەستن", + "Everything is up to date": "هەموو شتێک نوێکراوەتەوە", + "Discover Packages": "دۆزینەوەی پاکێجەکان", + "Available Updates": "نوێکردنەوە بەردەستەکان", + "Installed Packages": "پاکێجە دامەزراوەکان", + "UniGetUI Version {0} by Devolutions": "وەشانی UniGetUI {0} لەلایەن Devolutions", + "Show UniGetUI": "UniGetUI پیشان بدە", + "Quit": "دەرچوون", + "Are you sure?": "دڵنیایت؟", + "Do you really want to uninstall {0}?": "بەڕاستی دەتەوێت {0} بسڕیتەوە؟", + "Do you really want to uninstall the following {0} packages?": "بەڕاستی دەتەوێت ئەم {0} پاکێجەی خوارەوە بسڕیتەوە؟", + "No": "نەخێر", + "Yes": "بەڵێ", + "Partial": "پارچەیی", + "View on UniGetUI": "لە UniGetUI بیبینە", + "Update": "نوێی بکەرەوە", + "Open UniGetUI": "UniGetUI بکەرەوە", + "Update all": "هەمووی نوێ بکەرەوە", + "Update now": "ئێستا نوێی بکەرەوە", + "Installer host changed since the installed version.\n": "خانەخوێی دامەزرێنەرەکە لە دوای وەشانی دامەزراوەوە گۆڕاوە.\n", + "This package is on the queue": "ئەم پاکێجە لە ڕیزدایە", + "installing": "لە دامەزراندندایە", + "updating": "لە نوێکردنەوەدایە", + "uninstalling": "لە سڕینەوەدایە", + "installed": "دامەزراوە", + "Retry": "دووبارە هەوڵبدەوە", + "Install": "دامەزرێنە", + "Uninstall": "بسڕەوە", + "Open": "بیکەرەوە", + "Operation profile:": "پرۆفایلی کردار:", + "Follow the default options when installing, upgrading or uninstalling this package": "لە دامەزراندن، نوێکردنەوە یان سڕینەوەی ئەم پاکێجەدا هەڵبژاردە بنەڕەتییەکان بەکاربهێنە", + "The following settings will be applied each time this package is installed, updated or removed.": "ئەم ڕێکخستنانەی خوارەوە هەموو جارێک کە ئەم پاکێجە دادەمەزرێت، نوێ دەکرێتەوە یان لادەبرێت جێبەجێ دەکرێن.", + "Version to install:": "وەشانی بۆ دامەزراندن:", + "Architecture to install:": "مەعماری بۆ دامەزراندن:", + "Installation scope:": "مەودای دامەزراندن:", + "Install location:": "شوێنی دامەزراندن:", + "Select": "هەڵبژێرە", + "Reset": "ڕێکبخەرەوە", + "Custom install arguments:": "ئارگومێنتی تایبەتی دامەزراندن:", + "Custom update arguments:": "ئارگومێنتی تایبەتی نوێکردنەوە:", + "Custom uninstall arguments:": "ئارگومێنتی تایبەتی سڕینەوە:", + "Pre-install command:": "فەرمانی پێش دامەزراندن:", + "Post-install command:": "فەرمانی دوای دامەزراندن:", + "Abort install if pre-install command fails": "ئەگەر فەرمانی پێش دامەزراندن شکستی هێنا، دامەزراندن بوەستێنە", + "Pre-update command:": "فەرمانی پێش نوێکردنەوە:", + "Post-update command:": "فەرمانی دوای نوێکردنەوە:", + "Abort update if pre-update command fails": "ئەگەر فەرمانی پێش نوێکردنەوە شکستی هێنا، نوێکردنەوە بوەستێنە", + "Pre-uninstall command:": "فەرمانی پێش سڕینەوە:", + "Post-uninstall command:": "فەرمانی دوای سڕینەوە:", + "Abort uninstall if pre-uninstall command fails": "ئەگەر فەرمانی پێش سڕینەوە شکستی هێنا، سڕینەوە بوەستێنە", + "Command-line to run:": "هێڵی فەرمان بۆ جێبەجێکردن:", + "Save and close": "پاشەکەوت بکە و دایبخە", + "General": "گشتی", + "Architecture & Location": "مەعماری و شوێن", + "Command-line": "هێڵی فەرمان", + "Close apps": "ئەپەکان دابخە", + "Pre/Post install": "پێش/دوای دامەزراندن", + "Select the processes that should be closed before this package is installed, updated or uninstalled.": "ئەو پرۆسەسانە هەڵبژێرە کە دەبێت پێش دامەزراندن، نوێکردنەوە یان لابردنی ئەم پاکێجە دابخرێن.", + "Write here the process names here, separated by commas (,)": "ناوەکانی پرۆسەسەکان لێرە بنووسە، بە ویرگول (,) لێک جیاکراونەتەوە", + "Try to kill the processes that refuse to close when requested to": "هەوڵ بدە ئەو پرۆسەسانە بکوژیت کە کاتێک داوای لێدەکرێت دابخرێن ڕەت دەکەن", + "Run as admin": "وەک بەڕێوەبەر بیخەرە کار", + "Interactive installation": "دامەزراندنی کارلێککار", + "Skip hash check": "پشکنینی hash پشتگوێ بخە", + "Uninstall previous versions when updated": "کاتی نوێکردنەوە وەشانەکانی پێشوو بسڕەوە", + "Skip minor updates for this package": "نوێکردنەوە بچووکەکانی ئەم پاکێجە پشتگوێ بخە", + "Automatically update this package": "ئەم پاکێجە بە شێوەی خۆکار نوێ بکەرەوە", + "{0} installation options": "هەڵبژاردەکانی دامەزراندنی {0}", + "Latest": "دواین", + "PreRelease": "پێش-بڵاوکردنەوە", + "Default": "بنەڕەتی", + "Manage ignored updates": "بەڕێوەبردنی نوێکردنەوە پشتگوێخراوەکان", + "The packages listed here won't be taken in account when checking for updates. Double-click them or click the button on their right to stop ignoring their updates.": "ئەو پاکێجانەی لێرە لیست کراون لە کاتی پشکنینی نوێکردنەوەدا لەبەرچاو ناگیرێن. دووجار لەسەریان کلیک بکە یان لە دوگمەی لای ڕاستیان کلیک بکە بۆ وەستاندنی پشتگوێخستنی نوێکردنەوەکانیان.", + "Reset list": "لیستەکە ڕێکبخەرەوە", + "Do you really want to reset the ignored updates list? This action cannot be reverted": "بەڕاستی دەتەوێت لیستی نوێکردنەوە پشتگوێخراوەکان ڕێکبخەیتەوە؟ ئەم کردارە ناگەڕێتەوە", + "No ignored updates": "هیچ نوێکردنەوەیەک پشتگوێ نەخراوە", + "Package Name": "ناوی پاکێج", + "Package ID": "IDی پاکێج", + "Ignored version": "وەشانی پشتگوێخراو", + "New version": "وەشانی نوێ", + "Source": "سەرچاوە", + "All versions": "هەموو وەشانەکان", + "Unknown": "نادیار", + "Up to date": "تا دواین وەشانە", + "Package {name} from {manager}": "پاکێجی {name} لە {manager}", + "Remove {0} from ignored updates": "{0} لە نوێکردنەوە پشتگوێخراوەکان لاببە", + "Cancel": "هەڵوەشاندنەوە", + "Administrator privileges": "دەسەڵاتەکانی بەڕێوەبەر", + "This operation is running with administrator privileges.": "ئەم کردارە بە دەسەڵاتەکانی بەڕێوەبەر جێبەجێ دەکرێت.", + "Interactive operation": "کرداری کارلێککار", + "This operation is running interactively.": "ئەم کردارە بە شێوەی کارلێککار جێبەجێ دەکرێت.", + "You will likely need to interact with the installer.": "زۆرەوە پێویستت دەبێت لەگەڵ دامەزرێنەرەکە کارلێک بکەیت.", + "Integrity checks skipped": "پشکنینەکانی تەواویێتی پشتگوێ خران", + "Integrity checks will not be performed during this operation.": "لە ماوەی ئەم کردارەدا پشکنینەکانی تەواویێتی ئەنجام نادرێن.", + "Proceed at your own risk.": "بە مەترسیی خۆت بەردەوام بە.", + "Close": "دایبخە", + "Loading...": "باردەکرێت...", + "Installer SHA256": "SHA256ی دامەزرێنەر", + "Homepage": "ماڵپەڕی سەرەکی", + "Author": "نووسەر", + "Publisher": "بڵاوکەرەوە", + "License": "مۆڵەتنامە", + "Manifest": "مانیفێست", + "Installer Type": "جۆری دامەزرێنەر", + "Size": "قەبارە", + "Installer URL": "بەستەری دامەزرێنەر", + "Last updated:": "دوایین نوێکردنەوە:", + "Release notes URL": "بەستەری تێبینییەکانی وەشاندن", + "Package details": "وردەکارییەکانی پاکێج", + "Dependencies:": "پێویستییەکان:", + "Release notes": "تێبینییەکانی وەشاندن", + "Screenshots": "وێنەکانی شاشە", + "This package has no screenshots or is missing the icon? Contribute to UniGetUI by adding the missing icons and screenshots to our open, public database.": "ئەم پاکێجە هیچ وێنەی شاشەی نییە یان ئایکۆنەکەی ونە؟ بە زیادکردنی ئایکۆن و وێنەی شاشەی ونبوو بۆ بنکەدراوە کراوە و گشتییەکەمان، بەشداری لە UniGetUI بکە.", + "Version": "وەشان", + "Install as administrator": "وەک بەڕێوەبەری سیستەم دابمەزرێنە", + "Update to version {0}": "بۆ وەشانی {0} نوێ بکەرەوە", + "Installed Version": "وەشانی دامەزراو", + "Update as administrator": "وەک بەڕێوەبەری سیستەم نوێ بکەرەوە", + "Interactive update": "نوێکردنەوەی کارلێککارانە", + "Uninstall as administrator": "وەک بەڕێوەبەری سیستەم بیسڕەوە", + "Interactive uninstall": "سڕینەوەی کارلێککارانە", + "Uninstall and remove data": "بیسڕەوە و داتاکەش لاببە", + "Not available": "بەردەست نییە", + "Installer SHA512": "SHA512ی دامەزرێنەر", + "Unknown size": "قەبارە نەزانراوە", + "No dependencies specified": "هیچ پێویستییەک دیاری نەکراوە", + "mandatory": "پێویست", + "optional": "ئیختیاری", + "UniGetUI {0} is ready to be installed.": "UniGetUI {0} ئامادەیە بۆ دامەزراندن.", + "The update process will start after closing UniGetUI": "پرۆسەی نوێکردنەوەکە دوای داخستنی UniGetUI دەست پێ دەکات", + "UniGetUI has been ran as administrator, which is not recommended. When running UniGetUI as administrator, EVERY operation launched from UniGetUI will have administrator privileges. You can still use the program, but we highly recommend not running UniGetUI with administrator privileges.": "UniGetUI وەک بەڕێوەبەری سیستەم کارپێکراوە، کە پێشنیار ناکرێت. کاتێک UniGetUI وەک بەڕێوەبەری سیستەم کار پێدەکات، هەموو کردارێک کە لە UniGetUI دەست پێ دەکرێت دەسەڵاتی بەڕێوەبەری سیستەمی دەبێت. دەتوانیت هێشتا بەرنامەکە بەکاربهێنیت، بەڵام بە توندی پێشنیار دەکەین UniGetUI بە دەسەڵاتی بەڕێوەبەری سیستەم مەخەنە کار.", + "Share anonymous usage data": "داتای بەکارهێنانی نەناسراو هاوبەش بکە", + "UniGetUI collects anonymous usage data in order to improve the user experience.": "UniGetUI داتای بەکارهێنانی نەناسراو کۆدەکاتەوە بۆ باشترکردنی ئەزموونی بەکارهێنەر.", + "Accept": "قبووڵ بکە", + "Software Updates": "نوێکردنەوەکانی نەرمەکاڵا", + "Package Bundles": "باندڵەکانی پاکێج", + "Settings": "ڕێکخستنەکان", + "Package Managers": "بەڕێوەبەرانی پاکێج", + "UniGetUI Log": "تۆماری UniGetUI", + "Package Manager logs": "تۆمارەکانی بەڕێوەبەری پاکێج", + "Operation history": "مێژووی کردارەکان", + "Help": "یارمەتی", + "UniGetUI": "UniGetUI", + "You have installed UniGetUI Version {0}": "UniGetUI وەشانی {0}ت دامەزراندووە", + "Disclaimer": "ئاگادارکردنەوە", + "UniGetUI is developed by Devolutions and is not affiliated with any of the compatible package managers.": "UniGetUI لەلایەن Devolutions پەرەپێدراوە و پەیوەندیی بە هیچ یەکێک لە بەڕێوەبەرانی پاکێجی هاوگونجاوەوە نییە.", + "UniGetUI wouldn't have been possible without the help of the contributors. Thank you all 🥳": "UniGetUI بەبێ یارمەتی بەشداران بوونی نەدەبوو. سوپاسی هەمووتان 🥳", + "UniGetUI uses the following libraries. Without them, UniGetUI wouldn't have been possible.": "UniGetUI ئەم کتێبخانانەی خوارەوە بەکاردەهێنێت. بەبێ ئەوان، UniGetUI نەدەکرا.", + "{0} homepage": "ماڵپەڕی سەرەکی {0}", + "UniGetUI has been translated to more than 40 languages thanks to the volunteer translators. Thank you 🤝": "UniGetUI بۆ زیاتر لە 40 زمان وەرگێڕدراوە بە هۆی وەرگێڕانی خۆبەخشانەوە. سوپاس 🤝", + "Verbose": "ورد", + "1 - Errors": "1 - هەڵەکان", + "2 - Warnings": "2 - ئاگادارکردنەوەکان", + "3 - Information (less)": "3 - زانیاری (کەمتر)", + "4 - Information (more)": "4 - زانیاری (زیاتر)", + "5 - information (debug)": "5 - زانیاری (دیباگ)", + "Warning": "ئاگادارکردنەوە", + "The following settings may pose a security risk, hence they are disabled by default.": "ڕێکخستنەکانی خوارەوە لەوانەیە مەترسییەکی ئاسایشی دروست بکەن، بۆیە بە شێوەی بنەڕەتی ناچالاکن.", + "Enable the settings below if and only if you fully understand what they do, and the implications they may have.": "تەنها ئەوکات ڕێکخستنەکانی خوارەوە چالاک بکە کە بە تەواوی تێدەگەیت چی دەکەن و چی لێی دەکەوێتەوە.", + "The settings will list, in their descriptions, the potential security issues they may have.": "لە وەسفەکانیاندا، ڕێکخستنەکان کێشە ئاسایشییە ئەگەرییەکانی خۆیان باس دەکەن.", + "The backup will include the complete list of the installed packages and their installation options. Ignored updates and skipped versions will also be saved.": "پاڵپشتییەکە لیستی تەواوی پاکێجە دامەزراوەکان و هەڵبژاردەکانی دامەزراندنیان لەخۆ دەگرێت. نوێکردنەوە پشتگوێخراوەکان و وەشانە بازدراوەکانیش هەڵدەگیرێن.", + "The backup will NOT include any binary file nor any program's saved data.": "پاڵپشتییەکە هیچ پەڕگەی باینەری یان هیچ داتای هەڵگیراوی بەرنامەیەک لەخۆ ناگرێت.", + "The size of the backup is estimated to be less than 1MB.": "پێشبینی دەکرێت قەبارەی پاڵپشتییەکە لە 1MB کەمتر بێت.", + "The backup will be performed after login.": "پاڵپشتییەکە دوای چوونەژوورەوە ئەنجام دەدرێت.", + "{pcName} installed packages": "پاکێجە دامەزراوەکانی {pcName}", + "Current status: Not logged in": "دۆخی ئێستا: نەچووە ژوورەوە", + "You are logged in as {0} (@{1})": "وەک {0} (@{1}) چوویتە ژوورەوە", + "Nice! Backups will be uploaded to a private gist on your account": "باشە! پاڵپشتییەکان بۆ gistێکی تایبەت لە هەژمارەکەت بار دەکرێن", + "Select backup": "پاڵپشتی هەڵبژێرە", + "Settings imported from {0}": "ڕێکخستنەکان لە {0} هاوردە کران", + "UniGetUI Settings": "ڕێکخستنەکانی UniGetUI", + "Settings exported to {0}": "ڕێکخستنەکان بۆ {0} هەناردە کران", + "UniGetUI settings were reset": "ڕێکخستنەکانی UniGetUI ڕێکخرایەوە", + "Allow pre-release versions": "ڕێگە بدە بە وەشانەکانی پێش بڵاوکردنەوە", + "Apply": "جێبەجێ بکە", + "For security reasons, custom command-line arguments are disabled by default. Go to UniGetUI security settings to change this.": "بەهۆی هۆکاری ئاسایشییەوە، ئارگیومێنتی هێڵی فەرمانی تایبەت بە شێوەی بنەڕەتی ناچالاکە. بۆ گۆڕینی ئەمە بچۆ بۆ ڕێکخستنە ئاسایشییەکانی UniGetUI.", + "Go to UniGetUI security settings": "بچۆ بۆ ڕێکخستنە ئاسایشییەکانی UniGetUI", + "The following options will be applied by default each time a {0} package is installed, upgraded or uninstalled.": "هەڵبژاردەکانی خوارەوە بە شێوەی بنەڕەتی هەر کاتێک پاکێجێکی {0} دادەمەزرێت، نوێ دەکرێتەوە یان دەسڕدرێتەوە جێبەجێ دەکرێن.", + "Package's default": "بنەڕەتی پاکێج", + "Install location can't be changed for {0} packages": "شوێنی دامەزراندن بۆ پاکێجەکانی {0} ناگۆڕدرێت", + "The local icon cache currently takes {0} MB": "کاشی ئایکۆنی ناوخۆیی لە ئێستادا {0} MB جێگا دەگرێت", + "Username": "ناوی بەکارهێنەر", + "Password": "وشەی نهێنی", + "Credentials": "بڕوانامەکان", + "It is not guaranteed that the provided credentials will be stored safely": "دڵنیایی نییە بڕوانامە دابینکراوەکان بە ئاسایشی هەڵبگیرێن", + "Partially": "بەشێک", + "Package manager": "بەڕێوەبەری پاکێج", + "Compatible with proxy": "لەگەڵ proxy گونجاوە", + "Compatible with authentication": "لەگەڵ پشتڕاستکردنەوە گونجاوە", + "Proxy compatibility table": "خشتەی گونجانی proxy", + "{0} settings": "ڕێکخستنەکانی {0}", + "{0} status": "دۆخی {0}", + "Default installation options for {0} packages": "هەڵبژاردە بنەڕەتییەکانی دامەزراندن بۆ پاکێجەکانی {0}", + "Expand version": "وەشان فراوان بکە", + "The executable file for {0} was not found": "پەڕگەی جێبەجێکراوی {0} نەدۆزرایەوە", + "{pm} is disabled": "{pm} ناچالاکە", + "Enable it to install packages from {pm}.": "بۆ دامەزراندنی پاکێج لە {pm}، چالاکی بکە.", + "{pm} is enabled and ready to go": "{pm} چالاکە و ئامادەی کارکردنە", + "{pm} version:": "وەشانی {pm}:", + "{pm} was not found!": "{pm} نەدۆزرایەوە!", + "You may need to install {pm} in order to use it with UniGetUI.": "لەوانەیە پێویست بێت {pm} دابمەزرێنیت بۆ ئەوەی لەگەڵ UniGetUI بەکاریبهێنیت.", + "Scoop Installer - UniGetUI": "دامەزرێنەری Scoop - UniGetUI", + "Scoop Uninstaller - UniGetUI": "سڕەرەوەی Scoop - UniGetUI", + "Clearing Scoop cache - UniGetUI": "پاککردنەوەی کاشی Scoop - UniGetUI", + "Restart UniGetUI to fully apply changes": "UniGetUI دووبارە دەست پێ بکەرەوە بۆ جێبەجێکردنی تەواوی گۆڕانکارییەکان", + "Restart UniGetUI": "UniGetUI دووبارە دەست پێ بکەرەوە", + "Manage {0} sources": "سەرچاوەکانی {0} بەڕێوەبەرە", + "Add source": "سەرچاوە زیاد بکە", + "Add": "زیاد بکە", + "Source name": "ناوی سەرچاوە", + "Source URL": "بەستەری سەرچاوە", + "Other": "تر", + "No minimum age": "هیچ کەمترین ماوەیەک نییە", + "1 day": "1 ڕۆژ", + "{0} days": "{0} ڕۆژ", + "Custom...": "تایبەت...", + "{0} minutes": "{0} خولەک", + "1 hour": "یەک کاتژمێر", + "{0} hours": "{0} کاتژمێر", + "1 week": "1 هەفتە", + "Supports release dates": "پشتیوانی لە بەرواری بڵاوکردنەوە دەکات", + "Release date support per package manager": "پشتیوانی بەرواری بڵاوکردنەوە بەپێی بەڕێوەبەری پاکێج", + "Search for packages": "بگەڕێ بۆ پاکێجەکان", + "Local": "ناوخۆیی", + "OK": "OK", + "Last checked: {0}": "دوایین پشکنین: {0}", + "{0} packages were found, {1} of which match the specified filters.": "{0} پاکێج دۆزرایەوە، {1}یان لەوانە لەگەڵ فلتەرە دیاریکراوەکان دەگونجێن.", + "{0} selected": "{0} هەڵبژێردراو", + "(Last checked: {0})": "(دوایین پشکنین: {0})", + "All packages selected": "هەموو پاکێجەکان هەڵبژێردران", + "Package selection cleared": "هەڵبژاردنی پاکێج پاککرایەوە", + "{0}: {1}": "{0}: {1}", + "More info": "زانیاری زیاتر", + "GitHub account": "هەژماری GitHub", + "Log in with GitHub to enable cloud package backup.": "بۆ چالاککردنی پاڵپشتی پاکێجی هەور، بە GitHub بچۆ ژوورەوە.", + "More details": "وردەکاری زیاتر", + "Log in": "چوونەژوورەوە", + "If you have cloud backup enabled, it will be saved as a GitHub Gist on this account": "ئەگەر پاڵپشتی هەورەت چالاک کردبێت، وەک GitHub Gistێک لەم هەژمارەدا پاشەکەوت دەکرێت", + "Log out": "چوونەدەرەوە", + "About UniGetUI": "دەربارەی UniGetUI", + "About": "دەربارە", + "Third-party licenses": "مۆڵەتنامەکانی لایەنی سێیەم", + "Contributors": "بەشداربووان", + "Translators": "وەرگێڕان", + "Bundle security report": "ڕاپۆرتی ئاسایشی باندڵ", + "The bundle contained restricted content": "باندڵەکە ناوەڕۆکی سنووردار لەخۆ دەگرت", + "UniGetUI – Crash Report": "UniGetUI – ڕاپۆرتی تێکشکان", + "UniGetUI has crashed": "UniGetUI تێکشکا", + "Help us fix this by sending a crash report to Devolutions. All fields below are optional.": "یارمەتیمان بدە ئەمە چاکبکەینەوە بە ناردنی ڕاپۆرتی تێکشکان بۆ Devolutions. هەموو خانەکانی خوارەوە دڵخوازانەن.", + "Email (optional)": "ئیمەیل (دڵخوازانە)", + "your@email.com": "your@email.com", + "Additional details (optional)": "وردەکاری زیاتر (دڵخوازانە)", + "Describe what you were doing when the crash occurred…": "باسی ئەوە بکە چیت دەکرد کاتێک تێکشکانەکە ڕوویدا…", + "Crash report": "ڕاپۆرتی تێکشکان", + "Don't Send": "مەینێرە", + "Send Report": "ڕاپۆرتەکە بنێرە", + "Sending…": "دەنێردرێت…", + "Unsaved changes": "گۆڕانکارییە پاشەکەوت نەکراوەکان", + "You have unsaved changes in the current bundle. Do you want to discard them?": "لە باندڵی ئێستادا گۆڕانکارییە پاشەکەوت نەکراوت هەن. دەتەوێت فڕێیان بدەیت؟", + "Discard changes": "گۆڕانکارییەکان فڕێ بدە", + "Integrity violation": "پێشێلکردنی تەواویێتی", + "UniGetUI or some of its components are missing or corrupt. It is strongly recommended to reinstall UniGetUI to adress the situation.": "UniGetUI یان هەندێک لە پێکهاتەکانی ونن یان تێکچوون. بە توندی پێشنیار دەکرێت بۆ چارەسەرکردنی ئەم دۆخە UniGetUI دووبارە دابمەزرێنیت.", + "• Refer to the UniGetUI Logs to get more details regarding the affected file(s)": "• بگەڕێوە بۆ تۆمارەکانی UniGetUI بۆ بەدەستهێنانی وردەکاریی زیاتر سەبارەت بە پەڕگە زیانلێکەوتووەکان", + "• Integrity checks can be disabled from the Experimental Settings": "• پشکنینەکانی integrity دەتوانرێن لە ڕێکخستنە ئەزموونییەکان ناچالاک بکرێن", + "Manage shortcuts": "بەڕێوەبردنی ڕێگاکورتەکان", + "UniGetUI has detected the following desktop shortcuts which can be removed automatically on future upgrades": "UniGetUI ئەم ڕێگاکورتانەی خوارەوەی دۆزییەوە کە دەتوانرێت لە نوێکردنەوەکانی داهاتوودا بە شێوەی خۆکار بسڕدرێنەوە", + "Do you really want to reset this list? This action cannot be reverted.": "ئایا بە ڕاستی دەتەوێت ئەم لیستە بگەڕێنیتەوە بۆ دۆخی بنەڕەتی؟ ئەم کردارە ناگەڕێندرێتەوە.", + "Desktop shortcuts list": "لیستی کورتڕێکانی سەر مێز", + "Open in explorer": "لە Explorer بکەرەوە", + "Remove from list": "لە لیستەکە لای ببە", + "When new shortcuts are detected, delete them automatically instead of showing this dialog.": "کاتێک ڕێگاکورتەی نوێ دۆزرایەوە، لەبری پیشاندانی ئەم دیالۆگە، بە شێوەی خۆکار بیسڕەوە.", + "Not right now": "ئێستا نا", + "Missing dependency": "پێداویستی ونبوو", + "UniGetUI requires {0} to operate, but it was not found on your system.": "UniGetUI بۆ کارکردن پێویستی بە {0} هەیە، بەڵام لە سیستەمەکەتدا نەدۆزرایەوە.", + "Click on Install to begin the installation process. If you skip the installation, UniGetUI may not work as expected.": "بۆ دەستپێکردنی پرۆسەی دامەزراندن لە Install بکە. ئەگەر دامەزراندنەکە بازبدەیت، لەوانەیە UniGetUI وەک چاوەڕوانکراو کار نەکات.", + "Alternatively, you can also install {0} by running the following command in a Windows PowerShell prompt:": "بە شێوەیەکی تر، دەتوانیت {0} ـیش دابمەزرێنیت بە ڕاکردنی ئەم فرمانە لە ناو prompt ـێکی Windows PowerShell:", + "Install {0}": "{0} دابمەزرێنە", + "Do not show this dialog again for {0}": "ئەم دیالۆگە بۆ {0} جارێکی تر پیشان مەدە", + "Please wait while {0} is being installed. A black window may show up. Please wait until it closes.": "تکایە چاوەڕێ بکە تا {0} دادەمەزرێت. لەوانەیە پەنجەرەیەکی ڕەش یان شین دەرکەوێت. تکایە چاوەڕێ بکە تا دادەخرێت.", + "{0} has been installed successfully.": "{0} بە سەرکەوتوویی دامەزرا.", + "Please click on \"Continue\" to continue": "تکایە بۆ بەردەوامبوون لە \"Continue\" بکە", + "Continue": "بەردەوام بە", + "{0} has been installed successfully. It is recommended to restart UniGetUI to finish the installation": "{0} بە سەرکەوتوویی دامەزرا. پێشنیار دەکرێت UniGetUI دووبارە دەست پێ بکەیت بۆ تەواوکردنی دامەزراندن", + "Restart later": "دواتر دووبارە دەست پێ بکە", + "An error occurred:": "هەڵەیەک ڕوویدا:", + "Please see the Command-line Output or refer to the Operation History for further information about the issue.": "تکایە دەرهاویشتەی هێڵی فرمان ببینە یان بگەڕێوە بۆ مێژووی کردارەکان بۆ زانیاریی زیاتر سەبارەت بە کێشەکە.", + "Retry as administrator": "وەک بەڕێوەبەر دووبارە هەوڵ بدەوە", + "Retry interactively": "بە شێوەی کارلێککارانە دووبارە هەوڵ بدەوە", + "Retry skipping integrity checks": "بە بازدان لە پشکنینەکانی integrity دووبارە هەوڵ بدەوە", + "Installation options": "هەڵبژاردەکانی دامەزراندن", + "Save": "پاشەکەوتی بکە", + "UniGetUI collects anonymous usage data with the sole purpose of understanding and improving the user experience.": "UniGetUI داتای بەکارهێنانی نەناسراو تەنها بۆ تێگەیشتن و باشترکردنی ئەزموونی بەکارهێنەر کۆدەکاتەوە.", + "More details about the shared data and how it will be processed": "وردەکاری زیاتر دەربارەی داتای هاوبەشکراو و چۆنیەتی پرۆسەکردنی", + "Do you accept that UniGetUI collects and sends anonymous usage statistics, with the sole purpose of understanding and improving the user experience?": "ئایا قبووڵ دەکەیت UniGetUI ئامارە نەناسراوەکانی بەکارهێنان کۆبکاتەوە و بنێرێت، تەنها بۆ تێگەیشتن و باشترکردنی ئەزموونی بەکارهێنەر؟", + "Decline": "ڕەتکردنەوە", + "No personal information is collected nor sent, and the collected data is anonimized, so it can't be back-tracked to you.": "هیچ زانیارییەکی کەسی نە کۆدەکرێتەوە و نە دەنێردرێت، و داتای کۆکراوەش نەناسێندراوە، بۆیە ناتوانرێت بگەڕێندرێتەوە بۆ تۆ.", + "Navigation panel": "پانێلی ڕێنیشاندان", + "Operations": "کردارەکان", + "Toggle operations panel": "پانێلی کردارەکان پیشان بدە/بیشارەوە", + "Bulk operations": "کردارە کۆمەڵییەکان", + "Retry failed": "دووبارە هەوڵی شکستخواردووەکان بدەوە", + "Clear successful": "سەرکەوتووەکان پاک بکەرەوە", + "Clear finished": "تەواوبووەکان پاک بکەرەوە", + "Cancel all": "هەموو هەڵبوەشێنەوە", + "More": "زیاتر", + "Toggle navigation panel": "پانێڵی گەشتکردن بگۆڕە", + "Minimize": "بچووککردنەوە", + "Maximize": "گەورەکردنەوە", + "UniGetUI by Devolutions": "UniGetUI لەلایەن Devolutions", + "UniGetUI is an application that makes managing your software easier, by providing an all-in-one graphical interface for your command-line package managers.": "UniGetUI بەرنامەیەکە کە بەڕێوەبردنی نەرمەکاڵاکەت ئاسانتر دەکات، بە دابینکردنی ڕووکارێکی گرافیکی هەمووی لە یەکدا بۆ بەڕێوەبەرانی پاکێجی هێڵی فەرمانەکەت.", + "Useful links": "بەستەرە بەسوودەکان", + "UniGetUI Homepage": "ماڵپەڕی سەرەکی UniGetUI", + "Report an issue or submit a feature request": "کێشەیەک ڕاپۆرت بکە یان داواکاری تایبەتمەندییەک بنێرە", + "UniGetUI Repository": "ڕێپووزیتۆری UniGetUI", + "View GitHub Profile": "پڕۆفایلی GitHub ببینە", + "UniGetUI License": "مۆڵەتنامەی UniGetUI", + "Using UniGetUI implies the acceptation of the MIT License": "بەکارهێنانی UniGetUI واتای قبووڵکردنی مۆڵەتنامەی MITیە", + "Become a translator": "ببە بە وەرگێڕ", + "Go back": "بگەڕێوە دواوە", + "Go forward": "بڕۆ بۆ پێشەوە", + "Go to home page": "بڕۆ بۆ پەڕەی سەرەتایی", + "Reload page": "پەڕەکە بارکەرەوە", + "View page on browser": "لاپەڕەکە لە وێبگەڕدا ببینە", + "The built-in browser is not supported on Linux yet.": "وێبگەڕی ناوخۆ هێشتا لەسەر Linux پشتگیری ناکرێت.", + "Open in browser": "لە وێبگەڕدا بکەرەوە", + "Copy to clipboard": "کۆپی بکە بۆ کلیپبۆرد", + "Export to a file": "هەناردە بکە بۆ پەڕگەیەک", + "Log level:": "ئاستی تۆمار:", + "Reload log": "تۆمار دووبارە بار بکە", + "Export log": "تۆمار هەناردە بکە", + "Text": "دەق", + "Change how operations request administrator rights": "چۆنیەتی داواکاری مافی بەڕێوەبەری سیستەم بۆ کردارەکان بگۆڕە", + "Restrictions on package operations": "سنووردارکردن لەسەر کردارەکانی پاکێج", + "Restrictions on package managers": "سنووردارکردن لەسەر بەڕێوەبەرانی پاکێج", + "Restrictions when importing package bundles": "سنووردارکردن لە کاتی هاوردەکردنی کۆمەڵە پاکێجەکان", + "Ask for administrator privileges once for each batch of operations": "بۆ هەر کۆمەڵە کردارێک یەکجار داوای مافەکانی بەڕێوەبەری سیستەم بکە", + "Ask only once for administrator privileges": "تەنها یەکجار داوای مافەکانی بەڕێوەبەری سیستەم بکە", + "Prohibit any kind of Elevation via UniGetUI Elevator or GSudo": "هەموو جۆرێک لە بەرزکردنەوەی دەسەڵات لە ڕێگەی UniGetUI Elevator یان GSudo قەدەغە بکە", + "This option WILL cause issues. Any operation incapable of elevating itself WILL FAIL. Install/update/uninstall as administrator will NOT WORK.": "ئەم هەڵبژاردەیە بە دڵنیایی کێشە دروست دەکات. هەر کردارێک کە نەتوانێت خۆی بەرز بکاتەوە سەرناکەوێت. دامەزراندن/نوێکردنەوە/سڕینەوە وەک بەڕێوەبەری سیستەم کار ناکات.", + "Allow custom command-line arguments": "ڕێگە بدە بە ئارگیومێنتە تایبەتییەکانی هێڵی فەرمان", + "Custom command-line arguments can change the way in which programs are installed, upgraded or uninstalled, in a way UniGetUI cannot control. Using custom command-lines can break packages. Proceed with caution.": "ئارگیومێنتە تایبەتییەکانی هێڵی فەرمان دەتوانن شێوازی دامەزراندن، نوێکردنەوە یان سڕینەوەی بەرنامەکان بگۆڕن بە شێوەیەک کە UniGetUI ناتوانێت کۆنترۆڵی بکات. بەکارهێنانی هێڵی فەرمانی تایبەت دەتوانێت پاکێجەکان تێک بدات. بە وریاییەوە بەردەوام بە.", + "Ignore custom pre-install and post-install commands when importing packages from a bundle": "لە کاتی هاوردەکردنی پاکێج لە باندڵێک، فەرمانە تایبەتییەکانی پێش دامەزراندن و دوای دامەزراندن پشتگوێ بخە", + "Pre and post install commands will be run before and after a package gets installed, upgraded or uninstalled. Be aware that they may break things unless used carefully": "فەرمانەکانی پێش دامەزراندن و دوای دامەزراندن پێش و دوای ئەوەی پاکێجێک دابمەزرێت، نوێ بکرێتەوە یان بسڕدرێتەوە جێبەجێ دەکرێن. ئاگاداربە چونکە ئەگەر بە وریایی بەکارنەهێنرێن لەوانەیە شت تێک بدەن", + "Allow changing the paths for package manager executables": "ڕێگە بدە بە گۆڕینی ڕێڕەوی پەڕگە جێبەجێکراوەکانی بەڕێوەبەری پاکێج", + "Turning this on enables changing the executable file used to interact with package managers. While this allows finer-grained customization of your install processes, it may also be dangerous": "چالاککردنی ئەمە ڕێگە بە گۆڕینی پەڕگەی جێبەجێکراو دەدات کە بۆ کارلێککردن لەگەڵ بەڕێوەبەرانی پاکێج بەکاردێت. هەرچەندە ئەمە ڕێکخستنی وردتر بۆ پرۆسەکانی دامەزراندنت دابین دەکات، بەڵام دەتوانێت مەترسیداریش بێت", + "Allow importing custom command-line arguments when importing packages from a bundle": "ڕێگە بدە بە هاوردەکردنی ئارگیومێنتە تایبەتییەکانی هێڵی فەرمان لە کاتی هاوردەکردنی پاکێجەکان لە باندڵێک", + "Malformed command-line arguments can break packages, or even allow a malicious actor to gain privileged execution. Therefore, importing custom command-line arguments is disabled by default": "ئارگیومێنتە نادروستەکانی هێڵی فەرمان دەتوانن پاکێجەکان تێک بدەن، یان تەنانەت ڕێگە بدەن کە کەسێکی خراپکار دەسەڵاتی تایبەت وەربگرێت. بۆیە، هاوردەکردنی ئارگیومێنتە تایبەتییەکانی هێڵی فەرمان بە شێوەی بنەڕەتی ناچالاککراوە.", + "Allow importing custom pre-install and post-install commands when importing packages from a bundle": "ڕێگە بدە بە هاوردەکردنی فەرمانە تایبەتییەکانی پێش دامەزراندن و دوای دامەزراندن لە کاتی هاوردەکردنی پاکێجەکان لە باندڵێک", + "Pre and post install commands can do very nasty things to your device, if designed to do so. It can be very dangerous to import the commands from a bundle, unless you trust the source of that package bundle": "فەرمانەکانی پێش دامەزراندن و دوای دامەزراندن ئەگەر بۆ ئەو مەبەستە دروستکرابن دەتوانن زۆر شتی خراپ بەسەر ئامێرەکەت بهێنن. هاوردەکردنی ئەو فەرمانانە لە باندڵێک زۆر مەترسیدارە، مەگەر سەرچاوەی ئەو باندڵە پاکێجە متمانەپێکراو بێت", + "Administrator rights and other dangerous settings": "مافەکانی بەڕێوەبەری سیستەم و ڕێکخستنە مەترسیدارەکانی تر", + "Package backup": "پاڵپشتی پاکێج", + "Cloud package backup": "پاڵپشتی هەوری پاکێج", + "Local package backup": "پاڵپشتی ناوخۆیی پاکێج", + "Local backup advanced options": "هەڵبژاردە پێشکەوتووەکانی پاڵپشتی ناوخۆیی", + "Log in with GitHub": "بە GitHub بچۆ ژوورەوە", + "Log out from GitHub": "لە GitHub بچۆ دەرەوە", + "Periodically perform a cloud backup of the installed packages": "بە شێوەی خولی پاڵپشتییەکی هەوری لە پاکێجە دامەزراوەکان ئەنجام بدە", + "Cloud backup uses a private GitHub Gist to store a list of installed packages": "پاڵپشتی هەور لە GitHub Gistێکی تایبەتدا لیستی پاکێجە دامەزراوەکان هەڵدەگرێت", + "Perform a cloud backup now": "ئێستا پاڵپشتییەکی هەوری ئەنجام بدە", + "Backup": "پاڵپشتی", + "Restore a backup from the cloud": "پاڵپشتییەک لە هەورەوە بگەڕێنەرەوە", + "Begin the process to select a cloud backup and review which packages to restore": "پرۆسەی هەڵبژاردنی پاڵپشتییەکی هەوری دەست پێ بکە و پشکنین بکە کام پاکێجان بگەڕێندرێنەوە", + "Periodically perform a local backup of the installed packages": "بە شێوەی خولی پاڵپشتییەکی ناوخۆیی لە پاکێجە دامەزراوەکان ئەنجام بدە", + "Perform a local backup now": "ئێستا پاڵپشتییەکی ناوخۆیی ئەنجام بدە", + "Change backup output directory": "بوخچەی دەرچوونی پاڵپشتی بگۆڕە", + "Set a custom backup file name": "ناوی پەڕگەی پاڵپشتییەکی تایبەت دابنێ", + "Leave empty for default": "بۆ بنەڕەتی بە بەتاڵی جێیبێڵە", + "Add a timestamp to the backup file names": "کاتمۆر زیاد بکە بۆ ناوەکانی پەڕگەی پاڵپشتی", + "Backup and Restore": "پاڵپشتی و گەڕاندنەوە", + "Enable background api (UniGetUI Widgets and Sharing, port 7058)": "APIی پاشبنەما چالاک بکە (ویجێتەکانی UniGetUI و هاوبەشکردن، پۆرتی 7058)", + "Wait for the device to be connected to the internet before attempting to do tasks that require internet connectivity.": "پێش هەوڵدان بۆ ئەنجامدانی ئەرکەکانێک کە پێویستییان بە پەیوەندی ئینتەرنێتە، چاوەڕێ بکە تا ئامێرەکە بە ئینتەرنێت بپەیوەستێت.", + "Disable the 1-minute timeout for package-related operations": "سنووری کاتی 1 خولەک بۆ کردارە پەیوەندیدارەکانی پاکێج ناچالاک بکە", + "Use installed GSudo instead of UniGetUI Elevator": "لەبری UniGetUI Elevator، GSudoی دامەزراو بەکاربهێنە", + "Use a custom icon and screenshot database URL": "URLێکی تایبەت بۆ بنکەدراوەی ئایکۆن و وێنەی شاشە بەکاربهێنە", + "Enable background CPU Usage optimizations (see Pull Request #3278)": "باشکردنەوەکانی بەکارهێنانی CPU لە پاشبنەما چالاک بکە (Pull Request #3278 ببینە)", + "Perform integrity checks at startup": "لە دەستپێکدا پشکنینەکانی integrity ئەنجام بدە", + "When batch installing packages from a bundle, install also packages that are already installed": "کاتێک پاکێجەکان لە باندڵێک بە کۆمەڵ دامەزرێنیت، ئەو پاکێجانەش دابمەزرێنە کە پێشتر دامەزراون", + "Experimental settings and developer options": "ڕێکخستنە ئەزموونییەکان و هەڵبژاردەکانی گەشەپێدەران", + "Show UniGetUI's version and build number on the titlebar.": "وەشانی UniGetUI و ژمارەی build لەسەر شریتی ناونیشان پیشان بدە.", + "Language": "زمان", + "UniGetUI updater": "نوێکەرەوەی UniGetUI", + "Telemetry": "تێلێمێتری", + "Manage UniGetUI settings": "ڕێکخستنەکانی UniGetUI بەڕێوەبەرە", + "Related settings": "ڕێکخستنە پەیوەندیدارەکان", + "Update UniGetUI automatically": "UniGetUI بە شێوەی خۆکار نوێ بکەرەوە", + "Check for updates": "بۆ نوێکردنەوەکان بپشکنە", + "Install prerelease versions of UniGetUI": "وەشانەکانی پێش بڵاوکردنەوەی UniGetUI دابمەزرێنە", + "Manage telemetry settings": "ڕێکخستنەکانی تێلێمێتری بەڕێوەبەرە", + "Manage": "بەڕێوەبەرە", + "Import settings from a local file": "ڕێکخستنەکان لە پەڕگەیەکی ناوخۆییەوە هاوردە بکە", + "Import": "هاوردە بکە", + "Export settings to a local file": "ڕێکخستنەکان بۆ پەڕگەیەکی ناوخۆیی هەناردە بکە", + "Export": "هەناردە بکە", + "Reset UniGetUI": "UniGetUI بگەڕێنەرەوە بۆ دۆخی بنەڕەتی", + "User interface preferences": "هەڵبژاردەکانی ڕووکارى بەکارهێنەر", + "Application theme, startup page, package icons, clear successful installs automatically": "ڕووکارى بەرنامە، لاپەڕەی دەستپێک، ئایکۆنی پاکێجەکان، پاککردنەوەی خۆکاری دامەزراندنە سەرکەوتووەکان", + "General preferences": "هەڵبژاردە گشتییەکان", + "UniGetUI display language:": "زمانی پیشاندانی UniGetUI:", + "System language": "Zimanê pergalê", + "Is your language missing or incomplete?": "ئایا زمانەکەت ونە یان تەواو نییە؟", + "Appearance": "ڕووکار", + "UniGetUI on the background and system tray": "UniGetUI لە پاشبنەما و تڕەی سیستەمدا", + "Package lists": "لیستەکانی پاکێج", + "Use classic mode": "دۆخی کلاسیکی بەکاربهێنە", + "Restart UniGetUI to apply this change": "UniGetUI دووبارە پێبکەرەوە بۆ جێبەجێکردنی ئەم گۆڕانکارییە", + "The classic UI is disabled for beta testers": "ڕووکاری کلاسیکی بەکارهێنەر بۆ تاقیکەرەوەکانی بێتا ناچالاک کراوە", + "Close UniGetUI to the system tray": "UniGetUI بۆ تڕەی سیستەم دابخە", + "Manage UniGetUI autostart behaviour": "بەڕێوەبردنی ڕەفتاری دەستپێکردنی خۆکاری UniGetUI", + "Show package icons on package lists": "ئایکۆنی پاکێجەکان لە لیستەکانی پاکێج پیشان بدە", + "Clear cache": "کاش پاک بکەرەوە", + "Select upgradable packages by default": "پاکێجە نوێکراوەتوانەکان بە شێوەی بنەڕەتی هەڵبژێرە", + "Light": "ڕووناک", + "Dark": "تاریک", + "Follow system color scheme": "دوای پلانی ڕەنگی سیستەم بکەوە", + "Application theme:": "ڕووکارى بەرنامە:", + "UniGetUI startup page:": "لاپەڕەی دەستپێکی UniGetUI:", + "Proxy settings": "ڕێکخستنەکانی proxy", + "Other settings": "ڕێکخستنەکانی تر", + "Connect the internet using a custom proxy": "بە بەکارهێنانی proxyێکی تایبەت بە ئینتەرنێت پەیوەست بە", + "Please note that not all package managers may fully support this feature": "تکایە سەرنج بدە کە هەموو بەڕێوەبەرانی پاکێج ڕەنگە بە تەواوی پشتگیری ئەم تایبەتمەندییە نەکەن", + "Proxy URL": "URLی proxy", + "Enter proxy URL here": "URLی proxy لێرە بنووسە", + "Authenticate to the proxy with a user and a password": "بە ناوی بەکارهێنەر و وشەی نهێنی بۆ proxy پشتڕاستکردنەوە بکە", + "Internet and proxy settings": "ڕێکخستنەکانی ئینتەرنێت و proxy", + "Package manager preferences": "هەڵبژاردەکانی بەڕێوەبەرانی پاکێج", + "Ready": "ئامادە", + "Not found": "نەدۆزرایەوە", + "Notification preferences": "هەڵبژاردەکانی ئاگادارکردنەوە", + "Notification types": "جۆرەکانی ئاگادارکردنەوە", + "The system tray icon must be enabled in order for notifications to work": "بۆ ئەوەی ئاگادارکردنەوەکان کار بکەن، پێویستە ئایکۆنی تڕەی سیستەم چالاک بێت", + "Enable UniGetUI notifications": "ئاگادارکردنەوەکانی UniGetUI چالاک بکە", + "Show a notification when there are available updates": "کاتێک نوێکردنەوەی بەردەست هەیە ئاگادارکردنەوەیەک پیشان بدە", + "Show a silent notification when an operation is running": "کاتێک کردارێک بەڕێوە دەچێت ئاگادارکردنەوەیەکی بێدەنگ پیشان بدە", + "Show a notification when an operation fails": "کاتێک کردارێک سەرناکەوێت ئاگادارکردنەوەیەک پیشان بدە", + "Show a notification when an operation finishes successfully": "کاتێک کردارێک بە سەرکەوتوویی تەواو دەبێت ئاگادارکردنەوەیەک پیشان بدە", + "Concurrency and execution": "هاوکاتکاری و جێبەجێکردن", + "Automatic desktop shortcut remover": "سڕەرەوەی خۆکاری ڕێگاکورتەی سەر مێز", + "Choose how many operations should be performed in parallel": "هەڵبژێرە چەند کردارێک دەبێت بە هاوکاتی ئەنجام بدرێن", + "Clear successful operations from the operation list after a 5 second delay": "کردارە سەرکەوتووەکان دوای دواکەوتنێکی 5 چرکەیی لە لیستی کردارەکان لاببە", + "Download operations are not affected by this setting": "کردارەکانی داگرتن بەم ڕێکخستنە کاریگەرییان لەسەر نابێت", + "You may lose unsaved data": "لەوانەیە داتای پاشنەکراوت لەدەست بدەیت", + "Ask to delete desktop shortcuts created during an install or upgrade.": "بۆ سڕینەوەی ڕێگاکورتە سەر مێزانەی لە کاتی دامەزراندن یان نوێکردنەوە دروستکراون داوا بکە.", + "Package update preferences": "هەڵبژاردەکانی نوێکردنەوەی پاکێج", + "Update check frequency, automatically install updates, etc.": "دووبارەبوونەوەی پشکنینی نوێکردنەوە، دامەزراندنی خۆکاری نوێکردنەوەکان، هتد.", + "Reduce UAC prompts, elevate installations by default, unlock certain dangerous features, etc.": "داواکارییەکانی UAC کەم بکەرەوە، دامەزراندنەکان بە شێوەی بنەڕەتی بەرز بکەرەوە، هەندێک تایبەتمەندی مەترسیدار بکەرەوە، هتد.", + "Package operation preferences": "هەڵبژاردەکانی کردارەکانی پاکێج", + "Enable {pm}": "{pm} چالاک بکە", + "Not finding the file you are looking for? Make sure it has been added to path.": "پەڕگەکەی بەدوایدا دەگەڕێیت نادۆزیتەوە؟ دڵنیابە کە زیاد کراوە بۆ path.", + "Select the executable to be used. The following list shows the executables found by UniGetUI": "پەڕگەی جێبەجێکراوی بەکارهاتوو هەڵبژێرە. لیستی خوارەوە ئەو پەڕگە جێبەجێکراوانە پیشان دەدات کە UniGetUI دۆزیونیەتەوە", + "For security reasons, changing the executable file is disabled by default": "بەهۆی هۆکاری ئاسایشییەوە، گۆڕینی پەڕگەی جێبەجێکراو بە شێوەی بنەڕەتی ناچالاکە", + "Change this": "ئەمە بگۆڕە", + "Copy path": "ڕێڕەوەکە لەبەر بگرەوە", + "Current executable file:": "پەڕگەی جێبەجێکراوی ئێستا:", + "Ignore packages from {pm} when showing a notification about updates": "کاتێک ئاگادارکردنەوەیەک سەبارەت بە نوێکردنەوەکان پیشان دەدرێت، پاکێجەکانی {pm} پشتگوێ بخە", + "Update security": "ئاسایشی نوێکردنەوە", + "Use global setting": "ڕێکخستنی گشتی بەکاربهێنە", + "Minimum age for updates": "کەمترین تەمەن بۆ نوێکردنەوەکان", + "e.g. 10": "وەک 10", + "Custom minimum age (days)": "کەمترین تەمەنی تایبەت (ڕۆژ)", + "{pm} does not provide release dates for its packages, so this setting will have no effect": "{pm} بەرواری بڵاوکردنەوە بۆ پاکێجەکانی دابین ناکات، بۆیە ئەم ڕێکخستنە هیچ کاریگەرییەکی نابێت", + "{pm} only provides release dates for some of its packages, so this setting will only apply to those packages": "{pm} تەنها بۆ هەندێک لە پاکێجەکانی خۆی بەرواری بڵاوکردنەوە پێشکەش دەکات، بۆیە ئەم ڕێکخستنە تەنها بۆ ئەو پاکێجانە جێبەجێ دەبێت", + "Override the global minimum update age for this package manager": "کەمترین تەمەنی گشتیی نوێکردنەوە بۆ ئەم بەڕێوەبەری پاکێجە بگۆڕە", + "View {0} logs": "{0} تۆمار ببینە", + "If Python cannot be found or is not listing packages but is installed on the system, ": "ئەگەر Python نەدۆزرێتەوە یان پاکێجەکان لیست ناکات بەڵام لەسەر سیستەم دامەزراوە، ", + "Advanced options": "هەڵبژاردە پێشکەوتووەکان", + "WinGet command-line tool": "ئامرازی هێڵی فەرمانی WinGet", + "Choose which command-line tool UniGetUI uses for WinGet operations when the COM API is not used": "هەڵبژێرە UniGetUI کام ئامرازی هێڵی فەرمان بۆ کردارەکانی WinGet بەکاربهێنێت کاتێک COM API بەکارناهێنرێت", + "WinGet COM API": "WinGet COM API", + "Choose whether UniGetUI can use the WinGet COM API before falling back to the command-line tool": "هەڵبژێرە ئایا UniGetUI دەتوانێت پێش گەڕانەوە بۆ ئامرازی هێڵی فەرمان، WinGet COM API بەکاربهێنێت یان نا", + "Reset WinGet": "WinGet بگەڕێنەرەوە بۆ دۆخی بنەڕەتی", + "This may help if no packages are listed": "ئەگەر هیچ پاکێجێک لیست نەکرابێت، ئەمە لەوانەیە یارمەتیدەر بێت", + "Force install location parameter when updating packages with custom locations": "لە کاتی نوێکردنەوەی پاکێجەکانی شوێنی تایبەت، پارامیتەری شوێنی دامەزراندن بە زۆر بەکاربهێنە", + "Install Scoop": "Scoop دابمەزرێنە", + "Uninstall Scoop (and its packages)": "Scoop (و پاکێجەکانی) بیسڕەوە", + "Run cleanup and clear cache": "پاکسازی بەڕێوەببە و کاش پاک بکەرەوە", + "Run": "بەڕێوەببە", + "Enable Scoop cleanup on launch": "لە کاتی دەستپێکدا پاکسازیی Scoop چالاک بکە", + "Default vcpkg triplet": "tripletی بنەڕەتیی vcpkg", + "Change vcpkg root location": "شوێنی ڕەگی vcpkg بگۆڕە", + "Reset vcpkg root location": "شوێنی ڕەگی vcpkg ڕێکبخەرەوە", + "Open vcpkg root location": "شوێنی ڕەگی vcpkg بکەرەوە", + "Language, theme and other miscellaneous preferences": "زمان، ڕووکار و هەڵبژاردە جۆراوجۆرەکانی تر", + "Show notifications on different events": "لە ڕووداوە جیاوازەکاندا ئاگادارکردنەوەکان پیشان بدە", + "Change how UniGetUI checks and installs available updates for your packages": "ئەو شێوازە بگۆڕە کە UniGetUI پێی نوێکردنەوە بەردەستەکانی پاکێجەکانت دەپشکنێت و دایدەمەزرێنێت", + "Automatically save a list of all your installed packages to easily restore them.": "لیستی هەموو پاکێجە دامەزراوەکانت بە شێوەی خۆکار پاشەکەوت بکە بۆ ئەوەی بە ئاسانی بیانگەڕێنیتەوە.", + "Enable and disable package managers, change default install options, etc.": "بەڕێوەبەرانی پاکێج چالاک یان ناچالاک بکە، هەڵبژاردە بنەڕەتییەکانی دامەزراندن بگۆڕە، هتد.", + "Internet connection settings": "ڕێکخستنەکانی پەیوەندی ئینتەرنێت", + "Proxy settings, etc.": "ڕێکخستنەکانی proxy، هتد.", + "Beta features and other options that shouldn't be touched": "تایبەتمەندییە Beta ـەکان و هەڵبژاردەکانی تر کە نابێت دەستیان لێ بدرێت", + "Reload sources": "سەرچاوەکان بارکەرەوە", + "Delete source": "سەرچاوەکە بسڕەوە", + "Known sources": "سەرچاوە ناسراوەکان", + "Update checking": "پشکنینی نوێکردنەوە", + "Automatic updates": "نوێکردنەوە خۆکارەکان", + "Check for package updates periodically": "بە شێوەی خولەکی بۆ نوێکردنەوەکانی پاکێج بپشکنە", + "Check for updates every:": "هەر ئەم ماوەیە بۆ نوێکردنەوە بپشکنە:", + "Install available updates automatically": "نوێکردنەوە بەردەستەکان بە شێوەی خۆکار دابمەزرێنە", + "Do not automatically install updates when the network connection is metered": "کاتێک پەیوەندیی تۆڕەکە metered ـە، نوێکردنەوەکان بە شێوەی خۆکار دابمەزرێنە مەکە", + "Do not automatically install updates when the device runs on battery": "کاتێک ئامێرەکە لەسەر باتری کار دەکات، نوێکردنەوەکان بە شێوەی خۆکار دابمەزرێنە مەکە", + "Do not automatically install updates when the battery saver is on": "کاتێک باتری ساڤەر چالاکە، نوێکردنەوەکان بە شێوەی خۆکار دابمەزرێنە مەکە", + "Only show updates that are at least the specified number of days old": "تەنها ئەو نوێکردنەوانە پیشان بدە کە لانیکەم ئەو ژمارە ڕۆژە تەمەنیان هەیە کە دیاریکراوە", + "Warn me when the installer URL host changes between the installed version and the new version (WinGet only)": "ئاگادارم بکەرەوە کاتێک خانەخوێی بەستەری دامەزرێنەر لەنێوان وەشانی دامەزراو و وەشانی نوێدا دەگۆڕێت (تەنها WinGet)", + "Change how UniGetUI handles install, update and uninstall operations.": "ئەو شێوازە بگۆڕە کە UniGetUI کردارەکانی دامەزراندن، نوێکردنەوە و لابردن بەڕێوە دەبات.", + "Navigation": "ڕێنیشاندان", + "Check for UniGetUI updates": "پشکنین بۆ نوێکردنەوەکانی UniGetUI", + "Quit UniGetUI": "لە UniGetUI بچۆرە دەرەوە", + "Filters": "پالێوەرەکان", + "Sources": "سەرچاوەکان", + "Search for packages to start": "بۆ دەستپێکردن بەدوای پاکێجەکاندا بگەڕێ", + "Select all": "هەمووی هەڵبژێرە", + "Clear selection": "هەڵبژاردن پاک بکەرەوە", + "Instant search": "گەڕانی دەستبەجێ", + "Distinguish between uppercase and lowercase": "جیاوازی لەنێوان پیتی گەورە و بچووک بکە", + "Ignore special characters": "پیت و هێمای تایبەت پشتگوێ بخە", + "Search mode": "دۆخی گەڕان", + "Both": "هەردووکیان", + "Exact match": "گونجانی تەواو", + "Show similar packages": "پاکێجە هاوشێوەکان پیشان بدە", + "Loading": "بارکردن", + "Package": "پاکێج", + "More options": "هەڵبژاردەی زیاتر", + "Order by:": "ڕیزبەندی بکە بە:", + "Name": "ناو", + "Id": "ناسنامە", + "Ascendant": "بەرەو سەرەوە", + "Descendant": "بەرەو خوارەوە", + "View modes": "دۆخەکانی بینین", + "Reload": "بارکردنەوە", + "Closed": "داخراوە", + "Ascending": "بەرەو سەرەوە", + "Descending": "بەرەو خوارەوە", + "{0}: {1}, {2}": "{0}: {1}، {2}", + "Order by": "ڕیزکردن بەپێی", + "No results were found matching the input criteria": "هیچ ئەنجامێک نەدۆزرایەوە کە لەگەڵ پێوەرەکانی داخڵکراو بگونجێت", + "No packages were found": "هیچ پاکێجێک نەدۆزرایەوە", + "Loading packages": "پاکێجەکان بار دەکرێن", + "Skip integrity checks": "پشکنینەکانی integrity بازبدە", + "Download selected installers": "دامەزرێنەرە هەڵبژێردراوەکان دابگرە", + "Install selection": "هەڵبژاردن دامەزرێنە", + "Install options": "هەڵبژاردەکانی دامەزراندن", + "Add selection to bundle": "هەڵبژاردن زیاد بکە بۆ باندڵ", + "Download installer": "دامەزرێنەر دابگرە", + "Uninstall selection": "هەڵبژاردن لاببە", + "Uninstall options": "هەڵبژاردەکانی لابردن", + "Ignore selected packages": "پاکێجە هەڵبژێردراوەکان پشتگوێ بخە", + "Open install location": "شوێنی دامەزراندن بکەرەوە", + "Reinstall package": "پاکێجەکە دووبارە دابمەزرێنە", + "Uninstall package, then reinstall it": "پاکێجەکە لاببە، پاشان دووبارە دایبمەزرێنە", + "Ignore updates for this package": "نوێکردنەوەکانی ئەم پاکێجە پشتگوێ بخە", + "WinGet malfunction detected": "هەڵەی کارکردنی WinGet دۆزرایەوە", + "It looks like WinGet is not working properly. Do you want to attempt to repair WinGet?": "وا دیارە WinGet بە دروستی کار ناکات. دەتەوێت هەوڵی چاککردنەوەی WinGet بدەیت؟", + "Repair WinGet": "WinGet چاک بکەرەوە", + "Updates will no longer be ignored for {0}": "نوێکردنەوەکان چیتر پشتگوێ ناخرێن بۆ {0}", + "Updates are now ignored for {0}": "نوێکردنەوەکان ئێستا پشتگوێ دەخرێن بۆ {0}", + "Do not ignore updates for this package anymore": "لەمەودوا نوێکردنەوەکانی ئەم پاکێجە پشتگوێ مەخە", + "Add packages or open an existing package bundle": "پاکێج زیاد بکە یان باندڵێکی پاکێجی هەبوو بکەرەوە", + "Add packages to start": "بۆ دەستپێکردن پاکێج زیاد بکە", + "The current bundle has no packages. Add some packages to get started": "باندڵی ئێستا هیچ پاکێجێکی تێدا نییە. هەندێک پاکێج زیاد بکە بۆ ئەوەی دەست پێ بکەیت", + "New": "نوێ", + "Save as": "وەک... پاشەکەوتی بکە", + "Create .ps1 script": "سکریپتی .ps1 دروست بکە", + "Remove selection from bundle": "هەڵبژاردن لە باندڵ لاببە", + "Skip hash checks": "پشکنینەکانی hash بازبدە", + "The package bundle is not valid": "باندڵی پاکێج دروست نییە", + "The bundle you are trying to load appears to be invalid. Please check the file and try again.": "باندڵەکەی هەوڵی بارکردنی دەدەیت دیارە دروست نییە. تکایە پەڕگەکە بپشکنە و دووبارە هەوڵ بدەوە.", + "Package bundle": "باندڵی پاکێج", + "Could not create bundle": "نەکرا باندڵ دروست بکرێت", + "The package bundle could not be created due to an error.": "باندڵی پاکێج بەهۆی هەڵەیەکەوە نەکرا دروست بکرێت.", + "Install script": "سکریپتی دامەزراندن", + "PowerShell script": "سکریپتی PowerShell", + "The installation script saved to {0}": "سکریپتی دامەزراندن لە {0} پاشەکەوت کرا", + "An error occurred": "هەڵەیەک ڕوویدا", + "An error occurred while attempting to create an installation script:": "لە کاتی هەوڵدان بۆ دروستکردنی سکریپتی دامەزراندن هەڵەیەک ڕوویدا:", + "Hooray! No updates were found.": "زۆر باش! هیچ نوێکردنەوەیەک نەدۆزرایەوە.", + "Uninstall selected packages": "پاکێجە هەڵبژێردراوەکان لاببە", + "Update selection": "هەڵبژاردن نوێ بکەرەوە", + "Update options": "هەڵبژاردەکانی نوێکردنەوە", + "Uninstall package, then update it": "پاکێجەکە لاببە، پاشان نوێی بکەرەوە", + "Uninstall package": "پاکێجەکە لاببە", + "Skip this version": "ئەم وەشانە بازبدە", + "Pause updates for": "نوێکردنەوەکان بوەستێنە بۆ", + "User | Local": "بەکارهێنەر | ناوخۆیی", + "Machine | Global": "ئامێر | گشتی", + "The default package manager for Debian/Ubuntu-based Linux distributions.
Contains: Debian/Ubuntu packages": "بەڕێوەبەری پاکێجی بنەڕەتی بۆ دابەشکردنەکانی Linux ی پشت بە Debian/Ubuntu.
لەخۆدەگرێت: پاکێجەکانی Debian/Ubuntu", + "The Rust package manager.
Contains: Rust libraries and programs written in Rust": "بەڕێوەبەری پاکێجی Rust.
لەخۆدەگرێت: کتێبخانەکانی Rust و بەرنامە نووسراوەکانی بە Rust", + "The classical package manager for windows. You'll find everything there.
Contains: General Software": "بەڕێوەبەری پاکێجی کلاسیکی بۆ Windows. هەموو شتێکت لەوێ دەدۆزیتەوە.
لەخۆدەگرێت: نەرمەکاڵای گشتی", + "The default package manager for RHEL/Fedora-based Linux distributions.
Contains: RPM packages": "بەڕێوەبەری پاکێجی بنەڕەتی بۆ دابەشکردنەکانی Linux ی پشت بە RHEL/Fedora.
لەخۆدەگرێت: پاکێجەکانی RPM", + "A repository full of tools and executables designed with Microsoft's .NET ecosystem in mind.
Contains: .NET related tools and scripts": "کۆگایەکی پڕ لە ئامراز و پەڕگە جێبەجێکراوان کە بە مەبەستی ئەکۆسیستەمی .NET ـی Microsoft دیزاین کراون.
لەخۆدەگرێت: ئامراز و سکریپتە پەیوەندیدارەکانی .NET", + "The universal Linux package manager for desktop applications.
Contains: Flatpak applications from configured remotes": "بەڕێوەبەری پاکێجی گشتیی Linux بۆ ئەپڵیکەیشنەکانی ڕوومێز.
لەخۆی دەگرێت: ئەپڵیکەیشنەکانی Flatpak لە ڕیمۆتە ڕێکخراوەکانەوە", + "NuPkg (zipped manifest)": "NuPkg (مانیفێستی زیپکراو)", + "The Missing Package Manager for macOS (or Linux).
Contains: Formulae, Casks": "بەڕێوەبەری پاکێجی ونبوو بۆ macOS (یان Linux).
لەخۆدەگرێت: Formulae, Casks", + "Node JS's package manager. Full of libraries and other utilities that orbit the javascript world
Contains: Node javascript libraries and other related utilities": "بەڕێوەبەری پاکێجی Node JS. پڕە لە کتێبخانە و ئامرازەکانی تر کە دەوری جیهانی javascript دەخولێنەوە
لەخۆدەگرێت: کتێبخانەکانی Node javascript و ئامرازە پەیوەندیدارەکانی تر", + "The default package manager for Arch Linux and its derivatives.
Contains: Arch Linux packages": "بەڕێوەبەری پاکێجی بنەڕەتی بۆ Arch Linux و لقەکانی.
لەخۆدەگرێت: پاکێجەکانی Arch Linux", + "Python's library manager. Full of python libraries and other python-related utilities
Contains: Python libraries and related utilities": "بەڕێوەبەری کتێبخانەکانی Python. پڕە لە کتێبخانەکانی Python و ئامرازە پەیوەندیدارەکانی تر
لەخۆدەگرێت: کتێبخانەکانی Python و ئامرازە پەیوەندیدارەکان", + "PowerShell's package manager. Find libraries and scripts to expand PowerShell capabilities
Contains: Modules, Scripts, Cmdlets": "بەڕێوەبەری پاکێجی PowerShell. کتێبخانە و سکریپت بدۆزەرەوە بۆ فراوانکردنی تواناکانی PowerShell
لەخۆدەگرێت: Modules, Scripts, Cmdlets", + "extracted": "دەرهێنراو", + "Scoop package": "پاکێجی Scoop", + "Great repository of unknown but useful utilities and other interesting packages.
Contains: Utilities, Command-line programs, General Software (extras bucket required)": "کۆگایەکی باش لە ئامرازی نەناسراو بەڵام بەسوود و پاکێجە سەرنجڕاکێشەکانی تر.
لەخۆدەگرێت: ئامرازەکان، بەرنامەکانی هێڵی فرمان، نەرمەکاڵای گشتی (بوکتی extras پێویستە)", + "The universal Linux package manager by Canonical.
Contains: Snap packages from the Snapcraft store": "بەڕێوەبەری پاکێجی گشتیی Linux لەلایەن Canonical.
لەخۆدەگرێت: پاکێجەکانی Snap لە فرۆشگای Snapcraft", + "library": "کتێبخانە", + "feature": "تایبەتمەندی", + "A popular C/C++ library manager. Full of C/C++ libraries and other C/C++-related utilities
Contains: C/C++ libraries and related utilities": "بەڕێوەبەری کتێبخانەیەکی بەناوبانگی C/C++. پڕە لە کتێبخانەکانی C/C++ و ئامرازە پەیوەندیدارەکانی تر
لەخۆدەگرێت: کتێبخانەکانی C/C++ و ئامرازە پەیوەندیدارەکان", + "option": "هەڵبژاردە", + "This package cannot be installed from an elevated context.": "ئەم پاکێجە لە دۆخی بەڕێوەبەر ناتوانرێت دابمەزرێت.", + "Please run UniGetUI as a regular user and try again.": "تکایە UniGetUI وەک بەکارهێنەری ئاسایی بەڕێوەیببە و دووبارە هەوڵ بدەوە.", + "Please check the installation options for this package and try again": "تکایە هەڵبژاردەکانی دامەزراندنی ئەم پاکێجە بپشکنە و دووبارە هەوڵ بدەوە", + "Microsoft's official package manager. Full of well-known and verified packages
Contains: General Software, Microsoft Store apps": "بەڕێوەبەری پاکێجی فەرمیی Microsoft. پڕە لە پاکێجی ناسراو و پشتڕاستکراوە
لەخۆدەگرێت: نەرمەکاڵای گشتی، ئەپی Microsoft Store", + "Local PC": "کۆمپیوتەری ناوخۆ", + "Android Subsystem": "ژێرسیستەمی Android", + "Operation on queue (position {0})...": "کردار لە ناو ڕیزەکەدا (شوێن {0})...", + "Click here for more details": "بۆ وردەکاریی زیاتر لێرە کرتە بکە", + "Operation canceled by user": "کردارەکە لەلایەن بەکارهێنەرەوە هەڵوەشێندرایەوە", + "Running PreOperation ({0}/{1})...": "PreOperation ({0}/{1}) بەڕێوەدەچێت...", + "PreOperation {0} out of {1} failed, and was tagged as necessary. Aborting...": "PreOperation {0} لە {1} سەرکەوتوو نەبوو، وەک پێویست نیشانەکراوە. واز لێهێنرا...", + "PreOperation {0} out of {1} finished with result {2}": "PreOperation {0} لە {1} بە ئەنجامی {2} تەواو بوو", + "Starting operation...": "کردارەکە دەست پێ دەکات...", + "Running PostOperation ({0}/{1})...": "PostOperation ({0}/{1}) بەڕێوەدەچێت...", + "PostOperation {0} out of {1} failed, and was tagged as necessary. Aborting...": "PostOperation {0} لە {1} سەرکەوتوو نەبوو، وەک پێویست نیشانەکراوە. واز لێهێنرا...", + "PostOperation {0} out of {1} finished with result {2}": "PostOperation {0} لە {1} بە ئەنجامی {2} تەواو بوو", + "{package} installer download": "داگرتنی دامەزرێنەری {package}", + "{0} installer is being downloaded": "دامەزرێنەری {0} دادەگیرێت", + "Download succeeded": "داگرتن سەرکەوتوو بوو", + "{package} installer was downloaded successfully": "دامەزرێنەری {package} بە سەرکەوتوویی داگیرا", + "Download failed": "داگرتن سەرکەوتوو نەبوو", + "{package} installer could not be downloaded": "نەکرا دامەزرێنەری {package} دابگیرێت", + "{package} Installation": "دامەزراندنی {package}", + "{0} is being installed": "{0} دادەمەزرێت", + "Installation succeeded": "دامەزراندن سەرکەوتوو بوو", + "{package} was installed successfully": "{package} بە سەرکەوتوویی دامەزرا", + "Installation failed": "دامەزراندن سەرکەوتوو نەبوو", + "{package} could not be installed": "نەکرا {package} دابمەزرێت", + "{package} Update": "نوێکردنەوەی {package}", + "Update succeeded": "نوێکردنەوە سەرکەوتوو بوو", + "{package} was updated successfully": "{package} بە سەرکەوتوویی نوێ کرایەوە", + "Update failed": "نوێکردنەوە سەرکەوتوو نەبوو", + "{package} could not be updated": "نەکرا {package} نوێ بکرێتەوە", + "{package} Uninstall": "لابردنی {package}", + "{0} is being uninstalled": "{0} لادەبرێت", + "Uninstall succeeded": "لابردن سەرکەوتوو بوو", + "{package} was uninstalled successfully": "{package} بە سەرکەوتوویی لابرا", + "Uninstall failed": "لابردن سەرکەوتوو نەبوو", + "{package} could not be uninstalled": "نەکرا {package} لاببرێت", + "Adding source {source}": "سەرچاوەی {source} زیاد دەکرێت", + "Adding source {source} to {manager}": "سەرچاوەی {source} بۆ {manager} زیاد دەکرێت", + "Source added successfully": "سەرچاوەکە بە سەرکەوتوویی زیاد کرا", + "The source {source} was added to {manager} successfully": "سەرچاوەی {source} بە سەرکەوتوویی بۆ {manager} زیاد کرا", + "Could not add source": "نەکرا سەرچاوە زیاد بکرێت", + "Could not add source {source} to {manager}": "نەکرا سەرچاوەی {source} بۆ {manager} زیاد بکرێت", + "Removing source {source}": "سەرچاوەی {source} لادەبرێت", + "Removing source {source} from {manager}": "سەرچاوەی {source} لە {manager} لادەبرێت", + "Source removed successfully": "سەرچاوەکە بە سەرکەوتوویی لابرا", + "The source {source} was removed from {manager} successfully": "سەرچاوەی {source} بە سەرکەوتوویی لە {manager} لابرا", + "Could not remove source": "نەکرا سەرچاوە لاببرێت", + "Could not remove source {source} from {manager}": "نەکرا سەرچاوەی {source} لە {manager} لاببرێت", + "The package manager \"{0}\" was not found": "بەڕێوەبەری پاکێجی \"{0}\" نەدۆزرایەوە", + "The package manager \"{0}\" is disabled": "بەڕێوەبەری پاکێجی \"{0}\" ناچالاکە", + "There is an error with the configuration of the package manager \"{0}\"": "هەڵەیەک لە ڕێکخستنی بەڕێوەبەری پاکێجی \"{0}\" هەیە", + "The package \"{0}\" was not found on the package manager \"{1}\"": "پاکێجی \"{0}\" لە بەڕێوەبەری پاکێجی \"{1}\" نەدۆزرایەوە", + "{0} is disabled": "{0} ناچالاکە", + "{0} weeks": "{0} هەفتە", + "1 month": "1 مانگ", + "{0} months": "{0} مانگ", + "Something went wrong": "شتێک هەڵە ڕوویدا", + "An interal error occurred. Please view the log for further details.": "هەڵەیەکی ناوخۆیی ڕوویدا. تکایە بۆ وردەکاریی زیاتر سەیری تۆمارەکە بکە.", + "No applicable installer was found for the package {0}": "هیچ دامەزرێنەرێکی گونجاو بۆ پاکێجی {0} نەدۆزرایەوە", + "Integrity checks will not be performed during this operation": "لەم کردارەدا پشکنینەکانی integrity ئەنجام نادرێن", + "This is not recommended.": "ئەمە پێشنیار ناکرێت.", + "Run now": "ئێستا بەڕێوەیببە", + "Run next": "دواتر بەڕێوەیببە", + "Run last": "لە کۆتاییدا بەڕێوەیببە", + "Show in explorer": "لە Explorer پیشان بدە", + "Checked": "هەڵبژێردراو", + "Unchecked": "هەڵنەبژێردراو", + "This package is already installed": "ئەم پاکێجە پێشتر دامەزراوە", + "This package can be upgraded to version {0}": "ئەم پاکێجە دەتوانرێت بۆ وەشانی {0} نوێ بکرێتەوە", + "Updates for this package are ignored": "نوێکردنەوەکانی ئەم پاکێجە پشتگوێ خراون", + "This package is being processed": "ئەم پاکێجە لە ژێر پرۆسەدایە", + "This package is not available": "ئەم پاکێجە بەردەست نییە", + "Select the source you want to add:": "ئەو سەرچاوەیە هەڵبژێرە کە دەتەوێت زیادی بکەیت:", + "Source name:": "ناوی سەرچاوە:", + "Source URL:": "URLی سەرچاوە:", + "An error occurred when adding the source: ": "کاتێک سەرچاوەکە زیاد دەکرا هەڵەیەک ڕوویدا: ", + "Package management made easy": "بەڕێوەبردنی پاکێج بە ئاسانی", + "version {0}": "وەشانی {0}", + "[RAN AS ADMINISTRATOR]": "[وەک بەڕێوەبەر بەڕێوەچوو]", + "Portable mode": "دۆخی portable\n", + "DEBUG BUILD": "وەشانی DEBUG", + "Here you can change UniGetUI's behaviour regarding the following shortcuts. Checking a shortcut will make UniGetUI delete it if if gets created on a future upgrade. Unchecking it will keep the shortcut intact": "لێرە دەتوانیت هەڵسوکەوتی UniGetUI لەبارەی ئەم قەدبڕانەوە بگۆڕیت. ئەگەر قەدبڕێک هەڵبژێریت، UniGetUI ئەگەر لە نوێکردنەوەیەکی داهاتوودا دروست بکرێت دەیسڕێتەوە. ئەگەر هەڵیبگریتەوە، قەدبڕەکە وەک خۆی دەمێنێتەوە", + "Manual scan": "پشکنینی دەستی", + "Existing shortcuts on your desktop will be scanned, and you will need to pick which ones to keep and which ones to remove.": "قەدبڕە هەبووەکانی سەر ڕوومێزەکەت دەپشکنرێن، و تۆ دەبێت هەڵبژێریت کامیان بهێڵیتەوە و کامیان لاببەیت.", + "Delete?": "بسڕێتەوە؟", + "I understand": "تێگەیشتم", + "Chocolatey setup changed": "ڕێکخستنی Chocolatey گۆڕا", + "UniGetUI no longer includes its own private Chocolatey installation. A legacy UniGetUI-managed Chocolatey installation was detected for this user profile, but system Chocolatey was not found. Chocolatey will stay unavailable in UniGetUI until Chocolatey is installed on the system and UniGetUI is restarted. Applications previously installed through UniGetUI's bundled Chocolatey may still appear under other sources such as Local PC or WinGet.": "UniGetUI چیتر دامەزراندنی تایبەتی Chocolatey ی خۆی لەخۆ ناگرێت. دامەزراندنێکی کۆنی Chocolatey ی بەڕێوەبراو لەلایەن UniGetUI بۆ ئەم پرۆفایلی بەکارهێنەرە دۆزرایەوە، بەڵام Chocolatey ی سیستەم نەدۆزرایەوە. Chocolatey لە UniGetUI بەردەست نابێت تاکو Chocolatey لەسەر سیستەمەکە دادەمەزرێت و UniGetUI دووبارە دەستپێدەکرێتەوە. ئەو بەرنامانەی کە پێشتر لە ڕێگەی Chocolatey ی هاوپێچکراوی UniGetUI دامەزرابوون لەوانەیە هێشتا لەژێر سەرچاوەکانی دیکە وەک کۆمپیوتەری ناوخۆیی یان WinGet دەربکەون.", + "NOTE: This troubleshooter can be disabled from UniGetUI Settings, on the WinGet section": "تێبینی: ئەم چارەسەرکەرە لە ڕێکخستنەکانی UniGetUI، لە بەشی WinGet، دەتوانرێت ناچالاک بکرێت", + "Restart": "دووبارە دەست پێ بکە", + "Are you sure you want to delete all shortcuts?": "دڵنیایت دەتەوێت هەموو قەدبڕەکان بسڕیتەوە؟", + "Any new shorcuts created during an install or an update operation will be deleted automatically, instead of showing a confirmation prompt the first time they are detected.": "هەر قەدبڕێکی نوێ کە لە کاتی دامەزراندن یان کردارێکی نوێکردنەوەدا دروست بکرێت، بە شێوەی خۆکار دەسڕدرێتەوە، لەبری ئەوەی یەکەم جار کە دۆزرایەوە داوای پشتڕاستکردنەوە پیشان بدرێت.", + "Any shorcuts created or modified outside of UniGetUI will be ignored. You will be able to add them via the {0} button.": "هەر قەدبڕێک کە دەرەوەی UniGetUI دروست یان دەستکاریکراوە پشتگوێ دەخرێت. دەتوانیت لە ڕێگەی دوگمەی {0} زیادیان بکەیت.", + "Are you really sure you want to enable this feature?": "بەڕاستی دڵنیایت دەتەوێت ئەم تایبەتمەندییە چالاک بکەیت؟", + "No new shortcuts were found during the scan.": "لە کاتی پشکنینەکەدا هیچ قەدبڕێکی نوێ نەدۆزرایەوە.", + "How to add packages to a bundle": "چۆن پاکێج زیاد بکەیت بۆ باندڵێک", + "In order to add packages to a bundle, you will need to: ": "بۆ زیادکردنی پاکێج بۆ باندڵێک، پێویستە: ", + "1. Navigate to the \"{0}\" or \"{1}\" page.": "1. بڕۆ بۆ پەڕەی \"{0}\" یان \"{1}\".", + "2. Locate the package(s) you want to add to the bundle, and select their leftmost checkbox.": "2. ئەو پاکێجانە بدۆزەرەوە کە دەتەوێت زیادیان بکەیت بۆ باندڵەکە، و خانەی هەڵبژاردنی لای چەپەیان هەڵبژێرە.", + "3. When the packages you want to add to the bundle are selected, find and click the option \"{0}\" on the toolbar.": "3. کاتێک ئەو پاکێجانەی دەتەوێت زیادیان بکەیت بۆ باندڵەکە هەڵبژێردران، ئەو هەڵبژاردەی \"{0}\" لە تووڵامرازدا بدۆزەرەوە و لێی بدە.", + "4. Your packages will have been added to the bundle. You can continue adding packages, or export the bundle.": "4. پاکێجەکانت زیاد کراون بۆ باندڵەکە. دەتوانیت بە زیادکردنی پاکێجی تر بەردەوام بیت، یان باندڵەکە هەناردە بکەیت.", + "Which backup do you want to open?": "کام پاشەکەوت دەتەوێت بکەیتەوە؟", + "Select the backup you want to open. Later, you will be able to review which packages you want to install.": "ئەو پاشەکەوتە هەڵبژێرە کە دەتەوێت بکەیتەوە. دواتر دەتوانیت پشکنین بکەیت کام پاکێج/بەرنامە دەتەوێت بیگەڕێنیتەوە.", + "There are ongoing operations. Quitting UniGetUI may cause them to fail. Do you want to continue?": "هەندێک کردار لە بەڕێوەچووندان. دەرچوون لە UniGetUI لەوانەیە ببێتە هۆی سەرکەوتوو نەبوونیان. دەتەوێت بەردەوام بیت؟", + "UniGetUI or some of its components are missing or corrupt.": "UniGetUI یان هەندێک لە پێکهاتەکانی ونن یان تێکچوون.", + "It is strongly recommended to reinstall UniGetUI to adress the situation.": "زۆر بە هێز پێشنیار دەکرێت UniGetUI دووبارە دابمەزرێنیت بۆ چارەسەرکردنی ئەم دۆخە.", + "Refer to the UniGetUI Logs to get more details regarding the affected file(s)": "بگەڕێوە بۆ تۆمارەکانی UniGetUI بۆ بەدەستهێنانی وردەکاریی زیاتر سەبارەت بە پەڕگە زیانلێکەوتووەکان", + "Integrity checks can be disabled from the Experimental Settings": "پشکنینەکانی integrity دەتوانرێن لە ڕێکخستنە ئەزموونییەکان ناچالاک بکرێن", + "Repair UniGetUI": "UniGetUI چاک بکەرەوە", + "Live output": "دەرهاویشتەی ڕاستەوخۆ", + "This package bundle had some settings that are potentially dangerous, and may be ignored by default.": "ئەم باندڵەی پاکێجە هەندێک ڕێکخستن لەخۆ دەگرێت کە لەوانەیە مەترسیدار بن، و بە شێوەی بنەڕەتی پشتگوێ بخرێن.", + "Entries that show in YELLOW will be IGNORED.": "ئەو تۆمارانەی بە ڕەنگی زەرد پیشان دەدرێن پشتگوێ دەخرێن.", + "Entries that show in RED will be IMPORTED.": "ئەو تۆمارانەی بە ڕەنگی سوور پیشان دەدرێن هاوردە دەکرێن.", + "You can change this behavior on UniGetUI security settings.": "دەتوانیت ئەم هەڵسوکەوتە لە ڕێکخستنە ئاسایشییەکانی UniGetUI بگۆڕیت.", + "Open UniGetUI security settings": "ڕێکخستنە ئاسایشییەکانی UniGetUI بکەرەوە", + "Should you modify the security settings, you will need to open the bundle again for the changes to take effect.": "ئەگەر ڕێکخستنە ئاسایشییەکان بگۆڕیت، دەبێت باندڵەکە دووبارە بکەیتەوە تاکو گۆڕانکارییەکان کاریگەریان هەبێت.", + "Details of the report:": "وردەکارییەکانی ڕاپۆرتەکە:", + "Are you sure you want to create a new package bundle? ": "دڵنیایت دەتەوێت باندڵێکی پاکێجی نوێ دروست بکەیت؟ ", + "Any unsaved changes will be lost": "هەر گۆڕانکارییەکی پاشەکەوت نەکراو لەدەست دەچێت", + "Warning!": "ئاگاداری!", + "For security reasons, custom command-line arguments are disabled by default. Go to UniGetUI security settings to change this. ": "بۆ هۆکاری ئاسایش، ئارگیومێنتە تایبەتەکانی هێڵی فرمان بە شێوەی بنەڕەتی ناچالاکن. بڕۆ بۆ ڕێکخستنە ئاسایشییەکانی UniGetUI بۆ گۆڕینی ئەمە. ", + "Change default options": "هەڵبژاردە بنەڕەتییەکان بگۆڕە", + "Ignore future updates for this package": "نوێکردنەوە داهاتووەکانی ئەم پاکێجە پشتگوێ بخە", + "For security reasons, pre-operation and post-operation scripts are disabled by default. Go to UniGetUI security settings to change this. ": "بۆ هۆکاری ئاسایش، سکریپتەکانی پێش کردار و دوای کردار بە شێوەی بنەڕەتی ناچالاکن. بڕۆ بۆ ڕێکخستنە ئاسایشییەکانی UniGetUI بۆ گۆڕینی ئەمە. ", + "You can define the commands that will be run before or after this package is installed, updated or uninstalled. They will be run on a command prompt, so CMD scripts will work here.": "دەتوانیت ئەو فرمانانە دیاری بکەیت کە پێش یان دوای دامەزراندن، نوێکردنەوە یان لابردنی ئەم پاکێجە بەڕێوە دەچن. ئەوان لە ناو command prompt بەڕێوە دەچن، بۆیە سکریپتەکانی CMD لێرە کار دەکەن.", + "Change this and unlock": "ئەمە بگۆڕە و قفڵەکە بکەرەوە", + "{0} Install options are currently locked because {0} follows the default install options.": "هەڵبژاردەکانی دامەزراندنی {0} ئێستا قفڵکراون، چونکە {0} شوێنی هەڵبژاردە بنەڕەتییەکانی دامەزراندن دەکەوێت.", + "Unset or unknown": "دانەنراو یان نەزانراو", + "This package has no screenshots or is missing the icon? Contrbute to UniGetUI by adding the missing icons and screenshots to our open, public database.": "ئەم پاکێجە وێنەی شاشەی نییە یان ئایکۆنەکەی ونە؟ بە زیادکردنی ئایکۆن و وێنە شاشە ونبووەکان بۆ بنکەدراوە کراوە و گشتییەکەمان، یارمەتی UniGetUI بدە.", + "Become a contributor": "ببە بەشداربوو", + "Update to {0} available": "نوێکردنەوە بۆ {0} بەردەستە", + "Reinstall": "دووبارە دابمەزرێنە", + "Installer not available": "دامەزرێنەر بەردەست نییە", + "Version:": "وەشان:", + "UniGetUI Version {0}": "وەشانی UniGetUI {0}", + "Performing backup, please wait...": "پاشەکەوتکردن ئەنجام دەدرێت، تکایە چاوەڕێ بکە...", + "An error occurred while logging in: ": "کاتێک چوونەژوورەوە ئەنجام دەدرا هەڵەیەک ڕوویدا: ", + "Fetching available backups...": "پاشەکەوتە بەردەستەکان هێنراون...", + "Done!": "تەواو!", + "The cloud backup has been loaded successfully.": "پاشەکەوتی هەور بە سەرکەوتوویی بارکرا.", + "An error occurred while loading a backup: ": "کاتێک پاشەکەوتێک بار دەکرا هەڵەیەک ڕوویدا: ", + "Backing up packages to GitHub Gist...": "پاکێجەکان بۆ GitHub Gist پاشەکەوت دەکرێن...", + "Backup Successful": "پاشەکەوت سەرکەوتوو بوو", + "The cloud backup completed successfully.": "پاشەکەوتی هەور بە سەرکەوتوویی تەواو بوو.", + "Could not back up packages to GitHub Gist: ": "نەتوانرا باکاپی پەکەجەکان بۆ GitHub Gist بکرێت: ", + "It is not guaranteed that the provided credentials will be stored safely, so you may as well not use the credentials of your bank account": "هیچ ضمانەتێک نییە کە زانیارییەکانی چوونەژوورەوەی دابینکراو بە سەلامەتی پاشەکەوت بکرێن، بۆیە باشترە زانیارییەکانی هەژماری بانکی خۆت بەکارنەهێنیت", + "Enable the automatic WinGet troubleshooter": "چارەسەرکەری خۆکاری WinGet چالاک بکە", + "Add updates that fail with a 'no applicable update found' to the ignored updates list": "نوێکردنەوەکانێک کە بە 'no applicable update found' سەرکەوتوو نابن بخەرە ناو لیستی نوێکردنەوە پشتگوێخراوەکان.", + "Invalid selection": "هەڵبژاردنی نادروست", + "No package was selected": "هیچ پەکەجێک هەڵنەبژێردرا", + "More than 1 package was selected": "زیاتر لە 1 پەکەج هەڵبژێردرا", + "List": "لیست", + "Grid": "خانەبەندی", + "Icons": "ئایکۆنەکان", + "\"{0}\" is a local package and does not have available details": "\"{0}\" پەکەجێکی ناوخۆییە و وردەکاریی بەردەستی نییە", + "\"{0}\" is a local package and is not compatible with this feature": "\"{0}\" پەکەجێکی ناوخۆییە و لەگەڵ ئەم تایبەتمەندییە هاوگونجاو نییە", + "Add packages to bundle": "پەکەجەکان زیاد بکە بۆ باندڵ", + "Preparing packages, please wait...": "پەکەجەکان ئامادە دەکرێن، تکایە چاوەڕێ بکە...", + "Loading packages, please wait...": "پەکەجەکان بار دەکرێن، تکایە چاوەڕێ بکە...", + "Saving packages, please wait...": "پەکەجەکان پاشەکەوت دەکرێن، تکایە چاوەڕێ بکە...", + "The bundle was created successfully on {0}": "باندڵەکە بە سەرکەوتوویی لە {0} دروست کرا", + "User profile": "پرۆفایلی بەکارهێنەر", + "Error": "هەڵە", + "Log in failed: ": "چوونەژوورەوە سەرکەوتوو نەبوو: ", + "Log out failed: ": "چوونەدەرەوە سەرکەوتوو نەبوو: ", + "Package backup settings": "ڕێکخستنەکانی باکاپی پەکەج", + "Manage UniGetUI autostart behaviour from the Settings app": "هەڵسوکەوتی خۆکار دەستپێکردنی UniGetUI بەڕێوەبەرە", + "Choose how many operations shoulds be performed in parallel": "هەڵبژێرە چەند کردارێک دەبێت بە هاوکات ئەنجام بدرێن", + "Something went wrong while launching the updater.": "کاتێک نوێکەرەوەکە دەستپێدەکرا شتێک هەڵە ڕوویدا.", + "Please try again later": "تکایە دواتر دووبارە هەوڵ بدەوە", + "Show the release notes after UniGetUI is updated": "پیشاندانی تێبینییەکانی وەشاندن دوای نوێکردنەوەی UniGetUI" +} diff --git a/src/Languages/lang_lt.json b/src/Languages/lang_lt.json new file mode 100644 index 0000000..c00fcef --- /dev/null +++ b/src/Languages/lang_lt.json @@ -0,0 +1,850 @@ +{ + "{0} of {1} operations completed": "Užbaigta {0} iš {1} operacijų", + "{0} is now {1}": "„{0}“ dabar yra {1}", + "Enabled": "Įjungta", + "Disabled": "Išjungta/Neįgalinta (-s)", + "Privacy": "Privatumas", + "Hide my username from the logs": "Slėpti mano naudotojo vardą žurnaluose", + "Replaces your username with **** in the logs. Restart UniGetUI to also hide it from already-recorded entries.": "Žurnaluose jūsų naudotojo vardas pakeičiamas į ****. Iš naujo paleiskite „UniGetUI“, kad jis būtų paslėptas ir jau įrašytuose įrašuose.", + "Your last update attempt did not complete.": "Paskutinis bandymas atnaujinti nebuvo užbaigtas.", + "UniGetUI could not confirm whether the update succeeded. Open the log to see what happened.": "„UniGetUI“ negalėjo patvirtinti, ar atnaujinimas pavyko. Atidarykite žurnalą, kad pamatytumėte, kas nutiko.", + "View log": "Peržiūrėti žurnalą", + "The installer reported success but did not restart UniGetUI.": "Įdiegiklis pranešė apie sėkmę, bet nepaleido „UniGetUI“ iš naujo.", + "The installer failed to initialize.": "Nepavyko inicijuoti įdiegiklio.", + "Setup was canceled before installation began.": "Sąranka buvo atšaukta prieš pradedant diegimą.", + "A fatal error occurred during the preparation phase.": "Parengimo etape įvyko kritinė klaida.", + "A fatal error occurred during installation.": "Diegimo metu įvyko kritinė klaida.", + "Installation was canceled while in progress.": "Diegimas buvo atšauktas jam vykstant.", + "The installer was terminated by another process.": "Įdiegiklį nutraukė kitas procesas.", + "The preparation phase determined the installation cannot proceed.": "Parengimo etapas nustatė, kad diegimo tęsti negalima.", + "The installer could not start. UniGetUI may already be running, or you do not have permission to install.": "Įdiegiklio paleisti nepavyko. „UniGetUI“ galbūt jau veikia arba neturite leidimo diegti.", + "Unexpected installer error.": "Netikėta įdiegiklio klaida.", + "We are checking for updates.": "Tikriname, ar yra (at-)naujinimų.", + "Please wait": "Prašome palaukti", + "Great! You are on the latest version.": "Sveikiname! Jūs naudojate naujausią/paskiausią versiją!", + "There are no new UniGetUI versions to be installed": "Nėra naujų „UniGetUI“ versijų, kurias būtu galima įdiegti", + "UniGetUI version {0} is being downloaded.": "„UniGetUI“ versija – {0} yra atsisiunčiama/-s.", + "This may take a minute or two": "Šis gali užtrukti minutę ar dvi", + "The installer authenticity could not be verified.": "Nebuvo galima patvirtinti įdiegiklio autentiškumą.", + "The update process has been aborted.": "Atnaujinimo vyksmas buvo nutrauktas.", + "Auto-update is not yet available on this platform.": "Automatinis atnaujinimas šioje platformoje dar nepasiekiamas.", + "Please update UniGetUI manually.": "Atnaujinkite „UniGetUI“ rankiniu būdu.", + "An error occurred when checking for updates: ": "Tikrinant ar yra (at-)naujinimų/-ių įvyko klaida:", + "The updater could not be launched.": "Nepavyko paleisti atnaujinimo priemonės.", + "The operating system did not start the installer process.": "Operacinė sistema nepaleido įdiegiklio proceso.", + "UniGetUI is being updated...": "„UniGetUI“ yra naujinamas...", + "Update installed.": "Atnaujinimas įdiegtas.", + "UniGetUI was updated successfully, but this running copy was not replaced. This usually means you are running a development build. Close this copy and start the newly-installed version to finish.": "„UniGetUI“ sėkmingai atnaujinta, tačiau ši veikianti kopija nebuvo pakeista. Paprastai tai reiškia, kad naudojate kūrimo versiją. Uždarykite šią kopiją ir paleiskite naujai įdiegtą versiją, kad užbaigtumėte.", + "The update could not be applied.": "Atnaujinimo pritaikyti nepavyko.", + "Installer exit code {0}: {1}": "Įdiegiklio išėjimo kodas {0}: {1}", + "Update cancelled.": "Atnaujinimas atšauktas.", + "Authentication was cancelled.": "Autentifikavimas atšauktas.", + "Installer exit code {0}": "Įdiegiklio išėjimo kodas {0}", + "Operation in progress": "Operacija vykdoma", + "Please wait...": "Prašome palaukti...", + "Success!": "Sėkmė!", + "Failed": "Nepavyko", + "An error occurred while processing this package": "Apdorojant šį paketą įvyko klaida:", + "Installer": "Įdiegiklis", + "Executable": "Vykdomasis failas", + "MSI": "MSI", + "Compressed file": "Suglaudintas failas", + "MSIX": "MSIX", + "WinGet was repaired successfully": "„WinGet“ buvo sėkmingai sutaisytas", + "It is recommended to restart UniGetUI after WinGet has been repaired": "Yra rekomenduojama perleisti „UniGetUI“ po to, kai „WinGet“ buvo sutaisytas", + "WinGet could not be repaired": "Nebuvo galima sutaisyti „WinGet“", + "An unexpected issue occurred while attempting to repair WinGet. Please try again later": "Įvyko netikėta problema/klaida, kol buvo bandoma taisyti „WinGet“. Prašome bandyti dar kartą, vėlesniu laiku", + "Log in to enable cloud backup": "Prisijunkite, kad įjungtumėte debesies atsarginę kopiją", + "Backup Failed": "Nepavyko sukurti atsargines kopijos", + "Downloading backup...": "Atsisiunčiama atsarginė kopija...", + "An update was found!": "Buvo rastas (at-)naujinimas/-ys!", + "{0} can be updated to version {1}": "„{0}“ gali būti atnaujintas į – {1}", + "Updates found!": "Atnaujinimai rasti!", + "{0} packages can be updated": "{0} {0, plural, one {paketas} few {paketai} other {paketų}} gali būti atnaujinti", + "{0} is being updated to version {1}": "„{0}“ yra atnaujinama/-s į versiją – „{1}“", + "{0} packages are being updated": "{0} {0, plural, one {paketas} few {paketai} other {paketų}} yra atnaujinamas/naujinamas (-inami/-ama)", + "You have currently version {0} installed": "Jūsų dabartinė įdiegta versija – {0}", + "Desktop shortcut created": "Sukurta darbalaukio nuoroda", + "UniGetUI has detected a new desktop shortcut that can be deleted automatically.": "„UniGetUI“ aptiko naują darbalaukio nuorodą, kuri gali būti ištrinta automatiškai.", + "{0} desktop shortcuts created": "Sukurta {0} darbalaukio sparčiųjų klavišų", + "UniGetUI has detected {0} new desktop shortcuts that can be deleted automatically.": "„UniGetUI“ aptiko {0} naujus darbalaukio sparčiuosius klavišus, kuriuos galima ištrinti automatiškai.", + "Attention required": "Reikalauja dėmesio", + "Restart required": "Reikalingas paleidimas iš naujo", + "1 update is available": "Pasiekiamas 1-as (at-)naujinimas/-ys", + "{0} updates are available": "Pasiekiama/-s/-i {0} {0, plural, one {(at-)naujinimas/naujinys} few {(at-)naujinimai/naujiniai} other {(at-)naujinimų/naujinių}", + "Everything is up to date": "Viskas yra atnaujinta (Liuks!)", + "Discover Packages": "Atrasti paketus", + "Available Updates": "Pasiekiami (at-)naujinimai/-iai", + "Installed Packages": "Įdiegti paketai", + "UniGetUI Version {0} by Devolutions": "„UniGetUI“ versija {0}, „Devolutions“", + "Show UniGetUI": "Rodyti „UniGetUI“", + "Quit": "Išeiti", + "Are you sure?": "Ar Jūs esate tikras (-a)?", + "Do you really want to uninstall {0}?": "Ar Jūs tikrai norite išdiegti – „{0}“?", + "Do you really want to uninstall the following {0} packages?": "Ar Jūs tikrai norite išdiegti nurodomą/-us – {0} paketą/-us?", + "No": "Ne", + "Yes": "Taip", + "Partial": "Dalinai", + "View on UniGetUI": "Peržiūrėti per „UniGetUI“", + "Update": "Atnaujinti", + "Open UniGetUI": "Atidaryti „UniGetUI“", + "Update all": "Atnaujinti visus", + "Update now": "(At-)Naujinti dabar", + "Installer host changed since the installed version.\n": "Įdiegiklio pagrindinis kompiuteris pasikeitė nuo įdiegtos versijos.\n", + "This package is on the queue": "Šis paketas yra eilėje", + "installing": "(į-)diegiama/-s", + "updating": "atnaujinama", + "uninstalling": "išdiegiama/-s", + "installed": "įdiegta/-s", + "Retry": "Bandyti dar kartą", + "Install": "Įdiegti", + "Uninstall": "Išdiegti", + "Open": "Atidaryti", + "Operation profile:": "Operacijos/-nis profilis:", + "Follow the default options when installing, upgrading or uninstalling this package": "Sekti numatytąsias parinktis, kai (į-)diegiate, (at-)naujinate ar išdiegiate šį paketą", + "The following settings will be applied each time this package is installed, updated or removed.": "Toliau esantys nustatymai bus pritaikyti kiekvieną kartą, kai šis paketas yra įdiegtas, atnaujintas ar pašalintas.", + "Version to install:": "Versija, kurią įdiegti:", + "Architecture to install:": "Architektūra, kurią įdiegti:", + "Installation scope:": "Įdiegimo sritis:", + "Install location:": "Įdiegimo vietovė:", + "Select": "Pažymėti", + "Reset": "Atstatyti", + "Custom install arguments:": "Pasirinktiniai (į-)diegimo argumentai:", + "Custom update arguments:": "Pasirinktiniai (at-)naujinimo/-io (-ų/-ių) argumentai:", + "Custom uninstall arguments:": "Pasirinktiniai išdiegimo argumentai:", + "Pre-install command:": "Parengtinė (į-)diegimo komanda:", + "Post-install command:": "Paskesnioji (į-)diegimo komanda:", + "Abort install if pre-install command fails": "Nutraukti (į-)diegimą, jei parengtinė (į-)diegimo komanda patiria klaidą", + "Pre-update command:": "Parengtinė (at-)naujinimo komanda:", + "Post-update command:": "Paskesnioji (at-)naujinimo komanda:", + "Abort update if pre-update command fails": "Nutraukti (at-)naujinimą, jei parengtinė (at-)naujinimo komanda patiria klaidą", + "Pre-uninstall command:": "Parengtinė išdiegimo komanda:", + "Post-uninstall command:": "Paskesnioji išdiegimo komanda:", + "Abort uninstall if pre-uninstall command fails": "Nutraukti išdiegimą, jei parengtinė išdiegimo komanda patiria klaidą", + "Command-line to run:": "Komandos/-ų eilutė, kurią vykdyti:", + "Save and close": "Išsaugoti ir uždaryti", + "General": "Bendrieji", + "Architecture & Location": "Architektūra ir vieta", + "Command-line": "Komandų eilutė", + "Close apps": "Uždaryti programas", + "Pre/Post install": "Prieš / po diegimo", + "Select the processes that should be closed before this package is installed, updated or uninstalled.": "Pasirinkite procesus, kurie turi būti uždaryti prieš įdiegiant, atnaujinant ar pašalinant šį paketą.", + "Write here the process names here, separated by commas (,)": "Čia įrašykite procesų pavadinimus, atskirtus kableliais (,)", + "Try to kill the processes that refuse to close when requested to": "Bandykite nutraukti procesus, kurie atsisako užsidaryti paprašius", + "Run as admin": "Vykdyti kaip administratorių", + "Interactive installation": "Sąveikaujantis įdiegimas", + "Skip hash check": "Praleisti maišos patikrą", + "Uninstall previous versions when updated": "Išdiegti buvusias versijas, kai atnaujinsime", + "Skip minor updates for this package": "Praleisti smulkius (at-)naujinimus šiam paketui", + "Automatically update this package": "Automatiškai atnaujinti šį paketą", + "{0} installation options": "„{0}“ įdiegimo parinktys", + "Latest": "Paskiausias/Naujausias", + "PreRelease": "Išankstinis išleidimas", + "Default": "Numatyta/-s", + "Manage ignored updates": "Tvarkyti ignoruotus atnaujinimus", + "The packages listed here won't be taken in account when checking for updates. Double-click them or click the button on their right to stop ignoring their updates.": "Paketai pateikti čia nebus įtraukiami, kai tikrinama ar yra atnaujinimų. Du kart spaustelėjus ar paspaudus ant mygtuko jo dešinėje sustabdys jų atnaujinimus.", + "Reset list": "Atstatyti sąrašą", + "Do you really want to reset the ignored updates list? This action cannot be reverted": "Ar tikrai norite atkurti ignoruojamų naujinimų sąrašą? Šio veiksmo negalima atšaukti.", + "No ignored updates": "Nėra ignoruojamų naujinimų", + "Package Name": "Paketo pavadinimas", + "Package ID": "Paketo ID", + "Ignored version": "Ignoruota versija", + "New version": "Naują versiją", + "Source": "Šaltinį", + "All versions": "Visos versijos", + "Unknown": "Nežinoma/-s", + "Up to date": "Naudojate naujausią/paskiausią versijos leidinį", + "Package {name} from {manager}": "Paketas „{name}“ iš „{manager}“", + "Remove {0} from ignored updates": "Pašalinti „{0}“ iš ignoruojamų naujinimų", + "Cancel": "Atšaukti", + "Administrator privileges": "Administratoriaus privilegijos", + "This operation is running with administrator privileges.": "Ši operacija veikia su administratoriaus privilegijom.", + "Interactive operation": "Interaktyvus veiksmas", + "This operation is running interactively.": "Šis veiksmas vykdomas interaktyviai.", + "You will likely need to interact with the installer.": "Jums greičiausiai reikės sąveikauti su įdiegikliu.", + "Integrity checks skipped": "Vientisumo patikrinimai praleisti", + "Integrity checks will not be performed during this operation.": "Atliekant šią operaciją vientisumo patikros nebus vykdomos.", + "Proceed at your own risk.": "Tęskite savo nuožiūra.", + "Close": "Uždaryti/Užverti", + "Loading...": "Įkeliama...", + "Installer SHA256": "Įdiegiklio „SHA256“", + "Homepage": "Pagrindinis puslapis", + "Author": "Autorius/-ė", + "Publisher": "Leidė́jas", + "License": "Licencija", + "Manifest": "Manifestas", + "Installer Type": "Įdiegiklio tipas", + "Size": "Dydis", + "Installer URL": "Įdiegiklio „URL“ – saitas", + "Last updated:": "Paskutinį kartą atnaujinta:", + "Release notes URL": "Išleidimo užrašų „URL“ – saitas", + "Package details": "Paketo išsamumas", + "Dependencies:": "Priklausomybės:", + "Release notes": "Išleidimo užrašai", + "Screenshots": "Ekrano kopijos", + "This package has no screenshots or is missing the icon? Contribute to UniGetUI by adding the missing icons and screenshots to our open, public database.": "Šis paketas neturi ekrano kopijų arba jam trūksta piktogramos? Prisidėkite prie „UniGetUI“ pridėdami trūkstamas piktogramas ir ekrano kopijas į mūsų atvirą viešą duomenų bazę.", + "Version": "Versiją", + "Install as administrator": "Įdiegti kaip administratorių", + "Update to version {0}": "Atnaujinti į versiją – {0}", + "Installed Version": "Įdiegta versija:", + "Update as administrator": "Atnaujinti kaip administratorius", + "Interactive update": "Sąveikaujantis (at-)naujinimas", + "Uninstall as administrator": "Išdiegti kaip administratorius", + "Interactive uninstall": "Sąveikaujantis išdiegimas", + "Uninstall and remove data": "Išdiegti ir pašalinti duomenis", + "Not available": "Nepasiekiama/-s", + "Installer SHA512": "Įdiegiklio „SHA512“", + "Unknown size": "Nežinomas dydis", + "No dependencies specified": "Priklausomybės nenurodytos", + "mandatory": "privaloma/-s", + "optional": "pasirinktina/-s", + "UniGetUI {0} is ready to be installed.": "„UniGetUI“ – {0} yra pasiruošusi/-ęs būti įdiegta/-s.", + "The update process will start after closing UniGetUI": "Atnaujinimo vyksmas prasidės po „UniGetUI“ uždarymo", + "UniGetUI has been ran as administrator, which is not recommended. When running UniGetUI as administrator, EVERY operation launched from UniGetUI will have administrator privileges. You can still use the program, but we highly recommend not running UniGetUI with administrator privileges.": "„UniGetUI“ paleista administratoriaus teisėmis, o tai nerekomenduojama. Kai „UniGetUI“ veikia su administratoriaus teisėmis, KIEKVIENA iš „UniGetUI“ paleista operacija taip pat turės administratoriaus teises. Programa vis tiek gali būti naudojama, tačiau primygtinai rekomenduojame nepaleisti „UniGetUI“ administratoriaus teisėmis.", + "Share anonymous usage data": "Siųsti anoniminius naudojimo duomenis", + "UniGetUI collects anonymous usage data in order to improve the user experience.": "„UniGetUI“ surenka anonimišką naudojimosi duomenis, siekiant patobulinti naudotojo/vartotojo patirtį.", + "Accept": "Priimti", + "Software Updates": "Taikomieji atnaujinimai", + "Package Bundles": "Paketo/-ų rinkiniai", + "Settings": "Nustatymai", + "Package Managers": "Paketų tvarkytuvai/-ės", + "UniGetUI Log": "„UniGetUI“ žurnalas", + "Package Manager logs": "Paketų tvarkytuvo/-ės žurnalai", + "Operation history": "Operacijos istorija", + "Help": "Pagalba", + "UniGetUI": "UniGetUI", + "You have installed UniGetUI Version {0}": "Jūs esate įdiegę „UniGetUI“ versiją – {0}", + "Disclaimer": "Atsakomýbės ribójimas", + "UniGetUI is developed by Devolutions and is not affiliated with any of the compatible package managers.": "„UniGetUI“ kuria „Devolutions“ ir ji nėra susijusi su jokiais suderinamais paketų tvarkytuvais.", + "UniGetUI wouldn't have been possible without the help of the contributors. Thank you all 🥳": "UniGetUI nebūtų galima sukurti be visų prisidėjusių pagalbos. Ačiū Jums visiems! 🥳", + "UniGetUI uses the following libraries. Without them, UniGetUI wouldn't have been possible.": "„UniGetUI“ naudoja šias bibliotekas. Be jų, „UniGetUI“ nebūtų įmanomas.", + "{0} homepage": "Pagrindinis tinklalapio puslapis – {0}", + "UniGetUI has been translated to more than 40 languages thanks to the volunteer translators. Thank you 🤝": "„UniGetUI“ buvo išverstas į daugiau, nei 40 kalbų, savanorių vertėjų dėka. Ačiū/Dėkui/Diekoju Jums! 🤝", + "Verbose": "Plačiai/Išsamiai/Daugiažodiškai", + "1 - Errors": "1 – Klaidos", + "2 - Warnings": "2 – Įspėjimai", + "3 - Information (less)": "3 – Informacija (mažiau)", + "4 - Information (more)": "4 – Informacija (daugiau)", + "5 - information (debug)": "5 – Informacija (klaidų šalinimui)", + "Warning": "Įspėjimas", + "The following settings may pose a security risk, hence they are disabled by default.": "Toliau pateikti nustatymai gali kelti saugumo riziką, todėl pagal numatytuosius nustatymus jie yra išjungti.", + "Enable the settings below if and only if you fully understand what they do, and the implications they may have.": "Įjunkite toliau pateiktus nustatymus TIK TADA, jei visiškai suprantate, ką jie daro ir kokias pasekmes bei pavojus jie gali sukelti.", + "The settings will list, in their descriptions, the potential security issues they may have.": "Nustatymų aprašuose bus nurodytos galimos saugumo problemos, kurias jie gali sukelti.", + "The backup will include the complete list of the installed packages and their installation options. Ignored updates and skipped versions will also be saved.": "Atsarginė kopija įtraukia pilnąjį įdiegtų paketų sąrašą su jų įdiegimo parinktys. Ignoruojami atnaujinimai ir praleistos versijos irgi yra išsaugomos.", + "The backup will NOT include any binary file nor any program's saved data.": "Atsarginė kopija NEĮTRAUKIA jokių dvejetainių failų, nei jokių programų/-ėlių išsaugotų duomenų.", + "The size of the backup is estimated to be less than 1MB.": "Atsarginės kopijos dydis yra numatomas, kad bus mažesnis nei – 1MB.", + "The backup will be performed after login.": "Atsarginės kopija bus atlikta po prisijungimo.", + "{pcName} installed packages": "Įdiegti paketai – {pcName}", + "Current status: Not logged in": "Dabartinė būsena: Neprisijungęs/-usi", + "You are logged in as {0} (@{1})": "Esate prisijungę kaip {0} (@{1})", + "Nice! Backups will be uploaded to a private gist on your account": "Puiku! Atsarginės kopijos bus įkeltos į privatų „gist“ jūsų paskyroje", + "Select backup": "Pasirinkti atsarginę kopiją", + "Settings imported from {0}": "Nustatymai importuoti iš {0}", + "UniGetUI Settings": "„UniGetUI“ nustatymai", + "Settings exported to {0}": "Nustatymai eksportuoti į {0}", + "UniGetUI settings were reset": "„UniGetUI“ nustatymai buvo atstatyti", + "Allow pre-release versions": "Leisti išankstines versijas", + "Apply": "Pritaikyti", + "For security reasons, custom command-line arguments are disabled by default. Go to UniGetUI security settings to change this.": "Saugumo sumetimais pasirinktiniai komandų eilutės argumentai pagal numatytuosius nustatymus yra išjungti. Norėdami tai pakeisti, eikite į „UniGetUI“ saugumo nustatymus.", + "Go to UniGetUI security settings": "Eiti į „UniGetUI“ saugumo nustatymus", + "The following options will be applied by default each time a {0} package is installed, upgraded or uninstalled.": "Toliau pateiktos parinktys bus taikomos pagal numatytuosius nustatymus kiekvieną kartą, kai {0} paketas bus įdiegtas, atnaujintas arba pašalintas.", + "Package's default": "Numatytoji paketo parinktis", + "Install location can't be changed for {0} packages": "Diegimo vietos negalima pakeisti {0} paketams", + "The local icon cache currently takes {0} MB": "Vietinė/-is piktogramų talpykla/podėlis užima – {0} MB", + "Username": "Naudotojo/Vartotojo vardas (t.y. Slapyvardis)", + "Password": "Slaptažodis", + "Credentials": "Prisijungimo duomenys", + "It is not guaranteed that the provided credentials will be stored safely": "Nėra garantijos, kad pateikti prisijungimo duomenys bus saugiai saugomi", + "Partially": "Dalinai", + "Package manager": "Paketų tvarkytuvas/-ė", + "Compatible with proxy": "Suderintas su įgaliotiniu", + "Compatible with authentication": "Palaikomas su autentifikavimu", + "Proxy compatibility table": "Įgaliotinių/-ųjų suderinimo lentelė", + "{0} settings": "„{0}“ nustatymai", + "{0} status": "{0} būsena", + "Default installation options for {0} packages": "Numatytosios (į-)diegimo parinktys – „{0}“ paketams", + "Expand version": "Išplėsti versiją", + "The executable file for {0} was not found": "Vykdomasis failas, skirtas – „{0}“, nebuvo rastas", + "{pm} is disabled": "„{pm}“ išjungta/išgalinta (-s)", + "Enable it to install packages from {pm}.": "Įjunkite/Įgalinkite jį, norint įdiegti paketą/-us iš – „{pm}“.", + "{pm} is enabled and ready to go": "„{pm}“ yra įjungta/įgalinta (-s) ir pasiruošusi/-ęs", + "{pm} version:": "„{pm}“ versija:", + "{pm} was not found!": "„{pm}“ nebuvo rasta/-s!", + "You may need to install {pm} in order to use it with UniGetUI.": "Kad galėtumėte naudoti „UniGetUI“, jums gali tekti į(-si)diegti – „{pm}“.", + "Scoop Installer - UniGetUI": "„Scoop“ įdiegiklis – „UniGetUI“", + "Scoop Uninstaller - UniGetUI": "„Scoop“ išdiegiklis – „UniGetUI“", + "Clearing Scoop cache - UniGetUI": "Išvaloma/-s „Scoop“ talpykla/podėlis – „UniGetUI“", + "Restart UniGetUI to fully apply changes": "Iš naujo paleiskite „UniGetUI“, kad pakeitimai būtų visiškai pritaikyti", + "Restart UniGetUI": "Iš naujo paleisti – „UniGetUI“", + "Manage {0} sources": "Tvarkyti – „{0}“ šaltinius", + "Add source": "Pridėti šaltinį", + "Add": "Pridėti", + "Source name": "Šaltinio pavadinimas", + "Source URL": "Šaltinio URL", + "Other": "Kita/-s/-i", + "No minimum age": "Be minimalaus senumo", + "1 day": "1-ai dienai", + "{0} days": "{0} {0, plural, one {diena} few {dienas/-os/-om} other {dienų}}", + "Custom...": "Pasirinktinė...", + "{0} minutes": "{0} {0, plural, one {minutė} few {minutės/-ėm} other {minučių}}", + "1 hour": "1-ai valandai", + "{0} hours": "{0} {0, plural, one {valanda} few {valandas/-os/-om} other {valandų}}", + "1 week": "1-ai savaitei", + "Supports release dates": "Palaiko išleidimo datas", + "Release date support per package manager": "Išleidimo datų palaikymas pagal paketų tvarkytuvę", + "Search for packages": "Ieškoti paketų", + "Local": "Vietinis", + "OK": "Gerai", + "Last checked: {0}": "Paskutinį kartą tikrinta: {0}", + "{0} packages were found, {1} of which match the specified filters.": "{0} {0, plural, one {paketas} few {paketai} other {paketų}} buvo rastas/-i/-ų iš kurių {1} sutampa su esamais/pritaikytais filtrais.", + "{0} selected": "Pasirinkta {0}", + "(Last checked: {0})": "(Paskutinį kartą tikrinta: {0})", + "All packages selected": "Visi paketai pažymėti", + "Package selection cleared": "Paketų žymėjimas atšauktas", + "{0}: {1}": "{0}: {1}", + "More info": "Daugiau informacijos", + "GitHub account": "GitHub paskyra", + "Log in with GitHub to enable cloud package backup.": "Prisijunkite su „GitHub“, kad įjungtumėte/įgalintumėte debesijos paketų atsarginių kopijų vykdymą.", + "More details": "Daugiau išsamumo", + "Log in": "Prisijungti", + "If you have cloud backup enabled, it will be saved as a GitHub Gist on this account": "Jeigu Jūs turite atsarginių kopijų kūrimą įjungtą/įgalintą debesijoje, tada jis bus išsaugotas kaip „GitHub Gist“ šioje paskyroje.", + "Log out": "Atsijungti", + "About UniGetUI": "Apie „UniGetUI“", + "About": "Apie", + "Third-party licenses": "Trečios šalies licencija", + "Contributors": "Talkininkai", + "Translators": "Vertėjai", + "Bundle security report": "Rinkinio saugumo ataskaita", + "The bundle contained restricted content": "Rinkinyje buvo ribojamo turinio", + "UniGetUI – Crash Report": "„UniGetUI“ – strigties ataskaita", + "UniGetUI has crashed": "„UniGetUI“ užstrigo", + "Help us fix this by sending a crash report to Devolutions. All fields below are optional.": "Padėkite mums tai ištaisyti, atsiųsdami strigties ataskaitą „Devolutions“. Visi toliau pateikti laukai yra neprivalomi.", + "Email (optional)": "El. paštas (neprivaloma)", + "your@email.com": "jusu@elpastas.lt", + "Additional details (optional)": "Papildoma informacija (neprivaloma)", + "Describe what you were doing when the crash occurred…": "Aprašykite, ką darėte, kai įvyko strigis…", + "Crash report": "Strigties ataskaita", + "Don't Send": "Nesiųsti", + "Send Report": "Siųsti ataskaitą", + "Sending…": "Siunčiama…", + "Unsaved changes": "Neišsaugoti pakeitimai", + "You have unsaved changes in the current bundle. Do you want to discard them?": "Dabartiniame rinkinyje yra neišsaugotų pakeitimų. Ar norite juos atmesti?", + "Discard changes": "Atmesti pakeitimus", + "Integrity violation": "Vientisumo pažeidimas", + "UniGetUI or some of its components are missing or corrupt. It is strongly recommended to reinstall UniGetUI to adress the situation.": "Trūksta „UniGetUI“ arba kai kurių jos komponentų, arba jie yra sugadinti. Primygtinai rekomenduojama iš naujo įdiegti „UniGetUI“, kad išspręstumėte šią situaciją.", + "• Refer to the UniGetUI Logs to get more details regarding the affected file(s)": "• Peržvelkite „UniGetUI“ veikimo žurnalus, norint daugiau sužinoti apie paveiktą (-us) failą (-us)", + "• Integrity checks can be disabled from the Experimental Settings": "• Vientisumo patikrinimai gali būti išjungti/išgalinti per eksperimentinius nustatymus", + "Manage shortcuts": "Tvarkyti/Valdyti nuorodas", + "UniGetUI has detected the following desktop shortcuts which can be removed automatically on future upgrades": "„UniGetUI“ aptiko šias darbalaukio nuorodas, kurios gali būti ištrintos automatiškai po (ateities) atnaujinimų.", + "Do you really want to reset this list? This action cannot be reverted.": "Ar Jūs tikrai norite atstatyti šį sąrašą? Šis veiksmas negali būti anuliuotas.", + "Desktop shortcuts list": "Darbalaukio nuorodų sąrašas", + "Open in explorer": "Atidaryti failų naršyklėje", + "Remove from list": "Pašalinti iš sąrašo", + "When new shortcuts are detected, delete them automatically instead of showing this dialog.": "Kai aptinkami nauji spartieji klavišai, ištrinkite juos automatiškai, užuot rodę šį dialogą.", + "Not right now": "Ne dabar", + "Missing dependency": "Trūkstama priklausomybė", + "UniGetUI requires {0} to operate, but it was not found on your system.": "„UniGetUI“ reikalauja „{0}“, kad veiktu, bet ji/-s nebuvo rasta/-s Jūsų sistemoje.", + "Click on Install to begin the installation process. If you skip the installation, UniGetUI may not work as expected.": "Spauskite – „Įdiegti“ mygtuką, norint pradėti įdiegimo vyksmą. Jeigu Jūs praleisite įdiegimą, „UniGetUI“ galimai neveiks kaip derėtų. ", + "Alternatively, you can also install {0} by running the following command in a Windows PowerShell prompt:": "Kitu atveju, Jūs galite įdiegti – „{0}“ vykdant šią nurodančią komandą „Windows PowerShell“ lange:", + "Install {0}": "Įdiegti – „{0}“", + "Do not show this dialog again for {0}": "Neberodyti šio diologo lango „{0}“", + "Please wait while {0} is being installed. A black window may show up. Please wait until it closes.": "Prašome palaukti kol „{0}“ yra įdiegiama/-s. Juodas langas galimai atsiras. Prašome palaukti, kol ji/-s užsidarys.", + "{0} has been installed successfully.": "„{0}“ buvo sėkmingai įdiegtas.", + "Please click on \"Continue\" to continue": "Prašome paspausti – „Tęsti“, norint tęsti (pasiektas pasiekimas: Pirmieji žingsniai!)", + "Continue": "Tęsti", + "{0} has been installed successfully. It is recommended to restart UniGetUI to finish the installation": "„{0}“ buvo sėkmingai įdiegtas. Yra rekomenduojama, kad perleistumėte „UniGetUI“, kad užbaigtų įdiegimą", + "Restart later": "Paleisti iš naujo vėliau", + "An error occurred:": "Įvyko klaida:", + "Please see the Command-line Output or refer to the Operation History for further information about the issue.": "Prašome peržiūrėti komandinės eilutės išvestį arba telkitės – „Operacijos istorijos“, norint gauti daugiau informacijos apie tam tikrą bėdą.", + "Retry as administrator": "Bandyti dar kartą, kaip administratorius", + "Retry interactively": "Bandyti dar kartą interaktyviai", + "Retry skipping integrity checks": "Bandyti dar kartą, praleidžiant vientisumo patikrinimus", + "Installation options": "Įdiegimo parinktys", + "Save": "Išsaugoti", + "UniGetUI collects anonymous usage data with the sole purpose of understanding and improving the user experience.": "„UniGetUI“ surenka anonimišką naudojimosi duomenis su esmine paskirtimi, siekiant suprasti ir patobulinti naudotojo/vartotojo patirtį.", + "More details about the shared data and how it will be processed": "Daugiau informacijos apie bendrinamus duomenis ir kaip jie bus apdorojami", + "Do you accept that UniGetUI collects and sends anonymous usage statistics, with the sole purpose of understanding and improving the user experience?": "Ar Jūs sutinkate, kad „UniGetUI“ rinks ir siųs anonimiškus programos naudojimo statinius duomenis, skirtus vien susipažinti ir patobulinti naudotojo/vartotojo patirtį?", + "Decline": "Atmesti/Nepriimti", + "No personal information is collected nor sent, and the collected data is anonimized, so it can't be back-tracked to you.": "Jokia asmeninė informacija nėra reikama ar siunčiama, o surinkti duomenys yra anonimizuoti (t.y. jie negali būti atsekti atgal, kad jie būtent Jūsų).", + "Navigation panel": "Naršymo skydelis", + "Operations": "Operacijos", + "Toggle operations panel": "Perjungti operacijų skydelį", + "Bulk operations": "Masinės operacijos", + "Retry failed": "Kartoti nepavykusias", + "Clear successful": "Išvalyti sėkmingas", + "Clear finished": "Išvalyti užbaigtas", + "Cancel all": "Atšaukti viską", + "More": "Daugiau", + "Toggle navigation panel": "Rodyti / slėpti naršymo skydelį", + "Minimize": "Sumažinti", + "Maximize": "Išdidinti", + "UniGetUI by Devolutions": "„UniGetUI“, „Devolutions“", + "UniGetUI is an application that makes managing your software easier, by providing an all-in-one graphical interface for your command-line package managers.": "„UniGetUI“ yra programa, kuri padeda tvarkyti/valdyti taikomąsias programas paprasčiau, pateikdama paprastą „viskas viename“ grafinę sąsają, skirtą komandines eilutes vykdantiems paketų tvarkytuvams/-ėms.", + "Useful links": "Naudingos nuorodos", + "UniGetUI Homepage": "„UniGetUI“ pradinis puslapis", + "Report an issue or submit a feature request": "Pranešti apie problemą arba pridėti funkcijų pasiūlymą", + "UniGetUI Repository": "„UniGetUI“ saugykla", + "View GitHub Profile": "Peržiūrėti „GitHub“ profilį", + "UniGetUI License": "„UniGetUI“ licencija", + "Using UniGetUI implies the acceptation of the MIT License": "„UniGetUI“ naudojimas, nurodo neišreikštinį „MIT“ licencijos priėmimą", + "Become a translator": "Tapkite vertėju", + "Go back": "Grįžti atgal", + "Go forward": "Eiti pirmyn", + "Go to home page": "Eiti į pradžios puslapį", + "Reload page": "Perkrauti puslapį", + "View page on browser": "Peržiūrėti puslapį naršyklėje", + "The built-in browser is not supported on Linux yet.": "Integruota naršyklė dar nepalaikoma Linux sistemoje.", + "Open in browser": "Atidaryti naršyklėje", + "Copy to clipboard": "Kopijuoti į mainų sritį", + "Export to a file": "Eksportuoti į failą", + "Log level:": "Žurnalo lygis:", + "Reload log": "Perkrovimų žurnalas", + "Export log": "Eksportuoti žurnalą", + "Text": "Tekstas", + "Change how operations request administrator rights": "Pakeisti kaip operacijos prašo administratoriaus teisių", + "Restrictions on package operations": "Apribojimai paketo/-ų operacijom/-s", + "Restrictions on package managers": "Apribojimai paketų tvarkytuvams/-ėms", + "Restrictions when importing package bundles": "Apribojimai importuojant paketo/-ų rinkinį/-ius", + "Ask for administrator privileges once for each batch of operations": "Klausti dėl administratoriaus teisių tik vieną kartą, kiekvienai operacijų partijai (veiksmo)", + "Ask only once for administrator privileges": "Klausti tik kartą dėl administratoriaus privilegijų", + "Prohibit any kind of Elevation via UniGetUI Elevator or GSudo": "Uždrausti bet kokį teisių pakėlimą per „UniGetUI Elevator“ arba „GSudo“", + "This option WILL cause issues. Any operation incapable of elevating itself WILL FAIL. Install/update/uninstall as administrator will NOT WORK.": "Ši parinktis PADARYS trukdžių. Bet kokia operacija negalinti išsiaukštinti savęs PATIRS KLAIDĄ. Įdiegimas/(At-)Naujinimas/Išdiegimas kaip administratorius NEVEIKS!", + "Allow custom command-line arguments": "Leisti pasirinktinius komandines eilutes argumentus", + "Custom command-line arguments can change the way in which programs are installed, upgraded or uninstalled, in a way UniGetUI cannot control. Using custom command-lines can break packages. Proceed with caution.": "Pasirinktinės komandinės eilutės argumentai, gali pakeisti kaip šios programos yra (į-)diegiamos, (at-)naujinamos ar išdiegiamos, tokiu būdu, kokiu „UniGetUI“ negali valdyti. Naudojant pasirinktines komandinės eilutės argumentus, gali sugadinti paketų veikimą. Tęskite atsargiai, pagal savo nuožiūra.", + "Ignore custom pre-install and post-install commands when importing packages from a bundle": "Leisti vykdyti pasirinktines priešdiegimo ir podiegimo komandas importuojant paketus iš rinkinio", + "Pre and post install commands will be run before and after a package gets installed, upgraded or uninstalled. Be aware that they may break things unless used carefully": "Parengtinės ir paskesniosios komandos bus vykdomos prieš, bei po to, kada paketas būna įdiegtas, atnaujintas ar išdiegtas. Būkite atidūs, kad jie galimai sugadins kažką, nebendrais viską atliekate atsargiai.", + "Allow changing the paths for package manager executables": "Leisti keisti paketų tvarkyklių vykdomųjų failų kelius", + "Turning this on enables changing the executable file used to interact with package managers. While this allows finer-grained customization of your install processes, it may also be dangerous": "Įjungus tai, galima keisti vykdomąjį failą, naudojamą bendravimui su paketų tvarkytuvais. Nors tai leidžia smulkiau pritaikyti diegimo procesus, tai taip pat gali būti pavojinga", + "Allow importing custom command-line arguments when importing packages from a bundle": "Leisti importuoti pasirinktinius komandų eilutės argumentus importuojant paketus iš rinkinio", + "Malformed command-line arguments can break packages, or even allow a malicious actor to gain privileged execution. Therefore, importing custom command-line arguments is disabled by default": "Netaisyklingi komandų eilutės argumentai gali sugadinti paketus ar net leisti piktavaliui gauti privilegijuotą vykdymą. Todėl pasirinktinių komandų eilutės argumentų importavimas pagal numatytuosius nustatymus yra išjungtas.", + "Allow importing custom pre-install and post-install commands when importing packages from a bundle": "Leisti importuoti pasirinktines parengtines ir paskesniąsias (į-)diegimo komandas, kai importuojami paketai iš rinkinio", + "Pre and post install commands can do very nasty things to your device, if designed to do so. It can be very dangerous to import the commands from a bundle, unless you trust the source of that package bundle": "Parengtinės ir paskesniosios įdiegimo komandos gali sukelti daug problemų Jūsų įrenginiui, jeigu piktavališki asmenys jas taip sukūrę. Importuoti šias komandas iš paketo/-ų rinkinio gali būti labai pavojinga, patartina nenaudoti jų, nebent pasitikite jais.", + "Administrator rights and other dangerous settings": "Administratoriaus teisės ir kiti pavojingi nustatymai", + "Package backup": "Atsarginės paketų kopijos", + "Cloud package backup": "Debesies paketų atsarginė kopija", + "Local package backup": "Vietinė paketų atsarginė kopija", + "Local backup advanced options": "Išplėstinės vietinės atsarginės kopijos parinktys", + "Log in with GitHub": "Prisijungti su „GitHub“", + "Log out from GitHub": "Atsijungti iš „GitHub“", + "Periodically perform a cloud backup of the installed packages": "Periodiškai atlikti debesijos atsarginės kopijos sukūrimą, įdiegtų paketų", + "Cloud backup uses a private GitHub Gist to store a list of installed packages": "Atsargines kopijas laikyti – debesija naudoja privatų „GitHub Gist“, kad laikytų įdiegtų paketų sąrašą", + "Perform a cloud backup now": "Atlikti debesies atsarginę kopiją dabar", + "Backup": "Sukurti atsarginę kopiją", + "Restore a backup from the cloud": "Atkurti atsarginę kopiją iš debesijos", + "Begin the process to select a cloud backup and review which packages to restore": "Pradėti debesijos pasirinkimo atsarginėj kopijai vyksmą ir apžiūrėkite kuriuos paketus atkurti", + "Periodically perform a local backup of the installed packages": "Periodiškai atlikti vietinę atsarginės kopijos sukūrimą, įdiegtų paketų", + "Perform a local backup now": "Atlikti vietinę atsarginę kopiją dabar", + "Change backup output directory": "Pakeisti atsarginės kopijos išvesties katalogą", + "Set a custom backup file name": "Nustatykite pasirinktinį atsarginės kopijos, failo pavadinimą", + "Leave empty for default": "Numatytai, palikti tuščią", + "Add a timestamp to the backup file names": "Pridėti laiko žymę prie atsarginių failų pavadinimų", + "Backup and Restore": "Sukurti atsarginę kopiją ir atkurti", + "Enable background api (UniGetUI Widgets and Sharing, port 7058)": "Įjungti foninį „API“ („UniGetUI“ valdikliai ir bendrinimas, prievadas – 7058)", + "Wait for the device to be connected to the internet before attempting to do tasks that require internet connectivity.": "Palaukite, kol įrenginys prisijungs prie interneto, prieš bandydami atlikti užduotis, kurioms reikalingas interneto ryšys.", + "Disable the 1-minute timeout for package-related operations": "Išjungti/Išgalinti vienos minutės laukimo laiką, vykdant (susijusio/-ų) paketo/-ų operacijas", + "Use installed GSudo instead of UniGetUI Elevator": "Naudoti įdiegtą „GSudo“ vietoj „UniGetUI Elevator“", + "Use a custom icon and screenshot database URL": "Naudoti pasirinktinę piktogramą ir ekranų kopijų/iškarpų duomenų bazės „URL“ – saitą", + "Enable background CPU Usage optimizations (see Pull Request #3278)": "Įjungti/Įgalinti fonines „CPU“ naudosenos optimizacijas (peržiūrėti „Pull Request #3278“)", + "Perform integrity checks at startup": "Atlikti vientisumo patikrinimus paleidimo metu", + "When batch installing packages from a bundle, install also packages that are already installed": "Kai paketai iš rinkinio diegiami paketu, taip pat įdiekite jau įdiegtus paketus", + "Experimental settings and developer options": "Eksperimentiniai nustatymai ir kūrėjo parinktys", + "Show UniGetUI's version and build number on the titlebar.": "Rodyti „UniGetUI“ versiją ant lango antraštės juostos", + "Language": "Kalba", + "UniGetUI updater": "„UniGetUI“ atnaujinimo priemonė", + "Telemetry": "Telemètrija", + "Manage UniGetUI settings": "Tvarkyti ir valdyti „UniGetUI“ nustatymus", + "Related settings": "Susiję nustatymai", + "Update UniGetUI automatically": "Automatiškai (at-)naujinti „UniGetUI“", + "Check for updates": "Tikrinti, ar yra (at-)naujinimų/-ių", + "Install prerelease versions of UniGetUI": "Įdiegti išankstines „UniGetUI“ versijas", + "Manage telemetry settings": "Tvarkyti/Valdyti telemetrijos nustatymus", + "Manage": "Tvarkyti/Valdyti", + "Import settings from a local file": "Importuoti nustatymus iš vietinio failo", + "Import": "Importuoti", + "Export settings to a local file": "Eksportuoti nustatymus į failą", + "Export": "Eksportuoti", + "Reset UniGetUI": "Atstatyti „UniGetUI“", + "User interface preferences": "Naudotojo/Vartotojo sąsajos nuostatos", + "Application theme, startup page, package icons, clear successful installs automatically": "Programos apipavidalinimas, paleisties puslapis, paketo/-ų piktogramos ir išvalyti sėkmingus įdiegimus automatiškai.", + "General preferences": "Bendros parinktys", + "UniGetUI display language:": "„UniGetUI“ programos atvaizdavimo kalba:", + "System language": "Sistemos kalba", + "Is your language missing or incomplete?": "Ar Jūsų kalba nepasiekiama ar neužbaigta?", + "Appearance": "Išvaizda", + "UniGetUI on the background and system tray": "„UniGetUI“ fone ir sistemos dėkle", + "Package lists": "Paketų sąrašai", + "Use classic mode": "Naudoti klasikinį režimą", + "Restart UniGetUI to apply this change": "Paleiskite „UniGetUI“ iš naujo, kad pritaikytumėte šį pakeitimą", + "The classic UI is disabled for beta testers": "Klasikinė naudotojo sąsaja išjungta beta testuotojams", + "Close UniGetUI to the system tray": "Uždaryti „UniGetUI“ į sistemos juostelę", + "Manage UniGetUI autostart behaviour": "Valdyti „UniGetUI“ automatinio paleidimo elgseną", + "Show package icons on package lists": "Rodyti paketų piktogramas, paketų sąraše", + "Clear cache": "Išvalyti talpyklą/podėlį", + "Select upgradable packages by default": "Pasirinkti/Pažymėti atnaujinamus paketus numatytai", + "Light": "Šviesus", + "Dark": "Tamsus", + "Follow system color scheme": "Sekti sistemos spalvų schemą/parinktį", + "Application theme:": "Programos apipavidalinimas:", + "UniGetUI startup page:": "„UniGetUI“ paleisties puslapis:", + "Proxy settings": "Įgaliotinių/-ųjų nustatymai", + "Other settings": "Kiti nustatymai", + "Connect the internet using a custom proxy": "Prijunkite internetą naudojant pasirinktinį įgaliotąjį serverį", + "Please note that not all package managers may fully support this feature": "Atkreipkite dėmesį, kad ne visi paketų tvarkytuvai gali visiškai palaikyti šią funkciją", + "Proxy URL": "Įgaliotojo/-inio „URL“ – saitas", + "Enter proxy URL here": "Įveskite įgaliotojo „URL“ – saitą čia", + "Authenticate to the proxy with a user and a password": "Autentifikuotis tarpiniame serveryje naudojant naudotojo vardą ir slaptažodį", + "Internet and proxy settings": "Interneto ir tarpinio serverio nustatymai", + "Package manager preferences": "Paketų tvarkytuvo/-ės nuostatos", + "Ready": "Paruošta/-s", + "Not found": "Nerasta/-s", + "Notification preferences": "Pranešimų parinktys", + "Notification types": "Pranešimų tipai", + "The system tray icon must be enabled in order for notifications to work": "Kad pranešimai veiktų, sistemos dėklo piktograma turi būti įjungta", + "Enable UniGetUI notifications": "Įjungti „UniGetUI“ pranešimus", + "Show a notification when there are available updates": "Rodyti pranešimą, kai yra pasiekiami atnaujinimai", + "Show a silent notification when an operation is running": "Rodyti tylų pranešimą, kai operacija yra vykdoma", + "Show a notification when an operation fails": "Rodyti pranešimą, kai operacija nepavyksta ar patiria klaidą", + "Show a notification when an operation finishes successfully": "Rodyti pranešimą, kai operacija pavyksta ar baigia be problemų", + "Concurrency and execution": "Lygiagretumas ir vykdymas", + "Automatic desktop shortcut remover": "Automatinis/-iškas darbalaukio nuorodų nuėmiklis/nuimtuvas/naikiklis/šalintuvas (-ė).\n\n", + "Choose how many operations should be performed in parallel": "Pasirinkite, kiek operacijų turi būti vykdoma lygiagrečiai", + "Clear successful operations from the operation list after a 5 second delay": "Išvalyti sėkmingas operacijas iš operacijų sąrašo po 5-ių sekundžių atidėjimo", + "Download operations are not affected by this setting": "Atsisiuntimo operacijos nėra paveiktos šio nustatymo", + "You may lose unsaved data": "Jūs galimai prarasite visus neišsaugotus duomenis", + "Ask to delete desktop shortcuts created during an install or upgrade.": "Klausti, ar ištrinti darbalaukio nuorodas, kurios buvo sukurtas (į-)diegimo ar (at-)naujinimo metu.", + "Package update preferences": "Paketų (at-)naujinimų parinktys ir nuostatos", + "Update check frequency, automatically install updates, etc.": "Atnaujinimų tikrinimo dažnis, automatinis atnaujinimų diegimas ir kt.", + "Reduce UAC prompts, elevate installations by default, unlock certain dangerous features, etc.": "Sumažinti UAC užklausų skaičių, pagal numatytuosius nustatymus pakelti teises diegimams, atrakinti tam tikras pavojingas funkcijas ir t. t.", + "Package operation preferences": "Paketų operacijų parinktys ir nuostatos", + "Enable {pm}": "Įjungti/Įgalinti „{pm}“", + "Not finding the file you are looking for? Make sure it has been added to path.": "Nerandate ieškomo failo? Įsitikinkite, kad jis pridėtas prie kelio.", + "Select the executable to be used. The following list shows the executables found by UniGetUI": "Pasirinkite vykdomąjį, kurį norite naudoti. Toliau pateikiamas sąrašas parodo, visus vykdomuosius, kuriuos rado „UniGetUI“.", + "For security reasons, changing the executable file is disabled by default": "Numatytai dėl saugumo priežasčių, vykdomojo failo keitimas yra negalimas.", + "Change this": "Pakeisti tai/šį/šitą", + "Copy path": "Kopijuoti kelią", + "Current executable file:": "Dabartinis vykdomasis failas:", + "Ignore packages from {pm} when showing a notification about updates": "Rodydami pranešimą apie atnaujinimus, ignoruokite paketus iš {pm}", + "Update security": "Naujinimų sauga", + "Use global setting": "Naudoti bendrąjį nustatymą", + "Minimum age for updates": "Minimalus naujinimų senumas", + "e.g. 10": "pvz., 10", + "Custom minimum age (days)": "Pasirinktinis minimalus senumas (dienomis)", + "{pm} does not provide release dates for its packages, so this setting will have no effect": "{pm} nepateikia savo paketų išleidimo datų, todėl šis nustatymas neturės jokio poveikio", + "{pm} only provides release dates for some of its packages, so this setting will only apply to those packages": "„{pm}“ pateikia leidimo datas tik kai kuriems savo paketams, todėl šis nustatymas bus taikomas tik jiems", + "Override the global minimum update age for this package manager": "Nepaisyti bendro minimalaus naujinimų senumo šiai paketų tvarkytuvei", + "View {0} logs": "Peržiūrėti {0} žurnalus", + "If Python cannot be found or is not listing packages but is installed on the system, ": "Jei „Python“ nepavyksta rasti arba ji nerodo paketų, nors sistemoje yra įdiegta, ", + "Advanced options": "Pažangios parinktys", + "WinGet command-line tool": "„WinGet“ komandų eilutės įrankis", + "Choose which command-line tool UniGetUI uses for WinGet operations when the COM API is not used": "Pasirinkite, kurį komandų eilutės įrankį „UniGetUI“ naudos WinGet operacijoms, kai COM API nenaudojama", + "WinGet COM API": "„WinGet“ COM API", + "Choose whether UniGetUI can use the WinGet COM API before falling back to the command-line tool": "Pasirinkite, ar „UniGetUI“ gali naudoti WinGet COM API prieš pereidama prie komandų eilutės įrankio", + "Reset WinGet": "Atstatyti „WinGet“", + "This may help if no packages are listed": "Šis gali padėti, jei nėra paketų sąraše", + "Force install location parameter when updating packages with custom locations": "Atnaujinant paketus su pasirinktinėmis vietomis, priverstinai naudoti diegimo vietos parametrą", + "Install Scoop": "Įdiegti „Scoop“", + "Uninstall Scoop (and its packages)": "Išdiegti „Scoop“ (ir jo paketus)", + "Run cleanup and clear cache": "Vykdyti apvalymą ir išvalyti podėlį/talpyklą", + "Run": "Vykdyti", + "Enable Scoop cleanup on launch": "Įjungti/Įgalinti „Scoop“ apvalymą paleidimo metu", + "Default vcpkg triplet": "Numatyta „vcpkg“ trilypė", + "Change vcpkg root location": "Keisti „vcpkg“ šakninę vietą", + "Reset vcpkg root location": "Atstatyti „vcpkg“ šakninę vietą", + "Open vcpkg root location": "Atidaryti „vcpkg“ šakninę vietą", + "Language, theme and other miscellaneous preferences": "Kalba, apipavidalinimas ir kitos pašalinės parinktys", + "Show notifications on different events": "Rodyti pranešimus, skirtinguose įvykiuose", + "Change how UniGetUI checks and installs available updates for your packages": "Pakeisti kaip „UniGetUI“ patikrina ir įdiegia pasiekiamus (at-)naujinimus/-ius Jūsų paketams", + "Automatically save a list of all your installed packages to easily restore them.": "Automatiškai išsaugoti įdiegtų paketų sąrašą, kad lengvai juos atkurtumėte.", + "Enable and disable package managers, change default install options, etc.": "Įjungti/Išjungti (Įgalinti/Išgalinti) paketų tvarkytuvus/-es, pakeisti numatytąsias (į-)diegimo parinktis ir t.t.", + "Internet connection settings": "Interneto jungties nustatymai", + "Proxy settings, etc.": "Įgaliotinių/-ųjų nustatymai ir pan.", + "Beta features and other options that shouldn't be touched": "„Beta“ funkcijos ir kitos parinktys, kurios neturėtų būti sąveikaujamos", + "Reload sources": "Perkrauti šaltinius", + "Delete source": "Ištrinti šaltinį", + "Known sources": "Žinomi šaltiniai", + "Update checking": "Atnaujinimų tikrinimas", + "Automatic updates": "Automatiniai (at-)naujinimai", + "Check for package updates periodically": "Periodiškai tikrinti, ar yra paketų (at-)naujinimų/-ių", + "Check for updates every:": "Tikrinti, ar yra (at-)naujinimų/-ių kas:", + "Install available updates automatically": "Įdiegti pasiekiamus atnaujinimus automatiškai", + "Do not automatically install updates when the network connection is metered": "Automatiškai neįdiegti (at-)naujinimų/-ių, kai prijungtas tinklas yra apskaitomas", + "Do not automatically install updates when the device runs on battery": "Automatiškai neįdiegti (at-)naujinimų/-ių, kai įrenginys veikia akumuliatoriaus ar baterijų dėka.", + "Do not automatically install updates when the battery saver is on": "Automatiškai neįdiegti (at-)naujinimų/-ių, kai yra įjungtas energijos taupymas", + "Only show updates that are at least the specified number of days old": "Rodyti tik tuos naujinimus, kurie yra bent nurodyto dienų skaičiaus senumo", + "Warn me when the installer URL host changes between the installed version and the new version (WinGet only)": "Įspėti mane, kai įdiegiklio URL pagrindinis kompiuteris pasikeičia tarp įdiegtos ir naujos versijos (tik „WinGet“)", + "Change how UniGetUI handles install, update and uninstall operations.": "Pakeisti kaip „UniGetUI“ įdiegia, (at-)naujina ir išdiegia.", + "Navigation": "Naršymas", + "Check for UniGetUI updates": "Tikrinti, ar yra „UniGetUI“ atnaujinimų", + "Quit UniGetUI": "Užverti „UniGetUI“", + "Filters": "Filtrai", + "Sources": "Šaltiniai", + "Search for packages to start": "Ieškoti paketų, norint pradėti", + "Select all": "Pažymėti visus", + "Clear selection": "Atžymėti pasirinktus", + "Instant search": "Akimirksnio (pa-)ieška", + "Distinguish between uppercase and lowercase": "Atskirti didžiąsias ir mažąsias raides ", + "Ignore special characters": "Nepaisyti specialių rašmenų", + "Search mode": "(Pa-)Ieškos veiksena", + "Both": "Abu/-i", + "Exact match": "Tikslus sutapimas", + "Show similar packages": "Rodyti panašius paketus", + "Loading": "Įkeliama", + "Package": "Paketas", + "More options": "Daugiau parinkčių", + "Order by:": "Rikiuoti/Rūšiuoti pagal:", + "Name": "Pavadinimą", + "Id": "ID", + "Ascendant": "Didėjančia tvarką", + "Descendant": "Mažėjančia tvarką", + "View modes": "Rodinio režimai", + "Reload": "Perkrauti", + "Closed": "Uždaryta", + "Ascending": "Didėjančia tvarka", + "Descending": "Mažėjančia tvarka", + "{0}: {1}, {2}": "{0}: {1}, {2}", + "Order by": "Rikiuoti pagal", + "No results were found matching the input criteria": "Jokių rezultatų nebuvo rasta, atitinkančių įvesties kriterijų", + "No packages were found": "Paketų nerasta", + "Loading packages": "Įkeliami paketai", + "Skip integrity checks": "Praleisti vientisumo patikrinimus", + "Download selected installers": "Atsisiųsti pasirinktus/pažymėtus įdiegiklius", + "Install selection": "Įdiegimo atranka", + "Install options": "(Į-)Diegimo parinktys", + "Add selection to bundle": "Pridėti pažymėtus į rinkinį", + "Download installer": "Atsisiųsti įdiegiklį", + "Uninstall selection": "Pašalinti pažymėtus", + "Uninstall options": "Išdiegimo parinktys", + "Ignore selected packages": "Ignoruoti pasirinktus/-ą paketus/-ą", + "Open install location": "Atidaryti įdiegimo vietovę", + "Reinstall package": "Perdiegti paketą", + "Uninstall package, then reinstall it": "Išdiegti paketą, tada jį perdiegti", + "Ignore updates for this package": "Ignoruoti atnaujinimus šiam paketui", + "WinGet malfunction detected": "Aptikta/-s „WinGet“ triktis/sutrikimas", + "It looks like WinGet is not working properly. Do you want to attempt to repair WinGet?": "Atrodo, kad „WinGet“ neveikia tinkamai. Ar norite bandyti jį ištaisyti?", + "Repair WinGet": "Sutaisyti „WinGet“", + "Updates will no longer be ignored for {0}": "Atnaujinimai nebebus ignoruojami – „{0}“", + "Updates are now ignored for {0}": "Atnaujinimai dabar ignoruojami – „{0}“", + "Do not ignore updates for this package anymore": "Nebeignoruoti (at-)naujinimų/-ių šiam paketui", + "Add packages or open an existing package bundle": "Pridėkite paketus arba atidarykite jau egzistuojantį paketo/-ų rinkinį", + "Add packages to start": "Pridėkite paketus, norint pradėti", + "The current bundle has no packages. Add some packages to get started": "Dabartinis rinkinys neturi paketų. Pridėkite keletą paketų, norint pradėti", + "New": "Nauja/-s", + "Save as": "Išsaugoti kaip", + "Create .ps1 script": "Sukurti „*.ps1“ skriptą", + "Remove selection from bundle": "Pašalinti pasirinkimą iš rinkinio", + "Skip hash checks": "Praleisti maišos patikrinimus", + "The package bundle is not valid": "Paketo/-ų rinkinys yra negalimas", + "The bundle you are trying to load appears to be invalid. Please check the file and try again.": "Rinkinys, kurį bandot įkrauti (atrodomai) yra negalimas. Prašome patikrinti failą ir bandykite dar kartą.", + "Package bundle": "Paketo/-ų rinkinys", + "Could not create bundle": "Nepavyko sukurti rinkinio", + "The package bundle could not be created due to an error.": "Nepavyko sukurti paketo/-ų rinkinio dėl klaidos.", + "Install script": "(Į-)Diegimo skriptas", + "PowerShell script": "PowerShell scenarijus", + "The installation script saved to {0}": "Diegimo scenarijus išsaugotas į {0}", + "An error occurred": "Įvyko klaida", + "An error occurred while attempting to create an installation script:": "Įvyko klaida, bandant sukurti (į-)diegimo skriptą:", + "Hooray! No updates were found.": "Sveikinam! (At-)Naujinimų/-ių nerasta.", + "Uninstall selected packages": "Išdiegti pažymėtus/-ą paketus/-ą", + "Update selection": "(At-)Naujinti pasirinktus/pažymėtus", + "Update options": "Naujinimosi parinktys", + "Uninstall package, then update it": "Išdiegti paketą, tada jį atnaujinti", + "Uninstall package": "Išdiegti paketą", + "Skip this version": "Praleisti šią versiją", + "Pause updates for": "Pristabdyti (at-)naujinimus/-ius —", + "User | Local": "Naudotojas | Vietinis", + "Machine | Global": "Kompiuteris | Visuotinis", + "The default package manager for Debian/Ubuntu-based Linux distributions.
Contains: Debian/Ubuntu packages": "Numatytoji paketų tvarkytuvė, skirta „Debian“/„Ubuntu“ pagrindu veikiančioms „Linux“ distribucijoms.
Sudaro: „Debian“/„Ubuntu“ paketai", + "The Rust package manager.
Contains: Rust libraries and programs written in Rust": "„Rust“ paketų tvarkytuvė/-as.
Sudaro: „Rust“ bibliotekos ir programos, kurios sukurtos „Rust“ programavimo kalba", + "The classical package manager for windows. You'll find everything there.
Contains: General Software": "Klasikinė/-is paketų tvarkytuvė/-as, skirta/-s „Windows“. Jūs rasite viską ten.
Sudaro: Bendros taikomosios programos", + "The default package manager for RHEL/Fedora-based Linux distributions.
Contains: RPM packages": "Numatytoji paketų tvarkytuvė, skirta „RHEL“/„Fedora“ pagrindu veikiančioms „Linux“ distribucijoms.
Sudaro: RPM paketai", + "A repository full of tools and executables designed with Microsoft's .NET ecosystem in mind.
Contains: .NET related tools and scripts": "Saugykla, pilna įrankių ir vykdomųjų, sukurti su „Microsoft'o“ „.NET ekosistemą“ mintyje.
Sudaro: „.NET“ susijsiais įrankiais ir skriptais", + "The universal Linux package manager for desktop applications.
Contains: Flatpak applications from configured remotes": "Universalus Linux paketų tvarkytuvas darbalaukio programoms.
Apima: Flatpak programas iš sukonfigūruotų nuotolinių šaltinių", + "NuPkg (zipped manifest)": "„NuPkg“ (archyvuotas manifestas)", + "The Missing Package Manager for macOS (or Linux).
Contains: Formulae, Casks": "Trūkstama paketų tvarkytuvė, skirta „macOS“ (arba „Linux“).
Yra: Formulae, Casks", + "Node JS's package manager. Full of libraries and other utilities that orbit the javascript world
Contains: Node javascript libraries and other related utilities": "„Node JS“ paketų tvarkytuvas/-ė. Pilnas įvairių programinių bibliotekų ir įvairių įrankių, kurie apima „Javascript pasaulį“
Sudaro: „Node Javascript“ bibliotekos ir įvairūs įrankiai", + "The default package manager for Arch Linux and its derivatives.
Contains: Arch Linux packages": "Numatytoji paketų tvarkytuvė, skirta „Arch Linux“ ir jo darinėms.
Sudaro: „Arch Linux“ paketai", + "Python's library manager. Full of python libraries and other python-related utilities
Contains: Python libraries and related utilities": "„Python“ programinių bibliotekų tvarkytuvas/-ė. Pilnas „Python“ bibliotekų ir kitų „Python“ susijusių įrankių
Sudaro: „Python“ bibliotekas ir kitus „Python“ susijusius įrankius", + "PowerShell's package manager. Find libraries and scripts to expand PowerShell capabilities
Contains: Modules, Scripts, Cmdlets": "„PowerShell“ paketų tvarkytuvas/-ė. Pilnas programinių bibliotekų ir skriptų
Sudaro: Modulius, skriptus ir „cmdlets“", + "extracted": "išskleista/-s", + "Scoop package": "„Scoop“ paketas", + "Great repository of unknown but useful utilities and other interesting packages.
Contains: Utilities, Command-line programs, General Software (extras bucket required)": "Gera saugykla nežinomų, bet naudingų įrankių ir kitų įdomių paketų.
Sudaro: Įrankiai, komandinės eilutės programos, bendrosios taikomosios programos (papildomiems „bucket“ reikalingas)", + "The universal Linux package manager by Canonical.
Contains: Snap packages from the Snapcraft store": "Universali „Linux“ paketų tvarkytuvė, sukurta „Canonical“.
Sudaro: „Snap“ paketai iš „Snapcraft“ parduotuvės", + "library": "biblioteka", + "feature": "funkcija", + "A popular C/C++ library manager. Full of C/C++ libraries and other C/C++-related utilities
Contains: C/C++ libraries and related utilities": "Populiari „C“/„C++“ bibliotekų tvarkyklė/-uvė. Pilna „C“/„C++“ bibliotekų ir kitokių susijusių įrankių
Sudaro: „C“/„C++“ bibliotekas ir susijusius įrankius", + "option": "parinktis", + "This package cannot be installed from an elevated context.": "Šis paketas negali būti įdiegtas su paaukštintom teisėm („UniGetUI“ kontekstas).", + "Please run UniGetUI as a regular user and try again.": "Prašome vykdyti „UniGetUI“ kaip paprasta (-s) vartotoją/naudotoją (-as) ir bandykite dar kartą", + "Please check the installation options for this package and try again": "Prašome patikrinti įdiegimo parinktis šiam paketui ir bandykite dar kartą", + "Microsoft's official package manager. Full of well-known and verified packages
Contains: General Software, Microsoft Store apps": "Oficialus/-i „Microsoft“ paketų tvarkytuvas/-ė. Pilnas gerai žinomų ir patvirtintų paketų
Sudaro: Bendrąsias taikomąsias programas ir „Microsoft Store“ programėles", + "Local PC": "Vietinis AK", + "Android Subsystem": "„Android“ posistemis", + "Operation on queue (position {0})...": "Operacija eilėje (vieta eilėje – {0})...", + "Click here for more details": "Spauskite/Spustelėkite čia, norint gauti daugiau išsamumo", + "Operation canceled by user": "Operacija atšaukta naudotojo/vartotojo", + "Running PreOperation ({0}/{1})...": "Vykdoma „PreOperation“ ({0}/{1})...", + "PreOperation {0} out of {1} failed, and was tagged as necessary. Aborting...": "„PreOperation“ {0} iš {1} nepavyko ir buvo pažymėta kaip būtina. Nutraukiama...", + "PreOperation {0} out of {1} finished with result {2}": "„PreOperation“ {0} iš {1} baigėsi su rezultatu {2}", + "Starting operation...": "Pradedama operacija...", + "Running PostOperation ({0}/{1})...": "Vykdoma „PostOperation“ ({0}/{1})...", + "PostOperation {0} out of {1} failed, and was tagged as necessary. Aborting...": "„PostOperation“ {0} iš {1} nepavyko ir buvo pažymėta kaip būtina. Nutraukiama...", + "PostOperation {0} out of {1} finished with result {2}": "„PostOperation“ {0} iš {1} baigėsi su rezultatu {2}", + "{package} installer download": "„{package}“ diegiklio atsisiuntimas", + "{0} installer is being downloaded": "Atsisiunčiamas „{0}“ diegiklis", + "Download succeeded": "Atsisiuntimas buvo sėkmingas", + "{package} installer was downloaded successfully": "„{package}“ įdiegiklis buvo sėkmingai atsisiųstas", + "Download failed": "Nepavyko atsisiųsti/Atsisiuntimas nepavyko", + "{package} installer could not be downloaded": "„{package}“ diegiklio nepavyko atsisiųsti", + "{package} Installation": "„{package}“ įdiegimas", + "{0} is being installed": "„{0}“ yra įdiegama/-s", + "Installation succeeded": "Įdiegimas buvo sėkmingas", + "{package} was installed successfully": "„{package}“ buvo sėkmingai įdiegta/-s", + "Installation failed": "Įdiegimas nepavyko", + "{package} could not be installed": "Nepavyko įdiegti „{package}“", + "{package} Update": "Atnaujinti „{package}“", + "Update succeeded": "Sėkmingai atnaujinta", + "{package} was updated successfully": "„{package}“ buvo sėkmingai atnaujinta/-s", + "Update failed": "Atnaujinimas nepavyko", + "{package} could not be updated": "Nepavyko atnaujinti „{package}“", + "{package} Uninstall": "Išdiegti „{package}“", + "{0} is being uninstalled": "„{0}“ yra išdiegama/-s", + "Uninstall succeeded": "Išdiegimas buvo sėkmingas", + "{package} was uninstalled successfully": "„{package}“ buvo sėkmingai išdiegta/-s", + "Uninstall failed": "Išdiegimas buvo nesėkmingas", + "{package} could not be uninstalled": "Nepavyko išdiegti „{package}“", + "Adding source {source}": "Pridedamas šaltinis – „{source}“", + "Adding source {source} to {manager}": "Pridedamas šaltinis – „{source}“ į „{manager}“", + "Source added successfully": "Šaltinis sėkmingai pridėtas", + "The source {source} was added to {manager} successfully": "Šaltinis – „{source}“ buvo sėkmingai pridėtas prie – „{manager}", + "Could not add source": "Nepavyko pridėti šaltinio", + "Could not add source {source} to {manager}": "Nepavyko pridėti šaltinio – „{source}“ prie – „{manager}“", + "Removing source {source}": "(Pa-)Šalinimas šaltinis – „{source}“", + "Removing source {source} from {manager}": "(Pa-)Šalinimas šaltinis – „{source}“ iš – „{manager}“", + "Source removed successfully": "Šaltinis sėkmingai pašalintas", + "The source {source} was removed from {manager} successfully": "Šaltinis – „{source}“ buvo sėkmingai pašalintas iš – „{manager}", + "Could not remove source": "Nepavyko pašalinti šaltinio", + "Could not remove source {source} from {manager}": "Nepavyko pašalinti šaltinio – „{source}“ iš – „{manager}“", + "The package manager \"{0}\" was not found": "Paketų tvarkytuvė/-as – „{0}“ yra nerasta/-s", + "The package manager \"{0}\" is disabled": "Paketų tvarkytuvė/-as – „{0}“ yra išjungta/išgalinta (-s)", + "There is an error with the configuration of the package manager \"{0}\"": "Yra klaida su konfigūracija, siejančią paketų tvarkytuve/-u – „{0}“", + "The package \"{0}\" was not found on the package manager \"{1}\"": "Paketas – „{0}“ nebuvo rastas paketų tvarkytuvėje – „{1}“", + "{0} is disabled": "„{0}“ – yra išjungta/išgalinta (-s)", + "{0} weeks": "{0} savaičių", + "1 month": "1 mėnuo", + "{0} months": "{0} mėnesių", + "Something went wrong": "Kažkas, kažkur įvyko blogai", + "An interal error occurred. Please view the log for further details.": "Įvyko vidinė klaida. Prašome peržiūrėti žurnalą, norint sužinoti daugiau.", + "No applicable installer was found for the package {0}": "Joks pritaikomas įdiegiklis nebuvo rastas, paketui – „{0}“", + "Integrity checks will not be performed during this operation": "Vientisumo patikrinimai nebus vykdomi šios operacijos metu", + "This is not recommended.": "Tai nerekomenduojama.", + "Run now": "Vykdyti dabar", + "Run next": "Vykdyti kitą", + "Run last": "Vykdyti paskutinį", + "Show in explorer": "Rodyti failų naršyklėje", + "Checked": "Pažymėta", + "Unchecked": "Nepažymėta", + "This package is already installed": "Šis paketas jau įdiegtas", + "This package can be upgraded to version {0}": "Šis paketas gali būti aukštutiniškai atnaujintas į versiją – {0}", + "Updates for this package are ignored": "Atnaujinimai šiam paketui yra ignoruojami", + "This package is being processed": "Šis paketas yra apdorojamas", + "This package is not available": "Šis paketas nėra pasiekiamas", + "Select the source you want to add:": "Pažymėkite šaltinį, kurį norite pridėti:", + "Source name:": "Šaltinio pavadinimas:", + "Source URL:": "Šaltinio „URL“ – saitas:", + "An error occurred when adding the source: ": "Pridėdant šaltinį įvyko klaida:", + "Package management made easy": "Paketų valdymas ir tvarkymas padarytas lengvu!", + "version {0}": "versija – {0}", + "[RAN AS ADMINISTRATOR]": "VYKDĖ KAIP ADMINISTRATORIUS", + "Portable mode": "Nešiojamasis režimas\n", + "DEBUG BUILD": "Derinimo darinys", + "Here you can change UniGetUI's behaviour regarding the following shortcuts. Checking a shortcut will make UniGetUI delete it if if gets created on a future upgrade. Unchecking it will keep the shortcut intact": "Štai čia, Jūs galite pakeisti „UniGetUI“ elgseną su nurodytomis nuorodomis. Pažymint nuorodos parinktį, „UniGetUI“ ištrins ją, jeigu ji bus sukurta po atnaujinimo. (At-/Ne-)pažymint nuorodos parinktį, išlaikys nuorodą ten kur buvo", + "Manual scan": "Rankinis skenavimas", + "Existing shortcuts on your desktop will be scanned, and you will need to pick which ones to keep and which ones to remove.": "Bus nuskenuoti esami darbalaukio spartieji klavišai, ir turėsite pasirinkti, kuriuos palikti, o kuriuos pašalinti.", + "Delete?": "Ištrinti?", + "I understand": "Aš supratau", + "Chocolatey setup changed": "„Chocolatey“ sąranka pasikeitė", + "UniGetUI no longer includes its own private Chocolatey installation. A legacy UniGetUI-managed Chocolatey installation was detected for this user profile, but system Chocolatey was not found. Chocolatey will stay unavailable in UniGetUI until Chocolatey is installed on the system and UniGetUI is restarted. Applications previously installed through UniGetUI's bundled Chocolatey may still appear under other sources such as Local PC or WinGet.": "„UniGetUI“ nebeprideda savo privačios „Chocolatey“ instaliacijos. Šiam naudotojo profiliui aptikta senoji „UniGetUI“ valdoma „Chocolatey“ instaliacija, tačiau sisteminė „Chocolatey“ nebuvo rasta. „Chocolatey“ liks nepasiekiama „UniGetUI“ programoje, kol „Chocolatey“ nebus įdiegta sistemoje ir „UniGetUI“ nebus paleista iš naujo. Anksčiau per „UniGetUI“ pridėtą „Chocolatey“ įdiegtos programos vis dar gali būti rodomos kituose šaltiniuose, tokiuose kaip „Vietinis AK“ arba „WinGet“.", + "NOTE: This troubleshooter can be disabled from UniGetUI Settings, on the WinGet section": "Pastaba: Šis trikdžių tikrinimas gali būti išjungtas/išgalintas iš „UniGetUI“ nustatymų, „WinGet“ skyriuje", + "Restart": "Paleisti iš naujo", + "Are you sure you want to delete all shortcuts?": "Ar Jūs tikrai norite pašalinti visas nuorodas?", + "Any new shorcuts created during an install or an update operation will be deleted automatically, instead of showing a confirmation prompt the first time they are detected.": "Bet kokios naujos nuorodos, sukurtos per (į-)diegimo ar (at-)naujinimo operacija, bus automatiškai ištrintos, vietoj to, kad rodytų patvirtinimo langą, pirmą kartą būnant jiems aptiktiems.", + "Any shorcuts created or modified outside of UniGetUI will be ignored. You will be able to add them via the {0} button.": "Bet kokios sukurtos ir modifikuotos nuorodos išorės „UniGetUI“, bus ignoruojamos/nepaisomos. Jūs galėsite jas pridėti naudodami – „{0}“ mygtuką.", + "Are you really sure you want to enable this feature?": "Ar Jūs tikrai norite įjungti/įgalinti šią funkciją?", + "No new shortcuts were found during the scan.": "Nebuvo rasta naujų nuorodų per skenavimą.", + "How to add packages to a bundle": "Kaip pridėti paketus į rinkinį", + "In order to add packages to a bundle, you will need to: ": "Norėdami pridėti paketus į rinkinį, turėsite: ", + "1. Navigate to the \"{0}\" or \"{1}\" page.": "1. Pereikite į „{0}“ arba „{1}“ puslapį.", + "2. Locate the package(s) you want to add to the bundle, and select their leftmost checkbox.": "2. Atraskite paketą/-us, kurį/-iuos Jūs norite pridėti prie rinkinio ir pažymėkite jų kairiausiąją skiltį.", + "3. When the packages you want to add to the bundle are selected, find and click the option \"{0}\" on the toolbar.": "3. Kai paketai, kuriuos norite pridėti į rinkinį, yra pažymėti, įrankių juostoje suraskite ir spustelėkite parinktį „{0}“.", + "4. Your packages will have been added to the bundle. You can continue adding packages, or export the bundle.": "4. Jūsų paketai buvo pridėti prie rinkinio. Jūs galite tęsti jų pridėjimą, arba galite eksportuoti šį rinkinį.", + "Which backup do you want to open?": "Kurią atsarginę kopiją norite atidaryti?", + "Select the backup you want to open. Later, you will be able to review which packages you want to install.": "Pasirinkite atsarginę kopiją, kurią norite atidaryti. Vėliau galėsite peržiūrėti, kuriuos paketus ar programas norite atkurti.", + "There are ongoing operations. Quitting UniGetUI may cause them to fail. Do you want to continue?": "Yra einančios/vykdomos operacijos. Išeinant iš UniGetUI gali sukelti jų gedimą. Ar Jūs norite tęsti?", + "UniGetUI or some of its components are missing or corrupt.": "„UniGetUI“ arba kai kurie jo komponentai yra dingę arba sugadinti.", + "It is strongly recommended to reinstall UniGetUI to adress the situation.": "Yra stipriai rekomenduojama, kad perdiegtumėte „UniGetUI“, norint sutaisyti šią situaciją sukeliančia problemą.", + "Refer to the UniGetUI Logs to get more details regarding the affected file(s)": "Peržvelkite „UniGetUI“ veikimo žurnalus, norint daugiau sužinoti apie paveiktą (-us) failą (-us)", + "Integrity checks can be disabled from the Experimental Settings": "Vientisumo patikrinimai gali būti išjungti/išgalinti per eksperimentinius nustatymus", + "Repair UniGetUI": "(Su-)Taisyti „UniGetUI“", + "Live output": "Gyva išvestis", + "This package bundle had some settings that are potentially dangerous, and may be ignored by default.": "Šis paketų rinkinys turėjo kai kurių potencialiai pavojingų nustatymų, kurie pagal numatytuosius nustatymus gali būti ignoruojami.", + "Entries that show in YELLOW will be IGNORED.": "GELTONAI rodomi įrašai BUS IGNORUOJAMI.", + "Entries that show in RED will be IMPORTED.": "RAUDONAI rodomi įrašai BUS IMPORTUOTI.", + "You can change this behavior on UniGetUI security settings.": "Jūs galite pakeisti šią elgseną „UniGetUI“ saugumo nustatymuose.", + "Open UniGetUI security settings": "Atidaryti „UniGetUI“ saugumo nustatymus", + "Should you modify the security settings, you will need to open the bundle again for the changes to take effect.": "Jei pakeisite saugumo nustatymus, turėsite iš naujo atidaryti rinkinį, kad pakeitimai įsigaliotų.", + "Details of the report:": "At(-a)skaitos išsamumas:", + "Are you sure you want to create a new package bundle? ": "Ar Jūs tikrai norite sukurti naują paketo/-ų rinkinį?", + "Any unsaved changes will be lost": "Bet kokie neišsaugoti pakeitimai bus prarasti", + "Warning!": "Įspėjimas!", + "For security reasons, custom command-line arguments are disabled by default. Go to UniGetUI security settings to change this. ": "Numatytai dėl saugumo priežasčių, pasirinktiniai komandinės eilutės argumentai yra negalimi. Norint pakeisti, nueikite į „UniGetUI“ saugumo nustatymus.", + "Change default options": "Pakeisti numatytąsias parinktis", + "Ignore future updates for this package": "Ignoruoti paskesnius atnaujinimus šiam paketui", + "For security reasons, pre-operation and post-operation scripts are disabled by default. Go to UniGetUI security settings to change this. ": "Numatytai dėl saugumo priežasčių, parengtinės ir paskesniosios operacijos skriptai yra negalimi. Norint pakeisti, nueikite į „UniGetUI“ saugumo nustatymus.", + "You can define the commands that will be run before or after this package is installed, updated or uninstalled. They will be run on a command prompt, so CMD scripts will work here.": "Jūs galite apibrėžti komandas, kurios bus vykdomos prieš ar po šio paketo įdiegimą, (at-)naujinimą ar išdiegimą. Jie bus vykdomi komandines eilutės principu, tai „CMD“ skriptai yra priimtini.", + "Change this and unlock": "Pakeisti tai/šį/šitą ir atrakinti", + "{0} Install options are currently locked because {0} follows the default install options.": "„{0}“ (į-)diegimo parinktys šiuo metu yra užrakintos, nes „{0}“ seka pagal numatytąsias (į-)diegimo parinktis.", + "Unset or unknown": "Nenustatyta arba nežinoma", + "This package has no screenshots or is missing the icon? Contrbute to UniGetUI by adding the missing icons and screenshots to our open, public database.": "Šis paketas neturi ekrano kopijų, iškarpų ar neturi piktogramos? Prisidėkite prie UniGetUI pridėdami trūkstamus piktogramas, ekrano kopijas ir iškarpas į mūsų atvirą, viešą duomenų bazę.", + "Become a contributor": "Tapkite talkininku", + "Update to {0} available": "Atnaujinimas į – {0} pasiekiamas", + "Reinstall": "Perdiegti", + "Installer not available": "Įdiegiklis nepasiekiamas", + "Version:": "Versija:", + "UniGetUI Version {0}": "„UniGetUI“ versija – {0}", + "Performing backup, please wait...": "Atliekamas atsarginės kopijos sukūrimas, prašome palaukti...", + "An error occurred while logging in: ": "Bandant prisijungti, įvyko klaida:", + "Fetching available backups...": "Gaunamos galimos atsarginės kopijos...", + "Done!": "Atlikta!", + "The cloud backup has been loaded successfully.": "Debesies atsarginė kopija sėkmingai įkelta.", + "An error occurred while loading a backup: ": "Įkeliant atsarginę kopiją įvyko klaida: ", + "Backing up packages to GitHub Gist...": "Kuriamos ir siunčiamos atsarginės paketų kopijos į „GitHub Gist“...", + "Backup Successful": "Atsarginė kopija sėkmingai sukurta", + "The cloud backup completed successfully.": "Debesies atsarginė kopija sėkmingai baigta.", + "Could not back up packages to GitHub Gist: ": "Nepavyko sukurti paketų atsarginės kopijos į „GitHub Gist“: ", + "It is not guaranteed that the provided credentials will be stored safely, so you may as well not use the credentials of your bank account": "Nėra garantijos, kad pateikti prisijungimo duomenys bus saugomi saugiai, todėl geriau nenaudoti savo banko sąskaitos prisijungimo duomenų", + "Enable the automatic WinGet troubleshooter": "Įjungti/Įgalinti automatinį „WinGet“ trikdžių nagrinėjimą", + "Add updates that fail with a 'no applicable update found' to the ignored updates list": "Pridėti (at-)naujinimus/-ius, kurie patiria klaidą – „negalima rasti atitaikomo (at-)naujinimo“ prie ignoruojamų sąrašo.", + "Invalid selection": "Netinkamas pasirinkimas", + "No package was selected": "Nepasirinktas joks paketas", + "More than 1 package was selected": "Pasirinktas daugiau nei 1 paketas", + "List": "Sąrašas", + "Grid": "Tinklelis", + "Icons": "Piktogramos", + "\"{0}\" is a local package and does not have available details": "„{0}“ yra vietinis paketas, kuris neturi pasiekiamo išsamumo", + "\"{0}\" is a local package and is not compatible with this feature": "„{0}“ yra vietinis paketas, kuris nepalaiko šios funkcijos", + "Add packages to bundle": "Pridėti paketus į rinkinį", + "Preparing packages, please wait...": "Paruošiami paketai, prašome palaukti...", + "Loading packages, please wait...": "Įkeliami paketai, prašome palaukti...", + "Saving packages, please wait...": "Išsaugomi paketai, prašome palaukti...", + "The bundle was created successfully on {0}": "Rinkinys buvo sėkmingai sukurtas {0}", + "User profile": "Naudotojo profilis", + "Error": "Klaida", + "Log in failed: ": "Prisijungimas nepavyko:", + "Log out failed: ": "Nepavyko atsijungti:", + "Package backup settings": "Paketų atsarginės kopijos nustatymai", + "Manage UniGetUI autostart behaviour from the Settings app": "Valdyti „UniGetUI“ automatinio paleidimo elgseną", + "Choose how many operations shoulds be performed in parallel": "Pasirinkite, kiek operacijų turi būti vykdoma lygiagrečiai", + "Something went wrong while launching the updater.": "Kažkas įvyko negerai, bandant paleisti naujinį.", + "Please try again later": "Prašome pabandyti dar kartą, vėlesniu laiku", + "Show the release notes after UniGetUI is updated": "Rodyti išleidimo užrašus po UniGetUI atnaujinimo" +} diff --git a/src/Languages/lang_mk.json b/src/Languages/lang_mk.json new file mode 100644 index 0000000..534775c --- /dev/null +++ b/src/Languages/lang_mk.json @@ -0,0 +1,850 @@ +{ + "{0} of {1} operations completed": "Завршени се {0} од {1} операции", + "{0} is now {1}": "{0} сега е {1}", + "Enabled": "Овозможено", + "Disabled": "Оневозможено", + "Privacy": "Приватност", + "Hide my username from the logs": "Сокриј го моето корисничко име од дневниците", + "Replaces your username with **** in the logs. Restart UniGetUI to also hide it from already-recorded entries.": "Го заменува вашето корисничко име со **** во дневниците. Рестартирајте го UniGetUI за да го сокриете и од веќе запишаните записи.", + "Your last update attempt did not complete.": "Вашиот последен обид за ажурирање не заврши.", + "UniGetUI could not confirm whether the update succeeded. Open the log to see what happened.": "UniGetUI не можеше да потврди дали ажурирањето успеа. Отворете го дневникот за да видите што се случило.", + "View log": "Погледни дневник", + "The installer reported success but did not restart UniGetUI.": "Инсталаторот пријави успех, но не го рестартираше UniGetUI.", + "The installer failed to initialize.": "Инсталаторот не успеа да се иницијализира.", + "Setup was canceled before installation began.": "Поставувањето беше откажано пред да започне инсталацијата.", + "A fatal error occurred during the preparation phase.": "Настана фатална грешка за време на фазата на подготовка.", + "A fatal error occurred during installation.": "Настана фатална грешка за време на инсталацијата.", + "Installation was canceled while in progress.": "Инсталацијата беше откажана додека беше во тек.", + "The installer was terminated by another process.": "Инсталаторот беше прекинат од друг процес.", + "The preparation phase determined the installation cannot proceed.": "Фазата на подготовка утврди дека инсталацијата не може да продолжи.", + "The installer could not start. UniGetUI may already be running, or you do not have permission to install.": "Инсталаторот не можеше да се стартува. UniGetUI можеби веќе работи или немате дозвола за инсталација.", + "Unexpected installer error.": "Неочекувана грешка на инсталаторот.", + "We are checking for updates.": "Проверуваме за ажурирања.", + "Please wait": "Почекајте", + "Great! You are on the latest version.": "Одлично! Ја користите најновата верзија.", + "There are no new UniGetUI versions to be installed": "Нема нови верзии на UniGetUI за инсталација", + "UniGetUI version {0} is being downloaded.": "Се презема UniGetUI верзија {0}.", + "This may take a minute or two": "Ова може да потрае една или две минути", + "The installer authenticity could not be verified.": "Автентичноста на инсталаторот не можеше да се потврди.", + "The update process has been aborted.": "Процесот на ажурирање е прекинат.", + "Auto-update is not yet available on this platform.": "Автоматското ажурирање сè уште не е достапно на оваа платформа.", + "Please update UniGetUI manually.": "Ажурирајте го UniGetUI рачно.", + "An error occurred when checking for updates: ": "Настана грешка при проверката за ажурирања: ", + "The updater could not be launched.": "Ажурирачот не можеше да се стартува.", + "The operating system did not start the installer process.": "Оперативниот систем не го стартуваше процесот на инсталаторот.", + "UniGetUI is being updated...": "UniGetUI се ажурира...", + "Update installed.": "Ажурирањето е инсталирано.", + "UniGetUI was updated successfully, but this running copy was not replaced. This usually means you are running a development build. Close this copy and start the newly-installed version to finish.": "UniGetUI беше успешно ажуриран, но оваа активна копија не беше заменета. Ова обично значи дека користите развојна верзија. Затворете ја оваа копија и стартувајте ја новоинсталираната верзија за да завршите.", + "The update could not be applied.": "Ажурирањето не можеше да се примени.", + "Installer exit code {0}: {1}": "Излезен код на инсталаторот {0}: {1}", + "Update cancelled.": "Ажурирањето е откажано.", + "Authentication was cancelled.": "Автентикацијата е откажана.", + "Installer exit code {0}": "Излезен код на инсталаторот {0}", + "Operation in progress": "Операција во тек", + "Please wait...": "Ве молиме почекајте...", + "Success!": "Успех!", + "Failed": "Не успеа", + "An error occurred while processing this package": "Настана грешка при обработката на овој пакет", + "Installer": "Инсталатор", + "Executable": "Извршна датотека", + "MSI": "MSI", + "Compressed file": "Компресирана датотека", + "MSIX": "MSIX", + "WinGet was repaired successfully": "WinGet е успешно поправен", + "It is recommended to restart UniGetUI after WinGet has been repaired": "Препорачливо е да го рестартирате UniGetUI откако WinGet ќе биде поправен", + "WinGet could not be repaired": "WinGet не можеше да се поправи", + "An unexpected issue occurred while attempting to repair WinGet. Please try again later": "Настана неочекуван проблем при обидот да се поправи WinGet. Обидете се повторно подоцна", + "Log in to enable cloud backup": "Најавете се за да овозможите резервна копија во облак", + "Backup Failed": "Резервната копија не успеа", + "Downloading backup...": "Се презема резервната копија...", + "An update was found!": "Пронајдено е ажурирање!", + "{0} can be updated to version {1}": "{0} може да се ажурира на верзија {1}", + "Updates found!": "Најдени се ажурирањата!", + "{0} packages can be updated": "{0} пакети може да се ажурираат", + "{0} is being updated to version {1}": "{0} се ажурира на верзија {1}", + "{0} packages are being updated": "{0} пакети се ажурираат", + "You have currently version {0} installed": "Моментално ја имате инсталирано верзијата {0}", + "Desktop shortcut created": "Создадена е кратенка на работната површина", + "UniGetUI has detected a new desktop shortcut that can be deleted automatically.": "UniGetUI откри нова кратенка на работната површина што може автоматски да се избрише.", + "{0} desktop shortcuts created": "Создадени се {0} кратенки на работната површина", + "UniGetUI has detected {0} new desktop shortcuts that can be deleted automatically.": "UniGetUI откри {0} нови кратенки на работната површина што можат автоматски да се избришат.", + "Attention required": "Потребно е внимание", + "Restart required": "Потребно е рестартирање", + "1 update is available": "Достапно е 1 ажурирање", + "{0} updates are available": "Достапни се {0} ажурирања", + "Everything is up to date": "Сè е ажурирано", + "Discover Packages": "Откриј пакети", + "Available Updates": "Достапни ажурирања", + "Installed Packages": "Инсталирани пакети", + "UniGetUI Version {0} by Devolutions": "UniGetUI верзија {0} од Devolutions", + "Show UniGetUI": "Прикажи го UniGetUI", + "Quit": "Затвори", + "Are you sure?": "Дали сте сигурни?", + "Do you really want to uninstall {0}?": "Дали навистина сакате да деинсталирате {0}?", + "Do you really want to uninstall the following {0} packages?": "Дали навистина сакате да ги деинсталирате следниве {0} пакети?", + "No": "Не", + "Yes": "Да", + "Partial": "Делумно", + "View on UniGetUI": "Прикажи во UniGetUI", + "Update": "Ажурирај", + "Open UniGetUI": "Отвори UniGetUI", + "Update all": "Ажурирај сè", + "Update now": "Ажурирај сега", + "Installer host changed since the installed version.\n": "Хостот на инсталаторот се промени во однос на инсталираната верзија.\n", + "This package is on the queue": "Овој пакет е во редицата", + "installing": "инсталирање", + "updating": "ажурирање", + "uninstalling": "деинсталирање", + "installed": "инсталирано", + "Retry": "Обидете се повторно", + "Install": "инсталирај", + "Uninstall": "деинсталирај", + "Open": "Отвори", + "Operation profile:": "Профил на операцијата:", + "Follow the default options when installing, upgrading or uninstalling this package": "Следи ги стандардните опции при инсталација, надградба или деинсталација на овој пакет", + "The following settings will be applied each time this package is installed, updated or removed.": "Следниве поставки ќе се применуваат секојпат кога овој пакет ќе се инсталира, ажурира или отстрани.", + "Version to install:": "Верзија за инсталирање:", + "Architecture to install:": "Архитектура за инсталирање:", + "Installation scope:": "Опсег на инсталација:", + "Install location:": "Локација на инсталација:", + "Select": "Избери", + "Reset": "Ресетирај", + "Custom install arguments:": "Сопствени аргументи за инсталација:", + "Custom update arguments:": "Сопствени аргументи за ажурирање:", + "Custom uninstall arguments:": "Сопствени аргументи за деинсталација:", + "Pre-install command:": "Команда пред инсталација:", + "Post-install command:": "Команда по инсталација:", + "Abort install if pre-install command fails": "Прекини ја инсталацијата ако командата пред инсталација не успее", + "Pre-update command:": "Команда пред ажурирање:", + "Post-update command:": "Команда по ажурирање:", + "Abort update if pre-update command fails": "Прекини го ажурирањето ако командата пред ажурирање не успее", + "Pre-uninstall command:": "Команда пред деинсталација:", + "Post-uninstall command:": "Команда по деинсталација:", + "Abort uninstall if pre-uninstall command fails": "Прекини ја деинсталацијата ако командата пред деинсталација не успее", + "Command-line to run:": "Команда за извршување:", + "Save and close": "Зачувај и затвори", + "General": "Општо", + "Architecture & Location": "Архитектура и локација", + "Command-line": "Командна линија", + "Close apps": "Затвори апликации", + "Pre/Post install": "Пред/по инсталација", + "Select the processes that should be closed before this package is installed, updated or uninstalled.": "Изберете ги процесите што треба да се затворат пред овој пакет да биде инсталиран, ажуриран или деинсталиран.", + "Write here the process names here, separated by commas (,)": "Напишете ги овде имињата на процесите, разделени со запирки (,)", + "Try to kill the processes that refuse to close when requested to": "Обиди се да ги прекинеш процесите што одбиваат да се затворат кога ќе им биде побарано", + "Run as admin": "Стартувај како администратор", + "Interactive installation": "Интерактивна инсталација", + "Skip hash check": "Прескокни ја проверката на хашот", + "Uninstall previous versions when updated": "Деинсталирај ги претходните верзии при ажурирање", + "Skip minor updates for this package": "Прескокни помали ажурирања за овој пакет", + "Automatically update this package": "Автоматски ажурирај го овој пакет", + "{0} installation options": "Опции за инсталација за {0}", + "Latest": "Најнова", + "PreRelease": "Предиздание", + "Default": "Стандардно", + "Manage ignored updates": "Управувајте со игнорираните ажурирања", + "The packages listed here won't be taken in account when checking for updates. Double-click them or click the button on their right to stop ignoring their updates.": "Пакетите наведени овде нема да се земат во предвид при проверка за ажурирања. Кликнете двапати на нив или кликнете на копчето на нивната десна страна за да престанете да ги игнорирате нивните ажурирања.", + "Reset list": "Ресетирај список", + "Do you really want to reset the ignored updates list? This action cannot be reverted": "Дали навистина сакате да ја ресетирате листата на игнорирани ажурирања? Ова дејство не може да се врати", + "No ignored updates": "Нема игнорирани ажурирања", + "Package Name": "Име на пакетот", + "Package ID": "ИД на пакетот", + "Ignored version": "Игнорирана верзија", + "New version": "Нова верзија", + "Source": "Извор", + "All versions": "Сите верзии", + "Unknown": "Непознато", + "Up to date": "Ажурирано", + "Package {name} from {manager}": "Пакет {name} од {manager}", + "Remove {0} from ignored updates": "Отстрани го {0} од игнорираните ажурирања", + "Cancel": "Откажи", + "Administrator privileges": "Администраторски привилегии", + "This operation is running with administrator privileges.": "Оваа операција се извршува со администраторски привилегии.", + "Interactive operation": "Интерактивна операција", + "This operation is running interactively.": "Оваа операција се извршува интерактивно.", + "You will likely need to interact with the installer.": "Веројатно ќе треба да комуницирате со инсталаторот.", + "Integrity checks skipped": "Проверките на интегритет се прескокнати", + "Integrity checks will not be performed during this operation.": "Проверките на интегритет нема да се извршуваат за време на оваа операција.", + "Proceed at your own risk.": "Продолжете на сопствен ризик.", + "Close": "Затвори", + "Loading...": "Се вчитува...", + "Installer SHA256": "SHA256 инсталатер", + "Homepage": "страна", + "Author": "Автор", + "Publisher": "Издавач", + "License": "Лиценца", + "Manifest": "Манифест", + "Installer Type": "Тип на инсталатер", + "Size": "Големина", + "Installer URL": "URL инсталатер", + "Last updated:": "Последно ажурирање:", + "Release notes URL": "URL на белешките за изданието", + "Package details": "Детали за пакетот", + "Dependencies:": "Зависности:", + "Release notes": "Белешки за изданието", + "Screenshots": "Слики од екранот", + "This package has no screenshots or is missing the icon? Contribute to UniGetUI by adding the missing icons and screenshots to our open, public database.": "Овој пакет нема слики од екранот или му недостасува иконата? Придонесете во UniGetUI со додавање на недостасувачките икони и слики од екранот во нашата отворена, јавна база на податоци.", + "Version": "Верзија", + "Install as administrator": "Инсталирај како администратор", + "Update to version {0}": "Ажурирај на верзија {0}", + "Installed Version": "Инсталирана верзија", + "Update as administrator": "Ажурирај како администратор", + "Interactive update": "Интерактивно ажурирање", + "Uninstall as administrator": "Деинсталирај како администратор", + "Interactive uninstall": "Интерактивна деинсталација", + "Uninstall and remove data": "Деинсталирај и отстрани податоци", + "Not available": "Не е достапно", + "Installer SHA512": "SHA512 инсталатер", + "Unknown size": "Непозната големина", + "No dependencies specified": "Нема наведени зависности", + "mandatory": "задолжително", + "optional": "опционално", + "UniGetUI {0} is ready to be installed.": "UniGetUI {0} е подготвен за инсталација.", + "The update process will start after closing UniGetUI": "Процесот на ажурирање ќе започне по затворањето на UniGetUI", + "UniGetUI has been ran as administrator, which is not recommended. When running UniGetUI as administrator, EVERY operation launched from UniGetUI will have administrator privileges. You can still use the program, but we highly recommend not running UniGetUI with administrator privileges.": "UniGetUI е стартуван како администратор, што не се препорачува. Кога UniGetUI работи како администратор, СЕКОЈА операција стартувана од UniGetUI ќе има администраторски привилегии. Сепак можете да ја користите програмата, но силно препорачуваме да не го стартувате UniGetUI со администраторски привилегии.", + "Share anonymous usage data": "Сподели анонимни податоци за користење", + "UniGetUI collects anonymous usage data in order to improve the user experience.": "UniGetUI собира анонимни податоци за користење за да го подобри корисничкото искуство.", + "Accept": "Прифати", + "Software Updates": "Софтверски ажурирања", + "Package Bundles": "Збирки на пакети", + "Settings": "Поставки", + "Package Managers": "Менаџери на пакети", + "UniGetUI Log": "Дневник на UniGetUI", + "Package Manager logs": "Дневници на менаџерот на пакети", + "Operation history": "Историја на операции", + "Help": "Помош", + "UniGetUI": "UniGetUI", + "You have installed UniGetUI Version {0}": "Ја имате инсталирано UniGetUI верзија {0}", + "Disclaimer": "Одрекување од одговорност", + "UniGetUI is developed by Devolutions and is not affiliated with any of the compatible package managers.": "UniGetUI е развиен од Devolutions и не е поврзан со ниту еден од компатибилните менаџери на пакети.", + "UniGetUI wouldn't have been possible without the help of the contributors. Thank you all 🥳": "UniGetUI не би бил можен без помошта на придонесувачите. Ви благодарам на сите 🥳", + "UniGetUI uses the following libraries. Without them, UniGetUI wouldn't have been possible.": "UniGetUI ги користи следниве библиотеки. Без нив, UniGetUI немаше да биде можен.", + "{0} homepage": "Почетна страница на {0}", + "UniGetUI has been translated to more than 40 languages thanks to the volunteer translators. Thank you 🤝": "UniGetUI е преведен на повеќе од 40 јазици благодарение на волонтерите преведувачи. Ви благодариме 🤝", + "Verbose": "Детално", + "1 - Errors": "1 - Грешки", + "2 - Warnings": "2 - Предупредувања", + "3 - Information (less)": "3 - Информации (помалку)", + "4 - Information (more)": "4 - Информации (повеќе)", + "5 - information (debug)": "5 - Информации (дебаг)", + "Warning": "Предупредување", + "The following settings may pose a security risk, hence they are disabled by default.": "Следниве поставки можат да претставуваат безбедносен ризик, па затоа се стандардно оневозможени.", + "Enable the settings below if and only if you fully understand what they do, and the implications they may have.": "Овозможете ги поставките подолу ако и само ако целосно разбирате што прават и какви последици можат да имаат.", + "The settings will list, in their descriptions, the potential security issues they may have.": "Поставките во своите описи ќе ги наведат потенцијалните безбедносни проблеми што можат да ги имаат.", + "The backup will include the complete list of the installed packages and their installation options. Ignored updates and skipped versions will also be saved.": "Резервната копија ќе ја вклучи целосната листа на инсталирани пакети и нивните опции за инсталација. Ќе се зачуваат и игнорираните ажурирања и прескокнатите верзии.", + "The backup will NOT include any binary file nor any program's saved data.": "Резервната копија НЕМА да вклучува никаква бинарна датотека ниту зачувани податоци од било која програма.", + "The size of the backup is estimated to be less than 1MB.": "Големината на резервната копија се проценува дека е помала од 1MB.", + "The backup will be performed after login.": "Резервната копија ќе биде креирана по најавување.", + "{pcName} installed packages": "Инсталирани пакети на {pcName}", + "Current status: Not logged in": "Тековен статус: не сте најавени", + "You are logged in as {0} (@{1})": "Најавени сте како {0} (@{1})", + "Nice! Backups will be uploaded to a private gist on your account": "Одлично! Резервните копии ќе се прикачуваат во приватен gist на вашата сметка", + "Select backup": "Избери резервна копија", + "Settings imported from {0}": "Поставките се увезени од {0}", + "UniGetUI Settings": "Поставки на UniGetUI", + "Settings exported to {0}": "Поставките се извезени во {0}", + "UniGetUI settings were reset": "Поставките на UniGetUI беа ресетирани", + "Allow pre-release versions": "Дозволи предиздавачки верзии", + "Apply": "Примени", + "For security reasons, custom command-line arguments are disabled by default. Go to UniGetUI security settings to change this.": "Од безбедносни причини, сопствените аргументи на командната линија се стандардно оневозможени. Одете во безбедносните поставки на UniGetUI за да го промените ова.", + "Go to UniGetUI security settings": "Оди во безбедносните поставки на UniGetUI", + "The following options will be applied by default each time a {0} package is installed, upgraded or uninstalled.": "Следниве опции ќе се применуваат стандардно секогаш кога пакет {0} ќе се инсталира, надгради или деинсталира.", + "Package's default": "Стандардно за пакетот", + "Install location can't be changed for {0} packages": "Локацијата за инсталација не може да се смени за пакетите {0}", + "The local icon cache currently takes {0} MB": "Локалниот кеш на икони моментално зафаќа {0} MB", + "Username": "Корисничко име", + "Password": "Лозинка", + "Credentials": "Акредитиви", + "It is not guaranteed that the provided credentials will be stored safely": "Не е гарантирано дека дадените акредитиви ќе се чуваат безбедно", + "Partially": "Делумно", + "Package manager": "Менаџер на пакети", + "Compatible with proxy": "Компатибилно со прокси", + "Compatible with authentication": "Компатибилно со автентикација", + "Proxy compatibility table": "Табела за компатибилност со прокси", + "{0} settings": "Поставки за {0}", + "{0} status": "Статус на {0}", + "Default installation options for {0} packages": "Стандардни опции за инсталација за пакетите {0}", + "Expand version": "Прошири ја верзијата", + "The executable file for {0} was not found": "Извршната датотека за {0} не беше пронајдена", + "{pm} is disabled": "{pm} е оневозможен", + "Enable it to install packages from {pm}.": "Овозможи го за да инсталира пакети од {pm}.", + "{pm} is enabled and ready to go": "{pm} е овозможен и подготвен за работа", + "{pm} version:": "Верзија на {pm}:", + "{pm} was not found!": "{pm} не беше пронајден!", + "You may need to install {pm} in order to use it with UniGetUI.": "Можеби ќе треба да го инсталирате {pm} за да го користите со UniGetUI.", + "Scoop Installer - UniGetUI": "Scoop инсталатор - UniGetUI", + "Scoop Uninstaller - UniGetUI": "Scoop деинсталатор - UniGetUI", + "Clearing Scoop cache - UniGetUI": "Се чисти кешот на Scoop - UniGetUI", + "Restart UniGetUI to fully apply changes": "Рестартирајте го UniGetUI за целосно да се применат промените", + "Restart UniGetUI": "Рестартирај го UniGetUI", + "Manage {0} sources": "Управувајте со {0} извори", + "Add source": "Додај извор", + "Add": "Додај", + "Source name": "Име на изворот", + "Source URL": "URL на изворот", + "Other": "Друго", + "No minimum age": "Без минимална старост", + "1 day": "1 ден", + "{0} days": "{0} дена", + "Custom...": "Прилагодено...", + "{0} minutes": "{0} минути", + "1 hour": "1 час", + "{0} hours": "{0} часа", + "1 week": "1 недела", + "Supports release dates": "Поддржува датуми на издавање", + "Release date support per package manager": "Поддршка за датум на издавање по менаџер на пакети", + "Search for packages": "Пребарај пакети", + "Local": "Локално", + "OK": "Во ред", + "Last checked: {0}": "Последно проверено: {0}", + "{0} packages were found, {1} of which match the specified filters.": "Пронајдени се {0} пакети, од кои {1} одговараат на наведените филтри.", + "{0} selected": "Избрани се {0}", + "(Last checked: {0})": "(Последна проверка: {0})", + "All packages selected": "Избрани се сите пакети", + "Package selection cleared": "Изборот на пакети е исчистен", + "{0}: {1}": "{0}: {1}", + "More info": "Повеќе информации", + "GitHub account": "GitHub сметка", + "Log in with GitHub to enable cloud package backup.": "Најавете се со GitHub за да овозможите резервна копија на пакети во облак.", + "More details": "Повеќе детали", + "Log in": "Најави се", + "If you have cloud backup enabled, it will be saved as a GitHub Gist on this account": "Ако имате овозможена резервна копија во облак, таа ќе биде зачувана како GitHub Gist на оваа сметка", + "Log out": "Одјави се", + "About UniGetUI": "За UniGetUI", + "About": "За", + "Third-party licenses": "Лиценци од трети страни", + "Contributors": "Придонесувачи", + "Translators": "Преведувачи", + "Bundle security report": "Безбедносен извештај за збирката", + "The bundle contained restricted content": "Збирката содржеше ограничена содржина", + "UniGetUI – Crash Report": "UniGetUI – Извештај за пад", + "UniGetUI has crashed": "UniGetUI падна", + "Help us fix this by sending a crash report to Devolutions. All fields below are optional.": "Помогнете ни да го поправиме ова со испраќање извештај за падот до Devolutions. Сите полиња подолу се опционални.", + "Email (optional)": "Е-пошта (опционално)", + "your@email.com": "your@email.com", + "Additional details (optional)": "Дополнителни детали (опционално)", + "Describe what you were doing when the crash occurred…": "Опишете што правевте кога настана падот…", + "Crash report": "Извештај за пад", + "Don't Send": "Не испраќај", + "Send Report": "Испрати извештај", + "Sending…": "Се испраќа…", + "Unsaved changes": "Незачувани промени", + "You have unsaved changes in the current bundle. Do you want to discard them?": "Имате незачувани промени во тековната збирка. Дали сакате да ги отфрлите?", + "Discard changes": "Отфрли промени", + "Integrity violation": "Нарушување на интегритетот", + "UniGetUI or some of its components are missing or corrupt. It is strongly recommended to reinstall UniGetUI to adress the situation.": "UniGetUI или некои од неговите компоненти недостасуваат или се оштетени. Силно се препорачува повторно да го инсталирате UniGetUI за да ја решите ситуацијата.", + "• Refer to the UniGetUI Logs to get more details regarding the affected file(s)": "• Погледнете ги дневниците на UniGetUI за повеќе детали за засегнатите датотеки", + "• Integrity checks can be disabled from the Experimental Settings": "• Проверките на интегритет можат да се оневозможат од Експерименталните поставки", + "Manage shortcuts": "Управувај со кратенки", + "UniGetUI has detected the following desktop shortcuts which can be removed automatically on future upgrades": "UniGetUI ги откри следниве кратенки на работната површина што можат автоматски да се отстрануваат при идни надградби", + "Do you really want to reset this list? This action cannot be reverted.": "Дали навистина сакате да го ресетирате овој список? Ова дејство не може да се врати.", + "Desktop shortcuts list": "Список на кратенки на работната површина", + "Open in explorer": "Отвори во Explorer", + "Remove from list": "Отстрани од списокот", + "When new shortcuts are detected, delete them automatically instead of showing this dialog.": "Кога ќе се откријат нови кратенки, избриши ги автоматски наместо да го прикажуваш овој дијалог.", + "Not right now": "Не сега", + "Missing dependency": "Недостасува зависност", + "UniGetUI requires {0} to operate, but it was not found on your system.": "На UniGetUI му е потребен {0} за работа, но тој не беше пронајден на вашиот систем.", + "Click on Install to begin the installation process. If you skip the installation, UniGetUI may not work as expected.": "Кликнете на Инсталирај за да го започнете процесот на инсталација. Ако ја прескокнете инсталацијата, UniGetUI можеби нема да работи како што се очекува.", + "Alternatively, you can also install {0} by running the following command in a Windows PowerShell prompt:": "Исто така, можете да го инсталирате {0} со извршување на следнава команда во Windows PowerShell:", + "Install {0}": "Инсталирај {0}", + "Do not show this dialog again for {0}": "Не го прикажувај повторно овој дијалог за {0}", + "Please wait while {0} is being installed. A black window may show up. Please wait until it closes.": "Почекајте додека се инсталира {0}. Може да се појави црн прозорец. Почекајте додека не се затвори.", + "{0} has been installed successfully.": "{0} е успешно инсталиран.", + "Please click on \"Continue\" to continue": "Кликнете на \"Продолжи\" за да продолжите", + "Continue": "Продолжи", + "{0} has been installed successfully. It is recommended to restart UniGetUI to finish the installation": "{0} е успешно инсталиран. Препорачливо е да го рестартирате UniGetUI за да се заврши инсталацијата", + "Restart later": "Рестартирај подоцна", + "An error occurred:": "Настана грешка:", + "Please see the Command-line Output or refer to the Operation History for further information about the issue.": "Погледнете го Излезот од командна линија или Историјата на операции за повеќе информации за проблемот.", + "Retry as administrator": "Обиди се повторно како администратор", + "Retry interactively": "Повтори интерактивно", + "Retry skipping integrity checks": "Повтори со прескокнување на проверките на интегритет", + "Installation options": "Опции за инсталација", + "Save": "Зачувај", + "UniGetUI collects anonymous usage data with the sole purpose of understanding and improving the user experience.": "UniGetUI собира анонимни податоци за користење со единствена цел да го разбере и подобри корисничкото искуство.", + "More details about the shared data and how it will be processed": "Повеќе детали за споделените податоци и како ќе бидат обработени", + "Do you accept that UniGetUI collects and sends anonymous usage statistics, with the sole purpose of understanding and improving the user experience?": "Дали прифаќате UniGetUI да собира и испраќа анонимна статистика за користење, со единствена цел да го разбере и подобри корисничкото искуство?", + "Decline": "Одбиј", + "No personal information is collected nor sent, and the collected data is anonimized, so it can't be back-tracked to you.": "Не се собираат ниту се испраќаат лични информации, а собраните податоци се анонимизирани, па не можат да се поврзат назад со вас.", + "Navigation panel": "Панел за навигација", + "Operations": "Операции", + "Toggle operations panel": "Прикажи/скриј панел со операции", + "Bulk operations": "Масовни операции", + "Retry failed": "Повтори ги неуспешните", + "Clear successful": "Исчисти ги успешните", + "Clear finished": "Исчисти ги завршените", + "Cancel all": "Откажи ги сите", + "More": "Повеќе", + "Toggle navigation panel": "Прикажи/скриј го панелот за навигација", + "Minimize": "Минимизирај", + "Maximize": "Максимизирај", + "UniGetUI by Devolutions": "UniGetUI од Devolutions", + "UniGetUI is an application that makes managing your software easier, by providing an all-in-one graphical interface for your command-line package managers.": "UniGetUI е апликација што го олеснува управувањето со вашиот софтвер, обезбедувајќи сеопфатен графички интерфејс за вашите менаџери на пакети од командна линија.", + "Useful links": "Корисни врски", + "UniGetUI Homepage": "Почетна страница на UniGetUI", + "Report an issue or submit a feature request": "Пријави проблем или испрати барање за функција", + "UniGetUI Repository": "Репозиториум на UniGetUI", + "View GitHub Profile": "Погледни го GitHub профилот", + "UniGetUI License": "Лиценца на UniGetUI", + "Using UniGetUI implies the acceptation of the MIT License": "Користењето на UniGetUI подразбира прифаќање на MIT лиценцата", + "Become a translator": "Станете преведувач", + "Go back": "Оди назад", + "Go forward": "Оди напред", + "Go to home page": "Оди на почетната страница", + "Reload page": "Повторно вчитај ја страницата", + "View page on browser": "Прикажи ја страницата во прелистувач", + "The built-in browser is not supported on Linux yet.": "Вградениот прелистувач сè уште не е поддржан на Linux.", + "Open in browser": "Отвори во прелистувач", + "Copy to clipboard": "Копирај во таблата со исечоци", + "Export to a file": "Експортирај во датотека", + "Log level:": "Ниво на дневник:", + "Reload log": "Повторно вчитајте го дневникот", + "Export log": "Извези дневник", + "Text": "Текст", + "Change how operations request administrator rights": "Промени како операциите бараат администраторски права", + "Restrictions on package operations": "Ограничувања на операциите со пакети", + "Restrictions on package managers": "Ограничувања на менаџерите на пакети", + "Restrictions when importing package bundles": "Ограничувања при увоз на збирки на пакети", + "Ask for administrator privileges once for each batch of operations": "Побарај администраторски привилегии еднаш за секоја група операции", + "Ask only once for administrator privileges": "Побарај администраторски привилегии само еднаш", + "Prohibit any kind of Elevation via UniGetUI Elevator or GSudo": "Забрани каков било вид на подигнување преку UniGetUI Elevator или GSudo", + "This option WILL cause issues. Any operation incapable of elevating itself WILL FAIL. Install/update/uninstall as administrator will NOT WORK.": "Оваа опција ЌЕ предизвика проблеми. Секоја операција што не може самата да се подигне ЌЕ НЕ УСПЕЕ. Инсталирање/ажурирање/деинсталирање како администратор НЕМА ДА РАБОТИ.", + "Allow custom command-line arguments": "Дозволи сопствени аргументи на командната линија", + "Custom command-line arguments can change the way in which programs are installed, upgraded or uninstalled, in a way UniGetUI cannot control. Using custom command-lines can break packages. Proceed with caution.": "Сопствените аргументи на командната линија можат да го променат начинот на кој програмите се инсталираат, надградуваат или деинсталираат, на начин што UniGetUI не може да го контролира. Користењето сопствени командни линии може да ги расипе пакетите. Продолжете внимателно.", + "Ignore custom pre-install and post-install commands when importing packages from a bundle": "Игнорирај ги сопствените команди пред и по инсталација при увоз на пакети од збирка", + "Pre and post install commands will be run before and after a package gets installed, upgraded or uninstalled. Be aware that they may break things unless used carefully": "Командите пред и по инсталација ќе се извршуваат пред и по инсталирање, надградба или деинсталирање на пакет. Имајте предвид дека можат да предизвикаат проблеми ако не се користат внимателно", + "Allow changing the paths for package manager executables": "Дозволи промена на патеките за извршните датотеки на менаџерите на пакети", + "Turning this on enables changing the executable file used to interact with package managers. While this allows finer-grained customization of your install processes, it may also be dangerous": "Овозможувањето на оваа опција дозволува промена на извршната датотека што се користи за работа со менаџерите на пакети. Иако ова овозможува пофино приспособување на процесите на инсталација, може да биде и опасно", + "Allow importing custom command-line arguments when importing packages from a bundle": "Дозволи увоз на сопствени аргументи на командната линија при увоз на пакети од збирка", + "Malformed command-line arguments can break packages, or even allow a malicious actor to gain privileged execution. Therefore, importing custom command-line arguments is disabled by default": "Неправилно оформените аргументи на командната линија можат да ги расипат пакетите, па дури и да му дозволат на злонамерен актер да добие привилегирано извршување. Затоа, увозот на сопствени аргументи на командната линија е стандардно оневозможен.", + "Allow importing custom pre-install and post-install commands when importing packages from a bundle": "Дозволи увоз на сопствени команди пред и по инсталација при увоз на пакети од збирка", + "Pre and post install commands can do very nasty things to your device, if designed to do so. It can be very dangerous to import the commands from a bundle, unless you trust the source of that package bundle": "Командите пред и по инсталација можат да направат многу лоши работи на вашиот уред, ако се така дизајнирани. Може да биде многу опасно да увезувате команди од збирка, освен ако му верувате на изворот на таа збирка на пакети", + "Administrator rights and other dangerous settings": "Администраторски права и други опасни поставки", + "Package backup": "Резервна копија на пакети", + "Cloud package backup": "Резервна копија на пакети во облак", + "Local package backup": "Локална резервна копија на пакети", + "Local backup advanced options": "Напредни опции за локална резервна копија", + "Log in with GitHub": "Најави се со GitHub", + "Log out from GitHub": "Одјави се од GitHub", + "Periodically perform a cloud backup of the installed packages": "Периодично прави резервна копија во облак на инсталираните пакети", + "Cloud backup uses a private GitHub Gist to store a list of installed packages": "Резервната копија во облак користи приватен GitHub Gist за чување список на инсталирани пакети", + "Perform a cloud backup now": "Направи резервна копија во облак сега", + "Backup": "Резервна копија", + "Restore a backup from the cloud": "Врати резервна копија од облакот", + "Begin the process to select a cloud backup and review which packages to restore": "Започни го процесот на избор на резервна копија од облакот и преглед на пакетите за враќање", + "Periodically perform a local backup of the installed packages": "Периодично прави локална резервна копија на инсталираните пакети", + "Perform a local backup now": "Направи локална резервна копија сега", + "Change backup output directory": "Променете ја папката за резервни копии", + "Set a custom backup file name": "Постави сопствено име на резервната датотека", + "Leave empty for default": "Оставете празно за стандардно", + "Add a timestamp to the backup file names": "Додај временска ознака во имињата на резервните датотеки", + "Backup and Restore": "Резервна копија и враќање", + "Enable background api (UniGetUI Widgets and Sharing, port 7058)": "Овозможи background API (UniGetUI виџети и споделување, порта 7058)", + "Wait for the device to be connected to the internet before attempting to do tasks that require internet connectivity.": "Почекајте уредот да се поврзе на интернет пред да се обидете да извршите задачи што бараат интернет конекција.", + "Disable the 1-minute timeout for package-related operations": "Оневозможи го 1-минутното временско ограничување за операциите поврзани со пакети", + "Use installed GSudo instead of UniGetUI Elevator": "Користи инсталиран GSudo наместо UniGetUI Elevator", + "Use a custom icon and screenshot database URL": "Користи сопствен URL за базата на икони и слики од екранот", + "Enable background CPU Usage optimizations (see Pull Request #3278)": "Овозможи оптимизации за користење на CPU во заднина (види Pull Request #3278)", + "Perform integrity checks at startup": "Изврши проверки на интегритет при стартување", + "When batch installing packages from a bundle, install also packages that are already installed": "При масовна инсталација на пакети од збирка, инсталирај ги и пакетите што се веќе инсталирани", + "Experimental settings and developer options": "Експериментални поставки и опции за програмери", + "Show UniGetUI's version and build number on the titlebar.": "Прикажи ги верзијата и бројот на издание на UniGetUI во насловната лента.", + "Language": "Јазик", + "UniGetUI updater": "Ажурирач на UniGetUI", + "Telemetry": "Телеметрија", + "Manage UniGetUI settings": "Управувај со поставките на UniGetUI", + "Related settings": "Поврзани поставки", + "Update UniGetUI automatically": "Ажурирај го UniGetUI автоматски", + "Check for updates": "Провери за ажурирања", + "Install prerelease versions of UniGetUI": "Инсталирај предиздавачки верзии на UniGetUI", + "Manage telemetry settings": "Управувај со поставките за телеметрија", + "Manage": "Управувај", + "Import settings from a local file": "Импортирајте подесувања од локална датотека", + "Import": "Импортирање", + "Export settings to a local file": "Експортирај ги поставките во локална датотека", + "Export": "Експортирај", + "Reset UniGetUI": "Ресетирај го UniGetUI", + "User interface preferences": "Поставки за корисничкиот интерфејс", + "Application theme, startup page, package icons, clear successful installs automatically": "Тема на апликацијата, почетна страница, икони на пакети, автоматско чистење на успешните инсталации", + "General preferences": "Општи поставки", + "UniGetUI display language:": "Јазик на приказ на UniGetUI:", + "System language": "Системски јазик", + "Is your language missing or incomplete?": "Дали вашиот јазик недостасува или е нецелосен?", + "Appearance": "Изглед", + "UniGetUI on the background and system tray": "UniGetUI во заднина и системската фиока", + "Package lists": "Списоци на пакети", + "Use classic mode": "Користи класичен режим", + "Restart UniGetUI to apply this change": "Рестартирајте го UniGetUI за да ја примените оваа промена", + "The classic UI is disabled for beta testers": "Класичниот кориснички интерфејс е оневозможен за бета-тестерите", + "Close UniGetUI to the system tray": "Затвори го UniGetUI во системската фиока", + "Manage UniGetUI autostart behaviour": "Управувај со однесувањето на автоматското стартување на UniGetUI", + "Show package icons on package lists": "Прикажувај икони на пакетите во списоците со пакети", + "Clear cache": "Исчисти кеш", + "Select upgradable packages by default": "Стандардно избирај пакети што можат да се ажурираат", + "Light": "Светла", + "Dark": "Темна", + "Follow system color scheme": "Следете ја системската шема на бои", + "Application theme:": "Тема на апликацијата:", + "UniGetUI startup page:": "Почетна страница на UniGetUI:", + "Proxy settings": "Поставки за прокси", + "Other settings": "Други поставки", + "Connect the internet using a custom proxy": "Поврзи се на интернет преку сопствен прокси", + "Please note that not all package managers may fully support this feature": "Имајте предвид дека не сите менаџери на пакети можеби целосно ја поддржуваат оваа функција", + "Proxy URL": "URL на прокси", + "Enter proxy URL here": "Внесете URL на проксито тука", + "Authenticate to the proxy with a user and a password": "Автентицирај се на проксито со корисничко име и лозинка", + "Internet and proxy settings": "Поставки за интернет и прокси", + "Package manager preferences": "Поставки на менаџерот на пакети", + "Ready": "Подготвено", + "Not found": "Не е пронајдено", + "Notification preferences": "Поставки за известувања", + "Notification types": "Типови известувања", + "The system tray icon must be enabled in order for notifications to work": "Иконата во системската фиока мора да биде овозможена за известувањата да работат", + "Enable UniGetUI notifications": "Овозможи известувања од UniGetUI", + "Show a notification when there are available updates": "Прикажи известување кога има достапни ажурирања", + "Show a silent notification when an operation is running": "Прикажи тивко известување додека трае операција", + "Show a notification when an operation fails": "Прикажи известување кога операција ќе не успее", + "Show a notification when an operation finishes successfully": "Прикажи известување кога операција ќе заврши успешно", + "Concurrency and execution": "Паралелност и извршување", + "Automatic desktop shortcut remover": "Автоматско отстранување на кратенки од работната површина", + "Choose how many operations should be performed in parallel": "Избери колку операции треба да се извршуваат паралелно", + "Clear successful operations from the operation list after a 5 second delay": "Исчисти ги успешните операции од списокот на операции по одложување од 5 секунди", + "Download operations are not affected by this setting": "Операциите за преземање не се засегнати од оваа поставка", + "You may lose unsaved data": "Може да изгубите незачувани податоци", + "Ask to delete desktop shortcuts created during an install or upgrade.": "Прашај за бришење на кратенките на работната површина создадени при инсталација или надградба.", + "Package update preferences": "Поставки за ажурирање на пакети", + "Update check frequency, automatically install updates, etc.": "Фреквенција на проверка за ажурирања, автоматска инсталација на ажурирања итн.", + "Reduce UAC prompts, elevate installations by default, unlock certain dangerous features, etc.": "Намали ги UAC барањата, стандардно подигнувај инсталации, отклучи одредени опасни функции итн.", + "Package operation preferences": "Поставки за операции со пакети", + "Enable {pm}": "Овозможи {pm}", + "Not finding the file you are looking for? Make sure it has been added to path.": "Не ја наоѓате датотеката што ја барате? Проверете дали е додадена во path.", + "Select the executable to be used. The following list shows the executables found by UniGetUI": "Изберете ја извршната датотека што ќе се користи. Следниот список ги прикажува извршните датотеки пронајдени од UniGetUI", + "For security reasons, changing the executable file is disabled by default": "Поради безбедносни причини, менувањето на извршната датотека е стандардно оневозможено", + "Change this": "Промени го ова", + "Copy path": "Копирај патека", + "Current executable file:": "Тековна извршна датотека:", + "Ignore packages from {pm} when showing a notification about updates": "Игнорирај ги пакетите од {pm} при прикажување известување за ажурирања", + "Update security": "Безбедност на ажурирањата", + "Use global setting": "Користи глобална поставка", + "Minimum age for updates": "Минимална старост за ажурирања", + "e.g. 10": "на пр. 10", + "Custom minimum age (days)": "Прилагодена минимална старост (денови)", + "{pm} does not provide release dates for its packages, so this setting will have no effect": "{pm} не обезбедува датуми на издавање за своите пакети, па оваа поставка нема да има ефект", + "{pm} only provides release dates for some of its packages, so this setting will only apply to those packages": "{pm} обезбедува датуми на издавање само за некои од своите пакети, така што оваа поставка ќе важи само за тие пакети", + "Override the global minimum update age for this package manager": "Препокриј ја глобалната минимална старост на ажурирањата за овој менаџер на пакети", + "View {0} logs": "Погледни ги дневниците за {0}", + "If Python cannot be found or is not listing packages but is installed on the system, ": "Ако Python не може да се пронајде или не прикажува пакети, а е инсталиран на системот, ", + "Advanced options": "Напредни опции", + "WinGet command-line tool": "WinGet алатка од командна линија", + "Choose which command-line tool UniGetUI uses for WinGet operations when the COM API is not used": "Изберете која алатка од командна линија UniGetUI да ја користи за WinGet операции кога COM API не се користи", + "WinGet COM API": "WinGet COM API", + "Choose whether UniGetUI can use the WinGet COM API before falling back to the command-line tool": "Изберете дали UniGetUI може да го користи WinGet COM API пред да премине на алатката од командна линија", + "Reset WinGet": "Ресетирај го WinGet", + "This may help if no packages are listed": "Ова може да помогне ако не се прикажуваат пакети", + "Force install location parameter when updating packages with custom locations": "Присили параметар за локација на инсталација при ажурирање пакети со сопствени локации", + "Install Scoop": "Инсталирај Scoop", + "Uninstall Scoop (and its packages)": "Деинсталирај го Scoop (и неговите пакети)", + "Run cleanup and clear cache": "Изврши чистење и избриши кеш", + "Run": "Изврши", + "Enable Scoop cleanup on launch": "Овозможи чистење на Scoop при стартување", + "Default vcpkg triplet": "Стандарден vcpkg triplet", + "Change vcpkg root location": "Смени ја основната локација на vcpkg", + "Reset vcpkg root location": "Ресетирај ја локацијата на vcpkg коренот", + "Open vcpkg root location": "Отвори ја локацијата на vcpkg коренот", + "Language, theme and other miscellaneous preferences": "Јазик, тема и останати поставки", + "Show notifications on different events": "Прикажувај известувања при различни настани", + "Change how UniGetUI checks and installs available updates for your packages": "Промени како UniGetUI ги проверува и инсталира достапните ажурирања за вашите пакети", + "Automatically save a list of all your installed packages to easily restore them.": "Автоматски зачувајте листа со сите ваши инсталирани пакети за лесно да ги вратите.", + "Enable and disable package managers, change default install options, etc.": "Овозможувај и оневозможувај менаџери на пакети, менувај стандардни опции за инсталација итн.", + "Internet connection settings": "Поставки за интернет конекција", + "Proxy settings, etc.": "Поставки за прокси итн.", + "Beta features and other options that shouldn't be touched": "Бета функции и други опции што не треба да се допираат", + "Reload sources": "Повторно вчитај ги изворите", + "Delete source": "Избриши извор", + "Known sources": "Познати извори", + "Update checking": "Проверка за ажурирања", + "Automatic updates": "Автоматски ажурирања", + "Check for package updates periodically": "Повремено проверувајте за ажурирања на пакетите", + "Check for updates every:": "Проверувајте за ажурирања секој:", + "Install available updates automatically": "Автоматски инсталирај достапни ажурирања", + "Do not automatically install updates when the network connection is metered": "Не инсталирај ажурирања автоматски кога мрежната врска е мерена", + "Do not automatically install updates when the device runs on battery": "Не инсталирај ажурирања автоматски кога уредот работи на батерија", + "Do not automatically install updates when the battery saver is on": "Не инсталирај ажурирања автоматски кога е вклучен штедачот на батерија", + "Only show updates that are at least the specified number of days old": "Прикажувај само ажурирања што се стари најмалку наведениот број денови", + "Warn me when the installer URL host changes between the installed version and the new version (WinGet only)": "Предупреди ме кога хостот на URL-адресата на инсталаторот ќе се промени помеѓу инсталираната и новата верзија (само WinGet)", + "Change how UniGetUI handles install, update and uninstall operations.": "Промени како UniGetUI се справува со операциите за инсталација, ажурирање и деинсталација.", + "Navigation": "Навигација", + "Check for UniGetUI updates": "Провери за ажурирања на UniGetUI", + "Quit UniGetUI": "Излези од UniGetUI", + "Filters": "Филтри", + "Sources": "Извори", + "Search for packages to start": "Пребарај пакети за да започнете", + "Select all": "Избери сè", + "Clear selection": "Исчисти го изборот", + "Instant search": "Инстант пребарување", + "Distinguish between uppercase and lowercase": "Разликувај помеѓу големи и мали букви", + "Ignore special characters": "Игнорирај специјални знаци", + "Search mode": "Режим на пребарување", + "Both": "Двете", + "Exact match": "Точно совпаѓање", + "Show similar packages": "Прикажи слични пакети", + "Loading": "Се вчитува", + "Package": "Пакет", + "More options": "Повеќе опции", + "Order by:": "Подреди по:", + "Name": "Име", + "Id": "ID", + "Ascendant": "Растечки", + "Descendant": "Опаѓачки", + "View modes": "Режими на приказ", + "Reload": "Повторно вчитај", + "Closed": "Затворено", + "Ascending": "Растечки", + "Descending": "Опаѓачки", + "{0}: {1}, {2}": "{0}: {1}, {2}", + "Order by": "Подреди по", + "No results were found matching the input criteria": "Не беа пронајдени резултати што одговараат на внесените критериуми", + "No packages were found": "Не беа пронајдени пакети", + "Loading packages": "Се вчитуваат пакети", + "Skip integrity checks": "Прескокни проверки на интегритет", + "Download selected installers": "Преземи ги избраните инсталатори", + "Install selection": "Инсталирај го избраното", + "Install options": "Опции за инсталација", + "Add selection to bundle": "Додај го избраното во збирката", + "Download installer": "Преземи инсталатор", + "Uninstall selection": "Деинсталирај го избраното", + "Uninstall options": "Опции за деинсталација", + "Ignore selected packages": "Игнорирај ги избраните пакети", + "Open install location": "Отвори локација на инсталација", + "Reinstall package": "Реинсталирај го пакетот", + "Uninstall package, then reinstall it": "Деинсталирај го пакетот, а потоа повторно го инсталирај", + "Ignore updates for this package": "Игнорирај ажурирања за овој пакет", + "WinGet malfunction detected": "Откриен е проблем во WinGet", + "It looks like WinGet is not working properly. Do you want to attempt to repair WinGet?": "Изгледа дека WinGet не работи правилно. Дали сакате да се обидете да го поправите WinGet?", + "Repair WinGet": "Поправи WinGet", + "Updates will no longer be ignored for {0}": "Ажурирањата повеќе нема да се игнорираат за {0}", + "Updates are now ignored for {0}": "Ажурирањата сега се игнорираат за {0}", + "Do not ignore updates for this package anymore": "Повеќе не ги игнорирај ажурирањата за овој пакет", + "Add packages or open an existing package bundle": "Додај пакети или отвори постоечка збирка на пакети", + "Add packages to start": "Додај пакети за почеток", + "The current bundle has no packages. Add some packages to get started": "Тековната збирка нема пакети. Додајте неколку пакети за да започнете", + "New": "Ново", + "Save as": "Зачувај како", + "Create .ps1 script": "Создај .ps1 скрипта", + "Remove selection from bundle": "Отстрани го избраното од збирката", + "Skip hash checks": "Прескокни проверки на хаш", + "The package bundle is not valid": "Збирката на пакети не е валидна", + "The bundle you are trying to load appears to be invalid. Please check the file and try again.": "Збирката што се обидувате да ја вчитате изгледа невалидна. Проверете ја датотеката и обидете се повторно.", + "Package bundle": "Збирка на пакети", + "Could not create bundle": "Не можеше да се создаде збирката", + "The package bundle could not be created due to an error.": "Збирката на пакети не можеше да се создаде поради грешка.", + "Install script": "Инсталациска скрипта", + "PowerShell script": "PowerShell скрипта", + "The installation script saved to {0}": "Инсталациската скрипта е зачувана во {0}", + "An error occurred": "Настана грешка", + "An error occurred while attempting to create an installation script:": "Настана грешка при обидот за создавање инсталациска скрипта:", + "Hooray! No updates were found.": "Ура! Не беа пронајдени ажурирања!", + "Uninstall selected packages": "Деинсталирај ги избраните пакети", + "Update selection": "Ажурирај го избраното", + "Update options": "Опции за ажурирање", + "Uninstall package, then update it": "Деинсталирај го пакетот, а потоа го ажурирај", + "Uninstall package": "Деинсталирај го пакетот", + "Skip this version": "Прескокни ја оваа верзија", + "Pause updates for": "Паузирај ажурирања за", + "User | Local": "Корисник | Локално", + "Machine | Global": "Машина | Глобално", + "The default package manager for Debian/Ubuntu-based Linux distributions.
Contains: Debian/Ubuntu packages": "Стандардниот менаџер на пакети за Debian/Ubuntu-базирани Linux дистрибуции.
Содржи: Debian/Ubuntu пакети", + "The Rust package manager.
Contains: Rust libraries and programs written in Rust": "Менаџерот на пакети за Rust.
Содржи: Rust библиотеки и програми напишани на Rust", + "The classical package manager for windows. You'll find everything there.
Contains: General Software": "Класичниот менаџер на пакети за Windows. Таму ќе најдете сè.
Содржи: Општ софтвер", + "The default package manager for RHEL/Fedora-based Linux distributions.
Contains: RPM packages": "Стандардниот менаџер на пакети за RHEL/Fedora-базирани Linux дистрибуции.
Содржи: RPM пакети", + "A repository full of tools and executables designed with Microsoft's .NET ecosystem in mind.
Contains: .NET related tools and scripts": "Репозиториум полн со алатки и извршни датотеки дизајнирани за .NET екосистемот на Microsoft.
Содржи: .NET алатки и скрипти", + "The universal Linux package manager for desktop applications.
Contains: Flatpak applications from configured remotes": "Универзален Linux менаџер на пакети за десктоп апликации.
Содржи: Flatpak апликации од конфигурирани оддалечени извори", + "NuPkg (zipped manifest)": "NuPkg (спакуван манифест)", + "The Missing Package Manager for macOS (or Linux).
Contains: Formulae, Casks": "Менаџерот на пакети што недостасува за macOS (или Linux).
Содржи: Formulae, Casks", + "Node JS's package manager. Full of libraries and other utilities that orbit the javascript world
Contains: Node javascript libraries and other related utilities": "Node JS управувач со пакети. Полн со библиотеки и други алатки што орбитираат околу светот на Javascript
Содржи: Библиотеки на Node javascript и други поврзани алатки", + "The default package manager for Arch Linux and its derivatives.
Contains: Arch Linux packages": "Стандардниот менаџер на пакети за Arch Linux и неговите деривати.
Содржи: Arch Linux пакети", + "Python's library manager. Full of python libraries and other python-related utilities
Contains: Python libraries and related utilities": "Менаџер со библиотека на Python. Полн со библиотеки на Python и други алатки поврзани со Python
Содржи: библиотеки на Python и поврзани алатки", + "PowerShell's package manager. Find libraries and scripts to expand PowerShell capabilities
Contains: Modules, Scripts, Cmdlets": "Менаџерот на пакети на PowerShell. Пронајдете библиотеки и скрипти за проширување на можностите на PowerShell
Содржи: Модули, скрипти, Cmdlets", + "extracted": "извлечено", + "Scoop package": "Scoop пакет", + "Great repository of unknown but useful utilities and other interesting packages.
Contains: Utilities, Command-line programs, General Software (extras bucket required)": "Одличен репозиториум со непознати но корисни алатки и други интересни пакети.
Содржи: Алатки, програми од командна линија, општ софтвер (потребен е extras bucket)", + "The universal Linux package manager by Canonical.
Contains: Snap packages from the Snapcraft store": "Универзалниот Linux менаџер на пакети од Canonical.
Содржи: Snap пакети од продавницата Snapcraft", + "library": "библиотека", + "feature": "функција", + "A popular C/C++ library manager. Full of C/C++ libraries and other C/C++-related utilities
Contains: C/C++ libraries and related utilities": "Популарен менаџер за C/C++ библиотеки. Полн со C/C++ библиотеки и други алатки поврзани со C/C++
Содржи: C/C++ библиотеки и поврзани алатки", + "option": "опција", + "This package cannot be installed from an elevated context.": "Овој пакет не може да се инсталира од подигнат контекст.", + "Please run UniGetUI as a regular user and try again.": "Извршете го UniGetUI како обичен корисник и обидете се повторно.", + "Please check the installation options for this package and try again": "Проверете ги опциите за инсталација за овој пакет и обидете се повторно", + "Microsoft's official package manager. Full of well-known and verified packages
Contains: General Software, Microsoft Store apps": "Официјален менаџер на пакети на Microsoft. Полн со добро познати и проверени пакети
Содржи: Општ софтвер, апликации од Microsoft Store", + "Local PC": "Локален компјутер", + "Android Subsystem": "Андроид подсистем", + "Operation on queue (position {0})...": "Операција во редица (позиција {0})...", + "Click here for more details": "Кликнете овде за повеќе детали", + "Operation canceled by user": "Операцијата е откажана од корисникот", + "Running PreOperation ({0}/{1})...": "Се извршува PreOperation ({0}/{1})...", + "PreOperation {0} out of {1} failed, and was tagged as necessary. Aborting...": "PreOperation {0} од {1} не успеа и беше означена како неопходна. Се прекинува...", + "PreOperation {0} out of {1} finished with result {2}": "PreOperation {0} од {1} заврши со резултат {2}", + "Starting operation...": "Се започнува операцијата...", + "Running PostOperation ({0}/{1})...": "Се извршува PostOperation ({0}/{1})...", + "PostOperation {0} out of {1} failed, and was tagged as necessary. Aborting...": "PostOperation {0} од {1} не успеа и беше означена како неопходна. Се прекинува...", + "PostOperation {0} out of {1} finished with result {2}": "PostOperation {0} од {1} заврши со резултат {2}", + "{package} installer download": "Преземање на инсталаторот за {package}", + "{0} installer is being downloaded": "Се презема инсталаторот за {0}", + "Download succeeded": "Преземањето успеа", + "{package} installer was downloaded successfully": "Инсталаторот за {package} е успешно преземен", + "Download failed": "Преземањето не успеа", + "{package} installer could not be downloaded": "Инсталаторот за {package} не можеше да се преземе", + "{package} Installation": "Инсталација на {package}", + "{0} is being installed": "Се инсталира {0}", + "Installation succeeded": "Инсталацијата успеа", + "{package} was installed successfully": "{package} е успешно инсталиран", + "Installation failed": "Инсталацијата не успеа", + "{package} could not be installed": "{package} не можеше да се инсталира", + "{package} Update": "Ажурирање на {package}", + "Update succeeded": "Ажурирањето успеа", + "{package} was updated successfully": "{package} е успешно ажуриран", + "Update failed": "Ажурирањето не успеа", + "{package} could not be updated": "{package} не можеше да се ажурира", + "{package} Uninstall": "Деинсталација на {package}", + "{0} is being uninstalled": "Се деинсталира {0}", + "Uninstall succeeded": "Деинсталацијата успеа", + "{package} was uninstalled successfully": "{package} е успешно деинсталиран", + "Uninstall failed": "Деинсталацијата не успеа", + "{package} could not be uninstalled": "{package} не можеше да се деинсталира", + "Adding source {source}": "Се додава изворот {source}", + "Adding source {source} to {manager}": "Се додава изворот {source} во {manager}", + "Source added successfully": "Изворот е успешно додаден", + "The source {source} was added to {manager} successfully": "Изворот {source} е успешно додаден во {manager}", + "Could not add source": "Не можеше да се додаде изворот", + "Could not add source {source} to {manager}": "Не можеше да се додаде изворот {source} во {manager}", + "Removing source {source}": "Се отстранува изворот {source}", + "Removing source {source} from {manager}": "Се отстранува изворот {source} од {manager}", + "Source removed successfully": "Изворот е успешно отстранет", + "The source {source} was removed from {manager} successfully": "Изворот {source} е успешно отстранет од {manager}", + "Could not remove source": "Не можеше да се отстрани изворот", + "Could not remove source {source} from {manager}": "Не можеше да се отстрани изворот {source} од {manager}", + "The package manager \"{0}\" was not found": "Менаџерот на пакети \"{0}\" не беше пронајден", + "The package manager \"{0}\" is disabled": "Менаџерот на пакети \"{0}\" е оневозможен", + "There is an error with the configuration of the package manager \"{0}\"": "Има грешка во конфигурацијата на менаџерот на пакети \"{0}\"", + "The package \"{0}\" was not found on the package manager \"{1}\"": "Пакетот \"{0}\" не беше пронајден во менаџерот на пакети \"{1}\"", + "{0} is disabled": "{0} е оневозможен", + "{0} weeks": "{0} недели", + "1 month": "1 месец", + "{0} months": "{0} месеци", + "Something went wrong": "Нешто тргна наопаку", + "An interal error occurred. Please view the log for further details.": "Настана внатрешна грешка. Погледнете го дневникот за повеќе детали.", + "No applicable installer was found for the package {0}": "Не беше пронајден соодветен инсталатор за пакетот {0}", + "Integrity checks will not be performed during this operation": "Проверките на интегритет нема да се извршат за време на оваа операција", + "This is not recommended.": "Ова не се препорачува.", + "Run now": "Изврши сега", + "Run next": "Изврши следно", + "Run last": "Изврши последно", + "Show in explorer": "Прикажи во Explorer", + "Checked": "Означено", + "Unchecked": "Неозначено", + "This package is already installed": "Овој пакет е веќе инсталиран", + "This package can be upgraded to version {0}": "Овој пакет може да се надгради на верзија {0}", + "Updates for this package are ignored": "Ажурирањата за овој пакет се игнорираат", + "This package is being processed": "Овој пакет се обработува", + "This package is not available": "Овој пакет не е достапен", + "Select the source you want to add:": "Изберете го изворот што сакате да го додадете:", + "Source name:": "Име на изворот:", + "Source URL:": "URL на изворот:", + "An error occurred when adding the source: ": "Настана грешка при додавање на изворот: ", + "Package management made easy": "Лесно управување со пакети", + "version {0}": "верзија {0}", + "[RAN AS ADMINISTRATOR]": "[ИЗВРШЕНО КАКО АДМИНИСТРАТОР]", + "Portable mode": "Пренослив режим\n", + "DEBUG BUILD": "DEBUG ИЗДАНИЕ", + "Here you can change UniGetUI's behaviour regarding the following shortcuts. Checking a shortcut will make UniGetUI delete it if if gets created on a future upgrade. Unchecking it will keep the shortcut intact": "Тука можете да го промените однесувањето на UniGetUI во врска со следниве кратенки. Ако означите кратенка, UniGetUI ќе ја избрише ако се создаде при некое идно ажурирање. Ако ја отштиклирате, кратенката ќе остане недопрена.", + "Manual scan": "Рачно скенирање", + "Existing shortcuts on your desktop will be scanned, and you will need to pick which ones to keep and which ones to remove.": "Постоечките кратенки на вашата работна површина ќе бидат скенирани и ќе треба да изберете кои да ги задржите, а кои да ги отстраните.", + "Delete?": "Избриши?", + "I understand": "Разбирам", + "Chocolatey setup changed": "Поставувањето на Chocolatey е променето", + "UniGetUI no longer includes its own private Chocolatey installation. A legacy UniGetUI-managed Chocolatey installation was detected for this user profile, but system Chocolatey was not found. Chocolatey will stay unavailable in UniGetUI until Chocolatey is installed on the system and UniGetUI is restarted. Applications previously installed through UniGetUI's bundled Chocolatey may still appear under other sources such as Local PC or WinGet.": "UniGetUI повеќе не вклучува своја приватна инсталација на Chocolatey. Пронајдена е стара инсталација на Chocolatey управувана од UniGetUI за овој кориснички профил, но системскиот Chocolatey не е пронајден. Chocolatey ќе остане недостапен во UniGetUI додека не се инсталира Chocolatey на системот и не се рестартира UniGetUI. Апликациите претходно инсталирани преку вградениот Chocolatey на UniGetUI може сè уште да се појавуваат под други извори како Локален PC или WinGet.", + "NOTE: This troubleshooter can be disabled from UniGetUI Settings, on the WinGet section": "ЗАБЕЛЕШКА: Овој решавач на проблеми може да се оневозможи од Поставките на UniGetUI, во делот за WinGet", + "Restart": "Рестартирај", + "Are you sure you want to delete all shortcuts?": "Дали сте сигурни дека сакате да ги избришете сите кратенки?", + "Any new shorcuts created during an install or an update operation will be deleted automatically, instead of showing a confirmation prompt the first time they are detected.": "Сите нови кратенки создадени при инсталација или ажурирање ќе бидат избришани автоматски, наместо да се прикаже барање за потврда при првото откривање.", + "Any shorcuts created or modified outside of UniGetUI will be ignored. You will be able to add them via the {0} button.": "Сите кратенки создадени или изменети надвор од UniGetUI ќе бидат игнорирани. Ќе можете да ги додадете преку копчето {0}.", + "Are you really sure you want to enable this feature?": "Дали сте навистина сигурни дека сакате да ја овозможите оваа функција?", + "No new shortcuts were found during the scan.": "Не беа пронајдени нови кратенки при скенирањето.", + "How to add packages to a bundle": "Како да додадете пакети во збирка", + "In order to add packages to a bundle, you will need to: ": "За да додадете пакети во збирка, ќе треба да: ", + "1. Navigate to the \"{0}\" or \"{1}\" page.": "1. Одете на страницата \"{0}\" или \"{1}\".", + "2. Locate the package(s) you want to add to the bundle, and select their leftmost checkbox.": "2. Пронајдете ги пакетите што сакате да ги додадете во збирката и изберете го најлевото поле за избор.", + "3. When the packages you want to add to the bundle are selected, find and click the option \"{0}\" on the toolbar.": "3. Кога пакетите што сакате да ги додадете во збирката ќе бидат избрани, пронајдете ја и кликнете ја опцијата \"{0}\" на лентата со алатки.", + "4. Your packages will have been added to the bundle. You can continue adding packages, or export the bundle.": "4. Вашите пакети ќе бидат додадени во збирката. Можете да продолжите со додавање пакети или да ја извезете збирката.", + "Which backup do you want to open?": "Која резервна копија сакате да ја отворите?", + "Select the backup you want to open. Later, you will be able to review which packages you want to install.": "Изберете ја резервната копија што сакате да ја отворите. Подоцна ќе можете да прегледате кои пакети сакате да ги инсталирате.", + "There are ongoing operations. Quitting UniGetUI may cause them to fail. Do you want to continue?": "Во тек се операции. Затворањето на UniGetUI може да предизвика нивен неуспех. Дали сакате да продолжите?", + "UniGetUI or some of its components are missing or corrupt.": "UniGetUI или некои од неговите компоненти недостасуваат или се оштетени.", + "It is strongly recommended to reinstall UniGetUI to adress the situation.": "Силно се препорачува повторно да го инсталирате UniGetUI за да се реши ситуацијата.", + "Refer to the UniGetUI Logs to get more details regarding the affected file(s)": "Погледнете ги дневниците на UniGetUI за повеќе детали за засегнатите датотеки", + "Integrity checks can be disabled from the Experimental Settings": "Проверките на интегритет можат да се оневозможат од Експерименталните поставки", + "Repair UniGetUI": "Поправи UniGetUI", + "Live output": "Излез во живо", + "This package bundle had some settings that are potentially dangerous, and may be ignored by default.": "Оваа збирка на пакети имаше некои потенцијално опасни поставки, кои стандардно можат да бидат игнорирани.", + "Entries that show in YELLOW will be IGNORED.": "Ставките прикажани со ЖОЛТО ќе бидат ИГНОРИРАНИ.", + "Entries that show in RED will be IMPORTED.": "Ставките прикажани со ЦРВЕНО ќе бидат УВЕЗЕНИ.", + "You can change this behavior on UniGetUI security settings.": "Можете да го промените ова однесување во безбедносните поставки на UniGetUI.", + "Open UniGetUI security settings": "Отвори ги безбедносните поставки на UniGetUI", + "Should you modify the security settings, you will need to open the bundle again for the changes to take effect.": "Ако ги измените безбедносните поставки, ќе треба повторно да ја отворите збирката за да стапат промените на сила.", + "Details of the report:": "Детали за извештајот:", + "Are you sure you want to create a new package bundle? ": "Дали сте сигурни дека сакате да создадете нова збирка на пакети? ", + "Any unsaved changes will be lost": "Сите незачувани промени ќе бидат изгубени", + "Warning!": "Предупредување!", + "For security reasons, custom command-line arguments are disabled by default. Go to UniGetUI security settings to change this. ": "Поради безбедносни причини, сопствените аргументи на командната линија се стандардно оневозможени. Одете во безбедносните поставки на UniGetUI за да го промените ова. ", + "Change default options": "Промени ги стандардните опции", + "Ignore future updates for this package": "Игнорирај идни ажурирања за овој пакет", + "For security reasons, pre-operation and post-operation scripts are disabled by default. Go to UniGetUI security settings to change this. ": "Поради безбедносни причини, скриптите пред и по операција се стандардно оневозможени. Одете во безбедносните поставки на UniGetUI за да го промените ова. ", + "You can define the commands that will be run before or after this package is installed, updated or uninstalled. They will be run on a command prompt, so CMD scripts will work here.": "Можете да ги дефинирате командите што ќе се извршуваат пред или по инсталирање, ажурирање или деинсталирање на овој пакет. Тие ќе се извршуваат во command prompt, па CMD скриптите ќе работат тука.", + "Change this and unlock": "Промени го ова и отклучи", + "{0} Install options are currently locked because {0} follows the default install options.": "Опциите за инсталација на {0} моментално се заклучени затоа што {0} ги следи стандардните опции за инсталација.", + "Unset or unknown": "Непоставено или непознато", + "This package has no screenshots or is missing the icon? Contrbute to UniGetUI by adding the missing icons and screenshots to our open, public database.": "Овој пакет нема слики од екранот или му недостасува икона? Придонесете кон UniGetUI со додавање на иконите и сликите од екранот што недостасуваат во нашата отворена, јавна база на податоци.", + "Become a contributor": "Станете придонесувач", + "Update to {0} available": "Достапно е ажурирање на {0}", + "Reinstall": "Реинсталирај", + "Installer not available": "Инсталаторот не е достапен", + "Version:": "Верзија:", + "UniGetUI Version {0}": "UniGetUI верзија {0}", + "Performing backup, please wait...": "Се прави резервна копија, почекајте...", + "An error occurred while logging in: ": "Настана грешка при најавување: ", + "Fetching available backups...": "Се преземаат достапните резервни копии...", + "Done!": "Завршено!", + "The cloud backup has been loaded successfully.": "Резервната копија во облак е успешно вчитана.", + "An error occurred while loading a backup: ": "Настана грешка при вчитување резервна копија: ", + "Backing up packages to GitHub Gist...": "Се прави резервна копија на пакетите во GitHub Gist...", + "Backup Successful": "Резервната копија успеа", + "The cloud backup completed successfully.": "Резервната копија во облак заврши успешно.", + "Could not back up packages to GitHub Gist: ": "Не можеше да се направи резервна копија на пакетите во GitHub Gist: ", + "It is not guaranteed that the provided credentials will be stored safely, so you may as well not use the credentials of your bank account": "Не е загарантирано дека внесените акредитиви ќе се чуваат безбедно, затоа не користете ги акредитивите од вашата банкарска сметка", + "Enable the automatic WinGet troubleshooter": "Овозможи автоматски решавач на проблеми за WinGet", + "Add updates that fail with a 'no applicable update found' to the ignored updates list": "Додај ги ажурирањата што не успеваат со 'не е пронајдено соодветно ажурирање' во списокот со игнорирани ажурирања.", + "Invalid selection": "Невалиден избор", + "No package was selected": "Не беше избран пакет", + "More than 1 package was selected": "Избрани беа повеќе од 1 пакет", + "List": "Листа", + "Grid": "Мрежа", + "Icons": "Икони", + "\"{0}\" is a local package and does not have available details": "\"{0}\" е локален пакет и нема достапни детали", + "\"{0}\" is a local package and is not compatible with this feature": "\"{0}\" е локален пакет и не е компатибилен со оваа функција", + "Add packages to bundle": "Додај пакети во збирката", + "Preparing packages, please wait...": "Се подготвуваат пакетите, почекајте...", + "Loading packages, please wait...": "Се вчитуваат пакети, почекајте...", + "Saving packages, please wait...": "Се зачувуваат пакетите, почекајте...", + "The bundle was created successfully on {0}": "Збирката е успешно создадена на {0}", + "User profile": "Кориснички профил", + "Error": "Грешка", + "Log in failed: ": "Најавувањето не успеа: ", + "Log out failed: ": "Одјавувањето не успеа: ", + "Package backup settings": "Поставки за резервна копија на пакети", + "Manage UniGetUI autostart behaviour from the Settings app": "Управувај со однесувањето на автоматското стартување на UniGetUI", + "Choose how many operations shoulds be performed in parallel": "Избери колку операции треба да се извршуваат паралелно", + "Something went wrong while launching the updater.": "Нешто тргна наопаку при стартување на ажурирачот.", + "Please try again later": "Обидете се повторно подоцна", + "Show the release notes after UniGetUI is updated": "Прикажи ги белешките за изданието по ажурирањето на UniGetUI" +} diff --git a/src/Languages/lang_mr.json b/src/Languages/lang_mr.json new file mode 100644 index 0000000..47822c7 --- /dev/null +++ b/src/Languages/lang_mr.json @@ -0,0 +1,850 @@ +{ + "{0} of {1} operations completed": "{1} पैकी {0} क्रिया पूर्ण झाल्या", + "{0} is now {1}": "{0} आता {1} आहे", + "Enabled": "सक्षम", + "Disabled": "अक्षम", + "Privacy": "गोपनीयता", + "Hide my username from the logs": "लॉगमधून माझे वापरकर्तानाव लपवा", + "Replaces your username with **** in the logs. Restart UniGetUI to also hide it from already-recorded entries.": "लॉगमध्ये तुमचे वापरकर्तानाव **** ने बदलते. आधीच नोंदवलेल्या नोंदींमधूनही ते लपवण्यासाठी UniGetUI पुन्हा सुरू करा.", + "Your last update attempt did not complete.": "तुमचा मागील अद्यतन प्रयत्न पूर्ण झाला नाही.", + "UniGetUI could not confirm whether the update succeeded. Open the log to see what happened.": "अद्यतन यशस्वी झाले की नाही याची UniGetUI पुष्टी करू शकले नाही. काय झाले ते पाहण्यासाठी लॉग उघडा.", + "View log": "लॉग पहा", + "The installer reported success but did not restart UniGetUI.": "इंस्टॉलरने यशस्वी झाल्याचे कळवले, पण UniGetUI पुन्हा सुरू केले नाही.", + "The installer failed to initialize.": "इंस्टॉलर प्रारंभ करण्यात अयशस्वी झाला.", + "Setup was canceled before installation began.": "स्थापना सुरू होण्यापूर्वी सेटअप रद्द करण्यात आला.", + "A fatal error occurred during the preparation phase.": "तयारीच्या टप्प्यात गंभीर त्रुटी आली.", + "A fatal error occurred during installation.": "स्थापनेदरम्यान गंभीर त्रुटी आली.", + "Installation was canceled while in progress.": "स्थापना सुरू असताना रद्द करण्यात आली.", + "The installer was terminated by another process.": "इंस्टॉलर दुसऱ्या प्रक्रियेद्वारे समाप्त करण्यात आला.", + "The preparation phase determined the installation cannot proceed.": "तयारीच्या टप्प्यात स्थापना पुढे सुरू ठेवता येणार नाही असे ठरले.", + "The installer could not start. UniGetUI may already be running, or you do not have permission to install.": "इंस्टॉलर सुरू होऊ शकला नाही. UniGetUI आधीच चालू असू शकते किंवा तुम्हाला स्थापित करण्याची परवानगी नसू शकते.", + "Unexpected installer error.": "अनपेक्षित इंस्टॉलर त्रुटी.", + "We are checking for updates.": "आम्ही अद्यतने तपासत आहोत.", + "Please wait": "कृपया प्रतीक्षा करा", + "Great! You are on the latest version.": "छान! आपण नवीनतम आवृत्तीवर आहात.", + "There are no new UniGetUI versions to be installed": "स्थापित करण्यासाठी UniGetUI ची कोणतीही नवी आवृत्ती नाही", + "UniGetUI version {0} is being downloaded.": "UniGetUI आवृत्ती {0} डाउनलोड केली जात आहे.", + "This may take a minute or two": "यासाठी एक-दोन मिनिटे लागू शकतात", + "The installer authenticity could not be verified.": "इंस्टॉलरची प्रामाणिकता पडताळता आली नाही.", + "The update process has been aborted.": "अद्यतन प्रक्रिया रद्द करण्यात आली आहे.", + "Auto-update is not yet available on this platform.": "या प्लॅटफॉर्मवर स्वयं-अद्यतन अद्याप उपलब्ध नाही.", + "Please update UniGetUI manually.": "कृपया UniGetUI स्वतः अद्यतनित करा.", + "An error occurred when checking for updates: ": "अद्यतने तपासत असताना त्रुटी आली: ", + "The updater could not be launched.": "अपडेटर सुरू करता आला नाही.", + "The operating system did not start the installer process.": "ऑपरेटिंग सिस्टमने इंस्टॉलर प्रक्रिया सुरू केली नाही.", + "UniGetUI is being updated...": "UniGetUI अद्यतनित केले जात आहे...", + "Update installed.": "अद्यतन स्थापित झाले.", + "UniGetUI was updated successfully, but this running copy was not replaced. This usually means you are running a development build. Close this copy and start the newly-installed version to finish.": "UniGetUI यशस्वीरित्या अद्यतनित झाले, पण सध्या चालू असलेली प्रत बदलली गेली नाही. याचा सामान्यतः अर्थ तुम्ही विकास बिल्ड चालवत आहात. पूर्ण करण्यासाठी ही प्रत बंद करा आणि नव्याने स्थापित आवृत्ती सुरू करा.", + "The update could not be applied.": "अद्यतन लागू करता आले नाही.", + "Installer exit code {0}: {1}": "इंस्टॉलर निर्गमन कोड {0}: {1}", + "Update cancelled.": "अद्यतन रद्द केले.", + "Authentication was cancelled.": "प्रमाणीकरण रद्द केले.", + "Installer exit code {0}": "इंस्टॉलर निर्गमन कोड {0}", + "Operation in progress": "क्रिया सुरू आहे", + "Please wait...": "कृपया प्रतीक्षा करा...", + "Success!": "यशस्वी!", + "Failed": "अयशस्वी", + "An error occurred while processing this package": "हे पॅकेज प्रक्रिया करताना त्रुटी आली", + "Installer": "इंस्टॉलर", + "Executable": "एक्झिक्युटेबल", + "MSI": "MSI", + "Compressed file": "संकुचित फाइल", + "MSIX": "MSIX", + "WinGet was repaired successfully": "WinGet यशस्वीरित्या दुरुस्त झाले", + "It is recommended to restart UniGetUI after WinGet has been repaired": "WinGet दुरुस्त झाल्यानंतर UniGetUI पुन्हा सुरू करण्याची शिफारस केली जाते", + "WinGet could not be repaired": "WinGet दुरुस्त करता आले नाही", + "An unexpected issue occurred while attempting to repair WinGet. Please try again later": "WinGet दुरुस्त करण्याचा प्रयत्न करताना एक अनपेक्षित समस्या आली. कृपया नंतर पुन्हा प्रयत्न करा", + "Log in to enable cloud backup": "क्लाउड बॅकअप सक्षम करण्यासाठी लॉग इन करा", + "Backup Failed": "बॅकअप अयशस्वी", + "Downloading backup...": "बॅकअप डाउनलोड करत आहे...", + "An update was found!": "एक अद्यतन आढळले!", + "{0} can be updated to version {1}": "{0} ला आवृत्ती {1} पर्यंत अद्यतनित करता येईल", + "Updates found!": "अद्यतने आढळली!", + "{0} packages can be updated": "{0} पॅकेजेस अद्यतनित करता येतील", + "{0} is being updated to version {1}": "{0} ला आवृत्ती {1} वर अद्यतनित केले जात आहे", + "{0} packages are being updated": "{0} पॅकेजेस अद्यतनित होत आहेत", + "You have currently version {0} installed": "तुमच्याकडे सध्या आवृत्ती {0} स्थापित आहे", + "Desktop shortcut created": "डेस्कटॉप शॉर्टकट तयार झाला", + "UniGetUI has detected a new desktop shortcut that can be deleted automatically.": "UniGetUI ने एक नवीन डेस्कटॉप शॉर्टकट शोधला आहे जो आपोआप हटवता येऊ शकतो.", + "{0} desktop shortcuts created": "{0} डेस्कटॉप शॉर्टकट तयार झाले", + "UniGetUI has detected {0} new desktop shortcuts that can be deleted automatically.": "UniGetUI ने {0} नवीन डेस्कटॉप शॉर्टकट शोधले आहेत जे आपोआप हटवता येऊ शकतात.", + "Attention required": "लक्ष आवश्यक", + "Restart required": "पुन्हा सुरू करणे आवश्यक", + "1 update is available": "1 अद्यतन उपलब्ध आहे", + "{0} updates are available": "{0} अद्यतने उपलब्ध आहेत", + "Everything is up to date": "सर्व काही अद्ययावत आहे", + "Discover Packages": "पॅकेजेस शोधा", + "Available Updates": "उपलब्ध अद्यतने", + "Installed Packages": "स्थापित पॅकेजेस", + "UniGetUI Version {0} by Devolutions": "Devolutions कडून UniGetUI आवृत्ती {0}", + "Show UniGetUI": "UniGetUI दाखवा", + "Quit": "बाहेर पडा", + "Are you sure?": "तुम्हाला खात्री आहे का?", + "Do you really want to uninstall {0}?": "तुम्हाला खरोखर {0} विस्थापित करायचे आहे का?", + "Do you really want to uninstall the following {0} packages?": "तुम्हाला खरोखर खालील {0} पॅकेजेस विस्थापित करायची आहेत का?", + "No": "नाही", + "Yes": "होय", + "Partial": "अंशतः", + "View on UniGetUI": "UniGetUI वर पहा", + "Update": "अद्यतनित करा", + "Open UniGetUI": "UniGetUI उघडा", + "Update all": "सर्व अद्यतनित करा", + "Update now": "आता अद्यतनित करा", + "Installer host changed since the installed version.\n": "स्थापित आवृत्तीनंतर इंस्टॉलर होस्ट बदलला आहे.\n", + "This package is on the queue": "हे पॅकेज रांगेत आहे", + "installing": "स्थापित करत आहे", + "updating": "अद्यतनित करत आहे", + "uninstalling": "विस्थापित करत आहे", + "installed": "स्थापित झाले", + "Retry": "पुन्हा प्रयत्न करा", + "Install": "स्थापित करा", + "Uninstall": "विस्थापित करा", + "Open": "उघडा", + "Operation profile:": "क्रिया प्रोफाइल:", + "Follow the default options when installing, upgrading or uninstalling this package": "हे पॅकेज स्थापित, अद्यतनित किंवा विस्थापित करताना मूळ पर्याय वापरा", + "The following settings will be applied each time this package is installed, updated or removed.": "हे पॅकेज प्रत्येक वेळी स्थापित, अद्यतनित किंवा काढले जाताना खालील सेटिंग्ज लागू होतील.", + "Version to install:": "स्थापित करायची आवृत्ती:", + "Architecture to install:": "स्थापित करायची आर्किटेक्चर:", + "Installation scope:": "स्थापनेची व्याप्ती:", + "Install location:": "स्थापनेचे स्थान:", + "Select": "निवडा", + "Reset": "रीसेट करा", + "Custom install arguments:": "सानुकूल स्थापना वितर्क:", + "Custom update arguments:": "सानुकूल अद्यतन वितर्क:", + "Custom uninstall arguments:": "सानुकूल विस्थापन वितर्क:", + "Pre-install command:": "स्थापनेपूर्वीची आज्ञा:", + "Post-install command:": "स्थापनेनंतरची आज्ञा:", + "Abort install if pre-install command fails": "स्थापनेपूर्वीची आज्ञा अयशस्वी झाल्यास स्थापना थांबवा", + "Pre-update command:": "अद्यतनापूर्वीची आज्ञा:", + "Post-update command:": "अद्यतनानंतरची आज्ञा:", + "Abort update if pre-update command fails": "अद्यतनापूर्वीची आज्ञा अयशस्वी झाल्यास अद्यतन थांबवा", + "Pre-uninstall command:": "विस्थापनापूर्वीची आज्ञा:", + "Post-uninstall command:": "विस्थापनानंतरची आज्ञा:", + "Abort uninstall if pre-uninstall command fails": "विस्थापनापूर्वीची आज्ञा अयशस्वी झाल्यास विस्थापन थांबवा", + "Command-line to run:": "चालवायची कमांड-लाइन:", + "Save and close": "जतन करा आणि बंद करा", + "General": "सामान्य", + "Architecture & Location": "आर्किटेक्चर आणि स्थान", + "Command-line": "कमांड-लाइन", + "Close apps": "ॲप्स बंद करा", + "Pre/Post install": "स्थापनेपूर्वी/नंतर", + "Select the processes that should be closed before this package is installed, updated or uninstalled.": "हे पॅकेज स्थापित, अद्ययावत किंवा अनइंस्टॉल करण्यापूर्वी कोणत्या प्रक्रिया बंद करायच्या ते निवडा.", + "Write here the process names here, separated by commas (,)": "प्रक्रियांची नावे येथे स्वल्पविरामाने (,) वेगळी करून लिहा", + "Try to kill the processes that refuse to close when requested to": "बंद करण्यास सांगितल्यावरही बंद न होणाऱ्या प्रक्रिया समाप्त करण्याचा प्रयत्न करा", + "Run as admin": "प्रशासक म्हणून चालवा", + "Interactive installation": "परस्परसंवादी स्थापना", + "Skip hash check": "हॅश तपासणी वगळा", + "Uninstall previous versions when updated": "अद्यतनित करताना मागील आवृत्त्या विस्थापित करा", + "Skip minor updates for this package": "या पॅकेजसाठी किरकोळ अद्यतने वगळा", + "Automatically update this package": "हे पॅकेज आपोआप अद्यतनित करा", + "{0} installation options": "{0} स्थापनेचे पर्याय", + "Latest": "नवीनतम", + "PreRelease": "पूर्वप्रकाशन", + "Default": "मूळ", + "Manage ignored updates": "दुर्लक्षित अद्यतने व्यवस्थापित करा", + "The packages listed here won't be taken in account when checking for updates. Double-click them or click the button on their right to stop ignoring their updates.": "अद्यतने तपासताना येथे सूचीबद्ध पॅकेजेस विचारात घेतली जाणार नाहीत. त्यांची अद्यतने दुर्लक्षित करणे थांबवण्यासाठी त्यांच्यावर दुहेरी-क्लिक करा किंवा त्यांच्या उजवीकडील बटणावर क्लिक करा.", + "Reset list": "यादी रीसेट करा", + "Do you really want to reset the ignored updates list? This action cannot be reverted": "तुम्हाला खरोखर दुर्लक्षित अद्यतनांची यादी रीसेट करायची आहे का? ही क्रिया पूर्ववत करता येणार नाही", + "No ignored updates": "दुर्लक्षित अद्यतने नाहीत", + "Package Name": "पॅकेज नाव", + "Package ID": "पॅकेज आयडी", + "Ignored version": "दुर्लक्षित आवृत्ती", + "New version": "नवीन आवृत्ती", + "Source": "स्रोत", + "All versions": "सर्व आवृत्त्या", + "Unknown": "अज्ञात", + "Up to date": "अद्ययावत", + "Package {name} from {manager}": "{manager} मधील पॅकेज {name}", + "Remove {0} from ignored updates": "{0} ला दुर्लक्षित अद्यतनांमधून काढा", + "Cancel": "रद्द करा", + "Administrator privileges": "प्रशासक अधिकार", + "This operation is running with administrator privileges.": "ही क्रिया प्रशासक अधिकारांसह चालू आहे.", + "Interactive operation": "परस्परसंवादी क्रिया", + "This operation is running interactively.": "ही क्रिया परस्परसंवादी पद्धतीने चालू आहे.", + "You will likely need to interact with the installer.": "तुम्हाला कदाचित इंस्टॉलरशी संवाद साधावा लागेल.", + "Integrity checks skipped": "अखंडता तपासण्या वगळल्या", + "Integrity checks will not be performed during this operation.": "या क्रियेदरम्यान अखंडता तपासण्या केल्या जाणार नाहीत.", + "Proceed at your own risk.": "पुढे जाणे तुमच्या स्वतःच्या जोखमीवर आहे.", + "Close": "बंद करा", + "Loading...": "लोड करत आहे...", + "Installer SHA256": "इंस्टॉलर SHA256", + "Homepage": "मुखपृष्ठ", + "Author": "लेखक", + "Publisher": "प्रकाशक", + "License": "परवाना", + "Manifest": "मॅनिफेस्ट", + "Installer Type": "इंस्टॉलर प्रकार", + "Size": "आकार", + "Installer URL": "इंस्टॉलर URL", + "Last updated:": "शेवटचे अद्यतन:", + "Release notes URL": "प्रकाशन नोंदी URL", + "Package details": "पॅकेज तपशील", + "Dependencies:": "अवलंबने:", + "Release notes": "प्रकाशन नोंदी", + "Screenshots": "स्क्रीनशॉट्स", + "This package has no screenshots or is missing the icon? Contribute to UniGetUI by adding the missing icons and screenshots to our open, public database.": "या पॅकेजमध्ये स्क्रीनशॉट्स नाहीत किंवा त्याचे चिन्ह गहाळ आहे का? गहाळ चिन्हे आणि स्क्रीनशॉट्स आमच्या खुल्या, सार्वजनिक डेटाबेसमध्ये जोडून UniGetUI मध्ये योगदान द्या.", + "Version": "आवृत्ती", + "Install as administrator": "प्रशासक म्हणून स्थापित करा", + "Update to version {0}": "आवृत्ती {0} वर अद्यतनित करा", + "Installed Version": "स्थापित आवृत्ती", + "Update as administrator": "प्रशासक म्हणून अद्यतनित करा", + "Interactive update": "परस्परसंवादी अद्यतन", + "Uninstall as administrator": "प्रशासक म्हणून विस्थापित करा", + "Interactive uninstall": "परस्परसंवादी विस्थापना", + "Uninstall and remove data": "विस्थापित करा आणि डेटा हटवा", + "Not available": "उपलब्ध नाही", + "Installer SHA512": "इंस्टॉलर SHA512", + "Unknown size": "अज्ञात आकार", + "No dependencies specified": "कोणतीही अवलंबने दिलेली नाहीत", + "mandatory": "अनिवार्य", + "optional": "ऐच्छिक", + "UniGetUI {0} is ready to be installed.": "UniGetUI {0} स्थापित करण्यासाठी तयार आहे.", + "The update process will start after closing UniGetUI": "UniGetUI बंद केल्यानंतर अद्यतन प्रक्रिया सुरू होईल", + "UniGetUI has been ran as administrator, which is not recommended. When running UniGetUI as administrator, EVERY operation launched from UniGetUI will have administrator privileges. You can still use the program, but we highly recommend not running UniGetUI with administrator privileges.": "UniGetUI प्रशासक म्हणून चालवले गेले आहे, जे शिफारसीय नाही. UniGetUI प्रशासक म्हणून चालवल्यास, UniGetUI मधून सुरू केलेली प्रत्येक क्रिया प्रशासकीय विशेषाधिकारांसह चालेल. तुम्ही तरीही हा कार्यक्रम वापरू शकता, पण आम्ही ठामपणे शिफारस करतो की UniGetUI प्रशासकीय विशेषाधिकारांसह चालवू नका.", + "Share anonymous usage data": "अनामिक वापर डेटा शेअर करा", + "UniGetUI collects anonymous usage data in order to improve the user experience.": "वापरकर्ता अनुभव सुधारण्यासाठी UniGetUI अनामिक वापर डेटा संकलित करते.", + "Accept": "स्वीकारा", + "Software Updates": "सॉफ्टवेअर अद्यतने", + "Package Bundles": "पॅकेज बंडल्स", + "Settings": "सेटिंग्ज", + "Package Managers": "पॅकेज व्यवस्थापक", + "UniGetUI Log": "UniGetUI लॉग", + "Package Manager logs": "पॅकेज व्यवस्थापक नोंदी", + "Operation history": "क्रिया इतिहास", + "Help": "मदत", + "UniGetUI": "UniGetUI", + "You have installed UniGetUI Version {0}": "तुम्ही UniGetUI आवृत्ती {0} स्थापित केली आहे", + "Disclaimer": "अस्वीकरण", + "UniGetUI is developed by Devolutions and is not affiliated with any of the compatible package managers.": "UniGetUI हे Devolutions द्वारे विकसित केले गेले आहे आणि ते कोणत्याही सुसंगत पॅकेज व्यवस्थापकांशी संलग्न नाही.", + "UniGetUI wouldn't have been possible without the help of the contributors. Thank you all 🥳": "योगदानकर्त्यांच्या मदतीशिवाय UniGetUI शक्य झाले नसते. तुम्हा सर्वांचे आभार 🥳", + "UniGetUI uses the following libraries. Without them, UniGetUI wouldn't have been possible.": "UniGetUI खालील ग्रंथालये वापरते. त्यांच्याशिवाय UniGetUI शक्य झाले नसते.", + "{0} homepage": "{0} मुख्यपृष्ठ", + "UniGetUI has been translated to more than 40 languages thanks to the volunteer translators. Thank you 🤝": "स्वयंसेवक अनुवादकांमुळे UniGetUI चे 40 पेक्षा अधिक भाषांमध्ये भाषांतर झाले आहे. धन्यवाद 🤝", + "Verbose": "तपशीलवार", + "1 - Errors": "1 - त्रुटी", + "2 - Warnings": "2 - इशारे", + "3 - Information (less)": "3 - माहिती (कमी)", + "4 - Information (more)": "4 - माहिती (अधिक)", + "5 - information (debug)": "5 - माहिती (डीबग)", + "Warning": "इशारा", + "The following settings may pose a security risk, hence they are disabled by default.": "खालील सेटिंग्ज सुरक्षा जोखीम निर्माण करू शकतात, म्हणून त्या डीफॉल्टनुसार निष्क्रिय आहेत.", + "Enable the settings below if and only if you fully understand what they do, and the implications they may have.": "खालील सेटिंग्ज फक्त त्या काय करतात आणि त्यांचे परिणाम काय असू शकतात हे तुम्हाला पूर्णपणे समजत असल्यासच सक्षम करा.", + "The settings will list, in their descriptions, the potential security issues they may have.": "या सेटिंग्जच्या वर्णनांत त्यांच्याशी संबंधित संभाव्य सुरक्षा समस्या दिलेल्या असतील.", + "The backup will include the complete list of the installed packages and their installation options. Ignored updates and skipped versions will also be saved.": "बॅकअपमध्ये स्थापित पॅकेजांची संपूर्ण यादी आणि त्यांचे स्थापना पर्याय समाविष्ट असतील. दुर्लक्षित अद्यतने आणि वगळलेल्या आवृत्त्याही जतन केल्या जातील.", + "The backup will NOT include any binary file nor any program's saved data.": "बॅकअपमध्ये कोणतीही बायनरी फाइल किंवा कोणत्याही कार्यक्रमाचा जतन केलेला डेटा समाविष्ट नसेल.", + "The size of the backup is estimated to be less than 1MB.": "बॅकअपचा आकार 1MB पेक्षा कमी असेल असा अंदाज आहे.", + "The backup will be performed after login.": "लॉग इन केल्यानंतर बॅकअप घेतला जाईल.", + "{pcName} installed packages": "{pcName} वरील स्थापित पॅकेजेस", + "Current status: Not logged in": "सध्याची स्थिती: लॉग इन केलेले नाही", + "You are logged in as {0} (@{1})": "तुम्ही {0} (@{1}) म्हणून लॉग इन आहात", + "Nice! Backups will be uploaded to a private gist on your account": "छान! बॅकअप तुमच्या खात्यातील खाजगी gist वर अपलोड केले जातील", + "Select backup": "बॅकअप निवडा", + "Settings imported from {0}": "{0} मधून सेटिंग्ज आयात केल्या", + "UniGetUI Settings": "UniGetUI सेटिंग्ज", + "Settings exported to {0}": "{0} मध्ये सेटिंग्ज निर्यात केल्या", + "UniGetUI settings were reset": "UniGetUI सेटिंग्ज रीसेट केल्या गेल्या", + "Allow pre-release versions": "पूर्व-प्रकाशन आवृत्त्यांना परवानगी द्या", + "Apply": "लागू करा", + "For security reasons, custom command-line arguments are disabled by default. Go to UniGetUI security settings to change this.": "सुरक्षेच्या कारणास्तव, सानुकूल कमांड-लाइन युक्तिवाद डीफॉल्टनुसार निष्क्रिय आहेत. हे बदलण्यासाठी UniGetUI सुरक्षा सेटिंग्जमध्ये जा.", + "Go to UniGetUI security settings": "UniGetUI सुरक्षा सेटिंग्जमध्ये जा", + "The following options will be applied by default each time a {0} package is installed, upgraded or uninstalled.": "खालील पर्याय प्रत्येक वेळी {0} पॅकेज स्थापित, अद्यतनित किंवा विस्थापित केल्यावर डीफॉल्टनुसार लागू होतील.", + "Package's default": "पॅकेजचे डीफॉल्ट", + "Install location can't be changed for {0} packages": "{0} पॅकेजेससाठी स्थापना स्थान बदलता येत नाही", + "The local icon cache currently takes {0} MB": "स्थानिक आयकॉन कॅश सध्या {0} MB जागा घेत आहे", + "Username": "वापरकर्तानाव", + "Password": "संकेतशब्द", + "Credentials": "प्रवेश तपशील", + "It is not guaranteed that the provided credentials will be stored safely": "दिलेले प्रवेश तपशील सुरक्षितपणे साठवले जातील याची हमी नाही", + "Partially": "अंशतः", + "Package manager": "पॅकेज व्यवस्थापक", + "Compatible with proxy": "प्रॉक्सीशी सुसंगत", + "Compatible with authentication": "प्रमाणीकरणाशी सुसंगत", + "Proxy compatibility table": "प्रॉक्सी सुसंगतता तक्ता", + "{0} settings": "{0} सेटिंग्ज", + "{0} status": "{0} स्थिती", + "Default installation options for {0} packages": "{0} पॅकेजेससाठी डीफॉल्ट स्थापना पर्याय", + "Expand version": "आवृत्ती विस्तृत करा", + "The executable file for {0} was not found": "{0} साठी कार्यान्वयनीय फाइल सापडली नाही", + "{pm} is disabled": "{pm} निष्क्रिय आहे", + "Enable it to install packages from {pm}.": "{pm} मधून पॅकेजेस स्थापित करण्यासाठी ते सक्षम करा.", + "{pm} is enabled and ready to go": "{pm} सक्षम आहे आणि वापरासाठी तयार आहे", + "{pm} version:": "{pm} आवृत्ती:", + "{pm} was not found!": "{pm} सापडले नाही!", + "You may need to install {pm} in order to use it with UniGetUI.": "UniGetUI सोबत वापरण्यासाठी तुम्हाला {pm} स्थापित करावे लागू शकते.", + "Scoop Installer - UniGetUI": "Scoop इंस्टॉलर - UniGetUI", + "Scoop Uninstaller - UniGetUI": "Scoop अनइंस्टॉलर - UniGetUI", + "Clearing Scoop cache - UniGetUI": "Scoop कॅश साफ करणे - UniGetUI", + "Restart UniGetUI to fully apply changes": "बदल पूर्णपणे लागू करण्यासाठी UniGetUI पुन्हा सुरू करा", + "Restart UniGetUI": "UniGetUI पुन्हा सुरू करा", + "Manage {0} sources": "{0} स्रोत व्यवस्थापित करा", + "Add source": "स्रोत जोडा", + "Add": "जोडा", + "Source name": "स्रोत नाव", + "Source URL": "स्रोत URL", + "Other": "इतर", + "No minimum age": "किमान वय नाही", + "1 day": "1 दिवस", + "{0} days": "{0} दिवस", + "Custom...": "सानुकूल...", + "{0} minutes": "{0} मिनिटे", + "1 hour": "एक तास", + "{0} hours": "{0} तास", + "1 week": "एक आठवडा", + "Supports release dates": "प्रकाशन दिनांकांना समर्थन", + "Release date support per package manager": "प्रत्येक पॅकेज व्यवस्थापकानुसार प्रकाशन दिनांक समर्थन", + "Search for packages": "पॅकेजेस शोधा", + "Local": "स्थानिक", + "OK": "OK", + "Last checked: {0}": "शेवटची तपासणी: {0}", + "{0} packages were found, {1} of which match the specified filters.": "{0} पॅकेजेस आढळली, त्यापैकी {1} निर्दिष्ट फिल्टर्सशी जुळतात.", + "{0} selected": "{0} निवडले", + "(Last checked: {0})": "(शेवटची तपासणी: {0})", + "All packages selected": "सर्व पॅकेजेस निवडली", + "Package selection cleared": "पॅकेज निवड रद्द केली", + "{0}: {1}": "{0}: {1}", + "More info": "अधिक माहिती", + "GitHub account": "GitHub खाते", + "Log in with GitHub to enable cloud package backup.": "क्लाउड पॅकेज बॅकअप सक्षम करण्यासाठी GitHub सह लॉग इन करा.", + "More details": "अधिक तपशील", + "Log in": "लॉग इन", + "If you have cloud backup enabled, it will be saved as a GitHub Gist on this account": "जर तुम्ही क्लाउड बॅकअप सक्षम केले असेल, तर ते या खात्यावर GitHub Gist म्हणून जतन केले जाईल", + "Log out": "लॉग आउट", + "About UniGetUI": "UniGetUI बद्दल", + "About": "बद्दल", + "Third-party licenses": "तृतीय-पक्ष परवाने", + "Contributors": "योगदानकर्ते", + "Translators": "अनुवादक", + "Bundle security report": "बंडल सुरक्षा अहवाल", + "The bundle contained restricted content": "बंडलमध्ये प्रतिबंधित सामग्री होती", + "UniGetUI – Crash Report": "UniGetUI – क्रॅश अहवाल", + "UniGetUI has crashed": "UniGetUI क्रॅश झाले आहे", + "Help us fix this by sending a crash report to Devolutions. All fields below are optional.": "Devolutions ला क्रॅश अहवाल पाठवून हे दुरुस्त करण्यात आम्हाला मदत करा. खालील सर्व फील्ड ऐच्छिक आहेत.", + "Email (optional)": "ईमेल (ऐच्छिक)", + "your@email.com": "your@email.com", + "Additional details (optional)": "अतिरिक्त तपशील (ऐच्छिक)", + "Describe what you were doing when the crash occurred…": "क्रॅश झाला तेव्हा तुम्ही काय करत होता ते वर्णन करा…", + "Crash report": "क्रॅश अहवाल", + "Don't Send": "पाठवू नका", + "Send Report": "अहवाल पाठवा", + "Sending…": "पाठवत आहे…", + "Unsaved changes": "न जतन केलेले बदल", + "You have unsaved changes in the current bundle. Do you want to discard them?": "सध्याच्या बंडलमध्ये तुमचे न जतन केलेले बदल आहेत. तुम्हाला ते रद्द करायचे आहेत का?", + "Discard changes": "बदल रद्द करा", + "Integrity violation": "अखंडता उल्लंघन", + "UniGetUI or some of its components are missing or corrupt. It is strongly recommended to reinstall UniGetUI to adress the situation.": "UniGetUI किंवा त्याचे काही घटक गहाळ आहेत किंवा खराब झाले आहेत. ही परिस्थिती सोडवण्यासाठी UniGetUI पुन्हा स्थापित करण्याची जोरदार शिफारस केली जाते.", + "• Refer to the UniGetUI Logs to get more details regarding the affected file(s)": "• प्रभावित फाइल्सबद्दल अधिक तपशीलांसाठी UniGetUI Logs पाहा", + "• Integrity checks can be disabled from the Experimental Settings": "• Experimental Settings मधून अखंडता तपासणी निष्क्रिय करता येते", + "Manage shortcuts": "शॉर्टकट्स व्यवस्थापित करा", + "UniGetUI has detected the following desktop shortcuts which can be removed automatically on future upgrades": "UniGetUI ने खालील डेस्कटॉप शॉर्टकट्स शोधले आहेत, जे पुढील अपग्रेड्समध्ये आपोआप काढले जाऊ शकतात", + "Do you really want to reset this list? This action cannot be reverted.": "तुम्हाला ही यादी खरोखर रीसेट करायची आहे का? ही कृती मागे घेतली जाऊ शकत नाही.", + "Desktop shortcuts list": "डेस्कटॉप शॉर्टकट यादी", + "Open in explorer": "Explorer मध्ये उघडा", + "Remove from list": "यादीतून काढा", + "When new shortcuts are detected, delete them automatically instead of showing this dialog.": "नवीन शॉर्टकट्स आढळल्यावर, हा संवाद दाखवण्याऐवजी ते आपोआप हटवा.", + "Not right now": "आत्ता नाही", + "Missing dependency": "गहाळ अवलंबन", + "UniGetUI requires {0} to operate, but it was not found on your system.": "UniGetUI चालण्यासाठी {0} आवश्यक आहे, पण ते तुमच्या प्रणालीवर आढळले नाही.", + "Click on Install to begin the installation process. If you skip the installation, UniGetUI may not work as expected.": "स्थापना प्रक्रिया सुरू करण्यासाठी Install वर क्लिक करा. तुम्ही स्थापना वगळल्यास, UniGetUI अपेक्षेप्रमाणे कार्य न करू शकते.", + "Alternatively, you can also install {0} by running the following command in a Windows PowerShell prompt:": "पर्यायाने, तुम्ही Windows PowerShell प्रॉम्प्टमध्ये खालील आदेश चालवून {0} स्थापित करू शकता:", + "Install {0}": "{0} स्थापित करा", + "Do not show this dialog again for {0}": "{0} साठी हा संवाद पुन्हा दाखवू नका", + "Please wait while {0} is being installed. A black window may show up. Please wait until it closes.": "कृपया {0} स्थापित होत असताना प्रतीक्षा करा. काळी (किंवा निळी) विंडो दिसू शकते. ती बंद होईपर्यंत कृपया प्रतीक्षा करा.", + "{0} has been installed successfully.": "{0} यशस्वीरित्या स्थापित झाले आहे.", + "Please click on \"Continue\" to continue": "पुढे सुरू ठेवण्यासाठी कृपया \"Continue\" वर क्लिक करा", + "Continue": "सुरू ठेवा", + "{0} has been installed successfully. It is recommended to restart UniGetUI to finish the installation": "{0} यशस्वीरित्या स्थापित झाले आहे. स्थापना पूर्ण करण्यासाठी UniGetUI पुन्हा सुरू करण्याची शिफारस केली जाते", + "Restart later": "नंतर पुन्हा सुरू करा", + "An error occurred:": "एक त्रुटी आली:", + "Please see the Command-line Output or refer to the Operation History for further information about the issue.": "या समस्येबद्दल अधिक माहितीसाठी कृपया Command-line Output पाहा किंवा Operation History तपासा.", + "Retry as administrator": "प्रशासक म्हणून पुन्हा प्रयत्न करा", + "Retry interactively": "संवादी पद्धतीने पुन्हा प्रयत्न करा", + "Retry skipping integrity checks": "अखंडता तपासण्या वगळून पुन्हा प्रयत्न करा", + "Installation options": "स्थापना पर्याय", + "Save": "जतन करा", + "UniGetUI collects anonymous usage data with the sole purpose of understanding and improving the user experience.": "UniGetUI केवळ वापरकर्ता अनुभव समजून घेण्यासाठी आणि सुधारण्यासाठी अनामिक वापर डेटा संकलित करते.", + "More details about the shared data and how it will be processed": "सामायिक केलेल्या डेटाबद्दल आणि त्यावर कशी प्रक्रिया केली जाईल याबद्दल अधिक तपशील", + "Do you accept that UniGetUI collects and sends anonymous usage statistics, with the sole purpose of understanding and improving the user experience?": "UniGetUI वापरकर्ता अनुभव समजून घेण्यासाठी आणि सुधारण्यासाठी अनामिक वापर आकडेवारी संकलित करून पाठवते, हे तुम्ही स्वीकारता का?", + "Decline": "नकार द्या", + "No personal information is collected nor sent, and the collected data is anonimized, so it can't be back-tracked to you.": "कोणतीही वैयक्तिक माहिती संकलित किंवा पाठवली जात नाही, आणि संकलित डेटा अनामिक केला जातो, त्यामुळे तो तुमच्यापर्यंत मागोवा घेता येत नाही.", + "Navigation panel": "नेव्हिगेशन पॅनल", + "Operations": "क्रिया", + "Toggle operations panel": "क्रिया पॅनेल टॉगल करा", + "Bulk operations": "मोठ्या प्रमाणातील क्रिया", + "Retry failed": "अयशस्वी क्रिया पुन्हा करा", + "Clear successful": "यशस्वी क्रिया साफ करा", + "Clear finished": "पूर्ण झालेल्या क्रिया साफ करा", + "Cancel all": "सर्व रद्द करा", + "More": "अधिक", + "Toggle navigation panel": "नेव्हिगेशन पॅनल टॉगल करा", + "Minimize": "लहान करा", + "Maximize": "मोठे करा", + "UniGetUI by Devolutions": "Devolutions कडून UniGetUI", + "UniGetUI is an application that makes managing your software easier, by providing an all-in-one graphical interface for your command-line package managers.": "UniGetUI हे एक अनुप्रयोग आहे जे तुमचे सॉफ्टवेअर व्यवस्थापित करणे सोपे करते, कारण ते तुमच्या कमांड-लाइन पॅकेज व्यवस्थापकांसाठी सर्व-समावेशक ग्राफिकल इंटरफेस प्रदान करते.", + "Useful links": "उपयुक्त दुवे", + "UniGetUI Homepage": "UniGetUI मुख्यपृष्ठ", + "Report an issue or submit a feature request": "समस्या नोंदवा किंवा वैशिष्ट्य विनंती सादर करा", + "UniGetUI Repository": "UniGetUI रिपॉझिटरी", + "View GitHub Profile": "GitHub प्रोफाइल पहा", + "UniGetUI License": "UniGetUI परवाना", + "Using UniGetUI implies the acceptation of the MIT License": "UniGetUI वापरणे म्हणजे MIT परवान्याचा स्वीकार होय", + "Become a translator": "अनुवादक बना", + "Go back": "मागे जा", + "Go forward": "पुढे जा", + "Go to home page": "मुखपृष्ठावर जा", + "Reload page": "पृष्ठ पुन्हा लोड करा", + "View page on browser": "ब्राउझरमध्ये पृष्ठ पहा", + "The built-in browser is not supported on Linux yet.": "अंगभूत ब्राउझरला अजून Linux वर समर्थन नाही.", + "Open in browser": "ब्राउझरमध्ये उघडा", + "Copy to clipboard": "क्लिपबोर्डवर कॉपी करा", + "Export to a file": "फाइलमध्ये निर्यात करा", + "Log level:": "लॉग स्तर:", + "Reload log": "लॉग पुन्हा लोड करा", + "Export log": "लॉग निर्यात करा", + "Text": "मजकूर", + "Change how operations request administrator rights": "कार्यवाही प्रशासक अधिकारांची विनंती कशी करते ते बदला", + "Restrictions on package operations": "पॅकेज कार्यवाह्यांवरील निर्बंध", + "Restrictions on package managers": "पॅकेज व्यवस्थापकांवरील निर्बंध", + "Restrictions when importing package bundles": "पॅकेज बंडल आयात करताना निर्बंध", + "Ask for administrator privileges once for each batch of operations": "प्रत्येक कार्यवाही गटासाठी एकदाच प्रशासक अधिकारांची विनंती करा", + "Ask only once for administrator privileges": "प्रशासक अधिकारांसाठी फक्त एकदाच विचारा", + "Prohibit any kind of Elevation via UniGetUI Elevator or GSudo": "UniGetUI Elevator किंवा GSudo द्वारे कोणत्याही प्रकारची उन्नती प्रतिबंधित करा", + "This option WILL cause issues. Any operation incapable of elevating itself WILL FAIL. Install/update/uninstall as administrator will NOT WORK.": "हा पर्याय नक्कीच अडचणी निर्माण करेल. स्वतःला उन्नत करू न शकणारी कोणतीही कार्यवाही अपयशी ठरेल. प्रशासक म्हणून स्थापित/अद्यतनित/विस्थापित करणे कार्य करणार नाही.", + "Allow custom command-line arguments": "सानुकूल कमांड-लाइन आर्ग्युमेंट्सना परवानगी द्या", + "Custom command-line arguments can change the way in which programs are installed, upgraded or uninstalled, in a way UniGetUI cannot control. Using custom command-lines can break packages. Proceed with caution.": "सानुकूल कमांड-लाइन आर्ग्युमेंट्समुळे प्रोग्राम स्थापित, अद्ययावत किंवा विस्थापित करण्याची पद्धत UniGetUI च्या नियंत्रणाबाहेर बदलू शकते. सानुकूल कमांड-लाइन वापरल्याने पॅकेजेस बिघडू शकतात. काळजीपूर्वक पुढे जा.", + "Ignore custom pre-install and post-install commands when importing packages from a bundle": "बंडलमधून पॅकेजेस आयात करताना सानुकूल pre-install आणि post-install आदेश दुर्लक्षित करा", + "Pre and post install commands will be run before and after a package gets installed, upgraded or uninstalled. Be aware that they may break things unless used carefully": "pre-install आणि post-install आदेश पॅकेज स्थापित, अद्ययावत किंवा विस्थापित होण्यापूर्वी आणि नंतर चालवले जातील. ते काळजीपूर्वक वापरले नाहीत तर गोष्टी बिघडू शकतात याची जाणीव ठेवा", + "Allow changing the paths for package manager executables": "पॅकेज व्यवस्थापक executable च्या पथांमध्ये बदल करण्यास परवानगी द्या", + "Turning this on enables changing the executable file used to interact with package managers. While this allows finer-grained customization of your install processes, it may also be dangerous": "हे चालू केल्यावर पॅकेज व्यवस्थापकांशी संवाद साधण्यासाठी वापरली जाणारी executable फाइल बदलता येते. यामुळे तुमच्या स्थापिती प्रक्रियांचे अधिक सूक्ष्म सानुकूलन शक्य होते, पण ते धोकादायकही ठरू शकते", + "Allow importing custom command-line arguments when importing packages from a bundle": "बंडलमधून पॅकेजेस आयात करताना सानुकूल कमांड-लाइन आर्ग्युमेंट्स आयात करण्यास परवानगी द्या", + "Malformed command-line arguments can break packages, or even allow a malicious actor to gain privileged execution. Therefore, importing custom command-line arguments is disabled by default": "चुकीच्या स्वरूपातील कमांड-लाइन आर्ग्युमेंट्स पॅकेजेस बिघडवू शकतात, किंवा एखाद्या दुष्ट घटकाला विशेषाधिकारित कार्यवाही मिळवून देऊ शकतात. त्यामुळे, सानुकूल कमांड-लाइन आर्ग्युमेंट्सची आयात डीफॉल्टनुसार अक्षम आहे", + "Allow importing custom pre-install and post-install commands when importing packages from a bundle": "बंडलमधून पॅकेजेस आयात करताना सानुकूल pre-install आणि post-install आदेश आयात करण्यास परवानगी द्या", + "Pre and post install commands can do very nasty things to your device, if designed to do so. It can be very dangerous to import the commands from a bundle, unless you trust the source of that package bundle": "pre-install आणि post-install आदेश तसे रचलेले असल्यास तुमच्या डिव्हाइसवर अत्यंत घातक गोष्टी करू शकतात. त्या पॅकेज बंडलच्या स्रोतावर तुमचा विश्वास नसल्यास, त्यातील आदेश आयात करणे फार धोकादायक ठरू शकते", + "Administrator rights and other dangerous settings": "प्रशासक अधिकार आणि इतर धोकादायक सेटिंग्ज", + "Package backup": "पॅकेज बॅकअप", + "Cloud package backup": "क्लाउड पॅकेज बॅकअप", + "Local package backup": "स्थानिक पॅकेज बॅकअप", + "Local backup advanced options": "स्थानिक बॅकअप प्रगत पर्याय", + "Log in with GitHub": "GitHub सह लॉग इन करा", + "Log out from GitHub": "GitHub मधून लॉग आउट करा", + "Periodically perform a cloud backup of the installed packages": "स्थापित पॅकेजेसचा क्लाउड बॅकअप नियमितपणे घ्या", + "Cloud backup uses a private GitHub Gist to store a list of installed packages": "क्लाउड बॅकअप स्थापित पॅकेजेसची यादी साठवण्यासाठी खाजगी GitHub Gist वापरतो", + "Perform a cloud backup now": "आता क्लाउड बॅकअप घ्या", + "Backup": "बॅकअप", + "Restore a backup from the cloud": "क्लाउडमधून बॅकअप पुनर्संचयित करा", + "Begin the process to select a cloud backup and review which packages to restore": "क्लाउड बॅकअप निवडण्याची आणि कोणती पॅकेजेस पुनर्संचयित करायची ते पाहण्याची प्रक्रिया सुरू करा", + "Periodically perform a local backup of the installed packages": "स्थापित पॅकेजेसचा स्थानिक बॅकअप नियमितपणे घ्या", + "Perform a local backup now": "आता स्थानिक बॅकअप घ्या", + "Change backup output directory": "बॅकअप आउटपुट निर्देशिका बदला", + "Set a custom backup file name": "सानुकूल बॅकअप फाइल नाव सेट करा", + "Leave empty for default": "डीफॉल्टसाठी रिकामे ठेवा", + "Add a timestamp to the backup file names": "बॅकअप फाइल नावांमध्ये टाइमस्टॅम्प जोडा", + "Backup and Restore": "बॅकअप आणि पुनर्संचयित करा", + "Enable background api (UniGetUI Widgets and Sharing, port 7058)": "पार्श्वभूमी API सक्षम करा (UniGetUI Widgets and Sharing, port 7058)", + "Wait for the device to be connected to the internet before attempting to do tasks that require internet connectivity.": "इंटरनेट कनेक्टिव्हिटी आवश्यक असलेल्या कार्यांचा प्रयत्न करण्यापूर्वी डिव्हाइस इंटरनेटशी जोडले जाईपर्यंत प्रतीक्षा करा.", + "Disable the 1-minute timeout for package-related operations": "पॅकेज-संबंधित कार्यवाह्यांसाठी 1-मिनिटाचा टाइमआउट अक्षम करा", + "Use installed GSudo instead of UniGetUI Elevator": "UniGetUI Elevator ऐवजी स्थापित GSudo वापरा", + "Use a custom icon and screenshot database URL": "सानुकूल आयकॉन आणि स्क्रीनशॉट डेटाबेस URL वापरा", + "Enable background CPU Usage optimizations (see Pull Request #3278)": "पार्श्वभूमीतील CPU वापर अनुकूलन सक्षम करा (Pull Request #3278 पहा)", + "Perform integrity checks at startup": "सुरूवातीला अखंडता तपासण्या करा", + "When batch installing packages from a bundle, install also packages that are already installed": "बंडलमधून पॅकेजेस बॅचने स्थापित करताना, आधीपासून स्थापित असलेली पॅकेजेसही स्थापित करा", + "Experimental settings and developer options": "प्रायोगिक सेटिंग्ज आणि विकसक पर्याय", + "Show UniGetUI's version and build number on the titlebar.": "शीर्षकपट्टीवर UniGetUI ची आवृत्ती आणि बिल्ड क्रमांक दाखवा.", + "Language": "भाषा", + "UniGetUI updater": "UniGetUI अपडेटर", + "Telemetry": "टेलिमेट्री", + "Manage UniGetUI settings": "UniGetUI सेटिंग्ज व्यवस्थापित करा", + "Related settings": "संबंधित सेटिंग्ज", + "Update UniGetUI automatically": "UniGetUI आपोआप अद्ययावत करा", + "Check for updates": "अद्ययावतांची तपासणी करा", + "Install prerelease versions of UniGetUI": "UniGetUI च्या पूर्व-प्रकाशन आवृत्त्या स्थापित करा", + "Manage telemetry settings": "टेलिमेट्री सेटिंग्ज व्यवस्थापित करा", + "Manage": "व्यवस्थापित करा", + "Import settings from a local file": "स्थानिक फाइलमधून सेटिंग्ज आयात करा", + "Import": "आयात करा", + "Export settings to a local file": "सेटिंग्ज स्थानिक फाइलमध्ये निर्यात करा", + "Export": "निर्यात करा", + "Reset UniGetUI": "UniGetUI रीसेट करा", + "User interface preferences": "वापरकर्ता आंतरफलक प्राधान्ये", + "Application theme, startup page, package icons, clear successful installs automatically": "अनुप्रयोग थीम, प्रारंभ पृष्ठ, पॅकेज चिन्हे, यशस्वी स्थापना आपोआप साफ करा", + "General preferences": "सामान्य प्राधान्ये", + "UniGetUI display language:": "UniGetUI प्रदर्शन भाषा:", + "System language": "सिस्टम भाषा", + "Is your language missing or incomplete?": "तुमची भाषा उपलब्ध नाही किंवा अपूर्ण आहे का?", + "Appearance": "स्वरूप", + "UniGetUI on the background and system tray": "पार्श्वभूमीत आणि सिस्टम ट्रेमध्ये UniGetUI", + "Package lists": "पॅकेज सूची", + "Use classic mode": "क्लासिक मोड वापरा", + "Restart UniGetUI to apply this change": "हा बदल लागू करण्यासाठी UniGetUI रीस्टार्ट करा", + "The classic UI is disabled for beta testers": "बीटा परीक्षकांसाठी क्लासिक UI अक्षम केले आहे", + "Close UniGetUI to the system tray": "UniGetUI बंद केल्यावर सिस्टम ट्रेमध्ये पाठवा", + "Manage UniGetUI autostart behaviour": "UniGetUI स्वयंप्रारंभ वर्तन व्यवस्थापित करा", + "Show package icons on package lists": "पॅकेज सूचीत पॅकेज चिन्हे दाखवा", + "Clear cache": "कॅशे साफ करा", + "Select upgradable packages by default": "डिफॉल्टने अद्ययावत करता येणारी पॅकेजेस निवडा", + "Light": "उजळ", + "Dark": "गडद", + "Follow system color scheme": "सिस्टमची रंगसंगती अनुसरा", + "Application theme:": "अनुप्रयोग थीम:", + "UniGetUI startup page:": "UniGetUI प्रारंभ पृष्ठ:", + "Proxy settings": "प्रॉक्सी सेटिंग्ज", + "Other settings": "इतर सेटिंग्ज", + "Connect the internet using a custom proxy": "सानुकूल प्रॉक्सी वापरून इंटरनेटशी कनेक्ट करा", + "Please note that not all package managers may fully support this feature": "कृपया लक्षात घ्या की सर्व पॅकेज व्यवस्थापक हे वैशिष्ट्य पूर्णपणे समर्थित करतीलच असे नाही", + "Proxy URL": "प्रॉक्सी URL", + "Enter proxy URL here": "येथे प्रॉक्सी URL प्रविष्ट करा", + "Authenticate to the proxy with a user and a password": "प्रॉक्सीवर वापरकर्तानाव आणि संकेतशब्दासह प्रमाणीकरण करा", + "Internet and proxy settings": "इंटरनेट आणि प्रॉक्सी सेटिंग्ज", + "Package manager preferences": "पॅकेज व्यवस्थापक प्राधान्ये", + "Ready": "तयार", + "Not found": "आढळले नाही", + "Notification preferences": "सूचनांची प्राधान्ये", + "Notification types": "सूचनांचे प्रकार", + "The system tray icon must be enabled in order for notifications to work": "सूचना कार्य करण्यासाठी सिस्टम ट्रे चिन्ह सक्षम असणे आवश्यक आहे", + "Enable UniGetUI notifications": "UniGetUI सूचना सक्षम करा", + "Show a notification when there are available updates": "उपलब्ध अद्यतने असतील तेव्हा सूचना दाखवा", + "Show a silent notification when an operation is running": "एखादी क्रिया चालू असताना मूक सूचना दाखवा", + "Show a notification when an operation fails": "एखादी क्रिया अयशस्वी झाल्यास सूचना दाखवा", + "Show a notification when an operation finishes successfully": "एखादी क्रिया यशस्वीरित्या पूर्ण झाल्यास सूचना दाखवा", + "Concurrency and execution": "समांतरता आणि अंमलबजावणी", + "Automatic desktop shortcut remover": "स्वयंचलित डेस्कटॉप शॉर्टकट काढणारे साधन", + "Choose how many operations should be performed in parallel": "किती क्रिया समांतरपणे करायच्या ते निवडा", + "Clear successful operations from the operation list after a 5 second delay": "5 सेकंद विलंबानंतर क्रिया सूचीमधून यशस्वी क्रिया साफ करा", + "Download operations are not affected by this setting": "डाउनलोड क्रियांवर या सेटिंगचा परिणाम होत नाही", + "You may lose unsaved data": "न जतन केलेला डेटा गमावला जाऊ शकतो", + "Ask to delete desktop shortcuts created during an install or upgrade.": "स्थापना किंवा अद्ययावत दरम्यान तयार झालेले डेस्कटॉप शॉर्टकट हटवायचे का ते विचारा.", + "Package update preferences": "पॅकेज अद्यतन प्राधान्ये", + "Update check frequency, automatically install updates, etc.": "अद्यतन तपासणीची वारंवारता, अद्यतने आपोआप स्थापित करणे इत्यादी.", + "Reduce UAC prompts, elevate installations by default, unlock certain dangerous features, etc.": "UAC संकेत कमी करा, स्थापनेस डिफॉल्टने उच्चाधिकार द्या, काही धोकादायक वैशिष्ट्ये अनलॉक करा इत्यादी.", + "Package operation preferences": "पॅकेज क्रिया प्राधान्ये", + "Enable {pm}": "{pm} सक्षम करा", + "Not finding the file you are looking for? Make sure it has been added to path.": "तुम्ही शोधत असलेली फाइल सापडत नाहीये का? ती path मध्ये जोडली आहे याची खात्री करा.", + "Select the executable to be used. The following list shows the executables found by UniGetUI": "वापरायची executable file निवडा. खालील सूचीमध्ये UniGetUI ला सापडलेल्या executable files दाखवल्या आहेत", + "For security reasons, changing the executable file is disabled by default": "सुरक्षिततेच्या कारणास्तव, executable file बदलणे डिफॉल्टने अक्षम आहे", + "Change this": "हे बदला", + "Copy path": "मार्ग कॉपी करा", + "Current executable file:": "सध्याची executable file:", + "Ignore packages from {pm} when showing a notification about updates": "अद्यतनांविषयी सूचना दाखवताना {pm} मधील पॅकेजेस दुर्लक्षित करा", + "Update security": "अद्यतन सुरक्षा", + "Use global setting": "जागतिक सेटिंग वापरा", + "Minimum age for updates": "अद्यतनांसाठी किमान वय", + "e.g. 10": "उदा. 10", + "Custom minimum age (days)": "सानुकूल किमान वय (दिवस)", + "{pm} does not provide release dates for its packages, so this setting will have no effect": "{pm} त्याच्या पॅकेजेससाठी प्रकाशन दिनांक देत नाही, त्यामुळे या सेटिंगचा काही परिणाम होणार नाही", + "{pm} only provides release dates for some of its packages, so this setting will only apply to those packages": "{pm} फक्त त्याच्या काही पॅकेजेसाठीच प्रकाशन तारखा प्रदान करतो, त्यामुळे ही सेटिंग केवळ त्या पॅकेजेसवरच लागू होईल", + "Override the global minimum update age for this package manager": "या पॅकेज व्यवस्थापकासाठी जागतिक किमान अद्यतन-वय सेटिंग ओव्हरराइड करा", + "View {0} logs": "{0} लॉग पहा", + "If Python cannot be found or is not listing packages but is installed on the system, ": "जर Python सापडत नसेल किंवा तो पॅकेजेस दाखवत नसेल पण सिस्टमवर स्थापित असेल, ", + "Advanced options": "प्रगत पर्याय", + "WinGet command-line tool": "WinGet कमांड-लाइन साधन", + "Choose which command-line tool UniGetUI uses for WinGet operations when the COM API is not used": "COM API वापरली जात नसताना WinGet क्रियांसाठी UniGetUI कोणते कमांड-लाइन साधन वापरेल ते निवडा", + "WinGet COM API": "WinGet COM API", + "Choose whether UniGetUI can use the WinGet COM API before falling back to the command-line tool": "कमांड-लाइन साधनाकडे परत जाण्यापूर्वी UniGetUI WinGet COM API वापरू शकते का ते निवडा", + "Reset WinGet": "WinGet रीसेट करा", + "This may help if no packages are listed": "जर कोणतीही पॅकेजेस सूचीबद्ध दिसत नसतील तर यामुळे मदत होऊ शकते", + "Force install location parameter when updating packages with custom locations": "सानुकूल स्थानांसह पॅकेजेस अद्ययावत करताना install location parameter सक्तीने वापरा", + "Install Scoop": "Scoop स्थापित करा", + "Uninstall Scoop (and its packages)": "Scoop (आणि त्याची पॅकेजेस) विस्थापित करा", + "Run cleanup and clear cache": "साफसफाई चालवा आणि कॅशे साफ करा", + "Run": "चालवा", + "Enable Scoop cleanup on launch": "सुरुवातीला Scoop cleanup सक्षम करा", + "Default vcpkg triplet": "डीफॉल्ट vcpkg triplet", + "Change vcpkg root location": "vcpkg चे root स्थान बदला", + "Reset vcpkg root location": "vcpkg मूळ स्थान रीसेट करा", + "Open vcpkg root location": "vcpkg मूळ स्थान उघडा", + "Language, theme and other miscellaneous preferences": "भाषा, थीम आणि इतर विविध प्राधान्ये", + "Show notifications on different events": "विविध घटनांवर सूचना दाखवा", + "Change how UniGetUI checks and installs available updates for your packages": "UniGetUI तुमच्या पॅकेजसाठी उपलब्ध अद्यतने कशी तपासते आणि स्थापित करते ते बदला", + "Automatically save a list of all your installed packages to easily restore them.": "तुमची सर्व स्थापित पॅकेजेसची यादी आपोआप जतन करा, म्हणजे ती सहज पुनर्संचयित करता येतील.", + "Enable and disable package managers, change default install options, etc.": "पॅकेज व्यवस्थापक सक्षम किंवा अक्षम करा, डीफॉल्ट स्थापिती पर्याय बदला, इ.", + "Internet connection settings": "इंटरनेट कनेक्शन सेटिंग्ज", + "Proxy settings, etc.": "प्रॉक्सी सेटिंग्ज, इ.", + "Beta features and other options that shouldn't be touched": "बीटा वैशिष्ट्ये आणि इतर पर्याय ज्यांना हात लावू नये", + "Reload sources": "स्रोत पुन्हा लोड करा", + "Delete source": "स्रोत हटवा", + "Known sources": "ज्ञात स्रोत", + "Update checking": "अद्यतन तपासणी", + "Automatic updates": "स्वयंचलित अद्यतने", + "Check for package updates periodically": "पॅकेज अद्यतने नियमितपणे तपासा", + "Check for updates every:": "अद्यतने तपासण्याची वारंवारिता:", + "Install available updates automatically": "उपलब्ध अद्यतने आपोआप स्थापित करा", + "Do not automatically install updates when the network connection is metered": "नेटवर्क कनेक्शन मीटर केलेले असल्यास अद्यतने आपोआप स्थापित करू नका", + "Do not automatically install updates when the device runs on battery": "उपकरण बॅटरीवर चालत असल्यास अद्यतने आपोआप स्थापित करू नका", + "Do not automatically install updates when the battery saver is on": "बॅटरी सेवर चालू असल्यास अद्यतने आपोआप स्थापित करू नका", + "Only show updates that are at least the specified number of days old": "फक्त किमान निर्दिष्ट दिवसांइतकी जुनी अद्यतनेच दाखवा", + "Warn me when the installer URL host changes between the installed version and the new version (WinGet only)": "स्थापित आवृत्ती आणि नवीन आवृत्ती दरम्यान इंस्टॉलर URL होस्ट बदलल्यास मला चेतावणी द्या (फक्त WinGet)", + "Change how UniGetUI handles install, update and uninstall operations.": "UniGetUI स्थापिती, अद्यतन आणि विस्थापना क्रिया कशा हाताळते ते बदला.", + "Navigation": "नेव्हिगेशन", + "Check for UniGetUI updates": "UniGetUI अद्यतनांसाठी तपासा", + "Quit UniGetUI": "UniGetUI बंद करा", + "Filters": "फिल्टर्स", + "Sources": "स्रोत", + "Search for packages to start": "सुरुवात करण्यासाठी पॅकेजेस शोधा", + "Select all": "सर्व निवडा", + "Clear selection": "निवड साफ करा", + "Instant search": "त्वरित शोध", + "Distinguish between uppercase and lowercase": "मोठी आणि लहान अक्षरे वेगळी ओळखा", + "Ignore special characters": "विशेष अक्षरांकडे दुर्लक्ष करा", + "Search mode": "शोध मोड", + "Both": "दोन्ही", + "Exact match": "अचूक जुळणारे", + "Show similar packages": "समान पॅकेजेस दाखवा", + "Loading": "लोड करत आहे", + "Package": "पॅकेज", + "More options": "अधिक पर्याय", + "Order by:": "क्रम लावा:", + "Name": "नाव", + "Id": "आयडी", + "Ascendant": "चढत्या क्रमाने", + "Descendant": "उतरत्या क्रमाने", + "View modes": "दृश्य मोड", + "Reload": "पुन्हा लोड करा", + "Closed": "बंद", + "Ascending": "चढता", + "Descending": "उतरता", + "{0}: {1}, {2}": "{0}: {1}, {2}", + "Order by": "क्रमवारी", + "No results were found matching the input criteria": "दिलेल्या निकषांशी जुळणारे कोणतेही निकाल आढळले नाहीत", + "No packages were found": "कोणतीही पॅकेजेस आढळली नाहीत", + "Loading packages": "पॅकेजेस लोड होत आहेत", + "Skip integrity checks": "इंटिग्रिटी तपासण्या वगळा", + "Download selected installers": "निवडलेले इंस्टॉलर डाउनलोड करा", + "Install selection": "निवडलेले स्थापित करा", + "Install options": "स्थापिती पर्याय", + "Add selection to bundle": "निवड बंडलमध्ये जोडा", + "Download installer": "इंस्टॉलर डाउनलोड करा", + "Uninstall selection": "निवडलेले विस्थापित करा", + "Uninstall options": "विस्थापना पर्याय", + "Ignore selected packages": "निवडलेल्या पॅकेजेसकडे दुर्लक्ष करा", + "Open install location": "स्थापितीचे स्थान उघडा", + "Reinstall package": "पॅकेज पुन्हा स्थापित करा", + "Uninstall package, then reinstall it": "पॅकेज विस्थापित करा, नंतर ते पुन्हा स्थापित करा", + "Ignore updates for this package": "या पॅकेजसाठीची अद्यतने दुर्लक्षित करा", + "WinGet malfunction detected": "WinGet मध्ये बिघाड आढळला", + "It looks like WinGet is not working properly. Do you want to attempt to repair WinGet?": "WinGet नीट काम करत नाही असे दिसते. तुम्हाला WinGet दुरुस्त करण्याचा प्रयत्न करायचा आहे का?", + "Repair WinGet": "WinGet दुरुस्त करा", + "Updates will no longer be ignored for {0}": "{0} साठी अद्यतने यापुढे दुर्लक्षित केली जाणार नाहीत", + "Updates are now ignored for {0}": "{0} साठी अद्यतने आता दुर्लक्षित केली आहेत", + "Do not ignore updates for this package anymore": "या पॅकेजसाठीची अद्यतने आता दुर्लक्षित करू नका", + "Add packages or open an existing package bundle": "पॅकेजेस जोडा किंवा विद्यमान पॅकेज बंडल उघडा", + "Add packages to start": "सुरुवात करण्यासाठी पॅकेजेस जोडा", + "The current bundle has no packages. Add some packages to get started": "सध्याच्या बंडलमध्ये कोणतीही पॅकेजेस नाहीत. सुरुवात करण्यासाठी काही पॅकेजेस जोडा", + "New": "नवीन", + "Save as": "या नावाने जतन करा", + "Create .ps1 script": ".ps1 स्क्रिप्ट तयार करा", + "Remove selection from bundle": "निवड बंडलमधून काढा", + "Skip hash checks": "हॅश तपासण्या वगळा", + "The package bundle is not valid": "पॅकेज बंडल वैध नाही", + "The bundle you are trying to load appears to be invalid. Please check the file and try again.": "तुम्ही लोड करण्याचा प्रयत्न करत असलेले बंडल अवैध दिसत आहे. कृपया फाइल तपासा आणि पुन्हा प्रयत्न करा.", + "Package bundle": "पॅकेज बंडल", + "Could not create bundle": "बंडल तयार करता आले नाही", + "The package bundle could not be created due to an error.": "त्रुटीमुळे पॅकेज बंडल तयार करता आले नाही.", + "Install script": "स्थापना स्क्रिप्ट", + "PowerShell script": "PowerShell स्क्रिप्ट", + "The installation script saved to {0}": "स्थापना स्क्रिप्ट {0} येथे जतन केली गेली", + "An error occurred": "एक त्रुटी आली", + "An error occurred while attempting to create an installation script:": "स्थापना स्क्रिप्ट तयार करण्याचा प्रयत्न करताना त्रुटी आली:", + "Hooray! No updates were found.": "छान! कोणतीही अद्यतने आढळली नाहीत.", + "Uninstall selected packages": "निवडलेली पॅकेजेस विस्थापित करा", + "Update selection": "निवडलेल्यांचे अद्यतन करा", + "Update options": "अद्यतन पर्याय", + "Uninstall package, then update it": "पॅकेज विस्थापित करा, नंतर त्याचे अद्यतन करा", + "Uninstall package": "पॅकेज विस्थापित करा", + "Skip this version": "ही आवृत्ती वगळा", + "Pause updates for": "अद्यतने इतक्या काळासाठी थांबवा", + "User | Local": "वापरकर्ता | स्थानिक", + "Machine | Global": "मशीन | जागतिक", + "The default package manager for Debian/Ubuntu-based Linux distributions.
Contains: Debian/Ubuntu packages": "Debian/Ubuntu-आधारित Linux वितरणांसाठी मूळ पॅकेज व्यवस्थापक.
समाविष्ट: Debian/Ubuntu पॅकेजेस", + "The Rust package manager.
Contains: Rust libraries and programs written in Rust": "Rust पॅकेज व्यवस्थापक.
यात समाविष्ट आहे: Rust लायब्ररी आणि Rust मध्ये लिहिलेले प्रोग्राम", + "The classical package manager for windows. You'll find everything there.
Contains: General Software": "Windows साठीचा पारंपरिक पॅकेज व्यवस्थापक. तुम्हाला इथे सर्व काही सापडेल.
यात समाविष्ट आहे: सामान्य सॉफ्टवेअर", + "The default package manager for RHEL/Fedora-based Linux distributions.
Contains: RPM packages": "RHEL/Fedora-आधारित Linux वितरणांसाठी मूळ पॅकेज व्यवस्थापक.
समाविष्ट: RPM पॅकेजेस", + "A repository full of tools and executables designed with Microsoft's .NET ecosystem in mind.
Contains: .NET related tools and scripts": "Microsoft च्या .NET परिसंस्थेला लक्षात घेऊन तयार केलेली साधने आणि executable फाइल्सने भरलेले repository.
यात समाविष्ट आहे: .NET संबंधित साधने आणि scripts", + "The universal Linux package manager for desktop applications.
Contains: Flatpak applications from configured remotes": "डेस्कटॉप अनुप्रयोगांसाठी सार्वत्रिक Linux पॅकेज व्यवस्थापक.
यात समाविष्ट: कॉन्फिगर केलेल्या रिमोट्समधील Flatpak अनुप्रयोग", + "NuPkg (zipped manifest)": "NuPkg (zip केलेला manifest)", + "The Missing Package Manager for macOS (or Linux).
Contains: Formulae, Casks": "macOS (किंवा Linux) साठीचा अपरिहार्य पॅकेज व्यवस्थापक.
यात समाविष्ट आहे: Formulae, Casks", + "Node JS's package manager. Full of libraries and other utilities that orbit the javascript world
Contains: Node javascript libraries and other related utilities": "Node JS चा पॅकेज व्यवस्थापक. JavaScript विश्वाभोवती असलेल्या लायब्ररी आणि इतर उपयुक्त साधनांनी भरलेला
यामध्ये: Node JavaScript लायब्ररी आणि इतर संबंधित उपयुक्त साधने", + "The default package manager for Arch Linux and its derivatives.
Contains: Arch Linux packages": "Arch Linux आणि त्याच्या व्युत्पन्नांसाठी मूळ पॅकेज व्यवस्थापक.
समाविष्ट: Arch Linux पॅकेजेस", + "Python's library manager. Full of python libraries and other python-related utilities
Contains: Python libraries and related utilities": "Python चा लायब्ररी व्यवस्थापक. Python लायब्ररी आणि इतर Python-संबंधित उपयुक्त साधनांनी भरलेला
यामध्ये: Python लायब्ररी आणि संबंधित उपयुक्त साधने", + "PowerShell's package manager. Find libraries and scripts to expand PowerShell capabilities
Contains: Modules, Scripts, Cmdlets": "PowerShell चा पॅकेज व्यवस्थापक. PowerShell ची क्षमता वाढवण्यासाठी लायब्ररी आणि स्क्रिप्ट्स शोधा
यामध्ये: मॉड्यूल्स, स्क्रिप्ट्स, Cmdlets", + "extracted": "एक्स्ट्रॅक्ट केलेले", + "Scoop package": "Scoop पॅकेज", + "Great repository of unknown but useful utilities and other interesting packages.
Contains: Utilities, Command-line programs, General Software (extras bucket required)": "अपरिचित पण उपयोगी युटिलिटीज आणि इतर रंजक पॅकेजेसचे उत्कृष्ट भांडार.
यामध्ये: युटिलिटीज, कमांड-लाइन प्रोग्राम्स, सर्वसाधारण सॉफ्टवेअर (extras bucket आवश्यक)", + "The universal Linux package manager by Canonical.
Contains: Snap packages from the Snapcraft store": "Canonical चा सार्वत्रिक Linux पॅकेज व्यवस्थापक.
समाविष्ट: Snapcraft स्टोअरमधील Snap पॅकेजेस", + "library": "लायब्ररी", + "feature": "वैशिष्ट्य", + "A popular C/C++ library manager. Full of C/C++ libraries and other C/C++-related utilities
Contains: C/C++ libraries and related utilities": "लोकप्रिय C/C++ लायब्ररी व्यवस्थापक. C/C++ लायब्ररी आणि इतर C/C++-संबंधित उपयुक्त साधनांनी भरलेला
यामध्ये: C/C++ लायब्ररी आणि संबंधित उपयुक्त साधने", + "option": "पर्याय", + "This package cannot be installed from an elevated context.": "हे पॅकेज उच्चाधिकारित संदर्भातून स्थापित करता येणार नाही.", + "Please run UniGetUI as a regular user and try again.": "कृपया UniGetUI सामान्य वापरकर्ता म्हणून चालवा आणि पुन्हा प्रयत्न करा.", + "Please check the installation options for this package and try again": "कृपया या पॅकेजसाठीच्या स्थापना पर्यायांची तपासणी करा आणि पुन्हा प्रयत्न करा", + "Microsoft's official package manager. Full of well-known and verified packages
Contains: General Software, Microsoft Store apps": "Microsoft चा अधिकृत पॅकेज व्यवस्थापक. परिचित आणि पडताळलेली पॅकेजेस यांनी भरलेला
यामध्ये: सर्वसाधारण सॉफ्टवेअर, Microsoft Store अॅप्स", + "Local PC": "स्थानिक PC", + "Android Subsystem": "Android उपप्रणाली", + "Operation on queue (position {0})...": "रांगेतील कार्यवाही (स्थान {0})...", + "Click here for more details": "अधिक तपशीलांसाठी येथे क्लिक करा", + "Operation canceled by user": "कार्यवाही वापरकर्त्याने रद्द केली", + "Running PreOperation ({0}/{1})...": "PreOperation चालू आहे ({0}/{1})...", + "PreOperation {0} out of {1} failed, and was tagged as necessary. Aborting...": "एकूण {1} पैकी PreOperation {0} अयशस्वी झाले आणि ते आवश्यक म्हणून चिन्हांकित होते. रद्द करत आहे...", + "PreOperation {0} out of {1} finished with result {2}": "एकूण {1} पैकी PreOperation {0} हे {2} निकालासह पूर्ण झाले", + "Starting operation...": "कार्यवाही सुरू करत आहे...", + "Running PostOperation ({0}/{1})...": "PostOperation चालू आहे ({0}/{1})...", + "PostOperation {0} out of {1} failed, and was tagged as necessary. Aborting...": "एकूण {1} पैकी PostOperation {0} अयशस्वी झाले आणि ते आवश्यक म्हणून चिन्हांकित होते. रद्द करत आहे...", + "PostOperation {0} out of {1} finished with result {2}": "एकूण {1} पैकी PostOperation {0} हे {2} निकालासह पूर्ण झाले", + "{package} installer download": "{package} इंस्टॉलर डाउनलोड", + "{0} installer is being downloaded": "{0} इंस्टॉलर डाउनलोड केला जात आहे", + "Download succeeded": "डाउनलोड यशस्वी झाले", + "{package} installer was downloaded successfully": "{package} इंस्टॉलर यशस्वीरित्या डाउनलोड झाला", + "Download failed": "डाउनलोड अयशस्वी झाले", + "{package} installer could not be downloaded": "{package} इंस्टॉलर डाउनलोड होऊ शकला नाही", + "{package} Installation": "{package} स्थापना", + "{0} is being installed": "{0} स्थापित केले जात आहे", + "Installation succeeded": "स्थापना यशस्वी झाली", + "{package} was installed successfully": "{package} यशस्वीरित्या स्थापित झाले", + "Installation failed": "स्थापना अयशस्वी झाली", + "{package} could not be installed": "{package} स्थापित होऊ शकले नाही", + "{package} Update": "{package} अद्यतन", + "Update succeeded": "अद्यतन यशस्वी झाले", + "{package} was updated successfully": "{package} यशस्वीरित्या अद्यतनित झाले", + "Update failed": "अद्यतन अयशस्वी झाले", + "{package} could not be updated": "{package} अद्यतनित होऊ शकले नाही", + "{package} Uninstall": "{package} अनइन्स्टॉल", + "{0} is being uninstalled": "{0} अनइन्स्टॉल केले जात आहे", + "Uninstall succeeded": "अनइन्स्टॉल यशस्वी झाले", + "{package} was uninstalled successfully": "{package} यशस्वीरित्या अनइन्स्टॉल झाले", + "Uninstall failed": "अनइन्स्टॉल अयशस्वी झाले", + "{package} could not be uninstalled": "{package} अनइन्स्टॉल होऊ शकले नाही", + "Adding source {source}": "स्रोत {source} जोडत आहे", + "Adding source {source} to {manager}": "{manager} मध्ये स्रोत {source} जोडत आहे", + "Source added successfully": "स्रोत यशस्वीरित्या जोडला गेला", + "The source {source} was added to {manager} successfully": "स्रोत {source} हा {manager} मध्ये यशस्वीरित्या जोडला गेला", + "Could not add source": "स्रोत जोडता आला नाही", + "Could not add source {source} to {manager}": "{manager} मध्ये स्रोत {source} जोडता आला नाही", + "Removing source {source}": "स्रोत {source} काढत आहे", + "Removing source {source} from {manager}": "{manager} मधून स्रोत {source} काढत आहे", + "Source removed successfully": "स्रोत यशस्वीरित्या काढला गेला", + "The source {source} was removed from {manager} successfully": "स्रोत {source} हा {manager} मधून यशस्वीरित्या काढला गेला", + "Could not remove source": "स्रोत काढता आला नाही", + "Could not remove source {source} from {manager}": "{manager} मधून स्रोत {source} काढता आला नाही", + "The package manager \"{0}\" was not found": "पॅकेज व्यवस्थापक \"{0}\" सापडला नाही", + "The package manager \"{0}\" is disabled": "पॅकेज व्यवस्थापक \"{0}\" अक्षम आहे", + "There is an error with the configuration of the package manager \"{0}\"": "पॅकेज व्यवस्थापक \"{0}\" च्या संरचनेत त्रुटी आहे", + "The package \"{0}\" was not found on the package manager \"{1}\"": "पॅकेज व्यवस्थापक \"{1}\" वर पॅकेज \"{0}\" सापडले नाही", + "{0} is disabled": "{0} अक्षम आहे", + "{0} weeks": "{0} आठवडे", + "1 month": "1 महिना", + "{0} months": "{0} महिने", + "Something went wrong": "काहीतरी चुकले", + "An interal error occurred. Please view the log for further details.": "आंतरिक त्रुटी आली. अधिक तपशीलांसाठी कृपया लॉग पहा.", + "No applicable installer was found for the package {0}": "पॅकेज {0} साठी लागू होणारा कोणताही इंस्टॉलर सापडला नाही", + "Integrity checks will not be performed during this operation": "या कार्यवाहीदरम्यान अखंडता तपासण्या केल्या जाणार नाहीत", + "This is not recommended.": "याची शिफारस केली जात नाही.", + "Run now": "आता चालवा", + "Run next": "पुढे चालवा", + "Run last": "शेवटी चालवा", + "Show in explorer": "Explorer मध्ये दाखवा", + "Checked": "चेक केलेले", + "Unchecked": "चेक न केलेले", + "This package is already installed": "हे पॅकेज आधीच स्थापित आहे", + "This package can be upgraded to version {0}": "हे पॅकेज आवृत्ती {0} पर्यंत अपग्रेड करता येते", + "Updates for this package are ignored": "या पॅकेजसाठीची अद्यतने दुर्लक्षित केली जात आहेत", + "This package is being processed": "या पॅकेजवर प्रक्रिया सुरू आहे", + "This package is not available": "हे पॅकेज उपलब्ध नाही", + "Select the source you want to add:": "जोडायचा स्रोत निवडा:", + "Source name:": "स्रोत नाव:", + "Source URL:": "स्रोत URL:", + "An error occurred when adding the source: ": "स्रोत जोडताना एक त्रुटी आली: ", + "Package management made easy": "पॅकेज व्यवस्थापन सोपे झाले", + "version {0}": "आवृत्ती {0}", + "[RAN AS ADMINISTRATOR]": "[प्रशासक म्हणून चालवले]", + "Portable mode": "पोर्टेबल मोड\n", + "DEBUG BUILD": "डीबग बिल्ड", + "Here you can change UniGetUI's behaviour regarding the following shortcuts. Checking a shortcut will make UniGetUI delete it if if gets created on a future upgrade. Unchecking it will keep the shortcut intact": "येथे तुम्ही खालील शॉर्टकट्सबाबत UniGetUI चे वर्तन बदलू शकता. एखादा शॉर्टकट निवडल्यास भविष्यातील अपग्रेडमध्ये तो तयार झाल्यास UniGetUI तो हटवेल. निवड काढल्यास तो शॉर्टकट जसाच्या तसा राहील", + "Manual scan": "हस्तचालित स्कॅन", + "Existing shortcuts on your desktop will be scanned, and you will need to pick which ones to keep and which ones to remove.": "तुमच्या डेस्कटॉपवरील विद्यमान शॉर्टकट्स स्कॅन केले जातील, आणि कोणते ठेवायचे व कोणते काढायचे हे तुम्हाला निवडावे लागेल.", + "Delete?": "हटवायचे?", + "I understand": "मला समजले", + "Chocolatey setup changed": "Chocolatey सेटअप बदलला", + "UniGetUI no longer includes its own private Chocolatey installation. A legacy UniGetUI-managed Chocolatey installation was detected for this user profile, but system Chocolatey was not found. Chocolatey will stay unavailable in UniGetUI until Chocolatey is installed on the system and UniGetUI is restarted. Applications previously installed through UniGetUI's bundled Chocolatey may still appear under other sources such as Local PC or WinGet.": "UniGetUI यापुढे स्वतःची खाजगी Chocolatey स्थापना समाविष्ट करत नाही. या वापरकर्ता प्रोफाइलसाठी UniGetUI-व्यवस्थापित जुनी Chocolatey स्थापना आढळली, परंतु सिस्टम Chocolatey सापडली नाही. सिस्टमवर Chocolatey स्थापित होईपर्यंत आणि UniGetUI पुन्हा सुरू होईपर्यंत Chocolatey UniGetUI मध्ये अनुपलब्ध राहील. UniGetUI च्या समाविष्ट Chocolatey द्वारे पूर्वी स्थापित केलेले अनुप्रयोग Local PC किंवा WinGet सारख्या इतर स्रोतांखाली अजूनही दिसू शकतात.", + "NOTE: This troubleshooter can be disabled from UniGetUI Settings, on the WinGet section": "टीप: हा समस्या निवारक UniGetUI Settings मधील WinGet विभागातून निष्क्रिय केला जाऊ शकतो", + "Restart": "पुन्हा सुरू करा", + "Are you sure you want to delete all shortcuts?": "तुम्हाला सर्व शॉर्टकट्स हटवायचे आहेत याची खात्री आहे का?", + "Any new shorcuts created during an install or an update operation will be deleted automatically, instead of showing a confirmation prompt the first time they are detected.": "इंस्टॉल किंवा अद्यतन प्रक्रियेदरम्यान तयार होणारे कोणतेही नवीन शॉर्टकट्स, पहिल्यांदा आढळल्यावर पुष्टीकरण विचारण्याऐवजी, आपोआप हटवले जातील.", + "Any shorcuts created or modified outside of UniGetUI will be ignored. You will be able to add them via the {0} button.": "UniGetUI च्या बाहेर तयार केलेले किंवा बदललेले कोणतेही शॉर्टकट्स दुर्लक्षित केले जातील. तुम्ही ते {0} बटणाद्वारे जोडू शकाल.", + "Are you really sure you want to enable this feature?": "तुम्हाला हे वैशिष्ट्य सक्षम करायचे आहे याची खरोखर खात्री आहे का?", + "No new shortcuts were found during the scan.": "स्कॅनदरम्यान कोणतेही नवीन शॉर्टकट्स आढळले नाहीत.", + "How to add packages to a bundle": "बंडलमध्ये पॅकेजेस कशी जोडायची", + "In order to add packages to a bundle, you will need to: ": "बंडलमध्ये पॅकेजेस जोडण्यासाठी, तुम्हाला पुढील गोष्टी कराव्या लागतील: ", + "1. Navigate to the \"{0}\" or \"{1}\" page.": "1. \"{0}\" किंवा \"{1}\" पृष्ठावर जा.", + "2. Locate the package(s) you want to add to the bundle, and select their leftmost checkbox.": "2. बंडलमध्ये जोडायची पॅकेजेस शोधा आणि त्यांच्यापैकी प्रत्येकाची डावीकडील चेकबॉक्स निवडा.", + "3. When the packages you want to add to the bundle are selected, find and click the option \"{0}\" on the toolbar.": "3. जोडायची पॅकेजेस निवडल्यानंतर, टूलबारमधील \"{0}\" हा पर्याय शोधून त्यावर क्लिक करा.", + "4. Your packages will have been added to the bundle. You can continue adding packages, or export the bundle.": "4. तुमची पॅकेजेस बंडलमध्ये जोडली जातील. तुम्ही आणखी पॅकेजेस जोडू शकता किंवा बंडल निर्यात करू शकता.", + "Which backup do you want to open?": "तुम्हाला कोणता बॅकअप उघडायचा आहे?", + "Select the backup you want to open. Later, you will be able to review which packages you want to install.": "तुम्हाला उघडायचा असलेला बॅकअप निवडा. नंतर, तुम्हाला कोणती पॅकेजेस स्थापित करायची आहेत हे तपासता येईल.", + "There are ongoing operations. Quitting UniGetUI may cause them to fail. Do you want to continue?": "काही प्रक्रिया सुरू आहेत. UniGetUI बंद केल्यास त्या अपयशी ठरू शकतात. तुम्हाला पुढे जायचे आहे का?", + "UniGetUI or some of its components are missing or corrupt.": "UniGetUI किंवा त्याचे काही घटक गहाळ आहेत किंवा खराब झाले आहेत.", + "It is strongly recommended to reinstall UniGetUI to adress the situation.": "ही परिस्थिती सोडवण्यासाठी UniGetUI पुन्हा स्थापित करण्याची जोरदार शिफारस केली जाते.", + "Refer to the UniGetUI Logs to get more details regarding the affected file(s)": "प्रभावित फाइल्सबद्दल अधिक तपशीलांसाठी UniGetUI Logs पाहा", + "Integrity checks can be disabled from the Experimental Settings": "Experimental Settings मधून अखंडता तपासणी निष्क्रिय करता येते", + "Repair UniGetUI": "UniGetUI दुरुस्त करा", + "Live output": "थेट आउटपुट", + "This package bundle had some settings that are potentially dangerous, and may be ignored by default.": "या पॅकेज बंडलमध्ये काही अशी सेटिंग्ज आहेत जी संभाव्यतः धोकादायक आहेत आणि डीफॉल्टनुसार दुर्लक्षित केल्या जाऊ शकतात.", + "Entries that show in YELLOW will be IGNORED.": "YELLOW मध्ये दिसणाऱ्या नोंदी IGNORED केल्या जातील.", + "Entries that show in RED will be IMPORTED.": "RED मध्ये दिसणाऱ्या नोंदी IMPORTED केल्या जातील.", + "You can change this behavior on UniGetUI security settings.": "तुम्ही हे वर्तन UniGetUI security settings मध्ये बदलू शकता.", + "Open UniGetUI security settings": "UniGetUI security settings उघडा", + "Should you modify the security settings, you will need to open the bundle again for the changes to take effect.": "तुम्ही security settings बदलल्यास, बदल लागू होण्यासाठी तुम्हाला बंडल पुन्हा उघडावे लागेल.", + "Details of the report:": "अहवालाचे तपशील:", + "Are you sure you want to create a new package bundle? ": "तुम्हाला नवीन पॅकेज बंडल तयार करायचे आहे याची खात्री आहे का? ", + "Any unsaved changes will be lost": "जतन न केलेले सर्व बदल गमावले जातील", + "Warning!": "इशारा!", + "For security reasons, custom command-line arguments are disabled by default. Go to UniGetUI security settings to change this. ": "सुरक्षेच्या कारणास्तव, सानुकूल command-line arguments डीफॉल्टनुसार निष्क्रिय असतात. हे बदलण्यासाठी UniGetUI security settings मध्ये जा. ", + "Change default options": "डीफॉल्ट पर्याय बदला", + "Ignore future updates for this package": "या पॅकेजसाठी भविष्यातील अद्यतने दुर्लक्षित करा", + "For security reasons, pre-operation and post-operation scripts are disabled by default. Go to UniGetUI security settings to change this. ": "सुरक्षेच्या कारणास्तव, pre-operation आणि post-operation scripts डीफॉल्टनुसार निष्क्रिय असतात. हे बदलण्यासाठी UniGetUI security settings मध्ये जा. ", + "You can define the commands that will be run before or after this package is installed, updated or uninstalled. They will be run on a command prompt, so CMD scripts will work here.": "हे पॅकेज स्थापित, अद्ययावत किंवा अनइंस्टॉल होण्यापूर्वी किंवा नंतर चालवायचे आदेश तुम्ही ठरवू शकता. ते command prompt वर चालतील, त्यामुळे CMD scripts येथे कार्य करतील.", + "Change this and unlock": "हे बदला आणि अनलॉक करा", + "{0} Install options are currently locked because {0} follows the default install options.": "{0} साठी Install options सध्या लॉक आहेत कारण {0} डीफॉल्ट install options अनुसरते.", + "Unset or unknown": "सेट केलेले नाही किंवा अज्ञात", + "This package has no screenshots or is missing the icon? Contrbute to UniGetUI by adding the missing icons and screenshots to our open, public database.": "या पॅकेजमध्ये screenshots नाहीत किंवा icon गहाळ आहे का? आमच्या खुल्या, सार्वजनिक डेटाबेसमध्ये गहाळ icons आणि screenshots जोडून UniGetUI ला योगदान द्या.", + "Become a contributor": "योगदानकर्ता बना", + "Update to {0} available": "{0} साठी अद्यतन उपलब्ध आहे", + "Reinstall": "पुन्हा स्थापित करा", + "Installer not available": "इंस्टॉलर उपलब्ध नाही", + "Version:": "आवृत्ती:", + "UniGetUI Version {0}": "UniGetUI आवृत्ती {0}", + "Performing backup, please wait...": "बॅकअप घेत आहे, कृपया प्रतीक्षा करा...", + "An error occurred while logging in: ": "लॉग इन करताना एक त्रुटी आली: ", + "Fetching available backups...": "उपलब्ध बॅकअप्स आणत आहे...", + "Done!": "पूर्ण झाले!", + "The cloud backup has been loaded successfully.": "क्लाउड बॅकअप यशस्वीरित्या लोड झाला आहे.", + "An error occurred while loading a backup: ": "बॅकअप लोड करताना एक त्रुटी आली: ", + "Backing up packages to GitHub Gist...": "पॅकेजेसचा बॅकअप GitHub Gist वर घेत आहे...", + "Backup Successful": "बॅकअप यशस्वी", + "The cloud backup completed successfully.": "क्लाउड बॅकअप यशस्वीरित्या पूर्ण झाला.", + "Could not back up packages to GitHub Gist: ": "पॅकेजेसचा GitHub Gist वर बॅकअप घेता आला नाही: ", + "It is not guaranteed that the provided credentials will be stored safely, so you may as well not use the credentials of your bank account": "दिलेली लॉगिन माहिती सुरक्षितपणे साठवली जाईल याची हमी नाही, त्यामुळे तुमच्या बँक खात्याची लॉगिन माहिती वापरू नका", + "Enable the automatic WinGet troubleshooter": "स्वयंचलित WinGet ट्रबलशूटर सक्षम करा", + "Add updates that fail with a 'no applicable update found' to the ignored updates list": "ज्या अद्यतनांवर 'no applicable update found' अशी त्रुटी येते ती दुर्लक्षित अद्यतनांच्या यादीत जोडा.", + "Invalid selection": "अवैध निवड", + "No package was selected": "कोणतेही पॅकेज निवडले गेले नाही", + "More than 1 package was selected": "1 पेक्षा जास्त पॅकेज निवडले गेले", + "List": "यादी", + "Grid": "ग्रिड", + "Icons": "आयकॉन्स", + "\"{0}\" is a local package and does not have available details": "\"{0}\" हे स्थानिक पॅकेज आहे आणि त्याचे तपशील उपलब्ध नाहीत", + "\"{0}\" is a local package and is not compatible with this feature": "\"{0}\" हे स्थानिक पॅकेज आहे आणि ते या वैशिष्ट्याशी सुसंगत नाही", + "Add packages to bundle": "पॅकेजेस बंडलमध्ये जोडा", + "Preparing packages, please wait...": "पॅकेजेस तयार करत आहे, कृपया थांबा...", + "Loading packages, please wait...": "पॅकेजेस लोड करत आहे, कृपया थांबा...", + "Saving packages, please wait...": "पॅकेजेस जतन करत आहे, कृपया थांबा...", + "The bundle was created successfully on {0}": "बंडल {0} येथे यशस्वीरित्या तयार झाले", + "User profile": "वापरकर्ता प्रोफाइल", + "Error": "त्रुटी", + "Log in failed: ": "लॉग इन अयशस्वी झाले: ", + "Log out failed: ": "लॉग आउट अयशस्वी झाले: ", + "Package backup settings": "पॅकेज बॅकअप सेटिंग्ज", + "Manage UniGetUI autostart behaviour from the Settings app": "UniGetUI च्या स्वयंप्रारंभ वर्तनाचे व्यवस्थापन करा", + "Choose how many operations shoulds be performed in parallel": "किती क्रिया समांतरपणे करायच्या ते निवडा", + "Something went wrong while launching the updater.": "Updater सुरू करताना काहीतरी चुकले.", + "Please try again later": "कृपया नंतर पुन्हा प्रयत्न करा", + "Show the release notes after UniGetUI is updated": "UniGetUI अद्यतनित झाल्यानंतर प्रकाशन नोंदी दर्शवा" +} diff --git a/src/Languages/lang_nb.json b/src/Languages/lang_nb.json new file mode 100644 index 0000000..0c045fc --- /dev/null +++ b/src/Languages/lang_nb.json @@ -0,0 +1,850 @@ +{ + "{0} of {1} operations completed": "{0} av {1} operasjoner fullført", + "{0} is now {1}": "{0} er nå {1}", + "Enabled": "Skrudd på", + "Disabled": "Skrudd av", + "Privacy": "Personvern", + "Hide my username from the logs": "Skjul brukernavnet mitt fra loggene", + "Replaces your username with **** in the logs. Restart UniGetUI to also hide it from already-recorded entries.": "Erstatter brukernavnet ditt med **** i loggene. Start UniGetUI på nytt for å også skjule det i allerede registrerte oppføringer.", + "Your last update attempt did not complete.": "Det forrige oppdateringsforsøket ditt ble ikke fullført.", + "UniGetUI could not confirm whether the update succeeded. Open the log to see what happened.": "UniGetUI kunne ikke bekrefte om oppdateringen lyktes. Åpne loggen for å se hva som skjedde.", + "View log": "Vis logg", + "The installer reported success but did not restart UniGetUI.": "Installasjonsprogrammet rapporterte at det lyktes, men startet ikke UniGetUI på nytt.", + "The installer failed to initialize.": "Installasjonsprogrammet kunne ikke initialiseres.", + "Setup was canceled before installation began.": "Oppsettet ble avbrutt før installasjonen startet.", + "A fatal error occurred during the preparation phase.": "Det oppstod en fatal feil under forberedelsesfasen.", + "A fatal error occurred during installation.": "Det oppstod en fatal feil under installasjonen.", + "Installation was canceled while in progress.": "Installasjonen ble avbrutt mens den pågikk.", + "The installer was terminated by another process.": "Installasjonsprogrammet ble avsluttet av en annen prosess.", + "The preparation phase determined the installation cannot proceed.": "Forberedelsesfasen fastslo at installasjonen ikke kan fortsette.", + "The installer could not start. UniGetUI may already be running, or you do not have permission to install.": "Installasjonsprogrammet kunne ikke starte. UniGetUI kjører kanskje allerede, eller du har ikke tillatelse til å installere.", + "Unexpected installer error.": "Uventet feil i installasjonsprogrammet.", + "We are checking for updates.": "Vi søker etter oppdateringer.", + "Please wait": "Vennligst vent", + "Great! You are on the latest version.": "Flott! Du har den nyeste versjonen.", + "There are no new UniGetUI versions to be installed": "Det er ingen nye UniGetUI-versjoner å installere", + "UniGetUI version {0} is being downloaded.": "UniGetUI versjon {0} lastes ned.", + "This may take a minute or two": "Dette kan ta noen få minutter", + "The installer authenticity could not be verified.": "Autentisiteten til installasjonsprogrammet kunne ikke bekreftes.", + "The update process has been aborted.": "Oppdateringsprosessen har blitt avbrutt.", + "Auto-update is not yet available on this platform.": "Automatisk oppdatering er ikke tilgjengelig på denne plattformen ennå.", + "Please update UniGetUI manually.": "Oppdater UniGetUI manuelt.", + "An error occurred when checking for updates: ": "En feil oppstod ved sjekking for oppdateringer", + "The updater could not be launched.": "Oppdateringsprogrammet kunne ikke startes.", + "The operating system did not start the installer process.": "Operativsystemet startet ikke installasjonsprogramprosessen.", + "UniGetUI is being updated...": "UniGetUI oppdateres...", + "Update installed.": "Oppdatering installert.", + "UniGetUI was updated successfully, but this running copy was not replaced. This usually means you are running a development build. Close this copy and start the newly-installed version to finish.": "UniGetUI ble oppdatert, men denne kjørende kopien ble ikke erstattet. Dette betyr vanligvis at du kjører en utviklingsversjon. Lukk denne kopien og start den nylig installerte versjonen for å fullføre.", + "The update could not be applied.": "Oppdateringen kunne ikke tas i bruk.", + "Installer exit code {0}: {1}": "Avslutningskode for installasjonsprogram {0}: {1}", + "Update cancelled.": "Oppdatering avbrutt.", + "Authentication was cancelled.": "Autentisering ble avbrutt.", + "Installer exit code {0}": "Avslutningskode for installasjonsprogram {0}", + "Operation in progress": "Handlinger som utføres", + "Please wait...": "Vennligst vent...", + "Success!": "Suksess!", + "Failed": "Mislyktes", + "An error occurred while processing this package": "En feil oppstod i behandlingen av denne pakken", + "Installer": "Installasjonsprogram", + "Executable": "Kjørbar fil", + "MSI": "MSI", + "Compressed file": "Komprimert fil", + "MSIX": "MSIX", + "WinGet was repaired successfully": "WinGet ble reparert vellykket", + "It is recommended to restart UniGetUI after WinGet has been repaired": "Det anbefales å starte UniGetUI på nytt etter at WinGet har blitt reparert", + "WinGet could not be repaired": "WinGet kunne ikke repareres", + "An unexpected issue occurred while attempting to repair WinGet. Please try again later": "En uventet feil oppstod mens vi forsøkte å reparere WinGet. Vennligst prøv igjen senere", + "Log in to enable cloud backup": "Logg inn for å aktivere skysikkerhetskopi", + "Backup Failed": "Sikkerhetskopiering mislyktes", + "Downloading backup...": "Laster ned sikkerhetskopi...", + "An update was found!": "En oppdatering ble funnet!", + "{0} can be updated to version {1}": "{0} kan oppdateres til versjon {1}", + "Updates found!": "Oppdateringer funnet!", + "{0} packages can be updated": "{0} pakker kan oppdateres", + "{0} is being updated to version {1}": "{0} oppdateres til versjon {1}", + "{0} packages are being updated": "{0} pakker oppdateres", + "You have currently version {0} installed": "Nå har du versjon {0} installert", + "Desktop shortcut created": "Skrivebordsnarvei opprettet", + "UniGetUI has detected a new desktop shortcut that can be deleted automatically.": "UniGetUI har oppdaget en ny skrivebordsnarvei som kan bli slettet automatisk", + "{0} desktop shortcuts created": "{0} skrivebordssnarveier opprettet", + "UniGetUI has detected {0} new desktop shortcuts that can be deleted automatically.": "UniGetUI har oppdaget {0} nye skrivebordsnarveier som kan bli slettet automatisk", + "Attention required": "Oppmerksomhet kreves", + "Restart required": "Omstart kreves", + "1 update is available": "1 oppdatering er tilgjengelig", + "{0} updates are available": "{0} oppdateringer er tilgjengelige", + "Everything is up to date": "Alt er oppdatert", + "Discover Packages": "Oppdag pakker", + "Available Updates": "Tilgjengelige oppdateringer", + "Installed Packages": "Installerte pakker", + "UniGetUI Version {0} by Devolutions": "UniGetUI versjon {0} av Devolutions", + "Show UniGetUI": "Vis UniGetUI", + "Quit": "Lukk", + "Are you sure?": "Er du sikker?", + "Do you really want to uninstall {0}?": "Vil du virkelig avinstallere {0}?", + "Do you really want to uninstall the following {0} packages?": "Vil du virkelig avinstallere følgende {0} pakker?", + "No": "Nei", + "Yes": "Ja", + "Partial": "Delvis", + "View on UniGetUI": "Vis i UniGetUI", + "Update": "Oppdater", + "Open UniGetUI": "Åpne UniGetUI", + "Update all": "Oppdater alle", + "Update now": "Oppdater nå", + "Installer host changed since the installed version.\n": "Verten for installasjonsprogrammet er endret siden den installerte versjonen.\n", + "This package is on the queue": "Denne pakken er i køen", + "installing": "installerer", + "updating": "oppdaterer", + "uninstalling": "avinstallerer", + "installed": "installert", + "Retry": "Prøv igjen", + "Install": "Installer", + "Uninstall": "Avinstaller", + "Open": "Åpne", + "Operation profile:": "Operasjonsprofil:", + "Follow the default options when installing, upgrading or uninstalling this package": "Følg standardalternativene når du installerer, oppgraderer eller avinstallerer denne pakken", + "The following settings will be applied each time this package is installed, updated or removed.": "Følgende innstillinger kommer til å bli brukt hver gang denne pakken installeres, oppdateres, eller fjernes.", + "Version to install:": "Versjon å installere:", + "Architecture to install:": "Arkitektur som installeres:", + "Installation scope:": "Installasjonsomfang:", + "Install location:": "Installasjonsplassering:", + "Select": "Velg", + "Reset": "Tilbakestill", + "Custom install arguments:": "Egendefinerte installasjonsparametre:", + "Custom update arguments:": "Egendefinerte oppdateringsparametre:", + "Custom uninstall arguments:": "Egendefinerte avinstallasjonsparametre:", + "Pre-install command:": "Pre-installasjonskommando:", + "Post-install command:": "Post-installasjonskommando:", + "Abort install if pre-install command fails": "Avbryt installasjonen hvis pre-installasjonskommandoen mislykkes", + "Pre-update command:": "Pre-oppdateringskommando:", + "Post-update command:": "Post-oppdateringskommando:", + "Abort update if pre-update command fails": "Avbryt oppdateringen hvis pre-oppdateringskommandoen mislykkes", + "Pre-uninstall command:": "Pre-avinstallasjonskommando:", + "Post-uninstall command:": "Post-avinstallasjonskommando:", + "Abort uninstall if pre-uninstall command fails": "Avbryt avinstallasjonen hvis pre-avinstallasjonskommandoen mislykkes", + "Command-line to run:": "Kommandolinje som skal kjøres:", + "Save and close": "Lagre og lukk", + "General": "Generelt", + "Architecture & Location": "Arkitektur og plassering", + "Command-line": "Kommandolinje", + "Close apps": "Lukk apper", + "Pre/Post install": "Før/etter installasjon", + "Select the processes that should be closed before this package is installed, updated or uninstalled.": "Velg prosessene som skal lukkes før denne pakken blir installert, oppdatert eller avinstallert.", + "Write here the process names here, separated by commas (,)": "Skriv prosessnavnene her, atskilt med kommaer (,)", + "Try to kill the processes that refuse to close when requested to": "Prøv å tvangsavslutte prosesser som nekter å lukkes når de blir bedt om det", + "Run as admin": "Kjør som administrator", + "Interactive installation": "Interaktiv installasjon", + "Skip hash check": "Hopp over sjekk av hash", + "Uninstall previous versions when updated": "Avinstaller forrige versjoner ved oppdatering", + "Skip minor updates for this package": "Hopp over mindre oppdateringer for denne pakken", + "Automatically update this package": "Automatisk oppdater denne pakken", + "{0} installation options": "{0} sine installasjonsvalg", + "Latest": "Siste", + "PreRelease": "Forhåndsutgivelse", + "Default": "Standard", + "Manage ignored updates": "Behandle ignorerte oppdateringer", + "The packages listed here won't be taken in account when checking for updates. Double-click them or click the button on their right to stop ignoring their updates.": "Pakkene i denne listen kommer ikke til å bli tatt hensyn til ved sjekking etter oppdateringer. Dobbeltklikk på dem eller klikk på knappen til høyre for dem for å slutte å ignorere oppdateringene deres.", + "Reset list": "Tilbakestill liste", + "Do you really want to reset the ignored updates list? This action cannot be reverted": "Vil du virkelig tilbakestille listen over ignorerte oppdateringer? Denne handlingen kan ikke angres.", + "No ignored updates": "Ingen ignorerte oppdateringer", + "Package Name": "Pakkenavn", + "Package ID": "Pakke-ID", + "Ignored version": "Ignorert versjon", + "New version": "Ny versjon", + "Source": "Kilde", + "All versions": "Alle versjoner", + "Unknown": "Ukjent", + "Up to date": "Oppdatert", + "Package {name} from {manager}": "Pakke {name} fra {manager}", + "Remove {0} from ignored updates": "Fjern {0} fra ignorerte oppdateringer", + "Cancel": "Avbryt", + "Administrator privileges": "Administratorrettigheter", + "This operation is running with administrator privileges.": "Denne handlingen kjører med adminprivilegier.", + "Interactive operation": "Interaktiv operasjon", + "This operation is running interactively.": "Denne operasjonen kjøres interaktivt.", + "You will likely need to interact with the installer.": "Du må sannsynligvis samhandle med installasjonsprogrammet.", + "Integrity checks skipped": "Integritetssjekk hoppet over", + "Integrity checks will not be performed during this operation.": "Integritetssjekker vil ikke bli utført under denne handlingen.", + "Proceed at your own risk.": "Fortsett på eget ansvar.", + "Close": "Lukk", + "Loading...": "Laster...", + "Installer SHA256": "Installasjonsprogram SHA256", + "Homepage": "Hjemmeside", + "Author": "Forfatter", + "Publisher": "Utgiver", + "License": "Lisens", + "Manifest": "Konfigurasjonsfil", + "Installer Type": "Type installasjonsprogram", + "Size": "Størrelse", + "Installer URL": "URL til installasjonsprogram", + "Last updated:": "Sist oppdatert:", + "Release notes URL": "URL for utgivelsesnotater", + "Package details": "Pakkedetaljer", + "Dependencies:": "Avhengigheter:", + "Release notes": "Utgivelsesnotater", + "Screenshots": "Skjermbilder", + "This package has no screenshots or is missing the icon? Contribute to UniGetUI by adding the missing icons and screenshots to our open, public database.": "Denne pakken har ingen skjermbilder eller mangler ikonet? Bidra til UniGetUI ved å legge til manglende ikoner og skjermbilder i vår åpne, offentlige database.", + "Version": "Versjon", + "Install as administrator": "Installér som administrator", + "Update to version {0}": "Oppdater til versjon {0}", + "Installed Version": "Installert versjon", + "Update as administrator": "Oppdater som administrator", + "Interactive update": "Interaktiv oppdatering", + "Uninstall as administrator": "Avinstaller som administrator", + "Interactive uninstall": "Interaktiv avinstallering", + "Uninstall and remove data": "Avinstaller og fjern data", + "Not available": "Ikke tilgjengelig", + "Installer SHA512": "Installasjonsprogram SHA512", + "Unknown size": "Ukjent størrelse", + "No dependencies specified": "Ingen avhengigheter er spesifisert", + "mandatory": "obligatorisk", + "optional": "valgfri", + "UniGetUI {0} is ready to be installed.": "UniGetUI {0} er klar til å bli installert.", + "The update process will start after closing UniGetUI": "Oppdateringsprosessen starter etter at du lukker UniGetUI", + "UniGetUI has been ran as administrator, which is not recommended. When running UniGetUI as administrator, EVERY operation launched from UniGetUI will have administrator privileges. You can still use the program, but we highly recommend not running UniGetUI with administrator privileges.": "UniGetUI har blitt kjørt som administrator, noe som ikke anbefales. Når UniGetUI kjører som administrator, vil ALLE handlinger som startes fra UniGetUI ha administratorrettigheter. Du kan fortsatt bruke programmet, men vi anbefaler på det sterkeste å ikke kjøre UniGetUI med administratorrettigheter.", + "Share anonymous usage data": "Del anonyme bruksdata", + "UniGetUI collects anonymous usage data in order to improve the user experience.": "UniGetUI samler inn anonyme bruksdata for å forbedre brukeropplevelsen.", + "Accept": "Aksepter", + "Software Updates": "Programoppdateringer", + "Package Bundles": "Pakkebundler", + "Settings": "Innstillinger", + "Package Managers": "Pakkehåndterere", + "UniGetUI Log": "UniGetUI-logg", + "Package Manager logs": "Pakkehåndteringslogger", + "Operation history": "Handlingshistorikk", + "Help": "Hjelp", + "UniGetUI": "UniGetUI", + "You have installed UniGetUI Version {0}": "Du har installert UniGetUI versjon {0}", + "Disclaimer": "Ansvarsfraskrivelse", + "UniGetUI is developed by Devolutions and is not affiliated with any of the compatible package managers.": "UniGetUI er utviklet av Devolutions og er ikke tilknyttet noen av de kompatible pakkebehandlerne.", + "UniGetUI wouldn't have been possible without the help of the contributors. Thank you all 🥳": "UniGetUI ville ikke vært mulig uten hjelpen fra alle bidragsyterne. Takk alle sammen🥳", + "UniGetUI uses the following libraries. Without them, UniGetUI wouldn't have been possible.": "UniGetUI bruker følgende bibliotek. Uten dem ville ikke UniGetUI vært mulig.", + "{0} homepage": "{0} sin hjemmeside", + "UniGetUI has been translated to more than 40 languages thanks to the volunteer translators. Thank you 🤝": "UniGetUI har blitt oversatt til mer enn 40 språk takket være frivillige oversettere. Takk 🤝", + "Verbose": "Utfyllende", + "1 - Errors": "1 - Feilmeldinger", + "2 - Warnings": "2 - Advarsler", + "3 - Information (less)": "3 - Informasjon (mindre)", + "4 - Information (more)": "4 - Informasjon (mer)", + "5 - information (debug)": "5 - Informasjon (feilsøking)", + "Warning": "Advarsel", + "The following settings may pose a security risk, hence they are disabled by default.": "Følgende innstillinger kan utgjøre en sikkerhetsrisiko, derfor er de deaktivert som standard.", + "Enable the settings below if and only if you fully understand what they do, and the implications they may have.": "Aktiver innstillingene nedenfor hvis og bare hvis du fullt ut forstår hva de gjør, og konsekvensene de kan ha.", + "The settings will list, in their descriptions, the potential security issues they may have.": "Innstillingene vil liste opp de potensielle sikkerhetsproblemene de kan ha i beskrivelsene sine.", + "The backup will include the complete list of the installed packages and their installation options. Ignored updates and skipped versions will also be saved.": "Sikkerhetskopien vil inneholde en fullstendig liste over de installerte pakkene og deres installasjonsvalg. Ignorerte oppdateringer og versjoner som har blitt hoppet over vil også bli lagret.", + "The backup will NOT include any binary file nor any program's saved data.": "Sikkerhetskopien vil ikke inneholde noen binære filer eller programmers lagrede data.", + "The size of the backup is estimated to be less than 1MB.": "Størrelsen på sikkerhetskopien er estimert at vil være mindre enn 1MB.", + "The backup will be performed after login.": "Sikkerhetskopien vil utføres etter innlogging", + "{pcName} installed packages": "{pcName}: Installerte pakker", + "Current status: Not logged in": "Gjeldende status: Ikke logget inn", + "You are logged in as {0} (@{1})": "Du er logget inn som {0} (@{1})", + "Nice! Backups will be uploaded to a private gist on your account": "Flott! Sikkerhetskopier vil bli lastet opp til en privat gist på kontoen din", + "Select backup": "Velg sikkerhetskopi", + "Settings imported from {0}": "Innstillinger importert fra {0}", + "UniGetUI Settings": "UniGetUI-innstillinger", + "Settings exported to {0}": "Innstillinger eksportert til {0}", + "UniGetUI settings were reset": "UniGetUI-innstillinger ble tilbakestilt", + "Allow pre-release versions": "Tillat forhåndsversjoner", + "Apply": "Bruk", + "For security reasons, custom command-line arguments are disabled by default. Go to UniGetUI security settings to change this.": "Av sikkerhetsgrunner er egendefinerte kommandolinjeparametre deaktivert som standard. Gå til UniGetUI-sikkerhetsinnstillingene for å endre dette.", + "Go to UniGetUI security settings": "Gå til UniGetUI-sikkerhetsinnstillinger", + "The following options will be applied by default each time a {0} package is installed, upgraded or uninstalled.": "Følgende alternativer vil bli brukt som standard hver gang en {0}-pakke blir installert, oppgradert eller avinstallert.", + "Package's default": "Pakkens standard", + "Install location can't be changed for {0} packages": "Installasjonsplassering kan ikke endres for {0} pakker", + "The local icon cache currently takes {0} MB": "Den lokale ikonhurtigbufferen tar for øyeblikket opp {0} MB", + "Username": "Brukernavn", + "Password": "Passord", + "Credentials": "Legitimasjon", + "It is not guaranteed that the provided credentials will be stored safely": "Det er ikke garantert at den oppgitte legitimasjonen blir lagret på en sikker måte", + "Partially": "Delvis", + "Package manager": "Pakkebehandler", + "Compatible with proxy": "Kompatibel med mellomtjener", + "Compatible with authentication": "Kompatibel med autentisering", + "Proxy compatibility table": "Mellomtjenerkompatibilitetstabell", + "{0} settings": "{0}-innstillinger", + "{0} status": "{0}-status", + "Default installation options for {0} packages": "Standardinstallasjonsvalg for {0} pakker", + "Expand version": "Utvid versjon", + "The executable file for {0} was not found": "Den kjørbare filen for {0} ble ikke funnet", + "{pm} is disabled": "{pm} er deaktivert", + "Enable it to install packages from {pm}.": "Aktiver det for å installere pakker fra {pm}", + "{pm} is enabled and ready to go": "{pm} er aktivert og klar for bruk", + "{pm} version:": "{pm} versjon: ", + "{pm} was not found!": "{pm} ble ikke funnet!", + "You may need to install {pm} in order to use it with UniGetUI.": "Du må kanskje installere {pm} for å bruke det med UniGetUI.", + "Scoop Installer - UniGetUI": "Scoop-installasjonsprogram - UniGetUI", + "Scoop Uninstaller - UniGetUI": "Scoop-avinstallasjonsprogram - UniGetUI", + "Clearing Scoop cache - UniGetUI": "Renser Scoop-cachen - UniGetUI", + "Restart UniGetUI to fully apply changes": "Start UniGetUI på nytt for å ta i bruk endringene fullt ut", + "Restart UniGetUI": "Start UniGetUI på nytt", + "Manage {0} sources": "Behandle {0} kilder", + "Add source": "Legg til kilde", + "Add": "Legg til", + "Source name": "Kildenavn", + "Source URL": "Kilde-URL", + "Other": "Andre", + "No minimum age": "Ingen minimumsalder", + "1 day": "1 dag", + "{0} days": "{0} dager", + "Custom...": "Egendefinert...", + "{0} minutes": "{0} minutter", + "1 hour": "1 time", + "{0} hours": "{0} timer", + "1 week": "1 uke", + "Supports release dates": "Støtter utgivelsesdatoer", + "Release date support per package manager": "Støtte for utgivelsesdatoer per pakkebehandler", + "Search for packages": "Søk etter pakker", + "Local": "Lokal", + "OK": "Greit", + "Last checked: {0}": "Sist sjekket: {0}", + "{0} packages were found, {1} of which match the specified filters.": "{1} pakker ble funnet, hvorav {0} samsvarte med filtrene dine.", + "{0} selected": "{0} valgt", + "(Last checked: {0})": "(Sist sjekket: {0})", + "All packages selected": "Alle pakker valgt", + "Package selection cleared": "Pakkevalg fjernet", + "{0}: {1}": "{0}: {1}", + "More info": "Mer informasjon", + "GitHub account": "GitHub-konto", + "Log in with GitHub to enable cloud package backup.": "Logg inn med GitHub for å skru på skylagrede pakkesikkerhetskopier.", + "More details": "Flere detaljer", + "Log in": "Logg inn", + "If you have cloud backup enabled, it will be saved as a GitHub Gist on this account": "Hvis du har skysikkerhetskopi aktivert, blir den lagret som en GitHub Gist på denne kontoen", + "Log out": "Logg ut", + "About UniGetUI": "Om UniGetUI", + "About": "Om", + "Third-party licenses": "Tredjepartslisenser", + "Contributors": "Bidragsytere", + "Translators": "Oversettere", + "Bundle security report": "Sikkerhetsrapport for pakkebundle", + "The bundle contained restricted content": "Bunken inneholdt begrenset innhold", + "UniGetUI – Crash Report": "UniGetUI – Krasjrapport", + "UniGetUI has crashed": "UniGetUI har krasjet", + "Help us fix this by sending a crash report to Devolutions. All fields below are optional.": "Hjelp oss med å fikse dette ved å sende en krasjrapport til Devolutions. Alle feltene nedenfor er valgfrie.", + "Email (optional)": "E-post (valgfritt)", + "your@email.com": "din@epost.no", + "Additional details (optional)": "Ytterligere detaljer (valgfritt)", + "Describe what you were doing when the crash occurred…": "Beskriv hva du gjorde da krasjet oppstod…", + "Crash report": "Krasjrapport", + "Don't Send": "Ikke send", + "Send Report": "Send rapport", + "Sending…": "Sender…", + "Unsaved changes": "Ulagrede endringer", + "You have unsaved changes in the current bundle. Do you want to discard them?": "Du har ulagrede endringer i den nåværende bunken. Vil du forkaste dem?", + "Discard changes": "Forkast endringer", + "Integrity violation": "Integritetsbrudd", + "UniGetUI or some of its components are missing or corrupt. It is strongly recommended to reinstall UniGetUI to adress the situation.": "UniGetUI eller noen av komponentene mangler eller er skadet. Det anbefales på det sterkeste å installere UniGetUI på nytt for å rette opp situasjonen.", + "• Refer to the UniGetUI Logs to get more details regarding the affected file(s)": "• Se UniGetUI-loggene for å få mer informasjon om de berørte filene", + "• Integrity checks can be disabled from the Experimental Settings": "• Integritetssjekker kan deaktiveres fra eksperimentelle innstillinger", + "Manage shortcuts": "Behandle snarveier", + "UniGetUI has detected the following desktop shortcuts which can be removed automatically on future upgrades": "UniGetUI har oppdaget følgende skrivebordssnarveier som kan fjernes automatisk ved fremtidige oppgraderinger", + "Do you really want to reset this list? This action cannot be reverted.": "Vil du virkelig tilbakestille denne listen? Denne handlingen kan ikke reverseres.", + "Desktop shortcuts list": "Liste over skrivebordssnarveier", + "Open in explorer": "Åpne i Filutforsker", + "Remove from list": "Fjern fra liste", + "When new shortcuts are detected, delete them automatically instead of showing this dialog.": "Når nye snarveier oppdages, slett dem automatisk i stedet for å vise denne dialogen.", + "Not right now": "Ikke akkurat nå", + "Missing dependency": "Mangler avhengighet", + "UniGetUI requires {0} to operate, but it was not found on your system.": "UniGetUI krever {0} for å fungere, men det ble ikke funnet på systemet ditt.", + "Click on Install to begin the installation process. If you skip the installation, UniGetUI may not work as expected.": "Trykk på \"Installer\" for å starte installasjonsprosessen. Hvis du hopper over installasjonen, kan det hende at UniGetUI ikke fungerer som den skal.", + "Alternatively, you can also install {0} by running the following command in a Windows PowerShell prompt:": "Du kan eventuelt også installere {0} ved å kjøre følgende kommando i Windows PowerShell:", + "Install {0}": "Installer {0}", + "Do not show this dialog again for {0}": "Ikke vis denne dialogen igjen for {0}", + "Please wait while {0} is being installed. A black window may show up. Please wait until it closes.": "Vent mens {0} blir installert. Et svart (eller blått) vindu kan vises. Vent til det lukkes.", + "{0} has been installed successfully.": "{0} har blitt installert vellykket.", + "Please click on \"Continue\" to continue": "Vennligst klikk på \"Fortsett\" for å fortsette", + "Continue": "Fortsett", + "{0} has been installed successfully. It is recommended to restart UniGetUI to finish the installation": "{0} har blitt installert vellykket. Det anbefales å starte UniGetUI på nytt for å fullføre installasjonen", + "Restart later": "Start på nytt senere", + "An error occurred:": "En feil oppstod:", + "Please see the Command-line Output or refer to the Operation History for further information about the issue.": "Vennligst se på kommandolinje-outputen eller handlingshistorikken for mer informasjon om problemet.", + "Retry as administrator": "Prøv igjen som administrator", + "Retry interactively": "Prøv igjen interaktivt", + "Retry skipping integrity checks": "Prøv igjen og hopp over integritetssjekker", + "Installation options": "Installasjonsvalg", + "Save": "Lagre", + "UniGetUI collects anonymous usage data with the sole purpose of understanding and improving the user experience.": "UniGetUI samler inn anonyme bruksdata utelukkende for å forstå og forbedre brukeropplevelsen.", + "More details about the shared data and how it will be processed": "Mer informasjon om delte data og hvordan de vil bli behandlet", + "Do you accept that UniGetUI collects and sends anonymous usage statistics, with the sole purpose of understanding and improving the user experience?": "Godtar du at UniGetUI samler inn og sender anonyme bruksstatistikker, utelukkende for å forstå og forbedre brukeropplevelsen?", + "Decline": "Avslå", + "No personal information is collected nor sent, and the collected data is anonimized, so it can't be back-tracked to you.": "Ingen personlig informasjon blir samlet inn eller sendt, og de innsamlede dataene er anonymiserte, slik at de ikke kan spores tilbake til deg.", + "Navigation panel": "Navigasjonspanel", + "Operations": "Operasjoner", + "Toggle operations panel": "Vis/skjul operasjonspanel", + "Bulk operations": "Masseoperasjoner", + "Retry failed": "Prøv mislykkede på nytt", + "Clear successful": "Fjern vellykkede", + "Clear finished": "Fjern fullførte", + "Cancel all": "Avbryt alle", + "More": "Mer", + "Toggle navigation panel": "Vis/skjul navigasjonspanelet", + "Minimize": "Minimer", + "Maximize": "Maksimer", + "UniGetUI by Devolutions": "UniGetUI av Devolutions", + "UniGetUI is an application that makes managing your software easier, by providing an all-in-one graphical interface for your command-line package managers.": "UniGetUI er en applikasjon som forenkler håndtering av programvare, ved å tilby et alt-i-ett grafisk grensesnitt for kommandolinjepakkehåndtererne dine.", + "Useful links": "Nyttige lenker", + "UniGetUI Homepage": "UniGetUI-hjemmeside", + "Report an issue or submit a feature request": "Si fra om en feil eller send inn forslag til nye funksjoner", + "UniGetUI Repository": "UniGetUI-repositorium", + "View GitHub Profile": "Vis GitHub-profil", + "UniGetUI License": "UniGetUI - Lisens", + "Using UniGetUI implies the acceptation of the MIT License": "Bruk av UniGetUI innebærer å godta MIT-lisensen", + "Become a translator": "Bli en oversetter", + "Go back": "Gå tilbake", + "Go forward": "Gå fremover", + "Go to home page": "Gå til startsiden", + "Reload page": "Last inn siden på nytt", + "View page on browser": "Vis siden i nettleseren", + "The built-in browser is not supported on Linux yet.": "Den innebygde nettleseren støttes ikke på Linux ennå.", + "Open in browser": "Åpne i nettleser", + "Copy to clipboard": "Kopier til utklippstavlen", + "Export to a file": "Eksporter til en fil", + "Log level:": "Loggnivå:", + "Reload log": "Last inn logg på nytt", + "Export log": "Eksporter logg", + "Text": "Tekst", + "Change how operations request administrator rights": "Endre hvordan handlinger spør om adminrettigheter", + "Restrictions on package operations": "Begrensninger for pakkeoperasjoner", + "Restrictions on package managers": "Begrensninger på pakkebehandlere", + "Restrictions when importing package bundles": "Begrensninger ved import av pakkebundler", + "Ask for administrator privileges once for each batch of operations": "Spør etter administratorrettigheter en gang per gruppe operasjoner", + "Ask only once for administrator privileges": "Spør kun én gang om adminprivilegier", + "Prohibit any kind of Elevation via UniGetUI Elevator or GSudo": "Forby enhver form for opphøying via UniGetUI Elevator eller GSudo", + "This option WILL cause issues. Any operation incapable of elevating itself WILL FAIL. Install/update/uninstall as administrator will NOT WORK.": "Dette alternativet VIL forårsake problemer. Enhver operasjon som ikke klarer å opphøye seg selv VIL MISLYKKES. Installasjon/oppdatering/avinstallering som administrator VIL IKKE FUNGERE.", + "Allow custom command-line arguments": "Tillat tilpassede kommandolinjeparametre", + "Custom command-line arguments can change the way in which programs are installed, upgraded or uninstalled, in a way UniGetUI cannot control. Using custom command-lines can break packages. Proceed with caution.": "Egendefinerte kommandolinjeparametre kan endre måten programmer installeres, oppgraderes eller avinstalleres på, på en måte som UniGetUI ikke kan kontrollere. Bruk av egendefinerte kommandolinjer kan ødelegge pakker. Fortsett med forsiktighet.", + "Ignore custom pre-install and post-install commands when importing packages from a bundle": "Ignorer egendefinerte pre-installasjons- og post-installasjonskommandoer ved import av pakker fra en pakkegruppe", + "Pre and post install commands will be run before and after a package gets installed, upgraded or uninstalled. Be aware that they may break things unless used carefully": "Pre- og post-installasjonskommandoer vil kjøres før og etter at en pakke blir installert, oppgradert eller avinstallert. Vær oppmerksom på at de kan ødelegge ting med mindre de brukes nøye", + "Allow changing the paths for package manager executables": "Tillat endring av stier for pakkehåndtereres kjørbare filer", + "Turning this on enables changing the executable file used to interact with package managers. While this allows finer-grained customization of your install processes, it may also be dangerous": "Hvis du slår dette på, kan du endre den kjørbare filen som brukes til å samhandle med pakkehåndterere. Selv om dette gir mer detaljert tilpasning av installasjonsprosessene dine, kan det også være farlig", + "Allow importing custom command-line arguments when importing packages from a bundle": "Tillat import av tilpassede kommandolinjeparametre ved import av pakker fra en pakkebundle", + "Malformed command-line arguments can break packages, or even allow a malicious actor to gain privileged execution. Therefore, importing custom command-line arguments is disabled by default": "Feilformede kommandolinjeparametre kan ødelegge pakker, eller til og med tillate en ondsinnet aktør å oppnå privilegert kjøring. Derfor er import av egendefinerte kommandolinjeparametre deaktivert som standard.", + "Allow importing custom pre-install and post-install commands when importing packages from a bundle": "Tillat import av egendefinerte pre-installasjons- og post-installasjonskommandoer ved import av pakker fra en pakkebundle", + "Pre and post install commands can do very nasty things to your device, if designed to do so. It can be very dangerous to import the commands from a bundle, unless you trust the source of that package bundle": "Pre- og post-installasjonskommandoer kan gjøre veldig ubehagelige ting med enheten din, hvis de er designet for det. Det kan være veldig farlig å importere kommandoene fra en pakkebundle, med mindre du stoler på kilden til pakkebundlen", + "Administrator rights and other dangerous settings": "Adminrettigheter og andre risikable innstillinger", + "Package backup": "Pakke-sikkerhetskopiering", + "Cloud package backup": "Skylagret pakkesikkerhetskopi", + "Local package backup": "Lokal pakkesikkerhetskopi", + "Local backup advanced options": "Avanserte valg for lokal sikkerhetskopi", + "Log in with GitHub": "Logg inn med GitHub", + "Log out from GitHub": "Logg ut fra GitHub", + "Periodically perform a cloud backup of the installed packages": "Utfør periodisk en skysikkerhetskopi av de installerte pakkene", + "Cloud backup uses a private GitHub Gist to store a list of installed packages": "Skysikkerhetskopiering bruker en privat GitHub Gist til å lagre en liste over installerte pakker", + "Perform a cloud backup now": "Utfør en skysikkerhetskopi nå", + "Backup": "Ta sikkerhetskopi", + "Restore a backup from the cloud": "Gjenopprett en sikkerhetskopi fra skyen", + "Begin the process to select a cloud backup and review which packages to restore": "Start prosessen for å velge en skylagret sikkerhetskopi og gjennomgå hvilke pakker som skal gjenopprettes", + "Periodically perform a local backup of the installed packages": "Utfør periodisk en lokal sikkerhetskopi av de installerte pakkene", + "Perform a local backup now": "Utfør en lokal sikkerhetskopi nå", + "Change backup output directory": "Endre utdatamappen for sikkerhetskopier", + "Set a custom backup file name": "Velg et eget navn for sikkerhetskopifilen", + "Leave empty for default": "La stå tomt for standardvalget", + "Add a timestamp to the backup file names": "Legg til et tidsstempel til sikkerhetskopi-filnavnene", + "Backup and Restore": "Sikkerhetskopier og gjenopprett", + "Enable background api (UniGetUI Widgets and Sharing, port 7058)": "Aktiver bakgrunns-API-et (UniGetUI Widgets and Sharing, port 7058)", + "Wait for the device to be connected to the internet before attempting to do tasks that require internet connectivity.": "Vent til enheten er koblet til internett før du prøver å utføre oppgaver som krever internettilkobling.", + "Disable the 1-minute timeout for package-related operations": "Deaktiver 1-minutters tidsavbrudd for pakkerelaterte operasjoner", + "Use installed GSudo instead of UniGetUI Elevator": "Bruk installert GSudo i stedet for UniGetUI Elevator", + "Use a custom icon and screenshot database URL": "Bruk et egendefinert ikon og en egendefinert URL til databasen", + "Enable background CPU Usage optimizations (see Pull Request #3278)": "Aktiver optimaliseringer for CPU-bruk i bakgrunnen (se Pull Request #3278)", + "Perform integrity checks at startup": "Utfør integritetssjekker ved oppstart", + "When batch installing packages from a bundle, install also packages that are already installed": "Ved bunkeinstallasjon av pakker fra en pakkebundle, installer også pakker som allerede er installert", + "Experimental settings and developer options": "Eksperimentelle innstillinger og valg for utviklere", + "Show UniGetUI's version and build number on the titlebar.": "Vis UniGetUI-versjonen på tittellinjen.", + "Language": "Språk", + "UniGetUI updater": "UniGetUI-oppdaterer", + "Telemetry": "Telemetri", + "Manage UniGetUI settings": "Behandle UniGetUI-innstillinger", + "Related settings": "Relaterte innstillinger", + "Update UniGetUI automatically": "Oppdater UniGetUI automatisk", + "Check for updates": "Se etter oppdateringer", + "Install prerelease versions of UniGetUI": "Installer forhåndsversjoner av UniGetUI", + "Manage telemetry settings": "Administrer telemetriinnstillinger", + "Manage": "Behandle", + "Import settings from a local file": "Importer innstillinger fra en lokal fil", + "Import": "Importer", + "Export settings to a local file": "Eksporter innstillinger til en lokal fil", + "Export": "Eksporter", + "Reset UniGetUI": "Tilbakestill UniGetUI", + "User interface preferences": "Alternativer for brukergrensesnitt", + "Application theme, startup page, package icons, clear successful installs automatically": "App-tema, oppstartsfane, pakkeikoner, fjern suksessfulle installasjoner automatisk", + "General preferences": "Generelle innstillinger", + "UniGetUI display language:": "UniGetUI sitt visningsspråk:", + "System language": "Systemspråk", + "Is your language missing or incomplete?": "Mangler språket ditt eller er det uferdig?", + "Appearance": "Utseende", + "UniGetUI on the background and system tray": "UniGetUI i bakgrunnen og systemkurven", + "Package lists": "Pakkelister", + "Use classic mode": "Bruk klassisk modus", + "Restart UniGetUI to apply this change": "Start UniGetUI på nytt for å ta i bruk denne endringen", + "The classic UI is disabled for beta testers": "Det klassiske brukergrensesnittet er deaktivert for betatestere", + "Close UniGetUI to the system tray": "Lukk UniGetUI til systemkurven", + "Manage UniGetUI autostart behaviour": "Administrer UniGetUIs autostartoppførsel", + "Show package icons on package lists": "Vis pakkeikoner i pakkelistene", + "Clear cache": "Tøm hurtigbuffer (cache)", + "Select upgradable packages by default": "Velg oppgraderbare pakker som standard", + "Light": "Lys", + "Dark": "Mørk", + "Follow system color scheme": "Følg systemtemaet", + "Application theme:": "Applikasjonstema:", + "UniGetUI startup page:": "UniGetUI-oppstartsside:", + "Proxy settings": "Mellomtjenerinnstillinger", + "Other settings": "Andre innstillinger", + "Connect the internet using a custom proxy": "Koble til internettet med en selvvalgt mellomtjener", + "Please note that not all package managers may fully support this feature": "Vær oppmerksom på at ikke alle pakkehåndterere kan støtte denne funksjonen fullt ut", + "Proxy URL": "Mellomtjener-URL", + "Enter proxy URL here": "Skriv inn mellomtjener-URL her", + "Authenticate to the proxy with a user and a password": "Autentiser mot mellomtjeneren med brukernavn og passord", + "Internet and proxy settings": "Internett- og mellomtjenerinnstillinger", + "Package manager preferences": "Innstillinger for pakkehåndterer", + "Ready": "Klar", + "Not found": "Ikke funnet", + "Notification preferences": "Varslingsinnstillinger", + "Notification types": "Varslingstyper", + "The system tray icon must be enabled in order for notifications to work": "Systemkurv-ikonet må være aktivert for at varsler skal fungere", + "Enable UniGetUI notifications": "Aktiver varsler fra UniGetUI", + "Show a notification when there are available updates": "Vis et varsel når oppdateringer er tilgjengelige", + "Show a silent notification when an operation is running": "Vis en stille varsling når en operasjon kjører", + "Show a notification when an operation fails": "Vis en varsling når en operasjon feiler", + "Show a notification when an operation finishes successfully": "Vis en varsling når en operasjon fullføres", + "Concurrency and execution": "Samtidighet og kjøring", + "Automatic desktop shortcut remover": "Automatisk fjerner av skrivebordssnarveier", + "Choose how many operations should be performed in parallel": "Velg hvor mange handlinger som skal utføres parallelt", + "Clear successful operations from the operation list after a 5 second delay": "Tøm vellykkede handlinger fra handlingslisten etter en 5-sekunders forsinkelse", + "Download operations are not affected by this setting": "Nedlastningshandlinger er ikke påvirket av denne innstillingen", + "You may lose unsaved data": "Du kan miste ulagrede data", + "Ask to delete desktop shortcuts created during an install or upgrade.": "Be om å slette skrivebordssnarveier som ble opprettet under installasjon eller oppgradering.", + "Package update preferences": "Preferanser for pakkeoppdateringer", + "Update check frequency, automatically install updates, etc.": "Hvor ofte oppdateringer ses etter, installer oppdateringer automatisk, osv.", + "Reduce UAC prompts, elevate installations by default, unlock certain dangerous features, etc.": "Reduser UAC-forespørsler, kjør installerere som admin som standard, lås opp visse risikable funksjoner, osv.", + "Package operation preferences": "Pakkehandlingsinnstillinger", + "Enable {pm}": "Aktiver {pm}", + "Not finding the file you are looking for? Make sure it has been added to path.": "Finner du ikke filen du leter etter? Kontroller at den har blitt lagt til i stien.", + "Select the executable to be used. The following list shows the executables found by UniGetUI": "Velg den kjørbare filen som skal brukes. Følgende liste viser de kjørbare filene funnet av UniGetUI", + "For security reasons, changing the executable file is disabled by default": "Av sikkerhetsgrunner er endring av kjørbar fil deaktivert som standard", + "Change this": "Endre dette", + "Copy path": "Kopier bane", + "Current executable file:": "Gjeldende kjørbar fil:", + "Ignore packages from {pm} when showing a notification about updates": "Ignorer pakker fra {pm} når det vises et varsel om oppdateringer", + "Update security": "Oppdateringssikkerhet", + "Use global setting": "Bruk global innstilling", + "Minimum age for updates": "Minimumsalder for oppdateringer", + "e.g. 10": "f.eks. 10", + "Custom minimum age (days)": "Egendefinert minimumsalder (dager)", + "{pm} does not provide release dates for its packages, so this setting will have no effect": "{pm} oppgir ikke utgivelsesdatoer for pakkene sine, så denne innstillingen vil ikke ha noen effekt", + "{pm} only provides release dates for some of its packages, so this setting will only apply to those packages": "{pm} oppgir bare utgivelsesdatoer for noen av pakkene sine, så denne innstillingen gjelder bare for de pakkene", + "Override the global minimum update age for this package manager": "Overstyr den globale minimumsalderen for oppdateringer for denne pakkebehandleren", + "View {0} logs": "Vis {0} logger", + "If Python cannot be found or is not listing packages but is installed on the system, ": "Hvis Python ikke kan finnes eller ikke viser pakker selv om det er installert på systemet, ", + "Advanced options": "Avanserte innstillinger", + "WinGet command-line tool": "WinGet-kommandolinjeverktøy", + "Choose which command-line tool UniGetUI uses for WinGet operations when the COM API is not used": "Velg hvilket kommandolinjeverktøy UniGetUI bruker for WinGet-operasjoner når COM API ikke brukes", + "WinGet COM API": "WinGet COM API", + "Choose whether UniGetUI can use the WinGet COM API before falling back to the command-line tool": "Velg om UniGetUI kan bruke WinGet COM API før det faller tilbake til kommandolinjeverktøyet", + "Reset WinGet": "Tilbakestill UniGetUI", + "This may help if no packages are listed": "Dette kan hjelpe hvis ingen pakker vises", + "Force install location parameter when updating packages with custom locations": "Tving installasjonslokasjonsparameter ved oppdatering av pakker med egendefinerte plasseringer", + "Install Scoop": "Installer Scoop", + "Uninstall Scoop (and its packages)": "Avinstaller Scoop (og alle tilhørende pakker)", + "Run cleanup and clear cache": "Kjør opprensing og fjern buffer", + "Run": "Kjør", + "Enable Scoop cleanup on launch": "Aktiver Scoop-cleanup (nullstilling av buffer) ved oppstart", + "Default vcpkg triplet": "Standard vcpkg-triplet", + "Change vcpkg root location": "Endre plasseringen til vcpkg-roten", + "Reset vcpkg root location": "Tilbakestill vcpkg-rotplassering", + "Open vcpkg root location": "Åpne vcpkg-rotplassering", + "Language, theme and other miscellaneous preferences": "Språk, tema og diverse andre preferanser", + "Show notifications on different events": "Vis varslinger for ulike hendelser", + "Change how UniGetUI checks and installs available updates for your packages": "Endre hvordan UniGetUI sjekker for og installerer tilgjengelige oppdateringer for pakkene dine", + "Automatically save a list of all your installed packages to easily restore them.": "Lagre en liste over alle dine installerte pakker automatisk for å forenkle gjenoppretting av dem.", + "Enable and disable package managers, change default install options, etc.": "Skru på eller av pakkebehandlere, endre standardinnstillingene for installeringer, osv.", + "Internet connection settings": "Internettilkoblingsinnstillinger", + "Proxy settings, etc.": "Mellomtjenerinnstillinger, osv.", + "Beta features and other options that shouldn't be touched": "Beta-funksjonalitet og andre innstillinger som ikke bør røres", + "Reload sources": "Last inn kilder på nytt", + "Delete source": "Slett kilde", + "Known sources": "Kjente kilder", + "Update checking": "Oppdateringssjekker", + "Automatic updates": "Automatiske oppdateringer", + "Check for package updates periodically": "Sjekk etter pakkeoppdateringer med jevne mellomrom", + "Check for updates every:": "Søk etter oppdateringer hver:", + "Install available updates automatically": "Installer tilgjengelige oppdateringer automatisk", + "Do not automatically install updates when the network connection is metered": "Ikke automatisk oppdater pakker hvis nettverkstilkoblingen er på mobildata", + "Do not automatically install updates when the device runs on battery": "Ikke automatisk oppdater pakker mens enheten kjører på batteri", + "Do not automatically install updates when the battery saver is on": "Ikke automatisk installer oppdateringer mens Batterisparing er på", + "Only show updates that are at least the specified number of days old": "Vis bare oppdateringer som er minst det angitte antallet dager gamle", + "Warn me when the installer URL host changes between the installed version and the new version (WinGet only)": "Advar meg når verten i installasjonsprogrammets URL endres mellom den installerte versjonen og den nye versjonen (kun WinGet)", + "Change how UniGetUI handles install, update and uninstall operations.": "Endre hvordan UniGetUI håndterer installasjons-, oppdaterings- og avinstallasjonsoperasjoner.", + "Navigation": "Navigasjon", + "Check for UniGetUI updates": "Se etter UniGetUI-oppdateringer", + "Quit UniGetUI": "Avslutt UniGetUI", + "Filters": "Filtre", + "Sources": "Kilder", + "Search for packages to start": "Søk etter en eller flere pakker for å starte", + "Select all": "Velg alle", + "Clear selection": "Tøm valg", + "Instant search": "Hurtigsøk", + "Distinguish between uppercase and lowercase": "Skill mellom store og små bokstaver", + "Ignore special characters": "Ignorer spesialtegn", + "Search mode": "Søkemodus", + "Both": "Begge", + "Exact match": "Eksakt samsvar", + "Show similar packages": "Vis lignende pakker", + "Loading": "Laster", + "Package": "Pakke", + "More options": "Flere alternativer", + "Order by:": "Sortér etter:", + "Name": "Navn", + "Id": "ID", + "Ascendant": "Stigende", + "Descendant": "Synkende", + "View modes": "Visningsmoduser", + "Reload": "Last inn på nytt", + "Closed": "Lukket", + "Ascending": "Stigende", + "Descending": "Synkende", + "{0}: {1}, {2}": "{0}: {1}, {2}", + "Order by": "Sorter etter", + "No results were found matching the input criteria": "Ingen resultater som matchet kriteriene ble funnet", + "No packages were found": "Ingen pakker ble funnet", + "Loading packages": "Laster inn pakker", + "Skip integrity checks": "Hopp over integritetssjekker", + "Download selected installers": "Last ned de valgte installerere", + "Install selection": "Installer utvalg", + "Install options": "Installeringsalternativer", + "Add selection to bundle": "Legg til utvalg til bundlen", + "Download installer": "Last ned installasjonsprogram", + "Uninstall selection": "Avinstaller valgte", + "Uninstall options": "Avinstallasjonsvalg", + "Ignore selected packages": "Ignorer valgte pakker", + "Open install location": "Åpne installasjonsplassering", + "Reinstall package": "Installer pakke på nytt", + "Uninstall package, then reinstall it": "Avinstaller pakken, og så reinstaller den", + "Ignore updates for this package": "Ignorer oppdateringer til denne pakken", + "WinGet malfunction detected": "Feilfunksjon i WinGet oppdaget", + "It looks like WinGet is not working properly. Do you want to attempt to repair WinGet?": "Det ser ut til at WinGet ikke fungerer som det skal. Vil du forsøke å reparere WinGet?", + "Repair WinGet": "Reparer WinGet", + "Updates will no longer be ignored for {0}": "Oppdateringer vil ikke lenger bli ignorert for {0}", + "Updates are now ignored for {0}": "Oppdateringer er nå ignorert for {0}", + "Do not ignore updates for this package anymore": "Ikke ignorer oppdateringer for denne pakken lenger", + "Add packages or open an existing package bundle": "Legg til pakker eller åpne en eksisterende bundle", + "Add packages to start": "Legg til pakker for å starte", + "The current bundle has no packages. Add some packages to get started": "Nåværende bundle har ingen pakker. Legg til pakker for å sette i gang", + "New": "Ny", + "Save as": "Lagre som", + "Create .ps1 script": "Lag et .ps1-skript", + "Remove selection from bundle": "Fjern utvalg fra bundle", + "Skip hash checks": "Hopp over hash-sjekker", + "The package bundle is not valid": "Pakkebundlen er ikke gyldig", + "The bundle you are trying to load appears to be invalid. Please check the file and try again.": "Pakkebundlen du prøver å laste inn ser ut til å være ugyldig. Kontroller filen og prøv igjen.", + "Package bundle": "Pakkebundle", + "Could not create bundle": "Klarte ikke å lage pakkebundle", + "The package bundle could not be created due to an error.": "Pakkebundlen kunne ikke opprettes på grunn av en feil.", + "Install script": "Installasjonsskript", + "PowerShell script": "PowerShell-skript", + "The installation script saved to {0}": "Installasjonsskriptet ble lagret til {0}", + "An error occurred": "En feil oppstod", + "An error occurred while attempting to create an installation script:": "En feil oppstod under forsøk på å lage et installasjonsskript:", + "Hooray! No updates were found.": "Hurra! Ingen oppdateringer ble funnet!", + "Uninstall selected packages": "Avinstaller valgte pakker", + "Update selection": "Oppdater utvalg", + "Update options": "Oppdateringsinnstillinger", + "Uninstall package, then update it": "Avinstaller pakken, og så oppdater den", + "Uninstall package": "Avinstaller pakken", + "Skip this version": "Hopp over denne versjonen", + "Pause updates for": "Sett oppdateringer på pause i", + "User | Local": "Bruker | Lokal", + "Machine | Global": "Maskin | Global", + "The default package manager for Debian/Ubuntu-based Linux distributions.
Contains: Debian/Ubuntu packages": "Standard pakkebehandler for Debian/Ubuntu-baserte Linux-distribusjoner.
Inneholder: Debian/Ubuntu-pakker", + "The Rust package manager.
Contains: Rust libraries and programs written in Rust": "Rust-pakkehåndtereren.
Inneholder: Rust-biblioteker og programmer skrevet i Rust", + "The classical package manager for windows. You'll find everything there.
Contains: General Software": "Den klassiske pakkehåndtereren for Windows. Du kan finne alt mulig rart der.
Inneholder: Generell programvare", + "The default package manager for RHEL/Fedora-based Linux distributions.
Contains: RPM packages": "Standard pakkebehandler for RHEL/Fedora-baserte Linux-distribusjoner.
Inneholder: RPM-pakker", + "A repository full of tools and executables designed with Microsoft's .NET ecosystem in mind.
Contains: .NET related tools and scripts": "Et pakkelager fullt av verktøy og programmer designet for Microsoft sitt .NET-økosystem.
Inneholder: .NET-relaterte verktøy og skript", + "The universal Linux package manager for desktop applications.
Contains: Flatpak applications from configured remotes": "Den universelle Linux-pakkebehandleren for skrivebordsprogrammer.
Inneholder: Flatpak-programmer fra konfigurerte eksterne kilder", + "NuPkg (zipped manifest)": "NuPkg (zippet manifest)", + "The Missing Package Manager for macOS (or Linux).
Contains: Formulae, Casks": "Den manglende pakkebehandleren for macOS (eller Linux).
Inneholder: Formulae, Casks", + "Node JS's package manager. Full of libraries and other utilities that orbit the javascript world
Contains: Node javascript libraries and other related utilities": "Node JS sin pakkehåndterer. Full av biblioteker og andre verktøy som svever rundt i JavaScript-universet
Inneholder: Node.js-biblioteker og andre relaterte verktøy", + "The default package manager for Arch Linux and its derivatives.
Contains: Arch Linux packages": "Standard pakkebehandler for Arch Linux og dets derivater.
Inneholder: Arch Linux-pakker", + "Python's library manager. Full of python libraries and other python-related utilities
Contains: Python libraries and related utilities": "Python sin bibliotekshåndterer. Full av Python-biblioteker og andre python-relaterte verktøy
Inneholder: Python-biblioteker og relaterte verktøy", + "PowerShell's package manager. Find libraries and scripts to expand PowerShell capabilities
Contains: Modules, Scripts, Cmdlets": "PowerShell sin pakkehåndterer. Finn bibliotek og skript for å utvide PowerShell sine evner
Inneholder: Moduler, skript, cmdlets", + "extracted": "utpakket", + "Scoop package": "Scoop-pakke", + "Great repository of unknown but useful utilities and other interesting packages.
Contains: Utilities, Command-line programs, General Software (extras bucket required)": "Flott pakkehåndterer med ukjente men nyttige verktøy og andre interessante pakker.
Inneholder:Verktøy, kommandolinjeprogrammer, generell programvare (ekstra buckets trengs)", + "The universal Linux package manager by Canonical.
Contains: Snap packages from the Snapcraft store": "Den universelle Linux-pakkebehandleren fra Canonical.
Inneholder: Snap-pakker fra Snapcraft-butikken", + "library": "bibliotek", + "feature": "funksjon", + "A popular C/C++ library manager. Full of C/C++ libraries and other C/C++-related utilities
Contains: C/C++ libraries and related utilities": "En populær C/C++-bibliotekhåndterer. Full av C/C++-biblioteker og andre relaterte verktøy.
Inneholder: C/C++-biblioteker og relaterte verktøy", + "option": "valg", + "This package cannot be installed from an elevated context.": "Denne pakken kan ikke installeres fra en opphøyd kontekst.", + "Please run UniGetUI as a regular user and try again.": "Kjør UniGetUI som en vanlig bruker og prøv igjen.", + "Please check the installation options for this package and try again": "Kontroller installasjonsalternativene for denne pakken og prøv igjen", + "Microsoft's official package manager. Full of well-known and verified packages
Contains: General Software, Microsoft Store apps": "Microsoft sin offisielle pakkehåndterer. Full av velkjente og verifiserte pakker
Inneholder: Generell programvare, Microsoft Store-apper", + "Local PC": "Lokal PC", + "Android Subsystem": "Android-undersystem", + "Operation on queue (position {0})...": "Handlingen er i køen (posisjon {0})...", + "Click here for more details": "Klikk her for flere detaljer", + "Operation canceled by user": "Operasjon avbrutt av bruker", + "Running PreOperation ({0}/{1})...": "Kjører PreOperation ({0}/{1})...", + "PreOperation {0} out of {1} failed, and was tagged as necessary. Aborting...": "PreOperation {0} av {1} mislyktes og var merket som nødvendig. Avbryter...", + "PreOperation {0} out of {1} finished with result {2}": "PreOperation {0} av {1} fullførte med resultat {2}", + "Starting operation...": "Starter operasjon...", + "Running PostOperation ({0}/{1})...": "Kjører PostOperation ({0}/{1})...", + "PostOperation {0} out of {1} failed, and was tagged as necessary. Aborting...": "PostOperation {0} av {1} mislyktes og var merket som nødvendig. Avbryter...", + "PostOperation {0} out of {1} finished with result {2}": "PostOperation {0} av {1} fullførte med resultat {2}", + "{package} installer download": "{package} installasjonsprogramnedlasting", + "{0} installer is being downloaded": "{0} installasjonsprogram lastes ned", + "Download succeeded": "Nedlasting var suksessfull", + "{package} installer was downloaded successfully": "{package} installasjonsprogram ble lastet ned vellykket", + "Download failed": "Nedlasting mislyktes", + "{package} installer could not be downloaded": "{package} installasjonsprogram kunne ikke lastes ned", + "{package} Installation": "{package} Installasjon", + "{0} is being installed": "{0} blir installert", + "Installation succeeded": "Installasjon fullført", + "{package} was installed successfully": "{package} ble suksessfullt installert", + "Installation failed": "Installasjon feilet", + "{package} could not be installed": "{package} kunne ikke installeres", + "{package} Update": "{package} Oppdater", + "Update succeeded": "Suksessfull oppdatering", + "{package} was updated successfully": "{package} ble suksessfullt oppdatert", + "Update failed": "Oppdatering feilet", + "{package} could not be updated": "{package} kunne ikke oppdateres", + "{package} Uninstall": "{package} Avinstaller", + "{0} is being uninstalled": "{0} blir avinstallert", + "Uninstall succeeded": "Suksessfull avinstallering", + "{package} was uninstalled successfully": "{package} ble suksessfullt avinstallert", + "Uninstall failed": "Avinstallering feilet", + "{package} could not be uninstalled": "{package} kunne ikke avinstalleres", + "Adding source {source}": "Legger til kilde {source}", + "Adding source {source} to {manager}": "Legger til kilde {source} til {manager}", + "Source added successfully": "Kilde lagt til vellykket", + "The source {source} was added to {manager} successfully": "Kilden {source} ble suksessfullt lag til hos {manager}", + "Could not add source": "Mislyktes i å legge til kilde", + "Could not add source {source} to {manager}": "Kunne ikke legge til kilde {source} til {manager}", + "Removing source {source}": "Fjerner kilden {source}", + "Removing source {source} from {manager}": "Fjerner kilde {source} fra {manager}", + "Source removed successfully": "Kilde fjernet vellykket", + "The source {source} was removed from {manager} successfully": "Kilden {source} ble suksessfullt fjernet fra {manager}", + "Could not remove source": "Klarte ikke å fjerne kilde", + "Could not remove source {source} from {manager}": "Kunne ikke fjerne kilde {source} fra {manager}", + "The package manager \"{0}\" was not found": "«{0}»-pakkebehandleren ble ikke funnet", + "The package manager \"{0}\" is disabled": "«{0}»-pakkebehandleren er skrudd av", + "There is an error with the configuration of the package manager \"{0}\"": "Det er en feil med konfigurasjonen til pakkehåndtereren \"{0}\"", + "The package \"{0}\" was not found on the package manager \"{1}\"": "Pakken \"{0}\" ble ikke funnet hos pakkehåndtereren \"{1}\"", + "{0} is disabled": "{0} er deaktivert", + "{0} weeks": "{0} uker", + "1 month": "1 måned", + "{0} months": "{0} måneder", + "Something went wrong": "Noe gikk galt", + "An interal error occurred. Please view the log for further details.": "En intern feil oppstod. Vennligst se loggen for flere detaljer.", + "No applicable installer was found for the package {0}": "Ingen gjeldende installasjonsprogram ble funnet for pakken {0}", + "Integrity checks will not be performed during this operation": "Integritetssjekker vil ikke bli utført under denne operasjonen", + "This is not recommended.": "Dette anbefales ikke.", + "Run now": "Kjør nå", + "Run next": "Kjør neste", + "Run last": "Kjør sist", + "Show in explorer": "Vis i utforsker", + "Checked": "Avkrysset", + "Unchecked": "Ikke avkrysset", + "This package is already installed": "Denne pakken er allerede installert", + "This package can be upgraded to version {0}": "Denne pakken kan oppgraderes til versjon {0}", + "Updates for this package are ignored": "Oppdateringer for denne pakken er ignorert", + "This package is being processed": "Denne pakken behandles", + "This package is not available": "Denne pakken er ikke tilgjengelig", + "Select the source you want to add:": "Velg kilden du ønsker å legge til:", + "Source name:": "Kildenavn:", + "Source URL:": "Kilde-URL:", + "An error occurred when adding the source: ": "En feil oppstod da kilden ble lagt til:", + "Package management made easy": "Pakkebehandling gjort enkelt", + "version {0}": "versjon {0}", + "[RAN AS ADMINISTRATOR]": "KJØRTE SOM ADMINISTRATOR", + "Portable mode": "Bærbar modus\n", + "DEBUG BUILD": "FEILSØKINGSVERSJON", + "Here you can change UniGetUI's behaviour regarding the following shortcuts. Checking a shortcut will make UniGetUI delete it if if gets created on a future upgrade. Unchecking it will keep the shortcut intact": "Her kan du endre hvordan UniGetUI håndterer følgende snarveier. Hvis en snarvei er avkrysset, vil UniGetUI slette den hvis den opprettes under en fremtidig oppgradering. Hvis den ikke er avkrysset, vil snarveien forbli uendret.", + "Manual scan": "Manuell skanning", + "Existing shortcuts on your desktop will be scanned, and you will need to pick which ones to keep and which ones to remove.": "Eksisterende snarveier på skrivebordet ditt vil bli skannet, og du må velge hvilke du vil beholde og hvilke du vil fjerne.", + "Delete?": "Vil du slette?", + "I understand": "Jeg forstår", + "Chocolatey setup changed": "Chocolatey-oppsettet er endret", + "UniGetUI no longer includes its own private Chocolatey installation. A legacy UniGetUI-managed Chocolatey installation was detected for this user profile, but system Chocolatey was not found. Chocolatey will stay unavailable in UniGetUI until Chocolatey is installed on the system and UniGetUI is restarted. Applications previously installed through UniGetUI's bundled Chocolatey may still appear under other sources such as Local PC or WinGet.": "UniGetUI inkluderer ikke lenger sin egen private Chocolatey-installasjon. En eldre UniGetUI-administrert Chocolatey-installasjon ble oppdaget for denne brukerprofilen, men system-Chocolatey ble ikke funnet. Chocolatey vil forbli utilgjengelig i UniGetUI til Chocolatey er installert på systemet og UniGetUI er startet på nytt. Applikasjoner som tidligere ble installert gjennom UniGetUIs medfølgende Chocolatey kan fortsatt vises under andre kilder som Lokal PC eller WinGet.", + "NOTE: This troubleshooter can be disabled from UniGetUI Settings, on the WinGet section": "MERK: Denne feilsøkeren kan deaktiveres fra UniGetUI-innstillinger, i WinGet-seksjonen", + "Restart": "Omstart", + "Are you sure you want to delete all shortcuts?": "Er du sikker på at du vil slette alle snarveiene?", + "Any new shorcuts created during an install or an update operation will be deleted automatically, instead of showing a confirmation prompt the first time they are detected.": "Nye snarveier som opprettes under en installasjon eller oppdateringsoperasjon vil bli slettet automatisk, i stedet for å vise en bekreftelsesmelding første gang de oppdages.", + "Any shorcuts created or modified outside of UniGetUI will be ignored. You will be able to add them via the {0} button.": "Snarveier opprettet eller endret utenfor UniGetUI blir ignorert. Du vil kunne legge dem til via {0}-knappen.", + "Are you really sure you want to enable this feature?": "Er du virkelig sikker på at du vil aktivere denne funksjonen?", + "No new shortcuts were found during the scan.": "Ingen nye snarveier ble funnet under skanningen.", + "How to add packages to a bundle": "Hvordan legge pakker til i en pakkebundle", + "In order to add packages to a bundle, you will need to: ": "For å legge pakker til i en pakkebundle, må du: ", + "1. Navigate to the \"{0}\" or \"{1}\" page.": "1. Gå til «{0}»- eller «{1}»-siden.", + "2. Locate the package(s) you want to add to the bundle, and select their leftmost checkbox.": "2. Finn pakken(e) du vil legge til i pakkebundlen, og velg avmerkingsboksen lengst til venstre.", + "3. When the packages you want to add to the bundle are selected, find and click the option \"{0}\" on the toolbar.": "3. Når pakkene du vil legge til i pakkebundlen er valgt, finner du og klikker på alternativet \"{0}\" på verktøylinja.", + "4. Your packages will have been added to the bundle. You can continue adding packages, or export the bundle.": "4. Pakkene dine vil ha blitt lagt til i pakkebundlen. Du kan fortsette med å legge til pakker, eller eksportere pakkebundlen.", + "Which backup do you want to open?": "Hvilken sikkerhetskopi vil du åpne?", + "Select the backup you want to open. Later, you will be able to review which packages you want to install.": "Velg sikkerhetskopien du vil åpne. Senere vil du kunne gjennomgå hvilke pakker/programmer du vil gjenopprette.", + "There are ongoing operations. Quitting UniGetUI may cause them to fail. Do you want to continue?": "Det er mange pågående operasjoner. Å avslutte UniGetUI kan føre til at de feiler. Vil du fortsette?", + "UniGetUI or some of its components are missing or corrupt.": "UniGetUI eller noen av komponentene mangler eller er ødelagte.", + "It is strongly recommended to reinstall UniGetUI to adress the situation.": "Det anbefales sterkt å reinstallere UniGetUI for å håndtere situasjonen.", + "Refer to the UniGetUI Logs to get more details regarding the affected file(s)": "Se UniGetUI-loggene for å få mer informasjon om de berørte filene", + "Integrity checks can be disabled from the Experimental Settings": "Integritetssjekker kan deaktiveres fra eksperimentelle innstillinger", + "Repair UniGetUI": "Reparer UniGetUI", + "Live output": "Direkte output", + "This package bundle had some settings that are potentially dangerous, and may be ignored by default.": "Denne pakkebundlen hadde noen innstillinger som potensielt er farlige, og kan være ignorert som standard.", + "Entries that show in YELLOW will be IGNORED.": "Oppføringer som vises i GULT blir IGNORERT.", + "Entries that show in RED will be IMPORTED.": "Oppføringer som vises i RØDT vil bli IMPORTERT.", + "You can change this behavior on UniGetUI security settings.": "Du kan endre denne oppførselen i UniGetUI-sikkerhetsinnstillingene.", + "Open UniGetUI security settings": "Åpne UniGetUI-sikkerhetsinnstillinger", + "Should you modify the security settings, you will need to open the bundle again for the changes to take effect.": "Hvis du endrer sikkerhetsinnstillingene, må du åpne pakkebundlen igjen for at endringene skal tre i kraft.", + "Details of the report:": "Rapportens detaljer:", + "Are you sure you want to create a new package bundle? ": "Er du sikker på at du vil lage en ny pakkebundle?", + "Any unsaved changes will be lost": "Ulagrede endringer vill gå tapt", + "Warning!": "Advarsel!", + "For security reasons, custom command-line arguments are disabled by default. Go to UniGetUI security settings to change this. ": "Av sikkerhetsgrunner er egendefinerte kommandolinjeparametre deaktivert som standard. Gå til UniGetUI-sikkerhetsinnstillingene for å endre dette. ", + "Change default options": "Endre standardalternativene", + "Ignore future updates for this package": "Ignorer fremtidige oppdateringer for denne pakken", + "For security reasons, pre-operation and post-operation scripts are disabled by default. Go to UniGetUI security settings to change this. ": "Av sikkerhetsgrunner er pre-operasjons- og post-operasjonsskript deaktivert som standard. Gå til UniGetUI-sikkerhetsinnstillingene for å endre dette. ", + "You can define the commands that will be run before or after this package is installed, updated or uninstalled. They will be run on a command prompt, so CMD scripts will work here.": "Du kan definere kommandoene som skal kjøres før eller etter at denne pakken blir installert, oppdatert eller avinstallert. De kjøres i en kommandoprompt, slik at CMD-skript fungerer her.", + "Change this and unlock": "Endre dette og lås opp", + "{0} Install options are currently locked because {0} follows the default install options.": "{0} installeringsalternativer er for øyeblikket låst fordi {0} følger standardinstalleringsalternativene.", + "Unset or unknown": "Ikke satt eller ukjent", + "This package has no screenshots or is missing the icon? Contrbute to UniGetUI by adding the missing icons and screenshots to our open, public database.": "Denne pakken har ingen skjermbilder eller mangler et ikon? Bidra til UniGetUI ved å legge til de manglende ikonene og skjermbildene til vår åpne, offentlige database.", + "Become a contributor": "Bli en bidragsyter", + "Update to {0} available": "Oppdatering for {0} er tilgjengelig", + "Reinstall": "Reinstaller", + "Installer not available": "Installerer ikke tilgjengelig", + "Version:": "Versjon:", + "UniGetUI Version {0}": "UniGetUI versjon {0}", + "Performing backup, please wait...": "Utfører sikkerhetskopi, vennligst vent...", + "An error occurred while logging in: ": "En feil oppstod under innlogging: ", + "Fetching available backups...": "Henter tilgjengelige sikkerhetskopier...", + "Done!": "Ferdig!", + "The cloud backup has been loaded successfully.": "Skysikkerhetskopien har blitt lastet inn vellykket.", + "An error occurred while loading a backup: ": "En feil oppstod under lasting av en sikkerhetskopi: ", + "Backing up packages to GitHub Gist...": "Sikkerhetskopierer pakker til GitHub Gist...", + "Backup Successful": "Sikkerhetskopieringen lyktes", + "The cloud backup completed successfully.": "Skysikkerhetskopieringen ble fullført vellykket.", + "Could not back up packages to GitHub Gist: ": "Klarte ikke å sikkerhetskopiere pakker til GitHub Gist: ", + "It is not guaranteed that the provided credentials will be stored safely, so you may as well not use the credentials of your bank account": "Det er ikke garantert at oppgitte legitimasjonsdata blir lagret sikkert, så du bør helst ikke bruke legitimasjonsdata fra bankkontoen din", + "Enable the automatic WinGet troubleshooter": "Aktiver den automatiske WinGet-feilsøkeren", + "Add updates that fail with a 'no applicable update found' to the ignored updates list": "Legg til oppdateringer som mislykkes med \"ingen gjeldende oppdatering funnet\" i listen over ignorerte oppdateringer.", + "Invalid selection": "Ugyldig utvalg", + "No package was selected": "Ingen pakke ble valgt", + "More than 1 package was selected": "Mer enn 1 pakke var valgt", + "List": "Liste", + "Grid": "Rutenett", + "Icons": "Ikoner", + "\"{0}\" is a local package and does not have available details": "«{0}» er en lokal pakke og har ikke tilgjengelige detaljer", + "\"{0}\" is a local package and is not compatible with this feature": "«{0}» er en lokal pakke og støtter ikke denne funksjonen", + "Add packages to bundle": "Legg til pakker i pakkebundle", + "Preparing packages, please wait...": "Forbereder pakker, vennligst vent...", + "Loading packages, please wait...": "Laster pakker, vennligst vent...", + "Saving packages, please wait...": "Lagrer pakker, vennligst vent...", + "The bundle was created successfully on {0}": "Pakkebundlen ble opprettet vellykket på {0}", + "User profile": "Brukerprofil", + "Error": "Feil", + "Log in failed: ": "Innlogging mislyktes:", + "Log out failed: ": "Utlogging mislyktes: ", + "Package backup settings": "Innstillinger for pakkesikkerhetskopi", + "Manage UniGetUI autostart behaviour from the Settings app": "Administrer UniGetUIs autostartoppførsel", + "Choose how many operations shoulds be performed in parallel": "Velg hvor mange handlinger som skal utføres parallelt", + "Something went wrong while launching the updater.": "Noe gikk galt under oppstart av oppdateringsprogrammet.", + "Please try again later": "Vennligst prøv igjen senere", + "Show the release notes after UniGetUI is updated": "Vis utgivelsesnotater etter at UniGetUI er oppdatert" +} diff --git a/src/Languages/lang_nl.json b/src/Languages/lang_nl.json new file mode 100644 index 0000000..2d480ab --- /dev/null +++ b/src/Languages/lang_nl.json @@ -0,0 +1,850 @@ +{ + "{0} of {1} operations completed": "{0} van {1} bewerkingen voltooid", + "{0} is now {1}": "{0} is nu {1}", + "Enabled": "Ingeschakeld", + "Disabled": "Uitgeschakeld", + "Privacy": "Privacy", + "Hide my username from the logs": "Mijn gebruikersnaam verbergen in de logboeken", + "Replaces your username with **** in the logs. Restart UniGetUI to also hide it from already-recorded entries.": "Vervangt uw gebruikersnaam door **** in de logboeken. Start UniGetUI opnieuw om de naam ook te verbergen in reeds vastgelegde vermeldingen.", + "Your last update attempt did not complete.": "Je laatste updatepoging is niet voltooid.", + "UniGetUI could not confirm whether the update succeeded. Open the log to see what happened.": "UniGetUI kon niet bevestigen of de update is gelukt. Open het logboek om te zien wat er is gebeurd.", + "View log": "Logboek weergeven", + "The installer reported success but did not restart UniGetUI.": "Het installatieprogramma meldde succes, maar heeft UniGetUI niet opnieuw gestart.", + "The installer failed to initialize.": "Het installatieprogramma kon niet worden geïnitialiseerd.", + "Setup was canceled before installation began.": "De setup is geannuleerd voordat de installatie begon.", + "A fatal error occurred during the preparation phase.": "Er is een fatale fout opgetreden tijdens de voorbereidingsfase.", + "A fatal error occurred during installation.": "Er is een fatale fout opgetreden tijdens de installatie.", + "Installation was canceled while in progress.": "De installatie is geannuleerd terwijl deze bezig was.", + "The installer was terminated by another process.": "Het installatieprogramma is beëindigd door een ander proces.", + "The preparation phase determined the installation cannot proceed.": "Tijdens de voorbereidingsfase is vastgesteld dat de installatie niet kan doorgaan.", + "The installer could not start. UniGetUI may already be running, or you do not have permission to install.": "Het installatieprogramma kon niet starten. UniGetUI is mogelijk al actief, of je hebt geen toestemming om te installeren.", + "Unexpected installer error.": "Onverwachte fout in het installatieprogramma.", + "We are checking for updates.": "Controleren op updates.", + "Please wait": "Even geduld", + "Great! You are on the latest version.": "Geweldig! Je zit op de meest recente versie.", + "There are no new UniGetUI versions to be installed": "Er is geen nieuwe UniGetUI-versie om te installeren", + "UniGetUI version {0} is being downloaded.": "UniGetUI versie {0} wordt gedownload.", + "This may take a minute or two": "Dit kan 1-2 minuten duren", + "The installer authenticity could not be verified.": "De authenticiteit van het installatieprogramma kon niet worden geverifieerd.", + "The update process has been aborted.": "Het updateproces is afgebroken.", + "Auto-update is not yet available on this platform.": "Automatisch bijwerken is nog niet beschikbaar op dit platform.", + "Please update UniGetUI manually.": "Werk UniGetUI handmatig bij.", + "An error occurred when checking for updates: ": "Er is een fout opgetreden bij het controleren op updates:", + "The updater could not be launched.": "Het updateprogramma kon niet worden gestart.", + "The operating system did not start the installer process.": "Het besturingssysteem heeft het installatieproces niet gestart.", + "UniGetUI is being updated...": "UniGetUI wordt bijgewerkt...", + "Update installed.": "Update geïnstalleerd.", + "UniGetUI was updated successfully, but this running copy was not replaced. This usually means you are running a development build. Close this copy and start the newly-installed version to finish.": "UniGetUI is met succes bijgewerkt, maar deze actieve kopie is niet vervangen. Dit betekent meestal dat je een ontwikkelbuild gebruikt. Sluit deze kopie en start de nieuw geïnstalleerde versie om af te ronden.", + "The update could not be applied.": "De update kon niet worden toegepast.", + "Installer exit code {0}: {1}": "Afsluitcode van installatieprogramma {0}: {1}", + "Update cancelled.": "Update geannuleerd.", + "Authentication was cancelled.": "Authenticatie is geannuleerd.", + "Installer exit code {0}": "Afsluitcode van installatieprogramma {0}", + "Operation in progress": "Bewerking aan de gang", + "Please wait...": "Even geduld…", + "Success!": "Succes!", + "Failed": "Mislukt", + "An error occurred while processing this package": "Er is een fout opgetreden bij de verwerking van dit pakket", + "Installer": "Installatieprogramma", + "Executable": "Uitvoerbaar bestand", + "MSI": "MSI", + "Compressed file": "Gecomprimeerd bestand", + "MSIX": "MSIX", + "WinGet was repaired successfully": "WinGet is met succes gerepareerd", + "It is recommended to restart UniGetUI after WinGet has been repaired": "Het is raadzaam om UniGetUI opnieuw op te starten nadat WinGet is gerepareerd", + "WinGet could not be repaired": "WinGet kan niet worden gerepareerd", + "An unexpected issue occurred while attempting to repair WinGet. Please try again later": "Er is een onverwacht probleem opgetreden bij het repareren van WinGet. Probeer het later opnieuw", + "Log in to enable cloud backup": "Log in om cloud back-up in te schakelen", + "Backup Failed": "Back-up mislukt", + "Downloading backup...": "Back-up downloaden...", + "An update was found!": "Er is een update gevonden!", + "{0} can be updated to version {1}": "{0} kan worden bijgewerkt naar versie {1}", + "Updates found!": "Updates gevonden!", + "{0} packages can be updated": "{0} pakketten kunnen worden bijgewerkt", + "{0} is being updated to version {1}": "{0} wordt bijgewerkt naar versie {1}", + "{0} packages are being updated": "{0} pakketten worden bijgewerkt", + "You have currently version {0} installed": "Je hebt momenteel versie {0} geïnstalleerd", + "Desktop shortcut created": "Desktopsnelkoppeling aangemaakt", + "UniGetUI has detected a new desktop shortcut that can be deleted automatically.": "UniGetUI heeft een nieuwe bureaubladsnelkoppeling gedetecteerd die automatisch kan worden verwijderd.", + "{0} desktop shortcuts created": "{0} bureaubladsnelkoppelingen aangemaakt", + "UniGetUI has detected {0} new desktop shortcuts that can be deleted automatically.": "UniGetUI heeft {0} nieuwe bureaubladsnelkoppelingen gedetecteerd die automatisch kunnen worden verwijderd.", + "Attention required": "Aandacht vereist", + "Restart required": "Opnieuw starten vereist", + "1 update is available": "1 update beschikbaar", + "{0} updates are available": "Er zijn {0} updates beschikbaar", + "Everything is up to date": "Alles is bijgewerkt", + "Discover Packages": "Pakketten ontdekken", + "Available Updates": "Beschikbare updates", + "Installed Packages": "Pakketten op dit systeem", + "UniGetUI Version {0} by Devolutions": "UniGetUI versie {0} door Devolutions", + "Show UniGetUI": "UniGetUI openen", + "Quit": "Afsluiten", + "Are you sure?": "Weet je het zeker?", + "Do you really want to uninstall {0}?": "Wil je {0} echt verwijderen?", + "Do you really want to uninstall the following {0} packages?": "Wil je de volgende {0} pakketten verwijderen?", + "No": "Nee", + "Yes": "Ja", + "Partial": "Gedeeltelijk", + "View on UniGetUI": "Weergeven op UniGetUI", + "Update": "Bijwerken", + "Open UniGetUI": "UniGetUI openen", + "Update all": "Alles bijwerken", + "Update now": "Nu bijwerken", + "Installer host changed since the installed version.\n": "Host van het installatieprogramma is gewijzigd sinds de geïnstalleerde versie.\n", + "This package is on the queue": "Dit pakket staat in de wachtrij", + "installing": "installeren", + "updating": "bijwerken", + "uninstalling": "verwijderen", + "installed": "geïnstalleerd", + "Retry": "Opnieuw proberen", + "Install": "Installeren", + "Uninstall": "Verwijderen", + "Open": "Openen", + "Operation profile:": "Bewerkingsprofiel:", + "Follow the default options when installing, upgrading or uninstalling this package": "Standaardopties aanhouden bij het installeren, upgraden of verwijderen van dit pakket", + "The following settings will be applied each time this package is installed, updated or removed.": "De volgende instellingen worden toegepast telkens wanneer dit pakket wordt geïnstalleerd, bijgewerkt of verwijderd.", + "Version to install:": "Te installeren versie:", + "Architecture to install:": "Te installeren architectuur:", + "Installation scope:": "Installatiebereik:", + "Install location:": "Installatielocatie:", + "Select": "Selecteren", + "Reset": "Opnieuw instellen", + "Custom install arguments:": "Aangepaste installatie-argumenten:", + "Custom update arguments:": "Aangepaste bijwerkings-argumenten:", + "Custom uninstall arguments:": "Aangepaste verwijderings-argumenten:", + "Pre-install command:": "Pre-installatie opdracht:", + "Post-install command:": "Post-installatie opdracht:", + "Abort install if pre-install command fails": "Installatie afbreken als pre-installatie opdracht mislukt", + "Pre-update command:": "Pre-update opdracht:", + "Post-update command:": "Post-update opdracht:", + "Abort update if pre-update command fails": "Update afbreken als pre-update opdracht mislukt", + "Pre-uninstall command:": "Pre-verwijderings opdracht:", + "Post-uninstall command:": "Post-verwijderings opdracht:", + "Abort uninstall if pre-uninstall command fails": "Verwijdering afbreken als pre-verwijder opdracht mislukt", + "Command-line to run:": "Te gebruiken opdrachtregel:", + "Save and close": "Opslaan en sluiten", + "General": "Algemeen", + "Architecture & Location": "Architectuur en locatie", + "Command-line": "Opdrachtregel", + "Close apps": "Apps sluiten", + "Pre/Post install": "Voor/na installatie", + "Select the processes that should be closed before this package is installed, updated or uninstalled.": "Selecteer welke programma's gesloten moeten worden voordat dit pakket wordt geïnstalleerd, geüpdatet of verwijderd.", + "Write here the process names here, separated by commas (,)": "Schrijf de programma-namen hier, gescheiden door komma's (,)", + "Try to kill the processes that refuse to close when requested to": "Probeer programma's te beëindigen als ze weigeren te sluiten op verzoek", + "Run as admin": "Als administrator uitvoeren", + "Interactive installation": "Interactieve installatie", + "Skip hash check": "Hashcontrole overslaan", + "Uninstall previous versions when updated": "Oude versies verwijderen bij het updaten", + "Skip minor updates for this package": "Kleine updates voor dit pakket overslaan", + "Automatically update this package": "Dit pakket automatisch updaten", + "{0} installation options": "{0} installatieopties", + "Latest": "Meest recent", + "PreRelease": "Pre-release", + "Default": "Standaard", + "Manage ignored updates": "Genegeerde updates beheren", + "The packages listed here won't be taken in account when checking for updates. Double-click them or click the button on their right to stop ignoring their updates.": "De hier vermelde pakketten worden niet in aanmerking genomen bij het controleren op updates. Dubbelklik erop of klik op de knop aan de rechterkant om te stoppen met het negeren van hun updates.", + "Reset list": "Lijst opnieuw instellen", + "Do you really want to reset the ignored updates list? This action cannot be reverted": "Wil je de lijst met genegeerde updates echt opnieuw instellen? Deze actie kan niet worden teruggedraaid", + "No ignored updates": "Geen genegeerde updates", + "Package Name": "Pakketnaam", + "Package ID": "Pakket-ID", + "Ignored version": "Genegeerde versie", + "New version": "Nieuwe versie", + "Source": "Bron", + "All versions": "Alle versies", + "Unknown": "Onbekend", + "Up to date": "Bijgewerkt", + "Package {name} from {manager}": "Pakket {name} van {manager}", + "Remove {0} from ignored updates": "{0} verwijderen uit genegeerde updates", + "Cancel": "Annuleren", + "Administrator privileges": "Administratorrechten", + "This operation is running with administrator privileges.": "Deze bewerking wordt uitgevoerd met administratorrechten.", + "Interactive operation": "Interactieve bewerking", + "This operation is running interactively.": "Deze bewerking wordt interactief uitgevoerd.", + "You will likely need to interact with the installer.": "Je zult waarschijnlijk moeten communiceren met het installatieprogramma.", + "Integrity checks skipped": "Integriteitscontroles overgeslagen", + "Integrity checks will not be performed during this operation.": "Tijdens deze bewerking worden geen integriteitscontroles uitgevoerd.", + "Proceed at your own risk.": "Doorgaan op eigen risico.", + "Close": "Sluiten", + "Loading...": "Laden…", + "Installer SHA256": "Installatieprogramma-SHA256", + "Homepage": "Website", + "Author": "Auteur", + "Publisher": "Uitgever", + "License": "Licentie", + "Manifest": "Manifest", + "Installer Type": "Type installatieprogramma", + "Size": "Grootte", + "Installer URL": "Installatieprogramma URL", + "Last updated:": "Laatst bijgewerkt:", + "Release notes URL": "Release-opmerkingen URL", + "Package details": "Pakketdetails", + "Dependencies:": "Afhankelijkheden:", + "Release notes": "Release-opmerkingen", + "Screenshots": "Schermafbeeldingen", + "This package has no screenshots or is missing the icon? Contribute to UniGetUI by adding the missing icons and screenshots to our open, public database.": "Dit pakket heeft geen schermafbeeldingen of mist het pictogram? Draag bij aan UniGetUI door de ontbrekende pictogrammen en schermafbeeldingen toe te voegen aan onze open, openbare database.", + "Version": "Versie", + "Install as administrator": "Als administrator installeren", + "Update to version {0}": "Bijwerken naar versie {0}", + "Installed Version": "Geïnstalleerde versie", + "Update as administrator": "Als administrator bijwerken", + "Interactive update": "Interactief bijwerken", + "Uninstall as administrator": "Als administrator verwijderen", + "Interactive uninstall": "Interactief verwijderen", + "Uninstall and remove data": "Verwijderen, incl. gegevens", + "Not available": "Niet beschikbaar", + "Installer SHA512": "Installatieprogramma-SHA512", + "Unknown size": "Onbekende grootte", + "No dependencies specified": "Geen afhankelijkheden gespecificeerd", + "mandatory": "verplicht", + "optional": "optioneel", + "UniGetUI {0} is ready to be installed.": "UniGetUI {0} is klaar om geïnstalleerd te worden.", + "The update process will start after closing UniGetUI": "Het updateproces start na het sluiten van UniGetUI", + "UniGetUI has been ran as administrator, which is not recommended. When running UniGetUI as administrator, EVERY operation launched from UniGetUI will have administrator privileges. You can still use the program, but we highly recommend not running UniGetUI with administrator privileges.": "UniGetUI is als administrator uitgevoerd, wat niet wordt aanbevolen. Wanneer UniGetUI als administrator wordt uitgevoerd, krijgt ELKE vanuit UniGetUI gestarte bewerking administratorrechten. Je kunt het programma nog steeds gebruiken, maar we raden sterk af om UniGetUI met administratorrechten uit te voeren.", + "Share anonymous usage data": "Anonieme gebruiksgegevens delen", + "UniGetUI collects anonymous usage data in order to improve the user experience.": "UniGetUI verzamelt anonieme gebruiksgegevens om de gebruikerservaring te verbeteren.", + "Accept": "Accepteren", + "Software Updates": "Software-updates", + "Package Bundles": "Pakkettenbundels", + "Settings": "Instellingen", + "Package Managers": "Pakketbeheerders", + "UniGetUI Log": "UniGetUI-logboek", + "Package Manager logs": "Pakketbeheerder-logboeken", + "Operation history": "Bewerkingsgeschiedenis", + "Help": "Hulp (Engels)", + "UniGetUI": "UniGetUI", + "You have installed UniGetUI Version {0}": "Je hebt UniGetUI versie {0} geïnstalleerd", + "Disclaimer": "Clausule", + "UniGetUI is developed by Devolutions and is not affiliated with any of the compatible package managers.": "UniGetUI is ontwikkeld door Devolutions en is niet verbonden aan een van de compatibele pakketbeheerders.", + "UniGetUI wouldn't have been possible without the help of the contributors. Thank you all 🥳": "UniGetUI zou niet mogelijk zijn geweest zonder de bijdragen van deze personen. \nBedankt allemaal 🥳", + "UniGetUI uses the following libraries. Without them, UniGetUI wouldn't have been possible.": "UniGetUI maakt gebruik van de volgende bibliotheken, zonder welke UniGetUI niet mogelijk zou zijn geweest.", + "{0} homepage": "{0} website", + "UniGetUI has been translated to more than 40 languages thanks to the volunteer translators. Thank you 🤝": "UniGetUI is dankzij deze vrijwilligers in meer dan 40 talen vertaald. Hartelijk bedankt 🤝", + "Verbose": "Uitvoerig", + "1 - Errors": "1 - Fouten", + "2 - Warnings": "2 - Waarschuwingen", + "3 - Information (less)": "3 - Informatie (beperkt)", + "4 - Information (more)": "4 - Informatie (meer)", + "5 - information (debug)": "5 - Informatie (foutopsporing)", + "Warning": "Waarschuwing", + "The following settings may pose a security risk, hence they are disabled by default.": "De volgende instellingen kunnen een veiligheidsrisico met zich meebrengen. Hierom zijn ze standaard uitgeschakeld.", + "Enable the settings below if and only if you fully understand what they do, and the implications they may have.": "Schakel de onderstaande instellingen ENKEL EN ALLEEN in als je volledig begrijpt wat ze doen, en wat voor gevolgen en gevaren ze met zich meebrengen.", + "The settings will list, in their descriptions, the potential security issues they may have.": "De instellingen zullen in hun omschrijving mogelijke veiligheidsproblemen weergeven.", + "The backup will include the complete list of the installed packages and their installation options. Ignored updates and skipped versions will also be saved.": "De back-up bevat de volledige lijst met geïnstalleerde pakketten en hun installatieopties. Ook genegeerde updates en overgeslagen versies worden opgeslagen.", + "The backup will NOT include any binary file nor any program's saved data.": "De back-up bevat GEEN binair bestand en ook geen opgeslagen gegevens van een programma.", + "The size of the backup is estimated to be less than 1MB.": "De grootte van de back-up wordt geschat op minder dan 1 MB", + "The backup will be performed after login.": "De back-up wordt uitgevoerd na het inloggen.", + "{pcName} installed packages": "{pcName} geïnstalleerde pakketten", + "Current status: Not logged in": "Huidige status: Niet ingelogd", + "You are logged in as {0} (@{1})": "Je bent ingelogd als {0} (@{1})", + "Nice! Backups will be uploaded to a private gist on your account": "Mooi! Back-ups zullen als een privé Gist op je account worden geüpload", + "Select backup": "Back-up selecteren", + "Settings imported from {0}": "Instellingen geïmporteerd uit {0}", + "UniGetUI Settings": "UniGetUI-instellingen", + "Settings exported to {0}": "Instellingen geëxporteerd naar {0}", + "UniGetUI settings were reset": "UniGetUI-instellingen zijn opnieuw ingesteld", + "Allow pre-release versions": "Pre-release versies toestaan", + "Apply": "Toepassen", + "For security reasons, custom command-line arguments are disabled by default. Go to UniGetUI security settings to change this.": "Om veiligheidsredenen zijn aangepaste opdrachtregelargumenten standaard uitgeschakeld. Ga naar de beveiligingsinstellingen van UniGetUI om dit te wijzigen.", + "Go to UniGetUI security settings": "Ga naar UniGetUI veiligheidsinstellingen", + "The following options will be applied by default each time a {0} package is installed, upgraded or uninstalled.": "De volgende opties zullen standaard worden toegepast wanneer een {0} pakket wordt geïnstalleerd, geüpdatet of verwijderd.", + "Package's default": "Standaard van het pakket", + "Install location can't be changed for {0} packages": "Installatielocatie kan voor {0} pakketten niet worden gewijzigd", + "The local icon cache currently takes {0} MB": "Het lokale pictogram-buffer gebruikt momenteel {0} MB", + "Username": "Gebruikersnaam", + "Password": "Wachtwoord", + "Credentials": "Referenties", + "It is not guaranteed that the provided credentials will be stored safely": "Het is niet gegarandeerd dat de opgegeven referenties veilig worden opgeslagen", + "Partially": "Gedeeltelijk", + "Package manager": "Pakketbeheerder", + "Compatible with proxy": "Compatibel met proxy", + "Compatible with authentication": "Compatibel met authenticatie", + "Proxy compatibility table": "Proxy compatibiliteitstabel", + "{0} settings": "{0} instellingen", + "{0} status": "{0}-status", + "Default installation options for {0} packages": "Standaard installatie-opties voor {0} pakketten", + "Expand version": "Uitgebreide versie-informatie", + "The executable file for {0} was not found": "Het uitvoerbare bestand voor {0} is niet gevonden", + "{pm} is disabled": "{pm} is uitgeschakeld", + "Enable it to install packages from {pm}.": "Schakel het in om pakketten van {pm} te installeren.", + "{pm} is enabled and ready to go": "{pm} is ingeschakeld en klaar voor gebruik", + "{pm} version:": "{pm} versie:", + "{pm} was not found!": "{pm} niet aangetroffen!", + "You may need to install {pm} in order to use it with UniGetUI.": "Mogelijk moet je {pm} installeren om het met UniGetUI te kunnen gebruiken.", + "Scoop Installer - UniGetUI": "Scoop installatie - UniGetUI", + "Scoop Uninstaller - UniGetUI": "Scoop verwijderen - UniGetUI", + "Clearing Scoop cache - UniGetUI": "Scoop-buffer wissen - UniGetUI", + "Restart UniGetUI to fully apply changes": "Start UniGetUI opnieuw om de wijzigingen volledig toe te passen", + "Restart UniGetUI": "UniGetUI opnieuw starten", + "Manage {0} sources": "{0}-bronnen beheren", + "Add source": "Bron toevoegen", + "Add": "Toevoegen", + "Source name": "Bronnaam", + "Source URL": "Bron-URL", + "Other": "Overig", + "No minimum age": "Geen minimale leeftijd", + "1 day": "1 dag", + "{0} days": "{0} dagen", + "Custom...": "Aangepast...", + "{0} minutes": "{0} minuten", + "1 hour": "1 uur", + "{0} hours": "{0} uur", + "1 week": "1 week", + "Supports release dates": "Ondersteunt releasedatums", + "Release date support per package manager": "Ondersteuning voor releasedatums per pakketbeheerder", + "Search for packages": "Pakketten zoeken", + "Local": "Lokaal", + "OK": "OK", + "Last checked: {0}": "Laatst gecontroleerd: {0}", + "{0} packages were found, {1} of which match the specified filters.": "Er zijn {0} pakketten gevonden, waarvan {1} overeenkomen met de opgegeven filters.", + "{0} selected": "{0} geselecteerd", + "(Last checked: {0})": "(Laatste controle: {0})", + "All packages selected": "Alle pakketten geselecteerd", + "Package selection cleared": "Pakketselectie gewist", + "{0}: {1}": "{0}: {1}", + "More info": "Meer informatie", + "GitHub account": "GitHub-account", + "Log in with GitHub to enable cloud package backup.": "Log in bij GitHub om cloud pakket back-ups in te schakelen.", + "More details": "Meer details", + "Log in": "Inloggen", + "If you have cloud backup enabled, it will be saved as a GitHub Gist on this account": "Als je cloud back-up hebt ingeschakeld, wordt deze opgeslagen als een GitHub Gist op dit account", + "Log out": "Uitloggen", + "About UniGetUI": "Over UniGetUI", + "About": "Over", + "Third-party licenses": "Licenties van derden", + "Contributors": "Bijdragen", + "Translators": "Vertalingen", + "Bundle security report": "Veiligheidsrapportage bundelen", + "The bundle contained restricted content": "De bundel bevatte beperkte inhoud", + "UniGetUI – Crash Report": "UniGetUI – Crashrapport", + "UniGetUI has crashed": "UniGetUI is gecrasht", + "Help us fix this by sending a crash report to Devolutions. All fields below are optional.": "Help ons dit te verhelpen door een crashrapport naar Devolutions te sturen. Alle onderstaande velden zijn optioneel.", + "Email (optional)": "E-mail (optioneel)", + "your@email.com": "jouw@e-mail.com", + "Additional details (optional)": "Aanvullende details (optioneel)", + "Describe what you were doing when the crash occurred…": "Beschrijf wat je aan het doen was toen de crash optrad…", + "Crash report": "Crashrapport", + "Don't Send": "Niet verzenden", + "Send Report": "Rapport verzenden", + "Sending…": "Verzenden…", + "Unsaved changes": "Niet-opgeslagen wijzigingen", + "You have unsaved changes in the current bundle. Do you want to discard them?": "Je hebt niet-opgeslagen wijzigingen in de huidige bundel. Wil je die verwerpen?", + "Discard changes": "Wijzigingen verwerpen", + "Integrity violation": "Integriteitsschending", + "UniGetUI or some of its components are missing or corrupt. It is strongly recommended to reinstall UniGetUI to adress the situation.": "UniGetUI of sommige onderdelen ervan ontbreken of zijn beschadigd. Het wordt sterk aanbevolen om UniGetUI opnieuw te installeren om dit probleem op te lossen.", + "• Refer to the UniGetUI Logs to get more details regarding the affected file(s)": "• Raadpleeg de UniGetUI logboeken voor meer details met betrekking tot de getroffen bestand(en)", + "• Integrity checks can be disabled from the Experimental Settings": "• Integriteitscontroles kunnen worden uitgeschakeld via de experimentele instellingen", + "Manage shortcuts": "Snelkoppelingen beheren", + "UniGetUI has detected the following desktop shortcuts which can be removed automatically on future upgrades": "UniGetUI heeft de volgende snelkoppelingen op het bureaublad gedetecteerd die bij toekomstige upgrades automatisch kunnen worden verwijderd", + "Do you really want to reset this list? This action cannot be reverted.": "Wil je deze lijst echt opnieuw instellen? Deze actie kan niet worden teruggedraaid.", + "Desktop shortcuts list": "Lijst bureaubladsnelkoppelingen", + "Open in explorer": "Openen in Verkenner", + "Remove from list": "Van lijst wissen", + "When new shortcuts are detected, delete them automatically instead of showing this dialog.": "Nieuwe snelkoppelingen bij detectie automatisch verwijderen worden gedetecteerd, in plaats van dit dialoogvenster te tonen.", + "Not right now": "Nu even niet", + "Missing dependency": "Ontbrekende afhankelijkheid", + "UniGetUI requires {0} to operate, but it was not found on your system.": "UniGetUI heeft {0} nodig om te functioneren, maar het werd niet aangetroffen op het systeem.", + "Click on Install to begin the installation process. If you skip the installation, UniGetUI may not work as expected.": "Klik op Installeren om het installatieproces te starten. Als je de installatie overslaat, werkt UniGetUI mogelijk niet zoals verwacht.", + "Alternatively, you can also install {0} by running the following command in a Windows PowerShell prompt:": "Als alternatief kunt je ook {0} installeren door de volgende opdracht uit te voeren in een Windows PowerShell-opdrachtregel:", + "Install {0}": "{0} installeren", + "Do not show this dialog again for {0}": "Dit dialoogvenster niet meer weergeven voor {0}", + "Please wait while {0} is being installed. A black window may show up. Please wait until it closes.": "Even geduld terwijl {0} wordt geïnstalleerd. Er kan een zwart venster verschijnen. Wacht tot het sluit.", + "{0} has been installed successfully.": "{0} is met succes geïnstalleerd.", + "Please click on \"Continue\" to continue": "Klik op \"Doorgaan\" om door te gaan", + "Continue": "Doorgaan", + "{0} has been installed successfully. It is recommended to restart UniGetUI to finish the installation": "{0} is met succes geïnstalleerd. Het wordt aangeraden om UniGetUI opnieuw op te starten om de installatie te voltooien", + "Restart later": "Later opnieuw starten", + "An error occurred:": "Er is een fout opgetreden:", + "Please see the Command-line Output or refer to the Operation History for further information about the issue.": "Raadpleeg de opdrachtregeluitvoer of raadpleeg de Bewerkingsgeschiedenis voor meer informatie over het probleem.", + "Retry as administrator": "Opnieuw proberen als administrator", + "Retry interactively": "Interactief opnieuw proberen", + "Retry skipping integrity checks": "Opnieuw proberen zonder integriteitscontroles", + "Installation options": "Installatieopties", + "Save": "Opslaan", + "UniGetUI collects anonymous usage data with the sole purpose of understanding and improving the user experience.": "UniGetUI verzamelt anonieme gebruiksgegevens met als enig doel inzicht te verkrijgen in de gebruikerservaring en deze te verbeteren.", + "More details about the shared data and how it will be processed": "Meer informatie over de gedeelde gegevens en hoe deze worden verwerkt", + "Do you accept that UniGetUI collects and sends anonymous usage statistics, with the sole purpose of understanding and improving the user experience?": "Ga je ermee akkoord dat UniGetUI anonieme gebruiksstatistieken verzamelt en verzendt, met als enig doel inzicht te krijgen op de gebruikerservaring en deze te verbeteren?", + "Decline": "Afwijzen", + "No personal information is collected nor sent, and the collected data is anonimized, so it can't be back-tracked to you.": "Er wordt geen persoonlijke informatie verzameld of verzonden en de verzamelde gegevens worden geanonimiseerd, zodat deze niet naar jou kunnen worden teruggevoerd.", + "Navigation panel": "Navigatiepaneel", + "Operations": "Bewerkingen", + "Toggle operations panel": "Bewerkingenpaneel in-/uitschakelen", + "Bulk operations": "Bulkbewerkingen", + "Retry failed": "Mislukte opnieuw proberen", + "Clear successful": "Geslaagde wissen", + "Clear finished": "Voltooide wissen", + "Cancel all": "Alles annuleren", + "More": "Meer", + "Toggle navigation panel": "Navigatiepaneel wisselen", + "Minimize": "Minimaliseren", + "Maximize": "Maximaliseren", + "UniGetUI by Devolutions": "UniGetUI door Devolutions", + "UniGetUI is an application that makes managing your software easier, by providing an all-in-one graphical interface for your command-line package managers.": "UniGetUI is een applicatie die het beheer van jouw software eenvoudiger maakt door een alles-in-één grafische interface te bieden voor je opdrachtregelpakketbeheerders.", + "Useful links": "Nuttige links", + "UniGetUI Homepage": "UniGetUI-homepage", + "Report an issue or submit a feature request": "Een probleem melden of een functieverzoek indienen", + "UniGetUI Repository": "UniGetUI-repository", + "View GitHub Profile": "GitHub-profiel bekijken", + "UniGetUI License": "UniGetUI-licentie", + "Using UniGetUI implies the acceptation of the MIT License": "Met het gebruik van UniGetUI ga je akkoord met de MIT-licentie", + "Become a translator": "Meld je aan als vertaler", + "Go back": "Ga terug", + "Go forward": "Ga vooruit", + "Go to home page": "Ga naar startpagina", + "Reload page": "Pagina vernieuwen", + "View page on browser": "Pagina in browser bekijken", + "The built-in browser is not supported on Linux yet.": "De ingebouwde browser wordt nog niet ondersteund op Linux.", + "Open in browser": "Openen in browser", + "Copy to clipboard": "Naar klembord kopiëren", + "Export to a file": "Exporteren naar bestand", + "Log level:": "Logboek-niveau", + "Reload log": "Logboek opnieuw laden", + "Export log": "Logboek exporteren", + "Text": "Tekst", + "Change how operations request administrator rights": "Wijzigen hoe bewerkingen administratorrechten aanvragen", + "Restrictions on package operations": "Beperkingen op pakketbewerkingen", + "Restrictions on package managers": "Beperkingen op pakketbeheerders", + "Restrictions when importing package bundles": "Beperkingen bij het importeren van pakketbundels", + "Ask for administrator privileges once for each batch of operations": "Vraag één keer om administratorrechten voor elke reeks bewerkingen", + "Ask only once for administrator privileges": "Maar één keer om administratorrechten vragen", + "Prohibit any kind of Elevation via UniGetUI Elevator or GSudo": "Elke vorm van rechtenverheffing met UniGetUI Elevator of GSudo verbieden", + "This option WILL cause issues. Any operation incapable of elevating itself WILL FAIL. Install/update/uninstall as administrator will NOT WORK.": "Deze optie ZAL problemen veroorzaken. Elke handeling die zichzelf niet kan verheffen ZAL MISLUKKEN. Installeren/bijwerken/verwijderen als administrator zal NIET WERKEN.", + "Allow custom command-line arguments": "Aangepaste opdrachtregelargumenten toestaan", + "Custom command-line arguments can change the way in which programs are installed, upgraded or uninstalled, in a way UniGetUI cannot control. Using custom command-lines can break packages. Proceed with caution.": "Aangepaste opdrachtregelargumenten kunnen de manier veranderen waarop programma's worden geïnstalleerd, bijgewerkt of verwijderd, op een manier die UniGetUI niet kan controleren. Het gebruik van aangepaste opdrachtregels kan pakketten breken. Ga voorzichtig te werk.", + "Ignore custom pre-install and post-install commands when importing packages from a bundle": "Negeer aangepaste pre-installatie- en post-installatieopdrachten bij het importeren van pakketten uit een bundel", + "Pre and post install commands will be run before and after a package gets installed, upgraded or uninstalled. Be aware that they may break things unless used carefully": "Installatieopdrachten worden uitgevoerd vóór of nadat een pakket wordt geïnstalleerd, geüpgraded of verwijderd. Houd er rekening mee dat ze dingen kunnen breken, tenzij ze zorgvuldig worden gebruikt", + "Allow changing the paths for package manager executables": "Het wijzigen van paden van pakketbeheerders toestaan", + "Turning this on enables changing the executable file used to interact with package managers. While this allows finer-grained customization of your install processes, it may also be dangerous": "Het inschakelen van deze instelling staat het wijzigen van het uivoeringsbestand wat gebruikt wordt bij interacties met pakketbeheerders toe. Hoewel dit nauwkeurigere aanpassing van je installatie-proces toestaat, kan dit ook gevaren met zich meebrengen.", + "Allow importing custom command-line arguments when importing packages from a bundle": "Het importeren van aangepaste opdrachtregelargumenten toestaan bij het importeren van pakketten uit een bundel", + "Malformed command-line arguments can break packages, or even allow a malicious actor to gain privileged execution. Therefore, importing custom command-line arguments is disabled by default": "Misvormde opdrachtregelargumenten kunnen pakketten breken of zelfs een kwaadwillende actor in staat stellen een bevoorrechte uitvoering te krijgen. Daarom is het importeren van aangepaste opdrachtregelargumenten standaard uitgeschakeld.", + "Allow importing custom pre-install and post-install commands when importing packages from a bundle": "Het importeren van aangepaste pre-installatie- en post-installatieopdrachten toestaan bij het importeren van pakketten uit een bundel", + "Pre and post install commands can do very nasty things to your device, if designed to do so. It can be very dangerous to import the commands from a bundle, unless you trust the source of that package bundle": "Opdrachten vóór en na de installatie kunnen zeer vervelende dingen doen met je apparaat, als ze daarvoor zijn ontworpen. Het kan erg gevaarlijk zijn om de opdrachten uit een bundel te importeren, tenzij je de bron van die pakketbundel vertrouwt", + "Administrator rights and other dangerous settings": "Administratorrechten en andere risicovolle instellingen", + "Package backup": "Back-up van pakket", + "Cloud package backup": "Cloud pakket back-up", + "Local package backup": "Lokale pakket back-up", + "Local backup advanced options": "Lokale back-up geavanceerde opties", + "Log in with GitHub": "Log in met GitHub", + "Log out from GitHub": "Uitloggen van GitHub", + "Periodically perform a cloud backup of the installed packages": "Regelmatig een cloud back-up uitvoeren van de geïnstalleerde pakketten", + "Cloud backup uses a private GitHub Gist to store a list of installed packages": "Cloud back-up gebruikt een privé GitHub Gist om een lijst met geïnstalleerde pakketten op te slaan", + "Perform a cloud backup now": "Nu een cloud back-up uitvoeren", + "Backup": "Back-up", + "Restore a backup from the cloud": "Herstel een back-up van de cloud", + "Begin the process to select a cloud backup and review which packages to restore": "Start het proces om een Cloud back-up te selecteren en controleer welke pakketen hersteld moeten worden", + "Periodically perform a local backup of the installed packages": "Regelmatig een lokale back-up uitvoeren van de geïnstalleerde pakketten", + "Perform a local backup now": "Nu een lokale back-up uitvoeren", + "Change backup output directory": "De uitvoermap voor back-upbestanden wijzigen", + "Set a custom backup file name": "Een aangepaste naam voor een back-upbestand instellen", + "Leave empty for default": "Leeg laten voor standaard", + "Add a timestamp to the backup file names": "Voeg een tijdstempel toe aan de namen van de back-upbestanden", + "Backup and Restore": "Back-up en Herstel", + "Enable background api (UniGetUI Widgets and Sharing, port 7058)": "Achtergrond-API inschakelen (UniGetUI Widgets en Delen, poort 7058)", + "Wait for the device to be connected to the internet before attempting to do tasks that require internet connectivity.": "Taken die een internetverbinding verlangen uitstellen totdat het apparaat met internet is verbonden.", + "Disable the 1-minute timeout for package-related operations": "Time-out van 1 minuut voor pakketgerelateerde bewerkingen uitschakelen", + "Use installed GSudo instead of UniGetUI Elevator": "Geïnstalleerde GSudio gebruiken in plaats van UniGetUI Elevator", + "Use a custom icon and screenshot database URL": "Aangepast pictogram en schermopname database-URL gebruiken", + "Enable background CPU Usage optimizations (see Pull Request #3278)": "Optimalisaties van CPU-gebruik op de achtergrond inschakelen (zie Pull Request #3278)", + "Perform integrity checks at startup": "Integriteitscontroles uitvoeren bij het opstarten", + "When batch installing packages from a bundle, install also packages that are already installed": "Bij het reeksgewijs installeren van pakketten van een bundel, installeer ook pakketten die al geïnstalleerd zijn", + "Experimental settings and developer options": "Experimentele instellingen en ontwikkelaarsopties", + "Show UniGetUI's version and build number on the titlebar.": "UniGetUI's versie en bouwnummer in de titelbalk weergeven.", + "Language": "Taal", + "UniGetUI updater": "UniGetUI-updater", + "Telemetry": "Telemetrie", + "Manage UniGetUI settings": "UniGetUI-instellingen beheren", + "Related settings": "Gerelateerde instellingen", + "Update UniGetUI automatically": "UniGetUI automatisch bijwerken", + "Check for updates": "Controleren op updates", + "Install prerelease versions of UniGetUI": "Prerelease-versies van UniGetUI installeren", + "Manage telemetry settings": "Telemetrie-instellingen beheren", + "Manage": "Beheren", + "Import settings from a local file": "Instellingen importeren vanuit een lokaal bestand", + "Import": "Importeren", + "Export settings to a local file": "Instellingen exporteren naar een lokaal bestand", + "Export": "Exporteren", + "Reset UniGetUI": "UniGetUI opnieuw instellen", + "User interface preferences": "Voorkeuren gebruikersinterface", + "Application theme, startup page, package icons, clear successful installs automatically": "App-thema, startpagina, pakketpictogrammen, succesvolle installaties automatisch wissen", + "General preferences": "Algemene voorkeuren", + "UniGetUI display language:": "UniGetUI weergavetaal:", + "System language": "Systeemtaal", + "Is your language missing or incomplete?": "Ontbreekt jouw taal of is deze onjuist of incompleet?", + "Appearance": "Uiterlijk", + "UniGetUI on the background and system tray": "UniGetUI op de achtergrond en het systeemvak", + "Package lists": "Pakketlijsten", + "Use classic mode": "Klassieke modus gebruiken", + "Restart UniGetUI to apply this change": "Start UniGetUI opnieuw om deze wijziging toe te passen", + "The classic UI is disabled for beta testers": "De klassieke gebruikersinterface is uitgeschakeld voor bètatesters", + "Close UniGetUI to the system tray": "UniGetUI sluiten naar het systeemvak", + "Manage UniGetUI autostart behaviour": "Automatisch starten van UniGetUI beheren", + "Show package icons on package lists": "Pakketpictogrammen weergeven in pakketlijsten", + "Clear cache": "Buffer wissen", + "Select upgradable packages by default": "Standaard upgradebare pakketten selecteren", + "Light": "Licht", + "Dark": "Donker", + "Follow system color scheme": "Volg systeem kleur schema", + "Application theme:": "App-thema:", + "UniGetUI startup page:": "UniGetUI startpagina:", + "Proxy settings": "Proxy-instellingen", + "Other settings": "Overige instellingen", + "Connect the internet using a custom proxy": "Internetverbinding met behulp van een aangepaste proxy", + "Please note that not all package managers may fully support this feature": "Houd er rekening mee dat niet alle pakketbeheerders deze functie volledig ondersteunen", + "Proxy URL": "Proxy-url", + "Enter proxy URL here": "Voer hier de proxy-URL in", + "Authenticate to the proxy with a user and a password": "Bij de proxy verifiëren met een gebruikersnaam en wachtwoord", + "Internet and proxy settings": "Internet- en proxy-instellingen", + "Package manager preferences": "Voorkeuren voor Pakketbeheerders", + "Ready": "Klaar", + "Not found": "Niet gevonden", + "Notification preferences": "Meldingsvoorkeuren", + "Notification types": "Typen meldingen", + "The system tray icon must be enabled in order for notifications to work": "Het systeemvakpictogram moet ingeschakeld zijn om meldingen te laten werken", + "Enable UniGetUI notifications": "Meldingen van UniGetUI inschakelen", + "Show a notification when there are available updates": "Toon een melding wanneer updates beschikbaar zijn", + "Show a silent notification when an operation is running": "Toon een stille melding wanneer een bewerking wordt uitgevoerd", + "Show a notification when an operation fails": "Toon een melding wanneer een bewerking mislukt", + "Show a notification when an operation finishes successfully": "Toon een melding wanneer een bewerking met succes is voltooid", + "Concurrency and execution": "Gelijktijdigheid en uitvoering", + "Automatic desktop shortcut remover": "Bureaubladsnelkoppelingen automatisch verwijderen", + "Choose how many operations should be performed in parallel": "Kies hoeveel bewerkingen parallel moeten worden uitgevoerd", + "Clear successful operations from the operation list after a 5 second delay": "Geslaagde bewerkingen na 5 seconden uit de bewerkingslijst wissen", + "Download operations are not affected by this setting": "Download-handelingen worden niet beïnvloed door deze instelling", + "You may lose unsaved data": "Je kunt mogelijk niet-opgeslagen gegevens verliezen", + "Ask to delete desktop shortcuts created during an install or upgrade.": "Vragen om snelkoppelingen te verwijderen die op het bureaublad zijn aangemaakt tijdens een installatie or upgrade.", + "Package update preferences": "Voorkeuren voor pakketupdates", + "Update check frequency, automatically install updates, etc.": "Frequentie van update-controles, automatisch nieuwe versies installeren, enz.", + "Reduce UAC prompts, elevate installations by default, unlock certain dangerous features, etc.": "UAC-prompts verminderen, installaties standaard verheffen, bepaalde risicovolle functies ontgrendelen, etc.", + "Package operation preferences": "Voorkeuren voor pakketbewerkingen", + "Enable {pm}": "{pm} inschakelen", + "Not finding the file you are looking for? Make sure it has been added to path.": "Kun j het bestand dat je zoekt niet vinden? Zorg ervoor dat het aan pad is toegevoegd.", + "Select the executable to be used. The following list shows the executables found by UniGetUI": "Selecteer het uitvoerbare bestand dat gebruikt moet worden. De volgende lijst toont de uitvoerbare bestanden die door UniGetUI zijn gevonden.", + "For security reasons, changing the executable file is disabled by default": "Om veiligheidsredenen is het wijzigen van het uitvoeringsbestand standaard uitgeschakeld", + "Change this": "Dit aanpassen", + "Copy path": "Pad kopiëren", + "Current executable file:": "Huidig uitvoerbaar bestand:", + "Ignore packages from {pm} when showing a notification about updates": "Pakketten van {pm} negeren bij het tonen van een melding over updates", + "Update security": "Updatebeveiliging", + "Use global setting": "Globale instelling gebruiken", + "Minimum age for updates": "Minimale leeftijd voor updates", + "e.g. 10": "bijv. 10", + "Custom minimum age (days)": "Aangepaste minimale leeftijd (dagen)", + "{pm} does not provide release dates for its packages, so this setting will have no effect": "{pm} levert geen releasedatums voor zijn pakketten, dus deze instelling heeft geen effect", + "{pm} only provides release dates for some of its packages, so this setting will only apply to those packages": "{pm} biedt alleen voor sommige van zijn pakketten releasedatums, dus deze instelling is alleen van toepassing op die pakketten", + "Override the global minimum update age for this package manager": "Overschrijf de globale minimale updateleeftijd voor deze pakketbeheerder", + "View {0} logs": "{0} logboeken bekijken", + "If Python cannot be found or is not listing packages but is installed on the system, ": "Als Python niet kan worden gevonden of geen pakketten weergeeft terwijl het wel op het systeem is geïnstalleerd, ", + "Advanced options": "Geavanceerde opties", + "WinGet command-line tool": "WinGet-opdrachtregelhulpprogramma", + "Choose which command-line tool UniGetUI uses for WinGet operations when the COM API is not used": "Kies welk opdrachtregelhulpprogramma UniGetUI gebruikt voor WinGet-bewerkingen wanneer de COM API niet wordt gebruikt", + "WinGet COM API": "WinGet COM API", + "Choose whether UniGetUI can use the WinGet COM API before falling back to the command-line tool": "Kies of UniGetUI de WinGet COM API mag gebruiken voordat wordt teruggevallen op het opdrachtregelhulpprogramma", + "Reset WinGet": "WinGet opnieuw instellen", + "This may help if no packages are listed": "Dit kan helpen als er geen pakketten worden vermeld", + "Force install location parameter when updating packages with custom locations": "Forceer de installatielocatieparameter bij het bijwerken van pakketten met aangepaste locaties", + "Install Scoop": "Scoop installeren", + "Uninstall Scoop (and its packages)": "Scoop (en de pakketten) verwijderen", + "Run cleanup and clear cache": "Opruiming uitvoeren en cache wissen", + "Run": "Uitvoeren", + "Enable Scoop cleanup on launch": "Scoop opschonen inschakelen bij de start", + "Default vcpkg triplet": "Standaard vcpk tripel", + "Change vcpkg root location": "vcpkg-hoofdlocatie wijzigen", + "Reset vcpkg root location": "Vcpkg-hoofdlocatie opnieuw instellen", + "Open vcpkg root location": "Vcpkg-hoofdlocatie openen", + "Language, theme and other miscellaneous preferences": "Taal, thema en andere diverse voorkeuren", + "Show notifications on different events": "Meldingen tonen over verschillende gebeurtenissen", + "Change how UniGetUI checks and installs available updates for your packages": "Wijzig hoe UniGetUI beschikbare updates voor jouw pakketten controleert en installeert", + "Automatically save a list of all your installed packages to easily restore them.": "Automatisch een lijst opslaan van al je geïnstalleerde pakketten om ze gemakkelijk te herstellen.", + "Enable and disable package managers, change default install options, etc.": "Pakketbeheerder in- of uitschakelen, standaardopties wijzigen, etc.", + "Internet connection settings": "Instellingen voor internetverbinding", + "Proxy settings, etc.": "Proxy-instellingen, enz.", + "Beta features and other options that shouldn't be touched": "Bètafuncties en andere opties die je beter niet kan gebruiken", + "Reload sources": "Bronnen vernieuwen", + "Delete source": "Bron verwijderen", + "Known sources": "Bekende bronnen", + "Update checking": "Controle op updates", + "Automatic updates": "Automatische updates", + "Check for package updates periodically": "Regelmatig controleren op pakketupdates", + "Check for updates every:": "Controleren op updates, elke:", + "Install available updates automatically": "Beschikbare updates automatisch installeren", + "Do not automatically install updates when the network connection is metered": "Geen automatisch updates installeren wanneer bij betaalde netwerkverbinding", + "Do not automatically install updates when the device runs on battery": "Installeer geen updates automatisch wanneer het apparaat op de batterij werkt", + "Do not automatically install updates when the battery saver is on": "Niet automatisch updates installeren wanneer de batterijbeveiliging is ingeschakeld", + "Only show updates that are at least the specified number of days old": "Toon alleen updates die minstens het opgegeven aantal dagen oud zijn", + "Warn me when the installer URL host changes between the installed version and the new version (WinGet only)": "Waarschuw me wanneer de host van de URL van het installatieprogramma verandert tussen de geïnstalleerde versie en de nieuwe versie (alleen WinGet)", + "Change how UniGetUI handles install, update and uninstall operations.": "Wijzigen hoe UniGetUI de installatie-, update- en verwijderingsbewerkingen afhandelt.", + "Navigation": "Navigatie", + "Check for UniGetUI updates": "Controleren op UniGetUI-updates", + "Quit UniGetUI": "UniGetUI afsluiten", + "Filters": "Filters", + "Sources": "Bronnen", + "Search for packages to start": "Zoek om te beginnen naar pakketten", + "Select all": "Alles selecteren", + "Clear selection": "Selectie opheffen", + "Instant search": "Direct zoeken", + "Distinguish between uppercase and lowercase": "Hoofdlettergevoelig", + "Ignore special characters": "Speciale tekens negeren", + "Search mode": "Zoekmodus", + "Both": "Beide", + "Exact match": "Exacte overeenkomst", + "Show similar packages": "Vergelijkbaar pakket tonen", + "Loading": "Laden", + "Package": "Pakket", + "More options": "Meer opties", + "Order by:": "Sortering:", + "Name": "Naam", + "Id": "ID", + "Ascendant": "Voorouder", + "Descendant": "Nakomeling", + "View modes": "Weergavemodi", + "Reload": "Vernieuwen", + "Closed": "Gesloten", + "Ascending": "Oplopend", + "Descending": "Aflopend", + "{0}: {1}, {2}": "{0}: {1}, {2}", + "Order by": "Sorteren op", + "No results were found matching the input criteria": "Er zijn geen resultaten gevonden die voldoen aan de invoercriteria", + "No packages were found": "Er zijn geen pakketten gevonden", + "Loading packages": "Pakketten laden", + "Skip integrity checks": "Integriteitscontroles overslaan", + "Download selected installers": "Geselecteerde installatieprogramma's downloaden", + "Install selection": "Selectie installeren", + "Install options": "Installatie-opties", + "Add selection to bundle": "Selectie toevoegen aan bundel", + "Download installer": "Installatieprogramma downloaden", + "Uninstall selection": "Selectie verwijderen", + "Uninstall options": "Verwijderingsopties", + "Ignore selected packages": "Geselecteerde pakketten negeren", + "Open install location": "Installatiemap openen", + "Reinstall package": "Pakket opnieuw installeren", + "Uninstall package, then reinstall it": "Verwijder het pakket en installeer het opnieuw", + "Ignore updates for this package": "Updates voor dit pakket negeren", + "WinGet malfunction detected": "WinGet-storing gedetecteerd", + "It looks like WinGet is not working properly. Do you want to attempt to repair WinGet?": "Het lijkt erop dat WinGet niet goed functioneert. Wil je proberen dit te repareren?", + "Repair WinGet": "WinGet repareren", + "Updates will no longer be ignored for {0}": "Updates worden niet langer genegeerd voor {0}", + "Updates are now ignored for {0}": "Updates worden nu genegeerd voor {0}", + "Do not ignore updates for this package anymore": "Updates voor dit pakket niet langer negeren", + "Add packages or open an existing package bundle": "Voeg pakketten toe of open een bestaande pakketbundel", + "Add packages to start": "Voeg pakketten toe om te starten", + "The current bundle has no packages. Add some packages to get started": "De huidige bundel heeft geen pakketten. Voeg wat pakketten toe om te beginnen", + "New": "Nieuw", + "Save as": "Opslaan als", + "Create .ps1 script": ".ps1-script aanmaken", + "Remove selection from bundle": "Selectie verwijderen van bundel", + "Skip hash checks": "Hashcontroles overslaan", + "The package bundle is not valid": "De pakketbundel is niet geldig", + "The bundle you are trying to load appears to be invalid. Please check the file and try again.": "De bundel die je probeert te laden, lijkt ongeldig. Controleer het bestand en probeer het opnieuw.", + "Package bundle": "Pakkettenbundel", + "Could not create bundle": "Kan bundel niet aanmaken", + "The package bundle could not be created due to an error.": "De pakketbundel kan vanwege een fout niet worden angemaakt.", + "Install script": "installatiescript", + "PowerShell script": "PowerShell-script", + "The installation script saved to {0}": "Het installatiescript is opgeslagen op {0}", + "An error occurred": "Er is een fout opgetreden", + "An error occurred while attempting to create an installation script:": "Er is een fout opgetreden bij het aanmaken van een installatiescript:", + "Hooray! No updates were found.": "Top! Alles is bijgewerkt!", + "Uninstall selected packages": "Geselecteerde pakketten verwijderen", + "Update selection": "Selectie bijwerken", + "Update options": "Update-opties", + "Uninstall package, then update it": "Pakket verwijderen en daarna bijwerken", + "Uninstall package": "Pakket verwijderen", + "Skip this version": "Deze versie overslaan", + "Pause updates for": "Updates pauzeren voor", + "User | Local": "Gebruiker | Lokaal", + "Machine | Global": "Computer | Globaal", + "The default package manager for Debian/Ubuntu-based Linux distributions.
Contains: Debian/Ubuntu packages": "De standaardpakketbeheerder voor Debian/Ubuntu-gebaseerde Linux-distributies.
Bevat: Debian/Ubuntu-pakketten", + "The Rust package manager.
Contains: Rust libraries and programs written in Rust": "De Rust-pakketbeheerder.
Bevat: Rust-bibliotheken en programma's geschreven in Rust", + "The classical package manager for windows. You'll find everything there.
Contains: General Software": "De klassieke Windows pakketbeheerder. Hier kun je van alles vinden.
Bevat: Algemene software", + "The default package manager for RHEL/Fedora-based Linux distributions.
Contains: RPM packages": "De standaardpakketbeheerder voor RHEL/Fedora-gebaseerde Linux-distributies.
Bevat: RPM-pakketten", + "A repository full of tools and executables designed with Microsoft's .NET ecosystem in mind.
Contains: .NET related tools and scripts": "Een opslagplaats vol hulpmiddelen en uitvoerbare bestanden ontworpen voor het .NET-ecosysteem van Microsoft.
Bevat: .NET-gerelateerde hulpmiddelen en scripts", + "The universal Linux package manager for desktop applications.
Contains: Flatpak applications from configured remotes": "De universele Linux-pakketbeheerder voor desktoptoepassingen.
Bevat: Flatpak-applicaties van geconfigureerde remotes", + "NuPkg (zipped manifest)": "NuPkg (gezipte manifest)", + "The Missing Package Manager for macOS (or Linux).
Contains: Formulae, Casks": "De ontbrekende pakketbeheerder voor macOS (of Linux).
Bevat: Formulae, Casks", + "Node JS's package manager. Full of libraries and other utilities that orbit the javascript world
Contains: Node javascript libraries and other related utilities": "Node JS pakketbeheer. Vol met bibliotheken en andere hulpprogramma's die rond de javascript-wereld draaien
Bevat: Node javascript-bibliotheken en andere gerelateerde hulpprogramma's", + "The default package manager for Arch Linux and its derivatives.
Contains: Arch Linux packages": "De standaardpakketbeheerder voor Arch Linux en afgeleide distributies.
Bevat: Arch Linux-pakketten", + "Python's library manager. Full of python libraries and other python-related utilities
Contains: Python libraries and related utilities": "Python bibliotheekbeheer. Vol met python-bibliotheken en andere python-gerelateerde hulpprogramma's
Bevat: Python-bibliotheken en gerelateerde hulpprogramma's", + "PowerShell's package manager. Find libraries and scripts to expand PowerShell capabilities
Contains: Modules, Scripts, Cmdlets": "De pakketbeheerder van PowerShell. Bibliotheken en scripts zoeken om de PowerShell-mogelijkheden uit te breiden
Bevat: Modules, Scripts, Cmdlets", + "extracted": "uitgepakt", + "Scoop package": "Scoop-pakket", + "Great repository of unknown but useful utilities and other interesting packages.
Contains: Utilities, Command-line programs, General Software (extras bucket required)": "Geweldige opslagplaats van onbekende maar nuttige hulpprogramma's en andere interessante pakketten.
Bevat: Hulpprogramma's, opdrachtregelprogramma's, algemene software (vereist extra bucket)", + "The universal Linux package manager by Canonical.
Contains: Snap packages from the Snapcraft store": "De universele Linux-pakketbeheerder van Canonical.
Bevat: Snap-pakketten uit de Snapcraft-winkel", + "library": "bibliotheek", + "feature": "functie", + "A popular C/C++ library manager. Full of C/C++ libraries and other C/C++-related utilities
Contains: C/C++ libraries and related utilities": "Een populaire C/C++ bibliotheekmanager. Vol met C/C++-bibliotheken en andere C/C++-gerelateerde hulpprogramma's
Bevat: C/C++-bibliotheken en gerelateerde hulpprogramma's", + "option": "optie", + "This package cannot be installed from an elevated context.": "Dit pakket kan niet vanuit een verhoogde context worden geïnstalleerd.", + "Please run UniGetUI as a regular user and try again.": "Voer UniGetUI uit als gewone gebruiker en probeer het opnieuw.", + "Please check the installation options for this package and try again": "Controleer de installatie-opties voor dit pakket en probeer het opnieuw", + "Microsoft's official package manager. Full of well-known and verified packages
Contains: General Software, Microsoft Store apps": "Officiële pakketbeheerder van Microsoft. Vol met bekende en geverifieerde pakketten
Bevat: Algemene software, Microsoft Store-apps", + "Local PC": "Lokale PC", + "Android Subsystem": "Andoid Subsysteem", + "Operation on queue (position {0})...": "Bewerking in de wachtrij (positie {0})", + "Click here for more details": "Klik hier voor meer details", + "Operation canceled by user": "Bewerking geannuleerd door gebruiker", + "Running PreOperation ({0}/{1})...": "PreOperation uitvoeren ({0}/{1})...", + "PreOperation {0} out of {1} failed, and was tagged as necessary. Aborting...": "PreOperation {0} van {1} is mislukt en is als noodzakelijk gemarkeerd. Afbreken...", + "PreOperation {0} out of {1} finished with result {2}": "PreOperation {0} van {1} is voltooid met resultaat {2}", + "Starting operation...": "Bewerking starten...", + "Running PostOperation ({0}/{1})...": "PostOperation uitvoeren ({0}/{1})...", + "PostOperation {0} out of {1} failed, and was tagged as necessary. Aborting...": "PostOperation {0} van {1} is mislukt en is als noodzakelijk gemarkeerd. Afbreken...", + "PostOperation {0} out of {1} finished with result {2}": "PostOperation {0} van {1} is voltooid met resultaat {2}", + "{package} installer download": "Installatieprogramma voor {package} downloaden", + "{0} installer is being downloaded": "Installatieprogramma voor {0} wordt gedownload", + "Download succeeded": "Download voltooid", + "{package} installer was downloaded successfully": "Installatieprogramma voor {package} is met succes gedownload", + "Download failed": "Download mislukt", + "{package} installer could not be downloaded": "Installatieprogramma voor {package} kon niet worden gedownload", + "{package} Installation": "{package} installeren", + "{0} is being installed": "{0} wordt geïnstalleerd", + "Installation succeeded": "Installatie voltooid", + "{package} was installed successfully": "{package} is met succes geïnstalleerd", + "Installation failed": "Installatie mislukt", + "{package} could not be installed": "{package} kan niet worden geïnstalleerd", + "{package} Update": "{package} bijwerken", + "Update succeeded": "Update voltooid", + "{package} was updated successfully": "{package} is met succes bijgewerkt", + "Update failed": "Update mislukt", + "{package} could not be updated": "{package} kan niet worden bijgewerkt", + "{package} Uninstall": "{package} verwijderen", + "{0} is being uninstalled": "{0} wordt verwijderd", + "Uninstall succeeded": "Verwijderen voltooid", + "{package} was uninstalled successfully": "{package} is met succes verwijderd", + "Uninstall failed": "Verwijderen mislukt", + "{package} could not be uninstalled": "{package} kan niet worden verwijderd", + "Adding source {source}": "Bron toevoegen {source}", + "Adding source {source} to {manager}": "Bron {source} toevoegen aan {manager}", + "Source added successfully": "Bron met succes toegevoegd", + "The source {source} was added to {manager} successfully": "De bron {source} is met succes toegevoegd aan {manager}", + "Could not add source": "Kan bron niet toevoegen", + "Could not add source {source} to {manager}": "Kan bron {source} niet toevoegen aan {manager}", + "Removing source {source}": "Bron verwijderen {source}", + "Removing source {source} from {manager}": "Bron {source} verwijderen uit {manager}", + "Source removed successfully": "Bron met succes verwijderd", + "The source {source} was removed from {manager} successfully": "De bron {source} is met succes verwijderd van {manager}", + "Could not remove source": "Kan bron niet verwijderen", + "Could not remove source {source} from {manager}": "Kan bron {source} niet verwijderen uit {manager}", + "The package manager \"{0}\" was not found": "De pakketbeheerder \"{0}\" is niet aangetroffen", + "The package manager \"{0}\" is disabled": "Pakketbeheerder \"{0}\" is uitgeschakeld", + "There is an error with the configuration of the package manager \"{0}\"": "Er is een fout opgetreden bij de configuratie van pakketbeheerder \"{0}\"", + "The package \"{0}\" was not found on the package manager \"{1}\"": "Het pakket \"{0}\" is niet aangetroffen in pakketbeheerder \"{1}\"", + "{0} is disabled": "{0} is uitgeschakeld", + "{0} weeks": "{0} weken", + "1 month": "1 maand", + "{0} months": "{0} maanden", + "Something went wrong": "Er gings iets mis", + "An interal error occurred. Please view the log for further details.": "Er is een interne fout opgetreden. Bekijk het logboek voor meer informatie.", + "No applicable installer was found for the package {0}": "Geen installatieprogramma gevonden voor het pakket {0}", + "Integrity checks will not be performed during this operation": "Tijdens deze bewerking worden geen integriteitscontroles uitgevoerd", + "This is not recommended.": "Dit wordt afgeraden.", + "Run now": "Nu uitvoeren", + "Run next": "Volgende uitvoeren", + "Run last": "Laatste uitvoeren", + "Show in explorer": "In Verkenner weergeven", + "Checked": "Aangevinkt", + "Unchecked": "Niet aangevinkt", + "This package is already installed": "Dit pakket is al geïnstalleerd", + "This package can be upgraded to version {0}": "Dit pakket kan worden bijgewerkt naar versie {0}", + "Updates for this package are ignored": "Updates voor dit pakket worden genegeerd", + "This package is being processed": "Dit pakket wordt verwerkt", + "This package is not available": "Dit pakket is niet beschikbaar", + "Select the source you want to add:": "Selecteer de bron die je wilt toevoegen:", + "Source name:": "Naam van bron:", + "Source URL:": "Bron-URL:", + "An error occurred when adding the source: ": "Er is een fout opgetreden bij het toevoegen van de bron:", + "Package management made easy": "Pakketbeheer eenvoudig gemaakt", + "version {0}": "versie {0}", + "[RAN AS ADMINISTRATOR]": "[UITGEVOERD ALS ADMINISTRATOR]", + "Portable mode": "Portable modus\n", + "DEBUG BUILD": "TESTVERSIE", + "Here you can change UniGetUI's behaviour regarding the following shortcuts. Checking a shortcut will make UniGetUI delete it if if gets created on a future upgrade. Unchecking it will keep the shortcut intact": "Hier kun je het gedrag van UniGetUI met betrekking tot de volgende snelkoppelingen veranderen. Als je een snelkoppeling aanvinkt, wordt deze door UniGetUI verwijderd als deze bij een toekomstige upgrade wordt aangemaakt. Als je dit niet aanvinkt, blijft de snelkoppeling intact", + "Manual scan": "Handmatig scannen", + "Existing shortcuts on your desktop will be scanned, and you will need to pick which ones to keep and which ones to remove.": "Bestaande snelkoppelingen op je bureaublad worden gescand en je moet kiezen welke je wilt bewaren en welke je wilt verwijderen.", + "Delete?": "Verwijderen?", + "I understand": "Ik begrijp het", + "Chocolatey setup changed": "Chocolatey-configuratie gewijzigd", + "UniGetUI no longer includes its own private Chocolatey installation. A legacy UniGetUI-managed Chocolatey installation was detected for this user profile, but system Chocolatey was not found. Chocolatey will stay unavailable in UniGetUI until Chocolatey is installed on the system and UniGetUI is restarted. Applications previously installed through UniGetUI's bundled Chocolatey may still appear under other sources such as Local PC or WinGet.": "UniGetUI bevat niet langer een eigen privé Chocolatey-installatie. Er is een verouderde, door UniGetUI beheerde Chocolatey-installatie gedetecteerd voor dit gebruikersprofiel, maar Chocolatey is niet op het systeem gevonden. Chocolatey blijft onbeschikbaar in UniGetUI totdat Chocolatey op het systeem is geïnstalleerd en UniGetUI opnieuw wordt gestart. Applicaties die eerder via de meegeleverde Chocolatey van UniGetUI zijn geïnstalleerd, kunnen nog steeds verschijnen onder andere bronnen zoals Lokale PC of WinGet.", + "NOTE: This troubleshooter can be disabled from UniGetUI Settings, on the WinGet section": "OPMERKING: Deze probleemoplosser kan worden uitgeschakeld via UniGetUI instellingen - Pakketbeheerders - WinGet", + "Restart": "Opnieuw starten", + "Are you sure you want to delete all shortcuts?": "Weet je zeker dat je alle snelkoppelingen wilt verwijderen?", + "Any new shorcuts created during an install or an update operation will be deleted automatically, instead of showing a confirmation prompt the first time they are detected.": "Nieuwe snelkoppelingen die tijdens een installatie of een updatebewerking worden aangemaakt, worden automatisch verwijderd, in plaats van een bevestigingsprompt te tonen als ze voor het eerst worden gedetecteerd.", + "Any shorcuts created or modified outside of UniGetUI will be ignored. You will be able to add them via the {0} button.": "Snelkoppelingen die buiten UniGetUI om zijn aangemaakt of gewijzigd, worden genegeerd. Je kunt ze toevoegen via de knop {0}.", + "Are you really sure you want to enable this feature?": "Weet je echt zeker dat je deze functie wilt inschakelen?", + "No new shortcuts were found during the scan.": "Tijdens de scan zijn geen nieuwe snelkoppelingen gevonden.", + "How to add packages to a bundle": "Pakketten toevoegen aan een bundel", + "In order to add packages to a bundle, you will need to: ": "Om pakketten aan een bundel toe te voegen, moet je:", + "1. Navigate to the \"{0}\" or \"{1}\" page.": "1. Navigeer naar de pagina \"{0}\" of \"{1}\".", + "2. Locate the package(s) you want to add to the bundle, and select their leftmost checkbox.": "2. Zoek de pakket(en) die je aan de bundel wilt toevoegen, en selecteer hun meest linkse selectievakje.", + "3. When the packages you want to add to the bundle are selected, find and click the option \"{0}\" on the toolbar.": "3. Als je de pakketten die je aan de bundel wilt toevoegen hebt geselecteerd, klik dan op de optie \"{0}\" op de werkbalk.", + "4. Your packages will have been added to the bundle. You can continue adding packages, or export the bundle.": "4. De pakketten zijn dan aan de bundel zijn toegevoegd. Je kunt doorgaan met het toevoegen van pakketten of de bundel exporteren.", + "Which backup do you want to open?": "Welke back-up wil je openen?", + "Select the backup you want to open. Later, you will be able to review which packages you want to install.": "Selecteer welke back-up je wilt openen. Later kun je ook bepalen welke pakketten/programma's je wilt herstellen.", + "There are ongoing operations. Quitting UniGetUI may cause them to fail. Do you want to continue?": "Er zijn lopende bewerkingen. Als je UniGetUI afsluit, kunnen deze mislukken. Wil je doorgaan?", + "UniGetUI or some of its components are missing or corrupt.": "UniGetUI of componenten ervan ontbreken of zijn beschadigd.", + "It is strongly recommended to reinstall UniGetUI to adress the situation.": "Het wordt sterk aanbevolen om UniGetUI opnieuw te installeren om de situatie aan te pakken.", + "Refer to the UniGetUI Logs to get more details regarding the affected file(s)": "Raadpleeg de UniGetUI logboeken voor meer details met betrekking tot de getroffen bestand(en)", + "Integrity checks can be disabled from the Experimental Settings": "Integriteitscontroles kunnen worden uitgeschakeld via de experimentele instellingen", + "Repair UniGetUI": "UniGetUI repareren", + "Live output": "Live-uitvoer", + "This package bundle had some settings that are potentially dangerous, and may be ignored by default.": "Deze pakketbundel had een aantal instellingen die mogelijk gevaarlijk zijn, en worden mogelijk standaard genegeerd.", + "Entries that show in YELLOW will be IGNORED.": "GELE items worden GENEGEERD.", + "Entries that show in RED will be IMPORTED.": "RODE items worden GEÏMPORTEERD.", + "You can change this behavior on UniGetUI security settings.": "Je kunt dit gedrag wijzigen op UniGetUI veiligheidsinstellingen.", + "Open UniGetUI security settings": "UniGetUI veiligheidsinstellingen openen", + "Should you modify the security settings, you will need to open the bundle again for the changes to take effect.": "Als je de veiligheidsinstellingen wijzigt, zul je de bundel opnieuw moeten openen om de wijzigingen door te voeren.", + "Details of the report:": "Details van het rapport:", + "Are you sure you want to create a new package bundle? ": "Weet je zeker dat je een nieuwe pakketbundel wilt aanmaken?", + "Any unsaved changes will be lost": "Niet-opgeslagen wijzigingen gaan verloren", + "Warning!": "Waarschuwing!", + "For security reasons, custom command-line arguments are disabled by default. Go to UniGetUI security settings to change this. ": "Om veiligheidsredenen zijn aangepaste opdrachtregelargumenten standaard uitgeschakeld. Ga naar UniGetUI veiligheidsinstellingen om dit te wijzigen.", + "Change default options": "Standaardopties aanpassen", + "Ignore future updates for this package": "Toekomstige updates voor dit pakket negeren", + "For security reasons, pre-operation and post-operation scripts are disabled by default. Go to UniGetUI security settings to change this. ": "Om veiligheidsredenen zijn pre-bewerking en post-bewerking scripts standaard uitgeschakeld. Ga naar UniGetUI veiligheidsinstellingen om dit te wijzigen.", + "You can define the commands that will be run before or after this package is installed, updated or uninstalled. They will be run on a command prompt, so CMD scripts will work here.": "Je kunt de opdrachten die voor het installeren, updaten of verwijderen van dit pakket worden uitgevoerd bepalen. Deze worden op een opdrachtregel uitgevoerd, dus CMD-scripts zullen hier werken.", + "Change this and unlock": "Dit aanpassen en ontgrendelen", + "{0} Install options are currently locked because {0} follows the default install options.": "{0} Installatie-opties zijn op dit moment vergrendeld omdat {0} de standaard installatie-opties gebruikt.", + "Unset or unknown": "Onbepaald of onbekend", + "This package has no screenshots or is missing the icon? Contrbute to UniGetUI by adding the missing icons and screenshots to our open, public database.": "Heeft dit pakket geen schermopnames of pictogram? Draag bij aan UniGetUI door ontbrekende pictogrammen en schermopnames toe te voegen aan onze openbare database.", + "Become a contributor": "Lever een bijdrage", + "Update to {0} available": "Update naar {0} beschikbaar", + "Reinstall": "Opnieuw installeren", + "Installer not available": "Installatieprogramma niet beschikbaar", + "Version:": "Versie:", + "UniGetUI Version {0}": "UniGetUI-versie {0}", + "Performing backup, please wait...": "Back-up uitvoeren, even geduld…", + "An error occurred while logging in: ": "Er is een fout opgetreden bij het inloggen:", + "Fetching available backups...": "Beschikbare back-ups ophalen...", + "Done!": "Klaar!", + "The cloud backup has been loaded successfully.": "De cloud back-up is succesvol geladen.", + "An error occurred while loading a backup: ": "Er is een fout opgetreden bij het laden van een back-up:", + "Backing up packages to GitHub Gist...": "Back-up van pakketten maken op GitHub Gist...", + "Backup Successful": "Back-up voltooid", + "The cloud backup completed successfully.": "De cloud back-up is succesvol voltooid.", + "Could not back up packages to GitHub Gist: ": "Kon geen back-up van pakketten maken op GitHub Gist:", + "It is not guaranteed that the provided credentials will be stored safely, so you may as well not use the credentials of your bank account": "Er is geen garantie dat de verstrekte inloggegevens veilig worden opgeslagen, dus de inloggegevens van je bankrekening moest je maar niet gebruiken", + "Enable the automatic WinGet troubleshooter": "Automatische WinGet-probleemoplosser inschakelen", + "Add updates that fail with a 'no applicable update found' to the ignored updates list": "Voeg updates die mislukken met 'geen toepasselijke update gevonden' toe aan de lijst met genegeerde updates.", + "Invalid selection": "Ongeldige selectie", + "No package was selected": "Er is geen pakket geselecteerd", + "More than 1 package was selected": "Er is meer dan 1 pakket geselecteerd", + "List": "Lijst", + "Grid": "Raster", + "Icons": "Pictogrammen", + "\"{0}\" is a local package and does not have available details": "\"{0}\" is een lokaal pakket en heeft geen beschikbare details", + "\"{0}\" is a local package and is not compatible with this feature": "\"{0}\" is een lokaal pakket en is niet compatibel met deze functie", + "Add packages to bundle": "Pakketten toevoegen aan bundel", + "Preparing packages, please wait...": "Pakketten voorbereiden, even geduld…", + "Loading packages, please wait...": "Pakketten laden, even geduld…", + "Saving packages, please wait...": "Pakketten opslaan, even geduld…", + "The bundle was created successfully on {0}": "De bundel is met succes gemaakt op {0}", + "User profile": "Gebruikersprofiel", + "Error": "Foutmeldingen", + "Log in failed: ": "Inloggen mislukt:", + "Log out failed: ": "Uitloggen mislukt:", + "Package backup settings": "Back-up instellingen van het pakket", + "Manage UniGetUI autostart behaviour from the Settings app": "Automatisch opstartgedrag van UniGetUI beheren", + "Choose how many operations shoulds be performed in parallel": "Kies hoeveel bewerkingen parallel moeten worden uitgevoerd", + "Something went wrong while launching the updater.": "Er ging iets mis bij het starten van de updater.", + "Please try again later": "Probeer het later nog eens", + "Show the release notes after UniGetUI is updated": "Toon de release-opmerkingen nadat UniGetUI is bijgewerkt" +} diff --git a/src/Languages/lang_nn.json b/src/Languages/lang_nn.json new file mode 100644 index 0000000..e22a40f --- /dev/null +++ b/src/Languages/lang_nn.json @@ -0,0 +1,850 @@ +{ + "{0} of {1} operations completed": "{0} av {1} operasjonar fullførte", + "{0} is now {1}": "{0} er no {1}", + "Enabled": "Aktivert", + "Disabled": "Deaktivert", + "Privacy": "Personvern", + "Hide my username from the logs": "Skjul brukarnamnet mitt frå loggane", + "Replaces your username with **** in the logs. Restart UniGetUI to also hide it from already-recorded entries.": "Erstattar brukarnamnet ditt med **** i loggane. Start UniGetUI på nytt for å òg skjula det i allereie registrerte oppføringar.", + "Your last update attempt did not complete.": "Det siste forsøket ditt på å oppdatere vart ikkje fullført.", + "UniGetUI could not confirm whether the update succeeded. Open the log to see what happened.": "UniGetUI kunne ikkje stadfeste om oppdateringa lukkast. Opne loggen for å sjå kva som hende.", + "View log": "Vis logg", + "The installer reported success but did not restart UniGetUI.": "Installasjonsprogrammet rapporterte suksess, men starta ikkje UniGetUI på nytt.", + "The installer failed to initialize.": "Installasjonsprogrammet klarte ikkje å starte opp.", + "Setup was canceled before installation began.": "Oppsettet vart avbrote før installasjonen byrja.", + "A fatal error occurred during the preparation phase.": "Det oppstod ein fatal feil under førebuingsfasen.", + "A fatal error occurred during installation.": "Det oppstod ein fatal feil under installasjonen.", + "Installation was canceled while in progress.": "Installasjonen vart avbroten medan han pågjekk.", + "The installer was terminated by another process.": "Installasjonsprogrammet vart avslutta av ein annan prosess.", + "The preparation phase determined the installation cannot proceed.": "Førebuingsfasen fastslo at installasjonen ikkje kan halde fram.", + "The installer could not start. UniGetUI may already be running, or you do not have permission to install.": "Installasjonsprogrammet kunne ikkje starte. UniGetUI køyrer kanskje allereie, eller du har ikkje løyve til å installere.", + "Unexpected installer error.": "Uventa feil i installasjonsprogrammet.", + "We are checking for updates.": "Me er av sjekk for oppdateringar.", + "Please wait": "Venlegst vent", + "Great! You are on the latest version.": "Flott! Du er på siste versjon.", + "There are no new UniGetUI versions to be installed": "Det finst ingen nye UniGetUI-versjonar som skal installeras", + "UniGetUI version {0} is being downloaded.": "UniGetUI versjon {0} blir lasta ned.", + "This may take a minute or two": "Dette kan ta nokre få minutt", + "The installer authenticity could not be verified.": "Autentisiteten til installasjonsprogram kunne ikkje blir stadfest.", + "The update process has been aborted.": "Oppdateringsprosessen vart avbroten.", + "Auto-update is not yet available on this platform.": "Automatisk oppdatering er ikkje tilgjengeleg på denne plattforma enno.", + "Please update UniGetUI manually.": "Oppdater UniGetUI manuelt.", + "An error occurred when checking for updates: ": "Ein feil oppstod ved sjekking for oppdateringar", + "The updater could not be launched.": "Oppdateraren kunne ikkje startast.", + "The operating system did not start the installer process.": "Operativsystemet starta ikkje installasjonsprosessen.", + "UniGetUI is being updated...": "UniGetUI blir oppdatert...", + "Update installed.": "Oppdatering installert.", + "UniGetUI was updated successfully, but this running copy was not replaced. This usually means you are running a development build. Close this copy and start the newly-installed version to finish.": "UniGetUI vart oppdatert, men denne køyrande kopien vart ikkje bytt ut. Dette tyder vanlegvis at du køyrer ein utviklingsversjon. Lukk denne kopien og start den nyinstallerte versjonen for å fullføre.", + "The update could not be applied.": "Oppdateringa kunne ikkje takast i bruk.", + "Installer exit code {0}: {1}": "Avsluttingskode frå installasjonsprogrammet {0}: {1}", + "Update cancelled.": "Oppdateringa vart avbroten.", + "Authentication was cancelled.": "Autentiseringa vart avbroten.", + "Installer exit code {0}": "Avsluttingskode frå installasjonsprogrammet {0}", + "Operation in progress": "Handlingar som utførast", + "Please wait...": "Venlegst vent...", + "Success!": "Suksess!", + "Failed": "Feilet", + "An error occurred while processing this package": "Ein feil oppstod i behandlinga av denne pakken", + "Installer": "Installasjonsprogram", + "Executable": "Køyrbar fil", + "MSI": "MSI", + "Compressed file": "Komprimert fil", + "MSIX": "MSIX", + "WinGet was repaired successfully": "WinGet vart reparert med suksess", + "It is recommended to restart UniGetUI after WinGet has been repaired": "Det blir tilrådd å starte UniGetUI på nytt etter at WinGet har vorte reparert", + "WinGet could not be repaired": "WinGet kunne ikkje bli reparert", + "An unexpected issue occurred while attempting to repair WinGet. Please try again later": "Ein uventa feil oppstod ved forsøk på å reparere WinGet. Venlegst prøv igjen seinare", + "Log in to enable cloud backup": "Logg inn for å aktivere skya-sikkerheitskopi", + "Backup Failed": "Sikkerheitskopi feilet", + "Downloading backup...": "Lastar ned sikkerheitskopi...", + "An update was found!": "Ein oppdatering vart funnen!", + "{0} can be updated to version {1}": "{0} kan bli oppdatert til versjon {1}", + "Updates found!": "Oppdateringar funne!", + "{0} packages can be updated": "{0} pakkar kan bli oppdatert", + "{0} is being updated to version {1}": "{0} blir oppdatert til versjon {1}", + "{0} packages are being updated": "{0} pakkar blir oppdatert", + "You have currently version {0} installed": "No har du versjon {0} installert", + "Desktop shortcut created": "Skrivebordssnarveien vart opprett", + "UniGetUI has detected a new desktop shortcut that can be deleted automatically.": "UniGetUI har oppdaga ein ny skrivebordssnarveie som kan bli sletta automatisk.", + "{0} desktop shortcuts created": "{0} skrivebordssnarveiar oppretta", + "UniGetUI has detected {0} new desktop shortcuts that can be deleted automatically.": "UniGetUI har oppdaga {0} nye skrivebordssnarveiar som kan bli sletta automatisk.", + "Attention required": "Oppmerksemd krevst", + "Restart required": "Omstart krevst", + "1 update is available": "1 oppdatering er tilgjengeleg", + "{0} updates are available": "{0} oppdateringar er tilgjengelege", + "Everything is up to date": "Alt er oppdatert", + "Discover Packages": "Utforsk pakkar", + "Available Updates": "Tilgjengelege oppdateringar", + "Installed Packages": "Installerte pakkar", + "UniGetUI Version {0} by Devolutions": "UniGetUI versjon {0} av Devolutions", + "Show UniGetUI": "Vis UniGetUI", + "Quit": "Lukk", + "Are you sure?": "Er du sikker?", + "Do you really want to uninstall {0}?": "Vil du verkeleg avinstallere {0}?", + "Do you really want to uninstall the following {0} packages?": "Vil du verkeleg avinstallere føljande {0} pakkar?", + "No": "Nei", + "Yes": "Ja", + "Partial": "Delvis", + "View on UniGetUI": "Sjå på UniGetUI", + "Update": "Uppdater", + "Open UniGetUI": "Opne UniGetUI", + "Update all": "Oppdater alle", + "Update now": "Oppdater no", + "Installer host changed since the installed version.\n": "Verten for installasjonsprogrammet har endra seg sidan den installerte versjonen.\n", + "This package is on the queue": "Denne pakken er i køen", + "installing": "installerar", + "updating": "oppdaterar", + "uninstalling": "avinstallerar", + "installed": "installert", + "Retry": "Prøv igjen", + "Install": "Installer", + "Uninstall": "Avinstaller", + "Open": "Åpne", + "Operation profile:": "Handlingsprofil:", + "Follow the default options when installing, upgrading or uninstalling this package": "Følg standardvala når denne pakka blir installert, oppgradert eller avinstallert", + "The following settings will be applied each time this package is installed, updated or removed.": "Føljande innstillingar kjem til å bli brukt kvar gong denne pakken blir installert, oppdatert, eller fjerna.", + "Version to install:": "Versjon å installere:", + "Architecture to install:": "Arkitektur som blir installert:", + "Installation scope:": "Installasjonsomfang:", + "Install location:": "Installasjonsplassering:", + "Select": "Velj", + "Reset": "Tilbakestill", + "Custom install arguments:": "Tilpassa installasjonsparametrar:", + "Custom update arguments:": "Tilpassa oppdateringsparametrar:", + "Custom uninstall arguments:": "Tilpassa avinstallasjonsparametrar:", + "Pre-install command:": "Pre-installasjonskommando:", + "Post-install command:": "Post-installasjonskommando:", + "Abort install if pre-install command fails": "Avbryt installasjon viss pre-installasjonskommandoen mislykjast", + "Pre-update command:": "Pre-oppdateringskommando:", + "Post-update command:": "Post-oppdateringskommando:", + "Abort update if pre-update command fails": "Avbryt oppdateringa viss pre-oppdateringskommandoen mislykjast", + "Pre-uninstall command:": "Pre-avinstallasjonskommando:", + "Post-uninstall command:": "Post-avinstallasjonskommando:", + "Abort uninstall if pre-uninstall command fails": "Avbryt avinstallasjonen viss pre-avinstallasjonskommandoen mislykjast", + "Command-line to run:": "Kommandolinje som skal køyrast:", + "Save and close": "Lagre og lukk", + "General": "Generelt", + "Architecture & Location": "Arkitektur og plassering", + "Command-line": "Kommandolinje", + "Close apps": "Lukk appar", + "Pre/Post install": "Før/etter installasjon", + "Select the processes that should be closed before this package is installed, updated or uninstalled.": "Vel prosessane som skal lukka før denne pakka blir installert, oppdatert eller avinstallert.", + "Write here the process names here, separated by commas (,)": "Skriv her prosessnamna, separerte med komma (,)", + "Try to kill the processes that refuse to close when requested to": "Forsøk å doda dei prosessane som nektar av lukke seg når dei blir bedt om det", + "Run as admin": "Køyr som administrator", + "Interactive installation": "Interaktiv installasjon", + "Skip hash check": "Hopp over sjekk av hash", + "Uninstall previous versions when updated": "Avinstaller tidlegare versjonar når dei blir oppdatera", + "Skip minor updates for this package": "Hopp over mindre oppdateringar for denne pakka", + "Automatically update this package": "Oppdater denne pakka automatisk", + "{0} installation options": "{0} sine installasjonsval", + "Latest": "Siste", + "PreRelease": "Forhandsutgiving", + "Default": "Standard", + "Manage ignored updates": "Behandle ignorerte oppdateringar", + "The packages listed here won't be taken in account when checking for updates. Double-click them or click the button on their right to stop ignoring their updates.": "Pakkane i denne lista kjem ikkje til å bli tatt hensyn til ved sjekking etter oppdateringar. Dobbeltklikk på dei eller klikk på knappen til høgre for dei for å slutte å ignorere oppdateringa deira.", + "Reset list": "Nullstill liste", + "Do you really want to reset the ignored updates list? This action cannot be reverted": "Vil du verkeleg nullstille lista over ignorerte oppdateringar? Denne handlinga kan ikkje omgjerast", + "No ignored updates": "Ingen ignorerte oppdateringar", + "Package Name": "Pakkenamn", + "Package ID": "Pakke-ID", + "Ignored version": "Ignorert versjon", + "New version": "Ny versjon", + "Source": "Kjelde", + "All versions": "Alle versjonar", + "Unknown": "Ukjend", + "Up to date": "Oppdatert", + "Package {name} from {manager}": "Pakke {name} frå {manager}", + "Remove {0} from ignored updates": "Fjern {0} frå ignorerte oppdateringar", + "Cancel": "Avbryt", + "Administrator privileges": "Administratorrettar", + "This operation is running with administrator privileges.": "Denne handlinga køyrer med administratorrettar.", + "Interactive operation": "Interaktiv handling", + "This operation is running interactively.": "Denne handlinga køyrer interaktivt.", + "You will likely need to interact with the installer.": "Du vil truleg måtta samhandle med installasjonsprogram.", + "Integrity checks skipped": "Integritetssjekkar hoppa over", + "Integrity checks will not be performed during this operation.": "Integritetssjekkar blir ikkje utførte under denne handlinga.", + "Proceed at your own risk.": "Gå fram på eiga hand og risiko.", + "Close": "Lukk", + "Loading...": "Lastar...", + "Installer SHA256": "Installasjonsprogram SHA256", + "Homepage": "Heimeside", + "Author": "Forfattar", + "Publisher": "Utgjevar", + "License": "Lisens", + "Manifest": "Konfigurasjonsfil", + "Installer Type": "Type installasjonsprogram", + "Size": "Storleik", + "Installer URL": "URL til installasjonsprogram", + "Last updated:": "Sist oppdatert:", + "Release notes URL": "URL for utgivingsnotatar", + "Package details": "Pakkedetaljar", + "Dependencies:": "Avhengigheiter:", + "Release notes": "Utgivingsnotatar", + "Screenshots": "Skjermbilete", + "This package has no screenshots or is missing the icon? Contribute to UniGetUI by adding the missing icons and screenshots to our open, public database.": "Har denne pakken ingen skjermbilete, eller manglar han ikon? Bidra til UniGetUI ved å leggje til dei manglande ikona og skjermbileta i den opne, offentlege databasen vår.", + "Version": "Versjon", + "Install as administrator": "Installer som administrator", + "Update to version {0}": "Oppdater til versjon {0}", + "Installed Version": "Installer versjon", + "Update as administrator": "Oppdater som administrator", + "Interactive update": "Interaktiv oppdatering", + "Uninstall as administrator": "Avinstaller som administrator", + "Interactive uninstall": "Interaktiv avinstallering", + "Uninstall and remove data": "Avinstaller og fjern data", + "Not available": "Ikkje tilgjengeleg", + "Installer SHA512": "Installasjonsprogram SHA512", + "Unknown size": "Ukjent storleik", + "No dependencies specified": "Ingen avhengigheiter spesifiserte", + "mandatory": "obligatorisk", + "optional": "valfritt", + "UniGetUI {0} is ready to be installed.": "UniGetUI {0} er klar til å bli installert.", + "The update process will start after closing UniGetUI": "Oppdateringsprosessen vil starta etter at UniGetUI blir lukka", + "UniGetUI has been ran as administrator, which is not recommended. When running UniGetUI as administrator, EVERY operation launched from UniGetUI will have administrator privileges. You can still use the program, but we highly recommend not running UniGetUI with administrator privileges.": "UniGetUI har vorte køyrt som administrator, noko som ikkje er tilrådd. Når du køyrer UniGetUI som administrator, vil ALLE handlingar som blir starta frå UniGetUI få administratorrettar. Du kan framleis bruke programmet, men vi tilrår sterkt at du ikkje køyrer UniGetUI med administratorrettar.", + "Share anonymous usage data": "Del anonyme brukardata", + "UniGetUI collects anonymous usage data in order to improve the user experience.": "UniGetUI samlar anonyme brukardata for å forbetre brukarerfaringa.", + "Accept": "Aksepter", + "Software Updates": "Programvareoppdateringar", + "Package Bundles": "Pakkebundlar", + "Settings": "Innstillingar", + "Package Managers": "Pakkehåndterarar", + "UniGetUI Log": "UniGetUI-logg", + "Package Manager logs": "Pakkehandteringsloggar", + "Operation history": "Handlingshistorikk", + "Help": "Hjelp", + "UniGetUI": "UniGetUI", + "You have installed UniGetUI Version {0}": "Du har installert UniGetUI versjon {0}", + "Disclaimer": "Ansvarsfråskriving", + "UniGetUI is developed by Devolutions and is not affiliated with any of the compatible package managers.": "UniGetUI er utvikla av Devolutions og er ikkje knytt til nokon av dei kompatible pakkehandsamarane.", + "UniGetUI wouldn't have been possible without the help of the contributors. Thank you all 🥳": "UniGetUI ville ikkje vore mogleg uten hjelp frå alle bidragsytarane. Takk alle saman🥳", + "UniGetUI uses the following libraries. Without them, UniGetUI wouldn't have been possible.": "UniGetUI brukar føljande bibliotek. Utan dei ville ikkje UniGetUI ha vore mogleg.", + "{0} homepage": "{0} si heimeside", + "UniGetUI has been translated to more than 40 languages thanks to the volunteer translators. Thank you 🤝": "UniGetUI har blitt omsett til meir enn 40 språk takka vere frivillige omsetjare. Takk 🤝", + "Verbose": "Uttømmande", + "1 - Errors": "1 - Feilmeldingar", + "2 - Warnings": "2 - Åtvaringar", + "3 - Information (less)": "3 - Informasjon (mindre)", + "4 - Information (more)": "4 - Informasjon (meir)", + "5 - information (debug)": "5 - Informasjon (feilsøking)", + "Warning": "Åtvaring", + "The following settings may pose a security risk, hence they are disabled by default.": "Dei følgjande innstillingane kan me ein tryggleiksfråfall, så dei er deaktiverte som standard.", + "Enable the settings below if and only if you fully understand what they do, and the implications they may have.": "Aktiver innstillingane under BERRE DERSOM du fullstendig forstår kva dei gjer, og kva konsekvensar og farar dei kan ha.", + "The settings will list, in their descriptions, the potential security issues they may have.": "Innstillingane vil lista opp, i sine beskrivingarar, dei potensielle tryggleikspråfalla dei kan ha.", + "The backup will include the complete list of the installed packages and their installation options. Ignored updates and skipped versions will also be saved.": "Sikkerheitskopien kjem til å innehelde ein fullstendig liste over dei installerte pakkane og deira installasjonsval. Ignorerte oppdateringar og versjonar som har vorte hoppa over kjem også til å bli lagra.", + "The backup will NOT include any binary file nor any program's saved data.": "Sikkerheitskopien kjem ikkje til å innehelde nokre binære filar eller programmar sine lagrede data", + "The size of the backup is estimated to be less than 1MB.": "Storleiken på sikkerheitskopien er estimert til å vere mindre enn 1MB.", + "The backup will be performed after login.": "Sikkerheitskopien kjem til å bli utført etter innlogging", + "{pcName} installed packages": "{pcName}: Installerte pakkar", + "Current status: Not logged in": "Gjeldande status: Ikkje innlogga", + "You are logged in as {0} (@{1})": "Du er innlogga som {0} (@{1})", + "Nice! Backups will be uploaded to a private gist on your account": "Fint! Sikkerheitskopiar vil bli lasta opp til ein privat gist på kontoen din", + "Select backup": "Vel sikkerheitskopi", + "Settings imported from {0}": "Innstillingar importerte frå {0}", + "UniGetUI Settings": "UniGetUI-innstillingar", + "Settings exported to {0}": "Innstillingar eksporterte til {0}", + "UniGetUI settings were reset": "UniGetUI-innstillingane vart nullstilte", + "Allow pre-release versions": "Tillat forhandsversjonar", + "Apply": "Bruk", + "For security reasons, custom command-line arguments are disabled by default. Go to UniGetUI security settings to change this.": "Av tryggingsgrunnar er tilpassa kommandolinjeparametrar deaktiverte som standard. Gå til UniGetUI-tryggingsinnstillingane for å endre dette.", + "Go to UniGetUI security settings": "Gå til UniGetUI-tryggjingsinnstillingar", + "The following options will be applied by default each time a {0} package is installed, upgraded or uninstalled.": "Dei følgjande vala vil bli brukte som standard kvar gong ein {0}-pakke blir installert, oppgradert eller avinstallert.", + "Package's default": "Pakkens standard", + "Install location can't be changed for {0} packages": "Installasjonsplassering kan ikkje endrast for {0}-pakkar", + "The local icon cache currently takes {0} MB": "Det lokale ikonbufferet tek for tida {0} MB", + "Username": "Brukarnamn", + "Password": "Passord", + "Credentials": "Legitimasjon", + "It is not guaranteed that the provided credentials will be stored safely": "Det er ikkje garantert at dei oppgjevne legitimasjonsopplysningane blir lagra trygt", + "Partially": "Delvis", + "Package manager": "Pakkehåndterar", + "Compatible with proxy": "Kompatibel med proxy", + "Compatible with authentication": "Kompatibel med autentisering", + "Proxy compatibility table": "Proxy-kompatibilitetstabell", + "{0} settings": "{0} innstillingar", + "{0} status": "{0}-tilstand", + "Default installation options for {0} packages": "Standardinstallasjonsval for {0}-pakkar", + "Expand version": "Utvid versjon", + "The executable file for {0} was not found": "Kjørbar fil for {0} vart ikkje funne", + "{pm} is disabled": "{pm} er deaktivert", + "Enable it to install packages from {pm}.": "Aktiver det for å installere pakkar frå {pm}", + "{pm} is enabled and ready to go": "{pm} er aktivert og klar for bruk", + "{pm} version:": "{pm} versjon:", + "{pm} was not found!": "{pm} vart ikkje funne!", + "You may need to install {pm} in order to use it with UniGetUI.": "Du må kanskje installere {pm} for å bruke det med UniGetUI.", + "Scoop Installer - UniGetUI": "Scoop-installasjonsprogram - UniGetUI", + "Scoop Uninstaller - UniGetUI": "Scoop-avinstallasjonsprogram - UniGetUI", + "Clearing Scoop cache - UniGetUI": "Rensar Scoop-cachen - UniGetUI", + "Restart UniGetUI to fully apply changes": "Start UniGetUI på nytt for å ta i bruk endringane fullt ut", + "Restart UniGetUI": "Start UniGetUI på nytt", + "Manage {0} sources": "Behandle {0} kjelder", + "Add source": "Legg til kjelde", + "Add": "Legg til", + "Source name": "Kjeldenamn", + "Source URL": "Kjelde-URL", + "Other": "Andre", + "No minimum age": "Ingen minimumsalder", + "1 day": "1 dag", + "{0} days": "{0} dagar", + "Custom...": "Tilpassa...", + "{0} minutes": "{0} minutt", + "1 hour": "1 time", + "{0} hours": "{0} timar", + "1 week": "1 veke", + "Supports release dates": "Støttar utgivingsdatoar", + "Release date support per package manager": "Støtte for utgivingsdatoar per pakkehandterar", + "Search for packages": "Søk etter pakkar", + "Local": "Lokal", + "OK": "Ok", + "Last checked: {0}": "Sist sjekka: {0}", + "{0} packages were found, {1} of which match the specified filters.": "{0} pakkar var funne, av dei matcha {1} dine filter.", + "{0} selected": "{0} vald", + "(Last checked: {0})": "(Sist sjekka: {0})", + "All packages selected": "Alle pakkar valde", + "Package selection cleared": "Pakkeutvalet tømt", + "{0}: {1}": "{0}: {1}", + "More info": "Meir informasjon", + "GitHub account": "GitHub-konto", + "Log in with GitHub to enable cloud package backup.": "Logg inn med GitHub for å aktivere skya-pakke-sikkerheitskopi.", + "More details": "Fleire detaljar", + "Log in": "Logg inn", + "If you have cloud backup enabled, it will be saved as a GitHub Gist on this account": "Viss du har skya-sikkerheitskopi aktivert, vil ho bli lagra som ein GitHub Gist på denne kontoen", + "Log out": "Logg ut", + "About UniGetUI": "Om UniGetUI", + "About": "Om", + "Third-party licenses": "Tredjepartslisensar", + "Contributors": "Bidragsytare", + "Translators": "Omsettare", + "Bundle security report": "Sikkerheitsrapport for bundle", + "The bundle contained restricted content": "Pakkebundelen inneheldt avgrensa innhald", + "UniGetUI – Crash Report": "UniGetUI – Krasjrapport", + "UniGetUI has crashed": "UniGetUI har krasja", + "Help us fix this by sending a crash report to Devolutions. All fields below are optional.": "Hjelp oss å fikse dette ved å sende ein krasjrapport til Devolutions. Alle felta nedanfor er valfrie.", + "Email (optional)": "E-post (valfritt)", + "your@email.com": "din@epost.no", + "Additional details (optional)": "Ytterlegare detaljar (valfritt)", + "Describe what you were doing when the crash occurred…": "Beskriv kva du gjorde då krasjen oppstod…", + "Crash report": "Krasjrapport", + "Don't Send": "Ikkje send", + "Send Report": "Send rapport", + "Sending…": "Sender…", + "Unsaved changes": "Ulagra endringar", + "You have unsaved changes in the current bundle. Do you want to discard them?": "Du har ulagra endringar i den noverande pakkebundelen. Vil du forkaste dei?", + "Discard changes": "Forkast endringar", + "Integrity violation": "Integritetsbrot", + "UniGetUI or some of its components are missing or corrupt. It is strongly recommended to reinstall UniGetUI to adress the situation.": "UniGetUI eller nokre av komponentane manglar eller er skadde. Det blir sterkt tilrådd å installere UniGetUI på nytt for å rette opp situasjonen.", + "• Refer to the UniGetUI Logs to get more details regarding the affected file(s)": "• Sjå UniGetUI-loggane for å få fleire detaljar angåande dei påverka fil(ane)", + "• Integrity checks can be disabled from the Experimental Settings": "• Integritetssjekkar kan deaktiveringast frå Eksperimentelle innstillingar", + "Manage shortcuts": "Handsamar snarveiar", + "UniGetUI has detected the following desktop shortcuts which can be removed automatically on future upgrades": "UniGetUI har oppdaga dei følgjande skrivebordssnarveiane som kan bli fjerna automatisk på framtidige oppgraderingar", + "Do you really want to reset this list? This action cannot be reverted.": "Vil du verkeleg nullstille denne lista? Denne handlinga kan ikkje omgjørast.", + "Desktop shortcuts list": "Liste over skrivebordssnarveiar", + "Open in explorer": "Opne i Filutforskar", + "Remove from list": "Fjern frå liste", + "When new shortcuts are detected, delete them automatically instead of showing this dialog.": "Når nye snarveiar blir oppdaga, slette dei automatisk i staden for å visa denne dialogen.", + "Not right now": "Ikkje akkurat no", + "Missing dependency": "Manglar avhengigheit", + "UniGetUI requires {0} to operate, but it was not found on your system.": "UniGetUI krev {0} for å virke, men det vart ikkje funne på systemet ditt.", + "Click on Install to begin the installation process. If you skip the installation, UniGetUI may not work as expected.": "Trykk på \"Installer\" for å starte installasjonsprosessen. Viss du hoppar over installasjonen, kan det hende at UniGetUI ikkje fungerar som forventa.", + "Alternatively, you can also install {0} by running the following command in a Windows PowerShell prompt:": "Du kan eventuelt også installere {0} ved å køyre følgjande kommando i Windows PowerShell:", + "Install {0}": "Installer {0}", + "Do not show this dialog again for {0}": "Ikkje vis denne dialogen igjen for {0}", + "Please wait while {0} is being installed. A black window may show up. Please wait until it closes.": "Venlegst vent medan {0} blir installert. Eit svart (eller blått) vindauge kan dukke opp. Venlegst vent til det lukkar seg.", + "{0} has been installed successfully.": "{0} har vorte installert med suksess.", + "Please click on \"Continue\" to continue": "Venlegst klikk på \"Fortsett\" for å fortsette", + "Continue": "Fortsett", + "{0} has been installed successfully. It is recommended to restart UniGetUI to finish the installation": "{0} har vorte installert med suksess. Det blir tilrådd å starte UniGetUI på nytt for å fullføre installasjonen", + "Restart later": "Start på ny seinare", + "An error occurred:": "Ein feil oppstod:", + "Please see the Command-line Output or refer to the Operation History for further information about the issue.": "Venlegst sjå på kommandolinje-outputen eller handlingshistorikken for meir informasjon om problemet.", + "Retry as administrator": "Prøv igjen som administrator", + "Retry interactively": "Prøv på nytt interaktivt", + "Retry skipping integrity checks": "Prøv på nytt og hoppa over integritetssjekkar", + "Installation options": "Installasjonsval", + "Save": "Lagre", + "UniGetUI collects anonymous usage data with the sole purpose of understanding and improving the user experience.": "UniGetUI samlar anonyme brukardata med det einaste formålet å forstå og forbetre brukarerfaringa.", + "More details about the shared data and how it will be processed": "Fleire detaljar om dei delte dataa og korleis dei vil bli handsama", + "Do you accept that UniGetUI collects and sends anonymous usage statistics, with the sole purpose of understanding and improving the user experience?": "Godtar du at UniGetUI samlar og sendar anonyme brukarstatistikkar, med det einaste formålet å forstå og forbetre brukarerfaringa?", + "Decline": "Avslå", + "No personal information is collected nor sent, and the collected data is anonimized, so it can't be back-tracked to you.": "Ingen personleg informasjon blir samla eller sendt, og den samla dataa er anonymisert, så ho kan ikkje bli tilbakefølgd til deg.", + "Navigation panel": "Navigasjonspanel", + "Operations": "Handlingar", + "Toggle operations panel": "Vis/gøym handlingspanelet", + "Bulk operations": "Massehandlingar", + "Retry failed": "Prøv mislukka på nytt", + "Clear successful": "Fjern vellukka", + "Clear finished": "Fjern fullførte", + "Cancel all": "Avbryt alle", + "More": "Meir", + "Toggle navigation panel": "Vis/skjul navigasjonspanelet", + "Minimize": "Minimer", + "Maximize": "Maksimer", + "UniGetUI by Devolutions": "UniGetUI av Devolutions", + "UniGetUI is an application that makes managing your software easier, by providing an all-in-one graphical interface for your command-line package managers.": "UniGetUI er ein applikasjon som forenklar handtering av programvare, ved å tilby eit alt-i-eitt grafisk grensesnitt for kommandolinjepakkehandterarane dine.", + "Useful links": "Nyttige lenkar", + "UniGetUI Homepage": "UniGetUI-heimeside", + "Report an issue or submit a feature request": "Si frå om ein feil eller send inn forslag til nye funksjonar", + "UniGetUI Repository": "UniGetUI-kodelager", + "View GitHub Profile": "Vis GitHub-profil", + "UniGetUI License": "UniGetUI - Lisens", + "Using UniGetUI implies the acceptation of the MIT License": "Bruk av UniGetUI inneber å godta MIT-lisensen", + "Become a translator": "Bli ein omsettar", + "Go back": "Gå tilbake", + "Go forward": "Gå framover", + "Go to home page": "Gå til startsida", + "Reload page": "Last sida på nytt", + "View page on browser": "Vis sida i nettlesaren", + "The built-in browser is not supported on Linux yet.": "Den innebygde nettlesaren er ikkje støtta på Linux enno.", + "Open in browser": "Opne i nettlesar", + "Copy to clipboard": "Kopier til utklippstavla", + "Export to a file": "Eksporter til ei fil", + "Log level:": "Loggnivå:", + "Reload log": "Last inn logg på ny", + "Export log": "Eksporter logg", + "Text": "Tekst", + "Change how operations request administrator rights": "Endra korleis handlingar ber om administratorrettar", + "Restrictions on package operations": "Avgrensingar på pakkehandlingar", + "Restrictions on package managers": "Avgrensingar på pakkehåndterarar", + "Restrictions when importing package bundles": "Avgrensingar ved import av pakke-bundlar", + "Ask for administrator privileges once for each batch of operations": "Spør etter administratorrettar ein gong per gruppe operasjonar", + "Ask only once for administrator privileges": "Spør berre ein gong for administratorrettar", + "Prohibit any kind of Elevation via UniGetUI Elevator or GSudo": "Forbyd alle former for høgninga via UniGetUI Elevator eller GSudo", + "This option WILL cause issues. Any operation incapable of elevating itself WILL FAIL. Install/update/uninstall as administrator will NOT WORK.": "Dette valet VIL medføre problem. Any operation incapable of elevating itself WILL FAIL. Install/update/uninstall as administrator will NOT WORK.", + "Allow custom command-line arguments": "Tillat tilpassa kommandolinjeparametrar", + "Custom command-line arguments can change the way in which programs are installed, upgraded or uninstalled, in a way UniGetUI cannot control. Using custom command-lines can break packages. Proceed with caution.": "Tilpassa kommandolinjeparametrar kan endre korleis program blir installerte, oppgradera eller avinstallerte, på ein måte UniGetUI ikkje kan kontrollere. Å bruke tilpassa kommandolinjeparametrar kan bryte pakkar. Gå fram med forsiktighet.", + "Ignore custom pre-install and post-install commands when importing packages from a bundle": "Tillat at tilpassa pre-installasjons- og post-installasjonskommandoar skal køyrast", + "Pre and post install commands will be run before and after a package gets installed, upgraded or uninstalled. Be aware that they may break things unless used carefully": "Pre- og post-installasjonskommandoar vil bli køyrte før og etter ein pakke blir installert, oppgradert eller avinstallert. Ver merksam på at dei kan bryte ting med mindre dei blir brukte med forsiktighet", + "Allow changing the paths for package manager executables": "Tillat endring av stiar for pakkehåndterar-kjørbare filer", + "Turning this on enables changing the executable file used to interact with package managers. While this allows finer-grained customization of your install processes, it may also be dangerous": "Om du slår dette på kan du endra kjørbar fil som blir brukt til å samhandle med pakkehåndterarar. Medan dette tillat finare tilpassingar av instalasjonsplassane dine, kan det og vera farleg", + "Allow importing custom command-line arguments when importing packages from a bundle": "Tillat import av tilpassa kommandolinjeparametrar ved import av pakkar frå ein pakke-bundle", + "Malformed command-line arguments can break packages, or even allow a malicious actor to gain privileged execution. Therefore, importing custom command-line arguments is disabled by default": "Feilformatterte kommandolinjeparametrar kan bryte pakkar, eller til og med tillate ein skadeleg aktør å få privilegert kjøring. Difor er import av tilpassa kommandolinjeparametrar deaktivert som standard.", + "Allow importing custom pre-install and post-install commands when importing packages from a bundle": "Tillat import av tilpassa pre-installasjons- og post-installasjonskommandoar ved import av pakkar frå ein pakke-bundle", + "Pre and post install commands can do very nasty things to your device, if designed to do so. It can be very dangerous to import the commands from a bundle, unless you trust the source of that package bundle": "Pre- og post-installasjonskommandoar kan gjere veldig skadelege ting med eininga di, viss dei er designa for det. Det kan vera veldig farleg å importere kommandoane frå ein bundle, med mindre du stolar på kjelden av den pakke-bundlen", + "Administrator rights and other dangerous settings": "Administratorrettar og andre risikofylte innstillingar", + "Package backup": "Pakke-sikkerheitskopi", + "Cloud package backup": "Skya-pakke-sikkerheitskopi", + "Local package backup": "Lokal pakke-sikkerheitskopi", + "Local backup advanced options": "Avanserte val for lokal sikkerheitskopi", + "Log in with GitHub": "Logg inn med GitHub", + "Log out from GitHub": "Logg ut frå GitHub", + "Periodically perform a cloud backup of the installed packages": "Utfør periodemessig ein skya-sikkerheitskopi av installerte pakkar", + "Cloud backup uses a private GitHub Gist to store a list of installed packages": "Skya-sikkerheitskopi brukar ein privat GitHub Gist til å lagre ei liste over installerte pakkar", + "Perform a cloud backup now": "Utfør ein skya-sikkerheitskopi no", + "Backup": "Ta backup", + "Restore a backup from the cloud": "Gjenopprett ein sikkerheitskopi frå skya", + "Begin the process to select a cloud backup and review which packages to restore": "Starta prosessen for å velje ein skya-sikkerheitskopi og gjennomgå kva pakkar som skal gjenoppretta", + "Periodically perform a local backup of the installed packages": "Utfør periodemessig ein lokal sikkerheitskopi av installerte pakkar", + "Perform a local backup now": "Utfør ein lokal sikkerheitskopi no", + "Change backup output directory": "Endre mappa for sikkerheitskopien", + "Set a custom backup file name": "Velj eit eige namn for sikkerheitskopifila", + "Leave empty for default": "La stå tomt for standardvalet", + "Add a timestamp to the backup file names": "Legg til eit tidsstempel til backup-filnamna", + "Backup and Restore": "Sikkerheitskopi og gjenoppretting", + "Enable background api (UniGetUI Widgets and Sharing, port 7058)": "Aktiver bakgrunns-API-et (UniGetUI Widgets and Sharing, port 7058)", + "Wait for the device to be connected to the internet before attempting to do tasks that require internet connectivity.": "Vent til eininga er kopla til internett før du forsøk å utføre oppgåver som krev internettsamband.", + "Disable the 1-minute timeout for package-related operations": "Deaktiver 1-minutts-tidsavbrøytinga for pakke-relaterte handlingar", + "Use installed GSudo instead of UniGetUI Elevator": "Bruk installert GSudo i staden for UniGetUI Elevator", + "Use a custom icon and screenshot database URL": "Bruk eit eigendefinert ikon og ein eigendefinert URL til databasen", + "Enable background CPU Usage optimizations (see Pull Request #3278)": "Aktiver bakgrunns-CPU-brukaroptimaliseringar (sjå Pull Request #3278)", + "Perform integrity checks at startup": "Utfør integritetssjekkar ved oppstart", + "When batch installing packages from a bundle, install also packages that are already installed": "Når dei installerar pakkar frå ein bundle i batch, installer og pakkar som alt er installerte", + "Experimental settings and developer options": "Eksperimentelle innstillingar og val for utveklare", + "Show UniGetUI's version and build number on the titlebar.": "Vis UniGetUI si versjon på tittelbalken", + "Language": "Språk", + "UniGetUI updater": "UniGetUI-oppdaterar", + "Telemetry": "Telemetri", + "Manage UniGetUI settings": "Handsamar UniGetUI-innstillingar", + "Related settings": "Relaterte innstillingar", + "Update UniGetUI automatically": "Oppdater UniGetUI automatisk", + "Check for updates": "Sjekk for oppdateringar", + "Install prerelease versions of UniGetUI": "Installer forhandsversjonar av UniGetUI", + "Manage telemetry settings": "Handsamar telemetri-innstillingar", + "Manage": "Handsamar", + "Import settings from a local file": "Eksporter innstillingar frå ei lokal fil", + "Import": "Importer", + "Export settings to a local file": "Eksporter innstillingar til ei lokal fil", + "Export": "Eksporter", + "Reset UniGetUI": "Nullstill UniGetUI", + "User interface preferences": "Alternativar for brukargrensesnitt", + "Application theme, startup page, package icons, clear successful installs automatically": "App-tema, startsida, pakkeikon, fjern ferdige installasjonar automatisk", + "General preferences": "Generelle innstillingar", + "UniGetUI display language:": "UniGetUI sitt visningsspråk:", + "System language": "Systemspråk", + "Is your language missing or incomplete?": "Manglar språket ditt eller er det uferdig? (viss språket ditt er bokmål eller nynorsk jobbar eg med saka)", + "Appearance": "Utsjånad", + "UniGetUI on the background and system tray": "UniGetUI i bakgrunnen og systemstatusfeltet", + "Package lists": "Pakkelister", + "Use classic mode": "Bruk klassisk modus", + "Restart UniGetUI to apply this change": "Start UniGetUI på nytt for å ta i bruk denne endringa", + "The classic UI is disabled for beta testers": "Det klassiske brukargrensesnittet er deaktivert for betatestarar", + "Close UniGetUI to the system tray": "Lukk UniGetUI til systemstatusfeltet", + "Manage UniGetUI autostart behaviour": "Handsam autostartåtferda til UniGetUI", + "Show package icons on package lists": "Vis pakkeikon på pakkelister", + "Clear cache": "Tøm buffer", + "Select upgradable packages by default": "Vel oppgradeingsbare pakkar som standard", + "Light": "Lys", + "Dark": "Mørk", + "Follow system color scheme": "Følj systemtemaet", + "Application theme:": "Applikasjonstema:", + "UniGetUI startup page:": "UniGetUI-startsida:", + "Proxy settings": "Proxy-innstillingar", + "Other settings": "Andre innstillingar", + "Connect the internet using a custom proxy": "Kople til internett med ein tilpassa proxy", + "Please note that not all package managers may fully support this feature": "Ver merksam på at ikkje alle pakkehåndterarar kan fullstendig støtte denne funksjonen", + "Proxy URL": "Proxy-URL", + "Enter proxy URL here": "Skriv inn proxy-URL her", + "Authenticate to the proxy with a user and a password": "Autentiser mot proxyen med brukarnamn og passord", + "Internet and proxy settings": "Internett- og proxyinnstillingar", + "Package manager preferences": "Innstillingar for pakkehandterar", + "Ready": "Klar", + "Not found": "Ikkje funne", + "Notification preferences": "Varselinstillingar", + "Notification types": "Varslingtypar", + "The system tray icon must be enabled in order for notifications to work": "Systemstatusfeltet-ikonet må vera aktivert for at varslingane skal virke", + "Enable UniGetUI notifications": "Aktiver varslingar frå UniGetUI", + "Show a notification when there are available updates": "Vis ei varsling når oppdateringar er tilgjengelege", + "Show a silent notification when an operation is running": "Vis ein stille varsling når ein operasjon køyrar", + "Show a notification when an operation fails": "Vis ein varsling når ein operasjon feilar", + "Show a notification when an operation finishes successfully": "Vis ein varsling når ein operasjon er fullført", + "Concurrency and execution": "Parallell prosessering og eksekusjon", + "Automatic desktop shortcut remover": "Automatisk fjerning av skrivebordssnarveiar", + "Choose how many operations should be performed in parallel": "Vel kor mange handlingar som skal utførast parallelt", + "Clear successful operations from the operation list after a 5 second delay": "Tøm vellukkede handlingar frå handlingslista etter ein 5-sekunders forsinking", + "Download operations are not affected by this setting": "Nedlastingshandlingar blir ikkje påverka av denne innstillinga", + "You may lose unsaved data": "Du kan miste ulagra data", + "Ask to delete desktop shortcuts created during an install or upgrade.": "Spør om å slette skrivebordssnarveiar opprettede under installasjon eller oppgradering.", + "Package update preferences": "Preferansar for pakkeoppdateringar", + "Update check frequency, automatically install updates, etc.": "Frekvens for oppdateringskontroll, installer oppdateringar automatisk, osv.", + "Reduce UAC prompts, elevate installations by default, unlock certain dangerous features, etc.": "Reduser UAC-spørsmål, høgna installasjonar som standard, låst opp visse farefulle funksjonar, osv.", + "Package operation preferences": "Preferansar for pakkehandlingar", + "Enable {pm}": "Aktiver {pm}", + "Not finding the file you are looking for? Make sure it has been added to path.": "Finn du ikkje fila du leit etter? Viss at ho har vorte lagt til stien.", + "Select the executable to be used. The following list shows the executables found by UniGetUI": "Vel kjørbar fil som skal brukast. Den følgjande lista viser kjørbare filer funne av UniGetUI", + "For security reasons, changing the executable file is disabled by default": "Av tryggjingsgrunnar er endring av kjørbar fil deaktivert som standard", + "Change this": "Endra dette", + "Copy path": "Kopier sti", + "Current executable file:": "Gjeldande kjørbar fil:", + "Ignore packages from {pm} when showing a notification about updates": "Ignorer pakkar frå {pm} når ein varsling om oppdateringar blir vist", + "Update security": "Oppdateringstryggleik", + "Use global setting": "Bruk global innstilling", + "Minimum age for updates": "Minimumsalder for oppdateringar", + "e.g. 10": "t.d. 10", + "Custom minimum age (days)": "Tilpassa minimumsalder (dagar)", + "{pm} does not provide release dates for its packages, so this setting will have no effect": "{pm} oppgir ikkje utgivingsdatoar for pakkane sine, så denne innstillinga vil ikkje ha nokon effekt", + "{pm} only provides release dates for some of its packages, so this setting will only apply to those packages": "{pm} oppgjev berre utgjevingsdatoar for nokre av pakkane sine, så denne innstillinga gjeld berre for desse pakkane", + "Override the global minimum update age for this package manager": "Overstyr den globale minimumsalderen for oppdateringar for denne pakkehandteraren", + "View {0} logs": "Sjå {0}-logger", + "If Python cannot be found or is not listing packages but is installed on the system, ": "Viss Python ikkje kan finnast eller ikkje listar pakkar, men er installert på systemet, ", + "Advanced options": "Avanserte val", + "WinGet command-line tool": "WinGet-kommandolinjeverktøy", + "Choose which command-line tool UniGetUI uses for WinGet operations when the COM API is not used": "Vel kva kommandolinjeverktøy UniGetUI skal bruke for WinGet-handlingar når COM API ikkje blir brukt", + "WinGet COM API": "WinGet COM API", + "Choose whether UniGetUI can use the WinGet COM API before falling back to the command-line tool": "Vel om UniGetUI kan bruke WinGet COM API før programmet fell tilbake til kommandolinjeverktøyet", + "Reset WinGet": "Nullstill WinGet", + "This may help if no packages are listed": "Dette kan hjelpe viss ingen pakkar blir lista opp", + "Force install location parameter when updating packages with custom locations": "Tving installasjonsplassering-parameter når du oppdaterar pakkar med tilpassa plasseringar", + "Install Scoop": "Installer Scoop", + "Uninstall Scoop (and its packages)": "Avinstaller Scoop (og alle tilhørande pakkar)", + "Run cleanup and clear cache": "Køyr opprensing og fjern buffer", + "Run": "Køyr", + "Enable Scoop cleanup on launch": "Aktiver Scoop-cleanup (nullstilling av buffer) ved oppstart", + "Default vcpkg triplet": "Standard vcpkg-triplett", + "Change vcpkg root location": "Endre rotplasseringa for vcpkg", + "Reset vcpkg root location": "Nullstill rotplasseringa for vcpkg", + "Open vcpkg root location": "Opne rotplasseringa for vcpkg", + "Language, theme and other miscellaneous preferences": "Språk, tema, og diverse andre preferansar", + "Show notifications on different events": "Vis varslingar for ulike hendingar", + "Change how UniGetUI checks and installs available updates for your packages": "Endre korleis UniGetUI sjekkar for og installerar tilgjengelege oppdateringar for pakkane dine", + "Automatically save a list of all your installed packages to easily restore them.": "Lagre ei liste over alle dine installerte pakkar automatisk for å forenkle gjenoppretting av dei.", + "Enable and disable package managers, change default install options, etc.": "Aktiver og deaktiver pakkehåndterarar, endra standardinstallasjonsval, osv.", + "Internet connection settings": "Innstillingar for internettforbinding", + "Proxy settings, etc.": "Proxy-innstillingar, osv.", + "Beta features and other options that shouldn't be touched": "Beta-funksjonalitet og andre innstillingar som ikkje må rørast", + "Reload sources": "Last kjelder på nytt", + "Delete source": "Slett kjelde", + "Known sources": "Kjende kjelder", + "Update checking": "Oppdateringskontroll", + "Automatic updates": "Automatiske oppdateringar", + "Check for package updates periodically": "Sjekk etter pakkoppdateringar med jamne mellomrom", + "Check for updates every:": "Søk etter oppdateringar kvar:", + "Install available updates automatically": "Installer tilgjengelege oppdateringar automatisk", + "Do not automatically install updates when the network connection is metered": "Ikkje installer oppdateringar automatisk når nettverksforbindinga er målbar", + "Do not automatically install updates when the device runs on battery": "Ikkje installer oppdateringar automatisk når eininga køyrer på batteri", + "Do not automatically install updates when the battery saver is on": "Ikkje installer oppdateringar automatisk når batteri-sparing er på", + "Only show updates that are at least the specified number of days old": "Vis berre oppdateringar som er minst det oppgjevne talet på dagar gamle", + "Warn me when the installer URL host changes between the installed version and the new version (WinGet only)": "Åtvar meg når verten i installasjons-URL-en endrar seg mellom den installerte versjonen og den nye versjonen (berre WinGet)", + "Change how UniGetUI handles install, update and uninstall operations.": "Endra korleis UniGetUI handsamar installasjon, oppdatering og avinstallasjon.", + "Navigation": "Navigasjon", + "Check for UniGetUI updates": "Sjekk for UniGetUI-oppdateringar", + "Quit UniGetUI": "Avslutt UniGetUI", + "Filters": "Filtrar", + "Sources": "Kjelder", + "Search for packages to start": "Søk etter ein eller fleire pakkar for å starte", + "Select all": "Velj alle", + "Clear selection": "Tøm val", + "Instant search": "Hurtigsøk", + "Distinguish between uppercase and lowercase": "Skilj mellom store og små bokstavar", + "Ignore special characters": "Ignorer spesialtekn", + "Search mode": "Søkemodus", + "Both": "Båe", + "Exact match": "Eksakt match", + "Show similar packages": "Vis lignande pakkar", + "Loading": "Lastar", + "Package": "Pakke", + "More options": "Fleire val", + "Order by:": "Sorter etter:", + "Name": "Namn", + "Id": "ID", + "Ascendant": "Stigande", + "Descendant": "Synkande", + "View modes": "Visingsmodusar", + "Reload": "Last på nytt", + "Closed": "Lukka", + "Ascending": "Stigande", + "Descending": "Synkande", + "{0}: {1}, {2}": "{0}: {1}, {2}", + "Order by": "Sorter etter", + "No results were found matching the input criteria": "Ingen resultatar som matcha kriteria vart funne", + "No packages were found": "Ingen pakkar vart funne", + "Loading packages": "Lastar inn pakkar", + "Skip integrity checks": "Hopp over integritetssjekkar", + "Download selected installers": "Last ned valde installasjonsprogarammar", + "Install selection": "Installer utval", + "Install options": "Installasjonsval", + "Add selection to bundle": "Legg til utval til bundlen", + "Download installer": "Last ned installasjonsprogram", + "Uninstall selection": "Avinstaller utval", + "Uninstall options": "Avinstallasjonsval", + "Ignore selected packages": "Ignorer valte pakkar", + "Open install location": "Opne installasjonsplassering", + "Reinstall package": "Installer pakke på nytt", + "Uninstall package, then reinstall it": "Avinstaller pakka, og så reinstaller han", + "Ignore updates for this package": "Ignorer oppdateringar til denne pakka", + "WinGet malfunction detected": "WinGet-mangel oppdaga", + "It looks like WinGet is not working properly. Do you want to attempt to repair WinGet?": "Det ser ut som WinGet ikkje fungerar riktig. Vil du forsøke å reparere WinGet?", + "Repair WinGet": "Reparer WinGet", + "Updates will no longer be ignored for {0}": "Oppdateringar vil ikkje lenger bli ignorerte for {0}", + "Updates are now ignored for {0}": "Oppdateringar er no ignorerte for {0}", + "Do not ignore updates for this package anymore": "Ikkje ignorer oppdateringar for denne pakka lenger", + "Add packages or open an existing package bundle": "Legg til pakkar eller opne ein eksisterande bundle", + "Add packages to start": "Legg til pakkar for å starte", + "The current bundle has no packages. Add some packages to get started": "Nåverande bundle har ingen pakkar. Legg til pakkar for å setje i gong", + "New": "Ny", + "Save as": "Lagre som", + "Create .ps1 script": "Opprett .ps1-skript", + "Remove selection from bundle": "Fjern utval frå bundle", + "Skip hash checks": "Hopp over sjekka av hasj", + "The package bundle is not valid": "Pakke-bundlen er ikkje gyldig", + "The bundle you are trying to load appears to be invalid. Please check the file and try again.": "Bundlen du forsøkar å laste ser ut til å vera ugyldig. Venlegst sjekk fila og prøv igjen.", + "Package bundle": "Pakkebundle", + "Could not create bundle": "Kunne ikkje lage bundle", + "The package bundle could not be created due to an error.": "Pakke-bundlen kunne ikkje bli laga på grunn av ein feil.", + "Install script": "Installasjonsskript", + "PowerShell script": "PowerShell-skript", + "The installation script saved to {0}": "Installasjonsskriptet vart lagra til {0}", + "An error occurred": "Ein feil oppstod", + "An error occurred while attempting to create an installation script:": "Ein feil oppstod ved forsøk på å lage eit installasjonsskript:", + "Hooray! No updates were found.": "Hurra! Ingen oppdateringar funne!", + "Uninstall selected packages": "Avinstaller valte pakkar", + "Update selection": "Oppdater utval", + "Update options": "Oppdateringsval", + "Uninstall package, then update it": "Avinstaller pakka, og so oppdater ho", + "Uninstall package": "Avinstaller pakka", + "Skip this version": "Hopp over denne versjonen", + "Pause updates for": "Pause oppdateringar i", + "User | Local": "Brukar | Lokal", + "Machine | Global": "Maskin | Global", + "The default package manager for Debian/Ubuntu-based Linux distributions.
Contains: Debian/Ubuntu packages": "Standardpakkehandteraren for Debian/Ubuntu-baserte Linux-distribusjonar.
Inneheld: Debian/Ubuntu-pakkar", + "The Rust package manager.
Contains: Rust libraries and programs written in Rust": "Rust-pakkehåndteraren.
Inneheld: Rust-bibliotek og program skrivne i Rust", + "The classical package manager for windows. You'll find everything there.
Contains: General Software": "Den klassiske pakkehandteraren for Windows. Du kan finne alt der.
Inneheld: Generell programvare", + "The default package manager for RHEL/Fedora-based Linux distributions.
Contains: RPM packages": "Standardpakkehandteraren for RHEL/Fedora-baserte Linux-distribusjonar.
Inneheld: RPM-pakkar", + "A repository full of tools and executables designed with Microsoft's .NET ecosystem in mind.
Contains: .NET related tools and scripts": "Eit repository fullt av verktøy og programmar desingna for Microsoft sitt .NET-økosystem.
Inneheld: .NET-relaterte verktøy og skript", + "The universal Linux package manager for desktop applications.
Contains: Flatpak applications from configured remotes": "Den universelle Linux-pakkehandteraren for skrivebordsprogram.
Inneheld: Flatpak-program frå konfigurerte fjernlager", + "NuPkg (zipped manifest)": "NuPkg (zippa manifest)", + "The Missing Package Manager for macOS (or Linux).
Contains: Formulae, Casks": "Den manglande pakkehandteraren for macOS (eller Linux).
Inneheld: Formulae, Casks", + "Node JS's package manager. Full of libraries and other utilities that orbit the javascript world
Contains: Node javascript libraries and other related utilities": "Node JS sin pakkehandterer. Full av bibliotek og andre verktøy som svevar rundt i JavaScript-universet
Inneheld: Node.js-bibliotek og andre relaterte verktøy", + "The default package manager for Arch Linux and its derivatives.
Contains: Arch Linux packages": "Standardpakkehandteraren for Arch Linux og derivata.
Inneheld: Arch Linux-pakkar", + "Python's library manager. Full of python libraries and other python-related utilities
Contains: Python libraries and related utilities": "Python sin pakkehandterer. Full av bibliotek og andre Python-relaterte verktøy
Inneheld: Python-bibliotek og andre relaterte verktøy", + "PowerShell's package manager. Find libraries and scripts to expand PowerShell capabilities
Contains: Modules, Scripts, Cmdlets": "PowerShell sin pakkehandterar. Finn bibliotek og skript for å utvide PowerShell sine evnar
Inneheld: Modular, skript, cmdlets", + "extracted": "utpakka", + "Scoop package": "Skoop-pakke", + "Great repository of unknown but useful utilities and other interesting packages.
Contains: Utilities, Command-line programs, General Software (extras bucket required)": "Flott repository med ukjende men nyttige verktøy og andre interessante pakkar.
Inneheld:Verktøy, kommandolinjeprogram, generell programvare (ekstra buckets krevst)", + "The universal Linux package manager by Canonical.
Contains: Snap packages from the Snapcraft store": "Den universelle Linux-pakkehandteraren frå Canonical.
Inneheld: Snap-pakkar frå Snapcraft-butikken", + "library": "bibliotek", + "feature": "funksjon", + "A popular C/C++ library manager. Full of C/C++ libraries and other C/C++-related utilities
Contains: C/C++ libraries and related utilities": "Ein populær C/C++-bibliotekhåndterar. Full av C/C++-bibliotek og andre relaterte verktøy.
Inneheld: C/C++-bibliotek og relaterte verktøy", + "option": "val", + "This package cannot be installed from an elevated context.": "Denne pakka kan ikkje bli installert frå ein høgna kontekst.", + "Please run UniGetUI as a regular user and try again.": "Venlegst køyr UniGetUI som ein vanlег brukar og prøv igjen.", + "Please check the installation options for this package and try again": "Venlegst sjekk installasjonsvaline for denne pakka og prøv igjen", + "Microsoft's official package manager. Full of well-known and verified packages
Contains: General Software, Microsoft Store apps": "Microsoft sin offisielle pakkehandterar. Full av velkjende og verifiserte pakkar
Inneheld: Generell programvare, Microsoft Store-appar", + "Local PC": "Lokal PC", + "Android Subsystem": "Android-undersystem", + "Operation on queue (position {0})...": "Handlinga er i køen (posisjon {0})...", + "Click here for more details": "Klikk her for fleire detaljar", + "Operation canceled by user": "Operasjon avbroten av brukar", + "Running PreOperation ({0}/{1})...": "Køyrer PreOperation ({0}/{1})...", + "PreOperation {0} out of {1} failed, and was tagged as necessary. Aborting...": "PreOperation {0} av {1} mislukkast og var merkt som naudsynt. Avbryt...", + "PreOperation {0} out of {1} finished with result {2}": "PreOperation {0} av {1} blei fullført med resultatet {2}", + "Starting operation...": "Startar handling...", + "Running PostOperation ({0}/{1})...": "Køyrer PostOperation ({0}/{1})...", + "PostOperation {0} out of {1} failed, and was tagged as necessary. Aborting...": "PostOperation {0} av {1} mislukkast og var merkt som naudsynt. Avbryt...", + "PostOperation {0} out of {1} finished with result {2}": "PostOperation {0} av {1} blei fullført med resultatet {2}", + "{package} installer download": "{package} installasjonsprogram nedlasting", + "{0} installer is being downloaded": "{0} installasjonsprogram blir lasta ned", + "Download succeeded": "Nedlasting var suksessfull", + "{package} installer was downloaded successfully": "{package} installasjonsprogram vart lasta ned med suksess", + "Download failed": "Nedlasting feilet", + "{package} installer could not be downloaded": "{package} installasjonsprogram kunne ikkje bli lasta ned", + "{package} Installation": "{package} Installasjon", + "{0} is being installed": "{0} blir installert", + "Installation succeeded": "Installasjon fullført", + "{package} was installed successfully": "{package} vart suksessfullt installert", + "Installation failed": "Installasjon feilet", + "{package} could not be installed": "{package} kunne ikkje bli installert", + "{package} Update": "{package} Oppdater", + "Update succeeded": "Suksessfull oppdatering", + "{package} was updated successfully": "{package} vart suksessfullt oppdatert", + "Update failed": "Oppdatering feila", + "{package} could not be updated": "{package} kunne ikkje bli oppdatert", + "{package} Uninstall": "{package} Avinstaller", + "{0} is being uninstalled": "{0} blir avinstallert", + "Uninstall succeeded": "Suksessfull avinstallering", + "{package} was uninstalled successfully": "{package} vart suksessfullt avinstallert", + "Uninstall failed": "Avinstallering feila", + "{package} could not be uninstalled": "{package} kunne ikkje bli avinstallert", + "Adding source {source}": "Legg til kjelda {source}", + "Adding source {source} to {manager}": "Legg til kjelde {source} til {manager}", + "Source added successfully": "Kjelde lagd til med suksess", + "The source {source} was added to {manager} successfully": "Kjelden {source} vart suksessfullt lagt til hos {manager}", + "Could not add source": "Kunne ikkje legge til kjelde", + "Could not add source {source} to {manager}": "Kunne ikkje legge til kjelde {source} til {manager}", + "Removing source {source}": "Fjernar kjelden {source}", + "Removing source {source} from {manager}": "Fjernar kjelde {source} frå {manager}", + "Source removed successfully": "Kjelde fjerna med suksess", + "The source {source} was removed from {manager} successfully": "Kjelden {source} vart suksessfullt fjerna frå {manager}", + "Could not remove source": "Kunne ikkje fjerne kjelde", + "Could not remove source {source} from {manager}": "Kunne ikkje fjerne kjelde {source} frå {manager}", + "The package manager \"{0}\" was not found": "Pakkehåndteraren «{0}» vart ikkje funne", + "The package manager \"{0}\" is disabled": "Pakkehåndteraren «{0}» er deaktivert", + "There is an error with the configuration of the package manager \"{0}\"": "Det er ein feil med konfigurasjonen av pakkehåndteraren «{0}»", + "The package \"{0}\" was not found on the package manager \"{1}\"": "Pakka «{0}» vart ikkje funne på pakkehåndteraren «{1}»", + "{0} is disabled": "{0} er deaktivert", + "{0} weeks": "{0} veker", + "1 month": "1 månad", + "{0} months": "{0} månadar", + "Something went wrong": "Noko gikk galt", + "An interal error occurred. Please view the log for further details.": "Ein intern feil oppstod. Venlegst sjå loggen for fleire detaljar.", + "No applicable installer was found for the package {0}": "Ingen gjeldande installasjonsprogaramm vart funne for pakka {0}", + "Integrity checks will not be performed during this operation": "Integritetssjekkar vil ikkje bli utførte under denne handlinga", + "This is not recommended.": "Dette blir ikkje tilrådd.", + "Run now": "Køyr no", + "Run next": "Køyr neste", + "Run last": "Køyr sist", + "Show in explorer": "Vis i utforskar", + "Checked": "Avkryssa", + "Unchecked": "Ikkje avkryssa", + "This package is already installed": "Denne pakken er allereie installert", + "This package can be upgraded to version {0}": "Denne pakka kan bli oppgradert til versjon {0}", + "Updates for this package are ignored": "Oppdateringar for denne pakka er ignorert", + "This package is being processed": "Denne pakken behandlas", + "This package is not available": "Denne pakka er ikkje tilgjengeleg", + "Select the source you want to add:": "Velj kjelden du ynskjer å legge til:", + "Source name:": "Kjeldenamn:", + "Source URL:": "Kilde-URL:", + "An error occurred when adding the source: ": "Ein feil oppstod då kjelden vart lagt til:", + "Package management made easy": "Pakkestyring gjort enkelt", + "version {0}": "versjon {0}", + "[RAN AS ADMINISTRATOR]": "KØYRTE SOM ADMINISTRATOR", + "Portable mode": "Bærbar modus\n", + "DEBUG BUILD": "DEBUG-BUILD", + "Here you can change UniGetUI's behaviour regarding the following shortcuts. Checking a shortcut will make UniGetUI delete it if if gets created on a future upgrade. Unchecking it will keep the shortcut intact": "Her kan du endra UniGetUI si åtferd angåande dei følgjande snarviene. Om du merkar av ein snarvei vil UniGetUI slette den viss ho blir opprett på ein framtidig oppgradering. Om du ikkje merkar ho av vil snarveia bli bevart intakt", + "Manual scan": "Manuell skanning", + "Existing shortcuts on your desktop will be scanned, and you will need to pick which ones to keep and which ones to remove.": "Eksisterande snarveiar på skriveborddet ditt vil bli skannade, og du må velje kva du vil behalde og kva du vil fjerne.", + "Delete?": "Slette?", + "I understand": "Eg forstår", + "Chocolatey setup changed": "Chocolatey-oppsettet er endra", + "UniGetUI no longer includes its own private Chocolatey installation. A legacy UniGetUI-managed Chocolatey installation was detected for this user profile, but system Chocolatey was not found. Chocolatey will stay unavailable in UniGetUI until Chocolatey is installed on the system and UniGetUI is restarted. Applications previously installed through UniGetUI's bundled Chocolatey may still appear under other sources such as Local PC or WinGet.": "UniGetUI inkluderer ikkje lenger sin eigen private Chocolatey-installasjon. Ein eldre UniGetUI-administrert Chocolatey-installasjon vart oppdaga for denne brukarprofilen, men system-Chocolatey vart ikkje funne. Chocolatey vil vera utilgjengeleg i UniGetUI til Chocolatey er installert på systemet og UniGetUI er starta på nytt. Program som tidlegare vart installerte gjennom UniGetUI sin bundla Chocolatey kan framleis visast under andre kjelder som Lokal PC eller WinGet.", + "NOTE: This troubleshooter can be disabled from UniGetUI Settings, on the WinGet section": "MERK: Denne feilsøkaren kan deaktiveringast frå UniGetUI-innstillingar, på WinGet-delen", + "Restart": "Start på nytt", + "Are you sure you want to delete all shortcuts?": "Er du sikker på at du vil slette alle snarveiane?", + "Any new shorcuts created during an install or an update operation will be deleted automatically, instead of showing a confirmation prompt the first time they are detected.": "Nye snarveiar som blir oppretta under ein installasjon eller oppdateringshandling vil bli sletta automatisk, i staden for å visa ein bekreftingsdialog første gangen dei blir oppdaga.", + "Any shorcuts created or modified outside of UniGetUI will be ignored. You will be able to add them via the {0} button.": "Snarveiar oppretta eller endra utanfor UniGetUI vil bli ignorerte. Du vil kunne legge dei til via {0}-knappen.", + "Are you really sure you want to enable this feature?": "Er du verkeleg sikker på at du vil aktivere denne funksjonen?", + "No new shortcuts were found during the scan.": "Ingen nye snarveiar vart funne under skanningen.", + "How to add packages to a bundle": "Korleis å legge til pakkar til ein bundle", + "In order to add packages to a bundle, you will need to: ": "For å legge til pakkar til ein bundle må du: ", + "1. Navigate to the \"{0}\" or \"{1}\" page.": "1. Naviger til «{0}»- eller «{1}»-sida.", + "2. Locate the package(s) you want to add to the bundle, and select their leftmost checkbox.": "2. Finn pakka(ne) du vil legge til i bundlen, og vel den venstre avmerkingsboksen.", + "3. When the packages you want to add to the bundle are selected, find and click the option \"{0}\" on the toolbar.": "3. Når pakkane du vil legge til i bundlen er valde, finn og klikk på valet «{0}» på verktøylinja.", + "4. Your packages will have been added to the bundle. You can continue adding packages, or export the bundle.": "4. Pakkane dine vil ha vorte lagde til i bundlen. Du kan fortsette med å legge til pakkar, eller eksportere bundlen.", + "Which backup do you want to open?": "Kva sikkerheitskopi vil du opne?", + "Select the backup you want to open. Later, you will be able to review which packages you want to install.": "Vel sikkerheitskopien du vil opne. Seinare vil du kunne gjennomgå kva pakkar du vil installere.", + "There are ongoing operations. Quitting UniGetUI may cause them to fail. Do you want to continue?": "Det er mange pågåande operasjonar. Å avslutte UniGetUI kan føre til at dei feilar. Vil du fortsetje?", + "UniGetUI or some of its components are missing or corrupt.": "UniGetUI eller nokre av komponenta hans manglar eller er øydelagde.", + "It is strongly recommended to reinstall UniGetUI to adress the situation.": "Det blir sterkt tilrådd å reinstallere UniGetUI for å løyse situasjonen.", + "Refer to the UniGetUI Logs to get more details regarding the affected file(s)": "Sjå UniGetUI-loggane for å få fleire detaljar angåande dei påverka fil(ane)", + "Integrity checks can be disabled from the Experimental Settings": "Integritetssjekkar kan deaktiveringast frå Eksperimentelle innstillingar", + "Repair UniGetUI": "Reparer UniGetUI", + "Live output": "Direkte output", + "This package bundle had some settings that are potentially dangerous, and may be ignored by default.": "Denne pakke-bundlen hadde nokre innstillingar som potensielt kan vera farefulle, og kan bli ignorerte som standard.", + "Entries that show in YELLOW will be IGNORED.": "Oppføringar som vart vist i GULT vil bli IGNORERTE.", + "Entries that show in RED will be IMPORTED.": "Oppføringar som vart vist i RØD vil bli IMPORTERTE.", + "You can change this behavior on UniGetUI security settings.": "Du kan endra denne åtferda på UniGetUI-tryggjingsinnstillingar.", + "Open UniGetUI security settings": "Opne UniGetUI-tryggjingsinnstillingar", + "Should you modify the security settings, you will need to open the bundle again for the changes to take effect.": "Viss du endrar tryggjingsinnstillingane må du opne bundlen igjen for at endringane skal få effekt.", + "Details of the report:": "Detaljar av rapporten:", + "Are you sure you want to create a new package bundle? ": "Er du sikker på at du vil lage ein ny pakke-bundle?", + "Any unsaved changes will be lost": "Ulagra endringar vil gå tapt", + "Warning!": "Åtvaring!", + "For security reasons, custom command-line arguments are disabled by default. Go to UniGetUI security settings to change this. ": "Av tryggjingsgrunnar er tilpassa kommandolinjeparametrar deaktiverte som standard. Gå til UniGetUI-tryggjingsinnstillingar for å endra dette. ", + "Change default options": "Endra standardval", + "Ignore future updates for this package": "Ignorer framtidige oppdateringar for denne pakka", + "For security reasons, pre-operation and post-operation scripts are disabled by default. Go to UniGetUI security settings to change this. ": "Av tryggjingsgrunnar er pre-operasjons- og post-operasjons-skript deaktiverte som standard. Gå til UniGetUI-tryggjingsinnstillingar for å endra dette. ", + "You can define the commands that will be run before or after this package is installed, updated or uninstalled. They will be run on a command prompt, so CMD scripts will work here.": "Du kan definer kommandoane som vil bli køyrte før eller etter denne pakka blir installert, oppdatert eller avinstallert. Dei vil bli køyrte på ein kommandoleie, så CMD-skript vil virke her.", + "Change this and unlock": "Endra dette og låst opp", + "{0} Install options are currently locked because {0} follows the default install options.": "{0} Installasjonsval er for tida låste fordi {0} følgjer standardinstallasjonsvaline.", + "Unset or unknown": "Ikkje sett eller ukjend", + "This package has no screenshots or is missing the icon? Contrbute to UniGetUI by adding the missing icons and screenshots to our open, public database.": "Denne pakka har ingen skjermbilde eller manglar eit ikon? Bidra til UniGetUI ved å leggje til dei manglande ikona og skjermbilda til vår opne, offentlege database.", + "Become a contributor": "Bli ein bidragsytar", + "Update to {0} available": "Oppdatering for {0} er tilgjengeleg", + "Reinstall": "Installer på nytt", + "Installer not available": "Installerar ikkje tilgjengeleg", + "Version:": "Versjon:", + "UniGetUI Version {0}": "UniGetUI versjon {0}", + "Performing backup, please wait...": "Utførar sikkerheitskopi, venlegst vent...", + "An error occurred while logging in: ": "Ein feil oppstod under innlogging: ", + "Fetching available backups...": "Hentar tilgjengelege sikkerheitskopiar...", + "Done!": "Ferdig!", + "The cloud backup has been loaded successfully.": "Skya-sikkerheitskopien vart lasta inn med suksess.", + "An error occurred while loading a backup: ": "Ein feil oppstod under lasting av ein sikkerheitskopi: ", + "Backing up packages to GitHub Gist...": "Sikkerheitskopier pakkar til GitHub Gist...", + "Backup Successful": "Sikkerheitskopia vart fullført", + "The cloud backup completed successfully.": "Skya-sikkerheitskopien vart fullført med suksess.", + "Could not back up packages to GitHub Gist: ": "Kunne ikkje sikkerheitskopiere pakkar til GitHub Gist: ", + "It is not guaranteed that the provided credentials will be stored safely, so you may as well not use the credentials of your bank account": "Det er ikkje garantert at den oppgitte legitimasjonen vil bli lagra på ein trygg måte, så du kan like godt ikkje bruke legitimasjonen din for bankkontoen din", + "Enable the automatic WinGet troubleshooter": "Aktiver automatisk WinGet-feilsøkjar", + "Add updates that fail with a 'no applicable update found' to the ignored updates list": "Legg til oppdateringar som mislykjast med «ingen gjeldande oppdatering funne» i lista over ignorerte oppdateringar.", + "Invalid selection": "Ugyldig val", + "No package was selected": "Ingen pakke vart vald", + "More than 1 package was selected": "Meir enn 1 pakke vart vald", + "List": "Liste", + "Grid": "Rutenett", + "Icons": "Ikon", + "\"{0}\" is a local package and does not have available details": "«{0}» er ein lokal pakke og har ikkje tilgjengelege detaljar", + "\"{0}\" is a local package and is not compatible with this feature": "«{0}» er ein lokal pakke og støttar ikkje denne funksjonen", + "Add packages to bundle": "Legg til pakkar til bundlen", + "Preparing packages, please wait...": "Forbereiar pakkar, venlegst vent...", + "Loading packages, please wait...": "Lastar pakkar, venlegst vent...", + "Saving packages, please wait...": "Lagrar pakkar, venlegst vent...", + "The bundle was created successfully on {0}": "Bundlen vart opprett med suksess på {0}", + "User profile": "Brukarprofil", + "Error": "Feil", + "Log in failed: ": "Innlogging feilet: ", + "Log out failed: ": "Utlogging feilet: ", + "Package backup settings": "Innstillingar for pakke-sikkerheitskopi", + "Manage UniGetUI autostart behaviour from the Settings app": "Handsam autostartåtferda til UniGetUI", + "Choose how many operations shoulds be performed in parallel": "Vel kor mange handlingar som skal utførast parallelt", + "Something went wrong while launching the updater.": "Noko gjekk gale ved oppstart av oppdateraren.", + "Please try again later": "Venlegst prøv igjen seinare", + "Show the release notes after UniGetUI is updated": "Vis utgivingsnotata etter at UniGetUI er oppdatert" +} diff --git a/src/Languages/lang_pl.json b/src/Languages/lang_pl.json new file mode 100644 index 0000000..dd36f66 --- /dev/null +++ b/src/Languages/lang_pl.json @@ -0,0 +1,850 @@ +{ + "{0} of {1} operations completed": "Ukończono {0} z {1} operacji", + "{0} is now {1}": "{0} jest teraz {1}", + "Enabled": "Włączony", + "Disabled": "Wyłączony", + "Privacy": "Prywatność", + "Hide my username from the logs": "Ukryj moją nazwę użytkownika w dziennikach", + "Replaces your username with **** in the logs. Restart UniGetUI to also hide it from already-recorded entries.": "Zastępuje Twoją nazwę użytkownika znakami **** w dziennikach. Uruchom ponownie UniGetUI, aby ukryć ją także w już zapisanych wpisach.", + "Your last update attempt did not complete.": "Twoja ostatnia próba aktualizacji nie została ukończona.", + "UniGetUI could not confirm whether the update succeeded. Open the log to see what happened.": "UniGetUI nie mogło potwierdzić, czy aktualizacja się powiodła. Otwórz dziennik, aby zobaczyć, co się stało.", + "View log": "Zobacz dziennik", + "The installer reported success but did not restart UniGetUI.": "Instalator zgłosił powodzenie, ale nie uruchomił ponownie UniGetUI.", + "The installer failed to initialize.": "Nie udało się zainicjować instalatora.", + "Setup was canceled before installation began.": "Instalacja została anulowana przed rozpoczęciem.", + "A fatal error occurred during the preparation phase.": "Wystąpił błąd krytyczny podczas fazy przygotowania.", + "A fatal error occurred during installation.": "Wystąpił błąd krytyczny podczas instalacji.", + "Installation was canceled while in progress.": "Instalacja została anulowana w trakcie.", + "The installer was terminated by another process.": "Instalator został zakończony przez inny proces.", + "The preparation phase determined the installation cannot proceed.": "Faza przygotowania wykazała, że instalacja nie może być kontynuowana.", + "The installer could not start. UniGetUI may already be running, or you do not have permission to install.": "Nie można uruchomić instalatora. UniGetUI może już być uruchomione albo nie masz uprawnień do instalacji.", + "Unexpected installer error.": "Nieoczekiwany błąd instalatora.", + "We are checking for updates.": "Sprawdzamy dostępność aktualizacji.", + "Please wait": "Proszę czekać", + "Great! You are on the latest version.": "Świetnie! Masz najnowszą wersję!", + "There are no new UniGetUI versions to be installed": "Nie ma nowych wersji UniGetUI do zainstalowania", + "UniGetUI version {0} is being downloaded.": "Wersja {0} UniGetUI jest pobierana.", + "This may take a minute or two": "To może zająć minutę albo dwie", + "The installer authenticity could not be verified.": "Nie można zweryfikować autentyczności instalatora.", + "The update process has been aborted.": "Proces aktualizacji został przerwany.", + "Auto-update is not yet available on this platform.": "Automatyczna aktualizacja nie jest jeszcze dostępna na tej platformie.", + "Please update UniGetUI manually.": "Zaktualizuj UniGetUI ręcznie.", + "An error occurred when checking for updates: ": "Wystąpił błąd podczas sprawdzania dostępności aktualizacji:", + "The updater could not be launched.": "Nie można uruchomić aktualizatora.", + "The operating system did not start the installer process.": "System operacyjny nie uruchomił procesu instalatora.", + "UniGetUI is being updated...": "UniGetUI jest aktualizowany...", + "Update installed.": "Aktualizacja została zainstalowana.", + "UniGetUI was updated successfully, but this running copy was not replaced. This usually means you are running a development build. Close this copy and start the newly-installed version to finish.": "UniGetUI zostało pomyślnie zaktualizowane, ale ta działająca kopia nie została zastąpiona. Zwykle oznacza to, że korzystasz z kompilacji deweloperskiej. Zamknij tę kopię i uruchom nowo zainstalowaną wersję, aby dokończyć.", + "The update could not be applied.": "Nie można zastosować aktualizacji.", + "Installer exit code {0}: {1}": "Kod wyjścia instalatora {0}: {1}", + "Update cancelled.": "Aktualizacja została anulowana.", + "Authentication was cancelled.": "Uwierzytelnianie zostało anulowane.", + "Installer exit code {0}": "Kod wyjścia instalatora {0}", + "Operation in progress": "Operacja w toku", + "Please wait...": "Proszę czekać...", + "Success!": "Sukces!", + "Failed": "Niepowodzenie", + "An error occurred while processing this package": "Wystąpił błąd podczas przetwarzania tego pakietu", + "Installer": "Instalator", + "Executable": "Plik wykonywalny", + "MSI": "MSI", + "Compressed file": "Plik skompresowany", + "MSIX": "MSIX", + "WinGet was repaired successfully": "WinGet naprawiono pomyślnie", + "It is recommended to restart UniGetUI after WinGet has been repaired": "Zalecany jest restart UniGetUI po naprawieniu WinGet", + "WinGet could not be repaired": "WinGet nie został naprawiony", + "An unexpected issue occurred while attempting to repair WinGet. Please try again later": "Wystąpił nieoczekiwany błąd podczas próby naprawy WinGet. Spróbuj ponownie później", + "Log in to enable cloud backup": "Zaloguj się, aby umożliwić tworzenie kopii zapasowych w chmurze", + "Backup Failed": "Wykonanie kopii zapasowej nie powiodło się", + "Downloading backup...": "Pobieranie kopii zapasowej...", + "An update was found!": "Znaleziono aktualizację!", + "{0} can be updated to version {1}": "{0} może być zaktualizowany do wersji {1}", + "Updates found!": "Znaleziono aktualizacje!", + "{0} packages can be updated": "{0} pakietów może zostać zaktualizowanych", + "{0} is being updated to version {1}": "{0} jest aktualizowany do wersji {1}", + "{0} packages are being updated": "Aktualizowane pakiety: {0}", + "You have currently version {0} installed": "Aktualnie masz zainstalowaną wersję {0}", + "Desktop shortcut created": "Stworzono skrót na pulpicie", + "UniGetUI has detected a new desktop shortcut that can be deleted automatically.": "UniGetUI wykrył nowy skrót na pulpicie, który można automatycznie usunąć.", + "{0} desktop shortcuts created": "Utworzono {0} skrótów na pulpicie", + "UniGetUI has detected {0} new desktop shortcuts that can be deleted automatically.": "UniGetUI wykrył {0} nowych skrótów na pulpicie, które mogą zostać automatycznie usunięte.", + "Attention required": "Potrzebna uwaga", + "Restart required": "Wymagane ponowne uruchomienie", + "1 update is available": "Jest dostępna 1 aktualizacja", + "{0} updates are available": "{0} aktualizacji jest dostępnych", + "Everything is up to date": "Wszystko jest aktualne", + "Discover Packages": "Odkryj pakiety", + "Available Updates": "Aktualnie są dostępne aktualizacje", + "Installed Packages": "Zainstalowane pakiety", + "UniGetUI Version {0} by Devolutions": "UniGetUI w wersji {0} od Devolutions", + "Show UniGetUI": "Pokaż UniGetUI", + "Quit": "Wyjdź", + "Are you sure?": "Na pewno?", + "Do you really want to uninstall {0}?": "Czy na pewno chcesz odinstalować {0}?", + "Do you really want to uninstall the following {0} packages?": "Na pewno chcesz usunąć {0} pakietów?", + "No": "Nie", + "Yes": "Tak", + "Partial": "Częściowo", + "View on UniGetUI": "Zobacz w UniGetUI", + "Update": "Zaktualizuj", + "Open UniGetUI": "Otwórz UniGetUI", + "Update all": "Zaktualizuj wszystko", + "Update now": "Zaktualizuj teraz", + "Installer host changed since the installed version.\n": "Host instalatora zmienił się względem zainstalowanej wersji.\n", + "This package is on the queue": "Ten pakiet jest w kolejce", + "installing": "instalowanie", + "updating": "aktualizacja", + "uninstalling": "odinstalowywanie", + "installed": "zainstalowano", + "Retry": "Ponów", + "Install": "Zainstaluj", + "Uninstall": "Odinstaluj", + "Open": "Otwórz", + "Operation profile:": "Profil czynności:", + "Follow the default options when installing, upgrading or uninstalling this package": "Wykorzystuj domyślne ustawienia podczas instalacji, aktualizacji lub dezinstalacji tego pakietu", + "The following settings will be applied each time this package is installed, updated or removed.": "Poniższe ustawienia będą stosowane za każdym razem, gdy pakiet zostanie instalowany, aktualizowany lub usuwany.", + "Version to install:": "Wersja do instalacji:", + "Architecture to install:": "Architektura do instalacji:", + "Installation scope:": "Zakres instalacji:", + "Install location:": "Miejsce instalacji:", + "Select": "Wybierz", + "Reset": "Zresetuj", + "Custom install arguments:": "Niestandardowe argumenty instalacji:", + "Custom update arguments:": "Niestandardowe argumenty aktualizacji:", + "Custom uninstall arguments:": "Niestandardowe argumenty dezinstalacji:", + "Pre-install command:": "Komenda przedinstalacyjna:", + "Post-install command:": "Komenda poinstalacyjna:", + "Abort install if pre-install command fails": "Przerwij instalację, jeśli wykonanie komendy przedinstalacyjnej zakończy się niepowodzeniem", + "Pre-update command:": "Komenda przedaktualizacyjna:", + "Post-update command:": "Komenda poaktualizacyjna:", + "Abort update if pre-update command fails": "Przerwij aktualizację, jeśli wykonanie komendy przedaktualizacyjnej zakończy się niepowodzeniem", + "Pre-uninstall command:": "Komenda przeddezinstalacyjna:", + "Post-uninstall command:": "Komenda podezintalacyjna:", + "Abort uninstall if pre-uninstall command fails": "Przerwij dezinstalację, jeśli wykonanie komendy przeddezinstalacyjnej zakończy się niepowodzeniem", + "Command-line to run:": "Polecenie do wykonania:", + "Save and close": "Zapisz i zamknij", + "General": "Ogólne", + "Architecture & Location": "Architektura i lokalizacja", + "Command-line": "Wiersz poleceń", + "Close apps": "Zamknij aplikacje", + "Pre/Post install": "Przed/po instalacji", + "Select the processes that should be closed before this package is installed, updated or uninstalled.": "Wybierz procesy, które powinny zostać zamknięte przed zainstalowaniem, aktualizacją lub odinstalowaniem tego pakietu.", + "Write here the process names here, separated by commas (,)": "Wpisz tutaj nazwy procesów, odseparowane przecinkami (,)", + "Try to kill the processes that refuse to close when requested to": "Spróbuj wymusić zatrzymanie procesów, które odmawiają zamknięcia", + "Run as admin": "Uruchom jako administrator", + "Interactive installation": "Interaktywna instalacja", + "Skip hash check": "Pomiń weryfikacje hash'a", + "Uninstall previous versions when updated": "Odinstaluj poprzednie wersje po aktualizacji", + "Skip minor updates for this package": "Pomiń drobne aktualizacje dla tego pakietu", + "Automatically update this package": "Automatycznie aktualizuj ten pakiet", + "{0} installation options": "{0} - opcje instalacji", + "Latest": "Najnowsza", + "PreRelease": "Wersja przedpremierowa", + "Default": "Domyślne", + "Manage ignored updates": "Zarządzaj ignorowanymi aktualizacjami", + "The packages listed here won't be taken in account when checking for updates. Double-click them or click the button on their right to stop ignoring their updates.": "Pakiety wymienione tutaj nie będą brane pod uwagę podczas sprawdzania aktualizacji. Kliknij je dwukrotnie lub kliknij przycisk po ich prawej stronie, aby przestać ignorować ich aktualizacje.", + "Reset list": "Zresetuj listę", + "Do you really want to reset the ignored updates list? This action cannot be reverted": "Czy na pewno chcesz zresetować listę ignorowanych aktualizacji? Tego działania nie można cofnąć.", + "No ignored updates": "Brak ignorowanych aktualizacji", + "Package Name": "Nazwa pakietu", + "Package ID": "ID pakietu", + "Ignored version": "Ignorowane wersje", + "New version": "Nowa wersja", + "Source": "Źródło", + "All versions": "Wszystkie wersje", + "Unknown": "Brak informacji", + "Up to date": "Aktualny", + "Package {name} from {manager}": "Pakiet {name} z {manager}", + "Remove {0} from ignored updates": "Usuń {0} z ignorowanych aktualizacji", + "Cancel": "Anuluj", + "Administrator privileges": "Uprawnienia administratora", + "This operation is running with administrator privileges.": "Ta operacja jest wykonywana z uprawnieniami administratora.", + "Interactive operation": "Interaktywna operacja", + "This operation is running interactively.": "Operacja ta jest wykonywana interaktywnie.", + "You will likely need to interact with the installer.": "Prawdopodobnie konieczna będzie interakcja z instalatorem.", + "Integrity checks skipped": "Pominięto sprawdzanie spójności", + "Integrity checks will not be performed during this operation.": "Sprawdzenia integralności nie będą wykonywane podczas tej operacji.", + "Proceed at your own risk.": "Postępuj na własne ryzyko.", + "Close": "Zamknij", + "Loading...": "Ładowanie...", + "Installer SHA256": "SHA256 instalatora", + "Homepage": "Strona główna", + "Author": "Autor", + "Publisher": "Wydawca", + "License": "Licencja", + "Manifest": "Manifest pakietu", + "Installer Type": "Typ instalatora", + "Size": "Rozmiar", + "Installer URL": "Adres URL instalatora", + "Last updated:": "Ostatnia aktualizacja:", + "Release notes URL": "Adres URL informacji o wydaniu", + "Package details": "Szczegóły pakietu", + "Dependencies:": "Zależności:", + "Release notes": "Informacje o wydaniu", + "Screenshots": "Zrzuty ekranu", + "This package has no screenshots or is missing the icon? Contribute to UniGetUI by adding the missing icons and screenshots to our open, public database.": "Ten pakiet nie ma zrzutów ekranu lub brakuje mu ikony? Wesprzyj UniGetUI, dodając brakujące ikony i zrzuty ekranu do naszej otwartej, publicznej bazy danych.", + "Version": "Wersja", + "Install as administrator": "Zainstaluj jako administrator", + "Update to version {0}": "Zaktualizuj do wersji {0}", + "Installed Version": "Zainstalowana wersja", + "Update as administrator": "Zaktualizuj jako administrator", + "Interactive update": "Interaktywna aktualizacja", + "Uninstall as administrator": "Odinstaluj jako administrator", + "Interactive uninstall": "Interaktywna deinstalacja", + "Uninstall and remove data": "Odinstaluj i usuń dane", + "Not available": "Niedostępne", + "Installer SHA512": "SHA512 instalatora", + "Unknown size": "Nieznany rozmiar", + "No dependencies specified": "Brak wymienionych zależności", + "mandatory": "obowiązkowe", + "optional": "opcjonalne", + "UniGetUI {0} is ready to be installed.": "UniGetUI w wersji {0} jest gotowy do zainstalowania.", + "The update process will start after closing UniGetUI": "Proces aktualizacji rozpocznie się po zamknięciu UniGetUI", + "UniGetUI has been ran as administrator, which is not recommended. When running UniGetUI as administrator, EVERY operation launched from UniGetUI will have administrator privileges. You can still use the program, but we highly recommend not running UniGetUI with administrator privileges.": "UniGetUI został uruchomiony jako administrator, co nie jest zalecane. Gdy UniGetUI działa jako administrator, KAŻDA operacja uruchomiona z UniGetUI będzie miała uprawnienia administratora. Nadal możesz używać programu, ale zdecydowanie zalecamy, aby nie uruchamiać UniGetUI z uprawnieniami administratora.", + "Share anonymous usage data": "Udostępnij anonimowe dane o użytkowaniu", + "UniGetUI collects anonymous usage data in order to improve the user experience.": "UniGetUI zbiera anonimowe dane dotyczące użytkowania w celu poprawy doświadczeń użytkownika.", + "Accept": "Akceptuj", + "Software Updates": "Aktualizacje pakietów", + "Package Bundles": "Paczki pakietów", + "Settings": "Ustawienia", + "Package Managers": "Menedżery pakietów", + "UniGetUI Log": "Dziennik zdarzeń UniGetUI", + "Package Manager logs": "Dziennik zdarzeń menedżera pakietów", + "Operation history": "Historia", + "Help": "Pomoc", + "UniGetUI": "UniGetUI", + "You have installed UniGetUI Version {0}": "Zainstalowano UniGetUI w wersji {0}", + "Disclaimer": "Zastrzeżenie", + "UniGetUI is developed by Devolutions and is not affiliated with any of the compatible package managers.": "UniGetUI jest rozwijany przez Devolutions i nie jest powiązany z żadnym z kompatybilnych menedżerów pakietów.", + "UniGetUI wouldn't have been possible without the help of the contributors. Thank you all 🥳": "UniGetUI nie powstałby bez pomocy kontrybutorów. Dziękuję wam wszystkim 🥳", + "UniGetUI uses the following libraries. Without them, UniGetUI wouldn't have been possible.": "UniGetUI korzysta z następujących bibliotek. Bez nich UniGetUI by nie powstał.", + "{0} homepage": "Strona domowa {0}", + "UniGetUI has been translated to more than 40 languages thanks to the volunteer translators. Thank you 🤝": "UniGetUI został przetłumaczony na ponad 40 języków dzięki tłumaczom-wolontariuszom. Dziękuję 🤝", + "Verbose": "Wyczerpujący", + "1 - Errors": "1 - Błędy", + "2 - Warnings": "2 - Ostrzeżenia", + "3 - Information (less)": "3 - Informacje (mniej)", + "4 - Information (more)": "4 - Informacje (więcej)", + "5 - information (debug)": "5 - Informacje (debug)", + "Warning": "Ostrzeżenie", + "The following settings may pose a security risk, hence they are disabled by default.": "Poniższe ustawienia mogą stanowić zagrożenie, więc domyślnie są dezaktywowane.", + "Enable the settings below if and only if you fully understand what they do, and the implications they may have.": "Włącz poniższe ustawienia TYLKO WTEDY, GDY w pełni rozumiesz, jak działają, oraz jakie mogą wywołać konsekwencje i zagrożenia.", + "The settings will list, in their descriptions, the potential security issues they may have.": "W opisach ustawień zostaną wymienione potencjalne problemy związane z bezpieczeństwem, które mogą one powodować.", + "The backup will include the complete list of the installed packages and their installation options. Ignored updates and skipped versions will also be saved.": "Kopia zapasowa będzie zawierać pełną listę zainstalowanych pakietów i ich opcji instalacji. Zapisane zostaną również zignorowane aktualizacje i pominięte wersje.", + "The backup will NOT include any binary file nor any program's saved data.": "Kopia zapasowa NIE będzie zawierać żadnych plików binarnych ani zapisanych danych programu.", + "The size of the backup is estimated to be less than 1MB.": "Rozmiar kopii zapasowej jest szacowany na mniej niż 1MB.", + "The backup will be performed after login.": "Kopia zapasowa zostanie wykonana po zalogowaniu.", + "{pcName} installed packages": "{pcName} ma zainstalowanych pakietów", + "Current status: Not logged in": "Obecny status: Niezalogowany", + "You are logged in as {0} (@{1})": "Zalogowano jako {0} (@{1})", + "Nice! Backups will be uploaded to a private gist on your account": "Świetnie! Kopie zapasowe zostaną przesłane do prywatnego gistu na Twoim koncie.", + "Select backup": "Wybierz kopię zapasową", + "Settings imported from {0}": "Ustawienia zaimportowane z {0}", + "UniGetUI Settings": "Ustawienia UniGetUI", + "Settings exported to {0}": "Ustawienia wyeksportowane do {0}", + "UniGetUI settings were reset": "Ustawienia UniGetUI zostały zresetowane", + "Allow pre-release versions": "Zezwól na wersje wczesnego dostępu", + "Apply": "Zastosuj", + "For security reasons, custom command-line arguments are disabled by default. Go to UniGetUI security settings to change this.": "Ze względów bezpieczeństwa niestandardowe argumenty wiersza poleceń są domyślnie wyłączone. Aby to zmienić, przejdź do ustawień zabezpieczeń UniGetUI.", + "Go to UniGetUI security settings": "Przejdź do ustawień bezpieczeństwa UniGetUI", + "The following options will be applied by default each time a {0} package is installed, upgraded or uninstalled.": "Następujące opcje będą stosowane domyślnie za każdym razem, gdy pakiet {0} zostanie zainstalowany, zaktualizowany lub odinstalowany.", + "Package's default": "Domyślne ustawienia pakietu", + "Install location can't be changed for {0} packages": "Nie można zmienić lokalizacji instalacji dla {0} pakietów.", + "The local icon cache currently takes {0} MB": "Pamięć podręczna ikon obecnie zajmuje {0} MB", + "Username": "Nazwa użytkownika", + "Password": "Hasło", + "Credentials": "Poświadczenia", + "It is not guaranteed that the provided credentials will be stored safely": "Nie ma gwarancji, że podane poświadczenia będą przechowywane w bezpieczny sposób", + "Partially": "Częściowo", + "Package manager": "Menedżer pakietów", + "Compatible with proxy": "Kompatybilny z proxy", + "Compatible with authentication": "Zgodny z uwierzytelnianiem", + "Proxy compatibility table": "Tabela zgodności serwerów proxy", + "{0} settings": "Ustawienia {0}", + "{0} status": "Status {0}", + "Default installation options for {0} packages": "Domyślne opcje instalacji dla {0} pakietów", + "Expand version": "Rozwiń wersję", + "The executable file for {0} was not found": "Plik wykonywalny dla {0} nie został odnaleziony", + "{pm} is disabled": "{pm} jest wyłączony", + "Enable it to install packages from {pm}.": "Włącz instalację pakietów z {pm}.", + "{pm} is enabled and ready to go": "{pm} jest włączony i gotowy do użycia", + "{pm} version:": "Wersja {pm}:", + "{pm} was not found!": "Nie znaleziono {pm}!", + "You may need to install {pm} in order to use it with UniGetUI.": "Może być konieczne zainstalowanie {pm}, aby używać go z UniGetUI.", + "Scoop Installer - UniGetUI": "Instalator Scoop - UniGetUI", + "Scoop Uninstaller - UniGetUI": "Deinstalator Scoop - UniGetUI", + "Clearing Scoop cache - UniGetUI": "Czyszczenia pamięci podręcznej Scoop - UniGetUI", + "Restart UniGetUI to fully apply changes": "Uruchom ponownie UniGetUI, aby w pełni zastosować zmiany", + "Restart UniGetUI": "Uruchom ponownie UniGetUI", + "Manage {0} sources": "Zarządzaj źródłami {0}", + "Add source": "Dodaj źródło", + "Add": "Dodaj", + "Source name": "Nazwa źródła", + "Source URL": "Adres URL źródła", + "Other": "Inne", + "No minimum age": "Brak minimalnego wieku", + "1 day": "1 dzień", + "{0} days": "{0} dni", + "Custom...": "Niestandardowe...", + "{0} minutes": "{0} minut", + "1 hour": "1 godzina", + "{0} hours": "{0} godzin(y)", + "1 week": "1 tydzień", + "Supports release dates": "Obsługuje daty wydań", + "Release date support per package manager": "Obsługa dat wydań według menedżera pakietów", + "Search for packages": "Wyszukaj pakiety", + "Local": "Lokalnie", + "OK": "Potwierdź", + "Last checked: {0}": "Ostatnio sprawdzono: {0}", + "{0} packages were found, {1} of which match the specified filters.": "Znaleziono {0} pakietów, z których {1} pasuje do określonych filtrów.", + "{0} selected": "{0} wybranych", + "(Last checked: {0})": "(Ostatnio sprawdzane: {0})", + "All packages selected": "Wybrano wszystkie pakiety", + "Package selection cleared": "Wyczyszczono wybór pakietów", + "{0}: {1}": "{0}: {1}", + "More info": "Więcej informacji", + "GitHub account": "Konto GitHub", + "Log in with GitHub to enable cloud package backup.": "Zaloguj się do GitHub, aby umożliwić tworzenie kopii zapasowych pakietów w chmurze.", + "More details": "Więcej szczegółów", + "Log in": "Zaloguj się", + "If you have cloud backup enabled, it will be saved as a GitHub Gist on this account": "Jeśli aktywowano kopię zapasową w chmurze, będzie ona zapisywana jako GitHub Gist na tym koncie", + "Log out": "Wyloguj się", + "About UniGetUI": "O UniGetUI", + "About": "O programie", + "Third-party licenses": "Licencje zewnętrzne", + "Contributors": "Kontrybutorzy", + "Translators": "Tłumacze", + "Bundle security report": "Raport bezpieczeństwa paczki", + "The bundle contained restricted content": "Paczka zawierała ograniczoną zawartość", + "UniGetUI – Crash Report": "UniGetUI – Raport o awarii", + "UniGetUI has crashed": "UniGetUI uległ awarii", + "Help us fix this by sending a crash report to Devolutions. All fields below are optional.": "Pomóż nam to naprawić, wysyłając raport o awarii do Devolutions. Wszystkie poniższe pola są opcjonalne.", + "Email (optional)": "E-mail (opcjonalnie)", + "your@email.com": "twoj@email.com", + "Additional details (optional)": "Dodatkowe szczegóły (opcjonalnie)", + "Describe what you were doing when the crash occurred…": "Opisz, co robiłeś/robiłaś, gdy wystąpiła awaria…", + "Crash report": "Raport o awarii", + "Don't Send": "Nie wysyłaj", + "Send Report": "Wyślij raport", + "Sending…": "Wysyłanie…", + "Unsaved changes": "Niezapisane zmiany", + "You have unsaved changes in the current bundle. Do you want to discard them?": "W bieżącej paczce są niezapisane zmiany. Czy chcesz je odrzucić?", + "Discard changes": "Odrzuć zmiany", + "Integrity violation": "Naruszenie integralności", + "UniGetUI or some of its components are missing or corrupt. It is strongly recommended to reinstall UniGetUI to adress the situation.": "Brakuje UniGetUI lub niektórych jego składników albo są one uszkodzone. Zdecydowanie zaleca się ponowną instalację UniGetUI, aby rozwiązać ten problem.", + "• Refer to the UniGetUI Logs to get more details regarding the affected file(s)": "• Zapoznaj się z dziennikami UniGetUI, aby uzyskać więcej szczegółów dotyczących pliku(ów), których dotyczy problem", + "• Integrity checks can be disabled from the Experimental Settings": "• Sprawdzanie spójności może zostać wyłączone w Ustawieniach Eksperymentalnych", + "Manage shortcuts": "Zarządzaj skrótami", + "UniGetUI has detected the following desktop shortcuts which can be removed automatically on future upgrades": "UniGetUI wykrył następujące skróty na pulpicie, które mogą zostać automatycznie usunięte podczas przyszłych aktualizacji", + "Do you really want to reset this list? This action cannot be reverted.": "Czy naprawdę chcesz zresetować tę listę? Tej akcji nie można cofnąć.", + "Desktop shortcuts list": "Lista skrótów na pulpicie", + "Open in explorer": "Otwórz w eksploratorze", + "Remove from list": "Usuń z listy", + "When new shortcuts are detected, delete them automatically instead of showing this dialog.": "Gdy zostaną wykryte nowe skróty, usuń je automatycznie zamiast wyświetlać to okno dialogowe.", + "Not right now": "Nie teraz", + "Missing dependency": "Brakująca zależność", + "UniGetUI requires {0} to operate, but it was not found on your system.": "UniGetUI wymaga {0} do działania, lecz nie został znaleziony w systemie.", + "Click on Install to begin the installation process. If you skip the installation, UniGetUI may not work as expected.": "Kliknij Zainstaluj by rozpocząć instalację. Jeżeli ją pominiesz, UniGetUI może nie działać jak należy.", + "Alternatively, you can also install {0} by running the following command in a Windows PowerShell prompt:": "Alternatywnie, możesz zainstalować {0}, poprzez wykonanie odpowiedniej komendy w Windows PowerShell:", + "Install {0}": "Zainstaluj {0}", + "Do not show this dialog again for {0}": "Nie pokazuj ponownie tego okna dialogowego dla {0}", + "Please wait while {0} is being installed. A black window may show up. Please wait until it closes.": "Proszę czekać aż do zakończenia instalacji {0}. Może pojawić się czarne okno. Poczekaj aż ono się zamknie.", + "{0} has been installed successfully.": "{0} zainstalowano pomyślnie.", + "Please click on \"Continue\" to continue": "Kliknij \"Kontynuuj\", aby kontynuować", + "Continue": "Kontynuuj", + "{0} has been installed successfully. It is recommended to restart UniGetUI to finish the installation": "{0} zainstalowano pomyślnie. Zalecany jest restart UniGetUI by dokończyć instalację", + "Restart later": "Uruchom ponownie później", + "An error occurred:": "Wystąpił błąd:", + "Please see the Command-line Output or refer to the Operation History for further information about the issue.": "Więcej informacji na ten temat można znaleźć w Wyjściu wiersza poleceń lub w Historii operacji.", + "Retry as administrator": "Spróbuj ponownie jako administrator", + "Retry interactively": "Ponów interaktywnie", + "Retry skipping integrity checks": "Ponów próbę, pomijając sprawdzanie spójności", + "Installation options": "Opcje instalacji", + "Save": "Zapisz", + "UniGetUI collects anonymous usage data with the sole purpose of understanding and improving the user experience.": "UniGetUI zbiera anonimowe dane dotyczące użytkowania w celu zrozumienia i poprawy doświadczeń użytkownika.", + "More details about the shared data and how it will be processed": "Więcej szczegółów na temat udostępnianych danych i sposobu ich przetwarzania", + "Do you accept that UniGetUI collects and sends anonymous usage statistics, with the sole purpose of understanding and improving the user experience?": "Czy zgadzasz się, że UniGetUI zbiera i wysyła anonimowe statystyki użytkowania, wyłącznie w celu zrozumienia i poprawy doświadczenia użytkownika?", + "Decline": "Odrzuć", + "No personal information is collected nor sent, and the collected data is anonimized, so it can't be back-tracked to you.": "Nie gromadzimy ani nie przesyłamy żadnych danych osobowych. Zebrane dane są anonimizowane, więc nie ma możliwości ich powiązania z Twoją osobą.", + "Navigation panel": "Panel nawigacji", + "Operations": "Operacje", + "Toggle operations panel": "Przełącz panel operacji", + "Bulk operations": "Operacje zbiorcze", + "Retry failed": "Ponów nieudane", + "Clear successful": "Wyczyść zakończone powodzeniem", + "Clear finished": "Wyczyść zakończone", + "Cancel all": "Anuluj wszystko", + "More": "Więcej", + "Toggle navigation panel": "Przełącz panel nawigacyjny", + "Minimize": "Minimalizuj", + "Maximize": "Maksymalizuj", + "UniGetUI by Devolutions": "UniGetUI od Devolutions", + "UniGetUI is an application that makes managing your software easier, by providing an all-in-one graphical interface for your command-line package managers.": "UniGetUI to aplikacja, która ułatwia zarządzanie oprogramowaniem, zapewniając kompleksowy interfejs graficzny dla menedżerów pakietów wiersza poleceń.", + "Useful links": "Użyteczne adresy", + "UniGetUI Homepage": "Strona główna UniGetUI", + "Report an issue or submit a feature request": "Zgłoś problem lub prośbę o dodanie funkcji", + "UniGetUI Repository": "Repozytorium UniGetUI", + "View GitHub Profile": "Zobacz profil na GitHub", + "UniGetUI License": "Licencja UniGetUI", + "Using UniGetUI implies the acceptation of the MIT License": "Korzystanie z UniGetUI oznacza akceptację licencji MIT.", + "Become a translator": "Zostań tłumaczem", + "Go back": "Wstecz", + "Go forward": "Do przodu", + "Go to home page": "Przejdź do strony głównej", + "Reload page": "Odśwież stronę", + "View page on browser": "Zobacz w przeglądarce", + "The built-in browser is not supported on Linux yet.": "Wbudowana przeglądarka nie jest jeszcze obsługiwana w systemie Linux.", + "Open in browser": "Otwórz w przeglądarce", + "Copy to clipboard": "Kopiuj do schowka", + "Export to a file": "Eksportuj do pliku", + "Log level:": "Poziom logowania:", + "Reload log": "Przeładuj dziennik", + "Export log": "Eksportuj dziennik", + "Text": "Tekst", + "Change how operations request administrator rights": "Zmień sposób, w jaki operacje żądają uprawnień administratora", + "Restrictions on package operations": "Ograniczenia dotyczące operacji związanych z pakietami", + "Restrictions on package managers": "Ograniczenia menedżerów pakietów", + "Restrictions when importing package bundles": "Ograniczenia podczas importowania paczek pakietów", + "Ask for administrator privileges once for each batch of operations": "Poproś o uprawnienia administratora raz dla każdej grupy operacji", + "Ask only once for administrator privileges": "Pytaj tylko raz o uprawnienia administratora", + "Prohibit any kind of Elevation via UniGetUI Elevator or GSudo": "Zabroń wszelkiego rodzaju podnoszenia za pomocą UniGetUI Elevator lub GSudo.", + "This option WILL cause issues. Any operation incapable of elevating itself WILL FAIL. Install/update/uninstall as administrator will NOT WORK.": "Ta opcja SPOWODUJE problemy. Każda operacja, która nie może uzyskać uprawnień administratora, zakończy się niepowodzeniem. Instalacja/aktualizacja/deinstalacja jako administrator NIE BĘDZIE DZIAŁAĆ.", + "Allow custom command-line arguments": "Zezwalaj na niestandardowe argumenty wiersza poleceń", + "Custom command-line arguments can change the way in which programs are installed, upgraded or uninstalled, in a way UniGetUI cannot control. Using custom command-lines can break packages. Proceed with caution.": "Niestandardowe argumenty wiersza poleceń mogą zmienić sposób, w jaki programy są instalowane, uaktualniane lub odinstalowywane, w sposób, którego UniGetUI nie będzie w stanie kontrolować. Używanie niestandardowych wierszy poleceń może uszkodzić pakiety. Postępuj ostrożnie.", + "Ignore custom pre-install and post-install commands when importing packages from a bundle": "Zezwól na uruchamianie niestandardowych poleceń przed i po instalacji.", + "Pre and post install commands will be run before and after a package gets installed, upgraded or uninstalled. Be aware that they may break things unless used carefully": "Polecenia wykonywane przed i po instalacji, zostaną uruchomione przed i po zainstalowaniu, uaktualnieniu lub odinstalowaniu pakietu. Należy pamiętać, że mogą one coś zepsuć, jeśli nie zostaną użyte z rozwagą", + "Allow changing the paths for package manager executables": "Zezwól na modyfikowanie ścieżek dla plików wykonalnych menedżerów pakietów", + "Turning this on enables changing the executable file used to interact with package managers. While this allows finer-grained customization of your install processes, it may also be dangerous": "Włączenie tej opcji umożliwia zmianę pliku wykonywalnego używanego do interakcji z menedżerami pakietów. Chociaż pozwala to na bardziej szczegółowe dostosowanie procesów instalacji, może być również niebezpieczne.", + "Allow importing custom command-line arguments when importing packages from a bundle": "Zezwalaj na importowanie niestandardowych argumentów wiersza poleceń podczas importowania pakietów z paczki", + "Malformed command-line arguments can break packages, or even allow a malicious actor to gain privileged execution. Therefore, importing custom command-line arguments is disabled by default": "Błędnie sformułowane argumenty wiersza poleceń mogą uszkodzić pakiety lub nawet umożliwić atakującemu wykonanie kodu z podwyższonymi uprawnieniami. Z tego powodu, importowanie niestandardowych argumentów jest domyślnie wyłączone", + "Allow importing custom pre-install and post-install commands when importing packages from a bundle": "Zezwól na importowanie niestandardowych komend przed- i poinstalacyjnych podczas importowania pakietów z paczki", + "Pre and post install commands can do very nasty things to your device, if designed to do so. It can be very dangerous to import the commands from a bundle, unless you trust the source of that package bundle": "Polecenia wykonywane przed i po instalacji, mogą wyrządzić poważne szkody Twojemu urządzeniu, jeśli zostały do tego celowo zaprojektowane. Importowanie poleceń z pakietu bywa bardzo niebezpieczne, chyba że masz pełne zaufanie do jego źródła", + "Administrator rights and other dangerous settings": "Uprawnienia administratora i inne niebezpieczne ustawienia", + "Package backup": "Kopia zapasowa pakietów", + "Cloud package backup": "Kopia zapasowa pakietów w chmurze", + "Local package backup": "Lokalna kopia zapasowa", + "Local backup advanced options": "Opcje zaawansowane lokalnej kopii zapasowej", + "Log in with GitHub": "Zaloguj się do GitHub", + "Log out from GitHub": "Wyloguj się z GitHub", + "Periodically perform a cloud backup of the installed packages": "Okresowo wykonuj kopię zapasową zainstalowanych pakietów w chmurze", + "Cloud backup uses a private GitHub Gist to store a list of installed packages": "Kopia zapasowa w chmurze wykorzystuje prywatny GitHub Gist do przechowywania listy zainstalowanych pakietów", + "Perform a cloud backup now": "Utwórz kopię zapasową w chmurze teraz", + "Backup": "Kopia zapasowa", + "Restore a backup from the cloud": "Przywróć kopię zapasową z chmury", + "Begin the process to select a cloud backup and review which packages to restore": "Rozpocznij proces wyboru kopii zapasowej w chmurze i sprawdź, które pakiety chcesz przywrócić.", + "Periodically perform a local backup of the installed packages": "Okresowo wykonuj lokalną kopię zapasową zainstalowanych pakietów", + "Perform a local backup now": "Utwórz lokalną kopię zapasową teraz", + "Change backup output directory": "Zmień katalog wyjściowy dla kopii zapasowej", + "Set a custom backup file name": "Ustaw własną nazwę pliku z kopią zapasową", + "Leave empty for default": "Zostaw puste dla ustawień domyślnych", + "Add a timestamp to the backup file names": "Dodaj znacznik czasu do nazwy plików kopii zapasowych", + "Backup and Restore": "Tworzenie i przywracanie kopii zapasowej", + "Enable background api (UniGetUI Widgets and Sharing, port 7058)": "Włącz API w tle (Widgets for UniGetUI and Sharing, port 7058)", + "Wait for the device to be connected to the internet before attempting to do tasks that require internet connectivity.": "Przed przystąpieniem do wykonywania zadań wymagających połączenia internetowego należy zaczekać, aż urządzenie zostanie połączone z internetem.", + "Disable the 1-minute timeout for package-related operations": "Wyłącz 1-minutowy limit czasu dla operacji pakietów", + "Use installed GSudo instead of UniGetUI Elevator": "Użyj zainstalowanego GSudo zamiast UniGetUI Elevator", + "Use a custom icon and screenshot database URL": "Użyj niestandardowej ikony i adresu URL bazy danych zrzutów ekranu", + "Enable background CPU Usage optimizations (see Pull Request #3278)": "Włącz optymalizacje wykorzystania procesora w tle (patrz Pull Request #3278).", + "Perform integrity checks at startup": "Sprawdź spójność podczas uruchamiania", + "When batch installing packages from a bundle, install also packages that are already installed": "Podczas instalacji pakietów z paczki, zainstaluj również pakiety, które są już zainstalowane.", + "Experimental settings and developer options": "Eksperymentalne ustawienia i opcje deweloperskie", + "Show UniGetUI's version and build number on the titlebar.": "Pokaż wersję UniGetUI na pasku tytułowym", + "Language": "Język", + "UniGetUI updater": "Aktualizator UniGetUI ", + "Telemetry": "Telemetria", + "Manage UniGetUI settings": "Zarządzaj ustawieniami UniGetUI", + "Related settings": "Powiązane ustawienia", + "Update UniGetUI automatically": "Aktualizuj UniGetUI automatycznie", + "Check for updates": "Sprawdź aktualizacje", + "Install prerelease versions of UniGetUI": "Zainstaluj wstępne wersje UniGetUI", + "Manage telemetry settings": "Zarządzaj ustawieniami telemetrii", + "Manage": "Zarządzaj", + "Import settings from a local file": "Importuj ustawienia z pliku", + "Import": "Importuj", + "Export settings to a local file": "Eksportuj ustawienia do pliku", + "Export": "Eksport", + "Reset UniGetUI": "Zresetuj UniGetUI", + "User interface preferences": "Ustawienia interfejsu użytkownika", + "Application theme, startup page, package icons, clear successful installs automatically": "Motyw aplikacji, strona startowa, ikony pakietów, wyczyść pomyślne instalacje automatycznie", + "General preferences": "Ogólne ustawienia", + "UniGetUI display language:": "Język interfejsu UniGetUI:", + "System language": "Język systemu", + "Is your language missing or incomplete?": "Czy brakuje Twojego języka lub jest on niekompletny?", + "Appearance": "Wygląd", + "UniGetUI on the background and system tray": "UniGetUI na tle i pasku zadań", + "Package lists": "Lista pakietów", + "Use classic mode": "Użyj trybu klasycznego", + "Restart UniGetUI to apply this change": "Uruchom ponownie UniGetUI, aby zastosować tę zmianę", + "The classic UI is disabled for beta testers": "Klasyczny interfejs użytkownika jest wyłączony dla beta testerów", + "Close UniGetUI to the system tray": "Zamknij UniGetUI do paska zadań", + "Manage UniGetUI autostart behaviour": "Zarządzaj zachowaniem autostartu UniGetUI", + "Show package icons on package lists": "Pokaż ikony pakietu na liście pakietów", + "Clear cache": "Wyczyść pamięć podręczną", + "Select upgradable packages by default": "Wybierz domyślnie pakiety z możliwością aktualizacji", + "Light": "Jasny", + "Dark": "Ciemny", + "Follow system color scheme": "Zgodnie ze schematem kolorów systemu", + "Application theme:": "Motyw aplikacji:", + "UniGetUI startup page:": "Strona startowa UniGetUI:", + "Proxy settings": "Ustawienia proxy", + "Other settings": "Inne ustawienia", + "Connect the internet using a custom proxy": "Połącz przy pomocy własnego proxy", + "Please note that not all package managers may fully support this feature": "Nie wszystkie menedżery pakietów mogą w pełni obsługiwać tę funkcję", + "Proxy URL": "Adres serwera proxy", + "Enter proxy URL here": "Wprowadź tutaj adres serwera proxy", + "Authenticate to the proxy with a user and a password": "Uwierzytelnij się w serwerze proxy za pomocą nazwy użytkownika i hasła", + "Internet and proxy settings": "Ustawienia Internetu i proxy", + "Package manager preferences": "Preferencje menedżerów pakietów", + "Ready": "Gotowy", + "Not found": "Nie znaleziono", + "Notification preferences": "Ustawienia powiadomień", + "Notification types": "Typy powiadomień", + "The system tray icon must be enabled in order for notifications to work": "Aby powiadomienia działały, ikona na pasku zadań musi być włączona", + "Enable UniGetUI notifications": "Włącz powiadomienia UniGetUI", + "Show a notification when there are available updates": "Wyświetl powiadomienie gdy aktualizacje są dostępne", + "Show a silent notification when an operation is running": "Pokaż ciche powiadomienie gdy operacja jest wykonywana", + "Show a notification when an operation fails": "Pokaż powiadomienie gdy operacja się nie powiedzie", + "Show a notification when an operation finishes successfully": "Pokaż powiadomienie gdy operacja się powiedzie", + "Concurrency and execution": "Równoczesność i wykonywanie zadań", + "Automatic desktop shortcut remover": "Automatyczne narzędzie do usuwania skrótów z pulpitu", + "Choose how many operations should be performed in parallel": "Wybierz, ile operacji ma być wykonywanych równolegle", + "Clear successful operations from the operation list after a 5 second delay": "Wyczyść pomyślne operacje z listy operacji po 5 sekundach przerwy", + "Download operations are not affected by this setting": "To ustawienie nie ma wpływu na operacje pobierania", + "You may lose unsaved data": "Możesz utracić niezapisane dane", + "Ask to delete desktop shortcuts created during an install or upgrade.": "Zapytaj czy usunąć ikony stworzone podczas instalacji lub aktualizacji.", + "Package update preferences": "Preferencje aktualizacji pakietów", + "Update check frequency, automatically install updates, etc.": "Częstotliwość sprawdzania aktualizacji, automatyczna instalacja aktualizacji itp.", + "Reduce UAC prompts, elevate installations by default, unlock certain dangerous features, etc.": "Zmniejsz liczbę monitów UAC, domyślnie podnoś uprawnienia instalacji, odblokuj niektóre niebezpieczne funkcje itp.", + "Package operation preferences": "Preferencje operacji na pakietach", + "Enable {pm}": "Włącz {pm}", + "Not finding the file you are looking for? Make sure it has been added to path.": "Nie możesz znaleźć pliku, którego szukasz? Upewnij się, że został on dodany do ścieżki.", + "Select the executable to be used. The following list shows the executables found by UniGetUI": "Wybierz plik wykonywalny, który ma zostać użyty. Poniższa lista zawiera pliki wykonywalne znalezione przez UniGetUI.", + "For security reasons, changing the executable file is disabled by default": "Ze względów bezpieczeństwa zmiana pliku wykonywalnego jest domyślnie wyłączona.", + "Change this": "Zmień to", + "Copy path": "Kopiuj ścieżkę", + "Current executable file:": "Aktualny plik wykonywalny:", + "Ignore packages from {pm} when showing a notification about updates": "Ignoruj pakiety z {pm} podczas wyświetlania powiadomień o aktualizacjach", + "Update security": "Bezpieczeństwo aktualizacji", + "Use global setting": "Użyj ustawienia globalnego", + "Minimum age for updates": "Minimalny wiek aktualizacji", + "e.g. 10": "np. 10", + "Custom minimum age (days)": "Niestandardowy minimalny wiek (dni)", + "{pm} does not provide release dates for its packages, so this setting will have no effect": "{pm} nie udostępnia dat wydań swoich pakietów, więc to ustawienie nie będzie miało żadnego efektu", + "{pm} only provides release dates for some of its packages, so this setting will only apply to those packages": "{pm} udostępnia daty wydania tylko dla niektórych swoich pakietów, dlatego to ustawienie będzie obowiązywać wyłącznie dla tych pakietów", + "Override the global minimum update age for this package manager": "Zastąp globalny minimalny wiek aktualizacji dla tego menedżera pakietów", + "View {0} logs": "Zobacz logi {0}", + "If Python cannot be found or is not listing packages but is installed on the system, ": "Jeśli nie można znaleźć Pythona albo nie wyświetla pakietów, mimo że jest zainstalowany w systemie, ", + "Advanced options": "Zaawansowane", + "WinGet command-line tool": "Narzędzie wiersza polecenia WinGet", + "Choose which command-line tool UniGetUI uses for WinGet operations when the COM API is not used": "Wybierz narzędzie wiersza poleceń, którego UniGetUI używa do operacji WinGet, gdy COM API nie jest używany", + "WinGet COM API": "Interfejs API COM WinGet", + "Choose whether UniGetUI can use the WinGet COM API before falling back to the command-line tool": "Wybierz, czy UniGetUI może używać COM API WinGet przed powrotem do narzędzia wiersza poleceń", + "Reset WinGet": "Zresetuj WinGet", + "This may help if no packages are listed": "To może pomóc, gdy żadne pakiety nie są pokazywane", + "Force install location parameter when updating packages with custom locations": "Wymuś parametr lokalizacji instalacji podczas aktualizacji pakietów z niestandardowymi lokalizacjami", + "Install Scoop": "Zainstaluj Scoop", + "Uninstall Scoop (and its packages)": "Odinstaluj Scoop (i jego pakiety)", + "Run cleanup and clear cache": "Uruchom czyszczenie i wyczyść pamięć podręczną", + "Run": "Uruchom", + "Enable Scoop cleanup on launch": "Włącz czyszczenie Scoop podczas uruchamiania", + "Default vcpkg triplet": "Domyślne zmienne potrójne vcpkg", + "Change vcpkg root location": "Zmień lokalizację katalogu głównego vcpkg", + "Reset vcpkg root location": "Resetuj lokalizację katalogu głównego vcpkg", + "Open vcpkg root location": "Otwórz lokalizację katalogu głównego vcpkg", + "Language, theme and other miscellaneous preferences": "Język, motyw i inne preferencje", + "Show notifications on different events": "Pokaż powiadomienia o różnych wydarzeniach", + "Change how UniGetUI checks and installs available updates for your packages": "Zmień sposób, w jaki UniGetUI sprawdza i instaluje dostępne aktualizacje pakietów.", + "Automatically save a list of all your installed packages to easily restore them.": "Automatyczne zapisywanie listy wszystkich zainstalowanych pakietów w celu ich łatwego przywrócenia.", + "Enable and disable package managers, change default install options, etc.": "Aktywuj i dezaktywuj menedżery pakietów, zmień domyślne ustawienia instalacji, etc.", + "Internet connection settings": "Ustawienia połączenia internetowego", + "Proxy settings, etc.": "Ustawienia proxy itp.", + "Beta features and other options that shouldn't be touched": "Funkcje beta i inne opcje, które nie powinny być używane", + "Reload sources": "Odśwież źródła", + "Delete source": "Usuń źródło", + "Known sources": "Znane źródła", + "Update checking": "Sprawdzanie aktualizacji", + "Automatic updates": "Automatyczne aktualizacje", + "Check for package updates periodically": "Okresowo sprawdzaj dostępność aktualizacji pakietów", + "Check for updates every:": "Sprawdzaj aktualizacje co:", + "Install available updates automatically": "Automatyczne instaluj dostępne aktualizacje", + "Do not automatically install updates when the network connection is metered": "Nie instaluj automatycznie aktualizacji, gdy połączenie sieciowe jest taryfowe", + "Do not automatically install updates when the device runs on battery": "Nie instaluj automatycznie aktualizacji, gdy urządzenie jest zasilane z baterii", + "Do not automatically install updates when the battery saver is on": "Nie instaluj automatycznie aktualizacji, gdy oszczędzanie baterii jest włączone", + "Only show updates that are at least the specified number of days old": "Pokazuj tylko aktualizacje, które mają co najmniej określoną liczbę dni", + "Warn me when the installer URL host changes between the installed version and the new version (WinGet only)": "Ostrzegaj mnie, gdy host adresu URL instalatora zmieni się między zainstalowaną wersją a nową wersją (tylko WinGet)", + "Change how UniGetUI handles install, update and uninstall operations.": "Zmień sposób, w jaki UniGetUI obsługuje operacje instalacji, aktualizacji i odinstalowywania.", + "Navigation": "Nawigacja", + "Check for UniGetUI updates": "Sprawdź aktualizacje UniGetUI", + "Quit UniGetUI": "Zamknij UniGetUI", + "Filters": "Filtry", + "Sources": "Źródła", + "Search for packages to start": "Żeby zacząć, wyszukaj pakiety", + "Select all": "Zaznacz wszystkie", + "Clear selection": "Wyczyść wybór", + "Instant search": "Natychmiastowe wyszukiwanie", + "Distinguish between uppercase and lowercase": "Rozróżniaj wielke i małe litery", + "Ignore special characters": "Ignoruj znaki specjalne", + "Search mode": "Tryb wyszukiwania", + "Both": "Oba", + "Exact match": "Dokładne dopasowanie", + "Show similar packages": "Pokaż podobne pakiety", + "Loading": "Ładowanie", + "Package": "Pakiet", + "More options": "Więcej opcji", + "Order by:": "Sortuj według:", + "Name": "Nazwa", + "Id": "ID", + "Ascendant": "Rosnąco", + "Descendant": "Malejąco", + "View modes": "Tryby widoku", + "Reload": "Odśwież", + "Closed": "Zamknięte", + "Ascending": "Rosnąco", + "Descending": "Malejąco", + "{0}: {1}, {2}": "{0}: {1}, {2}", + "Order by": "Sortuj według", + "No results were found matching the input criteria": "Nie znaleziono żadnych wyników spełniających podane kryteria", + "No packages were found": "Nie znaleziono pakietów", + "Loading packages": "Wczytywanie pakietów", + "Skip integrity checks": "Pomiń sprawdzanie spójności", + "Download selected installers": "Pobierz wybrane instalatory", + "Install selection": "Zainstaluj wybrane", + "Install options": "Opcje instalacji", + "Add selection to bundle": "Dodaj wybrane do pakietu", + "Download installer": "Pobierz instalator", + "Uninstall selection": "Odinstaluj wybrane", + "Uninstall options": "Opcje dezinstalacji", + "Ignore selected packages": "Ignoruj zaznaczone pakiety", + "Open install location": "Otwórz lokalizację instalacji", + "Reinstall package": "Zainstaluj pakiet ponownie", + "Uninstall package, then reinstall it": "Odinstaluj i ponownie zainstaluj pakiet", + "Ignore updates for this package": "Zignoruj aktualizacje tego pakietu", + "WinGet malfunction detected": "Wykryto awarię WinGet", + "It looks like WinGet is not working properly. Do you want to attempt to repair WinGet?": "Wygląda na to, że WinGet nie działa prawidłowo. Czy podjąć próbę naprawy WinGet?", + "Repair WinGet": "Napraw WinGet", + "Updates will no longer be ignored for {0}": "Aktualizacje nie będą już ignorowane dla {0}", + "Updates are now ignored for {0}": "Aktualizacje są teraz ignorowane dla {0}", + "Do not ignore updates for this package anymore": "Nie ignoruj już aktualizacji dla tego pakietu", + "Add packages or open an existing package bundle": "Dodaj paczki albo otwórz istniejącą paczkę pakietów", + "Add packages to start": "Żeby zacząć, dodaj paczki", + "The current bundle has no packages. Add some packages to get started": "Obecna paczka nie zawiera pakietów. Dodaj pakiety aby rozpocząć", + "New": "Nowy", + "Save as": "Zapisz jako", + "Create .ps1 script": "Utwórz skrypt .ps1", + "Remove selection from bundle": "Usuń wybrane z paczki", + "Skip hash checks": "Pomiń weryfikacje hash'a", + "The package bundle is not valid": "Paczka pakietów jest nieprawidłowa", + "The bundle you are trying to load appears to be invalid. Please check the file and try again.": "Paczka, którą próbujesz załadować, jest nieprawidłowa. Sprawdź proszę plik i spróbuj ponownie.", + "Package bundle": "Paczka pakietów", + "Could not create bundle": "Nie można utworzyć paczki", + "The package bundle could not be created due to an error.": "Nie można utworzyć paczki pakietów z powodu błędu.", + "Install script": "Zainstaluj skrypt", + "PowerShell script": "Skrypt PowerShell", + "The installation script saved to {0}": "Skrypt instalacyjny zapisany w {0}", + "An error occurred": "Wystąpił błąd", + "An error occurred while attempting to create an installation script:": "Wystąpił błąd podczas próby utworzenia skryptu instalacyjnego:", + "Hooray! No updates were found.": "Super! Nie znaleziono żadnych aktualizacji.", + "Uninstall selected packages": "Odinstaluj wybrane pakiety", + "Update selection": "Zaktualizuj wybrane", + "Update options": "Opcje aktualizacji", + "Uninstall package, then update it": "Odinstaluj, a potem zaktualizuj pakiet", + "Uninstall package": "Odinstaluj pakiet", + "Skip this version": "Pomiń tę wersję", + "Pause updates for": "Wstrzymaj aktualizacje na", + "User | Local": "Użytkownik | lokalnie", + "Machine | Global": "Komputer | globalnie", + "The default package manager for Debian/Ubuntu-based Linux distributions.
Contains: Debian/Ubuntu packages": "Domyślny menedżer pakietów dla dystrybucji Linuksa opartych na Debianie/Ubuntu.
Zawiera: pakiety Debian/Ubuntu", + "The Rust package manager.
Contains: Rust libraries and programs written in Rust": "Menedżer pakietów Rust.
Zawiera: biblioteki Rust oraz programy napisane w Rust", + "The classical package manager for windows. You'll find everything there.
Contains: General Software": "Klasyczny menedżer pakietów dla Windows. Znajdziesz tam wszystko.
Zawiera: ogólne oprogramowanie", + "The default package manager for RHEL/Fedora-based Linux distributions.
Contains: RPM packages": "Domyślny menedżer pakietów dla dystrybucji Linuksa opartych na RHEL/Fedora.
Zawiera: pakiety RPM", + "A repository full of tools and executables designed with Microsoft's .NET ecosystem in mind.
Contains: .NET related tools and scripts": "Repozytorium zawierające pełny pakiet narzędzi i plików wykonywalnych zaprojektowanych z myślą o ekosystemie .NET firmy Microsoft.
Zawiera: narzędzia i skrypty powiązane z .NET", + "The universal Linux package manager for desktop applications.
Contains: Flatpak applications from configured remotes": "Uniwersalny menedżer pakietów systemu Linux dla aplikacji desktopowych.
Zawiera: aplikacje Flatpak ze skonfigurowanych zdalnych repozytoriów", + "NuPkg (zipped manifest)": "NuPkg (spakowany manifest)", + "The Missing Package Manager for macOS (or Linux).
Contains: Formulae, Casks": "Brakujący menedżer pakietów dla macOS (lub Linuksa).
Zawiera: Formulae, Casks", + "Node JS's package manager. Full of libraries and other utilities that orbit the javascript world
Contains: Node javascript libraries and other related utilities": "Mendedżer pakietów NodeJS. Pełen bibliotek i innych narzędzi, które krążą po świecie JavaScriptu
Zawiera: biblioteki javascriptowe dla Node i powiązane narzędzia", + "The default package manager for Arch Linux and its derivatives.
Contains: Arch Linux packages": "Domyślny menedżer pakietów dla Arch Linuksa i jego pochodnych.
Zawiera: pakiety Arch Linux", + "Python's library manager. Full of python libraries and other python-related utilities
Contains: Python libraries and related utilities": "Menedżer bibliotek Pythona. Pełen bibliotek Pythona i innych narzędzi związanych z Pythonem
Zawiera: biblioteki Pythona i powiązane narzędzia", + "PowerShell's package manager. Find libraries and scripts to expand PowerShell capabilities
Contains: Modules, Scripts, Cmdlets": "Menedżer pakietów PowerShella. Znajdź biblioteki i skrypty, aby rozszerzyć możliwości PowerShella
Zawiera: moduły, skrypty, polecenia", + "extracted": "wypakowany", + "Scoop package": "Pakiet Scoop", + "Great repository of unknown but useful utilities and other interesting packages.
Contains: Utilities, Command-line programs, General Software (extras bucket required)": "Świetne repozytorium nieznanych, ale przydatnych narzędzi i innych interesujących pakietów.
Zawiera: narzędzia, programy wiersza poleceń, ogólne oprogramowanie (wymagane dodatkowe repozytorium)", + "The universal Linux package manager by Canonical.
Contains: Snap packages from the Snapcraft store": "Uniwersalny menedżer pakietów Linux od Canonical.
Zawiera: pakiety Snap ze sklepu Snapcraft", + "library": "biblioteka", + "feature": "funkcja", + "A popular C/C++ library manager. Full of C/C++ libraries and other C/C++-related utilities
Contains: C/C++ libraries and related utilities": "Popularny menedżer bibliotek C/C++. Pełen bibliotek C/C++ i innych narzędzi związanych z C/C++
Zawiera: biblioteki C/C++ i powiązane narzędzia", + "option": "opcja", + "This package cannot be installed from an elevated context.": "Tego pakietu nie można zainstalować z podwyższonego kontekstu.", + "Please run UniGetUI as a regular user and try again.": "Uruchom UniGetUI jako zwykły użytkownik i spróbuj ponownie.", + "Please check the installation options for this package and try again": "Sprawdź opcje instalacji tego pakietu i spróbuj ponownie", + "Microsoft's official package manager. Full of well-known and verified packages
Contains: General Software, Microsoft Store apps": "Oficjalny menedżer pakietów firmy Microsoft. Pełen dobrze znanych i zweryfikowanych pakietów
Zawiera: ogólne oprogramowanie, aplikacje Microsoft Store", + "Local PC": "Komputer", + "Android Subsystem": "Podsystem Android", + "Operation on queue (position {0})...": "Operacja jest w kolejce (pozycja {0})...", + "Click here for more details": "Kliknij tutaj, aby uzyskać więcej szczegółów", + "Operation canceled by user": "Operacja anulowana przez użytkownika", + "Running PreOperation ({0}/{1})...": "Trwa wykonywanie PreOperation ({0}/{1})...", + "PreOperation {0} out of {1} failed, and was tagged as necessary. Aborting...": "PreOperation {0} z {1} zakończyła się niepowodzeniem i została oznaczona jako wymagana. Przerywanie...", + "PreOperation {0} out of {1} finished with result {2}": "PreOperation {0} z {1} zakończyła się z wynikiem {2}", + "Starting operation...": "Rozpoczęcie działania...", + "Running PostOperation ({0}/{1})...": "Trwa wykonywanie PostOperation ({0}/{1})...", + "PostOperation {0} out of {1} failed, and was tagged as necessary. Aborting...": "PostOperation {0} z {1} zakończyła się niepowodzeniem i została oznaczona jako wymagana. Przerywanie...", + "PostOperation {0} out of {1} finished with result {2}": "PostOperation {0} z {1} zakończyła się z wynikiem {2}", + "{package} installer download": "Pobierz instalator {package}", + "{0} installer is being downloaded": "Trwa pobieranie instalatora {0}", + "Download succeeded": "Pobieranie powiodło się", + "{package} installer was downloaded successfully": "Instalator {package} został pobrany pomyślnie", + "Download failed": "Pobieranie nie powiodło się", + "{package} installer could not be downloaded": "Instalator {package} nie mógł zostać pobrany", + "{package} Installation": "Instalowanie {package}", + "{0} is being installed": "{0} jest instalowany", + "Installation succeeded": "Instalacja powiodła się", + "{package} was installed successfully": "{package} został zainstalowany pomyślnie", + "Installation failed": "Instalacja nie powiodła się", + "{package} could not be installed": "{package} nie może być zainstalowany", + "{package} Update": "Aktualizuj {package}", + "Update succeeded": "Aktualizacja się powiodła", + "{package} was updated successfully": "{package} został zaktualizowany pomyślnie", + "Update failed": "Aktualizacja nie powiodła się", + "{package} could not be updated": "{package} nie może być zaktualizowany", + "{package} Uninstall": "Odinstaluj {package}", + "{0} is being uninstalled": "{0} jest odinstalowywany", + "Uninstall succeeded": "Odinstalowanie powiodło się", + "{package} was uninstalled successfully": "{package} został odinstalowany pomyślnie", + "Uninstall failed": "Odinstalowywanie nie powiodło się", + "{package} could not be uninstalled": "{package} nie może być odinstalowany", + "Adding source {source}": "Dodawanie źródła {source}", + "Adding source {source} to {manager}": "Dodawanie źródła {source} do {manager}", + "Source added successfully": "Źródło dodano pomyślnie", + "The source {source} was added to {manager} successfully": "Źródło {source} zostało dodane pomyślnie do {manager}", + "Could not add source": "Nie można dodać źródła", + "Could not add source {source} to {manager}": " Nie można dodać źródła {source} do {manager}", + "Removing source {source}": "Usuwanie źródła {source}", + "Removing source {source} from {manager}": "Usuwanie źródła {source} z {manager}", + "Source removed successfully": "Źródło zostało pomyślnie usunięte", + "The source {source} was removed from {manager} successfully": "Źródło {source} zostało usunięte pomyślnie z {manager}", + "Could not remove source": "Nie można usunąć źródła", + "Could not remove source {source} from {manager}": "Nie można usunąć źródła {source} z {manager}\n", + "The package manager \"{0}\" was not found": "Menedżer pakietów \"{0}\" nie został znaleziony", + "The package manager \"{0}\" is disabled": "Menedżer pakietów \"{0}\" jest wyłączony", + "There is an error with the configuration of the package manager \"{0}\"": "Konfiguracja menedżera pakietów \"{0}\" jest błędna", + "The package \"{0}\" was not found on the package manager \"{1}\"": "Paczka \"{0}\" nie została znaleziona w menedżerze pakietów \"{1}\"", + "{0} is disabled": "{0} jest wyłączony", + "{0} weeks": "{0} tyg.", + "1 month": "1 miesiąc", + "{0} months": "{0} mies.", + "Something went wrong": "Coś poszło nie tak", + "An interal error occurred. Please view the log for further details.": "Wystąpił błąd wewnętrzny. Sprawdź dziennik zdarzeń, aby uzyskać więcej informacji.", + "No applicable installer was found for the package {0}": "Nie znaleziono odpowiedniego instalatora dla pakietu {0}", + "Integrity checks will not be performed during this operation": "Podczas tej operacji nie będzie sprawdzana spójność", + "This is not recommended.": "Nie jest to zalecane.", + "Run now": "Uruchom teraz", + "Run next": "Uruchom następne", + "Run last": "Uruchom ostatnie", + "Show in explorer": "Pokaż w eksploratorze", + "Checked": "Zaznaczone", + "Unchecked": "Odznaczone", + "This package is already installed": "Ten pakiet jest już zainstalowany", + "This package can be upgraded to version {0}": "Pakiet może zostać zaktualizowany do wersji {0}", + "Updates for this package are ignored": "Aktualizacje tego pakietu są ignorowane", + "This package is being processed": "Ten pakiet jest przetwarzany", + "This package is not available": "Ten pakiet nie jest dostępny", + "Select the source you want to add:": "Wybierz źródło, które chcesz dodać:", + "Source name:": "Nazwa źródła:", + "Source URL:": "Adres URL źródła:", + "An error occurred when adding the source: ": "Wystąpił błąd podczas dodawania źródła:", + "Package management made easy": "Łatwe zarządzanie pakietami", + "version {0}": "wersja {0}", + "[RAN AS ADMINISTRATOR]": "URUCHOMIONY JAKO ADMINISTRATOR", + "Portable mode": "Tryb przenośny", + "DEBUG BUILD": "KOMPILACJA DEBUG", + "Here you can change UniGetUI's behaviour regarding the following shortcuts. Checking a shortcut will make UniGetUI delete it if if gets created on a future upgrade. Unchecking it will keep the shortcut intact": "Tutaj możesz zmienić zachowanie UniGetUI w odniesieniu do następujących skrótów. Zaznaczenie skrótu spowoduje, że UniGetUI usunie go, jeśli zostanie utworzony podczas przyszłej aktualizacji. Odznaczenie go spowoduje, że skrót pozostanie nienaruszony", + "Manual scan": "Ręczne skanowanie", + "Existing shortcuts on your desktop will be scanned, and you will need to pick which ones to keep and which ones to remove.": "Istniejące skróty na pulpicie zostaną przeskanowane i będziesz musiał(a) wybrać, które z nich zachować, a które usunąć.", + "Delete?": "Usunąć?", + "I understand": "Rozumiem", + "Chocolatey setup changed": "Zmieniono konfigurację Chocolatey", + "UniGetUI no longer includes its own private Chocolatey installation. A legacy UniGetUI-managed Chocolatey installation was detected for this user profile, but system Chocolatey was not found. Chocolatey will stay unavailable in UniGetUI until Chocolatey is installed on the system and UniGetUI is restarted. Applications previously installed through UniGetUI's bundled Chocolatey may still appear under other sources such as Local PC or WinGet.": "UniGetUI nie zawiera już własnej prywatnej instalacji Chocolatey. Wykryto starszą instalację Chocolatey zarządzaną przez UniGetUI dla tego profilu użytkownika, ale nie znaleziono systemowej instalacji Chocolatey. Chocolatey pozostanie niedostępne w UniGetUI, dopóki Chocolatey nie zostanie zainstalowane w systemie i UniGetUI nie zostanie ponownie uruchomione. Aplikacje wcześniej zainstalowane za pośrednictwem wbudowanego Chocolatey w UniGetUI mogą nadal pojawiać się w innych źródłach, takich jak Lokalny PC lub WinGet.", + "NOTE: This troubleshooter can be disabled from UniGetUI Settings, on the WinGet section": "UWAGA: Funkcję rozwiązywania problemów można wyłączyć w ustawieniach UniGetUI, w sekcji WinGet", + "Restart": "Uruchom ponownie", + "Are you sure you want to delete all shortcuts?": "Czy na pewno chcesz usunąć wszystkie skróty?", + "Any new shorcuts created during an install or an update operation will be deleted automatically, instead of showing a confirmation prompt the first time they are detected.": "Wszelkie nowe skróty utworzone podczas instalacji lub aktualizacji będą usuwane automatycznie, zamiast wyświetlania monitu o potwierdzeniu przy pierwszym wykryciu.", + "Any shorcuts created or modified outside of UniGetUI will be ignored. You will be able to add them via the {0} button.": "Wszelkie skróty utworzone lub zmodyfikowane poza UniGetUI będą ignorowane. Będzie je można dodać za pomocą przycisku {0}.", + "Are you really sure you want to enable this feature?": "Czy na pewno chcesz włączyć tę funkcję?", + "No new shortcuts were found during the scan.": "Podczas skanowania nie znaleziono żadnych nowych skrótów.", + "How to add packages to a bundle": "Jak dodać pakiety do paczki", + "In order to add packages to a bundle, you will need to: ": "Aby dodać pakiety do paczki, musisz: ", + "1. Navigate to the \"{0}\" or \"{1}\" page.": "1. Nawiguj do strony \"{0}\" lub \"{1}\".", + "2. Locate the package(s) you want to add to the bundle, and select their leftmost checkbox.": "2. Znajdź pakiet(y), które chcesz dodać do paczki i zaznacz ich pola wyboru znajdujące się po lewej.", + "3. When the packages you want to add to the bundle are selected, find and click the option \"{0}\" on the toolbar.": "3. Po wybraniu pakietów, które chcesz dodać do paczki, znajdź i kliknij opcję \"{0}\" na pasku narzędzi.", + "4. Your packages will have been added to the bundle. You can continue adding packages, or export the bundle.": "4. Twoje pakiety zostaną dodane do pakietu. Kontynuuj dodawanie, lub eksportuj pakiet.", + "Which backup do you want to open?": "Którą kopię zapasową chcesz otworzyć?", + "Select the backup you want to open. Later, you will be able to review which packages you want to install.": "Wybierz kopię zapasową, którą chcesz otworzyć. Później będziesz mógł sprawdzić, które pakiety/programy chcesz przywrócić.", + "There are ongoing operations. Quitting UniGetUI may cause them to fail. Do you want to continue?": "Operacje są w toku. Zamknięcie UniGetUI może spowodować ich niepowodzenie. Czy chcesz kontynuować?", + "UniGetUI or some of its components are missing or corrupt.": "UniGetUI lub niektóre jego komponenty są niekompletne albo uszkodzone.", + "It is strongly recommended to reinstall UniGetUI to adress the situation.": "Zdecydowanie zaleca się przeinstalowanie UniGetUI, w celu rozwiązania sytuacji.", + "Refer to the UniGetUI Logs to get more details regarding the affected file(s)": "Zapoznaj się z dziennikami UniGetUI, aby uzyskać więcej szczegółów dotyczących pliku(ów), których dotyczy problem", + "Integrity checks can be disabled from the Experimental Settings": "Sprawdzanie spójności może zostać wyłączone w Ustawieniach Eksperymentalnych", + "Repair UniGetUI": "Napraw UniGetUI", + "Live output": "Dane wyjściowe na żywo", + "This package bundle had some settings that are potentially dangerous, and may be ignored by default.": "Ta paczka pakietów zawiera pewne ustawienia, które mogą być potencjalnie niebezpieczne i mogą być domyślnie ignorowane.", + "Entries that show in YELLOW will be IGNORED.": "Pozycje zaznaczone na ŻÓŁTO zostaną ZIGNOROWANE.", + "Entries that show in RED will be IMPORTED.": "Pozycje zaznaczone na CZERWONO zostaną ZAIMPORTOWANE.", + "You can change this behavior on UniGetUI security settings.": "Możesz zmienić to zachowanie w ustawieniach bezpieczeństwa UniGetUI.", + "Open UniGetUI security settings": "Otwórz ustawienia bezpieczeństwa UniGetUI", + "Should you modify the security settings, you will need to open the bundle again for the changes to take effect.": "W przypadku zmiany ustawień zabezpieczeń konieczne będzie ponowne otwarcie paczki, aby zmiany zaczęły obowiązywać.", + "Details of the report:": "Szczegóły raportu:", + "Are you sure you want to create a new package bundle? ": "Czy na pewno chcesz utworzyć nową paczkę?", + "Any unsaved changes will be lost": "Wszelkie niezapisane zmiany zostaną utracone", + "Warning!": "Ostrzeżenie!", + "For security reasons, custom command-line arguments are disabled by default. Go to UniGetUI security settings to change this. ": "Ze względów bezpieczeństwa niestandardowe argumenty wiersza poleceń są domyślnie wyłączone. Aby to zmienić, przejdź do ustawień zabezpieczeń UniGetUI. ", + "Change default options": "Zmień opcje domyślne", + "Ignore future updates for this package": "Ignoruj przyszłe aktualizacje tego pakietu", + "For security reasons, pre-operation and post-operation scripts are disabled by default. Go to UniGetUI security settings to change this. ": "Ze względów bezpieczeństwa skrypty przed i po czynnościach są domyślnie wyłączone. Aby to zmienić, przejdź do ustawień bezpieczeństwa UniGetUI.", + "You can define the commands that will be run before or after this package is installed, updated or uninstalled. They will be run on a command prompt, so CMD scripts will work here.": "Możesz zdefiniować polecenia, które będą uruchamiane przed lub po zainstalowaniu, aktualizacji lub odinstalowaniu tego pakietu. Będą one uruchamiane w wierszu poleceń, więc skrypty CMD będą tutaj działać.", + "Change this and unlock": "Zmień to i odblokuj", + "{0} Install options are currently locked because {0} follows the default install options.": "{0} opcje instalacji są obecnie zablokowane, ponieważ {0} używa domyślnych opcji instalacji.", + "Unset or unknown": "Nieustawiona lub nieznana", + "This package has no screenshots or is missing the icon? Contrbute to UniGetUI by adding the missing icons and screenshots to our open, public database.": "Ten pakiet nie ma zrzutów ekranu lub brakuje ikony? Pomóż UniGetUI dodając brakujące ikony i zrzuty ekranu do naszej otwartej, publicznej bazy danych.", + "Become a contributor": "Zostań współtwórcą", + "Update to {0} available": "jest dostępna aktualizacja do {0}", + "Reinstall": "Zainstaluj ponownie", + "Installer not available": "Instalator nie jest dostępny", + "Version:": "Wersja:", + "UniGetUI Version {0}": "Wersja UniGetUI {0}", + "Performing backup, please wait...": "Tworzy się kopia zapasowa, proszę czekać...", + "An error occurred while logging in: ": "Wystąpił błąd podczas logowania:", + "Fetching available backups...": "Pozyskiwanie dostępnych kopii zapasowych...", + "Done!": "Ukończono!", + "The cloud backup has been loaded successfully.": "Ładowanie kopii zapasowej z chmury zakończone powodzeniem.", + "An error occurred while loading a backup: ": "Wystąpił błąd podczas ładowania kopii zapasowej:", + "Backing up packages to GitHub Gist...": "Tworzenie kopii zapasowej pakietów w GitHub Gist...", + "Backup Successful": "Wykonanie kopii zapasowej powiodło się", + "The cloud backup completed successfully.": "Tworzenie kopii zapasowej w chmurze zakończone powodzeniem.", + "Could not back up packages to GitHub Gist: ": "Tworzenie kopii zapasowej pakietów w GitHub Gist nie powiodło się:", + "It is not guaranteed that the provided credentials will be stored safely, so you may as well not use the credentials of your bank account": "Nie ma gwarancji, że podane dane uwierzytelniające będą przechowywane bezpiecznie, dlatego nie należy używać danych uwierzytelniających konta bankowego", + "Enable the automatic WinGet troubleshooter": "Włącz automatyczne rozwiązywanie problemów dla WinGet", + "Add updates that fail with a 'no applicable update found' to the ignored updates list": "Dodaj aktualizacje, które zakończyły się niepowodzeniem z komunikatem „nie znaleziono odpowiedniej aktualizacji” do listy ignorowanych aktualizacji", + "Invalid selection": "Niepoprawny wybór", + "No package was selected": "Nie wybrano pakietu", + "More than 1 package was selected": "Wybrano więcej niż 1 pakiet", + "List": "Lista", + "Grid": "Siatka", + "Icons": "Ikony", + "\"{0}\" is a local package and does not have available details": "\"{0}\" jest pakietem lokalnym i nie ma dostępnych szczegółów", + "\"{0}\" is a local package and is not compatible with this feature": "\"{0}\" jest pakietem lokalnym i nie jest kompatybilny z tą funkcją", + "Add packages to bundle": "Dodaj paczki do pakietu", + "Preparing packages, please wait...": "Przygotowywanie pakietów, proszę czekać...", + "Loading packages, please wait...": "Wczytywanie pakietów, proszę czekać...", + "Saving packages, please wait...": "Zapisywanie pakietów, proszę czekać...", + "The bundle was created successfully on {0}": "Pakiet został pomyślnie utworzony na {0}", + "User profile": "Profil użytkownika", + "Error": "Błąd", + "Log in failed: ": "Logowanie nie powiodło się:", + "Log out failed: ": "Wylogowywanie nie powiodło się:", + "Package backup settings": "Ustawienia kopii zapasowych pakietów", + "Manage UniGetUI autostart behaviour from the Settings app": "Zarządzaj zachowaniem autostartu UniGetUI", + "Choose how many operations shoulds be performed in parallel": "Wybierz, ile operacji ma być wykonywanych równolegle", + "Something went wrong while launching the updater.": "Wystąpił błąd podczas uruchamiania aktualizatora.", + "Please try again later": "Proszę spróbować ponownie później", + "Show the release notes after UniGetUI is updated": "Pokaż informacje o wydaniu po aktualizacji UniGetUI" +} diff --git a/src/Languages/lang_pt_BR.json b/src/Languages/lang_pt_BR.json new file mode 100644 index 0000000..57ec895 --- /dev/null +++ b/src/Languages/lang_pt_BR.json @@ -0,0 +1,851 @@ +{ + "{0} of {1} operations completed": "{0} de {1} operações concluídas", + "{0} is now {1}": "{0} agora é {1}", + "Enabled": "Habilitado", + "Disabled": "Desativado", + "Privacy": "Privacidade", + "Hide my username from the logs": "Ocultar meu nome de usuário dos registros", + "Replaces your username with **** in the logs. Restart UniGetUI to also hide it from already-recorded entries.": "Substitui seu nome de usuário por **** nos registros. Reinicie o UniGetUI para ocultá-lo também das entradas já registradas.", + "Your last update attempt did not complete.": "Sua última tentativa de atualização não foi concluída.", + "UniGetUI could not confirm whether the update succeeded. Open the log to see what happened.": "O UniGetUI não conseguiu confirmar se a atualização foi bem-sucedida. Abra o log para ver o que aconteceu.", + "View log": "Ver log", + "The installer reported success but did not restart UniGetUI.": "O instalador informou sucesso, mas não reiniciou o UniGetUI.", + "The installer failed to initialize.": "Falha ao inicializar o instalador.", + "Setup was canceled before installation began.": "A instalação foi cancelada antes de começar.", + "A fatal error occurred during the preparation phase.": "Ocorreu um erro fatal durante a fase de preparação.", + "A fatal error occurred during installation.": "Ocorreu um erro fatal durante a instalação.", + "Installation was canceled while in progress.": "A instalação foi cancelada enquanto estava em andamento.", + "The installer was terminated by another process.": "O instalador foi encerrado por outro processo.", + "The preparation phase determined the installation cannot proceed.": "A fase de preparação determinou que a instalação não pode continuar.", + "The installer could not start. UniGetUI may already be running, or you do not have permission to install.": "Não foi possível iniciar o instalador. O UniGetUI pode já estar em execução ou você não tem permissão para instalar.", + "Unexpected installer error.": "Erro inesperado do instalador.", + "We are checking for updates.": "Estamos verificando por atualizações.", + "Please wait": "Por favor, aguarde", + "Great! You are on the latest version.": "Ótimo! Você está na versão mais recente.", + "There are no new UniGetUI versions to be installed": "Não há novas versões do UniGetUI para serem instaladas", + "UniGetUI version {0} is being downloaded.": "A versão {0} do UniGetUI está sendo baixada.", + "This may take a minute or two": "Isso pode levar um ou dois minutos", + "The installer authenticity could not be verified.": "A autenticidade do instalador não pôde ser verificada.", + "The update process has been aborted.": "O processo de atualização foi interrompido.", + "Auto-update is not yet available on this platform.": "A atualização automática ainda não está disponível nesta plataforma.", + "Please update UniGetUI manually.": "Atualize o UniGetUI manualmente.", + "An error occurred when checking for updates: ": "Ocorreu um erro ao verificar se há atualizações:", + "The updater could not be launched.": "Não foi possível iniciar o atualizador.", + "The operating system did not start the installer process.": "O sistema operacional não iniciou o processo do instalador.", + "UniGetUI is being updated...": "O UniGetUI está sendo atualizado...", + "Update installed.": "Atualização instalada.", + "UniGetUI was updated successfully, but this running copy was not replaced. This usually means you are running a development build. Close this copy and start the newly-installed version to finish.": "O UniGetUI foi atualizado com sucesso, mas esta cópia em execução não foi substituída. Isso geralmente significa que você está executando uma compilação de desenvolvimento. Feche esta cópia e inicie a versão recém-instalada para concluir.", + "The update could not be applied.": "Não foi possível aplicar a atualização.", + "Installer exit code {0}: {1}": "Código de saída do instalador {0}: {1}", + "Update cancelled.": "Atualização cancelada.", + "Authentication was cancelled.": "A autenticação foi cancelada.", + "Installer exit code {0}": "Código de saída do instalador {0}", + "Operation in progress": "Operação em andamento", + "Please wait...": "Por favor, aguarde.", + "Success!": "Sucesso!", + "Failed": "Falhou", + "An error occurred while processing this package": "Ocorreu um erro ao processar este pacote", + "Installer": "Instalador", + "Executable": "Executável", + "MSI": "MSI", + "Compressed file": "Arquivo compactado", + "MSIX": "MSIX", + "WinGet was repaired successfully": "O WinGet foi reparado com sucesso", + "It is recommended to restart UniGetUI after WinGet has been repaired": "É recomendado reiniciar o UniGetUI após o WinGet ser reparado", + "WinGet could not be repaired": "O WinGet não pôde ser reparado", + "An unexpected issue occurred while attempting to repair WinGet. Please try again later": "Ocorreu um problema inesperado ao tentar reparar o WinGet. Por favor, tente novamente mais tarde", + "Log in to enable cloud backup": "Faça login para ativar o backup na nuvem", + "Backup Failed": "Falha no backup", + "Downloading backup...": "Baixando o backup...", + "An update was found!": "Uma atualização foi encontrada!", + "{0} can be updated to version {1}": "{0} pode ser atualizado para a versão {1}", + "Updates found!": "Atualizações encontradas!", + "{0} packages can be updated": "{0} pacotes podem ser atualizados", + "{0} is being updated to version {1}": "{0} está sendo atualizado para a versão {1}", + "{0} packages are being updated": "{0} pacotes estão sendo atualizados", + "You have currently version {0} installed": "Você tem a versão {0} instalada atualmente", + "Desktop shortcut created": "Atalho na área de trabalho criado", + "UniGetUI has detected a new desktop shortcut that can be deleted automatically.": "O UniGetUI detectou um novo atalho na área de trabalho que pode ser excluído automaticamente.", + "{0} desktop shortcuts created": "{0} atalhos na área de trabalho criados", + "UniGetUI has detected {0} new desktop shortcuts that can be deleted automatically.": "O UniGetUI detectou {0} novos atalhos na área de trabalho que podem ser excluídos automaticamente.", + "Attention required": "Requer atenção", + "Restart required": "Reinicialização necessária", + "1 update is available": "1 atualização está disponível", + "{0} updates are available": "{0} atualizações disponíveis", + "Everything is up to date": "Tudo está atualizado", + "Discover Packages": "Descobrir Pacotes", + "Available Updates": "Atualizações Disponíveis", + "Installed Packages": "Pacotes Instalados", + "UniGetUI Version {0} by Devolutions": "UniGetUI Versão {0} da Devolutions", + "Show UniGetUI": "Mostrar UniGetUI", + "Quit": "Sair", + "Are you sure?": "Você tem certeza?", + "Do you really want to uninstall {0}?": "Você tem certeza de que deseja desinstalar {0}?", + "Do you really want to uninstall the following {0} packages?": "Você tem certeza de que deseja desinstalar os {0} pacotes seguintes?", + "No": "Não", + "Yes": "Sim", + "Partial": "Parcial", + "View on UniGetUI": "Ver no UniGetUI", + "Update": "Atualizar", + "Open UniGetUI": "Abrir UniGetUI", + "Update all": "Atualizar tudo", + "Update now": "Atualizar agora", + "Installer host changed since the installed version.\n": "O host do instalador mudou desde a versão instalada.\n", + "This package is on the queue": "Este pacote está na fila", + "installing": "instalando", + "updating": "atualizando", + "uninstalling": "desinstalando", + "installed": "instalado", + "Retry": "Tentar novamente", + "Install": "Instalar", + "Uninstall": "Desinstalar", + "Open": "Abrir", + "Operation profile:": "Perfil de operação:", + "Follow the default options when installing, upgrading or uninstalling this package": "Seguir opções padrão ao instalar, atualizar ou desinstalar este pacote", + "The following settings will be applied each time this package is installed, updated or removed.": "As seguintes configurações serão aplicadas sempre que este pacote for instalado, atualizado ou removido.", + "Version to install:": "Versão para instalar:", + "Architecture to install:": "Arquitetura para instalar:", + "Installation scope:": "Escopo da instalação:", + "Install location:": "Local de instalação:", + "Select": "Selecionar", + "Reset": "Redefinir", + "Custom install arguments:": "Argumentos de instalação personalizados:", + "Custom update arguments:": "Argumentos de atualização personalizados:", + "Custom uninstall arguments:": "Argumentos de desinstalação personalizados:", + "Pre-install command:": "Comando de pré-instalação:", + "Post-install command:": "Comando de pós-instalação:", + "Abort install if pre-install command fails": "Cancelar instalação se o comando de pré-instalação falhar", + "Pre-update command:": "Comando de pré-atualização:", + "Post-update command:": "Comando de pós-atualização:", + "Abort update if pre-update command fails": "Cancelar atualização se o comando de pré-atualização falhar", + "Pre-uninstall command:": "Comando de pré-desinstalação:", + "Post-uninstall command:": "Comando de pós-desinstalação:", + "Abort uninstall if pre-uninstall command fails": "Cancelar desinstalação se o comando de pré-deinstalação falhar", + "Command-line to run:": "Linha de comando para executar:", + "Save and close": "Salvar e fechar", + "General": "Geral", + "Architecture & Location": "Arquitetura e local", + "Command-line": "Linha de comando", + "Close apps": "Fechar aplicativos", + "Pre/Post install": "Pré/Pós-instalação", + "Select the processes that should be closed before this package is installed, updated or uninstalled.": "Selecione os processos que devem ser fechados antes que este pacote seja instalado, atualizado ou desinstalado.", + "Write here the process names here, separated by commas (,)": "Escreva aqui os nomes dos processos, separados por vírgulas (,)", + "Try to kill the processes that refuse to close when requested to": "Tentar encerrar os processos que se recusam a fechar quando solicitados", + "Run as admin": "Executar como administrador", + "Interactive installation": "Instalação interativa", + "Skip hash check": "Ignorar verificação de hash", + "Uninstall previous versions when updated": "Desinstalar versões anteriores ao atualizar", + "Skip minor updates for this package": "Ignoras atualizações menores deste pacote", + "Automatically update this package": "Atualizar este pacote automaticamente", + "{0} installation options": "opções de instalação de {0}", + "Latest": "Mais recente", + "PreRelease": "Pré-lançamento", + "Default": "Padrão", + "Manage ignored updates": "Gerenciar atualizações ignoradas", + "The packages listed here won't be taken in account when checking for updates. Double-click them or click the button on their right to stop ignoring their updates.": "Os pacotes listados aqui não serão levados em conta ao verificar atualizações. Clique duas vezes neles ou clique no botão à direita para parar de ignorar suas atualizações.", + "Reset list": "Redefinir lista", + "Do you really want to reset the ignored updates list? This action cannot be reverted": "Você realmente deseja redefinir a lista de atualizações ignoradas? Esta ação não pode ser desfeita", + "No ignored updates": "Nenhuma atualização ignorada", + "Package Name": "Nome do Pacote", + "Package ID": "ID do Pacote", + "Ignored version": "Versão Ignorada", + "New version": "Nova versão", + "Source": "Origem", + "All versions": "Todas as versões", + "Unknown": "Desconhecido", + "Up to date": "Atualizado", + "Package {name} from {manager}": "Pacote {name} de {manager}", + "Remove {0} from ignored updates": "Remover {0} das atualizações ignoradas", + "Cancel": "Cancelar", + "Administrator privileges": "Privilégios de administrador", + "This operation is running with administrator privileges.": "Esta operação está sendo executada com privilégios de administrador.", + "Interactive operation": "Operação interativa", + "This operation is running interactively.": "Esta operação está sendo executada de forma interativa.", + "You will likely need to interact with the installer.": "Provavelmente você precisará interagir com o instalador.", + "Integrity checks skipped": "Verificações de integridade ignoradas", + "Integrity checks will not be performed during this operation.": "As verificações de integridade não serão realizadas durante esta operação.", + "Proceed at your own risk.": "Prossiga por sua conta e risco.", + "Close": "Fechar", + "Loading...": "Carregando...", + "Installer SHA256": "SHA256 do Instalador", + "Homepage": "Página Inicial", + "Author": "Autor", + "Publisher": "Desenvolvedor", + "License": "Licença", + "Manifest": "Manifesto", + "Installer Type": "Tipo de Instalador", + "Size": "Tamanho", + "Installer URL": "URL do Instalador ", + "Last updated:": "Última atualização:", + "Release notes URL": "URL das notas de lançamento", + "Package details": "Detalhes do pacote", + "Dependencies:": "Dependências:", + "Release notes": "Notas de lançamento", + "Screenshots": "Capturas de tela", + "This package has no screenshots or is missing the icon? Contribute to UniGetUI by adding the missing icons and screenshots to our open, public database.": "Este pacote não tem capturas de tela ou está sem o ícone? Contribua para o UniGetUI adicionando os ícones e capturas de tela ausentes ao nosso banco de dados público e aberto.", + "Version": "Versão", + "Install as administrator": "Instalar como administrador", + "Update to version {0}": "Atualizar para a versão {0}", + "Installed Version": "Versão Instalada", + "Update as administrator": "Atualizar como administrador", + "Interactive update": "Atualização interativa", + "Uninstall as administrator": "Desinstalar como administrador", + "Interactive uninstall": "Desinstalação interativa", + "Uninstall and remove data": "Desinstalar e remover dados", + "Not available": "Não disponível", + "Installer SHA512": "SHA512 do instalador", + "Unknown size": "Tamanho desconhecido", + "No dependencies specified": "Nenhuma dependência especificada", + "mandatory": "obrigatória", + "optional": "opcional", + "UniGetUI {0} is ready to be installed.": "O UniGetUI {0} está pronto para ser instalado.", + "The update process will start after closing UniGetUI": "O processo de atualização será iniciado após encerrar o UniGetUI", + "UniGetUI has been ran as administrator, which is not recommended. When running UniGetUI as administrator, EVERY operation launched from UniGetUI will have administrator privileges. You can still use the program, but we highly recommend not running UniGetUI with administrator privileges.": "O UniGetUI foi executado como administrador, o que não é recomendado. Ao executar o UniGetUI como administrador, TODAS as operações iniciadas pelo UniGetUI terão privilégios de administrador. Você ainda pode usar o programa, mas recomendamos fortemente não executar o UniGetUI com privilégios de administrador.", + "Share anonymous usage data": "Compartilhar dados de uso anônimos", + "UniGetUI collects anonymous usage data in order to improve the user experience.": "O UniGetUI coleta dados de uso anônimas para melhorar a experiência do usuário.", + "Accept": "Aceitar", + "Software Updates": "Atualizações de Software", + "Package Bundles": "Coleção de Pacotes", + "Settings": "Configurações", + "Package Managers": "Gerenciadores de Pacotes", + "UniGetUI Log": "Log do UniGetUI", + "Package Manager logs": "Logs do Gerenciador de Pacotes", + "Operation history": "Histórico de operações", + "Help": "Ajuda", + "UniGetUI": "UniGetUI", + "You have installed UniGetUI Version {0}": "Você instalou a versão {0} do UniGetUI", + "Disclaimer": "Aviso Legal", + "UniGetUI is developed by Devolutions and is not affiliated with any of the compatible package managers.": "O UniGetUI é desenvolvido pela Devolutions e não é afiliado a nenhum dos gerenciadores de pacotes compatíveis.", + "UniGetUI wouldn't have been possible without the help of the contributors. Thank you all 🥳": "O UniGetUI não seria possível sem a ajuda dos colaboradores. Obrigado a todos 🥳", + "UniGetUI uses the following libraries. Without them, UniGetUI wouldn't have been possible.": "O UniGetUI usa as seguintes bibliotecas. Sem elas, o UniGetUI não seria possível.", + "{0} homepage": "página inicial de {0}", + "UniGetUI has been translated to more than 40 languages thanks to the volunteer translators. Thank you 🤝": "O UniGetUI foi traduzido para mais de 40 idiomas graças aos tradutores voluntários. Obrigado 🤝", + "Verbose": "Detalhado", + "1 - Errors": "1 - Erros", + "2 - Warnings": "2 - Avisos", + "3 - Information (less)": "3 - Informações (resumidas)", + "4 - Information (more)": "4 - Informações (detalhadas)", + "5 - information (debug)": "5 - Informações (depuração)", + "Warning": "Aviso", + "The following settings may pose a security risk, hence they are disabled by default.": "As seguintes configurações podem representar um risco à segurança, por isso estão desabilitadas por padrão.", + "Enable the settings below if and only if you fully understand what they do, and the implications they may have.": "Ative as configurações abaixo SE E SOMENTE SE você entender completamente o que elas fazem e as implicações e perigos que podem envolver.", + "The settings will list, in their descriptions, the potential security issues they may have.": "As configurações listarão, em suas descrições, os potenciais problemas de segurança que podem ter.", + "The backup will include the complete list of the installed packages and their installation options. Ignored updates and skipped versions will also be saved.": "O backup incluirá a lista completa dos pacotes instalados e suas opções de instalação. Atualizações ignoradas e versões puladas também serão salvas.", + "The backup will NOT include any binary file nor any program's saved data.": "O backup NÃO incluirá nenhum arquivo binário nem dados salvos de nenhum programa.", + "The size of the backup is estimated to be less than 1MB.": "O tamanho do backup é estimado em menos de 1 MB.", + "The backup will be performed after login.": "O backup será realizado após o login.", + "{pcName} installed packages": "Pacotes instalados em {pcName}", + "Current status: Not logged in": "Status atual: Deslogado", + "You are logged in as {0} (@{1})": "Você está logado como {0} (@{1})", + "Nice! Backups will be uploaded to a private gist on your account": "Ótimo! Os backups serão enviados para um gist privado na sua conta.", + "Select backup": "Selecionar backup", + "Settings imported from {0}": "Configurações importadas de {0}", + "UniGetUI Settings": "Configurações do UniGetUI", + "Settings exported to {0}": "Configurações exportadas para {0}", + "UniGetUI settings were reset": "As configurações do UniGetUI foram redefinidas", + "Allow pre-release versions": "Permitir versões de pré-lançamento", + "Apply": "Aplicar", + "For security reasons, custom command-line arguments are disabled by default. Go to UniGetUI security settings to change this.": "Por motivos de segurança, os argumentos de linha de comando personalizados são desabilitados por padrão. Acesse as configurações de segurança do UniGetUI para alterar isso.", + "Go to UniGetUI security settings": "Acessar configurações de segurança do UniGetUI", + "The following options will be applied by default each time a {0} package is installed, upgraded or uninstalled.": "As seguintes opções serão aplicadas por padrão sempre que um pacote {0} for instalado, atualizado ou desinstalado.", + "Package's default": "Padrão do pacote", + "Install location can't be changed for {0} packages": "O local de instalação não pode ser alterado para {0} pacotes", + "The local icon cache currently takes {0} MB": "O cache de ícones local atualmente ocupa {0} MB", + "Username": "Nome de usuário", + "Password": "Senha", + "Credentials": "Credenciais", + "It is not guaranteed that the provided credentials will be stored safely": "Não é garantido que as credenciais fornecidas serão armazenadas com segurança", + "Partially": "Parcialmente", + "Package manager": "Gerenciador de pacotes", + "Compatible with proxy": "Compatível com proxy", + "Compatible with authentication": "Compatível com autenticação", + "Proxy compatibility table": "Tabela de compatibilidade do proxy", + "{0} settings": "Configurações do {0}", + "{0} status": "Status de {0}", + "Default installation options for {0} packages": "Opções de instalação padrão para {0} pacotes", + "Expand version": "Expandir", + "The executable file for {0} was not found": "O arquivo executável do {0} não foi encontrado", + "{pm} is disabled": "{pm} está desativado", + "Enable it to install packages from {pm}.": "Habilitar a instalação de pacotes do {pm}.", + "{pm} is enabled and ready to go": "{pm} está ativado e pronto para ser usado", + "{pm} version:": "Versão do {pm}:", + "{pm} was not found!": "{pm} não foi encontrado!", + "You may need to install {pm} in order to use it with UniGetUI.": "Você pode precisar instalar {pm} para usá-lo com o UniGetUI.", + "Scoop Installer - UniGetUI": "Instalador do Scoop - UniGetUI", + "Scoop Uninstaller - UniGetUI": "Desinstalador do Scoop - UniGetUI", + "Clearing Scoop cache - UniGetUI": "Limpando cache do Scoop - UniGetUI", + "Restart UniGetUI to fully apply changes": "Reinicie o UniGetUI para aplicar totalmente as alterações", + "Restart UniGetUI": "Reiniciar UniGetUI", + "Manage {0} sources": "Gerenciar {0} fontes", + "Add source": "Adicionar fonte", + "Add": "Adicionar", + "Source name": "Nome da fonte", + "Source URL": "URL da fonte", + "Other": "Outros", + "No minimum age": "Sem idade mínima", + "1 day": "1 dia", + "{0} days": "{0} dias", + "Custom...": "Personalizado...", + "{0} minutes": "{0} minutos", + "1 hour": "1 hora", + "{0} hours": "{0} horas", + "1 week": "1 semana", + "Supports release dates": "Suporta datas de lançamento", + "Release date support per package manager": "Suporte a datas de lançamento por gerenciador de pacotes", + "Search for packages": "Procurar por pacotes", + "Local": "Locais", + "OK": "OK", + "Last checked: {0}": "Última verificação: {0}", + "{0} packages were found, {1} of which match the specified filters.": "{0} pacotes foram encontrados, dos quais {1} correspondem aos filtros especificados.", + "{0} selected": "{0} selecionado(s)", + "(Last checked: {0})": "(Última verificação: {0})", + "All packages selected": "Todos os pacotes selecionados", + "Package selection cleared": "Seleção de pacotes limpa", + "{0}: {1}": "{0}: {1}", + "More info": "Mais informações", + "GitHub account": "Conta do GitHub", + "Log in with GitHub to enable cloud package backup.": "Faça login com o GitHub para ativar o backup de pacotes na nuvem.", + "More details": "Mais detalhes", + "Log in": "Login", + "If you have cloud backup enabled, it will be saved as a GitHub Gist on this account": "Se você tiver o backup em nuvem habilitado, ele será salvo como um GitHub Gist nesta conta", + "Log out": "Sair", + "About UniGetUI": "Sobre o UniGetUI", + "About": "Sobre", + "Third-party licenses": "Licenças de terceiros", + "Contributors": "Colaboradores", + "Translators": "Tradutores", + "Bundle security report": "Relatório de segurança do pacote", + "The bundle contained restricted content": "O pacote continha conteúdo restrito", + "UniGetUI – Crash Report": "UniGetUI – Relatório de Falha", + "UniGetUI has crashed": "O UniGetUI parou de funcionar", + "Help us fix this by sending a crash report to Devolutions. All fields below are optional.": "Ajude-nos a corrigir isso enviando um relatório de falha para a Devolutions. Todos os campos abaixo são opcionais.", + "Email (optional)": "E-mail (opcional)", + "your@email.com": "seu@email.com", + "Additional details (optional)": "Detalhes adicionais (opcional)", + "Describe what you were doing when the crash occurred…": "Descreva o que você estava fazendo quando a falha ocorreu…", + "Crash report": "Relatório de falha", + "Don't Send": "Não Enviar", + "Send Report": "Enviar Relatório", + "Sending…": "Enviando…", + "Unsaved changes": "Alterações não salvas", + "You have unsaved changes in the current bundle. Do you want to discard them?": "Há alterações não salvas no pacote atual. Deseja descartá-las?", + "Discard changes": "Descartar alterações", + "Integrity violation": "Violação de integridade", + "UniGetUI or some of its components are missing or corrupt. It is strongly recommended to reinstall UniGetUI to adress the situation.": "O UniGetUI ou alguns de seus componentes estão ausentes ou corrompidos. É altamente recomendável reinstalar o UniGetUI para resolver a situação.", + "• Refer to the UniGetUI Logs to get more details regarding the affected file(s)": "• Consulte os registros do UniGetUI para obter mais detalhes sobre os arquivos afetados", + "• Integrity checks can be disabled from the Experimental Settings": "• As verificações de integridade podem ser desabilitadas nas Configurações Experimentais", + "Manage shortcuts": "Gerenciar atalhos", + "UniGetUI has detected the following desktop shortcuts which can be removed automatically on future upgrades": "O UniGetUI detectou os seguintes atalhos na área de trabalho, que poderão ser removidos automaticamente em futuras atualizações", + "Do you really want to reset this list? This action cannot be reverted.": "Você deseja realmente redefinir esta lista? Esta ação não pode ser desfeita.", + "Desktop shortcuts list": "Lista de atalhos da área de trabalho", + "Open in explorer": "Abrir no Explorador", + "Remove from list": "Remover da lista", + "When new shortcuts are detected, delete them automatically instead of showing this dialog.": "Quando novos atalhos forem detectados, exclua-os automaticamente em vez de mostrar esta caixa de diálogo.", + "Not right now": "Agora não", + "Missing dependency": "Dependência ausente", + "UniGetUI requires {0} to operate, but it was not found on your system.": "O UniGetUI requer {0} para funcionar, mas ele não foi encontrado em seu sistema.", + "Click on Install to begin the installation process. If you skip the installation, UniGetUI may not work as expected.": "Clique em Instalar para iniciar a instalação. Se você pular esta etapa, o UniGetUI pode não funcionar corretamente.", + "Alternatively, you can also install {0} by running the following command in a Windows PowerShell prompt:": "Como alternativa, você também pode instalar {0} executando o seguinte comando no prompt do Windows PowerShell:", + "Install {0}": "Instalar {0}", + "Do not show this dialog again for {0}": "Não mostrar esta caixa de diálogo novamente para {0}", + "Please wait while {0} is being installed. A black window may show up. Please wait until it closes.": "Aguarde enquanto {0} está sendo instalado. Uma janela preta poderá aparecer. Aguarde até que ela seja fechada.", + "{0} has been installed successfully.": "{0} foi instalado com sucesso.", + "Please click on \"Continue\" to continue": "Clique em \"Continuar\" para prosseguir", + "Continue": "Continuar", + "{0} has been installed successfully. It is recommended to restart UniGetUI to finish the installation": "{0} foi instalado com sucesso. Recomenda-se reiniciar o UniGetUI para concluir a instalação", + "Restart later": "Reiniciar mais tarde", + "An error occurred:": "Ocorreu um erro:", + "Please see the Command-line Output or refer to the Operation History for further information about the issue.": "Consulte a saída da linha de comando ou o histórico de operações para mais informações sobre o problema.", + "Retry as administrator": "Repetir como administrador", + "Retry interactively": "Repetir interativamente", + "Retry skipping integrity checks": "Repetir verificações de integridade ignoradas", + "Installation options": "Opções de instalação", + "Save": "Salvar", + "UniGetUI collects anonymous usage data with the sole purpose of understanding and improving the user experience.": "O UniGetUI coleta dados de uso anônimos com o único propósito de entender e melhorar a experiência do usuário.", + "More details about the shared data and how it will be processed": "Mais detalhes sobre os dados compartilhados e como eles serão processados", + "Do you accept that UniGetUI collects and sends anonymous usage statistics, with the sole purpose of understanding and improving the user experience?": "Você permite que o UniGetUI colete e envie estatísticas de uso anônimas, com o único objetivo de entender e melhorar a experiência do usuário?", + "Decline": "Recusar", + "No personal information is collected nor sent, and the collected data is anonimized, so it can't be back-tracked to you.": "Nenhuma informação pessoal é coletada e enviada. Os dados coletados não anônimos, assim não podem ser rastreados.", + "Navigation panel": "Painel de navegação", + "Operations": "Operações", + "Toggle operations panel": "Alternar painel de operações", + "Bulk operations": "Operações em massa", + "Retry failed": "Tentar novamente os que falharam", + "Clear successful": "Limpar bem-sucedidas", + "Clear finished": "Limpar concluídas", + "Cancel all": "Cancelar tudo", + "More": "Mais", + "Toggle navigation panel": "Alternar painel de navegação", + "Minimize": "Minimizar", + "Maximize": "Maximizar", + "UniGetUI by Devolutions": "UniGetUI da Devolutions", + "UniGetUI is an application that makes managing your software easier, by providing an all-in-one graphical interface for your command-line package managers.": "O UniGetUI é um aplicativo que facilita o gerenciamento de seu software, fornecendo uma interface gráfica completa para seus gerenciadores de pacotes de linha de comando.", + "Useful links": "Links Úteis", + "UniGetUI Homepage": "Página inicial do UniGetUI", + "Report an issue or submit a feature request": "Reportar um problema ou solicitar um recurso", + "UniGetUI Repository": "Repositório do UniGetUI", + "View GitHub Profile": "Ver perfil do GitHub", + "UniGetUI License": "Licença do UniGetUI", + "Using UniGetUI implies the acceptation of the MIT License": "O uso do UniGetUI implica na aceitação da Licença MIT", + "Become a translator": "Torne-se um tradutor", + "Go back": "Voltar", + "Go forward": "Avançar", + "Go to home page": "Ir para a página inicial", + "Reload page": "Recarregar página", + "View page on browser": "Ver página no navegador", + "The built-in browser is not supported on Linux yet.": "O navegador integrado ainda não é compatível com Linux.", + "Open in browser": "Abrir no navegador", + "Copy to clipboard": "Copiar para a área de transferência", + "Export to a file": "Exportar para um arquivo", + "Log level:": "Nível de log:", + "Reload log": "Recarregar log", + "Export log": "Exportar log", + "Text": "Texto", + "Change how operations request administrator rights": "Alterar como as operações solicitam direitos de administrador", + "Restrictions on package operations": "Restrições nas operações de pacotes", + "Restrictions on package managers": "Restrições em gerenciadores de pacotes", + "Restrictions when importing package bundles": "Restrições ao importar pacotes", + "Ask for administrator privileges once for each batch of operations": "Solicitar privilégios de administrador uma vez para cada lote de operações", + "Ask only once for administrator privileges": "Perguntar uma única vez por direitos de administrador", + "Prohibit any kind of Elevation via UniGetUI Elevator or GSudo": "Proibir qualquer tipo de elevação via UniGetUI Elevator ou GSudo", + "This option WILL cause issues. Any operation incapable of elevating itself WILL FAIL. Install/update/uninstall as administrator will NOT WORK.": "Esta opção CAUSARÁ problemas. Qualquer operação que não consiga se elevar FALHARÁ. Instalar/atualizar/desinstalar como administrador NÃO FUNCIONARÁ.", + "Allow custom command-line arguments": "Permitir argumentos de linha de comando personalizados", + "Custom command-line arguments can change the way in which programs are installed, upgraded or uninstalled, in a way UniGetUI cannot control. Using custom command-lines can break packages. Proceed with caution.": "Argumentos de linha de comando personalizados podem alterar a maneira como os programas são instalados, atualizados ou desinstalados, de uma forma que o UniGetUI não pode controlar. O uso de linhas de comando personalizadas pode corromper pacotes. Prossiga com cautela.", + "Ignore custom pre-install and post-install commands when importing packages from a bundle": "Ignorar comandos personalizados de pré e pós-instalação ao importar pacotes de uma coleção de pacotes", + "Pre and post install commands will be run before and after a package gets installed, upgraded or uninstalled. Be aware that they may break things unless used carefully": "Os comandos de pré e pós-instalação serão executados antes e depois da instalação, atualização ou desinstalação de um pacote. Esteja ciente de que eles podem causar problemas, a menos que sejam usados com cuidado.", + "Allow changing the paths for package manager executables": "Permitir alterar caminhos para executáveis de gerenciadores de pacotes", + "Turning this on enables changing the executable file used to interact with package managers. While this allows finer-grained customization of your install processes, it may also be dangerous": "Ativar esta opção permite alterar o arquivo executável usado para interagir com os gerenciadores de pacotes. Embora isso permita uma personalização mais precisa dos seus processos de instalação, também pode ser perigoso.", + "Allow importing custom command-line arguments when importing packages from a bundle": "Permitir a importação de argumentos de linha de comando personalizados ao importar pacotes", + "Malformed command-line arguments can break packages, or even allow a malicious actor to gain privileged execution. Therefore, importing custom command-line arguments is disabled by default": "Argumentos de linha de comando malformados podem corromper pacotes ou até mesmo permitir que um agente malicioso obtenha execução privilegiada. Portanto, a importação de argumentos de linha de comando personalizados está desabilitada por padrão.", + "Allow importing custom pre-install and post-install commands when importing packages from a bundle": "Permitir a importação de comandos personalizados de pré-instalação e pós-instalação ao importar pacotes", + "Pre and post install commands can do very nasty things to your device, if designed to do so. It can be very dangerous to import the commands from a bundle, unless you trust the source of that package bundle": "Comandos de pré e pós-instalação podem causar danos graves ao seu dispositivo, se projetados para isso. Pode ser muito perigoso importar os comandos de um pacote, a menos que você confie na fonte desse pacote.", + "Administrator rights and other dangerous settings": "Direitos de administrador e outras configurações perigosas", + "Package backup": "Backup do pacote", + "Cloud package backup": "Backup de pacote em nuvem", + "Local package backup": "Backup de pacote local", + "Local backup advanced options": "Opções avançadas de backup local", + "Log in with GitHub": "Fazer login com o GitHub", + "Log out from GitHub": "Sair do GitHub", + "Periodically perform a cloud backup of the installed packages": "Executar periodicamente um backup na nuvem dos pacotes instalados", + "Cloud backup uses a private GitHub Gist to store a list of installed packages": "O backup em nuvem usa um GitHub Gist privado para armazenar uma lista de pacotes instalados", + "Perform a cloud backup now": "Executar backup na nuvem agora", + "Backup": "Fazer backup", + "Restore a backup from the cloud": "Restaurar backup da nuvem", + "Begin the process to select a cloud backup and review which packages to restore": "Inicie o processo para selecionar um backup na nuvem e revise quais pacotes restaurar", + "Periodically perform a local backup of the installed packages": "Executar periodicamente um backup local dos pacotes instalados", + "Perform a local backup now": "Executar backup local agora", + "Change backup output directory": "Alterar diretório de saída do backup", + "Set a custom backup file name": "Defina um nome para seu arquivo de backup", + "Leave empty for default": "Deixe em branco para padrão", + "Add a timestamp to the backup file names": "Adicionar um registro de data e hora aos nomes dos arquivos de backup", + "Backup and Restore": "Backup e Restauração", + "Enable background api (UniGetUI Widgets and Sharing, port 7058)": "Habilitar API em segundo plano (Widgets e Compartilhamento do UniGetUI, porta 7058)", + "Wait for the device to be connected to the internet before attempting to do tasks that require internet connectivity.": "Aguarde até que o dispositivo esteja conectado à internet antes de tentar realizar tarefas que exijam conectividade à internet.", + "Disable the 1-minute timeout for package-related operations": "Desativar o tempo limite de 1 minuto para operações relacionadas a pacotes", + "Use installed GSudo instead of UniGetUI Elevator": "Usar o GSudo instalado em vez do UniGetUI Elevator", + "Use a custom icon and screenshot database URL": "Usar uma URL de banco de dados personalizada para ícones e capturas de tela", + "Enable background CPU Usage optimizations (see Pull Request #3278)": "Ativar otimizações de uso de CPU em segundo plano (veja Pull Request #3278)", + "Perform integrity checks at startup": "Executar verificações de integridade na inicialização", + "When batch installing packages from a bundle, install also packages that are already installed": "Na instalação em lote, instalar também pacotes que já estão instalados", + "Experimental settings and developer options": "Configurações experimentais e opções de desenvolvedor", + "Show UniGetUI's version and build number on the titlebar.": "Mostrar versão do UniGetUI na barra de título", + "Language": "Idioma", + "UniGetUI updater": "Atualizador do UniGetUI", + "Telemetry": "Telemetria", + "Manage UniGetUI settings": "Gerenciar configurações do UniGetUI", + "Related settings": "Configurações relacionadas", + "Update UniGetUI automatically": "Atualizar o UniGetUI automaticamente", + "Check for updates": "Verificar atualizações", + "Install prerelease versions of UniGetUI": "Instalar versões de pré-lançamento do UniGetUI", + "Manage telemetry settings": "Gerenciar configurações de telemetria", + "Manage": "Gerenciar", + "Import settings from a local file": "Importar configurações de um arquivo local", + "Import": "Importar", + "Export settings to a local file": "Exportar configurações para um arquivo local", + "Export": "Exportar", + "Reset UniGetUI": "Redefinir UniGetUI", + "User interface preferences": "Preferências da interface do usuário", + "Application theme, startup page, package icons, clear successful installs automatically": "Tema do aplicativo, página inicial, ícones dos pacotes, remover instalações concluídas automaticamente", + "General preferences": "Preferências gerais", + "UniGetUI display language:": "Idioma de exibição do UniGetUI:", + "System language": "Idioma do sistema", + "Is your language missing or incomplete?": "Seu idioma está faltando ou incompleto?", + "Appearance": "Aparência", + "UniGetUI on the background and system tray": "UniGetUi em segundo plano e área de notificação", + "Package lists": "Listas de pacotes", + "Use classic mode": "Usar modo clássico", + "Restart UniGetUI to apply this change": "Reinicie o UniGetUI para aplicar esta alteração", + "The classic UI is disabled for beta testers": "A interface clássica está desativada para os testadores beta", + "Close UniGetUI to the system tray": "Fechar o UniGetUi para a área de notificação", + "Manage UniGetUI autostart behaviour": "Gerenciar o comportamento de inicialização automática do UniGetUI", + "Show package icons on package lists": "Exibir ícones dos pacotes nas listas de pacotes", + "Clear cache": "Limpar cache", + "Select upgradable packages by default": "Selecionar pacotes que podem ser atualizados por padrão", + "Light": "Claro", + "Dark": "Escuro", + "Follow system color scheme": "Seguir o esquema de cores do sistema", + "Application theme:": "Tema do aplicativo:", + "UniGetUI startup page:": "Página inicial do UniGetUI:", + "Proxy settings": "Configurações do proxy", + "Other settings": "Outras configurações", + "Connect the internet using a custom proxy": "Conectar na Internet usando proxy personalizado", + "Please note that not all package managers may fully support this feature": "Observe que nem todos os gerenciadores de pacotes podem suportar totalmente este recurso", + "Proxy URL": "URL do proxy", + "Enter proxy URL here": "Insira o URL do proxy aqui", + "Authenticate to the proxy with a user and a password": "Autenticar no proxy com um usuário e uma senha", + "Internet and proxy settings": "Configurações de internet e proxy", + "Package manager preferences": "Preferências do gerenciador de pacotes", + "Ready": "Pronto", + "Not found": "Não encontrado", + "Notification preferences": "Preferências de notificação", + "Notification types": "Tipos de notificação", + "The system tray icon must be enabled in order for notifications to work": "O ícone da área de notificação precisa estar ativado para que as notificações funcionem", + "Enable UniGetUI notifications": "Ativar notificações do UniGetUI", + "Show a notification when there are available updates": "Mostrar uma notificação quando houver atualizações disponíveis", + "Show a silent notification when an operation is running": "Exibir uma notificação silenciosa enquanto uma operação está em andamento", + "Show a notification when an operation fails": "Exibir uma notificação quando uma operação falhar", + "Show a notification when an operation finishes successfully": "Exibir uma notificação quando uma operação for concluída com sucesso", + "Concurrency and execution": "Concorrência e execução", + "Automatic desktop shortcut remover": "Removedor automático de atalhos na área de trabalho", + "Choose how many operations should be performed in parallel": "Escolha quantas operações devem ser executadas em paralelo", + "Clear successful operations from the operation list after a 5 second delay": "Limpar as operações bem-sucedidas da lista após um atraso de 5 segundos", + "Download operations are not affected by this setting": "Operações de download não são afetadas por esta configuração", + "You may lose unsaved data": "Você pode perder dados não salvos", + "Ask to delete desktop shortcuts created during an install or upgrade.": "Perguntar se deseja excluir atalhos criados na área de trabalho durante a instalação ou atualização.", + "Package update preferences": "Preferências da atualização de pacotes", + "Update check frequency, automatically install updates, etc.": "Frequência de verificação de atualização, instalação automática de atualizações, etc.", + "Reduce UAC prompts, elevate installations by default, unlock certain dangerous features, etc.": "Reduza os prompts do UAC, eleve as instalações por padrão, desbloqueie certos recursos perigosos, etc.", + "Package operation preferences": "Preferências das operações de pacotes", + "Enable {pm}": "Habilitar {pm}", + "Not finding the file you are looking for? Make sure it has been added to path.": "Não encontrou o arquivo que procurava? Certifique-se de que ele foi adicionado ao caminho.", + "Select the executable to be used. The following list shows the executables found by UniGetUI": "Selecione o executável a ser usado. A seguinte lista exibe os executáveis encontrados pelo UniGetUI", + "For security reasons, changing the executable file is disabled by default": "Por razões de segurança, a alteração do arquivo executável é desabilitada por padrão", + "Change this": "Alterar isto", + "Copy path": "Copiar caminho", + "Current executable file:": "Arquivo executável atual:", + "Ignore packages from {pm} when showing a notification about updates": "Ignorar pacotes do {pm} ao exibir notificação sobre atualização", + "Update security": "Segurança das atualizações", + "Use global setting": "Usar configuração global", + "Minimum age for updates": "Idade mínima para atualizações", + "e.g. 10": "ex.: 10", + "Custom minimum age (days)": "Idade mínima personalizada (dias)", + "{pm} does not provide release dates for its packages, so this setting will have no effect": "{pm} não fornece datas de lançamento para seus pacotes, portanto esta configuração não terá efeito", + "{pm} only provides release dates for some of its packages, so this setting will only apply to those packages": "O {pm} só fornece datas de lançamento para alguns de seus pacotes, então essa configuração só será aplicada a esses pacotes", + "Override the global minimum update age for this package manager": "Substituir a idade mínima global de atualização para este gerenciador de pacotes", + "View {0} logs": "Visualizar registros do {0}", + "If Python cannot be found or is not listing packages but is installed on the system, ": "Se o Python não puder ser encontrado ou não estiver listando pacotes, mas estiver instalado no sistema, ", + "Advanced options": "Opções avançadas", + "WinGet command-line tool": "Ferramenta de linha de comando do WinGet", + "Choose which command-line tool UniGetUI uses for WinGet operations when the COM API is not used": "Escolha qual ferramenta de linha de comando o UniGetUI usa para operações do WinGet quando a COM API não é usada", + "WinGet COM API": "API COM do WinGet", + "Choose whether UniGetUI can use the WinGet COM API before falling back to the command-line tool": "Escolha se o UniGetUI pode usar a COM API do WinGet antes de recorrer à ferramenta de linha de comando", + "Reset WinGet": "Redefinir WinGet", + "This may help if no packages are listed": "Isso pode ajudar se nenhum pacote estiver listado", + "Force install location parameter when updating packages with custom locations": "Forçar o parâmetro de local de instalação ao atualizar pacotes com locais personalizados", + "Install Scoop": "Instalar Scoop", + "Uninstall Scoop (and its packages)": "Desinstalar o Scoop (e os seus pacotes)\n", + "Run cleanup and clear cache": "Executar limpeza e limpar cache", + "Run": "Executar", + "Enable Scoop cleanup on launch": "Ativar limpeza do Scoop na inicialização", + "Default vcpkg triplet": "Triplet padrão do vcpkg", + "Change vcpkg root location": "Alterar o local raiz do vcpkg", + "Reset vcpkg root location": "Redefinir local raiz do vcpkg", + "Open vcpkg root location": "Abrir local raiz do vcpkg", + "Language, theme and other miscellaneous preferences": "Idioma, tema e outras preferências diversas", + "Show notifications on different events": "Exibir notificações em diferentes eventos", + "Change how UniGetUI checks and installs available updates for your packages": "Alterar como o UniGetUI verifica e instala atualizações disponíveis para seus pacotes", + "Automatically save a list of all your installed packages to easily restore them.": "Salvar automaticamente uma lista de todos os seus pacotes instalados para restaurá-los facilmente.", + "Enable and disable package managers, change default install options, etc.": "Habilite e desabilite gerenciadores de pacotes, altere opções de instalação padrão, etc.", + "Internet connection settings": "Configurações de conexão com a Internet", + "Proxy settings, etc.": "Configurações do proxy, etc.", + "Beta features and other options that shouldn't be touched": "Recursos beta e outras opções que não devem ser alteradas", + "Reload sources": "Recarregar origens", + "Delete source": "Excluir origem", + "Known sources": "Origens conhecidas", + "Update checking": "Verificação de atualização", + "Automatic updates": "Atualizações automáticas", + "Check for package updates periodically": "Verificar atualizações de pacotes periodicamente", + "Check for updates every:": "Verificar atualizações a cada:", + "Install available updates automatically": "Instalar atualizações disponíveis automaticamente", + "Do not automatically install updates when the network connection is metered": "Não instalar atualizações automaticamente quando a conexão de rede for limitada", + "Do not automatically install updates when the device runs on battery": "Não instalar atualizações automaticamente quando o dispositivo estiver funcionando com bateria", + "Do not automatically install updates when the battery saver is on": "Não instalar atualizações automaticamente com a economia de bateria ativada", + "Only show updates that are at least the specified number of days old": "Mostrar apenas atualizações com pelo menos o número especificado de dias", + "Warn me when the installer URL host changes between the installed version and the new version (WinGet only)": "Avisar quando o host da URL do instalador mudar entre a versão instalada e a nova versão (somente WinGet)", + "Change how UniGetUI handles install, update and uninstall operations.": "Altere como o UniGetUI lida com as operações de instalação, atualização e desinstalação.", + "Navigation": "Navegação", + "Check for UniGetUI updates": "Verificar atualizações do UniGetUI", + "Quit UniGetUI": "Sair do UniGetUI", + "Filters": "Filtros", + "Sources": "Fontes", + "Search for packages to start": "Procure por pacotes para começar", + "Select all": "Selecionar tudo", + "Clear selection": "Limpar seleção", + "Instant search": "Pesquisa instantânea", + "Distinguish between uppercase and lowercase": "Diferenciar maiúsculas de minúsculas", + "Ignore special characters": "Ignorar caracteres especiais", + "Search mode": "Modo de pesquisa", + "Both": "Ambos", + "Exact match": "Correspondência exata", + "Show similar packages": "Mostrar pacotes semelhantes", + "Loading": "Carregando", + "Package": "Pacote", + "More options": "Mais opções", + "Order by:": "Classificar por:", + "Name": "Nome", + "Id": "ID", + "Ascendant": "Ascendente", + "Descendant": "Descendente", + "View modes": "Modos de exibição", + "Reload": "Recarregar", + "Closed": "Fechado", + "Ascending": "Crescente", + "Descending": "Decrescente", + "{0}: {1}, {2}": "{0}: {1}, {2}", + "Order by": "Ordenar por", + "No results were found matching the input criteria": "Nenhum resultado foi encontrado que corresponda aos critérios informados", + "No packages were found": "Nenhum pacote foi encontrado", + "Loading packages": "Carregando pacotes", + "Skip integrity checks": "Ignorar verificações de integridade", + "Download selected installers": "Baixar instaladores selecionados", + "Install selection": "Instalar seleção", + "Install options": "Opções de instalação", + "Add selection to bundle": "Adicionar seleção à coleção", + "Download installer": "Baixar instalador", + "Uninstall selection": "Desinstalar seleção", + "Uninstall options": "Opções de desinstalação", + "Ignore selected packages": "Ignorar pacotes selecionados", + "Open install location": "Abrir local de instalação", + "Reinstall package": "Reinstalar pacote", + "Uninstall package, then reinstall it": "Desinstalar pacote e reinstalá-lo", + "Ignore updates for this package": "Ignorar atualizações para este pacote", + "WinGet malfunction detected": "Mau funcionamento do WinGet detectado", + "It looks like WinGet is not working properly. Do you want to attempt to repair WinGet?": "Parece que o WinGet não está funcionando corretamente. Deseja tentar repará-lo?", + "Repair WinGet": "Reparar WinGet", + "Updates will no longer be ignored for {0}": "As atualizações não serão mais ignoradas para {0}", + "Updates are now ignored for {0}": "As atualizações agora são ignoradas para {0}", + "Do not ignore updates for this package anymore": "Não ignorar mais atualizações para este pacote", + "Add packages or open an existing package bundle": "Adicione pacotes ou abra uma coleção existente", + "Add packages to start": "Adicione pacotes para começar", + "The current bundle has no packages. Add some packages to get started": "A coleção de pacotes atual não contém pacotes. Adicione alguns para começar!", + "New": "Novo", + "Save as": "Salvar como", + "Create .ps1 script": "Criar script .ps1", + "Remove selection from bundle": "Remover seleção da coleção", + "Skip hash checks": "Ignorar verificações de hash", + "The package bundle is not valid": "A coleção de pacotes não é válida", + "The bundle you are trying to load appears to be invalid. Please check the file and try again.": "A coleção de pacotes que você está tentando carregar parece ser inválida. Verifique o arquivo e tente novamente.", + "Package bundle": "Coleção de pacotes", + "Could not create bundle": "Não foi possível criar a coleção de pacotes", + "The package bundle could not be created due to an error.": "Não foi possível criar a coleção de pacotes devido a um erro.", + "Install script": "Instalar script", + "PowerShell script": "Script do PowerShell", + "The installation script saved to {0}": "O script de instalação foi salvo em {0}", + "An error occurred": "Ocorreu um erro\n", + "An error occurred while attempting to create an installation script:": "Ocorreu um erro ao tentar criar o script de instalação:", + "Hooray! No updates were found.": "Uhu! Nenhuma atualização foi encontrada.", + "Uninstall selected packages": "Desinstalar pacotes selecionados", + "Update selection": "Atualizar seleção", + "Update options": "Opções de atualização", + "Uninstall package, then update it": "Desinstalar o pacote e atualizá-lo", + "Uninstall package": "Desinstalar pacote", + "Skip this version": "Pular esta versão", + "Pause updates for": "Pausar atualizações por", + "User | Local": "Usuário | Local", + "Machine | Global": "Máquina | Global", + "The default package manager for Debian/Ubuntu-based Linux distributions.
Contains: Debian/Ubuntu packages": "O gerenciador de pacotes padrão para distribuições Linux baseadas em Debian/Ubuntu.
Contém: pacotes Debian/Ubuntu", + "The Rust package manager.
Contains: Rust libraries and programs written in Rust": "O gerenciador de pacotes Rust.
Contém: Bibliotecas Rust e programas escritos em Rust", + "The classical package manager for windows. You'll find everything there.
Contains: General Software": "O gerenciador de pacotes clássico para Windows. Você encontrará tudo lá.
Contém: Software Geral", + "The default package manager for RHEL/Fedora-based Linux distributions.
Contains: RPM packages": "O gerenciador de pacotes padrão para distribuições Linux baseadas em RHEL/Fedora.
Contém: pacotes RPM", + "A repository full of tools and executables designed with Microsoft's .NET ecosystem in mind.
Contains: .NET related tools and scripts": "Um repositório repleto de ferramentas e executáveis projetados para o ecossistema .NET da Microsoft.
Contém: ferramentas e scripts relacionados ao .NET", + "The universal Linux package manager for desktop applications.
Contains: Flatpak applications from configured remotes": "O gerenciador de pacotes universal para aplicativos de desktop no Linux.
Contém: aplicativos Flatpak de remotos configurados", + "NuPkg (zipped manifest)": "NuPkg (manifesto compactado)", + "The Missing Package Manager for macOS (or Linux).
Contains: Formulae, Casks": "O gerenciador de pacotes que faltava para macOS (ou Linux).
Contém: Fórmulas, Casks", + "Node JS's package manager. Full of libraries and other utilities that orbit the javascript world
Contains: Node javascript libraries and other related utilities": "Gerenciador de pacotes do Node JS. Repleto de bibliotecas e outros utilitários que orbitam o mundo JavaScript
Contém: Bibliotecas JavaScript do Node e outros utilitários relacionados", + "The default package manager for Arch Linux and its derivatives.
Contains: Arch Linux packages": "O gerenciador de pacotes padrão para Arch Linux e seus derivados.
Contém: pacotes Arch Linux", + "Python's library manager. Full of python libraries and other python-related utilities
Contains: Python libraries and related utilities": "Gerenciador de bibliotecas do Python. Repleto de bibliotecas Python e outros utilitários relacionados ao Python
Contém: Bibliotecas Python e utilitários relacionados", + "PowerShell's package manager. Find libraries and scripts to expand PowerShell capabilities
Contains: Modules, Scripts, Cmdlets": "Gerenciador de pacotes do PowerShell. Encontre bibliotecas e scripts para expandir as capacidades do PowerShell
Contém: Módulos, Scripts, Cmdlets", + "extracted": "extraído", + "Scoop package": "Pacote do Scoop", + "Great repository of unknown but useful utilities and other interesting packages.
Contains: Utilities, Command-line programs, General Software (extras bucket required)": "Uma vasta coleção de utilitários úteis, ainda que pouco conhecidos, e pacotes variados.
Contém: Utilitários, Programas para linha de comando, Software geral (é necessário habilitar o bucket extras)", + "The universal Linux package manager by Canonical.
Contains: Snap packages from the Snapcraft store": "O gerenciador de pacotes universal para Linux da Canonical.
Contém: pacotes Snap da loja Snapcraft", + "library": "biblioteca", + "feature": "recurso", + "A popular C/C++ library manager. Full of C/C++ libraries and other C/C++-related utilities
Contains: C/C++ libraries and related utilities": "Um gerenciador de bibliotecas C/C++ bastante popular. Repleto de bibliotecas C/C++ e outras ferramentas relacionadas a C/C++
Contém: Bibliotecas C/C++ e ferramentas relacionadas", + "option": "opção", + "This package cannot be installed from an elevated context.": "Este pacote não pode ser instalado em um contexto com privilégios elevados.", + "Please run UniGetUI as a regular user and try again.": "Execute o UniGetUI como um usuário comum e tente novamente.", + "Please check the installation options for this package and try again": "Verifique as opções de instalação deste pacote e tente novamente", + "Microsoft's official package manager. Full of well-known and verified packages
Contains: General Software, Microsoft Store apps": "Gerenciador de pacotes oficial da Microsoft. Repleto de pacotes conhecidos e verificados
Contém: Software Geral, aplicativos da Microsoft Store", + "Local PC": "PC Local", + "Android Subsystem": "Subsistema Android", + "Operation on queue (position {0})...": "Operação na fila (posição {0})...", + "Click here for more details": "Clique aqui para mais detalhes", + "Operation canceled by user": "Operação cancelada pelo usuário", + "Running PreOperation ({0}/{1})...": "Executando PreOperation ({0}/{1})...", + "PreOperation {0} out of {1} failed, and was tagged as necessary. Aborting...": "A PreOperation {0} de {1} falhou e foi marcada como necessária. Abortando...", + "PreOperation {0} out of {1} finished with result {2}": "A PreOperation {0} de {1} terminou com o resultado {2}", + "Starting operation...": "Iniciando operação...", + "Running PostOperation ({0}/{1})...": "Executando PostOperation ({0}/{1})...", + "PostOperation {0} out of {1} failed, and was tagged as necessary. Aborting...": "A PostOperation {0} de {1} falhou e foi marcada como necessária. Abortando...", + "PostOperation {0} out of {1} finished with result {2}": "A PostOperation {0} de {1} terminou com o resultado {2}", + "{package} installer download": "Download do instalador do {package}", + "{0} installer is being downloaded": "O instalador do {0} está sendo baixado", + "Download succeeded": "Download concluído", + "{package} installer was downloaded successfully": "Instalador do {package} baixado com sucesso", + "Download failed": "Falha no download", + "{package} installer could not be downloaded": "O instalador do {package} não pôde ser baixado", + "{package} Installation": "Instalação de {package}", + "{0} is being installed": "{0} está sendo instalado", + "Installation succeeded": "Instalação concluída com sucesso!", + "{package} was installed successfully": "{package} foi instalado com sucesso", + "Installation failed": "A instalação falhou!", + "{package} could not be installed": "{package} não pôde ser instalado", + "{package} Update": "Atualizando {package}...", + "Update succeeded": "Atualização bem-sucedida", + "{package} was updated successfully": "{package} foi atualizado com sucesso", + "Update failed": "Falha na atualização", + "{package} could not be updated": "{package} não pôde ser atualizado", + "{package} Uninstall": "Desinstalação de {package}", + "{0} is being uninstalled": "{0} está sendo desinstalado", + "Uninstall succeeded": "Desinstalação bem-sucedida", + "{package} was uninstalled successfully": "{package} foi desinstalado com sucesso", + "Uninstall failed": "Desinstalação falhou", + "{package} could not be uninstalled": "{package} não pôde ser desinstalado", + "Adding source {source}": "Adicionando fonte {source}", + "Adding source {source} to {manager}": "Adicionando a fonte {source} ao {manager}", + "Source added successfully": "Fonte adicionada com sucesso", + "The source {source} was added to {manager} successfully": "A fonte {source} foi adicionada ao {manager} com sucesso", + "Could not add source": "Não foi possível adicionar a fonte", + "Could not add source {source} to {manager}": "Não foi possível adicionar a fonte {source} ao {manager}", + "Removing source {source}": "Removendo fonte {source}", + "Removing source {source} from {manager}": "Removendo fonte {source} do {manager}", + "Source removed successfully": "Fonte removida com sucesso", + "The source {source} was removed from {manager} successfully": "A fonte {source} foi removida do {manager} com sucesso", + "Could not remove source": "Não foi possível remover a fonte", + "Could not remove source {source} from {manager}": "Não foi possível remover a fonte {source} do {manager}", + "The package manager \"{0}\" was not found": "O gerenciador de pacotes \"{0}\" não foi encontrado", + "The package manager \"{0}\" is disabled": "O gerenciador de pacotes \"{0}\" está desativado", + "There is an error with the configuration of the package manager \"{0}\"": "Há um erro na configuração do gerenciador de pacotes \"{0}\"", + "The package \"{0}\" was not found on the package manager \"{1}\"": "O pacote \"{0}\" não foi encontrado no gerenciador de pacotes \"{1}\"", + "{0} is disabled": "O {0} está desativado", + "{0} weeks": "{0} semanas", + "1 month": "1 mês", + "{0} months": "{0} meses", + "Something went wrong": "Algo deu errado", + "An interal error occurred. Please view the log for further details.": "Foi identificado um erro interno. Verifique o log para obter mais informações.", + "No applicable installer was found for the package {0}": "Nenhum instalador encontrado para o pacote {0}", + "Integrity checks will not be performed during this operation": "As verificações de integridade não serão executadas durante esta operação", + "This is not recommended.": "Isto não é recomendado", + "Run now": "Executar agora", + "Run next": "Executar próximo", + "Run last": "Executar último", + "Show in explorer": "Exibir no Explorer", + "Checked": "Marcado", + "Unchecked": "Desmarcado", + "This package is already installed": "Este pacote já está instalado", + "This package can be upgraded to version {0}": "Este pacote pode ser atualizado para a versão {0}", + "Updates for this package are ignored": "As atualizações para este pacote estão sendo ignoradas", + "This package is being processed": "Este pacote está sendo processado", + "This package is not available": "Este pacote não está disponível", + "Select the source you want to add:": "Selecione a fonte que você deseja adicionar:", + "Source name:": "Nome da fonte:", + "Source URL:": "URL da fonte:", + "An error occurred when adding the source: ": "Ocorreu um erro ao adicionar a fonte:", + "Package management made easy": "Gestão de pacotes facilitada", + "version {0}": "versão {0}", + "[RAN AS ADMINISTRATOR]": "EXECUTADO COMO ADMINISTRADOR", + "Portable mode": "Modo portátil", + "DEBUG BUILD": "COMPILAÇÃO DE DEPURAÇÃO", + "Here you can change UniGetUI's behaviour regarding the following shortcuts. Checking a shortcut will make UniGetUI delete it if if gets created on a future upgrade. Unchecking it will keep the shortcut intact": "Aqui você pode alterar o comportamento do UniGetUI em relação aos atalhos abaixo. Marcar um atalho fará com que o UniGetUI o exclua caso ele seja criado em uma futura atualização. Desmarcar manterá o atalho intacto", + "Manual scan": "Verificação manual", + "Existing shortcuts on your desktop will be scanned, and you will need to pick which ones to keep and which ones to remove.": "Atalhos existentes na sua área de trabalho serão verificados, e você precisará escolher quais manter e quais remover.", + "Delete?": "Excluir?", + "I understand": "Entendi", + "Chocolatey setup changed": "A configuração do Chocolatey foi alterada", + "UniGetUI no longer includes its own private Chocolatey installation. A legacy UniGetUI-managed Chocolatey installation was detected for this user profile, but system Chocolatey was not found. Chocolatey will stay unavailable in UniGetUI until Chocolatey is installed on the system and UniGetUI is restarted. Applications previously installed through UniGetUI's bundled Chocolatey may still appear under other sources such as Local PC or WinGet.": "O UniGetUI não inclui mais sua própria instalação privada do Chocolatey. Uma instalação legada do Chocolatey gerenciada pelo UniGetUI foi detectada para este perfil de usuário, mas o Chocolatey do sistema não foi encontrado. O Chocolatey permanecerá indisponível no UniGetUI até que o Chocolatey seja instalado no sistema e o UniGetUI seja reiniciado. Os aplicativos instalados anteriormente por meio do Chocolatey incluído no UniGetUI ainda podem aparecer em outras origens, como PC Local ou WinGet.", + "NOTE: This troubleshooter can be disabled from UniGetUI Settings, on the WinGet section": "OBSERVAÇÃO: esta solução de problemas pode ser desabilitada nas Configurações do UniGetUI, na seção WinGet", + "Restart": "Reiniciar", + "Are you sure you want to delete all shortcuts?": "Você deseja realmente excluir todos os atalhos?", + "Any new shorcuts created during an install or an update operation will be deleted automatically, instead of showing a confirmation prompt the first time they are detected.": "Quaisquer atalhos criados durante a instalação ou atualização serão excluídos automaticamente, em vez de mostrar um prompt de confirmação na primeira vez que forem detectados.", + "Any shorcuts created or modified outside of UniGetUI will be ignored. You will be able to add them via the {0} button.": "Quaisquer atalhos criados ou modificados fora do UniGetUI serão ignorados. Você poderá adicioná-los com o botão {0}.", + "Are you really sure you want to enable this feature?": "Você deseja realmente ativar este recurso?", + "No new shortcuts were found during the scan.": "Nenhum novo atalho foi encontrado durante a verificação.", + "How to add packages to a bundle": "Como adicionar pacotes no conjunto", + "In order to add packages to a bundle, you will need to: ": "Para poder adicionar pacotes no conjunto, você precisará:", + "1. Navigate to the \"{0}\" or \"{1}\" page.": "1. Navegue até a página \"{0}\" ou \"{1}\".", + "2. Locate the package(s) you want to add to the bundle, and select their leftmost checkbox.": "2. Encontre os pacotes que deseja adicionar ao conjunto e selecione a caixa de seleção mais à esquerda.", + "3. When the packages you want to add to the bundle are selected, find and click the option \"{0}\" on the toolbar.": "3. Quando os pacotes que deseja adicionar ao conjunto estiverem selecionados, localize e clique na opção \"{0}\" na barra de ferramentas.", + "4. Your packages will have been added to the bundle. You can continue adding packages, or export the bundle.": "4. Os seus pacotes serão adicionados ao conjunto. Você pode continuar adicionando pacotes ou exportar o conjunto.", + "Which backup do you want to open?": "Qual backup você deseja abrir?", + "Select the backup you want to open. Later, you will be able to review which packages you want to install.": "Selecione o backup que deseja abrir. Posteriormente, você poderá verificar quais pacotes/programas deseja restaurar.", + "There are ongoing operations. Quitting UniGetUI may cause them to fail. Do you want to continue?": "Há operações em andamento. Sair do UniGetUI pode fazer com que elas falhem. Deseja continuar?", + "UniGetUI or some of its components are missing or corrupt.": "O UniGetUI ou alguns de seus componentes estão ausentes ou corrompidos.", + "It is strongly recommended to reinstall UniGetUI to adress the situation.": "É altamente recomendável reinstalar o UniGetUI para resolver a situação.", + "Refer to the UniGetUI Logs to get more details regarding the affected file(s)": "Consulte os registros do UniGetUI para obter mais detalhes sobre os arquivos afetados", + "Integrity checks can be disabled from the Experimental Settings": "As verificações de integridade podem ser desabilitadas nas Configurações Experimentais", + "Repair UniGetUI": "Reparar o UniGetUI", + "Live output": "Saída em tempo real", + "This package bundle had some settings that are potentially dangerous, and may be ignored by default.": "Este pacote possui algumas configurações que são potencialmente perigosas e podem ser ignoradas por padrão.", + "Entries that show in YELLOW will be IGNORED.": "As entradas que aparecerem em AMARELO serão IGNORADAS.", + "Entries that show in RED will be IMPORTED.": "As entradas que aparecerem em VERMELHO serão IMPORTADAS.", + "You can change this behavior on UniGetUI security settings.": "Você pode alterar esse comportamento nas configurações de segurança do UniGetUI.", + "Open UniGetUI security settings": "Anrir configurações de segurança do UniGetUI", + "Should you modify the security settings, you will need to open the bundle again for the changes to take effect.": "Caso você modifique as configurações de segurança, será necessário abrir o pacote novamente para que as alterações entrem em vigor.", + "Details of the report:": "Detalhes do relatório:", + "Are you sure you want to create a new package bundle? ": "Tem certeza de que deseja criar uma nova coleção de pacotes? ", + "Any unsaved changes will be lost": "Quaisquer alterações não salvas serão perdidas", + "Warning!": "Aviso!", + "For security reasons, custom command-line arguments are disabled by default. Go to UniGetUI security settings to change this. ": "Por motivos de segurança, os argumentos de linha de comando personalizados são desabilitados por padrão. Acesse as configurações de segurança do UniGetUI para alterar isso.", + "Change default options": "Alterar opções padrão", + "Ignore future updates for this package": "Ignorar futuras atualizações para este pacote", + "For security reasons, pre-operation and post-operation scripts are disabled by default. Go to UniGetUI security settings to change this. ": "Por motivos de segurança, os scripts de pré e pós-operação são desabilitados por padrão. Acesse as configurações de segurança do UniGetUI para alterar isso.", + "You can define the commands that will be run before or after this package is installed, updated or uninstalled. They will be run on a command prompt, so CMD scripts will work here.": "Você pode definir os comandos que serão executados antes ou depois da instalação, atualização ou desinstalação deste pacote. Eles serão executados em um prompt de comando, portanto, scripts CMD funcionarão aqui.", + "Change this and unlock": "Alterar isto e desbloquear", + "{0} Install options are currently locked because {0} follows the default install options.": "{0} opções de instalação estão bloqueadas no momento porque {0} seguem as opções de instalação padrão.", + "Unset or unknown": "Não definido ou desconhecido", + "This package has no screenshots or is missing the icon? Contrbute to UniGetUI by adding the missing icons and screenshots to our open, public database.": "Este pacote não tem capturas de tela ou está faltando o ícone? Contribua para o UniGetUI adicionando os ícones e capturas de tela ausentes ao nosso banco de dados público e aberto.", + "Become a contributor": "Torne-se um colaborador", + "Update to {0} available": "Atualização para {0} disponível", + "Reinstall": "Reinstalar", + "Installer not available": "Instalador não disponível", + "Version:": "Versão:", + "UniGetUI Version {0}": "UniGetUI Versão {0}", + "Performing backup, please wait...": "Fazendo backup, aguarde...", + "An error occurred while logging in: ": "Ocorreu um erro ao fazer login:", + "Fetching available backups...": "Buscando backups disponíveis...", + "Done!": "Concluído!", + "The cloud backup has been loaded successfully.": "O backup na nuvem foi carregado com sucesso.", + "An error occurred while loading a backup: ": "Ocorreu um erro ao carregar o backup:", + "Backing up packages to GitHub Gist...": "Fazendo backup dos pacotes para o Github Gist...", + "Backup Successful": "Backup bem sucedido", + "The cloud backup completed successfully.": "O backup na nuvem foi concluído com sucesso.", + "Could not back up packages to GitHub Gist: ": "Não foi possível fazer backup dos pacotes para o GitHub Gist:", + "It is not guaranteed that the provided credentials will be stored safely, so you may as well not use the credentials of your bank account": "Não há garantia de que as credenciais fornecidas serão armazenadas com segurança, portanto, você também não pode usar as credenciais da sua conta bancária.", + "Enable the automatic WinGet troubleshooter": "Habilitar a solução de problemas automática do WinGet", + "Add updates that fail with a 'no applicable update found' to the ignored updates list": "Adicionar atualizações com falha 'nenhuma atualização aplicável encontrada' à lista de atualizações ignoradas", + "Invalid selection": "Seleção inválida", + "No package was selected": "Nenhum pacote foi selecionado", + "More than 1 package was selected": "Mais de 1 pacote foi selecionado", + "List": "Lista", + "Grid": "Grade", + "Icons": "Ícones", + "\"{0}\" is a local package and does not have available details": "\"{0}\" é um pacote local e não possui detalhes suficientes", + "\"{0}\" is a local package and is not compatible with this feature": "\"{0}\" é um pacote local e não é compatível com este recurso", + "Add packages to bundle": "Adicionar pacotes ao conjunto", + "Preparing packages, please wait...": "Preparando pacotes, por favor aguarde.", + "Loading packages, please wait...": "Carregando pacotes, por favor aguarde...", + "Saving packages, please wait...": "Salvando pacotes, por favor aguarde.", + "The bundle was created successfully on {0}": "O pacote foi criado com sucesso em {0}", + "User profile": "Perfil de usuário", + "Error": "Erro", + "Log in failed: ": "Falha no login:", + "Log out failed: ": "Falha ao sair:", + "Package backup settings": "Configurações de backup do pacote", + "Package managers": "Gerenciadores de pacotes", + "Manage UniGetUI autostart behaviour from the Settings app": "Gerenciar o comportamento de inicialização automática do UniGetUI", + "Choose how many operations shoulds be performed in parallel": "Escolha quantas operações devem ser executadas em paralelo", + "Something went wrong while launching the updater.": "Algo deu errado ao iniciar o atualizador.", + "Please try again later": "Por favor, tente novamente mais tarde", + "Show the release notes after UniGetUI is updated": "Mostrar as notas de lançamento após a atualização do UniGetUI" +} diff --git a/src/Languages/lang_pt_PT.json b/src/Languages/lang_pt_PT.json new file mode 100644 index 0000000..eccf55f --- /dev/null +++ b/src/Languages/lang_pt_PT.json @@ -0,0 +1,851 @@ +{ + "{0} of {1} operations completed": "{0} de {1} operações concluídas", + "{0} is now {1}": "{0} é agora {1}", + "Enabled": "Ativado", + "Disabled": "Desabilitado", + "Privacy": "Privacidade", + "Hide my username from the logs": "Ocultar o meu nome de utilizador dos registos", + "Replaces your username with **** in the logs. Restart UniGetUI to also hide it from already-recorded entries.": "Substitui o seu nome de utilizador por **** nos registos. Reinicie o UniGetUI para o ocultar também nas entradas já registadas.", + "Your last update attempt did not complete.": "A sua última tentativa de atualização não foi concluída.", + "UniGetUI could not confirm whether the update succeeded. Open the log to see what happened.": "O UniGetUI não conseguiu confirmar se a atualização foi bem-sucedida. Abra o registo para ver o que aconteceu.", + "View log": "Ver registo", + "The installer reported success but did not restart UniGetUI.": "O instalador comunicou êxito, mas não reiniciou o UniGetUI.", + "The installer failed to initialize.": "O instalador não conseguiu inicializar.", + "Setup was canceled before installation began.": "A configuração foi cancelada antes de a instalação começar.", + "A fatal error occurred during the preparation phase.": "Ocorreu um erro fatal durante a fase de preparação.", + "A fatal error occurred during installation.": "Ocorreu um erro fatal durante a instalação.", + "Installation was canceled while in progress.": "A instalação foi cancelada enquanto estava em curso.", + "The installer was terminated by another process.": "O instalador foi terminado por outro processo.", + "The preparation phase determined the installation cannot proceed.": "A fase de preparação determinou que a instalação não pode prosseguir.", + "The installer could not start. UniGetUI may already be running, or you do not have permission to install.": "Não foi possível iniciar o instalador. O UniGetUI pode já estar em execução ou pode não ter permissão para instalar.", + "Unexpected installer error.": "Erro inesperado do instalador.", + "We are checking for updates.": "Estamos a verificar atualizações.", + "Please wait": "Por favor aguarde", + "Great! You are on the latest version.": "Excelente! Tem a versão mais recente.", + "There are no new UniGetUI versions to be installed": "Não existem novas versões do UniGetUI para instalar", + "UniGetUI version {0} is being downloaded.": "A versão {0} do UniGetUI está a ser descarregada.", + "This may take a minute or two": "Isto pode demorar um minuto ou dois", + "The installer authenticity could not be verified.": "Não foi possível verificar a autenticidade do instalador.", + "The update process has been aborted.": "O processo de atualização foi interrompido.", + "Auto-update is not yet available on this platform.": "A atualização automática ainda não está disponível nesta plataforma.", + "Please update UniGetUI manually.": "Atualize o UniGetUI manualmente.", + "An error occurred when checking for updates: ": "Ocorreu um erro ao procurar por atualizaçoes:", + "The updater could not be launched.": "Não foi possível iniciar o atualizador.", + "The operating system did not start the installer process.": "O sistema operativo não iniciou o processo do instalador.", + "UniGetUI is being updated...": "O UniGetUI está a ser atualizado...", + "Update installed.": "Atualização instalada.", + "UniGetUI was updated successfully, but this running copy was not replaced. This usually means you are running a development build. Close this copy and start the newly-installed version to finish.": "O UniGetUI foi atualizado com sucesso, mas esta cópia em execução não foi substituída. Normalmente, isto significa que está a executar uma compilação de desenvolvimento. Feche esta cópia e inicie a versão recém-instalada para concluir.", + "The update could not be applied.": "Não foi possível aplicar a atualização.", + "Installer exit code {0}: {1}": "Código de saída do instalador {0}: {1}", + "Update cancelled.": "Atualização cancelada.", + "Authentication was cancelled.": "A autenticação foi cancelada.", + "Installer exit code {0}": "Código de saída do instalador {0}", + "Operation in progress": "Operação em andamento", + "Please wait...": "Por favor, aguarde...", + "Success!": "Sucesso!", + "Failed": "Falhou", + "An error occurred while processing this package": "Ocorreu um erro a processar este pacote", + "Installer": "Instalador", + "Executable": "Executável", + "MSI": "MSI", + "Compressed file": "Ficheiro comprimido", + "MSIX": "MSIX", + "WinGet was repaired successfully": "O WinGet foi reparado com sucesso", + "It is recommended to restart UniGetUI after WinGet has been repaired": "É recomendado reiniciar o UniGetUI após o WinGet ter sido reparado", + "WinGet could not be repaired": "O WinGet não pôde ser reparado", + "An unexpected issue occurred while attempting to repair WinGet. Please try again later": "Ocorreu um problema inesperado ao tentar reparar o WinGet. Por favor, tente mais tarde", + "Log in to enable cloud backup": "Inicia sessão para ativar cópias de segurança na nuvem", + "Backup Failed": "Cópia de segurança falhou", + "Downloading backup...": "A descarregar cópia de segurança...", + "An update was found!": "Foi encontrada uma atualização!", + "{0} can be updated to version {1}": "{0} pode ser atualizado para a versão {1}", + "Updates found!": "Atualizações encontradas!", + "{0} packages can be updated": "{0} pacotes podem ser atualizados", + "{0} is being updated to version {1}": "{0} está a ser atualizado para a versão {1}", + "{0} packages are being updated": "{0} pacotes estão a ser atualizados", + "You have currently version {0} installed": "Tem atualmente a versão {0} instalada", + "Desktop shortcut created": "Atalho criado no ambiente de trabalho", + "UniGetUI has detected a new desktop shortcut that can be deleted automatically.": "O UniGetUI detetou um novo atalho no ambiente de trabalho que pode ser eliminado automaticamente.", + "{0} desktop shortcuts created": "{0} atalhos de ambiente de trabalho criados", + "UniGetUI has detected {0} new desktop shortcuts that can be deleted automatically.": "O UniGetUI detetou {0} novos atalhos na área de trabalho que podem ser eliminados automaticamente.", + "Attention required": "Atenção necessária", + "Restart required": "É necessário reiniciar", + "1 update is available": "1 atualização disponível", + "{0} updates are available": "{0} atualizações disponíveis", + "Everything is up to date": "Todos os pacotes estão atualizados", + "Discover Packages": "Descobrir Pacotes", + "Available Updates": "Atualizações disponíveis", + "Installed Packages": "Pacotes Instalados", + "UniGetUI Version {0} by Devolutions": "UniGetUI Versão {0} pela Devolutions", + "Show UniGetUI": "Mostrar o UniGetUI", + "Quit": "Sair", + "Are you sure?": "Tem certeza?", + "Do you really want to uninstall {0}?": "Deseja realmente desinstalar {0}?", + "Do you really want to uninstall the following {0} packages?": "Deseja realmente desinstalar os seguintes {0} pacotes?", + "No": "Não", + "Yes": "Sim", + "Partial": "Parcial", + "View on UniGetUI": "Ver no UniGetUI", + "Update": "Atualizar", + "Open UniGetUI": "Abrir UniGetUI", + "Update all": "Atualizar todos", + "Update now": "Atualizar agora", + "Installer host changed since the installed version.\n": "O anfitrião do instalador foi alterado desde a versão instalada.\n", + "This package is on the queue": "Este pacote está na fila", + "installing": "A instalar", + "updating": "a atualizar", + "uninstalling": "a desinstalar", + "installed": "instalado", + "Retry": "Nova tentativa", + "Install": "Instalar", + "Uninstall": "Desinstalar", + "Open": "Abrir", + "Operation profile:": "Perfil da operação:", + "Follow the default options when installing, upgrading or uninstalling this package": "Seguir as opções padrão quando a instalar, a atualizar ou a desinstalar este pacote", + "The following settings will be applied each time this package is installed, updated or removed.": "As seguintes configurações serão aplicadas sempre que este pacote for instalado, atualizado ou removido.", + "Version to install:": "Versão para instalar:", + "Architecture to install:": "Arquitetura para instalar:", + "Installation scope:": "Âmbito da instalação:", + "Install location:": "Local de instalação:", + "Select": "Seleccionar", + "Reset": "Repor", + "Custom install arguments:": "Argumentos de instalação personalizados:", + "Custom update arguments:": "Argumentos de atualização personalizados:", + "Custom uninstall arguments:": "Argumentos de desinstalação personalizados:", + "Pre-install command:": "Comando pré-instalação:", + "Post-install command:": "Comando pós-instalação", + "Abort install if pre-install command fails": "Abortar instalação se comando pré-instalação falhar", + "Pre-update command:": "Comando pré-atualização:", + "Post-update command:": "Comando pós-atualização", + "Abort update if pre-update command fails": "Abortar atualização se comando pré-atualização falhar", + "Pre-uninstall command:": "Comando pré-desinstalação:", + "Post-uninstall command:": "Comando pós-desinstalação", + "Abort uninstall if pre-uninstall command fails": "Abortar desinstalação se comando pré-desinstalação falhar", + "Command-line to run:": "Linha de comandos para correr:", + "Save and close": "Salvar e fechar", + "General": "Geral", + "Architecture & Location": "Arquitetura e localização", + "Command-line": "Linha de comandos", + "Close apps": "Fechar aplicações", + "Pre/Post install": "Pré/pós-instalação", + "Select the processes that should be closed before this package is installed, updated or uninstalled.": "Seleciona o processo que deve ser terminado antes que este pacote seja instalado, atualizado ou desinstalado.", + "Write here the process names here, separated by commas (,)": "Escreve aqui o nome(s) do(s) processo(s), separado por virgulas (,)", + "Try to kill the processes that refuse to close when requested to": "Tenta matar os processos que se recusam a fechar após pedido", + "Run as admin": "Executar como administrador", + "Interactive installation": "Instalação interativa ", + "Skip hash check": "Ignorar verificação de hash", + "Uninstall previous versions when updated": "Desinstalar versões anteriores quando atualizar", + "Skip minor updates for this package": "Ignorar atualizações menores para este pacote", + "Automatically update this package": "Atualizar automaticamente este pacote", + "{0} installation options": "{0} opções de instalação", + "Latest": "Último", + "PreRelease": "Pré-lançamento", + "Default": "Padrão", + "Manage ignored updates": "Gerir atualizações ignoradas", + "The packages listed here won't be taken in account when checking for updates. Double-click them or click the button on their right to stop ignoring their updates.": "Os pacotes listados aqui não serão tidos em conta na verificação de atualizações. Clique duas vezes neles ou clique no botão à direita para parar de ignorar suas atualizações.", + "Reset list": "Repôr lista", + "Do you really want to reset the ignored updates list? This action cannot be reverted": "Tem a certeza de que pretende repor a lista de atualizações ignoradas? Esta ação não pode ser revertida", + "No ignored updates": "Sem atualizações ignoradas", + "Package Name": "Nome do Pacote", + "Package ID": "ID do Pacote", + "Ignored version": "Versão Ignorada", + "New version": "Nova versão", + "Source": "Fonte", + "All versions": "Todas as versões", + "Unknown": "Desconhecido", + "Up to date": "Atualizado", + "Package {name} from {manager}": "Pacote {name} de {manager}", + "Remove {0} from ignored updates": "Remover {0} das atualizações ignoradas", + "Cancel": "Cancelar", + "Administrator privileges": "Privilégios de administrador", + "This operation is running with administrator privileges.": "Esta operação está a correr com privilégios de administrador.", + "Interactive operation": "Operação interativa", + "This operation is running interactively.": "Esta operação está a correr de forma interativa.", + "You will likely need to interact with the installer.": "Provavelmente terá de interagir com o instalador.", + "Integrity checks skipped": "Verificações de integridade ignoradas", + "Integrity checks will not be performed during this operation.": "As verificações de integridade não serão realizadas durante esta operação.", + "Proceed at your own risk.": "Prossiga por sua conta e risco.", + "Close": "Fechar", + "Loading...": "A carregar...", + "Installer SHA256": "SHA256 do Instalador", + "Homepage": "Página Inicial", + "Author": "Autor(a)", + "Publisher": "Publicador", + "License": "Licença", + "Manifest": "Manifesto", + "Installer Type": "Tipo de Instalador", + "Size": "Tamanho", + "Installer URL": "URL do Instalador ", + "Last updated:": "Última atualização:", + "Release notes URL": "URL das Notas de lançamento", + "Package details": "Detalhes do pacote", + "Dependencies:": "Dependências:", + "Release notes": "Notas de lançamento", + "Screenshots": "Capturas de ecrã", + "This package has no screenshots or is missing the icon? Contribute to UniGetUI by adding the missing icons and screenshots to our open, public database.": "Este pacote não tem capturas de ecrã ou falta-lhe o ícone? Contribua para o UniGetUI adicionando os ícones e capturas de ecrã em falta à nossa base de dados aberta e pública.", + "Version": "Versão", + "Install as administrator": "Instalar como administrador", + "Update to version {0}": "Atualizar para a versão {0}", + "Installed Version": "Versão Instalada", + "Update as administrator": "Atualizar como administrador", + "Interactive update": "Atualização interativa ", + "Uninstall as administrator": "Desinstalar como administrador", + "Interactive uninstall": "Desinstalação interativa ", + "Uninstall and remove data": "Desinstalar e remover dados", + "Not available": "Não disponível", + "Installer SHA512": "SHA512 do instalador", + "Unknown size": "Tamanho desconhecido", + "No dependencies specified": "Sem dependências especificadas", + "mandatory": "obrigatório", + "optional": "opcional", + "UniGetUI {0} is ready to be installed.": "O UniGetUI {0} está pronto para ser instalado.", + "The update process will start after closing UniGetUI": "A atualização será iniciada após fechar o UniGetUI", + "UniGetUI has been ran as administrator, which is not recommended. When running UniGetUI as administrator, EVERY operation launched from UniGetUI will have administrator privileges. You can still use the program, but we highly recommend not running UniGetUI with administrator privileges.": "O UniGetUI foi executado como administrador, o que não é recomendado. Ao executar o UniGetUI como administrador, TODAS as operações iniciadas a partir do UniGetUI terão privilégios de administrador. Ainda pode utilizar o programa, mas recomendamos vivamente que não execute o UniGetUI com privilégios de administrador.", + "Share anonymous usage data": "Partilhar dados de utilização anónimos", + "UniGetUI collects anonymous usage data in order to improve the user experience.": "O UniGetUI coleta dados de uso anónimos para melhorar a experiência do utilizador.", + "Accept": "Aceitar", + "Software Updates": "Atualizações de Software", + "Package Bundles": "Conjunto de pacotes", + "Settings": "Definições", + "Package Managers": "Gestores de pacotes", + "UniGetUI Log": "Registo do UniGetUI", + "Package Manager logs": "Logs do gestor de pacotes", + "Operation history": "Histórico de operações ", + "Help": "Ajuda", + "UniGetUI": "UniGetUI", + "You have installed UniGetUI Version {0}": "Instalou o UniGetUI versão {0}", + "Disclaimer": "Renúncia de responsabilidade", + "UniGetUI is developed by Devolutions and is not affiliated with any of the compatible package managers.": "O UniGetUI é desenvolvido pela Devolutions e não está afiliado a nenhum dos gestores de pacotes compatíveis.", + "UniGetUI wouldn't have been possible without the help of the contributors. Thank you all 🥳": "O UniGetUI não teria sido possível sem a ajuda dos seus colaboradores. Obrigado a todos 🥳", + "UniGetUI uses the following libraries. Without them, UniGetUI wouldn't have been possible.": "UniGetUI usa as seguintes bibliotecas. Sem elas, o UniGetUI não teria sido possível.", + "{0} homepage": "{0} página inicial", + "UniGetUI has been translated to more than 40 languages thanks to the volunteer translators. Thank you 🤝": "O UniGetUI foi traduzido para mais de 40 idiomas graças a tradutores voluntários. Obrigado 🤝", + "Verbose": "Detalhado", + "1 - Errors": "1 - Erros", + "2 - Warnings": "2 - Avisos", + "3 - Information (less)": "3 - Informação (menos)", + "4 - Information (more)": "4 - Informação (mais)", + "5 - information (debug)": "5 - Informação (debug)", + "Warning": "Atenção", + "The following settings may pose a security risk, hence they are disabled by default.": "As seguintes configurações podem apresentar risco de segurança, por isso essas estão desabilitadas por padrão.", + "Enable the settings below if and only if you fully understand what they do, and the implications they may have.": "Ativa as definições abaixo SE E APENAS SE tu percebes o que elas fazem, e as implicações e perigos que elas podem involver.", + "The settings will list, in their descriptions, the potential security issues they may have.": "As definições vão indicar, nas suas descrições, os potenciais problemas de segurança que podem ter.", + "The backup will include the complete list of the installed packages and their installation options. Ignored updates and skipped versions will also be saved.": "A cópia de segurança incluirá a lista completa dos pacotes instalados e as suas opções de instalação. Atualizações ignoradas e versões ignoradas também serão guardadas.", + "The backup will NOT include any binary file nor any program's saved data.": "A cópia de segurança NÃO incluirá nenhum ficheiro binário nem dados guardados de nenhum programa.", + "The size of the backup is estimated to be less than 1MB.": "O tamanho da cópia de segurança é estimado em menos de 1 MB.", + "The backup will be performed after login.": "A cópia de segurança será realizada após o login.", + "{pcName} installed packages": "{pcName} pacotes instaldos", + "Current status: Not logged in": "Altual estado: Sem sessão iniciada", + "You are logged in as {0} (@{1})": "Tem sessão iniciada como {0} (@{1})", + "Nice! Backups will be uploaded to a private gist on your account": "Boa! Cópias de segurança vai ser carregada para um gist privado na tua conta", + "Select backup": "Selecionar cópia de segurança", + "Settings imported from {0}": "Definições importadas de {0}", + "UniGetUI Settings": "Definições do UniGetUI", + "Settings exported to {0}": "Definições exportadas para {0}", + "UniGetUI settings were reset": "As definições do UniGetUI foram repostas", + "Allow pre-release versions": "Permitir versões pré-lançamento", + "Apply": "Aplicar", + "For security reasons, custom command-line arguments are disabled by default. Go to UniGetUI security settings to change this.": "Por razões de segurança, os argumentos personalizados da linha de comandos estão desativados por defeito. Aceda às definições de segurança do UniGetUI para alterar isto.", + "Go to UniGetUI security settings": "Vai ás definições de segurança do UniGet UI", + "The following options will be applied by default each time a {0} package is installed, upgraded or uninstalled.": "As seguintes opções vão ser aplicadas por padrão cada vez um {0} pacote é instalado, atualizado ou desinstalado.", + "Package's default": "Padrão do pacote", + "Install location can't be changed for {0} packages": "A localização da instalação não pode ser alterada para {0} pacotes", + "The local icon cache currently takes {0} MB": "A cache de ícones locais ocupa atualmente {0} MB", + "Username": "Nome de utilizador", + "Password": "Palavra-passe", + "Credentials": "Credenciais", + "It is not guaranteed that the provided credentials will be stored safely": "Não é garantido que as credenciais fornecidas sejam armazenadas em segurança", + "Partially": "Parcialmente", + "Package manager": "Gestor de pacotes", + "Compatible with proxy": "Compatível com proxy", + "Compatible with authentication": "Compatível com autenticação", + "Proxy compatibility table": "Tabela de compatibilidade de proxy", + "{0} settings": "Definições de {0}", + "{0} status": "Status de {0}", + "Default installation options for {0} packages": "Opções de instalação padrão para {0} pacotes", + "Expand version": "Expandir", + "The executable file for {0} was not found": "O ficheiro executável para {0} não foi encontrado", + "{pm} is disabled": "{pm} está desativado", + "Enable it to install packages from {pm}.": "Ative-o para instalar pacotes de {pm}", + "{pm} is enabled and ready to go": "{pm} está ativo e pronto a funcionar", + "{pm} version:": "{pm} versão:", + "{pm} was not found!": "{pm} não foi encontrado!", + "You may need to install {pm} in order to use it with UniGetUI.": "Pode ser necessário instalar {pm} para ser possível usá-lo com o UniGetUI.", + "Scoop Installer - UniGetUI": "Instalador Scoop - UniGetUI", + "Scoop Uninstaller - UniGetUI": "Desinstalador Scoop - UniGetUI", + "Clearing Scoop cache - UniGetUI": "A limpar a cache do Scoop - UniGetUI", + "Restart UniGetUI to fully apply changes": "Reinicie o UniGetUI para aplicar totalmente as alterações", + "Restart UniGetUI": "Reiniciar o UniGetUI", + "Manage {0} sources": "Gerir {0} fontes", + "Add source": "Adicionar fonte", + "Add": "Adicionar", + "Source name": "Nome da fonte", + "Source URL": "URL da fonte", + "Other": "Outro(a)", + "No minimum age": "Sem idade mínima", + "1 day": "1 dia", + "{0} days": "{0} dias", + "Custom...": "Personalizado...", + "{0} minutes": "{0} minutos", + "1 hour": "1 hora", + "{0} hours": "{0} horas", + "1 week": "1 semana", + "Supports release dates": "Suporta datas de lançamento", + "Release date support per package manager": "Suporte de datas de lançamento por gestor de pacotes", + "Search for packages": "Pesquisar pacotes", + "Local": "Local", + "OK": "OK", + "Last checked: {0}": "Última verificação: {0}", + "{0} packages were found, {1} of which match the specified filters.": "{0} pacotes foram encontrados, {1} dos quais correspondem aos filtros especificados", + "{0} selected": "{0} selecionados", + "(Last checked: {0})": "(Verificado em: {0})", + "All packages selected": "Todos os pacotes selecionados", + "Package selection cleared": "Seleção de pacotes limpa", + "{0}: {1}": "{0}: {1}", + "More info": "Mais informações", + "GitHub account": "Conta GitHub", + "Log in with GitHub to enable cloud package backup.": "Inicia sessão com o GitHub para ativar cópias de segurança de pacotes na nuvem.", + "More details": "Mais detalhes", + "Log in": "Iniciar sessão", + "If you have cloud backup enabled, it will be saved as a GitHub Gist on this account": "Se tens a cópia de segurança na nuvem habilitada, vai ser guardada como um GitHub Gist nesta conta", + "Log out": "Terminar sessão", + "About UniGetUI": "Sobre o UniGetUI", + "About": "Sobre", + "Third-party licenses": "Licenças de terceiros", + "Contributors": "Contribuidores", + "Translators": "Tradutores", + "Bundle security report": "Relatório de segurança do conjunto", + "The bundle contained restricted content": "O conjunto continha conteúdo restrito", + "UniGetUI – Crash Report": "UniGetUI – Relatório de Erro", + "UniGetUI has crashed": "O UniGetUI parou inesperadamente", + "Help us fix this by sending a crash report to Devolutions. All fields below are optional.": "Ajude-nos a corrigir isto enviando um relatório de erro para a Devolutions. Todos os campos abaixo são opcionais.", + "Email (optional)": "E-mail (opcional)", + "your@email.com": "oseu@email.com", + "Additional details (optional)": "Detalhes adicionais (opcional)", + "Describe what you were doing when the crash occurred…": "Descreva o que estava a fazer quando o erro ocorreu…", + "Crash report": "Relatório de erro", + "Don't Send": "Não enviar", + "Send Report": "Enviar relatório", + "Sending…": "A enviar…", + "Unsaved changes": "Alterações não guardadas", + "You have unsaved changes in the current bundle. Do you want to discard them?": "Tem alterações não guardadas no conjunto atual. Pretende descartá-las?", + "Discard changes": "Descartar alterações", + "Integrity violation": "Violação de integridade", + "UniGetUI or some of its components are missing or corrupt. It is strongly recommended to reinstall UniGetUI to adress the situation.": "O UniGetUI ou alguns dos seus componentes estão em falta ou corrompidos. É vivamente recomendado reinstalar o UniGetUI para resolver a situação.", + "• Refer to the UniGetUI Logs to get more details regarding the affected file(s)": "• Consulte os registos do UniGetUI para obter mais detalhes sobre o(s) ficheiro(s) afetado(s)", + "• Integrity checks can be disabled from the Experimental Settings": "• Verificações de integridade podem ser desativadas nas Definições Exprimentais", + "Manage shortcuts": "Gerir atalhos", + "UniGetUI has detected the following desktop shortcuts which can be removed automatically on future upgrades": "O UniGetUI detetou os seguintes atalhos na área de trabalho que podem ser removidos automaticamente em futuras atualizações", + "Do you really want to reset this list? This action cannot be reverted.": "Tem a certeza que deseja repor esta lista? Esta ação não pode ser revertida.", + "Desktop shortcuts list": "Lista de atalhos do ambiente de trabalho", + "Open in explorer": "Abrir no Explorador", + "Remove from list": "Remover da lista", + "When new shortcuts are detected, delete them automatically instead of showing this dialog.": "Quando novos atalhos são detetados, apagá-los automaticamente em vez de mostrar este diálogo.", + "Not right now": "Agora não", + "Missing dependency": "Dependência em falta", + "UniGetUI requires {0} to operate, but it was not found on your system.": "O UniGetUI requer {0} para operar, mas não foi encontrado no seu sistema.", + "Click on Install to begin the installation process. If you skip the installation, UniGetUI may not work as expected.": "Clique em Instalar para iniciar o processo de instalação. Se saltar a instalação, o UniGetUI poderá não funcionar como esperado.", + "Alternatively, you can also install {0} by running the following command in a Windows PowerShell prompt:": "Em alternativa, também pode instalar {0} ao executar o seguinte comando numa janela do Windows PowerShell:", + "Install {0}": "Instalar {0}", + "Do not show this dialog again for {0}": "Não mostrar esta caixa de diálogo novamente para {0}", + "Please wait while {0} is being installed. A black window may show up. Please wait until it closes.": "Por favor aguarde enquanto {0} está a ser instalado. Pode aparecer uma janela preta (ou azul). Por favor aguarde até que esta feche.", + "{0} has been installed successfully.": "{0} foi instalado com sucesso.", + "Please click on \"Continue\" to continue": "Por favor clique em \"Continuar\" para continuar", + "Continue": "Continuar", + "{0} has been installed successfully. It is recommended to restart UniGetUI to finish the installation": "{0} foi instalado com sucesso. É recomendável reiniciar o UniGetUI para terminar a instalação", + "Restart later": "Reiniciar mais tarde", + "An error occurred:": "Ocorreu um erro:", + "Please see the Command-line Output or refer to the Operation History for further information about the issue.": "Por fovar, verifique o output da linha de comando ou o Histórico de Operações para obter mais informações sobre o problema.", + "Retry as administrator": "Voltar a tentar como administrador", + "Retry interactively": "Voltar a tentar de forma interativa", + "Retry skipping integrity checks": "Voltar a tentar, saltando as verificações de integridade", + "Installation options": "Opções de instalação", + "Save": "Guardar", + "UniGetUI collects anonymous usage data with the sole purpose of understanding and improving the user experience.": "O UniGetUI coleta dados de utilização anónimos com o único propósito de compreender e melhor a experiência do utilizador.", + "More details about the shared data and how it will be processed": "Mais detalhes acerca dos dados partilhados e de como serão processados", + "Do you accept that UniGetUI collects and sends anonymous usage statistics, with the sole purpose of understanding and improving the user experience?": "Aceita que o UniGetUI recolha e envie estatísticas de uso anónimas, com o único propósito de entender e melhorar a experiência do utilizador?", + "Decline": "Rejeitar", + "No personal information is collected nor sent, and the collected data is anonimized, so it can't be back-tracked to you.": "Nenhuma informação pessoal é coletada nem enviada e, os dados coletados são anonimizados, de modo a que não possam ser rastreados até si.", + "Navigation panel": "Painel de navegação", + "Operations": "Operações", + "Toggle operations panel": "Mostrar/ocultar painel de operações", + "Bulk operations": "Operações em lote", + "Retry failed": "Tentar novamente as falhadas", + "Clear successful": "Limpar bem-sucedidas", + "Clear finished": "Limpar concluídas", + "Cancel all": "Cancelar tudo", + "More": "Mais", + "Toggle navigation panel": "Alternar painel de navegação", + "Minimize": "Minimizar", + "Maximize": "Maximizar", + "UniGetUI by Devolutions": "UniGetUI pela Devolutions", + "UniGetUI is an application that makes managing your software easier, by providing an all-in-one graphical interface for your command-line package managers.": "O UniGetUI é uma aplicação que facilita a gestão do seu software, fornecendo uma interface gráfica completa para os seus gestores de pacotes de linha de comandos.", + "Useful links": "Links úteis", + "UniGetUI Homepage": "Página inicial do UniGetUI", + "Report an issue or submit a feature request": "Reportar um problema ou submeter um pedido de um recurso", + "UniGetUI Repository": "Repositório do UniGetUI", + "View GitHub Profile": "Ver perfil GitHub", + "UniGetUI License": "Licença UniGetUI", + "Using UniGetUI implies the acceptation of the MIT License": "A utilização do UniGetUI implica a aceitação da Licença MIT", + "Become a translator": "Torne-se num tradutor", + "Go back": "Voltar", + "Go forward": "Avançar", + "Go to home page": "Ir para a página inicial", + "Reload page": "Recarregar página", + "View page on browser": "Ver página no Browser", + "The built-in browser is not supported on Linux yet.": "O navegador incorporado ainda não é suportado no Linux.", + "Open in browser": "Abrir no navegador", + "Copy to clipboard": "Copiar para área de transferência", + "Export to a file": "Exportar para um ficheiro", + "Log level:": "Nível de registo:", + "Reload log": "Recarregar log", + "Export log": "Exportar registo", + "Text": "Texto", + "Change how operations request administrator rights": "Mudar como as operações pedem direitos de administrador", + "Restrictions on package operations": "Restrições nas operações de pacotes", + "Restrictions on package managers": "Restrições nos gestores de pacotes", + "Restrictions when importing package bundles": "Restrições quando estiveres a importar bundles dos pacotes", + "Ask for administrator privileges once for each batch of operations": "Pedir direitos de administrador uma vez para cada conjunto de operações", + "Ask only once for administrator privileges": "Pedir direitos de administrador apenas uma vez", + "Prohibit any kind of Elevation via UniGetUI Elevator or GSudo": "Proibir qualquer tipo de Elevação via UniGetUI Elevator ou GSudo", + "This option WILL cause issues. Any operation incapable of elevating itself WILL FAIL. Install/update/uninstall as administrator will NOT WORK.": "Esta opção VAI causar erros. Qualquer operação impossível de elevar-se VAI FALHAR. Instalar/atualizar/desinstalar como administrador NÃO VAI RESULTAR", + "Allow custom command-line arguments": "Permitir argumentos personalizados na linha de comandos", + "Custom command-line arguments can change the way in which programs are installed, upgraded or uninstalled, in a way UniGetUI cannot control. Using custom command-lines can break packages. Proceed with caution.": "Os argumentos personalizados da linha de comandos podem alterar a forma como os programas são instalados, atualizados ou desinstalados, de uma forma que o UniGetUI não consegue controlar. A utilização de linhas de comandos personalizadas pode danificar pacotes. Prossiga com cautela.", + "Ignore custom pre-install and post-install commands when importing packages from a bundle": "Permitir comandos personalizados de pre-instalação e pre-desinstalação serem executados", + "Pre and post install commands will be run before and after a package gets installed, upgraded or uninstalled. Be aware that they may break things unless used carefully": "Os comandos de pré-instalação e pós-instalação serão executados antes e depois de um pacote ser instalado, atualizado ou desinstalado. Tem atenção que estes comandos podem causar problemas caso não sejam utilizados com o devido cuidado.", + "Allow changing the paths for package manager executables": "Permitir mudar os caminhos de executáveis dos gerenciadores de pacotes", + "Turning this on enables changing the executable file used to interact with package managers. While this allows finer-grained customization of your install processes, it may also be dangerous": "Ativar isto permite alterar o ficheiro executável usado para interagir com os gestores de pacotes. Embora dê mais controlo sobre o processo de instalação, também pode ser perigoso.", + "Allow importing custom command-line arguments when importing packages from a bundle": "Permitir importar argumentos personalizados da linha de comandos quando estiveres a importar pacotes de um bundle", + "Malformed command-line arguments can break packages, or even allow a malicious actor to gain privileged execution. Therefore, importing custom command-line arguments is disabled by default": "Argumentos de linha de comandos malformados podem danificar pacotes ou até permitir que um agente malicioso obtenha execução privilegiada. Por isso, a importação de argumentos personalizados de linha de comandos está desativada por defeito.", + "Allow importing custom pre-install and post-install commands when importing packages from a bundle": "Permitir importar comandos pré e pós-instalação personalizados ao importar pacotes de um conjunto", + "Pre and post install commands can do very nasty things to your device, if designed to do so. It can be very dangerous to import the commands from a bundle, unless you trust the source of that package bundle": "Os comandos de pré e pós-instalação podem fazer coisas muito perigosas ao seu dispositivo, se tiverem sido concebidos para isso. Pode ser muito perigoso importar os comandos de um conjunto de pacotes, a menos que confie na origem desse conjunto.", + "Administrator rights and other dangerous settings": "Direitos de administrador e outras definições perigosas", + "Package backup": "Cópia de segurança dos pacotes", + "Cloud package backup": "Cópia de segurança do pacote na nuvem", + "Local package backup": "Cópia de segurança de pacotes local", + "Local backup advanced options": "Opções avançadas da cópia de segurança local", + "Log in with GitHub": "Iniciar sessão com o GitHub", + "Log out from GitHub": "Terminar sessão do GitHub", + "Periodically perform a cloud backup of the installed packages": "Fazer periodicamente uma cópia de segurança na nuvem dos pacotes instalados", + "Cloud backup uses a private GitHub Gist to store a list of installed packages": "Cópias de segurança na nuvem usam um GitHub Gist privado para guardar uma lista de pacotes instalados", + "Perform a cloud backup now": "Fazer uma cópia de segurança na nuvem agora", + "Backup": "Cópia de segurança", + "Restore a backup from the cloud": "Restaurar uma cópia de segurança da nuvem", + "Begin the process to select a cloud backup and review which packages to restore": "Inicie o processo para selecionar uma cópia de segurança na nuvem e reveja os pacotes a restaurar", + "Periodically perform a local backup of the installed packages": "Fazer periodicamente uma cópia de segurança local dos pacotes instalados", + "Perform a local backup now": "Fazer uma cópia de segurança local agora", + "Change backup output directory": "Alterar diretório do ficheiro de cópia de segurança", + "Set a custom backup file name": "Definir nome personalizado do ficheiro de cópia de segurança", + "Leave empty for default": "Deixar vazio para padrão", + "Add a timestamp to the backup file names": "Adicionar data e hora aos nomes dos ficheiros de cópia de segurança", + "Backup and Restore": "Cópia de segurança e restauro", + "Enable background api (UniGetUI Widgets and Sharing, port 7058)": "Ativar api em segundo plano (UniGetUI Widgets and Sharing, porta 7058)", + "Wait for the device to be connected to the internet before attempting to do tasks that require internet connectivity.": "Aguardar que o dispositivo esteja ligado à internet antes de tentar executar tarefas que requerem conexão à internet.", + "Disable the 1-minute timeout for package-related operations": "Desativar o tempo limite de 1 minuto para operações relacionadas com pacotes", + "Use installed GSudo instead of UniGetUI Elevator": "Usar GSudo instalado em vez do UniGetUI Elevator", + "Use a custom icon and screenshot database URL": "Utilizar uma base de dados de ícones e capturas de ecrã personalizada", + "Enable background CPU Usage optimizations (see Pull Request #3278)": "Ativar as otimizações de utilização de CPU em segundo plano (ver o Pull Request #3278)", + "Perform integrity checks at startup": "Fazer verificações de integridade ao iniciar", + "When batch installing packages from a bundle, install also packages that are already installed": "Ao instalar pacotes em lote a partir de um conjunto, instalar também pacotes que já estão instalados", + "Experimental settings and developer options": "Definições experimentais e opções do programador ", + "Show UniGetUI's version and build number on the titlebar.": "Mostrar a versão do UniGetUI na barra de título", + "Language": "Idioma", + "UniGetUI updater": "Atualizador do UniGetUI", + "Telemetry": "Telemetria", + "Manage UniGetUI settings": "Gerir definições do UniGetUI", + "Related settings": "Definições relacionadas", + "Update UniGetUI automatically": "Atualizar o UniGetUI automaticamente", + "Check for updates": "Verificar atualizações", + "Install prerelease versions of UniGetUI": "Instalar versões beta do UniGetUI", + "Manage telemetry settings": "Gerir definições de telemetria", + "Manage": "Gerir", + "Import settings from a local file": "Importar definições de um ficheiro local", + "Import": "Importar", + "Export settings to a local file": "Exportar definições para um ficheiro local", + "Export": "Exportar", + "Reset UniGetUI": "Repôr UniGetUI", + "User interface preferences": "Preferências da interface do utilizador", + "Application theme, startup page, package icons, clear successful installs automatically": "Tema da aplicação, página de arranque, ícones de pacotes, limpar instalações bem-sucedidas automaticamente", + "General preferences": "Preferências gerais", + "UniGetUI display language:": "Idioma de exibição do UniGetUI:", + "System language": "Idioma do sistema", + "Is your language missing or incomplete?": "O seu idioma está em falta ou incompleto?", + "Appearance": "Aparência", + "UniGetUI on the background and system tray": "Manter o UniGetUI no fundo e na bandeja do sistema", + "Package lists": "Listas de pacotes", + "Use classic mode": "Utilizar modo clássico", + "Restart UniGetUI to apply this change": "Reinicie o UniGetUI para aplicar esta alteração", + "The classic UI is disabled for beta testers": "A interface clássica está desativada para os testadores beta", + "Close UniGetUI to the system tray": "Fechar o UniGetUI para a bandeja do sistema", + "Manage UniGetUI autostart behaviour": "Gerir o comportamento de arranque automático do UniGetUI", + "Show package icons on package lists": "Mostrar ícones de pacotes em listas de pacotes", + "Clear cache": "Limpar cache", + "Select upgradable packages by default": "Selecione os pacotes atualizáveis por defeito", + "Light": "Claro", + "Dark": "Escuro", + "Follow system color scheme": "Padrão do sistema", + "Application theme:": "Tema da aplicação:", + "UniGetUI startup page:": "Página inicial do UniGetUI:", + "Proxy settings": "Definições de proxy", + "Other settings": "Outras definições", + "Connect the internet using a custom proxy": "Ligar à internet usando um proxy personalizado", + "Please note that not all package managers may fully support this feature": "Por favor tenha em conta que nem todos os gestores de pacotes conseguem suportar totalmente esta funcionalidade ", + "Proxy URL": "URL do proxy", + "Enter proxy URL here": "Introduza o URL do proxy aqui", + "Authenticate to the proxy with a user and a password": "Autenticar no proxy com um utilizador e uma palavra-passe", + "Internet and proxy settings": "Definições de internet e proxy", + "Package manager preferences": "Preferências do gestor de pacotes", + "Ready": "Pronto.", + "Not found": "Não encontrado", + "Notification preferences": "Preferências de notificações", + "Notification types": "Tipos de notificação", + "The system tray icon must be enabled in order for notifications to work": "O ícone da bandeja do sistema deve estar ativo para que as notificações funcionem", + "Enable UniGetUI notifications": "Ativar notificações do UniGetUI", + "Show a notification when there are available updates": "Mostrar uma notificação quando houver atualizações disponíveis", + "Show a silent notification when an operation is running": "Mostrar uma notificação silenciosa quando uma operação está a decorrer", + "Show a notification when an operation fails": "Mostrar uma notificação quando uma operação falha", + "Show a notification when an operation finishes successfully": "Mostrar uma notificação quando uma operação é completada com sucesso", + "Concurrency and execution": "Simultaneidade e execução", + "Automatic desktop shortcut remover": "Remoção automática de atalhos do ambiente de trabalho", + "Choose how many operations should be performed in parallel": "Escolha quantas operações devem ser executadas em paralelo", + "Clear successful operations from the operation list after a 5 second delay": "Limpar as operações bem-sucedidas da lista de operações após 5 segundos", + "Download operations are not affected by this setting": "Operações de descarga não são afetadas por esta definição", + "You may lose unsaved data": "Poderá perder dados não guardados", + "Ask to delete desktop shortcuts created during an install or upgrade.": "Pedir para eliminar atalhos do ambiente de trabalho criados durante uma instalação ou atualização.", + "Package update preferences": "Preferências da atualização de pacotes", + "Update check frequency, automatically install updates, etc.": "Frequência de busca de atualizações, instalar atualizações automaticamente, etc.", + "Reduce UAC prompts, elevate installations by default, unlock certain dangerous features, etc.": "Reduzir os avisos do UAC, elevar as instalações por padrão, desbloqueia certas funcionalidades perigosas, etc.", + "Package operation preferences": "Preferências das operações de pacotes", + "Enable {pm}": "Ativar o {pm}", + "Not finding the file you are looking for? Make sure it has been added to path.": "Não estás a encontrar o ficheiro que estás á procura? Vê se ele foi adicionado ao caminho.", + "Select the executable to be used. The following list shows the executables found by UniGetUI": "Seleciona o executável que vai ser executado. A lista seguinte mostra os executáveis encontrados pelo UniGetUI", + "For security reasons, changing the executable file is disabled by default": "Por razões de segurança, mudar o ficheiro executável está desabilitado por padrão", + "Change this": "Alterar isto", + "Copy path": "Copiar caminho", + "Current executable file:": "Ficheiro executável atual:", + "Ignore packages from {pm} when showing a notification about updates": "Ignorar pacotes de {pm} ao mostrar uma notificação sobre atualizações", + "Update security": "Segurança das atualizações", + "Use global setting": "Usar definição global", + "Minimum age for updates": "Idade mínima das atualizações", + "e.g. 10": "p. ex., 10", + "Custom minimum age (days)": "Idade mínima personalizada (dias)", + "{pm} does not provide release dates for its packages, so this setting will have no effect": "{pm} não fornece datas de lançamento para os seus pacotes, pelo que esta definição não terá qualquer efeito", + "{pm} only provides release dates for some of its packages, so this setting will only apply to those packages": "O {pm} só fornece datas de lançamento para alguns dos seus pacotes, pelo que esta definição só será aplicada a esses pacotes", + "Override the global minimum update age for this package manager": "Substituir a idade mínima global das atualizações para este gestor de pacotes", + "View {0} logs": "Ver {0} registos", + "If Python cannot be found or is not listing packages but is installed on the system, ": "Se o Python não puder ser encontrado ou não estiver a listar pacotes, mas estiver instalado no sistema, ", + "Advanced options": "Opções avançadas", + "WinGet command-line tool": "Ferramenta de linha de comandos do WinGet", + "Choose which command-line tool UniGetUI uses for WinGet operations when the COM API is not used": "Escolha a ferramenta de linha de comandos que o UniGetUI utiliza para operações WinGet quando a COM API não é utilizada", + "WinGet COM API": "API COM do WinGet", + "Choose whether UniGetUI can use the WinGet COM API before falling back to the command-line tool": "Escolha se o UniGetUI pode utilizar a COM API do WinGet antes de recorrer à ferramenta de linha de comandos", + "Reset WinGet": "Repôr WinGet", + "This may help if no packages are listed": "Isto pode ajudar se nenhum pacote for listado", + "Force install location parameter when updating packages with custom locations": "Forçar o parâmetro de localização de instalação ao atualizar pacotes com localizações personalizadas", + "Install Scoop": "Instalar o Scoop", + "Uninstall Scoop (and its packages)": "Desinstalar o Scoop (e os seus pacotes)", + "Run cleanup and clear cache": "Executar limpeza e limpar cache", + "Run": "Executar", + "Enable Scoop cleanup on launch": "Ativar a limpeza do Scoop ao iniciar", + "Default vcpkg triplet": "Trio vcpkg por defeito", + "Change vcpkg root location": "Alterar a localização da raiz do vcpkg", + "Reset vcpkg root location": "Repor localização raiz do vcpkg", + "Open vcpkg root location": "Abrir localização raiz do vcpkg", + "Language, theme and other miscellaneous preferences": "Idioma, tema e outras preferências", + "Show notifications on different events": "Mostrar notificações sobre eventos diferentes", + "Change how UniGetUI checks and installs available updates for your packages": "Altera a forma como o UniGetUI verifica e instala as atualizações disponíveis para os seus pacotes", + "Automatically save a list of all your installed packages to easily restore them.": "Guardar automaticamente uma lista de todos os pacotes instalados para ser mas fácil reinstalá-los.", + "Enable and disable package managers, change default install options, etc.": "Habilitar e desabilitar gestores de pacotes, mudar opções de instalação pré-definidas, etc. ", + "Internet connection settings": "Definições de ligação à internet", + "Proxy settings, etc.": "Definições de proxy, etc.", + "Beta features and other options that shouldn't be touched": "Recursos beta e outras opções que não devem ser alteradas", + "Reload sources": "Recarregar fontes", + "Delete source": "Eliminar fonte", + "Known sources": "Fontes conhecidas", + "Update checking": "A rever atualizações", + "Automatic updates": "Atualizações automáticas", + "Check for package updates periodically": "Verificar se há atualizações de pacotes periodicamente", + "Check for updates every:": "Procurar atualizações a cada:", + "Install available updates automatically": "Instalar as atualizações disponíveis automaticamente", + "Do not automatically install updates when the network connection is metered": "Não instalar atualizações automaticamente quando a ligação à rede é limitada", + "Do not automatically install updates when the device runs on battery": "Não instalar atualizações automáticas quando o dispositivo estiver a usar bateria", + "Do not automatically install updates when the battery saver is on": "Não instalar atualizações automaticamente quando a poupança de bateria está ativa", + "Only show updates that are at least the specified number of days old": "Mostrar apenas atualizações com pelo menos o número de dias especificado", + "Warn me when the installer URL host changes between the installed version and the new version (WinGet only)": "Avisar-me quando o anfitrião do URL do instalador mudar entre a versão instalada e a nova versão (apenas WinGet)", + "Change how UniGetUI handles install, update and uninstall operations.": "Mudar como o UniGetUI lida com as operações de instalação, atualização e desinstalação.", + "Navigation": "Navegação", + "Check for UniGetUI updates": "Verificar atualizações do UniGetUI", + "Quit UniGetUI": "Sair do UniGetUI", + "Filters": "Filtros", + "Sources": "Fontes", + "Search for packages to start": "Pesquisar por pacotes para iniciar", + "Select all": "Selecionar todos", + "Clear selection": "Limpar seleção ", + "Instant search": "Procura rápida", + "Distinguish between uppercase and lowercase": "Distinguir entre maiúsculas \ne minúsculas", + "Ignore special characters": "Ignorar caracteres especiais", + "Search mode": "Modo de pesquisa", + "Both": "Ambos", + "Exact match": "Correspondência exata", + "Show similar packages": "Mostrar pacotes similares", + "Loading": "A carregar", + "Package": "Pacote", + "More options": "Mais opções", + "Order by:": "Ordenar por:", + "Name": "Nome", + "Id": "ID", + "Ascendant": "Ascendente", + "Descendant": "Descendente", + "View modes": "Modos de visualização", + "Reload": "Recarregar", + "Closed": "Fechado", + "Ascending": "Ascendente", + "Descending": "Descendente", + "{0}: {1}, {2}": "{0}: {1}, {2}", + "Order by": "Ordenar por", + "No results were found matching the input criteria": "Nenhum resultado encontrado correspondente aos critérios de pesquisa", + "No packages were found": "Nenhum pacote encontrado", + "Loading packages": "A carregar pacotes", + "Skip integrity checks": "Ignorar verificações de integridade", + "Download selected installers": "Descarregar instaladores selecionados", + "Install selection": "Instalar seleção", + "Install options": "Opções de instalação", + "Add selection to bundle": "Adicionar a seleção ao conjunto", + "Download installer": "Descarregar instalador", + "Uninstall selection": "Desinstalar seleção", + "Uninstall options": "Opções de desinstalação", + "Ignore selected packages": "Ignorar pacotes selecionados ", + "Open install location": "Abrir local de instalação", + "Reinstall package": "Reinstalando pacote", + "Uninstall package, then reinstall it": "Desinstalar pacote e depois reinstalar", + "Ignore updates for this package": "Ignorar atualizações ", + "WinGet malfunction detected": "Detetado erro no funcionamento do Winget", + "It looks like WinGet is not working properly. Do you want to attempt to repair WinGet?": "Parece que o WinGet não está a funcionar corretamente. Quer tentar reparar o WinGet?", + "Repair WinGet": "Reparar WinGet", + "Updates will no longer be ignored for {0}": "As atualizações deixarão de ser ignoradas para {0}", + "Updates are now ignored for {0}": "As atualizações estão agora a ser ignoradas para {0}", + "Do not ignore updates for this package anymore": "Deixar de ignorar as atualizações deste pacote", + "Add packages or open an existing package bundle": "Adicionar pacotes ou abrir um conjunto de pacotes existente", + "Add packages to start": "Adicionar pacotes para começar", + "The current bundle has no packages. Add some packages to get started": "O atual conjunto não tem pacotes. Adicione alguns pacotes para começar", + "New": "Novo", + "Save as": "Guardar como", + "Create .ps1 script": "Criar script .ps1", + "Remove selection from bundle": "Remover seleção do conjunto", + "Skip hash checks": "Ignorar verificações de hash", + "The package bundle is not valid": "O conjunto de pacotes não é válido", + "The bundle you are trying to load appears to be invalid. Please check the file and try again.": "O pacote que está a tentar carregar parece ser inválido. Verifique o ficheiro e tente novamente.", + "Package bundle": "Conjunto de pacotes", + "Could not create bundle": "Não foi possível criar o conjunto de pacotes", + "The package bundle could not be created due to an error.": "O conjunto de pacotes não pôde ser criado devido a um erro.", + "Install script": "Instalar script", + "PowerShell script": "Script do PowerShell", + "The installation script saved to {0}": "O script da instalação foi guardado em {0}", + "An error occurred": "Ocorreu um erro", + "An error occurred while attempting to create an installation script:": "Ocorreu um erro ao tentar criar um script de instalação:", + "Hooray! No updates were found.": "Viva! Nenhuma atualização encontrada!", + "Uninstall selected packages": "Desinstalar selecionados", + "Update selection": "Atualizar seleção", + "Update options": "Opções de atualização", + "Uninstall package, then update it": "Desinstalar pacote e depois atualizar", + "Uninstall package": "Desinstalar pacote", + "Skip this version": "Ignorar esta versão", + "Pause updates for": "Pausar atualizações por", + "User | Local": "Utilizador | Local", + "Machine | Global": "Máquina | Global", + "The default package manager for Debian/Ubuntu-based Linux distributions.
Contains: Debian/Ubuntu packages": "O gestor de pacotes predefinido para distribuições Linux baseadas em Debian/Ubuntu.
Contém: Pacotes Debian/Ubuntu", + "The Rust package manager.
Contains: Rust libraries and programs written in Rust": "O gestor de pacotes Rust.
Contém: Bibliotecas Rust e programas escritos em Rust", + "The classical package manager for windows. You'll find everything there.
Contains: General Software": "O gestor de pacotes mais conhecido para Windows. Irá encontrar de tudo lá.
Contém: Software Geral", + "The default package manager for RHEL/Fedora-based Linux distributions.
Contains: RPM packages": "O gestor de pacotes predefinido para distribuições Linux baseadas em RHEL/Fedora.
Contém: Pacotes RPM", + "A repository full of tools and executables designed with Microsoft's .NET ecosystem in mind.
Contains: .NET related tools and scripts": "Um repositório cheio de ferramentas projetadas com o ecossistema .NET da Microsoft em mente.
Contém: Ferramentas e scripts relacionado(a)s com o .NET", + "The universal Linux package manager for desktop applications.
Contains: Flatpak applications from configured remotes": "O gestor universal de pacotes Linux para aplicações de ambiente de trabalho.
Contém: aplicações Flatpak de remotos configurados", + "NuPkg (zipped manifest)": "NuPkg (manifesto comprimido)", + "The Missing Package Manager for macOS (or Linux).
Contains: Formulae, Casks": "O gestor de pacotes em falta para macOS (ou Linux).
Contém: Formulae, Casks", + "Node JS's package manager. Full of libraries and other utilities that orbit the javascript world
Contains: Node javascript libraries and other related utilities": "Gestor de pacotes do Node JS. Cheio de bibliotecas e outros utilitários no mundo Javascript.
Contém: Bibliotecas Javascript do Node e outros utilitários relacionados", + "The default package manager for Arch Linux and its derivatives.
Contains: Arch Linux packages": "O gestor de pacotes predefinido para Arch Linux e as suas derivadas.
Contém: Pacotes Arch Linux", + "Python's library manager. Full of python libraries and other python-related utilities
Contains: Python libraries and related utilities": "Gestor de bibliotecas do Python. Cheio de bibliotecas Python e outros utilitários relacionados com o Python.
Contém: Bibliotecas Python e utilitários relacionados", + "PowerShell's package manager. Find libraries and scripts to expand PowerShell capabilities
Contains: Modules, Scripts, Cmdlets": "Gestor de pacotes do PowerShell. Encontrar bibliotecas e scripts para expandir os recursos do PowerShell.
Contém: Módulos, Scripts, Cmdlets", + "extracted": "extraído", + "Scoop package": "Pacote do Scoop", + "Great repository of unknown but useful utilities and other interesting packages.
Contains: Utilities, Command-line programs, General Software (extras bucket required)": "Ótimo repositório de utilitários desconhecidos, mas úteis, e outros pacotes interessantes.
Contém: Utilitários, Programas de linha de comando, Software geral (requer o bucket extras)", + "The universal Linux package manager by Canonical.
Contains: Snap packages from the Snapcraft store": "O gestor de pacotes universal para Linux da Canonical.
Contém: Pacotes Snap da loja Snapcraft", + "library": "biblioteca", + "feature": "funcionalidade", + "A popular C/C++ library manager. Full of C/C++ libraries and other C/C++-related utilities
Contains: C/C++ libraries and related utilities": "Gestor de bibliotecas de C/C++. Cheio de bibliotecas C/C++ e outros utilitários relacionados com C/C++.
Contém: bibliotecas C/C++ e utilitários relacionados", + "option": "opção", + "This package cannot be installed from an elevated context.": "Este pacote não pode ser instalado a partir de um comando elevado.", + "Please run UniGetUI as a regular user and try again.": "Execute o UniGetUI como um utilizador padrão e tente novamente.", + "Please check the installation options for this package and try again": "Verifique as opções de instalação para este pacote e tente novamente", + "Microsoft's official package manager. Full of well-known and verified packages
Contains: General Software, Microsoft Store apps": "Gestor de pacotes oficial da Microsoft. Cheio de pacotes conhecidos e verificados.
Contém: Software geral, aplicações da Microsoft Store", + "Local PC": "Computador local", + "Android Subsystem": "Subsistema Android", + "Operation on queue (position {0})...": "Operação em fila de espera (posição {0})", + "Click here for more details": "Clique aqui para mais detalhes", + "Operation canceled by user": "Operação cancelada pelo utilizador", + "Running PreOperation ({0}/{1})...": "A executar PreOperation ({0}/{1})...", + "PreOperation {0} out of {1} failed, and was tagged as necessary. Aborting...": "A PreOperation {0} de {1} falhou e foi marcada como necessária. A abortar...", + "PreOperation {0} out of {1} finished with result {2}": "A PreOperation {0} de {1} terminou com o resultado {2}", + "Starting operation...": "A iniciar a operação...", + "Running PostOperation ({0}/{1})...": "A executar PostOperation ({0}/{1})...", + "PostOperation {0} out of {1} failed, and was tagged as necessary. Aborting...": "A PostOperation {0} de {1} falhou e foi marcada como necessária. A abortar...", + "PostOperation {0} out of {1} finished with result {2}": "A PostOperation {0} de {1} terminou com o resultado {2}", + "{package} installer download": "Descarregar instalador do {package}", + "{0} installer is being downloaded": "O instalador {0} está a ser descarregado", + "Download succeeded": "Descarga bem sucedida", + "{package} installer was downloaded successfully": "O instalador do {package} foi descarregado com sucesso", + "Download failed": "A descarga falhou", + "{package} installer could not be downloaded": "Não foi possível descarregar o instalador do {package}", + "{package} Installation": "{package} Installação", + "{0} is being installed": "{0} está a ser instalado", + "Installation succeeded": "Instalação bem sucedida", + "{package} was installed successfully": "{package} foi instalado com sucesso", + "Installation failed": "Instalação falhada", + "{package} could not be installed": "{package} não pôde ser instalado.", + "{package} Update": "{package} Atualizar", + "Update succeeded": "Atualização bem-sucedida", + "{package} was updated successfully": "{package} foi atualizado com sucesso", + "Update failed": "Atualização falhou", + "{package} could not be updated": "{package} não pôde ser atualizado.", + "{package} Uninstall": "{package} Desinstalar", + "{0} is being uninstalled": "{0} está a ser desinstalado", + "Uninstall succeeded": "Desinstalação bem-sucedida", + "{package} was uninstalled successfully": "{package} foi desinstalado com sucesso", + "Uninstall failed": "Desinstalação falhou", + "{package} could not be uninstalled": "{package} não pôde ser desinstalado.", + "Adding source {source}": "Adicionando fonte {source}", + "Adding source {source} to {manager}": "Adicionar fonte {source} a {manager}", + "Source added successfully": "Fonte adicionada com sucesso", + "The source {source} was added to {manager} successfully": "A fonte {source} foi adicionada a {manager} com sucesso", + "Could not add source": "Não foi possível adicionar a fonte", + "Could not add source {source} to {manager}": "Não foi possível adicionar a fonte {source} a {manager}", + "Removing source {source}": "A remover a fonte {source}", + "Removing source {source} from {manager}": "Remover fonte {source} de {manager}", + "Source removed successfully": "Fonte removida com sucesso", + "The source {source} was removed from {manager} successfully": "A fonte {source} foi removida de {manager} com sucesso", + "Could not remove source": "Não foi possível remover a fonte", + "Could not remove source {source} from {manager}": "Não foi possível remover a fonte {source} do {manager}", + "The package manager \"{0}\" was not found": "O gestor de pacotes \"{0}\" não foi encontrado", + "The package manager \"{0}\" is disabled": "O gestor de pacotes \"{0}\" está desativado", + "There is an error with the configuration of the package manager \"{0}\"": "Existe um erro na configuração do gestor de pacotes \"{0}\"", + "The package \"{0}\" was not found on the package manager \"{1}\"": "O pacote \"{0}\" não foi encontrado no gestor de pacotes \"{1}\"", + "{0} is disabled": "O {0} está desativado", + "{0} weeks": "{0} semanas", + "1 month": "1 mês", + "{0} months": "{0} meses", + "Something went wrong": "Alguma coisa correu mal", + "An interal error occurred. Please view the log for further details.": "Ocorreu um erro interno. Por favor veja os registos para mais detalhes.", + "No applicable installer was found for the package {0}": "Nenhum instalador aplicável foi encontrado para o pacote {0}", + "Integrity checks will not be performed during this operation": "Verificações de integridade não serão realizadas durante esta operação", + "This is not recommended.": "Isto não é recomendado.", + "Run now": "Executar agora", + "Run next": "Executar a seguir", + "Run last": "Executar no fim", + "Show in explorer": "Mostrar no explorador", + "Checked": "Marcado", + "Unchecked": "Desmarcado", + "This package is already installed": "Este pacote já está instalado", + "This package can be upgraded to version {0}": "Este pacote pode ser atualizado para a versão {0}", + "Updates for this package are ignored": "As atualizações para este pacote estão a ser ignoradas", + "This package is being processed": "Este pacote está a ser processado", + "This package is not available": "Este pacote não está disponível", + "Select the source you want to add:": "Selecionar a fonte que deseja adicionar:", + "Source name:": "Nome da fonte", + "Source URL:": "URL da fonte:", + "An error occurred when adding the source: ": "Ocorreu um erro ao adicionar a fonte: ", + "Package management made easy": "Gestão de pacotes de forma fácil", + "version {0}": "versão {0}", + "[RAN AS ADMINISTRATOR]": "EXECUTADO COMO ADMINISTRADOR", + "Portable mode": "Modo portátil", + "DEBUG BUILD": "COMPILAÇÃO DE DEPURAÇÃO", + "Here you can change UniGetUI's behaviour regarding the following shortcuts. Checking a shortcut will make UniGetUI delete it if if gets created on a future upgrade. Unchecking it will keep the shortcut intact": "Aqui pode alterar o comportamento do UniGetUI em relação aos seguintes atalhos. Marcar um atalho fará com que o UniGetUI o apague se for criado numa atualização futura. Desmarcá-lo manterá o atalho intacto", + "Manual scan": "Pesquisa manual", + "Existing shortcuts on your desktop will be scanned, and you will need to pick which ones to keep and which ones to remove.": "Atalhos existentes na área de trabalho serão analizados e, terá de escolher quais deseja manter e quais deseja remover.", + "Delete?": "Apagar?", + "I understand": "Entendi", + "Chocolatey setup changed": "Configuração do Chocolatey alterada", + "UniGetUI no longer includes its own private Chocolatey installation. A legacy UniGetUI-managed Chocolatey installation was detected for this user profile, but system Chocolatey was not found. Chocolatey will stay unavailable in UniGetUI until Chocolatey is installed on the system and UniGetUI is restarted. Applications previously installed through UniGetUI's bundled Chocolatey may still appear under other sources such as Local PC or WinGet.": "O UniGetUI já não inclui a sua própria instalação privada do Chocolatey. Foi detetada uma instalação legada do Chocolatey gerida pelo UniGetUI para este perfil de utilizador, mas o Chocolatey de sistema não foi encontrado. O Chocolatey permanecerá indisponível no UniGetUI até que o Chocolatey seja instalado no sistema e o UniGetUI seja reiniciado. As aplicações previamente instaladas através do Chocolatey incluído no UniGetUI poderão ainda aparecer noutras fontes como PC Local ou WinGet.", + "NOTE: This troubleshooter can be disabled from UniGetUI Settings, on the WinGet section": "NOTA: Esta resolução de problemas pode ser desativada nas definições do UniGetUI, na secção WinGet", + "Restart": "Reiniciar", + "Are you sure you want to delete all shortcuts?": "Tem a certeza que pretende apagar todos os atalhos?", + "Any new shorcuts created during an install or an update operation will be deleted automatically, instead of showing a confirmation prompt the first time they are detected.": "Quaisquer novos atalhos criados durante uma operação de instalação ou atualização serão apagados automaticamente, em vez de mostrar um pedido de confirmação na primeira vez que são detetados", + "Any shorcuts created or modified outside of UniGetUI will be ignored. You will be able to add them via the {0} button.": "Quaisquer atalhos criados ou modificados fora do UniGetUI serão ignorados. Poderá adicioná-los através do botão {0}", + "Are you really sure you want to enable this feature?": "Tem mesmo a certeza de que pretende ativar esta funcionalidade?", + "No new shortcuts were found during the scan.": "Não foram encontrados novos atalhos durante a pesquisa.", + "How to add packages to a bundle": "Como adicionar pacotes a um conjunto", + "In order to add packages to a bundle, you will need to: ": "Para adicionar pacotes a um conjunto, terá de:", + "1. Navigate to the \"{0}\" or \"{1}\" page.": "1. Navegar para a página \"{0}\" ou \"{1}\".", + "2. Locate the package(s) you want to add to the bundle, and select their leftmost checkbox.": "2. Localize o(s) pacote(s) que deseja adicionar ao conjunto e, selecione a caixa mais à esquerda.", + "3. When the packages you want to add to the bundle are selected, find and click the option \"{0}\" on the toolbar.": "3. Quando os pacotes que deseja adicionar ao conjunto estiverem selecionados, encontre e clique na opção \"{0}\" na barra de tarefas.", + "4. Your packages will have been added to the bundle. You can continue adding packages, or export the bundle.": "4. Os seus pacotes foram adicionados ao conjunto. Pode continuar a adicionar pacotes ou, exportar o conjunto.", + "Which backup do you want to open?": "Que cópia de segurança quer abrir?", + "Select the backup you want to open. Later, you will be able to review which packages you want to install.": "Seleciona a cópia de segurança que queres abrir. Mais tarde, vais poder rever quais os pacotes/programas que queres restaurar.", + "There are ongoing operations. Quitting UniGetUI may cause them to fail. Do you want to continue?": "Existem operações em andamento. Sair do UniGetUI pode fazer com que elas falhem. Quer continuar?", + "UniGetUI or some of its components are missing or corrupt.": "O UniGetUI ou alguns dos seus componentes estão a faltar ou corrompidos.", + "It is strongly recommended to reinstall UniGetUI to adress the situation.": "É muito recomendado que reinstales o UniGetUI para resolver esta situação.", + "Refer to the UniGetUI Logs to get more details regarding the affected file(s)": "Consulte os registos do UniGetUI para obter mais detalhes sobre o(s) ficheiro(s) afetado(s)", + "Integrity checks can be disabled from the Experimental Settings": "Verificações de integridade podem ser desativadas nas Definições Exprimentais", + "Repair UniGetUI": "Reparar o UniGetUI", + "Live output": "Saída ao vivo", + "This package bundle had some settings that are potentially dangerous, and may be ignored by default.": "Este pacote contém algumas definições que são potencialmente perigosas, e podem ser ignoradas por padrão.", + "Entries that show in YELLOW will be IGNORED.": "Entradas a AMARELO serão IGNORADAS.", + "Entries that show in RED will be IMPORTED.": "Entradas que mostrem VERMELHO vão ser IMPORTADAS", + "You can change this behavior on UniGetUI security settings.": "Pode alterar este comportamento nas definições de segurança do UniGetUI.", + "Open UniGetUI security settings": "Abre as definições de segurança do UniGetUi", + "Should you modify the security settings, you will need to open the bundle again for the changes to take effect.": "Se modificares as definições de segurança, vais ter de abrir o pacote de novo para que as alterações tenham efeito.", + "Details of the report:": "Detalhes do relatório:", + "Are you sure you want to create a new package bundle? ": "Tem a certeza de que pretende criar um novo conjunto de pacotes?", + "Any unsaved changes will be lost": "Todas as alterações não guardadas serão perdidas", + "Warning!": "Aviso!", + "For security reasons, custom command-line arguments are disabled by default. Go to UniGetUI security settings to change this. ": "Por razões de segurança, argumentos de linha de comandos personalizados estão desabilitados por padrão. Vai ás definições de segurança do UniGetUI para mudar isso.", + "Change default options": "Alterar opções padrão", + "Ignore future updates for this package": "Ignorar atualizações futuras para este pacote", + "For security reasons, pre-operation and post-operation scripts are disabled by default. Go to UniGetUI security settings to change this. ": "Por motivos de segurança, scripts pré e pós-operação estão desativados por defeito. Vá às definições de segurança do UniGetUI para alterar isto.", + "You can define the commands that will be run before or after this package is installed, updated or uninstalled. They will be run on a command prompt, so CMD scripts will work here.": "Tu consegues definir os comandos que vão ser executados antes e depois que este pacote é instalado, atualizado ou desinstalado. Eles vão ser executados em uma linha de comandos, então scripts de CMD vão funcionar aqui.", + "Change this and unlock": "Alterar isto e desbloquear", + "{0} Install options are currently locked because {0} follows the default install options.": "{0} opções de instalação estão de momento bloqueadas porque {0} respeita as opções de instalação padrão.", + "Unset or unknown": "Não selecionado ou desconhecido", + "This package has no screenshots or is missing the icon? Contrbute to UniGetUI by adding the missing icons and screenshots to our open, public database.": "Este pacote não possui capturas de ecrã ou o ícone está em falta? Contribua para o UniGetUI adicionando os ícones e capturas de ecrã ausentes à nossa base de dados pública e aberta.", + "Become a contributor": "Torne-se num contribuidor", + "Update to {0} available": "Atualização para {0} disponível", + "Reinstall": "Reinstalar", + "Installer not available": "Instalador não disponível", + "Version:": "Versão:", + "UniGetUI Version {0}": "Versão UniGetUI {0}", + "Performing backup, please wait...": "A fazer cópia de segurança, por favor aguarde...", + "An error occurred while logging in: ": "Ocorreu um erro ao iniciar sessão:", + "Fetching available backups...": "A apanhar cópias de segurança disponiveis...", + "Done!": "Feito!", + "The cloud backup has been loaded successfully.": "A cópia de segurança foi carregada com sucesso.", + "An error occurred while loading a backup: ": "Ocorreu um erro ao carregar uma cópia de segurança:", + "Backing up packages to GitHub Gist...": "A fazer cópia de segurança dos pacotes para o GitHub Gist...", + "Backup Successful": "Cópia de segurança bem-sucedida", + "The cloud backup completed successfully.": "A cópia de segurança na nuvem foi completa com sucesso.", + "Could not back up packages to GitHub Gist: ": "Não foi possível fazer cópia de segurança dos pacotes para o GitHub Gist:", + "It is not guaranteed that the provided credentials will be stored safely, so you may as well not use the credentials of your bank account": "Não é garantido que as credenciais providenciadas sejam guardadas de forma segura, será melhor não utilizar as credenciais da sua conta bancária", + "Enable the automatic WinGet troubleshooter": "Ativar a resolução de problemas automática do WinGet", + "Add updates that fail with a 'no applicable update found' to the ignored updates list": "Adicionar atualizações que falham com o erro \"nenhuma atualização encontrada\" à lista de atualizações ignoradas.", + "Invalid selection": "Selecção invalida", + "No package was selected": "Sem pacotes selecionados", + "More than 1 package was selected": "Mais de 1 pacote foi selecionado", + "List": "Lista", + "Grid": "Grelha", + "Icons": "Ícones", + "\"{0}\" is a local package and does not have available details": "\"{0}\" é um pacote local e não tem detalhes disponíveis", + "\"{0}\" is a local package and is not compatible with this feature": "\"{0}\" é um pacote local e não é compatível com esta funcionalidade", + "Add packages to bundle": "Adicionar pacotes ao conjunto", + "Preparing packages, please wait...": "A preparar pacotes, por favor aguarde...", + "Loading packages, please wait...": "A carregar pacotes, por favor aguarde...", + "Saving packages, please wait...": "A salvar pacotes, por favor aguarde...", + "The bundle was created successfully on {0}": "O pacote foi criado com sucesso em {0}", + "User profile": "Perfil de utilizador", + "Error": "Erro", + "Log in failed: ": "Falhar ao iniciar sessão: ", + "Log out failed: ": "Falha ao terminar sessão:", + "Package backup settings": "Definições da cópia de segurança de pacotes", + "Package managers": "Gestores de pacotes", + "Manage UniGetUI autostart behaviour from the Settings app": "Gerir o comportamento de arranque automático do UniGetUI", + "Choose how many operations shoulds be performed in parallel": "Escolha quantas operações devem ser executadas em paralelo", + "Something went wrong while launching the updater.": "Algo correu mal ao iniciar o atualizador.", + "Please try again later": "Por favor tente novamente mais tarde", + "Show the release notes after UniGetUI is updated": "Mostrar as notas de lançamento após a atualização do UniGetUI" +} diff --git a/src/Languages/lang_ro.json b/src/Languages/lang_ro.json new file mode 100644 index 0000000..209dfdf --- /dev/null +++ b/src/Languages/lang_ro.json @@ -0,0 +1,851 @@ +{ + "{0} of {1} operations completed": "{0} din {1} operațiuni finalizate", + "{0} is now {1}": "{0} este acum {1}", + "Enabled": "Activat", + "Disabled": "Dezactivat", + "Privacy": "Confidențialitate", + "Hide my username from the logs": "Ascunde numele meu de utilizator din jurnale", + "Replaces your username with **** in the logs. Restart UniGetUI to also hide it from already-recorded entries.": "Înlocuiește numele tău de utilizator cu **** în jurnale. Repornește UniGetUI pentru a-l ascunde și din înregistrările deja salvate.", + "Your last update attempt did not complete.": "Ultima încercare de actualizare nu s-a finalizat.", + "UniGetUI could not confirm whether the update succeeded. Open the log to see what happened.": "UniGetUI nu a putut confirma dacă actualizarea a reușit. Deschide jurnalul pentru a vedea ce s-a întâmplat.", + "View log": "Vezi jurnalul", + "The installer reported success but did not restart UniGetUI.": "Instalatorul a raportat succes, dar nu a repornit UniGetUI.", + "The installer failed to initialize.": "Instalatorul nu a putut fi inițializat.", + "Setup was canceled before installation began.": "Configurarea a fost anulată înainte de începerea instalării.", + "A fatal error occurred during the preparation phase.": "A apărut o eroare fatală în timpul fazei de pregătire.", + "A fatal error occurred during installation.": "A apărut o eroare fatală în timpul instalării.", + "Installation was canceled while in progress.": "Instalarea a fost anulată în timp ce era în desfășurare.", + "The installer was terminated by another process.": "Instalatorul a fost închis de un alt proces.", + "The preparation phase determined the installation cannot proceed.": "Faza de pregătire a stabilit că instalarea nu poate continua.", + "The installer could not start. UniGetUI may already be running, or you do not have permission to install.": "Instalatorul nu a putut porni. UniGetUI ar putea rula deja sau nu ai permisiunea de a instala.", + "Unexpected installer error.": "Eroare neașteptată a instalatorului.", + "We are checking for updates.": "Verificăm pentru actualizări.", + "Please wait": "Te rog așteaptă", + "Great! You are on the latest version.": "Minunat! Folosești cea mai nouă versiune.", + "There are no new UniGetUI versions to be installed": "Nu există versiuni noi de UniGetUI pentru a fi instalate", + "UniGetUI version {0} is being downloaded.": "UniGetUI versiunea {0} este în curs de descărcare.", + "This may take a minute or two": "Acest lucru poate dura 1-2 minut(e)", + "The installer authenticity could not be verified.": "Autenticitatea instalatorului nu a putut fi verificată.", + "The update process has been aborted.": "Procesul de actualizare a fost anulat.", + "Auto-update is not yet available on this platform.": "Actualizarea automată nu este încă disponibilă pe această platformă.", + "Please update UniGetUI manually.": "Te rog actualizează UniGetUI manual.", + "An error occurred when checking for updates: ": "A apărut o eroare la verificarea de actualizări:", + "The updater could not be launched.": "Actualizatorul nu a putut fi lansat.", + "The operating system did not start the installer process.": "Sistemul de operare nu a pornit procesul instalatorului.", + "UniGetUI is being updated...": "UniGetUI este în curs de actualizare...", + "Update installed.": "Actualizare instalată.", + "UniGetUI was updated successfully, but this running copy was not replaced. This usually means you are running a development build. Close this copy and start the newly-installed version to finish.": "UniGetUI a fost actualizat cu succes, dar această copie aflată în execuție nu a fost înlocuită. Acest lucru înseamnă de obicei că rulezi un build de dezvoltare. Închide această copie și pornește versiunea nou instalată pentru a finaliza.", + "The update could not be applied.": "Actualizarea nu a putut fi aplicată.", + "Installer exit code {0}: {1}": "Cod de ieșire instalator {0}: {1}", + "Update cancelled.": "Actualizare anulată.", + "Authentication was cancelled.": "Autentificarea a fost anulată.", + "Installer exit code {0}": "Cod de ieșire instalator {0}", + "Operation in progress": "Operație în curs", + "Please wait...": "Te rog așteaptă...", + "Success!": "Succes!", + "Failed": "Eșuat", + "An error occurred while processing this package": "A apărut o eroare în timpul procesării acestui pachet", + "Installer": "Instalator", + "Executable": "Executabil", + "MSI": "MSI", + "Compressed file": "Fișier comprimat", + "MSIX": "MSIX", + "WinGet was repaired successfully": "WinGet a fost reparat cu succes", + "It is recommended to restart UniGetUI after WinGet has been repaired": "Este recomandat să repornești UniGetUI după ce WinGet a fost reparat", + "WinGet could not be repaired": "WinGet nu a putut fi reparat", + "An unexpected issue occurred while attempting to repair WinGet. Please try again later": "O problemă neașteptată a apărut în încercarea de a repara WinGet. Te rog încearcă mai târziu", + "Log in to enable cloud backup": "Autentifică-te pentru a activa backup în cloud", + "Backup Failed": "Backup-ul a eșuat", + "Downloading backup...": "Se descarcă copia de siguranță...", + "An update was found!": "A fost găsită o actualizare!", + "{0} can be updated to version {1}": "{0} poate fi actualizat la versiunea {1}", + "Updates found!": "Actualizări găsite!", + "{0} packages can be updated": "{0} pachete pot fi actualizate", + "{0} is being updated to version {1}": "{0} este în curs de actualizare la {1}", + "{0} packages are being updated": "{0} pachete sunt în curs de actualizare", + "You have currently version {0} installed": "Versiunea curentă instalată este {0}", + "Desktop shortcut created": "Scurtătură pe spațiul de lucru creată", + "UniGetUI has detected a new desktop shortcut that can be deleted automatically.": "UniGetUI a detectat o nouă scurtătură pe spațiul de lucru care poate fi ștearsă automat.", + "{0} desktop shortcuts created": "{0} scurtături create pe spațiul de lucru", + "UniGetUI has detected {0} new desktop shortcuts that can be deleted automatically.": "UniGetUI a detectat {0} noi scurtături pe spațiul de lucru care pot fi șterse automat.", + "Attention required": "Este necesară atenție", + "Restart required": "Repornire necesară", + "1 update is available": "1 actualizare este disponibilă", + "{0} updates are available": "{0} actualizări sunt disponibile", + "Everything is up to date": "Totul este la zi", + "Discover Packages": "Descoperă pachete", + "Available Updates": "Actualizări disponibile", + "Installed Packages": "Pachete instalate", + "UniGetUI Version {0} by Devolutions": "Versiunea UniGetUI {0} de la Devolutions", + "Show UniGetUI": "Arată UniGetUI", + "Quit": "Ieșire", + "Are you sure?": "Ești sigur?", + "Do you really want to uninstall {0}?": "Chiar dorești să dezinstalezi {0}?", + "Do you really want to uninstall the following {0} packages?": "Sigur dorești să dezinstalezi următoarele {0} pachete?", + "No": "Nu", + "Yes": "Da", + "Partial": "Parțial", + "View on UniGetUI": "Vezi în UniGetUI", + "Update": "Actualizează", + "Open UniGetUI": "Deschide UniGetUI", + "Update all": "Actualizează tot", + "Update now": "Actualizează acum", + "Installer host changed since the installed version.\n": "Gazda instalatorului s-a schimbat față de versiunea instalată.\n", + "This package is on the queue": "Acest pachet este pus în coadă", + "installing": "instalează", + "updating": "se actualizează", + "uninstalling": "se dezinstalează", + "installed": "instalat", + "Retry": "Reîncearcă", + "Install": "Instalează", + "Uninstall": "Dezinstalează", + "Open": "Deschide", + "Operation profile:": "Profil operațiuni:", + "Follow the default options when installing, upgrading or uninstalling this package": "Urmează opțiunile implicite la instalarea, actualizarea sau dezinstalarea acestui pachet.", + "The following settings will be applied each time this package is installed, updated or removed.": "Următoarele setări vor fi aplicate de fiecare dată când acest pachet este instalat, actualizat sau eliminat.", + "Version to install:": "Versiune de instalat:", + "Architecture to install:": "Arhitectura de instalat:", + "Installation scope:": "Domeniu instalare:", + "Install location:": "Locația instalării:", + "Select": "Selectează", + "Reset": "Resetează", + "Custom install arguments:": "Argumente de instalare personalizate:", + "Custom update arguments:": "Argumente de actualizare personalizate:", + "Custom uninstall arguments:": "Argumente de dezinstalare personalizate:", + "Pre-install command:": "Comandă pre-instalare:", + "Post-install command:": "Comandă post-instalare:", + "Abort install if pre-install command fails": "Anulează instalarea dacă comanda pre-instalare eșuează.", + "Pre-update command:": "Comandă pre-actualizare:", + "Post-update command:": "Comandă post-actualizare:", + "Abort update if pre-update command fails": "Anulează actualizarea dacă comanda pre-actualizării eșuează.", + "Pre-uninstall command:": "Comandă pre-dezinstalare:", + "Post-uninstall command:": "Comandă post-dezinstalare:", + "Abort uninstall if pre-uninstall command fails": "Anulează dezinstalarea dacă comanda pre-dezinstalare eșuează.", + "Command-line to run:": "Linia de comandă de rulat:", + "Save and close": "Salvează și închide", + "General": "Generale", + "Architecture & Location": "Arhitectură și locație", + "Command-line": "Linie de comandă", + "Close apps": "Închide aplicațiile", + "Pre/Post install": "Pre/Post instalare", + "Select the processes that should be closed before this package is installed, updated or uninstalled.": "Selectează procesele care ar trebui să fie închise înainte ca acest pachet să fie instalat, actualizat sau dezinstalat.", + "Write here the process names here, separated by commas (,)": "Scrie aici numele proceselor, separate de virgule (,)", + "Try to kill the processes that refuse to close when requested to": "Încearcă să ucizi procesul care refuză a fi închis la cerere.", + "Run as admin": "Rulează ca administrator", + "Interactive installation": "Instalare interactivă", + "Skip hash check": "Omite verificarea sumei de control", + "Uninstall previous versions when updated": "Dezinstalează versiunile anterioare la actualizare", + "Skip minor updates for this package": "Omite actualizări minore pentru acest pachet", + "Automatically update this package": "Actualizează pachetele automat", + "{0} installation options": "Opțiuni instalare {0}", + "Latest": "Ultima", + "PreRelease": "Versiune preliminară", + "Default": "Implicit", + "Manage ignored updates": "Administrează actualizările ignorate", + "The packages listed here won't be taken in account when checking for updates. Double-click them or click the button on their right to stop ignoring their updates.": "Pachetele enumerate aici nu vor fi luate în considerare la verificarea actualizărilor. Fă dublu clic pe ele sau fă clic pe butonul din dreapta lor pentru a nu mai mai ignora actualizările.", + "Reset list": "Resetează lista", + "Do you really want to reset the ignored updates list? This action cannot be reverted": "Chiar dorești să resetezi lista actualizărilor ignorate? Această acțiune nu poate fi anulată", + "No ignored updates": "Nicio actualizare ignorată", + "Package Name": "Nume pachet", + "Package ID": "ID pachet", + "Ignored version": "Versiune ignorată", + "New version": "Versiune nouă", + "Source": "Sursă", + "All versions": "Toate versiunile", + "Unknown": "Necunoscut", + "Up to date": "La zi", + "Package {name} from {manager}": "Pachetul {name} de la {manager}", + "Remove {0} from ignored updates": "Elimină {0} din actualizările ignorate", + "Cancel": "Anulează", + "Administrator privileges": "Privilegii administrator", + "This operation is running with administrator privileges.": "Această operație este rulată cu privilegii de administrator.", + "Interactive operation": "Operație interactivă", + "This operation is running interactively.": "Această operație este rulată interactiv.", + "You will likely need to interact with the installer.": "S-ar putea să trebuiască să interacționezi cu instalatorul.", + "Integrity checks skipped": "Verificările de integritate au fost omise", + "Integrity checks will not be performed during this operation.": "Verificările de integritate nu vor fi efectuate în timpul acestei operații.", + "Proceed at your own risk.": "Continuă pe riscul tău.", + "Close": "Închide", + "Loading...": "Se încarcă...", + "Installer SHA256": "Instalator SHA256", + "Homepage": "Pagina principală", + "Author": "Autor", + "Publisher": "Editor", + "License": "Licență", + "Manifest": "Fișier manifest", + "Installer Type": "Tip Instalator", + "Size": "Dimensiune", + "Installer URL": "Instalator URL", + "Last updated:": "Ultima dată actualizat:", + "Release notes URL": "URL informații versiune", + "Package details": "Detalii pachet", + "Dependencies:": "Dependințe:", + "Release notes": "Informații versiune", + "Screenshots": "Capturi de ecran", + "This package has no screenshots or is missing the icon? Contribute to UniGetUI by adding the missing icons and screenshots to our open, public database.": "Acest pachet nu are capturi de ecran sau îi lipsește pictograma? Contribuie la UniGetUI adăugând pictogramele și capturile de ecran lipsă în baza noastră de date deschisă și publică.", + "Version": "Versiune", + "Install as administrator": "Instalează ca administrator", + "Update to version {0}": "Actualizează la versiunea {0}", + "Installed Version": "Versiune instalată", + "Update as administrator": "Actualizează ca administrator", + "Interactive update": "Actualizare interactivă", + "Uninstall as administrator": "Dezinstalează ca administrator", + "Interactive uninstall": "Dezinstalare interactivă", + "Uninstall and remove data": "Dezinstalează și elimină datele", + "Not available": "Indisponibil", + "Installer SHA512": "Instalator SHA512", + "Unknown size": "Mărime necunoscută", + "No dependencies specified": "Nicio dependință specificată", + "mandatory": "obligatoriu", + "optional": "opțional", + "UniGetUI {0} is ready to be installed.": "UniGetUI {0} este gata pentru a fi instalat.", + "The update process will start after closing UniGetUI": "Procesul de actualizare va porni după închiderea UniGetUI", + "UniGetUI has been ran as administrator, which is not recommended. When running UniGetUI as administrator, EVERY operation launched from UniGetUI will have administrator privileges. You can still use the program, but we highly recommend not running UniGetUI with administrator privileges.": "UniGetUI a fost pornit ca administrator, ceea ce nu este recomandat. Când rulezi UniGetUI ca administrator, FIECARE operație lansată din UniGetUI va avea privilegii de administrator. Poți folosi programul în continuare, dar îți recomandăm insistent să nu rulezi UniGetUI cu privilegii de administrator.", + "Share anonymous usage data": "Partajează date de utilizare anonime", + "UniGetUI collects anonymous usage data in order to improve the user experience.": "UniGetUI colectează date de utilizare anonime pentru a îmbunătăți experiența utilizatorilor.", + "Accept": "Acceptă", + "Software Updates": "Actualizări pachete", + "Package Bundles": "Grupuri aplicații", + "Settings": "Setări", + "Package Managers": "Manageri de pachete", + "UniGetUI Log": "Jurnal UniGetUI", + "Package Manager logs": "Jurnale manager de pachete", + "Operation history": "Istoric operații", + "Help": "Ajutor", + "UniGetUI": "UniGetUI", + "You have installed UniGetUI Version {0}": "Ai instalat UniGetUI versiunea {0}", + "Disclaimer": "Negarea responsabilității", + "UniGetUI is developed by Devolutions and is not affiliated with any of the compatible package managers.": "UniGetUI este dezvoltat de Devolutions și nu este afiliat cu niciunul dintre managerii de pachete compatibili.", + "UniGetUI wouldn't have been possible without the help of the contributors. Thank you all 🥳": "UniGetUI nu ar fi fost posibil fără ajutorul contribuitorilor. Mulțumesc vouă, tuturor 🥳", + "UniGetUI uses the following libraries. Without them, UniGetUI wouldn't have been possible.": "UniGetUI folosește următoarele biblioteci. Fără ele, UniGetUI nu ar fi fost existat.", + "{0} homepage": "Pagina principală a {0}", + "UniGetUI has been translated to more than 40 languages thanks to the volunteer translators. Thank you 🤝": "UniGetUI a fost tradus în mai mult de 40 de limbi mulțumită voluntarilor. Mulțumesc🤝", + "Verbose": "Verbos", + "1 - Errors": "1 - Erori", + "2 - Warnings": "2 - Avertismente", + "3 - Information (less)": "3 - Informații (mai puține)", + "4 - Information (more)": "4 - Informații (mai multe)", + "5 - information (debug)": "5 - Informații (pentru depanare)", + "Warning": "Avertizare", + "The following settings may pose a security risk, hence they are disabled by default.": "Următoarele setări pot reprezenta un risc de securitate, de aceea sunt implicit dezactivate.", + "Enable the settings below if and only if you fully understand what they do, and the implications they may have.": "Activează setările de mai jos numai și numai dacă înțelegi deplin ceea ce fac și implicațiile pe care le pot avea.", + "The settings will list, in their descriptions, the potential security issues they may have.": "Setările vor lista, în descrierile lor, problemele potențiale de securitate pe care le pot introduce.", + "The backup will include the complete list of the installed packages and their installation options. Ignored updates and skipped versions will also be saved.": "Copia de siguranță va include lista completă a pachetelor instalate și opțiunile lor de instalare. Actualizările ignorate și versiunile omise vor fi salvate de asemenea.", + "The backup will NOT include any binary file nor any program's saved data.": "Copia de siguranță NU va conține fișiere binare sau salvări ale datelor programului.", + "The size of the backup is estimated to be less than 1MB.": "Dimensiunea copiei de siguranță este estimată a fi sub 1MB.", + "The backup will be performed after login.": "Copia de siguranță va fi făcută după autentificare.", + "{pcName} installed packages": "Pachete instalate {pcName}", + "Current status: Not logged in": "Stare curentă: Neautentificat", + "You are logged in as {0} (@{1})": "Ești autentificat ca {0} (@{1})", + "Nice! Backups will be uploaded to a private gist on your account": "Fain! Backup-urile se vor încărca automat într-un gist privat în contul tău", + "Select backup": "Alege backup", + "Settings imported from {0}": "Setări importate din {0}", + "UniGetUI Settings": "Setări UniGetUI", + "Settings exported to {0}": "Setări exportate în {0}", + "UniGetUI settings were reset": "Setările UniGetUI au fost resetate", + "Allow pre-release versions": "Permite versiuni beta", + "Apply": "Aplică", + "For security reasons, custom command-line arguments are disabled by default. Go to UniGetUI security settings to change this.": "Din motive de securitate, argumentele personalizate din linia de comandă sunt dezactivate implicit. Mergi la setările de securitate UniGetUI pentru a schimba acest lucru.", + "Go to UniGetUI security settings": "Mergi la setările de securitate UniGetUI", + "The following options will be applied by default each time a {0} package is installed, upgraded or uninstalled.": "Următoarele opțiuni vor fi aplicate implicit de fiecare dată când un pachet {0} este instalat, actualizat sau dezinstalat.", + "Package's default": "Implicitele pachetului", + "Install location can't be changed for {0} packages": "Locația instalării nu poate fi schimbată pentru pachetele {0}", + "The local icon cache currently takes {0} MB": "Cache-ul de pictograme local ocupă {0}MO", + "Username": "Nume utilizator", + "Password": "Parolă", + "Credentials": "Acreditări", + "It is not guaranteed that the provided credentials will be stored safely": "Nu este garantat că acreditările furnizate vor fi stocate în siguranță", + "Partially": "Parțial", + "Package manager": "Manager de pachete", + "Compatible with proxy": "Compatibil cu proxy", + "Compatible with authentication": "Compatibil cu autentificarea", + "Proxy compatibility table": "Tabel compatibilitate proxy", + "{0} settings": "Setări {0}", + "{0} status": "Stare {0}", + "Default installation options for {0} packages": "Opțiuni implicite de instalare pentru pachete {0}", + "Expand version": "Extinde versiunea", + "The executable file for {0} was not found": "Fișierul executabil pentru {0} nu a fost găsit", + "{pm} is disabled": "{pm} este dezactivat", + "Enable it to install packages from {pm}.": "Activează-l pentru a instala pachete de la {pm}.", + "{pm} is enabled and ready to go": "{pm} este activat și gata de lucru", + "{pm} version:": "{pm} versiunea:", + "{pm} was not found!": "{pm} nu a fost găsit!", + "You may need to install {pm} in order to use it with UniGetUI.": "Ar putea fi necesar să instalezi {pm} pentru a-l utiliza cu UniGetUI.", + "Scoop Installer - UniGetUI": "Instalator Scoop - UniGetUI", + "Scoop Uninstaller - UniGetUI": "Dezinstalator Scoop - UniGetUI", + "Clearing Scoop cache - UniGetUI": "Se curăță cache-ul pentru Scoop - UniGetUI", + "Restart UniGetUI to fully apply changes": "Repornește UniGetUI pentru a aplica complet modificările", + "Restart UniGetUI": "Repornește UniGetUI", + "Manage {0} sources": "Administrare surse {0}", + "Add source": "Adaugă sursă", + "Add": "Adaugă", + "Source name": "Nume sursă", + "Source URL": "URL sursă", + "Other": "Altele", + "No minimum age": "Fără vechime minimă", + "1 day": "1 zi", + "{0} days": "{0} zile", + "Custom...": "Personalizat...", + "{0} minutes": "{0} minute", + "1 hour": "o oră", + "{0} hours": "{0} ore", + "1 week": "o săptămână", + "Supports release dates": "Suportă date de lansare", + "Release date support per package manager": "Suport pentru date de lansare per manager de pachete", + "Search for packages": "Caută pachete", + "Local": "La nivel local", + "OK": "Bine", + "Last checked: {0}": "Ultima verificare: {0}", + "{0} packages were found, {1} of which match the specified filters.": "{0} pachete au fost găsite, dintre care {1} se potrivesc cu filtrele specificate.", + "{0} selected": "{0} selectate", + "(Last checked: {0})": "(Ultima verificare: {0})", + "All packages selected": "Toate pachetele selectate", + "Package selection cleared": "Selecția pachetelor anulată", + "{0}: {1}": "{0}: {1}", + "More info": "Mai multe informații", + "GitHub account": "Cont GitHub", + "Log in with GitHub to enable cloud package backup.": "Autentifică-te cu GitHub pentru a activa backup de pachete în cloud.", + "More details": "Mai multe detalii", + "Log in": "Autentifică-te", + "If you have cloud backup enabled, it will be saved as a GitHub Gist on this account": "Dacă ai activat backup în cloud, acesta va fi salvat ca un GitHub Gist în acest cont", + "Log out": "Deconectează-te", + "About UniGetUI": "Despre UniGetUI", + "About": "Despre", + "Third-party licenses": "Licențe terțe", + "Contributors": "Contribuitori", + "Translators": "Traducători", + "Bundle security report": "Raport de securitate grup", + "The bundle contained restricted content": "Pachetul a conținut conținut restricționat", + "UniGetUI – Crash Report": "UniGetUI – Raport de eroare", + "UniGetUI has crashed": "UniGetUI s-a oprit neașteptat", + "Help us fix this by sending a crash report to Devolutions. All fields below are optional.": "Ajută-ne să reparăm aceasta trimițând un raport de eroare către Devolutions. Toate câmpurile de mai jos sunt opționale.", + "Email (optional)": "Email (opțional)", + "your@email.com": "adresa@ta.ro", + "Additional details (optional)": "Detalii suplimentare (opțional)", + "Describe what you were doing when the crash occurred…": "Descrie ce făceai când s-a produs eroarea…", + "Crash report": "Raport de eroare", + "Don't Send": "Nu trimite", + "Send Report": "Trimite raportul", + "Sending…": "Se trimite…", + "Unsaved changes": "Modificări nesalvate", + "You have unsaved changes in the current bundle. Do you want to discard them?": "Ai modificări nesalvate în pachetul curent. Vrei să renunți la ele?", + "Discard changes": "Renunță la modificări", + "Integrity violation": "Încălcare a integrității", + "UniGetUI or some of its components are missing or corrupt. It is strongly recommended to reinstall UniGetUI to adress the situation.": "UniGetUI sau unele dintre componentele sale lipsesc sau sunt corupte. Se recomandă insistent să reinstalezi UniGetUI pentru a remedia situația.", + "• Refer to the UniGetUI Logs to get more details regarding the affected file(s)": "• Fă referire la jurnalele UniGetUI pentru a obține mai multe detalii despre fișierele afectate", + "• Integrity checks can be disabled from the Experimental Settings": "• Verificările de integritate pot fi dezactivate din setările experimentale", + "Manage shortcuts": "Administrează scurtăturile", + "UniGetUI has detected the following desktop shortcuts which can be removed automatically on future upgrades": "UniGetUI a detectat următoarele scurtături pe spațiul de lucru care pot fi șterse automat la actualizările viitoare", + "Do you really want to reset this list? This action cannot be reverted.": "Chiar vrei să resetezi această listă? Această acțiune nu poate fi anulată.", + "Desktop shortcuts list": "Lista scurtăturilor de pe desktop", + "Open in explorer": "Deschide în Explorer", + "Remove from list": "Elimină din listă", + "When new shortcuts are detected, delete them automatically instead of showing this dialog.": "Când noi scurtături sunt detectate, șterge-le automat în loc de a arăta acest dialog.", + "Not right now": "Nu chiar acum", + "Missing dependency": "Dependință lipsă", + "UniGetUI requires {0} to operate, but it was not found on your system.": "UniGetUI necesită {0} pentru a opera, dar nu a fost găsit pe sistemul tău.", + "Click on Install to begin the installation process. If you skip the installation, UniGetUI may not work as expected.": "Clic pe Instalează pentru a începe procesul de instalare. Dacă vei omite instalarea, UniGetUI ar putea să nu funcționeze așa cum te-ai aștepta.", + "Alternatively, you can also install {0} by running the following command in a Windows PowerShell prompt:": "Alternativ, poți de asemenea să instalezi {0} rulând următoarea comandă în Windows PowerShell:", + "Install {0}": "Instalează {0}", + "Do not show this dialog again for {0}": "Nu mai afișa acest dialog pentru {0}", + "Please wait while {0} is being installed. A black window may show up. Please wait until it closes.": "Te rog așteaptă cât timp {0} se instalează. O fereastră neagră ar putea apărea. Așteaptă până când aceasta va dispărea.", + "{0} has been installed successfully.": "{0} a fost instalat cu succes.", + "Please click on \"Continue\" to continue": "Te rog apasă pe „Continuă” pentru a continua", + "Continue": "Continuă", + "{0} has been installed successfully. It is recommended to restart UniGetUI to finish the installation": "{0} a fost instalat cu succes. Este recomandat să repornești UniGetUI pentru a finaliza instalarea", + "Restart later": "Repornește mai târziu", + "An error occurred:": "A apărut o eroare:", + "Please see the Command-line Output or refer to the Operation History for further information about the issue.": "Te rog uită-te în output-ul liniei de comandă sau vezi istoricul operațiilor pentru mai multe informații legate de problemă.", + "Retry as administrator": "Reîncearcă ca Administrator", + "Retry interactively": "Reîncearcă interactiv", + "Retry skipping integrity checks": "Reîncearcă omiterea verificărilor de integritate", + "Installation options": "Opțiuni instalare", + "Save": "Salvează", + "UniGetUI collects anonymous usage data with the sole purpose of understanding and improving the user experience.": "UniGetUI colectează date de utilizare anonime cu unicul scop de a înțelege și a îmbunătăți experiența utilizatorilor.", + "More details about the shared data and how it will be processed": "Mai multe detalii despre datele partajate și cum vor fi acestea procesate", + "Do you accept that UniGetUI collects and sends anonymous usage statistics, with the sole purpose of understanding and improving the user experience?": "Accepți ca UniGetUI să colecteze și să trimită statistici de utilizare anonime, cu unicul scop de a înțelege și îmbunătăți experiența utilizatorilor?", + "Decline": "Refuză", + "No personal information is collected nor sent, and the collected data is anonimized, so it can't be back-tracked to you.": "Nicio informație personală nu este colectată sau trimisă, iar datele colectate sunt anonimizate, deci nu pot fi asociate cu tine.", + "Navigation panel": "Panou de navigare", + "Operations": "Operații", + "Toggle operations panel": "Comută panoul de operații", + "Bulk operations": "Operații în bloc", + "Retry failed": "Reîncearcă eșuate", + "Clear successful": "Șterge reușite", + "Clear finished": "Șterge finalizate", + "Cancel all": "Anulează tot", + "More": "Mai mult", + "Toggle navigation panel": "Comută panoul de navigare", + "Minimize": "Minimizează", + "Maximize": "Maximizează", + "UniGetUI by Devolutions": "UniGetUI de la Devolutions", + "UniGetUI is an application that makes managing your software easier, by providing an all-in-one graphical interface for your command-line package managers.": "UniGetUI este o aplicație care face managementul software-ului instalat mai ușor aducând o interfață grafică comună tuturor managerelor de pachete în linie de comandă.", + "Useful links": "Legături utile", + "UniGetUI Homepage": "Pagina principală UniGetUI", + "Report an issue or submit a feature request": "Raportează o problemă sau creează o cerere pentru o funcție nouă", + "UniGetUI Repository": "Repozitoriul UniGetUI", + "View GitHub Profile": "Vezi profil GitHub", + "UniGetUI License": "Licență UniGetUI", + "Using UniGetUI implies the acceptation of the MIT License": "Folosirea UniGetUI implică acceptarea licenței MIT.", + "Become a translator": "Devino un traducător", + "Go back": "Mergi înapoi", + "Go forward": "Mergi înainte", + "Go to home page": "Mergi la pagina de pornire", + "Reload page": "Reîncarcă pagina", + "View page on browser": "Vezi pagina în navigatorul web", + "The built-in browser is not supported on Linux yet.": "Browserul încorporat nu este încă acceptat pe Linux.", + "Open in browser": "Deschide în browser", + "Copy to clipboard": "Copiază în clipboard", + "Export to a file": "Exportă într-un fișier", + "Log level:": "Nivel jurnalizare:", + "Reload log": "Reîncarcă jurnalul", + "Export log": "Exportă jurnalul", + "Text": "Textual", + "Change how operations request administrator rights": "Schimbă modul cum operațiile cer drepturi de administrator", + "Restrictions on package operations": "Restricții asupra operațiilor cu pachete", + "Restrictions on package managers": "Restricții asupra managerilor de pachete", + "Restrictions when importing package bundles": "Restricții la importarea grupurilor de pachete", + "Ask for administrator privileges once for each batch of operations": "Solicită drepturi de administrator o singură dată pentru fiecare serie de operații", + "Ask only once for administrator privileges": "Cere doar o singură dată drepturi de administrator", + "Prohibit any kind of Elevation via UniGetUI Elevator or GSudo": "Interzice orice tip de elevare via elevatorul UniGetUI sau GSudo", + "This option WILL cause issues. Any operation incapable of elevating itself WILL FAIL. Install/update/uninstall as administrator will NOT WORK.": "Această opțiune VA cauza probleme. Orice operație incapabilă de a se eleva singură VA EȘUA. Instalarea/actualizarea/dezinstalarea ca administrator NU VA FUNCȚIONA.", + "Allow custom command-line arguments": "Permite argumente personalizate în linia de comandă", + "Custom command-line arguments can change the way in which programs are installed, upgraded or uninstalled, in a way UniGetUI cannot control. Using custom command-lines can break packages. Proceed with caution.": "Argumentele personalizate în linie de comandă pot schimba modul în care programul este instalat, actualizat sau dezinstalat într-un mod pe care UniGetUI nu îl poate controla. Folosind argumente în linie de comandă poate strica pachetele. Continuă cu atenție.", + "Ignore custom pre-install and post-install commands when importing packages from a bundle": "Permiteți rularea comenzilor personalizate de pre-instalare și post-instalare", + "Pre and post install commands will be run before and after a package gets installed, upgraded or uninstalled. Be aware that they may break things unless used carefully": "Comenzile pre și post instalare vor fi rulate înainte și după ce un pachet a fost instalat, actualizat sau dezinstalat. Fii conștient că acestea pot strica lucruri dacă nu sunt utilizate cu grijă.", + "Allow changing the paths for package manager executables": "Permite schimbarea căilor pentru executabilele managerilor de pachete", + "Turning this on enables changing the executable file used to interact with package managers. While this allows finer-grained customization of your install processes, it may also be dangerous": "Activarea acestei opțiuni permite schimbarea fișierului executabil folosit pentru a interacționa cu managerii de pachete. Deși acest lucru permite personalizare mai detaliată a procesului de instalare, ar putea de asemenea să fie periculos.", + "Allow importing custom command-line arguments when importing packages from a bundle": "Permite importarea argumentelor personalizate în linia de comandă la importarea pachetelor dintr-un grup", + "Malformed command-line arguments can break packages, or even allow a malicious actor to gain privileged execution. Therefore, importing custom command-line arguments is disabled by default": "Argumentele în linie de comandă malformate pot strica pachetele sau chiar permite unui actor malițios să obțină acces privilegiat. Așadar, importarea argumentelor personalizate în linie de comandă este implicit dezactivată.", + "Allow importing custom pre-install and post-install commands when importing packages from a bundle": "Permite importarea comenzilor de pre-instalare și post-instalare la importarea unui pachet dintr-un grup", + "Pre and post install commands can do very nasty things to your device, if designed to do so. It can be very dangerous to import the commands from a bundle, unless you trust the source of that package bundle": "Comenzile pre și post instalare pot face lucruri rele pentru dispozitivul tău dacă sunt făcute să facă astfel. Este foarte periculos să imporți o comandă dintr-un grup dacă nu ai încredere în proveniența grupului.", + "Administrator rights and other dangerous settings": "Drepturi de administrator și alte setări periculoase", + "Package backup": "Backup pachete", + "Cloud package backup": "Backup pachete în cloud", + "Local package backup": "Backup pachete local", + "Local backup advanced options": "Opțiuni avansate backup local", + "Log in with GitHub": "Autentifică-te cu GitHub", + "Log out from GitHub": "Deconectează-te de la GitHub", + "Periodically perform a cloud backup of the installed packages": "Realizează periodic un backup în cloud al pachetelor instalate", + "Cloud backup uses a private GitHub Gist to store a list of installed packages": "Copia de siguranță în cloud folosește un GitHub Gist privat pentru a stoca o listă a pachetelor instalate", + "Perform a cloud backup now": "Realizează un backup în cloud acum", + "Backup": "Copie de rezervă", + "Restore a backup from the cloud": "Restaurează un backup din cloud", + "Begin the process to select a cloud backup and review which packages to restore": "Începe procesul de a selecta un backup din cloud și revizuiește ce pachete să restaurezi", + "Periodically perform a local backup of the installed packages": "Realizează periodic un backup local al pachetelor instalate", + "Perform a local backup now": "Realizează un backup local acum", + "Change backup output directory": "Schimbă dosarul pentru copia de siguranță", + "Set a custom backup file name": "Alege un nume de fișier personalizat al copiei de siguranță", + "Leave empty for default": "Lasă liber pentru valoarea implicită", + "Add a timestamp to the backup file names": "Adaugă data și ora în numele copiei de siguranță", + "Backup and Restore": "Backup și restaurare", + "Enable background api (UniGetUI Widgets and Sharing, port 7058)": "Activează API în fundal (Widgets for UniGetUI and Sharing, port 7058)", + "Wait for the device to be connected to the internet before attempting to do tasks that require internet connectivity.": "Așteaptă ca dispozitivul să fie conectat la internet înainte să rulezi sarcini care necesită o conexiune la internet.", + "Disable the 1-minute timeout for package-related operations": "Dezactivează întârzierea de 1 minut pentru operațiile legate de pachete", + "Use installed GSudo instead of UniGetUI Elevator": "Folosește GSudo instalat în loc de UniGetUI Elevator", + "Use a custom icon and screenshot database URL": "Utilizați o pictogramă personalizată și o captură de ecran la URL-ul bazei de date", + "Enable background CPU Usage optimizations (see Pull Request #3278)": "Activarea optimizărilor în fundal ale utilizării CPU (vezi Pull Request #3278)", + "Perform integrity checks at startup": "Realizează verificări de integritate la pornire", + "When batch installing packages from a bundle, install also packages that are already installed": "La instalarea pachetelor în serie dintr-un grup, instalează de asemenea și pachetele care sunt deja instalate.", + "Experimental settings and developer options": "Setări experimentale și opțiuni dezvoltator", + "Show UniGetUI's version and build number on the titlebar.": "Afișează versiunea și numărul de build al UniGetUI în bara de titlu.", + "Language": "Limbă", + "UniGetUI updater": "Actualizator UniGetUI", + "Telemetry": "Telemetrie", + "Manage UniGetUI settings": "Administrează setările UniGetUI", + "Related settings": "Setări înrudite", + "Update UniGetUI automatically": "Actualizează UniGetUI automat", + "Check for updates": "Verifică pentru actualizări", + "Install prerelease versions of UniGetUI": "Instalează versiuni în fază de testare ale UniGetUI", + "Manage telemetry settings": "Administrează setări telemetrie", + "Manage": "Administrează", + "Import settings from a local file": "Importă setări dintr-un fișier local", + "Import": "Importă", + "Export settings to a local file": "Exportă setările într-un fișier local", + "Export": "Exportă", + "Reset UniGetUI": "Resetează UniGetUI", + "User interface preferences": "Preferințele interfeței utilizatorului", + "Application theme, startup page, package icons, clear successful installs automatically": "Tema aplicației, pagina de pornire, pictogramele pachetelor, elimină instalările reușite automat", + "General preferences": "Preferințe generale", + "UniGetUI display language:": "Limba de afișare pentru UniGetUI:", + "System language": "Limba sistemului", + "Is your language missing or incomplete?": "Lipsește limba ta sau este incompletă?", + "Appearance": "Aspect", + "UniGetUI on the background and system tray": "UniGetUI în fundal și zona de notificări a sistemului", + "Package lists": "Liste de pachete", + "Use classic mode": "Folosește modul clasic", + "Restart UniGetUI to apply this change": "Repornește UniGetUI pentru a aplica această modificare", + "The classic UI is disabled for beta testers": "Interfața clasică este dezactivată pentru testerii beta", + "Close UniGetUI to the system tray": "Închide UniGetUI în tăvița sistemului", + "Manage UniGetUI autostart behaviour": "Administrează comportamentul de pornire automată al UniGetUI", + "Show package icons on package lists": "Afișează pictogramele pachetelor în listele de pachete", + "Clear cache": "Golește cache-ul", + "Select upgradable packages by default": "Selectează pachetele actualizabile în mod implicit", + "Light": "Luminos", + "Dark": "Întunecat", + "Follow system color scheme": "Urmează tema de culoare a sistemului", + "Application theme:": "Temă aplicație:", + "UniGetUI startup page:": "Pagina de pornire UniGetUI:", + "Proxy settings": "Setări proxy", + "Other settings": "Alte setări", + "Connect the internet using a custom proxy": "Conectează-te la internet folosind un proxy personalizat", + "Please note that not all package managers may fully support this feature": "Te rog ia aminte că nu toți managerii de pachete pot suporta această funcție", + "Proxy URL": "URL proxy", + "Enter proxy URL here": "Introdu URL proxy aici", + "Authenticate to the proxy with a user and a password": "Autentifică-te la proxy cu un utilizator și o parolă", + "Internet and proxy settings": "Setări Internet și proxy", + "Package manager preferences": "Preferințe manageri pachete", + "Ready": "Pregătit", + "Not found": "Negăsit", + "Notification preferences": "Preferințe notificări", + "Notification types": "Tipuri de notificări", + "The system tray icon must be enabled in order for notifications to work": "Pictograma din tăvița sistemului trebuie să fie activată pentru a putea primi notificări", + "Enable UniGetUI notifications": "Activează notificările de la UniGetUI", + "Show a notification when there are available updates": "Arată o notificare când există actualizări disponibile", + "Show a silent notification when an operation is running": "Afișează o notificare silențioasă când se rulează o operațiune", + "Show a notification when an operation fails": "Afișează o notificare dacă o operație eșuează", + "Show a notification when an operation finishes successfully": "Afișează o notificare dacă o operație se finalizează cu succes", + "Concurrency and execution": "Concurență și execuție", + "Automatic desktop shortcut remover": "Eliminarea automată a scurtăturilor de pe spațiul de lucru", + "Choose how many operations should be performed in parallel": "Alege câte operații ar trebui efectuate în paralel", + "Clear successful operations from the operation list after a 5 second delay": "Curăță operațiile terminate cu succes din lista de operații după 5 secunde", + "Download operations are not affected by this setting": "Operațiile de descărcare nu sunt afectate de această setare", + "You may lose unsaved data": "Ai putea pierde datele nesalvate", + "Ask to delete desktop shortcuts created during an install or upgrade.": "Întreabă pentru a șterge scurtăturile din spațiul de lucru create în timpul instalării sau actualizării.", + "Package update preferences": "Preferințe actualizări pachete", + "Update check frequency, automatically install updates, etc.": "Frecvența verificărilor de actualizări, instalări automate ș.a.m.d.", + "Reduce UAC prompts, elevate installations by default, unlock certain dangerous features, etc.": "Redu întrbările UAC, elevează instalările în mod implicit, deblochează anumite funcții periculoase etc.", + "Package operation preferences": "Preferințe operații cu pachete", + "Enable {pm}": "Activează {pm}", + "Not finding the file you are looking for? Make sure it has been added to path.": "Nu găsești fișierul pe care îl cauți? Asigură-te că a fost adăugat în cale.", + "Select the executable to be used. The following list shows the executables found by UniGetUI": "Selectează executabilul de folosit. Lista următoare arată executabilele găsite de UniGetUI", + "For security reasons, changing the executable file is disabled by default": "Din motive de securitate, schimbarea fișierului executabil este implicit dezactivată", + "Change this": "Schimbă asta", + "Copy path": "Copiază calea", + "Current executable file:": "Fișierul executabil curent:", + "Ignore packages from {pm} when showing a notification about updates": "Ignoră pachetele din {pm} când este arătată o notificare despre actualizări", + "Update security": "Securitatea actualizărilor", + "Use global setting": "Folosește setarea globală", + "Minimum age for updates": "Vechimea minimă pentru actualizări", + "e.g. 10": "ex. 10", + "Custom minimum age (days)": "Vechime minimă personalizată (zile)", + "{pm} does not provide release dates for its packages, so this setting will have no effect": "{pm} nu furnizează date de lansare pentru pachetele sale, așa că această setare nu va avea niciun efect", + "{pm} only provides release dates for some of its packages, so this setting will only apply to those packages": "{pm} furnizează date de lansare doar pentru unele dintre pachetele sale, așa că această setare se va aplica doar acelor pachete", + "Override the global minimum update age for this package manager": "Suprascrie vechimea minimă globală a actualizărilor pentru acest manager de pachete", + "View {0} logs": "Vezi jurnale {0}", + "If Python cannot be found or is not listing packages but is installed on the system, ": "Dacă Python nu poate fi găsit sau nu listează pachetele, dar este instalat pe sistem, ", + "Advanced options": "Opțiuni avansate", + "WinGet command-line tool": "Instrumentul de linie de comandă WinGet", + "Choose which command-line tool UniGetUI uses for WinGet operations when the COM API is not used": "Alege instrumentul de linie de comandă pe care UniGetUI îl folosește pentru operațiile WinGet atunci când COM API nu este utilizat", + "WinGet COM API": "API-ul COM WinGet", + "Choose whether UniGetUI can use the WinGet COM API before falling back to the command-line tool": "Alege dacă UniGetUI poate folosi WinGet COM API înainte de a reveni la instrumentul de linie de comandă", + "Reset WinGet": "Resetează WinGet", + "This may help if no packages are listed": "Acest lucru poate ajuta dacă nu este listat niciun pachet", + "Force install location parameter when updating packages with custom locations": "Forțează parametrul locației de instalare la actualizarea pachetelor cu locații personalizate", + "Install Scoop": "Instalează Scoop", + "Uninstall Scoop (and its packages)": "Dezinstalează Scoop (și pachetele sale)", + "Run cleanup and clear cache": "Rulează curățarea și curăță cache-ul", + "Run": "Rulează", + "Enable Scoop cleanup on launch": "Activează curățarea pentru Scoop la pornire", + "Default vcpkg triplet": "Triplet vcpkg implicit", + "Change vcpkg root location": "Schimbă locația rădăcină pentru vcpkg", + "Reset vcpkg root location": "Resetează locația rădăcină a vcpkg", + "Open vcpkg root location": "Deschide locația rădăcină a vcpkg", + "Language, theme and other miscellaneous preferences": "Limbă, temă și alte preferințe diverse", + "Show notifications on different events": "Arată notificări pentru diverse evenimente", + "Change how UniGetUI checks and installs available updates for your packages": "Schimbă modul în care UniGetUI verifică și instalează actualizările disponibile pentru pachetele tale", + "Automatically save a list of all your installed packages to easily restore them.": "Salvează automat o listă a tuturor pachetelor instalate pentru a putea să le restaurezi cu ușurință", + "Enable and disable package managers, change default install options, etc.": "Activează și dezactivează manageri de pachete, schimbă opțiunile implicite de instalare etc.", + "Internet connection settings": "Setări conexiune la internet", + "Proxy settings, etc.": "Setări proxy etc.", + "Beta features and other options that shouldn't be touched": "Funcții beta și alte opțiuni care nu ar trebui atinse", + "Reload sources": "Reîncarcă sursele", + "Delete source": "Șterge sursa", + "Known sources": "Surse cunoscute", + "Update checking": "Verificare pentru actualizări", + "Automatic updates": "Actualizări automate", + "Check for package updates periodically": "Verifică pentru actualizări pachete periodic", + "Check for updates every:": "Verifică pentru actualizări la fiecare:", + "Install available updates automatically": "Instalează actualizările disponibile automat", + "Do not automatically install updates when the network connection is metered": "Nu instala actualizările automat când conexiunea la internet este monitorizată", + "Do not automatically install updates when the device runs on battery": "Nu instala automat actualizările când dispozitivul rulează pe baterie", + "Do not automatically install updates when the battery saver is on": "Nu instala actualizările automat când economizorul de baterie este activat", + "Only show updates that are at least the specified number of days old": "Afișează doar actualizările care au cel puțin numărul de zile specificat", + "Warn me when the installer URL host changes between the installed version and the new version (WinGet only)": "Avertizează-mă când gazda URL-ului instalatorului se schimbă între versiunea instalată și versiunea nouă (doar WinGet)", + "Change how UniGetUI handles install, update and uninstall operations.": "Schimbă modul cum abordează UniGetUI operațiile de instalare, actualizare și dezinstalare.", + "Navigation": "Navigare", + "Check for UniGetUI updates": "Verifică pentru actualizări UniGetUI", + "Quit UniGetUI": "Închide UniGetUI", + "Filters": "Filtre", + "Sources": "Surse", + "Search for packages to start": "Caută pachete pentru a începe", + "Select all": "Selectează tot", + "Clear selection": "Anulează selecția", + "Instant search": "Căutare instantă", + "Distinguish between uppercase and lowercase": "Distingeți între majuscule și minuscule", + "Ignore special characters": "Ignoră caracterele speciale", + "Search mode": "Mod căutare", + "Both": "Amândouă", + "Exact match": "Potrivire exactă", + "Show similar packages": "Pachete similare", + "Loading": "Se încarcă", + "Package": "Pachet", + "More options": "Mai multe opțiuni", + "Order by:": "Ordonează după:", + "Name": "Nume", + "Id": "ID", + "Ascendant": "Crescător", + "Descendant": "Descrescător", + "View modes": "Moduri de vizualizare", + "Reload": "Reîncarcă", + "Closed": "Închis", + "Ascending": "Crescător", + "Descending": "Descrescător", + "{0}: {1}, {2}": "{0}: {1}, {2}", + "Order by": "Ordonează după", + "No results were found matching the input criteria": "Nu s-au găsit rezultate potrivite cu criteriile selectate", + "No packages were found": "Nu au fost găsite pachete", + "Loading packages": "Se încarcă pachetele", + "Skip integrity checks": "Omite verificările de integritate", + "Download selected installers": "Descarcă instalatoarele selectate", + "Install selection": "Instalează selecția", + "Install options": "Opțiuni instalare", + "Add selection to bundle": "Adaugă selecția la grup", + "Download installer": "Descarcă instalatorul", + "Uninstall selection": "Dezinstalează selecția", + "Uninstall options": "Opțiuni dezinstalare", + "Ignore selected packages": "Ignoră pachetele selectate", + "Open install location": "Deschide locația instalării", + "Reinstall package": "Reinstalează pachet", + "Uninstall package, then reinstall it": "Dezinstalează pachetul, apoi reinstalează-l", + "Ignore updates for this package": "Ignoră actualizările pentru acest pachet", + "WinGet malfunction detected": "A fost detectată o defecțiune a WinGet", + "It looks like WinGet is not working properly. Do you want to attempt to repair WinGet?": "Se pare că WinGet nu funcționează corect. Dorești să încerci să repari WinGet?", + "Repair WinGet": "Repară WinGet", + "Updates will no longer be ignored for {0}": "Actualizările nu vor mai fi ignorate pentru {0}", + "Updates are now ignored for {0}": "Actualizările sunt acum ignorate pentru {0}", + "Do not ignore updates for this package anymore": "Nu mai ignora actualizările pentru acest pachet", + "Add packages or open an existing package bundle": "Adaugă pachete sau deschide un set existent de pachete", + "Add packages to start": "Adaugă pachete pentru a începe", + "The current bundle has no packages. Add some packages to get started": "Setul curent nu conține pachete. Adaugă câteva pachete pentru a începe", + "New": "Nou", + "Save as": "Salvează ca", + "Create .ps1 script": "Creează un script .ps1", + "Remove selection from bundle": "Elimină selecția din grup", + "Skip hash checks": "Omite verificările sumelor de control", + "The package bundle is not valid": "Grupul de pachete nu este valid", + "The bundle you are trying to load appears to be invalid. Please check the file and try again.": "Grupul pe care încerci să-l încarci pare să fie invalid. Te rog verifică fișierul și încearcă din nou.", + "Package bundle": "Grup pachete", + "Could not create bundle": "Nu s-a putut crea grupul", + "The package bundle could not be created due to an error.": "Grupul de pachete nu a putut fi creat din cauza unei erori.", + "Install script": "Script instalare", + "PowerShell script": "Script PowerShell", + "The installation script saved to {0}": "Scriptul de instalare a fost salvat în {0}", + "An error occurred": "A apărut o eroare", + "An error occurred while attempting to create an installation script:": "A apărut o eroare la încercarea de a creea un script de instalare:", + "Hooray! No updates were found.": "Ura! Nu a fost găsită nicio actualizare!", + "Uninstall selected packages": "Dezinstalează pachetele selectate", + "Update selection": "Actualizează selecția", + "Update options": "Opțiuni actualizare", + "Uninstall package, then update it": "Dezinstalează pachetul, apoi actualizează-l", + "Uninstall package": "Dezinstalează pachetul", + "Skip this version": "Omite această versiune", + "Pause updates for": "Sistează actualizările pentru", + "User | Local": "Utilizator | Local", + "Machine | Global": "Computer | Global", + "The default package manager for Debian/Ubuntu-based Linux distributions.
Contains: Debian/Ubuntu packages": "Managerul de pachete implicit pentru distribuțiile Linux bazate pe Debian/Ubuntu.
Conține: Pachete Debian/Ubuntu", + "The Rust package manager.
Contains: Rust libraries and programs written in Rust": "Managerul de pachete Rust.
Conține: Biblioteci Rust și programe scrise în Rust", + "The classical package manager for windows. You'll find everything there.
Contains: General Software": "Managerul de pachete clasic pentru Windows. Vei găsi totul acolo.
Conține: Programe generale", + "The default package manager for RHEL/Fedora-based Linux distributions.
Contains: RPM packages": "Managerul de pachete implicit pentru distribuțiile Linux bazate pe RHEL/Fedora.
Conține: Pachete RPM", + "A repository full of tools and executables designed with Microsoft's .NET ecosystem in mind.
Contains: .NET related tools and scripts": "Un repository plin de unelte și executabile concepute pe baza ecosistemului Microsoft .NET.
Conține: Unelte și scripturi legate de .NET", + "The universal Linux package manager for desktop applications.
Contains: Flatpak applications from configured remotes": "Managerul universal de pachete Linux pentru aplicații desktop.
Conține: aplicații Flatpak din sursele la distanță configurate", + "NuPkg (zipped manifest)": "NuPkg (manifest zip)", + "The Missing Package Manager for macOS (or Linux).
Contains: Formulae, Casks": "Managerul de pachete lipsă pentru macOS (sau Linux).
Conține: Formulae, Casks", + "Node JS's package manager. Full of libraries and other utilities that orbit the javascript world
Contains: Node javascript libraries and other related utilities": "Managerul de pachete al lui Node JS. Plin de biblioteci și alte utilitare care orbitează lumea javascript
Conține: Biblioteci javascript Node și alte utilitare conexe", + "The default package manager for Arch Linux and its derivatives.
Contains: Arch Linux packages": "Managerul de pachete implicit pentru Arch Linux și derivatele sale.
Conține: Pachete Arch Linux", + "Python's library manager. Full of python libraries and other python-related utilities
Contains: Python libraries and related utilities": "Managerul bibliotecii Python. Plin de biblioteci Python și alte utilitare legate de Python
Conține: Biblioteci Python și utilități aferente", + "PowerShell's package manager. Find libraries and scripts to expand PowerShell capabilities
Contains: Modules, Scripts, Cmdlets": "Managerul de pachete al PowerShell. Găsește biblioteci și scripturi pentru a extinde capabilitățile PowerShell
Conține: Module, Scripturi, Comenzi", + "extracted": "extras", + "Scoop package": "Pachet Scoop", + "Great repository of unknown but useful utilities and other interesting packages.
Contains: Utilities, Command-line programs, General Software (extras bucket required)": "Repository excelent de utilități necunoscute, dar utile, și alte pachete interesante.
Conține: Utilitare, programe în linie de comandă, software general (găleata extra necesară)", + "The universal Linux package manager by Canonical.
Contains: Snap packages from the Snapcraft store": "Managerul universal de pachete Linux de la Canonical.
Conține: Pachete Snap din magazinul Snapcraft", + "library": "bibliotecă", + "feature": "caracteristică", + "A popular C/C++ library manager. Full of C/C++ libraries and other C/C++-related utilities
Contains: C/C++ libraries and related utilities": "Un manager de biblioteci C/C++ popular. Plin de biblioteci C/C++ și alte utilitare conexe
Conține: biblioteci C/C++ și utilitare conexe", + "option": "opțiune", + "This package cannot be installed from an elevated context.": "Acest pachet nu poate fi instalat dintr-un context elevat.", + "Please run UniGetUI as a regular user and try again.": "Te rog rulează UniGetUI ca un utilizator normal și încearcă din nou", + "Please check the installation options for this package and try again": "Te rog verifică opțiunile de instalare ale acestui pachet și încearcă din nou", + "Microsoft's official package manager. Full of well-known and verified packages
Contains: General Software, Microsoft Store apps": "Managerul de pachete oficial al Microsoft. Plin de pachete arhicunoscute și verificate.
Conține: Software general, aplicații Microsoft Store", + "Local PC": "PC-ul local", + "Android Subsystem": "Subsistemul Android", + "Operation on queue (position {0})...": "Operație în coadă (poziția {0})...", + "Click here for more details": "Clic aici pentru mai multe detalii", + "Operation canceled by user": "Operația a fost anulată de utilizator", + "Running PreOperation ({0}/{1})...": "Se rulează PreOperation ({0}/{1})...", + "PreOperation {0} out of {1} failed, and was tagged as necessary. Aborting...": "PreOperation {0} din {1} a eșuat și a fost marcată ca necesară. Se anulează...", + "PreOperation {0} out of {1} finished with result {2}": "PreOperation {0} din {1} s-a încheiat cu rezultatul {2}", + "Starting operation...": "Se începe operația...", + "Running PostOperation ({0}/{1})...": "Se rulează PostOperation ({0}/{1})...", + "PostOperation {0} out of {1} failed, and was tagged as necessary. Aborting...": "PostOperation {0} din {1} a eșuat și a fost marcată ca necesară. Se anulează...", + "PostOperation {0} out of {1} finished with result {2}": "PostOperation {0} din {1} s-a încheiat cu rezultatul {2}", + "{package} installer download": "Descărcare installer {package}", + "{0} installer is being downloaded": "Instalatorul {0} este în curs de descărcare", + "Download succeeded": "Descărcarea a fost realizată", + "{package} installer was downloaded successfully": "Instalatorul pentru {package} a fost descărcat cu succes", + "Download failed": "Descărcarea a eșuat", + "{package} installer could not be downloaded": "Instalatorul {package} nu a putut fi descărcat", + "{package} Installation": "Instalare {package}", + "{0} is being installed": "{0} este în curs de instalare", + "Installation succeeded": "Instalarea s-a realizat", + "{package} was installed successfully": "{package} a fost instalat cu succes", + "Installation failed": "Instalarea a eșuat", + "{package} could not be installed": "{package} nu a putut fi instalat", + "{package} Update": "Actualizare {package}", + "Update succeeded": "Actualizarea s-a realizat", + "{package} was updated successfully": "{package} a fost actualizat cu succes", + "Update failed": "Actualizarea a eșuat", + "{package} could not be updated": "{package} nu a putut fi actualizat", + "{package} Uninstall": "Dezinstalare {package}", + "{0} is being uninstalled": "{0} este în curs de dezinstalare", + "Uninstall succeeded": "Dezinstalarea s-a realizat", + "{package} was uninstalled successfully": "{package} a fost dezinstalat cu succes", + "Uninstall failed": "Dezinstalarea a eșuat", + "{package} could not be uninstalled": "{package} nu a putut fi dezinstalat", + "Adding source {source}": "Se adaugă sursa {source}", + "Adding source {source} to {manager}": "Se adaugă sursa {source} la {manager}", + "Source added successfully": "Sursa a fost adăugată cu succes", + "The source {source} was added to {manager} successfully": "Sursa {source} a fost adăugată la {manager} cu succes", + "Could not add source": "Nu s-a putut adăuga sursa", + "Could not add source {source} to {manager}": "Nu s-a putut adăuga sursa {source} la {manager}", + "Removing source {source}": "Se elimină sursa {source}", + "Removing source {source} from {manager}": "Se elimină sursa {source} din {manager}", + "Source removed successfully": "Sursa a fost eliminată cu succes", + "The source {source} was removed from {manager} successfully": "Sursa {source} a fost eliminată din {manager} cu succes", + "Could not remove source": "Nu s-a putut elimina sursa", + "Could not remove source {source} from {manager}": "Nu s-a putut elimina sursa {source} din {manager}", + "The package manager \"{0}\" was not found": "Managerul de pachete „{0}” nu a fost găsit", + "The package manager \"{0}\" is disabled": "Managerul de pachete „{0}” este dezactivat", + "There is an error with the configuration of the package manager \"{0}\"": "Există o eroare cu configurația managerului de pachete „{0}”", + "The package \"{0}\" was not found on the package manager \"{1}\"": "Pachetul „{0}” nu a fost găsit în managerul de pachete „{1}”", + "{0} is disabled": "{0} este dezactivat", + "{0} weeks": "{0} săptămâni", + "1 month": "o lună", + "{0} months": "{0} luni", + "Something went wrong": "Ceva nu a funcționat", + "An interal error occurred. Please view the log for further details.": "A apărut o eroare internă. Te rog să verifici jurnalul pentru detalii suplimentare.", + "No applicable installer was found for the package {0}": "Niciun instalator aplicabil nu a fost găsit pentru pachetul {0}", + "Integrity checks will not be performed during this operation": "Verificările de integritate nu vor fi făcute în timpul acestei operații", + "This is not recommended.": "Acest lucru nu este recomandat", + "Run now": "Rulează acum", + "Run next": "Rulează următoarea", + "Run last": "Rulează ultima", + "Show in explorer": "Arată în Explorer", + "Checked": "Bifat", + "Unchecked": "Debifat", + "This package is already installed": "Acest pachet este deja instalat", + "This package can be upgraded to version {0}": "Acest pachet poate fi actualizat la versiunea {0}", + "Updates for this package are ignored": "Actualizările pentru acest pachet sunt ignorate", + "This package is being processed": "Acest pachet este în curs de procesare", + "This package is not available": "Acest pachet nu este disponibil", + "Select the source you want to add:": "Selectează sursa pe care dorești să o adaugi:", + "Source name:": "Nume sursă:", + "Source URL:": "Sursă URL:", + "An error occurred when adding the source: ": "A apărut o eroare la adăugarea sursei:", + "Package management made easy": "Gestionarea pachetelor simplificată", + "version {0}": "versiunea {0}", + "[RAN AS ADMINISTRATOR]": "RULAT CA ADMINISTRATOR", + "Portable mode": "Mod portabil", + "DEBUG BUILD": "BUILD DEPANARE", + "Here you can change UniGetUI's behaviour regarding the following shortcuts. Checking a shortcut will make UniGetUI delete it if if gets created on a future upgrade. Unchecking it will keep the shortcut intact": "De aici poți schimba comportamentul UniGetUI legat de scurtături. Bifând o scurtătură vei face ca UniGetUI să o șteargă dacă ea va fi creată la o actualizare viitoare. Debifând-o, vei păstra scurtătura intactă.", + "Manual scan": "Scanare manuală", + "Existing shortcuts on your desktop will be scanned, and you will need to pick which ones to keep and which ones to remove.": "Scurtăturile existente pe Desktop vor fi scanate și va trebui să alegi pe care le păstrezi și pe care le ștergi.", + "Delete?": "Ștergi?", + "I understand": "Am înțeles", + "Chocolatey setup changed": "Configurarea Chocolatey a fost schimbată", + "UniGetUI no longer includes its own private Chocolatey installation. A legacy UniGetUI-managed Chocolatey installation was detected for this user profile, but system Chocolatey was not found. Chocolatey will stay unavailable in UniGetUI until Chocolatey is installed on the system and UniGetUI is restarted. Applications previously installed through UniGetUI's bundled Chocolatey may still appear under other sources such as Local PC or WinGet.": "UniGetUI nu mai include propria instalare privată de Chocolatey. O instalare Chocolatey moștenită gestionată de UniGetUI a fost detectată pentru acest profil de utilizator, dar Chocolatey de sistem nu a fost găsit. Chocolatey va rămâne indisponibil în UniGetUI până când Chocolatey este instalat pe sistem și UniGetUI este repornit. Aplicațiile instalate anterior prin Chocolatey inclus în UniGetUI pot apărea în continuare sub alte surse precum PC local sau WinGet.", + "NOTE: This troubleshooter can be disabled from UniGetUI Settings, on the WinGet section": "NOTĂ: Acest depanator poate fi dezactivat din setările UniGetUI, din secțiunea WinGet", + "Restart": "Repornește", + "Are you sure you want to delete all shortcuts?": "Ești sigur că dorești să ștergi toate scurtăturile?", + "Any new shorcuts created during an install or an update operation will be deleted automatically, instead of showing a confirmation prompt the first time they are detected.": "Orice scurtături noi create în timpul unei instalări sau actualizări vor fi șterse automat, în loc de a arăta o întrebare prima dată ce sunt detectate.", + "Any shorcuts created or modified outside of UniGetUI will be ignored. You will be able to add them via the {0} button.": "Orice scurtături create sau modificate în afara UniGetUI vor fi ignorate. Le vei putea adăuga cu butonul {0}.", + "Are you really sure you want to enable this feature?": "Ești sigur că dorești să activezi această caracteristică?", + "No new shortcuts were found during the scan.": "În timpul scanării nu au fost găsite noi scurtături.", + "How to add packages to a bundle": "Cum să adaugi pachete într-un grup", + "In order to add packages to a bundle, you will need to: ": "Pentru a putea adăuga pachete într-un grup va trebui să:", + "1. Navigate to the \"{0}\" or \"{1}\" page.": "1. Navighează la pagina „{0}” sau „{1}”", + "2. Locate the package(s) you want to add to the bundle, and select their leftmost checkbox.": "2. Localizează pachetele pe care dorești să le adaugi în grup și bifează caseta cea mai din stânga.", + "3. When the packages you want to add to the bundle are selected, find and click the option \"{0}\" on the toolbar.": "3. Când pachetele pe care dorești să le adaugi la grup sunt selectate, apasă pe opțiunea „{0}” din bara de instrumente.", + "4. Your packages will have been added to the bundle. You can continue adding packages, or export the bundle.": "4. Pachetele tale vor fi fost adăugate în grup. Poți continua să adaugi pachete sau să exporți grupul.", + "Which backup do you want to open?": "Ce backup dorești să deschizi?", + "Select the backup you want to open. Later, you will be able to review which packages you want to install.": "Selectează backup-ul pe care dorești să îl deschizi. Mai târziu vei putea să revizuiești ce pachete dorești să instalezi.", + "There are ongoing operations. Quitting UniGetUI may cause them to fail. Do you want to continue?": "Există operații în curs. Închizând UniGetUI va face ca ele să eșueze. Dorești să continui?", + "UniGetUI or some of its components are missing or corrupt.": "UniGetUI sau unele din componentele sale lipsesc sau sunt corupte.", + "It is strongly recommended to reinstall UniGetUI to adress the situation.": "Este recomandat cu tărie să reinstalezi UniGetUI pentru a adresa această situație.", + "Refer to the UniGetUI Logs to get more details regarding the affected file(s)": "Fă referire la jurnalele UniGetUI pentru a obține mai multe detalii despre fișierele afectate", + "Integrity checks can be disabled from the Experimental Settings": "Verificările de integritate pot fi dezactivate din setările experimentale", + "Repair UniGetUI": "Repară UniGetUI", + "Live output": "Output în timp real", + "This package bundle had some settings that are potentially dangerous, and may be ignored by default.": "Acest grup de pachete a avut anumite setări care sunt potențial periculoase și ar putea să fie implicit ignorate.", + "Entries that show in YELLOW will be IGNORED.": "Intrările afișate cu GALBEN for fi IGNORATE.", + "Entries that show in RED will be IMPORTED.": "Intrările afișate cu ROȘU vor fi IMPORTATE.", + "You can change this behavior on UniGetUI security settings.": "Poți schimba acest comportament în setările de securiate al UniGetUI.", + "Open UniGetUI security settings": "Deschide setările de securitate ale UniGetUI", + "Should you modify the security settings, you will need to open the bundle again for the changes to take effect.": "Dacă ar fi să modifici setările de securitate, va trebui să deschizi grupul din nou pentru ca schimbările să fie aplicate.", + "Details of the report:": "Detaliile raportului:", + "Are you sure you want to create a new package bundle? ": "Ești sigur că dorești să creezi un nou grup de pachete?", + "Any unsaved changes will be lost": "Orice modificări nesalvate vor fi pierdute", + "Warning!": "Atenție!", + "For security reasons, custom command-line arguments are disabled by default. Go to UniGetUI security settings to change this. ": "Din motive de securitate, argumentele personalizate din linia de comandă sunt implicit dezactivate. Mergi la setările de securitate ale UniGetUI pentru a schimba acest lucru.", + "Change default options": "Schimbă opțiunile implicite", + "Ignore future updates for this package": "Ignoră actualizările viitoare pentru acest pachet", + "For security reasons, pre-operation and post-operation scripts are disabled by default. Go to UniGetUI security settings to change this. ": "Din motive de securitate, scripturile pre-operație și post-operație sunt implicit dezactivate. Mergi la setările de securitate ale UniGetUI pentru a schimba acest lucru.", + "You can define the commands that will be run before or after this package is installed, updated or uninstalled. They will be run on a command prompt, so CMD scripts will work here.": "Poți defini comenzile care vor fi rulate înainte sau după ce acest pachet este instalat, actualizat sau dezinstalat. Acestea vor fi rulate într-un prompt de comandă, deci scripturile CMD vor funcționa aici.", + "Change this and unlock": "Schimbă asta și deblochează", + "{0} Install options are currently locked because {0} follows the default install options.": "Opțiunile de instalare ale {0} sunt blocate acum deoarece {0} respectă opțiunile de instalare implicite.", + "Unset or unknown": "Nesetat sau necunoscut", + "This package has no screenshots or is missing the icon? Contrbute to UniGetUI by adding the missing icons and screenshots to our open, public database.": "Lipsesc capturile de ecran sau pictograma acestui pachet? Contribuie la UniGetUI adăugând pictogramele sau capturile de ecran lipsă în baza noastră de date deschisă și publică.", + "Become a contributor": "Devino un contribuitor", + "Update to {0} available": "Actualizare la {0} disponibilă", + "Reinstall": "Reinstalează", + "Installer not available": "Instalatorul nu este disponibil", + "Version:": "Versiune:", + "UniGetUI Version {0}": "Versiunea UniGetUI {0}", + "Performing backup, please wait...": "Se face un backup, te rog așteaptă...", + "An error occurred while logging in: ": "A apărut o eroare la autentificare:", + "Fetching available backups...": "Se preiau copiile de siguranță disponibile...", + "Done!": "Gata!", + "The cloud backup has been loaded successfully.": "Copia de siguranță din cloud a fost încărcată cu succes.", + "An error occurred while loading a backup: ": "A apărut o eroare la încărcarea copiei de siguranță:", + "Backing up packages to GitHub Gist...": "Se face un backup al pachetelor pe GitHub Gist...", + "Backup Successful": "Backup-ul s-a finalizat cu succes", + "The cloud backup completed successfully.": "Copierea de siguranță s-a finalizat cu succes.", + "Could not back up packages to GitHub Gist: ": "Nu s-au putut copia pachetele în GitHub Gist:", + "It is not guaranteed that the provided credentials will be stored safely, so you may as well not use the credentials of your bank account": "Nu este garantat că acreditările oferite vor fi stocate în siguranță, deci ai putea să nu folosești datele contului tău bancar.", + "Enable the automatic WinGet troubleshooter": "Activează depanatorul automat pentru WinGet", + "Add updates that fail with a 'no applicable update found' to the ignored updates list": "Adaugă actualizările care eșuează cu „nicio actualizare aplicabilă găsită” în lista de actualizări ignorate", + "Invalid selection": "Selecție invalidă", + "No package was selected": "Niciun pachet selectat", + "More than 1 package was selected": "A fost selectat mai mult de un pachet", + "List": "Listă", + "Grid": "Grilă", + "Icons": "Pictograme", + "\"{0}\" is a local package and does not have available details": "„{0}” este un pachet local și nu are detalii disponibile", + "\"{0}\" is a local package and is not compatible with this feature": "„{0}” este un pachet local și nu este compatibil cu această funcție", + "Add packages to bundle": "Adaugă pachete în grup", + "Preparing packages, please wait...": "Se pregătesc pachetele, te rog așteaptă...", + "Loading packages, please wait...": "Se încarcă pachetele, te rog așteaptă...", + "Saving packages, please wait...": "Se salvează pachetele, te rog așteaptă...", + "The bundle was created successfully on {0}": "Grupul a fost creat cu succes pe {0}", + "User profile": "Profil utilizator", + "Error": "Eroare", + "Log in failed: ": "Autentificarea a eșuat:", + "Log out failed: ": "Deconectarea a eșuat:", + "Package backup settings": "Setări backup pachete", + "Package managers": "Manageri pachete", + "Manage UniGetUI autostart behaviour from the Settings app": "Gestionează comportamentul de pornire automată al UniGetUI", + "Choose how many operations shoulds be performed in parallel": "Alege câte operații să fie efectuate în paralel", + "Something went wrong while launching the updater.": "Ceva nu a funcționat la lansarea actualizatorului.", + "Please try again later": "Te rog încearcă din nou mai târziu", + "Show the release notes after UniGetUI is updated": "Afișează informațiile versiunii după actualizarea UniGetUI" +} diff --git a/src/Languages/lang_ru.json b/src/Languages/lang_ru.json new file mode 100644 index 0000000..8b1a55e --- /dev/null +++ b/src/Languages/lang_ru.json @@ -0,0 +1,851 @@ +{ + "{0} of {1} operations completed": "Завершено {0} из {1} операций", + "{0} is now {1}": "{0} теперь {1}", + "Enabled": "Включено", + "Disabled": "Выключено", + "Privacy": "Конфиденциальность", + "Hide my username from the logs": "Скрыть моё имя в журналах", + "Replaces your username with **** in the logs. Restart UniGetUI to also hide it from already-recorded entries.": "Заменяет ваше имя на **** в журналах. Перезапустите UniGetUI, чтобы скрыть его также в уже записанных записях.", + "Your last update attempt did not complete.": "Последняя попытка обновления не была завершена.", + "UniGetUI could not confirm whether the update succeeded. Open the log to see what happened.": "UniGetUI не удалось подтвердить, было ли обновление выполнено успешно. Откройте журнал, чтобы узнать, что произошло.", + "View log": "Просмотреть журнал", + "The installer reported success but did not restart UniGetUI.": "Установщик сообщил об успешном завершении, но не перезапустил UniGetUI.", + "The installer failed to initialize.": "Не удалось инициализировать установщик.", + "Setup was canceled before installation began.": "Установка была отменена до начала процесса установки.", + "A fatal error occurred during the preparation phase.": "На этапе подготовки произошла критическая ошибка.", + "A fatal error occurred during installation.": "Во время установки произошла критическая ошибка.", + "Installation was canceled while in progress.": "Установка была отменена во время выполнения.", + "The installer was terminated by another process.": "Установщик был завершен другим процессом.", + "The preparation phase determined the installation cannot proceed.": "На этапе подготовки было определено, что продолжить установку невозможно.", + "The installer could not start. UniGetUI may already be running, or you do not have permission to install.": "Не удалось запустить установщик. Возможно, UniGetUI уже запущен или у вас нет прав на установку.", + "Unexpected installer error.": "Непредвиденная ошибка установщика.", + "We are checking for updates.": "Мы проверяем наличие обновлений.", + "Please wait": "Пожалуйста подождите", + "Great! You are on the latest version.": "Отлично! Вы используете последнюю версию.", + "There are no new UniGetUI versions to be installed": "Новых версий UniGetUI для установки нет", + "UniGetUI version {0} is being downloaded.": "Идет загрузка UniGetUI версии {0}.", + "This may take a minute or two": "Это может занять минуту или две", + "The installer authenticity could not be verified.": "Подлинность установщика не удалось проверить.", + "The update process has been aborted.": "Процесс обновления был прерван.", + "Auto-update is not yet available on this platform.": "Автоматическое обновление пока недоступно на этой платформе.", + "Please update UniGetUI manually.": "Пожалуйста, обновите UniGetUI вручную.", + "An error occurred when checking for updates: ": "Ошибка при проверке обновлений:", + "The updater could not be launched.": "Не удалось запустить средство обновления.", + "The operating system did not start the installer process.": "Операционная система не запустила процесс установщика.", + "UniGetUI is being updated...": "UniGetUI обновляется...", + "Update installed.": "Обновление установлено.", + "UniGetUI was updated successfully, but this running copy was not replaced. This usually means you are running a development build. Close this copy and start the newly-installed version to finish.": "UniGetUI был успешно обновлен, но этот запущенный экземпляр не был заменен. Обычно это означает, что вы используете сборку для разработки. Закройте этот экземпляр и запустите только что установленную версию, чтобы завершить обновление.", + "The update could not be applied.": "Не удалось применить обновление.", + "Installer exit code {0}: {1}": "Код выхода установщика {0}: {1}", + "Update cancelled.": "Обновление отменено.", + "Authentication was cancelled.": "Проверка подлинности отменена.", + "Installer exit code {0}": "Код выхода установщика {0}", + "Operation in progress": "В процессе...", + "Please wait...": "Пожалуйста, подождите...", + "Success!": "Успешно!", + "Failed": "Не удалось", + "An error occurred while processing this package": "Произошла ошибка при обработке этого пакета", + "Installer": "Установщик", + "Executable": "Исполняемый файл", + "MSI": "MSI", + "Compressed file": "Сжатый файл", + "MSIX": "MSIX", + "WinGet was repaired successfully": "WinGet восстановлен успешно", + "It is recommended to restart UniGetUI after WinGet has been repaired": "Рекомендуется перезапустить UniGetUI после восстановления WinGet", + "WinGet could not be repaired": "WinGet не может быть восстановлен", + "An unexpected issue occurred while attempting to repair WinGet. Please try again later": "Неожиданная проблема во время восстановления WinGet. Пожалуйста, попробуйте запустить восстановление позднее", + "Log in to enable cloud backup": "Войдите для включения облачного резервного копирования", + "Backup Failed": "Ошибка резервного копирования", + "Downloading backup...": "Загружаем резервную копию…", + "An update was found!": "Найдено обновление!", + "{0} can be updated to version {1}": "{0} может быть обновлен до версии {1}", + "Updates found!": "Найдены обновления!", + "{0} packages can be updated": "{0} пакетов можно обновить", + "{0} is being updated to version {1}": "{0} обновляется до версии {1}", + "{0} packages are being updated": "{0} пакетов обновляется", + "You have currently version {0} installed": "На данный момент у вас установлена версия {0}", + "Desktop shortcut created": "Ярлык на рабочем столе создан", + "UniGetUI has detected a new desktop shortcut that can be deleted automatically.": "UniGetUI обнаружил новый ярлык на рабочем столе, который может быть удален автоматически.", + "{0} desktop shortcuts created": "Создано {0} ярлыков на рабочем столе", + "UniGetUI has detected {0} new desktop shortcuts that can be deleted automatically.": "UniGetUI обнаружил {0} новые ярлыки на рабочем столе, которые могут быть удалены автоматически.", + "Attention required": "Требуется внимание пользователя", + "Restart required": "Требуется перезагрузка", + "1 update is available": "Доступно 1 обновление", + "{0} updates are available": "{0} доступны обновления", + "Everything is up to date": "Все актуально", + "Discover Packages": "Доступные пакеты", + "Available Updates": "Доступные обновления", + "Installed Packages": "Установленные пакеты", + "UniGetUI Version {0} by Devolutions": "Версия UniGetUI {0} от Devolutions", + "Show UniGetUI": "Показать UniGetUI", + "Quit": "Выход", + "Are you sure?": "Вы уверены?", + "Do you really want to uninstall {0}?": "Вы действительно хотите удалить {0}?", + "Do you really want to uninstall the following {0} packages?": "Вы действительно хотите удалить следующие {0} пакетов?", + "No": "Нет", + "Yes": "Да", + "Partial": "Частично", + "View on UniGetUI": "Смотреть на сайте UniGetUI", + "Update": "Обновить", + "Open UniGetUI": "Открыть UniGetUI", + "Update all": "Обновить все", + "Update now": "Обновить сейчас", + "Installer host changed since the installed version.\n": "Хост установщика изменился по сравнению с установленной версией.\n", + "This package is on the queue": "Этот пакет находится в очереди", + "installing": "установка", + "updating": "обновление", + "uninstalling": "удаление", + "installed": "установлен", + "Retry": "Повторить", + "Install": "Установить", + "Uninstall": "Удалить", + "Open": "Открыть", + "Operation profile:": "Профиль операции:", + "Follow the default options when installing, upgrading or uninstalling this package": "Следовать настройкам по умолчанию при установке, обновлении или удалении этого пакета", + "The following settings will be applied each time this package is installed, updated or removed.": "Следующие настройки будут применяться каждый раз при установке, обновлении или удалении этого пакета.", + "Version to install:": "Версия для установки:", + "Architecture to install:": "Архитектура для установки:", + "Installation scope:": "Область установки:", + "Install location:": "Место установки:", + "Select": "Выбрать", + "Reset": "Сбросить", + "Custom install arguments:": "Пользовательские аргументы установки:", + "Custom update arguments:": "Пользовательские аргументы обновления:", + "Custom uninstall arguments:": "Пользовательские аргументы удаления:", + "Pre-install command:": "Команда перед установкой:", + "Post-install command:": "Команда после установки:", + "Abort install if pre-install command fails": "Отменить установку при ошибке выполнения предустановочной команды", + "Pre-update command:": "Команда перед обновлением:", + "Post-update command:": "Команда после обновления:", + "Abort update if pre-update command fails": "Отменить обновление при ошибке выполнения предварительной команды", + "Pre-uninstall command:": "Команда перед удалением:", + "Post-uninstall command:": "Команда после удаления:", + "Abort uninstall if pre-uninstall command fails": "Отменить удаление при ошибке выполнения предварительной команды", + "Command-line to run:": "Команда для запуска:", + "Save and close": "Сохранить и закрыть", + "General": "Общие", + "Architecture & Location": "Архитектура и расположение", + "Command-line": "Командная строка", + "Close apps": "Закрыть приложения", + "Pre/Post install": "До/после установки", + "Select the processes that should be closed before this package is installed, updated or uninstalled.": "Выберите процессы для закрытия перед установкой, обновлением или удалением пакета.", + "Write here the process names here, separated by commas (,)": "Укажите здесь имена процессов, разделяя их запятыми (,)", + "Try to kill the processes that refuse to close when requested to": "Пробовать останавливать процессы, препятствующие закрытию во время запроса.", + "Run as admin": "Запуск от имени администратора", + "Interactive installation": "Интерактивная установка", + "Skip hash check": "Пропустить проверку хэша", + "Uninstall previous versions when updated": "Удалять предыдущие версии после обновления", + "Skip minor updates for this package": "Пропускать минорные обновления данного пакета", + "Automatically update this package": "Автоматически обновлять этот пакет", + "{0} installation options": "Параметры установки {0}", + "Latest": "Последний", + "PreRelease": "Предварительный релиз", + "Default": "По умолчанию", + "Manage ignored updates": "Управление игнорируемыми обновлениями", + "The packages listed here won't be taken in account when checking for updates. Double-click them or click the button on their right to stop ignoring their updates.": "Перечисленные здесь пакеты не будут учитываться при проверке обновлений. Дважды щелкните по ним или нажмите кнопку справа, чтобы перестать игнорировать их обновления.", + "Reset list": "Сбросить список", + "Do you really want to reset the ignored updates list? This action cannot be reverted": "Вы действительно хотите сбросить список игнорируемых обновлений? Это действие нельзя отменить", + "No ignored updates": "Нет игнорируемых обновлений", + "Package Name": "Название пакета", + "Package ID": "ID пакета", + "Ignored version": "Игнорируемая версия", + "New version": "Новая версия", + "Source": "Источник", + "All versions": "Все версии", + "Unknown": "Неизвестно", + "Up to date": "Актуально", + "Package {name} from {manager}": "Пакет {name} из {manager}", + "Remove {0} from ignored updates": "Удалить {0} из игнорируемых обновлений", + "Cancel": "Отмена", + "Administrator privileges": "Права администратора", + "This operation is running with administrator privileges.": "Данная операция запущена с правами администратора", + "Interactive operation": "Интерактивное управление", + "This operation is running interactively.": "Данная операция запущена интерактивно", + "You will likely need to interact with the installer.": "Вам скорее всего потребуется взаимодействовать с установщиком", + "Integrity checks skipped": "Проверка целостности пропущена", + "Integrity checks will not be performed during this operation.": "Во время этой операции проверки целостности выполняться не будут.", + "Proceed at your own risk.": "Действуйте на свой страх и риск", + "Close": "Закрыть", + "Loading...": "Загрузка...", + "Installer SHA256": "SHA256 установщика", + "Homepage": "Домашняя страница", + "Author": "Автор", + "Publisher": "Издатель", + "License": "Лицензия", + "Manifest": "Манифест", + "Installer Type": "Тип установщика", + "Size": "Размер", + "Installer URL": "URL установщика", + "Last updated:": "Последнее обновление:", + "Release notes URL": "URL заметок к выпуску", + "Package details": "Информация о пакете", + "Dependencies:": "Зависимости:", + "Release notes": "Примечания к выпуску", + "Screenshots": "Скриншоты", + "This package has no screenshots or is missing the icon? Contribute to UniGetUI by adding the missing icons and screenshots to our open, public database.": "У этого пакета нет скриншотов или отсутствует иконка? Внесите свой вклад в UniGetUI, добавив недостающие иконки и скриншоты в нашу открытую, общедоступную базу данных.", + "Version": "Версия", + "Install as administrator": "Установить от имени администратора", + "Update to version {0}": "Обновление до версии {0}", + "Installed Version": "Установленная версия", + "Update as administrator": "Обновить от имени администратора", + "Interactive update": "Интерактивное обновление", + "Uninstall as administrator": "Удалить от имени администратора", + "Interactive uninstall": "Интерактивное удаление", + "Uninstall and remove data": "Деинсталляция и удаление данных", + "Not available": "Не доступно", + "Installer SHA512": "Хэш установщика SHA512", + "Unknown size": "Неизвестный размер", + "No dependencies specified": "Не указаны зависимости", + "mandatory": "обязательно", + "optional": "необязательно", + "UniGetUI {0} is ready to be installed.": "UniGetUI {0} готов к установке.", + "The update process will start after closing UniGetUI": "Процесс обновления начнется после закрытия UniGetUI", + "UniGetUI has been ran as administrator, which is not recommended. When running UniGetUI as administrator, EVERY operation launched from UniGetUI will have administrator privileges. You can still use the program, but we highly recommend not running UniGetUI with administrator privileges.": "UniGetUI был запущен от имени администратора, что не рекомендуется. При запуске UniGetUI от имени администратора КАЖДАЯ операция, запущенная из UniGetUI, будет иметь права администратора. Вы всё ещё можете использовать программу, но мы настоятельно рекомендуем не запускать UniGetUI с правами администратора.", + "Share anonymous usage data": "Отправлять анонимные пользовательские данные", + "UniGetUI collects anonymous usage data in order to improve the user experience.": "UniGetUI собирает анонимную статистику использования в целях улучшения опыта использования", + "Accept": "Применить", + "Software Updates": "Обновления программ", + "Package Bundles": "Наборы пакетов", + "Settings": "Настройки", + "Package Managers": "Менеджеры пакетов", + "UniGetUI Log": "Журнал UniGetUI", + "Package Manager logs": "Журналы менеджера пакетов", + "Operation history": "История действий", + "Help": "Помощь", + "UniGetUI": "UniGetUI", + "You have installed UniGetUI Version {0}": "Вы установили UniGetUI версию {0}", + "Disclaimer": "Отказ от ответственности", + "UniGetUI is developed by Devolutions and is not affiliated with any of the compatible package managers.": "UniGetUI разрабатывается Devolutions и не связана ни с одним из совместимых менеджеров пакетов.", + "UniGetUI wouldn't have been possible without the help of the contributors. Thank you all 🥳": "UniGetUI был бы невозможен без помощи участников. Спасибо вам всем 🥳", + "UniGetUI uses the following libraries. Without them, UniGetUI wouldn't have been possible.": "В UniGetUI используются следующие библиотеки. Без них UniGetUI был бы невозможен.", + "{0} homepage": "{0} домашняя страница", + "UniGetUI has been translated to more than 40 languages thanks to the volunteer translators. Thank you 🤝": "UniGetUI был переведен более чем на 40 языков благодаря переводчикам-добровольцам. Спасибо 🤝", + "Verbose": "Подробно", + "1 - Errors": "1 - Ошибки", + "2 - Warnings": "2 - Предупреждения", + "3 - Information (less)": "3 - Информация (меньше)", + "4 - Information (more)": "4 - Информация (больше)", + "5 - information (debug)": "5 - Информация (отладка)", + "Warning": "Внимание", + "The following settings may pose a security risk, hence they are disabled by default.": "Следующие настройки могут привести к риску, поэтому они отключены по умолчанию.", + "Enable the settings below if and only if you fully understand what they do, and the implications they may have.": "Включайте настройки ниже только в том случае, если вы полностью осознаете их назначение и эффект от включения", + "The settings will list, in their descriptions, the potential security issues they may have.": "В примечаниях к настройкам будут перечислены возможные нарушения безопасности, к которым может привести их изменение.", + "The backup will include the complete list of the installed packages and their installation options. Ignored updates and skipped versions will also be saved.": "Резервная копия будет включать полный список установленных пакетов и вариантов их установки. Проигнорированные обновления и пропущенные версии также будут сохранены.", + "The backup will NOT include any binary file nor any program's saved data.": "Резервная копия НЕ будет включать в себя ни двоичные файлы, ни сохраненные данные какой-либо программы.", + "The size of the backup is estimated to be less than 1MB.": "Предполагаемый размер резервной копии составляет менее 1 МБ.", + "The backup will be performed after login.": "Резервное копирование будет выполнено после входа в систему.", + "{pcName} installed packages": "Установленные пакеты {pcName}", + "Current status: Not logged in": "Статус: вход не выполнен", + "You are logged in as {0} (@{1})": "Вы вошли как {0} (@{1})", + "Nice! Backups will be uploaded to a private gist on your account": "Резервные копии будут загружены в приватный Gist на вашем аккаунте", + "Select backup": "Выбрать резервную копию", + "Settings imported from {0}": "Настройки импортированы из {0}", + "UniGetUI Settings": "Настройки UniGetUI", + "Settings exported to {0}": "Настройки экспортированы в {0}", + "UniGetUI settings were reset": "Настройки UniGetUI были сброшены", + "Allow pre-release versions": "Разрешить обновление до предварительных версий", + "Apply": "Применить", + "For security reasons, custom command-line arguments are disabled by default. Go to UniGetUI security settings to change this.": "Из соображений безопасности пользовательские аргументы командной строки по умолчанию отключены. Перейдите в настройки безопасности UniGetUI, чтобы изменить это.", + "Go to UniGetUI security settings": "Перейти в настройки безопасности UniGetUI", + "The following options will be applied by default each time a {0} package is installed, upgraded or uninstalled.": "Следующие настройки будут применяться по умолчанию каждый раз после установки, обновления или удаления {0} пакетов.", + "Package's default": "По умолчанию для пакета", + "Install location can't be changed for {0} packages": "Расположение установки не может быть изменено для {0} пакетов", + "The local icon cache currently takes {0} MB": "Локальный кэш иконок занимает {0} Мб", + "Username": "Имя пользователя", + "Password": "Пароль", + "Credentials": "Учетные данные", + "It is not guaranteed that the provided credentials will be stored safely": "Нет гарантии, что предоставленные учетные данные будут храниться безопасно", + "Partially": "Частично", + "Package manager": "Менеджер пакетов", + "Compatible with proxy": "Совместимо с прокси", + "Compatible with authentication": "Совместимо с аутентификацией", + "Proxy compatibility table": "Таблица совместимости с прокси", + "{0} settings": "Настройки {0}", + "{0} status": "{0} статус", + "Default installation options for {0} packages": "Настройки установки по умолчанию для {0} пакетов", + "Expand version": "Расширенная версия", + "The executable file for {0} was not found": "Исполняемый файл для {0} не найден", + "{pm} is disabled": "{pm} отключен", + "Enable it to install packages from {pm}.": "Включите его для установки пакетов из {pm}.", + "{pm} is enabled and ready to go": "{pm} включен и готов к работе", + "{pm} version:": "{pm} версия:", + "{pm} was not found!": "{pm} не найден!", + "You may need to install {pm} in order to use it with UniGetUI.": "Вам может потребоваться установить {pm}, чтобы использовать его с UniGetUI.", + "Scoop Installer - UniGetUI": "Установщик Scoop - UniGetUI", + "Scoop Uninstaller - UniGetUI": "Деинсталлятор Scoop - UniGetUI", + "Clearing Scoop cache - UniGetUI": "Очистка кэша Scoop - UniGetUI", + "Restart UniGetUI to fully apply changes": "Перезапустите UniGetUI, чтобы полностью применить изменения", + "Restart UniGetUI": "Перезапустить UniGetUI", + "Manage {0} sources": "Управление источниками {0}", + "Add source": "Добавить источник", + "Add": "Добавить", + "Source name": "Имя источника", + "Source URL": "URL источника", + "Other": "Другой", + "No minimum age": "Без минимального срока", + "1 day": "1 день", + "{0} days": "{0} дни", + "Custom...": "Другое...", + "{0} minutes": "{0} минут", + "1 hour": "1 час", + "{0} hours": "{0} часы", + "1 week": "1 неделя", + "Supports release dates": "Поддерживает даты выпуска", + "Release date support per package manager": "Поддержка дат выпуска по менеджерам пакетов", + "Search for packages": "Поиск пакетов", + "Local": "Локально", + "OK": "ОК", + "Last checked: {0}": "Последняя проверка: {0}", + "{0} packages were found, {1} of which match the specified filters.": "{0, plural, one {Найден {0} пакет} few {Найдено {0} пакета} other {Найдено {0} пакетов}}, {1} из которых {1, plural, one {соответствует} other {соответствуют}} указанным фильтрам.", + "{0} selected": "{0} выбрано", + "(Last checked: {0})": "(Последняя проверка: {0})", + "All packages selected": "Все пакеты выбраны", + "Package selection cleared": "Выбор пакетов очищен", + "{0}: {1}": "{0}: {1}", + "More info": "Дополнительная информация", + "GitHub account": "Учетная запись GitHub", + "Log in with GitHub to enable cloud package backup.": "Войдите с GitHub для включения облачного резервного копирования пакета.", + "More details": "Более подробная информация", + "Log in": "Вход", + "If you have cloud backup enabled, it will be saved as a GitHub Gist on this account": "Если включено резервное копирование в облако, копия будет сохранена как GitHub Gist в этом аккаунте", + "Log out": "Выйти", + "About UniGetUI": "О UniGetUI", + "About": "О приложении", + "Third-party licenses": "Сторонние лицензии", + "Contributors": "Участники", + "Translators": "Переводчики", + "Bundle security report": "Сводный отчет по безопасности", + "The bundle contained restricted content": "Набор содержал ограниченное содержимое", + "UniGetUI – Crash Report": "UniGetUI — Отчёт о сбое", + "UniGetUI has crashed": "UniGetUI аварийно завершил работу", + "Help us fix this by sending a crash report to Devolutions. All fields below are optional.": "Помогите нам исправить эту ошибку, отправив отчёт о сбое в Devolutions. Все поля ниже являются необязательными.", + "Email (optional)": "Электронная почта (необязательно)", + "your@email.com": "your@email.com", + "Additional details (optional)": "Дополнительные сведения (необязательно)", + "Describe what you were doing when the crash occurred…": "Опишите, что вы делали, когда произошёл сбой…", + "Crash report": "Отчёт о сбое", + "Don't Send": "Не отправлять", + "Send Report": "Отправить отчёт", + "Sending…": "Отправка…", + "Unsaved changes": "Несохраненные изменения", + "You have unsaved changes in the current bundle. Do you want to discard them?": "В текущем наборе есть несохраненные изменения. Хотите их отменить?", + "Discard changes": "Отменить изменения", + "Integrity violation": "Нарушение целостности", + "UniGetUI or some of its components are missing or corrupt. It is strongly recommended to reinstall UniGetUI to adress the situation.": "UniGetUI или некоторые ее компоненты отсутствуют или повреждены. Настоятельно рекомендуется переустановить UniGetUI, чтобы исправить ситуацию.", + "• Refer to the UniGetUI Logs to get more details regarding the affected file(s)": "• Обратитесь к логам UniGetUI, чтобы получить больше информации, связанной с затронутыми файлами.", + "• Integrity checks can be disabled from the Experimental Settings": "• Проверка целостности может быть отключена в разделе экспериментальных настроек.", + "Manage shortcuts": "Управление ярлыками", + "UniGetUI has detected the following desktop shortcuts which can be removed automatically on future upgrades": "UniGetUI обнаружил следующие ярлыки на рабочем столе, которые могут быть автоматически удалены при будущих обновлениях", + "Do you really want to reset this list? This action cannot be reverted.": "Вы действительно хотите сбросить этот список? Это действие нельзя отменить.", + "Desktop shortcuts list": "Список ярлыков на рабочем столе", + "Open in explorer": "Открыть в проводнике", + "Remove from list": "Удалить из списка", + "When new shortcuts are detected, delete them automatically instead of showing this dialog.": "Когда обнаружены новые ярлыки, удалять их автоматически вместо отображения этого диалога.", + "Not right now": "Не сейчас", + "Missing dependency": "Отсутствующие зависимости", + "UniGetUI requires {0} to operate, but it was not found on your system.": "UniGetUI требуется {0} для работы, но он не найден в системе", + "Click on Install to begin the installation process. If you skip the installation, UniGetUI may not work as expected.": "Нажмите \"Установить\" для начала процесса установки. Если Вы пропустите установку, UniGetUI может не работать должным образом ", + "Alternatively, you can also install {0} by running the following command in a Windows PowerShell prompt:": "В качестве альтернативы Вы также можете установить {0} запустив следующую команду из командной строки PowerShell:", + "Install {0}": "Установить {0}", + "Do not show this dialog again for {0}": "Не показывать диалог снова для {0}", + "Please wait while {0} is being installed. A black window may show up. Please wait until it closes.": "Пожалуйста, подождите, пока выполняется установка {0}. Во время установки может появляться черное окно. Ожидайте его закрытия", + "{0} has been installed successfully.": "{0} был успешно установлен", + "Please click on \"Continue\" to continue": "Пожалуйста, нажмите «Продолжить», чтобы продолжить", + "Continue": "Продолжить", + "{0} has been installed successfully. It is recommended to restart UniGetUI to finish the installation": "{0} был успешно установлен. Рекомендуется перезапустить UniGetUI для завершения установки", + "Restart later": "Перезагрузить позже", + "An error occurred:": "Возникла ошибка:", + "Please see the Command-line Output or refer to the Operation History for further information about the issue.": "Пожалуйста, посмотрите вывод командной строки или обратитесь к истории операций для получения дополнительной информации о проблеме.", + "Retry as administrator": "Перезапустить с правами администратора", + "Retry interactively": "Перезапустить в интерактивном режиме", + "Retry skipping integrity checks": "Повторить пропуск проверки целостности", + "Installation options": "Опции установки", + "Save": "Сохранить", + "UniGetUI collects anonymous usage data with the sole purpose of understanding and improving the user experience.": "UniGetUI собирает анонимную статистику использования с единственной целью изучения и улучшения опыта использования", + "More details about the shared data and how it will be processed": "Больше информации о передаваемых данных и их обработке", + "Do you accept that UniGetUI collects and sends anonymous usage statistics, with the sole purpose of understanding and improving the user experience?": "Разрешаете ли Вы UniGetUI сбор и отправку анонимной статистики использования с целью изучения и улучшения пользовательского опыта?", + "Decline": "Отменить", + "No personal information is collected nor sent, and the collected data is anonimized, so it can't be back-tracked to you.": "Сбор и обработка персональных данных не производятся. Собранные данные анонимизированы, поэтому по ним невозможно определить Вашу личность", + "Navigation panel": "Панель навигации", + "Operations": "Операции", + "Toggle operations panel": "Переключить панель операций", + "Bulk operations": "Массовые операции", + "Retry failed": "Повторить неудачные", + "Clear successful": "Очистить успешные", + "Clear finished": "Очистить завершенные", + "Cancel all": "Отменить все", + "More": "Еще", + "Toggle navigation panel": "Переключить панель навигации", + "Minimize": "Свернуть", + "Maximize": "Развернуть", + "UniGetUI by Devolutions": "UniGetUI от Devolutions", + "UniGetUI is an application that makes managing your software easier, by providing an all-in-one graphical interface for your command-line package managers.": "UniGetUI - это приложение, которое упрощает управление вашим программным обеспечением, предоставляя универсальный графический интерфейс для ваших менеджеров пакетов командной строки.", + "Useful links": "Полезные ссылки", + "UniGetUI Homepage": "Домашняя страница UniGetUI", + "Report an issue or submit a feature request": "Сообщить о проблеме или отправить запрос на функцию", + "UniGetUI Repository": "Репозиторий UniGetUI", + "View GitHub Profile": "Посмотреть профиль GitHub", + "UniGetUI License": "Лицензия UniGetUI", + "Using UniGetUI implies the acceptation of the MIT License": "Использование UniGetUI подразумевает согласие с лицензией MIT", + "Become a translator": "Стать переводчиком", + "Go back": "Назад", + "Go forward": "Вперёд", + "Go to home page": "Перейти на главную страницу", + "Reload page": "Обновить страницу", + "View page on browser": "Просмотреть страницу в браузере", + "The built-in browser is not supported on Linux yet.": "Встроенный браузер пока не поддерживается в Linux.", + "Open in browser": "Открыть в браузере", + "Copy to clipboard": "Копировать в буфер обмена", + "Export to a file": "Экспорт в файл", + "Log level:": "Уровень журнала:", + "Reload log": "Перезагрузить журнал", + "Export log": "Экспортировать журнал", + "Text": "Текст", + "Change how operations request administrator rights": "Изменить как операции запрашивают права администратора", + "Restrictions on package operations": "Ограничения операций с пакетами", + "Restrictions on package managers": "Ограничения менеджеров пакетов", + "Restrictions when importing package bundles": "Ограничения импорта бандлов пакетов", + "Ask for administrator privileges once for each batch of operations": "Запрашивать права администратора для каждого пакета операций", + "Ask only once for administrator privileges": "Запрашивать права администратора один раз", + "Prohibit any kind of Elevation via UniGetUI Elevator or GSudo": "Запрещать любую элевацию через UniGetUI Elevator или GSudo", + "This option WILL cause issues. Any operation incapable of elevating itself WILL FAIL. Install/update/uninstall as administrator will NOT WORK.": "Настройка БУДЕТ приводить к неполадкам. Любая операция, неспособная элевации, БУДЕТ ЗАВЕРШЕНА. Установка, обновление или удаление с правами администратора НЕ БУДЕТ работать.", + "Allow custom command-line arguments": "Допускать пользовательские аргументы командной строки", + "Custom command-line arguments can change the way in which programs are installed, upgraded or uninstalled, in a way UniGetUI cannot control. Using custom command-lines can break packages. Proceed with caution.": "Пользовательские аргументы командной строки могут изменять путь, по которому установлены, обновлены или удалены программы, что UniGetUI контролировать не может. Использование пользовательских аргументов командной строки может повредить пакеты. Продолжайте на свой страх и риск.", + "Ignore custom pre-install and post-install commands when importing packages from a bundle": "Разрешить выполнение пользовательских команд до и после установки при импорте пакетов из набора", + "Pre and post install commands will be run before and after a package gets installed, upgraded or uninstalled. Be aware that they may break things unless used carefully": "Пред- и послеустановочные команды будут запущены до и после того, как установится, обновится или удалится пакет. Имейте в виду, что такие команды могут нанести вред, если используются неосторожно.", + "Allow changing the paths for package manager executables": "Разрешить изменять каталоги исполняемых файлов менеджера пакетов", + "Turning this on enables changing the executable file used to interact with package managers. While this allows finer-grained customization of your install processes, it may also be dangerous": "Включение данной настройки изменит исполняемый файл, использовавшийся для взаимодействия с менеджером пакетов. В то время как данная настройка позволяет более тонко настраивать процесс установки, она также может представлять опасность.", + "Allow importing custom command-line arguments when importing packages from a bundle": "Разрешить импорт пользовательских аргументов командной строки при импорте пакетов из бандла", + "Malformed command-line arguments can break packages, or even allow a malicious actor to gain privileged execution. Therefore, importing custom command-line arguments is disabled by default": "Неправильные аргументы командной строки могут повредить пакеты или даже позволить вредоносному коду получить привилегии на исполнение.", + "Allow importing custom pre-install and post-install commands when importing packages from a bundle": "Разрешить импорт пользовательских пред- и постустановочных команд при импорте пакетов из комплекта", + "Pre and post install commands can do very nasty things to your device, if designed to do so. It can be very dangerous to import the commands from a bundle, unless you trust the source of that package bundle": "Пред- и послеустановочные команды могут навредить вашему устройству, если они созданы для этого. Крайне опасно импортировать команды из бандла, если вы не доверяете источнику бандла пакетов.", + "Administrator rights and other dangerous settings": "Права администратора и другие чувствительные настройки", + "Package backup": "Резервная копия пакета", + "Cloud package backup": "Резервное копирование в облако", + "Local package backup": "Резервное копирование локального пакета", + "Local backup advanced options": "Расширенные настройки локального резервного копирования", + "Log in with GitHub": "Войти используя GitHub", + "Log out from GitHub": "Выйти из GitHub", + "Periodically perform a cloud backup of the installed packages": "Периодически выполнять облачное резервное копирование установленных пакетов", + "Cloud backup uses a private GitHub Gist to store a list of installed packages": "Облачное хранилище использует частный сервис GitHub Gist для хранения списка установленных пакетов", + "Perform a cloud backup now": "Выполнить резервное копирование в облако сейчас", + "Backup": "Резервная копия", + "Restore a backup from the cloud": "Восстановить резервную копию из облака", + "Begin the process to select a cloud backup and review which packages to restore": "Выбрать облачное хранилище и пакеты для восстановления", + "Periodically perform a local backup of the installed packages": "Периодически выполнять локальное резервное копирование установленных пакетов", + "Perform a local backup now": "Выполнить локальное резервное копирование сейчас", + "Change backup output directory": "Изменить каталог для резервных копий", + "Set a custom backup file name": "Задать собственное имя файла резервной копии", + "Leave empty for default": "Оставьте пустым по умолчанию", + "Add a timestamp to the backup file names": "Добавить временную метку к именам файлов резервных копий", + "Backup and Restore": "Резервная копия и восстановление", + "Enable background api (UniGetUI Widgets and Sharing, port 7058)": "Включить фоновый API (UniGetUI виджеты и возможность поделиться, порт 7058)", + "Wait for the device to be connected to the internet before attempting to do tasks that require internet connectivity.": "Ожидать подключения устройства к сети перед запуском операций, требующих подключения к сети", + "Disable the 1-minute timeout for package-related operations": "Отключить 1-минутный тайм-аут для операций, связанных с пакетами", + "Use installed GSudo instead of UniGetUI Elevator": "Использовать установленный GSudo вместо UniGetUI Elevator", + "Use a custom icon and screenshot database URL": "Использовать пользовательский значок и URL-адрес базы данных снимков экрана", + "Enable background CPU Usage optimizations (see Pull Request #3278)": "Включить фоновую оптимизацию использования процессора", + "Perform integrity checks at startup": "Выполнять проверку целостности при запуске.", + "When batch installing packages from a bundle, install also packages that are already installed": "При групповой установке пакетов из бандла также установить пакеты, которые уже установлены", + "Experimental settings and developer options": "Экспериментальные настройки и опции разработчика", + "Show UniGetUI's version and build number on the titlebar.": "Показать версию UniGetUI на панели заголовка", + "Language": "Язык", + "UniGetUI updater": "Обновления UniGetUI", + "Telemetry": "Телеметрия", + "Manage UniGetUI settings": "Управление настройками UniGetUI", + "Related settings": "Связанные настройки", + "Update UniGetUI automatically": "Обновлять UniGetUI автоматически", + "Check for updates": "Проверка обновлений", + "Install prerelease versions of UniGetUI": "Установка пред-релиз версий UniGetUI", + "Manage telemetry settings": "Управление настройками телеметрии", + "Manage": "Управление", + "Import settings from a local file": "Импорт настроек из файла", + "Import": "Импорт", + "Export settings to a local file": "Экспорт настроек в файл", + "Export": "Экспорт", + "Reset UniGetUI": "Сброс UniGetUI", + "User interface preferences": "Настройки пользовательского интерфейса", + "Application theme, startup page, package icons, clear successful installs automatically": "Тема приложения, стартовая страница, значки пакетов, автоматическая очистка успешных установок", + "General preferences": "Общие настройки", + "UniGetUI display language:": "Язык интерфейса UniGetUI:", + "System language": "Язык системы", + "Is your language missing or incomplete?": "Ваш язык отсутствует или неполный?", + "Appearance": "Внешний вид", + "UniGetUI on the background and system tray": "UniGetUI в фоновом режиме и системном трее", + "Package lists": "Списки пакетов", + "Use classic mode": "Использовать классический режим", + "Restart UniGetUI to apply this change": "Перезапустите UniGetUI, чтобы применить это изменение", + "The classic UI is disabled for beta testers": "Классический интерфейс отключён для бета-тестеров", + "Close UniGetUI to the system tray": "Закрепить UniGetUI в системном трее", + "Manage UniGetUI autostart behaviour": "Управление поведением автозапуска UniGetUI", + "Show package icons on package lists": "Показывать иконки в списке пакетов", + "Clear cache": "Очистить кэш", + "Select upgradable packages by default": "Выбирать пакеты с возможностью обновления по умолчанию", + "Light": "Светлая", + "Dark": "Темная", + "Follow system color scheme": "Системная", + "Application theme:": "Тема оформления:", + "UniGetUI startup page:": "Начальная страница UniGetUI:", + "Proxy settings": "Настройки прокси", + "Other settings": "Другие настройки", + "Connect the internet using a custom proxy": "Подключиться к интернету, используя указанный прокси", + "Please note that not all package managers may fully support this feature": "Обратите внимание, что не все менеджеры пакетов могут полностью поддерживать эту функцию", + "Proxy URL": "Прокси URL", + "Enter proxy URL here": "Введите URL прокси здесь", + "Authenticate to the proxy with a user and a password": "Аутентифицироваться на прокси-сервере с помощью пользователя и пароля", + "Internet and proxy settings": "Настройки интернета и прокси", + "Package manager preferences": "Настройки менеджеров пакетов", + "Ready": "Готов", + "Not found": "Не найден", + "Notification preferences": "Параметры уведомлений", + "Notification types": "Типы уведомлений", + "The system tray icon must be enabled in order for notifications to work": "Иконка в системном трее должна быть включена, чтобы уведомления работали", + "Enable UniGetUI notifications": "Включить уведомления UniGetUI", + "Show a notification when there are available updates": "Показывать уведомление, когда есть доступные обновления", + "Show a silent notification when an operation is running": "Показывать беззвучное уведомление, когда операция запущена", + "Show a notification when an operation fails": "Показывать уведомление в случае ошибки операции", + "Show a notification when an operation finishes successfully": "Показывать уведомление, когда операция завершена успешно", + "Concurrency and execution": "Параллелизм и выполнение", + "Automatic desktop shortcut remover": "Автоматическое удаление ярлыков на рабочем столе", + "Choose how many operations should be performed in parallel": "Выберите, сколько операций следует выполнять параллельно", + "Clear successful operations from the operation list after a 5 second delay": "Очищать успешные операции из списка операций после 5-секундной задержки", + "Download operations are not affected by this setting": "Этот параметр не влияет на операции загрузки", + "You may lose unsaved data": "Вы можете потерять несохраненные данные", + "Ask to delete desktop shortcuts created during an install or upgrade.": "Спрашивать об удалении ярлыков на рабочем столе, созданных во время установки или обновления.", + "Package update preferences": "Настройка обновлений пакетов", + "Update check frequency, automatically install updates, etc.": "Частота проверки, автоматическая установка обновлений и т.д.", + "Reduce UAC prompts, elevate installations by default, unlock certain dangerous features, etc.": "Уменьшить частоту уведомлений UAC, запускать установку с правами администратора по умолчанию, разблокировать некоторые опасные функции и т.д.", + "Package operation preferences": "Настройка операций с пакетами", + "Enable {pm}": "Включить {pm}", + "Not finding the file you are looking for? Make sure it has been added to path.": "Не можете найти необходимый файл? Убедитесь, что он был добавлен в PATH.", + "Select the executable to be used. The following list shows the executables found by UniGetUI": "Укажите исполняемый файл. В данном списке перечислены исполняемые файлы найденные UniGetUI", + "For security reasons, changing the executable file is disabled by default": "В целях безопасности изменение исполняемого файла отключено по умолчанию", + "Change this": "Изменить это", + "Copy path": "Копировать путь", + "Current executable file:": "Текущий исполняемый файл:", + "Ignore packages from {pm} when showing a notification about updates": "Игнорировать пакеты из {pm} при показе уведомления о обновлениях", + "Update security": "Безопасность обновлений", + "Use global setting": "Использовать глобальную настройку", + "Minimum age for updates": "Минимальный возраст обновлений", + "e.g. 10": "например, 10", + "Custom minimum age (days)": "Пользовательский минимальный возраст (дни)", + "{pm} does not provide release dates for its packages, so this setting will have no effect": "{pm} не предоставляет даты выпуска для своих пакетов, поэтому этот параметр не будет иметь эффекта", + "{pm} only provides release dates for some of its packages, so this setting will only apply to those packages": "{pm} предоставляет даты выпуска только для некоторых своих пакетов, поэтому этот параметр будет применяться только к этим пакетам", + "Override the global minimum update age for this package manager": "Переопределить глобальный минимальный возраст обновлений для этого менеджера пакетов", + "View {0} logs": "Посмотреть журналы {0}", + "If Python cannot be found or is not listing packages but is installed on the system, ": "Если Python не удаётся найти или он не отображает пакеты, хотя установлен в системе, ", + "Advanced options": "Расширенные настройки", + "WinGet command-line tool": "Средство командной строки WinGet", + "Choose which command-line tool UniGetUI uses for WinGet operations when the COM API is not used": "Выберите, какой инструмент командной строки UniGetUI будет использовать для операций WinGet, когда COM API не используется", + "WinGet COM API": "COM API WinGet", + "Choose whether UniGetUI can use the WinGet COM API before falling back to the command-line tool": "Выберите, может ли UniGetUI использовать COM API WinGet перед переходом к инструменту командной строки", + "Reset WinGet": "Сброс WinGet", + "This may help if no packages are listed": "Это может помочь, если в списке нет пакетов", + "Force install location parameter when updating packages with custom locations": "Принудительно использовать параметр расположения установки при обновлении пакетов с пользовательскими путями", + "Install Scoop": "Установить Scoop", + "Uninstall Scoop (and its packages)": "Удалить Scoop (и его пакеты)", + "Run cleanup and clear cache": "Выполнить очистку и очистить кэш", + "Run": "Выполнить", + "Enable Scoop cleanup on launch": "Включить очистку Scoop при запуске", + "Default vcpkg triplet": "Триплет vcpkg по умолчанию", + "Change vcpkg root location": "Изменить расположение корня vcpkg", + "Reset vcpkg root location": "Сбросить расположение корневой папки vcpkg", + "Open vcpkg root location": "Открыть расположение корневой папки vcpkg", + "Language, theme and other miscellaneous preferences": "Язык, тема и другие настройки", + "Show notifications on different events": "Показывать уведомления о различных событиях", + "Change how UniGetUI checks and installs available updates for your packages": "Изменить способ проверки и установки доступных обновлений для пакетов в UniGetUI", + "Automatically save a list of all your installed packages to easily restore them.": "Автоматически сохраняйте список всех установленных вами пакетов, чтобы легко восстановить их.", + "Enable and disable package managers, change default install options, etc.": "Включить и отключить менеджеры пакетов, изменить настройки установки по умолчанию и т.д.", + "Internet connection settings": "Настройка подключения к интернету", + "Proxy settings, etc.": "Настройки прокси и т.д.", + "Beta features and other options that shouldn't be touched": "Функции бета-версии и другие настройки, которые не стоит изменять", + "Reload sources": "Обновить источники", + "Delete source": "Удалить источник", + "Known sources": "Известные источники", + "Update checking": "Проверка обновлений", + "Automatic updates": "Автоматические обновления", + "Check for package updates periodically": "Периодически проверять наличие обновлений пакетов", + "Check for updates every:": "Интервал проверки обновлений:", + "Install available updates automatically": "Автоматически устанавливать доступные обновления", + "Do not automatically install updates when the network connection is metered": "Не устанавливать обновления автоматически при использовании лимитированного подключения", + "Do not automatically install updates when the device runs on battery": "Не устанавливать обновления автоматически, когда включён режим экономии заряда батареи", + "Do not automatically install updates when the battery saver is on": "Не устанавливать обновления автоматически, когда включён режим экономии заряда батареи", + "Only show updates that are at least the specified number of days old": "Показывать только обновления, которым не меньше указанного количества дней", + "Warn me when the installer URL host changes between the installed version and the new version (WinGet only)": "Предупреждать, если хост URL-адреса установщика изменяется между установленной и новой версией (только WinGet)", + "Change how UniGetUI handles install, update and uninstall operations.": "Изменить управление операциями установки, обновления и удаления.", + "Navigation": "Навигация", + "Check for UniGetUI updates": "Проверять наличие обновлений UniGetUI", + "Quit UniGetUI": "Выйти из UniGetUI", + "Filters": "Фильтры", + "Sources": "Источники", + "Search for packages to start": "Начните поиск пакетов", + "Select all": "Выбрать все", + "Clear selection": "Снять выделение", + "Instant search": "Искать незамедлительно", + "Distinguish between uppercase and lowercase": "Различать прописные и строчные буквы", + "Ignore special characters": "Игнорировать специальные\nсимволы", + "Search mode": "Режим поиска", + "Both": "Оба", + "Exact match": "Точное совпадение", + "Show similar packages": "Показать похожие пакеты", + "Loading": "Загрузка", + "Package": "Пакет", + "More options": "Дополнительные параметры", + "Order by:": "Сортировать по:", + "Name": "Название", + "Id": "ID", + "Ascendant": "По возрастанию", + "Descendant": "По убыванию", + "View modes": "Режимы просмотра", + "Reload": "Проверить", + "Closed": "Закрыто", + "Ascending": "По возрастанию", + "Descending": "По убыванию", + "{0}: {1}, {2}": "{0}: {1}, {2}", + "Order by": "Сортировать по", + "No results were found matching the input criteria": "Не найдено результатов, соответствующих критериям ввода", + "No packages were found": "Пакеты не найдены", + "Loading packages": "Загрузка пакетов", + "Skip integrity checks": "Пропуск проверок целостности", + "Download selected installers": "Загрузить выбранные установщики", + "Install selection": "Установить выбранные", + "Install options": "Настройки установки", + "Add selection to bundle": "Добавить выбранное в набор", + "Download installer": "Загрузить программу установки", + "Uninstall selection": "Удалить выбранные", + "Uninstall options": "Настройки удаления", + "Ignore selected packages": "Игнорировать выбранные пакеты", + "Open install location": "Открыть папку установки", + "Reinstall package": "Переустановить пакет", + "Uninstall package, then reinstall it": "Удалить пакет, затем установить его заново", + "Ignore updates for this package": "Игнорировать обновления для этого пакета", + "WinGet malfunction detected": "Обнаружена неисправность WinGet", + "It looks like WinGet is not working properly. Do you want to attempt to repair WinGet?": "Похоже, WinGet не работает должным образом. Хотите ли Вы попробовать исправить WinGet?", + "Repair WinGet": "Восстановить WinGet", + "Updates will no longer be ignored for {0}": "Обновления больше не будут игнорироваться для {0}", + "Updates are now ignored for {0}": "Обновления теперь игнорируются для {0}", + "Do not ignore updates for this package anymore": "Больше не игнорировать обновления для этого пакета", + "Add packages or open an existing package bundle": "Добавьте пакеты или откройте существующий набор пакетов", + "Add packages to start": "Добавьте пакеты для начала", + "The current bundle has no packages. Add some packages to get started": "В текущем наборе нет пакетов. Добавьте пакеты, чтобы начать", + "New": "Новое", + "Save as": "Сохранить как", + "Create .ps1 script": "Создать скрипт .ps1", + "Remove selection from bundle": "Удалить выбранное из набора", + "Skip hash checks": "Пропустить проверки хэша", + "The package bundle is not valid": "Набор пакетов недействителен", + "The bundle you are trying to load appears to be invalid. Please check the file and try again.": "Набор, который вы пытаетесь загрузить, кажется недействительным. Пожалуйста, проверьте файл и попробуйте снова.", + "Package bundle": "Набор пакетов", + "Could not create bundle": "Не удалось создать набор", + "The package bundle could not be created due to an error.": "В связи с ошибкой набор пакетов не может быть создан", + "Install script": "Скрипт установки", + "PowerShell script": "Скрипт PowerShell", + "The installation script saved to {0}": "Скрипт установки сохранен в {0}", + "An error occurred": "Произошла ошибка", + "An error occurred while attempting to create an installation script:": "Произошла ошибка при попытке создания установочного скрипта:", + "Hooray! No updates were found.": "Ура! Обновления не найдены!", + "Uninstall selected packages": "Удалить выбранные пакеты", + "Update selection": "Обновить выбранные", + "Update options": "Настройки обновления", + "Uninstall package, then update it": "Удалить пакет, затем обновить его", + "Uninstall package": "Удалить пакет", + "Skip this version": "Пропустить версию", + "Pause updates for": "Приостановить обновления для", + "User | Local": "Пользователь | Локально", + "Machine | Global": "Компьютер | Глобально", + "The default package manager for Debian/Ubuntu-based Linux distributions.
Contains: Debian/Ubuntu packages": "Менеджер пакетов по умолчанию для дистрибутивов Linux на базе Debian/Ubuntu.
Содержит: пакеты Debian/Ubuntu", + "The Rust package manager.
Contains: Rust libraries and programs written in Rust": "Пакетный менеджер Rust.
Содержит: Библиотеки и программы, написанные на Rust ", + "The classical package manager for windows. You'll find everything there.
Contains: General Software": "Классический пакетный менеджер для Windows. Там ты найдешь все.
Содержит: General Software", + "The default package manager for RHEL/Fedora-based Linux distributions.
Contains: RPM packages": "Менеджер пакетов по умолчанию для дистрибутивов Linux на базе RHEL/Fedora.
Содержит: пакеты RPM", + "A repository full of tools and executables designed with Microsoft's .NET ecosystem in mind.
Contains: .NET related tools and scripts": "Репозиторий, полный инструментов и исполняемых файлов, разработан с учетом экосистемы Microsoft .NET.
Содержит: инструменты и сценарии, связанные с .NET ", + "The universal Linux package manager for desktop applications.
Contains: Flatpak applications from configured remotes": "Универсальный менеджер пакетов Linux для настольных приложений.
Содержит: приложения Flatpak из настроенных удаленных источников", + "NuPkg (zipped manifest)": "NuPkg (заархивированный манифест)", + "The Missing Package Manager for macOS (or Linux).
Contains: Formulae, Casks": "Недостающий менеджер пакетов для macOS (или Linux).
Содержит: Formulae, Casks", + "Node JS's package manager. Full of libraries and other utilities that orbit the javascript world
Contains: Node javascript libraries and other related utilities": "Пакетный менеджер NodeJS. Наполнен библиотеками и другими утилитами, которые вращаются вокруг мира javascript
Содержит: Библиотеки Node javascript и другие связанные с ними утилиты", + "The default package manager for Arch Linux and its derivatives.
Contains: Arch Linux packages": "Менеджер пакетов по умолчанию для Arch Linux и его производных.
Содержит: пакеты Arch Linux", + "Python's library manager. Full of python libraries and other python-related utilities
Contains: Python libraries and related utilities": "Менеджер библиотек Python. Полон библиотек Python и других утилит, связанных с Python
Содержит: Библиотеки Python и связанные с ними утилиты", + "PowerShell's package manager. Find libraries and scripts to expand PowerShell capabilities
Contains: Modules, Scripts, Cmdlets": "Менеджер пакетов PowerShell. Поиск библиотек и сценариев для расширения возможностей PowerShell
Содержит: Модули, скрипты, команды", + "extracted": "извлечено", + "Scoop package": "Пакет Scoop", + "Great repository of unknown but useful utilities and other interesting packages.
Contains: Utilities, Command-line programs, General Software (extras bucket required)": "Отличное хранилище малоизвестных, но полезных утилит и других интересных пакетов.
Содержит: Утилиты, программы командной строки, общее программное обеспечение (требуется дополнительный бакет)", + "The universal Linux package manager by Canonical.
Contains: Snap packages from the Snapcraft store": "Универсальный менеджер пакетов Linux от Canonical.
Содержит: Snap-пакеты из магазина Snapcraft", + "library": "библиотека", + "feature": "функция", + "A popular C/C++ library manager. Full of C/C++ libraries and other C/C++-related utilities
Contains: C/C++ libraries and related utilities": "Популярный менеджер библиотек C/C++. Полный набор библиотек C/C++ и других утилит, связанных с C/C++
Содержит: библиотеки C/C++ и связанные с ними утилиты", + "option": "опция", + "This package cannot be installed from an elevated context.": "Этот пакет не может быть установлен из контекста с повышенными правами.", + "Please run UniGetUI as a regular user and try again.": "Пожалуйста, запустите UniGetUI как обычный пользователь и повторите попытку.", + "Please check the installation options for this package and try again": "Пожалуйста, проверьте параметры установки этого пакета и повторите попытку", + "Microsoft's official package manager. Full of well-known and verified packages
Contains: General Software, Microsoft Store apps": "Официальный пакетный менеджер Microsoft. Полон хорошо известных и проверенных пакетов
Содержит: Общее программное обеспечение, приложения Microsoft Store", + "Local PC": "Этот ПК", + "Android Subsystem": "Подсистема Android", + "Operation on queue (position {0})...": "Операция в очереди (позиция {0})...", + "Click here for more details": "Нажмите здесь для получения подробностей", + "Operation canceled by user": "Операция отменена пользователем", + "Running PreOperation ({0}/{1})...": "Выполняется PreOperation ({0}/{1})...", + "PreOperation {0} out of {1} failed, and was tagged as necessary. Aborting...": "PreOperation {0} из {1} завершилась неудачей и была помечена как обязательная. Прерывание...", + "PreOperation {0} out of {1} finished with result {2}": "PreOperation {0} из {1} завершилась с результатом {2}", + "Starting operation...": "Запуск операции...", + "Running PostOperation ({0}/{1})...": "Выполняется PostOperation ({0}/{1})...", + "PostOperation {0} out of {1} failed, and was tagged as necessary. Aborting...": "PostOperation {0} из {1} завершилась неудачей и была помечена как обязательная. Прерывание...", + "PostOperation {0} out of {1} finished with result {2}": "PostOperation {0} из {1} завершилась с результатом {2}", + "{package} installer download": "{package} установщик загружается", + "{0} installer is being downloaded": "{0} установщиков было загружено", + "Download succeeded": "Загрузка прошла успешно", + "{package} installer was downloaded successfully": "{package} установщик был успешно загружен", + "Download failed": "Ошибка загрузки", + "{package} installer could not be downloaded": "{package} установщик не может быть загружен", + "{package} Installation": "Установка {package}", + "{0} is being installed": "{0} был установлен", + "Installation succeeded": "Установка выполнена успешно", + "{package} was installed successfully": "{package} был успешно установлен", + "Installation failed": "Ошибка установки", + "{package} could not be installed": "Не удалось установить {package}", + "{package} Update": "Обновление {package}", + "Update succeeded": "Обновление прошло успешно", + "{package} was updated successfully": "{package} был успешно обновлен", + "Update failed": "Ошибка обновления", + "{package} could not be updated": "Не удалось обновить {package}", + "{package} Uninstall": "Удаление {package}", + "{0} is being uninstalled": "{0} был удален", + "Uninstall succeeded": "Удаление прошло успешно", + "{package} was uninstalled successfully": "{package} был успешно удален", + "Uninstall failed": "Ошибка удаления", + "{package} could not be uninstalled": "Не удалось удалить {package}", + "Adding source {source}": "Добавление источника {source}", + "Adding source {source} to {manager}": "Добавление источника {source} в {manager}", + "Source added successfully": "Источник добавлен успешно", + "The source {source} was added to {manager} successfully": "Источник {source} был успешно добавлен в {manager}", + "Could not add source": "Невозможно добавить источник", + "Could not add source {source} to {manager}": "Не удалось добавить источник {source} в {manager}", + "Removing source {source}": "Удаление источника {source}", + "Removing source {source} from {manager}": "Удаление источника {source} из {manager}", + "Source removed successfully": "Источник удален успешно", + "The source {source} was removed from {manager} successfully": "Источник {source} был успешно удален из {manager}", + "Could not remove source": "Невозможно удалить источник", + "Could not remove source {source} from {manager}": "Не удалось удалить источник {source} из {manager}", + "The package manager \"{0}\" was not found": "Пакетный менеджер \"{0}\" не найден", + "The package manager \"{0}\" is disabled": "Пакетный менеджер \"{0}\" отключен", + "There is an error with the configuration of the package manager \"{0}\"": "Произошла ошибка с конфигурацией менеджера пакетов \"{0}\"", + "The package \"{0}\" was not found on the package manager \"{1}\"": "Пакет \"{0}\" не найден в пакетном менеджере \"{1}\"", + "{0} is disabled": "{0} отключён", + "{0} weeks": "{0} недель", + "1 month": "1 месяц", + "{0} months": "{0} месяцев", + "Something went wrong": "Что-то пошло не так", + "An interal error occurred. Please view the log for further details.": "Внутренняя ошибка. Пожалуйста, ознакомьтесь с журналом для получения более подробной информации.", + "No applicable installer was found for the package {0}": "Не найден подходящий установщик для пакета {0}", + "Integrity checks will not be performed during this operation": "Проверка целостности не будет выполнена во время этой операции", + "This is not recommended.": "Это не рекомендуется", + "Run now": "Запустить сейчас", + "Run next": "Запустить следующим", + "Run last": "Запустить последним", + "Show in explorer": "Показать в Проводнике", + "Checked": "Отмечено", + "Unchecked": "Не отмечено", + "This package is already installed": "Этот пакет уже установлен", + "This package can be upgraded to version {0}": "Пакет может быть обновлен до версии {0}", + "Updates for this package are ignored": "Обновления этих пакетов игнорируются", + "This package is being processed": "Этот пакет находится в стадии обработки", + "This package is not available": "Пакет недоступен", + "Select the source you want to add:": "Выберите источник, который вы хотите добавить:", + "Source name:": "Название источника:", + "Source URL:": "URL-адрес источника:", + "An error occurred when adding the source: ": "Ошибка при добавлении источника:", + "Package management made easy": "Управление пакетами стало легким", + "version {0}": "версия {0}", + "[RAN AS ADMINISTRATOR]": "ЗАПУЩЕН ОТ ИМЕНИ АДМИНИСТРАТОРА", + "Portable mode": "Портативный режим", + "DEBUG BUILD": "СБОРКА ДЛЯ ОТЛАДКИ", + "Here you can change UniGetUI's behaviour regarding the following shortcuts. Checking a shortcut will make UniGetUI delete it if if gets created on a future upgrade. Unchecking it will keep the shortcut intact": "Здесь вы можете изменить поведение UniGetUI в отношении следующих сочетаний клавиш. Проверка ярлыка приведет к тому, что UniGetUI удалит его, если он будет создан при будущем обновлении. Если снять флажок, ярлык останется нетронутым", + "Manual scan": "Ручное сканирование", + "Existing shortcuts on your desktop will be scanned, and you will need to pick which ones to keep and which ones to remove.": "Существующие ярлыки на вашем рабочем столе будут отсканированы, и вам нужно будет выбрать, какие из них оставить, а какие удалить.", + "Delete?": "Удалить?", + "I understand": "Я понимаю", + "Chocolatey setup changed": "Конфигурация Chocolatey изменена", + "UniGetUI no longer includes its own private Chocolatey installation. A legacy UniGetUI-managed Chocolatey installation was detected for this user profile, but system Chocolatey was not found. Chocolatey will stay unavailable in UniGetUI until Chocolatey is installed on the system and UniGetUI is restarted. Applications previously installed through UniGetUI's bundled Chocolatey may still appear under other sources such as Local PC or WinGet.": "UniGetUI больше не включает собственную встроенную установку Chocolatey. Для данного профиля пользователя обнаружена устаревшая установка Chocolatey, управлявшаяся UniGetUI, но системный Chocolatey не найден. Chocolatey останется недоступным в UniGetUI, пока Chocolatey не будет установлен в системе и UniGetUI не будет перезапущен. Приложения, ранее установленные через встроенный Chocolatey в UniGetUI, могут по-прежнему отображаться в других источниках, таких как Локальный ПК или WinGet.", + "NOTE: This troubleshooter can be disabled from UniGetUI Settings, on the WinGet section": "ПРИМЕЧАНИЕ: Это средство устранения неполадок можно отключить в настройках UniGetUI в разделе WinGet", + "Restart": "Рестарт", + "Are you sure you want to delete all shortcuts?": "Вы уверены, что хотите удалить все ярлыки?", + "Any new shorcuts created during an install or an update operation will be deleted automatically, instead of showing a confirmation prompt the first time they are detected.": "Все новые ярлыки, созданные во время установки или обновления, будут автоматически удалены, вместо того чтобы показывать запрос на подтверждение при их первом обнаружении.", + "Any shorcuts created or modified outside of UniGetUI will be ignored. You will be able to add them via the {0} button.": "Все ярлыки, созданные или измененные вне UniGetUI, будут проигнорированы. Вы сможете добавить их через кнопку {0}.", + "Are you really sure you want to enable this feature?": "Вы действительно уверены, что хотите включить эту функцию?", + "No new shortcuts were found during the scan.": "Во время сканирования не было обнаружено новых ярлыков.", + "How to add packages to a bundle": "Как добавить пакеты в набор", + "In order to add packages to a bundle, you will need to: ": "Чтобы добавить пакеты в набор, вам нужно:", + "1. Navigate to the \"{0}\" or \"{1}\" page.": "1. Перейдите на страницу \"{0}\" или \"{1}\".", + "2. Locate the package(s) you want to add to the bundle, and select their leftmost checkbox.": "2. Найдите пакет(ы), которые вы хотите добавить в набор, и выберите самый левый флажок.", + "3. When the packages you want to add to the bundle are selected, find and click the option \"{0}\" on the toolbar.": "3. Когда пакеты, которые вы хотите добавить в набор, выбраны, найдите и нажмите на опцию \"{0}\" на панели инструментов.", + "4. Your packages will have been added to the bundle. You can continue adding packages, or export the bundle.": "4. Ваши пакеты будут добавлены в набор. Вы можете продолжить добавление пакетов или экспортировать набор.", + "Which backup do you want to open?": "Какую резервную копию вы хотите открыть?", + "Select the backup you want to open. Later, you will be able to review which packages you want to install.": "Выберите резервную копию для открытия. Позже вы сможете ознакомиться с пакетами для установки.", + "There are ongoing operations. Quitting UniGetUI may cause them to fail. Do you want to continue?": "Операции продолжаются. Выход из UniGetUI может привести к их сбою. Вы хотите продолжить?", + "UniGetUI or some of its components are missing or corrupt.": "UniGetUI или некоторые ее компоненты утеряны или повреждены.", + "It is strongly recommended to reinstall UniGetUI to adress the situation.": "Настоятельно рекомендуется переустановить UniGetUI, чтобы исправить ситуацию.", + "Refer to the UniGetUI Logs to get more details regarding the affected file(s)": "Обратитесь к логам UniGetUI, чтобы получить больше информации, связанной с затронутыми файлами.", + "Integrity checks can be disabled from the Experimental Settings": "Проверка целостности может быть отключена в разделе экспериментальных настроек.", + "Repair UniGetUI": "Восстановить UniGetUI", + "Live output": "Вывод в реальном времени", + "This package bundle had some settings that are potentially dangerous, and may be ignored by default.": "Этот бандл пакетов имеет потенциально опасные настройки и может быть проигнорирован по умолчанию.", + "Entries that show in YELLOW will be IGNORED.": "Записи, показанные ЖЕЛТЫМ цветом, будут ПРОИГНОРИРОВАНЫ.", + "Entries that show in RED will be IMPORTED.": "Позиции, помеченные КРАСНЫМ цветом, будут ИМПОРТИРОВАНЫ", + "You can change this behavior on UniGetUI security settings.": "Вы можете изменить такое поведение в настройках безопасности UniGetUI.", + "Open UniGetUI security settings": "Открыть настройки безопасности UniGetUI", + "Should you modify the security settings, you will need to open the bundle again for the changes to take effect.": "Если вы измените настройки безопасности, необходимо будет открыть бандл снова, чтобы изменения вступили в силу.", + "Details of the report:": "Детали отчета:", + "Are you sure you want to create a new package bundle? ": "Вы уверены, что хотите создать новый набор пакетов?", + "Any unsaved changes will be lost": "Любые несохраненные изменения будут потеряны", + "Warning!": "Внимание!", + "For security reasons, custom command-line arguments are disabled by default. Go to UniGetUI security settings to change this. ": "В целях безопасности пользовательские аргументы командной строки отключены по умолчанию. Включить их можно в разделе настроек UniGetUI.", + "Change default options": "Изменить настройки по умолчанию", + "Ignore future updates for this package": "Игнорировать будущие обновления этого пакета", + "For security reasons, pre-operation and post-operation scripts are disabled by default. Go to UniGetUI security settings to change this. ": "В целях безопасности предварительные и завершающие скрипты отключены по умолчанию. Включить их можно в разделе настроек UnitGetUI.", + "You can define the commands that will be run before or after this package is installed, updated or uninstalled. They will be run on a command prompt, so CMD scripts will work here.": "Вы можете настроить, какие команды будут выполнять до или после установки, обновления или удаления пакета. Они будут запускаться в командной строке, поэтому CMD-скрипты будут работать.", + "Change this and unlock": "Изменить это и разблокировать", + "{0} Install options are currently locked because {0} follows the default install options.": "{0} Настройки установки в настоящее время заблокированы, т.к. {0} следуют настройкам установки по умолчанию.", + "Unset or unknown": "Отключено или неизвестно", + "This package has no screenshots or is missing the icon? Contrbute to UniGetUI by adding the missing icons and screenshots to our open, public database.": "У этого пакета нет скриншотов или отсутствует иконка? Внесите свой вклад в UniGetUI, добавив недостающие иконки и скриншоты в нашу открытую, общедоступную базу данных.", + "Become a contributor": "Стать участником", + "Update to {0} available": "Обновление для {0} найдено", + "Reinstall": "Переустановить", + "Installer not available": "Установщик недоступен", + "Version:": "Версия:", + "UniGetUI Version {0}": "UniGetUI Версия {0}", + "Performing backup, please wait...": "Создается резервная копия, пожалуйста, подождите...", + "An error occurred while logging in: ": "Ошибка при авторизации:", + "Fetching available backups...": "Получение доступных резервных копий...", + "Done!": "Готово!", + "The cloud backup has been loaded successfully.": "Облачная резервная копия была загружена успешно.", + "An error occurred while loading a backup: ": "Ошибка при загрузке резервной копии:", + "Backing up packages to GitHub Gist...": "Резервное копирование пакетов в сервис GitHub Gist...", + "Backup Successful": "Резервное копирование завершено успешно", + "The cloud backup completed successfully.": "Облачное резервное копирование завершено успешно.", + "Could not back up packages to GitHub Gist: ": "Ошибка резервного копирования пакетов на сервис GitHub Gist:", + "It is not guaranteed that the provided credentials will be stored safely, so you may as well not use the credentials of your bank account": "Не гарантированно, что предоставленные учётные данные будут храниться в безопасности, поэтому лучше не использовать учётные данные от вашего банковского счёта.", + "Enable the automatic WinGet troubleshooter": "Включить автоматическое средство устранения неполадок WinGet", + "Add updates that fail with a 'no applicable update found' to the ignored updates list": "Добавить обновления, которые завершаются ошибкой с сообщением \"не найдено подходящего обновления\", в список игнорируемых обновлений", + "Invalid selection": "Недопустимый выбор", + "No package was selected": "Не был выбран ни один пакет", + "More than 1 package was selected": "Было выбрано более одного пакета", + "List": "Список", + "Grid": "Сетка", + "Icons": "Иконки", + "\"{0}\" is a local package and does not have available details": "\"{0}\" является локальным пакетом, и сведения о нём недоступны", + "\"{0}\" is a local package and is not compatible with this feature": "\"{0}\" является локальным пакетом и не поддерживает эту функцию", + "Add packages to bundle": "Добавить пакеты в набор", + "Preparing packages, please wait...": "Подготовка пакетов, пожалуйста, подождите...", + "Loading packages, please wait...": "Загрузка пакетов, пожалуйста, подождите...", + "Saving packages, please wait...": "Сохранение пакетов, пожалуйста, подождите...", + "The bundle was created successfully on {0}": "Набор был успешно создан в {0}", + "User profile": "Профиль пользователя", + "Error": "Ошибка", + "Log in failed: ": "Ошибка входа:", + "Log out failed: ": "Ошибка выхода:", + "Package backup settings": "Настройки резервного копирования пакета", + "Package managers": "Менеджеры пакетов", + "Manage UniGetUI autostart behaviour from the Settings app": "Управление автозапуском UniGetUI", + "Choose how many operations shoulds be performed in parallel": "Выберите, сколько операций должно выполняться параллельно", + "Something went wrong while launching the updater.": "Что-то пошло не так при запуске программы обновления.", + "Please try again later": "Пожалуйста, попробуйте ещё раз позже", + "Show the release notes after UniGetUI is updated": "Показывать примечания к выпуску после обновления UniGetUI" +} diff --git a/src/Languages/lang_sa.json b/src/Languages/lang_sa.json new file mode 100644 index 0000000..18b115c --- /dev/null +++ b/src/Languages/lang_sa.json @@ -0,0 +1,851 @@ +{ + "{0} of {1} operations completed": "{1} इत्येतेषु {0} कार्याणि सम्पन्नानि", + "{0} is now {1}": "{0} अधुना {1} अस्ति", + "Enabled": "सक्रियम्", + "Disabled": "निष्क्रियीकृतम्", + "Privacy": "गोपनीयता", + "Hide my username from the logs": "logs मध्ये मम उपयोक्तृनाम गोपयतु", + "Replaces your username with **** in the logs. Restart UniGetUI to also hide it from already-recorded entries.": "logs मध्ये भवतः उपयोक्तृनाम **** इत्यनेन प्रतिस्थापयति। पूर्वलिखितप्रविष्टिषु अपि तत् गोपयितुं UniGetUI पुनः आरभताम्।", + "Your last update attempt did not complete.": "भवतः अन्तिमः अद्यतन-प्रयासः पूर्णः न अभवत्।", + "UniGetUI could not confirm whether the update succeeded. Open the log to see what happened.": "अद्यतनं सफलम् अभवत् वा इति UniGetUI निश्चितुं न अशक्नोत्। किं जातम् इति द्रष्टुं log-पत्रम् उद्घाटय।", + "View log": "log-पत्रं पश्य", + "The installer reported success but did not restart UniGetUI.": "स्थापकेन सफलता सूचिता, किन्तु UniGetUI पुनः न आरब्धम्।", + "The installer failed to initialize.": "स्थापकः आरम्भितुं विफलः।", + "Setup was canceled before installation began.": "स्थापनारम्भात् पूर्वं setup रद्दीकृतम्।", + "A fatal error occurred during the preparation phase.": "सज्जीकरण-चरणे घातकः दोषः अभवत्।", + "A fatal error occurred during installation.": "स्थापनकाले घातकः दोषः अभवत्।", + "Installation was canceled while in progress.": "स्थापनं प्रचलति स्म तदा रद्दीकृतम्।", + "The installer was terminated by another process.": "अन्येन process इत्यनेन स्थापकः समाप्तः।", + "The preparation phase determined the installation cannot proceed.": "सज्जीकरण-चरणेन निर्धारितं यत् स्थापनं अग्रे न गन्तुं शक्नोति।", + "The installer could not start. UniGetUI may already be running, or you do not have permission to install.": "स्थापकः आरभितुं न अशक्नोत्। UniGetUI पूर्वमेव चलति स्यात्, अथवा स्थापयितुं भवतः अधिकारः नास्ति।", + "Unexpected installer error.": "अनपेक्षितः स्थापक-दोषः।", + "We are checking for updates.": "वयं अद्यतनानि परीक्षामहे।", + "Please wait": "कृपया प्रतीक्षस्व", + "Great! You are on the latest version.": "सुन्दरम्! भवान् नवीनतम-संस्करणे अस्ति।", + "There are no new UniGetUI versions to be installed": "स्थापनार्थं नूतनानि UniGetUI संस्करणानि न सन्ति", + "UniGetUI version {0} is being downloaded.": "UniGetUI संस्करणं {0} अवतार्यते।", + "This may take a minute or two": "एतत् एकं वा द्वौ निमिषौ वा गृह्णीयात्", + "The installer authenticity could not be verified.": "installer इत्यस्य प्रामाणिकता सत्यापयितुं न शक्यत।", + "The update process has been aborted.": "अद्यतन-प्रक्रिया निरस्ता।", + "Auto-update is not yet available on this platform.": "अस्मिन् platform इत्यस्मिन् स्वयम्-अद्यतनम् अद्यापि उपलब्धं नास्ति।", + "Please update UniGetUI manually.": "कृपया UniGetUI हस्तेन अद्यतनयतु।", + "An error occurred when checking for updates: ": "अद्यतनेषु परीक्ष्यमाणेषु दोषः अभवत्", + "The updater could not be launched.": "अद्यतनकर्ता आरम्भयितुं न अशक्यत।", + "The operating system did not start the installer process.": "परिचालन-तन्त्रेण स्थापक-process आरब्धः न।", + "UniGetUI is being updated...": "UniGetUI अद्यतन्यते...", + "Update installed.": "अद्यतनं स्थापितम्।", + "UniGetUI was updated successfully, but this running copy was not replaced. This usually means you are running a development build. Close this copy and start the newly-installed version to finish.": "UniGetUI सफलतया अद्यतनितम्, किन्तु एषा चलन्ती प्रतिलिपिः प्रतिस्थापिता न। सामान्यतः अस्य अर्थः भवति यत् भवान् development build चालयति। समाप्त्यर्थं एतां प्रतिलिपिं पिधाय नवस्थापितं संस्करणम् आरभत।", + "The update could not be applied.": "अद्यतनं प्रयोक्तुं न अशक्यत।", + "Installer exit code {0}: {1}": "स्थापकस्य निर्गम-सङ्केतः {0}: {1}", + "Update cancelled.": "अद्यतनं रद्दीकृतम्।", + "Authentication was cancelled.": "प्रमाणीकरणं रद्दीकृतम्।", + "Installer exit code {0}": "स्थापकस्य निर्गम-सङ्केतः {0}", + "Operation in progress": "operation प्रचलति", + "Please wait...": "कृपया प्रतीक्षस्व...", + "Success!": "सफलम्!", + "Failed": "विफलम्", + "An error occurred while processing this package": "एतस्य पुटकस्य प्रक्रियायां दोषः अभवत्", + "Installer": "स्थापकः", + "Executable": "निष्पाद्य-सञ्चिका", + "MSI": "MSI", + "Compressed file": "सङ्कुचित-सञ्चिका", + "MSIX": "MSIX", + "WinGet was repaired successfully": "WinGet सफलतया मरम्मितः", + "It is recommended to restart UniGetUI after WinGet has been repaired": "WinGet मरम्मतस्य अनन्तरं UniGetUI पुनरारभितुं अनुशंस्यते", + "WinGet could not be repaired": "WinGet मरम्मतुं न शक्यत", + "An unexpected issue occurred while attempting to repair WinGet. Please try again later": "WinGet दुरुस्तीकरणे प्रयतमानस्य अप्रत्याशिता समस्या अभवत्। कृपया पश्चात् पुनः प्रयतध्वम्", + "Log in to enable cloud backup": "cloud backup सक्रियीकरणाय प्रविशतु", + "Backup Failed": "backup विफलम्", + "Downloading backup...": "backup download क्रियते...", + "An update was found!": "अद्यतनं लब्धम्!", + "{0} can be updated to version {1}": "{0} संस्करणं {1} पर्यन्तम् अद्यतनीयम् अस्ति", + "Updates found!": "अद्यतनानि लब्धानि!", + "{0} packages can be updated": "{0} packages अद्यतनीयानि सन्ति", + "{0} is being updated to version {1}": "{0} संस्करणं {1} पर्यन्तम् अद्यतन्यते", + "{0} packages are being updated": "{0} packages अद्यतन्यन्ते", + "You have currently version {0} installed": "अधुना संस्करणं {0} स्थापितम् अस्ति", + "Desktop shortcut created": "Desktop shortcut निर्मितम्", + "UniGetUI has detected a new desktop shortcut that can be deleted automatically.": "UniGetUI इत्यनेन नूतनः desktop shortcut ज्ञातः यः स्वयमेव अपाकर्तुं शक्यते।", + "{0} desktop shortcuts created": "{0} desktop shortcuts निर्मिताः", + "UniGetUI has detected {0} new desktop shortcuts that can be deleted automatically.": "UniGetUI इत्यनेन {0} नूतनाः desktop shortcuts ज्ञाताः ये स्वयमेव अपाकर्तुं शक्यन्ते।", + "Attention required": "सावधानता आवश्यकम्", + "Restart required": "पुनरारम्भः अपेक्षितः", + "1 update is available": "1 अद्यतनं उपलब्धम् अस्ति", + "{0} updates are available": "{0} अद्यतनानि उपलब्धानि", + "Everything is up to date": "सर्वम् अद्यतनम् अस्ति", + "Discover Packages": "packages अन्वेषयतु", + "Available Updates": "उपलब्धानि अद्यतनानि", + "Installed Packages": "स्थापित-packages", + "UniGetUI Version {0} by Devolutions": "Devolutions-द्वारा UniGetUI संस्करणम् {0}", + "Show UniGetUI": "UniGetUI दर्शय", + "Quit": "निर्गच्छ", + "Are you sure?": "किम् त्वं निश्चितः?", + "Do you really want to uninstall {0}?": "{0} uninstall कर्तुम् एव इच्छसि किम्?", + "Do you really want to uninstall the following {0} packages?": "निम्नलिखित {0} packages uninstall कर्तुम् एव इच्छसि किम्?", + "No": "न", + "Yes": "आम्", + "Partial": "आंशिकम्", + "View on UniGetUI": "UniGetUI मध्ये पश्य", + "Update": "अद्यतय", + "Open UniGetUI": "UniGetUI उद्घाटय", + "Update all": "सर्वम् अद्यतय", + "Update now": "अधुना अद्यतय", + "Installer host changed since the installed version.\n": "स्थापित-संस्करणात् परं स्थापक-host परिवर्तितः।\n", + "This package is on the queue": "अयं package queue मध्ये अस्ति", + "installing": "स्थाप्यते", + "updating": "अद्यतन्यते", + "uninstalling": "अनस्थाप्यते", + "installed": "स्थापितम्", + "Retry": "पुनः प्रयतस्व", + "Install": "स्थापयतु", + "Uninstall": "अनस्थापयतु", + "Open": "उद्घाटय", + "Operation profile:": "operation-profile:", + "Follow the default options when installing, upgrading or uninstalling this package": "अस्य package इत्यस्य install, upgrade, अथवा uninstall काले default options अनुसरतु", + "The following settings will be applied each time this package is installed, updated or removed.": "अयं package यदा स्थाप्यते, अद्यतन्यते, अथवा अपाक्रियते तदा तदा निम्नलिखिताः settings प्रयुज्यन्ते।", + "Version to install:": "स्थापनार्थं संस्करणम्:", + "Architecture to install:": "स्थापनीयम् architecture:", + "Installation scope:": "स्थापन-परिधिः:", + "Install location:": "स्थापन-स्थानम्:", + "Select": "चयनय", + "Reset": "पुनर्स्थापय", + "Custom install arguments:": "custom install arguments:", + "Custom update arguments:": "custom update arguments:", + "Custom uninstall arguments:": "custom uninstall arguments:", + "Pre-install command:": "स्थापनपूर्व-command:", + "Post-install command:": "स्थापनोत्तर-command:", + "Abort install if pre-install command fails": "pre-install आदेशः विफलः चेत् स्थापनं निरस्यतु", + "Pre-update command:": "अद्यतनपूर्व-command:", + "Post-update command:": "अद्यतनोत्तर-command:", + "Abort update if pre-update command fails": "pre-update आदेशः विफलः चेत् अद्यतनं निरस्यतु", + "Pre-uninstall command:": "अनस्थापनपूर्व-command:", + "Post-uninstall command:": "अनस्थापनोत्तर-command:", + "Abort uninstall if pre-uninstall command fails": "pre-uninstall आदेशः विफलः चेत् अनस्थापनं निरस्यतु", + "Command-line to run:": "चालयितव्यं command-line:", + "Save and close": "संगृह्य पिधाय", + "General": "सामान्यम्", + "Architecture & Location": "संरचना तथा स्थानम्", + "Command-line": "आदेश-पङ्क्तिः", + "Close apps": "अनुप्रयोगान् पिधाय", + "Pre/Post install": "पूर्व/पश्चात्-स्थापनम्", + "Select the processes that should be closed before this package is installed, updated or uninstalled.": "अस्य package स्थापना-अद्यतन-अनस्थापनपूर्वं ये processes पिधातव्याः ते चयनय।", + "Write here the process names here, separated by commas (,)": "अत्र process-names लिख, अल्पविरामैः (,) पृथक्कृताः", + "Try to kill the processes that refuse to close when requested to": "येषां processes पिधानार्थं अनुरोधे सति अपि न पिधीयन्ते तान् समाप्तुं प्रयतस्व", + "Run as admin": "admin रूपेण चालय", + "Interactive installation": "interactive स्थापना", + "Skip hash check": "hash check त्यज", + "Uninstall previous versions when updated": "अद्यतनकाले पूर्व-संस्करणानि अनस्थापय", + "Skip minor updates for this package": "अस्य package कृते लघ्व-अद्यतनानि त्यज", + "Automatically update this package": "एतत् पुटकं स्वयमेव अद्यतनयतु", + "{0} installation options": "{0} स्थापना-विकल्पाः", + "Latest": "नवीनतमम्", + "PreRelease": "पूर्व-प्रकाशनम्", + "Default": "मूलनिर्धारितम्", + "Manage ignored updates": "उपेक्षित-अद्यतनानि प्रबन्धय", + "The packages listed here won't be taken in account when checking for updates. Double-click them or click the button on their right to stop ignoring their updates.": "अत्र सूचीकृताः packages अद्यतन-परीक्षणकाले गणनायां न गृहीष्यन्ते। तेषां अद्यतनानाम् उपेक्षां निरोद्धुं तेषु double-click कुरु अथवा तेषां दक्षिणभागस्थं button क्लिक् कुरु।", + "Reset list": "सूचीं पुनर्स्थापय", + "Do you really want to reset the ignored updates list? This action cannot be reverted": "भवान् उपेक्षित-अद्यतन-सूचीं पुनर्स्थापयितुम् इच्छति किम्? एषा क्रिया प्रत्यावर्तयितुं न शक्यते", + "No ignored updates": "उपेक्षित-अद्यतनानि न सन्ति", + "Package Name": "पैकेज्-नाम", + "Package ID": "पैकेज् ID", + "Ignored version": "उपेक्षित-संस्करणम्", + "New version": "नूतनं संस्करणम्", + "Source": "स्रोतः", + "All versions": "सर्वाणि संस्करणानि", + "Unknown": "अज्ञातम्", + "Up to date": "अद्यतनम् अस्ति", + "Package {name} from {manager}": "{manager} तः पैकेज् {name}", + "Remove {0} from ignored updates": "{0} उपेक्षित-अद्यतनेभ्यः अपाकुरु", + "Cancel": "रद्दय", + "Administrator privileges": "प्रशासकाधिकाराः", + "This operation is running with administrator privileges.": "अयं operation administrator privileges सह चलति।", + "Interactive operation": "interactive क्रिया", + "This operation is running interactively.": "अयं operation interactive रूपेण चलति।", + "You will likely need to interact with the installer.": "installer सह परस्परं कार्यं कर्तुं सम्भाव्यं आवश्यकं भविष्यति।", + "Integrity checks skipped": "Integrity checks लङ्घितानि", + "Integrity checks will not be performed during this operation.": "अस्यां क्रियायां अखण्डता-परीक्षणानि न करिष्यन्ते।", + "Proceed at your own risk.": "स्वीय-जोखिमेन अग्रे गच्छ।", + "Close": "समापयतु", + "Loading...": "load क्रियते...", + "Installer SHA256": "स्थापक SHA256", + "Homepage": "मुखपृष्ठम्", + "Author": "लेखकः", + "Publisher": "प्रकाशकः", + "License": "अनुज्ञापत्रम्", + "Manifest": "manifest", + "Installer Type": "Installer प्रकारः", + "Size": "आकारः", + "Installer URL": "स्थापक URL", + "Last updated:": "अन्तिमवारम् अद्यतनम्:", + "Release notes URL": "प्रकाशन-टिप्पणी URL", + "Package details": "पैकेज्-विवरणानि", + "Dependencies:": "आश्रिततत्त्वानि:", + "Release notes": "प्रकाशन-टिप्पण्यः", + "Screenshots": "चित्रपट-चित्राणि", + "This package has no screenshots or is missing the icon? Contribute to UniGetUI by adding the missing icons and screenshots to our open, public database.": "अस्मिन् पैकेज् मध्ये चित्रपट-चित्राणि न सन्ति अथवा चिह्नं लुप्तम् अस्ति किम्? अस्माकं मुक्ते सार्वजनिके दत्तकोशे लुप्तानि चिह्नानि चित्रपट-चित्राणि च योजयित्वा UniGetUI मध्ये योगदानं कुरुत।", + "Version": "संस्करणम्", + "Install as administrator": "administrator रूपेण स्थापयतु", + "Update to version {0}": "संस्करणं {0} पर्यन्तम् अद्यतय", + "Installed Version": "स्थापित-संस्करणम्", + "Update as administrator": "administrator रूपेण अद्यतय", + "Interactive update": "परस्परक्रियात्मक update", + "Uninstall as administrator": "administrator रूपेण अनस्थापय", + "Interactive uninstall": "परस्परक्रियात्मक uninstall", + "Uninstall and remove data": "अनस्थापय तथा दत्तांशम् अपाकुरु", + "Not available": "उपलब्धं नास्ति", + "Installer SHA512": "स्थापक SHA512", + "Unknown size": "अज्ञात-आकारः", + "No dependencies specified": "निर्भरताः निर्दिष्टाः न सन्ति", + "mandatory": "अनिवार्यम्", + "optional": "वैकल्पिकम्", + "UniGetUI {0} is ready to be installed.": "UniGetUI {0} स्थापयितुं सज्जम् अस्ति।", + "The update process will start after closing UniGetUI": "UniGetUI पिधाय अनन्तरं अद्यतन-प्रक्रिया आरभ्यते", + "UniGetUI has been ran as administrator, which is not recommended. When running UniGetUI as administrator, EVERY operation launched from UniGetUI will have administrator privileges. You can still use the program, but we highly recommend not running UniGetUI with administrator privileges.": "UniGetUI प्रशासकरूपेण चालितम् अस्ति, यत् अनुशंसितं नास्ति। UniGetUI प्रशासकरूपेण चालिते सति UniGetUI तः आरब्धाः सर्वाः क्रियाः प्रशासकाधिकारैः सह भविष्यन्ति। भवन्तः कार्यक्रमम् उपयोक्तुं शक्नुवन्ति, किन्तु वयं दृढतया अनुशंसामः यत् UniGetUI प्रशासकाधिकारैः सह न चालयेत्।", + "Share anonymous usage data": "अनामिक-उपयोग-दत्तांशं साम्भाजय", + "UniGetUI collects anonymous usage data in order to improve the user experience.": "उपयोक्तृ-अनुभवं सुधारयितुं UniGetUI अनामिक-उपयोग-दत्तांशं संगृह्णाति।", + "Accept": "स्वीकरोतु", + "Software Updates": "software अद्यतनानि", + "Package Bundles": "पैकेज्-बण्डल्स्", + "Settings": "विन्यासाः", + "Package Managers": "पैकेज्-प्रबन्धकाः", + "UniGetUI Log": "UniGetUI log-पत्रम्", + "Package Manager logs": "पैकेज्-प्रबन्धक-logs", + "Operation history": "operation-इतिहासः", + "Help": "साहाय्यम्", + "UniGetUI": "UniGetUI", + "You have installed UniGetUI Version {0}": "त्वया UniGetUI संस्करणम् {0} स्थापितम्", + "Disclaimer": "अस्वीकरणम्", + "UniGetUI is developed by Devolutions and is not affiliated with any of the compatible package managers.": "UniGetUI Devolutions-द्वारा विकसितम् अस्ति तथा च कस्यापि संगत-पैकेज-प्रबन्धकस्य सह सम्बद्धं नास्ति।", + "UniGetUI wouldn't have been possible without the help of the contributors. Thank you all 🥳": "contributors सहाय्यं विना UniGetUI सम्भवमेव न स्यात्। सर्वेभ्यः धन्यवादाः 🥳", + "UniGetUI uses the following libraries. Without them, UniGetUI wouldn't have been possible.": "UniGetUI निम्नलिखित-libraries उपयोजयति। एताभिः विना UniGetUI सम्भवमेव न स्यात्।", + "{0} homepage": "{0} मुखपृष्ठम्", + "UniGetUI has been translated to more than 40 languages thanks to the volunteer translators. Thank you 🤝": "स्वयंसेवक-अनुवादकानां कृते UniGetUI 40 तः अधिकासु भाषासु अनूदितम् अस्ति। धन्यवादः 🤝", + "Verbose": "विस्तृतम्", + "1 - Errors": "1 - दोषाः", + "2 - Warnings": "2 - चेतावन्यः", + "3 - Information (less)": "3 - सूचना (अल्प)", + "4 - Information (more)": "4 - सूचना (अधिक)", + "5 - information (debug)": "5 - सूचना (डिबग)", + "Warning": "चेतावनी", + "The following settings may pose a security risk, hence they are disabled by default.": "निम्नलिखिताः settings सुरक्षा-जोखिमं जनयेयुः, अतः ते पूर्वनिर्धारितरूपेण निष्क्रियाः सन्ति।", + "Enable the settings below if and only if you fully understand what they do, and the implications they may have.": "अधोलिखिताः settings तदा एव सक्रियीकुरुत यदा तासां कार्यं तथा तासां प्रभावाः पूर्णतया बोध्यन्ते।", + "The settings will list, in their descriptions, the potential security issues they may have.": "settings तेषां विवरणेषु तेषां सम्भावित-सुरक्षा-समस्याः सूचयिष्यन्ति।", + "The backup will include the complete list of the installed packages and their installation options. Ignored updates and skipped versions will also be saved.": "backup मध्ये स्थापित-पैकेजानां पूर्णा सूची तथा तेषां स्थापना-विकल्पाः भविष्यन्ति। उपेक्षित-अद्यतनानि तथा त्यक्त-संस्करणानि अपि संगृहीष्यन्ते।", + "The backup will NOT include any binary file nor any program's saved data.": "backup मध्ये काचिदपि binary सञ्चिका न भविष्यति, न च कस्यचित् कार्यक्रमस्य संगृहीत-दत्तांशः।", + "The size of the backup is estimated to be less than 1MB.": "backup इत्यस्य परिमाणं 1MB तः न्यूनं भविष्यति इति अनुमान्यते।", + "The backup will be performed after login.": "login अनन्तरं backup क्रियते।", + "{pcName} installed packages": "{pcName} स्थापित-packages", + "Current status: Not logged in": "वर्तमानस्थितिः: logged in नास्ति", + "You are logged in as {0} (@{1})": "त्वं {0} (@{1}) इति नाम्ना logged in असि", + "Nice! Backups will be uploaded to a private gist on your account": "उत्तमम्! backups भवतः account इत्यस्मिन् निजी gist मध्ये अपलोड् भविष्यन्ति", + "Select backup": "backup चयनय", + "Settings imported from {0}": "{0} तः विन्यासाः आयातिताः", + "UniGetUI Settings": "UniGetUI विन्यासाः", + "Settings exported to {0}": "{0} प्रति विन्यासाः निर्यातिताः", + "UniGetUI settings were reset": "UniGetUI विन्यासाः पुनर्स्थापिताः", + "Allow pre-release versions": "pre-release संस्करणानि अनुमन्यन्ताम्", + "Apply": "प्रयोजयतु", + "For security reasons, custom command-line arguments are disabled by default. Go to UniGetUI security settings to change this.": "सुरक्षार्थं स्वनिर्धारित-आदेश-पङ्क्ति-तर्काः मूलतः निष्क्रियाः सन्ति। एतत् परिवर्तयितुं UniGetUI सुरक्षा-विन्यासान् गच्छतु।", + "Go to UniGetUI security settings": "UniGetUI security settings गच्छतु", + "The following options will be applied by default each time a {0} package is installed, upgraded or uninstalled.": "यदा यदा {0} package स्थाप्यते, उन्नीयते, अथवा अनस्थाप्यते तदा तदा निम्न-विकल्पाः पूर्वनिर्धारितरूपेण प्रयुज्यन्ते।", + "Package's default": "पैकेजस्य पूर्वनिर्धारितम्", + "Install location can't be changed for {0} packages": "{0} packages कृते install location परिवर्तयितुं न शक्यते", + "The local icon cache currently takes {0} MB": "स्थानीयः icon cache अधुना {0} MB गृह्णाति", + "Username": "उपयोक्तृनाम", + "Password": "गुह्यशब्दः", + "Credentials": "credentials", + "It is not guaranteed that the provided credentials will be stored safely": "प्रदत्तानि प्रमाणपत्राणि सुरक्षितरूपेण संग्रहीष्यन्ते इति न सुनिश्चितम्", + "Partially": "आंशिकरूपेण", + "Package manager": "पैकेज्-प्रबन्धकः", + "Compatible with proxy": "proxy सह सुसंगतम्", + "Compatible with authentication": "authentication सह सुसंगतम्", + "Proxy compatibility table": "proxy compatibility table", + "{0} settings": "{0} विन्यासाः", + "{0} status": "{0} स्थितिः", + "Default installation options for {0} packages": "{0} packages कृते मूलनिर्धारित-स्थापन-विकल्पाः", + "Expand version": "संस्करणं विस्तरयतु", + "The executable file for {0} was not found": "{0} कृते executable सञ्चिका न लब्धा", + "{pm} is disabled": "{pm} निष्क्रियः अस्ति", + "Enable it to install packages from {pm}.": "{pm} तः packages स्थापयितुं तत् सक्रियीकुरुत।", + "{pm} is enabled and ready to go": "{pm} सक्षमः अस्ति तथा सज्जः अस्ति", + "{pm} version:": "{pm} संस्करणम्:", + "{pm} was not found!": "{pm} न लब्धः!", + "You may need to install {pm} in order to use it with UniGetUI.": "UniGetUI सह उपयोक्तुं {pm} स्थापयितुं त्वया आवश्यकं भवेत्।", + "Scoop Installer - UniGetUI": "Scoop स्थापक - UniGetUI", + "Scoop Uninstaller - UniGetUI": "Scoop अनस्थापक - UniGetUI", + "Clearing Scoop cache - UniGetUI": "Scoop सञ्चिकायाः निर्मूल्यताम् - UniGetUI", + "Restart UniGetUI to fully apply changes": "परिवर्तनानि पूर्णतया प्रयोजयितुं UniGetUI पुनरारभताम्", + "Restart UniGetUI": "UniGetUI पुनरारभस्व", + "Manage {0} sources": "{0} स्रोतांसि प्रबन्धय", + "Add source": "स्रोतं योजय", + "Add": "योजय", + "Source name": "स्रोत-नाम", + "Source URL": "स्रोत-URL", + "Other": "अन्यत्", + "No minimum age": "न्यूनतम-कालः नास्ति", + "1 day": "1 दिनम्", + "{0} days": "{0} दिवसाः", + "Custom...": "स्वनिर्धारितम्...", + "{0} minutes": "{0} निमिषाः", + "1 hour": "1 होरात्रम्", + "{0} hours": "{0} घण्टाः", + "1 week": "1 सप्ताहः", + "Supports release dates": "प्रकाशन-तिथीनां समर्थनम् अस्ति", + "Release date support per package manager": "प्रत्येक-पुटक-प्रबन्धकस्य प्रकाशन-तिथि-समर्थनम्", + "Search for packages": "packages अन्वेषय", + "Local": "स्थानीयम्", + "OK": "अस्तु", + "Last checked: {0}": "अन्तिमवारं परीक्षितम्: {0}", + "{0} packages were found, {1} of which match the specified filters.": "{0} packages लब्धानि, तेषु {1} निर्दिष्ट-filters सह संगच्छन्ति।", + "{0} selected": "{0} चयनितम्", + "(Last checked: {0})": "(अन्तिमवारं परीक्षितम्: {0})", + "All packages selected": "सर्वे packages चयनिताः", + "Package selection cleared": "पैकेज्-चयनं निर्मलितम्", + "{0}: {1}": "{0}: {1}", + "More info": "अधिक-सूचना", + "GitHub account": "GitHub खातम्", + "Log in with GitHub to enable cloud package backup.": "cloud package backup सक्रियीकरणाय GitHub सह प्रविशतु।", + "More details": "अधिक-विवरणानि", + "Log in": "प्रविशतु", + "If you have cloud backup enabled, it will be saved as a GitHub Gist on this account": "यदि cloud backup सक्रियीकृतम् अस्ति, तर्हि एतस्मिन् खाते GitHub Gist रूपेण रक्षितं भविष्यति", + "Log out": "निर्गच्छतु", + "About UniGetUI": "UniGetUI विषये", + "About": "सम्बन्धे", + "Third-party licenses": "तृतीय-पक्ष-अनुज्ञापत्राणि", + "Contributors": "योगदातारः", + "Translators": "अनुवादकाः", + "Bundle security report": "bundle security report", + "The bundle contained restricted content": "bundle मध्ये प्रतिबद्ध-विषयवस्तु आसीत्", + "UniGetUI – Crash Report": "UniGetUI – विपत्ति-प्रतिवेदनम्", + "UniGetUI has crashed": "UniGetUI विपन्नम् अस्ति", + "Help us fix this by sending a crash report to Devolutions. All fields below are optional.": "Devolutions प्रति विपत्ति-प्रतिवेदनं प्रेषयित्वा एतत् सुधारयितुम् अस्मान् साहाय्यय। अधोलिखितानि सर्वाणि क्षेत्राणि वैकल्पिकानि सन्ति।", + "Email (optional)": "ईमेल् (वैकल्पिकम्)", + "your@email.com": "your@email.com", + "Additional details (optional)": "अतिरिक्त-विवरणानि (वैकल्पिकम्)", + "Describe what you were doing when the crash occurred…": "विपत्तिः यदा अभवत् तदा भवान् किं करोति स्म तत् वर्णयतु…", + "Crash report": "विपत्ति-प्रतिवेदनम्", + "Don't Send": "मा प्रेषय", + "Send Report": "प्रतिवेदनं प्रेषय", + "Sending…": "प्रेष्यते…", + "Unsaved changes": "असंगृहीत-परिवर्तनानि", + "You have unsaved changes in the current bundle. Do you want to discard them?": "वर्तमान-bundle मध्ये तव असंगृहीत-परिवर्तनानि सन्ति। किं तानि परित्यक्तुम् इच्छसि?", + "Discard changes": "परिवर्तनानि परित्यज", + "Integrity violation": "अखण्डता-उल्लङ्घनम्", + "UniGetUI or some of its components are missing or corrupt. It is strongly recommended to reinstall UniGetUI to adress the situation.": "UniGetUI अथवा तस्य केचन घटकाः लुप्ताः वा दूषिताः वा सन्ति। स्थितिं समाधातुं UniGetUI पुनः स्थापयितुं दृढतया अनुशंसितम् अस्ति।", + "• Refer to the UniGetUI Logs to get more details regarding the affected file(s)": "• प्रभावित-file(s) विषये अधिक-विवरणानि प्राप्तुं UniGetUI Logs प्रति सन्दर्भं कुरु", + "• Integrity checks can be disabled from the Experimental Settings": "• Integrity checks Experimental Settings तः निष्क्रियं कर्तुं शक्यन्ते", + "Manage shortcuts": "shortcuts प्रबन्धय", + "UniGetUI has detected the following desktop shortcuts which can be removed automatically on future upgrades": "UniGetUI इत्यनेन निम्नलिखिताः desktop shortcuts ज्ञाताः ये भविष्यत् upgrades मध्ये स्वयमेव अपाकर्तुं शक्यन्ते", + "Do you really want to reset this list? This action cannot be reverted.": "भवान् अस्याः सूच्याः reset कर्तुम् एव इच्छति किम्? एषा क्रिया प्रत्यावर्तयितुं न शक्यते।", + "Desktop shortcuts list": "Desktop shortcuts सूची", + "Open in explorer": "Explorer मध्ये उद्घाटय", + "Remove from list": "सूच्यातः अपाकुरु", + "When new shortcuts are detected, delete them automatically instead of showing this dialog.": "नूतनाः shortcuts ज्ञायमाने अस्य dialog दर्शनस्य स्थाने तान् स्वयमेव अपाकुरु।", + "Not right now": "अधुना न", + "Missing dependency": "अनुपस्थित-निर्भरता", + "UniGetUI requires {0} to operate, but it was not found on your system.": "UniGetUI संचालनाय {0} अपेक्षते, किन्तु तत् तव प्रणाल्यां न लब्धम्।", + "Click on Install to begin the installation process. If you skip the installation, UniGetUI may not work as expected.": "स्थापने प्रक्रियाम् आरब्धुं स्थापयति इति क्लिक् करोतु। यदि स्थापनेम् त्यजति, UniGetUI अपेक्षितरूपेण कार्यं न करिष्यति।", + "Alternatively, you can also install {0} by running the following command in a Windows PowerShell prompt:": "वैकल्पिकतया, Windows PowerShell prompt मध्ये अधोलिखितं command चालयित्वा {0} अपि स्थापयितुं शक्यते:", + "Install {0}": "{0} स्थापयतु", + "Do not show this dialog again for {0}": "{0} कृते एषः dialog पुनः मा दर्शयतु", + "Please wait while {0} is being installed. A black window may show up. Please wait until it closes.": "{0} स्थाप्यते यावत् कृपया प्रतीक्षस्व। कृष्णा window दृश्येत। सा यावत् न पिधीयते तावत् प्रतीक्षस्व।", + "{0} has been installed successfully.": "{0} सफलतया स्थापितम्।", + "Please click on \"Continue\" to continue": "अग्रे गन्तुं \"Continue\" इत्यत्र क्लिक् कुरु", + "Continue": "अनुवर्तताम्", + "{0} has been installed successfully. It is recommended to restart UniGetUI to finish the installation": "{0} सफलतया स्थापितम्। स्थापना समाप्तुं UniGetUI पुनरारभितुं अनुशंस्यते।", + "Restart later": "पश्चात् पुनरारभस्व", + "An error occurred:": "दोषः अभवत्:", + "Please see the Command-line Output or refer to the Operation History for further information about the issue.": "कृपया Command-line Output पश्यतु अथवा समस्यायाः विषये अधिक-सूचनार्थं Operation History प्रति सन्दर्भं कुरु।", + "Retry as administrator": "administrator रूपेण पुनः प्रयतस्व", + "Retry interactively": "interactive रूपेण पुनः प्रयतस्व", + "Retry skipping integrity checks": "integrity checks त्यक्त्वा पुनः प्रयतस्व", + "Installation options": "स्थापन-विकल्पाः", + "Save": "संगृहाण", + "UniGetUI collects anonymous usage data with the sole purpose of understanding and improving the user experience.": "उपयोक्तृ-अनुभवम् अवगन्तुं सुधारयितुं च केवलं UniGetUI अनामिक-उपयोग-दत्तांशं संगृह्णाति।", + "More details about the shared data and how it will be processed": "साम्भाजित-दत्तांशस्य तथा तस्य प्रक्रिया-रीतेः अधिक-विवरणानि", + "Do you accept that UniGetUI collects and sends anonymous usage statistics, with the sole purpose of understanding and improving the user experience?": "उपयोक्तृ-अनुभवं ज्ञातुं सुधरितुं च केवल-उद्देशेन UniGetUI अनाम-usage-statistics संकलयति प्रेषयति च, इति भवान् स्वीकरोति किम्?", + "Decline": "अस्वीकुरुत", + "No personal information is collected nor sent, and the collected data is anonimized, so it can't be back-tracked to you.": "काचिदपि व्यक्तिगत-सूचना न संगृह्यते न प्रेष्यते च, संगृहीत-दत्तांशश्च अनामिकीकृतः अस्ति, अतः सः पुनः त्वयि अनुसर्तुं न शक्यते।", + "Navigation panel": "संचालन-फलकम्", + "Operations": "क्रियाः", + "Toggle operations panel": "क्रियापटलं दर्शय/गोपय", + "Bulk operations": "समूह-क्रियाः", + "Retry failed": "विफलानि पुनः प्रयतस्व", + "Clear successful": "सफलानि निष्कासय", + "Clear finished": "समाप्तानि निष्कासय", + "Cancel all": "सर्वाणि रद्दय", + "More": "अधिकम्", + "Toggle navigation panel": "नाविकन-पट्टिकां दर्शय वा गोपय", + "Minimize": "न्यूनीकुरु", + "Maximize": "वर्धय", + "UniGetUI by Devolutions": "Devolutions-द्वारा UniGetUI", + "UniGetUI is an application that makes managing your software easier, by providing an all-in-one graphical interface for your command-line package managers.": "UniGetUI एषा application अस्ति या तव command-line package managers कृते सर्वसमावेशकं graphical interface प्रदाय software-प्रबन्धनं सुकरं करोति।", + "Useful links": "उपयोगिनः links", + "UniGetUI Homepage": "UniGetUI मुखपृष्ठम्", + "Report an issue or submit a feature request": "समस्यां निवेदय अथवा feature request प्रेषय", + "UniGetUI Repository": "UniGetUI संग्रहः", + "View GitHub Profile": "GitHub Profile पश्य", + "UniGetUI License": "UniGetUI अनुज्ञापत्रम्", + "Using UniGetUI implies the acceptation of the MIT License": "UniGetUI उपयोक्तुं MIT License इत्यस्य स्वीकृतिः सूच्यते", + "Become a translator": "अनुवादकः भव", + "Go back": "पृष्ठतः गच्छ", + "Go forward": "अग्रे गच्छ", + "Go to home page": "मुखपृष्ठं गच्छ", + "Reload page": "पृष्ठं पुनः लोडय", + "View page on browser": "browser मध्ये पृष्ठं पश्य", + "The built-in browser is not supported on Linux yet.": "अन्तर्निर्मितः browser Linux मध्ये अद्यापि समर्थितः नास्ति।", + "Open in browser": "browser मध्ये उद्घाटय", + "Copy to clipboard": "clipboard प्रति प्रतिलिखतु", + "Export to a file": "file इत्यस्मिन् निर्यातयतु", + "Log level:": "log स्तरः:", + "Reload log": "log पुनर्लोडय", + "Export log": "log निर्यातय", + "Text": "पाठः", + "Change how operations request administrator rights": "क्रियाः administrator rights कथं याचन्ते इति परिवर्तयतु", + "Restrictions on package operations": "package operations विषये प्रतिबन्धाः", + "Restrictions on package managers": "package managers विषये प्रतिबन्धाः", + "Restrictions when importing package bundles": "package bundles आयातकाले प्रतिबन्धाः", + "Ask for administrator privileges once for each batch of operations": "प्रत्येकस्य क्रियासमूहस्य कृते प्रशासकाधिकाराः एकवारं पृच्छतु", + "Ask only once for administrator privileges": "administrator privileges एकवारमेव पृच्छतु", + "Prohibit any kind of Elevation via UniGetUI Elevator or GSudo": "UniGetUI Elevator अथवा GSudo द्वारा कस्यापि Elevation प्रकारस्य निषेधं कुरु", + "This option WILL cause issues. Any operation incapable of elevating itself WILL FAIL. Install/update/uninstall as administrator will NOT WORK.": "अयं विकल्पः नूनं समस्याः जनयिष्यति। यः कश्चन operation स्वयम् elevate कर्तुं न शक्नोति सः नूनं विफलः भविष्यति। administrator रूपेण install/update/uninstall कार्यं न करिष्यति।", + "Allow custom command-line arguments": "custom command-line arguments अनुमन्यन्ताम्", + "Custom command-line arguments can change the way in which programs are installed, upgraded or uninstalled, in a way UniGetUI cannot control. Using custom command-lines can break packages. Proceed with caution.": "custom command-line arguments तादृशेन प्रकारेण कार्यक्रमानां स्थापनं, उन्नयनं, वा uninstall परिवर्तयितुं शक्नुवन्ति यं UniGetUI नियन्त्रयितुं न शक्नोति। custom command-lines उपयुज्य packages नष्टुं शक्नुवन्ति। सावधानतया अग्रे गच्छतु।", + "Ignore custom pre-install and post-install commands when importing packages from a bundle": "bundle तः packages आयातकाले custom pre-install तथा post-install commands उपेक्षध्वम्", + "Pre and post install commands will be run before and after a package gets installed, upgraded or uninstalled. Be aware that they may break things unless used carefully": "पूर्व-पर-स्थापन commands पैकेजस्य स्थापना, उन्नयन, अनस्थापनयोः पूर्वं पश्चाच्च चलिष्यन्ति। सावधानतया न प्रयुक्ताः चेत् ते वस्तूनि भङ्गयितुं शक्नुवन्ति।", + "Allow changing the paths for package manager executables": "package manager executables इत्येषां path परिवर्तनं अनुमन्यताम्", + "Turning this on enables changing the executable file used to interact with package managers. While this allows finer-grained customization of your install processes, it may also be dangerous": "एतत् सक्रियं कृत्वा package managers सह परस्परं कार्यकर्तुं प्रयुज्यमानस्य executable सञ्चिकायाः परिवर्तनं शक्यते। एतेन तव install processes सूक्ष्मतररूपेण अनुकूलयितुं शक्यते, किन्तु एतत् जोखिमपूर्णम् अपि भवेत्।", + "Allow importing custom command-line arguments when importing packages from a bundle": "बण्डलात् पुटकानि आयातयन् custom command-line arguments अपि आयातयितुम् अनुमन्यताम्", + "Malformed command-line arguments can break packages, or even allow a malicious actor to gain privileged execution. Therefore, importing custom command-line arguments is disabled by default": "विकृताः command-line arguments packages भङ्गयितुं शक्नुवन्ति, अथवा दुष्टकर्तारं privileged execution प्राप्तुं अपि अनुमन्येयुः। अतः custom command-line arguments आयातनं पूर्वनिर्धारितरूपेण निष्क्रियं कृतम् अस्ति।", + "Allow importing custom pre-install and post-install commands when importing packages from a bundle": "बण्डलात् पुटकानि आयातयन् custom pre-install तथा post-install आदेशान् अपि आयातयितुम् अनुमन्यताम्", + "Pre and post install commands can do very nasty things to your device, if designed to do so. It can be very dangerous to import the commands from a bundle, unless you trust the source of that package bundle": "पूर्व-पर-स्थापन commands यदि तथैव निर्मिताः स्युः तर्हि तव उपकरणे अत्यन्तं हानिकराणि कर्माणि कर्तुं शक्नुवन्ति। यदि तस्य package bundle इत्यस्य स्रोतसि विश्वासो नास्ति तर्हि bundle तः commands आयातयितुं महद् जोखिमम्।", + "Administrator rights and other dangerous settings": "प्रशासकीयाधिकाराः तथा अन्यानि जोखिमयुक्तानि settings", + "Package backup": "पैकेज्-backup", + "Cloud package backup": "cloud पुटक backup", + "Local package backup": "स्थानीय package backup", + "Local backup advanced options": "स्थानीय backup उन्नत-विकल्पाः", + "Log in with GitHub": "GitHub सह प्रविशतु", + "Log out from GitHub": "GitHub तः निर्गच्छतु", + "Periodically perform a cloud backup of the installed packages": "स्थापित-पैकेजानां cloud backup आवधिकरूपेण कुरु", + "Cloud backup uses a private GitHub Gist to store a list of installed packages": "cloud backup स्थापिता-पुटक-सूचीं संग्रहीतुं private GitHub Gist उपयुङ्क्ते", + "Perform a cloud backup now": "इदानीं cloud backup कुरु", + "Backup": "प्रतिस्थापनम्", + "Restore a backup from the cloud": "cloud तः backup पुनर्स्थापय", + "Begin the process to select a cloud backup and review which packages to restore": "cloud backup चयनस्य तथा पुनर्स्थापनीयपुटकानां समीक्षा-प्रक्रियाम् आरभताम्", + "Periodically perform a local backup of the installed packages": "स्थापित-पैकेजानां local backup आवधिकरूपेण कुरु", + "Perform a local backup now": "इदानीं local backup कुरु", + "Change backup output directory": "प्रतिस्थापनस्य निर्गमपथं परिवर्तय", + "Set a custom backup file name": "custom backup सञ्चिका-नाम निर्धारय", + "Leave empty for default": "मूलनिर्धारणाय रिक्तं त्यजतु", + "Add a timestamp to the backup file names": "प्रतिस्थापनसञ्चिकानामसु कालचिह्नं योजय", + "Backup and Restore": "backup तथा पुनर्स्थापनम्", + "Enable background api (UniGetUI Widgets and Sharing, port 7058)": "background api (UniGetUI Widgets and Sharing, port 7058) सक्रियीकुरुत", + "Wait for the device to be connected to the internet before attempting to do tasks that require internet connectivity.": "internet-संयोजनम् अपेक्षन्ते यानि कार्याणि तानि कर्तुं प्रयतमानः सन् उपकरणं प्रथमं internet सह सम्बद्धं भवतु इति प्रतीक्षस्व।", + "Disable the 1-minute timeout for package-related operations": "package-संबद्ध-क्रियाभ्यः 1-minute timeout निष्क्रियं कुरुत", + "Use installed GSudo instead of UniGetUI Elevator": "UniGetUI Elevator इत्यस्य स्थाने स्थापितं GSudo उपयोजय", + "Use a custom icon and screenshot database URL": "custom icon तथा screenshot database URL उपयोजय", + "Enable background CPU Usage optimizations (see Pull Request #3278)": "background CPU Usage optimizations सक्रियीकुरुत (Pull Request #3278 पश्यतु)", + "Perform integrity checks at startup": "आरम्भकाले integrity checks कुरु", + "When batch installing packages from a bundle, install also packages that are already installed": "bundle तः batch स्थापना कुर्वन् पूर्वमेव स्थापितान् packages अपि स्थापय", + "Experimental settings and developer options": "प्रायोगिक-settings तथा developer-options", + "Show UniGetUI's version and build number on the titlebar.": "titlebar मध्ये UniGetUI इत्यस्य version तथा build number दर्शय।", + "Language": "भाषा", + "UniGetUI updater": "UniGetUI अद्यतयिता", + "Telemetry": "दूरमिति", + "Manage UniGetUI settings": "UniGetUI settings प्रबन्धय", + "Related settings": "सम्बद्ध settings", + "Update UniGetUI automatically": "UniGetUI स्वयमेव अद्यतय", + "Check for updates": "अद्यतनानि परीक्ष्यन्ताम्", + "Install prerelease versions of UniGetUI": "UniGetUI इत्यस्य prerelease versions स्थापयतु", + "Manage telemetry settings": "telemetry settings प्रबन्धय", + "Manage": "प्रबन्धय", + "Import settings from a local file": "स्थानीय-file तः settings आयातयतु", + "Import": "आयातयतु", + "Export settings to a local file": "settings स्थानीय-file इत्यस्मिन् निर्यातयतु", + "Export": "निर्यातयतु", + "Reset UniGetUI": "UniGetUI पुनर्स्थापय", + "User interface preferences": "उपयोक्ता-अन्तरफल-अभिरुचयः", + "Application theme, startup page, package icons, clear successful installs automatically": "application theme, startup page, package icons, सफलस्थापनानि स्वयमेव अपसारयतु", + "General preferences": "सामान्य-अभिरुचयः", + "UniGetUI display language:": "UniGetUI प्रदर्शन-भाषा:", + "System language": "तन्त्रांशभाषा", + "Is your language missing or incomplete?": "भवतः भाषा अनुपस्थितास्ति वा अपूर्णा अस्ति किम्?", + "Appearance": "रूपम्", + "UniGetUI on the background and system tray": "background तथा system tray मध्ये UniGetUI", + "Package lists": "पैकेज्-सूचयः", + "Use classic mode": "पारम्परिक-रीतिं उपयुञ्जताम्", + "Restart UniGetUI to apply this change": "एतत् परिवर्तनं प्रयोक्तुं UniGetUI पुनः आरभताम्", + "The classic UI is disabled for beta testers": "बीटा-परीक्षकाणां कृते क्लासिक UI निष्क्रियीकृतम् अस्ति", + "Close UniGetUI to the system tray": "UniGetUI system tray प्रति पिधत्ताम्", + "Manage UniGetUI autostart behaviour": "UniGetUI स्वयमारम्भ-व्यवहारं प्रबन्धय", + "Show package icons on package lists": "package सूचिषु package icons दर्शय", + "Clear cache": "cache अपसारयतु", + "Select upgradable packages by default": "उन्नेय-packages पूर्वनिर्धारितरूपेण चयनय", + "Light": "प्रकाशः", + "Dark": "कृष्णवर्णीयम्", + "Follow system color scheme": "system color scheme अनुसरतु", + "Application theme:": "अनुप्रयोगस्य theme:", + "UniGetUI startup page:": "UniGetUI आरम्भ-पृष्ठम्:", + "Proxy settings": "proxy विन्यासाः", + "Other settings": "अन्ये settings", + "Connect the internet using a custom proxy": "custom proxy उपयुज्य internet संयोजयतु", + "Please note that not all package managers may fully support this feature": "कृपया ज्ञापयामः यत् सर्वे package managers एतत् feature पूर्णतया न समर्थयेयुः।", + "Proxy URL": "proxy URL", + "Enter proxy URL here": "अत्र proxy URL लिखतु", + "Authenticate to the proxy with a user and a password": "उपयोक्तृनाम्ना गुह्यशब्देन च proxy मध्ये प्रमाणीकरोतु", + "Internet and proxy settings": "internet तथा proxy विन्यासाः", + "Package manager preferences": "पैकेज्-प्रबन्धक-अभिरुचयः", + "Ready": "सज्जम्", + "Not found": "न लब्धम्", + "Notification preferences": "सूचना-अभिरुचयः", + "Notification types": "सूचना-प्रकाराः", + "The system tray icon must be enabled in order for notifications to work": "notifications कार्यकर्तुं system tray icon सक्षमः भवितुम् आवश्यकः।", + "Enable UniGetUI notifications": "UniGetUI notifications सक्रियीकुरुत", + "Show a notification when there are available updates": "उपलब्ध-अद्यतनानि सन्ति चेत् notification दर्शय", + "Show a silent notification when an operation is running": "operation प्रचलति चेत् निःशब्द notification दर्शय", + "Show a notification when an operation fails": "operation विफलः चेत् notification दर्शय", + "Show a notification when an operation finishes successfully": "operation सफलतया समाप्तः चेत् notification दर्शय", + "Concurrency and execution": "समकालिकता तथा execution", + "Automatic desktop shortcut remover": "स्वयंचलित desktop shortcut remover", + "Choose how many operations should be performed in parallel": "समकाले कति operations क्रियाः करणीयाः इति चयनय", + "Clear successful operations from the operation list after a 5 second delay": "5 second विलम्बेन operation list तः सफलाः क्रियाः अपसारयतु", + "Download operations are not affected by this setting": "Download operations एतया setting इत्यया न प्रभाविताः", + "You may lose unsaved data": "असंगृहीत-दत्तांशः नश्येत्", + "Ask to delete desktop shortcuts created during an install or upgrade.": "स्थापने अथवा upgrade काले निर्मितान् desktop shortcuts लोपयितुं पृच्छतु।", + "Package update preferences": "पैकेज्-अद्यतन-अभिरुचयः", + "Update check frequency, automatically install updates, etc.": "अद्यतन-परीक्षण-आवृत्तिः, updates स्वयमेव स्थापयितुम्, इत्यादि।", + "Reduce UAC prompts, elevate installations by default, unlock certain dangerous features, etc.": "UAC prompts न्यूनीकरोतु, स्थापनेषु पूर्वनिर्धारितरूपेण elevation ददातु, केचन जोखिमपूर्ण features उद्घाटयतु, इत्यादि।", + "Package operation preferences": "पैकेज्-operation अभिरुचयः", + "Enable {pm}": "{pm} सक्रियीकुरुत", + "Not finding the file you are looking for? Make sure it has been added to path.": "यत् file अन्विष्यसि तत् न लभ्यते किम्? तत् path मध्ये योजितम् इति सुनिश्चितं कुरु।", + "Select the executable to be used. The following list shows the executables found by UniGetUI": "उपयोक्तव्यं executable चयनय। अधोलिखिता सूची UniGetUI द्वारा लब्धानि executables दर्शयति।", + "For security reasons, changing the executable file is disabled by default": "सुरक्षार्थं executable file परिवर्तनं मूलतः निष्क्रियं कृतम् अस्ति", + "Change this": "एतत् परिवर्तयतु", + "Copy path": "पथं प्रतिलिख", + "Current executable file:": "वर्तमान executable सञ्चिका:", + "Ignore packages from {pm} when showing a notification about updates": "updates विषये notification दर्शने {pm} तः packages उपेक्षध्वम्", + "Update security": "अद्यतन-सुरक्षा", + "Use global setting": "वैश्विक-विन्यासम् उपयोजय", + "Minimum age for updates": "अद्यतनानां न्यूनतम-कालः", + "e.g. 10": "यथा 10", + "Custom minimum age (days)": "स्वनिर्धारितः न्यूनतम-कालः (दिवसाः)", + "{pm} does not provide release dates for its packages, so this setting will have no effect": "{pm} स्वेषां packages कृते प्रकाशन-तिथीः न ददाति, अतः अस्य विन्यासस्य प्रभावो न भविष्यति", + "{pm} only provides release dates for some of its packages, so this setting will only apply to those packages": "{pm} स्वस्य केषाञ्चित् एव संवेष्टनानां प्रकाशनतिथिं ददाति, अतः इयं समायोजना तेषु एव संवेष्टनेषु प्रवर्तते", + "Override the global minimum update age for this package manager": "अस्य package manager कृते वैश्विकं न्यूनतम-अद्यतन-कालम् अधिलिख्य स्थापय", + "View {0} logs": "{0} logs पश्य", + "If Python cannot be found or is not listing packages but is installed on the system, ": "यदि Python न लभ्यते अथवा packages न सूचयति किन्तु प्रणालीषु स्थापितम् अस्ति, ", + "Advanced options": "उन्नतविकल्पाः", + "WinGet command-line tool": "WinGet आदेश-पङ्क्ति-साधनम्", + "Choose which command-line tool UniGetUI uses for WinGet operations when the COM API is not used": "COM API न उपयुज्यमाने WinGet-क्रियाणां कृते UniGetUI किम् आदेश-पङ्क्ति-उपकरणम् उपयुङ्क्ते इति चयनय", + "WinGet COM API": "WinGet COM API", + "Choose whether UniGetUI can use the WinGet COM API before falling back to the command-line tool": "आदेश-पङ्क्ति-उपकरणे प्रत्यावर्तनात् पूर्वं UniGetUI WinGet COM API उपयोक्तुं शक्नोति वा इति चयनय", + "Reset WinGet": "WinGet पुनर्स्थापय", + "This may help if no packages are listed": "यदि packages न सूचीकृतानि स्युः तर्हि एतत् साहाय्यं कुर्यात्", + "Force install location parameter when updating packages with custom locations": "custom locations युक्त-packages अद्यतनकाले install location parameter बलात् योजयतु", + "Install Scoop": "Scoop स्थापयतु", + "Uninstall Scoop (and its packages)": "Scoop (तस्य packages च) अनस्थापय", + "Run cleanup and clear cache": "cleanup चालय तथा cache शुद्धीकुरु", + "Run": "चालय", + "Enable Scoop cleanup on launch": "launch काले Scoop cleanup सक्रियं कुरुत", + "Default vcpkg triplet": "मूलनिर्धारित vcpkg triplet", + "Change vcpkg root location": "vcpkg मूल-स्थानं परिवर्तय", + "Reset vcpkg root location": "vcpkg मूल-स्थानं पुनर्स्थापय", + "Open vcpkg root location": "vcpkg मूल-स्थानम् उद्घाटय", + "Language, theme and other miscellaneous preferences": "भाषा, theme तथा अन्याः miscellaneous अभिरुचयः", + "Show notifications on different events": "विविध-घटनासु notifications दर्शय", + "Change how UniGetUI checks and installs available updates for your packages": "तव पुटकानां अद्यतनानि परीक्ष्य स्थापयति च इति UniGetUI कथं परिवर्तय", + "Automatically save a list of all your installed packages to easily restore them.": "सर्वाणि स्थापिता पुटकानि स्वयमेव सुरक्षितानि कृत्वा पुनः स्थापयतु।", + "Enable and disable package managers, change default install options, etc.": "package managers सक्रियीकुरुत, निष्क्रियीकुरुत, मूलनिर्धारित install options परिवर्तयतु, इत्यादि", + "Internet connection settings": "internet-संयोजन-विन्यासाः", + "Proxy settings, etc.": "Proxy settings इत्यादयः", + "Beta features and other options that shouldn't be touched": "बीटा विशेषताः अन्य विकल्पाः च ये न स्पृशन्तु", + "Reload sources": "स्रोतांसि पुनः लोडय", + "Delete source": "स्रोतम् अपाकुरु", + "Known sources": "ज्ञात-स्रोतांसि", + "Update checking": "अद्यतन-परीक्षणम्", + "Automatic updates": "स्वयंचलित-अद्यतनानि", + "Check for package updates periodically": "पुटकस्य अद्यतनानि आवृत्त्या परीक्ष्यन्ताम्", + "Check for updates every:": "प्रत्येकस्मिन् समये अद्यतनानि परीक्ष्यन्ताम्:", + "Install available updates automatically": "उपलब्ध-updates स्वयमेव स्थापयतु", + "Do not automatically install updates when the network connection is metered": "network connection metered सति updates स्वयमेव मा स्थापयतु", + "Do not automatically install updates when the device runs on battery": "उपकरणं battery इत्यस्मिन् धावति चेत् updates स्वयमेव मा स्थापयतु", + "Do not automatically install updates when the battery saver is on": "battery saver सक्रियः सति updates स्वयमेव मा स्थापयतु", + "Only show updates that are at least the specified number of days old": "केवलं तानि अद्यतनानि दर्शय यानि न्यूनतया निर्दिष्ट-दिवस-संख्यया पुरातनानि सन्ति", + "Warn me when the installer URL host changes between the installed version and the new version (WinGet only)": "स्थापित-संस्करणस्य नूतन-संस्करणस्य च मध्ये स्थापक-URL host परिवर्तते चेत् मां चेतय (केवलं WinGet)", + "Change how UniGetUI handles install, update and uninstall operations.": "UniGetUI स्थापन, अद्यतन, अनस्थापन-क्रियाः कथं नियच्छति इति परिवर्तयतु।", + "Navigation": "संचालनम्", + "Check for UniGetUI updates": "UniGetUI अद्यतनानि परीक्षस्व", + "Quit UniGetUI": "UniGetUI त्यज", + "Filters": "परिशोधकाः", + "Sources": "स्रोतांसि", + "Search for packages to start": "आरम्भार्थं packages अन्वेषय", + "Select all": "सर्वं चयनय", + "Clear selection": "चयनं निर्मूल्यताम्", + "Instant search": "क्षणिक-अन्वेषणम्", + "Distinguish between uppercase and lowercase": "uppercase तथा lowercase मध्ये भेदं ज्ञातुं", + "Ignore special characters": "विशेष-अक्षराणि उपेक्षध्वम्", + "Search mode": "अन्वेषण-रीतिः", + "Both": "उभे", + "Exact match": "सटीक-साम्यं", + "Show similar packages": "सदृश packages दर्शय", + "Loading": "लोड् क्रियते", + "Package": "पैकेज्", + "More options": "अधिक-विकल्पाः", + "Order by:": "क्रमेण:", + "Name": "नाम", + "Id": "परिचयः", + "Ascendant": "आरोही", + "Descendant": "अवरोही", + "View modes": "दृश्य-रीतयः", + "Reload": "पुनः लोडय", + "Closed": "पिहितम्", + "Ascending": "आरोही", + "Descending": "अवरोही", + "{0}: {1}, {2}": "{0}: {1}, {2}", + "Order by": "क्रमेण योजय", + "No results were found matching the input criteria": "प्रविष्ट-मानदण्डैः अनुरूपाणि परिणामानि न लब्धानि", + "No packages were found": "packages न लब्धानि", + "Loading packages": "packages load क्रियन्ते", + "Skip integrity checks": "integrity checks त्यज", + "Download selected installers": "चयनित installers download कुरुत", + "Install selection": "चयनं स्थापयतु", + "Install options": "स्थापन-विकल्पाः", + "Add selection to bundle": "बण्डलम् प्रति विभागं योजय", + "Download installer": "installer download कुरुत", + "Uninstall selection": "चयनम् अनस्थापय", + "Uninstall options": "अनस्थापन-विकल्पाः", + "Ignore selected packages": "चयनित-packages उपेक्षध्वम्", + "Open install location": "स्थापन-स्थानम् उद्घाटय", + "Reinstall package": "पैकेज् पुनः स्थापय", + "Uninstall package, then reinstall it": "package अनस्थापय, ततः पुनः स्थापय", + "Ignore updates for this package": "अस्य package इत्यस्य updates उपेक्षध्वम्", + "WinGet malfunction detected": "WinGet विकारः ज्ञातः", + "It looks like WinGet is not working properly. Do you want to attempt to repair WinGet?": "WinGet सम्यक् कार्यं न करोति इव दृश्यते। WinGet मरम्मतुं प्रयत्नं कर्तुम् इच्छसि किम्?", + "Repair WinGet": "WinGet मरम्मतु", + "Updates will no longer be ignored for {0}": "{0} कृते अद्यतनानि अधुना उपेक्षितानि न भविष्यन्ति", + "Updates are now ignored for {0}": "{0} कृते अद्यतनानि अधुना उपेक्षितानि सन्ति", + "Do not ignore updates for this package anymore": "अस्य package इत्यस्य updates इदानीं परित्यज्य मा उपेक्षध्वम्", + "Add packages or open an existing package bundle": "पुटकानि योजय वा विद्यमानं पुटकबण्डलम् उद्घाटय", + "Add packages to start": "आरम्भाय पुटकानि योजय", + "The current bundle has no packages. Add some packages to get started": "वर्तमाने bundle मध्ये packages न सन्ति। आरम्भाय केचन packages योजय।", + "New": "नवम्", + "Save as": "इति नाम्ना संगृहाण", + "Create .ps1 script": ".ps1 script निर्मातु", + "Remove selection from bundle": "bundle तः चयनम् अपाकुरु", + "Skip hash checks": "hash checks त्यज", + "The package bundle is not valid": "package bundle वैधं नास्ति", + "The bundle you are trying to load appears to be invalid. Please check the file and try again.": "यत् bundle लोड् कर्तुं प्रयतसे तत् अवैधम् इव दृश्यते। कृपया सञ्चिकां परीक्ष्य पुनः प्रयतस्व।", + "Package bundle": "पैकेज्-bundle", + "Could not create bundle": "bundle निर्मातुं न शक्यते", + "The package bundle could not be created due to an error.": "दोषकारणात् package bundle निर्मातुं न शक्यत।", + "Install script": "स्थापन-script", + "PowerShell script": "PowerShell स्क्रिप्ट्", + "The installation script saved to {0}": "स्थापन-script {0} इत्यत्र संगृहीतः", + "An error occurred": "दोषः अभवत्", + "An error occurred while attempting to create an installation script:": "installation script निर्माणे प्रयतमानस्य दोषः अभवत्:", + "Hooray! No updates were found.": "साधु! updates न लब्धाः।", + "Uninstall selected packages": "चयनित-packages अनस्थापय", + "Update selection": "चयनम् अद्यतय", + "Update options": "अद्यतन-विकल्पाः", + "Uninstall package, then update it": "package अनस्थापय, ततः अद्यतय", + "Uninstall package": "package अनस्थापय", + "Skip this version": "अयं version त्यज", + "Pause updates for": "अद्यतनानि विरमयतु", + "User | Local": "उपयोक्ता | स्थानीयम्", + "Machine | Global": "यन्त्रम् | वैश्विकम्", + "The default package manager for Debian/Ubuntu-based Linux distributions.
Contains: Debian/Ubuntu packages": "Debian/Ubuntu-आधारित Linux वितरणानां पूर्वनिर्धारित-पैकेज्-प्रबन्धकः।
अन्तर्गतम्: Debian/Ubuntu packages", + "The Rust package manager.
Contains: Rust libraries and programs written in Rust": "Rust इत्यस्य package manager.
अन्तर्भवति: Rust libraries तथा Rust मध्ये लिखितानि कार्यक्रमानि", + "The classical package manager for windows. You'll find everything there.
Contains: General Software": "Windows कृते पारम्परिकः package manager। तत्र सर्वं प्राप्स्यसि।
अन्तर्भवति: General Software", + "The default package manager for RHEL/Fedora-based Linux distributions.
Contains: RPM packages": "RHEL/Fedora-आधारित Linux वितरणानां पूर्वनिर्धारित-पैकेज्-प्रबन्धकः।
अन्तर्गतम्: RPM packages", + "A repository full of tools and executables designed with Microsoft's .NET ecosystem in mind.
Contains: .NET related tools and scripts": "Microsoft इत्यस्य .NET परिसंस्थां मनसि निधाय निर्मितैः tools तथा executables इत्येतैः पूर्णः repository
अन्तर्भवति: .NET सम्बन्धित tools तथा scripts", + "The universal Linux package manager for desktop applications.
Contains: Flatpak applications from configured remotes": "डेस्कटॉप-अनुप्रयोगानां कृते सार्वत्रिकः Linux पैकेज्-प्रबन्धकः।
समाविशति: विन्यस्त-दूरस्थस्थानेभ्यः Flatpak अनुप्रयोगान्", + "NuPkg (zipped manifest)": "NuPkg (सङ्कुचित manifest)", + "The Missing Package Manager for macOS (or Linux).
Contains: Formulae, Casks": "macOS (वा Linux) कृते लुप्तः Package Manager.
अन्तर्भवति: Formulae, Casks", + "Node JS's package manager. Full of libraries and other utilities that orbit the javascript world
Contains: Node javascript libraries and other related utilities": "Node JS इत्यस्य package manager। javascript-जगतः परिभ्रमन्तीभिः libraries तथा अन्याभिः utilities पूर्णः
अन्तर्भवति: Node javascript libraries तथा अन्याः सम्बद्ध-utilities", + "The default package manager for Arch Linux and its derivatives.
Contains: Arch Linux packages": "Arch Linux तथा तस्य व्युत्पन्नानां पूर्वनिर्धारित-पैकेज्-प्रबन्धकः।
अन्तर्गतम्: Arch Linux packages", + "Python's library manager. Full of python libraries and other python-related utilities
Contains: Python libraries and related utilities": "Python इत्यस्य library manager। python libraries तथा अन्याभिः python-सम्बद्ध-utilities इत्यैः पूर्णः
अन्तर्भवति: Python libraries and related utilities", + "PowerShell's package manager. Find libraries and scripts to expand PowerShell capabilities
Contains: Modules, Scripts, Cmdlets": "PowerShell इत्यस्य package manager। PowerShell क्षमताः विस्तरयितुं libraries तथा scripts अन्विष्यताम्
अन्तर्भवति: Modules, Scripts, Cmdlets", + "extracted": "उद्धृतम्", + "Scoop package": "Scoop पैकेज्", + "Great repository of unknown but useful utilities and other interesting packages.
Contains: Utilities, Command-line programs, General Software (extras bucket required)": "अज्ञातानाम् अपि उपयुक्तानां utilities तथा अन्येषां रोचकानां packages इत्येषां महान् repository अस्ति।
अन्तर्भवति: Utilities, Command-line programs, General Software (extras bucket required)", + "The universal Linux package manager by Canonical.
Contains: Snap packages from the Snapcraft store": "Canonical इत्यस्य सार्वभौमिकः Linux पैकेज्-प्रबन्धकः।
अन्तर्गतम्: Snapcraft भण्डारात् Snap packages", + "library": "पुस्तकालयः", + "feature": "विशेषता", + "A popular C/C++ library manager. Full of C/C++ libraries and other C/C++-related utilities
Contains: C/C++ libraries and related utilities": "प्रसिद्धः C/C++ पुस्तकालयप्रबन्धकः। C/C++ पुस्तकालयैः तथा अन्यैः C/C++ सम्बन्धितोपकरणैः पूर्णः
अन्तर्भवति: C/C++ पुस्तकालयाः तथा सम्बन्धितोपकरणानि", + "option": "विकल्पः", + "This package cannot be installed from an elevated context.": "अयं package elevated context तः स्थापयितुं न शक्यते।", + "Please run UniGetUI as a regular user and try again.": "कृपया UniGetUI सामान्य-उपयोक्तृरूपेण चालयित्वा पुनः प्रयतस्व।", + "Please check the installation options for this package and try again": "अस्य पैकेजस्य स्थापना-विकल्पान् परीक्ष्य पुनः प्रयतस्व", + "Microsoft's official package manager. Full of well-known and verified packages
Contains: General Software, Microsoft Store apps": "Microsoft इत्यस्य आधिकारिकः package manager। सुप्रसिद्धैः सत्यापितैश्च packages पूर्णः
अन्तर्भवति: सामान्य software, Microsoft Store apps", + "Local PC": "स्थानीय PC", + "Android Subsystem": "आण्ड्रायड् उपव्यवस्था", + "Operation on queue (position {0})...": "queue मध्ये operation ({0} स्थानम्)...", + "Click here for more details": "अधिकविवरणार्थम् अत्र क्लिक् करोतु", + "Operation canceled by user": "उपयोक्त्रा operation निरस्तम्", + "Running PreOperation ({0}/{1})...": "PreOperation ({0}/{1}) प्रचलति...", + "PreOperation {0} out of {1} failed, and was tagged as necessary. Aborting...": "{1} मध्ये PreOperation {0} विफलम् अभवत्, आवश्यकम् इति चिह्नितम् आसीत्। निरस्यते...", + "PreOperation {0} out of {1} finished with result {2}": "{1} मध्ये PreOperation {0} {2} परिणामेन समाप्तम्", + "Starting operation...": "operation आरभ्यते...", + "Running PostOperation ({0}/{1})...": "PostOperation ({0}/{1}) प्रचलति...", + "PostOperation {0} out of {1} failed, and was tagged as necessary. Aborting...": "{1} मध्ये PostOperation {0} विफलम् अभवत्, आवश्यकम् इति चिह्नितम् आसीत्। निरस्यते...", + "PostOperation {0} out of {1} finished with result {2}": "{1} मध्ये PostOperation {0} {2} परिणामेन समाप्तम्", + "{package} installer download": "{package} installer अवतरणम्", + "{0} installer is being downloaded": "{0} installer अवतार्यते", + "Download succeeded": "Download सफलम्", + "{package} installer was downloaded successfully": "{package} installer सफलतया अवतारितः", + "Download failed": "Download विफलम्", + "{package} installer could not be downloaded": "{package} installer अवतारयितुं न शक्यत", + "{package} Installation": "{package} स्थापना", + "{0} is being installed": "{0} स्थाप्यते", + "Installation succeeded": "स्थापनं सफलम्", + "{package} was installed successfully": "{package} सफलतया स्थापितम्", + "Installation failed": "स्थापनं विफलम्", + "{package} could not be installed": "{package} स्थापयितुं न शक्यत", + "{package} Update": "{package} अद्यतनम्", + "Update succeeded": "अद्यतनं सफलम्", + "{package} was updated successfully": "{package} सफलतया अद्यतितम्", + "Update failed": "अद्यतनं विफलम्", + "{package} could not be updated": "{package} अद्यतयितुं न शक्यत", + "{package} Uninstall": "{package} अनस्थापना", + "{0} is being uninstalled": "{0} अनस्थाप्यते", + "Uninstall succeeded": "अनस्थापनं सफलम्", + "{package} was uninstalled successfully": "{package} सफलतया अनस्थापितम्", + "Uninstall failed": "अनस्थापनं विफलम्", + "{package} could not be uninstalled": "{package} अनस्थापयितुं न शक्यत", + "Adding source {source}": "स्रोतः {source} योज्यते", + "Adding source {source} to {manager}": "{manager} मध्ये स्रोतः {source} योज्यते", + "Source added successfully": "स्रोतः सफलतया योजितः", + "The source {source} was added to {manager} successfully": "स्रोतः {source} सफलतया {manager} मध्ये योजितः", + "Could not add source": "स्रोतं योजयितुं न शक्यते", + "Could not add source {source} to {manager}": "{manager} मध्ये {source} स्रोतं योजयितुं न शक्यते", + "Removing source {source}": "स्रोतः {source} अपाक्रियते", + "Removing source {source} from {manager}": "{manager} तः स्रोतः {source} अपाक्रियते", + "Source removed successfully": "स्रोतः सफलतया अपाकृतः", + "The source {source} was removed from {manager} successfully": "स्रोतः {source} सफलतया {manager} तः अपाकृतः", + "Could not remove source": "स्रोतं अपसारयितुं न शक्यते", + "Could not remove source {source} from {manager}": "{manager} तः {source} स्रोतं अपसारयितुं न शक्यते", + "The package manager \"{0}\" was not found": "package manager \"{0}\" न लब्धः", + "The package manager \"{0}\" is disabled": "package manager \"{0}\" निष्क्रियः अस्ति", + "There is an error with the configuration of the package manager \"{0}\"": "package manager \"{0}\" इत्यस्य विन्यासे दोषः अस्ति", + "The package \"{0}\" was not found on the package manager \"{1}\"": "package manager \"{1}\" मध्ये package \"{0}\" न लब्धः", + "{0} is disabled": "{0} निष्क्रियः अस्ति", + "{0} weeks": "{0} सप्ताहाः", + "1 month": "1 मासः", + "{0} months": "{0} मासाः", + "Something went wrong": "किमपि विपरीतं जातम्", + "An interal error occurred. Please view the log for further details.": "आन्तरिकः दोषः अभवत्। कृपया विस्तृतविवरणाय लघुः पश्यतु।", + "No applicable installer was found for the package {0}": "package {0} कृते उपयुक्तः installer न लब्धः", + "Integrity checks will not be performed during this operation": "अस्मिन् कार्ये Integrity checks न क्रियन्ते", + "This is not recommended.": "एतत् न अनुशंस्यते।", + "Run now": "अधुना चालय", + "Run next": "अनन्तरं चालय", + "Run last": "अन्तिमं चालय", + "Show in explorer": "explorer मध्ये दर्शय", + "Checked": "चिह्नितम्", + "Unchecked": "अचिह्नितम्", + "This package is already installed": "अयं package पूर्वमेव स्थापितः अस्ति", + "This package can be upgraded to version {0}": "अयं package संस्करणं {0} पर्यन्तम् उन्नेयः अस्ति", + "Updates for this package are ignored": "अस्य package कृते अद्यतनानि उपेक्षितानि सन्ति", + "This package is being processed": "अयं package संसाध्यते", + "This package is not available": "अयं package उपलब्धः नास्ति", + "Select the source you want to add:": "यत् स्रोतः योजयितुम् इच्छसि तत् चयनय:", + "Source name:": "स्रोत-नाम:", + "Source URL:": "स्रोत-URL:", + "An error occurred when adding the source: ": "स्रोतं योजयतः दोषः अभवत्:", + "Package management made easy": "पैकेज्-प्रबन्धनं सुलभं कृतम्", + "version {0}": "संस्करणम् {0}", + "[RAN AS ADMINISTRATOR]": "[ADMINISTRATOR रूपेण चालितम्]", + "Portable mode": "पोर्टेबल्-मोडः\n", + "DEBUG BUILD": "DEBUG build", + "Here you can change UniGetUI's behaviour regarding the following shortcuts. Checking a shortcut will make UniGetUI delete it if if gets created on a future upgrade. Unchecking it will keep the shortcut intact": "अत्र भवान् निम्नलिखित-shortcuts विषये UniGetUI इत्यस्य व्यवहारं परिवर्तयितुं शक्नोति। shortcut चयनं कृत्वा यदि भविष्यात् upgrade काले तत् निर्मीयते तर्हि UniGetUI तत् अपासारयिष्यति। चयनं निष्कास्य shortcut अक्षुण्णं भविष्यति।", + "Manual scan": "हस्तचालित-स्कैन", + "Existing shortcuts on your desktop will be scanned, and you will need to pick which ones to keep and which ones to remove.": "भवतः desktop इत्यत्र विद्यमानाः shortcuts परीक्षिताः भविष्यन्ति, तथा च केषां रक्षणं कर्तव्यम्, केषां अपसारणं कर्तव्यम् इति त्वया चयनं करणीयम्।", + "Delete?": "अपाकरोतु?", + "I understand": "अहं बोधामि", + "Chocolatey setup changed": "Chocolatey विन्यासः परिवर्तितः", + "UniGetUI no longer includes its own private Chocolatey installation. A legacy UniGetUI-managed Chocolatey installation was detected for this user profile, but system Chocolatey was not found. Chocolatey will stay unavailable in UniGetUI until Chocolatey is installed on the system and UniGetUI is restarted. Applications previously installed through UniGetUI's bundled Chocolatey may still appear under other sources such as Local PC or WinGet.": "UniGetUI अधुना स्वस्य निजी Chocolatey स्थापनं न अन्तर्गतं करोति। अस्य उपयोक्तृ-प्रोफ़ाइल् कृते UniGetUI-प्रबन्धित-Chocolatey-स्थापनं ज्ञातम्, किन्तु system Chocolatey न लब्धम्। यावत् system मध्ये Chocolatey न स्थाप्यते UniGetUI च पुनः न आरभ्यते तावत् UniGetUI मध्ये Chocolatey अनुपलब्धं स्थास्यति। UniGetUI इत्यस्य बन्डल्ड् Chocolatey द्वारा पूर्वं स्थापिताः अनुप्रयोगाः Local PC अथवा WinGet इत्यादिषु अन्येषु स्रोतेषु दृश्यन्ते स्म।", + "NOTE: This troubleshooter can be disabled from UniGetUI Settings, on the WinGet section": "टिप्पणी: अयं troubleshooter UniGetUI Settings इत्यत्र WinGet विभागे निष्क्रियः कर्तुं शक्यते", + "Restart": "पुनरारभस्व", + "Are you sure you want to delete all shortcuts?": "किं भवन्तः सर्वान् shortcuts लोपयितुम् इच्छन्ति?", + "Any new shorcuts created during an install or an update operation will be deleted automatically, instead of showing a confirmation prompt the first time they are detected.": "स्थापने अथवा अद्यतनक्रियायां निर्मिताः नूतनाः shortcuts प्रथमवारं दृश्यन्ते चेत् confirmation prompt दर्शयितुं विना स्वयमेव लुप्यन्ते।", + "Any shorcuts created or modified outside of UniGetUI will be ignored. You will be able to add them via the {0} button.": "UniGetUI बहिः निर्मिताः अथवा परिवर्तिताः shortcuts उपेक्षिताः भविष्यन्ति। तान् {0} बटनस्य माध्यमेन योजयितुं शक्यते।", + "Are you really sure you want to enable this feature?": "किं भवन्तः एतां विशेषतां सचरितार्थतया सक्षमयितुम् इच्छन्ति?", + "No new shortcuts were found during the scan.": "scan काले नूतनानि shortcuts न लब्धानि।", + "How to add packages to a bundle": "bundle इत्यस्मिन् packages कथं योजनीयानि", + "In order to add packages to a bundle, you will need to: ": "bundle मध्ये packages योजयितुं भवता एतत् आवश्यकम्:", + "1. Navigate to the \"{0}\" or \"{1}\" page.": "1. \"{0}\" अथवा \"{1}\" पृष्ठं प्रति गच्छतु।", + "2. Locate the package(s) you want to add to the bundle, and select their leftmost checkbox.": "2. बण्डले योजयितुम् इच्छितानि पुटकानि अन्विष्य, तेषां वामभागस्थं checkbox चिनोतु।", + "3. When the packages you want to add to the bundle are selected, find and click the option \"{0}\" on the toolbar.": "3. बण्डले योजयितुम् इच्छितानि पुटकानि चयनितानि सन्ति चेत्, toolbar मध्ये \"{0}\" विकल्पं अन्विष्य क्लिक् करोतु।", + "4. Your packages will have been added to the bundle. You can continue adding packages, or export the bundle.": "4. भवतः पुटकानि बण्डले योजितानि भविष्यन्ति। भवन्तः अन्यानि पुटकानि अपि योजयितुं वा बण्डलम् निर्यातयितुं शक्नुवन्ति।", + "Which backup do you want to open?": "कं backup उद्घाटयितुम् इच्छसि?", + "Select the backup you want to open. Later, you will be able to review which packages you want to install.": "यत् backup उद्घाटयितुम् इच्छसि तत् चयनय। पश्चात् केषु packages स्थापनीयाः इति समीक्षितुं शक्नोषि।", + "There are ongoing operations. Quitting UniGetUI may cause them to fail. Do you want to continue?": "प्रचलिताः operations सन्ति। UniGetUI त्यागेन ताः विफलाः भवेयुः। किं त्वम् अग्रे गन्तुम् इच्छसि?", + "UniGetUI or some of its components are missing or corrupt.": "UniGetUI अथवा तस्य केचन components अनुपस्थिताः अथवा भ्रष्टाः सन्ति।", + "It is strongly recommended to reinstall UniGetUI to adress the situation.": "अस्य स्थितेः समाधानाय UniGetUI पुनः स्थापयितुं दृढतया अनुशंस्यते।", + "Refer to the UniGetUI Logs to get more details regarding the affected file(s)": "प्रभावित-file(s) विषये अधिक-विवरणानि प्राप्तुं UniGetUI Logs प्रति सन्दर्भं कुरु", + "Integrity checks can be disabled from the Experimental Settings": "Integrity checks Experimental Settings तः निष्क्रियं कर्तुं शक्यन्ते", + "Repair UniGetUI": "UniGetUI मरम्मतु", + "Live output": "सजीव output", + "This package bundle had some settings that are potentially dangerous, and may be ignored by default.": "अस्मिन् package bundle मध्ये केचन settings सम्भावित-जोखिमपूर्णाः आसन्, अतः ते पूर्वनिर्धारितरूपेण उपेक्षिताः भवितुम् अर्हन्ति।", + "Entries that show in YELLOW will be IGNORED.": "याः entries YELLOW वर्णेन दृश्यन्ते ताः IGNORED भविष्यन्ति।", + "Entries that show in RED will be IMPORTED.": "याः entries RED वर्णेन दृश्यन्ते ताः IMPORTED भविष्यन्ति।", + "You can change this behavior on UniGetUI security settings.": "एतत् व्यवहारं UniGetUI security settings मध्ये परिवर्तयितुं शक्यते।", + "Open UniGetUI security settings": "UniGetUI सुरक्षा-settings उद्घाटय", + "Should you modify the security settings, you will need to open the bundle again for the changes to take effect.": "यदि त्वं security settings परिवर्तयसि, तर्हि परिवर्तनानां प्रभावाय bundle पुनरपि उद्घाटयितुं आवश्यकम्।", + "Details of the report:": "प्रतिवेदनस्य विवरणानि:", + "Are you sure you want to create a new package bundle? ": "किं भवन्तः नूतनं package bundle निर्मातुम् इच्छन्ति? ", + "Any unsaved changes will be lost": "असुरक्षिताः सर्वे परिवर्तनाः नष्टाः भविष्यन्ति", + "Warning!": "चेतावनी!", + "For security reasons, custom command-line arguments are disabled by default. Go to UniGetUI security settings to change this. ": "सुरक्षार्थं custom command-line arguments मूलतः निष्क्रियीकृतानि सन्ति। एतत् परिवर्तयितुं UniGetUI security settings गच्छतु। ", + "Change default options": "पूर्वनिर्धारित-विकल्पान् परिवर्तयतु", + "Ignore future updates for this package": "अस्य package इत्यस्य भविष्यत्-updates उपेक्षध्वम्", + "For security reasons, pre-operation and post-operation scripts are disabled by default. Go to UniGetUI security settings to change this. ": "सुरक्षार्थं pre-operation तथा post-operation scripts मूलतः निष्क्रियीकृतानि सन्ति। एतत् परिवर्तयितुं UniGetUI security settings गच्छतु। ", + "You can define the commands that will be run before or after this package is installed, updated or uninstalled. They will be run on a command prompt, so CMD scripts will work here.": "अस्य package स्थापना, अद्यतन, अनस्थापनयोः पूर्वं पश्चात् वा याः commands चलिष्यन्ति ताः त्वं निर्दिष्टुं शक्नोषि। ताः command prompt मध्ये चलिष्यन्ति, अतः CMD scripts अत्र कार्यं करिष्यन्ति।", + "Change this and unlock": "एतत् परिवर्त्य unlock कुरुत", + "{0} Install options are currently locked because {0} follows the default install options.": "{0} स्थापना-विकल्पाः अधुना locked सन्ति यतः {0} पूर्वनिर्धारित-स्थापना-विकल्पान् अनुसरति।", + "Unset or unknown": "अनिर्धारितम् अथवा अज्ञातम्", + "This package has no screenshots or is missing the icon? Contrbute to UniGetUI by adding the missing icons and screenshots to our open, public database.": "अस्य package इत्यस्य screenshots न सन्ति अथवा icon अनुपस्थितम्? अस्माकं उन्मुक्त-सार्वजनिक-database मध्ये अनुपस्थित-icons तथा screenshots योजयित्वा UniGetUI प्रति योगदानं कुरु।", + "Become a contributor": "योगदातारं भव", + "Update to {0} available": "{0} पर्यन्तम् अद्यतनम् उपलब्धम्", + "Reinstall": "पुनः स्थापय", + "Installer not available": "Installer उपलब्धः नास्ति", + "Version:": "संस्करणम्:", + "UniGetUI Version {0}": "UniGetUI संस्करणम् {0}", + "Performing backup, please wait...": "backup क्रियते, कृपया प्रतीक्षस्व...", + "An error occurred while logging in: ": "login कुर्वतः दोषः अभवत्: ", + "Fetching available backups...": "उपलब्ध-backups आनीयन्ते...", + "Done!": "समाप्तम्!", + "The cloud backup has been loaded successfully.": "cloud backup सफलतया load कृतः।", + "An error occurred while loading a backup: ": "backup लोड् कुर्वतः दोषः अभवत्: ", + "Backing up packages to GitHub Gist...": "पुटकानि GitHub Gist मध्ये backup क्रियन्ते...", + "Backup Successful": "backup सफलम्", + "The cloud backup completed successfully.": "cloud backup सफलतया सम्पन्नः।", + "Could not back up packages to GitHub Gist: ": "पुटकानि GitHub Gist मध्ये backup कर्तुं न शक्यते: ", + "It is not guaranteed that the provided credentials will be stored safely, so you may as well not use the credentials of your bank account": "प्रदत्त credentials सुरक्षितरूपेण रक्षितानि भविष्यन्ति इति न सुनिश्चितम्, अतः बैंक-खातस्य credentials मा उपयोजयतु।", + "Enable the automatic WinGet troubleshooter": "स्वयंचलित WinGet troubleshooter सक्रियीकुरुत", + "Add updates that fail with a 'no applicable update found' to the ignored updates list": "'no applicable update found' इति कारणेन विफलानि अद्यतनानि उपेक्षित-अद्यतन-सूच्यां योजयतु", + "Invalid selection": "अमान्य-चयनम्", + "No package was selected": "किमपि package न चयनितम्", + "More than 1 package was selected": "एकात् अधिकं package चयनितम्", + "List": "सूची", + "Grid": "जालकम्", + "Icons": "चिह्नानि", + "\"{0}\" is a local package and does not have available details": "\"{0}\" स्थानिकं पुटकं अस्ति, तस्य उपलब्धविवरणानि न सन्ति", + "\"{0}\" is a local package and is not compatible with this feature": "\"{0}\" स्थानिकं पुटकं अस्ति, एतया विशेषतया सह न सुसंगतम्", + "Add packages to bundle": "बण्डले पुटकानि योजयतु", + "Preparing packages, please wait...": "पैकेजाः सज्जीकुर्वन्ते, कृपया प्रतीक्षस्व...", + "Loading packages, please wait...": "packages load क्रियन्ते, कृपया प्रतीक्षताम्...", + "Saving packages, please wait...": "पैकेजाः संगृह्यन्ते, कृपया प्रतीक्षस्व...", + "The bundle was created successfully on {0}": "bundle {0} तस्मिन् सफलतया निर्मितम्", + "User profile": "उपयोक्तृ-प्रोफाइल्", + "Error": "त्रुटिः", + "Log in failed: ": "प्रवेशः विफलः:", + "Log out failed: ": "निर्गमनं विफलम्:", + "Package backup settings": "पैकेज्-backup settings", + "Package managers": "पैकेज्-प्रबन्धकाः", + "Manage UniGetUI autostart behaviour from the Settings app": "UniGetUI स्वयमारम्भ-व्यवहारं प्रबन्धय", + "Choose how many operations shoulds be performed in parallel": "कियत् क्रियाः समकालिकरूपेण क्रियेरन् इति चयनय", + "Something went wrong while launching the updater.": "updater आरम्भयन् किमपि विपरीतं जातम्।", + "Please try again later": "कृपया पश्चात् पुनः प्रयतस्व", + "Show the release notes after UniGetUI is updated": "UniGetUI नवीनीकृते सति प्रकाशन-टिप्पण्यः दर्शयतु" +} diff --git a/src/Languages/lang_si.json b/src/Languages/lang_si.json new file mode 100644 index 0000000..2c2b399 --- /dev/null +++ b/src/Languages/lang_si.json @@ -0,0 +1,851 @@ +{ + "{0} of {1} operations completed": "මෙහෙයුම් {1} කින් {0} ක් සම්පූර්ණ විය", + "{0} is now {1}": "{0} දැන් {1} වේ", + "Enabled": "සක්‍රීයයි", + "Disabled": "අක්‍රීයයි", + "Privacy": "පෞද්ගලිකත්වය", + "Hide my username from the logs": "logs වලින් මගේ පරිශීලක නාමය සඟවන්න", + "Replaces your username with **** in the logs. Restart UniGetUI to also hide it from already-recorded entries.": "logs තුළ ඔබේ පරිශීලක නාමය **** මගින් ප්‍රතිස්ථාපනය කරයි. දැනටමත් සටහන් කළ ඇතුළත් කිරීම් වලින් ද එය සැඟවීමට UniGetUI නැවත ආරම්භ කරන්න.", + "Your last update attempt did not complete.": "ඔබගේ අවසන් යාවත්කාලීන කිරීමේ උත්සාහය සම්පූර්ණ නොවීය.", + "UniGetUI could not confirm whether the update succeeded. Open the log to see what happened.": "යාවත්කාලීන කිරීම සාර්ථක වූවාදැයි UniGetUI තහවුරු කළ නොහැකි විය. සිදු වූ දේ බැලීමට ලොගය විවෘත කරන්න.", + "View log": "ලොගය බලන්න", + "The installer reported success but did not restart UniGetUI.": "ස්ථාපකය සාර්ථක බව වාර්තා කළ නමුත් UniGetUI නැවත ආරම්භ නොකළේය.", + "The installer failed to initialize.": "ස්ථාපකය ආරම්භ කිරීමට අසමත් විය.", + "Setup was canceled before installation began.": "ස්ථාපනය ආරම්භ වීමට පෙර සැකසුම අවලංගු කරන ලදී.", + "A fatal error occurred during the preparation phase.": "සූදානම් කිරීමේ අදියරේදී මාරක දෝෂයක් ඇති විය.", + "A fatal error occurred during installation.": "ස්ථාපනය අතරතුර මාරක දෝෂයක් ඇති විය.", + "Installation was canceled while in progress.": "ස්ථාපනය ක්‍රියාත්මක වෙමින් තිබියදී අවලංගු කරන ලදී.", + "The installer was terminated by another process.": "ස්ථාපකය වෙනත් process එකක් මගින් අවසන් කරන ලදී.", + "The preparation phase determined the installation cannot proceed.": "සූදානම් කිරීමේ අදියරේදී ස්ථාපනය ඉදිරියට ගෙන යා නොහැකි බව තීරණය විය.", + "The installer could not start. UniGetUI may already be running, or you do not have permission to install.": "ස්ථාපකය ආරම්භ කළ නොහැකි විය. UniGetUI දැනටමත් ධාවනය වෙමින් තිබිය හැක, නැතහොත් ස්ථාපනය කිරීමට ඔබට අවසර නොමැති විය හැක.", + "Unexpected installer error.": "බලාපොරොත්තු නොවූ ස්ථාපක දෝෂයක්.", + "We are checking for updates.": "අපි යාවත්කාලීන සඳහා පරීක්ෂා කරමින් සිටිමු.", + "Please wait": "කරුණාකර රැඳී සිටින්න", + "Great! You are on the latest version.": "විශිෂ්ටයි! ඔබ නවතම සංස්කරණය භාවිතා කරයි.", + "There are no new UniGetUI versions to be installed": "ස්ථාපනය කිරීමට නව UniGetUI versions නොමැත", + "UniGetUI version {0} is being downloaded.": "UniGetUI version {0} බාගත කරමින් පවතී.", + "This may take a minute or two": "මෙයට මිනිත්තුවක් හෝ දෙකක් ගත විය හැක", + "The installer authenticity could not be verified.": "installer හි සත්‍යතාව තහවුරු කළ නොහැකි විය.", + "The update process has been aborted.": "update process එක අත්හිටුවා ඇත.", + "Auto-update is not yet available on this platform.": "මෙම වේදිකාවේ ස්වයංක්‍රීය යාවත්කාලීන කිරීම තවම ලබාගත නොහැක.", + "Please update UniGetUI manually.": "කරුණාකර UniGetUI අතින් යාවත්කාලීන කරන්න.", + "An error occurred when checking for updates: ": "යාවත්කාලීන පරීක්ෂා කිරීමේදී දෝෂයක් ඇති විය: ", + "The updater could not be launched.": "යාවත්කාලීනකය ආරම්භ කළ නොහැකි විය.", + "The operating system did not start the installer process.": "මෙහෙයුම් පද්ධතිය ස්ථාපක process එක ආරම්භ නොකළේය.", + "UniGetUI is being updated...": "UniGetUI යාවත්කාලීන වෙමින් පවතී...", + "Update installed.": "යාවත්කාලීනය ස්ථාපනය කරන ලදී.", + "UniGetUI was updated successfully, but this running copy was not replaced. This usually means you are running a development build. Close this copy and start the newly-installed version to finish.": "UniGetUI සාර්ථකව යාවත්කාලීන කරන ලදී, නමුත් මේ ධාවනය වන පිටපත ප්‍රතිස්ථාපනය කර නොමැත. මෙය සාමාන්‍යයෙන් ඔබ development build එකක් ධාවනය කරන බව අදහස් කරයි. අවසන් කිරීමට මෙම පිටපත වසා අලුතින් ස්ථාපනය කළ සංස්කරණය ආරම්භ කරන්න.", + "The update could not be applied.": "යාවත්කාලීනය යෙදිය නොහැකි විය.", + "Installer exit code {0}: {1}": "ස්ථාපක exit code {0}: {1}", + "Update cancelled.": "යාවත්කාලීන කිරීම අවලංගු කරන ලදී.", + "Authentication was cancelled.": "සත්‍යාපනය අවලංගු කරන ලදී.", + "Installer exit code {0}": "ස්ථාපක exit code {0}", + "Operation in progress": "මෙහෙයුම ක්‍රියාත්මක වෙමින් පවතී", + "Please wait...": "කරුණාකර රැඳී සිටින්න...", + "Success!": "සාර්ථකයි!", + "Failed": "අසාර්ථකයි", + "An error occurred while processing this package": "මෙම පැකේජය සැකසීමේදී දෝෂයක් ඇති විය", + "Installer": "ස්ථාපකය", + "Executable": "ක්‍රියාත්මක කළ හැකි ගොනුව", + "MSI": "MSI", + "Compressed file": "සම්පීඩිත ගොනුව", + "MSIX": "MSIX", + "WinGet was repaired successfully": "WinGet සාර්ථකව අලුත්වැඩියා කරන ලදී", + "It is recommended to restart UniGetUI after WinGet has been repaired": "WinGet අලුත්වැඩියා කළ පසු UniGetUI නැවත ආරම්භ කිරීම නිර්දේශ කෙරේ", + "WinGet could not be repaired": "WinGet අලුත්වැඩියා කළ නොහැකි විය", + "An unexpected issue occurred while attempting to repair WinGet. Please try again later": "WinGet අලුත්වැඩියා කිරීමට උත්සාහ කිරීමේදී බලාපොරොත්තු නොවූ ගැටලුවක් ඇති විය. කරුණාකර පසුව නැවත උත්සාහ කරන්න", + "Log in to enable cloud backup": "cloud backup සක්‍රීය කිරීමට පිවිසෙන්න", + "Backup Failed": "උපස්ථය අසාර්ථකයි", + "Downloading backup...": "උපස්ථය බාගත කරමින්...", + "An update was found!": "නව යාවත්කාලීන කිරීමක් හමු විය", + "{0} can be updated to version {1}": "{0} {1} සංස්කරණයට යාවත්කාලීන කළ හැක", + "Updates found!": "යාවත්කාලීන හමු විය!", + "{0} packages can be updated": "{0}ක් ඇසුරුම් යාවත්කාලීන කල හැක ", + "{0} is being updated to version {1}": "{0} {1} සංස්කරණයට යාවත්කාලීන කරමින් පවතී", + "{0} packages are being updated": "{0}ක් ඇසුරුම් යාවත්කාලීන වෙමින් පවතී ", + "You have currently version {0} installed": "ඔබට දැනට version {0} ස්ථාපිත කර ඇත", + "Desktop shortcut created": "Desktop shortcut සාදන ලදී", + "UniGetUI has detected a new desktop shortcut that can be deleted automatically.": "ස්වයංක්‍රීයව මකා දැමිය හැකි නව desktop shortcut එකක් UniGetUI හඳුනාගෙන ඇත.", + "{0} desktop shortcuts created": "{0} desktop shortcuts නිර්මාණය කර ඇත", + "UniGetUI has detected {0} new desktop shortcuts that can be deleted automatically.": "ස්වයංක්‍රීයව මකා දැමිය හැකි නව desktop shortcuts {0} ක් UniGetUI හඳුනාගෙන ඇත.", + "Attention required": "අවධානය අවශ්‍යයි.", + "Restart required": "නැවත ආරම්භ කිරීම අවශ්‍යයි", + "1 update is available": "යාවත්කාලීන කිරීම් 1ක් ඇත", + "{0} updates are available": "යාවත්කාලීන {0} ක් ලබාගත හැක", + "Everything is up to date": "සියල්ල යාවත්කාලීනව ඇත", + "Discover Packages": "පැකේජ සොයන්න", + "Available Updates": "යාවත්කාලීන කිරීම්", + "Installed Packages": "ස්ථාපිත පැකේජ", + "UniGetUI Version {0} by Devolutions": "Devolutions විසින් UniGetUI අනුවාදය {0}", + "Show UniGetUI": "UniGetUI පෙන්වන්න", + "Quit": "ඉවත් වන්න", + "Are you sure?": "ඔබට විශ්වාසද?", + "Do you really want to uninstall {0}?": "{0} අස්ථාපනය කිරීමට ඔබට ඇත්තටම අවශ්‍යද?", + "Do you really want to uninstall the following {0} packages?": "පහත {0} පැකේජ අස්ථාපනය කිරීමට ඔබට ඇත්තටම අවශ්‍යද?", + "No": "නැහැ", + "Yes": "ඔව්", + "Partial": "අර්ධව", + "View on UniGetUI": "UniGetUI තුළ බලන්න", + "Update": "යාවත්කාලීන කරන්න", + "Open UniGetUI": "UniGetUI විවෘත කරන්න", + "Update all": "සියල්ල යාවත්කාලීන කරන්න", + "Update now": "දැන් යාවත්කාලීන කරන්න", + "Installer host changed since the installed version.\n": "ස්ථාපිත සංස්කරණයෙන් පසු ස්ථාපක host වෙනස් වී ඇත.\n", + "This package is on the queue": "මෙම පැකේජය queue එකේ ඇත", + "installing": "ස්ථාපනය කරමින්", + "updating": "යාවත්කාලීන කරමින්", + "uninstalling": "uninstall කරමින්", + "installed": "ස්ථාපිතයි", + "Retry": "නැවත උත්සාහ කරන්න", + "Install": "ස්ථාපනය කරන්න", + "Uninstall": "ඉවත් කරන්න", + "Open": "විවෘත කරන්න", + "Operation profile:": "මෙහෙයුම් profile:", + "Follow the default options when installing, upgrading or uninstalling this package": "මෙම පැකේජය ස්ථාපනය, උසස් කිරීම හෝ අස්ථාපනය කිරීමේදී පෙරනිමි විකල්ප අනුගමනය කරන්න", + "The following settings will be applied each time this package is installed, updated or removed.": "මෙම පැකේජය ස්ථාපනය, යාවත්කාලීන හෝ ඉවත් කරන සෑම වරම පහත සැකසුම් යෙදේ.", + "Version to install:": "ස්ථාපනය කිරීමට සංස්කරණය:", + "Architecture to install:": "ස්ථාපනය කිරීමට architecture:", + "Installation scope:": "ස්ථාපන ව්‍යාප්තිය:", + "Install location:": "ස්ථාපන ස්ථානය:", + "Select": "තෝරන්න", + "Reset": "Reset කරන්න", + "Custom install arguments:": "අභිරුචි ස්ථාපන arguments:", + "Custom update arguments:": "අභිරුචි යාවත්කාලීන arguments:", + "Custom uninstall arguments:": "අභිරුචි අස්ථාපන arguments:", + "Pre-install command:": "ස්ථාපනයට පෙර command:", + "Post-install command:": "ස්ථාපනයෙන් පසු command:", + "Abort install if pre-install command fails": "pre-install විධානය අසාර්ථක වුවහොත් ස්ථාපනය නවත්වන්න", + "Pre-update command:": "යාවත්කාලීන කිරීමට පෙර command:", + "Post-update command:": "යාවත්කාලීන කිරීමෙන් පසු command:", + "Abort update if pre-update command fails": "pre-update විධානය අසාර්ථක වුවහොත් යාවත්කාලීන කිරීම නවත්වන්න", + "Pre-uninstall command:": "uninstall කිරීමට පෙර command:", + "Post-uninstall command:": "uninstall කිරීමෙන් පසු command:", + "Abort uninstall if pre-uninstall command fails": "pre-uninstall විධානය අසාර්ථක වුවහොත් අස්ථාපනය නවත්වන්න", + "Command-line to run:": "ධාවනය කිරීමට command-line:", + "Save and close": "සුරකින්න සහ වසන්න", + "General": "සාමාන්‍ය", + "Architecture & Location": "ව්‍යුහය සහ ස්ථානය", + "Command-line": "විධාන පේළිය", + "Close apps": "යෙදුම් වසන්න", + "Pre/Post install": "පෙර/පසු ස්ථාපනය", + "Select the processes that should be closed before this package is installed, updated or uninstalled.": "මෙම පැකේජය ස්ථාපනය, යාවත්කාලීන හෝ අස්ථාපනය කිරීමට පෙර වසා දැමිය යුතු processes තෝරන්න.", + "Write here the process names here, separated by commas (,)": "මෙහි process නාම comma (,) මගින් වෙන් කර ලියන්න", + "Try to kill the processes that refuse to close when requested to": "වසා දමන්නැයි ඉල්ලා සිටින විට වසා නොදමන processes අවසන් කිරීමට උත්සාහ කරන්න", + "Run as admin": "admin ලෙස ධාවනය කරන්න", + "Interactive installation": "Interactive ස්ථාපනය", + "Skip hash check": "hash check මඟ හරින්න", + "Uninstall previous versions when updated": "update කරන විට පෙර versions uninstall කරන්න", + "Skip minor updates for this package": "මෙම පැකේජය සඳහා සුළු යාවත්කාලීන මඟ හරින්න", + "Automatically update this package": "මෙම පැකේජය ස්වයංක්‍රීයව යාවත්කාලීන කරන්න", + "{0} installation options": "{0} ස්ථාපන විකල්ප", + "Latest": "නවතම", + "PreRelease": "පූර්ව-නිකුතු", + "Default": "පෙරනිමි", + "Manage ignored updates": "නොසලකා හරින ලද යාවත්කාලීන කළමනාකරණය කරන්න", + "The packages listed here won't be taken in account when checking for updates. Double-click them or click the button on their right to stop ignoring their updates.": "මෙහි ලැයිස්තුගත කළ පැකේජ updates පරීක්ෂා කිරීමේදී සැලකිල්ලට ගනු නොලැබේ. ඒවා දෙවරක් ක්ලික් කරන්න හෝ දකුණු පැත්තේ බොත්තම ක්ලික් කර එම updates නොසලකා හැරීම නවත්වන්න.", + "Reset list": "ලැයිස්තුව reset කරන්න", + "Do you really want to reset the ignored updates list? This action cannot be reverted": "නොසලකා හරින ලද යාවත්කාලීන ලැයිස්තුව යළි පිහිටුවීමට ඔබට ඇත්තටම අවශ්‍යද? මෙම ක්‍රියාව ආපසු හැරවිය නොහැක", + "No ignored updates": "නොසලකා හරින ලද යාවත්කාලීන නොමැත", + "Package Name": "පැකේජ නම", + "Package ID": "පැකේජ ID", + "Ignored version": "නොසලකා හරින ලද සංස්කරණය", + "New version": "නව සංස්කරණය", + "Source": "මූලාශ්‍රය", + "All versions": "සියලු සංස්කරණ ", + "Unknown": "නොදනී", + "Up to date": "යාවත්කාලීනයි", + "Package {name} from {manager}": "{manager} වෙතින් {name} පැකේජය", + "Remove {0} from ignored updates": "{0} නොසලකා හරින ලද යාවත්කාලීන වලින් ඉවත් කරන්න", + "Cancel": "අවලංගු කරන්න", + "Administrator privileges": "පරිපාලක බලතල ", + "This operation is running with administrator privileges.": "මෙම මෙහෙයුම පරිපාලක බලතල සමඟ ක්‍රියාත්මක වෙමින් පවතී.", + "Interactive operation": "Interactive මෙහෙයුම", + "This operation is running interactively.": "මෙම මෙහෙයුම interactive ආකාරයෙන් ක්‍රියාත්මක වෙමින් පවතී.", + "You will likely need to interact with the installer.": "ඔබට බොහෝවිට installer සමඟ අන්තර්ක්‍රියා කිරීමට සිදුවේ.", + "Integrity checks skipped": "Integrity checks මඟ හරින ලදි", + "Integrity checks will not be performed during this operation.": "මෙම මෙහෙයුම අතරතුර integrity checks සිදු නොකෙරේ.", + "Proceed at your own risk.": "ඔබගේම අවදානම මත ඉදිරියට යන්න.", + "Close": "වසා දමන්න", + "Loading...": "පූරණය කරමින්...", + "Installer SHA256": "Installer SHA256 අගය", + "Homepage": "මුල් පිටුව", + "Author": "කර්තෘ", + "Publisher": "ප්‍රකාශකයා", + "License": "බලපත්‍රය", + "Manifest": "Manifest ගොනුව", + "Installer Type": "Installer වර්ගය", + "Size": "ප්‍රමාණය", + "Installer URL": "Installer URL ලිපිනය", + "Last updated:": "අවසන් යාවත්කාලීන කළේ:", + "Release notes URL": "නිකුතු සටහන් URL", + "Package details": "පැකේජ විස්තර", + "Dependencies:": "අවශ්‍යතා:", + "Release notes": "නිකුතු සටහන්", + "Screenshots": "තිර රූප", + "This package has no screenshots or is missing the icon? Contribute to UniGetUI by adding the missing icons and screenshots to our open, public database.": "මෙම පැකේජයට තිර රූප නොමැතිද, නැතිනම් අයිකනය අස්ථානගතද? අස්ථානගත අයිකන සහ තිර රූප අපගේ විවෘත, පොදු දත්තගබඩාවට එක් කරමින් UniGetUI වෙත දායක වන්න.", + "Version": "සංස්කරණය", + "Install as administrator": "පරිපාලක ලෙස ස්ථාපනය කරන්න", + "Update to version {0}": "{0} සංස්කරණයට යාවත්කාලීන කරන්න", + "Installed Version": "ස්ථාපිත සංස්කරණය", + "Update as administrator": "පරිපාලක ලෙස යාවත්කාලීන කරන්න", + "Interactive update": "Interactive යාවත්කාලීනය", + "Uninstall as administrator": "පරිපාලක ලෙස uninstall කරන්න", + "Interactive uninstall": "Interactive අස්ථාපනය", + "Uninstall and remove data": "uninstall කර දත්ත ඉවත් කරන්න", + "Not available": "ලබාගත නොහැක", + "Installer SHA512": "Installer SHA512 අගය", + "Unknown size": "නොදන්නා ප්‍රමාණය", + "No dependencies specified": "dependencies කිසිවක් සඳහන් කර නොමැත", + "mandatory": "අනිවාර්ය", + "optional": "විකල්ප", + "UniGetUI {0} is ready to be installed.": "UniGetUI {0} ස්ථාපනය කිරීමට සූදානම්ය.", + "The update process will start after closing UniGetUI": "UniGetUI වසා දැමූ පසු update process එක ආරම්භ වේ", + "UniGetUI has been ran as administrator, which is not recommended. When running UniGetUI as administrator, EVERY operation launched from UniGetUI will have administrator privileges. You can still use the program, but we highly recommend not running UniGetUI with administrator privileges.": "UniGetUI පරිපාලක ලෙස ධාවනය කර ඇත, එය නිර්දේශ නොකෙරේ. UniGetUI පරිපාලක ලෙස ධාවනය කරන විට, UniGetUI වෙතින් ආරම්භ කරන සියලුම මෙහෙයුම් පරිපාලක බලතල සමඟ ක්‍රියාත්මක වේ. ඔබට තවමත් වැඩසටහන භාවිතා කළ හැකි නමුත්, UniGetUI පරිපාලක බලතල සමඟ ධාවනය නොකිරීම තදින්ම නිර්දේශ කරමු.", + "Share anonymous usage data": "අනාමික භාවිත දත්ත බෙදාගන්න", + "UniGetUI collects anonymous usage data in order to improve the user experience.": "පරිශීලක අත්දැකීම වැඩිදියුණු කිරීම සඳහා UniGetUI අනාමික භාවිත දත්ත රැස් කරයි.", + "Accept": "එකඟ වන්න", + "Software Updates": "මෘදුකාංග යාවත්කාලීන", + "Package Bundles": "පැකේජ bundles", + "Settings": "සැකසුම්", + "Package Managers": "පැකේජ කළමනාකරුවන්", + "UniGetUI Log": "UniGetUI ලොගය", + "Package Manager logs": "පැකේජ කළමනාකරු logs", + "Operation history": "මෙහෙයුම් ඉතිහාසය", + "Help": "උපදෙස්", + "UniGetUI": "UniGetUI", + "You have installed UniGetUI Version {0}": "ඔබ UniGetUI Version {0} ස්ථාපනය කර ඇත", + "Disclaimer": "වියාචනය", + "UniGetUI is developed by Devolutions and is not affiliated with any of the compatible package managers.": "UniGetUI Devolutions විසින් සංවර්ධනය කර ඇති අතර, අනුකූල පැකේජ කළමනාකරුවන් කිසිවක් සමඟ අනුබද්ධ නොවේ.", + "UniGetUI wouldn't have been possible without the help of the contributors. Thank you all 🥳": "දායකයින්ගේ සහාය නොමැතිව UniGetUI හැකි නොවනු ඇත. ඔබ සැමට ස්තුතියි 🥳", + "UniGetUI uses the following libraries. Without them, UniGetUI wouldn't have been possible.": "UniGetUI පහත libraries භාවිතා කරයි. ඒවා නොමැතිව UniGetUI තිබීමට නොහැකි විය.", + "{0} homepage": "{0} මුල් පිටුව", + "UniGetUI has been translated to more than 40 languages thanks to the volunteer translators. Thank you 🤝": "ස්වේච්ඡා පරිවර්තකයන්ගේ շնորհයෙන් UniGetUI භාෂා 40 කට වඩා වැඩි ගණනකට පරිවර්තනය කර ඇත. ස්තුතියි 🤝", + "Verbose": "සවිස්තරාත්මක", + "1 - Errors": "1 - දෝෂ", + "2 - Warnings": "2 - අනතුරු ඇඟවීම්", + "3 - Information (less)": "3 - තොරතුරු (අඩු)", + "4 - Information (more)": "4 - තොරතුරු (වැඩි)", + "5 - information (debug)": "5 - තොරතුරු (debug)", + "Warning": "අවවාදය", + "The following settings may pose a security risk, hence they are disabled by default.": "පහත සැකසුම් ආරක්ෂක අවදානමක් ඇති කළ හැකි බැවින්, ඒවා පෙරනිමියෙන් අක්‍රීයයි.", + "Enable the settings below if and only if you fully understand what they do, and the implications they may have.": "පහත සැකසුම් සක්‍රීය කරන්න, ඔබ ඒවා කරන දේ සහ ඇති විය හැකි ප්‍රතිවිපාක සම්පූර්ණයෙන්ම තේරුම් ගන්නේ නම් පමණි.", + "The settings will list, in their descriptions, the potential security issues they may have.": "සැකසුම්වල විස්තර තුළ ඒවාට තිබිය හැකි ආරක්ෂක ගැටලු ලැයිස්තුගත කරනු ඇත.", + "The backup will include the complete list of the installed packages and their installation options. Ignored updates and skipped versions will also be saved.": "backup එකේ ස්ථාපිත පැකේජවල සම්පූර්ණ ලැයිස්තුව සහ ඒවායේ ස්ථාපන විකල්ප අඩංගු වේ. නොසලකා හරින ලද යාවත්කාලීන සහ skip කළ versions ද සුරකිනු ලැබේ.", + "The backup will NOT include any binary file nor any program's saved data.": "backup එකේ කිසිදු binary ගොනුවක් හෝ කිසිදු වැඩසටහනක සුරකින ලද දත්ත අඩංගු නොවේ.", + "The size of the backup is estimated to be less than 1MB.": "backup එකේ ප්‍රමාණය 1MB ට අඩු වනු ඇතැයි ඇස්තමේන්තු කර ඇත.", + "The backup will be performed after login.": "login වූ පසුව backup එක සිදු කෙරේ.", + "{pcName} installed packages": "{pcName} හි ස්ථාපිත පැකේජ", + "Current status: Not logged in": "වත්මන් තත්ත්වය: පිවිසී නැත", + "You are logged in as {0} (@{1})": "ඔබ {0} (@{1}) ලෙස පිවිසී ඇත", + "Nice! Backups will be uploaded to a private gist on your account": "හොඳයි! backup ඔබගේ ගිණුමේ private gist එකකට upload කෙරේ", + "Select backup": "backup තෝරන්න", + "Settings imported from {0}": "{0} වෙතින් සැකසුම් ආයාත කරන ලදී", + "UniGetUI Settings": "UniGetUI සැකසුම්", + "Settings exported to {0}": "{0} වෙත සැකසුම් නිර්යාත කරන ලදී", + "UniGetUI settings were reset": "UniGetUI සැකසුම් යළි පිහිටුවන ලදී", + "Allow pre-release versions": "pre-release සංස්කරණ සඳහා ඉඩ දෙන්න", + "Apply": "යොදන්න", + "For security reasons, custom command-line arguments are disabled by default. Go to UniGetUI security settings to change this.": "ආරක්ෂක හේතු මත අභිරුචි command-line arguments පෙරනිමියෙන් අක්‍රීය කර ඇත. මෙය වෙනස් කිරීමට UniGetUI ආරක්ෂක සැකසුම් වෙත යන්න.", + "Go to UniGetUI security settings": "UniGetUI ආරක්ෂක සැකසුම් වෙත යන්න", + "The following options will be applied by default each time a {0} package is installed, upgraded or uninstalled.": "{0} පැකේජයක් ස්ථාපනය, upgrade හෝ uninstall කරන සෑම අවස්ථාවකම පහත විකල්ප පෙරනිමියෙන් යෙදේ.", + "Package's default": "පැකේජයේ පෙරනිමිය", + "Install location can't be changed for {0} packages": "{0} පැකේජ සඳහා install ස්ථානය වෙනස් කළ නොහැක", + "The local icon cache currently takes {0} MB": "ස්ථානීය icon cache එක දැනට {0} MB ගනියි", + "Username": "පරිශීලක නාමය", + "Password": "මුරපදය", + "Credentials": "අක්තපත්‍ර", + "It is not guaranteed that the provided credentials will be stored safely": "ලබා දී ඇති අක්තපත්‍ර ආරක්ෂිතව ගබඩා වන බවට සහතික කළ නොහැක", + "Partially": "අර්ධ වශයෙන්", + "Package manager": "පැකේජ කළමනාකරු", + "Compatible with proxy": "proxy සමඟ අනුකූලයි", + "Compatible with authentication": "authentication සමඟ අනුකූලයි", + "Proxy compatibility table": "Proxy අනුකූලතා වගුව", + "{0} settings": "{0} සැකසුම්", + "{0} status": "{0} තත්ත්වය", + "Default installation options for {0} packages": "{0} පැකේජ සඳහා පෙරනිමි ස්ථාපන විකල්ප", + "Expand version": "version පුළුල් කරන්න", + "The executable file for {0} was not found": "{0} සඳහා executable ගොනුව හමු නොවීය", + "{pm} is disabled": "{pm} අක්‍රීයයි", + "Enable it to install packages from {pm}.": "{pm} වෙතින් පැකේජ ස්ථාපනය කිරීමට එය සක්‍රීය කරන්න.", + "{pm} is enabled and ready to go": "{pm} සක්‍රීය කර ඇති අතර සූදානම්ය", + "{pm} version:": "{pm} සංස්කරණය:", + "{pm} was not found!": "{pm} හමු නොවීය!", + "You may need to install {pm} in order to use it with UniGetUI.": "UniGetUI සමඟ භාවිතා කිරීමට ඔබට {pm} ස්ථාපනය කිරීමට අවශ්‍ය විය හැක.", + "Scoop Installer - UniGetUI": "Scoop ස්ථාපකය - UniGetUI", + "Scoop Uninstaller - UniGetUI": "Scoop අස්ථාපකය - UniGetUI", + "Clearing Scoop cache - UniGetUI": "Scoop cache ඉවත් කරමින් - UniGetUI", + "Restart UniGetUI to fully apply changes": "වෙනස්කම් සම්පූර්ණයෙන් යෙදීමට UniGetUI නැවත ආරම්භ කරන්න", + "Restart UniGetUI": "UniGetUI නැවත ආරම්භ කරන්න", + "Manage {0} sources": "{0} මූලාශ්‍ර කළමනාකරණය කරන්න", + "Add source": "මූලාශ්‍රය එක් කරන්න", + "Add": "එකතු කරන්න", + "Source name": "මූලාශ්‍ර නම", + "Source URL": "මූලාශ්‍ර URL ලිපිනය", + "Other": "වෙනත්", + "No minimum age": "අවම වයස් සීමාවක් නැත", + "1 day": "දින 1", + "{0} days": "දින {0}", + "Custom...": "අභිරුචි...", + "{0} minutes": "මිනිත්තු {0} ", + "1 hour": "පැය 1", + "{0} hours": "පැය {0} ", + "1 week": "සති 1", + "Supports release dates": "නිකුතු දින සඳහා සහය දක්වයි", + "Release date support per package manager": "එක් එක් පැකේජ කළමනාකරු අනුව නිකුතු දින සහය", + "Search for packages": "පැකේජ සොයන්න", + "Local": "ස්ථානීය", + "OK": "හරි", + "Last checked: {0}": "අවසන් වරට පරීක්ෂා කළේ: {0}", + "{0} packages were found, {1} of which match the specified filters.": "පැකේජ {0} ක් හමු විය, එයින් {1} ක් නියමිත filters සමඟ ගැලපේ.", + "{0} selected": "{0} තෝරා ඇත", + "(Last checked: {0})": "(අවසන් වරට පරීක්ෂා කළේ: {0})", + "All packages selected": "සියලුම පැකේජ තෝරාගන්නා ලදී", + "Package selection cleared": "පැකේජ තේරීම ඉවත් කරන ලදී", + "{0}: {1}": "{0}: {1}", + "More info": "වැඩි තොරතුරු", + "GitHub account": "GitHub ගිණුම", + "Log in with GitHub to enable cloud package backup.": "cloud package backup සක්‍රීය කිරීමට GitHub සමඟ පිවිසෙන්න.", + "More details": "වැඩි විස්තර", + "Log in": "පිවිසෙන්න", + "If you have cloud backup enabled, it will be saved as a GitHub Gist on this account": "ඔබ cloud backup සක්‍රීය කර තිබේ නම්, එය මෙම ගිණුමේ GitHub Gist එකක් ලෙස සුරකිනු ලැබේ", + "Log out": "ඉවත් වන්න", + "About UniGetUI": "UniGetUI පිළිබඳ", + "About": "පිළිබඳ", + "Third-party licenses": "Third-party බලපත්‍ර", + "Contributors": "සහයෝගිකයින්", + "Translators": "පරිවර්තකයින්", + "Bundle security report": "බණ්ඩල ආරක්ෂක වාර්තාව", + "The bundle contained restricted content": "bundle එකේ සීමා කළ අන්තර්ගතය තිබුණි", + "UniGetUI – Crash Report": "UniGetUI – බිඳවැටීම් වාර්තාව", + "UniGetUI has crashed": "UniGetUI බිඳ වැටුණි", + "Help us fix this by sending a crash report to Devolutions. All fields below are optional.": "Devolutions වෙත බිඳවැටීම් වාර්තාවක් යැවීමෙන් අපට මෙය නිවැරදි කිරීමට උදවු කරන්න. පහත සියලුම ක්ෂේත්‍ර අනිවාර්ය නොවේ.", + "Email (optional)": "විද්‍යුත් තැපෑල (අනිවාර්ය නොවේ)", + "your@email.com": "your@email.com", + "Additional details (optional)": "අමතර විස්තර (අනිවාර්ය නොවේ)", + "Describe what you were doing when the crash occurred…": "බිඳවැටීම සිදු වූ විට ඔබ කරමින් සිටි දේ විස්තර කරන්න…", + "Crash report": "බිඳවැටීම් වාර්තාව", + "Don't Send": "නොයවන්න", + "Send Report": "වාර්තාව යවන්න", + "Sending…": "යැවීම…", + "Unsaved changes": "සුරකින්නේ නැති වෙනස්කම්", + "You have unsaved changes in the current bundle. Do you want to discard them?": "වත්මන් bundle තුළ සුරකින්නේ නැති වෙනස්කම් ඇත. ඒවා ඉවත දමන්න අවශ්‍යද?", + "Discard changes": "වෙනස්කම් ඉවත දමන්න", + "Integrity violation": "අඛණ්ඩතාව උල්ලංඝනය වීම", + "UniGetUI or some of its components are missing or corrupt. It is strongly recommended to reinstall UniGetUI to adress the situation.": "UniGetUI හෝ එහි සමහර සංරචක අස්ථානගත වී ඇත හෝ දූෂිත වී ඇත. තත්ත්වය විසඳීම සඳහා UniGetUI නැවත ස්ථාපනය කිරීම තදින්ම නිර්දේශ කෙරේ.", + "• Refer to the UniGetUI Logs to get more details regarding the affected file(s)": "• බලපෑමට ලක්වූ ගොනු පිළිබඳ වැඩි විස්තර සඳහා UniGetUI Logs වෙත යොමු වන්න", + "• Integrity checks can be disabled from the Experimental Settings": "• Experimental Settings වෙතින් integrity checks අක්‍රීය කළ හැක", + "Manage shortcuts": "shortcuts කළමනාකරණය කරන්න", + "UniGetUI has detected the following desktop shortcuts which can be removed automatically on future upgrades": "අනාගත upgrades වලදී ස්වයංක්‍රීයව ඉවත් කළ හැකි පහත desktop shortcuts UniGetUI හඳුනාගෙන ඇත.", + "Do you really want to reset this list? This action cannot be reverted.": "මෙම ලැයිස්තුව reset කිරීමට ඔබට ඇත්තටම අවශ්‍යද? මෙම ක්‍රියාව ආපසු හැරවිය නොහැක.", + "Desktop shortcuts list": "ඩෙස්ක්ටොප් කෙටිමං ලැයිස්තුව", + "Open in explorer": "explorer තුළ විවෘත කරන්න", + "Remove from list": "ලැයිස්තුවෙන් ඉවත් කරන්න", + "When new shortcuts are detected, delete them automatically instead of showing this dialog.": "නව shortcuts හඳුනාගත් විට, මෙම dialog එක පෙන්වීම වෙනුවට ඒවා ස්වයංක්‍රීයව මකා දමන්න.", + "Not right now": "දැන් නොවේ", + "Missing dependency": "අතුරුදන් dependency", + "UniGetUI requires {0} to operate, but it was not found on your system.": "UniGetUI ක්‍රියා කිරීමට {0} අවශ්‍යය, නමුත් එය ඔබේ පද්ධතියේ හමු නොවීය.", + "Click on Install to begin the installation process. If you skip the installation, UniGetUI may not work as expected.": "ස්ථාපන ක්‍රියාවලිය ආරම්භ කිරීමට Install ක්ලික් කරන්න. ඔබ ස්ථාපනය මඟ හැරියහොත්, UniGetUI අපේක්ෂිත ආකාරයට ක්‍රියා නොකළ හැකිය.", + "Alternatively, you can also install {0} by running the following command in a Windows PowerShell prompt:": "විකල්පයක් ලෙස, Windows PowerShell prompt එකක පහත විධානය ධාවනය කර {0} ස්ථාපනය කළ හැකිය:", + "Install {0}": "{0} ස්ථාපනය කරන්න", + "Do not show this dialog again for {0}": "{0} සඳහා මෙම සංවාදය නැවත පෙන්වන්න එපා", + "Please wait while {0} is being installed. A black window may show up. Please wait until it closes.": "{0} ස්ථාපනය වන අතරතුර කරුණාකර රැඳී සිටින්න. කළු (හෝ නිල්) කවුළුවක් පෙන්විය හැක. එය වැසෙන තෙක් රැඳී සිටින්න.", + "{0} has been installed successfully.": "{0} සාර්ථකව ස්ථාපනය කරන ලදී.", + "Please click on \"Continue\" to continue": "ඉදිරියට යාමට \"Continue\" ක්ලික් කරන්න", + "Continue": "කරගෙන යන්න", + "{0} has been installed successfully. It is recommended to restart UniGetUI to finish the installation": "{0} සාර්ථකව ස්ථාපනය කරන ලදී. ස්ථාපනය අවසන් කිරීමට UniGetUI නැවත ආරම්භ කිරීම නිර්දේශ කරයි", + "Restart later": "පසුව නැවත ආරම්භ කරන්න", + "An error occurred:": "දෝෂයක් සිදු විය:", + "Please see the Command-line Output or refer to the Operation History for further information about the issue.": "ගැටලුව පිළිබඳ වැඩිදුර තොරතුරු සඳහා Command-line Output බලන්න හෝ Operation History වෙත යොමු වන්න.", + "Retry as administrator": "පරිපාලක ලෙස නැවත උත්සාහ කරන්න", + "Retry interactively": "interactive ආකාරයෙන් නැවත උත්සාහ කරන්න", + "Retry skipping integrity checks": "integrity checks මඟ හරිමින් නැවත උත්සාහ කරන්න", + "Installation options": "ස්ථාපන විකල්ප", + "Save": "සුරකින්න", + "UniGetUI collects anonymous usage data with the sole purpose of understanding and improving the user experience.": "පරිශීලක අත්දැකීම වටහාගෙන වැඩිදියුණු කිරීමේ එකම අරමුණින් UniGetUI අනාමික භාවිත දත්ත රැස් කරයි.", + "More details about the shared data and how it will be processed": "share කරන ලද දත්ත සහ ඒවා සැකසෙන ආකාරය පිළිබඳ වැඩි විස්තර", + "Do you accept that UniGetUI collects and sends anonymous usage statistics, with the sole purpose of understanding and improving the user experience?": "පරිශීලක අත්දැකීම වටහාගෙන වැඩිදියුණු කිරීමේ එකම අරමුණින් UniGetUI අනාමික භාවිත සංඛ්‍යාන රැස්කර යවන බව ඔබ පිළිගන්නවාද?", + "Decline": "ප්‍රතික්ෂේප කරන්න", + "No personal information is collected nor sent, and the collected data is anonimized, so it can't be back-tracked to you.": "පුද්ගලික තොරතුරු කිසිවක් රැස්කර හෝ යවා නැති අතර, රැස් කළ දත්ත අනාමික කර ඇති බැවින් ඒවා ඔබ වෙත හඹාගොස් හඳුනාගත නොහැක.", + "Navigation panel": "සංචාලන පැනලය", + "Operations": "මෙහෙයුම්", + "Toggle operations panel": "මෙහෙයුම් පැනලය මාරු කරන්න", + "Bulk operations": "තොග මෙහෙයුම්", + "Retry failed": "අසාර්ථක වූවන් නැවත උත්සාහ කරන්න", + "Clear successful": "සාර්ථක වූවන් ඉවත් කරන්න", + "Clear finished": "අවසන් වූවන් ඉවත් කරන්න", + "Cancel all": "සියල්ල අවලංගු කරන්න", + "More": "තවත්", + "Toggle navigation panel": "සංචාලන පැනලය මාරු කරන්න", + "Minimize": "කුඩා කරන්න", + "Maximize": "විශාල කරන්න", + "UniGetUI by Devolutions": "Devolutions විසින් UniGetUI", + "UniGetUI is an application that makes managing your software easier, by providing an all-in-one graphical interface for your command-line package managers.": "ඔබේ command-line package managers සඳහා all-in-one graphical interface එකක් ලබා දීමෙන් ඔබේ මෘදුකාංග කළමනාකරණය පහසු කරන යෙදුමක් UniGetUI වේ.", + "Useful links": "ප්‍රයෝජනවත් සබැඳි", + "UniGetUI Homepage": "UniGetUI මුල් පිටුව", + "Report an issue or submit a feature request": "ගැටලුවක් වාර්තා කරන්න හෝ feature request එකක් යවන්න", + "UniGetUI Repository": "UniGetUI ගබඩාව", + "View GitHub Profile": "GitHub profile බලන්න", + "UniGetUI License": "UniGetUI බලපත්‍රය", + "Using UniGetUI implies the acceptation of the MIT License": "UniGetUI භාවිතා කිරීමෙන් MIT බලපත්‍රය පිළිගැනීම අදහස් වේ", + "Become a translator": "පරිවර්තකයෙක් වෙන්න", + "Go back": "ආපසු යන්න", + "Go forward": "ඉදිරියට යන්න", + "Go to home page": "මුල් පිටුවට යන්න", + "Reload page": "පිටුව නැවත පූරණය කරන්න", + "View page on browser": "browser එකේ පිටුව බලන්න", + "The built-in browser is not supported on Linux yet.": "ඇතුළත් browser එක Linux මත තවමත් සහය නොදක්වයි.", + "Open in browser": "browser එකේ විවෘත කරන්න", + "Copy to clipboard": "clipboard වෙත පිටපත් කරන්න", + "Export to a file": "ගොනුවකට අපනයනය කරන්න", + "Log level:": "Log මට්ටම:", + "Reload log": "log නැවත පූරණය කරන්න", + "Export log": "ලොගය අපනයනය කරන්න", + "Text": "පෙළ", + "Change how operations request administrator rights": "මෙහෙයුම් පරිපාලක හිමිකම් ඉල්ලන ආකාරය වෙනස් කරන්න", + "Restrictions on package operations": "පැකේජ මෙහෙයුම් පිළිබඳ සීමා", + "Restrictions on package managers": "පැකේජ කළමනාකරුවන් පිළිබඳ සීමා", + "Restrictions when importing package bundles": "package bundles ආයාත කිරීමේදී ඇති සීමා", + "Ask for administrator privileges once for each batch of operations": "මෙහෙයුම් සෑම batch එකකටම එක් වරක් පරිපාලක බලතල ඉල්ලන්න", + "Ask only once for administrator privileges": "පරිපාලක බලතල එක් වරක් පමණක් ඉල්ලන්න", + "Prohibit any kind of Elevation via UniGetUI Elevator or GSudo": "UniGetUI Elevator හෝ GSudo හරහා කිසිදු Elevation වර්ගයක් තහනම් කරන්න", + "This option WILL cause issues. Any operation incapable of elevating itself WILL FAIL. Install/update/uninstall as administrator will NOT WORK.": "මෙම විකල්පය ගැටලු ඇති කරයි. තමන්ම elevate කරගත නොහැකි ඕනෑම මෙහෙයුමක් අසාර්ථක වනු ඇත. පරිපාලක ලෙස install/update/uninstall කිරීම ක්‍රියා නොකරනු ඇත.", + "Allow custom command-line arguments": "අභිරුචි command-line arguments සඳහා ඉඩ දෙන්න", + "Custom command-line arguments can change the way in which programs are installed, upgraded or uninstalled, in a way UniGetUI cannot control. Using custom command-lines can break packages. Proceed with caution.": "අභිරුචි command-line arguments මගින් වැඩසටහන් ස්ථාපනය, උසස් කිරීම හෝ අස්ථාපනය කරන ආකාරය UniGetUIට පාලනය කළ නොහැකි ලෙස වෙනස් විය හැක. අභිරුචි command-line භාවිතය පැකේජ බිඳ දමන්නත් පුළලවන්. ප්‍රවේශමෙන් ඉදිරියට යන්න.", + "Ignore custom pre-install and post-install commands when importing packages from a bundle": "බණ්ඩලයකින් පැකේජ ආයාත කිරීමේදී අභිරුචි pre-install සහ post-install commands නොසලකා හරින්න", + "Pre and post install commands will be run before and after a package gets installed, upgraded or uninstalled. Be aware that they may break things unless used carefully": "පැකේජයක් ස්ථාපනය, upgrade හෝ uninstall කරන පෙර හා පසුව pre සහ post install commands ධාවනය වේ. ඒවා ප්‍රවේශමෙන් භාවිතා නොකළහොත් දේවල් බිඳ දැමිය හැකි බව සැලකිලිමත් වන්න.", + "Allow changing the paths for package manager executables": "පැකේජ කළමනාකරු executable සඳහා path වෙනස් කිරීමට ඉඩ දෙන්න", + "Turning this on enables changing the executable file used to interact with package managers. While this allows finer-grained customization of your install processes, it may also be dangerous": "මෙය සක්‍රීය කිරීමෙන් package managers සමඟ අන්තර්ක්‍රියා කිරීමට භාවිතා කරන executable ගොනුව වෙනස් කිරීමට හැකි වේ. මෙය ඔබේ install processes වඩාත් සවිස්තරව අභිරුචිකරණය කිරීමට ඉඩ දෙන නමුත්, එය අනතුරුදායකද විය හැක.", + "Allow importing custom command-line arguments when importing packages from a bundle": "බණ්ඩලයකින් පැකේජ ආයාත කිරීමේදී අභිරුචි command-line arguments ආයාත කිරීමට ඉඩ දෙන්න", + "Malformed command-line arguments can break packages, or even allow a malicious actor to gain privileged execution. Therefore, importing custom command-line arguments is disabled by default": "වැරදි ලෙස සැකසූ command-line arguments මගින් පැකේජ බිඳ වැටිය හැකි අතර, දුෂ්ට පාර්ශවයකට privileged execution ලබා ගැනීමටද ඉඩ සැලසිය හැක. ඒ නිසා custom command-line arguments ආයාත කිරීම පෙරනිමියෙන් අක්‍රීයයි", + "Allow importing custom pre-install and post-install commands when importing packages from a bundle": "බණ්ඩලයකින් පැකේජ ආයාත කිරීමේදී අභිරුචි pre-install සහ post-install විධාන ආයාත කිරීමට ඉඩ දෙන්න", + "Pre and post install commands can do very nasty things to your device, if designed to do so. It can be very dangerous to import the commands from a bundle, unless you trust the source of that package bundle": "ඒ සඳහා නිර්මාණය කර ඇත්නම් pre සහ post install commands ඔබගේ උපාංගයට බරපතල හානි කළ හැක. එම package bundle එකේ මූලාශ්‍රය විශ්වාස නොකරන්නේ නම් ඒ bundle එකෙන් commands ආයාත කිරීම ඉතා අනතුරුදායක විය හැක.", + "Administrator rights and other dangerous settings": "පරිපාලක හිමිකම් සහ වෙනත් අවදානම් සහිත සැකසුම්", + "Package backup": "පැකේජ backup", + "Cloud package backup": "cloud පැකේජ උපස්ථ", + "Local package backup": "ස්ථානීය පැකේජ backup", + "Local backup advanced options": "ස්ථානීය backup උසස් විකල්ප", + "Log in with GitHub": "GitHub සමඟ පිවිසෙන්න", + "Log out from GitHub": "GitHub වෙතින් ඉවත් වන්න", + "Periodically perform a cloud backup of the installed packages": "ස්ථාපිත පැකේජ වල cloud backup එකක් වරින් වර ගන්න", + "Cloud backup uses a private GitHub Gist to store a list of installed packages": "cloud backup ස්ථාපිත පැකේජ ලැයිස්තුවක් ගබඩා කිරීම සඳහා private GitHub Gist භාවිතා කරයි", + "Perform a cloud backup now": "දැන් cloud backup එකක් ගන්න", + "Backup": "උපස්ථ", + "Restore a backup from the cloud": "cloud එකෙන් backup එකක් ප්‍රතිස්ථාපනය කරන්න", + "Begin the process to select a cloud backup and review which packages to restore": "cloud උපස්ථයක් තෝරා, ප්‍රතිස්ථාපනය කළ යුතු පැකේජ සමාලෝචනය කිරීමේ ක්‍රියාවලිය ආරම්භ කරන්න", + "Periodically perform a local backup of the installed packages": "ස්ථාපිත පැකේජ වල local backup එකක් වරින් වර ගන්න", + "Perform a local backup now": "දැන් local backup එකක් ගන්න", + "Change backup output directory": "උපස්ථ output directory එක වෙනස් කරන්න", + "Set a custom backup file name": "custom backup ගොනු නාමයක් සකසන්න", + "Leave empty for default": "පෙරනිමිය සඳහා හිස්ව තබන්න", + "Add a timestamp to the backup file names": "උපස්ථ ගොනු නාමවලට වේලා මුද්‍රාවක් එක් කරන්න", + "Backup and Restore": "උපස්ථ සහ ප්‍රතිස්ථාපනය", + "Enable background api (UniGetUI Widgets and Sharing, port 7058)": "background API සක්‍රීය කරන්න (UniGetUI Widgets සහ Sharing, port 7058)", + "Wait for the device to be connected to the internet before attempting to do tasks that require internet connectivity.": "internet සම්බන්ධතාව අවශ්‍ය කාර්යයන් කිරීමට උත්සාහ කිරීමට පෙර උපාංගය internet එකට සම්බන්ධ වනතුරු රැඳී සිටින්න.", + "Disable the 1-minute timeout for package-related operations": "පැකේජ සම්බන්ධ මෙහෙයුම් සඳහා මිනිත්තු 1 timeout එක අක්‍රීය කරන්න", + "Use installed GSudo instead of UniGetUI Elevator": "UniGetUI Elevator වෙනුවට ස්ථාපිත GSudo භාවිතා කරන්න", + "Use a custom icon and screenshot database URL": "අභිරුචි icon සහ screenshot database URL එකක් භාවිතා කරන්න", + "Enable background CPU Usage optimizations (see Pull Request #3278)": "background CPU භාවිතය සඳහා optimizations සක්‍රීය කරන්න (Pull Request #3278 බලන්න)", + "Perform integrity checks at startup": "ආරම්භයේදී integrity checks සිදු කරන්න", + "When batch installing packages from a bundle, install also packages that are already installed": "bundle එකකින් පැකේජ batch install කරන විට, දැනටමත් ස්ථාපිත පැකේජද install කරන්න", + "Experimental settings and developer options": "පරීක්ෂණාත්මක සැකසුම් සහ developer විකල්ප", + "Show UniGetUI's version and build number on the titlebar.": "titlebar මත UniGetUI හි version එක සහ build number එක පෙන්වන්න.", + "Language": "භාෂාව", + "UniGetUI updater": "UniGetUI යාවත්කාලීනකාරකය", + "Telemetry": "භාවිත දත්ත රැස්කිරීම", + "Manage UniGetUI settings": "UniGetUI සැකසුම් කළමනාකරණය කරන්න", + "Related settings": "සම්බන්ධ සැකසුම්", + "Update UniGetUI automatically": "UniGetUI ස්වයංක්‍රීයව යාවත්කාලීන කරන්න", + "Check for updates": "යාවත්කාලීන කිරීම් සදහා පරීක්ෂා කරන්න", + "Install prerelease versions of UniGetUI": "UniGetUI හි prerelease සංස්කරණ ස්ථාපනය කරන්න", + "Manage telemetry settings": "telemetry සැකසුම් කළමනාකරණය කරන්න", + "Manage": "කළමනාකරණය කරන්න", + "Import settings from a local file": "ස්ථානීය ගොනුවකින් සැකසුම් ආයාත කරන්න", + "Import": "ආයාත කරන්න", + "Export settings to a local file": "සැකසුම් ස්ථානීය ගොනුවකට අපනයනය කරන්න", + "Export": "අපනයනය", + "Reset UniGetUI": "UniGetUI reset කරන්න", + "User interface preferences": "පරිශීලක අතුරුමුහුණත් අභිරුචි", + "Application theme, startup page, package icons, clear successful installs automatically": "යෙදුම් තේමාව, ආරම්භක පිටුව, පැකේජ අයිකන, සාර්ථක ස්ථාපනයන් ස්වයංක්‍රීයව ඉවත් කිරීම", + "General preferences": "සාමාන්‍ය මනාපයන්", + "UniGetUI display language:": "UniGetUI දර්ශන භාෂාව:", + "System language": "පද්ධති භාෂාව", + "Is your language missing or incomplete?": "ඔබගේ භාෂාව අතුරුදන්වී තිබේද නැතහොත් අසම්පූර්ණද?", + "Appearance": "පෙනුම", + "UniGetUI on the background and system tray": "background සහ system tray තුළ UniGetUI", + "Package lists": "පැකේජ ලැයිස්තු", + "Use classic mode": "classic මාදිලිය භාවිතා කරන්න", + "Restart UniGetUI to apply this change": "මෙම වෙනස යෙදීමට UniGetUI නැවත ආරම්භ කරන්න", + "The classic UI is disabled for beta testers": "බීටා පරීක්ෂකයන් සඳහා සම්ප්‍රදායික UI අක්‍රිය කර ඇත", + "Close UniGetUI to the system tray": "UniGetUI system tray වෙත වසන්න", + "Manage UniGetUI autostart behaviour": "UniGetUI ස්වයංක්‍රීය ආරම්භක හැසිරීම කළමනාකරණය කරන්න", + "Show package icons on package lists": "පැකේජ ලැයිස්තු මත පැකේජ icons පෙන්වන්න", + "Clear cache": "cache ඉවත් කරන්න", + "Select upgradable packages by default": "upgrade කළ හැකි පැකේජ පෙරනිමියෙන් තෝරන්න", + "Light": "ආලෝකමත්", + "Dark": "අදුරු", + "Follow system color scheme": "පද්ධතියේ වර්ණ ක්‍රමය අනුගමනය කරන්න", + "Application theme:": "යෙදුම් තේමාව:", + "UniGetUI startup page:": "UniGetUI ආරම්භක පිටුව:", + "Proxy settings": "Proxy සැකසුම්", + "Other settings": "වෙනත් සැකසුම්", + "Connect the internet using a custom proxy": "අභිරුචි proxy භාවිතයෙන් අන්තර්ජාලයට සම්බන්ධ වන්න", + "Please note that not all package managers may fully support this feature": "සියලුම පැකේජ කළමනාකරුවන් මෙම විශේෂාංගයට සම්පූර්ණ සහය නොදක්වන්නට පුළුවන් බව සලකන්න", + "Proxy URL": "Proxy URL ලිපිනය", + "Enter proxy URL here": "proxy URL එක මෙතැන ඇතුල් කරන්න", + "Authenticate to the proxy with a user and a password": "පරිශීලක නාමයක් සහ මුරපදයක් සමඟ proxy වෙත සත්‍යාපනය කරන්න", + "Internet and proxy settings": "අන්තර්ජාල සහ proxy සැකසුම්", + "Package manager preferences": "පැකේජ කළමනාකරු මනාපයන්", + "Ready": "සූදානම්", + "Not found": "හමු නොවීය", + "Notification preferences": "දැනුම්දීම් මනාපයන්", + "Notification types": "දැනුම්දීම් වර්ග", + "The system tray icon must be enabled in order for notifications to work": "notifications වැඩ කිරීමට system tray icon එක සක්‍රීය කර තිබිය යුතුය", + "Enable UniGetUI notifications": "UniGetUI දැනුම්දීම් සක්‍රීය කරන්න", + "Show a notification when there are available updates": "ලබාගත හැකි යාවත්කාලීන ඇති විට දැනුම්දීමක් පෙන්වන්න", + "Show a silent notification when an operation is running": "මෙහෙයුමක් ක්‍රියාත්මක වන විට නිහඬ දැනුම්දීමක් පෙන්වන්න", + "Show a notification when an operation fails": "මෙහෙයුමක් අසාර්ථක වන විට දැනුම්දීමක් පෙන්වන්න", + "Show a notification when an operation finishes successfully": "මෙහෙයුමක් සාර්ථකව අවසන් වූ විට දැනුම්දීමක් පෙන්වන්න", + "Concurrency and execution": "සමාන්තර ක්‍රියාත්මක කිරීම සහ ධාවනය", + "Automatic desktop shortcut remover": "ස්වයංක්‍රීය desktop shortcut remover", + "Choose how many operations should be performed in parallel": "සමාන්තරව සිදු කළ යුතු මෙහෙයුම් ගණන තෝරන්න", + "Clear successful operations from the operation list after a 5 second delay": "තත්පර 5ක ප්‍රමාදයකින් පසු මෙහෙයුම් ලැයිස්තුවෙන් සාර්ථක මෙහෙයුම් ඉවත් කරන්න", + "Download operations are not affected by this setting": "මෙම සැකසුම බාගැනීම් මෙහෙයුම් වලට බලපාන්නේ නැත", + "You may lose unsaved data": "සුරකින්නේ නැති දත්ත ඔබට අහිමි විය හැක", + "Ask to delete desktop shortcuts created during an install or upgrade.": "ස්ථාපනයක් හෝ උසස් කිරීමක් අතරතුර නිර්මාණය කරන ලද desktop shortcuts මකා දැමීමට අසන්න.", + "Package update preferences": "පැකේජ යාවත්කාලීන මනාපයන්", + "Update check frequency, automatically install updates, etc.": "update පරීක්ෂා කිරීමේ වාර ගණන, updates ස්වයංක්‍රීයව install කිරීම, ආදිය.", + "Reduce UAC prompts, elevate installations by default, unlock certain dangerous features, etc.": "UAC prompts අඩු කරන්න, ස්ථාපන පෙරනිමියෙන් elevate කරන්න, සමහර අවදානම් විශේෂාංග unlock කරන්න, ආදිය.", + "Package operation preferences": "පැකේජ මෙහෙයුම් මනාපයන්", + "Enable {pm}": "{pm} ක්‍රියාත්මක කරන්න", + "Not finding the file you are looking for? Make sure it has been added to path.": "ඔබ සොයන ගොනුව හමු නොවන්නේද? එය path එකට එක් කර ඇති බව තහවුරු කරන්න.", + "Select the executable to be used. The following list shows the executables found by UniGetUI": "භාවිතා කළ යුතු executable එක තෝරන්න. පහත ලැයිස්තුව UniGetUI විසින් සොයාගත් executables පෙන්වයි", + "For security reasons, changing the executable file is disabled by default": "ආරක්ෂක හේතු මත executable ගොනුව වෙනස් කිරීම පෙරනිමියෙන් අක්‍රීයයි", + "Change this": "මෙය වෙනස් කරන්න", + "Copy path": "මාර්ගය පිටපත් කරන්න", + "Current executable file:": "වත්මන් executable ගොනුව:", + "Ignore packages from {pm} when showing a notification about updates": "යාවත්කාලීන පිළිබඳ දැනුම්දීමක් පෙන්වීමේදී {pm} හි පැකේජ නොසලකා හරින්න", + "Update security": "යාවත්කාලීන ආරක්ෂාව", + "Use global setting": "ගෝලීය සැකසුම භාවිතා කරන්න", + "Minimum age for updates": "යාවත්කාලීන සඳහා අවම වයස", + "e.g. 10": "උදා. 10", + "Custom minimum age (days)": "අභිරුචි අවම වයස (දින)", + "{pm} does not provide release dates for its packages, so this setting will have no effect": "{pm} එහි පැකේජ සඳහා නිකුතු දින ලබා නොදෙන බැවින්, මෙම සැකසුමට කිසිදු බලපෑමක් නොමැත", + "{pm} only provides release dates for some of its packages, so this setting will only apply to those packages": "{pm} එහි සමහර පැකේජ සඳහා පමණක් නිකුත් කිරීමේ දින සපයයි, එබැවින් මෙම සැකසුම අදාළ පැකේජ සඳහා පමණක් යෙදෙයි", + "Override the global minimum update age for this package manager": "මෙම පැකේජ කළමනාකරු සඳහා ගෝලීය අවම යාවත්කාලීන වයස් සීමාව අභිබවා සකසන්න", + "View {0} logs": "{0} logs බලන්න", + "If Python cannot be found or is not listing packages but is installed on the system, ": "Python හමු නොවන්නේ නම් හෝ පද්ධතියේ ස්ථාපිතව තිබුණත් පැකේජ ලැයිස්තුගත නොකරන්නේ නම්, ", + "Advanced options": "උසස් විකල්ප", + "WinGet command-line tool": "WinGet විධාන-රේඛා මෙවලම", + "Choose which command-line tool UniGetUI uses for WinGet operations when the COM API is not used": "COM API භාවිතා නොකරන විට WinGet මෙහෙයුම් සඳහා UniGetUI භාවිතා කරන command-line මෙවලම තෝරන්න", + "WinGet COM API": "WinGet COM API", + "Choose whether UniGetUI can use the WinGet COM API before falling back to the command-line tool": "command-line මෙවලමට ආපසු යාමට පෙර UniGetUI හට WinGet COM API භාවිතා කළ හැකිද යන්න තෝරන්න", + "Reset WinGet": "WinGet reset කරන්න", + "This may help if no packages are listed": "පැකේජ කිසිවක් ලැයිස්තුගත නොවන්නේ නම් මෙය උපකාරී විය හැක", + "Force install location parameter when updating packages with custom locations": "අභිරුචි ස්ථාන සහිත පැකේජ යාවත්කාලීන කිරීමේදී install location parameter බලෙන් යොදන්න", + "Install Scoop": "Scoop ස්ථාපනය කරන්න", + "Uninstall Scoop (and its packages)": "Scoop (සහ එහි පැකේජ) uninstall කරන්න", + "Run cleanup and clear cache": "cleanup ධාවනය කර cache ඉවත් කරන්න", + "Run": "ධාවනය කරන්න", + "Enable Scoop cleanup on launch": "launch වෙද්දී Scoop cleanup සක්‍රීය කරන්න", + "Default vcpkg triplet": "පෙරනිමි vcpkg triplet", + "Change vcpkg root location": "vcpkg මූල ස්ථානය වෙනස් කරන්න", + "Reset vcpkg root location": "vcpkg මූල ස්ථානය යළි පිහිටුවන්න", + "Open vcpkg root location": "vcpkg මූල ස්ථානය විවෘත කරන්න", + "Language, theme and other miscellaneous preferences": "භාෂාව, තේමාව සහ වෙනත් විවිධ මනාපයන්", + "Show notifications on different events": "විවිධ සිදුවීම්වලදී දැනුම්දීම් පෙන්වන්න", + "Change how UniGetUI checks and installs available updates for your packages": "UniGetUI ඔබගේ පැකේජ සඳහා ලබාගත හැකි යාවත්කාලීන පරීක්ෂා කරන සහ ස්ථාපනය කරන ආකාරය වෙනස් කරන්න", + "Automatically save a list of all your installed packages to easily restore them.": "ඔබගේ ස්ථාපිත සියලු පැකේජ ලැයිස්තුවක් ස්වයංක්‍රීයව සුරකින්න, ඒවා පහසුවෙන් ප්‍රතිස්ථාපනය කිරීමට.", + "Enable and disable package managers, change default install options, etc.": "පැකේජ කළමනාකරුවන් සක්‍රීය/අක්‍රීය කරන්න, පෙරනිමි ස්ථාපන විකල්ප වෙනස් කරන්න, ආදිය.", + "Internet connection settings": "අන්තර්ජාල සම්බන්ධතා සැකසුම්", + "Proxy settings, etc.": "Proxy සැකසුම්, ආදිය", + "Beta features and other options that shouldn't be touched": "Beta විශේෂාංග සහ අත නොතැබිය යුතු වෙනත් විකල්ප", + "Reload sources": "මූලාශ්‍ර නැවත පූරණය කරන්න", + "Delete source": "මූලාශ්‍රය මකන්න", + "Known sources": "දන්නා මූලාශ්‍ර", + "Update checking": "update පරීක්ෂාව", + "Automatic updates": "ස්වයංක්‍රීය යාවත්කාලීන", + "Check for package updates periodically": "පැකේජ යාවත්කාලීන වරින් වර පරීක්ෂා කරන්න", + "Check for updates every:": "යාවත්කාලීන කිරීම් සඳහා පරීක්ෂා කරන්න:", + "Install available updates automatically": "ලබාගත හැකි යාවත්කාලීන ස්වයංක්‍රීයව ස්ථාපනය කරන්න", + "Do not automatically install updates when the network connection is metered": "network connection එක metered වූ විට යාවත්කාලීන ස්වයංක්‍රීයව ස්ථාපනය නොකරන්න", + "Do not automatically install updates when the device runs on battery": "උපාංගය battery මත ධාවනය වන විට යාවත්කාලීන ස්වයංක්‍රීයව ස්ථාපනය නොකරන්න", + "Do not automatically install updates when the battery saver is on": "battery saver සක්‍රීය විට යාවත්කාලීන ස්වයංක්‍රීයව ස්ථාපනය නොකරන්න", + "Only show updates that are at least the specified number of days old": "අවම වශයෙන් සඳහන් කළ දින ගණනක් පැරණි යාවත්කාලීන පමණක් පෙන්වන්න", + "Warn me when the installer URL host changes between the installed version and the new version (WinGet only)": "ස්ථාපිත සංස්කරණය සහ නව සංස්කරණය අතර installer URL host වෙනස් වන විට මට අනතුරු අඟවන්න (WinGet පමණි)", + "Change how UniGetUI handles install, update and uninstall operations.": "UniGetUI ස්ථාපනය, යාවත්කාලීන සහ අස්ථාපන මෙහෙයුම් හසුරුවන ආකාරය වෙනස් කරන්න.", + "Navigation": "සංචාලනය", + "Check for UniGetUI updates": "UniGetUI යාවත්කාලීන සඳහා පරීක්ෂා කරන්න", + "Quit UniGetUI": "UniGetUI වෙතින් ඉවත් වන්න", + "Filters": "පෙරහන්", + "Sources": "මූලාශ්‍ර", + "Search for packages to start": "ආරම්භ කිරීමට පැකේජ සොයන්න", + "Select all": "සියල්ල තෝරන්න", + "Clear selection": "තේරීම ඉවත් කරන්න", + "Instant search": "ක්ෂණික සෙවීම", + "Distinguish between uppercase and lowercase": "ලොකු අකුරු සහ කුඩා අකුරු අතර වෙනස හඳුනාගන්න", + "Ignore special characters": "විශේෂ අක්ෂර නොසලකා හරින්න", + "Search mode": "සෙවුම් ආකාරය", + "Both": "දෙකම", + "Exact match": "සුදුසුම ගැලපීම", + "Show similar packages": "සමාන පැකේජ පෙන්වන්න", + "Loading": "පූරණය වෙමින්", + "Package": "පැකේජය", + "More options": "තවත් විකල්ප", + "Order by:": "පිළිවෙලට ගොනු කරන්න:", + "Name": "නම", + "Id": "අංකය", + "Ascendant": "ආරෝහණ", + "Descendant": "අවරෝහණ", + "View modes": "දර්ශන මාදිලි", + "Reload": "නැවත පූරණය", + "Closed": "වසා ඇත", + "Ascending": "ආරෝහණ", + "Descending": "අවරෝහණ", + "{0}: {1}, {2}": "{0}: {1}, {2}", + "Order by": "අනුපිළිවෙළ", + "No results were found matching the input criteria": "ඇතුළත් කළ නිර්ණායකයට ගැළපෙන ප්‍රතිඵල කිසිවක් හමු නොවීය", + "No packages were found": "පැකේජ කිසිවක් හමු නොවීය", + "Loading packages": "පැකේජ පූරණය කරමින්", + "Skip integrity checks": "integrity checks මඟ හරින්න", + "Download selected installers": "තෝරාගත් installers බාගන්න", + "Install selection": "තේරීම ස්ථාපනය කරන්න", + "Install options": "ස්ථාපන විකල්ප", + "Add selection to bundle": "බන්ඩලයක් සදහා තේරීම් කරන්න", + "Download installer": "installer බාගන්න", + "Uninstall selection": "තේරීම uninstall කරන්න", + "Uninstall options": "uninstall විකල්ප", + "Ignore selected packages": "තෝරාගත් පැකේජ නොසලකා හරින්න", + "Open install location": "ස්ථාපන ස්ථානය විවෘත කරන්න", + "Reinstall package": "පැකේජය නැවත ස්ථාපනය කරන්න", + "Uninstall package, then reinstall it": "පැකේජය uninstall කර, පසුව නැවත install කරන්න", + "Ignore updates for this package": "මෙම පැකේජය සඳහා යාවත්කාලීන නොසලකා හරින්න", + "WinGet malfunction detected": "WinGet අක්‍රියතාවක් හඳුනා ගන්නා ලදී", + "It looks like WinGet is not working properly. Do you want to attempt to repair WinGet?": "WinGet නිසි ලෙස ක්‍රියා නොකරන බව පෙනේ. WinGet අලුත්වැඩියා කිරීමට උත්සාහ කිරීමට ඔබට අවශ්‍යද?", + "Repair WinGet": "WinGet අලුත්වැඩියා කරන්න", + "Updates will no longer be ignored for {0}": "{0} සඳහා යාවත්කාලීන තවදුරටත් නොසලකා නොහරිනු ඇත", + "Updates are now ignored for {0}": "{0} සඳහා යාවත්කාලීන දැන් නොසලකා හරිනු ලැබේ", + "Do not ignore updates for this package anymore": "මෙම පැකේජය සඳහා යාවත්කාලීන තවදුරටත් නොසලකා හරින්න එපා", + "Add packages or open an existing package bundle": "ඇසුරුම් එක් කිරීම හෝ තිබෙන ඇසුරුම් බන්ඩලයක් විවෘත කරන්න", + "Add packages to start": "ආරම්භ කිරීමට ඇසුරුම් එක් කරන්න", + "The current bundle has no packages. Add some packages to get started": "වත්මන් bundle එකේ පැකේජ නොමැත. ආරම්භ කිරීමට පැකේජ කිහිපයක් එක් කරන්න", + "New": "නව", + "Save as": "ලෙස සුරකින්න", + "Create .ps1 script": ".ps1 script එක සාදන්න", + "Remove selection from bundle": "bundle එකෙන් තේරීම ඉවත් කරන්න", + "Skip hash checks": "hash checks මඟ හරින්න", + "The package bundle is not valid": "package bundle එක වලංගු නොවේ", + "The bundle you are trying to load appears to be invalid. Please check the file and try again.": "ඔබ load කිරීමට උත්සාහ කරන bundle එක වලංගු නොවන බව පෙනේ. කරුණාකර ගොනුව පරීක්ෂා කර නැවත උත්සාහ කරන්න.", + "Package bundle": "පැකේජ bundle", + "Could not create bundle": "බණ්ඩලය සෑදිය නොහැකි විය", + "The package bundle could not be created due to an error.": "දෝෂයක් හේතුවෙන් package bundle එක සෑදිය නොහැකි විය.", + "Install script": "ස්ථාපන script", + "PowerShell script": "PowerShell ස්ක්‍රිප්ට්", + "The installation script saved to {0}": "ස්ථාපන script එක {0} වෙත සුරකින ලදී", + "An error occurred": "දෝෂයක් සිදු විය", + "An error occurred while attempting to create an installation script:": "ස්ථාපන script එකක් සෑදීමට උත්සාහ කිරීමේදී දෝෂයක් ඇති විය:", + "Hooray! No updates were found.": "සුභ ආරංචියක්! කිසිදු යාවත්කාලීනයක් හමු නොවීය.", + "Uninstall selected packages": "තෝරාගත් පැකේජ uninstall කරන්න", + "Update selection": "තේරීම යාවත්කාලීන කරන්න", + "Update options": "update විකල්ප", + "Uninstall package, then update it": "පැකේජය uninstall කර, පසුව update කරන්න", + "Uninstall package": "පැකේජය uninstall කරන්න", + "Skip this version": "මෙම version එක මඟ හරින්න", + "Pause updates for": "යාවත්කාලීන නවත්වන්න", + "User | Local": "පරිශීලක | දේශීය", + "Machine | Global": "යන්ත්‍රය | ගෝලීය", + "The default package manager for Debian/Ubuntu-based Linux distributions.
Contains: Debian/Ubuntu packages": "Debian/Ubuntu පදනම් Linux බෙදාහැරීම් සඳහා පෙරනිමි පැකේජ කළමනාකරු.
අන්තර්ගතය: Debian/Ubuntu පැකේජ", + "The Rust package manager.
Contains: Rust libraries and programs written in Rust": "Rust පැකේජ කළමනාකරු.
අඩංගු වන්නේ: Rust libraries සහ Rust තුළ ලියූ වැඩසටහන්", + "The classical package manager for windows. You'll find everything there.
Contains: General Software": "Windows සඳහා සාම්ප්‍රදායික පැකේජ කළමනාකරු. ඔබට එහි සෑම දෙයක්ම හමුවේ.
අඩංගු වන්නේ: සාමාන්‍ය මෘදුකාංග", + "The default package manager for RHEL/Fedora-based Linux distributions.
Contains: RPM packages": "RHEL/Fedora පදනම් Linux බෙදාහැරීම් සඳහා පෙරනිමි පැකේජ කළමනාකරු.
අන්තර්ගතය: RPM පැකේජ", + "A repository full of tools and executables designed with Microsoft's .NET ecosystem in mind.
Contains: .NET related tools and scripts": "Microsoftගේ .NET පරිසර පද්ධතිය සැලකිල්ලට ගනිමින් නිර්මාණය කරන ලද මෙවලම් සහ ක්‍රියාත්මක ගොනු වලින් පිරුණු repository එකක්.
අඩංගු වන්නේ: .NET සම්බන්ධ මෙවලම් සහ scripts", + "The universal Linux package manager for desktop applications.
Contains: Flatpak applications from configured remotes": "ඩෙස්ක්ටොප් යෙදුම් සඳහා විශ්ව Linux පැකේජ කළමනාකරු.
අඩංගු වේ: වින්‍යාස කළ remotes වෙතින් Flatpak යෙදුම්", + "NuPkg (zipped manifest)": "NuPkg (සම්පීඩිත manifest)", + "The Missing Package Manager for macOS (or Linux).
Contains: Formulae, Casks": "macOS (හෝ Linux) සඳහා අතුරුදන් වූ පැකේජ කළමනාකරු.
අඩංගු වන්නේ: Formulae, Casks", + "Node JS's package manager. Full of libraries and other utilities that orbit the javascript world
Contains: Node javascript libraries and other related utilities": "Node JS හි පැකේජ කළමනාකරු. javascript ලෝකය වටා පවතින libraries සහ වෙනත් utilities වලින් පිරී ඇත
අඩංගු වන්නේ: Node javascript libraries සහ වෙනත් සම්බන්ධ utilities", + "The default package manager for Arch Linux and its derivatives.
Contains: Arch Linux packages": "Arch Linux සහ එහි ව්‍යුත්පන්න සඳහා පෙරනිමි පැකේජ කළමනාකරු.
අන්තර්ගතය: Arch Linux පැකේජ", + "Python's library manager. Full of python libraries and other python-related utilities
Contains: Python libraries and related utilities": "Python හි library manager. python libraries සහ වෙනත් python-සම්බන්ධ utilities වලින් පිරී ඇත
අඩංගු වන්නේ: Python libraries සහ සම්බන්ධ utilities", + "PowerShell's package manager. Find libraries and scripts to expand PowerShell capabilities
Contains: Modules, Scripts, Cmdlets": "PowerShell හි පැකේජ කළමනාකරු. PowerShell හැකියාවන් පුළුල් කිරීමට libraries සහ scripts සොයා ගන්න
අඩංගු වන්නේ: Modules, Scripts, Cmdlets", + "extracted": "උපුටා ගන්නා ලදී", + "Scoop package": "Scoop පැකේජය", + "Great repository of unknown but useful utilities and other interesting packages.
Contains: Utilities, Command-line programs, General Software (extras bucket required)": "නොදන්නා නමුත් ප්‍රයෝජනවත් utilities සහ වෙනත් රසවත් පැකේජ වලින් පිරුණු අගනා repository එකක්.
අඩංගු වන්නේ: Utilities, command-line වැඩසටහන්, සාමාන්‍ය මෘදුකාංග (extras bucket අවශ්‍යයි)", + "The universal Linux package manager by Canonical.
Contains: Snap packages from the Snapcraft store": "Canonical විසින් නිර්මිත සර්වත්‍ර Linux පැකේජ කළමනාකරු.
අන්තර්ගතය: Snapcraft වෙළඳසැලෙන් Snap පැකේජ", + "library": "පුස්තකාලය", + "feature": "විශේෂාංගය", + "A popular C/C++ library manager. Full of C/C++ libraries and other C/C++-related utilities
Contains: C/C++ libraries and related utilities": "ජනප්‍රිය C/C++ පුස්තකාල කළමනාකරුවෙකි. C/C++ පුස්තකාල සහ අනෙකුත් C/C++ සම්බන්ධ උපයෝගිතා වලින් පිරී ඇත
අඩංගු වන්නේ: C/C++ පුස්තකාල සහ සම්බන්ධ උපයෝගිතා", + "option": "විකල්පය", + "This package cannot be installed from an elevated context.": "මෙම පැකේජය elevated context එකකින් ස්ථාපනය කළ නොහැක.", + "Please run UniGetUI as a regular user and try again.": "කරුණාකර UniGetUI සාමාන්‍ය පරිශීලකයෙකු ලෙස ධාවනය කර නැවත උත්සාහ කරන්න.", + "Please check the installation options for this package and try again": "කරුණාකර මෙම පැකේජයේ ස්ථාපන විකල්ප පරීක්ෂා කර නැවත උත්සාහ කරන්න", + "Microsoft's official package manager. Full of well-known and verified packages
Contains: General Software, Microsoft Store apps": "Microsoft හි නිල පැකේජ කළමනාකරු. හොඳින් දන්නා සහ සනාථ කළ පැකේජ වලින් පිරී ඇත
අඩංගු වන්නේ: සාමාන්‍ය මෘදුකාංග, Microsoft Store apps", + "Local PC": "ස්ථානීය පරිගණකය", + "Android Subsystem": "ඇන්ඩ්‍රොයිඩ් උප පද්ධතිය", + "Operation on queue (position {0})...": "මෙහෙයුම queue හි ඇත (ස්ථානය {0})...", + "Click here for more details": "වැඩි විස්තර සඳහා මෙතැන ක්ලික් කරන්න", + "Operation canceled by user": "පරිශීලකයා මෙහෙයුම අවලංගු කළේය", + "Running PreOperation ({0}/{1})...": "PreOperation ධාවනය කරමින් ({0}/{1})...", + "PreOperation {0} out of {1} failed, and was tagged as necessary. Aborting...": "{1} න් {0} වන PreOperation අසාර්ථක වූ අතර එය අත්‍යවශ්‍ය ලෙස සලකුණු කර තිබුණි. නවත්වමින්...", + "PreOperation {0} out of {1} finished with result {2}": "{1} න් {0} වන PreOperation {2} ප්‍රතිඵලය සමඟ අවසන් විය", + "Starting operation...": "මෙහෙයුම ආරම්භ කරමින්...", + "Running PostOperation ({0}/{1})...": "PostOperation ධාවනය කරමින් ({0}/{1})...", + "PostOperation {0} out of {1} failed, and was tagged as necessary. Aborting...": "{1} න් {0} වන PostOperation අසාර්ථක වූ අතර එය අත්‍යවශ්‍ය ලෙස සලකුණු කර තිබුණි. නවත්වමින්...", + "PostOperation {0} out of {1} finished with result {2}": "{1} න් {0} වන PostOperation {2} ප්‍රතිඵලය සමඟ අවසන් විය", + "{package} installer download": "{package} installer බාගත කිරීම", + "{0} installer is being downloaded": "{0} installer බාගත කරමින් පවතී", + "Download succeeded": "බාගත කිරීම සම්පූර්ණයි", + "{package} installer was downloaded successfully": "{package} installer සාර්ථකව බාගත කරන ලදී", + "Download failed": "බාගත කිරීම අසාර්ථකයි", + "{package} installer could not be downloaded": "{package} installer බාගත කළ නොහැකි විය", + "{package} Installation": "{package} ස්ථාපනය", + "{0} is being installed": "{0} ස්ථාපනය කරමින් පවතී", + "Installation succeeded": "ස්ථාපනය සාර්ථකයි", + "{package} was installed successfully": "{package} සාර්ථකව ස්ථාපනය කරන ලදී", + "Installation failed": "ස්ථාපනය අසාර්ථකයි", + "{package} could not be installed": "{package} ස්ථාපනය කළ නොහැකි විය", + "{package} Update": "{package} යාවත්කාලීන කිරීම", + "Update succeeded": "යාවත්කාලීන කිරීම සාර්ථකයි", + "{package} was updated successfully": "{package} සාර්ථකව යාවත්කාලීන කරන ලදී", + "Update failed": "යාවත්කාලීන කිරීම අසාර්ථකයි", + "{package} could not be updated": "{package} යාවත්කාලීන කළ නොහැකි විය", + "{package} Uninstall": "{package} uninstall කිරීම", + "{0} is being uninstalled": "{0} uninstall කරමින් පවතී", + "Uninstall succeeded": "uninstall සාර්ථකයි", + "{package} was uninstalled successfully": "{package} සාර්ථකව uninstall කරන ලදී", + "Uninstall failed": "uninstall අසාර්ථකයි", + "{package} could not be uninstalled": "{package} uninstall කළ නොහැකි විය", + "Adding source {source}": "{source} ප්‍රභවය එක් කරයි", + "Adding source {source} to {manager}": "{source} ප්‍රභවය {manager} ට එක් කරයි", + "Source added successfully": "මූලාශ්‍රය සාර්ථකව එක් කරන ලදී", + "The source {source} was added to {manager} successfully": "{source} මූලාශ්‍රය {manager} වෙත සාර්ථකව එක් කරන ලදී", + "Could not add source": "මූලාශ්‍රය එක් කළ නොහැකි විය", + "Could not add source {source} to {manager}": "{source} මූලාශ්‍රය {manager} වෙත එක් කළ නොහැකි විය", + "Removing source {source}": "{source} මූලාශ්‍රය ඉවත් කරමින්", + "Removing source {source} from {manager}": "{manager} වෙතින් {source} මූලාශ්‍රය ඉවත් කරමින්", + "Source removed successfully": "මූලාශ්‍රය සාර්ථකව ඉවත් කරන ලදී", + "The source {source} was removed from {manager} successfully": "{source} මූලාශ්‍රය {manager} වෙතින් සාර්ථකව ඉවත් කරන ලදී", + "Could not remove source": "මූලාශ්‍රය ඉවත් කළ නොහැකි විය", + "Could not remove source {source} from {manager}": "{manager} වෙතින් {source} මූලාශ්‍රය ඉවත් කළ නොහැකි විය", + "The package manager \"{0}\" was not found": "\"{0}\" package manager එක හමු නොවීය", + "The package manager \"{0}\" is disabled": "\"{0}\" package manager එක අක්‍රීයයි", + "There is an error with the configuration of the package manager \"{0}\"": "\"{0}\" package manager එකේ configuration එකේ දෝෂයක් ඇත", + "The package \"{0}\" was not found on the package manager \"{1}\"": "\"{1}\" package manager හි \"{0}\" පැකේජය හමු නොවීය", + "{0} is disabled": "{0} අත්හිටු ඇත ", + "{0} weeks": "සති {0}ක්", + "1 month": "මාස 1ක්", + "{0} months": "මාස {0}ක්", + "Something went wrong": "යම් දෙයක් වැරදී ගියේය", + "An interal error occurred. Please view the log for further details.": "අභ්‍යන්තර දෝෂයක් සිදු විය. කරුණාකර වැඩිදුර තොරතුරු සදහා ලගුව බලන්න", + "No applicable installer was found for the package {0}": "{0} පැකේජය සඳහා ගැලපෙන installer එකක් හමු නොවීය", + "Integrity checks will not be performed during this operation": "මෙම මෙහෙයුම අතරතුර integrity checks සිදු නොවේ", + "This is not recommended.": "මෙය නිර්දේශ නොකෙරේ.", + "Run now": "දැන් ධාවනය කරන්න", + "Run next": "ඊළඟට ධාවනය කරන්න", + "Run last": "අවසන් ලෙස ධාවනය කරන්න", + "Show in explorer": "explorer තුළ පෙන්වන්න", + "Checked": "සලකුණු කර ඇත", + "Unchecked": "සලකුණු කර නැත", + "This package is already installed": "මෙම පැකේජය දැනටමත් ස්ථාපනය කර ඇත", + "This package can be upgraded to version {0}": "මෙම පැකේජය {0} සංස්කරණයට upgrade කළ හැක", + "Updates for this package are ignored": "මෙම පැකේජය සඳහා යාවත්කාලීන නොසලකා හැරේ", + "This package is being processed": "මෙම පැකේජය සැකසෙමින් පවතී", + "This package is not available": "මෙම පැකේජය ලබාගත නොහැක", + "Select the source you want to add:": "ඔබට එක් කිරීමට අවශ්‍ය මූලාශ්‍රය තෝරන්න:", + "Source name:": "මූලාශ්‍ර නම:", + "Source URL:": "මූලාශ්‍ර URL:", + "An error occurred when adding the source: ": "මූලාශ්‍රය එක් කිරීමේදී දෝෂයක් ඇති විය: ", + "Package management made easy": "පැකේජ කළමනාකරණය පහසු කළා", + "version {0}": "සංස්කරණය {0}", + "[RAN AS ADMINISTRATOR]": "[පරිපාලක ලෙස ධාවනය විය]", + "Portable mode": "ගෙන යා හැකි මාදිලිය\n", + "DEBUG BUILD": "DEBUG build සංස්කරණය", + "Here you can change UniGetUI's behaviour regarding the following shortcuts. Checking a shortcut will make UniGetUI delete it if if gets created on a future upgrade. Unchecking it will keep the shortcut intact": "මෙහි ඔබට පහත shortcuts සම්බන්ධයෙන් UniGetUI හි හැසිරීම වෙනස් කළ හැකිය. shortcut එකක් ටික් කළහොත් එය ඉදිරි upgrade එකකදී සෑදුවහොත් UniGetUI එය මකා දමයි. ටික් ඉවත් කළහොත් shortcut එක එලෙසම පවතී.", + "Manual scan": "අතින් scan කිරීම", + "Existing shortcuts on your desktop will be scanned, and you will need to pick which ones to keep and which ones to remove.": "ඔබගේ desktop හි පවතින shortcuts scan කරනු ලැබේ, සහ තබා ගත යුත්තේ කුමනද, ඉවත් කළ යුත්තේ කුමනද යන්න ඔබට තෝරාගත යුතුය.", + "Delete?": "මකන්නද?", + "I understand": "මම දැනුවත්", + "Chocolatey setup changed": "Chocolatey සැකසුම වෙනස් විය", + "UniGetUI no longer includes its own private Chocolatey installation. A legacy UniGetUI-managed Chocolatey installation was detected for this user profile, but system Chocolatey was not found. Chocolatey will stay unavailable in UniGetUI until Chocolatey is installed on the system and UniGetUI is restarted. Applications previously installed through UniGetUI's bundled Chocolatey may still appear under other sources such as Local PC or WinGet.": "UniGetUI හි තමන්ගේම පෞද්ගලික Chocolatey ස්ථාපනය තවදුරටත් ඇතුළත් නොවේ. මෙම පරිශීලක පැතිකඩ සඳහා UniGetUI-කළමනාකරණ පැරණි Chocolatey ස්ථාපනයක් හමු විය, නමුත් පද්ධති Chocolatey සොයාගත නොහැකි විය. පද්ධතියේ Chocolatey ස්ථාපනය කර UniGetUI නැවත ආරම්භ කරන තෙක් UniGetUI තුළ Chocolatey ලබා ගත නොහැක. UniGetUI හි ඇසුරුම් කළ Chocolatey හරහා කලින් ස්ථාපනය කළ යෙදුම් Local PC හෝ WinGet වැනි වෙනත් මූලාශ්‍ර යටතේ තවමත් දිස්විය හැක.", + "NOTE: This troubleshooter can be disabled from UniGetUI Settings, on the WinGet section": "සටහන: මෙම troubleshooter UniGetUI Settings හි WinGet කොටසෙන් අක්‍රීය කළ හැක", + "Restart": "නැවත ආරම්භ කරන්න", + "Are you sure you want to delete all shortcuts?": "ඔබට සියලු shortcuts මකා දැමීමට විශ්වාසද?", + "Any new shorcuts created during an install or an update operation will be deleted automatically, instead of showing a confirmation prompt the first time they are detected.": "ස්ථාපනයක් හෝ යාවත්කාලීන මෙහෙයුමක් අතරතුර නිර්මාණය කරන ලද නව shortcuts, මුල්වරට හඳුනාගත් විට තහවුරු කිරීමේ prompt එකක් පෙන්වීම වෙනුවට, ස්වයංක්‍රීයව මකා දමනු ඇත.", + "Any shorcuts created or modified outside of UniGetUI will be ignored. You will be able to add them via the {0} button.": "UniGetUI ට පිටතින් නිර්මාණය කරන ලද හෝ වෙනස් කරන ලද shortcuts නොසලකා හරිනු ලැබේ. ඔබට ඒවා {0} බොත්තම මගින් එක් කළ හැකියි.", + "Are you really sure you want to enable this feature?": "මෙම විශේෂාංගය සක්‍රීය කිරීමට ඔබට ඇත්තටම විශ්වාසද?", + "No new shortcuts were found during the scan.": "scan කිරීම අතරතුර නව shortcuts හමු නොවීය.", + "How to add packages to a bundle": "බණ්ඩලයකට පැකේජ එක් කරන ආකාරය", + "In order to add packages to a bundle, you will need to: ": "බණ්ඩලයකට පැකේජ එක් කිරීමට, ඔබට පහත දෑ කළ යුතුය: ", + "1. Navigate to the \"{0}\" or \"{1}\" page.": "1. \"{0}\" හෝ \"{1}\" පිටුවට යන්න.", + "2. Locate the package(s) you want to add to the bundle, and select their leftmost checkbox.": "2. ඔබට බණ්ඩලයට එක් කිරීමට අවශ්‍ය පැකේජ සොයාගෙන, ඒවායේ වම්පස ඇති checkbox එක තෝරන්න.", + "3. When the packages you want to add to the bundle are selected, find and click the option \"{0}\" on the toolbar.": "3. ඔබට බණ්ඩලයට එක් කිරීමට අවශ්‍ය පැකේජ තෝරාගත් පසු, toolbar එකේ \"{0}\" විකල්පය සොයා ක්ලික් කරන්න.", + "4. Your packages will have been added to the bundle. You can continue adding packages, or export the bundle.": "4. ඔබගේ පැකේජ බණ්ඩලයට එක් කර ඇත. ඔබට තවත් පැකේජ එක් කිරීමට හෝ බණ්ඩලය අපනයනය කිරීමට හැකිය.", + "Which backup do you want to open?": "ඔබට විවෘත කිරීමට අවශ්‍ය backup එක කුමක්ද?", + "Select the backup you want to open. Later, you will be able to review which packages you want to install.": "ඔබට විවෘත කිරීමට අවශ්‍ය backup එක තෝරන්න. පසුව, ස්ථාපනය කිරීමට අවශ්‍ය පැකේජ කුමනදැයි සමාලෝචනය කළ හැකිය.", + "There are ongoing operations. Quitting UniGetUI may cause them to fail. Do you want to continue?": "ක්‍රියාත්මක වෙමින් පවතින මෙහෙයුම් ඇත. UniGetUI ඉවත් වීමෙන් ඒවා අසාර්ථක විය හැක. ඔබට ඉදිරියට යාමට අවශ්‍යද?", + "UniGetUI or some of its components are missing or corrupt.": "UniGetUI හෝ එහි කොටස් කිහිපයක් අතුරුදන් හෝ දූෂිත වී ඇත.", + "It is strongly recommended to reinstall UniGetUI to adress the situation.": "මෙම තත්ත්වය නිවැරදි කිරීමට UniGetUI නැවත ස්ථාපනය කිරීම තදින්ම නිර්දේශ කෙරේ.", + "Refer to the UniGetUI Logs to get more details regarding the affected file(s)": "බලපෑමට ලක්වූ ගොනු පිළිබඳ වැඩි විස්තර සඳහා UniGetUI Logs වෙත යොමු වන්න", + "Integrity checks can be disabled from the Experimental Settings": "Experimental Settings වෙතින් integrity checks අක්‍රීය කළ හැක", + "Repair UniGetUI": "UniGetUI අලුත්වැඩියා කරන්න", + "Live output": "සජීව ප්‍රතිදානය", + "This package bundle had some settings that are potentially dangerous, and may be ignored by default.": "මෙම package bundle එකේ අනතුරුදායක විය හැකි සැකසුම් කිහිපයක් තිබූ අතර, ඒවා පෙරනිමියෙන් නොසලකා හැරිය හැක.", + "Entries that show in YELLOW will be IGNORED.": "YELLOW ලෙස පෙන්වන entries නොසලකා හරිනු ලැබේ.", + "Entries that show in RED will be IMPORTED.": "RED ලෙස පෙන්වන entries ආයාත කරනු ලැබේ.", + "You can change this behavior on UniGetUI security settings.": "මෙම හැසිරීම UniGetUI ආරක්ෂක සැකසුම් තුළ වෙනස් කළ හැක.", + "Open UniGetUI security settings": "UniGetUI ආරක්ෂක සැකසුම් විවෘත කරන්න", + "Should you modify the security settings, you will need to open the bundle again for the changes to take effect.": "ඔබ ආරක්ෂක සැකසුම් වෙනස් කළහොත්, වෙනස්කම් බලපැවැත්වීමට bundle එක නැවත විවෘත කළ යුතුය.", + "Details of the report:": "වාර්තාවේ විස්තර:", + "Are you sure you want to create a new package bundle? ": "නව පැකේජ බණ්ඩලයක් සෑදීමට ඔබට විශ්වාසද? ", + "Any unsaved changes will be lost": "සුරකින්නේ නැති සියලු වෙනස්කම් අහිමි වනු ඇත", + "Warning!": "අවවාදයයි!", + "For security reasons, custom command-line arguments are disabled by default. Go to UniGetUI security settings to change this. ": "ආරක්ෂක හේතු මත අභිරුචි command-line arguments පෙරනිමියෙන් අක්‍රීයයි. මෙය වෙනස් කිරීමට UniGetUI ආරක්ෂක සැකසුම් වෙත යන්න. ", + "Change default options": "පෙරනිමි විකල්ප වෙනස් කරන්න", + "Ignore future updates for this package": "මෙම පැකේජය සඳහා අනාගත යාවත්කාලීන නොසලකා හරින්න", + "For security reasons, pre-operation and post-operation scripts are disabled by default. Go to UniGetUI security settings to change this. ": "ආරක්ෂක හේතු මත pre-operation සහ post-operation scripts පෙරනිමියෙන් අක්‍රීයයි. මෙය වෙනස් කිරීමට UniGetUI ආරක්ෂක සැකසුම් වෙත යන්න. ", + "You can define the commands that will be run before or after this package is installed, updated or uninstalled. They will be run on a command prompt, so CMD scripts will work here.": "මෙම පැකේජය ස්ථාපනය, යාවත්කාලීන හෝ uninstall කිරීමට පෙර හෝ පසු ධාවනය වන commands ඔබට අර්ථ දැක්විය හැක. ඒවා command prompt එකක ධාවනය වන බැවින් CMD scripts මෙහි ක්‍රියා කරයි.", + "Change this and unlock": "මෙය වෙනස් කර unlock කරන්න", + "{0} Install options are currently locked because {0} follows the default install options.": "{0} පෙරනිමි install options අනුගමනය කරන බැවින් {0} Install options දැනට අගුලු දමා ඇත.", + "Unset or unknown": "set කර නොමැති හෝ නොදන්නා", + "This package has no screenshots or is missing the icon? Contrbute to UniGetUI by adding the missing icons and screenshots to our open, public database.": "මෙම පැකේජයට screenshots නොමැතිද හෝ icon එක අතුරුදන්වී තිබේද? අපගේ විවෘත, පොදු දත්ත සමුදායට අතුරුදන් icons සහ screenshots එක් කර UniGetUI වෙත දායක වන්න.", + "Become a contributor": "සහයෝගිකයෙකු වන්න", + "Update to {0} available": "{0} වෙත යාවත්කාලීන කිරීම ලබාගත හැක", + "Reinstall": "නැවත ස්ථාපනය කරන්න", + "Installer not available": "Installer ලබාගත නොහැක", + "Version:": "සංස්කරණය:", + "UniGetUI Version {0}": "UniGetUI සංස්කරණය {0}", + "Performing backup, please wait...": "backup ගනිමින් පවතී, කරුණාකර රැඳී සිටින්න...", + "An error occurred while logging in: ": "පිවිසීමේදී දෝෂයක් ඇති විය: ", + "Fetching available backups...": "ලබාගත හැකි උපස්ථ ගෙනෙමින්...", + "Done!": "සම්පූර්ණයි!", + "The cloud backup has been loaded successfully.": "cloud backup එක සාර්ථකව load කරන ලදී.", + "An error occurred while loading a backup: ": "උපස්ථයක් පූරණය කිරීමේදී දෝෂයක් ඇති විය: ", + "Backing up packages to GitHub Gist...": "පැකේජ GitHub Gist වෙත උපස්ථ කරමින්...", + "Backup Successful": "උපස්ථය සාර්ථකයි", + "The cloud backup completed successfully.": "cloud backup එක සාර්ථකව අවසන් විය.", + "Could not back up packages to GitHub Gist: ": "පැකේජ GitHub Gist වෙත උපස්ථ කළ නොහැකි විය: ", + "It is not guaranteed that the provided credentials will be stored safely, so you may as well not use the credentials of your bank account": "සපයන ලද credentials ආරක්ෂිතව ගබඩා කරනු ඇතැයි සහතික කළ නොහැකි බැවින්, ඔබේ බැංකු ගිණුමේ credentials භාවිතා නොකිරීම වඩාත් සුදුසුය", + "Enable the automatic WinGet troubleshooter": "ස්වයංක්‍රීය WinGet troubleshooter සක්‍රීය කරන්න", + "Add updates that fail with a 'no applicable update found' to the ignored updates list": "'no applicable update found' යන දෝෂයෙන් අසාර්ථක වන යාවත්කාලීන ignored updates ලැයිස්තුවට එක් කරන්න", + "Invalid selection": "වලංගු නොවන තේරීම", + "No package was selected": "කිසිදු පැකේජයක් තෝරා නොමැත", + "More than 1 package was selected": "පැකේජ 1කට වඩා තෝරා ඇත", + "List": "ලැයිස්තුව", + "Grid": "ජාලකය", + "Icons": "අයිකන", + "\"{0}\" is a local package and does not have available details": "\"{0}\" ස්ථානීය පැකේජයක් වන අතර ඒ සඳහා ලබාගත හැකි විස්තර නොමැත", + "\"{0}\" is a local package and is not compatible with this feature": "\"{0}\" ස්ථානීය පැකේජයක් වන අතර මෙම විශේෂාංගය සමඟ අනුකූල නොවේ", + "Add packages to bundle": "බණ්ඩලයට පැකේජ එක් කරන්න", + "Preparing packages, please wait...": "පැකේජ සූදානම් කරමින්, කරුණාකර රැඳී සිටින්න...", + "Loading packages, please wait...": "පැකේජ පූරණය කරමින්, කරුණාකර රැඳී සිටින්න...", + "Saving packages, please wait...": "පැකේජ සුරකිමින්, කරුණාකර රැඳී සිටින්න...", + "The bundle was created successfully on {0}": "bundle එක {0} දින සාර්ථකව සාදන ලදි", + "User profile": "පරිශීලක profile", + "Error": "දෝෂයක්", + "Log in failed: ": "පිවිසීම අසාර්ථකයි: ", + "Log out failed: ": "ඉවත් වීම අසාර්ථකයි: ", + "Package backup settings": "පැකේජ backup සැකසුම්", + "Package managers": "පැකේජ කළමනාකරුවන්", + "Manage UniGetUI autostart behaviour from the Settings app": "UniGetUI ස්වයං ආරම්භ හැසිරීම කළමනාකරණය කරන්න", + "Choose how many operations shoulds be performed in parallel": "එකවර ක්‍රියාත්මක කළ යුතු මෙහෙයුම් ගණන තෝරන්න", + "Something went wrong while launching the updater.": "updater ආරම්භ කිරීමේදී යම් දෙයක් වැරදී ගියේය.", + "Please try again later": "කරුණාකර පසුව නැවත උත්සාහ කරන්න", + "Show the release notes after UniGetUI is updated": "UniGetUI යාවත්කාලීන වූ පසු නිකුතු සටහන් පෙන්වන්න" +} diff --git a/src/Languages/lang_sk.json b/src/Languages/lang_sk.json new file mode 100644 index 0000000..84cc8a9 --- /dev/null +++ b/src/Languages/lang_sk.json @@ -0,0 +1,851 @@ +{ + "{0} of {1} operations completed": "Dokončených {0} z {1} operácií", + "{0} is now {1}": "{0} je teraz {1}", + "Enabled": "Povolené", + "Disabled": "Vypnutý", + "Privacy": "Súkromie", + "Hide my username from the logs": "Skryť moje používateľské meno z protokolov", + "Replaces your username with **** in the logs. Restart UniGetUI to also hide it from already-recorded entries.": "Nahradí vaše používateľské meno znakmi **** v protokoloch. Reštartujte UniGetUI, aby sa skrylo aj v už zaznamenaných záznamoch.", + "Your last update attempt did not complete.": "Váš posledný pokus o aktualizáciu sa nedokončil.", + "UniGetUI could not confirm whether the update succeeded. Open the log to see what happened.": "UniGetUI nedokázal potvrdiť, či bola aktualizácia úspešná. Otvorte protokol a zistite, čo sa stalo.", + "View log": "Zobraziť protokol", + "The installer reported success but did not restart UniGetUI.": "Inštalátor nahlásil úspech, ale nereštartoval UniGetUI.", + "The installer failed to initialize.": "Inštalátor sa nepodarilo inicializovať.", + "Setup was canceled before installation began.": "Inštalácia bola zrušená ešte pred jej začatím.", + "A fatal error occurred during the preparation phase.": "Počas prípravnej fázy nastala závažná chyba.", + "A fatal error occurred during installation.": "Počas inštalácie nastala závažná chyba.", + "Installation was canceled while in progress.": "Inštalácia bola zrušená počas priebehu.", + "The installer was terminated by another process.": "Inštalátor bol ukončený iným procesom.", + "The preparation phase determined the installation cannot proceed.": "Prípravná fáza zistila, že inštalácia nemôže pokračovať.", + "The installer could not start. UniGetUI may already be running, or you do not have permission to install.": "Inštalátor sa nepodarilo spustiť. UniGetUI už môže byť spustený alebo nemáte oprávnenie na inštaláciu.", + "Unexpected installer error.": "Neočakávaná chyba inštalátora.", + "We are checking for updates.": "Kontrolujeme aktualizácie.", + "Please wait": "Prosím čakajte", + "Great! You are on the latest version.": "Skvelé! Máte najnovšiu verziu.", + "There are no new UniGetUI versions to be installed": "Neexistujú žiadne nové verzie UniGetUI, ktoré by bolo treba inštalovať", + "UniGetUI version {0} is being downloaded.": "Sťahuje sa verzia UniGetUI {0}", + "This may take a minute or two": "Môže to trvať minútu alebo dve.", + "The installer authenticity could not be verified.": "Pravosť inštalačného programu nebolo možné overiť.", + "The update process has been aborted.": "Aktualizačný proces bol prerušený.", + "Auto-update is not yet available on this platform.": "Automatická aktualizácia zatiaľ nie je na tejto platforme dostupná.", + "Please update UniGetUI manually.": "Aktualizujte UniGetUI ručne.", + "An error occurred when checking for updates: ": "Došlo ku chybe pri vyhľadávaní aktualizácii", + "The updater could not be launched.": "Aktualizátor sa nepodarilo spustiť.", + "The operating system did not start the installer process.": "Operačný systém nespustil proces inštalátora.", + "UniGetUI is being updated...": "UniGetUI sa aktualizuje...", + "Update installed.": "Aktualizácia nainštalovaná.", + "UniGetUI was updated successfully, but this running copy was not replaced. This usually means you are running a development build. Close this copy and start the newly-installed version to finish.": "UniGetUI bol úspešne aktualizovaný, ale táto spustená kópia nebola nahradená. Zvyčajne to znamená, že používate vývojárske zostavenie. Dokončite to zatvorením tejto kópie a spustením novo nainštalovanej verzie.", + "The update could not be applied.": "Aktualizáciu sa nepodarilo použiť.", + "Installer exit code {0}: {1}": "Kód ukončenia inštalátora {0}: {1}", + "Update cancelled.": "Aktualizácia zrušená.", + "Authentication was cancelled.": "Overenie bolo zrušené.", + "Installer exit code {0}": "Kód ukončenia inštalátora {0}", + "Operation in progress": "Prebiehajúce operácie", + "Please wait...": "Prosím čakajte...", + "Success!": "Úspech!", + "Failed": "Zlyhalo", + "An error occurred while processing this package": "Došlo ku chybe pri spracovávaní tohoto balíčka", + "Installer": "Inštalátor", + "Executable": "Spustiteľný súbor", + "MSI": "MSI", + "Compressed file": "Komprimovaný súbor", + "MSIX": "MSIX", + "WinGet was repaired successfully": "WinGet bol úspešne opravený", + "It is recommended to restart UniGetUI after WinGet has been repaired": "Po oprave WinGet sa odporúča reštartovať aplikáciu UniGetUI", + "WinGet could not be repaired": "WinGet sa nepodarilo opraviť", + "An unexpected issue occurred while attempting to repair WinGet. Please try again later": "Nastala neočakávaná chyba pri pokuse o opravu WinGet. Skúste to neskôr", + "Log in to enable cloud backup": "Prihláste sa, aby sa povolilo zálohovánie do cloudu", + "Backup Failed": "Zálohovanie sa nepodarilo", + "Downloading backup...": "Sťahovanie zálohy...", + "An update was found!": "Bola nájdená aktualizácia!", + "{0} can be updated to version {1}": "{0} môže byť aktualizované na verziu {1}", + "Updates found!": "Nájdené aktualizácie!", + "{0} packages can be updated": "{0} sa môže aktualizovať", + "{0} is being updated to version {1}": "{0} sa aktualizuje na verziu {1}", + "{0} packages are being updated": "{0} balíčkov sa aktualizuje", + "You have currently version {0} installed": "Aktuálne máte nainštalovanú verziu {0}", + "Desktop shortcut created": "Odkaz na ploche vytvorený", + "UniGetUI has detected a new desktop shortcut that can be deleted automatically.": "UniGetUI zistil nový odkaz na ploche, ktorý môže byť automaticky odstránený.", + "{0} desktop shortcuts created": "{0} vytvorených odkazov na ploche", + "UniGetUI has detected {0} new desktop shortcuts that can be deleted automatically.": "UniGetUI zistil {0} nových zástupcov na ploche, ktoré je možné automaticky odstrániť.", + "Attention required": "Vyžaduje sa pozornosť", + "Restart required": "Je potrebný reštart", + "1 update is available": "1 dostupná aktualizácia", + "{0} updates are available": "Je dostupných {0} aktualizácií.", + "Everything is up to date": "Všetko je aktuálne", + "Discover Packages": "Objavte balíčky", + "Available Updates": "Dostupné aktualizácie", + "Installed Packages": "Nainštalované balíčky", + "UniGetUI Version {0} by Devolutions": "UniGetUI verzia {0} od Devolutions", + "Show UniGetUI": "Zobraziť UniGetUI", + "Quit": "Ukončiť", + "Are you sure?": "Ste si istý?", + "Do you really want to uninstall {0}?": "Naozaj chcete odinštalovať {0}?", + "Do you really want to uninstall the following {0} packages?": "Naozaj chcete odinštalovať nasledovných {0} balíčkov?", + "No": "Nie", + "Yes": "Áno", + "Partial": "Čiastočne", + "View on UniGetUI": "Zobraziť v UniGetUI", + "Update": "Aktualizovať", + "Open UniGetUI": "Otvoriť UniGetUI", + "Update all": "Aktualizovať všetko", + "Update now": "Aktualizovať teraz", + "Installer host changed since the installed version.\n": "Hostiteľ inštalátora sa od nainštalovanej verzie zmenil.\n", + "This package is on the queue": "Tento balíček je vo fronte", + "installing": "inštalujem", + "updating": "aktualizujem", + "uninstalling": "odinštalujem", + "installed": "nainštalované", + "Retry": "Skúsiť znovu", + "Install": "Inštalovať", + "Uninstall": "Odinštalovať", + "Open": "Otvoriť", + "Operation profile:": "Profil operácie:", + "Follow the default options when installing, upgrading or uninstalling this package": "Pri inštalácii, aktualizácii alebo odinštalácii tohoto balíčku postupujte podľa predvolených možností.", + "The following settings will be applied each time this package is installed, updated or removed.": "Nasledovné nastavenia sa použijú pri každej inštalácii, aktualizácii alebo odobraní tohoto balíčku.", + "Version to install:": "Verzia:", + "Architecture to install:": "Architektúra:", + "Installation scope:": "Rozsah rozhrania:", + "Install location:": "Umiestnenie inštalácie:", + "Select": "Vybrať", + "Reset": "Resetovať", + "Custom install arguments:": "Vlastné argumenty pre inštaláciu:", + "Custom update arguments:": "Vlastné argumenty pre aktualizáciu:", + "Custom uninstall arguments:": "Vlastné argumenty pre odinštalovanie:", + "Pre-install command:": "Príkaz pred inštaláciou:", + "Post-install command:": "Príkaz po inštalácii:", + "Abort install if pre-install command fails": "Zrušiť inštaláciu, ak zlyhá príkaz pred inštaláciou", + "Pre-update command:": "Príkaz pred aktualizáciou:", + "Post-update command:": "Príkaz po aktualizácii:", + "Abort update if pre-update command fails": "Zrušiť aktualizáciu, ak zlyhá príkaz pred aktualizáciou", + "Pre-uninstall command:": "Príkaz pred odinštaláciou:", + "Post-uninstall command:": "Príkaz po odinštalácii:", + "Abort uninstall if pre-uninstall command fails": "Zrušiť odinštalovanie, ak zlyhá príkaz pred odinštalovaním", + "Command-line to run:": "Príkazový riadok pre spustenie:", + "Save and close": "Uložiť a zavrieť", + "General": "Všeobecné", + "Architecture & Location": "Architektúra a umiestnenie", + "Command-line": "Príkazový riadok", + "Close apps": "Zavrieť aplikácie", + "Pre/Post install": "Pred/po inštalácii", + "Select the processes that should be closed before this package is installed, updated or uninstalled.": "Vyberte procesy, ktoré by mali byť ukončené pred inštaláciou, aktualizáciou alebo odinštaláciou tohoto balíčku.", + "Write here the process names here, separated by commas (,)": "Sem napíšte názvy procesov oddelené čiarkami (,).", + "Try to kill the processes that refuse to close when requested to": "Pokúste sa ukončiť procesy, ktoré sa odmietajú zavrieť, keď to je požadované.", + "Run as admin": "Spustiť ako správca", + "Interactive installation": "Interaktívna inštalácia", + "Skip hash check": "Preskočiť kontrolný súčet", + "Uninstall previous versions when updated": "Odinštalovať predchádzajúcu verziu po aktualizácii", + "Skip minor updates for this package": "Preskočenie drobných aktualizácií tohoto balíčku", + "Automatically update this package": "Automaticky aktualizovať tento balíček", + "{0} installation options": "{0} možnosti inštalácie", + "Latest": "Najnovšie", + "PreRelease": "Predbežná verzia", + "Default": "Predvolené", + "Manage ignored updates": "Spravovať ignorované aktualizácie", + "The packages listed here won't be taken in account when checking for updates. Double-click them or click the button on their right to stop ignoring their updates.": "Uvedené balíčky nebudú pri kontrole aktualizácií brané do úvahy. Dvakrát kliknite na ne alebo kliknite na tlačidlo vpravo, aby ste prestali ignorovať ich aktualizácie.", + "Reset list": "Obnoviť zoznam", + "Do you really want to reset the ignored updates list? This action cannot be reverted": "Naozaj chcete obnoviť zoznam ignorovaných aktualizácií? Túto akciu nemožno vrátiť späť.", + "No ignored updates": "Žiadne ignorované aktualizácie", + "Package Name": "Názov balíčka", + "Package ID": "ID balíčka", + "Ignored version": "Ignorovaná verzia", + "New version": "Nová verzia", + "Source": "Zdroj", + "All versions": "Všetky verzie", + "Unknown": "Neznáme", + "Up to date": "Aktuálne", + "Package {name} from {manager}": "Balíček {name} z {manager}", + "Remove {0} from ignored updates": "Odstrániť {0} z ignorovaných aktualizácií", + "Cancel": "Zrušiť", + "Administrator privileges": "Oprávnenia správcu", + "This operation is running with administrator privileges.": "Táto operácia je spustená s oprávnením správcu.", + "Interactive operation": "Interaktívna operácia", + "This operation is running interactively.": "Táto operácia je spustená interaktívne.", + "You will likely need to interact with the installer.": "Pravdepodobne budete musieť s inštalátorom interagovať.", + "Integrity checks skipped": "Kontrola integrity preskočená", + "Integrity checks will not be performed during this operation.": "Počas tejto operácie sa nebudú vykonávať kontroly integrity.", + "Proceed at your own risk.": "Pokračujte na vlastné nebezpečenstvo.", + "Close": "Zavrieť", + "Loading...": "Načítavam...", + "Installer SHA256": "SHA256", + "Homepage": "Domovská stránka", + "Author": "Autor", + "Publisher": "Vydavateľ", + "License": "Licencia", + "Manifest": "Manifest", + "Installer Type": "Typ inštalátora", + "Size": "Veľkosť", + "Installer URL": "URL", + "Last updated:": "Posledná aktualizácia:", + "Release notes URL": "URL Poznámok k vydaniu", + "Package details": "Detaily balíčka", + "Dependencies:": "Závislosti:", + "Release notes": "Poznámky k vydaniu", + "Screenshots": "Snímky obrazovky", + "This package has no screenshots or is missing the icon? Contribute to UniGetUI by adding the missing icons and screenshots to our open, public database.": "Chýbajú tomuto balíčku snímky obrazovky alebo ikona? Prispejte do UniGetUI pridaním chýbajúcich ikon a snímok obrazovky do našej otvorenej verejnej databázy.", + "Version": "Verzia", + "Install as administrator": "Inštalovať ako správca", + "Update to version {0}": "Aktualizovať na verziu {0}", + "Installed Version": "Nainštalovaná verzia", + "Update as administrator": "Aktualizovať ako správca", + "Interactive update": "Interaktívna aktualizácia", + "Uninstall as administrator": "Odinštalovať ako správca", + "Interactive uninstall": "Interaktívna odinštalácia", + "Uninstall and remove data": "Odinštalovať a odstrániť dáta", + "Not available": "Nedostupné", + "Installer SHA512": "SHA512", + "Unknown size": "Neznáma veľkosť", + "No dependencies specified": "Nie sú uvedené žiadne závislosti", + "mandatory": "povinné", + "optional": "voliteľné", + "UniGetUI {0} is ready to be installed.": "UniGetUI {0} je pripravený k inštalácii.", + "The update process will start after closing UniGetUI": "Aktualizácie začne po zavrení UniGetUI", + "UniGetUI has been ran as administrator, which is not recommended. When running UniGetUI as administrator, EVERY operation launched from UniGetUI will have administrator privileges. You can still use the program, but we highly recommend not running UniGetUI with administrator privileges.": "UniGetUI bol spustený ako správca, čo sa neodporúča. Keď UniGetUI spúšťate ako správca, KAŽDÁ operácia spustená z UniGetUI bude mať oprávnenia správcu. Program môžete používať aj naďalej, no dôrazne odporúčame nespúšťať UniGetUI s oprávneniami správcu.", + "Share anonymous usage data": "Zdieľanie anonymných dát o používaní", + "UniGetUI collects anonymous usage data in order to improve the user experience.": "UniGetUI zhromažďuje anonymné údaje o používaní za účelom zlepšenia používateľského komfortu.", + "Accept": "Prijať", + "Software Updates": "Aktualizácie softvéru", + "Package Bundles": "Zväzky balíčkov", + "Settings": "Nastavenia", + "Package Managers": "Manažéri balíčkov", + "UniGetUI Log": "Protokol UniGetUI", + "Package Manager logs": "Protokoly správcu balíčkov", + "Operation history": "História operácií", + "Help": "Pomoc", + "UniGetUI": "UniGetUI", + "You have installed UniGetUI Version {0}": "Je nainštalovaný UniGetUI verzie {0}", + "Disclaimer": "Upozornenie", + "UniGetUI is developed by Devolutions and is not affiliated with any of the compatible package managers.": "UniGetUI vyvíja spoločnosť Devolutions a nie je pridružený k žiadnemu z kompatibilných správcov balíkov.", + "UniGetUI wouldn't have been possible without the help of the contributors. Thank you all 🥳": "UniGetUI by nebolo možné vytvoriť bez pomoci prispievateľov. Ďakujem Vám všetkým 🥳", + "UniGetUI uses the following libraries. Without them, UniGetUI wouldn't have been possible.": "UniGetUI používa nasledovné knižnice. Bez nich by UniGetUI nebol možný.", + "{0} homepage": "{0} domovská stránka", + "UniGetUI has been translated to more than 40 languages thanks to the volunteer translators. Thank you 🤝": "UniGetUI bol vďaka dobrovoľným prekladateľom preložený do viac než 40 jazykov. Ďakujeme 🤝", + "Verbose": "Podrobný výstup", + "1 - Errors": "1 - Chyby", + "2 - Warnings": "2 - Varovania", + "3 - Information (less)": "3 - Informácie (menej)", + "4 - Information (more)": "4 - Informácie (viac)", + "5 - information (debug)": "5 - Informácie (ladenie)", + "Warning": "Upozornenie", + "The following settings may pose a security risk, hence they are disabled by default.": "Nasledovné nastavenia môžu predstavovať bezpečnostné riziko, preto sú v predvolenom nastavení zakázané.", + "Enable the settings below if and only if you fully understand what they do, and the implications they may have.": "Nižšie uvedené nastavenia povoľte, POKIAĽ A IBA POKIAĽ úplne rozumiete, k čomu slúžia a aké môžu mať dôsledky.", + "The settings will list, in their descriptions, the potential security issues they may have.": "V popise nastavení budú uvedené potenciálne bezpečnostné problémy, ktorú môžu mať.", + "The backup will include the complete list of the installed packages and their installation options. Ignored updates and skipped versions will also be saved.": "Záloha bude obsahovať kompletný zoznam nainštalovaných balíčkov a možnosti ich inštalácie. Uložené budú taktiež ignorované aktualizácie a preskočené verzie.", + "The backup will NOT include any binary file nor any program's saved data.": "Záloha NEBUDE obsahovať binárne súbory ani uložené dáta programov.", + "The size of the backup is estimated to be less than 1MB.": "Veľkosť zálohy sa odhaduje na menej než 1 MB.", + "The backup will be performed after login.": "Zálohovanie sa vykoná po prihlásení.", + "{pcName} installed packages": "{pcName} nainštalované balíčky", + "Current status: Not logged in": "Aktuálny stav: Neprihlásený", + "You are logged in as {0} (@{1})": "ste prihlásený ako {0} (@{1})", + "Nice! Backups will be uploaded to a private gist on your account": "Pekne! Zálohy budú nahraté do súkromného gistu na vašom účte.", + "Select backup": "Výber zálohy", + "Settings imported from {0}": "Nastavenia importované z {0}", + "UniGetUI Settings": "Nastavenia UniGetUI", + "Settings exported to {0}": "Nastavenia exportované do {0}", + "UniGetUI settings were reset": "Nastavenia UniGetUI boli obnovené", + "Allow pre-release versions": "Povoliť predbežné verzie", + "Apply": "Použiť", + "For security reasons, custom command-line arguments are disabled by default. Go to UniGetUI security settings to change this.": "Z bezpečnostných dôvodov sú vlastné argumenty príkazového riadku predvolene zakázané. Ak to chcete zmeniť, prejdite do nastavení zabezpečenia UniGetUI.", + "Go to UniGetUI security settings": "Prejdite do nastavenia zabezpečenia UniGetUI", + "The following options will be applied by default each time a {0} package is installed, upgraded or uninstalled.": "Pri každej inštalácii, aktualizácii alebo odinštalácii balíčku {0} sa v predvolenom nastavení použijú nasledovné možnosti.", + "Package's default": "Predvolené nastavenie balíčka", + "Install location can't be changed for {0} packages": "Umiestnenie inštalácie nejde zmeniť pre {0} balíčkov", + "The local icon cache currently takes {0} MB": "Medzipamäť ikoniek aktuálne zaberá {0} MB", + "Username": "Používateľské meno", + "Password": "Heslo", + "Credentials": "Osobné údaje", + "It is not guaranteed that the provided credentials will be stored safely": "Nie je zaručené, že poskytnuté prihlasovacie údaje budú uložené bezpečne", + "Partially": "Čiastočne", + "Package manager": "Správca balíčkov", + "Compatible with proxy": "Kompatibilné s proxy", + "Compatible with authentication": "Kompatibilné s overením", + "Proxy compatibility table": "Tabuľka kompatibility proxy serverov", + "{0} settings": "{0} nastavenia", + "{0} status": "{0} stav", + "Default installation options for {0} packages": "Predvolené možnosti inštalácie {0} balíčkov", + "Expand version": "Rozbal verziu", + "The executable file for {0} was not found": "Spustiteľný súbor pre {0} nebol nájdený", + "{pm} is disabled": "{pm} je vypnutý", + "Enable it to install packages from {pm}.": "Povoľte to pre inštaláciu balíčkov z {pm}.", + "{pm} is enabled and ready to go": "{pm} je povolený a pripravený k použitiu", + "{pm} version:": "{pm} verzia:", + "{pm} was not found!": "{pm} nebol nájdený!", + "You may need to install {pm} in order to use it with UniGetUI.": "Môže byť nutné nainštalovať {pm} pre použitie s UniGetUI.", + "Scoop Installer - UniGetUI": "Scoop inštalátor - UniGetUI", + "Scoop Uninstaller - UniGetUI": "Scoop odinštalátor - UniGetUI", + "Clearing Scoop cache - UniGetUI": "Mazanie medzipamäte Scoop - UniGetUI", + "Restart UniGetUI to fully apply changes": "Reštartujte UniGetUI, aby sa zmeny úplne prejavili", + "Restart UniGetUI": "Reštartovať UniGetUI", + "Manage {0} sources": "Správa zdrojov {0}", + "Add source": "Pridať zdroj", + "Add": "Pridať", + "Source name": "Názov zdroja", + "Source URL": "URL zdroja", + "Other": "Iné", + "No minimum age": "Bez minimálnej doby", + "1 day": "1 deň", + "{0} days": "{0} dní", + "Custom...": "Vlastné...", + "{0} minutes": "{0} minút", + "1 hour": "1 hodina", + "{0} hours": "{0} hodin", + "1 week": "1 týždeň", + "Supports release dates": "Podporuje dátumy vydania", + "Release date support per package manager": "Podpora dátumu vydania podľa správcu balíčkov", + "Search for packages": "Vyhľadávanie balíčkov", + "Local": "Lokálny", + "OK": "OK", + "Last checked: {0}": "Naposledy skontrolované: {0}", + "{0} packages were found, {1} of which match the specified filters.": "Bolo nájdených {0} balíčkov, z ktorých {1} vyhovuje zadaným filtrom.", + "{0} selected": "{0} vybraných", + "(Last checked: {0})": "(Naposledy skontrolované: {0})", + "All packages selected": "Všetky balíčky vybrané", + "Package selection cleared": "Výber balíčkov vymazaný", + "{0}: {1}": "{0}: {1}", + "More info": "Viac informácií", + "GitHub account": "Účet GitHub", + "Log in with GitHub to enable cloud package backup.": "Prihláste sa cez GitHub, aby sa povolilo zálohovanie do cloudu", + "More details": "Viac detailov", + "Log in": "Prihlásiť sa", + "If you have cloud backup enabled, it will be saved as a GitHub Gist on this account": "Pokiaľ máte povolené zálohovanie do cloudu, bude na tomto účte uložený ako GitHub Gist.", + "Log out": "Odhlásiť sa", + "About UniGetUI": "O aplikácii UniGetUI", + "About": "Aplikácie", + "Third-party licenses": "Licencie tretích strán", + "Contributors": "Prispievatelia", + "Translators": "Prekladatelia", + "Bundle security report": "Správa o bezpečnosti zväzku", + "The bundle contained restricted content": "Zväzok obsahoval obmedzený obsah", + "UniGetUI – Crash Report": "UniGetUI – Hlásenie o zlyhaní", + "UniGetUI has crashed": "UniGetUI zlyhalo", + "Help us fix this by sending a crash report to Devolutions. All fields below are optional.": "Pomôžte nám to opraviť odoslaním hlásenia o zlyhaní spoločnosti Devolutions. Všetky polia nižšie sú voliteľné.", + "Email (optional)": "E-mail (voliteľné)", + "your@email.com": "your@email.com", + "Additional details (optional)": "Ďalšie podrobnosti (voliteľné)", + "Describe what you were doing when the crash occurred…": "Popíšte, čo ste robili, keď došlo k zlyhaniu…", + "Crash report": "Hlásenie o zlyhaní", + "Don't Send": "Neodosielať", + "Send Report": "Odoslať hlásenie", + "Sending…": "Odosielanie…", + "Unsaved changes": "Neuložené zmeny", + "You have unsaved changes in the current bundle. Do you want to discard them?": "V aktuálnom zväzku máte neuložené zmeny. Chcete ich zahodiť?", + "Discard changes": "Zahodiť zmeny", + "Integrity violation": "Porušenie integrity", + "UniGetUI or some of its components are missing or corrupt. It is strongly recommended to reinstall UniGetUI to adress the situation.": "UniGetUI alebo niektoré jeho súčasti chýbajú alebo sú poškodené. Dôrazne sa odporúča preinštalovať UniGetUI, aby sa situácia vyriešila.", + "• Refer to the UniGetUI Logs to get more details regarding the affected file(s)": "• Pozrite sa do protokolov UniGetUI pre získanie viacerých podrobností o postihnutých súboroch", + "• Integrity checks can be disabled from the Experimental Settings": "• Kontrolu intergrity je možné zakázať v Experimentálnom nastavení", + "Manage shortcuts": "Spravovať odkazy", + "UniGetUI has detected the following desktop shortcuts which can be removed automatically on future upgrades": "UniGetUI zistil nasledovné odkazy na ploche, ktoré je možné pri budúcich aktualizáciách automaticky odstrániť", + "Do you really want to reset this list? This action cannot be reverted.": "Naozaj chcete tento zoznam obnoviť? Túto akciu nejde vrátiť späť.", + "Desktop shortcuts list": "Zoznam odkazov na ploche", + "Open in explorer": "Otvoriť v Prieskumníkovi", + "Remove from list": "Odstrániť zo zoznamu", + "When new shortcuts are detected, delete them automatically instead of showing this dialog.": "Keď sú detekované nové odkazy, automaticky ich zmazať, namiesto aby sa zobrazovalo toto dialógové okno.", + "Not right now": "Teraz nie", + "Missing dependency": "Chýbajúca závislosť", + "UniGetUI requires {0} to operate, but it was not found on your system.": "UniGetUI vyžaduje pre svoju činnosť {0}, ale vo vašom systéme nebol nájdený.", + "Click on Install to begin the installation process. If you skip the installation, UniGetUI may not work as expected.": "Kliknutím na tlačidlo Inštalácia zahájite proces inštalácie. Pokiaľ inštaláciu preskočíte, nemusí UniGetUI fungovať podľa očakávania.", + "Alternatively, you can also install {0} by running the following command in a Windows PowerShell prompt:": "Alternatívne môžete nainštalovať {0} aj spustením nasledujúceho príkazu v príkazovom riadku Windows PowerShell:", + "Install {0}": "Nainštalovať {0}", + "Do not show this dialog again for {0}": "Nezobrazovať znovu tento dialóg pre {0}", + "Please wait while {0} is being installed. A black window may show up. Please wait until it closes.": "Počkajte prosím, než sa nainštaluje {0}. Môže sa zobraziť čierne (alebo modré) okno. Počkajte, pokým sa nezavre.", + "{0} has been installed successfully.": "{0} bol úspešne nainštalovaný", + "Please click on \"Continue\" to continue": "Pre pokračovanie kliknite na \"Pokračovať\"", + "Continue": "Pokračovať", + "{0} has been installed successfully. It is recommended to restart UniGetUI to finish the installation": "{0} bolo úspešne nainštalované. Je odporúčané reštartovať UniGetUI pre dokončenie inštalácie.", + "Restart later": "Reštartovať neskôr", + "An error occurred:": "Nastala chyba:", + "Please see the Command-line Output or refer to the Operation History for further information about the issue.": "Ďalšie informácie o probléme nájdete vo výstupe príkazového riadku alebo v historii operácií.", + "Retry as administrator": "Skúsiť znovu ako správca", + "Retry interactively": "Skúsiť znovu interaktívne", + "Retry skipping integrity checks": "Skúsiť znovu bez kontroly integrity", + "Installation options": "Voľby inštalácie", + "Save": "Uložiť", + "UniGetUI collects anonymous usage data with the sole purpose of understanding and improving the user experience.": "UniGetUI zhromažďuje anonymné údaje o používaní iba za účelom pochopenia a zlepšenia používateľských skúseností.", + "More details about the shared data and how it will be processed": "Viac podrobností o zdieľaných údajoch a spôsobe ich spracovania", + "Do you accept that UniGetUI collects and sends anonymous usage statistics, with the sole purpose of understanding and improving the user experience?": "Súhlasíte s tým, že UniGetUI zhromažďuje a odosiela anonymné štatistiky o používaní, a to výhradne za účelom pochopenia a zlepšenia používateľských skúseností?", + "Decline": "Zamietnuť", + "No personal information is collected nor sent, and the collected data is anonimized, so it can't be back-tracked to you.": "Nie sú zhromažďované ani odosielané osobné údaje a zhromaždené údaje sú anonymizované, takže ich nejde spätne vysledovať.", + "Navigation panel": "Navigačný panel", + "Operations": "Operácie", + "Toggle operations panel": "Prepnúť panel operácií", + "Bulk operations": "Hromadné operácie", + "Retry failed": "Zopakovať neúspešné", + "Clear successful": "Vymazať úspešné", + "Clear finished": "Vymazať dokončené", + "Cancel all": "Zrušiť všetko", + "More": "Viac", + "Toggle navigation panel": "Prepnúť navigačný panel", + "Minimize": "Minimalizovať", + "Maximize": "Maximalizovať", + "UniGetUI by Devolutions": "UniGetUI od Devolutions", + "UniGetUI is an application that makes managing your software easier, by providing an all-in-one graphical interface for your command-line package managers.": "UniGetUI je aplikácia, ktorá uľahčuje správu vášho softvéru tak, že poskytuje grafické rozhranie pre vašich správcov balíčkov príkazového riadku.", + "Useful links": "Užitočné odkazy", + "UniGetUI Homepage": "Domovská stránka UniGetUI", + "Report an issue or submit a feature request": "Nahlásiť problém alebo odoslať požiadavku na funkciu", + "UniGetUI Repository": "Repozitár UniGetUI", + "View GitHub Profile": "Zobraziť GitHub profil", + "UniGetUI License": "UniGetUI licencia", + "Using UniGetUI implies the acceptation of the MIT License": "Používanie UniGetUI znamená súhlas s licenciou MIT.", + "Become a translator": "Staň sa prekladateľom", + "Go back": "Prejsť späť", + "Go forward": "Prejsť dopredu", + "Go to home page": "Prejsť na domovskú stránku", + "Reload page": "Obnoviť stránku", + "View page on browser": "Zobraziť stránku v prehliadači", + "The built-in browser is not supported on Linux yet.": "Vstavaný prehliadač zatiaľ nie je v Linuxe podporovaný.", + "Open in browser": "Otvoriť v prehliadači", + "Copy to clipboard": "Skopírovať do schránky", + "Export to a file": "Exportovať do súboru", + "Log level:": "Úroveň protokolu:", + "Reload log": "Znovu načítať protokol", + "Export log": "Exportovať protokol", + "Text": "Text", + "Change how operations request administrator rights": "Zmena spôsobu, akým operácie vyžadujú oprávnenia správcu", + "Restrictions on package operations": "Obmedzenie operácií s balíčkami", + "Restrictions on package managers": "Obmedzenie sprácov balíčkov", + "Restrictions when importing package bundles": "Obmedzenie pri importe balíčkov", + "Ask for administrator privileges once for each batch of operations": "Vyžiadať práva správcu pre každú várku operácii", + "Ask only once for administrator privileges": "Požiadať o administrátorské práva len raz", + "Prohibit any kind of Elevation via UniGetUI Elevator or GSudo": "Zákaz akéhokoľvek povýšenia pomocou UniGetUI Elevator alebo GSudo", + "This option WILL cause issues. Any operation incapable of elevating itself WILL FAIL. Install/update/uninstall as administrator will NOT WORK.": "Táto možnosť bude spôsobovať problémy. Akákoľvek operácia, ktorá sa nedokáže sama povýšiť, zlyhá. Inštalácia/aktualizácia/odinštalácia ako správca NEBUDE FUNGOVAŤ.", + "Allow custom command-line arguments": "Povoliť vlastné argumenty príkazového riadku", + "Custom command-line arguments can change the way in which programs are installed, upgraded or uninstalled, in a way UniGetUI cannot control. Using custom command-lines can break packages. Proceed with caution.": "Vlastné argumenty príkazového riadku môžu zmeniť spôsob, akým sú programy inštalované, aktualizované alebo odinštalované, spôsobom, akým UniGetUI nemôže kontrolovať. Použitie vlastných príkazových riadkov môže poškodiť balíčky. Postupujte opatrne.", + "Ignore custom pre-install and post-install commands when importing packages from a bundle": "Povoliť spustenie vlastných príkazov pred a po inštalácii", + "Pre and post install commands will be run before and after a package gets installed, upgraded or uninstalled. Be aware that they may break things unless used carefully": "Príkazy pred a po inštalácii budú spustené pred a po inštalácii, aktualizácii alebo odinštalácii balíčku. Uvedomte si, že môžu veci poškodiť, pokiaľ nebudú použité opatrne.", + "Allow changing the paths for package manager executables": "Povoliť zmenu ciest pre spustiteľné súbory správcu balíčkov", + "Turning this on enables changing the executable file used to interact with package managers. While this allows finer-grained customization of your install processes, it may also be dangerous": "Zapnutie tejto funkcie umožňuje zmeniť spustiteľný súbor používaný pre interakciu so správcami balíčkov. To síce umožňuje lepšie prispôsobenie inštalačných procesov, ale môže to byť nebezpečné.", + "Allow importing custom command-line arguments when importing packages from a bundle": "Povoliť importovanie vlastných argumentov príkazového riadku pri importe balíčkov zo zväzku", + "Malformed command-line arguments can break packages, or even allow a malicious actor to gain privileged execution. Therefore, importing custom command-line arguments is disabled by default": "Nesprávne formátované argumenty príkazového riadku môžu poškodiť balíčky alebo dokonca umožniť útočníkovi získať privilegované spúšťanie. Preto je import vlastných argumentov príkazového riadku v predvolenom nastavení zakázaný.", + "Allow importing custom pre-install and post-install commands when importing packages from a bundle": "Povoliť importovanie vlastných príkazov pred a po inštalácii pri importe balíčkov zo zväzku", + "Pre and post install commands can do very nasty things to your device, if designed to do so. It can be very dangerous to import the commands from a bundle, unless you trust the source of that package bundle": "Príkazy pred a po inštalácii môžu spôsobiť veľmi nepríjemné veci vašemu zariadeniu, pokiaľ sú k tomu navrhnuté. Môže byť veľmi nebezpečné importovať príkazy zo zväzku, pokiaľ nedôverujte zdroju tohto zväzku balíčkov.", + "Administrator rights and other dangerous settings": "Administrátorské práva a iné nebezpečné nastavenia", + "Package backup": "Záloha balíčku", + "Cloud package backup": "Zálohovanie balíčkov v cloude", + "Local package backup": "Miestne zálohovanie balíčkov", + "Local backup advanced options": "Pokročilé možnosti miestneho zálohovania", + "Log in with GitHub": "Prihlásiť sa cez GitHub", + "Log out from GitHub": "Odhlásiť sa z GitHub", + "Periodically perform a cloud backup of the installed packages": "Pravidelne vykonávať cloudovú zálohu nainštalovaných balíčkov", + "Cloud backup uses a private GitHub Gist to store a list of installed packages": "Cloudové zálohovanie používa súkromný Gist GitHub pre uloženie zoznamu nainštalovaných balíčkov.", + "Perform a cloud backup now": "Vykonať zálohovanie do cloudu teraz", + "Backup": "Zálohovať", + "Restore a backup from the cloud": "Obnova zálohy z cloudu", + "Begin the process to select a cloud backup and review which packages to restore": "Začnite proces výberu zálohy v cloude a skontrolujte, ktoré balíčky chcete obnoviť", + "Periodically perform a local backup of the installed packages": "Pravidelne vykonávať miestnu zálohu nainštalovaných balíčkov", + "Perform a local backup now": "Vykonať miestne zálohovanie teraz", + "Change backup output directory": "Zmena výstupného adresára zálohy", + "Set a custom backup file name": "Vlastný názov pre súbor zálohy", + "Leave empty for default": "Nechať prázdne pre predvolené", + "Add a timestamp to the backup file names": "Pridať čas do názvov záložných súborov", + "Backup and Restore": "Zálohovanie a obnovenie", + "Enable background api (UniGetUI Widgets and Sharing, port 7058)": "Povoliť api na pozadí (Widgets pre UniGetUI a Zdieľanie, port 7058)", + "Wait for the device to be connected to the internet before attempting to do tasks that require internet connectivity.": "Pred vykonávaním úloh, ktoré vyžadujú pripojenie k internetu, počkajte, až bude zariadenie pripojené k internetu.", + "Disable the 1-minute timeout for package-related operations": "Vypnutie minutového limitu pre operácie súvisiace s balíčkami", + "Use installed GSudo instead of UniGetUI Elevator": "Použiť nainštalovaný GSudo namiesto UniGetUI Elevator", + "Use a custom icon and screenshot database URL": "Použiť vlastnú URL databázu pre ikonky a screenshoty", + "Enable background CPU Usage optimizations (see Pull Request #3278)": "Povolenie optimalizácie využitia procesoru na pozadí (viď Pull Request #3278)", + "Perform integrity checks at startup": "Vykonať kontrolu integrity pri spustení", + "When batch installing packages from a bundle, install also packages that are already installed": "Pri dávkovej inštalácii balíčkov zo zväzku nainštalovať aj balíčky, ktoré už sú nainštalované.", + "Experimental settings and developer options": "Experimentálne nastavenia a možnosti pre vývojárov", + "Show UniGetUI's version and build number on the titlebar.": "Zobraziť verziu UniGetUI v záhlaviu okna", + "Language": "Jazyk", + "UniGetUI updater": "Aktualizácia UniGetUI", + "Telemetry": "Telemetria", + "Manage UniGetUI settings": "Správa nastavení UnigetUI", + "Related settings": "Súvisiace nastavenia", + "Update UniGetUI automatically": "Automaticky aktualizovať UniGetUI", + "Check for updates": "Kontrolovať aktualizácie", + "Install prerelease versions of UniGetUI": "Inštalovať predbežné verzie UniGetUI", + "Manage telemetry settings": "Spravovať nastavenia telemetrie", + "Manage": "Správa", + "Import settings from a local file": "Importovať nastavenie zo súboru", + "Import": "Importovať", + "Export settings to a local file": "Exportovať nastavenia do súboru", + "Export": "Exportovať", + "Reset UniGetUI": "Obnoviť UniGetUI", + "User interface preferences": "Vlastnosti používateľského rozhrania", + "Application theme, startup page, package icons, clear successful installs automatically": "Téma aplikácie, úvodná stránka, ikony balíčkov, automatické vymazanie úspešných inštalácií", + "General preferences": "Všeobecné preferencie", + "UniGetUI display language:": "Jazyk UniGetUI", + "System language": "Jazyk systému", + "Is your language missing or incomplete?": "Chýba váš jazyk, alebo nie je úplný?", + "Appearance": "Vzhľad", + "UniGetUI on the background and system tray": "UniGetUI v pozadí a systémovej lište", + "Package lists": "Zoznamy balíčkov", + "Use classic mode": "Použiť klasický režim", + "Restart UniGetUI to apply this change": "Reštartujte UniGetUI, aby sa táto zmena prejavila", + "The classic UI is disabled for beta testers": "Klasické používateľské rozhranie je pre beta testerov vypnuté", + "Close UniGetUI to the system tray": "Zatvárať UniGetUI do systémovej lišty", + "Manage UniGetUI autostart behaviour": "Spravovať správanie automatického spúšťania UniGetUI", + "Show package icons on package lists": "Zobraziť ikonky balíčkov na zozname balíčkov", + "Clear cache": "Vymazať vyrovnávaciu pamäť", + "Select upgradable packages by default": "Vždy vybrať aktualizovateľné balíčky", + "Light": "Svetlý", + "Dark": "Tmavé", + "Follow system color scheme": "Podľa systému", + "Application theme:": "Motív aplikácie:", + "UniGetUI startup page:": "Pri spustení UniGetUI zobraziť:", + "Proxy settings": "Nastavenia proxy serveru", + "Other settings": "Iné nastavenia", + "Connect the internet using a custom proxy": "Pripojte sa na internet pomocou vlastnej proxy", + "Please note that not all package managers may fully support this feature": "Upozorňujeme, že nie všetci správcovia balíčkov môžu túto funkciu plne podporovať.", + "Proxy URL": "URL proxy servera", + "Enter proxy URL here": "Sem zadajte URL proxy servera", + "Authenticate to the proxy with a user and a password": "Overiť sa na proxy pomocou používateľského mena a hesla", + "Internet and proxy settings": "Nastavenia internetu a proxy", + "Package manager preferences": "Nastavenie správcu balíčkov", + "Ready": "Pripravený", + "Not found": "Nenájdené", + "Notification preferences": "Predvoľby oznámení", + "Notification types": "Typy oznámení", + "The system tray icon must be enabled in order for notifications to work": "Aby oznámenia fungovali, musí byť povolená ikona v systémovej lište", + "Enable UniGetUI notifications": "Zapnúť oznámenia UniGetUI", + "Show a notification when there are available updates": "Zobraziť oznámenie, pokiaľ sú dostupné aktualizácie", + "Show a silent notification when an operation is running": "Zobraziť tiché oznámenia pri bežiacej operácii", + "Show a notification when an operation fails": "Zobraziť oznámenie po zlyhaní operácie", + "Show a notification when an operation finishes successfully": "Zobraziť oznámenie po úspešnom dokončení operácie", + "Concurrency and execution": "Súbežnosť a vykonávanie", + "Automatic desktop shortcut remover": "Automatický odstraňovač odkazov na ploche", + "Choose how many operations should be performed in parallel": "Vyberte, koľko operácií sa má vykonávať súbežne", + "Clear successful operations from the operation list after a 5 second delay": "Vymazať úspešné operácie po 5 minútach zo zoznamu operácií", + "Download operations are not affected by this setting": "Toto nastavenie nemá vplyv na operácie sťahovania", + "You may lose unsaved data": "Môže nastať strata neuložených dát.", + "Ask to delete desktop shortcuts created during an install or upgrade.": "Požiadajte o odstránenie odkazov na ploche vytvorených počas inštalácie alebo aktualizácie.", + "Package update preferences": "Predvoľby aktualizácií balíčkov", + "Update check frequency, automatically install updates, etc.": "Frekvencia kontroly aktualizácií, automatická inštalácia aktualizácií, atď.", + "Reduce UAC prompts, elevate installations by default, unlock certain dangerous features, etc.": "Obmedzenie výziev UAC, predvolene zvýšenie úrovne inštalácií, odomknutie niektorých nebezpečných funkcií, atď.", + "Package operation preferences": "Prevoľby operácií s balíčkami", + "Enable {pm}": "Zapnúť {pm}", + "Not finding the file you are looking for? Make sure it has been added to path.": "Nenašli ste hľadaný súbor? Skontrolujte, či bol pridaný do cesty.", + "Select the executable to be used. The following list shows the executables found by UniGetUI": "Vyberte spustiteľný súbor, ktorý chcete použiť. Nasledujúci zoznam obsahuje spustiteľné súbory nájdené UniGetUI.", + "For security reasons, changing the executable file is disabled by default": "Zmena spustiteľného súboru je v predvolenom nastavení z bezpečnostných dôvodov zakázaná.", + "Change this": "Zmeniť toto", + "Copy path": "Kopírovať cestu", + "Current executable file:": "Aktuálny spustiteľný súbor:", + "Ignore packages from {pm} when showing a notification about updates": "Ignorovať balíčky z {pm} pri zobrazení oznámení o aktualizáciách", + "Update security": "Zabezpečenie aktualizácií", + "Use global setting": "Použiť globálne nastavenie", + "Minimum age for updates": "Minimálny vek aktualizácií", + "e.g. 10": "napr. 10", + "Custom minimum age (days)": "Vlastný minimálny vek (dni)", + "{pm} does not provide release dates for its packages, so this setting will have no effect": "{pm} neposkytuje dátumy vydania svojich balíčkov, takže toto nastavenie nebude mať žiadny účinok", + "{pm} only provides release dates for some of its packages, so this setting will only apply to those packages": "{pm} poskytuje dátumy vydania len pre niektoré svoje balíky, preto sa toto nastavenie použije len pre tieto balíky", + "Override the global minimum update age for this package manager": "Prepísať globálny minimálny vek aktualizácií pre tohto správcu balíčkov", + "View {0} logs": "Zobraziť {0} protokolov", + "If Python cannot be found or is not listing packages but is installed on the system, ": "Ak sa Python nepodarí nájsť alebo nezobrazuje balíčky, ale je v systéme nainštalovaný, ", + "Advanced options": "Pokročilé možnosti", + "WinGet command-line tool": "Nástroj príkazového riadka WinGet", + "Choose which command-line tool UniGetUI uses for WinGet operations when the COM API is not used": "Vyberte, ktorý nástroj príkazového riadka má UniGetUI používať na operácie WinGet, keď sa nepoužíva COM API", + "WinGet COM API": "WinGet COM API", + "Choose whether UniGetUI can use the WinGet COM API before falling back to the command-line tool": "Vyberte, či môže UniGetUI používať COM API WinGet pred návratom k nástroju príkazového riadka", + "Reset WinGet": "Obnoviť UniGetUI", + "This may help if no packages are listed": "Toto môže pomôcť, keď sa balíčky nezobrazujú", + "Force install location parameter when updating packages with custom locations": "Vynútiť parameter umiestnenia inštalácie pri aktualizovaní balíčkov s vlastnými umiestneniami", + "Install Scoop": "Nainštalovať Scoop", + "Uninstall Scoop (and its packages)": "Odinštalovať Scoop (a jeho balíčky)", + "Run cleanup and clear cache": "Spustiť čistenie a vymazať medzipamäť", + "Run": "Spustiť", + "Enable Scoop cleanup on launch": "Zapnúť prečistenie Scoop-u po spustení", + "Default vcpkg triplet": "Predvolený vcpkg triplet", + "Change vcpkg root location": "Zmeniť koreňové umiestnenie vcpkg", + "Reset vcpkg root location": "Obnoviť umiestnenie koreňového adresára vcpkg", + "Open vcpkg root location": "Otvoriť umiestnenie koreňového adresára vcpkg", + "Language, theme and other miscellaneous preferences": "Lokalizácia, motívy a ďalšie rôzne vlastnosti", + "Show notifications on different events": "Zobraziť oznámenia o rôznych udalostiach", + "Change how UniGetUI checks and installs available updates for your packages": "Zmeňte, ako UniGetUI kontroluje a inštaluje dostupné aktualizácie pre vaše balíčky", + "Automatically save a list of all your installed packages to easily restore them.": "Automatické uloženie zoznamu všetkých nainštalovaných balíčkov pre ich jednoduché obnovenie.", + "Enable and disable package managers, change default install options, etc.": "Povolenie a zakázanie správcu balíčkov, zmena predvolených možností inštalácie, atď.", + "Internet connection settings": "Nastavenia pripojenia k internetu", + "Proxy settings, etc.": "Nastavenia proxy serveru, atď.", + "Beta features and other options that shouldn't be touched": "Beta funkcie a ďalšie nastavenia ktorých by ste sa nemali dotýkať", + "Reload sources": "Obnoviť zdroje", + "Delete source": "Odstrániť zdroj", + "Known sources": "Známe zdroje", + "Update checking": "Kontrola aktualizácií", + "Automatic updates": "Automatické aktualizácie", + "Check for package updates periodically": "Pravidelne kontrolovať aktualizácie balíčkov", + "Check for updates every:": "Kontrolovať aktualizácie každých: ", + "Install available updates automatically": "Automaticky inštalovať dostupné aktualizácie", + "Do not automatically install updates when the network connection is metered": "Neinštalovať aktualizácie, pokiaľ je sieťové pripojenie účtované objemom dát", + "Do not automatically install updates when the device runs on battery": "Neinštalovať aktualizácie, pokiaľ zariadenie beží na batérii", + "Do not automatically install updates when the battery saver is on": "Neinštalovať aktualizácie, pokiaľ je zapnutý šetrič energie", + "Only show updates that are at least the specified number of days old": "Zobrazovať len aktualizácie staré aspoň zadaný počet dní", + "Warn me when the installer URL host changes between the installed version and the new version (WinGet only)": "Upozorniť ma, keď sa hostiteľ URL inštalátora zmení medzi nainštalovanou verziou a novou verziou (iba WinGet)", + "Change how UniGetUI handles install, update and uninstall operations.": "Zmeňte spôsob, akým UniGetUI spracováva operácie inštalácie, aktualizácie a odinštalácie.", + "Navigation": "Navigácia", + "Check for UniGetUI updates": "Skontrolovať aktualizácie UniGetUI", + "Quit UniGetUI": "Ukončiť UniGetUI", + "Filters": "Filtre", + "Sources": "Zdroje", + "Search for packages to start": "Pre výpis balíčkov začnite vyhľadávať", + "Select all": "Vybrať všetko", + "Clear selection": "Zrušiť výber", + "Instant search": "Okamžité hľadanie", + "Distinguish between uppercase and lowercase": "Rozlišovať veľké a malé písmená", + "Ignore special characters": "Ignorovať špeciálne znaky", + "Search mode": "Režim vyhľadávania", + "Both": "Obe", + "Exact match": "Presná zhoda", + "Show similar packages": "Podobné balíčky", + "Loading": "Načítavanie", + "Package": "Balíček", + "More options": "Ďalšie možnosti", + "Order by:": "Zoradiť podľa:", + "Name": "Meno", + "Id": "ID", + "Ascendant": "Vzostupne", + "Descendant": "Zostupne", + "View modes": "Režimy zobrazenia", + "Reload": "Obnoviť", + "Closed": "Zatvorené", + "Ascending": "Vzostupne", + "Descending": "Zostupne", + "{0}: {1}, {2}": "{0}: {1}, {2}", + "Order by": "Zoradiť podľa", + "No results were found matching the input criteria": "Nebol nájdený žiadny výsledok splňujúci kritériá", + "No packages were found": "Žiadne balíčky neboli nájdené", + "Loading packages": "Načítanie balíčkov", + "Skip integrity checks": "Preskočiť kontrolu integrity", + "Download selected installers": "Stiahnuť vybrané inštalačné programy", + "Install selection": "Nainštalovať vybrané", + "Install options": "Možnosti inštalácie", + "Add selection to bundle": "Pridať výber do zväzku", + "Download installer": "Stiahnuť inštalátor", + "Uninstall selection": "Odinštalovať vybrané", + "Uninstall options": "Možnosti odinštalácie", + "Ignore selected packages": "Ignorovať vybrané balíčky", + "Open install location": "Otvoriť umiestnenie inštalácie", + "Reinstall package": "Preinštalovať balíček", + "Uninstall package, then reinstall it": "Odinštalovať balíček a potom znovu nainštalovať", + "Ignore updates for this package": "Ignorovať aktualizácie pre tento balíček", + "WinGet malfunction detected": "Zistená porucha WinGet", + "It looks like WinGet is not working properly. Do you want to attempt to repair WinGet?": "Vyzerá, že program WinGet nefunguje správne. Chcete sa pokúsiť WinGet opraviť?", + "Repair WinGet": "Opraviť WinGet", + "Updates will no longer be ignored for {0}": "Aktualizácie pre {0} už nebudú ignorované", + "Updates are now ignored for {0}": "Aktualizácie pre {0} sú teraz ignorované", + "Do not ignore updates for this package anymore": "Neignorovať aktualizácie tohoto balíčka", + "Add packages or open an existing package bundle": "Pridať balíčky alebo otvoriť existujúci zväzok balíčkov", + "Add packages to start": "Pridať balíčky na štart", + "The current bundle has no packages. Add some packages to get started": "Aktuálny zväzok neobsahuje žiadne balíčky. Pridajte nejaké balíčky", + "New": "Nový", + "Save as": "Uložiť ako", + "Create .ps1 script": "Vytvoriť .ps1 skript", + "Remove selection from bundle": "Odstrániť výber zo zväzku", + "Skip hash checks": "Preskočiť kontrolný súčet", + "The package bundle is not valid": "Zväzok balíčkov nie je platný", + "The bundle you are trying to load appears to be invalid. Please check the file and try again.": "Zväzok, ktorý sa snažíte načítať, vyzerá byť neplatný. Skontrolujte prosím súbor a skúste to znovu.", + "Package bundle": "Zväzok balíčka", + "Could not create bundle": "Zväzok sa nepodarilo vytvoriť", + "The package bundle could not be created due to an error.": "Zväzok balíčkov sa nepodarilo vytvoriť z dôvodu chyby.", + "Install script": "Inštalovať skript", + "PowerShell script": "Skript PowerShell", + "The installation script saved to {0}": "Inštalačný skript uložený do {0}", + "An error occurred": "Došlo ku chybe", + "An error occurred while attempting to create an installation script:": "Nastala chyba pri pokuse o vytvorenie inštalačného skriptu:", + "Hooray! No updates were found.": "Hurá! Neboli nájdené žiadne aktualizácie.", + "Uninstall selected packages": "Odinštalovať vybrané balíčky", + "Update selection": "Aktualizovať vybrané", + "Update options": "Možnosti aktualizácie", + "Uninstall package, then update it": "Odinštalovať balíček a potom ho aktualizovať", + "Uninstall package": "Odinštalovať balíček", + "Skip this version": "Preskočiť túto verziu", + "Pause updates for": "Pozastaviť aktualizácie na", + "User | Local": "Používateľ | Lokálne", + "Machine | Global": "Počítač | Globálne", + "The default package manager for Debian/Ubuntu-based Linux distributions.
Contains: Debian/Ubuntu packages": "Predvolený správca balíčkov pre distribúcie Linuxu založené na Debian/Ubuntu.
Obsahuje: balíčky Debian/Ubuntu", + "The Rust package manager.
Contains: Rust libraries and programs written in Rust": "Správca balíčkov Rust.
Obsahuje: Knižnice a programy napísané v Rust", + "The classical package manager for windows. You'll find everything there.
Contains: General Software": "Klasický správca balíčkov pre Windows. Nájdete v ňom všetko.
Obsahuje: Obecný softvér", + "The default package manager for RHEL/Fedora-based Linux distributions.
Contains: RPM packages": "Predvolený správca balíčkov pre distribúcie Linuxu založené na RHEL/Fedora.
Obsahuje: balíčky RPM", + "A repository full of tools and executables designed with Microsoft's .NET ecosystem in mind.
Contains: .NET related tools and scripts": "Repozitár plný nastrojov a spustiteľných súborov navrhnutých s ohľadom na Microsoft .NET ekosystém.
Obsahuje:Nástroje a skripty týkajúce sa platfromy .NET", + "The universal Linux package manager for desktop applications.
Contains: Flatpak applications from configured remotes": "Univerzálny správca balíčkov pre desktopové aplikácie v Linuxe.
Obsahuje: aplikácie Flatpak z nakonfigurovaných vzdialených zdrojov", + "NuPkg (zipped manifest)": "NuPkg (zazipovaný manifest)", + "The Missing Package Manager for macOS (or Linux).
Contains: Formulae, Casks": "Chýbajúci správca balíčkov pre macOS (alebo Linux).
Obsahuje: Formulae, Casks", + "Node JS's package manager. Full of libraries and other utilities that orbit the javascript world
Contains: Node javascript libraries and other related utilities": "Správca balíčkov Node.js, je plný knižníc a ďalších nástrojov, ktoré sa týkajú sveta javascriptu.
Obsahuje:Knižnice a ďalšie súvisiace nástroje pre Node.js", + "The default package manager for Arch Linux and its derivatives.
Contains: Arch Linux packages": "Predvolený správca balíčkov pre Arch Linux a jeho deriváty.
Obsahuje: balíčky Arch Linux", + "Python's library manager. Full of python libraries and other python-related utilities
Contains: Python libraries and related utilities": "Správca knižníc Pythonu a ďalších nástrojov súvisiacich s Pythonom.
Obsahuje: Knižnice Pythonu a súvisiace nástroje", + "PowerShell's package manager. Find libraries and scripts to expand PowerShell capabilities
Contains: Modules, Scripts, Cmdlets": "PowerShell správca balíčkov. Hľadanie knižníc a skriptov k rozšíreniu PowerShell schopností
Obsahuje: Moduly, Skripty, Cmdlets", + "extracted": "extrahované", + "Scoop package": "Scoop balíček", + "Great repository of unknown but useful utilities and other interesting packages.
Contains: Utilities, Command-line programs, General Software (extras bucket required)": "Rozsiahly repozitár neznámych, ale predsa užitočných nástrojov a ďalších zaujímavých balíčkov.
Obsahuje: Nástroje, programy príkazového riadku a obecný softvér (nutné extra repozitáre)", + "The universal Linux package manager by Canonical.
Contains: Snap packages from the Snapcraft store": "Univerzálny správca balíčkov pre Linux od Canonical.
Obsahuje: balíčky Snap z obchodu Snapcraft", + "library": "knižnica", + "feature": "funkcia", + "A popular C/C++ library manager. Full of C/C++ libraries and other C/C++-related utilities
Contains: C/C++ libraries and related utilities": "Populárny správca C/C++ knižníc. Obsahuje množstvo C/C++ knižníc a ďalších nástrojov súvisiacich s C/C++
Obsahuje:C/C++ knižnice a súvisiace nástroje", + "option": "možnosť", + "This package cannot be installed from an elevated context.": "Tento balíček nejde nainštalovať z kontextu vyššie.", + "Please run UniGetUI as a regular user and try again.": "Spusťte UniGetUI ako bežný používateľ a skúste to znova.", + "Please check the installation options for this package and try again": "Skontrolujte prosím možnosti inštalácie tohoto balíčka a skúste to znova", + "Microsoft's official package manager. Full of well-known and verified packages
Contains: General Software, Microsoft Store apps": "Oficiálny správca balíčkov od Microsoftu, plný dobre známych a overených programov
Obsahuje: Obecný softvér a aplikácie z Microsoft Store", + "Local PC": "Lokálny PC", + "Android Subsystem": "Subsystém Android", + "Operation on queue (position {0})...": "Operácia v poradí (pozícia {0})...", + "Click here for more details": "Kliknite sem pre viac informácií", + "Operation canceled by user": "Operácia zrušená používateľom", + "Running PreOperation ({0}/{1})...": "Spúšťa sa PreOperation ({0}/{1})...", + "PreOperation {0} out of {1} failed, and was tagged as necessary. Aborting...": "PreOperation {0} z {1} zlyhala a bola označená ako nevyhnutná. Prerušujem...", + "PreOperation {0} out of {1} finished with result {2}": "PreOperation {0} z {1} sa dokončila s výsledkom {2}", + "Starting operation...": "Spúštanie operácie...", + "Running PostOperation ({0}/{1})...": "Spúšťa sa PostOperation ({0}/{1})...", + "PostOperation {0} out of {1} failed, and was tagged as necessary. Aborting...": "PostOperation {0} z {1} zlyhala a bola označená ako nevyhnutná. Prerušujem...", + "PostOperation {0} out of {1} finished with result {2}": "PostOperation {0} z {1} sa dokončila s výsledkom {2}", + "{package} installer download": "Stiahnuť inštalačný program {package}", + "{0} installer is being downloaded": "Sťahuje sa inštalačný program {0}", + "Download succeeded": "Sťahovanie úspešné", + "{package} installer was downloaded successfully": "Inštalačný program {package} bol úspešne stiahnutý", + "Download failed": "Sťahovanie sa nepodarilo", + "{package} installer could not be downloaded": "Inštalačný program {package} sa nepodarilo stiahnuť", + "{package} Installation": "Inštalácia {package}", + "{0} is being installed": "{0} sa inštaluje", + "Installation succeeded": "Úspešne nainštalované", + "{package} was installed successfully": "{package} bol úspešne nainštalovaný", + "Installation failed": "Inštalácia zlyhala", + "{package} could not be installed": "{package} nemohol byť nainštalovaný", + "{package} Update": "Aktualizácia {package}", + "Update succeeded": "Úspešne aktualizované", + "{package} was updated successfully": "{package} bol úspešne aktualizovaný", + "Update failed": "Aktualizácia zlyhala", + "{package} could not be updated": "{package} nemohol byť aktualizovaný", + "{package} Uninstall": "Odinštalácia {package}", + "{0} is being uninstalled": "{0} sa odinštaluje", + "Uninstall succeeded": "Úspešne odinštalované", + "{package} was uninstalled successfully": "{package} bol úspešne odinštalovaný", + "Uninstall failed": "Odinštalácia zlyhala", + "{package} could not be uninstalled": "{package} nemohol byť odinštalovaný", + "Adding source {source}": "Pridávam zdroj {source}", + "Adding source {source} to {manager}": "Pridávanie zdroja {source} do {manager}", + "Source added successfully": "Zdroj bol úspešne pridaný", + "The source {source} was added to {manager} successfully": "Zdroj {source} bol úspešne pridaný do {manager}", + "Could not add source": "Nepodarilo sa pridať zdroj", + "Could not add source {source} to {manager}": "Nepodarilo sa pridať zdroj {source} do {manager}", + "Removing source {source}": "Odstraňovanie zdroja {source}", + "Removing source {source} from {manager}": "Odoberanie zdroja {source} z {manager}", + "Source removed successfully": "Zdroj bol úspešne odobraný", + "The source {source} was removed from {manager} successfully": "Zdroj {source} bol úspešne odobraný z {manager}", + "Could not remove source": "Nepodarilo sa odstrániť zdroj", + "Could not remove source {source} from {manager}": "Nepodarilo sa odobrať zdroj {source} z {manager}", + "The package manager \"{0}\" was not found": "Správca balíčkov \"{0}\" sa nenašiel", + "The package manager \"{0}\" is disabled": "Správca balíčkov \"{0}\" je vypnutý", + "There is an error with the configuration of the package manager \"{0}\"": "Došlo k chybe v konfigurácii správcu balíčkov \"{0}\"", + "The package \"{0}\" was not found on the package manager \"{1}\"": "Balíček \"{0}\" nebol nájdený v správcovi balíčkov \"{1}\"", + "{0} is disabled": "{0} je vypnuté", + "{0} weeks": "{0} týždňov", + "1 month": "1 mesiac", + "{0} months": "{0} mesiacov", + "Something went wrong": "Niečo sa pokazilo", + "An interal error occurred. Please view the log for further details.": "Došlo ku chybe. Prosím pozrite si protokol pre ďalšie detaily.", + "No applicable installer was found for the package {0}": "Pre balíček {0} nebol nájdený žiadny použiteľný inštalačný program.", + "Integrity checks will not be performed during this operation": "Kontrola integrity sa pri tejto operácii nevykonáva.", + "This is not recommended.": "Toto sa neodporúča.", + "Run now": "Spustiť hneď", + "Run next": "Spustiť ako ďalšie", + "Run last": "Spustiť ako posledné", + "Show in explorer": "Zobraziť v prieskumníkovi", + "Checked": "Zaškrtnuté", + "Unchecked": "Nezaškrtnuté", + "This package is already installed": "Tento balíček už je nainštalovaný", + "This package can be upgraded to version {0}": "Tento balíček môže byť aktualizovaný na verziu {0}", + "Updates for this package are ignored": "Aktualizácie tohoto balíčka sú ignorované", + "This package is being processed": "Tento balíček sa spracováva", + "This package is not available": "Tento balíček je nedostupný", + "Select the source you want to add:": "Vyber zdroj, ktorý chces pridať:", + "Source name:": "Názov zdroja:", + "Source URL:": "URL zdroje:", + "An error occurred when adding the source: ": "Došlo ku chybe pri pridávaní zdroja", + "Package management made easy": "Jednoduchá správa balíčkov", + "version {0}": "verzia {0}", + "[RAN AS ADMINISTRATOR]": "[SPUSTENÉ AKO SPRÁVCA]", + "Portable mode": "Portable režim\n", + "DEBUG BUILD": "LADIACA ZOSTAVA", + "Here you can change UniGetUI's behaviour regarding the following shortcuts. Checking a shortcut will make UniGetUI delete it if if gets created on a future upgrade. Unchecking it will keep the shortcut intact": "Tu môžete zmeniť chovanie rozhrania UniGetUI, pokiaľ ide o nasledovné skratky. Zaškrtnutie odkazu spôsobí, že ho UniGetUI odstráni, pokiaľ bude vytvorený pri budúcej aktualizácii. Zrušením zaškrtnutia zostane odkaz nedotknutý", + "Manual scan": "Manuálne skenovanie", + "Existing shortcuts on your desktop will be scanned, and you will need to pick which ones to keep and which ones to remove.": "Existujúce odkazy na ploche budú prehľadané a budete musieť vybrať, ktoré z nich chcete zachovať a ktoré odstrániť.", + "Delete?": "Vymazať?", + "I understand": "Rozumiem", + "Chocolatey setup changed": "Nastavenie Chocolatey sa zmenilo", + "UniGetUI no longer includes its own private Chocolatey installation. A legacy UniGetUI-managed Chocolatey installation was detected for this user profile, but system Chocolatey was not found. Chocolatey will stay unavailable in UniGetUI until Chocolatey is installed on the system and UniGetUI is restarted. Applications previously installed through UniGetUI's bundled Chocolatey may still appear under other sources such as Local PC or WinGet.": "UniGetUI už neobsahuje vlastnú privátnu inštaláciu Chocolatey. Pre tento používateľský profil bola zistená staršia inštalácia Chocolatey spravovaná UniGetUI, ale systémové Chocolatey nebolo nájdené. Chocolatey zostane v UniGetUI nedostupné, kým nebude Chocolatey nainštalované v systéme a UniGetUI nebude reštartované. Aplikácie predtým nainštalované prostredníctvom priloženého Chocolatey v UniGetUI sa môžu stále zobrazovať v iných zdrojoch, ako napríklad Lokálny počítač alebo WinGet.", + "NOTE: This troubleshooter can be disabled from UniGetUI Settings, on the WinGet section": "Poznámka: Toto riešenie problémov môže byť vypnuté v nastaveniach UniGetUI v sekcii WinGet", + "Restart": "Reštartovať", + "Are you sure you want to delete all shortcuts?": "Ste si istí, že chcete vymazať všetky odkazy?", + "Any new shorcuts created during an install or an update operation will be deleted automatically, instead of showing a confirmation prompt the first time they are detected.": "Všetky nové odkazy vytvorené počas inštalácie alebo aktualizácie budú odstránené automaticky, namiesto toho, aby sa pri ich prvej detekcii zobrazilo potvrdzovacie okno. ", + "Any shorcuts created or modified outside of UniGetUI will be ignored. You will be able to add them via the {0} button.": "Všetky odkazy vytvorené alebo upravené mimo UniGetUI budú ignorované. Budete ich môcť pridať pomocou tlačidla {0}.", + "Are you really sure you want to enable this feature?": "Ste si naozaj istí, že chcete povoliť túto funkciu?", + "No new shortcuts were found during the scan.": "Pri kontrole neboli nájdené žiadne nové odkazy.", + "How to add packages to a bundle": "Ako pridať balíčky do zväzku", + "In order to add packages to a bundle, you will need to: ": "Ak chcete pridať balíčky do zväzku, musíte:", + "1. Navigate to the \"{0}\" or \"{1}\" page.": "1. Prejdite na stránku \"{0}\" alebo \"{1}\".", + "2. Locate the package(s) you want to add to the bundle, and select their leftmost checkbox.": "2. Vyhľadajte balíčky, ktoré chcete pridať do zväzku, a zaškrtnite políčko vľavo od nich.", + "3. When the packages you want to add to the bundle are selected, find and click the option \"{0}\" on the toolbar.": "3. Keď sú balíčky, ktoré chcete pridať do zväzku vybrané, nájdite a kliknite na možnosť \"{0}\" na paneli nástrojov.", + "4. Your packages will have been added to the bundle. You can continue adding packages, or export the bundle.": "4. Vaše balíčky budú pridané do zväzku. Môžete pokračovať v pridávaní balíčkov, alebo zväzok exportovať.", + "Which backup do you want to open?": "Ktorú zálohu chcete otvoriť?", + "Select the backup you want to open. Later, you will be able to review which packages you want to install.": "Vyberte zálohu, ktorú chcete otvoriť. Neskôr budete môcť skontrolovať, ktoré balíčky/programy chcete obnoviť.", + "There are ongoing operations. Quitting UniGetUI may cause them to fail. Do you want to continue?": "Stále sa vykonávajú operácie. Ukočenie UniGetUI môže spôsobiť ich zlyhanie. Chcete aj napriek tomu pokračovať?", + "UniGetUI or some of its components are missing or corrupt.": "UniGetUI alebo niektorý z jeho komponentov chýbajú alebo sú poškodené.", + "It is strongly recommended to reinstall UniGetUI to adress the situation.": "Dôrazne sa odporúča preinštalovať UniGetUI pre vyriešenie tejto situácie.", + "Refer to the UniGetUI Logs to get more details regarding the affected file(s)": "Pozrite sa do protokolov UniGetUI pre získanie viacerých podrobností o postihnutých súboroch", + "Integrity checks can be disabled from the Experimental Settings": "Kontrolu intergrity je možné zakázať v Experimentálnom nastavení", + "Repair UniGetUI": "Opraviť UniGetUI", + "Live output": "Živý výstup", + "This package bundle had some settings that are potentially dangerous, and may be ignored by default.": "Tento zväzok balíčkov obsahoval niektoré potenciálne nebezpečné nastavenia, ktoré môžu byť v predvolenom nastavení ignorované.", + "Entries that show in YELLOW will be IGNORED.": "Záznamy, ktoré sa zobrazia ŽLTO, budú IGNOROVANÉ.", + "Entries that show in RED will be IMPORTED.": "Záznamy, ktoré sa zobrazia ČERVENO, budú IMPORTOVANÉ.", + "You can change this behavior on UniGetUI security settings.": "Toto chovanie môžete zmeniť v nastavení zabezpečení UniGetUI.", + "Open UniGetUI security settings": "Otvorte nastavenia zabezpečenia UniGetUI", + "Should you modify the security settings, you will need to open the bundle again for the changes to take effect.": "Pokiaľ zmeníte nastavenia zabezpečenia, budete musieť zväzok znovu otvoriť, aby sa zmeny prejavili.", + "Details of the report:": "Podrobnosti správy:", + "Are you sure you want to create a new package bundle? ": "Ste si istí, že chcete vytvoriť nový zväzok balíčkov?", + "Any unsaved changes will be lost": "Všetky neuložené zmeny budú stratené", + "Warning!": "Varovanie!", + "For security reasons, custom command-line arguments are disabled by default. Go to UniGetUI security settings to change this. ": "Z bezpečnostných dôvodov sú vlastné argumenty príkazového riadku v predvolenom nastavení zakázané. Ak to chcete zmeniť, prejdite do nastavenia zabezpečenia UniGetUI.", + "Change default options": "Zmeniť predvolené možnosti", + "Ignore future updates for this package": "Ignorovať budúce aktualizácie pre tento balíček", + "For security reasons, pre-operation and post-operation scripts are disabled by default. Go to UniGetUI security settings to change this. ": "Z bezpečnostných dôvodov sú predoperačné a pooperačné skripty v predvolenom nastavení zakázané. Ak to chcete zmeniť, prejdite do nastavenia zabezpečenia UniGetUI.", + "You can define the commands that will be run before or after this package is installed, updated or uninstalled. They will be run on a command prompt, so CMD scripts will work here.": "Môžete definovať príkazy, ktoré budú spustené pred alebo po inštalácii, aktualizácii alebo odinštalácii tohoto balíčku. Budú spustené v príkazovom riadku, takže tu budú fungovať skripty CMD.", + "Change this and unlock": "Zmeniť toto a odomknúť", + "{0} Install options are currently locked because {0} follows the default install options.": "{0} možnosti inštalácie sú v súčasnej dobe uzamknuté, pretože {0} sa riadi predvolenými možnosťami inštalácie.", + "Unset or unknown": "Nenastavené alebo neznáme", + "This package has no screenshots or is missing the icon? Contrbute to UniGetUI by adding the missing icons and screenshots to our open, public database.": "Chýbajú tomuto balíčku snímky obrazovky alebo ikonka? Prispejte do UniGetUI pridaním chýbajúcich ikoniek a snímkov obrazovky do našej otvorenej, verejnej databázy.", + "Become a contributor": "Staň sa prispievateľom", + "Update to {0} available": "Je dostupná aktualizácia na {0}", + "Reinstall": "Preinštalovať", + "Installer not available": "Inštalačný program nie je dostupný", + "Version:": "Verzia:", + "UniGetUI Version {0}": "UniGetUI verzie {0}", + "Performing backup, please wait...": "Vykonávam zálohu, prosím počkajte...", + "An error occurred while logging in: ": "Nastala chyba pri prihlasovaní:", + "Fetching available backups...": "Načítanie dostupných záloh...", + "Done!": "Hotovo!", + "The cloud backup has been loaded successfully.": "Cloudová záloha bola úspešne načítaná.", + "An error occurred while loading a backup: ": "Nastala chyba pri načítavaní zálohy: ", + "Backing up packages to GitHub Gist...": "Zálohovanie balíčkov na GitHub Gist...", + "Backup Successful": "Zálohovanie úspešné", + "The cloud backup completed successfully.": "Zálohovanie do cloudu bolo úspešne dokončené.", + "Could not back up packages to GitHub Gist: ": "Nepodarilo sa zálohovať balíčky na GitHub Gist:", + "It is not guaranteed that the provided credentials will be stored safely, so you may as well not use the credentials of your bank account": "Nie je zaručené, že poskytnuté prihlasovacie údaje budú bezpečne uložené, takže nepoužívajte prihlasovacie údaje k vašemu bankovému účtu.", + "Enable the automatic WinGet troubleshooter": "Zapnúť automatické riešenie problémov WinGet", + "Add updates that fail with a 'no applicable update found' to the ignored updates list": "Pridať aktualizácie, ktoré zlyhali s hlásením \"neboli nájdené žiadne použiteľné aktualizácie\" do zoznamu ignorovaných aktualizácií.", + "Invalid selection": "Neplatný výber", + "No package was selected": "Nebol vybraný žiadny balíček", + "More than 1 package was selected": "Bol vybraný viac ako 1 balíček", + "List": "Zoznam", + "Grid": "Mriežka", + "Icons": "Ikony", + "\"{0}\" is a local package and does not have available details": "\"{0}\" je lokálny balíček a nemá k dispozícii podrobnosti", + "\"{0}\" is a local package and is not compatible with this feature": "\"{0}\" je lokálny balíček a nie je kompatibilný s touto funkciou", + "Add packages to bundle": "Pridať balíčky do zväzku", + "Preparing packages, please wait...": "Príprava balíčkov, prosím počkajte...", + "Loading packages, please wait...": "Načítavanie balíčkov, prosím čakajte...", + "Saving packages, please wait...": "Ukladanie balíčkov, prosím počkajte...", + "The bundle was created successfully on {0}": "Zväzok bol úspešne vytvorený do {0}", + "User profile": "Používateľský profil", + "Error": "Chyba", + "Log in failed: ": "Prihlásenie sa nepodarilo:", + "Log out failed: ": "Odhlásenie sa nepodarilo:", + "Package backup settings": "Nastavenie zálohovania baličkov", + "Package managers": "Manažéri balíčkov", + "Manage UniGetUI autostart behaviour from the Settings app": "Spravovať správanie automatického spúšťania UniGetUI", + "Choose how many operations shoulds be performed in parallel": "Vyberte, koľko operácií sa má vykonávať súbežne", + "Something went wrong while launching the updater.": "Pri spustení aktualizácie sa niečo pokazilo.", + "Please try again later": "Skúste to prosím neskôr", + "Show the release notes after UniGetUI is updated": "Zobraziť poznámky k vydaniu po aktualizácii UniGetUI" +} diff --git a/src/Languages/lang_sl.json b/src/Languages/lang_sl.json new file mode 100644 index 0000000..f992230 --- /dev/null +++ b/src/Languages/lang_sl.json @@ -0,0 +1,851 @@ +{ + "{0} of {1} operations completed": "Dokončenih {0} od {1} opravil", + "{0} is now {1}": "{0} je zdaj {1}", + "Enabled": "Omogočeno", + "Disabled": "Onemogočeno", + "Privacy": "Zasebnost", + "Hide my username from the logs": "Skrij moje uporabniško ime iz dnevnikov", + "Replaces your username with **** in the logs. Restart UniGetUI to also hide it from already-recorded entries.": "V dnevnikih nadomesti vaše uporabniško ime z ****. Znova zaženite UniGetUI, da ga skrijete tudi v že zabeleženih vnosih.", + "Your last update attempt did not complete.": "Vaš zadnji poskus posodobitve ni bil dokončan.", + "UniGetUI could not confirm whether the update succeeded. Open the log to see what happened.": "UniGetUI ni mogel potrditi, ali je posodobitev uspela. Odprite dnevnik, da vidite, kaj se je zgodilo.", + "View log": "Ogled dnevnika", + "The installer reported success but did not restart UniGetUI.": "Namestitveni program je sporočil uspeh, vendar ni znova zagnal UniGetUI.", + "The installer failed to initialize.": "Namestitvenega programa ni bilo mogoče inicializirati.", + "Setup was canceled before installation began.": "Namestitev je bila preklicana, preden se je začela.", + "A fatal error occurred during the preparation phase.": "Med fazo priprave je prišlo do usodne napake.", + "A fatal error occurred during installation.": "Med namestitvijo je prišlo do usodne napake.", + "Installation was canceled while in progress.": "Namestitev je bila preklicana med izvajanjem.", + "The installer was terminated by another process.": "Namestitveni program je prekinil drug proces.", + "The preparation phase determined the installation cannot proceed.": "Faza priprave je ugotovila, da se namestitev ne more nadaljevati.", + "The installer could not start. UniGetUI may already be running, or you do not have permission to install.": "Namestitvenega programa ni bilo mogoče zagnati. UniGetUI se morda že izvaja ali pa nimate dovoljenja za namestitev.", + "Unexpected installer error.": "Nepričakovana napaka namestitvenega programa.", + "We are checking for updates.": "Preverjamo posodobitve.", + "Please wait": "Prosim počakajte", + "Great! You are on the latest version.": "Odlično! Ste na najnovejši različici.", + "There are no new UniGetUI versions to be installed": "Ni novih različic UniGetUI za namestitev", + "UniGetUI version {0} is being downloaded.": "Prenos različice UniGetUI {0} poteka.", + "This may take a minute or two": "To lahko traja minuto ali dve", + "The installer authenticity could not be verified.": "Pristnosti namestitvenega programa ni bilo mogoče preveriti.", + "The update process has been aborted.": "Postopek posodobitve je bil prekinjen.", + "Auto-update is not yet available on this platform.": "Samodejna posodobitev na tej platformi še ni na voljo.", + "Please update UniGetUI manually.": "Posodobite UniGetUI ročno.", + "An error occurred when checking for updates: ": "Pri preverjanju posodobitev je prišlo do napake:", + "The updater could not be launched.": "Posodobitvenega programa ni bilo mogoče zagnati.", + "The operating system did not start the installer process.": "Operacijski sistem ni zagnal procesa namestitvenega programa.", + "UniGetUI is being updated...": "UniGetUI se posodablja ...", + "Update installed.": "Posodobitev je nameščena.", + "UniGetUI was updated successfully, but this running copy was not replaced. This usually means you are running a development build. Close this copy and start the newly-installed version to finish.": "UniGetUI je bil uspešno posodobljen, vendar ta zagnani izvod ni bil zamenjan. To običajno pomeni, da uporabljate razvojno gradnjo. Zaprite ta izvod in zaženite novo nameščeno različico za dokončanje.", + "The update could not be applied.": "Posodobitve ni bilo mogoče uporabiti.", + "Installer exit code {0}: {1}": "Izhodna koda namestitvenega programa {0}: {1}", + "Update cancelled.": "Posodobitev je bila preklicana.", + "Authentication was cancelled.": "Overjanje je bilo preklicano.", + "Installer exit code {0}": "Izhodna koda namestitvenega programa {0}", + "Operation in progress": "Operacija v teku", + "Please wait...": "Prosim počakajte...", + "Success!": "Uspeh!", + "Failed": "Ni uspelo", + "An error occurred while processing this package": "Med obdelavo tega paketa je prišlo do napake", + "Installer": "Namestitveni program", + "Executable": "Izvršljiva datoteka", + "MSI": "MSI", + "Compressed file": "Stisnjena datoteka", + "MSIX": "MSIX", + "WinGet was repaired successfully": "WinGet je bil uspešno popravljen", + "It is recommended to restart UniGetUI after WinGet has been repaired": "Priporočljivo je, da znova zaženete UniGetUI, ko je WinGet popravljen", + "WinGet could not be repaired": "WinGet ni bilo mogoče popraviti", + "An unexpected issue occurred while attempting to repair WinGet. Please try again later": "Med poskusom popravila programa WinGet je prišlo do nepričakovane težave. Poskusite znova pozneje", + "Log in to enable cloud backup": "Prijavite se, da omogočite varnostno kopiranje v oblaku", + "Backup Failed": "Varnostno kopiranje ni uspelo", + "Downloading backup...": "Prenašanje varnostne kopije...", + "An update was found!": "Najdena je bila posodobitev!", + "{0} can be updated to version {1}": "{0} je mogoče posodobiti na različico {1}", + "Updates found!": "Najdene posodobitve!", + "{0} packages can be updated": "{0} paketov lahko posodobite", + "{0} is being updated to version {1}": "{0} se posodablja na različico {1}", + "{0} packages are being updated": "posodabljam {0} paketov", + "You have currently version {0} installed": "Trenutno imate nameščeno različico {0}", + "Desktop shortcut created": "Bližnjica na namizju je ustvarjena", + "UniGetUI has detected a new desktop shortcut that can be deleted automatically.": "UniGetUI je zaznal novo bližnjico na namizju, ki jo je mogoče samodejno izbrisati.", + "{0} desktop shortcuts created": "{0} ustvarjenih bližnjic na namizju", + "UniGetUI has detected {0} new desktop shortcuts that can be deleted automatically.": "UniGetUI je zaznal {0} novih bližnjic na namizju, ki jih je mogoče samodejno izbrisati.", + "Attention required": "Potrebna pozornost", + "Restart required": "Potreben ponovni zagon", + "1 update is available": "Na voljo je 1 posodobitev", + "{0} updates are available": "{0} posodobitev je na voljo", + "Everything is up to date": "Vse je posodobljeno", + "Discover Packages": "Odkrijte pakete", + "Available Updates": "Razpoložljive posodobitve", + "Installed Packages": "Nameščeni paketi", + "UniGetUI Version {0} by Devolutions": "UniGetUI različica {0} podjetja Devolutions", + "Show UniGetUI": "Prikaži UniGetUI", + "Quit": "Izhod", + "Are you sure?": "Ali ste prepričani?", + "Do you really want to uninstall {0}?": "Ali zares želite odstraniti {0}?", + "Do you really want to uninstall the following {0} packages?": "Ali res želite odstraniti naslednje pakete {0}?", + "No": "Ne", + "Yes": "Da", + "Partial": "Delno", + "View on UniGetUI": "Ogled v UniGetUI", + "Update": "Posodobi", + "Open UniGetUI": "Odprite UniGetUI", + "Update all": "Posodobi vse", + "Update now": "Posodobi zdaj", + "Installer host changed since the installed version.\n": "Gostitelj namestitvenega programa se je od nameščene različice spremenil.\n", + "This package is on the queue": "Ta paket je v čakalni vrsti", + "installing": "nameščam", + "updating": "posodabljanje", + "uninstalling": "odstranjujem", + "installed": "nameščeno", + "Retry": "Poskusite znova", + "Install": "Namesti", + "Uninstall": "Odstrani", + "Open": "Odpri", + "Operation profile:": "Profil operacije:", + "Follow the default options when installing, upgrading or uninstalling this package": "Pri nameščanju, nadgrajevanju ali odstranjevanju tega paketa upoštevaj privzete možnosti", + "The following settings will be applied each time this package is installed, updated or removed.": "Naslednje nastavitve bodo uporabljene vsakič, ko bo ta paket nameščen, posodobljen ali odstranjen.", + "Version to install:": "Verzija za namestitev:", + "Architecture to install:": "Arhitektura za namestitev:", + "Installation scope:": "Obseg namestitve:", + "Install location:": "Lokacija namestitve:", + "Select": "Izberi", + "Reset": "Ponastavi", + "Custom install arguments:": "Argumenti namestitve po meri:", + "Custom update arguments:": "Argumenti posodobitve po meri:", + "Custom uninstall arguments:": "Argumenti odstranitve po meri:", + "Pre-install command:": "Ukaz pred namestitvijo:", + "Post-install command:": "Ukaz po namestitvi:", + "Abort install if pre-install command fails": "Prekini namestitev, če ukaz za prednamestitev ne uspe", + "Pre-update command:": "Ukaz pred posodobitvijo:", + "Post-update command:": "Ukaz po posodobitvi:", + "Abort update if pre-update command fails": "Prekini posodobitev, če ukaz pred posodobitvijo ne uspe", + "Pre-uninstall command:": "Ukaz pred odstranitvijo:", + "Post-uninstall command:": "Ukaz po odstranitvi:", + "Abort uninstall if pre-uninstall command fails": "Prekini odstranitev, če ukaz pred odstranitvo ne uspe", + "Command-line to run:": "Ukazna vrstica za izvedbo:", + "Save and close": "Shrani in zapri", + "General": "Splošno", + "Architecture & Location": "Arhitektura in lokacija", + "Command-line": "Ukazna vrstica", + "Close apps": "Zapri aplikacije", + "Pre/Post install": "Pred/po namestitvi", + "Select the processes that should be closed before this package is installed, updated or uninstalled.": "Izberite procese, ki jih je treba zapreti, preden se ta paket namesti, posodobi ali odstrani.", + "Write here the process names here, separated by commas (,)": "Tukaj vnesite imena procesov, ločena z vejicami (,)", + "Try to kill the processes that refuse to close when requested to": "Poskusi končati procese, ki se ob zahtevi nočejo zapreti", + "Run as admin": "Zaženi kot skrbnik", + "Interactive installation": "Interaktivna namestitev", + "Skip hash check": "Preskoči preverjanje zgoščevanja", + "Uninstall previous versions when updated": "Ob posodobitvi odstrani prejšnje različice", + "Skip minor updates for this package": "Preskoči manjše posodobitve za ta paket", + "Automatically update this package": "Ta paket posodobi samodejno", + "{0} installation options": "Možnosti namestitve {0}", + "Latest": "Zadnje", + "PreRelease": "Predizdaja", + "Default": "Privzeto", + "Manage ignored updates": "Upravljanje prezrtih posodobitev", + "The packages listed here won't be taken in account when checking for updates. Double-click them or click the button on their right to stop ignoring their updates.": "Tukaj navedeni paketi ne bodo upoštevani pri preverjanju posodobitev. Dvokliknite jih ali kliknite gumb na njihovi desni, če želite prenehati ignorirati njihove posodobitve.", + "Reset list": "Ponastavi seznam", + "Do you really want to reset the ignored updates list? This action cannot be reverted": "Ali res želite ponastaviti seznam prezrtih posodobitev? Tega dejanja ni mogoče razveljaviti.", + "No ignored updates": "Ni prezrtih posodobitev", + "Package Name": "Naziv paketa", + "Package ID": "ID paketa", + "Ignored version": "Prezrte različice", + "New version": "Nova različica", + "Source": "Vir", + "All versions": "Vse različice", + "Unknown": "Neznano", + "Up to date": "Ažurno", + "Package {name} from {manager}": "Paket {name} iz {manager}", + "Remove {0} from ignored updates": "Odstrani {0} iz prezrtih posodobitev", + "Cancel": "Prekliči", + "Administrator privileges": "Skrbniške pravice", + "This operation is running with administrator privileges.": "Ta operacija se izvaja s skrbniškimi pravicami.", + "Interactive operation": "Interaktivna operacija", + "This operation is running interactively.": "Ta operacija se izvaja interaktivno.", + "You will likely need to interact with the installer.": "Verjetno boste morali sodelovati z namestitvenim programom.", + "Integrity checks skipped": "Preverjanje integritete preskočeno", + "Integrity checks will not be performed during this operation.": "Med to operacijo preverjanje integritete ne bo izvedeno.", + "Proceed at your own risk.": "Nadaljujte na lastno odgovornost.", + "Close": "Zapri", + "Loading...": "Nalagam...", + "Installer SHA256": "Namestitveni program SHA256", + "Homepage": "Domača stran", + "Author": "Avtor", + "Publisher": "Založnik", + "License": "Licenca", + "Manifest": "Datoteka manifesta", + "Installer Type": "Namestitveni program tip", + "Size": "Velikost", + "Installer URL": "Namestitveni program URL", + "Last updated:": "Zadnja posodobitev:", + "Release notes URL": "URL opomb ob izdaji", + "Package details": "Podrobnosti paketa", + "Dependencies:": "Odvisnosti:", + "Release notes": "Opombe ob izdaji", + "Screenshots": "Posnetki zaslona", + "This package has no screenshots or is missing the icon? Contribute to UniGetUI by adding the missing icons and screenshots to our open, public database.": "Ta paket nima posnetkov zaslona ali mu manjka ikona? Prispevajte k UniGetUI tako, da dodate manjkajoče ikone in posnetke zaslona v našo odprto javno bazo podatkov.", + "Version": "Različica", + "Install as administrator": "Namesti kot skrbnik", + "Update to version {0}": "Posodobite na različico {0}", + "Installed Version": "Nameščena različica", + "Update as administrator": "Posodobi kot skrbnik", + "Interactive update": "Interaktivna posodobitev", + "Uninstall as administrator": "Odstrani kot skrbnik", + "Interactive uninstall": "Interaktivna odstranitev", + "Uninstall and remove data": "Odmestite in odstranite podatke", + "Not available": "Ni na voljo", + "Installer SHA512": "SHA512 namestitvenega programa", + "Unknown size": "Neznana velikost", + "No dependencies specified": "Ni določenih odvisnosti", + "mandatory": "obvezno", + "optional": "neobvezno", + "UniGetUI {0} is ready to be installed.": "UniGetUI {0} je pripravljen za namestitev.", + "The update process will start after closing UniGetUI": "Postopek posodabljanja se bo začel po zaprtju UniGetUI", + "UniGetUI has been ran as administrator, which is not recommended. When running UniGetUI as administrator, EVERY operation launched from UniGetUI will have administrator privileges. You can still use the program, but we highly recommend not running UniGetUI with administrator privileges.": "UniGetUI je bil zagnan kot skrbnik, kar ni priporočljivo. Ko UniGetUI zaženete kot skrbnik, bo VSAKA operacija, zagnana iz UniGetUI, imela skrbniške pravice. Program lahko še vedno uporabljate, vendar močno priporočamo, da UniGetUI ne zaganjate s skrbniškimi pravicami.", + "Share anonymous usage data": "Deli anonimne podatke o uporabi", + "UniGetUI collects anonymous usage data in order to improve the user experience.": "UniGetUI zbira anonimne podatke o uporabi z namenom izboljšanja uporabniške izkušnje.", + "Accept": "Potrdi", + "Software Updates": "Posodobitve paketov", + "Package Bundles": "Sveženj paketov", + "Settings": "Nastavitve", + "Package Managers": "Upravljalniki paketov", + "UniGetUI Log": "Dnevnik UniGetUI", + "Package Manager logs": "Dnevniki upravitelja paketov", + "Operation history": "Zgodovina delovanja", + "Help": "Pomoč", + "UniGetUI": "UniGetUI", + "You have installed UniGetUI Version {0}": "Namestili ste različico UniGetUI {0}", + "Disclaimer": "Izjava o omejitvi odgovornosti", + "UniGetUI is developed by Devolutions and is not affiliated with any of the compatible package managers.": "UniGetUI razvija podjetje Devolutions in ni povezan z nobenim od združljivih upravljalnikov paketov.", + "UniGetUI wouldn't have been possible without the help of the contributors. Thank you all 🥳": "UniGetUI ne bi bil mogoč brez pomoči sodelavcev. Hvala vsem 🥳", + "UniGetUI uses the following libraries. Without them, UniGetUI wouldn't have been possible.": "UniGetUI uporablja naslednje knjižnice. Brez njih UniGetUI ne bi bil mogoč.", + "{0} homepage": "{0} domača stran", + "UniGetUI has been translated to more than 40 languages thanks to the volunteer translators. Thank you 🤝": "UniGetUI je bil zahvaljujoč prostovoljnim prevajalcem preveden v več kot 40 jezikov. Hvala 🤝", + "Verbose": "Podrobno", + "1 - Errors": "1 - Napake", + "2 - Warnings": "2 - Opozorila", + "3 - Information (less)": "3 - Informacije (manj)", + "4 - Information (more)": "4 - Informacije (več)", + "5 - information (debug)": "5 - Informacije (razhroščevanje)", + "Warning": "Opozorilo", + "The following settings may pose a security risk, hence they are disabled by default.": "Naslednje nastavitve lahko predstavljajo varnostno tveganje, zato so privzeto onemogočene.", + "Enable the settings below if and only if you fully understand what they do, and the implications they may have.": "Spodnje nastavitve omogočite le, če popolnoma razumete, kaj počnejo, ter kakšne posledice imajo lahko.", + "The settings will list, in their descriptions, the potential security issues they may have.": "Nastavitve bodo v svojih opisih navajale morebitna varnostna tveganja, ki jih lahko prinašajo.", + "The backup will include the complete list of the installed packages and their installation options. Ignored updates and skipped versions will also be saved.": "Varnostna kopija bo vsebovala celoten seznam nameščenih paketov in možnosti njihove namestitve. Shranjene bodo tudi prezrte posodobitve in preskočene različice.", + "The backup will NOT include any binary file nor any program's saved data.": "Varnostna kopija NE bo vključevala nobene binarne datoteke ali shranjenih podatkov katerega koli programa.", + "The size of the backup is estimated to be less than 1MB.": "Velikost varnostne kopije je ocenjena na manj kot 1 MB.", + "The backup will be performed after login.": "Varnostno kopiranje bo izvedeno po prijavi.", + "{pcName} installed packages": "{pcName} nameščenih paketov", + "Current status: Not logged in": "Trenutno stanje: Niste prijavljeni", + "You are logged in as {0} (@{1})": "Prijavljeni ste kot {0} (@{1})", + "Nice! Backups will be uploaded to a private gist on your account": "Odlično! Varnostne kopije bodo naložene v zasebni gist v vašem računu", + "Select backup": "Izberite varnostno kopijo", + "Settings imported from {0}": "Nastavitve uvožene iz {0}", + "UniGetUI Settings": "Nastavitve UniGetUI", + "Settings exported to {0}": "Nastavitve izvožene v {0}", + "UniGetUI settings were reset": "Nastavitve UniGetUI so bile ponastavljene", + "Allow pre-release versions": "Dovoli predizdajne različice", + "Apply": "Uporabi", + "For security reasons, custom command-line arguments are disabled by default. Go to UniGetUI security settings to change this.": "Iz varnostnih razlogov so argumenti ukazne vrstice po meri privzeto onemogočeni. Če želite to spremeniti, odprite varnostne nastavitve UniGetUI.", + "Go to UniGetUI security settings": "Pojdi v varnostne nastavitve UniGetUI", + "The following options will be applied by default each time a {0} package is installed, upgraded or uninstalled.": "Naslednje možnosti bodo privzeto uporabljene vsakič, ko bo paket {0} nameščen, nadgrajen ali odstranjen.", + "Package's default": "Privzeto za paket", + "Install location can't be changed for {0} packages": "Mesta namestitve za pakete {0} ni mogoče spremeniti", + "The local icon cache currently takes {0} MB": "Lokalni predpomnilnik ikon trenutno zaseda {0} MB", + "Username": "Uporabniško ime", + "Password": "Geslo", + "Credentials": "Poverilnice", + "It is not guaranteed that the provided credentials will be stored safely": "Ni zagotovljeno, da bodo podane poverilnice shranjene varno", + "Partially": "Delno", + "Package manager": "Upravljalnik paketov", + "Compatible with proxy": "Združljivo s posredniškim strežnikom", + "Compatible with authentication": "Združljivo z overjanjem", + "Proxy compatibility table": "Tabela združljivosti posredniškega strežnika", + "{0} settings": "Nastavitve za {0}", + "{0} status": "Stanje {0}", + "Default installation options for {0} packages": "Privzete možnosti namestitve za pakete {0}", + "Expand version": "Razširite različico", + "The executable file for {0} was not found": "Izvršljiva datoteka za {0} ni bila najdena", + "{pm} is disabled": "{pm} je onemogočen", + "Enable it to install packages from {pm}.": "Omogočite ga za namestitev paketov iz {pm}.", + "{pm} is enabled and ready to go": "{pm} je omogočen in pripravljen za uporabo", + "{pm} version:": "{pm} različica:", + "{pm} was not found!": "{pm} ni bilo mogoče najti!", + "You may need to install {pm} in order to use it with UniGetUI.": "Morda boste morali namestiti {pm}, če ga želite uporabljati z UniGetUI.", + "Scoop Installer - UniGetUI": "Namestitveni program Scoop - UniGetUI", + "Scoop Uninstaller - UniGetUI": "Odstranjevalnik Scoop - UniGetUI", + "Clearing Scoop cache - UniGetUI": "Čiščenje predpomnilnika Scoop - UniGetUI", + "Restart UniGetUI to fully apply changes": "Za popolno uveljavitev sprememb znova zaženite UniGetUI", + "Restart UniGetUI": "Ponovni zagon UniGetUI", + "Manage {0} sources": "Upravljaj {0} virov", + "Add source": "Dodaj vir", + "Add": "Dodaj", + "Source name": "Ime vira", + "Source URL": "URL vira", + "Other": "Ostalo", + "No minimum age": "Brez minimalne starosti", + "1 day": "1 dan", + "{0} days": "{0} dni", + "Custom...": "Po meri...", + "{0} minutes": "{0} minut", + "1 hour": "1 uro", + "{0} hours": "{0} ur", + "1 week": "1 teden", + "Supports release dates": "Podpira datume izdaje", + "Release date support per package manager": "Podpora datumom izdaje po upravitelju paketov", + "Search for packages": "Išči za pakete", + "Local": "Lokalno", + "OK": "V redu", + "Last checked: {0}": "Nazadnje preverjeno: {0}", + "{0} packages were found, {1} of which match the specified filters.": "Najdenih je bilo {0} paketov, od katerih se {1} ujema z navedenimi filtri.", + "{0} selected": "{0} izbranih", + "(Last checked: {0})": "(Nazadnje preverjeno: {0})", + "All packages selected": "Vsi paketi so izbrani", + "Package selection cleared": "Izbira paketov je ponastavljena", + "{0}: {1}": "{0}: {1}", + "More info": "Več informacij", + "GitHub account": "Račun GitHub", + "Log in with GitHub to enable cloud package backup.": "Za omogočanje varnostnega kopiranja paketov v oblaku se prijavite z GitHub.", + "More details": "Več podrobnosti", + "Log in": "Prijava", + "If you have cloud backup enabled, it will be saved as a GitHub Gist on this account": "Če imate omogočeno varnostno kopiranje v oblaku, bo shranjeno kot GitHub Gist v tem računu", + "Log out": "Odjava", + "About UniGetUI": "O UniGetUI", + "About": "O nas", + "Third-party licenses": "Licence tretjih oseb", + "Contributors": "Sodelujoči", + "Translators": "Prevajalci", + "Bundle security report": "Varnostno poročilo svežnja", + "The bundle contained restricted content": "Sveženj je vseboval omejeno vsebino", + "UniGetUI – Crash Report": "UniGetUI – Poročilo o sesutju", + "UniGetUI has crashed": "UniGetUI se je sesul", + "Help us fix this by sending a crash report to Devolutions. All fields below are optional.": "Pomagajte nam odpraviti napako s pošiljanjem poročila o sesutju podjetju Devolutions. Vsa spodnja polja so neobvezna.", + "Email (optional)": "E-pošta (neobvezno)", + "your@email.com": "vaš@email.com", + "Additional details (optional)": "Dodatne podrobnosti (neobvezno)", + "Describe what you were doing when the crash occurred…": "Opišite, kaj ste počeli, ko je prišlo do sesutja…", + "Crash report": "Poročilo o sesutju", + "Don't Send": "Ne pošlji", + "Send Report": "Pošlji poročilo", + "Sending…": "Pošiljanje…", + "Unsaved changes": "Neshranjene spremembe", + "You have unsaved changes in the current bundle. Do you want to discard them?": "V trenutnem svežnju imate neshranjene spremembe. Ali jih želite zavreči?", + "Discard changes": "Zavrzi spremembe", + "Integrity violation": "Kršitev integritete", + "UniGetUI or some of its components are missing or corrupt. It is strongly recommended to reinstall UniGetUI to adress the situation.": "UniGetUI ali nekatere njegove komponente manjkajo ali so poškodovane. Močno priporočamo, da za odpravo težave znova namestite UniGetUI.", + "• Refer to the UniGetUI Logs to get more details regarding the affected file(s)": "• Za več podrobnosti o prizadetih datotekah si oglejte dnevnike UniGetUI", + "• Integrity checks can be disabled from the Experimental Settings": "• Preverjanje integritete je mogoče onemogočiti v eksperimentalnih nastavitvah", + "Manage shortcuts": "Upravljanje bližnjic", + "UniGetUI has detected the following desktop shortcuts which can be removed automatically on future upgrades": "UniGetUI je zaznal naslednje bližnjice, ki jih je mogoče samodejno odstraniti ob prihodnjih nadgradnjah", + "Do you really want to reset this list? This action cannot be reverted.": "Ali res želite ponastaviti ta seznam? Tega dejanja ni mogoče razveljaviti.", + "Desktop shortcuts list": "Seznam bližnjic na namizju", + "Open in explorer": "Odpri v Raziskovalcu", + "Remove from list": "Odstrani iz seznama", + "When new shortcuts are detected, delete them automatically instead of showing this dialog.": "Ko so zaznane nove bližnjice, jih samodejno izbriši brez prikaza tega pogovornega okna.", + "Not right now": "Ne zdaj", + "Missing dependency": "Manjka programska odvisnost", + "UniGetUI requires {0} to operate, but it was not found on your system.": "UniGetUI potrebuje {0} za delovanje, vendar ni bil najden v vašem sistemu.", + "Click on Install to begin the installation process. If you skip the installation, UniGetUI may not work as expected.": "Kliknite Namesti, da začnete postopek namestitve. Če preskočite namestitev, UniGetUI morda ne bo deloval po pričakovanjih.", + "Alternatively, you can also install {0} by running the following command in a Windows PowerShell prompt:": "Lahko pa tudi namestite {0} tako, da zaženete naslednji ukaz v pozivu Windows PowerShell:", + "Install {0}": "Namesti {0}", + "Do not show this dialog again for {0}": "Ne prikaži več tega pogovornega okna za {0}", + "Please wait while {0} is being installed. A black window may show up. Please wait until it closes.": "Počakajte, da se {0} namesti. Lahko se prikaže črno okno. Počakajte, da se zapre.", + "{0} has been installed successfully.": "{0} je bil uspešno nameščen.", + "Please click on \"Continue\" to continue": "Kliknite »Nadaljuj« za nadaljevanje", + "Continue": "Nadaljuj", + "{0} has been installed successfully. It is recommended to restart UniGetUI to finish the installation": "{0} je bil uspešno nameščen. Priporočljivo je, da znova zaženete UniGetUI, da dokončate namestitev", + "Restart later": "Ponovno zaženi kasneje", + "An error occurred:": "Pripetila se je napaka:", + "Please see the Command-line Output or refer to the Operation History for further information about the issue.": "Za nadaljnje informacije o težavi si oglejte Izpis ukazne vrstice ali glejte Zgodovino delovanja.", + "Retry as administrator": "Poskusite znova kot skrbnik", + "Retry interactively": "Poskusite znova interaktivno", + "Retry skipping integrity checks": "Ponovno poskusi brez preverjanja integritete", + "Installation options": "Možnosti namestitve", + "Save": "Shrani", + "UniGetUI collects anonymous usage data with the sole purpose of understanding and improving the user experience.": "UniGetUI zbira anonimne podatke izključno za razumevanje in izboljšanje uporabniške izkušnje.", + "More details about the shared data and how it will be processed": "Več podrobnosti o deljenih podatkih in njihovi obdelavi", + "Do you accept that UniGetUI collects and sends anonymous usage statistics, with the sole purpose of understanding and improving the user experience?": "Ali soglašate, da UniGetUI zbira in pošilja anonimne statistike uporabe izključno z namenom izboljšanja uporabniške izkušnje?", + "Decline": "Zavrni", + "No personal information is collected nor sent, and the collected data is anonimized, so it can't be back-tracked to you.": "Osebni podatki se ne zbirajo niti pošiljajo, zbrani podatki so anonimizirani in jih ni mogoče povezati z vami.", + "Navigation panel": "Navigacijska plošča", + "Operations": "Operacije", + "Toggle operations panel": "Preklopi ploščo operacij", + "Bulk operations": "Množične operacije", + "Retry failed": "Ponovi neuspele", + "Clear successful": "Počisti uspešne", + "Clear finished": "Počisti dokončane", + "Cancel all": "Prekliči vse", + "More": "Več", + "Toggle navigation panel": "Preklopi navigacijsko ploščo", + "Minimize": "Minimiziraj", + "Maximize": "Maksimiziraj", + "UniGetUI by Devolutions": "UniGetUI podjetja Devolutions", + "UniGetUI is an application that makes managing your software easier, by providing an all-in-one graphical interface for your command-line package managers.": "UniGetUI je aplikacija, ki poenostavi upravljanje vaše programske opreme z zagotavljanjem grafičnega vmesnika vse v enem za vaše upravitelje paketov v ukazni vrstici.", + "Useful links": "Uporabne povezave", + "UniGetUI Homepage": "Domača stran UniGetUI", + "Report an issue or submit a feature request": "Prijavite težavo ali oddajte zahtevo po novi funkciji", + "UniGetUI Repository": "Repozitorij UniGetUI", + "View GitHub Profile": "Ogled profila GitHub", + "UniGetUI License": "Licenca UniGetUI", + "Using UniGetUI implies the acceptation of the MIT License": "Z uporabo UniGetUI se strinjate z MIT licenco", + "Become a translator": "Postanite prevajalec", + "Go back": "Pojdi nazaj", + "Go forward": "Pojdi naprej", + "Go to home page": "Pojdi na domačo stran", + "Reload page": "Osveži stran", + "View page on browser": "Oglej si stran v brskalniku", + "The built-in browser is not supported on Linux yet.": "Vgrajeni brskalnik v Linuxu še ni podprt.", + "Open in browser": "Odpri v brskalniku", + "Copy to clipboard": "Kopiraj v odložišče", + "Export to a file": "Izvozi v datoteko", + "Log level:": "Nivo logiranja:", + "Reload log": "Osveži dnevnik", + "Export log": "Izvozi dnevnik", + "Text": "Besedilo", + "Change how operations request administrator rights": "Spremenite način zahtevanja skrbniških pravic za operacije", + "Restrictions on package operations": "Omejitve paketnih operacij", + "Restrictions on package managers": "Omejitve upraviteljev paketov", + "Restrictions when importing package bundles": "Omejitve pri uvažanju svežnjev paketov", + "Ask for administrator privileges once for each batch of operations": "Enkrat zahtevajte skrbniške pravice za vsak sklop operacij", + "Ask only once for administrator privileges": "Za skrbniške pravice vprašaj samo enkrat", + "Prohibit any kind of Elevation via UniGetUI Elevator or GSudo": "Prepovej kakršnokoli povišanje pravic prek UniGetUI Elevator ali GSudo", + "This option WILL cause issues. Any operation incapable of elevating itself WILL FAIL. Install/update/uninstall as administrator will NOT WORK.": "Ta možnost BO povzročila težave. Vsaka operacija, ki se ne more sama povišati, BO SPODLETELA. Namestitev, posodobitev ali odstranitev kot skrbnik NE BO delovala.", + "Allow custom command-line arguments": "Dovoli argumente ukazne vrstice po meri", + "Custom command-line arguments can change the way in which programs are installed, upgraded or uninstalled, in a way UniGetUI cannot control. Using custom command-lines can break packages. Proceed with caution.": "Argumenti ukazne vrstice po meri lahko spremenijo način nameščanja, nadgrajevanja ali odstranjevanja programov na način, ki ga UniGetUI ne more nadzorovati. Uporaba ukaznih vrstic po meri lahko pokvari pakete. Nadaljujte previdno.", + "Ignore custom pre-install and post-install commands when importing packages from a bundle": "Dovoli izvajanje ukazov po meri pred namestitvijo in po njej", + "Pre and post install commands will be run before and after a package gets installed, upgraded or uninstalled. Be aware that they may break things unless used carefully": "Ukazi pred namestitvijo in po njej se bodo zagnali pred in po namestitvi, nadgradnji ali odstranitvi paketa. Upoštevajte, da lahko povzročijo težave, če jih ne uporabljate previdno", + "Allow changing the paths for package manager executables": "Dovoli spreminjanje poti za izvedljive datoteke upravitelja paketov", + "Turning this on enables changing the executable file used to interact with package managers. While this allows finer-grained customization of your install processes, it may also be dangerous": "Vklop te možnosti omogoča spreminjanje izvršljive datoteke, ki se uporablja za delo z upravitelji paketov. Čeprav to omogoča natančnejše prilagajanje postopkov namestitve, je lahko tudi nevarno", + "Allow importing custom command-line arguments when importing packages from a bundle": "Dovoli uvoz argumentov ukazne vrstice po meri pri uvozu paketov iz svežnja", + "Malformed command-line arguments can break packages, or even allow a malicious actor to gain privileged execution. Therefore, importing custom command-line arguments is disabled by default": "Napačno oblikovani argumenti ukazne vrstice lahko pokvarijo pakete ali celo omogočijo zlonamernemu akterju pridobitev povišanih pravic. Zato je uvoz argumentov ukazne vrstice po meri privzeto onemogočen.", + "Allow importing custom pre-install and post-install commands when importing packages from a bundle": "Dovoli uvoz ukazov po meri pred namestitvijo in po njej pri uvozu paketov iz svežnja", + "Pre and post install commands can do very nasty things to your device, if designed to do so. It can be very dangerous to import the commands from a bundle, unless you trust the source of that package bundle": "Ukazi pred namestitvijo in po njej lahko vaši napravi storijo zelo škodljive stvari, če so za to zasnovani. Uvoz teh ukazov iz svežnja je lahko zelo nevaren, razen če zaupate viru tega svežnja paketov", + "Administrator rights and other dangerous settings": "Skrbniške pravice in druge nevarne nastavitve", + "Package backup": "Varnostna kopija paketa", + "Cloud package backup": "Varnostno kopiranje paketov v oblaku", + "Local package backup": "Lokalno varnostno kopiranje paketov", + "Local backup advanced options": "Napredne možnosti lokalnega varnostnega kopiranja", + "Log in with GitHub": "Prijava z GitHub", + "Log out from GitHub": "Odjava iz GitHub", + "Periodically perform a cloud backup of the installed packages": "Redno izvajaj varnostno kopiranje nameščenih paketov v oblaku", + "Cloud backup uses a private GitHub Gist to store a list of installed packages": "Varnostno kopiranje v oblaku uporablja zasebni GitHub Gist za shranjevanje seznama nameščenih paketov", + "Perform a cloud backup now": "Izvedi varnostno kopiranje v oblaku zdaj", + "Backup": "Varnostna kopija", + "Restore a backup from the cloud": "Obnovi varnostno kopijo iz oblaka", + "Begin the process to select a cloud backup and review which packages to restore": "Začni postopek izbire varnostne kopije v oblaku in pregleda paketov za obnovitev", + "Periodically perform a local backup of the installed packages": "Redno izvajaj lokalno varnostno kopiranje nameščenih paketov", + "Perform a local backup now": "Izvedi lokalno varnostno kopiranje zdaj", + "Change backup output directory": "Spremenite lokacijo za varnostne kopije", + "Set a custom backup file name": "Nastavite ime datoteke varnostne kopije po meri", + "Leave empty for default": "Pustite prazno kot privzeto", + "Add a timestamp to the backup file names": "Dodajte časovni žig v imena datotek varnostne kopije", + "Backup and Restore": "Varnostno kopiranje in obnovitev", + "Enable background api (UniGetUI Widgets and Sharing, port 7058)": "Omogoči API v ozadju (UniGetUI Widgets and Sharing, vrata 7058)", + "Wait for the device to be connected to the internet before attempting to do tasks that require internet connectivity.": "Počakajte, da se naprava poveže z internetom, preden začnete z opravili, ki zahtevajo povezavo.", + "Disable the 1-minute timeout for package-related operations": "Onemogočite 1-minutno časovno omejitev za operacije, povezane s paketom", + "Use installed GSudo instead of UniGetUI Elevator": "Uporabi nameščeni GSudo namesto UniGetUI Elevator", + "Use a custom icon and screenshot database URL": "Uporabite ikono po meri in URL zbirke podatkov posnetkov zaslona", + "Enable background CPU Usage optimizations (see Pull Request #3278)": "Omogoči optimizacije porabe CPU v ozadju (glej zahtevo za združitev #3278)", + "Perform integrity checks at startup": "Ob zagonu izvedi preverjanje integritete", + "When batch installing packages from a bundle, install also packages that are already installed": "Pri paketni namestitvi iz svežnja namesti tudi pakete, ki so že nameščeni", + "Experimental settings and developer options": "Eksperimentalne nastavitve in opcije za razvijalce", + "Show UniGetUI's version and build number on the titlebar.": "Pokaži različico UniGetUI in številko izgradnje v naslovni vrstici.", + "Language": "Jezik", + "UniGetUI updater": "UniGetUI posodobitveni program", + "Telemetry": "Telemetrija", + "Manage UniGetUI settings": "Upravljaj nastavitve UniGetUI", + "Related settings": "Povezane nastavitve", + "Update UniGetUI automatically": "Posodobi UniGetUI samodejno", + "Check for updates": "Preverite posodobitve", + "Install prerelease versions of UniGetUI": "Namestite predizdajne različice UniGetUI", + "Manage telemetry settings": "Upravljaj nastavitve telemetrije", + "Manage": "Upravljaj", + "Import settings from a local file": "Uvozi nastavitve iz lokalne datoteke", + "Import": "Uvozi", + "Export settings to a local file": "Izvozi nastavitve v lokalno datoteko", + "Export": "Izvoz", + "Reset UniGetUI": "Ponastavite UniGetUI", + "User interface preferences": "Nastavitve uporabniškega vmesnika", + "Application theme, startup page, package icons, clear successful installs automatically": "Tema aplikacije, začetna stran, ikone paketov, samodejno brisanje uspešnih namestitev", + "General preferences": "Splošne nastavitve", + "UniGetUI display language:": "Prikazni jezik v UniGetUI:", + "System language": "Jezik sistema", + "Is your language missing or incomplete?": "Ali vaš jezik manjka ali je nepopoln?", + "Appearance": "Videz", + "UniGetUI on the background and system tray": "UniGetUI v ozadju in sistemski vrstici", + "Package lists": "Seznami paketov", + "Use classic mode": "Uporabi klasični način", + "Restart UniGetUI to apply this change": "Znova zaženite UniGetUI, da uveljavite to spremembo", + "The classic UI is disabled for beta testers": "Klasični uporabniški vmesnik je onemogočen za beta preizkuševalce", + "Close UniGetUI to the system tray": "Zaprite UniGetUI v sistemsko vrstico", + "Manage UniGetUI autostart behaviour": "Upravljaj vedenje samodejnega zagona UniGetUI", + "Show package icons on package lists": "Pokaži ikone paketov na seznamih paketov", + "Clear cache": "Počisti predpomnilnik", + "Select upgradable packages by default": "Privzeto izberite nadgradljive pakete", + "Light": "Svetla", + "Dark": "Temna", + "Follow system color scheme": "Sledi sistemski barvni shemi", + "Application theme:": "Teme aplikacije:", + "UniGetUI startup page:": "Začetna stran UniGetUI:", + "Proxy settings": "Nastavitve posredniškega strežnika", + "Other settings": "Druge nastavitve", + "Connect the internet using a custom proxy": "Povežite se z internetom prek prilagojenega posredniškega strežnika", + "Please note that not all package managers may fully support this feature": "Upoštevajte, da vsi upravljalniki paketov morda ne podpirajo te funkcije", + "Proxy URL": "URL posredniškega strežnika", + "Enter proxy URL here": "Vnesite URL posredniškega strežnika tukaj", + "Authenticate to the proxy with a user and a password": "Za overitev pri posredniškem strežniku uporabite uporabniško ime in geslo", + "Internet and proxy settings": "Nastavitve interneta in posredniškega strežnika", + "Package manager preferences": "Nastavitve upravitelja paketov", + "Ready": "Pripravljen", + "Not found": "Ni najdeno", + "Notification preferences": "Nastavitve obvestil", + "Notification types": "Vrste obvestil", + "The system tray icon must be enabled in order for notifications to work": "Ikona v sistemski vrstici mora biti omogočena za delovanje obvestil", + "Enable UniGetUI notifications": "Omogoči obvestila UniGetUI", + "Show a notification when there are available updates": "Prikaži obvestilo, ko so na voljo posodobitve", + "Show a silent notification when an operation is running": "Pokaži tiho obvestilo, ko se operacija izvaja", + "Show a notification when an operation fails": "Pokaži obvestilo, ko operacija ne uspe", + "Show a notification when an operation finishes successfully": "Pokažite obvestilo, ko se operacija uspešno konča", + "Concurrency and execution": "Vzporednost in izvajanje", + "Automatic desktop shortcut remover": "Samodejni odstranjevalec bližnjic na namizju", + "Choose how many operations should be performed in parallel": "Izberite, koliko operacij naj se izvaja vzporedno", + "Clear successful operations from the operation list after a 5 second delay": "Po 5 sekundnem zamiku izbrišite uspešne operacije s seznama operacij", + "Download operations are not affected by this setting": "Ta nastavitev ne vpliva na postopke prenosa", + "You may lose unsaved data": "Lahko izgubite neshranjene podatke", + "Ask to delete desktop shortcuts created during an install or upgrade.": "Vprašajte za brisanje bližnjic na namizju, ustvarjenih med namestitvijo ali nadgradnjo.", + "Package update preferences": "Nastavitve posodobitev paketov", + "Update check frequency, automatically install updates, etc.": "Pogostost preverjanja posodobitev, samodejna namestitev posodobitev itd.", + "Reduce UAC prompts, elevate installations by default, unlock certain dangerous features, etc.": "Zmanjšaj pozive UAC, privzeto povišaj namestitve, odkleni nekatere nevarne funkcije itd.", + "Package operation preferences": "Nastavitve operacij paketov", + "Enable {pm}": "Omogoči {pm}", + "Not finding the file you are looking for? Make sure it has been added to path.": "Ne najdete datoteke, ki jo iščete? Prepričajte se, da je bila dodana v PATH.", + "Select the executable to be used. The following list shows the executables found by UniGetUI": "Izberite izvršljivo datoteko, ki jo želite uporabiti. Naslednji seznam prikazuje izvršljive datoteke, ki jih je našel UniGetUI", + "For security reasons, changing the executable file is disabled by default": "Iz varnostnih razlogov je spreminjanje izvršljive datoteke privzeto onemogočeno", + "Change this": "Spremeni to", + "Copy path": "Kopiraj pot", + "Current executable file:": "Trenutna izvršljiva datoteka:", + "Ignore packages from {pm} when showing a notification about updates": "Prezri pakete iz {pm} pri prikazu obvestil o posodobitvah", + "Update security": "Varnost posodobitev", + "Use global setting": "Uporabi globalno nastavitev", + "Minimum age for updates": "Minimalna starost posodobitev", + "e.g. 10": "npr. 10", + "Custom minimum age (days)": "Minimalna starost po meri (dni)", + "{pm} does not provide release dates for its packages, so this setting will have no effect": "{pm} ne navaja datumov izdaje za svoje pakete, zato ta nastavitev ne bo imela učinka", + "{pm} only provides release dates for some of its packages, so this setting will only apply to those packages": "{pm} ponuja datume izdaje samo za nekatere svoje pakete, zato bo ta nastavitev veljala le za te pakete", + "Override the global minimum update age for this package manager": "Preglasi globalno minimalno starost posodobitev za tega upravitelja paketov", + "View {0} logs": "Ogled dnevnikov za {0}", + "If Python cannot be found or is not listing packages but is installed on the system, ": "Če Pythona ni mogoče najti ali ne navaja paketov, čeprav je nameščen v sistemu, ", + "Advanced options": "Napredne možnosti", + "WinGet command-line tool": "Orodje ukazne vrstice WinGet", + "Choose which command-line tool UniGetUI uses for WinGet operations when the COM API is not used": "Izberite, katero orodje ukazne vrstice UniGetUI uporablja za operacije WinGet, kadar COM API ni v uporabi", + "WinGet COM API": "WinGet COM API", + "Choose whether UniGetUI can use the WinGet COM API before falling back to the command-line tool": "Izberite, ali lahko UniGetUI uporabi WinGet COM API, preden preklopi na orodje ukazne vrstice", + "Reset WinGet": "Ponastavite WinGet", + "This may help if no packages are listed": "To lahko pomaga, če ni prikazanih paketov", + "Force install location parameter when updating packages with custom locations": "Ob posodabljanju paketov z lokacijami po meri vsili parameter mesta namestitve", + "Install Scoop": "Namesti Scoop", + "Uninstall Scoop (and its packages)": "Odstrani Scoop (in njegove pakete)", + "Run cleanup and clear cache": "Zaženite čiščenje in počistite predpomnilnik", + "Run": "Zaženi", + "Enable Scoop cleanup on launch": "Omogoči čiščenje Scoop-a ob zagonu", + "Default vcpkg triplet": "Privzeti vcpkg triplet", + "Change vcpkg root location": "Spremeni korensko lokacijo vcpkg", + "Reset vcpkg root location": "Ponastavi korensko lokacijo vcpkg", + "Open vcpkg root location": "Odpri korensko lokacijo vcpkg", + "Language, theme and other miscellaneous preferences": "Jezik, tema in druge raznovrstne nastavitve", + "Show notifications on different events": "Prikažite obvestila o različnih dogodkih", + "Change how UniGetUI checks and installs available updates for your packages": "Spremenite, kako UniGetUI preverja in namešča razpoložljive posodobitve za vaše pakete", + "Automatically save a list of all your installed packages to easily restore them.": "Samodejno shranite seznam vseh nameščenih paketov, da jih preprosto obnovite.", + "Enable and disable package managers, change default install options, etc.": "Omogočite in onemogočite upravitelje paketov, spremenite privzete možnosti namestitve itd.", + "Internet connection settings": "Nastavitve internetne povezave", + "Proxy settings, etc.": "Nastavitve posredniškega strežnika itd.", + "Beta features and other options that shouldn't be touched": "Beta funkcije in druge možnosti, ki se jih ne bi smeli dotikati", + "Reload sources": "Osveži vire", + "Delete source": "Izbriši vir", + "Known sources": "Znani viri", + "Update checking": "Preverjanje posodobitev", + "Automatic updates": "Samodejne posodobitve", + "Check for package updates periodically": "Periodično preverjaj posodobitve paketov", + "Check for updates every:": "Preveri za posodobitve vsak:", + "Install available updates automatically": "Samodejno namestite razpoložljive posodobitve", + "Do not automatically install updates when the network connection is metered": "Ne nameščaj posodobitev samodejno pri merjeni povezavi", + "Do not automatically install updates when the device runs on battery": "Ne nameščaj posodobitev samodejno, ko naprava deluje na baterijo", + "Do not automatically install updates when the battery saver is on": "Ne nameščaj posodobitev samodejno, ko je vklopljen varčevalnik baterije", + "Only show updates that are at least the specified number of days old": "Prikaži samo posodobitve, stare vsaj toliko dni, kot je določeno", + "Warn me when the installer URL host changes between the installed version and the new version (WinGet only)": "Opozori me, ko se gostitelj URL-ja namestitvenega programa spremeni med nameščeno in novo različico (samo WinGet)", + "Change how UniGetUI handles install, update and uninstall operations.": "Spremenite, kako UniGetUI upravlja z namestitvami, posodobitvami in odstranitvami.", + "Navigation": "Navigacija", + "Check for UniGetUI updates": "Preveri posodobitve UniGetUI", + "Quit UniGetUI": "Zapri UniGetUI", + "Filters": "Filtri", + "Sources": "Viri", + "Search for packages to start": "Za začetek poiščite pakete", + "Select all": "Označi vse", + "Clear selection": "Odznači vse", + "Instant search": "Takojšnje iskanje", + "Distinguish between uppercase and lowercase": "Razlikuj med velikimi in malimi črkami", + "Ignore special characters": "Ignorirajte posebne znake", + "Search mode": "Način iskanja", + "Both": "Oboje", + "Exact match": "Natančno ujemanje", + "Show similar packages": "Prikaži podobne pakete", + "Loading": "Nalaganje", + "Package": "Paket", + "More options": "Več možnosti", + "Order by:": "Razvrsti po:", + "Name": "Naziv", + "Id": "ID", + "Ascendant": "Naraščajoče", + "Descendant": "Padajoče", + "View modes": "Načini pogleda", + "Reload": "Osveži", + "Closed": "Zaprto", + "Ascending": "Naraščajoče", + "Descending": "Padajoče", + "{0}: {1}, {2}": "{0}: {1}, {2}", + "Order by": "Razvrsti po", + "No results were found matching the input criteria": "Ni bilo najdenih rezultatov, ki bi ustrezali kriterijem vnosa", + "No packages were found": "Najden ni bil noben paket", + "Loading packages": "Nalaganje paketov", + "Skip integrity checks": "Preskoči preverjanje celovitosti", + "Download selected installers": "Prenesi izbrane namestitvene programe", + "Install selection": "Namestite izbor", + "Install options": "Možnosti namestitve", + "Add selection to bundle": "Dodaj izbor v sveženj", + "Download installer": "Prenesite namestitveni program", + "Uninstall selection": "Odstrani izbor", + "Uninstall options": "Možnosti odstranitve", + "Ignore selected packages": "Prezri izbrane pakete", + "Open install location": "Odpri mesto namestitve", + "Reinstall package": "Ponovno namestite paket", + "Uninstall package, then reinstall it": "Odstranite paket in ga nato znova namestite", + "Ignore updates for this package": "Ignoriraj posodobitve za ta paket", + "WinGet malfunction detected": "Zaznana okvara WinGet", + "It looks like WinGet is not working properly. Do you want to attempt to repair WinGet?": "Videti je, da WinGet ne deluje pravilno. Ali želite poskusiti popraviti WinGet?", + "Repair WinGet": "Popravi WinGet", + "Updates will no longer be ignored for {0}": "Posodobitve za {0} ne bodo več prezrte", + "Updates are now ignored for {0}": "Posodobitve za {0} so zdaj prezrte", + "Do not ignore updates for this package anymore": "Ne prezrite več posodobitev za ta paket", + "Add packages or open an existing package bundle": "Dodaj pakete ali odpri obstoječi sveženj paketov", + "Add packages to start": "Dodaj pakete za začetek", + "The current bundle has no packages. Add some packages to get started": "Trenutni sveženj nima paketov. Za začetek dodajte nekaj paketov", + "New": "Novo", + "Save as": "Shrani kot", + "Create .ps1 script": "Ustvari skript .ps1", + "Remove selection from bundle": "Odstrani izbiro iz svežnja", + "Skip hash checks": "Preskoči preverjanje zgoščene vrednosti", + "The package bundle is not valid": "Sveženj paketov ni veljaven", + "The bundle you are trying to load appears to be invalid. Please check the file and try again.": "Zdi se, da paket, ki ga poskušate naložiti, ni veljaven. Preverite datoteko in poskusite znova.", + "Package bundle": "Sveženj paketov", + "Could not create bundle": "Ni bilo mogoče ustvariti svežnja", + "The package bundle could not be created due to an error.": "Paketa ni bilo mogoče ustvariti zaradi napake.", + "Install script": "Namestitveni skript", + "PowerShell script": "Skript PowerShell", + "The installation script saved to {0}": "Namestitveni skript je bil shranjen v {0}", + "An error occurred": "Prišlo je do napake", + "An error occurred while attempting to create an installation script:": "Pri poskusu ustvarjanja namestitvenega skripta je prišlo do napake:", + "Hooray! No updates were found.": "Hura! Ni najdenih posodobitev!", + "Uninstall selected packages": "Odstrani izbrane pakete", + "Update selection": "Posodobi izbor", + "Update options": "Možnosti posodobitve", + "Uninstall package, then update it": "Odstranite paket in ga nato posodobite", + "Uninstall package": "Odstrani paket", + "Skip this version": "Preskoči to različico", + "Pause updates for": "Začasno ustavi posodobitve za", + "User | Local": "Uporabnik | Lokalno", + "Machine | Global": "Računalnik | Globalno", + "The default package manager for Debian/Ubuntu-based Linux distributions.
Contains: Debian/Ubuntu packages": "Privzeti upravljalnik paketov za distribucije Linux, ki temeljijo na Debian/Ubuntu.
Vsebuje: pakete Debian/Ubuntu", + "The Rust package manager.
Contains: Rust libraries and programs written in Rust": "Upravitelj paketov Rust.
Vsebuje: Knjižnice in programe Rust, napisane v Rustu", + "The classical package manager for windows. You'll find everything there.
Contains: General Software": "Klasični upravitelj paketov za Windows. Tukaj boste našli vse.
Vsebuje: Splošno programsko opremo", + "The default package manager for RHEL/Fedora-based Linux distributions.
Contains: RPM packages": "Privzeti upravljalnik paketov za distribucije Linux, ki temeljijo na RHEL/Fedora.
Vsebuje: pakete RPM", + "A repository full of tools and executables designed with Microsoft's .NET ecosystem in mind.
Contains: .NET related tools and scripts": "Repozitorij, poln orodij in izvršljivih datotek, zasnovanih z mislijo na Microsoftov ekosistem .NET.
Vsebuje: orodja in skripte, povezane z .NET", + "The universal Linux package manager for desktop applications.
Contains: Flatpak applications from configured remotes": "Univerzalni upravljalnik paketov za Linux za namizne aplikacije.
Vsebuje: aplikacije Flatpak iz konfiguriranih oddaljenih virov", + "NuPkg (zipped manifest)": "NuPkg (stisnjen manifest)", + "The Missing Package Manager for macOS (or Linux).
Contains: Formulae, Casks": "Manjkajoči upravljalnik paketov za macOS (ali Linux).
Vsebuje: Formulae, Casks", + "Node JS's package manager. Full of libraries and other utilities that orbit the javascript world
Contains: Node javascript libraries and other related utilities": "Upravitelj paketov Node JS. Polno knjižnic in drugih pripomočkov, ki krožijo po svetu javascripta
Vsebuje: Knjižnice javascript vozlišča in druge povezane pripomočke", + "The default package manager for Arch Linux and its derivatives.
Contains: Arch Linux packages": "Privzeti upravljalnik paketov za Arch Linux in njegove izpeljanke.
Vsebuje: pakete Arch Linux", + "Python's library manager. Full of python libraries and other python-related utilities
Contains: Python libraries and related utilities": "Upravitelj knjižnice Python. Polno knjižnic Python in drugih pripomočkov, povezanih s Pythonom
Vsebuje: Knjižnice Python in sorodni pripomočki", + "PowerShell's package manager. Find libraries and scripts to expand PowerShell capabilities
Contains: Modules, Scripts, Cmdlets": "Upravitelj paketov PowerShell. Poiščite knjižnice in skripte za razširitev zmogljivosti lupine PowerShell
Vsebuje: Module, skripte, cmdlete", + "extracted": "ekstrahirano", + "Scoop package": "Scoop paket", + "Great repository of unknown but useful utilities and other interesting packages.
Contains: Utilities, Command-line programs, General Software (extras bucket required)": "Odlično skladišče neznanih, a uporabnih pripomočkov in drugih zanimivih paketov.
Vsebuje: Pripomočke, programe ukazne vrstice, splošno programsko opremo (potrebno je vedro z dodatki)", + "The universal Linux package manager by Canonical.
Contains: Snap packages from the Snapcraft store": "Univerzalni upravljalnik paketov za Linux podjetja Canonical.
Vsebuje: pakete Snap iz trgovine Snapcraft", + "library": "knjižnica", + "feature": "funkcija", + "A popular C/C++ library manager. Full of C/C++ libraries and other C/C++-related utilities
Contains: C/C++ libraries and related utilities": "Priljubljen upravitelj knjižnic C/C++. Polno knjižnic C/C++ in drugih pripomočkov, povezanih s C/C++
Vsebuje: Knjižnice C/C++ in sorodni pripomočki", + "option": "opcija", + "This package cannot be installed from an elevated context.": "Tega paketa ni mogoče namestiti iz povišanega konteksta.", + "Please run UniGetUI as a regular user and try again.": "Zaženite UniGetUI kot običajni uporabnik in poskusite znova.", + "Please check the installation options for this package and try again": "Preverite možnosti namestitve za ta paket in poskusite znova", + "Microsoft's official package manager. Full of well-known and verified packages
Contains: General Software, Microsoft Store apps": "Microsoftov uradni upravitelj paketov. Polno znanih in preverjenih paketov
Vsebuje: Splošno programsko opremo, aplikacije Microsoft Store", + "Local PC": "Lokalni PC", + "Android Subsystem": "Podsistem Android", + "Operation on queue (position {0})...": "Operacija v čakalni vrsti (položaj {0}) ...", + "Click here for more details": "Kliknite tukaj za več podrobnosti", + "Operation canceled by user": "Operacijo je preklical uporabnik", + "Running PreOperation ({0}/{1})...": "Izvajanje PreOperation ({0}/{1})...", + "PreOperation {0} out of {1} failed, and was tagged as necessary. Aborting...": "PreOperation {0} od {1} ni uspela in je bila označena kot obvezna. Prekinjam...", + "PreOperation {0} out of {1} finished with result {2}": "PreOperation {0} od {1} se je končala z rezultatom {2}", + "Starting operation...": "Zaganjanje operacije...", + "Running PostOperation ({0}/{1})...": "Izvajanje PostOperation ({0}/{1})...", + "PostOperation {0} out of {1} failed, and was tagged as necessary. Aborting...": "PostOperation {0} od {1} ni uspela in je bila označena kot obvezna. Prekinjam...", + "PostOperation {0} out of {1} finished with result {2}": "PostOperation {0} od {1} se je končala z rezultatom {2}", + "{package} installer download": "Prenos namestitvenega programa za {package}", + "{0} installer is being downloaded": "Namestitveni program za {0} se prenaša", + "Download succeeded": "Prenos uspel", + "{package} installer was downloaded successfully": "Namestitveni program za {package} je bil uspešno prenesen", + "Download failed": "Prenos ni uspel", + "{package} installer could not be downloaded": "Namestitvenega programa za {package} ni bilo mogoče prenesti", + "{package} Installation": "{package} Namestitev", + "{0} is being installed": "{0} se namešča", + "Installation succeeded": "Namestitev je uspela", + "{package} was installed successfully": "{package} je bil uspešno nameščen", + "Installation failed": "Namestitev ni uspela", + "{package} could not be installed": "{package} ni bilo mogoče namestiti", + "{package} Update": "{package} Posodobitev", + "Update succeeded": "Posodobite uspešna", + "{package} was updated successfully": "{package} je bil uspešno posodobljen", + "Update failed": "Posodobitev spodletela", + "{package} could not be updated": "{package} ni bilo mogoče posodobiti", + "{package} Uninstall": "{package} Odstranitev", + "{0} is being uninstalled": "{0} se odstranjuje", + "Uninstall succeeded": "Odmestitev uspešna", + "{package} was uninstalled successfully": "{package} je bil uspešno odstranjen", + "Uninstall failed": "Odmestitev ni uspela", + "{package} could not be uninstalled": "{package} ni bilo mogoče odstraniti", + "Adding source {source}": "Dodajanje vira {source}", + "Adding source {source} to {manager}": "Dodajanje vira {source} v {manager}", + "Source added successfully": "Vir uspešno dodan", + "The source {source} was added to {manager} successfully": "Vir {source} je bil uspešno dodan v {manager}", + "Could not add source": "Vira ni bilo mogoče dodati", + "Could not add source {source} to {manager}": "Ni bilo mogoče dodati vira {source} v {manager}", + "Removing source {source}": "Odstranjevanje vira {source}", + "Removing source {source} from {manager}": "Odstranjevanje vira {source} iz {manager}", + "Source removed successfully": "Vir uspešno odstranjen", + "The source {source} was removed from {manager} successfully": "Vir {source} je bil uspešno odstranjen iz {manager}", + "Could not remove source": "Vira ni bilo mogoče odstraniti", + "Could not remove source {source} from {manager}": "Vira {source} ni bilo mogoče odstraniti iz {manager}", + "The package manager \"{0}\" was not found": "Upravitelj paketov \"{0}\" ni bil najden", + "The package manager \"{0}\" is disabled": "Upravitelj paketov \"{0}\" je onemogočen", + "There is an error with the configuration of the package manager \"{0}\"": "Prišlo je do napake pri konfiguraciji upravitelja paketov \"{0}\"", + "The package \"{0}\" was not found on the package manager \"{1}\"": "Paket \"{0}\" ni bil najden v upravitelju paketov \"{1}\"", + "{0} is disabled": "{0} je onemogočeno", + "{0} weeks": "{0} tednov", + "1 month": "1 mesec", + "{0} months": "{0} mesecev", + "Something went wrong": "Nekaj je šlo narobe", + "An interal error occurred. Please view the log for further details.": "Prišlo je do notranje napake. Za več podrobnosti si oglejte dnevnik.", + "No applicable installer was found for the package {0}": "Za paket {0} ni bilo najdenega ustreznega namestitvenega programa", + "Integrity checks will not be performed during this operation": "Preverjanje integritete ne bo izvedeno med to operacijo", + "This is not recommended.": "To ni priporočljivo.", + "Run now": "Zaženi zdaj", + "Run next": "Zaženi naslednje", + "Run last": "Zaženi zadnje", + "Show in explorer": "Pokaži v raziskovalcu", + "Checked": "Označeno", + "Unchecked": "Neoznačeno", + "This package is already installed": "Ta paket je že nameščen", + "This package can be upgraded to version {0}": "Ta paket je mogoče nadgraditi na različico {0}", + "Updates for this package are ignored": "Posodobitve za ta paket so prezrte", + "This package is being processed": "Ta paket je v obdelavi", + "This package is not available": "Ta paket ni na voljo", + "Select the source you want to add:": "Izberite vir, ki ga želite dodati:", + "Source name:": "Ime vira:", + "Source URL:": "URL vira:", + "An error occurred when adding the source: ": "Pri dodajanju vira je prišlo do napake:", + "Package management made easy": "Upravljanje paketov na enostaven način", + "version {0}": "različica {0}", + "[RAN AS ADMINISTRATOR]": "ZAGNANO KOT SKRBNIK", + "Portable mode": "Prenosni način", + "DEBUG BUILD": "RAZVOJNA RAZLIČICA", + "Here you can change UniGetUI's behaviour regarding the following shortcuts. Checking a shortcut will make UniGetUI delete it if if gets created on a future upgrade. Unchecking it will keep the shortcut intact": "Tukaj lahko spremenite vedenje UniGetUI glede naslednjih bližnjic. Če označite bližnjico, jo bo UniGetUI izbrisal, če bo ustvarjena pri prihodnji nadgradnji. Če jo počistite, bo bližnjica ostala nedotaknjena", + "Manual scan": "Ročno iskanje", + "Existing shortcuts on your desktop will be scanned, and you will need to pick which ones to keep and which ones to remove.": "Obstoječe bližnjice na namizju bodo pregledane, izbrati boste morali, katere želite obdržati in katere odstraniti.", + "Delete?": "Odstrani?", + "I understand": "Razumem", + "Chocolatey setup changed": "Nastavitev Chocolatey se je spremenila", + "UniGetUI no longer includes its own private Chocolatey installation. A legacy UniGetUI-managed Chocolatey installation was detected for this user profile, but system Chocolatey was not found. Chocolatey will stay unavailable in UniGetUI until Chocolatey is installed on the system and UniGetUI is restarted. Applications previously installed through UniGetUI's bundled Chocolatey may still appear under other sources such as Local PC or WinGet.": "UniGetUI ne vključuje več lastne zasebne namestitve Chocolatey. Za ta uporabniški profil je bila zaznana starejša namestitev Chocolatey, ki jo je upravljal UniGetUI, vendar sistemski Chocolatey ni bil najden. Chocolatey bo v UniGetUI ostal nedostopen, dokler Chocolatey ni nameščen v sistem in UniGetUI ni znova zagnan. Aplikacije, ki so bile predhodno nameščene prek priloženega Chocolatey v UniGetUI, se lahko še vedno prikažejo pod drugimi viri, kot sta Lokalni PC ali WinGet.", + "NOTE: This troubleshooter can be disabled from UniGetUI Settings, on the WinGet section": "OPOMBA: To orodje za odpravljanje težav lahko onemogočite v nastavitvah UniGetUI v razdelku WinGet", + "Restart": "Ponovni zagon", + "Are you sure you want to delete all shortcuts?": "Ali ste prepričani, da želite izbrisati vse bližnjice?", + "Any new shorcuts created during an install or an update operation will be deleted automatically, instead of showing a confirmation prompt the first time they are detected.": "Vse nove bližnjice, ustvarjene med namestitvijo ali posodobitvijo, bodo samodejno izbrisane, namesto da bi se prvič prikazalo potrditveno okno.", + "Any shorcuts created or modified outside of UniGetUI will be ignored. You will be able to add them via the {0} button.": "Vse bližnjice, ustvarjene ali spremenjene zunaj UniGetUI, bodo prezrte. Dodate jih lahko z gumbom {0}.", + "Are you really sure you want to enable this feature?": "Ali ste res prepričani, da želite omogočiti to funkcijo?", + "No new shortcuts were found during the scan.": "Med iskanjem niso bile najdene nove bližnjice.", + "How to add packages to a bundle": "Kako dodati pakete v sveženj", + "In order to add packages to a bundle, you will need to: ": "Za dodajanje paketov v sveženj morate:", + "1. Navigate to the \"{0}\" or \"{1}\" page.": "1. Pomaknite se na stran \"{0}\" ali \"{1}\".", + "2. Locate the package(s) you want to add to the bundle, and select their leftmost checkbox.": "2. Poiščite pakete, ki jih želite dodati v sveženj, in izberite njihovo skrajno levo potrditveno polje.", + "3. When the packages you want to add to the bundle are selected, find and click the option \"{0}\" on the toolbar.": "3. Ko so izbrani paketi, ki jih želite dodati v sveženj, v orodni vrstici poiščite in kliknite možnost \"{0}\".", + "4. Your packages will have been added to the bundle. You can continue adding packages, or export the bundle.": "4. Vaši paketi bodo dodani v paket. Lahko nadaljujete z dodajanjem paketov ali izvozite sveženj.", + "Which backup do you want to open?": "Katero varnostno kopijo želite odpreti?", + "Select the backup you want to open. Later, you will be able to review which packages you want to install.": "Izberite varnostno kopijo, ki jo želite odpreti. Pozneje boste lahko pregledali, katere pakete ali programe želite obnoviti.", + "There are ongoing operations. Quitting UniGetUI may cause them to fail. Do you want to continue?": "V teku so operacije. Zapustitev UniGetUI lahko povzroči njihovo odpoved. Želite nadaljevati?", + "UniGetUI or some of its components are missing or corrupt.": "UniGetUI ali nekatere njegove komponente manjkajo ali so poškodovane.", + "It is strongly recommended to reinstall UniGetUI to adress the situation.": "Močno priporočamo, da znova namestite UniGetUI in s tem odpravite težavo.", + "Refer to the UniGetUI Logs to get more details regarding the affected file(s)": "Za več podrobnosti o prizadetih datotekah si oglejte dnevnike UniGetUI", + "Integrity checks can be disabled from the Experimental Settings": "Preverjanje integritete je mogoče onemogočiti v eksperimentalnih nastavitvah", + "Repair UniGetUI": "Popravi UniGetUI", + "Live output": "Trenutni izpis", + "This package bundle had some settings that are potentially dangerous, and may be ignored by default.": "Ta sveženj paketov je vseboval nekatere potencialno nevarne nastavitve, ki bodo morda privzeto prezrte.", + "Entries that show in YELLOW will be IGNORED.": "Vnosi, prikazani RUMENO, bodo PREZRTI.", + "Entries that show in RED will be IMPORTED.": "Vnosi, prikazani RDEČE, bodo UVOŽENI.", + "You can change this behavior on UniGetUI security settings.": "To vedenje lahko spremenite v varnostnih nastavitvah UniGetUI.", + "Open UniGetUI security settings": "Odpri varnostne nastavitve UniGetUI", + "Should you modify the security settings, you will need to open the bundle again for the changes to take effect.": "Če spremenite varnostne nastavitve, boste morali sveženj znova odpreti, da bodo spremembe začele veljati.", + "Details of the report:": "Podrobnosti poročila:", + "Are you sure you want to create a new package bundle? ": "Ali ste prepričani, da želite ustvariti nov sveženj paketov?", + "Any unsaved changes will be lost": "Vse neshranjene spremembe bodo izgubljene", + "Warning!": "Opozorilo!", + "For security reasons, custom command-line arguments are disabled by default. Go to UniGetUI security settings to change this. ": "Iz varnostnih razlogov so argumenti ukazne vrstice po meri privzeto onemogočeni. Če želite to spremeniti, odprite varnostne nastavitve UniGetUI.", + "Change default options": "Spremeni privzete možnosti", + "Ignore future updates for this package": "Ignoriraj posodobitve za ta paket", + "For security reasons, pre-operation and post-operation scripts are disabled by default. Go to UniGetUI security settings to change this. ": "Iz varnostnih razlogov so skripti pred in po operaciji privzeto onemogočeni. Če želite to spremeniti, odprite varnostne nastavitve UniGetUI.", + "You can define the commands that will be run before or after this package is installed, updated or uninstalled. They will be run on a command prompt, so CMD scripts will work here.": "Določite lahko ukaze, ki se bodo izvajali pred ali po namestitvi, posodobitvi ali odstranitvi tega paketa. Izvajali se bodo v ukaznem pozivu, zato bodo tukaj delovali skripti CMD.", + "Change this and unlock": "Spremeni to in odkleni", + "{0} Install options are currently locked because {0} follows the default install options.": "Možnosti namestitve za {0} so trenutno zaklenjene, ker {0} sledi privzetim možnostim namestitve.", + "Unset or unknown": "Nepostavljeno ali neznano", + "This package has no screenshots or is missing the icon? Contrbute to UniGetUI by adding the missing icons and screenshots to our open, public database.": "Ta paket nima posnetkov zaslona ali manjka ikona? Prispevajte k UniGetUI tako, da dodate manjkajoče ikone in posnetke zaslona v našo odprto javno bazo podatkov.", + "Become a contributor": "Postanite soustvarjalec", + "Update to {0} available": "Posodobitev na {0} na voljo", + "Reinstall": "Ponovno namestite", + "Installer not available": "Namestitveni program ni na voljo", + "Version:": "Različica:", + "UniGetUI Version {0}": "UniGetUI različica {0}", + "Performing backup, please wait...": "Izvajanje varnostne kopije, počakajte ...", + "An error occurred while logging in: ": "Pri prijavi je prišlo do napake: ", + "Fetching available backups...": "Pridobivanje razpoložljivih varnostnih kopij...", + "Done!": "Končano!", + "The cloud backup has been loaded successfully.": "Varnostna kopija iz oblaka je bila uspešno naložena.", + "An error occurred while loading a backup: ": "Pri nalaganju varnostne kopije je prišlo do napake: ", + "Backing up packages to GitHub Gist...": "Varnostno kopiranje paketov na GitHub Gist ...", + "Backup Successful": "Varnostno kopiranje je bilo uspešno", + "The cloud backup completed successfully.": "Varnostno kopiranje v oblaku je bilo uspešno dokončano.", + "Could not back up packages to GitHub Gist: ": "Paketov ni bilo mogoče varnostno kopirati v GitHub Gist: ", + "It is not guaranteed that the provided credentials will be stored safely, so you may as well not use the credentials of your bank account": "Ni zagotovila, da bodo poverilnice varno shranjene, zato ne uporabljajte bančnih podatkov", + "Enable the automatic WinGet troubleshooter": "Omogočite samodejno orodje za odpravljanje težav WinGet", + "Add updates that fail with a 'no applicable update found' to the ignored updates list": "Na seznam prezrtih posodobitev dodajte posodobitve, ki niso uspele z \"ni ustrezne posodobitve\".", + "Invalid selection": "Neveljaven izbor", + "No package was selected": "Noben paket ni bil izbran", + "More than 1 package was selected": "Izbranih je bilo več kot 1 paket", + "List": "Seznam", + "Grid": "Mreža", + "Icons": "Ikone", + "\"{0}\" is a local package and does not have available details": "\"{0}\" je lokalni paket in nima na voljo podrobnosti", + "\"{0}\" is a local package and is not compatible with this feature": "\"{0}\" je lokalni paket in ni združljiv s to funkcijo.", + "Add packages to bundle": "Dodajte pakete v sveženj", + "Preparing packages, please wait...": "Priprava paketov, počakajte ...", + "Loading packages, please wait...": "Nalaganje paketov, počakajte ...", + "Saving packages, please wait...": "Shranjevanje paketov, počakajte ...", + "The bundle was created successfully on {0}": "Sveženj je bil uspešno ustvarjen dne {0}", + "User profile": "Uporabniški profil", + "Error": "Napaka", + "Log in failed: ": "Prijava ni uspela: ", + "Log out failed: ": "Odjava ni uspela: ", + "Package backup settings": "Nastavitve varnostnega kopiranja paketov", + "Package managers": "Upravljalniki paketov", + "Manage UniGetUI autostart behaviour from the Settings app": "Upravljaj vedenje samodejnega zagona UniGetUI", + "Choose how many operations shoulds be performed in parallel": "Izberite, koliko operacij naj se izvaja vzporedno", + "Something went wrong while launching the updater.": "Pri zagonu posodobitvenega programa je prišlo do napake.", + "Please try again later": "Poskusite znova pozneje", + "Show the release notes after UniGetUI is updated": "Pokaži opombe ob izdaji po posodobitvi UniGetUI" +} diff --git a/src/Languages/lang_sq.json b/src/Languages/lang_sq.json new file mode 100644 index 0000000..ffd3572 --- /dev/null +++ b/src/Languages/lang_sq.json @@ -0,0 +1,851 @@ +{ + "{0} of {1} operations completed": "U përfunduan {0} nga {1} veprime", + "{0} is now {1}": "{0} tani është {1}", + "Enabled": "Aktivizuar", + "Disabled": "Çaktivizuar", + "Privacy": "Privatësia", + "Hide my username from the logs": "Fshih emrin tim të përdoruesit nga regjistrat", + "Replaces your username with **** in the logs. Restart UniGetUI to also hide it from already-recorded entries.": "Zëvendëson emrin tuaj të përdoruesit me **** në regjistra. Rinise UniGetUI për ta fshehur edhe te hyrjet e regjistruara tashmë.", + "Your last update attempt did not complete.": "Përpjekja jote e fundit për përditësim nuk përfundoi.", + "UniGetUI could not confirm whether the update succeeded. Open the log to see what happened.": "UniGetUI nuk mundi të konfirmonte nëse përditësimi pati sukses. Hap ditarin për të parë çfarë ndodhi.", + "View log": "Shiko ditarin", + "The installer reported success but did not restart UniGetUI.": "Instaluesi raportoi sukses, por nuk e rinisi UniGetUI.", + "The installer failed to initialize.": "Instaluesi nuk arriti të inicializohej.", + "Setup was canceled before installation began.": "Konfigurimi u anulua para se të fillonte instalimi.", + "A fatal error occurred during the preparation phase.": "Ndodhi një gabim fatal gjatë fazës së përgatitjes.", + "A fatal error occurred during installation.": "Ndodhi një gabim fatal gjatë instalimit.", + "Installation was canceled while in progress.": "Instalimi u anulua gjatë kryerjes.", + "The installer was terminated by another process.": "Instaluesi u përfundua nga një proces tjetër.", + "The preparation phase determined the installation cannot proceed.": "Faza e përgatitjes përcaktoi se instalimi nuk mund të vazhdojë.", + "The installer could not start. UniGetUI may already be running, or you do not have permission to install.": "Instaluesi nuk mundi të nisej. UniGetUI mund të jetë tashmë në ekzekutim, ose nuk ke leje për të instaluar.", + "Unexpected installer error.": "Gabim i papritur i instaluesit.", + "We are checking for updates.": "Po kontrollojmë për përditësime.", + "Please wait": "Të lutem prit", + "Great! You are on the latest version.": "Shkëlqyeshëm! Je në versionin më të fundit.", + "There are no new UniGetUI versions to be installed": "Nuk ka versione të reja të UniGetUI për t'u instaluar", + "UniGetUI version {0} is being downloaded.": "Versioni {0} i UniGetUI po shkarkohet.", + "This may take a minute or two": "Kjo mund të zgjasë një ose dy minuta", + "The installer authenticity could not be verified.": "Vërtetësia e instaluesit nuk mund të vërtetohej.", + "The update process has been aborted.": "Procesi i përditësimit është ndërprerë.", + "Auto-update is not yet available on this platform.": "Përditësimi automatik nuk ofrohet ende në këtë platformë.", + "Please update UniGetUI manually.": "Të lutem përditëso UniGetUI manualisht.", + "An error occurred when checking for updates: ": "Ndodhi një gabim gjatë kontrollit për përditësime:", + "The updater could not be launched.": "Përditësuesi nuk mundi të nisej.", + "The operating system did not start the installer process.": "Sistemi operativ nuk e nisi procesin e instaluesit.", + "UniGetUI is being updated...": "UniGetUI po përditësohet...", + "Update installed.": "Përditësimi u instalua.", + "UniGetUI was updated successfully, but this running copy was not replaced. This usually means you are running a development build. Close this copy and start the newly-installed version to finish.": "UniGetUI u përditësua me sukses, por kjo kopje në ekzekutim nuk u zëvendësua. Kjo zakonisht do të thotë se po përdor një ndërtim zhvillimi. Mbylle këtë kopje dhe nis versionin e sapoinstaluar për ta përfunduar.", + "The update could not be applied.": "Përditësimi nuk mundi të zbatohej.", + "Installer exit code {0}: {1}": "Kodi i daljes së instaluesit {0}: {1}", + "Update cancelled.": "Përditësimi u anulua.", + "Authentication was cancelled.": "Autentikimi u anulua.", + "Installer exit code {0}": "Kodi i daljes së instaluesit {0}", + "Operation in progress": "Operacion në vazhdim", + "Please wait...": "Të lutem prit...", + "Success!": "Sukses!", + "Failed": "Dështoi", + "An error occurred while processing this package": "Ndodhi një gabim gjatë përpunimit të kësaj pakete", + "Installer": "Instaluesi", + "Executable": "Skedar ekzekutues", + "MSI": "MSI", + "Compressed file": "Skedar i ngjeshur", + "MSIX": "MSIX", + "WinGet was repaired successfully": "WinGet u rregullua me sukses", + "It is recommended to restart UniGetUI after WinGet has been repaired": "Këshillohet të riniset UniGetUI mbasi që rregullohet WinGet", + "WinGet could not be repaired": "WinGet nuk mund të rregullohej", + "An unexpected issue occurred while attempting to repair WinGet. Please try again later": "Ndodhi një gabim i papritur gjatë përpjekjes për të rregulluar WinGet. Të lutem provo përsëri më vonë", + "Log in to enable cloud backup": "Hyr për të aktivizuar kopjen rezervë në re", + "Backup Failed": "Krijimi i kopjes rezervë dështoi", + "Downloading backup...": "Duke shkarkuar kopjen rezervë...", + "An update was found!": "U gjet një përditësim!", + "{0} can be updated to version {1}": "{0} mund të përditësohet në versionin {1}", + "Updates found!": "Përditësimet u gjetën!", + "{0} packages can be updated": "Mund të {0, plural, one {përditësohet {0} paketë} other {përditësohen {0} paketa}}", + "{0} is being updated to version {1}": "{0} po përditësohet në versionin {1}", + "{0} packages are being updated": "Po {0, plural, one {përditësohet {0} paketë} other {përditësohen {0} paketa}}", + "You have currently version {0} installed": "Tani ke të instaluar versionin {0}", + "Desktop shortcut created": "U krijua shkurtoja e tryezës", + "UniGetUI has detected a new desktop shortcut that can be deleted automatically.": "UniGetUI ka zbuluar një shkurtore të re të tryezës që mund të fshihet automatikisht.", + "{0} desktop shortcuts created": "{0, plural, one {U krijua një shkurtore në tryezë} other {U krijuan {0} shkurtore në tryezë}}", + "UniGetUI has detected {0} new desktop shortcuts that can be deleted automatically.": "UniGetUI ka zbuluar {0, plural, one {një shkurtore të re të tryezës që mund të fshihet} other {{0} shkurtore të reja të tryezës që mund të fshihen}} automatikisht.", + "Attention required": "Kërkohet vëmendje", + "Restart required": "Kërkohet rinisja", + "1 update is available": "Ofrohet 1 përditësim", + "{0} updates are available": "{0, plural, one {Ofrohet {0} përditësim} other {Ofrohen {0} përditësime}}", + "Everything is up to date": "Gjithçka është e përditësuar", + "Discover Packages": "Zbulo paketat", + "Available Updates": "Përditësimet e ofruara", + "Installed Packages": "Paketat e instaluara", + "UniGetUI Version {0} by Devolutions": "UniGetUI Versioni {0} nga Devolutions", + "Show UniGetUI": "Shfaq UniGetUI", + "Quit": "Ndal", + "Are you sure?": "A je i sigurt?", + "Do you really want to uninstall {0}?": "Dëshiron vërtet të çinstalosh {0}?", + "Do you really want to uninstall the following {0} packages?": "Dëshiron vërtet të çinstalosh {0, plural, one {paketën} other {{0} paketat}} në vijim?", + "No": "Jo", + "Yes": "Po", + "Partial": "Pjesërisht", + "View on UniGetUI": "Shiko në UniGetUI", + "Update": "Përditeso", + "Open UniGetUI": "Hap UniGetUI", + "Update all": "Përditëso të gjitha", + "Update now": "Përditëso tani", + "Installer host changed since the installed version.\n": "Hosti i instaluesit ka ndryshuar që nga versioni i instaluar.\n", + "This package is on the queue": "Kjo paketë është në radhë", + "installing": "duke instaluar", + "updating": "duke përditësuar", + "uninstalling": "duke çinstaluar", + "installed": "instaluar", + "Retry": "Provo përsëri", + "Install": "Instalo", + "Uninstall": "Çinstalo", + "Open": "Hap", + "Operation profile:": "Profili i operacionit:", + "Follow the default options when installing, upgrading or uninstalling this package": "Ndjek rregullimet e paracaktuara gjatë instalimit, përditësimit ose çinstalimit të kësaj pakete.", + "The following settings will be applied each time this package is installed, updated or removed.": "Cilësimet që vijojnë do të zbatohen sa herë që kjo paketë instalohet, përditësohet ose hiqet.", + "Version to install:": "Versioni për t'u instaluar:", + "Architecture to install:": "Arkitektura për të instaluar:", + "Installation scope:": "Shtrirja e instalimit:", + "Install location:": "Vendndodhja e instalimit:", + "Select": "Përzgjidh", + "Reset": "Rivendos", + "Custom install arguments:": "Argumente të instalimit të personalizuara:", + "Custom update arguments:": "Argumente të përditësimit të personalizuara:", + "Custom uninstall arguments:": "Argumente të çinstalimit të personalizuara:", + "Pre-install command:": "Komanda para instalimit:", + "Post-install command:": "Komanda pas instalimit:", + "Abort install if pre-install command fails": "Anulo instalimin nëse komanda e para-instalimit dështon", + "Pre-update command:": "Komanda para përditësimit:", + "Post-update command:": "Komanda pas përditësimit:", + "Abort update if pre-update command fails": "Anulo përditëimin nëse komanda e para-përditësimit dështon", + "Pre-uninstall command:": "Komanda para çinstalimit:", + "Post-uninstall command:": "Komanda pas çinstalimit:", + "Abort uninstall if pre-uninstall command fails": "Anulo çinstalimin nëse komanda e para-çinstalimit dështon", + "Command-line to run:": "Rreshti i komandës për t'u ekzekutuar:", + "Save and close": "Ruaj dhe mbyll", + "General": "Të përgjithshme", + "Architecture & Location": "Arkitektura dhe vendndodhja", + "Command-line": "Rreshti i komandës", + "Close apps": "Mbyll aplikacionet", + "Pre/Post install": "Para/Pas instalimit", + "Select the processes that should be closed before this package is installed, updated or uninstalled.": "Zgjidh proceset që duhet të mbyllen para se kjo paketë të instalohet, përditësohet ose çinstalohet.", + "Write here the process names here, separated by commas (,)": "Shkruaj këtu emrat e proceseve, të ndarë me presje (,)", + "Try to kill the processes that refuse to close when requested to": "Përpiqu të mbyllësh proceset që refuzojnë të mbyllen kur u kërkohet", + "Run as admin": "Ekzekuto si administrator", + "Interactive installation": "Instalim ndërveprues", + "Skip hash check": "Kapërce kontrollin e hash-it", + "Uninstall previous versions when updated": "Çinstalo versionet e mëparshme gjatë përditësimit", + "Skip minor updates for this package": "Anashkalo përditësimet e vogla për këtë paketë", + "Automatically update this package": "Përditëso këtë paketë automatikisht", + "{0} installation options": "{0} rregullimet e instalimit", + "Latest": "I fundit", + "PreRelease": "Botim paraprak", + "Default": "Paracaktuar", + "Manage ignored updates": "Menaxho përditësimet e shpërfillura", + "The packages listed here won't be taken in account when checking for updates. Double-click them or click the button on their right to stop ignoring their updates.": "Paketat e paraqitura këtu do të shpërfillen kur kontrollohen përditësimet. Kliko dy herë mbi to ose kliko butonin në të djathtën e tyre për të ndaluar shpërfilljen e përditësimeve të tyre.", + "Reset list": "Rivendos listën", + "Do you really want to reset the ignored updates list? This action cannot be reverted": "A dëshiron vërtet ta rivendosësh listën e përditësimeve të shpërfillura? Ky veprim nuk mund të rikthehet", + "No ignored updates": "Nuk ka përditësime të shpërfillura", + "Package Name": "Emri i paketës", + "Package ID": "ID i paketës", + "Ignored version": "Versionet e shpërfillura", + "New version": "Verisoni i ri", + "Source": "Burimi", + "All versions": "Çdo version", + "Unknown": "Panjohur", + "Up to date": "I përditësuar", + "Package {name} from {manager}": "Paketa {name} nga {manager}", + "Remove {0} from ignored updates": "Hiq {0} nga përditësimet e shpërfillura", + "Cancel": "Anulo", + "Administrator privileges": "Privilegjet e administratorit", + "This operation is running with administrator privileges.": "Ky operacion po ekzekutohet me privilegje administratori.", + "Interactive operation": "Operacion ndërveprues", + "This operation is running interactively.": "Ky operacion po ekzekutohet në mënyrë ndërvepruese.", + "You will likely need to interact with the installer.": "Ka shumë gjasa që do të duhet të ndërveprosh me instaluesin.", + "Integrity checks skipped": "Kontrollet e integritetit u anashkaluan", + "Integrity checks will not be performed during this operation.": "Kontrollet e integritetit nuk do të kryhen gjatë këtij operacioni.", + "Proceed at your own risk.": "Vazhdo, por çdo rrezik është në përgjegjësinë tënde.", + "Close": "Mbyll", + "Loading...": "Po ngarkohet...", + "Installer SHA256": "SHA256 i instaluesit", + "Homepage": "Kryefaqja", + "Author": "Autor", + "Publisher": "Botues", + "License": "Leja", + "Manifest": "Manifesti", + "Installer Type": "Lloji i instaluesit", + "Size": "Madhësi", + "Installer URL": "URL i instaluesit", + "Last updated:": "Përditësimi i fundit:", + "Release notes URL": "URL-ja e shënimeve të botimit", + "Package details": "Detajet e paketës", + "Dependencies:": "Varësitë:", + "Release notes": "Shënimet e botimit", + "Screenshots": "Pamje ekrani", + "This package has no screenshots or is missing the icon? Contribute to UniGetUI by adding the missing icons and screenshots to our open, public database.": "Kjo paketë nuk ka pamje ekrani ose i mungon ikona? Kontribuo në UniGetUI duke shtuar ikonat dhe pamjet e ekranit që mungojnë në bazën tonë të hapur dhe publike të të dhënave.", + "Version": "Versioni", + "Install as administrator": "Instalo si administrator", + "Update to version {0}": "Përditëso në versionin {0}", + "Installed Version": "Versioni i instaluar", + "Update as administrator": "Përditëso si administrator", + "Interactive update": "Përditësim ndërveprues", + "Uninstall as administrator": "Çinstalo si administrator", + "Interactive uninstall": "Çinstalim ndërveprues", + "Uninstall and remove data": "Çinstalo dhe hiq të dhënat", + "Not available": "Nuk ofrohet", + "Installer SHA512": "SHA512 i instaluesit", + "Unknown size": "Madhësi e panjohur", + "No dependencies specified": "Nuk janë përcaktuar varësi", + "mandatory": "i detyrueshëm", + "optional": "fakultativ", + "UniGetUI {0} is ready to be installed.": "Versioni {0} i UniGetUI është gati për t'u instaluar.", + "The update process will start after closing UniGetUI": "Procesi i përditësimit do të fillojë pasi të mbyllet UniGetUI", + "UniGetUI has been ran as administrator, which is not recommended. When running UniGetUI as administrator, EVERY operation launched from UniGetUI will have administrator privileges. You can still use the program, but we highly recommend not running UniGetUI with administrator privileges.": "UniGetUI është ekzekutuar si administrator, gjë që nuk rekomandohet. Kur UniGetUI ekzekutohet si administrator, ÇDO operacion i nisur nga UniGetUI do të ketë privilegje administratori. Mund ta përdorësh ende programin, por ne rekomandojmë fuqimisht të mos e ekzekutosh UniGetUI me privilegje administratori.", + "Share anonymous usage data": "Ndaj të dhëna anonime të përdorimit", + "UniGetUI collects anonymous usage data in order to improve the user experience.": "UniGetUI mbledh të dhëna anonime të përdorimit për të përmirësuar përvojën e përdoruesit.", + "Accept": "Prano", + "Software Updates": "Përditësimet e Programeve", + "Package Bundles": "Koleksione të paketave", + "Settings": "Cilësimet", + "Package Managers": "Menaxherët e paketave", + "UniGetUI Log": "Ditari i UniGetUI", + "Package Manager logs": "Ditari i menaxherit të paketave", + "Operation history": "Historiku i operacionëve", + "Help": "Ndihmë", + "UniGetUI": "UniGetUI", + "You have installed UniGetUI Version {0}": "Ke instaluar UniGetUI në versionin {0}", + "Disclaimer": "Mospranim përgjegjësie", + "UniGetUI is developed by Devolutions and is not affiliated with any of the compatible package managers.": "UniGetUI është zhvilluar nga Devolutions dhe nuk është i lidhur me asnjë nga menaxherët e përputhshëm të paketave.", + "UniGetUI wouldn't have been possible without the help of the contributors. Thank you all 🥳": "UniGetUI nuk do të ishte i mundur pa ndihmën e kontribuesve. Faleminderit të gjithëve 🥳", + "UniGetUI uses the following libraries. Without them, UniGetUI wouldn't have been possible.": "UniGetUI përdor libraritë që vijojnë. Pa to, UniGetUI nuk do të ishte i mundur.", + "{0} homepage": "Kryefaqja e {0}", + "UniGetUI has been translated to more than 40 languages thanks to the volunteer translators. Thank you 🤝": "UniGetUI është përkthyer në më shumë se 40 gjuhë falë përkthyesve vullnetarë. Faleminderit 🤝", + "Verbose": "Fjalëshumë", + "1 - Errors": "1 - Gabime", + "2 - Warnings": "2 - Paralajmërime", + "3 - Information (less)": "3 - Informacion (më pak)", + "4 - Information (more)": "4 - Informacion (më shumë)", + "5 - information (debug)": "5 - informacion (korrigjim)", + "Warning": "Paralajmërim", + "The following settings may pose a security risk, hence they are disabled by default.": "Cilësimet e mëposhtme mund të paraqesin një rrezik sigurie, prandaj ato janë të çaktivizuara si paracaktim.", + "Enable the settings below if and only if you fully understand what they do, and the implications they may have.": "Aktivizo cilësimet më poshtë VETËM NË QOFTË SE kupton plotësisht se çfarë bëjnë ato, si dhe implikimet dhe rreziqet që mund të sjellin.", + "The settings will list, in their descriptions, the potential security issues they may have.": "Cilësimet do të tregojnë, në përshkrimet e tyre, problemet e mundshme të sigurisë që mund të shkaktojnë.", + "The backup will include the complete list of the installed packages and their installation options. Ignored updates and skipped versions will also be saved.": "Rezervimi do të përfshijë listën e plotë të paketave të instaluara dhe rregullimet e instalimit të tyre. Gjithashtu do të ruhen përditësimet e shpërfillura dhe versionet e anashkaluara.", + "The backup will NOT include any binary file nor any program's saved data.": "Rezervimi NUK do të përfshijë asnjë skedar binar dhe as të dhëna të ruajtura të ndonjë programi.", + "The size of the backup is estimated to be less than 1MB.": "Madhësia e kopjes rezervë vlerësohet të jetë më pak se 1MB.", + "The backup will be performed after login.": "Rezervimi do të bëhet pas hyrjes.", + "{pcName} installed packages": "Paketat e instaluara në {pcName}", + "Current status: Not logged in": "Gjendja e tanishme: Nuk ke hyr", + "You are logged in as {0} (@{1})": "Ke hyr si {0} (@{1})", + "Nice! Backups will be uploaded to a private gist on your account": "Bukur! Kopjet rezervë do të ngarkohen në një Gist privat në llogarinë tënde", + "Select backup": "Zgjidh kopjen rezervë", + "Settings imported from {0}": "Cilësimet u importuan nga {0}", + "UniGetUI Settings": "Cilësimet e UniGetUI", + "Settings exported to {0}": "Cilësimet u eksportuan në {0}", + "UniGetUI settings were reset": "Cilësimet e UniGetUI u rivendosën", + "Allow pre-release versions": "Lejo versionet e botimit paraprak", + "Apply": "Zbato", + "For security reasons, custom command-line arguments are disabled by default. Go to UniGetUI security settings to change this.": "Për arsye sigurie, argumentet e personalizuara të rreshtit të komandës janë të çaktivizuara si paracaktim. Shko te cilësimet e sigurisë të UniGetUI për ta ndryshuar këtë.", + "Go to UniGetUI security settings": "Shko te cilësimet e sigurisë të UniGetUI", + "The following options will be applied by default each time a {0} package is installed, upgraded or uninstalled.": "Rregullimet e mëposhtme do të aplikohen si paracaktim sa herë që një paketë {0} instalohet, përditësohet ose çinstalohet.", + "Package's default": "Paracaktimet e paketës", + "Install location can't be changed for {0} packages": "Vendndodhja e instalimit nuk mund të ndryshohet për {0} paketa", + "The local icon cache currently takes {0} MB": "Kesh-i lokal i ikonave aktualisht merr {0} MB", + "Username": "Emri i përdoruesit", + "Password": "Fjalëkalim", + "Credentials": "Kredencialet", + "It is not guaranteed that the provided credentials will be stored safely": "Nuk garantohet që kredencialet e dhëna do të ruhen në mënyrë të sigurt", + "Partially": "Pjesërisht", + "Package manager": "Menaxheri i paketave", + "Compatible with proxy": "I përputhshëm me ndërmjetës", + "Compatible with authentication": "I përputhshëm me kyçjen", + "Proxy compatibility table": "Tabela e përputhshmërisë me ndërmjetësit", + "{0} settings": "Cilësimet e {0}", + "{0} status": "Gjendja e {0}", + "Default installation options for {0} packages": "Rregullimet e paracaktuara të instalimit për {0} paketa.", + "Expand version": "Shfaq versionin", + "The executable file for {0} was not found": "Skedari ekzekutues për {0} nuk u gjet", + "{pm} is disabled": "{pm} është çaktivizuar", + "Enable it to install packages from {pm}.": "Aktivizoje për të instaluar paketa nga {pm}.", + "{pm} is enabled and ready to go": "{pm} është aktivizuar dhe është gati", + "{pm} version:": "Versioni i {pm}:", + "{pm} was not found!": "{pm} nuk u gjet!", + "You may need to install {pm} in order to use it with UniGetUI.": "Mund të të duhet të instalosh {pm} në mënyrë që ta përdorësh me UniGetUI.", + "Scoop Installer - UniGetUI": "Instaluesi Scoop - UniGetUI", + "Scoop Uninstaller - UniGetUI": "Çinstaluesi Scoop - UniGetUI", + "Clearing Scoop cache - UniGetUI": "Po pastrohet keshi i Scoop - UniGetUI", + "Restart UniGetUI to fully apply changes": "Rinis UniGetUI që ndryshimet të zbatohen plotësisht", + "Restart UniGetUI": "Rinis UniGetUI", + "Manage {0} sources": "Menaxho burimet {0}", + "Add source": "Shto burim", + "Add": "Shto", + "Source name": "Emri i burimit", + "Source URL": "URL-ja e burimit", + "Other": "Tjerë", + "No minimum age": "Pa moshë minimale", + "1 day": "1 ditë", + "{0} days": "{0} ditë", + "Custom...": "E personalizuar...", + "{0} minutes": "{0, plural, one {{0} minutë} other {{0} minuta}}", + "1 hour": "1 orë", + "{0} hours": "{0} orë", + "1 week": "1 javë", + "Supports release dates": "Mbështet datat e publikimit", + "Release date support per package manager": "Mbështetja e datës së publikimit sipas menaxherit të paketave", + "Search for packages": "Kërko paketa", + "Local": "Lokal", + "OK": "OK", + "Last checked: {0}": "Kontrolluar për herë të fundit: {0}", + "{0} packages were found, {1} of which match the specified filters.": "U {0, plural, one {gjet {0} paketë} other {gjetën {0} paketa}}, {1, plural, one {dhe {1} përputhet} other {nga të cilat {1} përputhen}} me filtrat e specifikuar.", + "{0} selected": "{0} të përzgjedhur", + "(Last checked: {0})": "(Kontrolluar për herë të fundit në: {0})", + "All packages selected": "Të gjitha paketat u përzgjodhën", + "Package selection cleared": "Përzgjedhja e paketave u pastrua", + "{0}: {1}": "{0}: {1}", + "More info": "Më shumë informacione", + "GitHub account": "Llogaria GitHub", + "Log in with GitHub to enable cloud package backup.": "Hyr me GitHub për të aktivizuar kopjen rezervë në re të paketave.", + "More details": "Më shumë detaje", + "Log in": "Hyr", + "If you have cloud backup enabled, it will be saved as a GitHub Gist on this account": "Nëse ke aktivizuar kopjen rezervë në re, ajo do të ruhet si një GitHub Gist në këtë llogari", + "Log out": "Dil", + "About UniGetUI": "Rreth UniGetUI", + "About": "Rreth", + "Third-party licenses": "Leje të palëve të treta", + "Contributors": "Kontribuesit", + "Translators": "Përkthyesit", + "Bundle security report": "Raporti i sigurisë për koleksionin", + "The bundle contained restricted content": "Koleksioni përmbante përmbajtje të kufizuar", + "UniGetUI – Crash Report": "UniGetUI – Raporti i ndërprerjes", + "UniGetUI has crashed": "UniGetUI pësoi një ndërprerje", + "Help us fix this by sending a crash report to Devolutions. All fields below are optional.": "Na ndihmo ta rregullojmë duke dërguar një raport ndërprerjeje te Devolutions. Të gjitha fushat më poshtë janë opsionale.", + "Email (optional)": "Email (opsional)", + "your@email.com": "your@email.com", + "Additional details (optional)": "Detaje shtesë (opsionale)", + "Describe what you were doing when the crash occurred…": "Përshkruani çfarë po bënit kur ndodhi ndërprerja…", + "Crash report": "Raporti i ndërprerjes", + "Don't Send": "Mos dërgo", + "Send Report": "Dërgo raportin", + "Sending…": "Duke dërguar…", + "Unsaved changes": "Ndryshime të paruajtura", + "You have unsaved changes in the current bundle. Do you want to discard them?": "Ke ndryshime të paruajtura në koleksionin aktual. Dëshiron t'i hedhësh poshtë?", + "Discard changes": "Hidhi poshtë ndryshimet", + "Integrity violation": "Shkelje e integritetit", + "UniGetUI or some of its components are missing or corrupt. It is strongly recommended to reinstall UniGetUI to adress the situation.": "UniGetUI ose disa prej përbërësve të tij mungojnë ose janë të dëmtuar. Rekomandohet fuqishëm të riinstalohet UniGetUI për ta zgjidhur situatën.", + "• Refer to the UniGetUI Logs to get more details regarding the affected file(s)": "• Referohu te Ditarët e UniGetUI për të marrë më shumë detaje rreth skedarëve të prekur", + "• Integrity checks can be disabled from the Experimental Settings": "• Kontrollet e integritet mund të çaktivizohen nga Cilësimet Eksperimentale", + "Manage shortcuts": "Menaxho shkurtoret", + "UniGetUI has detected the following desktop shortcuts which can be removed automatically on future upgrades": "UniGetUI ka zbuluar shkurtoret të tryezës që vijojnë, të cilat mund të fshihen automatikisht gjatë përditësimeve të ardhshme.", + "Do you really want to reset this list? This action cannot be reverted.": "A je i sigurt që do të rivendosësh këtë listë? Ky veprim nuk mund të rikthehet.", + "Desktop shortcuts list": "Lista e shkurtoreve të tryezës", + "Open in explorer": "Hape në File Explorer", + "Remove from list": "Hiq nga lista", + "When new shortcuts are detected, delete them automatically instead of showing this dialog.": "Kur zbulohen shkurtore të reja, fshiji automatikisht në vend që të shfaqet ky dialog.", + "Not right now": "Jo tani", + "Missing dependency": "Mungon varësia", + "UniGetUI requires {0} to operate, but it was not found on your system.": "UniGetUI kërkon {0} për të punuar, por nuk u gjet në sistemin tënd.", + "Click on Install to begin the installation process. If you skip the installation, UniGetUI may not work as expected.": "Kliko mbi Instalo për të filluar procesin e instalimit. Nëse e anashkalon instalimin, UniGetUI mund të mos punon siç pritet.", + "Alternatively, you can also install {0} by running the following command in a Windows PowerShell prompt:": "Ndryshe, mund të instalosh {0} duke ekzekutuar komandën që vijon në një dritare Windows PowerShell:", + "Install {0}": "Instalo {0}", + "Do not show this dialog again for {0}": "Mos shfaq më këtë dialog për {0}", + "Please wait while {0} is being installed. A black window may show up. Please wait until it closes.": "Të lutem prit derisa të instalohet {0}. Mund të shfaqet një dritare e zezë (ose blu). Të lutem prit që të mbyllet.", + "{0} has been installed successfully.": "{0} u instalua me sukses.", + "Please click on \"Continue\" to continue": "Të lutem kliko \"Vazhdo\" për të vazhduar", + "Continue": "Vazhdo", + "{0} has been installed successfully. It is recommended to restart UniGetUI to finish the installation": "{0} u instalua me sukses. Këshillohet të riniset UniGetUI për ta mbaruar instalimin.", + "Restart later": "Rinis më vonë", + "An error occurred:": "Ndodhi një gabim:", + "Please see the Command-line Output or refer to the Operation History for further information about the issue.": "Të lutem shiko daljen e rreshtit të komandës ose referoju Historikut të Operacioneve për informacione të mëtejshme rreth problemit.", + "Retry as administrator": "Provo përsëri si administrator", + "Retry interactively": "Provo përsëri në mënyrë ndërvepruese", + "Retry skipping integrity checks": "Provo përsëri duke anashkaluar kontrollet e integritetit", + "Installation options": "Rregullimet e instalimit", + "Save": "Ruaj", + "UniGetUI collects anonymous usage data with the sole purpose of understanding and improving the user experience.": "UniGetUI mbledh të dhëna anonime të përdorimit me qëllim të vetëm kuptimin dhe përmirësimin e përvojës të përdoruesit.", + "More details about the shared data and how it will be processed": "Më shumë detaje rreth të dhënave të ndara dhe mënyrës se si do të përpunohen", + "Do you accept that UniGetUI collects and sends anonymous usage statistics, with the sole purpose of understanding and improving the user experience?": "A pranon që UniGetUI të mbledhë dhe të dërgojë statistika të përdorimit anonime, me qëllim të vetëm kuptimin dhe përmirësimin të përvojës së përdoruesit?", + "Decline": "Refuzo", + "No personal information is collected nor sent, and the collected data is anonimized, so it can't be back-tracked to you.": "Asnjë informacion personal nuk mblidhet as nuk dërgohet, dhe të dhënat e mbledhura janë të anonimizuara, kështu që nuk mund të gjurmohen mbrapsht te ty.", + "Navigation panel": "Paneli i navigimit", + "Operations": "Operacionet", + "Toggle operations panel": "Shfaq/fshih panelin e operacioneve", + "Bulk operations": "Operacione në masë", + "Retry failed": "Riprovo të dështuara", + "Clear successful": "Pastro të suksesshmet", + "Clear finished": "Pastro të përfunduarat", + "Cancel all": "Anulo të gjitha", + "More": "Më shumë", + "Toggle navigation panel": "Shfaq/Fshih panelin e lundrimit", + "Minimize": "Minimizo", + "Maximize": "Maksimizo", + "UniGetUI by Devolutions": "UniGetUI nga Devolutions", + "UniGetUI is an application that makes managing your software easier, by providing an all-in-one graphical interface for your command-line package managers.": "UniGetUI është një aplikacion që e bën më të lehtë menaxhimin e programeve të tua, duke ofruar një ndërfaqe grafike të plotë për menaxherët e paketave të rreshtit të komandës të tu.", + "Useful links": "Lidhje të dobishme", + "UniGetUI Homepage": "Kryefaqja e UniGetUI", + "Report an issue or submit a feature request": "Njofto një problem ose paraqit një kërkesë për veçori", + "UniGetUI Repository": "Depoja e UniGetUI", + "View GitHub Profile": "Shiko profilin GitHub", + "UniGetUI License": "Leja e UniGetUI", + "Using UniGetUI implies the acceptation of the MIT License": "Përdorimi i UniGetUI nënkupton pranimin e Lejes MIT", + "Become a translator": "Bëhu përkthyes", + "Go back": "Kthehu prapa", + "Go forward": "Shko përpara", + "Go to home page": "Shko te faqja kryesore", + "Reload page": "Ringarko faqen", + "View page on browser": "Shiko faqen në shfletues", + "The built-in browser is not supported on Linux yet.": "Shfletuesi i integruar nuk mbështetet ende në Linux.", + "Open in browser": "Hap në shfletues", + "Copy to clipboard": "Kopjo në letërmbajtëse", + "Export to a file": "Eksporto në një skedar", + "Log level:": "Niveli i ditarit:", + "Reload log": "Ngarko ditarin përsëri", + "Export log": "Eksporto ditarin", + "Text": "Tekst", + "Change how operations request administrator rights": "Ndrysho mënyrën se si operacionet kërkojnë të drejtat e administratorit", + "Restrictions on package operations": "Kufizime mbi operacionet e paketave", + "Restrictions on package managers": "Kufizime mbi menaxherët e paketave", + "Restrictions when importing package bundles": "Kufizime për importimin e koleksioneve të paketave", + "Ask for administrator privileges once for each batch of operations": "Kërko privilegje administratori një herë për secilin grup operacionesh", + "Ask only once for administrator privileges": "Pyet vetëm një herë për të drejtat e administratorit", + "Prohibit any kind of Elevation via UniGetUI Elevator or GSudo": "Ndalo çdo lloj ngritjeje të privilegjeve përmes UniGetUI Elevator ose GSudo", + "This option WILL cause issues. Any operation incapable of elevating itself WILL FAIL. Install/update/uninstall as administrator will NOT WORK.": "Ky rregullim do të shkaktojë probleme. Çdo veprim që nuk mund të ngrihet vetë me privilegje do të DËSHTOJË. Instalimi/përditësimi/çinstalimi si administrator NUK DO TË PUNOJË.", + "Allow custom command-line arguments": "Lejo argumente të personalizuara të rreshtit të komandës", + "Custom command-line arguments can change the way in which programs are installed, upgraded or uninstalled, in a way UniGetUI cannot control. Using custom command-lines can break packages. Proceed with caution.": "Argumentet e personalizuara të rreshtit të komandës mund të ndryshojnë mënyrën se si programet instalohen, përditësohen ose çinstalohen, në një mënyrë që UniGetUI nuk mund ta kontrollojë. Përdorimi i rreshtave të personalizuar të komandës mund t’i prishë paketat. Vazhdo me kujdes.", + "Ignore custom pre-install and post-install commands when importing packages from a bundle": "Lejo që të ekzekutohen komandat e personalizuara të para-instalimit dhe pas-instalimit", + "Pre and post install commands will be run before and after a package gets installed, upgraded or uninstalled. Be aware that they may break things unless used carefully": "Komandat para dhe pas instalimit do të ekzekutohen përpara dhe pas instalimit, përditësimit ose çinstalimit të një pakete. Ki parasysh që ato mund të prishin gjëra nëse nuk përdoren me kujdes", + "Allow changing the paths for package manager executables": "Mundëso ndryshimin e shtigjeve për ekzekutuesit e menaxherëve të paketave", + "Turning this on enables changing the executable file used to interact with package managers. While this allows finer-grained customization of your install processes, it may also be dangerous": "Aktivizimi i këtij rregullimi lejon ndryshimin e skedarit ekzekutues që përdoret për të ndërvepruar me menaxherët e paketave. Ndërsa kjo mundëson personalizim më të hollësishëm të proceseve të instalimit, gjithashtu mund të jetë e rrezikshme", + "Allow importing custom command-line arguments when importing packages from a bundle": "Lejo importimin e argumenteve të personalizuara të rreshtit të komandës kur importon paketa nga një koleksion", + "Malformed command-line arguments can break packages, or even allow a malicious actor to gain privileged execution. Therefore, importing custom command-line arguments is disabled by default": "Argumentet e pasakta të rreshtit të komandës mund të prishin paketat, ose madje t’i lejojnë një aktori keqdashës të marrë ekzekutimin me privilegje. Prandaj, importimi i argumenteve të personalizuara të rreshtit të komandës është i çaktivizuar si paracaktim.", + "Allow importing custom pre-install and post-install commands when importing packages from a bundle": "Mundëso importimin e komandave të personalizuara të para-instalimit dhe pas-instalimit kur importohen paketat nga një koleksion", + "Pre and post install commands can do very nasty things to your device, if designed to do so. It can be very dangerous to import the commands from a bundle, unless you trust the source of that package bundle": "Komandat para dhe pas instalimit mund të shkaktojnë dëme serioze në pajisjen tënde, nëse janë krijuar për këtë qëllim. Mund të jetë shumë e rrezikshme të importosh këto komanda nga një koleksion, përveç nëse e beson burimin e atij koleksioni paketash.", + "Administrator rights and other dangerous settings": "Të drejtat e administratorit dhe cilësimet e tjera të rrezikshme", + "Package backup": "Kopje rezervë e paketës", + "Cloud package backup": "Kopja reyervë e paketave në re", + "Local package backup": "Kopje rezervë lokale e paketës", + "Local backup advanced options": "Rregullimet e përparuara për kopjen rezervë lokale", + "Log in with GitHub": "Hyr me GitHub", + "Log out from GitHub": "Dil nga GitHub", + "Periodically perform a cloud backup of the installed packages": "Bëj periodikisht një kopje rezervë në re të paketave të instaluara", + "Cloud backup uses a private GitHub Gist to store a list of installed packages": "Kopja rezervë në re përdor një Gist privat në GitHub për të ruajtur një listë të paketave të instaluara.", + "Perform a cloud backup now": "Bëj një kopje rezervë në re tani", + "Backup": "Bëj një kopje rezervë", + "Restore a backup from the cloud": "Rikthe një kopje rezervë nga reja", + "Begin the process to select a cloud backup and review which packages to restore": "Fillo procesin për të zgjedhur një kopje rezervë në re dhe rishiko paketat që do të rikthehen.", + "Periodically perform a local backup of the installed packages": "Bëj periodikisht një kopje rezervë lokale të paketave të instaluara", + "Perform a local backup now": "Bëj një kopje rezervë lokale tani", + "Change backup output directory": "Ndrysho vendndodhjen e kopjës rezervë", + "Set a custom backup file name": "Vendos një emër skedari rezervë të personalizuar", + "Leave empty for default": "Lëre bosh për të ndjekur paracaktimin", + "Add a timestamp to the backup file names": "Shto një vulë kohore në emrat e skedarëve rezervë", + "Backup and Restore": "Kopje rezervë dhe Rikthim", + "Enable background api (UniGetUI Widgets and Sharing, port 7058)": "Aktivizo API-në e sfondit (Widgets for UniGetUI and Sharing, porta 7058)", + "Wait for the device to be connected to the internet before attempting to do tasks that require internet connectivity.": "Prit derisa pajisja të lidhet me internetin para se të përpiqesh të kryesh detyra që kërkojnë lidhje me internet.", + "Disable the 1-minute timeout for package-related operations": "Çaktivizo afatin 1 minutësh për operacionet që lidhen me paketat", + "Use installed GSudo instead of UniGetUI Elevator": "Përdor GSudo të instaluar në vend të UniGetUI Elevator", + "Use a custom icon and screenshot database URL": "Përdor një URL të bazës së të dhënave për ikona dhe pamje të ekranit të personalizuar", + "Enable background CPU Usage optimizations (see Pull Request #3278)": "Aktivizo përmirësimet e përdorimit të CPU-së në sfond (shih Pull Request #3278)", + "Perform integrity checks at startup": "Bëj kontrollet e integritet gjatë nisjes", + "When batch installing packages from a bundle, install also packages that are already installed": "Gjatë instalimit në grup të paketave nga një koleksion, instalo edhe paketat që janë tashmë të instaluara", + "Experimental settings and developer options": "Cilësimet eksperimentale dhe rregullimet për zhvilluesit", + "Show UniGetUI's version and build number on the titlebar.": "Shfaq versionin dhe numrin e ndërtimit të UniGetUI në shiritin e titullit.", + "Language": "Gjuha", + "UniGetUI updater": "Përditësuesi e UniGetUI", + "Telemetry": "Matja nga larg (Telemetria)", + "Manage UniGetUI settings": "Menaxho cilësimet e UniGetUI", + "Related settings": "Cilësimet përkatëse", + "Update UniGetUI automatically": "Përditëso automatikisht UniGetUI", + "Check for updates": "Kontrollo për përditësime", + "Install prerelease versions of UniGetUI": "Instalo versionet paraprake të UniGetUI", + "Manage telemetry settings": "Menaxho cilësimet e matjes nga larg (telemetrisë)", + "Manage": "Menaxho", + "Import settings from a local file": "Importo cilësimet nga një skedar lokal", + "Import": "Importo", + "Export settings to a local file": "Eksporto cilësimet në një skedar lokal", + "Export": "Eksporto", + "Reset UniGetUI": "Rivendos UniGetUI", + "User interface preferences": "Parapëlqimet e ndërfaqes së përdoruesit", + "Application theme, startup page, package icons, clear successful installs automatically": "Motivi i aplikacionit, faqja e nisjes, ikonat e paketave, pastrim automatik i instalimeve të suksesshme", + "General preferences": "Parapëlqime të përgjithshme", + "UniGetUI display language:": "Gjuha e UniGetUI:", + "System language": "Gjuha e sistemit", + "Is your language missing or incomplete?": "Gjuha jote mungon apo është e paplotë?", + "Appearance": "Pamja", + "UniGetUI on the background and system tray": "UniGetUI në sfond dhe në hapësirën e sistemit", + "Package lists": "Listat e paketave", + "Use classic mode": "Përdor modalitetin klasik", + "Restart UniGetUI to apply this change": "Rinis UniGetUI për të zbatuar këtë ndryshim", + "The classic UI is disabled for beta testers": "Ndërfaqja klasike e përdoruesit është çaktivizuar për testuesit beta", + "Close UniGetUI to the system tray": "Mbyll UniGetUI në hapësirën e sistemit", + "Manage UniGetUI autostart behaviour": "Menaxho sjelljen e nisjes automatike të UniGetUI", + "Show package icons on package lists": "Shfaq ikonat e paketave në listat e paketave", + "Clear cache": "Pastro kesh-in", + "Select upgradable packages by default": "Përzgjidh paketat e përditësueshme si paracaktim", + "Light": "Çelët", + "Dark": "Errët", + "Follow system color scheme": "Ndiq skemën e ngjyrave të sistemit", + "Application theme:": "Motivi i aplikacionit:", + "UniGetUI startup page:": "Faqja e nisjes së UniGetUI:", + "Proxy settings": "Cilësimet e ndërmjetësit", + "Other settings": "Cilësimet e tjera", + "Connect the internet using a custom proxy": "Lidhu me internetin duke përdorur një ndërmjetës të personalizuar", + "Please note that not all package managers may fully support this feature": "Të lutem vë re që jo të gjithë menaxherët e paketave mund ta mbështesin plotësisht këtë veçori", + "Proxy URL": "URL-ja e ndërmjetësit", + "Enter proxy URL here": "Shkruaj këtu URL-në e ndërmjetësit", + "Authenticate to the proxy with a user and a password": "Autentifikohu te ndërmjetësi me emër përdoruesi dhe fjalëkalim", + "Internet and proxy settings": "Cilësimet e internetit dhe të ndërmjetësit", + "Package manager preferences": "Parapëlqimet e menaxherit të paketave", + "Ready": "Gati", + "Not found": "Nuk u gjet", + "Notification preferences": "Parapëlqimet e njoftimit", + "Notification types": "Llojet e njoftimeve", + "The system tray icon must be enabled in order for notifications to work": "Ikona e hapësirës së sistemit duhet të jetë aktivizuar që njoftimet të funksionojnë", + "Enable UniGetUI notifications": "Aktivizo njoftimet e UniGetUI", + "Show a notification when there are available updates": "Shfaq një njoftim kur ofrohen përditësime", + "Show a silent notification when an operation is running": "Shfaq një njoftim të heshtur kur një operacion po ekzekutohet", + "Show a notification when an operation fails": "Shfaq një njoftim kur një operacion dështon", + "Show a notification when an operation finishes successfully": "Shfaq një njoftim kur një operacion përfundon me sukses", + "Concurrency and execution": "Njëkohshmëria dhe ekzekutimi", + "Automatic desktop shortcut remover": "Heqës automatik i shkurtoreve të tryezës", + "Choose how many operations should be performed in parallel": "Zgjidh sa operacione duhet të kryhen paralelisht", + "Clear successful operations from the operation list after a 5 second delay": "Pastro operacionet e suksesshme nga lista e operacioneve pas një vonese prej 5 sekondash", + "Download operations are not affected by this setting": "Operacionet e shkarkimit nuk preken nga ky cilësim", + "You may lose unsaved data": "Mund të humbasësh të dhënat e pa ruajtura.", + "Ask to delete desktop shortcuts created during an install or upgrade.": "Kërko të fshihen shkurtoret e tryezës të krijuara gjatë një instalimi ose përditësimi.", + "Package update preferences": "Parapëlqimet e përditësimit të paketave", + "Update check frequency, automatically install updates, etc.": "Shpeshtësia e kontrollit për përditësime, instalimi automatik i përditësimeve, etj.", + "Reduce UAC prompts, elevate installations by default, unlock certain dangerous features, etc.": "Ul paralajmërimet e UAC, ngri instalimet si paracaktim, zhblloko disa veçori të rrezikshme, etj.", + "Package operation preferences": "Parapëlqimet e operacioneve të paketave", + "Enable {pm}": "Aktivizo {pm}", + "Not finding the file you are looking for? Make sure it has been added to path.": "Nuk po gjen skedarin që po kërkon? Sigurohu që është shtuar në shteg.", + "Select the executable to be used. The following list shows the executables found by UniGetUI": "Zgjidh ekzekutuesin që do të përdoret. Lista e mëposhtme tregon ekzekutuesit që janë gjetur nga UniGetUI", + "For security reasons, changing the executable file is disabled by default": "Për arsye sigurie, ndryshimi i skedarit të ekzekutimit është i çaktivizuar si paracaktim", + "Change this": "Ndryshoje", + "Copy path": "Kopjo shtegun", + "Current executable file:": "Skedari ekzekutues i tanishëm:", + "Ignore packages from {pm} when showing a notification about updates": "Shpërfill paketat nga {pm} kur shfaqet një njoftim për përditësime", + "Update security": "Siguria e përditësimeve", + "Use global setting": "Përdor cilësimin global", + "Minimum age for updates": "Mosha minimale për përditësimet", + "e.g. 10": "p.sh. 10", + "Custom minimum age (days)": "Moshë minimale e personalizuar (ditë)", + "{pm} does not provide release dates for its packages, so this setting will have no effect": "{pm} nuk jep data publikimi për paketat e veta, ndaj ky cilësim nuk do të ketë asnjë efekt", + "{pm} only provides release dates for some of its packages, so this setting will only apply to those packages": "{pm} jep data publikimi vetëm për disa nga paketat e tij, prandaj ky cilësim do të zbatohet vetëm për ato paketa", + "Override the global minimum update age for this package manager": "Anashkalo moshën minimale globale të përditësimeve për këtë menaxher paketash", + "View {0} logs": "Shfaq ditarin e {0}", + "If Python cannot be found or is not listing packages but is installed on the system, ": "Nëse Python nuk gjendet ose nuk i liston paketat, por është i instaluar në sistem, ", + "Advanced options": "Rregullimet e përparuara", + "WinGet command-line tool": "Mjet i linjës së komandës WinGet", + "Choose which command-line tool UniGetUI uses for WinGet operations when the COM API is not used": "Zgjidh se cilin mjet të rreshtit të komandës përdor UniGetUI për operacionet e WinGet kur COM API nuk përdoret", + "WinGet COM API": "API COM e WinGet", + "Choose whether UniGetUI can use the WinGet COM API before falling back to the command-line tool": "Zgjidh nëse UniGetUI mund të përdorë WinGet COM API para se të kalojë te mjeti i rreshtit të komandës", + "Reset WinGet": "Rivendos WinGet", + "This may help if no packages are listed": "Kjo mund të ndihmojë nëse nuk ka paketa në listë", + "Force install location parameter when updating packages with custom locations": "Detyro parametrin e vendndodhjes së instalimit kur përditëson paketat me vendndodhje të personalizuara", + "Install Scoop": "Instalo Scoop", + "Uninstall Scoop (and its packages)": "Çinstalo Scoop (dhe paketat e tija)", + "Run cleanup and clear cache": "Bëj pastrimin dhe pastro keshin", + "Run": "Ekzekuto", + "Enable Scoop cleanup on launch": "Aktivizo pastrimin e Scoop në nisje", + "Default vcpkg triplet": "Treshja vcpkg e paracaktuar", + "Change vcpkg root location": "Ndrysho vendndodhjen rrënjësore të vcpkg", + "Reset vcpkg root location": "Rivendos vendndodhjen rrënjësore të vcpkg", + "Open vcpkg root location": "Hap vendndodhjen rrënjësore të vcpkg", + "Language, theme and other miscellaneous preferences": "Gjuha, motivi dhe parapëlqime të tjera të ndryshme", + "Show notifications on different events": "Shfaq njoftimet për ngjarje të ndryshme", + "Change how UniGetUI checks and installs available updates for your packages": "Ndrysho mënyrën se si UniGetUI kontrollon dhe instalon përditësimet e ofruara për paketat e tua", + "Automatically save a list of all your installed packages to easily restore them.": "Ruaj automatikisht një listë të të gjitha paketave të tua të instaluara për t'i rikthyer ato lehtësisht.", + "Enable and disable package managers, change default install options, etc.": "Aktivizo dhe çaktivizo menaxherët e paketave, ndrysho rregullimet e paracaktuara të instalimit, etj.", + "Internet connection settings": "Cilësimet e lidhjes së Internetit", + "Proxy settings, etc.": "Cilësimet e ndërmjetësit, etj.", + "Beta features and other options that shouldn't be touched": "Veçoritë për testim dhe rregullime të tjera që nuk duhen prekur", + "Reload sources": "Ringarko burimet", + "Delete source": "Fshi burimin", + "Known sources": "Burimet e njohura", + "Update checking": "Kontrollimi i përditësimeve", + "Automatic updates": "Përditësimet automatike", + "Check for package updates periodically": "Kontrollo periodikisht për përditësime të paketave", + "Check for updates every:": "Kontrollo për përditësime çdo:", + "Install available updates automatically": "Instalo automatikisht përditësimet e ofruara", + "Do not automatically install updates when the network connection is metered": "Mos i instalo automatikisht përditësimet kur lidhja e rrjetit është me kufizime të dozës", + "Do not automatically install updates when the device runs on battery": "Mos instalo automatikisht përditësime kur pajisja punon me bateri", + "Do not automatically install updates when the battery saver is on": "Mos i instalo automatikisht përditësimet kur kursyesi i baterisë është aktiv", + "Only show updates that are at least the specified number of days old": "Shfaq vetëm përditësime që janë të paktën aq ditë të vjetra sa numri i caktuar", + "Warn me when the installer URL host changes between the installed version and the new version (WinGet only)": "Më paralajmëro kur hosti i URL-së së instaluesit ndryshon mes versionit të instaluar dhe versionit të ri (vetëm WinGet)", + "Change how UniGetUI handles install, update and uninstall operations.": "Ndrysho mënyrën se si UniGetUI trajton operacionet e instalimit, përditësimit dhe çinstalimit.", + "Navigation": "Navigimi", + "Check for UniGetUI updates": "Kontrollo për përditësime të UniGetUI", + "Quit UniGetUI": "Dil nga UniGetUI", + "Filters": "Filtrat", + "Sources": "Burimet", + "Search for packages to start": "Për të nisur kërko për paketa", + "Select all": "Përzgjidh të gjitha", + "Clear selection": "Pastro përzgjedhjet", + "Instant search": "Kërkim i menjëhershëm", + "Distinguish between uppercase and lowercase": "Dallo midis shkronjave të mëdhaja dhe të vogla", + "Ignore special characters": "Shpërfill shkronjat e veçanta", + "Search mode": "Mënyra e kërkimit", + "Both": "Të dyja", + "Exact match": "Përputhje e saktë", + "Show similar packages": "Shfaq paketa të ngjashme", + "Loading": "Po ngarkohet", + "Package": "Paketë", + "More options": "Më shumë opsione", + "Order by:": "Rëndit sipas:", + "Name": "Emri", + "Id": "ID-ja", + "Ascendant": "Renditje ngjitëse", + "Descendant": "Renditje zbritëse", + "View modes": "Modalitetet e shfaqjes", + "Reload": "Ringarko", + "Closed": "Mbyllur", + "Ascending": "Rritës", + "Descending": "Zbritës", + "{0}: {1}, {2}": "{0}: {1}, {2}", + "Order by": "Rendit sipas", + "No results were found matching the input criteria": "Nuk u gjet asnjë rezultat që përputhet me kriteret hyrëse", + "No packages were found": "Nuk u gjet asnjë paketë", + "Loading packages": "Po ngarkohen paketat", + "Skip integrity checks": "Kapërce kontrollet e integritetit", + "Download selected installers": "Shkarko instaluesit e përzgjedhur", + "Install selection": "Instalo përzgjedhjet", + "Install options": "Rregullimet e instalimit", + "Add selection to bundle": "Shto përzgjedhjet në koleksion", + "Download installer": "Shkarko instaluesin", + "Uninstall selection": "Çinstalo përzgjedhjet", + "Uninstall options": "Rregullimet e çinstalimit", + "Ignore selected packages": "Shpërfill paketat e përzgjedhura", + "Open install location": "Hap vendndodhjen e instalimit", + "Reinstall package": "Instalo paketën përeseri", + "Uninstall package, then reinstall it": "Çinstalo paketën, më pas instaloje përsëri", + "Ignore updates for this package": "Shpërfill përditësimet për këtë paketë", + "WinGet malfunction detected": "U zbulua një gabim i WinGet", + "It looks like WinGet is not working properly. Do you want to attempt to repair WinGet?": "Duket sikur WinGet nuk po punon siç duhet. Dëshiron të përpiqesh të rregullosh WinGet?", + "Repair WinGet": "Rregullo WinGet", + "Updates will no longer be ignored for {0}": "Përditësimet nuk do të shpërfillen më për {0}", + "Updates are now ignored for {0}": "Përditësimet tani shpërfillen për {0}", + "Do not ignore updates for this package anymore": "Mos shpërfill përditësimet për këtë paketë", + "Add packages or open an existing package bundle": "Shto paketa ose hap një koleksion paketash ekzistues", + "Add packages to start": "Shto paketa për të filluar", + "The current bundle has no packages. Add some packages to get started": "Koleksioni i tanishëm nuk ka paketa. Shto disa paketa për të filluar", + "New": "I ri", + "Save as": "Ruaj si", + "Create .ps1 script": "Krijo një skript .ps1", + "Remove selection from bundle": "Hiq përzgjedhjet nga koleksioni", + "Skip hash checks": "Kapërce kontrollet e hash-it", + "The package bundle is not valid": "Koleksioni i paketave është i pavlefshëm", + "The bundle you are trying to load appears to be invalid. Please check the file and try again.": "Koleksioni që po përpiqesh të ngarkosh duket i pavlefshëm. Të lutem kontrollo skedarin dhe provo përsëri.", + "Package bundle": "Koleksion i paketave", + "Could not create bundle": "Nuk mund të krijohej koleksioni i paketave", + "The package bundle could not be created due to an error.": "Koleksioni i paketave nuk mund të krijohej për shkak të një gabimi.", + "Install script": "Skripti i instalimit", + "PowerShell script": "Skript PowerShell", + "The installation script saved to {0}": "Skripti i instalimit u ruajt në {0}", + "An error occurred": "Ndodhi një gabim", + "An error occurred while attempting to create an installation script:": "Ndodhi një gabim gjatë përpjekjes për të krijuar një skript instalimi:", + "Hooray! No updates were found.": "Ec aty! Nuk u gjetën përditësime.", + "Uninstall selected packages": "Çinstalo paketat e përzgjedhura", + "Update selection": "Përditëso përzgjedhjet", + "Update options": "Rregullimet e përditësimit", + "Uninstall package, then update it": "Çinstalo paketën, më pas përditësoje", + "Uninstall package": "Çinstalo paketën", + "Skip this version": "Kapërce këtë version", + "Pause updates for": "Pezullo përditësimet për", + "User | Local": "Përdorues | Lokal", + "Machine | Global": "Kompjuter | Global", + "The default package manager for Debian/Ubuntu-based Linux distributions.
Contains: Debian/Ubuntu packages": "Menaxheri i parazgjedhur i paketave për shpërndarjet Linux me bazë Debian/Ubuntu.
Përmban: paketa Debian/Ubuntu", + "The Rust package manager.
Contains: Rust libraries and programs written in Rust": "Menaxheri i paketave Rust.
Përmban: Libraritë dhe programet Rust të shkruara në Rust", + "The classical package manager for windows. You'll find everything there.
Contains: General Software": "Menaxheri klasik i paketave për Windows. Do të gjesh gjithçka atje.
Përmban: Programe të përgjithshme", + "The default package manager for RHEL/Fedora-based Linux distributions.
Contains: RPM packages": "Menaxheri i parazgjedhur i paketave për shpërndarjet Linux me bazë RHEL/Fedora.
Përmban: paketa RPM", + "A repository full of tools and executables designed with Microsoft's .NET ecosystem in mind.
Contains: .NET related tools and scripts": "Një depo plot me vegla dhe programe ekzekutuese të krijuar duke pasur parasysh ekosistemin .NET të Microsoft-it.
Përmban: vegla dhe skripte të lidhura me .NET", + "The universal Linux package manager for desktop applications.
Contains: Flatpak applications from configured remotes": "Menaxheri universal i paketave Linux për aplikacionet e desktopit.
Përmban: aplikacione Flatpak nga burimet e konfiguruara në distancë", + "NuPkg (zipped manifest)": "NuPkg (manifest i kompresuar)", + "The Missing Package Manager for macOS (or Linux).
Contains: Formulae, Casks": "Menaxheri i munguar i paketave për macOS (ose Linux).
Përmban: Formulae, Casks", + "Node JS's package manager. Full of libraries and other utilities that orbit the javascript world
Contains: Node javascript libraries and other related utilities": "Menaxheri i paketave të Node JS-it. Plot me librari dhe shërbime të tjera që kanë të bëjnë me botën e javascript-it
Përmban: Libraritë Node javascript dhe shërbime të tjera të lidhura me to", + "The default package manager for Arch Linux and its derivatives.
Contains: Arch Linux packages": "Menaxheri i parazgjedhur i paketave për Arch Linux dhe derivatet e tij.
Përmban: paketa Arch Linux", + "Python's library manager. Full of python libraries and other python-related utilities
Contains: Python libraries and related utilities": "Menaxheri i librarisë të Python-it. Plot me librari python dhe shërbime të tjera të lidhura me Python-in
Përmban: Librari të Python-it dhe shërbime të ngjashme", + "PowerShell's package manager. Find libraries and scripts to expand PowerShell capabilities
Contains: Modules, Scripts, Cmdlets": "Menaxheri i paketave të PowerShell-it. Gjen librari dhe skripta për të zgjeruar aftësitë e PowerShell-it
Përmban: Module, Skripta, Cmdlet-a", + "extracted": "nxjerrë", + "Scoop package": "Paketë Scoop", + "Great repository of unknown but useful utilities and other interesting packages.
Contains: Utilities, Command-line programs, General Software (extras bucket required)": "Depo e shkëlqyeshme me shërbime të panjohura por të dobishme dhe paketa të tjera interesante.
Përmban: Shërbime, Programe të rreshtit së komandës, Programe të përgjithshme (kërkohet kova e shtesave)", + "The universal Linux package manager by Canonical.
Contains: Snap packages from the Snapcraft store": "Menaxheri universal i paketave Linux nga Canonical.
Përmban: paketa Snap nga dyqani Snapcraft", + "library": "librari", + "feature": "veçori", + "A popular C/C++ library manager. Full of C/C++ libraries and other C/C++-related utilities
Contains: C/C++ libraries and related utilities": "Një menaxher i njohur i librarisë C/C++. Plot me librari C/C++ dhe shërbime të tjera të lidhura me C/C++
Përmban: librari C/C++ dhe shërbime të ngjashme", + "option": "rregullim", + "This package cannot be installed from an elevated context.": "Kjo paketë nuk mund të instalohet me privilegje të ngritura.", + "Please run UniGetUI as a regular user and try again.": "Të lutem hap UniGetUI si përdorues i zakonshëm dhe provo përsëri.", + "Please check the installation options for this package and try again": "Kontrollo rregullimet e instalimit për këtë paketë dhe provo përsëri.", + "Microsoft's official package manager. Full of well-known and verified packages
Contains: General Software, Microsoft Store apps": "Menaxheri zyrtar i paketave të Microsoft. Plot me paketa të njohura dhe të verifikuara
Përmban: Programe të përgjithshme, aplikacione të Microsoft Store", + "Local PC": "Kompjuteri lokal", + "Android Subsystem": "Nënsistemi Android", + "Operation on queue (position {0})...": "Operacion në radhë (vendi {0})...", + "Click here for more details": "Kliko këtu për më shumë detaje", + "Operation canceled by user": "Operacioni u anulua nga përdoruesi", + "Running PreOperation ({0}/{1})...": "Po ekzekutohet PreOperation ({0}/{1})...", + "PreOperation {0} out of {1} failed, and was tagged as necessary. Aborting...": "PreOperation {0} nga {1} dështoi dhe ishte shënuar si i nevojshëm. Po ndërpritet...", + "PreOperation {0} out of {1} finished with result {2}": "PreOperation {0} nga {1} përfundoi me rezultatin {2}", + "Starting operation...": "Duke nisur operacionin...", + "Running PostOperation ({0}/{1})...": "Po ekzekutohet PostOperation ({0}/{1})...", + "PostOperation {0} out of {1} failed, and was tagged as necessary. Aborting...": "PostOperation {0} nga {1} dështoi dhe ishte shënuar si i nevojshëm. Po ndërpritet...", + "PostOperation {0} out of {1} finished with result {2}": "PostOperation {0} nga {1} përfundoi me rezultatin {2}", + "{package} installer download": "Shkarkim i instaluesit të {package}", + "{0} installer is being downloaded": "Instaluesi i {0} po shkarkohet", + "Download succeeded": "Shkarkimi pati sukses", + "{package} installer was downloaded successfully": "Instaluesi i {package} u shkarkua me sukses", + "Download failed": "Shkarkimi dështoi", + "{package} installer could not be downloaded": "Instaluesi i {package} nuk mund të shkarkohej", + "{package} Installation": "{package} Instalim", + "{0} is being installed": "{0} po instalohet", + "Installation succeeded": "Instalimi pati sukses", + "{package} was installed successfully": "{package} u instalua me sukses", + "Installation failed": "Instalimi dështoi", + "{package} could not be installed": "{package} nuk mund të instalohej", + "{package} Update": "Përditësim i {package}", + "Update succeeded": "Përditësimi pati sukses", + "{package} was updated successfully": "{package} u përditësua me sukses", + "Update failed": "Përditësimi dështoi", + "{package} could not be updated": "{package} nuk mund të përditësohej", + "{package} Uninstall": "{package} Çinstalim", + "{0} is being uninstalled": "{0} po çinstalohet", + "Uninstall succeeded": "Çinstalimi pati sukses", + "{package} was uninstalled successfully": "{package} u çinstalua me sukses", + "Uninstall failed": "Çinstalimi dështoi", + "{package} could not be uninstalled": "{package} nuk mund të çinstalohej", + "Adding source {source}": "Duke shtuar burimin {source}", + "Adding source {source} to {manager}": "Shto burimin {source} në {manager}", + "Source added successfully": "Burimi u shtua me sukses", + "The source {source} was added to {manager} successfully": "Burimi {source} u shtua te {manager} me sukses", + "Could not add source": "Nuk mund të shtohet burimi", + "Could not add source {source} to {manager}": "Nuk mund të shtohej burimi {source} në {manager}", + "Removing source {source}": "Duke hequr burimin {source}", + "Removing source {source} from {manager}": "Po hiqet burimi {source} nga {manager}", + "Source removed successfully": "Burimi u hoq me sukses", + "The source {source} was removed from {manager} successfully": "Burimi {source} u hoq nga {manager} me sukses", + "Could not remove source": "Nuk mund të hiqet burimi", + "Could not remove source {source} from {manager}": "Burimi {source} nuk mund të hiqej nga {manager}", + "The package manager \"{0}\" was not found": "Menaxheri i paketave \"{0}\" nuk u gjet", + "The package manager \"{0}\" is disabled": "Menaxheri i paketave \"{0}\" është i çaktivizuar", + "There is an error with the configuration of the package manager \"{0}\"": "Ka një gabim me konfigurimin e menaxherit të paketave \"{0}\"", + "The package \"{0}\" was not found on the package manager \"{1}\"": "Paketa \"{0}\" nuk u gjet në menaxherin e paketave \"{1}\"", + "{0} is disabled": "{0} është çaktivizuar", + "{0} weeks": "{0} javë", + "1 month": "1 muaj", + "{0} months": "{0} muaj", + "Something went wrong": "Diçka shkoi keq", + "An interal error occurred. Please view the log for further details.": "Ndodhi një gabim i brendshëm. Të lutem shiko ditarin për detaje të mëtejshme.", + "No applicable installer was found for the package {0}": "Nuk u gjet asnjë instalues i përshtatshëm për paketën {0}", + "Integrity checks will not be performed during this operation": "Kontrollet e integritetit nuk do të kryhen gjatë këtij operacioni", + "This is not recommended.": "Nuk këshillohet.", + "Run now": "Ekzekuto tani", + "Run next": "Ekzekuto pas operacionit të tanishëm", + "Run last": "Ekzekuto në fund", + "Show in explorer": "Shfaq në Eksploruesin", + "Checked": "I zgjedhur", + "Unchecked": "I pazgjedhur", + "This package is already installed": "Kjo paketë është instaluar tashmë", + "This package can be upgraded to version {0}": "Kjo paketë mund të përditësohet në versionin {0}", + "Updates for this package are ignored": "Përditësimet për këtë paketë do të shpërfillen", + "This package is being processed": "Kjo paketë është duke u përpunuar", + "This package is not available": "Kjo paketë nuk ofrohet", + "Select the source you want to add:": "Përzgjidh burimin që do të shtosh:", + "Source name:": "Emri i burimit:", + "Source URL:": "URL-ja e burimit:", + "An error occurred when adding the source: ": "Ndodhi një gabim gjatë shtimit të burimit:", + "Package management made easy": "Menaxhimi i paketave i lehtësuar", + "version {0}": "versioni {0}", + "[RAN AS ADMINISTRATOR]": "EKZEKUTUAR SI ADMINISTRATOR", + "Portable mode": "Mënyra portative", + "DEBUG BUILD": "KONSTRUKT PËR KORRIGJIM", + "Here you can change UniGetUI's behaviour regarding the following shortcuts. Checking a shortcut will make UniGetUI delete it if if gets created on a future upgrade. Unchecking it will keep the shortcut intact": "Këtu mund të ndryshosh sjelljen e UniGetUI në lidhje me shkurtoret që vijojnë. Duke përzgjedhur një shkurtore, UniGetUI do ta fshijë atë nëse krijohet gjatë një përditësimi të ardhshëm. Nëse e heq përzgjedhjen, shkurtesa do të mbetet e pandryshuar", + "Manual scan": "Skanim manual", + "Existing shortcuts on your desktop will be scanned, and you will need to pick which ones to keep and which ones to remove.": "Shkurtoret ekzistuese në tryezën tënde do të skanohen, dhe do të duhet të zgjedhësh se cilat do mbash dhe cilat do fshish.", + "Delete?": "Do të fshish?", + "I understand": "Kuptoj", + "Chocolatey setup changed": "Konfigurimi i Chocolatey ndryshoi", + "UniGetUI no longer includes its own private Chocolatey installation. A legacy UniGetUI-managed Chocolatey installation was detected for this user profile, but system Chocolatey was not found. Chocolatey will stay unavailable in UniGetUI until Chocolatey is installed on the system and UniGetUI is restarted. Applications previously installed through UniGetUI's bundled Chocolatey may still appear under other sources such as Local PC or WinGet.": "UniGetUI nuk përfshin më instalimin e vet privat të Chocolatey. Një instalim i vjetër i Chocolatey i menaxhuar nga UniGetUI u zbulua për këtë profil përdoruesi, por Chocolatey i sistemit nuk u gjet. Chocolatey do të mbetet i padisponueshëm në UniGetUI derisa Chocolatey të instalohet në sistem dhe UniGetUI të riniset. Aplikacionet e instaluara më parë përmes Chocolatey të integruar në UniGetUI mund të shfaqen ende nën burime të tjera si PC Lokale ose WinGet.", + "NOTE: This troubleshooter can be disabled from UniGetUI Settings, on the WinGet section": "SHËNIM: Ky zgjidhës i problemeve mund të çaktivizohet nga Cilësimet UniGetUI, në seksionin WinGet", + "Restart": "Rinis", + "Are you sure you want to delete all shortcuts?": "A je i sigurt që do të fshish të gjitha shkurtoret?", + "Any new shorcuts created during an install or an update operation will be deleted automatically, instead of showing a confirmation prompt the first time they are detected.": "Çdo shkurtore e re e krijuar gjatë një instalimi ose përditësimi do të fshihet automatikisht, në vend se të shfaqet një dritare konfirmimi herën e parë kur zbulohet.", + "Any shorcuts created or modified outside of UniGetUI will be ignored. You will be able to add them via the {0} button.": "Çdo shkurtore e krijuar ose modifikuar jashtë UniGetUI do të shpërfillet. Do mund t'i shtosh ato përmes butonit {0}", + "Are you really sure you want to enable this feature?": "A je i sigurt që do të aktivizosh këtë veçori?", + "No new shortcuts were found during the scan.": "Nuk u gjetën shkurtore të reja gjatë skanimit.", + "How to add packages to a bundle": "Si të shtosh paketa në një koleksion", + "In order to add packages to a bundle, you will need to: ": "Për të shtuar paketa në një koleksion, do të duhet të:", + "1. Navigate to the \"{0}\" or \"{1}\" page.": "1. Shkosh në faqen \"{0}\" ose \"{1}\".", + "2. Locate the package(s) you want to add to the bundle, and select their leftmost checkbox.": "2. Gjesh paketën që dëshiron të shtosh në koleksion, dhe të përzgjidhësh kutinë e zgjedhjes më të majtë.", + "3. When the packages you want to add to the bundle are selected, find and click the option \"{0}\" on the toolbar.": "3. Kur paketata që dëshiron të shtosh në koleksion janë të përzgjedhura, gjej dhe kliko rregullimin \"{0}\" në shiritin e veglave.", + "4. Your packages will have been added to the bundle. You can continue adding packages, or export the bundle.": "4. Paketat e tua do të jenë shtuar në koleksion. Mund të vazhdosh të shtosh paketa ose të eksportosh koleksionin.", + "Which backup do you want to open?": "Cilën kopje rezervë dëshiron të hapësh?", + "Select the backup you want to open. Later, you will be able to review which packages you want to install.": "Zgjidh kopjen rezervë që dëshiron të hapësh. Më vonë, do të mund të rishikosh cilat paketa/programe dëshiron të rikthesh.", + "There are ongoing operations. Quitting UniGetUI may cause them to fail. Do you want to continue?": "Ka operacione në vazhdim. Mbyllja e UniGetUI mund të shkaktojë deshtimin e tyre. Do të vazhdosh?", + "UniGetUI or some of its components are missing or corrupt.": "UniGetUI ose disa nga përbërësit e tij mungojnë ose janë të dëmtuar.", + "It is strongly recommended to reinstall UniGetUI to adress the situation.": "Rekomandohet me ngulm të instalosh përsëri UniGetUI për të zgjidhur situatën.", + "Refer to the UniGetUI Logs to get more details regarding the affected file(s)": "Referohu te Ditarët e UniGetUI për të marrë më shumë detaje rreth skedarëve të prekur", + "Integrity checks can be disabled from the Experimental Settings": "Kontrollet e integritet mund të çaktivizohen nga Cilësimet Eksperimentale", + "Repair UniGetUI": "Ndreq UniGetUI", + "Live output": "Dalja e drejtpërdrejtë", + "This package bundle had some settings that are potentially dangerous, and may be ignored by default.": "Ky koleksion paketash kishte disa cilësime që mund të jenë të rrezikshme dhe mund të injorohen si paracaktim.", + "Entries that show in YELLOW will be IGNORED.": "Shënimet që shfaqen me të VERDHË do të ANASHKALOHEN.", + "Entries that show in RED will be IMPORTED.": "Shënimet që shfaqen me të KUQE do të IMPORTOHEN.", + "You can change this behavior on UniGetUI security settings.": "Mund ta ndryshosh këtë sjellje te cilësimet e sigurisë së UniGetUI.", + "Open UniGetUI security settings": "Hap cilësimet e sigurisë të UniGetUI", + "Should you modify the security settings, you will need to open the bundle again for the changes to take effect.": "Nëse modifikon cilësimet e sigurisë, do të duhet të hapësh përsëri koleksionin që ndryshimet të hyjnë në fuqi.", + "Details of the report:": "Detajet e raportit:", + "Are you sure you want to create a new package bundle? ": "Je i sigurt që do të krijosh një koleksion paketash të ri?", + "Any unsaved changes will be lost": "Çdo ndryshim i paruajtur do të humbet", + "Warning!": "Paralajmërim!", + "For security reasons, custom command-line arguments are disabled by default. Go to UniGetUI security settings to change this. ": "Për arsye sigurie, argumentet e personalizuara të rreshtit të komandës janë të çaktivizuara si paracaktim. Shko te cilësimet e sigurisë të UniGetUI për ta ndryshuar këtë.", + "Change default options": "Ndrysho rregullimet e paracaktuara", + "Ignore future updates for this package": "Shpërfill përditësimet e ardhshme për këtë paketë", + "For security reasons, pre-operation and post-operation scripts are disabled by default. Go to UniGetUI security settings to change this. ": "Për arsye sigurie, skriptet para dhe pas operacionit janë të çaktivizuara si paracaktim. Shko te cilësimet e sigurisë të UniGetUI për ta ndryshuar këtë.", + "You can define the commands that will be run before or after this package is installed, updated or uninstalled. They will be run on a command prompt, so CMD scripts will work here.": "Mund të përcaktosh komandat që do të ekzekutohen para ose pas instalimit, përditësimit ose çinstalimit të kësaj pakete. Ato do të ekzekutohen në një dritare komandash, kështu që skriptet CMD do të funksionojnë këtu.", + "Change this and unlock": "Ndryshoje dhe zhblloko", + "{0} Install options are currently locked because {0} follows the default install options.": "Rregullimet e instalimit të {0} janë të bllokuara për momentin sepse {0} ndjek rregullimet e paracaktuara të instalimit.", + "Unset or unknown": "I papërcaktuar ose i panjohur", + "This package has no screenshots or is missing the icon? Contrbute to UniGetUI by adding the missing icons and screenshots to our open, public database.": "Kjo paketë nuk ka pamje nga ekrani apo i mungon ikona? Kontribuo në UniGetUI duke shtuar ikonat dhe pamjet e ekranit që mungojnë në bazën tonë të të dhënave të hapur publike.", + "Become a contributor": "Bëhu kontribuues", + "Update to {0} available": "Ofrohet përditësim për {0}", + "Reinstall": "Instalo përsëri", + "Installer not available": "Instaluesi nuk ofrohet", + "Version:": "Versioni:", + "UniGetUI Version {0}": "Versioni {0} i UniGetUI", + "Performing backup, please wait...": "Po kryhet rezervimi, të lutem prit...", + "An error occurred while logging in: ": "Ndodhi një gabim gjatë hyrjes:", + "Fetching available backups...": "Po merren kopjet rezervë…", + "Done!": "U krye!", + "The cloud backup has been loaded successfully.": "Kopja rezervë në re u ngarkua me sukses.", + "An error occurred while loading a backup: ": "Ndodhi një gabim gjatë ngarkimit të kopjes rezervë:", + "Backing up packages to GitHub Gist...": "Po bëhet kopje rezervë e paketave në GitHub Gist…", + "Backup Successful": "Kopja rezervë u krijua me sukses.", + "The cloud backup completed successfully.": "Kopja rezervë në re u përfundua me sukses.", + "Could not back up packages to GitHub Gist: ": "Nuk mund të bëhej kopje rezervë e paketave në GitHub Gist:", + "It is not guaranteed that the provided credentials will be stored safely, so you may as well not use the credentials of your bank account": "Nuk është e garantuar që kredencialet do të ruhen në mënyrë të sigurt, prandaj mund të shmangësh përdorimin e kredencialeve të llogarisë tënde bankare", + "Enable the automatic WinGet troubleshooter": "Akitvizo zgjidhësin automatik të problemeve të WinGet-it", + "Add updates that fail with a 'no applicable update found' to the ignored updates list": "Shto përditësimet që dështojnë me 'nuk u gjet përditësim i përshtatshëm' në listën e përditësimeve të shpërfillura.", + "Invalid selection": "Përzgjedhje e pavlefshme", + "No package was selected": "Nuk është përzgjedhur asnjë paketë", + "More than 1 package was selected": "Është përzgjedhur më shumë se një paketë", + "List": "Listë", + "Grid": "Rrjetë", + "Icons": "Ikona", + "\"{0}\" is a local package and does not have available details": "\"{0}\" është një paketë lokale dhe nuk ofrohen detaje", + "\"{0}\" is a local package and is not compatible with this feature": "\"{0}\" është një paketë lokale dhe nuk është e përputhshme me këtë veçori", + "Add packages to bundle": "Shto paketa në koleksion", + "Preparing packages, please wait...": "Po përgatiten paketat, të lutem prit...", + "Loading packages, please wait...": "Po ngarkohen paketat, të lutem prit...", + "Saving packages, please wait...": "Po ruhen paketat, të lutem prit...", + "The bundle was created successfully on {0}": "Koleksioni u krijua me sukses më {0}", + "User profile": "Profili i përdoruesit", + "Error": "Gabim", + "Log in failed: ": "Hyrja dështoi:", + "Log out failed: ": "Dalja dështoi:", + "Package backup settings": "Cilësimet e kopjes rezervë të paketës", + "Package managers": "Menaxherët e paketave", + "Manage UniGetUI autostart behaviour from the Settings app": "Menaxho sjelljen e nisjes automatike të UniGetUI", + "Choose how many operations shoulds be performed in parallel": "Zgjidh sa operacione duhet të kryhen paralelisht", + "Something went wrong while launching the updater.": "Diçka shkoi gabim gjatë nisjes së përditësuesit.", + "Please try again later": "Të lutem provo përsëri më vonë", + "Show the release notes after UniGetUI is updated": "Shfaq shënimet e botimit pasi UniGetUI të jetë përditësuar" +} diff --git a/src/Languages/lang_sr.json b/src/Languages/lang_sr.json new file mode 100644 index 0000000..e9d57a5 --- /dev/null +++ b/src/Languages/lang_sr.json @@ -0,0 +1,851 @@ +{ + "{0} of {1} operations completed": "Завршено {0} од {1} операција", + "{0} is now {1}": "{0} је сада {1}", + "Enabled": "Омогућено", + "Disabled": "Онемогућено", + "Privacy": "Приватност", + "Hide my username from the logs": "Сакриј моје корисничко име из записа", + "Replaces your username with **** in the logs. Restart UniGetUI to also hide it from already-recorded entries.": "Замењује ваше корисничко име са **** у записима. Поново покрените UniGetUI да бисте га сакрили и из већ забележених уноса.", + "Your last update attempt did not complete.": "Последњи покушај ажурирања није довршен.", + "UniGetUI could not confirm whether the update succeeded. Open the log to see what happened.": "UniGetUI није могао да потврди да ли је ажурирање успело. Отвори евиденцију да видиш шта се догодило.", + "View log": "Прикажи евиденцију", + "The installer reported success but did not restart UniGetUI.": "Инсталер је пријавио успех, али није поново покренуо UniGetUI.", + "The installer failed to initialize.": "Инсталер није успео да се иницијализује.", + "Setup was canceled before installation began.": "Подешавање је отказано пре почетка инсталације.", + "A fatal error occurred during the preparation phase.": "Дошло је до фаталне грешке током фазе припреме.", + "A fatal error occurred during installation.": "Дошло је до фаталне грешке током инсталације.", + "Installation was canceled while in progress.": "Инсталација је отказана док је била у току.", + "The installer was terminated by another process.": "Инсталер је прекинуо други процес.", + "The preparation phase determined the installation cannot proceed.": "Фаза припреме је утврдила да инсталација не може да се настави.", + "The installer could not start. UniGetUI may already be running, or you do not have permission to install.": "Инсталер није могао да се покрене. UniGetUI је можда већ покренут или немаш дозволу за инсталацију.", + "Unexpected installer error.": "Неочекивана грешка инсталера.", + "We are checking for updates.": "Проверавам ажурирања.", + "Please wait": "Молимо сачекај", + "Great! You are on the latest version.": "Одлично! Користиш најновију верзију.", + "There are no new UniGetUI versions to be installed": "Нема нових UniGetUI верзија за инсталирање", + "UniGetUI version {0} is being downloaded.": "Преузима се UniGetUI верзија {0}.", + "This may take a minute or two": "Ово може потрајати минут или два", + "The installer authenticity could not be verified.": "Аутентичност инсталера није могла бити потврђена.", + "The update process has been aborted.": "Процес ажурирања је прекинут.", + "Auto-update is not yet available on this platform.": "Аутоматско ажурирање још није доступно на овој платформи.", + "Please update UniGetUI manually.": "Ажурирај UniGetUI ручно.", + "An error occurred when checking for updates: ": "Дошло је до грешке приликом проверавања ажурирања", + "The updater could not be launched.": "Ажурирач није могао да се покрене.", + "The operating system did not start the installer process.": "Оперативни систем није покренуо процес инсталера.", + "UniGetUI is being updated...": "UniGetUI се ажурира...", + "Update installed.": "Ажурирање је инсталирано.", + "UniGetUI was updated successfully, but this running copy was not replaced. This usually means you are running a development build. Close this copy and start the newly-installed version to finish.": "UniGetUI је успешно ажуриран, али ова покренута копија није замењена. То обично значи да користиш развојну верзију. Затвори ову копију и покрени новоинсталирану верзију да завршиш.", + "The update could not be applied.": "Ажурирање није могло да се примени.", + "Installer exit code {0}: {1}": "Излазни код инсталера {0}: {1}", + "Update cancelled.": "Ажурирање је отказано.", + "Authentication was cancelled.": "Аутентификација је отказана.", + "Installer exit code {0}": "Излазни код инсталера {0}", + "Operation in progress": "Операција у току", + "Please wait...": "Молимо сачекај...", + "Success!": "Успешно!", + "Failed": "Неуспешно", + "An error occurred while processing this package": "Настала је грешка током обраде пакета", + "Installer": "Инсталер", + "Executable": "Извршна датотека", + "MSI": "MSI", + "Compressed file": "Компримована датотека", + "MSIX": "MSIX", + "WinGet was repaired successfully": "WinGet је успешно поправљен", + "It is recommended to restart UniGetUI after WinGet has been repaired": "Препоручује се да поново покренеш UniGetUI након што је WinGet поправљен", + "WinGet could not be repaired": "WinGet није могао бити поправљен", + "An unexpected issue occurred while attempting to repair WinGet. Please try again later": "Дошло је до неочекиване грешке при покушају поправке WinGet‑а. Покушај поново касније.", + "Log in to enable cloud backup": "Пријави се да омогућиш резервну копију у облаку", + "Backup Failed": "Прављење резервне копије није успело", + "Downloading backup...": "Преузимање резервне копије...", + "An update was found!": "Пронађено је ажурирање!", + "{0} can be updated to version {1}": "{0} може бити ажуриран на верзију {1}", + "Updates found!": "Ажурирања пронађена!", + "{0} packages can be updated": "{0} пакета се може ажурирати", + "{0} is being updated to version {1}": "{0} се ажурира на верзију {1}", + "{0} packages are being updated": "Ажурира се {0} пакета", + "You have currently version {0} installed": "Тренутно имаш инсталирану верзију {0}", + "Desktop shortcut created": "Пречица на радној површини креирана", + "UniGetUI has detected a new desktop shortcut that can be deleted automatically.": "UniGetUI је открио нову пречицу на радној површини која може бити аутоматски избрисана.", + "{0} desktop shortcuts created": "{0} пречица на радној површини је креирано", + "UniGetUI has detected {0} new desktop shortcuts that can be deleted automatically.": "UniGetUI је открио {0} нових пречица на радној површини које могу бити аутоматски избрисане.", + "Attention required": "Потребна пажња", + "Restart required": "Неопходно је поновно покретање", + "1 update is available": "1 ажурирање доступно", + "{0} updates are available": "{0} ажурирања је доступно", + "Everything is up to date": "Све је ажурно", + "Discover Packages": "Откриј пакете", + "Available Updates": "Доступна Ажурирања", + "Installed Packages": "Инсталирани пакети", + "UniGetUI Version {0} by Devolutions": "UniGetUI верзија {0} од Devolutions", + "Show UniGetUI": "Прикажи UniGetUI", + "Quit": "Излаз", + "Are you sure?": "Да ли си сигуран?", + "Do you really want to uninstall {0}?": "Да ли заиста желиш да деинсталираш {0}?", + "Do you really want to uninstall the following {0} packages?": "Да ли заиста желиш да деинсталираш следећих {0} пакета?", + "No": "Не", + "Yes": "Да", + "Partial": "Делимично", + "View on UniGetUI": "Прикажи у UniGetUI", + "Update": "Ажурирај", + "Open UniGetUI": "Отвори UniGetUI", + "Update all": "Ажурирај све", + "Update now": "Ажурирај одмах", + "Installer host changed since the installed version.\n": "Хост инсталера се променио у односу на инсталирану верзију.\n", + "This package is on the queue": "Овај пакет је на листи чекања.", + "installing": "инсталирање", + "updating": "ажурирање", + "uninstalling": "деинсталирање", + "installed": "инсталирано", + "Retry": "Покушај поново", + "Install": "Инсталирај", + "Uninstall": "Деинсталирај", + "Open": "Отвори", + "Operation profile:": "Профил операције:", + "Follow the default options when installing, upgrading or uninstalling this package": "Следи подразумеване опције при инсталацији, надоградњи или деинсталацији овог пакета", + "The following settings will be applied each time this package is installed, updated or removed.": "Следећа подешавања ће бити примењена сваки пут када се овај пакет инсталира, ажурира или уклони.", + "Version to install:": "Верзија за инсталацију:", + "Architecture to install:": "Архитектура за инсталацију:", + "Installation scope:": "Опсег инсталације:", + "Install location:": "Локација инсталације:", + "Select": "Одабери", + "Reset": "Ресет", + "Custom install arguments:": "Прилагођени аргументи за инсталацију:", + "Custom update arguments:": "Прилагођени аргументи за ажурирање:", + "Custom uninstall arguments:": "Прилагођени аргументи за деинсталацију:", + "Pre-install command:": "Команда пре инсталације:", + "Post-install command:": "Команда после инсталације:", + "Abort install if pre-install command fails": "Обустави инсталацију ако пре-инсталациона команда не успе", + "Pre-update command:": "Команда пре ажурирања:", + "Post-update command:": "Команда после ажурирања:", + "Abort update if pre-update command fails": "Прекини ажурирање ако команда пре ажурирања не успе", + "Pre-uninstall command:": "Команда пре деинсталације:", + "Post-uninstall command:": "Команда после деинсталације:", + "Abort uninstall if pre-uninstall command fails": "Обустави деинсталацију ако пре-деинсталациона команда не успе", + "Command-line to run:": "Командна линија за покретање:", + "Save and close": "Сачувај и затвори", + "General": "Опште", + "Architecture & Location": "Архитектура и локација", + "Command-line": "Командна линија", + "Close apps": "Затвори апликације", + "Pre/Post install": "Пре/после инсталације", + "Select the processes that should be closed before this package is installed, updated or uninstalled.": "Изабери процесе који треба да буду затворени пре него што се овај пакет инсталира, ажурира или деинсталира.", + "Write here the process names here, separated by commas (,)": "Овде упиши називе процеса, раздвојене зарезима (,)", + "Try to kill the processes that refuse to close when requested to": "Покушај да прекинеш процесе који одбијају да се затворе када им се то затражи", + "Run as admin": "Покрени као администратор", + "Interactive installation": "Интерактивна инсталација", + "Skip hash check": "Прескочи проверу хеша", + "Uninstall previous versions when updated": "Деинсталирај претходне верзије приликом ажурирања", + "Skip minor updates for this package": "Прескочи мања ажурирања за овај пакет", + "Automatically update this package": "Аутоматски ажурирај овај пакет", + "{0} installation options": "{0} опције за инсталацију", + "Latest": "Најновије", + "PreRelease": "ПреИздање", + "Default": "Подразумевано", + "Manage ignored updates": "Управљај игнорисаним ажурирањима", + "The packages listed here won't be taken in account when checking for updates. Double-click them or click the button on their right to stop ignoring their updates.": "Пакети наведени овде неће бити узети у обзир при провери ажурирања. Двапут кликни на њих или кликни на дугме с њихове десне стране да би престао да игноришеш њихова ажурирања.", + "Reset list": "Ресетуј листу", + "Do you really want to reset the ignored updates list? This action cannot be reverted": "Да ли заиста желиш да ресетујеш листу игнорисаних ажурирања? Ова радња не може да се опозове", + "No ignored updates": "Нема игнорисаних ажурирања", + "Package Name": "Име пакета", + "Package ID": "ИД пакета", + "Ignored version": "Игнорисана верзија", + "New version": "Нова верзија", + "Source": "Извор", + "All versions": "Све верзије", + "Unknown": "Непознато", + "Up to date": "Ажурно", + "Package {name} from {manager}": "Пакет {name} од {manager}", + "Remove {0} from ignored updates": "Уклони {0} из игнорисаних ажурирања", + "Cancel": "Откажи", + "Administrator privileges": "Административне привилегије", + "This operation is running with administrator privileges.": "Ова операција се извршава са администраторским привилегијама.", + "Interactive operation": "Интерактивна операција", + "This operation is running interactively.": "Ова операција се извршава интерактивно.", + "You will likely need to interact with the installer.": "Вероватно ћеш морати да комуницираш са инсталером.", + "Integrity checks skipped": "Провере интегритета прескочене", + "Integrity checks will not be performed during this operation.": "Провере интегритета неће бити извршене током ове операције.", + "Proceed at your own risk.": "Настави на сопствени ризик.", + "Close": "Затвори", + "Loading...": "Учитавање...", + "Installer SHA256": "SHA256 инсталера", + "Homepage": "Почетна страна", + "Author": "Аутор", + "Publisher": "Издавач", + "License": "Лиценца", + "Manifest": "Манифест", + "Installer Type": "Тип инсталера", + "Size": "Величина", + "Installer URL": "УРЛ инсталера", + "Last updated:": "Последњи пут ажурирано:", + "Release notes URL": "УРЛ белешки о издању", + "Package details": "Детаљи пакета", + "Dependencies:": "Зависности:", + "Release notes": "Белешке о верзијама", + "Screenshots": "Снимци екрана", + "This package has no screenshots or is missing the icon? Contribute to UniGetUI by adding the missing icons and screenshots to our open, public database.": "Овај пакет нема снимке екрана или му недостаје икона? Допринеси UniGetUI-у додавањем недостајућих икона и снимака екрана у нашу отворену, јавну базу података.", + "Version": "Верзија", + "Install as administrator": "Инсталирај као администратор", + "Update to version {0}": "Ажурирај на верзију {0}", + "Installed Version": "Инсталирана верзија", + "Update as administrator": "Ажурирај као администратор", + "Interactive update": "Интерактивно ажурирање", + "Uninstall as administrator": "Деинсталирај као администратор", + "Interactive uninstall": "Интерактивно деинсталирање", + "Uninstall and remove data": "Деинсталирај и уклони податке", + "Not available": "Није доступно", + "Installer SHA512": "SHA512 инсталера", + "Unknown size": "Непозната величина", + "No dependencies specified": "Нема наведених зависности", + "mandatory": "обавезно", + "optional": "опционо", + "UniGetUI {0} is ready to be installed.": "UniGetUI {0} је спреман за инсталацију.", + "The update process will start after closing UniGetUI": "Процес ажурирања ће почети након затварања UniGetUI", + "UniGetUI has been ran as administrator, which is not recommended. When running UniGetUI as administrator, EVERY operation launched from UniGetUI will have administrator privileges. You can still use the program, but we highly recommend not running UniGetUI with administrator privileges.": "UniGetUI је покренут као администратор, што се не препоручује. Када UniGetUI ради са администраторским привилегијама, СВАКА операција покренута из UniGetUI-а имаће администраторске привилегије. И даље можеш да користиш програм, али изричито препоручујемо да не покрећеш UniGetUI са администраторским привилегијама.", + "Share anonymous usage data": "Дели анонимне податке о коришћењу", + "UniGetUI collects anonymous usage data in order to improve the user experience.": "UniGetUI прикупља анонимне податке о коришћењу ради побољшања корисничког искуства.", + "Accept": "Прихвати", + "Software Updates": "Ажурирања софтвера", + "Package Bundles": "Скупови пакета", + "Settings": "Подешавања", + "Package Managers": "Менаџери пакета", + "UniGetUI Log": "UniGetUI лог", + "Package Manager logs": "Логови пакет менаџера", + "Operation history": "Историја операција", + "Help": "Помоћ", + "UniGetUI": "UniGetUI", + "You have installed UniGetUI Version {0}": "Инсталирао си UniGetUI Верзију {0}", + "Disclaimer": "Одрицање од одговорности", + "UniGetUI is developed by Devolutions and is not affiliated with any of the compatible package managers.": "UniGetUI развија Devolutions и није повезан ни са једним од компатибилних менаџера пакета.", + "UniGetUI wouldn't have been possible without the help of the contributors. Thank you all 🥳": "UniGetUI не би био могућ без помоћи доприносиоца. Хвала свима 🥳", + "UniGetUI uses the following libraries. Without them, UniGetUI wouldn't have been possible.": "UniGetUI користи следеће библиотеке. Без њих, UniGetUI не би био могућ.", + "{0} homepage": "{0} почетна страна", + "UniGetUI has been translated to more than 40 languages thanks to the volunteer translators. Thank you 🤝": "UniGetUI је преведен на више од 40 језика захваљујући преводиоцима волонтерима. Хвала вам 🤝", + "Verbose": "Пуно детаља", + "1 - Errors": "1 - Грешке", + "2 - Warnings": "2 - Упозорења", + "3 - Information (less)": "3 - Информације (мање)", + "4 - Information (more)": "4 - Информације (више)", + "5 - information (debug)": "5 - информације (отклањање грешака)", + "Warning": "Упозорење", + "The following settings may pose a security risk, hence they are disabled by default.": "Следећа подешавања могу представљати безбедносни ризик, зато су подразумевано онемогућена.", + "Enable the settings below if and only if you fully understand what they do, and the implications they may have.": "Омогући поставке испод АКО И САМО АКО потпуно разумеш шта раде и какве последице могу имати.", + "The settings will list, in their descriptions, the potential security issues they may have.": "Подешавања ће у својим описима навести потенцијалне безбедносне проблеме које могу имати.", + "The backup will include the complete list of the installed packages and their installation options. Ignored updates and skipped versions will also be saved.": "Резервна копија ће садржати целу листу инсталираних пакета и њихове опције инсталације. Игнорисана ажурирања и прескочене верзије ће такође бити сачуване.", + "The backup will NOT include any binary file nor any program's saved data.": "Резервна копија НЕ укључује бинарну датотеку ни сачуване податке програма.", + "The size of the backup is estimated to be less than 1MB.": "Процењена величина резервне копије је мања од 1МБ.", + "The backup will be performed after login.": "Резервна копија ће бити направљена након пријаве.", + "{pcName} installed packages": "{pcName} инсталирани пакети", + "Current status: Not logged in": "Тренутни статус: Није пријављен", + "You are logged in as {0} (@{1})": "Пријављен си као {0} (@{1})", + "Nice! Backups will be uploaded to a private gist on your account": "Одлично! Резервне копије ће бити отпремљене у приватни gist на твом налогу", + "Select backup": "Изабери резервну копију", + "Settings imported from {0}": "Подешавања увезена из {0}", + "UniGetUI Settings": "Подешавања UniGetUI-а", + "Settings exported to {0}": "Подешавања извезена у {0}", + "UniGetUI settings were reset": "UniGetUI подешавања су ресетована", + "Allow pre-release versions": "Дозволи верзије за тестирање", + "Apply": "Примени", + "For security reasons, custom command-line arguments are disabled by default. Go to UniGetUI security settings to change this.": "Из безбедносних разлога, прилагођени аргументи командне линије су подразумевано онемогућени. Иди у безбедносна подешавања UniGetUI-а да би ово променио.", + "Go to UniGetUI security settings": "Иди у UniGetUI безбедносна подешавања", + "The following options will be applied by default each time a {0} package is installed, upgraded or uninstalled.": "Следеће опције ће се подразумевано примењивати сваки пут када се {0} пакет инсталира, надогради или деинсталира.", + "Package's default": "Подразумеване опције пакета", + "Install location can't be changed for {0} packages": "Локација инсталације не може да се промени за {0} пакета", + "The local icon cache currently takes {0} MB": "Локални кеш икона тренутно заузима {0} MB", + "Username": "Корисничко име", + "Password": "Лозинка", + "Credentials": "Подаци за пријаву", + "It is not guaranteed that the provided credentials will be stored safely": "Није гарантовано да ће достављени акредитиви бити безбедно сачувани", + "Partially": "Делимично", + "Package manager": "Менаџер пакета", + "Compatible with proxy": "Компатибилно са проксијем", + "Compatible with authentication": "Компатибилно са аутентификацијом", + "Proxy compatibility table": "Табела компатибилности проксија", + "{0} settings": "{0} подешавања", + "{0} status": "{0} статус", + "Default installation options for {0} packages": "Подразумеване опције инсталације за {0} пакета", + "Expand version": "Прошири верзију", + "The executable file for {0} was not found": "Извршна датотека за {0} није пронађена", + "{pm} is disabled": "{pm} је онемогућен", + "Enable it to install packages from {pm}.": "Омогући га да би инсталирао пакете са {pm}.", + "{pm} is enabled and ready to go": "{pm} је омогућен и спреман за рад", + "{pm} version:": "{pm} верзија:", + "{pm} was not found!": "{pm} није пронађен!", + "You may need to install {pm} in order to use it with UniGetUI.": "Можда ћеш морати да инсталираш {pm} да би га користио са UniGetUI.", + "Scoop Installer - UniGetUI": "Scoop Инсталер - UniGetUI", + "Scoop Uninstaller - UniGetUI": "Scoop Деинсталер - UniGetUI", + "Clearing Scoop cache - UniGetUI": "Брисање Scoop кеша - UniGetUI", + "Restart UniGetUI to fully apply changes": "Поново покрени UniGetUI да би у потпуности применио промене", + "Restart UniGetUI": "Рестартуј UniGetUI", + "Manage {0} sources": "Управљај са {0} извора", + "Add source": "Додај извор", + "Add": "Додај", + "Source name": "Назив извора", + "Source URL": "УРЛ извора", + "Other": "Друго", + "No minimum age": "Без минималне старости", + "1 day": "1 дан", + "{0} days": "{0} дана", + "Custom...": "Прилагођено...", + "{0} minutes": "{0} минута", + "1 hour": "1 сат", + "{0} hours": "{0} сати", + "1 week": "1 недеља", + "Supports release dates": "Подржава датуме издања", + "Release date support per package manager": "Подршка за датуме издања по менаџеру пакета", + "Search for packages": "Претражи пакете", + "Local": "Локално", + "OK": "У реду", + "Last checked: {0}": "Последње проверено: {0}", + "{0} packages were found, {1} of which match the specified filters.": "{0} пакета је пронађено, {1} од којих одговара наведеним филтерима.", + "{0} selected": "{0} изабрано", + "(Last checked: {0})": "(Последње проверено: {0})", + "All packages selected": "Сви пакети изабрани", + "Package selection cleared": "Избор пакета обрисан", + "{0}: {1}": "{0}: {1}", + "More info": "Више информација", + "GitHub account": "GitHub налог", + "Log in with GitHub to enable cloud package backup.": "Пријави се помоћу GitHub-а да омогућиш резервну копију пакета у облаку.", + "More details": "Више детаља", + "Log in": "Пријава", + "If you have cloud backup enabled, it will be saved as a GitHub Gist on this account": "Ако имаш омогућену резервну копију у облаку, биће сачувана као GitHub Gist на овом налогу", + "Log out": "Одјава", + "About UniGetUI": "О UniGetUI", + "About": "Информације", + "Third-party licenses": "Лиценце трећих лица", + "Contributors": "Доприниосци", + "Translators": "Преводиоци", + "Bundle security report": "Извештај о безбедности скупа пакета", + "The bundle contained restricted content": "Скуп пакета је садржао недозвољени садржај", + "UniGetUI – Crash Report": "UniGetUI – Извештај о паду", + "UniGetUI has crashed": "UniGetUI се срушио", + "Help us fix this by sending a crash report to Devolutions. All fields below are optional.": "Помозите нам да ово поправимо слањем извештаја о паду програма компанији Devolutions. Сва поља испод су опциона.", + "Email (optional)": "Имејл (опционо)", + "your@email.com": "tvoj@email.com", + "Additional details (optional)": "Додатни детаљи (опционо)", + "Describe what you were doing when the crash occurred…": "Опишите шта сте радили када се пад десио…", + "Crash report": "Извештај о паду", + "Don't Send": "Не шаљи", + "Send Report": "Пошаљи извештај", + "Sending…": "Слање…", + "Unsaved changes": "Несачуване промене", + "You have unsaved changes in the current bundle. Do you want to discard them?": "Имаш несачуване промене у тренутном скупу пакета. Да ли желиш да их одбациш?", + "Discard changes": "Одбаци промене", + "Integrity violation": "Нарушен интегритет", + "UniGetUI or some of its components are missing or corrupt. It is strongly recommended to reinstall UniGetUI to adress the situation.": "UniGetUI или неке његове компоненте недостају или су оштећене. Изричито се препоручује да поново инсталираш UniGetUI како би решио овај проблем.", + "• Refer to the UniGetUI Logs to get more details regarding the affected file(s)": "• Погледај UniGetUI дневнике да добијеш више детаља о погођеним датотекама", + "• Integrity checks can be disabled from the Experimental Settings": "• Провере интегритета могу се онемогућити у експерименталним подешавањима", + "Manage shortcuts": "Управљај пречицама", + "UniGetUI has detected the following desktop shortcuts which can be removed automatically on future upgrades": "UniGetUI је открио следеће пречице на радној површини које могу бити аутоматски уклоњене приликом будућих надоградњи", + "Do you really want to reset this list? This action cannot be reverted.": "Да ли заиста желиш да ресетујеш ову листу? Ова радња се не може отказати.", + "Desktop shortcuts list": "Листа пречица на радној површини", + "Open in explorer": "Отвори у истраживачу", + "Remove from list": "Уклони са листе", + "When new shortcuts are detected, delete them automatically instead of showing this dialog.": "Када се открију нове пречице, обриши их аутоматски уместо приказивања овог дијалога.", + "Not right now": "Не тренутно", + "Missing dependency": "Недостаје зависност", + "UniGetUI requires {0} to operate, but it was not found on your system.": "UniGetUI захтева {0} за рад, али није пронађен на твом систему.", + "Click on Install to begin the installation process. If you skip the installation, UniGetUI may not work as expected.": "Кликни на Инсталирај да би започео процес инсталације. Ако прескочиш инсталацију, UniGetUI можда неће радити како се очекује.", + "Alternatively, you can also install {0} by running the following command in a Windows PowerShell prompt:": "Алтернативно, {0} се може инсталирати покретањем следеће команде у Windows PowerShell окружењу:", + "Install {0}": "Инсталирај {0}", + "Do not show this dialog again for {0}": "Не приказуј овај дијалог поново за {0}", + "Please wait while {0} is being installed. A black window may show up. Please wait until it closes.": "Сачекај док се {0} инсталира. Може се појавити црни прозор. Сачекај док се не затвори.", + "{0} has been installed successfully.": "{0} је успешно инсталиран.", + "Please click on \"Continue\" to continue": "Кликни на „Настави“ да би наставио", + "Continue": "Настави", + "{0} has been installed successfully. It is recommended to restart UniGetUI to finish the installation": "{0} је успешно инсталиран. Препоручује се да поново покренеш UniGetUI да би довршио инсталацију", + "Restart later": "Поново покрени касније", + "An error occurred:": "Дошло је до грешке:", + "Please see the Command-line Output or refer to the Operation History for further information about the issue.": "Молимо погледај излаз командне линије или историју операција за додатне информације о проблему.", + "Retry as administrator": "Покушај поново као администратор", + "Retry interactively": "Покушај поново интерактивно", + "Retry skipping integrity checks": "Покушај поново прескачући провере интегритета", + "Installation options": "Опције инсталације", + "Save": "Сачувај", + "UniGetUI collects anonymous usage data with the sole purpose of understanding and improving the user experience.": "UniGetUI прикупља анонимне податке о коришћењу са једином сврхом разумевања и побољшања корисничког искуства.", + "More details about the shared data and how it will be processed": "Више детаља о дељеним подацима и како ће бити обрађени", + "Do you accept that UniGetUI collects and sends anonymous usage statistics, with the sole purpose of understanding and improving the user experience?": "Да ли прихваташ да UniGetUI прикупља и шаље анонимне статистике коришћења, са једином намером разумевања и побољшања корисничког искуства?", + "Decline": "Одбити", + "No personal information is collected nor sent, and the collected data is anonimized, so it can't be back-tracked to you.": "Никакве личне информације се не прикупљају нити шаљу, а прикупљени подаци су анонимизовани, тако да се не могу повезати са тобом.", + "Navigation panel": "Навигациони панел", + "Operations": "Операције", + "Toggle operations panel": "Укључи/искључи панел операција", + "Bulk operations": "Групне операције", + "Retry failed": "Понови неуспешне", + "Clear successful": "Обриши успешне", + "Clear finished": "Обриши завршене", + "Cancel all": "Откажи све", + "More": "Више", + "Toggle navigation panel": "Прикажи/сакриј навигациони панел", + "Minimize": "Умањи", + "Maximize": "Увећај", + "UniGetUI by Devolutions": "UniGetUI од Devolutions", + "UniGetUI is an application that makes managing your software easier, by providing an all-in-one graphical interface for your command-line package managers.": "UniGetUI је апликација која олакшава управљање твојим софтвером, пружајући свеобухватни графички интерфејс за твоје менаџере пакета на командној линији.", + "Useful links": "Корисни линкови", + "UniGetUI Homepage": "Почетна страница UniGetUI-а", + "Report an issue or submit a feature request": "Пријави проблем или пошаљи захтев за функционалност", + "UniGetUI Repository": "Репозиторијум UniGetUI-а", + "View GitHub Profile": "Види GitHub Профил", + "UniGetUI License": "UniGetUI Лиценца", + "Using UniGetUI implies the acceptation of the MIT License": "Коришћење UniGetUI подразумева прихватање MIT лиценце", + "Become a translator": "Постани преводилац", + "Go back": "Назад", + "Go forward": "Напред", + "Go to home page": "Иди на почетну страницу", + "Reload page": "Поново учитај страницу", + "View page on browser": "Погледај страницу у претраживачу", + "The built-in browser is not supported on Linux yet.": "Уграђени прегледач још није подржан на Linux-у.", + "Open in browser": "Отвори у прегледачу", + "Copy to clipboard": "Копирај на клипборд", + "Export to a file": "Извоз у датотеку", + "Log level:": "Ниво логовања:", + "Reload log": "Поново учитај лог", + "Export log": "Извези лог", + "Text": "Текст", + "Change how operations request administrator rights": "Промени начин на који операције захтевају администраторска права", + "Restrictions on package operations": "Ограничења за операције пакета", + "Restrictions on package managers": "Ограничења за менаџере пакета", + "Restrictions when importing package bundles": "Ограничења приликом увоза скупа пакета", + "Ask for administrator privileges once for each batch of operations": "Затражи администраторске привилегије једном за сваки скуп операција", + "Ask only once for administrator privileges": "Тражи администраторска права само једном", + "Prohibit any kind of Elevation via UniGetUI Elevator or GSudo": "Забрани било какво подизање привилегија преко UniGetUI Elevator-а или GSudo-а", + "This option WILL cause issues. Any operation incapable of elevating itself WILL FAIL. Install/update/uninstall as administrator will NOT WORK.": "Ова опција ЋЕ изазвати проблеме. Свака операција која не може сама да подигне привилегије НЕЋЕ УСПЕТИ. Инсталирање/ажурирање/деинсталација као администратор НЕЋЕ РАДИТИ.", + "Allow custom command-line arguments": "Дозволи прилагођене аргументе командне линије", + "Custom command-line arguments can change the way in which programs are installed, upgraded or uninstalled, in a way UniGetUI cannot control. Using custom command-lines can break packages. Proceed with caution.": "Прилагођени аргументи командне линије могу изменити начин на који се програми инсталирају, надограђују или деинсталирају, на начин који UniGetUI не може да контролише. Коришћење прилагођених командних линија може оштетити пакете. Настави с опрезом.", + "Ignore custom pre-install and post-install commands when importing packages from a bundle": "Игнориши прилагођене команде пре и после инсталације приликом увоза пакета из скупа пакета", + "Pre and post install commands will be run before and after a package gets installed, upgraded or uninstalled. Be aware that they may break things unless used carefully": "Команде пре и после инсталације извршаваће се пре и после него што се пакет инсталира, надогради или деинсталира. Имај на уму да могу покварити ствари ако се не користе пажљиво", + "Allow changing the paths for package manager executables": "Дозволи промену путања за извршне датотеке менаџера пакета", + "Turning this on enables changing the executable file used to interact with package managers. While this allows finer-grained customization of your install processes, it may also be dangerous": "Укључивање ове опције омогућава промену извршне датотеке која се користи за интеракцију са менаџерима пакета. Иако ово омогућава прецизније прилагођавање процеса инсталације, може бити и опасно", + "Allow importing custom command-line arguments when importing packages from a bundle": "Дозволи увоз прилагођених аргумената командне линије приликом увоза пакета из скупа пакета", + "Malformed command-line arguments can break packages, or even allow a malicious actor to gain privileged execution. Therefore, importing custom command-line arguments is disabled by default": "Лоше формирани аргументи командне линије могу покварити пакете, или чак омогућити злонамерном актеру привилеговано извршавање. Зато је увоз прилагођених аргумената командне линије подразумевано онемогућен.", + "Allow importing custom pre-install and post-install commands when importing packages from a bundle": "Дозволи увоз прилагођених команди пре и после инсталације приликом увоза пакета из скупа пакета", + "Pre and post install commands can do very nasty things to your device, if designed to do so. It can be very dangerous to import the commands from a bundle, unless you trust the source of that package bundle": "Команде пре и после инсталације могу урадити веома непријатне ствари твом уређају, ако су тако направљене. Може бити веома опасно увозити команде из пакета, осим ако верујеш извору тог скупа пакета", + "Administrator rights and other dangerous settings": "Администраторска права и друга опасна подешавања", + "Package backup": "Резервна копија пакета", + "Cloud package backup": "Резервна копија пакета у облаку", + "Local package backup": "Локална резервна копија пакета", + "Local backup advanced options": "Напредне опције локалне резервне копије", + "Log in with GitHub": "Пријави се помоћу GitHub-а", + "Log out from GitHub": "Одјави се са GitHub-а", + "Periodically perform a cloud backup of the installed packages": "Повремено прави резервну копију инсталираних пакета у облаку", + "Cloud backup uses a private GitHub Gist to store a list of installed packages": "Резервна копија у облаку користи приватни GitHub Gist за чување списка инсталираних пакета", + "Perform a cloud backup now": "Направи резервну копију у облаку сада", + "Backup": "Резервна копија", + "Restore a backup from the cloud": "Врати резервну копију из облака", + "Begin the process to select a cloud backup and review which packages to restore": "Започни процес избора резервне копије у облаку и прегледа пакета за враћање", + "Periodically perform a local backup of the installed packages": "Повремено прави локалну резервну копију инсталираних пакета", + "Perform a local backup now": "Направи локалну резервну копију сада", + "Change backup output directory": "Промени локацију резервне копије", + "Set a custom backup file name": "Постави другачији назив датотеке резервне копије", + "Leave empty for default": "Остави празно за подразумевано", + "Add a timestamp to the backup file names": "Додај време називу датотеке резервне копије", + "Backup and Restore": "Израда и враћање резервних копија", + "Enable background api (UniGetUI Widgets and Sharing, port 7058)": "Омогући позадински апи (UniGetUI Widgets and Sharing, порт 7058)", + "Wait for the device to be connected to the internet before attempting to do tasks that require internet connectivity.": "Сачекај да уређај буде повезан на интернет пре покушаја да се обаве задаци који захтевају интернет везу.", + "Disable the 1-minute timeout for package-related operations": "Поништи паузу од 1 минута за операције везане за пакете", + "Use installed GSudo instead of UniGetUI Elevator": "Користи инсталирани GSudo уместо UniGetUI Elevator-а", + "Use a custom icon and screenshot database URL": "Користи УРЛ са прилагођеним иконама и снимцима екрана", + "Enable background CPU Usage optimizations (see Pull Request #3278)": "Омогући оптимизације коришћења CPU-а у позадини (погледај Pull Request #3278)", + "Perform integrity checks at startup": "Изврши провере интегритета при покретању", + "When batch installing packages from a bundle, install also packages that are already installed": "При групној инсталацији пакета из пакета, инсталирај и пакете који су већ инсталирани", + "Experimental settings and developer options": "Експерименталне поставке и опције за развој", + "Show UniGetUI's version and build number on the titlebar.": "Прикажи верзију UniGetUI на насловној траци.", + "Language": "Језик", + "UniGetUI updater": "UniGetUI ажурирач", + "Telemetry": "Телеметрија", + "Manage UniGetUI settings": "Управљај UniGetUI подешавањима", + "Related settings": "Сродна подешавања", + "Update UniGetUI automatically": "Аутоматски ажурирај UniGetUI", + "Check for updates": "Провери ажурирања", + "Install prerelease versions of UniGetUI": "Инсталирај претходна издања UniGetUI", + "Manage telemetry settings": "Управљај подешавањима телеметрије", + "Manage": "Управљај", + "Import settings from a local file": "Увоз поставки из локалне датотеке", + "Import": "Увоз", + "Export settings to a local file": "Извоз поставки у локалну датотеку", + "Export": "Извоз", + "Reset UniGetUI": "Ресетуј UniGetUI", + "User interface preferences": "Поставке корисничког интерфејса", + "Application theme, startup page, package icons, clear successful installs automatically": "Тема апликације, почетна страница, иконе пакета, аутоматско брисање успешно инсталираних ставки", + "General preferences": "Опште поставке", + "UniGetUI display language:": "Језик приказивања UniGetUI-а:", + "System language": "Језик система", + "Is your language missing or incomplete?": "Да ли твој језик недостаје или је непотпун?", + "Appearance": "Изглед", + "UniGetUI on the background and system tray": "UniGetUI у позадини и системској палети", + "Package lists": "Листе пакета", + "Use classic mode": "Користи класични режим", + "Restart UniGetUI to apply this change": "Поново покрени UniGetUI да примениш ову промену", + "The classic UI is disabled for beta testers": "Класични кориснички интерфејс је онемогућен за бета тестере", + "Close UniGetUI to the system tray": "Затвори UniGetUI у системску траку", + "Manage UniGetUI autostart behaviour": "Управљај понашањем аутоматског покретања UniGetUI-а", + "Show package icons on package lists": "Прикажи иконе пакета на листама пакета", + "Clear cache": "Обриши кеш", + "Select upgradable packages by default": "Подразумевано изабери пакете који се могу надоградити", + "Light": "Светло", + "Dark": "Тамно", + "Follow system color scheme": "Прати шему боја система", + "Application theme:": "Тема апликације", + "UniGetUI startup page:": "Почетна страница UniGetUI:", + "Proxy settings": "Подешавања проксија", + "Other settings": "Остала подешавања", + "Connect the internet using a custom proxy": "Повежи се на интернет користећи прилагођени прокси", + "Please note that not all package managers may fully support this feature": "Имај на уму да сви менаџери пакета можда не подржавају у потпуности ову функцију", + "Proxy URL": "УРЛ проксија", + "Enter proxy URL here": "Унеси УРЛ проксија овде", + "Authenticate to the proxy with a user and a password": "Аутентификуј се на проксију корисничким именом и лозинком", + "Internet and proxy settings": "Подешавања интернета и проксија", + "Package manager preferences": "Поставке пакет менаџера", + "Ready": "Спремно", + "Not found": "Није пронађено", + "Notification preferences": "Подешавања обавештења", + "Notification types": "Врсте обавештења", + "The system tray icon must be enabled in order for notifications to work": "Икона у системској палети мора бити омогућена да би обавештења радила", + "Enable UniGetUI notifications": "Омогући обавештења за UniGetUI", + "Show a notification when there are available updates": "Прикажи обавештење када су ажурирања доступна", + "Show a silent notification when an operation is running": "Прикажи тихо обавештење када се операција извршава", + "Show a notification when an operation fails": "Прикажи обавештење када операција не успе", + "Show a notification when an operation finishes successfully": "Прикажи обавештење када операција успе", + "Concurrency and execution": "Истовременост и извршавање", + "Automatic desktop shortcut remover": "Аутоматски уклањач пречица са радне површине", + "Choose how many operations should be performed in parallel": "Изабери колико операција треба да се обавља паралелно", + "Clear successful operations from the operation list after a 5 second delay": "Уклони успешне операције са листе операција након 5 секунди", + "Download operations are not affected by this setting": "Операције преузимања нису захваћене овом поставком", + "You may lose unsaved data": "Можеш изгубити несачуване податке", + "Ask to delete desktop shortcuts created during an install or upgrade.": "Питај за брисање пречица на радној површини креираних током инсталације или надоградње.", + "Package update preferences": "Подешавања ажурирања пакета", + "Update check frequency, automatically install updates, etc.": "Учесталост провере ажурирања, аутоматска инсталација ажурирања, итд.", + "Reduce UAC prompts, elevate installations by default, unlock certain dangerous features, etc.": "Смањи UAC упите, подразумевано подигни инсталације, откључај одређене опасне функције, итд.", + "Package operation preferences": "Подешавања операција пакета", + "Enable {pm}": "Омогући {pm}", + "Not finding the file you are looking for? Make sure it has been added to path.": "Не налазиш датотеку коју тражиш? Увери се да је додата у путању.", + "Select the executable to be used. The following list shows the executables found by UniGetUI": "Изабери извршну датотеку која ће се користити. Следећа листа приказује извршне датотеке које је пронашао UniGetUI", + "For security reasons, changing the executable file is disabled by default": "Из безбедносних разлога, промена извршне датотеке је подразумевано онемогућена", + "Change this": "Измени ово", + "Copy path": "Копирај путању", + "Current executable file:": "Тренутна извршна датотека:", + "Ignore packages from {pm} when showing a notification about updates": "Игнориши пакете од {pm} при приказивању обавештења о ажурирањима", + "Update security": "Безбедност ажурирања", + "Use global setting": "Користи глобално подешавање", + "Minimum age for updates": "Минимална старост ажурирања", + "e.g. 10": "нпр. 10", + "Custom minimum age (days)": "Прилагођена минимална старост (у данима)", + "{pm} does not provide release dates for its packages, so this setting will have no effect": "{pm} не пружа датуме издања за своје пакете, па ово подешавање неће имати ефекта", + "{pm} only provides release dates for some of its packages, so this setting will only apply to those packages": "{pm} пружа датуме издавања само за неке од својих пакета, тако да ће се ово подешавање применити само на те пакете", + "Override the global minimum update age for this package manager": "Замени глобално подешавање минималне старости ажурирања за овај менаџер пакета", + "View {0} logs": "Прикажи {0} дневника", + "If Python cannot be found or is not listing packages but is installed on the system, ": "Ако Python не може бити пронађен или не приказује пакете али је инсталиран на систему, ", + "Advanced options": "Напредне опције", + "WinGet command-line tool": "WinGet алат командне линије", + "Choose which command-line tool UniGetUI uses for WinGet operations when the COM API is not used": "Одабери који алат командне линије UniGetUI користи за WinGet операције када се COM API не користи", + "WinGet COM API": "WinGet COM API", + "Choose whether UniGetUI can use the WinGet COM API before falling back to the command-line tool": "Одабери да ли UniGetUI може да користи WinGet COM API пре преласка на алат командне линије", + "Reset WinGet": "Ресетуј WinGet", + "This may help if no packages are listed": "Ово може помоћи ако ниједан пакет није наведен", + "Force install location parameter when updating packages with custom locations": "Присили параметар локације инсталације при ажурирању пакета са прилагођеним локацијама", + "Install Scoop": "Инсталирај Scoop", + "Uninstall Scoop (and its packages)": "Деинсталирај Scoop (и његове пакете)", + "Run cleanup and clear cache": "Покрени чишћење и обриши кеш", + "Run": "Покрени", + "Enable Scoop cleanup on launch": "Омогући чишћење Scoop-а при покретању", + "Default vcpkg triplet": "Подразумевани vcpkg триплет", + "Change vcpkg root location": "Промени основну локацију vcpkg-а", + "Reset vcpkg root location": "Ресетуј основну локацију vcpkg-а", + "Open vcpkg root location": "Отвори основну локацију vcpkg-а", + "Language, theme and other miscellaneous preferences": "Језик, тема и остале опције", + "Show notifications on different events": "Прикажи обавештења о различитим догађајима", + "Change how UniGetUI checks and installs available updates for your packages": "Промени како UniGetUI проверава и инсталира доступна ажурирања за твоје пакете", + "Automatically save a list of all your installed packages to easily restore them.": "Аутоматски сачувај листу свих инсталираних пакета ради лакшег враћања.", + "Enable and disable package managers, change default install options, etc.": "Омогући и онемогући менаџере пакета, измени подразумеване опције инсталације, итд.", + "Internet connection settings": "Подешавања интернет везе", + "Proxy settings, etc.": "Подешавања проксија, итд.", + "Beta features and other options that shouldn't be touched": "Бета функције и друге опције које не би требало да се додирну", + "Reload sources": "Поново учитај изворе", + "Delete source": "Обриши извор", + "Known sources": "Познати извори", + "Update checking": "Провера ажурирања", + "Automatic updates": "Аутоматска ажурирања", + "Check for package updates periodically": "Повремено провери ажурирања пакета", + "Check for updates every:": "Провери ажурирања сваких:", + "Install available updates automatically": "Аутоматски инсталирај доступна ажурирања", + "Do not automatically install updates when the network connection is metered": "Не инсталирај ажурирања аутоматски када је мрежна веза ограничена", + "Do not automatically install updates when the device runs on battery": "Не инсталирај ажурирања аутоматски када уређај ради на батеријском напону", + "Do not automatically install updates when the battery saver is on": "Не инсталирај ажурирања аутоматски када је батеријска заштита активна", + "Only show updates that are at least the specified number of days old": "Прикажи само ажурирања која су стара најмање наведени број дана", + "Warn me when the installer URL host changes between the installed version and the new version (WinGet only)": "Упозори ме када се хост УРЛ-а инсталера промени између инсталиране и нове верзије (само WinGet)", + "Change how UniGetUI handles install, update and uninstall operations.": "Промени начин на који UniGetUI обрађује инсталације, ажурирања и деинсталације.", + "Navigation": "Навигација", + "Check for UniGetUI updates": "Провери ажурирања за UniGetUI", + "Quit UniGetUI": "Изађи из UniGetUI-а", + "Filters": "Филтери", + "Sources": "Извори", + "Search for packages to start": "Претражите пакете за почетак", + "Select all": "Изабери све", + "Clear selection": "Обриши избор", + "Instant search": "Инстант претрага", + "Distinguish between uppercase and lowercase": "Прави разлику између великих и малих слова", + "Ignore special characters": "Игнориши посебне карактере", + "Search mode": "Мод претраге", + "Both": "Оба", + "Exact match": "Тачно подударање", + "Show similar packages": "Покажи сличне пакете", + "Loading": "Учитавање", + "Package": "Пакет", + "More options": "Још опција", + "Order by:": "Поређај по:", + "Name": "Име", + "Id": "Идентификатор", + "Ascendant": "Узлазнo", + "Descendant": "Силазно", + "View modes": "Режими приказа", + "Reload": "Поново учитај", + "Closed": "Затворено", + "Ascending": "Растуће", + "Descending": "Опадајуће", + "{0}: {1}, {2}": "{0}: {1}, {2}", + "Order by": "Поређај по", + "No results were found matching the input criteria": "Није пронађен ниједан резултат који одговара унетим критеријумима", + "No packages were found": "Није пронађен ниједан пакет", + "Loading packages": "Учитавање пакета", + "Skip integrity checks": "Прескочи проверу интегритета", + "Download selected installers": "Преузми одабране инсталере", + "Install selection": "Инсталирај одабране", + "Install options": "Опције инсталације", + "Add selection to bundle": "Додај одабране у скуп", + "Download installer": "Преузми инсталер", + "Uninstall selection": "Деинсталирај изабрано", + "Uninstall options": "Опције деинсталације", + "Ignore selected packages": "Игнориши изабране пакете", + "Open install location": "Отвори локацију инсталације", + "Reinstall package": "Реинсталирај пакет", + "Uninstall package, then reinstall it": "Уклони пакет, затим га поново инсталирај", + "Ignore updates for this package": "Игнориши ажурирања за овај пакет", + "WinGet malfunction detected": "Откривен је квар WinGet-а", + "It looks like WinGet is not working properly. Do you want to attempt to repair WinGet?": "Изгледа да WinGet не ради како треба. Да ли желиш да покушаш да поправиш WinGet?", + "Repair WinGet": "Поправи WinGet", + "Updates will no longer be ignored for {0}": "Ажурирања више неће бити игнорисана за {0}", + "Updates are now ignored for {0}": "Ажурирања су сада игнорисана за {0}", + "Do not ignore updates for this package anymore": "Престани да игноришеш ажурирања за овај пакет", + "Add packages or open an existing package bundle": "Додај пакете или отвори постојећи скуп", + "Add packages to start": "Додај пакете за почетак", + "The current bundle has no packages. Add some packages to get started": "Тренутни скуп нема пакета. Додај неке пакете како би започео", + "New": "Ново", + "Save as": "Сачувај као", + "Create .ps1 script": "Креирај .ps1 скрипту", + "Remove selection from bundle": "Уклони одабране из скупа пакета", + "Skip hash checks": "Прескочи провере хеша", + "The package bundle is not valid": "Скуп пакета није важећи", + "The bundle you are trying to load appears to be invalid. Please check the file and try again.": "Скуп пакета који покушаваш да учиташ делује неважеће. Провери датотеку и покушај поново.", + "Package bundle": "Скуп пакета", + "Could not create bundle": "Није могуће креирати скуп пакета", + "The package bundle could not be created due to an error.": "Скуп пакета није могао бити направљен због грешке.", + "Install script": "Инсталациона скрипта", + "PowerShell script": "PowerShell скрипта", + "The installation script saved to {0}": "Инсталациона скрипта је сачувана у {0}", + "An error occurred": "Дошло је до грешке", + "An error occurred while attempting to create an installation script:": "Дошло је до грешке при покушају креирања инсталационе скрипте:", + "Hooray! No updates were found.": "Ура! Нису пронађена ажурирања!", + "Uninstall selected packages": "Деинсталирај изабране пакете", + "Update selection": "Ажурирај изабрано", + "Update options": "Опције ажурирања", + "Uninstall package, then update it": "Уклони пакет, затим га ажурирај", + "Uninstall package": "Деинсталирај пакет", + "Skip this version": "Прескочи ову верзију", + "Pause updates for": "Паузирај ажурирања за", + "User | Local": "Корисник | Локално", + "Machine | Global": "Рачунар | Глобално", + "The default package manager for Debian/Ubuntu-based Linux distributions.
Contains: Debian/Ubuntu packages": "Подразумевани менаџер пакета за Linux дистрибуције засноване на Debian/Ubuntu.
Садржи: Debian/Ubuntu пакете", + "The Rust package manager.
Contains: Rust libraries and programs written in Rust": "Rust менаџер пакета.
Садржи: Rust библиотеке и програме написане у Rust-у", + "The classical package manager for windows. You'll find everything there.
Contains: General Software": "Класични менаџер пакета за Windows. Ту ћеш пронаћи све.
Садржи: Општи софтвер", + "The default package manager for RHEL/Fedora-based Linux distributions.
Contains: RPM packages": "Подразумевани менаџер пакета за Linux дистрибуције засноване на RHEL/Fedora.
Садржи: RPM пакете", + "A repository full of tools and executables designed with Microsoft's .NET ecosystem in mind.
Contains: .NET related tools and scripts": "Репозиторијум пун алата и извршних програма дизајниран имајући у виду Микрософтов .NET екосистем.
Садржи: алатке и скрипте везане за .NET", + "The universal Linux package manager for desktop applications.
Contains: Flatpak applications from configured remotes": "Универзални Linux менаџер пакета за десктоп апликације.
Садржи: Flatpak апликације из конфигурисаних удаљених извора", + "NuPkg (zipped manifest)": "NuPkg (зиповани манифест)", + "The Missing Package Manager for macOS (or Linux).
Contains: Formulae, Casks": "Недостајући менаџер пакета за macOS (или Linux).
Садржи: Formulae, Casks", + "Node JS's package manager. Full of libraries and other utilities that orbit the javascript world
Contains: Node javascript libraries and other related utilities": "Пакет менаџер за Node JS. Пун библиотека и других алатки које су у вези са JavaScript-ом
Садржи: Библиотеке JavaScript-a и друге релевантне алатке", + "The default package manager for Arch Linux and its derivatives.
Contains: Arch Linux packages": "Подразумевани менаџер пакета за Arch Linux и његове деривате.
Садржи: Arch Linux пакете", + "Python's library manager. Full of python libraries and other python-related utilities
Contains: Python libraries and related utilities": "Менаџер библиотека за Python. Пун Python библиотека и других Python-релевантних алатки
Садржи: Python библиотеке и релевантне алатке", + "PowerShell's package manager. Find libraries and scripts to expand PowerShell capabilities
Contains: Modules, Scripts, Cmdlets": "PowerShell-ов менаџер пакета. Пронађи библиотеке и скрипте за проширење PowerShell могућности
Садржи: Модуле, Скрипте, Cmdlet-ове\n", + "extracted": "екстраховано", + "Scoop package": "Scoop пакет", + "Great repository of unknown but useful utilities and other interesting packages.
Contains: Utilities, Command-line programs, General Software (extras bucket required)": "Велики репозиторијум непознатих, али корисних алатки и других интересантних пакета.
Садржи: Алатке, Програме за командну линију, Општи софтвер (потребна додатна кофа)", + "The universal Linux package manager by Canonical.
Contains: Snap packages from the Snapcraft store": "Универзални менаџер пакета за Linux од стране Canonical-а.
Садржи: Snap пакете из Snapcraft продавнице", + "library": "библиотека", + "feature": "функција", + "A popular C/C++ library manager. Full of C/C++ libraries and other C/C++-related utilities
Contains: C/C++ libraries and related utilities": "Популарни C/C++ управљач библиотекама. Пун C/C++ библиотека и других C/C++-сродних алата
Садржи: C/C++ библиотеке и сродне алате", + "option": "опција", + "This package cannot be installed from an elevated context.": "Овај пакет не може бити инсталиран из повишеног контекста.", + "Please run UniGetUI as a regular user and try again.": "Покрени UniGetUI као обичан корисник и покушај поново.", + "Please check the installation options for this package and try again": "Провери опције инсталације за овај пакет и покушај поново", + "Microsoft's official package manager. Full of well-known and verified packages
Contains: General Software, Microsoft Store apps": "Званични пакетни менаџер Microsoft-a. Пун добро познатих и верификованих пакета
Садржи: Општи софтвер, апликације из Microsoft Store-a", + "Local PC": "Локални рачунар", + "Android Subsystem": "Андроид Подсистем", + "Operation on queue (position {0})...": "Операција је у реду (позиција {0})...", + "Click here for more details": "Кликни овде за више детаља", + "Operation canceled by user": "Корисник је отказао операцију", + "Running PreOperation ({0}/{1})...": "Покрећем пред-операцију ({0}/{1})...", + "PreOperation {0} out of {1} failed, and was tagged as necessary. Aborting...": "Пред-операција {0} од {1} није успела и означена је као неопходна. Прекидам...", + "PreOperation {0} out of {1} finished with result {2}": "Пред-операција {0} од {1} је завршена са резултатом {2}", + "Starting operation...": "Покретање операције...", + "Running PostOperation ({0}/{1})...": "Покрећем PostOperation ({0}/{1})...", + "PostOperation {0} out of {1} failed, and was tagged as necessary. Aborting...": "Пост-операција {0} од {1} није успела и означена је као неопходна. Прекидам...", + "PostOperation {0} out of {1} finished with result {2}": "Пост-операција {0} од {1} је завршена са резултатом {2}", + "{package} installer download": "Преузимање инсталера за {package}", + "{0} installer is being downloaded": "Преузима се инсталер за {0}", + "Download succeeded": "Успешно преузимање", + "{package} installer was downloaded successfully": "Инсталер за {package} је успешно преузет", + "Download failed": "Преузимање није успело", + "{package} installer could not be downloaded": "Инсталер за {package} није могао бити преузет", + "{package} Installation": "{package} Инсталација", + "{0} is being installed": "{0} се инсталира", + "Installation succeeded": "Успешна инсталација", + "{package} was installed successfully": "{package} је успешно инсталиран", + "Installation failed": "Неуспешна инсталација", + "{package} could not be installed": "{package} није могуће инсталирати", + "{package} Update": "{package} Ажурирај", + "Update succeeded": "Успешно ажурирање", + "{package} was updated successfully": "{package} је успешно ажуриран", + "Update failed": "Неуспешно ажурирање", + "{package} could not be updated": "{package} није могуће ажурирати", + "{package} Uninstall": "{package} Деинсталирај", + "{0} is being uninstalled": "{0} се деинсталира", + "Uninstall succeeded": "Успешно деинсталирање", + "{package} was uninstalled successfully": "{package} је успешно деинсталиран", + "Uninstall failed": "Неуспешно деинсталирање", + "{package} could not be uninstalled": "{package} није могуће деинсталирати", + "Adding source {source}": "Додавање извора {source}", + "Adding source {source} to {manager}": "Додавање извора {source} у {manager}", + "Source added successfully": "Извор је успешно додат", + "The source {source} was added to {manager} successfully": "Извор {source} је успешно додат у {manager}", + "Could not add source": "Није могуће додати извор", + "Could not add source {source} to {manager}": "Није могуће додати извор {source} у {manager}\n", + "Removing source {source}": "Уклањање извора {source}", + "Removing source {source} from {manager}": "Уклањање извора {source} из {manager}", + "Source removed successfully": "Извор је успешно уклоњен", + "The source {source} was removed from {manager} successfully": "Извор {source} је успешно уклоњен из {manager}", + "Could not remove source": "Није могуће уклонити извор", + "Could not remove source {source} from {manager}": "Није могуће уклонити извор {source} из {manager}", + "The package manager \"{0}\" was not found": "Менаџер пакета \"{0}\" није пронађен", + "The package manager \"{0}\" is disabled": "Менаџер пакета \"{0}\" је онемогућен", + "There is an error with the configuration of the package manager \"{0}\"": "Постоји грешка у конфигурацији менаџера пакета \"{0}\"", + "The package \"{0}\" was not found on the package manager \"{1}\"": "Пакет \"{0}\" није пронађен у менаџеру пакета \"{1}\"", + "{0} is disabled": "{0} је онемогућен", + "{0} weeks": "{0} недеља", + "1 month": "1 месец", + "{0} months": "{0} месеци", + "Something went wrong": "Нешто је пошло по злу", + "An interal error occurred. Please view the log for further details.": "Догодила се унутрашња грешка. Молимо да погледаш логове за више детаља", + "No applicable installer was found for the package {0}": "Није пронађен одговарајући инсталер за пакет {0}", + "Integrity checks will not be performed during this operation": "Провере интегритета неће бити извршене током ове операције", + "This is not recommended.": "Ово није препоручено.", + "Run now": "Покрени сада", + "Run next": "Покрени следеће", + "Run last": "Покрени последње", + "Show in explorer": "Прикажи у истраживачу", + "Checked": "Означено", + "Unchecked": "Неозначено", + "This package is already installed": "Овај пакет је већ инсталиран", + "This package can be upgraded to version {0}": "Овај пакет може бити надограђен на верзију {0}", + "Updates for this package are ignored": "Ажурирања за овај пакет се игноришу", + "This package is being processed": "Овај пакет је тренутно у обради.", + "This package is not available": "Овај пакет није доступан", + "Select the source you want to add:": "Одабери извор који желиш да додаш:", + "Source name:": "Назив извора:", + "Source URL:": "УРЛ извора:", + "An error occurred when adding the source: ": "Дошло је до грешке приликом додавања извора:", + "Package management made easy": "Управљање пакетима учињено лаким", + "version {0}": "верзија {0}", + "[RAN AS ADMINISTRATOR]": "[ПОКРЕНУТО КАО АДМИНИСТРАТОР]", + "Portable mode": "Преносиви режим\n", + "DEBUG BUILD": "ВЕРЗИЈА ЗА ОТКЛАЊАЊЕ ГРЕШАКА", + "Here you can change UniGetUI's behaviour regarding the following shortcuts. Checking a shortcut will make UniGetUI delete it if if gets created on a future upgrade. Unchecking it will keep the shortcut intact": "Овде можеш да промениш понашање UniGetUI-а у вези са следећим пречицама. Означавање пречице ће учинити да је UniGetUI обрише ако се направи током будуће надоградње. Поништавање ознаке ће задржати пречицу нетакнутом", + "Manual scan": "Ручно скенирање", + "Existing shortcuts on your desktop will be scanned, and you will need to pick which ones to keep and which ones to remove.": "Постојеће пречице на радној површини ће бити скениране и мораћеш да одабереш које желиш да задржиш, а које да уклониш.", + "Delete?": "Обрисати?", + "I understand": "Разумем", + "Chocolatey setup changed": "Chocolatey подешавање промењено", + "UniGetUI no longer includes its own private Chocolatey installation. A legacy UniGetUI-managed Chocolatey installation was detected for this user profile, but system Chocolatey was not found. Chocolatey will stay unavailable in UniGetUI until Chocolatey is installed on the system and UniGetUI is restarted. Applications previously installed through UniGetUI's bundled Chocolatey may still appear under other sources such as Local PC or WinGet.": "UniGetUI више не укључује сопствену приватну Chocolatey инсталацију. Откривена је застарела Chocolatey инсталација којом је управљао UniGetUI за овај кориснички профил, али системски Chocolatey није пронађен. Chocolatey ће остати недоступан у UniGetUI док се Chocolatey не инсталира на систему и UniGetUI не рестартује. Апликације претходно инсталиране преко UniGetUI-овог уграђеног Chocolatey-ја могу и даље бити видљиве у другим изворима као што су Локални рачунар или WinGet.", + "NOTE: This troubleshooter can be disabled from UniGetUI Settings, on the WinGet section": "НАПОМЕНА: Овај решавач проблема може се онемогућити у UniGetUI подешавањима, у WinGet одељку", + "Restart": "Поново покрени", + "Are you sure you want to delete all shortcuts?": "Да ли си сигуран да желиш да обришеш све пречице?", + "Any new shorcuts created during an install or an update operation will be deleted automatically, instead of showing a confirmation prompt the first time they are detected.": "Све нове пречице креиране током инсталације или ажурирања биће аутоматски обрисане, уместо приказивања прозора за потврду при првом откривању.", + "Any shorcuts created or modified outside of UniGetUI will be ignored. You will be able to add them via the {0} button.": "Све пречице креиране или измењене ван UniGetUI биће игнорисане. Моћи ћеш да их додаш помоћу дугмета {0}.", + "Are you really sure you want to enable this feature?": "Да ли си заиста сигуран да желиш да омогућиш ову функцију?", + "No new shortcuts were found during the scan.": "Током скенирања нису пронађене нове пречице.", + "How to add packages to a bundle": "Како додати пакете у скуп пакета", + "In order to add packages to a bundle, you will need to: ": "Да би додао пакете у скуп пакета, требаће ти: ", + "1. Navigate to the \"{0}\" or \"{1}\" page.": "1. Иди на \"{0}\" или \"{1}\" страну.", + "2. Locate the package(s) you want to add to the bundle, and select their leftmost checkbox.": "2. Пронађи пакет(е) које желиш да додаш у скуп пакета, и означи њихово крајње лево поље за потврду.", + "3. When the packages you want to add to the bundle are selected, find and click the option \"{0}\" on the toolbar.": "3. Када су пакети које желиш да додаш у скуп пакета изабрани, пронађи и кликни на опцију \"{0}\" на траци са алатима.", + "4. Your packages will have been added to the bundle. You can continue adding packages, or export the bundle.": "4. Твоји пакети су додати у скуп пакета. Можеш да наставиш са додавањем пакета, или да извезеш скуп пакета.", + "Which backup do you want to open?": "Коју резервну копију желиш да отвориш?", + "Select the backup you want to open. Later, you will be able to review which packages you want to install.": "Изабери резервну копију коју желиш да отвориш. Касније ћеш моћи да прегледаш које пакете/програме желиш да вратиш.", + "There are ongoing operations. Quitting UniGetUI may cause them to fail. Do you want to continue?": "Операције су у току. Напуштање UniGetUI-ја може довести до њиховог неуспеха. Да ли желиш да наставиш?", + "UniGetUI or some of its components are missing or corrupt.": "UniGetUI или неке његове компоненте недостају или су оштећене.", + "It is strongly recommended to reinstall UniGetUI to adress the situation.": "Строго се препоручује да поново инсталираш UniGetUI да би решио ситуацију.", + "Refer to the UniGetUI Logs to get more details regarding the affected file(s)": "Погледај UniGetUI дневнике да добијеш више детаља о погођеним датотекама", + "Integrity checks can be disabled from the Experimental Settings": "Провере интегритета могу се онемогућити у експерименталним подешавањима", + "Repair UniGetUI": "Поправи UniGetUI", + "Live output": "Излаз уживо", + "This package bundle had some settings that are potentially dangerous, and may be ignored by default.": "Овај пакет је имао нека подешавања која су потенцијално опасна и могу бити подразумевано игнорисана.", + "Entries that show in YELLOW will be IGNORED.": "Уноси приказани ЖУТО биће ИГНОРИСАНИ.", + "Entries that show in RED will be IMPORTED.": "Уноси приказани ЦРВЕНО биће УВЕЗЕНИ.", + "You can change this behavior on UniGetUI security settings.": "Можеш променити ово понашање у UniGetUI безбедносним подешавањима.", + "Open UniGetUI security settings": "Отвори UniGetUI безбедносна подешавања", + "Should you modify the security settings, you will need to open the bundle again for the changes to take effect.": "Ако измениш безбедносна подешавања, мораћеш поново да отвориш пакет да би промене ступиле на снагу.", + "Details of the report:": "Детаљи извештаја:", + "Are you sure you want to create a new package bundle? ": "Да ли си сигуран да желиш да креираш нови скуп пакета?", + "Any unsaved changes will be lost": "Све несачуване измене биће изгубљене", + "Warning!": "Упозорење!", + "For security reasons, custom command-line arguments are disabled by default. Go to UniGetUI security settings to change this. ": "Из безбедносних разлога, прилагођени аргументи командне линије су подразумевано онемогућени. Иди у UniGetUI безбедносна подешавања да то промениш. ", + "Change default options": "Промени подразумеване опције", + "Ignore future updates for this package": "Игнориши будућа ажурирања за овај пакет", + "For security reasons, pre-operation and post-operation scripts are disabled by default. Go to UniGetUI security settings to change this. ": "Из безбедносних разлога, скрипте пре и после операције су подразумевано онемогућене. Иди у UniGetUI безбедносна подешавања да то промениш. ", + "You can define the commands that will be run before or after this package is installed, updated or uninstalled. They will be run on a command prompt, so CMD scripts will work here.": "Можеш дефинисати команде које ће се извршити пре или после него што се овај пакет инсталира, ажурира или деинсталира. Извршаваће се у командном прозору, тако да ће CMD скрипте радити овде.", + "Change this and unlock": "Измени ово и откључај", + "{0} Install options are currently locked because {0} follows the default install options.": "{0} опције инсталације су тренутно закључане јер {0} прати подразумеване опције инсталације.", + "Unset or unknown": "Неподешено или непознато", + "This package has no screenshots or is missing the icon? Contrbute to UniGetUI by adding the missing icons and screenshots to our open, public database.": "Овај пакет нема снимак екрана или му недостаје икона? Дај допринос UniGetUI додавањем икона и снимака екрана који недостају у нашу отворену, јавну базу података.", + "Become a contributor": "Постани доприносилац", + "Update to {0} available": "Ажурирање на {0} доступно", + "Reinstall": "Поново инсталирај", + "Installer not available": "Инсталер није доступан", + "Version:": "Верзија:", + "UniGetUI Version {0}": "UniGetUI Верзија {0}", + "Performing backup, please wait...": "Прављење резервне копије, молимо сачекај...", + "An error occurred while logging in: ": "Дошло је до грешке при пријављивању:", + "Fetching available backups...": "Прибављање доступних резервних копија...", + "Done!": "Готово!", + "The cloud backup has been loaded successfully.": "Резервна копија у облаку је успешно учитана.", + "An error occurred while loading a backup: ": "Дошло је до грешке при учитавању резервне копије:", + "Backing up packages to GitHub Gist...": "Прављење резервне копије пакета на GitHub Gist...", + "Backup Successful": "Резервна копија је успешно направљена", + "The cloud backup completed successfully.": "Резервна копија у облаку је успешно завршена.", + "Could not back up packages to GitHub Gist: ": "Није могуће направити резервну копију пакета на GitHub Gist:", + "It is not guaranteed that the provided credentials will be stored safely, so you may as well not use the credentials of your bank account": "Није загарантовано да ће достављени акредитиви бити безбедно сачувани, па је најбоље да не користиш акредитиве свог банковног налога", + "Enable the automatic WinGet troubleshooter": "Омогући аутоматски WinGet решавач проблема", + "Add updates that fail with a 'no applicable update found' to the ignored updates list": "Додај ажурирања која не успеју са ‘није пронађено примењиво ажурирање’ на листу игнорисаних ажурирања.", + "Invalid selection": "Неважећи избор", + "No package was selected": "Ниједан пакет није изабран", + "More than 1 package was selected": "Изабрано је више од 1 пакета", + "List": "Листа", + "Grid": "Мрежа", + "Icons": "Иконе", + "\"{0}\" is a local package and does not have available details": "\"{0}\" је локални пакет и нема доступних детаља", + "\"{0}\" is a local package and is not compatible with this feature": "\"{0}\" је локални пакет и није компатибилан са овом функцијом", + "Add packages to bundle": "Додај пакете у скуп пакета", + "Preparing packages, please wait...": "Припрема пакета, молимо сачекај...", + "Loading packages, please wait...": "Учитавање пакета, молимо сачекај...", + "Saving packages, please wait...": "Чување пакета, молимо сачекај...", + "The bundle was created successfully on {0}": "Пакет је успешно направљен на {0}", + "User profile": "Кориснички профил", + "Error": "Грешка", + "Log in failed: ": "Пријава није успела: ", + "Log out failed: ": "Одјава није успела: ", + "Package backup settings": "Подешавања резервне копије пакета", + "Package managers": "Менаџери пакета", + "Manage UniGetUI autostart behaviour from the Settings app": "Управљај понашањем аутоматског покретања UniGetUI-а", + "Choose how many operations shoulds be performed in parallel": "Изабери колико операција треба да се извршава паралелно", + "Something went wrong while launching the updater.": "Нешто је пошло наопако при покретању ажурирача.", + "Please try again later": "Покушај поново касније", + "Show the release notes after UniGetUI is updated": "Прикажи белешке о верзијама након ажурирања UniGetUI-а" +} diff --git a/src/Languages/lang_sv.json b/src/Languages/lang_sv.json new file mode 100644 index 0000000..905cc70 --- /dev/null +++ b/src/Languages/lang_sv.json @@ -0,0 +1,851 @@ +{ + "{0} of {1} operations completed": "{0} av {1} åtgärder slutförda", + "{0} is now {1}": "{0} är nu {1}", + "Enabled": "Aktiverad", + "Disabled": "Inaktiverad", + "Privacy": "Integritet", + "Hide my username from the logs": "Dölj mitt användarnamn i loggarna", + "Replaces your username with **** in the logs. Restart UniGetUI to also hide it from already-recorded entries.": "Ersätter ditt användarnamn med **** i loggarna. Starta om UniGetUI för att även dölja det i redan registrerade poster.", + "Your last update attempt did not complete.": "Ditt senaste uppdateringsförsök slutfördes inte.", + "UniGetUI could not confirm whether the update succeeded. Open the log to see what happened.": "UniGetUI kunde inte bekräfta om uppdateringen lyckades. Öppna loggen för att se vad som hände.", + "View log": "Visa logg", + "The installer reported success but did not restart UniGetUI.": "Installationsprogrammet rapporterade att åtgärden lyckades men startade inte om UniGetUI.", + "The installer failed to initialize.": "Installationsprogrammet kunde inte initieras.", + "Setup was canceled before installation began.": "Installationen avbröts innan den påbörjades.", + "A fatal error occurred during the preparation phase.": "Ett allvarligt fel uppstod under förberedelsefasen.", + "A fatal error occurred during installation.": "Ett allvarligt fel uppstod under installationen.", + "Installation was canceled while in progress.": "Installationen avbröts medan den pågick.", + "The installer was terminated by another process.": "Installationsprogrammet avslutades av en annan process.", + "The preparation phase determined the installation cannot proceed.": "Förberedelsefasen fastställde att installationen inte kan fortsätta.", + "The installer could not start. UniGetUI may already be running, or you do not have permission to install.": "Installationsprogrammet kunde inte startas. UniGetUI kanske redan körs, eller så saknar du behörighet att installera.", + "Unexpected installer error.": "Oväntat fel i installationsprogrammet.", + "We are checking for updates.": "Söker efter uppdateringar.", + "Please wait": "Vänligen vänta", + "Great! You are on the latest version.": "Grattis! Du använder senaste versionen.", + "There are no new UniGetUI versions to be installed": "Det finns ingen nyare UniGetUI version att installera", + "UniGetUI version {0} is being downloaded.": "UniGetUI version {0} laddas nu ned.", + "This may take a minute or two": "Detta kan ta en minut eller två", + "The installer authenticity could not be verified.": "Installerarens äkthet kunde inte verifieras.", + "The update process has been aborted.": "Uppdateringsprocessen har avbrutits", + "Auto-update is not yet available on this platform.": "Automatisk uppdatering är ännu inte tillgänglig på den här plattformen.", + "Please update UniGetUI manually.": "Uppdatera UniGetUI manuellt.", + "An error occurred when checking for updates: ": "Ett fel inträffade när uppdateringssökningen skulle genomföras:", + "The updater could not be launched.": "Uppdateringsprogrammet kunde inte startas.", + "The operating system did not start the installer process.": "Operativsystemet startade inte installationsprocessen.", + "UniGetUI is being updated...": "UniGetUI uppdateras...", + "Update installed.": "Uppdateringen installerades.", + "UniGetUI was updated successfully, but this running copy was not replaced. This usually means you are running a development build. Close this copy and start the newly-installed version to finish.": "UniGetUI uppdaterades, men den här körande kopian ersattes inte. Det betyder vanligtvis att du kör en utvecklingsversion. Stäng den här kopian och starta den nyinstallerade versionen för att slutföra.", + "The update could not be applied.": "Uppdateringen kunde inte tillämpas.", + "Installer exit code {0}: {1}": "Installationsprogrammets avslutningskod {0}: {1}", + "Update cancelled.": "Uppdateringen avbröts.", + "Authentication was cancelled.": "Autentiseringen avbröts.", + "Installer exit code {0}": "Installationsprogrammets avslutningskod {0}", + "Operation in progress": "Åtgärd pågår", + "Please wait...": "Vänligen vänta...", + "Success!": "Lyckades!", + "Failed": "Misslyckad", + "An error occurred while processing this package": "Ett fel inträffade i samband med att det här paketet skulle bearbetas", + "Installer": "Installerare", + "Executable": "Körbar fil", + "MSI": "MSI", + "Compressed file": "Komprimerad fil", + "MSIX": "MSIX", + "WinGet was repaired successfully": "WinGet har reparerats", + "It is recommended to restart UniGetUI after WinGet has been repaired": "Rekommenderar att du startar om UniGetUI efter att Winget blivit reparerad", + "WinGet could not be repaired": "WinGet kunde inte repareras", + "An unexpected issue occurred while attempting to repair WinGet. Please try again later": "Ett oväntat fel uppstod vid försök att reparera WinGet. Vänligen prova igen senare", + "Log in to enable cloud backup": "Logga in för att aktivera molnsäkerhetskopia", + "Backup Failed": "Säkerhetskopiering misslyckades", + "Downloading backup...": "Laddar ner säkerhetskopia...", + "An update was found!": "En uppdatering hittades!", + "{0} can be updated to version {1}": "{0} kan uppdateras till version {1}", + "Updates found!": "Uppdateringar hittade!", + "{0} packages can be updated": "{0} paket kan uppdateras", + "{0} is being updated to version {1}": "{0} uppdateras till version {1}", + "{0} packages are being updated": "{0} paket uppdateras", + "You have currently version {0} installed": "Du har just nu version {0} installerad", + "Desktop shortcut created": "Skrivbordsgenväg skapad", + "UniGetUI has detected a new desktop shortcut that can be deleted automatically.": "UniGetUI har hittat ett nytt skrivbordsgenvän som kan tas bort automatiskt.", + "{0} desktop shortcuts created": "{0} skrivbordsgenväg skapades", + "UniGetUI has detected {0} new desktop shortcuts that can be deleted automatically.": "UniGetUI har hittat {0} nytt skrivbordsgenväg som kan tas bort automatiskt.", + "Attention required": "Uppmärksamhet krävs", + "Restart required": "Omstart krävs", + "1 update is available": "1 uppdatering tillgänglig", + "{0} updates are available": "{0} uppdateringar är tillgängliga", + "Everything is up to date": "Allt är uppdaterat", + "Discover Packages": "Upptäck paket", + "Available Updates": "Tillgängliga uppdateringar", + "Installed Packages": "Installerade paket", + "UniGetUI Version {0} by Devolutions": "UniGetUI version {0} av Devolutions", + "Show UniGetUI": "Visa UniGetUI", + "Quit": "Avsluta", + "Are you sure?": "Är du säker?", + "Do you really want to uninstall {0}?": "Vill du verkligen avinstallera {0}?", + "Do you really want to uninstall the following {0} packages?": "Vill du verkligen avinstallera följande {0}-paket?", + "No": "Nej", + "Yes": "Ja", + "Partial": "Delvis", + "View on UniGetUI": "Visa i UniGetUI", + "Update": "Uppdatera", + "Open UniGetUI": "Öppna UniGetUI", + "Update all": "Uppdatera alla", + "Update now": "Uppdatera nu", + "Installer host changed since the installed version.\n": "Installationsprogrammets värd har ändrats sedan den installerade versionen.\n", + "This package is on the queue": "Paketet är i kö", + "installing": "installeras", + "updating": "uppdaterar", + "uninstalling": "avinstallerar", + "installed": "installerad", + "Retry": "Försök igen", + "Install": "Installera", + "Uninstall": "Avinstallera", + "Open": "Öppna", + "Operation profile:": "Åtgärdsprofil", + "Follow the default options when installing, upgrading or uninstalling this package": "Följ standardinställningen när du installerar, uppgraderar och avinstallerar denna paket", + "The following settings will be applied each time this package is installed, updated or removed.": "Följande inställningar kommer att tillämpas varje gång detta paket installeras, uppdateras eller avinstalleras.", + "Version to install:": "Version att installera:", + "Architecture to install:": "Arkitektur att installera:", + "Installation scope:": "Installationsomfång:", + "Install location:": "Installationsplats:", + "Select": "Välj", + "Reset": "Återställ", + "Custom install arguments:": "Anpassade installationsargument:", + "Custom update arguments:": "Anpassade uppdateringsargument", + "Custom uninstall arguments:": "Anpassade avinstallationsargument", + "Pre-install command:": "Pre-install kommando:", + "Post-install command:": "Post-install kommando:", + "Abort install if pre-install command fails": "Avbryt installationen om kommandot pre-install misslyckas", + "Pre-update command:": "Pre-update kommando:", + "Post-update command:": "Post-update kommando:", + "Abort update if pre-update command fails": "Avbryt uppdateringen om kommandot pre-update misslyckas", + "Pre-uninstall command:": "Pre-uninstall kommando:", + "Post-uninstall command:": "Post-uninstall kommando:", + "Abort uninstall if pre-uninstall command fails": "Avbryt avinstallationen om kommandot pre-uninstall misslyckas", + "Command-line to run:": "Kommandorad att köra:", + "Save and close": "Spara och stäng", + "General": "Allmänt", + "Architecture & Location": "Arkitektur och plats", + "Command-line": "Kommandorad", + "Close apps": "Stäng appar", + "Pre/Post install": "Före-/efterinstallation", + "Select the processes that should be closed before this package is installed, updated or uninstalled.": "Välj de processer som bör stängas innan paketet installeras, uppdateras eller avinstalleras.", + "Write here the process names here, separated by commas (,)": "Skriv in processnamnen här, skilj åt med komma (,)", + "Try to kill the processes that refuse to close when requested to": "Försök att avsluta den process som inte vill stänga", + "Run as admin": "Kör som admin", + "Interactive installation": "Interaktiv installation", + "Skip hash check": "Ignorera hash-kontroll", + "Uninstall previous versions when updated": "Avinstallera föregående versioner vid uppdatering", + "Skip minor updates for this package": "Ignorera mindre uppdateringar för denna paket", + "Automatically update this package": "Uppdatera det här paketet automatiskt", + "{0} installation options": "{0} installationsalternativ", + "Latest": "Senaste", + "PreRelease": "Förhandsutgåva", + "Default": "Standard", + "Manage ignored updates": "Hantera ignorerade uppdateringar", + "The packages listed here won't be taken in account when checking for updates. Double-click them or click the button on their right to stop ignoring their updates.": "Paketen listade här kommer inte tas hänsyn till vid uppdatering. Dubbelklicka på dem eller klicka på knappen till höger om dessa för att sluta ignorera dessa uppdateringar.", + "Reset list": "Återställ lista", + "Do you really want to reset the ignored updates list? This action cannot be reverted": "Vill du verkligen återställa listan över ignorerade uppdateringar? Den här åtgärden kan inte ångras", + "No ignored updates": "Inga ignorerade uppdateringar", + "Package Name": "Paketnamn", + "Package ID": "Paket ID", + "Ignored version": "Ignorerad version", + "New version": "Ny version", + "Source": "Källa", + "All versions": "Alla versioner", + "Unknown": "Okänd", + "Up to date": "Senaste versionen", + "Package {name} from {manager}": "Paket {name} från {manager}", + "Remove {0} from ignored updates": "Ta bort {0} från ignorerade uppdateringar", + "Cancel": "Avbryt", + "Administrator privileges": "Administratörsrättigheter", + "This operation is running with administrator privileges.": "Denna åtgärd körs med adminrättigheter.", + "Interactive operation": "Interaktiv åtgärd", + "This operation is running interactively.": "Denna åtgärd körs interaktivt.", + "You will likely need to interact with the installer.": "Du måste troligen interagera med installeraren.", + "Integrity checks skipped": "Integritetskontrollerna ignorerades", + "Integrity checks will not be performed during this operation.": "Integritetskontroller kommer inte att utföras under den här åtgärden.", + "Proceed at your own risk.": "Fortsätt på egen risk", + "Close": "Stäng", + "Loading...": "Laddar...", + "Installer SHA256": "Installation SHA256", + "Homepage": "Websida", + "Author": "Upphovsman", + "Publisher": "Utgivare", + "License": "Licens", + "Manifest": "Manifest", + "Installer Type": "Installations typ", + "Size": "Storlek", + "Installer URL": "Installations URL", + "Last updated:": "Senast uppdaterad:", + "Release notes URL": " Versionsinformation URL", + "Package details": "Paketdetaljer", + "Dependencies:": "Underordnad:", + "Release notes": "Versionsinformation", + "Screenshots": "Skärmbilder", + "This package has no screenshots or is missing the icon? Contribute to UniGetUI by adding the missing icons and screenshots to our open, public database.": "Saknar det här paketet skärmbilder eller ikon? Bidra till UniGetUI genom att lägga till de saknade ikonerna och skärmbilderna i vår öppna, offentliga databas.", + "Version": "Version", + "Install as administrator": "Installera som administratör", + "Update to version {0}": "Uppdatera till version {0}", + "Installed Version": "Installerad version", + "Update as administrator": "Uppdatera som administratör", + "Interactive update": "Interaktiv uppdatering", + "Uninstall as administrator": "Avinstallera som administratör", + "Interactive uninstall": "Interaktiv avinstallation", + "Uninstall and remove data": "Avinstallera och ta bort data", + "Not available": "Inte tillgänglig", + "Installer SHA512": "Installation SHA512", + "Unknown size": "Okänd storlek", + "No dependencies specified": "Inga specificerade komponenter", + "mandatory": "obligatorisk", + "optional": "valfri", + "UniGetUI {0} is ready to be installed.": "UniGetUI {0} är redo att installeras.", + "The update process will start after closing UniGetUI": "Uppdateringen startar när UniGetUI stängs", + "UniGetUI has been ran as administrator, which is not recommended. When running UniGetUI as administrator, EVERY operation launched from UniGetUI will have administrator privileges. You can still use the program, but we highly recommend not running UniGetUI with administrator privileges.": "UniGetUI har körts som administratör, vilket inte rekommenderas. När UniGetUI körs som administratör kommer ALLA åtgärder som startas från UniGetUI att ha administratörsbehörighet. Du kan fortfarande använda programmet, men vi rekommenderar starkt att du inte kör UniGetUI med administratörsbehörighet.", + "Share anonymous usage data": "Dela anonym användardata", + "UniGetUI collects anonymous usage data in order to improve the user experience.": "UniGetUI hämtar anonym data för att förbättra användarupplevelsen.", + "Accept": "Acceptera", + "Software Updates": "Uppdateringar", + "Package Bundles": "Paketgrupper", + "Settings": "Inställningar", + "Package Managers": "Pakethanterare", + "UniGetUI Log": "UniGetUI-logg", + "Package Manager logs": "Pakethanterarens loggar", + "Operation history": "Åtgärdshistorik", + "Help": "Hjälp", + "UniGetUI": "UniGetUI", + "You have installed UniGetUI Version {0}": "Du har installerat UniGetUI version {0}", + "Disclaimer": "Ansvarsfriskrivning", + "UniGetUI is developed by Devolutions and is not affiliated with any of the compatible package managers.": "UniGetUI utvecklas av Devolutions och är inte anslutet till någon av de kompatibla pakethanterarna.", + "UniGetUI wouldn't have been possible without the help of the contributors. Thank you all 🥳": "UniGetUI skulle inte finns utan all hjälp från våra medarbetare. Ett stort tack! 🥳", + "UniGetUI uses the following libraries. Without them, UniGetUI wouldn't have been possible.": "UniGetUI använder följande bibliotek. Utan dessa hade inte UniGetUI funnits.", + "{0} homepage": "{0} websida", + "UniGetUI has been translated to more than 40 languages thanks to the volunteer translators. Thank you 🤝": "UniGetUI är översatt till mer än 40 språk tack vara våra frivilliga översättare. Tack 🤝", + "Verbose": "Utökad", + "1 - Errors": "1 - Fel", + "2 - Warnings": "2 - Varningar", + "3 - Information (less)": "3 - Information (mindre)", + "4 - Information (more)": "4 - information (mer)", + "5 - information (debug)": "5 - Information (felsokning)", + "Warning": "Varning", + "The following settings may pose a security risk, hence they are disabled by default.": "Följander inställningar kan innebär en säkerhetsrisk och därför är det inaktiverad som standard.", + "Enable the settings below if and only if you fully understand what they do, and the implications they may have.": "Aktivera nedanstående inställningar BARA OCH ENDAST OM du helt och fullt förstår vad de gör, eventuella konsekvenser och vilken fara detta kan medföra.", + "The settings will list, in their descriptions, the potential security issues they may have.": "Inställningarna visar i dess beskrivning vilka eventuella säkerhetsrisker de kan ha.", + "The backup will include the complete list of the installed packages and their installation options. Ignored updates and skipped versions will also be saved.": "Säkerhetskopia inkluderar en komplett lista över installerade paket och dess installationsinställningar. Ignorerade uppdateringar och version kommer också att sparas.", + "The backup will NOT include any binary file nor any program's saved data.": "Säkerhetskopian kommer INTE att inkludera några binärä filer eller sparas data från något program.", + "The size of the backup is estimated to be less than 1MB.": "Säkerhetskopians storlek är beräknad till mindre än 1 MB.", + "The backup will be performed after login.": "Säkerhetskopiering kommer att utföras efter inloggning.", + "{pcName} installed packages": "{pcName} installerade paket", + "Current status: Not logged in": "Nuvarande status: Inte inloggad", + "You are logged in as {0} (@{1})": "Du är inloggad som {0} (@{1})", + "Nice! Backups will be uploaded to a private gist on your account": "Fint! Säkerhetskopior kommer att laddas upp till en privat gist på ditt konto", + "Select backup": "Välj säkerhetskopia", + "Settings imported from {0}": "Inställningar importerade från {0}", + "UniGetUI Settings": "UniGetUI-inställningar", + "Settings exported to {0}": "Inställningar exporterade till {0}", + "UniGetUI settings were reset": "UniGetUI-inställningar återställdes", + "Allow pre-release versions": "Tillåt förhandsversioner", + "Apply": "Tillämpa", + "For security reasons, custom command-line arguments are disabled by default. Go to UniGetUI security settings to change this.": "Av säkerhetsskäl är anpassade kommandoradsargument inaktiverade som standard. Gå till UniGetUI:s säkerhetsinställningar för att ändra detta.", + "Go to UniGetUI security settings": "Gå till UniGetUI säkerhetsinställningar", + "The following options will be applied by default each time a {0} package is installed, upgraded or uninstalled.": "Följäande åtgärder kommer tillämpas som standard varje gång en {0} paket installeras, uppgraderas eller avinstalleras.", + "Package's default": "Paketets standardvärden", + "Install location can't be changed for {0} packages": "Installationsplatsen kan inte ändras för {0} paketen", + "The local icon cache currently takes {0} MB": "Lokala ikoncache upptar för närvarande {0} MB", + "Username": "Användarnamn", + "Password": "Lösenord", + "Credentials": "Inloggningsuppgifter", + "It is not guaranteed that the provided credentials will be stored safely": "Det kan inte garanteras att de angivna inloggningsuppgifterna lagras säkert", + "Partially": "Delvis", + "Package manager": "Pakethanterare", + "Compatible with proxy": "Kompatibel med proxy", + "Compatible with authentication": "Kompatibel med autentisering", + "Proxy compatibility table": "Proxy kompabilitetstabell", + "{0} settings": "{0} inställningar", + "{0} status": "{0} status", + "Default installation options for {0} packages": "Standard installationsinställning för {0} paket", + "Expand version": "Expandera version", + "The executable file for {0} was not found": "Körbara filen för {0} kunde inte hittas", + "{pm} is disabled": "{pm} är inaktiverad", + "Enable it to install packages from {pm}.": "Aktivera den för att installera paket från {pm}.", + "{pm} is enabled and ready to go": "{pm} är tillgänglig och redo att användas", + "{pm} version:": "{pm} version:", + "{pm} was not found!": "{pm} kunde inte hittas!", + "You may need to install {pm} in order to use it with UniGetUI.": "Du kan behöva installera {pm} för att kunna använda den med UniGetUI.", + "Scoop Installer - UniGetUI": "Scoop installerare - UniGetUI", + "Scoop Uninstaller - UniGetUI": "Scoop avinstallerare - UniGetUI", + "Clearing Scoop cache - UniGetUI": "Rensa Scoop-cache - UniGetUI", + "Restart UniGetUI to fully apply changes": "Starta om UniGetUI för att tillämpa ändringarna fullt ut", + "Restart UniGetUI": "Starta om UniGetUI", + "Manage {0} sources": "Hantera {0} källor", + "Add source": "Lägg till källa", + "Add": "Lägg till", + "Source name": "Källnamn", + "Source URL": "Käll-URL", + "Other": "Övrigt", + "No minimum age": "Ingen minimiålder", + "1 day": "1 dag", + "{0} days": "{0} dagar", + "Custom...": "Anpassad...", + "{0} minutes": "{0} minuter", + "1 hour": "1 timme", + "{0} hours": "{0} timmar", + "1 week": "1 vecka", + "Supports release dates": "Stöder utgivningsdatum", + "Release date support per package manager": "Stöd för utgivningsdatum per pakethanterare", + "Search for packages": "Sök efter paket", + "Local": "Lokal", + "OK": "OK", + "Last checked: {0}": "Senast kontrollerad: {0}", + "{0} packages were found, {1} of which match the specified filters.": "{1} paket hittades, varav {0} matchade filtret", + "{0} selected": "{0} valda", + "(Last checked: {0})": "(Kontrollerades senast: {0})", + "All packages selected": "Alla paket valda", + "Package selection cleared": "Paketval rensat", + "{0}: {1}": "{0}: {1}", + "More info": "Mer info", + "GitHub account": "GitHub-konto", + "Log in with GitHub to enable cloud package backup.": "Logga in med GitHub för att aktivera molnsäkerhetskopia av paket", + "More details": "Mer detaljer", + "Log in": "Logga in", + "If you have cloud backup enabled, it will be saved as a GitHub Gist on this account": "Om du har molnsäkerheskopia valt, kommer den sparas som en GitHub Gist på denna konto", + "Log out": "Logga ut", + "About UniGetUI": "Om UniGetUI", + "About": "Om", + "Third-party licenses": "Tredjepartslicenser", + "Contributors": "Bidragsgivare", + "Translators": "Översättare", + "Bundle security report": "Säkerhetsrapport för paketgruppen", + "The bundle contained restricted content": "Bunten innehöll begränsat innehåll", + "UniGetUI – Crash Report": "UniGetUI – Kraschrapport", + "UniGetUI has crashed": "UniGetUI har kraschat", + "Help us fix this by sending a crash report to Devolutions. All fields below are optional.": "Hjälp oss att åtgärda detta genom att skicka en kraschrapport till Devolutions. Alla fält nedan är valfria.", + "Email (optional)": "E-post (valfritt)", + "your@email.com": "din@epost.se", + "Additional details (optional)": "Ytterligare detaljer (valfritt)", + "Describe what you were doing when the crash occurred…": "Beskriv vad du gjorde när kraschen inträffade…", + "Crash report": "Kraschrapport", + "Don't Send": "Skicka inte", + "Send Report": "Skicka rapport", + "Sending…": "Skickar…", + "Unsaved changes": "Osparade ändringar", + "You have unsaved changes in the current bundle. Do you want to discard them?": "Du har osparade ändringar i den aktuella bunten. Vill du förkasta dem?", + "Discard changes": "Förkasta ändringar", + "Integrity violation": "Integritetsöverträdelse", + "UniGetUI or some of its components are missing or corrupt. It is strongly recommended to reinstall UniGetUI to adress the situation.": "UniGetUI eller några av dess komponenter saknas eller är skadade. Det rekommenderas starkt att installera om UniGetUI för att åtgärda situationen.", + "• Refer to the UniGetUI Logs to get more details regarding the affected file(s)": "• Hänvisar till UniGetUI:s loggar för mer detaljerad information om påverkad(e) filer.", + "• Integrity checks can be disabled from the Experimental Settings": "• Integritetskontroller kan stängas av från Experimentinställningar", + "Manage shortcuts": "Hantera genvägar", + "UniGetUI has detected the following desktop shortcuts which can be removed automatically on future upgrades": "UniGetUI har hittat följande skrivsbordsgenväg som kan tas bort automatiskt på kommande uppgraderingar", + "Do you really want to reset this list? This action cannot be reverted.": "Vill du verkligen nollställa denna lista? Åtgärden kan inte ångras.", + "Desktop shortcuts list": "Lista över skrivbordsgenvägar", + "Open in explorer": "Öppna i Utforskaren", + "Remove from list": "Ta bort från listan", + "When new shortcuts are detected, delete them automatically instead of showing this dialog.": "När nya genvägar hittas, raderas de automatiskt istället för att visa denna dialog.", + "Not right now": "Inte just nu", + "Missing dependency": "Saknat beroende", + "UniGetUI requires {0} to operate, but it was not found on your system.": "UniGetUI kräver {0} för att fungera, men den kan inte hittas i ditt system.", + "Click on Install to begin the installation process. If you skip the installation, UniGetUI may not work as expected.": "Klicka på installera för att påbörja installation. UniGetUI kan bete sig annorlunda ifall du hoppar över installationen.", + "Alternatively, you can also install {0} by running the following command in a Windows PowerShell prompt:": "Alternativt så kan du även installera {0} genom att köra följande kommando i Windows PowerShell-prompten:", + "Install {0}": "Installera {0}", + "Do not show this dialog again for {0}": "Visa inte denna dialog igen för {0}", + "Please wait while {0} is being installed. A black window may show up. Please wait until it closes.": "Vänligen vänta medan {0} blir installerad. En svart (eller blå) fönster kan dyka upp. Vänta tills den stängs.", + "{0} has been installed successfully.": "{0} installerades", + "Please click on \"Continue\" to continue": "Vänligen klicka på \"Fortsätt\" för att fortsätta", + "Continue": "Fortsätt", + "{0} has been installed successfully. It is recommended to restart UniGetUI to finish the installation": "{0} installerades. Rekommenderar omstart av UniGetUI för att slutföra installationen", + "Restart later": "Starta om senare", + "An error occurred:": "Ett fel inträffade:", + "Please see the Command-line Output or refer to the Operation History for further information about the issue.": "Se kommandoradens utdata eller se Operation History för mer information om problemet.", + "Retry as administrator": "Försök igen som administatör", + "Retry interactively": "Försök igen interaktivt", + "Retry skipping integrity checks": "Försök att ignorera integritetskontrollerna igen", + "Installation options": "Installationsalternativ", + "Save": "Spara", + "UniGetUI collects anonymous usage data with the sole purpose of understanding and improving the user experience.": "UniGetUI hämtar anonymiserad användardata endast för att förstå och förbättra användarupplevelsen.", + "More details about the shared data and how it will be processed": "Mer information gällande delad data och hur det hanteras", + "Do you accept that UniGetUI collects and sends anonymous usage statistics, with the sole purpose of understanding and improving the user experience?": "Accepterar du att UniGetUI samlar in och skickar anonym användarstatistik? Den används endast för att förstå och förbättra använderupplevelsen.", + "Decline": "Avböj", + "No personal information is collected nor sent, and the collected data is anonimized, so it can't be back-tracked to you.": "Personlig information samlas inte in eller skickas vidare. All insamlad data är anonymiserat och kan inte spåras tillbaka till dig.", + "Navigation panel": "Navigeringspanel", + "Operations": "Åtgärder", + "Toggle operations panel": "Visa/dölj åtgärdspanelen", + "Bulk operations": "Massåtgärder", + "Retry failed": "Försök igen med misslyckade", + "Clear successful": "Rensa lyckade", + "Clear finished": "Rensa slutförda", + "Cancel all": "Avbryt alla", + "More": "Mer", + "Toggle navigation panel": "Växla navigeringspanelen", + "Minimize": "Minimera", + "Maximize": "Maximera", + "UniGetUI by Devolutions": "UniGetUI av Devolutions", + "UniGetUI is an application that makes managing your software easier, by providing an all-in-one graphical interface for your command-line package managers.": "UniGetUI är ett program som mjukvaruhanteringen enklare genom att erbjuda ett tilltalande grafiskt gränssnitt för dina kommandorads pakethanterare.", + "Useful links": "Användbara länkar", + "UniGetUI Homepage": "UniGetUI:s hemsida", + "Report an issue or submit a feature request": "Rapportera fel eller skicka begäran om förbättringar", + "UniGetUI Repository": "UniGetUI:s kodförråd", + "View GitHub Profile": "Visa GitHub-profil", + "UniGetUI License": "UniGetUI-licens", + "Using UniGetUI implies the acceptation of the MIT License": "Användning av UniGetUI innebär att du accepterar MIT licensen", + "Become a translator": "Bli en översättare", + "Go back": "Gå tillbaka", + "Go forward": "Gå framåt", + "Go to home page": "Gå till startsidan", + "Reload page": "Ladda om sidan", + "View page on browser": "Visa sidan i webbläsaren", + "The built-in browser is not supported on Linux yet.": "Den inbyggda webbläsaren stöds inte på Linux ännu.", + "Open in browser": "Öppna i webbläsare", + "Copy to clipboard": "Kopiera till urklipp", + "Export to a file": "Exportera till en fil", + "Log level:": "Loggnivå", + "Reload log": "Ladda om loggen", + "Export log": "Exportera logg", + "Text": "Text", + "Change how operations request administrator rights": "Ändra hur åtgärder begär adminrättigheter", + "Restrictions on package operations": "Restriktioner för paketåtgärder", + "Restrictions on package managers": "Restriktioner för pakethanterare", + "Restrictions when importing package bundles": "Restriktioner vid import av paketgrupper", + "Ask for administrator privileges once for each batch of operations": "Be om administratörsrättigheter en gång för varje omgång av åtgärder", + "Ask only once for administrator privileges": "Fråga om administratörsrättigheter endast en gång", + "Prohibit any kind of Elevation via UniGetUI Elevator or GSudo": "Förhindra all typ av behörighetshöjning via UniGetUI höjaren eller GSudo", + "This option WILL cause issues. Any operation incapable of elevating itself WILL FAIL. Install/update/uninstall as administrator will NOT WORK.": "Denna inställning KOMMER att skapa problem. Alla åtgärder som inte kan höja sig själv KOMMER MISSLYCKAS. Installering/uppdatering/avinstallering som administrator kommer INTE FUNGERA.", + "Allow custom command-line arguments": "Tillått anpassade kommandoradsargument", + "Custom command-line arguments can change the way in which programs are installed, upgraded or uninstalled, in a way UniGetUI cannot control. Using custom command-lines can break packages. Proceed with caution.": "Anpassade kommandoradsargument kan ändra hur program installeras, uppgraders eller avinstalleras på ett sätt som UniGetUI inte kan kontrollera. Användning av anpassad kommandorad kan bryta paket. Fortsätt med försiktighet.", + "Ignore custom pre-install and post-install commands when importing packages from a bundle": "Tillåt att anpassade för- och efterinstallationskommandon körs", + "Pre and post install commands will be run before and after a package gets installed, upgraded or uninstalled. Be aware that they may break things unless used carefully": "Pre och post install kommandon kommer att köras före och efter paketet blir installerad, uppgraderad eller avinstallerad. Var medveten om att de kan göra skada om man inte är försiktig", + "Allow changing the paths for package manager executables": "Tillåt ändring av sökväg för pakethanterarens körbara filer", + "Turning this on enables changing the executable file used to interact with package managers. While this allows finer-grained customization of your install processes, it may also be dangerous": "Genom att aktivera denna kan körbara filer interagera med pakethanterare. Detta möjliggör en mer exakt anpassning av installationsprocessen, men den gör den också mer farlig", + "Allow importing custom command-line arguments when importing packages from a bundle": "Tillåt importering av anpassade kommandoradsargument vid import av paket från en paket-grupp", + "Malformed command-line arguments can break packages, or even allow a malicious actor to gain privileged execution. Therefore, importing custom command-line arguments is disabled by default": "Felaktig kommandoradsargument kan förstöra paket eller tillåta att angripare utnyttjar för att få höga rättigheter. Därför är import av anpassade kommandoradsargument avstängt som standard.", + "Allow importing custom pre-install and post-install commands when importing packages from a bundle": "Tillåt importering av anpassade pre-install och post-install-kommandon när importering av paket sker från en paket-grupp", + "Pre and post install commands can do very nasty things to your device, if designed to do so. It can be very dangerous to import the commands from a bundle, unless you trust the source of that package bundle": "Pre och post install kommandon kan orsaka otäcka saker på din enhet. Det kan bli farligt att importera kommandon från en paketgrupp såvida du inte litar på källa till paketgruppen.", + "Administrator rights and other dangerous settings": "Administratörsrättigheter och andra farliga inställningar", + "Package backup": "Säkerhetskopia av paket", + "Cloud package backup": "Säkerhetskopia av molnpaketet", + "Local package backup": "Lokal säkerhetskopia av paket", + "Local backup advanced options": "Avancerade inställningar för lokala säkerhetskopior", + "Log in with GitHub": "Logga in med GitHub", + "Log out from GitHub": "Logga ut från GitHub", + "Periodically perform a cloud backup of the installed packages": "Gör periodiska molnsäkerhetskopior av installerade paket", + "Cloud backup uses a private GitHub Gist to store a list of installed packages": "Molnsäkerhetskopian använder en privat GitHub Gist för att lagra en lista över installerade paket", + "Perform a cloud backup now": "Gör en molnsäkerhetskopia nu", + "Backup": "Säkerhetskopiera", + "Restore a backup from the cloud": "Återställ säkerhetskopia från molnet", + "Begin the process to select a cloud backup and review which packages to restore": "Starta processen med att välja molnsäkerhetskopia och välj vilka paket som ska återställas", + "Periodically perform a local backup of the installed packages": "Gör periodiska lokala säkerhetskopior av installerade paket", + "Perform a local backup now": "Gör en lokal säkerhetskopia nu", + "Change backup output directory": "Ändra katalog för säkerhetskopiering", + "Set a custom backup file name": "Ställ in filnamnet för den anpassade säkerhetskopian", + "Leave empty for default": "Lämna tomt som standard", + "Add a timestamp to the backup file names": "Lägg till en tidsstämpel till säkerhetskopiornas filnamn", + "Backup and Restore": "Säkerhetskopiera och återställ", + "Enable background api (UniGetUI Widgets and Sharing, port 7058)": "Aktivera bakgrunds-API (UniGetUI Widgets and Sharing, port 7058)", + "Wait for the device to be connected to the internet before attempting to do tasks that require internet connectivity.": "Vänta tills enheten är ansluten till internet innan du börjar med uppgifter som kräver internetuppkoppling.", + "Disable the 1-minute timeout for package-related operations": "Inaktivera 1-minut timeout för paketrelaterade åtgärder", + "Use installed GSudo instead of UniGetUI Elevator": "Används installerad GSudo istället för UniGetUI höjaren", + "Use a custom icon and screenshot database URL": "Använd en anpassad icon och skärmdumps databas URL", + "Enable background CPU Usage optimizations (see Pull Request #3278)": "Aktivera bakgrunds CPU användningsoptimering (se Pull-begäran #3278)", + "Perform integrity checks at startup": "Genomför integritetskontroller vid start", + "When batch installing packages from a bundle, install also packages that are already installed": "Vid batch-installation av paket från en paketgruppen, installera även paket som är redan installerade.", + "Experimental settings and developer options": "Experimentella inställningar och utvecklaralternativ", + "Show UniGetUI's version and build number on the titlebar.": "Visa UniGetUI:s version i titelraden", + "Language": "Språk", + "UniGetUI updater": "UniGetUI updaterare", + "Telemetry": "Telemetri", + "Manage UniGetUI settings": "Hantera UniGetUI inställningar", + "Related settings": "Relaterade inställningar", + "Update UniGetUI automatically": "Uppdatera UniGetUI automatiskt", + "Check for updates": "Sök efter uppdateringar", + "Install prerelease versions of UniGetUI": "Installera förhandsversioner av UniGetUI", + "Manage telemetry settings": "Hantera telemetri-inställningar", + "Manage": "Hantera", + "Import settings from a local file": "Importera inställningar från en lokal fil", + "Import": "Importera", + "Export settings to a local file": "Exportera inställningar till en lokal fil", + "Export": "Exportera", + "Reset UniGetUI": "Återställ UniGetUI", + "User interface preferences": "Utseendeinstälningar", + "Application theme, startup page, package icons, clear successful installs automatically": "Teman, startsidor och paketikoner installeras automatiskt", + "General preferences": "Allmänna inställningar", + "UniGetUI display language:": "UniGetUI visningsspråk", + "System language": "Systemspråk", + "Is your language missing or incomplete?": "Saknas ditt språk eller är det ofullständigt?", + "Appearance": "Utseende", + "UniGetUI on the background and system tray": "UniGetUI i bakgrunden och i systemfältet", + "Package lists": "Paketlistor", + "Use classic mode": "Använd klassiskt läge", + "Restart UniGetUI to apply this change": "Starta om UniGetUI för att tillämpa den här ändringen", + "The classic UI is disabled for beta testers": "Det klassiska användargränssnittet är inaktiverat för betatestare", + "Close UniGetUI to the system tray": "Stäng ned UniGetUI till systemfältet", + "Manage UniGetUI autostart behaviour": "Hantera UniGetUI:s autostartbeteende", + "Show package icons on package lists": "Visa paketikoner på paketlistan", + "Clear cache": "Rensa cache", + "Select upgradable packages by default": "Välj uppgraderingsbara paket som standard", + "Light": "Ljust", + "Dark": "Mörk", + "Follow system color scheme": "Följ systemets färgschema", + "Application theme:": "Programtema:", + "UniGetUI startup page:": "UniGetUI:s startsida:", + "Proxy settings": "Proxyinställningar", + "Other settings": "Andra inställningar", + "Connect the internet using a custom proxy": "Anslut internet genom att använda en anpassad proxy", + "Please note that not all package managers may fully support this feature": "Vänligen notera att alla pakethanterare kanske inte fullt stöder denna funktion", + "Proxy URL": "Proxy-URL", + "Enter proxy URL here": "Ange proxyadressen här", + "Authenticate to the proxy with a user and a password": "Autentisera mot proxyn med användarnamn och lösenord", + "Internet and proxy settings": "Internet- och proxyinställningar", + "Package manager preferences": "Pakethanterarens inställningar", + "Ready": "Klar", + "Not found": "Hittades inte", + "Notification preferences": "Notifieringsinställningar", + "Notification types": "Notifieringstyper", + "The system tray icon must be enabled in order for notifications to work": "Systemfältsikonen måste aktiveras för att notifieringar ska fungera", + "Enable UniGetUI notifications": "Aktivera UniGetUI-aviseringar", + "Show a notification when there are available updates": "Visa en notifiering när en uppdatering finns tillgänglig", + "Show a silent notification when an operation is running": "Visa en tyst notifiering när en åtgärd körs", + "Show a notification when an operation fails": "Visa en notifiering när en åtgärd misslyckas", + "Show a notification when an operation finishes successfully": "Visa en notering när en åtgärd lyckas", + "Concurrency and execution": "Samtidighet och utförande", + "Automatic desktop shortcut remover": "Automatisk borttagning av skrivbordsgenvägar", + "Choose how many operations should be performed in parallel": "Välj hur många åtgärder som ska utföras parallellt", + "Clear successful operations from the operation list after a 5 second delay": "Rensa lyckade åtgärder från åtgärdslitan med 5 sekunders fördröjning", + "Download operations are not affected by this setting": "Nedladdningsåtgärder är inte påverkade av denna inställning", + "You may lose unsaved data": "Osparad data kan förloras", + "Ask to delete desktop shortcuts created during an install or upgrade.": "Fråga om att ta bort skrivbordsgenvägar som har skapats under en installation eller uppgradering.", + "Package update preferences": "Inställningr för paketuppdateringar", + "Update check frequency, automatically install updates, etc.": "Uppdateringsintervall, automatiska uppdateringar m.m.", + "Reduce UAC prompts, elevate installations by default, unlock certain dangerous features, etc.": "Reducera UAC-rutor, förhöj installationen som standard, lås upp vissa farliga funktioner m.m.", + "Package operation preferences": "Inställningar för paketåtgärder", + "Enable {pm}": "Aktivera {pm}", + "Not finding the file you are looking for? Make sure it has been added to path.": "Hittar du inte filen du söker? Säkerställ att den har lagts in i sökvägen.", + "Select the executable to be used. The following list shows the executables found by UniGetUI": "Välj den körbara filen som ska användas. Följande lista visar körbara filer som har hittats av UniGetUI", + "For security reasons, changing the executable file is disabled by default": "Av säkerhetsskäl är ändring av körbara filer inte tillåtet som standard", + "Change this": "Ändra detta", + "Copy path": "Kopiera sökväg", + "Current executable file:": "Nuvarande körbara fil:", + "Ignore packages from {pm} when showing a notification about updates": "Ignorera paket från {pm} när en notifiering om uppdatering visas", + "Update security": "Uppdateringssäkerhet", + "Use global setting": "Använd global inställning", + "Minimum age for updates": "Minimiålder för uppdateringar", + "e.g. 10": "t.ex. 10", + "Custom minimum age (days)": "Anpassad minimiålder (dagar)", + "{pm} does not provide release dates for its packages, so this setting will have no effect": "{pm} tillhandahåller inte utgivningsdatum för sina paket, så den här inställningen har ingen effekt", + "{pm} only provides release dates for some of its packages, so this setting will only apply to those packages": "{pm} anger endast utgivningsdatum för vissa av sina paket, så den här inställningen gäller endast för de paketen", + "Override the global minimum update age for this package manager": "Åsidosätt den globala minimiåldern för uppdateringar för den här pakethanteraren", + "View {0} logs": "Se {0} loggar", + "If Python cannot be found or is not listing packages but is installed on the system, ": "Om Python inte kan hittas eller inte listar paket men är installerat på systemet, ", + "Advanced options": "Avancerade alternativ", + "WinGet command-line tool": "WinGet-kommandoradsverktyg", + "Choose which command-line tool UniGetUI uses for WinGet operations when the COM API is not used": "Välj vilket kommandoradsverktyg UniGetUI använder för WinGet-åtgärder när COM API inte används", + "WinGet COM API": "WinGet COM API", + "Choose whether UniGetUI can use the WinGet COM API before falling back to the command-line tool": "Välj om UniGetUI kan använda WinGet COM API innan det faller tillbaka på kommandoradsverktyget", + "Reset WinGet": "Återställ WinGet", + "This may help if no packages are listed": "Detta kan hjälpa ifall inga paket listas.", + "Force install location parameter when updating packages with custom locations": "Tvinga installationsplatsparameter vid uppdatering av paket med anpassade installationsplatser", + "Install Scoop": "Installera Scoop", + "Uninstall Scoop (and its packages)": "Avinstallera Scoop och dess paket", + "Run cleanup and clear cache": "Kör städning och töm cachen", + "Run": "Kör", + "Enable Scoop cleanup on launch": "Aktivera Scoop-rensning vid start", + "Default vcpkg triplet": "Standard vcpkg triplet", + "Change vcpkg root location": "Ändra vcpkg-rotkatalog", + "Reset vcpkg root location": "Återställ vcpkg-rotplats", + "Open vcpkg root location": "Öppna vcpkg-rotplats", + "Language, theme and other miscellaneous preferences": "Språk, tema och andra övriga preferenser", + "Show notifications on different events": "Visa notifiering om olika händelser", + "Change how UniGetUI checks and installs available updates for your packages": "Ändra hur UniGetUI kontrollerar och installerar tillgängliga uppdateringar till dina paket", + "Automatically save a list of all your installed packages to easily restore them.": "Spara automatiskt en lista över alla dina installerade paket för att enkelt återställa dem.", + "Enable and disable package managers, change default install options, etc.": "Aktivera och avaktivera pakethanterare, ställa in standardinställningar, etc.", + "Internet connection settings": "Inställningar för internetanslutning", + "Proxy settings, etc.": "Proxyinställningar m.m.", + "Beta features and other options that shouldn't be touched": "Betafunktioner och andra alternativ som inte bör röras", + "Reload sources": "Ladda om källor", + "Delete source": "Ta bort källa", + "Known sources": "Kända källor", + "Update checking": "Uppdateringskontroll", + "Automatic updates": "Automatiska uppdateringar", + "Check for package updates periodically": "Sök efter paketuppdateringar med jämna mellanrum", + "Check for updates every:": "Sök efter uppdateringar varje:", + "Install available updates automatically": "Installera tillgängliga uppdateringar automatiskt", + "Do not automatically install updates when the network connection is metered": "Installera inte automatiska uppdateringar vid användning av uppkoppling med datapriser", + "Do not automatically install updates when the device runs on battery": "Installera inte automatiska uppdateringar när datorn körs på batteri", + "Do not automatically install updates when the battery saver is on": "Installera inte uppdateringar automatiskt när datorns strömsparläge är på", + "Only show updates that are at least the specified number of days old": "Visa endast uppdateringar som är minst det angivna antalet dagar gamla", + "Warn me when the installer URL host changes between the installed version and the new version (WinGet only)": "Varna mig när installationsprogrammets URL-värd ändras mellan den installerade versionen och den nya versionen (endast WinGet)", + "Change how UniGetUI handles install, update and uninstall operations.": "Ändra hur UniGetUI hanterar installation, uppdatering och avinstallation.", + "Navigation": "Navigering", + "Check for UniGetUI updates": "Sök efter uppdateringar för UniGetUI", + "Quit UniGetUI": "Avsluta UniGetUI", + "Filters": "Filter", + "Sources": "Källor", + "Search for packages to start": "Sök efter paket att starta", + "Select all": "Välj alla", + "Clear selection": "Rensa val", + "Instant search": "Direktsökning", + "Distinguish between uppercase and lowercase": "Skilj mellan stora och små bokstäver", + "Ignore special characters": "Ignorera specialtecken", + "Search mode": "Sökläge", + "Both": "Båda", + "Exact match": "Exakt matchning", + "Show similar packages": "Visa liknande paket", + "Loading": "Laddar", + "Package": "Paket", + "More options": "Fler alternativ", + "Order by:": "Sortering:", + "Name": "Namn", + "Id": "ID", + "Ascendant": "Stigande", + "Descendant": "Ättling", + "View modes": "Visningslägen", + "Reload": "Ladda om", + "Closed": "Stängd", + "Ascending": "Stigande", + "Descending": "Fallande", + "{0}: {1}, {2}": "{0}: {1}, {2}", + "Order by": "Sortera efter", + "No results were found matching the input criteria": "Inga resultat hittades som matchade inmatningskriterierna", + "No packages were found": "Inga paket hittades", + "Loading packages": "Laddar paket", + "Skip integrity checks": "Ignorera integritetskontrollerna", + "Download selected installers": "Ladda ned valda installationer", + "Install selection": "Installera val", + "Install options": "Installationsinställningar", + "Add selection to bundle": "Lägg till val i paket-gruppen", + "Download installer": "Hämta installationsprogrammet", + "Uninstall selection": "Avinstallera urval", + "Uninstall options": "Avinstallationinställningar", + "Ignore selected packages": "Ignorera valda paket", + "Open install location": "Öppna installationsplatsen", + "Reinstall package": "Ominstallera paketet", + "Uninstall package, then reinstall it": "Avinstallera paket och sedan ominstallera den", + "Ignore updates for this package": "Ignorera uppdateringar för detta paket", + "WinGet malfunction detected": "WinGet-fel hittades", + "It looks like WinGet is not working properly. Do you want to attempt to repair WinGet?": "Det verkar som om Winget inte fungerar korrekt. Vill du reparera WinGet?", + "Repair WinGet": "Reparera WinGet", + "Updates will no longer be ignored for {0}": "Uppdateringar kommer inte längre att ignoreras för {0}", + "Updates are now ignored for {0}": "Uppdateringar ignoreras nu för {0}", + "Do not ignore updates for this package anymore": "Ignorera inte längre uppdateringar för denna paket", + "Add packages or open an existing package bundle": "Lägg till paket eller öppna en befintlig paket-grupp", + "Add packages to start": "Lägg till paket för att börja", + "The current bundle has no packages. Add some packages to get started": "Nuvarande paketgrupp innehåller inga paket. Lägg till några paket för att komma igång", + "New": "Nytt", + "Save as": "Spara som", + "Create .ps1 script": "Skapa .ps1 skript", + "Remove selection from bundle": "Ta bort urval från paketgruppen", + "Skip hash checks": "Ignorera hash-kontrollerna", + "The package bundle is not valid": "Paketgruppen är inte giltig", + "The bundle you are trying to load appears to be invalid. Please check the file and try again.": "Paketgruppen du försöker ladda in verkar vara defekt. Vänligen kontrollera filen och prova igen.", + "Package bundle": "Paketgrupp", + "Could not create bundle": "Kunde inte skapa ett paketgrupp", + "The package bundle could not be created due to an error.": "Paketgruppen kunde inte skapas på grund av något fel.", + "Install script": "Installationsskript", + "PowerShell script": "PowerShell-skript", + "The installation script saved to {0}": "Installationskriptet sparades till {0}", + "An error occurred": "Ett fel inträffade", + "An error occurred while attempting to create an installation script:": "Ett fel inträffade i samband med försöket att skapa ett installationsskript:", + "Hooray! No updates were found.": "Hurra! Inga uppdateringar hittades.", + "Uninstall selected packages": "Avinstallera valda paket", + "Update selection": "Uppdatera valda", + "Update options": "Uppdateringsinställningar", + "Uninstall package, then update it": "Avinstallera paketet, uppdatera sen sidan", + "Uninstall package": "Avinstallera paket", + "Skip this version": "Ignorera denna version", + "Pause updates for": "Pausa uppdateringar för", + "User | Local": "Användare | Lokal", + "Machine | Global": "Dator | Global", + "The default package manager for Debian/Ubuntu-based Linux distributions.
Contains: Debian/Ubuntu packages": "Standardpakethanteraren för Debian/Ubuntu-baserade Linux-distributioner.
Innehåller: Debian/Ubuntu-paket", + "The Rust package manager.
Contains: Rust libraries and programs written in Rust": "Rust pakethanteraren.
Innehåller. Rust bibliotek och program skrivna i Rust", + "The classical package manager for windows. You'll find everything there.
Contains: General Software": "Den klassiska pakethanteren för Windows. Du hittar allt där.
Innehåller: Allmän mjukvara", + "The default package manager for RHEL/Fedora-based Linux distributions.
Contains: RPM packages": "Standardpakethanteraren för RHEL/Fedora-baserade Linux-distributioner.
Innehåller: RPM-paket", + "A repository full of tools and executables designed with Microsoft's .NET ecosystem in mind.
Contains: .NET related tools and scripts": "En förvaringsplats fullt av verktyg och körbara filer som är designade med Microsofts .NET-ekosystem i åtanke.
Innehåller: .NET-relaterade verktyg och skript", + "The universal Linux package manager for desktop applications.
Contains: Flatpak applications from configured remotes": "Den universella Linux-pakethanteraren för skrivbordsprogram.
Innehåller: Flatpak-program från konfigurerade fjärrkällor", + "NuPkg (zipped manifest)": "NuPkg (zippad manifest)", + "The Missing Package Manager for macOS (or Linux).
Contains: Formulae, Casks": "Den saknade pakethanteraren för macOS (eller Linux).
Innehåller: Formulae, Casks", + "Node JS's package manager. Full of libraries and other utilities that orbit the javascript world
Contains: Node javascript libraries and other related utilities": "Node JS:s pakethanterare. Fullt av bibliotek och andra verktyg som kretsar runt Javascript-världen
Innehåller: Node javascript-bibliotek och andra relaterade verktyg", + "The default package manager for Arch Linux and its derivatives.
Contains: Arch Linux packages": "Standardpakethanteraren för Arch Linux och dess derivat.
Innehåller: Arch Linux-paket", + "Python's library manager. Full of python libraries and other python-related utilities
Contains: Python libraries and related utilities": "Pythons pakethanterare. Fullt med pythonbibliotek och andra pythonrelaterade verktyg
Innehåller: Pythonbibliotek och relaterade verktyg", + "PowerShell's package manager. Find libraries and scripts to expand PowerShell capabilities
Contains: Modules, Scripts, Cmdlets": "PowerShells pakethanterare. Hitta bibliotek och skript för att utöka PowerShell-funktionerna
Innehåller: Moduler, skript, Cmdlets", + "extracted": "extraherad", + "Scoop package": "Scoop-paket", + "Great repository of unknown but useful utilities and other interesting packages.
Contains: Utilities, Command-line programs, General Software (extras bucket required)": "Stort katalog av okända men användbara verktyg och andra intressanta paket.
Innehåller: Verktyg, kommandoradsprogram, allmän programvara (extras paketarkiv krävs)", + "The universal Linux package manager by Canonical.
Contains: Snap packages from the Snapcraft store": "Den universella Linux-pakethanteraren från Canonical.
Innehåller: Snap-paket från Snapcraft-butiken", + "library": "bibliotek", + "feature": "funktion", + "A popular C/C++ library manager. Full of C/C++ libraries and other C/C++-related utilities
Contains: C/C++ libraries and related utilities": "En populär hanterare för C/C++bibliotek. Fylld av C/C++bibliotek och andra C/C++relaterade verktyg
Innehåller: C/C++bibliotek och relaterade verktyg", + "option": "inställning", + "This package cannot be installed from an elevated context.": "Denna paket kan inte installeras med adminrättigheter.", + "Please run UniGetUI as a regular user and try again.": "Vänligen kör UniGetUI som en vanlig användare och prova igen.", + "Please check the installation options for this package and try again": "Vänlgien kontrollera installationsinställningarna för paketet och prova igen", + "Microsoft's official package manager. Full of well-known and verified packages
Contains: General Software, Microsoft Store apps": "Microsofts officiella pakethanterare. Full av välkända och verifierade paket
Innehåller: Allmän programvara, Microsoft Store-appar", + "Local PC": "Lokal PC", + "Android Subsystem": "Android-undersystem", + "Operation on queue (position {0})...": "Åtgärd på kö (position {0})...", + "Click here for more details": "Klicka här för fler detaljer", + "Operation canceled by user": "Åtgärden avbröts av användaren", + "Running PreOperation ({0}/{1})...": "Kör PreOperation ({0}/{1})...", + "PreOperation {0} out of {1} failed, and was tagged as necessary. Aborting...": "PreOperation {0} av {1} misslyckades och markerades som nödvändig. Avbryter...", + "PreOperation {0} out of {1} finished with result {2}": "PreOperation {0} av {1} slutfördes med resultatet {2}", + "Starting operation...": "Startar åtgärd...", + "Running PostOperation ({0}/{1})...": "Kör PostOperation ({0}/{1})...", + "PostOperation {0} out of {1} failed, and was tagged as necessary. Aborting...": "PostOperation {0} av {1} misslyckades och markerades som nödvändig. Avbryter...", + "PostOperation {0} out of {1} finished with result {2}": "PostOperation {0} av {1} slutfördes med resultatet {2}", + "{package} installer download": "{package} installerarens nedladdning", + "{0} installer is being downloaded": "{0} installeraren laddas ned", + "Download succeeded": "Nedladdningen lyckades", + "{package} installer was downloaded successfully": "{package} installeraren laddades ned", + "Download failed": "Nedladdning misslyckad", + "{package} installer could not be downloaded": "{package} installeraren kunde inte laddas ned", + "{package} Installation": "{package} installation", + "{0} is being installed": "{0} installeras", + "Installation succeeded": "Installationen lyckades", + "{package} was installed successfully": "{package} installerades", + "Installation failed": "Installationen misslyckades", + "{package} could not be installed": "{package} kunde inte installeras", + "{package} Update": "{package} Uppdaterar", + "Update succeeded": "Uppdatering lyckad", + "{package} was updated successfully": "{package} uppdaterades", + "Update failed": "Uppdatering misslyckad", + "{package} could not be updated": "{package} kunde inte uppdateras", + "{package} Uninstall": "{package} avinstallera", + "{0} is being uninstalled": "{0} avinstalleras", + "Uninstall succeeded": "Avinstallation lyckad", + "{package} was uninstalled successfully": "{package} avinstallerades", + "Uninstall failed": "Avinstallation misslyckad", + "{package} could not be uninstalled": "{package} kunde inte avinstalleras", + "Adding source {source}": "Lägger till källan {source}", + "Adding source {source} to {manager}": "Lägger till källan {source} till {manager}", + "Source added successfully": "Källan lades till", + "The source {source} was added to {manager} successfully": "Källan {source} har lagts till i {manager}", + "Could not add source": "Kunde inte lägga till källa", + "Could not add source {source} to {manager}": "Det gick inte att lägga till källan {source} till {manager}", + "Removing source {source}": "Tar bort källan {source}", + "Removing source {source} from {manager}": "Ta bort källa {source} från {manager} ", + "Source removed successfully": "Borttagning av källan lyckades", + "The source {source} was removed from {manager} successfully": "Källan {source} togs bort från {manager}", + "Could not remove source": "Kunde inte ta bort källa", + "Could not remove source {source} from {manager}": "Det gick inte att ta bort källan {source} från {manager}", + "The package manager \"{0}\" was not found": "Pakethanteraren {0} kunde inte hittas", + "The package manager \"{0}\" is disabled": "Pakethanterare {0} är inaktiverad", + "There is an error with the configuration of the package manager \"{0}\"": "Ett fel uppstod vid inställning av pakethanteraren {0}", + "The package \"{0}\" was not found on the package manager \"{1}\"": "Paket {0} kunde inte hittas i pakethanteraren {1}", + "{0} is disabled": "{0} är inaktiverad", + "{0} weeks": "{0} veckor", + "1 month": "1 månad", + "{0} months": "{0} månader", + "Something went wrong": "Något gick fel", + "An interal error occurred. Please view the log for further details.": "Ett internt fel inträffade. Vänligen läs loggen för fler detaljer.", + "No applicable installer was found for the package {0}": "Ingen lämplig installerare kunde hittas för paketet {0}", + "Integrity checks will not be performed during this operation": "Integritetskontroller kommer inte utföras i denna åtgärd", + "This is not recommended.": "Detta är inte rekommenderat.", + "Run now": "Kör nu", + "Run next": "Kör nästa", + "Run last": "Kör sist", + "Show in explorer": "Visa i utforskaren", + "Checked": "Markerad", + "Unchecked": "Avmarkerad", + "This package is already installed": "Denna paket är redan installerad", + "This package can be upgraded to version {0}": "Denna paket kan uppgraderas till version {0}", + "Updates for this package are ignored": "Uppdateringar för denna paket ignoreras", + "This package is being processed": "Den paket är under behandling", + "This package is not available": "Paketet är inte tillgängligt", + "Select the source you want to add:": "Välj källan du vill lägga till:", + "Source name:": "Källnamnet:", + "Source URL:": "Källa URL:", + "An error occurred when adding the source: ": "Ett fel inträffade när källan lades till:", + "Package management made easy": "Pakethantering på ett enkelt sätt", + "version {0}": "version {0}", + "[RAN AS ADMINISTRATOR]": "KÖRS SOM ADMIN", + "Portable mode": "Portabelt läge", + "DEBUG BUILD": "Felsökningsversion", + "Here you can change UniGetUI's behaviour regarding the following shortcuts. Checking a shortcut will make UniGetUI delete it if if gets created on a future upgrade. Unchecking it will keep the shortcut intact": "Här kan du ändra hur UniGetUI beter sig gällande följande genvägar. Markera en genväg och UniGetUI tar bort den vid en framtida uppgradering. Utan markering kommer genvägen bevaras intakt", + "Manual scan": "Manuell skanning", + "Existing shortcuts on your desktop will be scanned, and you will need to pick which ones to keep and which ones to remove.": "Befintliga genvägar på ditt skrivbord kommer att skannas och du får välja vilka som ska behållas och vilka ska tas bort.", + "Delete?": "Ta bort?", + "I understand": "Jag förstår", + "Chocolatey setup changed": "Chocolatey-konfigurationen har ändrats", + "UniGetUI no longer includes its own private Chocolatey installation. A legacy UniGetUI-managed Chocolatey installation was detected for this user profile, but system Chocolatey was not found. Chocolatey will stay unavailable in UniGetUI until Chocolatey is installed on the system and UniGetUI is restarted. Applications previously installed through UniGetUI's bundled Chocolatey may still appear under other sources such as Local PC or WinGet.": "UniGetUI inkluderar inte längre sin egen privata Chocolatey-installation. En äldre UniGetUI-hanterad Chocolatey-installation har upptäckts för den här användarprofilen, men system-Chocolatey kunde inte hittas. Chocolatey förblir otillgängligt i UniGetUI tills Chocolatey installeras på systemet och UniGetUI startas om. Program som tidigare installerats via UniGetUI:s medföljande Chocolatey kan fortfarande visas under andra källor som Lokal dator eller WinGet.", + "NOTE: This troubleshooter can be disabled from UniGetUI Settings, on the WinGet section": "OBS: Denna felsökning kan avaktiveras i inställningar för UniGetUI i WinGet avsnittet", + "Restart": "Starta om", + "Are you sure you want to delete all shortcuts?": "Är du säker på att du vill ta bort alla genvägar?", + "Any new shorcuts created during an install or an update operation will be deleted automatically, instead of showing a confirmation prompt the first time they are detected.": "Nya genvägar skapade vid en installation eller efter en uppdatering kommer tas bort automatiskt istället för att visa en bekräftelse första gången de upptäckts.", + "Any shorcuts created or modified outside of UniGetUI will be ignored. You will be able to add them via the {0} button.": "Alla genvägar som skapats eller som har modifierats utanför UniGetUI kommer att ignoreras. Du kommer att ges möjlighet att lägga till dessa via knappen {0}.", + "Are you really sure you want to enable this feature?": "Är du säker på att du vill aktivera den här funktionen?", + "No new shortcuts were found during the scan.": "Hittade inga nya genvägar vid skanning", + "How to add packages to a bundle": "Hur lägger man till paket i en paketgrupp", + "In order to add packages to a bundle, you will need to: ": "För att lägga till paket i en paketgrupp behöver du:", + "1. Navigate to the \"{0}\" or \"{1}\" page.": "Navigera till sidan \"{0}\" eller \"{1}\".", + "2. Locate the package(s) you want to add to the bundle, and select their leftmost checkbox.": "2. Lokalisera paket(en) du vill lägga till i paketgruppen och bocka i den vänstra kryssrutan.", + "3. When the packages you want to add to the bundle are selected, find and click the option \"{0}\" on the toolbar.": "3. När du valt paketen du vill lägga till paketgruppen, leta upp och klicka i valet \"{0}\" i verktygsfältet.", + "4. Your packages will have been added to the bundle. You can continue adding packages, or export the bundle.": "4. Dina paket har nu lagts till i paketgruppen. Du kan lägga till fler paket eller exportera hela paketgruppen.", + "Which backup do you want to open?": "Vilken säkerhetskopia vill du öppna?", + "Select the backup you want to open. Later, you will be able to review which packages you want to install.": "Välj säkerhetskopian du vill öppna. Senare får du möjlighet att välja vilka paket/program du vill återställa.", + "There are ongoing operations. Quitting UniGetUI may cause them to fail. Do you want to continue?": "Det finns pågående åtgärder. Genom att stänga UniGetUI kan dessa misslyckas. Vill du fortsätta?", + "UniGetUI or some of its components are missing or corrupt.": "UniGetUI eller någon av dess komponenter saknas eller är korrupta.", + "It is strongly recommended to reinstall UniGetUI to adress the situation.": "Rekommenderar starkt att du ominstallerar UniGetUI för att lösa situationen", + "Refer to the UniGetUI Logs to get more details regarding the affected file(s)": "Hänvisar till UniGetUI:s loggar för mer detaljerad information om påverkad(e) filer.", + "Integrity checks can be disabled from the Experimental Settings": "Integritetskontroller kan stängas av från Experimentinställningar", + "Repair UniGetUI": "Reparera UniGetUI", + "Live output": "Live-utgång", + "This package bundle had some settings that are potentially dangerous, and may be ignored by default.": "Denna paketgrupp har några inställningar som kan vara farliga och som kan åsidosättas som standard.", + "Entries that show in YELLOW will be IGNORED.": "Inlägg i GULT kommer att IGNORERAS.", + "Entries that show in RED will be IMPORTED.": "Inlägg i RÖTT kommer att IMPORTERAS.", + "You can change this behavior on UniGetUI security settings.": "Du kan ändra detta beteende i UniGetUI:s säkerhetsinställningar.", + "Open UniGetUI security settings": "Öppna säkerhetsinställningar för UniGetUI", + "Should you modify the security settings, you will need to open the bundle again for the changes to take effect.": "Skulle du ändra säkerhetsinställningarna behöver du öppna paketgruppen igen för att ändringarna ska slå igenom.", + "Details of the report:": "Rapportdetaljer:", + "Are you sure you want to create a new package bundle? ": "Är du säker på att du vill skapa en nytt paketgrupp?", + "Any unsaved changes will be lost": "Ändringar som inte sparats kommer att försvinna", + "Warning!": "Varning!", + "For security reasons, custom command-line arguments are disabled by default. Go to UniGetUI security settings to change this. ": "Av säkerhetsskäl är anpassade kommandoradsargument avstängda som standard. Gå till UniGetUI säkerhetsinställningar för att ändra detta.", + "Change default options": "Ändra standardvärden", + "Ignore future updates for this package": "Ignorera framtida uppdateringar för denna paket", + "For security reasons, pre-operation and post-operation scripts are disabled by default. Go to UniGetUI security settings to change this. ": "Av säkerhetsskäl är pre-operation och post-operation skript avstängda som standard. Gå till UniGetUI säkerhetsinställningar för att ändra detta.", + "You can define the commands that will be run before or after this package is installed, updated or uninstalled. They will be run on a command prompt, so CMD scripts will work here.": "Du kan definiera kommandon som ska köras före eller efter att paketet installeras, uppdateras eller avinstalleras. De körs på en kommandotolk, så CMD skript kommer att fungera.", + "Change this and unlock": "Ändra denna och lås upp", + "{0} Install options are currently locked because {0} follows the default install options.": "{0} installationsinställningar är låsta på grund av att {0} följer standardinställningarna.", + "Unset or unknown": "Avstängt eller okänt", + "This package has no screenshots or is missing the icon? Contrbute to UniGetUI by adding the missing icons and screenshots to our open, public database.": "Denna paket har ingen skärmdump eller saknas ikonen. Bidra till UniGetUI genom att lägga till den saknade ikonen och skärmdumpa den till vår öppna och publika databas.", + "Become a contributor": "Bli en bidragare", + "Update to {0} available": "Uppdatering till {0} är tillgänglig", + "Reinstall": "Ominstallera", + "Installer not available": "Installeraren inte tillgänglig", + "Version:": "Version:", + "UniGetUI Version {0}": "UniGetUI version {0}", + "Performing backup, please wait...": "Säkerhetskopiering utförs, vänligen vänta...", + "An error occurred while logging in: ": "Ett fel inträffade i samband med inloggning:", + "Fetching available backups...": "Hämtar tillgängliga säkerhetskopior...", + "Done!": "Klart!", + "The cloud backup has been loaded successfully.": "Molnsäkerhetskopian har laddats.", + "An error occurred while loading a backup: ": "Ett fel uppstod vid inläsning av säkerhetskopian:", + "Backing up packages to GitHub Gist...": "Säkerhetskopierar paket till GitHub Gist...", + "Backup Successful": "Säkerhetskopieringen lyckades", + "The cloud backup completed successfully.": "Molnsäkerhetskopian färdigställdes.", + "Could not back up packages to GitHub Gist: ": "Kunde inte göra en säkerhetskopia till GitHub Gist:", + "It is not guaranteed that the provided credentials will be stored safely, so you may as well not use the credentials of your bank account": "Kan inte garantera att inloggningsuppgifter kommer att lagras säkert, så du bör inte använda samma inloggning som till din bank", + "Enable the automatic WinGet troubleshooter": "Aktivera den automatiska WinGet felsökningen", + "Add updates that fail with a 'no applicable update found' to the ignored updates list": "Lägg till uppdateringar som misslyckas med felet \"ingen passande uppdatering funnen\" till listan över ignorerade uppdateringar,", + "Invalid selection": "Ogiltigt val", + "No package was selected": "Inga paket har valts", + "More than 1 package was selected": "Fler än 1 paket valdes", + "List": "Lista", + "Grid": "Rutnät", + "Icons": "Ikoner", + "\"{0}\" is a local package and does not have available details": "\"{0}\" är ett lokalt paket och har inga detaljer tillgängliga", + "\"{0}\" is a local package and is not compatible with this feature": "\"{0}\" är ett lokalt paket och är inte kompatibelt med den här funktionen", + "Add packages to bundle": "Lägg till paket i paket-gruppen", + "Preparing packages, please wait...": "Förbereder paket, vänligen vänta ...", + "Loading packages, please wait...": "Laddar paket, vänligen vänta ...", + "Saving packages, please wait...": "Sparar paket, vänligen vänta...", + "The bundle was created successfully on {0}": "Paketgruppen skapades den {0}", + "User profile": "Användarprofil", + "Error": "Fel", + "Log in failed: ": "Inloggning misslyckades:", + "Log out failed: ": "Utloggning misslyckades", + "Package backup settings": "Inställningar för paketets säkerhetskopia", + "Package managers": "Pakethanterare", + "Manage UniGetUI autostart behaviour from the Settings app": "Hantera UniGetUI:s autostartbeteende", + "Choose how many operations shoulds be performed in parallel": "Välj hur många åtgärder som ska utföras parallellt", + "Something went wrong while launching the updater.": "Något gick fel vid starten av uppdateraren", + "Please try again later": "Försök igen senare", + "Show the release notes after UniGetUI is updated": "Visa versionsinformation efter att UniGetUI har uppdaterats" +} diff --git a/src/Languages/lang_ta.json b/src/Languages/lang_ta.json new file mode 100644 index 0000000..a4aa328 --- /dev/null +++ b/src/Languages/lang_ta.json @@ -0,0 +1,851 @@ +{ + "{0} of {1} operations completed": "{1} செயல்பாடுகளில் {0} முடிந்தது", + "{0} is now {1}": "{0} இப்போது {1}", + "Enabled": "இயக்கப்பட்டது", + "Disabled": "முடக்கப்பட்டது", + "Privacy": "தனியுரிமை", + "Hide my username from the logs": "பதிவுகளில் இருந்து எனது பயனர்பெயரை மறை", + "Replaces your username with **** in the logs. Restart UniGetUI to also hide it from already-recorded entries.": "பதிவுகளில் உங்கள் பயனர்பெயரை **** ஆல் மாற்றுகிறது. ஏற்கனவே பதிவு செய்யப்பட்ட உள்ளீடுகளிலிருந்தும் அதை மறைக்க UniGetUI ஐ மறுதொடக்கம் செய்யவும்.", + "Your last update attempt did not complete.": "உங்கள் கடைசி புதுப்பிப்பு முயற்சி நிறைவடையவில்லை.", + "UniGetUI could not confirm whether the update succeeded. Open the log to see what happened.": "புதுப்பிப்பு வெற்றியடைந்ததா என்பதை UniGetUI உறுதிப்படுத்த முடியவில்லை. என்ன நடந்தது என்பதைப் பார்க்க பதிவைத் திறக்கவும்.", + "View log": "பதிவைப் பார்", + "The installer reported success but did not restart UniGetUI.": "நிறுவி வெற்றி என அறிவித்தது, ஆனால் UniGetUI-ஐ மறுதொடக்கம் செய்யவில்லை.", + "The installer failed to initialize.": "நிறுவி துவக்கப்பட முடியவில்லை.", + "Setup was canceled before installation began.": "நிறுவல் தொடங்கும் முன் அமைப்பு ரத்து செய்யப்பட்டது.", + "A fatal error occurred during the preparation phase.": "தயாரிப்பு கட்டத்தில் கடுமையான பிழை ஏற்பட்டது.", + "A fatal error occurred during installation.": "நிறுவலின் போது கடுமையான பிழை ஏற்பட்டது.", + "Installation was canceled while in progress.": "நிறுவல் நடைபெறும் போது ரத்து செய்யப்பட்டது.", + "The installer was terminated by another process.": "நிறுவி மற்றொரு செயல்முறையால் நிறுத்தப்பட்டது.", + "The preparation phase determined the installation cannot proceed.": "நிறுவலைத் தொடர முடியாது என்று தயாரிப்பு கட்டம் தீர்மானித்தது.", + "The installer could not start. UniGetUI may already be running, or you do not have permission to install.": "நிறுவியைத் தொடங்க முடியவில்லை. UniGetUI ஏற்கனவே இயங்கிக்கொண்டிருக்கலாம் அல்லது நிறுவ உங்களுக்கு அனுமதி இல்லாமல் இருக்கலாம்.", + "Unexpected installer error.": "எதிர்பாராத நிறுவி பிழை.", + "We are checking for updates.": "நாங்கள் updates ஐச் சரிபார்த்து கொண்டிருக்கிறோம்.", + "Please wait": "தயவுசெய்து காத்திருக்கவும்", + "Great! You are on the latest version.": "அருமை! நீங்கள் சமீபத்திய பதிப்பில் உள்ளீர்கள்.", + "There are no new UniGetUI versions to be installed": "install செய்ய புதிய UniGetUI versions எதுவும் இல்லை", + "UniGetUI version {0} is being downloaded.": "UniGetUI version {0} பதிவிறக்கப்படுகிறது.", + "This may take a minute or two": "இதற்கு ஒரு அல்லது இரண்டு நிமிடங்கள் ஆகலாம்", + "The installer authenticity could not be verified.": "installer இன் உண்மைத்தன்மையை சரிபார்க்க முடியவில்லை.", + "The update process has been aborted.": "update process நிறுத்தப்பட்டது.", + "Auto-update is not yet available on this platform.": "இந்த தளத்தில் தானியங்கி புதுப்பிப்பு இன்னும் கிடைக்கவில்லை.", + "Please update UniGetUI manually.": "தயவுசெய்து UniGetUI-ஐ கைமுறையாக புதுப்பிக்கவும்.", + "An error occurred when checking for updates: ": "புதுப்பிப்புகளைச் சரிபார்க்கும் போது ஒரு பிழை ஏற்பட்டது:", + "The updater could not be launched.": "புதுப்பிப்பியைத் தொடங்க முடியவில்லை.", + "The operating system did not start the installer process.": "இயக்க முறைமை நிறுவி செயல்முறையைத் தொடங்கவில்லை.", + "UniGetUI is being updated...": "UniGetUI update செய்யப்படுகிறது...", + "Update installed.": "புதுப்பிப்பு நிறுவப்பட்டது.", + "UniGetUI was updated successfully, but this running copy was not replaced. This usually means you are running a development build. Close this copy and start the newly-installed version to finish.": "UniGetUI வெற்றிகரமாக புதுப்பிக்கப்பட்டது, ஆனால் தற்போது இயங்கும் இந்த நகல் மாற்றப்படவில்லை. இது பொதுவாக நீங்கள் development build ஒன்றை இயக்குகிறீர்கள் என்பதைக் குறிக்கும். முடிக்க, இந்த நகலை மூடி புதிதாக நிறுவப்பட்ட பதிப்பைத் தொடங்கவும்.", + "The update could not be applied.": "புதுப்பிப்பைச் செயல்படுத்த முடியவில்லை.", + "Installer exit code {0}: {1}": "நிறுவி வெளியேறு குறியீடு {0}: {1}", + "Update cancelled.": "புதுப்பிப்பு ரத்து செய்யப்பட்டது.", + "Authentication was cancelled.": "அங்கீகாரம் ரத்து செய்யப்பட்டது.", + "Installer exit code {0}": "நிறுவி வெளியேறு குறியீடு {0}", + "Operation in progress": "செயல்பாடு நடைபெற்று கொண்டிருக்கிறது", + "Please wait...": "தயவுசெய்து காத்திருக்கவும்...", + "Success!": "வெற்றி!", + "Failed": "தோல்வியடைந்தது", + "An error occurred while processing this package": "இந்த தொகுப்பை செயலாக்கும்போது பிழை ஏற்பட்டது", + "Installer": "நிறுவி", + "Executable": "இயக்கக்கூடிய கோப்பு", + "MSI": "MSI", + "Compressed file": "சுருக்கப்பட்ட கோப்பு", + "MSIX": "MSIX", + "WinGet was repaired successfully": "WinGet வெற்றிகரமாக repair செய்யப்பட்டது", + "It is recommended to restart UniGetUI after WinGet has been repaired": "WinGet சரிசெய்யப்பட்ட பிறகு UniGetUI ஐ restart செய்ய பரிந்துரைக்கப்படுகிறது", + "WinGet could not be repaired": "WinGet ஐ repair செய்ய முடியவில்லை", + "An unexpected issue occurred while attempting to repair WinGet. Please try again later": "WinGet ஐ சரிசெய்ய முயன்றபோது எதிர்பாராத சிக்கல் ஏற்பட்டது. பின்னர் மீண்டும் முயற்சிக்கவும்", + "Log in to enable cloud backup": "மேகக் காப்புப்பிரதியை செயல்படுத்த உள்நுழையவும்", + "Backup Failed": "காப்புப்பிரதி தோல்வியுற்றது", + "Downloading backup...": "காப்புப்பிரதி பதிவிறக்கப்படுகிறது...", + "An update was found!": "ஒரு புதுப்பிப்பு கிடைத்தது!", + "{0} can be updated to version {1}": "{0} ஐ பதிப்பு {1} க்கு புதுப்பிக்கலாம்", + "Updates found!": "புதுப்பிப்புகள் கிடைத்தன!", + "{0} packages can be updated": "{0} தொகுப்புகளை புதுப்பிக்கலாம்", + "{0} is being updated to version {1}": "{0} version {1} க்கு update செய்யப்படுகிறது", + "{0} packages are being updated": "{0} packages update செய்யப்படுகின்றன", + "You have currently version {0} installed": "உங்களிடம் தற்போது பதிப்பு {0} நிறுவப்பட்டுள்ளது", + "Desktop shortcut created": "டெஸ்க்டாப் குறுக்குவழி உருவாக்கப்பட்டது", + "UniGetUI has detected a new desktop shortcut that can be deleted automatically.": "தானாக நீக்கக்கூடிய புதிய டெஸ்க்டாப் குறுக்குவழியை UniGetUI கண்டறிந்துள்ளது.", + "{0} desktop shortcuts created": "{0} டெஸ்க்டாப் குறுக்குவழிகள் உருவாக்கப்பட்டன", + "UniGetUI has detected {0} new desktop shortcuts that can be deleted automatically.": "தானாக நீக்கக்கூடிய {0} புதிய டெஸ்க்டாப் குறுக்குவழிகளை UniGetUI கண்டறிந்துள்ளது.", + "Attention required": "கவனம் தேவை", + "Restart required": "restart தேவை", + "1 update is available": "ஒரு புதுப்பிப்பு உள்ளது", + "{0} updates are available": "{0} updates கிடைக்கின்றன", + "Everything is up to date": "அனைத்தும் புதுப்பிக்கப்பட்டுள்ளது", + "Discover Packages": "packages ஐ கண்டறி", + "Available Updates": "கிடைகப்பட்ட புதுப்பிப்புகள்", + "Installed Packages": "install செய்யப்பட்ட packages", + "UniGetUI Version {0} by Devolutions": "Devolutions வழங்கும் UniGetUI பதிப்பு {0}", + "Show UniGetUI": "UniGetUI ஐ காட்டு", + "Quit": "வெளியேறு", + "Are you sure?": "உறுதியாக இருக்கிறீர்களா?", + "Do you really want to uninstall {0}?": "{0} ஐ அகற்ற உண்மையில் விரும்புகிறீர்களா?", + "Do you really want to uninstall the following {0} packages?": "கீழ்க்கண்ட {0} தொகுப்புகளை அகற்ற உண்மையில் விரும்புகிறீர்களா?", + "No": "இல்லை", + "Yes": "ஆம்", + "Partial": "பகுதியளவில்", + "View on UniGetUI": "UniGetUI இல் பார்", + "Update": "புதுப்பி", + "Open UniGetUI": "UniGetUI ஐத் திற", + "Update all": "அனைத்தையும் புதுப்பி", + "Update now": "இப்போது புதுப்பி", + "Installer host changed since the installed version.\n": "நிறுவப்பட்ட பதிப்பிலிருந்து நிறுவியின் host மாறியுள்ளது.\n", + "This package is on the queue": "இந்த தொகுப்பு வரிசையில் உள்ளது", + "installing": "நிறுவப்படுகிறது", + "updating": "புதுப்பிக்கப்படுகிறது", + "uninstalling": "அகற்றப்படுகிறது", + "installed": "நிறுவப்பட்டது", + "Retry": "மீண்டும் முயற்சி செய்", + "Install": "நிறுவு", + "Uninstall": "அகற்று", + "Open": "திற", + "Operation profile:": "செயல்பாட்டு சுயவிவரம்:", + "Follow the default options when installing, upgrading or uninstalling this package": "இந்த தொகுப்பை நிறுவும், புதுப்பிக்கும் அல்லது அகற்றும் போது இயல்புநிலை விருப்பங்களைப் பின்பற்று", + "The following settings will be applied each time this package is installed, updated or removed.": "இந்த தொகுப்பு நிறுவப்படும், புதுப்பிக்கப்படும் அல்லது அகற்றப்படும் ஒவ்வொரு முறையும் பின்வரும் அமைப்புகள் பயன்படுத்தப்படும்.", + "Version to install:": "நிறுவ வேண்டிய பதிப்பு:", + "Architecture to install:": "நிறுவ வேண்டிய கட்டமைப்பு:", + "Installation scope:": "நிறுவல் வரம்பு:", + "Install location:": "நிறுவல் இடம்:", + "Select": "தேர்ந்தெடு", + "Reset": "மீட்டமை", + "Custom install arguments:": "தனிப்பயன் நிறுவல் அளவுருக்கள்:", + "Custom update arguments:": "தனிப்பயன் புதுப்பிப்பு அளவுருக்கள்:", + "Custom uninstall arguments:": "தனிப்பயன் அகற்றல் அளவுருக்கள்:", + "Pre-install command:": "நிறுவலுக்கு முன் கட்டளை:", + "Post-install command:": "நிறுவலுக்கு பின் கட்டளை:", + "Abort install if pre-install command fails": "நிறுவலுக்கு முந்தைய கட்டளை தோல்வியுற்றால் நிறுவலை நிறுத்து", + "Pre-update command:": "புதுப்பிப்புக்கு முன் கட்டளை:", + "Post-update command:": "புதுப்பிப்புக்கு பின் கட்டளை:", + "Abort update if pre-update command fails": "புதுப்பிப்புக்கு முந்தைய கட்டளை தோல்வியுற்றால் புதுப்பிப்பை நிறுத்து", + "Pre-uninstall command:": "அகற்றலுக்கு முன் கட்டளை:", + "Post-uninstall command:": "அகற்றலுக்கு பின் கட்டளை:", + "Abort uninstall if pre-uninstall command fails": "அகற்றலுக்கு முந்தைய கட்டளை தோல்வியுற்றால் அகற்றலை நிறுத்து", + "Command-line to run:": "இயக்க வேண்டிய கட்டளைவரி:", + "Save and close": "சேமித்து மூடு", + "General": "பொது", + "Architecture & Location": "கட்டமைப்பு மற்றும் இடம்", + "Command-line": "கட்டளைவரி", + "Close apps": "பயன்பாடுகளை மூடு", + "Pre/Post install": "நிறுவல் முன்/பின்", + "Select the processes that should be closed before this package is installed, updated or uninstalled.": "இந்த package install, update அல்லது uninstall ஆகும் முன் மூடப்பட வேண்டிய processes ஐத் தேர்ந்தெடுக்கவும்.", + "Write here the process names here, separated by commas (,)": "process பெயர்களை இங்கே comma (,) களைப் பயன்படுத்தி பிரித்து எழுதவும்", + "Try to kill the processes that refuse to close when requested to": "மூடுமாறு கேட்டாலும் மூட மறுக்கும் processes ஐ kill செய்ய முயற்சி செய்", + "Run as admin": "நிர்வாகியாக இயக்கு", + "Interactive installation": "இணையச் செயல்பாட்டு நிறுவல்", + "Skip hash check": "ஹாஷ் சரிபார்ப்பை தவிர்", + "Uninstall previous versions when updated": "புதுப்பிக்கும்போது முந்தைய பதிப்புகளை அகற்று", + "Skip minor updates for this package": "இந்த தொகுப்புக்கான சிறிய புதுப்பிப்புகளை தவிர்", + "Automatically update this package": "இந்த தொகுப்பை தானாகப் புதுப்பி", + "{0} installation options": "{0} நிறுவல் விருப்பங்கள்", + "Latest": "சமீபத்தியது", + "PreRelease": "முன்வெளியீடு", + "Default": "இயல்புநிலை", + "Manage ignored updates": "புறக்கணிக்கப்பட்ட புதுப்பிப்புகளை நிர்வகி", + "The packages listed here won't be taken in account when checking for updates. Double-click them or click the button on their right to stop ignoring their updates.": "இங்கே பட்டியலிடப்பட்டுள்ள தொகுப்புகள் புதுப்பிப்புகளைச் சரிபார்க்கும் போது கணக்கில் எடுத்துக்கொள்ளப்படமாட்டாது. அவற்றின் புதுப்பிப்புகளை புறக்கணிப்பதை நிறுத்த அவற்றை இருமுறை சொடுக்கவும் அல்லது வலப்புறத்தில் உள்ள பொத்தானை சொடுக்கவும்.", + "Reset list": "பட்டியலை மீட்டமை", + "Do you really want to reset the ignored updates list? This action cannot be reverted": "புறக்கணிக்கப்பட்ட புதுப்பிப்புகள் பட்டியலை உண்மையிலேயே மீட்டமைக்க விரும்புகிறீர்களா? இந்த செயலைத் திரும்ப மாற்ற முடியாது", + "No ignored updates": "புறக்கணிக்கப்பட்ட புதுப்பிப்புகள் இல்லை", + "Package Name": "தொகுப்பு பெயர்", + "Package ID": "தொகுப்பு அடையாளம்", + "Ignored version": "புறக்கணிக்கப்பட்ட பதிப்பு", + "New version": "புதிய பதிப்பு", + "Source": "மூலம்", + "All versions": "எல்லா பதிப்புகளும்", + "Unknown": "அறியப்படாதது", + "Up to date": "புதுப்பிக்கப்பட்டது", + "Package {name} from {manager}": "{manager} இலிருந்து {name} தொகுப்பு", + "Remove {0} from ignored updates": "புறக்கணிக்கப்பட்ட புதுப்பிப்புகளிலிருந்து {0} ஐ நீக்கு", + "Cancel": "ரத்து", + "Administrator privileges": "நிர்வாகி சிறப்புரிமைகள்", + "This operation is running with administrator privileges.": "இந்த செயல்பாடு நிர்வாகி சிறப்புரிமைகளுடன் இயங்குகிறது.", + "Interactive operation": "இணையாடும் செயல்பாடு", + "This operation is running interactively.": "இந்த செயல்பாடு இணையாடும் முறையில் இயங்குகிறது.", + "You will likely need to interact with the installer.": "நீங்கள் நிறுவியுடன் தொடர்பு கொள்ள வேண்டியிருக்கும்.", + "Integrity checks skipped": "முழுமைத்தன்மைச் சோதனைகள் தவிர்க்கப்பட்டன", + "Integrity checks will not be performed during this operation.": "இந்த செயல்பாட்டின் போது முழுமைத்தன்மைச் சோதனைகள் செய்யப்படமாட்டாது.", + "Proceed at your own risk.": "உங்கள் சொந்த ஆபத்தில் தொடரவும்.", + "Close": "மூடு", + "Loading...": "ஏற்றப்படுகிறது...", + "Installer SHA256": "நிறுவி SHA256", + "Homepage": "முகப்புப்பக்கம்", + "Author": "ஆசிரியர்", + "Publisher": "வெளியீட்டாளர்", + "License": "உரிமம்", + "Manifest": "மெனிபெஸ்ட்", + "Installer Type": "நிறுவி வகை", + "Size": "அளவு", + "Installer URL": "நிறுவி URL", + "Last updated:": "கடைசியாக புதுப்பிக்கப்பட்டது:", + "Release notes URL": "வெளியீட்டு குறிப்புகள் URL", + "Package details": "தொகுப்பு விவரங்கள்", + "Dependencies:": "சார்புகள்:", + "Release notes": "வெளியீட்டு குறிப்புகள்", + "Screenshots": "திரைக்காட்சிகள்", + "This package has no screenshots or is missing the icon? Contribute to UniGetUI by adding the missing icons and screenshots to our open, public database.": "இந்த தொகுப்பில் திரைக்காட்சிகள் இல்லை அல்லது ஐகான் காணவில்லையா? காணாமல் உள்ள ஐகான்கள் மற்றும் திரைக்காட்சிகளை எங்கள் திறந்த, பொதுத் தரவுத்தளத்தில் சேர்த்து UniGetUIக்கு பங்களிக்கவும்.", + "Version": "பதிப்பு", + "Install as administrator": "நிர்வாகியாக நிறுவு", + "Update to version {0}": "பதிப்பு {0} க்கு புதுப்பி", + "Installed Version": "நிறுவப்பட்ட பதிப்பு", + "Update as administrator": "நிர்வாகியாக புதுப்பி", + "Interactive update": "இணையாடும் புதுப்பிப்பு", + "Uninstall as administrator": "நிர்வாகியாக அகற்று", + "Interactive uninstall": "இணையாடும் அகற்றல்", + "Uninstall and remove data": "அகற்றி தரவையும் நீக்கு", + "Not available": "கிடைக்கவில்லை", + "Installer SHA512": "நிறுவி SHA512", + "Unknown size": "அறியப்படாத அளவு", + "No dependencies specified": "சார்புகள் எதுவும் குறிப்பிடப்படவில்லை", + "mandatory": "கட்டாயம்", + "optional": "விருப்பத்திற்குரியது", + "UniGetUI {0} is ready to be installed.": "UniGetUI {0} install செய்யத் தயாராக உள்ளது.", + "The update process will start after closing UniGetUI": "UniGetUI மூடிய பிறகு update process தொடங்கும்", + "UniGetUI has been ran as administrator, which is not recommended. When running UniGetUI as administrator, EVERY operation launched from UniGetUI will have administrator privileges. You can still use the program, but we highly recommend not running UniGetUI with administrator privileges.": "UniGetUI நிர்வாகியாக இயக்கப்பட்டுள்ளது, இது பரிந்துரைக்கப்படவில்லை. UniGetUI-ஐ நிர்வாகியாக இயக்கும் போது, UniGetUI-இல் இருந்து தொடங்கப்படும் ஒவ்வொரு செயல்பாடும் நிர்வாகி அனுமதிகளுடன் இயங்கும். நீங்கள் இன்னும் இந்த நிரலைப் பயன்படுத்தலாம்; ஆனால் UniGetUI-ஐ நிர்வாகி அனுமதிகளுடன் இயக்க வேண்டாம் என்று நாங்கள் வலியுறுத்துகிறோம்.", + "Share anonymous usage data": "பெயரில்லா usage data ஐ பகிர்", + "UniGetUI collects anonymous usage data in order to improve the user experience.": "user experience ஐ மேம்படுத்த UniGetUI பெயரில்லா usage data ஐ சேகரிக்கிறது.", + "Accept": "ஒத்திரு", + "Software Updates": "மென்பொருள் புதுப்பிப்புகள்", + "Package Bundles": "தொகுப்பு பண்டில்கள்", + "Settings": "settings", + "Package Managers": "தொகுப்பு மேலாளர்கள்", + "UniGetUI Log": "UniGetUI பதிவு", + "Package Manager logs": "தொகுப்பு மேலாளர் பதிவுகள்", + "Operation history": "செயல்பாட்டு வரலாறு", + "Help": "உதவி", + "UniGetUI": "UniGetUI", + "You have installed UniGetUI Version {0}": "நீங்கள் UniGetUI Version {0} ஐ install செய்துள்ளீர்கள்", + "Disclaimer": "பொறுப்புத்துறப்பு", + "UniGetUI is developed by Devolutions and is not affiliated with any of the compatible package managers.": "UniGetUI, Devolutions மூலம் உருவாக்கப்பட்டது; இது எந்த இணக்கமான தொகுப்பு மேலாளர்களுடனும் இணைக்கப்படவில்லை.", + "UniGetUI wouldn't have been possible without the help of the contributors. Thank you all 🥳": "contributors இன் உதவியில்லாமல் UniGetUI சாத்தியமாகியிருக்காது. அனைவருக்கும் நன்றி 🥳", + "UniGetUI uses the following libraries. Without them, UniGetUI wouldn't have been possible.": "UniGetUI பின்வரும் libraries ஐப் பயன்படுத்துகிறது. அவற்றில்லாமல் UniGetUI சாத்தியமாகியிருக்காது.", + "{0} homepage": "{0} முகப்புப்பக்கம்", + "UniGetUI has been translated to more than 40 languages thanks to the volunteer translators. Thank you 🤝": "தன்னார்வ மொழிபெயர்ப்பாளர்களின் உதவியால் UniGetUI 40 க்கும் மேற்பட்ட மொழிகளுக்கு மொழிபெயர்க்கப்பட்டுள்ளது. நன்றி 🤝", + "Verbose": "விரிவான", + "1 - Errors": "1 - பிழைகள்", + "2 - Warnings": "2 - எச்சரிக்கைகள்", + "3 - Information (less)": "3 - தகவல் (குறைவு)", + "4 - Information (more)": "4 - தகவல் (மேலும்)", + "5 - information (debug)": "5 - தகவல் (debug)", + "Warning": "எச்சரிக்கை", + "The following settings may pose a security risk, hence they are disabled by default.": "பின்வரும் settings பாதுகாப்பு ஆபத்தை உண்டாக்கக்கூடும்; ஆகவே அவை இயல்பாக முடக்கப்பட்டுள்ளன.", + "Enable the settings below if and only if you fully understand what they do, and the implications they may have.": "கீழே உள்ள settings என்ன செய்கின்றன மற்றும் அவற்றால் ஏற்படக்கூடிய விளைவுகளை நீங்கள் முழுமையாகப் புரிந்தால் மட்டுமே அவற்றை இயக்கு.", + "The settings will list, in their descriptions, the potential security issues they may have.": "settings இன் descriptions இல் அவற்றில் இருக்கக்கூடிய பாதுகாப்பு சிக்கல்கள் பட்டியலிடப்படும்.", + "The backup will include the complete list of the installed packages and their installation options. Ignored updates and skipped versions will also be saved.": "backup இல் install செய்யப்பட்ட packages மற்றும் அவற்றின் installation options ஆகியவற்றின் முழு பட்டியல் சேர்க்கப்படும். புறக்கணிக்கப்பட்ட updates மற்றும் skipped versions கூட சேமிக்கப்படும்.", + "The backup will NOT include any binary file nor any program's saved data.": "backup இல் எந்த binary file ம் அல்லது program saved data ம் சேர்க்கப்படாது.", + "The size of the backup is estimated to be less than 1MB.": "backup இன் அளவு 1MB க்குக் குறைவாக இருக்கும் என கணிக்கப்படுகிறது.", + "The backup will be performed after login.": "backup login ஆன பின் செய்யப்படும்.", + "{pcName} installed packages": "{pcName} இல் install செய்யப்பட்ட packages", + "Current status: Not logged in": "தற்போதைய நிலை: உள்நுழையவில்லை", + "You are logged in as {0} (@{1})": "நீங்கள் {0} (@{1}) ஆக உள்நுழைந்துள்ளீர்கள்", + "Nice! Backups will be uploaded to a private gist on your account": "அருமை! backups உங்கள் account இல் private gist ஆக upload செய்யப்படும்", + "Select backup": "backup ஐத் தேர்ந்தெடு", + "Settings imported from {0}": "{0} இலிருந்து அமைப்புகள் இறக்குமதி செய்யப்பட்டன", + "UniGetUI Settings": "UniGetUI அமைப்புகள்", + "Settings exported to {0}": "அமைப்புகள் {0} க்கு ஏற்றுமதி செய்யப்பட்டன", + "UniGetUI settings were reset": "UniGetUI அமைப்புகள் மீட்டமைக்கப்பட்டன", + "Allow pre-release versions": "pre-release பதிப்புகளுக்கு அனுமதி கொடு", + "Apply": "இடு", + "For security reasons, custom command-line arguments are disabled by default. Go to UniGetUI security settings to change this.": "பாதுகாப்பு காரணங்களால், தனிப்பயன் கட்டளைவரி arguments இயல்பாக முடக்கப்பட்டுள்ளன. இதை மாற்ற UniGetUI பாதுகாப்பு அமைப்புகளுக்கு செல்லவும்.", + "Go to UniGetUI security settings": "UniGetUI security settings க்கு செல்லவும்", + "The following options will be applied by default each time a {0} package is installed, upgraded or uninstalled.": "ஒவ்வொரு முறையும் {0} package install, upgrade அல்லது uninstall செய்யப்படும் போது பின்வரும் options இயல்பாகப் பயன்படுத்தப்படும்.", + "Package's default": "தொகுப்பின் இயல்புநிலை", + "Install location can't be changed for {0} packages": "{0} தொகுப்புகளுக்கான நிறுவல் இடத்தை மாற்ற முடியாது", + "The local icon cache currently takes {0} MB": "உள்ளூர் சின்ன தற்காலிக சேமிப்பு தற்போது {0} MB இடத்தைப் பயன்படுத்துகிறது", + "Username": "பயனர்பெயர்", + "Password": "கடவுச்சொல்", + "Credentials": "அடையாளச் சான்றுகள்", + "It is not guaranteed that the provided credentials will be stored safely": "வழங்கப்பட்ட அடையாளச் சான்றுகள் பாதுகாப்பாக சேமிக்கப்படும் என்று உத்தரவாதமில்லை", + "Partially": "பகுதியாக", + "Package manager": "தொகுப்பு மேலாளர்", + "Compatible with proxy": "ப்ராக்ஸியுடன் பொருந்தும்", + "Compatible with authentication": "அங்கீகாரத்துடன் பொருந்தும்", + "Proxy compatibility table": "ப்ராக்ஸி பொருந்துதலின் அட்டவணை", + "{0} settings": "{0} அமைப்புகள்", + "{0} status": "{0} நிலை", + "Default installation options for {0} packages": "{0} தொகுப்புகளுக்கான இயல்புநிலை நிறுவல் விருப்பங்கள்", + "Expand version": "பதிப்பை விரிவாக்கு", + "The executable file for {0} was not found": "{0} க்கான executable file கிடைக்கவில்லை", + "{pm} is disabled": "{pm} முடக்கப்பட்டுள்ளது", + "Enable it to install packages from {pm}.": "{pm} இலிருந்து packages ஐ install செய்ய இதை இயக்கு.", + "{pm} is enabled and ready to go": "{pm} இயக்கப்பட்டு தயார் நிலையில் உள்ளது", + "{pm} version:": "{pm} பதிப்பு:", + "{pm} was not found!": "{pm} கிடைக்கவில்லை!", + "You may need to install {pm} in order to use it with UniGetUI.": "{pm} ஐ UniGetUI உடன் பயன்படுத்த அதை install செய்ய வேண்டியிருக்கலாம்.", + "Scoop Installer - UniGetUI": "Scoop நிறுவி - UniGetUI", + "Scoop Uninstaller - UniGetUI": "Scoop அகற்றுநர் - UniGetUI", + "Clearing Scoop cache - UniGetUI": "Scoop cache ஐ அழிக்கிறது - UniGetUI", + "Restart UniGetUI to fully apply changes": "மாற்றங்கள் முழுமையாக அமலாக UniGetUI ஐ மறுதொடக்கம் செய்யவும்", + "Restart UniGetUI": "UniGetUI ஐ restart செய்", + "Manage {0} sources": "{0} மூலங்களை நிர்வகி", + "Add source": "மூலத்தைச் சேர்", + "Add": "சேர்", + "Source name": "மூலத்தின் பெயர்", + "Source URL": "மூல URL", + "Other": "மற்றவை", + "No minimum age": "குறைந்தபட்ச வயது இல்லை", + "1 day": "ஒரு நாள்", + "{0} days": "{0} நாட்கள்", + "Custom...": "தனிப்பயன்...", + "{0} minutes": "{0} நிமிடங்கள்", + "1 hour": "ஒரு மணி நேரம்", + "{0} hours": "{0} மணிநேரங்கள்", + "1 week": "ஒரு வாரம்", + "Supports release dates": "வெளியீட்டு தேதிகளை ஆதரிக்கிறது", + "Release date support per package manager": "ஒவ்வொரு package manager-க்குமான வெளியீட்டு தேதி ஆதரவு", + "Search for packages": "தொகுப்புகளைத் தேடு", + "Local": "உள்ளூர்", + "OK": "சரி", + "Last checked: {0}": "கடைசியாக சரிபார்க்கப்பட்டது: {0}", + "{0} packages were found, {1} of which match the specified filters.": "{0} தொகுப்புகள் கண்டறியப்பட்டன, அவற்றில் {1} குறிப்பிட்ட வடிகட்டிகளுடன் பொருந்துகின்றன.", + "{0} selected": "{0} தேர்ந்தெடுக்கப்பட்டது", + "(Last checked: {0})": "(கடைசியாக சரிபார்க்கப்பட்டது: {0})", + "All packages selected": "அனைத்து தொகுப்புகளும் தேர்ந்தெடுக்கப்பட்டன", + "Package selection cleared": "தொகுப்பு தேர்வு அழிக்கப்பட்டது", + "{0}: {1}": "{0}: {1}", + "More info": "மேலும் தகவல்", + "GitHub account": "GitHub கணக்கு", + "Log in with GitHub to enable cloud package backup.": "மேகத் தொகுப்பு காப்புப்பிரதியை செயல்படுத்த GitHub மூலம் உள்நுழையவும்.", + "More details": "மேலும் விவரங்கள்", + "Log in": "உள்நுழை", + "If you have cloud backup enabled, it will be saved as a GitHub Gist on this account": "மேகக் காப்புப்பிரதி இயக்கப்பட்டிருந்தால், அது இந்த கணக்கில் GitHub Gist ஆக சேமிக்கப்படும்", + "Log out": "வெளியேறு", + "About UniGetUI": "UniGetUI பற்றி", + "About": "பற்றி", + "Third-party licenses": "மூன்றாம் தரப்பு உரிமங்கள்", + "Contributors": "பங்களிப்பாளர்கள்", + "Translators": "மொழிபெயர்ப்பாளர்கள்", + "Bundle security report": "bundle பாதுகாப்பு அறிக்கை", + "The bundle contained restricted content": "bundle இல் கட்டுப்படுத்தப்பட்ட உள்ளடக்கம் இருந்தது", + "UniGetUI – Crash Report": "UniGetUI – செயலிழப்பு அறிக்கை", + "UniGetUI has crashed": "UniGetUI செயலிழந்தது", + "Help us fix this by sending a crash report to Devolutions. All fields below are optional.": "Devolutions க்கு செயலிழப்பு அறிக்கையை அனுப்புவதன் மூலம் இதைச் சரிசெய்ய எங்களுக்கு உதவுங்கள். கீழே உள்ள அனைத்து புலங்களும் விருப்பமானவை.", + "Email (optional)": "மின்னஞ்சல் (விருப்பமானது)", + "your@email.com": "your@email.com", + "Additional details (optional)": "கூடுதல் விவரங்கள் (விருப்பமானது)", + "Describe what you were doing when the crash occurred…": "செயலிழப்பு நிகழும்போது நீங்கள் என்ன செய்துகொண்டிருந்தீர்கள் என்பதை விவரிக்கவும்…", + "Crash report": "செயலிழப்பு அறிக்கை", + "Don't Send": "அனுப்ப வேண்டாம்", + "Send Report": "அறிக்கையை அனுப்பு", + "Sending…": "அனுப்புகிறது…", + "Unsaved changes": "சேமிக்கப்படாத மாற்றங்கள்", + "You have unsaved changes in the current bundle. Do you want to discard them?": "தற்போதைய bundle இல் சேமிக்கப்படாத மாற்றங்கள் உள்ளன. அவற்றை நிராகரிக்க விரும்புகிறீர்களா?", + "Discard changes": "மாற்றங்களை நிராகரி", + "Integrity violation": "முழுமைத்தன்மை மீறல்", + "UniGetUI or some of its components are missing or corrupt. It is strongly recommended to reinstall UniGetUI to adress the situation.": "UniGetUI அல்லது அதன் சில கூறுகள் காணாமல் போயுள்ளன அல்லது சேதமடைந்துள்ளன. இந்த நிலையை சரிசெய்ய UniGetUI ஐ மீண்டும் நிறுவுவது வலுவாக பரிந்துரைக்கப்படுகிறது.", + "• Refer to the UniGetUI Logs to get more details regarding the affected file(s)": "• பாதிக்கப்பட்ட file(s) குறித்த மேலும் விவரங்களுக்கு UniGetUI Logs ஐ பார்க்கவும்", + "• Integrity checks can be disabled from the Experimental Settings": "• integrity checks ஐ Experimental Settings இலிருந்து முடக்கலாம்", + "Manage shortcuts": "குறுக்குவழிகளை நிர்வகி", + "UniGetUI has detected the following desktop shortcuts which can be removed automatically on future upgrades": "எதிர்கால புதுப்பிப்புகளில் தானாக அகற்றக்கூடிய பின்வரும் டெஸ்க்டாப் குறுக்குவழிகளை UniGetUI கண்டறிந்துள்ளது", + "Do you really want to reset this list? This action cannot be reverted.": "இந்த பட்டியலை உண்மையிலேயே மீட்டமைக்க விரும்புகிறீர்களா? இந்த செயலைத் திரும்ப மாற்ற முடியாது.", + "Desktop shortcuts list": "டெஸ்க்டாப் குறுக்குவழிகள் பட்டியல்", + "Open in explorer": "எக்ஸ்ப்ளோரரில் திற", + "Remove from list": "பட்டியலிலிருந்து அகற்று", + "When new shortcuts are detected, delete them automatically instead of showing this dialog.": "புதிய shortcuts கண்டறியப்படும் போது இந்த dialog ஐக் காட்டுவதற்கு பதிலாக அவற்றை தானாக delete செய்.", + "Not right now": "இப்போது வேண்டாம்", + "Missing dependency": "சார்பு இல்லை", + "UniGetUI requires {0} to operate, but it was not found on your system.": "UniGetUI இயங்க {0} தேவைப்படுகிறது, ஆனால் அது உங்கள் system இல் கிடைக்கவில்லை.", + "Click on Install to begin the installation process. If you skip the installation, UniGetUI may not work as expected.": "installation process ஐ ஆரம்பிக்க Install ஐ கிளிக் செய்யவும். நீங்கள் installation ஐ தவிர்த்தால், UniGetUI எதிர்பார்த்தபடி வேலை செய்யாமல் இருக்கலாம்.", + "Alternatively, you can also install {0} by running the following command in a Windows PowerShell prompt:": "மாற்றாக, Windows PowerShell prompt இல் பின்வரும் command ஐ இயக்கி {0} ஐ நிறுவலாம்:", + "Install {0}": "{0} ஐ install செய்", + "Do not show this dialog again for {0}": "{0} க்காக இந்த dialog ஐ மீண்டும் காட்ட வேண்டாம்", + "Please wait while {0} is being installed. A black window may show up. Please wait until it closes.": "{0} install செய்யப்படும் வரை தயவுசெய்து காத்திருக்கவும். கருப்பு (அல்லது நீல) window ஒன்று தோன்றலாம். அது மூடப்படும் வரை காத்திருக்கவும்.", + "{0} has been installed successfully.": "{0} வெற்றிகரமாக install செய்யப்பட்டது.", + "Please click on \"Continue\" to continue": "தொடர \"Continue\" ஐ click செய்யவும்", + "Continue": "தொடர்", + "{0} has been installed successfully. It is recommended to restart UniGetUI to finish the installation": "{0} வெற்றிகரமாக install செய்யப்பட்டது. installation ஐ முடிக்க UniGetUI ஐ restart செய்ய பரிந்துரைக்கப்படுகிறது", + "Restart later": "பிறகு restart செய்", + "An error occurred:": "ஒரு பிழை ஏற்பட்டது.", + "Please see the Command-line Output or refer to the Operation History for further information about the issue.": "சிக்கல் குறித்து மேலும் அறிய கட்டளைவரி வெளியீட்டை அல்லது செயல்பாட்டு வரலாற்றைப் பார்க்கவும்.", + "Retry as administrator": "administrator ஆக மீண்டும் முயற்சி செய்", + "Retry interactively": "interactive ஆக மீண்டும் முயற்சி செய்", + "Retry skipping integrity checks": "integrity checks ஐ தவிர்த்து மீண்டும் முயற்சி செய்", + "Installation options": "நிறுவல் விருப்பங்கள்", + "Save": "சேமி", + "UniGetUI collects anonymous usage data with the sole purpose of understanding and improving the user experience.": "user experience ஐப் புரிந்து மேம்படுத்தும் ஒரே நோக்கத்திற்காக UniGetUI பெயரில்லா usage data ஐ சேகரிக்கிறது.", + "More details about the shared data and how it will be processed": "பகிரப்பட்ட தரவு மற்றும் அது எவ்வாறு செயலாக்கப்படும் என்பதற்கான மேலும் விவரங்கள்", + "Do you accept that UniGetUI collects and sends anonymous usage statistics, with the sole purpose of understanding and improving the user experience?": "user experience ஐப் புரிந்து மேம்படுத்தும் ஒரே நோக்கத்திற்காக UniGetUI பெயரில்லா usage statistics ஐ சேகரித்து அனுப்புவதை ஏற்கிறீர்களா?", + "Decline": "நிராகரி", + "No personal information is collected nor sent, and the collected data is anonimized, so it can't be back-tracked to you.": "தனிப்பட்ட தகவல் எதுவும் சேகரிக்கப்படவும் அனுப்பப்படவும் இல்லை. சேகரிக்கப்பட்ட தரவு anonimized ஆக இருப்பதால் அது உங்களிடம் திரும்பப் பின்தொடர முடியாது.", + "Navigation panel": "வழிசெலுத்தல் பலகம்", + "Operations": "செயல்பாடுகள்", + "Toggle operations panel": "செயல்பாடுகள் பலகையை காட்டு/மறை", + "Bulk operations": "மொத்த செயல்பாடுகள்", + "Retry failed": "தோல்வியுற்றவற்றை மீண்டும் முயற்சி செய்", + "Clear successful": "வெற்றிகரமானவற்றை அழி", + "Clear finished": "முடிந்தவற்றை அழி", + "Cancel all": "அனைத்தையும் ரத்து செய்", + "More": "மேலும்", + "Toggle navigation panel": "வழிசெலுத்தல் பலகையை மாற்றிக் காட்டு", + "Minimize": "சுருக்கு", + "Maximize": "பெரிதாக்கு", + "UniGetUI by Devolutions": "Devolutions வழங்கும் UniGetUI", + "UniGetUI is an application that makes managing your software easier, by providing an all-in-one graphical interface for your command-line package managers.": "உங்கள் command-line package managers க்காக all-in-one graphical interface ஒன்றை வழங்கி software நிர்வகிப்பதை எளிதாக்கும் application தான் UniGetUI.", + "Useful links": "பயனுள்ள links", + "UniGetUI Homepage": "UniGetUI முகப்புப்பக்கம்", + "Report an issue or submit a feature request": "ஒரு issue ஐ report செய்யவும் அல்லது feature request ஐ சமர்ப்பிக்கவும்", + "UniGetUI Repository": "UniGetUI சேமிப்பகம்", + "View GitHub Profile": "GitHub profile ஐப் பார்", + "UniGetUI License": "UniGetUI உரிமம்", + "Using UniGetUI implies the acceptation of the MIT License": "UniGetUI ஐப் பயன்படுத்துவது MIT License ஐ ஏற்றுக்கொள்வதை குறிக்கிறது", + "Become a translator": "மொழிபெயர்ப்பாளராகுங்கள்", + "Go back": "பின் செல்", + "Go forward": "முன் செல்", + "Go to home page": "முகப்புப் பக்கத்திற்குச் செல்", + "Reload page": "பக்கத்தை மீள்ஏற்று", + "View page on browser": "browser இல் page ஐப் பார்", + "The built-in browser is not supported on Linux yet.": "உள்ளமைந்த உலாவி Linux இல் இன்னும் ஆதரிக்கப்படவில்லை.", + "Open in browser": "உலாவியில் திற", + "Copy to clipboard": "clipboard க்கு நகலெடு", + "Export to a file": "file க்கு ஏற்றுமதி செய்", + "Log level:": "log நிலை:", + "Reload log": "log ஐ மீண்டும் ஏற்று", + "Export log": "பதிவை ஏற்றுமதி செய்", + "Text": "உரை", + "Change how operations request administrator rights": "operations எவ்வாறு administrator rights கோருகின்றன என்பதை மாற்று", + "Restrictions on package operations": "package operations மீதான கட்டுப்பாடுகள்", + "Restrictions on package managers": "package managers மீதான கட்டுப்பாடுகள்", + "Restrictions when importing package bundles": "package bundles import செய்யும் போது உள்ள கட்டுப்பாடுகள்", + "Ask for administrator privileges once for each batch of operations": "ஒவ்வொரு batch செயல்பாட்டிற்கும் ஒருமுறை நிர்வாகி சிறப்புரிமைகளை கேள்", + "Ask only once for administrator privileges": "நிர்வாகி சிறப்புரிமைகளை ஒருமுறை மட்டும் கேள்", + "Prohibit any kind of Elevation via UniGetUI Elevator or GSudo": "UniGetUI Elevator அல்லது GSudo வழியாக எந்தவித elevation ஐயும் தடை செய்", + "This option WILL cause issues. Any operation incapable of elevating itself WILL FAIL. Install/update/uninstall as administrator will NOT WORK.": "இந்த option கண்டிப்பாக சிக்கல்களை உருவாக்கும். தானாக elevate செய்ய முடியாத எந்த operation ம் தோல்வியடையும். administrator ஆக Install/update/uninstall வேலை செய்யாது.", + "Allow custom command-line arguments": "தனிப்பயன் command-line arguments க்கு அனுமதி கொடு", + "Custom command-line arguments can change the way in which programs are installed, upgraded or uninstalled, in a way UniGetUI cannot control. Using custom command-lines can break packages. Proceed with caution.": "UniGetUI கட்டுப்படுத்த முடியாத வகையில் programs install, upgrade அல்லது uninstall ஆகும் முறையை தனிப்பயன் command-line arguments மாற்றக்கூடும். தனிப்பயன் command-lines பயன்படுத்துவது packages ஐ பாதிக்கக்கூடும். கவனமாக தொடரவும்.", + "Ignore custom pre-install and post-install commands when importing packages from a bundle": "ஒரு bundle இலிருந்து தொகுப்புகளை இறக்குமதி செய்யும் போது தனிப்பயன் pre-install மற்றும் post-install கட்டளைகளை புறக்கணி", + "Pre and post install commands will be run before and after a package gets installed, upgraded or uninstalled. Be aware that they may break things unless used carefully": "ஒரு package install, upgrade அல்லது uninstall ஆகும் முன்பும் பின்னும் pre மற்றும் post install commands இயங்கும். அவற்றை கவனமாக பயன்படுத்தாவிட்டால் பிரச்சினைகள் உண்டாகலாம் என்பதை நினைவில் கொள்க", + "Allow changing the paths for package manager executables": "package manager executables க்கான பாதைகளை மாற்ற அனுமதி கொடு", + "Turning this on enables changing the executable file used to interact with package managers. While this allows finer-grained customization of your install processes, it may also be dangerous": "இதனை இயக்கினால் package managers உடன் தொடர்பு கொள்ள பயன்படும் executable file ஐ மாற்ற முடியும். இது install processes ஐ நுணுக்கமாக தனிப்பயனாக்க அனுமதிக்கும்; ஆனால் ஆபத்தும் இருக்கலாம்", + "Allow importing custom command-line arguments when importing packages from a bundle": "bundle இலிருந்து தொகுப்புகளை இறக்குமதி செய்யும்போது தனிப்பயன் command-line arguments ஐ இறக்குமதி செய்ய அனுமதி கொடு", + "Malformed command-line arguments can break packages, or even allow a malicious actor to gain privileged execution. Therefore, importing custom command-line arguments is disabled by default": "தவறான command-line arguments packages ஐ பாதிக்கலாம், அல்லது தீங்கு செய்பவருக்கு privileged execution ஐ வழங்கக்கூடும். ஆகவே custom command-line arguments ஐ import செய்வது இயல்புநிலையில் முடக்கப்பட்டுள்ளது.", + "Allow importing custom pre-install and post-install commands when importing packages from a bundle": "bundle இலிருந்து தொகுப்புகளை இறக்குமதி செய்யும்போது தனிப்பயன் pre-install மற்றும் post-install commands ஐ இறக்குமதி செய்ய அனுமதி கொடு", + "Pre and post install commands can do very nasty things to your device, if designed to do so. It can be very dangerous to import the commands from a bundle, unless you trust the source of that package bundle": "அவ்வாறு வடிவமைக்கப்பட்டிருந்தால் pre மற்றும் post install commands உங்கள் device க்கு மிகவும் தீங்கான செயல்களைச் செய்யலாம். package bundle இன் source மீது நம்பிக்கை இல்லையெனில் bundle இலிருந்து commands ஐ import செய்வது மிக ஆபத்தானது", + "Administrator rights and other dangerous settings": "நிர்வாகி உரிமைகள் மற்றும் பிற ஆபத்தான settings", + "Package backup": "தொகுப்பு காப்புப்பிரதி", + "Cloud package backup": "மேகத் தொகுப்பு காப்புப்பிரதி", + "Local package backup": "உள்ளூர் package backup", + "Local backup advanced options": "உள்ளூர் backup மேம்பட்ட விருப்பங்கள்", + "Log in with GitHub": "GitHub மூலம் உள்நுழையவும்", + "Log out from GitHub": "GitHub இலிருந்து வெளியேறு", + "Periodically perform a cloud backup of the installed packages": "install செய்யப்பட்ட packages க்கான cloud backup ஐ காலந்தோறும் செய்", + "Cloud backup uses a private GitHub Gist to store a list of installed packages": "installed packages பட்டியலை சேமிக்க cloud backup ஒரு private GitHub Gist ஐப் பயன்படுத்துகிறது", + "Perform a cloud backup now": "இப்போது cloud backup செய்", + "Backup": "காப்புப்பிரதி", + "Restore a backup from the cloud": "cloud இலிருந்து backup ஐ restore செய்", + "Begin the process to select a cloud backup and review which packages to restore": "cloud backup ஐத் தேர்ந்தெடுத்து எந்த தொகுப்புகளை மீட்டமைப்பது என்பதை பரிசீலிக்கும் செயல்முறையைத் தொடங்கு", + "Periodically perform a local backup of the installed packages": "install செய்யப்பட்ட packages க்கான local backup ஐ காலந்தோறும் செய்", + "Perform a local backup now": "இப்போது local backup செய்", + "Change backup output directory": "backup output directory ஐ மாற்று", + "Set a custom backup file name": "தனிப்பயன் backup file name ஐ அமை", + "Leave empty for default": "இயல்புநிலைக்கு காலியாக விடவும்", + "Add a timestamp to the backup file names": "காப்புப்பிரதி கோப்பு பெயர்களில் நேரமுத்திரையைச் சேர்", + "Backup and Restore": "காப்புப்பிரதி மற்றும் மீட்டமைப்பு", + "Enable background api (UniGetUI Widgets and Sharing, port 7058)": "background API ஐ இயக்கு (UniGetUI Widgets மற்றும் Sharing, port 7058)", + "Wait for the device to be connected to the internet before attempting to do tasks that require internet connectivity.": "internet connectivity தேவைப்படும் tasks ஐ முயற்சிக்கும் முன் device internet க்கு connect ஆகும் வரை காத்திருக்கவும்.", + "Disable the 1-minute timeout for package-related operations": "package தொடர்பான operations க்கான 1-minute timeout ஐ முடக்கு", + "Use installed GSudo instead of UniGetUI Elevator": "UniGetUI Elevator க்கு பதிலாக install செய்யப்பட்ட GSudo ஐப் பயன்படுத்து", + "Use a custom icon and screenshot database URL": "தனிப்பயன் icon மற்றும் screenshot database URL ஐப் பயன்படுத்து", + "Enable background CPU Usage optimizations (see Pull Request #3278)": "background CPU usage optimizations ஐ இயக்கு (Pull Request #3278 ஐ பார்க்கவும்)", + "Perform integrity checks at startup": "startup இல் integrity checks செய்", + "When batch installing packages from a bundle, install also packages that are already installed": "bundle இலிருந்து batch install செய்யும் போது ஏற்கனவே install செய்யப்பட்ட packages ஐயும் install செய்", + "Experimental settings and developer options": "பரிசோதனை settings மற்றும் developer options", + "Show UniGetUI's version and build number on the titlebar.": "titlebar இல் UniGetUI பதிப்பை காட்டு", + "Language": "மொழி", + "UniGetUI updater": "UniGetUI update கருவி", + "Telemetry": "டெலிமெட்ரி", + "Manage UniGetUI settings": "UniGetUI settings ஐ நிர்வகி", + "Related settings": "தொடர்புடைய settings", + "Update UniGetUI automatically": "UniGetUI ஐ தானாக update செய்", + "Check for updates": "updates க்கு சரிபார்", + "Install prerelease versions of UniGetUI": "UniGetUI இன் prerelease versions ஐ install செய்", + "Manage telemetry settings": "telemetry settings ஐ நிர்வகி", + "Manage": "நிர்வகி", + "Import settings from a local file": "local file இலிருந்து settings ஐ இறக்குமதி செய்", + "Import": "இறக்குமதி", + "Export settings to a local file": "settings ஐ local file க்கு ஏற்றுமதி செய்", + "Export": "ஏற்றுமதி", + "Reset UniGetUI": "UniGetUI ஐ reset செய்", + "User interface preferences": "user interface விருப்பங்கள்", + "Application theme, startup page, package icons, clear successful installs automatically": "பயன்பாட்டு theme, startup page, package icons, வெற்றிகரமான நிறுவல்களை தானாக நீக்கு", + "General preferences": "பொதுவான விருப்பங்கள்", + "UniGetUI display language:": "UniGetUI காட்சி மொழி:", + "System language": "கணினி மொழி", + "Is your language missing or incomplete?": "உங்கள் மொழி இல்லை அல்லது முழுமையில்லையா?", + "Appearance": "தோற்றம்", + "UniGetUI on the background and system tray": "background மற்றும் system tray இல் UniGetUI", + "Package lists": "package பட்டியல்கள்", + "Use classic mode": "பாரம்பரிய முறையைப் பயன்படுத்து", + "Restart UniGetUI to apply this change": "இந்த மாற்றத்தைப் பயன்படுத்த UniGetUI ஐ மறுதொடக்கம் செய்", + "The classic UI is disabled for beta testers": "பீட்டா சோதனையாளர்களுக்கு கிளாசிக் UI முடக்கப்பட்டுள்ளது", + "Close UniGetUI to the system tray": "UniGetUI ஐ system tray க்கு close செய்", + "Manage UniGetUI autostart behaviour": "UniGetUI தானியங்கு தொடக்க நடத்தையை நிர்வகி", + "Show package icons on package lists": "package பட்டியல்களில் package icons ஐ காட்டு", + "Clear cache": "cache ஐ அழி", + "Select upgradable packages by default": "upgrade செய்யக்கூடிய packages ஐ இயல்பாகத் தேர்ந்தெடு", + "Light": "ஒளிரும்", + "Dark": "இருண்ட", + "Follow system color scheme": "system color scheme ஐப் பின்பற்று", + "Application theme:": "ஆப் தீம்", + "UniGetUI startup page:": "UniGetUI தொடக்கப் பக்கம்:", + "Proxy settings": "ப்ராக்ஸி அமைப்புகள்", + "Other settings": "மற்ற settings", + "Connect the internet using a custom proxy": "custom proxy ஐப் பயன்படுத்தி internet க்கு இணை", + "Please note that not all package managers may fully support this feature": "அனைத்து package managers உம் இந்த feature ஐ முழுமையாக ஆதரிக்காமல் இருக்கலாம் என்பதை கவனிக்கவும்", + "Proxy URL": "ப்ராக்ஸி URL", + "Enter proxy URL here": "proxy URL ஐ இங்கே உள்ளிடவும்", + "Authenticate to the proxy with a user and a password": "proxy-இற்கு பயனர் பெயரும் கடவுச்சொல்லும் கொண்டு அங்கீகரி", + "Internet and proxy settings": "இணையம் மற்றும் proxy அமைப்புகள்", + "Package manager preferences": "தொகுப்பு மேலாளர் விருப்பங்கள்", + "Ready": "தயார்", + "Not found": "கிடைக்கவில்லை", + "Notification preferences": "notification விருப்பங்கள்", + "Notification types": "notification வகைகள்", + "The system tray icon must be enabled in order for notifications to work": "notifications வேலை செய்ய system tray icon இயங்கியிருக்க வேண்டும்", + "Enable UniGetUI notifications": "UniGetUI notifications ஐ இயக்கு", + "Show a notification when there are available updates": "updates கிடைக்கும் போது notification காட்டு", + "Show a silent notification when an operation is running": "operation நடக்கும் போது silent notification காட்டு", + "Show a notification when an operation fails": "operation தோல்வியடைந்தால் notification காட்டு", + "Show a notification when an operation finishes successfully": "operation வெற்றிகரமாக முடிந்தால் notification காட்டு", + "Concurrency and execution": "ஒரேநேர செயற்பாடு மற்றும் இயக்கம்", + "Automatic desktop shortcut remover": "தானியங்கி desktop shortcut அகற்றுபவர்", + "Choose how many operations should be performed in parallel": "ஒரே நேரத்தில் எத்தனை செயல்பாடுகள் செய்யப்பட வேண்டும் என்பதைத் தேர்ந்தெடு", + "Clear successful operations from the operation list after a 5 second delay": "5 விநாடி தாமதத்திற்குப் பிறகு operation list இலிருந்து வெற்றிகரமான operations ஐ அழி", + "Download operations are not affected by this setting": "இந்த setting download operations ஐ பாதிக்காது", + "You may lose unsaved data": "சேமிக்காத data ஐ இழக்கலாம்", + "Ask to delete desktop shortcuts created during an install or upgrade.": "நிறுவல் அல்லது upgrade இன் போது உருவான desktop shortcuts ஐ நீக்க வேண்டுமா என்று கேள்", + "Package update preferences": "package update விருப்பங்கள்", + "Update check frequency, automatically install updates, etc.": "update check frequency, updates ஐ தானாக install செய்தல் போன்றவை.", + "Reduce UAC prompts, elevate installations by default, unlock certain dangerous features, etc.": "UAC prompts ஐ குறை, installations ஐ இயல்பாக elevate செய், சில ஆபத்தான features ஐ unlock செய், போன்றவை.", + "Package operation preferences": "package operation விருப்பங்கள்", + "Enable {pm}": "{pm} ஐ இயக்கு", + "Not finding the file you are looking for? Make sure it has been added to path.": "நீங்கள் தேடும் file கிடைக்கவில்லையா? அது path இல் சேர்க்கப்பட்டுள்ளதா என்பதை உறுதிசெய்யவும்.", + "Select the executable to be used. The following list shows the executables found by UniGetUI": "பயன்படுத்த வேண்டிய executable ஐத் தேர்ந்தெடுக்கவும். கீழே உள்ள பட்டியல் UniGetUI கண்டறிந்த executables ஐக் காட்டுகிறது", + "For security reasons, changing the executable file is disabled by default": "பாதுகாப்பு காரணங்களுக்காக, executable file ஐ மாற்றுவது இயல்புநிலையில் முடக்கப்பட்டுள்ளது", + "Change this": "இதனை மாற்று", + "Copy path": "பாதையை நகலெடு", + "Current executable file:": "தற்போதைய இயக்கக்கோப்பு:", + "Ignore packages from {pm} when showing a notification about updates": "updates குறித்த notification காட்டும் போது {pm} இலிருந்து வரும் packages ஐ புறக்கணி", + "Update security": "புதுப்பிப்பு பாதுகாப்பு", + "Use global setting": "பொதுவான அமைப்பைப் பயன்படுத்து", + "Minimum age for updates": "புதுப்பிப்புகளுக்கான குறைந்தபட்ச வயது", + "e.g. 10": "எடுத்துக்காட்டு: 10", + "Custom minimum age (days)": "தனிப்பயன் குறைந்தபட்ச வயது (நாட்கள்)", + "{pm} does not provide release dates for its packages, so this setting will have no effect": "{pm} அதன் packages க்கான release dates ஐ வழங்காது; ஆகவே இந்த அமைப்பு எந்த விளைவையும் ஏற்படுத்தாது", + "{pm} only provides release dates for some of its packages, so this setting will only apply to those packages": "{pm} அதன் சில தொகுப்புகளுக்கு மட்டுமே வெளியீட்டுத் தேதிகளை வழங்குகிறது, எனவே இந்த அமைப்பு அந்தத் தொகுப்புகளுக்கு மட்டுமே பொருந்தும்", + "Override the global minimum update age for this package manager": "இந்த package manager க்கான பொது குறைந்தபட்ச update வயதை மாற்றி அமை", + "View {0} logs": "{0} logs ஐப் பார்", + "If Python cannot be found or is not listing packages but is installed on the system, ": "Python கண்டுபிடிக்கப்படவில்லை அல்லது packages பட்டியலிடப்படவில்லை, ஆனால் அது கணினியில் நிறுவப்பட்டிருந்தால், ", + "Advanced options": "மேம்பட்ட விருப்பங்கள்", + "WinGet command-line tool": "WinGet கட்டளைவரி கருவி", + "Choose which command-line tool UniGetUI uses for WinGet operations when the COM API is not used": "COM API பயன்படுத்தப்படாதபோது WinGet செயல்பாடுகளுக்கு UniGetUI எந்த கட்டளைவரி கருவியைப் பயன்படுத்தும் என்பதைத் தேர்ந்தெடுக்கவும்", + "WinGet COM API": "WinGet COM API", + "Choose whether UniGetUI can use the WinGet COM API before falling back to the command-line tool": "கட்டளைவரி கருவிக்கு மாறுவதற்கு முன் UniGetUI WinGet COM API ஐப் பயன்படுத்தலாமா என்பதைத் தேர்ந்தெடுக்கவும்", + "Reset WinGet": "WinGet ஐ reset செய்", + "This may help if no packages are listed": "packages எதுவும் பட்டியலிடப்படவில்லையெனில் இது உதவக்கூடும்", + "Force install location parameter when updating packages with custom locations": "custom locations உடன் packages ஐ update செய்யும் போது install location parameter ஐ கட்டாயப்படுத்து", + "Install Scoop": "Scoop ஐ install செய்", + "Uninstall Scoop (and its packages)": "Scoop ஐ (அதன் packages உடன்) uninstall செய்", + "Run cleanup and clear cache": "cleanup ஐ இயக்கு மற்றும் cache ஐ அழி", + "Run": "இயக்கு", + "Enable Scoop cleanup on launch": "launch இல் Scoop cleanup ஐ இயக்கு", + "Default vcpkg triplet": "இயல்புநிலை vcpkg triplet", + "Change vcpkg root location": "vcpkg root இடத்தை மாற்று", + "Reset vcpkg root location": "vcpkg ரூட் இருப்பிடத்தை மீட்டமை", + "Open vcpkg root location": "vcpkg ரூட் இருப்பிடத்தைத் திற", + "Language, theme and other miscellaneous preferences": "மொழி, theme மற்றும் பிற miscellaneous விருப்பங்கள்", + "Show notifications on different events": "பல்வேறு நிகழ்வுகளில் notifications காட்டு", + "Change how UniGetUI checks and installs available updates for your packages": "உங்கள் packages க்கான available updates ஐ UniGetUI எவ்வாறு சரிபார்த்து install செய்கிறது என்பதை மாற்று", + "Automatically save a list of all your installed packages to easily restore them.": "உங்கள் நிறுவப்பட்ட அனைத்து தொகுப்புகளின் பட்டியலை அவற்றை எளிதாக மீட்டமைக்க தானாகச் சேமி.", + "Enable and disable package managers, change default install options, etc.": "package managers ஐ இயக்கு அல்லது முடக்கு, default install options ஐ மாற்று, போன்றவை.", + "Internet connection settings": "இணைய இணைப்பு அமைப்புகள்", + "Proxy settings, etc.": "proxy settings, போன்றவை.", + "Beta features and other options that shouldn't be touched": "beta அம்சங்கள் மற்றும் தொடக்கூடாத பிற விருப்பங்கள்", + "Reload sources": "மூலங்களை மீள்ஏற்று", + "Delete source": "மூலத்தை நீக்கு", + "Known sources": "அறியப்பட்ட மூலங்கள்", + "Update checking": "update சரிபார்த்தல்", + "Automatic updates": "தானியங்கி புதுப்பிப்புகள்", + "Check for package updates periodically": "package updates க்கு காலந்தோறும் சரிபார்", + "Check for updates every:": "இதற்கொரு முறை updates க்கு சரிபார்:", + "Install available updates automatically": "கிடைக்கும் updates ஐ தானாக install செய்", + "Do not automatically install updates when the network connection is metered": "network connection metered ஆக இருக்கும்போது updates ஐ தானாக install செய்ய வேண்டாம்", + "Do not automatically install updates when the device runs on battery": "device battery இல் இயங்கும்போது updates ஐ தானாக install செய்ய வேண்டாம்", + "Do not automatically install updates when the battery saver is on": "battery saver இயங்கும்போது updates ஐ தானாக install செய்ய வேண்டாம்", + "Only show updates that are at least the specified number of days old": "குறிப்பிடப்பட்ட எண்ணிக்கையிலாவது நாட்கள் பழமையான புதுப்பிப்புகளை மட்டும் காட்டு", + "Warn me when the installer URL host changes between the installed version and the new version (WinGet only)": "நிறுவப்பட்ட பதிப்புக்கும் புதிய பதிப்புக்கும் இடையில் நிறுவி URL host மாறும்போது எனக்கு எச்சரிக்கை காட்டு (WinGet மட்டும்)", + "Change how UniGetUI handles install, update and uninstall operations.": "install, update மற்றும் uninstall operations ஐ UniGetUI எவ்வாறு கையாளுகிறது என்பதை மாற்று.", + "Navigation": "வழிசெலுத்தல்", + "Check for UniGetUI updates": "UniGetUI புதுப்பிப்புகளைச் சரிபார்", + "Quit UniGetUI": "UniGetUI இலிருந்து வெளியேறு", + "Filters": "வடிகட்டிகள்", + "Sources": "sources", + "Search for packages to start": "தொடங்க packages ஐத் தேடு", + "Select all": "அனைத்தையும் தேர்ந்தெடு", + "Clear selection": "தேர்வை அழி", + "Instant search": "உடனடி தேடல்", + "Distinguish between uppercase and lowercase": "uppercase மற்றும் lowercase ஐ வேறுபடுத்து", + "Ignore special characters": "special characters ஐ புறக்கணி", + "Search mode": "தேடல் முறை", + "Both": "இரண்டும்", + "Exact match": "சரியான பொருத்தம்", + "Show similar packages": "ஒத்த packages ஐ காட்டு", + "Loading": "ஏற்றுகிறது", + "Package": "package", + "More options": "மேலும் விருப்பங்கள்", + "Order by:": "இதன்படி வரிசைப்படுத்து:", + "Name": "பெயர்", + "Id": "அடையாளம்", + "Ascendant": "ஏறுவரிசை", + "Descendant": "சந்ததி", + "View modes": "காட்சி முறைகள்", + "Reload": "மீள்ஏற்று", + "Closed": "மூடப்பட்டது", + "Ascending": "ஏறுவரிசை", + "Descending": "இறங்குவரிசை", + "{0}: {1}, {2}": "{0}: {1}, {2}", + "Order by": "வரிசைப்படுத்து", + "No results were found matching the input criteria": "உள்ளீட்டு அளவுகோலுக்கு பொருந்தும் முடிவுகள் எதுவும் கிடைக்கவில்லை", + "No packages were found": "packages எதுவும் கிடைக்கவில்லை", + "Loading packages": "packages ஏற்றப்படுகின்றன", + "Skip integrity checks": "integrity checks ஐ தவிர்", + "Download selected installers": "தேர்ந்தெடுக்கப்பட்ட installers ஐப் பதிவிறக்கு", + "Install selection": "தேர்வை install செய்", + "Install options": "நிறுவல் விருப்பங்கள்", + "Add selection to bundle": "தேர்வை bundle இற்கு சேர்", + "Download installer": "installer ஐப் பதிவிறக்கு", + "Uninstall selection": "தேர்வை uninstall செய்", + "Uninstall options": "அகற்றல் விருப்பங்கள்", + "Ignore selected packages": "தேர்ந்தெடுக்கப்பட்ட packages ஐ புறக்கணி", + "Open install location": "install location ஐத் திற", + "Reinstall package": "package ஐ மறுபடியும் install செய்", + "Uninstall package, then reinstall it": "package ஐ uninstall செய்து, பின்னர் மறுபடியும் install செய்", + "Ignore updates for this package": "இந்த package க்கான updates ஐ புறக்கணி", + "WinGet malfunction detected": "WinGet கோளாறு கண்டறியப்பட்டது", + "It looks like WinGet is not working properly. Do you want to attempt to repair WinGet?": "WinGet சரியாக வேலை செய்யவில்லை போல தெரிகிறது. அதை repair செய்ய முயற்சிக்க விரும்புகிறீர்களா?", + "Repair WinGet": "WinGet ஐ repair செய்", + "Updates will no longer be ignored for {0}": "{0} க்கான புதுப்பிப்புகள் இனி புறக்கணிக்கப்படாது", + "Updates are now ignored for {0}": "{0} க்கான புதுப்பிப்புகள் இப்போது புறக்கணிக்கப்படுகின்றன", + "Do not ignore updates for this package anymore": "இந்த package க்கான updates ஐ இனி புறக்கணிக்க வேண்டாம்", + "Add packages or open an existing package bundle": "தொகுப்புகளைச் சேர்க்கவும் அல்லது ஏற்கனவே உள்ள package bundle ஐத் திறக்கவும்", + "Add packages to start": "தொடங்க தொகுப்புகளைச் சேர்", + "The current bundle has no packages. Add some packages to get started": "தற்போதைய bundle இல் packages எதுவும் இல்லை. தொடங்க சில packages ஐச் சேர்க்கவும்", + "New": "புதிய", + "Save as": "இவ்வாறு சேமி", + "Create .ps1 script": ".ps1 script உருவாக்கு", + "Remove selection from bundle": "bundle இலிருந்து தேர்வை அகற்று", + "Skip hash checks": "hash checks ஐ தவிர்", + "The package bundle is not valid": "package bundle செல்லுபடியாகவில்லை", + "The bundle you are trying to load appears to be invalid. Please check the file and try again.": "நீங்கள் load செய்ய முயல்கிற bundle தவறானதாக இருக்கிறது. file ஐ சரிபார்த்து மீண்டும் முயற்சிக்கவும்.", + "Package bundle": "தொகுப்பு பண்டில்", + "Could not create bundle": "bundle ஐ உருவாக்க முடியவில்லை", + "The package bundle could not be created due to an error.": "பிழையால் package bundle உருவாக்க முடியவில்லை.", + "Install script": "நிறுவல் ஸ்கிரிப்ட்", + "PowerShell script": "PowerShell ஸ்கிரிப்ட்", + "The installation script saved to {0}": "installation script {0} இல் சேமிக்கப்பட்டது", + "An error occurred": "ஒரு பிழை ஏற்பட்டது.", + "An error occurred while attempting to create an installation script:": "installation script உருவாக்க முயன்றபோது பிழை ஏற்பட்டது:", + "Hooray! No updates were found.": "அருமை! எந்த updates ம் கிடைக்கவில்லை.", + "Uninstall selected packages": "தேர்ந்தெடுக்கப்பட்ட packages ஐ uninstall செய்", + "Update selection": "தேர்வை update செய்", + "Update options": "புதுப்பிப்பு விருப்பங்கள்", + "Uninstall package, then update it": "package ஐ uninstall செய்து, பின்னர் update செய்", + "Uninstall package": "package ஐ uninstall செய்", + "Skip this version": "இந்த version ஐ தவிர்", + "Pause updates for": "updates ஐ இவ்வளவு நேரம் இடைநிறுத்து", + "User | Local": "பயனர் | உள்ளூர்", + "Machine | Global": "இயந்திரம் | உலகளாவிய", + "The default package manager for Debian/Ubuntu-based Linux distributions.
Contains: Debian/Ubuntu packages": "Debian/Ubuntu அடிப்படையிலான Linux விநியோகங்களுக்கான இயல்புநிலை தொகுப்பு மேலாளர்.
உள்ளடக்கம்: Debian/Ubuntu தொகுப்புகள்", + "The Rust package manager.
Contains: Rust libraries and programs written in Rust": "Rust package manager.
இதில் உள்ளவை: Rust libraries மற்றும் Rust இல் எழுதப்பட்ட programs", + "The classical package manager for windows. You'll find everything there.
Contains: General Software": "Windows க்கான பாரம்பரிய package manager. தேவையான எல்லாவற்றையும் அங்கே காணலாம்.
இதில் உள்ளவை: General Software", + "The default package manager for RHEL/Fedora-based Linux distributions.
Contains: RPM packages": "RHEL/Fedora அடிப்படையிலான Linux விநியோகங்களுக்கான இயல்புநிலை தொகுப்பு மேலாளர்.
உள்ளடக்கம்: RPM தொகுப்புகள்", + "A repository full of tools and executables designed with Microsoft's .NET ecosystem in mind.
Contains: .NET related tools and scripts": "Microsoft இன் .NET சூழலை மனதில் கொண்டு வடிவமைக்கப்பட்ட tools மற்றும் executables நிறைந்த repository.
உள்ளடக்கம்: .NET தொடர்புடைய tools மற்றும் scripts", + "The universal Linux package manager for desktop applications.
Contains: Flatpak applications from configured remotes": "டெஸ்க்டாப் பயன்பாடுகளுக்கான உலகளாவிய Linux தொகுப்பு மேலாளர்.
உள்ளடக்கம்: கட்டமைக்கப்பட்ட remotes இலிருந்து Flatpak பயன்பாடுகள்", + "NuPkg (zipped manifest)": "NuPkg (zip செய்யப்பட்ட manifest)", + "The Missing Package Manager for macOS (or Linux).
Contains: Formulae, Casks": "macOS (அல்லது Linux) க்கான குறைவாக இருந்த package manager.
இதில் உள்ளது: Formulae, Casks", + "Node JS's package manager. Full of libraries and other utilities that orbit the javascript world
Contains: Node javascript libraries and other related utilities": "Node JS இன் package manager. javascript உலகைச் சுற்றியுள்ள libraries மற்றும் மற்ற utilities நிரம்பியுள்ளது
இதில் உள்ளவை: Node javascript libraries மற்றும் தொடர்புடைய utilities", + "The default package manager for Arch Linux and its derivatives.
Contains: Arch Linux packages": "Arch Linux மற்றும் அதன் வழித்தோன்றல்களுக்கான இயல்புநிலை தொகுப்பு மேலாளர்.
உள்ளடக்கம்: Arch Linux தொகுப்புகள்", + "Python's library manager. Full of python libraries and other python-related utilities
Contains: Python libraries and related utilities": "Python இன் library manager. python libraries மற்றும் பிற python தொடர்பான utilities நிறைந்தது
இதில் உள்ளவை: Python libraries மற்றும் தொடர்புடைய utilities", + "PowerShell's package manager. Find libraries and scripts to expand PowerShell capabilities
Contains: Modules, Scripts, Cmdlets": "PowerShell இன் package manager. PowerShell திறன்களை விரிவுபடுத்த libraries மற்றும் scripts ஐ கண்டறிக
இதில் உள்ளவை: Modules, Scripts, Cmdlets", + "extracted": "extract செய்யப்பட்டது", + "Scoop package": "Scoop package தொகுப்பு", + "Great repository of unknown but useful utilities and other interesting packages.
Contains: Utilities, Command-line programs, General Software (extras bucket required)": "அறியப்படாத ஆனால் பயனுள்ள utilities மற்றும் மற்ற சுவாரஸ்யமான packages கொண்ட சிறந்த repository.
இதில் உள்ளவை: Utilities, Command-line programs, General Software (extras bucket தேவை)", + "The universal Linux package manager by Canonical.
Contains: Snap packages from the Snapcraft store": "Canonical நிறுவனத்தின் உலகளாவிய Linux தொகுப்பு மேலாளர்.
உள்ளடக்கம்: Snapcraft கடையிலிருந்து Snap தொகுப்புகள்", + "library": "நூலகம்", + "feature": "சிறப்பம்சம்", + "A popular C/C++ library manager. Full of C/C++ libraries and other C/C++-related utilities
Contains: C/C++ libraries and related utilities": "பிரபலமான C/C++ நூலக மேலாளர். C/C++ நூலகங்கள் மற்றும் பிற C/C++ தொடர்பான பயன்பாடுகள் நிரம்பியுள்ளது
உள்ளடக்கம்: C/C++ நூலகங்கள் மற்றும் தொடர்புடைய பயன்பாடுகள்", + "option": "விருப்பம்", + "This package cannot be installed from an elevated context.": "இந்த package ஐ elevated context இலிருந்து install செய்ய முடியாது.", + "Please run UniGetUI as a regular user and try again.": "UniGetUI ஐ சாதாரண user ஆக இயக்கி மீண்டும் முயற்சிக்கவும்.", + "Please check the installation options for this package and try again": "இந்த package இற்கான installation options ஐச் சரிபார்த்து மீண்டும் முயற்சிக்கவும்", + "Microsoft's official package manager. Full of well-known and verified packages
Contains: General Software, Microsoft Store apps": "Microsoft இன் அதிகாரப்பூர்வ package manager. நன்கு அறியப்பட்ட மற்றும் சரிபார்க்கப்பட்ட packages நிரம்பியுள்ளது
இதில் உள்ளவை: General Software, Microsoft Store apps", + "Local PC": "உள்ளூர் PC", + "Android Subsystem": "ஆண்ட்ராய்டு துணை அமைப்பு", + "Operation on queue (position {0})...": "queue இல் operation (position {0})...", + "Click here for more details": "மேலும் விவரங்களுக்கு இங்கே கிளிக் செய்யவும்", + "Operation canceled by user": "user operation ஐ ரத்து செய்தார்", + "Running PreOperation ({0}/{1})...": "PreOperation இயக்கப்படுகிறது ({0}/{1})...", + "PreOperation {0} out of {1} failed, and was tagged as necessary. Aborting...": "{1} இல் {0}வது PreOperation தோல்வியடைந்தது, மேலும் அது அவசியமானதாக குறிக்கப்பட்டிருந்தது. நிறுத்தப்படுகிறது...", + "PreOperation {0} out of {1} finished with result {2}": "{1} இல் {0}வது PreOperation, முடிவு {2} உடன் நிறைவடைந்தது", + "Starting operation...": "operation தொடங்குகிறது...", + "Running PostOperation ({0}/{1})...": "PostOperation இயக்கப்படுகிறது ({0}/{1})...", + "PostOperation {0} out of {1} failed, and was tagged as necessary. Aborting...": "{1} இல் {0}வது PostOperation தோல்வியடைந்தது, மேலும் அது அவசியமானதாக குறிக்கப்பட்டிருந்தது. நிறுத்தப்படுகிறது...", + "PostOperation {0} out of {1} finished with result {2}": "{1} இல் {0}வது PostOperation, முடிவு {2} உடன் நிறைவடைந்தது", + "{package} installer download": "{package} installer பதிவிறக்கம்", + "{0} installer is being downloaded": "{0} installer பதிவிறக்கப்படுகிறது", + "Download succeeded": "பதிவிறக்கம் வெற்றியடைந்தது", + "{package} installer was downloaded successfully": "{package} installer வெற்றிகரமாக பதிவிறக்கப்பட்டது", + "Download failed": "பதிவிறக்கம் தோல்வியடைந்தது", + "{package} installer could not be downloaded": "{package} installer பதிவிறக்க முடியவில்லை", + "{package} Installation": "{package} நிறுவல்", + "{0} is being installed": "{0} install செய்யப்படுகிறது", + "Installation succeeded": "installation வெற்றியடைந்தது", + "{package} was installed successfully": "{package} வெற்றிகரமாக install செய்யப்பட்டது", + "Installation failed": "installation தோல்வியடைந்தது", + "{package} could not be installed": "{package} install செய்ய முடியவில்லை", + "{package} Update": "{package} புதுப்பிப்பு", + "Update succeeded": "update வெற்றியடைந்தது", + "{package} was updated successfully": "{package} வெற்றிகரமாக update செய்யப்பட்டது", + "Update failed": "update தோல்வியடைந்தது", + "{package} could not be updated": "{package} update செய்ய முடியவில்லை", + "{package} Uninstall": "{package} அகற்றல்", + "{0} is being uninstalled": "{0} uninstall செய்யப்படுகிறது", + "Uninstall succeeded": "uninstall வெற்றியடைந்தது", + "{package} was uninstalled successfully": "{package} வெற்றிகரமாக uninstall செய்யப்பட்டது", + "Uninstall failed": "uninstall தோல்வியடைந்தது", + "{package} could not be uninstalled": "{package} uninstall செய்ய முடியவில்லை", + "Adding source {source}": "{source} என்ற மூலத்தைச் சேர்க்கிறது", + "Adding source {source} to {manager}": "{source} source ஐ {manager} இற்கு சேர்க்கிறது", + "Source added successfully": "source வெற்றிகரமாக சேர்க்கப்பட்டது", + "The source {source} was added to {manager} successfully": "source {source} வெற்றிகரமாக {manager} இல் சேர்க்கப்பட்டது", + "Could not add source": "source ஐச் சேர்க்க முடியவில்லை", + "Could not add source {source} to {manager}": "{source} source ஐ {manager} இற்கு சேர்க்க முடியவில்லை", + "Removing source {source}": "source {source} அகற்றப்படுகிறது", + "Removing source {source} from {manager}": "{source} source ஐ {manager} இலிருந்து அகற்றுகிறது", + "Source removed successfully": "source வெற்றிகரமாக அகற்றப்பட்டது", + "The source {source} was removed from {manager} successfully": "source {source} வெற்றிகரமாக {manager} இலிருந்து அகற்றப்பட்டது", + "Could not remove source": "source ஐ அகற்ற முடியவில்லை", + "Could not remove source {source} from {manager}": "{source} source ஐ {manager} இலிருந்து அகற்ற முடியவில்லை", + "The package manager \"{0}\" was not found": "package manager \"{0}\" கிடைக்கவில்லை", + "The package manager \"{0}\" is disabled": "package manager \"{0}\" முடக்கப்பட்டுள்ளது", + "There is an error with the configuration of the package manager \"{0}\"": "package manager \"{0}\" இன் configuration இல் ஒரு பிழை உள்ளது", + "The package \"{0}\" was not found on the package manager \"{1}\"": "package \"{0}\" ஐ package manager \"{1}\" இல் கண்டுபிடிக்க முடியவில்லை", + "{0} is disabled": "{0} முடக்கப்பட்டுள்ளது", + "{0} weeks": "{0} வாரங்கள்", + "1 month": "1 மாதம்", + "{0} months": "{0} மாதங்கள்", + "Something went wrong": "ஏதோ தவறாகிவிட்டது", + "An interal error occurred. Please view the log for further details.": "உள் பிழை ஏற்பட்டது. கூடுதல் விவரங்களுக்கு log ஐ பார்க்கவும்.", + "No applicable installer was found for the package {0}": "package {0} க்கு பொருந்தும் installer எதுவும் கிடைக்கவில்லை", + "Integrity checks will not be performed during this operation": "இந்த operation நடக்கும் போது integrity checks செய்யப்படமாட்டாது", + "This is not recommended.": "இது பரிந்துரைக்கப்படவில்லை.", + "Run now": "இப்போது இயக்கு", + "Run next": "அடுத்ததாக இயக்கு", + "Run last": "கடைசியில் இயக்கு", + "Show in explorer": "explorer இல் காட்டு", + "Checked": "தேர்வுசெய்யப்பட்டது", + "Unchecked": "தேர்வுசெய்யப்படவில்லை", + "This package is already installed": "இந்த package ஏற்கனவே install செய்யப்பட்டுள்ளது", + "This package can be upgraded to version {0}": "இந்த package ஐ version {0} க்கு upgrade செய்யலாம்", + "Updates for this package are ignored": "இந்த package க்கான updates புறக்கணிக்கப்படுகின்றன", + "This package is being processed": "இந்த package செயலாக்கப்படுகிறது", + "This package is not available": "இந்த package கிடைக்கவில்லை", + "Select the source you want to add:": "நீங்கள் சேர்க்க விரும்பும் source ஐத் தேர்ந்தெடுக்கவும்:", + "Source name:": "source பெயர்:", + "Source URL:": "மூல URL:", + "An error occurred when adding the source: ": "மூலத்தைச் சேர்க்கும்போது பிழை ஏற்பட்டது: ", + "Package management made easy": "package management ஐ எளிதாக்கியது", + "version {0}": "பதிப்பு {0}", + "[RAN AS ADMINISTRATOR]": "[ADMINISTRATOR ஆக இயக்கப்பட்டது]", + "Portable mode": "கையடக்க முறை\n", + "DEBUG BUILD": "பிழைத்திருத்த கட்டமைப்பு", + "Here you can change UniGetUI's behaviour regarding the following shortcuts. Checking a shortcut will make UniGetUI delete it if if gets created on a future upgrade. Unchecking it will keep the shortcut intact": "பின்வரும் shortcuts குறித்து UniGetUI இன் நடத்தையை இங்கே மாற்றலாம். ஒரு shortcut ஐ check செய்தால், அது எதிர்கால upgrade இல் உருவானால் UniGetUI அதை delete செய்யும். அதை uncheck செய்தால் shortcut அப்படியே இருக்கும்", + "Manual scan": "கைமுறை scan", + "Existing shortcuts on your desktop will be scanned, and you will need to pick which ones to keep and which ones to remove.": "உங்கள் desktop இல் உள்ள shortcuts scan செய்யப்படும், மேலும் எவற்றை வைத்திருக்க வேண்டும், எவற்றை அகற்ற வேண்டும் என்பதைக் நீங்கள் தேர்ந்தெடுக்க வேண்டும்.", + "Delete?": "நீக்கவா?", + "I understand": "எனக்கு புரிகிறது", + "Chocolatey setup changed": "Chocolatey அமைப்பு மாறியது", + "UniGetUI no longer includes its own private Chocolatey installation. A legacy UniGetUI-managed Chocolatey installation was detected for this user profile, but system Chocolatey was not found. Chocolatey will stay unavailable in UniGetUI until Chocolatey is installed on the system and UniGetUI is restarted. Applications previously installed through UniGetUI's bundled Chocolatey may still appear under other sources such as Local PC or WinGet.": "UniGetUI இனி தனது சொந்த தனிப்பட்ட Chocolatey நிறுவலைச் சேர்க்காது. இந்தப் பயனர் சுயவிவரத்தில் பழைய UniGetUI-நிர்வகிக்கப்பட்ட Chocolatey நிறுவல் கண்டறியப்பட்டது, ஆனால் கணினி Chocolatey கண்டறியப்படவில்லை. கணினியில் Chocolatey நிறுவப்பட்டு UniGetUI மறுதொடக்கம் செய்யப்படும் வரை UniGetUI இல் Chocolatey கிடைக்காது. UniGetUI இன் உள்ளடக்கிய Chocolatey மூலம் முன்பு நிறுவப்பட்ட பயன்பாடுகள் Local PC அல்லது WinGet போன்ற பிற மூலங்களின் கீழ் இன்னும் தோன்றலாம்.", + "NOTE: This troubleshooter can be disabled from UniGetUI Settings, on the WinGet section": "குறிப்பு: இந்த troubleshooter ஐ UniGetUI Settings இன் WinGet பிரிவில் முடக்கலாம்", + "Restart": "restart செய்", + "Are you sure you want to delete all shortcuts?": "அனைத்து shortcuts ஐயும் நீக்க விரும்புகிறீர்களா?", + "Any new shorcuts created during an install or an update operation will be deleted automatically, instead of showing a confirmation prompt the first time they are detected.": "நிறுவல் அல்லது புதுப்பிப்பு செயல்பாட்டின் போது உருவாகும் புதிய shortcuts முதன்முதலில் கண்டறியப்படும் போது உறுதிப்படுத்தும் prompt காட்டாமல் தானாகவே நீக்கப்படும்.", + "Any shorcuts created or modified outside of UniGetUI will be ignored. You will be able to add them via the {0} button.": "UniGetUI க்கு வெளியே உருவாக்கப்பட்ட அல்லது மாற்றப்பட்ட shortcuts புறக்கணிக்கப்படும். அவற்றை {0} பொத்தானின் மூலம் சேர்க்கலாம்.", + "Are you really sure you want to enable this feature?": "இந்த அம்சத்தை இயக்க நீங்கள் உண்மையிலேயே உறுதியாக உள்ளீர்களா?", + "No new shortcuts were found during the scan.": "scan இன் போது புதிய shortcuts எதுவும் கிடைக்கவில்லை.", + "How to add packages to a bundle": "bundle இற்கு packages ஐ எப்படி சேர்ப்பது", + "In order to add packages to a bundle, you will need to: ": "ஒரு bundle இற்கு packages ஐச் சேர்க்க, நீங்கள் இதை செய்ய வேண்டும்: ", + "1. Navigate to the \"{0}\" or \"{1}\" page.": "1. \"{0}\" அல்லது \"{1}\" பக்கத்துக்கு செல்லவும்.", + "2. Locate the package(s) you want to add to the bundle, and select their leftmost checkbox.": "2. தொகுப்பில் சேர்க்க விரும்பும் தொகுப்பு(களை) கண்டுபிடித்து, அவற்றின் இடதுபுற checkbox ஐ தேர்ந்தெடுக்கவும்.", + "3. When the packages you want to add to the bundle are selected, find and click the option \"{0}\" on the toolbar.": "3. தொகுப்பில் சேர்க்க வேண்டிய தொகுப்புகள் தேர்ந்தெடுக்கப்பட்ட பிறகு, toolbar இல் உள்ள \"{0}\" விருப்பத்தை கண்டுபிடித்து அழுத்தவும்.", + "4. Your packages will have been added to the bundle. You can continue adding packages, or export the bundle.": "4. உங்கள் தொகுப்புகள் bundle இல் சேர்க்கப்பட்டிருக்கும். நீங்கள் மேலும் தொகுப்புகளை சேர்க்கலாம் அல்லது bundle ஐ ஏற்றுமதி செய்யலாம்.", + "Which backup do you want to open?": "நீங்கள் எந்த backup ஐத் திறக்க விரும்புகிறீர்கள்?", + "Select the backup you want to open. Later, you will be able to review which packages you want to install.": "நீங்கள் திறக்க விரும்பும் backup ஐத் தேர்ந்தெடுக்கவும். பின்னர் எந்த packages/programs ஐ restore செய்ய வேண்டும் என்பதை review செய்யலாம்.", + "There are ongoing operations. Quitting UniGetUI may cause them to fail. Do you want to continue?": "operations நடைபெற்று கொண்டிருக்கின்றன. UniGetUI யிலிருந்து வெளியேறினால் அவை தோல்வியடையக்கூடும். தொடர விரும்புகிறீர்களா?", + "UniGetUI or some of its components are missing or corrupt.": "UniGetUI அல்லது அதன் சில components காணாமல் போயுள்ளன அல்லது கெடுக்கப்பட்டுள்ளன.", + "It is strongly recommended to reinstall UniGetUI to adress the situation.": "இந்த நிலையை சரி செய்ய UniGetUI ஐ மறுபடியும் install செய்ய வலியுறுத்தப்படுகிறது.", + "Refer to the UniGetUI Logs to get more details regarding the affected file(s)": "பாதிக்கப்பட்ட file(s) குறித்த மேலும் விவரங்களுக்கு UniGetUI Logs ஐ பார்க்கவும்", + "Integrity checks can be disabled from the Experimental Settings": "integrity checks ஐ Experimental Settings இலிருந்து முடக்கலாம்", + "Repair UniGetUI": "UniGetUI ஐ repair செய்", + "Live output": "நேரடி output", + "This package bundle had some settings that are potentially dangerous, and may be ignored by default.": "இந்த package bundle இல் சில settings ஆபத்தானவையாக இருக்கக்கூடும்; ஆகவே அவை இயல்பாகப் புறக்கணிக்கப்படலாம்.", + "Entries that show in YELLOW will be IGNORED.": "YELLOW இல் காட்டப்படும் entries புறக்கணிக்கப்படும்.", + "Entries that show in RED will be IMPORTED.": "RED இல் காட்டப்படும் entries IMPORT செய்யப்படும்.", + "You can change this behavior on UniGetUI security settings.": "இந்த நடத்தையை UniGetUI security settings இல் மாற்றலாம்.", + "Open UniGetUI security settings": "UniGetUI security settings ஐத் திற", + "Should you modify the security settings, you will need to open the bundle again for the changes to take effect.": "security settings ஐ மாற்றினால், மாற்றங்கள் செயல்பட bundle ஐ மீண்டும் திறக்க வேண்டும்.", + "Details of the report:": "அறிக்கையின் விவரங்கள்:", + "Are you sure you want to create a new package bundle? ": "புதிய package bundle உருவாக்க விரும்புகிறீர்களா? ", + "Any unsaved changes will be lost": "சேமிக்கப்படாத மாற்றங்கள் அனைத்தும் இழக்கப்படும்", + "Warning!": "எச்சரிக்கை!", + "For security reasons, custom command-line arguments are disabled by default. Go to UniGetUI security settings to change this. ": "பாதுகாப்பு காரணங்களுக்காக, custom command-line arguments இயல்புநிலையில் முடக்கப்பட்டுள்ளன. இதை மாற்ற UniGetUI security settings க்கு செல்லவும். ", + "Change default options": "இயல்புநிலை விருப்பங்களை மாற்று", + "Ignore future updates for this package": "இந்த package க்கான எதிர்கால updates ஐ புறக்கணி", + "For security reasons, pre-operation and post-operation scripts are disabled by default. Go to UniGetUI security settings to change this. ": "பாதுகாப்பு காரணங்களுக்காக, pre-operation மற்றும் post-operation scripts இயல்புநிலையில் முடக்கப்பட்டுள்ளன. இதை மாற்ற UniGetUI security settings க்கு செல்லவும். ", + "You can define the commands that will be run before or after this package is installed, updated or uninstalled. They will be run on a command prompt, so CMD scripts will work here.": "இந்த package install, update அல்லது uninstall செய்யப்படும் முன் அல்லது பின் இயங்க வேண்டிய commands ஐ நீங்கள் வரையறுக்கலாம். அவை command prompt இல் இயங்கும்; ஆகவே CMD scripts இங்கே வேலை செய்யும்.", + "Change this and unlock": "இதனை மாற்றி unlock செய்", + "{0} Install options are currently locked because {0} follows the default install options.": "{0} இயல்புநிலை install options ஐப் பின்பற்றுவதால், {0} இன் Install options தற்போது lock செய்யப்பட்டுள்ளன.", + "Unset or unknown": "unset அல்லது அறியப்படாதது", + "This package has no screenshots or is missing the icon? Contrbute to UniGetUI by adding the missing icons and screenshots to our open, public database.": "இந்த package க்கு screenshots இல்லை அல்லது icon இல்லைதா? எங்கள் திறந்த public database இல் காணாமல் போன icons மற்றும் screenshots ஐச் சேர்த்து UniGetUI க்கு பங்களியுங்கள்.", + "Become a contributor": "பங்களிப்பாளராகுங்கள்", + "Update to {0} available": "{0} க்கு update கிடைக்கிறது", + "Reinstall": "மறுபடியும் install செய்", + "Installer not available": "installer கிடைக்கவில்லை", + "Version:": "பதிப்பு:", + "UniGetUI Version {0}": "UniGetUI பதிப்பு {0}", + "Performing backup, please wait...": "backup செய்யப்படுகிறது, தயவுசெய்து காத்திருக்கவும்...", + "An error occurred while logging in: ": "உள்நுழையும்போது பிழை ஏற்பட்டது: ", + "Fetching available backups...": "கிடைக்கக்கூடிய backups ஐப் பெறுகிறது...", + "Done!": "முடிந்தது!", + "The cloud backup has been loaded successfully.": "cloud backup வெற்றிகரமாக load செய்யப்பட்டது.", + "An error occurred while loading a backup: ": "காப்புப்பிரதியை ஏற்றும்போது பிழை ஏற்பட்டது: ", + "Backing up packages to GitHub Gist...": "தொகுப்புகளை GitHub Gist இற்கு காப்புப்பிரதி எடுக்கிறது...", + "Backup Successful": "காப்புப்பிரதி வெற்றிபெற்றது", + "The cloud backup completed successfully.": "cloud backup வெற்றிகரமாக முடிந்தது.", + "Could not back up packages to GitHub Gist: ": "packages ஐ GitHub Gist க்கு backup செய்ய முடியவில்லை: ", + "It is not guaranteed that the provided credentials will be stored safely, so you may as well not use the credentials of your bank account": "வழங்கப்பட்ட credentials பாதுகாப்பாக சேமிக்கப்படும் என்று உறுதி இல்லை; ஆகவே உங்கள் bank account credentials ஐ பயன்படுத்தாமல் இருப்பது நல்லது", + "Enable the automatic WinGet troubleshooter": "automatic WinGet troubleshooter ஐ இயக்கு", + "Add updates that fail with a 'no applicable update found' to the ignored updates list": "'no applicable update found' காரணமாக தோல்வியுறும் புதுப்பிப்புகளை புறக்கணிக்கப்பட்ட புதுப்பிப்புகள் பட்டியலில் சேர்", + "Invalid selection": "செல்லாத தேர்வு", + "No package was selected": "எந்த package ம் தேர்ந்தெடுக்கப்படவில்லை", + "More than 1 package was selected": "1 க்கும் மேற்பட்ட package தேர்ந்தெடுக்கப்பட்டது", + "List": "பட்டியல்", + "Grid": "கட்டம்", + "Icons": "icons", + "\"{0}\" is a local package and does not have available details": "\"{0}\" ஒரு உள்ளூர் தொகுப்பு மற்றும் இதில் கிடைக்கக்கூடிய விவரங்கள் இல்லை.", + "\"{0}\" is a local package and is not compatible with this feature": "\"{0}\" ஒரு உள்ளூர் தொகுப்பு மற்றும் இந்த அம்சத்துடன் இணக்கமாக இல்லை", + "Add packages to bundle": "bundle இற்கு தொகுப்புகளைச் சேர்", + "Preparing packages, please wait...": "packages தயாராக்கப்படுகின்றன, தயவுசெய்து காத்திருக்கவும்...", + "Loading packages, please wait...": "packages ஏற்றப்படுகின்றன, தயவுசெய்து காத்திருக்கவும்...", + "Saving packages, please wait...": "packages சேமிக்கப்படுகின்றன, தயவுசெய்து காத்திருக்கவும்...", + "The bundle was created successfully on {0}": "bundle {0} அன்று வெற்றிகரமாக உருவாக்கப்பட்டது", + "User profile": "பயனர் சுயவிவரம்", + "Error": "பிழை", + "Log in failed: ": "உள்நுழைவு தோல்வியடைந்தது: ", + "Log out failed: ": "வெளியேறல் தோல்வியடைந்தது: ", + "Package backup settings": "தொகுப்பு காப்புப்பிரதி அமைப்புகள்", + "Package managers": "தொகுப்பு மேலாளர்கள்", + "Manage UniGetUI autostart behaviour from the Settings app": "UniGetUI தானியங்கி தொடக்க நடத்தையை நிர்வகி", + "Choose how many operations shoulds be performed in parallel": "ஒரே நேரத்தில் எத்தனை செயல்பாடுகள் மேற்கொள்ளப்பட வேண்டும் என்பதைத் தேர்ந்தெடுக்கவும்", + "Something went wrong while launching the updater.": "updater ஐ தொடங்கும் போது ஏதோ தவறாகிவிட்டது.", + "Please try again later": "பின்னர் மீண்டும் முயற்சிக்கவும்", + "Show the release notes after UniGetUI is updated": "UniGetUI புதுப்பிக்கப்பட்ட பிறகு வெளியீட்டு குறிப்புகளைக் காட்டு" +} diff --git a/src/Languages/lang_th.json b/src/Languages/lang_th.json new file mode 100644 index 0000000..4504752 --- /dev/null +++ b/src/Languages/lang_th.json @@ -0,0 +1,851 @@ +{ + "{0} of {1} operations completed": "ดำเนินการเสร็จสิ้น {0} จาก {1} รายการ", + "{0} is now {1}": "{0} ตอนนี้เป็น {1}", + "Enabled": "เปิดใช้งาน", + "Disabled": "ปิดใช้งาน", + "Privacy": "ความเป็นส่วนตัว", + "Hide my username from the logs": "ซ่อนชื่อผู้ใช้ของฉันจากบันทึก", + "Replaces your username with **** in the logs. Restart UniGetUI to also hide it from already-recorded entries.": "แทนที่ชื่อผู้ใช้ของคุณด้วย **** ในบันทึก รีสตาร์ท UniGetUI เพื่อซ่อนชื่อผู้ใช้จากรายการที่บันทึกไว้แล้วด้วย", + "Your last update attempt did not complete.": "ความพยายามอัปเดตครั้งล่าสุดของคุณไม่เสร็จสมบูรณ์", + "UniGetUI could not confirm whether the update succeeded. Open the log to see what happened.": "UniGetUI ไม่สามารถยืนยันได้ว่าการอัปเดตสำเร็จหรือไม่ เปิดบันทึกเพื่อดูว่าเกิดอะไรขึ้น", + "View log": "ดูบันทึก", + "The installer reported success but did not restart UniGetUI.": "ตัวติดตั้งรายงานว่าสำเร็จ แต่ไม่ได้รีสตาร์ท UniGetUI", + "The installer failed to initialize.": "ตัวติดตั้งไม่สามารถเริ่มต้นได้", + "Setup was canceled before installation began.": "การตั้งค่าถูกยกเลิกก่อนเริ่มการติดตั้ง", + "A fatal error occurred during the preparation phase.": "เกิดข้อผิดพลาดร้ายแรงระหว่างขั้นตอนการเตรียมการ", + "A fatal error occurred during installation.": "เกิดข้อผิดพลาดร้ายแรงระหว่างการติดตั้ง", + "Installation was canceled while in progress.": "การติดตั้งถูกยกเลิกขณะกำลังดำเนินการ", + "The installer was terminated by another process.": "ตัวติดตั้งถูกยุติโดยกระบวนการอื่น", + "The preparation phase determined the installation cannot proceed.": "ขั้นตอนการเตรียมการระบุว่าการติดตั้งไม่สามารถดำเนินการต่อได้", + "The installer could not start. UniGetUI may already be running, or you do not have permission to install.": "ไม่สามารถเริ่มตัวติดตั้งได้ UniGetUI อาจกำลังทำงานอยู่แล้ว หรือคุณไม่มีสิทธิ์ในการติดตั้ง", + "Unexpected installer error.": "เกิดข้อผิดพลาดของตัวติดตั้งที่ไม่คาดคิด", + "We are checking for updates.": "อยู่ระหว่างการตรวจสอบอัปเดต", + "Please wait": "โปรดรอ", + "Great! You are on the latest version.": "เยี่ยมมาก! คุณใช้เวอร์ชันล่าสุดแล้ว", + "There are no new UniGetUI versions to be installed": "ไม่มี UniGetUI เวอร์ชันใหม่ให้ติดตั้ง", + "UniGetUI version {0} is being downloaded.": "กำลังดาวน์โหลด UniGetUI เวอร์ชัน {0}", + "This may take a minute or two": "การดำเนินการนี้อาจใช้เวลาประมาณหนึ่งถึงสองนาที", + "The installer authenticity could not be verified.": "ไม่สามารถตรวจสอบความถูกต้องของตัวติดตั้งได้", + "The update process has been aborted.": "กระบวนการอัปเดตถูกยกเลิกแล้ว", + "Auto-update is not yet available on this platform.": "การอัปเดตอัตโนมัติยังไม่พร้อมใช้งานบนแพลตฟอร์มนี้", + "Please update UniGetUI manually.": "โปรดอัปเดต UniGetUI ด้วยตนเอง", + "An error occurred when checking for updates: ": "มีข้อผิดพลาดเกิดขึ้นขณะตรวจสอบการอัปเดต:", + "The updater could not be launched.": "ไม่สามารถเปิดตัวอัปเดตได้", + "The operating system did not start the installer process.": "ระบบปฏิบัติการไม่ได้เริ่มกระบวนการตัวติดตั้ง", + "UniGetUI is being updated...": "UniGetUI กำลังอัปเดต...", + "Update installed.": "ติดตั้งการอัปเดตแล้ว", + "UniGetUI was updated successfully, but this running copy was not replaced. This usually means you are running a development build. Close this copy and start the newly-installed version to finish.": "อัปเดต UniGetUI สำเร็จแล้ว แต่สำเนาที่กำลังทำงานอยู่นี้ไม่ได้ถูกแทนที่ โดยปกติหมายความว่าคุณกำลังใช้งานบิลด์สำหรับการพัฒนา ปิดสำเนานี้แล้วเริ่มเวอร์ชันที่ติดตั้งใหม่เพื่อเสร็จสิ้น", + "The update could not be applied.": "ไม่สามารถนำการอัปเดตไปใช้ได้", + "Installer exit code {0}: {1}": "รหัสออกของตัวติดตั้ง {0}: {1}", + "Update cancelled.": "การอัปเดตถูกยกเลิก", + "Authentication was cancelled.": "การยืนยันตัวตนถูกยกเลิก", + "Installer exit code {0}": "รหัสออกของตัวติดตั้ง {0}", + "Operation in progress": "กำลังดำเนินการ", + "Please wait...": "กรุณารอสักครู่...", + "Success!": "สำเร็จ!", + "Failed": "ล้มเหลว", + "An error occurred while processing this package": "มีข้อผิดพลาดเกิดขึ้นขณะประมวลผลแพ็กเกจนี้", + "Installer": "ตัวติดตั้ง", + "Executable": "ไฟล์ปฏิบัติการ", + "MSI": "MSI", + "Compressed file": "ไฟล์บีบอัด", + "MSIX": "MSIX", + "WinGet was repaired successfully": "ซ่อมแซม WinGet สำเร็จ", + "It is recommended to restart UniGetUI after WinGet has been repaired": "แนะนำให้รีสตาร์ท UniGetUI หลังจากซ่อมแซม WinGet แล้ว", + "WinGet could not be repaired": "ไม่สามารถซ่อมแซม WinGet ได้", + "An unexpected issue occurred while attempting to repair WinGet. Please try again later": "เกิดปัญหาที่ไม่คาดคิดขึ้น ขณะพยายามซ่อมแซม WinGet กรุณาลองใหม่อีกครั้งในภายหลัง", + "Log in to enable cloud backup": "ลงชื่อเข้าใช้เพื่อสำรองข้อมูลบนคลาวด์", + "Backup Failed": "การสำรองข้อมูลล้มเหลว", + "Downloading backup...": "กำลังดาวน์โหลดข้อมูลสำรอง...", + "An update was found!": "พบการอัปเดต!", + "{0} can be updated to version {1}": "{0} สามารถอัปเดตเป็นเวอร์ชัน {1}", + "Updates found!": "พบอัปเดต!", + "{0} packages can be updated": "{0} แพ็กเกจสามารถอัปเดตได้", + "{0} is being updated to version {1}": "{0} กำลังอัปเดตเป็นเวอร์ชัน {1}", + "{0} packages are being updated": "{0} แพ็กเกจกำลังถูกอัปเดต", + "You have currently version {0} installed": "ขณะนี้คุณได้ติดตั้งเวอร์ชัน {0} แล้ว", + "Desktop shortcut created": "สร้างทางลัดบนเดสก์ท็อปแล้ว", + "UniGetUI has detected a new desktop shortcut that can be deleted automatically.": "UniGetUI ตรวจพบทางลัดบนเดสก์ท็อปใหม่ที่สามารถลบโดยอัตโนมัติได้", + "{0} desktop shortcuts created": "{0} ทางลัดบนเดสก์ท็อป ถูกสร้างแล้ว", + "UniGetUI has detected {0} new desktop shortcuts that can be deleted automatically.": "UniGetUI ตรวจพบทางลัดบนเดสก์ท็อปใหม่ {0} รายการที่สามารถลบโดยอัตโนมัติได้", + "Attention required": "ต้องการความสนใจ", + "Restart required": "จำเป็นต้องรีสตาร์ท", + "1 update is available": "มีการอัปเดต 1 รายการ", + "{0} updates are available": "มีการอัปเดตที่พร้อมใช้งาน {0} รายการ", + "Everything is up to date": "ทุกอย่างได้รับการอัปเดตแล้ว", + "Discover Packages": "ค้นหาแพ็กเกจ", + "Available Updates": "การอัปเดตที่พร้อมใช้งาน", + "Installed Packages": "แพ็กเกจที่ติดตั้ง", + "UniGetUI Version {0} by Devolutions": "UniGetUI เวอร์ชัน {0} โดย Devolutions", + "Show UniGetUI": "แสดง UniGetUI", + "Quit": "ออก", + "Are you sure?": "คุณแน่ใจใช่ไหม", + "Do you really want to uninstall {0}?": "คุณต้องการถอนการติดตั้ง {0} ใช่ไหม", + "Do you really want to uninstall the following {0} packages?": "คุณต้องการถอนการติดตั้ง {0} แพ็กเกจต่อไปนี้หรือไม่", + "No": "ไม่", + "Yes": "ใช่", + "Partial": "บางส่วน", + "View on UniGetUI": "ดูบน UnigetUI", + "Update": "อัปเดต", + "Open UniGetUI": "เปิด UniGetUI", + "Update all": "อัปเดตทั้งหมด", + "Update now": "อัปเดตทันที", + "Installer host changed since the installed version.\n": "โฮสต์ของตัวติดตั้งเปลี่ยนไปจากเวอร์ชันที่ติดตั้งอยู่\n", + "This package is on the queue": "แพ็กเกจนี้อยู่ในคิว", + "installing": "กำลังติดตั้ง", + "updating": "กำลังอัปเดต", + "uninstalling": "กำลังถอนการติดตั้ง", + "installed": "ติดตั้งสำเร็จ", + "Retry": "ลองใหม่อีกครั้ง", + "Install": "ติดตั้ง", + "Uninstall": "ถอนการติดตั้ง", + "Open": "เปิด", + "Operation profile:": "โปรไฟล์การดำเนินการ:", + "Follow the default options when installing, upgrading or uninstalling this package": "ใช้ตัวเลือกเริ่มต้นเมื่อติดตั้ง อัปเกรด หรือถอนการติดตั้งแพ็กเกจนี้", + "The following settings will be applied each time this package is installed, updated or removed.": "การตั้งค่าต่อไปนี้จะถูกนำไปใช้ทุกครั้งที่ติดตั้ง อัปเดต หรือลบแพ็กเกจนี้", + "Version to install:": "เวอร์ชันที่จะทำการติดตั้ง:", + "Architecture to install:": "สถาปัตยกรรมที่จะทำการติดตั้ง:", + "Installation scope:": "ขอบเขตการติดตั้ง:", + "Install location:": "ตำแหน่งติดตั้ง:", + "Select": "เลือก", + "Reset": "รีเซ็ต", + "Custom install arguments:": "อาร์กิวเมนต์การติดตั้งแบบกำหนดเอง:", + "Custom update arguments:": "อาร์กิวเมนต์การอัปเดตแบบกำหนดเอง:", + "Custom uninstall arguments:": "อาร์กิวเมนต์การถอนการติดตั้งแบบกำหนดเอง:", + "Pre-install command:": "คำสั่งก่อนการติดตั้ง:", + "Post-install command:": "คำสั่งหลังการติดตั้ง:", + "Abort install if pre-install command fails": "ยกเลิกการติดตั้งหากคำสั่ง pre-install ล้มเหลว", + "Pre-update command:": "คำสั่งก่อนการอัปเดต:", + "Post-update command:": "คำสั่งหลังการอัปเดต:", + "Abort update if pre-update command fails": "ยกเลิกการอัปเดตหากคำสั่งก่อนการอัปเดตล้มเหลว", + "Pre-uninstall command:": "คำสั่งก่อนการถอนการติดตั้ง:", + "Post-uninstall command:": "คำสั่งหลังการถอนการติดตั้ง:", + "Abort uninstall if pre-uninstall command fails": "ยกเลิกการถอนการติดตั้งหากคำสั่ง pre-uninstall ล้มเหลว", + "Command-line to run:": "บรรทัดคำสั่งที่จะรัน:", + "Save and close": "บันทึกและปิด", + "General": "ทั่วไป", + "Architecture & Location": "สถาปัตยกรรมและตำแหน่งที่ตั้ง", + "Command-line": "บรรทัดคำสั่ง", + "Close apps": "ปิดแอป", + "Pre/Post install": "ก่อน/หลังการติดตั้ง", + "Select the processes that should be closed before this package is installed, updated or uninstalled.": "เลือกกระบวนการที่ควรถูกปิดก่อนติดตั้ง อัปเดต หรือถอนการติดตั้งแพ็กเกจนี้", + "Write here the process names here, separated by commas (,)": "เขียนชื่อโปรเซสที่นี่ โดยคั่นด้วยเครื่องหมายจุลภาค (,)", + "Try to kill the processes that refuse to close when requested to": "พยายามปิดโปรเซสที่ปฏิเสธการปิดเมื่อมีการร้องขอ", + "Run as admin": "รันด้วยสิทธิ์ผู้ดูแลระบบ", + "Interactive installation": "ติดตั้งแบบอินเตอร์แอคทีฟ", + "Skip hash check": "ข้ามการตรวจสอบแฮช", + "Uninstall previous versions when updated": "ถอนการติดตั้งเวอร์ชันก่อนหน้าเมื่อมีการอัปเดต", + "Skip minor updates for this package": "ข้ามการอัปเดตย่อยสำหรับแพ็กเกจนี้", + "Automatically update this package": "อัปเดตแพ็กเกจนี้โดยอัตโนมัติ", + "{0} installation options": "{0} ตัวเลือกการติดตั้ง", + "Latest": "ล่าสุด", + "PreRelease": "ก่อนเผยแพร่", + "Default": "ค่าเริ่มต้น", + "Manage ignored updates": "จัดการการอัปเดตที่ถูกละเว้น", + "The packages listed here won't be taken in account when checking for updates. Double-click them or click the button on their right to stop ignoring their updates.": "แพ็กเกจที่มีรายชื่อดังต่อไปนี้จะไม่ถูกตรวจสอบการอัปเดต ดับเบิลคลิกที่รายชื่อหรือคลิกที่ปุ่มทางด้านขวาของรายชื่อเพื่อยกเลิกการละเว้นการอัปเดตรายการนั้น", + "Reset list": "รีเซ็ตรายการ", + "Do you really want to reset the ignored updates list? This action cannot be reverted": "คุณต้องการรีเซ็ตรายการอัปเดตที่ถูกละเว้นจริงหรือไม่? การกระทำนี้ไม่สามารถย้อนกลับได้", + "No ignored updates": "ไม่มีการอัปเดตที่ถูกละเว้น", + "Package Name": "ชื่อแพ็กเกจ", + "Package ID": "แพ็กเกจ ID", + "Ignored version": "เวอร์ชันที่ถูกละเว้น", + "New version": "เวอร์ชันใหม่", + "Source": "ซอร์ซ", + "All versions": "เวอร์ชันทั้งหมด", + "Unknown": "ไม่ทราบ", + "Up to date": "อัพเดทล่าสุด", + "Package {name} from {manager}": "แพ็กเกจ {name} จาก {manager}", + "Remove {0} from ignored updates": "ลบ {0} ออกจากรายการอัปเดตที่ถูกละเว้น", + "Cancel": "ยกเลิก", + "Administrator privileges": "สิทธิ์ผู้ดูแลระบบ", + "This operation is running with administrator privileges.": "การดำเนินการนี้กำลังทำงานด้วยสิทธิ์ผู้ดูแลระบบ", + "Interactive operation": "การดำเนินการแบบโต้ตอบ", + "This operation is running interactively.": "การดำเนินการนี้กำลังทำงานแบบโต้ตอบ", + "You will likely need to interact with the installer.": "คุณอาจต้องโต้ตอบกับตัวติดตั้ง", + "Integrity checks skipped": "ข้ามขั้นตอนการตรวจสอบ", + "Integrity checks will not be performed during this operation.": "จะไม่มีการตรวจสอบความถูกต้องระหว่างการดำเนินการนี้", + "Proceed at your own risk.": "โปรดดำเนินการโดยยอมรับความเสี่ยงด้วยตนเอง", + "Close": "ปิด", + "Loading...": "กำลังโหลด...", + "Installer SHA256": "SHA256 ของตัวติดตั้ง", + "Homepage": "เว็บไซต์", + "Author": "ผู้จัดทำ", + "Publisher": "ผู้เผยแพร่", + "License": "ลิขสิทธ์", + "Manifest": "แมนิเฟสต์", + "Installer Type": "ประเภทการติดตั้ง", + "Size": "ขนาด", + "Installer URL": "URL ติดตั้ง", + "Last updated:": "อัปเดตล่าสุด:", + "Release notes URL": "URL บันทึกประจำเวอร์ชัน", + "Package details": "รายละเอียดแพ็กเกจ", + "Dependencies:": "การอ้างอิง:", + "Release notes": "รายละเอียดการปรับปรุง", + "Screenshots": "ภาพหน้าจอ", + "This package has no screenshots or is missing the icon? Contribute to UniGetUI by adding the missing icons and screenshots to our open, public database.": "แพ็กเกจนี้ไม่มีภาพหน้าจอหรือไอคอนหายไปใช่หรือไม่? ร่วมพัฒนา UniGetUI โดยเพิ่มไอคอนและภาพหน้าจอที่ขาดหายไปลงในฐานข้อมูลสาธารณะแบบเปิดของเรา", + "Version": "เวอร์ชัน", + "Install as administrator": "ติดตั้งในฐานะผู้ดูแลระบบ", + "Update to version {0}": "อัปเดตเป็นเวอร์ชัน {0}", + "Installed Version": "เวอร์ชันที่ติดตั้ง", + "Update as administrator": "อัปเดตในฐานะผู้ดูแลระบบ", + "Interactive update": "การอัปเดตแบบอินเตอร์แอคทีฟ", + "Uninstall as administrator": "ถอนการติดตั้งในฐานะผู้ดูแลระบบ", + "Interactive uninstall": "การถอนการติดตั้งแบบอินเตอร์แอคทีฟ", + "Uninstall and remove data": "ถอนการติดตั้งและลบข้อมูล", + "Not available": "ไม่มีข้อมูล", + "Installer SHA512": "SHA512 ของตัวติดตั้ง", + "Unknown size": "ไม่ทราบขนาด", + "No dependencies specified": "ไม่ได้ระบุการอ้างอิงไว้", + "mandatory": "บังคับ", + "optional": "ไม่บังคับ", + "UniGetUI {0} is ready to be installed.": "UniGetUI {0} พร้อมสำหรับการติดตั้ง", + "The update process will start after closing UniGetUI": "กระบวนการอัปเดตจะเริ่มหลังจากปิด UniGetUI", + "UniGetUI has been ran as administrator, which is not recommended. When running UniGetUI as administrator, EVERY operation launched from UniGetUI will have administrator privileges. You can still use the program, but we highly recommend not running UniGetUI with administrator privileges.": "UniGetUI ถูกเรียกใช้ด้วยสิทธิ์ผู้ดูแลระบบ ซึ่งไม่แนะนำ เมื่อเรียกใช้ UniGetUI ด้วยสิทธิ์ผู้ดูแลระบบ ทุกการดำเนินการที่เริ่มจาก UniGetUI จะมีสิทธิ์ผู้ดูแลระบบ คุณยังสามารถใช้โปรแกรมได้ แต่เราแนะนำอย่างยิ่งว่าไม่ควรเรียกใช้ UniGetUI ด้วยสิทธิ์ผู้ดูแลระบบ", + "Share anonymous usage data": "แชร์ข้อมูลการใช้งานแบบไม่ระบุตัวตน", + "UniGetUI collects anonymous usage data in order to improve the user experience.": "UniGetUI เก็บรวบรวมข้อมูลการใช้งานแบบไม่ระบุตัวตนเพื่อปรับปรุงประสบการณ์ของผู้ใช้", + "Accept": "ยอมรับ", + "Software Updates": "การอัปเดต​ซอฟต์แวร์", + "Package Bundles": "แพ็กเกจบันเดิล", + "Settings": "การตั้งค่า", + "Package Managers": "ตัวจัดการแพ็กเกจ", + "UniGetUI Log": "บันทึกของ UniGetUI", + "Package Manager logs": "บันทึกการทำงานของตัวจัดการแพ็กเกจ", + "Operation history": "ประวัติการดำเนินการ", + "Help": "ความช่วยเหลือ", + "UniGetUI": "UniGetUI", + "You have installed UniGetUI Version {0}": "คุณได้ติดตั้ง UniGetUI เวอร์ชัน {0} แล้ว", + "Disclaimer": "คำสงวนสิทธิ์", + "UniGetUI is developed by Devolutions and is not affiliated with any of the compatible package managers.": "UniGetUI พัฒนาโดย Devolutions และไม่มีความเกี่ยวข้องกับตัวจัดการแพ็กเกจที่รองรับใด ๆ", + "UniGetUI wouldn't have been possible without the help of the contributors. Thank you all 🥳": "UniGetUI คงไม่เกิดขึ้นหากไม่ได้รับความช่วยเหลือจากผู้ที่มีส่วนช่วย ขอบคุณทุกท่าน 🥳", + "UniGetUI uses the following libraries. Without them, UniGetUI wouldn't have been possible.": "UniGetUI ใช้ไลบรารีดังต่อไปนี้ UniGetUI คงไม่อาจเกิดขึ้นได้หากไม่มีไลบรารีเหล่านี้", + "{0} homepage": "เว็บไซต์ {0}", + "UniGetUI has been translated to more than 40 languages thanks to the volunteer translators. Thank you 🤝": "UniGetUI ได้รับการแปลเป็นภาษาต่าง ๆ มากกว่า 40 ภาษา ต้องขอบคุณอาสาสมัครนักแปลทุกท่าน ขอบคุณ🤝", + "Verbose": "รายละเอียด", + "1 - Errors": "1 - ข้อผิดพลาด", + "2 - Warnings": "2 - คำเตือน", + "3 - Information (less)": "3 - ข้อมูล (ย่อ)", + "4 - Information (more)": "4 - ข้อมูล (ละเอียด)", + "5 - information (debug)": "5 - ข้อมูล (ดีบั๊ก)", + "Warning": "คำเตือน", + "The following settings may pose a security risk, hence they are disabled by default.": "การตั้งค่าต่อไปนี้อาจก่อให้เกิดความเสี่ยงด้านความปลอดภัยจึงถูกปิดไว้โดยเริ่มต้น", + "Enable the settings below if and only if you fully understand what they do, and the implications they may have.": "เปิดตัวเลือกการตั้งค่านี้ก็ต่อเมื่อคุณเข้าใจว่าสิ่งนี้ใช้ทำอะไรและผลข้างเคียงและอันตรายที่อาจเกิดขึ้น", + "The settings will list, in their descriptions, the potential security issues they may have.": "การตั้งค่าจะระบุปัญหาด้านความปลอดภัยที่อาจเกิดขึ้นไว้ในคำอธิบายของแต่ละรายการ", + "The backup will include the complete list of the installed packages and their installation options. Ignored updates and skipped versions will also be saved.": "การสำรองข้อมูลจะรวมถึงรายการทั้งหมดของแพ็กเกจที่ติดตั้ง และการตั้งค่าการติดตั้งของแพ็กเกจนั้นทั้งหมด การอัปเดตที่ถูกละเว้น และเวอร์ชันที่ข้ามไปจะถูกบันทึกไว้ด้วย", + "The backup will NOT include any binary file nor any program's saved data.": "การสำรองข้อมูลจะไม่รวมถึงไฟล์ที่เป็นไบนารีหรือข้อมูลที่บันทึกไว้ของโปรแกรมใด ๆ", + "The size of the backup is estimated to be less than 1MB.": "ขนาดของไฟล์สำรองคาดว่าจะน้อยกว่า 1MB", + "The backup will be performed after login.": "การสำรองข้อมูลจะทำงานหลังจากเข้าสู่ระบบ", + "{pcName} installed packages": "แพ็กเกจที่ติดตั้งใน {pcName} แล้ว", + "Current status: Not logged in": "สถานะตอนนี้: ยังไม่ได้ลงชื่อเข้าใช้", + "You are logged in as {0} (@{1})": "ลงชื่อเข้าใช้ในชื่อ {0} (@{1})", + "Nice! Backups will be uploaded to a private gist on your account": "ยอดเยี่ยม! ข้อมูลสำรองจะถูกอัปโหลดไปยัง gist ส่วนตัวในบัญชีของคุณ", + "Select backup": "เลือกข้อมูลสำรอง", + "Settings imported from {0}": "นำเข้าการตั้งค่าจาก {0}", + "UniGetUI Settings": "การตั้งค่า UniGetUI", + "Settings exported to {0}": "ส่งออกการตั้งค่าไปยัง {0}", + "UniGetUI settings were reset": "การตั้งค่า UniGetUI ถูกรีเซ็ตแล้ว", + "Allow pre-release versions": "อนุญาตเวอร์ชันก่อนใช้งานจริง (pre-release)", + "Apply": "ใช้", + "For security reasons, custom command-line arguments are disabled by default. Go to UniGetUI security settings to change this.": "ด้วยเหตุผลด้านความปลอดภัย อาร์กิวเมนต์บรรทัดคำสั่งแบบกำหนดเองจึงถูกปิดใช้งานตามค่าเริ่มต้น ไปที่การตั้งค่าความปลอดภัยของ UniGetUI เพื่อเปลี่ยนแปลงสิ่งนี้", + "Go to UniGetUI security settings": "ไปยังการตั้งค่าความปลอดภัยของ UniGetUI", + "The following options will be applied by default each time a {0} package is installed, upgraded or uninstalled.": "การตั้งค่าต่อไปนี้จะถูกนำไปใช้ทุกครั้งที่ติดตั้ง อัปเดต หรือลบแพ็กเกจ {0}", + "Package's default": "ค่าเริ่มต้นของแพ็กเกจ", + "Install location can't be changed for {0} packages": "ไม่สามารถเปลี่ยนตำแหน่งการติดตั้งสำหรับแพ็กเกจ {0}", + "The local icon cache currently takes {0} MB": "แคชไอคอนภายในเครื่องปัจจุบันใช้พื้นที่ {0} MB", + "Username": "บัญชีผู้ใช้", + "Password": "รหัสผ่าน", + "Credentials": "ข้อมูลรับรอง (Credentials)", + "It is not guaranteed that the provided credentials will be stored safely": "ไม่สามารถรับประกันได้ว่าข้อมูลรับรองที่ระบุจะถูกจัดเก็บอย่างปลอดภัย", + "Partially": "บางส่วน", + "Package manager": "ตัวจัดการแพ็กเกจ", + "Compatible with proxy": "รองรับพร็อกซี", + "Compatible with authentication": "เข้ากันได้กับระบบ authentication", + "Proxy compatibility table": "ตารางความเข้ากันได้ของพร็อกซี", + "{0} settings": "{0} การตั้งค่า", + "{0} status": "{0} สถานะ", + "Default installation options for {0} packages": "ตัวเลือกการติดตั้งเริ่มต้นสำหรับแพ็กเกจ {0}", + "Expand version": "ขยายข้อมูลเวอร์ชัน", + "The executable file for {0} was not found": "ไม่พบไฟล์ปฏิบัติการสำหรับ {0}", + "{pm} is disabled": "{pm} ถูกปิดใช้งาน", + "Enable it to install packages from {pm}.": "เปิดใช้งานเพื่อติดตั้งแพ็กเกจจาก {pm}", + "{pm} is enabled and ready to go": "{pm} ถูกเปิดใช้งานและพร้อมใช้งานแล้ว", + "{pm} version:": "{pm} เวอร์ชัน:", + "{pm} was not found!": "ไม่พบ {pm}!", + "You may need to install {pm} in order to use it with UniGetUI.": "คุณจำเป็นต้องติดตั้ง {pm} เพื่อใช้งานร่วมกับ UniGetUI", + "Scoop Installer - UniGetUI": "ตัวติดตั้ง Scoop - UniGetUI", + "Scoop Uninstaller - UniGetUI": "ตัวถอนการติดตั้ง Scoop - UniGetUI", + "Clearing Scoop cache - UniGetUI": "กำลังล้างแคช Scoop - UniGetUI", + "Restart UniGetUI to fully apply changes": "รีสตาร์ท UniGetUI เพื่อให้การเปลี่ยนแปลงมีผลอย่างสมบูรณ์", + "Restart UniGetUI": "รีสตาร์ท UniGetUI", + "Manage {0} sources": "จัดการ {0} แหล่งข้อมูล", + "Add source": "เพิ่มซอร์ซ", + "Add": "เพิ่ม", + "Source name": "ชื่อซอร์ซ", + "Source URL": "URL ของซอร์ซ", + "Other": "อื่น ๆ", + "No minimum age": "ไม่มีอายุขั้นต่ำ", + "1 day": "1 วัน", + "{0} days": "{0} วัน", + "Custom...": "กำหนดเอง...", + "{0} minutes": "{0} นาที", + "1 hour": "1 ชั่วโมง", + "{0} hours": "{0} ชั่วโมง", + "1 week": "1 สัปดาห์", + "Supports release dates": "รองรับวันที่เผยแพร่", + "Release date support per package manager": "การรองรับวันที่เผยแพร่ของตัวจัดการแพ็กเกจแต่ละตัว", + "Search for packages": "ค้นหาแพ็กเกจ", + "Local": "เฉพาะที่", + "OK": "โอเค", + "Last checked: {0}": "ตรวจสอบล่าสุด: {0}", + "{0} packages were found, {1} of which match the specified filters.": "พบแพ็กเกจ {0} รายการ โดยแพ็กเกจ {1} รายการตรงกับตัวกรองที่ระบุไว้", + "{0} selected": "เลือกแล้ว {0}", + "(Last checked: {0})": "(ตรวจสอบล่าสุด: {0})", + "All packages selected": "เลือกแพ็กเกจทั้งหมดแล้ว", + "Package selection cleared": "ล้างการเลือกแพ็กเกจแล้ว", + "{0}: {1}": "{0}: {1}", + "More info": "ข้อมูลเพิ่มเติม", + "GitHub account": "บัญชี GitHub", + "Log in with GitHub to enable cloud package backup.": "ลงชื่อเข้าใช้ด้วย GitHub เพื่อสำรองข้อมูลแพ็กเกจบนคลาวด์", + "More details": "รายละเอียดเพิ่มเติม", + "Log in": "ลงชื่อเข้าใช้", + "If you have cloud backup enabled, it will be saved as a GitHub Gist on this account": "หากคุณเปิดใช้งานการสำรองข้อมูลบนคลาวด์ ข้อมูลจะถูกบันทึกเป็น GitHub Gist ในบัญชีนี้", + "Log out": "ออกจากระบบ", + "About UniGetUI": "เกี่ยวกับ UniGetUI", + "About": "เกี่ยวกับ", + "Third-party licenses": "ใบอนุญาตของบุคคลภายนอก", + "Contributors": "ผู้ที่มีส่วนช่วย", + "Translators": "ผู้แปล", + "Bundle security report": "รายงานความปลอดภัยของบันเดิล", + "The bundle contained restricted content": "บันเดิลมีเนื้อหาที่ถูกจำกัด", + "UniGetUI – Crash Report": "UniGetUI – รายงานข้อขัดข้อง", + "UniGetUI has crashed": "UniGetUI หยุดทำงาน", + "Help us fix this by sending a crash report to Devolutions. All fields below are optional.": "ช่วยเราแก้ไขปัญหานี้โดยส่งรายงานข้อขัดข้องไปยัง Devolutions ช่องข้อมูลด้านล่างทั้งหมดเป็นทางเลือก", + "Email (optional)": "อีเมล (ไม่บังคับ)", + "your@email.com": "your@email.com", + "Additional details (optional)": "รายละเอียดเพิ่มเติม (ไม่บังคับ)", + "Describe what you were doing when the crash occurred…": "อธิบายสิ่งที่คุณกำลังทำเมื่อเกิดข้อขัดข้อง…", + "Crash report": "รายงานข้อขัดข้อง", + "Don't Send": "ไม่ส่ง", + "Send Report": "ส่งรายงาน", + "Sending…": "กำลังส่ง…", + "Unsaved changes": "การเปลี่ยนแปลงที่ยังไม่ได้บันทึก", + "You have unsaved changes in the current bundle. Do you want to discard them?": "คุณมีการเปลี่ยนแปลงที่ยังไม่ได้บันทึกในบันเดิลปัจจุบัน คุณต้องการละทิ้งการเปลี่ยนแปลงเหล่านั้นหรือไม่", + "Discard changes": "ละทิ้งการเปลี่ยนแปลง", + "Integrity violation": "การละเมิดความถูกต้องของไฟล์", + "UniGetUI or some of its components are missing or corrupt. It is strongly recommended to reinstall UniGetUI to adress the situation.": "UniGetUI หรือส่วนประกอบบางรายการหายไปหรือเสียหาย ขอแนะนำอย่างยิ่งให้ติดตั้ง UniGetUI ใหม่เพื่อแก้ไขสถานการณ์นี้", + "• Refer to the UniGetUI Logs to get more details regarding the affected file(s)": "• โปรดดูบันทึกของ UniGetUI เพื่อรับรายละเอียดเพิ่มเติมเกี่ยวกับไฟล์ที่ได้รับผลกระทบ", + "• Integrity checks can be disabled from the Experimental Settings": "• สามารถปิดใช้งานการตรวจสอบความสมบูรณ์ได้จากการตั้งค่าทดลอง", + "Manage shortcuts": "จัดการทางลัด", + "UniGetUI has detected the following desktop shortcuts which can be removed automatically on future upgrades": "UniGetUI ตรวจพบทางลัดบนเดสก์ท็อปต่อไปนี้ซึ่งสามารถลบโดยอัตโนมัติได้ในการอัปเกรดครั้งถัดไป", + "Do you really want to reset this list? This action cannot be reverted.": "คุณแน่ใจที่จะรีเซ็ตรายการนี้หรือไม่? การกระทำนี้ไม่สามารถเรียกคืนได้", + "Desktop shortcuts list": "รายการทางลัดบนเดสก์ท็อป", + "Open in explorer": "เปิดใน Explorer", + "Remove from list": "ลบออกจากรายการ", + "When new shortcuts are detected, delete them automatically instead of showing this dialog.": "เมื่อตรวจพบทางลัดใหม่ ให้ลบโดยอัตโนมัติแทนการแสดงกล่องโต้ตอบนี้", + "Not right now": "ไม่ใช่ตอนนี้", + "Missing dependency": "Dependency ขาดหายไป", + "UniGetUI requires {0} to operate, but it was not found on your system.": "UniGetUI ต้องใช้ {0} ในการทำงาน แต่ไม่พบบนระบบของคุณ", + "Click on Install to begin the installation process. If you skip the installation, UniGetUI may not work as expected.": "คลิกที่ติดตั้ง เพื่อเริ่มต้นขั้นตอนการติดตั้ง ถ้าข้ามการติดตั้ง UniGetUI อาจไม่ทำงานตามที่คาดไว้", + "Alternatively, you can also install {0} by running the following command in a Windows PowerShell prompt:": "อีกทางหนึ่ง คุณสามารถติดตั้ง {0} ได้โดยการรันคำสั่งต่อไปนี้ใน Windows PowerShell prompt:", + "Install {0}": "ติดตั้ง {0}", + "Do not show this dialog again for {0}": "อย่าแสดงกล่องข้อความนี้อีกสำหรับ {0}", + "Please wait while {0} is being installed. A black window may show up. Please wait until it closes.": "กรุณารอสักครู่ขณะที่ {0} กำลังติดตั้ง หน้าต่างสีดำ (หรือสีน้ำเงิน) อาจปรากฏขึ้น กรุณารอจนกว่าจะปิดลง", + "{0} has been installed successfully.": "{0} ถูกติดตั้งสำเร็จ", + "Please click on \"Continue\" to continue": "โปรดคลิกที่ \"ดำเนินการต่อ\" เพื่อดำเนินการต่อ", + "Continue": "ดำเนินการต่อ", + "{0} has been installed successfully. It is recommended to restart UniGetUI to finish the installation": "ติดตั้ง {0} สำเร็จแล้ว แนะนำให้รีสตาร์ท UniGetUI เพื่อให้การติดตั้งเสร็จสมบูรณ์", + "Restart later": "รีสตาร์ททีหลัง", + "An error occurred:": "เกิดข้อผิดพลาด:", + "Please see the Command-line Output or refer to the Operation History for further information about the issue.": "โปรดดูเอาต์พุตบรรทัดคำสั่งหรืออ้างอิงประวัติการดำเนินการสำหรับข้อมูลเพิ่มเติมเกี่ยวกับปัญหานี้", + "Retry as administrator": "ทำซ้ำในฐานะผู้ดูแลระบบ", + "Retry interactively": "ลองใหม่แบบโต้ตอบ", + "Retry skipping integrity checks": "ลองใหม่โดยข้ามการตรวจสอบความสมบูรณ์", + "Installation options": "การตั้งค่าการติดตั้ง", + "Save": "บันทึก", + "UniGetUI collects anonymous usage data with the sole purpose of understanding and improving the user experience.": "UniGetUI เก็บรวบรวมข้อมูลการใช้งานแบบไม่ระบุตัวตนเพื่อจุดประสงค์เดียวในการทำความเข้าใจและปรับปรุงประสบการณ์ของผู้ใช้", + "More details about the shared data and how it will be processed": "รายละเอียดเพิ่มเติมเกี่ยวกับข้อมูลที่ใช้ร่วมกันและวิธีการประมวลผล", + "Do you accept that UniGetUI collects and sends anonymous usage statistics, with the sole purpose of understanding and improving the user experience?": "คุณยินยอมให้ UniGetUI เก็บและส่งข้อมูลสถิติการใช้งานแบบไม่เปิดเผยตัวตน เพื่อจุดประสงค์ในการพัฒนาและปรับปรุงประสบการณ์ของผู้ใช้ หรือไม่?", + "Decline": "ปฏิเสธ", + "No personal information is collected nor sent, and the collected data is anonimized, so it can't be back-tracked to you.": "ไม่มีการเก็บรวบรวมหรือส่งข้อมูลส่วนบุคคล และข้อมูลที่เก็บรวบรวมจะถูกทำให้ไม่ระบุตัวตน จึงไม่สามารถติดตามกลับไปถึงคุณได้", + "Navigation panel": "แผงนำทาง", + "Operations": "การดำเนินการ", + "Toggle operations panel": "สลับแผงการดำเนินการ", + "Bulk operations": "การดำเนินการแบบกลุ่ม", + "Retry failed": "ลองรายการที่ล้มเหลวอีกครั้ง", + "Clear successful": "ล้างรายการที่สำเร็จ", + "Clear finished": "ล้างรายการที่เสร็จสิ้น", + "Cancel all": "ยกเลิกทั้งหมด", + "More": "เพิ่มเติม", + "Toggle navigation panel": "สลับแผงนำทาง", + "Minimize": "ย่อ", + "Maximize": "ขยาย", + "UniGetUI by Devolutions": "UniGetUI โดย Devolutions", + "UniGetUI is an application that makes managing your software easier, by providing an all-in-one graphical interface for your command-line package managers.": "UniGetUI เป็นแอปพลิเคชันที่ทำให้การจัดการซอฟต์แวร์ของคุณง่ายขึ้น โดยมอบอินเทอร์เฟซผู้ใช้แบบกราฟิกที่ครอบคลุมสำหรับตัวจัดการแพ็กเกจบรรทัดคำสั่งของคุณ", + "Useful links": "ลิงก์ที่เป็นประโยชน์", + "UniGetUI Homepage": "หน้าแรกของ UniGetUI", + "Report an issue or submit a feature request": "รายงานปัญหาหรือส่งคำขอคุณสมบัติใหม่", + "UniGetUI Repository": "ที่เก็บโค้ดของ UniGetUI", + "View GitHub Profile": "ดูโปรไฟล์ GitHub", + "UniGetUI License": "ใบอนุญาต UniGetUI", + "Using UniGetUI implies the acceptation of the MIT License": "การใช้ UniGetUI ถือว่าเป็นการการยอมรับสัญญาอนุญาตเอ็มไอที (MIT License)", + "Become a translator": "มาเป็นผู้แปล", + "Go back": "ย้อนกลับ", + "Go forward": "ไปข้างหน้า", + "Go to home page": "ไปยังหน้าหลัก", + "Reload page": "โหลดหน้าใหม่", + "View page on browser": "ดูหน้านี้บนเบราว์เซอร์", + "The built-in browser is not supported on Linux yet.": "เบราว์เซอร์ในตัวยังไม่รองรับบน Linux", + "Open in browser": "เปิดในเบราว์เซอร์", + "Copy to clipboard": "คัดลอกไปยังคลิปบอร์ด", + "Export to a file": "ส่งออกไปยังไฟล์", + "Log level:": "ระดับบันทึก:", + "Reload log": "รีโหลดบันทึก", + "Export log": "ส่งออกบันทึก", + "Text": "ข้อความ", + "Change how operations request administrator rights": "เปลี่ยนวิธีที่การดำเนินการขอสิทธิ์ผู้ดูแลระบบ", + "Restrictions on package operations": "ข้อจำกัดของการดำเนินการแพ็กเกจ", + "Restrictions on package managers": "ข้อจำกัดของตัวจัดการแพ็กเกจ", + "Restrictions when importing package bundles": "ข้อจำกัดเมื่อนำเข้าบันเดิลแพ็กเกจ", + "Ask for administrator privileges once for each batch of operations": "ขอสิทธิ์ผู้ดูแลระบบหนึ่งครั้งสำหรับการดำเนินการแต่ละชุด", + "Ask only once for administrator privileges": "ขอสิทธิ์ผู้ดูแลระบบครั้งเดียวเท่านั้น", + "Prohibit any kind of Elevation via UniGetUI Elevator or GSudo": "ห้ามการยกระดับสิทธิ์ทุกรูปแบบผ่าน UniGetUI Elevator หรือ GSudo", + "This option WILL cause issues. Any operation incapable of elevating itself WILL FAIL. Install/update/uninstall as administrator will NOT WORK.": "ตัวเลือกนี้จะก่อให้เกิดปัญหาอย่างแน่นอน การดำเนินการใดก็ตามที่ไม่สามารถยกระดับสิทธิ์ตัวเองได้จะล้มเหลว การติดตั้ง/อัปเดต/ถอนการติดตั้งแบบผู้ดูแลระบบจะไม่ทำงาน", + "Allow custom command-line arguments": "อนุญาตอาร์กิวเมนต์บรรทัดคำสั่งแบบกำหนดเอง", + "Custom command-line arguments can change the way in which programs are installed, upgraded or uninstalled, in a way UniGetUI cannot control. Using custom command-lines can break packages. Proceed with caution.": "อาร์กิวเมนต์บรรทัดคำสั่งแบบกำหนดเองสามารถเปลี่ยนวิธีการติดตั้ง อัปเกรด หรือถอนการติดตั้งโปรแกรมในแบบที่ UniGetUI ไม่สามารถควบคุมได้ การใช้บรรทัดคำสั่งแบบกำหนดเองอาจทำให้แพ็กเกจเสียหายได้ โปรดดำเนินการด้วยความระมัดระวัง", + "Ignore custom pre-install and post-install commands when importing packages from a bundle": "อนุญาตให้รันคำสั่งก่อนติดตั้งและหลังติดตั้งแบบกำหนดเอง", + "Pre and post install commands will be run before and after a package gets installed, upgraded or uninstalled. Be aware that they may break things unless used carefully": "คำสั่งก่อนและหลังการติดตั้งจะถูกรันก่อนและหลังจากที่แพ็กเกจได้รับการติดตั้ง อัปเกรด หรือถอนการติดตั้ง โปรดทราบว่าคำสั่งเหล่านี้อาจทำให้ระบบเสียหายได้หากไม่ได้ใช้อย่างระมัดระวัง", + "Allow changing the paths for package manager executables": "อนุญาตให้เปลี่ยนเส้นทางสำหรับไฟล์ปฏิบัติการของตัวจัดการแพ็กเกจ", + "Turning this on enables changing the executable file used to interact with package managers. While this allows finer-grained customization of your install processes, it may also be dangerous": "การเปิดใช้สิ่งนี้จะทำให้สามารถเปลี่ยนไฟล์ปฏิบัติการที่ใช้โต้ตอบกับตัวจัดการแพ็กเกจได้ แม้ว่าจะช่วยให้ปรับแต่งกระบวนการติดตั้งได้ละเอียดขึ้น แต่อาจเป็นอันตรายได้เช่นกัน", + "Allow importing custom command-line arguments when importing packages from a bundle": "อนุญาตให้นำเข้าอาร์กิวเมนต์บรรทัดคำสั่งแบบกำหนดเองเมื่อทำการนำเข้าพ็กเกจจากบันเดิล", + "Malformed command-line arguments can break packages, or even allow a malicious actor to gain privileged execution. Therefore, importing custom command-line arguments is disabled by default": "อาร์กิวเมนต์บรรทัดคำสั่งที่ไม่ถูกต้องอาจทำให้แพ็กเกจเสียหาย หรือแม้แต่เปิดทางให้ผู้ไม่ประสงค์ดีได้รับสิทธิ์ยกระดับการทำงานได้ ดังนั้นการนำเข้าอาร์กิวเมนต์บรรทัดคำสั่งแบบกำหนดเองจึงถูกปิดใช้งานตามค่าเริ่มต้น", + "Allow importing custom pre-install and post-install commands when importing packages from a bundle": "อนุญาตให้นำเข้าคำสั่งก่อนติดตั้งและหลังติดตั้งแบบกำหนดเองเมื่อทำการนำเข้าพัสดุพ็กเกจ (bundle)", + "Pre and post install commands can do very nasty things to your device, if designed to do so. It can be very dangerous to import the commands from a bundle, unless you trust the source of that package bundle": "คำสั่งก่อนและหลังการติดตั้งสามารถทำสิ่งที่เป็นอันตรายต่ออุปกรณ์ของคุณได้ หากถูกออกแบบมาเพื่อทำเช่นนั้น การนำเข้าคำสั่งจากบันเดิลอาจเป็นอันตรายมาก เว้นแต่คุณจะเชื่อถือแหล่งที่มาของบันเดิลแพ็กเกจนั้น", + "Administrator rights and other dangerous settings": "การอนุญาตผู้ดูแลระบบและการตั้งค่าที่อันตราย", + "Package backup": "การสำรองข้อมูลแพ็กเกจ", + "Cloud package backup": "การสำรองข้อมูลแพ็กเกจบนคลาวด์", + "Local package backup": "การสำรองข้อมูลแพ็กเกจภายในเครื่อง", + "Local backup advanced options": "ตัวเลือกขั้นสูงของการสำรองข้อมูลภายในเครื่อง", + "Log in with GitHub": "ลงชื่อเข้าใช้ด้วย GitHub", + "Log out from GitHub": "ออกจากระบบ GitHub", + "Periodically perform a cloud backup of the installed packages": "สำรองข้อมูลแพ็กเกจที่ติดตั้งแล้วบนคลาวด์เป็นระยะ", + "Cloud backup uses a private GitHub Gist to store a list of installed packages": "การสำรองข้อมูลบนคลาวด์ใช้ GitHub Gist ส่วนตัวเพื่อเก็บรายการแพ็กเกจที่ติดตั้ง", + "Perform a cloud backup now": "สำรองข้อมูลบนคลาวด์เดี๋ยวนี้", + "Backup": "สำรองข้อมูล", + "Restore a backup from the cloud": "กู้คืนข้อมูลสำรองจากคลาวด์", + "Begin the process to select a cloud backup and review which packages to restore": "เริ่มกระบวนการเลือกข้อมูลสำรองบนคลาวด์และตรวจสอบว่าจะกู้คืนแพ็กเกจใด", + "Periodically perform a local backup of the installed packages": "สำรองข้อมูลแพ็กเกจที่ติดตั้งแล้วในเครื่องเป็นระยะ", + "Perform a local backup now": "สำรองข้อมูลในเครื่องเดี๋ยวนี้", + "Change backup output directory": "เปลี่ยนไดเร็กทอรีเอาท์พุตของการสำรองข้อมูล", + "Set a custom backup file name": "ตั้งชื่อไฟล์สำรองข้อมูลเอง", + "Leave empty for default": "เว้นว่างไว้เพื่อใช้ค่าเริ่มต้น", + "Add a timestamp to the backup file names": "เพิ่มการบันทึกเวลาในชื่อไฟล์สำรองข้อมูล", + "Backup and Restore": "สำรองข้อมูลและกู้คืน", + "Enable background api (UniGetUI Widgets and Sharing, port 7058)": "เปิดใช้งาน API พื้นหลัง (Widgets สำหรับ UniGetUI และการแชร์ พอร์ต 7058)", + "Wait for the device to be connected to the internet before attempting to do tasks that require internet connectivity.": "รอให้อุปกรณ์เชื่อมต่ออินเทอร์เน็ตก่อนที่จะพยายามทำงานที่ต้องใช้การเชื่อมต่ออินเทอร์เน็ต", + "Disable the 1-minute timeout for package-related operations": "ปิดใช้งานการหมดเวลา 1 นาทีในการดำเนินการแพ็กเกจ", + "Use installed GSudo instead of UniGetUI Elevator": "ใช้ GSudo ที่ติดตั้งไว้แทน UniGetUI Elevator", + "Use a custom icon and screenshot database URL": "ใช้ URL ของฐานข้อมูลไอคอนและสกรีนช็อตที่กำหนดเอง", + "Enable background CPU Usage optimizations (see Pull Request #3278)": "เปิดใช้งานการปรับปรุงประสิทธิภาพการใช้ CPU ในพื้นหลัง (อ่านเพิ่มเติมที่ Pull Request #3278)", + "Perform integrity checks at startup": "ดำเนินการตรวจสอบความสมบูรณ์เมื่อเริ่มต้นระบบ", + "When batch installing packages from a bundle, install also packages that are already installed": "เมื่อติดตั้งแพ็กเกจเป็นชุดจากบันเดิล ให้ติดตั้งแพ็กเกจที่ติดตั้งไว้แล้วด้วย", + "Experimental settings and developer options": "การตั้งค่าการทดลองและการตั้งค่าสำหรับนักพัฒนา", + "Show UniGetUI's version and build number on the titlebar.": "แสดงเวอร์ชันของ UniGetUI บนแถบชื่อเรื่อง", + "Language": "ภาษา", + "UniGetUI updater": "ตัวอัปเดต UniGetUI", + "Telemetry": "ข้อมูลการใช้งาน", + "Manage UniGetUI settings": "จัดการการตั้งค่า UniGetUI", + "Related settings": "การตั้งค่าที่เกี่ยวข้อง", + "Update UniGetUI automatically": "อัปเดต UniGetUI โดยอัตโนมัติ", + "Check for updates": "ตรวจสอบการอัปเดต", + "Install prerelease versions of UniGetUI": "ติดตั้งพรีเวอร์ชัน (Pre-Release) ของ UniGetUI", + "Manage telemetry settings": "จัดการการตั้งค่า telemetry", + "Manage": "จัดการ", + "Import settings from a local file": "นำเข้าการตั้งค่าจากไฟล์ในเครื่อง", + "Import": "นำเข้า", + "Export settings to a local file": "ส่งออกการตั้งค่าไปยังไฟล์ในเครื่อง", + "Export": "ส่งออก", + "Reset UniGetUI": "รีเซ็ต UniGetUI", + "User interface preferences": "การตั้งค่าอินเตอร์เฟซผู้ใช้", + "Application theme, startup page, package icons, clear successful installs automatically": "ธีมแอปพลิเคชัน, หน้าเริ่มต้น, ไอคอนแพ็กเกจ, ล้างการติดตั้งที่สำเร็จโดยอัตโนมัติ", + "General preferences": "การตั้งค่า", + "UniGetUI display language:": "ภาษาที่แสดงใน UniGetUI:", + "System language": "ภาษาของระบบ", + "Is your language missing or incomplete?": "ไม่พบภาษาของคุณหรือการแปลในภาษาของคุณยังไม่สมบูรณ์ใช่ไหม", + "Appearance": "การแสดงผล", + "UniGetUI on the background and system tray": "UniGetUI ในพื้นหลังและถาดระบบ", + "Package lists": "รายการแพ็กเกจ", + "Use classic mode": "ใช้โหมดคลาสสิก", + "Restart UniGetUI to apply this change": "รีสตาร์ท UniGetUI เพื่อใช้การเปลี่ยนแปลงนี้", + "The classic UI is disabled for beta testers": "UI แบบคลาสสิกถูกปิดใช้งานสำหรับผู้ทดสอบเบต้า", + "Close UniGetUI to the system tray": "ย่อ UniGetUI ไปที่แถบไอคอน", + "Manage UniGetUI autostart behaviour": "จัดการพฤติกรรมการเริ่มอัตโนมัติของ UniGetUI", + "Show package icons on package lists": "แสดงแพ็คเกจไอค่อนในรายการแพ็คแกจ", + "Clear cache": "ล้างแคช", + "Select upgradable packages by default": "เลือกแพ็กเกจที่อัปเกรดได้ตามค่าเริ่มต้น", + "Light": "สว่าง", + "Dark": "มืด", + "Follow system color scheme": "ตามธีมของระบบ", + "Application theme:": "ธีม:", + "UniGetUI startup page:": "หน้าเริ่มต้นของ UniGetUI:", + "Proxy settings": "การตั้งค่าพร็อกซี", + "Other settings": "การตั้งค่าอื่นๆ", + "Connect the internet using a custom proxy": "เชื่อมต่ออินเทอร์เน็ตโดยใช้พร็อกซี่กำหนดเอง", + "Please note that not all package managers may fully support this feature": "โปรดทราบว่าอาจมีตัวจัดการแพ็กเกจบางตัวที่ไม่รองรับฟีเจอร์นี้อย่างสมบูรณ์", + "Proxy URL": "URL ของพร็อกซี", + "Enter proxy URL here": "กรอก URL ของ proxy ที่นี่", + "Authenticate to the proxy with a user and a password": "ยืนยันตัวตนกับพร็อกซีด้วยชื่อผู้ใช้และรหัสผ่าน", + "Internet and proxy settings": "การตั้งค่าอินเทอร์เน็ตและพร็อกซี", + "Package manager preferences": "การตั้งค่าตัวจัดการแพ็กเกจ", + "Ready": "พร้อม", + "Not found": "ไม่พบ", + "Notification preferences": "การตั้งค่าการแจ้งเตือน", + "Notification types": "ประเภทการแจ้งเตือน", + "The system tray icon must be enabled in order for notifications to work": "ต้องเปิดใช้งานไอคอนถาดระบบเพื่อให้การแจ้งเตือนทำงานได้", + "Enable UniGetUI notifications": "เปิดการแจ้งเตือน UniGetUI", + "Show a notification when there are available updates": "แสดงการแจ้งเตือนเมื่อพบอัปเดต", + "Show a silent notification when an operation is running": "แสดงการแจ้งเตือนแบบเงียบเมื่อมีการดำเนินการอยู่", + "Show a notification when an operation fails": "แสดงการแจ้งเตือนเมื่อการดำเนินการล้มเหลว", + "Show a notification when an operation finishes successfully": "แสดงการแจ้งเตือนเมื่อการดำเนินการเสร็จสิ้นสำเร็จ", + "Concurrency and execution": "การทำงานพร้อมกันและการดำเนินการ", + "Automatic desktop shortcut remover": "เครื่องมือลบทางลัดหน้าจออัตโนมัติ", + "Choose how many operations should be performed in parallel": "เลือกจำนวนการดำเนินการที่ควรทำพร้อมกัน", + "Clear successful operations from the operation list after a 5 second delay": "ล้างการดำเนินการที่สำเร็จออกจากรายการ หลังจากเวลาผ่านไป 5 วินาที", + "Download operations are not affected by this setting": "การดาวน์โหลดไม่ได้รับผลกระทบจากการตั้งค่านี้", + "You may lose unsaved data": "คุณอาจสูญเสียข้อมูลที่ยังไม่ได้บันทึก", + "Ask to delete desktop shortcuts created during an install or upgrade.": "สอบถามการลบทางลัดเดสก์ท็อปที่สร้างจากการติดตั้งหรืออัปเกรด", + "Package update preferences": "การตั้งค่าการอัปเดตแพ็กเกจ", + "Update check frequency, automatically install updates, etc.": "ความถี่ในการตรวจสอบการอัปเดต ติดตั้งการอัปเดตอัตโนมัติ และอื่น ๆ", + "Reduce UAC prompts, elevate installations by default, unlock certain dangerous features, etc.": "ลดการแจ้งเตือน UAC ยกระดับการติดตั้งตามค่าเริ่มต้น ปลดล็อกฟีเจอร์อันตรายบางอย่าง และอื่น ๆ", + "Package operation preferences": "การตั้งค่าการดำเนินการแพ็กเกจ", + "Enable {pm}": "เปิด {pm}", + "Not finding the file you are looking for? Make sure it has been added to path.": "ไม่พบไฟล์ที่คุณกำลังมองหาใช่ไหม ตรวจสอบให้แน่ใจว่าได้เพิ่มไฟล์นั้นลงใน path แล้ว", + "Select the executable to be used. The following list shows the executables found by UniGetUI": "เลือกไฟล์ปฏิบัติการที่จะใช้ รายการต่อไปนี้แสดงไฟล์ปฏิบัติการที่ UniGetUI พบ", + "For security reasons, changing the executable file is disabled by default": "ด้วยเหตุผลด้านความปลอดภัย การเปลี่ยนไฟล์ปฏิบัติการจึงถูกปิดใช้งานตามค่าเริ่มต้น", + "Change this": "เปลี่ยนสิ่งนี้", + "Copy path": "คัดลอกเส้นทาง", + "Current executable file:": "ไฟล์ปฏิบัติการปัจจุบัน:", + "Ignore packages from {pm} when showing a notification about updates": "ละเว้นแพ็กเกจจาก {pm} เมื่อแสดงการแจ้งเตือนเกี่ยวกับการอัปเดต", + "Update security": "ความปลอดภัยของการอัปเดต", + "Use global setting": "ใช้การตั้งค่าส่วนกลาง", + "Minimum age for updates": "อายุขั้นต่ำของการอัปเดต", + "e.g. 10": "เช่น 10", + "Custom minimum age (days)": "อายุขั้นต่ำแบบกำหนดเอง (วัน)", + "{pm} does not provide release dates for its packages, so this setting will have no effect": "{pm} ไม่มีวันที่เผยแพร่สำหรับแพ็กเกจของตน ดังนั้นการตั้งค่านี้จะไม่มีผล", + "{pm} only provides release dates for some of its packages, so this setting will only apply to those packages": "{pm} ระบุวันที่เผยแพร่ให้กับแพ็กเกจบางรายการเท่านั้น ดังนั้นการตั้งค่านี้จะมีผลเฉพาะกับแพ็กเกจเหล่านั้น", + "Override the global minimum update age for this package manager": "แทนที่อายุขั้นต่ำของการอัปเดตส่วนกลางสำหรับตัวจัดการแพ็กเกจนี้", + "View {0} logs": "ดูบันทึกของ {0}", + "If Python cannot be found or is not listing packages but is installed on the system, ": "หากไม่พบ Python หรือ Python ไม่แสดงรายการแพ็กเกจทั้งที่ติดตั้งอยู่ในระบบแล้ว ", + "Advanced options": "ตัวเลือกขั้นสูง", + "WinGet command-line tool": "เครื่องมือบรรทัดคำสั่ง WinGet", + "Choose which command-line tool UniGetUI uses for WinGet operations when the COM API is not used": "เลือกเครื่องมือบรรทัดคำสั่งที่ UniGetUI ใช้สำหรับการดำเนินการของ WinGet เมื่อไม่ได้ใช้ COM API", + "WinGet COM API": "WinGet COM API", + "Choose whether UniGetUI can use the WinGet COM API before falling back to the command-line tool": "เลือกว่าจะให้ UniGetUI ใช้ WinGet COM API ก่อนที่จะกลับไปใช้เครื่องมือบรรทัดคำสั่งได้หรือไม่", + "Reset WinGet": "รีเซ็ต WinGet", + "This may help if no packages are listed": "สิ่งนี้อาจช่วยได้หากไม่มีแพ็กเกจแสดงในรายการ", + "Force install location parameter when updating packages with custom locations": "บังคับใช้พารามิเตอร์ตำแหน่งการติดตั้งเมื่ออัปเดตแพ็กเกจที่มีตำแหน่งกำหนดเอง", + "Install Scoop": "ติดตั้ง Scoop", + "Uninstall Scoop (and its packages)": "ถอนการติดตั้ง Scoop (และแพ็กเกจ)", + "Run cleanup and clear cache": "เรียกใช้การล้างข้อมูลและล้างแคช", + "Run": "เรียกใช้", + "Enable Scoop cleanup on launch": "เปิดใช้งานการล้างข้อมูล Scoop เมื่อเปิดโปรแกรม", + "Default vcpkg triplet": "vcpkg triplet ค่าเริ่มต้น", + "Change vcpkg root location": "เปลี่ยนตำแหน่งรากของ vcpkg", + "Reset vcpkg root location": "รีเซ็ตตำแหน่งรากของ vcpkg", + "Open vcpkg root location": "เปิดตำแหน่งรากของ vcpkg", + "Language, theme and other miscellaneous preferences": "การตั้งค่าภาษา ธีม และการตั้งค่าอื่น ๆ ที่เกี่ยวข้อง", + "Show notifications on different events": "แสดงการแจ้งเตือนเกี่ยวกับเหตุการณ์ต่าง ๆ", + "Change how UniGetUI checks and installs available updates for your packages": "เปลี่ยนวิธีที่ UniGetUI ตรวจสอบและติดตั้งการอัปเดตที่พร้อมใช้งานสำหรับแพ็กเกจของคุณ", + "Automatically save a list of all your installed packages to easily restore them.": "บันทึกรายการแพ็กเกจทั้งหมดที่ติดตั้งไว้โดยอัตโนมัติเพื่อทำให้การกู้คืนง่ายขึ้น", + "Enable and disable package managers, change default install options, etc.": "เปิดหรือปิดใช้งานตัวจัดการแพ็กเกจ เปลี่ยนตัวเลือกการติดตั้งเริ่มต้น และอื่น ๆ", + "Internet connection settings": "การตั้งค่าการเชื่อมต่ออินเทอร์เน็ต", + "Proxy settings, etc.": "การตั้งค่าพร็อกซี และอื่น ๆ", + "Beta features and other options that shouldn't be touched": "คุณสมบัติเบต้าและตัวเลือกอื่น ๆ ที่ไม่ควรแตะต้อง", + "Reload sources": "โหลดแหล่งข้อมูลใหม่", + "Delete source": "ลบแหล่งข้อมูล", + "Known sources": "แหล่งข้อมูลที่รู้จัก", + "Update checking": "การตรวจสอบการอัปเดต", + "Automatic updates": "อัปเดตอัตโนมัติ", + "Check for package updates periodically": "ตรวจสอบการอัปเดตแพ็กเกจเป็นระยะ ๆ", + "Check for updates every:": "ตรวจสอบการอัปเดตทุก:", + "Install available updates automatically": "ติดตั้งการอัปเดตที่พร้อมใช้งานโดยอัตโนมัติ", + "Do not automatically install updates when the network connection is metered": "ไม่ติดตั้งการอัปเดตโดยอัตโนมัติเมื่อการเชื่อมต่อเครื่อข่ายคิดราคาการใช้งาน", + "Do not automatically install updates when the device runs on battery": "อย่าติดตั้งการอัปเดตโดยอัตโนมัติเมื่ออุปกรณ์กำลังใช้แบตเตอรี่", + "Do not automatically install updates when the battery saver is on": "ไม่ติดตั้งการอัปเดตโดยอัตโนมัติเมื่อเปิดโหมดประหยัดแบตเตอรี่", + "Only show updates that are at least the specified number of days old": "แสดงเฉพาะการอัปเดตที่มีอายุอย่างน้อยตามจำนวนวันที่ระบุ", + "Warn me when the installer URL host changes between the installed version and the new version (WinGet only)": "เตือนฉันเมื่อโฮสต์ URL ของตัวติดตั้งเปลี่ยนไประหว่างเวอร์ชันที่ติดตั้งอยู่กับเวอร์ชันใหม่ (เฉพาะ WinGet)", + "Change how UniGetUI handles install, update and uninstall operations.": "กำหนดวิธีการจัดการการติดตั้ง อัปเดต และการถอนการติดตั้งของ UniGetUI", + "Navigation": "การนำทาง", + "Check for UniGetUI updates": "ตรวจสอบการอัปเดต UniGetUI", + "Quit UniGetUI": "ออกจาก UniGetUI", + "Filters": "ฟิลเตอร์", + "Sources": "แหล่งข้อมูล", + "Search for packages to start": "ค้นหาแพ็กเกจเพื่อเริ่มต้น", + "Select all": "เลือกทั้งหมด", + "Clear selection": "ล้างการเลือก", + "Instant search": "ค้นหาทันที", + "Distinguish between uppercase and lowercase": "แยกความแตกต่างระหว่างตัวพิมพ์ใหญ่และตัวพิมพ์เล็ก", + "Ignore special characters": "ละเว้นอักขระพิเศษ", + "Search mode": "โหมดการค้นหา", + "Both": "ทั้งคู่", + "Exact match": "ตรงทั้งหมด", + "Show similar packages": "แสดงแพ็กเกจที่คล้ายกัน", + "Loading": "กำลังโหลด", + "Package": "แพ็กเกจ", + "More options": "ตัวเลือกเพิ่มเติม", + "Order by:": "เรียงลำดับโดย:", + "Name": "ชื่อ", + "Id": "ไอดี", + "Ascendant": "เด่นขึ้น", + "Descendant": "รายการย่อย", + "View modes": "โหมดการแสดงผล", + "Reload": "โหลดใหม่", + "Closed": "ปิดแล้ว", + "Ascending": "เรียงจากน้อยไปมาก", + "Descending": "เรียงจากมากไปน้อย", + "{0}: {1}, {2}": "{0}: {1}, {2}", + "Order by": "เรียงตาม", + "No results were found matching the input criteria": "ไม่พบผลลัพธ์ที่ตรงกับเกณฑ์การค้นหา", + "No packages were found": "ไม่พบแพ็กเกจ", + "Loading packages": "กำลังโหลดแพ็กเกจ", + "Skip integrity checks": "ข้ามการตรวจสอบความสมบูรณ์", + "Download selected installers": "ดาวน์โหลดตัวติดตั้งที่เลือกไว้", + "Install selection": "ติดตั้งรายการที่เลือก", + "Install options": "ตัวเลือกการติดตั้ง", + "Add selection to bundle": "เพิ่มรายการที่เลือกไว้ไปยังบันเดิล", + "Download installer": "ดาวน์โหลดตัวติดตั้ง", + "Uninstall selection": "ถอนการติดตั้งรายการที่เลือก", + "Uninstall options": "ตัวเลือกการถอนการติดตั้ง", + "Ignore selected packages": "ละเว้นแพ็กเกจที่เลือก", + "Open install location": "เปิด Path folder ที่ติดตั้งไป", + "Reinstall package": "ติดตั้งแพ็กเกจอีกรอบ", + "Uninstall package, then reinstall it": "ถอนการติดตั้งแพ็กเกจ แล้วติดตั้งใหม่", + "Ignore updates for this package": "ละเว้นการอัปเดตสำหรับแพ็กเกจนี้", + "WinGet malfunction detected": "ตรวจพบความผิดปกติของ WinGet", + "It looks like WinGet is not working properly. Do you want to attempt to repair WinGet?": "ดูเหมือนว่า WinGet จะทำงานผิดปกติ คุณต้องการลองซ่อมแซม WinGet หรือไม่?", + "Repair WinGet": "ซ่อมแซม WinGet", + "Updates will no longer be ignored for {0}": "การอัปเดตจะไม่ถูกละเว้นสำหรับ {0} อีกต่อไป", + "Updates are now ignored for {0}": "การอัปเดตถูกละเว้นสำหรับ {0} แล้ว", + "Do not ignore updates for this package anymore": "เลิกเพิกเฉยการอัปเดตแพ็กเกจนี้", + "Add packages or open an existing package bundle": "เพิ่มแพ็กเกจหรือเปิดชุดแพ็กเกจ(บันเดิล) ที่มีอยู่", + "Add packages to start": "เพิ่มแพ็กเกจเพื่อเริ่มใช้งาน", + "The current bundle has no packages. Add some packages to get started": "บันเดิลปัจจุบันไม่มีแพ็กเกจ เพิ่มแพ็กเกจบางรายการเพื่อเริ่มต้น", + "New": "ใหม่", + "Save as": "บันทึกเป็น", + "Create .ps1 script": "สร้างสคริปต์ .ps1", + "Remove selection from bundle": "ลบรายการที่เลือกออกจากบันเดิล", + "Skip hash checks": "ข้ามการตรวจสอบแฮช", + "The package bundle is not valid": "บันเดิลแพ็กเกจไม่ถูกต้อง", + "The bundle you are trying to load appears to be invalid. Please check the file and try again.": "บันเดิลที่คุณพยายามโหลดดูเหมือนจะไม่ถูกต้อง โปรดตรวจสอบไฟล์แล้วลองอีกครั้ง", + "Package bundle": "แพ็กเกจบันเดิล", + "Could not create bundle": "ไม่สามารถสร้างชุดแพ็กเกจ(บันเดิล)ได้", + "The package bundle could not be created due to an error.": "ไม่สามารถสร้างบันเดิลแพ็กเกจได้เนื่องจากเกิดข้อผิดพลาด", + "Install script": "สคริปต์การติดตั้ง", + "PowerShell script": "สคริปต์ PowerShell", + "The installation script saved to {0}": "บันทึกสคริปต์การติดตั้งไปยัง {0}", + "An error occurred": "มีข้อผิดพลาดเกิดขึ้น", + "An error occurred while attempting to create an installation script:": "เกิดข้อผิดพลาดขณะพยายามสร้างสคริปต์การติดตั้ง:", + "Hooray! No updates were found.": "ไชโย! ไม่พบการอัปเดต", + "Uninstall selected packages": "ถอนการติดตั้งแพ็กเกจที่เลือก", + "Update selection": "อัปเดตรายการที่เลือก", + "Update options": "ตัวเลือกการอัปเดต", + "Uninstall package, then update it": "ถอนการติดตั้งแพ็กเกจ แล้วทำการอัปเดต", + "Uninstall package": "ถอนการติดตั้งแพ็กเกจ", + "Skip this version": "ข้ามเวอร์ชันนี้", + "Pause updates for": "หยุดการอัปเดตชั่วคราวเป็นเวลา", + "User | Local": "ผู้ใช้ | ภายในเครื่อง", + "Machine | Global": "เครื่อง | ทั่วทั้งระบบ", + "The default package manager for Debian/Ubuntu-based Linux distributions.
Contains: Debian/Ubuntu packages": "ตัวจัดการแพ็กเกจเริ่มต้นสำหรับ Linux ที่ใช้ Debian/Ubuntu
ประกอบด้วย: แพ็กเกจ Debian/Ubuntu", + "The Rust package manager.
Contains: Rust libraries and programs written in Rust": "ตัวจัดการแพ็กเกจ Rust
ประกอบด้วย: ไลบรารี Rust และโปรแกรมที่เขียนด้วย Rust", + "The classical package manager for windows. You'll find everything there.
Contains: General Software": "ตัวจัดการแพ็กเกจสุดคลาสสิกสำหรับ Windows คุณสามารถหาทุกอย่างได้ที่นี่
ประกอบด้วย: ซอฟต์แวร์ทั่วไป", + "The default package manager for RHEL/Fedora-based Linux distributions.
Contains: RPM packages": "ตัวจัดการแพ็กเกจเริ่มต้นสำหรับ Linux ที่ใช้ RHEL/Fedora
ประกอบด้วย: แพ็กเกจ RPM", + "A repository full of tools and executables designed with Microsoft's .NET ecosystem in mind.
Contains: .NET related tools and scripts": "คลังข้อมูลที่เต็มไปด้วยเครื่องมือและโปรแกรมสั่งทำการที่ออกแบบมาโดยคำนึงถึงระบบนิเวศ .NET ของ Microsoft
ประกอบด้วย: เครื่องมือและสคริปต์ที่เกี่ยวข้องกับ .NET", + "The universal Linux package manager for desktop applications.
Contains: Flatpak applications from configured remotes": "ตัวจัดการแพ็กเกจ Linux สากลสำหรับแอปพลิเคชันเดสก์ท็อป
ประกอบด้วย: แอปพลิเคชัน Flatpak จากรีโมตที่กำหนดค่าไว้", + "NuPkg (zipped manifest)": "NuPkg (ไฟล์ Manifest ที่บีบอัด)", + "The Missing Package Manager for macOS (or Linux).
Contains: Formulae, Casks": "ตัวจัดการแพ็กเกจที่ขาดหายไปสำหรับ macOS (หรือ Linux)
ประกอบด้วย: Formulae, Casks", + "Node JS's package manager. Full of libraries and other utilities that orbit the javascript world
Contains: Node javascript libraries and other related utilities": "ตัวจัดการแพ็กเกจ Node JS ที่เต็มไปด้วยไลบรารีและเครื่องมืออื่น ๆ ที่เกี่ยวข้องกับ JavaScript
ประกอบด้วย: ไลบรารี JavaScript และเครื่องมือที่เกี่ยวข้องอื่น ๆ", + "The default package manager for Arch Linux and its derivatives.
Contains: Arch Linux packages": "ตัวจัดการแพ็กเกจเริ่มต้นสำหรับ Arch Linux และอนุพันธ์
ประกอบด้วย: แพ็กเกจ Arch Linux", + "Python's library manager. Full of python libraries and other python-related utilities
Contains: Python libraries and related utilities": "ตัวจัดการไลบรารีของ Python ที่เต็มไปด้วยไลบรารี Python และเครื่องมือที่เกี่ยวข้องกับ Python อื่น ๆ
ประกอบด้วย: ไลบรารี Python และเครื่องมือที่เกี่ยวข้องกับ Python", + "PowerShell's package manager. Find libraries and scripts to expand PowerShell capabilities
Contains: Modules, Scripts, Cmdlets": "ตัวจัดการแพ็กเกจของ PowerShell ค้นหาไลบรารีและสคริปต์เพื่อเพิ่มขีดความสามารถของ PowerShell
ประกอบด้วย: โมดูล, สคริปต์, Cmdlets", + "extracted": "แตกไฟล์แล้ว", + "Scoop package": "แพ็กเกจ Scoop", + "Great repository of unknown but useful utilities and other interesting packages.
Contains: Utilities, Command-line programs, General Software (extras bucket required)": "คลังข้อมูลที่ยอดเยี่ยมของโปรแกรมอรรถประโยชน์ที่ไม่เป็นที่รู้จักแต่มีประโยชน์ และแพ็กเกจอื่น ๆ ที่น่าสนใจ
ประกอบด้วย: โปรแกรมอรรถประโยชน์ โปรแกรมบรรทัดคำสั่ง ซอฟต์แวร์ทั่วไป (ต้องมีบักเก็ตเพิ่มเติม)", + "The universal Linux package manager by Canonical.
Contains: Snap packages from the Snapcraft store": "ตัวจัดการแพ็กเกจ Linux สากลโดย Canonical
ประกอบด้วย: แพ็กเกจ Snap จากร้านค้า Snapcraft", + "library": "ไลบรารี", + "feature": "คุณสมบัติ", + "A popular C/C++ library manager. Full of C/C++ libraries and other C/C++-related utilities
Contains: C/C++ libraries and related utilities": "ตัวจัดการไลบรารี C/C++ ยอดนิยม มีไลบรารี C/C++ และเครื่องมืออื่น ๆ ที่เกี่ยวข้องกับ C/C++ มากมาย
ประกอบด้วย: ไลบรารี C/C++ และเครื่องมือที่เกี่ยวข้อง", + "option": "ตัวเลือก", + "This package cannot be installed from an elevated context.": "ไม่สามารถติดตั้งแพ็กเกจนี้จากบริบทที่ยกระดับสิทธิ์ได้", + "Please run UniGetUI as a regular user and try again.": "โปรดรัน UniGetUI ในฐานะผู้ใช้ปกติแล้วลองอีกครั้ง", + "Please check the installation options for this package and try again": "โปรดตรวจสอบตัวเลือกการติดตั้งสำหรับแพ็กเกจนี้และลองอีกครั้ง", + "Microsoft's official package manager. Full of well-known and verified packages
Contains: General Software, Microsoft Store apps": "ตัวจัดการแพ็กเกจอย่างเป็นทางการของ Microsoft ที่เต็มด้วยแพ็กเกจที่เป็นที่รู้จักกันดี และผ่านการตรวจสอบแล้ว
ประกอบด้วย: ซอฟต์แวร์ทั่วไป, แอปจาก Microsoft Store", + "Local PC": "พีซีเครื่องนี้", + "Android Subsystem": "ระบบย่อยสำหรับ Android", + "Operation on queue (position {0})...": "การดำเนินการอยู่ในคิว (ลำดับที่ {0})...", + "Click here for more details": "คลิกที่นี่เพื่อดูรายละเอียดเพิ่มเติม", + "Operation canceled by user": "ผู้ใช้ยกเลิกการดำเนินการ", + "Running PreOperation ({0}/{1})...": "กำลังเรียกใช้ PreOperation ({0}/{1})...", + "PreOperation {0} out of {1} failed, and was tagged as necessary. Aborting...": "PreOperation {0} จาก {1} ล้มเหลว และถูกทำเครื่องหมายว่าจำเป็น กำลังยกเลิก...", + "PreOperation {0} out of {1} finished with result {2}": "PreOperation {0} จาก {1} เสร็จสิ้นด้วยผลลัพธ์ {2}", + "Starting operation...": "กำลังเริ่มการดำเนินการ...", + "Running PostOperation ({0}/{1})...": "กำลังเรียกใช้ PostOperation ({0}/{1})...", + "PostOperation {0} out of {1} failed, and was tagged as necessary. Aborting...": "PostOperation {0} จาก {1} ล้มเหลว และถูกทำเครื่องหมายว่าจำเป็น กำลังยกเลิก...", + "PostOperation {0} out of {1} finished with result {2}": "PostOperation {0} จาก {1} เสร็จสิ้นด้วยผลลัพธ์ {2}", + "{package} installer download": "ดาวน์โหลดตัวติดตั้ง {package}", + "{0} installer is being downloaded": "กำลังดาวน์โหลดตัวติดตั้ง {0}", + "Download succeeded": "ดาวน์โหลดสำเร็จ", + "{package} installer was downloaded successfully": "ดาวน์โหลดตัวติดตั้ง {package} สำเร็จแล้ว", + "Download failed": "ดาวน์โหลดไม่สำเร็จ", + "{package} installer could not be downloaded": "ไม่สามารถดาวน์โหลดตัวติดตั้ง {package} ได้", + "{package} Installation": "การติดตั้ง {package}", + "{0} is being installed": "กำลังติดตั้ง {0}", + "Installation succeeded": "การติดตั้งสำเร็จ", + "{package} was installed successfully": "ติดตั้ง {package} เสร็จสมบูรณ์", + "Installation failed": "การติดตั้งล้มเหลว", + "{package} could not be installed": "ไม่สามารถติดตั้ง {package} ได้", + "{package} Update": "อัปเดต {package}", + "Update succeeded": "อัปเดตสำเร็จแล้ว", + "{package} was updated successfully": "การอัปเดต {package} เสร็จสมบูรณ์", + "Update failed": "การอัปเดตล้มเหลว", + "{package} could not be updated": "ไม่สามารถอัปเดต {package} ได้", + "{package} Uninstall": "การถอนการติดตั้ง {package}", + "{0} is being uninstalled": "กำลังถอนการติดตั้ง {0}", + "Uninstall succeeded": "ถอนการติดตั้งสำเร็จ", + "{package} was uninstalled successfully": "ถอนการติดตั้ง {package} เสร็จสมบูรณ์", + "Uninstall failed": "ถอนการติดตั้งล้มเหลว", + "{package} could not be uninstalled": "ไม่สามารถถอนการติดตั้ง {package} ได้", + "Adding source {source}": "กำลังเพิ่มแหล่งที่มา (ซอร์ซ) {source}", + "Adding source {source} to {manager}": "กำลังเพิ่มซอร์ซ {source} ไปยัง {manager}", + "Source added successfully": "เพิ่มแหล่งที่มาสำเร็จ", + "The source {source} was added to {manager} successfully": "เพิ่มซอร์ซ {source} ไปยัง {manager} เสร็จสมบูรณ์", + "Could not add source": "ไม่สามารถเพิ่มแหล่งที่มาได้", + "Could not add source {source} to {manager}": "ไม่สามารถเพิ่มซอร์ซ {source} ให้กับ {manager}", + "Removing source {source}": "กำลังลบแหล่งที่มา {source}", + "Removing source {source} from {manager}": "กำลังลบซอร์ซ {source} ออกจาก {manager}", + "Source removed successfully": "ลบแหล่งที่มาสำเร็จ", + "The source {source} was removed from {manager} successfully": "ลบซอร์ซ {source} ออกจาก {manager} เสร็จสมบูรณ์", + "Could not remove source": "ไม่สามารถลบแหล่งที่มา", + "Could not remove source {source} from {manager}": "ไม่สามารถลบซอร์ซ {source} ออกจาก {manager}", + "The package manager \"{0}\" was not found": "ไม่พบตัวจัดการแพ็กเกจ \"{0}\"", + "The package manager \"{0}\" is disabled": "ตัวจัดการแพ็กเกจ \"{0}\" ถูกปิดใช้งาน", + "There is an error with the configuration of the package manager \"{0}\"": "เกิดข้อผิดพลาดในการกำหนดค่าของตัวจัดการแพ็กเกจ \"{0}\"", + "The package \"{0}\" was not found on the package manager \"{1}\"": "ไม่พบแพ็กเกจ \"{0}\" ในตัวจัดการแพ็กเกจ \"{1}\"", + "{0} is disabled": "{0} ถูกปิดใช้งานอยู่", + "{0} weeks": "{0} สัปดาห์", + "1 month": "1 เดือน", + "{0} months": "{0} เดือน", + "Something went wrong": "มีบางอย่างผิดพลาด", + "An interal error occurred. Please view the log for further details.": "เกิดข้อผิดพลาดภายใน โปรดดูบันทึกสำหรับรายละเอียดเพิ่มเติม", + "No applicable installer was found for the package {0}": "ไม่พบตัวติดตั้งที่เหมาะสมสำหรับแพ็กเกจ {0}", + "Integrity checks will not be performed during this operation": "ข้ามการตรวจสอบความสมบูรณ์ระหว่างการดำเนินการ", + "This is not recommended.": "ไม่แนะนำให้ทำเช่นนี้", + "Run now": "ดำเนินการทันที", + "Run next": "ดำเนินการรายการต่อไป", + "Run last": "ดำเนินการรายการสุดท้าย", + "Show in explorer": "แสดงใน Explorer", + "Checked": "เลือกแล้ว", + "Unchecked": "ไม่ได้เลือก", + "This package is already installed": "แพ็กเกจนี้ถูกติดตั้งแล้ว", + "This package can be upgraded to version {0}": "แพ็กเกจนี้สามารถอัปเกรดเป็นเวอร์ชัน {0}", + "Updates for this package are ignored": "อัปเดตสำหรับแพ็กเกจนี้ถูกละเว้น", + "This package is being processed": "แพ็กนี้กำลังถูกประมวลผล", + "This package is not available": "แพ็กเกจนี้ไม่พร้อมใช้งาน", + "Select the source you want to add:": "เลือกซอร์ซที่คุณต้องการเพิ่ม:", + "Source name:": "ชื่อซอร์ซ:", + "Source URL:": "URL ซอร์ซ:", + "An error occurred when adding the source: ": "มีข้อผิดพลาดเกิดขึ้นขณะเพิ่มซอร์ซ:", + "Package management made easy": "จัดการแพ็กเกจได้อย่างง่ายดาย", + "version {0}": "เวอร์ชัน {0}", + "[RAN AS ADMINISTRATOR]": "เรียกใช้ในฐานะผู้ดูแลระบบ", + "Portable mode": "โหมดพกพา\n", + "DEBUG BUILD": "บิลด์ดีบัก", + "Here you can change UniGetUI's behaviour regarding the following shortcuts. Checking a shortcut will make UniGetUI delete it if if gets created on a future upgrade. Unchecking it will keep the shortcut intact": "คุณสามารถเปลี่ยนแปลงพฤติกรรมของ UniGetUI สำหรับทางลัดเหล่านี้ การเลือกทางลัดจะให้ UniGetUI ลบทางลัดนั้นหากมีการสร้างขึ้นในการอัปเกรดครั้งต่อไป การไม่เลือกจะคงทางลัดไว้เหมือนเดิม", + "Manual scan": "สแกนด้วยตนเอง", + "Existing shortcuts on your desktop will be scanned, and you will need to pick which ones to keep and which ones to remove.": "ทางลัดที่มีอยู่บนหน้าจอของคุณจะถูกสแกน และคุณจะต้องเลือกว่าจะเก็บอันไหนและลบอันไหน", + "Delete?": "ลบ?", + "I understand": "ฉันเข้าใจแล้ว", + "Chocolatey setup changed": "การตั้งค่า Chocolatey เปลี่ยนแปลงแล้ว", + "UniGetUI no longer includes its own private Chocolatey installation. A legacy UniGetUI-managed Chocolatey installation was detected for this user profile, but system Chocolatey was not found. Chocolatey will stay unavailable in UniGetUI until Chocolatey is installed on the system and UniGetUI is restarted. Applications previously installed through UniGetUI's bundled Chocolatey may still appear under other sources such as Local PC or WinGet.": "UniGetUI ไม่รวมการติดตั้ง Chocolatey ส่วนตัวของตัวเองอีกต่อไป ตรวจพบการติดตั้ง Chocolatey ที่จัดการโดย UniGetUI รุ่นเก่าสำหรับโปรไฟล์ผู้ใช้นี้ แต่ไม่พบ Chocolatey ของระบบ Chocolatey จะยังคงใช้งานไม่ได้ใน UniGetUI จนกว่าจะติดตั้ง Chocolatey ในระบบและรีสตาร์ท UniGetUI แอปพลิเคชันที่ติดตั้งผ่าน Chocolatey ที่รวมมากับ UniGetUI ก่อนหน้านี้อาจยังคงปรากฏภายใต้แหล่งข้อมูลอื่น เช่น Local PC หรือ WinGet", + "NOTE: This troubleshooter can be disabled from UniGetUI Settings, on the WinGet section": "หมายเหตุ: ตัวช่วยแก้ปัญหานี้สามารถปิดได้ที่การตั้งค่า UniGetUI ในส่วน WinGet", + "Restart": "รีสตาร์ท", + "Are you sure you want to delete all shortcuts?": "คุณแน่ใจหรือไม่ที่ต้องการลบทางลัดทั้งหมด?", + "Any new shorcuts created during an install or an update operation will be deleted automatically, instead of showing a confirmation prompt the first time they are detected.": "ทางลัดใหม่ที่ถูกสร้างขึ้นระหว่างการติดตั้งหรือการอัปเดตจะถูกลบออกโดยอัตโนมัติ แทนที่จะแสดงหน้าต่างยืนยันในครั้งแรกที่ตรวจพบ", + "Any shorcuts created or modified outside of UniGetUI will be ignored. You will be able to add them via the {0} button.": "ทางลัดที่สร้างหรือแก้ไขนอก UniGetUI จะถูกละเว้น คุณสามารถเพิ่มทางลัดเหล่านั้นได้ผ่านปุ่ม {0}", + "Are you really sure you want to enable this feature?": "คุณแน่ใจจริงๆ หรือไม่ที่ต้องการเปิดใช้งานฟีเจอร์นี้?", + "No new shortcuts were found during the scan.": "ไม่พบทางลัดใหม่ระหว่างการสแกน", + "How to add packages to a bundle": "วิธีการเพิ่มแพ็กเกจไปยังชุดแพ็กเกจ", + "In order to add packages to a bundle, you will need to: ": "การจะเพิ่มแพ็กเกจลงในบันเดิล คุณต้องทำดังนี้:", + "1. Navigate to the \"{0}\" or \"{1}\" page.": "โปรดไปที่หน้าของ \"{0}\" หรือ \"{1}\"", + "2. Locate the package(s) you want to add to the bundle, and select their leftmost checkbox.": "2. ค้นหาแพ็กเกจที่คุณต้องการเพิ่มลงในชุดแพ็กเกจ จากนั้นเลือกช่องทำเครื่องหมายที่อยู่ซ้ายสุดของแต่ละรายการ", + "3. When the packages you want to add to the bundle are selected, find and click the option \"{0}\" on the toolbar.": "3. เมื่อเลือกแพ็กเกจที่ต้องการเพิ่มเข้าในบันเดิลแล้ว ให้หาและคลิกตัวเลือก \"{0}\" บนแถบเครื่องมือ", + "4. Your packages will have been added to the bundle. You can continue adding packages, or export the bundle.": "4. แพ็กเกจของคุณจะถูกเพิ่มลงในชุดแพ็กเกจเรียบร้อยแล้ว คุณสามารถเพิ่มแพ็กเกจต่อไปได้ หรือส่งออกชุดแพ็กเกจนี้", + "Which backup do you want to open?": "คุณต้องการเปิดข้อมูลสำรองใด", + "Select the backup you want to open. Later, you will be able to review which packages you want to install.": "เลือกข้อมูลสำรองที่คุณต้องการเปิด หลังจากนั้นคุณจะสามารถตรวจสอบได้ว่าต้องการกู้คืนแพ็กเกจ/โปรแกรมใด", + "There are ongoing operations. Quitting UniGetUI may cause them to fail. Do you want to continue?": "มีการดำเนินงานอยู่ในขณะนี้ การออกจาก UniGetUI อาจทำให้การทำงานล้มเหลว คุณต้องการดำเนินการต่อหรือไม่", + "UniGetUI or some of its components are missing or corrupt.": "UniGetUI หรือส่วนประกอบบางอย่างสูญหายหรือเสียหาย", + "It is strongly recommended to reinstall UniGetUI to adress the situation.": "ขอแนะนำอย่างยิ่งให้ติดตั้ง UniGetUI ใหม่เพื่อแก้ไขสถานการณ์นี้", + "Refer to the UniGetUI Logs to get more details regarding the affected file(s)": "โปรดดูบันทึกของ UniGetUI เพื่อรับรายละเอียดเพิ่มเติมเกี่ยวกับไฟล์ที่ได้รับผลกระทบ", + "Integrity checks can be disabled from the Experimental Settings": "สามารถปิดใช้งานการตรวจสอบความสมบูรณ์ได้จากการตั้งค่าทดลอง", + "Repair UniGetUI": "ซ่อมแซม UniGetUI", + "Live output": "เอาต์พุตสด", + "This package bundle had some settings that are potentially dangerous, and may be ignored by default.": "บันเดิลแพ็กเกจนี้มีการตั้งค่าบางอย่างที่อาจเป็นอันตราย และอาจถูกละเว้นตามค่าเริ่มต้น", + "Entries that show in YELLOW will be IGNORED.": "บรรทัดสีเหลืองจะถูกละเว้น", + "Entries that show in RED will be IMPORTED.": "บรรทัดสีแดงจะถูกนำเข้า", + "You can change this behavior on UniGetUI security settings.": "คุณสามารถเปลี่ยนพฤติกรรมนี้ได้ที่การตั้งค่าความปลอดภัยของ UniGetUI", + "Open UniGetUI security settings": "เปิดการตั้งค่าความปลอดภัยของ UniGetUI", + "Should you modify the security settings, you will need to open the bundle again for the changes to take effect.": "หากคุณแก้ไขการตั้งค่าความปลอดภัย คุณจะต้องเปิดบันเดิลอีกครั้งเพื่อให้การเปลี่ยนแปลงมีผล", + "Details of the report:": "รายละเอียดของรายงาน:", + "Are you sure you want to create a new package bundle? ": "คุณแน่ใจหรือไม่ที่ต้องการสร้างแพ็กเกจบันเดิลใหม่?", + "Any unsaved changes will be lost": "การเปลี่ยนแปลงที่ยังไม่ได้บันทึกจะหายไป", + "Warning!": "คำเตือน!", + "For security reasons, custom command-line arguments are disabled by default. Go to UniGetUI security settings to change this. ": "ด้วยเหตุผลด้านความปลอดภัย อาร์กิวเมนต์บรรทัดคำสั่งแบบกำหนดเองจึงถูกปิดใช้งานตามค่าเริ่มต้น ไปที่การตั้งค่าความปลอดภัยของ UniGetUI เพื่อเปลี่ยนแปลงสิ่งนี้ ", + "Change default options": "เปลี่ยนการตั้งค่าเริ่มต้น", + "Ignore future updates for this package": "ละเว้นการอัปเดตในอนาคตสำหรับแพ็กเกจนี้", + "For security reasons, pre-operation and post-operation scripts are disabled by default. Go to UniGetUI security settings to change this. ": "ด้วยเหตุผลด้านความปลอดภัย สคริปต์ก่อนและหลังการดำเนินการจึงถูกปิดใช้งานตามค่าเริ่มต้น ไปที่การตั้งค่าความปลอดภัยของ UniGetUI เพื่อเปลี่ยนแปลงสิ่งนี้ ", + "You can define the commands that will be run before or after this package is installed, updated or uninstalled. They will be run on a command prompt, so CMD scripts will work here.": "คุณสามารถกำหนดคำสั่งที่จะรันก่อนหรือหลังจากติดตั้ง อัปเดต หรือถอนการติดตั้งแพ็กเกจนี้ได้ คำสั่งจะรันผ่าน command prompt ดังนั้นสคริปต์ CMD จึงใช้ได้ที่นี่", + "Change this and unlock": "เปลี่ยนสิ่งนี้และปลดล็อก", + "{0} Install options are currently locked because {0} follows the default install options.": "ตัวเลือกการติดตั้งของ {0} ถูกล็อกอยู่ในขณะนี้ เพราะ {0} ใช้ตัวเลือกการติดตั้งเริ่มต้น", + "Unset or unknown": "ยังไม่ได้ตั้งค่าหรือไม่ทราบ", + "This package has no screenshots or is missing the icon? Contrbute to UniGetUI by adding the missing icons and screenshots to our open, public database.": "แพ็กเกจนี้ไม่มีภาพหน้าจอหรือขาดไอคอนใช่ไหม ขอเชิญมีส่วนร่วมกับ UniGetUI โดยการเพิ่มไอคอนและภาพหน้าจอที่ขาดหายไปในฐานข้อมูลสาธารณะแบบเปิดของเรา", + "Become a contributor": "มาเป็นผู้ร่วมให้ข้อมูล", + "Update to {0} available": "มีอัปเดตสำหรับ {0}", + "Reinstall": "ติดตั้งใหม่", + "Installer not available": "ตัวติดตั้งไม่พร้อมใช้งาน", + "Version:": "เวอร์ชัน:", + "UniGetUI Version {0}": "UniGetUI เวอร์ชัน {0}", + "Performing backup, please wait...": "กำลังสำรองข้อมูล โปรดรอสักครู่...", + "An error occurred while logging in: ": "เกิดข้อผิดพลาดขณะลงชื่อเข้าใช้: ", + "Fetching available backups...": "กำลังดึงข้อมูลสำรองที่พร้อมใช้งาน...", + "Done!": "เสร็จสิ้น", + "The cloud backup has been loaded successfully.": "โหลดข้อมูลสำรองบนคลาวด์สำเร็จ", + "An error occurred while loading a backup: ": "เกิดข้อผิดพลาดขณะโหลดข้อมูลสำรองข้อมูล: ", + "Backing up packages to GitHub Gist...": "กำลังสำรองข้อมูลแพ็กเกจไปยัง GitHub Gist...", + "Backup Successful": "สำรองข้อมูลสำเร็จ", + "The cloud backup completed successfully.": "สำรองข้อมูลบนคลาวด์สำเร็จ", + "Could not back up packages to GitHub Gist: ": "ไม่สามารถสำรองข้อมูลแพ็กเกจไปยัง GitHub Gist:", + "It is not guaranteed that the provided credentials will be stored safely, so you may as well not use the credentials of your bank account": "ไม่มีการรับประกันว่าข้อมูลส่วนตัวที่ให้ไว้จะถูกเก็บไว้อย่างปลอดภัย ดังนั้นคุณไม่ควรใช้ข้อมูลประจำตัวของบัญชีธนาคารของคุณ", + "Enable the automatic WinGet troubleshooter": "เปิดใช้ WinGet troubleshooter อัตโนมัติ", + "Add updates that fail with a 'no applicable update found' to the ignored updates list": "เพิ่มรายการอัปเดตที่ไม่สำเร็จด้วยข้อความ ‘ไม่พบการอัปเดตที่เหมาะสม’ ลงในรายการอัปเดตที่ถูกละเว้น", + "Invalid selection": "การเลือกไม่ถูกต้อง", + "No package was selected": "ไม่มีแพ็กเกจที่ถูกเลือก", + "More than 1 package was selected": "มีการเลือกมากกว่า 1 แพ็กเกจ", + "List": "รายการ", + "Grid": "ตาราง", + "Icons": "ไอคอน", + "\"{0}\" is a local package and does not have available details": "\"{0}\" เป็นแพ็กเกจภายในเครื่องและไม่มีรายละเอียดที่สามารถแสดงได้", + "\"{0}\" is a local package and is not compatible with this feature": "\"{0}\" เป็นแพ็กเกจภายในเครื่องและไม่สามารถใช้งานร่วมกับฟีเจอร์นี้ได้", + "Add packages to bundle": "เพิ่มแพ็กเกจเข้าไปในชุดแพ็กเกจ(บันเดิล)", + "Preparing packages, please wait...": "กำลังเตรียมแพ็กเกจ โปรดรอสักครู่...", + "Loading packages, please wait...": "กำลังโหลดแพ็กเกจ โปรดรอสักครู่...", + "Saving packages, please wait...": "กำลังบันทึกแพ็กเกจ โปรดรอสักครู่...", + "The bundle was created successfully on {0}": "สร้างบันเดิลสำเร็จเมื่อ {0}", + "User profile": "โปรไฟล์ผู้ใช้", + "Error": "ข้อผิดพลาด", + "Log in failed: ": "ลงชื่อเข้าใช้ไม่สำเร็จ:", + "Log out failed: ": "ออกจากระบบไม่สำเร็จ:", + "Package backup settings": "การตั้งค่าการสำรองข้อมูลแพ็กเกจ", + "Package managers": "ตัวจัดการแพ็กเกจ", + "Manage UniGetUI autostart behaviour from the Settings app": "จัดการพฤติกรรมการเริ่มอัตโนมัติของ UniGetUI", + "Choose how many operations shoulds be performed in parallel": "เลือกจำนวนการดำเนินการที่ควรทำพร้อมกัน", + "Something went wrong while launching the updater.": "มีข้อผิดพลาดขณะเปิดตัวอัปเดต", + "Please try again later": "กรุณาลองใหม่ในภายหลัง", + "Show the release notes after UniGetUI is updated": "แสดงรายละเอียดการปรับปรุงหลังจากอัปเดต UniGetUI" +} diff --git a/src/Languages/lang_tl.json b/src/Languages/lang_tl.json new file mode 100644 index 0000000..8507d71 --- /dev/null +++ b/src/Languages/lang_tl.json @@ -0,0 +1,851 @@ +{ + "{0} of {1} operations completed": "{0} sa {1} operasyon ang natapos", + "{0} is now {1}": "Ang {0} ay {1} na ngayon", + "Enabled": "Naka-enable", + "Disabled": "Naka-disable", + "Privacy": "Privacy", + "Hide my username from the logs": "Itago ang aking username sa mga log", + "Replaces your username with **** in the logs. Restart UniGetUI to also hide it from already-recorded entries.": "Pinapalitan ang iyong username ng **** sa mga log. I-restart ang UniGetUI upang itago din ito sa mga naitala na entry.", + "Your last update attempt did not complete.": "Hindi nakumpleto ang huli mong pagtatangkang mag-update.", + "UniGetUI could not confirm whether the update succeeded. Open the log to see what happened.": "Hindi makumpirma ng UniGetUI kung nagtagumpay ang update. Buksan ang log para makita kung ano ang nangyari.", + "View log": "Tingnan ang log", + "The installer reported success but did not restart UniGetUI.": "Iniulat ng installer na matagumpay ito ngunit hindi nito na-restart ang UniGetUI.", + "The installer failed to initialize.": "Pumalya ang pag-initialize ng installer.", + "Setup was canceled before installation began.": "Kinansela ang setup bago nagsimula ang installation.", + "A fatal error occurred during the preparation phase.": "Nagkaroon ng malubhang error sa yugto ng paghahanda.", + "A fatal error occurred during installation.": "Nagkaroon ng malubhang error habang nag-i-install.", + "Installation was canceled while in progress.": "Kinansela ang installation habang isinasagawa.", + "The installer was terminated by another process.": "Tinapos ng ibang proseso ang installer.", + "The preparation phase determined the installation cannot proceed.": "Natukoy sa yugto ng paghahanda na hindi maaaring magpatuloy ang installation.", + "The installer could not start. UniGetUI may already be running, or you do not have permission to install.": "Hindi masimulan ang installer. Maaaring tumatakbo na ang UniGetUI, o wala kang pahintulot na mag-install.", + "Unexpected installer error.": "Hindi inaasahang error ng installer.", + "We are checking for updates.": "Sinusuri namin ang mga update.", + "Please wait": "Pakihintay", + "Great! You are on the latest version.": "Ayos! Nasa pinakabagong bersyon ka na.", + "There are no new UniGetUI versions to be installed": "Walang bagong bersyon ng UniGetUI na mai-install", + "UniGetUI version {0} is being downloaded.": "Dina-download ang bersyon {0} ng UniGetUI.", + "This may take a minute or two": "Maaaring tumagal ito ng isa o dalawang minuto", + "The installer authenticity could not be verified.": "Hindi mabeberipika ang pagiging tunay ng installer.", + "The update process has been aborted.": "Na-abort ang proseso ng update.", + "Auto-update is not yet available on this platform.": "Hindi pa available ang auto-update sa platform na ito.", + "Please update UniGetUI manually.": "Paki-update nang mano-mano ang UniGetUI.", + "An error occurred when checking for updates: ": "Nagkaroon ng kamalian sa paghahanap ng updates:", + "The updater could not be launched.": "Hindi mailunsad ang updater.", + "The operating system did not start the installer process.": "Hindi sinimulan ng operating system ang proseso ng installer.", + "UniGetUI is being updated...": "Ina-update ang UniGetUI...", + "Update installed.": "Na-install ang update.", + "UniGetUI was updated successfully, but this running copy was not replaced. This usually means you are running a development build. Close this copy and start the newly-installed version to finish.": "Matagumpay na na-update ang UniGetUI, ngunit hindi napalitan ang tumatakbong kopyang ito. Karaniwang ibig sabihin nito ay nagpapatakbo ka ng development build. Isara ang kopyang ito at simulan ang bagong na-install na bersyon para matapos.", + "The update could not be applied.": "Hindi mailapat ang update.", + "Installer exit code {0}: {1}": "Exit code ng installer {0}: {1}", + "Update cancelled.": "Kinansela ang update.", + "Authentication was cancelled.": "Kinansela ang authentication.", + "Installer exit code {0}": "Exit code ng installer {0}", + "Operation in progress": "May operasyong isinasagawa", + "Please wait...": "Pakihintay...", + "Success!": "Tagumpay!", + "Failed": "Pumalya", + "An error occurred while processing this package": "Nagkaroon ng error habang pinoproseso ang package na ito", + "Installer": "Pang-install", + "Executable": "Maipapatakbong file", + "MSI": "MSI", + "Compressed file": "Naka-compress na file", + "MSIX": "MSIX", + "WinGet was repaired successfully": "Matagumpay na naayos ang WinGet", + "It is recommended to restart UniGetUI after WinGet has been repaired": "Inirerekomendang i-restart ang UniGetUI matapos maayos ang WinGet", + "WinGet could not be repaired": "Hindi naayos ang WinGet", + "An unexpected issue occurred while attempting to repair WinGet. Please try again later": "Nagkaroon ng hindi inaasahang isyu habang sinusubukang ayusin ang WinGet. Pakisubukan muli mamaya", + "Log in to enable cloud backup": "Mag-log in para paganahin ang cloud backup", + "Backup Failed": "Pumalya ang backup", + "Downloading backup...": "Dina-download ang backup...", + "An update was found!": "Mayroong update na nahanap!", + "{0} can be updated to version {1}": "Maaaring i-update ang {0} sa bersyon {1}", + "Updates found!": "May nahanap na mga update!", + "{0} packages can be updated": "{0} pa na mga package ang maaaring i-update", + "{0} is being updated to version {1}": "Ina-update ang {0} sa bersyon {1}", + "{0} packages are being updated": "{0}ng mga package ang inuupdate", + "You have currently version {0} installed": "Kasalukuyan mong naka-install ang bersyon {0}", + "Desktop shortcut created": "Nalikhang desktop shortcut", + "UniGetUI has detected a new desktop shortcut that can be deleted automatically.": "Nakakita ang UniGetUI ng bagong desktop shortcut na maaaring awtomatikong burahin.", + "{0} desktop shortcuts created": "{0} desktop shortcut ang nalikha", + "UniGetUI has detected {0} new desktop shortcuts that can be deleted automatically.": "Nakakita ang UniGetUI ng {0} bagong desktop shortcut na maaaring awtomatikong burahin.", + "Attention required": "Kailangan ng iyong atensyon", + "Restart required": "Kailangan ang restart", + "1 update is available": "May 1 update na available", + "{0} updates are available": "May {0} available na update", + "Everything is up to date": "Lahat ay updated", + "Discover Packages": "Mag-discover ng mga package", + "Available Updates": "Mga Available na Update", + "Installed Packages": "Mga naka-install na package", + "UniGetUI Version {0} by Devolutions": "UniGetUI Bersyon {0} ng Devolutions", + "Show UniGetUI": "Ipakita ng UniGetUI", + "Quit": "Lumabas", + "Are you sure?": "Sigurado ka na?", + "Do you really want to uninstall {0}?": "Gusto mo ba talaga na alisin ang {0}", + "Do you really want to uninstall the following {0} packages?": "Sigurado ka bang gusto mong i-uninstall ang sumusunod na {0} package?", + "No": "Hindi", + "Yes": "Oo", + "Partial": "Bahagya", + "View on UniGetUI": "Tingnan sa UniGetUI", + "Update": "I-update", + "Open UniGetUI": "Buksan ang UniGetUI", + "Update all": "I-update lahat", + "Update now": "I-update ngayon", + "Installer host changed since the installed version.\n": "Nagbago ang host ng installer mula noong naka-install na bersyon.\n", + "This package is on the queue": "Nasa pila ang package na ito", + "installing": "nag-i-install", + "updating": "nag-a-update", + "uninstalling": "nag-u-uninstall", + "installed": "naka-install", + "Retry": "Subukan muli", + "Install": "i-install", + "Uninstall": "i-uninstall", + "Open": "Buksan", + "Operation profile:": "Profile ng operasyon:", + "Follow the default options when installing, upgrading or uninstalling this package": "Sundin ang mga default na opsyon kapag ini-install, ina-upgrade, o ina-uninstall ang package na ito", + "The following settings will be applied each time this package is installed, updated or removed.": "Ang mga sumusunod na setting ay ilalapat sa tuwing ini-install, ina-update, o inaalis ang package na ito.", + "Version to install:": "Bersyon na i-install:", + "Architecture to install:": "Arkitektura para mainstall:", + "Installation scope:": "Saklaw ng installation:", + "Install location:": "Lokasyon ng install:", + "Select": "Piliin", + "Reset": "I-reset", + "Custom install arguments:": "Mga custom na argument sa install:", + "Custom update arguments:": "Mga custom na argument sa update:", + "Custom uninstall arguments:": "Mga custom na argument sa uninstall:", + "Pre-install command:": "Command bago mag-install:", + "Post-install command:": "Command pagkatapos mag-install:", + "Abort install if pre-install command fails": "I-abort ang install kung pumalya ang pre-install command", + "Pre-update command:": "Command bago mag-update:", + "Post-update command:": "Command pagkatapos mag-update:", + "Abort update if pre-update command fails": "I-abort ang update kung pumalya ang pre-update command", + "Pre-uninstall command:": "Command bago mag-uninstall:", + "Post-uninstall command:": "Command pagkatapos mag-uninstall:", + "Abort uninstall if pre-uninstall command fails": "I-abort ang uninstall kung pumalya ang pre-uninstall command", + "Command-line to run:": "Command-line na tatakbuhin:", + "Save and close": "I-save at isara", + "General": "Pangkalahatan", + "Architecture & Location": "Arkitektura at Lokasyon", + "Command-line": "Linya ng command", + "Close apps": "Isara ang mga app", + "Pre/Post install": "Bago/Pagkatapos ng pag-install", + "Select the processes that should be closed before this package is installed, updated or uninstalled.": "Piliin ang mga prosesong dapat isara bago ma-install, ma-update, o ma-uninstall ang package na ito.", + "Write here the process names here, separated by commas (,)": "Isulat dito ang mga pangalan ng proseso, na pinaghihiwalay ng mga kuwit (,)", + "Try to kill the processes that refuse to close when requested to": "Subukang i-kill ang mga prosesong tumatangging magsara kapag hiniling", + "Run as admin": "Patakbuhin bilang admin", + "Interactive installation": "Interactive na installation", + "Skip hash check": "Laktawan ang hash check", + "Uninstall previous versions when updated": "I-uninstall ang mga naunang bersyon kapag na-update", + "Skip minor updates for this package": "Laktawan ang mga minor na update para sa package na ito", + "Automatically update this package": "Awtomatikong i-update ang package na ito", + "{0} installation options": "Mga opsyon sa installation ng {0}", + "Latest": "Pinakabago", + "PreRelease": "Pre-release", + "Default": "Nakatakda", + "Manage ignored updates": "Pamahalaan ang mga in-ignore na update", + "The packages listed here won't be taken in account when checking for updates. Double-click them or click the button on their right to stop ignoring their updates.": "Ang mga package na nakalista rito ay hindi isasama kapag naghahanap ng mga update. I-double-click ang mga ito o i-click ang button sa kanan nila para itigil ang pag-ignore sa kanilang mga update.", + "Reset list": "I-reset ang listahan", + "Do you really want to reset the ignored updates list? This action cannot be reverted": "Gusto mo ba talagang i-reset ang listahan ng mga binalewalang update? Hindi na maibabalik ang pagkilos na ito.", + "No ignored updates": "Walang binalewalang update", + "Package Name": "Pangalan ng Package", + "Package ID": "ID ng Package", + "Ignored version": "In-ignore na bersyon", + "New version": "Bagong bersyon", + "Source": "Pinagmulan", + "All versions": "Lahat ng Bersyon", + "Unknown": "Hindi alam", + "Up to date": "Napapanahon", + "Package {name} from {manager}": "Package {name} mula sa {manager}", + "Remove {0} from ignored updates": "Alisin ang {0} sa mga binalewalang update", + "Cancel": "Ikansela", + "Administrator privileges": "Nakatataas na pribilehiyo", + "This operation is running with administrator privileges.": "Ang operasyong ito ay tumatakbo nang may mga pribilehiyo ng administrator.", + "Interactive operation": "Interactive na operasyon", + "This operation is running interactively.": "Ang operasyong ito ay tumatakbo nang interactive.", + "You will likely need to interact with the installer.": "Malamang na kakailanganin mong makipag-ugnayan sa installer.", + "Integrity checks skipped": "Nilaktawan ang mga integrity check", + "Integrity checks will not be performed during this operation.": "Hindi isasagawa ang mga pagsusuri sa integridad sa operasyong ito.", + "Proceed at your own risk.": "Magpatuloy sa sarili mong panganib.", + "Close": "Isara", + "Loading...": "Nilo-load...", + "Installer SHA256": "SHA256 ng installer", + "Homepage": "Pahina sa web", + "Author": "Manggagawa", + "Publisher": "Tagapaglathala", + "License": "Lisensya", + "Manifest": "Manipesto", + "Installer Type": "Uri ng installer", + "Size": "Laki", + "Installer URL": "URL ng installer", + "Last updated:": "Huling na-update:", + "Release notes URL": "URL ng mga tala sa release", + "Package details": "Mga detalye ng package", + "Dependencies:": "Mga dependency:", + "Release notes": "Mga tala sa release", + "Screenshots": "Mga screenshot", + "This package has no screenshots or is missing the icon? Contribute to UniGetUI by adding the missing icons and screenshots to our open, public database.": "Wala bang mga screenshot ang package na ito o nawawala ba ang icon? Mag-ambag sa UniGetUI sa pamamagitan ng pagdaragdag ng mga nawawalang icon at screenshot sa aming bukas at pampublikong database.", + "Version": "Bersyon", + "Install as administrator": "I-install bilang administrator", + "Update to version {0}": "I-update sa bersyon {0}", + "Installed Version": "Naka-install na Bersyon", + "Update as administrator": "I-update bilang administrator", + "Interactive update": "Interactive na update", + "Uninstall as administrator": "I-uninstall bilang administrator", + "Interactive uninstall": "Interactive na uninstall", + "Uninstall and remove data": "I-uninstall at alisin ang data", + "Not available": "Hindi available", + "Installer SHA512": "SHA512 ng installer", + "Unknown size": "Hindi alam ang laki", + "No dependencies specified": "Walang tinukoy na dependency", + "mandatory": "sapilitan", + "optional": "opsyonal", + "UniGetUI {0} is ready to be installed.": "Handa nang i-install ang UniGetUI {0}.", + "The update process will start after closing UniGetUI": "Magsisimula ang proseso ng update pagkatapos isara ang UniGetUI", + "UniGetUI has been ran as administrator, which is not recommended. When running UniGetUI as administrator, EVERY operation launched from UniGetUI will have administrator privileges. You can still use the program, but we highly recommend not running UniGetUI with administrator privileges.": "Ang UniGetUI ay pinatakbo bilang administrator, na hindi inirerekomenda. Kapag pinatakbo mo ang UniGetUI bilang administrator, BAWAT operasyong ilulunsad mula sa UniGetUI ay magkakaroon ng mga pribilehiyo ng administrator. Magagamit mo pa rin ang programa, ngunit mahigpit naming inirerekomenda na huwag patakbuhin ang UniGetUI nang may mga pribilehiyo ng administrator.", + "Share anonymous usage data": "Ibahagi ang anonymous na data ng paggamit", + "UniGetUI collects anonymous usage data in order to improve the user experience.": "Nangongolekta ang UniGetUI ng anonymous na data ng paggamit upang mapabuti ang karanasan ng user.", + "Accept": "Tanggapin", + "Software Updates": "Mga Update ng Software", + "Package Bundles": "Mga Package Bundle", + "Settings": "Mga Setting", + "Package Managers": "Mga package manager", + "UniGetUI Log": "Log ng UniGetUI", + "Package Manager logs": "Mga log ng Package Manager", + "Operation history": "Kasaysayan ng operasyon", + "Help": "Tulong", + "UniGetUI": "UniGetUI", + "You have installed UniGetUI Version {0}": "Naka-install ang Bersyon ng UniGetUI {0}", + "Disclaimer": "Paunawa", + "UniGetUI is developed by Devolutions and is not affiliated with any of the compatible package managers.": "Ang UniGetUI ay binuo ng Devolutions at hindi kaakibat ng alinman sa mga katugmang package manager.", + "UniGetUI wouldn't have been possible without the help of the contributors. Thank you all 🥳": "Hindi magiging posible ang UniGetUI kung wala ang tulong ng mga kontribyutor. Salamat sa inyong lahat 🥳", + "UniGetUI uses the following libraries. Without them, UniGetUI wouldn't have been possible.": "Ginagamit ng UniGetUI ang mga sumusunod na library. Kung wala sila, hindi magiging posible ang UniGetUI.", + "{0} homepage": "Homepage ng {0}", + "UniGetUI has been translated to more than 40 languages thanks to the volunteer translators. Thank you 🤝": "Ang UniGetUI ay isinalin sa higit sa 40 mga wika salamat sa mga boluntaryong tagasalin. Salamat 🤝", + "Verbose": "Detalyado", + "1 - Errors": "1 - Mga Error", + "2 - Warnings": "2 - Mga Babala", + "3 - Information (less)": "3 - Impormasyon (kaunti)", + "4 - Information (more)": "4 - Impormasyon (mas marami)", + "5 - information (debug)": "5 - Impormasyon (debug)", + "Warning": "Babala", + "The following settings may pose a security risk, hence they are disabled by default.": "Maaaring magdulot ng panganib sa seguridad ang mga sumusunod na setting, kaya naka-disable ang mga ito bilang default.", + "Enable the settings below if and only if you fully understand what they do, and the implications they may have.": "Paganahin lamang ang mga setting sa ibaba kung lubos mong nauunawaan ang ginagawa ng mga ito at ang mga implikasyon nila.", + "The settings will list, in their descriptions, the potential security issues they may have.": "Ililista ng mga setting, sa kanilang mga paglalarawan, ang mga posibleng isyu sa seguridad na maaari nilang taglayin.", + "The backup will include the complete list of the installed packages and their installation options. Ignored updates and skipped versions will also be saved.": "Isasama sa backup ang kumpletong listahan ng mga naka-install na package at ang mga opsyon ng installation ng mga ito. Mase-save rin ang mga in-ignore na update at nilaktawang bersyon.", + "The backup will NOT include any binary file nor any program's saved data.": "HINDI isasama sa backup ang anumang binary file o saved data ng alinmang programa.", + "The size of the backup is estimated to be less than 1MB.": "Tinatayang mas mababa sa 1MB ang laki ng backup.", + "The backup will be performed after login.": "Isasagawa ang backup pagkatapos mag-log in.", + "{pcName} installed packages": "Mga naka-install na package sa {pcName}", + "Current status: Not logged in": "Kasalukuyang status: Hindi naka-log in", + "You are logged in as {0} (@{1})": "Naka-log in ka bilang {0} (@{1})", + "Nice! Backups will be uploaded to a private gist on your account": "Ayos! Ia-upload ang mga backup sa pribadong gist sa iyong account", + "Select backup": "Piliin ang backup", + "Settings imported from {0}": "Na-import ang mga setting mula sa {0}", + "UniGetUI Settings": "Mga Setting ng UniGetUI", + "Settings exported to {0}": "Na-export ang mga setting sa {0}", + "UniGetUI settings were reset": "Na-reset ang mga setting ng UniGetUI", + "Allow pre-release versions": "Payagan ang mga pre-release na bersyon", + "Apply": "Ilapat", + "For security reasons, custom command-line arguments are disabled by default. Go to UniGetUI security settings to change this.": "Dahil sa mga kadahilanang pangseguridad, ang mga custom na argumento sa command-line ay naka-disable bilang default. Pumunta sa mga setting ng seguridad ng UniGetUI upang baguhin ito.", + "Go to UniGetUI security settings": "Pumunta sa mga security setting ng UniGetUI", + "The following options will be applied by default each time a {0} package is installed, upgraded or uninstalled.": "Ang mga sumusunod na opsyon ay ilalapat bilang default sa tuwing ini-install, ina-upgrade, o ina-uninstall ang isang package ng {0}.", + "Package's default": "Default ng package", + "Install location can't be changed for {0} packages": "Hindi mababago ang lokasyon ng install para sa mga package ng {0}", + "The local icon cache currently takes {0} MB": "Kasalukuyang kumakain ng {0} MB ang lokal na cache ng icon", + "Username": "Pangalan ng user", + "Password": "Pasword", + "Credentials": "Mga kredensyal", + "It is not guaranteed that the provided credentials will be stored safely": "Hindi ginagarantiya na ligtas na maiimbak ang mga ibinigay na kredensyal", + "Partially": "Bahagya", + "Package manager": "Manager ng pakete", + "Compatible with proxy": "Compatible sa proxy", + "Compatible with authentication": "Compatible sa authentication", + "Proxy compatibility table": "Talahanayan ng compatibility ng proxy", + "{0} settings": "Mga setting ng {0}", + "{0} status": "Status ng {0}", + "Default installation options for {0} packages": "Mga default na opsyon sa install para sa mga package ng {0}", + "Expand version": "I-expand ang bersyon", + "The executable file for {0} was not found": "Hindi nakita ang executable file para sa {0}", + "{pm} is disabled": "Naka-disable ang {pm}", + "Enable it to install packages from {pm}.": "Paganahin ito para makapag-install ng mga package mula sa {pm}.", + "{pm} is enabled and ready to go": "Naka-enable ang {pm} at handa nang gamitin", + "{pm} version:": "Bersyon ng {pm}:", + "{pm} was not found!": "Hindi nakita ang {pm}!", + "You may need to install {pm} in order to use it with UniGetUI.": "Maaaring kailanganin mong i-install ang {pm} upang magamit ito sa UniGetUI.", + "Scoop Installer - UniGetUI": "Installer ng Scoop - UniGetUI", + "Scoop Uninstaller - UniGetUI": "Uninstaller ng Scoop - UniGetUI", + "Clearing Scoop cache - UniGetUI": "Linilinis ang Scoop cache - UniGetUI", + "Restart UniGetUI to fully apply changes": "I-restart ang UniGetUI upang ganap na mailapat ang mga pagbabago", + "Restart UniGetUI": "I-restart ang UniGetUI", + "Manage {0} sources": "Pamahalaan ang mga source ng {0}", + "Add source": "Magdagdag ng source", + "Add": "Magdagdag", + "Source name": "Pangalan ng source", + "Source URL": "URL ng source", + "Other": "Iba pa", + "No minimum age": "Walang minimum na tagal", + "1 day": "isang araw", + "{0} days": "{0} araw", + "Custom...": "Pasadya...", + "{0} minutes": "{0} minuto", + "1 hour": "isang oras", + "{0} hours": "{0} oras", + "1 week": "isang linggo", + "Supports release dates": "Sinusuportahan ang mga petsa ng release", + "Release date support per package manager": "Suporta sa petsa ng release ayon sa package manager", + "Search for packages": "Maghanap ng mga package", + "Local": "Lokal", + "OK": "Ok", + "Last checked: {0}": "Huling sinuri: {0}", + "{0} packages were found, {1} of which match the specified filters.": "May {0} package na nakita, at {1} sa mga iyon ang tumutugma sa mga tinukoy na filter.", + "{0} selected": "{0} ang napili", + "(Last checked: {0})": "(Huling sinuri: {0})", + "All packages selected": "Lahat ng package ay napili", + "Package selection cleared": "Na-clear ang pagpili ng package", + "{0}: {1}": "{0}: {1}", + "More info": "Higit pang impormasyon", + "GitHub account": "Account sa GitHub", + "Log in with GitHub to enable cloud package backup.": "Mag-log in gamit ang GitHub para paganahin ang cloud backup ng package.", + "More details": "Higit pang detalye", + "Log in": "Mag-log in", + "If you have cloud backup enabled, it will be saved as a GitHub Gist on this account": "Kung naka-enable ang cloud backup, ise-save ito bilang GitHub Gist sa account na ito", + "Log out": "Mag-log out", + "About UniGetUI": "Tungkol sa UniGetUI", + "About": "Tungkol", + "Third-party licenses": "Mga lisensya ng third-party", + "Contributors": "Mga nag-ambag", + "Translators": "Mga translator", + "Bundle security report": "Ulat sa seguridad ng bundle", + "The bundle contained restricted content": "Naglaman ang bundle ng pinaghihigpitang nilalaman", + "UniGetUI – Crash Report": "UniGetUI – Ulat ng Pag-crash", + "UniGetUI has crashed": "Nag-crash ang UniGetUI", + "Help us fix this by sending a crash report to Devolutions. All fields below are optional.": "Tulungan kaming ayusin ito sa pamamagitan ng pagpapadala ng crash report sa Devolutions. Opsyonal ang lahat ng mga field sa ibaba.", + "Email (optional)": "Email (opsyonal)", + "your@email.com": "your@email.com", + "Additional details (optional)": "Karagdagang detalye (opsyonal)", + "Describe what you were doing when the crash occurred…": "Ilarawan kung ano ang iyong ginagawa nang nangyari ang pag-crash…", + "Crash report": "Ulat ng pag-crash", + "Don't Send": "Huwag Ipadala", + "Send Report": "Ipadala ang Ulat", + "Sending…": "Ipinapadala…", + "Unsaved changes": "Mga hindi na-save na pagbabago", + "You have unsaved changes in the current bundle. Do you want to discard them?": "May mga hindi na-save na pagbabago sa kasalukuyang bundle. Gusto mo bang huwag i-save ang mga ito?", + "Discard changes": "Huwag i-save ang mga pagbabago", + "Integrity violation": "Paglabag sa integridad", + "UniGetUI or some of its components are missing or corrupt. It is strongly recommended to reinstall UniGetUI to adress the situation.": "Nawawala o sira ang UniGetUI o ilan sa mga component nito. Mahigpit na inirerekomendang i-reinstall ang UniGetUI upang matugunan ang sitwasyon.", + "• Refer to the UniGetUI Logs to get more details regarding the affected file(s)": "• Sumangguni sa mga log ng UniGetUI para sa higit pang detalye tungkol sa (mga) apektadong file", + "• Integrity checks can be disabled from the Experimental Settings": "• Maaaring i-disable ang mga integrity check mula sa Experimental Settings", + "Manage shortcuts": "Pamahalaan ang mga shortcut", + "UniGetUI has detected the following desktop shortcuts which can be removed automatically on future upgrades": "Natukoy ng UniGetUI ang mga sumusunod na desktop shortcut na maaaring awtomatikong alisin sa mga susunod na upgrade", + "Do you really want to reset this list? This action cannot be reverted.": "Sigurado ka bang gusto mong i-reset ang listahang ito? Hindi na ito maaaring ibalik.", + "Desktop shortcuts list": "Listahan ng mga desktop shortcut", + "Open in explorer": "Buksan sa explorer", + "Remove from list": "Alisin sa listahan", + "When new shortcuts are detected, delete them automatically instead of showing this dialog.": "Kapag may natukoy na bagong shortcut, awtomatiko silang burahin sa halip na ipakita ang dialog na ito.", + "Not right now": "Hindi muna ngayon", + "Missing dependency": "Nawawalang dependency", + "UniGetUI requires {0} to operate, but it was not found on your system.": "Kailangan ng UniGetUI ang {0} para gumana, ngunit hindi ito nakita sa iyong system.", + "Click on Install to begin the installation process. If you skip the installation, UniGetUI may not work as expected.": "I-click ang Install para simulan ang proseso ng installation. Kung lalaktawan mo ang installation, maaaring hindi gumana ang UniGetUI gaya ng inaasahan.", + "Alternatively, you can also install {0} by running the following command in a Windows PowerShell prompt:": "Bilang alternatibo, maaari mo ring i-install ang {0} sa pagpapatakbo ng sumusunod na command sa Windows PowerShell prompt:", + "Install {0}": "I-install ang {0}", + "Do not show this dialog again for {0}": "Huwag nang ipakita muli ang dialog na ito para sa {0}", + "Please wait while {0} is being installed. A black window may show up. Please wait until it closes.": "Pakihintay habang ini-install ang {0}. Maaaring may lumitaw na itim na window. Pakihintay hanggang sa magsara ito.", + "{0} has been installed successfully.": "Matagumpay na na-install ang {0}.", + "Please click on \"Continue\" to continue": "Paki-click ang \"Continue\" para magpatuloy", + "Continue": "Magpatuloy", + "{0} has been installed successfully. It is recommended to restart UniGetUI to finish the installation": "Matagumpay na na-install ang {0}. Inirerekomendang i-restart ang UniGetUI para matapos ang installation", + "Restart later": "I-restart mamaya", + "An error occurred:": "Nagkaroon ng kamalian: ", + "Please see the Command-line Output or refer to the Operation History for further information about the issue.": "Pakitingnan ang Command-line Output o sumangguni sa Operation History para sa karagdagang impormasyon tungkol sa isyu.", + "Retry as administrator": "Subukang muli bilang administrator", + "Retry interactively": "Subukang muli nang interactive", + "Retry skipping integrity checks": "Subukang muli habang nilalaktawan ang mga integrity check", + "Installation options": "Mga opsyon sa installation", + "Save": "I-save", + "UniGetUI collects anonymous usage data with the sole purpose of understanding and improving the user experience.": "Nangongolekta ang UniGetUI ng anonymous na data ng paggamit para lamang maunawaan at mapabuti ang karanasan ng user.", + "More details about the shared data and how it will be processed": "Higit pang detalye tungkol sa ibinahaging data at kung paano ito ipoproseso", + "Do you accept that UniGetUI collects and sends anonymous usage statistics, with the sole purpose of understanding and improving the user experience?": "Tinatanggap mo ba na nangongolekta at nagpapadala ang UniGetUI ng anonymous na estadistika ng paggamit, para lamang maunawaan at mapabuti ang karanasan ng user?", + "Decline": "Tanggihan", + "No personal information is collected nor sent, and the collected data is anonimized, so it can't be back-tracked to you.": "Walang personal na impormasyon ang kinokolekta o ipinapadala, at naka-anonymize ang nakolektang data, kaya hindi ito matutunton pabalik sa iyo.", + "Navigation panel": "Panel ng nabigasyon", + "Operations": "Mga Operasyon", + "Toggle operations panel": "Ipakita/itago ang panel ng mga operasyon", + "Bulk operations": "Maramihang operasyon", + "Retry failed": "Subukang muli ang mga pumalya", + "Clear successful": "I-clear ang mga matagumpay", + "Clear finished": "I-clear ang mga natapos", + "Cancel all": "Ikansela lahat", + "More": "Higit pa", + "Toggle navigation panel": "Ipakita/itago ang navigation panel", + "Minimize": "I-minimize", + "Maximize": "I-maximize", + "UniGetUI by Devolutions": "UniGetUI ng Devolutions", + "UniGetUI is an application that makes managing your software easier, by providing an all-in-one graphical interface for your command-line package managers.": "Ang UniGetUI ay isang aplikasyon na nagpapadali sa pamamahala ng iyong software, sa pamamagitan ng pagbibigay ng isahang graphical na interface para sa iyong mga command-line package manager.", + "Useful links": "Mga kapaki-pakinabang na link", + "UniGetUI Homepage": "Homepage ng UniGetUI", + "Report an issue or submit a feature request": "Mag-ulat ng isyu o magsumite ng kahilingan para sa feature", + "UniGetUI Repository": "Repository ng UniGetUI", + "View GitHub Profile": "Tingnan ang Profile sa GitHub", + "UniGetUI License": "Lisensya ng UniGetUI", + "Using UniGetUI implies the acceptation of the MIT License": "Ang paggamit ng UniGetUI ay nagpapahiwatig ng pagtanggap ng MIT License", + "Become a translator": "Maging translator", + "Go back": "Bumalik", + "Go forward": "Sumulong", + "Go to home page": "Pumunta sa pangunahing pahina", + "Reload page": "I-reload ang pahina", + "View page on browser": "Tingnan ang pahina sa browser", + "The built-in browser is not supported on Linux yet.": "Hindi pa sinusuportahan ang built-in na browser sa Linux.", + "Open in browser": "Buksan sa browser", + "Copy to clipboard": "Kopyahin patungo sa clipboard", + "Export to a file": "I-export sa isang file", + "Log level:": "Antas ng log:", + "Reload log": "I-reload ang log", + "Export log": "I-export ang log", + "Text": "Teksto", + "Change how operations request administrator rights": "Baguhin kung paano humihingi ng mga karapatan ng administrator ang mga operasyon", + "Restrictions on package operations": "Mga restriksyon sa mga operasyon ng package", + "Restrictions on package managers": "Mga restriksyon sa mga package manager", + "Restrictions when importing package bundles": "Mga restriksyon kapag nag-i-import ng mga package bundle", + "Ask for administrator privileges once for each batch of operations": "Humingi ng mga pribilehiyo ng administrator isang beses para sa bawat batch ng mga operasyon", + "Ask only once for administrator privileges": "Humingi ng mga pribilehiyo ng administrator nang isang beses lang", + "Prohibit any kind of Elevation via UniGetUI Elevator or GSudo": "Ipagbawal ang anumang uri ng elevation sa pamamagitan ng UniGetUI Elevator o GSudo", + "This option WILL cause issues. Any operation incapable of elevating itself WILL FAIL. Install/update/uninstall as administrator will NOT WORK.": "MAGDUDULOT ng mga isyu ang opsyong ito. PUMAPALYA ang anumang operasyong hindi kayang i-elevate ang sarili. HINDI GAGANA ang install/update/uninstall bilang administrator.", + "Allow custom command-line arguments": "Payagan ang mga custom na argument sa command-line", + "Custom command-line arguments can change the way in which programs are installed, upgraded or uninstalled, in a way UniGetUI cannot control. Using custom command-lines can break packages. Proceed with caution.": "Maaaring baguhin ng mga custom na argument sa command-line ang paraan ng pag-install, pag-upgrade, o pag-uninstall ng mga programa sa paraang hindi makokontrol ng UniGetUI. Maaaring makasira ng mga package ang paggamit ng mga custom na command-line. Magpatuloy nang may pag-iingat.", + "Ignore custom pre-install and post-install commands when importing packages from a bundle": "Huwag pansinin ang mga custom na pre-install at post-install command kapag nag-i-import ng mga package mula sa bundle", + "Pre and post install commands will be run before and after a package gets installed, upgraded or uninstalled. Be aware that they may break things unless used carefully": "Patatakbuhin ang mga pre at post install command bago at pagkatapos ma-install, ma-upgrade, o ma-uninstall ang isang package. Tandaan na maaari silang makasira ng mga bagay kung hindi gagamitin nang maingat.", + "Allow changing the paths for package manager executables": "Payagan ang pagbabago ng mga path para sa mga executable ng package manager", + "Turning this on enables changing the executable file used to interact with package managers. While this allows finer-grained customization of your install processes, it may also be dangerous": "Kapag in-on ito, mapapagana ang pagbabago ng executable file na ginagamit para makipag-ugnayan sa mga package manager. Bagama't nagbibigay ito ng mas detalyadong pag-customize sa iyong mga proseso ng install, maaari rin itong maging mapanganib.", + "Allow importing custom command-line arguments when importing packages from a bundle": "Payagan ang pag-import ng mga custom na argument sa command-line kapag nag-i-import ng mga package mula sa bundle", + "Malformed command-line arguments can break packages, or even allow a malicious actor to gain privileged execution. Therefore, importing custom command-line arguments is disabled by default": "Maaaring makasira ng mga package ang maling anyo ng mga argument sa command-line, o magbigay pa ng privileged execution sa isang mapaminsalang aktor. Kaya naka-disable bilang default ang pag-import ng mga custom na argument sa command-line.", + "Allow importing custom pre-install and post-install commands when importing packages from a bundle": "Payagan ang pag-import ng mga custom na pre-install at post-install command kapag nag-i-import ng mga package mula sa bundle", + "Pre and post install commands can do very nasty things to your device, if designed to do so. It can be very dangerous to import the commands from a bundle, unless you trust the source of that package bundle": "Maaaring gumawa ng napakasamang bagay sa iyong device ang mga pre at post install command kung ganoon ang pagkakadisenyo sa mga ito. Maaaring maging lubhang mapanganib ang pag-import ng mga command mula sa bundle, maliban kung pinagkakatiwalaan mo ang pinagmulan ng package bundle na iyon.", + "Administrator rights and other dangerous settings": "Mga karapatan ng administrator at iba pang mapanganib na setting", + "Package backup": "Backup ng package", + "Cloud package backup": "Cloud backup ng package", + "Local package backup": "Lokal na backup ng package", + "Local backup advanced options": "Mga advanced na opsyon sa lokal na backup", + "Log in with GitHub": "Mag-log in gamit ang GitHub", + "Log out from GitHub": "Mag-log out mula sa GitHub", + "Periodically perform a cloud backup of the installed packages": "Pana-panahong magsagawa ng cloud backup ng mga naka-install na package", + "Cloud backup uses a private GitHub Gist to store a list of installed packages": "Gumagamit ang cloud backup ng pribadong GitHub Gist para itago ang listahan ng mga naka-install na package", + "Perform a cloud backup now": "Magsagawa ng cloud backup ngayon", + "Backup": "Pag-backup", + "Restore a backup from the cloud": "I-restore ang backup mula sa cloud", + "Begin the process to select a cloud backup and review which packages to restore": "Simulan ang proseso para pumili ng cloud backup at suriin kung aling mga package ang ire-restore", + "Periodically perform a local backup of the installed packages": "Pana-panahong magsagawa ng lokal na backup ng mga naka-install na package", + "Perform a local backup now": "Magsagawa ng lokal na backup ngayon", + "Change backup output directory": "Baguhin ang output directory ng backup", + "Set a custom backup file name": "Magtakda ng custom na pangalan ng backup file", + "Leave empty for default": "Iwanang walang laman para sa default", + "Add a timestamp to the backup file names": "Idagdag ang oras sa backup ng mga pangalan ", + "Backup and Restore": "Backup at Restore", + "Enable background api (UniGetUI Widgets and Sharing, port 7058)": "Paganahin ang background API (Mga Widget para sa UniGetUI at Pagbabahagi, port 7058)", + "Wait for the device to be connected to the internet before attempting to do tasks that require internet connectivity.": "Hintaying kumonekta ang device sa internet bago subukang gawin ang mga gawaing nangangailangan ng koneksyon sa internet.", + "Disable the 1-minute timeout for package-related operations": "I-disable ang 1-minutong timeout para sa mga operasyong may kaugnayan sa package", + "Use installed GSudo instead of UniGetUI Elevator": "Gamitin ang naka-install na GSudo sa halip na UniGetUI Elevator", + "Use a custom icon and screenshot database URL": "Gumamit ng custom na URL para sa database ng icon at screenshot", + "Enable background CPU Usage optimizations (see Pull Request #3278)": "Paganahin ang mga optimization sa paggamit ng CPU sa background (tingnan ang Pull Request #3278)", + "Perform integrity checks at startup": "Magsagawa ng mga integrity check sa startup", + "When batch installing packages from a bundle, install also packages that are already installed": "Kapag nagba-batch install ng mga package mula sa bundle, i-install din ang mga package na naka-install na", + "Experimental settings and developer options": "Mga experimental na setting at opsyon para sa developer", + "Show UniGetUI's version and build number on the titlebar.": "Ipakita ang bersyon at build number ng UniGetUI sa titlebar.", + "Language": "Wika", + "UniGetUI updater": "Updater ng UniGetUI", + "Telemetry": "Telemetriya", + "Manage UniGetUI settings": "Pamahalaan ang mga setting ng UniGetUI", + "Related settings": "Mga kaugnay na setting", + "Update UniGetUI automatically": "Awtomatikong i-update ang UniGetUI", + "Check for updates": "Maghanap ng mga update", + "Install prerelease versions of UniGetUI": "I-install ang mga prerelease na bersyon ng UniGetUI", + "Manage telemetry settings": "Pamahalaan ang mga setting ng telemetry", + "Manage": "Pamahalaan", + "Import settings from a local file": "I-import ang mga setting mula sa isang lokal na file", + "Import": "I-import", + "Export settings to a local file": "I-export ang mga setting sa isang lokal na file", + "Export": "I-export", + "Reset UniGetUI": "I-reset ang UniGetUI", + "User interface preferences": "Mga preference sa user interface", + "Application theme, startup page, package icons, clear successful installs automatically": "Tema ng app, startup page, mga icon ng package, awtomatikong alisin ang matagumpay na install", + "General preferences": "Mga pangkalahatang preference", + "UniGetUI display language:": "Ipinapakitang wika ng UniGetUI:", + "System language": "Wika ng sistema", + "Is your language missing or incomplete?": "Nawawala o kulang ba ang iyong wika?", + "Appearance": "Itsura", + "UniGetUI on the background and system tray": "UniGetUI sa background at system tray", + "Package lists": "Mga listahan ng package", + "Use classic mode": "Gamitin ang classic mode", + "Restart UniGetUI to apply this change": "I-restart ang UniGetUI upang mailapat ang pagbabagong ito", + "The classic UI is disabled for beta testers": "Hindi pinagana ang klasikong UI para sa mga beta tester", + "Close UniGetUI to the system tray": "Isara ang UniGetUI sa system tray", + "Manage UniGetUI autostart behaviour": "Pamahalaan ang awtomatikong pagsisimula ng UniGetUI", + "Show package icons on package lists": "Ipakita ang mga icon ng package sa mga listahan ng package", + "Clear cache": "I-clear ang cache", + "Select upgradable packages by default": "Piliin bilang default ang mga package na maaaring i-upgrade", + "Light": "Maliwanag", + "Dark": "Madilim", + "Follow system color scheme": "Sundin ang color scheme ng system", + "Application theme:": "Tema ng aplikasyon:", + "UniGetUI startup page:": "Startup page ng UniGetUI:", + "Proxy settings": "Mga setting ng proxy", + "Other settings": "Iba pang setting", + "Connect the internet using a custom proxy": "Kumonekta sa internet gamit ang custom na proxy", + "Please note that not all package managers may fully support this feature": "Pakitandaan na hindi lahat ng package manager ay maaaring lubos na sumuporta sa feature na ito", + "Proxy URL": "URL ng proxy", + "Enter proxy URL here": "Ilagay dito ang proxy URL", + "Authenticate to the proxy with a user and a password": "Mag-authenticate sa proxy gamit ang user at password", + "Internet and proxy settings": "Mga setting ng internet at proxy", + "Package manager preferences": "Mga preference sa package manager", + "Ready": "Handa na", + "Not found": "Hindi nakita", + "Notification preferences": "Mga preference sa notification", + "Notification types": "Mga uri ng notification", + "The system tray icon must be enabled in order for notifications to work": "Dapat naka-enable ang icon sa system tray para gumana ang mga notification", + "Enable UniGetUI notifications": "Paganahin ang mga notification ng UniGetUI", + "Show a notification when there are available updates": "Magpakita ng notification kapag may mga available na update", + "Show a silent notification when an operation is running": "Magpakita ng tahimik na notification habang may tumatakbong operasyon", + "Show a notification when an operation fails": "Magpakita ng notification kapag pumalya ang isang operasyon", + "Show a notification when an operation finishes successfully": "Magpakita ng notification kapag matagumpay na natapos ang isang operasyon", + "Concurrency and execution": "Concurrency at execution", + "Automatic desktop shortcut remover": "Awtomatikong tagabura ng desktop shortcut", + "Choose how many operations should be performed in parallel": "Piliin kung ilang operasyon ang dapat isagawa nang sabay-sabay", + "Clear successful operations from the operation list after a 5 second delay": "Alisin ang matagumpay na mga operasyon mula sa listahan matapos ang 5 segundong delay", + "Download operations are not affected by this setting": "Hindi naaapektuhan ng setting na ito ang mga operasyon sa pag-download", + "You may lose unsaved data": "Maaaring mawala ang hindi pa nasasave na data", + "Ask to delete desktop shortcuts created during an install or upgrade.": "Magtanong bago burahin ang mga desktop shortcut na nalikha sa panahon ng install o upgrade.", + "Package update preferences": "Mga preference sa update ng package", + "Update check frequency, automatically install updates, etc.": "Dalas ng pagsusuri ng update, awtomatikong pag-install ng mga update, at iba pa.", + "Reduce UAC prompts, elevate installations by default, unlock certain dangerous features, etc.": "Bawasan ang mga UAC prompt, i-elevate ang mga installation bilang default, i-unlock ang ilang mapanganib na feature, at iba pa.", + "Package operation preferences": "Mga preference sa operasyon ng package", + "Enable {pm}": "Buksan ang {pm}", + "Not finding the file you are looking for? Make sure it has been added to path.": "Hindi makita ang file na hinahanap mo? Tiyaking nadagdag na ito sa path.", + "Select the executable to be used. The following list shows the executables found by UniGetUI": "Piliin ang executable na gagamitin. Ipinapakita ng sumusunod na listahan ang mga executable na nakita ng UniGetUI", + "For security reasons, changing the executable file is disabled by default": "Dahil sa seguridad, naka-disable bilang default ang pagbabago ng executable file", + "Change this": "Baguhin ito", + "Copy path": "Kopyahin ang path", + "Current executable file:": "Kasalukuyang executable file:", + "Ignore packages from {pm} when showing a notification about updates": "I-ignore ang mga package mula sa {pm} kapag nagpapakita ng notification tungkol sa mga update", + "Update security": "Seguridad sa pag-update", + "Use global setting": "Gamitin ang global na setting", + "Minimum age for updates": "Minimum na tagal para sa mga update", + "e.g. 10": "hal. 10", + "Custom minimum age (days)": "Custom na minimum na tagal (araw)", + "{pm} does not provide release dates for its packages, so this setting will have no effect": "Hindi nagbibigay ang {pm} ng mga petsa ng release para sa mga package nito, kaya walang epekto ang setting na ito", + "{pm} only provides release dates for some of its packages, so this setting will only apply to those packages": "Ang {pm} ay nagbibigay lamang ng petsa ng paglabas para sa ilan sa mga pakete nito, kaya ang setting na ito ay aaplay lamang sa mga pakete na iyon", + "Override the global minimum update age for this package manager": "I-override ang global na minimum na tagal ng update para sa package manager na ito", + "View {0} logs": "Tingnan ang mga log ng {0}", + "If Python cannot be found or is not listing packages but is installed on the system, ": "Kung hindi mahanap ang Python o hindi nito naililista ang mga package ngunit naka-install ito sa system, ", + "Advanced options": "Mga advanced na opsyon", + "WinGet command-line tool": "Command-line tool ng WinGet", + "Choose which command-line tool UniGetUI uses for WinGet operations when the COM API is not used": "Piliin kung aling command-line tool ang gagamitin ng UniGetUI para sa mga operasyon ng WinGet kapag hindi ginagamit ang COM API", + "WinGet COM API": "WinGet COM API", + "Choose whether UniGetUI can use the WinGet COM API before falling back to the command-line tool": "Piliin kung maaaring gamitin ng UniGetUI ang WinGet COM API bago bumalik sa command-line tool", + "Reset WinGet": "I-reset ang WinGet", + "This may help if no packages are listed": "Maaaring makatulong ito kung walang nakalistang mga package", + "Force install location parameter when updating packages with custom locations": "Pilitin ang parameter ng lokasyon ng install kapag nag-a-update ng mga package na may custom na lokasyon", + "Install Scoop": "I-install ang Scoop", + "Uninstall Scoop (and its packages)": "I-uninstall ang Scoop (at ang mga package nito)", + "Run cleanup and clear cache": "Patakbuhin ang cleanup at i-clear ang cache", + "Run": "Patakbuhin", + "Enable Scoop cleanup on launch": "Paganahin ang Scoop cleanup sa pag-launch", + "Default vcpkg triplet": "Default na vcpkg triplet", + "Change vcpkg root location": "Baguhin ang root na lokasyon ng vcpkg", + "Reset vcpkg root location": "I-reset ang lokasyon ng vcpkg root", + "Open vcpkg root location": "Buksan ang lokasyon ng vcpkg root", + "Language, theme and other miscellaneous preferences": "Wika, tema, at iba pang sari-saring preference", + "Show notifications on different events": "Ipakita ang mga notification sa iba't ibang pangyayari", + "Change how UniGetUI checks and installs available updates for your packages": "Baguhin kung paano sinusuri at ini-install ng UniGetUI ang mga available na update para sa iyong mga package", + "Automatically save a list of all your installed packages to easily restore them.": "Awtomatikong i-save ang listahan ng lahat ng naka-install mong package para madali silang ma-restore.", + "Enable and disable package managers, change default install options, etc.": "Paganahin at i-disable ang mga package manager, baguhin ang mga default na opsyon sa install, at iba pa.", + "Internet connection settings": "Mga setting ng koneksyon sa internet", + "Proxy settings, etc.": "Mga setting ng proxy, atbp.", + "Beta features and other options that shouldn't be touched": "Ibang mga bagay na di dapat baguhin gaya ng beta features", + "Reload sources": "I-reload ang mga source", + "Delete source": "Burahin ang source", + "Known sources": "Mga kilalang source", + "Update checking": "Pagsusuri ng update", + "Automatic updates": "Awtomatikong mga update", + "Check for package updates periodically": "Hanapin ang mga bagong updates ng mga package kada panahon", + "Check for updates every:": "Maghanap ng mga bagong updates ng mga package tuwing:", + "Install available updates automatically": "Awtomatikong i-install ang mga available na update", + "Do not automatically install updates when the network connection is metered": "Huwag awtomatikong mag-install ng mga update kapag metered ang koneksyon sa network", + "Do not automatically install updates when the device runs on battery": "Huwag awtomatikong mag-install ng mga update kapag naka-battery ang device", + "Do not automatically install updates when the battery saver is on": "Huwag awtomatikong mag-install ng mga update kapag naka-on ang battery saver", + "Only show updates that are at least the specified number of days old": "Ipakita lamang ang mga update na hindi bababa sa tinukoy na bilang ng araw na ang nakalipas", + "Warn me when the installer URL host changes between the installed version and the new version (WinGet only)": "Babalaan ako kapag nagbago ang host ng URL ng installer sa pagitan ng naka-install na bersyon at ng bagong bersyon (WinGet lang)", + "Change how UniGetUI handles install, update and uninstall operations.": "Baguhin kung paano pinangangasiwaan ng UniGetUI ang mga operasyon ng install, update, at uninstall.", + "Navigation": "Nabigasyon", + "Check for UniGetUI updates": "Maghanap ng mga update para sa UniGetUI", + "Quit UniGetUI": "Lumabas sa UniGetUI", + "Filters": "Mga filter", + "Sources": "Mga source", + "Search for packages to start": "Maghanap ng mga package para makapagsimula", + "Select all": "Piliin lahat", + "Clear selection": "Alisin ang pinili", + "Instant search": "Agarang paghahanap", + "Distinguish between uppercase and lowercase": "Pag-ibahin ang malalaking titik at maliliit na titik", + "Ignore special characters": "I-ignore ang mga espesyal na character", + "Search mode": "Mode ng paghahanap", + "Both": "Pareho", + "Exact match": "Eksaktong tugma", + "Show similar packages": "Ipakita ang mga kahalintulad na package", + "Loading": "Nilo-load", + "Package": "Pakete", + "More options": "Higit pang opsyon", + "Order by:": "Ayusin ayon sa:", + "Name": "Pangalan", + "Id": "Pagkakakilanlan", + "Ascendant": "Paakyat", + "Descendant": "Pababa", + "View modes": "Mga mode ng view", + "Reload": "I-reload", + "Closed": "Sarado", + "Ascending": "Pataas", + "Descending": "Pababa", + "{0}: {1}, {2}": "{0}: {1}, {2}", + "Order by": "Ayusin ayon sa", + "No results were found matching the input criteria": "Walang nahanap na resultang tumutugma sa ibinigay na pamantayan", + "No packages were found": "Walang nahanap na mga package", + "Loading packages": "Nilo-load ang mga package", + "Skip integrity checks": "Laktawan ang mga integrity check", + "Download selected installers": "I-download ang mga napiling installer", + "Install selection": "I-install ang napili", + "Install options": "Mga opsyon sa install", + "Add selection to bundle": "Idagdag ang napili sa bundle", + "Download installer": "I-download ang installer", + "Uninstall selection": "I-uninstall ang napili", + "Uninstall options": "Mga opsyon sa uninstall", + "Ignore selected packages": "I-ignore ang mga napiling package", + "Open install location": "Buksan ang lokasyon ng install", + "Reinstall package": "I-reinstall ang package", + "Uninstall package, then reinstall it": "I-uninstall ang package, saka i-reinstall ito", + "Ignore updates for this package": "I-ignore ang mga update para sa package na ito", + "WinGet malfunction detected": "Natukoy ang hindi paggana ng WinGet", + "It looks like WinGet is not working properly. Do you want to attempt to repair WinGet?": "Mukhang hindi gumagana nang maayos ang WinGet. Gusto mo bang subukang ayusin ang WinGet?", + "Repair WinGet": "Ayusin ang WinGet", + "Updates will no longer be ignored for {0}": "Hindi na ibabalewala ang mga update para sa {0}", + "Updates are now ignored for {0}": "Binabalewala na ngayon ang mga update para sa {0}", + "Do not ignore updates for this package anymore": "Huwag nang i-ignore ang mga update para sa package na ito", + "Add packages or open an existing package bundle": "Magdagdag ng mga package o magbukas ng umiiral na package bundle", + "Add packages to start": "Magdagdag ng mga package para makapagsimula", + "The current bundle has no packages. Add some packages to get started": "Walang package ang kasalukuyang bundle. Magdagdag ng ilang package para makapagsimula", + "New": "Bago", + "Save as": "I-save bilang", + "Create .ps1 script": "Gumawa ng .ps1 script", + "Remove selection from bundle": "Alisin ang napili mula sa bundle", + "Skip hash checks": "Laktawan ang mga hash check", + "The package bundle is not valid": "Hindi valid ang package bundle", + "The bundle you are trying to load appears to be invalid. Please check the file and try again.": "Mukhang hindi valid ang bundle na sinusubukan mong i-load. Pakisuri ang file at subukan muli.", + "Package bundle": "Bundle ng pakete", + "Could not create bundle": "Hindi magawa ang bundle", + "The package bundle could not be created due to an error.": "Hindi nagawa ang package bundle dahil sa isang error.", + "Install script": "Script sa install", + "PowerShell script": "Script ng PowerShell", + "The installation script saved to {0}": "Naisave ang installation script sa {0}", + "An error occurred": "Nagkaroon ng kamalian", + "An error occurred while attempting to create an installation script:": "Nagkaroon ng error habang sinusubukang gumawa ng installation script:", + "Hooray! No updates were found.": "Yehey! Walang nahanap na update.", + "Uninstall selected packages": "I-uninstall ang mga napiling package", + "Update selection": "I-update ang napili", + "Update options": "Mga opsyon sa update", + "Uninstall package, then update it": "I-uninstall ang package, saka i-update ito", + "Uninstall package": "I-uninstall ang package", + "Skip this version": "Laktawan ang bersyong ito", + "Pause updates for": "I-pause ang mga update sa loob ng", + "User | Local": "User | Lokal", + "Machine | Global": "Machine | Global", + "The default package manager for Debian/Ubuntu-based Linux distributions.
Contains: Debian/Ubuntu packages": "Ang default na package manager para sa mga distribusyon ng Linux na nakabatay sa Debian/Ubuntu.
Naglalaman ng: mga package ng Debian/Ubuntu", + "The Rust package manager.
Contains: Rust libraries and programs written in Rust": "Package manager ng Rust.
Naglalaman ng: Mga Rust library at programang isinulat sa Rust", + "The classical package manager for windows. You'll find everything there.
Contains: General Software": "Ang klasikong package manager para sa Windows. Makikita mo roon ang lahat.
Naglalaman ng: Pangkalahatang Software", + "The default package manager for RHEL/Fedora-based Linux distributions.
Contains: RPM packages": "Ang default na package manager para sa mga distribusyon ng Linux na nakabatay sa RHEL/Fedora.
Naglalaman ng: mga RPM package", + "A repository full of tools and executables designed with Microsoft's .NET ecosystem in mind.
Contains: .NET related tools and scripts": "Isang repository na puno ng mga tool at executable na idinisenyo para sa .NET ecosystem ng Microsoft.
Naglalaman ng: Mga tool at script na may kaugnayan sa .NET", + "The universal Linux package manager for desktop applications.
Contains: Flatpak applications from configured remotes": "Ang universal Linux package manager para sa mga desktop application.
Naglalaman ng: Mga Flatpak application mula sa mga naka-configure na remote", + "NuPkg (zipped manifest)": "NuPkg (naka-zip na manifest)", + "The Missing Package Manager for macOS (or Linux).
Contains: Formulae, Casks": "Ang Nawawalang Package Manager para sa macOS (o Linux).
Naglalaman ng: Formulae, Casks", + "Node JS's package manager. Full of libraries and other utilities that orbit the javascript world
Contains: Node javascript libraries and other related utilities": "Package manager ng Node JS. Puno ito ng mga library at iba pang utility na umiikot sa mundo ng JavaScript
Naglalaman ng: Mga Node JavaScript library at iba pang kaugnay na utility", + "The default package manager for Arch Linux and its derivatives.
Contains: Arch Linux packages": "Ang default na package manager para sa Arch Linux at mga derivative nito.
Naglalaman ng: mga package ng Arch Linux", + "Python's library manager. Full of python libraries and other python-related utilities
Contains: Python libraries and related utilities": "Library manager ng Python. Puno ito ng mga Python library at iba pang utility na may kaugnayan sa Python
Naglalaman ng: Mga Python library at kaugnay na utility", + "PowerShell's package manager. Find libraries and scripts to expand PowerShell capabilities
Contains: Modules, Scripts, Cmdlets": "Package manager ng PowerShell. Maghanap ng mga library at script para mapalawak ang kakayahan ng PowerShell
Naglalaman ng: Mga module, script, cmdlet", + "extracted": "na-extract", + "Scoop package": "Package ng Scoop", + "Great repository of unknown but useful utilities and other interesting packages.
Contains: Utilities, Command-line programs, General Software (extras bucket required)": "Napakagandang repository ng mga hindi gaanong kilala ngunit kapaki-pakinabang na utility at iba pang interesanteng package.
Naglalaman ng: Mga utility, command-line program, pangkalahatang software (kailangan ang extras bucket)", + "The universal Linux package manager by Canonical.
Contains: Snap packages from the Snapcraft store": "Ang pangkalahatang Linux package manager mula sa Canonical.
Naglalaman ng: Mga Snap package mula sa Snapcraft store", + "library": "aklatan ng software", + "feature": "tampok", + "A popular C/C++ library manager. Full of C/C++ libraries and other C/C++-related utilities
Contains: C/C++ libraries and related utilities": "Isang sikat na C/C++ library manager. Puno ito ng mga C/C++ library at iba pang utility na may kaugnayan sa C/C++
Naglalaman ng: Mga C/C++ library at kaugnay na utility", + "option": "opsyon", + "This package cannot be installed from an elevated context.": "Hindi maaaring i-install ang package na ito mula sa elevated na context.", + "Please run UniGetUI as a regular user and try again.": "Pakipatbong muli ang UniGetUI bilang regular na user at subukan ulit.", + "Please check the installation options for this package and try again": "Pakisuri ang mga opsyon sa installation para sa package na ito at subukan muli", + "Microsoft's official package manager. Full of well-known and verified packages
Contains: General Software, Microsoft Store apps": "Opisyal na package manager ng Microsoft. Puno ito ng mga kilala at beripikadong package
Naglalaman ng: Pangkalahatang software, mga app mula sa Microsoft Store", + "Local PC": "Lokal na PC", + "Android Subsystem": "Subsystem ng Android", + "Operation on queue (position {0})...": "Operasyon sa pila (posisyon {0})...", + "Click here for more details": "I-click dito para sa higit pang detalye", + "Operation canceled by user": "Kinansela ng user ang operasyon", + "Running PreOperation ({0}/{1})...": "Pinapatakbo ang PreOperation ({0}/{1})...", + "PreOperation {0} out of {1} failed, and was tagged as necessary. Aborting...": "Nabigo ang PreOperation {0} sa {1}, at minarkahang kinakailangan. Ina-abort...", + "PreOperation {0} out of {1} finished with result {2}": "Natapos ang PreOperation {0} sa {1} na may resultang {2}", + "Starting operation...": "Sinisimulan ang operasyon...", + "Running PostOperation ({0}/{1})...": "Pinapatakbo ang PostOperation ({0}/{1})...", + "PostOperation {0} out of {1} failed, and was tagged as necessary. Aborting...": "Nabigo ang PostOperation {0} sa {1}, at minarkahang kinakailangan. Ina-abort...", + "PostOperation {0} out of {1} finished with result {2}": "Natapos ang PostOperation {0} sa {1} na may resultang {2}", + "{package} installer download": "Pag-download ng installer ng {package}", + "{0} installer is being downloaded": "Dina-download ang installer ng {0}", + "Download succeeded": "Matagumpay ang pag-download", + "{package} installer was downloaded successfully": "Matagumpay na na-download ang installer ng {package}", + "Download failed": "Pumalya ang pag-download", + "{package} installer could not be downloaded": "Hindi ma-download ang installer ng {package}", + "{package} Installation": "Installation ng {package}", + "{0} is being installed": "Ini-install ang {0}", + "Installation succeeded": "Matagumpay ang installation", + "{package} was installed successfully": "Matagumpay na na-install ang {package}", + "Installation failed": "Pumalya ang installation", + "{package} could not be installed": "Hindi ma-install ang {package}", + "{package} Update": "Update ng {package}", + "Update succeeded": "Matagumpay ang update", + "{package} was updated successfully": "Matagumpay na na-update ang {package}", + "Update failed": "Pumalya ang update", + "{package} could not be updated": "Hindi ma-update ang {package}", + "{package} Uninstall": "Uninstall ng {package}", + "{0} is being uninstalled": "Ina-uninstall ang {0}", + "Uninstall succeeded": "Matagumpay ang uninstall", + "{package} was uninstalled successfully": "Matagumpay na na-uninstall ang {package}", + "Uninstall failed": "Pumalya ang uninstall", + "{package} could not be uninstalled": "Hindi ma-uninstall ang {package}", + "Adding source {source}": "Idinadagdag na ang {source}", + "Adding source {source} to {manager}": "Idinadagdag ang {source} sa {manager}", + "Source added successfully": "Matagumpay na naidagdag ang source", + "The source {source} was added to {manager} successfully": "Matagumpay na naidagdag ang source na {source} sa {manager}", + "Could not add source": "Hindi maidagdag ang source", + "Could not add source {source} to {manager}": "Hindi maidagdag ang {source} sa {manager}", + "Removing source {source}": "Inaalis na ang {source}", + "Removing source {source} from {manager}": "Inaalis ang {source} mula sa {manager}", + "Source removed successfully": "Matagumpay na naalis ang source", + "The source {source} was removed from {manager} successfully": "Matagumpay na naalis ang source na {source} mula sa {manager}", + "Could not remove source": "Hindi maalis ang source", + "Could not remove source {source} from {manager}": "Hindi maalis ang {source} mula sa {manager}", + "The package manager \"{0}\" was not found": "Hindi nakita ang package manager na \"{0}\"", + "The package manager \"{0}\" is disabled": "Naka-disable ang package manager na \"{0}\"", + "There is an error with the configuration of the package manager \"{0}\"": "May error sa configuration ng package manager na \"{0}\"", + "The package \"{0}\" was not found on the package manager \"{1}\"": "Hindi nakita ang package na \"{0}\" sa package manager na \"{1}\"", + "{0} is disabled": "{0} ay nakasara", + "{0} weeks": "{0} linggo", + "1 month": "1 buwan", + "{0} months": "{0} buwan", + "Something went wrong": "May nangyaring mali", + "An interal error occurred. Please view the log for further details.": "May panloob na error na nangyari. Pakitingnan ang log para sa higit pang detalye.", + "No applicable installer was found for the package {0}": "Walang nahanap na naaangkop na installer para sa package na {0}", + "Integrity checks will not be performed during this operation": "Hindi isasagawa ang mga integrity check sa operasyong ito", + "This is not recommended.": "Hindi ito inirerekomenda.", + "Run now": "Patakbuhin ngayon", + "Run next": "Patakbuhin nang sunod", + "Run last": "Patakbuhin nang huli", + "Show in explorer": "Ipakita sa explorer", + "Checked": "Naka-check", + "Unchecked": "Hindi naka-check", + "This package is already installed": "Naka-install na ang package na ito", + "This package can be upgraded to version {0}": "Maaaring i-upgrade ang package na ito sa bersyon {0}", + "Updates for this package are ignored": "In-ignore ang mga update para sa package na ito", + "This package is being processed": "Pinoproseso ang package na ito", + "This package is not available": "Hindi available ang package na ito", + "Select the source you want to add:": "Piliin ang source na gusto mong idagdag:", + "Source name:": "Pangalan ng source:", + "Source URL:": "URL ng source:", + "An error occurred when adding the source: ": "Nagkaroon ng pagkakamali sa pagdagdag ng source:", + "Package management made easy": "Pinadaling pamamahala ng package", + "version {0}": "bersyon {0}", + "[RAN AS ADMINISTRATOR]": "[PINATAKBO BILANG ADMINISTRATOR]", + "Portable mode": "Portable na mode\n", + "DEBUG BUILD": "Pang-debug na build", + "Here you can change UniGetUI's behaviour regarding the following shortcuts. Checking a shortcut will make UniGetUI delete it if if gets created on a future upgrade. Unchecking it will keep the shortcut intact": "Dito mo mababago ang kilos ng UniGetUI para sa mga sumusunod na shortcut. Kapag chineck mo ang isang shortcut, buburahin ito ng UniGetUI kung malikha ito sa susunod na upgrade. Kapag inalis mo ang check, mananatiling buo ang shortcut.", + "Manual scan": "Manwal na pag-scan", + "Existing shortcuts on your desktop will be scanned, and you will need to pick which ones to keep and which ones to remove.": "Isi-scan ang mga umiiral na shortcut sa iyong desktop, at kailangan mong pumili kung alin ang itatago at alin ang aalisin.", + "Delete?": "Burahin?", + "I understand": "Nauunawaan ko", + "Chocolatey setup changed": "Nagbago ang setup ng Chocolatey", + "UniGetUI no longer includes its own private Chocolatey installation. A legacy UniGetUI-managed Chocolatey installation was detected for this user profile, but system Chocolatey was not found. Chocolatey will stay unavailable in UniGetUI until Chocolatey is installed on the system and UniGetUI is restarted. Applications previously installed through UniGetUI's bundled Chocolatey may still appear under other sources such as Local PC or WinGet.": "Hindi na kasama sa UniGetUI ang sarili nitong pribadong installation ng Chocolatey. May natukoy na lumang installation ng Chocolatey na pinamamahalaan ng UniGetUI para sa user profile na ito, ngunit hindi nahanap ang system Chocolatey. Mananatiling hindi available ang Chocolatey sa UniGetUI hanggang sa ma-install ang Chocolatey sa system at ma-restart ang UniGetUI. Ang mga application na dating na-install sa pamamagitan ng kasamang Chocolatey ng UniGetUI ay maaari pa ring lumabas sa ibang mga source tulad ng Local PC o WinGet.", + "NOTE: This troubleshooter can be disabled from UniGetUI Settings, on the WinGet section": "PAALALA: Maaaring i-disable ang troubleshooter na ito mula sa UniGetUI Settings, sa seksyong WinGet", + "Restart": "I-restart", + "Are you sure you want to delete all shortcuts?": "Sigurado ka bang gusto mong burahin ang lahat ng shortcut?", + "Any new shorcuts created during an install or an update operation will be deleted automatically, instead of showing a confirmation prompt the first time they are detected.": "Anumang bagong shortcut na malilikha sa panahon ng install o update ay awtomatikong buburahin, sa halip na magpakita ng confirmation prompt sa unang beses na matukoy ang mga ito.", + "Any shorcuts created or modified outside of UniGetUI will be ignored. You will be able to add them via the {0} button.": "Anumang shortcut na ginawa o binago sa labas ng UniGetUI ay hindi papansinin. Magagawa mo pa rin silang idagdag sa pamamagitan ng button na {0}.", + "Are you really sure you want to enable this feature?": "Sigurado ka ba talaga na gusto mong paganahin ang feature na ito?", + "No new shortcuts were found during the scan.": "Walang nahanap na bagong shortcut sa panahon ng pag-scan.", + "How to add packages to a bundle": "Paano magdagdag ng mga package sa isang bundle", + "In order to add packages to a bundle, you will need to: ": "Para makapagdagdag ng mga package sa bundle, kailangan mong: ", + "1. Navigate to the \"{0}\" or \"{1}\" page.": "1. Pumunta sa pahinang \"{0}\" o \"{1}\".", + "2. Locate the package(s) you want to add to the bundle, and select their leftmost checkbox.": "2. Hanapin ang mga package na gusto mong idagdag sa bundle, at piliin ang pinakakaliwang checkbox ng mga ito.", + "3. When the packages you want to add to the bundle are selected, find and click the option \"{0}\" on the toolbar.": "3. Kapag napili na ang mga package na gusto mong idagdag sa bundle, hanapin at i-click ang opsyong \"{0}\" sa toolbar.", + "4. Your packages will have been added to the bundle. You can continue adding packages, or export the bundle.": "4. Naidagdag na ang mga package mo sa bundle. Maaari kang magpatuloy sa pagdagdag ng mga package o i-export ang bundle.", + "Which backup do you want to open?": "Aling backup ang gusto mong buksan?", + "Select the backup you want to open. Later, you will be able to review which packages you want to install.": "Piliin ang backup na gusto mong buksan. Mamaya, masusuri mo kung aling mga package ang gusto mong i-install.", + "There are ongoing operations. Quitting UniGetUI may cause them to fail. Do you want to continue?": "May mga patuloy na operasyon. Ang paghinto sa UniGetUI ay maaaring maging sanhi ng pagkabigo sa kanila. Gusto mo bang magpatuloy?", + "UniGetUI or some of its components are missing or corrupt.": "Nawawala o sira ang UniGetUI o ang ilan sa mga component nito.", + "It is strongly recommended to reinstall UniGetUI to adress the situation.": "Mahigpit na inirerekomendang i-reinstall ang UniGetUI para matugunan ang sitwasyong ito.", + "Refer to the UniGetUI Logs to get more details regarding the affected file(s)": "Sumangguni sa mga log ng UniGetUI para sa higit pang detalye tungkol sa (mga) apektadong file", + "Integrity checks can be disabled from the Experimental Settings": "Maaaring i-disable ang mga integrity check mula sa Experimental Settings", + "Repair UniGetUI": "Ayusin ang UniGetUI", + "Live output": "Live na output", + "This package bundle had some settings that are potentially dangerous, and may be ignored by default.": "May ilang setting ang package bundle na ito na maaaring mapanganib at maaaring i-ignore bilang default.", + "Entries that show in YELLOW will be IGNORED.": "Ang mga entry na nakadilaw ay I-IIGNORE.", + "Entries that show in RED will be IMPORTED.": "Ang mga entry na nakapula ay I-IIMPORT.", + "You can change this behavior on UniGetUI security settings.": "Maaari mong baguhin ang ugaling ito sa mga security setting ng UniGetUI.", + "Open UniGetUI security settings": "Buksan ang mga security setting ng UniGetUI", + "Should you modify the security settings, you will need to open the bundle again for the changes to take effect.": "Kung babaguhin mo ang mga security setting, kakailanganin mong buksan muli ang bundle para magkabisa ang mga pagbabago.", + "Details of the report:": "Mga detalye ng ulat:", + "Are you sure you want to create a new package bundle? ": "Sigurado ka bang gusto mong gumawa ng bagong package bundle? ", + "Any unsaved changes will be lost": "Mawawala ang anumang hindi pa nasasave na pagbabago", + "Warning!": "Babala!", + "For security reasons, custom command-line arguments are disabled by default. Go to UniGetUI security settings to change this. ": "Dahil sa seguridad, naka-disable bilang default ang mga custom na argument sa command-line. Pumunta sa mga security setting ng UniGetUI para baguhin ito. ", + "Change default options": "Baguhin ang mga default na opsyon", + "Ignore future updates for this package": "I-ignore ang mga susunod na update para sa package na ito", + "For security reasons, pre-operation and post-operation scripts are disabled by default. Go to UniGetUI security settings to change this. ": "Dahil sa seguridad, naka-disable bilang default ang mga pre-operation at post-operation script. Pumunta sa mga security setting ng UniGetUI para baguhin ito. ", + "You can define the commands that will be run before or after this package is installed, updated or uninstalled. They will be run on a command prompt, so CMD scripts will work here.": "Maaari mong tukuyin ang mga command na tatakbo bago o pagkatapos ma-install, ma-update, o ma-uninstall ang package na ito. Tatakbo ang mga ito sa command prompt, kaya gagana rito ang mga CMD script.", + "Change this and unlock": "Baguhin ito at i-unlock", + "{0} Install options are currently locked because {0} follows the default install options.": "Naka-lock ngayon ang mga opsyon sa install ng {0} dahil sinusunod ng {0} ang mga default na opsyon sa install.", + "Unset or unknown": "Hindi nakatakda o hindi alam", + "This package has no screenshots or is missing the icon? Contrbute to UniGetUI by adding the missing icons and screenshots to our open, public database.": "Ang package na ito ay walang mga screenshot o nawawala ang icon? Mag-ambag sa UniGetUI sa pamamagitan ng pagdaragdag ng mga nawawalang icon at screenshot sa aming bukas, pampublikong database.", + "Become a contributor": "Maging contributor", + "Update to {0} available": "Available ang update sa {0}", + "Reinstall": "I-reinstall", + "Installer not available": "Hindi available ang installer", + "Version:": "Bersyon:", + "UniGetUI Version {0}": "Bersyon ng UniGetUI {0}", + "Performing backup, please wait...": "Isinasagawa ang backup, pakihintay...", + "An error occurred while logging in: ": "Nagkaroon ng error habang nagla-log in: ", + "Fetching available backups...": "Kinukuha ang mga available na backup...", + "Done!": "Tapos na!", + "The cloud backup has been loaded successfully.": "Matagumpay na na-load ang cloud backup.", + "An error occurred while loading a backup: ": "Nagkaroon ng error habang nilo-load ang backup: ", + "Backing up packages to GitHub Gist...": "Binu-backup ang mga package sa GitHub Gist...", + "Backup Successful": "Matagumpay ang backup", + "The cloud backup completed successfully.": "Matagumpay na nakumpleto ang cloud backup.", + "Could not back up packages to GitHub Gist: ": "Hindi ma-backup ang mga package sa GitHub Gist: ", + "It is not guaranteed that the provided credentials will be stored safely, so you may as well not use the credentials of your bank account": "Hindi garantisadong ligtas na mase-save ang mga ibinigay na kredensyal, kaya mas mabuting huwag mong gamitin ang kredensyal ng iyong bank account", + "Enable the automatic WinGet troubleshooter": "Paganahin ang awtomatikong troubleshooter ng WinGet", + "Add updates that fail with a 'no applicable update found' to the ignored updates list": "Idagdag sa listahan ng mga in-ignore na update ang mga update na pumapalya dahil sa 'no applicable update found'.", + "Invalid selection": "Hindi valid ang napili", + "No package was selected": "Walang napiling package", + "More than 1 package was selected": "Mahigit sa 1 package ang napili", + "List": "Listahan", + "Grid": "Grid na view", + "Icons": "Mga icon", + "\"{0}\" is a local package and does not have available details": "\"{0}\" ay isang lokal na package at walang available na detalye", + "\"{0}\" is a local package and is not compatible with this feature": "\"{0}\" ay isang lokal na package at hindi compatible sa feature na ito", + "Add packages to bundle": "Magdagdag ng mga package sa bundle", + "Preparing packages, please wait...": "Inihahanda ang mga package, pakihintay...", + "Loading packages, please wait...": "Nilo-load ang mga package, pakihintay...", + "Saving packages, please wait...": "Sine-save ang mga package, pakihintay...", + "The bundle was created successfully on {0}": "Matagumpay na nagawa ang bundle noong {0}", + "User profile": "Profile ng user", + "Error": "Kamalian", + "Log in failed: ": "Pumalya ang pag-log in: ", + "Log out failed: ": "Pumalya ang pag-log out: ", + "Package backup settings": "Mga setting ng backup ng package", + "Package managers": "Mga package manager", + "Manage UniGetUI autostart behaviour from the Settings app": "Pamahalaan ang awtomatikong pagsisimula ng UniGetUI", + "Choose how many operations shoulds be performed in parallel": "Piliin kung ilang operasyon ang dapat isagawa nang sabay-sabay", + "Something went wrong while launching the updater.": "May nangyaring mali habang inilulunsad ang updater.", + "Please try again later": "Pakisubukan muli mamaya", + "Show the release notes after UniGetUI is updated": "Ipakita ang mga tala sa release pagkatapos ma-update ang UniGetUI" +} diff --git a/src/Languages/lang_tr.json b/src/Languages/lang_tr.json new file mode 100644 index 0000000..dfa12c5 --- /dev/null +++ b/src/Languages/lang_tr.json @@ -0,0 +1,851 @@ +{ + "{0} of {1} operations completed": "{1} işlemden {0} tanesi tamamlandı", + "{0} is now {1}": "{0} artık {1}", + "Enabled": "Etkin", + "Disabled": "Devre dışı", + "Privacy": "Gizlilik", + "Hide my username from the logs": "Kullanıcı adımı günlüklerden gizle", + "Replaces your username with **** in the logs. Restart UniGetUI to also hide it from already-recorded entries.": "Günlüklerde kullanıcı adınızı **** ile değiştirir. Önceden kaydedilmiş girişlerden de gizlemek için UniGetUI'yi yeniden başlatın.", + "Your last update attempt did not complete.": "Son güncelleme denemeniz tamamlanmadı.", + "UniGetUI could not confirm whether the update succeeded. Open the log to see what happened.": "UniGetUI güncellemenin başarılı olup olmadığını doğrulayamadı. Ne olduğunu görmek için günlüğü açın.", + "View log": "Günlüğü görüntüle", + "The installer reported success but did not restart UniGetUI.": "Yükleyici başarı bildirdi ancak UniGetUI'yi yeniden başlatmadı.", + "The installer failed to initialize.": "Yükleyici başlatılamadı.", + "Setup was canceled before installation began.": "Kurulum, yükleme başlamadan önce iptal edildi.", + "A fatal error occurred during the preparation phase.": "Hazırlık aşamasında ölümcül bir hata oluştu.", + "A fatal error occurred during installation.": "Yükleme sırasında ölümcül bir hata oluştu.", + "Installation was canceled while in progress.": "Yükleme devam ederken iptal edildi.", + "The installer was terminated by another process.": "Yükleyici başka bir işlem tarafından sonlandırıldı.", + "The preparation phase determined the installation cannot proceed.": "Hazırlık aşamasında kurulumun devam edemeyeceği belirlendi.", + "The installer could not start. UniGetUI may already be running, or you do not have permission to install.": "Yükleyici başlatılamadı. UniGetUI zaten çalışıyor olabilir veya kurulum için izniniz olmayabilir.", + "Unexpected installer error.": "Beklenmeyen yükleyici hatası.", + "We are checking for updates.": "Güncellemeleri kontrol ediyoruz.", + "Please wait": "Lütfen bekleyin", + "Great! You are on the latest version.": "Harika! En son sürümdesiniz.", + "There are no new UniGetUI versions to be installed": "Yüklenecek yeni UniGetUI sürümü yok", + "UniGetUI version {0} is being downloaded.": "UniGetUI {0} sürümü indiriliyor.", + "This may take a minute or two": "Bu işlem bir veya iki dakika sürebilir", + "The installer authenticity could not be verified.": "Yükleyicinin orijinalliği doğrulanamadı.", + "The update process has been aborted.": "Güncelleme işlemi iptal edildi.", + "Auto-update is not yet available on this platform.": "Otomatik güncelleme bu platformda henüz kullanılamıyor.", + "Please update UniGetUI manually.": "Lütfen UniGetUI'yi elle güncelleyin.", + "An error occurred when checking for updates: ": "Güncellemeler kontrol edilirken bir hata oluştu:", + "The updater could not be launched.": "Güncelleyici başlatılamadı.", + "The operating system did not start the installer process.": "İşletim sistemi yükleyici işlemini başlatmadı.", + "UniGetUI is being updated...": "UniGetUI güncelleniyor...", + "Update installed.": "Güncelleme yüklendi.", + "UniGetUI was updated successfully, but this running copy was not replaced. This usually means you are running a development build. Close this copy and start the newly-installed version to finish.": "UniGetUI başarıyla güncellendi, ancak çalışan bu kopya değiştirilmedi. Bu genellikle bir geliştirme derlemesi çalıştırdığınız anlamına gelir. Bitirmek için bu kopyayı kapatın ve yeni yüklenen sürümü başlatın.", + "The update could not be applied.": "Güncelleme uygulanamadı.", + "Installer exit code {0}: {1}": "Yükleyici çıkış kodu {0}: {1}", + "Update cancelled.": "Güncelleme iptal edildi.", + "Authentication was cancelled.": "Kimlik doğrulama iptal edildi.", + "Installer exit code {0}": "Yükleyici çıkış kodu {0}", + "Operation in progress": "İşlem devam ediyor.", + "Please wait...": "Lütfen bekleyin...", + "Success!": "Başarılı!", + "Failed": "Başarısız", + "An error occurred while processing this package": "Bu paket işlenirken bir hata oluştu", + "Installer": "Yükleyici", + "Executable": "Çalıştırılabilir dosya", + "MSI": "MSI", + "Compressed file": "Sıkıştırılmış dosya", + "MSIX": "MSIX", + "WinGet was repaired successfully": "WinGet başarıyla onarıldı", + "It is recommended to restart UniGetUI after WinGet has been repaired": "WinGet onarıldıktan sonra UniGetUI'nin yeniden başlatılması önerilir", + "WinGet could not be repaired": "WinGet onarılamadı", + "An unexpected issue occurred while attempting to repair WinGet. Please try again later": "WinGet onarılmaya çalışılırken beklenmeyen bir sorun oluştu. Lütfen daha sonra tekrar deneyin", + "Log in to enable cloud backup": "Bulut yedeklemesini etkinleştirmek için oturum açın", + "Backup Failed": "Yedekleme Başarısız Oldu", + "Downloading backup...": "Yedekleme indiriliyor...", + "An update was found!": "Bir güncelleme bulundu!", + "{0} can be updated to version {1}": "{0}, {1} sürümüne güncellenebilir", + "Updates found!": "Güncellemeler bulundu!", + "{0} packages can be updated": "{0} paket güncellenebilir", + "{0} is being updated to version {1}": "{0}, {1} sürümüne güncelleniyor", + "{0} packages are being updated": "{0} paket güncelleniyor", + "You have currently version {0} installed": "Şu anda {0} sürümünü yüklediniz", + "Desktop shortcut created": "Masaüstü kısayolu oluşturuldu", + "UniGetUI has detected a new desktop shortcut that can be deleted automatically.": "UniGetUI, otomatik olarak silinebilecek yeni bir masaüstü kısayolu algıladı.", + "{0} desktop shortcuts created": "Masaüstünde {0} kısayol oluşturuldu", + "UniGetUI has detected {0} new desktop shortcuts that can be deleted automatically.": "UniGetUI, otomatik olarak silinebilecek {0} yeni masaüstü kısayolu algıladı.", + "Attention required": "Dikkat gerektirir", + "Restart required": "Yeniden başlatma gerekli", + "1 update is available": "1 güncelleme mevcut", + "{0} updates are available": "{0} güncellemeler mevcut", + "Everything is up to date": "Her şey güncel", + "Discover Packages": "Paketleri Keşfet", + "Available Updates": "Mevcut Güncellemeler", + "Installed Packages": "Yüklü Paketler", + "UniGetUI Version {0} by Devolutions": "Devolutions tarafından UniGetUI Sürümü {0}", + "Show UniGetUI": "UniGetUI'ı göster\n", + "Quit": "Çıkış", + "Are you sure?": "Emin misiniz?", + "Do you really want to uninstall {0}?": "{0} uygulamasını gerçekten kaldırmak istiyor musunuz?", + "Do you really want to uninstall the following {0} packages?": "Aşağıdaki {0} paketleri gerçekten kaldırmak istiyor musunuz?", + "No": "Hayır", + "Yes": "Evet", + "Partial": "Kısmi", + "View on UniGetUI": "UniGetUI'de göster", + "Update": "Güncelleme", + "Open UniGetUI": "UniGetUI'yi aç", + "Update all": "Tümünü güncelle", + "Update now": "Şimdi güncelle", + "Installer host changed since the installed version.\n": "Yükleyici ana bilgisayarı yüklü sürümden bu yana değişti.\n", + "This package is on the queue": "Bu paket sırada", + "installing": "Yükleniyor", + "updating": "Güncelleniyor", + "uninstalling": "kaldırılıyor", + "installed": "yüklü", + "Retry": "Yeniden dene", + "Install": "Yükle", + "Uninstall": "Kaldır", + "Open": "Aç", + "Operation profile:": "Çalışma profili:", + "Follow the default options when installing, upgrading or uninstalling this package": "Bu paketi yüklerken, yükseltirken veya kaldırırken varsayılan seçenekleri izleyin", + "The following settings will be applied each time this package is installed, updated or removed.": "Bu paket her yüklendiğinde, güncellendiğinde veya kaldırıldığında aşağıdaki ayarlar uygulanacaktır.", + "Version to install:": "Yüklenecek sürüm:", + "Architecture to install:": "Kurulacak mimari:", + "Installation scope:": "Scope yüklemesi:", + "Install location:": "Kurulum yeri:", + "Select": "Seç", + "Reset": "Sıfırla", + "Custom install arguments:": "Özel kurulum argümanları:", + "Custom update arguments:": "Özel güncelleme argümanları:", + "Custom uninstall arguments:": "Özel kaldırma argümanları:", + "Pre-install command:": "Yükleme öncesi komutu:", + "Post-install command:": "Yükleme sonrası komutu:", + "Abort install if pre-install command fails": "Ön kurulum komutu başarısız olursa kurulumu iptal et", + "Pre-update command:": "Güncelleme öncesi komutu:", + "Post-update command:": "Güncelleme sonrası komutu:", + "Abort update if pre-update command fails": "Ön güncelleme komutu başarısız olursa güncellemeyi iptal et", + "Pre-uninstall command:": "Kaldırma öncesi komutu:", + "Post-uninstall command:": "Kaldırma sonrası komutu:", + "Abort uninstall if pre-uninstall command fails": "Ön kaldırma komutu başarısız olursa kaldırmayı iptal et", + "Command-line to run:": "Çalıştırılacak komut satırı:", + "Save and close": "Kaydet ve Kapat", + "General": "Genel", + "Architecture & Location": "Mimari ve Konum", + "Command-line": "Komut satırı", + "Close apps": "Uygulamaları kapat", + "Pre/Post install": "Kurulum öncesi/sonrası", + "Select the processes that should be closed before this package is installed, updated or uninstalled.": "Bu paket yüklenmeden, güncellenmeden veya kaldırılmadan önce kapatılması gereken işlemleri seçin.", + "Write here the process names here, separated by commas (,)": "Süreç adlarını buraya virgülle (,) ayırarak yazın", + "Try to kill the processes that refuse to close when requested to": "Talep edildiğinde kapatmayı reddeden işlemleri kapatmaya çalışın", + "Run as admin": "Yönetici olarak çalıştır", + "Interactive installation": "İnteraktif kurulum", + "Skip hash check": "Hash kontrolünü atla", + "Uninstall previous versions when updated": "Güncellendiğinde önceki sürümleri kaldır", + "Skip minor updates for this package": "Bu paket için küçük güncellemeleri atla", + "Automatically update this package": "Bu paketi otomatik güncelle", + "{0} installation options": "{0} Kurulum Seçenekleri", + "Latest": "En son", + "PreRelease": "Önsürüm", + "Default": "Varsayılan", + "Manage ignored updates": "Yok sayılan güncellemeleri yönet", + "The packages listed here won't be taken in account when checking for updates. Double-click them or click the button on their right to stop ignoring their updates.": "Burada listelenen paketler güncellemeler kontrol edilirken dikkate alınmayacaktır. Güncellemelerini yok saymayı durdurmak için bunlara çift tıklayın veya sağlarındaki düğmeye tıklayın.", + "Reset list": "Listeyi sıfırla", + "Do you really want to reset the ignored updates list? This action cannot be reverted": "Yok sayılan güncellemeler listesini gerçekten sıfırlamak istiyor musunuz? Bu işlem geri alınamaz", + "No ignored updates": "Yok sayılan güncelleme yok", + "Package Name": "Paket ismi", + "Package ID": "Paket kimliği (ID)", + "Ignored version": "Yok sayılan sürümler", + "New version": "Yeni sürüm", + "Source": "Kaynak", + "All versions": "Tüm sürümler", + "Unknown": "Bilinmeyen", + "Up to date": "Güncel", + "Package {name} from {manager}": "{manager} kaynağından {name} paketi", + "Remove {0} from ignored updates": "{0} paketini yoksayılan güncellemelerden kaldır", + "Cancel": "İptal", + "Administrator privileges": "Yönetici ayrıcalıkları", + "This operation is running with administrator privileges.": "Bu işlem yönetici ayrıcalıklarıyla çalışıyor.", + "Interactive operation": "Etkileşimli çalışma", + "This operation is running interactively.": "Bu işlem etkileşimli olarak çalışmaktadır.", + "You will likely need to interact with the installer.": "Muhtemelen yükleyiciyle etkileşime girmeniz gerekecektir.", + "Integrity checks skipped": "Bütünlük kontrolleri atlandı", + "Integrity checks will not be performed during this operation.": "Bu işlem sırasında bütünlük denetimleri yapılmayacaktır.", + "Proceed at your own risk.": "Devam etmek kendi sorumluluğunuzda.", + "Close": "Kapat", + "Loading...": "Yükleniyor...", + "Installer SHA256": "SHA256 Yükleyici", + "Homepage": "Ana Sayfa", + "Author": "Yazar", + "Publisher": "Yayımcı", + "License": "Lisans", + "Manifest": "Manifesto", + "Installer Type": "Yükleyici Türü", + "Size": "Boyut", + "Installer URL": "Yükleyici URL'si", + "Last updated:": "Son güncelleme:", + "Release notes URL": "Sürüm notları", + "Package details": "Paket ayrıntıları", + "Dependencies:": "Bağımlılıklar:", + "Release notes": "Sürüm notları", + "Screenshots": "Ekran görüntüleri", + "This package has no screenshots or is missing the icon? Contribute to UniGetUI by adding the missing icons and screenshots to our open, public database.": "Bu paketin ekran görüntüsü yok mu veya simgesi eksik mi? Eksik simgeleri ve ekran görüntülerini açık, herkese açık veri tabanımıza ekleyerek UniGetUI'ye katkıda bulunun.", + "Version": "Sürüm", + "Install as administrator": "Yönetici olarak yükle", + "Update to version {0}": "{0} sürümüne güncelleme", + "Installed Version": "Yüklü Sürüm", + "Update as administrator": "Yönetici olarak güncelle", + "Interactive update": "İnteraktif güncelleme", + "Uninstall as administrator": "Yönetici olarak kaldır", + "Interactive uninstall": "İnteraktif kaldırma", + "Uninstall and remove data": "Verileri kaldır", + "Not available": "Mevcut değil", + "Installer SHA512": "SHA512 Yükleyici", + "Unknown size": "Bilinmeyen boyut", + "No dependencies specified": "Bağımlılık belirtilmedi", + "mandatory": "zorunlu", + "optional": "isteğe bağlı", + "UniGetUI {0} is ready to be installed.": "UniGetUI {0} kurulmaya hazır.", + "The update process will start after closing UniGetUI": "UniGetUI kapatıldıktan sonra güncelleme işlemi başlayacak", + "UniGetUI has been ran as administrator, which is not recommended. When running UniGetUI as administrator, EVERY operation launched from UniGetUI will have administrator privileges. You can still use the program, but we highly recommend not running UniGetUI with administrator privileges.": "UniGetUI yönetici olarak çalıştırıldı; bu önerilmez. UniGetUI yönetici olarak çalıştırıldığında, UniGetUI'den başlatılan TÜM işlemler yönetici ayrıcalıklarıyla çalışır. Programı yine de kullanabilirsiniz, ancak UniGetUI'yi yönetici ayrıcalıklarıyla çalıştırmamanızı önemle tavsiye ederiz.", + "Share anonymous usage data": "Anonim kullanım verilerini paylaşın", + "UniGetUI collects anonymous usage data in order to improve the user experience.": "UniGetUI, kullanıcı deneyimini geliştirmek için anonim kullanım verileri toplar.", + "Accept": "Kabul", + "Software Updates": "Yazılım Güncellemeleri", + "Package Bundles": "Paketleme Grupları", + "Settings": "Ayarlar", + "Package Managers": "Paket Yöneticileri", + "UniGetUI Log": "UniGetUI günlüğü", + "Package Manager logs": "Paket Yöneticisi günlükleri", + "Operation history": "İşlem geçmişi", + "Help": "Yardım", + "UniGetUI": "UniGetUI", + "You have installed UniGetUI Version {0}": "UniGetUI {0} Sürümünü yüklediniz", + "Disclaimer": "Feragatname", + "UniGetUI is developed by Devolutions and is not affiliated with any of the compatible package managers.": "UniGetUI, Devolutions tarafından geliştirilmiştir ve uyumlu paket yöneticilerinin hiçbiriyle ilişkili değildir.", + "UniGetUI wouldn't have been possible without the help of the contributors. Thank you all 🥳": "Katkıda bulunanların yardımı olmadan UniGetUI mümkün olmazdı. Hepinize teşekkür ederim 🥳", + "UniGetUI uses the following libraries. Without them, UniGetUI wouldn't have been possible.": "UniGetUI Aşağıdaki kütüphaneleri kullanır. Onlar olmasaydı, UniGetUI mümkün olmazdı.", + "{0} homepage": "{0} ana sayfa", + "UniGetUI has been translated to more than 40 languages thanks to the volunteer translators. Thank you 🤝": "UniGetUI, gönüllü çevirmenler sayesinde 40 'tan fazla dile çevrildi. Teşekkürler 🤝", + "Verbose": "Ayrıntılı", + "1 - Errors": "1 - Hatalar", + "2 - Warnings": "2 - Uyarılar", + "3 - Information (less)": "3 - Bilgilendirme (az)", + "4 - Information (more)": "4 - Bilgilendirme (Ek)", + "5 - information (debug)": "5 - Bilgilendirme (hata ayıklama)", + "Warning": "Uyarı", + "The following settings may pose a security risk, hence they are disabled by default.": "Aşağıdaki ayarlar güvenlik riski oluşturabileceğinden varsayılan olarak devre dışıdır.", + "Enable the settings below if and only if you fully understand what they do, and the implications they may have.": "Aşağıdaki ayarları, YALNIZCA VE YALNIZCA bunların ne işe yaradığını, olası etkilerini ve tehlikelerini tam olarak anlıyorsanız etkinleştirin.", + "The settings will list, in their descriptions, the potential security issues they may have.": "Ayarlar, açıklamalarında oluşabilecek güvenlik sorunlarını listeleyecektir.", + "The backup will include the complete list of the installed packages and their installation options. Ignored updates and skipped versions will also be saved.": "Yedekleme, yüklü paketlerin tam listesini ve kurulum seçeneklerini içerecektir. Yok sayılan güncellemeler ve atlanan sürümler de kaydedilecektir.", + "The backup will NOT include any binary file nor any program's saved data.": "Yedekleme, herhangi bir ikili dosya veya herhangi bir programın kaydedilmiş verilerini içermeyecektir.", + "The size of the backup is estimated to be less than 1MB.": "Yedekleme boyutunun 1 MB'den küçük olduğu tahmin edilmektedir.", + "The backup will be performed after login.": "Yedekleme, giriş yapıldıktan sonra gerçekleştirilecektir.", + "{pcName} installed packages": "{pcName} yüklü paketler", + "Current status: Not logged in": "Mevcut durum: Giriş yapılmadı", + "You are logged in as {0} (@{1})": "{0} (@{1}) olarak giriş yaptınız", + "Nice! Backups will be uploaded to a private gist on your account": "Güzel! Yedekler hesabınızdaki özel bir github gist'e yüklenecek", + "Select backup": "Yedeklemeyi seçin", + "Settings imported from {0}": "Ayarlar {0} konumundan içe aktarıldı", + "UniGetUI Settings": "UniGetUI ayarları", + "Settings exported to {0}": "Ayarlar {0} konumuna dışa aktarıldı", + "UniGetUI settings were reset": "UniGetUI ayarları sıfırlandı", + "Allow pre-release versions": "Ön sürümlere izin ver", + "Apply": "Uygula", + "For security reasons, custom command-line arguments are disabled by default. Go to UniGetUI security settings to change this.": "Güvenlik nedeniyle özel komut satırı bağımsız değişkenleri varsayılan olarak devre dışıdır. Bunu değiştirmek için UniGetUI güvenlik ayarlarına gidin.", + "Go to UniGetUI security settings": "UniGetUI güvenlik ayarlarına gidin", + "The following options will be applied by default each time a {0} package is installed, upgraded or uninstalled.": "Bir {0} paket her kurulduğunda, yükseltildiğinde veya kaldırıldığında aşağıdaki seçenekler varsayılan olarak uygulanacaktır.", + "Package's default": "Paket varsayılanı", + "Install location can't be changed for {0} packages": "{0} paket için yükleme konumu değiştirilemez", + "The local icon cache currently takes {0} MB": "Yerel simge önbelleği şu anda {0} MB yer kaplıyor", + "Username": "Kullanıcı adı", + "Password": "Şifre", + "Credentials": "Kimlik Bilgileri", + "It is not guaranteed that the provided credentials will be stored safely": "Sağlanan kimlik bilgilerinin güvenli biçimde saklanacağı garanti edilmez", + "Partially": "Kısmen", + "Package manager": "Paket yöneticisi", + "Compatible with proxy": "Proxy ile uyumlu", + "Compatible with authentication": "Kimlik doğrulama ile uyumlu", + "Proxy compatibility table": "Proxy uyumluluk tablosu", + "{0} settings": "{0} ayarlar", + "{0} status": "{0} durum", + "Default installation options for {0} packages": "{0} paket için varsayılan kurulum seçenekleri", + "Expand version": "Sürümü genişlet", + "The executable file for {0} was not found": "Yürütülebilir dosya {0} için bulunamadı", + "{pm} is disabled": "{pm} devre dışı", + "Enable it to install packages from {pm}.": "Paketleri {pm} tarihinden itibaren yüklemek için etkinleştirin.", + "{pm} is enabled and ready to go": "{pm} etkinleştirildi ve kullanıma hazır", + "{pm} version:": "{pm} sürümü:", + "{pm} was not found!": "{pm} bulunamadı!", + "You may need to install {pm} in order to use it with UniGetUI.": "UniGetUI ile kullanmak için {pm} yüklemeniz gerekebilir.", + "Scoop Installer - UniGetUI": "Kepçe Yükleyici - UniGetUI", + "Scoop Uninstaller - UniGetUI": "Kepçe Kaldırma Programı - UniGetUI", + "Clearing Scoop cache - UniGetUI": "Kepçe önbelleğini temizleme - UniGetUI", + "Restart UniGetUI to fully apply changes": "Değişikliklerin tamamen uygulanması için UniGetUI'yi yeniden başlatın", + "Restart UniGetUI": "UniGetUI'yi yeniden başlat", + "Manage {0} sources": "{0} kaynaklarını yönet", + "Add source": "Kaynak ekle", + "Add": "Ekle", + "Source name": "Kaynak adı", + "Source URL": "Kaynak URL'si", + "Other": "Diğer", + "No minimum age": "Minimum süre yok", + "1 day": "1 gün", + "{0} days": "{0} gün", + "Custom...": "Özel...", + "{0} minutes": "{0} dakika", + "1 hour": "1 saat", + "{0} hours": "{0} saat", + "1 week": "1 hafta", + "Supports release dates": "Yayın tarihlerini destekler", + "Release date support per package manager": "Paket yöneticisine göre yayın tarihi desteği", + "Search for packages": "Paket ara", + "Local": "Yerel", + "OK": "TAMAM", + "Last checked: {0}": "Son kontrol: {0}", + "{0} packages were found, {1} of which match the specified filters.": "{1} tanesi belirtilen filtrelerle eşleşen {0} paket bulundu.", + "{0} selected": "{0} seçildi", + "(Last checked: {0})": "(Son kontrol: {0})", + "All packages selected": "Tüm paketler seçildi", + "Package selection cleared": "Paket seçimi temizlendi", + "{0}: {1}": "{0}: {1}", + "More info": "Daha fazla bilgi", + "GitHub account": "GitHub hesabı", + "Log in with GitHub to enable cloud package backup.": "Bulut paketi yedeklemesini etkinleştirmek için GitHub ile oturum açın.", + "More details": "Daha fazla detay", + "Log in": "Oturum aç", + "If you have cloud backup enabled, it will be saved as a GitHub Gist on this account": "Bulut yedeklemesini etkinleştirdiyseniz, bu hesapta GitHub Gist olarak kaydedilecektir", + "Log out": "Çıkış yap", + "About UniGetUI": "UniGetUI hakkında", + "About": "Hakkında", + "Third-party licenses": "Üçüncü taraf lisansları", + "Contributors": "Katkıda Bulunanlar", + "Translators": "Çevirmenler", + "Bundle security report": "Paket güvenlik raporu", + "The bundle contained restricted content": "Paket, kısıtlanmış içerik içeriyordu", + "UniGetUI – Crash Report": "UniGetUI – Çökme Raporu", + "UniGetUI has crashed": "UniGetUI çöktü", + "Help us fix this by sending a crash report to Devolutions. All fields below are optional.": "Devolutions'a bir çökme raporu göndererek bu sorunu düzeltmemize yardımcı olun. Aşağıdaki tüm alanlar isteğe bağlıdır.", + "Email (optional)": "E-posta (isteğe bağlı)", + "your@email.com": "epostaniz@email.com", + "Additional details (optional)": "Ek ayrıntılar (isteğe bağlı)", + "Describe what you were doing when the crash occurred…": "Çökme meydana geldiğinde ne yaptığınızı açıklayın…", + "Crash report": "Çökme raporu", + "Don't Send": "Gönderme", + "Send Report": "Raporu Gönder", + "Sending…": "Gönderiliyor…", + "Unsaved changes": "Kaydedilmemiş değişiklikler", + "You have unsaved changes in the current bundle. Do you want to discard them?": "Geçerli pakette kaydedilmemiş değişiklikler var. Bunları göz ardı etmek istiyor musunuz?", + "Discard changes": "Değişiklikleri göz ardı et", + "Integrity violation": "Bütünlük ihlali", + "UniGetUI or some of its components are missing or corrupt. It is strongly recommended to reinstall UniGetUI to adress the situation.": "UniGetUI veya bileşenlerinden bazıları eksik ya da bozuk. Bu durumu gidermek için UniGetUI'yi yeniden yüklemeniz önemle önerilir.", + "• Refer to the UniGetUI Logs to get more details regarding the affected file(s)": "• Etkilenen dosya(lar) hakkında daha fazla bilgi edinmek için UniGetUI Günlüklerine bakın", + "• Integrity checks can be disabled from the Experimental Settings": "• Bütünlük kontrolleri Deney Ayarlarından devre dışı bırakılabilir", + "Manage shortcuts": "Kısayolları yönet", + "UniGetUI has detected the following desktop shortcuts which can be removed automatically on future upgrades": "UniGetUI, gelecekteki yükseltmelerde otomatik olarak kaldırılabilecek aşağıdaki masaüstü kısayollarını algıladı", + "Do you really want to reset this list? This action cannot be reverted.": "Bu listeyi gerçekten sıfırlamak istiyor musunuz? Bu eylem geri alınamaz.", + "Desktop shortcuts list": "Masaüstü kısayolları listesi", + "Open in explorer": "Gezginde aç", + "Remove from list": "Listeden sil", + "When new shortcuts are detected, delete them automatically instead of showing this dialog.": "Yeni kısayollar algılandığında, bu iletişim kutusunu göstermek yerine bunları otomatik olarak silin.", + "Not right now": "Şimdi olmaz", + "Missing dependency": "Eksik bağımlılık", + "UniGetUI requires {0} to operate, but it was not found on your system.": "UniGetUI'nin çalışması için {0} gerekiyor ancak sisteminizde bulunamadı.", + "Click on Install to begin the installation process. If you skip the installation, UniGetUI may not work as expected.": "Kurulum işlemine başlamak için Install'a tıklayın. Kurulumu atlarsanız UniGetUI beklendiği gibi çalışmayabilir.", + "Alternatively, you can also install {0} by running the following command in a Windows PowerShell prompt:": "Alternatif olarak, Windows PowerShell isteminde aşağıdaki komutu çalıştırarak da {0}'ı yükleyebilirsiniz:", + "Install {0}": "{0}'ı yükleyin", + "Do not show this dialog again for {0}": "{0} için bu iletişim kutusunu bir daha gösterme", + "Please wait while {0} is being installed. A black window may show up. Please wait until it closes.": "{0} yüklenirken lütfen bekleyin. Siyah bir pencere görünebilir. Lütfen kapanana kadar bekleyin.", + "{0} has been installed successfully.": "{0} başarıyla kuruldu.", + "Please click on \"Continue\" to continue": "Devam etmek için lütfen \"Devam\"a tıklayın", + "Continue": "Devam", + "{0} has been installed successfully. It is recommended to restart UniGetUI to finish the installation": "{0} başarıyla kuruldu. Kurulumu tamamlamak için UniGetUI'nin yeniden başlatılması önerilir.", + "Restart later": "Daha sonra yeniden başlatacağım", + "An error occurred:": "Bir hata oluştu:", + "Please see the Command-line Output or refer to the Operation History for further information about the issue.": "Sorun hakkında daha fazla bilgi için lütfen Komut satırı Çıktısına veya İşlem Geçmişine bakın.", + "Retry as administrator": "Yönetici olarak yeniden deneyin", + "Retry interactively": "Etkileşimli olarak yeniden deneyin", + "Retry skipping integrity checks": "Bütünlük kontrollerini atlayarak yeniden dene", + "Installation options": "Yükleme seçenekleri", + "Save": "Kaydet", + "UniGetUI collects anonymous usage data with the sole purpose of understanding and improving the user experience.": "UniGetUI, yalnızca kullanıcı deneyimini anlamak ve geliştirmek amacıyla anonim kullanım verileri toplar.", + "More details about the shared data and how it will be processed": "Paylaşılan veriler ve nasıl işleneceği hakkında daha fazla ayrıntı", + "Do you accept that UniGetUI collects and sends anonymous usage statistics, with the sole purpose of understanding and improving the user experience?": "UniGetui'nin yalnızca kullanıcı deneyimini anlamak ve geliştirmek amacıyla anonim kullanım istatistikleri topladığını ve gönderdiğini kabul ediyor musunuz?", + "Decline": "Reddet", + "No personal information is collected nor sent, and the collected data is anonimized, so it can't be back-tracked to you.": "Kişisel bilgi toplanmaz veya gönderilmez ve toplanan veriler anonimize edilir, bu nedenle bulunamazsınız.", + "Navigation panel": "Gezinti paneli", + "Operations": "İşlemler", + "Toggle operations panel": "İşlemler panelini aç/kapat", + "Bulk operations": "Toplu işlemler", + "Retry failed": "Başarısız olanları yeniden dene", + "Clear successful": "Başarılı olanları temizle", + "Clear finished": "Tamamlananları temizle", + "Cancel all": "Tümünü iptal et", + "More": "Daha çok", + "Toggle navigation panel": "Gezinti panelini aç/kapat", + "Minimize": "Simge durumuna küçült", + "Maximize": "Büyüt", + "UniGetUI by Devolutions": "Devolutions tarafından UniGetUI", + "UniGetUI is an application that makes managing your software easier, by providing an all-in-one graphical interface for your command-line package managers.": "UniGetUI, komut satırı paket yöneticileriniz için hepsi bir arada grafik arayüzü sağlayarak yazılımınızı yönetmeyi kolaylaştıran bir uygulamadır.", + "Useful links": "Faydalı bağlantılar", + "UniGetUI Homepage": "UniGetUI ana sayfası", + "Report an issue or submit a feature request": "Bir sorunu bildirin veya bir özellik isteği gönderin", + "UniGetUI Repository": "UniGetUI deposu", + "View GitHub Profile": "GitHub Profili", + "UniGetUI License": "UniGetUI Lisansı", + "Using UniGetUI implies the acceptation of the MIT License": "UniGetUI'yi kullanmak MIT Lisansının kabul edildiğini ifade eder", + "Become a translator": "Çevirmen olun", + "Go back": "Geri git", + "Go forward": "İleri git", + "Go to home page": "Ana sayfaya git", + "Reload page": "Sayfayı yeniden yükle", + "View page on browser": "Sayfayı tarayıcıda görüntüle", + "The built-in browser is not supported on Linux yet.": "Yerleşik tarayıcı henüz Linux'ta desteklenmiyor.", + "Open in browser": "Tarayıcıda aç", + "Copy to clipboard": "Panoya kopyala", + "Export to a file": "Bir dosyaya aktar", + "Log level:": "Günlük düzeyi:", + "Reload log": "Günlüğü yeniden yükle", + "Export log": "Günlüğü dışa aktar", + "Text": "Metin", + "Change how operations request administrator rights": "İşlemlerin yönetici haklarını nasıl talep edeceğini değiştirin", + "Restrictions on package operations": "Paket işlemleriyle ilgili kısıtlamalar", + "Restrictions on package managers": "Paket yöneticilerine yönelik kısıtlamalar", + "Restrictions when importing package bundles": "Paket paketlerini içe aktarırken kısıtlamalar", + "Ask for administrator privileges once for each batch of operations": "Her bir işlem grubu için bir kez yönetici ayrıcalıkları isteyin", + "Ask only once for administrator privileges": "Yönetici ayrıcalıkları için yalnızca bir kez sor", + "Prohibit any kind of Elevation via UniGetUI Elevator or GSudo": "UniGetUI Elevator veya GSudo aracılığıyla her türlü yükseltmeyi kaçın", + "This option WILL cause issues. Any operation incapable of elevating itself WILL FAIL. Install/update/uninstall as administrator will NOT WORK.": "Bu seçenek SORUNLARA neden olacaktır. Kendini yükseltme yeteneği olmayan herhangi bir işlem BAŞARISIZ OLACAKTIR. Yönetici olarak yükle/güncelle/kaldır ÇALIŞMAYACAKTIR.", + "Allow custom command-line arguments": "Özel komut satırı argümanlarına izin ver", + "Custom command-line arguments can change the way in which programs are installed, upgraded or uninstalled, in a way UniGetUI cannot control. Using custom command-lines can break packages. Proceed with caution.": "Özel komut satırı bağımsız değişkenleri, UniGetUI'nin kontrol edemeyeceği bir şekilde programların yüklenme, yükseltilme veya kaldırılma şeklini değiştirebilir. Özel komut satırları kullanmak paketleri bozabilir. Dikkatli devam edin.", + "Ignore custom pre-install and post-install commands when importing packages from a bundle": "Paket grubundan içe aktarırken özel ön kurulum ve son kurulum komutlarının çalıştırılmasına izin ver", + "Pre and post install commands will be run before and after a package gets installed, upgraded or uninstalled. Be aware that they may break things unless used carefully": "Kurulum öncesi ve sonrası komutlar, bir paket kurulmasından, yükseltilmesinden veya kaldırılmasından önce ve sonra çalıştırılacaktır. Dikkatli kullanılmadıkça bir şeyleri bozabileceklerini unutmayın", + "Allow changing the paths for package manager executables": "Paket yöneticisi çalıştırılabilir dosyaları için yolların değiştirilmesine izin ver", + "Turning this on enables changing the executable file used to interact with package managers. While this allows finer-grained customization of your install processes, it may also be dangerous": "Bunu açmak, paket yöneticileriyle etkileşimde bulunmak için kullanılan yürütülebilir dosyanın değiştirilmesini sağlar. Bu, kurulum süreçlerinizin daha ayrıntılı özelleştirilmesine izin verirken, aynı zamanda tehlikeli de olabilir", + "Allow importing custom command-line arguments when importing packages from a bundle": "Bir paketten paketler içe aktarılırken özel komut satırı argümanlarının içe aktarılmasına izin ver", + "Malformed command-line arguments can break packages, or even allow a malicious actor to gain privileged execution. Therefore, importing custom command-line arguments is disabled by default": "Hatalı biçimlendirilmiş komut satırı argümanları paketleri kırabilir veya hatta kötü niyetli bir aktörün ayrıcalıklı yürütme elde etmesine izin verebilir. Bu nedenle, özel komut satırı bağımsız değişkenlerini içe aktarma varsayılan olarak devre dışıdır", + "Allow importing custom pre-install and post-install commands when importing packages from a bundle": "Paketleri bir paketten içe aktarırken özel ön yükleme ve yükleme sonrası komutlarının içe aktarılmasına izin ver", + "Pre and post install commands can do very nasty things to your device, if designed to do so. It can be very dangerous to import the commands from a bundle, unless you trust the source of that package bundle": "Kurulum öncesi ve sonrası komutları, eğer bu şekilde tasarlanmışlarsa, cihazınıza çok kötü şeyler yapabilirler. Paketin kaynağına güvenmediğiniz sürece komutları bir paketten içe aktarmak çok tehlikeli olabilir", + "Administrator rights and other dangerous settings": "Yönetici ayrıcalıkları ve diğer tehlikeli ayarlar", + "Package backup": "Paket yedekleme", + "Cloud package backup": "Bulut paketi yedekleme", + "Local package backup": "Yerel paket yedekleme", + "Local backup advanced options": "Yerel yedekleme gelişmiş seçenekleri", + "Log in with GitHub": "GitHub ile giriş yap", + "Log out from GitHub": "GitHub'dan çıkış yap", + "Periodically perform a cloud backup of the installed packages": "Yüklü paketlerin bulut yedeklemesini periyodik olarak gerçekleştirin", + "Cloud backup uses a private GitHub Gist to store a list of installed packages": "Bulut yedekleme, yüklü paketlerin listesini depolamak için özel bir GitHub Gist kullanır", + "Perform a cloud backup now": "Şimdi bir bulut yedeklemesi gerçekleştirin", + "Backup": "Yedekle", + "Restore a backup from the cloud": "Buluttan bir yedeklemeyi geri yükleyin", + "Begin the process to select a cloud backup and review which packages to restore": "Bir bulut yedeklemesi seçme sürecini başlatın ve hangi paketlerin geri yükleneceğini inceleyin", + "Periodically perform a local backup of the installed packages": "Yüklü paketlerin yerel yedeklemesini periyodik olarak gerçekleştirin", + "Perform a local backup now": "Şimdi yerel bir yedekleme gerçekleştirin", + "Change backup output directory": "Yedekleme çıktı dizinini değiştir", + "Set a custom backup file name": "Özel bir yedekleme dosyası adı belirleyin", + "Leave empty for default": "Varsayılan olarak boş bırakın", + "Add a timestamp to the backup file names": "Yedekleme dosyası adlarına bir zaman damgası ekleyin", + "Backup and Restore": "Yedekleme ve Geri Yükleme", + "Enable background api (UniGetUI Widgets and Sharing, port 7058)": "Arka plan api'sini etkinleştir (UniGetUI Widget'ları ve Paylaşımı, bağlantı noktası 7058)", + "Wait for the device to be connected to the internet before attempting to do tasks that require internet connectivity.": "İnternet bağlantısı gerektiren görevleri yapmaya başlamadan önce cihazın internete bağlanmasını bekleyin.", + "Disable the 1-minute timeout for package-related operations": "Paketle ilgili işlemler için 1 dakikalık zaman aşımını devre dışı bırakın", + "Use installed GSudo instead of UniGetUI Elevator": "UniGetUI Elevator yerine kurulu GSudo'yu kullanın", + "Use a custom icon and screenshot database URL": "Özel bir simge ve ekran görüntüsü veritabanı URL'si kullanın", + "Enable background CPU Usage optimizations (see Pull Request #3278)": "Arka Plan CPU kullanım optimizasyonlarını etkinleştirin (Bkz. İstek #3278)", + "Perform integrity checks at startup": "Başlangıçta bütünlük kontrolleri gerçekleştirin", + "When batch installing packages from a bundle, install also packages that are already installed": "Paketleri bir paketten toplu olarak yüklerken, önceden yüklenmiş paketleri de yükleyin", + "Experimental settings and developer options": "Deneysel ayarlar ve geliştirici seçenekleri", + "Show UniGetUI's version and build number on the titlebar.": "UniGetUI'nin sürümünü başlık çubuğunda göster", + "Language": "Dil", + "UniGetUI updater": "UniGetUI güncelleyici", + "Telemetry": "Telemetri", + "Manage UniGetUI settings": "UniGetUI ayarlarını yönetin", + "Related settings": "İlgili ayarlar", + "Update UniGetUI automatically": "UniGetUI'ı otomatik olarak güncelle", + "Check for updates": "Güncellemeleri kontrol et", + "Install prerelease versions of UniGetUI": "UniGetUI'nin yayın öncesi sürümlerini yükleyin", + "Manage telemetry settings": "Telemetri ayarlarını yönet", + "Manage": "Yönet", + "Import settings from a local file": "Ayarları yerel bir dosyadan içe aktar", + "Import": "İçe aktar", + "Export settings to a local file": "Ayarları yerel bir dosyaya aktar", + "Export": "Dışa Aktar", + "Reset UniGetUI": "UniGetUI'yi sıfırla", + "User interface preferences": "Kullanıcı arayüzü tercihleri", + "Application theme, startup page, package icons, clear successful installs automatically": "Uygulama teması, başlangıç sayfası, paket simgeleri, başarılı yüklemeleri otomatik olarak temizle", + "General preferences": "Genel tercihler", + "UniGetUI display language:": "UniGetUI arayüz dili:", + "System language": "Sistem dili", + "Is your language missing or incomplete?": "Diliniz eksik mi yoksa tam değil mi?", + "Appearance": "Dış görünüş", + "UniGetUI on the background and system tray": "Arka planda ve sistem tepsisinde UniGetUI", + "Package lists": "Paket listeleri", + "Use classic mode": "Klasik modu kullan", + "Restart UniGetUI to apply this change": "Bu değişikliği uygulamak için UniGetUI'yi yeniden başlatın", + "The classic UI is disabled for beta testers": "Klasik kullanıcı arayüzü beta test kullanıcıları için devre dışı bırakıldı", + "Close UniGetUI to the system tray": "UniGetUI'yi sistem tepsisine kapatın", + "Manage UniGetUI autostart behaviour": "UniGetUI otomatik başlatma davranışını yönet", + "Show package icons on package lists": "Paket listelerinde paket simgelerini göster", + "Clear cache": "Önbelleği temizle", + "Select upgradable packages by default": "Yükseltilebilir paketleri varsayılan olarak seç", + "Light": "Aydınlık", + "Dark": "Karanlık", + "Follow system color scheme": "Sistem temasını kullan", + "Application theme:": "Uygulama teması:", + "UniGetUI startup page:": "UniGetUI başlangıç ​​sayfası:", + "Proxy settings": "Proxy ayarları", + "Other settings": "Diğer ayarlar", + "Connect the internet using a custom proxy": "Özel bir proxy kullanarak internete bağlanın", + "Please note that not all package managers may fully support this feature": "Lütfen tüm paket yöneticilerinin bu özelliği tam olarak desteklemeyebileceğini unutmayın", + "Proxy URL": "Proxy URL'si", + "Enter proxy URL here": "Proxy URL'sini buraya girin", + "Authenticate to the proxy with a user and a password": "Proxy için kullanıcı adı ve parola ile kimlik doğrulayın", + "Internet and proxy settings": "İnternet ve proxy ayarları", + "Package manager preferences": "Paket yöneticisi tercihleri", + "Ready": "Hazır", + "Not found": "Bulunamadı", + "Notification preferences": "Bildirim tercihleri", + "Notification types": "Bildirim türleri", + "The system tray icon must be enabled in order for notifications to work": "Bildirimlerin çalışması için sistem tepsisi simgesinin etkinleştirilmesi gerekir", + "Enable UniGetUI notifications": "UniGetUI bildirimlerini etkinleştir", + "Show a notification when there are available updates": "Mevcut güncellemeler olduğunda bildirim göster", + "Show a silent notification when an operation is running": "Bir işlem çalışırken sessiz bildirim göster", + "Show a notification when an operation fails": "Bir işlem başarısız olduğunda bildirim göster", + "Show a notification when an operation finishes successfully": "Bir işlem başarıyla tamamlandığında bildirim göster", + "Concurrency and execution": "Eşzamanlılık ve yürütme", + "Automatic desktop shortcut remover": "Otomatik masaüstü kısayolu kaldırıcı", + "Choose how many operations should be performed in parallel": "Paralel olarak kaç işlem gerçekleştirileceğini seçin", + "Clear successful operations from the operation list after a 5 second delay": "5 saniyelik bir gecikmenin ardından başarılı işlemleri işlem listesinden silin", + "Download operations are not affected by this setting": "İndirme işlemleri bu ayardan etkilenmez", + "You may lose unsaved data": "Kaydedilmemiş verileri kaybedebilirsiniz", + "Ask to delete desktop shortcuts created during an install or upgrade.": "Yükleme veya yükseltme sırasında oluşturulan masaüstü kısayollarının silinmesini sor.", + "Package update preferences": "Paket güncelleme tercihleri", + "Update check frequency, automatically install updates, etc.": "Güncelleme kontrol sıklığı, güncellemelerin otomatik olarak yüklenmesi vb.", + "Reduce UAC prompts, elevate installations by default, unlock certain dangerous features, etc.": "UAC uyarılarını azaltın, kurulumları varsayılan olarak yükseltin, belirli tehlikeli özelliklerin kilidini açın, vb.", + "Package operation preferences": "Paket işlem tercihleri", + "Enable {pm}": "{pm} etkinleştirilsin", + "Not finding the file you are looking for? Make sure it has been added to path.": "Aradığınız dosyayı bulamıyor musunuz? Yola eklendiğinden emin olun.", + "Select the executable to be used. The following list shows the executables found by UniGetUI": "Kullanılacak yürütülebilir dosyayı seçin. Aşağıdaki liste, UniGetUI tarafından bulunan yürütülebilir dosyaları göstermektedir", + "For security reasons, changing the executable file is disabled by default": "Güvenlik nedenlerinden dolayı, yürütülebilir dosyayı değiştirme varsayılan olarak devre dışıdır", + "Change this": "Bunu değiştir", + "Copy path": "Yolu kopyala", + "Current executable file:": "Geçerli yürütülebilir dosya:", + "Ignore packages from {pm} when showing a notification about updates": "Güncellemeler hakkında bir bildirim gösteren {pm} paketleri yoksay", + "Update security": "Güncelleme güvenliği", + "Use global setting": "Genel ayarı kullan", + "Minimum age for updates": "Güncellemeler için minimum süre", + "e.g. 10": "ör. 10", + "Custom minimum age (days)": "Özel minimum süre (gün)", + "{pm} does not provide release dates for its packages, so this setting will have no effect": "{pm} paketleri için yayın tarihi sağlamıyor, bu nedenle bu ayarın etkisi olmayacaktır", + "{pm} only provides release dates for some of its packages, so this setting will only apply to those packages": "{pm} yalnızca bazı paketleri için yayın tarihi sağlar, bu nedenle bu ayar yalnızca o paketler için geçerli olur", + "Override the global minimum update age for this package manager": "Bu paket yöneticisi için genel minimum güncelleme süresini geçersiz kıl", + "View {0} logs": "{0} günlükleri görüntüle", + "If Python cannot be found or is not listing packages but is installed on the system, ": "Python bulunamıyorsa veya sistemde kurulu olmasına rağmen paketleri listelemiyorsa, ", + "Advanced options": "Gelişmiş seçenekler", + "WinGet command-line tool": "WinGet komut satırı aracı", + "Choose which command-line tool UniGetUI uses for WinGet operations when the COM API is not used": "COM API kullanılmadığında UniGetUI'nin WinGet işlemleri için hangi komut satırı aracını kullanacağını seçin", + "WinGet COM API": "WinGet COM API", + "Choose whether UniGetUI can use the WinGet COM API before falling back to the command-line tool": "Komut satırı aracına geri dönmeden önce UniGetUI'nin WinGet COM API'sini kullanıp kullanamayacağını seçin", + "Reset WinGet": "WinGet'i sıfırla", + "This may help if no packages are listed": "Hiçbir paket listelenmemişse bu yardımcı olabilir", + "Force install location parameter when updating packages with custom locations": "Özel konumlarla paketleri güncellerken konum parametresini zorla yükle", + "Install Scoop": "Scoop'u yükle", + "Uninstall Scoop (and its packages)": "Scoop'u (ve paketlerini) kaldırın", + "Run cleanup and clear cache": "Temizlemeyi çalıştır ve önbelleği temizle", + "Run": "Çalıştır", + "Enable Scoop cleanup on launch": "Başlangıçta Scoop temizlemeyi etkinleştir", + "Default vcpkg triplet": "Varsayılan vcpkg üçlüsü", + "Change vcpkg root location": "vcpkg kök konumunu değiştir", + "Reset vcpkg root location": "vcpkg kök konumunu sıfırla", + "Open vcpkg root location": "vcpkg kök konumunu aç", + "Language, theme and other miscellaneous preferences": "Dil, tema ve diğer çeşitli tercihler", + "Show notifications on different events": "Farklı etkinliklere ilişkin bildirimleri göster", + "Change how UniGetUI checks and installs available updates for your packages": "UniGetUI'nin paketleriniz için mevcut güncellemeleri kontrol etme ve yükleme şeklini değiştirin", + "Automatically save a list of all your installed packages to easily restore them.": "Kolayca geri yüklemek için yüklü tüm paketlerinizin bir listesini otomatik olarak kaydedin.", + "Enable and disable package managers, change default install options, etc.": "Paket yöneticilerini etkinleştirin ve devre dışı bırakın, varsayılan kurulum seçeneklerini değiştirin, vb.", + "Internet connection settings": "İnternet bağlantı ayarları", + "Proxy settings, etc.": "Proxy ayarları vb.", + "Beta features and other options that shouldn't be touched": "Beta özellikleri ve diğer dokunulmaması gereken seçenekler", + "Reload sources": "Kaynakları yeniden yükle", + "Delete source": "Kaynağı sil", + "Known sources": "Bilinen kaynaklar", + "Update checking": "Güncelleme denetimi", + "Automatic updates": "Otomatik güncellemeler", + "Check for package updates periodically": "Paket güncellemelerin düzenli olarak kontrol et", + "Check for updates every:": "Güncellemeleri şu aralıklarla kontrol et:", + "Install available updates automatically": "Mevcut güncellemeleri otomatik olarak yükle", + "Do not automatically install updates when the network connection is metered": "Ağ bağlantısı sınırlı olduğunda güncellemeleri otomatik olarak yükleme", + "Do not automatically install updates when the device runs on battery": "Cihaz pille çalışırken güncellemeleri otomatik olarak yüklemeyin", + "Do not automatically install updates when the battery saver is on": "Pil tasarrufu açıkken güncellemeleri otomatik olarak yükleme", + "Only show updates that are at least the specified number of days old": "Yalnızca en az belirtilen gün sayısı kadar eski güncellemeleri göster", + "Warn me when the installer URL host changes between the installed version and the new version (WinGet only)": "Yükleyici URL ana bilgisayarı yüklü sürüm ile yeni sürüm arasında değiştiğinde beni uyar (yalnızca WinGet)", + "Change how UniGetUI handles install, update and uninstall operations.": "UniGetUI'nin yükleme, güncelleme ve kaldırma işlemlerini nasıl işlediğini değiştirin.", + "Navigation": "Gezinti", + "Check for UniGetUI updates": "UniGetUI güncellemelerini denetle", + "Quit UniGetUI": "UniGetUI'den çık", + "Filters": "Filtreler", + "Sources": "Kaynaklar", + "Search for packages to start": "Başlamak için paket ara", + "Select all": "Tümünü seç", + "Clear selection": "Seçileni/Seçilenleri iptal et", + "Instant search": "Yazarken ara", + "Distinguish between uppercase and lowercase": "Büyük ve küçük\n harf arasında ayrım yapın", + "Ignore special characters": "Özel karakterleri yoksay", + "Search mode": "Arama modu", + "Both": "Her ikisi", + "Exact match": "Tam eşleşme", + "Show similar packages": "Benzer paketleri göster", + "Loading": "Yükleniyor", + "Package": "Paket", + "More options": "Daha fazla seçenek", + "Order by:": "Sıralama:", + "Name": "İsim", + "Id": "İd", + "Ascendant": "Artan", + "Descendant": "Azalan", + "View modes": "Görünüm modları", + "Reload": "Yeniden yükle", + "Closed": "Kapalı", + "Ascending": "Artan", + "Descending": "Azalan", + "{0}: {1}, {2}": "{0}: {1}, {2}", + "Order by": "Sırala", + "No results were found matching the input criteria": "Giriş kriterlerine uygun sonuç bulunamadı", + "No packages were found": "Paket bulunamadı", + "Loading packages": "Paketler yükleniyor", + "Skip integrity checks": "Bütünlük kontrollerini atla", + "Download selected installers": "Seçilen yükleyicileri indir", + "Install selection": "Seçileni/Seçilenleri yükle", + "Install options": "Yükleme Ayarları", + "Add selection to bundle": "Seçileni/Seçilenleri paket grubuna ekle", + "Download installer": "Yükleyiciyi indir", + "Uninstall selection": "Seçileni/Seçilenleri kaldır", + "Uninstall options": "Kaldırma seçenekleri", + "Ignore selected packages": "Seçilen paketleri yoksay", + "Open install location": "Kurulum konumunu aç", + "Reinstall package": "Paketi yeniden yükle", + "Uninstall package, then reinstall it": "Paketi kaldırın, ardından yeniden yükleyin", + "Ignore updates for this package": "Bu paket için güncellemeleri yok say", + "WinGet malfunction detected": "WinGet arızası tespit edildi", + "It looks like WinGet is not working properly. Do you want to attempt to repair WinGet?": "Görünüşe göre WinGet düzgün çalışmıyor. WinGet'i onarmayı denemek istiyor musunuz?", + "Repair WinGet": "WinGet'i onar", + "Updates will no longer be ignored for {0}": "{0} için güncellemeler artık yoksayılmayacak", + "Updates are now ignored for {0}": "{0} için güncellemeler artık yoksayılıyor", + "Do not ignore updates for this package anymore": "Artık bu pakete ilişkin güncellemeleri göz ardı etmeyin", + "Add packages or open an existing package bundle": "Paketler ekleyin veya mevcut bir paket grubunu açın", + "Add packages to start": "Başlamak için paketleri ekleyin", + "The current bundle has no packages. Add some packages to get started": "Mevcut paket grubunda paket yok. Başlamak için birkaç paket ekleyin.", + "New": "Yeni", + "Save as": "Farklı kaydet", + "Create .ps1 script": ".ps1 komut dosyası oluştur", + "Remove selection from bundle": "Seçileni/Seçilenleri paket grubundan kaldır", + "Skip hash checks": "Karma kontrollerini atla", + "The package bundle is not valid": "Paket grubu geçerli değil", + "The bundle you are trying to load appears to be invalid. Please check the file and try again.": "Yüklemeye çalıştığınız paket grubu geçersiz görünüyor. Lütfen dosyayı kontrol edip tekrar deneyin.", + "Package bundle": "Paketleme grubu", + "Could not create bundle": "Paket grubu oluşturulamadı", + "The package bundle could not be created due to an error.": "Bir hata nedeniyle paket grubu oluşturulamadı.", + "Install script": "Komut dosyasını yükle", + "PowerShell script": "PowerShell betiği", + "The installation script saved to {0}": "Kurulum komut dosyası {0} konumuna kaydedildi", + "An error occurred": "Bir hata oluştu", + "An error occurred while attempting to create an installation script:": "Kurulum komut dosyası oluşturulmaya çalışılırken bir hata oluştu:", + "Hooray! No updates were found.": "Yaşasın! Her şey güncel!", + "Uninstall selected packages": "Seçili paketleri kaldır\n", + "Update selection": "Seçileni/Seçilenleri Güncelle", + "Update options": "Güncelleme seçenekleri", + "Uninstall package, then update it": "Paketi kaldırın, ardından güncelleyin", + "Uninstall package": "Paketi kaldır", + "Skip this version": "Bu sürümü atla", + "Pause updates for": "Bunun için güncellemeleri duraklat", + "User | Local": "Kullanıcı | Yerel", + "Machine | Global": "Makine | Genel", + "The default package manager for Debian/Ubuntu-based Linux distributions.
Contains: Debian/Ubuntu packages": "Debian/Ubuntu tabanlı Linux dağıtımları için varsayılan paket yöneticisi.
İçerir: Debian/Ubuntu paketleri", + "The Rust package manager.
Contains: Rust libraries and programs written in Rust": "Rust paket yöneticisi.
İçerir: Rust kitaplıkları ve Rust'ta yazılmış programlar", + "The classical package manager for windows. You'll find everything there.
Contains: General Software": "Windows için klasik paket yöneticisi. Orada her şeyi bulacaksınız.
İçerir: Genel Yazılım", + "The default package manager for RHEL/Fedora-based Linux distributions.
Contains: RPM packages": "RHEL/Fedora tabanlı Linux dağıtımları için varsayılan paket yöneticisi.
İçerir: RPM paketleri", + "A repository full of tools and executables designed with Microsoft's .NET ecosystem in mind.
Contains: .NET related tools and scripts": "Microsoft ile tasarlanmış araçlar ve yürütülebilir dosyalarla dolu bir depo.NET ekosistemini göz önünde bulundurun.
İçerikleri: .NET ile ilgili araçlar ve komut dosyaları", + "The universal Linux package manager for desktop applications.
Contains: Flatpak applications from configured remotes": "Masaüstü uygulamaları için evrensel Linux paket yöneticisi.
İçerir: Yapılandırılmış uzak kaynaklardan Flatpak uygulamaları", + "NuPkg (zipped manifest)": "NuPkg (sıkıştırılmış manifest)", + "The Missing Package Manager for macOS (or Linux).
Contains: Formulae, Casks": "macOS (veya Linux) için eksik paket yöneticisi.
İçerdikleri: Formulae, Casks", + "Node JS's package manager. Full of libraries and other utilities that orbit the javascript world
Contains: Node javascript libraries and other related utilities": "\"Node JS'in paket yöneticisi. Javascript dünyasının yörüngesinde dönen kütüphaneler ve diğer yardımcı programlarla dolu.
İçerik: Node JavaScript kütüphaneleri ve diğer ilgili yardımcı programlar\"", + "The default package manager for Arch Linux and its derivatives.
Contains: Arch Linux packages": "Arch Linux ve türevleri için varsayılan paket yöneticisi.
İçerir: Arch Linux paketleri", + "Python's library manager. Full of python libraries and other python-related utilities
Contains: Python libraries and related utilities": "Python'un kütüphane yöneticisi. Python kitaplıkları ve diğer python ile ilgili yardımcı programlarla dolu
İçerik: Python kitaplıkları ve ilgili yardımcı programlar", + "PowerShell's package manager. Find libraries and scripts to expand PowerShell capabilities
Contains: Modules, Scripts, Cmdlets": "PowerShell'in paket yöneticisi. PowerShell özelliklerini genişletmek için kitaplıkları ve komut dosyalarını bulun
İçerir: Modüller, Komut Dosyaları, Cmdlet'ler", + "extracted": "Çıkarıldı", + "Scoop package": "Scoop paketi", + "Great repository of unknown but useful utilities and other interesting packages.
Contains: Utilities, Command-line programs, General Software (extras bucket required)": "Bilinmeyen ama kullanışlı yardımcı programlar ve diğer ilginç paketlerden oluşan harika bir depo.
İçerik: Yardımcı Programlar, Komut Satırı Programları, Genel Yazılım (Ekstra olarak Bucket gerekir)", + "The universal Linux package manager by Canonical.
Contains: Snap packages from the Snapcraft store": "Canonical tarafından geliştirilen evrensel Linux paket yöneticisi.
İçerik: Snapcraft mağazasından Snap paketleri", + "library": "kütüphane", + "feature": "özellik", + "A popular C/C++ library manager. Full of C/C++ libraries and other C/C++-related utilities
Contains: C/C++ libraries and related utilities": "Popüler bir C/C++ kütüphane yöneticisi. C/C++ kitaplıkları ve diğer C/C++ ile ilgili yardımcı programlarla dolu
İçerikler: C/C++ kitaplıkları ve ilgili yardımcı programlar", + "option": "seçenek", + "This package cannot be installed from an elevated context.": "Bu paket yükseltilmiş bir bağlamdan yüklenemez.", + "Please run UniGetUI as a regular user and try again.": "Lütfen UniGetUI'yi normal kullanıcı olarak çalıştırın ve tekrar deneyin.", + "Please check the installation options for this package and try again": "Lütfen bu paketin yükleme seçeneklerini kontrol edip tekrar deneyin.", + "Microsoft's official package manager. Full of well-known and verified packages
Contains: General Software, Microsoft Store apps": "Microsoft'un resmi paket yöneticisi. Tanınmış ve doğrulanmış paketlerle dolu
İçerik: Genel Yazılım, Microsoft Mağazası uygulamaları", + "Local PC": "Yerel bilgisayar", + "Android Subsystem": "Android Alt Sistemi", + "Operation on queue (position {0})...": "Kuyrukta işlem (konum {0})...", + "Click here for more details": "Daha fazla bilgi için buraya tıklayın", + "Operation canceled by user": "İşlem kullanıcı tarafından iptal edildi", + "Running PreOperation ({0}/{1})...": "PreOperation çalıştırılıyor ({0}/{1})...", + "PreOperation {0} out of {1} failed, and was tagged as necessary. Aborting...": "{1} içinden PreOperation {0} başarısız oldu ve gerekli olarak işaretlenmişti. İptal ediliyor...", + "PreOperation {0} out of {1} finished with result {2}": "{1} içinden PreOperation {0}, {2} sonucu ile tamamlandı", + "Starting operation...": "Çalışmaya başlıyor...", + "Running PostOperation ({0}/{1})...": "PostOperation çalıştırılıyor ({0}/{1})...", + "PostOperation {0} out of {1} failed, and was tagged as necessary. Aborting...": "{1} içinden PostOperation {0} başarısız oldu ve gerekli olarak işaretlenmişti. İptal ediliyor...", + "PostOperation {0} out of {1} finished with result {2}": "{1} içinden PostOperation {0}, {2} sonucu ile tamamlandı", + "{package} installer download": "{package} yükleyi̇ci̇ i̇ndi̇r", + "{0} installer is being downloaded": "{0} yükleyici indiriliyor", + "Download succeeded": "İndirme başarılı", + "{package} installer was downloaded successfully": "{package} yükleyici başarıyla indirildi", + "Download failed": "İndir başarısız", + "{package} installer could not be downloaded": "{package} yükleyici indirilemedi", + "{package} Installation": "{package} Yükleniyor", + "{0} is being installed": "{0} kuruluyor", + "Installation succeeded": "Kurulum başarılı", + "{package} was installed successfully": "{package} başarıyla yüklendi", + "Installation failed": "Yükleme başarısız", + "{package} could not be installed": "{package} yüklenemedi", + "{package} Update": "{package} Güncelleştir", + "Update succeeded": "Güncelleme başarılı", + "{package} was updated successfully": "{package} başarıyla güncellendi", + "Update failed": "Güncelleme işlemi başarısız", + "{package} could not be updated": "{package} güncellenemedi", + "{package} Uninstall": "{package} Kaldır", + "{0} is being uninstalled": "{0} kaldırılıyor", + "Uninstall succeeded": "Kaldırma başarılı", + "{package} was uninstalled successfully": "{package} başarıyla kaldırıldı", + "Uninstall failed": "Kaldırma başarısız", + "{package} could not be uninstalled": "{package} kaldırılamadı", + "Adding source {source}": "Kaynak ekleniyor {source}", + "Adding source {source} to {manager}": "Kaynak {source} {manager}' a ekleniyor", + "Source added successfully": "Kaynak başarıyla eklendi", + "The source {source} was added to {manager} successfully": "{source} kaynağı {manager} yöneticisine başarıyla eklendi", + "Could not add source": "Kaynak eklenilemedi", + "Could not add source {source} to {manager}": "{source} kaynağı {manager} yöneticisine eklenemedi", + "Removing source {source}": "{source} kaynağından kaldırılıyor", + "Removing source {source} from {manager}": "{source} kaynağı {manager} kaynağından kaldırılıyor", + "Source removed successfully": "Kaynak başarıyla kaldırıldı", + "The source {source} was removed from {manager} successfully": "{source} kaynağı {manager} tarafından başarıyla kaldırıldı", + "Could not remove source": "Kaynak kaldırılamadı", + "Could not remove source {source} from {manager}": "{source} kaynağı {manager} kaynağından kaldırılamadı", + "The package manager \"{0}\" was not found": "\"{0}\" paket yöneticisi bulunamadı", + "The package manager \"{0}\" is disabled": "\"{0}\" paket yöneticisi devre dışı", + "There is an error with the configuration of the package manager \"{0}\"": "\"{0}\" paket yöneticisinin yapılandırmasında bir hata var", + "The package \"{0}\" was not found on the package manager \"{1}\"": "\"{0}\" paketi \"{1}\" paket yöneticisinde bulunamadı", + "{0} is disabled": "{0} devre dışı", + "{0} weeks": "{0} hafta", + "1 month": "1 ay", + "{0} months": "{0} ay", + "Something went wrong": "Bir sorun oluştu", + "An interal error occurred. Please view the log for further details.": "Bir hata oluştu. Daha fazla bilgi için lütfen günlüğe bakın.", + "No applicable installer was found for the package {0}": "Paket için geçerli bir yükleyici bulunamadı ({0})", + "Integrity checks will not be performed during this operation": "Bu işlem sırasında bütünlük kontrolleri yapılmayacak", + "This is not recommended.": "Bu önerilmez.", + "Run now": "Şimdi başlat", + "Run next": "Sonra çalış", + "Run last": "Son çalış", + "Show in explorer": "Dosya gezgininde göster", + "Checked": "İşaretli", + "Unchecked": "İşaretlenmemiş", + "This package is already installed": "Paket zaten kurulmuş", + "This package can be upgraded to version {0}": "Bu paket {0} sürümüne yükseltilebilir", + "Updates for this package are ignored": "Bu paketin güncellemeleri yoksayıldı", + "This package is being processed": "Bu paket işleniyor", + "This package is not available": "Bu paket mevcut değil", + "Select the source you want to add:": "Eklemek istediğiniz kaynağı seçin:", + "Source name:": "Kaynak adı:", + "Source URL:": "Kaynak URL'si:", + "An error occurred when adding the source: ": "Kaynak eklenirken bir hata oluştu:", + "Package management made easy": "Paket yönetimi kolaylaştırıldı", + "version {0}": "sürüm {0}", + "[RAN AS ADMINISTRATOR]": "YÖNETİCİ OLARAK ÇALIŞTIR", + "Portable mode": "Taşınabilir Mod", + "DEBUG BUILD": "HATA AYIKLAMA YAPISI", + "Here you can change UniGetUI's behaviour regarding the following shortcuts. Checking a shortcut will make UniGetUI delete it if if gets created on a future upgrade. Unchecking it will keep the shortcut intact": "Burada UniGetUI'nin aşağıdaki kısayollara ilişkin davranışını değiştirebilirsiniz. Bir kısayolun kontrol edilmesi, eğer gelecekteki bir yükseltmede oluşturulursa UniGetUI'nin onu silmesini sağlayacaktır. İşaretini kaldırmak kısayolu olduğu gibi koruyacaktır", + "Manual scan": "Manuel tarama", + "Existing shortcuts on your desktop will be scanned, and you will need to pick which ones to keep and which ones to remove.": "Masaüstünüzde bulunan kısayollar taranacak ve hangilerini tutacağınızı, hangilerini kaldıracağınızı seçmeniz gerekecektir.", + "Delete?": "Silinsin mi?", + "I understand": "Anladım", + "Chocolatey setup changed": "Chocolatey kurulumu değişti", + "UniGetUI no longer includes its own private Chocolatey installation. A legacy UniGetUI-managed Chocolatey installation was detected for this user profile, but system Chocolatey was not found. Chocolatey will stay unavailable in UniGetUI until Chocolatey is installed on the system and UniGetUI is restarted. Applications previously installed through UniGetUI's bundled Chocolatey may still appear under other sources such as Local PC or WinGet.": "UniGetUI artık kendi özel Chocolatey kurulumunu içermemektedir. Bu kullanıcı profili için eski bir UniGetUI tarafından yönetilen Chocolatey kurulumu algılandı, ancak sistemde Chocolatey bulunamadı. Chocolatey, sisteme kurulup UniGetUI yeniden başlatılana kadar UniGetUI'da kullanılamaz durumda kalacaktır. Daha önce UniGetUI'nın paketlenmiş Chocolatey'si aracılığıyla kurulan uygulamalar, Yerel PC veya WinGet gibi diğer kaynaklarda görünmeye devam edebilir.", + "NOTE: This troubleshooter can be disabled from UniGetUI Settings, on the WinGet section": "NOT: Bu sorun giderici, WinGet bölümündeki UniGetUI Ayarları'ndan devre dışı bırakılabilir", + "Restart": "Yeniden başlat", + "Are you sure you want to delete all shortcuts?": "Tüm kısayolları silmek istediğinizden emin misiniz?", + "Any new shorcuts created during an install or an update operation will be deleted automatically, instead of showing a confirmation prompt the first time they are detected.": "Bir yükleme veya güncelleme işlemi sırasında oluşturulan yeni kısayollar, ilk algılandıklarında bir onay istemi göstermek yerine otomatik olarak silinecektir.", + "Any shorcuts created or modified outside of UniGetUI will be ignored. You will be able to add them via the {0} button.": "UniGetUI dışında oluşturulan veya değiştirilen herhangi bir kısayol göz ardı edilecektir. Bunları {0} düğme aracılığıyla ekleyebileceksiniz.", + "Are you really sure you want to enable this feature?": "Bu özelliği gerçekten etkinleştirmek istiyor musunuz?", + "No new shortcuts were found during the scan.": "Tarama sırasında yeni kısayol bulunmadı.", + "How to add packages to a bundle": "Bir paket grubuna paketler nasıl eklenir", + "In order to add packages to a bundle, you will need to: ": "Bir paket grubuna paket eklemek için şunları yapmanız gerekir:", + "1. Navigate to the \"{0}\" or \"{1}\" page.": "1. \"{0}\" veya \"{1}\" sayfasına gidin.", + "2. Locate the package(s) you want to add to the bundle, and select their leftmost checkbox.": "2. Paket grubuna eklemek istediğiniz paketi/paketleri bulun ve en soldaki onay kutusunu seçin.", + "3. When the packages you want to add to the bundle are selected, find and click the option \"{0}\" on the toolbar.": "3. Paket grubuna eklemek istediğiniz paketler seçiliyken araç çubuğunda \"{0}\" seçeneğini bulup tıklayın.", + "4. Your packages will have been added to the bundle. You can continue adding packages, or export the bundle.": "4. Paketleriniz paket grubuna eklenmiş olacak. Paket eklemeye devam edebilir veya paket grubunu dışa aktarabilirsiniz.", + "Which backup do you want to open?": "Hangi yedeği açmak istiyorsunuz?", + "Select the backup you want to open. Later, you will be able to review which packages you want to install.": "Açmak istediğiniz yedeği seçin. Daha sonra, hangi paketleri yüklemek istediğinizi inceleyebileceksiniz.", + "There are ongoing operations. Quitting UniGetUI may cause them to fail. Do you want to continue?": "Devam eden işlemler var. UniGetUI'den çıkmak başarısız olmalarına neden olabilir. Devam etmek ister misiniz?", + "UniGetUI or some of its components are missing or corrupt.": "UniGetUI veya bazı bileşenleri eksik veya bozuk.", + "It is strongly recommended to reinstall UniGetUI to adress the situation.": "Durumu ele almak için UniGetUI'yi yeniden yüklemeniz şiddetle tavsiye edilir.", + "Refer to the UniGetUI Logs to get more details regarding the affected file(s)": "Etkilenen dosya(lar) hakkında daha fazla bilgi edinmek için UniGetUI Günlüklerine bakın", + "Integrity checks can be disabled from the Experimental Settings": "Bütünlük kontrolleri Deney Ayarlarından devre dışı bırakılabilir", + "Repair UniGetUI": "UniGetUI'yi onar", + "Live output": "Canlı çıkış", + "This package bundle had some settings that are potentially dangerous, and may be ignored by default.": "Bu paket paketinde potansiyel olarak tehlikeli olabilecek ve varsayılan olarak göz ardı edilebilecek bazı ayarlar vardı.", + "Entries that show in YELLOW will be IGNORED.": "SARI renkte gösterilen girdiler YOK SAYILACAKTIR.", + "Entries that show in RED will be IMPORTED.": "KIRMIZI renkte gösterilen girdiler ÖNEMLİDİR.", + "You can change this behavior on UniGetUI security settings.": "Bu davranışı UniGetUI güvenlik ayarlarından değiştirebilirsiniz.", + "Open UniGetUI security settings": "UniGetUI güvenlik ayarlarını açın", + "Should you modify the security settings, you will need to open the bundle again for the changes to take effect.": "Güvenlik ayarlarında değişiklik yapmanız durumunda, değişikliklerin geçerli olması için paketi tekrar açmanız gerekecektir.", + "Details of the report:": "Raporun detayları:", + "Are you sure you want to create a new package bundle? ": "Yeni bir paket grubu oluşturmak istediğinizden emin misiniz?", + "Any unsaved changes will be lost": "Kaydedilmemiş değişiklikler kaybolacak", + "Warning!": "Uyarı!", + "For security reasons, custom command-line arguments are disabled by default. Go to UniGetUI security settings to change this. ": "Güvenlik nedeniyle, özel komut satırı argümanları varsayılan olarak devre dışıdır. Bunu değiştirmek için UniGetUI güvenlik ayarlarına gidin.", + "Change default options": "Varsayılan seçenekleri değiştir", + "Ignore future updates for this package": "Bu paket için gelecekteki güncellemeleri yoksay", + "For security reasons, pre-operation and post-operation scripts are disabled by default. Go to UniGetUI security settings to change this. ": "Güvenlik nedeniyle, işlem öncesi ve işlem sonrası komut dosyaları varsayılan olarak devre dışıdır. Bunu değiştirmek için UniGetUI güvenlik ayarlarına gidin.", + "You can define the commands that will be run before or after this package is installed, updated or uninstalled. They will be run on a command prompt, so CMD scripts will work here.": "Bu paketin yüklenmesinden, güncellenmesinden veya kaldırılmasından önce veya sonra çalıştırılacak komutları tanımlayabilirsiniz. Komut isteminde çalıştırılacaklardır, bu nedenle CMD komut dosyaları burada çalışacaktır.", + "Change this and unlock": "Bunu değiştir ve kilidini aç", + "{0} Install options are currently locked because {0} follows the default install options.": "{0} varsayılan yükleme seçeneklerini takip ettiği için {0} yükleme seçenekleri şu anda kilitli.", + "Unset or unknown": "Ayarlanmamış veya bilinmiyor", + "This package has no screenshots or is missing the icon? Contrbute to UniGetUI by adding the missing icons and screenshots to our open, public database.": "Bu paketin ekran görüntüsü yok veya simgesi eksik mi? Eksik simgeleri ve ekran görüntülerini herkese açık veritabanımıza ekleyerek UniGetUI'ye katkıda bulunun.", + "Become a contributor": "Katkıda bulunan olun", + "Update to {0} available": "{0} Güncelleme mevcut", + "Reinstall": "Yeniden yükle", + "Installer not available": "Yükleyici kullanılamıyor", + "Version:": "Versiyon:", + "UniGetUI Version {0}": "UniGetUI Sürüm {0}", + "Performing backup, please wait...": "Yedekleme gerçekleştiriliyor, lütfen bekleyin...", + "An error occurred while logging in: ": "Giriş yaparken bir hata oluştu:", + "Fetching available backups...": "Kullanılabilir yedekler getiriliyor...", + "Done!": "Tamam!", + "The cloud backup has been loaded successfully.": "Bulut yedeklemesi başarıyla yüklendi.", + "An error occurred while loading a backup: ": "Yedekleme yüklenirken bir hata oluştu:", + "Backing up packages to GitHub Gist...": "Paketler GitHub Gist'e yedekleniyor...", + "Backup Successful": "Yedekleme başarılı", + "The cloud backup completed successfully.": "Yedekleme başarılı şekilde tamamlandı.", + "Could not back up packages to GitHub Gist: ": "Paketler GitHub Gist'e yedeklenemedi:", + "It is not guaranteed that the provided credentials will be stored safely, so you may as well not use the credentials of your bank account": "Sağlanan kimlik bilgilerinin güvenli bir şekilde saklanacağı garanti edilmez, bu nedenle banka hesabınızın kimlik bilgilerini kullanmamanız daha iyi olur", + "Enable the automatic WinGet troubleshooter": "Otomatik WinGet sorun gidericisini etkinleştirin", + "Add updates that fail with a 'no applicable update found' to the ignored updates list": "'Uygulanabilir güncelleme bulunamadı' uyarısıyla başarısız olan güncellemeleri yoksayılan güncellemeler listesine ekleyin", + "Invalid selection": "Geçersiz seçim", + "No package was selected": "Hiçbir paket seçilmedi", + "More than 1 package was selected": "1'den fazla paket seçildi", + "List": "Liste", + "Grid": "Izgara", + "Icons": "Simgeler", + "\"{0}\" is a local package and does not have available details": "\"{0}\" yerel bir pakettir ve kullanılabilir ayrıntılara sahip değildir", + "\"{0}\" is a local package and is not compatible with this feature": "\"{0}\" yerel bir pakettir ve bu özellik ile uyumlu değildir", + "Add packages to bundle": "Paketleri paket grubuna ekle", + "Preparing packages, please wait...": "Paketler hazırlanıyor, lütfen bekleyin...", + "Loading packages, please wait...": "Paketler yükleniyor, lütfen bekleyin...", + "Saving packages, please wait...": "Paketler kaydediliyor, lütfen bekleyin...", + "The bundle was created successfully on {0}": "Paket {0} tarihinde başarıyla oluşturuldu", + "User profile": "Kullanıcı profili", + "Error": "Hata", + "Log in failed: ": "Oturum açma başarısız: ", + "Log out failed: ": "Çıkış başarısız oldu: ", + "Package backup settings": "Paket yedekleme ayarları", + "Package managers": "Paket Yöneticileri", + "Manage UniGetUI autostart behaviour from the Settings app": "UniGetUI otomatik başlatma davranışını yönet", + "Choose how many operations shoulds be performed in parallel": "Aynı anda kaç işlemin yürütüleceğini seçin", + "Something went wrong while launching the updater.": "Güncelleyici başlatılırken bir şeyler ters gitti.", + "Please try again later": "Lütfen daha sonra tekrar deneyin", + "Show the release notes after UniGetUI is updated": "UniGetUI güncellendikten sonra sürüm notlarını göster" +} diff --git a/src/Languages/lang_uk.json b/src/Languages/lang_uk.json new file mode 100644 index 0000000..9ed02a9 --- /dev/null +++ b/src/Languages/lang_uk.json @@ -0,0 +1,851 @@ +{ + "{0} of {1} operations completed": "Завершено {0} з {1} операцій", + "{0} is now {1}": "{0} тепер {1}", + "Enabled": "Увімкнено", + "Disabled": "Вимкнено", + "Privacy": "Конфіденційність", + "Hide my username from the logs": "Приховати моє ім'я у журналах", + "Replaces your username with **** in the logs. Restart UniGetUI to also hide it from already-recorded entries.": "Замінює ваше ім'я на **** у журналах. Перезапустіть UniGetUI, щоб також приховати його у вже записаних записах.", + "Your last update attempt did not complete.": "Остання спроба оновлення не завершилася.", + "UniGetUI could not confirm whether the update succeeded. Open the log to see what happened.": "UniGetUI не вдалося підтвердити, чи оновлення виконано успішно. Відкрийте журнал, щоб переглянути, що сталося.", + "View log": "Переглянути журнал", + "The installer reported success but did not restart UniGetUI.": "Інсталятор повідомив про успіх, але не перезапустив UniGetUI.", + "The installer failed to initialize.": "Не вдалося ініціалізувати інсталятор.", + "Setup was canceled before installation began.": "Встановлення було скасовано до його початку.", + "A fatal error occurred during the preparation phase.": "Під час етапу підготовки сталася критична помилка.", + "A fatal error occurred during installation.": "Під час встановлення сталася критична помилка.", + "Installation was canceled while in progress.": "Встановлення було скасовано під час виконання.", + "The installer was terminated by another process.": "Інсталятор було завершено іншим процесом.", + "The preparation phase determined the installation cannot proceed.": "На етапі підготовки визначено, що встановлення не може продовжуватися.", + "The installer could not start. UniGetUI may already be running, or you do not have permission to install.": "Не вдалося запустити інсталятор. Можливо, UniGetUI вже запущено або у вас немає дозволу на встановлення.", + "Unexpected installer error.": "Неочікувана помилка інсталятора.", + "We are checking for updates.": "Ми перевіряємо оновлення.", + "Please wait": "Будь ласка, зачекайте", + "Great! You are on the latest version.": "Чудово! У вас найновіша версія.", + "There are no new UniGetUI versions to be installed": "Немає більш нової версії UniGetUI для встановлення", + "UniGetUI version {0} is being downloaded.": "UniGetUI версії {0} завантажується.", + "This may take a minute or two": "Це може зайняти хвилину або дві", + "The installer authenticity could not be verified.": "Автентичність інсталятора неможливо перевірити. ", + "The update process has been aborted.": "Процес оновлення був перерваний", + "Auto-update is not yet available on this platform.": "Автоматичне оновлення поки що недоступне на цій платформі.", + "Please update UniGetUI manually.": "Будь ласка, оновіть UniGetUI вручну.", + "An error occurred when checking for updates: ": "Виникла помилка при перевірці оновлень:", + "The updater could not be launched.": "Не вдалося запустити засіб оновлення.", + "The operating system did not start the installer process.": "Операційна система не запустила процес інсталятора.", + "UniGetUI is being updated...": "UniGetUI оновлюється…", + "Update installed.": "Оновлення встановлено.", + "UniGetUI was updated successfully, but this running copy was not replaced. This usually means you are running a development build. Close this copy and start the newly-installed version to finish.": "UniGetUI було успішно оновлено, але цю запущену копію не було замінено. Зазвичай це означає, що ви використовуєте збірку для розробки. Закрийте цю копію та запустіть щойно встановлену версію, щоб завершити оновлення.", + "The update could not be applied.": "Не вдалося застосувати оновлення.", + "Installer exit code {0}: {1}": "Код виходу інсталятора {0}: {1}", + "Update cancelled.": "Оновлення скасовано.", + "Authentication was cancelled.": "Автентифікацію скасовано.", + "Installer exit code {0}": "Код виходу інсталятора {0}", + "Operation in progress": "Операція у процесі", + "Please wait...": "Будь ласка, зачекайте...", + "Success!": "Успіх!", + "Failed": "Не вдалося", + "An error occurred while processing this package": "Виникла помилка при обробці цього пакету", + "Installer": "Інсталятор", + "Executable": "Виконуваний файл", + "MSI": "MSI", + "Compressed file": "Стиснений файл", + "MSIX": "MSIX", + "WinGet was repaired successfully": "WinGet був успішно відновлений", + "It is recommended to restart UniGetUI after WinGet has been repaired": "Рекомендовано перезапустити UniGetUI після того, як WinGet буде відновлено", + "WinGet could not be repaired": "Неможливо відновити WinGet", + "An unexpected issue occurred while attempting to repair WinGet. Please try again later": "Виникла неочікувана проблема при намаганні відновити WinGet. Будь ласка, спробуйте пізніше.", + "Log in to enable cloud backup": "Увійдіть, щоб увімкнути резервне копіювання в хмару", + "Backup Failed": "Резервне копіювання не вдалося", + "Downloading backup...": "Завантажуємо резервну копію…", + "An update was found!": "Знайдено оновлення!", + "{0} can be updated to version {1}": "{0} можна оновити до версії {1}", + "Updates found!": "Оновлення знайдено!", + "{0} packages can be updated": "{0} пакетів можна оновити", + "{0} is being updated to version {1}": "{0} був оновлений до версії {1}", + "{0} packages are being updated": "{0} пакетів оновлюється", + "You have currently version {0} installed": "У вас встановлено версію {0} ", + "Desktop shortcut created": "Створено ярлик на робочому столі", + "UniGetUI has detected a new desktop shortcut that can be deleted automatically.": "UniGetUI виявив новий ярлик на робочому столі, який можна автоматично видалити.", + "{0} desktop shortcuts created": "Створено {0} ярликів на робочому столі.", + "UniGetUI has detected {0} new desktop shortcuts that can be deleted automatically.": "UniGetUI виявив {0} нових ярликів на робочому столі, які можна автоматично видалити.", + "Attention required": "Потрібна ваша увага", + "Restart required": "Потрібне перезавантаження", + "1 update is available": "1 оновлення доступне", + "{0} updates are available": "{0} доступні оновлення", + "Everything is up to date": "Все оновлено", + "Discover Packages": "Доступні пакети", + "Available Updates": "Доступні оновлення", + "Installed Packages": "Встановлені пакети", + "UniGetUI Version {0} by Devolutions": "UniGetUI версії {0} від Devolutions", + "Show UniGetUI": "Показати UniGetUI", + "Quit": "Вийти", + "Are you sure?": "Ви впевнені?", + "Do you really want to uninstall {0}?": "Ви дійсно хочете видалити {0}?", + "Do you really want to uninstall the following {0} packages?": "Ви дійсно хочете видалити наступні {0} пакетів?", + "No": "Ні", + "Yes": "Так", + "Partial": "Частково", + "View on UniGetUI": "Відкрити у UniGetUI", + "Update": "Оновити", + "Open UniGetUI": "Відкрити UniGetUI", + "Update all": "Оновити все", + "Update now": "Оновити зараз", + "Installer host changed since the installed version.\n": "Хост інсталятора змінився порівняно зі встановленою версією.\n", + "This package is on the queue": "Цей пакет в черзі", + "installing": "встановлення", + "updating": "оновлення", + "uninstalling": "видалення", + "installed": "встановлено", + "Retry": "Повторити", + "Install": "Встановити", + "Uninstall": "Видалити", + "Open": "Відкрити", + "Operation profile:": "Профіль операції:", + "Follow the default options when installing, upgrading or uninstalling this package": "Дотримуватися налаштувань за замовченням при встановленні, оновленні й видаленні цього пакета ", + "The following settings will be applied each time this package is installed, updated or removed.": "Наступні налаштування будуть застосовані кожного разу коли цей пакет встановлюється, оновлюється чи видаляється.", + "Version to install:": "Версія для встановлення:", + "Architecture to install:": "Архітектура для встановлення:", + "Installation scope:": "Рівень встановлення:", + "Install location:": "Місце встановлення:", + "Select": "Вибрати", + "Reset": "Скинути", + "Custom install arguments:": "Користувацькі аргументи встановлення:", + "Custom update arguments:": "Користувацькі аргументи оновлення:", + "Custom uninstall arguments:": "Користувацькі аргументи видалення:", + "Pre-install command:": "Команда перед встановленням:", + "Post-install command:": "Команда після встановлення:", + "Abort install if pre-install command fails": "Відмінити встановлення, якщо команда перед встановленням завершиться невдало", + "Pre-update command:": "Команда перед оновленням:", + "Post-update command:": "Команда після оновлення:", + "Abort update if pre-update command fails": "Відмінити оновлення, якщо команда перед оновленням завершиться невдало", + "Pre-uninstall command:": "Команда перед видаленням:", + "Post-uninstall command:": "Команда після видалення:", + "Abort uninstall if pre-uninstall command fails": "Відмінити видалення, якщо команда перед видаленням завершиться невдало", + "Command-line to run:": "Команда для запуску:", + "Save and close": "Зберегти та закрити", + "General": "Загальні", + "Architecture & Location": "Архітектура й розташування", + "Command-line": "Командний рядок", + "Close apps": "Закрити програми", + "Pre/Post install": "Перед/після встановлення", + "Select the processes that should be closed before this package is installed, updated or uninstalled.": "Виберіть процеси, які мають бути закрити до того як цей пакет буде встановлено, оновлено чи видалено.", + "Write here the process names here, separated by commas (,)": "Введіть імена процесів тут, розділивши комами (,)", + "Try to kill the processes that refuse to close when requested to": "Спробувати завершити процес, який відмовляється закритися за запитом", + "Run as admin": "У режимі адміна", + "Interactive installation": "Інтерактивна інсталяція", + "Skip hash check": "Не перевіряти хеш", + "Uninstall previous versions when updated": "Видалити попередні версії при оновленні", + "Skip minor updates for this package": "Пропустити мінорні оновлення", + "Automatically update this package": "Автоматично оновлювати цей пакет", + "{0} installation options": "Варіанти встановлення {0}", + "Latest": "Остання", + "PreRelease": "Підготовча", + "Default": "За замовчуванням", + "Manage ignored updates": "Керування ігнорованими оновленнями", + "The packages listed here won't be taken in account when checking for updates. Double-click them or click the button on their right to stop ignoring their updates.": "Перераховані тут пакети не враховуватимуться під час перевірки оновлень. Двічі клацніть по них або натисніть кнопку праворуч, щоб перестати ігнорувати їхні оновлення.", + "Reset list": "Скинути список", + "Do you really want to reset the ignored updates list? This action cannot be reverted": "Ви дійсно хочете скинути список ігнорованих оновлень? Цю дію неможливо скасувати", + "No ignored updates": "Немає ігнорованих оновлень", + "Package Name": "Ім'я пакета", + "Package ID": "ID пакета", + "Ignored version": "Ігнорована версія", + "New version": "Нова версія", + "Source": "Джерело", + "All versions": "Всі версії", + "Unknown": "Невідомо", + "Up to date": "Найновіший", + "Package {name} from {manager}": "Пакунок {name} від {manager}", + "Remove {0} from ignored updates": "Видалити {0} зі списку ігнорованих оновлень", + "Cancel": "Скасувати", + "Administrator privileges": "Права адміністратора", + "This operation is running with administrator privileges.": "Ця операція запущена з правами адміністратора.", + "Interactive operation": "Інтерактивна операція", + "This operation is running interactively.": "Ця операція запущена інтерактивно.", + "You will likely need to interact with the installer.": "Вірогідно, вам доведеться взаємодіяти за інсталятором.", + "Integrity checks skipped": "Перевірка хешу пропущена", + "Integrity checks will not be performed during this operation.": "Під час цієї операції перевірки цілісності не виконуватимуться.", + "Proceed at your own risk.": "Продовжуйте на власний ризик.", + "Close": "Закрити", + "Loading...": "Завантаження...", + "Installer SHA256": "SHA256 інсталятора", + "Homepage": "Домашня сторінка", + "Author": "Автор", + "Publisher": "Видавець", + "License": "Ліцензія", + "Manifest": "Маніфест", + "Installer Type": "Тип інсталятора", + "Size": "Розмір", + "Installer URL": "URL інсталятора", + "Last updated:": "Останнє оновлення:", + "Release notes URL": "URL нотаток до випуску", + "Package details": "Інформація про пакет", + "Dependencies:": "Залежності:", + "Release notes": "Нотатки про випуск", + "Screenshots": "Знімки екрана", + "This package has no screenshots or is missing the icon? Contribute to UniGetUI by adding the missing icons and screenshots to our open, public database.": "Цей пакет не має знімків екрана або для нього відсутня піктограма? Допоможіть UniGetUI, додавши відсутні піктограми та знімки екрана до нашої відкритої публічної бази даних.", + "Version": "Версія", + "Install as administrator": "Встановити від імені адміністратора", + "Update to version {0}": "Оновити до версії {0}", + "Installed Version": "Встановлена версія", + "Update as administrator": "Оновити від імені адміністратора", + "Interactive update": "Інтерактивне оновлення", + "Uninstall as administrator": "Видаліть як адміністратор", + "Interactive uninstall": "Інтерактивне видалення", + "Uninstall and remove data": "Видалити разом з даними", + "Not available": "Не доступно", + "Installer SHA512": "Хеш SHA512", + "Unknown size": "Розмір невідомий", + "No dependencies specified": "Жодних залежностей не вказано", + "mandatory": "обов'язкова", + "optional": "необов'язкова", + "UniGetUI {0} is ready to be installed.": "UniGetUI {0} готовий для встановлення.", + "The update process will start after closing UniGetUI": "Процес оновлення почнеться після закриття UniGetUI", + "UniGetUI has been ran as administrator, which is not recommended. When running UniGetUI as administrator, EVERY operation launched from UniGetUI will have administrator privileges. You can still use the program, but we highly recommend not running UniGetUI with administrator privileges.": "UniGetUI було запущено від імені адміністратора, що не рекомендується. Якщо запускати UniGetUI від імені адміністратора, КОЖНА операція, запущена з UniGetUI, матиме права адміністратора. Ви все одно можете користуватися програмою, але ми наполегливо рекомендуємо не запускати UniGetUI від імені адміністратора.", + "Share anonymous usage data": "Збір анонімних даних про використання", + "UniGetUI collects anonymous usage data in order to improve the user experience.": "UniGetUI збирає анонімні дані про використання, щоб покращити користувацький досвід.", + "Accept": "Погоджуюсь", + "Software Updates": "Оновлення програм", + "Package Bundles": "Колекції пакетів", + "Settings": "Налаштування", + "Package Managers": "Менеджери пакетів", + "UniGetUI Log": "Журнал UniGetUI", + "Package Manager logs": "Журнали менеджера пакетів", + "Operation history": "Історія операцій", + "Help": "Допомога", + "UniGetUI": "UniGetUI", + "You have installed UniGetUI Version {0}": "У вас встановлена UniGetUI версії {0}", + "Disclaimer": "Відмова від відповідальності", + "UniGetUI is developed by Devolutions and is not affiliated with any of the compatible package managers.": "UniGetUI розробляється Devolutions і не пов'язаний з жодним із сумісних менеджерів пакетів.", + "UniGetUI wouldn't have been possible without the help of the contributors. Thank you all 🥳": "UniGetUI було б неможливо створити без допомоги учасників. Дякую вам всім 🥳", + "UniGetUI uses the following libraries. Without them, UniGetUI wouldn't have been possible.": "UniGetUI використовує наступні бібліотеки. Без них UniGetUI було б неможливо створити.", + "{0} homepage": "Cторінка {0}", + "UniGetUI has been translated to more than 40 languages thanks to the volunteer translators. Thank you 🤝": "UniGetUI був перекладений на більше ніж 40 мов дякуючи добровільним перекладачам. Дякую 🤝", + "Verbose": "Детальний", + "1 - Errors": "1 - Помилки", + "2 - Warnings": "2 - Застереження", + "3 - Information (less)": "3 - Інформація (менше)", + "4 - Information (more)": "4 - Інформація (більше)", + "5 - information (debug)": "5 - Інформація (налагодження)", + "Warning": "Увага", + "The following settings may pose a security risk, hence they are disabled by default.": "Наступні налаштування можуть становити загрозу безпеці, тож вони відключені за замовчуванням.", + "Enable the settings below if and only if you fully understand what they do, and the implications they may have.": "Вмикайте налаштування нижче ТОДІ Й ЛИШЕ ТОДІ, коли ви повністю розумієте що вони роблять і які наслідки та небезпеки вони можуть нести.", + "The settings will list, in their descriptions, the potential security issues they may have.": "Кожне налаштування має опис потенційний ризиків, які воно може нести.", + "The backup will include the complete list of the installed packages and their installation options. Ignored updates and skipped versions will also be saved.": "Резервна копія буде включати в себе повний список усіх встановлених пакетів та вибрані варіанти їх встановлення. Проігноровані оновлення та пропущені версії також будуть збережені.", + "The backup will NOT include any binary file nor any program's saved data.": "Резервна копія НЕ буде включати в собі жодних файлів програм або їх збережених даних.", + "The size of the backup is estimated to be less than 1MB.": "Очікуваний розмір резервної копії — менше 1 МБ.", + "The backup will be performed after login.": "Резервне копіювання буде виконано після входу у систему.", + "{pcName} installed packages": "Пакети, встановлені на {pcName}", + "Current status: Not logged in": "Статус: вхід не виконано", + "You are logged in as {0} (@{1})": "Ви увійшли як {0} (@{1})", + "Nice! Backups will be uploaded to a private gist on your account": "Славно! Резервні копії будуть завантажені у приватний Gist на вашому обліковому запису", + "Select backup": "Виберіть копію", + "Settings imported from {0}": "Налаштування імпортовано з {0}", + "UniGetUI Settings": "Налаштування UniGetUI", + "Settings exported to {0}": "Налаштування експортовано до {0}", + "UniGetUI settings were reset": "Налаштування UniGetUI було скинуто", + "Allow pre-release versions": "Дозволити підготовчі версії", + "Apply": "Застосувати", + "For security reasons, custom command-line arguments are disabled by default. Go to UniGetUI security settings to change this.": "З міркувань безпеки користувацькі аргументи командного рядка типово вимкнені. Щоб змінити це, перейдіть до налаштувань безпеки UniGetUI.", + "Go to UniGetUI security settings": "Перейти в налаштування безпеки UniGetUI", + "The following options will be applied by default each time a {0} package is installed, upgraded or uninstalled.": "Наступні налаштування будуть застосовані кожного разу коли пакет з {0} встановлюється, оновлюється чи видаляється.", + "Package's default": "За замовчуванням для пакета", + "Install location can't be changed for {0} packages": "Не можна змінювати місце встановлення для пакетів з {0}", + "The local icon cache currently takes {0} MB": "Локальний кеш піктограм займає {0} МБ", + "Username": "Ім'я користувача", + "Password": "Пароль", + "Credentials": "Облікові данні", + "It is not guaranteed that the provided credentials will be stored safely": "Немає гарантії, що надані облікові дані буде збережено безпечно", + "Partially": "Частково", + "Package manager": "Менеджер пакетів", + "Compatible with proxy": "Сумісність з проксі", + "Compatible with authentication": "Сумісність з автентифікацією", + "Proxy compatibility table": "Таблиця сумісності з проксі", + "{0} settings": "Налаштування {0}", + "{0} status": "Статус {0}", + "Default installation options for {0} packages": "Варіанти встановлення за замовчуванням для пакетів з {0}", + "Expand version": "Розгорнути версію", + "The executable file for {0} was not found": "Виконуваний файл для {0} не знайдено", + "{pm} is disabled": "{pm} вимкнено", + "Enable it to install packages from {pm}.": "Увімкніть, щоб встановлювати пакети з {pm}.", + "{pm} is enabled and ready to go": "{pm} увімкнений та готовий до використання", + "{pm} version:": "Версія {pm}:", + "{pm} was not found!": "{pm} не знайдено!", + "You may need to install {pm} in order to use it with UniGetUI.": "Можливо, вам необхідно встановити {pm}, щоб використовувати його з UniGetUI.", + "Scoop Installer - UniGetUI": "Інсталятор Scoop — UniGetUI", + "Scoop Uninstaller - UniGetUI": "Програма видалення Scoop – UniGetUI", + "Clearing Scoop cache - UniGetUI": "Очищаємо кеш Scoop — UniGetUI", + "Restart UniGetUI to fully apply changes": "Перезапустіть UniGetUI, щоб повністю застосувати зміни", + "Restart UniGetUI": "Перезапустити UniGetUI", + "Manage {0} sources": "Керування джерелами для {0}", + "Add source": "Додати джерело", + "Add": "Додати", + "Source name": "Назва джерела", + "Source URL": "URL джерела", + "Other": "Інше", + "No minimum age": "Без мінімального віку", + "1 day": "1 день", + "{0} days": "{0} дня", + "Custom...": "Власне...", + "{0} minutes": "{0} хвилин", + "1 hour": "1 година", + "{0} hours": "{0} годин(и)", + "1 week": "1 тиждень", + "Supports release dates": "Підтримує дати випуску", + "Release date support per package manager": "Підтримка дат випуску для кожного менеджера пакетів", + "Search for packages": "Пошук пакетів", + "Local": "Локально", + "OK": "ОК", + "Last checked: {0}": "Остання перевірка: {0}", + "{0} packages were found, {1} of which match the specified filters.": "Знайдено {0} пакетів, {1} з яких підходять під вибрані фільтри.", + "{0} selected": "{0} вибрано", + "(Last checked: {0})": "(Остання перевірка: {0})", + "All packages selected": "Усі пакунки вибрано", + "Package selection cleared": "Вибір пакунків скасовано", + "{0}: {1}": "{0}: {1}", + "More info": "Додаткова інформація", + "GitHub account": "Обліковий запис GitHub", + "Log in with GitHub to enable cloud package backup.": "Увійдіть через GitHub, щоб увімкнути резервне копіювання в хмару", + "More details": "Більше деталей", + "Log in": "Увійти", + "If you have cloud backup enabled, it will be saved as a GitHub Gist on this account": "Якщо резервне копіювання в хмару увімкнуто, копія буде збережена як GitHub Gist в цей обліковий запис", + "Log out": "Вийти", + "About UniGetUI": "Про UniGetUI", + "About": "Про програму", + "Third-party licenses": "Сторонні ліцензії", + "Contributors": "Учасники", + "Translators": "Перекладачі", + "Bundle security report": "Звіт про безпеку колекції", + "The bundle contained restricted content": "Колекція містила обмежений вміст", + "UniGetUI – Crash Report": "UniGetUI – Звіт про збій", + "UniGetUI has crashed": "UniGetUI аварійно завершив роботу", + "Help us fix this by sending a crash report to Devolutions. All fields below are optional.": "Допоможіть нам виправити це, надіславши звіт про збій до Devolutions. Усі поля нижче є необов'язковими.", + "Email (optional)": "Електронна пошта (необов'язково)", + "your@email.com": "your@email.com", + "Additional details (optional)": "Додаткові відомості (необов'язково)", + "Describe what you were doing when the crash occurred…": "Опишіть, що ви робили, коли стався збій…", + "Crash report": "Звіт про збій", + "Don't Send": "Не надсилати", + "Send Report": "Надіслати звіт", + "Sending…": "Надсилання…", + "Unsaved changes": "Незбережені зміни", + "You have unsaved changes in the current bundle. Do you want to discard them?": "У поточній колекції є незбережені зміни. Хочете їх відкинути?", + "Discard changes": "Відкинути зміни", + "Integrity violation": "Порушення цілісності", + "UniGetUI or some of its components are missing or corrupt. It is strongly recommended to reinstall UniGetUI to adress the situation.": "UniGetUI або деякі його компоненти відсутні чи пошкоджені. Наполегливо рекомендується перевстановити UniGetUI, щоб виправити ситуацію.", + "• Refer to the UniGetUI Logs to get more details regarding the affected file(s)": "• Зверніться до журналів UniGetUI, щоб отримати більше деталей стосовно пошкоджених файлів", + "• Integrity checks can be disabled from the Experimental Settings": "• Перевірка цілісності може бути відключена в експериментальних налаштуваннях", + "Manage shortcuts": "Керування ярликами", + "UniGetUI has detected the following desktop shortcuts which can be removed automatically on future upgrades": "UniGetUI виявив наступні ярлики робочого стола, які можна автоматично видалити при наступних оновленнях пакетів.", + "Do you really want to reset this list? This action cannot be reverted.": "Ви дійсно хочете скинути цей список? Ці зміни буде неможливо відмінити.", + "Desktop shortcuts list": "Список ярликів робочого стола", + "Open in explorer": "Відкрити в провіднику", + "Remove from list": "Видалити зі списку", + "When new shortcuts are detected, delete them automatically instead of showing this dialog.": "Коли виявлені нові ярлики, видаляти їх автоматично замість відображення цього діалогу.", + "Not right now": "Не зараз", + "Missing dependency": "Відсутня залежність", + "UniGetUI requires {0} to operate, but it was not found on your system.": "UniGetUI потребує {0} для функціонування, але його не знайдено в вашій системі.", + "Click on Install to begin the installation process. If you skip the installation, UniGetUI may not work as expected.": "Натисніть \"Встановити\" щоби почати процес встановлення. Якщо ви пропустите цей крок, UniGetUI може працювати не правильно.", + "Alternatively, you can also install {0} by running the following command in a Windows PowerShell prompt:": "Також, ви можете встановити {0}, запустивши наступну команду у стрічці Windows PowerShell:", + "Install {0}": "Встановити {0}", + "Do not show this dialog again for {0}": "Більше не показувати цей діалог для {0}", + "Please wait while {0} is being installed. A black window may show up. Please wait until it closes.": "Будь ласка, зачекайте, поки {0} встановлюється. Ви можете побачити чорне (або блакитне) вікно. Дочекайтесь його закриття.", + "{0} has been installed successfully.": "{0} було успішно встановлено.", + "Please click on \"Continue\" to continue": "Будь ласка, натисніть на \"Продовжити\", щоб продовжити", + "Continue": "Продовжити", + "{0} has been installed successfully. It is recommended to restart UniGetUI to finish the installation": "{0} було успішно встановлено. Рекомендовано перезапустити UniGetUI для завершення установки.", + "Restart later": "Перезавантажити пізніше", + "An error occurred:": "Виникла помилка:", + "Please see the Command-line Output or refer to the Operation History for further information about the issue.": "Будь ласка, подивіться на вивід з командного рядка, або в історію операцій, щоб отримати більше інформації про проблему.", + "Retry as administrator": "Повторити від імені адміністратора", + "Retry interactively": "Спробувати знов у інтерактивному режимі", + "Retry skipping integrity checks": "Повторити без перевірки хешу", + "Installation options": "Варіанти встановлення", + "Save": "Зберегти", + "UniGetUI collects anonymous usage data with the sole purpose of understanding and improving the user experience.": "UniGetUI збирає анонімну статистику використання, єдина ціль якої - краще зрозуміти та покращити користувацький досвід.", + "More details about the shared data and how it will be processed": "Більше деталей про дані, які передаються, та як вони обробляються", + "Do you accept that UniGetUI collects and sends anonymous usage statistics, with the sole purpose of understanding and improving the user experience?": "Чи ви погоджуєтесь з тим, що UniGetUI збиратиме та відправлятиме анонімну статистику використання, єдина ціль якої - краще зрозуміти та покращити користувацький досвід?", + "Decline": "Не погоджуюсь", + "No personal information is collected nor sent, and the collected data is anonimized, so it can't be back-tracked to you.": "Жодна персональна інформація не збирається й не передається, зібрані данні анонімізуються, отже їх не можна зв'язати з вами.", + "Navigation panel": "Панель навігації", + "Operations": "Операції", + "Toggle operations panel": "Перемкнути панель операцій", + "Bulk operations": "Масові операції", + "Retry failed": "Повторити невдалі", + "Clear successful": "Очистити успішні", + "Clear finished": "Очистити завершені", + "Cancel all": "Скасувати всі", + "More": "Ще", + "Toggle navigation panel": "Перемкнути панель навігації", + "Minimize": "Згорнути", + "Maximize": "Розгорнути", + "UniGetUI by Devolutions": "UniGetUI від Devolutions", + "UniGetUI is an application that makes managing your software easier, by providing an all-in-one graphical interface for your command-line package managers.": "UniGetUI — це застосунок, який робить керування вашим програмним забезпеченням простіше: він надає графічний інтерфейс \"все в одному\" для ваших менеджерів пакетів.", + "Useful links": "Корисні посилання", + "UniGetUI Homepage": "Домашня сторінка UniGetUI", + "Report an issue or submit a feature request": "Повідомити про проблему чи запропонувати покращення", + "UniGetUI Repository": "Репозиторій UniGetUI", + "View GitHub Profile": "Профіль на GitHub", + "UniGetUI License": "Ліцензія UniGetUI", + "Using UniGetUI implies the acceptation of the MIT License": "Використання UniGetUI означає згоду з ліцензією MIT.", + "Become a translator": "Станьте перекладачем", + "Go back": "Назад", + "Go forward": "Вперед", + "Go to home page": "Перейти на домашню сторінку", + "Reload page": "Перезавантажити сторінку", + "View page on browser": "Відкрити сторінку в браузері", + "The built-in browser is not supported on Linux yet.": "Вбудований браузер поки що не підтримується в Linux.", + "Open in browser": "Відкрити в браузері", + "Copy to clipboard": "Копіювати в буфер обміну", + "Export to a file": "Експорт у файл", + "Log level:": "Рівень журналу:", + "Reload log": "Перезавантажити журнал", + "Export log": "Експортувати журнал", + "Text": "Текст", + "Change how operations request administrator rights": "Змінити як операції запитають права адміністратора", + "Restrictions on package operations": "Обмеження для операцій з пакетами", + "Restrictions on package managers": "Обмеження для менеджерів пакетів", + "Restrictions when importing package bundles": "Обмеження при імпорті колекцій пакетів", + "Ask for administrator privileges once for each batch of operations": "Запитувати права адміністратора один раз для кожної групи операцій ", + "Ask only once for administrator privileges": "Одноразово запитувати права адміністратора", + "Prohibit any kind of Elevation via UniGetUI Elevator or GSudo": "Заборонити будь-яке підвищення прав через модуль підвищення UniGetUI або GSudo", + "This option WILL cause issues. Any operation incapable of elevating itself WILL FAIL. Install/update/uninstall as administrator will NOT WORK.": "Вибір цієї опції СПРИЧИНЯТИМЕ проблеми. Будь які операції, що нездатні підвищити собі права, завершаться НЕВДАЛО. Встановлення/оновлення/видалення від імені адміністратора НЕ ПРАЦЮВАТИМЕ.", + "Allow custom command-line arguments": "Дозволити користувацькі аргументи командного рядка", + "Custom command-line arguments can change the way in which programs are installed, upgraded or uninstalled, in a way UniGetUI cannot control. Using custom command-lines can break packages. Proceed with caution.": "Аргументи командного рядка, задані користувачем, можуть змінювати як програми встановлюються, оновлюються чи видаляються. UniGetUI не має можливості це контролювати. Також такі аргументи можуть псувати пакети. Дійте обережно.", + "Ignore custom pre-install and post-install commands when importing packages from a bundle": "Дозволити виконання користувацьких команд до та після встановлення під час імпорту пакетів із колекції", + "Pre and post install commands will be run before and after a package gets installed, upgraded or uninstalled. Be aware that they may break things unless used carefully": "Перед- і після-операційні команди будуть запущені до та після встановлення, оновлення чи видалення пакету. Усвідомлюйте, що вони може щось зламати, якщо ви не будете обачні", + "Allow changing the paths for package manager executables": "Дозволити зміну шляхів до виконавчих файлів менеджерів пакетів", + "Turning this on enables changing the executable file used to interact with package managers. While this allows finer-grained customization of your install processes, it may also be dangerous": "Увімкнення цієї опції дозволить змінювати виконавчій файл, який використовується для взаємодії з менеджерами пакетами. Це дозволить точну кастомізацію вашого процесу встановлення, але може бути небезпечним", + "Allow importing custom command-line arguments when importing packages from a bundle": "Дозволити імпортувати користувацькі аргументи командного рядка при імпорті пакетів з колекції", + "Malformed command-line arguments can break packages, or even allow a malicious actor to gain privileged execution. Therefore, importing custom command-line arguments is disabled by default": "Неправильно сформовані аргументи командного рядка можуть псувати пакети, або навіть можуть дозволити зловмиснику запустити код з підвищеними привілеями. Саме тому імпортування користувацьких аргументів командного рядка відключено за замовчуванням", + "Allow importing custom pre-install and post-install commands when importing packages from a bundle": "Дозволити імпортувати користувацькі перед- і після-операційні скрипти при імпорті пакетів з колекції", + "Pre and post install commands can do very nasty things to your device, if designed to do so. It can be very dangerous to import the commands from a bundle, unless you trust the source of that package bundle": "Перед- і після-операційні команди можуть зробити кепсько вашому пристрою, якщо вони задумувались з цією метою. Імпортувати команди з колекції може бути дуже небезпечно, окрім випадків, коли ви довіряєте джерелу її походження", + "Administrator rights and other dangerous settings": "Права адміністратора та інші небезпечні налаштування", + "Package backup": "Резервне копіювання пакетів", + "Cloud package backup": "Резервне копіювання в хмару", + "Local package backup": "Локальне резервне копіювання пакетів", + "Local backup advanced options": "Розширені налаштування локального резервного копіювання", + "Log in with GitHub": "Увійти через GitHub", + "Log out from GitHub": "Вийти з GitHub аккаунту", + "Periodically perform a cloud backup of the installed packages": "Періодично виконувати резервне копіювання в хмару встановлених пакетів", + "Cloud backup uses a private GitHub Gist to store a list of installed packages": "Резервне копіювання в хмару використовує GitHub Gist для зберігання списку встановлених пакетів", + "Perform a cloud backup now": "Виконати резервне копіювання в хмару зараз", + "Backup": "Зробити копію", + "Restore a backup from the cloud": "Відновити з резервної копії в хмарі", + "Begin the process to select a cloud backup and review which packages to restore": "Почніть процес з вибору резервної копії й пакетів для відновлення", + "Periodically perform a local backup of the installed packages": "Періодично виконувати локальне резервне копіювання встановлених пакетів", + "Perform a local backup now": "Виконати локальне резервне копіювання зараз", + "Change backup output directory": "Змінити вихідну теку для резервного копіювання", + "Set a custom backup file name": "Задати особливе ім'я для файла резервної копії", + "Leave empty for default": "Пусте за замовчуванням", + "Add a timestamp to the backup file names": "Додавати мітку часу до імен файлів резервної копії", + "Backup and Restore": "Резервне копіювання і відновлення", + "Enable background api (UniGetUI Widgets and Sharing, port 7058)": "Увімкнути фоновий API (Віджети UniGetUI та можливість ділитися, порт 7058).", + "Wait for the device to be connected to the internet before attempting to do tasks that require internet connectivity.": "Зачекати наявності підключення до інтернету перед тим, як виконувати задачі, які потребують цього підключення.", + "Disable the 1-minute timeout for package-related operations": "Відключити 1-хвилинний тайм-аут для операцій, пов'язаних з пакетами", + "Use installed GSudo instead of UniGetUI Elevator": "Використовувати встановлений GSudo замість вбудованого модуля підвищення UniGetUI", + "Use a custom icon and screenshot database URL": "Вкажіть URL до користувацької бази даних значків та знімків екрану", + "Enable background CPU Usage optimizations (see Pull Request #3278)": "Увімкнути оптимізацію використання ЦП у фоновому режимі (див. Pull Request №3278)", + "Perform integrity checks at startup": "Проводити перевірку цілісності під час запуску", + "When batch installing packages from a bundle, install also packages that are already installed": "Встановлювати також вже встановлені пакети при пакетному встановленні з колекції", + "Experimental settings and developer options": "Експериментальні налаштування та опції розробника", + "Show UniGetUI's version and build number on the titlebar.": "Показувати версію UniGetUI на панелі заголовка", + "Language": "Мова", + "UniGetUI updater": "Оновлення UniGetUI", + "Telemetry": "Телеметрія", + "Manage UniGetUI settings": "Керування налаштуваннями UniGetUI", + "Related settings": "Пов'язані налаштування", + "Update UniGetUI automatically": "Оновлювати UniGetUI автоматично", + "Check for updates": "Перевірити зараз", + "Install prerelease versions of UniGetUI": "Встановлення перед-реліз версій UniGetUI", + "Manage telemetry settings": "Керування налаштуваннями телеметрії", + "Manage": "Керувати", + "Import settings from a local file": "Імпортувати налаштування з локального файлу", + "Import": "Імпорт", + "Export settings to a local file": "Експортувати налаштування у локальний файл", + "Export": "Експорт", + "Reset UniGetUI": "Скинути UniGetUI", + "User interface preferences": "Налаштування інтерфейсу користувача", + "Application theme, startup page, package icons, clear successful installs automatically": "Тема програми, початковий екран, піктограми пакетів, автоматичне прибирання успішних операцій", + "General preferences": "Загальні налаштування", + "UniGetUI display language:": "Мова відображення UniGetUI:", + "System language": "Мова системи", + "Is your language missing or incomplete?": "Ваша мова відсутня або неповна?", + "Appearance": "Зовнішній вигляд", + "UniGetUI on the background and system tray": "UniGetUI у фоні та системному лотку", + "Package lists": "Списки пакетів", + "Use classic mode": "Використовувати класичний режим", + "Restart UniGetUI to apply this change": "Перезапустіть UniGetUI, щоб застосувати цю зміну", + "The classic UI is disabled for beta testers": "Класичний інтерфейс вимкнено для бета-тестерів", + "Close UniGetUI to the system tray": "Закріпити UniGetUI в системному треї", + "Manage UniGetUI autostart behaviour": "Керування поведінкою автозапуску UniGetUI", + "Show package icons on package lists": "Відображати піктограми пакетів", + "Clear cache": "Очистити кеш", + "Select upgradable packages by default": "Вибирати пакети, що можна оновити, за замовчуванням", + "Light": "Світла", + "Dark": "Темна", + "Follow system color scheme": "Системна", + "Application theme:": "Тема програми:", + "UniGetUI startup page:": "Початковий екран UniGetUI:", + "Proxy settings": "Налаштування проксі", + "Other settings": "Інші налаштування", + "Connect the internet using a custom proxy": "Підключатися до інтернету, використовуючи вказаний проксі", + "Please note that not all package managers may fully support this feature": "Будь ласка, зауважте, що не всі менеджери пакетів повністю підтримують цю функціональність ", + "Proxy URL": "URL-адреса проксі", + "Enter proxy URL here": "Введіть URL проксі тут", + "Authenticate to the proxy with a user and a password": "Автентифікуватися на проксі-сервері за допомогою користувача та пароля", + "Internet and proxy settings": "Налаштування Інтернету та проксі", + "Package manager preferences": "Налаштування менеджерів пакетів", + "Ready": "Готовий", + "Not found": "Не знайдено", + "Notification preferences": "Параметри сповіщень", + "Notification types": "Типи сповіщень", + "The system tray icon must be enabled in order for notifications to work": "Для функціонування сповіщень іконка у системному лотку має бути увімкнена", + "Enable UniGetUI notifications": "Увімкнути сповіщення UniGetUI", + "Show a notification when there are available updates": "Показувати сповіщення, коли є доступні оновлення", + "Show a silent notification when an operation is running": "Показувати беззвучне сповіщення, поки операція проводиться", + "Show a notification when an operation fails": "Показувати сповіщення про неуспішні операції", + "Show a notification when an operation finishes successfully": "Показувати сповіщення про успішні операції", + "Concurrency and execution": "Паралелізм та виконання ", + "Automatic desktop shortcut remover": "Автоматичне видалення ярликів з робочого столу", + "Choose how many operations should be performed in parallel": "Виберіть, скільки операцій слід виконувати паралельно", + "Clear successful operations from the operation list after a 5 second delay": "Прибирати успішні операції зі списку операцій після 5 секунд очікування", + "Download operations are not affected by this setting": "Це налаштування не впливає на операції завантаження", + "You may lose unsaved data": "Ви можете втратити незбережені данні", + "Ask to delete desktop shortcuts created during an install or upgrade.": "Спробувати видалити ярлики з робочого стола, створені під час встановлення або оновлення.", + "Package update preferences": "Налаштування оновлень пакетів", + "Update check frequency, automatically install updates, etc.": "Частота перевірки, автоматичне встановлення оновлень та інше.", + "Reduce UAC prompts, elevate installations by default, unlock certain dangerous features, etc.": "Зменшити кількість запитів UAC, підвищувати права установки за замовчуванням, розблокувати деякі небезпечні функції і т.д. ", + "Package operation preferences": "Налаштування операцій з пакетами", + "Enable {pm}": "Увімкнути {pm}", + "Not finding the file you are looking for? Make sure it has been added to path.": "Не бачите файл, який ви шукали? Впевнитесь, що він був доданий у змінну path.", + "Select the executable to be used. The following list shows the executables found by UniGetUI": "Виберіть виконавчій файл, який буде використовуватися. Наступний список містить файли, знайдені UniGetUI", + "For security reasons, changing the executable file is disabled by default": "З міркувань безпеки зміна виконавчого файлу відключена за замовчуванням.", + "Change this": "Змінити", + "Copy path": "Копіювати шлях", + "Current executable file:": "Поточний виконавчій файл:", + "Ignore packages from {pm} when showing a notification about updates": "Ігнорувати пакети з {pm} при показі сповіщень про оновлення", + "Update security": "Безпека оновлень", + "Use global setting": "Використовувати глобальне налаштування", + "Minimum age for updates": "Мінімальний вік оновлень", + "e.g. 10": "напр. 10", + "Custom minimum age (days)": "Власний мінімальний вік (днів)", + "{pm} does not provide release dates for its packages, so this setting will have no effect": "{pm} не надає дати випуску для своїх пакетів, тому це налаштування не матиме жодного ефекту", + "{pm} only provides release dates for some of its packages, so this setting will only apply to those packages": "{pm} надає дати випуску лише для частини своїх пакетів, тож цей параметр застосовуватиметься лише до них", + "Override the global minimum update age for this package manager": "Перевизначити глобальний мінімальний вік оновлень для цього менеджера пакетів", + "View {0} logs": "Переглянути журнали {0}", + "If Python cannot be found or is not listing packages but is installed on the system, ": "Якщо Python не вдається знайти або він не показує пакети, хоча встановлений у системі, ", + "Advanced options": "Розширені налаштування", + "WinGet command-line tool": "Інструмент командного рядка WinGet", + "Choose which command-line tool UniGetUI uses for WinGet operations when the COM API is not used": "Виберіть, який інструмент командного рядка UniGetUI використовуватиме для операцій WinGet, коли COM API не використовується", + "WinGet COM API": "COM API WinGet", + "Choose whether UniGetUI can use the WinGet COM API before falling back to the command-line tool": "Виберіть, чи може UniGetUI використовувати COM API WinGet перед поверненням до інструмента командного рядка", + "Reset WinGet": "Скинути WinGet", + "This may help if no packages are listed": "Це може допомогти, якщо пакети не відображаються", + "Force install location parameter when updating packages with custom locations": "Примусово використовувати параметр розташування встановлення під час оновлення пакетів із користувацькими шляхами", + "Install Scoop": "Встановити Scoop", + "Uninstall Scoop (and its packages)": "Видалити Scoop (і його пакети)", + "Run cleanup and clear cache": "Запустити очищення та видалити кеш", + "Run": "Запустити", + "Enable Scoop cleanup on launch": "Увімкнути очищення Scoop під час запуску", + "Default vcpkg triplet": "Триплет vcpk за замовчуванням", + "Change vcpkg root location": "Змінити розташування кореня vcpkg", + "Reset vcpkg root location": "Скинути розташування кореневої теки vcpkg", + "Open vcpkg root location": "Відкрити розташування кореневої теки vcpkg", + "Language, theme and other miscellaneous preferences": "Мова, тема та інші параметри", + "Show notifications on different events": "Показувати сповіщення про різні події", + "Change how UniGetUI checks and installs available updates for your packages": "Змінити як UniGetUI перевіряє та встановлює оновлення для ваших пакетів", + "Automatically save a list of all your installed packages to easily restore them.": "Автоматично зберігати список усіх встановлених вами пакетів, щоб мати змогу їх легко відновити.", + "Enable and disable package managers, change default install options, etc.": "Увімкнути та вимкнути менеджери пакетів, змінити налаштування встановлення за замовчуванням і т.д.", + "Internet connection settings": "Налаштування з'єднання з інтернетом", + "Proxy settings, etc.": "Налаштування проксі та іншого.", + "Beta features and other options that shouldn't be touched": "Бета-функції та інші параметри, які не варто чіпати", + "Reload sources": "Перезавантажити джерела", + "Delete source": "Видалити джерело", + "Known sources": "Відомі джерела", + "Update checking": "Перевірка оновлень", + "Automatic updates": "Автоматичні оновлення", + "Check for package updates periodically": "Періодично перевіряти оновлення пакетів", + "Check for updates every:": "Перевіряти наявність оновлень кожні:", + "Install available updates automatically": "Автоматично встановлювати доступні оновлення", + "Do not automatically install updates when the network connection is metered": "Не встановлювати оновлення автоматично, якщо підключення до мережі є лімітним", + "Do not automatically install updates when the device runs on battery": "Не встановлювати оновлення автоматично, якщо пристрій працює від батареї", + "Do not automatically install updates when the battery saver is on": "Не встановлювати оновлення автоматично, якщо увімкнутий режим економії енергії", + "Only show updates that are at least the specified number of days old": "Показувати лише оновлення, яким щонайменше вказана кількість днів", + "Warn me when the installer URL host changes between the installed version and the new version (WinGet only)": "Попереджати мене, коли хост URL-адреси інсталятора змінюється між встановленою версією та новою версією (лише WinGet)", + "Change how UniGetUI handles install, update and uninstall operations.": "Змінити як UniGetUI керує операціями встановлення, оновлення й видалення.", + "Navigation": "Навігація", + "Check for UniGetUI updates": "Перевіряти наявність оновлень UniGetUI", + "Quit UniGetUI": "Вийти з UniGetUI", + "Filters": "Фільтри", + "Sources": "Джерела", + "Search for packages to start": "Для початку знайдіть пакети", + "Select all": "Вибрати все", + "Clear selection": "Зняти виділення", + "Instant search": "Миттєвий пошук", + "Distinguish between uppercase and lowercase": "Враховувати регістр", + "Ignore special characters": "Ігнорувати спеціальні символи", + "Search mode": "Метод пошуку", + "Both": "ІD або ім'я пакета", + "Exact match": "Точна відповідність", + "Show similar packages": "Показувати схожі пакети", + "Loading": "Завантаження", + "Package": "Пакет", + "More options": "Більше параметрів", + "Order by:": "Сортувати за:", + "Name": "Ім'я", + "Id": "ID", + "Ascendant": "Зростанням", + "Descendant": "Спаданням", + "View modes": "Режими перегляду", + "Reload": "Перезавантажити", + "Closed": "Закрито", + "Ascending": "За зростанням", + "Descending": "За спаданням", + "{0}: {1}, {2}": "{0}: {1}, {2}", + "Order by": "Сортувати за", + "No results were found matching the input criteria": "Не знайдено жодного результату, що відповідає введеним критеріям", + "No packages were found": "Жодного пакету не знайдено", + "Loading packages": "Завантаження пакетів", + "Skip integrity checks": "Пропустити перевірку хешу", + "Download selected installers": "Завантажити вибрані інсталятори", + "Install selection": "Встановити вибране", + "Install options": "Варіанти встановлення", + "Add selection to bundle": "Додати вибране в колекцію", + "Download installer": "Завантажити інсталятор", + "Uninstall selection": "Видалити вибране", + "Uninstall options": "Варіанти видалення", + "Ignore selected packages": "Ігнорувати обрані пакети", + "Open install location": "Відкрити теку установки", + "Reinstall package": "Перевстановити пакет", + "Uninstall package, then reinstall it": "Видалити пакет, потім встановити наново", + "Ignore updates for this package": "Ігнорувати оновлення цього пакета", + "WinGet malfunction detected": "Виявлена проблема з WinGet ", + "It looks like WinGet is not working properly. Do you want to attempt to repair WinGet?": "Схоже, WinGet несправний. Хочете спробувати відновити WinGet?", + "Repair WinGet": "Відновити WinGet", + "Updates will no longer be ignored for {0}": "Оновлення більше не ігноруватимуться для {0}", + "Updates are now ignored for {0}": "Оновлення тепер ігноруються для {0}", + "Do not ignore updates for this package anymore": "Більше не ігнорувати оновлення цього пакету", + "Add packages or open an existing package bundle": "Додайте пакети чи відкрийте існуючу колекцію пакетів", + "Add packages to start": "Додайте пакети, щоби почати", + "The current bundle has no packages. Add some packages to get started": "У відкритій колекції немає жодного пакету. Додайте кілька, щоби почати.", + "New": "Створити", + "Save as": "Зберегти як", + "Create .ps1 script": "Створити .ps1 скрипт", + "Remove selection from bundle": "Прибрати вибране з колекції", + "Skip hash checks": "Пропустити перевірки хешу", + "The package bundle is not valid": "Ця колекція пакетів сформована не коректно", + "The bundle you are trying to load appears to be invalid. Please check the file and try again.": "Колекція, яку ви намагаєтеся відкрити, сформована некоректно. Будь ласка, перевірте файл, та спробуйте знову.", + "Package bundle": "Колекція пакетів", + "Could not create bundle": "Неможливо створити колекцію", + "The package bundle could not be created due to an error.": "Колекцію пакетів неможливо створити через помилку.", + "Install script": "Скрипт для встановлення", + "PowerShell script": "Скрипт PowerShell", + "The installation script saved to {0}": "Скрипт для встановлення був збережений як {0}", + "An error occurred": "Виникла помилка", + "An error occurred while attempting to create an installation script:": "При спробі створити скрипт для встановлення виникла помилка:", + "Hooray! No updates were found.": "Ура! Оновлення не знайдено.", + "Uninstall selected packages": "Видалити вибрані пакети", + "Update selection": "Оновити вибране", + "Update options": "Варіанти оновлення", + "Uninstall package, then update it": "Видалити пакет, потім оновити його", + "Uninstall package": "Видалити пакет", + "Skip this version": "Пропустити версію", + "Pause updates for": "Призупинити оновлення на", + "User | Local": "Користувач | Локально", + "Machine | Global": "Комп’ютер | Глобально", + "The default package manager for Debian/Ubuntu-based Linux distributions.
Contains: Debian/Ubuntu packages": "Стандартний менеджер пакунків для дистрибутивів Linux на основі Debian/Ubuntu.
Містить: пакунки Debian/Ubuntu", + "The Rust package manager.
Contains: Rust libraries and programs written in Rust": "Пакетний менеджер для Rust.
Містить: Бібліотеки та програми, написані мовою Rust ", + "The classical package manager for windows. You'll find everything there.
Contains: General Software": "Класичний менеджер пакетів для Windows. Тут ви знайдете все, що потрібно.
Містить: Загальне програмне забезпечення", + "The default package manager for RHEL/Fedora-based Linux distributions.
Contains: RPM packages": "Стандартний менеджер пакунків для дистрибутивів Linux на основі RHEL/Fedora.
Містить: пакунки RPM", + "A repository full of tools and executables designed with Microsoft's .NET ecosystem in mind.
Contains: .NET related tools and scripts": "Репозиторій повний утиліт та застосунків, спроектованих для екосистеми .NET від Microsoft.
Містить: Утиліти, зв'язані з .NET, та скрипти", + "The universal Linux package manager for desktop applications.
Contains: Flatpak applications from configured remotes": "Універсальний менеджер пакетів Linux для настільних застосунків.
Містить: застосунки Flatpak із налаштованих віддалених репозиторіїв", + "NuPkg (zipped manifest)": "NuPkg (стиснутий маніфест)", + "The Missing Package Manager for macOS (or Linux).
Contains: Formulae, Casks": "Відсутній менеджер пакетів для macOS (або Linux).
Містить: Formulae, Casks", + "Node JS's package manager. Full of libraries and other utilities that orbit the javascript world
Contains: Node javascript libraries and other related utilities": "Менеджер пакетів Node JS. Повний бібліотек та інших утиліт, які обертаються навколо світу javascript
Містить: Бібліотеки Node javascript та інші пов'язані з ними утиліти", + "The default package manager for Arch Linux and its derivatives.
Contains: Arch Linux packages": "Стандартний менеджер пакунків для Arch Linux та його похідних.
Містить: пакунки Arch Linux", + "Python's library manager. Full of python libraries and other python-related utilities
Contains: Python libraries and related utilities": "Менеджер бібліотек Python. Повний набір бібліотек python та інших утиліт, пов'язаних з python
Містить: Бібліотеки python та пов'язані з ними утиліти", + "PowerShell's package manager. Find libraries and scripts to expand PowerShell capabilities
Contains: Modules, Scripts, Cmdlets": "Менеджер пакетів для PowerShell. Знайди бібліотеки та скрипти які розширяють можливості PowerShell
Містить: Модулі, Скрипти, Командлети", + "extracted": "видобуто", + "Scoop package": "Пакет Scoop", + "Great repository of unknown but useful utilities and other interesting packages.
Contains: Utilities, Command-line programs, General Software (extras bucket required)": "Чудове сховище невідомих, але корисних утиліт та інших цікавих пакетів.
Містить: Утиліти, програми командного рядка, загальне програмне забезпечення (потрібно додатково bucket)", + "The universal Linux package manager by Canonical.
Contains: Snap packages from the Snapcraft store": "Універсальний менеджер пакетів Linux від Canonical.
Містить: Snap-пакети з магазину Snapcraft", + "library": "бібліотека", + "feature": "функція", + "A popular C/C++ library manager. Full of C/C++ libraries and other C/C++-related utilities
Contains: C/C++ libraries and related utilities": "Популярний менеджер бібліотек для C/C++. Заповнений бібліотеками для C/C++ та зв'язаними утилітами.
Містить: C/C++ бібліотеки та зв'язані утиліти", + "option": "опція", + "This package cannot be installed from an elevated context.": "Цей пакет не можна встановити від імені адміністратора.", + "Please run UniGetUI as a regular user and try again.": "Будь ласка, перезапустіть UniGetUI від імені звичайного користувача, та спробуйте знову", + "Please check the installation options for this package and try again": "Будь ласка, перевірте вибраний варіант встановлення для цього пакету, та спробуйте знову", + "Microsoft's official package manager. Full of well-known and verified packages
Contains: General Software, Microsoft Store apps": "Офіційний менеджер пакетів Microsoft. Повний відомих і перевірених пакетів
Містить: Загальне програмне забезпечення, програми Microsoft Store", + "Local PC": "Цей ПК", + "Android Subsystem": "Підсистема Android", + "Operation on queue (position {0})...": "Операція в черзі (позиція {0})…", + "Click here for more details": "Натисніть тут для подробиць", + "Operation canceled by user": "Операція відмінена користувачем", + "Running PreOperation ({0}/{1})...": "Виконується PreOperation ({0}/{1})...", + "PreOperation {0} out of {1} failed, and was tagged as necessary. Aborting...": "PreOperation {0} з {1} завершилася невдало й була позначена як обов'язкова. Переривання...", + "PreOperation {0} out of {1} finished with result {2}": "PreOperation {0} з {1} завершилася з результатом {2}", + "Starting operation...": "Починаємо операцію…", + "Running PostOperation ({0}/{1})...": "Виконується PostOperation ({0}/{1})...", + "PostOperation {0} out of {1} failed, and was tagged as necessary. Aborting...": "PostOperation {0} з {1} завершилася невдало й була позначена як обов'язкова. Переривання...", + "PostOperation {0} out of {1} finished with result {2}": "PostOperation {0} з {1} завершилася з результатом {2}", + "{package} installer download": "Завантаження інсталятора для {package}", + "{0} installer is being downloaded": "Інсталятор для {0} завантажується", + "Download succeeded": "Завантаження завершено успішно", + "{package} installer was downloaded successfully": "Інсталятор для {package} було успішно завантажено", + "Download failed": "Завантаження не вдалося", + "{package} installer could not be downloaded": "Інсталятор для {package} неможливо завантажити", + "{package} Installation": "Встановлення {package}", + "{0} is being installed": "Встановлюється {0}", + "Installation succeeded": "Встановлення завершено успішно", + "{package} was installed successfully": "{package} було успішно встановлено", + "Installation failed": "Встановлення не вдалося", + "{package} could not be installed": "Неможливо встановити {package}", + "{package} Update": "Оновлення {package}", + "Update succeeded": "Оновлення виконано успішно", + "{package} was updated successfully": "{package} було успішно оновлено", + "Update failed": "Оновлення не вдалося", + "{package} could not be updated": "Неможливо оновити {package}", + "{package} Uninstall": "Видалення {package}", + "{0} is being uninstalled": "Видаляється {0}", + "Uninstall succeeded": "Видалення закінчилося вдало", + "{package} was uninstalled successfully": "{package} було успішно видалено", + "Uninstall failed": "Видалення не вдалося", + "{package} could not be uninstalled": "{package} неможливо видалити", + "Adding source {source}": "Додавання джерела {source}", + "Adding source {source} to {manager}": "Додаємо джерело {source} до {manager}", + "Source added successfully": "Джерело успішно додано", + "The source {source} was added to {manager} successfully": "Джерело {source} було успішно додано до {manager}", + "Could not add source": "Неможливо додати джерело", + "Could not add source {source} to {manager}": "Неможливо додати джерело {source} до {manager}", + "Removing source {source}": "Видалення джерела {source}", + "Removing source {source} from {manager}": "Видаляємо джерело {source} з {manager}", + "Source removed successfully": "Джерело успішно видалено", + "The source {source} was removed from {manager} successfully": "Джерело {source} було успішно видалено з {manager}", + "Could not remove source": "Неможливо видалити джерело", + "Could not remove source {source} from {manager}": "Неможливо видалити джерело {source} з {manager}", + "The package manager \"{0}\" was not found": "Пакетний менеджер \"{0}\" не знайдено", + "The package manager \"{0}\" is disabled": "Пакетний менеджер \"{0}\" відключено", + "There is an error with the configuration of the package manager \"{0}\"": "Сталася помилка зв'язана з конфігурацією менеджера пакетів \"{0}\"", + "The package \"{0}\" was not found on the package manager \"{1}\"": "Пакет \"{0}\" не знайдено в пакетному менеджері \"{1}\"", + "{0} is disabled": "{0} вимкнено", + "{0} weeks": "{0} тижнів", + "1 month": "1 місяць", + "{0} months": "{0} місяців", + "Something went wrong": "Щось пішло не так", + "An interal error occurred. Please view the log for further details.": "Виникла внутрішня помилка. Будь ласка, продивіться журнал для більш детальної інформації.", + "No applicable installer was found for the package {0}": "Підходящого інсталятора не знайдено для пакета {0}", + "Integrity checks will not be performed during this operation": "Перевірка хешу не буде виконана під час цієї операції", + "This is not recommended.": "Це не рекомендується.", + "Run now": "Запустити зараз", + "Run next": "Запустити наступним", + "Run last": "Запустити останнім", + "Show in explorer": "Показати в Провіднику", + "Checked": "Позначено", + "Unchecked": "Не позначено", + "This package is already installed": "Цей пакет вже встановлено", + "This package can be upgraded to version {0}": "Пакет було оновлено до версії {0}", + "Updates for this package are ignored": "Оновлення для цього пакета ігноруються", + "This package is being processed": "Цей пакет обробляється", + "This package is not available": "Цей пакет не доступний", + "Select the source you want to add:": "Виберіть джерело для додавання:", + "Source name:": "Назва джерела:", + "Source URL:": "URL джерела:", + "An error occurred when adding the source: ": "Сталася помилка при додаванні джерела:", + "Package management made easy": "Керування пакетами стало легким", + "version {0}": "версії {0}", + "[RAN AS ADMINISTRATOR]": "ЗАПУЩЕНО ВІД ІМЕНІ АДМІНІСТРАТОРА", + "Portable mode": "Портативний режим\n", + "DEBUG BUILD": "ЗБІРКА ДЛЯ ВІДЛАДЖУВАННЯ", + "Here you can change UniGetUI's behaviour regarding the following shortcuts. Checking a shortcut will make UniGetUI delete it if if gets created on a future upgrade. Unchecking it will keep the shortcut intact": "Тут ви можете змінити поведінку UniGetUI стосовно наступних ярликів. Виділення ярлика призведе до його видалення програмою UniGetUI, якщо він буде створений при наступних оновленнях. Якщо прапорець зняти, ярлик залишиться неторкнутим.", + "Manual scan": "Ручне сканування", + "Existing shortcuts on your desktop will be scanned, and you will need to pick which ones to keep and which ones to remove.": "Існуючи ярлики на вашому робочому столі будуть проскановані, вам буде необхідно вибрати які залишити, а які видалити.", + "Delete?": "Видалити?", + "I understand": "Я розумію", + "Chocolatey setup changed": "Налаштування Chocolatey змінено", + "UniGetUI no longer includes its own private Chocolatey installation. A legacy UniGetUI-managed Chocolatey installation was detected for this user profile, but system Chocolatey was not found. Chocolatey will stay unavailable in UniGetUI until Chocolatey is installed on the system and UniGetUI is restarted. Applications previously installed through UniGetUI's bundled Chocolatey may still appear under other sources such as Local PC or WinGet.": "UniGetUI більше не включає власну вбудовану інсталяцію Chocolatey. Для цього профілю користувача виявлено застарілу інсталяцію Chocolatey, керовану UniGetUI, але системну версію Chocolatey не знайдено. Chocolatey залишатиметься недоступним у UniGetUI, доки Chocolatey не буде встановлено в системі та UniGetUI не буде перезапущено. Програми, раніше встановлені через вбудований Chocolatey UniGetUI, можуть усе ще відображатися в інших джерелах, таких як Локальний ПК або WinGet.", + "NOTE: This troubleshooter can be disabled from UniGetUI Settings, on the WinGet section": "ПРИМІТКА: Засіб усунення неполадок можна відключити у налаштуваннях UniGetUI, у секції WinGet", + "Restart": "Перезавантажити", + "Are you sure you want to delete all shortcuts?": "Ви впевнені що хочете видаляти всі ярлики?", + "Any new shorcuts created during an install or an update operation will be deleted automatically, instead of showing a confirmation prompt the first time they are detected.": "Для новий ярликів, створених під час операцій встановлення та оновлення, не буде показано діалогу підтвердження: замість цього вони будуть видалені автоматично.", + "Any shorcuts created or modified outside of UniGetUI will be ignored. You will be able to add them via the {0} button.": "Всі ярлики, створені або змінені не через UniGetUI, будуть проігноровані. Ви зможете додати їх за допомогою кнопки \"{0}\".", + "Are you really sure you want to enable this feature?": "Ви точно впевнені що хочете увімкнути цю функцію?", + "No new shortcuts were found during the scan.": "В ході сканування нових ярликів не виявлено.", + "How to add packages to a bundle": "Як додати пакети до колекції", + "In order to add packages to a bundle, you will need to: ": "Щоб додати пакети до колекції, вам необхідно:", + "1. Navigate to the \"{0}\" or \"{1}\" page.": "1. Перейти на сторінку \"{0}\" чи \"{1}\".", + "2. Locate the package(s) you want to add to the bundle, and select their leftmost checkbox.": "2. Знайти пакети, які ви хочете додати до колекції, та позначити їх прапорцем у найлівішій колонці.", + "3. When the packages you want to add to the bundle are selected, find and click the option \"{0}\" on the toolbar.": "3. Коли пакети, які ви хочете додати, вибрані, знайдіть та натисніть \"{0}\" на панелі інструментів.", + "4. Your packages will have been added to the bundle. You can continue adding packages, or export the bundle.": "4. Вибрані пакети будуть додані до колекції. Ви можете продовжити додавати пакети або експортувати колекцію.", + "Which backup do you want to open?": "Яку резервну копію ви бажаєте відкрити?", + "Select the backup you want to open. Later, you will be able to review which packages you want to install.": "Виберіть резервну копію для відкриття. Пізніше ви зможете переглянути, які пакети/програми ви хочете відновити.", + "There are ongoing operations. Quitting UniGetUI may cause them to fail. Do you want to continue?": "Деякі операції ще не завершені. Вихід з UniGetUI може призвести до їх невдалого завершення. Бажаєте продовжити?", + "UniGetUI or some of its components are missing or corrupt.": "UniGetUI чи деякі з його компонентів відсутні або пошкоджені.", + "It is strongly recommended to reinstall UniGetUI to adress the situation.": "Дуже радимо перевстановити UniGetUI щоби виправити ситуацію.", + "Refer to the UniGetUI Logs to get more details regarding the affected file(s)": "Зверніться до журналів UniGetUI, щоб отримати більше деталей стосовно пошкоджених файлів", + "Integrity checks can be disabled from the Experimental Settings": "Перевірка цілісності може бути відключена в експериментальних налаштуваннях", + "Repair UniGetUI": "Відновити UniGetUI", + "Live output": "Вивід наживо", + "This package bundle had some settings that are potentially dangerous, and may be ignored by default.": "Ця колекція пакетів містить деякі потенційно небезпечні налаштування, що можуть ігноруватися за замовчуванням.", + "Entries that show in YELLOW will be IGNORED.": "Записи, які показані ЖОВТИМ, будуть ПРОІГНОРОВАНІ.", + "Entries that show in RED will be IMPORTED.": "Записи, які показані ЧЕРВОНИМ, будуть ІМПОРТОВАНІ.", + "You can change this behavior on UniGetUI security settings.": "Ви можете змінити цю поведінку в налаштуваннях безпеки UniGetUI.", + "Open UniGetUI security settings": "Відкрити налаштування безпеки UniGetUI", + "Should you modify the security settings, you will need to open the bundle again for the changes to take effect.": "Після зміни налаштувань безпеки вам буде необхідно перевідкрити колекцію, щоби зміни набули чинності.", + "Details of the report:": "Деталі звіту:", + "Are you sure you want to create a new package bundle? ": "Ви впевнені, що хочете створити нову колекцію?", + "Any unsaved changes will be lost": "Всі незбережені зміни буде втрачено", + "Warning!": "Увага!", + "For security reasons, custom command-line arguments are disabled by default. Go to UniGetUI security settings to change this. ": "З міркувань безпеки, користувацькі аргументи командного рядка відключені за замовчуванням. Ви можете змінити це в налаштуваннях безпеки UniGetUI.", + "Change default options": "Змінити налаштування за замовченням", + "Ignore future updates for this package": "Ігнорувати оновлення цього пакета", + "For security reasons, pre-operation and post-operation scripts are disabled by default. Go to UniGetUI security settings to change this. ": "З міркувань безпеки, перед- і після-операційні скрипти відключені за замовчуванням. Ви можете змінити це в налаштуваннях безпеки UniGetUI.", + "You can define the commands that will be run before or after this package is installed, updated or uninstalled. They will be run on a command prompt, so CMD scripts will work here.": "Ви можете задати команди, які будуть запущені до чи після встановлення, оновлення або видалення цього пакету. Вони будуть запущені з командного рядка, тож тут можна використовувати CMD скрипти.", + "Change this and unlock": "Змінити це й розблокувати", + "{0} Install options are currently locked because {0} follows the default install options.": "Варіанти встановлення для {0} заблоковані тому, що {0} дотримується налаштувань встановлення за замовчуванням.", + "Unset or unknown": "Невідома або невстановлена", + "This package has no screenshots or is missing the icon? Contrbute to UniGetUI by adding the missing icons and screenshots to our open, public database.": "В цьому пакеті не вистачає знімків екрану чи піктограми? Зробіть внесок у UniGetUI, додавши відсутні піктограми та знімки екрану в нашу відкриту та публічну базу даних.", + "Become a contributor": "Стати учасником", + "Update to {0} available": "Доступне оновлення до {0}", + "Reinstall": "Перевстановити", + "Installer not available": "Інсталятор не доступний", + "Version:": "Версія:", + "UniGetUI Version {0}": "UniGetUI версія {0}", + "Performing backup, please wait...": "Створюється резервна копія, зачекайте, будь ласка…", + "An error occurred while logging in: ": "Виникла помилка при вході:", + "Fetching available backups...": "Завантажуємо список резервних копій…", + "Done!": "Виконано!", + "The cloud backup has been loaded successfully.": "Резервна копія з хмари була успішно завантажена.", + "An error occurred while loading a backup: ": "Виникла помилка при завантаженні резервної копії:", + "Backing up packages to GitHub Gist...": "Виконую резервне копіювання пакетів до GitHub Gist...", + "Backup Successful": "Резервне копіювання успішно виконано", + "The cloud backup completed successfully.": "Резервне копіювання в хмару завершено успішно.", + "Could not back up packages to GitHub Gist: ": "Не можу завантажити резервну копію пакетів до GitHub Gist:", + "It is not guaranteed that the provided credentials will be stored safely, so you may as well not use the credentials of your bank account": "Не має гарантій, що облікові данні зберігаються безпечно, тож, по можливості, не використовуйте тут облікові данні вашого банківського рахунку", + "Enable the automatic WinGet troubleshooter": "Увімкнути автоматичний засіб усунення неполадок для WinGet", + "Add updates that fail with a 'no applicable update found' to the ignored updates list": "Додати оновлення, що не вдалися з помилкою \"не знайдено оновлень, що можна застосувати\", до списку ігнорованих оновлень", + "Invalid selection": "Неприпустимий вибір", + "No package was selected": "Не було вибрано жодного пакета", + "More than 1 package was selected": "Було вибрано більше ніж один пакет", + "List": "Список", + "Grid": "Сітка", + "Icons": "Плитки", + "\"{0}\" is a local package and does not have available details": "\"{0}\" є локальним пакетом: про нього немає доступної інформації", + "\"{0}\" is a local package and is not compatible with this feature": "\"{0}\" є локальним пакетом і несумісний з цією функціональністю", + "Add packages to bundle": "Додати пакети до колекції", + "Preparing packages, please wait...": "Підготовка пакетів, будь ласка, зачекайте…", + "Loading packages, please wait...": "Завантаження пакетів, будь ласка, зачекайте…", + "Saving packages, please wait...": "Збереження пакетів, будь ласка, зачекайте…", + "The bundle was created successfully on {0}": "Колекція була збережена у файл {0}", + "User profile": "Профіль користувача", + "Error": "Помилка", + "Log in failed: ": "Вхід не вдався:", + "Log out failed: ": "Вихід не вдався:", + "Package backup settings": "Налаштування резервного копіювання", + "Package managers": "Менеджери пакетів", + "Manage UniGetUI autostart behaviour from the Settings app": "Керування автозапуском UniGetUI", + "Choose how many operations shoulds be performed in parallel": "Виберіть, скільки операцій слід виконувати паралельно", + "Something went wrong while launching the updater.": "Щось пішло не так при запуску програми оновлення.", + "Please try again later": "Будь ласка, спробуйте ще раз пізніше", + "Show the release notes after UniGetUI is updated": "Показувати нотатки про випуск після оновлення UniGetUI" +} diff --git a/src/Languages/lang_ur.json b/src/Languages/lang_ur.json new file mode 100644 index 0000000..d7b9a86 --- /dev/null +++ b/src/Languages/lang_ur.json @@ -0,0 +1,851 @@ +{ + "{0} of {1} operations completed": "{1} میں سے {0} آپریشن مکمل ہوئے", + "{0} is now {1}": "{0} اب {1} ہے", + "Enabled": "فعال", + "Disabled": "غیر فعال", + "Privacy": "رازداری", + "Hide my username from the logs": "لاگز سے میرا صارف نام چھپائیں", + "Replaces your username with **** in the logs. Restart UniGetUI to also hide it from already-recorded entries.": "لاگز میں آپ کے صارف نام کو **** سے بدل دیتا ہے۔ پہلے سے ریکارڈ شدہ اندراجات سے بھی اسے چھپانے کے لیے UniGetUI کو دوبارہ شروع کریں۔", + "Your last update attempt did not complete.": "آپ کی آخری اپ ڈیٹ کی کوشش مکمل نہیں ہوئی۔", + "UniGetUI could not confirm whether the update succeeded. Open the log to see what happened.": "UniGetUI اس بات کی تصدیق نہیں کر سکا کہ اپ ڈیٹ کامیاب ہوئی یا نہیں۔ کیا ہوا دیکھنے کے لیے لاگ کھولیں۔", + "View log": "لاگ دیکھیں", + "The installer reported success but did not restart UniGetUI.": "انسٹالر نے کامیابی کی اطلاع دی، لیکن UniGetUI کو دوبارہ شروع نہیں کیا۔", + "The installer failed to initialize.": "انسٹالر ابتدائیہ کاری میں ناکام رہا۔", + "Setup was canceled before installation began.": "انسٹالیشن شروع ہونے سے پہلے سیٹ اپ منسوخ کر دیا گیا۔", + "A fatal error occurred during the preparation phase.": "تیاری کے مرحلے کے دوران ایک سنگین خرابی پیش آئی۔", + "A fatal error occurred during installation.": "انسٹالیشن کے دوران ایک سنگین خرابی پیش آئی۔", + "Installation was canceled while in progress.": "انسٹالیشن جاری رہتے ہوئے منسوخ کر دی گئی۔", + "The installer was terminated by another process.": "انسٹالر کو کسی دوسرے پروسیس نے ختم کر دیا۔", + "The preparation phase determined the installation cannot proceed.": "تیاری کے مرحلے میں طے ہوا کہ انسٹالیشن آگے نہیں بڑھ سکتی۔", + "The installer could not start. UniGetUI may already be running, or you do not have permission to install.": "انسٹالر شروع نہیں ہو سکا۔ ممکن ہے UniGetUI پہلے سے چل رہا ہو، یا آپ کو انسٹال کرنے کی اجازت نہ ہو۔", + "Unexpected installer error.": "انسٹالر کی غیر متوقع خرابی۔", + "We are checking for updates.": "ہم اپ ڈیٹس کی جانچ کر رہے ہیں۔", + "Please wait": "برائے مہربانی انتظار کریں۔", + "Great! You are on the latest version.": "بہت اچھا! آپ تازہ ترین ورژن پر ہیں۔", + "There are no new UniGetUI versions to be installed": "انسٹال کرنے کے لیے کوئی نیا UniGetUI ورژن نہیں ہے۔", + "UniGetUI version {0} is being downloaded.": "UniGetUI ورژن {0} ڈاؤن لوڈ کیا جا رہا ہے۔", + "This may take a minute or two": "اس میں ایک یا دو منٹ لگ سکتے ہیں۔", + "The installer authenticity could not be verified.": "انسٹالر کی صداقت کی تصدیق نہیں ہو سکی۔", + "The update process has been aborted.": "اپ ڈیٹ کا عمل روک دیا گیا ہے۔", + "Auto-update is not yet available on this platform.": "خودکار اپ ڈیٹ اس پلیٹ فارم پر ابھی دستیاب نہیں ہے۔", + "Please update UniGetUI manually.": "براہ کرم UniGetUI کو دستی طور پر اپ ڈیٹ کریں۔", + "An error occurred when checking for updates: ": "اپ ڈیٹس کی جانچ کرتے وقت ایک خرابی پیش آئی: ", + "The updater could not be launched.": "اپڈیٹر شروع نہیں کیا جا سکا۔", + "The operating system did not start the installer process.": "آپریٹنگ سسٹم نے انسٹالر پروسیس شروع نہیں کیا۔", + "UniGetUI is being updated...": "UniGetUI کو اپ ڈیٹ کیا جا رہا ہے...", + "Update installed.": "اپ ڈیٹ انسٹال ہو گئی۔", + "UniGetUI was updated successfully, but this running copy was not replaced. This usually means you are running a development build. Close this copy and start the newly-installed version to finish.": "UniGetUI کو کامیابی سے اپ ڈیٹ کر دیا گیا، لیکن چلنے والی یہ کاپی تبدیل نہیں ہوئی۔ اس کا عموماً مطلب ہے کہ آپ ڈیولپمنٹ بلڈ چلا رہے ہیں۔ مکمل کرنے کے لیے اس کاپی کو بند کریں اور نیا انسٹال شدہ ورژن شروع کریں۔", + "The update could not be applied.": "اپ ڈیٹ لاگو نہیں کی جا سکی۔", + "Installer exit code {0}: {1}": "انسٹالر ایگزٹ کوڈ {0}: {1}", + "Update cancelled.": "اپ ڈیٹ منسوخ ہو گئی۔", + "Authentication was cancelled.": "تصدیق منسوخ ہو گئی۔", + "Installer exit code {0}": "انسٹالر ایگزٹ کوڈ {0}", + "Operation in progress": "آپریشن جاری ہے", + "Please wait...": "برائے مہربانی انتظار کریں...", + "Success!": "کامیابی!", + "Failed": "ناکام", + "An error occurred while processing this package": "اس پیکیج کو پروسیس کرتے وقت ایک خرابی پیش آئی", + "Installer": "انسٹالر", + "Executable": "ایگزیکیوٹیبل", + "MSI": "MSI", + "Compressed file": "کمپریسڈ فائل", + "MSIX": "MSIX", + "WinGet was repaired successfully": "WinGet کو کامیابی کے ساتھ ٹھیک کیا گیا۔", + "It is recommended to restart UniGetUI after WinGet has been repaired": "WinGet کی مرمت کے بعد UniGetUI کو دوبارہ شروع کرنے کی سفارش کی جاتی ہے۔", + "WinGet could not be repaired": "WinGet کی مرمت نہیں ہو سکی", + "An unexpected issue occurred while attempting to repair WinGet. Please try again later": "WinGet کو ٹھیک کرنے کی کوشش کے دوران ایک غیر متوقع مسئلہ پیش آیا۔ براہ کرم بعد میں دوبارہ کوشش کریں۔", + "Log in to enable cloud backup": "کلاؤڈ بیک اپ فعال کرنے کے لیے لاگ ان کریں", + "Backup Failed": "بیک اپ ناکام ہو گیا", + "Downloading backup...": "بیک اپ ڈاؤن لوڈ ہو رہا ہے...", + "An update was found!": "ایک اپ ڈیٹ ملا!", + "{0} can be updated to version {1}": "{0} کو ورژن {1} میں اپ ڈیٹ کیا جا سکتا ہے", + "Updates found!": "اپ ڈیٹس مل گئیں!", + "{0} packages can be updated": "{0} پیکیجز کو اپ ڈیٹ کیا جا سکتا ہے", + "{0} is being updated to version {1}": "{0} ورژن {1} میں اپ ڈیٹ ہو رہا ہے", + "{0} packages are being updated": "{0} پیکیجز اپ ڈیٹ ہو رہے ہیں", + "You have currently version {0} installed": "آپ کے پاس فی الحال ورژن {0} انسٹال ہے۔", + "Desktop shortcut created": "ڈیسک ٹاپ شارٹ کٹ بنایا گیا۔", + "UniGetUI has detected a new desktop shortcut that can be deleted automatically.": "UniGetUI نے ایک نئے ڈیسک ٹاپ شارٹ کٹ کا پتہ لگایا ہے جسے خود بخود حذف کیا جا سکتا ہے۔", + "{0} desktop shortcuts created": "{0} ڈیسک ٹاپ شارٹ کٹس بنائے گئے۔", + "UniGetUI has detected {0} new desktop shortcuts that can be deleted automatically.": "UniGetUI نے {0} نئے ڈیسک ٹاپ شارٹ کٹس کا پتہ لگایا ہے جو خود بخود حذف ہو سکتے ہیں۔", + "Attention required": "توجہ درکار ہے", + "Restart required": "دوبارہ شروع کرنا ضروری ہے", + "1 update is available": "۱ اپ ڈیٹ دستیاب ہے", + "{0} updates are available": "{0} اپ ڈیٹس دستیاب ہیں", + "Everything is up to date": "سب کچھ تازہ ترین ہے", + "Discover Packages": "پیکیجز دریافت کریں۔", + "Available Updates": "دستیاب اپ ڈیٹس", + "Installed Packages": "انسٹال شدہ پیکجز", + "UniGetUI Version {0} by Devolutions": "Devolutions کی جانب سے UniGetUI ورژن {0}", + "Show UniGetUI": "UniGetUI دکھائیں", + "Quit": "بند کریں", + "Are you sure?": "کیا آپ یقین رکھتے ہیں؟", + "Do you really want to uninstall {0}?": "کیا آپ واقعی {0} کو اَن انسٹال کرنا چاہتے ہیں؟", + "Do you really want to uninstall the following {0} packages?": "کیا آپ واقعی درج ذیل {0} پیکجوں کو اَن انسٹال کرنا چاہتے ہیں؟", + "No": "نہیں", + "Yes": "جی ہاں", + "Partial": "جزوی", + "View on UniGetUI": "UniGetUI پر دیکھیں", + "Update": "اپ ڈیٹ", + "Open UniGetUI": "UniGetUI کھولیں۔", + "Update all": "سب کو اپ ڈیٹ کریں", + "Update now": "ابھی اپ ڈیٹ کریں", + "Installer host changed since the installed version.\n": "انسٹال شدہ ورژن کے مقابلے میں انسٹالر ہوسٹ تبدیل ہو گیا ہے۔\n", + "This package is on the queue": "یہ پیکج قطار میں ہے۔", + "installing": "انسٹال ہو رہا ہے", + "updating": "اپ ڈیٹ ہو رہا ہے", + "uninstalling": "ان انسٹال ہو رہا ہے", + "installed": "انسٹال ہو چکا ہے", + "Retry": "دوبارہ کوشش کریں", + "Install": "انسٹال کریں", + "Uninstall": "ان انسٹال کریں", + "Open": "کھولیں", + "Operation profile:": "آپریشن پروفائل:", + "Follow the default options when installing, upgrading or uninstalling this package": "اس پیکیج کو انسٹال، اپ گریڈ یا ان انسٹال کرتے وقت ڈیفالٹ اختیارات پر عمل کریں", + "The following settings will be applied each time this package is installed, updated or removed.": "ہر بار جب یہ پیکیج انسٹال، اپ ڈیٹ یا ہٹایا جائے گا تو درج ذیل ترتیبات لاگو ہوں گی۔", + "Version to install:": "انسٹال کرنے کے لئے ورژن:", + "Architecture to install:": "تنصیب کے لئے فن تعمیر:", + "Installation scope:": "انسٹالیشن کا دائرہ:", + "Install location:": "انسٹال مقام:", + "Select": "منتخب کریں", + "Reset": "ری سیٹ کریں", + "Custom install arguments:": "حسب ضرورت انسٹال دلائل:", + "Custom update arguments:": "حسب ضرورت اپ ڈیٹ دلائل:", + "Custom uninstall arguments:": "حسب ضرورت ان انسٹال دلائل:", + "Pre-install command:": "پری انسٹال کمانڈ:", + "Post-install command:": "پوسٹ انسٹال کمانڈ:", + "Abort install if pre-install command fails": "اگر پری انسٹال کمانڈ ناکام ہو تو انسٹالیشن منسوخ کریں", + "Pre-update command:": "پری اپ ڈیٹ کمانڈ:", + "Post-update command:": "پوسٹ اپ ڈیٹ کمانڈ:", + "Abort update if pre-update command fails": "اگر پری اپ ڈیٹ کمانڈ ناکام ہو تو اپ ڈیٹ منسوخ کریں", + "Pre-uninstall command:": "پری ان انسٹال کمانڈ:", + "Post-uninstall command:": "پوسٹ ان انسٹال کمانڈ:", + "Abort uninstall if pre-uninstall command fails": "اگر پری ان انسٹال کمانڈ ناکام ہو تو ان انسٹالیشن منسوخ کریں", + "Command-line to run:": "چلانے کے لیے کمانڈ لائن:", + "Save and close": "محفوظ کریں اور بند کریں", + "General": "عمومی", + "Architecture & Location": "آرکیٹیکچر اور مقام", + "Command-line": "کمانڈ لائن", + "Close apps": "ایپس بند کریں", + "Pre/Post install": "پری/پوسٹ انسٹال", + "Select the processes that should be closed before this package is installed, updated or uninstalled.": "وہ پروسیس منتخب کریں جو اس پیکیج کے انسٹال، اپ ڈیٹ یا ان انسٹال ہونے سے پہلے بند ہونے چاہئیں۔", + "Write here the process names here, separated by commas (,)": "یہاں پروسیسز کے نام لکھیں، کوما (,) سے الگ کریں", + "Try to kill the processes that refuse to close when requested to": "ان پروسیسز کو ختم کرنے کی کوشش کریں جو درخواست کرنے پر بند ہونے سے انکار کرتے ہیں", + "Run as admin": "ایڈمن کے طور پر چلائیں", + "Interactive installation": "انٹرایکٹو تنصیب", + "Skip hash check": "ہیش چیک چھوڑیں", + "Uninstall previous versions when updated": "اپ ڈیٹ ہونے پر پچھلے ورژنز کو ان انسٹال کریں", + "Skip minor updates for this package": "اس پیکیج کے لیے معمولی اپ ڈیٹس کو چھوڑ دیں۔", + "Automatically update this package": "اس پیکیج کو خود بخود اپ ڈیٹ کریں", + "{0} installation options": "{0} انسٹالیشن کے اختیارات", + "Latest": "تازہ ترین", + "PreRelease": "پری ریلیز", + "Default": "طے شدہ", + "Manage ignored updates": "نظرانداز کردہ اپ ڈیٹس کو منظم کریں", + "The packages listed here won't be taken in account when checking for updates. Double-click them or click the button on their right to stop ignoring their updates.": "اپ ڈیٹس کی جانچ کرتے وقت یہاں درج پیکیجز کو مدنظر نہیں رکھا جائے گا۔ ان پر ڈبل کلک کریں یا ان کے دائیں جانب کے بٹن پر کلک کریں تاکہ ان کی اپ ڈیٹس کو نظر انداز کرنا بند کر دیں۔", + "Reset list": "فہرست کو دوبارہ ترتیب دیں۔", + "Do you really want to reset the ignored updates list? This action cannot be reverted": "کیا آپ واقعی نظرانداز کردہ اپ ڈیٹس کی فہرست کو دوبارہ ترتیب دینا چاہتے ہیں؟ اس کارروائی کو واپس نہیں لیا جا سکتا۔", + "No ignored updates": "کوئی نظرانداز کردہ اپ ڈیٹس نہیں", + "Package Name": "پیکیج کا نام", + "Package ID": "پیکیج آئی ڈی", + "Ignored version": "نظرانداز کردہ ورژن", + "New version": "نیا ورژن", + "Source": "ذریعہ", + "All versions": "تمام ورژنز", + "Unknown": "نامعلوم", + "Up to date": "تازہ ترین", + "Package {name} from {manager}": "{manager} سے پیکیج {name}", + "Remove {0} from ignored updates": "{0} کو نظرانداز شدہ اپ ڈیٹس سے ہٹائیں", + "Cancel": "منسوخ کریں", + "Administrator privileges": "ایڈمنسٹریٹر کی مراعات", + "This operation is running with administrator privileges.": "یہ آپریشن ایڈمنسٹریٹر کی مراعات کے ساتھ چل رہا ہے۔", + "Interactive operation": "انٹرایکٹو آپریشن", + "This operation is running interactively.": "یہ آپریشن انٹرایکٹو چل رہا ہے۔", + "You will likely need to interact with the installer.": "آپ کو ممکنہ طور پر انسٹالر کے ساتھ بات چیت کرنے کی ضرورت ہوگی۔", + "Integrity checks skipped": "سالمیت کی جانچ کو چھوڑ دیا گیا۔", + "Integrity checks will not be performed during this operation.": "اس آپریشن کے دوران سالمیت کی جانچ نہیں کی جائے گی۔", + "Proceed at your own risk.": "اپنی ذمہ داری پر آگے بڑھیں۔", + "Close": "بند کریں", + "Loading...": "لوڈ ہو رہا ہے...", + "Installer SHA256": "انسٹالر SHA256", + "Homepage": "ہوم پیج", + "Author": "مصنف", + "Publisher": "پبلشر", + "License": "لائسنس", + "Manifest": "منصوبہ", + "Installer Type": "انسٹالر کی قسم", + "Size": "سائز", + "Installer URL": "انسٹالر یو آر ایل", + "Last updated:": "آخری بار اپ ڈیٹ کیا گیا:", + "Release notes URL": "ریلیز نوٹس یو آر ایل", + "Package details": "پیکیج کی تفصیلات", + "Dependencies:": "انحصارات:", + "Release notes": "ریلیز نوٹس", + "Screenshots": "اسکرین شاٹس", + "This package has no screenshots or is missing the icon? Contribute to UniGetUI by adding the missing icons and screenshots to our open, public database.": "اس پیکیج میں کوئی اسکرین شاٹس نہیں ہیں یا آئیکن موجود نہیں؟ گم شدہ آئیکنز اور اسکرین شاٹس ہمارے کھلے، عوامی ڈیٹا بیس میں شامل کر کے UniGetUI میں تعاون کریں۔", + "Version": "ورژن", + "Install as administrator": "ایڈمنسٹریٹر کے طور پر انسٹال کریں", + "Update to version {0}": "ورژن {0} میں اپ ڈیٹ کریں", + "Installed Version": "انسٹال شدہ ورژن", + "Update as administrator": "ایڈمنسٹریٹر کے طور پر اپ ڈیٹ کریں", + "Interactive update": "انٹرایکٹو اپ ڈیٹ", + "Uninstall as administrator": "بطور ایڈمنسٹریٹر ان انسٹال کریں۔", + "Interactive uninstall": "انٹرایکٹو ان انسٹال", + "Uninstall and remove data": "ان انسٹال کریں اور ڈیٹا کو ہٹا دیں۔", + "Not available": "دستیاب نہیں", + "Installer SHA512": "انسٹالر SHA512", + "Unknown size": "نامعلوم سائز", + "No dependencies specified": "کوئی انحصارات متعین نہیں", + "mandatory": "لازمی", + "optional": "اختیاری", + "UniGetUI {0} is ready to be installed.": "UniGetUI {0} انسٹال ہونے کے لیے تیار ہے۔", + "The update process will start after closing UniGetUI": "اپ ڈیٹ کا عمل UniGetUI کو بند کرنے کے بعد شروع ہوگا۔", + "UniGetUI has been ran as administrator, which is not recommended. When running UniGetUI as administrator, EVERY operation launched from UniGetUI will have administrator privileges. You can still use the program, but we highly recommend not running UniGetUI with administrator privileges.": "UniGetUI کو ایڈمنسٹریٹر کے طور پر چلایا گیا ہے، جس کی سفارش نہیں کی جاتی۔ جب UniGetUI ایڈمنسٹریٹر کے طور پر چلتا ہے تو UniGetUI سے شروع کی گئی ہر کارروائی کو ایڈمنسٹریٹر کی مراعات حاصل ہوں گی۔ آپ اب بھی پروگرام استعمال کر سکتے ہیں، لیکن ہم سختی سے تجویز کرتے ہیں کہ UniGetUI کو ایڈمنسٹریٹر کی مراعات کے ساتھ نہ چلائیں۔", + "Share anonymous usage data": "گمنام استعمال کا ڈیٹا شیئر کریں۔", + "UniGetUI collects anonymous usage data in order to improve the user experience.": "UniGetUI صارف کے تجربے کو بہتر بنانے کے لیے گمنام استعمال کا ڈیٹا اکٹھا کرتا ہے۔", + "Accept": "قبول کریں۔", + "Software Updates": "سافٹ ویئر اپ ڈیٹس", + "Package Bundles": "پیکیج بنڈلز", + "Settings": "ترتیبات", + "Package Managers": "پیکیج مینیجرز", + "UniGetUI Log": "UniGetUI لاگ", + "Package Manager logs": "پیکیج منیجر لاگز", + "Operation history": "آپریشن کی تاریخ", + "Help": "مدد", + "UniGetUI": "UniGetUI", + "You have installed UniGetUI Version {0}": "آپ نے UniGetUI ورژن {0} انسٹال کیا ہے", + "Disclaimer": "دستبرداری", + "UniGetUI is developed by Devolutions and is not affiliated with any of the compatible package managers.": "UniGetUI کو Devolutions نے تیار کیا ہے اور یہ کسی بھی موافق پیکیج مینیجر سے وابستہ نہیں ہے۔", + "UniGetUI wouldn't have been possible without the help of the contributors. Thank you all 🥳": "UniGetUI تعاون کرنے والوں کی مدد کے بغیر ممکن نہیں تھا۔ آپ سب کا شکریہ 🥳", + "UniGetUI uses the following libraries. Without them, UniGetUI wouldn't have been possible.": "UniGetUI درج ذیل لائبریریوں کا استعمال کرتا ہے۔ ان کے بغیر، UniGetUI ممکن نہیں ہوتا۔", + "{0} homepage": "{0} ہوم پیج", + "UniGetUI has been translated to more than 40 languages thanks to the volunteer translators. Thank you 🤝": "رضاکار مترجمین کی بدولت UniGetUI کا 40 سے زیادہ زبانوں میں ترجمہ ہو چکا ہے۔ شکریہ 🤝", + "Verbose": "تفصیل سے", + "1 - Errors": "۱ - غلطیاں", + "2 - Warnings": "۲ - انتباہات", + "3 - Information (less)": "۳ - معلومات (کم)", + "4 - Information (more)": "۴ - معلومات (زیادہ)", + "5 - information (debug)": "۵ - معلومات (ڈی بگ)", + "Warning": "انتباہ", + "The following settings may pose a security risk, hence they are disabled by default.": "درج ذیل ترتیبات سیکیورٹی کا خطرہ پیدا کر سکتی ہیں، اس لیے وہ ڈیفالٹ طور پر غیر فعال ہیں۔", + "Enable the settings below if and only if you fully understand what they do, and the implications they may have.": "درج ذیل ترتیبات کو صرف اسی صورت فعال کریں جب آپ مکمل طور پر سمجھتے ہوں کہ وہ کیا کرتی ہیں اور ان کے ممکنہ اثرات کیا ہو سکتے ہیں۔", + "The settings will list, in their descriptions, the potential security issues they may have.": "ترتیبات اپنی وضاحتوں میں ان ممکنہ سیکیورٹی مسائل کی فہرست دیں گی جو ان میں ہو سکتے ہیں۔", + "The backup will include the complete list of the installed packages and their installation options. Ignored updates and skipped versions will also be saved.": "بیک اپ میں انسٹال شدہ پیکجوں کی مکمل فہرست اور ان کی تنصیب کے اختیارات شامل ہوں گے۔ نظر انداز کیے گئے اپ ڈیٹس اور چھوڑے گئے ورژن بھی محفوظ کیے جائیں گے۔", + "The backup will NOT include any binary file nor any program's saved data.": "بیک اپ میں کوئی بائنری فائل شامل نہیں ہوگی اور نہ ہی کسی پروگرام کا محفوظ کردہ ڈیٹا۔", + "The size of the backup is estimated to be less than 1MB.": "بیک اپ کے سائز کا تخمینہ 1MB سے کم ہے۔", + "The backup will be performed after login.": "لاگ ان کے بعد بیک اپ لیا جائے گا۔", + "{pcName} installed packages": "{pcName} پر انسٹال شدہ پیکیجز", + "Current status: Not logged in": "موجودہ حالت: لاگ ان نہیں ہے", + "You are logged in as {0} (@{1})": "آپ {0} (@{1}) کے طور پر لاگ ان ہیں", + "Nice! Backups will be uploaded to a private gist on your account": "بہترین! بیک اپس آپ کے اکاؤنٹ پر نجی gist میں اپ لوڈ کیے جائیں گے", + "Select backup": "بیک اپ منتخب کریں", + "Settings imported from {0}": "ترتیبات {0} سے درآمد کی گئیں", + "UniGetUI Settings": "UniGetUI ترتیبات", + "Settings exported to {0}": "ترتیبات {0} میں برآمد کی گئیں", + "UniGetUI settings were reset": "UniGetUI کی ترتیبات دوبارہ سیٹ کر دی گئیں", + "Allow pre-release versions": "پری ریلیز ورژنز کی اجازت دیں", + "Apply": "لاگو کریں", + "For security reasons, custom command-line arguments are disabled by default. Go to UniGetUI security settings to change this.": "سیکیورٹی وجوہات کی بنا پر حسب ضرورت کمانڈ لائن دلائل ڈیفالٹ طور پر غیر فعال ہیں۔ اسے تبدیل کرنے کے لیے UniGetUI کی سیکیورٹی ترتیبات پر جائیں۔", + "Go to UniGetUI security settings": "UniGetUI سیکیورٹی کی ترتیبات پر جائیں", + "The following options will be applied by default each time a {0} package is installed, upgraded or uninstalled.": "درج ذیل اختیارات ہر بار {0} پیکیج کے انسٹال، اپ گریڈ یا ان انسٹال ہونے پر ڈیفالٹ کے طور پر لاگو کیے جائیں گے۔", + "Package's default": "پیکیج کا ڈیفالٹ", + "Install location can't be changed for {0} packages": "{0} پیکجز کے لیے انسٹال مقام تبدیل نہیں کیا جا سکتا", + "The local icon cache currently takes {0} MB": "مقامی آئیکن کیش فی الحال {0} MB لیتا ہے۔", + "Username": "صارف کا نام", + "Password": "پاس ورڈ", + "Credentials": "اسناد", + "It is not guaranteed that the provided credentials will be stored safely": "اس بات کی ضمانت نہیں دی جا سکتی کہ فراہم کردہ اسناد محفوظ طریقے سے ذخیرہ ہوں گی۔", + "Partially": "جزوی طور پر", + "Package manager": "پیکیج منیجر", + "Compatible with proxy": "پروکسی کے ساتھ مطابقت رکھتا ہے", + "Compatible with authentication": "تصدیق کے ساتھ مطابقت رکھتا ہے", + "Proxy compatibility table": "پروکسی مطابقت ٹیبل", + "{0} settings": "{0} ترتیبات", + "{0} status": "{0} حالت", + "Default installation options for {0} packages": "{0} پیکجز کے لیے ڈیفالٹ انسٹالیشن اختیارات", + "Expand version": "ورژن کو پھیلائیں۔", + "The executable file for {0} was not found": "{0} کے لیے قابل عمل فائل نہیں ملی", + "{pm} is disabled": "{pm} غیر فعال ہے", + "Enable it to install packages from {pm}.": "{pm} سے پیکجز انسٹال کرنے کے لیے اسے فعال کریں۔", + "{pm} is enabled and ready to go": "{pm} فعال ہے اور تیار ہے", + "{pm} version:": "{pm} ورژن:", + "{pm} was not found!": "{pm} نہیں ملا!", + "You may need to install {pm} in order to use it with UniGetUI.": "UniGetUI کے ساتھ استعمال کرنے کے لیے آپ کو {pm} انسٹال کرنے کی ضرورت پڑ سکتی ہے۔", + "Scoop Installer - UniGetUI": "Scoop انسٹالر - UniGetUI", + "Scoop Uninstaller - UniGetUI": "Scoop ان انسٹالر - UniGetUI", + "Clearing Scoop cache - UniGetUI": "اسکوپ کیشے کو صاف کرنا - UniGetUI", + "Restart UniGetUI to fully apply changes": "تبدیلیاں مکمل طور پر لاگو کرنے کے لیے UniGetUI دوبارہ شروع کریں", + "Restart UniGetUI": "UniGetUI دوبارہ شروع کریں", + "Manage {0} sources": "{0} ماخذ کو منظم کریں", + "Add source": "ذریعہ شامل کریں", + "Add": "شامل کریں", + "Source name": "ماخذ کا نام", + "Source URL": "ماخذ URL", + "Other": "دیگر", + "No minimum age": "کم از کم مدت نہیں", + "1 day": "۱ دن", + "{0} days": "{0} دن", + "Custom...": "حسب ضرورت...", + "{0} minutes": "{0} منٹ", + "1 hour": "۱ گھنٹہ", + "{0} hours": "{0} گھنٹے", + "1 week": "۱ ہفتہ", + "Supports release dates": "ریلیز کی تاریخوں کی معاونت کرتا ہے", + "Release date support per package manager": "ہر پیکیج مینیجر کے لیے ریلیز کی تاریخ کی معاونت", + "Search for packages": "پیکیجز تلاش کریں", + "Local": "مقامی", + "OK": "ٹھیک ہے", + "Last checked: {0}": "آخری بار جانچ: {0}", + "{0} packages were found, {1} of which match the specified filters.": "{0} پیکیجز ملے، جن میں سے {1} مخصوص فلٹرز کے مطابق ہیں", + "{0} selected": "{0} منتخب ہے", + "(Last checked: {0})": "(آخری چیک: {0})", + "All packages selected": "تمام پیکیجز منتخب کیے گئے", + "Package selection cleared": "پیکیج کا انتخاب صاف کیا گیا", + "{0}: {1}": "{0}: {1}", + "More info": "مزید معلومات", + "GitHub account": "GitHub اکاؤنٹ", + "Log in with GitHub to enable cloud package backup.": "کلاؤڈ پیکیج بیک اپ فعال کرنے کے لیے GitHub کے ساتھ لاگ ان کریں۔", + "More details": "مزید تفصیلات", + "Log in": "لاگ ان کریں", + "If you have cloud backup enabled, it will be saved as a GitHub Gist on this account": "اگر کلاؤڈ بیک اپ فعال ہے تو یہ اس اکاؤنٹ پر GitHub Gist کے طور پر محفوظ ہوگا", + "Log out": "لاگ آؤٹ کریں", + "About UniGetUI": "UniGetUI کے بارے میں", + "About": "کے بارے میں", + "Third-party licenses": "تیسری پارٹی کے لائسنس", + "Contributors": "تعاون کرنے والے", + "Translators": "مترجم", + "Bundle security report": "بنڈل کی سیکیورٹی رپورٹ", + "The bundle contained restricted content": "بنڈل میں محدود مواد شامل تھا", + "UniGetUI – Crash Report": "UniGetUI – کریش رپورٹ", + "UniGetUI has crashed": "UniGetUI کریش ہو گیا ہے", + "Help us fix this by sending a crash report to Devolutions. All fields below are optional.": "Devolutions کو کریش رپورٹ بھیج کر اسے ٹھیک کرنے میں ہماری مدد کریں۔ نیچے دیے گئے تمام فیلڈز اختیاری ہیں۔", + "Email (optional)": "ای میل (اختیاری)", + "your@email.com": "your@email.com", + "Additional details (optional)": "اضافی تفصیلات (اختیاری)", + "Describe what you were doing when the crash occurred…": "بیان کریں کہ کریش ہونے پر آپ کیا کر رہے تھے…", + "Crash report": "کریش رپورٹ", + "Don't Send": "مت بھیجیں", + "Send Report": "رپورٹ بھیجیں", + "Sending…": "بھیجا جا رہا ہے…", + "Unsaved changes": "غیر محفوظ شدہ تبدیلیاں", + "You have unsaved changes in the current bundle. Do you want to discard them?": "موجودہ بنڈل میں آپ کی کچھ تبدیلیاں محفوظ نہیں ہیں۔ کیا آپ انہیں رد کرنا چاہتے ہیں؟", + "Discard changes": "تبدیلیاں رد کریں", + "Integrity violation": "سالمیت کی خلاف ورزی", + "UniGetUI or some of its components are missing or corrupt. It is strongly recommended to reinstall UniGetUI to adress the situation.": "UniGetUI یا اس کے کچھ اجزاء غائب یا خراب ہیں۔ صورتحال سے نمٹنے کے لیے UniGetUI کو دوبارہ انسٹال کرنے کی سختی سے سفارش کی جاتی ہے۔", + "• Refer to the UniGetUI Logs to get more details regarding the affected file(s)": "• متاثرہ فائلوں کے بارے میں مزید تفصیلات حاصل کرنے کے لیے UniGetUI لاگز دیکھیں", + "• Integrity checks can be disabled from the Experimental Settings": "• سالمیت کی جانچ کو تجرباتی ترتیبات سے غیر فعال کیا جا سکتا ہے", + "Manage shortcuts": "شارٹ کٹس کا نظم کریں۔", + "UniGetUI has detected the following desktop shortcuts which can be removed automatically on future upgrades": "UniGetUI نے مندرجہ ذیل ڈیسک ٹاپ شارٹ کٹس کا پتہ لگایا ہے جنہیں مستقبل کے اپ گریڈ پر خود بخود ہٹایا جا سکتا ہے۔", + "Do you really want to reset this list? This action cannot be reverted.": "کیا آپ واقعی اس فہرست کو دوبارہ ترتیب دینا چاہتے ہیں؟ اس کارروائی کو واپس نہیں لیا جا سکتا۔", + "Desktop shortcuts list": "ڈیسک ٹاپ شارٹ کٹس کی فہرست", + "Open in explorer": "ایکسپلورر میں کھولیں", + "Remove from list": "فہرست سے ہٹائیں", + "When new shortcuts are detected, delete them automatically instead of showing this dialog.": "جب نئے شارٹ کٹس دریافت ہوں تو اس ڈائیلاگ کو دکھانے کے بجائے انہیں خود بخود حذف کریں۔", + "Not right now": "ابھی نہیں", + "Missing dependency": "ضروریات غائب ہیں", + "UniGetUI requires {0} to operate, but it was not found on your system.": "UniGetUI کو آپریٹ کرنے کے لیے {0} کی ضرورت ہے، لیکن یہ آپ کے سسٹم پر نہیں ملا۔", + "Click on Install to begin the installation process. If you skip the installation, UniGetUI may not work as expected.": "تنصیب کا عمل شروع کرنے کے لیے انسٹال پر کلک کریں۔ اگر آپ انسٹالیشن کو چھوڑ دیتے ہیں تو ہو سکتا ہے UniGetUI توقع کے مطابق کام نہ کرے۔", + "Alternatively, you can also install {0} by running the following command in a Windows PowerShell prompt:": "متبادل طور پر، آپ Windows PowerShell پرامپٹ میں درج ذیل کمانڈ کو چلا کر بھی {0} کو انسٹال کر سکتے ہیں:", + "Install {0}": "انسٹال کریں {0}", + "Do not show this dialog again for {0}": "{0} کے لیے یہ ڈائیلاگ دوبارہ مت دکھائیں", + "Please wait while {0} is being installed. A black window may show up. Please wait until it closes.": "براہ کرم {0} کے انسٹال ہونے تک انتظار کریں۔ ایک سیاہ ونڈو ظاہر ہوسکتی ہے۔ براہ کرم اس کے بند ہونے تک انتظار کریں۔", + "{0} has been installed successfully.": "{0} کامیابی سے انسٹال ہو گیا ہے۔", + "Please click on \"Continue\" to continue": "جاری رکھنے کے لئے براہ کرم \"Continue\" پر کلک کریں", + "Continue": "جاری رکھیں", + "{0} has been installed successfully. It is recommended to restart UniGetUI to finish the installation": "{0} کامیابی سے انسٹال ہو گیا ہے۔ تنصیب کو مکمل کرنے کے لیے UniGetUI کو دوبارہ شروع کرنے کی سفارش کی جاتی ہے۔", + "Restart later": "بعد میں دوبارہ شروع کریں", + "An error occurred:": "ایک خرابی پیش آئی:", + "Please see the Command-line Output or refer to the Operation History for further information about the issue.": "براہ کرم کمانڈ لائن آؤٹ پٹ دیکھیں یا مسئلے کے بارے میں مزید معلومات کے لیے آپریشن کی تاریخ دیکھیں۔", + "Retry as administrator": "بطور منتظم دوبارہ کوشش کریں۔", + "Retry interactively": "انٹرایکٹو دوبارہ کوشش کریں۔", + "Retry skipping integrity checks": "سالمیت کی جانچ کو چھوڑنے کی دوبارہ کوشش کریں۔", + "Installation options": "انسٹالیشن کے اختیارات", + "Save": "محفوظ کریں", + "UniGetUI collects anonymous usage data with the sole purpose of understanding and improving the user experience.": "UniGetUI صارف کے تجربے کو سمجھنے اور بہتر بنانے کے واحد مقصد کے ساتھ گمنام استعمال کا ڈیٹا اکٹھا کرتا ہے۔", + "More details about the shared data and how it will be processed": "مشترکہ ڈیٹا کے بارے میں مزید تفصیلات اور اس پر کارروائی کیسے کی جائے گی۔", + "Do you accept that UniGetUI collects and sends anonymous usage statistics, with the sole purpose of understanding and improving the user experience?": "کیا آپ قبول کرتے ہیں کہ UniGetUI استعمال کے گمنام اعدادوشمار جمع اور بھیجتا ہے، جس کا واحد مقصد صارف کے تجربے کو سمجھنا اور بہتر بنانا ہے؟", + "Decline": "رد کرنا", + "No personal information is collected nor sent, and the collected data is anonimized, so it can't be back-tracked to you.": "کوئی ذاتی معلومات اکٹھی نہیں کی جاتی اور نہ ہی بھیجی جاتی ہے، اور جمع کردہ ڈیٹا کو گمنام کر دیا جاتا ہے، اس لیے اسے آپ کو بیک ٹریک نہیں کیا جا سکتا۔", + "Navigation panel": "نیویگیشن پینل", + "Operations": "آپریشنز", + "Toggle operations panel": "آپریشنز پینل ٹوگل کریں", + "Bulk operations": "بلک آپریشنز", + "Retry failed": "ناکام آپریشنز دوبارہ آزمائیں", + "Clear successful": "کامیاب آپریشنز صاف کریں", + "Clear finished": "مکمل شدہ آپریشنز صاف کریں", + "Cancel all": "سب منسوخ کریں", + "More": "مزید", + "Toggle navigation panel": "نیویگیشن پینل ٹوگل کریں", + "Minimize": "چھوٹا کریں", + "Maximize": "بڑا کریں", + "UniGetUI by Devolutions": "Devolutions کی جانب سے UniGetUI", + "UniGetUI is an application that makes managing your software easier, by providing an all-in-one graphical interface for your command-line package managers.": "UniGetUI ایک ایسی ایپلی کیشن ہے جو آپ کے کمانڈ لائن پیکج مینیجرز کے لیے ایک آل ان ون گرافیکل انٹرفیس فراہم کر کے آپ کے سافٹ ویئر کا انتظام آسان بناتی ہے۔", + "Useful links": "مفید لنکس", + "UniGetUI Homepage": "UniGetUI ہوم پیج", + "Report an issue or submit a feature request": "مسئلہ رپورٹ کریں یا فیچر کی درخواست جمع کروائیں", + "UniGetUI Repository": "UniGetUI ریپوزٹری", + "View GitHub Profile": "GitHub پروفائل دیکھیں", + "UniGetUI License": "UniGetUI لائسنس", + "Using UniGetUI implies the acceptation of the MIT License": "UniGetUI کا استعمال کرنے کا مطلب ہے کہ آپ نے MIT لائسنس کو قبول کر لیا ہے", + "Become a translator": "مترجم بنیں", + "Go back": "واپس جائیں", + "Go forward": "آگے جائیں", + "Go to home page": "ہوم پیج پر جائیں", + "Reload page": "صفحہ دوبارہ لوڈ کریں", + "View page on browser": "براؤزر میں صفحہ دیکھیں", + "The built-in browser is not supported on Linux yet.": "بلٹ اِن براؤزر ابھی Linux پر معاونت یافتہ نہیں ہے۔", + "Open in browser": "براؤزر میں کھولیں", + "Copy to clipboard": "کلپ بورڈ پر کاپی کریں۔", + "Export to a file": "فائل میں ایکسپورٹ کریں", + "Log level:": "لاگ کی سطح:", + "Reload log": "لاگ دوبارہ لوڈ کریں", + "Export log": "لاگ برآمد کریں", + "Text": "متن", + "Change how operations request administrator rights": "آپریشنز کے ایڈمنسٹریٹر حقوق کی درخواست کرنے کا طریقہ تبدیل کریں", + "Restrictions on package operations": "پیکیج آپریشنز پر پابندیاں", + "Restrictions on package managers": "پیکیج مینیجرز پر پابندیاں", + "Restrictions when importing package bundles": "پیکیج بنڈلز درآمد کرتے وقت پابندیاں", + "Ask for administrator privileges once for each batch of operations": "ہر بیچ کے آپریشنز کے لئے ایک بار ایڈمنسٹریٹر مراعات طلب کریں", + "Ask only once for administrator privileges": "صرف ایک بار ایڈمنسٹریٹر مراعات طلب کریں", + "Prohibit any kind of Elevation via UniGetUI Elevator or GSudo": "UniGetUI Elevator یا GSudo کے ذریعے کسی بھی قسم کی بلندی کو ممنوع قرار دیں", + "This option WILL cause issues. Any operation incapable of elevating itself WILL FAIL. Install/update/uninstall as administrator will NOT WORK.": "یہ اختیار یقیناً مسائل پیدا کرے گا۔ کوئی بھی آپریشن جو خود کو بلند کرنے کے قابل نہیں ہوگا ناکام ہو جائے گا۔ ایڈمنسٹریٹر کے طور پر انسٹال/اپ ڈیٹ/ان انسٹال کام نہیں کرے گا۔", + "Allow custom command-line arguments": "حسب ضرورت کمانڈ لائن دلائل کی اجازت دیں", + "Custom command-line arguments can change the way in which programs are installed, upgraded or uninstalled, in a way UniGetUI cannot control. Using custom command-lines can break packages. Proceed with caution.": "حسب ضرورت کمانڈ لائن دلائل اس طریقے کو بدل سکتے ہیں جس سے پروگرام انسٹال، اپ گریڈ یا ان انسٹال ہوتے ہیں، اور اس پر UniGetUI قابو نہیں رکھتا۔ حسب ضرورت کمانڈ لائنوں کا استعمال پیکجز کو خراب کر سکتا ہے۔ احتیاط سے آگے بڑھیں۔", + "Ignore custom pre-install and post-install commands when importing packages from a bundle": "حسب ضرورت پری انسٹال اور پوسٹ انسٹال کمانڈز کو چلانے کی اجازت دیں", + "Pre and post install commands will be run before and after a package gets installed, upgraded or uninstalled. Be aware that they may break things unless used carefully": "پری اور پوسٹ انسٹال کمانڈز پیکیج کے انسٹال، اپ گریڈ یا ان انسٹال ہونے سے پہلے اور بعد میں چلائی جائیں گی۔ خیال رکھیں کہ اگر احتیاط سے استعمال نہ کیا جائے تو یہ چیزوں کو خراب کر سکتی ہیں", + "Allow changing the paths for package manager executables": "پیکیج منیجر کے ایگزیکیوبلز کے راستے تبدیل کرنے کی اجازت دیں", + "Turning this on enables changing the executable file used to interact with package managers. While this allows finer-grained customization of your install processes, it may also be dangerous": "اسے آن کرنے سے پیکیج مینیجرز کے ساتھ تعامل کے لیے استعمال ہونے والی ایگزیکیوبل فائل کو تبدیل کرنا ممکن ہو جاتا ہے۔ اگرچہ یہ آپ کے انسٹالیشن عمل کو زیادہ باریک سطح پر حسب ضرورت بنانے دیتا ہے، لیکن یہ خطرناک بھی ہو سکتا ہے", + "Allow importing custom command-line arguments when importing packages from a bundle": "بنڈل سے پیکجز درآمد کرتے وقت حسب ضرورت کمانڈ لائن دلائل درآمد کرنے کی اجازت دیں", + "Malformed command-line arguments can break packages, or even allow a malicious actor to gain privileged execution. Therefore, importing custom command-line arguments is disabled by default": "خراب کمانڈ لائن دلائل پیکجز کو خراب کر سکتے ہیں، یا حتیٰ کہ کسی بدنیت عنصر کو خصوصی اجرا حاصل کرنے دے سکتے ہیں۔ اس لیے، حسب ضرورت کمانڈ لائن دلائل درآمد کرنا ڈیفالٹ طور پر غیر فعال ہے۔", + "Allow importing custom pre-install and post-install commands when importing packages from a bundle": "بنڈل سے پیکجز درآمد کرتے وقت حسب ضرورت پری انسٹال اور پوسٹ انسٹال کمانڈز درآمد کرنے کی اجازت دیں", + "Pre and post install commands can do very nasty things to your device, if designed to do so. It can be very dangerous to import the commands from a bundle, unless you trust the source of that package bundle": "پری اور پوسٹ انسٹال کمانڈز آپ کے ڈیوائس پر بہت نقصان دہ کام کر سکتی ہیں، اگر انہیں ایسا کرنے کے لیے ڈیزائن کیا گیا ہو۔ بنڈل سے کمانڈز درآمد کرنا بہت خطرناک ہو سکتا ہے، جب تک آپ اس پیکیج بنڈل کے ماخذ پر اعتماد نہ کریں", + "Administrator rights and other dangerous settings": "ایڈمنسٹریٹر کے حقوق اور دیگر خطرناک ترتیبات", + "Package backup": "پیکیج بیک اپ", + "Cloud package backup": "کلاؤڈ پیکیج بیک اپ", + "Local package backup": "مقامی پیکیج بیک اپ", + "Local backup advanced options": "مقامی بیک اپ کے اعلیٰ اختیارات", + "Log in with GitHub": "GitHub کے ساتھ لاگ ان کریں", + "Log out from GitHub": "GitHub سے لاگ آؤٹ کریں", + "Periodically perform a cloud backup of the installed packages": "وقتاً فوقتاً انسٹال شدہ پیکجز کا کلاؤڈ بیک اپ کریں", + "Cloud backup uses a private GitHub Gist to store a list of installed packages": "کلاؤڈ بیک اپ انسٹال شدہ پیکجز کی فہرست محفوظ کرنے کے لیے ایک نجی GitHub Gist استعمال کرتا ہے", + "Perform a cloud backup now": "ابھی کلاؤڈ بیک اپ کریں", + "Backup": "بیک اپ", + "Restore a backup from the cloud": "کلاؤڈ سے بیک اپ بحال کریں", + "Begin the process to select a cloud backup and review which packages to restore": "کلاؤڈ بیک اپ منتخب کرنے اور بحال کیے جانے والے پیکجز کا جائزہ لینے کا عمل شروع کریں", + "Periodically perform a local backup of the installed packages": "وقتاً فوقتاً انسٹال شدہ پیکجز کا مقامی بیک اپ کریں", + "Perform a local backup now": "ابھی مقامی بیک اپ کریں", + "Change backup output directory": "بیک اپ آؤٹ پٹ ڈائریکٹری تبدیل کریں", + "Set a custom backup file name": "اپنی مرضی کا بیک اپ فائل نام سیٹ کریں", + "Leave empty for default": "ڈیفالٹ کے لئے خالی چھوڑ دیں", + "Add a timestamp to the backup file names": "بیک اپ فائل کے ناموں میں ٹائم اسٹیمپ شامل کریں", + "Backup and Restore": "بیک اپ اور بحالی", + "Enable background api (UniGetUI Widgets and Sharing, port 7058)": "بیک گراؤنڈ API کو فعال کریں (UniGetUI وجیٹس اور شیئرنگ، پورٹ 7058)", + "Wait for the device to be connected to the internet before attempting to do tasks that require internet connectivity.": "انٹرنیٹ کنیکٹیویٹی کی ضرورت کے کاموں کو کرنے کی کوشش کرنے سے پہلے ڈیوائس کے انٹرنیٹ سے منسلک ہونے کا انتظار کریں۔", + "Disable the 1-minute timeout for package-related operations": "پیکیج سے متعلق کارروائیوں کے لیے 1 منٹ کا ٹائم آؤٹ غیر فعال کریں۔", + "Use installed GSudo instead of UniGetUI Elevator": "UniGetUI Elevator کی بجائے انسٹال شدہ GSudo استعمال کریں", + "Use a custom icon and screenshot database URL": "ایک حسب ضرورت آئیکن اور اسکرین شاٹ ڈیٹا بیس یو آر ایل کا استعمال کریں", + "Enable background CPU Usage optimizations (see Pull Request #3278)": "پس منظر CPU کے استعمال کی اصلاح کو فعال کریں (دیکھیں پل کی درخواست #3278)", + "Perform integrity checks at startup": "آغاز پر سالمیت کی جانچ کریں", + "When batch installing packages from a bundle, install also packages that are already installed": "جب بنڈل سے بیچ میں پیکجز انسٹال کیے جائیں تو وہ پیکجز بھی انسٹال کریں جو پہلے سے انسٹال ہیں", + "Experimental settings and developer options": "تجرباتی ترتیبات اور ڈویلپر کے اختیارات", + "Show UniGetUI's version and build number on the titlebar.": "ٹائٹل بار پر UniGetUI کا ورژن اور بلڈ نمبر دکھائیں۔", + "Language": "زبان", + "UniGetUI updater": "UniGetUI اپ ڈیٹر", + "Telemetry": "ٹیلیمیٹری", + "Manage UniGetUI settings": "UniGetUI کی ترتیبات کا انتظام کریں", + "Related settings": "متعلقہ ترتیبات", + "Update UniGetUI automatically": "UniGetUI کو خود بخود اپ ڈیٹ کریں", + "Check for updates": "اپ ڈیٹس کے لیے چیک کریں۔", + "Install prerelease versions of UniGetUI": "UniGetUI کے پری ریلیز ورژن انسٹال کریں۔", + "Manage telemetry settings": "ٹیلی میٹری کی ترتیبات کا نظم کریں۔", + "Manage": "انتظام کریں۔", + "Import settings from a local file": "مقامی فائل سے ترتیبات درآمد کریں", + "Import": "درآمد کریں", + "Export settings to a local file": "ترتیبات کو مقامی فائل میں ایکسپورٹ کریں", + "Export": "برآمد کریں", + "Reset UniGetUI": "UniGetUI کو دوبارہ ترتیب دیں۔", + "User interface preferences": "صارف انٹرفیس کی ترجیحات", + "Application theme, startup page, package icons, clear successful installs automatically": "ایپلیکیشن تھیم، سٹارٹ اپ پیج، پیکج آئیکنز، خود بخود کامیاب انسٹال صاف ہو جاتے ہیں۔", + "General preferences": "عمومی ترجیحات", + "UniGetUI display language:": "UniGetUI ڈسپلے زبان:", + "System language": "نظام کی زبان", + "Is your language missing or incomplete?": "کیا آپ کی زبان غائب ہے یا نامکمل؟", + "Appearance": "ظاہری شکل", + "UniGetUI on the background and system tray": "UniGetUI پس منظر اور سسٹم ٹرے میں", + "Package lists": "پیکیج کی فہرستیں", + "Use classic mode": "کلاسک موڈ استعمال کریں", + "Restart UniGetUI to apply this change": "یہ تبدیلی لاگو کرنے کے لیے UniGetUI کو دوبارہ شروع کریں", + "The classic UI is disabled for beta testers": "بیٹا ٹیسٹرز کے لیے کلاسک UI غیر فعال ہے", + "Close UniGetUI to the system tray": "UniGetUI کو سسٹم ٹرے میں بند کریں۔", + "Manage UniGetUI autostart behaviour": "UniGetUI کے خودکار آغاز کا رویہ منظم کریں", + "Show package icons on package lists": "پیکیج کی فہرستوں پر پیکیج کی شبیہیں دکھائیں۔", + "Clear cache": "کیشے صاف کریں۔", + "Select upgradable packages by default": "ڈیفالٹ کے لحاظ سے اپ گریڈ ایبل پیکجز کو منتخب کریں۔", + "Light": "ہلکا", + "Dark": "اندھیرا", + "Follow system color scheme": "سسٹم کلر سکیم پر عمل کریں۔", + "Application theme:": "ایپلیکیشن تھیم:", + "UniGetUI startup page:": "UniGetUI آغاز صفحہ:", + "Proxy settings": "پروکسی کی ترتیبات", + "Other settings": "دیگر ترتیبات", + "Connect the internet using a custom proxy": "حسب ضرورت پروکسی استعمال کرتے ہوئے انٹرنیٹ سے جڑیں", + "Please note that not all package managers may fully support this feature": "براہ کرم نوٹ کریں کہ تمام پیکیج مینیجرز اس خصوصیت کو مکمل طور پر سپورٹ نہیں کر سکتے", + "Proxy URL": "پروکسی URL", + "Enter proxy URL here": "یہاں پروکسی URL درج کریں", + "Authenticate to the proxy with a user and a password": "صارف نام اور پاس ورڈ کے ساتھ پروکسی پر توثیق کریں", + "Internet and proxy settings": "انٹرنیٹ اور پروکسی کی ترتیبات", + "Package manager preferences": "پیکیج منیجر کی ترجیحات", + "Ready": "تیار", + "Not found": "نہیں ملا", + "Notification preferences": "اطلاع کی ترجیحات", + "Notification types": "اطلاع کی اقسام", + "The system tray icon must be enabled in order for notifications to work": "اطلاعات کے کام کرنے کے لیے سسٹم ٹرے آئیکن کا فعال ہونا ضروری ہے۔", + "Enable UniGetUI notifications": "UniGetUI اطلاعات کو فعال کریں۔", + "Show a notification when there are available updates": "جب اپ ڈیٹس دستیاب ہوں تو نوٹیفکیشن دکھائیں", + "Show a silent notification when an operation is running": "جب کوئی آپریشن چل رہا ہو تو خاموش اطلاع دکھائیں۔", + "Show a notification when an operation fails": "آپریشن ناکام ہونے پر اطلاع دکھائیں۔", + "Show a notification when an operation finishes successfully": "جب آپریشن کامیابی سے ختم ہو جائے تو اطلاع دکھائیں۔", + "Concurrency and execution": "بیک وقت عمل اور اجرا", + "Automatic desktop shortcut remover": "خودکار ڈیسک ٹاپ شارٹ کٹ ہٹانے والا", + "Choose how many operations should be performed in parallel": "منتخب کریں کہ متوازی طور پر کتنے آپریشنز انجام دیے جائیں", + "Clear successful operations from the operation list after a 5 second delay": "5 سیکنڈ کی تاخیر کے بعد آپریشن لسٹ سے کامیاب آپریشنز کو صاف کریں۔", + "Download operations are not affected by this setting": "ڈاؤن لوڈ آپریشنز اس ترتیب سے متاثر نہیں ہوتے", + "You may lose unsaved data": "آپ محفوظ نہ کیا گیا ڈیٹا کھو سکتے ہیں", + "Ask to delete desktop shortcuts created during an install or upgrade.": "انسٹال یا اپ گریڈ کے دوران بنائے گئے ڈیسک ٹاپ شارٹ کٹس کو حذف کرنے کو کہیں۔", + "Package update preferences": "پیکیج اپ ڈیٹ کی ترجیحات", + "Update check frequency, automatically install updates, etc.": "اپ ڈیٹ کی جانچ کی تعدد، اپ ڈیٹس خود بخود انسٹال کریں، وغیرہ", + "Reduce UAC prompts, elevate installations by default, unlock certain dangerous features, etc.": "UAC اشاروں کو کم کریں، ڈیفالٹ کے طور پر انسٹالیشنز کو بلند کریں، کچھ خطرناک خصوصیات کو غیر مقفل کریں، وغیرہ", + "Package operation preferences": "پیکیج آپریشن کی ترجیحات", + "Enable {pm}": "{pm} کو فعال کریں", + "Not finding the file you are looking for? Make sure it has been added to path.": "جو فائل آپ تلاش کر رہے ہیں وہ نہیں مل رہی؟ یقینی بنائیں کہ اسے path میں شامل کیا گیا ہے۔", + "Select the executable to be used. The following list shows the executables found by UniGetUI": "استعمال کیے جانے والے ایگزیکیوبل کو منتخب کریں۔ درج ذیل فہرست UniGetUI کی طرف سے ملنے والے ایگزیکیوبلز دکھاتی ہے", + "For security reasons, changing the executable file is disabled by default": "سیکیورٹی کی وجوہات کی بنا پر، ایگزیکیوبل فائل تبدیل کرنا ڈیفالٹ طور پر غیر فعال ہے", + "Change this": "یہ تبدیل کریں", + "Copy path": "پاتھ کاپی کریں", + "Current executable file:": "موجودہ ایگزیکیوبل فائل:", + "Ignore packages from {pm} when showing a notification about updates": "اپ ڈیٹس کے بارے میں اطلاع دکھاتے وقت {pm} کے پیکجز کو نظر انداز کریں۔", + "Update security": "اپ ڈیٹ سیکیورٹی", + "Use global setting": "عالمی ترتیب استعمال کریں", + "Minimum age for updates": "اپ ڈیٹس کے لیے کم از کم مدت", + "e.g. 10": "مثلاً 10", + "Custom minimum age (days)": "حسب ضرورت کم از کم مدت (دن)", + "{pm} does not provide release dates for its packages, so this setting will have no effect": "{pm} اپنے پیکجز کے لیے ریلیز کی تاریخیں فراہم نہیں کرتا، اس لیے اس ترتیب کا کوئی اثر نہیں ہوگا", + "{pm} only provides release dates for some of its packages, so this setting will only apply to those packages": "{pm} اپنے کچھ پیکجز کے لیے ہی ریلیز کی تاریخیں فراہم کرتا ہے، لہٰذا یہ ترتیب صرف انہی پیکجز پر لاگو ہوگی", + "Override the global minimum update age for this package manager": "اس پیکیج مینیجر کے لیے اپ ڈیٹ کی عالمی کم از کم مدت کو اووررائیڈ کریں", + "View {0} logs": "{0} لاگز دیکھیں", + "If Python cannot be found or is not listing packages but is installed on the system, ": "اگر Python نہیں مل رہا یا پیکجز کی فہرست نہیں دکھا رہا لیکن سسٹم پر انسٹال ہے، ", + "Advanced options": "اعلیٰ ترین اختیارات", + "WinGet command-line tool": "WinGet کمانڈ لائن ٹول", + "Choose which command-line tool UniGetUI uses for WinGet operations when the COM API is not used": "منتخب کریں کہ جب COM API استعمال نہ ہو تو WinGet آپریشنز کے لیے UniGetUI کون سا کمانڈ لائن ٹول استعمال کرے", + "WinGet COM API": "WinGet COM API", + "Choose whether UniGetUI can use the WinGet COM API before falling back to the command-line tool": "منتخب کریں کہ آیا کمانڈ لائن ٹول پر واپس جانے سے پہلے UniGetUI WinGet COM API استعمال کر سکتا ہے", + "Reset WinGet": "WinGet کو دوبارہ ترتیب دیں۔", + "This may help if no packages are listed": "اس سے مدد مل سکتی ہے اگر کوئی پیکیج درج نہ ہو۔", + "Force install location parameter when updating packages with custom locations": "حسب ضرورت مقامات والے پیکیجز کو اپ ڈیٹ کرتے وقت انسٹال مقام کا پیرامیٹر لازمی کریں", + "Install Scoop": "سکوپ انسٹال کریں۔", + "Uninstall Scoop (and its packages)": "اسکوپ کو ان انسٹال کریں (اور اس کے پیکجز)", + "Run cleanup and clear cache": "صفائی کریں اور کیشے صاف کریں", + "Run": "چلائیں", + "Enable Scoop cleanup on launch": "لانچ پر اسکوپ کلین اپ کو فعال کریں۔", + "Default vcpkg triplet": "ڈیفالٹ vcpkg ٹرپلٹ", + "Change vcpkg root location": "vcpkg کی بنیادی جگہ تبدیل کریں", + "Reset vcpkg root location": "vcpkg روٹ مقام ری سیٹ کریں", + "Open vcpkg root location": "vcpkg روٹ مقام کھولیں", + "Language, theme and other miscellaneous preferences": "زبان، تھیم اور دیگر متفرق ترجیحات", + "Show notifications on different events": "مختلف واقعات پر نوٹیفکیشن دکھائیں", + "Change how UniGetUI checks and installs available updates for your packages": "یہ تبدیل کریں کہ UniGetUI آپ کے پیکیجز کے لئے دستیاب اپ ڈیٹس کو کیسے چیک اور انسٹال کرتا ہے", + "Automatically save a list of all your installed packages to easily restore them.": "تمام تنصیب شدہ پیکیجز کی فہرست خودکار طور پر محفوظ کریں تاکہ انہیں آسانی سے بحال کیا جا سکے۔", + "Enable and disable package managers, change default install options, etc.": "پیکیج مینیجرز کو فعال اور غیر فعال کریں، ڈیفالٹ انسٹالیشن اختیارات تبدیل کریں، وغیرہ", + "Internet connection settings": "انٹرنیٹ کنکشن کی ترتیبات", + "Proxy settings, etc.": "پروکسی کی ترتیبات، وغیرہ", + "Beta features and other options that shouldn't be touched": "بیٹا فیچرز اور دیگر اختیارات جنہیں نہیں چھیڑنا چاہئے", + "Reload sources": "ذرائع دوبارہ لوڈ کریں", + "Delete source": "ذریعہ حذف کریں", + "Known sources": "معلوم ذرائع", + "Update checking": "اپ ڈیٹ کی جانچ", + "Automatic updates": "خودکار اپ ڈیٹس", + "Check for package updates periodically": "پیکیج اپ ڈیٹس کو وقتاً فوقتاً چیک کریں", + "Check for updates every:": "ہر ایک کے لئے اپ ڈیٹس چیک کریں:", + "Install available updates automatically": "دستیاب اپ ڈیٹس خود بخود انسٹال کریں", + "Do not automatically install updates when the network connection is metered": "جب نیٹ ورک کنکشن میٹرڈ ہو تو اپ ڈیٹس خود بخود انسٹال نہ کریں", + "Do not automatically install updates when the device runs on battery": "جب ڈیوائس بیٹری پر چل رہی ہو تو اپ ڈیٹس خود بخود انسٹال نہ کریں", + "Do not automatically install updates when the battery saver is on": "جب بیٹری سیور آن ہو تو اپ ڈیٹس خود بخود انسٹال نہ کریں", + "Only show updates that are at least the specified number of days old": "صرف وہ اپ ڈیٹس دکھائیں جو کم از کم مقررہ تعداد کے دن پرانی ہوں", + "Warn me when the installer URL host changes between the installed version and the new version (WinGet only)": "جب انسٹالر URL ہوسٹ انسٹال شدہ ورژن اور نئے ورژن کے درمیان تبدیل ہو جائے تو مجھے خبردار کریں (صرف WinGet)", + "Change how UniGetUI handles install, update and uninstall operations.": "یہ تبدیل کریں کہ UniGetUI انسٹال، اپ ڈیٹ اور ان انسٹال آپریشنز کو کیسے ہینڈل کرتا ہے۔", + "Navigation": "نیویگیشن", + "Check for UniGetUI updates": "UniGetUI اپ ڈیٹس کی جانچ کریں", + "Quit UniGetUI": "UniGetUI بند کریں", + "Filters": "فلٹرز", + "Sources": "ذرائع", + "Search for packages to start": "شروع کرنے کے لئے پیکیجز تلاش کریں", + "Select all": "سب منتخب کریں", + "Clear selection": "انتخاب صاف کریں", + "Instant search": "فوری تلاش", + "Distinguish between uppercase and lowercase": "بڑے اور چھوٹے کے درمیان فرق کریں۔", + "Ignore special characters": "خاص کریکٹرز کو نظرانداز کریں", + "Search mode": "تلاش کا موڈ", + "Both": "دونوں", + "Exact match": "عین مطابق میچ", + "Show similar packages": "مشابہ پیکیجز دکھائیں", + "Loading": "لوڈ ہو رہا ہے", + "Package": "پیکیج", + "More options": "مزید اختیارات", + "Order by:": "ترتیب کے لحاظ سے:", + "Name": "نام", + "Id": "شناخت", + "Ascendant": "صعودی", + "Descendant": "نزولی", + "View modes": "ویو موڈز", + "Reload": "دوبارہ لوڈ", + "Closed": "بند", + "Ascending": "صعودی", + "Descending": "نزولی", + "{0}: {1}, {2}": "{0}: {1}، {2}", + "Order by": "ترتیب بلحاظ", + "No results were found matching the input criteria": "ان پٹ معیار کے مطابق کوئی نتائج نہیں ملے", + "No packages were found": "کوئی پیکجز نہیں ملے", + "Loading packages": "پیکیجز لوڈ ہو رہے ہیں", + "Skip integrity checks": "سالمیت کی جانچ چھوڑیں", + "Download selected installers": "منتخب انسٹالرز ڈاؤن لوڈ کریں", + "Install selection": "انتخاب انسٹال کریں", + "Install options": "انسٹالیشن کے اختیارات", + "Add selection to bundle": "انتخاب کو بنڈل میں شامل کریں", + "Download installer": "انسٹالر ڈاؤن لوڈ کریں", + "Uninstall selection": "منتخب کردہ کو ان انسٹال کریں", + "Uninstall options": "ان انسٹال کے اختیارات", + "Ignore selected packages": "منتخب کردہ پیکیجز کو نظرانداز کریں", + "Open install location": "انسٹال لوکیشن کھولیں۔", + "Reinstall package": "پیکیج دوبارہ انسٹال کریں", + "Uninstall package, then reinstall it": "پیکیج کو ان انسٹال کریں، پھر اسے دوبارہ انسٹال کریں۔", + "Ignore updates for this package": "اس پیکیج کے اپ ڈیٹس کو نظرانداز کریں", + "WinGet malfunction detected": "WinGet کی خرابی کا پتہ چلا", + "It looks like WinGet is not working properly. Do you want to attempt to repair WinGet?": "ایسا لگتا ہے کہ WinGet ٹھیک سے کام نہیں کر رہا ہے۔ کیا آپ WinGet کو ٹھیک کرنے کی کوشش کرنا چاہتے ہیں؟", + "Repair WinGet": "WinGet کی مرمت کریں۔", + "Updates will no longer be ignored for {0}": "{0} کے لیے اپ ڈیٹس کو مزید نظرانداز نہیں کیا جائے گا", + "Updates are now ignored for {0}": "{0} کے لیے اپ ڈیٹس اب نظرانداز ہیں", + "Do not ignore updates for this package anymore": "اس پیکج کے لیے اپ ڈیٹس کو مزید نظر انداز نہ کریں۔", + "Add packages or open an existing package bundle": "پیکیجز شامل کریں یا موجودہ پیکیج بنڈل کھولیں۔", + "Add packages to start": "شروع کرنے کے لیے پیکجز شامل کریں۔", + "The current bundle has no packages. Add some packages to get started": "موجودہ بنڈل میں کوئی پیکیج نہیں ہے۔ شروع کرنے کے لیے کچھ پیکجز شامل کریں۔", + "New": "نیا", + "Save as": "اس نام سے محفوظ کریں", + "Create .ps1 script": ".ps1 سکرپٹ بنائیں", + "Remove selection from bundle": "بُنڈل سے انتخاب ہٹائیں", + "Skip hash checks": "ہیش چیکس کو چھوڑ دیں۔", + "The package bundle is not valid": "پیکیج بنڈل درست نہیں ہے۔", + "The bundle you are trying to load appears to be invalid. Please check the file and try again.": "آپ جس بنڈل کو لوڈ کرنے کی کوشش کر رہے ہیں وہ غلط معلوم ہوتا ہے۔ براہ کرم فائل چیک کریں اور دوبارہ کوشش کریں۔", + "Package bundle": "پیکیج بنڈل", + "Could not create bundle": "بنڈل نہیں بنایا جا سکا", + "The package bundle could not be created due to an error.": "ایک خرابی کی وجہ سے پیکیج بنڈل نہیں بنایا جا سکا۔", + "Install script": "انسٹالیشن سکرپٹ", + "PowerShell script": "PowerShell اسکرپٹ", + "The installation script saved to {0}": "انسٹالیشن سکرپٹ {0} میں محفوظ کیا گیا", + "An error occurred": "ایک خرابی پیش آگئی", + "An error occurred while attempting to create an installation script:": "انسٹالیشن سکرپٹ بنانے کی کوشش میں خرابی پیش آئی:", + "Hooray! No updates were found.": "واہ! کوئی اپ ڈیٹس نہیں ملی۔", + "Uninstall selected packages": "منتخب پیکجز کو ان انسٹال کریں۔", + "Update selection": "منتخب کردہ کو اپ ڈیٹ کریں", + "Update options": "اپ ڈیٹ کے اختیارات", + "Uninstall package, then update it": "پیکیج کو ان انسٹال کریں، پھر اسے اپ ڈیٹ کریں۔", + "Uninstall package": "پیکیج کو ان انسٹال کریں۔", + "Skip this version": "اس ورژن کو چھوڑیں", + "Pause updates for": "اتنے وقت کے لیے اپ ڈیٹس موقوف کریں:", + "User | Local": "صارف | مقامی", + "Machine | Global": "مشین | عالمی", + "The default package manager for Debian/Ubuntu-based Linux distributions.
Contains: Debian/Ubuntu packages": "Debian/Ubuntu پر مبنی Linux ڈسٹری بیوشنز کا ڈیفالٹ پیکیج مینیجر۔
مشتمل ہے: Debian/Ubuntu پیکیجز", + "The Rust package manager.
Contains: Rust libraries and programs written in Rust": "رسٹ پیکیج مینیجر۔
پر مشتمل ہے: رسٹ لائبریریز اور پروگرامز جو زنگ میں لکھے گئے ہیں", + "The classical package manager for windows. You'll find everything there.
Contains: General Software": "ونڈوز کے لیے کلاسیکل پیکیج مینیجر۔ آپ کو وہاں سب کچھ مل جائے گا۔
پر مشتمل ہے: جنرل سافٹ ویئر", + "The default package manager for RHEL/Fedora-based Linux distributions.
Contains: RPM packages": "RHEL/Fedora پر مبنی Linux ڈسٹری بیوشنز کا ڈیفالٹ پیکیج مینیجر۔
مشتمل ہے: RPM پیکیجز", + "A repository full of tools and executables designed with Microsoft's .NET ecosystem in mind.
Contains: .NET related tools and scripts": "مائیکروسافٹ کے .NET ایکو سسٹم کے لئے تیار کردہ ٹولز اور ایگزیکیوشن فائلز سے بھرا ہوا ریپوزیٹری۔
اس میں شامل ہے: .NET سے متعلق ٹولز اور سکرپٹس", + "The universal Linux package manager for desktop applications.
Contains: Flatpak applications from configured remotes": "ڈیسک ٹاپ ایپلیکیشنز کے لیے عالمگیر Linux پیکیج مینیجر۔
شامل ہے: ترتیب دیے گئے ریموٹس سے Flatpak ایپلیکیشنز", + "NuPkg (zipped manifest)": "NuPkg (زپ شدہ منیفیسٹ)", + "The Missing Package Manager for macOS (or Linux).
Contains: Formulae, Casks": "macOS (یا Linux) کے لیے گمشدہ پیکیج مینیجر۔
شامل ہیں: Formulae, Casks", + "Node JS's package manager. Full of libraries and other utilities that orbit the javascript world
Contains: Node javascript libraries and other related utilities": "نوڈ جے ایس کا پیکیج مینیجر۔ لائبریریوں اور دیگر افادیت سے بھری ہوئی ہے جو جاوا اسکرپٹ کی دنیا کا چکر لگاتی ہے
پر مشتمل ہے: نوڈ جاوا اسکرپٹ لائبریریاں اور دیگر متعلقہ یوٹیلیٹیز", + "The default package manager for Arch Linux and its derivatives.
Contains: Arch Linux packages": "Arch Linux اور اس کے مشتقات کا ڈیفالٹ پیکیج مینیجر۔
مشتمل ہے: Arch Linux پیکیجز", + "Python's library manager. Full of python libraries and other python-related utilities
Contains: Python libraries and related utilities": "ازگر کی لائبریری مینیجر۔ ازگر کی لائبریریوں اور ازگر سے متعلق دیگر یوٹیلیٹیز سے بھرا ہوا
مشتمل ہے: پائیتھن لائبریریز اور متعلقہ یوٹیلیٹیز", + "PowerShell's package manager. Find libraries and scripts to expand PowerShell capabilities
Contains: Modules, Scripts, Cmdlets": "پاور شیل کا پیکیج مینیجر۔ PowerShell کی صلاحیتوں کو بڑھانے کے لیے لائبریریاں اور اسکرپٹ تلاش کریں
مشتمل ہیں: ماڈیولز، اسکرپٹس، Cmdlets", + "extracted": "نکالا گیا", + "Scoop package": "Scoop پیکیج", + "Great repository of unknown but useful utilities and other interesting packages.
Contains: Utilities, Command-line programs, General Software (extras bucket required)": "نامعلوم لیکن کارآمد یوٹیلیٹیز اور دیگر دلچسپ پیکجز کا زبردست ذخیرہ۔
مشتمل ہے: یوٹیلٹیز، کمانڈ لائن پروگرام، جنرل سافٹ ویئر (اضافی بالٹی درکار)", + "The universal Linux package manager by Canonical.
Contains: Snap packages from the Snapcraft store": "Canonical کی جانب سے عالمگیر Linux پیکیج مینیجر۔
مشتمل ہے: Snapcraft اسٹور سے Snap پیکیجز", + "library": "لائبریری", + "feature": "خصوصیت", + "A popular C/C++ library manager. Full of C/C++ libraries and other C/C++-related utilities
Contains: C/C++ libraries and related utilities": "ایک مشہور C/C++ لائبریری مینیجر۔ C/C++ لائبریریوں اور دیگر C/C++ سے متعلقہ یوٹیلیٹیز
پر مشتمل ہے: C/C++ لائبریریاں اور متعلقہ یوٹیلیٹیز", + "option": "اختیار", + "This package cannot be installed from an elevated context.": "اس پیکج کو بلند سیاق و سباق سے انسٹال نہیں کیا جا سکتا۔", + "Please run UniGetUI as a regular user and try again.": "براہ کرم UniGetUI کو باقاعدہ صارف کے طور پر چلائیں اور دوبارہ کوشش کریں۔", + "Please check the installation options for this package and try again": "براہ کرم اس پیکیج کے لیے انسٹالیشن کے اختیارات چیک کریں اور دوبارہ کوشش کریں۔", + "Microsoft's official package manager. Full of well-known and verified packages
Contains: General Software, Microsoft Store apps": "مائیکروسافٹ کا آفیشل پیکیج مینیجر۔ معروف اور تصدیق شدہ پیکجوں سے بھرا
مشتمل ہے: جنرل سافٹ ویئر، مائیکروسافٹ اسٹور ایپس", + "Local PC": "مقامی پی سی", + "Android Subsystem": "اینڈرائیڈ سب سسٹم", + "Operation on queue (position {0})...": "قطار میں آپریشن (پوزیشن {0}...)", + "Click here for more details": "مزید تفصیلات کے لیے یہاں کلک کریں۔", + "Operation canceled by user": "صارف کے ذریعے آپریشن منسوخ کر دیا گیا۔", + "Running PreOperation ({0}/{1})...": "PreOperation ({0}/{1}) چل رہا ہے...", + "PreOperation {0} out of {1} failed, and was tagged as necessary. Aborting...": "{1} میں سے PreOperation {0} ناکام ہو گیا اور اسے ضروری کے طور پر نشان زد کیا گیا تھا۔ کارروائی منسوخ کی جا رہی ہے...", + "PreOperation {0} out of {1} finished with result {2}": "{1} میں سے PreOperation {0} نتیجہ {2} کے ساتھ مکمل ہوا", + "Starting operation...": "آپریشن شروع ہو رہا ہے...", + "Running PostOperation ({0}/{1})...": "PostOperation ({0}/{1}) چل رہا ہے...", + "PostOperation {0} out of {1} failed, and was tagged as necessary. Aborting...": "{1} میں سے PostOperation {0} ناکام ہو گیا اور اسے ضروری کے طور پر نشان زد کیا گیا تھا۔ کارروائی منسوخ کی جا رہی ہے...", + "PostOperation {0} out of {1} finished with result {2}": "{1} میں سے PostOperation {0} نتیجہ {2} کے ساتھ مکمل ہوا", + "{package} installer download": "{package} انسٹالر ڈاؤن لوڈ", + "{0} installer is being downloaded": "{0} انسٹالر ڈاؤن لوڈ ہو رہا ہے۔", + "Download succeeded": "ڈاؤن لوڈ کامیاب ہو گیا۔", + "{package} installer was downloaded successfully": "{package} انسٹالر کامیابی سے ڈاؤن لوڈ ہو گیا۔", + "Download failed": "ڈاؤن لوڈ ناکام ہو گیا۔", + "{package} installer could not be downloaded": "{package} انسٹالر ڈاؤن لوڈ نہیں ہو سکا", + "{package} Installation": "{package} انسٹالیشن", + "{0} is being installed": "{0} انسٹال ہو رہا ہے۔", + "Installation succeeded": "انسٹالیشن کامیاب ہوگئی", + "{package} was installed successfully": "{package} کامیابی سے انسٹال ہو گیا", + "Installation failed": "انسٹالیشن ناکام ہوگئی", + "{package} could not be installed": "{package} انسٹال نہیں ہو سکا", + "{package} Update": "{package} اپ ڈیٹ", + "Update succeeded": "اپ ڈیٹ کامیاب ہو گیا", + "{package} was updated successfully": "{package} کامیابی سے اپ ڈیٹ ہو گیا", + "Update failed": "اپ ڈیٹ ناکام ہو گیا", + "{package} could not be updated": "{package} اپ ڈیٹ نہیں ہو سکا", + "{package} Uninstall": "{package} ان انسٹال", + "{0} is being uninstalled": "{0} کو اَن انسٹال کیا جا رہا ہے۔", + "Uninstall succeeded": "اَن انسٹال کرنا کامیاب ہو گیا۔", + "{package} was uninstalled successfully": "{package} کامیابی سے ان انسٹال ہو گیا", + "Uninstall failed": "اَن انسٹال ناکام ہو گیا۔", + "{package} could not be uninstalled": "{package} ان انسٹال نہیں ہو سکا", + "Adding source {source}": "ماخذ شامل کرنا {source}", + "Adding source {source} to {manager}": "ذریعہ {source} کو {manager} میں شامل کیا جا رہا ہے", + "Source added successfully": "ماخذ کامیابی کے ساتھ شامل ہو گیا۔", + "The source {source} was added to {manager} successfully": "ماخذ {source} کو کامیابی کے ساتھ {manager} میں شامل کر دیا گیا۔", + "Could not add source": "ماخذ شامل نہیں کیا جا سکا", + "Could not add source {source} to {manager}": "ماخذ {source} کو {manager} میں شامل نہیں کیا جا سکا", + "Removing source {source}": "ماخذ کو ہٹایا جا رہا ہے {source}", + "Removing source {source} from {manager}": "{source} کو {manager} سے ہٹایا جا رہا ہے", + "Source removed successfully": "ماخذ کامیابی کے ساتھ ہٹا دیا گیا۔", + "The source {source} was removed from {manager} successfully": "ماخذ {source} کو {manager} سے کامیابی کے ساتھ ہٹا دیا گیا تھا۔", + "Could not remove source": "ماخذ کو ہٹایا نہیں جا سکا", + "Could not remove source {source} from {manager}": "{manager} سے ماخذ {source} کو ہٹایا نہیں جا سکا", + "The package manager \"{0}\" was not found": "پیکیج مینیجر \"{0}\" نہیں ملا", + "The package manager \"{0}\" is disabled": "پیکیج مینیجر \"{0}\" غیر فعال ہے۔", + "There is an error with the configuration of the package manager \"{0}\"": "پیکیج مینیجر \"{0}\" کی ترتیب میں ایک خرابی ہے۔", + "The package \"{0}\" was not found on the package manager \"{1}\"": "پیکیج مینیجر \"{1}\" پر پیکیج \"{0}\" نہیں ملا", + "{0} is disabled": "{0} غیر فعال ہے", + "{0} weeks": "{0} ہفتے", + "1 month": "1 مہینہ", + "{0} months": "{0} مہینے", + "Something went wrong": "کچھ غلط ہو گیا", + "An interal error occurred. Please view the log for further details.": "ایک اندرونی خرابی پیش آگئی۔ مزید تفصیلات کے لیے براہ کرم لاگ دیکھیں۔", + "No applicable installer was found for the package {0}": "پیکیج {0} کے لیے کوئی قابل اطلاق انسٹالر نہیں ملا", + "Integrity checks will not be performed during this operation": "اس آپریشن کے دوران سالمیت کی جانچ نہیں کی جائے گی۔", + "This is not recommended.": "اس کی سفارش نہیں کی جاتی ہے۔", + "Run now": "اب دوڑو", + "Run next": "اگلا چلائیں۔", + "Run last": "آخری چلائیں۔", + "Show in explorer": "ایکسپلورر میں دکھائیں۔", + "Checked": "منتخب", + "Unchecked": "غیر منتخب", + "This package is already installed": "یہ پیکیج پہلے سے انسٹال ہے۔", + "This package can be upgraded to version {0}": "اس پیکیج کو ورژن {0} میں اپ گریڈ کیا جا سکتا ہے", + "Updates for this package are ignored": "اس پیکیج کے لئے اپ ڈیٹس کو نظر انداز کیا گیا ہے", + "This package is being processed": "اس پیکج پر کارروائی ہو رہی ہے۔", + "This package is not available": "یہ پیکیج دستیاب نہیں ہے۔", + "Select the source you want to add:": "جس ماخذ کو آپ شامل کرنا چاہتے ہیں اسے منتخب کریں:", + "Source name:": "ذریعہ کا نام:", + "Source URL:": "ذریعہ یو آر ایل:", + "An error occurred when adding the source: ": "ماخذ شامل کرتے وقت ایک خرابی پیش آئی: ", + "Package management made easy": "پیکیج مینجمنٹ آسان بنائی گئی", + "version {0}": "ورژن {0}", + "[RAN AS ADMINISTRATOR]": "[ایڈمنسٹریٹر کے طور پر چلایا گیا]", + "Portable mode": "پورٹ ایبل موڈ", + "DEBUG BUILD": "ڈیبگ بلڈ", + "Here you can change UniGetUI's behaviour regarding the following shortcuts. Checking a shortcut will make UniGetUI delete it if if gets created on a future upgrade. Unchecking it will keep the shortcut intact": "یہاں آپ درج ذیل شارٹ کٹس کے حوالے سے UniGetUI کے رویے کو تبدیل کر سکتے ہیں۔ شارٹ کٹ چیک کرنے سے UniGetUI اسے حذف کر دے گا اگر مستقبل میں اپ گریڈ بنایا جاتا ہے۔ اسے غیر چیک کرنے سے شارٹ کٹ برقرار رہے گا۔", + "Manual scan": "دستی اسکین", + "Existing shortcuts on your desktop will be scanned, and you will need to pick which ones to keep and which ones to remove.": "آپ کے ڈیسک ٹاپ پر موجودہ شارٹ کٹس کو اسکین کیا جائے گا، اور آپ کو یہ منتخب کرنے کی ضرورت ہوگی کہ کن کو رکھنا ہے اور کون سے ہٹانا ہے۔", + "Delete?": "حذف کریں؟", + "I understand": "مجھے سمجھ آگیا", + "Chocolatey setup changed": "Chocolatey کی ترتیب تبدیل ہو گئی", + "UniGetUI no longer includes its own private Chocolatey installation. A legacy UniGetUI-managed Chocolatey installation was detected for this user profile, but system Chocolatey was not found. Chocolatey will stay unavailable in UniGetUI until Chocolatey is installed on the system and UniGetUI is restarted. Applications previously installed through UniGetUI's bundled Chocolatey may still appear under other sources such as Local PC or WinGet.": "UniGetUI اب اپنی ذاتی Chocolatey انسٹالیشن شامل نہیں کرتا۔ اس صارف پروفائل کے لیے UniGetUI کے زیر انتظام ایک پرانی Chocolatey انسٹالیشن کا پتا چلا، لیکن سسٹم Chocolatey نہیں ملا۔ Chocolatey اس وقت تک UniGetUI میں دستیاب نہیں رہے گا جب تک کہ Chocolatey سسٹم پر انسٹال نہ ہو اور UniGetUI دوبارہ شروع نہ کیا جائے۔ UniGetUI کے بنڈل شدہ Chocolatey کے ذریعے پہلے انسٹال کی گئی ایپلیکیشنز اب بھی دوسرے ذرائع جیسے Local PC یا WinGet کے تحت ظاہر ہو سکتی ہیں۔", + "NOTE: This troubleshooter can be disabled from UniGetUI Settings, on the WinGet section": "نوٹ: اس ٹربل شوٹر کو WinGet سیکشن پر UniGetUI سیٹنگز سے غیر فعال کیا جا سکتا ہے۔", + "Restart": "دوبارہ شروع کریں۔", + "Are you sure you want to delete all shortcuts?": "کیا آپ واقعی تمام شارٹ کٹس کو حذف کرنا چاہتے ہیں؟", + "Any new shorcuts created during an install or an update operation will be deleted automatically, instead of showing a confirmation prompt the first time they are detected.": "کسی انسٹال یا اپ ڈیٹ آپریشن کے دوران بنائے گئے کوئی بھی نئے شارٹ کٹس کو پہلی بار پتہ چلنے پر تصدیقی اشارہ دکھانے کے بجائے خود بخود حذف کر دیا جائے گا۔", + "Any shorcuts created or modified outside of UniGetUI will be ignored. You will be able to add them via the {0} button.": "UniGetUI کے باہر تخلیق یا ترمیم شدہ کسی بھی شارٹ کو نظر انداز کر دیا جائے گا۔ آپ انہیں {0} بٹن کے ذریعے شامل کر سکیں گے۔", + "Are you really sure you want to enable this feature?": "کیا آپ واقعی اس خصوصیت کو فعال کرنا چاہتے ہیں؟", + "No new shortcuts were found during the scan.": "اسکین کے دوران کوئی نیا شارٹ کٹ نہیں ملا۔", + "How to add packages to a bundle": "پیکجوں کو بنڈل میں کیسے شامل کریں۔", + "In order to add packages to a bundle, you will need to: ": "پیکجوں کو بنڈل میں شامل کرنے کے لیے، آپ کو یہ کرنے کی ضرورت ہوگی: ", + "1. Navigate to the \"{0}\" or \"{1}\" page.": "1. \"{0}\" یا \"{1}\" صفحہ پر جائیں۔", + "2. Locate the package(s) you want to add to the bundle, and select their leftmost checkbox.": "2. وہ پیکج (پیکیجز) تلاش کریں جسے آپ بنڈل میں شامل کرنا چاہتے ہیں، اور ان کا سب سے بائیں چیک باکس منتخب کریں۔", + "3. When the packages you want to add to the bundle are selected, find and click the option \"{0}\" on the toolbar.": "3. جب پیکجز جو آپ بنڈل میں شامل کرنا چاہتے ہیں منتخب ہو جائیں، تو ٹول بار پر \"{0}\" آپشن تلاش کریں اور کلک کریں۔", + "4. Your packages will have been added to the bundle. You can continue adding packages, or export the bundle.": "4. آپ کے پیکجز کو بنڈل میں شامل کر دیا جائے گا۔ آپ پیکجز شامل کرنا جاری رکھ سکتے ہیں، یا بنڈل برآمد کر سکتے ہیں۔", + "Which backup do you want to open?": "آپ کون سا بیک اپ کھولنا چاہتے ہیں؟", + "Select the backup you want to open. Later, you will be able to review which packages you want to install.": "وہ بیک اپ منتخب کریں جو آپ کھولنا چاہتے ہیں۔ بعد میں، آپ یہ جائزہ لے سکیں گے کہ آپ کون سے پیکجز/پروگرام بحال کرنا چاہتے ہیں۔", + "There are ongoing operations. Quitting UniGetUI may cause them to fail. Do you want to continue?": "آپریشنز جاری ہیں۔ UniGetUI کو چھوڑنا ان کے ناکام ہونے کا سبب بن سکتا ہے۔ کیا آپ جاری رکھنا چاہتے ہیں؟", + "UniGetUI or some of its components are missing or corrupt.": "UniGetUI یا اس کے کچھ اجزاء غائب یا خراب ہیں۔", + "It is strongly recommended to reinstall UniGetUI to adress the situation.": "اس صورتحال کو درست کرنے کے لیے UniGetUI کو دوبارہ انسٹال کرنے کی سخت سفارش کی جاتی ہے۔", + "Refer to the UniGetUI Logs to get more details regarding the affected file(s)": "متاثرہ فائلوں کے بارے میں مزید تفصیلات حاصل کرنے کے لیے UniGetUI لاگز دیکھیں", + "Integrity checks can be disabled from the Experimental Settings": "سالمیت کی جانچ کو تجرباتی ترتیبات سے غیر فعال کیا جا سکتا ہے", + "Repair UniGetUI": "UniGetUI کی مرمت کریں", + "Live output": "براہ راست آؤٹ پٹ", + "This package bundle had some settings that are potentially dangerous, and may be ignored by default.": "اس پیکیج بنڈل میں کچھ ترتیبات تھیں جو ممکنہ طور پر خطرناک ہیں، اور انہیں ڈیفالٹ طور پر نظر انداز کیا جا سکتا ہے۔", + "Entries that show in YELLOW will be IGNORED.": "زرد رنگ میں دکھائی دینے والی اندراجات نظر انداز کی جائیں گی۔", + "Entries that show in RED will be IMPORTED.": "سرخ رنگ میں دکھائی دینے والی اندراجات درآمد کی جائیں گی۔", + "You can change this behavior on UniGetUI security settings.": "آپ اس رویے کو UniGetUI سیکیورٹی کی ترتیبات میں تبدیل کر سکتے ہیں۔", + "Open UniGetUI security settings": "UniGetUI سیکیورٹی کی ترتیبات کھولیں", + "Should you modify the security settings, you will need to open the bundle again for the changes to take effect.": "اگر آپ سیکیورٹی کی ترتیبات میں تبدیلی کرتے ہیں، تو تبدیلیوں کے اثر میں آنے کے لیے آپ کو بنڈل دوبارہ کھولنا ہوگا۔", + "Details of the report:": "رپورٹ کی تفصیلات:", + "Are you sure you want to create a new package bundle? ": "کیا آپ واقعی ایک نیا پیکج بنڈل بنانا چاہتے ہیں؟ ", + "Any unsaved changes will be lost": "کوئی بھی غیر محفوظ شدہ تبدیلیاں ضائع ہو جائیں گی۔", + "Warning!": "وارننگ!", + "For security reasons, custom command-line arguments are disabled by default. Go to UniGetUI security settings to change this. ": "سیکیورٹی کی وجوہات کی بنا پر، حسب ضرورت کمانڈ لائن دلائل ڈیفالٹ طور پر غیر فعال ہیں۔ یہ تبدیل کرنے کے لیے UniGetUI سیکیورٹی کی ترتیبات پر جائیں۔ ", + "Change default options": "ڈیفالٹ اختیارات تبدیل کریں", + "Ignore future updates for this package": "اس پیکیج کے مستقبل کے اپ ڈیٹس کو نظرانداز کریں", + "For security reasons, pre-operation and post-operation scripts are disabled by default. Go to UniGetUI security settings to change this. ": "سیکیورٹی کی وجوہات کی بنا پر، پری آپریشن اور پوسٹ آپریشن سکرپٹس ڈیفالٹ طور پر غیر فعال ہیں۔ یہ تبدیل کرنے کے لیے UniGetUI سیکیورٹی کی ترتیبات پر جائیں۔ ", + "You can define the commands that will be run before or after this package is installed, updated or uninstalled. They will be run on a command prompt, so CMD scripts will work here.": "آپ وہ کمانڈز متعین کر سکتے ہیں جو اس پیکیج کے انسٹال، اپ ڈیٹ یا ان انسٹال ہونے سے پہلے یا بعد میں چلائی جائیں گی۔ وہ کمانڈ پرامپٹ پر چلیں گی، اس لیے CMD سکرپٹس یہاں کام کریں گی۔", + "Change this and unlock": "یہ تبدیل کریں اور غیر مقفل کریں", + "{0} Install options are currently locked because {0} follows the default install options.": "{0} انسٹالیشن کے اختیارات فی الوقت مقفل ہیں کیونکہ {0} ڈیفالٹ انسٹالیشن کے اختیارات پر عمل کرتا ہے۔", + "Unset or unknown": "غیر سیٹ یا نامعلوم", + "This package has no screenshots or is missing the icon? Contrbute to UniGetUI by adding the missing icons and screenshots to our open, public database.": "اس پیکیج میں کوئی اسکرین شاٹس نہیں ہیں یا آئیکن غائب ہے؟ ہمارے کھلے، عوامی ڈیٹا بیس میں گمشدہ آئیکنز اور اسکرین شاٹس کو شامل کرکے UniGetUI سے تعاون کریں۔", + "Become a contributor": "شراکت دار بنیں", + "Update to {0} available": "{0} کے لئے اپ ڈیٹ دستیاب ہے", + "Reinstall": "دوبارہ انسٹال کریں۔", + "Installer not available": "انسٹالر دستیاب نہیں ہے۔", + "Version:": "ورژن:", + "UniGetUI Version {0}": "UniGetUI ورژن {0}", + "Performing backup, please wait...": "بیک اپ ہو رہا ہے، براہ کرم انتظار کریں...", + "An error occurred while logging in: ": "لاگ ان کرتے وقت خرابی پیش آئی: ", + "Fetching available backups...": "دستیاب بیک اپس حاصل کیے جا رہے ہیں...", + "Done!": "مکمل!", + "The cloud backup has been loaded successfully.": "کلاؤڈ بیک اپ کامیابی سے لوڈ ہو گیا ہے۔", + "An error occurred while loading a backup: ": "بیک اپ لوڈ کرتے وقت خرابی پیش آئی: ", + "Backing up packages to GitHub Gist...": "GitHub Gist میں پیکجز کا بیک اپ ہو رہا ہے...", + "Backup Successful": "بیک اپ کامیاب ہو گیا", + "The cloud backup completed successfully.": "کلاؤڈ بیک اپ کامیابی سے مکمل ہو گیا۔", + "Could not back up packages to GitHub Gist: ": "پیکجز کا GitHub Gist میں بیک اپ نہیں ہو سکا: ", + "It is not guaranteed that the provided credentials will be stored safely, so you may as well not use the credentials of your bank account": "یہ ضمانت نہیں دی جا سکتی کہ فراہم کردہ اسناد محفوظ طریقے سے رکھی جائیں گی، لہٰذا بہتر ہے کہ اپنے بینک اکاؤنٹ کی اسناد استعمال نہ کریں", + "Enable the automatic WinGet troubleshooter": "خودکار WinGet ٹربل شوٹر کو فعال کریں۔", + "Add updates that fail with a 'no applicable update found' to the ignored updates list": "نظر انداز کردہ اپ ڈیٹس کی فہرست میں 'کوئی قابل اطلاق اپ ڈیٹ نہیں ملا' کے ساتھ ناکام ہونے والی اپ ڈیٹس شامل کریں۔", + "Invalid selection": "غلط انتخاب", + "No package was selected": "کوئی پیکیج منتخب نہیں کیا گیا", + "More than 1 package was selected": "1 سے زیادہ پیکیج منتخب کیے گئے", + "List": "فہرست", + "Grid": "گرڈ", + "Icons": "آئیکنز", + "\"{0}\" is a local package and does not have available details": "\"{0}\" ایک مقامی پیکیج ہے اور اس میں دستیاب تفصیلات نہیں ہیں", + "\"{0}\" is a local package and is not compatible with this feature": "\"{0}\" ایک مقامی پیکیج ہے اور یہ اس خصوصیت کے ساتھ مطابقت نہیں رکھتا", + "Add packages to bundle": "بنڈل میں پیکجز شامل کریں۔", + "Preparing packages, please wait...": "پیکجز تیار ہو رہے ہیں، براہ کرم انتظار کریں...", + "Loading packages, please wait...": "پیکیجز لوڈ ہو رہے ہیں، براہ کرم انتظار کریں...", + "Saving packages, please wait...": "پیکیجز محفوظ کیے جا رہے ہیں، براہ کرم انتظار کریں...", + "The bundle was created successfully on {0}": "بنڈل کامیابی سے {0} پر بنایا گیا", + "User profile": "صارف پروفائل", + "Error": "خرابی", + "Log in failed: ": "لاگ ان ناکام ہو گیا: ", + "Log out failed: ": "لاگ آؤٹ ناکام ہو گیا: ", + "Package backup settings": "پیکیج بیک اپ کی ترتیبات", + "Package managers": "پیکیج مینیجرز", + "Manage UniGetUI autostart behaviour from the Settings app": "UniGetUI کے خودکار آغاز کے رویے کا نظم کریں", + "Choose how many operations shoulds be performed in parallel": "منتخب کریں کہ کتنی کارروائیاں بیک وقت انجام دی جائیں", + "Something went wrong while launching the updater.": "اپڈیٹر لانچ کرتے وقت کچھ غلط ہو گیا۔", + "Please try again later": "براہ کرم بعد میں دوبارہ کوشش کریں۔", + "Show the release notes after UniGetUI is updated": "UniGetUI اپ ڈیٹ ہونے کے بعد ریلیز نوٹس دکھائیں" +} diff --git a/src/Languages/lang_vi.json b/src/Languages/lang_vi.json new file mode 100644 index 0000000..d858b16 --- /dev/null +++ b/src/Languages/lang_vi.json @@ -0,0 +1,851 @@ +{ + "{0} of {1} operations completed": "Đã hoàn thành {0} trên {1} thao tác", + "{0} is now {1}": "{0} hiện tại là {1}", + "Enabled": "Đã bật", + "Disabled": "Đã tắt", + "Privacy": "Quyền riêng tư", + "Hide my username from the logs": "Ẩn tên người dùng của tôi khỏi nhật ký", + "Replaces your username with **** in the logs. Restart UniGetUI to also hide it from already-recorded entries.": "Thay thế tên người dùng của bạn bằng **** trong nhật ký. Khởi động lại UniGetUI để ẩn tên người dùng khỏi các mục đã được ghi lại trước đó.", + "Your last update attempt did not complete.": "Lần thử cập nhật gần nhất của bạn chưa hoàn tất.", + "UniGetUI could not confirm whether the update succeeded. Open the log to see what happened.": "UniGetUI không thể xác nhận bản cập nhật có thành công hay không. Mở nhật ký để xem điều gì đã xảy ra.", + "View log": "Xem nhật ký", + "The installer reported success but did not restart UniGetUI.": "Trình cài đặt báo thành công nhưng không khởi động lại UniGetUI.", + "The installer failed to initialize.": "Trình cài đặt không thể khởi tạo.", + "Setup was canceled before installation began.": "Quá trình thiết lập đã bị hủy trước khi quá trình cài đặt bắt đầu.", + "A fatal error occurred during the preparation phase.": "Đã xảy ra lỗi nghiêm trọng trong giai đoạn chuẩn bị.", + "A fatal error occurred during installation.": "Đã xảy ra lỗi nghiêm trọng trong quá trình cài đặt.", + "Installation was canceled while in progress.": "Quá trình cài đặt đã bị hủy khi đang diễn ra.", + "The installer was terminated by another process.": "Trình cài đặt đã bị một tiến trình khác chấm dứt.", + "The preparation phase determined the installation cannot proceed.": "Giai đoạn chuẩn bị xác định quá trình cài đặt không thể tiếp tục.", + "The installer could not start. UniGetUI may already be running, or you do not have permission to install.": "Trình cài đặt không thể khởi động. UniGetUI có thể đang chạy, hoặc bạn không có quyền cài đặt.", + "Unexpected installer error.": "Lỗi trình cài đặt không mong muốn.", + "We are checking for updates.": "Chúng tôi đang kiểm tra các bản cập nhật.", + "Please wait": "Vui lòng chờ", + "Great! You are on the latest version.": "Tuyệt vời! Bạn đang sử dụng phiên bản mới nhất.", + "There are no new UniGetUI versions to be installed": "Không có phiên bản UniGetUI mới nào để cài đặt", + "UniGetUI version {0} is being downloaded.": "Đang tải xuống UniGetUI phiên bản {0}", + "This may take a minute or two": "Việc này có thể mất một hoặc hai phút", + "The installer authenticity could not be verified.": "Không thể xác minh tính xác thực của trình cài đặt.", + "The update process has been aborted.": "Quá trình cập nhật đã bị hủy bỏ.", + "Auto-update is not yet available on this platform.": "Tự động cập nhật chưa khả dụng trên nền tảng này.", + "Please update UniGetUI manually.": "Vui lòng cập nhật UniGetUI thủ công.", + "An error occurred when checking for updates: ": "Có lỗi khi kiểm tra cập nhật", + "The updater could not be launched.": "Không thể khởi chạy trình cập nhật.", + "The operating system did not start the installer process.": "Hệ điều hành đã không khởi chạy tiến trình trình cài đặt.", + "UniGetUI is being updated...": "UniGetUI đang được cập nhật...", + "Update installed.": "Bản cập nhật đã được cài đặt.", + "UniGetUI was updated successfully, but this running copy was not replaced. This usually means you are running a development build. Close this copy and start the newly-installed version to finish.": "UniGetUI đã được cập nhật thành công, nhưng bản sao đang chạy này chưa được thay thế. Điều này thường có nghĩa là bạn đang chạy bản dựng phát triển. Hãy đóng bản sao này và khởi động phiên bản vừa cài đặt để hoàn tất.", + "The update could not be applied.": "Không thể áp dụng bản cập nhật.", + "Installer exit code {0}: {1}": "Mã thoát trình cài đặt {0}: {1}", + "Update cancelled.": "Cập nhật đã bị hủy.", + "Authentication was cancelled.": "Xác thực đã bị hủy.", + "Installer exit code {0}": "Mã thoát trình cài đặt {0}", + "Operation in progress": "Hoạt động đang tiến hành", + "Please wait...": "Vui lòng chờ.....", + "Success!": "Thành công!", + "Failed": "Thất bại", + "An error occurred while processing this package": "Có lỗi xảy ra khi xử lý gói này", + "Installer": "Trình cài đặt", + "Executable": "Tệp thực thi", + "MSI": "MSI", + "Compressed file": "Tệp nén", + "MSIX": "MSIX", + "WinGet was repaired successfully": "WinGet đã được sửa chữa thành công", + "It is recommended to restart UniGetUI after WinGet has been repaired": "Nên khởi động lại UniGetUI sau khi WinGet đã được sửa chữa", + "WinGet could not be repaired": "WinGet không thể sửa chữa được", + "An unexpected issue occurred while attempting to repair WinGet. Please try again later": "Đã xảy ra sự cố không mong muốn khi cố gắng sửa chữa WinGet. Vui lòng thử lại sau", + "Log in to enable cloud backup": "Đăng nhập để bật tính năng sao lưu lên đám mây", + "Backup Failed": "Sao lưu thất bại", + "Downloading backup...": "Đang tải bản sao lưu...", + "An update was found!": "Một bản cập nhật đã được tìm thấy!", + "{0} can be updated to version {1}": "{0} có thể được cập nhật lên phiên bản {1}", + "Updates found!": "Đã tìm thấy bản cập nhật!", + "{0} packages can be updated": "{0} gói có thể cập nhật", + "{0} is being updated to version {1}": "{0} đang được cập nhật lên phiên bản {1}", + "{0} packages are being updated": "{0} gói tài nguyên đang được cập nhật", + "You have currently version {0} installed": "Hiện tại bạn đã cài đặt phiên bản {0}", + "Desktop shortcut created": "Lối tắt trên màn hình đã được tạo", + "UniGetUI has detected a new desktop shortcut that can be deleted automatically.": "UniGetUI đã phát hiện một phím tắt trên màn hình mới có thể được xóa tự động.", + "{0} desktop shortcuts created": "{0} lối tắt màn hình đã tạo", + "UniGetUI has detected {0} new desktop shortcuts that can be deleted automatically.": "UniGetUI đã phát hiện {0} lối tắt trên màn hình mới có thể được xóa tự động.", + "Attention required": "Cần chú ý", + "Restart required": "Yêu cầu khởi động lại", + "1 update is available": "Có 1 bản cập nhật có sẵn", + "{0} updates are available": "Có {0} bản cập nhật", + "Everything is up to date": "Mọi thứ đều được cập nhật", + "Discover Packages": "Khám phá các gói", + "Available Updates": "Cập nhật có sẵn", + "Installed Packages": "Gói đã cài đặt", + "UniGetUI Version {0} by Devolutions": "UniGetUI phiên bản {0} của Devolutions", + "Show UniGetUI": "Hiển thị UniGetUI", + "Quit": "Thoát", + "Are you sure?": "Bạn có chắc không?", + "Do you really want to uninstall {0}?": "Bạn thực sự muốn gỡ bỏ {0} chứ?", + "Do you really want to uninstall the following {0} packages?": "Bạn có thực sự muốn gỡ cài đặt các gói {0} sau không?", + "No": "Không", + "Yes": "Có", + "Partial": "Một phần", + "View on UniGetUI": "Xem trên UniGetUI", + "Update": "Cập nhật", + "Open UniGetUI": "Mở UniGetUI", + "Update all": "Cập nhật toàn bộ", + "Update now": "Cập nhật bây giờ", + "Installer host changed since the installed version.\n": "Máy chủ trình cài đặt đã thay đổi so với phiên bản đã cài đặt.\n", + "This package is on the queue": "Gói này đang trong hàng đợi", + "installing": "đang cài", + "updating": "đang cập nhật", + "uninstalling": "đang gỡ", + "installed": "Đã cài đặt", + "Retry": "Thử lại", + "Install": "Cài đặt", + "Uninstall": "Gỡ cài đặt", + "Open": "Mở", + "Operation profile:": "Hồ sơ thao tác:", + "Follow the default options when installing, upgrading or uninstalling this package": "Làm theo tùy chọn mặc định khi cài đặt, nâng cấp hoặc gỡ bỏ gói này", + "The following settings will be applied each time this package is installed, updated or removed.": "Các cài đặt sau sẽ được áp dụng mỗi khi gói này được cài đặt, cập nhật hoặc gỡ bỏ.", + "Version to install:": "Phiên bản để cài đặt:", + "Architecture to install:": "Kiến trúc cài đặt: ", + "Installation scope:": "Phạm vi cài đặt:", + "Install location:": "Vị trí cài đặt:", + "Select": "Chọn", + "Reset": "Đặt lại", + "Custom install arguments:": "Tham số cài đặt tùy chỉnh:", + "Custom update arguments:": "Tham số cập nhật tùy chỉnh:", + "Custom uninstall arguments:": "Tham số gỡ cài đặt tùy chỉnh:", + "Pre-install command:": "Lệnh trước khi cài đặt:", + "Post-install command:": "Lệnh sau khi cài đặt:", + "Abort install if pre-install command fails": "Hủy cài đặt nếu lệnh tiền cài đặt thất bại", + "Pre-update command:": "Lệnh trước khi cập nhật:", + "Post-update command:": "Lệnh sau khi cập nhật:", + "Abort update if pre-update command fails": "Hủy cập nhật nếu lệnh tiền cập nhật thất bại", + "Pre-uninstall command:": "Lệnh trước khi gỡ cài đặt:", + "Post-uninstall command:": "Lệnh sau khi gỡ cài đặt:", + "Abort uninstall if pre-uninstall command fails": "Hủy gỡ cài đặt nếu lệnh tiền gỡ cài đặt thất bại", + "Command-line to run:": "Dòng lệnh để chạy:", + "Save and close": "Lưu và đóng", + "General": "Chung", + "Architecture & Location": "Kiến trúc & vị trí", + "Command-line": "Dòng lệnh", + "Close apps": "Đóng ứng dụng", + "Pre/Post install": "Trước/Sau khi cài đặt", + "Select the processes that should be closed before this package is installed, updated or uninstalled.": "Chọn các tiến trình cần đóng trước khi gói phần mềm này được cài đặt, cập nhật hoặc gỡ bỏ.", + "Write here the process names here, separated by commas (,)": "Viết tên các tiến trình vào đây, cách nhau bằng dấu phẩy (,)", + "Try to kill the processes that refuse to close when requested to": "Cố gắng kết thúc các tiến trình không chịu đóng khi được yêu cầu", + "Run as admin": "Chạy với quyền quản trị", + "Interactive installation": "Cài đặt tương tác", + "Skip hash check": "Bỏ qua kiểm tra hash", + "Uninstall previous versions when updated": "Gỡ bỏ các phiên bản trước đó khi cập nhật", + "Skip minor updates for this package": "Bỏ qua các cập nhật nhỏ cho gói này", + "Automatically update this package": "Tự động cập nhật gói này", + "{0} installation options": "Tùy chọn cài đặt {0}", + "Latest": "Mới nhất", + "PreRelease": "Trước khi phát hành", + "Default": "Mặc định", + "Manage ignored updates": "Quản lý các cập nhật bị bỏ qua", + "The packages listed here won't be taken in account when checking for updates. Double-click them or click the button on their right to stop ignoring their updates.": "Các gói được liệt kê ở đây sẽ không được tính đến khi kiểm tra các bản cập nhật. Nhấp đúp vào chúng hoặc nhấp vào nút ở bên phải của chúng để ngừng bỏ qua các cập nhật của chúng.", + "Reset list": "Đặt lại danh sách", + "Do you really want to reset the ignored updates list? This action cannot be reverted": "Bạn có thực sự muốn đặt lại danh sách các bản cập nhật bị bỏ qua không? Hành động này không thể hoàn tác", + "No ignored updates": "Không có bản cập nhật bị bỏ qua", + "Package Name": "Tên gói", + "Package ID": "ID gói", + "Ignored version": "Phiên bản bị bỏ qua", + "New version": "Phiên bản mới", + "Source": "Nguồn", + "All versions": "Tất cả phiên bản", + "Unknown": "Không biết", + "Up to date": "Đã cập nhật", + "Package {name} from {manager}": "Gói {name} từ {manager}", + "Remove {0} from ignored updates": "Xóa {0} khỏi danh sách cập nhật bị bỏ qua", + "Cancel": "Hủy", + "Administrator privileges": "Quyền quản trị viên", + "This operation is running with administrator privileges.": "Hoạt động này đang chạy với quyền quản trị.", + "Interactive operation": "Hoạt động tương tác", + "This operation is running interactively.": "Hoạt động này đang chạy tương tác.", + "You will likely need to interact with the installer.": "Bạn có khả năng sẽ cần tương tác với trình cài đặt.", + "Integrity checks skipped": "Bỏ qua kiểm tra tính hoàn hảo", + "Integrity checks will not be performed during this operation.": "Các kiểm tra tính toàn vẹn sẽ không được thực hiện trong thao tác này.", + "Proceed at your own risk.": "Tiến hành tự chịu rủi ro", + "Close": "Đóng", + "Loading...": "Đang tải....", + "Installer SHA256": "Trình cài đặt SHA256", + "Homepage": "Trang chủ", + "Author": "Tác giả", + "Publisher": "Người xuất bản", + "License": "Giấy phép", + "Manifest": "Tệp cấu hình", + "Installer Type": "Loại cài đặt", + "Size": "Kích thước", + "Installer URL": "URL trình cài đặt", + "Last updated:": "Lần cuối cập nhật: ", + "Release notes URL": "URL ghi chú phát hành", + "Package details": "Chi tiết gói", + "Dependencies:": "Các thành phần phụ thuộc:", + "Release notes": "Ghi chú phát hành", + "Screenshots": "Ảnh chụp màn hình", + "This package has no screenshots or is missing the icon? Contribute to UniGetUI by adding the missing icons and screenshots to our open, public database.": "Gói này không có ảnh chụp màn hình hoặc bị thiếu biểu tượng? Hãy đóng góp cho UniGetUI bằng cách thêm các biểu tượng và ảnh chụp màn hình còn thiếu vào cơ sở dữ liệu mở, công khai của chúng tôi.", + "Version": "Phiên bản", + "Install as administrator": "Cài đặt với quyền quản trị viên", + "Update to version {0}": "Cập nhật lên phiên bản {0}", + "Installed Version": "Phiên bản đã cài", + "Update as administrator": "Cập nhật với tư cách quản trị viên", + "Interactive update": "Cập nhật tương tác", + "Uninstall as administrator": "Gỡ cài đặt với tư cách quản trị viên", + "Interactive uninstall": "Gỡ cài đặt tương tác", + "Uninstall and remove data": "Gỡ cài đặt và xóa dữ liệu", + "Not available": "Không khả dụng", + "Installer SHA512": "Trình cài đặt SHA512", + "Unknown size": "Kích thước không xác định", + "No dependencies specified": "Không có thành phần phụ thuộc nào được chỉ định", + "mandatory": "bắt buộc", + "optional": "tùy chọn", + "UniGetUI {0} is ready to be installed.": "UniGetUI phiên bản {0} đã sẵn sàng để cài đặt", + "The update process will start after closing UniGetUI": "Quá trình cập nhật sẽ bắt đầu sau khi đóng UniGetUI.", + "UniGetUI has been ran as administrator, which is not recommended. When running UniGetUI as administrator, EVERY operation launched from UniGetUI will have administrator privileges. You can still use the program, but we highly recommend not running UniGetUI with administrator privileges.": "UniGetUI đang được chạy với quyền quản trị viên, điều này không được khuyến nghị. Khi chạy UniGetUI với quyền quản trị viên, MỌI thao tác được khởi chạy từ UniGetUI sẽ có quyền quản trị viên. Bạn vẫn có thể dùng chương trình, nhưng chúng tôi đặc biệt khuyến nghị không chạy UniGetUI với quyền quản trị viên.", + "Share anonymous usage data": "Chia sẻ dữ liệu sử dụng ẩn danh", + "UniGetUI collects anonymous usage data in order to improve the user experience.": "UniGetUI thu thập dữ liệu sử dụng ẩn danh để cải thiện trải nghiệm người dùng.", + "Accept": "Chấp nhận", + "Software Updates": "Cập nhật phần mềm", + "Package Bundles": "Nhóm gói", + "Settings": "Cài đặt", + "Package Managers": "Các trình quản lý gói", + "UniGetUI Log": "Nhật ký UniGetUI", + "Package Manager logs": "Nhật ký Trình quản lý gói", + "Operation history": "Lịch sử hoạt động", + "Help": "Trợ giúp", + "UniGetUI": "UniGetUI", + "You have installed UniGetUI Version {0}": "Bạn đã cài đặt Phiên bản UniGetUI {0}", + "Disclaimer": "Tuyên bố miễn trừ trách nhiệm", + "UniGetUI is developed by Devolutions and is not affiliated with any of the compatible package managers.": "UniGetUI được phát triển bởi Devolutions và không liên kết với bất kỳ trình quản lý gói tương thích nào.", + "UniGetUI wouldn't have been possible without the help of the contributors. Thank you all 🥳": "UniGetUI sẽ không thể thực hiện được nếu không có sự giúp đỡ của những người đóng góp. Cảm ơn tất cả các bạn 🥳", + "UniGetUI uses the following libraries. Without them, UniGetUI wouldn't have been possible.": "UniGetUI sử dụng các thư viện sau. Nếu không có họ, UniGetUI sẽ không thể tồn tại được.", + "{0} homepage": "Trang chủ {0}", + "UniGetUI has been translated to more than 40 languages thanks to the volunteer translators. Thank you 🤝": "UniGetUI đã được dịch sang hơn 40 ngôn ngữ nhờ các dịch giả tình nguyện. Cảm ơn bạn 🤝", + "Verbose": "Chi tiết", + "1 - Errors": "1 - Lỗi", + "2 - Warnings": "2 - Cảnh báo", + "3 - Information (less)": "3 - Thông tin (ít hơn)", + "4 - Information (more)": "4 - Thông tin (thêm)", + "5 - information (debug)": "5 - Thông tin (gỡ lỗi)", + "Warning": "Cảnh báo", + "The following settings may pose a security risk, hence they are disabled by default.": "Các thiết lập sau có thể gây rủi ro bảo mật, do đó chúng bị vô hiệu hóa theo mặc định.", + "Enable the settings below if and only if you fully understand what they do, and the implications they may have.": "Chỉ bật các thiết lập bên dưới NẾU VÀ CHỈ NẾU bạn thực sự hiểu rõ chức năng của chúng, cũng như các hệ quả và rủi ro tiềm ẩn.", + "The settings will list, in their descriptions, the potential security issues they may have.": "Các thiết lập sẽ liệt kê trong phần mô tả của chúng các vấn đề bảo mật tiềm ẩn.", + "The backup will include the complete list of the installed packages and their installation options. Ignored updates and skipped versions will also be saved.": "Bản sao lưu sẽ bao gồm danh sách đầy đủ các gói đã cài đặt và các tùy chọn cài đặt của chúng. Các bản cập nhật bị bỏ qua và các phiên bản bị bỏ qua cũng sẽ được lưu lại.", + "The backup will NOT include any binary file nor any program's saved data.": "Bản sao lưu sẽ KHÔNG bao gồm bất kỳ tệp nhị phân nào hoặc bất kỳ dữ liệu đã lưu của chương trình nào.", + "The size of the backup is estimated to be less than 1MB.": "Kích thước của bản sao lưu được ước tính nhỏ hơn 1MB.", + "The backup will be performed after login.": "Bản sao lưu sẽ được thực hiện sau khi đăng nhập.", + "{pcName} installed packages": "Gói {pcName} đã cài đặt", + "Current status: Not logged in": "Trạng thái hiện tại: Chưa đăng nhập", + "You are logged in as {0} (@{1})": "Bạn đang đăng nhập với tài khoản {0} (@{1})", + "Nice! Backups will be uploaded to a private gist on your account": "Tuyệt! Các bản sao lưu sẽ được tải lên một Gist riêng tư trong tài khoản của bạn", + "Select backup": "Chọn bản sao lưu", + "Settings imported from {0}": "Đã nhập cài đặt từ {0}", + "UniGetUI Settings": "Cài đặt UniGetUI", + "Settings exported to {0}": "Đã xuất cài đặt đến {0}", + "UniGetUI settings were reset": "Cài đặt UniGetUI đã được đặt lại", + "Allow pre-release versions": "Cho phép phiên bản phát hành trước", + "Apply": "Áp dụng", + "For security reasons, custom command-line arguments are disabled by default. Go to UniGetUI security settings to change this.": "Vì lý do bảo mật, các đối số dòng lệnh tùy chỉnh bị tắt theo mặc định. Hãy vào cài đặt bảo mật của UniGetUI để thay đổi điều này.", + "Go to UniGetUI security settings": "Đi tới cài đặt bảo mật của UniGetUI.", + "The following options will be applied by default each time a {0} package is installed, upgraded or uninstalled.": "Các tùy chọn sau sẽ được áp dụng theo mặc định mỗi khi một gói {0} được cài đặt, nâng cấp hoặc gỡ bỏ.", + "Package's default": "Gói phần mềm mặc định", + "Install location can't be changed for {0} packages": "Không thể thay đổi vị trí cài đặt cho {0} gói.", + "The local icon cache currently takes {0} MB": "Bộ nhớ đệm biểu tượng cục bộ hiện tại chiếm {0} MB", + "Username": "Tên người dùng", + "Password": "Mật khẩu", + "Credentials": "Thông tin xác thực", + "It is not guaranteed that the provided credentials will be stored safely": "Không thể bảo đảm rằng thông tin xác thực được cung cấp sẽ được lưu trữ an toàn", + "Partially": "Một phần", + "Package manager": "Trình quản lý gói", + "Compatible with proxy": "Tương thích với proxy", + "Compatible with authentication": "Tương thích với xác thực", + "Proxy compatibility table": "Bảng tương thích proxy", + "{0} settings": "{0} cài đặt", + "{0} status": "Trạng thái {0}", + "Default installation options for {0} packages": "Tùy chọn cài đặt mặc định cho {0} gói", + "Expand version": "Phiên bản mở rộng", + "The executable file for {0} was not found": "Tệp thực thi cho {0} không được tìm thấy.", + "{pm} is disabled": "{pm} đã bị vô hiệu hóa", + "Enable it to install packages from {pm}.": "Kích hoạt nó để cài đặt các gói từ {pm}.", + "{pm} is enabled and ready to go": "{pm} đã được bật và sẵn sàng hoạt động", + "{pm} version:": "{pm} phiên bản:", + "{pm} was not found!": "{pm} không tìm thấy!", + "You may need to install {pm} in order to use it with UniGetUI.": "Bạn có thể cần cài đặt {pm} để sử dụng nó với UniGetUI.", + "Scoop Installer - UniGetUI": "Trình cài đặt Scoop - UniGetUI", + "Scoop Uninstaller - UniGetUI": "Trình gỡ cài đặt Scoop - UniGetUI", + "Clearing Scoop cache - UniGetUI": "Dọn dẹp bộ nhớ đệm Scoop - WingetU", + "Restart UniGetUI to fully apply changes": "Khởi động lại UniGetUI để áp dụng đầy đủ các thay đổi", + "Restart UniGetUI": "Khởi động lại UniGetUI", + "Manage {0} sources": "Quản lý {0} nguồn", + "Add source": "Thêm nguồn", + "Add": "Thêm", + "Source name": "Tên nguồn", + "Source URL": "URL nguồn", + "Other": "Khác", + "No minimum age": "Không có thời gian tối thiểu", + "1 day": "1 ngày", + "{0} days": "{0} ngày", + "Custom...": "Tùy chỉnh...", + "{0} minutes": "{0} phút", + "1 hour": "1 giờ", + "{0} hours": "{0} giờ", + "1 week": "1 tuần", + "Supports release dates": "Hỗ trợ ngày phát hành", + "Release date support per package manager": "Mức hỗ trợ ngày phát hành theo từng trình quản lý gói", + "Search for packages": "Tìm kiếm gói", + "Local": "Cục bộ", + "OK": "OK ", + "Last checked: {0}": "Lần kiểm tra cuối: {0}", + "{0} packages were found, {1} of which match the specified filters.": "Đã tìm thấy {0} gói, {1} trong số đó phù hợp với các bộ lọc được chỉ định.", + "{0} selected": "Đã chọn {0} mục", + "(Last checked: {0})": "(Lần kiểm tra cuối: {0})", + "All packages selected": "Đã chọn tất cả các gói", + "Package selection cleared": "Đã bỏ chọn tất cả các gói", + "{0}: {1}": "{0}: {1}", + "More info": "Thêm thông tin", + "GitHub account": "Tài khoản GitHub", + "Log in with GitHub to enable cloud package backup.": "Đăng nhập bằng GitHub để bật tính năng sao lưu gói lên đám mây.", + "More details": "Chi tiết hơn", + "Log in": "Đăng nhập", + "If you have cloud backup enabled, it will be saved as a GitHub Gist on this account": "Nếu bạn đã bật tính năng sao lưu đám mây, bản sao lưu sẽ được lưu dưới dạng GitHub Gist trong tài khoản này.", + "Log out": "Đăng xuất", + "About UniGetUI": "Giới thiệu về UniGetUI", + "About": "Giới thiệu", + "Third-party licenses": "Giấy phép bên thứ ba", + "Contributors": "Người đóng góp", + "Translators": "Người dịch", + "Bundle security report": "Tập hợp báo cáo bảo mật", + "The bundle contained restricted content": "Gói chứa nội dung bị hạn chế", + "UniGetUI – Crash Report": "UniGetUI – Báo cáo lỗi", + "UniGetUI has crashed": "UniGetUI đã bị lỗi", + "Help us fix this by sending a crash report to Devolutions. All fields below are optional.": "Giúp chúng tôi khắc phục sự cố bằng cách gửi báo cáo lỗi đến Devolutions. Tất cả các trường bên dưới là tùy chọn.", + "Email (optional)": "Email (tùy chọn)", + "your@email.com": "your@email.com", + "Additional details (optional)": "Chi tiết bổ sung (tùy chọn)", + "Describe what you were doing when the crash occurred…": "Mô tả những gì bạn đang làm khi sự cố xảy ra…", + "Crash report": "Báo cáo lỗi", + "Don't Send": "Không gửi", + "Send Report": "Gửi báo cáo", + "Sending…": "Đang gửi…", + "Unsaved changes": "Các thay đổi chưa lưu", + "You have unsaved changes in the current bundle. Do you want to discard them?": "Bạn có các thay đổi chưa lưu trong gói hiện tại. Bạn có muốn bỏ chúng không?", + "Discard changes": "Bỏ thay đổi", + "Integrity violation": "Vi phạm tính toàn vẹn", + "UniGetUI or some of its components are missing or corrupt. It is strongly recommended to reinstall UniGetUI to adress the situation.": "UniGetUI hoặc một số thành phần của UniGetUI bị thiếu hoặc hỏng. Bạn nên cài đặt lại UniGetUI để khắc phục tình trạng này.", + "• Refer to the UniGetUI Logs to get more details regarding the affected file(s)": "• Tham khảo nhật ký UniGetUI để biết thêm chi tiết về (các) tệp bị ảnh hưởng", + "• Integrity checks can be disabled from the Experimental Settings": "• Kiểm tra tính toàn vẹn có thể được vô hiệu hóa từ phần Cài đặt Thử nghiệm", + "Manage shortcuts": "Quản lý lối tắt", + "UniGetUI has detected the following desktop shortcuts which can be removed automatically on future upgrades": "UniGetUI đã phát hiện các phím tắt trên màn hình sau đây có thể được xóa tự động trong các bản nâng cấp tương lai.", + "Do you really want to reset this list? This action cannot be reverted.": "Bạn có thật sự muốn đặt lại danh sách này không? Hành động này không thể hoàn tác.", + "Desktop shortcuts list": "Danh sách lối tắt trên màn hình", + "Open in explorer": "Mở trong Explorer", + "Remove from list": "Xóa khỏi danh sách", + "When new shortcuts are detected, delete them automatically instead of showing this dialog.": "Khi phát hiện các phím tắt mới, hãy tự động xóa chúng thay vì hiển thị hộp thoại này.", + "Not right now": "Không phải bây giờ", + "Missing dependency": "Thiếu phần phụ thuộc", + "UniGetUI requires {0} to operate, but it was not found on your system.": "UniGetUI yêu cầu {0} hoạt động nhưng không tìm thấy nó trên hệ thống của bạn.", + "Click on Install to begin the installation process. If you skip the installation, UniGetUI may not work as expected.": "Bấm vào Cài đặt để bắt đầu quá trình cài đặt. Nếu bạn bỏ qua quá trình cài đặt, UniGetUI có thể không hoạt động như mong đợi.", + "Alternatively, you can also install {0} by running the following command in a Windows PowerShell prompt:": "Ngoài ra, bạn cũng có thể cài đặt {0} bằng cách chạy lệnh sau trong lời nhắc Windows PowerShell:", + "Install {0}": "Cài đặt {0}", + "Do not show this dialog again for {0}": "Không hiển thị lại hộp thoại này cho {0}", + "Please wait while {0} is being installed. A black window may show up. Please wait until it closes.": "Vui lòng đợi trong khi {0} đang được cài đặt. Một cửa sổ màu đen có thể xuất hiện. Vui lòng đợi cho đến khi nó đóng lại.", + "{0} has been installed successfully.": "{0} đã được cài đặt thành công.", + "Please click on \"Continue\" to continue": "Vui lòng click vào \"Tiếp tục\" để tiếp tục", + "Continue": "Tiếp tục", + "{0} has been installed successfully. It is recommended to restart UniGetUI to finish the installation": "{0} đã được cài đặt thành công. Nên khởi động lại UniGetUI để hoàn tất quá trình cài đặt", + "Restart later": "Khởi động lại sau ", + "An error occurred:": "Đã xảy ra lỗi:", + "Please see the Command-line Output or refer to the Operation History for further information about the issue.": "Vui lòng xem Đầu ra dòng lệnh hoặc tham khảo Lịch sử hoạt động để biết thêm thông tin về sự cố.", + "Retry as administrator": "Thử lại với quyền quản trị viên", + "Retry interactively": "Thử lại một cách tương tác", + "Retry skipping integrity checks": "Thử lại bỏ qua các kiểm tra tính toàn vẹn", + "Installation options": "Lựa chọn cài đặt", + "Save": "Lưu", + "UniGetUI collects anonymous usage data with the sole purpose of understanding and improving the user experience.": "UniGetUI thu thập dữ liệu sử dụng ẩn danh với mục đích duy nhất là hiểu và cải thiện trải nghiệm người dùng.", + "More details about the shared data and how it will be processed": "Thông tin chi tiết hơn về dữ liệu được chia sẻ và cách nó sẽ được xử lý", + "Do you accept that UniGetUI collects and sends anonymous usage statistics, with the sole purpose of understanding and improving the user experience?": "Bạn có chấp nhận rằng UniGetUI thu thập và gửi các số liệu thống kê sử dụng ẩn danh, với mục đích duy nhất là hiểu và cải thiện trải nghiệm người dùng không?", + "Decline": "Từ chối", + "No personal information is collected nor sent, and the collected data is anonimized, so it can't be back-tracked to you.": "Không có thông tin cá nhân nào được thu thập hoặc gửi đi, và dữ liệu thu thập được là ẩn danh, vì vậy không thể truy ngược lại bạn.", + "Navigation panel": "Bảng điều hướng", + "Operations": "Các thao tác", + "Toggle operations panel": "Bật/tắt bảng thao tác", + "Bulk operations": "Thao tác hàng loạt", + "Retry failed": "Thử lại các thao tác thất bại", + "Clear successful": "Xóa các thao tác thành công", + "Clear finished": "Xóa các thao tác đã hoàn tất", + "Cancel all": "Hủy tất cả", + "More": "Thêm", + "Toggle navigation panel": "Bật/tắt ngăn điều hướng", + "Minimize": "Thu nhỏ", + "Maximize": "Phóng to", + "UniGetUI by Devolutions": "UniGetUI của Devolutions", + "UniGetUI is an application that makes managing your software easier, by providing an all-in-one graphical interface for your command-line package managers.": "UniGetUI là một ứng dụng giúp việc quản lý phần mềm của bạn dễ dàng hơn bằng cách cung cấp giao diện đồ họa tất cả trong một cho trình quản lý gói dòng lệnh của bạn.", + "Useful links": "Liên kết hữu ích", + "UniGetUI Homepage": "Trang chủ UniGetUI", + "Report an issue or submit a feature request": "Báo cáo một vấn đề hoặc yêu cầu tính năng nào đó", + "UniGetUI Repository": "Kho mã UniGetUI", + "View GitHub Profile": "Xem hồ sơ GitHub", + "UniGetUI License": "Giấy phép WingetU", + "Using UniGetUI implies the acceptation of the MIT License": "Sử dụng UniGetUI ngụ ý việc chấp nhận Giấy phép MIT", + "Become a translator": "Trở thành người phiên dịch", + "Go back": "Quay lại", + "Go forward": "Đi tiếp", + "Go to home page": "Đi đến trang chủ", + "Reload page": "Tải lại trang", + "View page on browser": "Xem trang trên trình duyệt", + "The built-in browser is not supported on Linux yet.": "Trình duyệt tích hợp chưa được hỗ trợ trên Linux.", + "Open in browser": "Mở trong trình duyệt", + "Copy to clipboard": "Sao chép vào bảng nhớ tạm", + "Export to a file": "Xuất thành tệp", + "Log level:": "Mức độ ghi log:", + "Reload log": "Tải lại nhật ký", + "Export log": "Xuất nhật ký", + "Text": "Văn bản", + "Change how operations request administrator rights": "Thay đổi cách các thao tác yêu cầu quyền quản trị viên", + "Restrictions on package operations": "Các giới hạn áp dụng cho thao tác xử lý gói", + "Restrictions on package managers": "Các giới hạn áp dụng cho trình quản lý gói", + "Restrictions when importing package bundles": "Hạn chế khi nhập các gói phần mềm theo bộ", + "Ask for administrator privileges once for each batch of operations": "Yêu cầu đặc quyền của quản trị viên một lần cho mỗi nhóm hành động", + "Ask only once for administrator privileges": "Chỉ yêu cầu quyền quản trị một lần", + "Prohibit any kind of Elevation via UniGetUI Elevator or GSudo": "Cấm mọi hình thức nâng quyền thông qua UniGetUI Elevator hoặc GSudo", + "This option WILL cause issues. Any operation incapable of elevating itself WILL FAIL. Install/update/uninstall as administrator will NOT WORK.": "Tùy chọn này SẼ gây sự cố. Mọi thao tác không thể tự nâng quyền SẼ THẤT BẠI. Việc cài đặt/cập nhật/gỡ bỏ với quyền quản trị SẼ KHÔNG HOẠT ĐỘNG", + "Allow custom command-line arguments": "Cho phép sử dụng đối số dòng lệnh tùy chỉnh", + "Custom command-line arguments can change the way in which programs are installed, upgraded or uninstalled, in a way UniGetUI cannot control. Using custom command-lines can break packages. Proceed with caution.": "Các đối số dòng lệnh tùy chỉnh có thể thay đổi cách chương trình được cài đặt, nâng cấp hoặc gỡ bỏ, theo cách mà UniGetUI không thể kiểm soát. Việc sử dụng dòng lệnh tùy chỉnh có thể làm hỏng các gói phần mềm. Hãy tiến hành thận trọng.", + "Ignore custom pre-install and post-install commands when importing packages from a bundle": "Cho phép chạy các lệnh tùy chỉnh trước và sau khi cài đặt", + "Pre and post install commands will be run before and after a package gets installed, upgraded or uninstalled. Be aware that they may break things unless used carefully": "Các lệnh trước và sau khi cài đặt sẽ được thực thi trước và sau khi một gói phần mềm được cài đặt, nâng cấp hoặc gỡ bỏ. Hãy lưu ý rằng chúng có thể gây hỏng hóc nếu không được sử dụng cẩn thận", + "Allow changing the paths for package manager executables": "Cho phép thay đổi đường dẫn của các tệp thực thi trình quản lý gói", + "Turning this on enables changing the executable file used to interact with package managers. While this allows finer-grained customization of your install processes, it may also be dangerous": "Bật tùy chọn này cho phép thay đổi tệp thực thi được dùng để tương tác với trình quản lý gói. Mặc dù điều này giúp bạn tùy chỉnh quá trình cài đặt một cách chi tiết hơn, nhưng nó cũng có thể gây nguy hiểm", + "Allow importing custom command-line arguments when importing packages from a bundle": "Cho phép nhập các đối số dòng lệnh tùy chỉnh khi nhập gói từ một gói tổng hợp", + "Malformed command-line arguments can break packages, or even allow a malicious actor to gain privileged execution. Therefore, importing custom command-line arguments is disabled by default": "Các đối số dòng lệnh sai định dạng có thể làm hỏng các gói phần mềm, hoặc thậm chí tạo điều kiện cho kẻ tấn công xấu chiếm quyền thực thi đặc biệt. Vì vậy, việc nhập các đối số dòng lệnh tùy chỉnh bị vô hiệu hóa theo mặc định", + "Allow importing custom pre-install and post-install commands when importing packages from a bundle": "Cho phép nhập các lệnh tùy chỉnh trước và sau khi cài đặt khi nhập gói phần mềm từ một bộ", + "Pre and post install commands can do very nasty things to your device, if designed to do so. It can be very dangerous to import the commands from a bundle, unless you trust the source of that package bundle": "Các lệnh trước và sau khi cài đặt có thể gây hại nghiêm trọng cho thiết bị của bạn nếu được thiết kế với mục đích xấu. Việc nhập các lệnh này từ một gói tổng hợp có thể rất nguy hiểm, trừ khi bạn tin tưởng nguồn của gói phần mềm đó", + "Administrator rights and other dangerous settings": "Quyền quản trị và các thiết lập nguy hiểm khác", + "Package backup": "Sao lưu gói", + "Cloud package backup": "Sao lưu gói lên đám mây", + "Local package backup": "Sao lưu gói cục bộ", + "Local backup advanced options": "Tùy chọn nâng cao cho sao lưu cục bộ.", + "Log in with GitHub": "Đăng nhập bằng GitHub", + "Log out from GitHub": "Đăng xuất khỏi GitHub", + "Periodically perform a cloud backup of the installed packages": "Thực hiện sao lưu định kỳ lên đám mây cho các gói đã cài đặt", + "Cloud backup uses a private GitHub Gist to store a list of installed packages": "Sao lưu đám mây sử dụng một GitHub Gist riêng tư để lưu trữ danh sách các gói đã cài đặt", + "Perform a cloud backup now": "Thực hiện sao lưu lên đám mây ngay bây giờ", + "Backup": "Sao lưu", + "Restore a backup from the cloud": "Khôi phục bản sao lưu từ đám mây", + "Begin the process to select a cloud backup and review which packages to restore": "Bắt đầu quá trình chọn bản sao lưu trên đám mây và xem xét các gói cần khôi phục", + "Periodically perform a local backup of the installed packages": "Thực hiện sao lưu cục bộ định kỳ cho các gói đã cài đặt", + "Perform a local backup now": "Thực hiện sao lưu cục bộ ngay bây giờ", + "Change backup output directory": "Thay đổi thư mục sao lưu", + "Set a custom backup file name": "Đặt tên tệp sao lưu tùy chỉnh", + "Leave empty for default": "Để trống theo mặc định", + "Add a timestamp to the backup file names": "Thêm dấu thời gian vào tên tệp sao lưu", + "Backup and Restore": "Sao lưu và Khôi phục", + "Enable background api (UniGetUI Widgets and Sharing, port 7058)": "Kích hoạt api nền (Tiện ích và chia sẻ UniGetUI, cổng 7058)", + "Wait for the device to be connected to the internet before attempting to do tasks that require internet connectivity.": "Chờ cho thiết bị kết nối internet trước khi thực hiện các tác vụ yêu cầu kết nối internet.", + "Disable the 1-minute timeout for package-related operations": "Vô hiệu hóa thời gian chờ 1 phút cho các hoạt động liên quan đến gói", + "Use installed GSudo instead of UniGetUI Elevator": "Sử dụng GSudo đã cài thay cho UniGetUI Elevator", + "Use a custom icon and screenshot database URL": "Sử dụng URL cơ sở dữ liệu biểu tượng và ảnh chụp màn hình tùy chỉnh", + "Enable background CPU Usage optimizations (see Pull Request #3278)": "Bật các tối ưu hóa sử dụng CPU nền (xem Yêu cầu Kéo #3278)", + "Perform integrity checks at startup": "Thực hiện kiểm tra tính toàn vẹn khi khởi động", + "When batch installing packages from a bundle, install also packages that are already installed": "Khi cài đặt hàng loạt các gói từ một bộ, hãy cài cả những gói đã được cài đặt trước đó", + "Experimental settings and developer options": "Cài đặt thử nghiệm và tùy chọn nhà phát triển", + "Show UniGetUI's version and build number on the titlebar.": "Hiển thị phiên bản UniGetUI trên thanh tiêu đề", + "Language": "Ngôn ngữ", + "UniGetUI updater": "Trình cập nhật UniGetUI", + "Telemetry": "Thu thập dữ liệu từ xa", + "Manage UniGetUI settings": "Quản lý cài đặt UniGetUI", + "Related settings": "Cài đặt liên quan", + "Update UniGetUI automatically": "Tự động cập nhật UniGetUI", + "Check for updates": "Kiểm tra bản cập nhật", + "Install prerelease versions of UniGetUI": "Cài đặt các phiên bản phát hành trước của UniGetUI", + "Manage telemetry settings": "Quản lý cài đặt thu thập thông tin", + "Manage": "Quản lý", + "Import settings from a local file": "Nhập cài đặt từ tệp tin cục bộ", + "Import": "Nhập", + "Export settings to a local file": "Xuất cài đặt ra tệp tin cục bộ", + "Export": "Xuất", + "Reset UniGetUI": "Đặt lại UniGetUI", + "User interface preferences": "Tùy chọn giao diện người dùng", + "Application theme, startup page, package icons, clear successful installs automatically": "Chủ đề ứng dụng, trang khởi động, biểu tượng gói, tự động xóa các cài đặt thành công", + "General preferences": "Tùy chỉnh chung", + "UniGetUI display language:": "Ngôn ngữ hiển thị UniGetUI:", + "System language": "Ngôn ngữ hệ thống", + "Is your language missing or incomplete?": "Ngôn ngữ của bạn bị thiếu hoặc không đầy đủ?", + "Appearance": "Giao diện", + "UniGetUI on the background and system tray": "UniGetUI chạy trong nền và khay hệ thống", + "Package lists": "Danh sách gói", + "Use classic mode": "Dùng chế độ cổ điển", + "Restart UniGetUI to apply this change": "Khởi động lại UniGetUI để áp dụng thay đổi này", + "The classic UI is disabled for beta testers": "Giao diện cổ điển bị tắt đối với người thử nghiệm beta", + "Close UniGetUI to the system tray": "Đóng UniGetUI vào khay hệ thống.", + "Manage UniGetUI autostart behaviour": "Quản lý hành vi tự khởi động của UniGetUI", + "Show package icons on package lists": "Hiển thị biểu tượng gói trên danh sách gói", + "Clear cache": "Xóa bộ nhớ đệm", + "Select upgradable packages by default": "Chọn các gói có thể nâng cấp theo mặc định", + "Light": "Sáng", + "Dark": "Tối", + "Follow system color scheme": "Theo dõi bảng màu hệ thống", + "Application theme:": "Giao diện ứng dụng", + "UniGetUI startup page:": "Trang khởi động UniGetUI:", + "Proxy settings": "Cài đặt proxy", + "Other settings": "Cài đặt khác", + "Connect the internet using a custom proxy": "Kết nối internet bằng proxy tùy chỉnh", + "Please note that not all package managers may fully support this feature": "Xin lưu ý rằng không phải tất cả các trình quản lý gói đều có thể hỗ trợ đầy đủ tính năng này", + "Proxy URL": "URL proxy", + "Enter proxy URL here": "Nhập URL proxy vào đây", + "Authenticate to the proxy with a user and a password": "Xác thực với proxy bằng tên người dùng và mật khẩu", + "Internet and proxy settings": "Cài đặt Internet và proxy", + "Package manager preferences": "Tùy chọn trình quản lý gói", + "Ready": "Sẵn sàng", + "Not found": "Không tìm thấy", + "Notification preferences": "Tùy chọn thông báo", + "Notification types": "Các loại thông báo", + "The system tray icon must be enabled in order for notifications to work": "Biểu tượng khay hệ thống phải được bật để các thông báo hoạt động", + "Enable UniGetUI notifications": "Bật thông báo của UniGetUI", + "Show a notification when there are available updates": "Hiển thị thông báo ngay khi có bản cập nhật", + "Show a silent notification when an operation is running": "Hiển thị thông báo im lặng khi một thao tác đang chạy", + "Show a notification when an operation fails": "Hiển thị thông báo khi thao tác thất bại", + "Show a notification when an operation finishes successfully": "Hiển thị thông báo khi một thao tác kết thúc thành công", + "Concurrency and execution": "Đồng thời và thực thi", + "Automatic desktop shortcut remover": "Trình gỡ lối tắt trên màn hình tự động", + "Choose how many operations should be performed in parallel": "Chọn số lượng thao tác được thực hiện song song", + "Clear successful operations from the operation list after a 5 second delay": "Xóa các thao tác thành công khỏi danh sách thao tác sau khi trễ 5 giây", + "Download operations are not affected by this setting": "Các thao tác tải xuống không bị ảnh hưởng bởi thiết lập này", + "You may lose unsaved data": "Bạn có thể mất dữ liệu chưa được lưu", + "Ask to delete desktop shortcuts created during an install or upgrade.": "Yêu cầu xóa các lối tắt trên màn hình được tạo ra trong quá trình cài đặt hoặc nâng cấp.", + "Package update preferences": "Tùy chọn cập nhật gói", + "Update check frequency, automatically install updates, etc.": "Tần suất kiểm tra cập nhật, tự động cài đặt cập nhật, v.v.", + "Reduce UAC prompts, elevate installations by default, unlock certain dangerous features, etc.": "Giảm số lần hiển thị thông báo UAC, tự động nâng quyền khi cài đặt, mở khóa một số tính năng nguy hiểm, v.v.", + "Package operation preferences": "Tùy chọn thao tác gói", + "Enable {pm}": "Bật {pm}", + "Not finding the file you are looking for? Make sure it has been added to path.": "Không tìm thấy tệp bạn cần? Hãy đảm bảo rằng nó đã được thêm vào biến đường dẫn.", + "Select the executable to be used. The following list shows the executables found by UniGetUI": "Chọn tệp thực thi cần sử dụng. Danh sách sau đây hiển thị các tệp thực thi được UniGetUI tìm thấy.", + "For security reasons, changing the executable file is disabled by default": "Vì lý do bảo mật, việc thay đổi tệp thực thi bị vô hiệu hóa theo mặc định", + "Change this": "Thay đổi mục này", + "Copy path": "Sao chép đường dẫn", + "Current executable file:": "Tệp thực thi hiện tại:", + "Ignore packages from {pm} when showing a notification about updates": "Bỏ qua các gói từ {pm} khi hiển thị thông báo về các bản cập nhật", + "Update security": "Bảo mật cập nhật", + "Use global setting": "Sử dụng cài đặt toàn cục", + "Minimum age for updates": "Tuổi tối thiểu của bản cập nhật", + "e.g. 10": "ví dụ: 10", + "Custom minimum age (days)": "Tuổi tối thiểu tùy chỉnh (ngày)", + "{pm} does not provide release dates for its packages, so this setting will have no effect": "{pm} không cung cấp ngày phát hành cho các gói của nó, vì vậy cài đặt này sẽ không có tác dụng", + "{pm} only provides release dates for some of its packages, so this setting will only apply to those packages": "{pm} chỉ cung cấp ngày phát hành cho một số gói của nó, vì vậy thiết lập này sẽ chỉ áp dụng cho các gói đó", + "Override the global minimum update age for this package manager": "Ghi đè tuổi cập nhật tối thiểu toàn cục cho trình quản lý gói này", + "View {0} logs": "Xem {0} nhật ký", + "If Python cannot be found or is not listing packages but is installed on the system, ": "Nếu không tìm thấy Python hoặc Python không liệt kê gói dù đã được cài đặt trên hệ thống, ", + "Advanced options": "Tùy chọn nâng cao", + "WinGet command-line tool": "Công cụ dòng lệnh WinGet", + "Choose which command-line tool UniGetUI uses for WinGet operations when the COM API is not used": "Chọn công cụ dòng lệnh mà UniGetUI sử dụng cho các thao tác WinGet khi không dùng COM API", + "WinGet COM API": "WinGet COM API", + "Choose whether UniGetUI can use the WinGet COM API before falling back to the command-line tool": "Chọn liệu UniGetUI có thể dùng WinGet COM API trước khi quay lại công cụ dòng lệnh hay không", + "Reset WinGet": "Đặt lại WinGet", + "This may help if no packages are listed": "Điều này có thể hữu ích nếu không có gói nào được liệt kê", + "Force install location parameter when updating packages with custom locations": "Buộc tham số vị trí cài đặt khi cập nhật các gói có vị trí tùy chỉnh", + "Install Scoop": "Cài đặt Scoop", + "Uninstall Scoop (and its packages)": "Gỡ cài đặt Scoop (và các gói của nó)", + "Run cleanup and clear cache": "Dọn dẹp và xóa bộ nhớ tạm", + "Run": "Chạy", + "Enable Scoop cleanup on launch": "Bật tính năng dọn dẹp Scoop khi khởi chạy", + "Default vcpkg triplet": "Bộ ba vcpkg mặc định", + "Change vcpkg root location": "Thay đổi vị trí gốc của vcpkg", + "Reset vcpkg root location": "Đặt lại vị trí gốc vcpkg", + "Open vcpkg root location": "Mở vị trí gốc vcpkg", + "Language, theme and other miscellaneous preferences": "Ngôn ngữ, chủ đề và các cài đặt khác", + "Show notifications on different events": "Hiển thị thông báo về các sự kiện khác nhau", + "Change how UniGetUI checks and installs available updates for your packages": "Thay đổi cách UniGetUI kiểm tra và cài đặt các bản cập nhật có sẵn cho gói của bạn", + "Automatically save a list of all your installed packages to easily restore them.": "Tự động lưu một danh sách tất cả các gói bạn đã cài đặt để dễ dàng khôi phục chúng sau này.", + "Enable and disable package managers, change default install options, etc.": "Bật và tắt trình quản lý gói, thay đổi tùy chọn cài đặt mặc định, v.v.", + "Internet connection settings": "Cài đặt kết nối Internet", + "Proxy settings, etc.": "Cài đặt proxy, v.v.", + "Beta features and other options that shouldn't be touched": "Các tính năng beta và lựa chọn khác không nên điều chỉnh", + "Reload sources": "Tải lại nguồn", + "Delete source": "Xóa nguồn", + "Known sources": "Các nguồn đã biết", + "Update checking": "Kiểm tra cập nhật", + "Automatic updates": "Cập nhật tự động", + "Check for package updates periodically": "Kiểm tra cập nhật gói định kỳ", + "Check for updates every:": "Kiểm tra cập nhật mỗi: ", + "Install available updates automatically": "Tự động cài đặt các bản cập nhật có sẵn", + "Do not automatically install updates when the network connection is metered": "Không tự động cài đặt cập nhật khi kết nối mạng được đo lường", + "Do not automatically install updates when the device runs on battery": "Không tự động cài đặt bản cập nhật khi thiết bị đang chạy bằng pin", + "Do not automatically install updates when the battery saver is on": "Không tự động cài đặt cập nhật khi chế độ tiết kiệm pin đang bật", + "Only show updates that are at least the specified number of days old": "Chỉ hiển thị các bản cập nhật đã cũ ít nhất bằng số ngày được chỉ định", + "Warn me when the installer URL host changes between the installed version and the new version (WinGet only)": "Cảnh báo tôi khi máy chủ URL trình cài đặt thay đổi giữa phiên bản đã cài đặt và phiên bản mới (chỉ WinGet)", + "Change how UniGetUI handles install, update and uninstall operations.": "Thay đổi cách UniGetUI xử lý các thao tác cài đặt, cập nhật và gỡ cài đặt.", + "Navigation": "Điều hướng", + "Check for UniGetUI updates": "Kiểm tra bản cập nhật UniGetUI", + "Quit UniGetUI": "Thoát UniGetUI", + "Filters": "Bộ lọc", + "Sources": "Nguồn", + "Search for packages to start": "Tìm kiếm các gói để bắt đầu", + "Select all": "Chọn tất cả", + "Clear selection": "Xóa lựa chọn", + "Instant search": "Tìm kiếm tức thì", + "Distinguish between uppercase and lowercase": "Phân biệt chữ hoa và chữ thường", + "Ignore special characters": "Bỏ qua các ký tự đặc biệt", + "Search mode": "Chế độ tìm kiếm", + "Both": "Cả hai", + "Exact match": "Khớp chính xác", + "Show similar packages": "Hiện các gói liên quan", + "Loading": "Đang tải", + "Package": "Gói phần mềm", + "More options": "Tùy chọn khác", + "Order by:": "Sắp xếp theo:", + "Name": "Tên", + "Id": "Mã định danh", + "Ascendant": "Thăng tiến", + "Descendant": "Phần tử con", + "View modes": "Chế độ xem", + "Reload": "Tải lại", + "Closed": "Đã đóng", + "Ascending": "Tăng dần", + "Descending": "Giảm dần", + "{0}: {1}, {2}": "{0}: {1}, {2}", + "Order by": "Sắp xếp theo", + "No results were found matching the input criteria": "Không tìm thấy kết quả nào phù hợp với tiêu chí đầu vào", + "No packages were found": "Không tìm thấy gói nào", + "Loading packages": "Đang tải gói", + "Skip integrity checks": "Bỏ qua kiểm tra tính toàn vẹn", + "Download selected installers": "Tải xuống các trình cài đặt đã chọn", + "Install selection": "Cài đặt những lựa chọn", + "Install options": "Tùy chọn cài đặt", + "Add selection to bundle": "Thêm gói lựa chọn vào nhóm", + "Download installer": "Tải xuống trình cài đặt", + "Uninstall selection": "Gỡ bỏ các mục đã chọn", + "Uninstall options": "Tùy chọn gỡ cài đặt", + "Ignore selected packages": "Bỏ qua các gói đã chọn", + "Open install location": "Mở vị trí cài đặt", + "Reinstall package": "Cài đặt lại gói", + "Uninstall package, then reinstall it": "Gỡ rồi cài đặt lại gói", + "Ignore updates for this package": "Bỏ qua các bản cập nhật cho gói này", + "WinGet malfunction detected": "Đã phát hiện sự cố WinGet", + "It looks like WinGet is not working properly. Do you want to attempt to repair WinGet?": "Có vẻ như WinGet không hoạt động bình thường. Bạn có muốn thử sửa chữa WinGet không?", + "Repair WinGet": "Sửa chữa WinGet", + "Updates will no longer be ignored for {0}": "Các bản cập nhật sẽ không còn bị bỏ qua cho {0}", + "Updates are now ignored for {0}": "Các bản cập nhật hiện đã bị bỏ qua cho {0}", + "Do not ignore updates for this package anymore": "Không bỏ qua các cập nhật cho gói này nữa", + "Add packages or open an existing package bundle": "Thêm gói hoặc mở một nhóm có sẵn", + "Add packages to start": "Thêm gói để bắt đầu", + "The current bundle has no packages. Add some packages to get started": "Nhóm hiện tại không có gói nào. Thêm một số gói để bắt đầu", + "New": "Mới", + "Save as": "Lưu thành...", + "Create .ps1 script": "Tạo tập lệnh .ps1", + "Remove selection from bundle": "Xóa lựa chọn khỏi nhóm", + "Skip hash checks": "Bỏ qua kiểm tra hàm băm", + "The package bundle is not valid": "Nhóm gói không hợp lệ", + "The bundle you are trying to load appears to be invalid. Please check the file and try again.": "Nhóm bạn đang cố tải có vẻ không hợp lệ. Vui lòng kiểm tra tập tin và thử lại.", + "Package bundle": "Nhóm gói", + "Could not create bundle": "Không thể tạo gói", + "The package bundle could not be created due to an error.": "Không thể tạo nhóm gói do có lỗi.", + "Install script": "Tập lệnh cài đặt", + "PowerShell script": "Tập lệnh PowerShell", + "The installation script saved to {0}": "Tập lệnh cài đặt đã được lưu tại {0}", + "An error occurred": "Oops! Có lỗi xảy ra", + "An error occurred while attempting to create an installation script:": "Đã xảy ra lỗi khi cố gắng tạo tập lệnh cài đặt:", + "Hooray! No updates were found.": "Yeah! Không có bản cập nhật nào được tìm thấy!", + "Uninstall selected packages": "Gỡ cài đặt các gói đã chọn", + "Update selection": "Cập nhật các mục đã chọn", + "Update options": "Tùy chọn cập nhật", + "Uninstall package, then update it": "Gỡ rồi cập nhật gói", + "Uninstall package": "Gỡ cài đặt gói", + "Skip this version": "Bỏ qua phiên bản này", + "Pause updates for": "Tạm dừng cập nhật trong vòng", + "User | Local": "Người dùng | Cục bộ", + "Machine | Global": "Máy | Toàn cục", + "The default package manager for Debian/Ubuntu-based Linux distributions.
Contains: Debian/Ubuntu packages": "Trình quản lý gói mặc định cho các bản phân phối Linux dựa trên Debian/Ubuntu.
Bao gồm: Các gói Debian/Ubuntu", + "The Rust package manager.
Contains: Rust libraries and programs written in Rust": "Trình quản lý gói của Rust.
Bao gồm: Các thư viện Rust và các chương trình được viết bằng Rust", + "The classical package manager for windows. You'll find everything there.
Contains: General Software": "Trình quản lý gói cổ điển cho Windows. Bạn sẽ tìm thấy mọi thứ ở đó.
Bao gồm: Phần mềm chung", + "The default package manager for RHEL/Fedora-based Linux distributions.
Contains: RPM packages": "Trình quản lý gói mặc định cho các bản phân phối Linux dựa trên RHEL/Fedora.
Bao gồm: Các gói RPM", + "A repository full of tools and executables designed with Microsoft's .NET ecosystem in mind.
Contains: .NET related tools and scripts": "Một kho chứa đầy đủ các công cụ và tệp thực thi được thiết kế với hệ sinh thái .NET của Microsoft.
Bao gồm: Các công cụ và tập lệnh liên quan đến .NET", + "The universal Linux package manager for desktop applications.
Contains: Flatpak applications from configured remotes": "Trình quản lý gói Linux phổ quát cho các ứng dụng máy tính để bàn.
Chứa: các ứng dụng Flatpak từ các nguồn từ xa đã cấu hình", + "NuPkg (zipped manifest)": "NuPkg (tệp cấu hình nén)", + "The Missing Package Manager for macOS (or Linux).
Contains: Formulae, Casks": "Trình quản lý gói còn thiếu cho macOS (hoặc Linux).
Chứa: Formulae, Casks", + "Node JS's package manager. Full of libraries and other utilities that orbit the javascript world
Contains: Node javascript libraries and other related utilities": "Trình quản lý gói của Node JS. Đầy đủ các thư viện và các tiện ích khác xoay quanh thế giới JavaScript
Bao gồm: Các thư viện JavaScript của Node và các tiện ích liên quan khác", + "The default package manager for Arch Linux and its derivatives.
Contains: Arch Linux packages": "Trình quản lý gói mặc định cho Arch Linux và các bản phái sinh của nó.
Bao gồm: Các gói Arch Linux", + "Python's library manager. Full of python libraries and other python-related utilities
Contains: Python libraries and related utilities": "Trình quản lý thư viện của Python. Đầy đủ các thư viện Python và các tiện ích liên quan đến Python khác
Bao gồm: Các thư viện Python và các tiện ích liên quan", + "PowerShell's package manager. Find libraries and scripts to expand PowerShell capabilities
Contains: Modules, Scripts, Cmdlets": "Trình quản lý gói của PowerShell. Tìm thư viện và tập lệnh để mở rộng khả năng của PowerShell
Bao gồm: Mô-đun, Tập lệnh, Lệnh ghép ngắn", + "extracted": "đã giải nén", + "Scoop package": "Gói Scoop", + "Great repository of unknown but useful utilities and other interesting packages.
Contains: Utilities, Command-line programs, General Software (extras bucket required)": "Kho lưu trữ lớn chưa biết nhưng có các tiện ích hữu ích và các gói thú vị khác.
Bao gồm: Tiện ích, Chương trình dòng lệnh, Phần mềm chung (yêu cầu bộ chứa bổ sung)", + "The universal Linux package manager by Canonical.
Contains: Snap packages from the Snapcraft store": "Trình quản lý gói Linux phổ quát của Canonical.
Bao gồm: Các gói Snap từ cửa hàng Snapcraft", + "library": "thư viện", + "feature": "tính năng", + "A popular C/C++ library manager. Full of C/C++ libraries and other C/C++-related utilities
Contains: C/C++ libraries and related utilities": "Một trình quản lý thư viện C/C++ phổ biến. Đầy đủ các thư viện C/C++ và các tiện ích liên quan đến C/C++ khác.
Bao gồm: Các thư viện C/C++ và các tiện ích liên quan.", + "option": "lựa chọn", + "This package cannot be installed from an elevated context.": "Gói này không thể được cài đặt từ một ngữ cảnh nâng cao.", + "Please run UniGetUI as a regular user and try again.": "Vui lòng chạy UniGetUI với quyền người dùng thông thường và thử lại.", + "Please check the installation options for this package and try again": "Vui lòng kiểm tra các tùy chọn cài đặt cho gói này và thử lại", + "Microsoft's official package manager. Full of well-known and verified packages
Contains: General Software, Microsoft Store apps": "Trình quản lý gói chính thức của Microsoft. Đầy đủ các gói nổi tiếng và đã được xác minh
Bao gồm: Phần mềm chung, ứng dụng Microsoft Store", + "Local PC": "PC cục bộ", + "Android Subsystem": "Hệ thống Android", + "Operation on queue (position {0})...": "Hoạt động trên hàng đợi (vị trí {0})...", + "Click here for more details": "Bấm vào đây để biết thêm chi tiết", + "Operation canceled by user": "Người dùng đã hủy thao tác", + "Running PreOperation ({0}/{1})...": "Đang chạy PreOperation ({0}/{1})...", + "PreOperation {0} out of {1} failed, and was tagged as necessary. Aborting...": "PreOperation {0} trên {1} đã thất bại và được đánh dấu là bắt buộc. Đang hủy...", + "PreOperation {0} out of {1} finished with result {2}": "PreOperation {0} trên {1} đã hoàn tất với kết quả {2}", + "Starting operation...": "Bắt đầu hoạt động...", + "Running PostOperation ({0}/{1})...": "Đang chạy PostOperation ({0}/{1})...", + "PostOperation {0} out of {1} failed, and was tagged as necessary. Aborting...": "PostOperation {0} trên {1} đã thất bại và được đánh dấu là bắt buộc. Đang hủy...", + "PostOperation {0} out of {1} finished with result {2}": "PostOperation {0} trên {1} đã hoàn tất với kết quả {2}", + "{package} installer download": "{package} trình cài đặt tải xuống", + "{0} installer is being downloaded": "Trình cài đặt {0} đang được tải xuống", + "Download succeeded": "Tải xuống thành công", + "{package} installer was downloaded successfully": "Trình cài đặt {package} đã được tải xuống thành công", + "Download failed": "Tải xuống thất bại", + "{package} installer could not be downloaded": "Trình cài đặt {package} không thể tải xuống", + "{package} Installation": "Cài đặt {package}", + "{0} is being installed": "{0} đang được cài đặt", + "Installation succeeded": "Cài đặt thành công", + "{package} was installed successfully": "\n{package} đã được cài đặt thành công", + "Installation failed": "Cài đặt thất bại", + "{package} could not be installed": "{package} không thể cài đặt", + "{package} Update": "Bản cập nhật {package}", + "Update succeeded": "Cập nhật thành công", + "{package} was updated successfully": "{package} đã được cập nhật thành công", + "Update failed": "Cập nhật không thành công", + "{package} could not be updated": "{package} không thể cập nhật", + "{package} Uninstall": "Gỡ cài đặt {package}", + "{0} is being uninstalled": "{0} đang được gỡ cài đặt", + "Uninstall succeeded": "Gỡ cài đặt thành công", + "{package} was uninstalled successfully": "\n{package} đã được gỡ thành công", + "Uninstall failed": "Gỡ cài đặt không thành công", + "{package} could not be uninstalled": "{package} không thể gỡ", + "Adding source {source}": "Đang thêm nguồn {source}", + "Adding source {source} to {manager}": "Thêm nguồn {source} vào {manager}", + "Source added successfully": "Thêm nguồn thành công", + "The source {source} was added to {manager} successfully": "Nguồn {source} đã được thêm vào {manager} thành công", + "Could not add source": "Không thể thêm nguồn", + "Could not add source {source} to {manager}": "Không thể thêm nguồn {source} vào {manager}", + "Removing source {source}": "Đang gỡ bỏ nguồn {source}", + "Removing source {source} from {manager}": "Đang xóa nguồn {source} khỏi {manager}", + "Source removed successfully": "Gỡ bỏ nguồn thành công", + "The source {source} was removed from {manager} successfully": "Nguồn {source} đã được xóa khỏi {manager} thành công", + "Could not remove source": "Không thể xóa nguồn", + "Could not remove source {source} from {manager}": "Không thể xóa nguồn {source} khỏi {manager}", + "The package manager \"{0}\" was not found": "Không tìm thấy trình quản lý gói \"{0}\"", + "The package manager \"{0}\" is disabled": "Trình quản lý gói \"{0}\" bị tắt", + "There is an error with the configuration of the package manager \"{0}\"": "Đã xảy ra lỗi với cấu hình của trình quản lý gói \"{0}\"", + "The package \"{0}\" was not found on the package manager \"{1}\"": "Không tìm thấy gói \"{0}\" trên trình quản lý gói \"{1}\"", + "{0} is disabled": "{0} đã bị vô hiệu hóa", + "{0} weeks": "{0} tuần", + "1 month": "1 tháng", + "{0} months": "{0} tháng", + "Something went wrong": "Điều gì đó không ổn", + "An interal error occurred. Please view the log for further details.": "Đã xảy ra lỗi nội bộ. Vui lòng xem nhật ký để biết thêm chi tiết.", + "No applicable installer was found for the package {0}": "Không tìm thấy trình cài đặt phù hợp cho gói {0}", + "Integrity checks will not be performed during this operation": "Kiểm tra tính hoàn hảo sẽ không được thực hiện trong quá trình hoạt động này", + "This is not recommended.": "Điều này không được khuyến nghị.", + "Run now": "Chạy ngay bây giờ", + "Run next": "Chạy tiếp theo", + "Run last": "Chạy cuối cùng", + "Show in explorer": "Hiển thị trong trình duyệt", + "Checked": "Đã chọn", + "Unchecked": "Bỏ chọn", + "This package is already installed": "Gói này đã được cài đặt", + "This package can be upgraded to version {0}": "Gói này có thể được nâng cấp lên phiên bản {0}", + "Updates for this package are ignored": "Các bản cập nhật cho gói này bị bỏ qua", + "This package is being processed": "Gói này đang được xử lý", + "This package is not available": "Gói này không có sẵn", + "Select the source you want to add:": "Chọn nguồn bạn muốn thêm", + "Source name:": "Tên nguồn:", + "Source URL:": "URL nguồn:", + "An error occurred when adding the source: ": "Có lỗi khi thêm nguồn", + "Package management made easy": "Quản lý gói trở nên dễ dàng", + "version {0}": "phiên bản {0}", + "[RAN AS ADMINISTRATOR]": "CHẠY DƯỚI QUYỀN QUẢN TRỊ VIÊN", + "Portable mode": "Chế độ di động", + "DEBUG BUILD": "BẢN DỰNG GỠ LỖI", + "Here you can change UniGetUI's behaviour regarding the following shortcuts. Checking a shortcut will make UniGetUI delete it if if gets created on a future upgrade. Unchecking it will keep the shortcut intact": "Tại đây, bạn có thể thay đổi hành vi của UniGetUI liên quan đến các phím tắt sau. Kiểm tra một phím tắt sẽ làm cho UniGetUI xóa nó nếu nó được tạo ra trong lần nâng cấp tương lai. Bỏ chọn nó sẽ giữ nguyên phím tắt.", + "Manual scan": "Quét thủ công", + "Existing shortcuts on your desktop will be scanned, and you will need to pick which ones to keep and which ones to remove.": "Các lối tắt hiện có trên màn hình của bạn sẽ được quét, và bạn sẽ cần chọn những lối tắt nào để giữ lại và những lối tắt nào để xóa.", + "Delete?": "Xóa?", + "I understand": "Tôi hiểu", + "Chocolatey setup changed": "Thiết lập Chocolatey đã thay đổi", + "UniGetUI no longer includes its own private Chocolatey installation. A legacy UniGetUI-managed Chocolatey installation was detected for this user profile, but system Chocolatey was not found. Chocolatey will stay unavailable in UniGetUI until Chocolatey is installed on the system and UniGetUI is restarted. Applications previously installed through UniGetUI's bundled Chocolatey may still appear under other sources such as Local PC or WinGet.": "UniGetUI không còn bao gồm bản cài đặt Chocolatey riêng nữa. Một bản cài đặt Chocolatey do UniGetUI quản lý trước đây đã được phát hiện cho hồ sơ người dùng này, nhưng không tìm thấy Chocolatey hệ thống. Chocolatey sẽ không khả dụng trong UniGetUI cho đến khi Chocolatey được cài đặt trên hệ thống và UniGetUI được khởi động lại. Các ứng dụng đã cài đặt trước đó thông qua Chocolatey đi kèm UniGetUI vẫn có thể xuất hiện trong các nguồn khác như Local PC hoặc WinGet.", + "NOTE: This troubleshooter can be disabled from UniGetUI Settings, on the WinGet section": "LƯU Ý: Trình khắc phục sự cố này có thể bị tắt từ Cài đặt UniGetUI, trên phần WinGet", + "Restart": "Khởi động lại", + "Are you sure you want to delete all shortcuts?": "Bạn có chắc chắn muốn xóa tất cả các lối tắt không?", + "Any new shorcuts created during an install or an update operation will be deleted automatically, instead of showing a confirmation prompt the first time they are detected.": "Bất kỳ lối tắt mới nào được tạo trong quá trình cài đặt hoặc cập nhật sẽ tự động bị xóa, thay vì hiển thị lời nhắc xác nhận lần đầu tiên chúng được phát hiện.", + "Any shorcuts created or modified outside of UniGetUI will be ignored. You will be able to add them via the {0} button.": "Bất kỳ lối tắt nào được tạo hoặc chỉnh sửa ngoài UniGetUI sẽ bị bỏ qua. Bạn có thể thêm chúng thông qua nút {0}.", + "Are you really sure you want to enable this feature?": "Bạn có thật sự chắc chắn muốn bật tính năng này không?", + "No new shortcuts were found during the scan.": "Không tìm thấy lối tắt mới nào trong quá trình quét.", + "How to add packages to a bundle": "Cách thêm các gói vào bộ sản phẩm", + "In order to add packages to a bundle, you will need to: ": "Để thêm các gói vào bộ sản phẩm, bạn cần:", + "1. Navigate to the \"{0}\" or \"{1}\" page.": "1. Điều hướng đến trang \"{0}\" hoặc \"{1}\".", + "2. Locate the package(s) you want to add to the bundle, and select their leftmost checkbox.": "2. Xác định gói hàng bạn muốn thêm vào bộ sản phẩm và chọn hộp kiểm ở vị trí ngoài cùng bên trái của chúng.", + "3. When the packages you want to add to the bundle are selected, find and click the option \"{0}\" on the toolbar.": "3. Khi các gói hàng bạn muốn thêm vào bộ sản phẩm đã được chọn, hãy tìm và nhấp vào tùy chọn \"{0}\" trên thanh công cụ.", + "4. Your packages will have been added to the bundle. You can continue adding packages, or export the bundle.": "4. Các gói hàng của bạn sẽ được thêm vào bộ sản phẩm. Bạn có thể tiếp tục thêm các gói hàng khác hoặc xuất bộ sản phẩm.", + "Which backup do you want to open?": "Bạn muốn mở bản sao lưu nào?", + "Select the backup you want to open. Later, you will be able to review which packages you want to install.": "Chọn bản sao lưu bạn muốn mở. Sau đó, bạn sẽ có thể xem lại và chọn các gói/chương trình muốn khôi phục.", + "There are ongoing operations. Quitting UniGetUI may cause them to fail. Do you want to continue?": "Có các hoạt động đang diễn ra. Thoát UniGetUI có thể khiến chúng bị thất bại. Bạn có muốn tiếp tục không?", + "UniGetUI or some of its components are missing or corrupt.": "UniGetUI hoặc một số thành phần của nó đang bị thiếu hoặc bị hỏng.", + "It is strongly recommended to reinstall UniGetUI to adress the situation.": "Rất khuyến nghị bạn nên cài đặt lại UniGetUI để xử lý tình huống hiện tại.", + "Refer to the UniGetUI Logs to get more details regarding the affected file(s)": "Tham khảo nhật ký UniGetUI để biết thêm chi tiết về (các) tệp bị ảnh hưởng", + "Integrity checks can be disabled from the Experimental Settings": "Kiểm tra tính toàn vẹn có thể được vô hiệu hóa từ phần Cài đặt Thử nghiệm", + "Repair UniGetUI": "Sửa chữa UniGetUI", + "Live output": "Đầu ra trực tiếp", + "This package bundle had some settings that are potentially dangerous, and may be ignored by default.": "Bộ gói này có một số thiết lập tiềm ẩn nguy hiểm và có thể bị bỏ qua theo mặc định.", + "Entries that show in YELLOW will be IGNORED.": "Các mục hiển thị bằng màu VÀNG sẽ bị BỎ QUA.", + "Entries that show in RED will be IMPORTED.": "Các mục hiển thị bằng màu ĐỎ sẽ được NHẬP vào.", + "You can change this behavior on UniGetUI security settings.": "Bạn có thể thay đổi hành vi này trong phần cài đặt bảo mật của UniGetUI.", + "Open UniGetUI security settings": "Mở cài đặt bảo mật của UniGetUI", + "Should you modify the security settings, you will need to open the bundle again for the changes to take effect.": "Nếu bạn thay đổi cài đặt bảo mật, bạn sẽ cần mở lại bộ gói để các thay đổi có hiệu lực.", + "Details of the report:": "Chi tiết của báo cáo:", + "Are you sure you want to create a new package bundle? ": "Bạn có chắc chắn muốn tạo một nhóm gói mới không?", + "Any unsaved changes will be lost": "Mọi thay đổi chưa lưu sẽ bị mất", + "Warning!": "Cảnh báo!", + "For security reasons, custom command-line arguments are disabled by default. Go to UniGetUI security settings to change this. ": "Vì lý do bảo mật, các tham số dòng lệnh tùy chỉnh bị vô hiệu hóa theo mặc định. Hãy vào cài đặt bảo mật của UniGetUI để thay đổi.", + "Change default options": "Thay đổi tùy chọn mặc định", + "Ignore future updates for this package": "Bỏ qua các bản cập nhật tương lai cho gói này", + "For security reasons, pre-operation and post-operation scripts are disabled by default. Go to UniGetUI security settings to change this. ": "Vì lý do bảo mật, các tập lệnh trước và sau thao tác bị vô hiệu hóa theo mặc định. Hãy vào cài đặt bảo mật của UniGetUI để thay đổi.", + "You can define the commands that will be run before or after this package is installed, updated or uninstalled. They will be run on a command prompt, so CMD scripts will work here.": "Bạn có thể xác định các lệnh sẽ được thực thi trước hoặc sau khi gói phần mềm này được cài đặt, cập nhật hoặc gỡ bỏ. Các lệnh này sẽ chạy trong cửa sổ dòng lệnh, vì vậy các script CMD đều hoạt động được ở đây.", + "Change this and unlock": "Thay đổi mục này và mở khóa", + "{0} Install options are currently locked because {0} follows the default install options.": "Các tùy chọn cài đặt của {0} hiện đang bị khóa vì {0} đang tuân theo thiết lập cài đặt mặc định.", + "Unset or unknown": "Chưa thiết lập hoặc không xác định", + "This package has no screenshots or is missing the icon? Contrbute to UniGetUI by adding the missing icons and screenshots to our open, public database.": "Gói này không có ảnh chụp màn hình hoặc bị thiếu biểu tượng? Hãy đóng góp cho UniGetUI bằng cách thêm các biểu tượng và ảnh chụp màn hình bị thiếu vào cơ sở dữ liệu mở và công cộng của chúng tôi.", + "Become a contributor": "Trở thành người đóng góp", + "Update to {0} available": "Đã có bản cập nhật lên {0}", + "Reinstall": "Cài đặt lại", + "Installer not available": "Trình cài đặt không có sẵn", + "Version:": "Phiên bản:", + "UniGetUI Version {0}": "UniGetUI Phiên bản {0}", + "Performing backup, please wait...": "Đang thực hiện sao lưu, vui lòng đợi...", + "An error occurred while logging in: ": "Đã xảy ra lỗi khi đăng nhập: ", + "Fetching available backups...": "Đang tìm các bản sao lưu có sẵn...", + "Done!": "Xong!", + "The cloud backup has been loaded successfully.": "Bản sao lưu trên đám mây đã được tải thành công.", + "An error occurred while loading a backup: ": "Đã xảy ra lỗi khi tải bản sao lưu: ", + "Backing up packages to GitHub Gist...": "Đang sao lưu các gói lên GitHub Gist...", + "Backup Successful": "Sao lưu thành công", + "The cloud backup completed successfully.": "Sao lưu lên đám mây đã hoàn tất thành công.", + "Could not back up packages to GitHub Gist: ": "Không thể sao lưu các gói lên GitHub Gist:", + "It is not guaranteed that the provided credentials will be stored safely, so you may as well not use the credentials of your bank account": "Không đảm bảo rằng thông tin xác thực được cung cấp sẽ được lưu trữ an toàn, vì vậy bạn không nên sử dụng thông tin xác thực của tài khoản ngân hàng của mình", + "Enable the automatic WinGet troubleshooter": "Kích hoạt trình khắc phục sự cố WinGet tự động", + "Add updates that fail with a 'no applicable update found' to the ignored updates list": "Thêm các bản cập nhật bị lỗi với thông báo \"không tìm thấy bản cập nhật phù hợp\" vào danh sách cập nhật bị bỏ qua", + "Invalid selection": "Lựa chọn không hợp lệ", + "No package was selected": "Không có gói nào được chọn", + "More than 1 package was selected": "Đã chọn nhiều hơn 1 gói", + "List": "Danh sách", + "Grid": "Lưới", + "Icons": "Các biểu tượng", + "\"{0}\" is a local package and does not have available details": "\"{0}\" là một gói cục bộ và không có chi tiết sẵn có", + "\"{0}\" is a local package and is not compatible with this feature": "\"{0}\" là một gói cục bộ và không tương thích với tính năng này", + "Add packages to bundle": "Thêm gói hàng vào bộ sản phẩm", + "Preparing packages, please wait...": "Đang chuẩn bị gói, vui lòng đợi...", + "Loading packages, please wait...": "Đang tải gói, vui lòng đợi...", + "Saving packages, please wait...": "Đang lưu gói, vui lòng đợi...", + "The bundle was created successfully on {0}": "Gói tổng hợp đã được tạo thành công tại {0}", + "User profile": "Hồ sơ người dùng", + "Error": "Lỗi", + "Log in failed: ": "Đăng nhập thất bại:", + "Log out failed: ": "Đăng xuất thất bại:", + "Package backup settings": "Cài đặt sao lưu gói", + "Package managers": "Các trình quản lý gói", + "Manage UniGetUI autostart behaviour from the Settings app": "Quản lý hành vi tự khởi động của UniGetUI", + "Choose how many operations shoulds be performed in parallel": "Chọn số thao tác nên được thực hiện song song", + "Something went wrong while launching the updater.": "Đã xảy ra sự cố khi khởi động trình cập nhật.", + "Please try again later": "Vui lòng thử lại sau", + "Show the release notes after UniGetUI is updated": "Hiển thị ghi chú phát hành sau khi UniGetUI được cập nhật" +} diff --git a/src/Languages/lang_zh_CN.json b/src/Languages/lang_zh_CN.json new file mode 100644 index 0000000..8f16f8e --- /dev/null +++ b/src/Languages/lang_zh_CN.json @@ -0,0 +1,850 @@ +{ + "{0} of {1} operations completed": "已完成 {1} 项操作中的 {0} 项", + "{0} is now {1}": "{0} 现在是 {1}", + "Enabled": "已启用", + "Disabled": "已禁用", + "Privacy": "隐私", + "Hide my username from the logs": "在日志中隐藏我的用户名", + "Replaces your username with **** in the logs. Restart UniGetUI to also hide it from already-recorded entries.": "在日志中用 **** 替换您的用户名。重启 UniGetUI 也可将其从已记录的条目中隐藏。", + "Your last update attempt did not complete.": "上次更新尝试未完成。", + "UniGetUI could not confirm whether the update succeeded. Open the log to see what happened.": "UniGetUI 无法确认更新是否成功。打开日志以查看发生了什么。", + "View log": "查看日志", + "The installer reported success but did not restart UniGetUI.": "安装程序报告成功,但未重新启动 UniGetUI。", + "The installer failed to initialize.": "安装程序初始化失败。", + "Setup was canceled before installation began.": "安装开始前已取消安装。", + "A fatal error occurred during the preparation phase.": "准备阶段发生严重错误。", + "A fatal error occurred during installation.": "安装期间发生严重错误。", + "Installation was canceled while in progress.": "安装进行过程中已取消。", + "The installer was terminated by another process.": "安装程序已被另一进程终止。", + "The preparation phase determined the installation cannot proceed.": "准备阶段判定无法继续安装。", + "The installer could not start. UniGetUI may already be running, or you do not have permission to install.": "安装程序无法启动。UniGetUI 可能已在运行,或者您没有安装权限。", + "Unexpected installer error.": "意外的安装程序错误。", + "We are checking for updates.": "正在检查更新", + "Please wait": "请稍候", + "Great! You are on the latest version.": "很好!您有最新版本。", + "There are no new UniGetUI versions to be installed": "没有可安装的新 UniGetUI 版本", + "UniGetUI version {0} is being downloaded.": "正在下载 UniGetUI 版本 {0}", + "This may take a minute or two": "这可能需要一两分钟的时间", + "The installer authenticity could not be verified.": "无法验证安装程序的真实性。", + "The update process has been aborted.": "更新过程已中止。", + "Auto-update is not yet available on this platform.": "此平台尚不支持自动更新。", + "Please update UniGetUI manually.": "请手动更新 UniGetUI。", + "An error occurred when checking for updates: ": "检查更新时出现错误:", + "The updater could not be launched.": "无法启动更新程序。", + "The operating system did not start the installer process.": "操作系统未启动安装程序进程。", + "UniGetUI is being updated...": "正在更新 UniGetUI ...", + "Update installed.": "更新已安装。", + "UniGetUI was updated successfully, but this running copy was not replaced. This usually means you are running a development build. Close this copy and start the newly-installed version to finish.": "UniGetUI 已成功更新,但当前正在运行的副本未被替换。这通常意味着您正在运行开发版本。请关闭此副本并启动新安装的版本以完成更新。", + "The update could not be applied.": "无法应用更新。", + "Installer exit code {0}: {1}": "安装程序退出代码 {0}: {1}", + "Update cancelled.": "更新已取消。", + "Authentication was cancelled.": "身份验证已取消。", + "Installer exit code {0}": "安装程序退出代码 {0}", + "Operation in progress": "操作正在进行中", + "Please wait...": "请稍候……", + "Success!": "成功!", + "Failed": "失败", + "An error occurred while processing this package": "处理此软件包时出现错误", + "Installer": "安装程序", + "Executable": "可执行文件", + "MSI": "MSI", + "Compressed file": "压缩文件", + "MSIX": "MSIX", + "WinGet was repaired successfully": "已成功修复 WinGet", + "It is recommended to restart UniGetUI after WinGet has been repaired": "建议在 WinGet 完成修复之后重新启动 UniGetUI", + "WinGet could not be repaired": "无法修复 WinGet", + "An unexpected issue occurred while attempting to repair WinGet. Please try again later": "尝试修复 WinGet 时出现意外错误。请稍后再试", + "Log in to enable cloud backup": "登录以启用云备份", + "Backup Failed": "备份失败", + "Downloading backup...": "正在下载备份...", + "An update was found!": "发现更新!", + "{0} can be updated to version {1}": "{0} 可更新至版本 {1}", + "Updates found!": "发现更新!", + "{0} packages can be updated": "可以更新 {0} 个软件包", + "{0} is being updated to version {1}": "正在更新 {0} 至版本 {1}", + "{0} packages are being updated": "正在更新 {0} 个软件包", + "You have currently version {0} installed": "您当前已安装版本 {0}", + "Desktop shortcut created": "已创建桌面快捷方式", + "UniGetUI has detected a new desktop shortcut that can be deleted automatically.": "UniGetUI 检测到可以自动删除的新桌面快捷方式。", + "{0} desktop shortcuts created": "已创建 {0} 个桌面快捷方式", + "UniGetUI has detected {0} new desktop shortcuts that can be deleted automatically.": "UniGetUI 已检测到有 {0} 个新的桌面快捷方式可被自动删除。", + "Attention required": "请注意", + "Restart required": "需要重启", + "1 update is available": "有 1 个可用更新", + "{0} updates are available": "{0} 个可用更新", + "Everything is up to date": "所有软件包均已为最新版", + "Discover Packages": "发现软件包", + "Available Updates": "可用更新", + "Installed Packages": "已安装软件包", + "UniGetUI Version {0} by Devolutions": "Devolutions 出品的 UniGetUI 版本 {0}", + "Show UniGetUI": "显示 UniGetUI", + "Quit": "退出", + "Are you sure?": "您确定要进行吗?", + "Do you really want to uninstall {0}?": "您确定要卸载 {0} 吗?", + "Do you really want to uninstall the following {0} packages?": "您确定要卸载以下 {0} 个软件包吗?", + "No": "否", + "Yes": "是", + "Partial": "部分", + "View on UniGetUI": "在 UniGetUI 中查看", + "Update": "更新", + "Open UniGetUI": "打开 UniGetUI", + "Update all": "全部更新", + "Update now": "立刻更新", + "Installer host changed since the installed version.\n": "安装程序主机与已安装版本相比已更改。\n", + "This package is on the queue": "此软件包已在队列中", + "installing": "正在安装", + "updating": "正在更新", + "uninstalling": "正在卸载", + "installed": "已安装", + "Retry": "重试", + "Install": "安装", + "Uninstall": "卸载", + "Open": "打开", + "Operation profile:": "操作配置文件:", + "Follow the default options when installing, upgrading or uninstalling this package": "安装、升级或卸载此软件包时遵循默认选项", + "The following settings will be applied each time this package is installed, updated or removed.": "每次安装、更新或移除此软件包时都会应用以下设置。", + "Version to install:": "安装版本:", + "Architecture to install:": "安装架构:", + "Installation scope:": "安装范围:", + "Install location:": "安装位置:", + "Select": "选择", + "Reset": "重置", + "Custom install arguments:": "自定义安装参数:", + "Custom update arguments:": "自定义更新参数:", + "Custom uninstall arguments:": "自定义卸载参数:", + "Pre-install command:": "安装前命令:", + "Post-install command:": "安装后命令:", + "Abort install if pre-install command fails": "如果安装前命令失败,则中止安装操作", + "Pre-update command:": "更新前命令:", + "Post-update command:": "更新后命令:", + "Abort update if pre-update command fails": "如果更新前命令失败,则中止更新操作", + "Pre-uninstall command:": "卸载前命令:", + "Post-uninstall command:": "卸载后命令:", + "Abort uninstall if pre-uninstall command fails": "如果卸载前命令失败,则中止卸载操作", + "Command-line to run:": "运行命令行:", + "Save and close": "保存并关闭", + "General": "常规", + "Architecture & Location": "架构和位置", + "Command-line": "命令行", + "Close apps": "关闭应用", + "Pre/Post install": "安装前/后", + "Select the processes that should be closed before this package is installed, updated or uninstalled.": "选择在安装、更新或卸载此软件包之前应关闭的进程。", + "Write here the process names here, separated by commas (,)": "在此处写入进程名称,以英文逗号 (,) 分隔", + "Try to kill the processes that refuse to close when requested to": "尝试终止那些在收到关闭请求时拒绝关闭的进程", + "Run as admin": "以管理员身份运行", + "Interactive installation": "交互式安装", + "Skip hash check": "跳过哈希校验", + "Uninstall previous versions when updated": "更新时卸载旧版本", + "Skip minor updates for this package": "忽略此软件包的小幅更新", + "Automatically update this package": "自动更新此软件包", + "{0} installation options": "{0} 安装选项", + "Latest": "最新", + "PreRelease": "预发布", + "Default": "默认", + "Manage ignored updates": "管理已忽略更新", + "The packages listed here won't be taken in account when checking for updates. Double-click them or click the button on their right to stop ignoring their updates.": "检查更新时,此处列出的软件包将会被忽略。双击它们或点击其右侧的按钮可不再忽略其更新。", + "Reset list": "重置列表", + "Do you really want to reset the ignored updates list? This action cannot be reverted": "您确定要重置已忽略更新列表吗?此操作无法撤销", + "No ignored updates": "没有已忽略的更新", + "Package Name": "软件包名称", + "Package ID": "软件包 ID", + "Ignored version": "已忽略版本", + "New version": "新版本", + "Source": "来源", + "All versions": "所有版本", + "Unknown": "未知", + "Up to date": "已是最新", + "Package {name} from {manager}": "来自 {manager} 的软件包 {name}", + "Remove {0} from ignored updates": "从已忽略更新中移除 {0}", + "Cancel": "取消", + "Administrator privileges": "管理员权限", + "This operation is running with administrator privileges.": "此操作正以管理员权限运行。", + "Interactive operation": "交互式操作", + "This operation is running interactively.": "此操作正处于交互式运行。", + "You will likely need to interact with the installer.": "您可能需要与安装程序交互。", + "Integrity checks skipped": "已跳过完整性检查", + "Integrity checks will not be performed during this operation.": "此操作期间不会执行完整性检查。", + "Proceed at your own risk.": "继续进行,风险自负。", + "Close": "关闭", + "Loading...": "正在加载……", + "Installer SHA256": "安装程序 SHA256 值", + "Homepage": "主页", + "Author": "制作者", + "Publisher": "发布者", + "License": "许可证", + "Manifest": "清单", + "Installer Type": "安装类型", + "Size": "尺寸", + "Installer URL": "安装程序网址", + "Last updated:": "最近更新:", + "Release notes URL": "发布说明网址", + "Package details": "软件包详情", + "Dependencies:": "依赖项:", + "Release notes": "发布说明", + "Screenshots": "屏幕截图", + "This package has no screenshots or is missing the icon? Contribute to UniGetUI by adding the missing icons and screenshots to our open, public database.": "此软件包没有屏幕截图或缺少图标?您可以为 UniGetUI 作出贡献,将缺失的图标和屏幕截图添加到我们的开放公共数据库中。", + "Version": "版本", + "Install as administrator": "以管理员身份安装", + "Update to version {0}": "更新至版本 {0}", + "Installed Version": "已安装版本", + "Update as administrator": "以管理员身份更新", + "Interactive update": "交互式更新", + "Uninstall as administrator": "以管理员身份卸载", + "Interactive uninstall": "交互式卸载", + "Uninstall and remove data": "卸载并移除数据", + "Not available": "无法获取", + "Installer SHA512": "安装程序 SHA512 值", + "Unknown size": "未知大小", + "No dependencies specified": "未指定依赖项", + "mandatory": "强制", + "optional": "可选", + "UniGetUI {0} is ready to be installed.": "已准备好安装 UniGetUI {0}", + "The update process will start after closing UniGetUI": "更新过程将在 UniGetUI 关闭后开始", + "UniGetUI has been ran as administrator, which is not recommended. When running UniGetUI as administrator, EVERY operation launched from UniGetUI will have administrator privileges. You can still use the program, but we highly recommend not running UniGetUI with administrator privileges.": "UniGetUI 已以管理员身份运行,但这并不推荐。以管理员身份运行 UniGetUI 时,从 UniGetUI 启动的每一项操作都将拥有管理员权限。您仍然可以继续使用该程序,但我们强烈建议不要以管理员权限运行 UniGetUI。", + "Share anonymous usage data": "共享匿名使用数据", + "UniGetUI collects anonymous usage data in order to improve the user experience.": "UniGetUI 收集匿名使用数据,以改善用户体验。", + "Accept": "接受", + "Software Updates": "软件更新", + "Package Bundles": "软件捆绑包", + "Settings": "设置", + "Package Managers": "软件包管理器", + "UniGetUI Log": "UniGetUI 日志", + "Package Manager logs": "软件包管理器日志", + "Operation history": "操作历史", + "Help": "帮助", + "UniGetUI": "UniGetUI", + "You have installed UniGetUI Version {0}": "您已安装 UniGetUI 版本 {0} ", + "Disclaimer": "免责声明", + "UniGetUI is developed by Devolutions and is not affiliated with any of the compatible package managers.": "UniGetUI 由 Devolutions 开发,与任何兼容的软件包管理器均无关联。", + "UniGetUI wouldn't have been possible without the help of the contributors. Thank you all 🥳": "如果没有众多贡献者的帮助,UniGetUI 是不可能实现的。感谢大家 🥳", + "UniGetUI uses the following libraries. Without them, UniGetUI wouldn't have been possible.": "UniGetUI 使用以下库。如果没有它们,UniGetUI 将不可能实现。", + "{0} homepage": "{0} 主页", + "UniGetUI has been translated to more than 40 languages thanks to the volunteer translators. Thank you 🤝": "UniGetUI 已经由志愿翻译人员翻译成了 40 多种语言,感谢他们的辛勤工作!🤝", + "Verbose": "详情", + "1 - Errors": "1 - 错误", + "2 - Warnings": "2 - 警告", + "3 - Information (less)": "3 - 信息(简要)", + "4 - Information (more)": "4 - 信息(详情)", + "5 - information (debug)": "5 - 信息(调试)", + "Warning": "警告", + "The following settings may pose a security risk, hence they are disabled by default.": "以下设置可能存在安全风险,因此默认被禁用。", + "Enable the settings below if and only if you fully understand what they do, and the implications they may have.": "只有在您完全了解以下设置的作用及其可能产生的影响时,才应启用这些设置。", + "The settings will list, in their descriptions, the potential security issues they may have.": "这些设置将在其描述中列出潜在的安全问题。", + "The backup will include the complete list of the installed packages and their installation options. Ignored updates and skipped versions will also be saved.": "备份将包含已安装软件包及其安装选项的完整列表。已忽略的更新和跳过的版本也将被保存。", + "The backup will NOT include any binary file nor any program's saved data.": "备份将不包含任何二进制文件或任何程序的已保存数据。", + "The size of the backup is estimated to be less than 1MB.": "备份的大小预计小于 1MB 。", + "The backup will be performed after login.": "备份将在登录后执行", + "{pcName} installed packages": "{pcName} 已安装软件包", + "Current status: Not logged in": "当前状态:未登录", + "You are logged in as {0} (@{1})": "你以 {0}(@{1})的身份登录", + "Nice! Backups will be uploaded to a private gist on your account": "很好!备份将上传到您账户上的一个私有 Gist。", + "Select backup": "选择备份", + "Settings imported from {0}": "已从 {0} 导入设置", + "UniGetUI Settings": "UniGetUI 设置", + "Settings exported to {0}": "已将设置导出至 {0}", + "UniGetUI settings were reset": "UniGetUI 设置已重置", + "Allow pre-release versions": "允许预发布版本", + "Apply": "应用", + "For security reasons, custom command-line arguments are disabled by default. Go to UniGetUI security settings to change this.": "出于安全原因,自定义命令行参数默认处于禁用状态。前往 UniGetUI 安全设置可更改此项。", + "Go to UniGetUI security settings": "前往 UniGetUI 安全设置", + "The following options will be applied by default each time a {0} package is installed, upgraded or uninstalled.": "每次安装、升级或卸载 {0} 软件包时,将默认应用以下选项。", + "Package's default": "软件包默认", + "Install location can't be changed for {0} packages": "{0} 软件包的安装位置无法更改", + "The local icon cache currently takes {0} MB": "本地图标缓存当前占用了 {0} MB", + "Username": "用户名", + "Password": "密码", + "Credentials": "凭据", + "It is not guaranteed that the provided credentials will be stored safely": "无法保证所提供的凭据会被安全存储", + "Partially": "部分", + "Package manager": "软件包管理器", + "Compatible with proxy": "兼容代理", + "Compatible with authentication": "兼容身份验证", + "Proxy compatibility table": "代理兼容表", + "{0} settings": "{0} 设置", + "{0} status": "{0} 状态", + "Default installation options for {0} packages": "{0} 程序包的默认安装选项", + "Expand version": "查看版本", + "The executable file for {0} was not found": "找不到 {0} 的可执行文件", + "{pm} is disabled": "{pm} 已禁用", + "Enable it to install packages from {pm}.": "启用它可从 {pm} 安装软件包。", + "{pm} is enabled and ready to go": "{pm} 已启用且准备就绪", + "{pm} version:": "{pm} 版本:", + "{pm} was not found!": "找不到 {pm}!", + "You may need to install {pm} in order to use it with UniGetUI.": "您可能需要安装 {pm} 才能将其与 UniGetUI 一起使用。 ", + "Scoop Installer - UniGetUI": "Scoop 安装程序 - UniGetUI", + "Scoop Uninstaller - UniGetUI": "Scoop 卸载程序 - UniGetUI", + "Clearing Scoop cache - UniGetUI": "清理 Scoop 缓存 - UniGetUI", + "Restart UniGetUI to fully apply changes": "重启 UniGetUI 以完全应用更改", + "Restart UniGetUI": "重启 UniGetUI", + "Manage {0} sources": "管理 {0} 安装源", + "Add source": "添加安装源", + "Add": "添加", + "Source name": "源名称", + "Source URL": "源 URL", + "Other": "其它", + "No minimum age": "无最短时长", + "1 day": "1 天", + "{0} days": "{0} 天", + "Custom...": "自定义...", + "{0} minutes": "{0} 分钟", + "1 hour": "1 小时", + "{0} hours": "{0} 小时", + "1 week": "1 周", + "Supports release dates": "支持发布日期", + "Release date support per package manager": "各软件包管理器的发布日期支持情况", + "Search for packages": "搜索软件包", + "Local": "本地", + "OK": "确定", + "Last checked: {0}": "上次检查:{0}", + "{0} packages were found, {1} of which match the specified filters.": "已找到 {0} 个软件包,其中 {1} 个与指定的筛选器匹配。", + "{0} selected": "{0} 选中", + "(Last checked: {0})": "(上一次检查的时间:{0})", + "All packages selected": "已选择所有软件包", + "Package selection cleared": "已清除软件包选择", + "{0}: {1}": "{0}:{1}", + "More info": "更多信息", + "GitHub account": "GitHub 账户", + "Log in with GitHub to enable cloud package backup.": "用 GitHub 登录以启用云软件包备份。", + "More details": "更多详情", + "Log in": "登录", + "If you have cloud backup enabled, it will be saved as a GitHub Gist on this account": "如果你启用了云备份,它将作为 GitHub Gist 保存到该账户中", + "Log out": "注销", + "About UniGetUI": "关于 UniGetUI", + "About": "关于", + "Third-party licenses": "第三方许可证", + "Contributors": "贡献者", + "Translators": "翻译人员", + "Bundle security report": "捆绑包安全报告", + "The bundle contained restricted content": "该捆绑包包含受限内容", + "UniGetUI – Crash Report": "UniGetUI – 崩溃报告", + "UniGetUI has crashed": "UniGetUI 已崩溃", + "Help us fix this by sending a crash report to Devolutions. All fields below are optional.": "通过向 Devolutions 发送崩溃报告来帮助我们修复此问题。以下所有字段均为可选。", + "Email (optional)": "电子邮件(可选)", + "your@email.com": "your@email.com", + "Additional details (optional)": "补充说明(可选)", + "Describe what you were doing when the crash occurred…": "请描述崩溃发生时您正在进行的操作……", + "Crash report": "崩溃报告", + "Don't Send": "不发送", + "Send Report": "发送报告", + "Sending…": "正在发送……", + "Unsaved changes": "未保存的更改", + "You have unsaved changes in the current bundle. Do you want to discard them?": "当前捆绑包中有未保存的更改。您要放弃它们吗?", + "Discard changes": "放弃更改", + "Integrity violation": "完整性违规", + "UniGetUI or some of its components are missing or corrupt. It is strongly recommended to reinstall UniGetUI to adress the situation.": "UniGetUI 或其某些组件缺失或已损坏。强烈建议重新安装 UniGetUI 以解决此问题。", + "• Refer to the UniGetUI Logs to get more details regarding the affected file(s)": "• 参考 UniGetUI 日志可获取有关受影响文件的更多详细信息。", + "• Integrity checks can be disabled from the Experimental Settings": "• 可以在“实验设置”中禁用完整性检查", + "Manage shortcuts": "管理快捷方式", + "UniGetUI has detected the following desktop shortcuts which can be removed automatically on future upgrades": "UniGetUI 检测到以下会在未来升级时自动删除的快捷方式", + "Do you really want to reset this list? This action cannot be reverted.": "你确定想重置此列表吗?此操作无法撤销。", + "Desktop shortcuts list": "桌面快捷方式列表", + "Open in explorer": "在文件资源管理器中打开", + "Remove from list": "从列表中删除", + "When new shortcuts are detected, delete them automatically instead of showing this dialog.": "当检测到新的快捷方式时自动删除它们,而不显示此对话框。", + "Not right now": "不是现在", + "Missing dependency": "缺少依赖项", + "UniGetUI requires {0} to operate, but it was not found on your system.": "UniGetUI 需要 {0} 才能运行,但在您的系统中找不到它。", + "Click on Install to begin the installation process. If you skip the installation, UniGetUI may not work as expected.": "点击安装可开始安装进程。如果您跳过安装步骤,UniGetUI 可能不会正常工作。", + "Alternatively, you can also install {0} by running the following command in a Windows PowerShell prompt:": "另外,您也可以在 Windows PowerShell 提示符中运行以下命令来安装 {0}:", + "Install {0}": "安装 {0}", + "Do not show this dialog again for {0}": "不再为 {0} 显示此对话框", + "Please wait while {0} is being installed. A black window may show up. Please wait until it closes.": "在安装 {0} 时请等待。可能会显示一个黑色窗口。请等待它自己关闭。", + "{0} has been installed successfully.": "已成功安装 {0} 。", + "Please click on \"Continue\" to continue": "请点击“继续”执行后续操作", + "Continue": "继续", + "{0} has been installed successfully. It is recommended to restart UniGetUI to finish the installation": "已成功安装 {0} 。建议重启 UniGetUI 以便完成此次安装", + "Restart later": "稍后重启", + "An error occurred:": "出现错误:", + "Please see the Command-line Output or refer to the Operation History for further information about the issue.": "有关此问题的更多信息,请查看命令行输出或参考操作历史记录。", + "Retry as administrator": "以管理员身份重试", + "Retry interactively": "交互式重试", + "Retry skipping integrity checks": "尝试跳过完整性检查", + "Installation options": "安装选项", + "Save": "保存", + "UniGetUI collects anonymous usage data with the sole purpose of understanding and improving the user experience.": "UniGetUI 收集匿名使用数据的唯一目的是了解和改善用户体验。", + "More details about the shared data and how it will be processed": "有关共享数据及其处理方式的更多详细信息", + "Do you accept that UniGetUI collects and sends anonymous usage statistics, with the sole purpose of understanding and improving the user experience?": "您是否允许 UniGetUI 收集和发送匿名使用统计数据?其唯一目的是了解和改善用户体验", + "Decline": "拒绝", + "No personal information is collected nor sent, and the collected data is anonimized, so it can't be back-tracked to you.": "个人信息不会被收集也不会被发送,且收集的数据都已被匿名化,因此无法通过它们回溯到您。", + "Navigation panel": "导航面板", + "Operations": "操作", + "Toggle operations panel": "切换操作面板", + "Bulk operations": "批量操作", + "Retry failed": "重试失败项", + "Clear successful": "清除成功项", + "Clear finished": "清除已完成项", + "Cancel all": "全部取消", + "More": "更多", + "Toggle navigation panel": "切换导航面板", + "Minimize": "最小化", + "Maximize": "最大化", + "UniGetUI by Devolutions": "Devolutions 出品的 UniGetUI", + "UniGetUI is an application that makes managing your software easier, by providing an all-in-one graphical interface for your command-line package managers.": "UniGetUI 应用程序为您基于命令行的软件包管理器提供了一体化图形界面,使得管理软件变得更容易。", + "Useful links": "帮助链接", + "UniGetUI Homepage": "UniGetUI 主页", + "Report an issue or submit a feature request": "报告问题或者提交功能请求", + "UniGetUI Repository": "UniGetUI 仓库", + "View GitHub Profile": "查看 GitHub 个人资料", + "UniGetUI License": "UniGetUI 许可证", + "Using UniGetUI implies the acceptation of the MIT License": "使用 UniGetUI 意味着接受 MIT 许可证 ", + "Become a translator": "成为翻译人员", + "Go back": "后退", + "Go forward": "前进", + "Go to home page": "转到主页", + "Reload page": "重新加载页面", + "View page on browser": "在浏览器中查看页面", + "The built-in browser is not supported on Linux yet.": "内置浏览器尚不支持 Linux。", + "Open in browser": "在浏览器中打开", + "Copy to clipboard": "复制到剪贴板", + "Export to a file": "导出到文件", + "Log level:": "日志级别:", + "Reload log": "重载日志", + "Export log": "导出日志", + "Text": "文本", + "Change how operations request administrator rights": "更改操作请求管理员权限的方式", + "Restrictions on package operations": "对软件包操作的限制", + "Restrictions on package managers": "对软件包管理器的限制", + "Restrictions when importing package bundles": "导入软件捆绑包时的限制", + "Ask for administrator privileges once for each batch of operations": "每批操作请求一次管理员权限", + "Ask only once for administrator privileges": "仅请求一次管理员权限", + "Prohibit any kind of Elevation via UniGetUI Elevator or GSudo": "禁止任何通过 UniGetUI Elevator 或 GSudo 的提权操作", + "This option WILL cause issues. Any operation incapable of elevating itself WILL FAIL. Install/update/uninstall as administrator will NOT WORK.": "此选项会导致一些问题。任何无法自行提升权限的操作都将失败。以管理员身份进行安装/更新/卸载将不起作用。", + "Allow custom command-line arguments": "允许自定义命令行参数", + "Custom command-line arguments can change the way in which programs are installed, upgraded or uninstalled, in a way UniGetUI cannot control. Using custom command-lines can break packages. Proceed with caution.": "自定义命令行参数将以 UniGetUI 无法控制的方式更改程序的安装、升级或卸载方式。使用自定义命令行可能会损坏软件包。请谨慎操作。", + "Ignore custom pre-install and post-install commands when importing packages from a bundle": "允许运行自定义预安装和安装后命令", + "Pre and post install commands will be run before and after a package gets installed, upgraded or uninstalled. Be aware that they may break things unless used carefully": "安装前和安装后命令将在软件包安装、升级或卸载之前和之后运行。请谨慎使用,这些命令可能会导致问题。", + "Allow changing the paths for package manager executables": "允许更改软件包管理器执行文件的路径", + "Turning this on enables changing the executable file used to interact with package managers. While this allows finer-grained customization of your install processes, it may also be dangerous": "启用此功能后,可更改用于与软件包管理器交互的可执行文件。虽然这能让您对安装过程进行更细致的自定义,但也可能存在风险。 ", + "Allow importing custom command-line arguments when importing packages from a bundle": "从捆绑包导入软件包时允许导入自定义命令行参数", + "Malformed command-line arguments can break packages, or even allow a malicious actor to gain privileged execution. Therefore, importing custom command-line arguments is disabled by default": "格式错误的命令行参数可能导致软件包受损,甚至使恶意攻击者获得特权执行权限。因此,默认情况下禁止导入自定义命令行参数。", + "Allow importing custom pre-install and post-install commands when importing packages from a bundle": "从捆绑包导入软件包时,允许导入自定义的安装前和安装后命令", + "Pre and post install commands can do very nasty things to your device, if designed to do so. It can be very dangerous to import the commands from a bundle, unless you trust the source of that package bundle": "预安装与安装后命令可被设计用于执行恶意行为,从而严重危害您的设备。导入来自未知软件包的此类命令极度危险,请务必确保其来源可信。", + "Administrator rights and other dangerous settings": "管理员权限和其它存在风险的设置", + "Package backup": "软件包备份", + "Cloud package backup": "云软件包备份", + "Local package backup": "本地软件包备份", + "Local backup advanced options": "本地备份高级选项", + "Log in with GitHub": "用 GitHub 登录", + "Log out from GitHub": "从 GitHub 注销", + "Periodically perform a cloud backup of the installed packages": "定期对已安装的软件包执行云备份", + "Cloud backup uses a private GitHub Gist to store a list of installed packages": "云备份使用私有 GitHub Gist 来存储已安装软件包的列表", + "Perform a cloud backup now": "立即执行云备份", + "Backup": "备份", + "Restore a backup from the cloud": "从云端还原备份", + "Begin the process to select a cloud backup and review which packages to restore": "启动选择云备份并查看要还原哪些软件包的流程", + "Periodically perform a local backup of the installed packages": "定期对已安装的软件包执行本地备份", + "Perform a local backup now": "立即执行本地备份", + "Change backup output directory": "更改备份输出文件夹", + "Set a custom backup file name": "设置一个自定义备份文件名", + "Leave empty for default": "选择默认路径请留空", + "Add a timestamp to the backup file names": "在备份文件名中添加时间戳", + "Backup and Restore": "备份和还原", + "Enable background api (UniGetUI Widgets and Sharing, port 7058)": "启用后台 API(用于 UniGetUI 小组件与分享,端口 7058)", + "Wait for the device to be connected to the internet before attempting to do tasks that require internet connectivity.": "在尝试执行需要互联网连接的任务前,请先等待设备连接到互联网。", + "Disable the 1-minute timeout for package-related operations": "禁用软件包相关操作的 1 分钟超时", + "Use installed GSudo instead of UniGetUI Elevator": "使用已安装的 GSudo ,而不是 UniGetUI Elevator", + "Use a custom icon and screenshot database URL": "使用自定义图标和截图数据库网址", + "Enable background CPU Usage optimizations (see Pull Request #3278)": "启用后台 CPU 使用优化(详见 Pull Request #3278)", + "Perform integrity checks at startup": "启动时执行完整性检查", + "When batch installing packages from a bundle, install also packages that are already installed": "从捆绑包中批量安装软件包时,也安装已安装的软件包", + "Experimental settings and developer options": "实验性设置和开发者选项", + "Show UniGetUI's version and build number on the titlebar.": "在标题栏上显示 UniGetUI 的版本和构建编号", + "Language": "语言", + "UniGetUI updater": "UniGetUI 更新程序", + "Telemetry": "遥测", + "Manage UniGetUI settings": "管理 UniGetUI 设置", + "Related settings": "相关设置", + "Update UniGetUI automatically": "自动更新 UniGetUI", + "Check for updates": "检查更新", + "Install prerelease versions of UniGetUI": "安装 UniGetUI 的预发布版本", + "Manage telemetry settings": "管理遥测设置", + "Manage": "管理", + "Import settings from a local file": "从本地文件导入设置", + "Import": "导入", + "Export settings to a local file": "导出设置到本地文件", + "Export": "导出", + "Reset UniGetUI": "重置 UniGetUI", + "User interface preferences": "用户界面首选项", + "Application theme, startup page, package icons, clear successful installs automatically": "应用程序主题、起始页、软件包图标、自动清除安装成功的记录", + "General preferences": "通用首选项", + "UniGetUI display language:": "UniGetUI 显示语言:", + "System language": "系统语言", + "Is your language missing or incomplete?": "您的语言翻译是否缺失或不完整? ", + "Appearance": "外观", + "UniGetUI on the background and system tray": "UniGetUI 位于后台和系统托盘", + "Package lists": "软件包列表", + "Use classic mode": "使用经典模式", + "Restart UniGetUI to apply this change": "重启 UniGetUI 以应用此更改", + "The classic UI is disabled for beta testers": "经典 UI 已对测试版测试人员禁用", + "Close UniGetUI to the system tray": "关闭 UniGetUI 时将它隐藏到系统托盘", + "Manage UniGetUI autostart behaviour": "管理 UniGetUI 自动启动行为", + "Show package icons on package lists": "在软件包列表中显示软件包图标", + "Clear cache": "清除缓存", + "Select upgradable packages by default": "默认选择可升级软件包", + "Light": "浅色", + "Dark": "深色", + "Follow system color scheme": "跟随系统颜色方案", + "Application theme:": "应用程序主题:", + "UniGetUI startup page:": "UniGetUI 启动页面:", + "Proxy settings": "代理设置", + "Other settings": "其它设置", + "Connect the internet using a custom proxy": "使用自定义代理连接互联网", + "Please note that not all package managers may fully support this feature": "请注意,并非所有的软件包管理器都能完全支持此功能", + "Proxy URL": "代理网址", + "Enter proxy URL here": "在此输入代理网址", + "Authenticate to the proxy with a user and a password": "使用用户名和密码对代理进行身份验证", + "Internet and proxy settings": "网络和代理设置", + "Package manager preferences": "软件包管理器首选项", + "Ready": "就绪", + "Not found": "未找到", + "Notification preferences": "通知首选项", + "Notification types": "通知类型", + "The system tray icon must be enabled in order for notifications to work": "必须启用系统托盘图标才能让通知生效", + "Enable UniGetUI notifications": "启用 UniGetUI 的通知", + "Show a notification when there are available updates": "有可用更新时推送通知", + "Show a silent notification when an operation is running": "当操作正在运行时显示一个静默通知", + "Show a notification when an operation fails": "当操作失败时显示通知", + "Show a notification when an operation finishes successfully": "当操作成功完成时显示通知", + "Concurrency and execution": "并发与执行", + "Automatic desktop shortcut remover": "桌面快捷方式自动删除程序", + "Choose how many operations should be performed in parallel": "选择并行执行的操作数量", + "Clear successful operations from the operation list after a 5 second delay": "延迟 5 秒后从操作列表中清除成功的操作", + "Download operations are not affected by this setting": "此设置不影响下载操作", + "You may lose unsaved data": "你可能会丢失未保存的数据", + "Ask to delete desktop shortcuts created during an install or upgrade.": "安装或升级期间询问是否要删除创建的桌面快捷方式。", + "Package update preferences": "软件包更新首选项", + "Update check frequency, automatically install updates, etc.": "更新检查频率、自动安装更新等", + "Reduce UAC prompts, elevate installations by default, unlock certain dangerous features, etc.": "减少用户账户控制(UAC)提示,默认提升安装权限,解锁某些危险功能等。", + "Package operation preferences": "软件包操作首选项", + "Enable {pm}": "启用 {pm}", + "Not finding the file you are looking for? Make sure it has been added to path.": "找不到您要找的文件?请确保已将其添加到路径中。", + "Select the executable to be used. The following list shows the executables found by UniGetUI": "选择要使用的可执行文件。以下列表显示了 UniGetUI 找到的可执行文件", + "For security reasons, changing the executable file is disabled by default": "出于安全原因,默认禁用更改可执行文件", + "Change this": "更改", + "Copy path": "复制路径", + "Current executable file:": "当前可执行文件:", + "Ignore packages from {pm} when showing a notification about updates": "在显示更新通知时忽略来自 {pm} 的软件包", + "Update security": "更新安全设置", + "Use global setting": "使用全局设置", + "Minimum age for updates": "更新最短时长", + "e.g. 10": "例如 10", + "Custom minimum age (days)": "自定义最短时长(天)", + "{pm} does not provide release dates for its packages, so this setting will have no effect": "{pm} 不为其软件包提供发布日期,因此此设置不会生效", + "{pm} only provides release dates for some of its packages, so this setting will only apply to those packages": "{pm} 仅为部分软件包提供发布日期,因此此设置将只对那些软件包生效", + "Override the global minimum update age for this package manager": "为此软件包管理器覆盖全局最短更新时间", + "View {0} logs": "查看 {0} 日志", + "If Python cannot be found or is not listing packages but is installed on the system, ": "如果找不到 Python,或者系统中已安装 Python 但无法列出软件包, ", + "Advanced options": "高级选项", + "WinGet command-line tool": "WinGet 命令行工具", + "Choose which command-line tool UniGetUI uses for WinGet operations when the COM API is not used": "选择当不使用 COM API 时 UniGetUI 用于 WinGet 操作的命令行工具", + "WinGet COM API": "WinGet COM API", + "Choose whether UniGetUI can use the WinGet COM API before falling back to the command-line tool": "选择 UniGetUI 是否可以先使用 WinGet COM API,然后再回退到命令行工具", + "Reset WinGet": "重置 WinGet", + "This may help if no packages are listed": "未列出任何软件包时此选项可能有帮助", + "Force install location parameter when updating packages with custom locations": "更新软件包时强制安装位置参数使用自定义位置", + "Install Scoop": "安装 Scoop", + "Uninstall Scoop (and its packages)": "卸载 Scoop(及其软件包)", + "Run cleanup and clear cache": "运行清理并清除缓存", + "Run": "运行", + "Enable Scoop cleanup on launch": "打开程序时清理 Scoop", + "Default vcpkg triplet": "默认 vcpkg triplet", + "Change vcpkg root location": "更改 vcpkg 根目录位置", + "Reset vcpkg root location": "重置 vcpkg 根目录位置", + "Open vcpkg root location": "打开 vcpkg 根目录位置", + "Language, theme and other miscellaneous preferences": "语言、主题和其它首选项", + "Show notifications on different events": "显示各种事件的通知", + "Change how UniGetUI checks and installs available updates for your packages": "更改 UniGetUI 检查和安装软件包可用更新的方式", + "Automatically save a list of all your installed packages to easily restore them.": "自动保存所有已安装软件的列表以便于恢复它们。", + "Enable and disable package managers, change default install options, etc.": "启用和禁用软件包管理器、更改默认安装选项等。", + "Internet connection settings": "互联网连接设置", + "Proxy settings, etc.": "代理设置等", + "Beta features and other options that shouldn't be touched": "测试版功能和其它不建议更改的选项", + "Reload sources": "重新加载来源", + "Delete source": "删除来源", + "Known sources": "已知来源", + "Update checking": "更新检查", + "Automatic updates": "自动更新", + "Check for package updates periodically": "定期检查软件包更新", + "Check for updates every:": "更新检查间隔:", + "Install available updates automatically": "自动安装可用更新", + "Do not automatically install updates when the network connection is metered": "网络连接为按流量计费时,请勿自动安装更新", + "Do not automatically install updates when the device runs on battery": "设备使用电池供电时不自动安装更新", + "Do not automatically install updates when the battery saver is on": "开启省电模式时,请勿自动安装更新", + "Only show updates that are at least the specified number of days old": "仅显示至少已发布指定天数的更新", + "Warn me when the installer URL host changes between the installed version and the new version (WinGet only)": "当安装程序 URL 主机在已安装版本和新版本之间发生变化时警告我(仅 WinGet)", + "Change how UniGetUI handles install, update and uninstall operations.": "更改 UniGetUI 处理安装、更新和卸载操作的方式。", + "Navigation": "导航", + "Check for UniGetUI updates": "检查 UniGetUI 更新", + "Quit UniGetUI": "退出 UniGetUI", + "Filters": "筛选器", + "Sources": "来源", + "Search for packages to start": "从搜索软件包开始", + "Select all": "全选", + "Clear selection": "清除已选", + "Instant search": "实时搜索", + "Distinguish between uppercase and lowercase": "区分大小写", + "Ignore special characters": "忽略特殊字符", + "Search mode": "搜索模式", + "Both": "软件包名称或 ID", + "Exact match": "精确匹配", + "Show similar packages": "显示相似软件包", + "Loading": "正在加载", + "Package": "软件包", + "More options": "更多选项", + "Order by:": "排序", + "Name": "名称", + "Id": "ID", + "Ascendant": "升序", + "Descendant": "降序", + "View modes": "视图模式", + "Reload": "重新加载", + "Closed": "已关闭", + "Ascending": "升序", + "Descending": "降序", + "{0}: {1}, {2}": "{0}:{1},{2}", + "Order by": "排序方式", + "No results were found matching the input criteria": "未找到与输入条件匹配的结果", + "No packages were found": "未找到软件包", + "Loading packages": "正在加载软件包", + "Skip integrity checks": "跳过完整性检查", + "Download selected installers": "下载选定的安装程序", + "Install selection": "安装所选项", + "Install options": "安装选项", + "Add selection to bundle": "添加所选项进捆绑包", + "Download installer": "下载安装程序", + "Uninstall selection": "卸载所选项", + "Uninstall options": "卸载选项", + "Ignore selected packages": "忽略所选软件包", + "Open install location": "打开安装位置", + "Reinstall package": "重新安装软件包", + "Uninstall package, then reinstall it": "卸载并重新安装软件包", + "Ignore updates for this package": "忽略此软件包的更新", + "WinGet malfunction detected": "检测到 WinGet 发生故障", + "It looks like WinGet is not working properly. Do you want to attempt to repair WinGet?": "看来 WinGet 工作不正常。您想尝试修复 WinGet 吗?", + "Repair WinGet": "修复 WinGet", + "Updates will no longer be ignored for {0}": "将不再忽略 {0} 的更新", + "Updates are now ignored for {0}": "已忽略 {0} 的更新", + "Do not ignore updates for this package anymore": "不再忽略此软件包的更新", + "Add packages or open an existing package bundle": "添加软件包或打开一个已有的捆绑包", + "Add packages to start": "从添加软件包开始", + "The current bundle has no packages. Add some packages to get started": "当前捆绑包中还没有软件包。先添加一些软件包吧", + "New": "新建", + "Save as": "另存为", + "Create .ps1 script": "创建 .ps1 脚本", + "Remove selection from bundle": "移除捆绑包中所选项", + "Skip hash checks": "跳过哈希检验", + "The package bundle is not valid": "软件捆绑包无效", + "The bundle you are trying to load appears to be invalid. Please check the file and try again.": "您尝试载入的捆绑包似乎无效。请检查此文件然后再试。", + "Package bundle": "软件捆绑包", + "Could not create bundle": "无法创建捆绑包", + "The package bundle could not be created due to an error.": "无法创建软件捆绑包,发生了错误。", + "Install script": "安装脚本", + "PowerShell script": "PowerShell 脚本", + "The installation script saved to {0}": "安装脚本已保存至 {0}", + "An error occurred": "出现错误", + "An error occurred while attempting to create an installation script:": "尝试创建安装脚本时出错:", + "Hooray! No updates were found.": "好极了!没有待更新的软件!", + "Uninstall selected packages": "卸载所选软件包", + "Update selection": "更新所选项", + "Update options": "更新选项", + "Uninstall package, then update it": "卸载并更新软件包", + "Uninstall package": "卸载软件包", + "Skip this version": "跳过此版本", + "Pause updates for": "暂停更新:", + "User | Local": "用户 | 本地", + "Machine | Global": "计算机 | 全局", + "The default package manager for Debian/Ubuntu-based Linux distributions.
Contains: Debian/Ubuntu packages": "适用于基于 Debian/Ubuntu 的 Linux 发行版的默认包管理器。
包含:Debian/Ubuntu 软件包", + "The Rust package manager.
Contains: Rust libraries and programs written in Rust": "Rust 的软件包管理器。
包含:Rust 库和用 Rust 编写的程序", + "The classical package manager for windows. You'll find everything there.
Contains: General Software": "Windows 的经典软件包管理器。您可以在其中找到所有需要的东西。
包括:通用软件", + "The default package manager for RHEL/Fedora-based Linux distributions.
Contains: RPM packages": "适用于基于 RHEL/Fedora 的 Linux 发行版的默认包管理器。
包含:RPM 软件包", + "A repository full of tools and executables designed with Microsoft's .NET ecosystem in mind.
Contains: .NET related tools and scripts": "一个含有所有为微软 .NET 生态设计的工具和可执行程序的存储库。
包括:与 .NET 相关的工具和脚本\n", + "The universal Linux package manager for desktop applications.
Contains: Flatpak applications from configured remotes": "适用于桌面应用程序的通用 Linux 软件包管理器。
包含:来自已配置远程源的 Flatpak 应用程序", + "NuPkg (zipped manifest)": "NuPkg(压缩清单)", + "The Missing Package Manager for macOS (or Linux).
Contains: Formulae, Casks": "macOS(或 Linux)缺失的软件包管理器。
包含:Formulae、Casks", + "Node JS's package manager. Full of libraries and other utilities that orbit the javascript world
Contains: Node javascript libraries and other related utilities": "Node JS 的软件包管理器。其中包含大量库和其它实用程序,为 JavaScript 世界增添色彩
包括:Node JavaScript 库和其他相关实用程序。", + "The default package manager for Arch Linux and its derivatives.
Contains: Arch Linux packages": "适用于 Arch Linux 及其衍生发行版的默认包管理器。
包含:Arch Linux 软件包", + "Python's library manager. Full of python libraries and other python-related utilities
Contains: Python libraries and related utilities": "Python 的软件包管理器。包含所有 Python 的库以及其它与 Python 相关的实用工具。
包括:Python 包和相关实用工具", + "PowerShell's package manager. Find libraries and scripts to expand PowerShell capabilities
Contains: Modules, Scripts, Cmdlets": "PowerShell 的软件包管理器。可用于寻找扩展 PowerShell 功能的库和脚本。
包括:模块、脚本、Cmdlets\n", + "extracted": "已提取", + "Scoop package": "Scoop 软件包", + "Great repository of unknown but useful utilities and other interesting packages.
Contains: Utilities, Command-line programs, General Software (extras bucket required)": "包含不知名但有用的实用程序和其它有趣软件包的重要存储库。
包括:实用工具、命令行程序、通用软件(需要 extras bucket)", + "The universal Linux package manager by Canonical.
Contains: Snap packages from the Snapcraft store": "Canonical 推出的通用 Linux 软件包管理器。
包括:来自 Snapcraft 商店的 Snap 软件包", + "library": "库", + "feature": "功能", + "A popular C/C++ library manager. Full of C/C++ libraries and other C/C++-related utilities
Contains: C/C++ libraries and related utilities": "一个流行的 C/C++ 库管理器。包含 C/C++ 库和其它与 C/C++ 相关的实用程序
包括:C/C++ 库和相关的实用程序", + "option": "选项", + "This package cannot be installed from an elevated context.": "无法在提升的上下文中安装此软件包。", + "Please run UniGetUI as a regular user and try again.": "请以普通用户身份运行 UniGetUI ,然后重试。", + "Please check the installation options for this package and try again": "请检查此软件包的安装选项,然后重试", + "Microsoft's official package manager. Full of well-known and verified packages
Contains: General Software, Microsoft Store apps": "微软的官方软件包管理器。拥有知名的、经过验证的众多软件包。
包括:通用软件、微软商店应用\n", + "Local PC": "本地电脑", + "Android Subsystem": "安卓子系统", + "Operation on queue (position {0})...": "操作正在排队中(位置 {0})……", + "Click here for more details": "单击此处可获取更多详情", + "Operation canceled by user": "用户取消了操作", + "Running PreOperation ({0}/{1})...": "正在运行 PreOperation ({0}/{1})...", + "PreOperation {0} out of {1} failed, and was tagged as necessary. Aborting...": "PreOperation {0}/{1} 失败,且被标记为必需。正在中止...", + "PreOperation {0} out of {1} finished with result {2}": "PreOperation {0}/{1} 已完成,结果为 {2}", + "Starting operation...": "开始操作...", + "Running PostOperation ({0}/{1})...": "正在运行 PostOperation ({0}/{1})...", + "PostOperation {0} out of {1} failed, and was tagged as necessary. Aborting...": "PostOperation {0}/{1} 失败,且被标记为必需。正在中止...", + "PostOperation {0} out of {1} finished with result {2}": "PostOperation {0}/{1} 已完成,结果为 {2}", + "{package} installer download": "{package} 安装程序下载", + "{0} installer is being downloaded": "正在下载 {0} 安装程序", + "Download succeeded": "下载成功", + "{package} installer was downloaded successfully": "已成功下载 {package} 安装程序", + "Download failed": "下载失败", + "{package} installer could not be downloaded": "无法下载 {package} 安装程序", + "{package} Installation": "{package} 安装", + "{0} is being installed": "正在安装 {0}", + "Installation succeeded": "安装成功", + "{package} was installed successfully": "{package} 已成功安装", + "Installation failed": "安装失败", + "{package} could not be installed": "无法安装 {package}", + "{package} Update": "{package} 更新", + "Update succeeded": "更新成功", + "{package} was updated successfully": "{package} 已成功更新", + "Update failed": "更新失败", + "{package} could not be updated": "无法更新 {package}", + "{package} Uninstall": "{package} 卸载", + "{0} is being uninstalled": "正在卸载 {0}", + "Uninstall succeeded": "卸载成功", + "{package} was uninstalled successfully": "{package} 已成功卸载", + "Uninstall failed": "卸载失败", + "{package} could not be uninstalled": "无法卸载 {package}", + "Adding source {source}": "添加源 {source}", + "Adding source {source} to {manager}": "添加安装源 {source} 至软件包管理器 {manager}", + "Source added successfully": "已成功添加源", + "The source {source} was added to {manager} successfully": "安装源 {source} 已成功添加到 {manager}", + "Could not add source": "无法添加源", + "Could not add source {source} to {manager}": "无法添加安装源 {source} 至 {manager}", + "Removing source {source}": "正在移除源 {source}", + "Removing source {source} from {manager}": "正在从 {manager} 中移除安装源 {source}", + "Source removed successfully": "已成功移除源", + "The source {source} was removed from {manager} successfully": "安装源 {source} 已成功从 {manager} 中移除", + "Could not remove source": "无法移除源", + "Could not remove source {source} from {manager}": "无法从 {manager} 移除安装源 {source}", + "The package manager \"{0}\" was not found": "软件管理器 \"{0}\" 找不到", + "The package manager \"{0}\" is disabled": "软件管理器 \"{0}\" 已禁用", + "There is an error with the configuration of the package manager \"{0}\"": "软件包管理器 \"{0}\" 的配置中有错误", + "The package \"{0}\" was not found on the package manager \"{1}\"": "在软件包管理器 \"{1}\" 中找不到软件包 \"{0}\"", + "{0} is disabled": "已禁用 {0}", + "{0} weeks": "{0} 周", + "1 month": "1 个月", + "{0} months": "{0} 个月", + "Something went wrong": "出现了一些问题", + "An interal error occurred. Please view the log for further details.": "程序出现内部错误,请查看日志文件获取详情。", + "No applicable installer was found for the package {0}": "未找到适用于包 {0} 的安装程序", + "Integrity checks will not be performed during this operation": "此操作期间将不执行完整性检查", + "This is not recommended.": "不建议。", + "Run now": "立即运行", + "Run next": "下个运行", + "Run last": "最后运行", + "Show in explorer": "在浏览器中显示", + "Checked": "已勾选", + "Unchecked": "未勾选", + "This package is already installed": "此软件包已安装", + "This package can be upgraded to version {0}": "此软件包可以升级到版本 {0}", + "Updates for this package are ignored": "已忽略该软件包的所有更新", + "This package is being processed": "正在处理此软件包", + "This package is not available": "此软件包不存在", + "Select the source you want to add:": "请选择您想添加的安装源:", + "Source name:": "安装源名称:", + "Source URL:": "安装源网址:", + "An error occurred when adding the source: ": "添加源时出现错误:", + "Package management made easy": "让软件包管理更简单", + "version {0}": "版本 {0}", + "[RAN AS ADMINISTRATOR]": "以管理员身份运行", + "Portable mode": "便携模式", + "DEBUG BUILD": "调试构建", + "Here you can change UniGetUI's behaviour regarding the following shortcuts. Checking a shortcut will make UniGetUI delete it if if gets created on a future upgrade. Unchecking it will keep the shortcut intact": "在这里,您可以更改 UniGetUI 针对以下快捷方式的行为。若勾选,则 UniGetUI 会删除未来升级时创建的快捷方式。取消勾选将保持它不变", + "Manual scan": "手动扫描", + "Existing shortcuts on your desktop will be scanned, and you will need to pick which ones to keep and which ones to remove.": "将扫描桌面上现有的快捷方式,请选择要保留和删除的内容。", + "Delete?": "要删除吗?", + "I understand": "我明白", + "Chocolatey setup changed": "Chocolatey 设置已更改", + "UniGetUI no longer includes its own private Chocolatey installation. A legacy UniGetUI-managed Chocolatey installation was detected for this user profile, but system Chocolatey was not found. Chocolatey will stay unavailable in UniGetUI until Chocolatey is installed on the system and UniGetUI is restarted. Applications previously installed through UniGetUI's bundled Chocolatey may still appear under other sources such as Local PC or WinGet.": "UniGetUI 不再包含其自带的私有 Chocolatey 安装。已检测到此用户配置文件中有旧版 UniGetUI 托管的 Chocolatey 安装,但未找到系统级 Chocolatey。在系统上安装 Chocolatey 并重新启动 UniGetUI 之前,Chocolatey 将在 UniGetUI 中保持不可用状态。之前通过 UniGetUI 内置的 Chocolatey 安装的应用程序可能仍会显示在其他来源下,例如本地电脑或 WinGet。", + "NOTE: This troubleshooter can be disabled from UniGetUI Settings, on the WinGet section": "注意:可在 UniGetUI 设置的 WinGet 部分中,禁用此故障排除程序", + "Restart": "重新启动", + "Are you sure you want to delete all shortcuts?": "您确实想要删除所有快捷方式吗?", + "Any new shorcuts created during an install or an update operation will be deleted automatically, instead of showing a confirmation prompt the first time they are detected.": "将自动删除在安装或更新操作期间创建的任何新快捷方式,不会在首次检测到它们时显示确认提示。", + "Any shorcuts created or modified outside of UniGetUI will be ignored. You will be able to add them via the {0} button.": "将忽略在 UniGetUI 之外创建或修改的任何快捷方式。您可以通过 {0} 按钮来添加它们。", + "Are you really sure you want to enable this feature?": "您确实想要启用此功能吗?", + "No new shortcuts were found during the scan.": "扫描期间未发现新的快捷方式。", + "How to add packages to a bundle": "如何添加软件包进捆绑包", + "In order to add packages to a bundle, you will need to: ": "要添加软件包进捆绑包,您需要:", + "1. Navigate to the \"{0}\" or \"{1}\" page.": "1. 导航至 “{0}” 或 “{1}” 页面。", + "2. Locate the package(s) you want to add to the bundle, and select their leftmost checkbox.": "2. 找到要添加进捆绑包的软件包,然后选中它们最左侧的复选框。", + "3. When the packages you want to add to the bundle are selected, find and click the option \"{0}\" on the toolbar.": "3. 当你选择好要添加进捆绑包的软件包时,找到并点击工具栏上的选项 “{0}” 。", + "4. Your packages will have been added to the bundle. You can continue adding packages, or export the bundle.": "4. 你的软件包将被添加进捆绑包。你可以继续添加软件包,或者导出捆绑包。", + "Which backup do you want to open?": "你想要打开哪个备份?", + "Select the backup you want to open. Later, you will be able to review which packages you want to install.": "选择你要打开的备份。稍后你将能看到要安装哪些软件包。", + "There are ongoing operations. Quitting UniGetUI may cause them to fail. Do you want to continue?": "有正在进行的操作。退出 UniGetUI 可能会导致它们失败。您确定要继续吗?", + "UniGetUI or some of its components are missing or corrupt.": "UniGetUI 或它的某些组件缺失或已损坏。", + "It is strongly recommended to reinstall UniGetUI to adress the situation.": "强烈建议重新安装 UniGetUI 以解决该情况。", + "Refer to the UniGetUI Logs to get more details regarding the affected file(s)": "参考 UniGetUI 日志可获取有关受影响文件的更多详细信息。", + "Integrity checks can be disabled from the Experimental Settings": "可以在“实验设置”中禁用完整性检查", + "Repair UniGetUI": "修复 UniGetUI", + "Live output": "实时输出", + "This package bundle had some settings that are potentially dangerous, and may be ignored by default.": "此软件包有一些设置可能存在潜在危险,默认情况下可能会被忽略。", + "Entries that show in YELLOW will be IGNORED.": "将忽略以黄色显示的项目。", + "Entries that show in RED will be IMPORTED.": "将导入以红色显示的项目。", + "You can change this behavior on UniGetUI security settings.": "你可以在 UniGetUI 安全设置中更改此行为。", + "Open UniGetUI security settings": "打开 UniGetUI 安全设置", + "Should you modify the security settings, you will need to open the bundle again for the changes to take effect.": "如果您修改了安全设置,则需要再次打开该软件包,以使更改生效。", + "Details of the report:": "报告详情:", + "Are you sure you want to create a new package bundle? ": "您确定要创建一个新的软件捆绑包吗?", + "Any unsaved changes will be lost": "未保存的更改将会丢失", + "Warning!": "警告!", + "For security reasons, custom command-line arguments are disabled by default. Go to UniGetUI security settings to change this. ": "出于安全原因,自定义命令行参数默认处于禁用状态。可前往 UniGetUI 安全设置更改此设置。", + "Change default options": "更改默认选项", + "Ignore future updates for this package": "忽略此软件包的后续更新", + "For security reasons, pre-operation and post-operation scripts are disabled by default. Go to UniGetUI security settings to change this. ": "出于安全原因,操作前和操作后脚本默认处于禁用状态。可前往 UniGetUI 安全设置更改此设置。", + "You can define the commands that will be run before or after this package is installed, updated or uninstalled. They will be run on a command prompt, so CMD scripts will work here.": "你可以定义在安装、更新或卸载此软件包之前或之后运行的命令。这些命令将在命令提示符下运行,所以可在此处使用 CMD 脚本。", + "Change this and unlock": "更改并解锁", + "{0} Install options are currently locked because {0} follows the default install options.": "已锁定 {0} 安装选项,因为 {0} 遵循默认安装选项。", + "Unset or unknown": "未设置或未知", + "This package has no screenshots or is missing the icon? Contrbute to UniGetUI by adding the missing icons and screenshots to our open, public database.": "此软件包缺少截图或图标吗?可以向我们的开放公共数据库添加缺失的图标或截图,为 UniGetUI 做出贡献。", + "Become a contributor": "成为贡献者", + "Update to {0} available": "可更新至 {0}", + "Reinstall": "重新安装", + "Installer not available": "安装程序不可用", + "Version:": "版本:", + "UniGetUI Version {0}": "UniGetUI 版本 {0}", + "Performing backup, please wait...": "正在备份中,请稍候...", + "An error occurred while logging in: ": "登录时出错:", + "Fetching available backups...": "正在获取可用的备份...", + "Done!": "完成!", + "The cloud backup has been loaded successfully.": "已成功加载云备份。", + "An error occurred while loading a backup: ": "载入备份时出错:", + "Backing up packages to GitHub Gist...": "正在将软件包备份到 GitHub Gist...", + "Backup Successful": "备份成功", + "The cloud backup completed successfully.": "云备份已成功完成。", + "Could not back up packages to GitHub Gist: ": "无法将软件包备份至 GitHub Gist :", + "It is not guaranteed that the provided credentials will be stored safely, so you may as well not use the credentials of your bank account": "无法保证所提供的凭据会被安全存储,你最好不要使用银行账户的凭据", + "Enable the automatic WinGet troubleshooter": "启用自动 WinGet 故障排除程序", + "Add updates that fail with a 'no applicable update found' to the ignored updates list": "将“未找到适用更新”错误而失败的更新添加进“已忽略更新”列表中。", + "Invalid selection": "无效选择", + "No package was selected": "未选择任何软件包", + "More than 1 package was selected": "选择了多个软件包", + "List": "列表", + "Grid": "网格", + "Icons": "图标", + "\"{0}\" is a local package and does not have available details": "“{0}”是缺乏详细信息的本地软件包", + "\"{0}\" is a local package and is not compatible with this feature": "“{0}”是本地软件包,与此功能不兼容", + "Add packages to bundle": "添加软件包进捆绑包", + "Preparing packages, please wait...": "正在准备软件包,请稍候……", + "Loading packages, please wait...": "正在加载软件包,请稍候……", + "Saving packages, please wait...": "正在保存软件包,请稍候……", + "The bundle was created successfully on {0}": "已成功于 {0} 创建了捆绑包", + "User profile": "用户配置文件", + "Error": "错误", + "Log in failed: ": "登录失败:", + "Log out failed: ": "登录失败:", + "Package backup settings": "软件包备份设置", + "Package managers": "软件包管理器", + "Manage UniGetUI autostart behaviour from the Settings app": "管理 UniGetUI 自动启动行为", + "Something went wrong while launching the updater.": "在启动更新程序时出错。", + "Please try again later": "请稍后再试", + "Show the release notes after UniGetUI is updated": "在 UniGetUI 更新后显示发布说明" +} diff --git a/src/Languages/lang_zh_TW.json b/src/Languages/lang_zh_TW.json new file mode 100644 index 0000000..845f96a --- /dev/null +++ b/src/Languages/lang_zh_TW.json @@ -0,0 +1,852 @@ +{ + "{0} of {1} operations completed": "已完成 {1} 項操作中的 {0} 項", + "{0} is now {1}": "{0} 現在是 {1}", + "Enabled": "啟用", + "Disabled": "停用", + "Privacy": "隱私", + "Hide my username from the logs": "在記錄檔中隱藏我的使用者名稱", + "Replaces your username with **** in the logs. Restart UniGetUI to also hide it from already-recorded entries.": "在記錄檔中以 **** 取代您的使用者名稱。重新啟動 UniGetUI 亦可將其從已記錄的項目中隱藏。", + "Your last update attempt did not complete.": "您上次的更新嘗試未完成。", + "UniGetUI could not confirm whether the update succeeded. Open the log to see what happened.": "UniGetUI 無法確認更新是否成功。請開啟紀錄檔查看發生了什麼事。", + "View log": "檢視紀錄", + "The installer reported success but did not restart UniGetUI.": "安裝程式回報成功,但未重新啟動 UniGetUI。", + "The installer failed to initialize.": "安裝程式初始化失敗。", + "Setup was canceled before installation began.": "安裝開始前已取消設定程式。", + "A fatal error occurred during the preparation phase.": "準備階段發生嚴重錯誤。", + "A fatal error occurred during installation.": "安裝期間發生嚴重錯誤。", + "Installation was canceled while in progress.": "安裝進行中被取消。", + "The installer was terminated by another process.": "安裝程式已被另一個程序終止。", + "The preparation phase determined the installation cannot proceed.": "準備階段判定無法繼續安裝。", + "The installer could not start. UniGetUI may already be running, or you do not have permission to install.": "安裝程式無法啟動。UniGetUI 可能已在執行,或您沒有安裝權限。", + "Unexpected installer error.": "未預期的安裝程式錯誤。", + "We are checking for updates.": "我們正在檢查更新。", + "Please wait": "請稍候...", + "Great! You are on the latest version.": "太棒了!您已經在使用 UniGetUI 的最新版本。", + "There are no new UniGetUI versions to be installed": "目前沒有新版的 UniGetUI 可供安裝", + "UniGetUI version {0} is being downloaded.": "正在下載 UnigetUI 版本 {0}", + "This may take a minute or two": "這需要一些時間", + "The installer authenticity could not be verified.": "無法驗證安裝程式的真實性。", + "The update process has been aborted.": "更新過程已被中止。", + "Auto-update is not yet available on this platform.": "此平台尚不支援自動更新。", + "Please update UniGetUI manually.": "請手動更新 UniGetUI。", + "An error occurred when checking for updates: ": "檢查更新時發生錯誤:", + "The updater could not be launched.": "無法啟動更新程式。", + "The operating system did not start the installer process.": "作業系統未啟動安裝程式程序。", + "UniGetUI is being updated...": "UniGetUI 正在更新...", + "Update installed.": "更新已安裝。", + "UniGetUI was updated successfully, but this running copy was not replaced. This usually means you are running a development build. Close this copy and start the newly-installed version to finish.": "UniGetUI 已成功更新,但這個執行中的副本未被取代。這通常表示您正在執行開發組建。請關閉此副本並啟動新安裝的版本以完成更新。", + "The update could not be applied.": "無法套用更新。", + "Installer exit code {0}: {1}": "安裝程式結束代碼 {0}: {1}", + "Update cancelled.": "更新已取消。", + "Authentication was cancelled.": "認證已取消。", + "Installer exit code {0}": "安裝程式結束代碼 {0}", + "Operation in progress": "正在執行操作", + "Please wait...": "請稍候...", + "Success!": "完成!", + "Failed": "失敗", + "An error occurred while processing this package": "處理這個套件的時候發生錯誤", + "Installer": "安裝程式", + "Executable": "可執行檔", + "MSI": "MSI", + "Compressed file": "壓縮檔案", + "MSIX": "MSIX", + "WinGet was repaired successfully": "WinGet 已修復成功", + "It is recommended to restart UniGetUI after WinGet has been repaired": "建議在 WinGet 修復完成後,重新啟動 UniGetUI", + "WinGet could not be repaired": "無法完成修復 WinGet", + "An unexpected issue occurred while attempting to repair WinGet. Please try again later": "在修復 WinGet 時遭遇未知的錯誤,請稍候再重試一次", + "Log in to enable cloud backup": "登入以啟用雲端備份", + "Backup Failed": "備份失敗", + "Downloading backup...": "下載備份...", + "An update was found!": "找到一個更新!", + "{0} can be updated to version {1}": "{0} 可以更新到版本 {1}", + "Updates found!": "發現更新!", + "{0} packages can be updated": "有 {0} 個套件可供更新", + "{0} is being updated to version {1}": "正在更新 {0} 到版本 {1}", + "{0} packages are being updated": "{0} 個套件正在更新", + "You have currently version {0} installed": "您已安裝版本 {0}", + "Desktop shortcut created": "已建立桌面捷徑", + "UniGetUI has detected a new desktop shortcut that can be deleted automatically.": "UniGetUI 已偵測到一個新的桌面捷徑,可以自動刪除。", + "{0} desktop shortcuts created": "已在桌面建立{0}個捷徑。", + "UniGetUI has detected {0} new desktop shortcuts that can be deleted automatically.": "UniGetUI 已偵測到 {0} 個新的桌面捷徑,不需要自動刪除。", + "Attention required": "請注意", + "Restart required": "需要重新啟動", + "1 update is available": "一個可用的更新", + "{0} updates are available": "有可用的 {0} 個更新", + "Everything is up to date": "每項更新都是最新的", + "Discover Packages": "瀏覽套件", + "Available Updates": "可用更新", + "Installed Packages": "已安裝的套件", + "UniGetUI Version {0} by Devolutions": "Devolutions 出品的 UniGetUI 版本 {0}", + "Show UniGetUI": "顯示 UniGetUI 視窗", + "Quit": "離開", + "Are you sure?": "您確定嗎?", + "Do you really want to uninstall {0}?": "您是否確定要解除安裝 {0}?", + "Do you really want to uninstall the following {0} packages?": "您確定要解除安裝以下 {0} 套件嗎?", + "No": "否", + "Yes": "是", + "Partial": "部分", + "View on UniGetUI": "在 UniGetUI 上檢視", + "Update": "更新", + "Open UniGetUI": "啟動 UniGetUI", + "Update all": "更新全部", + "Update now": "現在更新", + "Installer host changed since the installed version.\n": "安裝程式主機在已安裝版本之後變更。\n", + "This package is on the queue": "此套件已排入佇列", + "installing": "正在安裝", + "updating": "正在更新", + "uninstalling": "正在解除安裝", + "installed": "已安裝", + "Retry": "重試", + "Install": "安裝", + "Uninstall": "解除安裝", + "Open": "開啟", + "Operation profile:": "操作狀況:", + "Follow the default options when installing, upgrading or uninstalling this package": "安裝、更新或解除安裝此套件時,請遵循預設選項", + "The following settings will be applied each time this package is installed, updated or removed.": "以下的設定會被套用到這個套件安裝、更新或移除", + "Version to install:": "即將安裝的版本:", + "Architecture to install:": "安裝架構:", + "Installation scope:": "安裝範圍:", + "Install location:": "安裝位置:", + "Select": "選擇", + "Reset": "重設", + "Custom install arguments:": "自訂安裝參數:", + "Custom update arguments:": "自訂更新參數:", + "Custom uninstall arguments:": "自訂解除安裝參數:", + "Pre-install command:": "預安裝指令:", + "Post-install command:": "安裝後指令:", + "Abort install if pre-install command fails": "如果預安裝指令失敗,則中止安裝", + "Pre-update command:": "更新前指令:", + "Post-update command:": "更新後指令:", + "Abort update if pre-update command fails": "如果更新前指令失敗,則中止更新", + "Pre-uninstall command:": "預解除安裝前指令:", + "Post-uninstall command:": "解除安裝後指令:", + "Abort uninstall if pre-uninstall command fails": "如果解除安裝前指令失敗,則中止解除安裝", + "Command-line to run:": "命令列執行:", + "Save and close": "儲存並關閉", + "General": "一般", + "Architecture & Location": "架構與位置", + "Command-line": "命令列", + "Close apps": "關閉應用程式", + "Pre/Post install": "安裝前/安裝後", + "Select the processes that should be closed before this package is installed, updated or uninstalled.": "選擇在安裝、更新或解除安裝此套件前應關閉的進程。", + "Write here the process names here, separated by commas (,)": "在此輸入程式名稱,並以逗號 (,) 分隔", + "Try to kill the processes that refuse to close when requested to": "嘗試停止那些在被要求關閉時拒絕關閉的進程。", + "Run as admin": "以系統管理員身分執行", + "Interactive installation": "互動式安裝", + "Skip hash check": "略過雜湊值檢查", + "Uninstall previous versions when updated": "更新時解除安裝先前版本", + "Skip minor updates for this package": "跳過此套件的次要更新", + "Automatically update this package": "自動更新此套件", + "{0} installation options": "{0} 安裝選項", + "Latest": "最新", + "PreRelease": "預先發行", + "Default": "預設", + "Manage ignored updates": "管理已略過的更新", + "The packages listed here won't be taken in account when checking for updates. Double-click them or click the button on their right to stop ignoring their updates.": "檢查更新時將不會考慮此處列出的套件。按兩下它們或按右鍵來停止略過它們的更新。", + "Reset list": "重設清單", + "Do you really want to reset the ignored updates list? This action cannot be reverted": "您確定要重設已忽略更新清單嗎?此操作無法還原", + "No ignored updates": "沒有已忽略的更新", + "Package Name": "套件名稱", + "Package ID": "套件識別碼", + "Ignored version": "已略過的版本", + "New version": "新版本", + "Source": "來源", + "All versions": "所有版本", + "Unknown": "未知", + "Up to date": "為最新版本", + "Package {name} from {manager}": "來自 {manager} 的套件 {name}", + "Remove {0} from ignored updates": "將 {0} 從忽略更新中移除", + "Cancel": "取消", + "Administrator privileges": "系統管理員權限", + "This operation is running with administrator privileges.": "此操作是以管理員權限執行。", + "Interactive operation": "互動式操作", + "This operation is running interactively.": "此操作以互動方式執行。", + "You will likely need to interact with the installer.": "您可能需要與安裝程式進行互動。", + "Integrity checks skipped": "跳過完整性檢查", + "Integrity checks will not be performed during this operation.": "此操作期間不會執行完整性檢查。", + "Proceed at your own risk.": "請自行承擔風險。", + "Close": "關閉", + "Loading...": "正在載入...", + "Installer SHA256": "安裝程式 SHA256 值", + "Homepage": "首頁", + "Author": "作者", + "Publisher": "發行者", + "License": "授權", + "Manifest": "清單", + "Installer Type": "安裝類型", + "Size": "大小", + "Installer URL": "安裝來源網址", + "Last updated:": "最近更新:", + "Release notes URL": "版本更新說明連結", + "Package details": "套件詳細資料", + "Dependencies:": "依賴性:", + "Release notes": "版本更新說明", + "Screenshots": "螢幕截圖", + "This package has no screenshots or is missing the icon? Contribute to UniGetUI by adding the missing icons and screenshots to our open, public database.": "此套件沒有螢幕截圖或缺少圖示嗎?請將缺少的圖示和螢幕截圖新增到我們開放的公開資料庫,為 UniGetUI 做出貢獻。", + "Version": "版本", + "Install as administrator": "以系統管理員身分安裝", + "Update to version {0}": "更新版本至 {0}", + "Installed Version": "已安裝的版本", + "Update as administrator": "以系統管理員身分更新", + "Interactive update": "互動式更新", + "Uninstall as administrator": "以系統管理員身分解除安裝", + "Interactive uninstall": "互動式解除安裝", + "Uninstall and remove data": "解除安裝和移除資料", + "Not available": "無法使用", + "Installer SHA512": "安裝程式 SHA512 雜湊值", + "Unknown size": "大小未知", + "No dependencies specified": "未指定依賴", + "mandatory": "指定", + "optional": "可選", + "UniGetUI {0} is ready to be installed.": "UniGetUI 版本 {0} 已準備好安裝", + "The update process will start after closing UniGetUI": "更新過程將在關閉 UniGetUI 後開始", + "UniGetUI has been ran as administrator, which is not recommended. When running UniGetUI as administrator, EVERY operation launched from UniGetUI will have administrator privileges. You can still use the program, but we highly recommend not running UniGetUI with administrator privileges.": "UniGetUI 已以系統管理員身分執行,但不建議這樣做。當 UniGetUI 以系統管理員身分執行時,從 UniGetUI 啟動的每一項操作都將具有系統管理員權限。您仍然可以使用此程式,但我們強烈建議不要以系統管理員身分執行 UniGetUI。", + "Share anonymous usage data": "分享匿名使用資料", + "UniGetUI collects anonymous usage data in order to improve the user experience.": "UniGetUI 收集匿名使用資料,以改善使用者體驗。", + "Accept": "同意", + "Software Updates": "套件更新", + "Package Bundles": "套件組合", + "Settings": "設定", + "Package Managers": "套件管理員", + "UniGetUI Log": "UniGetUI 紀錄", + "Package Manager logs": "套件管理器紀錄", + "Operation history": "操作歷史記錄", + "Help": "說明", + "UniGetUI": "UniGetUI", + "You have installed UniGetUI Version {0}": "您已經安裝 UniGetUI 版本 {0}", + "Disclaimer": "免責聲明", + "UniGetUI is developed by Devolutions and is not affiliated with any of the compatible package managers.": "UniGetUI 由 Devolutions 開發,並未隸屬於任何相容的套件管理員。", + "UniGetUI wouldn't have been possible without the help of the contributors. Thank you all 🥳": "如果沒有貢獻者的幫助,UniGetUI 就沒辦法實現。感謝各位 🥳", + "UniGetUI uses the following libraries. Without them, UniGetUI wouldn't have been possible.": "UniGetUI 使用以下函式庫:", + "{0} homepage": "{0} 首頁", + "UniGetUI has been translated to more than 40 languages thanks to the volunteer translators. Thank you 🤝": "感謝貢獻翻譯人員的幫助,UniGetUI 已被翻譯成 40 多種語言。謝謝 🤝", + "Verbose": "詳細資料", + "1 - Errors": "1 - 錯誤", + "2 - Warnings": "2 - 警告", + "3 - Information (less)": "3 - 資訊 (簡易)", + "4 - Information (more)": "4 - 資訊 (詳細)", + "5 - information (debug)": "5 - 資訊 (除錯)", + "Warning": "警告", + "The following settings may pose a security risk, hence they are disabled by default.": "下列設定可能會造成安全風險,因此預設為停用。", + "Enable the settings below if and only if you fully understand what they do, and the implications they may have.": "只有在您完全瞭解下列設定的作用及其可能涉及的影響和危險後,才能啟用這些設定。", + "The settings will list, in their descriptions, the potential security issues they may have.": "這些設定會在說明中列出其可能具有的潛在安全問題。", + "The backup will include the complete list of the installed packages and their installation options. Ignored updates and skipped versions will also be saved.": "備份檔將包含完整的已安裝套件清單與它們的安裝設定,已忽略的版本與更新也將會被儲存。", + "The backup will NOT include any binary file nor any program's saved data.": "備份檔「不會」包含任何執行檔與任何程式儲存的資料", + "The size of the backup is estimated to be less than 1MB.": "備份檔案預計不會超過 1MB。", + "The backup will be performed after login.": "備份將在登入後進行", + "{pcName} installed packages": "{pcName} 已安裝的套件", + "Current status: Not logged in": "目前狀態: 尚未登入", + "You are logged in as {0} (@{1})": "您的登入帳號是{0}(@{1})", + "Nice! Backups will be uploaded to a private gist on your account": "非常好!備份會上傳到您帳戶的私人 gist 中", + "Select backup": "選擇備份", + "Settings imported from {0}": "已從 {0} 匯入設定", + "UniGetUI Settings": "UniGetUI 設定", + "Settings exported to {0}": "已將設定匯出至 {0}", + "UniGetUI settings were reset": "UniGetUI 設定已重設", + "Allow pre-release versions": "允許預發行版本", + "Apply": "套用", + "For security reasons, custom command-line arguments are disabled by default. Go to UniGetUI security settings to change this.": "基於安全考量,自訂命令列參數預設為停用。請前往 UniGetUI 安全性設定變更此設定。", + "Go to UniGetUI security settings": "前往 UniGetUI 安全設定", + "The following options will be applied by default each time a {0} package is installed, upgraded or uninstalled.": "每次安裝、更新或解除安裝{0}套件時,預設會套用下列選項。", + "Package's default": "套件的預設值", + "Install location can't be changed for {0} packages": "{0}套件安裝的位置無法變更", + "The local icon cache currently takes {0} MB": "此本機圖示快取使用容量為 {0} MB", + "Username": "使用者名稱", + "Password": "密碼", + "Credentials": "證書", + "It is not guaranteed that the provided credentials will be stored safely": "無法保證所提供的認證資料會被安全儲存", + "Partially": "部分", + "Package manager": "套件管理員", + "Compatible with proxy": "與 Proxy 相容", + "Compatible with authentication": "與認證相容", + "Proxy compatibility table": "Proxy 相容性列表", + "{0} settings": "{0} 設定", + "{0} status": "狀態{0}", + "Default installation options for {0} packages": "{0}套件安裝的預設選項", + "Expand version": "更多版本", + "The executable file for {0} was not found": "未找到 {0} 的可執行檔案", + "{pm} is disabled": "{pm} 已停用", + "Enable it to install packages from {pm}.": "從{pm}啟用安裝套件", + "{pm} is enabled and ready to go": "{pm} 已啟用並準備好", + "{pm} version:": "{pm} 版本:", + "{pm} was not found!": "沒有找到 {pm}!", + "You may need to install {pm} in order to use it with UniGetUI.": "您可能需要安裝 {pm} 來與 UniGetUI 一起使用。", + "Scoop Installer - UniGetUI": "Scoop 安裝程式 - UniGetUI", + "Scoop Uninstaller - UniGetUI": "解除安裝 Scoop - UniGetUI", + "Clearing Scoop cache - UniGetUI": "清理 Scoop 快取 - UniGetUI", + "Restart UniGetUI to fully apply changes": "重新啟動 UniGetUI 以完整套用變更", + "Restart UniGetUI": "重新啟動 UniGetUI", + "Manage {0} sources": "管理 {0} 個來源", + "Add source": "新增來源", + "Add": "新增", + "Source name": "來源名稱", + "Source URL": "來源網址", + "Other": "其他", + "No minimum age": "無最短天數限制", + "1 day": "1 天", + "{0} days": "{0} 天", + "Custom...": "自訂...", + "{0} minutes": "{0} 分鐘", + "1 hour": "1 小時", + "{0} hours": "{0} 小時", + "1 week": "1 週", + "Supports release dates": "支援發行日期", + "Release date support per package manager": "各套件管理器的發行日期支援情況", + "Search for packages": "搜尋套件", + "Local": "本機", + "OK": "確定", + "Last checked: {0}": "上次檢查:{0}", + "{0} packages were found, {1} of which match the specified filters.": "{0} 個套件已找到,{1} 個項目符合過濾條件。", + "{0} selected": "已選取 {0}", + "(Last checked: {0})": "(最後更新於:{0})", + "All packages selected": "已選取所有套件", + "Package selection cleared": "已清除套件選取", + "{0}: {1}": "{0}:{1}", + "More info": "詳細資訊", + "GitHub account": "GitHub 帳戶", + "Log in with GitHub to enable cloud package backup.": "使用 GitHub 登入,以啟用雲端套件備份。", + "More details": "詳細資料", + "Log in": "登入", + "If you have cloud backup enabled, it will be saved as a GitHub Gist on this account": "如果您已啟用雲端備份,則會以 GitHub Gist 的形式儲存於此帳戶中", + "Log out": "登出", + "About UniGetUI": "關於 UniGetUI", + "About": "關於", + "Third-party licenses": "第三方授權", + "Contributors": "貢獻者", + "Translators": "翻譯人員", + "Bundle security report": "綑綁式安全報告", + "The bundle contained restricted content": "套件組合包含受限制的內容", + "UniGetUI – Crash Report": "UniGetUI – 當機報告", + "UniGetUI has crashed": "UniGetUI 已當機", + "Help us fix this by sending a crash report to Devolutions. All fields below are optional.": "透過向 Devolutions 傳送當機報告來協助我們修復此問題。以下所有欄位皆為選填。", + "Email (optional)": "電子郵件(選填)", + "your@email.com": "your@email.com", + "Additional details (optional)": "其他詳細資訊(選填)", + "Describe what you were doing when the crash occurred…": "描述當機發生時您正在進行的操作…", + "Crash report": "當機報告", + "Don't Send": "不要傳送", + "Send Report": "傳送報告", + "Sending…": "正在傳送…", + "Unsaved changes": "未儲存的變更", + "You have unsaved changes in the current bundle. Do you want to discard them?": "目前的套件組合中有未儲存的變更。您要捨棄它們嗎?", + "Discard changes": "捨棄變更", + "Integrity violation": "完整性違規", + "UniGetUI or some of its components are missing or corrupt. It is strongly recommended to reinstall UniGetUI to adress the situation.": "UniGetUI 或其部分元件遺失或損毀。強烈建議重新安裝 UniGetUI 以解決此情況。", + "• Refer to the UniGetUI Logs to get more details regarding the affected file(s)": "• 請參閱 UniGetUI 紀錄,以取得有關受影響檔案的詳細資訊", + "• Integrity checks can be disabled from the Experimental Settings": "• 可從實驗設定停用完整性檢查。", + "Manage shortcuts": "桌面捷徑管理", + "UniGetUI has detected the following desktop shortcuts which can be removed automatically on future upgrades": "UniGetUI 已偵測到以下桌面捷徑,這些捷徑可以在未來的更新中自動刪除。", + "Do you really want to reset this list? This action cannot be reverted.": "您確定要重置此清單嗎?此操作無法撤銷", + "Desktop shortcuts list": "桌面捷徑清單", + "Open in explorer": "在檔案總管中開啟", + "Remove from list": "從清單中移除", + "When new shortcuts are detected, delete them automatically instead of showing this dialog.": "偵測到新的捷徑時,會自動刪除它們,而不是顯示此對話框。", + "Not right now": "現在不行", + "Missing dependency": "缺少依賴", + "UniGetUI requires {0} to operate, but it was not found on your system.": "UniGetUI 需要 {0} 協同作業,但未被安裝在您的系統中。", + "Click on Install to begin the installation process. If you skip the installation, UniGetUI may not work as expected.": "點擊安裝鈕來開始安裝流程。若跳過安裝,UniGetUI 可能無法正常運作。", + "Alternatively, you can also install {0} by running the following command in a Windows PowerShell prompt:": "您也可以在 Windows PowerShell 中使用以下指令來安裝 {0}:", + "Install {0}": "安裝 {0}", + "Do not show this dialog again for {0}": "不要再次於 {0} 中顯示此訊息", + "Please wait while {0} is being installed. A black window may show up. Please wait until it closes.": "請等候 {0} 安裝,在安裝過程期間可能會出現黑色視窗,請勿關閉它並等待它執行完畢。", + "{0} has been installed successfully.": "{0} 已成功安裝。", + "Please click on \"Continue\" to continue": "請點擊\"繼續\"以繼續", + "Continue": "繼續", + "{0} has been installed successfully. It is recommended to restart UniGetUI to finish the installation": "{0} 已成功安裝。建議重新啟動 UniGetUI 以便完成安裝。", + "Restart later": "稍後重新啟動", + "An error occurred:": "發生錯誤:", + "Please see the Command-line Output or refer to the Operation History for further information about the issue.": "請參閱命令列輸出或參考操作歷史記錄以取得有關該問題的詳細資訊。", + "Retry as administrator": "以管理員身份重試", + "Retry interactively": "以互動方式重試", + "Retry skipping integrity checks": "重試並跳過完整性檢查", + "Installation options": "安裝選項", + "Save": "儲存", + "UniGetUI collects anonymous usage data with the sole purpose of understanding and improving the user experience.": "UniGetUI 收集匿名使用資料的唯一目的是瞭解並改善使用者體驗。", + "More details about the shared data and how it will be processed": "有關共用資料的更多詳細資訊,以及如何處理這些資料", + "Do you accept that UniGetUI collects and sends anonymous usage statistics, with the sole purpose of understanding and improving the user experience?": "您是否接受 UniGetUI 收集並傳送匿名使用統計資料,其唯一目的在於了解並改善使用者體驗?", + "Decline": "拒絕", + "No personal information is collected nor sent, and the collected data is anonimized, so it can't be back-tracked to you.": "我們不會收集或傳送任何個人資訊,而且所收集的資料都是匿名的,因此無法追溯到您。", + "Navigation panel": "導覽面板", + "Operations": "操作", + "Toggle operations panel": "切換操作面板", + "Bulk operations": "批次操作", + "Retry failed": "重試失敗項目", + "Clear successful": "清除成功項目", + "Clear finished": "清除已完成項目", + "Cancel all": "全部取消", + "More": "更多", + "Toggle navigation panel": "切換導覽面板", + "Minimize": "最小化", + "Maximize": "最大化", + "UniGetUI by Devolutions": "Devolutions 出品的 UniGetUI", + "UniGetUI is an application that makes managing your software easier, by providing an all-in-one graphical interface for your command-line package managers.": "UniGetUI 是一款應用程式,透過為命令列套件管理程式提供一體化圖形介面,讓您的套件管理變得更加輕鬆。", + "Useful links": "分享連結", + "UniGetUI Homepage": "UniGetUI 首頁", + "Report an issue or submit a feature request": "回報問題或提交功能需求", + "UniGetUI Repository": "UniGetUI 儲存庫", + "View GitHub Profile": "檢視 GitHub 個人檔案", + "UniGetUI License": "UniGetUI 授權", + "Using UniGetUI implies the acceptation of the MIT License": "使用 UniGetUI 代表著您已接受 MIT 許可證", + "Become a translator": "成為一位翻譯人員", + "Go back": "返回上一頁", + "Go forward": "前往下一頁", + "Go to home page": "前往首頁", + "Reload page": "重新載入頁面", + "View page on browser": "在瀏覽器中顯示頁面", + "The built-in browser is not supported on Linux yet.": "內建瀏覽器尚未支援 Linux。", + "Open in browser": "在瀏覽器中開啟", + "Copy to clipboard": "複製到剪貼簿", + "Export to a file": "匯出為檔案", + "Log level:": "紀錄等級:", + "Reload log": "重新載入記錄", + "Export log": "匯出紀錄", + "Text": "文字", + "Change how operations request administrator rights": "變更操作要求管理員權限的方式", + "Restrictions on package operations": "套件操作的限制", + "Restrictions on package managers": "套件管理員的限制", + "Restrictions when importing package bundles": "匯入套件包時的限制", + "Ask for administrator privileges once for each batch of operations": "需要系統管理員權限來執行每一個批次檔的操作", + "Ask only once for administrator privileges": "只要求一次管理員權限", + "Prohibit any kind of Elevation via UniGetUI Elevator or GSudo": "阻止透過 UniGetUI Elevator 或 GSudo 進行任何形式的提升", + "This option WILL cause issues. Any operation incapable of elevating itself WILL FAIL. Install/update/uninstall as administrator will NOT WORK.": "此選項將導致問題。任何無法自我提升的操作都會失敗。以管理員身份安裝/更新/解除安裝將無法執行。", + "Allow custom command-line arguments": "允許自訂指令列參數", + "Custom command-line arguments can change the way in which programs are installed, upgraded or uninstalled, in a way UniGetUI cannot control. Using custom command-lines can break packages. Proceed with caution.": "自訂命令列參數可以改變程式安裝、更新或解除安裝的方式,而 UniGetUI 無法控制。使用自訂命令列可能會破壞套件。請謹慎使用。", + "Ignore custom pre-install and post-install commands when importing packages from a bundle": "允許執行自訂的安裝前與安裝後的指令", + "Pre and post install commands will be run before and after a package gets installed, upgraded or uninstalled. Be aware that they may break things unless used carefully": "安裝前和安裝後指令會在套件安裝、更新或解除安裝前後執行。請注意,除非小心使用,否則這些指令可能會破壞系統。", + "Allow changing the paths for package manager executables": "允許變更套件管理員執行檔的路徑", + "Turning this on enables changing the executable file used to interact with package managers. While this allows finer-grained customization of your install processes, it may also be dangerous": "開啟此功能可變更用於與套件管理員互動的可執行檔案。雖然這可讓您更精準的自訂安裝程式,但也可能會有危險", + "Allow importing custom command-line arguments when importing packages from a bundle": "從套件包匯入套件時,允許匯入自訂命令列參數", + "Malformed command-line arguments can break packages, or even allow a malicious actor to gain privileged execution. Therefore, importing custom command-line arguments is disabled by default": "不正確的命令列參數可能會破壞套件,甚至允許惡意使用者取得執行權限。因此,預設關閉了匯入自訂命令列參數的功能", + "Allow importing custom pre-install and post-install commands when importing packages from a bundle": "從套件中匯入套件時,允許匯入自訂的安裝前和安裝後指令", + "Pre and post install commands can do very nasty things to your device, if designed to do so. It can be very dangerous to import the commands from a bundle, unless you trust the source of that package bundle": "安裝前和安裝後的指令可能會對您的裝置造成非常惡劣的影響,如果設計是這樣的話。從套件包匯入指令可能非常危險,除非您信任該套件包的來源。", + "Administrator rights and other dangerous settings": "管理員權限和其他危險設定", + "Package backup": "套件備份", + "Cloud package backup": "雲端套件備份", + "Local package backup": "本機套件備份", + "Local backup advanced options": "本機備份進階選項", + "Log in with GitHub": "從 Github 登入", + "Log out from GitHub": "從 Github 登出", + "Periodically perform a cloud backup of the installed packages": "定期執行已安裝套件的雲端備份", + "Cloud backup uses a private GitHub Gist to store a list of installed packages": "雲端備份使用私人 GitHub Gist 來儲存已安裝套件的清單", + "Perform a cloud backup now": "立即執行雲端備份", + "Backup": "備份", + "Restore a backup from the cloud": "從雲端還原備份", + "Begin the process to select a cloud backup and review which packages to restore": "開始選擇雲端備份的程式,並檢視要還原的套件", + "Periodically perform a local backup of the installed packages": "定期執行已安裝套件的本機備份", + "Perform a local backup now": "立即執行本機備份", + "Change backup output directory": "變更備份儲存位置", + "Set a custom backup file name": "自訂備份的檔案名稱", + "Leave empty for default": "預設值為空", + "Add a timestamp to the backup file names": "新增一個時間戳給備份的檔案", + "Backup and Restore": "備份與還原", + "Enable background api (UniGetUI Widgets and Sharing, port 7058)": "啟用背景 API(UniGetUI 小工具和共享,連接埠 7058)", + "Wait for the device to be connected to the internet before attempting to do tasks that require internet connectivity.": "在嘗試執行需要網際網路連線的操作之前,請等待裝置連線至網際網路。", + "Disable the 1-minute timeout for package-related operations": "停用與套件相關操作的 1 分鐘超時限制。", + "Use installed GSudo instead of UniGetUI Elevator": "使用已安裝的 GSudo 取代 UniGetUI Elevator", + "Use a custom icon and screenshot database URL": "使用自訂的圖示與截圖資料庫的網址", + "Enable background CPU Usage optimizations (see Pull Request #3278)": "啟用背景處理器使用最佳化(請參閱 拉取請求 #3278)", + "Perform integrity checks at startup": "啟動時執行完整性檢查", + "When batch installing packages from a bundle, install also packages that are already installed": "從套件包批量安裝套件時,也會安裝已經安裝的套件", + "Experimental settings and developer options": "實驗性設定與開發選項", + "Show UniGetUI's version and build number on the titlebar.": "在標題列上顯示 UniGetUI 的版本", + "Language": "語言", + "UniGetUI updater": "UniGetUI 更新工具", + "Telemetry": "搖測", + "Manage UniGetUI settings": "管理 UniGetUI 設定", + "Related settings": "相關設定", + "Update UniGetUI automatically": "自動更新 UniGetUI", + "Check for updates": "檢查更新", + "Install prerelease versions of UniGetUI": "安裝 UniGetUI 的預發布版本", + "Manage telemetry settings": "管理遙測設定", + "Manage": "管理", + "Import settings from a local file": "從本機檔案匯入", + "Import": "匯入", + "Export settings to a local file": "匯出設定為本機檔案", + "Export": "匯出", + "Reset UniGetUI": "重設 UniGetUI", + "User interface preferences": "使用者介面偏好設定", + "Application theme, startup page, package icons, clear successful installs automatically": "應用程式主題、啟動頁面、套件圖示、自動清除成功安裝", + "General preferences": "一般設定", + "UniGetUI display language:": "UniGetUI 顯示語言", + "System language": "系統語言", + "Is your language missing or incomplete?": "你的語言遺失或是尚未完成", + "Appearance": "外觀", + "UniGetUI on the background and system tray": "UniGetUI 在背景和系統匣上", + "Package lists": "套件清單", + "Use classic mode": "使用傳統模式", + "Restart UniGetUI to apply this change": "重新啟動 UniGetUI 以套用此變更", + "The classic UI is disabled for beta testers": "傳統 UI 已對測試版測試人員停用", + "Close UniGetUI to the system tray": "將 UniGetUI 關閉至系統匣", + "Manage UniGetUI autostart behaviour": "管理 UniGetUI 的自動啟動行為", + "Show package icons on package lists": "在套件清單中顯示套件圖示", + "Clear cache": "清除快取", + "Select upgradable packages by default": "預設選擇可更新的套件", + "Light": "淺色", + "Dark": "深色", + "Follow system color scheme": "跟隨系統色彩模式", + "Application theme:": "應用程式佈景主題:", + "UniGetUI startup page:": "UniGetUI 啟動頁面:", + "Proxy settings": "Proxy 設定", + "Other settings": "其他設定", + "Connect the internet using a custom proxy": "使用自訂 Proxy 連線到網路", + "Please note that not all package managers may fully support this feature": "請注意,並非所有套件管理員都完全支援此功能", + "Proxy URL": "Proxy 網址", + "Enter proxy URL here": "在這裡輸入 Proxy 伺服器網址", + "Authenticate to the proxy with a user and a password": "使用使用者名稱與密碼驗證 Proxy", + "Internet and proxy settings": "網際網路與 Proxy 設定", + "Package manager preferences": "套件管理平台偏好設定", + "Ready": "已就緒", + "Not found": "沒有找到", + "Notification preferences": "通知設定", + "Notification types": "通知類型", + "The system tray icon must be enabled in order for notifications to work": "必須啟用系統匣圖示,通知功能才能正常運作", + "Enable UniGetUI notifications": "啟用 UniGetUI 通知", + "Show a notification when there are available updates": "有可用更新時顯示通知", + "Show a silent notification when an operation is running": "操作正在進行時顯示背景通知", + "Show a notification when an operation fails": "操作失敗時顯示通知", + "Show a notification when an operation finishes successfully": "操作成功完成時顯示通知", + "Concurrency and execution": "同時作業與執行方式", + "Automatic desktop shortcut remover": "桌面捷徑自動刪除工具", + "Choose how many operations should be performed in parallel": "選擇要同時執行的操作數量", + "Clear successful operations from the operation list after a 5 second delay": "在 5 秒延遲後清除操作列表中成功的操作。", + "Download operations are not affected by this setting": "下載作業不受此設定影響", + "You may lose unsaved data": "您可能會遺失未儲存的資料", + "Ask to delete desktop shortcuts created during an install or upgrade.": "是否刪除在套件包安裝或更新過程中建立的桌面捷徑。", + "Package update preferences": "套件更新偏好設定", + "Update check frequency, automatically install updates, etc.": "更新檢查頻率、自動安裝更新等。", + "Reduce UAC prompts, elevate installations by default, unlock certain dangerous features, etc.": "減少使用者帳戶控制提示、預設提升安裝、解鎖某些危險功能等。", + "Package operation preferences": "封裝操作偏好設定", + "Enable {pm}": "啟用 {pm}", + "Not finding the file you are looking for? Make sure it has been added to path.": "找不到您要的檔案?請確定它已加入路徑。", + "Select the executable to be used. The following list shows the executables found by UniGetUI": "請選擇要使用的可執行檔。以下列表顯示 UniGetUI 找到的可執行檔。", + "For security reasons, changing the executable file is disabled by default": "基於安全理由,預設停用變更可執行檔案", + "Change this": "變更此選項", + "Copy path": "複製路徑", + "Current executable file:": "目前可執行檔:", + "Ignore packages from {pm} when showing a notification about updates": "在顯示更新通知時,忽略來自 {pm} 的套件", + "Update security": "更新安全性", + "Use global setting": "使用全域設定", + "Minimum age for updates": "更新的最短天數", + "e.g. 10": "例如:10", + "Custom minimum age (days)": "自訂最短天數(天)", + "{pm} does not provide release dates for its packages, so this setting will have no effect": "{pm} 不提供其套件的發行日期,因此此設定不會生效", + "{pm} only provides release dates for some of its packages, so this setting will only apply to those packages": "{pm} 僅為部分套件提供發行日期,因此此設定僅會套用至這些套件", + "Override the global minimum update age for this package manager": "覆寫此套件管理器的全域最短更新天數", + "View {0} logs": "檢視 {0} 記錄", + "If Python cannot be found or is not listing packages but is installed on the system, ": "如果找不到 Python,或系統中已安裝 Python 但未列出任何套件, ", + "Advanced options": "進階選項", + "WinGet command-line tool": "WinGet 命令列工具", + "Choose which command-line tool UniGetUI uses for WinGet operations when the COM API is not used": "選擇在未使用 COM API 時,UniGetUI 用於 WinGet 操作的命令列工具", + "WinGet COM API": "WinGet COM API", + "Choose whether UniGetUI can use the WinGet COM API before falling back to the command-line tool": "選擇 UniGetUI 是否可在回退至命令列工具前使用 WinGet COM API", + "Reset WinGet": "重設 WinGet", + "This may help if no packages are listed": "這可能對於沒有套件的狀況會有幫助", + "Force install location parameter when updating packages with custom locations": "在更新有自訂路徑的套件時強制安裝路徑參數", + "Install Scoop": "安裝 Scoop", + "Uninstall Scoop (and its packages)": "解除安裝 Scoop(及其套件)", + "Run cleanup and clear cache": "執行清理及清除快取", + "Run": "執行", + "Enable Scoop cleanup on launch": "啟動時自動清理 Scoop", + "Default vcpkg triplet": "預設 Vcpkg 三重組(triplet)", + "Change vcpkg root location": "變更 vcpkg 根目錄位置", + "Reset vcpkg root location": "重設 vcpkg 根目錄位置", + "Open vcpkg root location": "開啟 vcpkg 根目錄位置", + "Language, theme and other miscellaneous preferences": "語言、佈景主題與其他設定", + "Show notifications on different events": "顯示不同事件的通知", + "Change how UniGetUI checks and installs available updates for your packages": "變更 UniGetUI 檢查與安裝套件更新的方式", + "Automatically save a list of all your installed packages to easily restore them.": "自動儲存已安裝的套件清單以便輕鬆還原它們。", + "Enable and disable package managers, change default install options, etc.": "啟用或停用套件管理員、變更預設安裝選項等。", + "Internet connection settings": "網路連線設定", + "Proxy settings, etc.": "Proxy 設定等。", + "Beta features and other options that shouldn't be touched": "不建議變更的測試版功能及其他選項", + "Reload sources": "重新載入來源", + "Delete source": "刪除來源", + "Known sources": "已知來源", + "Update checking": "更新檢查", + "Automatic updates": "自動更新", + "Check for package updates periodically": "定期檢查套件更新", + "Check for updates every:": "檢查更新頻率:", + "Install available updates automatically": "自動安裝可用的更新", + "Do not automatically install updates when the network connection is metered": "網路計量連線時,請勿自動安裝更新", + "Do not automatically install updates when the device runs on battery": "當裝置使用電池供電時,請勿自動安裝更新。", + "Do not automatically install updates when the battery saver is on": "開啟電池保護模式時,請勿自動安裝更新", + "Only show updates that are at least the specified number of days old": "只顯示至少已發佈指定天數的更新", + "Warn me when the installer URL host changes between the installed version and the new version (WinGet only)": "當安裝程式 URL 主機在已安裝版本與新版本之間變更時提醒我(僅限 WinGet)", + "Change how UniGetUI handles install, update and uninstall operations.": "變更 UniGetUI 處理安裝、更新以及解除安裝操作的方式。", + "Navigation": "導覽", + "Check for UniGetUI updates": "檢查 UniGetUI 更新", + "Quit UniGetUI": "結束 UniGetUI", + "Filters": "過濾器", + "Sources": "來源", + "Search for packages to start": "搜尋套件來開始", + "Select all": "全選", + "Clear selection": "取消選取", + "Instant search": "即時搜尋", + "Distinguish between uppercase and lowercase": "區分大小寫", + "Ignore special characters": "忽略特殊符號", + "Search mode": "搜尋模式", + "Both": "兩者皆是", + "Exact match": "完全符合", + "Show similar packages": "顯示相似的套件", + "Loading": "載入中", + "Package": "套件", + "More options": "更多選項", + "Order by:": "根據排序:", + "Name": "名稱", + "Id": "ID", + "Ascendant": "遞增", + "Descendant": "遞減", + "View modes": "檢視模式", + "Reload": "重新載入", + "Closed": "已關閉", + "Ascending": "遞增", + "Descending": "遞減", + "{0}: {1}, {2}": "{0}:{1},{2}", + "Order by": "排序依據", + "No results were found matching the input criteria": "沒有符合輸入條件的結果", + "No packages were found": "沒有套件被找到", + "Loading packages": "正在掃描套件", + "Skip integrity checks": "略過完整性驗證", + "Download selected installers": "下載選取的安裝程式", + "Install selection": "安裝選擇的程式", + "Install options": "安裝選項", + "Add selection to bundle": "新增套件組合選取項目", + "Download installer": "下載安裝程式", + "Uninstall selection": "解除安裝選擇的程式", + "Uninstall options": "解除安裝選項", + "Ignore selected packages": "略過已選取的套件", + "Open install location": "開啟安裝位置", + "Reinstall package": "重新安裝套件", + "Uninstall package, then reinstall it": "解除安裝套件,然後重新安裝", + "Ignore updates for this package": "忽略此套件的更新", + "WinGet malfunction detected": "已偵測到 WinGet 功能異常", + "It looks like WinGet is not working properly. Do you want to attempt to repair WinGet?": "WinGet 似乎沒有正常運作,您是否想要嘗試修復 WinGet?", + "Repair WinGet": "修復 WinGet", + "Updates will no longer be ignored for {0}": "將不再忽略 {0} 的更新", + "Updates are now ignored for {0}": "現在已忽略 {0} 的更新", + "Do not ignore updates for this package anymore": "不再忽略此套件包的更新。", + "Add packages or open an existing package bundle": "新增套件或打開現有的套件包", + "Add packages to start": "新增套件開始", + "The current bundle has no packages. Add some packages to get started": "目前套件包沒有任何套件。新增一些套件開始使用。", + "New": "新增", + "Save as": "另存為", + "Create .ps1 script": "創建 .ps1 腳本", + "Remove selection from bundle": "從套件組合移除選取項目", + "Skip hash checks": "略過雜湊值驗證", + "The package bundle is not valid": "此套件組合無效", + "The bundle you are trying to load appears to be invalid. Please check the file and try again.": "您指定的套件組合格式似乎不正確,請檢查該檔案後再重試。", + "Package bundle": "套件組合", + "Could not create bundle": "無法建立組合", + "The package bundle could not be created due to an error.": "套件組合建立時發生錯誤,故無法完成建立。", + "Install script": "安裝腳本", + "PowerShell script": "PowerShell 腳本", + "The installation script saved to {0}": "安裝腳本已儲存到 {0}", + "An error occurred": "發生錯誤", + "An error occurred while attempting to create an installation script:": "建立安裝程式碼的過程中發生了錯誤", + "Hooray! No updates were found.": "您現在為最新狀態", + "Uninstall selected packages": "解除安裝已選取的套件", + "Update selection": "更新選擇的程式", + "Update options": "更新選項", + "Uninstall package, then update it": "解除安裝套件,然後更新", + "Uninstall package": "解除安裝套件", + "Skip this version": "略過這個版本", + "Pause updates for": "暫停更新至", + "User | Local": "使用者 | 本機", + "Machine | Global": "電腦 | 全域", + "The default package manager for Debian/Ubuntu-based Linux distributions.
Contains: Debian/Ubuntu packages": "Debian/Ubuntu 系列 Linux 發行版的預設套件管理工具。
包含:Debian/Ubuntu 套件", + "The Rust package manager.
Contains: Rust libraries and programs written in Rust": "Rust 套件管理程式,
包含:Rust 函式庫與使用 Rust 編寫的程式", + "The classical package manager for windows. You'll find everything there.
Contains: General Software": "經典的 Windows 套件管理程式。您可以在那裡找到所有東西。
包含:一般軟體", + "The default package manager for RHEL/Fedora-based Linux distributions.
Contains: RPM packages": "RHEL/Fedora 系列 Linux 發行版的預設套件管理工具。
包含:RPM 套件", + "A repository full of tools and executables designed with Microsoft's .NET ecosystem in mind.
Contains: .NET related tools and scripts": "一個充滿工具和可執行檔的儲存庫,在設計使用了 Microsoft .NET 生態系。
包含:.NET 相關的工具與腳本", + "The universal Linux package manager for desktop applications.
Contains: Flatpak applications from configured remotes": "桌面應用程式的通用 Linux 套件管理器。
包含:來自已設定遠端來源的 Flatpak 應用程式", + "NuPkg (zipped manifest)": "NuPkg (壓縮清單)", + "The Missing Package Manager for macOS (or Linux).
Contains: Formulae, Casks": "macOS(或 Linux)缺少的套件管理器。
包含:Formulae、Casks", + "Node JS's package manager. Full of libraries and other utilities that orbit the javascript world
Contains: Node javascript libraries and other related utilities": "Node JS 的套件管理程式。圍繞 Javascript 生態的完整套件庫和其他工具程式
包含:Node Javascript 函式庫和其他相關工具程式", + "The default package manager for Arch Linux and its derivatives.
Contains: Arch Linux packages": "Arch Linux 及其衍生發行版的預設套件管理工具。
包含:Arch Linux 套件", + "Python's library manager. Full of python libraries and other python-related utilities
Contains: Python libraries and related utilities": "Python 的套件管理程式。完整的 Python 套件庫和其他與 Python 相關的工具程式
包含:Python 套件和相關工具程式", + "PowerShell's package manager. Find libraries and scripts to expand PowerShell capabilities
Contains: Modules, Scripts, Cmdlets": "PowerShell 的套件管理器。尋找庫和腳本以擴充 PowerShell 功能
包含:模組、腳本、Cmdlet", + "extracted": "已解壓縮", + "Scoop package": "Scoop 套件", + "Great repository of unknown but useful utilities and other interesting packages.
Contains: Utilities, Command-line programs, General Software (extras bucket required)": "未知但有用的工具程式和其他有趣套件的存放庫。
包含:工具程式、命令列程式、一般軟體 (需要額外的bucket)", + "The universal Linux package manager by Canonical.
Contains: Snap packages from the Snapcraft store": "Canonical 推出的通用 Linux 套件管理工具。
包含:來自 Snapcraft 商店的 Snap 套件", + "library": "函式庫", + "feature": "功能", + "A popular C/C++ library manager. Full of C/C++ libraries and other C/C++-related utilities
Contains: C/C++ libraries and related utilities": "一個受歡迎的C/C++庫管理器。包含了大量的C/C++庫和其他C/C++相關的工具
包含: C/C++庫及相關工具", + "option": "選項", + "This package cannot be installed from an elevated context.": "此套件無法從更高權限的環境下安裝。", + "Please run UniGetUI as a regular user and try again.": "請以一般使用者身份執行 UniGetUI 並再試一次。", + "Please check the installation options for this package and try again": "請檢查此套件包的安裝選項,然後再試一次。", + "Microsoft's official package manager. Full of well-known and verified packages
Contains: General Software, Microsoft Store apps": "Microsoft的官方套件管理程式。充滿有名和經過驗證的軟體套件
包含:一般軟體、在 Microsoft Store 上架的應用程式", + "Local PC": "電腦本機", + "Android Subsystem": "Android 子系統", + "Operation on queue (position {0})...": "(第{0}執行順位)", + "Click here for more details": "按一下此處以瞭解更多詳細資訊", + "Operation canceled by user": "操作已由使用者取消", + "Running PreOperation ({0}/{1})...": "正在執行 PreOperation ({0}/{1})...", + "PreOperation {0} out of {1} failed, and was tagged as necessary. Aborting...": "PreOperation {0}/{1} 失敗,且被標記為必要步驟。正在中止...", + "PreOperation {0} out of {1} finished with result {2}": "PreOperation {0}/{1} 已完成,結果為 {2}", + "Starting operation...": "開始操作...", + "Running PostOperation ({0}/{1})...": "正在執行 PostOperation ({0}/{1})...", + "PostOperation {0} out of {1} failed, and was tagged as necessary. Aborting...": "PostOperation {0}/{1} 失敗,且被標記為必要步驟。正在中止...", + "PostOperation {0} out of {1} finished with result {2}": "PostOperation {0}/{1} 已完成,結果為 {2}", + "{package} installer download": "{package} 下載安裝程式", + "{0} installer is being downloaded": "{0} 正在下載安裝程式", + "Download succeeded": "下載成功", + "{package} installer was downloaded successfully": "{package} 安裝程式已成功下載", + "Download failed": "下載失敗", + "{package} installer could not be downloaded": "{package} 無法下載安裝程式", + "{package} Installation": "安裝 {package}", + "{0} is being installed": "正在安裝 {0}", + "Installation succeeded": "已安裝成功", + "{package} was installed successfully": "{package} 已安裝完成", + "Installation failed": "安裝失敗", + "{package} could not be installed": "{package} 無法完成安裝", + "{package} Update": "更新 {package}", + "Update succeeded": "已完成更新", + "{package} was updated successfully": "{package} 已更新完成", + "Update failed": "更新失敗", + "{package} could not be updated": "{package} 無法完成更新", + "{package} Uninstall": "解除安裝 {package}", + "{0} is being uninstalled": "正在解除安裝 {0}", + "Uninstall succeeded": "解除安裝成功", + "{package} was uninstalled successfully": "{package} 已解除安裝完成", + "Uninstall failed": "解除安裝失敗", + "{package} could not be uninstalled": "{package} 無法解除安裝", + "Adding source {source}": "添加源{source}", + "Adding source {source} to {manager}": "將來源 {source} 新增到 {manager}", + "Source added successfully": "來源已成功新增", + "The source {source} was added to {manager} successfully": "來源 {source} 已成功的新增到 {manager}", + "Could not add source": "無法新增來源", + "Could not add source {source} to {manager}": "無法新增來源 {source} 至 {manager}", + "Removing source {source}": "移除源{source}", + "Removing source {source} from {manager}": "從 {manager} 移除來源 {source}", + "Source removed successfully": "來源已成功移除", + "The source {source} was removed from {manager} successfully": "來源 {source} 已成功的從 {manager} 移除", + "Could not remove source": "無法移除來源", + "Could not remove source {source} from {manager}": "無法從 {manager} 移除來源 {source}", + "The package manager \"{0}\" was not found": "找不到「{0}」套件管理程式", + "The package manager \"{0}\" is disabled": "「{0}」套件管理程式已停用", + "There is an error with the configuration of the package manager \"{0}\"": "「{0}」套件管理程式中發現組態錯誤", + "The package \"{0}\" was not found on the package manager \"{1}\"": "無法在「{1}」中取得套件「{0}」\n\n\n\n\n", + "{0} is disabled": "{0} 已停用", + "{0} weeks": "{0} 週", + "1 month": "1 個月", + "{0} months": "{0} 個月", + "Something went wrong": "出現某些錯誤", + "An interal error occurred. Please view the log for further details.": "發生一個內部錯誤,請查詢記錄檔以取得詳細資訊。", + "No applicable installer was found for the package {0}": "未找到適用於套件的安裝程式 {0}", + "Integrity checks will not be performed during this operation": "此操作期間不會執行完整性檢查", + "This is not recommended.": "不建議這麼做。", + "Run now": "立即執行", + "Run next": "排下一個執行", + "Run last": "排最後執行", + "Show in explorer": "在瀏覽器中顯示", + "Checked": "已勾選", + "Unchecked": "未勾選", + "This package is already installed": "此套件已安裝", + "This package can be upgraded to version {0}": "此套件可以被更新至版本 {0}", + "Updates for this package are ignored": "此套件已忽略的更新", + "This package is being processed": "正在處理此套件", + "This package is not available": "目前無法使用此套件", + "Select the source you want to add:": "選擇想要新增的來源:", + "Source name:": "來源名稱:", + "Source URL:": "來源網站:", + "An error occurred when adding the source: ": "一個執行錯誤於新增來源時", + "Package management made easy": "套件管理變的簡單", + "version {0}": "版本{0}", + "[RAN AS ADMINISTRATOR]": "以系統管理員身份執行", + "Portable mode": "便攜模式", + "DEBUG BUILD": "偵錯建置", + "Here you can change UniGetUI's behaviour regarding the following shortcuts. Checking a shortcut will make UniGetUI delete it if if gets created on a future upgrade. Unchecking it will keep the shortcut intact": "在這裡,您可以更改 UniGetUI 關於以下快速鍵的行為。勾選某個快速鍵將使 UniGetUI 在未來更新時刪除它。取消勾選則會保留該快速鍵不變。", + "Manual scan": "手動掃描", + "Existing shortcuts on your desktop will be scanned, and you will need to pick which ones to keep and which ones to remove.": "您桌面上的現有捷徑將被掃描,您需要選擇要保留的捷徑以及要移除的捷徑", + "Delete?": "刪除?", + "I understand": "我了解", + "Chocolatey setup changed": "Chocolatey 設定已變更", + "UniGetUI no longer includes its own private Chocolatey installation. A legacy UniGetUI-managed Chocolatey installation was detected for this user profile, but system Chocolatey was not found. Chocolatey will stay unavailable in UniGetUI until Chocolatey is installed on the system and UniGetUI is restarted. Applications previously installed through UniGetUI's bundled Chocolatey may still appear under other sources such as Local PC or WinGet.": "UniGetUI 不再包含自帶的 Chocolatey 安裝。已偵測到此使用者設定檔中由 UniGetUI 管理的舊版 Chocolatey 安裝,但未找到系統 Chocolatey。在系統安裝 Chocolatey 並重新啟動 UniGetUI 之前,Chocolatey 將在 UniGetUI 中保持不可用狀態。先前透過 UniGetUI 內建 Chocolatey 安裝的應用程式可能仍會顯示在其他來源中,例如本機電腦或 WinGet。", + "NOTE: This troubleshooter can be disabled from UniGetUI Settings, on the WinGet section": "備註:此疑難排解程式可以從 UniGetUI 設定中停用,位於 WinGet 設定中。", + "Restart": "重新啟動", + "Are you sure you want to delete all shortcuts?": "您確定要刪除所有捷徑嗎?", + "Any new shorcuts created during an install or an update operation will be deleted automatically, instead of showing a confirmation prompt the first time they are detected.": "任何在安裝或更新操作期間建立的新捷徑,都會自動刪除,而不會在第一次檢測到時顯示確認提示", + "Any shorcuts created or modified outside of UniGetUI will be ignored. You will be able to add them via the {0} button.": "任何在 UniGetUI 外建立或修改的捷徑都將被忽略 您可以通過 {0} 按鈕來新增它們", + "Are you really sure you want to enable this feature?": "您確定真的要啟用此功能嗎?", + "No new shortcuts were found during the scan.": "掃描過程中未發現新的捷徑。", + "How to add packages to a bundle": "如何將套件加入套件包", + "In order to add packages to a bundle, you will need to: ": "為了將套件加入套件包,您需要:", + "1. Navigate to the \"{0}\" or \"{1}\" page.": "1. 導覽至 {0} 或 {1}頁", + "2. Locate the package(s) you want to add to the bundle, and select their leftmost checkbox.": "2. 找到想要加入套件包的套件,並選擇左方的核取方塊", + "3. When the packages you want to add to the bundle are selected, find and click the option \"{0}\" on the toolbar.": "3. 當選擇了想要加入套件包的套件後,請在工具列上找到並點擊 {0} 選項", + "4. Your packages will have been added to the bundle. You can continue adding packages, or export the bundle.": "4. 您的套件已成功加入套件包。您可以繼續添加套件,或者匯出套件包", + "Which backup do you want to open?": "您要開啟哪個備份?", + "Select the backup you want to open. Later, you will be able to review which packages you want to install.": "選擇您要開啟的備份。稍後,您將可檢視要還原的套件/程式。", + "There are ongoing operations. Quitting UniGetUI may cause them to fail. Do you want to continue?": "目前有正在進行的操作。退出 UniGetUI 可能會導致這些操作失敗。您確定要繼續嗎?", + "UniGetUI or some of its components are missing or corrupt.": "UniGetUI 或其某些元件遺失或損毀。", + "It is strongly recommended to reinstall UniGetUI to adress the situation.": "強烈建議重新安裝 UniGetUI 以解決問題。", + "Refer to the UniGetUI Logs to get more details regarding the affected file(s)": "請參閱 UniGetUI 紀錄,以取得有關受影響檔案的詳細資訊", + "Integrity checks can be disabled from the Experimental Settings": "可從實驗設定停用完整性檢查。", + "Repair UniGetUI": "修復 UniGetUI", + "Live output": "即時輸出", + "This package bundle had some settings that are potentially dangerous, and may be ignored by default.": "此套件包有一些潛在危險的設定,可能會被預設忽略。", + "Entries that show in YELLOW will be IGNORED.": "顯示黃色的項目將被忽略。", + "Entries that show in RED will be IMPORTED.": "顯示為紅色的項目將會被輸入。", + "You can change this behavior on UniGetUI security settings.": "您可以在 UniGetUI 安全設定中變更此行為。", + "Open UniGetUI security settings": "開啟 UniGetUI 安全設定", + "Should you modify the security settings, you will need to open the bundle again for the changes to take effect.": "如果您修改了安全設定,您將需要再次打開套件包才能使修改生效。", + "Details of the report:": "報告的詳細內容:", + "Are you sure you want to create a new package bundle? ": "您確定要建立一個新的套件組合嗎?", + "Any unsaved changes will be lost": "任何未儲存的變更將會遺失", + "Warning!": "警告!", + "For security reasons, custom command-line arguments are disabled by default. Go to UniGetUI security settings to change this. ": "基於安全理由,自訂指令列參數預設為停用。請前往 UniGetUI 安全性設定變更。", + "Change default options": "變更預設選項", + "Ignore future updates for this package": "略過此套件未來的更新", + "For security reasons, pre-operation and post-operation scripts are disabled by default. Go to UniGetUI security settings to change this. ": "基於安全理由,預設停用作業前與作業後指令碼。前往 UniGetUI 安全性設定變更此設定。", + "You can define the commands that will be run before or after this package is installed, updated or uninstalled. They will be run on a command prompt, so CMD scripts will work here.": "您可以自訂在安裝、更新或解除安裝此套件之前或之後執行的指令。這些指令會在命令提示字元上執行,因此命令提示字元腳本在此也能運作。", + "Change this and unlock": "變更此選項並解鎖", + "{0} Install options are currently locked because {0} follows the default install options.": "{0} 安裝選項目前已鎖定,因為{0}遵循預設安裝選項。", + "Unset or unknown": "尚未設定或未知", + "This package has no screenshots or is missing the icon? Contrbute to UniGetUI by adding the missing icons and screenshots to our open, public database.": "此套件沒有螢幕截圖或圖示嗎?您可以向 UniGetUI 開放資料庫提供這些項目。", + "Become a contributor": "成為一位協作者", + "Update to {0} available": "{0} 有可用的更新", + "Reinstall": "重新安裝", + "Installer not available": "安裝程式無法使用", + "Version:": "版本:", + "UniGetUI Version {0}": "UniGetUI 版本 {0}", + "Performing backup, please wait...": "正在備份中,請稍後...", + "An error occurred while logging in: ": "登入時發生錯誤:", + "Fetching available backups...": "擷取可用備份...", + "Done!": "完成!", + "The cloud backup has been loaded successfully.": "雲端備份已成功載入。", + "An error occurred while loading a backup: ": "載入備份時發生錯誤:", + "Backing up packages to GitHub Gist...": "備份套件到 GitHub Gist...", + "Backup Successful": "備份成功", + "The cloud backup completed successfully.": "雲端備份成功完成。", + "Could not back up packages to GitHub Gist: ": "無法將套件備份至 GitHub Gist:", + "It is not guaranteed that the provided credentials will be stored safely, so you may as well not use the credentials of your bank account": "無法保證所提供的憑證會被安全地儲存,因此您可以不使用銀行帳戶的憑證", + "Enable the automatic WinGet troubleshooter": "啟用 WinGet 自動疑難排解程式", + "Add updates that fail with a 'no applicable update found' to the ignored updates list": "將更新失敗並顯示「未找到適用更新」的項目新增至忽略更新清單", + "Invalid selection": "無效的選取", + "No package was selected": "沒有套件被選取", + "More than 1 package was selected": "已選取超過一個套件", + "List": "清單", + "Grid": "並排", + "Icons": "圖示", + "\"{0}\" is a local package and does not have available details": "\"{0}\"是本機套件,沒有可以顯示的詳細資料", + "\"{0}\" is a local package and is not compatible with this feature": "\"{0}\"是本機套件,與此功能不相容", + "Add packages to bundle": "將套件新增至套件包", + "Preparing packages, please wait...": "準備套件包中,請稍後...", + "Loading packages, please wait...": "正在載入套件,請稍候...", + "Saving packages, please wait...": "正在儲存套件,請稍候...", + "The bundle was created successfully on {0}": "成功建立於 {0}", + "User profile": "使用者設定檔", + "Error": "錯誤", + "Log in failed: ": "登入失敗:", + "Log out failed: ": "登出失敗:", + "Package backup settings": "套件備份設定", + "Package managers": "套件管理員", + "Manage UniGetUI autostart behaviour from the Settings app": "在設定應用程式中管理 UniGetUI 的自動啟動行為", + "Choose how many operations shoulds be performed in parallel": "選擇要同時執行的操作數量", + "Something went wrong while launching the updater.": "啟動更新程式時發生錯誤。", + "Please try again later": "請稍後再試", + "Installer host changed since the installed version.\nOld: {0}\nNew: {1}\n\nThis is usually harmless (the publisher moved hosting), but can also indicate a hijacked package manifest. Verify the new source before upgrading.": "安裝程式主機在已安裝版本之後變更。\n舊版: {0}\n新版: {1}\n\n這通常無害(發布者移動了主機),但也可能表示套件描述檔已被劫持。更新前請驗證新來源。", + "Show the release notes after UniGetUI is updated": "在 UniGetUI 更新後顯示版本更新說明" +} diff --git a/src/Shared/AutoUpdater.Helpers.cs b/src/Shared/AutoUpdater.Helpers.cs new file mode 100644 index 0000000..291b3ec --- /dev/null +++ b/src/Shared/AutoUpdater.Helpers.cs @@ -0,0 +1,156 @@ +using System.Runtime.InteropServices; +using Microsoft.Win32; +using UniGetUI.Core.Logging; +using UniGetUI.Core.Tools; + +namespace UniGetUI.Shared; + +internal static class AutoUpdaterHelpers +{ + internal static bool IsSourceUrlAllowed(string url, bool allowUnsafeUrls) + { + if (!Uri.TryCreate(url, UriKind.Absolute, out Uri? uri)) + { + return false; + } + + if (allowUnsafeUrls) + { + Logger.Warn($"Registry override enabled: allowing potentially unsafe updater URL {url}"); + return true; + } + + if (!string.Equals(uri.Scheme, Uri.UriSchemeHttps, StringComparison.OrdinalIgnoreCase)) + { + return false; + } + + return uri.Host.Equals("devolutions.net", StringComparison.OrdinalIgnoreCase) + || uri.Host.EndsWith(".devolutions.net", StringComparison.OrdinalIgnoreCase) + || uri.Host.Equals("github.com", StringComparison.OrdinalIgnoreCase) + || uri.Host.Equals("objects.githubusercontent.com", StringComparison.OrdinalIgnoreCase) + || uri.Host.Equals( + "release-assets.githubusercontent.com", + StringComparison.OrdinalIgnoreCase + ); + } + + internal static ProductInfoFile SelectInstallerFile(List files) + { + string targetArch = RuntimeInformation.ProcessArchitecture switch + { + Architecture.Arm64 => "arm64", + Architecture.X64 => "x64", + _ => "x64", + }; + + ProductInfoFile? match = files.FirstOrDefault(file => + file.Type.Equals("exe", StringComparison.OrdinalIgnoreCase) + && file.Arch.Equals(targetArch, StringComparison.OrdinalIgnoreCase) + ); + + match ??= files.FirstOrDefault(file => + file.Type.Equals("exe", StringComparison.OrdinalIgnoreCase) + && file.Arch.Equals("Any", StringComparison.OrdinalIgnoreCase) + ); + + match ??= files.FirstOrDefault(file => + file.Type.Equals("msi", StringComparison.OrdinalIgnoreCase) + && file.Arch.Equals(targetArch, StringComparison.OrdinalIgnoreCase) + ); + + match ??= files.FirstOrDefault(file => + file.Type.Equals("msi", StringComparison.OrdinalIgnoreCase) + && file.Arch.Equals("Any", StringComparison.OrdinalIgnoreCase) + ); + + if (match is null) + { + throw new KeyNotFoundException( + $"No compatible installer file found in productinfo for architecture '{targetArch}'" + ); + } + + return match; + } + + internal static Version ParseVersionOrFallback(string rawVersion, Version fallbackVersion) + { + if (Version.TryParse(rawVersion, out Version? parsed)) + { + return CoreTools.NormalizeVersionForComparison(parsed); + } + + string sanitized = rawVersion.Trim().TrimStart('v', 'V'); + if (Version.TryParse(sanitized, out parsed)) + { + return CoreTools.NormalizeVersionForComparison(parsed); + } + + Logger.Warn($"Could not parse version '{rawVersion}', using fallback '{fallbackVersion}'"); + return fallbackVersion; + } + + internal static string NormalizeThumbprint(string thumbprint) + { + char[] normalized = thumbprint.ToLowerInvariant().Where(char.IsAsciiHexDigit).ToArray(); + + return new string(normalized); + } + + internal static string? GetRegistryString(RegistryKey? key, string valueName) + { +#pragma warning disable CA1416 + object? value = key?.GetValue(valueName); +#pragma warning restore CA1416 + if (value is null) + { + return null; + } + + string? parsedValue = value.ToString(); + if (string.IsNullOrWhiteSpace(parsedValue)) + { + return null; + } + + return parsedValue.Trim(); + } + +#if DEBUG + internal static bool GetRegistryBool(RegistryKey? key, string valueName) + { +#pragma warning disable CA1416 + object? value = key?.GetValue(valueName); +#pragma warning restore CA1416 + if (value is null) + { + return false; + } + + if (value is int intValue) + { + return intValue != 0; + } + + if (value is long longValue) + { + return longValue != 0; + } + + string normalized = value.ToString()?.Trim() ?? ""; + return normalized.Equals("1", StringComparison.OrdinalIgnoreCase) + || normalized.Equals("true", StringComparison.OrdinalIgnoreCase) + || normalized.Equals("yes", StringComparison.OrdinalIgnoreCase) + || normalized.Equals("on", StringComparison.OrdinalIgnoreCase); + } +#endif + + internal sealed class ProductInfoFile + { + public string Arch { get; set; } = string.Empty; + public string Type { get; set; } = string.Empty; + public string Url { get; set; } = string.Empty; + public string Hash { get; set; } = string.Empty; + } +} diff --git a/src/Shared/SharedPreUiCommandDispatcher.cs b/src/Shared/SharedPreUiCommandDispatcher.cs new file mode 100644 index 0000000..e3595b0 --- /dev/null +++ b/src/Shared/SharedPreUiCommandDispatcher.cs @@ -0,0 +1,428 @@ +using UniGetUI.Core.Logging; +using UniGetUI.Core.SettingsEngine; +using UniGetUI.Core.SettingsEngine.SecureSettings; +using UniGetUI.Core.Tools; + +namespace UniGetUI.Shared; + +internal readonly record struct SharedPreUiCommandExitCodes( + int Success, + int Failed, + int InvalidParameter, + int NoSuchFile, + int UnknownSettingsKey +); + +internal static class SharedPreUiCommandDispatcher +{ + internal static readonly SharedPreUiCommandExitCodes WindowsCliExitCodes = new( + Success: 0, + Failed: -1, + InvalidParameter: -1073741811, + NoSuchFile: -1073741809, + UnknownSettingsKey: -2 + ); + + internal static readonly SharedPreUiCommandExitCodes PortableCliExitCodes = new( + Success: 0, + Failed: 1, + InvalidParameter: 2, + NoSuchFile: 3, + UnknownSettingsKey: 4 + ); + + internal const string HelpArgument = "--help"; + internal const string ImportSettingsArgument = "--import-settings"; + internal const string ExportSettingsArgument = "--export-settings"; + internal const string EnableSettingArgument = "--enable-setting"; + internal const string DisableSettingArgument = "--disable-setting"; + internal const string SetSettingValueArgument = "--set-setting-value"; + internal const string EnableSecureSettingArgument = "--enable-secure-setting"; + internal const string DisableSecureSettingArgument = "--disable-secure-setting"; + internal const string MigrateWingetUIToUniGetUIArgument = "--migrate-wingetui-to-unigetui"; + internal const string UninstallWingetUIArgument = "--uninstall-wingetui"; + internal const string UninstallUniGetUIArgument = "--uninstall-unigetui"; + + private const string EnableSecureSettingForUserArgument = SecureSettings.Args.ENABLE_FOR_USER; + private const string DisableSecureSettingForUserArgument = SecureSettings.Args.DISABLE_FOR_USER; + + public static int? TryHandle(IReadOnlyList args, SharedPreUiCommandExitCodes exitCodes) + { + if (args.Contains(HelpArgument)) + { + return Help(); + } + + if (args.Contains(ImportSettingsArgument)) + { + return ImportSettings(args, exitCodes); + } + + if (args.Contains(ExportSettingsArgument)) + { + return ExportSettings(args, exitCodes); + } + + if (args.Contains(EnableSettingArgument)) + { + return EnableSetting(args, exitCodes); + } + + if (args.Contains(DisableSettingArgument)) + { + return DisableSetting(args, exitCodes); + } + + if (args.Contains(SetSettingValueArgument)) + { + return SetSettingValue(args, exitCodes); + } + + if (args.Contains(EnableSecureSettingArgument)) + { + return EnableSecureSetting(args, exitCodes); + } + + if (args.Contains(DisableSecureSettingArgument)) + { + return DisableSecureSetting(args, exitCodes); + } + + if (args.Contains(EnableSecureSettingForUserArgument)) + { + return EnableSecureSettingForUser(args, exitCodes); + } + + if (args.Contains(DisableSecureSettingForUserArgument)) + { + return DisableSecureSettingForUser(args, exitCodes); + } + + if (args.Contains(MigrateWingetUIToUniGetUIArgument)) + { + return MigrateWingetUIToUniGetUI(); + } + + if (args.Contains(UninstallWingetUIArgument) || args.Contains(UninstallUniGetUIArgument)) + { + return exitCodes.Success; + } + + return null; + } + + public static int Help() + { + CoreTools.Launch( + "https://github.com/Devolutions/UniGetUI/blob/main/docs/CLI.md#unigetui-command-line-interface" + ); + return 0; + } + + public static int ImportSettings(IReadOnlyList args, SharedPreUiCommandExitCodes exitCodes) + { + if (!TryGetValueAfterArgument(args, ImportSettingsArgument, 1, out string file)) + { + return exitCodes.InvalidParameter; + } + + if (!File.Exists(file)) + { + return exitCodes.NoSuchFile; + } + + try + { + Settings.ImportFromFile_JSON(file); + return exitCodes.Success; + } + catch (Exception ex) + { + return ex.HResult; + } + } + + public static int ExportSettings(IReadOnlyList args, SharedPreUiCommandExitCodes exitCodes) + { + if (!TryGetValueAfterArgument(args, ExportSettingsArgument, 1, out string file)) + { + return exitCodes.InvalidParameter; + } + + try + { + Settings.ExportToFile_JSON(file); + return exitCodes.Success; + } + catch (Exception ex) + { + return ex.HResult; + } + } + + public static int EnableSetting(IReadOnlyList args, SharedPreUiCommandExitCodes exitCodes) + { + if (!TryGetEnumArgument(args, EnableSettingArgument, out Settings.K validKey)) + { + return GetEnumArgumentErrorCode(args, EnableSettingArgument, exitCodes); + } + + try + { + Settings.Set(validKey, true); + return exitCodes.Success; + } + catch (Exception ex) + { + return ex.HResult; + } + } + + public static int DisableSetting(IReadOnlyList args, SharedPreUiCommandExitCodes exitCodes) + { + if (!TryGetEnumArgument(args, DisableSettingArgument, out Settings.K validKey)) + { + return GetEnumArgumentErrorCode(args, DisableSettingArgument, exitCodes); + } + + try + { + Settings.Set(validKey, false); + return exitCodes.Success; + } + catch (Exception ex) + { + return ex.HResult; + } + } + + public static int SetSettingValue(IReadOnlyList args, SharedPreUiCommandExitCodes exitCodes) + { + if (!TryGetValueAfterArgument(args, SetSettingValueArgument, 1, out string setting)) + { + return exitCodes.InvalidParameter; + } + + if (!TryGetValueAfterArgument(args, SetSettingValueArgument, 2, out string value)) + { + return exitCodes.InvalidParameter; + } + + if (!Enum.TryParse(setting, out Settings.K validKey)) + { + return exitCodes.UnknownSettingsKey; + } + + try + { + Settings.SetValue(validKey, value); + return exitCodes.Success; + } + catch (Exception ex) + { + return ex.HResult; + } + } + + public static int EnableSecureSetting(IReadOnlyList args, SharedPreUiCommandExitCodes exitCodes) + { + if (!TryGetEnumArgument(args, EnableSecureSettingArgument, out SecureSettings.K validKey)) + { + return GetEnumArgumentErrorCode(args, EnableSecureSettingArgument, exitCodes); + } + + try + { + bool success = SecureSettings.TrySet(validKey, true).GetAwaiter().GetResult(); + return success ? exitCodes.Success : exitCodes.Failed; + } + catch (Exception ex) + { + return ex.HResult; + } + } + + public static int DisableSecureSetting(IReadOnlyList args, SharedPreUiCommandExitCodes exitCodes) + { + if (!TryGetEnumArgument(args, DisableSecureSettingArgument, out SecureSettings.K validKey)) + { + return GetEnumArgumentErrorCode(args, DisableSecureSettingArgument, exitCodes); + } + + try + { + bool success = SecureSettings.TrySet(validKey, false).GetAwaiter().GetResult(); + return success ? exitCodes.Success : exitCodes.Failed; + } + catch (Exception ex) + { + return ex.HResult; + } + } + + public static int EnableSecureSettingForUser(IReadOnlyList args, SharedPreUiCommandExitCodes exitCodes) + { + if (!TryGetValueAfterArgument(args, EnableSecureSettingForUserArgument, 1, out string user)) + { + return exitCodes.InvalidParameter; + } + + if (!TryGetValueAfterArgument(args, EnableSecureSettingForUserArgument, 2, out string setting)) + { + return exitCodes.InvalidParameter; + } + + try + { + return SecureSettings.ApplyForUser(user, setting, true); + } + catch (Exception ex) + { + return ex.HResult; + } + } + + public static int DisableSecureSettingForUser(IReadOnlyList args, SharedPreUiCommandExitCodes exitCodes) + { + if (!TryGetValueAfterArgument(args, DisableSecureSettingForUserArgument, 1, out string user)) + { + return exitCodes.InvalidParameter; + } + + if (!TryGetValueAfterArgument(args, DisableSecureSettingForUserArgument, 2, out string setting)) + { + return exitCodes.InvalidParameter; + } + + try + { + return SecureSettings.ApplyForUser(user, setting, false); + } + catch (Exception ex) + { + return ex.HResult; + } + } + + public static int MigrateWingetUIToUniGetUI() + { + try + { + string[] basePaths = + [ + Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory), + Environment.GetFolderPath(Environment.SpecialFolder.StartMenu), + Environment.GetFolderPath(Environment.SpecialFolder.CommonDesktopDirectory), + Environment.GetFolderPath(Environment.SpecialFolder.CommonStartMenu), + ]; + + foreach (string path in basePaths) + { + foreach ( + string oldWingetUIIcon in new[] + { + "WingetUI.lnk", + "WingetUI .lnk", + "UniGetUI (formerly WingetUI) .lnk", + "UniGetUI (formerly WingetUI).lnk", + } + ) + { + try + { + string oldFile = Path.Join(path, oldWingetUIIcon); + string newFile = Path.Join(path, "UniGetUI.lnk"); + if (!File.Exists(oldFile)) + { + continue; + } + + if (File.Exists(newFile)) + { + Logger.Info( + "Deleting shortcut " + + oldFile + + " since new shortcut already exists" + ); + File.Delete(oldFile); + } + else + { + Logger.Info("Moving shortcut to " + newFile); + File.Move(oldFile, newFile); + } + } + catch (Exception ex) + { + Logger.Warn( + $"An error occurred while migrating the shortcut {Path.Join(path, oldWingetUIIcon)}" + ); + Logger.Warn(ex); + } + } + } + + return 0; + } + catch (Exception ex) + { + Logger.Error(ex); + return ex.HResult; + } + } + + private static bool TryGetValueAfterArgument( + IReadOnlyList args, + string argument, + int offset, + out string value + ) + { + int basePos = FindArgumentIndex(args, argument); + if (basePos < 0 || basePos + offset >= args.Count) + { + value = string.Empty; + return false; + } + + value = args[basePos + offset].Trim('"').Trim('\''); + return true; + } + + private static bool TryGetEnumArgument( + IReadOnlyList args, + string argument, + out TEnum value + ) where TEnum : struct + { + if (!TryGetValueAfterArgument(args, argument, 1, out string rawValue)) + { + value = default; + return false; + } + + return Enum.TryParse(rawValue, out value); + } + + private static int GetEnumArgumentErrorCode( + IReadOnlyList args, + string argument, + SharedPreUiCommandExitCodes exitCodes + ) + { + return TryGetValueAfterArgument(args, argument, 1, out _) ? exitCodes.UnknownSettingsKey : exitCodes.InvalidParameter; + } + + private static int FindArgumentIndex(IReadOnlyList args, string argument) + { + for (int i = 0; i < args.Count; i++) + { + if (string.Equals(args[i], argument, StringComparison.Ordinal)) + { + return i; + } + } + + return -1; + } +} diff --git a/src/SharedAssemblyInfo.cs b/src/SharedAssemblyInfo.cs new file mode 100644 index 0000000..c0f566d --- /dev/null +++ b/src/SharedAssemblyInfo.cs @@ -0,0 +1,17 @@ +using System.Reflection; +#if WINDOWS +using System.Runtime.Versioning; +#endif + +[assembly: AssemblyProduct("UniGetUI")] +[assembly: AssemblyDescription("UniGetUI")] +[assembly: AssemblyTitle("UniGetUI")] +[assembly: AssemblyDefaultAlias("UniGetUI")] +[assembly: AssemblyCompany("Devolutions Inc.")] +[assembly: AssemblyCopyright("Copyright 2021-2026 Devolutions Inc.")] +[assembly: AssemblyVersion("3.3.7.0")] +[assembly: AssemblyFileVersion("3.3.7.0")] +[assembly: AssemblyInformationalVersion("3.3.7")] +#if WINDOWS +[assembly: SupportedOSPlatform("windows10.0.19041")] +#endif diff --git a/src/SharedAssets/Assets/Images/admin_color.png b/src/SharedAssets/Assets/Images/admin_color.png new file mode 100644 index 0000000..402a8a6 Binary files /dev/null and b/src/SharedAssets/Assets/Images/admin_color.png differ diff --git a/src/SharedAssets/Assets/Images/agreement.png b/src/SharedAssets/Assets/Images/agreement.png new file mode 100644 index 0000000..4ccf283 Binary files /dev/null and b/src/SharedAssets/Assets/Images/agreement.png differ diff --git a/src/SharedAssets/Assets/Images/alert_laptop.png b/src/SharedAssets/Assets/Images/alert_laptop.png new file mode 100644 index 0000000..59a89f2 Binary files /dev/null and b/src/SharedAssets/Assets/Images/alert_laptop.png differ diff --git a/src/SharedAssets/Assets/Images/cancel.png b/src/SharedAssets/Assets/Images/cancel.png new file mode 100644 index 0000000..2b0dfd2 Binary files /dev/null and b/src/SharedAssets/Assets/Images/cancel.png differ diff --git a/src/SharedAssets/Assets/Images/cargo_color.png b/src/SharedAssets/Assets/Images/cargo_color.png new file mode 100644 index 0000000..293e76f Binary files /dev/null and b/src/SharedAssets/Assets/Images/cargo_color.png differ diff --git a/src/SharedAssets/Assets/Images/checked_laptop.png b/src/SharedAssets/Assets/Images/checked_laptop.png new file mode 100644 index 0000000..a4ff892 Binary files /dev/null and b/src/SharedAssets/Assets/Images/checked_laptop.png differ diff --git a/src/SharedAssets/Assets/Images/choco_color.png b/src/SharedAssets/Assets/Images/choco_color.png new file mode 100644 index 0000000..3f8b06e Binary files /dev/null and b/src/SharedAssets/Assets/Images/choco_color.png differ diff --git a/src/SharedAssets/Assets/Images/coffee.png b/src/SharedAssets/Assets/Images/coffee.png new file mode 100644 index 0000000..e359434 Binary files /dev/null and b/src/SharedAssets/Assets/Images/coffee.png differ diff --git a/src/SharedAssets/Assets/Images/console_color.png b/src/SharedAssets/Assets/Images/console_color.png new file mode 100644 index 0000000..da90fe9 Binary files /dev/null and b/src/SharedAssets/Assets/Images/console_color.png differ diff --git a/src/SharedAssets/Assets/Images/desktop_download.png b/src/SharedAssets/Assets/Images/desktop_download.png new file mode 100644 index 0000000..5383826 Binary files /dev/null and b/src/SharedAssets/Assets/Images/desktop_download.png differ diff --git a/src/SharedAssets/Assets/Images/dotnet_color.png b/src/SharedAssets/Assets/Images/dotnet_color.png new file mode 100644 index 0000000..6d9caab Binary files /dev/null and b/src/SharedAssets/Assets/Images/dotnet_color.png differ diff --git a/src/SharedAssets/Assets/Images/finish.png b/src/SharedAssets/Assets/Images/finish.png new file mode 100644 index 0000000..d92ae0c Binary files /dev/null and b/src/SharedAssets/Assets/Images/finish.png differ diff --git a/src/SharedAssets/Assets/Images/github.png b/src/SharedAssets/Assets/Images/github.png new file mode 100644 index 0000000..b95227d Binary files /dev/null and b/src/SharedAssets/Assets/Images/github.png differ diff --git a/src/SharedAssets/Assets/Images/hacker.png b/src/SharedAssets/Assets/Images/hacker.png new file mode 100644 index 0000000..0373a48 Binary files /dev/null and b/src/SharedAssets/Assets/Images/hacker.png differ diff --git a/src/SharedAssets/Assets/Images/icon.bmp b/src/SharedAssets/Assets/Images/icon.bmp new file mode 100644 index 0000000..2657295 Binary files /dev/null and b/src/SharedAssets/Assets/Images/icon.bmp differ diff --git a/src/SharedAssets/Assets/Images/icon.ico b/src/SharedAssets/Assets/Images/icon.ico new file mode 100644 index 0000000..c32fc09 Binary files /dev/null and b/src/SharedAssets/Assets/Images/icon.ico differ diff --git a/src/SharedAssets/Assets/Images/icon.png b/src/SharedAssets/Assets/Images/icon.png new file mode 100644 index 0000000..8b9c6dd Binary files /dev/null and b/src/SharedAssets/Assets/Images/icon.png differ diff --git a/src/SharedAssets/Assets/Images/icon_unsquare.png b/src/SharedAssets/Assets/Images/icon_unsquare.png new file mode 100644 index 0000000..8b9c6dd Binary files /dev/null and b/src/SharedAssets/Assets/Images/icon_unsquare.png differ diff --git a/src/SharedAssets/Assets/Images/infocolor.png b/src/SharedAssets/Assets/Images/infocolor.png new file mode 100644 index 0000000..2ad78e2 Binary files /dev/null and b/src/SharedAssets/Assets/Images/infocolor.png differ diff --git a/src/SharedAssets/Assets/Images/kofi.png b/src/SharedAssets/Assets/Images/kofi.png new file mode 100644 index 0000000..660f4ad Binary files /dev/null and b/src/SharedAssets/Assets/Images/kofi.png differ diff --git a/src/SharedAssets/Assets/Images/node_color.png b/src/SharedAssets/Assets/Images/node_color.png new file mode 100644 index 0000000..afbfbae Binary files /dev/null and b/src/SharedAssets/Assets/Images/node_color.png differ diff --git a/src/SharedAssets/Assets/Images/package_color.png b/src/SharedAssets/Assets/Images/package_color.png new file mode 100644 index 0000000..5faf17c Binary files /dev/null and b/src/SharedAssets/Assets/Images/package_color.png differ diff --git a/src/SharedAssets/Assets/Images/pin_color.png b/src/SharedAssets/Assets/Images/pin_color.png new file mode 100644 index 0000000..d9d71f1 Binary files /dev/null and b/src/SharedAssets/Assets/Images/pin_color.png differ diff --git a/src/SharedAssets/Assets/Images/pip_color.png b/src/SharedAssets/Assets/Images/pip_color.png new file mode 100644 index 0000000..4ac2864 Binary files /dev/null and b/src/SharedAssets/Assets/Images/pip_color.png differ diff --git a/src/SharedAssets/Assets/Images/powershell_color.png b/src/SharedAssets/Assets/Images/powershell_color.png new file mode 100644 index 0000000..1d70cc1 Binary files /dev/null and b/src/SharedAssets/Assets/Images/powershell_color.png differ diff --git a/src/SharedAssets/Assets/Images/restart_color.png b/src/SharedAssets/Assets/Images/restart_color.png new file mode 100644 index 0000000..1288675 Binary files /dev/null and b/src/SharedAssets/Assets/Images/restart_color.png differ diff --git a/src/SharedAssets/Assets/Images/rocket.png b/src/SharedAssets/Assets/Images/rocket.png new file mode 100644 index 0000000..73de5f2 Binary files /dev/null and b/src/SharedAssets/Assets/Images/rocket.png differ diff --git a/src/SharedAssets/Assets/Images/save.png b/src/SharedAssets/Assets/Images/save.png new file mode 100644 index 0000000..05c9ae0 Binary files /dev/null and b/src/SharedAssets/Assets/Images/save.png differ diff --git a/src/SharedAssets/Assets/Images/scoop_color.png b/src/SharedAssets/Assets/Images/scoop_color.png new file mode 100644 index 0000000..997107a Binary files /dev/null and b/src/SharedAssets/Assets/Images/scoop_color.png differ diff --git a/src/SharedAssets/Assets/Images/settings_gear.png b/src/SharedAssets/Assets/Images/settings_gear.png new file mode 100644 index 0000000..4ca508b Binary files /dev/null and b/src/SharedAssets/Assets/Images/settings_gear.png differ diff --git a/src/SharedAssets/Assets/Images/shield_green.png b/src/SharedAssets/Assets/Images/shield_green.png new file mode 100644 index 0000000..43d2bd9 Binary files /dev/null and b/src/SharedAssets/Assets/Images/shield_green.png differ diff --git a/src/SharedAssets/Assets/Images/shield_question.png b/src/SharedAssets/Assets/Images/shield_question.png new file mode 100644 index 0000000..0a86403 Binary files /dev/null and b/src/SharedAssets/Assets/Images/shield_question.png differ diff --git a/src/SharedAssets/Assets/Images/shield_red.png b/src/SharedAssets/Assets/Images/shield_red.png new file mode 100644 index 0000000..12e2036 Binary files /dev/null and b/src/SharedAssets/Assets/Images/shield_red.png differ diff --git a/src/SharedAssets/Assets/Images/shield_reload.png b/src/SharedAssets/Assets/Images/shield_reload.png new file mode 100644 index 0000000..0845858 Binary files /dev/null and b/src/SharedAssets/Assets/Images/shield_reload.png differ diff --git a/src/SharedAssets/Assets/Images/shield_yellow.png b/src/SharedAssets/Assets/Images/shield_yellow.png new file mode 100644 index 0000000..e33c2d4 Binary files /dev/null and b/src/SharedAssets/Assets/Images/shield_yellow.png differ diff --git a/src/SharedAssets/Assets/Images/simple_user.png b/src/SharedAssets/Assets/Images/simple_user.png new file mode 100644 index 0000000..31efaef Binary files /dev/null and b/src/SharedAssets/Assets/Images/simple_user.png differ diff --git a/src/SharedAssets/Assets/Images/tick.png b/src/SharedAssets/Assets/Images/tick.png new file mode 100644 index 0000000..d1eff99 Binary files /dev/null and b/src/SharedAssets/Assets/Images/tick.png differ diff --git a/src/SharedAssets/Assets/Images/tray_blue_black_legacy.ico b/src/SharedAssets/Assets/Images/tray_blue_black_legacy.ico new file mode 100644 index 0000000..d2ddfdb Binary files /dev/null and b/src/SharedAssets/Assets/Images/tray_blue_black_legacy.ico differ diff --git a/src/SharedAssets/Assets/Images/tray_blue_white_legacy.ico b/src/SharedAssets/Assets/Images/tray_blue_white_legacy.ico new file mode 100644 index 0000000..55781f5 Binary files /dev/null and b/src/SharedAssets/Assets/Images/tray_blue_white_legacy.ico differ diff --git a/src/SharedAssets/Assets/Images/tray_empty_black_legacy.ico b/src/SharedAssets/Assets/Images/tray_empty_black_legacy.ico new file mode 100644 index 0000000..5e80a13 Binary files /dev/null and b/src/SharedAssets/Assets/Images/tray_empty_black_legacy.ico differ diff --git a/src/SharedAssets/Assets/Images/tray_empty_white_legacy.ico b/src/SharedAssets/Assets/Images/tray_empty_white_legacy.ico new file mode 100644 index 0000000..74cff7d Binary files /dev/null and b/src/SharedAssets/Assets/Images/tray_empty_white_legacy.ico differ diff --git a/src/SharedAssets/Assets/Images/tray_green_black_legacy.ico b/src/SharedAssets/Assets/Images/tray_green_black_legacy.ico new file mode 100644 index 0000000..061e5f5 Binary files /dev/null and b/src/SharedAssets/Assets/Images/tray_green_black_legacy.ico differ diff --git a/src/SharedAssets/Assets/Images/tray_green_white_legacy.ico b/src/SharedAssets/Assets/Images/tray_green_white_legacy.ico new file mode 100644 index 0000000..26a6523 Binary files /dev/null and b/src/SharedAssets/Assets/Images/tray_green_white_legacy.ico differ diff --git a/src/SharedAssets/Assets/Images/tray_orange_black_legacy.ico b/src/SharedAssets/Assets/Images/tray_orange_black_legacy.ico new file mode 100644 index 0000000..1573adb Binary files /dev/null and b/src/SharedAssets/Assets/Images/tray_orange_black_legacy.ico differ diff --git a/src/SharedAssets/Assets/Images/tray_orange_white_legacy.ico b/src/SharedAssets/Assets/Images/tray_orange_white_legacy.ico new file mode 100644 index 0000000..21f41fc Binary files /dev/null and b/src/SharedAssets/Assets/Images/tray_orange_white_legacy.ico differ diff --git a/src/SharedAssets/Assets/Images/tray_turquoise_black_legacy.ico b/src/SharedAssets/Assets/Images/tray_turquoise_black_legacy.ico new file mode 100644 index 0000000..9804679 Binary files /dev/null and b/src/SharedAssets/Assets/Images/tray_turquoise_black_legacy.ico differ diff --git a/src/SharedAssets/Assets/Images/tray_turquoise_white_legacy.ico b/src/SharedAssets/Assets/Images/tray_turquoise_white_legacy.ico new file mode 100644 index 0000000..84bb80b Binary files /dev/null and b/src/SharedAssets/Assets/Images/tray_turquoise_white_legacy.ico differ diff --git a/src/SharedAssets/Assets/Images/update_pc_color.png b/src/SharedAssets/Assets/Images/update_pc_color.png new file mode 100644 index 0000000..ab29254 Binary files /dev/null and b/src/SharedAssets/Assets/Images/update_pc_color.png differ diff --git a/src/SharedAssets/Assets/Images/vcpkg_color.png b/src/SharedAssets/Assets/Images/vcpkg_color.png new file mode 100644 index 0000000..eca380a Binary files /dev/null and b/src/SharedAssets/Assets/Images/vcpkg_color.png differ diff --git a/src/SharedAssets/Assets/Images/warn.png b/src/SharedAssets/Assets/Images/warn.png new file mode 100644 index 0000000..33596bf Binary files /dev/null and b/src/SharedAssets/Assets/Images/warn.png differ diff --git a/src/SharedAssets/Assets/Images/winget_color.png b/src/SharedAssets/Assets/Images/winget_color.png new file mode 100644 index 0000000..f8a1581 Binary files /dev/null and b/src/SharedAssets/Assets/Images/winget_color.png differ diff --git a/src/SharedAssets/Assets/Images/workstation.png b/src/SharedAssets/Assets/Images/workstation.png new file mode 100644 index 0000000..ca964d6 Binary files /dev/null and b/src/SharedAssets/Assets/Images/workstation.png differ diff --git a/src/SharedAssets/Assets/Images/youtube.png b/src/SharedAssets/Assets/Images/youtube.png new file mode 100644 index 0000000..2c965aa Binary files /dev/null and b/src/SharedAssets/Assets/Images/youtube.png differ diff --git a/src/SharedAssets/Assets/SplashScreen.png b/src/SharedAssets/Assets/SplashScreen.png new file mode 100644 index 0000000..fdf588d Binary files /dev/null and b/src/SharedAssets/Assets/SplashScreen.png differ diff --git a/src/SharedAssets/Assets/SplashScreen.svg b/src/SharedAssets/Assets/SplashScreen.svg new file mode 100644 index 0000000..732a211 --- /dev/null +++ b/src/SharedAssets/Assets/SplashScreen.svg @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/SharedAssets/Assets/SplashScreen.theme-dark.png b/src/SharedAssets/Assets/SplashScreen.theme-dark.png new file mode 100644 index 0000000..eaaae61 Binary files /dev/null and b/src/SharedAssets/Assets/SplashScreen.theme-dark.png differ diff --git a/src/SharedAssets/Assets/SplashScreen.theme-dark.svg b/src/SharedAssets/Assets/SplashScreen.theme-dark.svg new file mode 100644 index 0000000..47409a3 --- /dev/null +++ b/src/SharedAssets/Assets/SplashScreen.theme-dark.svg @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/SharedAssets/Assets/Square150x150Logo.png b/src/SharedAssets/Assets/Square150x150Logo.png new file mode 100644 index 0000000..d282f9b Binary files /dev/null and b/src/SharedAssets/Assets/Square150x150Logo.png differ diff --git a/src/SharedAssets/Assets/Square44x44Logo.png b/src/SharedAssets/Assets/Square44x44Logo.png new file mode 100644 index 0000000..088c2ab Binary files /dev/null and b/src/SharedAssets/Assets/Square44x44Logo.png differ diff --git a/src/SharedAssets/Assets/StoreLogo.png b/src/SharedAssets/Assets/StoreLogo.png new file mode 100644 index 0000000..0b6e531 Binary files /dev/null and b/src/SharedAssets/Assets/StoreLogo.png differ diff --git a/src/SharedAssets/Assets/Symbols/DiscoverPackage.svg b/src/SharedAssets/Assets/Symbols/DiscoverPackage.svg new file mode 100644 index 0000000..f9f4e3a --- /dev/null +++ b/src/SharedAssets/Assets/Symbols/DiscoverPackage.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/SharedAssets/Assets/Symbols/Filter.svg b/src/SharedAssets/Assets/Symbols/Filter.svg new file mode 100644 index 0000000..5086b2c --- /dev/null +++ b/src/SharedAssets/Assets/Symbols/Filter.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/SharedAssets/Assets/Symbols/Font/Read Me.txt b/src/SharedAssets/Assets/Symbols/Font/Read Me.txt new file mode 100644 index 0000000..723a49e --- /dev/null +++ b/src/SharedAssets/Assets/Symbols/Font/Read Me.txt @@ -0,0 +1,7 @@ +Open *demo.html* to see a list of all the glyphs in your font along with their codes/ligatures. + +To use the generated font in desktop programs, you can install the TTF font. In order to copy the character associated with each icon, refer to the text box at the bottom right corner of each glyph in demo.html. The character inside this text box may be invisible; but it can still be copied. See this guide for more info: https://icomoon.io/docs/#local-fonts + +You won't need any of the files located under the *demo-files* directory when including the generated font in your own projects. + +You can import *selection.json* back to the IcoMoon app using the *Import Icons* button (or via Main Menu → Manage Projects) to retrieve your icon selection. diff --git a/src/SharedAssets/Assets/Symbols/Font/demo-files/demo.css b/src/SharedAssets/Assets/Symbols/Font/demo-files/demo.css new file mode 100644 index 0000000..39b8991 --- /dev/null +++ b/src/SharedAssets/Assets/Symbols/Font/demo-files/demo.css @@ -0,0 +1,152 @@ +body { + padding: 0; + margin: 0; + font-family: sans-serif; + font-size: 1em; + line-height: 1.5; + color: #555; + background: #fff; +} +h1 { + font-size: 1.5em; + font-weight: normal; +} +small { + font-size: .66666667em; +} +a { + color: #e74c3c; + text-decoration: none; +} +a:hover, a:focus { + box-shadow: 0 1px #e74c3c; +} +.bshadow0, input { + box-shadow: inset 0 -2px #e7e7e7; +} +input:hover { + box-shadow: inset 0 -2px #ccc; +} +input, fieldset { + font-family: sans-serif; + font-size: 1em; + margin: 0; + padding: 0; + border: 0; +} +input { + color: inherit; + line-height: 1.5; + height: 1.5em; + padding: .25em 0; +} +input:focus { + outline: none; + box-shadow: inset 0 -2px #449fdb; +} +.glyph { + font-size: 16px; + width: 15em; + padding-bottom: 1em; + margin-right: 4em; + margin-bottom: 1em; + float: left; + overflow: hidden; +} +.liga { + width: 80%; + width: calc(100% - 2.5em); +} +.talign-right { + text-align: right; +} +.talign-center { + text-align: center; +} +.bgc1 { + background: #f1f1f1; +} +.fgc1 { + color: #999; +} +.fgc0 { + color: #000; +} +p { + margin-top: 1em; + margin-bottom: 1em; +} +.mvm { + margin-top: .75em; + margin-bottom: .75em; +} +.mtn { + margin-top: 0; +} +.mtl, .mal { + margin-top: 1.5em; +} +.mbl, .mal { + margin-bottom: 1.5em; +} +.mal, .mhl { + margin-left: 1.5em; + margin-right: 1.5em; +} +.mhmm { + margin-left: 1em; + margin-right: 1em; +} +.mls { + margin-left: .25em; +} +.ptl { + padding-top: 1.5em; +} +.pbs, .pvs { + padding-bottom: .25em; +} +.pvs, .pts { + padding-top: .25em; +} +.unit { + float: left; +} +.unitRight { + float: right; +} +.size1of2 { + width: 50%; +} +.size1of1 { + width: 100%; +} +.clearfix:before, .clearfix:after { + content: " "; + display: table; +} +.clearfix:after { + clear: both; +} +.hidden-true { + display: none; +} +.textbox0 { + width: 3em; + background: #f1f1f1; + padding: .25em .5em; + line-height: 1.5; + height: 1.5em; +} +#testDrive { + display: block; + padding-top: 24px; + line-height: 1.5; +} +.fs0 { + font-size: 16px; +} +.fs1 { + font-size: 32px; +} + diff --git a/src/SharedAssets/Assets/Symbols/Font/demo-files/demo.js b/src/SharedAssets/Assets/Symbols/Font/demo-files/demo.js new file mode 100644 index 0000000..6f45f1c --- /dev/null +++ b/src/SharedAssets/Assets/Symbols/Font/demo-files/demo.js @@ -0,0 +1,30 @@ +if (!('boxShadow' in document.body.style)) { + document.body.setAttribute('class', 'noBoxShadow'); +} + +document.body.addEventListener("click", function(e) { + var target = e.target; + if (target.tagName === "INPUT" && + target.getAttribute('class').indexOf('liga') === -1) { + target.select(); + } +}); + +(function() { + var fontSize = document.getElementById('fontSize'), + testDrive = document.getElementById('testDrive'), + testText = document.getElementById('testText'); + function updateTest() { + testDrive.innerHTML = testText.value || String.fromCharCode(160); + if (window.icomoonLiga) { + window.icomoonLiga(testDrive); + } + } + function updateSize() { + testDrive.style.fontSize = fontSize.value + 'px'; + } + fontSize.addEventListener('change', updateSize, false); + testText.addEventListener('input', updateTest, false); + testText.addEventListener('change', updateTest, false); + updateSize(); +}()); diff --git a/src/SharedAssets/Assets/Symbols/Font/demo.html b/src/SharedAssets/Assets/Symbols/Font/demo.html new file mode 100644 index 0000000..6984811 --- /dev/null +++ b/src/SharedAssets/Assets/Symbols/Font/demo.html @@ -0,0 +1,976 @@ + + + + + IcoMoon Demo + + + + + +
+

Font Name: UniGetUI-Symbols (Glyphs: 67)

+
+
+

Grid Size: Unknown

+
+
+ + icon-add_to +
+
+ + +
+
+ liga: + +
+
+
+
+ + icon-android +
+
+ + +
+
+ liga: + +
+
+
+
+ + icon-backward +
+
+ + +
+
+ liga: + +
+
+
+
+ + icon-bucket +
+
+ + +
+
+ liga: + +
+
+
+
+ + icon-buggy +
+
+ + +
+
+ liga: + +
+
+
+
+ + icon-checksum +
+
+ + +
+
+ liga: + +
+
+
+
+ + icon-choco +
+
+ + +
+
+ liga: + +
+
+
+
+ + icon-clipboard_list +
+
+ + +
+
+ liga: + +
+
+
+
+ + icon-close_round +
+
+ + +
+
+ liga: + +
+
+
+
+ + icon-collapse +
+
+ + +
+
+ liga: + +
+
+
+
+ + icon-console +
+
+ + +
+
+ liga: + +
+
+
+
+ + icon-copy +
+
+ + +
+
+ liga: + +
+
+
+
+ + icon-cross +
+
+ + +
+
+ liga: + +
+
+
+
+ + icon-delete +
+
+ + +
+
+ liga: + +
+
+
+
+ + icon-disk +
+
+ + +
+
+ liga: + +
+
+
+
+ + icon-dotnet +
+
+ + +
+
+ liga: + +
+
+
+
+ + icon-download +
+
+ + +
+
+ liga: + +
+
+
+
+ + icon-empty +
+
+ + +
+
+ liga: + +
+
+
+
+ + icon-expand +
+
+ + +
+
+ liga: + +
+
+
+
+ + icon-experimental +
+
+ + +
+
+ liga: + +
+
+
+
+ + icon-forward +
+
+ + +
+
+ liga: + +
+
+
+
+ + icon-gog +
+
+ + +
+
+ liga: + +
+
+
+
+ + icon-help +
+
+ + +
+
+ liga: + +
+
+
+
+ + icon-history +
+
+ + +
+
+ liga: + +
+
+
+
+ + icon-home +
+
+ + +
+
+ liga: + +
+
+
+
+ + icon-id +
+
+ + +
+
+ liga: + +
+
+
+
+ + icon-info_round +
+
+ + +
+
+ liga: + +
+
+
+
+ + icon-installed +
+
+ + +
+
+ liga: + +
+
+
+
+ + icon-installed_filled +
+
+ + +
+
+ liga: + +
+
+
+
+ + icon-interactive +
+
+ + +
+
+ liga: + +
+
+
+
+ + icon-launch +
+
+ + +
+
+ liga: + +
+
+
+
+ + icon-loading +
+
+ + +
+
+ liga: + +
+
+
+
+ + icon-loading_filled +
+
+ + +
+
+ liga: + +
+
+
+
+ + icon-local_pc +
+
+ + +
+
+ liga: + +
+
+
+
+ + icon-megaphone +
+
+ + +
+
+ liga: + +
+
+
+
+ + icon-ms_store +
+
+ + +
+
+ liga: + +
+
+
+
+ + icon-node +
+
+ + +
+
+ liga: + +
+
+
+
+ + icon-open_folder +
+
+ + +
+
+ liga: + +
+
+
+
+ + icon-options +
+
+ + +
+
+ liga: + +
+
+
+
+ + icon-package +
+
+ + +
+
+ liga: + +
+
+
+
+ + icon-pin +
+
+ + +
+
+ liga: + +
+
+
+
+ + icon-pin_filled +
+
+ + +
+
+ liga: + +
+
+
+
+ + icon-powershell +
+
+ + +
+
+ liga: + +
+
+
+
+ + icon-python +
+
+ + +
+
+ liga: + +
+
+
+
+ + icon-reload +
+
+ + +
+
+ liga: + +
+
+
+
+ + icon-sandclock +
+
+ + +
+
+ liga: + +
+
+
+
+ + icon-save_as +
+
+ + +
+
+ liga: + +
+
+
+
+ + icon-scoop +
+
+ + +
+
+ liga: + +
+
+
+
+ + icon-search +
+
+ + +
+
+ liga: + +
+
+
+
+ + icon-settings +
+
+ + +
+
+ liga: + +
+
+
+
+ + icon-share +
+
+ + +
+
+ liga: + +
+
+
+
+ + icon-skip +
+
+ + +
+
+ liga: + +
+
+
+
+ + icon-steam +
+
+ + +
+
+ liga: + +
+
+
+
+ + icon-sys_tray +
+
+ + +
+
+ liga: + +
+
+
+
+ + icon-uac +
+
+ + +
+
+ liga: + +
+
+
+
+ + icon-undelete +
+
+ + +
+
+ liga: + +
+
+
+
+ + icon-update +
+
+ + +
+
+ liga: + +
+
+
+
+ + icon-upgradable +
+
+ + +
+
+ liga: + +
+
+
+
+ + icon-upgradable_filled +
+
+ + +
+
+ liga: + +
+
+
+
+ + icon-uplay +
+
+ + +
+
+ liga: + +
+
+
+
+ + icon-version +
+
+ + +
+
+ liga: + +
+
+
+
+ + icon-warning +
+
+ + +
+
+ liga: + +
+
+
+
+ + icon-warning_filled +
+
+ + +
+
+ liga: + +
+
+
+
+ + icon-warning_round +
+
+ + +
+
+ liga: + +
+
+
+
+ + icon-winget +
+
+ + +
+
+ liga: + +
+
+
+
+ + icon-rust +
+
+ + +
+
+ liga: + +
+
+
+
+ + icon-vcpkg +
+
+ + +
+
+ liga: + +
+
+
+ + +
+

Font Test Drive

+ + +
  +
+
+ +
+

Generated by IcoMoon

+
+ + + + diff --git a/src/SharedAssets/Assets/Symbols/Font/fonts/UniGetUI-Symbols.eot b/src/SharedAssets/Assets/Symbols/Font/fonts/UniGetUI-Symbols.eot new file mode 100644 index 0000000..e0cb9be Binary files /dev/null and b/src/SharedAssets/Assets/Symbols/Font/fonts/UniGetUI-Symbols.eot differ diff --git a/src/SharedAssets/Assets/Symbols/Font/fonts/UniGetUI-Symbols.svg b/src/SharedAssets/Assets/Symbols/Font/fonts/UniGetUI-Symbols.svg new file mode 100644 index 0000000..775db25 --- /dev/null +++ b/src/SharedAssets/Assets/Symbols/Font/fonts/UniGetUI-Symbols.svg @@ -0,0 +1,76 @@ + + + +Generated by IcoMoon + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/SharedAssets/Assets/Symbols/Font/fonts/UniGetUI-Symbols.ttf b/src/SharedAssets/Assets/Symbols/Font/fonts/UniGetUI-Symbols.ttf new file mode 100644 index 0000000..5b090f3 Binary files /dev/null and b/src/SharedAssets/Assets/Symbols/Font/fonts/UniGetUI-Symbols.ttf differ diff --git a/src/SharedAssets/Assets/Symbols/Font/fonts/UniGetUI-Symbols.woff b/src/SharedAssets/Assets/Symbols/Font/fonts/UniGetUI-Symbols.woff new file mode 100644 index 0000000..ec60f9b Binary files /dev/null and b/src/SharedAssets/Assets/Symbols/Font/fonts/UniGetUI-Symbols.woff differ diff --git a/src/SharedAssets/Assets/Symbols/Font/selection.json b/src/SharedAssets/Assets/Symbols/Font/selection.json new file mode 100644 index 0000000..00005e5 --- /dev/null +++ b/src/SharedAssets/Assets/Symbols/Font/selection.json @@ -0,0 +1 @@ +{"IcoMoonType":"selection","icons":[{"icon":{"paths":["M746.667 42.667c-129.6 0-234.667 105.067-234.667 234.667s105.067 234.667 234.667 234.667c129.6 0 234.667-105.067 234.667-234.667s-105.067-234.667-234.667-234.667zM746.667 106.667c11.776 0 21.333 9.557 21.333 21.333v128h128c11.776 0 21.333 9.557 21.333 21.333s-9.557 21.333-21.333 21.333h-128v128c0 11.776-9.557 21.333-21.333 21.333s-21.333-9.557-21.333-21.333v-128h-128c-11.776 0-21.333-9.557-21.333-21.333s9.557-21.333 21.333-21.333h128v-128c0-11.776 9.557-21.333 21.333-21.333zM266.667 128c-76.373 0-138.667 62.293-138.667 138.667v490.667c0 76.373 62.293 138.667 138.667 138.667h490.667c76.373 0 138.667-62.293 138.667-138.667v-202.667h-257.708c-17.672 0.002-31.998 14.328-32 32l-0 0c0 34.277-12.347 56.311-30.125 72s-42.281 24-64.167 24c-21.885 0-46.389-8.311-64.167-24s-30.125-37.723-30.125-72c-0.002-17.672-14.328-31.998-32-32l-193.709-0v-288c0-41.173 33.493-74.667 74.667-74.667h216.125c7.253-22.827 17.492-44.16 30.292-64h-246.417zM192 618.667h168.417c7.063 35.742 21.599 67.275 45.083 88 30.569 26.977 69.228 40 106.5 40s75.931-13.023 106.5-40c23.484-20.725 38.020-52.258 45.083-88h168.417v138.667c0 41.173-33.493 74.667-74.667 74.667h-490.667c-41.173 0-74.667-33.493-74.667-74.667v-138.667z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"grid":0,"tags":["add_to"]},"attrs":[{}],"properties":{"order":2,"id":66,"name":"add_to","prevSize":32,"code":59648},"setIdx":0,"setId":0,"iconIdx":0},{"icon":{"paths":["M693.75 20.958c-0.042-0-0.092-0-0.142-0-10.863 0-20.463 5.413-26.248 13.688l-0.069 0.104-39.292 55.042c-35.356-16.394-74.573-25.792-116-25.792s-80.644 9.397-116 25.792l-39.292-55.042c-5.855-8.366-15.447-13.769-26.301-13.769-0.392 0-0.783 0.007-1.172 0.021l0.056-0.002c-17.18 0.629-30.868 14.707-30.868 31.983 0 7.123 2.327 13.703 6.263 19.020l-0.061-0.087 36.708 51.375c-61.037 47.903-101.436 120.677-105.917 202.917-10.28-3.802-21.221-6.208-32.75-6.208-52.64 0-96 43.36-96 96v234.667c0 52.64 43.36 96 96 96 12.593 0 24.602-2.587 35.667-7.083 8.373 29.955 31.135 53.953 60.333 64.542v81.208c0 52.64 43.36 96 96 96s96-43.36 96-96v-74.667h42.667v74.667c0 52.64 43.36 96 96 96s96-43.36 96-96v-81.208c29.198-10.589 51.961-34.587 60.333-64.542 11.064 4.497 23.073 7.083 35.667 7.083 52.64 0 96-43.36 96-96v-234.667c0-52.64-43.36-96-96-96-11.529 0-22.47 2.407-32.75 6.208-4.481-82.24-44.88-155.013-105.917-202.917l36.708-51.375c3.884-5.235 6.218-11.823 6.218-18.956 0-17.618-14.237-31.912-31.834-32.003l-0.009-0zM512 128c110.616 0 197.904 84.427 209.042 192h-418.083c11.138-107.573 98.426-192 209.042-192zM416 213.333c-17.673 0-32 14.327-32 32s14.327 32 32 32v0c17.673 0 32-14.327 32-32s-14.327-32-32-32v0zM608 213.333c-17.673 0-32 14.327-32 32s14.327 32 32 32v0c17.673 0 32-14.327 32-32s-14.327-32-32-32v0zM202.667 384c18.059 0 32 13.941 32 32v234.667c0 18.059-13.941 32-32 32s-32-13.941-32-32v-234.667c0-18.059 13.941-32 32-32zM298.667 384h426.667v330.667c0 18.059-13.941 32-32 32h-362.667c-18.059 0-32-13.941-32-32v-330.667zM821.333 384c18.059 0 32 13.941 32 32v234.667c0 18.059-13.941 32-32 32s-32-13.941-32-32v-234.667c0-18.059 13.941-32 32-32zM362.667 810.667h64v74.667c0 18.059-13.941 32-32 32s-32-13.941-32-32v-74.667zM597.333 810.667h64v74.667c0 18.059-13.941 32-32 32s-32-13.941-32-32v-74.667z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"grid":0,"tags":["android"]},"attrs":[{}],"properties":{"order":3,"id":65,"name":"android","prevSize":32,"code":59649},"setIdx":0,"setId":0,"iconIdx":1},{"icon":{"paths":["M735.375 63.708c-8.646 0.26-16.392 3.91-21.993 9.66l-0.007 0.007-416 416c-5.789 5.791-9.369 13.79-9.369 22.625s3.58 16.834 9.369 22.625l416 416c5.833 6.068 14.019 9.838 23.085 9.838 17.675 0 32.003-14.328 32.003-32.003 0-9.066-3.77-17.252-9.828-23.075l-0.011-0.010-393.375-393.375 393.375-393.375c5.971-5.82 9.675-13.941 9.675-22.927 0-17.675-14.328-32.003-32.003-32.003-0.324 0-0.647 0.005-0.969 0.014l0.047-0.001z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"grid":0,"tags":["backward"]},"attrs":[{}],"properties":{"order":4,"id":64,"name":"backward","prevSize":32,"code":59650},"setIdx":0,"setId":0,"iconIdx":2},{"icon":{"paths":["M522.667 21.333c-170.466 0-309.333 138.868-309.333 309.333v53.333h-10.667c-17.672 0.002-31.998 14.328-32 32l-0 0v448c0 64.422 52.911 117.333 117.333 117.333h469.333c64.422 0 117.333-52.911 117.333-117.333v-448c-0.002-17.672-14.328-31.998-32-32l-10.667-0v-53.333c0-170.466-138.868-309.333-309.333-309.333zM522.667 85.333c135.881 0 245.333 109.452 245.333 245.333v53.333h-490.667v-53.333c0-135.881 109.452-245.333 245.333-245.333zM234.667 448h5.417c1.559 0.269 3.356 0.423 5.187 0.423s3.628-0.154 5.376-0.45l-0.188 0.026h69.542c35.349 0 64 28.651 64 64v117.333c0 29.461 23.872 53.333 53.333 53.333s53.333-23.872 53.333-53.333v-96c0-23.573 19.093-42.667 42.667-42.667s42.667 19.093 42.667 42.667v10.667c0 29.461 23.872 53.333 53.333 53.333s53.333-23.872 53.333-53.333v-32c0-35.349 28.651-64 64-64h48.083c1.559 0.269 3.356 0.423 5.187 0.423s3.628-0.154 5.376-0.45l-0.188 0.026h5.542v416c0 29.829-23.505 53.333-53.333 53.333h-469.333c-29.829 0-53.333-23.505-53.333-53.333v-416z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"grid":0,"tags":["bucket"]},"attrs":[{}],"properties":{"order":5,"id":63,"name":"bucket","prevSize":32,"code":59651},"setIdx":0,"setId":0,"iconIdx":3},{"icon":{"paths":["M308.833 106.208c-17.459 0.281-31.503 14.5-31.503 31.999 0 0.161 0.001 0.323 0.004 0.483l-0-0.024v64c0.002 8.836 3.584 16.835 9.375 22.625l45.125 45.125c-20.881 32.954-33.167 71.854-33.167 113.583v10.667c-0.002 0.138-0.003 0.301-0.003 0.465 0 3.16 0.458 6.212 1.311 9.095l-0.057-0.226-53.292-53.292c-3.739-3.732-8.398-6.545-13.607-8.068l-0.226-0.057-149.333-42.667c-2.959-0.997-6.366-1.573-9.908-1.573-17.675 0-32.003 14.328-32.003 32.003 0 14.95 10.251 27.506 24.107 31.022l0.221 0.048 141.375 40.417 60.083 60.083c-1.902 2.506-3.559 5.184-5.375 7.75-0.361 0.049-0.545 0.078-0.729 0.109l0.187-0.026-128 21.333c-9.485 1.617-17.413 7.217-22.128 14.983l-0.080 0.142-64 106.667c-2.862 4.699-4.556 10.381-4.556 16.46 0 17.68 14.333 32.013 32.013 32.013 11.603 0 21.764-6.173 27.379-15.414l0.080-0.142 56.375-94 67.542-11.25c-8.086 24.718-12.708 50.85-12.708 78.125 0 46.972 16.319 91.167 41.25 130.625l-61.167 87.375-128.167 39.417c-13.404 4.019-23.004 16.244-23.004 30.712 0 17.675 14.328 32.003 32.003 32.003 3.514 0 6.897-0.566 10.060-1.613l-0.226 0.065 138.667-42.667c6.964-2.195 12.736-6.497 16.724-12.149l0.068-0.101 55.958-79.958c7.727 8.329 15.686 16.403 23.958 24 58.625 53.841 128.499 90.958 192.542 90.958s133.917-37.118 192.542-90.958c4.976-4.57 9.706-9.494 14.5-14.333l55.708 71.625c4.121 5.244 9.751 9.133 16.232 11.027l0.226 0.057 149.333 42.667c2.959 0.997 6.367 1.573 9.909 1.573 17.675 0 32.003-14.328 32.003-32.003 0-14.95-10.251-27.506-24.107-31.022l-0.221-0.048-139.292-39.833-57.667-74.125c29.664-42.527 49.5-91.243 49.5-143.292 0-27.275-4.622-53.407-12.708-78.125l67.542 11.25 56.375 94c5.694 9.386 15.857 15.561 27.462 15.561 17.68 0 32.013-14.333 32.013-32.013 0-6.080-1.695-11.765-4.639-16.607l0.080 0.142-64-106.667c-4.796-7.908-12.723-13.508-22.019-15.098l-0.19-0.027-128-21.333c0.003-0.005-0.181-0.034-0.366-0.062l-0.176-0.022c-1.816-2.566-3.473-5.244-5.375-7.75l58.417-58.417 138.792-19.833c16.031-1.897 28.347-15.407 28.347-31.794 0-17.675-14.328-32.003-32.003-32.003-1.917 0-3.795 0.169-5.62 0.492l0.193-0.028-149.333 21.333c-7.122 1.046-13.342 4.304-18.083 9.042l-53.333 53.333c0.821-2.697 1.294-5.797 1.294-9.008 0-0.129-0.001-0.258-0.002-0.387l0 0.020v-10.667c0-36.19-9.171-70.286-25.208-100.208l58.5-58.5c5.791-5.79 9.373-13.789 9.375-22.625l0-0v-64c0.002-0.136 0.003-0.298 0.003-0.459 0-17.675-14.328-32.003-32.003-32.003-0.176 0-0.351 0.001-0.526 0.004l0.026-0c-17.459 0.281-31.503 14.5-31.503 31.999 0 0.161 0.001 0.323 0.004 0.483l-0-0.024v50.75l-42.625 42.625c-31.559-31.030-72.723-52.159-118.458-58.875-3.736-13.82-16.157-23.822-30.915-23.833l-0.001-0c-14.76 0.011-27.181 10.014-30.865 23.609l-0.052 0.224c-40.533 5.952-77.411 23.261-107.25 48.75l-32.5-32.5v-50.75c0.002-0.136 0.003-0.298 0.003-0.459 0-17.675-14.328-32.003-32.003-32.003-0.176 0-0.351 0.001-0.526 0.004l0.026-0zM512 234.667c81.617 0 147.242 64.578 149.167 145.708-44.898-24.719-96.237-39.042-149.167-39.042s-104.268 14.323-149.167 39.042c0.805-33.912 12.729-64.887 32.333-89.5 2.141-1.914 4-4.077 5.55-6.46l0.075-0.124c27.285-30.441 66.841-49.625 111.208-49.625zM512 405.333c121.767 0 234.667 98 234.667 213.333 0 54.634-35.743 114.963-85.417 160.583-37.117 34.088-81.901 58.579-117.25 68.792v-261.375c0.002-0.137 0.003-0.298 0.003-0.459 0-17.675-14.328-32.003-32.003-32.003-0.176 0-0.351 0.001-0.527 0.004l0.026-0c-17.459 0.281-31.503 14.5-31.503 31.999 0 0.161 0.001 0.323 0.004 0.483l-0-0.024v261.375c-35.349-10.213-80.133-34.704-117.25-68.792-49.674-45.621-85.417-105.95-85.417-160.583 0-115.334 112.899-213.333 234.667-213.333z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"grid":0,"tags":["buggy"]},"attrs":[{}],"properties":{"order":6,"id":62,"name":"buggy","prevSize":32,"code":59652},"setIdx":0,"setId":0,"iconIdx":4},{"icon":{"paths":["M436.5 84.917c-15.344 0.443-27.95 11.621-30.596 26.263l-0.029 0.195-43.5 229.958h-202.375c-0.135-0.002-0.293-0.003-0.453-0.003-17.675 0-32.003 14.328-32.003 32.003s14.328 32.003 32.003 32.003c0.159 0 0.318-0.001 0.477-0.003l-0.024 0h190.25l-40.333 213.333h-192.583c-0.135-0.002-0.293-0.003-0.453-0.003-17.675 0-32.003 14.328-32.003 32.003s14.328 32.003 32.003 32.003c0.159 0 0.318-0.001 0.477-0.003l-0.024 0h180.458l-41.25 218.042c-0.356 1.791-0.559 3.851-0.559 5.958 0 17.683 14.335 32.018 32.018 32.018 15.576 0 28.554-11.122 31.426-25.857l0.033-0.202 43.5-229.958h233.5l-41.25 218.042c-0.356 1.791-0.559 3.851-0.559 5.958 0 17.683 14.335 32.018 32.018 32.018 15.576 0 28.554-11.122 31.426-25.857l0.033-0.202 43.5-229.958h202.375c0.135 0.002 0.293 0.003 0.453 0.003 17.675 0 32.003-14.328 32.003-32.003s-14.328-32.003-32.003-32.003c-0.159 0-0.318 0.001-0.477 0.003l0.024-0h-190.25l40.333-213.333h192.583c0.135 0.002 0.293 0.003 0.453 0.003 17.675 0 32.003-14.328 32.003-32.003s-14.328-32.003-32.003-32.003c-0.159 0-0.318 0.001-0.477 0.003l0.024-0h-180.458l41.25-218.042c0.356-1.791 0.559-3.851 0.559-5.958 0-17.683-14.335-32.018-32.018-32.018-15.576 0-28.554 11.122-31.426 25.857l-0.033 0.202-43.5 229.958h-233.5l41.25-218.042c0.409-1.92 0.643-4.125 0.643-6.385 0-17.675-14.328-32.003-32.003-32.003-0.328 0-0.654 0.005-0.98 0.015l0.048-0.001zM415.417 405.333h233.5l-40.333 213.333h-233.5l40.333-213.333z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"grid":0,"tags":["checksum"]},"attrs":[{}],"properties":{"order":7,"id":61,"name":"checksum","prevSize":32,"code":59653},"setIdx":0,"setId":0,"iconIdx":5},{"icon":{"paths":["M309.333 85.333c-64.422 0-117.333 52.911-117.333 117.333v597.333c0 64.422 52.911 117.333 117.333 117.333h405.333c64.422 0 117.333-52.911 117.333-117.333v-295.208c0.15-1.163 0.235-2.509 0.235-3.875s-0.086-2.712-0.252-4.032l0.016 0.157v-294.375c0-64.422-52.911-117.333-117.333-117.333h-405.333zM309.333 149.333h74.667v128h-128v-74.667c0-29.829 23.505-53.333 53.333-53.333zM448 149.333h128v128h-128v-128zM640 149.333h74.667c29.829 0 53.333 23.505 53.333 53.333v74.667h-128v-128zM256 341.333h128v128h-128v-128zM448 341.333h128v128h-128v-128zM640 341.333h128v128h-128v-128zM379.917 533.333h360.292l-45.625 68.417c-20.076 30.106-58.28 41.459-91.542 27.208l-223.125-95.625zM256 549.875l321.833 137.917c61.245 26.24 133.030 4.94 170-50.5 0-0.006 0-0.014 0-0.021s-0-0.015-0-0.022l0 0.001 20.167-30.25v193c0 29.829-23.505 53.333-53.333 53.333h-405.333c-29.829 0-53.333-23.505-53.333-53.333v-250.125z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"grid":0,"tags":["choco"]},"attrs":[{}],"properties":{"order":8,"id":60,"name":"choco","prevSize":32,"code":59654},"setIdx":0,"setId":0,"iconIdx":6},{"icon":{"paths":["M437.333 85.333c-48.994 0-89.478 37.688-94.917 85.333h-75.75c-52.64 0-96 43.36-96 96v576c0 52.64 43.36 96 96 96h490.667c52.64 0 96-43.36 96-96v-576c0-52.64-43.36-96-96-96h-75.75c-5.438-47.645-45.923-85.333-94.917-85.333h-149.333zM437.333 149.333h149.333c18.059 0 32 13.941 32 32s-13.941 32-32 32h-149.333c-18.059 0-32-13.941-32-32s13.941-32 32-32zM266.667 234.667h91.083c17.316 25.641 46.617 42.667 79.583 42.667h149.333c32.966 0 62.267-17.026 79.583-42.667h91.083c18.059 0 32 13.941 32 32v576c0 18.059-13.941 32-32 32h-490.667c-18.059 0-32-13.941-32-32v-576c0-18.059 13.941-32 32-32zM352 426.667c-17.673 0-32 14.327-32 32s14.327 32 32 32v0c17.673 0 32-14.327 32-32s-14.327-32-32-32v0zM480 426.667c-0.135-0.002-0.293-0.003-0.453-0.003-17.675 0-32.003 14.328-32.003 32.003s14.328 32.003 32.003 32.003c0.159 0 0.318-0.001 0.477-0.003l-0.024 0h192c0.135 0.002 0.293 0.003 0.453 0.003 17.675 0 32.003-14.328 32.003-32.003s-14.328-32.003-32.003-32.003c-0.159 0-0.318 0.001-0.477 0.003l0.024-0h-192zM352 554.667c-17.673 0-32 14.327-32 32s14.327 32 32 32v0c17.673 0 32-14.327 32-32s-14.327-32-32-32v0zM480 554.667c-0.135-0.002-0.293-0.003-0.453-0.003-17.675 0-32.003 14.328-32.003 32.003s14.328 32.003 32.003 32.003c0.159 0 0.318-0.001 0.477-0.003l-0.024 0h192c0.135 0.002 0.293 0.003 0.453 0.003 17.675 0 32.003-14.328 32.003-32.003s-14.328-32.003-32.003-32.003c-0.159 0-0.318 0.001-0.477 0.003l0.024-0h-192zM352 682.667c-17.673 0-32 14.327-32 32s14.327 32 32 32v0c17.673 0 32-14.327 32-32s-14.327-32-32-32v0zM480 682.667c-0.135-0.002-0.293-0.003-0.453-0.003-17.675 0-32.003 14.328-32.003 32.003s14.328 32.003 32.003 32.003c0.159 0 0.318-0.001 0.477-0.003l-0.024 0h192c0.135 0.002 0.293 0.003 0.453 0.003 17.675 0 32.003-14.328 32.003-32.003s-14.328-32.003-32.003-32.003c-0.159 0-0.318 0.001-0.477 0.003l0.024-0h-192z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"grid":0,"tags":["clipboard_list"]},"attrs":[{}],"properties":{"order":9,"id":59,"name":"clipboard_list","prevSize":32,"code":59655},"setIdx":0,"setId":0,"iconIdx":7},{"icon":{"paths":["M512 85.333c-235.263 0-426.667 191.404-426.667 426.667s191.404 426.667 426.667 426.667c235.263 0 426.667-191.404 426.667-426.667s-191.404-426.667-426.667-426.667zM512 149.333c200.674 0 362.667 161.992 362.667 362.667s-161.992 362.667-362.667 362.667c-200.674 0-362.667-161.992-362.667-362.667s161.992-362.667 362.667-362.667zM650.375 340.875c-8.79 0.214-16.67 3.94-22.323 9.823l-0.010 0.011-116.042 116.042-116.042-116.042c-5.822-5.991-13.956-9.708-22.958-9.708l-0-0c-17.672 0.004-31.995 14.331-31.995 32.003 0 9 3.715 17.133 9.696 22.948l0.007 0.007 116.042 116.042-116.042 116.042c-6.068 5.833-9.838 14.019-9.838 23.085 0 17.675 14.328 32.003 32.003 32.003 9.066 0 17.252-3.77 23.075-9.828l0.010-0.011 116.042-116.042 116.042 116.042c5.833 6.068 14.019 9.838 23.085 9.838 17.675 0 32.003-14.328 32.003-32.003 0-9.066-3.77-17.252-9.828-23.075l-0.011-0.010-116.042-116.042 116.042-116.042c6.071-5.833 9.842-14.021 9.842-23.089 0-17.675-14.328-32.003-32.003-32.003-0.266 0-0.531 0.003-0.795 0.010l0.039-0.001z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"grid":0,"tags":["close_round"]},"attrs":[{}],"properties":{"order":10,"id":58,"name":"close_round","prevSize":32,"code":59656},"setIdx":0,"setId":0,"iconIdx":8},{"icon":{"paths":["M511.542 245.333c-8.669 0.131-16.483 3.688-22.167 9.375l-416 416c-6.068 5.833-9.838 14.019-9.838 23.085 0 17.675 14.328 32.003 32.003 32.003 9.066 0 17.252-3.77 23.075-9.828l0.010-0.011 393.375-393.375 393.375 393.375c5.833 6.068 14.019 9.838 23.085 9.838 17.675 0 32.003-14.328 32.003-32.003 0-9.066-3.77-17.252-9.828-23.075l-0.011-0.010-416-416c-5.792-5.794-13.795-9.378-22.634-9.378-0.158 0-0.315 0.001-0.473 0.003l0.024-0z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"grid":0,"tags":["collapse"]},"attrs":[{}],"properties":{"order":11,"id":57,"name":"collapse","prevSize":32,"code":59657},"setIdx":0,"setId":0,"iconIdx":9},{"icon":{"paths":["M266.667 128c-76.201 0-138.667 62.465-138.667 138.667v490.667c0 76.201 62.465 138.667 138.667 138.667h490.667c76.201 0 138.667-62.465 138.667-138.667v-490.667c0-76.201-62.465-138.667-138.667-138.667h-490.667zM266.667 192h490.667c41.601 0 74.667 33.065 74.667 74.667v32h-640v-32c0-41.601 33.065-74.667 74.667-74.667zM192 362.667h640v394.667c0 41.601-33.065 74.667-74.667 74.667h-490.667c-41.601 0-74.667-33.065-74.667-74.667v-394.667zM373 469c-17.672 0.004-31.995 14.331-31.995 32.003 0 9 3.715 17.133 9.696 22.948l0.007 0.007 62.708 62.708-62.708 62.708c-6.068 5.833-9.838 14.019-9.838 23.085 0 17.675 14.328 32.003 32.003 32.003 9.066 0 17.252-3.77 23.075-9.828l0.010-0.011 85.333-85.333c5.789-5.791 9.369-13.79 9.369-22.625s-3.58-16.834-9.369-22.625l-85.333-85.333c-5.822-5.991-13.956-9.708-22.958-9.708l-0-0zM544 640c-0.135-0.002-0.293-0.003-0.453-0.003-17.675 0-32.003 14.328-32.003 32.003s14.328 32.003 32.003 32.003c0.159 0 0.318-0.001 0.477-0.003l-0.024 0h128c0.135 0.002 0.293 0.003 0.453 0.003 17.675 0 32.003-14.328 32.003-32.003s-14.328-32.003-32.003-32.003c-0.159 0-0.318 0.001-0.477 0.003l0.024-0h-128z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"grid":0,"tags":["console"]},"attrs":[{}],"properties":{"order":12,"id":56,"name":"console","prevSize":32,"code":59658},"setIdx":0,"setId":0,"iconIdx":10},{"icon":{"paths":["M394.667 106.667c-64.422 0-117.333 52.911-117.333 117.333v469.333c0 64.422 52.911 117.333 117.333 117.333h341.333c64.422 0 117.333-52.911 117.333-117.333v-469.333c0-64.422-52.911-117.333-117.333-117.333h-341.333zM394.667 170.667h341.333c29.829 0 53.333 23.505 53.333 53.333v469.333c0 29.829-23.505 53.333-53.333 53.333h-341.333c-29.829 0-53.333-23.505-53.333-53.333v-469.333c0-29.829 23.505-53.333 53.333-53.333zM234.667 213.333l-26 17.333c-23.744 15.829-38 42.477-38 71v413c0 111.936 90.731 202.667 202.667 202.667h285c28.544 0 55.192-14.256 71-38l17.333-26h-373.333c-76.587 0-138.667-62.080-138.667-138.667v-501.333z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"grid":0,"tags":["copy"]},"attrs":[{}],"properties":{"order":13,"id":55,"name":"copy","prevSize":32,"code":59659},"setIdx":0,"setId":0,"iconIdx":11},{"icon":{"paths":["M842.375 148.875c-8.79 0.214-16.67 3.94-22.323 9.823l-0.010 0.011-308.042 308.042-308.042-308.042c-5.822-5.991-13.956-9.708-22.958-9.708l-0-0c-17.672 0.004-31.995 14.331-31.995 32.003 0 9 3.715 17.133 9.696 22.948l0.007 0.007 308.042 308.042-308.042 308.042c-6.068 5.833-9.838 14.019-9.838 23.085 0 17.675 14.328 32.003 32.003 32.003 9.066 0 17.252-3.77 23.075-9.828l0.010-0.011 308.042-308.042 308.042 308.042c5.833 6.068 14.019 9.838 23.085 9.838 17.675 0 32.003-14.328 32.003-32.003 0-9.066-3.77-17.252-9.828-23.075l-0.011-0.010-308.042-308.042 308.042-308.042c6.071-5.834 9.842-14.021 9.842-23.089 0-17.675-14.328-32.003-32.003-32.003-0.266 0-0.531 0.003-0.795 0.010l0.039-0.001z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"grid":0,"tags":["cross"]},"attrs":[{}],"properties":{"order":14,"id":54,"name":"cross","prevSize":32,"code":59660},"setIdx":0,"setId":0,"iconIdx":12},{"icon":{"paths":["M512 85.333c-74.844 0-137.165 55.924-147.625 128h-145.958c-1.623-0.292-3.491-0.458-5.398-0.458-0.036 0-0.072 0-0.108 0l0.006-0c-1.706 0.038-3.345 0.203-4.943 0.487l0.193-0.028h-69.5c-0.135-0.002-0.293-0.003-0.453-0.003-17.675 0-32.003 14.328-32.003 32.003s14.328 32.003 32.003 32.003c0.159 0 0.318-0.001 0.477-0.003l-0.024 0h45.625l53.708 555.292c5.783 59.875 56.651 106.042 116.792 106.042h314.375c60.143 0 111.011-46.162 116.792-106.042l53.75-555.292h45.625c0.135 0.002 0.293 0.003 0.453 0.003 17.675 0 32.003-14.328 32.003-32.003s-14.328-32.003-32.003-32.003c-0.159 0-0.318 0.001-0.477 0.003l0.024-0h-69.458c-1.541-0.263-3.315-0.413-5.125-0.413s-3.584 0.15-5.312 0.439l0.187-0.026h-146c-10.46-72.076-72.781-128-147.625-128zM512 149.333c40.089 0 72.976 27.054 82.375 64h-164.75c9.399-36.946 42.286-64 82.375-64zM248.542 277.333h526.875l-53.167 549.125c-2.667 27.629-25.333 48.208-53.083 48.208h-314.375c-27.71 0-50.418-20.616-53.083-48.208l-53.167-549.125zM436.833 383.542c-17.459 0.281-31.503 14.5-31.503 31.999 0 0.161 0.001 0.323 0.004 0.483l-0-0.024v320c-0.002 0.135-0.003 0.293-0.003 0.453 0 17.675 14.328 32.003 32.003 32.003s32.003-14.328 32.003-32.003c0-0.159-0.001-0.318-0.003-0.477l0 0.024v-320c0.002-0.137 0.003-0.298 0.003-0.459 0-17.675-14.328-32.003-32.003-32.003-0.176 0-0.351 0.001-0.527 0.004l0.026-0zM586.167 383.542c-17.459 0.281-31.503 14.5-31.503 31.999 0 0.161 0.001 0.323 0.004 0.483l-0-0.024v320c-0.002 0.135-0.003 0.293-0.003 0.453 0 17.675 14.328 32.003 32.003 32.003s32.003-14.328 32.003-32.003c0-0.159-0.001-0.318-0.003-0.477l0 0.024v-320c0.002-0.137 0.003-0.298 0.003-0.459 0-17.675-14.328-32.003-32.003-32.003-0.176 0-0.351 0.001-0.527 0.004l0.026-0z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"grid":0,"tags":["delete"]},"attrs":[{}],"properties":{"order":15,"id":53,"name":"delete","prevSize":32,"code":59661},"setIdx":0,"setId":0,"iconIdx":13},{"icon":{"paths":["M288 85.333c-64.422 0-117.333 52.911-117.333 117.333v618.667c0 64.422 52.911 117.333 117.333 117.333h448c64.422 0 117.333-52.911 117.333-117.333v-618.667c0-64.422-52.911-117.333-117.333-117.333h-448zM288 149.333h448c29.829 0 53.333 23.505 53.333 53.333v618.667c0 29.829-23.505 53.333-53.333 53.333h-448c-29.829 0-53.333-23.505-53.333-53.333v-618.667c0-29.829 23.505-53.333 53.333-53.333zM309.333 192c-17.673 0-32 14.327-32 32s14.327 32 32 32v0c17.673 0 32-14.327 32-32s-14.327-32-32-32v0zM714.667 192c-17.673 0-32 14.327-32 32s14.327 32 32 32v0c17.673 0 32-14.327 32-32s-14.327-32-32-32v0zM512 256c-117.632 0-213.333 95.701-213.333 213.333 0 47.287 15.771 90.77 41.958 126.125l-32.583 32.583c-6.068 5.833-9.838 14.019-9.838 23.085 0 17.675 14.328 32.003 32.003 32.003 9.066 0 17.252-3.77 23.075-9.828l0.010-0.011 181.333-181.333c5.971-5.82 9.675-13.941 9.675-22.927 0-17.675-14.328-32.003-32.003-32.003-0.324 0-0.647 0.005-0.969 0.014l0.047-0.001c-8.646 0.26-16.392 3.91-21.993 9.66l-0.007 0.007-102.833 102.833c-14.93-23.203-23.875-50.611-23.875-80.208 0-82.347 67.008-149.333 149.333-149.333s149.333 66.987 149.333 149.333c0 82.347-67.008 149.333-149.333 149.333-13.547 0-26.624-1.983-39.125-5.375l-49.708 49.708c27.093 12.501 57.089 19.667 88.833 19.667 117.632 0 213.333-95.701 213.333-213.333s-95.701-213.333-213.333-213.333zM309.333 768c-17.673 0-32 14.327-32 32s14.327 32 32 32v0c17.673 0 32-14.327 32-32s-14.327-32-32-32v0zM714.667 768c-17.673 0-32 14.327-32 32s14.327 32 32 32v0c17.673 0 32-14.327 32-32s-14.327-32-32-32v0z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"grid":0,"tags":["disk"]},"attrs":[{}],"properties":{"order":16,"id":52,"name":"disk","prevSize":32,"code":59662},"setIdx":0,"setId":0,"iconIdx":14},{"icon":{"paths":["M99.413 476.16c-11.093 0-20.48-3.84-27.733-11.947-7.68-7.68-11.52-17.493-11.52-29.013 0-11.947 3.84-22.187 11.52-29.44 7.68-7.68 17.067-11.52 28.587-11.52s20.907 3.84 28.587 11.52 11.093 17.493 11.093 29.44c0 11.947-3.84 22.187-11.093 29.867s-17.493 11.093-29.44 11.093z","M466.347 470.613h-69.547l-126.72-195.84c-3.413-5.973-6.4-11.093-8.96-15.36s-4.267-8.107-5.547-11.093h-0.853c0.427 5.547 0.427 12.373 0.853 20.907 0 8.533 0 18.773 0 30.293v171.093h-65.28v-317.44h74.24l122.027 189.867c2.56 4.267 5.12 8.533 7.68 12.8s4.693 8.533 6.827 12.8h4.267c-2.56-3.84-3.84-9.387-4.267-16.64 0-7.253-0.427-16.213-0.427-27.307v-171.52h65.28v317.44z","M716.8 470.613h-184.32v-317.44h177.067v59.307h-107.947v69.12h100.267v58.88h-100.267v70.827h115.2v59.307z","M969.813 211.627h-82.347v259.413h-69.547v-259.413h-82.347v-58.453h233.813v58.453z","M307.2 619.093h-53.76v155.733h-32v-155.733h-53.76v-25.6h139.52v25.6z","M416.427 777.813c-27.307 0-49.92-8.533-66.987-25.173-17.493-17.067-26.027-38.827-26.027-66.133 0-29.013 8.96-52.053 26.453-69.547 17.92-17.493 40.96-26.453 69.547-26.453 26.88 0 49.067 8.533 65.707 25.173s25.173 39.253 25.173 66.56c0 28.587-8.533 51.627-26.027 69.12s-39.68 26.453-67.84 26.453zM416.853 750.933c17.92 0 32.853-5.973 43.52-17.92 11.093-11.947 16.64-28.16 16.64-48.213 0-20.907-5.547-37.12-16.213-49.493-10.667-11.947-24.747-18.347-42.667-18.347-18.347 0-33.28 5.973-44.373 18.347s-17.067 28.587-17.067 48.64c0 20.053 5.547 36.267 16.64 48.213 11.52 12.8 26.027 18.773 43.52 18.773z","M623.787 777.813c-27.307 0-49.92-8.533-66.987-25.173-17.067-17.067-26.027-38.827-26.027-66.133 0-29.013 8.96-52.053 26.453-69.547 17.92-17.493 40.96-26.453 69.547-26.453 26.88 0 49.067 8.533 65.707 25.173s25.173 39.253 25.173 66.56c0 28.587-8.96 51.627-26.027 69.12s-40.107 26.453-67.84 26.453zM624.213 750.933c18.347 0 32.853-5.973 43.52-17.92 11.093-11.947 16.64-28.16 16.64-48.213 0-20.907-5.547-37.12-16.213-49.493-10.667-11.947-24.747-18.347-42.667-18.347-18.347 0-33.28 5.973-44.373 18.347s-16.64 28.587-16.64 48.64c0 20.053 5.547 36.267 16.64 48.213 11.093 12.8 25.173 18.773 43.093 18.773z","M857.173 774.827h-106.667v-181.333h32v155.307h74.667v26.027z"],"attrs":[{},{},{},{},{},{},{},{}],"isMulticolor":false,"isMulticolor2":false,"grid":0,"tags":["dotnet"]},"attrs":[{},{},{},{},{},{},{},{}],"properties":{"order":17,"id":51,"name":"dotnet","prevSize":32,"code":59663},"setIdx":0,"setId":0,"iconIdx":15},{"icon":{"paths":["M511.5 127.542c-17.459 0.281-31.503 14.5-31.503 31.999 0 0.161 0.001 0.323 0.004 0.483l-0-0.024v456.083l-73.375-73.375c-5.822-5.991-13.956-9.708-22.958-9.708l-0-0c-17.672 0.004-31.995 14.331-31.995 32.003 0 9 3.715 17.133 9.696 22.948l0.007 0.007 128 128c5.791 5.789 13.79 9.369 22.625 9.369s16.834-3.58 22.625-9.369l128-128c6.068-5.833 9.838-14.019 9.838-23.085 0-17.675-14.328-32.003-32.003-32.003-9.066 0-17.252 3.77-23.075 9.828l-0.010 0.011-73.375 73.375v-456.083c0.002-0.136 0.003-0.298 0.003-0.459 0-17.675-14.328-32.003-32.003-32.003-0.176 0-0.351 0.001-0.526 0.004l0.026-0zM159.5 660.875c-17.459 0.281-31.503 14.5-31.503 31.999 0 0.161 0.001 0.323 0.004 0.483l-0-0.024v85.333c0 64.422 52.911 117.333 117.333 117.333h533.333c64.422 0 117.333-52.911 117.333-117.333v-85.333c0.002-0.135 0.003-0.293 0.003-0.453 0-17.675-14.328-32.003-32.003-32.003s-32.003 14.328-32.003 32.003c0 0.159 0.001 0.318 0.003 0.477l-0-0.024v85.333c0 29.829-23.505 53.333-53.333 53.333h-533.333c-29.829 0-53.333-23.505-53.333-53.333v-85.333c0.002-0.137 0.003-0.298 0.003-0.459 0-17.675-14.328-32.003-32.003-32.003-0.176 0-0.351 0.001-0.527 0.004l0.026-0z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"grid":0,"tags":["download"]},"attrs":[{}],"properties":{"order":18,"id":50,"name":"download","prevSize":32,"code":59664},"setIdx":0,"setId":0,"iconIdx":16},{"icon":{"paths":[],"attrs":[],"isMulticolor":false,"isMulticolor2":false,"grid":0,"tags":["empty"]},"attrs":[],"properties":{"order":19,"id":49,"name":"empty","prevSize":32,"code":59665},"setIdx":0,"setId":0,"iconIdx":17},{"icon":{"paths":["M927.708 255.542c-8.79 0.214-16.67 3.94-22.323 9.823l-0.010 0.011-393.375 393.375-393.375-393.375c-5.822-5.991-13.956-9.708-22.958-9.708l-0-0c-17.672 0.004-31.995 14.331-31.995 32.003 0 9 3.715 17.133 9.696 22.948l0.007 0.007 416 416c5.791 5.789 13.79 9.369 22.625 9.369s16.834-3.58 22.625-9.369l416-416c6.071-5.833 9.842-14.021 9.842-23.089 0-17.675-14.328-32.003-32.003-32.003-0.266 0-0.531 0.003-0.795 0.010l0.039-0.001z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"grid":0,"tags":["expand"]},"attrs":[{}],"properties":{"order":20,"id":48,"name":"expand","prevSize":32,"code":59666},"setIdx":0,"setId":0,"iconIdx":18},{"icon":{"paths":["M352 106.667c-0.135-0.002-0.293-0.003-0.453-0.003-17.675 0-32.003 14.328-32.003 32.003s14.328 32.003 32.003 32.003c0.159 0 0.318-0.001 0.477-0.003l-0.024 0h10.667v251.708c0 19.522-5.972 38.59-17.083 54.625l-200.542 289.667c-0 0.006-0 0.014-0 0.021s0 0.015 0 0.022l-0-0.001c-24.882 35.964-22.396 85.778 8.083 119.375 19.897 21.953 47.733 31.25 74.208 31.25h569.333c26.475 0 54.311-9.297 74.208-31.25 30.48-33.597 32.965-83.41 8.083-119.375 0-0.006 0-0.014 0-0.021s-0-0.015-0-0.022l0 0.001-200.542-289.667c-11.111-16.035-17.083-35.103-17.083-54.625v-251.708h10.667c0.135 0.002 0.293 0.003 0.453 0.003 17.675 0 32.003-14.328 32.003-32.003s-14.328-32.003-32.003-32.003c-0.159 0-0.318 0.001-0.477 0.003l0.024-0h-320zM426.667 170.667h170.667v170.667h-170.667v-170.667zM426.667 405.333h170.667v17.042c0 32.532 9.916 64.324 28.458 91.083l200.542 289.667c8.331 12.073 7.978 28.041-2.833 39.958-0.014 0.014-0.028 0.028-0.041 0.041l-0 0c-5.487 6.058-15.475 10.208-26.792 10.208h-569.333c-11.317 0-21.304-4.149-26.792-10.208-0.014-0.014-0.028-0.028-0.041-0.041l-0-0c-10.811-11.916-11.164-27.885-2.833-39.958v-0.042l200.542-289.625c18.542-26.759 28.458-58.552 28.458-91.083v-17.042zM448 554.667c-23.564 0-42.667 19.103-42.667 42.667s19.103 42.667 42.667 42.667v0c23.564 0 42.667-19.103 42.667-42.667s-19.103-42.667-42.667-42.667v0zM629.333 682.667c-29.455 0-53.333 23.878-53.333 53.333s23.878 53.333 53.333 53.333v0c29.455 0 53.333-23.878 53.333-53.333s-23.878-53.333-53.333-53.333v0z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"grid":0,"tags":["experimental"]},"attrs":[{}],"properties":{"order":21,"id":47,"name":"experimental","prevSize":32,"code":59667},"setIdx":0,"setId":0,"iconIdx":19},{"icon":{"paths":["M394.333 63.667c-17.672 0.004-31.995 14.331-31.995 32.003 0 9 3.715 17.133 9.696 22.948l0.007 0.007 393.375 393.375-393.375 393.375c-6.068 5.833-9.838 14.019-9.838 23.085 0 17.675 14.328 32.003 32.003 32.003 9.066 0 17.252-3.77 23.075-9.828l0.010-0.011 416-416c5.789-5.791 9.369-13.79 9.369-22.625s-3.58-16.834-9.369-22.625l-416-416c-5.822-5.991-13.956-9.708-22.958-9.708l-0-0z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"grid":0,"tags":["forward"]},"attrs":[{}],"properties":{"order":22,"id":46,"name":"forward","prevSize":32,"code":59668},"setIdx":0,"setId":0,"iconIdx":20},{"icon":{"paths":["M512 40.96c-259.906 0-471.040 211.134-471.040 471.040s211.134 471.040 471.040 471.040c259.906 0 471.040-211.134 471.040-471.040s-211.134-471.040-471.040-471.040zM512 81.92c237.769 0 430.080 192.311 430.080 430.080s-192.311 430.080-430.080 430.080c-237.769 0-430.080-192.311-430.080-430.080s192.311-430.080 430.080-430.080zM237.56 266.24c-18.104 0-32.76 14.656-32.76 32.76v118.8c0 18.104 14.676 32.76 32.76 32.76h79.88v-40.96h-59.4c-6.779 0-12.28-5.501-12.28-12.28v-77.84c0-6.779 5.501-12.28 12.28-12.28h77.84c6.779 0 12.28 5.501 12.28 12.28v159.76c0 6.779-5.501 12.28-12.28 12.28h-131.080v40.96h151.56c18.104 0 32.76-14.656 32.76-32.76v-200.72c0-18.104-14.676-32.76-32.76-32.76h-118.8zM452.6 266.24c-18.063 0-32.76 14.697-32.76 32.76v118.8c0 18.063 14.697 32.76 32.76 32.76h118.8c18.063 0 32.76-14.697 32.76-32.76v-118.8c0-18.063-14.697-32.76-32.76-32.76h-118.8zM667.64 266.24c-18.104 0-32.76 14.656-32.76 32.76v118.8c0 18.104 14.676 32.76 32.76 32.76h79.88v-40.96h-59.4c-6.779 0-12.28-5.501-12.28-12.28v-77.84c0-6.779 5.501-12.28 12.28-12.28h77.84c6.779 0 12.28 5.501 12.28 12.28v159.76c0 6.779-5.501 12.28-12.28 12.28h-131.080v40.96h151.56c18.104 0 32.76-14.656 32.76-32.76v-200.72c0-18.104-14.676-32.76-32.76-32.76h-118.8zM473.080 307.2h77.84c6.779 0 12.28 5.501 12.28 12.28v77.84c0 6.779-5.501 12.28-12.28 12.28h-77.84c-6.779 0-12.28-5.501-12.28-12.28v-77.84c0-6.779 5.501-12.28 12.28-12.28zM237.56 573.44c-18.104 0-32.76 14.676-32.76 32.76v118.8c0 18.104 14.676 32.76 32.76 32.76h120.84v-40.96h-100.36c-6.779 0-12.28-5.501-12.28-12.28v-77.84c0-6.779 5.501-12.28 12.28-12.28h100.36v-40.96h-120.84zM421.88 573.44c-18.063 0-32.76 14.697-32.76 32.76v118.8c0 18.063 14.697 32.76 32.76 32.76h118.8c18.063 0 32.76-14.697 32.76-32.76v-118.8c0-18.063-14.697-32.76-32.76-32.76h-118.8zM636.92 573.44c-18.084 0-32.76 14.656-32.76 32.76v151.56h40.96v-131.080c0-6.779 5.501-12.28 12.28-12.28h33.8v143.36h40.96v-131.080c0-6.779 5.501-12.28 12.28-12.28h33.8v143.36h40.96v-184.32h-182.28zM442.36 614.4h77.84c6.779 0 12.28 5.501 12.28 12.28v77.84c0 6.779-5.501 12.28-12.28 12.28h-77.84c-6.779 0-12.28-5.501-12.28-12.28v-77.84c0-6.779 5.501-12.28 12.28-12.28z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"grid":0,"tags":["gog"]},"attrs":[{}],"properties":{"order":23,"id":45,"name":"gog","prevSize":32,"code":59669},"setIdx":0,"setId":0,"iconIdx":21},{"icon":{"paths":["M512 85.333c-235.263 0-426.667 191.404-426.667 426.667s191.404 426.667 426.667 426.667c235.263 0 426.667-191.404 426.667-426.667s-191.404-426.667-426.667-426.667zM512 149.333c200.674 0 362.667 161.992 362.667 362.667s-161.992 362.667-362.667 362.667c-200.674 0-362.667-161.992-362.667-362.667s161.992-362.667 362.667-362.667zM512 277.333c-70.312 0-128 57.688-128 128v10.667c-0.002 0.135-0.003 0.293-0.003 0.453 0 17.675 14.328 32.003 32.003 32.003s32.003-14.328 32.003-32.003c0-0.159-0.001-0.318-0.003-0.477l0 0.024v-10.667c0-35.715 28.285-64 64-64s64 28.285 64 64c0 49.939-12.984 56.197-35.75 74.083-11.383 8.943-26.292 19.254-39.042 36.625s-21.208 41.585-21.208 70.625c-0.002 0.135-0.003 0.293-0.003 0.453 0 17.675 14.328 32.003 32.003 32.003s32.003-14.328 32.003-32.003c0-0.159-0.001-0.318-0.003-0.477l0 0.024c0-18.202 3.541-25.596 8.792-32.75s14.341-14.254 26.958-24.167c25.234-19.826 60.25-57.023 60.25-124.417 0-70.312-57.688-128-128-128zM512 682.667c-23.564 0-42.667 19.103-42.667 42.667s19.103 42.667 42.667 42.667v0c23.564 0 42.667-19.103 42.667-42.667s-19.103-42.667-42.667-42.667v0z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"grid":0,"tags":["help"]},"attrs":[{}],"properties":{"order":24,"id":44,"name":"help","prevSize":32,"code":59670},"setIdx":0,"setId":0,"iconIdx":22},{"icon":{"paths":["M512 85.333c-139.431 0-263.442 67.182-341.333 170.917v-74.917c0.002-0.136 0.003-0.298 0.003-0.459 0-17.675-14.328-32.003-32.003-32.003-0.176 0-0.351 0.001-0.526 0.004l0.026-0c-17.459 0.281-31.503 14.5-31.503 31.999 0 0.161 0.001 0.323 0.004 0.483l-0-0.024v149.333c0.002 17.672 14.328 31.998 32 32l149.334 0c0.135 0.002 0.293 0.003 0.453 0.003 17.675 0 32.003-14.328 32.003-32.003s-14.328-32.003-32.003-32.003c-0.159 0-0.318 0.001-0.477 0.003l0.024-0h-69.333c65.9-90.492 172.569-149.333 293.333-149.333 200.668 0 362.667 161.999 362.667 362.667s-161.999 362.667-362.667 362.667c-200.668 0-362.667-161.999-362.667-362.667 0.002-0.135 0.003-0.293 0.003-0.453 0-17.675-14.328-32.003-32.003-32.003s-32.003 14.328-32.003 32.003c0 0.159 0.001 0.318 0.003 0.477l-0-0.024c0 235.258 191.409 426.667 426.667 426.667s426.667-191.409 426.667-426.667c0-235.258-191.409-426.667-426.667-426.667zM500.833 276.875c-17.459 0.281-31.503 14.5-31.503 31.999 0 0.161 0.001 0.323 0.004 0.483l-0-0.024v256c0.002 17.672 14.328 31.998 32 32l170.667 0c0.135 0.002 0.293 0.003 0.453 0.003 17.675 0 32.003-14.328 32.003-32.003s-14.328-32.003-32.003-32.003c-0.159 0-0.318 0.001-0.477 0.003l0.024-0h-138.667v-224c0.002-0.137 0.003-0.298 0.003-0.459 0-17.675-14.328-32.003-32.003-32.003-0.176 0-0.351 0.001-0.527 0.004l0.026-0z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"grid":0,"tags":["history"]},"attrs":[{}],"properties":{"order":25,"id":43,"name":"history","prevSize":32,"code":59671},"setIdx":0,"setId":0,"iconIdx":23},{"icon":{"paths":["M510.958 85.333c-7.135 0.251-13.63 2.8-18.815 6.925l0.065-0.050-303.208 238.875c-38.483 30.328-61 76.671-61 125.667v407.25c0 29.090 24.243 53.333 53.333 53.333h213.333c29.090 0 53.333-24.243 53.333-53.333v-213.333c0-6.294 4.372-10.667 10.667-10.667h106.667c6.294 0 10.667 4.372 10.667 10.667v213.333c0 29.090 24.243 53.333 53.333 53.333h213.333c29.090 0 53.333-24.243 53.333-53.333v-407.25c0-48.995-22.517-95.339-61-125.667l-303.208-238.875c-5.398-4.295-12.315-6.89-19.838-6.89-0.35 0-0.699 0.006-1.046 0.017l0.051-0.001zM512 158.083l283.417 223.292c23.128 18.227 36.583 45.949 36.583 75.375v396.583h-192v-202.667c0-40.852-33.814-74.667-74.667-74.667h-106.667c-40.852 0-74.667 33.814-74.667 74.667v202.667h-192v-396.583c0-29.426 13.456-57.148 36.583-75.375l283.417-223.292z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"grid":0,"tags":["home"]},"attrs":[{}],"properties":{"order":26,"id":42,"name":"home","prevSize":32,"code":59672},"setIdx":0,"setId":0,"iconIdx":24},{"icon":{"paths":["M223.708 170.708c-76.201 0-138.667 62.465-138.667 138.667v405.333c0 76.201 62.465 138.667 138.667 138.667h353.583c0.006 0 0.014 0 0.021 0s0.015-0 0.022-0l-0.001 0c41.476-0.026 81.336-16.182 111.167-45 0.006 0 0.014 0 0.021 0s0.015-0 0.022-0l-0.001 0 211.375-204.333c51.748-50.023 51.748-134.060 0-184.083l-211.375-204.292c-29.833-28.846-69.733-44.958-111.208-44.958h-353.625zM223.708 234.708h353.625c24.914 0 48.797 9.639 66.708 26.958l211.375 204.333c26.332 25.454 26.332 66.588 0 92.042l-211.375 204.292c-17.913 17.305-41.837 27.026-66.75 27.042h-353.583c-41.601 0-74.667-33.065-74.667-74.667v-405.333c0-41.601 33.065-74.667 74.667-74.667zM704 469.333c-23.564 0-42.667 19.103-42.667 42.667s19.103 42.667 42.667 42.667v0c23.564 0 42.667-19.103 42.667-42.667s-19.103-42.667-42.667-42.667v0z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"grid":0,"tags":["id"]},"attrs":[{}],"properties":{"order":27,"id":41,"name":"id","prevSize":32,"code":59673},"setIdx":0,"setId":0,"iconIdx":25},{"icon":{"paths":["M512 85.333c-235.263 0-426.667 191.404-426.667 426.667s191.404 426.667 426.667 426.667c235.263 0 426.667-191.404 426.667-426.667s-191.404-426.667-426.667-426.667zM512 149.333c200.674 0 362.667 161.992 362.667 362.667s-161.992 362.667-362.667 362.667c-200.674 0-362.667-161.992-362.667-362.667s161.992-362.667 362.667-362.667zM512 298.667c-23.564 0-42.667 19.103-42.667 42.667s19.103 42.667 42.667 42.667v0c23.564 0 42.667-19.103 42.667-42.667s-19.103-42.667-42.667-42.667v0zM511.5 447.542c-17.459 0.281-31.503 14.5-31.503 31.999 0 0.161 0.001 0.323 0.004 0.483l-0-0.024v234.667c-0.002 0.135-0.003 0.293-0.003 0.453 0 17.675 14.328 32.003 32.003 32.003s32.003-14.328 32.003-32.003c0-0.159-0.001-0.318-0.003-0.477l0 0.024v-234.667c0.002-0.137 0.003-0.298 0.003-0.459 0-17.675-14.328-32.003-32.003-32.003-0.176 0-0.351 0.001-0.527 0.004l0.026-0z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"grid":0,"tags":["info_round"]},"attrs":[{}],"properties":{"order":28,"id":40,"name":"info_round","prevSize":32,"code":59674},"setIdx":0,"setId":0,"iconIdx":26},{"icon":{"paths":["M512 85.333c-235.263 0-426.667 191.404-426.667 426.667s191.404 426.667 426.667 426.667c235.263 0 426.667-191.404 426.667-426.667s-191.404-426.667-426.667-426.667zM512 149.333c200.674 0 362.667 161.992 362.667 362.667s-161.992 362.667-362.667 362.667c-200.674 0-362.667-161.992-362.667-362.667s161.992-362.667 362.667-362.667zM671.375 383.708c-8.646 0.26-16.392 3.91-21.993 9.66l-0.007 0.007-190.708 190.708-84.042-84.042c-5.833-6.068-14.019-9.838-23.085-9.838-17.675 0-32.003 14.328-32.003 32.003 0 9.066 3.77 17.252 9.828 23.075l0.011 0.010 106.667 106.667c5.791 5.789 13.79 9.369 22.625 9.369s16.834-3.58 22.625-9.369l213.333-213.333c5.971-5.82 9.675-13.941 9.675-22.927 0-17.675-14.328-32.003-32.003-32.003-0.324 0-0.647 0.005-0.969 0.014l0.047-0.001z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"grid":0,"tags":["installed"]},"attrs":[{}],"properties":{"order":29,"id":39,"name":"installed","prevSize":32,"code":59675},"setIdx":0,"setId":0,"iconIdx":27},{"icon":{"paths":["M512 85.333c-235.264 0-426.667 191.403-426.667 426.667s191.403 426.667 426.667 426.667 426.667-191.403 426.667-426.667-191.403-426.667-426.667-426.667zM694.635 438.635l-213.333 213.333c-6.251 6.251-14.443 9.365-22.635 9.365s-16.384-3.115-22.635-9.365l-106.667-106.667c-12.501-12.501-12.501-32.747 0-45.248s32.747-12.501 45.248 0l84.032 84.032 190.699-190.699c12.501-12.501 32.747-12.501 45.248 0s12.523 32.747 0.043 45.248z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"grid":0,"tags":["installed_filled"]},"attrs":[{}],"properties":{"order":30,"id":38,"name":"installed_filled","prevSize":32,"code":59676},"setIdx":0,"setId":0,"iconIdx":28},{"icon":{"paths":["M501.333 106.667c-135.117 0-245.333 110.216-245.333 245.333 0 34.792 7.283 68.053 20.417 98.125 4.987 11.584 16.303 19.547 29.48 19.547 17.675 0 32.003-14.328 32.003-32.003 0-4.756-1.037-9.269-2.898-13.326l0.082 0.199c-9.693-22.194-15.083-46.661-15.083-72.542 0-100.531 80.802-181.333 181.333-181.333s181.333 80.802 181.333 181.333c0 12.464-1.251 24.583-3.625 36.292-0.5 2.12-0.787 4.554-0.787 7.054 0 17.675 14.328 32.003 32.003 32.003 15.662 0 28.696-11.25 31.462-26.11l0.031-0.198c3.215-15.854 4.917-32.279 4.917-49.042 0-135.117-110.216-245.333-245.333-245.333zM501.333 256c-52.64 0-96 43.36-96 96v197.542l-18.375-7.583c-77.971-32.082-166.484 22.020-173.5 106.042-0.072 0.807-0.114 1.745-0.114 2.693 0 11.281 5.837 21.198 14.655 26.898l0.126 0.076 197.625 125.917c13.739 8.763 25.483 20.311 34.542 33.875l31.083 46.625c0.006 0 0.014 0 0.021 0s0.015-0 0.022-0l-0.001 0c16.4 24.544 45.967 37.222 75.083 32.083l113.667-20.042c36.716-6.455 66.476-33.788 76.083-69.792-0.035 0.167-0.020 0.111-0.006 0.055l0.048-0.221 50.792-195.208c17.532-65.74-25.416-133.492-92.375-145.667l-117.375-21.333v-111.958c0-52.64-43.36-96-96-96zM501.333 320c18.059 0 32 13.941 32 32v138.667c-0 0.003-0 0.007-0 0.011 0 15.656 11.242 28.686 26.094 31.459l0.198 0.031 143.625 26.083c31.132 5.66 50.151 35.649 42 66.208 0.049-0.144 0.021-0.075-0.007-0.006l-0.077 0.215-50.75 195.167c-3.235 12.125-13.026 21.086-25.333 23.25-0 0.006-0 0.014-0 0.021s0 0.015 0 0.022l-0-0.001-113.708 20.042c-4.249 0.75-8.334-1.009-10.75-4.625l-31.083-46.583c-13.979-20.942-32.136-38.787-53.375-52.333-0.006-0-0.014-0-0.021-0s-0.015 0-0.022 0l0.001-0-177.417-113.125c12.003-31.65 46.115-49.224 79.875-35.333l62.583 25.75c3.596 1.519 7.777 2.402 12.163 2.402 17.668 0 31.993-14.318 32.003-31.984l0-0.001v-245.333c0-18.059 13.941-32 32-32z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"grid":0,"tags":["interactive"]},"attrs":[{}],"properties":{"order":31,"id":37,"name":"interactive","prevSize":32,"code":59677},"setIdx":0,"setId":0,"iconIdx":29},{"icon":{"paths":["M884.708 106.375c-1.261 0.039-2.455 0.143-3.63 0.312l0.171-0.020h-294.583c-0.135-0.002-0.293-0.003-0.453-0.003-17.675 0-32.003 14.328-32.003 32.003s14.328 32.003 32.003 32.003c0.159 0 0.318-0.001 0.477-0.003l-0.024 0h221.417l-329.375 329.375c-6.068 5.833-9.838 14.019-9.838 23.085 0 17.675 14.328 32.003 32.003 32.003 9.066 0 17.252-3.77 23.075-9.828l0.010-0.011 329.375-329.375v221.417c-0.002 0.135-0.003 0.293-0.003 0.453 0 17.675 14.328 32.003 32.003 32.003s32.003-14.328 32.003-32.003c0-0.159-0.001-0.318-0.003-0.477l0 0.024v-294.625c0.188-1.305 0.296-2.811 0.296-4.343 0-17.675-14.328-32.003-32.003-32.003-0.323 0-0.644 0.005-0.965 0.014l0.047-0.001zM266.667 170.667c-87.989 0-160 72.011-160 160v426.667c0 87.989 72.011 160 160 160h426.667c87.989 0 160-72.011 160-160v-213.333c0.002-0.135 0.003-0.293 0.003-0.453 0-17.675-14.328-32.003-32.003-32.003s-32.003 14.328-32.003 32.003c0 0.159 0.001 0.318 0.003 0.477l-0-0.024v213.333c0 53.408-42.592 96-96 96h-426.667c-53.408 0-96-42.592-96-96v-426.667c0-53.408 42.592-96 96-96h213.333c0.135 0.002 0.293 0.003 0.453 0.003 17.675 0 32.003-14.328 32.003-32.003s-14.328-32.003-32.003-32.003c-0.159 0-0.318 0.001-0.477 0.003l0.024-0h-213.333z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"grid":0,"tags":["launch"]},"attrs":[{}],"properties":{"order":32,"id":36,"name":"launch","prevSize":32,"code":59678},"setIdx":0,"setId":0,"iconIdx":30},{"icon":{"paths":["M725.333 85.375c-18.208 0-36.4 2.208-54.875 6.667-13.269 3.179-23.094 14.474-24.417 28.042l-0.875 9c-1.003 10.261-6.895 19.462-15.833 24.625-8.939 5.141-19.864 5.726-29.208 1.417l-8.292-3.75c-12.352-5.611-27.072-2.815-36.458 7.083-25.557 26.88-44.631 59.756-55.042 95.042-3.883 13.077 1.010 27.147 12.125 35.083l7.458 5.333c8.384 6.037 13.417 15.779 13.417 26.083 0 5.461-1.482 10.724-4.042 15.375l4 24.667 30.792-11.667c8.448-3.179 17.289-4.792 26.292-4.792 1.173 0 2.327 0.311 3.5 0.375 2.048-7.787 3.458-15.745 3.458-23.958 0-25.728-10.391-50.248-28.375-68.125 5.12-11.712 11.613-22.862 19.25-33.208 24.448 6.635 50.853 3.364 73.125-9.5s38.348-34.155 44.833-58.667c12.992-1.536 25.362-1.536 38.375 0 6.464 24.512 22.498 45.803 44.792 58.667 22.251 12.885 48.634 16.135 73.125 9.5 7.637 10.325 14.13 21.496 19.25 33.208-17.984 17.899-28.375 42.397-28.375 68.125s10.391 50.248 28.375 68.125c-5.12 11.712-11.613 22.862-19.25 33.208-24.448-6.635-50.853-3.364-73.125 9.5-22.293 12.864-38.348 34.155-44.833 58.667-7.339 0.875-14.457 1.107-21.625 1 3.648 9.6 6.997 19.269 9.792 29.125 3.243 11.456 3.53 23.257 1.375 34.5 15.211-0.597 30.678-2.433 46.208-6.167 13.248-3.179 23.052-14.474 24.375-28.042l0.875-9.042c1.003-10.261 6.895-19.421 15.833-24.583 8.96-5.12 19.886-5.683 29.208-1.417l8.292 3.75c12.352 5.653 27.093 2.837 36.458-7.083 25.557-26.88 44.631-59.756 55.042-95.042 3.883-13.099-1.010-27.169-12.125-35.083l-7.458-5.333c-8.384-6.037-13.417-15.779-13.417-26.083s5.012-20.026 13.375-26.042l7.5-5.375c11.115-7.915 16.008-21.985 12.125-35.083-10.411-35.285-29.484-68.162-55.042-95.042-9.387-9.92-24.128-12.737-36.458-7.083l-8.25 3.75c-9.429 4.267-20.333 3.682-29.25-1.417-8.939-5.163-14.831-14.343-15.833-24.583l-0.875-9.042c-1.323-13.589-11.147-24.863-24.417-28.042-18.475-4.459-36.667-6.667-54.875-6.667zM725.333 234.667c-25.778 0-49.163 10.819-63.917 27.417s-21.417 37.472-21.417 57.917c0 20.444 6.663 41.319 21.417 57.917s38.139 27.417 63.917 27.417c25.778 0 49.163-10.819 63.917-27.417s21.417-37.472 21.417-57.917c0-20.444-6.663-41.319-21.417-57.917s-38.139-27.417-63.917-27.417zM384 298.667c-27.258 0-53.388 3.756-78.125 9.958-12.33 3.171-21.663 13.202-23.766 25.687l-0.026 0.188-5.292 32.375c-2.079 12.673-9.69 23.672-20.792 30.083s-24.379 7.501-36.417 2.958l-30.792-11.667c-3.358-1.307-7.245-2.065-11.309-2.065-9.014 0-17.158 3.727-22.974 9.723l-0.008 0.008c-36.331 37.445-63.499 83.746-78.125 135.375-0.768 2.613-1.211 5.614-1.211 8.719 0 9.966 4.555 18.867 11.697 24.737l0.056 0.044 25.458 20.833c9.901 8.153 15.625 20.231 15.625 33.042 0 12.83-5.744 24.916-15.667 33.042l-25.458 20.833c-7.177 5.914-11.718 14.803-11.718 24.753 0 3.115 0.445 6.126 1.275 8.973l-0.056-0.226c14.644 51.61 41.789 97.925 78.125 135.375 5.821 5.98 13.948 9.69 22.941 9.69 4.064 0 7.951-0.757 11.527-2.139l-0.219 0.074 30.833-11.625c12.003-4.535 25.281-3.466 36.417 2.958 11.119 6.415 18.686 17.391 20.75 30.042l5.292 32.375c2.129 12.673 11.461 22.704 23.57 25.826l0.222 0.049c24.77 6.228 50.909 10 78.167 10s53.388-3.756 78.125-9.958c12.33-3.171 21.663-13.202 23.766-25.687l0.026-0.188 5.292-32.375c2.079-12.673 9.69-23.672 20.792-30.083s24.379-7.501 36.417-2.958l30.792 11.667c3.358 1.307 7.245 2.065 11.309 2.065 9.014 0 17.158-3.727 22.974-9.723l0.008-0.008c36.331-37.445 63.499-83.746 78.125-135.375 0.768-2.613 1.211-5.614 1.211-8.719 0-9.966-4.555-18.867-11.697-24.737l-0.056-0.044-25.458-20.833c-9.901-8.153-15.625-20.231-15.625-33.042 0-12.83 5.744-24.916 15.667-33.042l25.458-20.833c7.177-5.914 11.718-14.803 11.718-24.753 0-3.115-0.445-6.126-1.275-8.973l0.056 0.226c-14.647-51.679-41.973-97.897-78.208-135.292-5.824-6.005-13.968-9.732-22.982-9.732-4.064 0-7.951 0.758-11.528 2.139l0.219-0.074-30.708 11.583c-12.003 4.535-25.322 3.466-36.458-2.958-11.119-6.415-18.686-17.391-20.75-30.042l-5.375-32.708c-2.122-12.663-11.437-22.69-23.528-25.826l-0.222-0.049c-24.965-6.277-51.144-9.667-78.083-9.667zM725.333 298.667c9.778 0 13.059 2.514 16.083 5.917s5.25 9.194 5.25 15.417c0 6.222-2.226 12.014-5.25 15.417s-6.306 5.917-16.083 5.917c-9.778 0-13.059-2.514-16.083-5.917s-5.25-9.194-5.25-15.417c0-6.222 2.226-12.014 5.25-15.417s6.306-5.917 16.083-5.917zM384 362.667c14.694 0 28.544 2.901 42.542 5.292l1.5 9.292c5.156 31.535 24.262 59.188 51.958 75.167 27.691 15.975 61.146 18.67 91.042 7.375l8.542-3.208c18.187 21.936 32.526 46.622 42.625 73.75l-7.083 5.792c-0.006-0-0.014-0-0.021-0s-0.015 0-0.022 0l0.001-0c-24.722 20.247-39.083 50.572-39.083 82.542s14.368 62.28 39.042 82.542c0.014 0.014 0.028 0.028 0.041 0.041l0 0 7.125 5.833c-10.082 27.152-24.396 51.852-42.542 73.75l-8.625-3.292c-29.904-11.286-63.401-8.571-91.083 7.417s-46.743 43.595-51.917 75.125c-0 0.006-0 0.014-0 0.021s0 0.015 0 0.022l-0-0.001-1.5 9.083c-14.055 2.474-27.998 5.458-42.542 5.458-14.558 0-28.516-2.973-42.583-5.458l-1.5-9.083v-0.042c-5.156-31.534-24.22-59.188-51.917-75.167-27.691-15.975-61.146-18.67-91.042-7.375l-8.667 3.25c-18.141-21.902-32.455-46.582-42.542-73.75l7.125-5.833c0.006 0 0.014 0 0.021 0s0.015-0 0.022-0l-0.001 0c24.723-20.247 39.083-50.572 39.083-82.542s-14.368-62.28-39.042-82.542c-0.014-0.014-0.028-0.028-0.041-0.041l-0-0-7.125-5.833c10.082-27.152 24.396-51.852 42.542-73.75l8.625 3.292c29.904 11.286 63.401 8.571 91.083-7.417s46.743-43.595 51.917-75.125c0-0.006 0-0.014 0-0.021s-0-0.015-0-0.022l0 0.001 1.5-9.083c14.054-2.475 27.998-5.458 42.542-5.458zM384 490.667c-40 0-74.052 16.152-95.917 40.75s-32.083 56.139-32.083 87.25c0 31.111 10.219 62.652 32.083 87.25s55.917 40.75 95.917 40.75c40 0 74.052-16.152 95.917-40.75s32.083-56.139 32.083-87.25c0-31.111-10.219-62.652-32.083-87.25s-55.917-40.75-95.917-40.75zM384 554.667c24 0 37.948 7.848 48.083 19.25s15.917 27.861 15.917 44.75c0 16.889-5.781 33.348-15.917 44.75s-24.083 19.25-48.083 19.25c-24 0-37.948-7.848-48.083-19.25s-15.917-27.861-15.917-44.75c0-16.889 5.781-33.348 15.917-44.75s24.083-19.25 48.083-19.25z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"grid":0,"tags":["loading"]},"attrs":[{}],"properties":{"order":33,"id":35,"name":"loading","prevSize":32,"code":59679},"setIdx":0,"setId":0,"iconIdx":31},{"icon":{"paths":["M725.333 85.375c-18.208 0-36.4 2.208-54.875 6.667-13.269 3.179-23.094 14.474-24.417 28.042l-0.875 9c-1.003 10.261-6.895 19.462-15.833 24.625-8.939 5.141-19.864 5.726-29.208 1.417l-8.292-3.75c-12.352-5.611-27.072-2.815-36.458 7.083-25.557 26.88-44.631 59.756-55.042 95.042-3.883 13.077 1.010 27.147 12.125 35.083l7.458 5.333c8.384 6.037 13.417 15.779 13.417 26.083s-5.012 20.026-13.375 26.042l-7.5 5.375c-0.683 0.491-1.11 1.175-1.75 1.708l1.542 10.125c1.003 6.528 4.658 11.943 10.375 15.25 3.307 1.899 6.997 2.917 10.667 2.917 2.603 0 5.21-0.518 7.792-1.542l36.708-14.333c8.683-3.371 17.782-5.083 27.083-5.083 22.272 0 43.23 9.829 57.417 26.917 26.261 31.573 46.852 67.137 61.167 105.75 7.616 20.565 5.524 42.735-4.375 61.167 2.091 0.064 4.202 0.375 6.25 0.375 17.963 0 36.442-2.25 54.917-6.708 13.248-3.179 23.052-14.432 24.375-28l0.875-9.042c1.003-10.261 6.895-19.462 15.833-24.625 8.96-5.12 19.886-5.683 29.208-1.417l8.292 3.792c12.352 5.653 27.093 2.837 36.458-7.083 25.557-26.88 44.631-59.756 55.042-95.042 3.883-13.12-1.010-27.21-12.125-35.125l-7.458-5.333c-8.384-6.037-13.417-15.779-13.417-26.083s5.012-20.026 13.375-26.042l7.5-5.375c11.115-7.915 16.008-21.985 12.125-35.083-10.411-35.285-29.484-68.162-55.042-95.042-9.387-9.92-24.128-12.737-36.458-7.083l-8.25 3.75c-9.429 4.267-20.333 3.682-29.25-1.417-8.939-5.163-14.831-14.343-15.833-24.583l-0.875-9.042c-1.323-13.589-11.147-24.863-24.417-28.042-18.475-4.459-36.667-6.667-54.875-6.667zM725.333 256c35.349 0 64 28.651 64 64s-28.651 64-64 64c-35.349 0-64-28.651-64-64s28.651-64 64-64zM381.917 298.583c-17.229 0.053-33.762 1.81-51.917 5.042-13.504 2.368-24.014 13.099-26.083 26.667l-6 39.375c-2.923 19.307-14.311 36-31.25 45.792-16.896 9.771-37.052 11.355-55.292 4.208l-36.75-14.375c-12.821-4.971-27.439-1.269-36.25 9.333-23.125 27.819-41.267 59.22-53.875 93.375-4.779 12.928-0.732 27.465 10.042 36.083l30.792 24.625c15.253 12.181 24 30.396 24 49.958s-8.747 37.777-24 49.958l-30.792 24.625c-10.773 8.619-14.799 23.155-10.042 36.083 12.629 34.155 30.75 65.556 53.875 93.375 8.811 10.603 23.471 14.368 36.25 9.333l36.75-14.375c18.219-7.125 38.396-5.541 55.292 4.208 16.939 9.792 28.348 26.464 31.292 45.792l5.958 39.375c2.069 13.568 12.579 24.299 26.083 26.667 18.709 3.349 36.357 4.958 54 4.958s35.291-1.589 54-4.917c13.504-2.368 24.014-13.14 26.083-26.708l5.958-39.375h0.042c2.923-19.307 14.311-36 31.25-45.792 16.939-9.749 37.094-11.292 55.292-4.167l36.75 14.375c12.821 4.992 27.439 1.228 36.25-9.375 23.125-27.819 41.267-59.179 53.875-93.333 4.779-12.949 0.732-27.506-10.042-36.125l-30.792-24.625c-15.253-12.181-24-30.396-24-49.958s8.767-37.797 24.042-50l30.75-24.583c10.773-8.597 14.779-23.197 10-36.125-12.629-34.048-30.769-65.409-53.958-93.292-8.811-10.603-23.45-14.346-36.25-9.375l-36.625 14.333c-18.197 7.147-38.353 5.604-55.292-4.167-16.939-9.792-28.348-26.464-31.292-45.792l-5.958-39.208c-2.069-13.632-12.64-24.383-26.208-26.708-20.811-3.573-38.729-5.22-55.958-5.167zM384 512c58.901 0 106.667 47.765 106.667 106.667s-47.765 106.667-106.667 106.667c-58.901 0-106.667-47.765-106.667-106.667s47.765-106.667 106.667-106.667z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"grid":0,"tags":["loading_filled"]},"attrs":[{}],"properties":{"order":34,"id":34,"name":"loading_filled","prevSize":32,"code":59680},"setIdx":0,"setId":0,"iconIdx":32},{"icon":{"paths":["M202.667 128c-52.64 0-96 43.36-96 96v576c0 52.64 43.36 96 96 96h234.667c52.64 0 96-43.36 96-96v-576c0-52.64-43.36-96-96-96h-234.667zM537.167 128c16.896 17.557 29.134 39.531 34.958 64h249.208c17.643 0 32 14.357 32 32v405.333c0 17.643-14.357 32-32 32h-165.417c-1.626-0.293-3.497-0.46-5.408-0.46-0.12 0-0.241 0.001-0.361 0.002l0.018-0c-1.681 0.042-3.29 0.207-4.86 0.487l0.193-0.029h-69.5v64h42.667v106.667h-46.542c-5.824 24.469-18.062 46.443-34.958 64h108.25c1.559 0.269 3.356 0.423 5.187 0.423s3.628-0.154 5.376-0.45l-0.188 0.026h80.208c17.685 0 32-14.315 32-32s-14.315-32-32-32h-53.333v-106.667h138.667c52.928 0 96-43.072 96-96v-405.333c0-52.928-43.072-96-96-96h-284.167zM202.667 192h234.667c18.059 0 32 13.941 32 32v576c0 18.059-13.941 32-32 32h-234.667c-18.059 0-32-13.941-32-32v-576c0-18.059 13.941-32 32-32zM245.333 234.667c-17.672 0.002-31.998 14.328-32 32l-0 0v101.417c-0.269 1.559-0.423 3.356-0.423 5.187s0.154 3.628 0.45 5.376l-0.026-0.188v101.542c0.002 17.672 14.328 31.998 32 32l149.334 0c17.672-0.002 31.998-14.328 32-32l0-0v-101.417c0.269-1.559 0.423-3.356 0.423-5.187s-0.154-3.628-0.45-5.376l0.026 0.188v-101.542c-0.002-17.672-14.328-31.998-32-32l-149.334-0zM277.333 298.667h85.333v42.667h-85.333v-42.667zM277.333 405.333h85.333v42.667h-85.333v-42.667zM320 661.333c-23.564 0-42.667 19.103-42.667 42.667s19.103 42.667 42.667 42.667v0c23.564 0 42.667-19.103 42.667-42.667s-19.103-42.667-42.667-42.667v0z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"grid":0,"tags":["local_pc"]},"attrs":[{}],"properties":{"order":35,"id":33,"name":"local_pc","prevSize":32,"code":59681},"setIdx":0,"setId":0,"iconIdx":33},{"icon":{"paths":["M838.042 171.292c-7.52 0.333-15.119 1.58-22.708 3.833l-661.375 196.583c-40.553 12.083-68.625 49.687-68.625 92.042v96.5c0 42.355 28.072 79.959 68.625 92.042l106.583 31.667c-9.435 80.839 37.186 159.888 117.75 183.708 80.389 23.745 162.299-17.028 198.458-89.708l238.542 70.917c60.715 18.060 123.375-28.648 123.375-92v-489.75c0-47.506-35.229-85.664-78.458-94.167-7.205-1.417-14.646-1.999-22.167-1.667zM841.417 235.042c18.080-1.116 33.25 12.616 33.25 32.083v489.75c0 22.28-19.792 37.012-41.125 30.667l-661.333-196.625c-13.686-4.105-22.875-16.381-22.875-30.667v-96.5c0-14.286 9.189-26.562 22.875-30.667l661.333-196.625c2.667-0.792 5.292-1.257 7.875-1.417zM321.792 702.167l193.708 57.583c-24.748 39.658-71.848 60.494-119.083 46.542-47.337-13.996-75.551-57.265-74.625-104.125z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"grid":0,"tags":["megaphone"]},"attrs":[{}],"properties":{"order":36,"id":32,"name":"megaphone","prevSize":32,"code":59682},"setIdx":0,"setId":0,"iconIdx":34},{"icon":{"paths":["M490.667 42.667c-98.447 0-180.060 74.967-190.75 170.667h-43.917c-49.323 0-90.38 36.975-95.5 86.042l-53.333 512c-2.816 26.987 5.991 54.047 24.167 74.25 18.176 20.16 44.197 31.708 71.333 31.708h618.667c27.136 0 53.157-11.548 71.333-31.708 18.176-20.181 26.941-47.263 24.125-74.25l-53.292-512c-5.12-49.067-46.177-86.042-95.5-86.042h-43.667c0.661 7.040 1 14.165 1 21.333v42.667h42.667c16.448 0 30.127 12.346 31.833 28.708l53.333 512c0.939 9.003-2.004 18.010-8.042 24.708-6.059 6.72-14.746 10.583-23.792 10.583h-618.667c-9.045 0-17.713-3.843-23.75-10.542-6.059-6.72-9.022-15.747-8.083-24.75l53.333-512c1.707-16.363 15.385-28.708 31.833-28.708h42.667v74.667c-0.002 0.135-0.003 0.293-0.003 0.453 0 17.675 14.328 32.003 32.003 32.003s32.003-14.328 32.003-32.003c0-0.159-0.001-0.318-0.003-0.477l0 0.024v-117.333c0-71.067 56.933-128 128-128 63.782 0 116.052 45.89 126.125 106.667h-208.625c-1.792 6.827-2.833 13.952-2.833 21.333v42.667h213.333v74.667c-0.002 0.135-0.003 0.293-0.003 0.453 0 17.675 14.328 32.003 32.003 32.003s32.003-14.328 32.003-32.003c0-0.159-0.001-0.318-0.003-0.477l0 0.024v-117.333c0-105.658-86.342-192-192-192z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"grid":0,"tags":["ms_store"]},"attrs":[{}],"properties":{"order":37,"id":31,"name":"ms_store","prevSize":32,"code":59683},"setIdx":0,"setId":0,"iconIdx":35},{"icon":{"paths":["M0 320v352h288v64h224v-64h512v-352h-1024zM56.875 376.875h227.625v245.375h-56.938v-188.437h-56.875v188.437h-113.812v-245.375zM341.375 376.875h227.562v245.312h-113.813v56.938h-113.75v-302.25zM625.813 376.875h341.375v245.375h-56.938v-188.437h-56.875v188.437h-56.875v-188.437h-56.938v188.437h-113.75v-245.375zM455.125 433.813v131.562h56.875v-131.562h-56.875z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"grid":0,"tags":["node"]},"attrs":[{}],"properties":{"order":38,"id":30,"name":"node","prevSize":32,"code":59684},"setIdx":0,"setId":0,"iconIdx":36},{"icon":{"paths":["M181.333 170.667c-52.64 0-96 43.36-96 96v510h0.333c-0.621 39.908 31.846 76.667 74.375 76.667h619.625c39.893 0 75.859-24.896 89.875-62.25l106.833-284.5c18.261-47.881-18.491-101.25-69.75-101.25h-10.625v-32c0-52.64-43.36-96-96-96h-287.083l-95.333-79.458c-0.006-0-0.014-0-0.021-0s-0.015 0-0.022 0l0.001-0c-21.081-17.563-47.64-27.208-75.083-27.208h-161.125zM181.333 234.667h161.125c12.492 0 24.53 4.381 34.125 12.375l104.25 86.875c5.508 4.614 12.67 7.417 20.487 7.417 0.005 0 0.009-0 0.014-0l298.666 0c18.059 0 32 13.941 32 32v32h-545c-39.893 0-75.859 24.896-89.875 62.25l-47.792 127.25v-328.167c0-18.059 13.941-32 32-32zM287 469.333h619.625c8.53 0 13 6.51 9.958 14.458 0.049-0.144 0.021-0.075-0.007-0.006l-0.077 0.215-106.875 284.583c-4.715 12.566-16.518 20.75-29.958 20.75h-619.625c-8.485 0-12.979-6.462-10-14.375 0.014-0.014 0.028-0.028 0.041-0.041l0-0 106.958-284.833c4.715-12.566 16.518-20.75 29.958-20.75z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"grid":0,"tags":["open_folder"]},"attrs":[{}],"properties":{"order":39,"id":29,"name":"open_folder","prevSize":32,"code":59685},"setIdx":0,"setId":0,"iconIdx":37},{"icon":{"paths":["M85.333 780.8c0 17.067 12.8 29.867 34.133 29.867h422.4c4.267 21.333 17.067 42.667 29.867 55.467 21.333 21.333 51.2 29.867 81.067 29.867s55.467-8.533 81.067-29.867c17.067-12.8 25.6-34.133 29.867-55.467h145.067c17.067 0 34.133-12.8 34.133-29.867s-12.8-34.133-29.867-34.133c0 0 0 0 0 0h-145.067c-4.267-21.333-17.067-42.667-29.867-55.467-21.333-21.333-51.2-29.867-81.067-29.867s-55.467 8.533-81.067 29.867c-17.067 12.8-25.6 34.133-29.867 55.467h-426.667c-21.333 0-34.133 12.8-34.133 34.133 0-4.267 0 0 0 0zM85.333 512c0 17.067 12.8 29.867 34.133 29.867h102.4c4.267 21.333 17.067 42.667 29.867 55.467 21.333 21.333 51.2 29.867 81.067 29.867s55.467-8.533 81.067-29.867c17.067-12.8 25.6-34.133 29.867-55.467h465.067c17.067 0 34.133-12.8 34.133-29.867s-12.8-34.133-29.867-34.133c0 0 0 0 0 0h-473.6c-4.267-21.333-17.067-42.667-29.867-55.467-21.333-17.067-51.2-29.867-76.8-29.867s-59.733 12.8-81.067 29.867c-17.067 12.8-25.6 34.133-29.867 55.467h-102.4c-21.333-0-34.133 17.067-34.133 34.133 0 0 0 0 0 0zM85.333 247.467c0 17.067 12.8 29.867 34.133 29.867h465.067c4.267 21.333 17.067 42.667 29.867 55.467 21.333 21.333 51.2 29.867 81.067 29.867s55.467-8.533 81.067-29.867c17.067-12.8 25.6-34.133 29.867-55.467h102.4c17.067 0 34.133-12.8 34.133-29.867s-17.067-34.133-34.133-34.133c0 0 0 0 0 0h-102.4c-4.267-21.333-17.067-42.667-29.867-55.467-25.6-21.333-55.467-29.867-81.067-29.867s-55.467 8.533-81.067 29.867c-17.067 12.8-25.6 34.133-29.867 55.467h-465.067c-21.333 0-34.133 12.8-34.133 34.133 0-4.267 0 0 0 0zM277.333 512c0 0 0 0 0 0 0-21.333 8.533-34.133 17.067-42.667s21.333-12.8 38.4-12.8c12.8 0 29.867 4.267 38.4 12.8s12.8 21.333 12.8 42.667-8.533 29.867-17.067 38.4-21.333 12.8-38.4 12.8c-12.8 0-29.867-4.267-38.4-12.8-4.267-4.267-12.8-17.067-12.8-38.4zM597.333 780.8c0 0 0-4.267 0 0 0-21.333 8.533-34.133 17.067-42.667s21.333-12.8 38.4-12.8 29.867 4.267 38.4 12.8c8.533 8.533 17.067 17.067 17.067 38.4 0 0 0 4.267 0 4.267 0 17.067-8.533 29.867-17.067 38.4s-21.333 12.8-38.4 12.8-29.867-4.267-38.4-12.8c-8.533-8.533-17.067-21.333-17.067-38.4zM640 247.467c0 0 0-4.267 0 0 0-21.333 8.533-34.133 17.067-42.667s21.333-12.8 38.4-12.8 29.867 4.267 38.4 12.8c8.533 8.533 17.067 17.067 17.067 38.4 0 0 0 4.267 0 4.267 0 17.067-8.533 29.867-17.067 38.4-12.8 8.533-25.6 12.8-38.4 12.8s-29.867-4.267-38.4-12.8c-8.533-8.533-17.067-21.333-17.067-38.4z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"grid":0,"tags":["options"]},"attrs":[{}],"properties":{"order":40,"id":28,"name":"options","prevSize":32,"code":59686},"setIdx":0,"setId":0,"iconIdx":38},{"icon":{"paths":["M296.625 128c-28.455 0-55.512 12.656-73.75 34.542l-72.625 87.167c-0.006-0-0.014-0-0.021-0s-0.015 0-0.022 0l0.001-0c-14.336 17.242-22.208 39.007-22.208 61.458v467.5c0 64.422 52.911 117.333 117.333 117.333h533.333c64.422 0 117.333-52.911 117.333-117.333v-467.5c0-22.452-7.879-44.207-22.25-61.458l-72.625-87.167c-18.238-21.886-45.295-34.542-73.75-34.542h-430.75zM296.625 192h183.375v85.333h-269.5l61.542-73.833c6.082-7.298 15.065-11.5 24.583-11.5zM544 192h183.375c9.519 0 18.502 4.202 24.583 11.5l61.5 73.833h-269.458v-85.333zM192 341.333h640v437.333c0 29.829-23.505 53.333-53.333 53.333h-533.333c-29.829 0-53.333-23.505-53.333-53.333v-437.333zM416 426.667c-0.135-0.002-0.293-0.003-0.453-0.003-17.675 0-32.003 14.328-32.003 32.003s14.328 32.003 32.003 32.003c0.159 0 0.318-0.001 0.477-0.003l-0.024 0h192c0.135 0.002 0.293 0.003 0.453 0.003 17.675 0 32.003-14.328 32.003-32.003s-14.328-32.003-32.003-32.003c-0.159 0-0.318 0.001-0.477 0.003l0.024-0h-192z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"grid":0,"tags":["package"]},"attrs":[{}],"properties":{"order":41,"id":27,"name":"package","prevSize":32,"code":59687},"setIdx":0,"setId":0,"iconIdx":39},{"icon":{"paths":["M405.25 107.167c-25.032-0.622-50.381 8.256-69.667 27.542l-200.875 200.833c-0 0.006-0 0.014-0 0.021s0 0.015 0 0.022l-0-0.001c-44.068 44.1-33.887 119.949 20.25 150.875l215.458 123.167 80.917 202.25c4.85 11.888 16.321 20.114 29.713 20.114 8.833 0 16.83-3.578 22.621-9.364l136.875-136.833 222.167 222.167c5.833 6.068 14.019 9.838 23.085 9.838 17.675 0 32.003-14.328 32.003-32.003 0-9.066-3.77-17.252-9.828-23.075l-0.011-0.010-222.167-222.167 136.875-136.875c5.786-5.791 9.364-13.788 9.364-22.62 0-13.392-8.226-24.863-19.901-29.636l-0.214-0.077-202.292-80.917-123.125-215.458c0-0.006 0-0.014 0-0.021s-0-0.015-0-0.022l0 0.001c-15.475-27.061-42.194-43.121-70.542-46.917-3.543-0.474-7.132-0.745-10.708-0.833zM400.583 170.333c2.34-0.235 4.688-0.185 7 0.125 9.247 1.239 17.923 6.788 23.333 16.25l128.708 225.167c3.61 6.243 9.088 11.061 15.662 13.756l0.213 0.077 167.583 67-250.375 250.375-67-167.583c-2.764-6.803-7.585-12.296-13.68-15.835l-0.153-0.082-225.167-128.667c-18.895-10.794-22.081-34.662-6.708-50.083v-0.042l200.833-200.792c5.773-5.773 12.73-8.961 19.75-9.667z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"grid":0,"tags":["pin"]},"attrs":[{}],"properties":{"order":42,"id":26,"name":"pin","prevSize":32,"code":59688},"setIdx":0,"setId":0,"iconIdx":40},{"icon":{"paths":["M404.917 106.667c-25.845-0.491-50.704 9.394-69.333 28.042l-200.875 200.875c-21.291 21.291-31.219 50.613-27.208 80.458 4.011 29.824 21.325 55.483 47.458 70.417l215.458 123.167 80.917 202.25c4.011 9.984 12.711 17.304 23.25 19.458 2.155 0.448 4.304 0.667 6.458 0.667 8.384 0 16.566-3.316 22.625-9.375l136.833-136.875 222.208 222.208c5.833 6.068 14.019 9.838 23.085 9.838 17.675 0 32.003-14.328 32.003-32.003 0-9.066-3.77-17.252-9.828-23.075l-0.011-0.010-222.208-222.208 136.875-136.833c7.595-7.595 10.863-18.545 8.708-29.083s-9.453-19.261-19.458-23.25l-202.292-80.917-123.083-215.458c-14.933-26.133-40.613-43.448-70.458-47.458-3.717-0.499-7.433-0.763-11.125-0.833z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"grid":0,"tags":["pin_filled"]},"attrs":[{}],"properties":{"order":43,"id":25,"name":"pin_filled","prevSize":32,"code":59689},"setIdx":0,"setId":0,"iconIdx":41},{"icon":{"paths":["M258.188 160c-15.034 0-31.819 2.259-45.875 13.688s-19.727 27.275-23 42.125c-41.089 187.619-82.163 375.256-123.188 562.875v0.063c-4.306 19.872-2.316 41.579 10.188 58.875 12.503 17.295 34.379 26.375 55.688 26.375h636c16.463 0 34.337-5.76 46.313-17.562s17.043-26.126 20-39.625v-0.062c41.25-188.518 82.41-377.071 123.5-565.625 4.209-19.318 2.827-41.304-10.75-58.187s-34.754-22.938-54.375-22.938h-634.5zM258.188 224h634.5c2.020 0 2.114 0.138 3.063 0.25-0.091 0.984 0.017 1.167-0.438 3.25-41.086 188.534-82.316 377.12-123.562 565.625l0.062-0.062c-1.364 6.227-2.515 7.277-2.188 7-0.38-0.020-0.234-0.062-1.625-0.062h-636c-6.020 0-4.38-0.659-3.812 0.125 0.563 0.778-1.019-0.884 0.437-7.75v-0.062c41.019-187.591 82.105-375.157 123.188-562.75 0.711-3.227 1.167-4.17 1.563-5.25 1.060-0.129 1.82-0.312 4.812-0.312zM369.062 255.5c-0.452-0.015-0.983-0.024-1.516-0.024-26.512 0-48.005 21.492-48.005 48.005 0 12.954 5.131 24.71 13.472 33.346l-0.013-0.014 155 165.437-244.375 179.063c-12.707 8.765-20.93 23.243-20.93 39.641 0 26.512 21.492 48.005 48.005 48.005 11.248 0 21.592-3.868 29.775-10.347l-0.1 0.077 288-211c11.955-8.836 19.622-22.88 19.622-38.715 0-12.719-4.946-24.283-13.021-32.872l0.023 0.025-192-204.937c-8.466-9.288-20.466-15.229-33.857-15.685l-0.080-0.002zM496 672c-0.202-0.003-0.44-0.005-0.679-0.005-26.512 0-48.005 21.492-48.005 48.005s21.492 48.005 48.005 48.005c0.239 0 0.477-0.002 0.715-0.005l-0.036 0h128c0.202 0.003 0.44 0.005 0.679 0.005 26.512 0 48.005-21.492 48.005-48.005s-21.492-48.005-48.005-48.005c-0.239 0-0.477 0.002-0.715 0.005l0.036-0h-128z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"grid":0,"tags":["powershell"]},"attrs":[{}],"properties":{"order":44,"id":24,"name":"powershell","prevSize":32,"code":59690},"setIdx":0,"setId":0,"iconIdx":42},{"icon":{"paths":["M512 64c-79.543 0-122.874 20.204-153.75 33.583h-0.042c-27.783 12.115-44.507 37.217-51.75 60.917s-7.792 47.381-7.792 68.5v71.667h-71.667c-21.119 0-44.801 0.548-68.5 7.792s-48.801 23.966-60.917 51.75v0.042c-13.379 30.875-33.583 74.207-33.583 153.75s20.204 122.874 33.583 153.75v0.042c12.115 27.784 37.217 44.507 60.917 51.75 23.699 7.242 47.381 7.792 68.5 7.792h71.667v71.667c0 21.119 0.548 44.801 7.792 68.5s23.966 48.801 51.75 60.917h0.042c30.875 13.379 74.207 33.583 153.75 33.583s122.874-20.204 153.75-33.583h0.042c27.784-12.115 44.507-37.217 51.75-60.917 7.242-23.699 7.792-47.381 7.792-68.5v-71.667h71.667c21.119 0 44.801-0.548 68.5-7.792s48.801-23.966 60.917-51.75v-0.042c13.379-30.875 33.583-74.207 33.583-153.75s-20.204-122.874-33.583-153.75v-0.042c-12.115-27.783-37.217-44.507-60.917-51.75s-47.381-7.792-68.5-7.792h-71.667v-71.667c0-21.119-0.548-44.801-7.792-68.5s-23.966-48.801-51.75-60.917h-0.042c-30.875-13.379-74.207-33.583-153.75-33.583zM512 128c69.731 0 95.126 13.909 128.208 28.25 8.909 3.885 12.382 8.711 16.125 20.958s5 30.591 5 49.792v98.417c-0.269 1.559-0.423 3.356-0.423 5.187s0.154 3.628 0.45 5.376l-0.026-0.188v69.542c0 41.601-33.065 74.667-74.667 74.667h-149.333c-76.201 0-138.667 62.465-138.667 138.667v42.667h-71.667c-19.201 0-37.544-1.257-49.792-5s-17.074-7.216-20.958-16.125c-14.341-33.083-28.25-58.478-28.25-128.208s13.909-95.126 28.25-128.208c3.885-8.909 8.711-12.382 20.958-16.125s30.591-5 49.792-5h274.333c0.135 0.002 0.293 0.003 0.453 0.003 17.675 0 32.003-14.328 32.003-32.003s-14.328-32.003-32.003-32.003c-0.159 0-0.318 0.001-0.477 0.003l0.024-0h-138.667v-71.667c0-19.201 1.257-37.544 5-49.792s7.216-17.074 16.125-20.958c33.083-14.341 58.478-28.25 128.208-28.25zM437.333 192c-17.673 0-32 14.327-32 32s14.327 32 32 32v0c17.673 0 32-14.327 32-32s-14.327-32-32-32v0zM725.333 362.667h71.667c19.201 0 37.544 1.257 49.792 5s17.074 7.216 20.958 16.125c14.341 33.083 28.25 58.478 28.25 128.208s-13.909 95.126-28.25 128.208c-3.885 8.909-8.711 12.382-20.958 16.125s-30.591 5-49.792 5h-274.333c-0.135-0.002-0.293-0.003-0.453-0.003-17.675 0-32.003 14.328-32.003 32.003s14.328 32.003 32.003 32.003c0.159 0 0.318-0.001 0.477-0.003l-0.024 0h138.667v71.667c0 19.201-1.257 37.544-5 49.792s-7.216 17.074-16.125 20.958c-33.083 14.341-58.478 28.25-128.208 28.25s-95.126-13.909-128.208-28.25c-8.909-3.885-12.382-8.711-16.125-20.958s-5-30.591-5-49.792v-178.333c0-41.601 33.065-74.667 74.667-74.667h149.333c76.201 0 138.667-62.465 138.667-138.667v-42.667zM586.667 768c-17.673 0-32 14.327-32 32s14.327 32 32 32v0c17.673 0 32-14.327 32-32s-14.327-32-32-32v0z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"grid":0,"tags":["python"]},"attrs":[{}],"properties":{"order":45,"id":23,"name":"python","prevSize":32,"code":59691},"setIdx":0,"setId":0,"iconIdx":43},{"icon":{"paths":["M799.5 127.542c-17.459 0.281-31.503 14.5-31.503 31.999 0 0.161 0.001 0.323 0.004 0.483l-0-0.024v66.25c-67.928-60.977-157.668-98.25-256-98.25-211.703 0-384 172.297-384 384s172.297 384 384 384c211.703 0 384-172.297 384-384 0-20.279-2-39.649-4.833-58.167-2.059-15.868-15.488-27.999-31.752-27.999-17.675 0-32.003 14.328-32.003 32.003 0 2.001 0.184 3.96 0.535 5.859l-0.030-0.197c2.5 16.341 4.083 32.427 4.083 48.5 0 177.118-142.882 320-320 320s-320-142.882-320-320c0-177.118 142.882-320 320-320 83.931 0 159.583 32.587 216.542 85.333h-77.875c-0.135-0.002-0.293-0.003-0.453-0.003-17.675 0-32.003 14.328-32.003 32.003s14.328 32.003 32.003 32.003c0.159 0 0.318-0.001 0.477-0.003l-0.024 0h149.333c0.36-0.012 0.665-0.027 0.968-0.046l-0.093 0.005c0.847-0.015 1.658-0.060 2.46-0.135l-0.127 0.010c1.131-0.113 2.112-0.26 3.078-0.45l-0.203 0.033c1.044-0.204 1.871-0.405 2.684-0.639l-0.226 0.055c0.433-0.105 0.642-0.162 0.851-0.222l-0.226 0.055c0.324-0.084 0.421-0.112 0.518-0.141l-0.227 0.058c0.582-0.207 0.941-0.348 1.296-0.495l-0.212 0.078c0.869-0.287 1.504-0.527 2.129-0.786l-0.212 0.078c1.091-0.46 1.954-0.878 2.794-1.334l-0.169 0.084c0.266-0.125 0.348-0.167 0.43-0.209l-0.18 0.084c1.006-0.544 1.823-1.041 2.615-1.573l-0.115 0.073c0.198-0.128 0.28-0.183 0.361-0.238l-0.111 0.071c0.874-0.609 1.621-1.184 2.34-1.79l-0.048 0.040c0.135-0.11 0.216-0.179 0.297-0.247l-0.047 0.039c0.767-0.647 1.46-1.287 2.123-1.956l0.002-0.002c0.071-0.070 0.138-0.138 0.206-0.206l0.002-0.002c0.648-0.669 1.275-1.375 1.87-2.107l0.047-0.059c0.030-0.034 0.098-0.115 0.166-0.197l0.043-0.053c0.105-0.139 0.269-0.369 0.43-0.602l0.070-0.106c0.404-0.52 0.843-1.131 1.26-1.758l0.074-0.117c0.492-0.757 1.018-1.67 1.499-2.611l0.084-0.181c0.358-0.666 0.763-1.529 1.13-2.413l0.078-0.212c-0.038 0.108 0.004 0.012 0.045-0.084l0.080-0.208c0.276-0.677 0.589-1.592 0.86-2.524l0.056-0.226c-0.029 0.129-0 0.032 0.028-0.066l0.056-0.226c0.216-0.71 0.447-1.663 0.634-2.632l0.032-0.201c-0.007 0.078 0.008-0.022 0.022-0.121l0.020-0.17c-0.013 0.107 0.002 0.022 0.016-0.063l0.026-0.187c0.138-0.8 0.256-1.801 0.328-2.816l0.006-0.101c0.012-0.142 0.027-0.387 0.039-0.634l0.003-0.075c0.025-0.456 0.040-0.995 0.042-1.537l0-0.005v-149.333c0.002-0.136 0.003-0.298 0.003-0.459 0-17.675-14.328-32.003-32.003-32.003-0.176 0-0.351 0.001-0.526 0.004l0.026-0z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"grid":0,"tags":["reload"]},"attrs":[{}],"properties":{"order":46,"id":22,"name":"reload","prevSize":32,"code":59692},"setIdx":0,"setId":0,"iconIdx":44},{"icon":{"paths":["M202.667 128c-0.135-0.002-0.293-0.003-0.453-0.003-17.675 0-32.003 14.328-32.003 32.003s14.328 32.003 32.003 32.003c0.159 0 0.318-0.001 0.477-0.003l-0.024 0h10.667v42.667c0 126.504 80.479 232.212 192 275.583v3.5c-111.521 43.371-192 149.079-192 275.583v42.667h-10.667c-0.135-0.002-0.293-0.003-0.453-0.003-17.675 0-32.003 14.328-32.003 32.003s14.328 32.003 32.003 32.003c0.159 0 0.318-0.001 0.477-0.003l-0.024 0h618.667c0.135 0.002 0.293 0.003 0.453 0.003 17.675 0 32.003-14.328 32.003-32.003s-14.328-32.003-32.003-32.003c-0.159 0-0.318 0.001-0.477 0.003l0.024-0h-10.667v-42.667c0-126.504-80.479-232.212-192-275.583v-3.5c111.521-43.371 192-149.079 192-275.583v-42.667h10.667c0.135 0.002 0.293 0.003 0.453 0.003 17.675 0 32.003-14.328 32.003-32.003s-14.328-32.003-32.003-32.003c-0.159 0-0.318 0.001-0.477 0.003l0.024-0h-618.667zM277.333 192h469.333v42.667c0 107.060-71.446 196.746-168.958 225.167-13.419 4.005-23.035 16.233-23.042 30.708l-0 0.001v42.917c0.007 14.475 9.623 26.703 22.815 30.65l0.227 0.058c97.512 28.421 168.958 118.106 168.958 225.167v42.667h-77.875c-14.825-73.031-79.387-128-156.792-128s-141.967 54.969-156.792 128h-77.875v-42.667c0-107.060 71.446-196.746 168.958-225.167 13.419-4.005 23.035-16.233 23.042-30.708l0-0.001v-42.917c-0.007-14.475-9.623-26.703-22.815-30.65l-0.227-0.058c-97.512-28.421-168.958-118.106-168.958-225.167v-42.667zM426.667 341.333c0 47.125 38.208 85.333 85.333 85.333s85.333-38.208 85.333-85.333h-170.667z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"grid":0,"tags":["sandclock"]},"attrs":[{}],"properties":{"order":47,"id":20,"name":"sandclock","prevSize":32,"code":59693},"setIdx":0,"setId":0,"iconIdx":45},{"icon":{"paths":["M308.833 127.542c-1.681 0.042-3.29 0.207-4.86 0.487l0.193-0.029h-58.833c-64.683 0-117.333 52.629-117.333 117.333v533.333c0 64.704 52.651 117.333 117.333 117.333h236.25l18.292-64h-179.875v-245.333c0-5.888 4.8-10.667 10.667-10.667h362.667c5.867 0 10.667 4.779 10.667 10.667v6.958l50.083-50.083c-13.547-19.029-35.683-31.542-60.75-31.542h-362.667c-41.173 0-74.667 33.493-74.667 74.667v245.333h-10.667c-29.419 0-53.333-23.936-53.333-53.333v-533.333c0-29.397 23.915-53.333 53.333-53.333h32v117.333c0 40.852 33.814 74.667 74.667 74.667h256c40.852 0 74.667-33.814 74.667-74.667v-97.042l149.333 132.75v135.125c20.352-8.533 42.304-11.955 64-10.333v-139.167c0-9.131-3.923-17.837-10.75-23.917l-192-170.667c-5.845-5.205-13.421-8.083-21.25-8.083h-16.083c-1.559-0.269-3.356-0.423-5.187-0.423s-3.628 0.154-5.376 0.45l0.188-0.026h-330.958c-1.626-0.293-3.497-0.46-5.408-0.46-0.12 0-0.241 0.001-0.361 0.002l0.018-0zM341.333 192h277.333v117.333c0 6.294-4.372 10.667-10.667 10.667h-256c-6.294 0-10.667-4.372-10.667-10.667v-117.333zM885.625 512c-24.507 0.005-48.99 9.324-67.625 27.958l-256.375 256.333c-6.635 6.613-11.44 14.872-14 23.875l-34.375 120.333c-3.179 11.157-0.11 23.203 8.125 31.417 6.080 6.080 14.283 9.375 22.667 9.375 2.944 0 5.849-0.418 8.75-1.25l120.417-34.375c9.045-2.581 17.306-7.451 23.792-14l256.333-256.333c18.048-18.091 28-42.151 28-67.708s-9.972-49.597-28.042-67.667c-18.656-18.656-43.16-27.964-67.667-27.958z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"grid":0,"tags":["save_as"]},"attrs":[{}],"properties":{"order":48,"id":19,"name":"save_as","prevSize":32,"code":59694},"setIdx":0,"setId":0,"iconIdx":46},{"icon":{"paths":["M501.333 64c-114.382 0-202.667 80.616-202.667 181.333v40.667c-89.742 19.020-157.462 91.756-166.625 184.667-37.672 3.567-68.042 34.819-68.042 73.333 0 99.769 81.565 181.333 181.333 181.333h234.667v170.667h-192c-0.135-0.002-0.293-0.003-0.453-0.003-17.675 0-32.003 14.328-32.003 32.003s14.328 32.003 32.003 32.003c0.159 0 0.318-0.001 0.477-0.003l-0.024 0h448c0.135 0.002 0.293 0.003 0.453 0.003 17.675 0 32.003-14.328 32.003-32.003s-14.328-32.003-32.003-32.003c-0.159 0-0.318 0.001-0.477 0.003l0.024-0h-192v-170.667h234.667c99.769 0 181.333-81.565 181.333-181.333 0-38.514-30.37-69.767-68.042-73.333-9.373-104.657-86.473-186.492-187.958-206v-19.333c0-100.718-88.285-181.333-202.667-181.333zM501.333 128c85.895 0 138.667 53.102 138.667 117.333v14.125c-25.422 3.859-48.911 11.893-67.625 21.25-10.952 5.239-18.382 16.232-18.382 28.96 0 17.675 14.328 32.003 32.003 32.003 5.474 0 10.627-1.374 15.133-3.797l-0.171 0.084c19.775-9.888 42.978-17.958 60.375-17.958 87.063 0 155.51 65.354 166.375 149.333h-631.458c10.671-72.164 69.82-128 145.083-128 63.571 0 107.591 19.699 131.333 67.542 5.224 10.994 16.238 18.459 28.996 18.459 17.675 0 32.003-14.328 32.003-32.003 0-5.439-1.357-10.56-3.75-15.045l0.084 0.172c-32.28-65.048-96.776-95.535-167.333-100.875v-34.25c0-64.232 52.771-117.333 138.667-117.333zM138.667 533.333h746.667c6.294 0 10.667 4.372 10.667 10.667 0 65.181-52.153 117.333-117.333 117.333h-533.333c-65.181 0-117.333-52.153-117.333-117.333 0-6.294 4.372-10.667 10.667-10.667z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"grid":0,"tags":["scoop"]},"attrs":[{}],"properties":{"order":49,"id":18,"name":"scoop","prevSize":32,"code":59695},"setIdx":0,"setId":0,"iconIdx":47},{"icon":{"paths":["M437.333 128c-170.461 0-309.333 138.872-309.333 309.333s138.872 309.333 309.333 309.333c73.736 0 141.519-26.047 194.75-69.333l209.292 209.292c5.833 6.068 14.019 9.838 23.085 9.838 17.675 0 32.003-14.328 32.003-32.003 0-9.066-3.77-17.252-9.828-23.075l-0.011-0.010-209.292-209.292c43.286-53.231 69.333-121.014 69.333-194.75 0-170.461-138.872-309.333-309.333-309.333zM437.333 192c135.873 0 245.333 109.46 245.333 245.333 0 66.189-26.108 125.989-68.458 170.042-2.631 1.948-4.886 4.202-6.772 6.747l-0.061 0.086c-44.053 42.351-103.853 68.458-170.042 68.458-135.873 0-245.333-109.46-245.333-245.333s109.46-245.333 245.333-245.333z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"grid":0,"tags":["search"]},"attrs":[{}],"properties":{"order":50,"id":17,"name":"search","prevSize":32,"code":59696},"setIdx":0,"setId":0,"iconIdx":48},{"icon":{"paths":["M512 85.333c-33.64 0-66.077 4.254-97.042 11.458-13.144 3.145-23.019 14.089-24.528 27.563l-0.013 0.145-6.792 61.917c-2.221 20.29-13.942 38.242-31.625 48.458-17.648 10.196-39.069 11.326-57.75 3.125h-0.042l-56.875-25.042c-3.794-1.713-8.226-2.711-12.891-2.711-9.206 0-17.505 3.887-23.343 10.11l-0.016 0.017c-44.213 47.136-78.146 104.213-97.417 167.917-0.871 2.775-1.373 5.965-1.373 9.273 0 10.557 5.111 19.919 12.994 25.749l0.087 0.061 50.458 37c16.477 12.114 26.167 31.205 26.167 51.625 0 20.431-9.69 39.538-26.167 51.625l-50.458 36.958c-7.97 5.891-13.081 15.254-13.081 25.81 0 3.308 0.502 6.498 1.434 9.5l-0.061-0.227c19.268 63.697 53.174 120.816 97.417 167.958 5.853 6.223 14.14 10.098 23.332 10.098 4.675 0 9.117-1.003 13.12-2.804l-0.202 0.081 56.875-25.042c18.69-8.219 40.131-7.037 57.792 3.167 17.683 10.217 29.404 28.169 31.625 48.458l6.792 61.917c1.534 13.591 11.385 24.512 24.282 27.622l0.218 0.044c30.979 7.23 63.443 11.5 97.083 11.5s66.077-4.254 97.042-11.458c13.144-3.145 23.019-14.089 24.528-27.563l0.013-0.145 6.792-61.917c2.221-20.29 13.942-38.242 31.625-48.458 17.648-10.196 39.069-11.368 57.75-3.167l56.917 25.042c3.802 1.721 8.243 2.723 12.918 2.723 9.192 0 17.479-3.875 23.316-10.082l0.015-0.017c44.213-47.136 78.146-104.255 97.417-167.958 0.871-2.775 1.373-5.965 1.373-9.273 0-10.557-5.111-19.919-12.994-25.749l-0.087-0.062-50.458-36.958c-16.477-12.087-26.167-31.194-26.167-51.625s9.69-39.538 26.167-51.625l50.458-36.958c7.97-5.891 13.081-15.254 13.081-25.81 0-3.308-0.502-6.498-1.434-9.5l0.061 0.227c-19.271-63.704-53.203-120.822-97.417-167.958-5.853-6.223-14.14-10.098-23.332-10.098-4.675 0-9.117 1.003-13.12 2.804l0.202-0.081-56.917 25.042c-18.681 8.201-40.102 7.030-57.75-3.167-17.683-10.217-29.404-28.169-31.625-48.458l-6.792-61.917c-1.534-13.591-11.385-24.512-24.282-27.622l-0.218-0.044c-30.979-7.23-63.443-11.5-97.083-11.5zM512 149.333c20.785 0 40.745 3.731 60.75 7.25l4 36.792c4.435 40.51 27.984 76.541 63.25 96.917 35.289 20.389 78.253 22.733 115.542 6.333l33.833-14.875c25.98 31.197 46.55 66.435 60.917 105.042l-30 22c-32.846 24.094-52.292 62.455-52.292 103.208s19.446 79.114 52.292 103.208l30 22c-14.367 38.606-34.936 73.844-60.917 105.042l-33.833-14.875c-37.289-16.399-80.253-14.055-115.542 6.333-35.266 20.375-58.815 56.406-63.25 96.917l-4 36.792c-20.003 3.509-39.975 7.25-60.75 7.25-20.785 0-40.745-3.731-60.75-7.25l-4-36.792c-4.435-40.51-27.984-76.541-63.25-96.917-35.289-20.389-78.253-22.733-115.542-6.333l-33.833 14.875c-25.985-31.193-46.552-66.432-60.917-105.042l30-22c32.846-24.094 52.292-62.455 52.292-103.208s-19.462-79.139-52.292-103.25l-30-22c14.373-38.621 34.963-73.836 60.958-105.042l33.792 14.875c37.289 16.399 80.253 14.097 115.542-6.292 35.266-20.375 58.815-56.406 63.25-96.917l4-36.792c20.003-3.509 39.975-7.25 60.75-7.25zM512 341.333c-93.878 0-170.667 76.789-170.667 170.667s76.789 170.667 170.667 170.667c93.878 0 170.667-76.789 170.667-170.667s-76.789-170.667-170.667-170.667zM512 405.333c59.289 0 106.667 47.377 106.667 106.667s-47.377 106.667-106.667 106.667c-59.289 0-106.667-47.377-106.667-106.667s47.377-106.667 106.667-106.667z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"grid":0,"tags":["settings"]},"attrs":[{}],"properties":{"order":51,"id":16,"name":"settings","prevSize":32,"code":59697},"setIdx":0,"setId":0,"iconIdx":49},{"icon":{"paths":["M768 106.667c-82.096 0-149.333 67.238-149.333 149.333 0 12.496 4.236 23.669 7.167 35.292l-255.792 127.958c-27.447-33.673-67.503-56.583-114.042-56.583-82.096 0-149.333 67.238-149.333 149.333s67.238 149.333 149.333 149.333c46.539 0 86.595-22.911 114.042-56.583l255.792 127.958c-2.931 11.623-7.167 22.795-7.167 35.292 0 82.095 67.238 149.333 149.333 149.333s149.333-67.238 149.333-149.333c0-82.095-67.238-149.333-149.333-149.333-46.539 0-86.595 22.911-114.042 56.583l-255.792-127.958c2.931-11.623 7.167-22.795 7.167-35.292s-4.236-23.669-7.167-35.292l255.792-127.958c27.447 33.673 67.503 56.583 114.042 56.583 82.096 0 149.333-67.238 149.333-149.333s-67.238-149.333-149.333-149.333zM768 170.667c47.507 0 85.333 37.826 85.333 85.333s-37.826 85.333-85.333 85.333c-47.507 0-85.333-37.826-85.333-85.333s37.826-85.333 85.333-85.333zM256 426.667c47.507 0 85.333 37.826 85.333 85.333s-37.826 85.333-85.333 85.333c-47.507 0-85.333-37.826-85.333-85.333s37.826-85.333 85.333-85.333zM768 682.667c47.507 0 85.333 37.826 85.333 85.333s-37.826 85.333-85.333 85.333c-47.507 0-85.333-37.826-85.333-85.333s37.826-85.333 85.333-85.333z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"grid":0,"tags":["share"]},"attrs":[{}],"properties":{"order":52,"id":15,"name":"share","prevSize":32,"code":59698},"setIdx":0,"setId":0,"iconIdx":50},{"icon":{"paths":["M564.25 152.5c-37.657 1.723-73.583 31.577-73.583 73.667v181.042l-282.542-238.125c-11.704-9.86-25.253-15.054-38.958-16.333-41.116-3.838-83.833 27.501-83.833 73.417v571.667c0 61.221 75.975 96.523 122.792 57.083l282.542-238.125v181.042c0 61.221 75.975 96.523 122.792 57.083l339.125-285.833c34.912-29.425 34.93-84.766 0.042-114.208-0.006-0-0.014-0-0.021-0s-0.015 0-0.022 0l0.001-0-339.125-285.792c-14.63-12.325-32.092-17.366-49.208-16.583zM160.458 214.583c2.055 0.463 4.244 1.586 6.417 3.417l323.792 272.917v42.167l-323.792 272.875c-8.693 7.323-17.542 3.23-17.542-8.125v-571.667c0-5.678 2.199-9.551 5.5-11.083 1.65-0.766 3.57-0.963 5.625-0.5zM565.792 214.583c2.055 0.463 4.244 1.586 6.417 3.417l339.125 285.792c5.559 4.691 5.536 11.668 0 16.333l-339.125 285.833c-8.693 7.323-17.542 3.23-17.542-8.125v-571.667c0-5.678 2.199-9.551 5.5-11.083 1.65-0.766 3.57-0.963 5.625-0.5z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"grid":0,"tags":["skip"]},"attrs":[{}],"properties":{"order":53,"id":14,"name":"skip","prevSize":32,"code":59699},"setIdx":0,"setId":0,"iconIdx":51},{"icon":{"paths":["M512 85.333c-235.263 0-426.667 191.404-426.667 426.667s191.404 426.667 426.667 426.667c235.263 0 426.667-191.404 426.667-426.667s-191.404-426.667-426.667-426.667zM512 149.333c200.674 0 362.667 161.992 362.667 362.667s-161.992 362.667-362.667 362.667c-176.242 0-322.588-124.969-355.625-291.333l122.208 52.417c-0.575 4.966-1.25 9.931-1.25 14.917 0 28.741 9.465 57.768 29.375 80.167s50.625 37.167 87.958 37.167c37.333 0 68.049-14.768 87.958-37.167s29.375-51.426 29.375-80.167c0-5.556-0.661-11.098-1.375-16.625l102.333-79.667c1.908 0.073 3.782 0.292 5.708 0.292 82.325 0 149.333-67.008 149.333-149.333s-67.008-149.333-149.333-149.333c-82.325 0-149.333 67.008-149.333 149.333 0 4.4 0.292 8.737 0.667 13.042l-69.208 115.25c-2.049-0.091-4.034-0.292-6.125-0.292-37.333 0-68.049 14.768-87.958 37.167-1.629 1.832-3.052 3.791-4.542 5.708l-152.75-65.458c0.68-200.089 162.332-361.417 362.583-361.417zM618.667 320c47.061 0 85.333 38.272 85.333 85.333s-38.272 85.333-85.333 85.333c-47.061 0-85.333-38.272-85.333-85.333s38.272-85.333 85.333-85.333zM618.667 362.667c-23.564 0-42.667 19.103-42.667 42.667s19.103 42.667 42.667 42.667v0c23.564 0 42.667-19.103 42.667-42.667s-19.103-42.667-42.667-42.667v0zM394.667 576c26.667 0 43.951 9.232 56.042 22.833s18.625 32.574 18.625 51.833c0 19.259-6.535 38.232-18.625 51.833s-29.375 22.833-56.042 22.833c-26.667 0-43.951-9.232-56.042-22.833-11.473-12.907-17.745-30.68-18.375-48.917l61.792 26.5c3.724 1.642 8.067 2.598 12.632 2.598 17.679 0 32.011-14.332 32.011-32.011 0-13.119-7.892-24.395-19.188-29.339l-0.206-0.080-63.458-27.208c11.759-10.8 27.6-18.042 50.833-18.042z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"grid":0,"tags":["steam"]},"attrs":[{}],"properties":{"order":54,"id":13,"name":"steam","prevSize":32,"code":59700},"setIdx":0,"setId":0,"iconIdx":52},{"icon":{"paths":["M842.667 149.333c64.422 0 117.333 52.911 117.333 117.333v490.667c0 64.422-52.911 117.333-117.333 117.333h-661.333c-64.422 0-117.333-52.911-117.333-117.333v-490.667c0-64.422 52.911-117.333 117.333-117.333h661.333zM842.667 213.333h-661.333c-29.829 0-53.333 23.505-53.333 53.333v490.667c0 29.829 23.505 53.333 53.333 53.333h245.333v-181.333c0-64.41 52.923-117.333 117.333-117.333h352v-245.333c0-29.829-23.505-53.333-53.333-53.333zM224.625 277.042c8.646 0.26 16.392 3.91 21.993 9.66l0.007 0.007 116.042 116.042v-29.417c-0.002-0.137-0.003-0.298-0.003-0.459 0-17.675 14.328-32.003 32.003-32.003 0.176 0 0.351 0.001 0.527 0.004l-0.026-0c17.459 0.281 31.503 14.5 31.503 31.999 0 0.161-0.001 0.323-0.004 0.483l0-0.024v101.917c0.266 1.551 0.419 3.338 0.419 5.16 0 17.675-14.328 32.003-32.003 32.003-1.809 0-3.584-0.15-5.311-0.439l0.187 0.026h-101.958c-0.135 0.002-0.293 0.003-0.453 0.003-17.675 0-32.003-14.328-32.003-32.003s14.328-32.003 32.003-32.003c0.159 0 0.318 0.001 0.477 0.003l-0.024-0h29.417l-116.042-116.042c-5.971-5.82-9.675-13.941-9.675-22.927 0-17.675 14.328-32.003 32.003-32.003 0.324 0 0.647 0.005 0.969 0.014l-0.047-0.001zM896 576h-352c-29.712 0-53.333 23.621-53.333 53.333v181.333h352c29.829 0 53.333-23.505 53.333-53.333v-181.333z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"grid":0,"tags":["sys_tray"]},"attrs":[{}],"properties":{"order":55,"id":12,"name":"sys_tray","prevSize":32,"code":59701},"setIdx":0,"setId":0,"iconIdx":53},{"icon":{"paths":["M512 43c-55.73 0-102.016 38.966-156.5 74.917s-113.488 71.988-166.917 81.5c-36.997 6.573-60.583 40.133-60.583 75.625v98.125c0 151.544 55.917 300.537 129.875 413.458 36.979 56.461 78.503 103.938 121.333 138.292s87.293 56.75 132.792 56.75c45.498 0 89.962-22.397 132.792-56.75s84.355-81.831 121.333-138.292c73.958-112.921 129.875-261.915 129.875-413.458v-98.125c0-35.492-23.586-69.052-60.583-75.625-53.429-9.512-112.432-45.55-166.917-81.5s-100.77-74.917-156.5-74.917zM480 119.875v165.625c-5.633-5.063-13.121-8.161-21.332-8.167l-0.001-0c-17.673 0-32 14.327-32 32s14.327 32 32 32v0c8.218-0.018 15.705-3.13 21.362-8.233l-0.028 0.025v123.042c-5.633-5.063-13.121-8.161-21.332-8.167l-0.001-0c-17.672 0.002-31.997 14.328-31.997 32 0 3.824 0.671 7.49 1.901 10.889l-0.070-0.223h-110.375c1.16-3.176 1.83-6.843 1.83-10.667 0-17.657-14.301-31.974-31.953-32l-0.002-0c-17.672 0.002-31.997 14.328-31.997 32 0 3.824 0.671 7.49 1.901 10.889l-0.070-0.223h-52.708c-4.316-21.543-7.765-43.208-10.083-64.917 2.283 0.582 4.905 0.917 7.604 0.917 0.007 0 0.014-0 0.022-0l-0.001 0c17.673 0 32-14.327 32-32s-14.327-32-32-32v0c-3.829 0.016-7.494 0.702-10.889 1.946l0.222-0.071v-89.5c0-7.26 4.682-12.073 7.792-12.625 51.241-9.123 98.528-33.195 141.542-59.458 0.165 17.547 14.428 31.708 31.999 31.708 0 0 0.001-0 0.001-0l-0 0c17.657-0.022 31.962-14.34 31.962-32 0-12.694-7.391-23.661-18.104-28.833l-0.191-0.083c1.21-0.798 2.548-1.624 3.75-2.417 29.85-19.696 54.325-33.475 75.625-44.292 5.221-1.33 9.749-3.789 13.491-7.112l-0.033 0.029c0.049-0.023 0.118-0.060 0.167-0.083zM544 119.875c23.598 11.129 53.27 27.718 89.25 51.458 55.217 36.434 119.289 78.324 190.958 91.083 3.11 0.552 7.792 5.365 7.792 12.625v98.125c0 39.258-5.327 78.578-13.125 117.5h-274.875v-370.792zM288 277.333c-17.673 0-32 14.327-32 32s14.327 32 32 32v0c17.673 0 32-14.327 32-32s-14.327-32-32-32v0zM373.333 362.667c-17.673 0-32 14.327-32 32s14.327 32 32 32v0c17.673 0 32-14.327 32-32s-14.327-32-32-32v0zM221.292 554.667h258.708v354.875c-18.437-6.654-38.643-16.81-60.75-34.542-36.004-28.878-73.924-71.684-107.833-123.458-37.269-56.904-68.52-124.939-90.125-196.875zM574.167 554.667h110.375c-1.16 3.176-1.83 6.843-1.83 10.667 0 17.657 14.301 31.974 31.953 32l0.002 0c17.672-0.002 31.997-14.328 31.997-32 0-3.824-0.671-7.49-1.901-10.889l0.070 0.223h57.875c-16.853 56.114-39.713 109.648-66.583 157.583-5.651-5.118-13.183-8.25-21.446-8.25-0.004 0-0.009 0-0.013 0l0.001-0c-17.631 0.055-31.902 14.361-31.902 32 0 13.311 8.128 24.724 19.691 29.547l0.212 0.078c-13.435 19.415-27.248 37.719-41.375 54-0.933-16.923-14.882-30.292-31.954-30.292-0.001 0-0.003 0-0.004 0l0-0c-0.031-0-0.068-0-0.104-0-17.673 0-32 14.327-32 32 0 17.637 14.268 31.941 31.89 32l0.006 0c-8.179 7.798-16.322 15.207-24.375 21.667-15.046 12.069-29.131 20.458-42.458 26.792-5.098-3.61-11.44-5.776-18.288-5.792l-0.004-0v-128c17.673 0 32-14.327 32-32s-14.327-32-32-32v0-106.667c17.672-0.002 31.997-14.328 31.997-32 0-3.824-0.671-7.49-1.901-10.889l0.070 0.223zM629.333 618.667c-17.673 0-32 14.327-32 32s14.327 32 32 32v0c17.673 0 32-14.327 32-32s-14.327-32-32-32v0z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"grid":0,"tags":["uac"]},"attrs":[{}],"properties":{"order":56,"id":11,"name":"uac","prevSize":32,"code":59702},"setIdx":0,"setId":0,"iconIdx":54},{"icon":{"paths":["M512 85.333c-74.844 0-137.165 55.924-147.625 128h-145.958c-1.623-0.292-3.491-0.458-5.398-0.458-0.036 0-0.072 0-0.108 0l0.006-0c-1.706 0.038-3.345 0.203-4.943 0.487l0.193-0.028h-69.5c-0.135-0.002-0.293-0.003-0.453-0.003-17.675 0-32.003 14.328-32.003 32.003s14.328 32.003 32.003 32.003c0.159 0 0.318-0.001 0.477-0.003l-0.024 0h45.625l53.708 555.292c5.783 59.875 56.651 106.042 116.792 106.042h314.375c60.143 0 111.011-46.162 116.792-106.042l53.75-555.292h45.625c0.135 0.002 0.293 0.003 0.453 0.003 17.675 0 32.003-14.328 32.003-32.003s-14.328-32.003-32.003-32.003c-0.159 0-0.318 0.001-0.477 0.003l0.024-0h-69.458c-1.541-0.263-3.315-0.413-5.125-0.413s-3.584 0.15-5.312 0.439l0.187-0.026h-146c-10.46-72.076-72.781-128-147.625-128zM512 149.333c40.089 0 72.976 27.054 82.375 64h-164.75c9.399-36.946 42.286-64 82.375-64zM248.542 277.333h526.875l-53.167 549.125c-2.667 27.629-25.333 48.208-53.083 48.208h-314.375c-27.71 0-50.418-20.616-53.083-48.208l-53.167-549.125zM511.542 384c-8.669 0.131-16.483 3.688-22.167 9.375l-106.667 106.667c-6.068 5.833-9.838 14.019-9.838 23.085 0 17.675 14.328 32.003 32.003 32.003 9.066 0 17.252-3.77 23.075-9.828l0.010-0.011 52.042-52.042v242.75c-0.002 0.135-0.003 0.293-0.003 0.453 0 17.675 14.328 32.003 32.003 32.003s32.003-14.328 32.003-32.003c0-0.159-0.001-0.318-0.003-0.477l0 0.024v-242.75l52.042 52.042c5.833 6.068 14.019 9.838 23.085 9.838 17.675 0 32.003-14.328 32.003-32.003 0-9.066-3.77-17.252-9.828-23.075l-0.011-0.010-106.667-106.667c-5.792-5.794-13.795-9.378-22.634-9.378-0.158 0-0.315 0.001-0.473 0.003l0.024-0z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"grid":0,"tags":["undelete"]},"attrs":[{}],"properties":{"order":57,"id":10,"name":"undelete","prevSize":32,"code":59703},"setIdx":0,"setId":0,"iconIdx":55},{"icon":{"paths":["M512 128c-129.494 0-244.196 64.495-313.667 162.875-3.666 5.137-5.861 11.543-5.861 18.462 0 17.676 14.329 32.005 32.005 32.005 10.76 0 20.28-5.31 26.082-13.452l0.066-0.098c57.975-82.1 153.088-135.792 261.375-135.792 172.406 0 311.966 135.484 319.292 306.042l-51.333-51.333c-5.822-5.991-13.956-9.708-22.958-9.708l-0-0c-17.672 0.004-31.995 14.331-31.995 32.003 0 9 3.715 17.133 9.696 22.948l0.007 0.007 96 96c5.791 5.789 13.79 9.369 22.625 9.369s16.834-3.58 22.625-9.369l7.417-7.417c2.346-1.79 4.376-3.82 6.11-6.089l0.057-0.077 82.417-82.417c6.068-5.833 9.838-14.019 9.838-23.085 0-17.675-14.328-32.003-32.003-32.003-9.066 0-17.252 3.77-23.075 9.828l-0.010 0.011-32.375 32.375c-16.785-196.33-181.738-351.083-382.333-351.083zM170.208 426.667c-8.669 0.131-16.483 3.688-22.167 9.375l-7.292 7.292c-2.417 1.83-4.503 3.917-6.275 6.254l-0.058 0.080-82.375 82.375c-6.068 5.833-9.838 14.019-9.838 23.085 0 17.675 14.328 32.003 32.003 32.003 9.066 0 17.252-3.77 23.075-9.828l0.010-0.011 32.375-32.375c16.785 196.33 181.738 351.083 382.333 351.083 129.494 0 244.196-64.495 313.667-162.875 3.666-5.137 5.861-11.543 5.861-18.462 0-17.676-14.329-32.005-32.005-32.005-10.76 0-20.28 5.31-26.082 13.452l-0.066 0.098c-57.975 82.1-153.088 135.792-261.375 135.792-172.406 0-311.966-135.484-319.292-306.042l51.333 51.333c5.833 6.068 14.019 9.838 23.085 9.838 17.675 0 32.003-14.328 32.003-32.003 0-9.066-3.77-17.252-9.828-23.075l-0.011-0.010-96-96c-5.792-5.794-13.795-9.378-22.634-9.378-0.158 0-0.315 0.001-0.473 0.003l0.024-0z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"grid":0,"tags":["update"]},"attrs":[{}],"properties":{"order":58,"id":9,"name":"update","prevSize":32,"code":59704},"setIdx":0,"setId":0,"iconIdx":56},{"icon":{"paths":["M512 85.333c-235.263 0-426.667 191.404-426.667 426.667s191.404 426.667 426.667 426.667c235.263 0 426.667-191.404 426.667-426.667s-191.404-426.667-426.667-426.667zM512 149.333c200.674 0 362.667 161.992 362.667 362.667s-161.992 362.667-362.667 362.667c-200.674 0-362.667-161.992-362.667-362.667s161.992-362.667 362.667-362.667zM511.542 320c-8.669 0.131-16.483 3.688-22.167 9.375l-128 128c-6.068 5.833-9.838 14.019-9.838 23.085 0 17.675 14.328 32.003 32.003 32.003 9.066 0 17.252-3.77 23.075-9.828l0.010-0.011 73.375-73.375v242.75c-0.002 0.135-0.003 0.293-0.003 0.453 0 17.675 14.328 32.003 32.003 32.003s32.003-14.328 32.003-32.003c0-0.159-0.001-0.318-0.003-0.477l0 0.024v-242.75l73.375 73.375c5.833 6.068 14.019 9.838 23.085 9.838 17.675 0 32.003-14.328 32.003-32.003 0-9.066-3.77-17.252-9.828-23.075l-0.011-0.010-128-128c-5.792-5.794-13.795-9.378-22.634-9.378-0.158 0-0.315 0.001-0.473 0.003l0.024-0z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"grid":0,"tags":["upgradable"]},"attrs":[{}],"properties":{"order":59,"id":8,"name":"upgradable","prevSize":32,"code":59705},"setIdx":0,"setId":0,"iconIdx":57},{"icon":{"paths":["M512 938.667c235.264 0 426.667-191.403 426.667-426.667s-191.403-426.667-426.667-426.667-426.667 191.403-426.667 426.667 191.403 426.667 426.667 426.667zM361.365 457.365l128-128c12.501-12.501 32.747-12.501 45.248 0l128 128c12.501 12.501 12.501 32.747 0 45.248-6.229 6.272-14.421 9.387-22.613 9.387s-16.384-3.115-22.635-9.365l-73.365-73.387v242.752c0 17.664-14.336 32-32 32s-32-14.336-32-32v-242.752l-73.365 73.365c-12.501 12.501-32.747 12.501-45.248 0s-12.501-32.747-0.021-45.248z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"grid":0,"tags":["upgradable_filled"]},"attrs":[{}],"properties":{"order":60,"id":7,"name":"upgradable_filled","prevSize":32,"code":59706},"setIdx":0,"setId":0,"iconIdx":58},{"icon":{"paths":["M532.224 85.611c-165.632-4.395-254.464 45.44-319.424 94.123-58.432 43.84-105.323 114.368-118.997 136.128-2.24 3.563-1.045 8.235 2.581 10.389l32.213 19.115c-23.125 40.96-43.264 96.747-43.264 166.635 0 32.64 4.032 64.299 11.008 94.869 0.32 1.664 0.405 3.371 0.747 5.013l0.512-0.107c42.709 177.28 196.075 311.509 382.805 325.291 10.304 1.024 20.629 1.6 30.933 1.6v-0.043c0.235 0 0.448 0.043 0.661 0.043 288.448 0 510.976-287.744 395.605-591.275-53.525-140.8-224.789-257.792-375.381-261.781zM490.496 725.333c-95.104-0.149-166.229-104.491-105.003-204.779 14.955-24.491 40.384-41.195 68.459-47.104 55.829-11.733 96.469 1.387 125.504 41.344 10.837 14.912 30.485 60.608 7.061 108.629-4.928 10.069-2.197 22.208 6.955 28.693l17.664 12.501c-27.477 40.469-74.901 59.392-116.651 60.48-1.365 0.064-2.645 0.235-3.989 0.235zM661.184 485.717c-48.491-73.344-126.485-122.155-212.757-122.155-141.397 0-256.427 114.645-256.427 255.552 0 9.685 0.704 19.008 1.451 28.309l-15.637 5.44c-7.979-18.88-14.101-38.699-18.816-59.051-13.547-71.936 5.227-150.037 49.899-205.056 47.851-58.944 122.688-90.091 216.405-90.091 128.405 0 223.595 88.171 249.835 182.187l-13.952 4.864zM512 874.667c-8.747 0-17.301-0.704-25.899-1.323-115.776-11.264-230.101-99.499-230.101-254.229 0-82.005 52.139-151.936 125.056-179.2-49.728 34.731-82.389 92.288-82.389 157.419 0 105.771 85.973 191.808 191.68 191.979v0.021c0.064 0 0.107 0 0.171 0s0.107 0 0.171 0c6.208 0 12.544-0.405 18.923-0.981 132.331-9.941 237.056-120.981 237.056-256.341 0-140.629-131.989-297.344-321.365-297.344-107.477 0-179.52 34.645-226.645 73.856l-12.8-11.733c18.069-22.613 40.747-47.424 65.323-65.856 58.347-43.755 131.797-84.117 273.92-81.472 141.76 2.645 270.997 87.872 322.197 220.096 100.267 258.944-89.301 505.109-335.296 505.109z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"grid":0,"tags":["uplay"]},"attrs":[{}],"properties":{"order":61,"id":6,"name":"uplay","prevSize":32,"code":59707},"setIdx":0,"setId":0,"iconIdx":59},{"icon":{"paths":["M288 106.667c-43.556 0-80.274 17.486-103.917 44.083s-34.75 60.806-34.75 94.583c0 33.778 11.108 67.986 34.75 94.583 17.276 19.436 43.11 31.149 71.917 37.583v269c-28.806 6.435-54.64 18.148-71.917 37.583-23.642 26.598-34.75 60.806-34.75 94.583s11.108 67.986 34.75 94.583c23.643 26.598 60.361 44.083 103.917 44.083 76.204 0 138.667-62.462 138.667-138.667 0-64.881-46.179-117.278-106.667-132.167v-102.958c26.809 20.26 60.011 32.458 96 32.458h184.875c4.91 22.693 15.068 44.425 31.208 62.583 23.642 26.598 60.361 44.083 103.917 44.083 76.204 0 138.667-62.462 138.667-138.667s-62.462-138.667-138.667-138.667c-43.556 0-80.274 17.486-103.917 44.083-16.14 18.158-26.298 39.89-31.208 62.583h-184.875c-53.408 0-96-42.592-96-96v-38.5c60.488-14.889 106.667-67.286 106.667-132.167 0-76.204-62.462-138.667-138.667-138.667zM288 170.667c41.616 0 74.667 33.050 74.667 74.667 0 40.963-32.141 73.276-72.833 74.292-0.567-0.036-1.229-0.056-1.896-0.056s-1.329 0.020-1.986 0.061l0.090-0.004c-26.15-0.512-42.556-9.194-54.125-22.208-11.913-13.402-18.583-32.528-18.583-52.083s6.67-38.681 18.583-52.083c11.913-13.402 28.528-22.583 56.083-22.583zM736 469.333c41.616 0 74.667 33.050 74.667 74.667s-33.050 74.667-74.667 74.667c-27.556 0-44.17-9.181-56.083-22.583-11.254-12.661-17.641-30.461-18.333-48.875 0.119-1.036 0.187-2.237 0.187-3.454 0-1.073-0.053-2.133-0.156-3.178l0.011 0.132c0.71-18.383 7.055-36.15 18.292-48.792 11.913-13.402 28.528-22.583 56.083-22.583zM286.042 704.375c0.567 0.036 1.229 0.056 1.896 0.056s1.329-0.020 1.986-0.061l-0.090 0.004c40.692 1.016 72.833 33.329 72.833 74.292 0 41.616-33.050 74.667-74.667 74.667-27.556 0-44.17-9.181-56.083-22.583s-18.583-32.528-18.583-52.083c0-19.556 6.67-38.681 18.583-52.083 11.569-13.015 27.975-21.696 54.125-22.208z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"grid":0,"tags":["version"]},"attrs":[{}],"properties":{"order":62,"id":4,"name":"version","prevSize":32,"code":59708},"setIdx":0,"setId":0,"iconIdx":60},{"icon":{"paths":["M508.333 64.208c-30.667 0.248-61.225 12.099-84.25 35.5l-325.75 331.125c-46.049 46.802-45.428 123.034 1.375 169.083l331.125 325.75c46.802 46.049 123.034 45.428 169.083-1.375l325.75-331.083c0.014-0.014 0.028-0.028 0.041-0.041l0-0c46.012-46.823 45.386-123.034-1.417-169.083l-331.125-325.75c-23.401-23.024-54.166-34.373-84.833-34.125zM508.875 127.792c14.154-0.115 28.343 5.271 39.417 16.167l331.125 325.75c22.147 21.79 22.41 56.456 0.625 78.625l-325.75 331.083c-21.79 22.147-56.436 22.416-78.583 0.625l-331.125-325.75c-22.147-21.79-22.416-56.436-0.625-78.583l325.75-331.125c10.895-11.073 25.012-16.677 39.167-16.792zM511.5 276.875c-17.458 0.282-31.503 14.5-31.503 31.999 0 0.147 0.001 0.293 0.003 0.44l-0-0.022v256c-0.002 0.135-0.003 0.293-0.003 0.453 0 17.675 14.328 32.003 32.003 32.003s32.003-14.328 32.003-32.003c0-0.159-0.001-0.318-0.003-0.477l0 0.024v-256c0.002-0.124 0.003-0.271 0.003-0.417 0-17.675-14.328-32.003-32.003-32.003-0.176 0-0.351 0.001-0.526 0.004l0.026-0zM512 661.292c-23.564 0-42.667 19.103-42.667 42.667s19.103 42.667 42.667 42.667v0c23.564 0 42.667-19.103 42.667-42.667s-19.103-42.667-42.667-42.667v0z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"grid":0,"tags":["warning"]},"attrs":[{}],"properties":{"order":63,"id":3,"name":"warning","prevSize":32,"code":59709},"setIdx":0,"setId":0,"iconIdx":61},{"icon":{"paths":["M924.288 424.085l-331.115-325.76c-22.763-22.4-52.779-34.453-84.821-34.325-31.936 0.256-61.867 12.949-84.267 35.712l-325.76 331.115c-22.379 22.763-34.581 52.885-34.325 84.821s12.949 61.867 35.712 84.267l331.115 325.76c22.528 22.165 52.267 34.325 83.84 34.325 0.341 0 0.661 0 1.003 0 31.936-0.256 61.867-12.949 84.267-35.712l325.76-331.115c22.4-22.763 34.603-52.885 34.325-84.843s-12.971-61.845-35.733-84.245zM480 309.312c0-17.685 14.315-32 32-32s32 14.315 32 32v256c0 17.685-14.315 32-32 32s-32-14.315-32-32v-256zM512 746.645c-23.573 0-42.667-19.093-42.667-42.667s19.093-42.667 42.667-42.667 42.667 19.093 42.667 42.667c0 23.552-19.093 42.667-42.667 42.667z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"grid":0,"tags":["warning_filled"]},"attrs":[{}],"properties":{"order":64,"id":2,"name":"warning_filled","prevSize":32,"code":59710},"setIdx":0,"setId":0,"iconIdx":62},{"icon":{"paths":["M512 85.333c-235.263 0-426.667 191.404-426.667 426.667s191.404 426.667 426.667 426.667c235.263 0 426.667-191.404 426.667-426.667s-191.404-426.667-426.667-426.667zM512 149.333c200.674 0 362.667 161.992 362.667 362.667s-161.992 362.667-362.667 362.667c-200.674 0-362.667-161.992-362.667-362.667s161.992-362.667 362.667-362.667zM511.5 298.208c-17.459 0.281-31.503 14.5-31.503 31.999 0 0.161 0.001 0.323 0.004 0.483l-0-0.024v213.333c-0.002 0.135-0.003 0.293-0.003 0.453 0 17.675 14.328 32.003 32.003 32.003s32.003-14.328 32.003-32.003c0-0.159-0.001-0.318-0.003-0.477l0 0.024v-213.333c0.002-0.137 0.003-0.298 0.003-0.459 0-17.675-14.328-32.003-32.003-32.003-0.176 0-0.351 0.001-0.527 0.004l0.026-0zM512 640c-23.564 0-42.667 19.103-42.667 42.667s19.103 42.667 42.667 42.667v0c23.564 0 42.667-19.103 42.667-42.667s-19.103-42.667-42.667-42.667v0z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"grid":0,"tags":["warning_round"]},"attrs":[{}],"properties":{"order":65,"id":1,"name":"warning_round","prevSize":32,"code":59711},"setIdx":0,"setId":0,"iconIdx":63},{"icon":{"paths":["M866.133 264.533h-725.333c0-38.4 34.133-72.533 72.533-72.533h584.533c38.4 0 68.267 34.133 68.267 72.533z","M921.6 362.667c-4.267-38.4-34.133-64-72.533-64h-686.933c-38.4 0-68.267 25.6-72.533 64 0 4.267 0 4.267 0 8.533v477.867c0 38.4 29.867 68.267 72.533 68.267h691.2c38.4 0 68.267-29.867 72.533-68.267v-477.867c-4.267-4.267-4.267-8.533-4.267-8.533zM849.067 844.8h-686.933v-473.6h686.933v473.6z","M819.2 162.133h-627.2c0-38.4 34.133-72.533 72.533-72.533h477.867c42.667 0 76.8 34.133 76.8 72.533z","M89.6 362.667c0 4.267 0 4.267 0 8.533v-8.533z","M921.6 362.667v8.533c0-4.267 0-8.533 0-8.533v0z","M657.067 644.267l-123.733 128c-4.267 4.267-8.533 4.267-12.8 8.533 0 0-4.267 0-4.267 0-4.267 0-4.267 0-8.533 0h-8.533c0 0-4.267 0-4.267 0l-12.8-8.533-123.733-128c-12.8-4.267-17.067-12.8-17.067-25.6 0-8.533 4.267-17.067 12.8-25.6 12.8-12.8 38.4-12.8 51.2 0l64 64v-192c0-21.333 17.067-34.133 38.4-34.133s38.4 17.067 38.4 34.133v192l64-64c8.533-8.533 17.067-12.8 25.6-12.8s17.067 4.267 25.6 12.8c8.533 17.067 8.533 38.4-4.267 51.2z"],"attrs":[{},{},{},{},{},{}],"isMulticolor":false,"isMulticolor2":false,"grid":0,"tags":["winget"]},"attrs":[{},{},{},{},{},{}],"properties":{"order":66,"id":0,"name":"winget","prevSize":32,"code":59712},"setIdx":0,"setId":0,"iconIdx":64},{"icon":{"paths":["M505.244 168.391c-185.316 0-336.142 150.898-336.142 336.142s150.898 336.142 336.142 336.142 336.142-150.898 336.142-336.142-150.898-336.142-336.142-336.142zM504.747 198.258c11.928 0.319 21.476 10.095 21.476 22.108 0 0.003-0 0.005-0 0.008l0-0c0 12.214-9.901 22.116-22.116 22.116s-22.116-9.901-22.116-22.116v0c-0-0.003-0-0.006-0-0.009 0-12.214 9.901-22.116 22.116-22.116 0.225 0 0.449 0.003 0.673 0.010l-0.033-0.001zM555.378 234.667c80.287 15.42 146.83 64.365 185.612 131.384l0.699 1.309-26.098 58.88c-4.48 10.169 0.142 22.116 10.24 26.667l50.204 22.258c0.847 8.059 1.33 17.411 1.33 26.875 0 7.159-0.276 14.254-0.819 21.274l0.058-0.931h-27.947c-2.773 0-3.911 1.849-3.911 4.551v12.8c0 30.151-16.996 36.764-31.929 38.4-14.222 1.636-29.938-5.973-31.929-14.649-8.391-47.147-22.329-57.173-44.373-74.596 27.378-17.351 55.822-43.022 55.822-77.298 0-37.049-25.387-60.373-42.667-71.822-24.32-16-51.2-19.2-58.453-19.2h-288.711c38.978-43.411 91.328-74.114 150.533-85.624l1.716-0.278 34.062 35.698c7.68 8.036 20.409 8.391 28.444 0.64zM241.067 398.364c11.936 0.356 21.476 10.117 21.476 22.106 0 0.003-0 0.007-0 0.010l0-0.001c0 12.214-9.901 22.116-22.116 22.116s-22.116-9.901-22.116-22.116v0c-0-0.003-0-0.006-0-0.009 0-12.214 9.901-22.116 22.116-22.116 0.225 0 0.449 0.003 0.673 0.010l-0.033-0.001zM768.356 399.36c11.936 0.356 21.476 10.117 21.476 22.106 0 0.003-0 0.007-0 0.010l0-0.001c0 12.214-9.901 22.116-22.116 22.116s-22.116-9.901-22.116-22.116v0c-0-0.003-0-0.006-0-0.009 0-12.214 9.901-22.116 22.116-22.116 0.225 0 0.449 0.003 0.673 0.010l-0.033-0.001zM282.738 402.916h38.542v173.796h-77.796c-6.605-22.332-10.406-47.99-10.406-74.535 0-10.342 0.577-20.55 1.7-30.592l-0.112 1.234 47.644-21.191c10.169-4.551 14.791-16.427 10.24-26.596zM443.591 404.764h91.804c4.764 0 33.493 5.476 33.493 27.022 0 17.849-22.044 24.249-40.178 24.249h-85.191zM443.591 529.636h70.329c6.4 0 34.347 1.849 43.236 37.547 2.773 10.951 8.96 46.649 13.156 58.098 4.196 12.8 21.191 38.4 39.324 38.4h114.773c-8.071 10.75-16.321 20.263-25.184 29.166l0.010-0.010-46.72-10.027c-10.88-2.347-21.618 4.622-23.964 15.502l-11.093 51.769c-32.984 15.315-71.596 24.249-112.295 24.249-41.598 0-81.016-9.333-116.275-26.019l1.654 0.704-11.093-51.769c-2.347-10.88-13.013-17.849-23.893-15.502l-45.724 9.813c-8.229-8.481-15.969-17.573-23.093-27.15l-0.516-0.726h222.364c2.489 0 4.196-0.427 4.196-2.773v-78.649c0-2.276-1.707-2.773-4.196-2.773h-65.067zM340.978 709.76c11.936 0.356 21.476 10.117 21.476 22.106 0 0.003-0 0.007-0 0.010l0-0.001c0 12.214-9.901 22.116-22.116 22.116s-22.116-9.901-22.116-22.116v0c-0-0.003-0-0.006-0-0.009 0-12.214 9.901-22.116 22.116-22.116 0.225 0 0.449 0.003 0.673 0.010l-0.033-0.001zM668.444 710.756c11.936 0.356 21.476 10.117 21.476 22.106 0 0.003-0 0.007-0 0.010l0-0.001c0 12.214-9.901 22.116-22.116 22.116s-22.116-9.901-22.116-22.116v0c-0-0.003-0-0.006-0-0.009 0-12.214 9.901-22.116 22.116-22.116 0.225 0 0.449 0.003 0.673 0.010l-0.033-0.001z","M822.613 504.533v0c0-175.278-142.091-317.369-317.369-317.369v0c-175.278 0-317.369 142.091-317.369 317.369v0c0 175.278 142.091 317.369 317.369 317.369v0c175.278 0 317.369-142.091 317.369-317.369zM816.64 473.884l49.493 30.649-49.493 30.649 42.524 39.751-54.471 20.409 33.991 47.289-57.529 9.387 24.178 53.049-58.24-2.062 13.369 56.747-56.747-13.369 2.062 58.24-53.049-24.178-9.387 57.529-47.289-33.991-20.409 54.471-39.751-42.524-30.649 49.493-30.649-49.493-39.751 42.524-20.409-54.471-47.289 33.991-9.387-57.529-53.049 24.178 2.062-58.24-56.747 13.369 13.369-56.747-58.24 2.062 24.178-53.049-57.529-9.387 33.991-47.289-54.471-20.409 42.524-39.751-49.493-30.649 49.493-30.649-42.524-39.751 54.471-20.409-33.991-47.289 57.529-9.387-24.178-53.049 58.24 2.062-13.369-56.747 56.747 13.369-2.062-58.24 53.049 24.178 9.387-57.529 47.289 33.991 20.409-54.471 39.751 42.524 30.649-49.493 30.649 49.493 39.751-42.524 20.409 54.471 47.289-33.991 9.387 57.529 53.049-24.178-2.062 58.24 56.747-13.369-13.369 56.747 58.24-2.062-24.178 53.049 57.529 9.387-33.991 47.289 54.471 20.409z"],"attrs":[{},{"stroke":"rgb(0, 0, 0)","strokeLinejoin":"round","strokeLinecap":"round","strokeMiterlimit":"4","strokeWidth":21.333333333333332}],"isMulticolor":false,"isMulticolor2":true,"grid":0,"tags":["rust"]},"attrs":[{},{"stroke":"rgb(0, 0, 0)","strokeLinejoin":"round","strokeLinecap":"round","strokeMiterlimit":"4","strokeWidth":21.333333333333332}],"properties":{"order":73,"id":21,"name":"rust","prevSize":32,"code":59713},"setIdx":0,"setId":0,"iconIdx":65},{"icon":{"paths":["M96.894 488.139l30.623-105.298c4.166-14.394 8.703-26.481 14.032-38.13l-0.701 1.71c9.153-19.732 19.108-36.626 30.49-52.422l-0.639 0.933c13.686-19.485 27.964-36.584 43.528-52.417l-0.056 0.058c32.151-34.054 68.522-63.602 108.409-87.958l2.298-1.304c55.048-33.662 121.265-54.376 192.163-56.404l0.562-0.013c1.409-0.019 3.073-0.030 4.74-0.030 52.164 0 101.837 10.667 146.957 29.939l-2.444-0.928c51.78 21.543 72.26 45.404 83.176 61.537 15.218 20.851 24.348 46.988 24.348 75.258 0 0.338-0.001 0.676-0.004 1.014l0-0.052c-0.731 22.11-6.951 42.621-17.33 60.406l0.328-0.609c-11.59 20.977-27.649 38.179-46.984 50.771l-0.545 0.333-1.159 0.676c-18.321 10.649-40.016 17.606-63.174 19.292l-0.488 0.028c-5.519 0.458-11.947 0.718-18.435 0.718-27.075 0-53.089-4.543-77.322-12.907l1.665 0.5c-36.13-10.24-54.774-17.292-69.651-22.895-9.333-3.886-20.918-7.753-32.808-10.865l-1.969-0.438c-23.108-6.065-49.638-9.547-76.98-9.547-12.223 0-24.283 0.696-36.143 2.050l1.45-0.135c-48.474 4.262-92.396 20.733-129.591 46.287l0.914-0.594c-11.504 8.071-21.597 16.447-30.971 25.559l0.058-0.056zM369.413 281.117c32.331 0.021 63.689 4.142 93.596 11.872l-2.595-0.569c16.318 4.153 29.996 8.714 43.24 14.12l-2.184-0.788c14.008 5.217 31.3 11.689 65.014 21.253 31.106 8.791 50.041 12.558 73.129 9.66 14.631-1.115 28.052-5.386 39.881-12.127l-0.467 0.245c11.511-7.551 20.788-17.601 27.223-29.423l0.213-0.427 0.483-0.966c5.59-9.171 9.11-20.158 9.655-31.922l0.006-0.151c-0.065-15.748-5.24-30.274-13.95-42.021l0.136 0.192c-4.347-6.472-16.229-23.861-57.962-41.25-36.083-15.647-78.107-24.748-122.256-24.748-1.17 0-2.339 0.006-3.506 0.019l0.178-0.002c-60.916 1.811-117.335 19.538-165.698 49.139l1.472-0.838c-37.838 22.893-70.441 49.348-98.995 79.659l-0.217 0.233c-7.438 7.825-14.008 15.553-20.77 23.378 27.445-11.407 59.247-19.334 92.49-22.23l1.216-0.085c12.201-1.413 26.34-2.22 40.667-2.222l0.003-0z","M207.118 629.18c-2.898 0-5.796 0-8.791 0-52.295-6.26-93.107-48.098-97.733-100.335l-0.030-0.423-1.063-12.172 7.922-9.66c19.914-23.203 40.173-44.288 61.547-64.193l0.473-0.435c28.305-26.276 47.046-43.665 77.283-57.962 21.638-10.701 46.79-18.279 73.317-21.346l1.068-0.1 31.493-3.574 0.676 31.686c0.067 2.58 0.105 5.618 0.105 8.665 0 13.76-0.775 27.339-2.284 40.695l0.15-1.638c-3.381 34.777-7.342 74.482-31.396 112.93-15.070 24.151-54.774 77.863-112.737 77.863zM160.555 534.315c1.701 5.485 4.068 10.261 7.068 14.564l-0.112-0.17c8.44 12.125 21.588 20.469 36.739 22.385l0.26 0.027c30.43 2.512 57.962-37.675 65.787-50.137 16.809-27.049 19.804-56.996 22.895-88.296l0.58-5.12c-8.826 2.829-16.211 5.841-23.318 9.333l1.002-0.445c-21.060 10.24-34.391 22.219-62.599 48.302-16.809 15.746-33.038 32.266-48.302 49.558z","M510.261 927.686c-0.332 0.001-0.725 0.002-1.118 0.002-52.112 0-101.735-10.657-146.808-29.91l2.441 0.927c-51.297-21.349-71.97-45.017-82.886-61.054-15.399-21.164-24.635-47.675-24.635-76.342 0-0.161 0-0.322 0.001-0.483l-0 0.025c0.744-22.077 6.962-42.553 17.33-60.309l-0.328 0.608c11.554-20.975 27.582-38.178 46.891-50.772l0.542-0.331 1.159-0.676c18.364-10.595 40.081-17.544 63.25-19.29l0.508-0.031c5.263-0.412 11.396-0.647 17.585-0.647 27.452 0 53.825 4.623 78.382 13.133l-1.681-0.507c36.033 10.24 54.581 17.292 69.555 22.895 9.333 3.886 20.918 7.753 32.808 10.865l1.969 0.438c23.085 6.066 49.588 9.549 76.904 9.549 12.216 0 24.269-0.697 36.121-2.052l-1.448 0.135c48.464-4.405 92.336-20.965 129.489-46.576l-0.909 0.592c11.423-8.069 21.453-16.444 30.766-25.549l-0.046 0.045 77.283-76.22-29.078 104.718c-4.148 14.505-8.753 26.755-14.202 38.535l0.677-1.632c-8.984 19.676-18.882 36.546-30.263 52.272l0.606-0.879c-13.73 19.231-28.034 36.14-43.591 51.802l0.022-0.023c-32.183 34.093-68.622 63.647-108.6 87.962l-2.301 1.3c-55.143 33.952-121.504 54.929-192.59 57.174l-0.618 0.015zM352.411 698.735c-11.456 7.58-20.696 17.624-27.124 29.421l-0.214 0.43v0.966c-5.59 9.171-9.11 20.158-9.655 31.922l-0.006 0.151c-0.001 0.158-0.002 0.344-0.002 0.531 0 15.478 5 29.787 13.473 41.402l-0.139-0.2 0.58 0.869c3.864 5.7 15.746 23.088 57.962 40.477 36.065 15.647 78.069 24.749 122.199 24.749 1.19 0 2.379-0.007 3.567-0.020l-0.181 0.002c60.917-1.801 117.338-19.53 165.697-49.139l-1.47 0.837c37.838-23.003 70.462-49.481 99.101-79.767l0.207-0.221c7.149-7.245 13.911-14.587 20.287-22.219-27.475 11.348-59.311 19.24-92.579 22.133l-1.224 0.086c-12.158 1.417-26.244 2.225-40.518 2.225-32.242 0-63.521-4.124-93.337-11.873l2.571 0.567c-16.318-4.153-29.996-8.714-43.24-14.12l2.184 0.788c-14.008-5.217-31.3-11.786-65.014-21.253-31.106-8.791-50.041-12.558-73.129-10.143-14.785 0.876-28.433 4.994-40.485 11.648l0.491-0.248z","M679.414 664.731l-0.773-31.589c-0.072-2.869-0.113-6.248-0.113-9.637 0-13.341 0.638-26.534 1.884-39.549l-0.128 1.657c3.478-34.971 7.438-74.578 31.589-113.22 32.749-53.035 77.283-81.244 121.045-77.283 52.429 5.983 93.454 47.77 98.214 100.036l0.032 0.432 1.063 12.172-7.922 9.66c-19.936 23.201-40.258 44.289-61.714 64.171l-0.499 0.457c-29.561 27.339-47.432 43.858-77.283 57.962-21.609 10.715-46.73 18.294-73.228 21.347l-1.060 0.099zM824.32 452.782c-28.981 0-55.354 38.158-62.792 50.234-17.002 27.146-20.094 57.962-22.992 88.296 0 1.739 0 3.478-0.483 5.217 8.908-2.944 16.288-5.985 23.412-9.468l-1.096 0.484c21.832-10.53 35.55-23.185 62.792-48.302 16.906-15.65 33.135-32.169 48.302-49.461-1.676-5.485-4.046-10.264-7.063-14.556l0.108 0.162c-8.5-12.19-21.765-20.552-37.038-22.387l-0.251-0.025z"],"attrs":[{},{},{},{}],"width":1032,"grid":0,"tags":["vcpkg"],"isMulticolor":false,"isMulticolor2":false},"attrs":[{},{},{},{}],"properties":{"order":74,"id":5,"name":"vcpkg","prevSize":32,"code":59714},"setIdx":0,"setId":0,"iconIdx":66}],"height":1024,"metadata":{"name":"UniGetUI-Symbols"},"preferences":{"showGlyphs":true,"showQuickUse":true,"showQuickUse2":true,"showSVGs":true,"fontPref":{"prefix":"icon-","metadata":{"fontFamily":"UniGetUI-Symbols","majorVersion":1,"minorVersion":2},"metrics":{"emSize":1024,"baseline":6.25,"whitespace":50},"embed":false,"hideFormats":false,"autoHost":false,"showVersion":false,"showMetadata":false,"showMetrics":false,"showSelector":false},"imagePref":{"prefix":"icon-","png":true,"useClassSelector":true,"color":0,"bgColor":16777215,"classSelector":".icon","name":"UniGetUI-Symbols","height":32,"columns":16,"margin":16},"historySize":50,"showCodes":true,"gridSize":16,"quickUsageToken":{"UntitledProject":"YTZmOTliNmFmMyMxNzMxMjc2MjI4I3RKQ25ENFZzM0VwS29RaWxEbUwwR1VoSk1mUkxPZzduMm5ON1NtcUphSE1Z"}}} \ No newline at end of file diff --git a/src/SharedAssets/Assets/Symbols/Font/style.css b/src/SharedAssets/Assets/Symbols/Font/style.css new file mode 100644 index 0000000..ce67275 --- /dev/null +++ b/src/SharedAssets/Assets/Symbols/Font/style.css @@ -0,0 +1,228 @@ +@font-face { + font-family: 'UniGetUI-Symbols'; + src: url('fonts/UniGetUI-Symbols.eot?ktqh67'); + src: url('fonts/UniGetUI-Symbols.eot?ktqh67#iefix') format('embedded-opentype'), + url('fonts/UniGetUI-Symbols.ttf?ktqh67') format('truetype'), + url('fonts/UniGetUI-Symbols.woff?ktqh67') format('woff'), + url('fonts/UniGetUI-Symbols.svg?ktqh67#UniGetUI-Symbols') format('svg'); + font-weight: normal; + font-style: normal; + font-display: block; +} + +[class^="icon-"], [class*=" icon-"] { + /* use !important to prevent issues with browser extensions that change fonts */ + font-family: 'UniGetUI-Symbols' !important; + speak: never; + font-style: normal; + font-weight: normal; + font-variant: normal; + text-transform: none; + line-height: 1; + + /* Better Font Rendering =========== */ + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +.icon-add_to:before { + content: "\e900"; +} +.icon-android:before { + content: "\e901"; +} +.icon-backward:before { + content: "\e902"; +} +.icon-bucket:before { + content: "\e903"; +} +.icon-buggy:before { + content: "\e904"; +} +.icon-checksum:before { + content: "\e905"; +} +.icon-choco:before { + content: "\e906"; +} +.icon-clipboard_list:before { + content: "\e907"; +} +.icon-close_round:before { + content: "\e908"; +} +.icon-collapse:before { + content: "\e909"; +} +.icon-console:before { + content: "\e90a"; +} +.icon-copy:before { + content: "\e90b"; +} +.icon-cross:before { + content: "\e90c"; +} +.icon-delete:before { + content: "\e90d"; +} +.icon-disk:before { + content: "\e90e"; +} +.icon-dotnet:before { + content: "\e90f"; +} +.icon-download:before { + content: "\e910"; +} +.icon-empty:before { + content: "\e911"; +} +.icon-expand:before { + content: "\e912"; +} +.icon-experimental:before { + content: "\e913"; +} +.icon-forward:before { + content: "\e914"; +} +.icon-gog:before { + content: "\e915"; +} +.icon-help:before { + content: "\e916"; +} +.icon-history:before { + content: "\e917"; +} +.icon-home:before { + content: "\e918"; +} +.icon-id:before { + content: "\e919"; +} +.icon-info_round:before { + content: "\e91a"; +} +.icon-installed:before { + content: "\e91b"; +} +.icon-installed_filled:before { + content: "\e91c"; +} +.icon-interactive:before { + content: "\e91d"; +} +.icon-launch:before { + content: "\e91e"; +} +.icon-loading:before { + content: "\e91f"; +} +.icon-loading_filled:before { + content: "\e920"; +} +.icon-local_pc:before { + content: "\e921"; +} +.icon-megaphone:before { + content: "\e922"; +} +.icon-ms_store:before { + content: "\e923"; +} +.icon-node:before { + content: "\e924"; +} +.icon-open_folder:before { + content: "\e925"; +} +.icon-options:before { + content: "\e926"; +} +.icon-package:before { + content: "\e927"; +} +.icon-pin:before { + content: "\e928"; +} +.icon-pin_filled:before { + content: "\e929"; +} +.icon-powershell:before { + content: "\e92a"; +} +.icon-python:before { + content: "\e92b"; +} +.icon-reload:before { + content: "\e92c"; +} +.icon-sandclock:before { + content: "\e92d"; +} +.icon-save_as:before { + content: "\e92e"; +} +.icon-scoop:before { + content: "\e92f"; +} +.icon-search:before { + content: "\e930"; +} +.icon-settings:before { + content: "\e931"; +} +.icon-share:before { + content: "\e932"; +} +.icon-skip:before { + content: "\e933"; +} +.icon-steam:before { + content: "\e934"; +} +.icon-sys_tray:before { + content: "\e935"; +} +.icon-uac:before { + content: "\e936"; +} +.icon-undelete:before { + content: "\e937"; +} +.icon-update:before { + content: "\e938"; +} +.icon-upgradable:before { + content: "\e939"; +} +.icon-upgradable_filled:before { + content: "\e93a"; +} +.icon-uplay:before { + content: "\e93b"; +} +.icon-version:before { + content: "\e93c"; +} +.icon-warning:before { + content: "\e93d"; +} +.icon-warning_filled:before { + content: "\e93e"; +} +.icon-warning_round:before { + content: "\e93f"; +} +.icon-winget:before { + content: "\e940"; +} +.icon-rust:before { + content: "\e941"; +} +.icon-vcpkg:before { + content: "\e942"; +} diff --git a/src/SharedAssets/Assets/Symbols/InstalledPackages.svg b/src/SharedAssets/Assets/Symbols/InstalledPackages.svg new file mode 100644 index 0000000..0f2fee2 --- /dev/null +++ b/src/SharedAssets/Assets/Symbols/InstalledPackages.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/SharedAssets/Assets/Symbols/PackagesBundle.svg b/src/SharedAssets/Assets/Symbols/PackagesBundle.svg new file mode 100644 index 0000000..7434f22 --- /dev/null +++ b/src/SharedAssets/Assets/Symbols/PackagesBundle.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/SharedAssets/Assets/Symbols/Sources.svg b/src/SharedAssets/Assets/Symbols/Sources.svg new file mode 100644 index 0000000..a46cf38 --- /dev/null +++ b/src/SharedAssets/Assets/Symbols/Sources.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/SharedAssets/Assets/Symbols/add_to.svg b/src/SharedAssets/Assets/Symbols/add_to.svg new file mode 100644 index 0000000..601a6e4 --- /dev/null +++ b/src/SharedAssets/Assets/Symbols/add_to.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/SharedAssets/Assets/Symbols/android.svg b/src/SharedAssets/Assets/Symbols/android.svg new file mode 100644 index 0000000..c39d2c8 --- /dev/null +++ b/src/SharedAssets/Assets/Symbols/android.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/SharedAssets/Assets/Symbols/apt.svg b/src/SharedAssets/Assets/Symbols/apt.svg new file mode 100644 index 0000000..bc759bb --- /dev/null +++ b/src/SharedAssets/Assets/Symbols/apt.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/src/SharedAssets/Assets/Symbols/backward.svg b/src/SharedAssets/Assets/Symbols/backward.svg new file mode 100644 index 0000000..8d0e0d2 --- /dev/null +++ b/src/SharedAssets/Assets/Symbols/backward.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/SharedAssets/Assets/Symbols/bucket.svg b/src/SharedAssets/Assets/Symbols/bucket.svg new file mode 100644 index 0000000..4d52af1 --- /dev/null +++ b/src/SharedAssets/Assets/Symbols/bucket.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/SharedAssets/Assets/Symbols/buggy.svg b/src/SharedAssets/Assets/Symbols/buggy.svg new file mode 100644 index 0000000..297b8f8 --- /dev/null +++ b/src/SharedAssets/Assets/Symbols/buggy.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/SharedAssets/Assets/Symbols/bun.svg b/src/SharedAssets/Assets/Symbols/bun.svg new file mode 100644 index 0000000..278b63c --- /dev/null +++ b/src/SharedAssets/Assets/Symbols/bun.svg @@ -0,0 +1 @@ +Bun \ No newline at end of file diff --git a/src/SharedAssets/Assets/Symbols/checksum.svg b/src/SharedAssets/Assets/Symbols/checksum.svg new file mode 100644 index 0000000..e869c2c --- /dev/null +++ b/src/SharedAssets/Assets/Symbols/checksum.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/SharedAssets/Assets/Symbols/choco.svg b/src/SharedAssets/Assets/Symbols/choco.svg new file mode 100644 index 0000000..334a043 --- /dev/null +++ b/src/SharedAssets/Assets/Symbols/choco.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/SharedAssets/Assets/Symbols/clipboard_list.svg b/src/SharedAssets/Assets/Symbols/clipboard_list.svg new file mode 100644 index 0000000..aa14f81 --- /dev/null +++ b/src/SharedAssets/Assets/Symbols/clipboard_list.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/SharedAssets/Assets/Symbols/close_round.svg b/src/SharedAssets/Assets/Symbols/close_round.svg new file mode 100644 index 0000000..d3a22f5 --- /dev/null +++ b/src/SharedAssets/Assets/Symbols/close_round.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/SharedAssets/Assets/Symbols/collapse.svg b/src/SharedAssets/Assets/Symbols/collapse.svg new file mode 100644 index 0000000..5c451f4 --- /dev/null +++ b/src/SharedAssets/Assets/Symbols/collapse.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/SharedAssets/Assets/Symbols/console.svg b/src/SharedAssets/Assets/Symbols/console.svg new file mode 100644 index 0000000..22c18ee --- /dev/null +++ b/src/SharedAssets/Assets/Symbols/console.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/SharedAssets/Assets/Symbols/copy.svg b/src/SharedAssets/Assets/Symbols/copy.svg new file mode 100644 index 0000000..be87342 --- /dev/null +++ b/src/SharedAssets/Assets/Symbols/copy.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/SharedAssets/Assets/Symbols/cross.svg b/src/SharedAssets/Assets/Symbols/cross.svg new file mode 100644 index 0000000..412a2e8 --- /dev/null +++ b/src/SharedAssets/Assets/Symbols/cross.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/SharedAssets/Assets/Symbols/delete.svg b/src/SharedAssets/Assets/Symbols/delete.svg new file mode 100644 index 0000000..3ec6e38 --- /dev/null +++ b/src/SharedAssets/Assets/Symbols/delete.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/SharedAssets/Assets/Symbols/disk.svg b/src/SharedAssets/Assets/Symbols/disk.svg new file mode 100644 index 0000000..e2a1860 --- /dev/null +++ b/src/SharedAssets/Assets/Symbols/disk.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/SharedAssets/Assets/Symbols/dnf.svg b/src/SharedAssets/Assets/Symbols/dnf.svg new file mode 100644 index 0000000..105386f --- /dev/null +++ b/src/SharedAssets/Assets/Symbols/dnf.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/src/SharedAssets/Assets/Symbols/dotnet.svg b/src/SharedAssets/Assets/Symbols/dotnet.svg new file mode 100644 index 0000000..149e605 --- /dev/null +++ b/src/SharedAssets/Assets/Symbols/dotnet.svg @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/src/SharedAssets/Assets/Symbols/download.svg b/src/SharedAssets/Assets/Symbols/download.svg new file mode 100644 index 0000000..c8482a8 --- /dev/null +++ b/src/SharedAssets/Assets/Symbols/download.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/SharedAssets/Assets/Symbols/empty.svg b/src/SharedAssets/Assets/Symbols/empty.svg new file mode 100644 index 0000000..9f63a28 --- /dev/null +++ b/src/SharedAssets/Assets/Symbols/empty.svg @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/src/SharedAssets/Assets/Symbols/expand.svg b/src/SharedAssets/Assets/Symbols/expand.svg new file mode 100644 index 0000000..41033f7 --- /dev/null +++ b/src/SharedAssets/Assets/Symbols/expand.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/SharedAssets/Assets/Symbols/experimental.svg b/src/SharedAssets/Assets/Symbols/experimental.svg new file mode 100644 index 0000000..c19c78a --- /dev/null +++ b/src/SharedAssets/Assets/Symbols/experimental.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/SharedAssets/Assets/Symbols/flatpak.svg b/src/SharedAssets/Assets/Symbols/flatpak.svg new file mode 100644 index 0000000..49b9130 --- /dev/null +++ b/src/SharedAssets/Assets/Symbols/flatpak.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/SharedAssets/Assets/Symbols/forward.svg b/src/SharedAssets/Assets/Symbols/forward.svg new file mode 100644 index 0000000..c801b13 --- /dev/null +++ b/src/SharedAssets/Assets/Symbols/forward.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/SharedAssets/Assets/Symbols/gog.svg b/src/SharedAssets/Assets/Symbols/gog.svg new file mode 100644 index 0000000..8bf6dde --- /dev/null +++ b/src/SharedAssets/Assets/Symbols/gog.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/SharedAssets/Assets/Symbols/help.svg b/src/SharedAssets/Assets/Symbols/help.svg new file mode 100644 index 0000000..8740667 --- /dev/null +++ b/src/SharedAssets/Assets/Symbols/help.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/SharedAssets/Assets/Symbols/history.svg b/src/SharedAssets/Assets/Symbols/history.svg new file mode 100644 index 0000000..25b97c0 --- /dev/null +++ b/src/SharedAssets/Assets/Symbols/history.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/SharedAssets/Assets/Symbols/home.svg b/src/SharedAssets/Assets/Symbols/home.svg new file mode 100644 index 0000000..297e783 --- /dev/null +++ b/src/SharedAssets/Assets/Symbols/home.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/SharedAssets/Assets/Symbols/homebrew.svg b/src/SharedAssets/Assets/Symbols/homebrew.svg new file mode 100644 index 0000000..ada5623 --- /dev/null +++ b/src/SharedAssets/Assets/Symbols/homebrew.svg @@ -0,0 +1,2 @@ + +Homebrew icon \ No newline at end of file diff --git a/src/SharedAssets/Assets/Symbols/icomoon-project.json b/src/SharedAssets/Assets/Symbols/icomoon-project.json new file mode 100644 index 0000000..9518cd7 --- /dev/null +++ b/src/SharedAssets/Assets/Symbols/icomoon-project.json @@ -0,0 +1,1648 @@ +{ + "metadata": { + "name": "UniGetUI", + "lastOpened": 1418773394855, + "created": 1731272040854 + }, + "iconSets": [ + { + "selection": [ + { + "order": 2, + "id": 66, + "name": "add_to", + "prevSize": 32, + "code": 59648, + "tempChar": "" + }, + { + "order": 3, + "id": 65, + "name": "android", + "prevSize": 32, + "code": 59649, + "tempChar": "" + }, + { + "order": 4, + "id": 64, + "name": "backward", + "prevSize": 32, + "code": 59650, + "tempChar": "" + }, + { + "order": 5, + "id": 63, + "name": "bucket", + "prevSize": 32, + "code": 59651, + "tempChar": "" + }, + { + "order": 6, + "id": 62, + "name": "buggy", + "prevSize": 32, + "code": 59652, + "tempChar": "" + }, + { + "order": 7, + "id": 61, + "name": "checksum", + "prevSize": 32, + "code": 59653, + "tempChar": "" + }, + { + "order": 8, + "id": 60, + "name": "choco", + "prevSize": 32, + "code": 59654, + "tempChar": "" + }, + { + "order": 9, + "id": 59, + "name": "clipboard_list", + "prevSize": 32, + "code": 59655, + "tempChar": "" + }, + { + "order": 10, + "id": 58, + "name": "close_round", + "prevSize": 32, + "code": 59656, + "tempChar": "" + }, + { + "order": 11, + "id": 57, + "name": "collapse", + "prevSize": 32, + "code": 59657, + "tempChar": "" + }, + { + "order": 12, + "id": 56, + "name": "console", + "prevSize": 32, + "code": 59658, + "tempChar": "" + }, + { + "order": 13, + "id": 55, + "name": "copy", + "prevSize": 32, + "code": 59659, + "tempChar": "" + }, + { + "order": 14, + "id": 54, + "name": "cross", + "prevSize": 32, + "code": 59660, + "tempChar": "" + }, + { + "order": 15, + "id": 53, + "name": "delete", + "prevSize": 32, + "code": 59661, + "tempChar": "" + }, + { + "order": 16, + "id": 52, + "name": "disk", + "prevSize": 32, + "code": 59662, + "tempChar": "" + }, + { + "order": 17, + "id": 51, + "name": "dotnet", + "prevSize": 32, + "code": 59663, + "tempChar": "" + }, + { + "order": 18, + "id": 50, + "name": "download", + "prevSize": 32, + "code": 59664, + "tempChar": "" + }, + { + "order": 19, + "id": 49, + "name": "empty", + "prevSize": 32, + "code": 59665, + "tempChar": "" + }, + { + "order": 20, + "id": 48, + "name": "expand", + "prevSize": 32, + "code": 59666, + "tempChar": "" + }, + { + "order": 21, + "id": 47, + "name": "experimental", + "prevSize": 32, + "code": 59667, + "tempChar": "" + }, + { + "order": 22, + "id": 46, + "name": "forward", + "prevSize": 32, + "code": 59668, + "tempChar": "" + }, + { + "order": 23, + "id": 45, + "name": "gog", + "prevSize": 32, + "code": 59669, + "tempChar": "" + }, + { + "order": 24, + "id": 44, + "name": "help", + "prevSize": 32, + "code": 59670, + "tempChar": "" + }, + { + "order": 25, + "id": 43, + "name": "history", + "prevSize": 32, + "code": 59671, + "tempChar": "" + }, + { + "order": 26, + "id": 42, + "name": "home", + "prevSize": 32, + "code": 59672, + "tempChar": "" + }, + { + "order": 27, + "id": 41, + "name": "id", + "prevSize": 32, + "code": 59673, + "tempChar": "" + }, + { + "order": 28, + "id": 40, + "name": "info_round", + "prevSize": 32, + "code": 59674, + "tempChar": "" + }, + { + "order": 29, + "id": 39, + "name": "installed", + "prevSize": 32, + "code": 59675, + "tempChar": "" + }, + { + "order": 30, + "id": 38, + "name": "installed_filled", + "prevSize": 32, + "code": 59676, + "tempChar": "" + }, + { + "order": 31, + "id": 37, + "name": "interactive", + "prevSize": 32, + "code": 59677, + "tempChar": "" + }, + { + "order": 32, + "id": 36, + "name": "launch", + "prevSize": 32, + "code": 59678, + "tempChar": "" + }, + { + "order": 33, + "id": 35, + "name": "loading", + "prevSize": 32, + "code": 59679, + "tempChar": "" + }, + { + "order": 34, + "id": 34, + "name": "loading_filled", + "prevSize": 32, + "code": 59680, + "tempChar": "" + }, + { + "order": 35, + "id": 33, + "name": "local_pc", + "prevSize": 32, + "code": 59681, + "tempChar": "" + }, + { + "order": 36, + "id": 32, + "name": "megaphone", + "prevSize": 32, + "code": 59682, + "tempChar": "" + }, + { + "order": 37, + "id": 31, + "name": "ms_store", + "prevSize": 32, + "code": 59683, + "tempChar": "" + }, + { + "order": 38, + "id": 30, + "name": "node", + "prevSize": 32, + "code": 59684, + "tempChar": "" + }, + { + "order": 39, + "id": 29, + "name": "open_folder", + "prevSize": 32, + "code": 59685, + "tempChar": "" + }, + { + "order": 40, + "id": 28, + "name": "options", + "prevSize": 32, + "code": 59686, + "tempChar": "" + }, + { + "order": 41, + "id": 27, + "name": "package", + "prevSize": 32, + "code": 59687, + "tempChar": "" + }, + { + "order": 42, + "id": 26, + "name": "pin", + "prevSize": 32, + "code": 59688, + "tempChar": "" + }, + { + "order": 43, + "id": 25, + "name": "pin_filled", + "prevSize": 32, + "code": 59689, + "tempChar": "" + }, + { + "order": 44, + "id": 24, + "name": "powershell", + "prevSize": 32, + "code": 59690, + "tempChar": "" + }, + { + "order": 45, + "id": 23, + "name": "python", + "prevSize": 32, + "code": 59691, + "tempChar": "" + }, + { + "order": 46, + "id": 22, + "name": "reload", + "prevSize": 32, + "code": 59692, + "tempChar": "" + }, + { + "order": 47, + "id": 20, + "name": "sandclock", + "prevSize": 32, + "code": 59693, + "tempChar": "" + }, + { + "order": 48, + "id": 19, + "name": "save_as", + "prevSize": 32, + "code": 59694, + "tempChar": "" + }, + { + "order": 49, + "id": 18, + "name": "scoop", + "prevSize": 32, + "code": 59695, + "tempChar": "" + }, + { + "order": 50, + "id": 17, + "name": "search", + "prevSize": 32, + "code": 59696, + "tempChar": "" + }, + { + "order": 51, + "id": 16, + "name": "settings", + "prevSize": 32, + "code": 59697, + "tempChar": "" + }, + { + "order": 52, + "id": 15, + "name": "share", + "prevSize": 32, + "code": 59698, + "tempChar": "" + }, + { + "order": 53, + "id": 14, + "name": "skip", + "prevSize": 32, + "code": 59699, + "tempChar": "" + }, + { + "order": 54, + "id": 13, + "name": "steam", + "prevSize": 32, + "code": 59700, + "tempChar": "" + }, + { + "order": 55, + "id": 12, + "name": "sys_tray", + "prevSize": 32, + "code": 59701, + "tempChar": "" + }, + { + "order": 56, + "id": 11, + "name": "uac", + "prevSize": 32, + "code": 59702, + "tempChar": "" + }, + { + "order": 57, + "id": 10, + "name": "undelete", + "prevSize": 32, + "code": 59703, + "tempChar": "" + }, + { + "order": 58, + "id": 9, + "name": "update", + "prevSize": 32, + "code": 59704, + "tempChar": "" + }, + { + "order": 59, + "id": 8, + "name": "upgradable", + "prevSize": 32, + "code": 59705, + "tempChar": "" + }, + { + "order": 60, + "id": 7, + "name": "upgradable_filled", + "prevSize": 32, + "code": 59706, + "tempChar": "" + }, + { + "order": 61, + "id": 6, + "name": "uplay", + "prevSize": 32, + "code": 59707, + "tempChar": "" + }, + { + "order": 62, + "id": 4, + "name": "version", + "prevSize": 32, + "code": 59708, + "tempChar": "" + }, + { + "order": 63, + "id": 3, + "name": "warning", + "prevSize": 32, + "code": 59709, + "tempChar": "" + }, + { + "order": 64, + "id": 2, + "name": "warning_filled", + "prevSize": 32, + "code": 59710, + "tempChar": "" + }, + { + "order": 65, + "id": 1, + "name": "warning_round", + "prevSize": 32, + "code": 59711, + "tempChar": "" + }, + { + "order": 66, + "id": 0, + "name": "winget", + "prevSize": 32, + "code": 59712, + "tempChar": "" + }, + { + "order": 73, + "id": 21, + "name": "rust", + "prevSize": 32, + "code": 59713, + "tempChar": "" + }, + { + "order": 74, + "id": 5, + "name": "vcpkg", + "prevSize": 32, + "code": 59714, + "tempChar": "" + } + ], + "id": 0, + "metadata": { + "name": "Untitled Set", + "importSize": { + "width": 24, + "height": 24 + } + }, + "height": 1024, + "prevSize": 32, + "icons": [ + { + "id": 66, + "paths": [ + "M746.667 42.667c-129.6 0-234.667 105.067-234.667 234.667s105.067 234.667 234.667 234.667c129.6 0 234.667-105.067 234.667-234.667s-105.067-234.667-234.667-234.667zM746.667 106.667c11.776 0 21.333 9.557 21.333 21.333v128h128c11.776 0 21.333 9.557 21.333 21.333s-9.557 21.333-21.333 21.333h-128v128c0 11.776-9.557 21.333-21.333 21.333s-21.333-9.557-21.333-21.333v-128h-128c-11.776 0-21.333-9.557-21.333-21.333s9.557-21.333 21.333-21.333h128v-128c0-11.776 9.557-21.333 21.333-21.333zM266.667 128c-76.373 0-138.667 62.293-138.667 138.667v490.667c0 76.373 62.293 138.667 138.667 138.667h490.667c76.373 0 138.667-62.293 138.667-138.667v-202.667h-257.708c-17.672 0.002-31.998 14.328-32 32l-0 0c0 34.277-12.347 56.311-30.125 72s-42.281 24-64.167 24c-21.885 0-46.389-8.311-64.167-24s-30.125-37.723-30.125-72c-0.002-17.672-14.328-31.998-32-32l-193.709-0v-288c0-41.173 33.493-74.667 74.667-74.667h216.125c7.253-22.827 17.492-44.16 30.292-64h-246.417zM192 618.667h168.417c7.063 35.742 21.599 67.275 45.083 88 30.569 26.977 69.228 40 106.5 40s75.931-13.023 106.5-40c23.484-20.725 38.020-52.258 45.083-88h168.417v138.667c0 41.173-33.493 74.667-74.667 74.667h-490.667c-41.173 0-74.667-33.493-74.667-74.667v-138.667z" + ], + "attrs": [ + {} + ], + "isMulticolor": false, + "isMulticolor2": false, + "grid": 0, + "tags": [ + "add_to" + ] + }, + { + "id": 65, + "paths": [ + "M693.75 20.958c-0.042-0-0.092-0-0.142-0-10.863 0-20.463 5.413-26.248 13.688l-0.069 0.104-39.292 55.042c-35.356-16.394-74.573-25.792-116-25.792s-80.644 9.397-116 25.792l-39.292-55.042c-5.855-8.366-15.447-13.769-26.301-13.769-0.392 0-0.783 0.007-1.172 0.021l0.056-0.002c-17.18 0.629-30.868 14.707-30.868 31.983 0 7.123 2.327 13.703 6.263 19.020l-0.061-0.087 36.708 51.375c-61.037 47.903-101.436 120.677-105.917 202.917-10.28-3.802-21.221-6.208-32.75-6.208-52.64 0-96 43.36-96 96v234.667c0 52.64 43.36 96 96 96 12.593 0 24.602-2.587 35.667-7.083 8.373 29.955 31.135 53.953 60.333 64.542v81.208c0 52.64 43.36 96 96 96s96-43.36 96-96v-74.667h42.667v74.667c0 52.64 43.36 96 96 96s96-43.36 96-96v-81.208c29.198-10.589 51.961-34.587 60.333-64.542 11.064 4.497 23.073 7.083 35.667 7.083 52.64 0 96-43.36 96-96v-234.667c0-52.64-43.36-96-96-96-11.529 0-22.47 2.407-32.75 6.208-4.481-82.24-44.88-155.013-105.917-202.917l36.708-51.375c3.884-5.235 6.218-11.823 6.218-18.956 0-17.618-14.237-31.912-31.834-32.003l-0.009-0zM512 128c110.616 0 197.904 84.427 209.042 192h-418.083c11.138-107.573 98.426-192 209.042-192zM416 213.333c-17.673 0-32 14.327-32 32s14.327 32 32 32v0c17.673 0 32-14.327 32-32s-14.327-32-32-32v0zM608 213.333c-17.673 0-32 14.327-32 32s14.327 32 32 32v0c17.673 0 32-14.327 32-32s-14.327-32-32-32v0zM202.667 384c18.059 0 32 13.941 32 32v234.667c0 18.059-13.941 32-32 32s-32-13.941-32-32v-234.667c0-18.059 13.941-32 32-32zM298.667 384h426.667v330.667c0 18.059-13.941 32-32 32h-362.667c-18.059 0-32-13.941-32-32v-330.667zM821.333 384c18.059 0 32 13.941 32 32v234.667c0 18.059-13.941 32-32 32s-32-13.941-32-32v-234.667c0-18.059 13.941-32 32-32zM362.667 810.667h64v74.667c0 18.059-13.941 32-32 32s-32-13.941-32-32v-74.667zM597.333 810.667h64v74.667c0 18.059-13.941 32-32 32s-32-13.941-32-32v-74.667z" + ], + "attrs": [ + {} + ], + "isMulticolor": false, + "isMulticolor2": false, + "grid": 0, + "tags": [ + "android" + ] + }, + { + "id": 64, + "paths": [ + "M735.375 63.708c-8.646 0.26-16.392 3.91-21.993 9.66l-0.007 0.007-416 416c-5.789 5.791-9.369 13.79-9.369 22.625s3.58 16.834 9.369 22.625l416 416c5.833 6.068 14.019 9.838 23.085 9.838 17.675 0 32.003-14.328 32.003-32.003 0-9.066-3.77-17.252-9.828-23.075l-0.011-0.010-393.375-393.375 393.375-393.375c5.971-5.82 9.675-13.941 9.675-22.927 0-17.675-14.328-32.003-32.003-32.003-0.324 0-0.647 0.005-0.969 0.014l0.047-0.001z" + ], + "attrs": [ + {} + ], + "isMulticolor": false, + "isMulticolor2": false, + "grid": 0, + "tags": [ + "backward" + ] + }, + { + "id": 63, + "paths": [ + "M522.667 21.333c-170.466 0-309.333 138.868-309.333 309.333v53.333h-10.667c-17.672 0.002-31.998 14.328-32 32l-0 0v448c0 64.422 52.911 117.333 117.333 117.333h469.333c64.422 0 117.333-52.911 117.333-117.333v-448c-0.002-17.672-14.328-31.998-32-32l-10.667-0v-53.333c0-170.466-138.868-309.333-309.333-309.333zM522.667 85.333c135.881 0 245.333 109.452 245.333 245.333v53.333h-490.667v-53.333c0-135.881 109.452-245.333 245.333-245.333zM234.667 448h5.417c1.559 0.269 3.356 0.423 5.187 0.423s3.628-0.154 5.376-0.45l-0.188 0.026h69.542c35.349 0 64 28.651 64 64v117.333c0 29.461 23.872 53.333 53.333 53.333s53.333-23.872 53.333-53.333v-96c0-23.573 19.093-42.667 42.667-42.667s42.667 19.093 42.667 42.667v10.667c0 29.461 23.872 53.333 53.333 53.333s53.333-23.872 53.333-53.333v-32c0-35.349 28.651-64 64-64h48.083c1.559 0.269 3.356 0.423 5.187 0.423s3.628-0.154 5.376-0.45l-0.188 0.026h5.542v416c0 29.829-23.505 53.333-53.333 53.333h-469.333c-29.829 0-53.333-23.505-53.333-53.333v-416z" + ], + "attrs": [ + {} + ], + "isMulticolor": false, + "isMulticolor2": false, + "grid": 0, + "tags": [ + "bucket" + ] + }, + { + "id": 62, + "paths": [ + "M308.833 106.208c-17.459 0.281-31.503 14.5-31.503 31.999 0 0.161 0.001 0.323 0.004 0.483l-0-0.024v64c0.002 8.836 3.584 16.835 9.375 22.625l45.125 45.125c-20.881 32.954-33.167 71.854-33.167 113.583v10.667c-0.002 0.138-0.003 0.301-0.003 0.465 0 3.16 0.458 6.212 1.311 9.095l-0.057-0.226-53.292-53.292c-3.739-3.732-8.398-6.545-13.607-8.068l-0.226-0.057-149.333-42.667c-2.959-0.997-6.366-1.573-9.908-1.573-17.675 0-32.003 14.328-32.003 32.003 0 14.95 10.251 27.506 24.107 31.022l0.221 0.048 141.375 40.417 60.083 60.083c-1.902 2.506-3.559 5.184-5.375 7.75-0.361 0.049-0.545 0.078-0.729 0.109l0.187-0.026-128 21.333c-9.485 1.617-17.413 7.217-22.128 14.983l-0.080 0.142-64 106.667c-2.862 4.699-4.556 10.381-4.556 16.46 0 17.68 14.333 32.013 32.013 32.013 11.603 0 21.764-6.173 27.379-15.414l0.080-0.142 56.375-94 67.542-11.25c-8.086 24.718-12.708 50.85-12.708 78.125 0 46.972 16.319 91.167 41.25 130.625l-61.167 87.375-128.167 39.417c-13.404 4.019-23.004 16.244-23.004 30.712 0 17.675 14.328 32.003 32.003 32.003 3.514 0 6.897-0.566 10.060-1.613l-0.226 0.065 138.667-42.667c6.964-2.195 12.736-6.497 16.724-12.149l0.068-0.101 55.958-79.958c7.727 8.329 15.686 16.403 23.958 24 58.625 53.841 128.499 90.958 192.542 90.958s133.917-37.118 192.542-90.958c4.976-4.57 9.706-9.494 14.5-14.333l55.708 71.625c4.121 5.244 9.751 9.133 16.232 11.027l0.226 0.057 149.333 42.667c2.959 0.997 6.367 1.573 9.909 1.573 17.675 0 32.003-14.328 32.003-32.003 0-14.95-10.251-27.506-24.107-31.022l-0.221-0.048-139.292-39.833-57.667-74.125c29.664-42.527 49.5-91.243 49.5-143.292 0-27.275-4.622-53.407-12.708-78.125l67.542 11.25 56.375 94c5.694 9.386 15.857 15.561 27.462 15.561 17.68 0 32.013-14.333 32.013-32.013 0-6.080-1.695-11.765-4.639-16.607l0.080 0.142-64-106.667c-4.796-7.908-12.723-13.508-22.019-15.098l-0.19-0.027-128-21.333c0.003-0.005-0.181-0.034-0.366-0.062l-0.176-0.022c-1.816-2.566-3.473-5.244-5.375-7.75l58.417-58.417 138.792-19.833c16.031-1.897 28.347-15.407 28.347-31.794 0-17.675-14.328-32.003-32.003-32.003-1.917 0-3.795 0.169-5.62 0.492l0.193-0.028-149.333 21.333c-7.122 1.046-13.342 4.304-18.083 9.042l-53.333 53.333c0.821-2.697 1.294-5.797 1.294-9.008 0-0.129-0.001-0.258-0.002-0.387l0 0.020v-10.667c0-36.19-9.171-70.286-25.208-100.208l58.5-58.5c5.791-5.79 9.373-13.789 9.375-22.625l0-0v-64c0.002-0.136 0.003-0.298 0.003-0.459 0-17.675-14.328-32.003-32.003-32.003-0.176 0-0.351 0.001-0.526 0.004l0.026-0c-17.459 0.281-31.503 14.5-31.503 31.999 0 0.161 0.001 0.323 0.004 0.483l-0-0.024v50.75l-42.625 42.625c-31.559-31.030-72.723-52.159-118.458-58.875-3.736-13.82-16.157-23.822-30.915-23.833l-0.001-0c-14.76 0.011-27.181 10.014-30.865 23.609l-0.052 0.224c-40.533 5.952-77.411 23.261-107.25 48.75l-32.5-32.5v-50.75c0.002-0.136 0.003-0.298 0.003-0.459 0-17.675-14.328-32.003-32.003-32.003-0.176 0-0.351 0.001-0.526 0.004l0.026-0zM512 234.667c81.617 0 147.242 64.578 149.167 145.708-44.898-24.719-96.237-39.042-149.167-39.042s-104.268 14.323-149.167 39.042c0.805-33.912 12.729-64.887 32.333-89.5 2.141-1.914 4-4.077 5.55-6.46l0.075-0.124c27.285-30.441 66.841-49.625 111.208-49.625zM512 405.333c121.767 0 234.667 98 234.667 213.333 0 54.634-35.743 114.963-85.417 160.583-37.117 34.088-81.901 58.579-117.25 68.792v-261.375c0.002-0.137 0.003-0.298 0.003-0.459 0-17.675-14.328-32.003-32.003-32.003-0.176 0-0.351 0.001-0.527 0.004l0.026-0c-17.459 0.281-31.503 14.5-31.503 31.999 0 0.161 0.001 0.323 0.004 0.483l-0-0.024v261.375c-35.349-10.213-80.133-34.704-117.25-68.792-49.674-45.621-85.417-105.95-85.417-160.583 0-115.334 112.899-213.333 234.667-213.333z" + ], + "attrs": [ + {} + ], + "isMulticolor": false, + "isMulticolor2": false, + "grid": 0, + "tags": [ + "buggy" + ] + }, + { + "id": 61, + "paths": [ + "M436.5 84.917c-15.344 0.443-27.95 11.621-30.596 26.263l-0.029 0.195-43.5 229.958h-202.375c-0.135-0.002-0.293-0.003-0.453-0.003-17.675 0-32.003 14.328-32.003 32.003s14.328 32.003 32.003 32.003c0.159 0 0.318-0.001 0.477-0.003l-0.024 0h190.25l-40.333 213.333h-192.583c-0.135-0.002-0.293-0.003-0.453-0.003-17.675 0-32.003 14.328-32.003 32.003s14.328 32.003 32.003 32.003c0.159 0 0.318-0.001 0.477-0.003l-0.024 0h180.458l-41.25 218.042c-0.356 1.791-0.559 3.851-0.559 5.958 0 17.683 14.335 32.018 32.018 32.018 15.576 0 28.554-11.122 31.426-25.857l0.033-0.202 43.5-229.958h233.5l-41.25 218.042c-0.356 1.791-0.559 3.851-0.559 5.958 0 17.683 14.335 32.018 32.018 32.018 15.576 0 28.554-11.122 31.426-25.857l0.033-0.202 43.5-229.958h202.375c0.135 0.002 0.293 0.003 0.453 0.003 17.675 0 32.003-14.328 32.003-32.003s-14.328-32.003-32.003-32.003c-0.159 0-0.318 0.001-0.477 0.003l0.024-0h-190.25l40.333-213.333h192.583c0.135 0.002 0.293 0.003 0.453 0.003 17.675 0 32.003-14.328 32.003-32.003s-14.328-32.003-32.003-32.003c-0.159 0-0.318 0.001-0.477 0.003l0.024-0h-180.458l41.25-218.042c0.356-1.791 0.559-3.851 0.559-5.958 0-17.683-14.335-32.018-32.018-32.018-15.576 0-28.554 11.122-31.426 25.857l-0.033 0.202-43.5 229.958h-233.5l41.25-218.042c0.409-1.92 0.643-4.125 0.643-6.385 0-17.675-14.328-32.003-32.003-32.003-0.328 0-0.654 0.005-0.98 0.015l0.048-0.001zM415.417 405.333h233.5l-40.333 213.333h-233.5l40.333-213.333z" + ], + "attrs": [ + {} + ], + "isMulticolor": false, + "isMulticolor2": false, + "grid": 0, + "tags": [ + "checksum" + ] + }, + { + "id": 60, + "paths": [ + "M309.333 85.333c-64.422 0-117.333 52.911-117.333 117.333v597.333c0 64.422 52.911 117.333 117.333 117.333h405.333c64.422 0 117.333-52.911 117.333-117.333v-295.208c0.15-1.163 0.235-2.509 0.235-3.875s-0.086-2.712-0.252-4.032l0.016 0.157v-294.375c0-64.422-52.911-117.333-117.333-117.333h-405.333zM309.333 149.333h74.667v128h-128v-74.667c0-29.829 23.505-53.333 53.333-53.333zM448 149.333h128v128h-128v-128zM640 149.333h74.667c29.829 0 53.333 23.505 53.333 53.333v74.667h-128v-128zM256 341.333h128v128h-128v-128zM448 341.333h128v128h-128v-128zM640 341.333h128v128h-128v-128zM379.917 533.333h360.292l-45.625 68.417c-20.076 30.106-58.28 41.459-91.542 27.208l-223.125-95.625zM256 549.875l321.833 137.917c61.245 26.24 133.030 4.94 170-50.5 0-0.006 0-0.014 0-0.021s-0-0.015-0-0.022l0 0.001 20.167-30.25v193c0 29.829-23.505 53.333-53.333 53.333h-405.333c-29.829 0-53.333-23.505-53.333-53.333v-250.125z" + ], + "attrs": [ + {} + ], + "isMulticolor": false, + "isMulticolor2": false, + "grid": 0, + "tags": [ + "choco" + ] + }, + { + "id": 59, + "paths": [ + "M437.333 85.333c-48.994 0-89.478 37.688-94.917 85.333h-75.75c-52.64 0-96 43.36-96 96v576c0 52.64 43.36 96 96 96h490.667c52.64 0 96-43.36 96-96v-576c0-52.64-43.36-96-96-96h-75.75c-5.438-47.645-45.923-85.333-94.917-85.333h-149.333zM437.333 149.333h149.333c18.059 0 32 13.941 32 32s-13.941 32-32 32h-149.333c-18.059 0-32-13.941-32-32s13.941-32 32-32zM266.667 234.667h91.083c17.316 25.641 46.617 42.667 79.583 42.667h149.333c32.966 0 62.267-17.026 79.583-42.667h91.083c18.059 0 32 13.941 32 32v576c0 18.059-13.941 32-32 32h-490.667c-18.059 0-32-13.941-32-32v-576c0-18.059 13.941-32 32-32zM352 426.667c-17.673 0-32 14.327-32 32s14.327 32 32 32v0c17.673 0 32-14.327 32-32s-14.327-32-32-32v0zM480 426.667c-0.135-0.002-0.293-0.003-0.453-0.003-17.675 0-32.003 14.328-32.003 32.003s14.328 32.003 32.003 32.003c0.159 0 0.318-0.001 0.477-0.003l-0.024 0h192c0.135 0.002 0.293 0.003 0.453 0.003 17.675 0 32.003-14.328 32.003-32.003s-14.328-32.003-32.003-32.003c-0.159 0-0.318 0.001-0.477 0.003l0.024-0h-192zM352 554.667c-17.673 0-32 14.327-32 32s14.327 32 32 32v0c17.673 0 32-14.327 32-32s-14.327-32-32-32v0zM480 554.667c-0.135-0.002-0.293-0.003-0.453-0.003-17.675 0-32.003 14.328-32.003 32.003s14.328 32.003 32.003 32.003c0.159 0 0.318-0.001 0.477-0.003l-0.024 0h192c0.135 0.002 0.293 0.003 0.453 0.003 17.675 0 32.003-14.328 32.003-32.003s-14.328-32.003-32.003-32.003c-0.159 0-0.318 0.001-0.477 0.003l0.024-0h-192zM352 682.667c-17.673 0-32 14.327-32 32s14.327 32 32 32v0c17.673 0 32-14.327 32-32s-14.327-32-32-32v0zM480 682.667c-0.135-0.002-0.293-0.003-0.453-0.003-17.675 0-32.003 14.328-32.003 32.003s14.328 32.003 32.003 32.003c0.159 0 0.318-0.001 0.477-0.003l-0.024 0h192c0.135 0.002 0.293 0.003 0.453 0.003 17.675 0 32.003-14.328 32.003-32.003s-14.328-32.003-32.003-32.003c-0.159 0-0.318 0.001-0.477 0.003l0.024-0h-192z" + ], + "attrs": [ + {} + ], + "isMulticolor": false, + "isMulticolor2": false, + "grid": 0, + "tags": [ + "clipboard_list" + ] + }, + { + "id": 58, + "paths": [ + "M512 85.333c-235.263 0-426.667 191.404-426.667 426.667s191.404 426.667 426.667 426.667c235.263 0 426.667-191.404 426.667-426.667s-191.404-426.667-426.667-426.667zM512 149.333c200.674 0 362.667 161.992 362.667 362.667s-161.992 362.667-362.667 362.667c-200.674 0-362.667-161.992-362.667-362.667s161.992-362.667 362.667-362.667zM650.375 340.875c-8.79 0.214-16.67 3.94-22.323 9.823l-0.010 0.011-116.042 116.042-116.042-116.042c-5.822-5.991-13.956-9.708-22.958-9.708l-0-0c-17.672 0.004-31.995 14.331-31.995 32.003 0 9 3.715 17.133 9.696 22.948l0.007 0.007 116.042 116.042-116.042 116.042c-6.068 5.833-9.838 14.019-9.838 23.085 0 17.675 14.328 32.003 32.003 32.003 9.066 0 17.252-3.77 23.075-9.828l0.010-0.011 116.042-116.042 116.042 116.042c5.833 6.068 14.019 9.838 23.085 9.838 17.675 0 32.003-14.328 32.003-32.003 0-9.066-3.77-17.252-9.828-23.075l-0.011-0.010-116.042-116.042 116.042-116.042c6.071-5.833 9.842-14.021 9.842-23.089 0-17.675-14.328-32.003-32.003-32.003-0.266 0-0.531 0.003-0.795 0.010l0.039-0.001z" + ], + "attrs": [ + {} + ], + "isMulticolor": false, + "isMulticolor2": false, + "grid": 0, + "tags": [ + "close_round" + ] + }, + { + "id": 57, + "paths": [ + "M511.542 245.333c-8.669 0.131-16.483 3.688-22.167 9.375l-416 416c-6.068 5.833-9.838 14.019-9.838 23.085 0 17.675 14.328 32.003 32.003 32.003 9.066 0 17.252-3.77 23.075-9.828l0.010-0.011 393.375-393.375 393.375 393.375c5.833 6.068 14.019 9.838 23.085 9.838 17.675 0 32.003-14.328 32.003-32.003 0-9.066-3.77-17.252-9.828-23.075l-0.011-0.010-416-416c-5.792-5.794-13.795-9.378-22.634-9.378-0.158 0-0.315 0.001-0.473 0.003l0.024-0z" + ], + "attrs": [ + {} + ], + "isMulticolor": false, + "isMulticolor2": false, + "grid": 0, + "tags": [ + "collapse" + ] + }, + { + "id": 56, + "paths": [ + "M266.667 128c-76.201 0-138.667 62.465-138.667 138.667v490.667c0 76.201 62.465 138.667 138.667 138.667h490.667c76.201 0 138.667-62.465 138.667-138.667v-490.667c0-76.201-62.465-138.667-138.667-138.667h-490.667zM266.667 192h490.667c41.601 0 74.667 33.065 74.667 74.667v32h-640v-32c0-41.601 33.065-74.667 74.667-74.667zM192 362.667h640v394.667c0 41.601-33.065 74.667-74.667 74.667h-490.667c-41.601 0-74.667-33.065-74.667-74.667v-394.667zM373 469c-17.672 0.004-31.995 14.331-31.995 32.003 0 9 3.715 17.133 9.696 22.948l0.007 0.007 62.708 62.708-62.708 62.708c-6.068 5.833-9.838 14.019-9.838 23.085 0 17.675 14.328 32.003 32.003 32.003 9.066 0 17.252-3.77 23.075-9.828l0.010-0.011 85.333-85.333c5.789-5.791 9.369-13.79 9.369-22.625s-3.58-16.834-9.369-22.625l-85.333-85.333c-5.822-5.991-13.956-9.708-22.958-9.708l-0-0zM544 640c-0.135-0.002-0.293-0.003-0.453-0.003-17.675 0-32.003 14.328-32.003 32.003s14.328 32.003 32.003 32.003c0.159 0 0.318-0.001 0.477-0.003l-0.024 0h128c0.135 0.002 0.293 0.003 0.453 0.003 17.675 0 32.003-14.328 32.003-32.003s-14.328-32.003-32.003-32.003c-0.159 0-0.318 0.001-0.477 0.003l0.024-0h-128z" + ], + "attrs": [ + {} + ], + "isMulticolor": false, + "isMulticolor2": false, + "grid": 0, + "tags": [ + "console" + ] + }, + { + "id": 55, + "paths": [ + "M394.667 106.667c-64.422 0-117.333 52.911-117.333 117.333v469.333c0 64.422 52.911 117.333 117.333 117.333h341.333c64.422 0 117.333-52.911 117.333-117.333v-469.333c0-64.422-52.911-117.333-117.333-117.333h-341.333zM394.667 170.667h341.333c29.829 0 53.333 23.505 53.333 53.333v469.333c0 29.829-23.505 53.333-53.333 53.333h-341.333c-29.829 0-53.333-23.505-53.333-53.333v-469.333c0-29.829 23.505-53.333 53.333-53.333zM234.667 213.333l-26 17.333c-23.744 15.829-38 42.477-38 71v413c0 111.936 90.731 202.667 202.667 202.667h285c28.544 0 55.192-14.256 71-38l17.333-26h-373.333c-76.587 0-138.667-62.080-138.667-138.667v-501.333z" + ], + "attrs": [ + {} + ], + "isMulticolor": false, + "isMulticolor2": false, + "grid": 0, + "tags": [ + "copy" + ] + }, + { + "id": 54, + "paths": [ + "M842.375 148.875c-8.79 0.214-16.67 3.94-22.323 9.823l-0.010 0.011-308.042 308.042-308.042-308.042c-5.822-5.991-13.956-9.708-22.958-9.708l-0-0c-17.672 0.004-31.995 14.331-31.995 32.003 0 9 3.715 17.133 9.696 22.948l0.007 0.007 308.042 308.042-308.042 308.042c-6.068 5.833-9.838 14.019-9.838 23.085 0 17.675 14.328 32.003 32.003 32.003 9.066 0 17.252-3.77 23.075-9.828l0.010-0.011 308.042-308.042 308.042 308.042c5.833 6.068 14.019 9.838 23.085 9.838 17.675 0 32.003-14.328 32.003-32.003 0-9.066-3.77-17.252-9.828-23.075l-0.011-0.010-308.042-308.042 308.042-308.042c6.071-5.834 9.842-14.021 9.842-23.089 0-17.675-14.328-32.003-32.003-32.003-0.266 0-0.531 0.003-0.795 0.010l0.039-0.001z" + ], + "attrs": [ + {} + ], + "isMulticolor": false, + "isMulticolor2": false, + "grid": 0, + "tags": [ + "cross" + ] + }, + { + "id": 53, + "paths": [ + "M512 85.333c-74.844 0-137.165 55.924-147.625 128h-145.958c-1.623-0.292-3.491-0.458-5.398-0.458-0.036 0-0.072 0-0.108 0l0.006-0c-1.706 0.038-3.345 0.203-4.943 0.487l0.193-0.028h-69.5c-0.135-0.002-0.293-0.003-0.453-0.003-17.675 0-32.003 14.328-32.003 32.003s14.328 32.003 32.003 32.003c0.159 0 0.318-0.001 0.477-0.003l-0.024 0h45.625l53.708 555.292c5.783 59.875 56.651 106.042 116.792 106.042h314.375c60.143 0 111.011-46.162 116.792-106.042l53.75-555.292h45.625c0.135 0.002 0.293 0.003 0.453 0.003 17.675 0 32.003-14.328 32.003-32.003s-14.328-32.003-32.003-32.003c-0.159 0-0.318 0.001-0.477 0.003l0.024-0h-69.458c-1.541-0.263-3.315-0.413-5.125-0.413s-3.584 0.15-5.312 0.439l0.187-0.026h-146c-10.46-72.076-72.781-128-147.625-128zM512 149.333c40.089 0 72.976 27.054 82.375 64h-164.75c9.399-36.946 42.286-64 82.375-64zM248.542 277.333h526.875l-53.167 549.125c-2.667 27.629-25.333 48.208-53.083 48.208h-314.375c-27.71 0-50.418-20.616-53.083-48.208l-53.167-549.125zM436.833 383.542c-17.459 0.281-31.503 14.5-31.503 31.999 0 0.161 0.001 0.323 0.004 0.483l-0-0.024v320c-0.002 0.135-0.003 0.293-0.003 0.453 0 17.675 14.328 32.003 32.003 32.003s32.003-14.328 32.003-32.003c0-0.159-0.001-0.318-0.003-0.477l0 0.024v-320c0.002-0.137 0.003-0.298 0.003-0.459 0-17.675-14.328-32.003-32.003-32.003-0.176 0-0.351 0.001-0.527 0.004l0.026-0zM586.167 383.542c-17.459 0.281-31.503 14.5-31.503 31.999 0 0.161 0.001 0.323 0.004 0.483l-0-0.024v320c-0.002 0.135-0.003 0.293-0.003 0.453 0 17.675 14.328 32.003 32.003 32.003s32.003-14.328 32.003-32.003c0-0.159-0.001-0.318-0.003-0.477l0 0.024v-320c0.002-0.137 0.003-0.298 0.003-0.459 0-17.675-14.328-32.003-32.003-32.003-0.176 0-0.351 0.001-0.527 0.004l0.026-0z" + ], + "attrs": [ + {} + ], + "isMulticolor": false, + "isMulticolor2": false, + "grid": 0, + "tags": [ + "delete" + ] + }, + { + "id": 52, + "paths": [ + "M288 85.333c-64.422 0-117.333 52.911-117.333 117.333v618.667c0 64.422 52.911 117.333 117.333 117.333h448c64.422 0 117.333-52.911 117.333-117.333v-618.667c0-64.422-52.911-117.333-117.333-117.333h-448zM288 149.333h448c29.829 0 53.333 23.505 53.333 53.333v618.667c0 29.829-23.505 53.333-53.333 53.333h-448c-29.829 0-53.333-23.505-53.333-53.333v-618.667c0-29.829 23.505-53.333 53.333-53.333zM309.333 192c-17.673 0-32 14.327-32 32s14.327 32 32 32v0c17.673 0 32-14.327 32-32s-14.327-32-32-32v0zM714.667 192c-17.673 0-32 14.327-32 32s14.327 32 32 32v0c17.673 0 32-14.327 32-32s-14.327-32-32-32v0zM512 256c-117.632 0-213.333 95.701-213.333 213.333 0 47.287 15.771 90.77 41.958 126.125l-32.583 32.583c-6.068 5.833-9.838 14.019-9.838 23.085 0 17.675 14.328 32.003 32.003 32.003 9.066 0 17.252-3.77 23.075-9.828l0.010-0.011 181.333-181.333c5.971-5.82 9.675-13.941 9.675-22.927 0-17.675-14.328-32.003-32.003-32.003-0.324 0-0.647 0.005-0.969 0.014l0.047-0.001c-8.646 0.26-16.392 3.91-21.993 9.66l-0.007 0.007-102.833 102.833c-14.93-23.203-23.875-50.611-23.875-80.208 0-82.347 67.008-149.333 149.333-149.333s149.333 66.987 149.333 149.333c0 82.347-67.008 149.333-149.333 149.333-13.547 0-26.624-1.983-39.125-5.375l-49.708 49.708c27.093 12.501 57.089 19.667 88.833 19.667 117.632 0 213.333-95.701 213.333-213.333s-95.701-213.333-213.333-213.333zM309.333 768c-17.673 0-32 14.327-32 32s14.327 32 32 32v0c17.673 0 32-14.327 32-32s-14.327-32-32-32v0zM714.667 768c-17.673 0-32 14.327-32 32s14.327 32 32 32v0c17.673 0 32-14.327 32-32s-14.327-32-32-32v0z" + ], + "attrs": [ + {} + ], + "isMulticolor": false, + "isMulticolor2": false, + "grid": 0, + "tags": [ + "disk" + ] + }, + { + "id": 51, + "paths": [ + "M99.413 476.16c-11.093 0-20.48-3.84-27.733-11.947-7.68-7.68-11.52-17.493-11.52-29.013 0-11.947 3.84-22.187 11.52-29.44 7.68-7.68 17.067-11.52 28.587-11.52s20.907 3.84 28.587 11.52 11.093 17.493 11.093 29.44c0 11.947-3.84 22.187-11.093 29.867s-17.493 11.093-29.44 11.093z", + "M466.347 470.613h-69.547l-126.72-195.84c-3.413-5.973-6.4-11.093-8.96-15.36s-4.267-8.107-5.547-11.093h-0.853c0.427 5.547 0.427 12.373 0.853 20.907 0 8.533 0 18.773 0 30.293v171.093h-65.28v-317.44h74.24l122.027 189.867c2.56 4.267 5.12 8.533 7.68 12.8s4.693 8.533 6.827 12.8h4.267c-2.56-3.84-3.84-9.387-4.267-16.64 0-7.253-0.427-16.213-0.427-27.307v-171.52h65.28v317.44z", + "M716.8 470.613h-184.32v-317.44h177.067v59.307h-107.947v69.12h100.267v58.88h-100.267v70.827h115.2v59.307z", + "M969.813 211.627h-82.347v259.413h-69.547v-259.413h-82.347v-58.453h233.813v58.453z", + "M307.2 619.093h-53.76v155.733h-32v-155.733h-53.76v-25.6h139.52v25.6z", + "M416.427 777.813c-27.307 0-49.92-8.533-66.987-25.173-17.493-17.067-26.027-38.827-26.027-66.133 0-29.013 8.96-52.053 26.453-69.547 17.92-17.493 40.96-26.453 69.547-26.453 26.88 0 49.067 8.533 65.707 25.173s25.173 39.253 25.173 66.56c0 28.587-8.533 51.627-26.027 69.12s-39.68 26.453-67.84 26.453zM416.853 750.933c17.92 0 32.853-5.973 43.52-17.92 11.093-11.947 16.64-28.16 16.64-48.213 0-20.907-5.547-37.12-16.213-49.493-10.667-11.947-24.747-18.347-42.667-18.347-18.347 0-33.28 5.973-44.373 18.347s-17.067 28.587-17.067 48.64c0 20.053 5.547 36.267 16.64 48.213 11.52 12.8 26.027 18.773 43.52 18.773z", + "M623.787 777.813c-27.307 0-49.92-8.533-66.987-25.173-17.067-17.067-26.027-38.827-26.027-66.133 0-29.013 8.96-52.053 26.453-69.547 17.92-17.493 40.96-26.453 69.547-26.453 26.88 0 49.067 8.533 65.707 25.173s25.173 39.253 25.173 66.56c0 28.587-8.96 51.627-26.027 69.12s-40.107 26.453-67.84 26.453zM624.213 750.933c18.347 0 32.853-5.973 43.52-17.92 11.093-11.947 16.64-28.16 16.64-48.213 0-20.907-5.547-37.12-16.213-49.493-10.667-11.947-24.747-18.347-42.667-18.347-18.347 0-33.28 5.973-44.373 18.347s-16.64 28.587-16.64 48.64c0 20.053 5.547 36.267 16.64 48.213 11.093 12.8 25.173 18.773 43.093 18.773z", + "M857.173 774.827h-106.667v-181.333h32v155.307h74.667v26.027z" + ], + "attrs": [ + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {} + ], + "isMulticolor": false, + "isMulticolor2": false, + "grid": 0, + "tags": [ + "dotnet" + ] + }, + { + "id": 50, + "paths": [ + "M511.5 127.542c-17.459 0.281-31.503 14.5-31.503 31.999 0 0.161 0.001 0.323 0.004 0.483l-0-0.024v456.083l-73.375-73.375c-5.822-5.991-13.956-9.708-22.958-9.708l-0-0c-17.672 0.004-31.995 14.331-31.995 32.003 0 9 3.715 17.133 9.696 22.948l0.007 0.007 128 128c5.791 5.789 13.79 9.369 22.625 9.369s16.834-3.58 22.625-9.369l128-128c6.068-5.833 9.838-14.019 9.838-23.085 0-17.675-14.328-32.003-32.003-32.003-9.066 0-17.252 3.77-23.075 9.828l-0.010 0.011-73.375 73.375v-456.083c0.002-0.136 0.003-0.298 0.003-0.459 0-17.675-14.328-32.003-32.003-32.003-0.176 0-0.351 0.001-0.526 0.004l0.026-0zM159.5 660.875c-17.459 0.281-31.503 14.5-31.503 31.999 0 0.161 0.001 0.323 0.004 0.483l-0-0.024v85.333c0 64.422 52.911 117.333 117.333 117.333h533.333c64.422 0 117.333-52.911 117.333-117.333v-85.333c0.002-0.135 0.003-0.293 0.003-0.453 0-17.675-14.328-32.003-32.003-32.003s-32.003 14.328-32.003 32.003c0 0.159 0.001 0.318 0.003 0.477l-0-0.024v85.333c0 29.829-23.505 53.333-53.333 53.333h-533.333c-29.829 0-53.333-23.505-53.333-53.333v-85.333c0.002-0.137 0.003-0.298 0.003-0.459 0-17.675-14.328-32.003-32.003-32.003-0.176 0-0.351 0.001-0.527 0.004l0.026-0z" + ], + "attrs": [ + {} + ], + "isMulticolor": false, + "isMulticolor2": false, + "grid": 0, + "tags": [ + "download" + ] + }, + { + "id": 49, + "paths": [], + "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, + "grid": 0, + "tags": [ + "empty" + ] + }, + { + "id": 48, + "paths": [ + "M927.708 255.542c-8.79 0.214-16.67 3.94-22.323 9.823l-0.010 0.011-393.375 393.375-393.375-393.375c-5.822-5.991-13.956-9.708-22.958-9.708l-0-0c-17.672 0.004-31.995 14.331-31.995 32.003 0 9 3.715 17.133 9.696 22.948l0.007 0.007 416 416c5.791 5.789 13.79 9.369 22.625 9.369s16.834-3.58 22.625-9.369l416-416c6.071-5.833 9.842-14.021 9.842-23.089 0-17.675-14.328-32.003-32.003-32.003-0.266 0-0.531 0.003-0.795 0.010l0.039-0.001z" + ], + "attrs": [ + {} + ], + "isMulticolor": false, + "isMulticolor2": false, + "grid": 0, + "tags": [ + "expand" + ] + }, + { + "id": 47, + "paths": [ + "M352 106.667c-0.135-0.002-0.293-0.003-0.453-0.003-17.675 0-32.003 14.328-32.003 32.003s14.328 32.003 32.003 32.003c0.159 0 0.318-0.001 0.477-0.003l-0.024 0h10.667v251.708c0 19.522-5.972 38.59-17.083 54.625l-200.542 289.667c-0 0.006-0 0.014-0 0.021s0 0.015 0 0.022l-0-0.001c-24.882 35.964-22.396 85.778 8.083 119.375 19.897 21.953 47.733 31.25 74.208 31.25h569.333c26.475 0 54.311-9.297 74.208-31.25 30.48-33.597 32.965-83.41 8.083-119.375 0-0.006 0-0.014 0-0.021s-0-0.015-0-0.022l0 0.001-200.542-289.667c-11.111-16.035-17.083-35.103-17.083-54.625v-251.708h10.667c0.135 0.002 0.293 0.003 0.453 0.003 17.675 0 32.003-14.328 32.003-32.003s-14.328-32.003-32.003-32.003c-0.159 0-0.318 0.001-0.477 0.003l0.024-0h-320zM426.667 170.667h170.667v170.667h-170.667v-170.667zM426.667 405.333h170.667v17.042c0 32.532 9.916 64.324 28.458 91.083l200.542 289.667c8.331 12.073 7.978 28.041-2.833 39.958-0.014 0.014-0.028 0.028-0.041 0.041l-0 0c-5.487 6.058-15.475 10.208-26.792 10.208h-569.333c-11.317 0-21.304-4.149-26.792-10.208-0.014-0.014-0.028-0.028-0.041-0.041l-0-0c-10.811-11.916-11.164-27.885-2.833-39.958v-0.042l200.542-289.625c18.542-26.759 28.458-58.552 28.458-91.083v-17.042zM448 554.667c-23.564 0-42.667 19.103-42.667 42.667s19.103 42.667 42.667 42.667v0c23.564 0 42.667-19.103 42.667-42.667s-19.103-42.667-42.667-42.667v0zM629.333 682.667c-29.455 0-53.333 23.878-53.333 53.333s23.878 53.333 53.333 53.333v0c29.455 0 53.333-23.878 53.333-53.333s-23.878-53.333-53.333-53.333v0z" + ], + "attrs": [ + {} + ], + "isMulticolor": false, + "isMulticolor2": false, + "grid": 0, + "tags": [ + "experimental" + ] + }, + { + "id": 46, + "paths": [ + "M394.333 63.667c-17.672 0.004-31.995 14.331-31.995 32.003 0 9 3.715 17.133 9.696 22.948l0.007 0.007 393.375 393.375-393.375 393.375c-6.068 5.833-9.838 14.019-9.838 23.085 0 17.675 14.328 32.003 32.003 32.003 9.066 0 17.252-3.77 23.075-9.828l0.010-0.011 416-416c5.789-5.791 9.369-13.79 9.369-22.625s-3.58-16.834-9.369-22.625l-416-416c-5.822-5.991-13.956-9.708-22.958-9.708l-0-0z" + ], + "attrs": [ + {} + ], + "isMulticolor": false, + "isMulticolor2": false, + "grid": 0, + "tags": [ + "forward" + ] + }, + { + "id": 45, + "paths": [ + "M512 40.96c-259.906 0-471.040 211.134-471.040 471.040s211.134 471.040 471.040 471.040c259.906 0 471.040-211.134 471.040-471.040s-211.134-471.040-471.040-471.040zM512 81.92c237.769 0 430.080 192.311 430.080 430.080s-192.311 430.080-430.080 430.080c-237.769 0-430.080-192.311-430.080-430.080s192.311-430.080 430.080-430.080zM237.56 266.24c-18.104 0-32.76 14.656-32.76 32.76v118.8c0 18.104 14.676 32.76 32.76 32.76h79.88v-40.96h-59.4c-6.779 0-12.28-5.501-12.28-12.28v-77.84c0-6.779 5.501-12.28 12.28-12.28h77.84c6.779 0 12.28 5.501 12.28 12.28v159.76c0 6.779-5.501 12.28-12.28 12.28h-131.080v40.96h151.56c18.104 0 32.76-14.656 32.76-32.76v-200.72c0-18.104-14.676-32.76-32.76-32.76h-118.8zM452.6 266.24c-18.063 0-32.76 14.697-32.76 32.76v118.8c0 18.063 14.697 32.76 32.76 32.76h118.8c18.063 0 32.76-14.697 32.76-32.76v-118.8c0-18.063-14.697-32.76-32.76-32.76h-118.8zM667.64 266.24c-18.104 0-32.76 14.656-32.76 32.76v118.8c0 18.104 14.676 32.76 32.76 32.76h79.88v-40.96h-59.4c-6.779 0-12.28-5.501-12.28-12.28v-77.84c0-6.779 5.501-12.28 12.28-12.28h77.84c6.779 0 12.28 5.501 12.28 12.28v159.76c0 6.779-5.501 12.28-12.28 12.28h-131.080v40.96h151.56c18.104 0 32.76-14.656 32.76-32.76v-200.72c0-18.104-14.676-32.76-32.76-32.76h-118.8zM473.080 307.2h77.84c6.779 0 12.28 5.501 12.28 12.28v77.84c0 6.779-5.501 12.28-12.28 12.28h-77.84c-6.779 0-12.28-5.501-12.28-12.28v-77.84c0-6.779 5.501-12.28 12.28-12.28zM237.56 573.44c-18.104 0-32.76 14.676-32.76 32.76v118.8c0 18.104 14.676 32.76 32.76 32.76h120.84v-40.96h-100.36c-6.779 0-12.28-5.501-12.28-12.28v-77.84c0-6.779 5.501-12.28 12.28-12.28h100.36v-40.96h-120.84zM421.88 573.44c-18.063 0-32.76 14.697-32.76 32.76v118.8c0 18.063 14.697 32.76 32.76 32.76h118.8c18.063 0 32.76-14.697 32.76-32.76v-118.8c0-18.063-14.697-32.76-32.76-32.76h-118.8zM636.92 573.44c-18.084 0-32.76 14.656-32.76 32.76v151.56h40.96v-131.080c0-6.779 5.501-12.28 12.28-12.28h33.8v143.36h40.96v-131.080c0-6.779 5.501-12.28 12.28-12.28h33.8v143.36h40.96v-184.32h-182.28zM442.36 614.4h77.84c6.779 0 12.28 5.501 12.28 12.28v77.84c0 6.779-5.501 12.28-12.28 12.28h-77.84c-6.779 0-12.28-5.501-12.28-12.28v-77.84c0-6.779 5.501-12.28 12.28-12.28z" + ], + "attrs": [ + {} + ], + "isMulticolor": false, + "isMulticolor2": false, + "grid": 0, + "tags": [ + "gog" + ] + }, + { + "id": 44, + "paths": [ + "M512 85.333c-235.263 0-426.667 191.404-426.667 426.667s191.404 426.667 426.667 426.667c235.263 0 426.667-191.404 426.667-426.667s-191.404-426.667-426.667-426.667zM512 149.333c200.674 0 362.667 161.992 362.667 362.667s-161.992 362.667-362.667 362.667c-200.674 0-362.667-161.992-362.667-362.667s161.992-362.667 362.667-362.667zM512 277.333c-70.312 0-128 57.688-128 128v10.667c-0.002 0.135-0.003 0.293-0.003 0.453 0 17.675 14.328 32.003 32.003 32.003s32.003-14.328 32.003-32.003c0-0.159-0.001-0.318-0.003-0.477l0 0.024v-10.667c0-35.715 28.285-64 64-64s64 28.285 64 64c0 49.939-12.984 56.197-35.75 74.083-11.383 8.943-26.292 19.254-39.042 36.625s-21.208 41.585-21.208 70.625c-0.002 0.135-0.003 0.293-0.003 0.453 0 17.675 14.328 32.003 32.003 32.003s32.003-14.328 32.003-32.003c0-0.159-0.001-0.318-0.003-0.477l0 0.024c0-18.202 3.541-25.596 8.792-32.75s14.341-14.254 26.958-24.167c25.234-19.826 60.25-57.023 60.25-124.417 0-70.312-57.688-128-128-128zM512 682.667c-23.564 0-42.667 19.103-42.667 42.667s19.103 42.667 42.667 42.667v0c23.564 0 42.667-19.103 42.667-42.667s-19.103-42.667-42.667-42.667v0z" + ], + "attrs": [ + {} + ], + "isMulticolor": false, + "isMulticolor2": false, + "grid": 0, + "tags": [ + "help" + ] + }, + { + "id": 43, + "paths": [ + "M512 85.333c-139.431 0-263.442 67.182-341.333 170.917v-74.917c0.002-0.136 0.003-0.298 0.003-0.459 0-17.675-14.328-32.003-32.003-32.003-0.176 0-0.351 0.001-0.526 0.004l0.026-0c-17.459 0.281-31.503 14.5-31.503 31.999 0 0.161 0.001 0.323 0.004 0.483l-0-0.024v149.333c0.002 17.672 14.328 31.998 32 32l149.334 0c0.135 0.002 0.293 0.003 0.453 0.003 17.675 0 32.003-14.328 32.003-32.003s-14.328-32.003-32.003-32.003c-0.159 0-0.318 0.001-0.477 0.003l0.024-0h-69.333c65.9-90.492 172.569-149.333 293.333-149.333 200.668 0 362.667 161.999 362.667 362.667s-161.999 362.667-362.667 362.667c-200.668 0-362.667-161.999-362.667-362.667 0.002-0.135 0.003-0.293 0.003-0.453 0-17.675-14.328-32.003-32.003-32.003s-32.003 14.328-32.003 32.003c0 0.159 0.001 0.318 0.003 0.477l-0-0.024c0 235.258 191.409 426.667 426.667 426.667s426.667-191.409 426.667-426.667c0-235.258-191.409-426.667-426.667-426.667zM500.833 276.875c-17.459 0.281-31.503 14.5-31.503 31.999 0 0.161 0.001 0.323 0.004 0.483l-0-0.024v256c0.002 17.672 14.328 31.998 32 32l170.667 0c0.135 0.002 0.293 0.003 0.453 0.003 17.675 0 32.003-14.328 32.003-32.003s-14.328-32.003-32.003-32.003c-0.159 0-0.318 0.001-0.477 0.003l0.024-0h-138.667v-224c0.002-0.137 0.003-0.298 0.003-0.459 0-17.675-14.328-32.003-32.003-32.003-0.176 0-0.351 0.001-0.527 0.004l0.026-0z" + ], + "attrs": [ + {} + ], + "isMulticolor": false, + "isMulticolor2": false, + "grid": 0, + "tags": [ + "history" + ] + }, + { + "id": 42, + "paths": [ + "M510.958 85.333c-7.135 0.251-13.63 2.8-18.815 6.925l0.065-0.050-303.208 238.875c-38.483 30.328-61 76.671-61 125.667v407.25c0 29.090 24.243 53.333 53.333 53.333h213.333c29.090 0 53.333-24.243 53.333-53.333v-213.333c0-6.294 4.372-10.667 10.667-10.667h106.667c6.294 0 10.667 4.372 10.667 10.667v213.333c0 29.090 24.243 53.333 53.333 53.333h213.333c29.090 0 53.333-24.243 53.333-53.333v-407.25c0-48.995-22.517-95.339-61-125.667l-303.208-238.875c-5.398-4.295-12.315-6.89-19.838-6.89-0.35 0-0.699 0.006-1.046 0.017l0.051-0.001zM512 158.083l283.417 223.292c23.128 18.227 36.583 45.949 36.583 75.375v396.583h-192v-202.667c0-40.852-33.814-74.667-74.667-74.667h-106.667c-40.852 0-74.667 33.814-74.667 74.667v202.667h-192v-396.583c0-29.426 13.456-57.148 36.583-75.375l283.417-223.292z" + ], + "attrs": [ + {} + ], + "isMulticolor": false, + "isMulticolor2": false, + "grid": 0, + "tags": [ + "home" + ] + }, + { + "id": 41, + "paths": [ + "M223.708 170.708c-76.201 0-138.667 62.465-138.667 138.667v405.333c0 76.201 62.465 138.667 138.667 138.667h353.583c0.006 0 0.014 0 0.021 0s0.015-0 0.022-0l-0.001 0c41.476-0.026 81.336-16.182 111.167-45 0.006 0 0.014 0 0.021 0s0.015-0 0.022-0l-0.001 0 211.375-204.333c51.748-50.023 51.748-134.060 0-184.083l-211.375-204.292c-29.833-28.846-69.733-44.958-111.208-44.958h-353.625zM223.708 234.708h353.625c24.914 0 48.797 9.639 66.708 26.958l211.375 204.333c26.332 25.454 26.332 66.588 0 92.042l-211.375 204.292c-17.913 17.305-41.837 27.026-66.75 27.042h-353.583c-41.601 0-74.667-33.065-74.667-74.667v-405.333c0-41.601 33.065-74.667 74.667-74.667zM704 469.333c-23.564 0-42.667 19.103-42.667 42.667s19.103 42.667 42.667 42.667v0c23.564 0 42.667-19.103 42.667-42.667s-19.103-42.667-42.667-42.667v0z" + ], + "attrs": [ + {} + ], + "isMulticolor": false, + "isMulticolor2": false, + "grid": 0, + "tags": [ + "id" + ] + }, + { + "id": 40, + "paths": [ + "M512 85.333c-235.263 0-426.667 191.404-426.667 426.667s191.404 426.667 426.667 426.667c235.263 0 426.667-191.404 426.667-426.667s-191.404-426.667-426.667-426.667zM512 149.333c200.674 0 362.667 161.992 362.667 362.667s-161.992 362.667-362.667 362.667c-200.674 0-362.667-161.992-362.667-362.667s161.992-362.667 362.667-362.667zM512 298.667c-23.564 0-42.667 19.103-42.667 42.667s19.103 42.667 42.667 42.667v0c23.564 0 42.667-19.103 42.667-42.667s-19.103-42.667-42.667-42.667v0zM511.5 447.542c-17.459 0.281-31.503 14.5-31.503 31.999 0 0.161 0.001 0.323 0.004 0.483l-0-0.024v234.667c-0.002 0.135-0.003 0.293-0.003 0.453 0 17.675 14.328 32.003 32.003 32.003s32.003-14.328 32.003-32.003c0-0.159-0.001-0.318-0.003-0.477l0 0.024v-234.667c0.002-0.137 0.003-0.298 0.003-0.459 0-17.675-14.328-32.003-32.003-32.003-0.176 0-0.351 0.001-0.527 0.004l0.026-0z" + ], + "attrs": [ + {} + ], + "isMulticolor": false, + "isMulticolor2": false, + "grid": 0, + "tags": [ + "info_round" + ] + }, + { + "id": 39, + "paths": [ + "M512 85.333c-235.263 0-426.667 191.404-426.667 426.667s191.404 426.667 426.667 426.667c235.263 0 426.667-191.404 426.667-426.667s-191.404-426.667-426.667-426.667zM512 149.333c200.674 0 362.667 161.992 362.667 362.667s-161.992 362.667-362.667 362.667c-200.674 0-362.667-161.992-362.667-362.667s161.992-362.667 362.667-362.667zM671.375 383.708c-8.646 0.26-16.392 3.91-21.993 9.66l-0.007 0.007-190.708 190.708-84.042-84.042c-5.833-6.068-14.019-9.838-23.085-9.838-17.675 0-32.003 14.328-32.003 32.003 0 9.066 3.77 17.252 9.828 23.075l0.011 0.010 106.667 106.667c5.791 5.789 13.79 9.369 22.625 9.369s16.834-3.58 22.625-9.369l213.333-213.333c5.971-5.82 9.675-13.941 9.675-22.927 0-17.675-14.328-32.003-32.003-32.003-0.324 0-0.647 0.005-0.969 0.014l0.047-0.001z" + ], + "attrs": [ + {} + ], + "isMulticolor": false, + "isMulticolor2": false, + "grid": 0, + "tags": [ + "installed" + ] + }, + { + "id": 38, + "paths": [ + "M512 85.333c-235.264 0-426.667 191.403-426.667 426.667s191.403 426.667 426.667 426.667 426.667-191.403 426.667-426.667-191.403-426.667-426.667-426.667zM694.635 438.635l-213.333 213.333c-6.251 6.251-14.443 9.365-22.635 9.365s-16.384-3.115-22.635-9.365l-106.667-106.667c-12.501-12.501-12.501-32.747 0-45.248s32.747-12.501 45.248 0l84.032 84.032 190.699-190.699c12.501-12.501 32.747-12.501 45.248 0s12.523 32.747 0.043 45.248z" + ], + "attrs": [ + {} + ], + "isMulticolor": false, + "isMulticolor2": false, + "grid": 0, + "tags": [ + "installed_filled" + ] + }, + { + "id": 37, + "paths": [ + "M501.333 106.667c-135.117 0-245.333 110.216-245.333 245.333 0 34.792 7.283 68.053 20.417 98.125 4.987 11.584 16.303 19.547 29.48 19.547 17.675 0 32.003-14.328 32.003-32.003 0-4.756-1.037-9.269-2.898-13.326l0.082 0.199c-9.693-22.194-15.083-46.661-15.083-72.542 0-100.531 80.802-181.333 181.333-181.333s181.333 80.802 181.333 181.333c0 12.464-1.251 24.583-3.625 36.292-0.5 2.12-0.787 4.554-0.787 7.054 0 17.675 14.328 32.003 32.003 32.003 15.662 0 28.696-11.25 31.462-26.11l0.031-0.198c3.215-15.854 4.917-32.279 4.917-49.042 0-135.117-110.216-245.333-245.333-245.333zM501.333 256c-52.64 0-96 43.36-96 96v197.542l-18.375-7.583c-77.971-32.082-166.484 22.020-173.5 106.042-0.072 0.807-0.114 1.745-0.114 2.693 0 11.281 5.837 21.198 14.655 26.898l0.126 0.076 197.625 125.917c13.739 8.763 25.483 20.311 34.542 33.875l31.083 46.625c0.006 0 0.014 0 0.021 0s0.015-0 0.022-0l-0.001 0c16.4 24.544 45.967 37.222 75.083 32.083l113.667-20.042c36.716-6.455 66.476-33.788 76.083-69.792-0.035 0.167-0.020 0.111-0.006 0.055l0.048-0.221 50.792-195.208c17.532-65.74-25.416-133.492-92.375-145.667l-117.375-21.333v-111.958c0-52.64-43.36-96-96-96zM501.333 320c18.059 0 32 13.941 32 32v138.667c-0 0.003-0 0.007-0 0.011 0 15.656 11.242 28.686 26.094 31.459l0.198 0.031 143.625 26.083c31.132 5.66 50.151 35.649 42 66.208 0.049-0.144 0.021-0.075-0.007-0.006l-0.077 0.215-50.75 195.167c-3.235 12.125-13.026 21.086-25.333 23.25-0 0.006-0 0.014-0 0.021s0 0.015 0 0.022l-0-0.001-113.708 20.042c-4.249 0.75-8.334-1.009-10.75-4.625l-31.083-46.583c-13.979-20.942-32.136-38.787-53.375-52.333-0.006-0-0.014-0-0.021-0s-0.015 0-0.022 0l0.001-0-177.417-113.125c12.003-31.65 46.115-49.224 79.875-35.333l62.583 25.75c3.596 1.519 7.777 2.402 12.163 2.402 17.668 0 31.993-14.318 32.003-31.984l0-0.001v-245.333c0-18.059 13.941-32 32-32z" + ], + "attrs": [ + {} + ], + "isMulticolor": false, + "isMulticolor2": false, + "grid": 0, + "tags": [ + "interactive" + ] + }, + { + "id": 36, + "paths": [ + "M884.708 106.375c-1.261 0.039-2.455 0.143-3.63 0.312l0.171-0.020h-294.583c-0.135-0.002-0.293-0.003-0.453-0.003-17.675 0-32.003 14.328-32.003 32.003s14.328 32.003 32.003 32.003c0.159 0 0.318-0.001 0.477-0.003l-0.024 0h221.417l-329.375 329.375c-6.068 5.833-9.838 14.019-9.838 23.085 0 17.675 14.328 32.003 32.003 32.003 9.066 0 17.252-3.77 23.075-9.828l0.010-0.011 329.375-329.375v221.417c-0.002 0.135-0.003 0.293-0.003 0.453 0 17.675 14.328 32.003 32.003 32.003s32.003-14.328 32.003-32.003c0-0.159-0.001-0.318-0.003-0.477l0 0.024v-294.625c0.188-1.305 0.296-2.811 0.296-4.343 0-17.675-14.328-32.003-32.003-32.003-0.323 0-0.644 0.005-0.965 0.014l0.047-0.001zM266.667 170.667c-87.989 0-160 72.011-160 160v426.667c0 87.989 72.011 160 160 160h426.667c87.989 0 160-72.011 160-160v-213.333c0.002-0.135 0.003-0.293 0.003-0.453 0-17.675-14.328-32.003-32.003-32.003s-32.003 14.328-32.003 32.003c0 0.159 0.001 0.318 0.003 0.477l-0-0.024v213.333c0 53.408-42.592 96-96 96h-426.667c-53.408 0-96-42.592-96-96v-426.667c0-53.408 42.592-96 96-96h213.333c0.135 0.002 0.293 0.003 0.453 0.003 17.675 0 32.003-14.328 32.003-32.003s-14.328-32.003-32.003-32.003c-0.159 0-0.318 0.001-0.477 0.003l0.024-0h-213.333z" + ], + "attrs": [ + {} + ], + "isMulticolor": false, + "isMulticolor2": false, + "grid": 0, + "tags": [ + "launch" + ] + }, + { + "id": 35, + "paths": [ + "M725.333 85.375c-18.208 0-36.4 2.208-54.875 6.667-13.269 3.179-23.094 14.474-24.417 28.042l-0.875 9c-1.003 10.261-6.895 19.462-15.833 24.625-8.939 5.141-19.864 5.726-29.208 1.417l-8.292-3.75c-12.352-5.611-27.072-2.815-36.458 7.083-25.557 26.88-44.631 59.756-55.042 95.042-3.883 13.077 1.010 27.147 12.125 35.083l7.458 5.333c8.384 6.037 13.417 15.779 13.417 26.083 0 5.461-1.482 10.724-4.042 15.375l4 24.667 30.792-11.667c8.448-3.179 17.289-4.792 26.292-4.792 1.173 0 2.327 0.311 3.5 0.375 2.048-7.787 3.458-15.745 3.458-23.958 0-25.728-10.391-50.248-28.375-68.125 5.12-11.712 11.613-22.862 19.25-33.208 24.448 6.635 50.853 3.364 73.125-9.5s38.348-34.155 44.833-58.667c12.992-1.536 25.362-1.536 38.375 0 6.464 24.512 22.498 45.803 44.792 58.667 22.251 12.885 48.634 16.135 73.125 9.5 7.637 10.325 14.13 21.496 19.25 33.208-17.984 17.899-28.375 42.397-28.375 68.125s10.391 50.248 28.375 68.125c-5.12 11.712-11.613 22.862-19.25 33.208-24.448-6.635-50.853-3.364-73.125 9.5-22.293 12.864-38.348 34.155-44.833 58.667-7.339 0.875-14.457 1.107-21.625 1 3.648 9.6 6.997 19.269 9.792 29.125 3.243 11.456 3.53 23.257 1.375 34.5 15.211-0.597 30.678-2.433 46.208-6.167 13.248-3.179 23.052-14.474 24.375-28.042l0.875-9.042c1.003-10.261 6.895-19.421 15.833-24.583 8.96-5.12 19.886-5.683 29.208-1.417l8.292 3.75c12.352 5.653 27.093 2.837 36.458-7.083 25.557-26.88 44.631-59.756 55.042-95.042 3.883-13.099-1.010-27.169-12.125-35.083l-7.458-5.333c-8.384-6.037-13.417-15.779-13.417-26.083s5.012-20.026 13.375-26.042l7.5-5.375c11.115-7.915 16.008-21.985 12.125-35.083-10.411-35.285-29.484-68.162-55.042-95.042-9.387-9.92-24.128-12.737-36.458-7.083l-8.25 3.75c-9.429 4.267-20.333 3.682-29.25-1.417-8.939-5.163-14.831-14.343-15.833-24.583l-0.875-9.042c-1.323-13.589-11.147-24.863-24.417-28.042-18.475-4.459-36.667-6.667-54.875-6.667zM725.333 234.667c-25.778 0-49.163 10.819-63.917 27.417s-21.417 37.472-21.417 57.917c0 20.444 6.663 41.319 21.417 57.917s38.139 27.417 63.917 27.417c25.778 0 49.163-10.819 63.917-27.417s21.417-37.472 21.417-57.917c0-20.444-6.663-41.319-21.417-57.917s-38.139-27.417-63.917-27.417zM384 298.667c-27.258 0-53.388 3.756-78.125 9.958-12.33 3.171-21.663 13.202-23.766 25.687l-0.026 0.188-5.292 32.375c-2.079 12.673-9.69 23.672-20.792 30.083s-24.379 7.501-36.417 2.958l-30.792-11.667c-3.358-1.307-7.245-2.065-11.309-2.065-9.014 0-17.158 3.727-22.974 9.723l-0.008 0.008c-36.331 37.445-63.499 83.746-78.125 135.375-0.768 2.613-1.211 5.614-1.211 8.719 0 9.966 4.555 18.867 11.697 24.737l0.056 0.044 25.458 20.833c9.901 8.153 15.625 20.231 15.625 33.042 0 12.83-5.744 24.916-15.667 33.042l-25.458 20.833c-7.177 5.914-11.718 14.803-11.718 24.753 0 3.115 0.445 6.126 1.275 8.973l-0.056-0.226c14.644 51.61 41.789 97.925 78.125 135.375 5.821 5.98 13.948 9.69 22.941 9.69 4.064 0 7.951-0.757 11.527-2.139l-0.219 0.074 30.833-11.625c12.003-4.535 25.281-3.466 36.417 2.958 11.119 6.415 18.686 17.391 20.75 30.042l5.292 32.375c2.129 12.673 11.461 22.704 23.57 25.826l0.222 0.049c24.77 6.228 50.909 10 78.167 10s53.388-3.756 78.125-9.958c12.33-3.171 21.663-13.202 23.766-25.687l0.026-0.188 5.292-32.375c2.079-12.673 9.69-23.672 20.792-30.083s24.379-7.501 36.417-2.958l30.792 11.667c3.358 1.307 7.245 2.065 11.309 2.065 9.014 0 17.158-3.727 22.974-9.723l0.008-0.008c36.331-37.445 63.499-83.746 78.125-135.375 0.768-2.613 1.211-5.614 1.211-8.719 0-9.966-4.555-18.867-11.697-24.737l-0.056-0.044-25.458-20.833c-9.901-8.153-15.625-20.231-15.625-33.042 0-12.83 5.744-24.916 15.667-33.042l25.458-20.833c7.177-5.914 11.718-14.803 11.718-24.753 0-3.115-0.445-6.126-1.275-8.973l0.056 0.226c-14.647-51.679-41.973-97.897-78.208-135.292-5.824-6.005-13.968-9.732-22.982-9.732-4.064 0-7.951 0.758-11.528 2.139l0.219-0.074-30.708 11.583c-12.003 4.535-25.322 3.466-36.458-2.958-11.119-6.415-18.686-17.391-20.75-30.042l-5.375-32.708c-2.122-12.663-11.437-22.69-23.528-25.826l-0.222-0.049c-24.965-6.277-51.144-9.667-78.083-9.667zM725.333 298.667c9.778 0 13.059 2.514 16.083 5.917s5.25 9.194 5.25 15.417c0 6.222-2.226 12.014-5.25 15.417s-6.306 5.917-16.083 5.917c-9.778 0-13.059-2.514-16.083-5.917s-5.25-9.194-5.25-15.417c0-6.222 2.226-12.014 5.25-15.417s6.306-5.917 16.083-5.917zM384 362.667c14.694 0 28.544 2.901 42.542 5.292l1.5 9.292c5.156 31.535 24.262 59.188 51.958 75.167 27.691 15.975 61.146 18.67 91.042 7.375l8.542-3.208c18.187 21.936 32.526 46.622 42.625 73.75l-7.083 5.792c-0.006-0-0.014-0-0.021-0s-0.015 0-0.022 0l0.001-0c-24.722 20.247-39.083 50.572-39.083 82.542s14.368 62.28 39.042 82.542c0.014 0.014 0.028 0.028 0.041 0.041l0 0 7.125 5.833c-10.082 27.152-24.396 51.852-42.542 73.75l-8.625-3.292c-29.904-11.286-63.401-8.571-91.083 7.417s-46.743 43.595-51.917 75.125c-0 0.006-0 0.014-0 0.021s0 0.015 0 0.022l-0-0.001-1.5 9.083c-14.055 2.474-27.998 5.458-42.542 5.458-14.558 0-28.516-2.973-42.583-5.458l-1.5-9.083v-0.042c-5.156-31.534-24.22-59.188-51.917-75.167-27.691-15.975-61.146-18.67-91.042-7.375l-8.667 3.25c-18.141-21.902-32.455-46.582-42.542-73.75l7.125-5.833c0.006 0 0.014 0 0.021 0s0.015-0 0.022-0l-0.001 0c24.723-20.247 39.083-50.572 39.083-82.542s-14.368-62.28-39.042-82.542c-0.014-0.014-0.028-0.028-0.041-0.041l-0-0-7.125-5.833c10.082-27.152 24.396-51.852 42.542-73.75l8.625 3.292c29.904 11.286 63.401 8.571 91.083-7.417s46.743-43.595 51.917-75.125c0-0.006 0-0.014 0-0.021s-0-0.015-0-0.022l0 0.001 1.5-9.083c14.054-2.475 27.998-5.458 42.542-5.458zM384 490.667c-40 0-74.052 16.152-95.917 40.75s-32.083 56.139-32.083 87.25c0 31.111 10.219 62.652 32.083 87.25s55.917 40.75 95.917 40.75c40 0 74.052-16.152 95.917-40.75s32.083-56.139 32.083-87.25c0-31.111-10.219-62.652-32.083-87.25s-55.917-40.75-95.917-40.75zM384 554.667c24 0 37.948 7.848 48.083 19.25s15.917 27.861 15.917 44.75c0 16.889-5.781 33.348-15.917 44.75s-24.083 19.25-48.083 19.25c-24 0-37.948-7.848-48.083-19.25s-15.917-27.861-15.917-44.75c0-16.889 5.781-33.348 15.917-44.75s24.083-19.25 48.083-19.25z" + ], + "attrs": [ + {} + ], + "isMulticolor": false, + "isMulticolor2": false, + "grid": 0, + "tags": [ + "loading" + ] + }, + { + "id": 34, + "paths": [ + "M725.333 85.375c-18.208 0-36.4 2.208-54.875 6.667-13.269 3.179-23.094 14.474-24.417 28.042l-0.875 9c-1.003 10.261-6.895 19.462-15.833 24.625-8.939 5.141-19.864 5.726-29.208 1.417l-8.292-3.75c-12.352-5.611-27.072-2.815-36.458 7.083-25.557 26.88-44.631 59.756-55.042 95.042-3.883 13.077 1.010 27.147 12.125 35.083l7.458 5.333c8.384 6.037 13.417 15.779 13.417 26.083s-5.012 20.026-13.375 26.042l-7.5 5.375c-0.683 0.491-1.11 1.175-1.75 1.708l1.542 10.125c1.003 6.528 4.658 11.943 10.375 15.25 3.307 1.899 6.997 2.917 10.667 2.917 2.603 0 5.21-0.518 7.792-1.542l36.708-14.333c8.683-3.371 17.782-5.083 27.083-5.083 22.272 0 43.23 9.829 57.417 26.917 26.261 31.573 46.852 67.137 61.167 105.75 7.616 20.565 5.524 42.735-4.375 61.167 2.091 0.064 4.202 0.375 6.25 0.375 17.963 0 36.442-2.25 54.917-6.708 13.248-3.179 23.052-14.432 24.375-28l0.875-9.042c1.003-10.261 6.895-19.462 15.833-24.625 8.96-5.12 19.886-5.683 29.208-1.417l8.292 3.792c12.352 5.653 27.093 2.837 36.458-7.083 25.557-26.88 44.631-59.756 55.042-95.042 3.883-13.12-1.010-27.21-12.125-35.125l-7.458-5.333c-8.384-6.037-13.417-15.779-13.417-26.083s5.012-20.026 13.375-26.042l7.5-5.375c11.115-7.915 16.008-21.985 12.125-35.083-10.411-35.285-29.484-68.162-55.042-95.042-9.387-9.92-24.128-12.737-36.458-7.083l-8.25 3.75c-9.429 4.267-20.333 3.682-29.25-1.417-8.939-5.163-14.831-14.343-15.833-24.583l-0.875-9.042c-1.323-13.589-11.147-24.863-24.417-28.042-18.475-4.459-36.667-6.667-54.875-6.667zM725.333 256c35.349 0 64 28.651 64 64s-28.651 64-64 64c-35.349 0-64-28.651-64-64s28.651-64 64-64zM381.917 298.583c-17.229 0.053-33.762 1.81-51.917 5.042-13.504 2.368-24.014 13.099-26.083 26.667l-6 39.375c-2.923 19.307-14.311 36-31.25 45.792-16.896 9.771-37.052 11.355-55.292 4.208l-36.75-14.375c-12.821-4.971-27.439-1.269-36.25 9.333-23.125 27.819-41.267 59.22-53.875 93.375-4.779 12.928-0.732 27.465 10.042 36.083l30.792 24.625c15.253 12.181 24 30.396 24 49.958s-8.747 37.777-24 49.958l-30.792 24.625c-10.773 8.619-14.799 23.155-10.042 36.083 12.629 34.155 30.75 65.556 53.875 93.375 8.811 10.603 23.471 14.368 36.25 9.333l36.75-14.375c18.219-7.125 38.396-5.541 55.292 4.208 16.939 9.792 28.348 26.464 31.292 45.792l5.958 39.375c2.069 13.568 12.579 24.299 26.083 26.667 18.709 3.349 36.357 4.958 54 4.958s35.291-1.589 54-4.917c13.504-2.368 24.014-13.14 26.083-26.708l5.958-39.375h0.042c2.923-19.307 14.311-36 31.25-45.792 16.939-9.749 37.094-11.292 55.292-4.167l36.75 14.375c12.821 4.992 27.439 1.228 36.25-9.375 23.125-27.819 41.267-59.179 53.875-93.333 4.779-12.949 0.732-27.506-10.042-36.125l-30.792-24.625c-15.253-12.181-24-30.396-24-49.958s8.767-37.797 24.042-50l30.75-24.583c10.773-8.597 14.779-23.197 10-36.125-12.629-34.048-30.769-65.409-53.958-93.292-8.811-10.603-23.45-14.346-36.25-9.375l-36.625 14.333c-18.197 7.147-38.353 5.604-55.292-4.167-16.939-9.792-28.348-26.464-31.292-45.792l-5.958-39.208c-2.069-13.632-12.64-24.383-26.208-26.708-20.811-3.573-38.729-5.22-55.958-5.167zM384 512c58.901 0 106.667 47.765 106.667 106.667s-47.765 106.667-106.667 106.667c-58.901 0-106.667-47.765-106.667-106.667s47.765-106.667 106.667-106.667z" + ], + "attrs": [ + {} + ], + "isMulticolor": false, + "isMulticolor2": false, + "grid": 0, + "tags": [ + "loading_filled" + ] + }, + { + "id": 33, + "paths": [ + "M202.667 128c-52.64 0-96 43.36-96 96v576c0 52.64 43.36 96 96 96h234.667c52.64 0 96-43.36 96-96v-576c0-52.64-43.36-96-96-96h-234.667zM537.167 128c16.896 17.557 29.134 39.531 34.958 64h249.208c17.643 0 32 14.357 32 32v405.333c0 17.643-14.357 32-32 32h-165.417c-1.626-0.293-3.497-0.46-5.408-0.46-0.12 0-0.241 0.001-0.361 0.002l0.018-0c-1.681 0.042-3.29 0.207-4.86 0.487l0.193-0.029h-69.5v64h42.667v106.667h-46.542c-5.824 24.469-18.062 46.443-34.958 64h108.25c1.559 0.269 3.356 0.423 5.187 0.423s3.628-0.154 5.376-0.45l-0.188 0.026h80.208c17.685 0 32-14.315 32-32s-14.315-32-32-32h-53.333v-106.667h138.667c52.928 0 96-43.072 96-96v-405.333c0-52.928-43.072-96-96-96h-284.167zM202.667 192h234.667c18.059 0 32 13.941 32 32v576c0 18.059-13.941 32-32 32h-234.667c-18.059 0-32-13.941-32-32v-576c0-18.059 13.941-32 32-32zM245.333 234.667c-17.672 0.002-31.998 14.328-32 32l-0 0v101.417c-0.269 1.559-0.423 3.356-0.423 5.187s0.154 3.628 0.45 5.376l-0.026-0.188v101.542c0.002 17.672 14.328 31.998 32 32l149.334 0c17.672-0.002 31.998-14.328 32-32l0-0v-101.417c0.269-1.559 0.423-3.356 0.423-5.187s-0.154-3.628-0.45-5.376l0.026 0.188v-101.542c-0.002-17.672-14.328-31.998-32-32l-149.334-0zM277.333 298.667h85.333v42.667h-85.333v-42.667zM277.333 405.333h85.333v42.667h-85.333v-42.667zM320 661.333c-23.564 0-42.667 19.103-42.667 42.667s19.103 42.667 42.667 42.667v0c23.564 0 42.667-19.103 42.667-42.667s-19.103-42.667-42.667-42.667v0z" + ], + "attrs": [ + {} + ], + "isMulticolor": false, + "isMulticolor2": false, + "grid": 0, + "tags": [ + "local_pc" + ] + }, + { + "id": 32, + "paths": [ + "M838.042 171.292c-7.52 0.333-15.119 1.58-22.708 3.833l-661.375 196.583c-40.553 12.083-68.625 49.687-68.625 92.042v96.5c0 42.355 28.072 79.959 68.625 92.042l106.583 31.667c-9.435 80.839 37.186 159.888 117.75 183.708 80.389 23.745 162.299-17.028 198.458-89.708l238.542 70.917c60.715 18.060 123.375-28.648 123.375-92v-489.75c0-47.506-35.229-85.664-78.458-94.167-7.205-1.417-14.646-1.999-22.167-1.667zM841.417 235.042c18.080-1.116 33.25 12.616 33.25 32.083v489.75c0 22.28-19.792 37.012-41.125 30.667l-661.333-196.625c-13.686-4.105-22.875-16.381-22.875-30.667v-96.5c0-14.286 9.189-26.562 22.875-30.667l661.333-196.625c2.667-0.792 5.292-1.257 7.875-1.417zM321.792 702.167l193.708 57.583c-24.748 39.658-71.848 60.494-119.083 46.542-47.337-13.996-75.551-57.265-74.625-104.125z" + ], + "attrs": [ + {} + ], + "isMulticolor": false, + "isMulticolor2": false, + "grid": 0, + "tags": [ + "megaphone" + ] + }, + { + "id": 31, + "paths": [ + "M490.667 42.667c-98.447 0-180.060 74.967-190.75 170.667h-43.917c-49.323 0-90.38 36.975-95.5 86.042l-53.333 512c-2.816 26.987 5.991 54.047 24.167 74.25 18.176 20.16 44.197 31.708 71.333 31.708h618.667c27.136 0 53.157-11.548 71.333-31.708 18.176-20.181 26.941-47.263 24.125-74.25l-53.292-512c-5.12-49.067-46.177-86.042-95.5-86.042h-43.667c0.661 7.040 1 14.165 1 21.333v42.667h42.667c16.448 0 30.127 12.346 31.833 28.708l53.333 512c0.939 9.003-2.004 18.010-8.042 24.708-6.059 6.72-14.746 10.583-23.792 10.583h-618.667c-9.045 0-17.713-3.843-23.75-10.542-6.059-6.72-9.022-15.747-8.083-24.75l53.333-512c1.707-16.363 15.385-28.708 31.833-28.708h42.667v74.667c-0.002 0.135-0.003 0.293-0.003 0.453 0 17.675 14.328 32.003 32.003 32.003s32.003-14.328 32.003-32.003c0-0.159-0.001-0.318-0.003-0.477l0 0.024v-117.333c0-71.067 56.933-128 128-128 63.782 0 116.052 45.89 126.125 106.667h-208.625c-1.792 6.827-2.833 13.952-2.833 21.333v42.667h213.333v74.667c-0.002 0.135-0.003 0.293-0.003 0.453 0 17.675 14.328 32.003 32.003 32.003s32.003-14.328 32.003-32.003c0-0.159-0.001-0.318-0.003-0.477l0 0.024v-117.333c0-105.658-86.342-192-192-192z" + ], + "attrs": [ + {} + ], + "isMulticolor": false, + "isMulticolor2": false, + "grid": 0, + "tags": [ + "ms_store" + ] + }, + { + "id": 30, + "paths": [ + "M0 320v352h288v64h224v-64h512v-352h-1024zM56.875 376.875h227.625v245.375h-56.938v-188.437h-56.875v188.437h-113.812v-245.375zM341.375 376.875h227.562v245.312h-113.813v56.938h-113.75v-302.25zM625.813 376.875h341.375v245.375h-56.938v-188.437h-56.875v188.437h-56.875v-188.437h-56.938v188.437h-113.75v-245.375zM455.125 433.813v131.562h56.875v-131.562h-56.875z" + ], + "attrs": [ + {} + ], + "isMulticolor": false, + "isMulticolor2": false, + "grid": 0, + "tags": [ + "node" + ] + }, + { + "id": 29, + "paths": [ + "M181.333 170.667c-52.64 0-96 43.36-96 96v510h0.333c-0.621 39.908 31.846 76.667 74.375 76.667h619.625c39.893 0 75.859-24.896 89.875-62.25l106.833-284.5c18.261-47.881-18.491-101.25-69.75-101.25h-10.625v-32c0-52.64-43.36-96-96-96h-287.083l-95.333-79.458c-0.006-0-0.014-0-0.021-0s-0.015 0-0.022 0l0.001-0c-21.081-17.563-47.64-27.208-75.083-27.208h-161.125zM181.333 234.667h161.125c12.492 0 24.53 4.381 34.125 12.375l104.25 86.875c5.508 4.614 12.67 7.417 20.487 7.417 0.005 0 0.009-0 0.014-0l298.666 0c18.059 0 32 13.941 32 32v32h-545c-39.893 0-75.859 24.896-89.875 62.25l-47.792 127.25v-328.167c0-18.059 13.941-32 32-32zM287 469.333h619.625c8.53 0 13 6.51 9.958 14.458 0.049-0.144 0.021-0.075-0.007-0.006l-0.077 0.215-106.875 284.583c-4.715 12.566-16.518 20.75-29.958 20.75h-619.625c-8.485 0-12.979-6.462-10-14.375 0.014-0.014 0.028-0.028 0.041-0.041l0-0 106.958-284.833c4.715-12.566 16.518-20.75 29.958-20.75z" + ], + "attrs": [ + {} + ], + "isMulticolor": false, + "isMulticolor2": false, + "grid": 0, + "tags": [ + "open_folder" + ] + }, + { + "id": 28, + "paths": [ + "M85.333 780.8c0 17.067 12.8 29.867 34.133 29.867h422.4c4.267 21.333 17.067 42.667 29.867 55.467 21.333 21.333 51.2 29.867 81.067 29.867s55.467-8.533 81.067-29.867c17.067-12.8 25.6-34.133 29.867-55.467h145.067c17.067 0 34.133-12.8 34.133-29.867s-12.8-34.133-29.867-34.133c0 0 0 0 0 0h-145.067c-4.267-21.333-17.067-42.667-29.867-55.467-21.333-21.333-51.2-29.867-81.067-29.867s-55.467 8.533-81.067 29.867c-17.067 12.8-25.6 34.133-29.867 55.467h-426.667c-21.333 0-34.133 12.8-34.133 34.133 0-4.267 0 0 0 0zM85.333 512c0 17.067 12.8 29.867 34.133 29.867h102.4c4.267 21.333 17.067 42.667 29.867 55.467 21.333 21.333 51.2 29.867 81.067 29.867s55.467-8.533 81.067-29.867c17.067-12.8 25.6-34.133 29.867-55.467h465.067c17.067 0 34.133-12.8 34.133-29.867s-12.8-34.133-29.867-34.133c0 0 0 0 0 0h-473.6c-4.267-21.333-17.067-42.667-29.867-55.467-21.333-17.067-51.2-29.867-76.8-29.867s-59.733 12.8-81.067 29.867c-17.067 12.8-25.6 34.133-29.867 55.467h-102.4c-21.333-0-34.133 17.067-34.133 34.133 0 0 0 0 0 0zM85.333 247.467c0 17.067 12.8 29.867 34.133 29.867h465.067c4.267 21.333 17.067 42.667 29.867 55.467 21.333 21.333 51.2 29.867 81.067 29.867s55.467-8.533 81.067-29.867c17.067-12.8 25.6-34.133 29.867-55.467h102.4c17.067 0 34.133-12.8 34.133-29.867s-17.067-34.133-34.133-34.133c0 0 0 0 0 0h-102.4c-4.267-21.333-17.067-42.667-29.867-55.467-25.6-21.333-55.467-29.867-81.067-29.867s-55.467 8.533-81.067 29.867c-17.067 12.8-25.6 34.133-29.867 55.467h-465.067c-21.333 0-34.133 12.8-34.133 34.133 0-4.267 0 0 0 0zM277.333 512c0 0 0 0 0 0 0-21.333 8.533-34.133 17.067-42.667s21.333-12.8 38.4-12.8c12.8 0 29.867 4.267 38.4 12.8s12.8 21.333 12.8 42.667-8.533 29.867-17.067 38.4-21.333 12.8-38.4 12.8c-12.8 0-29.867-4.267-38.4-12.8-4.267-4.267-12.8-17.067-12.8-38.4zM597.333 780.8c0 0 0-4.267 0 0 0-21.333 8.533-34.133 17.067-42.667s21.333-12.8 38.4-12.8 29.867 4.267 38.4 12.8c8.533 8.533 17.067 17.067 17.067 38.4 0 0 0 4.267 0 4.267 0 17.067-8.533 29.867-17.067 38.4s-21.333 12.8-38.4 12.8-29.867-4.267-38.4-12.8c-8.533-8.533-17.067-21.333-17.067-38.4zM640 247.467c0 0 0-4.267 0 0 0-21.333 8.533-34.133 17.067-42.667s21.333-12.8 38.4-12.8 29.867 4.267 38.4 12.8c8.533 8.533 17.067 17.067 17.067 38.4 0 0 0 4.267 0 4.267 0 17.067-8.533 29.867-17.067 38.4-12.8 8.533-25.6 12.8-38.4 12.8s-29.867-4.267-38.4-12.8c-8.533-8.533-17.067-21.333-17.067-38.4z" + ], + "attrs": [ + {} + ], + "isMulticolor": false, + "isMulticolor2": false, + "grid": 0, + "tags": [ + "options" + ] + }, + { + "id": 27, + "paths": [ + "M296.625 128c-28.455 0-55.512 12.656-73.75 34.542l-72.625 87.167c-0.006-0-0.014-0-0.021-0s-0.015 0-0.022 0l0.001-0c-14.336 17.242-22.208 39.007-22.208 61.458v467.5c0 64.422 52.911 117.333 117.333 117.333h533.333c64.422 0 117.333-52.911 117.333-117.333v-467.5c0-22.452-7.879-44.207-22.25-61.458l-72.625-87.167c-18.238-21.886-45.295-34.542-73.75-34.542h-430.75zM296.625 192h183.375v85.333h-269.5l61.542-73.833c6.082-7.298 15.065-11.5 24.583-11.5zM544 192h183.375c9.519 0 18.502 4.202 24.583 11.5l61.5 73.833h-269.458v-85.333zM192 341.333h640v437.333c0 29.829-23.505 53.333-53.333 53.333h-533.333c-29.829 0-53.333-23.505-53.333-53.333v-437.333zM416 426.667c-0.135-0.002-0.293-0.003-0.453-0.003-17.675 0-32.003 14.328-32.003 32.003s14.328 32.003 32.003 32.003c0.159 0 0.318-0.001 0.477-0.003l-0.024 0h192c0.135 0.002 0.293 0.003 0.453 0.003 17.675 0 32.003-14.328 32.003-32.003s-14.328-32.003-32.003-32.003c-0.159 0-0.318 0.001-0.477 0.003l0.024-0h-192z" + ], + "attrs": [ + {} + ], + "isMulticolor": false, + "isMulticolor2": false, + "grid": 0, + "tags": [ + "package" + ] + }, + { + "id": 26, + "paths": [ + "M405.25 107.167c-25.032-0.622-50.381 8.256-69.667 27.542l-200.875 200.833c-0 0.006-0 0.014-0 0.021s0 0.015 0 0.022l-0-0.001c-44.068 44.1-33.887 119.949 20.25 150.875l215.458 123.167 80.917 202.25c4.85 11.888 16.321 20.114 29.713 20.114 8.833 0 16.83-3.578 22.621-9.364l136.875-136.833 222.167 222.167c5.833 6.068 14.019 9.838 23.085 9.838 17.675 0 32.003-14.328 32.003-32.003 0-9.066-3.77-17.252-9.828-23.075l-0.011-0.010-222.167-222.167 136.875-136.875c5.786-5.791 9.364-13.788 9.364-22.62 0-13.392-8.226-24.863-19.901-29.636l-0.214-0.077-202.292-80.917-123.125-215.458c0-0.006 0-0.014 0-0.021s-0-0.015-0-0.022l0 0.001c-15.475-27.061-42.194-43.121-70.542-46.917-3.543-0.474-7.132-0.745-10.708-0.833zM400.583 170.333c2.34-0.235 4.688-0.185 7 0.125 9.247 1.239 17.923 6.788 23.333 16.25l128.708 225.167c3.61 6.243 9.088 11.061 15.662 13.756l0.213 0.077 167.583 67-250.375 250.375-67-167.583c-2.764-6.803-7.585-12.296-13.68-15.835l-0.153-0.082-225.167-128.667c-18.895-10.794-22.081-34.662-6.708-50.083v-0.042l200.833-200.792c5.773-5.773 12.73-8.961 19.75-9.667z" + ], + "attrs": [ + {} + ], + "isMulticolor": false, + "isMulticolor2": false, + "grid": 0, + "tags": [ + "pin" + ] + }, + { + "id": 25, + "paths": [ + "M404.917 106.667c-25.845-0.491-50.704 9.394-69.333 28.042l-200.875 200.875c-21.291 21.291-31.219 50.613-27.208 80.458 4.011 29.824 21.325 55.483 47.458 70.417l215.458 123.167 80.917 202.25c4.011 9.984 12.711 17.304 23.25 19.458 2.155 0.448 4.304 0.667 6.458 0.667 8.384 0 16.566-3.316 22.625-9.375l136.833-136.875 222.208 222.208c5.833 6.068 14.019 9.838 23.085 9.838 17.675 0 32.003-14.328 32.003-32.003 0-9.066-3.77-17.252-9.828-23.075l-0.011-0.010-222.208-222.208 136.875-136.833c7.595-7.595 10.863-18.545 8.708-29.083s-9.453-19.261-19.458-23.25l-202.292-80.917-123.083-215.458c-14.933-26.133-40.613-43.448-70.458-47.458-3.717-0.499-7.433-0.763-11.125-0.833z" + ], + "attrs": [ + {} + ], + "isMulticolor": false, + "isMulticolor2": false, + "grid": 0, + "tags": [ + "pin_filled" + ] + }, + { + "id": 24, + "paths": [ + "M258.188 160c-15.034 0-31.819 2.259-45.875 13.688s-19.727 27.275-23 42.125c-41.089 187.619-82.163 375.256-123.188 562.875v0.063c-4.306 19.872-2.316 41.579 10.188 58.875 12.503 17.295 34.379 26.375 55.688 26.375h636c16.463 0 34.337-5.76 46.313-17.562s17.043-26.126 20-39.625v-0.062c41.25-188.518 82.41-377.071 123.5-565.625 4.209-19.318 2.827-41.304-10.75-58.187s-34.754-22.938-54.375-22.938h-634.5zM258.188 224h634.5c2.020 0 2.114 0.138 3.063 0.25-0.091 0.984 0.017 1.167-0.438 3.25-41.086 188.534-82.316 377.12-123.562 565.625l0.062-0.062c-1.364 6.227-2.515 7.277-2.188 7-0.38-0.020-0.234-0.062-1.625-0.062h-636c-6.020 0-4.38-0.659-3.812 0.125 0.563 0.778-1.019-0.884 0.437-7.75v-0.062c41.019-187.591 82.105-375.157 123.188-562.75 0.711-3.227 1.167-4.17 1.563-5.25 1.060-0.129 1.82-0.312 4.812-0.312zM369.062 255.5c-0.452-0.015-0.983-0.024-1.516-0.024-26.512 0-48.005 21.492-48.005 48.005 0 12.954 5.131 24.71 13.472 33.346l-0.013-0.014 155 165.437-244.375 179.063c-12.707 8.765-20.93 23.243-20.93 39.641 0 26.512 21.492 48.005 48.005 48.005 11.248 0 21.592-3.868 29.775-10.347l-0.1 0.077 288-211c11.955-8.836 19.622-22.88 19.622-38.715 0-12.719-4.946-24.283-13.021-32.872l0.023 0.025-192-204.937c-8.466-9.288-20.466-15.229-33.857-15.685l-0.080-0.002zM496 672c-0.202-0.003-0.44-0.005-0.679-0.005-26.512 0-48.005 21.492-48.005 48.005s21.492 48.005 48.005 48.005c0.239 0 0.477-0.002 0.715-0.005l-0.036 0h128c0.202 0.003 0.44 0.005 0.679 0.005 26.512 0 48.005-21.492 48.005-48.005s-21.492-48.005-48.005-48.005c-0.239 0-0.477 0.002-0.715 0.005l0.036-0h-128z" + ], + "attrs": [ + {} + ], + "isMulticolor": false, + "isMulticolor2": false, + "grid": 0, + "tags": [ + "powershell" + ] + }, + { + "id": 23, + "paths": [ + "M512 64c-79.543 0-122.874 20.204-153.75 33.583h-0.042c-27.783 12.115-44.507 37.217-51.75 60.917s-7.792 47.381-7.792 68.5v71.667h-71.667c-21.119 0-44.801 0.548-68.5 7.792s-48.801 23.966-60.917 51.75v0.042c-13.379 30.875-33.583 74.207-33.583 153.75s20.204 122.874 33.583 153.75v0.042c12.115 27.784 37.217 44.507 60.917 51.75 23.699 7.242 47.381 7.792 68.5 7.792h71.667v71.667c0 21.119 0.548 44.801 7.792 68.5s23.966 48.801 51.75 60.917h0.042c30.875 13.379 74.207 33.583 153.75 33.583s122.874-20.204 153.75-33.583h0.042c27.784-12.115 44.507-37.217 51.75-60.917 7.242-23.699 7.792-47.381 7.792-68.5v-71.667h71.667c21.119 0 44.801-0.548 68.5-7.792s48.801-23.966 60.917-51.75v-0.042c13.379-30.875 33.583-74.207 33.583-153.75s-20.204-122.874-33.583-153.75v-0.042c-12.115-27.783-37.217-44.507-60.917-51.75s-47.381-7.792-68.5-7.792h-71.667v-71.667c0-21.119-0.548-44.801-7.792-68.5s-23.966-48.801-51.75-60.917h-0.042c-30.875-13.379-74.207-33.583-153.75-33.583zM512 128c69.731 0 95.126 13.909 128.208 28.25 8.909 3.885 12.382 8.711 16.125 20.958s5 30.591 5 49.792v98.417c-0.269 1.559-0.423 3.356-0.423 5.187s0.154 3.628 0.45 5.376l-0.026-0.188v69.542c0 41.601-33.065 74.667-74.667 74.667h-149.333c-76.201 0-138.667 62.465-138.667 138.667v42.667h-71.667c-19.201 0-37.544-1.257-49.792-5s-17.074-7.216-20.958-16.125c-14.341-33.083-28.25-58.478-28.25-128.208s13.909-95.126 28.25-128.208c3.885-8.909 8.711-12.382 20.958-16.125s30.591-5 49.792-5h274.333c0.135 0.002 0.293 0.003 0.453 0.003 17.675 0 32.003-14.328 32.003-32.003s-14.328-32.003-32.003-32.003c-0.159 0-0.318 0.001-0.477 0.003l0.024-0h-138.667v-71.667c0-19.201 1.257-37.544 5-49.792s7.216-17.074 16.125-20.958c33.083-14.341 58.478-28.25 128.208-28.25zM437.333 192c-17.673 0-32 14.327-32 32s14.327 32 32 32v0c17.673 0 32-14.327 32-32s-14.327-32-32-32v0zM725.333 362.667h71.667c19.201 0 37.544 1.257 49.792 5s17.074 7.216 20.958 16.125c14.341 33.083 28.25 58.478 28.25 128.208s-13.909 95.126-28.25 128.208c-3.885 8.909-8.711 12.382-20.958 16.125s-30.591 5-49.792 5h-274.333c-0.135-0.002-0.293-0.003-0.453-0.003-17.675 0-32.003 14.328-32.003 32.003s14.328 32.003 32.003 32.003c0.159 0 0.318-0.001 0.477-0.003l-0.024 0h138.667v71.667c0 19.201-1.257 37.544-5 49.792s-7.216 17.074-16.125 20.958c-33.083 14.341-58.478 28.25-128.208 28.25s-95.126-13.909-128.208-28.25c-8.909-3.885-12.382-8.711-16.125-20.958s-5-30.591-5-49.792v-178.333c0-41.601 33.065-74.667 74.667-74.667h149.333c76.201 0 138.667-62.465 138.667-138.667v-42.667zM586.667 768c-17.673 0-32 14.327-32 32s14.327 32 32 32v0c17.673 0 32-14.327 32-32s-14.327-32-32-32v0z" + ], + "attrs": [ + {} + ], + "isMulticolor": false, + "isMulticolor2": false, + "grid": 0, + "tags": [ + "python" + ] + }, + { + "id": 22, + "paths": [ + "M799.5 127.542c-17.459 0.281-31.503 14.5-31.503 31.999 0 0.161 0.001 0.323 0.004 0.483l-0-0.024v66.25c-67.928-60.977-157.668-98.25-256-98.25-211.703 0-384 172.297-384 384s172.297 384 384 384c211.703 0 384-172.297 384-384 0-20.279-2-39.649-4.833-58.167-2.059-15.868-15.488-27.999-31.752-27.999-17.675 0-32.003 14.328-32.003 32.003 0 2.001 0.184 3.96 0.535 5.859l-0.030-0.197c2.5 16.341 4.083 32.427 4.083 48.5 0 177.118-142.882 320-320 320s-320-142.882-320-320c0-177.118 142.882-320 320-320 83.931 0 159.583 32.587 216.542 85.333h-77.875c-0.135-0.002-0.293-0.003-0.453-0.003-17.675 0-32.003 14.328-32.003 32.003s14.328 32.003 32.003 32.003c0.159 0 0.318-0.001 0.477-0.003l-0.024 0h149.333c0.36-0.012 0.665-0.027 0.968-0.046l-0.093 0.005c0.847-0.015 1.658-0.060 2.46-0.135l-0.127 0.010c1.131-0.113 2.112-0.26 3.078-0.45l-0.203 0.033c1.044-0.204 1.871-0.405 2.684-0.639l-0.226 0.055c0.433-0.105 0.642-0.162 0.851-0.222l-0.226 0.055c0.324-0.084 0.421-0.112 0.518-0.141l-0.227 0.058c0.582-0.207 0.941-0.348 1.296-0.495l-0.212 0.078c0.869-0.287 1.504-0.527 2.129-0.786l-0.212 0.078c1.091-0.46 1.954-0.878 2.794-1.334l-0.169 0.084c0.266-0.125 0.348-0.167 0.43-0.209l-0.18 0.084c1.006-0.544 1.823-1.041 2.615-1.573l-0.115 0.073c0.198-0.128 0.28-0.183 0.361-0.238l-0.111 0.071c0.874-0.609 1.621-1.184 2.34-1.79l-0.048 0.040c0.135-0.11 0.216-0.179 0.297-0.247l-0.047 0.039c0.767-0.647 1.46-1.287 2.123-1.956l0.002-0.002c0.071-0.070 0.138-0.138 0.206-0.206l0.002-0.002c0.648-0.669 1.275-1.375 1.87-2.107l0.047-0.059c0.030-0.034 0.098-0.115 0.166-0.197l0.043-0.053c0.105-0.139 0.269-0.369 0.43-0.602l0.070-0.106c0.404-0.52 0.843-1.131 1.26-1.758l0.074-0.117c0.492-0.757 1.018-1.67 1.499-2.611l0.084-0.181c0.358-0.666 0.763-1.529 1.13-2.413l0.078-0.212c-0.038 0.108 0.004 0.012 0.045-0.084l0.080-0.208c0.276-0.677 0.589-1.592 0.86-2.524l0.056-0.226c-0.029 0.129-0 0.032 0.028-0.066l0.056-0.226c0.216-0.71 0.447-1.663 0.634-2.632l0.032-0.201c-0.007 0.078 0.008-0.022 0.022-0.121l0.020-0.17c-0.013 0.107 0.002 0.022 0.016-0.063l0.026-0.187c0.138-0.8 0.256-1.801 0.328-2.816l0.006-0.101c0.012-0.142 0.027-0.387 0.039-0.634l0.003-0.075c0.025-0.456 0.040-0.995 0.042-1.537l0-0.005v-149.333c0.002-0.136 0.003-0.298 0.003-0.459 0-17.675-14.328-32.003-32.003-32.003-0.176 0-0.351 0.001-0.526 0.004l0.026-0z" + ], + "attrs": [ + {} + ], + "isMulticolor": false, + "isMulticolor2": false, + "grid": 0, + "tags": [ + "reload" + ] + }, + { + "id": 20, + "paths": [ + "M202.667 128c-0.135-0.002-0.293-0.003-0.453-0.003-17.675 0-32.003 14.328-32.003 32.003s14.328 32.003 32.003 32.003c0.159 0 0.318-0.001 0.477-0.003l-0.024 0h10.667v42.667c0 126.504 80.479 232.212 192 275.583v3.5c-111.521 43.371-192 149.079-192 275.583v42.667h-10.667c-0.135-0.002-0.293-0.003-0.453-0.003-17.675 0-32.003 14.328-32.003 32.003s14.328 32.003 32.003 32.003c0.159 0 0.318-0.001 0.477-0.003l-0.024 0h618.667c0.135 0.002 0.293 0.003 0.453 0.003 17.675 0 32.003-14.328 32.003-32.003s-14.328-32.003-32.003-32.003c-0.159 0-0.318 0.001-0.477 0.003l0.024-0h-10.667v-42.667c0-126.504-80.479-232.212-192-275.583v-3.5c111.521-43.371 192-149.079 192-275.583v-42.667h10.667c0.135 0.002 0.293 0.003 0.453 0.003 17.675 0 32.003-14.328 32.003-32.003s-14.328-32.003-32.003-32.003c-0.159 0-0.318 0.001-0.477 0.003l0.024-0h-618.667zM277.333 192h469.333v42.667c0 107.060-71.446 196.746-168.958 225.167-13.419 4.005-23.035 16.233-23.042 30.708l-0 0.001v42.917c0.007 14.475 9.623 26.703 22.815 30.65l0.227 0.058c97.512 28.421 168.958 118.106 168.958 225.167v42.667h-77.875c-14.825-73.031-79.387-128-156.792-128s-141.967 54.969-156.792 128h-77.875v-42.667c0-107.060 71.446-196.746 168.958-225.167 13.419-4.005 23.035-16.233 23.042-30.708l0-0.001v-42.917c-0.007-14.475-9.623-26.703-22.815-30.65l-0.227-0.058c-97.512-28.421-168.958-118.106-168.958-225.167v-42.667zM426.667 341.333c0 47.125 38.208 85.333 85.333 85.333s85.333-38.208 85.333-85.333h-170.667z" + ], + "attrs": [ + {} + ], + "isMulticolor": false, + "isMulticolor2": false, + "grid": 0, + "tags": [ + "sandclock" + ] + }, + { + "id": 19, + "paths": [ + "M308.833 127.542c-1.681 0.042-3.29 0.207-4.86 0.487l0.193-0.029h-58.833c-64.683 0-117.333 52.629-117.333 117.333v533.333c0 64.704 52.651 117.333 117.333 117.333h236.25l18.292-64h-179.875v-245.333c0-5.888 4.8-10.667 10.667-10.667h362.667c5.867 0 10.667 4.779 10.667 10.667v6.958l50.083-50.083c-13.547-19.029-35.683-31.542-60.75-31.542h-362.667c-41.173 0-74.667 33.493-74.667 74.667v245.333h-10.667c-29.419 0-53.333-23.936-53.333-53.333v-533.333c0-29.397 23.915-53.333 53.333-53.333h32v117.333c0 40.852 33.814 74.667 74.667 74.667h256c40.852 0 74.667-33.814 74.667-74.667v-97.042l149.333 132.75v135.125c20.352-8.533 42.304-11.955 64-10.333v-139.167c0-9.131-3.923-17.837-10.75-23.917l-192-170.667c-5.845-5.205-13.421-8.083-21.25-8.083h-16.083c-1.559-0.269-3.356-0.423-5.187-0.423s-3.628 0.154-5.376 0.45l0.188-0.026h-330.958c-1.626-0.293-3.497-0.46-5.408-0.46-0.12 0-0.241 0.001-0.361 0.002l0.018-0zM341.333 192h277.333v117.333c0 6.294-4.372 10.667-10.667 10.667h-256c-6.294 0-10.667-4.372-10.667-10.667v-117.333zM885.625 512c-24.507 0.005-48.99 9.324-67.625 27.958l-256.375 256.333c-6.635 6.613-11.44 14.872-14 23.875l-34.375 120.333c-3.179 11.157-0.11 23.203 8.125 31.417 6.080 6.080 14.283 9.375 22.667 9.375 2.944 0 5.849-0.418 8.75-1.25l120.417-34.375c9.045-2.581 17.306-7.451 23.792-14l256.333-256.333c18.048-18.091 28-42.151 28-67.708s-9.972-49.597-28.042-67.667c-18.656-18.656-43.16-27.964-67.667-27.958z" + ], + "attrs": [ + {} + ], + "isMulticolor": false, + "isMulticolor2": false, + "grid": 0, + "tags": [ + "save_as" + ] + }, + { + "id": 18, + "paths": [ + "M501.333 64c-114.382 0-202.667 80.616-202.667 181.333v40.667c-89.742 19.020-157.462 91.756-166.625 184.667-37.672 3.567-68.042 34.819-68.042 73.333 0 99.769 81.565 181.333 181.333 181.333h234.667v170.667h-192c-0.135-0.002-0.293-0.003-0.453-0.003-17.675 0-32.003 14.328-32.003 32.003s14.328 32.003 32.003 32.003c0.159 0 0.318-0.001 0.477-0.003l-0.024 0h448c0.135 0.002 0.293 0.003 0.453 0.003 17.675 0 32.003-14.328 32.003-32.003s-14.328-32.003-32.003-32.003c-0.159 0-0.318 0.001-0.477 0.003l0.024-0h-192v-170.667h234.667c99.769 0 181.333-81.565 181.333-181.333 0-38.514-30.37-69.767-68.042-73.333-9.373-104.657-86.473-186.492-187.958-206v-19.333c0-100.718-88.285-181.333-202.667-181.333zM501.333 128c85.895 0 138.667 53.102 138.667 117.333v14.125c-25.422 3.859-48.911 11.893-67.625 21.25-10.952 5.239-18.382 16.232-18.382 28.96 0 17.675 14.328 32.003 32.003 32.003 5.474 0 10.627-1.374 15.133-3.797l-0.171 0.084c19.775-9.888 42.978-17.958 60.375-17.958 87.063 0 155.51 65.354 166.375 149.333h-631.458c10.671-72.164 69.82-128 145.083-128 63.571 0 107.591 19.699 131.333 67.542 5.224 10.994 16.238 18.459 28.996 18.459 17.675 0 32.003-14.328 32.003-32.003 0-5.439-1.357-10.56-3.75-15.045l0.084 0.172c-32.28-65.048-96.776-95.535-167.333-100.875v-34.25c0-64.232 52.771-117.333 138.667-117.333zM138.667 533.333h746.667c6.294 0 10.667 4.372 10.667 10.667 0 65.181-52.153 117.333-117.333 117.333h-533.333c-65.181 0-117.333-52.153-117.333-117.333 0-6.294 4.372-10.667 10.667-10.667z" + ], + "attrs": [ + {} + ], + "isMulticolor": false, + "isMulticolor2": false, + "grid": 0, + "tags": [ + "scoop" + ] + }, + { + "id": 17, + "paths": [ + "M437.333 128c-170.461 0-309.333 138.872-309.333 309.333s138.872 309.333 309.333 309.333c73.736 0 141.519-26.047 194.75-69.333l209.292 209.292c5.833 6.068 14.019 9.838 23.085 9.838 17.675 0 32.003-14.328 32.003-32.003 0-9.066-3.77-17.252-9.828-23.075l-0.011-0.010-209.292-209.292c43.286-53.231 69.333-121.014 69.333-194.75 0-170.461-138.872-309.333-309.333-309.333zM437.333 192c135.873 0 245.333 109.46 245.333 245.333 0 66.189-26.108 125.989-68.458 170.042-2.631 1.948-4.886 4.202-6.772 6.747l-0.061 0.086c-44.053 42.351-103.853 68.458-170.042 68.458-135.873 0-245.333-109.46-245.333-245.333s109.46-245.333 245.333-245.333z" + ], + "attrs": [ + {} + ], + "isMulticolor": false, + "isMulticolor2": false, + "grid": 0, + "tags": [ + "search" + ] + }, + { + "id": 16, + "paths": [ + "M512 85.333c-33.64 0-66.077 4.254-97.042 11.458-13.144 3.145-23.019 14.089-24.528 27.563l-0.013 0.145-6.792 61.917c-2.221 20.29-13.942 38.242-31.625 48.458-17.648 10.196-39.069 11.326-57.75 3.125h-0.042l-56.875-25.042c-3.794-1.713-8.226-2.711-12.891-2.711-9.206 0-17.505 3.887-23.343 10.11l-0.016 0.017c-44.213 47.136-78.146 104.213-97.417 167.917-0.871 2.775-1.373 5.965-1.373 9.273 0 10.557 5.111 19.919 12.994 25.749l0.087 0.061 50.458 37c16.477 12.114 26.167 31.205 26.167 51.625 0 20.431-9.69 39.538-26.167 51.625l-50.458 36.958c-7.97 5.891-13.081 15.254-13.081 25.81 0 3.308 0.502 6.498 1.434 9.5l-0.061-0.227c19.268 63.697 53.174 120.816 97.417 167.958 5.853 6.223 14.14 10.098 23.332 10.098 4.675 0 9.117-1.003 13.12-2.804l-0.202 0.081 56.875-25.042c18.69-8.219 40.131-7.037 57.792 3.167 17.683 10.217 29.404 28.169 31.625 48.458l6.792 61.917c1.534 13.591 11.385 24.512 24.282 27.622l0.218 0.044c30.979 7.23 63.443 11.5 97.083 11.5s66.077-4.254 97.042-11.458c13.144-3.145 23.019-14.089 24.528-27.563l0.013-0.145 6.792-61.917c2.221-20.29 13.942-38.242 31.625-48.458 17.648-10.196 39.069-11.368 57.75-3.167l56.917 25.042c3.802 1.721 8.243 2.723 12.918 2.723 9.192 0 17.479-3.875 23.316-10.082l0.015-0.017c44.213-47.136 78.146-104.255 97.417-167.958 0.871-2.775 1.373-5.965 1.373-9.273 0-10.557-5.111-19.919-12.994-25.749l-0.087-0.062-50.458-36.958c-16.477-12.087-26.167-31.194-26.167-51.625s9.69-39.538 26.167-51.625l50.458-36.958c7.97-5.891 13.081-15.254 13.081-25.81 0-3.308-0.502-6.498-1.434-9.5l0.061 0.227c-19.271-63.704-53.203-120.822-97.417-167.958-5.853-6.223-14.14-10.098-23.332-10.098-4.675 0-9.117 1.003-13.12 2.804l0.202-0.081-56.917 25.042c-18.681 8.201-40.102 7.030-57.75-3.167-17.683-10.217-29.404-28.169-31.625-48.458l-6.792-61.917c-1.534-13.591-11.385-24.512-24.282-27.622l-0.218-0.044c-30.979-7.23-63.443-11.5-97.083-11.5zM512 149.333c20.785 0 40.745 3.731 60.75 7.25l4 36.792c4.435 40.51 27.984 76.541 63.25 96.917 35.289 20.389 78.253 22.733 115.542 6.333l33.833-14.875c25.98 31.197 46.55 66.435 60.917 105.042l-30 22c-32.846 24.094-52.292 62.455-52.292 103.208s19.446 79.114 52.292 103.208l30 22c-14.367 38.606-34.936 73.844-60.917 105.042l-33.833-14.875c-37.289-16.399-80.253-14.055-115.542 6.333-35.266 20.375-58.815 56.406-63.25 96.917l-4 36.792c-20.003 3.509-39.975 7.25-60.75 7.25-20.785 0-40.745-3.731-60.75-7.25l-4-36.792c-4.435-40.51-27.984-76.541-63.25-96.917-35.289-20.389-78.253-22.733-115.542-6.333l-33.833 14.875c-25.985-31.193-46.552-66.432-60.917-105.042l30-22c32.846-24.094 52.292-62.455 52.292-103.208s-19.462-79.139-52.292-103.25l-30-22c14.373-38.621 34.963-73.836 60.958-105.042l33.792 14.875c37.289 16.399 80.253 14.097 115.542-6.292 35.266-20.375 58.815-56.406 63.25-96.917l4-36.792c20.003-3.509 39.975-7.25 60.75-7.25zM512 341.333c-93.878 0-170.667 76.789-170.667 170.667s76.789 170.667 170.667 170.667c93.878 0 170.667-76.789 170.667-170.667s-76.789-170.667-170.667-170.667zM512 405.333c59.289 0 106.667 47.377 106.667 106.667s-47.377 106.667-106.667 106.667c-59.289 0-106.667-47.377-106.667-106.667s47.377-106.667 106.667-106.667z" + ], + "attrs": [ + {} + ], + "isMulticolor": false, + "isMulticolor2": false, + "grid": 0, + "tags": [ + "settings" + ] + }, + { + "id": 15, + "paths": [ + "M768 106.667c-82.096 0-149.333 67.238-149.333 149.333 0 12.496 4.236 23.669 7.167 35.292l-255.792 127.958c-27.447-33.673-67.503-56.583-114.042-56.583-82.096 0-149.333 67.238-149.333 149.333s67.238 149.333 149.333 149.333c46.539 0 86.595-22.911 114.042-56.583l255.792 127.958c-2.931 11.623-7.167 22.795-7.167 35.292 0 82.095 67.238 149.333 149.333 149.333s149.333-67.238 149.333-149.333c0-82.095-67.238-149.333-149.333-149.333-46.539 0-86.595 22.911-114.042 56.583l-255.792-127.958c2.931-11.623 7.167-22.795 7.167-35.292s-4.236-23.669-7.167-35.292l255.792-127.958c27.447 33.673 67.503 56.583 114.042 56.583 82.096 0 149.333-67.238 149.333-149.333s-67.238-149.333-149.333-149.333zM768 170.667c47.507 0 85.333 37.826 85.333 85.333s-37.826 85.333-85.333 85.333c-47.507 0-85.333-37.826-85.333-85.333s37.826-85.333 85.333-85.333zM256 426.667c47.507 0 85.333 37.826 85.333 85.333s-37.826 85.333-85.333 85.333c-47.507 0-85.333-37.826-85.333-85.333s37.826-85.333 85.333-85.333zM768 682.667c47.507 0 85.333 37.826 85.333 85.333s-37.826 85.333-85.333 85.333c-47.507 0-85.333-37.826-85.333-85.333s37.826-85.333 85.333-85.333z" + ], + "attrs": [ + {} + ], + "isMulticolor": false, + "isMulticolor2": false, + "grid": 0, + "tags": [ + "share" + ] + }, + { + "id": 14, + "paths": [ + "M564.25 152.5c-37.657 1.723-73.583 31.577-73.583 73.667v181.042l-282.542-238.125c-11.704-9.86-25.253-15.054-38.958-16.333-41.116-3.838-83.833 27.501-83.833 73.417v571.667c0 61.221 75.975 96.523 122.792 57.083l282.542-238.125v181.042c0 61.221 75.975 96.523 122.792 57.083l339.125-285.833c34.912-29.425 34.93-84.766 0.042-114.208-0.006-0-0.014-0-0.021-0s-0.015 0-0.022 0l0.001-0-339.125-285.792c-14.63-12.325-32.092-17.366-49.208-16.583zM160.458 214.583c2.055 0.463 4.244 1.586 6.417 3.417l323.792 272.917v42.167l-323.792 272.875c-8.693 7.323-17.542 3.23-17.542-8.125v-571.667c0-5.678 2.199-9.551 5.5-11.083 1.65-0.766 3.57-0.963 5.625-0.5zM565.792 214.583c2.055 0.463 4.244 1.586 6.417 3.417l339.125 285.792c5.559 4.691 5.536 11.668 0 16.333l-339.125 285.833c-8.693 7.323-17.542 3.23-17.542-8.125v-571.667c0-5.678 2.199-9.551 5.5-11.083 1.65-0.766 3.57-0.963 5.625-0.5z" + ], + "attrs": [ + {} + ], + "isMulticolor": false, + "isMulticolor2": false, + "grid": 0, + "tags": [ + "skip" + ] + }, + { + "id": 13, + "paths": [ + "M512 85.333c-235.263 0-426.667 191.404-426.667 426.667s191.404 426.667 426.667 426.667c235.263 0 426.667-191.404 426.667-426.667s-191.404-426.667-426.667-426.667zM512 149.333c200.674 0 362.667 161.992 362.667 362.667s-161.992 362.667-362.667 362.667c-176.242 0-322.588-124.969-355.625-291.333l122.208 52.417c-0.575 4.966-1.25 9.931-1.25 14.917 0 28.741 9.465 57.768 29.375 80.167s50.625 37.167 87.958 37.167c37.333 0 68.049-14.768 87.958-37.167s29.375-51.426 29.375-80.167c0-5.556-0.661-11.098-1.375-16.625l102.333-79.667c1.908 0.073 3.782 0.292 5.708 0.292 82.325 0 149.333-67.008 149.333-149.333s-67.008-149.333-149.333-149.333c-82.325 0-149.333 67.008-149.333 149.333 0 4.4 0.292 8.737 0.667 13.042l-69.208 115.25c-2.049-0.091-4.034-0.292-6.125-0.292-37.333 0-68.049 14.768-87.958 37.167-1.629 1.832-3.052 3.791-4.542 5.708l-152.75-65.458c0.68-200.089 162.332-361.417 362.583-361.417zM618.667 320c47.061 0 85.333 38.272 85.333 85.333s-38.272 85.333-85.333 85.333c-47.061 0-85.333-38.272-85.333-85.333s38.272-85.333 85.333-85.333zM618.667 362.667c-23.564 0-42.667 19.103-42.667 42.667s19.103 42.667 42.667 42.667v0c23.564 0 42.667-19.103 42.667-42.667s-19.103-42.667-42.667-42.667v0zM394.667 576c26.667 0 43.951 9.232 56.042 22.833s18.625 32.574 18.625 51.833c0 19.259-6.535 38.232-18.625 51.833s-29.375 22.833-56.042 22.833c-26.667 0-43.951-9.232-56.042-22.833-11.473-12.907-17.745-30.68-18.375-48.917l61.792 26.5c3.724 1.642 8.067 2.598 12.632 2.598 17.679 0 32.011-14.332 32.011-32.011 0-13.119-7.892-24.395-19.188-29.339l-0.206-0.080-63.458-27.208c11.759-10.8 27.6-18.042 50.833-18.042z" + ], + "attrs": [ + {} + ], + "isMulticolor": false, + "isMulticolor2": false, + "grid": 0, + "tags": [ + "steam" + ] + }, + { + "id": 12, + "paths": [ + "M842.667 149.333c64.422 0 117.333 52.911 117.333 117.333v490.667c0 64.422-52.911 117.333-117.333 117.333h-661.333c-64.422 0-117.333-52.911-117.333-117.333v-490.667c0-64.422 52.911-117.333 117.333-117.333h661.333zM842.667 213.333h-661.333c-29.829 0-53.333 23.505-53.333 53.333v490.667c0 29.829 23.505 53.333 53.333 53.333h245.333v-181.333c0-64.41 52.923-117.333 117.333-117.333h352v-245.333c0-29.829-23.505-53.333-53.333-53.333zM224.625 277.042c8.646 0.26 16.392 3.91 21.993 9.66l0.007 0.007 116.042 116.042v-29.417c-0.002-0.137-0.003-0.298-0.003-0.459 0-17.675 14.328-32.003 32.003-32.003 0.176 0 0.351 0.001 0.527 0.004l-0.026-0c17.459 0.281 31.503 14.5 31.503 31.999 0 0.161-0.001 0.323-0.004 0.483l0-0.024v101.917c0.266 1.551 0.419 3.338 0.419 5.16 0 17.675-14.328 32.003-32.003 32.003-1.809 0-3.584-0.15-5.311-0.439l0.187 0.026h-101.958c-0.135 0.002-0.293 0.003-0.453 0.003-17.675 0-32.003-14.328-32.003-32.003s14.328-32.003 32.003-32.003c0.159 0 0.318 0.001 0.477 0.003l-0.024-0h29.417l-116.042-116.042c-5.971-5.82-9.675-13.941-9.675-22.927 0-17.675 14.328-32.003 32.003-32.003 0.324 0 0.647 0.005 0.969 0.014l-0.047-0.001zM896 576h-352c-29.712 0-53.333 23.621-53.333 53.333v181.333h352c29.829 0 53.333-23.505 53.333-53.333v-181.333z" + ], + "attrs": [ + {} + ], + "isMulticolor": false, + "isMulticolor2": false, + "grid": 0, + "tags": [ + "sys_tray" + ] + }, + { + "id": 11, + "paths": [ + "M512 43c-55.73 0-102.016 38.966-156.5 74.917s-113.488 71.988-166.917 81.5c-36.997 6.573-60.583 40.133-60.583 75.625v98.125c0 151.544 55.917 300.537 129.875 413.458 36.979 56.461 78.503 103.938 121.333 138.292s87.293 56.75 132.792 56.75c45.498 0 89.962-22.397 132.792-56.75s84.355-81.831 121.333-138.292c73.958-112.921 129.875-261.915 129.875-413.458v-98.125c0-35.492-23.586-69.052-60.583-75.625-53.429-9.512-112.432-45.55-166.917-81.5s-100.77-74.917-156.5-74.917zM480 119.875v165.625c-5.633-5.063-13.121-8.161-21.332-8.167l-0.001-0c-17.673 0-32 14.327-32 32s14.327 32 32 32v0c8.218-0.018 15.705-3.13 21.362-8.233l-0.028 0.025v123.042c-5.633-5.063-13.121-8.161-21.332-8.167l-0.001-0c-17.672 0.002-31.997 14.328-31.997 32 0 3.824 0.671 7.49 1.901 10.889l-0.070-0.223h-110.375c1.16-3.176 1.83-6.843 1.83-10.667 0-17.657-14.301-31.974-31.953-32l-0.002-0c-17.672 0.002-31.997 14.328-31.997 32 0 3.824 0.671 7.49 1.901 10.889l-0.070-0.223h-52.708c-4.316-21.543-7.765-43.208-10.083-64.917 2.283 0.582 4.905 0.917 7.604 0.917 0.007 0 0.014-0 0.022-0l-0.001 0c17.673 0 32-14.327 32-32s-14.327-32-32-32v0c-3.829 0.016-7.494 0.702-10.889 1.946l0.222-0.071v-89.5c0-7.26 4.682-12.073 7.792-12.625 51.241-9.123 98.528-33.195 141.542-59.458 0.165 17.547 14.428 31.708 31.999 31.708 0 0 0.001-0 0.001-0l-0 0c17.657-0.022 31.962-14.34 31.962-32 0-12.694-7.391-23.661-18.104-28.833l-0.191-0.083c1.21-0.798 2.548-1.624 3.75-2.417 29.85-19.696 54.325-33.475 75.625-44.292 5.221-1.33 9.749-3.789 13.491-7.112l-0.033 0.029c0.049-0.023 0.118-0.060 0.167-0.083zM544 119.875c23.598 11.129 53.27 27.718 89.25 51.458 55.217 36.434 119.289 78.324 190.958 91.083 3.11 0.552 7.792 5.365 7.792 12.625v98.125c0 39.258-5.327 78.578-13.125 117.5h-274.875v-370.792zM288 277.333c-17.673 0-32 14.327-32 32s14.327 32 32 32v0c17.673 0 32-14.327 32-32s-14.327-32-32-32v0zM373.333 362.667c-17.673 0-32 14.327-32 32s14.327 32 32 32v0c17.673 0 32-14.327 32-32s-14.327-32-32-32v0zM221.292 554.667h258.708v354.875c-18.437-6.654-38.643-16.81-60.75-34.542-36.004-28.878-73.924-71.684-107.833-123.458-37.269-56.904-68.52-124.939-90.125-196.875zM574.167 554.667h110.375c-1.16 3.176-1.83 6.843-1.83 10.667 0 17.657 14.301 31.974 31.953 32l0.002 0c17.672-0.002 31.997-14.328 31.997-32 0-3.824-0.671-7.49-1.901-10.889l0.070 0.223h57.875c-16.853 56.114-39.713 109.648-66.583 157.583-5.651-5.118-13.183-8.25-21.446-8.25-0.004 0-0.009 0-0.013 0l0.001-0c-17.631 0.055-31.902 14.361-31.902 32 0 13.311 8.128 24.724 19.691 29.547l0.212 0.078c-13.435 19.415-27.248 37.719-41.375 54-0.933-16.923-14.882-30.292-31.954-30.292-0.001 0-0.003 0-0.004 0l0-0c-0.031-0-0.068-0-0.104-0-17.673 0-32 14.327-32 32 0 17.637 14.268 31.941 31.89 32l0.006 0c-8.179 7.798-16.322 15.207-24.375 21.667-15.046 12.069-29.131 20.458-42.458 26.792-5.098-3.61-11.44-5.776-18.288-5.792l-0.004-0v-128c17.673 0 32-14.327 32-32s-14.327-32-32-32v0-106.667c17.672-0.002 31.997-14.328 31.997-32 0-3.824-0.671-7.49-1.901-10.889l0.070 0.223zM629.333 618.667c-17.673 0-32 14.327-32 32s14.327 32 32 32v0c17.673 0 32-14.327 32-32s-14.327-32-32-32v0z" + ], + "attrs": [ + {} + ], + "isMulticolor": false, + "isMulticolor2": false, + "grid": 0, + "tags": [ + "uac" + ] + }, + { + "id": 10, + "paths": [ + "M512 85.333c-74.844 0-137.165 55.924-147.625 128h-145.958c-1.623-0.292-3.491-0.458-5.398-0.458-0.036 0-0.072 0-0.108 0l0.006-0c-1.706 0.038-3.345 0.203-4.943 0.487l0.193-0.028h-69.5c-0.135-0.002-0.293-0.003-0.453-0.003-17.675 0-32.003 14.328-32.003 32.003s14.328 32.003 32.003 32.003c0.159 0 0.318-0.001 0.477-0.003l-0.024 0h45.625l53.708 555.292c5.783 59.875 56.651 106.042 116.792 106.042h314.375c60.143 0 111.011-46.162 116.792-106.042l53.75-555.292h45.625c0.135 0.002 0.293 0.003 0.453 0.003 17.675 0 32.003-14.328 32.003-32.003s-14.328-32.003-32.003-32.003c-0.159 0-0.318 0.001-0.477 0.003l0.024-0h-69.458c-1.541-0.263-3.315-0.413-5.125-0.413s-3.584 0.15-5.312 0.439l0.187-0.026h-146c-10.46-72.076-72.781-128-147.625-128zM512 149.333c40.089 0 72.976 27.054 82.375 64h-164.75c9.399-36.946 42.286-64 82.375-64zM248.542 277.333h526.875l-53.167 549.125c-2.667 27.629-25.333 48.208-53.083 48.208h-314.375c-27.71 0-50.418-20.616-53.083-48.208l-53.167-549.125zM511.542 384c-8.669 0.131-16.483 3.688-22.167 9.375l-106.667 106.667c-6.068 5.833-9.838 14.019-9.838 23.085 0 17.675 14.328 32.003 32.003 32.003 9.066 0 17.252-3.77 23.075-9.828l0.010-0.011 52.042-52.042v242.75c-0.002 0.135-0.003 0.293-0.003 0.453 0 17.675 14.328 32.003 32.003 32.003s32.003-14.328 32.003-32.003c0-0.159-0.001-0.318-0.003-0.477l0 0.024v-242.75l52.042 52.042c5.833 6.068 14.019 9.838 23.085 9.838 17.675 0 32.003-14.328 32.003-32.003 0-9.066-3.77-17.252-9.828-23.075l-0.011-0.010-106.667-106.667c-5.792-5.794-13.795-9.378-22.634-9.378-0.158 0-0.315 0.001-0.473 0.003l0.024-0z" + ], + "attrs": [ + {} + ], + "isMulticolor": false, + "isMulticolor2": false, + "grid": 0, + "tags": [ + "undelete" + ] + }, + { + "id": 9, + "paths": [ + "M512 128c-129.494 0-244.196 64.495-313.667 162.875-3.666 5.137-5.861 11.543-5.861 18.462 0 17.676 14.329 32.005 32.005 32.005 10.76 0 20.28-5.31 26.082-13.452l0.066-0.098c57.975-82.1 153.088-135.792 261.375-135.792 172.406 0 311.966 135.484 319.292 306.042l-51.333-51.333c-5.822-5.991-13.956-9.708-22.958-9.708l-0-0c-17.672 0.004-31.995 14.331-31.995 32.003 0 9 3.715 17.133 9.696 22.948l0.007 0.007 96 96c5.791 5.789 13.79 9.369 22.625 9.369s16.834-3.58 22.625-9.369l7.417-7.417c2.346-1.79 4.376-3.82 6.11-6.089l0.057-0.077 82.417-82.417c6.068-5.833 9.838-14.019 9.838-23.085 0-17.675-14.328-32.003-32.003-32.003-9.066 0-17.252 3.77-23.075 9.828l-0.010 0.011-32.375 32.375c-16.785-196.33-181.738-351.083-382.333-351.083zM170.208 426.667c-8.669 0.131-16.483 3.688-22.167 9.375l-7.292 7.292c-2.417 1.83-4.503 3.917-6.275 6.254l-0.058 0.080-82.375 82.375c-6.068 5.833-9.838 14.019-9.838 23.085 0 17.675 14.328 32.003 32.003 32.003 9.066 0 17.252-3.77 23.075-9.828l0.010-0.011 32.375-32.375c16.785 196.33 181.738 351.083 382.333 351.083 129.494 0 244.196-64.495 313.667-162.875 3.666-5.137 5.861-11.543 5.861-18.462 0-17.676-14.329-32.005-32.005-32.005-10.76 0-20.28 5.31-26.082 13.452l-0.066 0.098c-57.975 82.1-153.088 135.792-261.375 135.792-172.406 0-311.966-135.484-319.292-306.042l51.333 51.333c5.833 6.068 14.019 9.838 23.085 9.838 17.675 0 32.003-14.328 32.003-32.003 0-9.066-3.77-17.252-9.828-23.075l-0.011-0.010-96-96c-5.792-5.794-13.795-9.378-22.634-9.378-0.158 0-0.315 0.001-0.473 0.003l0.024-0z" + ], + "attrs": [ + {} + ], + "isMulticolor": false, + "isMulticolor2": false, + "grid": 0, + "tags": [ + "update" + ] + }, + { + "id": 8, + "paths": [ + "M512 85.333c-235.263 0-426.667 191.404-426.667 426.667s191.404 426.667 426.667 426.667c235.263 0 426.667-191.404 426.667-426.667s-191.404-426.667-426.667-426.667zM512 149.333c200.674 0 362.667 161.992 362.667 362.667s-161.992 362.667-362.667 362.667c-200.674 0-362.667-161.992-362.667-362.667s161.992-362.667 362.667-362.667zM511.542 320c-8.669 0.131-16.483 3.688-22.167 9.375l-128 128c-6.068 5.833-9.838 14.019-9.838 23.085 0 17.675 14.328 32.003 32.003 32.003 9.066 0 17.252-3.77 23.075-9.828l0.010-0.011 73.375-73.375v242.75c-0.002 0.135-0.003 0.293-0.003 0.453 0 17.675 14.328 32.003 32.003 32.003s32.003-14.328 32.003-32.003c0-0.159-0.001-0.318-0.003-0.477l0 0.024v-242.75l73.375 73.375c5.833 6.068 14.019 9.838 23.085 9.838 17.675 0 32.003-14.328 32.003-32.003 0-9.066-3.77-17.252-9.828-23.075l-0.011-0.010-128-128c-5.792-5.794-13.795-9.378-22.634-9.378-0.158 0-0.315 0.001-0.473 0.003l0.024-0z" + ], + "attrs": [ + {} + ], + "isMulticolor": false, + "isMulticolor2": false, + "grid": 0, + "tags": [ + "upgradable" + ] + }, + { + "id": 7, + "paths": [ + "M512 938.667c235.264 0 426.667-191.403 426.667-426.667s-191.403-426.667-426.667-426.667-426.667 191.403-426.667 426.667 191.403 426.667 426.667 426.667zM361.365 457.365l128-128c12.501-12.501 32.747-12.501 45.248 0l128 128c12.501 12.501 12.501 32.747 0 45.248-6.229 6.272-14.421 9.387-22.613 9.387s-16.384-3.115-22.635-9.365l-73.365-73.387v242.752c0 17.664-14.336 32-32 32s-32-14.336-32-32v-242.752l-73.365 73.365c-12.501 12.501-32.747 12.501-45.248 0s-12.501-32.747-0.021-45.248z" + ], + "attrs": [ + {} + ], + "isMulticolor": false, + "isMulticolor2": false, + "grid": 0, + "tags": [ + "upgradable_filled" + ] + }, + { + "id": 6, + "paths": [ + "M532.224 85.611c-165.632-4.395-254.464 45.44-319.424 94.123-58.432 43.84-105.323 114.368-118.997 136.128-2.24 3.563-1.045 8.235 2.581 10.389l32.213 19.115c-23.125 40.96-43.264 96.747-43.264 166.635 0 32.64 4.032 64.299 11.008 94.869 0.32 1.664 0.405 3.371 0.747 5.013l0.512-0.107c42.709 177.28 196.075 311.509 382.805 325.291 10.304 1.024 20.629 1.6 30.933 1.6v-0.043c0.235 0 0.448 0.043 0.661 0.043 288.448 0 510.976-287.744 395.605-591.275-53.525-140.8-224.789-257.792-375.381-261.781zM490.496 725.333c-95.104-0.149-166.229-104.491-105.003-204.779 14.955-24.491 40.384-41.195 68.459-47.104 55.829-11.733 96.469 1.387 125.504 41.344 10.837 14.912 30.485 60.608 7.061 108.629-4.928 10.069-2.197 22.208 6.955 28.693l17.664 12.501c-27.477 40.469-74.901 59.392-116.651 60.48-1.365 0.064-2.645 0.235-3.989 0.235zM661.184 485.717c-48.491-73.344-126.485-122.155-212.757-122.155-141.397 0-256.427 114.645-256.427 255.552 0 9.685 0.704 19.008 1.451 28.309l-15.637 5.44c-7.979-18.88-14.101-38.699-18.816-59.051-13.547-71.936 5.227-150.037 49.899-205.056 47.851-58.944 122.688-90.091 216.405-90.091 128.405 0 223.595 88.171 249.835 182.187l-13.952 4.864zM512 874.667c-8.747 0-17.301-0.704-25.899-1.323-115.776-11.264-230.101-99.499-230.101-254.229 0-82.005 52.139-151.936 125.056-179.2-49.728 34.731-82.389 92.288-82.389 157.419 0 105.771 85.973 191.808 191.68 191.979v0.021c0.064 0 0.107 0 0.171 0s0.107 0 0.171 0c6.208 0 12.544-0.405 18.923-0.981 132.331-9.941 237.056-120.981 237.056-256.341 0-140.629-131.989-297.344-321.365-297.344-107.477 0-179.52 34.645-226.645 73.856l-12.8-11.733c18.069-22.613 40.747-47.424 65.323-65.856 58.347-43.755 131.797-84.117 273.92-81.472 141.76 2.645 270.997 87.872 322.197 220.096 100.267 258.944-89.301 505.109-335.296 505.109z" + ], + "attrs": [ + {} + ], + "isMulticolor": false, + "isMulticolor2": false, + "grid": 0, + "tags": [ + "uplay" + ] + }, + { + "id": 4, + "paths": [ + "M288 106.667c-43.556 0-80.274 17.486-103.917 44.083s-34.75 60.806-34.75 94.583c0 33.778 11.108 67.986 34.75 94.583 17.276 19.436 43.11 31.149 71.917 37.583v269c-28.806 6.435-54.64 18.148-71.917 37.583-23.642 26.598-34.75 60.806-34.75 94.583s11.108 67.986 34.75 94.583c23.643 26.598 60.361 44.083 103.917 44.083 76.204 0 138.667-62.462 138.667-138.667 0-64.881-46.179-117.278-106.667-132.167v-102.958c26.809 20.26 60.011 32.458 96 32.458h184.875c4.91 22.693 15.068 44.425 31.208 62.583 23.642 26.598 60.361 44.083 103.917 44.083 76.204 0 138.667-62.462 138.667-138.667s-62.462-138.667-138.667-138.667c-43.556 0-80.274 17.486-103.917 44.083-16.14 18.158-26.298 39.89-31.208 62.583h-184.875c-53.408 0-96-42.592-96-96v-38.5c60.488-14.889 106.667-67.286 106.667-132.167 0-76.204-62.462-138.667-138.667-138.667zM288 170.667c41.616 0 74.667 33.050 74.667 74.667 0 40.963-32.141 73.276-72.833 74.292-0.567-0.036-1.229-0.056-1.896-0.056s-1.329 0.020-1.986 0.061l0.090-0.004c-26.15-0.512-42.556-9.194-54.125-22.208-11.913-13.402-18.583-32.528-18.583-52.083s6.67-38.681 18.583-52.083c11.913-13.402 28.528-22.583 56.083-22.583zM736 469.333c41.616 0 74.667 33.050 74.667 74.667s-33.050 74.667-74.667 74.667c-27.556 0-44.17-9.181-56.083-22.583-11.254-12.661-17.641-30.461-18.333-48.875 0.119-1.036 0.187-2.237 0.187-3.454 0-1.073-0.053-2.133-0.156-3.178l0.011 0.132c0.71-18.383 7.055-36.15 18.292-48.792 11.913-13.402 28.528-22.583 56.083-22.583zM286.042 704.375c0.567 0.036 1.229 0.056 1.896 0.056s1.329-0.020 1.986-0.061l-0.090 0.004c40.692 1.016 72.833 33.329 72.833 74.292 0 41.616-33.050 74.667-74.667 74.667-27.556 0-44.17-9.181-56.083-22.583s-18.583-32.528-18.583-52.083c0-19.556 6.67-38.681 18.583-52.083 11.569-13.015 27.975-21.696 54.125-22.208z" + ], + "attrs": [ + {} + ], + "isMulticolor": false, + "isMulticolor2": false, + "grid": 0, + "tags": [ + "version" + ] + }, + { + "id": 3, + "paths": [ + "M508.333 64.208c-30.667 0.248-61.225 12.099-84.25 35.5l-325.75 331.125c-46.049 46.802-45.428 123.034 1.375 169.083l331.125 325.75c46.802 46.049 123.034 45.428 169.083-1.375l325.75-331.083c0.014-0.014 0.028-0.028 0.041-0.041l0-0c46.012-46.823 45.386-123.034-1.417-169.083l-331.125-325.75c-23.401-23.024-54.166-34.373-84.833-34.125zM508.875 127.792c14.154-0.115 28.343 5.271 39.417 16.167l331.125 325.75c22.147 21.79 22.41 56.456 0.625 78.625l-325.75 331.083c-21.79 22.147-56.436 22.416-78.583 0.625l-331.125-325.75c-22.147-21.79-22.416-56.436-0.625-78.583l325.75-331.125c10.895-11.073 25.012-16.677 39.167-16.792zM511.5 276.875c-17.458 0.282-31.503 14.5-31.503 31.999 0 0.147 0.001 0.293 0.003 0.44l-0-0.022v256c-0.002 0.135-0.003 0.293-0.003 0.453 0 17.675 14.328 32.003 32.003 32.003s32.003-14.328 32.003-32.003c0-0.159-0.001-0.318-0.003-0.477l0 0.024v-256c0.002-0.124 0.003-0.271 0.003-0.417 0-17.675-14.328-32.003-32.003-32.003-0.176 0-0.351 0.001-0.526 0.004l0.026-0zM512 661.292c-23.564 0-42.667 19.103-42.667 42.667s19.103 42.667 42.667 42.667v0c23.564 0 42.667-19.103 42.667-42.667s-19.103-42.667-42.667-42.667v0z" + ], + "attrs": [ + {} + ], + "isMulticolor": false, + "isMulticolor2": false, + "grid": 0, + "tags": [ + "warning" + ] + }, + { + "id": 2, + "paths": [ + "M924.288 424.085l-331.115-325.76c-22.763-22.4-52.779-34.453-84.821-34.325-31.936 0.256-61.867 12.949-84.267 35.712l-325.76 331.115c-22.379 22.763-34.581 52.885-34.325 84.821s12.949 61.867 35.712 84.267l331.115 325.76c22.528 22.165 52.267 34.325 83.84 34.325 0.341 0 0.661 0 1.003 0 31.936-0.256 61.867-12.949 84.267-35.712l325.76-331.115c22.4-22.763 34.603-52.885 34.325-84.843s-12.971-61.845-35.733-84.245zM480 309.312c0-17.685 14.315-32 32-32s32 14.315 32 32v256c0 17.685-14.315 32-32 32s-32-14.315-32-32v-256zM512 746.645c-23.573 0-42.667-19.093-42.667-42.667s19.093-42.667 42.667-42.667 42.667 19.093 42.667 42.667c0 23.552-19.093 42.667-42.667 42.667z" + ], + "attrs": [ + {} + ], + "isMulticolor": false, + "isMulticolor2": false, + "grid": 0, + "tags": [ + "warning_filled" + ] + }, + { + "id": 1, + "paths": [ + "M512 85.333c-235.263 0-426.667 191.404-426.667 426.667s191.404 426.667 426.667 426.667c235.263 0 426.667-191.404 426.667-426.667s-191.404-426.667-426.667-426.667zM512 149.333c200.674 0 362.667 161.992 362.667 362.667s-161.992 362.667-362.667 362.667c-200.674 0-362.667-161.992-362.667-362.667s161.992-362.667 362.667-362.667zM511.5 298.208c-17.459 0.281-31.503 14.5-31.503 31.999 0 0.161 0.001 0.323 0.004 0.483l-0-0.024v213.333c-0.002 0.135-0.003 0.293-0.003 0.453 0 17.675 14.328 32.003 32.003 32.003s32.003-14.328 32.003-32.003c0-0.159-0.001-0.318-0.003-0.477l0 0.024v-213.333c0.002-0.137 0.003-0.298 0.003-0.459 0-17.675-14.328-32.003-32.003-32.003-0.176 0-0.351 0.001-0.527 0.004l0.026-0zM512 640c-23.564 0-42.667 19.103-42.667 42.667s19.103 42.667 42.667 42.667v0c23.564 0 42.667-19.103 42.667-42.667s-19.103-42.667-42.667-42.667v0z" + ], + "attrs": [ + {} + ], + "isMulticolor": false, + "isMulticolor2": false, + "grid": 0, + "tags": [ + "warning_round" + ] + }, + { + "id": 0, + "paths": [ + "M866.133 264.533h-725.333c0-38.4 34.133-72.533 72.533-72.533h584.533c38.4 0 68.267 34.133 68.267 72.533z", + "M921.6 362.667c-4.267-38.4-34.133-64-72.533-64h-686.933c-38.4 0-68.267 25.6-72.533 64 0 4.267 0 4.267 0 8.533v477.867c0 38.4 29.867 68.267 72.533 68.267h691.2c38.4 0 68.267-29.867 72.533-68.267v-477.867c-4.267-4.267-4.267-8.533-4.267-8.533zM849.067 844.8h-686.933v-473.6h686.933v473.6z", + "M819.2 162.133h-627.2c0-38.4 34.133-72.533 72.533-72.533h477.867c42.667 0 76.8 34.133 76.8 72.533z", + "M89.6 362.667c0 4.267 0 4.267 0 8.533v-8.533z", + "M921.6 362.667v8.533c0-4.267 0-8.533 0-8.533v0z", + "M657.067 644.267l-123.733 128c-4.267 4.267-8.533 4.267-12.8 8.533 0 0-4.267 0-4.267 0-4.267 0-4.267 0-8.533 0h-8.533c0 0-4.267 0-4.267 0l-12.8-8.533-123.733-128c-12.8-4.267-17.067-12.8-17.067-25.6 0-8.533 4.267-17.067 12.8-25.6 12.8-12.8 38.4-12.8 51.2 0l64 64v-192c0-21.333 17.067-34.133 38.4-34.133s38.4 17.067 38.4 34.133v192l64-64c8.533-8.533 17.067-12.8 25.6-12.8s17.067 4.267 25.6 12.8c8.533 17.067 8.533 38.4-4.267 51.2z" + ], + "attrs": [ + {}, + {}, + {}, + {}, + {}, + {} + ], + "isMulticolor": false, + "isMulticolor2": false, + "grid": 0, + "tags": [ + "winget" + ] + }, + { + "id": 21, + "paths": [ + "M505.244 168.391c-185.316 0-336.142 150.898-336.142 336.142s150.898 336.142 336.142 336.142 336.142-150.898 336.142-336.142-150.898-336.142-336.142-336.142zM504.747 198.258c11.928 0.319 21.476 10.095 21.476 22.108 0 0.003-0 0.005-0 0.008l0-0c0 12.214-9.901 22.116-22.116 22.116s-22.116-9.901-22.116-22.116v0c-0-0.003-0-0.006-0-0.009 0-12.214 9.901-22.116 22.116-22.116 0.225 0 0.449 0.003 0.673 0.010l-0.033-0.001zM555.378 234.667c80.287 15.42 146.83 64.365 185.612 131.384l0.699 1.309-26.098 58.88c-4.48 10.169 0.142 22.116 10.24 26.667l50.204 22.258c0.847 8.059 1.33 17.411 1.33 26.875 0 7.159-0.276 14.254-0.819 21.274l0.058-0.931h-27.947c-2.773 0-3.911 1.849-3.911 4.551v12.8c0 30.151-16.996 36.764-31.929 38.4-14.222 1.636-29.938-5.973-31.929-14.649-8.391-47.147-22.329-57.173-44.373-74.596 27.378-17.351 55.822-43.022 55.822-77.298 0-37.049-25.387-60.373-42.667-71.822-24.32-16-51.2-19.2-58.453-19.2h-288.711c38.978-43.411 91.328-74.114 150.533-85.624l1.716-0.278 34.062 35.698c7.68 8.036 20.409 8.391 28.444 0.64zM241.067 398.364c11.936 0.356 21.476 10.117 21.476 22.106 0 0.003-0 0.007-0 0.010l0-0.001c0 12.214-9.901 22.116-22.116 22.116s-22.116-9.901-22.116-22.116v0c-0-0.003-0-0.006-0-0.009 0-12.214 9.901-22.116 22.116-22.116 0.225 0 0.449 0.003 0.673 0.010l-0.033-0.001zM768.356 399.36c11.936 0.356 21.476 10.117 21.476 22.106 0 0.003-0 0.007-0 0.010l0-0.001c0 12.214-9.901 22.116-22.116 22.116s-22.116-9.901-22.116-22.116v0c-0-0.003-0-0.006-0-0.009 0-12.214 9.901-22.116 22.116-22.116 0.225 0 0.449 0.003 0.673 0.010l-0.033-0.001zM282.738 402.916h38.542v173.796h-77.796c-6.605-22.332-10.406-47.99-10.406-74.535 0-10.342 0.577-20.55 1.7-30.592l-0.112 1.234 47.644-21.191c10.169-4.551 14.791-16.427 10.24-26.596zM443.591 404.764h91.804c4.764 0 33.493 5.476 33.493 27.022 0 17.849-22.044 24.249-40.178 24.249h-85.191zM443.591 529.636h70.329c6.4 0 34.347 1.849 43.236 37.547 2.773 10.951 8.96 46.649 13.156 58.098 4.196 12.8 21.191 38.4 39.324 38.4h114.773c-8.071 10.75-16.321 20.263-25.184 29.166l0.010-0.010-46.72-10.027c-10.88-2.347-21.618 4.622-23.964 15.502l-11.093 51.769c-32.984 15.315-71.596 24.249-112.295 24.249-41.598 0-81.016-9.333-116.275-26.019l1.654 0.704-11.093-51.769c-2.347-10.88-13.013-17.849-23.893-15.502l-45.724 9.813c-8.229-8.481-15.969-17.573-23.093-27.15l-0.516-0.726h222.364c2.489 0 4.196-0.427 4.196-2.773v-78.649c0-2.276-1.707-2.773-4.196-2.773h-65.067zM340.978 709.76c11.936 0.356 21.476 10.117 21.476 22.106 0 0.003-0 0.007-0 0.010l0-0.001c0 12.214-9.901 22.116-22.116 22.116s-22.116-9.901-22.116-22.116v0c-0-0.003-0-0.006-0-0.009 0-12.214 9.901-22.116 22.116-22.116 0.225 0 0.449 0.003 0.673 0.010l-0.033-0.001zM668.444 710.756c11.936 0.356 21.476 10.117 21.476 22.106 0 0.003-0 0.007-0 0.010l0-0.001c0 12.214-9.901 22.116-22.116 22.116s-22.116-9.901-22.116-22.116v0c-0-0.003-0-0.006-0-0.009 0-12.214 9.901-22.116 22.116-22.116 0.225 0 0.449 0.003 0.673 0.010l-0.033-0.001z", + "M822.613 504.533v0c0-175.278-142.091-317.369-317.369-317.369v0c-175.278 0-317.369 142.091-317.369 317.369v0c0 175.278 142.091 317.369 317.369 317.369v0c175.278 0 317.369-142.091 317.369-317.369zM816.64 473.884l49.493 30.649-49.493 30.649 42.524 39.751-54.471 20.409 33.991 47.289-57.529 9.387 24.178 53.049-58.24-2.062 13.369 56.747-56.747-13.369 2.062 58.24-53.049-24.178-9.387 57.529-47.289-33.991-20.409 54.471-39.751-42.524-30.649 49.493-30.649-49.493-39.751 42.524-20.409-54.471-47.289 33.991-9.387-57.529-53.049 24.178 2.062-58.24-56.747 13.369 13.369-56.747-58.24 2.062 24.178-53.049-57.529-9.387 33.991-47.289-54.471-20.409 42.524-39.751-49.493-30.649 49.493-30.649-42.524-39.751 54.471-20.409-33.991-47.289 57.529-9.387-24.178-53.049 58.24 2.062-13.369-56.747 56.747 13.369-2.062-58.24 53.049 24.178 9.387-57.529 47.289 33.991 20.409-54.471 39.751 42.524 30.649-49.493 30.649 49.493 39.751-42.524 20.409 54.471 47.289-33.991 9.387 57.529 53.049-24.178-2.062 58.24 56.747-13.369-13.369 56.747 58.24-2.062-24.178 53.049 57.529 9.387-33.991 47.289 54.471 20.409z" + ], + "attrs": [ + {}, + { + "stroke": "rgb(0, 0, 0)", + "strokeLinejoin": "round", + "strokeLinecap": "round", + "strokeMiterlimit": "4", + "strokeWidth": 21.333333333333332 + } + ], + "isMulticolor": false, + "isMulticolor2": true, + "grid": 0, + "tags": [ + "rust" + ] + }, + { + "id": 5, + "paths": [ + "M96.894 488.139l30.623-105.298c4.166-14.394 8.703-26.481 14.032-38.13l-0.701 1.71c9.153-19.732 19.108-36.626 30.49-52.422l-0.639 0.933c13.686-19.485 27.964-36.584 43.528-52.417l-0.056 0.058c32.151-34.054 68.522-63.602 108.409-87.958l2.298-1.304c55.048-33.662 121.265-54.376 192.163-56.404l0.562-0.013c1.409-0.019 3.073-0.030 4.74-0.030 52.164 0 101.837 10.667 146.957 29.939l-2.444-0.928c51.78 21.543 72.26 45.404 83.176 61.537 15.218 20.851 24.348 46.988 24.348 75.258 0 0.338-0.001 0.676-0.004 1.014l0-0.052c-0.731 22.11-6.951 42.621-17.33 60.406l0.328-0.609c-11.59 20.977-27.649 38.179-46.984 50.771l-0.545 0.333-1.159 0.676c-18.321 10.649-40.016 17.606-63.174 19.292l-0.488 0.028c-5.519 0.458-11.947 0.718-18.435 0.718-27.075 0-53.089-4.543-77.322-12.907l1.665 0.5c-36.13-10.24-54.774-17.292-69.651-22.895-9.333-3.886-20.918-7.753-32.808-10.865l-1.969-0.438c-23.108-6.065-49.638-9.547-76.98-9.547-12.223 0-24.283 0.696-36.143 2.050l1.45-0.135c-48.474 4.262-92.396 20.733-129.591 46.287l0.914-0.594c-11.504 8.071-21.597 16.447-30.971 25.559l0.058-0.056zM369.413 281.117c32.331 0.021 63.689 4.142 93.596 11.872l-2.595-0.569c16.318 4.153 29.996 8.714 43.24 14.12l-2.184-0.788c14.008 5.217 31.3 11.689 65.014 21.253 31.106 8.791 50.041 12.558 73.129 9.66 14.631-1.115 28.052-5.386 39.881-12.127l-0.467 0.245c11.511-7.551 20.788-17.601 27.223-29.423l0.213-0.427 0.483-0.966c5.59-9.171 9.11-20.158 9.655-31.922l0.006-0.151c-0.065-15.748-5.24-30.274-13.95-42.021l0.136 0.192c-4.347-6.472-16.229-23.861-57.962-41.25-36.083-15.647-78.107-24.748-122.256-24.748-1.17 0-2.339 0.006-3.506 0.019l0.178-0.002c-60.916 1.811-117.335 19.538-165.698 49.139l1.472-0.838c-37.838 22.893-70.441 49.348-98.995 79.659l-0.217 0.233c-7.438 7.825-14.008 15.553-20.77 23.378 27.445-11.407 59.247-19.334 92.49-22.23l1.216-0.085c12.201-1.413 26.34-2.22 40.667-2.222l0.003-0z", + "M207.118 629.18c-2.898 0-5.796 0-8.791 0-52.295-6.26-93.107-48.098-97.733-100.335l-0.030-0.423-1.063-12.172 7.922-9.66c19.914-23.203 40.173-44.288 61.547-64.193l0.473-0.435c28.305-26.276 47.046-43.665 77.283-57.962 21.638-10.701 46.79-18.279 73.317-21.346l1.068-0.1 31.493-3.574 0.676 31.686c0.067 2.58 0.105 5.618 0.105 8.665 0 13.76-0.775 27.339-2.284 40.695l0.15-1.638c-3.381 34.777-7.342 74.482-31.396 112.93-15.070 24.151-54.774 77.863-112.737 77.863zM160.555 534.315c1.701 5.485 4.068 10.261 7.068 14.564l-0.112-0.17c8.44 12.125 21.588 20.469 36.739 22.385l0.26 0.027c30.43 2.512 57.962-37.675 65.787-50.137 16.809-27.049 19.804-56.996 22.895-88.296l0.58-5.12c-8.826 2.829-16.211 5.841-23.318 9.333l1.002-0.445c-21.060 10.24-34.391 22.219-62.599 48.302-16.809 15.746-33.038 32.266-48.302 49.558z", + "M510.261 927.686c-0.332 0.001-0.725 0.002-1.118 0.002-52.112 0-101.735-10.657-146.808-29.91l2.441 0.927c-51.297-21.349-71.97-45.017-82.886-61.054-15.399-21.164-24.635-47.675-24.635-76.342 0-0.161 0-0.322 0.001-0.483l-0 0.025c0.744-22.077 6.962-42.553 17.33-60.309l-0.328 0.608c11.554-20.975 27.582-38.178 46.891-50.772l0.542-0.331 1.159-0.676c18.364-10.595 40.081-17.544 63.25-19.29l0.508-0.031c5.263-0.412 11.396-0.647 17.585-0.647 27.452 0 53.825 4.623 78.382 13.133l-1.681-0.507c36.033 10.24 54.581 17.292 69.555 22.895 9.333 3.886 20.918 7.753 32.808 10.865l1.969 0.438c23.085 6.066 49.588 9.549 76.904 9.549 12.216 0 24.269-0.697 36.121-2.052l-1.448 0.135c48.464-4.405 92.336-20.965 129.489-46.576l-0.909 0.592c11.423-8.069 21.453-16.444 30.766-25.549l-0.046 0.045 77.283-76.22-29.078 104.718c-4.148 14.505-8.753 26.755-14.202 38.535l0.677-1.632c-8.984 19.676-18.882 36.546-30.263 52.272l0.606-0.879c-13.73 19.231-28.034 36.14-43.591 51.802l0.022-0.023c-32.183 34.093-68.622 63.647-108.6 87.962l-2.301 1.3c-55.143 33.952-121.504 54.929-192.59 57.174l-0.618 0.015zM352.411 698.735c-11.456 7.58-20.696 17.624-27.124 29.421l-0.214 0.43v0.966c-5.59 9.171-9.11 20.158-9.655 31.922l-0.006 0.151c-0.001 0.158-0.002 0.344-0.002 0.531 0 15.478 5 29.787 13.473 41.402l-0.139-0.2 0.58 0.869c3.864 5.7 15.746 23.088 57.962 40.477 36.065 15.647 78.069 24.749 122.199 24.749 1.19 0 2.379-0.007 3.567-0.020l-0.181 0.002c60.917-1.801 117.338-19.53 165.697-49.139l-1.47 0.837c37.838-23.003 70.462-49.481 99.101-79.767l0.207-0.221c7.149-7.245 13.911-14.587 20.287-22.219-27.475 11.348-59.311 19.24-92.579 22.133l-1.224 0.086c-12.158 1.417-26.244 2.225-40.518 2.225-32.242 0-63.521-4.124-93.337-11.873l2.571 0.567c-16.318-4.153-29.996-8.714-43.24-14.12l2.184 0.788c-14.008-5.217-31.3-11.786-65.014-21.253-31.106-8.791-50.041-12.558-73.129-10.143-14.785 0.876-28.433 4.994-40.485 11.648l0.491-0.248z", + "M679.414 664.731l-0.773-31.589c-0.072-2.869-0.113-6.248-0.113-9.637 0-13.341 0.638-26.534 1.884-39.549l-0.128 1.657c3.478-34.971 7.438-74.578 31.589-113.22 32.749-53.035 77.283-81.244 121.045-77.283 52.429 5.983 93.454 47.77 98.214 100.036l0.032 0.432 1.063 12.172-7.922 9.66c-19.936 23.201-40.258 44.289-61.714 64.171l-0.499 0.457c-29.561 27.339-47.432 43.858-77.283 57.962-21.609 10.715-46.73 18.294-73.228 21.347l-1.060 0.099zM824.32 452.782c-28.981 0-55.354 38.158-62.792 50.234-17.002 27.146-20.094 57.962-22.992 88.296 0 1.739 0 3.478-0.483 5.217 8.908-2.944 16.288-5.985 23.412-9.468l-1.096 0.484c21.832-10.53 35.55-23.185 62.792-48.302 16.906-15.65 33.135-32.169 48.302-49.461-1.676-5.485-4.046-10.264-7.063-14.556l0.108 0.162c-8.5-12.19-21.765-20.552-37.038-22.387l-0.251-0.025z" + ], + "attrs": [ + {}, + {}, + {}, + {} + ], + "width": 1032, + "grid": 0, + "tags": [ + "vcpkg" + ], + "isMulticolor": false, + "isMulticolor2": false + } + ], + "invisible": false, + "colorThemes": [] + } + ], + "preferences": { + "showGlyphs": true, + "showQuickUse": true, + "showQuickUse2": true, + "showSVGs": true, + "fontPref": { + "prefix": "icon-", + "metadata": { + "fontFamily": "UniGetUI-Symbols", + "majorVersion": 1, + "minorVersion": 2 + }, + "metrics": { + "emSize": 1024, + "baseline": 6.25, + "whitespace": 50 + }, + "embed": false, + "hideFormats": false, + "autoHost": false, + "showVersion": false, + "showMetadata": false, + "showMetrics": false, + "showSelector": false + }, + "imagePref": { + "prefix": "icon-", + "png": true, + "useClassSelector": true, + "color": 0, + "bgColor": 16777215, + "classSelector": ".icon", + "name": "UniGetUI-Symbols", + "height": 32, + "columns": 16, + "margin": 16 + }, + "historySize": 50, + "showCodes": true, + "gridSize": 16, + "quickUsageToken": { + "UntitledProject": "YTZmOTliNmFmMyMxNzMxMjc2MjI4I3RKQ25ENFZzM0VwS29RaWxEbUwwR1VoSk1mUkxPZzduMm5ON1NtcUphSE1Z" + } + }, + "uid": -1 +} \ No newline at end of file diff --git a/src/SharedAssets/Assets/Symbols/id.svg b/src/SharedAssets/Assets/Symbols/id.svg new file mode 100644 index 0000000..0761b53 --- /dev/null +++ b/src/SharedAssets/Assets/Symbols/id.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/SharedAssets/Assets/Symbols/info_round.svg b/src/SharedAssets/Assets/Symbols/info_round.svg new file mode 100644 index 0000000..86b2930 --- /dev/null +++ b/src/SharedAssets/Assets/Symbols/info_round.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/SharedAssets/Assets/Symbols/installed.svg b/src/SharedAssets/Assets/Symbols/installed.svg new file mode 100644 index 0000000..0becaa0 --- /dev/null +++ b/src/SharedAssets/Assets/Symbols/installed.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/SharedAssets/Assets/Symbols/installed_filled.svg b/src/SharedAssets/Assets/Symbols/installed_filled.svg new file mode 100644 index 0000000..da933ed --- /dev/null +++ b/src/SharedAssets/Assets/Symbols/installed_filled.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/SharedAssets/Assets/Symbols/interactive.svg b/src/SharedAssets/Assets/Symbols/interactive.svg new file mode 100644 index 0000000..81c0379 --- /dev/null +++ b/src/SharedAssets/Assets/Symbols/interactive.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/SharedAssets/Assets/Symbols/launch.svg b/src/SharedAssets/Assets/Symbols/launch.svg new file mode 100644 index 0000000..b005a43 --- /dev/null +++ b/src/SharedAssets/Assets/Symbols/launch.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/SharedAssets/Assets/Symbols/loading.svg b/src/SharedAssets/Assets/Symbols/loading.svg new file mode 100644 index 0000000..56be414 --- /dev/null +++ b/src/SharedAssets/Assets/Symbols/loading.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/SharedAssets/Assets/Symbols/loading_filled.svg b/src/SharedAssets/Assets/Symbols/loading_filled.svg new file mode 100644 index 0000000..34c7fde --- /dev/null +++ b/src/SharedAssets/Assets/Symbols/loading_filled.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/SharedAssets/Assets/Symbols/local_pc.svg b/src/SharedAssets/Assets/Symbols/local_pc.svg new file mode 100644 index 0000000..3e7838e --- /dev/null +++ b/src/SharedAssets/Assets/Symbols/local_pc.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/SharedAssets/Assets/Symbols/megaphone.svg b/src/SharedAssets/Assets/Symbols/megaphone.svg new file mode 100644 index 0000000..3e98201 --- /dev/null +++ b/src/SharedAssets/Assets/Symbols/megaphone.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/SharedAssets/Assets/Symbols/ms_store.svg b/src/SharedAssets/Assets/Symbols/ms_store.svg new file mode 100644 index 0000000..b37e6af --- /dev/null +++ b/src/SharedAssets/Assets/Symbols/ms_store.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/SharedAssets/Assets/Symbols/node.svg b/src/SharedAssets/Assets/Symbols/node.svg new file mode 100644 index 0000000..b669412 --- /dev/null +++ b/src/SharedAssets/Assets/Symbols/node.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/SharedAssets/Assets/Symbols/open_folder.svg b/src/SharedAssets/Assets/Symbols/open_folder.svg new file mode 100644 index 0000000..7f7b672 --- /dev/null +++ b/src/SharedAssets/Assets/Symbols/open_folder.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/SharedAssets/Assets/Symbols/options.svg b/src/SharedAssets/Assets/Symbols/options.svg new file mode 100644 index 0000000..c56201a --- /dev/null +++ b/src/SharedAssets/Assets/Symbols/options.svg @@ -0,0 +1,23 @@ + + + + + + diff --git a/src/SharedAssets/Assets/Symbols/package.svg b/src/SharedAssets/Assets/Symbols/package.svg new file mode 100644 index 0000000..01cc9d8 --- /dev/null +++ b/src/SharedAssets/Assets/Symbols/package.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/SharedAssets/Assets/Symbols/package_managers.svg b/src/SharedAssets/Assets/Symbols/package_managers.svg new file mode 100644 index 0000000..c405c00 --- /dev/null +++ b/src/SharedAssets/Assets/Symbols/package_managers.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/SharedAssets/Assets/Symbols/pacman.svg b/src/SharedAssets/Assets/Symbols/pacman.svg new file mode 100644 index 0000000..c5ab7ad --- /dev/null +++ b/src/SharedAssets/Assets/Symbols/pacman.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/SharedAssets/Assets/Symbols/pin.svg b/src/SharedAssets/Assets/Symbols/pin.svg new file mode 100644 index 0000000..97773e7 --- /dev/null +++ b/src/SharedAssets/Assets/Symbols/pin.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/SharedAssets/Assets/Symbols/pin_filled.svg b/src/SharedAssets/Assets/Symbols/pin_filled.svg new file mode 100644 index 0000000..ae72b16 --- /dev/null +++ b/src/SharedAssets/Assets/Symbols/pin_filled.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/SharedAssets/Assets/Symbols/powershell.svg b/src/SharedAssets/Assets/Symbols/powershell.svg new file mode 100644 index 0000000..f5a7b5f --- /dev/null +++ b/src/SharedAssets/Assets/Symbols/powershell.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/SharedAssets/Assets/Symbols/python.svg b/src/SharedAssets/Assets/Symbols/python.svg new file mode 100644 index 0000000..461be9a --- /dev/null +++ b/src/SharedAssets/Assets/Symbols/python.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/SharedAssets/Assets/Symbols/reload.svg b/src/SharedAssets/Assets/Symbols/reload.svg new file mode 100644 index 0000000..91c3eeb --- /dev/null +++ b/src/SharedAssets/Assets/Symbols/reload.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/SharedAssets/Assets/Symbols/rust.svg b/src/SharedAssets/Assets/Symbols/rust.svg new file mode 100644 index 0000000..1a6c762 --- /dev/null +++ b/src/SharedAssets/Assets/Symbols/rust.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/SharedAssets/Assets/Symbols/sandclock.svg b/src/SharedAssets/Assets/Symbols/sandclock.svg new file mode 100644 index 0000000..a98bce7 --- /dev/null +++ b/src/SharedAssets/Assets/Symbols/sandclock.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/SharedAssets/Assets/Symbols/save_as.svg b/src/SharedAssets/Assets/Symbols/save_as.svg new file mode 100644 index 0000000..07b67ff --- /dev/null +++ b/src/SharedAssets/Assets/Symbols/save_as.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/SharedAssets/Assets/Symbols/scoop.svg b/src/SharedAssets/Assets/Symbols/scoop.svg new file mode 100644 index 0000000..cd6ccee --- /dev/null +++ b/src/SharedAssets/Assets/Symbols/scoop.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/SharedAssets/Assets/Symbols/search.svg b/src/SharedAssets/Assets/Symbols/search.svg new file mode 100644 index 0000000..d97005d --- /dev/null +++ b/src/SharedAssets/Assets/Symbols/search.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/SharedAssets/Assets/Symbols/search_filled.svg b/src/SharedAssets/Assets/Symbols/search_filled.svg new file mode 100644 index 0000000..ceb576e --- /dev/null +++ b/src/SharedAssets/Assets/Symbols/search_filled.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/SharedAssets/Assets/Symbols/settings.svg b/src/SharedAssets/Assets/Symbols/settings.svg new file mode 100644 index 0000000..610ce86 --- /dev/null +++ b/src/SharedAssets/Assets/Symbols/settings.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/SharedAssets/Assets/Symbols/share.svg b/src/SharedAssets/Assets/Symbols/share.svg new file mode 100644 index 0000000..11409eb --- /dev/null +++ b/src/SharedAssets/Assets/Symbols/share.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/SharedAssets/Assets/Symbols/skip.svg b/src/SharedAssets/Assets/Symbols/skip.svg new file mode 100644 index 0000000..5ce9bca --- /dev/null +++ b/src/SharedAssets/Assets/Symbols/skip.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/SharedAssets/Assets/Symbols/snap.svg b/src/SharedAssets/Assets/Symbols/snap.svg new file mode 100644 index 0000000..8d883f2 --- /dev/null +++ b/src/SharedAssets/Assets/Symbols/snap.svg @@ -0,0 +1,2 @@ + +Snapcraft icon diff --git a/src/SharedAssets/Assets/Symbols/steam.svg b/src/SharedAssets/Assets/Symbols/steam.svg new file mode 100644 index 0000000..fc9ef33 --- /dev/null +++ b/src/SharedAssets/Assets/Symbols/steam.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/SharedAssets/Assets/Symbols/success_round.svg b/src/SharedAssets/Assets/Symbols/success_round.svg new file mode 100644 index 0000000..1b60f79 --- /dev/null +++ b/src/SharedAssets/Assets/Symbols/success_round.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/SharedAssets/Assets/Symbols/sys_tray.svg b/src/SharedAssets/Assets/Symbols/sys_tray.svg new file mode 100644 index 0000000..6173a20 --- /dev/null +++ b/src/SharedAssets/Assets/Symbols/sys_tray.svg @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/src/SharedAssets/Assets/Symbols/uac.svg b/src/SharedAssets/Assets/Symbols/uac.svg new file mode 100644 index 0000000..8b6d727 --- /dev/null +++ b/src/SharedAssets/Assets/Symbols/uac.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/SharedAssets/Assets/Symbols/undelete.svg b/src/SharedAssets/Assets/Symbols/undelete.svg new file mode 100644 index 0000000..ba9672b --- /dev/null +++ b/src/SharedAssets/Assets/Symbols/undelete.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/SharedAssets/Assets/Symbols/update.svg b/src/SharedAssets/Assets/Symbols/update.svg new file mode 100644 index 0000000..eac6062 --- /dev/null +++ b/src/SharedAssets/Assets/Symbols/update.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/SharedAssets/Assets/Symbols/upgradable.svg b/src/SharedAssets/Assets/Symbols/upgradable.svg new file mode 100644 index 0000000..198ef45 --- /dev/null +++ b/src/SharedAssets/Assets/Symbols/upgradable.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/SharedAssets/Assets/Symbols/upgradable_filled.svg b/src/SharedAssets/Assets/Symbols/upgradable_filled.svg new file mode 100644 index 0000000..abfa1ce --- /dev/null +++ b/src/SharedAssets/Assets/Symbols/upgradable_filled.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/SharedAssets/Assets/Symbols/uplay.svg b/src/SharedAssets/Assets/Symbols/uplay.svg new file mode 100644 index 0000000..efcd987 --- /dev/null +++ b/src/SharedAssets/Assets/Symbols/uplay.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/SharedAssets/Assets/Symbols/vcpkg.svg b/src/SharedAssets/Assets/Symbols/vcpkg.svg new file mode 100644 index 0000000..80a7a9a --- /dev/null +++ b/src/SharedAssets/Assets/Symbols/vcpkg.svg @@ -0,0 +1,18 @@ + + + + + + + + \ No newline at end of file diff --git a/src/SharedAssets/Assets/Symbols/version.svg b/src/SharedAssets/Assets/Symbols/version.svg new file mode 100644 index 0000000..31dacc7 --- /dev/null +++ b/src/SharedAssets/Assets/Symbols/version.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/SharedAssets/Assets/Symbols/warning.svg b/src/SharedAssets/Assets/Symbols/warning.svg new file mode 100644 index 0000000..9786d77 --- /dev/null +++ b/src/SharedAssets/Assets/Symbols/warning.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/SharedAssets/Assets/Symbols/warning_filled.svg b/src/SharedAssets/Assets/Symbols/warning_filled.svg new file mode 100644 index 0000000..7f92185 --- /dev/null +++ b/src/SharedAssets/Assets/Symbols/warning_filled.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/SharedAssets/Assets/Symbols/warning_round.svg b/src/SharedAssets/Assets/Symbols/warning_round.svg new file mode 100644 index 0000000..46a47eb --- /dev/null +++ b/src/SharedAssets/Assets/Symbols/warning_round.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/SharedAssets/Assets/Symbols/winget.svg b/src/SharedAssets/Assets/Symbols/winget.svg new file mode 100644 index 0000000..67c5a9f --- /dev/null +++ b/src/SharedAssets/Assets/Symbols/winget.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + diff --git a/src/SharedAssets/Assets/Utilities/install_scoop.cmd b/src/SharedAssets/Assets/Utilities/install_scoop.cmd new file mode 100644 index 0000000..fa90e52 --- /dev/null +++ b/src/SharedAssets/Assets/Utilities/install_scoop.cmd @@ -0,0 +1,19 @@ +@echo off +SET unigetuipath=%~dp0..\..\UniGetUI.exe +set pwsh=C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe +echo Scoop Installer Assistant - UniGetUI +echo This script will install Scoop and its dependencies, since it appears that they are not installed on your machine. +echo|set/p="Press to continue or CLOSE this window to abort this process"&runas/u: "">NUL +cls +%pwsh% Set-ExecutionPolicy RemoteSigned -Scope CurrentUser +%pwsh% -ExecutionPolicy ByPass -File "%~dp0\install_scoop.ps1" +if %errorlevel% equ 0 ( + echo UniGetUI will be restarted to continue. + pause + taskkill /im unigetui.exe /f + start "" /b "%unigetuipath%" /i +) else ( + pause + taskkill /im unigetui.exe /f + start "" /b "%unigetuipath%" /i +) diff --git a/src/SharedAssets/Assets/Utilities/install_scoop.ps1 b/src/SharedAssets/Assets/Utilities/install_scoop.ps1 new file mode 100644 index 0000000..8a7dc6b --- /dev/null +++ b/src/SharedAssets/Assets/Utilities/install_scoop.ps1 @@ -0,0 +1,19 @@ +If (Get-Command scoop -ErrorAction SilentlyContinue) { + Write-Output "Scoop is already installed." + exit 1 +} + +Write-Output "Installing scoop..." + +iex "& {$(irm get.scoop.sh)} -RunAsAdmin" + +$Env:Path = [System.Environment]::GetEnvironmentVariable("Path","Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path","User") + +If (-Not (Get-Command git -ErrorAction SilentlyContinue)) { + Write-Output "Installing git..." + scoop install git +} + +scoop install scoop-search + +Write-Output "Done!" diff --git a/src/SharedAssets/Assets/Utilities/scoop_cleanup.cmd b/src/SharedAssets/Assets/Utilities/scoop_cleanup.cmd new file mode 100644 index 0000000..4d2dc52 --- /dev/null +++ b/src/SharedAssets/Assets/Utilities/scoop_cleanup.cmd @@ -0,0 +1,12 @@ +@echo off +echo This script will clean the Scoop cache and run the cleanup command. +echo|set/p="Press to continue or CLOSE this window to abort this process"&runas/u: "">NUL +cls +echo Cleaning Scoop cache... +call scoop cleanup --all +call scoop cleanup --all --global +call scoop cache rm --all +call scoop cache rm --all --global +echo Done! +pause +exit diff --git a/src/SharedAssets/Assets/Utilities/uninstall_scoop.cmd b/src/SharedAssets/Assets/Utilities/uninstall_scoop.cmd new file mode 100644 index 0000000..4720fba --- /dev/null +++ b/src/SharedAssets/Assets/Utilities/uninstall_scoop.cmd @@ -0,0 +1,21 @@ +@echo off +SET unigetuipath=%~dp0..\..\UniGetUI.exe +echo This script will remove scoop from your machine. +echo Removing Scoop implies removing all Scoop installed packages, buckets and preferences, and might also erase valuable user data related to the affected packages +echo|set/p="Press to continue or CLOSE this window to abort this process"&runas/u: "">NUL +cls +echo|set/p="ALL YOUR SCOOP PACKAGES WILL BE PERMANENTLY DELETED. Press to continue or CLOSE this window to abort this process."&runas/u: "">NUL +cls +echo. +echo Uninstalling scoop... +powershell -ExecutionPolicy ByPass -Command "scoop uninstall -p scoop" +if %errorlevel% equ 0 ( + echo UniGetUI will be restarted to continue. + pause + taskkill /im unigetui.exe /f + start "" /b "%unigetuipath%" /i +) else ( + pause + taskkill /im unigetui.exe /f + start "" /b "%unigetuipath%" /i +) diff --git a/src/SharedAssets/Assets/Wide310x150Logo.png b/src/SharedAssets/Assets/Wide310x150Logo.png new file mode 100644 index 0000000..208d554 Binary files /dev/null and b/src/SharedAssets/Assets/Wide310x150Logo.png differ diff --git a/src/SharedAssets/icon.ico b/src/SharedAssets/icon.ico new file mode 100644 index 0000000..c32fc09 Binary files /dev/null and b/src/SharedAssets/icon.ico differ diff --git a/src/UniGetUI.Avalonia.slnx b/src/UniGetUI.Avalonia.slnx new file mode 100644 index 0000000..9d0b8ab --- /dev/null +++ b/src/UniGetUI.Avalonia.slnx @@ -0,0 +1,240 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/UniGetUI.Avalonia/.vscode/launch.json b/src/UniGetUI.Avalonia/.vscode/launch.json new file mode 100644 index 0000000..9e5ba13 --- /dev/null +++ b/src/UniGetUI.Avalonia/.vscode/launch.json @@ -0,0 +1,19 @@ +{ + "configurations": [ + { + "name": "UniGetUI.Avalonia (Debug)", + "type": "coreclr", + "request": "launch", + "preLaunchTask": "build UniGetUI.Avalonia (Debug)", + "program": "${workspaceFolder}/bin/arm64/Debug/net10.0/UniGetUI.Avalonia", + "args": [], + "cwd": "${workspaceFolder}/bin/arm64/Debug/net10.0/", + "console": "integratedTerminal", + "stopAtEntry": false, + "env": { + "UNIGETUI_GITHUB_CLIENT_ID": "", + "UNIGETUI_GITHUB_CLIENT_SECRET": "" + } + } + ] +} diff --git a/src/UniGetUI.Avalonia/App.axaml b/src/UniGetUI.Avalonia/App.axaml new file mode 100644 index 0000000..3b30430 --- /dev/null +++ b/src/UniGetUI.Avalonia/App.axaml @@ -0,0 +1,17 @@ + + + + + + + + + + + + diff --git a/src/UniGetUI.Avalonia/App.axaml.cs b/src/UniGetUI.Avalonia/App.axaml.cs new file mode 100644 index 0000000..ccb15dc --- /dev/null +++ b/src/UniGetUI.Avalonia/App.axaml.cs @@ -0,0 +1,251 @@ +using System; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.IO; +using Avalonia; +using Avalonia.Controls.ApplicationLifetimes; +using Avalonia.Markup.Xaml; +using Avalonia.Markup.Xaml.Styling; +using Avalonia.Styling; +using Avalonia.Threading; +#if AVALONIA_DIAGNOSTICS_ENABLED +using Avalonia.Diagnostics; +#endif +using UniGetUI.Avalonia.Assets.Styles; +using UniGetUI.Avalonia.Infrastructure; +using UniGetUI.Avalonia.Views; +using UniGetUI.Avalonia.Views.DialogPages; +using UniGetUI.Core.Data; +using UniGetUI.Core.Logging; +using UniGetUI.PackageEngine; +using CoreSettings = global::UniGetUI.Core.SettingsEngine.Settings; + +namespace UniGetUI.Avalonia; + +public partial class App : Application +{ + public override void Initialize() + { + AvaloniaXamlLoader.Load(this); + + // Windows 11 Mica look is opt-in per environment: only merge the translucent + // surface overrides when Mica is actually usable (Win11 + transparency on). + // macOS, Linux, Windows 10, and transparency-off all keep the solid Styles.Common look. + if (MicaWindowHelper.IsMicaEnabled()) + ApplyWindowsMicaStyling(); +#if AVALONIA_DIAGNOSTICS_ENABLED + this.AttachDeveloperTools(); +#endif + } + + private void ApplyWindowsMicaStyling() + { + Resources.MergedDictionaries.Add(new WindowsMicaStyles()); + // Give flyouts/menus/tooltips a native acrylic backdrop (DWM) so they blur + tint + // from behind and adapt to the theme. + MicaWindowHelper.EnableAcrylicPopups(); + } + + public override void OnFrameworkInitializationCompleted() + { + if (OperatingSystem.IsWindows()) + { + // Redirect WebView2 user-data folder to a writable temp location. + // Without this, WebView2 tries to write next to the executable in + // C:\Program Files\, which is read-only for non-admin users and + // causes UnauthorizedAccessException (E_ACCESSDENIED) on startup. + SetUpWebViewUserDataFolder(); + + // Safety net for NativeWebView (WebView2) initialization failures thrown + // asynchronously on the dispatcher. Without this the app crashes; with it + // the Help page shows a fallback "Open in browser" button. + Dispatcher.UIThread.UnhandledException += (_, e) => + { + if (e.Exception is InvalidOperationException { Message: var msg } + && msg.Contains("child window for native control host")) + { + e.Handled = true; + } + }; + } + + if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) + { + // Apply the saved theme before any window is shown so the splash + // appears in the user's preferred light/dark variant from the start. + ApplyTheme(CoreSettings.GetValue(CoreSettings.K.PreferredTheme)); + + // Show the splash before any heavy initialization. Skipped in daemon + // mode since the app isn't supposed to be visible at all. + SplashWindow? splash = null; + if (!CoreData.WasDaemon) + { + splash = new SplashWindow(); + splash.Show(); + } + + // Defer the rest of startup so the splash gets a chance to paint + // before we block the UI thread loading package managers and the + // main window XAML. Without this the splash window appears empty + // until init completes, defeating its purpose. + Dispatcher.UIThread.Post(() => StartMainWindow(desktop, splash), DispatcherPriority.Background); + } + + base.OnFrameworkInitializationCompleted(); + } + + private static void StartMainWindow(IClassicDesktopStyleApplicationLifetime desktop, SplashWindow? splash) + { + if (OperatingSystem.IsMacOS()) + { + // The Dock icon (incl. Default/Dark/Tinted/Clear styling) is provided by the .app bundle's + // AppIcon (scripts/macos/AppIcon.icon → Assets.car, via CFBundleIconName) and rendered by + // the system — for packaged releases and for Debug builds, which also build into a .app + // (see UniGetUI.Avalonia.csproj). There is nothing to do at runtime. + ProcessEnvironmentConfigurator.PrepareForCurrentPlatform(); + } + else + { + ProcessEnvironmentConfigurator.ApplyProxySettingsToProcess(); + } + PEInterface.LoadLoaders(); + var mainWindow = new MainWindow(); + desktop.MainWindow = mainWindow; + AvaloniaAppHost.SecondaryInstanceArgsReceived += args => + HandleSecondaryInstanceArgs(mainWindow, args); + + desktop.ShutdownRequested += (_, e) => + { + if (mainWindow.IsQuitting) + return; + + e.Cancel = true; + mainWindow.QuitApplication(); + }; + + if (Current?.TryGetFeature() is { } activatable) + { + activatable.Activated += (_, e) => + { + if (e.Kind == ActivationKind.Reopen) + mainWindow.ShowFromTray(); + }; + } + + if (CoreData.WasDaemon) + { + // Start silently: hide the window on first open only. + // Opened fires on every Show() in Avalonia, so we must unsubscribe + // immediately or every ShowFromTray() call would hide the window again. + void HideOnce(object? s, EventArgs e) + { + mainWindow.Opened -= HideOnce; + mainWindow.Hide(); + } + mainWindow.Opened += HideOnce; + } + + if (splash is not null) + { + var splashRef = splash; + void CloseSplashOnce(object? s, EventArgs e) + { + mainWindow.Opened -= CloseSplashOnce; + splashRef.Close(); + } + mainWindow.Opened += CloseSplashOnce; + } + + // Framework auto-show already passed (we deferred via Dispatcher.Post), + // so we have to open the window ourselves. + mainWindow.Show(); + + _ = StartupAsync(mainWindow); + } + + private static async Task StartupAsync(MainWindow mainWindow) + { + // Show crash report from the previous session and wait for the user + // to dismiss it before continuing with normal startup. + if (File.Exists(CrashHandler.PendingCrashFile)) + { + try + { + string report = File.ReadAllText(CrashHandler.PendingCrashFile); + File.Delete(CrashHandler.PendingCrashFile); + // Yield once so the main window has time to open before + // ShowDialog tries to attach to it as owner. + await Task.Yield(); + + // ShowDialog requires a visible owner. In daemon mode the main window + // is hidden, so temporarily show it and re-hide after the dialog closes. + bool reshide = CoreData.WasDaemon; + if (reshide) mainWindow.Show(); + await new CrashReportWindow(report).ShowDialog(mainWindow); + if (reshide) mainWindow.Hide(); + } + catch { /* must not prevent normal startup */ } + } + + await AvaloniaBootstrapper.InitializeAsync(); + } + + private static void HandleSecondaryInstanceArgs(MainWindow mainWindow, string[] args) + { + bool isDaemonLaunch = args.Contains(AvaloniaCliHandler.DAEMON); + CoreData.IsDaemon = isDaemonLaunch; + + // A toast click launches the app with its unigetui:// deep-link; route the + // encoded action to the notification activation handler before foregrounding. + if (args is { Length: > 0 }) + { + foreach (string arg in args) + { + string? action = WindowsAppNotificationBridge.TryParseToastLaunchArgument(arg); + if (action is not null) + { + WindowsAppNotificationBridge.RaiseActivation(action); + break; + } + } + } + + if (isDaemonLaunch) + return; + + if (!mainWindow.IsVisible) + mainWindow.Show(); + + mainWindow.Activate(); + } + + public static void ApplyTheme(string value) + { + Current!.RequestedThemeVariant = value switch + { + "light" => ThemeVariant.Light, + "dark" => ThemeVariant.Dark, + _ => ThemeVariant.Default, + }; + } + + public static string WebViewUserDataFolder { get; } = + Path.Join(Path.GetTempPath(), "UniGetUI", "WebView"); + + private static void SetUpWebViewUserDataFolder() + { + try + { + if (!Directory.Exists(WebViewUserDataFolder)) + Directory.CreateDirectory(WebViewUserDataFolder); + + Environment.SetEnvironmentVariable("WEBVIEW2_USER_DATA_FOLDER", WebViewUserDataFolder); + } + catch (Exception e) + { + Logger.Warn("Could not set up data folder for WebView2"); + Logger.Warn(e); + } + } + +} diff --git a/src/UniGetUI.Avalonia/Assets/Images/Empty_inbox.png b/src/UniGetUI.Avalonia/Assets/Images/Empty_inbox.png new file mode 100644 index 0000000..ffbaac8 Binary files /dev/null and b/src/UniGetUI.Avalonia/Assets/Images/Empty_inbox.png differ diff --git a/src/UniGetUI.Avalonia/Assets/Images/Trophee.png b/src/UniGetUI.Avalonia/Assets/Images/Trophee.png new file mode 100644 index 0000000..50b5fea Binary files /dev/null and b/src/UniGetUI.Avalonia/Assets/Images/Trophee.png differ diff --git a/src/UniGetUI.Avalonia/Assets/Images/launcher.png b/src/UniGetUI.Avalonia/Assets/Images/launcher.png new file mode 100644 index 0000000..e4a5da8 Binary files /dev/null and b/src/UniGetUI.Avalonia/Assets/Images/launcher.png differ diff --git a/src/UniGetUI.Avalonia/Assets/Images/maurice_penseur.png b/src/UniGetUI.Avalonia/Assets/Images/maurice_penseur.png new file mode 100644 index 0000000..0c48cdd Binary files /dev/null and b/src/UniGetUI.Avalonia/Assets/Images/maurice_penseur.png differ diff --git a/src/UniGetUI.Avalonia/Assets/Styles/Styles.Common.axaml b/src/UniGetUI.Avalonia/Assets/Styles/Styles.Common.axaml new file mode 100644 index 0000000..1582038 --- /dev/null +++ b/src/UniGetUI.Avalonia/Assets/Styles/Styles.Common.axaml @@ -0,0 +1,410 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 4 16 0 #33000000 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 4 18 0 #80000000 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/UniGetUI.Avalonia/Assets/Styles/Styles.WindowsMica.axaml b/src/UniGetUI.Avalonia/Assets/Styles/Styles.WindowsMica.axaml new file mode 100644 index 0000000..073cc87 --- /dev/null +++ b/src/UniGetUI.Avalonia/Assets/Styles/Styles.WindowsMica.axaml @@ -0,0 +1,96 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/UniGetUI.Avalonia/Assets/Styles/Styles.WindowsMica.axaml.cs b/src/UniGetUI.Avalonia/Assets/Styles/Styles.WindowsMica.axaml.cs new file mode 100644 index 0000000..c46e2fd --- /dev/null +++ b/src/UniGetUI.Avalonia/Assets/Styles/Styles.WindowsMica.axaml.cs @@ -0,0 +1,12 @@ +using Avalonia.Controls; +using Avalonia.Markup.Xaml; + +namespace UniGetUI.Avalonia.Assets.Styles; + +public partial class WindowsMicaStyles : ResourceDictionary +{ + public WindowsMicaStyles() + { + AvaloniaXamlLoader.Load(this); + } +} diff --git a/src/UniGetUI.Avalonia/AvaloniaCliHandler.cs b/src/UniGetUI.Avalonia/AvaloniaCliHandler.cs new file mode 100644 index 0000000..ff19c7e --- /dev/null +++ b/src/UniGetUI.Avalonia/AvaloniaCliHandler.cs @@ -0,0 +1,21 @@ +using UniGetUI.Shared; + +namespace UniGetUI.Avalonia; + +internal static class AvaloniaCliHandler +{ + public const string DAEMON = "--daemon"; + public const string NO_CORRUPT_DIALOG = "--no-corrupt-dialog"; + + public static int? HandlePreUiArgs(string[] args) + { + SharedPreUiCommandExitCodes exitCodes = OperatingSystem.IsWindows() + ? SharedPreUiCommandDispatcher.WindowsCliExitCodes + : SharedPreUiCommandDispatcher.PortableCliExitCodes; + + return SharedPreUiCommandDispatcher.TryHandle( + args, + exitCodes + ); + } +} diff --git a/src/UniGetUI.Avalonia/Converters/ScaleClampConverter.cs b/src/UniGetUI.Avalonia/Converters/ScaleClampConverter.cs new file mode 100644 index 0000000..8efa532 --- /dev/null +++ b/src/UniGetUI.Avalonia/Converters/ScaleClampConverter.cs @@ -0,0 +1,36 @@ +using System; +using System.Globalization; +using Avalonia.Data.Converters; + +namespace UniGetUI.Avalonia.Converters; + +/// +/// Multiplies a bound double (typically a container dimension) by a fraction and clamps the +/// result to an upper bound, so an element can scale down with its container yet never grow +/// past a sensible maximum. The converter parameter is "fraction|max" (e.g. "0.5|240"). +/// +public sealed class ScaleClampConverter : IValueConverter +{ + public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture) + { + if (value is not double available || double.IsNaN(available) || available <= 0) + return 0.0; + + double fraction = 1.0; + double max = double.PositiveInfinity; + + if (parameter is string param) + { + string[] parts = param.Split('|'); + if (parts.Length > 0 && double.TryParse(parts[0], NumberStyles.Float, CultureInfo.InvariantCulture, out double f)) + fraction = f; + if (parts.Length > 1 && double.TryParse(parts[1], NumberStyles.Float, CultureInfo.InvariantCulture, out double m)) + max = m; + } + + return Math.Min(available * fraction, max); + } + + public object ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture) + => throw new NotSupportedException(); +} diff --git a/src/UniGetUI.Avalonia/CrashHandler.cs b/src/UniGetUI.Avalonia/CrashHandler.cs new file mode 100644 index 0000000..2e67164 --- /dev/null +++ b/src/UniGetUI.Avalonia/CrashHandler.cs @@ -0,0 +1,235 @@ +using System.Diagnostics; +using System.Runtime.InteropServices; +using System.Runtime.Versioning; +using System.Text; +using UniGetUI.Core.Data; +using UniGetUI.Core.Logging; +using UniGetUI.Core.Tools; + +namespace UniGetUI.Avalonia; + +public static class CrashHandler +{ + public static readonly string PendingCrashFile = + Path.Combine(Path.GetTempPath(), "UniGetUI_pending_crash.txt"); + + private const string NO_CORRUPT_DIALOG = "--no-corrupt-dialog"; + + private const uint MB_ICONSTOP = 0x00000010; + private const uint MB_OKCANCEL = 0x00000001; + private const uint MB_YESNOCANCEL = 0x00000003; + private const int IDOK = 1; + private const int IDYES = 6; + private const int IDNO = 7; + + [SupportedOSPlatform("windows")] + [DllImport("user32.dll", CharSet = CharSet.Unicode)] + private static extern int MessageBox(IntPtr hWnd, string lpText, string lpCaption, uint uType); + + [SupportedOSPlatform("windows")] + private static void _reportMissingFiles(out bool showDetailedReport) + { + try + { + string installerPath = Path.Join( + CoreData.UniGetUIExecutableDirectory, + "UniGetUI.Installer.exe" + ); + bool canAutoRepair = File.Exists(installerPath); + + var title = "UniGetUI - Missing Files"; + + if (canAutoRepair) + { + var errorMessage = + "UniGetUI has detected that some required files are missing." + + "\n\nThis might be caused by an incomplete installation or corrupted files. Please reinstall UniGetUI." + + "\n\nPress YES to reinstall UniGetUI right now." + + "\nPress NO to close this prompt." + + "\nPress CANCEL to get more details about the crash."; + + var msgboxResult = MessageBox( + IntPtr.Zero, + errorMessage, + title, + MB_ICONSTOP | MB_YESNOCANCEL + ); + if (msgboxResult is IDYES) + { + Process.Start(installerPath, "/silent /NoDeployInstaller"); + } + + if (msgboxResult is IDYES or IDNO) + showDetailedReport = false; + else + showDetailedReport = true; // IDCANCEL + } + else + { + var errorMessage = + "UniGetUI has detected that some required files are missing." + + "\n\nThis might be caused by an incomplete installation or corrupted files. Please reinstall UniGetUI." + + "\n\nPress OK to close this prompt." + + "\nPress CANCEL to get more details about the crash."; + + var msgboxResult = MessageBox( + IntPtr.Zero, + errorMessage, + title, + MB_ICONSTOP | MB_OKCANCEL + ); + if (msgboxResult is IDOK) + showDetailedReport = false; + else + showDetailedReport = true; // IDCANCEL + } + } + catch + { + showDetailedReport = false; + } + } + + public static void ReportFatalException(Exception e) + { + Debugger.Break(); + + if (OperatingSystem.IsWindows() && !Environment.GetCommandLineArgs().Contains(NO_CORRUPT_DIALOG)) + { + Exception? fileEx = e; + while (fileEx is not null) + { + if ((uint)fileEx.HResult is 0x80070002 or 0x8007007E or 0x802B000A) + { + _reportMissingFiles(out bool showDetailedReport); + if (!showDetailedReport) + { + Environment.Exit(1); + } + } + fileEx = fileEx.InnerException; + } + } + + string langName = "Unknown"; + try + { + langName = CoreTools.GetCurrentLocale(); + } + catch + { + // ignored + } + + static string GetExceptionData(Exception ex) + { + try + { + StringBuilder b = new(); + foreach (var key in ex.Data.Keys) + b.AppendLine($"{key}: {ex.Data[key]}"); + string r = b.ToString(); + return r.Any() ? r : "No extra data was provided"; + } + catch (Exception inner) + { + return $"Failed to get exception Data with exception {inner.Message}"; + } + } + + // Run the integrity check on a background thread with a tight timeout. + // Running it synchronously on the UI thread can block for 20-30 s on slow + // disks, and calling Environment.Exit while the UI thread holds locks + // causes a native crash. + string iReport; + try + { + var integrityTask = Task.Run(() => IntegrityTester.CheckIntegrity(false)); + if (integrityTask.Wait(TimeSpan.FromSeconds(5))) + { + iReport = IntegrityTester.GetReadableReport(integrityTask.Result); + } + else + { + iReport = "Integrity check timed out (> 5 s) — skipped in crash report"; + } + } + catch (Exception ex) + { + iReport = "Failed to compute integrity report: "; + iReport += ex.GetType() + ": " + ex.Message; + } + + string Error_String = $$""" + Environment details: + OS version: {{Environment.OSVersion.VersionString}} + Language: {{langName}} + APP Version: {{CoreData.VersionName}} + APP Build number: {{CoreData.BuildNumber}} + Executable: {{Environment.ProcessPath}} + Command-line arguments: {{Environment.CommandLine}} + + Integrity report: + {{iReport.Replace("\n", "\n ")}} + + Exception type: {{e.GetType()?.Name}} ({{e.GetType()}}) + Crash HResult: 0x{{(uint)e.HResult:X}} ({{(uint)e.HResult}}, {{e.HResult}}) + Crash Message: {{e.Message}} + + Crash Data: + {{GetExceptionData(e).Replace("\n", "\n ")}} + + Crash Trace: + {{e.StackTrace?.Replace("\n", "\n ")}} + """; + + try + { + int i = 0; + while (e.InnerException is not null) + { + i++; + e = e.InnerException; + Error_String += + "\n\n\n\n" + + $$""" + ——————————————————————————————————————————————————————————— + Inner exception details (depth level: {{i}}) + Crash HResult: 0x{{(uint)e.HResult:X}} ({{(uint)e.HResult}}, {{e.HResult}}) + Crash Message: {{e.Message}} + + Crash Data: + {{GetExceptionData(e).Replace("\n", "\n ")}} + + Crash Traceback: + {{e.StackTrace?.Replace("\n", "\n ")}} + """; + } + + if (i == 0) + { + Error_String += $"\n\n\nNo inner exceptions found"; + } + } + catch + { + // ignore + } + + Error_String = Logger.Redact(Error_String); + + Console.WriteLine(Error_String); + + // Persist crash data so the next normal app launch can show the report. + try + { + File.WriteAllText(PendingCrashFile, Error_String, Encoding.UTF8); + } + catch + { + // If we can't write the file, nothing more we can do — just exit. + } + + Environment.Exit(1); + } +} diff --git a/src/UniGetUI.Avalonia/Extensions/ObservableSubscriptionExtensions.cs b/src/UniGetUI.Avalonia/Extensions/ObservableSubscriptionExtensions.cs new file mode 100644 index 0000000..07f7fa8 --- /dev/null +++ b/src/UniGetUI.Avalonia/Extensions/ObservableSubscriptionExtensions.cs @@ -0,0 +1,29 @@ +using System.Runtime.ExceptionServices; + +namespace UniGetUI.Avalonia.Extensions; + +internal static class ObservableSubscriptionExtensions +{ + public static IDisposable SubscribeValue(this IObservable source, Action onNext) + { + ArgumentNullException.ThrowIfNull(source); + ArgumentNullException.ThrowIfNull(onNext); + + return source.Subscribe(new ActionObserver(onNext)); + } + + private sealed class ActionObserver(Action onNext) : IObserver + { + public void OnCompleted() + { + } + + public void OnError(Exception error) + { + ExceptionDispatchInfo.Capture(error).Throw(); + } + + public void OnNext(T value) + => onNext(value); + } +} diff --git a/src/UniGetUI.Avalonia/Infrastructure/AccessibilityAnnouncementService.cs b/src/UniGetUI.Avalonia/Infrastructure/AccessibilityAnnouncementService.cs new file mode 100644 index 0000000..09d7cdd --- /dev/null +++ b/src/UniGetUI.Avalonia/Infrastructure/AccessibilityAnnouncementService.cs @@ -0,0 +1,33 @@ +using Avalonia.Automation; +using Avalonia.Threading; +using UniGetUI.Core.Tools; + +namespace UniGetUI.Avalonia.Infrastructure; + +public sealed record AccessibilityAnnouncement( + string Message, + AutomationLiveSetting LiveSetting = AutomationLiveSetting.Polite); + +public static class AccessibilityAnnouncementService +{ + public static event EventHandler? AnnouncementRequested; + + public static void Announce( + string? message, + AutomationLiveSetting liveSetting = AutomationLiveSetting.Polite) + { + if (string.IsNullOrWhiteSpace(message)) + return; + + Dispatcher.UIThread.Post(() => + AnnouncementRequested?.Invoke( + null, + new AccessibilityAnnouncement(message, liveSetting))); + } + + public static void AnnounceToggle(string label, bool isEnabled) + { + Announce(CoreTools.Translate("{0} is now {1}", label, + isEnabled ? CoreTools.Translate("Enabled") : CoreTools.Translate("Disabled"))); + } +} diff --git a/src/UniGetUI.Avalonia/Infrastructure/AppRestartHelper.cs b/src/UniGetUI.Avalonia/Infrastructure/AppRestartHelper.cs new file mode 100644 index 0000000..def6de7 --- /dev/null +++ b/src/UniGetUI.Avalonia/Infrastructure/AppRestartHelper.cs @@ -0,0 +1,72 @@ +using Avalonia.Controls.ApplicationLifetimes; +using UniGetUI.Avalonia.Views; +using UniGetUI.Core.Tools; + +namespace UniGetUI.Avalonia.Infrastructure; + +internal static class AppRestartHelper +{ + private const string LauncherExecutableName = "UniGetUI.exe"; + + public static void Restart() + { + string executablePath = ResolveRestartExecutablePath(AppContext.BaseDirectory); + CoreTools.ScheduleRelaunchAfterExit(executablePath); + + if (MainWindow.Instance is { } mainWindow) + { + mainWindow.QuitApplication(); + return; + } + + (global::Avalonia.Application.Current?.ApplicationLifetime + as IClassicDesktopStyleApplicationLifetime)?.Shutdown(); + } + + internal static string ResolveRestartExecutablePath(string baseDirectory) + { + if (!OperatingSystem.IsWindows()) + return Environment.ProcessPath + ?? throw new InvalidOperationException("Could not resolve the current executable path."); + + foreach (string candidate in GetWindowsLauncherCandidates(baseDirectory)) + { + if (File.Exists(candidate)) + return candidate; + } + + return Environment.ProcessPath + ?? throw new FileNotFoundException( + $"Could not find the UniGetUI launcher '{LauncherExecutableName}'." + ); + } + + private static IEnumerable GetWindowsLauncherCandidates(string baseDirectory) + { + yield return Path.Combine(baseDirectory, "..", LauncherExecutableName); + yield return Path.Combine(baseDirectory, LauncherExecutableName); + + var directory = new DirectoryInfo(Path.GetFullPath(baseDirectory)); + while (directory is not null) + { + string launcherBinDirectory = Path.Combine(directory.FullName, "UniGetUI", "bin"); + if (Directory.Exists(launcherBinDirectory)) + { + foreach ( + string candidate in Directory + .EnumerateFiles( + launcherBinDirectory, + LauncherExecutableName, + SearchOption.AllDirectories + ) + .OrderByDescending(File.GetLastWriteTimeUtc) + ) + { + yield return candidate; + } + } + + directory = directory.Parent; + } + } +} diff --git a/src/UniGetUI.Avalonia/Infrastructure/AppShortcutAumidStamper.cs b/src/UniGetUI.Avalonia/Infrastructure/AppShortcutAumidStamper.cs new file mode 100644 index 0000000..faecf7c --- /dev/null +++ b/src/UniGetUI.Avalonia/Infrastructure/AppShortcutAumidStamper.cs @@ -0,0 +1,219 @@ +#if WINDOWS +using System; +using System.Diagnostics.CodeAnalysis; +using System.IO; +using System.Runtime.InteropServices; +using UniGetUI.Core.Logging; + +namespace UniGetUI.Avalonia.Infrastructure; + +/// +/// Stamps the UniGetUI AppUserModelID onto the Start Menu shortcut the installer +/// creates, which is the shell's "app is installed" signal required before Windows will +/// surface Action-Center toasts for an unpackaged Win32 app. +/// +/// +/// Inno Setup cannot write shortcut property-store values directly, so the app performs +/// this idempotent fix-up on first launch (and on every launch; it is cheap). The AUMID +/// must match the one set on the process by . +/// +internal static class AppShortcutAumidStamper +{ + private const string ShortcutName = "UniGetUI"; + private const string Aumid = Win32ToastNotifier.AppUserModelId; + + // System.AppUserModel.Id property key: {9F4C2855-9F79-4B39-A8D0-E1A8F39EFCDC}, pid 5 + private static readonly PropertyKey AppUserModelIdKey = + new(new Guid("9F4C2855-9F79-4B39-A8D0-E1A8F39EFCDC"), 5); + + public static void EnsureStamped() + { + if (!OperatingSystem.IsWindows()) + return; + + try + { + string? shortcutPath = ResolveStartMenuShortcut(); + if (shortcutPath is null || !File.Exists(shortcutPath)) + return; + + StampIfMissing(shortcutPath); + } + catch (Exception ex) + { + Logger.Warn("Could not stamp AUMID on Start Menu shortcut"); + Logger.Warn(ex); + } + } + + private static string? ResolveStartMenuShortcut() + { + // {autostartmenu} in Inno Setup resolves to the per-user Start Menu Programs folder. + string baseDir = Environment.GetFolderPath( + Environment.SpecialFolder.StartMenu, Environment.SpecialFolderOption.DoNotVerify); + string userPath = Path.Combine(baseDir, "Programs", ShortcutName + ".lnk"); + if (File.Exists(userPath)) + return userPath; + + // Fallback to the common Start Menu Programs folder. + string commonBase = Environment.GetFolderPath( + Environment.SpecialFolder.CommonStartMenu, Environment.SpecialFolderOption.DoNotVerify); + string commonPath = Path.Combine(commonBase, "Programs", ShortcutName + ".lnk"); + return File.Exists(commonPath) ? commonPath : null; + } + + [UnconditionalSuppressMessage( + "Trimming", + "IL2072", + Justification = "ShellLink COM activation uses the shell-registered CLSID and COM interfaces declared below; it does not depend on app-owned constructors trimmed from this assembly.")] + private static void StampIfMissing(string shortcutPath) + { + // ShellLink (CLSID 00021401-0000-0000-C000-000000000046) implements IPersistFile and + // IPropertyStore for .lnk files. We read the AppUserModel.Id value; if it already + // matches, there's nothing to do, otherwise we set it and persist. + var shellLinkClsid = new Guid("00021401-0000-0000-C000-000000000046"); + object? linkObj = null; + try + { + linkObj = Activator.CreateInstance(Type.GetTypeFromCLSID(shellLinkClsid) + ?? throw new InvalidOperationException("ShellLink CLSID is not registered")); + if (linkObj is not IPersistFile persistFile) + return; + + persistFile.Load(shortcutPath, 0); + + if (linkObj is not IPropertyStore props) + return; + + if (TryGetAumid(props, out string? existing) && existing == Aumid) + return; // Already correct. + + var aumidValue = new PropVariant(Aumid); + try + { + props.SetValue(AppUserModelIdKey, aumidValue); + props.Commit(); + persistFile.Save(shortcutPath, fRemember: false); + } + finally + { + aumidValue.Clear(); + } + } + finally + { + if (linkObj is not null) + Marshal.ReleaseComObject(linkObj); + } + } + + private static bool TryGetAumid(IPropertyStore props, out string? value) + { + value = null; + try + { + uint count = props.GetCount(); + for (uint i = 0; i < count; i++) + { + props.GetAt(i, out PropertyKey key); + if (key.fmtid == AppUserModelIdKey.fmtid && key.pid == AppUserModelIdKey.pid) + { + var pv = new PropVariant(); + try + { + props.GetValue(key, out pv); + value = pv.Value as string; + return true; + } + finally + { + pv.Clear(); + } + } + } + } + catch + { + // Reading failed; fall through to write. + } + return false; + } + + // ── COM interop ────────────────────────────────────────────────────────── + + [ComImport] + [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + [Guid("886D8EEB-8CF2-4446-8D02-CDBA1DBDCF99")] + internal interface IPropertyStore + { + uint GetCount(); + void GetAt(uint i, out PropertyKey key); + void GetValue([In] ref PropertyKey key, out PropVariant value); + void SetValue([In] ref PropertyKey key, [In] ref PropVariant value); + void Commit(); + } + + [ComImport] + [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + [Guid("0000010B-0000-0000-C000-000000000046")] + internal interface IPersistFile + { + void GetClassID(out Guid pClassID); + void IsDirty(); + void Load([MarshalAs(UnmanagedType.LPWStr)] string pszFileName, uint dwMode); + void Save([MarshalAs(UnmanagedType.LPWStr)] string pszFileName, bool fRemember); + void SaveCompleted([MarshalAs(UnmanagedType.LPWStr)] string pszFileName); + void GetCurFile([MarshalAs(UnmanagedType.LPWStr)] out string ppszFileName); + } + + [StructLayout(LayoutKind.Sequential)] + internal struct PropertyKey + { + public Guid fmtid; + public int pid; + public PropertyKey(Guid fmtid, int pid) + { + this.fmtid = fmtid; + this.pid = pid; + } + } + + // Minimal PropVariant supporting VT_LPWSTR (string) — the only type we set/read for AUMID. + [StructLayout(LayoutKind.Sequential)] + internal struct PropVariant + { + private ushort vt; + private readonly ushort reserved1; + private readonly ushort reserved2; + private readonly ushort reserved3; + private IntPtr value1; + private readonly IntPtr value2; + + public PropVariant(string value) + { + vt = (ushort)VarEnum.VT_LPWSTR; + reserved1 = reserved2 = reserved3 = 0; + value1 = Marshal.StringToCoTaskMemUni(value); + value2 = IntPtr.Zero; + } + + public string? Value + { + get + { + if ((VarEnum)vt != VarEnum.VT_LPWSTR || value1 == IntPtr.Zero) + return null; + return Marshal.PtrToStringUni(value1); + } + } + + public void Clear() + { + if ((VarEnum)vt == VarEnum.VT_LPWSTR && value1 != IntPtr.Zero) + Marshal.FreeCoTaskMem(value1); + vt = 0; + value1 = IntPtr.Zero; + } + } +} +#endif diff --git a/src/UniGetUI.Avalonia/Infrastructure/AsyncCommand.cs b/src/UniGetUI.Avalonia/Infrastructure/AsyncCommand.cs new file mode 100644 index 0000000..27070ea --- /dev/null +++ b/src/UniGetUI.Avalonia/Infrastructure/AsyncCommand.cs @@ -0,0 +1,49 @@ +using System.Windows.Input; + +namespace UniGetUI.Avalonia.Infrastructure; + +internal sealed class AsyncCommand : ICommand +{ + private readonly Func _executeAsync; + private readonly Func? _canExecute; + private bool _isExecuting; + + public AsyncCommand(Func executeAsync, Func? canExecute = null) + { + _executeAsync = executeAsync; + _canExecute = canExecute; + } + + public event EventHandler? CanExecuteChanged; + + public bool CanExecute(object? parameter) + { + return !_isExecuting && (_canExecute?.Invoke() ?? true); + } + + public async void Execute(object? parameter) + { + if (!CanExecute(parameter)) + { + return; + } + + _isExecuting = true; + RaiseCanExecuteChanged(); + + try + { + await _executeAsync(); + } + finally + { + _isExecuting = false; + RaiseCanExecuteChanged(); + } + } + + public void RaiseCanExecuteChanged() + { + CanExecuteChanged?.Invoke(this, EventArgs.Empty); + } +} diff --git a/src/UniGetUI.Avalonia/Infrastructure/AvaloniaAppHost.cs b/src/UniGetUI.Avalonia/Infrastructure/AvaloniaAppHost.cs new file mode 100644 index 0000000..fb417b1 --- /dev/null +++ b/src/UniGetUI.Avalonia/Infrastructure/AvaloniaAppHost.cs @@ -0,0 +1,146 @@ +using System.Runtime.InteropServices; +using Avalonia; +#if WINDOWS +using Avalonia.Win32; +#endif +using Avalonia.Threading; +using UniGetUI.Core.Data; +using UniGetUI.Core.Logging; +using UniGetUI.Core.Tools; +using UniGetUI.Interface; + +namespace UniGetUI.Avalonia.Infrastructure; + +public static class AvaloniaAppHost +{ + private static Mutex? _singleInstanceMutex; + + public static event Action? SecondaryInstanceArgsReceived; + + public static void Run(string[] args) + { + AppDomain.CurrentDomain.UnhandledException += (_, e) => + CrashHandler.ReportFatalException((Exception)e.ExceptionObject); + + if (ShouldPrepareCliConsole(args)) + { + WindowsConsoleHost.PrepareCliIO(); + } + + if (AvaloniaCliHandler.HandlePreUiArgs(args) is { } exitCode) + { + Environment.Exit(exitCode); + return; + } + + if (IpcCliSyntax.IsIpcCommand(args)) + { + Environment.ExitCode = IpcCliCommandRunner.RunAsync(args, Console.Out, Console.Error) + .GetAwaiter() + .GetResult(); + return; + } + + if (HeadlessModeOptions.IsHeadless(args)) + { + Environment.ExitCode = HeadlessDaemonHost.RunAsync().GetAwaiter().GetResult(); + return; + } + + CoreData.WasDaemon = CoreData.IsDaemon = args.Contains(AvaloniaCliHandler.DAEMON); + + string textart = $""" + __ __ _ ______ __ __ ______ + / / / /___ (_) ____/__ / /_/ / / / _/ + / / / / __ \/ / / __/ _ \/ __/ / / // / + / /_/ / / / / / /_/ / __/ /_/ /_/ // / + \____/_/ /_/_/\____/\___/\__/\____/___/ + Welcome to UniGetUI Version {CoreData.VersionName} + """; + + Logger.RedactUsername = Core.SettingsEngine.Settings.Get(Core.SettingsEngine.Settings.K.RedactUsernameInLog); + + Logger.ImportantInfo(textart); + Logger.ImportantInfo(" "); + Logger.ImportantInfo($"Build {CoreData.BuildNumber}"); + Logger.ImportantInfo("UI Framework: Avalonia"); + Logger.ImportantInfo($"Data directory {CoreData.UniGetUIDataDirectory}"); + Logger.ImportantInfo($"OS: {RuntimeInformation.OSDescription}"); + Logger.ImportantInfo($"Process arch: {RuntimeInformation.ProcessArchitecture} (OS: {RuntimeInformation.OSArchitecture})"); + Logger.ImportantInfo($"Runtime: {RuntimeInformation.FrameworkDescription}"); + Logger.ImportantInfo($"Elevated: {CoreTools.IsAdministrator()}"); + Logger.ImportantInfo($"Packaged (MSIX): {CoreTools.IsPackagedApp()}"); + Logger.ImportantInfo($"Args: {(args.Length > 0 ? string.Join(" ", args) : "(none)")}"); + + // Stamp the AUMID onto the Start Menu shortcut so the shell surfaces toasts. The + // installer cannot write the property-store value directly; this is idempotent. +#if WINDOWS + AppShortcutAumidStamper.EnsureStamped(); +#endif + + // Bind Avalonia's UI-thread dispatcher to this (main/STA) thread before the single-instance + // listener starts: if a second instance connects mid-startup, the listener's Dispatcher.UIThread.Post + // would otherwise bind it to the worker thread and make Win32Platform.Initialize throw. + _ = Dispatcher.UIThread; + + if (!TryRegisterSingleInstance(args)) + { + return; + } + + BuildAvaloniaApp().StartWithClassicDesktopLifetime(args); + } + + public static AppBuilder BuildAvaloniaApp() + { + AppBuilder builder = AppBuilder.Configure() + .UsePlatformDetect(); + +#if WINDOWS + if (WindowsAvaloniaRenderingPolicy.ShouldUseSoftwareRendering) + { + builder = builder.With(new Win32PlatformOptions + { + RenderingMode = [Win32RenderingMode.Software], + }); + } +#endif + + return builder.LogToTrace(); + } + + private static bool ShouldPrepareCliConsole(IReadOnlyList args) + { + return IpcCliSyntax.HasVerbCommand(args); + } + + private static bool TryRegisterSingleInstance(string[] args) + { + if (!OperatingSystem.IsWindows()) + return true; + + _singleInstanceMutex = new Mutex( + initiallyOwned: true, + name: CoreData.MainWindowIdentifier, + createdNew: out bool createdNew + ); + + if (createdNew) + { + SingleInstanceRedirector.StartListener(args => + SecondaryInstanceArgsReceived?.Invoke(args) + ); + return true; + } + + if (SingleInstanceRedirector.TryForwardToFirstInstance(args)) + { + _singleInstanceMutex.Dispose(); + _singleInstanceMutex = null; + return false; + } + + Logger.Warn("Could not redirect to the existing Avalonia instance; starting a new one"); + return true; + } +} diff --git a/src/UniGetUI.Avalonia/Infrastructure/AvaloniaAutoUpdater.cs b/src/UniGetUI.Avalonia/Infrastructure/AvaloniaAutoUpdater.cs new file mode 100644 index 0000000..9f08c42 --- /dev/null +++ b/src/UniGetUI.Avalonia/Infrastructure/AvaloniaAutoUpdater.cs @@ -0,0 +1,1728 @@ +using System.Diagnostics; +using System.Globalization; +using System.Runtime.InteropServices; +using System.Runtime.Versioning; +using System.Security.Cryptography; +using System.Security.Cryptography.X509Certificates; +using System.Text; +using System.Text.Json; +using System.Text.Json.Serialization; +using Avalonia.Threading; +using Microsoft.Win32; +using UniGetUI.Avalonia.ViewModels; +using UniGetUI.Core.Data; +using UniGetUI.Core.Logging; +using UniGetUI.Core.SettingsEngine; +using UniGetUI.Core.Tools; + +namespace UniGetUI.Avalonia.Infrastructure; + +/// +/// Avalonia port of the WinUI AutoUpdater. Checks for new UniGetUI versions and +/// lets the user trigger an in-place upgrade. +/// +internal static partial class AvaloniaAutoUpdater +{ + private const string INSTALLER_VALIDATION_FAILURE_MARKER_SUFFIX = ".validation-failed"; + + // ------------------------------------------------------------------ constants + private const string REGISTRY_PATH = @"Software\Devolutions\UniGetUI"; + private const string DEFAULT_PRODUCTINFO_URL = "https://devolutions.net/productinfo.json"; + private const string DEFAULT_PRODUCTINFO_KEY = "Devolutions.UniGetUI"; + + private const string REG_PRODUCTINFO_URL = "UpdaterProductInfoUrl"; + private const string REG_PRODUCTINFO_KEY = "UpdaterProductKey"; + private const string REG_ALLOW_UNSAFE_URLS = "UpdaterAllowUnsafeUrls"; + private const string REG_SKIP_HASH_VALIDATION = "UpdaterSkipHashValidation"; + private const string REG_SKIP_SIGNER_THUMBPRINT_CHECK = "UpdaterSkipSignerThumbprintCheck"; + private const string REG_DISABLE_TLS_VALIDATION = "UpdaterDisableTlsValidation"; + + private static readonly string[] DEVOLUTIONS_CERT_THUMBPRINTS = + [ + "3f5202a9432d54293bdfe6f7e46adb0a6f8b3ba6", + "8db5a43bb8afe4d2ffb92da9007d8997a4cc4e13", + "50f753333811ff11f1920274afde3ffd4468b210", + ]; + + private static readonly string[] DEVOLUTIONS_MAC_DEVELOPER_IDS = + [ + "N592S9ASDB", + ]; + +#if !DEBUG + private static readonly string[] RELEASE_IGNORED_REGISTRY_VALUES = + [ + REG_PRODUCTINFO_KEY, + REG_ALLOW_UNSAFE_URLS, + REG_SKIP_HASH_VALIDATION, + REG_SKIP_SIGNER_THUMBPRINT_CHECK, + REG_DISABLE_TLS_VALIDATION, + ]; +#endif + + private static readonly AutoUpdaterJsonContext _jsonContext = new( + new JsonSerializerOptions(SerializationHelpers.DefaultOptions) + ); + + // ------------------------------------------------------------------ public API + /// + /// Fired on the UI thread when a validated installer is ready. Argument is the + /// human-readable version string, e.g. "4.2.1". + /// + public static event Action? UpdateAvailable; + + /// + /// Fired on the UI thread to surface progress/result of an update check or + /// install attempt to the UI banner. Mirrors the verbose feedback the WinUI + /// AutoUpdater shows in its InfoBar. + /// + public static event Action? StatusChanged; + + public sealed record UpdateStatusInfo( + string Title, + string Message, + InfoBarSeverity Severity, + bool IsClosable, + string? ActionButtonText = null, + Action? ActionButtonAction = null); + + private static void RaiseStatus( + string title, + string message, + InfoBarSeverity severity, + bool isClosable, + string? actionButtonText = null, + Action? actionButtonAction = null) + { + var info = new UpdateStatusInfo(title, message, severity, isClosable, actionButtonText, actionButtonAction); + Dispatcher.UIThread.Post(() => StatusChanged?.Invoke(info)); + } + + // ------------------------------------------------------------------ per-attempt log + // Captures auto-updater log entries for the current update attempt. We keep a + // dedicated buffer (in addition to the global session log) so the "View log" + // banner button can show the user only the entries relevant to their failed + // update, instead of dumping the entire noisy session log. + private static readonly Lock _updateLogLock = new(); + private static StringBuilder? _updateLogBuilder; + private static readonly string _updateLogPath = Path.Combine( + Path.GetTempPath(), + "UniGetUI", + "last-update-attempt.log" + ); + + private static void ResetUpdateLog(bool manualCheck, bool autoLaunch) + { + lock (_updateLogLock) + { + _updateLogBuilder = new StringBuilder() + .AppendLine($"=== UniGetUI update attempt started at {DateTime.Now:yyyy-MM-dd HH:mm:ss} ===") + .AppendLine($"Current version: {CoreData.VersionName} (build {CoreData.BuildNumber})") + .AppendLine($"Manual check: {manualCheck}") + .AppendLine($"Auto-launch: {autoLaunch}") + .AppendLine($"Process architecture: {RuntimeInformation.ProcessArchitecture}") + .AppendLine(); + FlushUpdateLogToDiskNoLock(); + } + } + + private static void AppendToUpdateLog(string severity, string message) + { + lock (_updateLogLock) + { + if (_updateLogBuilder is null) return; + _updateLogBuilder.AppendLine($"[{DateTime.Now:HH:mm:ss}] [{severity}] {Logger.Redact(message)}"); + FlushUpdateLogToDiskNoLock(); + } + } + + // Tmp + rename so a kill mid-flush (installer terminates us during file replacement) can't leave a 0-byte file. + private static void FlushUpdateLogToDiskNoLock() + { + if (_updateLogBuilder is null) return; + try + { + Directory.CreateDirectory(Path.GetDirectoryName(_updateLogPath)!); + string tempPath = _updateLogPath + ".tmp"; + File.WriteAllText(tempPath, _updateLogBuilder.ToString()); + File.Move(tempPath, _updateLogPath, overwrite: true); + } + catch { } + } + + private const string AttemptFinishedMarker = "=== Attempt finished:"; + + // Appends a structured line indicating the update flow reached a terminal state. + // The presence/absence of this marker on disk lets a subsequent app launch tell + // whether the previous attempt completed cleanly or was killed mid-flow (e.g., + // by the installer terminating us during file replacement). + private static void MarkAttemptFinished(string outcome) + { + lock (_updateLogLock) + { + if (_updateLogBuilder is null) return; + _updateLogBuilder + .AppendLine() + .AppendLine($"{AttemptFinishedMarker} {outcome} at {DateTime.Now:yyyy-MM-dd HH:mm:ss} ==="); + FlushUpdateLogToDiskNoLock(); + } + } + + private static void RecordTargetVersion(string version) + { + lock (_updateLogLock) + { + _updateLogBuilder?.AppendLine($"Target version: {version}"); + FlushUpdateLogToDiskNoLock(); + } + } + + /// + /// On app startup, detects an interrupted update attempt — the log file + /// from the previous attempt has no , + /// indicating the app was killed mid-flow (almost always because the + /// installer terminated us during file replacement). + /// + /// If the running version equals the target version we recorded, the + /// install succeeded and we are now the new version — silently appends + /// a marker so we don't re-prompt next time. + /// + /// Otherwise, surfaces a Warning banner with a "View log" button so the + /// user can investigate what happened. + /// + public static void CheckForOrphanedUpdateAttempt() + { + try + { + if (!File.Exists(_updateLogPath)) return; + + var info = new FileInfo(_updateLogPath); + if ((DateTime.Now - info.LastWriteTime).TotalMinutes > 10) + return; + + string content = File.ReadAllText(_updateLogPath); + if (content.Contains(AttemptFinishedMarker)) + return; + + string currentVer = CoreData.VersionName; + string? targetVer = null; + foreach (string line in content.Split('\n')) + { + if (line.StartsWith("Target version: ")) + { + targetVer = line["Target version: ".Length..].Trim(); + break; + } + } + + if (targetVer is null) + { + Logger.Info("Update log has no recorded target version; skipping orphan-attempt banner."); + return; + } + + if (VersionsMatch(targetVer, currentVer)) + { + Logger.Info($"Previous update attempt killed mid-flow but install succeeded (running version {currentVer} matches target {targetVer}). Marking as finished."); + try + { + File.AppendAllText( + _updateLogPath, + $"{Environment.NewLine}{AttemptFinishedMarker} installer succeeded (detected on next launch — running version is {currentVer}) at {DateTime.Now:yyyy-MM-dd HH:mm:ss} ==={Environment.NewLine}"); + } + catch { /* swallow */ } + return; + } + + Logger.Warn($"Detected interrupted update attempt. Running={currentVer}, Target={targetVer}"); + + RaiseStatus( + CoreTools.Translate("Your last update attempt did not complete."), + CoreTools.Translate("UniGetUI could not confirm whether the update succeeded. Open the log to see what happened."), + InfoBarSeverity.Warning, + isClosable: true, + actionButtonText: CoreTools.Translate("View log"), + actionButtonAction: OpenUpdateLog); + } + catch (Exception ex) + { + Logger.Warn($"Could not check for orphaned update attempt: {ex.Message}"); + } + } + + private static void LogUpdateInfo(string message, [System.Runtime.CompilerServices.CallerMemberName] string caller = "") + { + Logger.Info(message, caller); + AppendToUpdateLog("INFO ", message); + } + + private static void LogUpdateWarn(string message, [System.Runtime.CompilerServices.CallerMemberName] string caller = "") + { + Logger.Warn(message, caller); + AppendToUpdateLog("WARN ", message); + } + + private static void LogUpdateWarn(Exception ex, [System.Runtime.CompilerServices.CallerMemberName] string caller = "") + { + Logger.Warn(ex, caller); + AppendToUpdateLog("WARN ", ex.ToString()); + } + + private static void LogUpdateError(string message, [System.Runtime.CompilerServices.CallerMemberName] string caller = "") + { + Logger.Error(message, caller); + AppendToUpdateLog("ERROR", message); + } + + private static void LogUpdateError(Exception ex, [System.Runtime.CompilerServices.CallerMemberName] string caller = "") + { + Logger.Error(ex, caller); + AppendToUpdateLog("ERROR", ex.ToString()); + } + + private static void LogUpdateDebug(string message, [System.Runtime.CompilerServices.CallerMemberName] string caller = "") + { + Logger.Debug(message, caller); + AppendToUpdateLog("DEBUG", message); + } + + private static void OpenUpdateLog() + { + // The buffer is flushed to disk on every append/reset, so the file should + // already be current. Only fall back to the full session log if no flow + // has ever run (button shouldn't appear in that case, but be defensive). + string pathToOpen = File.Exists(_updateLogPath) + ? _updateLogPath + : Logger.GetSessionLogPath(); + + try + { + Process.Start(new ProcessStartInfo + { + FileName = pathToOpen, + UseShellExecute = true, + }); + } + catch (Exception ex) + { + Logger.Warn($"Could not open log file '{pathToOpen}': {ex.Message}"); + } + } + + /// + /// Translates an Inno Setup installer exit code into a short human-readable + /// reason. The codes come from the Inno Setup documentation + /// (https://jrsoftware.org/ishelp/index.php?topic=setupexitcodes). + /// + private static string DescribeInstallerExitCode(int code) => code switch + { + 0 => CoreTools.Translate("The installer reported success but did not restart UniGetUI."), + 1 => CoreTools.Translate("The installer failed to initialize."), + 2 => CoreTools.Translate("Setup was canceled before installation began."), + 3 => CoreTools.Translate("A fatal error occurred during the preparation phase."), + 4 => CoreTools.Translate("A fatal error occurred during installation."), + 5 => CoreTools.Translate("Installation was canceled while in progress."), + 6 => CoreTools.Translate("The installer was terminated by another process."), + 7 => CoreTools.Translate("The preparation phase determined the installation cannot proceed."), + 8 => CoreTools.Translate("The installer could not start. UniGetUI may already be running, or you do not have permission to install."), + _ => CoreTools.Translate("Unexpected installer error."), + }; + + private static volatile bool _installRequested; + private static string? _pendingInstallerPath; + + /// + /// Set to true when the main window is closing (user quit or hidden path). + /// Mirrors WinUI's AutoUpdater.ReleaseLockForAutoupdate_Window — once set, + /// a pending installer is allowed to launch even if the user has not yet clicked + /// the banner (e.g. user quits via tray while an update is ready). + /// + public static bool ReleaseLockForAutoupdate_Window; + + /// + /// Set to true when the user clicks the "Update now" button in the Windows toast + /// notification. Mirrors WinUI's AutoUpdater.ReleaseLockForAutoupdate_Notification. + /// + public static bool ReleaseLockForAutoupdate_Notification; + + /// + /// Called by the user when they click "Update now" in the update banner. + /// + public static void TriggerInstall() + { + LogUpdateInfo("Auto-updater: TriggerInstall invoked (user clicked Update now)."); + _installRequested = true; + } + public static async Task UpdateCheckLoopAsync() + { + if (Settings.Get(Settings.K.DisableAutoUpdateWingetUI)) + { + LogUpdateWarn("Auto-updater: disabled by user setting, skipping."); + return; + } + + await CoreTools.WaitForInternetConnection(); + + bool isFirstLaunch = true; + while (true) + { + if (Settings.Get(Settings.K.DisableAutoUpdateWingetUI)) + { + LogUpdateWarn("Auto-updater: disabled by user setting, stopping loop."); + return; + } + + await CheckAndInstallUpdatesAsync(autoLaunch: isFirstLaunch); + isFirstLaunch = false; + + await Task.Delay(UpdaterDownloadEngine.DefaultAutomaticUpdateCheckInterval); + } + } + + // ------------------------------------------------------------------ core logic + internal static async Task CheckAndInstallUpdatesAsync(bool autoLaunch = false, bool manualCheck = false) + { + ResetUpdateLog(manualCheck, autoLaunch); + UpdaterOverrides overrides = LoadUpdaterOverrides(); + bool wasCheckingForUpdates = true; + + try + { + if (manualCheck) + { + RaiseStatus( + CoreTools.Translate("We are checking for updates."), + CoreTools.Translate("Please wait"), + InfoBarSeverity.Informational, + isClosable: false); + } + + UpdateCandidate candidate = await GetUpdateCandidateAsync(overrides); + LogUpdateInfo( + $"Auto-updater source '{candidate.SourceName}' returned version {candidate.VersionName} (upgradable={candidate.IsUpgradable})" + ); + + if (!candidate.IsUpgradable) + { + if (manualCheck) + { + RaiseStatus( + CoreTools.Translate("Great! You are on the latest version."), + CoreTools.Translate("There are no new UniGetUI versions to be installed"), + InfoBarSeverity.Success, + isClosable: true); + } + MarkAttemptFinished("no update available"); + return true; + } + + wasCheckingForUpdates = false; + RecordTargetVersion(candidate.VersionName); + LogUpdateInfo($"Update to UniGetUI {candidate.VersionName} is available."); + + string installerName; + if (OperatingSystem.IsWindows()) + installerName = "UniGetUI Updater.exe"; + else + // macOS and Linux both ship as self-contained .tar.gz archives. + installerName = "UniGetUI Updater.tar.gz"; + string installerPath = Path.Join(CoreData.UniGetUIDataDirectory, installerName); + UpdaterDownloadIdentity installerIdentity = new( + candidate.VersionName, + candidate.InstallerHash, + candidate.InstallerDownloadUrl + ); + + // Try cached installer first + if ( + File.Exists(installerPath) + && await CheckInstallerHashAsync(installerPath, candidate.InstallerHash, overrides) + && CheckInstallerSignerThumbprint(installerPath, overrides) + ) + { + ClearInstallerValidationFailure(GetInstallerValidationFailureMarkerPath(installerPath)); + UpdaterDownloadEngine.ClearFailureState( + UpdaterDownloadEngine.GetFailureStatePath(installerPath), + message => LogUpdateWarn(message) + ); + LogUpdateInfo("Cached valid installer found, preparing to launch..."); + return await PrepareAndLaunchAsync(installerPath, candidate.VersionName, autoLaunch, manualCheck); + } + + string installerValidationFailureMarkerPath = + GetInstallerValidationFailureMarkerPath(installerPath); + string installerDownloadFailureStatePath = + UpdaterDownloadEngine.GetFailureStatePath(installerPath); + if (File.Exists(installerPath)) + { + LogUpdateWarn( + "Cached installer is invalid; it will be kept until a replacement is validated." + ); + } + + if ( + !manualCheck + && UpdaterDownloadEngine.IsFailureBackoffActive( + installerDownloadFailureStatePath, + installerIdentity, + DateTime.UtcNow, + out TimeSpan remainingBackoff, + out UpdaterDownloadFailureState? failureState, + message => LogUpdateWarn(message) + ) + ) + { + LogUpdateWarn( + $"Skipping installer download for version {candidate.VersionName}; previous {failureState?.FailureClass ?? "download"} failure is backed off for {remainingBackoff:g}." + ); + MarkAttemptFinished("installer download skipped by failure backoff"); + return true; + } + + RaiseStatus( + CoreTools.Translate( + "UniGetUI version {0} is being downloaded.", + candidate.VersionName.ToString(CultureInfo.InvariantCulture)), + CoreTools.Translate("This may take a minute or two"), + InfoBarSeverity.Informational, + isClosable: false); + + LogUpdateInfo("Downloading installer..."); + string downloadedInstallerPath; + try + { + downloadedInstallerPath = await DownloadInstallerAsync( + candidate.InstallerDownloadUrl, + installerPath, + overrides, + installerIdentity + ); + } + catch (Exception ex) + { + UpdaterDownloadEngine.RecordFailure( + installerDownloadFailureStatePath, + installerIdentity, + "download", + DateTime.UtcNow, + message => LogUpdateWarn(message) + ); + LogUpdateWarn($"Installer download failed: {ex.Message}"); + throw; + } + + if ( + await CheckInstallerHashAsync(downloadedInstallerPath, candidate.InstallerHash, overrides) + && CheckInstallerSignerThumbprint(downloadedInstallerPath, overrides) + ) + { + UpdaterDownloadEngine.PromotePartialDownload( + installerPath, + message => LogUpdateWarn(message) + ); + ClearInstallerValidationFailure(installerValidationFailureMarkerPath); + UpdaterDownloadEngine.ClearFailureState( + installerDownloadFailureStatePath, + message => LogUpdateWarn(message) + ); + LogUpdateInfo("Downloaded installer is valid, preparing to launch..."); + return await PrepareAndLaunchAsync(installerPath, candidate.VersionName, autoLaunch, manualCheck); + } + + UpdaterDownloadEngine.RecordFailure( + installerDownloadFailureStatePath, + installerIdentity, + "validation", + DateTime.UtcNow, + message => LogUpdateWarn(message) + ); + UpdaterDownloadEngine.DeletePartialDownload( + installerPath, + message => LogUpdateWarn(message) + ); + + LogUpdateError("Installer authenticity could not be verified. Aborting update."); + RaiseStatus( + CoreTools.Translate("The installer authenticity could not be verified."), + CoreTools.Translate("The update process has been aborted."), + InfoBarSeverity.Error, + isClosable: true, + actionButtonText: CoreTools.Translate("View log"), + actionButtonAction: OpenUpdateLog); + MarkAttemptFinished("authenticity verification failed"); + return !manualCheck; + } + catch (PlatformArtifactMissingException ex) + { + // A newer version exists in productinfo but no installer artifact is + // published for the current OS/arch yet. Surface this as a friendly + // "manual update required" notice rather than a generic error. + LogUpdateWarn(ex.Message); + if (manualCheck) + { + RaiseStatus( + CoreTools.Translate("Auto-update is not yet available on this platform."), + CoreTools.Translate("Please update UniGetUI manually."), + InfoBarSeverity.Warning, + isClosable: true); + } + MarkAttemptFinished("platform artifact missing"); + return false; + } + catch (Exception ex) + { + LogUpdateError("An error occurred while checking for updates:"); + LogUpdateError(ex); + if (manualCheck || !wasCheckingForUpdates) + { + RaiseStatus( + CoreTools.Translate("An error occurred when checking for updates: "), + ex.Message, + InfoBarSeverity.Error, + isClosable: true, + actionButtonText: CoreTools.Translate("View log"), + actionButtonAction: OpenUpdateLog); + } + MarkAttemptFinished($"exception: {ex.Message}"); + return false; + } + } + + // ------------------------------------------------------------------ update flow + internal static string GetInstallerValidationFailureMarkerPath(string installerPath) + { + return installerPath + INSTALLER_VALIDATION_FAILURE_MARKER_SUFFIX; + } + + private static void ClearInstallerValidationFailure(string markerPath) + { + DeleteFileIfExists(markerPath, "installer validation failure marker"); + } + + private static void DeleteFileIfExists(string path, string description) + { + if (!File.Exists(path)) + { + return; + } + + try + { + File.Delete(path); + } + catch (Exception ex) + { + LogUpdateWarn($"Could not delete {description} at '{path}': {ex.Message}"); + } + } + + private static async Task PrepareAndLaunchAsync( + string installerPath, + string versionName, + bool autoLaunch, + bool manualCheck) + { + _pendingInstallerPath = installerPath; + _installRequested = false; + ReleaseLockForAutoupdate_Notification = false; + + // Notify UI (update banner + toast) + Dispatcher.UIThread.Post(() => UpdateAvailable?.Invoke(versionName)); + if (OperatingSystem.IsWindows()) + WindowsAppNotificationBridge.ShowSelfUpdateAvailableNotification(versionName); + else if (OperatingSystem.IsMacOS()) + MacOsNotificationBridge.ShowSelfUpdateAvailableNotification(versionName); + + if (autoLaunch) + { + // On first launch in background we wait for user interaction + } + + // Wait until user requests install, clicks the toast, or the window is being closed + while (!_installRequested && !ReleaseLockForAutoupdate_Window && !ReleaseLockForAutoupdate_Notification) + { + if (!manualCheck && Settings.Get(Settings.K.DisableAutoUpdateWingetUI)) + { + LogUpdateWarn("Auto-updater: disabled while waiting for user \u2014 aborting."); + MarkAttemptFinished("aborted - auto-update disabled while waiting"); + return true; + } + await Task.Delay(500); + } + + LogUpdateInfo("Installing update \u2014 launching installer."); + await LaunchInstallerAsync(installerPath); + return true; + } + + private static async Task LaunchInstallerAsync(string installerLocation) + { + if (OperatingSystem.IsMacOS()) + { + await LaunchMacInstallerAsync(installerLocation); + return; + } + + if (OperatingSystem.IsLinux()) + { + await LaunchLinuxInstallerAsync(installerLocation); + return; + } + + LogUpdateInfo($"Launching installer: {installerLocation}"); + using Process p = new() + { + StartInfo = new ProcessStartInfo + { + FileName = installerLocation, + Arguments = "/SILENT /SUPPRESSMSGBOXES /NORESTART /SP- /NoVCRedist /NoEdgeWebView /NoWinGet", + UseShellExecute = true, + CreateNoWindow = true, + }, + }; + + bool started; + try + { + started = p.Start(); + } + catch (Exception ex) + { + LogUpdateError("Process.Start threw while launching the installer:"); + LogUpdateError(ex); + RaiseStatus( + CoreTools.Translate("The updater could not be launched."), + ex.Message, + InfoBarSeverity.Error, + isClosable: true, + actionButtonText: CoreTools.Translate("View log"), + actionButtonAction: OpenUpdateLog); + MarkAttemptFinished($"installer launch threw: {ex.Message}"); + return; + } + + if (!started) + { + LogUpdateError("Failed to start installer process (Process.Start returned false)."); + RaiseStatus( + CoreTools.Translate("The updater could not be launched."), + CoreTools.Translate("The operating system did not start the installer process."), + InfoBarSeverity.Error, + isClosable: true, + actionButtonText: CoreTools.Translate("View log"), + actionButtonAction: OpenUpdateLog); + MarkAttemptFinished("Process.Start returned false"); + return; + } + + LogUpdateInfo($"Installer process started (PID {p.Id}). The installer is expected to terminate UniGetUI before file replacement."); + + RaiseStatus( + CoreTools.Translate("UniGetUI is being updated..."), + CoreTools.Translate("This may take a minute or two"), + InfoBarSeverity.Informational, + isClosable: false); + + await p.WaitForExitAsync(); + + // If we reach here, the installer exited without terminating this process. + // Distinguish two cases: + // - Exit code 0: installer succeeded; the new version IS installed at the + // install location, but the running copy was not replaced (almost always + // because UniGetUI is running from outside the install location — typically + // a development build). This is not really an error. + // - Any other code: installer reported a failure; the update did not apply. + int exitCode = p.ExitCode; + string reason = DescribeInstallerExitCode(exitCode); + + if (exitCode == 0) + { + string runningPath = Environment.ProcessPath ?? "(unknown)"; + LogUpdateWarn($"Installer reported success (exit code 0) but did not replace this running copy. Running from: {runningPath}"); + + RaiseStatus( + CoreTools.Translate("Update installed."), + CoreTools.Translate("UniGetUI was updated successfully, but this running copy was not replaced. This usually means you are running a development build. Close this copy and start the newly-installed version to finish."), + InfoBarSeverity.Warning, + isClosable: true, + actionButtonText: CoreTools.Translate("View log"), + actionButtonAction: OpenUpdateLog); + MarkAttemptFinished("installer succeeded but did not replace running copy"); + return; + } + + LogUpdateError($"Installer exited with code {exitCode} ({reason}) without restarting UniGetUI."); + + RaiseStatus( + CoreTools.Translate("The update could not be applied."), + CoreTools.Translate("Installer exit code {0}: {1}", exitCode, reason), + InfoBarSeverity.Error, + isClosable: true, + actionButtonText: CoreTools.Translate("View log"), + actionButtonAction: OpenUpdateLog); + MarkAttemptFinished($"installer failed with code {exitCode}"); + } + + [SupportedOSPlatform("macos")] + private static async Task LaunchMacInstallerAsync(string installerLocation) + { + LogUpdateInfo($"Applying macOS update from archive: {installerLocation}"); + + RaiseStatus( + CoreTools.Translate("UniGetUI is being updated..."), + CoreTools.Translate("This may take a minute or two"), + InfoBarSeverity.Informational, + isClosable: false); + + string stagingDir; + try + { + stagingDir = await Task.Run(() => ExtractTarGz(installerLocation)); + } + catch (Exception ex) + { + LogUpdateError("Failed to extract the macOS update archive:"); + LogUpdateError(ex); + RaiseStatus( + CoreTools.Translate("The update could not be applied."), + ex.Message, + InfoBarSeverity.Error, + isClosable: true, + actionButtonText: CoreTools.Translate("View log"), + actionButtonAction: OpenUpdateLog); + MarkAttemptFinished($"archive extraction failed: {ex.Message}"); + return; + } + + // Locate the UniGetUI.app bundle inside the extracted archive. + string topLevelApp = Path.Join(stagingDir, "UniGetUI.app"); + string? newApp = Directory.Exists(topLevelApp) + ? topLevelApp + : Directory.EnumerateDirectories(stagingDir, "UniGetUI.app", SearchOption.AllDirectories).FirstOrDefault(); + + if (newApp is null || !Directory.Exists(newApp)) + { + LogUpdateError($"Could not find UniGetUI.app inside the extracted archive at {stagingDir}."); + RaiseStatus( + CoreTools.Translate("The update could not be applied."), + CoreTools.Translate("The update package was malformed."), + InfoBarSeverity.Error, + isClosable: true, + actionButtonText: CoreTools.Translate("View log"), + actionButtonAction: OpenUpdateLog); + MarkAttemptFinished("UniGetUI.app not found in archive"); + return; + } + + // Verify the embedded app is signed by Devolutions before trusting it. + if (!VerifyMacAppSignature(newApp)) + { + LogUpdateError("The extracted app failed signature validation. Aborting update."); + RaiseStatus( + CoreTools.Translate("The installer authenticity could not be verified."), + CoreTools.Translate("The update process has been aborted."), + InfoBarSeverity.Error, + isClosable: true, + actionButtonText: CoreTools.Translate("View log"), + actionButtonAction: OpenUpdateLog); + MarkAttemptFinished("extracted app signature invalid"); + return; + } + + // Replace the *running* bundle wherever it lives, falling back to /Applications. + string target = ResolveRunningMacAppBundle() ?? "/Applications/UniGetUI.app"; + + if (!Directory.Exists(target)) + { + LogUpdateWarn( + $"No installed .app bundle found at {target} (running from {Environment.ProcessPath ?? "unknown"}); " + + "the running copy will not be replaced." + ); + ReportRunningCopyNotReplaced("no installed bundle to replace"); + return; + } + + // Guard against clobbering a development build (a published .app sitting in a + // build/publish output tree). + if (LooksLikeDevBuild(string.Empty, target)) + { + LogUpdateWarn($"Resolved bundle '{target}' looks like a development build; the running copy will not be replaced."); + ReportRunningCopyNotReplaced("development build detected; running copy not replaced"); + return; + } + + LogUpdateInfo($"Replacing {target} with the freshly-extracted bundle and relaunching."); + + // The swap is handed to a detached helper that waits for THIS process to exit + // before touching the bundle, so the running app never has its files yanked out + // from under it. On success the helper relaunches the new bundle; on any failure + // it rolls back and relaunches whatever remains. We deliberately do NOT write the + // "attempt finished" marker here — exactly like the Windows installer path, the + // relaunched copy confirms success via CheckForOrphanedUpdateAttempt() by + // comparing its own version against the recorded target version. + // + // Arguments are passed positionally ($1=pid, $2=target, $3=new app) so no path + // is ever interpolated into the script text. + const string swap = """ + pid="$1"; target="$2"; newapp="$3" + i=0 + while kill -0 "$pid" 2>/dev/null && [ "$i" -lt 150 ]; do sleep 0.2; i=$((i+1)); done + rm -rf "$target.old" + if mv "$target" "$target.old"; then + if mv "$newapp" "$target"; then + xattr -dr com.apple.quarantine "$target" 2>/dev/null + rm -rf "$target.old" + else + rm -rf "$target" + mv "$target.old" "$target" + fi + fi + /usr/bin/open -na "$target" + """; + if (!TrySpawnSwapHelper(swap, Environment.ProcessId.ToString(CultureInfo.InvariantCulture), target, newApp)) + { + // We could not even launch the helper, so nothing was changed. Report and bail + // without exiting so the user keeps a working copy. + RaiseStatus( + CoreTools.Translate("The update could not be applied."), + CoreTools.Translate("The updater could not be launched."), + InfoBarSeverity.Error, + isClosable: true, + actionButtonText: CoreTools.Translate("View log"), + actionButtonAction: OpenUpdateLog); + MarkAttemptFinished("could not spawn swap helper"); + return; + } + + // Match the Windows flow: terminate the running copy so the helper can replace + // the bundle and relaunch the freshly-installed version. + Environment.Exit(0); + } + + [SupportedOSPlatform("linux")] + private static async Task LaunchLinuxInstallerAsync(string installerLocation) + { + LogUpdateInfo($"Applying Linux update from archive: {installerLocation}"); + + RaiseStatus( + CoreTools.Translate("UniGetUI is being updated..."), + CoreTools.Translate("This may take a minute or two"), + InfoBarSeverity.Informational, + isClosable: false); + + // The directory holding the running executable is the install location to replace. + string? exePath = Environment.ProcessPath; + string? installDir = Path.GetDirectoryName(exePath); + if (string.IsNullOrEmpty(exePath) || string.IsNullOrEmpty(installDir)) + { + LogUpdateWarn( + $"Could not resolve the running install directory (ProcessPath='{exePath}'); " + + "the running copy will not be replaced." + ); + ReportRunningCopyNotReplaced("could not resolve install directory; running copy not replaced"); + return; + } + + string exeName = Path.GetFileName(exePath); + + // Guard against clobbering a development build: when running through the `dotnet` + // host or from a build/publish output tree, do not swap the directory in place. + if (LooksLikeDevBuild(exeName, installDir)) + { + LogUpdateWarn($"Running from what looks like a development build ('{exePath}'); the running copy will not be replaced."); + ReportRunningCopyNotReplaced("development build detected; running copy not replaced"); + return; + } + + string stagingDir; + try + { + stagingDir = await Task.Run(() => ExtractTarGz(installerLocation)); + } + catch (Exception ex) + { + LogUpdateError("Failed to extract the Linux update archive:"); + LogUpdateError(ex); + RaiseStatus( + CoreTools.Translate("The update could not be applied."), + ex.Message, + InfoBarSeverity.Error, + isClosable: true, + actionButtonText: CoreTools.Translate("View log"), + actionButtonAction: OpenUpdateLog); + MarkAttemptFinished($"archive extraction failed: {ex.Message}"); + return; + } + + // The new install tree is either the single top-level directory inside the + // archive, or the staging directory itself if the executable sits at the root. + string newRoot = ResolveExtractedLinuxRoot(stagingDir); + + // Confirm the archive actually contains the executable we expect before we + // commit to swapping the install directory. + if (!File.Exists(Path.Join(newRoot, exeName))) + { + LogUpdateError($"Expected executable '{exeName}' was not found in the extracted archive at {newRoot}."); + RaiseStatus( + CoreTools.Translate("The update could not be applied."), + CoreTools.Translate("The update package was malformed."), + InfoBarSeverity.Error, + isClosable: true, + actionButtonText: CoreTools.Translate("View log"), + actionButtonAction: OpenUpdateLog); + MarkAttemptFinished("executable not found in archive"); + return; + } + + LogUpdateInfo($"Replacing install directory {installDir} with the freshly-extracted tree and relaunching."); + + // Hand the swap to a detached helper that waits for THIS process to exit before + // renaming the install directory (renaming, not overwriting, avoids "text file + // busy" on the running executable and keeps the running process's mapped files + // intact until it is gone). On failure the helper rolls back. As with Windows, + // success/failure is confirmed by the relaunched copy via + // CheckForOrphanedUpdateAttempt() — so no "attempt finished" marker is written here. + // + // Positional args: $1=pid, $2=install dir, $3=new tree, $4=executable name. + const string swap = """ + pid="$1"; dir="$2"; newroot="$3"; exe="$4" + i=0 + while kill -0 "$pid" 2>/dev/null && [ "$i" -lt 150 ]; do sleep 0.2; i=$((i+1)); done + rm -rf "$dir.old" + if mv "$dir" "$dir.old"; then + if mv "$newroot" "$dir"; then + chmod +x "$dir/$exe" 2>/dev/null + rm -rf "$dir.old" + else + rm -rf "$dir" + mv "$dir.old" "$dir" + fi + fi + "$dir/$exe" >/dev/null 2>&1 & + """; + if (!TrySpawnSwapHelper(swap, Environment.ProcessId.ToString(CultureInfo.InvariantCulture), installDir, newRoot, exeName)) + { + RaiseStatus( + CoreTools.Translate("The update could not be applied."), + CoreTools.Translate("The updater could not be launched."), + InfoBarSeverity.Error, + isClosable: true, + actionButtonText: CoreTools.Translate("View log"), + actionButtonAction: OpenUpdateLog); + MarkAttemptFinished("could not spawn swap helper"); + return; + } + + Environment.Exit(0); + } + + // Shows the friendly "updated, but this running copy was not replaced" notice used + // for development builds and unresolved install locations, and finishes the attempt. + private static void ReportRunningCopyNotReplaced(string outcome) + { + RaiseStatus( + CoreTools.Translate("Update installed."), + CoreTools.Translate("UniGetUI was updated successfully, but this running copy was not replaced. This usually means you are running a development build. Close this copy and start the newly-installed version to finish."), + InfoBarSeverity.Warning, + isClosable: true, + actionButtonText: CoreTools.Translate("View log"), + actionButtonAction: OpenUpdateLog); + MarkAttemptFinished(outcome); + } + + // True when the running process looks like a development build rather than an + // installed copy that should replace itself in place. + private static bool LooksLikeDevBuild(string exeName, string installDir) + { + if (exeName.Equals("dotnet", StringComparison.OrdinalIgnoreCase)) + return true; + + char sep = Path.DirectorySeparatorChar; + return installDir.Contains($"{sep}bin{sep}Debug{sep}", StringComparison.OrdinalIgnoreCase) + || installDir.Contains($"{sep}bin{sep}Release{sep}", StringComparison.OrdinalIgnoreCase) + || installDir.Contains($"{sep}obj{sep}", StringComparison.OrdinalIgnoreCase); + } + + // Launches the detached /bin/sh helper that performs the file swap after this + // process exits. Returns false if the helper process could not be started. + private static bool TrySpawnSwapHelper(string script, params string[] positionalArgs) + { + try + { + var psi = new ProcessStartInfo + { + FileName = "/bin/sh", + UseShellExecute = false, + CreateNoWindow = true, + }; + psi.ArgumentList.Add("-c"); + psi.ArgumentList.Add(script); + psi.ArgumentList.Add("sh"); // becomes $0 inside the script + foreach (string arg in positionalArgs) + { + psi.ArgumentList.Add(arg); + } + + Process? p = Process.Start(psi); + return p is not null; + } + catch (Exception ex) + { + LogUpdateError("Could not spawn the update swap helper:"); + LogUpdateError(ex); + return false; + } + } + + // ------------------------------------------------------------------ archive helpers + // Extracts a .tar.gz into a fresh per-attempt staging directory and returns its path. + private static string ExtractTarGz(string tarballPath) + { + string stagingRoot = Path.Join(CoreData.UniGetUIDataDirectory, "update-staging"); + Directory.CreateDirectory(stagingRoot); + PruneStaleStagingDirs(stagingRoot); + + // A unique subdirectory per attempt: update checks can run concurrently (the + // background loop and a manual check), so a single shared directory would let two + // attempts delete/overwrite each other's contents mid-extraction. + string stagingDir = Path.Join(stagingRoot, Guid.NewGuid().ToString("N")); + Directory.CreateDirectory(stagingDir); + + string tar = ResolveTarExecutable(); + LogUpdateInfo($"Extracting {tarballPath} -> {stagingDir} (using '{tar}')"); + + // Use the system `tar` rather than System.Formats.Tar: the published archives use + // PAX extended headers that the managed TarReader rejects ("extended header + // contains invalid records"), whereas bsdtar (macOS) and GNU tar (Linux) extract + // them cleanly while restoring Unix permissions and symlinks. + using Process p = new() + { + StartInfo = new ProcessStartInfo + { + FileName = tar, + ArgumentList = { "-xzf", tarballPath, "-C", stagingDir }, + UseShellExecute = false, + RedirectStandardError = true, + CreateNoWindow = true, + }, + }; + p.Start(); + string stderr = p.StandardError.ReadToEnd(); + p.WaitForExit(); + if (p.ExitCode != 0) + { + throw new InvalidOperationException( + $"tar exited with code {p.ExitCode} while extracting the update archive. {stderr.Trim()}"); + } + return stagingDir; + } + + // Resolves the `tar` executable. Prefers the standard FHS locations, then defers to a + // bare name so the OS resolves it from PATH (covers Nix and other non-FHS layouts; + // Process searches PATH for an unrooted file name when UseShellExecute is false). + private static string ResolveTarExecutable() + { + foreach (string candidate in new[] { "/usr/bin/tar", "/bin/tar" }) + { + if (File.Exists(candidate)) + { + return candidate; + } + } + return "tar"; + } + + // Best-effort removal of staging directories left behind by previous runs. Only + // touches directories old enough that no in-flight attempt could still be using them, + // so it never races a concurrent extraction. + private static void PruneStaleStagingDirs(string stagingRoot) + { + try + { + foreach (string dir in Directory.EnumerateDirectories(stagingRoot)) + { + try + { + if (DateTime.Now - Directory.GetLastWriteTime(dir) > TimeSpan.FromHours(1)) + { + Directory.Delete(dir, recursive: true); + } + } + catch { /* leftover will be retried next time */ } + } + } + catch (Exception ex) + { + LogUpdateWarn($"Could not prune stale staging directories: {ex.Message}"); + } + } + + // If the archive wraps everything in a single top-level directory, return it; + // otherwise the staging directory itself is the install root. + private static string ResolveExtractedLinuxRoot(string stagingDir) + { + string[] entries = Directory.GetFileSystemEntries(stagingDir); + if (entries.Length == 1 && Directory.Exists(entries[0])) + { + return entries[0]; + } + return stagingDir; + } + + // Walks up from the running executable to the enclosing ".app" bundle directory. + [SupportedOSPlatform("macos")] + private static string? ResolveRunningMacAppBundle() + { + // Environment.ProcessPath is typically /Applications/UniGetUI.app/Contents/MacOS/UniGetUI. + string? dir = Path.GetDirectoryName(Environment.ProcessPath); + while (!string.IsNullOrEmpty(dir)) + { + if (dir.EndsWith(".app", StringComparison.OrdinalIgnoreCase)) + { + return dir; + } + dir = Path.GetDirectoryName(dir); + } + return null; + } + + // ------------------------------------------------------------------ update check sources + private static async Task GetUpdateCandidateAsync(UpdaterOverrides overrides) + { + return await CheckFromProductInfoAsync(overrides); + } + + private static async Task CheckFromProductInfoAsync(UpdaterOverrides overrides) + { + LogUpdateDebug($"Checking updates via ProductInfo: {overrides.ProductInfoUrl}"); + + if (!IsSourceUrlAllowed(overrides.ProductInfoUrl, overrides.AllowUnsafeUrls)) + { + throw new InvalidOperationException( + $"ProductInfo URL is not allowed: {overrides.ProductInfoUrl}" + ); + } + + string json; + using (HttpClient client = new(CreateHttpClientHandler(overrides))) + { + client.Timeout = TimeSpan.FromSeconds(600); + client.DefaultRequestHeaders.UserAgent.ParseAdd(CoreData.UserAgentString); + json = await client.GetStringAsync(overrides.ProductInfoUrl); + } + + Dictionary? root = + JsonSerializer.Deserialize( + json, + typeof(Dictionary), + _jsonContext + ) as Dictionary; + + if (root is null || root.Count == 0) + { + throw new FormatException("productinfo.json is empty or invalid."); + } + + if (!root.TryGetValue(overrides.ProductInfoProductKey, out ProductInfoProduct? product)) + { + throw new KeyNotFoundException( + $"Product key '{overrides.ProductInfoProductKey}' not found in productinfo.json" + ); + } + + bool useBeta = Settings.Get(Settings.K.EnableUniGetUIBeta); + ProductInfoChannel? channel = useBeta ? product.Beta : product.Current; + if (channel is null) + { + throw new KeyNotFoundException( + $"Channel '{(useBeta ? "Beta" : "Current")}' not found for product '{overrides.ProductInfoProductKey}'" + ); + } + + ProductInfoFile installer = SelectInstallerFile(channel.Files); + if (!IsSourceUrlAllowed(installer.Url, overrides.AllowUnsafeUrls)) + { + throw new InvalidOperationException($"Installer URL is not allowed: {installer.Url}"); + } + + Version current = ParseVersionOrFallback( + CoreData.VersionName, + new Version(0, 0, 0, CoreData.BuildNumber) + ); + Version available = ParseVersionOrFallback(channel.Version, new Version(0, 0, 0, 0)); + bool upgradable = available > current; + + LogUpdateDebug( + $"ProductInfo check: current={current}, available={available}, upgradable={upgradable}" + ); + + return new UpdateCandidate(upgradable, channel.Version, installer.Hash, installer.Url, "ProductInfo"); + } + + // ------------------------------------------------------------------ validation helpers + private static async Task CheckInstallerHashAsync( + string path, + string expectedHash, + UpdaterOverrides overrides) + { + if (overrides.SkipHashValidation) + { + LogUpdateWarn("Registry override: skipping hash validation."); + return true; + } + + using FileStream fs = File.OpenRead(path); + string actual = Convert + .ToHexString(await SHA256.Create().ComputeHashAsync(fs)) + .ToLowerInvariant(); + + if (actual == expectedHash.ToLowerInvariant()) + { + LogUpdateDebug($"Hash match: {actual}"); + return true; + } + + LogUpdateWarn($"Hash mismatch. Expected: {expectedHash} Got: {actual}"); + return false; + } + + private static bool CheckInstallerSignerThumbprint(string path, UpdaterOverrides overrides) + { + if (overrides.SkipSignerThumbprintCheck) + { + LogUpdateWarn("Registry override: skipping signer thumbprint validation."); + return true; + } + + if (OperatingSystem.IsMacOS()) + { + // The downloaded artifact is a .tar.gz archive, which carries no signature of + // its own. Integrity is guaranteed by the SHA256 hash (verified separately + // against productinfo.json fetched over HTTPS from a trusted host). The + // Developer ID of the embedded UniGetUI.app is verified after extraction, in + // VerifyMacAppSignature(), before the running bundle is replaced. + LogUpdateDebug("macOS .tar.gz integrity is enforced via hash; the app signature is verified post-extraction."); + return true; + } + + if (OperatingSystem.IsLinux()) + { + // .tar.gz has no built-in signing format equivalent to Authenticode/.pkg. + // Hash validation (verified separately, against the productinfo.json fetched + // over HTTPS from a trusted host) provides the integrity guarantee. A future + // extension could verify a detached GPG signature published alongside the + // archive in productinfo. + LogUpdateWarn("Linux .tar.gz signature validation is not implemented — relying on hash check."); + return true; + } + + if (!OperatingSystem.IsWindows()) + { + LogUpdateWarn("Skipping installer signature validation on unsupported platform."); + return true; + } + + try + { +#pragma warning disable SYSLIB0057 + X509Certificate signerCert = X509Certificate.CreateFromSignedFile(path); +#pragma warning restore SYSLIB0057 + using X509Certificate2 cert2 = new(signerCert); + string thumbprint = NormalizeThumbprint(cert2.Thumbprint ?? string.Empty); + + if (string.IsNullOrWhiteSpace(thumbprint)) + { + LogUpdateWarn($"Could not read signer thumbprint for '{path}'"); + return false; + } + + if (DEVOLUTIONS_CERT_THUMBPRINTS.Contains(thumbprint, StringComparer.OrdinalIgnoreCase)) + { + LogUpdateDebug($"Installer signer thumbprint is trusted: {thumbprint}"); + return true; + } + + LogUpdateWarn($"Installer signer thumbprint is NOT trusted: {thumbprint}"); + return false; + } + catch (Exception ex) + { + LogUpdateWarn("Could not validate installer signer thumbprint."); + LogUpdateWarn(ex); + return false; + } + } + + [SupportedOSPlatform("macos")] + private static bool VerifyMacAppSignature(string appBundlePath) + { + if (DEVOLUTIONS_MAC_DEVELOPER_IDS.Length == 0) + { + LogUpdateWarn( + "No Devolutions macOS Developer Team IDs configured — skipping .app signature validation." + ); + return true; + } + + // IMPORTANT: `codesign --verify` (with or without --deep/--strict) cannot be used + // as a gate here. The published self-contained .NET bundle contains nested managed + // assemblies that are not individually code-signed, so --verify reports "code + // object is not signed at all" even for a perfectly legitimate, Developer-ID-signed + // bundle (and `spctl` likewise rejects it). Integrity and authenticity are already + // guaranteed by the SHA256 hash, which is checked against productinfo.json fetched + // over HTTPS from a trusted host. Here we additionally read the bundle's Team + // Identifier as a best-effort signer check: a *mismatch* is treated as tampering + // and blocks the update; an absent/unreadable signature only warns and defers to + // the verified download hash. + try + { + using Process info = new() + { + StartInfo = new ProcessStartInfo + { + FileName = "/usr/bin/codesign", + ArgumentList = { "-dv", "--verbose=4", appBundlePath }, + UseShellExecute = false, + RedirectStandardOutput = true, + RedirectStandardError = true, + CreateNoWindow = true, + }, + }; + info.Start(); + // codesign prints the signing metadata to stderr, but read both streams + // concurrently so a full pipe on one stream can never deadlock the updater. + Task stderrTask = info.StandardError.ReadToEndAsync(); + Task stdoutTask = info.StandardOutput.ReadToEndAsync(); + info.WaitForExit(); + string metadata = stderrTask.GetAwaiter().GetResult() + stdoutTask.GetAwaiter().GetResult(); + + if (info.ExitCode != 0) + { + LogUpdateWarn("Could not read the extracted app's code signature; relying on the verified download hash."); + return true; + } + + string? teamId = null; + foreach (string rawLine in metadata.Split('\n')) + { + string line = rawLine.Trim(); + if (line.StartsWith("TeamIdentifier=", StringComparison.OrdinalIgnoreCase)) + { + teamId = line["TeamIdentifier=".Length..].Trim(); + break; + } + } + + if (string.IsNullOrEmpty(teamId) || teamId.Equals("not set", StringComparison.OrdinalIgnoreCase)) + { + LogUpdateWarn("Extracted app has no Team Identifier; relying on the verified download hash."); + return true; + } + + if (DEVOLUTIONS_MAC_DEVELOPER_IDS.Contains(teamId, StringComparer.OrdinalIgnoreCase)) + { + LogUpdateDebug($"Extracted app is signed by trusted Developer Team ID {teamId}."); + return true; + } + + LogUpdateWarn($"Extracted app is signed by an untrusted Team Identifier '{teamId}'. Aborting update."); + return false; + } + catch (Exception ex) + { + LogUpdateWarn("Could not validate the extracted app signature via codesign; relying on the verified download hash."); + LogUpdateWarn(ex); + return true; + } + } + + // ------------------------------------------------------------------ download + private static async Task DownloadInstallerAsync( + string url, + string destination, + UpdaterOverrides overrides, + UpdaterDownloadIdentity identity) + { + if (!IsSourceUrlAllowed(url, overrides.AllowUnsafeUrls)) + { + throw new InvalidOperationException($"Download URL is not allowed: {url}"); + } + + LogUpdateDebug($"Downloading installer from {url}"); + using HttpClient client = new(CreateHttpClientHandler(overrides)); + client.Timeout = TimeSpan.FromSeconds(600); + client.DefaultRequestHeaders.UserAgent.ParseAdd(CoreData.UserAgentString); + using CancellationTokenSource downloadTimeout = new(TimeSpan.FromSeconds(600)); + + UpdaterDownloadResult result = await UpdaterDownloadEngine.DownloadInstallerPartAsync( + client, + identity, + destination, + message => LogUpdateDebug(message), + downloadTimeout.Token + ); + + LogUpdateDebug("Installer download complete."); + return result.PartialPath; + } + + // ------------------------------------------------------------------ HTTP client + private static HttpClientHandler CreateHttpClientHandler(UpdaterOverrides overrides) + { + var handler = new HttpClientHandler(); + if (overrides.DisableTlsValidation) + { + LogUpdateWarn("Registry override: TLS certificate validation is disabled for updater requests."); + handler.ServerCertificateCustomValidationCallback = static (_, _, _, _) => true; + } + return handler; + } + + // ------------------------------------------------------------------ URL / arch helpers + private static bool IsSourceUrlAllowed(string url, bool allowUnsafe) + { + if (!Uri.TryCreate(url, UriKind.Absolute, out Uri? uri)) + { + return false; + } + + if (allowUnsafe) + { + LogUpdateWarn($"Registry override: allowing potentially unsafe URL {url}"); + return true; + } + + if (!string.Equals(uri.Scheme, Uri.UriSchemeHttps, StringComparison.OrdinalIgnoreCase)) + { + return false; + } + + return uri.Host.Equals("devolutions.net", StringComparison.OrdinalIgnoreCase) + || uri.Host.EndsWith(".devolutions.net", StringComparison.OrdinalIgnoreCase) + || uri.Host.Equals("github.com", StringComparison.OrdinalIgnoreCase) + || uri.Host.Equals("objects.githubusercontent.com", StringComparison.OrdinalIgnoreCase) + || uri.Host.Equals("release-assets.githubusercontent.com", StringComparison.OrdinalIgnoreCase); + } + + private static ProductInfoFile SelectInstallerFile(List files) + { + string arch = RuntimeInformation.ProcessArchitecture switch + { + Architecture.Arm64 => "arm64", + _ => "x64", + }; + + // Note: macOS and Linux both publish "tar.gz" artifacts, so the Type field + // alone is ambiguous between the two. Disambiguate on the platform token that + // is embedded in the download URL (e.g. "...macos-arm64..." vs "...linux-x64..."). + if (OperatingSystem.IsMacOS()) + { + ProductInfoFile? mac = + files.FirstOrDefault(f => IsTarGzFor(f, "macos", arch)) + ?? files.FirstOrDefault(f => IsTarGzFor(f, "macos", "universal")) + ?? files.FirstOrDefault(f => IsTarGzFor(f, "macos", "Any")); + + return mac ?? throw new PlatformArtifactMissingException( + $"No compatible macOS package (.tar.gz) found in productinfo for architecture '{arch}'" + ); + } + + if (OperatingSystem.IsLinux()) + { + ProductInfoFile? linux = + files.FirstOrDefault(f => IsTarGzFor(f, "linux", arch)) + ?? files.FirstOrDefault(f => IsTarGzFor(f, "linux", "universal")) + ?? files.FirstOrDefault(f => IsTarGzFor(f, "linux", "Any")); + + return linux ?? throw new PlatformArtifactMissingException( + $"No compatible Linux package (.tar.gz) found in productinfo for architecture '{arch}'" + ); + } + + ProductInfoFile? match = + files.FirstOrDefault(f => f.Type.Equals("exe", StringComparison.OrdinalIgnoreCase) && f.Arch.Equals(arch, StringComparison.OrdinalIgnoreCase)) + ?? files.FirstOrDefault(f => f.Type.Equals("exe", StringComparison.OrdinalIgnoreCase) && f.Arch.Equals("Any", StringComparison.OrdinalIgnoreCase)) + ?? files.FirstOrDefault(f => f.Type.Equals("msi", StringComparison.OrdinalIgnoreCase) && f.Arch.Equals(arch, StringComparison.OrdinalIgnoreCase)) + ?? files.FirstOrDefault(f => f.Type.Equals("msi", StringComparison.OrdinalIgnoreCase) && f.Arch.Equals("Any", StringComparison.OrdinalIgnoreCase)); + + return match ?? throw new KeyNotFoundException( + $"No compatible installer found in productinfo for architecture '{arch}'" + ); + } + + // Matches a .tar.gz artifact for a given OS (identified by a token in the URL, + // since macOS and Linux share the same "tar.gz" Type) and processor architecture. + private static bool IsTarGzFor(ProductInfoFile f, string osToken, string arch) => + f.Type.Equals("tar.gz", StringComparison.OrdinalIgnoreCase) + && f.Arch.Equals(arch, StringComparison.OrdinalIgnoreCase) + && f.Url.Contains(osToken, StringComparison.OrdinalIgnoreCase); + + private static Version ParseVersionOrFallback(string raw, Version fallback) + { + string sanitized = raw.Trim().TrimStart('v', 'V'); + if (Version.TryParse(sanitized, out Version? parsed)) + { + return CoreTools.NormalizeVersionForComparison(parsed); + } + + LogUpdateWarn($"Could not parse version '{raw}', using fallback '{fallback}'"); + return fallback; + } + + // Normalize trailing zero components so "2026.1.11" and "2026.1.11.0" compare equal. + private static bool VersionsMatch(string a, string b) + { + string sa = a.Trim().TrimStart('v', 'V'); + string sb = b.Trim().TrimStart('v', 'V'); + + if (Version.TryParse(sa, out Version? va) && Version.TryParse(sb, out Version? vb)) + { + return CoreTools.NormalizeVersionForComparison(va) + .Equals(CoreTools.NormalizeVersionForComparison(vb)); + } + + return string.Equals(sa, sb, StringComparison.OrdinalIgnoreCase); + } + + private static string NormalizeThumbprint(string thumbprint) => + new(thumbprint.ToLowerInvariant().Where(char.IsAsciiHexDigit).ToArray()); + + // ------------------------------------------------------------------ registry + private static UpdaterOverrides LoadUpdaterOverrides() + { + if (!OperatingSystem.IsWindows()) + { + return new UpdaterOverrides( + DEFAULT_PRODUCTINFO_URL, + DEFAULT_PRODUCTINFO_KEY, + false, + false, + false, + false + ); + } + +#pragma warning disable CA1416 + using RegistryKey? key = Registry.LocalMachine.OpenSubKey(REGISTRY_PATH); + +#if DEBUG + if (key is not null) + { + LogUpdateInfo($"Updater registry overrides loaded from HKLM\\{REGISTRY_PATH}"); + } + + return new UpdaterOverrides( + GetRegistryString(key, REG_PRODUCTINFO_URL) ?? DEFAULT_PRODUCTINFO_URL, + GetRegistryString(key, REG_PRODUCTINFO_KEY) ?? DEFAULT_PRODUCTINFO_KEY, + GetRegistryBool(key, REG_ALLOW_UNSAFE_URLS), + GetRegistryBool(key, REG_SKIP_HASH_VALIDATION), + GetRegistryBool(key, REG_SKIP_SIGNER_THUMBPRINT_CHECK), + GetRegistryBool(key, REG_DISABLE_TLS_VALIDATION) + ); +#else + LogIgnoredReleaseOverrides(key); + string productInfoUrl = GetRegistryString(key, REG_PRODUCTINFO_URL) ?? DEFAULT_PRODUCTINFO_URL; + + return new UpdaterOverrides( + productInfoUrl, + DEFAULT_PRODUCTINFO_KEY, + false, + false, + false, + false + ); +#endif +#pragma warning restore CA1416 + } + +#if !DEBUG + private static void LogIgnoredReleaseOverrides(RegistryKey? key) + { +#pragma warning disable CA1416 + if (key is null) + { + return; + } + + foreach (string valueName in RELEASE_IGNORED_REGISTRY_VALUES) + { + if (key.GetValue(valueName) is not null) + { + LogUpdateWarn( + $"Release build is ignoring updater registry value HKLM\\{REGISTRY_PATH}\\{valueName}." + ); + } + } +#pragma warning restore CA1416 + } +#endif + + private static string? GetRegistryString(RegistryKey? key, string valueName) + { +#pragma warning disable CA1416 + string? parsed = key?.GetValue(valueName)?.ToString(); +#pragma warning restore CA1416 + return string.IsNullOrWhiteSpace(parsed) ? null : parsed.Trim(); + } + +#if DEBUG + private static bool GetRegistryBool(RegistryKey? key, string valueName) + { +#pragma warning disable CA1416 + object? value = key?.GetValue(valueName); +#pragma warning restore CA1416 + if (value is null) return false; + if (value is int i) return i != 0; + if (value is long l) return l != 0; + string s = value.ToString()?.Trim() ?? ""; + return s == "1" + || s.Equals("true", StringComparison.OrdinalIgnoreCase) + || s.Equals("yes", StringComparison.OrdinalIgnoreCase) + || s.Equals("on", StringComparison.OrdinalIgnoreCase); + } +#endif + + // ------------------------------------------------------------------ data types + private sealed class PlatformArtifactMissingException(string message) : Exception(message); + + private sealed record UpdateCandidate( + bool IsUpgradable, + string VersionName, + string InstallerHash, + string InstallerDownloadUrl, + string SourceName + ); + + private sealed record UpdaterOverrides( + string ProductInfoUrl, + string ProductInfoProductKey, + bool AllowUnsafeUrls, + bool SkipHashValidation, + bool SkipSignerThumbprintCheck, + bool DisableTlsValidation + ); + + private sealed class ProductInfoProduct + { + public ProductInfoChannel? Current { get; set; } + public ProductInfoChannel? Beta { get; set; } + } + + private sealed class ProductInfoChannel + { + public string Version { get; set; } = string.Empty; + public List Files { get; set; } = []; + } + + private sealed class ProductInfoFile + { + public string Arch { get; set; } = string.Empty; + public string Type { get; set; } = string.Empty; + public string Url { get; set; } = string.Empty; + public string Hash { get; set; } = string.Empty; + } + + [JsonSourceGenerationOptions(AllowTrailingCommas = true)] + [JsonSerializable(typeof(Dictionary))] + private sealed partial class AutoUpdaterJsonContext : JsonSerializerContext { } +} diff --git a/src/UniGetUI.Avalonia/Infrastructure/AvaloniaBootstrapper.cs b/src/UniGetUI.Avalonia/Infrastructure/AvaloniaBootstrapper.cs new file mode 100644 index 0000000..c7ccf41 --- /dev/null +++ b/src/UniGetUI.Avalonia/Infrastructure/AvaloniaBootstrapper.cs @@ -0,0 +1,508 @@ +using Avalonia.Threading; +using UniGetUI.Avalonia.Models; +using UniGetUI.Avalonia.Views; +using UniGetUI.Avalonia.Views.DialogPages; +using UniGetUI.Core.Data; +using UniGetUI.Core.IconEngine; +using UniGetUI.Core.Logging; +using UniGetUI.Core.SettingsEngine; +using UniGetUI.Core.SettingsEngine.SecureSettings; +using UniGetUI.Core.Tools; +using UniGetUI.Interface; +using UniGetUI.Interface.Telemetry; +using UniGetUI.PackageEngine; +using UniGetUI.PackageEngine.Classes.Manager.Classes; +using UniGetUI.PackageEngine.Enums; +using UniGetUI.PackageEngine.Interfaces; +using UniGetUI.PackageOperations; + +namespace UniGetUI.Avalonia.Infrastructure; + +internal static class AvaloniaBootstrapper +{ + private static bool _hasStarted; + private static IpcServer? _ipcApi; + + public static async Task InitializeAsync() + { + if (_hasStarted) + { + return; + } + + _hasStarted = true; + Logger.Info("Starting Avalonia shell bootstrap"); + + await Task.WhenAll( + InitializeSharedServicesAsync(), + InitializePackageEngineAsync() + ); + + await RunPostLoadChecksAsync(); + + Logger.Info("Avalonia shell bootstrap completed"); + } + + private static async Task RunPostLoadChecksAsync() + { + if (!Settings.Get(Settings.K.DisableIntegrityChecks)) + { + var result = await Task.Run(() => IntegrityTester.CheckIntegrity(allowRetry: true)); + if (!result.Passed) + { + // When IntegrityTree.json is absent (debug / CI builds, tree is only generated + // during `dotnet publish`), the tester returns Passed=false with a single + // missing-file entry for the tree itself. That is not a real integrity failure — + // skip the dialog so it does not fire on every dev launch. + bool onlyTreeMissing = result.MissingFiles.Count == 1 + && result.MissingFiles[0] == "/IntegrityTree.json" + && result.CorruptedFiles.Count == 0; + + if (!onlyTreeMissing) + { + Logger.Warn("Integrity check failed; showing integrity violation dialog."); + await Dispatcher.UIThread.InvokeAsync(ShowIntegrityViolationDialogAsync); + } + else + { + Logger.Info("IntegrityTree.json not found (dev/CI build) — skipping integrity dialog."); + } + } + } + + var missing = await GetMissingDependenciesAsync(); + if (missing.Count > 0) + { + Logger.Info($"Found {missing.Count} missing dependencies; showing install dialogs."); + for (int i = 0; i < missing.Count; i++) + { + int idx = i; + await Dispatcher.UIThread.InvokeAsync( + () => ShowMissingDependencyDialogAsync(missing[idx], idx + 1, missing.Count)); + } + } + } + + private static async Task ShowIntegrityViolationDialogAsync() + { + if (MainWindow.Instance is not { } owner) return; + await new IntegrityViolationDialog().ShowDialog(owner); + } + + private static async Task ShowMissingDependencyDialogAsync( + ManagerDependency dep, int current, int total) + { + if (MainWindow.Instance is not { } owner) return; + await new MissingDependencyDialog(dep, current, total).ShowDialog(owner); + } + + private static Task InitializeSharedServicesAsync() + { + CoreTools.ReloadLanguageEngineInstance(); + ProcessEnvironmentConfigurator.ApplyProxySettingsToProcess(); + _ = Task.Run(AvaloniaAutoUpdater.UpdateCheckLoopAsync) + .ContinueWith( + t => Logger.Error(t.Exception!), + CancellationToken.None, + TaskContinuationOptions.OnlyOnFaulted, + TaskScheduler.Default); + _ = Task.Run(InitializeIpcApiAsync) + .ContinueWith( + t => Logger.Error(t.Exception!), + CancellationToken.None, + TaskContinuationOptions.OnlyOnFaulted, + TaskScheduler.Default); + TelemetryHandler.Configure( + Secrets.GetOpenSearchUsername(), + Secrets.GetOpenSearchPassword()); + AbstractOperation.QueueDrained += (_, _) => _ = TelemetryHandler.FlushPackageEventsAsync(); + _ = TelemetryHandler.InitializeAsync() + .ContinueWith( + t => Logger.Error(t.Exception!), + CancellationToken.None, + TaskContinuationOptions.OnlyOnFaulted, + TaskScheduler.Default); + _ = Task.Run(LoadElevatorAsync) + .ContinueWith( + t => Logger.Error(t.Exception!), + CancellationToken.None, + TaskContinuationOptions.OnlyOnFaulted, + TaskScheduler.Default); + _ = Task.Run(IconDatabase.Instance.LoadFromCacheAsync) + .ContinueWith( + t => Logger.Error(t.Exception!), + CancellationToken.None, + TaskContinuationOptions.OnlyOnFaulted, + TaskScheduler.Default); + _ = Task.Run(IconDatabase.Instance.LoadIconAndScreenshotsDatabaseAsync) + .ContinueWith( + t => Logger.Error(t.Exception!), + CancellationToken.None, + TaskContinuationOptions.OnlyOnFaulted, + TaskScheduler.Default); + return Task.CompletedTask; + } + + private static async Task InitializePackageEngineAsync() + { + // LoadLoaders is called synchronously in App.axaml.cs before MainWindow creation + await Task.Run(PEInterface.LoadManagers); + } + + private static async Task InitializeIpcApiAsync() + { + try + { + if (Settings.Get(Settings.K.DisableApi)) + return; + + _ipcApi = new IpcServer + { + SessionKind = IpcTransportOptions.GuiSessionKind, + }; + _ipcApi.AppInfoProvider = () => + Dispatcher.UIThread.InvokeAsync(GetAppInfo).GetAwaiter().GetResult(); + _ipcApi.ShowAppHandler = () => + Dispatcher.UIThread.InvokeAsync(ShowApp).GetAwaiter().GetResult(); + _ipcApi.NavigateAppHandler = request => + Dispatcher.UIThread.InvokeAsync(() => NavigateApp(request)).GetAwaiter().GetResult(); + _ipcApi.QuitAppHandler = () => + Dispatcher.UIThread.InvokeAsync(QuitApp).GetAwaiter().GetResult(); + _ipcApi.ShowPackageHandler = request => + Dispatcher.UIThread.InvokeAsync(() => ShowPackage(request)).GetAwaiter().GetResult(); + + _ipcApi.OnUpgradeAll += (_, _) => + Dispatcher.UIThread.Post(() => _ = AvaloniaPackageOperationHelper.UpdateAllAsync()); + + _ipcApi.OnUpgradeAllForManager += (_, managerName) => + Dispatcher.UIThread.Post(() => + _ = AvaloniaPackageOperationHelper.UpdateAllForManagerAsync(managerName)); + + await _ipcApi.Start(); + } + catch (Exception ex) + { + Logger.Error("Could not initialize IPC API:"); + Logger.Error(ex); + } + } + + public static async Task StopIpcApiAsync() + { + if (_ipcApi is null) + { + return; + } + + IpcServer ipcApi = _ipcApi; + _ipcApi = null; + await ipcApi.Stop().ConfigureAwait(false); + } + + private static IpcAppInfo GetAppInfo() + { + MainWindow? window = MainWindow.Instance; + return new IpcAppInfo + { + Headless = false, + WindowAvailable = window is not null, + WindowVisible = window?.IsVisible ?? false, + CanShowWindow = window is not null, + CanNavigate = window is not null, + CanQuit = true, + CurrentPage = window is null ? "" : IpcAppPages.ToPageName(window.CurrentPage.ToString()), + SupportedPages = IpcAppPages.SupportedPages, + }; + } + + private static IpcCommandResult ShowApp() + { + MainWindow window = MainWindow.Instance + ?? throw new InvalidOperationException("The application window is not available."); + window.ShowFromTray(); + return IpcCommandResult.Success("show-app"); + } + + private static IpcCommandResult NavigateApp(IpcAppNavigateRequest request) + { + MainWindow window = MainWindow.Instance + ?? throw new InvalidOperationException("The application window is not available."); + string page = IpcAppPages.NormalizePageName(request.Page); + var manager = ResolveManager(request.ManagerName); + + switch (page) + { + case "discover": + window.Navigate(PageType.Discover); + break; + case "updates": + window.Navigate(PageType.Updates); + break; + case "installed": + window.Navigate(PageType.Installed); + break; + case "bundles": + window.Navigate(PageType.Bundles); + break; + case "settings": + window.Navigate(PageType.Settings); + break; + case "managers": + window.OpenManagerSettings(manager); + break; + case "own-log": + window.Navigate(PageType.OwnLog); + break; + case "manager-log": + window.OpenManagerLogs(manager); + break; + case "operation-history": + window.Navigate(PageType.OperationHistory); + break; + case "help": + window.ShowHelp(request.HelpAttachment ?? ""); + break; + case "release-notes": + window.Navigate(PageType.ReleaseNotes); + break; + case "about": + window.Navigate(PageType.About); + break; + default: + throw new InvalidOperationException( + $"Unsupported app page \"{request.Page}\"." + ); + } + + window.ShowFromTray(); + return IpcCommandResult.Success("navigate-app"); + } + + private static IpcCommandResult ShowPackage(IpcPackageActionRequest request) + { + MainWindow window = MainWindow.Instance + ?? throw new InvalidOperationException("The application window is not available."); + IPackage package = IpcPackageApi.ResolvePackage(request); + window.ShowFromTray(); + _ = new PackageDetailsWindow(package, OperationType.Install).ShowDialog(window); + return IpcCommandResult.Success("show-package"); + } + + private static IpcCommandResult QuitApp() + { + MainWindow window = MainWindow.Instance + ?? throw new InvalidOperationException("The application window is not available."); + _ = Task.Run(async () => + { + await Task.Delay(150); + await Dispatcher.UIThread.InvokeAsync(window.QuitApplication); + }); + return IpcCommandResult.Success("quit-app"); + } + + private static IPackageManager? ResolveManager(string? managerName) + { + if (string.IsNullOrWhiteSpace(managerName)) + { + return null; + } + + return PEInterface.Managers.FirstOrDefault(manager => + manager.Id.Equals(managerName, StringComparison.OrdinalIgnoreCase)) + ?? throw new InvalidOperationException( + $"Unknown manager \"{managerName}\"." + ); + } + + private static async Task LoadElevatorAsync() + { + try + { + if (Settings.Get(Settings.K.ProhibitElevation)) + { + Logger.Warn("UniGetUI Elevator has been disabled since elevation is prohibited!"); + return; + } + + if (OperatingSystem.IsLinux()) + { + await LoadLinuxElevatorAsync(); + return; + } + + if (SecureSettings.Get(SecureSettings.K.ForceUserGSudo)) + { + var res = await CoreTools.WhichAsync("gsudo.exe"); + if (res.Item1) + { + CoreData.ElevatorPath = res.Item2; + Logger.Warn($"Using user GSudo (forced by user) at {CoreData.ElevatorPath}"); + return; + } + } + +#if DEBUG + Logger.Warn($"Using system GSudo since UniGetUI Elevator is not available in DEBUG builds"); + CoreData.ElevatorPath = (await CoreTools.WhichAsync("gsudo.exe")).Item2; +#else + CoreData.ElevatorPath = ResolveBundledElevatorPath(); + Logger.Debug($"Using built-in UniGetUI Elevator at {CoreData.ElevatorPath}"); +#endif + } + catch (Exception ex) + { + Logger.Error("Elevator/GSudo failed to be loaded!"); + Logger.Error(ex); + } + } + +#if !DEBUG + private static string ResolveBundledElevatorPath() + { + string executableDirectory = CoreData.UniGetUIExecutableDirectory; + string localPath = Path.Join( + executableDirectory, + "Assets", + "Utilities", + "UniGetUI Elevator.exe" + ); + + if (File.Exists(localPath)) + { + return localPath; + } + + string? parentDirectory = Path.GetDirectoryName(executableDirectory); + if (!string.IsNullOrEmpty(parentDirectory)) + { + string parentPath = Path.Join( + parentDirectory, + "Assets", + "Utilities", + "UniGetUI Elevator.exe" + ); + + if (File.Exists(parentPath)) + { + return parentPath; + } + } + + return localPath; + } +#endif + + [System.Runtime.Versioning.SupportedOSPlatform("linux")] + private static async Task LoadLinuxElevatorAsync() + { + // Prefer sudo over pkexec: sudo caches credentials on disk (per user, not per + // process), so the user is only prompted once per ~15-minute window regardless + // of how many packages are installed. pkexec prompts on every single invocation + // because polkit ties its authorization cache to the calling process PID. + var results = await Task.WhenAll( + CoreTools.WhichAsync("sudo"), + CoreTools.WhichAsync("pkexec"), + CoreTools.WhichAsync("zenity")); + var (sudoFound, sudoPath) = results[0]; + var (pkexecFound, pkexecPath) = results[1]; + var (zenityFound, zenityPath) = results[2]; + + if (sudoFound) + { + // Find a graphical askpass helper so sudo can prompt without a terminal. + // Most DEs (KDE, XFCE, ...) pre-set SSH_ASKPASS to their native tool; + // GNOME doesn't, so we fall back to zenity with a small wrapper script + // (zenity --password ignores positional args, so it needs the wrapper + // to forward the prompt text via --text="$1"). + string? askpass = null; + var envAskpass = Environment.GetEnvironmentVariable("SSH_ASKPASS"); + if (!string.IsNullOrEmpty(envAskpass) && File.Exists(envAskpass)) + askpass = envAskpass; + else if (zenityFound) + { + askpass = Path.Join(CoreData.UniGetUIDataDirectory, "linux-askpass.sh"); + await File.WriteAllTextAsync(askpass, + $"#!/bin/sh\n\"{zenityPath}\" --password --title=\"UniGetUI\" --text=\"$1\"\n"); + File.SetUnixFileMode(askpass, + UnixFileMode.UserRead | UnixFileMode.UserWrite | UnixFileMode.UserExecute | + UnixFileMode.GroupRead | UnixFileMode.GroupExecute | + UnixFileMode.OtherRead | UnixFileMode.OtherExecute); + } + + if (askpass != null) + { + Environment.SetEnvironmentVariable("SUDO_ASKPASS", askpass); + CoreData.ElevatorPath = sudoPath; + CoreData.ElevatorArgs = "-A"; + Logger.Debug($"Using sudo -A with askpass '{askpass}'"); + return; + } + } + + // Fall back to pkexec when no usable sudo+askpass combination is found. + // pkexec handles its own graphical prompt via polkit but prompts every invocation. + if (pkexecFound) + { + CoreData.ElevatorPath = pkexecPath; + Logger.Warn($"Using pkexec at {pkexecPath} (prompts on every operation)"); + return; + } + + if (sudoFound) + { + CoreData.ElevatorPath = sudoPath; + Logger.Warn($"Falling back to sudo without graphical askpass at {sudoPath}"); + return; + } + + Logger.Warn("No elevation tool found (pkexec/sudo). Admin operations will fail."); + } + + /// + /// Checks all ready package managers for missing dependencies. + /// Returns the list of dependencies whose installation was not skipped by the user. + /// + public static async Task> GetMissingDependenciesAsync() + { + var missing = new List(); + + foreach (var manager in PEInterface.Managers) + { + if (!manager.IsReady()) continue; + + foreach (var dep in manager.Dependencies) + { + bool isInstalled = true; + try + { + isInstalled = await dep.IsInstalled(); + } + catch (Exception ex) + { + Logger.Error($"Error checking dependency {dep.Name}: {ex.Message}"); + } + + if (!isInstalled) + { + if (Settings.GetDictionaryItem( + Settings.K.DependencyManagement, dep.Name) == "skipped") + { + Logger.Info($"Dependency {dep.Name} skipped by user preference."); + } + else + { + Logger.Warn( + $"Dependency {dep.Name} not found for manager {manager.Name}."); + missing.Add(dep); + } + } + else + { + Logger.Info($"Dependency {dep.Name} for {manager.Name} is present."); + } + } + } + + return missing; + } +} diff --git a/src/UniGetUI.Avalonia/Infrastructure/AvaloniaOperationRegistry.cs b/src/UniGetUI.Avalonia/Infrastructure/AvaloniaOperationRegistry.cs new file mode 100644 index 0000000..efd8635 --- /dev/null +++ b/src/UniGetUI.Avalonia/Infrastructure/AvaloniaOperationRegistry.cs @@ -0,0 +1,304 @@ +using System.Collections.Concurrent; +using System.Collections.ObjectModel; +using Avalonia; +using Avalonia.Automation; +using Avalonia.Collections; +using Avalonia.Controls; +using Avalonia.Controls.ApplicationLifetimes; +using Avalonia.Threading; +using UniGetUI.Avalonia.ViewModels; +using UniGetUI.Core.Logging; +using UniGetUI.Core.SettingsEngine; +using UniGetUI.Core.Tools; +using UniGetUI.Interface; +using UniGetUI.PackageEngine.Classes.Packages.Classes; +using UniGetUI.PackageEngine.Enums; +using UniGetUI.PackageOperations; + +namespace UniGetUI.Avalonia.Infrastructure; + +/// +/// Global registry of operations for the Avalonia shell. +/// The operations panel binds to . +/// +public static class AvaloniaOperationRegistry +{ + /// Raw operations — kept for compatibility / queue checks. + public static readonly ObservableCollection Operations = new(); + + /// Bindable view-models shown in the operations panel. + public static readonly AvaloniaList OperationViewModels = new(); + + // Mirrors WinUI's MainApp.Tooltip.ErrorsOccurred / RestartRequired + private static readonly ConcurrentDictionary _errorCounts = new(); + private static int _errorsOccurred; + public static int ErrorsOccurred => _errorsOccurred; + public static bool RestartRequired { get; set; } + + /// + /// Register an operation and create its UI view-model. + /// Must be called before operation.MainThread(). + /// + public static void Add(AbstractOperation op) + { + IpcOperationApi.Track(op); + var vm = new OperationViewModel(op); + + Dispatcher.UIThread.Post(() => + { + if (!Operations.Contains(op)) + { + Operations.Add(op); + OperationViewModels.Add(vm); + } + }); + + op.OperationStarting += (_, _) => + { + Dispatcher.UIThread.Post(() => ShowOperationProgressNotification(op)); + }; + + op.OperationSucceeded += (_, _) => + { + if (_errorCounts.TryRemove(op, out int errCount) && errCount > 0) + Interlocked.Add(ref _errorsOccurred, -errCount); + + if (!Settings.Get(Settings.K.MaintainSuccessfulInstalls)) + _ = RemoveAfterDelayAsync(op, milliseconds: 4000); + + _ = Task.Run(() => AppendOperationHistory(op)); + + Dispatcher.UIThread.Post(() => ShowOperationSuccessNotification(op)); + + _ = RunPostOperationChecksAsync(); + Dispatcher.UIThread.Post(UpdateTrayStatus); + }; + + op.OperationFailed += (_, _) => + { + _errorCounts.AddOrUpdate(op, 1, (_, n) => n + 1); + Interlocked.Increment(ref _errorsOccurred); + + _ = Task.Run(() => AppendOperationHistory(op)); + Dispatcher.UIThread.Post(() => ShowOperationFailureNotification(op)); + Dispatcher.UIThread.Post(UpdateTrayStatus); + }; + + op.StatusChanged += (_, status) => + { + if (status is OperationStatus.Canceled) + { + WindowsAppNotificationBridge.RemoveProgress(op); + _ = RemoveAfterDelayAsync(op, milliseconds: 2500); + } + Dispatcher.UIThread.Post(UpdateTrayStatus); + }; + } + + public static void RetryFailed() + { + var failed = OperationViewModels + .Where(vm => vm.Operation.Status is OperationStatus.Failed) + .ToList(); + foreach (var vm in failed) + vm.Operation.Retry(AbstractOperation.RetryMode.Retry); + } + + public static void ClearSuccessful() + { + var succeeded = OperationViewModels + .Where(vm => vm.Operation.Status is OperationStatus.Succeeded) + .ToList(); + foreach (var vm in succeeded) + Remove(vm); + } + + public static void ClearFinished() + { + var finished = OperationViewModels + .Where(vm => vm.Operation.Status + is OperationStatus.Succeeded or OperationStatus.Failed or OperationStatus.Canceled) + .ToList(); + foreach (var vm in finished) + Remove(vm); + } + + public static void CancelAll() + { + var active = OperationViewModels + .Where(vm => vm.Operation.Status is OperationStatus.Running or OperationStatus.InQueue) + .ToList(); + foreach (var vm in active) + vm.Operation.Cancel(); + } + + /// Remove a view-model (and its backing operation) from the panel. Called by the Close button. + public static void Remove(OperationViewModel vm) + { + if (_errorCounts.TryRemove(vm.Operation, out int errCount) && errCount > 0) + Interlocked.Add(ref _errorsOccurred, -errCount); + + Dispatcher.UIThread.Post(() => + { + OperationViewModels.Remove(vm); + Operations.Remove(vm.Operation); + UpdateTrayStatus(); + }); + while (AbstractOperation.OperationQueue.Remove(vm.Operation)) ; + if (vm.Operation.Status is not (OperationStatus.InQueue or OperationStatus.Running)) + { + IpcOperationApi.ForgetTracking(vm.Operation.Metadata.Identifier); + } + } + + private static async Task RemoveAfterDelayAsync(AbstractOperation op, int milliseconds) + { + await Task.Delay(milliseconds); + + if (_errorCounts.TryRemove(op, out int errCount) && errCount > 0) + Interlocked.Add(ref _errorsOccurred, -errCount); + + Dispatcher.UIThread.Post(() => + { + var vm = OperationViewModels.FirstOrDefault(v => v.Operation == op); + if (vm is not null) OperationViewModels.Remove(vm); + Operations.Remove(op); + UpdateTrayStatus(); + if (op.Status is not (OperationStatus.InQueue or OperationStatus.Running)) + { + IpcOperationApi.ForgetTracking(op.Metadata.Identifier); + } + UpdateTrayStatus(); + }); + } + + private static void UpdateTrayStatus() + { + if (Application.Current?.ApplicationLifetime + is IClassicDesktopStyleApplicationLifetime { MainWindow: UniGetUI.Avalonia.Views.MainWindow mw }) + mw.UpdateSystemTrayStatus(); + } + + private static void ShowOperationProgressNotification(AbstractOperation op) + { + if (Settings.AreProgressNotificationsDisabled()) + return; + + string title = op.Metadata.Title.Length > 0 + ? op.Metadata.Title + : CoreTools.Translate("Operation in progress"); + + string message = op.Metadata.Status.Length > 0 + ? op.Metadata.Status + : CoreTools.Translate("Please wait..."); + + AccessibilityAnnouncementService.Announce( + $"{title}. {message}", + AutomationLiveSetting.Polite); + + if (OperatingSystem.IsWindows()) WindowsAppNotificationBridge.ShowProgress(op); + else if (OperatingSystem.IsMacOS()) MacOsNotificationBridge.ShowProgress(op); + } + + private static void ShowOperationSuccessNotification(AbstractOperation op) + { + if (Settings.AreSuccessNotificationsDisabled()) + return; + + string title = op.Metadata.SuccessTitle.Length > 0 + ? op.Metadata.SuccessTitle + : CoreTools.Translate("Success!"); + + string message = op.Metadata.SuccessMessage.Length > 0 + ? op.Metadata.SuccessMessage + : CoreTools.Translate("Success!"); + + AccessibilityAnnouncementService.Announce( + $"{title}. {message}", + AutomationLiveSetting.Polite); + + WindowsAppNotificationBridge.RemoveProgress(op); + + if (OperatingSystem.IsWindows()) WindowsAppNotificationBridge.ShowSuccess(op); + else if (OperatingSystem.IsMacOS()) MacOsNotificationBridge.ShowSuccess(op); + } + + private static void ShowOperationFailureNotification(AbstractOperation op) + { + if (Settings.AreErrorNotificationsDisabled()) + return; + + string title = op.Metadata.FailureTitle.Length > 0 + ? op.Metadata.FailureTitle + : CoreTools.Translate("Failed"); + + string message = op.Metadata.FailureMessage.Length > 0 + ? op.Metadata.FailureMessage + : CoreTools.Translate("An error occurred while processing this package"); + + AccessibilityAnnouncementService.Announce( + $"{title}. {message}", + AutomationLiveSetting.Assertive); + + WindowsAppNotificationBridge.RemoveProgress(op); + + if (OperatingSystem.IsWindows()) WindowsAppNotificationBridge.ShowError(op); + else if (OperatingSystem.IsMacOS()) MacOsNotificationBridge.ShowError(op); + } + + private static void AppendOperationHistory(AbstractOperation op) + { + try + { + var rawOutput = new List + { + " ", + "▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄", + }; + foreach (var (text, _) in op.GetOutput()) + rawOutput.Add(text); + + var oldLines = Settings.GetValue(Settings.K.OperationHistory).Split('\n'); + if (oldLines.Length > 300) + oldLines = oldLines.Take(300).ToArray(); + + Settings.SetValue( + Settings.K.OperationHistory, + string.Join('\n', rawOutput.Concat(oldLines))); + } + catch (Exception ex) + { + Logger.Warn("Failed to write operation history"); + Logger.Warn(ex); + } + } + + private static async Task RunPostOperationChecksAsync() + { + // Let all remaining operations settle before making decisions + await Task.Delay(500); + + bool anyStillRunning = Operations.Any( + o => o.Status is OperationStatus.Running or OperationStatus.InQueue); + + // Clear UAC cache after the last operation in a batch finishes + if (!anyStillRunning && Settings.Get(Settings.K.DoCacheAdminRightsForBatches)) + { + Logger.Info("Clearing UAC prompt since there are no remaining operations"); + await CoreTools.ResetUACForCurrentProcess(); + } + + if (OperatingSystem.IsWindows()) + { + var unknownShortcuts = UniGetUI.PackageEngine.Classes.Packages.Classes.DesktopShortcutsDatabase.GetUnknownShortcuts(); + if (unknownShortcuts.Count > 0) + WindowsAppNotificationBridge.ShowNewShortcutsNotification(unknownShortcuts); + } + else if (OperatingSystem.IsMacOS()) + { + var unknownShortcuts = UniGetUI.PackageEngine.Classes.Packages.Classes.DesktopShortcutsDatabase.GetUnknownShortcuts(); + if (unknownShortcuts.Count > 0) + MacOsNotificationBridge.ShowNewShortcutsNotification(unknownShortcuts); + } + } +} diff --git a/src/UniGetUI.Avalonia/Infrastructure/AvaloniaPackageOperationHelper.cs b/src/UniGetUI.Avalonia/Infrastructure/AvaloniaPackageOperationHelper.cs new file mode 100644 index 0000000..ff2167a --- /dev/null +++ b/src/UniGetUI.Avalonia/Infrastructure/AvaloniaPackageOperationHelper.cs @@ -0,0 +1,274 @@ +using System.Diagnostics; +using Avalonia.Controls.ApplicationLifetimes; +using Avalonia.Platform.Storage; +using CommunityToolkit.Mvvm.Input; +using UniGetUI.Avalonia.ViewModels; +using UniGetUI.Avalonia.Views; +using UniGetUI.Core.Data; +using UniGetUI.Core.Logging; +using UniGetUI.Core.SettingsEngine; +using UniGetUI.Core.Tools; +using UniGetUI.Interface.Enums; +using UniGetUI.Interface.Telemetry; +using UniGetUI.PackageEngine; +using UniGetUI.PackageEngine.Enums; +using UniGetUI.PackageEngine.Interfaces; +using UniGetUI.PackageEngine.Operations; +using UniGetUI.PackageEngine.PackageClasses; +using UniGetUI.PackageEngine.PackageLoader; +using UniGetUI.PackageOperations; +#if WINDOWS +using UniGetUI.PackageEngine.Managers.WingetManager; +#endif + +namespace UniGetUI.Avalonia.Infrastructure; + +/// +/// Avalonia-side helpers for bulk package update operations, consumed by +/// the BackgroundApi event handlers and the --updateapps CLI flag. +/// +internal static class AvaloniaPackageOperationHelper +{ + public static async Task UpdateAllAsync() + { + foreach (var pkg in UpgradablePackagesLoader.Instance.Packages.ToList()) + { + if (pkg.Tag is PackageTag.BeingProcessed or PackageTag.OnQueue) continue; + var opts = await InstallOptionsFactory.LoadApplicableAsync(pkg); + var op = new UpdatePackageOperation(pkg, opts); + op.OperationSucceeded += (_, _) => TelemetryHandler.UpdatePackage(pkg, TEL_OP_RESULT.SUCCESS); + op.OperationFailed += (_, _) => TelemetryHandler.UpdatePackage(pkg, TEL_OP_RESULT.FAILED); + AvaloniaOperationRegistry.Add(op); + _ = op.MainThread(); + } + } + + public static async Task UpdateAllForManagerAsync(string managerName) + { + foreach (var pkg in UpgradablePackagesLoader.Instance.Packages + .Where(p => p.Manager.Id == managerName) + .ToList()) + { + if (pkg.Tag is PackageTag.BeingProcessed or PackageTag.OnQueue) continue; + var opts = await InstallOptionsFactory.LoadApplicableAsync(pkg); + var op = new UpdatePackageOperation(pkg, opts); + op.OperationSucceeded += (_, _) => TelemetryHandler.UpdatePackage(pkg, TEL_OP_RESULT.SUCCESS); + op.OperationFailed += (_, _) => TelemetryHandler.UpdatePackage(pkg, TEL_OP_RESULT.FAILED); + AvaloniaOperationRegistry.Add(op); + _ = op.MainThread(); + } + } + + public static async Task UpdateForIdAsync(string packageId) + { + var pkg = UpgradablePackagesLoader.Instance.Packages.FirstOrDefault(p => p.Id == packageId); + if (pkg is null) + { + Logger.Warn($"BackgroundApi: no upgradable package found with id={packageId}"); + return; + } + + var opts = await InstallOptionsFactory.LoadApplicableAsync(pkg); + var op = new UpdatePackageOperation(pkg, opts); + op.OperationSucceeded += (_, _) => TelemetryHandler.UpdatePackage(pkg, TEL_OP_RESULT.SUCCESS); + op.OperationFailed += (_, _) => TelemetryHandler.UpdatePackage(pkg, TEL_OP_RESULT.FAILED); + AvaloniaOperationRegistry.Add(op); + _ = op.MainThread(); + } + + /// + /// Prompts the user with a save-file dialog and downloads the installer for + /// a single package into the chosen location. + /// + public static async Task AskLocationAndDownloadAsync(IPackage? package, TEL_InstallReferral referral) + { + if (package is null) return; + if (MainWindow.Instance is not { } win) return; + +#if WINDOWS + if (package.Manager is WinGet && Settings.Get(Settings.K.WinGetDownloadFullManifest)) + { + await AskFolderAndDownloadWinGetManifestAsync(package, referral, win); + return; + } +#endif + + await package.Details.Load(); + + if (package.Details.InstallerUrl is null) + { + Logger.Warn($"No installer URL found for {package.Id}"); + return; + } + + string? suggestedName = await package.GetInstallerFileName(); + if (string.IsNullOrWhiteSpace(suggestedName)) + suggestedName = CoreTools.MakeValidFileName(package.Id) + ".exe"; + + string ext = suggestedName.Contains('.') + ? CoreTools.MakeValidFileName(suggestedName.Split('.')[^1]) + : "exe"; + + var file = await win.StorageProvider.SaveFilePickerAsync(new FilePickerSaveOptions + { + SuggestedFileName = suggestedName, + FileTypeChoices = + [ + new FilePickerFileType(CoreTools.Translate("Installer")) { Patterns = [$"*.{ext}"] }, + new FilePickerFileType(CoreTools.Translate("Executable")) { Patterns = ["*.exe"] }, + new FilePickerFileType(CoreTools.Translate("MSI")) { Patterns = ["*.msi"] }, + new FilePickerFileType(CoreTools.Translate("Compressed file")) { Patterns = ["*.zip"] }, + new FilePickerFileType(CoreTools.Translate("MSIX")) { Patterns = ["*.msix"] }, + ], + }); + + var path = file?.TryGetLocalPath(); + if (path is null) return; + + var op = new DownloadOperation(package, path); + op.OperationSucceeded += (_, _) => TelemetryHandler.DownloadPackage(package, TEL_OP_RESULT.SUCCESS, referral); + op.OperationFailed += (_, _) => TelemetryHandler.DownloadPackage(package, TEL_OP_RESULT.FAILED, referral); + AvaloniaOperationRegistry.Add(op); + _ = op.MainThread(); + } + + /// + /// Prompts the user with a folder-picker dialog and downloads the installers + /// for all eligible packages into the chosen folder. + /// + public static async Task DownloadSelectedAsync(IEnumerable packages, TEL_InstallReferral referral) + { + if (MainWindow.Instance is not { } win) return; + + var eligible = packages + .Where(p => !p.Source.IsVirtualManager && p.Manager.Capabilities.CanDownloadInstaller) + .ToList(); + + if (eligible.Count == 0) return; + + var folders = await win.StorageProvider.OpenFolderPickerAsync( + new FolderPickerOpenOptions { AllowMultiple = false }); + + var folder = folders.FirstOrDefault(); + var outputPath = folder?.TryGetLocalPath(); + if (outputPath is null) return; + + bool fullManifest = Settings.Get(Settings.K.WinGetDownloadFullManifest); + foreach (var pkg in eligible) + { + AbstractOperation op; +#if WINDOWS + if (fullManifest && pkg.Manager is WinGet) + op = new WinGetManifestDownloadOperation(pkg, outputPath); + else + op = new DownloadOperation(pkg, outputPath); +#else + op = new DownloadOperation(pkg, outputPath); +#endif + op.OperationSucceeded += (_, _) => TelemetryHandler.DownloadPackage(pkg, TEL_OP_RESULT.SUCCESS, referral); + op.OperationFailed += (_, _) => TelemetryHandler.DownloadPackage(pkg, TEL_OP_RESULT.FAILED, referral); + AvaloniaOperationRegistry.Add(op); + _ = op.MainThread(); + } + } + +#if WINDOWS + private static async Task AskFolderAndDownloadWinGetManifestAsync( + IPackage package, + TEL_InstallReferral referral, + MainWindow win) + { + var folders = await win.StorageProvider.OpenFolderPickerAsync( + new FolderPickerOpenOptions { AllowMultiple = false }); + var folder = folders.FirstOrDefault(); + var outputPath = folder?.TryGetLocalPath(); + if (outputPath is null) return; + + var op = new WinGetManifestDownloadOperation(package, outputPath); + op.OperationSucceeded += (_, _) => TelemetryHandler.DownloadPackage(package, TEL_OP_RESULT.SUCCESS, referral); + op.OperationFailed += (_, _) => TelemetryHandler.DownloadPackage(package, TEL_OP_RESULT.FAILED, referral); + AvaloniaOperationRegistry.Add(op); + _ = op.MainThread(); + } +#endif + + /// + /// Runs the WinGet self-repair sequence elevated and shows a result notification. + /// Only meaningful on Windows; no-ops on other platforms. + /// + [System.Runtime.Versioning.SupportedOSPlatform("windows")] + public static async Task HandleBrokenWinGetAsync() + { + var banner = (MainWindow.Instance?.DataContext as MainWindowViewModel)?.WinGetWarningBanner; + banner?.IsOpen = false; + + try + { + using var p = new Process + { + StartInfo = new ProcessStartInfo + { + FileName = CoreData.PowerShell5, + Arguments = + "-ExecutionPolicy Bypass -NoLogo -NoProfile -Command \"& {" + + "cmd.exe /C \"rmdir /Q /S `\"%temp%\\WinGet`\"\"; " + + "cmd.exe /C \"`\"%localappdata%\\Microsoft\\WindowsApps\\winget.exe`\" source reset --force\"; " + + "taskkill /im winget.exe /f; " + + "taskkill /im WindowsPackageManagerServer.exe /f; " + + "Install-PackageProvider -Name NuGet -MinimumVersion 2.8.5.201 -Force; " + + "Install-Module Microsoft.WinGet.Client -Force -AllowClobber; " + + "Import-Module Microsoft.WinGet.Client; " + + "Repair-WinGetPackageManager -Force -Latest; " + + "Get-AppxPackage -Name 'Microsoft.DesktopAppInstaller' | Reset-AppxPackage; " + + "}\"", + UseShellExecute = true, + Verb = "runas", + }, + }; + + p.Start(); + await p.WaitForExitAsync(); + + if (string.Equals( + Settings.GetValue(Settings.K.WinGetCliToolPreference), + "pinget", + StringComparison.OrdinalIgnoreCase)) + { + Settings.SetValue(Settings.K.WinGetCliToolPreference, "default"); + } + + MainWindow.Instance?.ShowBanner( + CoreTools.Translate("WinGet was repaired successfully"), + CoreTools.Translate("It is recommended to restart UniGetUI after WinGet has been repaired"), + MainWindow.RuntimeNotificationLevel.Success); + + _ = UpgradablePackagesLoader.Instance.ReloadPackages(); + _ = InstalledPackagesLoader.Instance.ReloadPackages(); + } + catch (Exception ex) + { + Logger.Error("An error occurred while trying to repair WinGet"); + Logger.Error(ex); + + banner?.IsOpen = true; + + MainWindow.Instance?.ShowBanner( + CoreTools.Translate("WinGet could not be repaired"), + CoreTools.Translate("An unexpected issue occurred while attempting to repair WinGet. Please try again later") + + " — " + ex.Message, + MainWindow.RuntimeNotificationLevel.Error); + } + } + + /// + /// Returns true when the WinGet manager is ready but loaded zero installed packages, + /// which is a strong signal that WinGet has malfunctioned. + /// + public static bool IsWinGetMalfunctioning() + { + var winget = PEInterface.Managers.FirstOrDefault(m => m.Name == "WinGet"); + return winget is not null + && winget.IsReady() + && !InstalledPackagesLoader.Instance.Packages.Any(p => p.Manager == winget); + } +} diff --git a/src/UniGetUI.Avalonia/Infrastructure/DirectionalSlideTransition.cs b/src/UniGetUI.Avalonia/Infrastructure/DirectionalSlideTransition.cs new file mode 100644 index 0000000..7ddba62 --- /dev/null +++ b/src/UniGetUI.Avalonia/Infrastructure/DirectionalSlideTransition.cs @@ -0,0 +1,105 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Avalonia; +using Avalonia.Animation; +using Avalonia.Animation.Easings; +using Avalonia.Controls; +using Avalonia.Controls.Primitives; +using Avalonia.Media; +using Avalonia.Styling; +using Avalonia.VisualTree; + +namespace UniGetUI.Avalonia.Infrastructure; + +/// +/// Horizontal page slide whose direction is set explicitly via . +/// (TransitioningContentControl always reports forward navigation, so the caller toggles this +/// before changing content.) Reverse=false slides the incoming page in from the right +/// (drill-in); Reverse=true slides it in from the left (back navigation). +/// Scrollbars are hidden for the duration so they don't drag across the view. +/// +public sealed class DirectionalSlideTransition : IPageTransition +{ + public TimeSpan Duration { get; set; } = TimeSpan.FromMilliseconds(220); + + public bool Reverse { get; set; } + + public async Task Start(Visual? from, Visual? to, bool forward, CancellationToken cancellationToken) + { + // Honor the OS "reduce motion" preference: swap pages instantly, no slide. + if (MotionPreference.ReducedMotion) + { + if (from is not null) { from.IsVisible = false; from.RenderTransform = null; } + to?.RenderTransform = null; + return; + } + + double sign = Reverse ? -1d : 1d; + double width = (to ?? from)?.GetVisualParent()?.Bounds.Width + ?? (to ?? from)?.Bounds.Width ?? 0d; + + var hidden = new List(); + HideScrollBars(from, hidden); + HideScrollBars(to, hidden); + + try + { + var tasks = new List(); + if (from is not null) + tasks.Add(Slide(from, 0d, -sign * width, cancellationToken)); + if (to is not null) + tasks.Add(Slide(to, sign * width, 0d, cancellationToken)); + await Task.WhenAll(tasks); + } + finally + { + foreach (var sv in hidden) + sv.VerticalScrollBarVisibility = ScrollBarVisibility.Auto; + } + + if (cancellationToken.IsCancellationRequested) + return; + + // Hide before clearing the transform so the outgoing page never snaps back on-screen. + if (from is not null) + { + from.IsVisible = false; + from.RenderTransform = null; + } + to?.RenderTransform = null; + } + + private static void HideScrollBars(Visual? root, List hidden) + { + if (root is null) + return; + + foreach (var sv in root.GetVisualDescendants().OfType()) + { + if (sv.VerticalScrollBarVisibility == ScrollBarVisibility.Auto) + { + sv.VerticalScrollBarVisibility = ScrollBarVisibility.Hidden; + hidden.Add(sv); + } + } + } + + private Task Slide(Visual target, double fromX, double toX, CancellationToken cancellationToken) + { + var anim = new Animation + { + Duration = Duration, + Easing = new CubicEaseInOut(), + FillMode = FillMode.Forward, + Children = + { + new KeyFrame { Cue = new Cue(0d), Setters = { new Setter(TranslateTransform.XProperty, fromX) } }, + new KeyFrame { Cue = new Cue(1d), Setters = { new Setter(TranslateTransform.XProperty, toX) } }, + }, + }; + return anim.RunAsync(target, cancellationToken); + } +} diff --git a/src/UniGetUI.Avalonia/Infrastructure/EntrancePageTransition.cs b/src/UniGetUI.Avalonia/Infrastructure/EntrancePageTransition.cs new file mode 100644 index 0000000..f508045 --- /dev/null +++ b/src/UniGetUI.Avalonia/Infrastructure/EntrancePageTransition.cs @@ -0,0 +1,77 @@ +using System; +using System.Threading; +using System.Threading.Tasks; +using Avalonia; +using Avalonia.Animation; +using Avalonia.Animation.Easings; +using Avalonia.Media; +using Avalonia.Styling; + +namespace UniGetUI.Avalonia.Infrastructure; + +/// +/// WinUI-style page entrance: the incoming page fades in while sliding up a few pixels +/// (mimics the Frame NavigationThemeTransition); the outgoing page fades out. +/// +public sealed class EntrancePageTransition : IPageTransition +{ + public TimeSpan Duration { get; set; } = TimeSpan.FromMilliseconds(220); + + /// How far (px) the incoming page slides up as it fades in. + public double VerticalOffset { get; set; } = 28; + + public async Task Start(Visual? from, Visual? to, bool forward, CancellationToken cancellationToken) + { + // Honor "reduce motion": hide the outgoing page and show the incoming one instantly, no overlap. + if (MotionPreference.ReducedMotion) + { + from?.Opacity = 0; + to?.Opacity = 1; + return; + } + + // Drop the outgoing page immediately so only the incoming page animates in. + from?.Opacity = 0; + + if (to is null) + return; + + var enter = new Animation + { + Duration = Duration, + Easing = new CubicEaseOut(), + FillMode = FillMode.Forward, + Children = + { + new KeyFrame + { + Cue = new Cue(0d), + Setters = + { + new Setter(Visual.OpacityProperty, 0d), + new Setter(TranslateTransform.YProperty, VerticalOffset), + }, + }, + new KeyFrame + { + Cue = new Cue(1d), + Setters = + { + new Setter(Visual.OpacityProperty, 1d), + new Setter(TranslateTransform.YProperty, 0d), + }, + }, + }, + }; + + try + { + await enter.RunAsync(to, cancellationToken); + } + finally + { + // Restore even if cancelled, so the presenter is never reused while stranded invisible. + from?.Opacity = 1; + } + } +} diff --git a/src/UniGetUI.Avalonia/Infrastructure/GHAuthApiRunner.cs b/src/UniGetUI.Avalonia/Infrastructure/GHAuthApiRunner.cs new file mode 100644 index 0000000..b9f1e29 --- /dev/null +++ b/src/UniGetUI.Avalonia/Infrastructure/GHAuthApiRunner.cs @@ -0,0 +1,148 @@ +using System.Net; +using System.Net.Sockets; +using System.Text; +using UniGetUI.Core.Logging; + +namespace UniGetUI.Avalonia.Infrastructure; + +/// +/// Tiny loopback HTTP server that catches the GitHub OAuth redirect and extracts the +/// authorization code. Uses a raw TcpListener so no ASP.NET Core dependency is pulled into +/// the cross-platform Avalonia app. +/// +internal sealed class GHAuthApiRunner : IDisposable +{ + private const int Port = 58642; + + public event EventHandler? OnLogin; + public event EventHandler? OnCancelled; + + private TcpListener? _listener; + private CancellationTokenSource? _cts; + + public Task Start() + { + _listener = new TcpListener(IPAddress.Loopback, Port); + _listener.Start(); + _cts = new CancellationTokenSource(); + _ = AcceptLoopAsync(_cts.Token); + Logger.Info($"GitHub auth loopback server running on http://127.0.0.1:{Port}"); + return Task.CompletedTask; + } + + private async Task AcceptLoopAsync(CancellationToken ct) + { + while (!ct.IsCancellationRequested) + { + TcpClient client; + try { client = await _listener!.AcceptTcpClientAsync(ct); } + catch (Exception) { break; } + _ = HandleClientAsync(client); + } + } + + private async Task HandleClientAsync(TcpClient client) + { + try + { + using (client) + await using (var stream = client.GetStream()) + { + var buffer = new byte[8192]; + int read = await stream.ReadAsync(buffer); + string requestLine = Encoding.ASCII.GetString(buffer, 0, read).Split("\r\n")[0]; + + string? code = ExtractParam(requestLine, "code"); + string? error = ExtractParam(requestLine, "error"); + + // GitHub redirects here with an "error" parameter when the user cancels/denies authorization. + bool isCallback = code is not null || error is not null; + string body = code is not null + ? ResultPage("Authentication successful") + : error is not null + ? ResultPage("Authentication cancelled") + : "

Authentication failed

"; + + var response = Encoding.UTF8.GetBytes( + $"HTTP/1.1 {(isCallback ? "200 OK" : "400 Bad Request")}\r\n" + + "Content-Type: text/html; charset=utf-8\r\n" + + $"Content-Length: {Encoding.UTF8.GetByteCount(body)}\r\n" + + "Connection: close\r\n\r\n" + + body); + await stream.WriteAsync(response); + await stream.FlushAsync(); + + if (code is not null) + { + Logger.ImportantInfo("[AUTH API] Received authentication code from GitHub"); + OnLogin?.Invoke(this, code); + } + else if (error is not null) + { + Logger.Warn($"[AUTH API] GitHub authentication was cancelled or failed (error: {error})"); + OnCancelled?.Invoke(this, error); + } + } + } + catch (Exception ex) + { + Logger.Warn(ex); + } + } + + private static string? ExtractParam(string requestLine, string key) + { + // requestLine looks like: GET /?code=XXXX&state=YYYY HTTP/1.1 + int q = requestLine.IndexOf('?'); + if (q < 0) return null; + int end = requestLine.IndexOf(' ', q); + string query = end < 0 ? requestLine[(q + 1)..] : requestLine[(q + 1)..end]; + + foreach (var pair in query.Split('&')) + { + var kv = pair.Split('=', 2); + if (kv.Length == 2 && kv[0] == key && kv[1].Length > 0) + return Uri.UnescapeDataString(kv[1]); + } + return null; + } + + private static string ResultPage(string title) => + $$""" +
+ UniGetUI authentication +

{{title}}

+

You can now close this window and return to UniGetUI

+
+ """; + + public async Task Stop() + { + try + { + if (_cts is not null) await _cts.CancelAsync(); + _listener?.Stop(); + } + catch (Exception ex) + { + Logger.Error(ex); + } + } + + public void Dispose() + { + _cts?.Dispose(); + } +} diff --git a/src/UniGetUI.Avalonia/Infrastructure/GitHubAuthService.cs b/src/UniGetUI.Avalonia/Infrastructure/GitHubAuthService.cs new file mode 100644 index 0000000..ab5c20f --- /dev/null +++ b/src/UniGetUI.Avalonia/Infrastructure/GitHubAuthService.cs @@ -0,0 +1,190 @@ +using UniGetUI.Core.Data; +using UniGetUI.Core.Logging; +using UniGetUI.Core.SecureSettings; +using UniGetUI.Core.Tools; +using UniGetUI.Interface; +using CoreSettings = UniGetUI.Core.SettingsEngine.Settings; + +namespace UniGetUI.Avalonia.Infrastructure; + +internal sealed class GitHubAuthService +{ + private const string MissingClientId = "CLIENT_ID_UNSET"; + private const string MissingClientSecret = "CLIENT_SECRET_UNSET"; + private static readonly TimeSpan LoginTimeout = TimeSpan.FromMinutes(2); + private readonly string _gitHubClientId = Secrets.GetGitHubClientId(); + private readonly string _gitHubClientSecret = Secrets.GetGitHubClientSecret(); + private const string RedirectUri = "http://127.0.0.1:58642/"; + + public static event EventHandler? AuthStatusChanged; + + public GitHubAuthService() { } + + public static GitHubApiClient? CreateGitHubClient() + { + var token = SecureGHTokenManager.GetToken(); + if (string.IsNullOrEmpty(token)) + return null; + + return new GitHubApiClient(token); + } + + private GHAuthApiRunner? _loginBackend; + private string? _codeFromApi; + private bool _loginWasCancelled; + + public async Task SignInAsync() + { + try + { + if (!HasConfiguredOAuthClient()) + { + Logger.Error("GitHub sign-in is not configured for this build. Missing OAuth client ID or client secret."); + AuthStatusChanged?.Invoke(this, EventArgs.Empty); + return false; + } + + Logger.Info("Initiating GitHub sign-in process using loopback redirect..."); + + var oauthLoginUrl = GitHubApiClient.GetOAuthLoginUrl( + _gitHubClientId, + new Uri(RedirectUri), + ["read:user", "gist"] + ); + + _codeFromApi = null; + _loginWasCancelled = false; + await StopLoginBackend(); + _loginBackend = new GHAuthApiRunner(); + _loginBackend.OnLogin += BackgroundApiOnOnLogin; + _loginBackend.OnCancelled += BackgroundApiOnCancelled; + await _loginBackend.Start(); + + CoreTools.Launch(oauthLoginUrl.ToString()); + + DateTime timeoutAt = DateTime.UtcNow.Add(LoginTimeout); + while (_codeFromApi is null && !_loginWasCancelled && DateTime.UtcNow < timeoutAt) + await Task.Delay(100); + + if (_loginWasCancelled) + { + Logger.Warn("GitHub sign-in was cancelled by the user."); + AuthStatusChanged?.Invoke(this, EventArgs.Empty); + return false; + } + + if (string.IsNullOrEmpty(_codeFromApi)) + { + Logger.Error("GitHub sign-in timed out before the loopback callback was received."); + AuthStatusChanged?.Invoke(this, EventArgs.Empty); + return false; + } + + return await CompleteSignInAsync(_codeFromApi); + } + catch (Exception ex) + { + Logger.Error("Exception during GitHub sign-in process:"); + Logger.Error(ex); + ClearAuthenticatedUserData(); + AuthStatusChanged?.Invoke(this, EventArgs.Empty); + return false; + } + finally + { + await StopLoginBackend(); + } + } + + private void BackgroundApiOnOnLogin(object? sender, string code) + { + _codeFromApi = code; + } + + private void BackgroundApiOnCancelled(object? sender, string error) + { + _loginWasCancelled = true; + } + + private async Task StopLoginBackend() + { + if (_loginBackend is null) return; + try + { + _loginBackend.OnLogin -= BackgroundApiOnOnLogin; + _loginBackend.OnCancelled -= BackgroundApiOnCancelled; + await _loginBackend.Stop(); + _loginBackend.Dispose(); + } + catch (Exception ex) { Logger.Warn(ex); } + finally { _loginBackend = null; } + } + + private bool HasConfiguredOAuthClient() + { + return !string.IsNullOrWhiteSpace(_gitHubClientId) + && !string.IsNullOrWhiteSpace(_gitHubClientSecret) + && !string.Equals(_gitHubClientId, MissingClientId, StringComparison.Ordinal) + && !string.Equals(_gitHubClientSecret, MissingClientSecret, StringComparison.Ordinal); + } + + private async Task CompleteSignInAsync(string code) + { + try + { + using var client = new GitHubApiClient(); + var token = await client.CreateAccessTokenAsync( + _gitHubClientId, + _gitHubClientSecret, + code, + new Uri(RedirectUri) + ); + + if (string.IsNullOrEmpty(token.AccessToken)) + { + Logger.Error("Failed to obtain GitHub access token."); + AuthStatusChanged?.Invoke(this, EventArgs.Empty); + return false; + } + + Logger.Info("GitHub login successful. Storing access token."); + SecureGHTokenManager.StoreToken(token.AccessToken); + + using var userClient = new GitHubApiClient(token.AccessToken); + var user = await userClient.GetCurrentUserAsync(); + if (user is not null) + { + CoreSettings.SetValue(CoreSettings.K.GitHubUserLogin, user.Login); + Logger.Info($"Logged in as GitHub user: {user.Login}"); + } + + AuthStatusChanged?.Invoke(this, EventArgs.Empty); + return true; + } + catch (Exception ex) + { + Logger.Error("Exception during GitHub token exchange:"); + Logger.Error(ex); + ClearAuthenticatedUserData(); + AuthStatusChanged?.Invoke(this, EventArgs.Empty); + return false; + } + } + + public void SignOut() + { + Logger.Info("Signing out from GitHub..."); + try { ClearAuthenticatedUserData(); } + catch (Exception ex) { Logger.Error("Failed to log out:"); Logger.Error(ex); } + AuthStatusChanged?.Invoke(this, EventArgs.Empty); + Logger.Info("GitHub sign-out complete."); + } + + private static void ClearAuthenticatedUserData() + { + CoreSettings.SetValue(CoreSettings.K.GitHubUserLogin, ""); + SecureGHTokenManager.DeleteToken(); + } + + public static bool IsAuthenticated() => !string.IsNullOrEmpty(SecureGHTokenManager.GetToken()); +} diff --git a/src/UniGetUI.Avalonia/Infrastructure/GitHubCloudBackupService.cs b/src/UniGetUI.Avalonia/Infrastructure/GitHubCloudBackupService.cs new file mode 100644 index 0000000..cfcc565 --- /dev/null +++ b/src/UniGetUI.Avalonia/Infrastructure/GitHubCloudBackupService.cs @@ -0,0 +1,122 @@ +using UniGetUI.Core.SecureSettings; +using UniGetUI.Core.Tools; +using UniGetUI.Interface; + +namespace UniGetUI.Avalonia.Infrastructure; + +internal static class GitHubCloudBackupService +{ + private const string GistDescriptionEndingKey = "@[UNIGETUI_BACKUP_V1]"; + private const string PackageBackupStartingKey = "@[PACKAGES]"; + private const string GistDescription = "UniGetUI package backups - DO NOT RENAME OR MODIFY " + GistDescriptionEndingKey; + private const string ReadMeContents = "This special Gist is used by UniGetUI to store your package backups.\n" + + "Please DO NOT EDIT the contents or the description of this gist, or unexpected behaviours may occur.\n" + + "Learn more about UniGetUI at https://github.com/Devolutions/UniGetUI\n"; + + internal sealed class CloudBackupEntry + { + public required string Key { get; init; } + public required string Display { get; init; } + } + + public static GitHubApiClient? CreateGitHubClient() + { + string? token = SecureGHTokenManager.GetToken(); + if (string.IsNullOrWhiteSpace(token)) + return null; + + return new GitHubApiClient(token); + } + + public static async Task<(string Login, string DisplayName)> GetCurrentUserAsync() + { + using var client = CreateGitHubClient() + ?? throw new InvalidOperationException(CoreTools.Translate("Log in to enable cloud backup")); + + var user = await client.GetCurrentUserAsync(); + string login = user.Login ?? string.Empty; + string displayName = string.IsNullOrWhiteSpace(user.Name) ? login : user.Name; + return (login, displayName); + } + + public static async Task UploadPackageBundleAsync(string bundleContents) + { + using var client = CreateGitHubClient() + ?? throw new InvalidOperationException(CoreTools.Translate("Log in to enable cloud backup")); + + var backupGist = await GetBackupGistAsync(client, createIfMissing: true) + ?? throw new InvalidOperationException(CoreTools.Translate("Backup Failed")); + + string fileKey = BuildGistFileKey(); + await client.EditGistAsync( + backupGist.Id, + GistDescription, + new Dictionary { [fileKey] = bundleContents } + ); + } + + public static async Task> GetAvailableBackupsAsync() + { + using var client = CreateGitHubClient() + ?? throw new InvalidOperationException(CoreTools.Translate("Log in to enable cloud backup")); + + var backupGist = await GetBackupGistAsync(client, createIfMissing: false); + if (backupGist is null) + return []; + + return backupGist.Files + .Where(f => f.Key.StartsWith(PackageBackupStartingKey, StringComparison.Ordinal)) + .Select(f => new CloudBackupEntry + { + Key = f.Key.Split(' ')[^1], + Display = f.Key.Split(' ')[^1] + " (" + CoreTools.FormatAsSize(f.Value.Size) + ")", + }) + .ToArray(); + } + + public static async Task GetBackupContentsAsync(string backupKey) + { + using var client = CreateGitHubClient() + ?? throw new InvalidOperationException(CoreTools.Translate("Log in to enable cloud backup")); + + var backupGist = await GetBackupGistAsync(client, createIfMissing: false); + + if (backupGist is null) + throw new KeyNotFoundException(CoreTools.Translate("Log in to enable cloud backup")); + + var fullGist = await client.GetGistAsync(backupGist.Id); + var file = fullGist.Files.FirstOrDefault(f => + f.Key.StartsWith(PackageBackupStartingKey, StringComparison.Ordinal) + && f.Key.EndsWith(backupKey, StringComparison.Ordinal)); + + if (file.Value?.Content is null) + throw new KeyNotFoundException(CoreTools.Translate("Downloading backup...")); + + return file.Value.Content; + } + + private static async Task GetBackupGistAsync( + GitHubApiClient client, + bool createIfMissing + ) + { + var candidates = await client.GetCurrentUserGistsAsync(); + var backupGist = candidates.FirstOrDefault(g => + g.Description?.EndsWith(GistDescriptionEndingKey, StringComparison.Ordinal) == true); + + if (backupGist is not null || !createIfMissing) + return backupGist; + + return await client.CreateGistAsync( + GistDescription, + isPublic: false, + new Dictionary { ["- UniGetUI Package Backups"] = ReadMeContents } + ); + } + + private static string BuildGistFileKey() + { + string deviceUser = (Environment.MachineName + "\\" + Environment.UserName).Replace(" ", string.Empty); + return PackageBackupStartingKey + " " + deviceUser; + } +} diff --git a/src/UniGetUI.Avalonia/Infrastructure/HeadlessDaemonHost.cs b/src/UniGetUI.Avalonia/Infrastructure/HeadlessDaemonHost.cs new file mode 100644 index 0000000..22ae849 --- /dev/null +++ b/src/UniGetUI.Avalonia/Infrastructure/HeadlessDaemonHost.cs @@ -0,0 +1,17 @@ +using UniGetUI.Interface; +using UniGetUI.PackageEngine; + +namespace UniGetUI.Avalonia.Infrastructure; + +internal static class HeadlessDaemonHost +{ + public static async Task RunAsync() + { + return await HeadlessIpcHost.RunAsync(async () => + { + ProcessEnvironmentConfigurator.PrepareForCurrentPlatform(); + PEInterface.LoadLoaders(); + await Task.Run(PEInterface.LoadManagers); + }); + } +} diff --git a/src/UniGetUI.Avalonia/Infrastructure/HeadlessModeOptions.cs b/src/UniGetUI.Avalonia/Infrastructure/HeadlessModeOptions.cs new file mode 100644 index 0000000..f877a93 --- /dev/null +++ b/src/UniGetUI.Avalonia/Infrastructure/HeadlessModeOptions.cs @@ -0,0 +1,11 @@ +namespace UniGetUI.Avalonia.Infrastructure; + +internal static class HeadlessModeOptions +{ + public const string HeadlessArgument = "--headless"; + + public static bool IsHeadless(IReadOnlyList args) + { + return args.Contains(HeadlessArgument, StringComparer.OrdinalIgnoreCase); + } +} diff --git a/src/UniGetUI.Avalonia/Infrastructure/MacOsNotificationBridge.cs b/src/UniGetUI.Avalonia/Infrastructure/MacOsNotificationBridge.cs new file mode 100644 index 0000000..3648cc5 --- /dev/null +++ b/src/UniGetUI.Avalonia/Infrastructure/MacOsNotificationBridge.cs @@ -0,0 +1,203 @@ +using System.Diagnostics; +using UniGetUI.Core.Data; +using UniGetUI.Core.Logging; +using UniGetUI.Core.SettingsEngine; +using UniGetUI.Core.Tools; +using UniGetUI.PackageEngine.Interfaces; +using UniGetUI.PackageOperations; + +namespace UniGetUI.Avalonia.Infrastructure; + +/// +/// macOS system notification delivery via osascript (works on all macOS versions). +/// NSUserNotificationCenter was removed in macOS 14; UNUserNotificationCenter requires +/// ObjC blocks that are impractical via pure P/Invoke. osascript is always available. +/// Callers are responsible for the OperatingSystem.IsMacOS() guard before invoking. +/// +internal static class MacOsNotificationBridge +{ + // ── Operation notifications ──────────────────────────────────────────── + + public static bool ShowProgress(AbstractOperation operation) + { + if (Settings.AreProgressNotificationsDisabled()) return false; + try + { + string title = operation.Metadata.Title.Length > 0 + ? operation.Metadata.Title + : CoreTools.Translate("Operation in progress"); + string message = operation.Metadata.Status.Length > 0 + ? operation.Metadata.Status + : CoreTools.Translate("Please wait..."); + DeliverNotification(title, message); + return true; + } + catch (Exception ex) + { + Logger.Warn("macOS progress notification failed"); + Logger.Warn(ex); + return false; + } + } + + public static bool ShowSuccess(AbstractOperation operation) + { + if (Settings.AreSuccessNotificationsDisabled()) return false; + try + { + string title = operation.Metadata.SuccessTitle.Length > 0 + ? operation.Metadata.SuccessTitle + : CoreTools.Translate("Success!"); + string message = operation.Metadata.SuccessMessage.Length > 0 + ? operation.Metadata.SuccessMessage + : CoreTools.Translate("Success!"); + DeliverNotification(title, message); + return true; + } + catch (Exception ex) + { + Logger.Warn("macOS success notification failed"); + Logger.Warn(ex); + return false; + } + } + + public static bool ShowError(AbstractOperation operation) + { + if (Settings.AreErrorNotificationsDisabled()) return false; + try + { + string title = operation.Metadata.FailureTitle.Length > 0 + ? operation.Metadata.FailureTitle + : CoreTools.Translate("Failed"); + string message = operation.Metadata.FailureMessage.Length > 0 + ? operation.Metadata.FailureMessage + : CoreTools.Translate("An error occurred while processing this package"); + DeliverNotification(title, message); + return true; + } + catch (Exception ex) + { + Logger.Warn("macOS error notification failed"); + Logger.Warn(ex); + return false; + } + } + + // ── Feature notifications ────────────────────────────────────────────── + + public static void ShowUpdatesAvailableNotification(IReadOnlyList upgradable) + { + if (Settings.AreUpdatesNotificationsDisabled()) return; + try + { + string title, message; + if (upgradable.Count == 1) + { + title = CoreTools.Translate("An update was found!"); + message = CoreTools.Translate("{0} can be updated to version {1}", + upgradable[0].Name, upgradable[0].NewVersionString); + } + else + { + title = CoreTools.Translate("Updates found!"); + message = CoreTools.Translate("{0} packages can be updated", upgradable.Count); + } + DeliverNotification(title, message); + } + catch (Exception ex) + { + Logger.Warn("macOS updates-available notification failed"); + Logger.Warn(ex); + } + } + + public static void ShowUpgradingPackagesNotification(IReadOnlyList upgradable) + { + if (Settings.AreUpdatesNotificationsDisabled()) return; + try + { + string title, message; + if (upgradable.Count == 1) + { + title = CoreTools.Translate("An update was found!"); + message = CoreTools.Translate("{0} is being updated to version {1}", + upgradable[0].Name, upgradable[0].NewVersionString); + } + else + { + title = CoreTools.Translate("{0} packages are being updated", upgradable.Count); + message = string.Join(", ", upgradable.Select(p => p.Name)); + } + DeliverNotification(title, message); + } + catch (Exception ex) + { + Logger.Warn("macOS upgrading-packages notification failed"); + Logger.Warn(ex); + } + } + + public static void ShowSelfUpdateAvailableNotification(string newVersion) + { + try + { + DeliverNotification( + CoreTools.Translate("{0} can be updated to version {1}", "UniGetUI", newVersion), + CoreTools.Translate("You have currently version {0} installed", CoreData.VersionName)); + } + catch (Exception ex) + { + Logger.Warn("macOS self-update notification failed"); + Logger.Warn(ex); + } + } + + public static void ShowNewShortcutsNotification(IReadOnlyList shortcuts) + { + if (Settings.AreNotificationsDisabled()) return; + try + { + string title, message; + if (shortcuts.Count == 1) + { + title = CoreTools.Translate("Desktop shortcut created"); + message = CoreTools.Translate( + "UniGetUI has detected a new desktop shortcut that can be deleted automatically.") + + "\n" + shortcuts[0].Split('/')[^1]; + } + else + { + title = CoreTools.Translate("{0} desktop shortcuts created", shortcuts.Count); + message = CoreTools.Translate( + "UniGetUI has detected {0} new desktop shortcuts that can be deleted automatically.", + shortcuts.Count); + } + DeliverNotification(title, message); + } + catch (Exception ex) + { + Logger.Warn("macOS shortcuts notification failed"); + Logger.Warn(ex); + } + } + + // ── Core delivery ────────────────────────────────────────────────────── + + private static void DeliverNotification(string title, string message) + { + // NSUserNotificationCenter was removed in macOS 14; osascript works on all versions. + string script = "display notification " + AppleScriptString(message) + + " with title " + AppleScriptString(title); + Process.Start(new ProcessStartInfo + { + FileName = "/usr/bin/osascript", + ArgumentList = { "-e", script }, + UseShellExecute = false, + CreateNoWindow = true, + }); + } + + private static string AppleScriptString(string s) => + "\"" + s.Replace("\\", "\\\\").Replace("\"", "\\\"") + "\""; +} diff --git a/src/UniGetUI.Avalonia/Infrastructure/MemoryTrimmer.cs b/src/UniGetUI.Avalonia/Infrastructure/MemoryTrimmer.cs new file mode 100644 index 0000000..04499a2 --- /dev/null +++ b/src/UniGetUI.Avalonia/Infrastructure/MemoryTrimmer.cs @@ -0,0 +1,82 @@ +using System; +using System.Runtime.InteropServices; +using System.Threading.Tasks; +using Avalonia.Threading; +using UniGetUI.Core.Logging; + +namespace UniGetUI.Avalonia.Infrastructure; + +// Collects and returns the working set to the OS once loading has settled — neither .NET nor the +// native allocator hand freed memory back on their own. Debounced so it never runs mid-load. +// Windows-only, best-effort. +internal static class MemoryTrimmer +{ + private static readonly TimeSpan SettleDelay = TimeSpan.FromSeconds(3); + private static DispatcherTimer? _timer; + + public static void RequestTrimAfterIdle() + { + if (!OperatingSystem.IsWindows()) return; + if (!Dispatcher.UIThread.CheckAccess()) + { + Dispatcher.UIThread.Post(RequestTrimAfterIdle); + return; + } + + _timer ??= CreateTimer(); + _timer.Stop(); + _timer.Start(); + } + + public static void CancelPending() + { + if (!OperatingSystem.IsWindows()) return; + if (!Dispatcher.UIThread.CheckAccess()) + { + Dispatcher.UIThread.Post(CancelPending); + return; + } + + _timer?.Stop(); + } + + private static DispatcherTimer CreateTimer() + { + var timer = new DispatcherTimer { Interval = SettleDelay }; + timer.Tick += (_, _) => + { + timer.Stop(); + Trim(); + }; + return timer; + } + + private static void Trim() => _ = Task.Run(() => + { + try + { + GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced, blocking: true); + GC.WaitForPendingFinalizers(); + GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced, blocking: true); + NativeMethods.SetProcessWorkingSetSize(NativeMethods.GetCurrentProcess(), -1, -1); + } + catch (Exception ex) + { + Logger.Warn($"Post-load working-set trim failed: {ex.Message}"); + } + }); + + private static class NativeMethods + { + [DllImport("kernel32.dll")] + public static extern nint GetCurrentProcess(); + + [DllImport("kernel32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool SetProcessWorkingSetSize( + nint hProcess, + nint dwMinimumWorkingSetSize, + nint dwMaximumWorkingSetSize + ); + } +} diff --git a/src/UniGetUI.Avalonia/Infrastructure/MicaWindowHelper.cs b/src/UniGetUI.Avalonia/Infrastructure/MicaWindowHelper.cs new file mode 100644 index 0000000..beab6ec --- /dev/null +++ b/src/UniGetUI.Avalonia/Infrastructure/MicaWindowHelper.cs @@ -0,0 +1,137 @@ +using System; +using System.Runtime.InteropServices; +using Avalonia; +using Avalonia.Controls; +using Avalonia.Controls.Primitives; +using Avalonia.Media; +using Avalonia.Platform; + +namespace UniGetUI.Avalonia.Infrastructure; + +/// +/// Gives a standard Avalonia the native Windows 11 look: +/// the Mica backdrop (whole-window) and rounded corners. The window border is left +/// at the OS default, so it only shows an accent color if the user enabled that in +/// Personalization. Windows-only and gated on Windows 11; a no-op elsewhere, so +/// the window keeps its opaque look when Mica isn't available. +/// Used by the secondary windows/dialogs; MainWindow has its own (custom-frame) variant. +/// +internal static class MicaWindowHelper +{ + private const int DWMWA_WINDOW_CORNER_PREFERENCE = 33; + private const int DWMWA_SYSTEMBACKDROP_TYPE = 38; + private const int DWMWCP_ROUND = 2; + private const int DWMSBT_TRANSIENTWINDOW = 3; // Acrylic — for transient surfaces (menus/flyouts); Mica won't paint on these + + private static bool _acrylicPopupsHooked; + + public static void Apply(Window window) + { + if (!IsMicaEnabled()) + return; + + // Avalonia paints the Mica backdrop from this hint; the transparent window lets it + // show. The dialog's content panels keep their (translucent) surfaces from the + // merged Styles.WindowsMica dictionary. + window.TransparencyLevelHint = new[] { WindowTransparencyLevel.Mica }; + + window.Opened += (_, _) => + { + if (window.TryGetPlatformHandle()?.Handle is { } handle && handle != 0) + { + int corner = DWMWCP_ROUND; + NativeMethods.DwmSetWindowAttribute(handle, DWMWA_WINDOW_CORNER_PREFERENCE, ref corner, sizeof(int)); + } + window.Background = Brushes.Transparent; + }; + } + + // Gives flyouts / menus / combo dropdowns / tooltips a native Win11 acrylic backdrop: + // the popup window is made transparent and DWM paints the (blurred, theme-adaptive) + // acrylic material behind it. Registered once at startup when Mica is enabled. + public static void EnableAcrylicPopups() + { + if (!IsMicaEnabled() || _acrylicPopupsHooked) + return; + _acrylicPopupsHooked = true; + + // In-app flyouts/menus/tooltips/combo popups are hosted in a PopupRoot; style each as it loads. + Control.LoadedEvent.AddClassHandler((root, _) => ApplyAcrylicToPopup(root)); + + // The system-tray context menu is NOT a PopupRoot — Avalonia hosts it in its own Window + // (Avalonia.Win32.TrayIconImpl.TrayPopupRoot), so it misses the handler above and would + // render with no backdrop (transparent over the desktop). Catch it by type name and apply + // the same acrylic treatment. The other Windows (MainWindow/dialogs) are handled via Apply(). + Control.LoadedEvent.AddClassHandler((win, _) => + { + if (win.GetType().Name == "TrayPopupRoot") + ApplyAcrylicToPopup(win); + }); + } + + private static void ApplyAcrylicToPopup(TopLevel root) + { + // Request acrylic (not Transparent): the Transparent level makes a layered window, and DWM + // system backdrops never paint on those — so the popup ended up fully see-through with only + // the presenter tint, unreadable when shown over the desktop (e.g. the tray menu). AcrylicBlur + // gives a composited window DWM can actually fill. This path only runs when Mica is enabled + // (Win11 + transparency effects), so acrylic is always available here. + root.TransparencyLevelHint = new[] { WindowTransparencyLevel.AcrylicBlur, WindowTransparencyLevel.Blur }; + root.Background = Brushes.Transparent; + + if (root.TryGetPlatformHandle()?.Handle is not { } handle || handle == 0) + return; + + int corner = DWMWCP_ROUND; + NativeMethods.DwmSetWindowAttribute(handle, DWMWA_WINDOW_CORNER_PREFERENCE, ref corner, sizeof(int)); + int backdrop = DWMSBT_TRANSIENTWINDOW; + NativeMethods.DwmSetWindowAttribute(handle, DWMWA_SYSTEMBACKDROP_TYPE, ref backdrop, sizeof(int)); + } + + /// + /// True when the native Mica look should be used: Windows 11+ AND the user has + /// "Transparency effects" enabled. When transparency is off we keep the solid look, + /// since the Mica backdrop otherwise lingers (DWM keeps painting it). + /// + public static bool IsMicaEnabled() + => OperatingSystem.IsWindows() + && Environment.OSVersion.Version.Build >= 22000 + && IsOsTransparencyEnabled(); + + private static bool IsOsTransparencyEnabled() + { + if (!OperatingSystem.IsWindows()) + return false; + + try + { + var data = new byte[4]; + int size = data.Length; + int result = NativeMethods.RegGetValueW( + NativeMethods.HKEY_CURRENT_USER, + @"Software\Microsoft\Windows\CurrentVersion\Themes\Personalize", + "EnableTransparency", + NativeMethods.RRF_RT_REG_DWORD, + out _, data, ref size); + if (result == 0) // ERROR_SUCCESS + return BitConverter.ToInt32(data, 0) != 0; + } + catch { /* fall through to the default */ } + + return true; // value missing/unreadable -> assume transparency is on + } + + private static class NativeMethods + { + // winreg.h: HKEY_CURRENT_USER = (HKEY)(ULONG_PTR)((LONG)0x80000001) — sign-extended on x64. + public static readonly nint HKEY_CURRENT_USER = new(unchecked((int)0x80000001)); + public const int RRF_RT_REG_DWORD = 0x00000010; + + [DllImport("dwmapi.dll")] + public static extern int DwmSetWindowAttribute(nint hwnd, int attr, ref int value, int size); + + [DllImport("advapi32.dll", CharSet = CharSet.Unicode)] + public static extern int RegGetValueW(nint hkey, string lpSubKey, string lpValue, int dwFlags, + out int pdwType, byte[] pvData, ref int pcbData); + } +} diff --git a/src/UniGetUI.Avalonia/Infrastructure/MotionPreference.cs b/src/UniGetUI.Avalonia/Infrastructure/MotionPreference.cs new file mode 100644 index 0000000..47ea897 --- /dev/null +++ b/src/UniGetUI.Avalonia/Infrastructure/MotionPreference.cs @@ -0,0 +1,109 @@ +using System; +using System.Diagnostics; +using System.Runtime.InteropServices; +using System.Runtime.Versioning; +using UniGetUI.Core.Logging; + +namespace UniGetUI.Avalonia.Infrastructure; + +/// +/// Reads the OS "reduce motion / show animations" accessibility preference so UI +/// transitions can honor it (Windows: Settings → Accessibility → Visual effects → +/// Animation effects; macOS: Accessibility → Display → Reduce motion). Windows is read +/// live on each access (cheap P/Invoke); macOS/Linux are read once and cached because +/// they spawn a process. Defaults to "animations on" if the preference can't be read. +/// +internal static class MotionPreference +{ + private static bool? _cachedUnix; + + /// True when the user has asked the OS to minimize animations. + public static bool ReducedMotion + { + get + { + if (OperatingSystem.IsWindows()) + { + if (WindowsAvaloniaRenderingPolicy.ShouldReduceMotion) + return true; + + return GetWindowsReducedMotion(); + } + + return _cachedUnix ??= GetUnixReducedMotion(); + } + } + + [SupportedOSPlatform("windows")] + private static bool GetWindowsReducedMotion() + { + try + { + // Same signal WinUI's UISettings.AnimationsEnabled reads; pvParam is a BOOL. + int enabled = 1; + if (NativeMethods.SystemParametersInfoW(NativeMethods.SPI_GETCLIENTAREAANIMATION, 0, ref enabled, 0)) + return enabled == 0; + } + catch (Exception ex) + { + Logger.Warn("Could not read SPI_GETCLIENTAREAANIMATION; assuming animations enabled"); + Logger.Warn(ex); + } + return false; + } + + private static bool GetUnixReducedMotion() + { + try + { + if (OperatingSystem.IsMacOS()) + return ReadCommand("/usr/bin/defaults", ["read", "com.apple.universalaccess", "reduceMotion"]) is "1"; + + if (OperatingSystem.IsLinux()) + return string.Equals( + ReadCommand("/usr/bin/gsettings", ["get", "org.gnome.desktop.interface", "gtk-enable-animations"]), + "false", StringComparison.OrdinalIgnoreCase); + } + catch (Exception ex) + { + Logger.Warn("Could not read OS reduce-motion preference; assuming animations enabled"); + Logger.Warn(ex); + } + return false; + } + + private static string? ReadCommand(string fileName, string[] args) + { + var psi = new ProcessStartInfo + { + FileName = fileName, + UseShellExecute = false, + RedirectStandardOutput = true, + RedirectStandardError = true, + CreateNoWindow = true, + }; + foreach (var arg in args) + psi.ArgumentList.Add(arg); + + using var proc = Process.Start(psi); + if (proc is null) + return null; + + string output = proc.StandardOutput.ReadToEnd(); + if (!proc.WaitForExit(2000)) + { + try { proc.Kill(); } catch { /* best effort */ } + return null; + } + return proc.ExitCode == 0 ? output.Trim() : null; + } + + private static class NativeMethods + { + public const uint SPI_GETCLIENTAREAANIMATION = 0x1042; + + [DllImport("user32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool SystemParametersInfoW(uint uiAction, uint uiParam, ref int pvParam, uint fWinIni); + } +} diff --git a/src/UniGetUI.Avalonia/Infrastructure/ProcessEnvironmentConfigurator.cs b/src/UniGetUI.Avalonia/Infrastructure/ProcessEnvironmentConfigurator.cs new file mode 100644 index 0000000..469b374 --- /dev/null +++ b/src/UniGetUI.Avalonia/Infrastructure/ProcessEnvironmentConfigurator.cs @@ -0,0 +1,85 @@ +using System.Diagnostics; +using UniGetUI.Core.Logging; +using UniGetUI.Core.SettingsEngine; + +namespace UniGetUI.Avalonia.Infrastructure; + +internal static class ProcessEnvironmentConfigurator +{ + public static void PrepareForCurrentPlatform() + { + if (OperatingSystem.IsMacOS()) + { + ExpandMacOSPath(); + } + + ApplyProxySettingsToProcess(); + } + + public static void ApplyProxySettingsToProcess() + { + try + { + var proxyUri = Settings.GetProxyUrl(); + if (proxyUri is null || !Settings.Get(Settings.K.EnableProxy)) + { + Environment.SetEnvironmentVariable("HTTP_PROXY", "", EnvironmentVariableTarget.Process); + return; + } + + string content; + if (!Settings.Get(Settings.K.EnableProxyAuth)) + { + content = proxyUri.ToString(); + } + else + { + var creds = Settings.GetProxyCredentials(); + if (creds is null) + { + content = proxyUri.ToString(); + } + else + { + content = $"{proxyUri.Scheme}://{Uri.EscapeDataString(creds.UserName)}" + + $":{Uri.EscapeDataString(creds.Password)}" + + $"@{proxyUri.AbsoluteUri.Replace($"{proxyUri.Scheme}://", "")}"; + } + } + + Environment.SetEnvironmentVariable("HTTP_PROXY", content, EnvironmentVariableTarget.Process); + } + catch (Exception ex) + { + Logger.Error("Failed to apply proxy settings:"); + Logger.Error(ex); + } + } + + private static void ExpandMacOSPath() + { + try + { + using var process = new Process + { + StartInfo = new ProcessStartInfo("zsh", ["-l", "-c", "printenv PATH"]) + { + UseShellExecute = false, + RedirectStandardOutput = true, + CreateNoWindow = true, + }, + }; + process.Start(); + string shellPath = process.StandardOutput.ReadToEnd().Trim(); + process.WaitForExit(5000); + if (!string.IsNullOrEmpty(shellPath)) + { + Environment.SetEnvironmentVariable("PATH", shellPath); + } + } + catch + { + // Keep the existing PATH if the shell can't be launched. + } + } +} diff --git a/src/UniGetUI.Avalonia/Infrastructure/RelayCommand.cs b/src/UniGetUI.Avalonia/Infrastructure/RelayCommand.cs new file mode 100644 index 0000000..c9fa12a --- /dev/null +++ b/src/UniGetUI.Avalonia/Infrastructure/RelayCommand.cs @@ -0,0 +1,19 @@ +using System.Windows.Input; + +namespace UniGetUI.Avalonia.Infrastructure; + +internal sealed class RelayCommand : ICommand +{ + private readonly Action _execute; + + public RelayCommand(Action execute) + { + _execute = execute; + } + + public event EventHandler? CanExecuteChanged { add { } remove { } } + + public bool CanExecute(object? parameter) => true; + + public void Execute(object? parameter) => _execute(); +} diff --git a/src/UniGetUI.Avalonia/Infrastructure/Secrets.cs b/src/UniGetUI.Avalonia/Infrastructure/Secrets.cs new file mode 100644 index 0000000..7663356 --- /dev/null +++ b/src/UniGetUI.Avalonia/Infrastructure/Secrets.cs @@ -0,0 +1,15 @@ +namespace UniGetUI.Avalonia.Infrastructure; + +internal static partial class Secrets +{ + /* ---------------------------------------------------------------- + * W A R N I N G !!! + * + * Seeing errors? Build the project (maybe twice) + */ + public static partial string GetGitHubClientId(); + public static partial string GetGitHubClientSecret(); + public static partial string GetOpenSearchUsername(); + public static partial string GetOpenSearchPassword(); + /* ------------------------------------------------------------------------ */ +} diff --git a/src/UniGetUI.Avalonia/Infrastructure/SingleInstanceRedirector.cs b/src/UniGetUI.Avalonia/Infrastructure/SingleInstanceRedirector.cs new file mode 100644 index 0000000..add5a1d --- /dev/null +++ b/src/UniGetUI.Avalonia/Infrastructure/SingleInstanceRedirector.cs @@ -0,0 +1,99 @@ +using System.IO.Pipes; +using System.Text; +using Avalonia.Threading; +using UniGetUI.Core.Data; +using UniGetUI.Core.Logging; + +namespace UniGetUI.Avalonia.Infrastructure; + +/// +/// Forwards command-line arguments from a second UniGetUI instance to the already-running +/// first instance via a named pipe, mirroring WinUI3's AppInstance.RedirectActivationToAsync(). +/// +/// The first instance calls immediately after acquiring the +/// single-instance mutex. Any subsequent launch that cannot acquire the mutex calls +/// and exits. +/// +internal static class SingleInstanceRedirector +{ + // One pipe name per user session (the MainWindowIdentifier is a stable constant). + private static readonly string PipeName = + $"UniGetUI_Pipe_{CoreData.MainWindowIdentifier}_{Environment.UserName}"; + + private static Thread? _listener; + + /// + /// Start a background listener thread. When a second instance forwards its args, + /// is invoked on the Avalonia UI thread. + /// + public static void StartListener(Action onArgsReceived) + { + _listener = new Thread(() => + { + while (true) + { + try + { + using var pipe = new NamedPipeServerStream( + PipeName, + PipeDirection.In, + maxNumberOfServerInstances: 1, + transmissionMode: PipeTransmissionMode.Byte); + + pipe.WaitForConnection(); + + using var reader = new StreamReader(pipe, Encoding.UTF8); + string payload = reader.ReadToEnd(); + + // Args are newline-delimited. + var args = payload.Split('\n', StringSplitOptions.RemoveEmptyEntries); + Dispatcher.UIThread.Post(() => onArgsReceived(args)); + } + catch (Exception ex) when (ex is not ThreadAbortException) + { + // Keep the listener alive through errors (the pipe breaks on disconnect, etc.) + Logger.Warn($"SingleInstanceRedirector listener error: {ex.Message}"); + } + } + }) + { + IsBackground = true, + Name = "SingleInstancePipeListener", + }; + + _listener.Start(); + } + + /// + /// Try to forward to the already-running first instance. + /// + /// true if the message was delivered successfully. + public static bool TryForwardToFirstInstance(string[] args) + { + if (args.Length == 0) + { + // Nothing to forward — still show the window by sending an empty payload. + } + + try + { + using var pipe = new NamedPipeClientStream( + serverName: ".", + pipeName: PipeName, + direction: PipeDirection.Out); + + pipe.Connect(500); + + using var writer = new StreamWriter(pipe, Encoding.UTF8); + // Newline-delimited args payload. + writer.Write(string.Join('\n', args)); + writer.Flush(); + return true; + } + catch (Exception ex) + { + Logger.Warn($"Could not forward args to first instance: {ex.Message}"); + return false; + } + } +} diff --git a/src/UniGetUI.Avalonia/Infrastructure/ThemeHelper.cs b/src/UniGetUI.Avalonia/Infrastructure/ThemeHelper.cs new file mode 100644 index 0000000..2bb6113 --- /dev/null +++ b/src/UniGetUI.Avalonia/Infrastructure/ThemeHelper.cs @@ -0,0 +1,27 @@ +using Avalonia; +using Avalonia.Platform; +using Avalonia.Styling; + +namespace UniGetUI.Avalonia.Infrastructure; + +// Reliable theme resolution for code that bakes colors in C# (log/output views). ActualThemeVariant +// can read back as Default before it settles; resolve that against the OS theme so a resource lookup +// never falls back to the light-theme (near-black) value on a dark background (#5032). +public static class ThemeHelper +{ + public static ThemeVariant Variant + { + get + { + var app = Application.Current; + var variant = app?.ActualThemeVariant; + if (variant == ThemeVariant.Dark) return ThemeVariant.Dark; + if (variant == ThemeVariant.Light) return ThemeVariant.Light; + return app?.PlatformSettings?.GetColorValues().ThemeVariant == PlatformThemeVariant.Dark + ? ThemeVariant.Dark + : ThemeVariant.Light; + } + } + + public static bool IsDark => Variant == ThemeVariant.Dark; +} diff --git a/src/UniGetUI.Avalonia/Infrastructure/TrayService.cs b/src/UniGetUI.Avalonia/Infrastructure/TrayService.cs new file mode 100644 index 0000000..c1311c2 --- /dev/null +++ b/src/UniGetUI.Avalonia/Infrastructure/TrayService.cs @@ -0,0 +1,163 @@ +using Avalonia; +using Avalonia.Controls; +using Avalonia.Platform; +using Avalonia.Styling; +using Avalonia.Threading; +using UniGetUI.Avalonia.Views; +using UniGetUI.Core.Data; +using UniGetUI.Core.Logging; +using UniGetUI.Core.SettingsEngine; +using UniGetUI.Core.Tools; +using UniGetUI.PackageEngine.Enums; +using UniGetUI.PackageEngine.PackageLoader; + +namespace UniGetUI.Avalonia.Infrastructure; + +internal sealed class TrayService : IDisposable +{ + private readonly TrayIcon _trayIcon; + private string _lastIconUri = ""; + + public TrayService(MainWindow owner) + { + _trayIcon = new TrayIcon + { + ToolTipText = "UniGetUI", + Menu = BuildMenu(owner), + }; + + _trayIcon.Clicked += (_, _) => Dispatcher.UIThread.Post(() => owner.ShowFromTray()); + + var app = Application.Current!; + var icons = TrayIcon.GetIcons(app) ?? new TrayIcons(); + icons.Add(_trayIcon); + TrayIcon.SetIcons(app, icons); + } + + public void UpdateStatus() + { + try + { + _trayIcon.IsVisible = !Settings.Get(Settings.K.DisableSystemTray); + + string status; + string tooltip; + + bool anyRunning = AvaloniaOperationRegistry.Operations.Any( + o => o.Status is OperationStatus.Running or OperationStatus.InQueue); + + int updatesCount = UpgradablePackagesLoader.Instance?.Count() ?? 0; + + if (anyRunning) + { + status = "blue"; + tooltip = CoreTools.Translate("Operation in progress"); + } + else if (AvaloniaOperationRegistry.ErrorsOccurred > 0) + { + status = "orange"; + tooltip = CoreTools.Translate("Attention required"); + } + else if (AvaloniaOperationRegistry.RestartRequired) + { + status = "turquoise"; + tooltip = CoreTools.Translate("Restart required"); + } + else if (updatesCount > 0) + { + status = "green"; + tooltip = updatesCount == 1 + ? CoreTools.Translate("1 update is available") + : CoreTools.Translate("{0} updates are available", updatesCount); + } + else + { + status = "empty"; + tooltip = CoreTools.Translate("Everything is up to date"); + } + + _trayIcon.ToolTipText = tooltip + " - UniGetUI"; + + bool light = IsTaskbarLight(); + string tone = light ? "_black" : "_white"; + + string uri = $"avares://UniGetUI/Assets/tray_{status}{tone}_legacy.ico"; + + if (_lastIconUri == uri) return; + _lastIconUri = uri; + + using var stream = AssetLoader.Open(new Uri(uri)); + _trayIcon.Icon = new WindowIcon(stream); + } + catch (Exception ex) + { + Logger.Error("Failed to update tray icon status:"); + Logger.Error(ex); + } + } + + private static bool IsTaskbarLight() + { +#if WINDOWS + // On Windows, read the registry to match the taskbar background colour. + try + { + using var key = Microsoft.Win32.Registry.CurrentUser.OpenSubKey( + @"Software\Microsoft\Windows\CurrentVersion\Themes\Personalize"); + return key?.GetValue("SystemUsesLightTheme") is int v && v > 0; + } + catch + { + return false; + } +#else + // On Linux (and other platforms), mirror the app's active theme variant so + // the icon remains legible regardless of the desktop colour scheme. + return Application.Current?.ActualThemeVariant == ThemeVariant.Light; +#endif + } + + private static NativeMenu BuildMenu(MainWindow owner) + { + var menu = new NativeMenu(); + + var discover = new NativeMenuItem(CoreTools.Translate("Discover Packages")); + discover.Click += (_, _) => Dispatcher.UIThread.Post(() => { owner.Navigate(PageType.Discover); owner.ShowFromTray(); }); + + var updates = new NativeMenuItem(CoreTools.Translate("Available Updates")); + updates.Click += (_, _) => Dispatcher.UIThread.Post(() => { owner.Navigate(PageType.Updates); owner.ShowFromTray(); }); + + var installed = new NativeMenuItem(CoreTools.Translate("Installed Packages")); + installed.Click += (_, _) => Dispatcher.UIThread.Post(() => { owner.Navigate(PageType.Installed); owner.ShowFromTray(); }); + + menu.Add(discover); + menu.Add(updates); + menu.Add(installed); + menu.Add(new NativeMenuItemSeparator()); + + menu.Add(new NativeMenuItem( + CoreTools.Translate("UniGetUI Version {0} by Devolutions", CoreData.VersionName)) + { + IsEnabled = false, + }); + menu.Add(new NativeMenuItemSeparator()); + + var show = new NativeMenuItem(CoreTools.Translate("Show UniGetUI")); + show.Click += (_, _) => Dispatcher.UIThread.Post(() => owner.ShowFromTray()); + menu.Add(show); + + var quit = new NativeMenuItem(CoreTools.Translate("Quit")); + quit.Click += (_, _) => Dispatcher.UIThread.Post(() => owner.QuitApplication()); + menu.Add(quit); + + return menu; + } + + public void Dispose() + { + var app = Application.Current; + if (app is not null) + TrayIcon.GetIcons(app)?.Remove(_trayIcon); + _trayIcon.Dispose(); + } +} diff --git a/src/UniGetUI.Avalonia/Infrastructure/UninstallConfirmationDialog.cs b/src/UniGetUI.Avalonia/Infrastructure/UninstallConfirmationDialog.cs new file mode 100644 index 0000000..d414993 --- /dev/null +++ b/src/UniGetUI.Avalonia/Infrastructure/UninstallConfirmationDialog.cs @@ -0,0 +1,136 @@ +using Avalonia; +using Avalonia.Controls; +using Avalonia.Layout; +using Avalonia.Media; +using UniGetUI.Core.Tools; +using UniGetUI.PackageEngine.Interfaces; + +namespace UniGetUI.Avalonia.Infrastructure; + +internal static class UninstallConfirmationDialog +{ + public static Task ConfirmAsync(Window owner, IPackage package) + { + return ConfirmAsync(owner, [package]); + } + + public static async Task ConfirmAsync(Window owner, IReadOnlyList packages) + { + if (packages.Count == 0) + { + return false; + } + + bool isConfirmed = false; + var dialog = new Window + { + Width = packages.Count == 1 ? 520 : 560, + Height = packages.Count == 1 ? 220 : 380, + MinWidth = 420, + MinHeight = packages.Count == 1 ? 220 : 300, + CanResize = packages.Count > 1, + ShowInTaskbar = false, + WindowStartupLocation = WindowStartupLocation.CenterOwner, + Title = CoreTools.Translate("Are you sure?"), + }; + + var titleBlock = new TextBlock + { + Text = CoreTools.Translate("Are you sure?"), + FontSize = 18, + FontWeight = FontWeight.SemiBold, + TextWrapping = TextWrapping.Wrap, + }; + + var messageBlock = new TextBlock + { + Text = packages.Count == 1 + ? CoreTools.Translate("Do you really want to uninstall {0}?", packages[0].Name) + : CoreTools.Translate( + "Do you really want to uninstall the following {0} packages?", + packages.Count), + Opacity = 0.82, + TextWrapping = TextWrapping.Wrap, + }; + + var root = new Grid + { + Margin = new Thickness(20), + RowDefinitions = new RowDefinitions("Auto,*,Auto"), + RowSpacing = 14, + }; + + var headerPanel = new StackPanel + { + Spacing = 8, + Children = + { + titleBlock, + messageBlock, + }, + }; + Grid.SetRow(headerPanel, 0); + root.Children.Add(headerPanel); + + if (packages.Count > 1) + { + string packageListText = string.Join( + Environment.NewLine, + packages + .OrderBy(package => package.Name, StringComparer.OrdinalIgnoreCase) + .Select(package => "* " + package.Name)); + + var packageListBlock = new TextBlock + { + Text = packageListText, + FontFamily = new FontFamily("Consolas"), + TextWrapping = TextWrapping.Wrap, + }; + + var packageListViewer = new ScrollViewer + { + MaxHeight = 220, + Content = packageListBlock, + }; + Grid.SetRow(packageListViewer, 1); + root.Children.Add(packageListViewer); + } + + var noButton = new Button + { + Content = CoreTools.Translate("No"), + MinWidth = 100, + }; + noButton.Click += (_, _) => dialog.Close(); + + var yesButton = new Button + { + Content = CoreTools.Translate("Yes"), + MinWidth = 100, + }; + yesButton.Classes.Add("accent"); + yesButton.Click += (_, _) => + { + isConfirmed = true; + dialog.Close(); + }; + + var footerPanel = new StackPanel + { + Orientation = Orientation.Horizontal, + Spacing = 8, + HorizontalAlignment = HorizontalAlignment.Right, + Children = + { + noButton, + yesButton, + }, + }; + Grid.SetRow(footerPanel, 2); + root.Children.Add(footerPanel); + + dialog.Content = root; + await dialog.ShowDialog(owner); + return isConfirmed; + } +} diff --git a/src/UniGetUI.Avalonia/Infrastructure/Win32ToastNotifier.cs b/src/UniGetUI.Avalonia/Infrastructure/Win32ToastNotifier.cs new file mode 100644 index 0000000..29b2205 --- /dev/null +++ b/src/UniGetUI.Avalonia/Infrastructure/Win32ToastNotifier.cs @@ -0,0 +1,137 @@ +#if WINDOWS +using System; +using System.Runtime.InteropServices; +using UniGetUI.Core.Logging; +using Windows.Data.Xml.Dom; +using Windows.UI.Notifications; + +namespace UniGetUI.Avalonia.Infrastructure; + +/// +/// Show-only Windows toast notifications via the OS-provided UWP +/// Windows.UI.Notifications surface, with no Windows App SDK / WinUI dependency. +/// +/// +/// The notifier is keyed by an AppUserModelID (AUMID). For an unpackaged Win32 app the +/// shell will only surface toasts for that AUMID once a Start Menu shortcut carrying the +/// same AUMID exists; handles that side. Toast +/// activation (button clicks) is intentionally not wired — clicking the toast launches +/// the app with its unigetui:// deep-link so the single-instance handler can +/// foreground the window, which keeps this dependency-free. +/// +internal static class Win32ToastNotifier +{ + /// Stable AUMID for UniGetUI. Must match the one stamped on the Start Menu shortcut. + public const string AppUserModelId = "Devolutions.UniGetUI"; + + private static bool _availabilityChecked; + private static bool _isAvailable; + + /// + /// Stamps onto the current process so the shell attributes + /// toasts to UniGetUI. Safe to call repeatedly; a no-op on non-Windows. + /// + public static void SetProcessAumid() + { + if (!OperatingSystem.IsWindows()) + return; + + try + { + _ = SetCurrentProcessExplicitAppUserModelID(AppUserModelId); + } + catch (Exception ex) + { + Logger.Warn("Could not set process AppUserModelID for toast notifications"); + Logger.Warn(ex); + } + } + + /// + /// True once we have confirmed the UWP toast surface is usable on this Windows install. + /// Non-Windows platforms report false. + /// + public static bool IsAvailable() + { + if (!OperatingSystem.IsWindows()) + return false; + + if (_availabilityChecked) + return _isAvailable; + + _availabilityChecked = true; + try + { + _ = ToastNotificationManager.CreateToastNotifier(AppUserModelId); + _isAvailable = true; + } + catch (Exception ex) + { + Logger.Warn("UWP toast notifier is not available; falling back to in-app banners"); + Logger.Warn(ex); + _isAvailable = false; + } + + return _isAvailable; + } + + /// + /// Shows a toast with the supplied title and message and a launch argument that is + /// forwarded to the app when the user clicks the toast. Returns false if the + /// toast could not be shown (caller should fall back to an in-app banner). + /// + public static bool Show(string title, string message, string launchArgument) + { + if (!OperatingSystem.IsWindows()) + return false; + + try + { + string xml = BuildToastXml(title, message, launchArgument); + + var xmlDoc = new XmlDocument(); + xmlDoc.LoadXml(xml); + + var notification = new ToastNotification(xmlDoc); + ToastNotificationManager.CreateToastNotifier(AppUserModelId).Show(notification); + return true; + } + catch (Exception ex) + { + Logger.Warn("Could not show Windows toast notification"); + Logger.Warn(ex); + return false; + } + } + + private static string BuildToastXml(string title, string message, string launchArgument) + { + string titleEsc = XmlEscape(title); + string messageEsc = XmlEscape(message); + string launchEsc = XmlEscape(launchArgument); + + return $""" + + + + {titleEsc} + {messageEsc} + + + + """; + } + + private static string XmlEscape(string value) + => value + .Replace("&", "&") + .Replace("<", "<") + .Replace(">", ">") + .Replace("\"", """) + .Replace("'", "'"); + + [DllImport("shell32.dll", CharSet = CharSet.Unicode, SetLastError = true)] + private static extern int SetCurrentProcessExplicitAppUserModelID(string appUserModelID); +} +#endif diff --git a/src/UniGetUI.Avalonia/Infrastructure/WindowsAppNotificationBridge.cs b/src/UniGetUI.Avalonia/Infrastructure/WindowsAppNotificationBridge.cs new file mode 100644 index 0000000..9bfe70a --- /dev/null +++ b/src/UniGetUI.Avalonia/Infrastructure/WindowsAppNotificationBridge.cs @@ -0,0 +1,306 @@ +using System.Collections.Generic; +using UniGetUI.Avalonia.Views; +using UniGetUI.Core.Data; +using UniGetUI.Core.Logging; +using UniGetUI.Core.SettingsEngine; +using UniGetUI.Core.Tools; +using UniGetUI.Interface.Enums; +using UniGetUI.PackageEngine.Interfaces; +using UniGetUI.PackageOperations; + +namespace UniGetUI.Avalonia.Infrastructure; + +/// +/// Delivers UniGetUI's notifications via native Windows Action-Center toasts using the +/// UWP Windows.UI.Notifications COM surface, with no Windows App SDK / WinUI +/// dependency. Toasts are show-only: clicking a toast launches the app through the +/// unigetui:// deep-link (registered by the installer) so the existing +/// single-instance handler foregrounds the window. The inline action buttons carried +/// by the old WinRT toasts are intentionally dropped; activation is surfaced via +/// only when the app is already running and the toast +/// is clicked, so the main-window view model keeps its handler. When the toast COM surface +/// is unavailable, feature notifications fall back to the in-app Avalonia banner via +/// ; per-operation results do not (they +/// already appear in the operations panel — see the allowInAppFallback flag on Show). +/// +internal static class WindowsAppNotificationBridge +{ + /// Invoked when a notification's default action is triggered (toast clicked). + public static event Action? NotificationActivated; + + /// + /// Parses a unigetui://<action> launch argument produced by a toast + /// click, returning the encoded action or null if the argument is not a toast + /// deep-link. Used by the secondary-instance handler to route toast activations. + /// + public static string? TryParseToastLaunchArgument(string arg) + { + if (string.IsNullOrEmpty(arg)) + return null; + + const string prefix = "unigetui://"; + return arg.StartsWith(prefix, StringComparison.OrdinalIgnoreCase) + ? arg[prefix.Length..] + : null; + } + + /// Raises with the given action. + public static void RaiseActivation(string action) + { + try { NotificationActivated?.Invoke(action); } + catch (Exception ex) + { + Logger.Warn("NotificationActivated raise failed"); + Logger.Warn(ex); + } + } + + public static bool ShowProgress(AbstractOperation operation) + { + string title = operation.Metadata.Title.Length > 0 + ? operation.Metadata.Title + : CoreTools.Translate("Operation in progress"); + + string message = operation.Metadata.Status.Length > 0 + ? operation.Metadata.Status + : CoreTools.Translate("Please wait..."); + + return Show(title, message, MainWindow.RuntimeNotificationLevel.Progress, launchAction: NotificationArguments.Show, allowInAppFallback: false); + } + + public static bool ShowSuccess(AbstractOperation operation) + { + string title = operation.Metadata.SuccessTitle.Length > 0 + ? operation.Metadata.SuccessTitle + : CoreTools.Translate("Success!"); + + string message = operation.Metadata.SuccessMessage.Length > 0 + ? operation.Metadata.SuccessMessage + : CoreTools.Translate("Success!"); + + return Show(title, message, MainWindow.RuntimeNotificationLevel.Success, launchAction: NotificationArguments.Show, allowInAppFallback: false); + } + + public static bool ShowError(AbstractOperation operation) + { + string title = operation.Metadata.FailureTitle.Length > 0 + ? operation.Metadata.FailureTitle + : CoreTools.Translate("Failed"); + + string message = operation.Metadata.FailureMessage.Length > 0 + ? operation.Metadata.FailureMessage + : CoreTools.Translate("An error occurred while processing this package"); + + return Show(title, message, MainWindow.RuntimeNotificationLevel.Error, launchAction: NotificationArguments.Show, allowInAppFallback: false); + } + + public static void RemoveProgress(AbstractOperation operation) + { + // The UWP toast surface has no tag-based remove without the WinAppSDK helper. + // Progress toasts are short-lived and replaced by the subsequent success/error toast. + _ = operation; + } + + // ── updates-available notification ─────────────────────────────────────── + + /// + /// Shows a Windows toast notification listing available package updates. No-op on + /// non-Windows or when notifications are disabled (mirrors the previous bridge's + /// platform guard so macOS/Linux stay untouched). + /// + public static void ShowUpdatesAvailableNotification(IReadOnlyList upgradable) + { + if (!OperatingSystem.IsWindows()) return; + if (Settings.AreUpdatesNotificationsDisabled()) return; + + bool sendNotification = upgradable.Any(p => + !Settings.GetDictionaryItem( + Settings.K.DisabledPackageManagerNotifications, p.Manager.Name)); + if (!sendNotification) return; + + try + { + if (upgradable.Count == 1) + { + Show( + CoreTools.Translate("An update was found!"), + CoreTools.Translate("{0} can be updated to version {1}", + upgradable[0].Name, upgradable[0].NewVersionString), + MainWindow.RuntimeNotificationLevel.Success, + launchAction: NotificationArguments.ShowOnUpdatesTab); + } + else + { + Show( + CoreTools.Translate("Updates found!"), + CoreTools.Translate("{0} packages can be updated", upgradable.Count), + MainWindow.RuntimeNotificationLevel.Success, + launchAction: NotificationArguments.ShowOnUpdatesTab); + } + } + catch (Exception ex) + { + Logger.Warn("Could not show updates-available notification"); + Logger.Warn(ex); + } + } + + /// + /// Shows a Windows toast notification when packages are actively being updated (auto-update triggered). + /// + public static void ShowUpgradingPackagesNotification(IReadOnlyList upgradable) + { + if (!OperatingSystem.IsWindows()) return; + if (Settings.AreUpdatesNotificationsDisabled()) return; + + bool sendNotification = upgradable.Any(p => + !Settings.GetDictionaryItem( + Settings.K.DisabledPackageManagerNotifications, p.Manager.Name)); + if (!sendNotification) return; + + try + { + if (upgradable.Count == 1) + { + Show( + CoreTools.Translate("An update was found!"), + CoreTools.Translate("{0} is being updated to version {1}", + upgradable[0].Name, upgradable[0].NewVersionString), + MainWindow.RuntimeNotificationLevel.Progress, + launchAction: NotificationArguments.ShowOnUpdatesTab); + } + else + { + string attribution = string.Join(", ", upgradable + .Where(p => !Settings.GetDictionaryItem( + Settings.K.DisabledPackageManagerNotifications, p.Manager.Name)) + .Select(p => p.Name)); + + Show( + CoreTools.Translate("{0} packages are being updated", upgradable.Count), + attribution, + MainWindow.RuntimeNotificationLevel.Progress, + launchAction: NotificationArguments.ShowOnUpdatesTab); + } + } + catch (Exception ex) + { + Logger.Warn("Could not show upgrading-packages notification"); + Logger.Warn(ex); + } + } + + /// + /// Shows a Windows toast offering a UniGetUI self-update. + /// + public static void ShowSelfUpdateAvailableNotification(string newVersion) + { + if (!OperatingSystem.IsWindows()) return; + try + { + Show( + CoreTools.Translate("{0} can be updated to version {1}", "UniGetUI", newVersion), + CoreTools.Translate("You have currently version {0} installed", CoreData.VersionName), + MainWindow.RuntimeNotificationLevel.Success, + launchAction: NotificationArguments.Show); + } + catch (Exception ex) + { + Logger.Warn("Could not show self-update notification"); + Logger.Warn(ex); + } + } + + /// + /// Shows a Windows toast notification after new desktop shortcuts are detected. + /// + public static void ShowNewShortcutsNotification(IReadOnlyList shortcuts) + { + if (!OperatingSystem.IsWindows()) return; + if (Settings.AreNotificationsDisabled()) return; + + try + { + string title; + string message; + + if (shortcuts.Count == 1) + { + title = CoreTools.Translate("Desktop shortcut created"); + message = CoreTools.Translate( + "UniGetUI has detected a new desktop shortcut that can be deleted automatically.") + + "\n" + shortcuts[0].Split('\\')[^1]; + } + else + { + string names = string.Join(", ", shortcuts.Select(s => s.Split('\\')[^1])); + title = CoreTools.Translate("{0} desktop shortcuts created", shortcuts.Count); + message = CoreTools.Translate( + "UniGetUI has detected {0} new desktop shortcuts that can be deleted automatically.", + shortcuts.Count) + "\n" + names; + } + + Show( + title, + message, + MainWindow.RuntimeNotificationLevel.Success, + launchAction: NotificationArguments.Show); + } + catch (Exception ex) + { + Logger.Warn("Could not show new shortcuts notification"); + Logger.Warn(ex); + } + } + + /// + /// Shows a native toast when available, otherwise falls back to the in-app banner. + /// The is encoded into the unigetui:// launch + /// argument so the single-instance handler can route the activation when the toast + /// is clicked. Returns true once the notification has been surfaced (toast or + /// banner), so callers skip their own fallback banner and avoid double-showing. + /// is false for per-operation results: + /// those already live in the operations panel, so we don't duplicate them as a toast. + /// + private static bool Show( + string title, + string message, + MainWindow.RuntimeNotificationLevel level, + string launchAction, + bool allowInAppFallback = true) + { +#if WINDOWS + if (OperatingSystem.IsWindows() && Win32ToastNotifier.IsAvailable()) + { + string launchArg = BuildLaunchArgument(launchAction); + if (Win32ToastNotifier.Show(title, message, launchArg)) + { + // When the app is already running, raise activation immediately so the + // in-process handler fires; a subsequent toast click routes through the + // single-instance redirector on launch via TryParseToastLaunchArgument. + if (MainWindow.Instance is not null) + RaiseActivation(launchAction); + return true; + } + } +#endif + + return allowInAppFallback && ShowInAppBanner(title, message, level); + } + + private static bool ShowInAppBanner( + string title, + string message, + MainWindow.RuntimeNotificationLevel level) + { + var mainWindow = MainWindow.Instance; + if (mainWindow is null) + return false; + + mainWindow.ShowRuntimeNotification(title, message, level); + return true; + } + + private static string BuildLaunchArgument(string action) + => $"unigetui://{action}"; +} diff --git a/src/UniGetUI.Avalonia/Infrastructure/WindowsAvaloniaRenderingPolicy.cs b/src/UniGetUI.Avalonia/Infrastructure/WindowsAvaloniaRenderingPolicy.cs new file mode 100644 index 0000000..f29d3c8 --- /dev/null +++ b/src/UniGetUI.Avalonia/Infrastructure/WindowsAvaloniaRenderingPolicy.cs @@ -0,0 +1,192 @@ +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Runtime.InteropServices; +using System.Runtime.Versioning; +using Avalonia.Controls; +using UniGetUI.Core.Logging; +using CoreSettings = global::UniGetUI.Core.SettingsEngine.Settings; + +namespace UniGetUI.Avalonia.Infrastructure; + +internal static class WindowsAvaloniaRenderingPolicy +{ + private static bool? _hasHardwareGpu; + private static bool? _shouldUseSoftwareRendering; + + public static bool ShouldUseSoftwareRendering + { + get + { + if (_shouldUseSoftwareRendering is not null) + return _shouldUseSoftwareRendering.Value; + + if (!OperatingSystem.IsWindows() || Design.IsDesignMode) + return false; + + if (CoreSettings.Get(CoreSettings.K.DisableAutoSoftwareRenderingOnGpuLessHosts)) + return false; + + _shouldUseSoftwareRendering = !HasHardwareGpu; + if (_shouldUseSoftwareRendering.Value) + { + Logger.Warn( + "No hardware GPU detected. Using Avalonia software rendering and reduced motion."); + } + + return _shouldUseSoftwareRendering.Value; + } + } + + public static bool ShouldReduceMotion => ShouldUseSoftwareRendering; + + [SupportedOSPlatform("windows")] + private static bool HasHardwareGpu + { + get + { + if (_hasHardwareGpu is not null) + return _hasHardwareGpu.Value; + + Stopwatch stopwatch = Stopwatch.StartNew(); + _hasHardwareGpu = DetectHardwareGpu(); + stopwatch.Stop(); + + Logger.Info( + $"DXGI hardware GPU detection took {stopwatch.Elapsed.TotalMilliseconds:F1} ms; hardware GPU: {_hasHardwareGpu.Value}"); + + return _hasHardwareGpu.Value; + } + } + + [SupportedOSPlatform("windows")] + [UnconditionalSuppressMessage("Trimming", "IL2050", + Justification = "The DXGI COM interfaces are declared in full and referenced directly here, so their members are preserved by trimming.")] + private static bool DetectHardwareGpu() + { + try + { + Guid factoryIid = typeof(IDXGIFactory1).GUID; + if (CreateDXGIFactory1(ref factoryIid, out object factoryObj) != HResult.Ok + || factoryObj is not IDXGIFactory1 factory) + { + Logger.Warn("Could not create DXGI factory; assuming a hardware GPU is present."); + return true; + } + + try + { + for (uint i = 0; ; i++) + { + int hr = factory.EnumAdapters1(i, out IDXGIAdapter1 adapter); + if (hr == HResult.DxgiErrorNotFound || hr != HResult.Ok || adapter is null) + break; + + try + { + if (adapter.GetDesc1(out DXGI_ADAPTER_DESC1 desc) != HResult.Ok) + continue; + + bool isSoftwareAdapter = + (desc.Flags & DXGI_ADAPTER_FLAG_SOFTWARE) != 0 + || (desc.VendorId == MicrosoftVendorId + && desc.DeviceId == BasicRenderDriverDeviceId); + + if (!isSoftwareAdapter) + return true; + } + finally + { + Marshal.ReleaseComObject(adapter); + } + } + } + finally + { + Marshal.ReleaseComObject(factory); + } + + return false; + } + catch (Exception ex) + { + Logger.Warn("Could not detect DXGI hardware GPU; assuming one is present."); + Logger.Warn(ex); + return true; + } + } + + [DllImport("dxgi.dll", ExactSpelling = true)] + private static extern int CreateDXGIFactory1( + ref Guid riid, + [MarshalAs(UnmanagedType.IUnknown)] out object ppFactory + ); + + private static class HResult + { + public const int Ok = 0; + public const int DxgiErrorNotFound = unchecked((int)0x887A0002); + } + + private const uint DXGI_ADAPTER_FLAG_SOFTWARE = 2; + + // Microsoft Basic Render Driver (WARP) is enumerated with this VendorId/DeviceId pair. + private const uint MicrosoftVendorId = 0x1414; + private const uint BasicRenderDriverDeviceId = 0x8C; + + [ComImport] + [Guid("770aae78-f26f-4dba-a829-253c83d1b387")] + [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + private interface IDXGIFactory1 + { + void SetPrivateData(); + void SetPrivateDataInterface(); + void GetPrivateData(); + void GetParent(); + void EnumAdapters(); + void MakeWindowAssociation(); + void GetWindowAssociation(); + void CreateSwapChain(); + void CreateSoftwareAdapter(); + + [PreserveSig] + int EnumAdapters1(uint adapter, out IDXGIAdapter1 ppAdapter); + + [PreserveSig] + bool IsCurrent(); + } + + [ComImport] + [Guid("29038f61-3839-4626-91fd-086879011a05")] + [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + private interface IDXGIAdapter1 + { + void SetPrivateData(); + void SetPrivateDataInterface(); + void GetPrivateData(); + void GetParent(); + void EnumOutputs(); + void GetDesc(); + void CheckInterfaceSupport(); + + [PreserveSig] + int GetDesc1(out DXGI_ADAPTER_DESC1 pDesc); + } + + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] + private struct DXGI_ADAPTER_DESC1 + { + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)] + public string Description; + + public uint VendorId; + public uint DeviceId; + public uint SubSysId; + public uint Revision; + public UIntPtr DedicatedVideoMemory; + public UIntPtr DedicatedSystemMemory; + public UIntPtr SharedSystemMemory; + public uint AdapterLuidLowPart; + public int AdapterLuidHighPart; + public uint Flags; + } +} diff --git a/src/UniGetUI.Avalonia/Infrastructure/generate-secrets.ps1 b/src/UniGetUI.Avalonia/Infrastructure/generate-secrets.ps1 new file mode 100644 index 0000000..18d6410 --- /dev/null +++ b/src/UniGetUI.Avalonia/Infrastructure/generate-secrets.ps1 @@ -0,0 +1,37 @@ +param ( + [string]$OutputPath = "obj" +) + +if (-not (Test-Path -Path "Generated Files")) { + New-Item -ItemType Directory -Path "Generated Files" -Force | Out-Null +} + +$generatedDir = [System.IO.Path]::Combine($OutputPath, "Generated Files") +if (-not (Test-Path -Path $generatedDir)) { + New-Item -ItemType Directory -Path $generatedDir -Force | Out-Null +} + +$clientId = $env:UNIGETUI_GITHUB_CLIENT_ID +$clientSecret = $env:UNIGETUI_GITHUB_CLIENT_SECRET +$openSearchUsername = $env:UNIGETUI_OPENSEARCH_USERNAME +$openSearchPassword = $env:UNIGETUI_OPENSEARCH_PASSWORD + +if (-not $clientId) { $clientId = "CLIENT_ID_UNSET" } +if (-not $clientSecret) { $clientSecret = "CLIENT_SECRET_UNSET" } +if (-not $openSearchUsername) { $openSearchUsername = "OPENSEARCH_USERNAME_UNSET" } +if (-not $openSearchPassword) { $openSearchPassword = "OPENSEARCH_PASSWORD_UNSET" } + +@" +// Auto-generated file - do not modify +namespace UniGetUI.Avalonia.Infrastructure +{ + internal static partial class Secrets + { + public static partial string GetGitHubClientId() => `"$clientId`"; + public static partial string GetGitHubClientSecret() => `"$clientSecret`"; + public static partial string GetOpenSearchUsername() => `"$openSearchUsername`"; + public static partial string GetOpenSearchPassword() => `"$openSearchPassword`"; + } +} +"@ | Set-Content -Encoding UTF8 "Generated Files\Secrets.Generated.cs" +Copy-Item "Generated Files\Secrets.Generated.cs" ([System.IO.Path]::Combine($generatedDir, "Secrets.Generated.cs")) diff --git a/src/UniGetUI.Avalonia/Infrastructure/generate-secrets.sh b/src/UniGetUI.Avalonia/Infrastructure/generate-secrets.sh new file mode 100755 index 0000000..76bf51b --- /dev/null +++ b/src/UniGetUI.Avalonia/Infrastructure/generate-secrets.sh @@ -0,0 +1,31 @@ +#!/bin/bash +OUTPUT_PATH="${1:-obj}" + +if [ ! -d "Generated Files" ]; then mkdir -p "Generated Files"; fi +if [ ! -d "${OUTPUT_PATH}Generated Files" ]; then mkdir -p "${OUTPUT_PATH}Generated Files"; fi + +CLIENT_ID="${UNIGETUI_GITHUB_CLIENT_ID}" +CLIENT_SECRET="${UNIGETUI_GITHUB_CLIENT_SECRET}" +OPENSEARCH_USERNAME="${UNIGETUI_OPENSEARCH_USERNAME}" +OPENSEARCH_PASSWORD="${UNIGETUI_OPENSEARCH_PASSWORD}" + +if [ -z "$CLIENT_ID" ]; then CLIENT_ID="CLIENT_ID_UNSET"; fi +if [ -z "$CLIENT_SECRET" ]; then CLIENT_SECRET="CLIENT_SECRET_UNSET"; fi +if [ -z "$OPENSEARCH_USERNAME" ]; then OPENSEARCH_USERNAME="OPENSEARCH_USERNAME_UNSET"; fi +if [ -z "$OPENSEARCH_PASSWORD" ]; then OPENSEARCH_PASSWORD="OPENSEARCH_PASSWORD_UNSET"; fi + +cat > "Generated Files/Secrets.Generated.cs" << CSEOF +// Auto-generated file - do not modify +namespace UniGetUI.Avalonia.Infrastructure +{ + internal static partial class Secrets + { + public static partial string GetGitHubClientId() => "$CLIENT_ID"; + public static partial string GetGitHubClientSecret() => "$CLIENT_SECRET"; + public static partial string GetOpenSearchUsername() => "$OPENSEARCH_USERNAME"; + public static partial string GetOpenSearchPassword() => "$OPENSEARCH_PASSWORD"; + } +} +CSEOF + +cp "Generated Files/Secrets.Generated.cs" "${OUTPUT_PATH}Generated Files/Secrets.Generated.cs" diff --git a/src/UniGetUI.Avalonia/MarkupExtensions/TranslateExtension.cs b/src/UniGetUI.Avalonia/MarkupExtensions/TranslateExtension.cs new file mode 100644 index 0000000..d4efcc9 --- /dev/null +++ b/src/UniGetUI.Avalonia/MarkupExtensions/TranslateExtension.cs @@ -0,0 +1,22 @@ +using Avalonia.Markup.Xaml; +using Avalonia.Metadata; +using UniGetUI.Core.Tools; + +namespace UniGetUI.Avalonia.MarkupExtensions; + +/// +/// Markup extension that translates a string at load time. +/// Usage: Text="{t:Translate Some text}" +/// For strings with commas use named-property form: Text="{t:Translate Text='A, B, C'}" +/// +public class TranslateExtension : MarkupExtension +{ + public TranslateExtension() { } + public TranslateExtension(string text) => Text = text; + + [ConstructorArgument("text")] + public string Text { get; set; } = ""; + + public override object ProvideValue(IServiceProvider serviceProvider) + => CoreTools.Translate(Text); +} diff --git a/src/UniGetUI.Avalonia/Models/PackageCollections.cs b/src/UniGetUI.Avalonia/Models/PackageCollections.cs new file mode 100644 index 0000000..b2220f5 --- /dev/null +++ b/src/UniGetUI.Avalonia/Models/PackageCollections.cs @@ -0,0 +1,507 @@ +using System.Collections.ObjectModel; +using System.ComponentModel; +using System.Net.Http; +using Avalonia; +using Avalonia.Collections; +using Avalonia.Media.Imaging; +using Avalonia.Threading; +using UniGetUI.Avalonia.ViewModels.Pages; +using UniGetUI.Core.Logging; +using UniGetUI.Core.SettingsEngine; +using UniGetUI.Core.Tools; +using UniGetUI.Interface.Enums; +using UniGetUI.PackageEngine.Interfaces; +#if WINDOWS +using UniGetUI.PackageEngine.Managers.WingetManager; +#endif + +// ReSharper disable once CheckNamespace +namespace UniGetUI.PackageEngine.PackageClasses; + +/// +/// Avalonia-compatible package wrapper (replaces the WinUI PackageWrapper that uses Microsoft.UI.Xaml). +/// +public sealed class PackageWrapper : INotifyPropertyChanged, IDisposable +{ + private static readonly HttpClient _iconHttpClient = new(CoreTools.GenericHttpClientParameters) + { + Timeout = TimeSpan.FromSeconds(8), + }; + private static readonly SemaphoreSlim _iconLoadSemaphore = new(8, 8); + + // Cap decoded icon size; the list shows icons at ≤64px (128 covers 2x DPI). + private const int MaxIconSide = 128; + + // Bounded LRU by package hash. Evicted entries aren't disposed: a visible row may still + // reference the bitmap, so dropping it here only makes it GC-eligible. + private const int MaxIconCacheEntries = 512; + private static readonly object _iconCacheLock = new(); + private static readonly Dictionary> _iconCache = new(); + private static readonly LinkedList<(long Hash, Bitmap? Bitmap)> _iconCacheOrder = new(); + + private static bool TryGetCachedIcon(long hash, out Bitmap? bitmap) + { + lock (_iconCacheLock) + { + if (_iconCache.TryGetValue(hash, out var node)) + { + _iconCacheOrder.Remove(node); + _iconCacheOrder.AddFirst(node); + bitmap = node.Value.Bitmap; + return true; + } + } + bitmap = null; + return false; + } + + private static void CacheIcon(long hash, Bitmap? bitmap) + { + lock (_iconCacheLock) + { + if (_iconCache.TryGetValue(hash, out var existing)) + { + existing.Value = (hash, bitmap); + _iconCacheOrder.Remove(existing); + _iconCacheOrder.AddFirst(existing); + return; + } + + var node = new LinkedListNode<(long, Bitmap?)>((hash, bitmap)); + _iconCache[hash] = node; + _iconCacheOrder.AddFirst(node); + + while (_iconCache.Count > MaxIconCacheEntries && _iconCacheOrder.Last is { } last) + { + _iconCacheOrder.RemoveLast(); + _iconCache.Remove(last.Value.Hash); + } + } + } + + public static void ClearIconCache() + { + lock (_iconCacheLock) + { + _iconCache.Clear(); + _iconCacheOrder.Clear(); + } + } + + public IPackage Package { get; } + public PackageWrapper Self => this; + public int Index { get; set; } + + public event PropertyChangedEventHandler? PropertyChanged; + + private readonly PackagesPageViewModel _page; + + private Bitmap? _iconBitmap; + public Bitmap? IconBitmap + { + get => _iconBitmap; + private set + { + _iconBitmap = value; + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(IconBitmap))); + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(HasCustomIcon))); + } + } + public bool HasCustomIcon => _iconBitmap is not null; + + public bool IsChecked + { + get => Package.IsChecked; + set + { + Package.IsChecked = value; + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(IsChecked))); + _page.UpdatePackageCount(); + } + } + + public string VersionComboString { get; } + public string ListedNameTooltip { get; private set; } = ""; + public float ListedOpacity { get; private set; } = 1.0f; + public string TagBackdropIconPath { get; private set; } = ""; + public string TagSymbolIconPath { get; private set; } = ""; + public bool TagIconVisible { get; private set; } + + public bool InstallerHostChanged { get; private set; } + public string InstallerHostChangeTooltip { get; private set; } = ""; + + private CancellationTokenSource? _installerHostCheckCts; + // Cancels this row's queued/in-flight icon load on disposal so it stops rooting the wrapper. + private readonly CancellationTokenSource _lifetimeCts = new(); + + public string SourceIconPath => IconTypeToSvgPath(Package.Source.IconId); + + private static string IconTypeToSvgPath(IconType icon) + { + string name = icon switch + { + IconType.Chocolatey => "choco", + IconType.MsStore => "ms_store", + IconType.LocalPc => "local_pc", + IconType.SaveAs => "save_as", + IconType.SysTray => "sys_tray", + IconType.ClipboardList => "clipboard_list", + IconType.OpenFolder => "open_folder", + IconType.AddTo => "add_to", + _ => icon.ToString().ToLowerInvariant(), + }; + return $"avares://UniGetUI/Assets/Symbols/{name}.svg"; + } + + public PackageWrapper(IPackage package, PackagesPageViewModel page) + { + Package = package; + _page = page; + VersionComboString = package.VersionString; + + Package.PropertyChanged += Package_PropertyChanged; + UpdateDisplayState(); + + // Icons load lazily per visible row (see EnsureIconLoaded), not eagerly for every result. + MaybeStartInstallerHostCheck(); + } + + private int _iconLoadStarted; + + /// Loads this row's icon at most once; called when the row becomes visible. + public void EnsureIconLoaded() + { + if (Settings.Get(Settings.K.DisableIconsOnPackageLists)) return; + if (Interlocked.Exchange(ref _iconLoadStarted, 1) != 0) return; + _ = LoadIconAsync(); + } + + /// + /// For upgradable WinGet packages, asynchronously fetches the installer URL host for + /// both the installed and the new version, and flags the row when the hosts differ. + /// See issue #4617 — defense-in-depth signal that an upgrade may be redirecting the + /// download to a different domain than the user originally trusted. + /// + private void MaybeStartInstallerHostCheck() + { +#if WINDOWS + if (!Package.IsUpgradable) return; + if (Package.Manager is not WinGet) return; + if (Settings.Get(Settings.K.DisableInstallerHostChangeWarning)) return; + + string installedVersion = Package.VersionString; + string newVersion = Package.NewVersionString; + if (string.IsNullOrWhiteSpace(installedVersion) || string.IsNullOrWhiteSpace(newVersion)) + return; + if (installedVersion == newVersion) return; + + _installerHostCheckCts?.Cancel(); + _installerHostCheckCts = new CancellationTokenSource(); + CancellationToken token = _installerHostCheckCts.Token; + + _ = Task.Run(async () => + { + try + { + if (token.IsCancellationRequested) return; + var oldHosts = WinGet.TryGetInstallerHostsForVersion(Package, installedVersion); + if (token.IsCancellationRequested) return; + var newHosts = WinGet.TryGetInstallerHostsForVersion(Package, newVersion); + if (token.IsCancellationRequested) return; + + if (oldHosts is null || newHosts is null) return; + // Only flag when the two host sets are fully disjoint. If they share even + // one host, the publisher hasn't moved hosting — adding/removing CDN mirrors + // or architectures shouldn't trigger the warning. + if (oldHosts.Overlaps(newHosts)) return; + + string tooltip = CoreTools.Translate( + "Installer host changed since the installed version.\n" + + "Old: {0}\n" + + "New: {1}\n\n" + + "This is usually harmless (the publisher moved hosting), " + + "but can also indicate a hijacked package manifest. " + + "Verify the new source before upgrading.", + string.Join(", ", oldHosts), + string.Join(", ", newHosts) + ); + + await Dispatcher.UIThread.InvokeAsync(() => + { + if (token.IsCancellationRequested) return; + InstallerHostChanged = true; + InstallerHostChangeTooltip = tooltip; + PropertyChanged?.Invoke( + this, + new PropertyChangedEventArgs(nameof(InstallerHostChanged)) + ); + PropertyChanged?.Invoke( + this, + new PropertyChangedEventArgs(nameof(InstallerHostChangeTooltip)) + ); + }); + } + catch (Exception ex) + { + Logger.Warn($"Installer-host check failed for {Package.Id}: {ex.Message}"); + } + }, token); +#endif + } + + private async Task LoadIconAsync() + { + CancellationToken token = _lifetimeCts.Token; + long hash = Package.GetHash(); + if (TryGetCachedIcon(hash, out Bitmap? cached)) + { + if (cached is not null) + IconBitmap = cached; + return; + } + + try + { + await _iconLoadSemaphore.WaitAsync(token).ConfigureAwait(false); + Bitmap bitmap; + try + { + var uri = await Task.Run(Package.GetIconUrlIfAny, token).ConfigureAwait(false); + if (uri is null) { CacheIcon(hash, null); return; } + + Bitmap? decoded; + if (uri.IsFile) + { + if (!IsSkiaDecodableExtension(uri.LocalPath)) + { + // Avalonia's Bitmap (Skia) can't decode SVG/AVIF/ICO/TIFF — the + // icon cache may produce those. Reject upfront so we don't throw. + CacheIcon(hash, null); + return; + } + decoded = await Task.Run(() => TryDecodeIcon(uri.LocalPath), token).ConfigureAwait(false); + } + else if (uri.Scheme is "http" or "https") + { + var bytes = await _iconHttpClient.GetByteArrayAsync(uri, token).ConfigureAwait(false); + decoded = TryDecodeIcon(bytes, uri.Host); + } + else { CacheIcon(hash, null); return; } + + if (decoded is null) { CacheIcon(hash, null); return; } + bitmap = decoded; + CacheIcon(hash, bitmap); + } + finally + { + _iconLoadSemaphore.Release(); + } + + if (token.IsCancellationRequested) return; + await Dispatcher.UIThread.InvokeAsync(() => + { + if (!token.IsCancellationRequested) IconBitmap = bitmap; + }); + } + catch (OperationCanceledException) { /* row discarded before its icon finished loading */ } + catch { CacheIcon(hash, null); } + } + + // Icons come from a shared on-disk cache that can hold empty or partial entries after an + // interrupted download; decoding those throws. Skip them quietly instead of surfacing an error. + private static Bitmap? TryDecodeIcon(string filePath) + { + var info = new FileInfo(filePath); + if (!info.Exists || info.Length == 0) return null; + return TryDecodeIcon(() => { using var fs = File.OpenRead(filePath); return DecodeDownscaled(fs); }, filePath); + } + + private static Bitmap? TryDecodeIcon(byte[] bytes, string source) + => bytes.Length == 0 ? null : TryDecodeIcon(() => { using var ms = new MemoryStream(bytes); return DecodeDownscaled(ms); }, source); + + private static Bitmap? TryDecodeIcon(Func decode, string source) + { + try { return decode(); } + catch (Exception ex) { Logger.Debug($"Discarding undecodable icon '{source}': {ex.Message}"); return null; } + } + + // Downscales oversized icons to MaxIconSide; small icons pass through (never upscaled). + private static Bitmap DecodeDownscaled(Stream stream) + { + var bitmap = new Bitmap(stream); + PixelSize size = bitmap.PixelSize; + if (size.Width <= MaxIconSide && size.Height <= MaxIconSide) + return bitmap; + + double scale = (double)MaxIconSide / Math.Max(size.Width, size.Height); + var target = new PixelSize( + Math.Max(1, (int)Math.Round(size.Width * scale)), + Math.Max(1, (int)Math.Round(size.Height * scale))); + + try + { + return bitmap.CreateScaledBitmap(target, BitmapInterpolationMode.HighQuality); + } + finally + { + bitmap.Dispose(); + } + } + + private static bool IsSkiaDecodableExtension(string path) + { + string ext = Path.GetExtension(path); + return ext.Equals(".png", StringComparison.OrdinalIgnoreCase) + || ext.Equals(".jpg", StringComparison.OrdinalIgnoreCase) + || ext.Equals(".jpeg", StringComparison.OrdinalIgnoreCase) + || ext.Equals(".gif", StringComparison.OrdinalIgnoreCase) + || ext.Equals(".bmp", StringComparison.OrdinalIgnoreCase) + || ext.Equals(".webp", StringComparison.OrdinalIgnoreCase); + } + + private void Package_PropertyChanged(object? sender, PropertyChangedEventArgs e) + { + if (e.PropertyName == nameof(Package.Tag)) + { + UpdateDisplayState(); + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(ListedOpacity))); + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(ListedNameTooltip))); + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(TagBackdropIconPath))); + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(TagSymbolIconPath))); + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(TagIconVisible))); + } + else if (e.PropertyName == nameof(Package.IsChecked)) + { + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(IsChecked))); + } + else + { + PropertyChanged?.Invoke(this, e); + } + } + + private void UpdateDisplayState() + { + ListedOpacity = Package.Tag switch + { + PackageTag.OnQueue or PackageTag.BeingProcessed or PackageTag.Unavailable => 0.5f, + _ => 1.0f, + }; + ListedNameTooltip = Package.Name; + + // Match WinUI: an accent-coloured filled disc with the symbol punched out, then the + // symbol drawn on top in the default foreground. OnQueue/Unavailable show no badge. + (string symbol, string backdrop) = Package.Tag switch + { + PackageTag.AlreadyInstalled => ("installed", "installed_filled"), + PackageTag.IsUpgradable => ("upgradable", "upgradable_filled"), + PackageTag.Pinned => ("pin", "pin_filled"), + PackageTag.BeingProcessed => ("loading", "loading_filled"), + PackageTag.Failed => ("warning", "warning_filled"), + _ => ("", ""), + }; + TagIconVisible = symbol.Length > 0; + TagSymbolIconPath = TagIconVisible ? $"avares://UniGetUI/Assets/Symbols/{symbol}.svg" : ""; + TagBackdropIconPath = TagIconVisible ? $"avares://UniGetUI/Assets/Symbols/{backdrop}.svg" : ""; + } + + public void Dispose() + { + Package.PropertyChanged -= Package_PropertyChanged; + _installerHostCheckCts?.Cancel(); + _installerHostCheckCts?.Dispose(); + _installerHostCheckCts = null; + _lifetimeCts.Cancel(); // not disposed: a background load may still hold the token + } +} + +/// +/// Avalonia-compatible observable collection of PackageWrapper with sorting support +/// (replaces WinUI's ObservablePackageCollection that used SortableObservableCollection). +/// +public sealed class ObservablePackageCollection : AvaloniaList +{ + public enum Sorter + { + Checked, + Name, + Id, + Version, + NewVersion, + Source, + } + + public Sorter CurrentSorter { get; private set; } = Sorter.Name; + private bool _ascending = true; + + /// Fires when any wrapper's IsChecked changes, or when items are added/removed. + public event EventHandler? SelectionStateChanged; + + public ObservablePackageCollection() + { + CollectionChanged += OnCollectionChanged; + } + + private void OnCollectionChanged(object? sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) + { + if (e.OldItems is not null) + foreach (PackageWrapper w in e.OldItems) w.PropertyChanged -= OnWrapperPropertyChanged; + if (e.NewItems is not null) + foreach (PackageWrapper w in e.NewItems) w.PropertyChanged += OnWrapperPropertyChanged; + SelectionStateChanged?.Invoke(this, EventArgs.Empty); + } + + private void OnWrapperPropertyChanged(object? sender, PropertyChangedEventArgs e) + { + if (e.PropertyName == nameof(PackageWrapper.IsChecked)) + SelectionStateChanged?.Invoke(this, EventArgs.Empty); + } + + /// Returns the tri-state value for a "select-all" checkbox: true=all, false=none, null=some. + public bool? GetSelectionState() + { + if (Count == 0) return false; + int checkedCount = 0; + foreach (var w in this) if (w.IsChecked) checkedCount++; + if (checkedCount == 0) return false; + if (checkedCount == Count) return true; + return null; + } + + public List GetPackages() => + this.Select(w => w.Package).ToList(); + + public List GetCheckedPackages() => + this.Where(w => w.IsChecked).Select(w => w.Package).ToList(); + + public void SelectAll() + { + foreach (var w in this) w.IsChecked = true; + } + + public void ClearSelection() + { + foreach (var w in this) w.IsChecked = false; + } + + public void SortBy(Sorter sorter) => CurrentSorter = sorter; + + public void SetSortDirection(bool ascending) => _ascending = ascending; + + /// Returns in the current sort order. + public IEnumerable ApplyToList(IEnumerable items) => + _ascending + ? items.OrderBy(GetSortKey, StringComparer.OrdinalIgnoreCase) + : items.OrderByDescending(GetSortKey, StringComparer.OrdinalIgnoreCase); + + private string GetSortKey(PackageWrapper w) => CurrentSorter switch + { + Sorter.Checked => w.IsChecked ? "0" : "1", + Sorter.Name => w.Package.Name, + Sorter.Id => w.Package.Id, + Sorter.Version => w.Package.NormalizedVersion.ToString() ?? string.Empty, + Sorter.NewVersion => w.Package.NormalizedNewVersion.ToString() ?? string.Empty, + Sorter.Source => w.Package.Source.AsString_DisplayName, + _ => w.Package.Name, + }; +} diff --git a/src/UniGetUI.Avalonia/Models/PackagePageMode.cs b/src/UniGetUI.Avalonia/Models/PackagePageMode.cs new file mode 100644 index 0000000..5259a58 --- /dev/null +++ b/src/UniGetUI.Avalonia/Models/PackagePageMode.cs @@ -0,0 +1,9 @@ +namespace UniGetUI.Avalonia.Models; + +public enum PackagePageMode +{ + None, + Discover, + Updates, + Installed, +} diff --git a/src/UniGetUI.Avalonia/Models/PackageRowModel.cs b/src/UniGetUI.Avalonia/Models/PackageRowModel.cs new file mode 100644 index 0000000..e161b0b --- /dev/null +++ b/src/UniGetUI.Avalonia/Models/PackageRowModel.cs @@ -0,0 +1,191 @@ +using System.ComponentModel; +using System.Net.Http; +using System.Runtime.CompilerServices; +using System.Windows.Input; +using Avalonia.Media.Imaging; +using UniGetUI.Avalonia.Infrastructure; +using UniGetUI.Core.SettingsEngine; +using UniGetUI.Core.Tools; +using UniGetUI.Interface.Enums; +using UniGetUI.PackageEngine.Interfaces; + +namespace UniGetUI.Avalonia.Models; + +internal sealed class PackageRowModel : INotifyPropertyChanged, IDisposable +{ + private static readonly HttpClient _iconHttpClient = new(CoreTools.GenericHttpClientParameters) + { + Timeout = TimeSpan.FromSeconds(8), + }; + + private readonly PackagePageMode _pageMode; + private readonly AsyncCommand _primaryActionCommand; + private bool _isSelected; + private bool _isChecked; + private Bitmap? _iconBitmap; + + public PackageRowModel( + IPackage package, + bool showNewVersionColumn, + PackagePageMode pageMode, + Func runPrimaryActionAsync + ) + { + Package = package; + _pageMode = pageMode; + Name = package.Name; + Id = package.Id; + Version = string.IsNullOrWhiteSpace(package.VersionString) ? "-" : package.VersionString; + Status = showNewVersionColumn + ? (string.IsNullOrWhiteSpace(package.NewVersionString) ? "-" : package.NewVersionString) + : package.Manager.DisplayName; + Source = package.Source.AsString_DisplayName; + + _primaryActionCommand = new AsyncCommand( + () => runPrimaryActionAsync(Package), + () => CanExecutePrimaryAction + ); + + Package.PropertyChanged += Package_OnPropertyChanged; + + if (!Settings.Get(Settings.K.DisableIconsOnPackageLists)) + _ = LoadIconAsync(); + } + + public event PropertyChangedEventHandler? PropertyChanged; + + public IPackage Package { get; } + + public string Name { get; } + + public string Id { get; } + + public string Version { get; } + + public string Status { get; } + + public string Source { get; } + + public ICommand PrimaryActionCommand => _primaryActionCommand; + + public Bitmap? IconBitmap + { + get => _iconBitmap; + private set { _iconBitmap = value; OnPropertyChanged(); } + } + + public bool IsSelected + { + get => _isSelected; + set + { + if (_isSelected == value) return; + _isSelected = value; + OnPropertyChanged(); + } + } + + public bool IsChecked + { + get => _isChecked; + set + { + if (_isChecked == value) return; + _isChecked = value; + OnPropertyChanged(); + } + } + + public string PrimaryActionLabel => GetPrimaryActionLabel(); + + public bool CanExecutePrimaryAction => CanExecutePrimaryActionInternal(); + + private void Package_OnPropertyChanged(object? sender, PropertyChangedEventArgs e) + { + if (!string.IsNullOrWhiteSpace(e.PropertyName) && e.PropertyName != nameof(IPackage.Tag)) + { + return; + } + + OnPropertyChanged(nameof(PrimaryActionLabel)); + OnPropertyChanged(nameof(CanExecutePrimaryAction)); + _primaryActionCommand.RaiseCanExecuteChanged(); + } + + private string GetPrimaryActionLabel() + { + return Package.Tag switch + { + PackageTag.OnQueue => CoreTools.Translate("This package is on the queue"), + PackageTag.BeingProcessed => _pageMode switch + { + PackagePageMode.Discover => CoreTools.Translate("installing"), + PackagePageMode.Updates => CoreTools.Translate("updating"), + PackagePageMode.Installed => CoreTools.Translate("uninstalling"), + _ => CoreTools.Translate("Operation in progress"), + }, + PackageTag.AlreadyInstalled when _pageMode == PackagePageMode.Discover => CoreTools.Translate("installed"), + PackageTag.Failed => CoreTools.Translate("Retry"), + _ => _pageMode switch + { + PackagePageMode.Discover => CoreTools.Translate("Install"), + PackagePageMode.Updates => CoreTools.Translate("Update"), + PackagePageMode.Installed => CoreTools.Translate("Uninstall"), + _ => CoreTools.Translate("Open"), + }, + }; + } + + private bool CanExecutePrimaryActionInternal() + { + return _pageMode switch + { + PackagePageMode.Discover => Package.Tag is not PackageTag.AlreadyInstalled + and not PackageTag.OnQueue + and not PackageTag.BeingProcessed + and not PackageTag.Unavailable, + PackagePageMode.Updates => Package.Tag is not PackageTag.OnQueue + and not PackageTag.BeingProcessed + and not PackageTag.Unavailable, + PackagePageMode.Installed => Package.Tag is not PackageTag.OnQueue + and not PackageTag.BeingProcessed + and not PackageTag.Unavailable, + _ => false, + }; + } + + public void Dispose() + { + Package.PropertyChanged -= Package_OnPropertyChanged; + } + + private async Task LoadIconAsync() + { + try + { + var uri = Package.GetIconUrlIfAny(); + if (uri is null) return; + + Bitmap bitmap; + if (uri.IsFile) + { + bitmap = new Bitmap(uri.LocalPath); + } + else if (uri.Scheme is "http" or "https") + { + var bytes = await _iconHttpClient.GetByteArrayAsync(uri); + using var ms = new MemoryStream(bytes); + bitmap = new Bitmap(ms); + } + else return; + + IconBitmap = bitmap; + } + catch { /* ignore — no icon is fine */ } + } + + private void OnPropertyChanged([CallerMemberName] string? propertyName = null) + { + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); + } +} diff --git a/src/UniGetUI.Avalonia/Models/ShellPageType.cs b/src/UniGetUI.Avalonia/Models/ShellPageType.cs new file mode 100644 index 0000000..02e2480 --- /dev/null +++ b/src/UniGetUI.Avalonia/Models/ShellPageType.cs @@ -0,0 +1,13 @@ +namespace UniGetUI.Avalonia.Models; + +internal enum ShellPageType +{ + Discover, + Updates, + Installed, + Bundles, + Settings, + Managers, + Help, + Logs, +} diff --git a/src/UniGetUI.Avalonia/Program.cs b/src/UniGetUI.Avalonia/Program.cs new file mode 100644 index 0000000..7554989 --- /dev/null +++ b/src/UniGetUI.Avalonia/Program.cs @@ -0,0 +1,40 @@ +using System; +using Avalonia; +using UniGetUI.Avalonia.Infrastructure; +using UniGetUI.Core.Data; + +namespace UniGetUI.Avalonia; + +sealed class Program +{ + // 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) + { + // Bail out if the installer is mid-swap (try/catch so the guard never blocks a normal launch). + try + { + if (UpdateInProgressGuard.IsUpdateInProgress()) + { + Environment.ExitCode = 0; + return; + } + } + catch { } + +#if WINDOWS + // Stamp the AUMID onto this process before anything else so the shell attributes + // Action-Center toasts to UniGetUI. Must match the AUMID stamped on the Start Menu + // shortcut by AppShortcutAumidStamper. + Win32ToastNotifier.SetProcessAumid(); +#endif + + AvaloniaAppHost.Run(args); + } + + // Avalonia configuration, don't remove; also used by visual designer. + public static AppBuilder BuildAvaloniaApp() + => AvaloniaAppHost.BuildAvaloniaApp(); +} diff --git a/src/UniGetUI.Avalonia/Properties/PublishProfiles/Win-arm64-NativeAot.pubxml b/src/UniGetUI.Avalonia/Properties/PublishProfiles/Win-arm64-NativeAot.pubxml new file mode 100644 index 0000000..cbdb710 --- /dev/null +++ b/src/UniGetUI.Avalonia/Properties/PublishProfiles/Win-arm64-NativeAot.pubxml @@ -0,0 +1,16 @@ + + + + Release + arm64 + win-arm64 + true + true + false + true + full + false + false + false + + diff --git a/src/UniGetUI.Avalonia/Properties/PublishProfiles/Win-x64-NativeAot.pubxml b/src/UniGetUI.Avalonia/Properties/PublishProfiles/Win-x64-NativeAot.pubxml new file mode 100644 index 0000000..21532d6 --- /dev/null +++ b/src/UniGetUI.Avalonia/Properties/PublishProfiles/Win-x64-NativeAot.pubxml @@ -0,0 +1,16 @@ + + + + Release + x64 + win-x64 + true + true + false + true + full + false + false + false + + diff --git a/src/UniGetUI.Avalonia/Properties/PublishProfiles/linux-arm64-NativeAot.pubxml b/src/UniGetUI.Avalonia/Properties/PublishProfiles/linux-arm64-NativeAot.pubxml new file mode 100644 index 0000000..64b1110 --- /dev/null +++ b/src/UniGetUI.Avalonia/Properties/PublishProfiles/linux-arm64-NativeAot.pubxml @@ -0,0 +1,16 @@ + + + + Release + arm64 + linux-arm64 + true + true + false + true + full + false + false + false + + diff --git a/src/UniGetUI.Avalonia/Properties/PublishProfiles/linux-x64-NativeAot.pubxml b/src/UniGetUI.Avalonia/Properties/PublishProfiles/linux-x64-NativeAot.pubxml new file mode 100644 index 0000000..ed2479d --- /dev/null +++ b/src/UniGetUI.Avalonia/Properties/PublishProfiles/linux-x64-NativeAot.pubxml @@ -0,0 +1,16 @@ + + + + Release + x64 + linux-x64 + true + true + false + true + full + false + false + false + + diff --git a/src/UniGetUI.Avalonia/Properties/PublishProfiles/osx-arm64-NativeAot.pubxml b/src/UniGetUI.Avalonia/Properties/PublishProfiles/osx-arm64-NativeAot.pubxml new file mode 100644 index 0000000..b61e9fc --- /dev/null +++ b/src/UniGetUI.Avalonia/Properties/PublishProfiles/osx-arm64-NativeAot.pubxml @@ -0,0 +1,16 @@ + + + + Release + arm64 + osx-arm64 + true + true + false + true + full + false + false + false + + diff --git a/src/UniGetUI.Avalonia/Properties/PublishProfiles/osx-x64-NativeAot.pubxml b/src/UniGetUI.Avalonia/Properties/PublishProfiles/osx-x64-NativeAot.pubxml new file mode 100644 index 0000000..c80c2c2 --- /dev/null +++ b/src/UniGetUI.Avalonia/Properties/PublishProfiles/osx-x64-NativeAot.pubxml @@ -0,0 +1,16 @@ + + + + Release + x64 + osx-x64 + true + true + false + true + full + false + false + false + + diff --git a/src/UniGetUI.Avalonia/UniGetUI.Avalonia.csproj b/src/UniGetUI.Avalonia/UniGetUI.Avalonia.csproj new file mode 100644 index 0000000..b0875d7 --- /dev/null +++ b/src/UniGetUI.Avalonia/UniGetUI.Avalonia.csproj @@ -0,0 +1,376 @@ + + + + + + + + + + + + $(WindowsTargetFramework) + $(PortableTargetFramework) + + WinExe + UniGetUI.Avalonia + UniGetUI + ..\SharedAssets\icon.ico + true + app.manifest + true + full + false + false + + + + + true + + false + + + + + + + + + + $(NoWarn);MVVMTK0045;AVLN3001 + win-x64;win-arm64 + win-arm64 + win-$(Platform) + win-x64 + + + + $(RuntimeIdentifier) + win-arm64 + win-x64 + $(PkgDevolutions_Pinget_Cli_Rust)\runtimes\$(PingetCliRuntimeIdentifier)\native + $(PingetCliPackageNativePath)\pinget.exe + + + + arm64 + x64 + $(PkgDevolutions_UniGetUI_Elevator)\runtimes\win-$(ElevatorPackageArchitecture)\native + $(ElevatorPackageNativePath)\UniGetUI Elevator.exe + $(ElevatorPackageNativePath)\getfilesiginforedist.dll + + + + + $(MSBuildProjectDirectory)/bin/$(Configuration)/$(TargetFramework)/UniGetUI.app + false + false + $(MacAppBundleDir)/Contents/MacOS/ + + + + + <_MacBundleContents>$(MacAppBundleDir)/Contents + <_MacScriptsDir>$(MSBuildProjectDirectory)/../../scripts/macos + + + + + + + + + + + + $(DefineConstants);AVALONIA_DIAGNOSTICS_ENABLED + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + App.axaml + + + UserAvatarControl.axaml + Code + + + SidebarView.axaml + + + MainWindow.axaml + + + SplashWindow.axaml + + + AbstractPackagesPage.axaml + + + InstallOptionsWindow.axaml + + + InstallOptionsWindow.axaml + Code + + + ManageIgnoredUpdatesWindow.axaml + Code + + + ManageDesktopShortcutsWindow.axaml + Code + + + PackageDetailsWindow.axaml.axaml + Code + + + SettingsBasePage.axaml + Code + + + SettingsHomepage.axaml + Code + + + Notifications.axaml + Code + + + Updates.axaml + Code + + + Operations.axaml + Code + + + Experimental.axaml + Code + + + Administrator.axaml + Code + + + ManagersHomepage.axaml + Code + + + CrashReportWindow.axaml + + + OperationOutputWindow.axaml + + + AboutPage.axaml + + + HelpPage.axaml + Code + + + BaseLogPage.axaml + Code + + + PackageManagerPage.axaml + Code + + + InstallOptionsPanel.axaml + Code + + + SourceManagerCard.axaml + Code + + + BundleSecurityReportDialog.axaml + + + + + + + + + + + + + + + + + + + diff --git a/src/UniGetUI.Avalonia/ViewLocator.cs b/src/UniGetUI.Avalonia/ViewLocator.cs new file mode 100644 index 0000000..7d178d5 --- /dev/null +++ b/src/UniGetUI.Avalonia/ViewLocator.cs @@ -0,0 +1,33 @@ +using Avalonia.Controls; +using Avalonia.Controls.Templates; +using UniGetUI.Avalonia.ViewModels; +using UniGetUI.Avalonia.Views; + +namespace UniGetUI.Avalonia; + +/// +/// Given a view model, returns the corresponding view if possible without reflection. +/// +public class ViewLocator : IDataTemplate +{ + public Control? Build(object? param) + { + if (param is null) + return null; + + if (param is SidebarViewModel sidebar) + { + return new SidebarView + { + DataContext = sidebar, + }; + } + + return new TextBlock { Text = "Not Found: " + param.GetType().Name }; + } + + public bool Match(object? data) + { + return data is SidebarViewModel; + } +} diff --git a/src/UniGetUI.Avalonia/ViewModels/Controls/Settings/SettingsCardViewModel.cs b/src/UniGetUI.Avalonia/ViewModels/Controls/Settings/SettingsCardViewModel.cs new file mode 100644 index 0000000..65b4b47 --- /dev/null +++ b/src/UniGetUI.Avalonia/ViewModels/Controls/Settings/SettingsCardViewModel.cs @@ -0,0 +1 @@ +// Removed — SettingsCard does not use a ViewModel diff --git a/src/UniGetUI.Avalonia/ViewModels/Controls/UserAvatarViewModel.cs b/src/UniGetUI.Avalonia/ViewModels/Controls/UserAvatarViewModel.cs new file mode 100644 index 0000000..5e0eede --- /dev/null +++ b/src/UniGetUI.Avalonia/ViewModels/Controls/UserAvatarViewModel.cs @@ -0,0 +1,176 @@ +using Avalonia.Media.Imaging; +using Avalonia.Threading; +using CommunityToolkit.Mvvm.Input; +using UniGetUI.Avalonia.Infrastructure; +using UniGetUI.Core.Logging; +using UniGetUI.Core.Tools; +using UniGetUI.Interface; +using MvvmRelayCommand = CommunityToolkit.Mvvm.Input.RelayCommand; + +namespace UniGetUI.Avalonia.ViewModels.Controls; + +public class UserAvatarViewModel : ViewModelBase, IDisposable +{ + private readonly CancellationTokenSource _lifetimeCancellation = new(); + private readonly CancellationToken _lifetimeToken; + private int _isDisposed; + private long _refreshGeneration; + + private bool _isAuthenticated; + public bool IsAuthenticated + { + get => _isAuthenticated; + private set => SetProperty(ref _isAuthenticated, value); + } + + private string _userDisplayName = ""; + public string UserDisplayName + { + get => _userDisplayName; + private set => SetProperty(ref _userDisplayName, value); + } + + private Bitmap? _avatarBitmap; + public Bitmap? AvatarBitmap + { + get => _avatarBitmap; + private set => SetProperty(ref _avatarBitmap, value); + } + + public IAsyncRelayCommand LoginCommand { get; } + public IRelayCommand LogoutCommand { get; } + public IRelayCommand MoreDetailsCommand { get; } + + public UserAvatarViewModel() + { + _lifetimeToken = _lifetimeCancellation.Token; + LoginCommand = new AsyncRelayCommand(LoginAsync); + LogoutCommand = new MvvmRelayCommand(Logout); + MoreDetailsCommand = new MvvmRelayCommand(() => CoreTools.Launch("https://devolutions.net/unigetui")); + GitHubAuthService.AuthStatusChanged += OnAuthStatusChanged; + _ = RefreshAsync(); + } + + private bool IsDisposed => Volatile.Read(ref _isDisposed) != 0; + + private bool CanApplyRefresh(long generation) => + !IsDisposed + && !_lifetimeToken.IsCancellationRequested + && generation == Volatile.Read(ref _refreshGeneration); + + private void OnAuthStatusChanged(object? sender, EventArgs e) + { + if (!IsDisposed) + _ = RefreshAsync(); + } + + private async Task RefreshAsync() + { + if (IsDisposed) return; + + long generation = Interlocked.Increment(ref _refreshGeneration); + var service = new GitHubAuthService(); + bool authenticated = GitHubAuthService.IsAuthenticated(); + + string displayName = ""; + Bitmap? bitmap = null; + + if (authenticated) + { + try + { + using var client = GitHubAuthService.CreateGitHubClient(); + if (client is not null) + { + GitHubUser user = await client.GetCurrentUserAsync(); + if (!CanApplyRefresh(generation)) return; + + displayName = string.IsNullOrEmpty(user.Name) + ? $"@{user.Login}" + : $"{user.Name} (@{user.Login})"; + + if (!string.IsNullOrEmpty(user.AvatarUrl)) + { + using var http = new HttpClient(CoreTools.GenericHttpClientParameters); + byte[] bytes = await http.GetByteArrayAsync(user.AvatarUrl, _lifetimeToken); + if (!CanApplyRefresh(generation)) return; + + using var ms = new MemoryStream(bytes); + bitmap = new Bitmap(ms); + } + } + } + catch (OperationCanceledException) when (_lifetimeToken.IsCancellationRequested) + { + return; + } + catch (Exception ex) + { + if (!IsDisposed) + { + Logger.Warn("UserAvatarViewModel: failed to fetch GitHub user info"); + Logger.Warn(ex); + } + authenticated = false; + } + } + + if (!CanApplyRefresh(generation)) + { + bitmap?.Dispose(); + return; + } + + await Dispatcher.UIThread.InvokeAsync(() => + { + if (!CanApplyRefresh(generation)) return; + + IsAuthenticated = authenticated; + UserDisplayName = displayName; + AvatarBitmap = bitmap; + bitmap = null; + }); + + // A queued UI update can become obsolete while it is waiting to run. + bitmap?.Dispose(); + } + + private async Task LoginAsync() + { + try + { + await new GitHubAuthService().SignInAsync(); + } + catch (Exception ex) + { + if (!IsDisposed) + { + Logger.Error("UserAvatarViewModel: login failed"); + Logger.Error(ex); + } + } + } + + private void Logout() + { + try { new GitHubAuthService().SignOut(); } + catch (Exception ex) + { + if (!IsDisposed) + { + Logger.Error("UserAvatarViewModel: logout failed"); + Logger.Error(ex); + } + } + } + + public void Dispose() + { + if (Interlocked.Exchange(ref _isDisposed, 1) != 0) return; + + GitHubAuthService.AuthStatusChanged -= OnAuthStatusChanged; + // In-flight HTTP work can still observe this token. Cancelling is sufficient; + // disposing the source here could race with that work. + _lifetimeCancellation.Cancel(); + } +} diff --git a/src/UniGetUI.Avalonia/ViewModels/DialogPages/InstallOptionsViewModel.cs b/src/UniGetUI.Avalonia/ViewModels/DialogPages/InstallOptionsViewModel.cs new file mode 100644 index 0000000..71c9453 --- /dev/null +++ b/src/UniGetUI.Avalonia/ViewModels/DialogPages/InstallOptionsViewModel.cs @@ -0,0 +1,591 @@ +using System.Collections.ObjectModel; +using System.Net.Http; +using System.Windows.Input; +using Avalonia.Media.Imaging; +using Avalonia.Platform; +using CommunityToolkit.Mvvm.ComponentModel; +using CommunityToolkit.Mvvm.Input; +using UniGetUI.Avalonia.Views; +using UniGetUI.Core.Language; +using UniGetUI.Core.Logging; +using UniGetUI.Core.SettingsEngine; +using UniGetUI.Core.SettingsEngine.SecureSettings; +using UniGetUI.Core.Tools; +using UniGetUI.PackageEngine.Enums; +using UniGetUI.PackageEngine.Interfaces; +using UniGetUI.PackageEngine.PackageClasses; +using UniGetUI.PackageEngine.Serializable; + +namespace UniGetUI.Avalonia.ViewModels; + +public partial class InstallOptionsViewModel : ObservableObject +{ + // ── Public result ────────────────────────────────────────────────────────── + public bool ShouldProceedWithOperation { get; private set; } + public event EventHandler? CloseRequested; + + private readonly IPackage _package; + private readonly InstallOptions _options; + private readonly bool _uiLoaded; + + // ── Translated static labels ─────────────────────────────────────────────── + public string DialogTitle { get; } + public string PlaceholderText { get; } + public string UnlockLabel { get; } = CoreTools.Translate("Change this and unlock"); + public string ProfileLabel { get; } = CoreTools.Translate("Operation profile:"); + public string FollowGlobalLabel { get; } = CoreTools.Translate("Follow the default options when installing, upgrading or uninstalling this package"); + public string ChangeDefaultOptionsLabel { get; } = CoreTools.Translate("Change default options"); + public string GeneralInfoLabel { get; } = CoreTools.Translate("The following settings will be applied each time this package is installed, updated or removed."); + public string VersionLabel { get; } = CoreTools.Translate("Version to install:"); + public string ArchLabel { get; } = CoreTools.Translate("Architecture to install:"); + public string ScopeLabel { get; } = CoreTools.Translate("Installation scope:"); + public string LocationLabel { get; } = CoreTools.Translate("Install location:"); + public string SelectDirLabel { get; } = CoreTools.Translate("Select"); + public string ResetDirLabel { get; } = CoreTools.Translate("Reset"); + public string ParamsInstallLabel { get; } = CoreTools.Translate("Custom install arguments:"); + public string ParamsUpdateLabel { get; } = CoreTools.Translate("Custom update arguments:"); + public string ParamsUninstallLabel { get; } = CoreTools.Translate("Custom uninstall arguments:"); + public string CliArgsHintLabel { get; } = CoreTools.Translate("These fields are independent: an argument set for Install won't apply to Update or Uninstall, and vice versa."); + public string CopyInstallArgsLabel { get; } = CoreTools.Translate("Copy install arguments to update and uninstall"); + public string PreInstallLabel { get; } = CoreTools.Translate("Pre-install command:"); + public string PostInstallLabel { get; } = CoreTools.Translate("Post-install command:"); + public string AbortInstallLabel { get; } = CoreTools.Translate("Abort install if pre-install command fails"); + public string PreUpdateLabel { get; } = CoreTools.Translate("Pre-update command:"); + public string PostUpdateLabel { get; } = CoreTools.Translate("Post-update command:"); + public string AbortUpdateLabel { get; } = CoreTools.Translate("Abort update if pre-update command fails"); + public string PreUninstallLabel { get; } = CoreTools.Translate("Pre-uninstall command:"); + public string PostUninstallLabel { get; } = CoreTools.Translate("Post-uninstall command:"); + public string AbortUninstallLabel { get; } = CoreTools.Translate("Abort uninstall if pre-uninstall command fails"); + public string CommandPreviewLabel { get; } = CoreTools.Translate("Command-line to run:"); + public string SaveLabel { get; } = CoreTools.Translate("Save and close"); + // Tab headers — icon + two text lines, mirroring the WinUI BetterTabViewItem tabs. + public string TabGeneralLine1 { get; } = CoreTools.Translate("General"); + public string TabGeneralLine2 { get; } = CoreTools.Translate("Version"); + public string TabLocationLine1 { get; } = CoreTools.Translate("Architecture"); + public string TabLocationLine2 { get; } = CoreTools.Translate("Location and Scope"); + public string TabCLILine1 { get; } = CoreTools.Translate("Command-line"); + public string TabCLILine2 { get; } = CoreTools.Translate("Arguments"); + public string TabCloseAppsLine1 { get; } = CoreTools.Translate("Close apps"); + public string TabCloseAppsLine2 { get; } = CoreTools.Translate("before installing"); + public string TabPrePostLine1 { get; } = CoreTools.Translate("Pre-install"); + public string TabPrePostLine2 { get; } = CoreTools.Translate("Post-install"); + + // Close-apps tab labels + public string KillProcessesDescriptionLabel { get; } = CoreTools.Translate( + "Select the processes that should be closed before this package is installed, updated or uninstalled."); + public string KillProcessesPlaceholderLabel { get; } = CoreTools.Translate( + "Write here the process names here, separated by commas (,)"); + public string ForceKillLabelText { get; } = CoreTools.Translate( + "Try to kill the processes that refuse to close when requested to"); + + // Checkbox content labels + public string AdminCheckBox_Content { get; } = CoreTools.Translate("Run as admin"); + public string InteractiveCheckBox_Content { get; } = CoreTools.Translate("Interactive installation"); + public string SkipHashCheckBox_Content { get; } = CoreTools.Translate("Skip hash check"); + public string UninstallPrevCheckBox_Content { get; } = CoreTools.Translate("Uninstall previous versions when updated"); + public string SkipMinorCheckBox_Content { get; } = CoreTools.Translate("Skip minor updates for this package"); + public string AutoUpdateCheckBox_Content { get; } = CoreTools.Translate("Automatically update this package"); + public string IgnoreUpdatesCheckBox_Content { get; } = CoreTools.Translate("Ignore future updates for this package"); + + // ── Security-gated sections (CLI args & pre/post commands), mirrors WinUI ── + public bool CliEnabled { get; } + public bool CliDisabledWarningVisible => !CliEnabled; + public bool PrePostEnabled { get; } + public bool PrePostDisabledWarningVisible => !PrePostEnabled; + public string CliDisabledLabel { get; } = CoreTools.Translate("For security reasons, custom command-line arguments are disabled by default. Go to UniGetUI security settings to change this."); + public string PrePostDisabledLabel { get; } = CoreTools.Translate("For security reasons, pre-operation and post-operation scripts are disabled by default. Go to UniGetUI security settings to change this."); + public string PrePostExplainerLabel { get; } = CoreTools.Translate("You can define the commands that will be run before or after this package is installed, updated or uninstalled. They will be run on a command prompt, so CMD scripts will work here."); + public string GoToSecurityLabel { get; } = CoreTools.Translate("Go to UniGetUI security settings"); + + // ── Capability flags (for IsEnabled bindings) ───────────────────────────── + public bool CanRunAsAdmin { get; } + public bool CanRunInteractively { get; } + public bool CanSkipHash { get; } + public bool CanUninstallPrev { get; } + public bool HasCustomScopes { get; } + public bool HasCustomLocations { get; } + + // ── Package icon ─────────────────────────────────────────────────────────── + [ObservableProperty] private Bitmap? _packageIcon; + + // ── Follow-global toggle ─────────────────────────────────────────────────── + [ObservableProperty] private bool _followGlobal; + [ObservableProperty] private bool _isCustomMode; + [ObservableProperty] private double _optionsOpacity = 1.0; + + partial void OnFollowGlobalChanged(bool value) + { + IsCustomMode = !value; + OptionsOpacity = value ? 0.35 : 1.0; + if (_uiLoaded) _ = RefreshCommandPreviewAsync(); + } + + // ── Profile combo ────────────────────────────────────────────────────────── + public ObservableCollection ProfileOptions { get; } = []; + + [ObservableProperty] private string? _selectedProfile; + [ObservableProperty] private string _proceedButtonLabel = ""; + + partial void OnSelectedProfileChanged(string? value) + { + ProceedButtonLabel = value ?? ""; + ApplyProfileEnableState(); + if (_uiLoaded) _ = RefreshCommandPreviewAsync(); + } + + // ── General tab ─────────────────────────────────────────────────────────── + [ObservableProperty] private bool _adminChecked; + [ObservableProperty] private bool _interactiveChecked; + [ObservableProperty] private bool _skipHashChecked; + [ObservableProperty] private bool _skipHashEnabled; + [ObservableProperty] private bool _uninstallPrevChecked; + + [ObservableProperty] private bool _versionEnabled; + public ObservableCollection VersionOptions { get; } = []; + [ObservableProperty] private string? _selectedVersion; + + [ObservableProperty] private bool _skipMinorChecked; + [ObservableProperty] private bool _autoUpdateChecked; + [ObservableProperty] private bool _ignoreUpdatesChecked; + + partial void OnAdminCheckedChanged(bool value) => Refresh(); + partial void OnInteractiveCheckedChanged(bool value) => Refresh(); + partial void OnSkipHashCheckedChanged(bool value) => Refresh(); + partial void OnSelectedVersionChanged(string? value) => Refresh(); + + // ── Architecture / Scope / Location tab ─────────────────────────────────── + [ObservableProperty] private bool _archEnabled; + public ObservableCollection ArchOptions { get; } = []; + [ObservableProperty] private string? _selectedArch; + + [ObservableProperty] private bool _scopeEnabled; + public ObservableCollection ScopeOptions { get; } = []; + [ObservableProperty] private string? _selectedScope; + + [ObservableProperty] private string _locationText = ""; + [ObservableProperty] private bool _locationEnabled; + + partial void OnSelectedArchChanged(string? value) => Refresh(); + partial void OnSelectedScopeChanged(string? value) => Refresh(); + + // ── CLI params tab ──────────────────────────────────────────────────────── + [ObservableProperty] private string _paramsInstall = ""; + [ObservableProperty] private string _paramsUpdate = ""; + [ObservableProperty] private string _paramsUninstall = ""; + + partial void OnParamsInstallChanged(string value) => Refresh(); + partial void OnParamsUpdateChanged(string value) => Refresh(); + partial void OnParamsUninstallChanged(string value) => Refresh(); + + // ── Pre/Post commands tab ───────────────────────────────────────────────── + [ObservableProperty] private string _preInstallText = ""; + [ObservableProperty] private string _postInstallText = ""; + [ObservableProperty] private bool _abortInstall; + + [ObservableProperty] private string _preUpdateText = ""; + [ObservableProperty] private string _postUpdateText = ""; + [ObservableProperty] private bool _abortUpdate; + + [ObservableProperty] private string _preUninstallText = ""; + [ObservableProperty] private string _postUninstallText = ""; + [ObservableProperty] private bool _abortUninstall; + + // ── Close apps tab ──────────────────────────────────────────────────────── + public ObservableCollection KillProcessEntries { get; } = []; + + [ObservableProperty] private string _killProcessNewEntry = ""; + [ObservableProperty] private bool _forceKillChecked; + + [RelayCommand] + private void AddKillProcess() + { + var name = KillProcessNewEntry.Trim(); + if (string.IsNullOrEmpty(name)) return; + if (!KillProcessEntries.Any(e => e.Name.Equals(name, StringComparison.OrdinalIgnoreCase))) + KillProcessEntries.Add(new KillProcessEntry(name, e => KillProcessEntries.Remove(e))); + KillProcessNewEntry = ""; + } + + // ── Command preview ─────────────────────────────────────────────────────── + [ObservableProperty] private string _commandPreview = ""; + + // ── Constructor ─────────────────────────────────────────────────────────── + public InstallOptionsViewModel(IPackage package, OperationType operation, InstallOptions options) + { + _package = package; + _options = options; + var caps = package.Manager.Capabilities; + + DialogTitle = CoreTools.Translate("{0} installation options", package.Name); + PlaceholderText = CoreTools.Translate( + "{0} Install options are currently locked because {0} follows the default install options.", + package.Name); + + // Capability flags + CanRunAsAdmin = OperatingSystem.IsWindows() && caps.CanRunAsAdmin; + CanRunInteractively = caps.CanRunInteractively; + CanSkipHash = caps.CanSkipIntegrityChecks; + CanUninstallPrev = caps.CanUninstallPreviousVersionsAfterUpdate; + HasCustomScopes = caps.SupportsCustomScopes; + HasCustomLocations = caps.SupportsCustomLocations; + + // Security-gated sections (disabled by default; toggled in security settings) + CliEnabled = SecureSettings.Get(SecureSettings.K.AllowCLIArguments); + PrePostEnabled = SecureSettings.Get(SecureSettings.K.AllowPrePostOpCommand); + + // Profile + string installLabel = CoreTools.Translate("Install"); + string updateLabel = CoreTools.Translate("Update"); + string uninstallLabel = CoreTools.Translate("Uninstall"); + ProfileOptions.Add(installLabel); + ProfileOptions.Add(updateLabel); + ProfileOptions.Add(uninstallLabel); + SelectedProfile = operation switch + { + OperationType.Update => updateLabel, + OperationType.Uninstall => uninstallLabel, + _ => installLabel, + }; + ProceedButtonLabel = SelectedProfile; + + // Follow-global + FollowGlobal = !options.OverridesNextLevelOpts; + IsCustomMode = options.OverridesNextLevelOpts; + OptionsOpacity = options.OverridesNextLevelOpts ? 1.0 : 0.35; + + // General checkboxes + AdminChecked = options.RunAsAdministrator; + InteractiveChecked = options.InteractiveInstallation; + SkipHashChecked = options.SkipHashCheck; + SkipHashEnabled = caps.CanSkipIntegrityChecks; + UninstallPrevChecked = options.UninstallPreviousVersionsOnUpdate; + SkipMinorChecked = options.SkipMinorUpdates; + AutoUpdateChecked = options.AutoUpdatePackage; + + // Version + VersionOptions.Add(CoreTools.Translate("Latest")); + if (caps.SupportsPreRelease) + VersionOptions.Add(CoreTools.Translate("PreRelease")); + SelectedVersion = options.PreRelease + ? CoreTools.Translate("PreRelease") + : CoreTools.Translate("Latest"); + VersionEnabled = caps.SupportsCustomVersions || caps.SupportsPreRelease; + + // Architecture + string defaultLabel = CoreTools.Translate("Default"); + ArchOptions.Add(defaultLabel); + SelectedArch = defaultLabel; + if (caps.SupportsCustomArchitectures) + { + foreach (var arch in caps.SupportedCustomArchitectures) + { + ArchOptions.Add(arch); + if (options.Architecture == arch) SelectedArch = arch; + } + } + ArchEnabled = caps.SupportsCustomArchitectures; + + // Scope + ScopeOptions.Add(CoreTools.Translate("Default")); + SelectedScope = CoreTools.Translate("Default"); + if (caps.SupportsCustomScopes) + { + string localName = CoreTools.Translate(CommonTranslations.ScopeNames[PackageScope.Local]); + string globalName = CoreTools.Translate(CommonTranslations.ScopeNames[PackageScope.Global]); + ScopeOptions.Add(localName); + ScopeOptions.Add(globalName); + if (options.InstallationScope == "Local") SelectedScope = localName; + if (options.InstallationScope == "Global") SelectedScope = globalName; + } + ScopeEnabled = caps.SupportsCustomScopes; + + // Location + LocationText = options.CustomInstallLocation; + LocationEnabled = caps.SupportsCustomLocations; + + // CLI params + ParamsInstall = string.Join(' ', options.CustomParameters_Install); + ParamsUpdate = string.Join(' ', options.CustomParameters_Update); + ParamsUninstall = string.Join(' ', options.CustomParameters_Uninstall); + + // Pre/Post commands + PreInstallText = options.PreInstallCommand; + PostInstallText = options.PostInstallCommand; + AbortInstall = options.AbortOnPreInstallFail; + PreUpdateText = options.PreUpdateCommand; + PostUpdateText = options.PostUpdateCommand; + AbortUpdate = options.AbortOnPreUpdateFail; + PreUninstallText = options.PreUninstallCommand; + PostUninstallText = options.PostUninstallCommand; + AbortUninstall = options.AbortOnPreUninstallFail; + + // Close apps + foreach (var proc in options.KillBeforeOperation) + KillProcessEntries.Add(new KillProcessEntry(proc, e => KillProcessEntries.Remove(e))); + ForceKillChecked = Settings.Get(Settings.K.KillProcessesThatRefuseToDie); + + // Show fallback immediately, then replace with real icon if available + using var fallback = AssetLoader.Open(_fallbackIconUri); + PackageIcon = new Bitmap(fallback); + _ = LoadIconAsync(); + + if (caps.SupportsCustomVersions) + _ = LoadVersionsAsync(options.Version); + + _ = LoadIgnoredUpdatesAsync(); + + _uiLoaded = true; + // Apply the operation-dependent enable gates for the initial operation, matching + // WinUI's EnableDisableControls (which runs on load): e.g. Skip-hash/Architecture are + // disabled for Uninstall, Version is enabled only for Install. + ApplyProfileEnableState(); + _ = RefreshCommandPreviewAsync(); + } + + // ── Commands ────────────────────────────────────────────────────────────── + + /// Captures the current UI state into the options object without closing. + public void ApplyChanges() => ApplyToOptions(); + + [RelayCommand] + private void Save() + { + ApplyToOptions(); + CloseRequested?.Invoke(this, EventArgs.Empty); + } + + [RelayCommand] + private void Proceed() + { + ApplyToOptions(); + ShouldProceedWithOperation = true; + CloseRequested?.Invoke(this, EventArgs.Empty); + } + + [RelayCommand] + private void ResetLocation() => LocationText = ""; + + [RelayCommand] + private void CopyInstallArgsToOthers() + { + ParamsUpdate = ParamsInstall; + ParamsUninstall = ParamsInstall; + } + + /// Unlocks the options by turning off "follow default options" (matches WinUI). + [RelayCommand] + private void Unlock() => FollowGlobal = false; + + /// Closes the dialog and opens the manager's default-options settings (matches WinUI). + [RelayCommand] + private void ChangeDefaultOptions() + { + CloseRequested?.Invoke(this, EventArgs.Empty); + if (MainWindow.Instance?.DataContext is MainWindowViewModel vm) + vm.OpenManagerSettings(_package.Manager); + } + + /// Closes the dialog and opens the security settings page (matches WinUI). + [RelayCommand] + private void GoToSecuritySettings() + { + CloseRequested?.Invoke(this, EventArgs.Empty); + if (MainWindow.Instance?.DataContext is MainWindowViewModel vm) + vm.OpenSettingsPage(typeof(Views.Pages.SettingsPages.Administrator)); + } + + // ── Ignore-future-updates state (package-level, like WinUI) ──────────────── + private async Task LoadIgnoredUpdatesAsync() + { + try { IgnoreUpdatesChecked = await _package.HasUpdatesIgnoredAsync(); } + catch (Exception ex) { Logger.Warn($"[InstallOptionsViewModel] Failed to read ignored-updates state: {ex.Message}"); } + } + + private async Task ApplyIgnoredUpdatesAsync() + { + try + { + if (IgnoreUpdatesChecked) + await _package.AddToIgnoredUpdatesAsync("*"); + else if (await _package.GetIgnoredUpdatesVersionAsync() == "*") + await _package.RemoveFromIgnoredUpdatesAsync(); + } + catch (Exception ex) { Logger.Warn($"[InstallOptionsViewModel] Failed to apply ignored-updates state: {ex.Message}"); } + } + + // ── Enable/disable based on selected operation profile ──────────────────── + private void ApplyProfileEnableState() + { + if (!_uiLoaded) return; + var op = CurrentOp(); + var caps = _package.Manager.Capabilities; + + SkipHashEnabled = op is not OperationType.Uninstall && caps.CanSkipIntegrityChecks; + ArchEnabled = op is not OperationType.Uninstall && caps.SupportsCustomArchitectures; + VersionEnabled = op is OperationType.Install && (caps.SupportsCustomVersions || caps.SupportsPreRelease); + } + + // ── Live command preview ────────────────────────────────────────────────── + private async Task RefreshCommandPreviewAsync() + { + if (!_uiLoaded) return; + var snap = SnapshotOptions(); + var op = CurrentOp(); + var applied = await InstallOptionsFactory.LoadApplicableAsync(_package, overridePackageOptions: snap); + var args = await Task.Run(() => _package.Manager.OperationHelper.GetParameters(_package, applied, op)); + CommandPreview = _package.Manager.Properties.ExecutableFriendlyName + " " + string.Join(' ', args); + } + + private void Refresh() { if (_uiLoaded) _ = RefreshCommandPreviewAsync(); } + + // ── Package icon ────────────────────────────────────────────────────────── + private static readonly HttpClient _iconHttp = new(CoreTools.GenericHttpClientParameters); + + private static readonly Uri _fallbackIconUri = + new("avares://UniGetUI/Assets/package_color.png"); + + private async Task LoadIconAsync() + { + try + { + var uri = await Task.Run(_package.GetIconUrlIfAny); + if (uri is null) return; + + Bitmap bmp; + if (uri.IsFile) + bmp = new Bitmap(uri.LocalPath); + else if (uri.Scheme is "http" or "https") + { + var bytes = await _iconHttp.GetByteArrayAsync(uri); + using var ms = new MemoryStream(bytes); + bmp = new Bitmap(ms); + } + else return; + + PackageIcon = bmp; + } + catch (Exception ex) { Logger.Warn($"[InstallOptionsViewModel] Failed to load icon for {_package.Id}: {ex.Message}"); } + } + + // ── Async version loader ────────────────────────────────────────────────── + private async Task LoadVersionsAsync(string selectedVersion) + { + VersionEnabled = false; + var versions = await Task.Run(() => _package.Manager.DetailsHelper.GetVersions(_package)); + foreach (var ver in versions) + { + VersionOptions.Add(ver); + if (selectedVersion == ver) + SelectedVersion = ver; + } + var op = CurrentOp(); + VersionEnabled = op is OperationType.Install && + (_package.Manager.Capabilities.SupportsCustomVersions || + _package.Manager.Capabilities.SupportsPreRelease); + } + + // ── Snapshot & apply ────────────────────────────────────────────────────── + private OperationType CurrentOp() => SelectedProfile switch + { + var s when s == CoreTools.Translate("Update") => OperationType.Update, + var s when s == CoreTools.Translate("Uninstall") => OperationType.Uninstall, + _ => OperationType.Install, + }; + + private InstallOptions SnapshotOptions() + { + var o = new InstallOptions(); + o.RunAsAdministrator = AdminChecked; + o.InteractiveInstallation = InteractiveChecked; + o.SkipHashCheck = SkipHashChecked; + o.UninstallPreviousVersionsOnUpdate = UninstallPrevChecked; + o.AutoUpdatePackage = AutoUpdateChecked; + o.SkipMinorUpdates = SkipMinorChecked; + o.OverridesNextLevelOpts = !FollowGlobal; + + var ver = SelectedVersion ?? ""; + o.PreRelease = ver == CoreTools.Translate("PreRelease"); + o.Version = (ver != CoreTools.Translate("Latest") && ver != CoreTools.Translate("PreRelease") && ver.Length > 0) ? ver : ""; + + string defaultLabel = CoreTools.Translate("Default"); + o.Architecture = (SelectedArch != defaultLabel && SelectedArch is not null) ? SelectedArch : ""; + o.InstallationScope = ScopeToString(SelectedScope); + + o.CustomInstallLocation = LocationText; + o.CustomParameters_Install = Split(ParamsInstall); + o.CustomParameters_Update = Split(ParamsUpdate); + o.CustomParameters_Uninstall = Split(ParamsUninstall); + o.PreInstallCommand = PreInstallText; + o.PostInstallCommand = PostInstallText; + o.AbortOnPreInstallFail = AbortInstall; + o.PreUpdateCommand = PreUpdateText; + o.PostUpdateCommand = PostUpdateText; + o.AbortOnPreUpdateFail = AbortUpdate; + o.PreUninstallCommand = PreUninstallText; + o.PostUninstallCommand = PostUninstallText; + o.AbortOnPreUninstallFail = AbortUninstall; + return o; + } + + private void ApplyToOptions() + { + var s = SnapshotOptions(); + _options.RunAsAdministrator = s.RunAsAdministrator; + _options.InteractiveInstallation = s.InteractiveInstallation; + _options.SkipHashCheck = s.SkipHashCheck; + _options.UninstallPreviousVersionsOnUpdate = s.UninstallPreviousVersionsOnUpdate; + _options.AutoUpdatePackage = s.AutoUpdatePackage; + _options.SkipMinorUpdates = s.SkipMinorUpdates; + _options.OverridesNextLevelOpts = s.OverridesNextLevelOpts; + _options.PreRelease = s.PreRelease; + _options.Version = s.Version; + _options.Architecture = s.Architecture; + _options.InstallationScope = s.InstallationScope; + _options.CustomInstallLocation = s.CustomInstallLocation; + _options.CustomParameters_Install = s.CustomParameters_Install; + _options.CustomParameters_Update = s.CustomParameters_Update; + _options.CustomParameters_Uninstall = s.CustomParameters_Uninstall; + _options.PreInstallCommand = s.PreInstallCommand; + _options.PostInstallCommand = s.PostInstallCommand; + _options.AbortOnPreInstallFail = s.AbortOnPreInstallFail; + _options.PreUpdateCommand = s.PreUpdateCommand; + _options.PostUpdateCommand = s.PostUpdateCommand; + _options.AbortOnPreUpdateFail = s.AbortOnPreUpdateFail; + _options.PreUninstallCommand = s.PreUninstallCommand; + _options.PostUninstallCommand = s.PostUninstallCommand; + _options.AbortOnPreUninstallFail = s.AbortOnPreUninstallFail; + _options.KillBeforeOperation = KillProcessEntries.Select(e => e.Name).ToList(); + Settings.Set(Settings.K.KillProcessesThatRefuseToDie, ForceKillChecked); + _ = ApplyIgnoredUpdatesAsync(); + } + + private static string ScopeToString(string? selected) + { + if (selected == CoreTools.Translate(CommonTranslations.ScopeNames[PackageScope.Local])) return "Local"; + if (selected == CoreTools.Translate(CommonTranslations.ScopeNames[PackageScope.Global])) return "Global"; + return ""; + } + + private static List Split(string text) + => text.Split(' ', StringSplitOptions.RemoveEmptyEntries).ToList(); +} + +/// A single entry in the "close apps before installing" list. +public sealed class KillProcessEntry +{ + public string Name { get; } + public ICommand RemoveCommand { get; } + + public KillProcessEntry(string name, Action remove) + { + Name = name; + RemoveCommand = new SyncCommand(() => remove(this)); + } + + private sealed class SyncCommand(Action action) : ICommand + { + public event EventHandler? CanExecuteChanged { add { } remove { } } + public bool CanExecute(object? _) => true; + public void Execute(object? _) => action(); + } +} diff --git a/src/UniGetUI.Avalonia/ViewModels/DialogPages/ManageDesktopShortcutsViewModel.cs b/src/UniGetUI.Avalonia/ViewModels/DialogPages/ManageDesktopShortcutsViewModel.cs new file mode 100644 index 0000000..9ff34fa --- /dev/null +++ b/src/UniGetUI.Avalonia/ViewModels/DialogPages/ManageDesktopShortcutsViewModel.cs @@ -0,0 +1,106 @@ +using System.Collections.ObjectModel; +using CommunityToolkit.Mvvm.ComponentModel; +using CommunityToolkit.Mvvm.Input; +using UniGetUI.Core.Tools; +using UniGetUI.PackageEngine.Classes.Packages.Classes; +using CoreSettings = UniGetUI.Core.SettingsEngine.Settings; + +namespace UniGetUI.Avalonia.ViewModels; + +public partial class ManageDesktopShortcutsViewModel : ObservableObject +{ + public event EventHandler? CloseRequested; + + public ObservableCollection Entries { get; } = []; + + [ObservableProperty] + private bool _autoDelete; + + partial void OnAutoDeleteChanged(bool value) => + CoreSettings.Set(CoreSettings.K.RemoveAllDesktopShortcuts, value); + + public ManageDesktopShortcutsViewModel(IReadOnlyList? shortcuts = null) + { + _autoDelete = CoreSettings.Get(CoreSettings.K.RemoveAllDesktopShortcuts); + LoadEntries(shortcuts ?? DesktopShortcutsDatabase.GetAllShortcuts()); + } + + private void LoadEntries(IReadOnlyList shortcuts) + { + Entries.Clear(); + foreach (var path in shortcuts.OrderBy(Path.GetFileName)) + { + var entry = new ShortcutEntryViewModel(path); + entry.Removed += OnEntryRemoved; + Entries.Add(entry); + } + } + + private void OnEntryRemoved(object? sender, EventArgs e) + { + if (sender is ShortcutEntryViewModel entry) + Entries.Remove(entry); + } + + [RelayCommand] + private void ResetAll() + { + foreach (var entry in Entries.ToList()) + entry.Reset(); + } + + public void SaveChanges() + { + foreach (var entry in Entries) + { + DesktopShortcutsDatabase.AddToDatabase( + entry.Path, + entry.IsDeletable + ? DesktopShortcutsDatabase.Status.Delete + : DesktopShortcutsDatabase.Status.Maintain); + DesktopShortcutsDatabase.RemoveFromUnknownShortcuts(entry.Path); + + if (entry.IsDeletable && File.Exists(entry.Path)) + DesktopShortcutsDatabase.DeleteFromDisk(entry.Path); + } + } + + [RelayCommand] + public void SaveAndClose() + { + SaveChanges(); + CloseRequested?.Invoke(this, EventArgs.Empty); + } +} + +public partial class ShortcutEntryViewModel : ObservableObject +{ + public event EventHandler? Removed; + + public string Path { get; } + public string Name { get; } + public bool ExistsOnDisk => File.Exists(Path); + + [ObservableProperty] + private bool _isDeletable; + + public ShortcutEntryViewModel(string path) + { + Path = path; + var filename = System.IO.Path.GetFileName(path); + Name = string.Join('.', filename.Split('.')[..^1]); + IsDeletable = DesktopShortcutsDatabase.GetStatus(path) is DesktopShortcutsDatabase.Status.Delete; + } + + [RelayCommand] + public void Open() => _ = CoreTools.ShowFileOnExplorer(Path); + + public void Reset() + { + DesktopShortcutsDatabase.AddToDatabase(Path, DesktopShortcutsDatabase.Status.Unknown); + Removed?.Invoke(this, EventArgs.Empty); + } + + [RelayCommand] + public void Remove() => Reset(); +} diff --git a/src/UniGetUI.Avalonia/ViewModels/DialogPages/ManageIgnoredUpdatesViewModel.cs b/src/UniGetUI.Avalonia/ViewModels/DialogPages/ManageIgnoredUpdatesViewModel.cs new file mode 100644 index 0000000..78ac769 --- /dev/null +++ b/src/UniGetUI.Avalonia/ViewModels/DialogPages/ManageIgnoredUpdatesViewModel.cs @@ -0,0 +1,199 @@ +using System.Collections.ObjectModel; +using CommunityToolkit.Mvvm.ComponentModel; +using CommunityToolkit.Mvvm.Input; +using UniGetUI.Core.Tools; +using UniGetUI.Interface.Enums; +using UniGetUI.PackageEngine; +using UniGetUI.PackageEngine.Classes.Packages.Classes; +using UniGetUI.PackageEngine.PackageLoader; + +namespace UniGetUI.Avalonia.ViewModels; + +public partial class ManageIgnoredUpdatesViewModel : ObservableObject +{ + public event EventHandler? CloseRequested; + + public string Title { get; } = CoreTools.Translate("Manage ignored updates"); + public string Description { get; } = CoreTools.Translate("The packages listed here won't be taken in account when checking for updates. Double-click them or click the button on their right to stop ignoring their updates."); + public string ResetLabel { get; } = CoreTools.Translate("Reset list"); + public string ResetConfirm { get; } = CoreTools.Translate("Do you really want to reset the ignored updates list? This action cannot be reverted"); + public string ResetYes { get; } = CoreTools.Translate("Yes"); + public string ResetNo { get; } = CoreTools.Translate("No"); + public string EmptyLabel { get; } = CoreTools.Translate("No ignored updates"); + public string ColName { get; } = CoreTools.Translate("Package Name"); + public string ColId { get; } = CoreTools.Translate("Package ID"); + public string ColVersion { get; } = CoreTools.Translate("Ignored version"); + public string ColNewVersion { get; } = CoreTools.Translate("New version"); + public string ColManager { get; } = CoreTools.Translate("Source"); + + public ObservableCollection Entries { get; } = []; + + [ObservableProperty] + [NotifyPropertyChangedFor(nameof(ShowEmptyLabel))] + private bool _hasEntries; + + public bool ShowEmptyLabel => !HasEntries; + + public ManageIgnoredUpdatesViewModel() + { + LoadEntries(); + } + + private void LoadEntries() + { + Entries.Clear(); + + var db = IgnoredUpdatesDatabase.GetDatabase(); + var managerMap = PEInterface.Managers + .ToDictionary(m => m.Properties.Name.ToLower(), m => m); + + foreach (var (ignoredId, version) in db.OrderBy(x => x.Key)) + { + var parts = ignoredId.Split('\\'); + var managerKey = parts[0]; + var packageId = parts.Length > 1 ? parts[^1] : ignoredId; + + string managerDisplay = managerMap.TryGetValue(managerKey, out var mgr) + ? mgr.DisplayName + : managerKey; + string managerIconPath = ResolveManagerIcon(managerKey); + string packageName = CoreTools.FormatAsName(packageId); + + string versionDisplay = version == "*" + ? CoreTools.Translate("All versions") + : version; + + // Compute the "new version" column like WinUI does + string currentVersion = + InstalledPackagesLoader.Instance.GetPackageForId(packageId)?.VersionString + ?? CoreTools.Translate("Unknown"); + + string newVersion; + if (UpgradablePackagesLoader.Instance.IgnoredPackages + .TryGetValue(packageId, out var upgradable) + && upgradable.NewVersionString != upgradable.VersionString) + { + newVersion = currentVersion + " \u27a4 " + upgradable.NewVersionString; + } + else if (currentVersion != CoreTools.Translate("Unknown")) + { + newVersion = CoreTools.Translate("Up to date") + $" ({currentVersion})"; + } + else + { + newVersion = CoreTools.Translate("Unknown"); + } + + var entry = new IgnoredPackageEntryViewModel( + ignoredId, packageId, packageName, managerDisplay, + managerIconPath, versionDisplay, newVersion); + entry.Removed += OnEntryRemoved; + Entries.Add(entry); + } + + HasEntries = Entries.Count > 0; + } + + private void OnEntryRemoved(object? sender, EventArgs e) + { + if (sender is IgnoredPackageEntryViewModel entry) + Entries.Remove(entry); + HasEntries = Entries.Count > 0; + } + + [RelayCommand] + private async Task ResetAll() + { + foreach (var entry in Entries.ToList()) + await entry.RemoveAsync(); + } + + private static string ResolveManagerIcon(string managerKey) + { + string name = managerKey switch + { + "winget" => "winget", + "scoop" => "scoop", + "chocolatey" => "choco", + "dotnet" => "dotnet", + "npm" => "node", + "pip" => "python", + "powershell" => "powershell", + "cargo" => "rust", + "vcpkg" => "vcpkg", + "steam" => "steam", + "gog" => "gog", + "uplay" => "uplay", + "apt" => "apt", + "dnf" => "dnf", + "pacman" => "pacman", + _ => "ms_store", + }; + return $"avares://UniGetUI/Assets/Symbols/{name}.svg"; + } +} + +public partial class IgnoredPackageEntryViewModel : ObservableObject +{ + public event EventHandler? Removed; + + public string Id { get; } + public string Name { get; } + public string Manager { get; } + public string ManagerIconPath { get; } + public string VersionDisplay { get; } + public string NewVersion { get; } + public string AutomationName { get; } + public string RemoveAutomationName { get; } + + private readonly string _ignoredId; + + public IgnoredPackageEntryViewModel( + string ignoredId, string id, string name, + string manager, string managerIconPath, + string versionDisplay, string newVersion) + { + _ignoredId = ignoredId; + Id = id; + Name = name; + Manager = manager; + ManagerIconPath = managerIconPath; + VersionDisplay = versionDisplay; + NewVersion = newVersion; + AutomationName = CoreTools.Translate("Package {name} from {manager}") + .Replace("{name}", Name) + .Replace("{manager}", Manager); + RemoveAutomationName = CoreTools.Translate("Remove {0} from ignored updates", Name); + } + + [RelayCommand] + public async Task Remove() => await RemoveAsync(); + + public async Task RemoveAsync() + { + await Task.Run(() => IgnoredUpdatesDatabase.Remove(_ignoredId)); + await RestoreToUpdatesAsync(); + Removed?.Invoke(this, EventArgs.Empty); + } + + private async Task RestoreToUpdatesAsync() + { + var parts = _ignoredId.Split('\\'); + var packageId = parts.Length > 1 ? parts[^1] : _ignoredId; + + if (UpgradablePackagesLoader.Instance.IgnoredPackages.TryRemove(packageId, out var pkg) + && pkg.NewVersionString != pkg.VersionString) + { + await UpgradablePackagesLoader.Instance.AddForeign(pkg); + } + + foreach (var installed in InstalledPackagesLoader.Instance.Packages) + { + if (installed.Id == packageId) + { + installed.SetTag(PackageTag.Default); + break; + } + } + } +} diff --git a/src/UniGetUI.Avalonia/ViewModels/DialogPages/OperationOutputViewModel.cs b/src/UniGetUI.Avalonia/ViewModels/DialogPages/OperationOutputViewModel.cs new file mode 100644 index 0000000..6263415 --- /dev/null +++ b/src/UniGetUI.Avalonia/ViewModels/DialogPages/OperationOutputViewModel.cs @@ -0,0 +1,79 @@ +using System.Collections.ObjectModel; +using Avalonia; +using Avalonia.Media; +using Avalonia.Styling; +using Avalonia.Threading; +using CommunityToolkit.Mvvm.ComponentModel; +using UniGetUI.Avalonia.ViewModels.Pages.LogPages; +using UniGetUI.PackageOperations; + +namespace UniGetUI.Avalonia.ViewModels.DialogPages; + +public partial class OperationOutputViewModel : ObservableObject +{ + [ObservableProperty] private string _title = ""; + public ObservableCollection OutputLines { get; } = new(); + + private IBrush _errorBrush = Brushes.Transparent; + private IBrush _debugBrush = Brushes.Transparent; + private IBrush _normalBrush = Brushes.Transparent; + + private readonly AbstractOperation _operation; + private ProgressLineCollapser _collapser = new(); + + public OperationOutputViewModel(AbstractOperation operation) + { + _operation = operation; + Title = operation.Metadata.Title; + + Rebuild(); + + operation.LogLineAdded += (_, ev) => + Dispatcher.UIThread.Post(() => AddOrCollapseLine(ev.Item1, ev.Item2)); + } + + // Rebuilds every line with brushes for the current theme; called on construction and whenever + // the theme changes, so already-rendered output follows a live light/dark switch. + public void Rebuild() + { + var theme = Infrastructure.ThemeHelper.Variant; + _errorBrush = LookupBrush("StatusErrorForeground", theme, new SolidColorBrush(Color.Parse("#c62828"))); + _debugBrush = LookupBrush("LogOutputVerboseForeground", theme, new SolidColorBrush(Color.Parse("#767676"))); + _normalBrush = LookupBrush("SystemControlForegroundBaseHighBrush", theme, Brushes.White); + + OutputLines.Clear(); + _collapser = new(); + foreach (var (text, type) in _operation.GetOutput()) + AddOrCollapseLine(text, type); + } + + // Progress indicators (carriage-return redraws like installer spinners) overwrite the previous + // line instead of stacking up, mirroring how a terminal repaints in place. The first + // non-progress line that follows settles into that same line. + private void AddOrCollapseLine(string text, AbstractOperation.LineType type) + { + LogLineItem item = MakeLine(text, type); + if (_collapser.Next(type) is ProgressLineCollapser.Fold.ReplaceLast && OutputLines.Count > 0) + OutputLines[^1] = item; + else + OutputLines.Add(item); + } + + private static IBrush LookupBrush(string key, ThemeVariant theme, IBrush fallback) + { + if (Application.Current?.TryGetResource(key, theme, out var resource) == true && resource is IBrush brush) + return brush; + return fallback; + } + + private LogLineItem MakeLine(string text, AbstractOperation.LineType type) + { + IBrush brush = type switch + { + AbstractOperation.LineType.Error => _errorBrush, + AbstractOperation.LineType.VerboseDetails => _debugBrush, + _ => _normalBrush, + }; + return new LogLineItem(text, brush); + } +} diff --git a/src/UniGetUI.Avalonia/ViewModels/DialogPages/OperationViewModel.cs b/src/UniGetUI.Avalonia/ViewModels/DialogPages/OperationViewModel.cs new file mode 100644 index 0000000..3dd727d --- /dev/null +++ b/src/UniGetUI.Avalonia/ViewModels/DialogPages/OperationViewModel.cs @@ -0,0 +1,347 @@ +using System.Collections.ObjectModel; +using System.IO; +using System.Windows.Input; +using Avalonia; +using Avalonia.Controls; +using Avalonia.Controls.ApplicationLifetimes; +using Avalonia.Media; +using Avalonia.Media.Imaging; +using Avalonia.Platform; +using Avalonia.Threading; +using CommunityToolkit.Mvvm.ComponentModel; +using UniGetUI.Avalonia.Infrastructure; +using UniGetUI.Avalonia.Views; +using UniGetUI.Avalonia.Views.Controls; +using UniGetUI.Avalonia.Views.DialogPages; +using UniGetUI.Core.Tools; +using UniGetUI.PackageEngine.Classes.Packages.Classes; +using UniGetUI.PackageEngine.Enums; +using UniGetUI.PackageEngine.Operations; +using UniGetUI.PackageEngine.PackageClasses; +using UniGetUI.PackageOperations; + +namespace UniGetUI.Avalonia.ViewModels; + +/// Badge displayed next to the progress bar (Admin, Interactive, …). +public sealed record OperationBadgeVm( + string Label, + string IconPath, + string Primary, + string Secondary +); + +public sealed partial class OperationViewModel : ViewModelBase +{ + public AbstractOperation Operation { get; } + + public ObservableCollection Badges { get; } = []; + + public ICommand ButtonCommand { get; } + public ICommand ShowDetailsCommand { get; } + + /// Flyout for the "…" button; rebuilt each time the operation status changes. + public MenuFlyout OpMenu { get; } = new(); + private OperationStatus? _menuState; + + // ── Bindable properties ─────────────────────────────────────────────────── + [ObservableProperty] private string _title; + [ObservableProperty] private string _liveLine; + [ObservableProperty] private string _buttonText; + [ObservableProperty] private bool _progressIndeterminate; + [ObservableProperty] private double _progressValue; + [ObservableProperty] private IBrush _progressBrush; + [ObservableProperty] private IBrush _backgroundBrush; + [ObservableProperty] private IImage? _packageIcon; + + private static readonly Uri _fallbackIconUri = + new("avares://UniGetUI/Assets/package_color.png"); + + public OperationViewModel(AbstractOperation operation) + { + Operation = operation; + ButtonCommand = new SyncCommand(ButtonClick); + ShowDetailsCommand = new SyncCommand(ShowDetails); + + _title = operation.Metadata.Title; + _liveLine = operation.GetOutput().Any() + ? operation.GetOutput()[^1].Item1 + : CoreTools.Translate("Please wait..."); + _buttonText = CoreTools.Translate("Cancel"); + _progressBrush = new SolidColorBrush(Color.Parse("#888888")); + _backgroundBrush = Brushes.Transparent; + + _ = LoadIconAsync(); + + // Route all background-thread events to the UI thread + operation.LogLineAdded += (_, ev) => + Dispatcher.UIThread.Post(() => LiveLine = ev.Item1); + + operation.StatusChanged += (_, status) => + Dispatcher.UIThread.Post(() => ApplyStatus(status)); + + operation.BadgesChanged += (_, badges) => + Dispatcher.UIThread.Post(() => + { + Badges.Clear(); + if (badges.AsAdministrator) + Badges.Add(new( + CoreTools.Translate("Administrator privileges"), + "avares://UniGetUI/Assets/Symbols/uac.svg", + CoreTools.Translate("This operation is running with administrator privileges."), + "" + )); + if (badges.Interactive) + Badges.Add(new( + CoreTools.Translate("Interactive operation"), + "avares://UniGetUI/Assets/Symbols/interactive.svg", + CoreTools.Translate("This operation is running interactively."), + CoreTools.Translate("You will likely need to interact with the installer.") + )); + if (badges.SkipHashCheck) + Badges.Add(new( + CoreTools.Translate("Integrity checks skipped"), + "avares://UniGetUI/Assets/Symbols/checksum.svg", + CoreTools.Translate("Integrity checks will not be performed during this operation."), + CoreTools.Translate("Proceed at your own risk.") + )); + }); + + // Sync with current status in case the operation already started + ApplyStatus(operation.Status); + } + + // ── Icon loading ────────────────────────────────────────────────────────── + private async Task LoadIconAsync() + { + try + { + var uri = await Operation.GetOperationIcon(); + Bitmap? bmp = null; + if (uri.Scheme is "http" or "https") + { + using var http = new HttpClient(CoreTools.GenericHttpClientParameters); + var bytes = await http.GetByteArrayAsync(uri); + using var ms = new MemoryStream(bytes); + bmp = new Bitmap(ms); + } + else if (uri.Scheme is "avares") + { + using var stream = AssetLoader.Open(uri); + bmp = new Bitmap(stream); + } + + if (bmp is not null) + { + Dispatcher.UIThread.Post(() => PackageIcon = bmp); + return; + } + } + catch { /* icon is optional; fall through to fallback */ } + + try + { + using var stream = AssetLoader.Open(_fallbackIconUri); + var fallback = new Bitmap(stream); + Dispatcher.UIThread.Post(() => PackageIcon = fallback); + } + catch { } + } + + // ── Status → visual properties ──────────────────────────────────────────── + private void ApplyStatus(OperationStatus status) + { + switch (status) + { + case OperationStatus.InQueue: + ProgressIndeterminate = false; + ProgressValue = 0; + ProgressBrush = new SolidColorBrush(Color.Parse("#888888")); + BackgroundBrush = Brushes.Transparent; + ButtonText = CoreTools.Translate("Cancel"); + break; + + case OperationStatus.Running: + ProgressIndeterminate = true; + ProgressBrush = new SolidColorBrush(Color.Parse("#F0A500")); + BackgroundBrush = new SolidColorBrush(Color.FromArgb(30, 240, 165, 0)); + ButtonText = CoreTools.Translate("Cancel"); + break; + + case OperationStatus.Succeeded: + ProgressIndeterminate = false; + ProgressValue = 100; + ProgressBrush = new SolidColorBrush(Color.Parse("#0F7B0F")); + BackgroundBrush = new SolidColorBrush(Color.FromArgb(30, 15, 123, 15)); + ButtonText = CoreTools.Translate("Close"); + break; + + case OperationStatus.Failed: + ProgressIndeterminate = false; + ProgressValue = 100; + ProgressBrush = new SolidColorBrush(Color.Parse("#BC0000")); + BackgroundBrush = new SolidColorBrush(Color.FromArgb(40, 188, 0, 0)); + ButtonText = CoreTools.Translate("Close"); + break; + + case OperationStatus.Canceled: + ProgressIndeterminate = false; + ProgressValue = 100; + ProgressBrush = new SolidColorBrush(Color.Parse("#9D5D00")); + BackgroundBrush = Brushes.Transparent; + ButtonText = CoreTools.Translate("Close"); + break; + } + + RebuildMenu(status); + } + + // ── "…" menu ───────────────────────────────────────────────────────────── + private void RebuildMenu(OperationStatus status) + { + if (_menuState == status) return; + _menuState = status; + + OpMenu.Items.Clear(); + + // ── Operation-specific items (package details, install options, etc.) ── + if (Operation is PackageOperation packageOp) + { + bool notVirtual = !packageOp.Package.Source.IsVirtualManager; + + OpMenu.Items.Add(Item("Package details", "info_round.svg", + notVirtual, () => ShowPackageDetails(packageOp))); + + OpMenu.Items.Add(Item("Installation options", "options.svg", + notVirtual, () => _ = ShowInstallOptionsAsync(packageOp))); + + string? location = packageOp.Package.Manager.DetailsHelper.GetInstallLocation(packageOp.Package); + OpMenu.Items.Add(Item("Open install location", "open_folder.svg", + location is not null && Directory.Exists(location), + () => CoreTools.Launch(location))); + + OpMenu.Items.Add(new Separator()); + } + else if (Operation is DownloadOperation downloadOp) + { + bool succeeded = status is OperationStatus.Succeeded; + + OpMenu.Items.Add(Item("Open", "launch.svg", + succeeded, () => CoreTools.Launch(downloadOp.DownloadLocation))); + + OpMenu.Items.Add(Item("Show in explorer", "open_folder.svg", + succeeded, () => _ = CoreTools.ShowFileOnExplorer(downloadOp.DownloadLocation))); + + OpMenu.Items.Add(new Separator()); + } + + // ── Queue management ────────────────────────────────────────────────── + if (status is OperationStatus.InQueue) + { + OpMenu.Items.Add(Item("Run now", "forward.svg", true, Operation.SkipQueue)); + OpMenu.Items.Add(Item("Run next", "forward.svg", true, Operation.RunNext)); + OpMenu.Items.Add(Item("Run last", "backward.svg", true, Operation.BackOfTheQueue)); + OpMenu.Items.Add(new Separator()); + } + + // ── Cancel / Retry ──────────────────────────────────────────────────── + if (status is OperationStatus.InQueue or OperationStatus.Running) + { + OpMenu.Items.Add(Item("Cancel", "cross.svg", true, Operation.Cancel)); + } + else + { + OpMenu.Items.Add(Item("Retry", "reload.svg", true, + () => Operation.Retry(AbstractOperation.RetryMode.Retry))); + + if (Operation is PackageOperation pkgOp) + { + var caps = pkgOp.Package.Manager.Capabilities; + + if (OperatingSystem.IsWindows() && !pkgOp.Options.RunAsAdministrator && caps.CanRunAsAdmin) + OpMenu.Items.Add(Item("Retry as administrator", "uac.svg", true, + () => Operation.Retry(AbstractOperation.RetryMode.Retry_AsAdmin))); + + if (!pkgOp.Options.InteractiveInstallation && caps.CanRunInteractively) + OpMenu.Items.Add(Item("Retry interactively", "interactive.svg", true, + () => Operation.Retry(AbstractOperation.RetryMode.Retry_Interactive))); + + if (!pkgOp.Options.SkipHashCheck && caps.CanSkipIntegrityChecks) + OpMenu.Items.Add(Item("Retry skipping integrity checks", "checksum.svg", true, + () => Operation.Retry(AbstractOperation.RetryMode.Retry_SkipIntegrity))); + } + else if (OperatingSystem.IsWindows() && Operation is SourceOperation srcOp && !srcOp.ForceAsAdministrator) + { + OpMenu.Items.Add(Item("Retry as administrator", "uac.svg", true, + () => Operation.Retry(AbstractOperation.RetryMode.Retry_AsAdmin))); + } + } + } + + /// Creates a MenuItem with an SVG icon, translated header, and a SyncCommand. + private static MenuItem Item(string translationKey, string svgName, bool enabled, Action action) => + new() + { + Header = CoreTools.Translate(translationKey), + IsEnabled = enabled, + Command = new SyncCommand(action), + Icon = new SvgIcon + { + Path = $"avares://UniGetUI/Assets/Symbols/{svgName}", + Width = 16, + Height = 16, + }, + }; + + // ── Package details / install options ──────────────────────────────────── + private static void ShowPackageDetails(PackageOperation packageOp) + { + if (GetMainWindow() is not { } mainWindow) return; + var win = new PackageDetailsWindow(packageOp.Package, OperationType.None); + _ = win.ShowDialog(mainWindow); + } + + private static async Task ShowInstallOptionsAsync(PackageOperation packageOp) + { + if (GetMainWindow() is not { } mainWindow) return; + var opts = await InstallOptionsFactory.LoadApplicableAsync(packageOp.Package); + var win = new InstallOptionsWindow(packageOp.Package, OperationType.None, opts); + await win.ShowDialog(mainWindow); + await InstallOptionsFactory.SaveForPackageAsync(opts, packageOp.Package); + } + + private static Window? GetMainWindow() => + Application.Current?.ApplicationLifetime + is IClassicDesktopStyleApplicationLifetime { MainWindow: Window mw } ? mw : null; + + // ── Button / details actions ────────────────────────────────────────────── + private void ButtonClick() + { + if (Operation.Status is OperationStatus.Running or OperationStatus.InQueue) + Operation.Cancel(); + else + AvaloniaOperationRegistry.Remove(this); + } + + private void ShowDetails() + { + if (GetMainWindow() is not { } mainWindow) return; + if (Operation.Status is OperationStatus.Failed) + { + var win = new OperationFailedDialog(Operation); + win.Show(mainWindow); + } + else + { + var win = new OperationOutputWindow(Operation); + win.Show(mainWindow); + } + } + + // ── Minimal ICommand implementation ─────────────────────────────────────── + private sealed class SyncCommand(Action action) : ICommand + { + public event EventHandler? CanExecuteChanged { add { } remove { } } + public bool CanExecute(object? parameter) => true; + public void Execute(object? parameter) => action(); + } +} diff --git a/src/UniGetUI.Avalonia/ViewModels/DialogPages/PackageDetailsViewModel.cs b/src/UniGetUI.Avalonia/ViewModels/DialogPages/PackageDetailsViewModel.cs new file mode 100644 index 0000000..5fb3020 --- /dev/null +++ b/src/UniGetUI.Avalonia/ViewModels/DialogPages/PackageDetailsViewModel.cs @@ -0,0 +1,385 @@ +using System.Collections.ObjectModel; +using System.Diagnostics; +using System.Net.Http; +using Avalonia.Media.Imaging; +using Avalonia.Platform; +using Avalonia.Threading; +using CommunityToolkit.Mvvm.ComponentModel; +using CommunityToolkit.Mvvm.Input; +using UniGetUI.Core.Logging; +using UniGetUI.Core.Tools; +using UniGetUI.PackageEngine.Enums; +using UniGetUI.PackageEngine.Interfaces; + +namespace UniGetUI.Avalonia.ViewModels; + +public partial class PackageDetailsViewModel : ObservableObject +{ + public event EventHandler? CloseRequested; + /// Raised on the UI thread after details have been loaded so the view + /// can (re)populate the inline rich-text blocks. + public event EventHandler? DetailsLoaded; + + public readonly IPackage Package; + public readonly OperationType OperationRole; + + // ── Header ───────────────────────────────────────────────────────────────── + public string PackageName { get; } + public string SourceDisplay { get; } + + [ObservableProperty] + private Bitmap? _packageIcon; + + [ObservableProperty] + [NotifyPropertyChangedFor(nameof(IsLoaded))] + private bool _isLoading = true; + + public bool IsLoaded => !IsLoading; + + // ── Tags ─────────────────────────────────────────────────────────────────── + public ObservableCollection Tags { get; } = []; + + [ObservableProperty] + [NotifyPropertyChangedFor(nameof(HasTags))] + private int _tagCount; + + public bool HasTags => TagCount > 0; + + // ── Description ──────────────────────────────────────────────────────────── + [ObservableProperty] + private string _description = CoreTools.Translate("Loading..."); + + // ── Basic info (raw values exposed; the view builds the inline rich text) ── + [ObservableProperty] + private string _versionDisplay = ""; + + [ObservableProperty] + private Uri? _homepageUrl; + + [ObservableProperty] + private string _author = CoreTools.Translate("Loading..."); + [ObservableProperty] + private string _publisher = CoreTools.Translate("Loading..."); + + [ObservableProperty] + private string? _licenseName; + [ObservableProperty] + private Uri? _licenseUrl; + + // ── Actions ──────────────────────────────────────────────────────────────── + public string MainActionLabel { get; } + public string AsAdminLabel { get; } + public string InteractiveLabel { get; } + public string SkipHashOrRemoveDataLabel { get; } + public bool CanRunAsAdmin { get; } + public bool CanRunInteractively { get; } + public bool CanSkipHashOrRemoveData { get; } + + // ── Extended details ─────────────────────────────────────────────────────── + public string PackageId { get; } + + [ObservableProperty] + private Uri? _manifestUrl; + + [ObservableProperty] + private string _installerHashLabel = CoreTools.Translate("Installer SHA256") + ":"; + [ObservableProperty] + private string _installerHash = CoreTools.Translate("Loading..."); + [ObservableProperty] + private string _installerType = CoreTools.Translate("Loading..."); + [ObservableProperty] + private Uri? _installerUrl; + [ObservableProperty] + private string _installerSize = ""; + + public bool CanDownloadInstaller { get; } + + [ObservableProperty] + private string _updateDate = CoreTools.Translate("Loading..."); + + // ── Dependencies ─────────────────────────────────────────────────────────── + public bool CanListDependencies { get; } + public ObservableCollection Dependencies { get; } = []; + + [ObservableProperty] + [NotifyPropertyChangedFor(nameof(HasDependenciesList))] + private bool _hasDependencyNote = true; + + public bool HasDependenciesList => !HasDependencyNote; + + [ObservableProperty] + private string _dependencyNote = ""; + + // ── Screenshots ──────────────────────────────────────────────────────────── + public ObservableCollection Screenshots { get; } = []; + + [ObservableProperty] + [NotifyPropertyChangedFor(nameof(HasScreenshots))] + private int _screenshotCount; + + public bool HasScreenshots => ScreenshotCount > 0; + + [ObservableProperty] + private int _selectedScreenshotIndex; + + // ── Release notes ────────────────────────────────────────────────────────── + [ObservableProperty] + private string _releaseNotes = CoreTools.Translate("Loading..."); + [ObservableProperty] + private Uri? _releaseNotesUrl; + + // ── Translated labels ────────────────────────────────────────────────────── + public string LabelVersion { get; } + public string LabelHomepage { get; } = CoreTools.Translate("Homepage"); + public string LabelAuthor { get; } = CoreTools.Translate("Author"); + public string LabelPublisher { get; } = CoreTools.Translate("Publisher"); + public string LabelLicense { get; } = CoreTools.Translate("License"); + public string LabelSource { get; } = CoreTools.Translate("Package Manager"); + public string LabelPackageId { get; } = CoreTools.Translate("Package ID"); + public string LabelManifest { get; } = CoreTools.Translate("Manifest"); + public string LabelInstallerType { get; } = CoreTools.Translate("Installer Type"); + public string LabelInstallerUrl { get; } = CoreTools.Translate("Installer URL"); + public string LabelUpdateDate { get; } = CoreTools.Translate("Last updated"); + public string LabelDependencies { get; } = CoreTools.Translate("Dependencies"); + public string LabelReleaseNotes { get; } = CoreTools.Translate("Release notes"); + public string LabelReleaseNotesUrl { get; } = CoreTools.Translate("Release notes URL"); + public string LabelDownloadInstaller { get; } = CoreTools.Translate("Download installer"); + public string LabelInstallerNotAvailable { get; } = CoreTools.Translate("Installer not available"); + public string LabelNotAvailable { get; } = CoreTools.Translate("Not available"); + public string LabelNoDependencies { get; } = CoreTools.Translate("No dependencies specified"); + public string LabelInstallationOptions { get; } = CoreTools.Translate("Installation options"); + public string LabelSave { get; } = CoreTools.Translate("Save"); + public string LabelContributorBanner { get; } = CoreTools.Translate( + "This package has no screenshots or is missing the icon? Contribute to UniGetUI by adding the missing icons and screenshots to our open, public database."); + public string LabelContribute { get; } = CoreTools.Translate("Become a contributor"); + + public PackageDetailsViewModel(IPackage package, OperationType role) + { + if (role == OperationType.None) role = OperationType.Install; + + Package = package; + OperationRole = role; + PackageName = package.Name; + PackageId = package.Id; + SourceDisplay = package.Source.AsString_DisplayName; + + CanDownloadInstaller = package.Manager.Capabilities.CanDownloadInstaller; + CanListDependencies = package.Manager.Capabilities.CanListDependencies; + + var caps = package.Manager.Capabilities; + CanRunAsAdmin = caps.CanRunAsAdmin; + CanRunInteractively = caps.CanRunInteractively; + + var available = package.GetAvailablePackage(); + var upgradable = package.GetUpgradablePackage(); + var installed = upgradable?.GetInstalledPackages().FirstOrDefault(); + + if (role == OperationType.Install) + { + MainActionLabel = CoreTools.Translate("Install"); + LabelVersion = CoreTools.Translate("Version"); + VersionDisplay = available?.VersionString ?? package.VersionString; + AsAdminLabel = CoreTools.Translate("Install as administrator"); + InteractiveLabel = CoreTools.Translate("Interactive installation"); + SkipHashOrRemoveDataLabel = CoreTools.Translate("Skip hash check"); + CanSkipHashOrRemoveData = caps.CanSkipIntegrityChecks; + } + else if (role == OperationType.Update) + { + MainActionLabel = CoreTools.Translate( + "Update to version {0}", upgradable?.NewVersionString ?? package.NewVersionString); + LabelVersion = CoreTools.Translate("Installed Version"); + VersionDisplay = (upgradable?.VersionString ?? package.VersionString) + + " ➤ " + + (upgradable?.NewVersionString ?? package.NewVersionString); + AsAdminLabel = CoreTools.Translate("Update as administrator"); + InteractiveLabel = CoreTools.Translate("Interactive update"); + SkipHashOrRemoveDataLabel = CoreTools.Translate("Skip hash check"); + CanSkipHashOrRemoveData = caps.CanSkipIntegrityChecks; + } + else + { + MainActionLabel = CoreTools.Translate("Uninstall"); + LabelVersion = CoreTools.Translate("Installed Version"); + VersionDisplay = installed?.VersionString ?? package.VersionString; + AsAdminLabel = CoreTools.Translate("Uninstall as administrator"); + InteractiveLabel = CoreTools.Translate("Interactive uninstall"); + SkipHashOrRemoveDataLabel = CoreTools.Translate("Uninstall and remove data"); + CanSkipHashOrRemoveData = caps.CanRemoveDataOnUninstall; + } + } + + [RelayCommand] + private void PreviousScreenshot() + { + if (SelectedScreenshotIndex > 0) + SelectedScreenshotIndex--; + } + + [RelayCommand] + private void NextScreenshot() + { + if (SelectedScreenshotIndex < ScreenshotCount - 1) + SelectedScreenshotIndex++; + } + + public async Task LoadDetailsAsync() + { + _ = LoadIconAsync(); + _ = LoadScreenshotsAsync(); + + var details = Package.Details; + if (!details.IsPopulated) + await details.Load(); + + IsLoading = false; + + Description = details.Description ?? CoreTools.Translate("Not available"); + HomepageUrl = details.HomepageUrl; + Author = details.Author ?? CoreTools.Translate("Not available"); + Publisher = details.Publisher ?? CoreTools.Translate("Not available"); + + LicenseName = details.License; + LicenseUrl = details.LicenseUrl; + + ManifestUrl = details.ManifestUrl; + + if (Package.Manager.Properties.Name.Equals("chocolatey", StringComparison.OrdinalIgnoreCase)) + InstallerHashLabel = CoreTools.Translate("Installer SHA512") + ":"; + + InstallerHash = details.InstallerHash ?? CoreTools.Translate("Not available"); + InstallerType = details.InstallerType ?? CoreTools.Translate("Not available"); + InstallerUrl = details.InstallerUrl; + InstallerSize = details.InstallerSize > 0 + ? CoreTools.FormatAsSize(details.InstallerSize, 2) + : CoreTools.Translate("Unknown size"); + UpdateDate = details.UpdateDate ?? CoreTools.Translate("Not available"); + + ReleaseNotes = details.ReleaseNotes ?? CoreTools.Translate("Not available"); + ReleaseNotesUrl = details.ReleaseNotesUrl; + + if (!CanListDependencies) + { + DependencyNote = CoreTools.Translate("Not available"); + HasDependencyNote = true; + } + else if (details.Dependencies.Any()) + { + HasDependencyNote = false; + Dependencies.Clear(); + foreach (var dep in details.Dependencies) + Dependencies.Add(new DependencyViewModel(dep)); + } + else + { + DependencyNote = CoreTools.Translate("No dependencies specified"); + HasDependencyNote = true; + } + + Tags.Clear(); + foreach (var tag in details.Tags) + Tags.Add(tag); + TagCount = Tags.Count; + + DetailsLoaded?.Invoke(this, EventArgs.Empty); + } + + private async Task LoadIconAsync() + { + try + { + var uri = await Task.Run(Package.GetIconUrlIfAny); + if (uri is not null) + { + Bitmap? bitmap = null; + if (uri.IsFile) + { + bitmap = await Task.Run(() => new Bitmap(uri.LocalPath)); + } + else if (uri.Scheme is "http" or "https") + { + using var http = new HttpClient(CoreTools.GenericHttpClientParameters); + var bytes = await http.GetByteArrayAsync(uri); + using var ms = new MemoryStream(bytes); + bitmap = new Bitmap(ms); + } + + if (bitmap is not null) + { + PackageIcon = bitmap; + return; + } + } + } + catch (Exception ex) + { + Logger.Warn($"[PackageDetailsViewModel] Failed to load icon: {ex.Message}"); + } + + try + { + using var stream = AssetLoader.Open( + new Uri("avares://UniGetUI/Assets/package_color.png")); + PackageIcon = new Bitmap(stream); + } + catch { } + } + + private async Task LoadScreenshotsAsync() + { + try + { + var uris = await Task.Run(Package.GetScreenshots); + if (!uris.Any()) return; + + using var http = new HttpClient(CoreTools.GenericHttpClientParameters); + foreach (var uri in uris) + { + try + { + var bytes = await http.GetByteArrayAsync(uri); + using var ms = new MemoryStream(bytes); + var bmp = new Bitmap(ms); + await Dispatcher.UIThread.InvokeAsync(() => + { + Screenshots.Add(bmp); + ScreenshotCount = Screenshots.Count; + }); + } + catch { /* skip failed screenshots */ } + } + } + catch (Exception ex) + { + Logger.Warn($"[PackageDetailsViewModel] Failed to load screenshots: {ex.Message}"); + } + } + + [RelayCommand] + public static void OpenUrl(string? url) + { + if (string.IsNullOrEmpty(url) || !url.StartsWith("http", StringComparison.OrdinalIgnoreCase)) + return; + try { Process.Start(new ProcessStartInfo(url) { UseShellExecute = true }); } + catch { } + } + + [RelayCommand] + public void RequestClose() => CloseRequested?.Invoke(this, EventArgs.Empty); +} + +public class DependencyViewModel +{ + public string DisplayText { get; } + + public DependencyViewModel(IPackageDetails.Dependency dep) + { + var text = $" • {dep.Name}"; + if (!string.IsNullOrEmpty(dep.Version)) + text += $" v{dep.Version}"; + text += dep.Mandatory + ? $" ({CoreTools.Translate("mandatory")})" + : $" ({CoreTools.Translate("optional")})"; + DisplayText = text; + } +} diff --git a/src/UniGetUI.Avalonia/ViewModels/InfoBarViewModel.cs b/src/UniGetUI.Avalonia/ViewModels/InfoBarViewModel.cs new file mode 100644 index 0000000..63c814d --- /dev/null +++ b/src/UniGetUI.Avalonia/ViewModels/InfoBarViewModel.cs @@ -0,0 +1,28 @@ +using System.Windows.Input; +using CommunityToolkit.Mvvm.ComponentModel; +using CommunityToolkit.Mvvm.Input; + +namespace UniGetUI.Avalonia.ViewModels; + +public enum InfoBarSeverity { Informational, Warning, Error, Success } + +public partial class InfoBarViewModel : ObservableObject +{ + [ObservableProperty] private bool _isOpen; + [ObservableProperty] private string _title = ""; + [ObservableProperty] private string _message = ""; + [ObservableProperty] private InfoBarSeverity _severity = InfoBarSeverity.Informational; + [ObservableProperty] private bool _isClosable = true; + [ObservableProperty] private string _actionButtonText = ""; + [ObservableProperty] private ICommand? _actionButtonCommand; + + public Action? OnClosed { get; set; } + + partial void OnIsOpenChanged(bool value) + { + if (!value) OnClosed?.Invoke(); + } + + [RelayCommand] + private void Close() => IsOpen = false; +} diff --git a/src/UniGetUI.Avalonia/ViewModels/MainWindowViewModel.cs b/src/UniGetUI.Avalonia/ViewModels/MainWindowViewModel.cs new file mode 100644 index 0000000..195743c --- /dev/null +++ b/src/UniGetUI.Avalonia/ViewModels/MainWindowViewModel.cs @@ -0,0 +1,719 @@ +using System.Collections.ObjectModel; +using System.Collections.Specialized; +using Avalonia; +using Avalonia.Automation; +using Avalonia.Collections; +using Avalonia.Controls; +using Avalonia.Controls.ApplicationLifetimes; +using Avalonia.Threading; +using CommunityToolkit.Mvvm.ComponentModel; +using CommunityToolkit.Mvvm.Input; +using UniGetUI.Avalonia.Infrastructure; +using UniGetUI.Avalonia.ViewModels.Pages; +using UniGetUI.Avalonia.Views; +using UniGetUI.Avalonia.Views.DialogPages; +using UniGetUI.Avalonia.Views.Pages; +using UniGetUI.Avalonia.Views.Pages.LogPages; +using UniGetUI.Avalonia.Views.Pages.SettingsPages; +using UniGetUI.Core.Data; +using UniGetUI.Core.SettingsEngine; +using UniGetUI.Core.Tools; +using UniGetUI.Interface.Enums; +using UniGetUI.PackageEngine; +using UniGetUI.PackageEngine.Enums; +using UniGetUI.PackageEngine.Interfaces; +using UniGetUI.PackageEngine.PackageLoader; +using UniGetUI.PackageOperations; + +namespace UniGetUI.Avalonia.ViewModels; + +public partial class MainWindowViewModel : ViewModelBase +{ + // ─── Pages ─────────────────────────────────────────────────────────────── + private readonly DiscoverSoftwarePage DiscoverPage; + private readonly SoftwareUpdatesPage UpdatesPage; + private readonly InstalledPackagesPage InstalledPage; + private readonly PackageBundlesPage BundlesPage; + private SettingsBasePage? SettingsPage; + private SettingsBasePage? ManagersPage; + private UniGetUILogPage? UniGetUILogPage; + private ManagerLogsPage? ManagerLogPage; + private OperationHistoryPage? OperationHistoryPage; + private HelpPage? HelpPage; + private ReleaseNotesPage? ReleaseNotesPage; + + // ─── Navigation state ──────────────────────────────────────────────────── + private PageType _oldPage = PageType.Null; + private PageType _currentPage = PageType.Null; + public PageType CurrentPage_t => _currentPage; + private readonly List NavigationHistory = new(); + + [ObservableProperty] + private object? _currentPageContent; + + public event EventHandler? CanGoBackChanged; + public event EventHandler? CurrentPageChanged; + + [ObservableProperty] + private string _announcementText = ""; + + [ObservableProperty] + private AutomationLiveSetting _announcementLiveSetting = AutomationLiveSetting.Polite; + + // ─── Operations panel ───────────────────────────────────────────────────── + public AvaloniaList Operations => AvaloniaOperationRegistry.OperationViewModels; + + [ObservableProperty] + [NotifyPropertyChangedFor(nameof(ShowFailedOperationBadge))] + private bool _operationsPanelVisible; + + [ObservableProperty] + [NotifyPropertyChangedFor(nameof(ShowFailedOperationBadge))] + private bool _operationsPanelExpanded = true; + + private readonly List _operationBatch = new(); + private bool _batchSummaryShown; + + public bool HasFailedOperations => Operations.Any(o => o.Operation.Status is OperationStatus.Failed); + + public OperationViewModel? FirstFailedOperation => + Operations.FirstOrDefault(o => o.Operation.Status is OperationStatus.Failed); + + // Red badge on the chevron when the panel is collapsed and an operation failed + // (failures no longer pop a toast; expanded, the failure is already visible). + public bool ShowFailedOperationBadge => OperationsPanelVisible && !OperationsPanelExpanded && HasFailedOperations; + + public string OperationsHeaderText + { + get + { + int total = _operationBatch.Count; + if (total == 0) + return CoreTools.Translate("Operations"); + int completed = _operationBatch.Count(o => + o.Status is OperationStatus.Succeeded or OperationStatus.Failed or OperationStatus.Canceled); + return CoreTools.Translate("{0} of {1} operations completed", completed, total); + } + } + + private void AddToBatch(AbstractOperation op) + { + if (_operationBatch.Count > 0 + && _operationBatch.All(o => o.Status is not (OperationStatus.InQueue or OperationStatus.Running))) + { + foreach (var old in _operationBatch) + old.StatusChanged -= OnOperationStatusChanged; + _operationBatch.Clear(); + _batchSummaryShown = false; + } + + if (!_operationBatch.Contains(op)) + { + _operationBatch.Add(op); + op.StatusChanged += OnOperationStatusChanged; + } + } + + private void OnOperationStatusChanged(object? sender, OperationStatus e) + => Dispatcher.UIThread.Post(() => + { + OnPropertyChanged(nameof(OperationsHeaderText)); + OnPropertyChanged(nameof(HasFailedOperations)); + OnPropertyChanged(nameof(ShowFailedOperationBadge)); + MaybeShowBatchSummaryToast(); + }); + + // Opt-in: one toast summarizing the batch once every operation in it has finished. + private void MaybeShowBatchSummaryToast() + { + if (_batchSummaryShown || _operationBatch.Count == 0) return; + if (!Settings.Get(Settings.K.ShowOperationSummaryNotifications)) return; + if (_operationBatch.Any(o => o.Status is OperationStatus.InQueue or OperationStatus.Running)) return; + + _batchSummaryShown = true; + + int total = _operationBatch.Count; + int failed = _operationBatch.Count(o => o.Status is OperationStatus.Failed); + int succeeded = _operationBatch.Count(o => o.Status is OperationStatus.Succeeded); + + var toast = new InfoBarViewModel + { + Title = failed > 0 + ? CoreTools.Translate("Operations finished with errors") + : CoreTools.Translate("Operations completed"), + Message = failed > 0 + ? CoreTools.Translate("{0} of {1} succeeded, {2} failed", succeeded, total, failed) + : CoreTools.Translate("{0} of {1} operations completed", succeeded, total), + Severity = failed > 0 ? InfoBarSeverity.Error : InfoBarSeverity.Success, + IsClosable = true, + IsOpen = true, + }; + toast.OnClosed = () => DismissToast(toast); + ShowToast(toast); + } + + [RelayCommand] + private void ToggleOperationsPanel() => OperationsPanelExpanded = !OperationsPanelExpanded; + + [RelayCommand] + private void RetryFailedOperations() => AvaloniaOperationRegistry.RetryFailed(); + + [RelayCommand] + private void ClearSuccessfulOperations() => AvaloniaOperationRegistry.ClearSuccessful(); + + [RelayCommand] + private void ClearFinishedOperations() => AvaloniaOperationRegistry.ClearFinished(); + + [RelayCommand] + private void CancelAllOperations() => AvaloniaOperationRegistry.CancelAll(); + + // ─── Sidebar ───────────────────────────────────────────────────────────── + public SidebarViewModel Sidebar { get; } = new(); + + // ─── Global search ─────────────────────────────────────────────────────── + [ObservableProperty] + private string _globalSearchText = ""; + + [ObservableProperty] + private bool _globalSearchEnabled; + + [ObservableProperty] + private string _globalSearchPlaceholder = ""; + + // When search text changes, notify the current page + private PackagesPageViewModel? _subscribedPageViewModel; + private bool _syncingSearch; + + partial void OnGlobalSearchTextChanged(string value) + { + if (_syncingSearch) return; + if (CurrentPageContent is AbstractPackagesPage page) + page.ViewModel.GlobalQueryText = value; + } + + private void SubscribeToPageViewModel(AbstractPackagesPage? page) + { + _subscribedPageViewModel?.PropertyChanged -= OnPageViewModelPropertyChanged; + + _subscribedPageViewModel = page?.ViewModel; + + _subscribedPageViewModel?.PropertyChanged += OnPageViewModelPropertyChanged; + } + + private void OnPageViewModelPropertyChanged(object? sender, System.ComponentModel.PropertyChangedEventArgs e) + { + if (e.PropertyName == nameof(PackagesPageViewModel.GlobalQueryText) && sender is PackagesPageViewModel vm) + { + _syncingSearch = true; + GlobalSearchText = vm.GlobalQueryText; + _syncingSearch = false; + } + } + + // ─── Title bar ─────────────────────────────────────────────────────────── + // Mirrors WinUI behavior: the version appears next to "UniGetUI" only when + // the ShowVersionNumberOnTitlebar setting is enabled (the setting is gated + // on restart, so a one-shot read at construction is sufficient). + public string TitleBarText { get; } = Settings.Get(Settings.K.ShowVersionNumberOnTitlebar) + ? $"UniGetUI {CoreTools.Translate("version {0}", CoreData.VersionName)}" + : "UniGetUI"; + + // ─── Notifications (bottom-right toasts) ─────────────────────────────────── + // Persistent banners kept as singletons; RegisterBannerToast mirrors their IsOpen into Toasts. + public InfoBarViewModel UpdatesBanner { get; } = new() { Severity = InfoBarSeverity.Success }; + public InfoBarViewModel WinGetWarningBanner { get; } = new() { Severity = InfoBarSeverity.Warning }; + public InfoBarViewModel TelemetryWarner { get; } = new() { Severity = InfoBarSeverity.Informational }; + + // Oldest first (rendered bottom-up so the newest sits nearest the corner). + public ObservableCollection Toasts { get; } = new(); + private readonly Dictionary _toastTimers = new(); + private const int MaxVisibleToasts = 5; + + // A toast with an action button stays until acted on; everything else auto-dismisses. + private static bool IsSticky(InfoBarViewModel t) => !string.IsNullOrEmpty(t.ActionButtonText); + private static TimeSpan ToastDuration(InfoBarViewModel t) + => t.Severity is InfoBarSeverity.Error or InfoBarSeverity.Warning + ? TimeSpan.FromSeconds(8) + : TimeSpan.FromSeconds(5); + + public void ShowToast(InfoBarViewModel toast) + { + if (!Dispatcher.UIThread.CheckAccess()) + { + Dispatcher.UIThread.Post(() => ShowToast(toast)); + return; + } + if (!Toasts.Contains(toast)) + { + Toasts.Add(toast); + AnnounceToast(toast); + } + TrimToastStack(keep: toast); + ArmToastTimer(toast); + } + + // Keep the stack from overflowing the screen: drop the oldest auto-dismissing toasts, + // but never a sticky (action-button) one or the toast just shown. + private void TrimToastStack(InfoBarViewModel keep) + { + while (Toasts.Count > MaxVisibleToasts) + { + var oldest = Toasts.FirstOrDefault(t => t != keep && !IsSticky(t)); + if (oldest is null) break; + DismissToast(oldest); + } + } + + // Surface the toast to screen readers via the live region (assertive for errors so it + // interrupts, polite otherwise) — the toast's own automation name isn't announced on its own. + private static void AnnounceToast(InfoBarViewModel toast) + { + string message = string.IsNullOrEmpty(toast.Message) + ? toast.Title + : $"{toast.Title}. {toast.Message}"; + AccessibilityAnnouncementService.Announce( + message, + toast.Severity is InfoBarSeverity.Error + ? AutomationLiveSetting.Assertive + : AutomationLiveSetting.Polite); + } + + public void DismissToast(InfoBarViewModel toast) + { + if (!Dispatcher.UIThread.CheckAccess()) + { + Dispatcher.UIThread.Post(() => DismissToast(toast)); + return; + } + DisposeToastTimer(toast); + Toasts.Remove(toast); + } + + // Pause the auto-dismiss countdown while the pointer hovers a toast; restart it on leave. + public void PauseToast(InfoBarViewModel toast) + { + if (_toastTimers.TryGetValue(toast, out var timer)) timer.Stop(); + } + + public void ResumeToast(InfoBarViewModel toast) + { + if (_toastTimers.TryGetValue(toast, out var timer)) { timer.Stop(); timer.Start(); } + } + + private void ArmToastTimer(InfoBarViewModel toast) + { + DisposeToastTimer(toast); + if (IsSticky(toast)) + return; + + var timer = new DispatcherTimer { Interval = ToastDuration(toast) }; + timer.Tick += (_, _) => toast.IsOpen = false; + _toastTimers[toast] = timer; + timer.Start(); + } + + private void DisposeToastTimer(InfoBarViewModel toast) + { + if (_toastTimers.Remove(toast, out var timer)) + timer.Stop(); + } + + // Mirrors a persistent banner's IsOpen into Toasts so code that just flips IsOpen keeps working. + private void RegisterBannerToast(InfoBarViewModel banner) + { + banner.PropertyChanged += (_, e) => + { + if (e.PropertyName == nameof(InfoBarViewModel.IsOpen)) + { + if (banner.IsOpen) ShowToast(banner); + else DismissToast(banner); + } + // Content can change in place while the banner stays open (the updater cycles + // statuses on the same banner, finally adding the "Update now" action); re-arm so + // stickiness/countdown track the new content instead of a stale timer dismissing it. + else if (banner.IsOpen && Toasts.Contains(banner)) + { + ArmToastTimer(banner); + } + }; + } + + // ─── Constructor ───────────────────────────────────────────────────────── + [RelayCommand] + private void ToggleSidebar() => Sidebar.IsPaneOpen = !Sidebar.IsPaneOpen; + + public MainWindowViewModel() + { + AccessibilityAnnouncementService.AnnouncementRequested += OnAnnouncementRequested; + + // Wire before the blocks below flip the banners' IsOpen flags. + RegisterBannerToast(UpdatesBanner); + RegisterBannerToast(WinGetWarningBanner); + RegisterBannerToast(TelemetryWarner); + + DiscoverPage = new DiscoverSoftwarePage(); + UpdatesPage = new SoftwareUpdatesPage(); + InstalledPage = new InstalledPackagesPage(); + BundlesPage = new PackageBundlesPage(); + + // Wire loader status → sidebar badges (loaders are null until package engine initializes) + foreach (var (pageType, loader) in new (PageType, AbstractPackageLoader?)[] + { + (PageType.Discover, DiscoverablePackagesLoader.Instance), + (PageType.Updates, UpgradablePackagesLoader.Instance), + (PageType.Installed, InstalledPackagesLoader.Instance), + }) + { + if (loader is null) continue; + var pt = pageType; + loader.FinishedLoading += (_, _) => + { + Dispatcher.UIThread.Post(() => Sidebar.SetNavItemLoading(pt, false)); + // Return the load's memory to the OS once it settles. + Infrastructure.MemoryTrimmer.RequestTrimAfterIdle(); + }; + loader.StartedLoading += (_, _) => + { + Dispatcher.UIThread.Post(() => Sidebar.SetNavItemLoading(pt, true)); + Infrastructure.MemoryTrimmer.CancelPending(); + }; + Sidebar.SetNavItemLoading(pt, loader.IsLoading); + } + + if (UpgradablePackagesLoader.Instance is { } upgLoader) + { + upgLoader.PackagesChanged += (_, _) => + Dispatcher.UIThread.Post(() => + { + Sidebar.UpdatesBadgeCount = upgLoader.Count(); + MainWindow.Instance?.UpdateSystemTrayStatus(); + }); + Sidebar.UpdatesBadgeCount = upgLoader.Count(); + // Notifications and auto-update logic are handled by SoftwareUpdatesPage.WhenPackagesLoaded + } + + WindowsAppNotificationBridge.NotificationActivated += action => + Dispatcher.UIThread.Post(() => HandleNotificationActivation(action)); + + BundlesPage.UnsavedChangesStateChanged += (_, _) => + Dispatcher.UIThread.Post(() => + Sidebar.BundlesBadgeVisible = BundlesPage.HasUnsavedChanges); + Sidebar.BundlesBadgeVisible = BundlesPage.HasUnsavedChanges; + + Sidebar.NavigationRequested += (_, pageType) => NavigateTo(pageType); + + AvaloniaAutoUpdater.UpdateAvailable += version => Dispatcher.UIThread.Post(() => + { + UpdatesBanner.Severity = InfoBarSeverity.Success; + UpdatesBanner.Title = CoreTools.Translate("UniGetUI {0} is ready to be installed.", version); + UpdatesBanner.Message = CoreTools.Translate("The update process will start after closing UniGetUI"); + UpdatesBanner.ActionButtonText = CoreTools.Translate("Update now"); + UpdatesBanner.ActionButtonCommand = new CommunityToolkit.Mvvm.Input.RelayCommand(AvaloniaAutoUpdater.TriggerInstall); + UpdatesBanner.IsClosable = true; + UpdatesBanner.IsOpen = true; + }); + + AvaloniaAutoUpdater.StatusChanged += status => Dispatcher.UIThread.Post(() => + { + UpdatesBanner.Severity = status.Severity; + UpdatesBanner.Title = status.Title; + UpdatesBanner.Message = status.Message; + UpdatesBanner.ActionButtonText = status.ActionButtonText ?? ""; + UpdatesBanner.ActionButtonCommand = status.ActionButtonAction is { } action + ? new CommunityToolkit.Mvvm.Input.RelayCommand(action) + : null; + UpdatesBanner.IsClosable = status.IsClosable; + UpdatesBanner.IsOpen = true; + }); + + // If the previous update attempt was killed mid-flow (typically by the + // installer terminating us during file replacement), surface a banner now + // that subscriptions are wired up. + AvaloniaAutoUpdater.CheckForOrphanedUpdateAttempt(); + + // Keep OperationsPanelVisible in sync with the live operations list + Operations.CollectionChanged += (_, e) => + { + if (e.NewItems is not null) + foreach (OperationViewModel vm in e.NewItems) + AddToBatch(vm.Operation); + OperationsPanelVisible = Operations.Count > 0; + OnPropertyChanged(nameof(OperationsHeaderText)); + OnPropertyChanged(nameof(HasFailedOperations)); + OnPropertyChanged(nameof(ShowFailedOperationBadge)); + }; + + if (OperatingSystem.IsWindows() && CoreTools.IsAdministrator() && !Settings.Get(Settings.K.AlreadyWarnedAboutAdmin)) + { + Settings.Set(Settings.K.AlreadyWarnedAboutAdmin, true); + WinGetWarningBanner.Title = CoreTools.Translate("Administrator privileges"); + WinGetWarningBanner.Message = CoreTools.Translate( + "UniGetUI has been ran as administrator, which is not recommended. When running UniGetUI as administrator, EVERY operation launched from UniGetUI will have administrator privileges. You can still use the program, but we highly recommend not running UniGetUI with administrator privileges." + ); + WinGetWarningBanner.IsClosable = true; + WinGetWarningBanner.IsOpen = true; + } + + if (!Settings.Get(Settings.K.ShownTelemetryBanner)) + { + TelemetryWarner.Title = CoreTools.Translate("Share anonymous usage data"); + TelemetryWarner.Message = CoreTools.Translate( + "UniGetUI collects anonymous usage data in order to improve the user experience." + ); + TelemetryWarner.IsClosable = true; + TelemetryWarner.ActionButtonText = CoreTools.Translate("Accept"); + TelemetryWarner.ActionButtonCommand = new CommunityToolkit.Mvvm.Input.RelayCommand(() => + { + TelemetryWarner.IsOpen = false; + Settings.Set(Settings.K.ShownTelemetryBanner, true); + }); + TelemetryWarner.OnClosed = () => Settings.Set(Settings.K.ShownTelemetryBanner, true); + TelemetryWarner.IsOpen = true; + } + + if (WasUpdatedSinceLastRun() && !Settings.Get(Settings.K.DisableReleaseNotesOnUpdate)) + { + NavigateTo(PageType.ReleaseNotes); + } + else + { + LoadDefaultPage(); + } + } + + // Returns true the first time the app runs after being updated to a newer build + private static bool WasUpdatedSinceLastRun() + { + _ = int.TryParse(Settings.GetValue(Settings.K.LastKnownBuildNumber), out int lastBuild); + + if (lastBuild != CoreData.BuildNumber) + { + Settings.SetValue(Settings.K.LastKnownBuildNumber, CoreData.BuildNumber.ToString()); + } + + return lastBuild != 0 && lastBuild < CoreData.BuildNumber; + } + + private void OnAnnouncementRequested(object? _, AccessibilityAnnouncement announcement) + { + AnnouncementLiveSetting = announcement.LiveSetting; + AnnouncementText = string.Empty; + Dispatcher.UIThread.Post( + () => AnnouncementText = announcement.Message, + DispatcherPriority.Background); + } + + // ─── Navigation ────────────────────────────────────────────────────────── + public void LoadDefaultPage() + { + PageType type = Settings.GetValue(Settings.K.StartupPage) switch + { + "discover" => PageType.Discover, + "updates" => PageType.Updates, + "installed" => PageType.Installed, + "bundles" => PageType.Bundles, + "settings" => PageType.Settings, + _ => UpgradablePackagesLoader.Instance is { } l && l.Count() > 0 ? PageType.Updates : PageType.Discover, + }; + NavigateTo(type); + } + + private Control GetPageForType(PageType type) => + type switch + { + PageType.Discover => DiscoverPage, + PageType.Updates => UpdatesPage, + PageType.Installed => InstalledPage, + PageType.Bundles => BundlesPage, + PageType.Settings => SettingsPage ??= new SettingsBasePage(false), + PageType.Managers => ManagersPage ??= new SettingsBasePage(true), + PageType.OwnLog => UniGetUILogPage ??= new UniGetUILogPage(), + PageType.ManagerLog => ManagerLogPage ??= new ManagerLogsPage(), + PageType.OperationHistory => OperationHistoryPage ??= new OperationHistoryPage(), + PageType.Help => HelpPage ??= new HelpPage(), + PageType.ReleaseNotes => ReleaseNotesPage ??= new ReleaseNotesPage(), + PageType.Null => throw new InvalidOperationException("Page type is Null"), + _ => throw new InvalidDataException($"Unknown page type {type}"), + }; + + public static PageType GetNextPage(PageType type) => + type switch + { + PageType.Discover => PageType.Updates, + PageType.Updates => PageType.Installed, + PageType.Installed => PageType.Bundles, + PageType.Bundles => PageType.Settings, + PageType.Settings => PageType.Managers, + PageType.Managers => PageType.Discover, + _ => PageType.Discover, + }; + + public static PageType GetPreviousPage(PageType type) => + type switch + { + PageType.Discover => PageType.Managers, + PageType.Updates => PageType.Discover, + PageType.Installed => PageType.Updates, + PageType.Bundles => PageType.Installed, + PageType.Settings => PageType.Bundles, + PageType.Managers => PageType.Settings, + _ => PageType.Discover, + }; + + public void NavigateTo(PageType newPage_t, bool toHistory = true) + { + if (newPage_t is PageType.About) { _ = ShowAboutDialog(); return; } + if (newPage_t is PageType.Quit) { MainWindow.Instance?.QuitApplication(); return; } + + if (_currentPage == newPage_t) + { + // Re-focus the primary control even when we're already on the page + (CurrentPageContent as AbstractPackagesPage)?.FocusPackageList(); + return; + } + + Sidebar.SelectNavButtonForPage(newPage_t); + + var newPage = GetPageForType(newPage_t); + var oldPage = CurrentPageContent as Control; + + if (oldPage is ISearchBoxPage oldSPage) + oldSPage.QueryBackup = GlobalSearchText; + (oldPage as IEnterLeaveListener)?.OnLeave(); + + CurrentPageContent = newPage; + _oldPage = _currentPage; + _currentPage = newPage_t; + + if (toHistory && _oldPage is not PageType.Null) + { + NavigationHistory.Add(_oldPage); + CanGoBackChanged?.Invoke(this, true); + } + + (newPage as AbstractPackagesPage)?.FilterPackages(); + (newPage as IEnterLeaveListener)?.OnEnter(); + + if (newPage is ISearchBoxPage newSPage) + { + SubscribeToPageViewModel(newPage as AbstractPackagesPage); + GlobalSearchText = newSPage.QueryBackup; + GlobalSearchPlaceholder = newSPage.SearchBoxPlaceholder; + GlobalSearchEnabled = true; + } + else + { + SubscribeToPageViewModel(null); + GlobalSearchText = ""; + GlobalSearchPlaceholder = ""; + GlobalSearchEnabled = false; + } + + // Focus after search state is restored so MegaQueryVisible is already correct + (newPage as AbstractPackagesPage)?.FocusPackageList(); + + AccessibilityAnnouncementService.Announce(GetPageAnnouncement(newPage_t)); + CurrentPageChanged?.Invoke(this, newPage_t); + } + + private static string GetPageAnnouncement(PageType pageType) => pageType switch + { + PageType.Discover => CoreTools.Translate("Discover Packages"), + PageType.Updates => CoreTools.Translate("Software Updates"), + PageType.Installed => CoreTools.Translate("Installed Packages"), + PageType.Bundles => CoreTools.Translate("Package Bundles"), + PageType.Settings => CoreTools.Translate("Settings"), + PageType.Managers => CoreTools.Translate("Package Managers"), + PageType.OwnLog => CoreTools.Translate("UniGetUI Log"), + PageType.ManagerLog => CoreTools.Translate("Package Manager logs"), + PageType.OperationHistory => CoreTools.Translate("Operation history"), + PageType.Help => CoreTools.Translate("Help"), + PageType.ReleaseNotes => CoreTools.Translate("Release notes"), + _ => CoreTools.Translate("UniGetUI"), + }; + + public void NavigateBack() + { + if (CurrentPageContent is IInnerNavigationPage navPage && navPage.CanGoBack()) + { + navPage.GoBack(); + } + else if (NavigationHistory.Count > 0) + { + NavigateTo(NavigationHistory.Last(), toHistory: false); + NavigationHistory.RemoveAt(NavigationHistory.Count - 1); + CanGoBackChanged?.Invoke(this, + NavigationHistory.Count > 0 + || ((CurrentPageContent as IInnerNavigationPage)?.CanGoBack() ?? false)); + } + } + + public void OpenManagerLogs(IPackageManager? manager = null) + { + NavigateTo(PageType.ManagerLog); + if (manager is not null) ManagerLogPage?.LoadForManager(manager); + } + + public void OpenManagerSettings(IPackageManager? manager = null) + { + NavigateTo(PageType.Managers); + if (manager is not null) ManagersPage?.NavigateTo(manager); + } + + public void OpenSettingsPage(Type page) + { + NavigateTo(PageType.Settings); + SettingsPage?.NavigateTo(page); + } + + public void ShowHelp(string uriAttachment = "") + { + NavigateTo(PageType.Help); + HelpPage?.NavigateTo(uriAttachment); + } + + public async Task LoadCloudBundleAsync(string content) + { + NavigateTo(PageType.Bundles); + await BundlesPage.OpenFromString(content, BundleFormatType.UBUNDLE, "GitHub Gist"); + } + + private async Task ShowAboutDialog() + { + Sidebar.SelectNavButtonForPage(PageType.Null); + var owner = (Application.Current?.ApplicationLifetime as IClassicDesktopStyleApplicationLifetime)?.MainWindow; + if (owner is not null) + await new AboutWindow().ShowDialog(owner); + Sidebar.SelectNavButtonForPage(_currentPage); + } + + // ─── Notification activation ───────────────────────────────────────────── + private void HandleNotificationActivation(string action) + { + if (action == NotificationArguments.UpdateAllPackages) + { + _ = AvaloniaPackageOperationHelper.UpdateAllAsync(); + } + else if (action == NotificationArguments.ShowOnUpdatesTab) + { + NavigateTo(PageType.Updates); + MainWindow.Instance?.ShowFromTray(); + } + else if (action == NotificationArguments.Show) + { + MainWindow.Instance?.ShowFromTray(); + } + else if (action == NotificationArguments.ReleaseSelfUpdateLock) + { + AvaloniaAutoUpdater.ReleaseLockForAutoupdate_Notification = true; + } + } + + // ─── Search box ────────────────────────────────────────────────────────── + [RelayCommand] + public void SubmitGlobalSearch() + { + if (CurrentPageContent is ISearchBoxPage page) + page.SearchBox_QuerySubmitted(this, EventArgs.Empty); + } +} diff --git a/src/UniGetUI.Avalonia/ViewModels/Pages/AboutPages/AboutPageViewModel.cs b/src/UniGetUI.Avalonia/ViewModels/Pages/AboutPages/AboutPageViewModel.cs new file mode 100644 index 0000000..36bdacc --- /dev/null +++ b/src/UniGetUI.Avalonia/ViewModels/Pages/AboutPages/AboutPageViewModel.cs @@ -0,0 +1,28 @@ +using CommunityToolkit.Mvvm.Input; +using UniGetUI.Core.Data; +using UniGetUI.Core.Tools; + +namespace UniGetUI.Avalonia.ViewModels.Pages.AboutPages; + +public partial class AboutPageViewModel : ViewModelBase +{ + public string VersionText { get; } = + CoreTools.Translate("You have installed UniGetUI Version {0}", CoreData.VersionName); + + public string DisclaimerTitle { get; } = CoreTools.Translate("Disclaimer"); + + public string DisclaimerMessage { get; } = CoreTools.Translate( + "UniGetUI is developed by Devolutions and is not affiliated with any of the compatible package managers."); + + [RelayCommand] + private static void OpenHomepage() => + CoreTools.Launch("https://devolutions.net/unigetui"); + + [RelayCommand] + private static void OpenIssues() => + CoreTools.Launch("https://github.com/Devolutions/UniGetUI/issues/new/choose"); + + [RelayCommand] + private static void OpenRepository() => + CoreTools.Launch("https://github.com/Devolutions/UniGetUI/"); +} diff --git a/src/UniGetUI.Avalonia/ViewModels/Pages/AboutPages/ContributorsViewModel.cs b/src/UniGetUI.Avalonia/ViewModels/Pages/AboutPages/ContributorsViewModel.cs new file mode 100644 index 0000000..ec1b244 --- /dev/null +++ b/src/UniGetUI.Avalonia/ViewModels/Pages/AboutPages/ContributorsViewModel.cs @@ -0,0 +1,60 @@ +using System.Collections.ObjectModel; +using Avalonia.Media.Imaging; +using CommunityToolkit.Mvvm.ComponentModel; +using UniGetUI.Core.Data; +using UniGetUI.Core.Tools; + +namespace UniGetUI.Avalonia.ViewModels.Pages.AboutPages; + +public partial class ContributorEntry : ObservableObject +{ + public string Name { get; init; } = ""; + public Uri? GitHubUrl { get; init; } + public bool HasGitHubProfile => GitHubUrl is not null; + + [ObservableProperty] private Bitmap? _profilePicture; + + private readonly Uri? _pictureUrl; + + public ContributorEntry(string name, Uri? gitHubUrl, Uri? pictureUrl) + { + Name = name; + GitHubUrl = gitHubUrl; + _pictureUrl = pictureUrl; + } + + public async Task LoadPictureAsync() + { + if (_pictureUrl is null) return; + try + { + using var http = new HttpClient(CoreTools.GenericHttpClientParameters); + var bytes = await http.GetByteArrayAsync(_pictureUrl); + using var ms = new MemoryStream(bytes); + ProfilePicture = new Bitmap(ms); + } + catch { } + } +} + +public class ContributorsViewModel : ViewModelBase +{ + public string ThanksText { get; } = CoreTools.Translate( + "UniGetUI wouldn't have been possible without the help of the contributors. Thank you all 🥳"); + + public ObservableCollection ContributorList { get; } = []; + + public ContributorsViewModel() + { + foreach (string contributor in ContributorsData.Contributors) + { + var entry = new ContributorEntry( + name: "@" + contributor, + gitHubUrl: new Uri("https://github.com/" + contributor), + pictureUrl: new Uri("https://github.com/" + contributor + ".png") + ); + ContributorList.Add(entry); + _ = entry.LoadPictureAsync(); + } + } +} diff --git a/src/UniGetUI.Avalonia/ViewModels/Pages/AboutPages/ThirdPartyLicensesViewModel.cs b/src/UniGetUI.Avalonia/ViewModels/Pages/AboutPages/ThirdPartyLicensesViewModel.cs new file mode 100644 index 0000000..54c620f --- /dev/null +++ b/src/UniGetUI.Avalonia/ViewModels/Pages/AboutPages/ThirdPartyLicensesViewModel.cs @@ -0,0 +1,37 @@ +using System.Collections.ObjectModel; +using UniGetUI.Core.Data; +using UniGetUI.Core.Tools; + +namespace UniGetUI.Avalonia.ViewModels.Pages.AboutPages; + +public class LibraryLicense +{ + public string Name { get; init; } = ""; + public string License { get; init; } = ""; + public Uri? LicenseURL { get; init; } + public string HomepageText { get; init; } = ""; + public Uri? HomepageUrl { get; init; } +} + +public class ThirdPartyLicensesViewModel : ViewModelBase +{ + public string LicensesIntro { get; } = CoreTools.Translate( + "UniGetUI uses the following libraries. Without them, UniGetUI wouldn't have been possible."); + + public ObservableCollection Licenses { get; } = []; + + public ThirdPartyLicensesViewModel() + { + foreach (string license in LicenseData.LicenseNames.Keys) + { + Licenses.Add(new LibraryLicense + { + Name = license, + License = LicenseData.LicenseNames[license], + LicenseURL = LicenseData.LicenseURLs[license], + HomepageUrl = LicenseData.HomepageUrls[license], + HomepageText = CoreTools.Translate("{0} homepage", license), + }); + } + } +} diff --git a/src/UniGetUI.Avalonia/ViewModels/Pages/AboutPages/TranslatorsViewModel.cs b/src/UniGetUI.Avalonia/ViewModels/Pages/AboutPages/TranslatorsViewModel.cs new file mode 100644 index 0000000..39fcc20 --- /dev/null +++ b/src/UniGetUI.Avalonia/ViewModels/Pages/AboutPages/TranslatorsViewModel.cs @@ -0,0 +1,63 @@ +using System.Collections.ObjectModel; +using Avalonia.Media.Imaging; +using CommunityToolkit.Mvvm.ComponentModel; +using UniGetUI.Core.Language; +using UniGetUI.Core.Tools; + +namespace UniGetUI.Avalonia.ViewModels.Pages.AboutPages; + +public partial class TranslatorEntry : ObservableObject +{ + public string Name { get; init; } = ""; + public string Language { get; init; } = ""; + public Uri? GitHubUrl { get; init; } + public bool HasGitHubProfile => GitHubUrl is not null; + + [ObservableProperty] private Bitmap? _profilePicture; + + private readonly Uri? _pictureUrl; + + public TranslatorEntry(string name, string language, Uri? gitHubUrl, Uri? pictureUrl) + { + Name = name; + Language = language; + GitHubUrl = gitHubUrl; + _pictureUrl = pictureUrl; + } + + public async Task LoadPictureAsync() + { + if (_pictureUrl is null) return; + try + { + using var http = new HttpClient(CoreTools.GenericHttpClientParameters); + var bytes = await http.GetByteArrayAsync(_pictureUrl); + using var ms = new MemoryStream(bytes); + ProfilePicture = new Bitmap(ms); + } + catch { } + } +} + +public class TranslatorsViewModel : ViewModelBase +{ + public string ThanksText { get; } = CoreTools.Translate( + "UniGetUI has been translated to more than 40 languages thanks to the volunteer translators. Thank you 🤝"); + + public ObservableCollection TranslatorList { get; } = []; + + public TranslatorsViewModel() + { + foreach (var person in LanguageData.TranslatorsList) + { + var entry = new TranslatorEntry( + name: person.Name, + language: person.Language, + gitHubUrl: person.GitHubUrl, + pictureUrl: person.ProfilePicture + ); + TranslatorList.Add(entry); + _ = entry.LoadPictureAsync(); + } + } +} diff --git a/src/UniGetUI.Avalonia/ViewModels/Pages/HelpPageViewModel.cs b/src/UniGetUI.Avalonia/ViewModels/Pages/HelpPageViewModel.cs new file mode 100644 index 0000000..53ecc39 --- /dev/null +++ b/src/UniGetUI.Avalonia/ViewModels/Pages/HelpPageViewModel.cs @@ -0,0 +1,17 @@ +using CommunityToolkit.Mvvm.Input; +using UniGetUI.Core.Tools; + +namespace UniGetUI.Avalonia.ViewModels.Pages; + +public partial class HelpPageViewModel : ViewModels.ViewModelBase +{ + public const string HelpBaseUrl = "https://github.com/Devolutions/UniGetUI"; + + // Kept in sync from the WebView's NavigationCompleted event via code-behind + public string CurrentUrl { get; set; } = HelpBaseUrl; + + [RelayCommand] + private void OpenInBrowser() => CoreTools.Launch(CurrentUrl); + + public string GetInitialUrl(string uriAttachment) => HelpBaseUrl; +} diff --git a/src/UniGetUI.Avalonia/ViewModels/Pages/LogPages/BaseLogPageViewModel.cs b/src/UniGetUI.Avalonia/ViewModels/Pages/LogPages/BaseLogPageViewModel.cs new file mode 100644 index 0000000..4a1749e --- /dev/null +++ b/src/UniGetUI.Avalonia/ViewModels/Pages/LogPages/BaseLogPageViewModel.cs @@ -0,0 +1,90 @@ +using System.Collections.ObjectModel; +using Avalonia.Media; +using CommunityToolkit.Mvvm.ComponentModel; +using CommunityToolkit.Mvvm.Input; +using UniGetUI.Core.Logging; +using UniGetUI.Core.Tools; + +namespace UniGetUI.Avalonia.ViewModels.Pages.LogPages; + +public abstract partial class BaseLogPageViewModel : ViewModels.ViewModelBase +{ + public ObservableCollection LogLines { get; } = new(); + public ObservableCollection LogLevelItems { get; } = new(); + + [ObservableProperty] + private bool _logLevelVisible; + + [ObservableProperty] + private int _selectedLogLevelIndex; + + partial void OnSelectedLogLevelIndexChanged(int value) => LoadLog(); + + // Events for view-layer operations (clipboard, file save, scroll) + public event EventHandler? CopyTextRequested; + public event EventHandler? ExportTextRequested; + public event EventHandler? ScrollToBottomRequested; + + protected BaseLogPageViewModel(bool logLevelEnabled, int initialLogLevelIndex = 0) + { + LogLevelVisible = logLevelEnabled; + _selectedLogLevelIndex = initialLogLevelIndex; + if (logLevelEnabled) + LoadLogLevels(); + } + + protected abstract void LoadLogLevels(); + public abstract void LoadLog(bool isReload = false); + + public void ClearLog() => LogLines.Clear(); + + protected static bool IsDark => Infrastructure.ThemeHelper.IsDark; + + protected static IBrush GetSeverityBrush(LogEntry.SeverityLevel severity, bool isDark) + { + var color = severity switch + { + LogEntry.SeverityLevel.Debug => isDark ? Color.FromRgb(130, 130, 130) : Color.FromRgb(125, 125, 225), + LogEntry.SeverityLevel.Info => isDark ? Color.FromRgb(190, 190, 190) : Color.FromRgb(50, 50, 150), + LogEntry.SeverityLevel.Success => isDark ? Color.FromRgb(250, 250, 250) : Color.FromRgb(0, 0, 0), + LogEntry.SeverityLevel.Warning => isDark ? Color.FromRgb(255, 255, 90) : Color.FromRgb(150, 150, 0), + LogEntry.SeverityLevel.Error => isDark ? Color.FromRgb(255, 80, 80) : Color.FromRgb(205, 0, 0), + _ => isDark ? Color.FromRgb(130, 130, 130) : Color.FromRgb(125, 125, 225), + }; + return new SolidColorBrush(color); + } + + protected static IBrush GetManagerColorBrush(char colorCode, bool isDark) + { + var color = colorCode switch + { + '0' => isDark ? Color.FromRgb(250, 250, 250) : Color.FromRgb(0, 0, 0), + '1' => isDark ? Color.FromRgb(190, 190, 190) : Color.FromRgb(50, 50, 150), + '2' => isDark ? Color.FromRgb(255, 80, 80) : Color.FromRgb(205, 0, 0), + '3' => isDark ? Color.FromRgb(120, 120, 255) : Color.FromRgb(0, 0, 205), + '4' => isDark ? Color.FromRgb(80, 255, 80) : Color.FromRgb(0, 205, 0), + '5' => isDark ? Color.FromRgb(255, 255, 90) : Color.FromRgb(150, 150, 0), + _ => isDark ? Color.FromRgb(255, 255, 90) : Color.FromRgb(150, 150, 0), + }; + return new SolidColorBrush(color); + } + + [RelayCommand] + private void Copy() + { + var text = string.Join("\n", LogLines.Select(l => l.Text)); + CopyTextRequested?.Invoke(this, text); + } + + [RelayCommand] + private void Export() + { + var text = string.Join("\n", LogLines.Select(l => l.Text)); + ExportTextRequested?.Invoke(this, text); + } + + [RelayCommand] + private void Reload() => LoadLog(isReload: true); + + protected void FireScrollToBottom() => ScrollToBottomRequested?.Invoke(this, EventArgs.Empty); +} diff --git a/src/UniGetUI.Avalonia/ViewModels/Pages/LogPages/LogLineItem.cs b/src/UniGetUI.Avalonia/ViewModels/Pages/LogPages/LogLineItem.cs new file mode 100644 index 0000000..a71beb7 --- /dev/null +++ b/src/UniGetUI.Avalonia/ViewModels/Pages/LogPages/LogLineItem.cs @@ -0,0 +1,15 @@ +using Avalonia.Media; + +namespace UniGetUI.Avalonia.ViewModels.Pages.LogPages; + +public class LogLineItem +{ + public string Text { get; } + public IBrush Foreground { get; } + + public LogLineItem(string text, IBrush foreground) + { + Text = text; + Foreground = foreground; + } +} diff --git a/src/UniGetUI.Avalonia/ViewModels/Pages/LogPages/ManagerLogsPageViewModel.cs b/src/UniGetUI.Avalonia/ViewModels/Pages/LogPages/ManagerLogsPageViewModel.cs new file mode 100644 index 0000000..19b12cb --- /dev/null +++ b/src/UniGetUI.Avalonia/ViewModels/Pages/LogPages/ManagerLogsPageViewModel.cs @@ -0,0 +1,89 @@ +using UniGetUI.Core.Tools; +using UniGetUI.PackageEngine; +using UniGetUI.PackageEngine.Interfaces; + +namespace UniGetUI.Avalonia.ViewModels.Pages.LogPages; + +public class ManagerLogsPageViewModel : BaseLogPageViewModel +{ + public ManagerLogsPageViewModel() : base(true) + { + LoadLog(); + } + + protected override void LoadLogLevels() + { + LogLevelItems.Clear(); + foreach (IPackageManager manager in PEInterface.Managers) + { + LogLevelItems.Add(manager.DisplayName); + LogLevelItems.Add($"{manager.DisplayName} ({CoreTools.Translate("Verbose")})"); + } + // SelectedLogLevelIndex defaults to 0 + } + + public void LoadForManager(IPackageManager manager) + { + bool isDark = IsDark; + bool verbose = LogLevelItems.Count > SelectedLogLevelIndex + && (LogLevelItems[SelectedLogLevelIndex]?.Contains(CoreTools.Translate("Verbose")) ?? false); + + if (!verbose) + { + int idx = LogLevelItems.IndexOf(manager.DisplayName); + if (idx >= 0) + SelectedLogLevelIndex = idx; + } + + LogLines.Clear(); + + LogLines.Add(new LogLineItem( + $"Manager {manager.DisplayName} with version:\n{manager.Status.Version}\n\n——————————————————————————————————————————\n", + GetManagerColorBrush('0', isDark))); + + foreach (var operation in manager.TaskLogger.Operations) + { + var lines = operation.AsColoredString(verbose).ToList(); + if (lines.Count == 0) continue; + + var sb = new System.Text.StringBuilder(); + bool first = true; + foreach (string line in lines) + { + if (line.Length == 0) continue; + char colorCode = line[0]; + string text = line[1..]; + if (!first) sb.Append('\n'); + sb.Append(text); + first = false; + + // Each colored segment is its own LogLineItem + if (sb.Length > 0) + { + LogLines.Add(new LogLineItem(sb.ToString(), GetManagerColorBrush(colorCode, isDark))); + sb.Clear(); + first = true; + } + } + } + } + + public override void LoadLog(bool isReload = false) + { + int idx = SelectedLogLevelIndex; + if (idx < 0 || idx >= LogLevelItems.Count) return; + + string selectedItem = LogLevelItems[idx]; + foreach (IPackageManager manager in PEInterface.Managers) + { + if (selectedItem.Contains(manager.DisplayName)) + { + LoadForManager(manager); + break; + } + } + + if (isReload) + FireScrollToBottom(); + } +} diff --git a/src/UniGetUI.Avalonia/ViewModels/Pages/LogPages/OperationHistoryPageViewModel.cs b/src/UniGetUI.Avalonia/ViewModels/Pages/LogPages/OperationHistoryPageViewModel.cs new file mode 100644 index 0000000..bbd22a3 --- /dev/null +++ b/src/UniGetUI.Avalonia/ViewModels/Pages/LogPages/OperationHistoryPageViewModel.cs @@ -0,0 +1,32 @@ +using Avalonia.Media; +using UniGetUI.Core.SettingsEngine; + +namespace UniGetUI.Avalonia.ViewModels.Pages.LogPages; + +public class OperationHistoryPageViewModel : BaseLogPageViewModel +{ + public OperationHistoryPageViewModel() : base(false) + { + LoadLog(); + } + + protected override void LoadLogLevels() { } + + public override void LoadLog(bool isReload = false) + { + bool isDark = IsDark; + var defaultBrush = new SolidColorBrush(isDark ? Color.FromRgb(250, 250, 250) : Color.FromRgb(0, 0, 0)); + + LogLines.Clear(); + + foreach (string line in Settings.GetValue(Settings.K.OperationHistory).Split("\n")) + { + string trimmed = line.Replace("\r", "").Replace("\n", "").Trim(); + if (trimmed == "") continue; + LogLines.Add(new LogLineItem(trimmed, defaultBrush)); + } + + if (isReload) + FireScrollToBottom(); + } +} diff --git a/src/UniGetUI.Avalonia/ViewModels/Pages/LogPages/UniGetUILogPageViewModel.cs b/src/UniGetUI.Avalonia/ViewModels/Pages/LogPages/UniGetUILogPageViewModel.cs new file mode 100644 index 0000000..8a3f3e3 --- /dev/null +++ b/src/UniGetUI.Avalonia/ViewModels/Pages/LogPages/UniGetUILogPageViewModel.cs @@ -0,0 +1,82 @@ +using UniGetUI.Core.Logging; +using UniGetUI.Core.Tools; + +namespace UniGetUI.Avalonia.ViewModels.Pages.LogPages; + +public class UniGetUILogPageViewModel : BaseLogPageViewModel +{ + public UniGetUILogPageViewModel() +#if DEBUG + : base(true, initialLogLevelIndex: 4) +#else + : base(true, initialLogLevelIndex: 3) +#endif + { + LoadLog(); + } + + protected override void LoadLogLevels() + { + LogLevelItems.Clear(); + LogLevelItems.Add(CoreTools.Translate("1 - Errors")); + LogLevelItems.Add(CoreTools.Translate("2 - Warnings")); + LogLevelItems.Add(CoreTools.Translate("3 - Information (less)")); + LogLevelItems.Add(CoreTools.Translate("4 - Information (more)")); + LogLevelItems.Add(CoreTools.Translate("5 - information (debug)")); + } + + public override void LoadLog(bool isReload = false) + { + bool isDark = IsDark; + int logLevel = SelectedLogLevelIndex + 1; + + LogLines.Clear(); + + foreach (LogEntry entry in Logger.GetLogs()) + { + if (entry.Content == "") + continue; + + if (ShouldSkip(entry.Severity, logLevel)) + continue; + + var brush = GetSeverityBrush(entry.Severity, isDark); + var sb = new System.Text.StringBuilder(); + bool first = true; + int dateLength = 0; + + foreach (string line in entry.Content.Split('\n')) + { + if (first) + { + string prefix = $"[{entry.Time}] "; + sb.Append(prefix).Append(line); + dateLength = prefix.Length; + first = false; + } + else + { + sb.Append('\n').Append(' ', dateLength).Append(line); + } + } + + LogLines.Add(new LogLineItem(sb.ToString(), brush)); + } + + if (isReload) + FireScrollToBottom(); + } + + private static bool ShouldSkip(LogEntry.SeverityLevel severity, int logLevel) => + logLevel switch + { + 1 => severity != LogEntry.SeverityLevel.Error, + 2 => severity is LogEntry.SeverityLevel.Debug + or LogEntry.SeverityLevel.Info + or LogEntry.SeverityLevel.Success, + 3 => severity is LogEntry.SeverityLevel.Debug + or LogEntry.SeverityLevel.Info, + 4 => severity == LogEntry.SeverityLevel.Debug, + _ => false, + }; +} diff --git a/src/UniGetUI.Avalonia/ViewModels/Pages/ReleaseNotesPageViewModel.cs b/src/UniGetUI.Avalonia/ViewModels/Pages/ReleaseNotesPageViewModel.cs new file mode 100644 index 0000000..575c9f1 --- /dev/null +++ b/src/UniGetUI.Avalonia/ViewModels/Pages/ReleaseNotesPageViewModel.cs @@ -0,0 +1,16 @@ +using CommunityToolkit.Mvvm.Input; +using UniGetUI.Core.Data; +using UniGetUI.Core.Tools; + +namespace UniGetUI.Avalonia.ViewModels.Pages; + +public partial class ReleaseNotesPageViewModel : ViewModels.ViewModelBase +{ + public string ReleaseNotesUrl { get; } = CoreData.ReleaseNotesUrl; + + // Kept in sync from the WebView's NavigationCompleted event via code-behind + public string CurrentUrl { get; set; } = CoreData.ReleaseNotesUrl; + + [RelayCommand] + private void OpenInBrowser() => CoreTools.Launch(CurrentUrl); +} diff --git a/src/UniGetUI.Avalonia/ViewModels/Pages/SettingsPages/AdministratorViewModel.cs b/src/UniGetUI.Avalonia/ViewModels/Pages/SettingsPages/AdministratorViewModel.cs new file mode 100644 index 0000000..3abd7ca --- /dev/null +++ b/src/UniGetUI.Avalonia/ViewModels/Pages/SettingsPages/AdministratorViewModel.cs @@ -0,0 +1,70 @@ +using CommunityToolkit.Mvvm.ComponentModel; +using CommunityToolkit.Mvvm.Input; +using UniGetUI.Avalonia.ViewModels; +using UniGetUI.Core.SettingsEngine; +using UniGetUI.Core.SettingsEngine.SecureSettings; +using UniGetUI.Core.Tools; + +namespace UniGetUI.Avalonia.ViewModels.Pages.SettingsPages; + +public partial class AdministratorViewModel : ViewModelBase +{ + public event EventHandler? RestartRequired; + + // ── Warning banner strings ──────────────────────────────────────────── + public string WarningTitle { get; } = CoreTools.Translate("Warning") + "!"; + + public string WarningBody1 { get; } = + CoreTools.Translate("The following settings may pose a security risk, hence they are disabled by default.") + + " " + + CoreTools.Translate("Enable the settings below if and only if you fully understand what they do, and the implications they may have."); + + public string WarningBody2 { get; } = + CoreTools.Translate("The settings will list, in their descriptions, the potential security issues they may have."); + + public bool IsWindows { get; } = OperatingSystem.IsWindows(); + + // ── Observable state ───────────────────────────────────────────────── + /// True when elevation is NOT prohibited — controls enabled-state of the cache-admin-rights cards. + [ObservableProperty] private bool _isElevationEnabled; + + /// Mirrors AllowCLIArguments toggle — controls IsEnabled of AllowImportingCLIArguments. + [ObservableProperty] private bool _isCLIArgumentsEnabled; + + /// Mirrors AllowPrePostOpCommand toggle — controls IsEnabled of AllowImportingPrePostInstallCommands. + [ObservableProperty] private bool _isPrePostCommandsEnabled; + + public AdministratorViewModel() + { + _isElevationEnabled = !Settings.Get(Settings.K.ProhibitElevation); + _isCLIArgumentsEnabled = SecureSettings.Get(SecureSettings.K.AllowCLIArguments); + _isPrePostCommandsEnabled = SecureSettings.Get(SecureSettings.K.AllowPrePostOpCommand); + } + + // ── Commands ───────────────────────────────────────────────────────── + + [RelayCommand] + private static void RestartCache() => _ = CoreTools.ResetUACForCurrentProcess(); + + [RelayCommand] + private void ShowRestartRequired() => RestartRequired?.Invoke(this, EventArgs.Empty); + + [RelayCommand] + private void RefreshElevationState() + { + IsElevationEnabled = !Settings.Get(Settings.K.ProhibitElevation); + RestartRequired?.Invoke(this, EventArgs.Empty); + } + + [RelayCommand] + private void RefreshCLIState() + { + IsCLIArgumentsEnabled = SecureSettings.Get(SecureSettings.K.AllowCLIArguments); + } + + [RelayCommand] + private void RefreshPrePostState() + { + IsPrePostCommandsEnabled = SecureSettings.Get(SecureSettings.K.AllowPrePostOpCommand); + } +} diff --git a/src/UniGetUI.Avalonia/ViewModels/Pages/SettingsPages/BackupViewModel.cs b/src/UniGetUI.Avalonia/ViewModels/Pages/SettingsPages/BackupViewModel.cs new file mode 100644 index 0000000..d2a79a2 --- /dev/null +++ b/src/UniGetUI.Avalonia/ViewModels/Pages/SettingsPages/BackupViewModel.cs @@ -0,0 +1,407 @@ +using Avalonia; +using Avalonia.Controls; +using Avalonia.Layout; +using Avalonia.Media; +using Avalonia.Media.Imaging; +using Avalonia.Platform.Storage; +using CommunityToolkit.Mvvm.ComponentModel; +using CommunityToolkit.Mvvm.Input; +using UniGetUI.Avalonia.Infrastructure; +using UniGetUI.Avalonia.Views; +using UniGetUI.Avalonia.Views.Pages; +using UniGetUI.Core.Data; +using UniGetUI.Core.Logging; +using UniGetUI.Core.Tools; +using UniGetUI.PackageEngine.PackageLoader; +using CoreSettings = UniGetUI.Core.SettingsEngine.Settings; + +namespace UniGetUI.Avalonia.ViewModels.Pages.SettingsPages; + +public partial class BackupViewModel : ViewModelBase, IDisposable +{ + public event EventHandler? RestartRequired; + + public IReadOnlyList InfoLines { get; } = + [ + " \u25cf " + CoreTools.Translate("The backup will include the complete list of the installed packages and their installation options. Ignored updates and skipped versions will also be saved."), + " \u25cf " + CoreTools.Translate("The backup will NOT include any binary file nor any program's saved data."), + " \u25cf " + CoreTools.Translate("The size of the backup is estimated to be less than 1MB."), + " \u25cf " + CoreTools.Translate("The backup will be performed after login."), + ]; + + /* ── Local backup ── */ + [ObservableProperty] private bool _isLocalBackupEnabled; + [ObservableProperty] private string _backupDirectoryLabel = ""; + + /* ── Cloud backup ── */ + [ObservableProperty] private bool _isLoggedIn; + [ObservableProperty] private bool _isLoginButtonEnabled = true; + [ObservableProperty] private bool _isCloudControlsEnabled; + [ObservableProperty] private bool _isCloudBackupNowEnabled; + [ObservableProperty] private string _gitHubUserTitle = ""; + [ObservableProperty] private string _gitHubUserSubtitle = ""; + [ObservableProperty] private IImage? _gitHubAvatarBitmap; + + private readonly GitHubAuthService _authService = new(); + private readonly CancellationTokenSource _lifetimeCancellation = new(); + private readonly CancellationToken _lifetimeToken; + private bool _isLoading; + private int _isDisposed; + private long _statusGeneration; + + public BackupViewModel() + { + _lifetimeToken = _lifetimeCancellation.Token; + _isLocalBackupEnabled = CoreSettings.Get(CoreSettings.K.EnablePackageBackup_LOCAL); + RefreshDirectoryLabel(); + + GitHubAuthService.AuthStatusChanged += OnAuthStatusChanged; + _ = UpdateGitHubLoginStatus(); + } + + private bool IsDisposed => Volatile.Read(ref _isDisposed) != 0; + + private bool CanApplyStatus(long generation) => + !IsDisposed + && !_lifetimeToken.IsCancellationRequested + && generation == Volatile.Read(ref _statusGeneration); + + private void OnAuthStatusChanged(object? sender, EventArgs e) + { + if (!IsDisposed) + _ = UpdateGitHubLoginStatus(); + } + + /* ─────────────── Local backup ─────────────── */ + + [RelayCommand] + private void EnableLocalBackupChanged() + { + if (IsDisposed) return; + IsLocalBackupEnabled = CoreSettings.Get(CoreSettings.K.EnablePackageBackup_LOCAL); + RestartRequired?.Invoke(this, EventArgs.Empty); + } + + private void RefreshDirectoryLabel() + { + if (IsDisposed) return; + string dir = CoreSettings.GetValue(CoreSettings.K.ChangeBackupOutputDirectory); + BackupDirectoryLabel = string.IsNullOrEmpty(dir) ? CoreData.UniGetUI_DefaultBackupDirectory : dir; + } + + [RelayCommand] + private async Task PickBackupDirectory(Visual? visual) + { + if (IsDisposed || visual is null || TopLevel.GetTopLevel(visual) is not { } topLevel) return; + var folders = await topLevel.StorageProvider.OpenFolderPickerAsync(new FolderPickerOpenOptions + { + AllowMultiple = false, + }); + if (IsDisposed || folders is not [{ } folder]) return; + var path = folder.TryGetLocalPath(); + if (path is null) return; + CoreSettings.SetValue(CoreSettings.K.ChangeBackupOutputDirectory, path); + RefreshDirectoryLabel(); + } + + [RelayCommand] + private static Task DoLocalBackup(Visual? _) => DoLocalBackupStatic(); + + public static async Task DoLocalBackupStatic() + { + try + { + var packages = InstalledPackagesLoader.Instance?.Packages.ToList() + ?? []; + string backupContents = await PackageBundlesPage.CreateBundle(packages); + + string dirName = CoreSettings.GetValue(CoreSettings.K.ChangeBackupOutputDirectory); + if (string.IsNullOrEmpty(dirName)) + dirName = CoreData.UniGetUI_DefaultBackupDirectory; + + if (!Directory.Exists(dirName)) + Directory.CreateDirectory(dirName); + + string fileName = CoreSettings.GetValue(CoreSettings.K.ChangeBackupFileName); + if (string.IsNullOrEmpty(fileName)) + fileName = CoreTools.Translate( + "{pcName} installed packages", + new Dictionary { { "pcName", Environment.MachineName } } + ); + + if (CoreSettings.Get(CoreSettings.K.EnableBackupTimestamping)) + fileName += " " + DateTime.Now.ToString("yyyy-MM-dd HH-mm-ss"); + + fileName += ".ubundle"; + + string filePath = Path.Combine(dirName, fileName); + await File.WriteAllTextAsync(filePath, backupContents); + Logger.ImportantInfo("Local backup saved to " + filePath); + } + catch (Exception ex) + { + Logger.Error("An error occurred while performing a LOCAL backup:"); + Logger.Error(ex); + } + } + + /* ─────────────── Cloud backup ─────────────── */ + + private async Task UpdateGitHubLoginStatus() + { + if (IsDisposed) return; + + long generation = Interlocked.Increment(ref _statusGeneration); + if (GitHubAuthService.IsAuthenticated()) + { + try { await GenerateLogoutState(generation); } + catch (OperationCanceledException) when (_lifetimeToken.IsCancellationRequested) + { + return; + } + catch (Exception ex) + { + if (!IsDisposed) + { + Logger.Error("An error occurred while attempting to generate settings login UI:"); + Logger.Error(ex); + } + GenerateLoginState(generation); + } + } + else + { + GenerateLoginState(generation); + } + + if (CanApplyStatus(generation)) + UpdateCloudControlsEnabled(); + } + + private void GenerateLoginState(long generation) + { + if (!CanApplyStatus(generation)) return; + + IsLoggedIn = false; + GitHubUserTitle = CoreTools.Translate("Current status: Not logged in"); + GitHubUserSubtitle = CoreTools.Translate("Log in to enable cloud backup"); + SetGitHubAvatarBitmap(null); + } + + private async Task GenerateLogoutState(long generation) + { + using var client = GitHubAuthService.CreateGitHubClient() + ?? throw new InvalidOperationException("Authenticated but cannot create GitHub client."); + var user = await client.GetCurrentUserAsync(); + if (!CanApplyStatus(generation)) return; + + IsLoggedIn = true; + string displayName = string.IsNullOrWhiteSpace(user.Name) ? user.Login : user.Name; + GitHubUserTitle = CoreTools.Translate("You are logged in as {0} (@{1})", displayName, user.Login); + GitHubUserSubtitle = CoreTools.Translate("Nice! Backups will be uploaded to a private gist on your account"); + + try + { + using var http = new HttpClient(CoreTools.GenericHttpClientParameters); + if (!string.IsNullOrWhiteSpace(user.AvatarUrl)) + { + var bytes = await http.GetByteArrayAsync(user.AvatarUrl, _lifetimeToken); + if (!CanApplyStatus(generation)) return; + + using var ms = new MemoryStream(bytes); + var bitmap = new Bitmap(ms); + if (CanApplyStatus(generation)) + SetGitHubAvatarBitmap(bitmap); + else + bitmap.Dispose(); + } + } + catch (OperationCanceledException) when (_lifetimeToken.IsCancellationRequested) + { + } + catch (Exception ex) + { + if (!IsDisposed) + { + Logger.Error("Failed to load GitHub avatar:"); + Logger.Error(ex); + } + } + } + + private void SetGitHubAvatarBitmap(IImage? bitmap) => GitHubAvatarBitmap = bitmap; + + private void UpdateCloudControlsEnabled() + { + if (IsDisposed) return; + + IsLoginButtonEnabled = !_isLoading; + IsCloudControlsEnabled = IsLoggedIn && !_isLoading; + IsCloudBackupNowEnabled = IsLoggedIn && !_isLoading + && CoreSettings.Get(CoreSettings.K.EnablePackageBackup_CLOUD); + } + + [RelayCommand] + private void EnableCloudBackupChanged() + { + if (IsDisposed) return; + RestartRequired?.Invoke(this, EventArgs.Empty); + UpdateCloudControlsEnabled(); + } + + [RelayCommand] + private async Task Login() + { + if (IsDisposed) return; + _isLoading = true; + UpdateCloudControlsEnabled(); + + bool success = await _authService.SignInAsync(); + if (!success && !IsDisposed) + Logger.Error("An error occurred while logging in to GitHub."); + + if (IsDisposed) return; + _isLoading = false; + UpdateCloudControlsEnabled(); + } + + [RelayCommand] + private void Logout() + { + if (IsDisposed) return; + _isLoading = true; + UpdateCloudControlsEnabled(); + + _authService.SignOut(); + + _isLoading = false; + UpdateCloudControlsEnabled(); + } + + [RelayCommand] + private async Task DoCloudBackup() + { + if (IsDisposed) return; + _isLoading = true; + UpdateCloudControlsEnabled(); + try { await DoCloudBackupStatic(); } + finally + { + _isLoading = false; + UpdateCloudControlsEnabled(); + } + } + + public static async Task DoCloudBackupStatic() + { + try + { + var packages = InstalledPackagesLoader.Instance?.Packages.ToList() ?? []; + string bundle = await PackageBundlesPage.CreateBundle(packages); + await GitHubCloudBackupService.UploadPackageBundleAsync(bundle); + Logger.ImportantInfo("Cloud backup completed successfully."); + } + catch (Exception ex) + { + Logger.Error("An error occurred while performing a CLOUD backup:"); + Logger.Error(ex); + } + } + + [RelayCommand] + private static async Task RestoreFromCloud() + { + try + { + var backups = await GitHubCloudBackupService.GetAvailableBackupsAsync(); + if (backups.Count == 0) + { + Logger.Warn("No cloud backups found for this account."); + return; + } + + string? selectedKey = await AskForBackupSelectionAsync(backups); + if (selectedKey is null) return; + + string contents = await GitHubCloudBackupService.GetBackupContentsAsync(selectedKey); + + if (MainWindow.Instance?.DataContext is MainWindowViewModel vm) + await vm.LoadCloudBundleAsync(contents); + } + catch (Exception ex) + { + Logger.Error("An error occurred while restoring from cloud backup:"); + Logger.Error(ex); + } + } + + private static async Task AskForBackupSelectionAsync( + IReadOnlyList backups) + { + if (MainWindow.Instance is not { } owner) return null; + + var combo = new ComboBox + { + ItemsSource = backups.Select(b => b.Display).ToList(), + SelectedIndex = 0, + Width = 360, + }; + + var dialog = new Window + { + Title = CoreTools.Translate("Select backup"), + Width = 440, + Height = 160, + CanResize = false, + WindowStartupLocation = WindowStartupLocation.CenterOwner, + Content = new StackPanel + { + Margin = new Thickness(20), + Spacing = 16, + Children = + { + combo, + new StackPanel + { + Orientation = Orientation.Horizontal, + HorizontalAlignment = HorizontalAlignment.Right, + Spacing = 8, + Children = + { + new Button { Content = CoreTools.Translate("Cancel") }, + new Button { Content = CoreTools.Translate("Select backup"), Classes = { "accent" } }, + } + } + } + } + }; + + string? result = null; + var buttons = ((StackPanel)((StackPanel)dialog.Content).Children[1]).Children; + ((Button)buttons[0]).Click += (_, _) => dialog.Close(); + ((Button)buttons[1]).Click += (_, _) => + { + result = backups[combo.SelectedIndex].Key; + dialog.Close(); + }; + + await dialog.ShowDialog(owner); + return result; + } + + [RelayCommand] + private static void MoreDetails() + { + CoreTools.Launch("https://devolutions.net/unigetui"); + } + + public void Dispose() + { + if (Interlocked.Exchange(ref _isDisposed, 1) != 0) return; + + GitHubAuthService.AuthStatusChanged -= OnAuthStatusChanged; + // In-flight HTTP work can still observe this token. Cancelling is sufficient; + // disposing the source here could race with that work. + _lifetimeCancellation.Cancel(); + } +} diff --git a/src/UniGetUI.Avalonia/ViewModels/Pages/SettingsPages/ExperimentalViewModel.cs b/src/UniGetUI.Avalonia/ViewModels/Pages/SettingsPages/ExperimentalViewModel.cs new file mode 100644 index 0000000..47f1031 --- /dev/null +++ b/src/UniGetUI.Avalonia/ViewModels/Pages/SettingsPages/ExperimentalViewModel.cs @@ -0,0 +1,14 @@ +using CommunityToolkit.Mvvm.Input; +using UniGetUI.Avalonia.ViewModels; + +namespace UniGetUI.Avalonia.ViewModels.Pages.SettingsPages; + +public partial class ExperimentalViewModel : ViewModelBase +{ + public bool IsWindows { get; } = OperatingSystem.IsWindows(); + + public event EventHandler? RestartRequired; + + [RelayCommand] + private void ShowRestartRequired() => RestartRequired?.Invoke(this, EventArgs.Empty); +} diff --git a/src/UniGetUI.Avalonia/ViewModels/Pages/SettingsPages/GeneralViewModel.cs b/src/UniGetUI.Avalonia/ViewModels/Pages/SettingsPages/GeneralViewModel.cs new file mode 100644 index 0000000..c33dad3 --- /dev/null +++ b/src/UniGetUI.Avalonia/ViewModels/Pages/SettingsPages/GeneralViewModel.cs @@ -0,0 +1,99 @@ +using System.IO; +using Avalonia.Automation; +using CommunityToolkit.Mvvm.ComponentModel; +using CommunityToolkit.Mvvm.Input; +using global::Avalonia; +using global::Avalonia.Controls; +using global::Avalonia.Platform.Storage; +using UniGetUI.Avalonia.Infrastructure; +using UniGetUI.Avalonia.ViewModels; +using UniGetUI.Avalonia.Views.DialogPages; +using UniGetUI.Avalonia.Views.Pages.SettingsPages; +using UniGetUI.Core.Logging; +using UniGetUI.Core.Tools; +using CoreSettings = global::UniGetUI.Core.SettingsEngine.Settings; + +namespace UniGetUI.Avalonia.ViewModels.Pages.SettingsPages; + +public partial class GeneralViewModel : ViewModelBase +{ + [RelayCommand] + private static async Task ShowTelemetryDialog(Visual? visual) + { + if (visual is null || TopLevel.GetTopLevel(visual) is not Window owner) return; + var dialog = new TelemetryDialog(); + await dialog.ShowDialog(owner); + if (dialog.Result.HasValue) + CoreSettings.Set(CoreSettings.K.DisableTelemetry, !dialog.Result.Value); + } + + [RelayCommand] + private async Task ImportSettings(Visual? visual) + { + if (visual is null || TopLevel.GetTopLevel(visual) is not { } topLevel) return; + var files = await topLevel.StorageProvider.OpenFilePickerAsync(new FilePickerOpenOptions + { + AllowMultiple = false, + FileTypeFilter = [new FilePickerFileType("Settings JSON") { Patterns = ["*.json"] }], + }); + if (files is not [{ } file]) return; + var path = file.TryGetLocalPath(); + if (path is null) return; + await Task.Run(() => CoreSettings.ImportFromFile_JSON(path)); + AccessibilityAnnouncementService.Announce( + CoreTools.Translate("Settings imported from {0}", Path.GetFileName(path)), + AutomationLiveSetting.Polite); + OnRestartRequired(); + } + + [RelayCommand] + private static async Task ExportSettings(Visual? visual) + { + if (visual is null || TopLevel.GetTopLevel(visual) is not { } topLevel) return; + var file = await topLevel.StorageProvider.SaveFilePickerAsync(new FilePickerSaveOptions + { + SuggestedFileName = CoreTools.Translate("UniGetUI Settings") + ".json", + FileTypeChoices = [new FilePickerFileType("Settings JSON") { Patterns = ["*.json"] }], + }); + if (file is null) return; + var path = file.TryGetLocalPath(); + if (path is null) return; + try + { + await Task.Run(() => CoreSettings.ExportToFile_JSON(path)); + AccessibilityAnnouncementService.Announce( + CoreTools.Translate("Settings exported to {0}", Path.GetFileName(path)), + AutomationLiveSetting.Polite); + } + catch (Exception ex) { Logger.Error(ex); } + } + + [RelayCommand] + private void ResetSettings(Visual? _) + { + try { CoreSettings.ResetSettings(); } + catch (Exception ex) { Logger.Error(ex); } + AccessibilityAnnouncementService.Announce( + CoreTools.Translate("UniGetUI settings were reset"), + AutomationLiveSetting.Assertive); + OnRestartRequired(); + } + + public event EventHandler? RestartRequired; + public event EventHandler? NavigationRequested; + + private void OnRestartRequired() => RestartRequired?.Invoke(this, EventArgs.Empty); + + [RelayCommand] + private void ShowRestartRequired() => RestartRequired?.Invoke(this, EventArgs.Empty); + + [RelayCommand] + private void ToggleRedactUsername() + { + Logger.RedactUsername = CoreSettings.Get(CoreSettings.K.RedactUsernameInLog); + OnRestartRequired(); + } + + [RelayCommand] + private void NavigateToInterface() => NavigationRequested?.Invoke(this, typeof(Interface_P)); +} diff --git a/src/UniGetUI.Avalonia/ViewModels/Pages/SettingsPages/InstallOptionsPanelViewModel.cs b/src/UniGetUI.Avalonia/ViewModels/Pages/SettingsPages/InstallOptionsPanelViewModel.cs new file mode 100644 index 0000000..9f145aa --- /dev/null +++ b/src/UniGetUI.Avalonia/ViewModels/Pages/SettingsPages/InstallOptionsPanelViewModel.cs @@ -0,0 +1,302 @@ +using System.Collections.ObjectModel; +using Avalonia; +using Avalonia.Controls; +using Avalonia.Platform.Storage; +using CommunityToolkit.Mvvm.ComponentModel; +using CommunityToolkit.Mvvm.Input; +using UniGetUI.Core.Language; +using UniGetUI.Core.SettingsEngine.SecureSettings; +using UniGetUI.Core.Tools; +using UniGetUI.PackageEngine.Enums; +using UniGetUI.PackageEngine.Interfaces; +using UniGetUI.PackageEngine.PackageClasses; +using UniGetUI.PackageEngine.Serializable; + +namespace UniGetUI.Avalonia.ViewModels.Pages.SettingsPages; + +public partial class InstallOptionsPanelViewModel : ViewModelBase +{ + private readonly IPackageManager _manager; + private readonly string _defaultLocationLabel; + + public event EventHandler? NavigateToAdministratorRequested; + + // ── Loading state ───────────────────────────────────────────────────────── + [ObservableProperty] private bool _isLoading = true; + [ObservableProperty] private bool _hasChanges; + + // ── Checkbox enabled + checked ──────────────────────────────────────────── + [ObservableProperty] private bool _adminEnabled; + [ObservableProperty] private bool _adminChecked; + + [ObservableProperty] private bool _interactiveEnabled; + [ObservableProperty] private bool _interactiveChecked; + + [ObservableProperty] private bool _skipHashEnabled; + [ObservableProperty] private bool _skipHashChecked; + + [ObservableProperty] private bool _preReleaseEnabled; + [ObservableProperty] private bool _preReleaseChecked; + + [ObservableProperty] private bool _uninstallPreviousEnabled; + [ObservableProperty] private bool _uninstallPreviousChecked; + + // ── Architecture ────────────────────────────────────────────────────────── + [ObservableProperty] private bool _architectureEnabled; + [ObservableProperty] private ObservableCollection _architectureItems = []; + [ObservableProperty] private string? _selectedArchitecture; + + // ── Scope ───────────────────────────────────────────────────────────────── + [ObservableProperty] private bool _scopeEnabled; + [ObservableProperty] private ObservableCollection _scopeItems = []; + [ObservableProperty] private string? _selectedScope; + + // ── Location ────────────────────────────────────────────────────────────── + [ObservableProperty] private bool _locationSelectEnabled; + [ObservableProperty] private bool _locationResetEnabled; + [ObservableProperty] private string _locationText = ""; + + // ── CLI args ────────────────────────────────────────────────────────────── + [ObservableProperty] private bool _cliSectionEnabled; + [ObservableProperty] private bool _cliDisabledWarningVisible; + [ObservableProperty] private string _customInstall = ""; + [ObservableProperty] private string _customUpdate = ""; + [ObservableProperty] private string _customUninstall = ""; + + // ── Translated labels (static) ──────────────────────────────────────────── + public string AdminLabel { get; } = CoreTools.Translate("Run as admin"); + public string InteractiveLabel { get; } = CoreTools.Translate("Interactive installation"); + public string SkipHashLabel { get; } = CoreTools.Translate("Skip hash check"); + public string PreReleaseLabel { get; } = CoreTools.Translate("Allow pre-release versions"); + public string UninstallPrevLabel { get; } = CoreTools.Translate("Uninstall previous versions when updated"); + public string ArchLabel { get; } = CoreTools.Translate("Architecture to install:"); + public string ScopeLabel { get; } = CoreTools.Translate("Installation scope:"); + public string LocationLabel { get; } = CoreTools.Translate("Install location:"); + public string SelectDirLabel { get; } = CoreTools.Translate("Select"); + public string ResetDirLabel { get; } = CoreTools.Translate("Reset"); + public string InstallArgsLabel { get; } = CoreTools.Translate("Custom install arguments:"); + public string UpdateArgsLabel { get; } = CoreTools.Translate("Custom update arguments:"); + public string UninstallArgsLabel { get; } = CoreTools.Translate("Custom uninstall arguments:"); + public string CliArgsHintLabel { get; } = CoreTools.Translate("These fields are independent: an argument set for Install won't apply to Update or Uninstall, and vice versa."); + public string CopyInstallArgsLabel { get; } = CoreTools.Translate("Copy install arguments to update and uninstall"); + public string ResetLabel { get; } = CoreTools.Translate("Reset"); + public string ApplyLabel { get; } = CoreTools.Translate("Apply"); + public string CliDisabledLabel { get; } = CoreTools.Translate("For security reasons, custom command-line arguments are disabled by default. Go to UniGetUI security settings to change this."); + public string GoToSecurityLabel { get; } = CoreTools.Translate("Go to UniGetUI security settings"); + + public string HeaderText => CoreTools.Translate( + "The following options will be applied by default each time a {0} package is installed, upgraded or uninstalled.", + _manager.DisplayName); + + public double CliOpacity => CliSectionEnabled ? 1.0 : 0.5; + public double ArchOpacity => ArchitectureEnabled ? 1.0 : 0.5; + public double ScopeOpacity => ScopeEnabled ? 1.0 : 0.5; + public double LocationOpacity => LocationSelectEnabled ? 1.0 : 0.5; + + partial void OnCliSectionEnabledChanged(bool value) => OnPropertyChanged(nameof(CliOpacity)); + partial void OnArchitectureEnabledChanged(bool value) => OnPropertyChanged(nameof(ArchOpacity)); + partial void OnScopeEnabledChanged(bool value) => OnPropertyChanged(nameof(ScopeOpacity)); + partial void OnLocationSelectEnabledChanged(bool value) => OnPropertyChanged(nameof(LocationOpacity)); + + // Mark HasChanges when user edits options (guards against firing during load) + partial void OnAdminCheckedChanged(bool value) => HasChanges = !IsLoading; + partial void OnInteractiveCheckedChanged(bool value) => HasChanges = !IsLoading; + partial void OnSkipHashCheckedChanged(bool value) => HasChanges = !IsLoading; + partial void OnPreReleaseCheckedChanged(bool value) => HasChanges = !IsLoading; + partial void OnUninstallPreviousCheckedChanged(bool value) => HasChanges = !IsLoading; + partial void OnSelectedArchitectureChanged(string? value) => HasChanges = !IsLoading; + partial void OnSelectedScopeChanged(string? value) => HasChanges = !IsLoading; + + public InstallOptionsPanelViewModel(IPackageManager manager) + { + _manager = manager; + _defaultLocationLabel = CoreTools.Translate("Package's default"); + + // Architecture items — always show Default + any supported archs + _architectureItems.Add(CoreTools.Translate("Default")); + foreach (var arch in manager.Capabilities.SupportedCustomArchitectures) + _architectureItems.Add(arch); + + // Scope items — always show Default + Local + Global + _scopeItems.Add(CoreTools.Translate("Default")); + _scopeItems.Add(CoreTools.Translate(CommonTranslations.ScopeNames[PackageScope.Local])); + _scopeItems.Add(CoreTools.Translate(CommonTranslations.ScopeNames[PackageScope.Global])); + + _ = DoLoadOptions(); + } + + // ── Load / Save / Reset ─────────────────────────────────────────────────── + + [RelayCommand] + private Task LoadOptions() => DoLoadOptions(); + + [RelayCommand] + private async Task SaveOptions() + { + IsLoading = true; + DisableAllInput(); + + var options = new InstallOptions + { + RunAsAdministrator = AdminChecked, + SkipHashCheck = SkipHashChecked, + InteractiveInstallation = InteractiveChecked, + PreRelease = PreReleaseChecked, + UninstallPreviousVersionsOnUpdate = UninstallPreviousChecked, + }; + + if (_manager.Capabilities.SupportsCustomArchitectures && + SelectedArchitecture is { } arch && + _manager.Capabilities.SupportedCustomArchitectures.Contains(arch)) + options.Architecture = arch; + + if (_manager.Capabilities.SupportsCustomScopes && SelectedScope is { } scope) + if (CommonTranslations.InvertedScopeNames.TryGetValue(scope, out string? scopeVal)) + options.InstallationScope = scopeVal; + + if (_manager.Capabilities.SupportsCustomLocations && + LocationText != _defaultLocationLabel) + options.CustomInstallLocation = LocationText; + + options.CustomParameters_Install = CustomInstall.Split(' ').Where(x => x.Any()).ToList(); + options.CustomParameters_Update = CustomUpdate.Split(' ').Where(x => x.Any()).ToList(); + options.CustomParameters_Uninstall = CustomUninstall.Split(' ').Where(x => x.Any()).ToList(); + + await InstallOptionsFactory.SaveForManagerAsync(options, _manager); + await DoLoadOptions(); + } + + [RelayCommand] + private async Task ResetOptions() + { + IsLoading = true; + DisableAllInput(); + await InstallOptionsFactory.SaveForManagerAsync(new InstallOptions(), _manager); + await DoLoadOptions(); + } + + private void DisableAllInput() + { + AdminEnabled = false; + InteractiveEnabled = false; + SkipHashEnabled = false; + PreReleaseEnabled = false; + UninstallPreviousEnabled = false; + ArchitectureEnabled = false; + ScopeEnabled = false; + LocationSelectEnabled = false; + LocationResetEnabled = false; + CliSectionEnabled = false; + } + + private async Task DoLoadOptions() + { + IsLoading = true; + HasChanges = false; + DisableAllInput(); + + var options = await InstallOptionsFactory.LoadForManagerAsync(_manager); + await Task.Delay(300); + + // Checkboxes — load value, then set enabled per capability + AdminChecked = options.RunAsAdministrator; + AdminEnabled = OperatingSystem.IsWindows(); + + InteractiveChecked = options.InteractiveInstallation; + InteractiveEnabled = _manager.Capabilities.CanRunInteractively; + + SkipHashChecked = options.SkipHashCheck; + SkipHashEnabled = _manager.Capabilities.CanSkipIntegrityChecks; + + PreReleaseChecked = options.PreRelease; + PreReleaseEnabled = _manager.Capabilities.SupportsPreRelease; + + UninstallPreviousChecked = options.UninstallPreviousVersionsOnUpdate; + UninstallPreviousEnabled = _manager.Capabilities.CanUninstallPreviousVersionsAfterUpdate; + + // Architecture + ArchitectureEnabled = _manager.Capabilities.SupportsCustomArchitectures; + string? matchedArch = ArchitectureItems.Contains(options.Architecture) ? options.Architecture : null; + SelectedArchitecture = matchedArch ?? ArchitectureItems.FirstOrDefault(); + + // Scope + ScopeEnabled = _manager.Capabilities.SupportsCustomScopes; + string? matchedScope = null; + if (!string.IsNullOrEmpty(options.InstallationScope) && + CommonTranslations.ScopeNames.TryGetValue(options.InstallationScope, out string? display)) + { + string translated = CoreTools.Translate(display); + if (ScopeItems.Contains(translated)) matchedScope = translated; + } + SelectedScope = matchedScope ?? ScopeItems.FirstOrDefault(); + + // Location + LocationSelectEnabled = _manager.Capabilities.SupportsCustomLocations; + if (!string.IsNullOrEmpty(options.CustomInstallLocation)) + { + LocationText = options.CustomInstallLocation; + LocationResetEnabled = true; + } + else + { + LocationText = _manager.Capabilities.SupportsCustomLocations + ? _defaultLocationLabel + : CoreTools.Translate("Install location can't be changed for {0} packages", _manager.DisplayName); + LocationResetEnabled = false; + } + + // CLI + bool isCLI = SecureSettings.Get(SecureSettings.K.AllowCLIArguments); + CliSectionEnabled = isCLI; + CliDisabledWarningVisible = !isCLI; + CustomInstall = string.Join(' ', options.CustomParameters_Install); + CustomUpdate = string.Join(' ', options.CustomParameters_Update); + CustomUninstall = string.Join(' ', options.CustomParameters_Uninstall); + + IsLoading = false; + } + + // ── Location picker ─────────────────────────────────────────────────────── + + [RelayCommand] + private async Task SelectLocation(Visual? visual) + { + if (visual is null || TopLevel.GetTopLevel(visual) is not { } topLevel) return; + var folders = await topLevel.StorageProvider.OpenFolderPickerAsync( + new FolderPickerOpenOptions { AllowMultiple = false }); + if (folders is not [{ } folder]) return; + var path = folder.TryGetLocalPath(); + if (string.IsNullOrEmpty(path)) return; + LocationText = path.TrimEnd('/').TrimEnd('\\') + "/%PACKAGE%"; + LocationResetEnabled = true; + HasChanges = true; + } + + [RelayCommand] + private void ResetLocation() + { + LocationText = _defaultLocationLabel; + LocationResetEnabled = false; + HasChanges = true; + } + + // ── Navigation ──────────────────────────────────────────────────────────── + + [RelayCommand] + private void NavigateToAdministrator() => + NavigateToAdministratorRequested?.Invoke(this, EventArgs.Empty); + + // ── CLI args convenience ───────────────────────────────────────────────── + + [RelayCommand] + private void CopyInstallArgsToOthers() + { + CustomUpdate = CustomInstall; + CustomUninstall = CustomInstall; + HasChanges = true; + } + + // ── Mark changed ───────────────────────────────────────────────────────── + + public void MarkChanged() => HasChanges = true; +} diff --git a/src/UniGetUI.Avalonia/ViewModels/Pages/SettingsPages/Interface_PViewModel.cs b/src/UniGetUI.Avalonia/ViewModels/Pages/SettingsPages/Interface_PViewModel.cs new file mode 100644 index 0000000..bc74d87 --- /dev/null +++ b/src/UniGetUI.Avalonia/ViewModels/Pages/SettingsPages/Interface_PViewModel.cs @@ -0,0 +1,50 @@ +using CommunityToolkit.Mvvm.ComponentModel; +using CommunityToolkit.Mvvm.Input; +using global::Avalonia; +using global::Avalonia.Controls; +using UniGetUI.Avalonia.ViewModels; +using UniGetUI.Avalonia.Views; +using UniGetUI.Core.Data; +using UniGetUI.Core.Logging; +using UniGetUI.Core.Tools; + +namespace UniGetUI.Avalonia.ViewModels.Pages.SettingsPages; + +public partial class Interface_PViewModel : ViewModelBase +{ + public bool IsWindows { get; } = OperatingSystem.IsWindows(); + + [ObservableProperty] private string _iconCacheSizeText = ""; + + public event EventHandler? RestartRequired; + + [RelayCommand] + private void ShowRestartRequired() => RestartRequired?.Invoke(this, EventArgs.Empty); + + [RelayCommand] + private static void EditAutostartSettings() + => CoreTools.Launch("ms-settings:startupapps"); + + [RelayCommand] + private static void RefreshSystemTray() + => MainWindow.Instance?.UpdateSystemTrayStatus(); + + [RelayCommand] + private async Task ResetIconCache(Visual? _) + { + try { Directory.Delete(CoreData.UniGetUICacheDirectory_Icons, true); } + catch (Exception ex) { Logger.Error(ex); } + global::UniGetUI.PackageEngine.PackageClasses.PackageWrapper.ClearIconCache(); + RestartRequired?.Invoke(this, EventArgs.Empty); + await LoadIconCacheSize(); + } + + public async Task LoadIconCacheSize() + { + double realSize = (await Task.Run(() => + Directory.GetFiles(CoreData.UniGetUICacheDirectory_Icons, "*", SearchOption.AllDirectories) + .Sum(f => new FileInfo(f).Length))) / 1048576d; + double rounded = ((int)(realSize * 100)) / 100d; + IconCacheSizeText = CoreTools.Translate("The local icon cache currently takes {0} MB", rounded); + } +} diff --git a/src/UniGetUI.Avalonia/ViewModels/Pages/SettingsPages/InternetViewModel.cs b/src/UniGetUI.Avalonia/ViewModels/Pages/SettingsPages/InternetViewModel.cs new file mode 100644 index 0000000..b2e0f3c --- /dev/null +++ b/src/UniGetUI.Avalonia/ViewModels/Pages/SettingsPages/InternetViewModel.cs @@ -0,0 +1,231 @@ +using Avalonia; +using Avalonia.Controls; +using Avalonia.Layout; +using Avalonia.Media; +using CommunityToolkit.Mvvm.ComponentModel; +using CommunityToolkit.Mvvm.Input; +using UniGetUI.Avalonia.ViewModels; +using UniGetUI.Avalonia.Views.Controls.Settings; +using UniGetUI.Core.Tools; +using UniGetUI.PackageEngine; +using UniGetUI.PackageEngine.ManagerClasses.Manager; +using CoreSettings = global::UniGetUI.Core.SettingsEngine.Settings; + +namespace UniGetUI.Avalonia.ViewModels.Pages.SettingsPages; + +public partial class InternetViewModel : ViewModelBase +{ + public event EventHandler? RestartRequired; + + private TextBox? _usernameBox; + private TextBox? _passwordBox; + private ProgressBar? _savingIndicator; + + [ObservableProperty] private bool _isProxyEnabled; + [ObservableProperty] private bool _isProxyAuthEnabled; + + public InternetViewModel() + { + _isProxyEnabled = CoreSettings.Get(CoreSettings.K.EnableProxy); + _isProxyAuthEnabled = CoreSettings.Get(CoreSettings.K.EnableProxyAuth); + } + + public SettingsCard BuildCredentialsCard() + { + _savingIndicator = new ProgressBar + { + IsIndeterminate = false, + Opacity = 0, + Margin = new Thickness(0, -8, 0, 0), + }; + + _usernameBox = new TextBox + { + PlaceholderText = CoreTools.Translate("Username"), + MinWidth = 200, + Margin = new Thickness(0, 0, 0, 4), + }; + + _passwordBox = new TextBox + { + PlaceholderText = CoreTools.Translate("Password"), + MinWidth = 200, + PasswordChar = '●', + }; + + var creds = CoreSettings.GetProxyCredentials(); + if (creds is not null) + { + _usernameBox.Text = creds.UserName; + _passwordBox.Text = creds.Password; + } + + _usernameBox.TextChanged += (_, _) => _ = SaveCredentialsAsync(); + _passwordBox.TextChanged += (_, _) => _ = SaveCredentialsAsync(); + + var stack = new StackPanel { Orientation = Orientation.Vertical }; + stack.Children.Add(_savingIndicator); + stack.Children.Add(_usernameBox); + stack.Children.Add(_passwordBox); + + return new SettingsCard + { + CornerRadius = new CornerRadius(0, 0, 8, 8), + BorderThickness = new Thickness(1, 0, 1, 1), + Header = CoreTools.Translate("Credentials"), + Description = CoreTools.Translate("It is not guaranteed that the provided credentials will be stored safely"), + Content = stack, + }; + } + + public Control BuildProxyCompatTable() + { + var noStr = CoreTools.Translate("No"); + var yesStr = CoreTools.Translate("Yes"); + var partStr = CoreTools.Translate("Partially"); + + var managers = PEInterface.Managers.ToList(); + + // Single unified grid: row 0 = column headers, rows 1..N = data rows. + // All columns are shared, so widths are consistent throughout. + var table = new Grid + { + ColumnDefinitions = new ColumnDefinitions("Auto,Auto,Auto"), + ColumnSpacing = 24, + RowSpacing = 8, + }; + for (int i = 0; i <= managers.Count; i++) + table.RowDefinitions.Add(new RowDefinition(GridLength.Auto)); + + // Header row (row 0) + var h1 = new TextBlock { Text = CoreTools.Translate("Package manager"), FontWeight = FontWeight.Bold, TextWrapping = TextWrapping.Wrap }; + var h2 = new TextBlock { Text = CoreTools.Translate("Compatible with proxy"), FontWeight = FontWeight.Bold, TextWrapping = TextWrapping.Wrap, HorizontalAlignment = HorizontalAlignment.Center }; + var h3 = new TextBlock { Text = CoreTools.Translate("Compatible with authentication"), FontWeight = FontWeight.Bold, TextWrapping = TextWrapping.Wrap, HorizontalAlignment = HorizontalAlignment.Center }; + SetCell(h1, 0, 0); SetCell(h2, 0, 1); SetCell(h3, 0, 2); + table.Children.Add(h1); table.Children.Add(h2); table.Children.Add(h3); + + // Data rows + for (int i = 0; i < managers.Count; i++) + { + var manager = managers[i]; + int row = i + 1; + + var name = new TextBlock { Text = manager.DisplayName, VerticalAlignment = VerticalAlignment.Center, TextAlignment = TextAlignment.Center }; + SetCell(name, row, 0); + + var proxyLevel = manager.Capabilities.SupportsProxy; + var proxyBadge = StatusBadge( + proxyLevel is ProxySupport.No ? noStr : (proxyLevel is ProxySupport.Partially ? partStr : yesStr), + proxyLevel is ProxySupport.Yes ? Colors.Green : (proxyLevel is ProxySupport.Partially ? Colors.Orange : Colors.Red)); + SetCell(proxyBadge, row, 1); + + var authBadge = StatusBadge( + manager.Capabilities.SupportsProxyAuth ? yesStr : noStr, + manager.Capabilities.SupportsProxyAuth ? Colors.Green : Colors.Red); + SetCell(authBadge, row, 2); + + table.Children.Add(name); + table.Children.Add(proxyBadge); + table.Children.Add(authBadge); + } + + var title = new TextBlock + { + Text = CoreTools.Translate("Proxy compatibility table"), + FontWeight = FontWeight.SemiBold, + Margin = new Thickness(0, 0, 0, 12), + }; + + var centerWrapper = new Grid { ColumnDefinitions = new ColumnDefinitions("*,Auto,*") }; + Grid.SetColumn(table, 1); + centerWrapper.Children.Add(table); + + var stack = new StackPanel { Orientation = Orientation.Vertical }; + stack.Children.Add(title); + stack.Children.Add(centerWrapper); + + var border = new Border + { + CornerRadius = new CornerRadius(8), + BorderThickness = new Thickness(1), + Padding = new Thickness(16, 12), + Child = stack, + }; + border.Classes.Add("settings-card"); + return border; + } + + private static Border StatusBadge(string text, Color color) => new Border + { + CornerRadius = new CornerRadius(4), + Padding = new Thickness(4, 2), + BorderThickness = new Thickness(1), + HorizontalAlignment = HorizontalAlignment.Stretch, + Background = new SolidColorBrush(Color.FromArgb(60, color.R, color.G, color.B)), + BorderBrush = new SolidColorBrush(Color.FromArgb(120, color.R, color.G, color.B)), + Child = new TextBlock { Text = text, TextAlignment = TextAlignment.Center }, + }; + + private static void SetCell(Control c, int row, int col) { Grid.SetRow(c, row); Grid.SetColumn(c, col); } + + private async Task SaveCredentialsAsync() + { + if (_usernameBox is null || _passwordBox is null || _savingIndicator is null) return; + _savingIndicator.Opacity = 1; + _savingIndicator.IsIndeterminate = true; + string u = _usernameBox.Text ?? ""; + string p = _passwordBox.Text ?? ""; + await Task.Delay(500); + if ((_usernameBox.Text ?? "") != u) return; + if ((_passwordBox.Text ?? "") != p) return; + CoreSettings.SetProxyCredentials(u, p); + InternetViewModel.ApplyProxyToProcess(); + _savingIndicator.Opacity = 0; + _savingIndicator.IsIndeterminate = false; + } + + [RelayCommand] + private void RefreshProxyEnabled() + { + IsProxyEnabled = CoreSettings.Get(CoreSettings.K.EnableProxy); + ApplyProxyToProcess(); + } + + [RelayCommand] + private void RefreshProxyAuthEnabled() + { + IsProxyAuthEnabled = CoreSettings.Get(CoreSettings.K.EnableProxyAuth); + ApplyProxyToProcess(); + } + + [RelayCommand] + private static void ApplyProxy() => ApplyProxyToProcess(); + + [RelayCommand] + private void ShowRestartRequired() => RestartRequired?.Invoke(this, EventArgs.Empty); + + public static void ApplyProxyToProcess() + { + var proxyUri = CoreSettings.GetProxyUrl(); + if (proxyUri is null || !CoreSettings.Get(CoreSettings.K.EnableProxy)) + { + Environment.SetEnvironmentVariable("HTTP_PROXY", "", EnvironmentVariableTarget.Process); + Environment.SetEnvironmentVariable("HTTPS_PROXY", "", EnvironmentVariableTarget.Process); + return; + } + string content; + if (!CoreSettings.Get(CoreSettings.K.EnableProxyAuth)) + { + content = proxyUri.ToString(); + } + else + { + var creds = CoreSettings.GetProxyCredentials(); + content = creds is not null + ? $"{proxyUri.Scheme}://{creds.UserName}:{creds.Password}@{proxyUri.Host}:{proxyUri.Port}" + : proxyUri.ToString(); + } + Environment.SetEnvironmentVariable("HTTP_PROXY", content, EnvironmentVariableTarget.Process); + Environment.SetEnvironmentVariable("HTTPS_PROXY", content, EnvironmentVariableTarget.Process); + } +} diff --git a/src/UniGetUI.Avalonia/ViewModels/Pages/SettingsPages/ManagersHomepageViewModel.cs b/src/UniGetUI.Avalonia/ViewModels/Pages/SettingsPages/ManagersHomepageViewModel.cs new file mode 100644 index 0000000..1c05c6c --- /dev/null +++ b/src/UniGetUI.Avalonia/ViewModels/Pages/SettingsPages/ManagersHomepageViewModel.cs @@ -0,0 +1,11 @@ +using System.Collections.ObjectModel; +using UniGetUI.Avalonia.ViewModels; + +namespace UniGetUI.Avalonia.ViewModels.Pages.SettingsPages; + +public record ManagerButtonInfo(string DisplayName, string StatusText); + +public partial class ManagersHomepageViewModel : ViewModelBase +{ + public ObservableCollection Managers { get; } = new(); +} diff --git a/src/UniGetUI.Avalonia/ViewModels/Pages/SettingsPages/NotificationsViewModel.cs b/src/UniGetUI.Avalonia/ViewModels/Pages/SettingsPages/NotificationsViewModel.cs new file mode 100644 index 0000000..76dc138 --- /dev/null +++ b/src/UniGetUI.Avalonia/ViewModels/Pages/SettingsPages/NotificationsViewModel.cs @@ -0,0 +1,32 @@ +using CommunityToolkit.Mvvm.ComponentModel; +using CommunityToolkit.Mvvm.Input; +using UniGetUI.Avalonia.ViewModels; +using CoreSettings = global::UniGetUI.Core.SettingsEngine.Settings; + +namespace UniGetUI.Avalonia.ViewModels.Pages.SettingsPages; + +public partial class NotificationsViewModel : ViewModelBase +{ + [ObservableProperty] private bool _isSystemTrayEnabled; + [ObservableProperty] private bool _isNotificationsEnabled; + + /// True when the system-tray-disabled warning should be shown. + public bool IsSystemTrayWarningVisible => !IsSystemTrayEnabled; + + // Per-type notifications are delivered only by the Windows/macOS bridges; Linux has no + // delivery path, so the whole "Notification types" group is hidden there. + public bool AreNotificationTypesSupported { get; } = + OperatingSystem.IsWindows() || OperatingSystem.IsMacOS(); + + public NotificationsViewModel() + { + _isSystemTrayEnabled = !CoreSettings.Get(CoreSettings.K.DisableSystemTray); + _isNotificationsEnabled = !CoreSettings.Get(CoreSettings.K.DisableNotifications); + } + + [RelayCommand] + private void UpdateNotificationsEnabled() + { + IsNotificationsEnabled = !CoreSettings.Get(CoreSettings.K.DisableNotifications); + } +} diff --git a/src/UniGetUI.Avalonia/ViewModels/Pages/SettingsPages/OperationsViewModel.cs b/src/UniGetUI.Avalonia/ViewModels/Pages/SettingsPages/OperationsViewModel.cs new file mode 100644 index 0000000..e052708 --- /dev/null +++ b/src/UniGetUI.Avalonia/ViewModels/Pages/SettingsPages/OperationsViewModel.cs @@ -0,0 +1,33 @@ +using CommunityToolkit.Mvvm.Input; +using UniGetUI.Avalonia.ViewModels; +using UniGetUI.Avalonia.Views.Pages.SettingsPages; +using UniGetUI.PackageOperations; +using CoreSettings = global::UniGetUI.Core.SettingsEngine.Settings; + +namespace UniGetUI.Avalonia.ViewModels.Pages.SettingsPages; + +public partial class OperationsViewModel : ViewModelBase +{ + public event EventHandler? RestartRequired; + public event EventHandler? NavigationRequested; + + /// Items for the parallel operation count ComboboxCard. + public IReadOnlyList ParallelOpCounts { get; } = + [.. Enumerable.Range(1, 10).Select(i => i.ToString()), "15", "20", "30", "50", "75", "100"]; + + [RelayCommand] + private static void UpdateMaxOperations() + { + if (int.TryParse(CoreSettings.GetValue(CoreSettings.K.ParallelOperationCount), out int value)) + AbstractOperation.MAX_OPERATIONS = value; + } + + [RelayCommand] + private void ShowRestartRequired() => RestartRequired?.Invoke(this, EventArgs.Empty); + + [RelayCommand] + private void NavigateToUpdates() => NavigationRequested?.Invoke(this, typeof(Updates)); + + [RelayCommand] + private void NavigateToAdministrator() => NavigationRequested?.Invoke(this, typeof(Administrator)); +} diff --git a/src/UniGetUI.Avalonia/ViewModels/Pages/SettingsPages/PackageManagerViewModel.cs b/src/UniGetUI.Avalonia/ViewModels/Pages/SettingsPages/PackageManagerViewModel.cs new file mode 100644 index 0000000..73ca3fa --- /dev/null +++ b/src/UniGetUI.Avalonia/ViewModels/Pages/SettingsPages/PackageManagerViewModel.cs @@ -0,0 +1,201 @@ +using Avalonia; +using Avalonia.Controls; +using Avalonia.Platform.Storage; +using CommunityToolkit.Mvvm.ComponentModel; +using CommunityToolkit.Mvvm.Input; +using UniGetUI.Core.Data; +using UniGetUI.Core.Tools; +using UniGetUI.PackageEngine.Interfaces; +using CoreSettings = UniGetUI.Core.SettingsEngine.Settings; + +namespace UniGetUI.Avalonia.ViewModels.Pages.SettingsPages; + +public enum ManagerStatusSeverity { Info, Success, Warning, Error } + +public partial class PackageManagerViewModel : ViewModelBase +{ + public readonly IPackageManager Manager; + + // ── Events ──────────────────────────────────────────────────────────────── + public event EventHandler? RestartRequired; + public event EventHandler? NavigateToAdministratorRequested; + + // ── Section headings ────────────────────────────────────────────────────── + public string PageTitle => CoreTools.Translate("{0} settings", Manager.DisplayName); + public string StatusSectionTitle => CoreTools.Translate("{0} status", Manager.DisplayName); + public string InstallSectionTitle => CoreTools.Translate("Default installation options for {0} packages", Manager.DisplayName); + public string SettingsSectionTitle => CoreTools.Translate("{0} settings", Manager.DisplayName); + + // ── Status bar ──────────────────────────────────────────────────────────── + [ObservableProperty] private ManagerStatusSeverity _severity = ManagerStatusSeverity.Info; + [ObservableProperty] private string _statusTitle = ""; + [ObservableProperty] private string _statusMessage = ""; + [ObservableProperty] private bool _statusMessageVisible; + [ObservableProperty] private string _versionText = ""; + [ObservableProperty] private bool _versionTextVisible; + [ObservableProperty] private bool _showVersionVisible; + public string ShowVersionLabel { get; } = CoreTools.Translate("Expand version"); + + // ── Path label ──────────────────────────────────────────────────────────── + [ObservableProperty] private string _pathLabelText = ""; + + // ── Loading state ───────────────────────────────────────────────────────── + [ObservableProperty] private bool _isLoading; + + // ── Vcpkg root ──────────────────────────────────────────────────────────── + [ObservableProperty] private string _vcpkgRootPath = "%VCPKG_ROOT%"; + [ObservableProperty] private bool _isCustomVcpkgRootSet; + + public PackageManagerViewModel(IPackageManager manager) + { + Manager = manager; + RefreshState(); + IsCustomVcpkgRootSet = CoreSettings.Get(CoreSettings.K.CustomVcpkgRoot); + VcpkgRootPath = IsCustomVcpkgRootSet + ? CoreSettings.GetValue(CoreSettings.K.CustomVcpkgRoot) + : "%VCPKG_ROOT%"; + } + + // ── Commands ────────────────────────────────────────────────────────────── + [RelayCommand] + public async Task ReloadManager() + { + IsLoading = true; + RefreshState(); + await Task.Run(Manager.Initialize); + IsLoading = false; + RefreshState(showVersion: true); + } + + [RelayCommand] + public void ShowVersion() => RefreshState(showVersion: true); + + public void OnExecutableSelected(string path) + { + CoreSettings.SetDictionaryItem(CoreSettings.K.ManagerPaths, Manager.Name, path); + _ = ReloadManagerCommand.ExecuteAsync(null); + } + + // ── State computation ───────────────────────────────────────────────────── + public void RefreshState(bool showVersion = false) + { + PathLabelText = string.IsNullOrEmpty(Manager.Status.ExecutablePath) + ? CoreTools.Translate("The executable file for {0} was not found", Manager.DisplayName) + : Manager.Status.ExecutablePath + " " + Manager.Status.ExecutableCallArgs.Trim(); + + VersionText = ""; + VersionTextVisible = false; + ShowVersionVisible = false; + + if (IsLoading) + { + Severity = ManagerStatusSeverity.Info; + StatusTitle = CoreTools.Translate("Please wait..."); + StatusMessage = ""; + } + else if (!Manager.IsEnabled()) + { + Severity = ManagerStatusSeverity.Warning; + StatusTitle = CoreTools.Translate("{pm} is disabled").Replace("{pm}", Manager.DisplayName); + StatusMessage = CoreTools.Translate("Enable it to install packages from {pm}.").Replace("{pm}", Manager.DisplayName); + } + else if (Manager.Status.Found) + { + Severity = ManagerStatusSeverity.Success; + StatusTitle = CoreTools.Translate("{pm} is enabled and ready to go").Replace("{pm}", Manager.DisplayName); + if (Manager.Status.Version.Contains('\n')) + { + StatusMessage = ""; + if (showVersion) + { + VersionText = Manager.Status.Version; + VersionTextVisible = true; + } + else + { + ShowVersionVisible = true; + } + } + else + { + StatusMessage = CoreTools.Translate("{pm} version:").Replace("{pm}", Manager.DisplayName) + + " " + Manager.Status.Version; + } + } + else + { + Severity = ManagerStatusSeverity.Error; + StatusTitle = CoreTools.Translate("{pm} was not found!").Replace("{pm}", Manager.DisplayName); + StatusMessage = CoreTools.Translate("You may need to install {pm} in order to use it with UniGetUI.").Replace("{pm}", Manager.DisplayName); + } + + StatusMessageVisible = !string.IsNullOrEmpty(StatusMessage); + } + + // ── Scoop commands ──────────────────────────────────────────────────────── + [RelayCommand] + private void ScoopInstall() + { + _ = CoreTools.LaunchBatchFile( + Path.Join(CoreData.UniGetUIExecutableDirectory, "Assets", "Utilities", "install_scoop.cmd"), + CoreTools.Translate("Scoop Installer - UniGetUI")); + RestartRequired?.Invoke(this, EventArgs.Empty); + } + + [RelayCommand] + private void ScoopUninstall() + { + _ = CoreTools.LaunchBatchFile( + Path.Join(CoreData.UniGetUIExecutableDirectory, "Assets", "Utilities", "uninstall_scoop.cmd"), + CoreTools.Translate("Scoop Uninstaller - UniGetUI")); + RestartRequired?.Invoke(this, EventArgs.Empty); + } + + [RelayCommand] + private static void ScoopCleanup() + { + _ = CoreTools.LaunchBatchFile( + Path.Join(CoreData.UniGetUIExecutableDirectory, "Assets", "Utilities", "scoop_cleanup.cmd"), + CoreTools.Translate("Clearing Scoop cache - UniGetUI"), + RunAsAdmin: true); + } + + // ── Vcpkg root commands ─────────────────────────────────────────────────── + [RelayCommand] + private void ResetVcpkgRoot() + { + CoreSettings.Set(CoreSettings.K.CustomVcpkgRoot, false); + VcpkgRootPath = "%VCPKG_ROOT%"; + IsCustomVcpkgRootSet = false; + } + + [RelayCommand] + private static void OpenVcpkgRoot() + { + string directory = CoreSettings.GetValue(CoreSettings.K.CustomVcpkgRoot); + if (!string.IsNullOrEmpty(directory)) + CoreTools.Launch(directory); + } + + [RelayCommand] + private async Task PickVcpkgRoot(Visual? visual) + { + if (visual is null || TopLevel.GetTopLevel(visual) is not { } topLevel) return; + var folders = await topLevel.StorageProvider.OpenFolderPickerAsync( + new FolderPickerOpenOptions { AllowMultiple = false }); + if (folders is not [{ } folder]) return; + var path = folder.TryGetLocalPath(); + if (string.IsNullOrEmpty(path)) return; + CoreSettings.SetValue(CoreSettings.K.CustomVcpkgRoot, path); + VcpkgRootPath = path; + IsCustomVcpkgRootSet = true; + _ = ReloadManagerCommand.ExecuteAsync(null); + } + + // ── Navigation commands ─────────────────────────────────────────────────── + [RelayCommand] + private void NavigateToAdministrator() + { + NavigateToAdministratorRequested?.Invoke(this, EventArgs.Empty); + } +} diff --git a/src/UniGetUI.Avalonia/ViewModels/Pages/SettingsPages/SettingsBasePageViewModel.cs b/src/UniGetUI.Avalonia/ViewModels/Pages/SettingsPages/SettingsBasePageViewModel.cs new file mode 100644 index 0000000..7cd544f --- /dev/null +++ b/src/UniGetUI.Avalonia/ViewModels/Pages/SettingsPages/SettingsBasePageViewModel.cs @@ -0,0 +1,27 @@ +using CommunityToolkit.Mvvm.ComponentModel; +using CommunityToolkit.Mvvm.Input; +using UniGetUI.Avalonia.Infrastructure; +using UniGetUI.Avalonia.ViewModels; +using UniGetUI.Core.Tools; + +namespace UniGetUI.Avalonia.ViewModels.Pages.SettingsPages; + +public partial class SettingsBasePageViewModel : ViewModelBase +{ + [ObservableProperty] private string _title = ""; + [ObservableProperty] private bool _isRestartBannerVisible; + + public event EventHandler? BackRequested; + + public string RestartBannerText => CoreTools.Translate("Restart UniGetUI to fully apply changes"); + public string RestartButtonText => CoreTools.Translate("Restart UniGetUI"); + + [RelayCommand] + private void Back() => BackRequested?.Invoke(this, EventArgs.Empty); + + [RelayCommand] + private static void RestartApp() + { + AppRestartHelper.Restart(); + } +} diff --git a/src/UniGetUI.Avalonia/ViewModels/Pages/SettingsPages/SettingsHomepageViewModel.cs b/src/UniGetUI.Avalonia/ViewModels/Pages/SettingsPages/SettingsHomepageViewModel.cs new file mode 100644 index 0000000..06d34df --- /dev/null +++ b/src/UniGetUI.Avalonia/ViewModels/Pages/SettingsPages/SettingsHomepageViewModel.cs @@ -0,0 +1,21 @@ +using CommunityToolkit.Mvvm.Input; +using UniGetUI.Avalonia.ViewModels; +using UniGetUI.Avalonia.Views.Pages.SettingsPages; + +namespace UniGetUI.Avalonia.ViewModels.Pages.SettingsPages; + +public partial class SettingsHomepageViewModel : ViewModelBase +{ + public event EventHandler? NavigationRequested; + + [RelayCommand] private void NavigateToGeneral() => NavigationRequested?.Invoke(this, typeof(General)); + [RelayCommand] private void NavigateToInterface() => NavigationRequested?.Invoke(this, typeof(Interface_P)); + [RelayCommand] private void NavigateToNotifications() => NavigationRequested?.Invoke(this, typeof(Notifications)); + [RelayCommand] private void NavigateToUpdates() => NavigationRequested?.Invoke(this, typeof(Updates)); + [RelayCommand] private void NavigateToOperations() => NavigationRequested?.Invoke(this, typeof(Operations)); + [RelayCommand] private void NavigateToInternet() => NavigationRequested?.Invoke(this, typeof(Internet)); + [RelayCommand] private void NavigateToBackup() => NavigationRequested?.Invoke(this, typeof(Backup)); + [RelayCommand] private void NavigateToAdministrator() => NavigationRequested?.Invoke(this, typeof(Administrator)); + [RelayCommand] private void NavigateToExperimental() => NavigationRequested?.Invoke(this, typeof(Experimental)); + [RelayCommand] private void NavigateToManagers() => NavigationRequested?.Invoke(this, typeof(ManagersHomepage)); +} diff --git a/src/UniGetUI.Avalonia/ViewModels/Pages/SettingsPages/SourceManagerCardViewModel.cs b/src/UniGetUI.Avalonia/ViewModels/Pages/SettingsPages/SourceManagerCardViewModel.cs new file mode 100644 index 0000000..eca5265 --- /dev/null +++ b/src/UniGetUI.Avalonia/ViewModels/Pages/SettingsPages/SourceManagerCardViewModel.cs @@ -0,0 +1,155 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Threading.Tasks; +using CommunityToolkit.Mvvm.ComponentModel; +using CommunityToolkit.Mvvm.Input; +using UniGetUI.Avalonia.Infrastructure; +using UniGetUI.Core.Logging; +using UniGetUI.Core.Tools; +using UniGetUI.PackageEngine.Classes.Manager; +using UniGetUI.PackageEngine.Interfaces; +using UniGetUI.PackageEngine.Operations; +using UniGetUI.PackageOperations; + +namespace UniGetUI.Avalonia.ViewModels.Pages.SettingsPages; + +public partial class SourceManagerCardViewModel : ViewModelBase +{ + private readonly IPackageManager _manager; + private readonly string _otherLabel; + private readonly Dictionary _knownSourceMap = new(); + + [ObservableProperty] private bool _isLoading = true; + [ObservableProperty] private bool _showAddForm; + [ObservableProperty] private ObservableCollection _sources = []; + [ObservableProperty] private ObservableCollection _knownSourceNames = []; + [ObservableProperty] private string? _selectedKnownSource; + [ObservableProperty] private string _newSourceName = ""; + [ObservableProperty] private string _newSourceUrl = ""; + [ObservableProperty] private bool _nameUrlEditable = true; + + public string TitleText => CoreTools.Translate("Manage {0} sources", _manager.DisplayName); + public string AddLabel { get; } = CoreTools.Translate("Add source"); + public string AddConfirmLabel { get; } = CoreTools.Translate("Add"); + public string CancelLabel { get; } = CoreTools.Translate("Cancel"); + public string NameHint { get; } = CoreTools.Translate("Source name"); + public string UrlHint { get; } = CoreTools.Translate("Source URL"); + + public SourceManagerCardViewModel(IPackageManager manager) + { + _manager = manager; + _otherLabel = CoreTools.Translate("Other"); + + _knownSourceNames.Add(_otherLabel); + foreach (var s in manager.Properties.KnownSources) + { + _knownSourceNames.Add(s.Name); + _knownSourceMap[s.Name] = s; + } + SelectedKnownSource = _otherLabel; + + _ = DoLoadSources(); + } + + [RelayCommand] + private Task ReloadSources() => DoLoadSources(); + + private async Task DoLoadSources() + { + IsLoading = true; + Sources.Clear(); + + if (!_manager.Status.Found) + { + IsLoading = false; + return; + } + + try + { + var loaded = await Task.Run(_manager.SourcesHelper.GetSources); + foreach (var s in loaded) + Sources.Add(s); + } + catch (Exception e) + { + Logger.Warn($"[SourceManagerCard] Failed to load sources for {_manager.DisplayName}: {e.Message}"); + } + finally + { + IsLoading = false; + } + } + + [RelayCommand] + private void ShowAddSource() => ShowAddForm = true; + + [RelayCommand] + private void CancelAddSource() + { + ShowAddForm = false; + NewSourceName = ""; + NewSourceUrl = ""; + SelectedKnownSource = _otherLabel; + } + + [RelayCommand] + private async Task ConfirmAddSource() + { + IManagerSource source; + if (SelectedKnownSource != _otherLabel && + _knownSourceMap.TryGetValue(SelectedKnownSource ?? "", out var known)) + { + source = known; + } + else + { + if (string.IsNullOrWhiteSpace(NewSourceName)) return; + if (!Uri.TryCreate(NewSourceUrl.Trim(), UriKind.Absolute, out var uri)) return; + source = new ManagerSource(_manager, NewSourceName.Trim(), uri); + } + + ShowAddForm = false; + NewSourceName = ""; + NewSourceUrl = ""; + SelectedKnownSource = _otherLabel; + + var op = new AddSourceOperation(source); + op.OperationFinished += OnAddOperationFinished; + AvaloniaOperationRegistry.Add(op); + _ = op.MainThread(); + } + + private void OnAddOperationFinished(object? sender, EventArgs e) + { + if (sender is AbstractOperation op) + op.OperationFinished -= OnAddOperationFinished; + _ = DoLoadSources(); + } + + [RelayCommand] + private void DeleteSource(IManagerSource source) + { + var op = new RemoveSourceOperation(source); + AvaloniaOperationRegistry.Add(op); + _ = op.MainThread(); + Sources.Remove(source); + } + + partial void OnSelectedKnownSourceChanged(string? value) + { + if (value is null || value == _otherLabel) + { + NameUrlEditable = true; + NewSourceName = ""; + NewSourceUrl = ""; + } + else if (_knownSourceMap.TryGetValue(value, out var s)) + { + NameUrlEditable = false; + NewSourceName = s.Name; + NewSourceUrl = s.Url.ToString(); + } + } +} diff --git a/src/UniGetUI.Avalonia/ViewModels/Pages/SettingsPages/UpdatesViewModel.cs b/src/UniGetUI.Avalonia/ViewModels/Pages/SettingsPages/UpdatesViewModel.cs new file mode 100644 index 0000000..78be881 --- /dev/null +++ b/src/UniGetUI.Avalonia/ViewModels/Pages/SettingsPages/UpdatesViewModel.cs @@ -0,0 +1,150 @@ +using Avalonia.Controls; +using Avalonia.Layout; +using Avalonia.Media; +using CommunityToolkit.Mvvm.ComponentModel; +using CommunityToolkit.Mvvm.Input; +using UniGetUI.Avalonia.Views.Pages.SettingsPages; +using UniGetUI.Core.Tools; +using UniGetUI.PackageEngine; +using UniGetUI.PackageEngine.ManagerClasses.Manager; +using CoreSettings = UniGetUI.Core.SettingsEngine.Settings; +using CornerRadius = Avalonia.CornerRadius; +using Thickness = Avalonia.Thickness; + +namespace UniGetUI.Avalonia.ViewModels.Pages.SettingsPages; + +public partial class UpdatesViewModel : ViewModelBase +{ + public event EventHandler? RestartRequired; + public event EventHandler? NavigationRequested; + + [ObservableProperty] private bool _isAutoCheckEnabled; + [ObservableProperty] private bool _isCustomAgeSelected; + + /// Items for the minimum update age ComboboxCard, in display/value pairs. + public IReadOnlyList<(string Name, string Value)> MinimumAgeItems { get; } = + [ + (CoreTools.Translate("No minimum age"), "0"), + (CoreTools.Translate("1 day"), "1"), + (CoreTools.Translate("{0} days", 3), "3"), + (CoreTools.Translate("{0} days", 7), "7"), + (CoreTools.Translate("{0} days", 14), "14"), + (CoreTools.Translate("{0} days", 30), "30"), + (CoreTools.Translate("Custom..."), "custom"), + ]; + + /// Items for the update interval ComboboxCard, in display/value pairs. + public IReadOnlyList<(string Name, string Value)> IntervalItems { get; } = + [ + (CoreTools.Translate("{0} minutes", 10), "600"), + (CoreTools.Translate("{0} minutes", 30), "1800"), + (CoreTools.Translate("1 hour"), "3600"), + (CoreTools.Translate("{0} hours", 2), "7200"), + (CoreTools.Translate("{0} hours", 4), "14400"), + (CoreTools.Translate("{0} hours", 8), "28800"), + (CoreTools.Translate("{0} hours", 12), "43200"), + (CoreTools.Translate("1 day"), "86400"), + (CoreTools.Translate("{0} days", 2), "172800"), + (CoreTools.Translate("{0} days", 3), "259200"), + (CoreTools.Translate("1 week"), "604800"), + ]; + + public UpdatesViewModel() + { + _isAutoCheckEnabled = !CoreSettings.Get(CoreSettings.K.DisableAutoCheckforUpdates); + _isCustomAgeSelected = CoreSettings.GetValue(CoreSettings.K.MinimumUpdateAge) == "custom"; + } + + public Control BuildReleaseDateCompatTable() + { + var managers = PEInterface.Managers.ToList(); + + var table = new Grid + { + ColumnDefinitions = new ColumnDefinitions("Auto,Auto"), + ColumnSpacing = 24, + RowSpacing = 8, + }; + for (int i = 0; i <= managers.Count; i++) + table.RowDefinitions.Add(new RowDefinition(GridLength.Auto)); + + var h1 = new TextBlock { Text = CoreTools.Translate("Package manager"), FontWeight = FontWeight.Bold }; + var h2 = new TextBlock { Text = CoreTools.Translate("Supports release dates"), FontWeight = FontWeight.Bold, HorizontalAlignment = HorizontalAlignment.Center }; + Grid.SetRow(h1, 0); Grid.SetColumn(h1, 0); + Grid.SetRow(h2, 0); Grid.SetColumn(h2, 1); + table.Children.Add(h1); + table.Children.Add(h2); + + for (int i = 0; i < managers.Count; i++) + { + var manager = managers[i]; + int row = i + 1; + + var name = new TextBlock { Text = manager.DisplayName, VerticalAlignment = VerticalAlignment.Center }; + Grid.SetRow(name, row); Grid.SetColumn(name, 0); + + (string label, Color color) = manager.Capabilities.KnowsPackageReleaseDate switch + { + PackageReleaseDateSupport.Yes => (CoreTools.Translate("Yes"), Colors.Green), + PackageReleaseDateSupport.Partial => (CoreTools.Translate("Partial"), Color.FromRgb(224, 168, 0)), + _ => (CoreTools.Translate("No"), Colors.Red), + }; + var badge = _statusBadge(label, color); + Grid.SetRow(badge, row); Grid.SetColumn(badge, 1); + + table.Children.Add(name); + table.Children.Add(badge); + } + + var title = new TextBlock + { + Text = CoreTools.Translate("Release date support per package manager"), + FontWeight = FontWeight.SemiBold, + Margin = new Thickness(0, 0, 0, 12), + }; + + var centerWrapper = new Grid { ColumnDefinitions = new ColumnDefinitions("*,Auto,*") }; + Grid.SetColumn(table, 1); + centerWrapper.Children.Add(table); + + var stack = new StackPanel { Orientation = Orientation.Vertical }; + stack.Children.Add(title); + stack.Children.Add(centerWrapper); + + var border = new Border + { + CornerRadius = new CornerRadius(8), + BorderThickness = new Thickness(1), + Padding = new Thickness(16, 12), + Child = stack, + }; + border.Classes.Add("settings-card"); + return border; + } + + private static Border _statusBadge(string text, Color color) => new Border + { + CornerRadius = new CornerRadius(4), + Padding = new Thickness(4, 2), + BorderThickness = new Thickness(1), + HorizontalAlignment = HorizontalAlignment.Stretch, + Background = new SolidColorBrush(Color.FromArgb(60, color.R, color.G, color.B)), + BorderBrush = new SolidColorBrush(Color.FromArgb(120, color.R, color.G, color.B)), + Child = new TextBlock { Text = text, TextAlignment = TextAlignment.Center }, + }; + + [RelayCommand] + private void UpdateAutoCheckEnabled() + { + IsAutoCheckEnabled = !CoreSettings.Get(CoreSettings.K.DisableAutoCheckforUpdates); + } + + [RelayCommand] + private void ShowRestartRequired() => RestartRequired?.Invoke(this, EventArgs.Empty); + + [RelayCommand] + private void NavigateToOperations() => NavigationRequested?.Invoke(this, typeof(Operations)); + + [RelayCommand] + private void NavigateToAdministrator() => NavigationRequested?.Invoke(this, typeof(Administrator)); +} diff --git a/src/UniGetUI.Avalonia/ViewModels/SidebarViewModel.cs b/src/UniGetUI.Avalonia/ViewModels/SidebarViewModel.cs new file mode 100644 index 0000000..6972730 --- /dev/null +++ b/src/UniGetUI.Avalonia/ViewModels/SidebarViewModel.cs @@ -0,0 +1,150 @@ +using CommunityToolkit.Mvvm.ComponentModel; +using CommunityToolkit.Mvvm.Input; +using UniGetUI.Avalonia.Infrastructure; +using UniGetUI.Avalonia.Views; +using UniGetUI.Core.Data; +using UniGetUI.Core.SettingsEngine; +using UniGetUI.Core.Tools; + +namespace UniGetUI.Avalonia.ViewModels; + +public partial class SidebarViewModel : ViewModelBase +{ + // ─── Badge properties ───────────────────────────────────────────────────── + [ObservableProperty] + private int _updatesBadgeCount; + + [ObservableProperty] + private bool _updatesBadgeVisible; + + [ObservableProperty] + private bool _bundlesBadgeVisible; + + // When the count changes, sync the badge visibility + partial void OnUpdatesBadgeCountChanged(int value) => + UpdatesBadgeVisible = value > 0; + + // ─── Loading indicators ─────────────────────────────────────────────────── + [ObservableProperty] + private bool _discoverIsLoading; + + [ObservableProperty] + private bool _updatesIsLoading; + + [ObservableProperty] + private bool _installedIsLoading; + + // ─── Pane open/closed ───────────────────────────────────────────────────── + // NavMenuMode: Automatic mirrors WinUI (dock ≥1600px, else rail+overlay), Docked = always + // inline, Overlay = always rail+overlay. IsPaneOpen = labeled pane showing, in any mode. + public enum NavMode { Automatic, Docked, Overlay } + + private const double ExpandedThreshold = 1600; // WinUI ExpandedModeThresholdWidth + private const double CompactThreshold = 800; // WinUI CompactModeThresholdWidth + + // Live window width, pushed by MainWindow's bounds observer. + [ObservableProperty] + private double _windowWidth = 1450; + + [ObservableProperty] + private NavMode _mode = ParseMode(Settings.GetValue(Settings.K.NavMenuMode)); + + [ObservableProperty] + private bool _isPaneOpen; + + public static NavMode ParseMode(string value) => value switch + { + "docked" => NavMode.Docked, + "overlay" => NavMode.Overlay, + _ => NavMode.Automatic, + }; + + // Whether the pane docks inline (vs. the rail + sliding overlay). + public bool Docked => Mode switch + { + NavMode.Docked => true, + NavMode.Overlay => false, + _ => WindowWidth >= ExpandedThreshold, + }; + + private bool RailAllowed => WindowWidth >= CompactThreshold; + + // Icon rail vs docked labeled pane vs sliding overlay — mutually exclusive. + public bool NavDockVisible => Docked && IsPaneOpen; + public bool RailVisible => (Docked && !IsPaneOpen) || (!Docked && RailAllowed); + public bool OverlayActive => !Docked && IsPaneOpen; + + private bool _wasDocked; + + public SidebarViewModel() + { + _wasDocked = Docked; + _isPaneOpen = Docked && !Settings.Get(Settings.K.CollapseNavMenuOnWideScreen); + } + + partial void OnWindowWidthChanged(double value) => ReconcileDock(); + + partial void OnModeChanged(NavMode value) => ReconcileDock(); + + // On a docked-state flip, open the pane by default (unless collapsed on a wide screen), or + // collapse when leaving docked mode. Mirrors WinUI's startup IsPaneOpen logic. + private void ReconcileDock() + { + bool docked = Docked; + if (docked != _wasDocked) + { + _wasDocked = docked; + IsPaneOpen = docked && !Settings.Get(Settings.K.CollapseNavMenuOnWideScreen); + } + RaiseLayoutChanged(); + } + + partial void OnIsPaneOpenChanged(bool value) + { + // Persist the collapse choice only while docked (WinUI persisted only at ≥1600px). + if (Docked) + Settings.Set(Settings.K.CollapseNavMenuOnWideScreen, !value); + RaiseLayoutChanged(); + } + + private void RaiseLayoutChanged() + { + OnPropertyChanged(nameof(NavDockVisible)); + OnPropertyChanged(nameof(RailVisible)); + OnPropertyChanged(nameof(OverlayActive)); + } + + // ─── Selected page ──────────────────────────────────────────────────────── + [ObservableProperty] + private PageType _selectedPageType = PageType.Null; + + // ─── Navigation ────────────────────────────────────────────────────────── + public event EventHandler? NavigationRequested; + + public string VersionLabel { get; } = + CoreTools.Translate("UniGetUI Version {0} by Devolutions", CoreData.VersionName); + + [RelayCommand] + public void RequestNavigation(string? pageName) + { + if (Enum.TryParse(pageName, out var page)) + NavigationRequested?.Invoke(this, page); + } + + [RelayCommand] + private static Task CheckForUpdates() => + AvaloniaAutoUpdater.CheckAndInstallUpdatesAsync(autoLaunch: false, manualCheck: true); + + public void SelectNavButtonForPage(PageType page) => + SelectedPageType = page; + + public void SetNavItemLoading(PageType page, bool isLoading) + { + switch (page) + { + case PageType.Discover: DiscoverIsLoading = isLoading; break; + case PageType.Updates: UpdatesIsLoading = isLoading; break; + case PageType.Installed: InstalledIsLoading = isLoading; break; + } + } +} diff --git a/src/UniGetUI.Avalonia/ViewModels/SoftwarePages/PackagesPageViewModel.cs b/src/UniGetUI.Avalonia/ViewModels/SoftwarePages/PackagesPageViewModel.cs new file mode 100644 index 0000000..363cfd2 --- /dev/null +++ b/src/UniGetUI.Avalonia/ViewModels/SoftwarePages/PackagesPageViewModel.cs @@ -0,0 +1,1031 @@ +using System.Collections.Concurrent; +using System.Collections.ObjectModel; +using System.ComponentModel; +using System.Globalization; +using Avalonia; +using Avalonia.Automation; +using Avalonia.Collections; +using Avalonia.Controls; +using Avalonia.Layout; +using Avalonia.Media; +using Avalonia.Media.Imaging; +using Avalonia.Platform; +using Avalonia.Threading; +using CommunityToolkit.Mvvm.ComponentModel; +using CommunityToolkit.Mvvm.Input; +using UniGetUI.Avalonia.Infrastructure; +using UniGetUI.Avalonia.ViewModels; +using UniGetUI.Avalonia.Views.Controls; +using UniGetUI.Core.SettingsEngine; +using UniGetUI.Core.Tools; +using UniGetUI.Interface.Telemetry; +using UniGetUI.PackageEngine.Enums; +using UniGetUI.PackageEngine.Interfaces; +using UniGetUI.PackageEngine.Operations; +using UniGetUI.PackageEngine.PackageClasses; +using UniGetUI.PackageEngine.PackageLoader; + +namespace UniGetUI.Avalonia.ViewModels.Pages; + +public enum SearchMode { Both, Name, Id, Exact, Similar } + +public enum PackageViewMode { List = 0, Grid = 1, Icons = 2 } + +public enum ReloadReason +{ + FirstRun, + Automated, + Manual, + External, +} + +public struct PackagesPageData +{ + public bool DisableAutomaticPackageLoadOnStart; + public bool MegaQueryBlockEnabled; + public bool PackagesAreCheckedByDefault; + public bool ShowLastLoadTime; + public bool DisableSuggestedResultsRadio; + public bool DisableFilterOnQueryChange; + public bool DisableReload; + + public OperationType PageRole; + public AbstractPackageLoader Loader; + + public string PageName; + public string PageTitle; + public string IconName; // SVG filename without extension, e.g. "search" + + public string NoPackages_BackgroundText; + public string NoPackages_ImagePath; // optional avares:// illustration shown when no packages are present + public string NoPackages_SourcesText; + public string NoPackages_SubtitleText_Base; + public string MainSubtitle_StillLoading; + public string NoMatches_BackgroundText; +} + +/// +/// Represents a node in the sources tree (replaces WinUI TreeViewNode). +/// +public class SourceTreeNode : INotifyPropertyChanged +{ + public string? PackageName { get; set; } + public string? PackageID { get; init; } + public string? Version { get; init; } + public string? Source { get; init; } + public AvaloniaList Children { get; } + + public bool HasChildren => Children.Count > 0; + + public SourceTreeNode() + { + Children = new AvaloniaList(); + Children.CollectionChanged += (_, _) => + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(HasChildren))); + } + + public event PropertyChangedEventHandler? PropertyChanged; + + private bool _isSelected; + public bool IsSelected + { + get => _isSelected; + set { _isSelected = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(IsSelected))); } + } + + private bool _isExpanded; + public bool IsExpanded + { + get => _isExpanded; + set { _isExpanded = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(IsExpanded))); } + } +} + +public partial class PackagesPageViewModel : ViewModelBase +{ + // Live width of the filter pane. Code-behind keeps this in sync with the GridSplitter + // so the toolbar's main button (bound to FilterPaneColumnWidth) tracks resizes. + private double _trackedFilterPaneWidth = 220.0; + public double TrackedFilterPaneWidth + { + get => _trackedFilterPaneWidth; + set + { + if (Math.Abs(_trackedFilterPaneWidth - value) < 0.5) return; + _trackedFilterPaneWidth = value; + if (IsFilterPaneOpen) OnPropertyChanged(nameof(FilterPaneColumnWidth)); + } + } + + public double FilterPaneColumnWidth => IsFilterPaneOpen ? _trackedFilterPaneWidth : 0.0; + partial void OnIsFilterPaneOpenChanged(bool value) + { + OnPropertyChanged(nameof(FilterPaneColumnWidth)); + Settings.SetDictionaryItem(Settings.K.HideToggleFilters, PageName, !value); + } + + // ─── Static config (set once in constructor) ────────────────────────────── + public readonly string PageName; + public readonly bool MegaQueryBoxEnabled; + public readonly bool DisableFilterOnQueryChange; + public readonly bool DisableReload; + public readonly bool LoadsOnStart; + public readonly bool RoleIsUpdateLike; + public bool SimilarSearchEnabled { get; private set; } + public readonly string NoPackagesText; + public readonly string NoMatchesText; + public readonly string SearchBoxPlaceholder; + private readonly string _noPackagesSubtitleBase; + private readonly string _stillLoadingSubtitle; + private readonly bool _showLastCheckedTime; + private DateTime _lastLoadTime = DateTime.Now; + + protected AbstractPackageLoader Loader; + + // ─── Observable properties ──────────────────────────────────────────────── + [ObservableProperty] private string _pageTitle = ""; + [ObservableProperty] private string _pageIconPath = ""; + [ObservableProperty] private string _subtitle = ""; + [ObservableProperty] private bool _isLoading; + [ObservableProperty] private bool _backgroundTextVisible; + [ObservableProperty] private bool _loadingImageVisible; + [ObservableProperty] private Bitmap? _noPackagesImage; + [ObservableProperty] private bool _noPackagesImageVisible; + [ObservableProperty] private string _backgroundText = ""; + [ObservableProperty] private bool _sourcesPlaceholderVisible = true; + [ObservableProperty] private bool _sourcesTreeVisible; + [ObservableProperty] private bool _megaQueryVisible; + [ObservableProperty] private string _megaQueryText = ""; + [ObservableProperty] private string _globalQueryText = ""; + [ObservableProperty] private bool _newVersionHeaderVisible; + [ObservableProperty] private bool _reloadButtonVisible; + [ObservableProperty] private string _reloadButtonTooltip = ""; + [ObservableProperty] private bool _isFilterPaneOpen; + [ObservableProperty] private PackageViewMode _viewMode; + [ObservableProperty] private int _sortFieldIndex; + [ObservableProperty] private bool _sortAscending = true; + [ObservableProperty] private bool _instantSearch = true; + [ObservableProperty] private bool _upperLowerCase; + [ObservableProperty] private bool _ignoreSpecialChars = true; + [ObservableProperty] private SearchMode _searchMode = SearchMode.Both; + [ObservableProperty] private bool? _allPackagesChecked; + [ObservableProperty] private string _nameHeaderText = ""; + [ObservableProperty] private string _idHeaderText = ""; + [ObservableProperty] private string _versionHeaderText = ""; + [ObservableProperty] private string _newVersionHeaderText = ""; + [ObservableProperty] private string _sourceHeaderText = ""; + + // ─── Collections ────────────────────────────────────────────────────────── + public ObservablePackageCollection FilteredPackages { get; } = new(); + public AvaloniaList SourceNodes { get; } = new(); + public AvaloniaList ToolBarItems { get; } = new(); + + // Labels of toolbar buttons that can be hidden to collapse the menu bar to icon-only + // on narrow windows (buttons created with showLabel: false are never tracked here). + private readonly List _collapsibleToolbarLabels = new(); + private bool _toolbarLabelsCollapsed; + + // ─── Internal state ─────────────────────────────────────────────────────── + private string _searchQuery = ""; + public string QueryBackup { get; set; } = ""; + + private readonly ObservableCollection _wrappedPackages = new(); + protected List UsedManagers = []; + protected ConcurrentDictionary> UsedSourcesForManager = new(); + protected ConcurrentDictionary RootNodeForManager = new(); + protected ConcurrentDictionary NodesForSources = new(); + private readonly SourceTreeNode _localPackagesNode = new() { PackageName = "local" }; + private bool _isSynchronizingSourceSelection; + + // ─── Events (replace abstract methods) ─────────────────────────────────── + public event Action? PackagesLoaded; + public event Action? PackageCountUpdated; + public event Action? FocusListRequested; + + // ─── Events: view-side dialog/navigation requests ───────────────────────── + /// Fired when the ViewModel wants to navigate to the Help page. + public event Action? HelpRequested; + /// Fired when the ViewModel wants to show the Manage-Ignored-Updates dialog. + public event Action? ManageIgnoredRequested; + + // ─── Constructor ───────────────────────────────────────────────────────── + public PackagesPageViewModel(PackagesPageData data) + { + PageName = data.PageName; + PageTitle = data.PageTitle; + PageIconPath = $"avares://UniGetUI/Assets/Symbols/{data.IconName}.svg"; + DisableFilterOnQueryChange = data.DisableFilterOnQueryChange; + MegaQueryBoxEnabled = data.MegaQueryBlockEnabled; + DisableReload = data.DisableReload; + LoadsOnStart = !data.DisableAutomaticPackageLoadOnStart; + _showLastCheckedTime = data.ShowLastLoadTime; + NoPackagesText = data.NoPackages_BackgroundText; + NoMatchesText = data.NoMatches_BackgroundText; + if (!string.IsNullOrEmpty(data.NoPackages_ImagePath)) + { + using var stream = AssetLoader.Open(new Uri(data.NoPackages_ImagePath)); + NoPackagesImage = new Bitmap(stream); + } + _noPackagesSubtitleBase = data.NoPackages_SubtitleText_Base; + _stillLoadingSubtitle = data.MainSubtitle_StillLoading; + SimilarSearchEnabled = !data.DisableSuggestedResultsRadio; + RoleIsUpdateLike = data.PageRole == OperationType.Update; + NewVersionHeaderVisible = RoleIsUpdateLike; + ReloadButtonVisible = !DisableReload; + SearchBoxPlaceholder = CoreTools.Translate("Search for packages"); + + AllPackagesChecked = data.PackagesAreCheckedByDefault; + FilteredPackages.SelectionStateChanged += (_, _) => + { + if (_suppressSelectionRecompute) return; + AllPackagesChecked = FilteredPackages.GetSelectionState(); + }; + + Loader = data.Loader; + Loader.StartedLoading += Loader_StartedLoading; + Loader.FinishedLoading += Loader_FinishedLoading; + Loader.PackagesChanged += Loader_PackagesChanged; + + _wrappedPackages.CollectionChanged += (_, _) => { /* invalidate query cache if needed */ }; + + InstantSearch = !Settings.GetDictionaryItem(Settings.K.DisableInstantSearch, PageName); + + var savedMode = Settings.GetDictionaryItem(Settings.K.PackageListViewMode, PageName); + ViewMode = Enum.IsDefined(typeof(PackageViewMode), savedMode) + ? (PackageViewMode)savedMode + : PackageViewMode.List; + + // Restore per-page filter pane open/closed state (default: open). + // Use backing field to avoid writing to settings during construction. + _isFilterPaneOpen = !Settings.GetDictionaryItem(Settings.K.HideToggleFilters, PageName); + + // Restore per-page sort preferences (default: Name, ascending). + int savedSortField = Settings.GetDictionaryItem(Settings.K.PackageListSortFieldIndex, PageName); + if (savedSortField is < 0 or > 4 || (savedSortField is 3 && !RoleIsUpdateLike)) + savedSortField = 0; + SortFieldIndex = savedSortField; + SortAscending = !Settings.GetDictionaryItem(Settings.K.PackageListSortDescending, PageName); + + _localPackagesNode.PackageName = CoreTools.Translate("Local"); + + if (Loader.IsLoading) + Loader_StartedLoading(this, EventArgs.Empty); + else + { + Loader_FinishedLoading(this, EventArgs.Empty); + FilterPackages(); + } + Loader_PackagesChanged(this, new(false, [], [])); + + UpdateHeaderTexts(); + + if (MegaQueryBoxEnabled) + { + MegaQueryVisible = true; + BackgroundTextVisible = false; + } + + // Toolbar is generated by the View after construction (see AbstractPackagesPage ctor) + } + + public Button AddToolbarButton(string svgName, string label, Action onClick, bool showLabel = true) + { + var icon = new SvgIcon + { + Path = $"avares://UniGetUI/Assets/Symbols/{svgName}.svg", + Width = 20, + Height = 20, + VerticalAlignment = VerticalAlignment.Center, + }; + + var content = new StackPanel { Orientation = Orientation.Horizontal, Spacing = 6 }; + content.Children.Add(icon); + if (showLabel) + { + var labelBlock = new TextBlock + { + Text = label, + FontSize = 12, + VerticalAlignment = VerticalAlignment.Center, + IsVisible = !_toolbarLabelsCollapsed, + }; + content.Children.Add(labelBlock); + _collapsibleToolbarLabels.Add(labelBlock); + } + + var btn = new Button + { + Height = 40, + Padding = new Thickness(10, 4), + CornerRadius = new CornerRadius(4), + Content = content, + }; + ToolTip.SetTip(btn, label); + AutomationProperties.SetName(btn, label); + btn.Click += (_, _) => onClick(); + ToolBarItems.Add(btn); + return btn; + } + + /// + /// Collapses the menu bar to icon-only (or restores labels) on narrow windows, + /// mirroring the WinUI CommandBar's DefaultLabelPosition behavior. + /// + public void SetToolbarLabelsCollapsed(bool collapsed) + { + if (_toolbarLabelsCollapsed == collapsed) return; + _toolbarLabelsCollapsed = collapsed; + foreach (var label in _collapsibleToolbarLabels) + label.IsVisible = !collapsed; + } + + /// Adds a thin vertical separator to the toolbar. + public void AddToolbarSeparator() + { + object? borderResource = null; + Application.Current?.Resources.TryGetResource( + "AppBorderBrush", + Application.Current?.ActualThemeVariant, + out borderResource); + + var sep = new Separator + { + Width = 1, + Height = 32, + Margin = new Thickness(4, 4), + Background = borderResource as IBrush + ?? new SolidColorBrush(Color.FromArgb(80, 128, 128, 128)), + }; + AutomationProperties.SetAccessibilityView(sep, AccessibilityView.Raw); + ToolBarItems.Add(sep); + } + + public async Task ShowInfoDialog(Window owner, string title, string message) + { + object? bgResource = null; + Application.Current?.Resources.TryGetResource("AppWindowBackground", Application.Current.ActualThemeVariant, out bgResource); + var dialog = new Window + { + Width = 460, + Height = 180, + CanResize = false, + ShowInTaskbar = false, + WindowStartupLocation = WindowStartupLocation.CenterOwner, + Title = title, + Background = bgResource as IBrush, + }; + + var okBtn = new Button + { + Content = CoreTools.Translate("OK"), + MinWidth = 80, + CornerRadius = new CornerRadius(4), + HorizontalAlignment = HorizontalAlignment.Right, + }; + okBtn.Classes.Add("accent"); + okBtn.Click += (_, _) => dialog.Close(); + + var root = new Grid + { + Margin = new Thickness(20), + RowDefinitions = new RowDefinitions("Auto,*,Auto"), + RowSpacing = 12, + }; + var titleBlock = new TextBlock + { + Text = title, + FontSize = 16, + FontWeight = FontWeight.SemiBold, + }; + var msgBlock = new TextBlock + { + Text = message, + TextWrapping = TextWrapping.Wrap, + Opacity = 0.85, + }; + Grid.SetRow(titleBlock, 0); + Grid.SetRow(msgBlock, 1); + Grid.SetRow(okBtn, 2); + root.Children.Add(titleBlock); + root.Children.Add(msgBlock); + root.Children.Add(okBtn); + dialog.Content = root; + + await dialog.ShowDialog(owner); + } + + // ─── Loader events ──────────────────────────────────────────────────────── + private void Loader_PackagesChanged(object? sender, PackagesChangedEvent e) + { + if (!Dispatcher.UIThread.CheckAccess()) + { + Dispatcher.UIThread.Post(() => Loader_PackagesChanged(sender, e)); + return; + } + + if (e.ProceduralChange) + { + foreach (var pkg in e.AddedPackages) + { + if (_wrappedPackages.Any(w => w.Package.GetVersionedHash() == pkg.GetVersionedHash())) continue; + _wrappedPackages.Add(new PackageWrapper(pkg, this)); + AddPackageToSourcesList(pkg); + } + var toRemove = _wrappedPackages + .Where(w => e.RemovedPackages.Any(r => r.GetVersionedHash() == w.Package.GetVersionedHash())) + .ToList(); + foreach (var wrapper in toRemove) { wrapper.Dispose(); _wrappedPackages.Remove(wrapper); } + } + else + { + foreach (var w in _wrappedPackages) w.Dispose(); + _wrappedPackages.Clear(); + ClearSourcesList(); + foreach (var pkg in Loader.Packages) + { + _wrappedPackages.Add(new PackageWrapper(pkg, this)); + AddPackageToSourcesList(pkg); + } + } + FilterPackages(); + } + + private void Loader_FinishedLoading(object? sender, EventArgs e) + { + if (!Dispatcher.UIThread.CheckAccess()) + { + Dispatcher.UIThread.Post(() => Loader_FinishedLoading(sender, e)); + return; + } + IsLoading = false; + _lastLoadTime = DateTime.Now; + ReloadButtonTooltip = CoreTools.Translate("Last checked: {0}", _lastLoadTime.ToString(CultureInfo.CurrentCulture)); + FilterPackages(); + PackagesLoaded?.Invoke(ReloadReason.External); + } + + private void Loader_StartedLoading(object? sender, EventArgs e) + { + if (!Dispatcher.UIThread.CheckAccess()) + { + Dispatcher.UIThread.Post(() => Loader_StartedLoading(sender, e)); + return; + } + IsLoading = true; + UpdateSubtitle(); + } + + // ─── Search & filter ────────────────────────────────────────────────────── + partial void OnGlobalQueryTextChanged(string value) + { + _searchQuery = value; + if (MegaQueryBoxEnabled) + { + if (string.IsNullOrEmpty(value)) + { + MegaQueryText = ""; + MegaQueryVisible = true; + Loader?.ClearPackages(emitFinishSignal: false); + } + else + { + MegaQueryText = value; + MegaQueryVisible = false; + } + return; + } + if (!DisableFilterOnQueryChange && InstantSearch) + FilterPackages(); + } + + [RelayCommand] + public void SubmitSearch() + { + string query = _searchQuery = GlobalQueryText = MegaQueryText.Trim(); + MegaQueryVisible = false; + + if (Loader is DiscoverablePackagesLoader discoverLoader) + { + Loader.ClearPackages(emitFinishSignal: false); + _ = discoverLoader.ReloadPackages(query); + } + else + { + FilterPackages(fromQuery: true); + } + } + + public void FilterPackages(bool fromQuery = false) + { + var filters = new List>(); + if (!UpperLowerCase) filters.Add(FilterHelpers.NormalizeCase); + if (IgnoreSpecialChars) filters.Add(FilterHelpers.NormalizeSpecialCharacters); + + string query = _searchQuery; + foreach (var f in filters) query = f(query); + + Func matchFunc = SearchMode switch + { + SearchMode.Name => pkg => FilterHelpers.NameContains(pkg, query, filters), + SearchMode.Id => pkg => FilterHelpers.IdContains(pkg, query, filters), + SearchMode.Exact => pkg => FilterHelpers.NameOrIdExactMatch(pkg, query, filters), + SearchMode.Similar => _ => true, + _ => pkg => FilterHelpers.NameOrIdContains(pkg, query, filters), + }; + + var (visibleSources, visibleManagers) = GetSelectedSourceFilters(); + Func sourceFilter = SourceNodes.Count == 0 + ? _ => true // sources not yet loaded — show everything + : visibleSources.Count == 0 && visibleManagers.Count == 0 + ? _ => false // sources loaded but none selected — show nothing + : pkg => + visibleSources.Contains(pkg.Source) + || ( + !pkg.Manager.Capabilities.SupportsCustomSources + && visibleManagers.Contains(pkg.Manager) + ); + + var results = FilteredPackages.ApplyToList( + _wrappedPackages.Where(w => matchFunc(w.Package) && sourceFilter(w.Package)) + ).ToList(); + + FilteredPackages.Clear(); + foreach (var w in results) FilteredPackages.Add(w); + + UpdateSubtitle(); + PackageCountUpdated?.Invoke(); + + bool loadingOrPending = Loader.IsLoading || (LoadsOnStart && !Loader.IsLoaded); + + if (loadingOrPending && FilteredPackages.Count == 0) + { + BackgroundText = _stillLoadingSubtitle; + BackgroundTextVisible = true; + LoadingImageVisible = true; + NoPackagesImageVisible = false; + } + else if (FilteredPackages.Count == 0) + { + bool noQuery = string.IsNullOrWhiteSpace(query); + BackgroundText = noQuery ? NoPackagesText : NoMatchesText; + BackgroundTextVisible = !MegaQueryBoxEnabled || !noQuery; + LoadingImageVisible = false; + NoPackagesImageVisible = noQuery && BackgroundTextVisible && NoPackagesImage is not null; + } + else + { + BackgroundTextVisible = false; + LoadingImageVisible = false; + NoPackagesImageVisible = false; + } + } + + // ─── Package loading ────────────────────────────────────────────────────── + public async Task LoadPackages(ReloadReason reason = ReloadReason.External) + { + if (!Loader.IsLoading && (!Loader.IsLoaded + || reason is ReloadReason.External or ReloadReason.Manual or ReloadReason.Automated)) + { + await Loader.ReloadPackages(); + } + } + + // ─── Sorting ────────────────────────────────────────────────────────────── + public string SortFieldName => CoreTools.Translate(SortFieldIndex switch + { + 1 => "Id", + 2 => "Version", + 3 => "New version", + 4 => "Source", + _ => "Name", + }); + + partial void OnSortFieldIndexChanged(int value) + { + FilteredPackages.SortBy(value switch + { + 1 => ObservablePackageCollection.Sorter.Id, + 2 => ObservablePackageCollection.Sorter.Version, + 3 => ObservablePackageCollection.Sorter.NewVersion, + 4 => ObservablePackageCollection.Sorter.Source, + _ => ObservablePackageCollection.Sorter.Name, + }); + OnPropertyChanged(nameof(SortFieldName)); + FilterPackages(); + Settings.SetDictionaryItem(Settings.K.PackageListSortFieldIndex, PageName, value); + } + + partial void OnSortAscendingChanged(bool value) + { + FilteredPackages.SetSortDirection(value); + FilterPackages(); + Settings.SetDictionaryItem(Settings.K.PackageListSortDescending, PageName, !value); + } + + // ─── Selection ──────────────────────────────────────────────────────────── + partial void OnInstantSearchChanged(bool value) + => Settings.SetDictionaryItem(Settings.K.DisableInstantSearch, PageName, !value); + + partial void OnUpperLowerCaseChanged(bool value) => FilterPackages(); + partial void OnIgnoreSpecialCharsChanged(bool value) => FilterPackages(); + partial void OnSearchModeChanged(SearchMode value) + { + OnPropertyChanged(nameof(SearchMode_Both)); + OnPropertyChanged(nameof(SearchMode_Name)); + OnPropertyChanged(nameof(SearchMode_Id)); + OnPropertyChanged(nameof(SearchMode_Exact)); + OnPropertyChanged(nameof(SearchMode_Similar)); + FilterPackages(); + } + + // One bool property per mode — used for two-way RadioButton bindings. + // Mutual exclusion is enforced by the ViewModel: setting any one to true + // changes SearchMode, which notifies all five properties. + public bool SearchMode_Both { get => SearchMode == SearchMode.Both; set { if (value) SearchMode = SearchMode.Both; } } + public bool SearchMode_Name { get => SearchMode == SearchMode.Name; set { if (value) SearchMode = SearchMode.Name; } } + public bool SearchMode_Id { get => SearchMode == SearchMode.Id; set { if (value) SearchMode = SearchMode.Id; } } + public bool SearchMode_Exact { get => SearchMode == SearchMode.Exact; set { if (value) SearchMode = SearchMode.Exact; } } + public bool SearchMode_Similar { get => SearchMode == SearchMode.Similar; set { if (value) SearchMode = SearchMode.Similar; } } + + private bool _suppressSelectionRecompute; + partial void OnAllPackagesCheckedChanged(bool? value) + { + _suppressSelectionRecompute = true; + try + { + if (value == true) FilteredPackages.SelectAll(); + else if (value == false) FilteredPackages.ClearSelection(); + } + finally + { + _suppressSelectionRecompute = false; + } + } + + // ─── Sources ────────────────────────────────────────────────────────────── + public void AddPackageToSourcesList(IPackage package) + { + IManagerSource source = package.Source; + if (!UsedManagers.Contains(source.Manager)) + { + UsedManagers.Add(source.Manager); + var node = new SourceTreeNode + { + PackageName = source.Manager.DisplayName, + PackageID = package.Id, + Version = package.VersionString, + Source = package.Source.Name + }; + + var existing = GetAllSourceNodes(); + if (existing.Count == 0 || existing.Count(n => n.IsSelected) >= existing.Count / 2) + node.IsSelected = true; + + AddRootSourceNode(node); + RootNodeForManager.TryAdd(source.Manager, node); + UsedSourcesForManager.TryAdd(source.Manager, []); + SourcesPlaceholderVisible = false; + SourcesTreeVisible = true; + } + + if ((!UsedSourcesForManager.ContainsKey(source.Manager) + || !UsedSourcesForManager[source.Manager].Contains(source)) + && source.Manager.Capabilities.SupportsCustomSources) + { + UsedSourcesForManager[source.Manager].Add(source); + var item = new SourceTreeNode + { + PackageName = source.Name, + PackageID = package.Id, + Version = package.VersionString, + Source = package.Source.Name + }; + NodesForSources.TryAdd(source, item); + + if (source.IsVirtualManager) + { + item.IsSelected = _localPackagesNode.IsSelected; + item.PropertyChanged += OnRootSourceNodePropertyChanged; + _localPackagesNode.Children.Add(item); + if (!GetAllSourceNodes().Contains(_localPackagesNode)) + { + AddRootSourceNode(_localPackagesNode); + _localPackagesNode.IsSelected = true; + } + } + else + { + var rootNode = RootNodeForManager[source.Manager]; + item.IsSelected = rootNode.IsSelected; + item.PropertyChanged += OnRootSourceNodePropertyChanged; + rootNode.Children.Add(item); + } + } + } + + public void ClearSourcesList() + { + foreach (var node in SourceNodes) + { + node.PropertyChanged -= OnRootSourceNodePropertyChanged; + foreach (var child in node.Children) + child.PropertyChanged -= OnRootSourceNodePropertyChanged; + } + UsedManagers.Clear(); + SourceNodes.Clear(); + UsedSourcesForManager.Clear(); + RootNodeForManager.Clear(); + NodesForSources.Clear(); + _localPackagesNode.Children.Clear(); + } + + private void AddRootSourceNode(SourceTreeNode node) + { + node.PropertyChanged += OnRootSourceNodePropertyChanged; + SourceNodes.Add(node); + } + + private void OnRootSourceNodePropertyChanged(object? sender, PropertyChangedEventArgs e) + { + if (e.PropertyName == nameof(SourceTreeNode.IsSelected)) + { + if (sender is SourceTreeNode node && SourceNodes.Contains(node)) + { + _isSynchronizingSourceSelection = true; + try + { + foreach (var child in node.Children) + { + child.IsSelected = node.IsSelected; + } + } + finally + { + _isSynchronizingSourceSelection = false; + } + } + + if (_isSynchronizingSourceSelection) + return; + + FilterPackages(); + } + } + private List GetAllSourceNodes() => SourceNodes.ToList(); + + private (List Sources, List Managers) GetSelectedSourceFilters() + { + var visibleSources = new List(); + var visibleManagers = new List(); + + foreach (var node in GetSelectedSourceNodes()) + { + var source = NodesForSources.FirstOrDefault(x => ReferenceEquals(x.Value, node)).Key; + if (source is not null) + { + if (!visibleSources.Contains(source)) + visibleSources.Add(source); + continue; + } + + var manager = RootNodeForManager.FirstOrDefault(x => ReferenceEquals(x.Value, node)).Key; + if (manager is null) + continue; + + if (!visibleManagers.Contains(manager)) + visibleManagers.Add(manager); + + if (!manager.Capabilities.SupportsCustomSources || node.Children.Count > 0) + continue; + + foreach (IManagerSource managerSource in manager.SourcesHelper.Factory.GetAvailableSources()) + { + if (!visibleSources.Contains(managerSource)) + visibleSources.Add(managerSource); + } + } + + return (visibleSources, visibleManagers); + } + + private List GetSelectedSourceNodes() + { + var result = new List(); + foreach (var root in SourceNodes) + { + if (root.IsSelected) result.Add(root); + result.AddRange(root.Children.Where(c => c.IsSelected)); + } + return result; + } + + public void SetSourceNodeSelected(SourceTreeNode node, bool selected) => node.IsSelected = selected; + + public void ClearSourceSelection() + { + foreach (var n in SourceNodes) + { + n.IsSelected = false; + foreach (var c in n.Children) c.IsSelected = false; + } + } + + public void SelectAllSources() + { + foreach (var n in SourceNodes) + { + n.IsSelected = true; + foreach (var c in n.Children) c.IsSelected = true; + } + } + + // ─── Header texts ───────────────────────────────────────────────────────── + public void UpdateHeaderTexts() + { + bool isList = ViewMode == PackageViewMode.List; + NameHeaderText = isList ? CoreTools.Translate("Package Name") : ""; + IdHeaderText = isList ? CoreTools.Translate("Package ID") : ""; + VersionHeaderText = isList ? CoreTools.Translate("Version") : ""; + NewVersionHeaderText = isList ? CoreTools.Translate("New version") : ""; + SourceHeaderText = isList ? CoreTools.Translate("Source") : ""; + } + + public bool IsListViewMode => ViewMode == PackageViewMode.List; + public bool IsGridViewMode => ViewMode == PackageViewMode.Grid; + public bool IsIconsViewMode => ViewMode == PackageViewMode.Icons; + + // Width of each grid-view card slot. The code-behind recomputes this from the available + // viewport width so cards stretch to fill the row then reflow, matching WinUI's + // UniformGridLayout (ItemsStretch=Fill, MinItemWidth=275) instead of leaving dead space. + [ObservableProperty] private double _gridCardWidth = 275; + + // Same idea for the icons view: stretch tiles to fill the row then reflow (min 128px). + [ObservableProperty] private double _iconCardWidth = 128; + + // Shim for SelectedIndex="{Binding ViewModeIndex}" in AXAML (ListBox requires int) + public int ViewModeIndex + { + get => (int)ViewMode; + set => ViewMode = (PackageViewMode)value; + } + + partial void OnViewModeChanged(PackageViewMode value) + { + UpdateHeaderTexts(); + Settings.SetDictionaryItem(Settings.K.PackageListViewMode, PageName, (int)value); + OnPropertyChanged(nameof(IsListViewMode)); + OnPropertyChanged(nameof(IsGridViewMode)); + OnPropertyChanged(nameof(IsIconsViewMode)); + OnPropertyChanged(nameof(ViewModeIndex)); + } + + // ─── Package count (called by PackageWrapper.IsChecked setter) ──────────── + public void UpdatePackageCount() + { + UpdateSubtitle(); + PackageCountUpdated?.Invoke(); + } + + // ─── Subtitle ───────────────────────────────────────────────────────────── + public void UpdateSubtitle() + { + if (Loader.IsLoading || (LoadsOnStart && !Loader.IsLoaded)) + { + Subtitle = _stillLoadingSubtitle; + return; + } + + if (Loader.Any()) + { + int selected = FilteredPackages.GetCheckedPackages().Count; + string r = CoreTools.Translate( + "{0} packages were found, {1} of which match the specified filters.", + FilteredPackages.Count, + _wrappedPackages.Count + ) + " (" + CoreTools.Translate("{0} selected", selected) + ")"; + + if (_showLastCheckedTime) + r += " " + CoreTools.Translate("(Last checked: {0})", _lastLoadTime.ToString(CultureInfo.CurrentCulture)); + + Subtitle = r; + } + else + { + Subtitle = _noPackagesSubtitleBase + (_showLastCheckedTime + ? " " + CoreTools.Translate("(Last checked: {0})", _lastLoadTime.ToString(CultureInfo.CurrentCulture)) + : ""); + } + } + + // ─── Commands ───────────────────────────────────────────────────────────── + [RelayCommand] private async Task Reload() => await LoadPackages(ReloadReason.Manual); + [RelayCommand] private void SelectAllSources_Cmd() { SelectAllSources(); FilterPackages(); } + [RelayCommand] private void ClearSourceSelection_Cmd() { ClearSourceSelection(); FilterPackages(); } + [RelayCommand] private void RequestHelp() => HelpRequested?.Invoke(); + [RelayCommand] private void RequestManageIgnored() => ManageIgnoredRequested?.Invoke(); + + // ─── Sort commands ──────────────────────────────────────────────────────── + [RelayCommand] private void SortByName() => SortFieldIndex = 0; + [RelayCommand] private void SortById() => SortFieldIndex = 1; + [RelayCommand] private void SortByVersion() => SortFieldIndex = 2; + [RelayCommand] private void SortByNewVersion() => SortFieldIndex = 3; + [RelayCommand] private void SortBySource() => SortFieldIndex = 4; + [RelayCommand] private void SetSortAscending() => SortAscending = true; + [RelayCommand] private void SetSortDescending() => SortAscending = false; + + [RelayCommand] + private void SubmitMegaQuery(string query) + { + MegaQueryVisible = false; + _searchQuery = query?.Trim() ?? ""; + FilterPackages(fromQuery: true); + } + + // ─── Keyboard / search-box actions (called by the View's interface impls) ── + public void TriggerReload() + { + if (!DisableReload) + _ = LoadPackages(ReloadReason.Manual); + } + + public void ToggleSelectAll() + { + if (AllPackagesChecked != true) + { + AllPackagesChecked = true; + FilteredPackages.SelectAll(); + AccessibilityAnnouncementService.Announce( + CoreTools.Translate("All packages selected")); + } + else + { + AllPackagesChecked = false; + FilteredPackages.ClearSelection(); + AccessibilityAnnouncementService.Announce( + CoreTools.Translate("Package selection cleared")); + } + } + + public void HandleSearchSubmitted() + { + if (MegaQueryBoxEnabled) SubmitSearch(); + else FilterPackages(fromQuery: true); + } + + // ─── Operation launchers ───────────────────────────────────────────────── + public static async Task LaunchInstall( + IEnumerable packages, + bool? elevated = null, + bool? interactive = null, + bool? no_integrity = null) + { + foreach (var pkg in packages) + { + var opts = await InstallOptionsFactory.LoadApplicableAsync( + pkg, elevated: elevated, interactive: interactive, no_integrity: no_integrity); + var op = new InstallPackageOperation(pkg, opts); + op.OperationSucceeded += (_, _) => TelemetryHandler.InstallPackage(pkg, TEL_OP_RESULT.SUCCESS, TEL_InstallReferral.DIRECT_SEARCH); + op.OperationFailed += (_, _) => TelemetryHandler.InstallPackage(pkg, TEL_OP_RESULT.FAILED, TEL_InstallReferral.DIRECT_SEARCH); + AvaloniaOperationRegistry.Add(op); + _ = op.MainThread(); + } + } + + // ─── Focus (triggers view to focus the list) ────────────────────────────── + public void RequestFocusList() => FocusListRequested?.Invoke(); + + // ─── FilterHelpers (inner static class) ────────────────────────────────── + internal static class FilterHelpers + { + public static string NormalizeCase(string input) => input.ToLower(); + + public static string NormalizeSpecialCharacters(string input) + { + input = input.Replace("-", "").Replace("_", "").Replace(" ", "") + .Replace("@", "").Replace("\t", "").Replace(".", "") + .Replace(",", "").Replace(":", ""); + foreach (var (replacement, chars) in new (char, string)[] + { + ('a',"àáäâ"),('e',"èéëê"),('i',"ìíïî"),('o',"òóöô"), + ('u',"ùúüû"),('y',"ýÿ"),('c',"ç"),('ñ',"n"), + }) + foreach (char c in chars) input = input.Replace(c, replacement); + return input; + } + + public static bool NameContains(IPackage pkg, string q, List> f) + { var n = pkg.Name; foreach (var x in f) n = x(n); return n.Contains(q); } + + public static bool IdContains(IPackage pkg, string q, List> f) + { var id = pkg.Id; foreach (var x in f) id = x(id); return id.Contains(q); } + + public static bool NameOrIdContains(IPackage pkg, string q, List> f) + => NameContains(pkg, q, f) || IdContains(pkg, q, f); + + public static bool NameOrIdExactMatch(IPackage pkg, string q, List> f) + { + var id = pkg.Id; foreach (var x in f) id = x(id); if (q == id) return true; + var n = pkg.Name; foreach (var x in f) n = x(n); return q == n; + } + } +} diff --git a/src/UniGetUI.Avalonia/ViewModels/ViewModelBase.cs b/src/UniGetUI.Avalonia/ViewModels/ViewModelBase.cs new file mode 100644 index 0000000..aca5b14 --- /dev/null +++ b/src/UniGetUI.Avalonia/ViewModels/ViewModelBase.cs @@ -0,0 +1,11 @@ +using CommunityToolkit.Mvvm.ComponentModel; + +namespace UniGetUI.Avalonia.ViewModels; + +/// +/// Base class for all ViewModels. Inherits ObservableObject from CommunityToolkit.Mvvm, +/// which provides INotifyPropertyChanged, SetProperty, and [ObservableProperty] source-generator support. +/// +public abstract class ViewModelBase : ObservableObject +{ +} diff --git a/src/UniGetUI.Avalonia/Views/BaseView.cs b/src/UniGetUI.Avalonia/Views/BaseView.cs new file mode 100644 index 0000000..7f0ab4b --- /dev/null +++ b/src/UniGetUI.Avalonia/Views/BaseView.cs @@ -0,0 +1,13 @@ +using Avalonia.Controls; +using UniGetUI.Avalonia.ViewModels; + +namespace UniGetUI.Avalonia.Views; + +/// +/// Typed base class for all UserControl views. +/// Provides a strongly-typed ViewModel property that mirrors DataContext. +/// +public abstract class BaseView : UserControl where TViewModel : ViewModelBase +{ + public TViewModel? ViewModel => DataContext as TViewModel; +} diff --git a/src/UniGetUI.Avalonia/Views/Controls/DataGridWheelAnimator.cs b/src/UniGetUI.Avalonia/Views/Controls/DataGridWheelAnimator.cs new file mode 100644 index 0000000..d9eb2f3 --- /dev/null +++ b/src/UniGetUI.Avalonia/Views/Controls/DataGridWheelAnimator.cs @@ -0,0 +1,80 @@ +using System; +using System.Reflection; +using Avalonia; +using Avalonia.Controls; +using Avalonia.Input; +using Avalonia.Interactivity; +using UniGetUI.Avalonia.Infrastructure; + +namespace UniGetUI.Avalonia.Views.Controls; + +/// +/// Eases DataGrid wheel scrolling to a stop (WinUI-like) instead of jumping the whole delta at once. +/// The grid has no public scroll offset, so we drive its internal UpdateScroll via reflection; if that +/// ever breaks we never attach and the stock instant behavior stands. +/// +public sealed class DataGridWheelAnimator +{ + private static readonly MethodInfo? UpdateScroll = + typeof(DataGrid).GetMethod("UpdateScroll", BindingFlags.Instance | BindingFlags.NonPublic); + + private const double WheelStep = 70.0; // pixels travelled per notch; larger = faster scroll, more to glide over + private const double Tau = 0.12; // ease time constant in seconds; larger = longer, more visible glide + + private readonly DataGrid _grid; + private readonly object?[] _args = new object?[1]; + private double _pending; + private TimeSpan? _lastFrame; + private bool _frameRequested; + + private DataGridWheelAnimator(DataGrid grid) + { + _grid = grid; + grid.AddHandler(InputElement.PointerWheelChangedEvent, OnWheel, RoutingStrategies.Tunnel); + } + + public static void Attach(DataGrid grid) + { + if (UpdateScroll is not null) _ = new DataGridWheelAnimator(grid); + } + + private void OnWheel(object? sender, PointerWheelEventArgs e) + { + // Fall back to the native instant scroll for horizontal/shift, or when reduced motion is on. + if (e.Delta.Y == 0 || e.KeyModifiers == KeyModifiers.Shift || MotionPreference.ReducedMotion) return; + + if (_pending == 0) _lastFrame = null; // fresh gesture: don't carry a stale timestamp + _pending += e.Delta.Y * WheelStep; + e.Handled = true; + RequestFrame(); + } + + private void RequestFrame() + { + if (_frameRequested) return; + if (TopLevel.GetTopLevel(_grid) is not { } top) { _pending = 0; return; } + _frameRequested = true; + top.RequestAnimationFrame(OnFrame); + } + + private void OnFrame(TimeSpan now) + { + _frameRequested = false; + if (_pending == 0) return; + + double dt = _lastFrame is { } last ? (now - last).TotalSeconds : 1.0 / 60.0; + _lastFrame = now; + if (dt <= 0) dt = 1.0 / 60.0; + if (dt > 0.1) dt = 0.1; // clamp after a stall so the glide doesn't lurch + + double remaining = _pending * Math.Exp(-dt / Tau); + double step = Math.Abs(remaining) < 0.5 ? _pending : _pending - remaining; + + _args[0] = new Vector(0, step); + bool scrolled = UpdateScroll!.Invoke(_grid, _args) is true; + _pending -= step; + + if (!scrolled) { _pending = 0; return; } + if (_pending != 0) RequestFrame(); + } +} diff --git a/src/UniGetUI.Avalonia/Views/Controls/InfoBar.axaml b/src/UniGetUI.Avalonia/Views/Controls/InfoBar.axaml new file mode 100644 index 0000000..1ae4be5 --- /dev/null +++ b/src/UniGetUI.Avalonia/Views/Controls/InfoBar.axaml @@ -0,0 +1,115 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/UniGetUI.Avalonia/Views/Controls/InfoBar.axaml.cs b/src/UniGetUI.Avalonia/Views/Controls/InfoBar.axaml.cs new file mode 100644 index 0000000..9191e6d --- /dev/null +++ b/src/UniGetUI.Avalonia/Views/Controls/InfoBar.axaml.cs @@ -0,0 +1,76 @@ +using Avalonia; +using Avalonia.Controls; +using Avalonia.Media; +using UniGetUI.Avalonia.Infrastructure; +using UniGetUI.Avalonia.ViewModels; + +namespace UniGetUI.Avalonia.Views.Controls; + +public partial class InfoBar : UserControl +{ + // Severity glyphs reuse the app's shared round symbols (same SvgIcon-by-path convention + // as the rest of the app), tinted with the severity colour. + private const string InfoIcon = "avares://UniGetUI/Assets/Symbols/info_round.svg"; + private const string WarningIcon = "avares://UniGetUI/Assets/Symbols/warning_round.svg"; + private const string ErrorIcon = "avares://UniGetUI/Assets/Symbols/close_round.svg"; + private const string SuccessIcon = "avares://UniGetUI/Assets/Symbols/success_round.svg"; + + public InfoBar() + { + InitializeComponent(); + DataContextChanged += OnDataContextChanged; + + // Play the slide-in entrance only when the OS isn't set to minimize motion. + if (!MotionPreference.ReducedMotion) + BodyBorder.Classes.Add("animate-in"); + } + + private InfoBarViewModel? _vm; + + private void OnDataContextChanged(object? sender, EventArgs e) + { + _vm?.PropertyChanged -= OnViewModelPropertyChanged; + + _vm = DataContext as InfoBarViewModel; + + _vm?.PropertyChanged += OnViewModelPropertyChanged; + if (_vm is not null) + ApplySeverity(_vm.Severity); + } + + private void OnViewModelPropertyChanged(object? sender, System.ComponentModel.PropertyChangedEventArgs e) + { + if (e.PropertyName == nameof(InfoBarViewModel.Severity) && _vm is not null) + ApplySeverity(_vm.Severity); + } + + private void ApplySeverity(InfoBarSeverity severity) + { + // Background + border: swap a single CSS class — DynamicResource in the style + // handles theme changes automatically without any event subscription. + BodyBorder.Classes.Set("severity-success", severity == InfoBarSeverity.Success); + BodyBorder.Classes.Set("severity-error", severity == InfoBarSeverity.Error); + BodyBorder.Classes.Set("severity-warning", severity == InfoBarSeverity.Warning); + BodyBorder.Classes.Set("severity-info", severity == InfoBarSeverity.Informational); + + // Strip colour (solid, not theme-sensitive) + var stripColor = severity switch + { + InfoBarSeverity.Warning => Color.Parse("#F7A800"), + InfoBarSeverity.Error => Color.Parse("#C42B1C"), + InfoBarSeverity.Success => Color.Parse("#107C10"), + _ => Color.Parse("#0078D4"), + }; + SeverityStrip.Background = new SolidColorBrush(stripColor); + + // Icon (shared SVG asset, tinted with the severity colour) + SeverityIcon.Path = severity switch + { + InfoBarSeverity.Warning => WarningIcon, + InfoBarSeverity.Error => ErrorIcon, + InfoBarSeverity.Success => SuccessIcon, + _ => InfoIcon, + }; + SeverityIcon.Foreground = new SolidColorBrush(stripColor); + } +} diff --git a/src/UniGetUI.Avalonia/Views/Controls/LogTextEditor.cs b/src/UniGetUI.Avalonia/Views/Controls/LogTextEditor.cs new file mode 100644 index 0000000..c5e29fe --- /dev/null +++ b/src/UniGetUI.Avalonia/Views/Controls/LogTextEditor.cs @@ -0,0 +1,122 @@ +using System.Text; +using Avalonia; +using Avalonia.Controls.Primitives; +using Avalonia.Media; +using Avalonia.Styling; +using AvaloniaEdit; +using AvaloniaEdit.Document; +using AvaloniaEdit.Rendering; +using UniGetUI.Avalonia.ViewModels.Pages.LogPages; + +namespace UniGetUI.Avalonia.Views.Controls; + +// Read-only colored log/console viewer shared by every log and command-output view: virtualized +// rendering (smooth scroll), free character-level selection across lines, per-line colors, and a +// theme-aware hyperlink color. +public class LogTextEditor : TextEditor +{ + // Per physical line color, indexed by 0-based document line number. + private readonly List _lineColors = []; + + // Use AvaloniaEdit's TextEditor theme/template; a subclass key has no matching ControlTheme. + protected override Type StyleKeyOverride => typeof(TextEditor); + + public LogTextEditor() + { + IsReadOnly = true; + ShowLineNumbers = false; + WordWrap = true; + Background = Brushes.Transparent; + FontFamily = new FontFamily("Cascadia Mono,Consolas,Menlo,monospace"); + FontSize = 12; + Padding = new Thickness(8); + HorizontalScrollBarVisibility = ScrollBarVisibility.Disabled; + VerticalScrollBarVisibility = ScrollBarVisibility.Auto; + + TextArea.TextView.LineTransformers.Add(new SeverityColorizer(_lineColors)); + UpdateLinkColor(); + ActualThemeVariantChanged += (_, _) => UpdateLinkColor(); + } + + public void SetLines(IEnumerable lines) + { + _lineColors.Clear(); + var sb = new StringBuilder(); + bool first = true; + + foreach (var item in lines) + { + foreach (string physicalLine in item.Text.Split('\n')) + { + if (!first) sb.Append('\n'); + sb.Append(physicalLine); + _lineColors.Add(item.Foreground); + first = false; + } + } + + Text = sb.ToString(); + TextArea.TextView.Redraw(); + } + + public void AppendLine(LogLineItem line) + { + var sb = new StringBuilder(); + foreach (string physicalLine in line.Text.Split('\n')) + { + if (Document.TextLength > 0 || sb.Length > 0) + sb.Append('\n'); + sb.Append(physicalLine); + _lineColors.Add(line.Foreground); + } + + Document.Insert(Document.TextLength, sb.ToString()); + } + + // Overwrites the last physical line in place instead of appending, so carriage-return progress + // redraws (installer spinners) repaint a single line rather than flooding the view. + public void ReplaceLastLine(LogLineItem line) + { + if (Document.TextLength == 0 || _lineColors.Count == 0) + { + AppendLine(line); + return; + } + + DocumentLine last = Document.GetLineByNumber(Document.LineCount); + Document.Replace(last.Offset, last.Length, line.Text); + _lineColors[^1] = line.Foreground; + } + + public void ClearLines() + { + _lineColors.Clear(); + Text = string.Empty; + } + + public void ScrollToBottom() => ScrollToEnd(); + + // True when the view is pinned to the last line; used to keep auto-scroll from fighting a manual scroll-up. + public bool IsScrolledToBottom => ExtentHeight - ViewportHeight - VerticalOffset <= 1.0; + + // AvaloniaEdit auto-links URLs; its default link brush is too dark to read on the dark theme. + private void UpdateLinkColor() + { + bool isDark = Application.Current?.ActualThemeVariant == ThemeVariant.Dark; + TextArea.TextView.LinkTextForegroundBrush = + new SolidColorBrush(isDark ? Color.FromRgb(100, 170, 255) : Color.FromRgb(0, 0, 205)); + } + + private sealed class SeverityColorizer(List lineColors) : DocumentColorizingTransformer + { + protected override void ColorizeLine(DocumentLine line) + { + if (line.Length == 0) return; + int index = line.LineNumber - 1; + if (index < 0 || index >= lineColors.Count) return; + + IBrush brush = lineColors[index]; + ChangeLinePart(line.Offset, line.EndOffset, element => element.TextRunProperties.SetForegroundBrush(brush)); + } + } +} diff --git a/src/UniGetUI.Avalonia/Views/Controls/PackageIconLoader.cs b/src/UniGetUI.Avalonia/Views/Controls/PackageIconLoader.cs new file mode 100644 index 0000000..706b3cb --- /dev/null +++ b/src/UniGetUI.Avalonia/Views/Controls/PackageIconLoader.cs @@ -0,0 +1,50 @@ +using System; +using Avalonia; +using Avalonia.Controls; +using UniGetUI.PackageEngine.PackageClasses; + +namespace UniGetUI.Avalonia.Views.Controls; + +// Calls PackageWrapper.EnsureIconLoaded when the icon element attaches or is rebound, so only +// realized (visible) rows in the virtualized list load their icons. +public static class PackageIconLoader +{ + public static readonly AttachedProperty TrackProperty = + AvaloniaProperty.RegisterAttached("Track", typeof(PackageIconLoader)); + + public static void SetTrack(Control control, bool value) => control.SetValue(TrackProperty, value); + public static bool GetTrack(Control control) => control.GetValue(TrackProperty); + + static PackageIconLoader() + { + TrackProperty.Changed.AddClassHandler((control, e) => + { + if (e.GetNewValue()) + { + control.AttachedToVisualTree += OnAttached; + control.DataContextChanged += OnDataContextChanged; + if (control.IsLoaded) TryLoad(control); + } + else + { + control.AttachedToVisualTree -= OnAttached; + control.DataContextChanged -= OnDataContextChanged; + } + }); + } + + private static void OnAttached(object? sender, VisualTreeAttachmentEventArgs e) + => TryLoad((Control)sender!); + + private static void OnDataContextChanged(object? sender, EventArgs e) + { + var control = (Control)sender!; + // A recycled container also fires this while detached; only load when realized. + if (control.IsLoaded) TryLoad(control); + } + + private static void TryLoad(Control control) + { + if (control.DataContext is PackageWrapper wrapper) wrapper.EnsureIconLoaded(); + } +} diff --git a/src/UniGetUI.Avalonia/Views/Controls/Settings/ButtonCard.cs b/src/UniGetUI.Avalonia/Views/Controls/Settings/ButtonCard.cs new file mode 100644 index 0000000..bb3f8c8 --- /dev/null +++ b/src/UniGetUI.Avalonia/Views/Controls/Settings/ButtonCard.cs @@ -0,0 +1,48 @@ +using Avalonia; +using Avalonia.Controls; +using Avalonia.Interactivity; +using UniGetUI.Core.Tools; + +namespace UniGetUI.Avalonia.Views.Controls.Settings; + +public sealed partial class ButtonCard : SettingsCard +{ + private readonly Button _button = new(); + + public string ButtonText + { + set + { + _button.Content = value; + ApplyAutomationMetadata(_button, GetAutomationNameText(), value); + } + } + + public string Text + { + set + { + Header = value; + ApplyAutomationMetadata(_button, value); + } + } + + public new event EventHandler? Click; + + public ButtonCard() + { + _button.MinWidth = 200; + _button.Click += (_, _) => Click?.Invoke(this, EventArgs.Empty); + Content = _button; + ApplyAutomationMetadata(_button); + } + + protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change) + { + base.OnPropertyChanged(change); + if (change.Property == CommandProperty) + _button.Command = Command; + else if (change.Property == CommandParameterProperty) + _button.CommandParameter = CommandParameter; + } +} diff --git a/src/UniGetUI.Avalonia/Views/Controls/Settings/CheckboxButtonCard.cs b/src/UniGetUI.Avalonia/Views/Controls/Settings/CheckboxButtonCard.cs new file mode 100644 index 0000000..e10f438 --- /dev/null +++ b/src/UniGetUI.Avalonia/Views/Controls/Settings/CheckboxButtonCard.cs @@ -0,0 +1,129 @@ +using Avalonia; +using Avalonia.Automation; +using Avalonia.Controls; +using Avalonia.Interactivity; +using Avalonia.Layout; +using Avalonia.Media; +using UniGetUI.Avalonia.Infrastructure; +using UniGetUI.Core.Tools; +using CoreSettings = global::UniGetUI.Core.SettingsEngine.Settings; + +namespace UniGetUI.Avalonia.Views.Controls.Settings; + +public sealed partial class CheckboxButtonCard : SettingsCard +{ + public ToggleSwitch _checkbox; + public TextBlock _textblock; + public Button Button; + private readonly TextBlock _stateLabel; + private static readonly string EnabledLabel = CoreTools.Translate("Enabled"); + private static readonly string DisabledLabel = CoreTools.Translate("Disabled"); + private bool IS_INVERTED; + + private CoreSettings.K setting_name = CoreSettings.K.Unset; + public CoreSettings.K SettingName + { + set + { + setting_name = value; + IS_INVERTED = CoreSettings.ResolveKey(value).StartsWith("Disable"); + _checkbox.IsChecked = CoreSettings.Get(setting_name) ^ IS_INVERTED ^ ForceInversion; + _textblock.Opacity = (_checkbox.IsChecked ?? false) ? 1 : 0.7; + UpdateStateLabel(); + Button.IsEnabled = (_checkbox.IsChecked ?? false) || _buttonAlwaysOn; + } + } + + public bool ForceInversion { get; set; } + public bool Checked => _checkbox.IsChecked ?? false; + + public event EventHandler? StateChanged; + public new event EventHandler? Click; + + public string CheckboxText + { + set + { + _textblock.Text = value; + ApplyAutomationMetadata(_checkbox, value); + ApplyAutomationMetadata(Button, value); + } + } + + public string ButtonText + { + set + { + Button.Content = value; + ApplyAutomationMetadata(Button, _textblock.Text, value); + } + } + + private bool _buttonAlwaysOn; + public bool ButtonAlwaysOn + { + set + { + _buttonAlwaysOn = value; + Button.IsEnabled = (_checkbox.IsChecked ?? false) || _buttonAlwaysOn; + } + } + + public CheckboxButtonCard() + { + Button = new Button { Margin = new Thickness(0, 8, 0, 0) }; + _checkbox = new ToggleSwitch + { + // OnContent/OffContent intentionally left null — state label is a + // sibling TextBlock to the LEFT of the knob. + OnContent = null, + OffContent = null, + VerticalAlignment = VerticalAlignment.Center, + }; + _stateLabel = new TextBlock + { + Text = DisabledLabel, + VerticalAlignment = VerticalAlignment.Center, + Margin = new Thickness(0, 0, 8, 0), + }; + AutomationProperties.SetAccessibilityView(_stateLabel, AccessibilityView.Raw); + _textblock = new TextBlock + { + Margin = new Thickness(2, 0, 0, 0), + VerticalAlignment = VerticalAlignment.Center, + TextWrapping = TextWrapping.Wrap, + FontSize = 14, + }; + IS_INVERTED = false; + AutomationProperties.SetAccessibilityView(Button, AccessibilityView.Control); + + Content = new StackPanel + { + Orientation = Orientation.Horizontal, + VerticalAlignment = VerticalAlignment.Center, + Children = { _stateLabel, _checkbox }, + }; + Header = _textblock; + Description = Button; + + _checkbox.IsCheckedChanged += (_, _) => + { + CoreSettings.Set(setting_name, (_checkbox.IsChecked ?? false) ^ IS_INVERTED ^ ForceInversion); + StateChanged?.Invoke(this, EventArgs.Empty); + Button.IsEnabled = (_checkbox.IsChecked ?? false) ? true : _buttonAlwaysOn; + _textblock.Opacity = (_checkbox.IsChecked ?? false) ? 1 : 0.7; + UpdateStateLabel(); + if (_textblock.Text is not null) + { + AccessibilityAnnouncementService.AnnounceToggle(_textblock.Text, _checkbox.IsChecked ?? false); + } + }; + Button.Click += (s, e) => Click?.Invoke(s, e); + ApplyAutomationMetadata(_checkbox, _textblock.Text); + } + + private void UpdateStateLabel() + { + _stateLabel.Text = (_checkbox.IsChecked ?? false) ? EnabledLabel : DisabledLabel; + } +} diff --git a/src/UniGetUI.Avalonia/Views/Controls/Settings/CheckboxCard.cs b/src/UniGetUI.Avalonia/Views/Controls/Settings/CheckboxCard.cs new file mode 100644 index 0000000..b106215 --- /dev/null +++ b/src/UniGetUI.Avalonia/Views/Controls/Settings/CheckboxCard.cs @@ -0,0 +1,238 @@ +using System.Windows.Input; +using Avalonia; +using Avalonia.Automation; +using Avalonia.Automation.Peers; +using Avalonia.Controls; +using Avalonia.Interactivity; +using Avalonia.Layout; +using Avalonia.Media; +using UniGetUI.Avalonia.Infrastructure; +using UniGetUI.Core.Tools; +using CoreSettings = global::UniGetUI.Core.SettingsEngine.Settings; + +namespace UniGetUI.Avalonia.Views.Controls.Settings; + +public partial class CheckboxCard : SettingsCard +{ + public static readonly StyledProperty StateChangedCommandProperty = + AvaloniaProperty.Register(nameof(StateChangedCommand)); + + public ICommand? StateChangedCommand + { + get => GetValue(StateChangedCommandProperty); + set => SetValue(StateChangedCommandProperty, value); + } + + public ToggleSwitch _checkbox; + public TextBlock _textblock; + public TextBlock _warningBlock; + private readonly TextBlock _stateLabel; + private static readonly string EnabledLabel = CoreTools.Translate("Enabled"); + private static readonly string DisabledLabel = CoreTools.Translate("Disabled"); + protected bool IS_INVERTED; + + private CoreSettings.K setting_name = CoreSettings.K.Unset; + public CoreSettings.K SettingName + { + set + { + _checkbox.IsCheckedChanged -= _checkbox_Toggled; + setting_name = value; + IS_INVERTED = CoreSettings.ResolveKey(value).StartsWith("Disable"); + _checkbox.IsChecked = CoreSettings.Get(setting_name) ^ IS_INVERTED ^ ForceInversion; + _textblock.Opacity = (_checkbox.IsChecked ?? false) ? 1 : 0.7; + UpdateStateLabel(); + _checkbox.IsCheckedChanged += _checkbox_Toggled; + SyncToggleItemStatus(); + } + } + + public bool ForceInversion { get; set; } + + public bool Checked => _checkbox.IsChecked ?? false; + + public virtual event EventHandler? StateChanged; + + public string Text + { + set + { + _textblock.Text = value; + ApplyAutomationMetadata(_checkbox, value, _warningBlock.IsVisible ? _warningBlock.Text : null); + } + } + + public string WarningText + { + set + { + _warningBlock.Text = value; + _warningBlock.IsVisible = value.Any(); + ApplyAutomationMetadata(_checkbox, _textblock.Text, _warningBlock.IsVisible ? value : null); + } + } + + public double WarningOpacity + { + set => _warningBlock.Opacity = value; + } + + public CheckboxCard() + { + _checkbox = new ToggleSwitch + { + // OnContent/OffContent intentionally left null — the state label is + // rendered as a sibling TextBlock to the LEFT of the knob below. + OnContent = null, + OffContent = null, + VerticalAlignment = VerticalAlignment.Center, + }; + // Force CheckBox role so macOS VoiceOver exposes checked/unchecked state + AutomationProperties.SetControlTypeOverride(_checkbox, AutomationControlType.CheckBox); + _stateLabel = new TextBlock + { + Text = DisabledLabel, + VerticalAlignment = VerticalAlignment.Center, + Margin = new Thickness(0, 0, 8, 0), + }; + AutomationProperties.SetAccessibilityView(_stateLabel, AccessibilityView.Raw); + _textblock = new TextBlock + { + VerticalAlignment = VerticalAlignment.Center, + TextWrapping = TextWrapping.Wrap, + FontSize = 14, + }; + _warningBlock = new TextBlock + { + VerticalAlignment = VerticalAlignment.Center, + TextWrapping = TextWrapping.Wrap, + FontSize = 12, + Opacity = 0.7, + IsVisible = false, + }; + _warningBlock.Classes.Add("setting-warning-text"); + IS_INVERTED = false; + AutomationProperties.SetAccessibilityView(_warningBlock, AccessibilityView.Raw); + + Content = new StackPanel + { + Orientation = Orientation.Horizontal, + VerticalAlignment = VerticalAlignment.Center, + Children = { _stateLabel, _checkbox }, + }; + Header = new StackPanel + { + Spacing = 4, + Orientation = Orientation.Vertical, + Children = { _textblock, _warningBlock }, + }; + + _checkbox.IsCheckedChanged += _checkbox_Toggled; + ApplyAutomationMetadata(_checkbox, _textblock.Text); + } + + protected void UpdateStateLabel() + { + _stateLabel.Text = (_checkbox.IsChecked ?? false) ? EnabledLabel : DisabledLabel; + } + + protected virtual void _checkbox_Toggled(object? sender, RoutedEventArgs e) + { + CoreSettings.Set(setting_name, (_checkbox.IsChecked ?? false) ^ IS_INVERTED ^ ForceInversion); + StateChanged?.Invoke(this, EventArgs.Empty); + _textblock.Opacity = (_checkbox.IsChecked ?? false) ? 1 : 0.7; + UpdateStateLabel(); + SyncToggleItemStatus(); + if (_textblock.Text is not null) + { + AccessibilityAnnouncementService.AnnounceToggle(_textblock.Text, _checkbox.IsChecked ?? false); + } + var cmd = StateChangedCommand; + if (cmd?.CanExecute(null) == true) + cmd.Execute(null); + } + + protected void SyncToggleItemStatus() + { + string state = (_checkbox.IsChecked ?? false) + ? CoreTools.Translate("Enabled") + : CoreTools.Translate("Disabled"); + // ItemStatus: some screen readers read this separately + AutomationProperties.SetItemStatus(_checkbox, state); + // Name with state suffix: guarantees VoiceOver announces state on macOS + // where ToggleSwitch AX role may not expose IsChecked natively + string? baseName = _textblock.Text; + if (!string.IsNullOrEmpty(baseName)) + { + AutomationProperties.SetName(_checkbox, $"{baseName}, {state}"); + } + } +} + +public partial class CheckboxCard_Dict : CheckboxCard +{ + public override event EventHandler? StateChanged; + + private CoreSettings.K _dictName = CoreSettings.K.Unset; + private bool _disableStateChangedEvent; + + private string _keyName = ""; + public string KeyName + { + set + { + _keyName = value; + if (_dictName != CoreSettings.K.Unset && _keyName.Any()) + { + _disableStateChangedEvent = true; + _checkbox.IsChecked = + CoreSettings.GetDictionaryItem(_dictName, _keyName) + ^ IS_INVERTED + ^ ForceInversion; + _textblock.Opacity = (_checkbox.IsChecked ?? false) ? 1 : 0.7; + UpdateStateLabel(); + _disableStateChangedEvent = false; + SyncToggleItemStatus(); + } + } + } + + public CoreSettings.K DictionaryName + { + set + { + _dictName = value; + IS_INVERTED = CoreSettings.ResolveKey(value).StartsWith("Disable"); + if (_dictName != CoreSettings.K.Unset && _keyName.Any()) + { + _checkbox.IsChecked = + CoreSettings.GetDictionaryItem(_dictName, _keyName) + ^ IS_INVERTED + ^ ForceInversion; + _textblock.Opacity = (_checkbox.IsChecked ?? false) ? 1 : 0.7; + UpdateStateLabel(); + SyncToggleItemStatus(); + } + } + } + + public CheckboxCard_Dict() : base() { } + + protected override void _checkbox_Toggled(object? sender, RoutedEventArgs e) + { + if (_disableStateChangedEvent) return; + CoreSettings.SetDictionaryItem( + _dictName, + _keyName, + (_checkbox.IsChecked ?? false) ^ IS_INVERTED ^ ForceInversion + ); + StateChanged?.Invoke(this, EventArgs.Empty); + _textblock.Opacity = (_checkbox.IsChecked ?? false) ? 1 : 0.7; + UpdateStateLabel(); + SyncToggleItemStatus(); + if (_textblock.Text is not null) + { + AccessibilityAnnouncementService.AnnounceToggle(_textblock.Text, _checkbox.IsChecked ?? false); + } + } +} diff --git a/src/UniGetUI.Avalonia/Views/Controls/Settings/ComboboxCard.cs b/src/UniGetUI.Avalonia/Views/Controls/Settings/ComboboxCard.cs new file mode 100644 index 0000000..0dcc120 --- /dev/null +++ b/src/UniGetUI.Avalonia/Views/Controls/Settings/ComboboxCard.cs @@ -0,0 +1,103 @@ +using System.Collections.ObjectModel; +using System.Windows.Input; +using Avalonia; +using Avalonia.Controls; +using UniGetUI.Avalonia.Infrastructure; +using UniGetUI.Core.Logging; +using UniGetUI.Core.Tools; +using CoreSettings = global::UniGetUI.Core.SettingsEngine.Settings; + +namespace UniGetUI.Avalonia.Views.Controls.Settings; + +public sealed partial class ComboboxCard : SettingsCard +{ + public static readonly StyledProperty ValueChangedCommandProperty = + AvaloniaProperty.Register(nameof(ValueChangedCommand)); + + public ICommand? ValueChangedCommand + { + get => GetValue(ValueChangedCommandProperty); + set => SetValue(ValueChangedCommandProperty, value); + } + + private readonly ComboBox _combobox = new(); + private readonly ObservableCollection _elements = []; + private readonly Dictionary _values_ref = []; + private readonly Dictionary _inverted_val_ref = []; + + private CoreSettings.K settings_name = CoreSettings.K.Unset; + public CoreSettings.K SettingName + { + set => settings_name = value; + } + + public string Text + { + set + { + Header = value; + ApplyAutomationMetadata(_combobox, value); + } + } + + public event EventHandler? ValueChanged; + + public ComboboxCard() + { + _combobox.MinWidth = 200; + _combobox.ItemsSource = _elements; + Content = _combobox; + ApplyAutomationMetadata(_combobox); + } + + public void AddItem(string name, string value) => AddItem(name, value, true); + + public void AddItem(string name, string value, bool translate) + { + if (translate) name = CoreTools.Translate(name); + _elements.Add(name); + _values_ref.Add(name, value); + _inverted_val_ref.Add(value, name); + } + + public void ShowAddedItems() + { + try + { + string savedItem = CoreSettings.GetValue(settings_name); + _combobox.SelectedIndex = _elements.IndexOf(_inverted_val_ref[savedItem]); + } + catch + { + _combobox.SelectedIndex = 0; + } + _combobox.SelectionChanged += (_, _) => + { + try + { + string selectedName = _combobox.SelectedItem?.ToString() ?? ""; + CoreSettings.SetValue( + settings_name, + _values_ref[selectedName] + ); + ValueChanged?.Invoke(this, EventArgs.Empty); + var cmd = ValueChangedCommand; + if (cmd?.CanExecute(null) == true) + cmd.Execute(null); + string headerText = Header?.ToString() ?? ""; + if (!string.IsNullOrEmpty(headerText) && !string.IsNullOrEmpty(selectedName)) + AccessibilityAnnouncementService.Announce( + CoreTools.Translate("{0}: {1}", headerText, selectedName)); + } + catch (Exception ex) + { + Logger.Warn(ex); + } + }; + } + + public string SelectedValue() => + _combobox.SelectedItem?.ToString() ?? throw new InvalidCastException(); + + public void SelectIndex(int index) => _combobox.SelectedIndex = index; +} diff --git a/src/UniGetUI.Avalonia/Views/Controls/Settings/SecureCheckboxCard.cs b/src/UniGetUI.Avalonia/Views/Controls/Settings/SecureCheckboxCard.cs new file mode 100644 index 0000000..2e3bab4 --- /dev/null +++ b/src/UniGetUI.Avalonia/Views/Controls/Settings/SecureCheckboxCard.cs @@ -0,0 +1,192 @@ +using System.Windows.Input; +using Avalonia; +using Avalonia.Controls; +using Avalonia.Layout; +using Avalonia.Media; +using UniGetUI.Avalonia.Extensions; +using UniGetUI.Avalonia.Infrastructure; +using UniGetUI.Core.Logging; +using UniGetUI.Core.SettingsEngine.SecureSettings; +using UniGetUI.Core.Tools; + +namespace UniGetUI.Avalonia.Views.Controls.Settings; + +public partial class SecureCheckboxCard : SettingsCard +{ + public static readonly StyledProperty StateChangedCommandProperty = + AvaloniaProperty.Register(nameof(StateChangedCommand)); + + public ICommand? StateChangedCommand + { + get => GetValue(StateChangedCommandProperty); + set => SetValue(StateChangedCommandProperty, value); + } + + public ToggleSwitch _checkbox; + public TextBlock _textblock; + public TextBlock _warningBlock; + public ProgressBar _loading; // Avalonia has no ProgressRing; use indeterminate ProgressBar + private readonly TextBlock _stateLabel; + private static readonly string EnabledLabel = CoreTools.Translate("Enabled"); + private static readonly string DisabledLabel = CoreTools.Translate("Disabled"); + private bool IS_INVERTED; + + private SecureSettings.K setting_name = SecureSettings.K.Unset; + public SecureSettings.K SettingName + { + set + { + _checkbox.IsEnabled = false; + setting_name = value; + IS_INVERTED = SecureSettings.ResolveKey(value).StartsWith("Disable"); + _checkbox.IsChecked = SecureSettings.Get(setting_name) ^ IS_INVERTED ^ ForceInversion; + _textblock.Opacity = (_checkbox.IsChecked ?? false) ? 1 : 0.7; + UpdateStateLabel(); + _checkbox.IsEnabled = true; + } + } + + public bool ForceInversion { get; set; } + public bool Checked => _checkbox.IsChecked ?? false; + + public virtual event EventHandler? StateChanged; + + public string Text + { + set => _textblock.Text = value; + } + + public string WarningText + { + set + { + _warningBlock.Text = FormatTwoLine(value); + _warningBlock.IsVisible = value.Any(); + } + } + + // Splits translated warning text at the first sentence boundary so it renders + // on two readable lines. Handles both Latin (". ") and CJK ("。") separators. + private static string FormatTwoLine(string text) + { + var idx = text.IndexOf(". ", StringComparison.Ordinal); + if (idx >= 0) + return text[..(idx + 1)] + "\n" + text[(idx + 2)..]; + idx = text.IndexOf('。'); + if (idx >= 0) + return text[..(idx + 1)] + "\n" + text[(idx + 1)..]; + return text; + } + + public SecureCheckboxCard() + { + _checkbox = new ToggleSwitch + { + // OnContent/OffContent intentionally left null — the state label is + // a sibling TextBlock placed to the LEFT of the knob below. + OnContent = null, + OffContent = null, + VerticalAlignment = VerticalAlignment.Center, + }; + _stateLabel = new TextBlock + { + Text = DisabledLabel, + VerticalAlignment = VerticalAlignment.Center, + Margin = new Thickness(0, 0, 8, 0), + }; + _loading = new ProgressBar + { + IsIndeterminate = false, + IsVisible = false, + Width = 20, + Height = 20, + Margin = new Thickness(0, 0, 4, 0), + }; + // Keep the indeterminate clock off while hidden so it doesn't pin the render loop. + _loading.Bind(ProgressBar.IsIndeterminateProperty, _loading.GetObservable(Visual.IsVisibleProperty)); + _textblock = new TextBlock + { + VerticalAlignment = VerticalAlignment.Center, + TextWrapping = TextWrapping.Wrap, + FontSize = 14, + }; + _warningBlock = new TextBlock + { + VerticalAlignment = VerticalAlignment.Center, + TextWrapping = TextWrapping.Wrap, + FontSize = 12, + IsVisible = false, + }; + _warningBlock.Classes.Add("setting-warning-text"); + IS_INVERTED = false; + + Content = new StackPanel + { + Spacing = 4, + Orientation = Orientation.Horizontal, + VerticalAlignment = VerticalAlignment.Center, + Children = { _loading, _stateLabel, _checkbox }, + }; + Header = new StackPanel + { + Spacing = 4, + Orientation = Orientation.Vertical, + Children = { _textblock, _warningBlock }, + }; + + _checkbox.IsCheckedChanged += (s, e) => _ = _checkbox_Toggled(); + + this.GetObservable(IsEnabledProperty) + .SubscribeValue(enabled => _warningBlock.Opacity = enabled ? 1 : 0.2); + + // The Devolutions SettingsCard measures the Header with infinite width, so + // TextWrapping alone won't constrain the warning block. We fix it by updating + // MaxWidth after every layout pass, leaving room for the Content (toggle) area. + SizeChanged += (_, e) => + { + var contentWidth = (Content as Control)?.Bounds.Width ?? 0; + _warningBlock.MaxWidth = Math.Max(100, e.NewSize.Width - contentWidth - 48); + }; + } + + protected virtual async Task _checkbox_Toggled() + { + try + { + if (_checkbox.IsEnabled is false) return; + + _loading.IsVisible = true; + _checkbox.IsEnabled = false; + await SecureSettings.TrySet( + setting_name, + (_checkbox.IsChecked ?? false) ^ IS_INVERTED ^ ForceInversion + ); + StateChanged?.Invoke(this, EventArgs.Empty); + var cmd = StateChangedCommand; + if (cmd?.CanExecute(null) == true) + cmd.Execute(null); + _textblock.Opacity = (_checkbox.IsChecked ?? false) ? 1 : 0.7; + _checkbox.IsChecked = SecureSettings.Get(setting_name) ^ IS_INVERTED ^ ForceInversion; + UpdateStateLabel(); + if (_textblock.Text is not null) + { + AccessibilityAnnouncementService.AnnounceToggle(_textblock.Text, _checkbox.IsChecked ?? false); + } + _loading.IsVisible = false; + _checkbox.IsEnabled = true; + } + catch (Exception ex) + { + Logger.Warn(ex); + _checkbox.IsChecked = SecureSettings.Get(setting_name) ^ IS_INVERTED ^ ForceInversion; + UpdateStateLabel(); + _loading.IsVisible = false; + _checkbox.IsEnabled = true; + } + } + + private void UpdateStateLabel() + { + _stateLabel.Text = (_checkbox.IsChecked ?? false) ? EnabledLabel : DisabledLabel; + } +} diff --git a/src/UniGetUI.Avalonia/Views/Controls/Settings/SettingsCard.cs b/src/UniGetUI.Avalonia/Views/Controls/Settings/SettingsCard.cs new file mode 100644 index 0000000..7cb8d9b --- /dev/null +++ b/src/UniGetUI.Avalonia/Views/Controls/Settings/SettingsCard.cs @@ -0,0 +1,364 @@ +using Avalonia; +using Avalonia.Automation; +using Avalonia.Automation.Peers; +using Avalonia.Controls; +using Avalonia.Input; +using Avalonia.Interactivity; +using Avalonia.Layout; +using Avalonia.Media; +using UniGetUI.Avalonia.Views.Controls; +using ICommand = System.Windows.Input.ICommand; + +namespace UniGetUI.Avalonia.Views.Controls.Settings; + +/// +/// Avalonia equivalent of CommunityToolkit.WinUI.Controls.SettingsCard. +/// Layout: [icon][header / description stack] [content] +/// +public class SettingsCard : UserControl +{ + // ── Internal layout elements ─────────────────────────────────────────── + private readonly Border _border; + private readonly ContentControl _iconPresenter; + private readonly ContentControl _headerPresenter; + private readonly ContentControl _descriptionPresenter; + private readonly ContentControl _contentPresenter; + private readonly StackPanel _descriptionRow; + private readonly SvgIcon _chevron; + + // ── Styled properties ────────────────────────────────────────────────── + public static readonly StyledProperty HeaderProperty = + AvaloniaProperty.Register(nameof(Header)); + + public static readonly StyledProperty DescriptionProperty = + AvaloniaProperty.Register(nameof(Description)); + + public static readonly StyledProperty CommandProperty = + AvaloniaProperty.Register(nameof(Command)); + + public static readonly StyledProperty CommandParameterProperty = + AvaloniaProperty.Register(nameof(CommandParameter)); + + // ── Backing stores ───────────────────────────────────────────────────── + private Control? _headerIcon; + private object? _rightContent; + private bool _isClickEnabled; + + // ── Events ───────────────────────────────────────────────────────────── + public event EventHandler? Click; + + // ── Properties ──────────────────────────────────────────────────────── + + public new object? Content + { + get => _rightContent; + set + { + _rightContent = value; + _contentPresenter.Content = value is string s + ? new TextBlock { Text = s, FontSize = 14, VerticalAlignment = VerticalAlignment.Center } + : value; + } + } + + public object? Header + { + get => GetValue(HeaderProperty); + set => SetValue(HeaderProperty, value); + } + + public ICommand? Command + { + get => GetValue(CommandProperty); + set => SetValue(CommandProperty, value); + } + + public object? CommandParameter + { + get => GetValue(CommandParameterProperty); + set => SetValue(CommandParameterProperty, value); + } + + public object? Description + { + get => GetValue(DescriptionProperty); + set => SetValue(DescriptionProperty, value); + } + + public Control? HeaderIcon + { + get => _headerIcon; + set + { + _headerIcon = value; + _iconPresenter.Content = value; + _iconPresenter.IsVisible = value is not null; + } + } + + public bool IsClickEnabled + { + get => _isClickEnabled; + set + { + _isClickEnabled = value; + Focusable = value; + Cursor = value ? new Cursor(StandardCursorType.Hand) : Cursor.Default; + _chevron.IsVisible = value; + if (value) + _border.Classes.Add("settings-card-clickable"); + else + _border.Classes.Remove("settings-card-clickable"); + } + } + + public new CornerRadius CornerRadius + { + get => _border.CornerRadius; + set => _border.CornerRadius = value; + } + + // Base (unfocused) thickness as assigned by the consumer. Grouped cards use a + // partial thickness like "1,0,1,1" to share a divider with the card above; we + // must remember it so we can restore it when focus leaves. + private Thickness _baseBorderThickness = new(1); + + public new Thickness BorderThickness + { + get => _border.BorderThickness; + set + { + _baseBorderThickness = value; + // While focused the border is forced complete (see GotFocus); don't clobber it. + if (!_border.Classes.Contains("settings-card-focused")) + _border.BorderThickness = value; + } + } + + // A focused card needs a border on all four sides, even when its base thickness omits + // the top (grouped cards). The accent focus style can't supply this: BorderThickness is + // a local value on _border, which wins over the style setter — so we set it here instead. + private static Thickness FocusedBorderThickness(Thickness baseThickness) + { + double t = Math.Max(Math.Max(baseThickness.Left, baseThickness.Right), + Math.Max(baseThickness.Top, baseThickness.Bottom)); + return new Thickness(Math.Max(t, 1)); + } + + // ── Constructor ──────────────────────────────────────────────────────── + + public SettingsCard() + { + _iconPresenter = new ContentControl + { + IsVisible = false, + VerticalAlignment = VerticalAlignment.Center, + Margin = new Thickness(0, 0, 12, 0), + Width = 24, + Height = 24, + }; + AutomationProperties.SetAccessibilityView(_iconPresenter, AccessibilityView.Raw); + + _headerPresenter = new ContentControl + { + VerticalAlignment = VerticalAlignment.Center, + }; + + _descriptionPresenter = new ContentControl + { + VerticalAlignment = VerticalAlignment.Center, + }; + + _descriptionRow = new StackPanel + { + Orientation = Orientation.Vertical, + IsVisible = false, + }; + _descriptionRow.Children.Add(_descriptionPresenter); + + var leftStack = new StackPanel + { + Orientation = Orientation.Vertical, + VerticalAlignment = VerticalAlignment.Center, + }; + leftStack.Children.Add(_headerPresenter); + leftStack.Children.Add(_descriptionRow); + + var leftRow = new StackPanel + { + Orientation = Orientation.Horizontal, + VerticalAlignment = VerticalAlignment.Center, + }; + leftRow.Children.Add(_iconPresenter); + leftRow.Children.Add(leftStack); + + _contentPresenter = new ContentControl + { + VerticalAlignment = VerticalAlignment.Center, + HorizontalAlignment = HorizontalAlignment.Right, + MinWidth = 80, + Margin = new Thickness(16, 0, 0, 0), + }; + + _chevron = new SvgIcon + { + Path = "avares://UniGetUI/Assets/Symbols/forward.svg", + Width = 16, + Height = 16, + VerticalAlignment = VerticalAlignment.Center, + Opacity = 0.6, + Margin = new Thickness(8, 0, 0, 0), + IsVisible = false, + }; + AutomationProperties.SetAccessibilityView(_chevron, AccessibilityView.Raw); + + var grid = new Grid + { + ColumnDefinitions = new ColumnDefinitions("*,Auto,Auto"), + MinHeight = 60, + Margin = new Thickness(16, 8, 16, 8), + }; + Grid.SetColumn(leftRow, 0); + Grid.SetColumn(_contentPresenter, 1); + Grid.SetColumn(_chevron, 2); + grid.Children.Add(leftRow); + grid.Children.Add(_contentPresenter); + grid.Children.Add(_chevron); + + _border = new Border + { + CornerRadius = new CornerRadius(8), + BorderThickness = new Thickness(1), + Child = grid, + }; + _border.Classes.Add("settings-card"); + + base.Content = _border; + + PointerPressed += OnPointerPressed; + KeyDown += OnKeyDown; + GotFocus += (_, _) => + { + if (!_isClickEnabled) return; + _border.Classes.Add("settings-card-focused"); + _border.BorderThickness = FocusedBorderThickness(_baseBorderThickness); + }; + LostFocus += (_, _) => + { + _border.Classes.Remove("settings-card-focused"); + _border.BorderThickness = _baseBorderThickness; + }; + SyncAutomationProperties(); + } + + protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change) + { + base.OnPropertyChanged(change); + if (change.Property == HeaderProperty) + { + var value = change.NewValue; + _headerPresenter.Content = value is string s + ? new TextBlock + { + Text = s, + FontSize = 14, + TextWrapping = TextWrapping.Wrap, + VerticalAlignment = VerticalAlignment.Center, + } + : value; + SyncAutomationProperties(); + } + else if (change.Property == DescriptionProperty) + { + var value = change.NewValue; + if (value is null) + { + _descriptionRow.IsVisible = false; + SyncAutomationProperties(); + return; + } + _descriptionPresenter.Content = value is string s + ? new TextBlock + { + Text = s, + TextWrapping = TextWrapping.NoWrap, + TextTrimming = TextTrimming.CharacterEllipsis, + FontSize = 12, + Opacity = 0.7, + } + : value; + _descriptionRow.IsVisible = true; + SyncAutomationProperties(); + } + } + + protected string? GetAutomationNameText() => ExtractAutomationText(Header); + + protected string? GetAutomationHelpText() => ExtractAutomationText(Description); + + protected void ApplyAutomationMetadata(Control control, string? name = null, string? helpText = null) + { + name ??= GetAutomationNameText(); + helpText ??= GetAutomationHelpText(); + + if (!string.IsNullOrWhiteSpace(name)) + AutomationProperties.SetName(control, name); + + if (!string.IsNullOrWhiteSpace(helpText)) + AutomationProperties.SetHelpText(control, helpText); + } + + private static string? ExtractAutomationText(object? value) => value switch + { + string s when !string.IsNullOrWhiteSpace(s) => s, + TextBlock tb when !string.IsNullOrWhiteSpace(tb.Text) => tb.Text, + SelectableTextBlock stb when !string.IsNullOrWhiteSpace(stb.Text) => stb.Text, + ContentControl cc when cc.Content is not null => ExtractAutomationText(cc.Content), + _ => null, + }; + + private void SyncAutomationProperties() + { + string? name = GetAutomationNameText(); + string? help = GetAutomationHelpText(); + ApplyAutomationMetadata(this, name, help); + // Also propagate to _border: on macOS, Avalonia may surface the Border element + // rather than the UserControl wrapper, so set the name on both. + if (!string.IsNullOrWhiteSpace(name)) + AutomationProperties.SetName(_border, name); + if (!string.IsNullOrWhiteSpace(help)) + AutomationProperties.SetHelpText(_border, help); + var type = IsClickEnabled ? (AutomationControlType?)AutomationControlType.Button : null; + AutomationProperties.SetControlTypeOverride(this, type); + if (type.HasValue) + AutomationProperties.SetControlTypeOverride(_border, type); + } + + private void OnPointerPressed(object? sender, PointerPressedEventArgs e) + { + if (!_isClickEnabled) return; + if (!e.GetCurrentPoint(this).Properties.IsLeftButtonPressed) return; + + InvokeClick(); + e.Handled = true; + } + + private void OnKeyDown(object? sender, KeyEventArgs e) + { + if (!_isClickEnabled) return; + if (e.Source != this) return; // only when the card itself has focus, not a child + if (e.Key is not (Key.Enter or Key.Space)) return; + + InvokeClick(); + e.Handled = true; + } + + private void InvokeClick() + { + Click?.Invoke(this, new RoutedEventArgs()); + var cmd = Command; + var param = CommandParameter; + if (cmd?.CanExecute(param) == true) + cmd.Execute(param); + } +} diff --git a/src/UniGetUI.Avalonia/Views/Controls/Settings/SettingsPageButton.cs b/src/UniGetUI.Avalonia/Views/Controls/Settings/SettingsPageButton.cs new file mode 100644 index 0000000..0c772f6 --- /dev/null +++ b/src/UniGetUI.Avalonia/Views/Controls/Settings/SettingsPageButton.cs @@ -0,0 +1,64 @@ +using Avalonia; +using UniGetUI.Avalonia.Views.Controls; +using UniGetUI.Interface.Enums; + +namespace UniGetUI.Avalonia.Views.Controls.Settings; + +public partial class SettingsPageButton : SettingsCard +{ + public string Text + { + set + { + Header = value; + ApplyAutomationMetadata(this, value, GetAutomationHelpText()); + } + } + + public string UnderText + { + set + { + Description = value; + ApplyAutomationMetadata(this, GetAutomationNameText(), value); + } + } + + public IconType Icon + { + set => HeaderIcon = new SvgIcon + { + Path = IconTypeToPath(value), + Width = 24, + Height = 24, + }; + } + + public SettingsPageButton() + { + CornerRadius = new CornerRadius(8); + IsClickEnabled = true; + } + + private static string IconTypeToPath(IconType icon) + { + string name = icon switch + { + IconType.Chocolatey => "choco", + IconType.Package => "package", + IconType.UAC => "uac", + IconType.Update => "update", + IconType.Help => "help", + IconType.Console => "console", + IconType.Checksum => "checksum", + IconType.Download => "download", + IconType.Settings => "settings", + IconType.SaveAs => "save_as", + IconType.OpenFolder => "open_folder", + IconType.Experimental => "experimental", + IconType.ClipboardList => "clipboard_list", + _ => icon.ToString().ToLower(), + }; + return $"avares://UniGetUI/Assets/Symbols/{name}.svg"; + } +} diff --git a/src/UniGetUI.Avalonia/Views/Controls/Settings/TextboxCard.cs b/src/UniGetUI.Avalonia/Views/Controls/Settings/TextboxCard.cs new file mode 100644 index 0000000..b8d2d4b --- /dev/null +++ b/src/UniGetUI.Avalonia/Views/Controls/Settings/TextboxCard.cs @@ -0,0 +1,122 @@ +using System.Diagnostics; +using System.Windows.Input; +using Avalonia; +using Avalonia.Controls; +using Avalonia.Layout; +using UniGetUI.Core.Tools; +using CoreSettings = global::UniGetUI.Core.SettingsEngine.Settings; + +namespace UniGetUI.Avalonia.Views.Controls.Settings; + +public sealed partial class TextboxCard : SettingsCard +{ + public static readonly StyledProperty ValueChangedCommandProperty = + AvaloniaProperty.Register(nameof(ValueChangedCommand)); + + public ICommand? ValueChangedCommand + { + get => GetValue(ValueChangedCommandProperty); + set => SetValue(ValueChangedCommandProperty, value); + } + + private readonly TextBox _textbox; + private readonly Button _helpbutton; // WinUI HyperlinkButton → plain Button + Process.Start + + private CoreSettings.K setting_name = CoreSettings.K.Unset; + private Uri? _helpUri; + + public CoreSettings.K SettingName + { + set + { + setting_name = value; + _textbox.Text = CoreSettings.GetValue(setting_name); + _textbox.TextChanged += (_, _) => SaveValue(); + } + } + + public bool IsNumericOnly { get; set; } + + public string Placeholder + { + set + { + _textbox.PlaceholderText = value; + ApplyAutomationMetadata(_textbox, GetAutomationNameText() ?? value); + } + } + + public string Text + { + set + { + Header = value; + ApplyAutomationMetadata(_textbox, value); + } + } + + public Uri HelpUrl + { + set + { + _helpUri = value; + _helpbutton.IsVisible = true; + _helpbutton.Content = CoreTools.Translate("More info"); + ApplyAutomationMetadata(_helpbutton, CoreTools.Translate("More info"), GetAutomationNameText()); + } + } + + public event EventHandler? ValueChanged; + + public TextboxCard() + { + _helpbutton = new Button + { + IsVisible = false, + Margin = new Thickness(0, 0, 8, 0), + }; + _helpbutton.Click += (_, _) => + { + if (_helpUri is not null) + Process.Start(new ProcessStartInfo(_helpUri.ToString()) { UseShellExecute = true }); + }; + + _textbox = new TextBox { MinWidth = 200, MaxWidth = 300 }; + + var s = new StackPanel { Orientation = Orientation.Horizontal }; + s.Children.Add(_helpbutton); + s.Children.Add(_textbox); + + Content = s; + ApplyAutomationMetadata(_textbox); + } + + public void SaveValue() + { + string sanitizedText = _textbox.Text ?? ""; + + if (IsNumericOnly) + { + string filtered = string.Concat(sanitizedText.Where(char.IsDigit)); + if (filtered != sanitizedText) + { + _textbox.Text = filtered; // triggers TextChanged → SaveValue again with clean text + return; + } + sanitizedText = filtered; + } + + if (CoreSettings.ResolveKey(setting_name).Contains("File")) + sanitizedText = CoreTools.MakeValidFileName(sanitizedText); + + if (sanitizedText != "") + CoreSettings.SetValue(setting_name, sanitizedText); + else + CoreSettings.Set(setting_name, false); + + ValueChanged?.Invoke(this, EventArgs.Empty); + var cmd = ValueChangedCommand; + if (cmd?.CanExecute(null) == true) + cmd.Execute(null); + } +} diff --git a/src/UniGetUI.Avalonia/Views/Controls/Settings/TranslatedTextBlock.cs b/src/UniGetUI.Avalonia/Views/Controls/Settings/TranslatedTextBlock.cs new file mode 100644 index 0000000..b0819b3 --- /dev/null +++ b/src/UniGetUI.Avalonia/Views/Controls/Settings/TranslatedTextBlock.cs @@ -0,0 +1,17 @@ +using Avalonia.Controls; +using UniGetUI.Core.Tools; + +namespace UniGetUI.Avalonia.Views.Controls.Settings; + +/// +/// A TextBlock whose Text property is automatically translated via CoreTools.Translate. +/// Used for section headers set from code-behind; prefer {t:Translate} in AXAML instead. +/// +public class TranslatedTextBlock : TextBlock +{ + public new string Text + { + get => base.Text ?? ""; + set => base.Text = CoreTools.Translate(value); + } +} diff --git a/src/UniGetUI.Avalonia/Views/Controls/SvgIcon.cs b/src/UniGetUI.Avalonia/Views/Controls/SvgIcon.cs new file mode 100644 index 0000000..6a6cefb --- /dev/null +++ b/src/UniGetUI.Avalonia/Views/Controls/SvgIcon.cs @@ -0,0 +1,216 @@ +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.IO; +using System.Xml.Linq; +using Avalonia; +using Avalonia.Automation; +using Avalonia.Controls; +using Avalonia.Data; +using Avalonia.Media; +using Avalonia.Platform; +using Avalonia.Styling; + +namespace UniGetUI.Avalonia.Views.Controls; + +/// +/// Lightweight SVG icon renderer that uses Avalonia's native geometry engine +/// instead of SkiaSharp's SVG module (which is broken on some macOS configurations). +/// Supports single-path and multi-path SVGs with a uniform viewBox. +/// +public class SvgIcon : Control +{ + public SvgIcon() + { + AutomationProperties.SetAccessibilityView(this, AccessibilityView.Raw); + } + + public static readonly StyledProperty PathProperty = + AvaloniaProperty.Register(nameof(Path)); + + public static readonly StyledProperty ForegroundProperty = + AvaloniaProperty.Register(nameof(Foreground), + defaultValue: null, inherits: true); + + public string? Path + { + get => GetValue(PathProperty); + set => SetValue(PathProperty, value); + } + + private IBrush? _localForeground; + public IBrush? Foreground + { + get => GetValue(ForegroundProperty); + set => SetValue(ForegroundProperty, value); + } + + private readonly List _geometries = new(); + private double _viewBoxWidth = 24, _viewBoxHeight = 24; + + static SvgIcon() + { + AffectsRender(ForegroundProperty); + AffectsMeasure(PathProperty); + } + + protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e) + { + base.OnAttachedToVisualTree(e); + if (Application.Current is { } app) + app.ActualThemeVariantChanged += OnThemeChanged; + } + + protected override void OnDetachedFromVisualTree(VisualTreeAttachmentEventArgs e) + { + base.OnDetachedFromVisualTree(e); + if (Application.Current is { } app) + app.ActualThemeVariantChanged -= OnThemeChanged; + } + + protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change) + { + base.OnPropertyChanged(change); + if (change.Property == ForegroundProperty) + { + _localForeground = change.Priority < BindingPriority.Style + ? change.NewValue as IBrush + : null; + } + else if (change.Property == PathProperty) + LoadSvg(change.NewValue as string); + } + + private void OnThemeChanged(object? sender, EventArgs e) => InvalidateVisual(); + + // Parsed SVGs are immutable static assets referenced by a small fixed set of URIs, yet the + // same icon is realized thousands of times as the DataGrid recycles rows during scrolling. + // Memoizing the parse keeps scrolling from re-opening and re-parsing assets on the UI thread. + private sealed record ParsedSvg(IReadOnlyList Geometries, double ViewBoxWidth, double ViewBoxHeight); + private static readonly ConcurrentDictionary _cache = new(); + + private void LoadSvg(string? uri) + { + if (string.IsNullOrEmpty(uri)) + { + _geometries.Clear(); + _viewBoxWidth = 24; + _viewBoxHeight = 24; + InvalidateVisual(); + return; + } + + ParsedSvg parsed = _cache.GetOrAdd(uri, ParseSvg); + _geometries.Clear(); + _geometries.AddRange(parsed.Geometries); + _viewBoxWidth = parsed.ViewBoxWidth; + _viewBoxHeight = parsed.ViewBoxHeight; + + InvalidateMeasure(); + InvalidateVisual(); + } + + private static ParsedSvg ParseSvg(string uri) + { + var geometries = new List(); + double viewBoxWidth = 24, viewBoxHeight = 24; + + try + { + using Stream stream = AssetLoader.Open(new Uri(uri)); + XDocument doc = XDocument.Load(stream); + XElement? svg = doc.Root; + if (svg is null) return new ParsedSvg(geometries, viewBoxWidth, viewBoxHeight); + + string? vb = svg.Attribute("viewBox")?.Value; + if (vb != null) + { + var parts = vb.Split(' ', System.StringSplitOptions.RemoveEmptyEntries); + if (parts.Length >= 4 && + double.TryParse(parts[2], System.Globalization.NumberStyles.Any, + System.Globalization.CultureInfo.InvariantCulture, out double w) && + double.TryParse(parts[3], System.Globalization.NumberStyles.Any, + System.Globalization.CultureInfo.InvariantCulture, out double h)) + { + viewBoxWidth = w; + viewBoxHeight = h; + } + } + else if ( + double.TryParse(svg.Attribute("width")?.Value, System.Globalization.NumberStyles.Any, + System.Globalization.CultureInfo.InvariantCulture, out double svgW) && + double.TryParse(svg.Attribute("height")?.Value, System.Globalization.NumberStyles.Any, + System.Globalization.CultureInfo.InvariantCulture, out double svgH)) + { + viewBoxWidth = svgW; + viewBoxHeight = svgH; + } + + XNamespace ns = "http://www.w3.org/2000/svg"; + foreach (XElement el in doc.Descendants(ns + "path")) + { + string? d = el.Attribute("d")?.Value; + if (!string.IsNullOrEmpty(d)) + { + try { geometries.Add(Geometry.Parse(d)); } + catch { /* skip malformed path data */ } + } + } + foreach (XElement el in doc.Descendants(ns + "ellipse")) + { + if (double.TryParse(el.Attribute("cx")?.Value, System.Globalization.NumberStyles.Any, + System.Globalization.CultureInfo.InvariantCulture, out double cx) && + double.TryParse(el.Attribute("cy")?.Value, System.Globalization.NumberStyles.Any, + System.Globalization.CultureInfo.InvariantCulture, out double cy) && + double.TryParse(el.Attribute("rx")?.Value, System.Globalization.NumberStyles.Any, + System.Globalization.CultureInfo.InvariantCulture, out double rx) && + double.TryParse(el.Attribute("ry")?.Value, System.Globalization.NumberStyles.Any, + System.Globalization.CultureInfo.InvariantCulture, out double ry)) + { + geometries.Add(new EllipseGeometry(new Rect(cx - rx, cy - ry, rx * 2, ry * 2))); + } + } + } + catch + { + // Silently ignore missing or unreadable assets + } + + return new ParsedSvg(geometries, viewBoxWidth, viewBoxHeight); + } + + private static readonly IBrush _darkFg = new SolidColorBrush(Color.Parse("#E8E8E8")); + private static readonly IBrush _lightFg = new SolidColorBrush(Color.Parse("#1E1E1E")); + + private static IBrush LookupThemeForeground() => + Application.Current?.ActualThemeVariant == ThemeVariant.Dark + ? _darkFg + : _lightFg; + + protected override Size MeasureOverride(Size availableSize) + { + double w = double.IsInfinity(availableSize.Width) ? _viewBoxWidth : availableSize.Width; + double h = double.IsInfinity(availableSize.Height) ? _viewBoxHeight : availableSize.Height; + return new Size(w, h); + } + + public override void Render(DrawingContext context) + { + if (_geometries.Count == 0) return; + + IBrush brush = _localForeground ?? LookupThemeForeground(); + + double scaleX = Bounds.Width / _viewBoxWidth; + double scaleY = Bounds.Height / _viewBoxHeight; + double scale = Math.Min(scaleX, scaleY); + + double offsetX = (Bounds.Width - _viewBoxWidth * scale) / 2; + double offsetY = (Bounds.Height - _viewBoxHeight * scale) / 2; + + using var _ = context.PushTransform( + Matrix.CreateTranslation(offsetX, offsetY) * Matrix.CreateScale(scale, scale)); + + foreach (Geometry geo in _geometries) + context.DrawGeometry(brush, null, geo); + } +} diff --git a/src/UniGetUI.Avalonia/Views/Controls/UniGetUiWebView.cs b/src/UniGetUI.Avalonia/Views/Controls/UniGetUiWebView.cs new file mode 100644 index 0000000..e941423 --- /dev/null +++ b/src/UniGetUI.Avalonia/Views/Controls/UniGetUiWebView.cs @@ -0,0 +1,16 @@ +using Avalonia.Controls; +using Avalonia.Platform; + +namespace UniGetUI.Avalonia.Views.Controls; + +public sealed class UniGetUiWebView : NativeWebView +{ + public UniGetUiWebView() + { + EnvironmentRequested += (_, args) => + { + if (args is WindowsWebView2EnvironmentRequestedEventArgs winArgs) + winArgs.UserDataFolder = App.WebViewUserDataFolder; + }; + } +} diff --git a/src/UniGetUI.Avalonia/Views/Controls/UserAvatarControl.axaml b/src/UniGetUI.Avalonia/Views/Controls/UserAvatarControl.axaml new file mode 100644 index 0000000..ec2b118 --- /dev/null +++ b/src/UniGetUI.Avalonia/Views/Controls/UserAvatarControl.axaml @@ -0,0 +1,117 @@ + + + + + diff --git a/src/UniGetUI.Avalonia/Views/Controls/UserAvatarControl.axaml.cs b/src/UniGetUI.Avalonia/Views/Controls/UserAvatarControl.axaml.cs new file mode 100644 index 0000000..83dc8fa --- /dev/null +++ b/src/UniGetUI.Avalonia/Views/Controls/UserAvatarControl.axaml.cs @@ -0,0 +1,25 @@ +using Avalonia; +using Avalonia.Controls; +using UniGetUI.Avalonia.ViewModels.Controls; + +namespace UniGetUI.Avalonia.Views.Controls; + +public partial class UserAvatarControl : UserControl +{ + private readonly UserAvatarViewModel _viewModel; + + public UserAvatarControl() + { + _viewModel = new UserAvatarViewModel(); + DataContext = _viewModel; + InitializeComponent(); + } + + protected override void OnDetachedFromVisualTree(VisualTreeAttachmentEventArgs e) + { + // This control belongs to a SidebarView data template, which Avalonia can recreate as + // the navigation layout changes. Its visual lifetime—not page navigation—is the owner. + _viewModel.Dispose(); + base.OnDetachedFromVisualTree(e); + } +} diff --git a/src/UniGetUI.Avalonia/Views/DialogPages/AboutWindow.axaml b/src/UniGetUI.Avalonia/Views/DialogPages/AboutWindow.axaml new file mode 100644 index 0000000..8e048a7 --- /dev/null +++ b/src/UniGetUI.Avalonia/Views/DialogPages/AboutWindow.axaml @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/UniGetUI.Avalonia/Views/DialogPages/AboutWindow.axaml.cs b/src/UniGetUI.Avalonia/Views/DialogPages/AboutWindow.axaml.cs new file mode 100644 index 0000000..267b438 --- /dev/null +++ b/src/UniGetUI.Avalonia/Views/DialogPages/AboutWindow.axaml.cs @@ -0,0 +1,19 @@ +using Avalonia.Controls; +using Avalonia.Threading; + +namespace UniGetUI.Avalonia.Views.DialogPages; + +public partial class AboutWindow : Window +{ + public AboutWindow() + { + InitializeComponent(); + UniGetUI.Avalonia.Infrastructure.MicaWindowHelper.Apply(this); + } + + protected override void OnOpened(EventArgs e) + { + base.OnOpened(e); + Dispatcher.UIThread.Post(() => MainTabControl.Focus(), DispatcherPriority.Background); + } +} diff --git a/src/UniGetUI.Avalonia/Views/DialogPages/BundleSecurityReportDialog.axaml b/src/UniGetUI.Avalonia/Views/DialogPages/BundleSecurityReportDialog.axaml new file mode 100644 index 0000000..14b8221 --- /dev/null +++ b/src/UniGetUI.Avalonia/Views/DialogPages/BundleSecurityReportDialog.axaml @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/UniGetUI.Avalonia/Views/DialogPages/ManageIgnoredUpdatesWindow.axaml.cs b/src/UniGetUI.Avalonia/Views/DialogPages/ManageIgnoredUpdatesWindow.axaml.cs new file mode 100644 index 0000000..ec23a3c --- /dev/null +++ b/src/UniGetUI.Avalonia/Views/DialogPages/ManageIgnoredUpdatesWindow.axaml.cs @@ -0,0 +1,46 @@ +using Avalonia.Controls; +using Avalonia.Interactivity; +using Avalonia.Threading; +using UniGetUI.Avalonia.ViewModels; + +namespace UniGetUI.Avalonia.Views; + +public partial class ManageIgnoredUpdatesWindow : Window +{ + public ManageIgnoredUpdatesWindow() + { + var vm = new ManageIgnoredUpdatesViewModel(); + DataContext = vm; + InitializeComponent(); + + // Drop the OS title-bar strip (its background clashed with the dialog) but keep + // the system min/max/close buttons floating over the extended client area. Default + // WindowDecorations (Full) keeps the system buttons; extending the client area + // merges the title-bar region into the content. + ExtendClientAreaToDecorationsHint = true; + ExtendClientAreaTitleBarHeightHint = -1; + + vm.CloseRequested += (_, _) => Close(); + } + + protected override void OnOpened(EventArgs e) + { + base.OnOpened(e); + Dispatcher.UIThread.Post(() => + { + if (((ManageIgnoredUpdatesViewModel)DataContext!).HasEntries) + IgnoredUpdatesGrid.Focus(); + else + ResetButton.Focus(); + }, DispatcherPriority.Background); + } + + private void ResetYes_Click(object? sender, RoutedEventArgs e) + { + ((ManageIgnoredUpdatesViewModel)DataContext!).ResetAllCommand.Execute(null); + ResetButton.Flyout?.Hide(); + } + + private void ResetNo_Click(object? sender, RoutedEventArgs e) => + ResetButton.Flyout?.Hide(); +} diff --git a/src/UniGetUI.Avalonia/Views/DialogPages/MissingDependencyDialog.axaml b/src/UniGetUI.Avalonia/Views/DialogPages/MissingDependencyDialog.axaml new file mode 100644 index 0000000..fbf0e55 --- /dev/null +++ b/src/UniGetUI.Avalonia/Views/DialogPages/MissingDependencyDialog.axaml @@ -0,0 +1,64 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/UniGetUI.Avalonia/Views/DialogPages/PackageDetailsWindow.axaml.cs b/src/UniGetUI.Avalonia/Views/DialogPages/PackageDetailsWindow.axaml.cs new file mode 100644 index 0000000..c12270c --- /dev/null +++ b/src/UniGetUI.Avalonia/Views/DialogPages/PackageDetailsWindow.axaml.cs @@ -0,0 +1,550 @@ +using System.ComponentModel; +using System.Diagnostics; +using Avalonia; +using Avalonia.Controls; +using Avalonia.Controls.Documents; +using Avalonia.Controls.Shapes; +using Avalonia.Input; +using Avalonia.Interactivity; +using Avalonia.Layout; +using Avalonia.Media; +using Avalonia.Threading; +using UniGetUI.Avalonia.Infrastructure; +using UniGetUI.Avalonia.ViewModels; +using UniGetUI.Avalonia.Views.DialogPages; +using UniGetUI.Core.Logging; +using UniGetUI.Core.Tools; +using UniGetUI.Interface.Telemetry; +using UniGetUI.PackageEngine.Enums; +using UniGetUI.PackageEngine.Interfaces; +using UniGetUI.PackageEngine.Operations; +using UniGetUI.PackageEngine.PackageClasses; +using UniGetUI.PackageEngine.Serializable; +using UniGetUI.PackageOperations; + +namespace UniGetUI.Avalonia.Views; + +public partial class PackageDetailsWindow : Window +{ + private const double WideThreshold = 950; + private const string ContributeUrl = "https://github.com/Devolutions/UniGetUI"; + + private enum LayoutMode { Unset, Normal, Wide } + private LayoutMode _layoutMode = LayoutMode.Unset; + + /// True when the user confirmed the main action (install/update/uninstall) without extras. + public bool ShouldProceedWithOperation { get; private set; } + + private readonly PackageDetailsViewModel _vm; + private InstallOptionsViewModel? _installVm; + private InstallOptions? _installOpts; + + public PackageDetailsWindow(IPackage package, OperationType operation) + { + _vm = new PackageDetailsViewModel(package, operation); + DataContext = _vm; + InitializeComponent(); + UniGetUI.Avalonia.Infrastructure.MicaWindowHelper.Apply(this); + + // Honor the OS "reduce motion" preference: drop the screenshot slide animation. + if (MotionPreference.ReducedMotion) + ScreenshotsCarousel.PageTransition = null; + + _vm.CloseRequested += (_, _) => Close(); + _vm.DetailsLoaded += (_, _) => + { + BuildBasicInfoInlines(); + BuildDetailsInlines(); + }; + _vm.PropertyChanged += OnVmPropertyChanged; + _vm.Screenshots.CollectionChanged += (_, _) => Dispatcher.UIThread.Post(UpdatePips); + + MainActionButton.Click += (_, _) => OnMainAction(); + ActionVariantsButton.Flyout = BuildActionFlyout(); + InstallOptionsSaveButton.Click += (_, _) => _ = SaveInstallOptionsAsync(); + ContributeButton.Click += (_, _) => OpenUrl(ContributeUrl); + PrevScreenshotButton.Click += (_, _) => + { + if (_vm.SelectedScreenshotIndex > 0) + _vm.SelectedScreenshotIndex--; + }; + NextScreenshotButton.Click += (_, _) => + { + if (_vm.SelectedScreenshotIndex < _vm.ScreenshotCount - 1) + _vm.SelectedScreenshotIndex++; + }; + ScreenshotPips.AddHandler(Button.ClickEvent, OnPipClicked); + + SizeChanged += (_, _) => ApplyLayoutForCurrentSize(); + + // Seed inline blocks with loading placeholders. + BuildBasicInfoInlines(); + BuildDetailsInlines(); + } + + protected override void OnOpened(EventArgs e) + { + base.OnOpened(e); + ApplyLayoutForCurrentSize(); + Dispatcher.UIThread.Post(() => MainActionButton.Focus(), DispatcherPriority.Background); + _ = _vm.LoadDetailsAsync(); + TelemetryHandler.PackageDetails(_vm.Package, _vm.OperationRole.ToString()); + _ = InitInstallOptionsAsync(); + } + + private async Task InitInstallOptionsAsync() + { + _installOpts = await InstallOptionsFactory.LoadForPackageAsync(_vm.Package); + _installVm = new InstallOptionsViewModel(_vm.Package, _vm.OperationRole, _installOpts); + var embed = new InstallOptionsControl { DataContext = _installVm }; + InstallOptionsHolder.Content = embed; + } + + private async Task SaveInstallOptionsAsync() + { + if (_installVm is null || _installOpts is null) return; + _installVm.ApplyChanges(); + await InstallOptionsFactory.SaveForPackageAsync(_installOpts, _vm.Package); + } + + private void OnVmPropertyChanged(object? sender, PropertyChangedEventArgs e) + { + if (e.PropertyName == nameof(PackageDetailsViewModel.SelectedScreenshotIndex) + || e.PropertyName == nameof(PackageDetailsViewModel.ScreenshotCount)) + Dispatcher.UIThread.Post(UpdatePips); + } + + private void OnPipClicked(object? sender, RoutedEventArgs e) + { + if (e.Source is not Control src) return; + // Walk up to find the pip Button container; ask the ItemsControl for its index. + Control? cursor = src; + while (cursor is not null && cursor.Parent is not ItemsControl) + cursor = cursor.Parent as Control; + if (cursor is null) return; + int idx = ScreenshotPips.IndexFromContainer(cursor); + if (idx >= 0 && idx < _vm.ScreenshotCount) + _vm.SelectedScreenshotIndex = idx; + } + + private void UpdatePips() + { + int active = _vm.SelectedScreenshotIndex; + int i = 0; + foreach (var container in ScreenshotPips.GetRealizedContainers()) + { + // The pip template is ; the realized container is the Button itself. + if (container is Button btn && btn.Content is Ellipse ellipse) + ellipse.Classes.Set("active", i == active); + i++; + } + } + + // ── Responsive layout ──────────────────────────────────────────────────── + + private void ApplyLayoutForCurrentSize() + { + var wide = Bounds.Width >= WideThreshold; + var mode = wide ? LayoutMode.Wide : LayoutMode.Normal; + if (mode == _layoutMode) return; + _layoutMode = mode; + + if (mode == LayoutMode.Wide) + { + // Ensure two columns and the right-column panels live in RightPanel. + EnsureChild(RightPanel, ScreenshotsPanel, 0); + EnsureChild(RightPanel, DetailsPanel, 1); + RightPanel.IsVisible = true; + MainGrid.ColumnDefinitions[1].Width = new GridLength(1, GridUnitType.Star); + + ScreenshotsBorder.Height = _vm.HasScreenshots ? 320 : 150; + } + else + { + // Move screenshots + details into LeftPanel (after install options) and collapse the right column. + EnsureChild(LeftPanel, ScreenshotsPanel, LeftPanel.Children.Count); + EnsureChild(LeftPanel, DetailsPanel, LeftPanel.Children.Count); + RightPanel.IsVisible = false; + MainGrid.ColumnDefinitions[1].Width = new GridLength(0); + + ScreenshotsBorder.Height = _vm.HasScreenshots ? 225 : 130; + } + } + + /// Move to at the given index, removing from its old parent first. + private static void EnsureChild(Panel target, Control child, int index) + { + if (child.Parent is Panel current && current != target) + current.Children.Remove(child); + if (!target.Children.Contains(child)) + target.Children.Insert(Math.Min(index, target.Children.Count), child); + } + + // ── Per-row layout builders (inline flow like WinUI's RichTextBlock) ───── + + private void BuildBasicInfoInlines() + { + BasicInfoPanel.Children.Clear(); + + if (!string.IsNullOrWhiteSpace(_vm.Description)) + { + BasicInfoPanel.Children.Add(new SelectableTextBlock + { + Text = _vm.Description, + TextWrapping = TextWrapping.Wrap, + Margin = new Thickness(0, 0, 0, 8), + }); + } + + AddInlineRow(BasicInfoPanel, _vm.LabelHomepage, _vm.HomepageUrl); + AddInlineRow(BasicInfoPanel, _vm.LabelPublisher, _vm.Publisher); + AddInlineRow(BasicInfoPanel, _vm.LabelAuthor, _vm.Author); + AddLicenseRow(BasicInfoPanel); + AddInlineRow(BasicInfoPanel, _vm.LabelUpdateDate, _vm.UpdateDate); + AddInlineRow(BasicInfoPanel, _vm.LabelSource, _vm.SourceDisplay); + } + + private void BuildDetailsInlines() + { + DetailsPanel.Children.Clear(); + + AddInlineRow(DetailsPanel, _vm.LabelPackageId, _vm.PackageId); + AddInlineRow(DetailsPanel, _vm.LabelManifest, _vm.ManifestUrl); + AddInlineRow(DetailsPanel, _vm.LabelVersion, _vm.VersionDisplay); + + AddSpacer(DetailsPanel); + + AddInlineRow(DetailsPanel, _vm.LabelInstallerType, _vm.InstallerType); + AddInlineRow(DetailsPanel, _vm.LabelInstallerUrl, _vm.InstallerUrl); + AddInlineRow(DetailsPanel, _vm.InstallerHashLabel.TrimEnd(':'), _vm.InstallerHash); + + AddDownloadRow(DetailsPanel); + + AddSpacer(DetailsPanel); + + // Dependencies header + list + DetailsPanel.Children.Add(new SelectableTextBlock + { + Text = _vm.LabelDependencies + ":", + FontWeight = FontWeight.Bold, + Margin = new Thickness(0, 0, 0, 4), + }); + if (_vm.HasDependencyNote) + { + DetailsPanel.Children.Add(new SelectableTextBlock + { + Text = " " + _vm.DependencyNote, + Foreground = NotAvailableBrush, + Margin = new Thickness(0, 0, 0, 4), + }); + } + else + { + foreach (var dep in _vm.Dependencies) + { + DetailsPanel.Children.Add(new SelectableTextBlock + { + Text = dep.DisplayText, + TextWrapping = TextWrapping.Wrap, + }); + } + } + + AddSpacer(DetailsPanel); + + // Release notes + DetailsPanel.Children.Add(new SelectableTextBlock + { + Text = _vm.LabelReleaseNotes + ":", + FontWeight = FontWeight.Bold, + Margin = new Thickness(0, 0, 0, 4), + }); + DetailsPanel.Children.Add(new SelectableTextBlock + { + Text = _vm.ReleaseNotes, + TextWrapping = TextWrapping.Wrap, + Margin = new Thickness(0, 0, 0, 8), + }); + AddInlineRow(DetailsPanel, _vm.LabelReleaseNotesUrl, _vm.ReleaseNotesUrl); + } + + private static readonly IBrush NotAvailableBrush = + new SolidColorBrush(Color.FromArgb(255, 127, 127, 127)); + + private static void AddSpacer(StackPanel host) => + host.Children.Add(new Border { Height = 10 }); + + /// + /// Builds a single wrap-able row with "Label: value" all on one line, + /// matching the WinUI RichTextBlock paragraph layout. + /// + private void AddInlineRow(StackPanel host, string label, string value) + { + var tb = new SelectableTextBlock { TextWrapping = TextWrapping.Wrap }; + var inlines = tb.Inlines ??= new InlineCollection(); + inlines.Add(new Run(label + ": ") { FontWeight = FontWeight.Bold }); + if (string.IsNullOrWhiteSpace(value) || value == _vm.LabelNotAvailable) + inlines.Add(new Run(_vm.LabelNotAvailable) + { + Foreground = NotAvailableBrush, + FontStyle = FontStyle.Italic, + }); + else + inlines.Add(new Run(value)); + host.Children.Add(tb); + } + + private void AddInlineRow(StackPanel host, string label, Uri? url) + { + if (url is null) + { + var tb = new SelectableTextBlock { TextWrapping = TextWrapping.Wrap }; + var inlines = tb.Inlines ??= new InlineCollection(); + inlines.Add(new Run(label + ": ") { FontWeight = FontWeight.Bold }); + inlines.Add(new Run(_vm.LabelNotAvailable) + { + Foreground = NotAvailableBrush, + FontStyle = FontStyle.Italic, + }); + host.Children.Add(tb); + return; + } + + host.Children.Add(BuildLinkRow(BoldLabel(label + ": "), url.ToString())); + } + + private void AddLicenseRow(StackPanel host) + { + bool hasName = !string.IsNullOrEmpty(_vm.LicenseName); + bool hasUrl = _vm.LicenseUrl is not null; + + if (!hasUrl) + { + // No link: render as a plain selectable line with the usual cursor. + var tb = new SelectableTextBlock { TextWrapping = TextWrapping.Wrap }; + var inlines = tb.Inlines ??= new InlineCollection(); + inlines.Add(new Run(_vm.LabelLicense + ": ") { FontWeight = FontWeight.Bold }); + if (hasName) + inlines.Add(new Run(_vm.LicenseName!)); + else + inlines.Add(new Run(_vm.LabelNotAvailable) + { + Foreground = NotAvailableBrush, + FontStyle = FontStyle.Italic, + }); + host.Children.Add(tb); + return; + } + + var labelBlock = new SelectableTextBlock + { + TextWrapping = TextWrapping.Wrap, + VerticalAlignment = VerticalAlignment.Top, + }; + var labelInlines = labelBlock.Inlines ??= new InlineCollection(); + labelInlines.Add(new Run(_vm.LabelLicense + ": ") { FontWeight = FontWeight.Bold }); + if (hasName) + labelInlines.Add(new Run(_vm.LicenseName! + " ")); + + host.Children.Add(BuildLinkRow(labelBlock, _vm.LicenseUrl!.ToString())); + } + + private void AddDownloadRow(StackPanel host) + { + if (_vm.CanDownloadInstaller && !_vm.IsLoading) + { + var panel = new StackPanel { Orientation = Orientation.Horizontal }; + var link = CreateLinkBlock(_vm.LabelDownloadInstaller, DownloadInstaller); + link.FontWeight = FontWeight.SemiBold; + panel.Children.Add(link); + if (!string.IsNullOrEmpty(_vm.InstallerSize)) + panel.Children.Add(new SelectableTextBlock { Text = $" ({_vm.InstallerSize})" }); + host.Children.Add(panel); + } + else + { + host.Children.Add(new SelectableTextBlock + { + Text = _vm.LabelInstallerNotAvailable, + Foreground = NotAvailableBrush, + FontStyle = FontStyle.Italic, + }); + } + } + + private static SelectableTextBlock BoldLabel(string text) => new() + { + Text = text, + FontWeight = FontWeight.Bold, + VerticalAlignment = VerticalAlignment.Top, + }; + + /// "Label: url" laid out so a long URL wraps under itself; only the URL is the link. + private Grid BuildLinkRow(Control label, string url) + { + var grid = new Grid + { + ColumnDefinitions = + [ + new ColumnDefinition(GridLength.Auto), + new ColumnDefinition(new GridLength(1, GridUnitType.Star)), + ], + }; + Grid.SetColumn(label, 0); + var link = CreateLinkBlock(url, () => OpenUrl(url)); + link.TextWrapping = TextWrapping.Wrap; + Grid.SetColumn(link, 1); + grid.Children.Add(label); + grid.Children.Add(link); + return grid; + } + + /// A selectable, copyable hyperlink. The hand cursor and activation cover only this text. + private SelectableTextBlock CreateLinkBlock(string text, Action activate) + { + var link = new SelectableTextBlock + { + Text = text, + Foreground = LinkBrush, + TextDecorations = TextDecorations.Underline, + Cursor = new Cursor(StandardCursorType.Hand), + }; + AttachLinkActivation(link, activate); + return link; + } + + /// Activate on a clean click, but let a press-and-drag run the text selection instead. + private static void AttachLinkActivation(Control link, Action activate) + { + Point press = default; + bool tracking = false; + + link.AddHandler(InputElement.PointerPressedEvent, (_, e) => + { + if (e.GetCurrentPoint(link).Properties.IsLeftButtonPressed) + { + tracking = true; + press = e.GetPosition(link); + } + }, RoutingStrategies.Bubble, handledEventsToo: true); + + link.AddHandler(InputElement.PointerReleasedEvent, (_, e) => + { + if (!tracking) return; + tracking = false; + var moved = e.GetPosition(link) - press; + if (Math.Abs(moved.X) <= 4 && Math.Abs(moved.Y) <= 4) + activate(); + }, RoutingStrategies.Bubble, handledEventsToo: true); + } + + private IBrush LinkBrush => + this.TryFindResource("HyperlinkForeground", ActualThemeVariant, out var res) && res is IBrush b + ? b + : new SolidColorBrush(Color.FromArgb(255, 0, 120, 212)); + + private static void OpenUrl(string url) + { + if (string.IsNullOrEmpty(url) || !url.StartsWith("http", StringComparison.OrdinalIgnoreCase)) + return; + try + { + Process.Start(new ProcessStartInfo(url) { UseShellExecute = true }); + } + catch (Exception ex) + { + Logger.Error($"Failed to open URL: {url}"); + Logger.Error(ex); + } + } + + private void DownloadInstaller() + { + if (!_vm.Package.Manager.Capabilities.CanDownloadInstaller) return; + Close(); + // Hook into the platform's download path if/when wired up. For now, fall back to opening + // the installer URL so the user can still grab the file. + if (_vm.InstallerUrl is not null) + OpenUrl(_vm.InstallerUrl.ToString()); + } + + // ── Action flyout ──────────────────────────────────────────────────────── + + private MenuFlyout BuildActionFlyout() + { + var flyout = new MenuFlyout(); + var asAdmin = new MenuItem { Header = _vm.AsAdminLabel, IsEnabled = _vm.CanRunAsAdmin }; + var interactive = new MenuItem { Header = _vm.InteractiveLabel, IsEnabled = _vm.CanRunInteractively }; + var skipOrRemove = new MenuItem { Header = _vm.SkipHashOrRemoveDataLabel, IsEnabled = _vm.CanSkipHashOrRemoveData }; + + var role = _vm.OperationRole; + if (role is OperationType.Uninstall) + { + asAdmin.Click += (_, _) => _ = LaunchAndClose(role, elevated: true); + interactive.Click += (_, _) => _ = LaunchAndClose(role, interactive: true); + skipOrRemove.Click += (_, _) => _ = LaunchAndClose(role, remove_data: true); + } + else + { + asAdmin.Click += (_, _) => _ = LaunchAndClose(role, elevated: true); + interactive.Click += (_, _) => _ = LaunchAndClose(role, interactive: true); + skipOrRemove.Click += (_, _) => _ = LaunchAndClose(role, no_integrity: true); + } + + flyout.Items.Add(asAdmin); + flyout.Items.Add(interactive); + flyout.Items.Add(skipOrRemove); + return flyout; + } + + private void OnMainAction() + { + ShouldProceedWithOperation = true; + Close(); + } + + private async Task LaunchAndClose( + OperationType role, + bool? elevated = null, + bool? interactive = null, + bool? no_integrity = null, + bool? remove_data = null) + { + Close(); + + var pkg = _vm.Package; + var opts = await InstallOptionsFactory.LoadApplicableAsync( + pkg, + elevated: elevated, + interactive: interactive, + no_integrity: no_integrity, + remove_data: remove_data); + + AbstractOperation op = role switch + { + OperationType.Install => new InstallPackageOperation(pkg, opts), + OperationType.Update => new UpdatePackageOperation(pkg, opts), + OperationType.Uninstall => new UninstallPackageOperation(pkg, opts), + _ => throw new ArgumentOutOfRangeException(nameof(role)), + }; + + switch (role) + { + case OperationType.Install: + op.OperationSucceeded += (_, _) => TelemetryHandler.InstallPackage(pkg, TEL_OP_RESULT.SUCCESS, TEL_InstallReferral.DIRECT_SEARCH); + op.OperationFailed += (_, _) => TelemetryHandler.InstallPackage(pkg, TEL_OP_RESULT.FAILED, TEL_InstallReferral.DIRECT_SEARCH); + break; + case OperationType.Update: + op.OperationSucceeded += (_, _) => TelemetryHandler.UpdatePackage(pkg, TEL_OP_RESULT.SUCCESS); + op.OperationFailed += (_, _) => TelemetryHandler.UpdatePackage(pkg, TEL_OP_RESULT.FAILED); + break; + case OperationType.Uninstall: + op.OperationSucceeded += (_, _) => TelemetryHandler.UninstallPackage(pkg, TEL_OP_RESULT.SUCCESS); + op.OperationFailed += (_, _) => TelemetryHandler.UninstallPackage(pkg, TEL_OP_RESULT.FAILED); + break; + } + + AvaloniaOperationRegistry.Add(op); + _ = op.MainThread(); + } +} diff --git a/src/UniGetUI.Avalonia/Views/DialogPages/SimpleErrorDialog.axaml b/src/UniGetUI.Avalonia/Views/DialogPages/SimpleErrorDialog.axaml new file mode 100644 index 0000000..284f114 --- /dev/null +++ b/src/UniGetUI.Avalonia/Views/DialogPages/SimpleErrorDialog.axaml @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/UniGetUI.Avalonia/Views/MainWindow.axaml.cs b/src/UniGetUI.Avalonia/Views/MainWindow.axaml.cs new file mode 100644 index 0000000..c13f1b5 --- /dev/null +++ b/src/UniGetUI.Avalonia/Views/MainWindow.axaml.cs @@ -0,0 +1,1403 @@ +using System; +using System.Runtime.InteropServices; +using System.Threading; +using Avalonia; +using Avalonia.Controls; +using Avalonia.Input; +using Avalonia.Interactivity; +using Avalonia.Layout; +using Avalonia.Media; +using Avalonia.Threading; +using Avalonia.VisualTree; +using UniGetUI.Avalonia.Extensions; +using UniGetUI.Avalonia.Infrastructure; +using UniGetUI.Avalonia.ViewModels; +using UniGetUI.Avalonia.Views.Pages; +using UniGetUI.Core.Logging; +using UniGetUI.Core.SettingsEngine; +using UniGetUI.Core.Tools; +using UniGetUI.PackageEngine.Interfaces; + +namespace UniGetUI.Avalonia.Views; + +public enum PageType +{ + Discover, + Updates, + Installed, + Bundles, + Settings, + Managers, + OwnLog, + ManagerLog, + OperationHistory, + Help, + ReleaseNotes, + About, + Quit, + Null, // Used for initializers +} + +public partial class MainWindow : Window +{ + private const string FORCE_NATIVE_LINUX_DECORATIONS_ENVIRONMENT_VARIABLE = "UNIGETUI_FORCE_NATIVE_LINUX_DECORATIONS"; + + // Workaround for Avalonia 12 issue #21160 / #21212: BorderOnly + ExtendClientArea + // strips WS_CAPTION / WS_THICKFRAME, which makes DWM disable Aero Snap drag-to-top, + // Win+Up, and the maximize/minimize/restore animations. Re-add those bits on every + // style change. WM_GETMINMAXINFO is also overridden because Avalonia's default values + // on the primary monitor make Aero Snap maximize to the current window size (no-op). + // Targeted upstream fix in Avalonia 12.1. + private const uint WM_STYLECHANGING = 0x007C; + private const uint WM_GETMINMAXINFO = 0x0024; + private const uint WM_NCCALCSIZE = 0x0083; + // Snap Layouts: DWM shows the maximize flyout only when WM_NCHITTEST reports HTMAXBUTTON + // over the button. That routes the button's input through non-client messages, so the + // click and hover/press visuals are driven from the WndProc below (the Avalonia Button + // no longer sees pointer events there). + private const uint WM_NCHITTEST = 0x0084; + private const uint WM_NCMOUSEMOVE = 0x00A0; + private const uint WM_NCMOUSELEAVE = 0x02A2; + private const uint WM_NCLBUTTONDOWN = 0x00A1; + private const uint WM_NCLBUTTONUP = 0x00A2; + private const uint WM_NCLBUTTONDBLCLK = 0x00A3; + private const uint WM_MOUSEMOVE = 0x0200; + private const uint WM_SYSCOMMAND = 0x0112; + private const nint SC_MAXIMIZE = 0xF030; + private const nint SC_RESTORE = 0xF120; + private const int HTMAXBUTTON = 9; + private const uint TME_LEAVE = 0x0002; + private const uint TME_NONCLIENT = 0x0010; + private const int GWL_STYLE = -16; + private const uint WS_CAPTION = 0x00C00000; + private const uint WS_THICKFRAME = 0x00040000; + private const uint WS_MINIMIZEBOX = 0x00020000; + private const uint WS_MAXIMIZEBOX = 0x00010000; + private const uint MONITOR_DEFAULTTONEAREST = 2; + private const uint SWP_NOSIZE = 0x0001; + private const uint SWP_NOMOVE = 0x0002; + private const uint SWP_NOZORDER = 0x0004; + private const uint SWP_NOACTIVATE = 0x0010; + private const uint SWP_FRAMECHANGED = 0x0020; + + // DWM attributes for the native Windows 11 Mica look: rounded corners and an + // accent-colored window border that tracks focus. + private const int DWMWA_WINDOW_CORNER_PREFERENCE = 33; + private const int DWMWA_BORDER_COLOR = 34; + private const int DWMWCP_ROUND = 2; + private const int DWMWA_COLOR_NONE = unchecked((int)0xFFFFFFFE); + + private bool _focusSidebarSelectionOnNextPageChange; + private bool _maxButtonHover; + private bool _maxButtonPressed; + private TrayService? _trayService; + private bool _allowClose; + private int _isQuitting; + + // Saved outer size (DIPs) awaiting a native, exact restore in OnOpened on Windows. + private double _pendingRestoreWidth; + private double _pendingRestoreHeight; + + // Last user-chosen height (px) of the operations panel; restored when re-expanded. + private double _operationsPanelHeight = 240; + + public enum RuntimeNotificationLevel + { + Progress, + Success, + Error, + } + + public static MainWindow? Instance { get; private set; } + + private MainWindowViewModel ViewModel => (MainWindowViewModel)DataContext!; + public PageType CurrentPage => ViewModel.CurrentPage_t; + + public MainWindow() + { + Instance = this; + DataContext = new MainWindowViewModel(); + InitializeComponent(); + SetupTitleBar(); + SetupTitleBarFocusOpacity(); + SetupResponsiveRail(); + + RestoreGeometry(); + + KeyDown += Window_KeyDown; + ViewModel.CurrentPageChanged += OnCurrentPageChanged; + // Title-bar back button: visible whenever there's somewhere to go back to (mirrors WinUI's TitleBar.IsBackButtonVisible). + ViewModel.CanGoBackChanged += (_, canGoBack) => BackButton.IsVisible = canGoBack; + ViewModel.PropertyChanged += OnViewModelPropertyChanged; + UpdateOperationsPanelRow(); + + Resized += (_, _) => _ = SaveGeometryAsync(); + PositionChanged += (_, _) => _ = SaveGeometryAsync(); + this.GetObservable(WindowStateProperty).SubscribeValue(state => { _ = SaveGeometryAsync(); }); + + _trayService = new TrayService(this); + _trayService.UpdateStatus(); + } + + protected override void OnOpened(EventArgs e) + { + base.OnOpened(e); + if (!OperatingSystem.IsWindows()) + return; + + // Install the hook so future style-change attempts by Avalonia can't re-strip our bits. + Win32Properties.AddWndProcHookCallback(this, OnWindowsWndProc); + + // The initial strip already happened during Show() (before this hook could catch it), + // so manually OR our bits back into the current style. DWM picks them up immediately + // and starts honouring Aero Snap / Win+Up / native maximize animations again. + if (TryGetPlatformHandle()?.Handle is { } handle && handle != 0) + { + nint current = NativeMethods.GetWindowLongPtr(handle, GWL_STYLE); + nint updated = (nint)((nuint)current | WS_CAPTION | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX); + if (updated != current) + { + NativeMethods.SetWindowLongPtr(handle, GWL_STYLE, updated); + // Trigger WM_NCCALCSIZE so our hook runs against the new style. + NativeMethods.SetWindowPos(handle, 0, 0, 0, 0, 0, + SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED); + } + } + + SetupMicaAndAccentBorder(); + + // Restore the saved size as an exact outer rect in physical pixels. Because our + // WM_NCCALCSIZE keeps client == window rect, this round-trips with SaveGeometry with no + // frame drift, unlike Avalonia's Width/Height setter (see RestoreGeometry). + if (_pendingRestoreWidth > 0 && _pendingRestoreHeight > 0 && WindowState == WindowState.Normal + && TryGetPlatformHandle()?.Handle is { } sizeHandle && sizeHandle != 0) + { + uint dpi = NativeMethods.GetDpiForWindow(sizeHandle); + if (dpi == 0) dpi = 96; + double scale = dpi / 96.0; + NativeMethods.SetWindowPos(sizeHandle, 0, 0, 0, + (int)Math.Round(_pendingRestoreWidth * scale), (int)Math.Round(_pendingRestoreHeight * scale), + SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE); + } + _pendingRestoreWidth = _pendingRestoreHeight = 0; + } + + protected override void OnClosing(WindowClosingEventArgs e) + { + if (!_allowClose && (OperatingSystem.IsMacOS() || !Settings.Get(Settings.K.DisableSystemTray))) + { + e.Cancel = true; + Hide(); + return; + } + + e.Cancel = true; + QuitApplication(); + } + + private void ReleaseWindowResources() + { + SaveGeometryNow(); + AvaloniaAutoUpdater.ReleaseLockForAutoupdate_Window = true; + _trayService?.Dispose(); + _trayService = null; + } + + private void Window_KeyDown(object? sender, KeyEventArgs e) + { + bool isCtrl = e.KeyModifiers.HasFlag(KeyModifiers.Control); + bool isShift = e.KeyModifiers.HasFlag(KeyModifiers.Shift); + + if (e.Key == Key.Tab && isCtrl) + { + _focusSidebarSelectionOnNextPageChange = true; + ViewModel.NavigateTo(isShift + ? MainWindowViewModel.GetPreviousPage(ViewModel.CurrentPage_t) + : MainWindowViewModel.GetNextPage(ViewModel.CurrentPage_t)); + } + else if (!isCtrl && !isShift && e.Key == Key.F1) + { + ViewModel.NavigateTo(PageType.Help); + } + else if ((e.Key is Key.Q or Key.W) && isCtrl) + { + Close(); + } + else if (e.Key == Key.F5 || (e.Key == Key.R && isCtrl)) + { + (ViewModel.CurrentPageContent as IKeyboardShortcutListener)?.ReloadTriggered(); + } + else if (e.Key == Key.F && isCtrl) + { + (ViewModel.CurrentPageContent as IKeyboardShortcutListener)?.SearchTriggered(); + } + else if (e.Key == Key.A && isCtrl) + { + (ViewModel.CurrentPageContent as IKeyboardShortcutListener)?.SelectAllTriggered(); + } + else if (isCtrl && !isShift && e.Key is Key.D1 or Key.D2 or Key.D3 or Key.D4 or Key.D5 or Key.D6) + { + _focusSidebarSelectionOnNextPageChange = true; + ViewModel.NavigateTo(e.Key switch + { + Key.D1 => PageType.Discover, + Key.D2 => PageType.Updates, + Key.D3 => PageType.Installed, + Key.D4 => PageType.Bundles, + Key.D5 => PageType.Settings, + _ => PageType.Managers, + }); + e.Handled = true; + } + else if (isCtrl && !isShift && e.Key == Key.D) + { + (ViewModel.CurrentPageContent as IKeyboardShortcutListener)?.DetailsTriggered(); + e.Handled = true; + } + } + + private void OnCurrentPageChanged(object? sender, PageType pageType) + { + // Like WinUI's NavigationView: picking a page collapses the sliding flyout back to the rail. + // A docked pane stays put (it's a persistent inline pane, not a transient overlay). + if (!ViewModel.Sidebar.Docked) + ViewModel.Sidebar.IsPaneOpen = false; + + if (!_focusSidebarSelectionOnNextPageChange) + return; + + _focusSidebarSelectionOnNextPageChange = false; + Dispatcher.UIThread.Post(() => + { + var sidebar = this.GetVisualDescendants().OfType().FirstOrDefault(); + sidebar?.FocusSelectedItem(); + }, DispatcherPriority.Background); + } + + private void BackButton_Click(object? sender, RoutedEventArgs e) => ViewModel.NavigateBack(); + + private void OnViewModelPropertyChanged(object? sender, System.ComponentModel.PropertyChangedEventArgs e) + { + if (e.PropertyName is nameof(MainWindowViewModel.OperationsPanelExpanded) + or nameof(MainWindowViewModel.OperationsPanelVisible)) + UpdateOperationsPanelRow(); + + // Expanding the panel while an operation has failed jumps to that op (the failure + // badge on the chevron is what drew the user here). + if (e.PropertyName is nameof(MainWindowViewModel.OperationsPanelExpanded) + && ViewModel.OperationsPanelExpanded) + ScrollToFirstFailedOperation(); + } + + private void ScrollToFirstFailedOperation() + { + if (ViewModel.FirstFailedOperation is not { } failed) + return; + + // Defer until the just-shown list has laid out its containers. + Dispatcher.UIThread.Post(() => + { + if (OperationsList.ContainerFromItem(failed) is Control container) + container.BringIntoView(); + }, DispatcherPriority.Background); + } + + // Drive the operations-panel grid row: a resizable pixel height while the panel is + // open, Auto otherwise so it collapses to just the toolbar (or vanishes when empty). + // The GridSplitter writes the row height directly, so we read it back to preserve the + // user's chosen size across collapse/expand. + private void UpdateOperationsPanelRow() + { + if (ContentRoot.RowDefinitions.Count < 3) + return; + + RowDefinition row = ContentRoot.RowDefinitions[2]; + if (ViewModel.OperationsPanelVisible && ViewModel.OperationsPanelExpanded) + { + row.MinHeight = 80; + row.Height = new GridLength(_operationsPanelHeight, GridUnitType.Pixel); + } + else + { + if (row.Height.IsAbsolute && row.Height.Value > 0) + _operationsPanelHeight = row.Height.Value; + row.MinHeight = 0; + row.Height = GridLength.Auto; + } + } + + // ─── Navigation rail / docked pane (responsive) ──────────────────────────── + // Feed the live window width to the sidebar, which resolves the layout mode and drives + // the NavRail / NavDock / overlay visibility bindings. + private void SetupResponsiveRail() + => MainContentRoot.GetObservable(BoundsProperty) + .SubscribeValue(b => + { + if (b.Width <= 0) return; + ViewModel.Sidebar.WindowWidth = b.Width; + }); + + // Re-reads the NavMenuMode setting so the layout switch applies live from the settings page. + public void RefreshNavigationMode() + => ViewModel.Sidebar.Mode = SidebarViewModel.ParseMode(Settings.GetValue(Settings.K.NavMenuMode)); + + // Light-dismiss: clicking outside the open flyout closes it (no darkening — the layer is transparent). + private void FlyoutDismiss_PointerPressed(object? sender, PointerPressedEventArgs e) + => ViewModel.Sidebar.IsPaneOpen = false; + + // Title-bar caption follows window focus (WinUI behaviour): full opacity — white title — when active, dimmed when not. + private void SetupTitleBarFocusOpacity() + => this.GetObservable(IsActiveProperty).SubscribeValue(active => + { + HamburgerPanel.Opacity = active ? 1.0 : 0.6; + WindowButtons.Opacity = active ? 1.0 : 0.55; + }); + + private void SetupTitleBar() + { + if (OperatingSystem.IsMacOS()) + { + // macOS: extend into the native title bar area. + // WindowDecorationMargin.Top drives TitleBarGrid.Height via binding. + // Traffic lights sit on the left → keep the 65 px HamburgerPanel margin. + // Request a 44 px title bar (matching Windows/Linux) instead of the default + // ~28 px one: the default is shorter than the 32 px search pill, so the + // centred pill overflowed upward and hugged the top of the window. macOS + // vertically centres the traffic lights in the taller bar. + ExtendClientAreaToDecorationsHint = true; + ExtendClientAreaTitleBarHeightHint = 44; + + // In fullscreen the native title bar is hidden and WindowDecorationMargin + // collapses to 0, which would clip the search box and hamburger. Use a fixed + // title bar height in that state, and drop the traffic-light reservation + // since the traffic lights aren't shown either. + // + // Track the window state and the live decoration margin directly rather than + // via string-based Bindings: reflection bindings are trim-unsafe (IL2026). + void ApplyMacTitleBarLayout() + { + if (WindowState == WindowState.FullScreen) + { + TitleBarGrid.Height = 44; + MainContentRoot.Margin = new Thickness(0, 44, 0, 0); + HamburgerPanel.Margin = new Thickness(10, 0, 8, 0); + } + else + { + Thickness margin = WindowDecorationMargin; + TitleBarGrid.Height = margin.Top; + MainContentRoot.Margin = margin; + HamburgerPanel.Margin = new Thickness(65, 0, 8, 0); + } + } + + this.GetObservable(WindowStateProperty).SubscribeValue(_ => ApplyMacTitleBarLayout()); + this.GetObservable(WindowDecorationMarginProperty).SubscribeValue(_ => ApplyMacTitleBarLayout()); + } + else if (OperatingSystem.IsWindows()) + { + WindowDecorations = WindowDecorations.BorderOnly; + ExtendClientAreaToDecorationsHint = true; + ExtendClientAreaTitleBarHeightHint = -1; + // Request the Win11 Mica backdrop only when it should actually be used + // (Windows 11 + "Transparency effects" enabled). Otherwise leave the default + // so the window stays solid. The transparent-background switch happens in + // SetupMicaAndAccentBorder() once the native handle exists. + if (MicaWindowHelper.IsMicaEnabled()) + TransparencyLevelHint = new[] { WindowTransparencyLevel.Mica }; + TitleBarGrid.ClearValue(HeightProperty); + TitleBarGrid.Height = 50; + HamburgerPanel.Margin = new Thickness(10, 0, 8, 0); + WindowButtons.IsVisible = true; + MainContentRoot.Margin = new Thickness(0, 50, 0, 0); + this.GetObservable(WindowStateProperty).SubscribeValue(state => + { + UpdateMaximizeButtonState(state == WindowState.Maximized); + }); + } + else if (OperatingSystem.IsLinux()) + { + // WSLg and SSH-forwarded X11 can report incorrect maximize/input bounds + // with frameless windows. Keep native decorations for those environments. + bool useNativeDecorations = ShouldUseNativeLinuxWindowDecorations(out string decorationReason); + Logger.Info($"Linux window decorations: {(useNativeDecorations ? "native" : "custom")} ({decorationReason})"); + WindowDecorations = useNativeDecorations ? WindowDecorations.Full : WindowDecorations.None; + TitleBarGrid.ClearValue(HeightProperty); + TitleBarGrid.Height = 44; + HamburgerPanel.Margin = new Thickness(10, 0, 8, 0); + WindowButtons.IsVisible = !useNativeDecorations; + MainContentRoot.Margin = new Thickness(0, 44, 0, 0); + // Keep maximize icon in sync with window state + this.GetObservable(WindowStateProperty).SubscribeValue(state => + { + UpdateMaximizeButtonState(state == WindowState.Maximized); + }); + + // Avalonia's X11 backend treats BorderOnly as None (no decorations at all). + // Add invisible resize grips so the user can still resize by dragging edges. + if (!useNativeDecorations) + { + CreateResizeGrips(); + } + } + } + + private static bool ShouldUseNativeLinuxWindowDecorations(out string reason) + { + if (TryGetNativeLinuxDecorationsOverride(out bool forceNativeDecorations)) + { + reason = $"{FORCE_NATIVE_LINUX_DECORATIONS_ENVIRONMENT_VARIABLE}={(forceNativeDecorations ? "true" : "false")}"; + return forceNativeDecorations; + } + + if (IsRunningUnderWsl()) + { + reason = "WSL environment"; + return true; + } + + if (IsRunningUnderSshX11Forwarding()) + { + reason = "SSH X11 forwarding"; + return true; + } + + reason = "default Linux desktop"; + return false; + } + + private static bool TryGetNativeLinuxDecorationsOverride(out bool forceNativeDecorations) + { + forceNativeDecorations = false; + + string? overrideValue = Environment.GetEnvironmentVariable(FORCE_NATIVE_LINUX_DECORATIONS_ENVIRONMENT_VARIABLE); + if (string.IsNullOrWhiteSpace(overrideValue)) + { + return false; + } + + switch (overrideValue.Trim().ToLowerInvariant()) + { + case "1": + case "true": + case "on": + case "yes": + case "enabled": + forceNativeDecorations = true; + return true; + + case "0": + case "false": + case "off": + case "no": + case "disabled": + forceNativeDecorations = false; + return true; + + default: + Logger.Warn($"Ignoring invalid {FORCE_NATIVE_LINUX_DECORATIONS_ENVIRONMENT_VARIABLE} value '{overrideValue}'. Use true/false."); + return false; + } + } + + private static bool IsRunningUnderWsl() + { + string? wslDistro = Environment.GetEnvironmentVariable("WSL_DISTRO_NAME"); + string? wslInterop = Environment.GetEnvironmentVariable("WSL_INTEROP"); + return !string.IsNullOrWhiteSpace(wslDistro) || !string.IsNullOrWhiteSpace(wslInterop); + } + + private static bool IsRunningUnderSshX11Forwarding() + { + if (!OperatingSystem.IsLinux()) + { + return false; + } + + string? display = Environment.GetEnvironmentVariable("DISPLAY"); + if (string.IsNullOrWhiteSpace(display)) + { + return false; + } + + bool hasSshSession = + !string.IsNullOrWhiteSpace(Environment.GetEnvironmentVariable("SSH_CONNECTION")) || + !string.IsNullOrWhiteSpace(Environment.GetEnvironmentVariable("SSH_CLIENT")); + if (!hasSshSession) + { + return false; + } + + string normalizedDisplay = display.Trim(); + if (normalizedDisplay.StartsWith(":", StringComparison.Ordinal) || + normalizedDisplay.StartsWith("unix/", StringComparison.OrdinalIgnoreCase) || + normalizedDisplay.StartsWith("unix:", StringComparison.OrdinalIgnoreCase)) + { + return false; + } + + return normalizedDisplay.Contains(':'); + } + + /// + /// Creates invisible resize-grip borders at the edges and corners of the window, + /// enabling mouse-driven resize on platforms where native decorations are absent + /// (e.g. Linux with WindowDecorations.None). + /// + private void CreateResizeGrips() + { + if (this.Content is not Panel panel) + { + return; + } + + const int edgeThickness = 5; + const int cornerSize = 8; + + // Edge strips + panel.Children.Add(MakeGrip(this, double.NaN, edgeThickness, + HorizontalAlignment.Stretch, VerticalAlignment.Top, + StandardCursorType.SizeNorthSouth, WindowEdge.North)); + + panel.Children.Add(MakeGrip(this, double.NaN, edgeThickness, + HorizontalAlignment.Stretch, VerticalAlignment.Bottom, + StandardCursorType.SizeNorthSouth, WindowEdge.South)); + + panel.Children.Add(MakeGrip(this, edgeThickness, double.NaN, + HorizontalAlignment.Left, VerticalAlignment.Stretch, + StandardCursorType.SizeWestEast, WindowEdge.West)); + + panel.Children.Add(MakeGrip(this, edgeThickness, double.NaN, + HorizontalAlignment.Right, VerticalAlignment.Stretch, + StandardCursorType.SizeWestEast, WindowEdge.East)); + + // Corner squares + panel.Children.Add(MakeGrip(this, cornerSize, cornerSize, + HorizontalAlignment.Left, VerticalAlignment.Top, + StandardCursorType.TopLeftCorner, WindowEdge.NorthWest)); + + panel.Children.Add(MakeGrip(this, cornerSize, cornerSize, + HorizontalAlignment.Right, VerticalAlignment.Top, + StandardCursorType.TopRightCorner, WindowEdge.NorthEast)); + + panel.Children.Add(MakeGrip(this, cornerSize, cornerSize, + HorizontalAlignment.Left, VerticalAlignment.Bottom, + StandardCursorType.BottomLeftCorner, WindowEdge.SouthWest)); + + panel.Children.Add(MakeGrip(this, cornerSize, cornerSize, + HorizontalAlignment.Right, VerticalAlignment.Bottom, + StandardCursorType.BottomRightCorner, WindowEdge.SouthEast)); + return; + + static Border MakeGrip(MainWindow window, double width, double height, + HorizontalAlignment hAlign, VerticalAlignment vAlign, + StandardCursorType cursorType, WindowEdge edge) + { + var grip = new Border + { + Width = width, + Height = height, + HorizontalAlignment = hAlign, + VerticalAlignment = vAlign, + Background = Brushes.Transparent, + Cursor = new Cursor(cursorType), + IsHitTestVisible = true, + }; + grip.PointerPressed += (_, e) => + { + if (e.GetCurrentPoint(window).Properties.IsLeftButtonPressed) + { + window.BeginResizeDrag(edge, e); + e.Handled = true; + } + }; + return grip; + } + } + + private async Task SaveGeometryAsync() + { + try + { + int oldWidth = (int)Width; + int oldHeight = (int)Height; + PixelPoint oldPosition = Position; + WindowState oldState = WindowState; + await Task.Delay(100); + + if (oldWidth != (int)Width || oldHeight != (int)Height + || oldPosition != Position || oldState != WindowState) + return; + + SaveGeometryNow(); + } + catch (Exception ex) + { + Logger.Error(ex); + } + } + + private void SaveGeometryNow() + { + try + { + int state = WindowState == WindowState.Maximized ? 1 : 0; + string geometry = $"v2,{Position.X},{Position.Y},{(int)Width},{(int)Height},{state}"; + Settings.SetValue(Settings.K.WindowGeometry, geometry); + } + catch (Exception ex) + { + Logger.Error(ex); + } + } + + private void RestoreGeometry() + { + string geometry = Settings.GetValue(Settings.K.WindowGeometry); + if (string.IsNullOrEmpty(geometry)) + return; + + string[] items = geometry.Split(','); + if (items.Length is not (5 or 6)) + { + Logger.Warn($"The restored geometry did not have a supported item count (found length was {items.Length})"); + return; + } + + int x, y, width, height, state; + try + { + if (items.Length == 6 && items[0] == "v2") + { + x = int.Parse(items[1]); + y = int.Parse(items[2]); + width = int.Parse(items[3]); + height = int.Parse(items[4]); + state = int.Parse(items[5]); + } + else + { + x = int.Parse(items[0]); + y = int.Parse(items[1]); + width = int.Parse(items[2]); + height = int.Parse(items[3]); + state = int.Parse(items[4]); + } + } + catch (Exception ex) + { + Logger.Error("Could not parse window geometry integers"); + Logger.Error(ex); + return; + } + + WindowStartupLocation = WindowStartupLocation.Manual; + + if (state == 1) + { + // Mirror WinUI behaviour: don't reapply the saved (maximized) bounds, just + // maximize. The OS / Avalonia picks a sensible un-maximize restore size. + WindowState = WindowState.Maximized; + } + else if (IsRectangleFullyVisible(x, y, width, height)) + { + Width = width; + Height = height; + Position = new PixelPoint(x, y); + // On Windows our WM_NCCALCSIZE makes the client rect equal the full window rect, so the + // saved size is the outer size. Avalonia's Width/Height setter re-adds WS_THICKFRAME via + // AdjustWindowRectEx, inflating the window a little on every restart; OnOpened restores + // the exact outer rect natively to cancel that drift. + if (OperatingSystem.IsWindows()) + { + _pendingRestoreWidth = width; + _pendingRestoreHeight = height; + } + } + else + { + Logger.Warn("Restored geometry was outside of desktop bounds"); + } + } + + private bool IsRectangleFullyVisible(int x, int y, int width, int height) + { + // Position is in screen pixels, Width/Height are DIPs. Scale width/height + // by the DPI of the screen that contains the saved position before comparing + // against the union of all monitor bounds (which Avalonia reports in pixels). + var screens = Screens?.All; + if (screens is null || screens.Count == 0) + return true; + + int minX = int.MaxValue, minY = int.MaxValue; + int maxX = int.MinValue, maxY = int.MinValue; + double hostScaling = 1.0; + bool foundHost = false; + + foreach (var screen in screens) + { + var bounds = screen.Bounds; + if (bounds.X < minX) minX = bounds.X; + if (bounds.Y < minY) minY = bounds.Y; + if (bounds.X + bounds.Width > maxX) maxX = bounds.X + bounds.Width; + if (bounds.Y + bounds.Height > maxY) maxY = bounds.Y + bounds.Height; + + if (!foundHost && bounds.Contains(new PixelPoint(x, y))) + { + hostScaling = screen.Scaling; + foundHost = true; + } + } + + if (!foundHost) + hostScaling = Screens?.Primary?.Scaling ?? 1.0; + + int widthPx = (int)(width * hostScaling); + int heightPx = (int)(height * hostScaling); + + if (x + 10 < minX || x + widthPx - 10 > maxX || y + 10 < minY || y + heightPx - 10 > maxY) + return false; + + return true; + } + + private void MinimizeButton_Click(object? sender, RoutedEventArgs e) + => WindowState = WindowState.Minimized; + + private void MaximizeButton_Click(object? sender, RoutedEventArgs e) + { + WindowState = WindowState == WindowState.Maximized + ? WindowState.Normal + : WindowState.Maximized; + } + + private void UpdateMaximizeButtonState(bool isMaximized) + { + MaximizeIcon.Data = Geometry.Parse( + isMaximized + ? "M2,0 H10 V8 H2 Z M0,2 H8 V10 H0 Z" + : "M0,0 H10 V10 H0 Z"); + ToolTip.SetTip( + MaximizeButton, + CoreTools.Translate(isMaximized ? "Restore" : "Maximize")); + } + + // True when the WM_NCHITTEST screen point (physical px in lParam) falls within the maximize + // button's bounds — the area for which we claim HTMAXBUTTON so Snap Layouts can attach. + private bool HitTestMaximizeButton(nint lParam) + { + if (!MaximizeButton.IsVisible) + return false; + try + { + int x = unchecked((short)(lParam.ToInt64() & 0xFFFF)); + int y = unchecked((short)((lParam.ToInt64() >> 16) & 0xFFFF)); + PixelPoint topLeft = MaximizeButton.PointToScreen(new Point(0, 0)); + PixelPoint bottomRight = MaximizeButton.PointToScreen( + new Point(MaximizeButton.Bounds.Width, MaximizeButton.Bounds.Height)); + return x >= topLeft.X && x < bottomRight.X && y >= topLeft.Y && y < bottomRight.Y; + } + catch + { + return false; + } + } + + // Emulates the button's pointer-over/pressed fill (lost once input is non-client) using the + // same Fluent brushes the neighbouring min/close buttons use, so the row stays consistent. + private void SetMaximizeButtonVisual(bool hover, bool pressed) + { + _maxButtonHover = hover; + _maxButtonPressed = pressed; + + string? key = pressed ? "ButtonBackgroundPressed" : hover ? "ButtonBackgroundPointerOver" : null; + if (key is not null && this.TryFindResource(key, ActualThemeVariant, out var res) && res is IBrush brush) + MaximizeButton.Background = brush; + else + MaximizeButton.Background = Brushes.Transparent; + } + + private static void TrackNonClientMouseLeave(nint hWnd) + { + var tme = new NativeMethods.TRACKMOUSEEVENT + { + cbSize = (uint)Marshal.SizeOf(), + dwFlags = TME_LEAVE | TME_NONCLIENT, + hwndTrack = hWnd, + dwHoverTime = 0, + }; + NativeMethods.TrackMouseEvent(ref tme); + } + + // Applies the Windows 11 Mica look when it's actually usable (Win11 + transparency on): + // a transparent window so the backdrop shows, native rounded corners, and no accent + // border (it reads as out of place on the large main window). Otherwise the window keeps + // its solid background. Must run after the native handle exists (OnOpened); Windows-only. + private void SetupMicaAndAccentBorder() + { + if (!OperatingSystem.IsWindows()) + return; + + if (TryGetPlatformHandle()?.Handle is not { } handle || handle == 0) + return; + + if (!MicaWindowHelper.IsMicaEnabled()) + { + // No Mica (Windows 10, transparency off, etc.): keep the solid window background. + // Styles.WindowsMica is not merged in this case, so the surfaces stay opaque too. + if (this.TryFindResource("AppWindowBackground", ActualThemeVariant, out var bg) && bg is IBrush brush) + Background = brush; + return; + } + + // The custom NCCALCSIZE frame keeps WS_THICKFRAME, so DWM still has a frame to round. + int corner = DWMWCP_ROUND; + NativeMethods.DwmSetWindowAttribute(handle, DWMWA_WINDOW_CORNER_PREFERENCE, ref corner, sizeof(int)); + + // Transparent window + transparent MicaPageBackground (from Styles.WindowsMica) let + // the backdrop show through the chrome and page area. + Background = Brushes.Transparent; + + // Suppress the window border colour so the main window doesn't get the accent edge + // (the dialogs keep it via MicaWindowHelper). + int noBorder = DWMWA_COLOR_NONE; + NativeMethods.DwmSetWindowAttribute(handle, DWMWA_BORDER_COLOR, ref noBorder, sizeof(int)); + } + + private static nint OnWindowsWndProc(nint hWnd, uint msg, nint wParam, nint lParam, ref bool handled) + { + // ── Snap Layouts: report HTMAXBUTTON over the custom maximize button so Win11 shows the + // layout flyout, and emulate hover/press/click since input now arrives as NC messages. ── + if (Instance is { } self && self.WindowButtons.IsVisible) + { + switch (msg) + { + case WM_NCHITTEST: + if (self.HitTestMaximizeButton(lParam)) + { + handled = true; + return HTMAXBUTTON; + } + break; + + case WM_NCMOUSEMOVE: + if (wParam == HTMAXBUTTON) + { + self.SetMaximizeButtonVisual(hover: true, self._maxButtonPressed); + TrackNonClientMouseLeave(hWnd); + handled = true; + return 0; + } + self.SetMaximizeButtonVisual(hover: false, pressed: false); + break; + + case WM_MOUSEMOVE: + if (self._maxButtonHover) + self.SetMaximizeButtonVisual(hover: false, pressed: false); + break; + + case WM_NCMOUSELEAVE: + self.SetMaximizeButtonVisual(hover: false, pressed: false); + break; + + case WM_NCLBUTTONDOWN when wParam == HTMAXBUTTON: + self.SetMaximizeButtonVisual(hover: true, pressed: true); + handled = true; + return 0; + + case WM_NCLBUTTONUP when wParam == HTMAXBUTTON: + bool wasPressed = self._maxButtonPressed; + self.SetMaximizeButtonVisual(hover: true, pressed: false); + if (wasPressed) + NativeMethods.PostMessage(hWnd, WM_SYSCOMMAND, + self.WindowState == WindowState.Maximized ? SC_RESTORE : SC_MAXIMIZE, 0); + handled = true; + return 0; + + case WM_NCLBUTTONDBLCLK when wParam == HTMAXBUTTON: + handled = true; // the down/up pair already toggled; swallow the follow-up dblclk + return 0; + } + } + + // Force client = full window rect. Avalonia's ExtendClientArea handler only overrides + // the top inset, leaving the WS_THICKFRAME left/right/bottom resize border as glass. + if (msg == WM_NCCALCSIZE && wParam.ToInt64() != 0) + { + // When maximized, Windows places the window so its resize border sits offscreen + // (top-left near (-frame, -frame)). Claiming the whole window rect as client then + // pushes the title bar's top few pixels off the monitor, clipping the search box + // so it hugs the top edge (#5013). While maximized, inset the client rect by the + // frame thickness so it fills exactly the visible monitor; keep the full-rect + // (borderless, extended) client otherwise. + if (NativeMethods.IsZoomed(hWnd)) + { + uint dpi = NativeMethods.GetDpiForWindow(hWnd); + if (dpi == 0) dpi = 96; + var border = default(NativeMethods.RECT); + if (NativeMethods.AdjustWindowRectExForDpi(ref border, WS_THICKFRAME, false, 0, dpi)) + { + var p = Marshal.PtrToStructure(lParam); + p.rgrc0.Left -= border.Left; + p.rgrc0.Top -= border.Top; + p.rgrc0.Right -= border.Right; + p.rgrc0.Bottom -= border.Bottom; + Marshal.StructureToPtr(p, lParam, false); + } + } + handled = true; + return 0; + } + + // Intercept SetWindowLong(GWL_STYLE, ...) attempts and OR our required bits back into + // the new style before Windows accepts the change. lParam points to a STYLESTRUCT + // whose styleNew member is the proposed new style. We modify it in place and let the + // chain continue (no handled=true) so Avalonia / DefWindowProc still process the + // (now-corrected) message. + if (msg == WM_STYLECHANGING && wParam.ToInt64() == GWL_STYLE) + { + var ss = Marshal.PtrToStructure(lParam); + uint preserved = ss.styleNew | WS_CAPTION | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX; + if (preserved != ss.styleNew) + { + ss.styleNew = preserved; + Marshal.StructureToPtr(ss, lParam, false); + } + } + + // Override the max-size / max-position Avalonia would otherwise provide. On the + // primary monitor (where the taskbar lives) Avalonia's defaults can leave ptMaxSize + // equal to the current window size, so Aero Snap drag-to-top "maximizes" to the same + // bounds and the window appears not to resize. We always report the current monitor's + // work area, which is what Windows actually uses for native maximize. + // handled = true so Avalonia's own WM_GETMINMAXINFO handler can't run after us and + // overwrite the values we just set. + if (msg == WM_GETMINMAXINFO) + { + nint monitor = NativeMethods.MonitorFromWindow(hWnd, MONITOR_DEFAULTTONEAREST); + if (monitor != 0) + { + var mi = new NativeMethods.MONITORINFO { cbSize = Marshal.SizeOf() }; + if (NativeMethods.GetMonitorInfo(monitor, ref mi)) + { + var mmi = Marshal.PtrToStructure(lParam); + mmi.ptMaxPosition.X = mi.rcWork.Left - mi.rcMonitor.Left; + mmi.ptMaxPosition.Y = mi.rcWork.Top - mi.rcMonitor.Top; + mmi.ptMaxSize.X = mi.rcWork.Right - mi.rcWork.Left; + mmi.ptMaxSize.Y = mi.rcWork.Bottom - mi.rcWork.Top; + if (mmi.ptMaxTrackSize.X < mmi.ptMaxSize.X) mmi.ptMaxTrackSize.X = mmi.ptMaxSize.X; + if (mmi.ptMaxTrackSize.Y < mmi.ptMaxSize.Y) mmi.ptMaxTrackSize.Y = mmi.ptMaxSize.Y; + // Set ptMinTrackSize to MinWidth/MinHeight in DIPs plus the real + // WS_THICKFRAME inset. Avalonia's own handler would omit the inset for + // BorderOnly (BorderThickness returns 0), letting the outer window shrink + // below the client minimum — Avalonia then grows it back via SetWindowPos + // pinning x, pushing the right edge → the window slides past MinWidth. + if (Instance is { } w) + { + uint dpi = NativeMethods.GetDpiForWindow(hWnd); + if (dpi == 0) dpi = 96; + double scale = dpi / 96.0; + uint style = (uint)NativeMethods.GetWindowLongPtr(hWnd, GWL_STYLE).ToInt64(); + + var frame = default(NativeMethods.RECT); + int frameW = 0, frameH = 0; + if (NativeMethods.AdjustWindowRectExForDpi(ref frame, style, false, 0, dpi)) + { + frameW = (-frame.Left) + frame.Right; + frameH = (-frame.Top) + frame.Bottom; + } + + int minX = (int)Math.Ceiling(w.MinWidth * scale) + frameW; + int minY = (int)Math.Ceiling(w.MinHeight * scale) + frameH; + if (mmi.ptMinTrackSize.X < minX) mmi.ptMinTrackSize.X = minX; + if (mmi.ptMinTrackSize.Y < minY) mmi.ptMinTrackSize.Y = minY; + } + + Marshal.StructureToPtr(mmi, lParam, false); + handled = true; + return 0; + } + } + } + return 0; + } + + // P/Invokes compile on any platform; they are only called from code paths guarded by + // OperatingSystem.IsWindows(), so non-Windows targets never invoke user32.dll at runtime. + private static class NativeMethods + { + [DllImport("user32.dll", EntryPoint = "GetWindowLongPtrW", SetLastError = true)] + public static extern nint GetWindowLongPtr(nint hWnd, int nIndex); + + [DllImport("user32.dll", EntryPoint = "SetWindowLongPtrW", SetLastError = true)] + public static extern nint SetWindowLongPtr(nint hWnd, int nIndex, nint dwNewLong); + + [DllImport("user32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool SetWindowPos(nint hWnd, nint hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags); + + [DllImport("user32.dll")] + public static extern uint GetDpiForWindow(nint hWnd); + + [DllImport("user32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool PostMessage(nint hWnd, uint Msg, nint wParam, nint lParam); + + [DllImport("user32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool TrackMouseEvent(ref TRACKMOUSEEVENT lpEventTrack); + + [DllImport("user32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool AdjustWindowRectExForDpi(ref RECT lpRect, uint dwStyle, [MarshalAs(UnmanagedType.Bool)] bool bMenu, uint dwExStyle, uint dpi); + + [DllImport("user32.dll")] + public static extern nint MonitorFromWindow(nint hwnd, uint dwFlags); + + [DllImport("user32.dll")] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool IsZoomed(nint hWnd); + + [DllImport("user32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool GetMonitorInfo(nint hMonitor, ref MONITORINFO lpmi); + + [DllImport("dwmapi.dll")] + public static extern int DwmSetWindowAttribute(nint hwnd, int attr, ref int value, int size); + + [StructLayout(LayoutKind.Sequential)] + public struct STYLESTRUCT + { + public uint styleOld; + public uint styleNew; + } + + [StructLayout(LayoutKind.Sequential)] + public struct POINT + { + public int X; + public int Y; + } + + [StructLayout(LayoutKind.Sequential)] + public struct TRACKMOUSEEVENT + { + public uint cbSize; + public uint dwFlags; + public nint hwndTrack; + public uint dwHoverTime; + } + + [StructLayout(LayoutKind.Sequential)] + public struct MINMAXINFO + { + public POINT ptReserved; + public POINT ptMaxSize; + public POINT ptMaxPosition; + public POINT ptMinTrackSize; + public POINT ptMaxTrackSize; + } + + [StructLayout(LayoutKind.Sequential)] + public struct RECT + { + public int Left; + public int Top; + public int Right; + public int Bottom; + } + + [StructLayout(LayoutKind.Sequential)] + public struct MONITORINFO + { + public int cbSize; + public RECT rcMonitor; + public RECT rcWork; + public uint dwFlags; + } + + // rgrc is a RECT[3] laid out inline; only rgrc[0] (the proposed client rect) is needed here. + [StructLayout(LayoutKind.Sequential)] + public struct NCCALCSIZE_PARAMS + { + public RECT rgrc0; + public RECT rgrc1; + public RECT rgrc2; + public nint lppos; + } + } + + private void CloseButton_Click(object? sender, RoutedEventArgs e) + => Close(); + + // Manual title-bar drag state. Only used for touch/pen on Windows (see TitleBar_PointerPressed), + // where Avalonia's BeginMoveDrag drives an OS modal loop the finger can't feed. Bound to the + // owning pointer so a second contact can't hijack or end an in-progress drag. + private IPointer? _titleBarDragPointer; + private Point _titleBarDragOrigin; + private bool _restoreThenDrag; // press began while maximized → restore on first real move + + private void TitleBar_PointerPressed(object? sender, PointerPressedEventArgs e) + { + // Manual drag only on Windows + touch/pen. Mouse keeps the OS move (Aero Snap), and on + // macOS/Linux the native BeginMoveDrag already handles touch (and Wayland forbids self-positioning). + bool manualDrag = OperatingSystem.IsWindows() && e.Pointer.Type != PointerType.Mouse; + + if (!manualDrag && !e.GetCurrentPoint(this).Properties.IsLeftButtonPressed) + return; + + if (e.ClickCount == 2) + { + WindowState = WindowState == WindowState.Maximized + ? WindowState.Normal + : WindowState.Maximized; + return; + } + + if (!manualDrag) + { + BeginMoveDrag(e); + return; + } + + // Touch/pen on Windows: move the window manually (issue #4866). + if (_titleBarDragPointer is not null) + return; + + _titleBarDragPointer = e.Pointer; + _titleBarDragOrigin = e.GetPosition(this); + // Dragging a maximized window restores it first (matches the native mouse gesture). + _restoreThenDrag = WindowState == WindowState.Maximized; + e.Pointer.Capture(TitleBarDragArea); + e.Handled = true; + } + + private void TitleBar_PointerMoved(object? sender, PointerEventArgs e) + { + if (e.Pointer != _titleBarDragPointer) + return; + + Vector delta = e.GetPosition(this) - _titleBarDragOrigin; + + // Started on a maximized window: ignore tiny jitter (so a tap doesn't restore), then + // restore-and-reposition under the finger before the normal drag takes over. + if (_restoreThenDrag) + { + if (Math.Abs(delta.X) < 4 && Math.Abs(delta.Y) < 4) + return; + RestoreForTouchDrag(e.GetPosition(this)); + e.Handled = true; + return; + } + + if (delta.X == 0 && delta.Y == 0) + return; + + // GetPosition is window-relative and Position is in screen pixels; scale converts between + // them. Closed loop: the origin stays fixed and delta is re-measured against the moved + // window each event, so the sub-pixel remainder is held in the geometry and re-applied + // rather than accumulating. Round (not truncate) to keep the residual symmetric and <0.5px. + double scale = RenderScaling; + Position += new PixelVector((int)Math.Round(delta.X * scale), (int)Math.Round(delta.Y * scale)); + e.Handled = true; + } + + // Restores a maximized window mid-drag and re-anchors it under the finger, matching the native + // mouse gesture. The finger's screen point and its horizontal fraction of the title bar are + // captured while still maximized; after WindowState.Normal the window is placed so that same + // fraction of the (now restored) width sits under the finger. On Win32 the restore is + // synchronous — ShowWindow sends WM_SIZE inline, so Bounds already reflects the restored size. + private void RestoreForTouchDrag(Point grab) + { + double fraction = Bounds.Width > 0 ? Math.Clamp(grab.X / Bounds.Width, 0, 1) : 0.5; + double titleY = grab.Y; + PixelPoint fingerScreen = this.PointToScreen(grab); + + _restoreThenDrag = false; + WindowState = WindowState.Normal; + + double scale = RenderScaling; + var origin = new Point(fraction * Bounds.Width, titleY); + Position = fingerScreen - new PixelVector( + (int)Math.Round(origin.X * scale), + (int)Math.Round(origin.Y * scale)); + _titleBarDragOrigin = origin; + } + + private void TitleBar_PointerReleased(object? sender, PointerReleasedEventArgs e) + { + if (e.Pointer != _titleBarDragPointer) + return; + + _titleBarDragPointer = null; + _restoreThenDrag = false; + e.Pointer.Capture(null); + e.Handled = true; + } + + private void TitleBar_PointerCaptureLost(object? sender, PointerCaptureLostEventArgs e) + { + if (e.Pointer == _titleBarDragPointer) + { + _titleBarDragPointer = null; + _restoreThenDrag = false; + } + } + + private void SearchBox_KeyDown(object? sender, KeyEventArgs e) + { + if (e.Key == Key.Enter) + ViewModel.SubmitGlobalSearch(); + } + + // ─── Public navigation API ──────────────────────────────────────────────── + public void Navigate(PageType type) => ViewModel.NavigateTo(type); + public void OpenManagerLogs(IPackageManager? manager = null) => ViewModel.OpenManagerLogs(manager); + public void OpenManagerSettings(IPackageManager? manager = null) => + ViewModel.OpenManagerSettings(manager); + public void ShowHelp(string uriAttachment = "") => ViewModel.ShowHelp(uriAttachment); + + /// + /// Focuses the global search box and optionally pre-fills a character typed + /// while the package list had focus (type-to-search). + /// + public void FocusGlobalSearch(string prefill = "") + { + if (!string.IsNullOrEmpty(prefill)) + { + ViewModel.GlobalSearchText = prefill; + // Place cursor at end so the user can keep typing + GlobalSearchBox.CaretIndex = prefill.Length; + } + GlobalSearchBox.Focus(); + } + + // ─── Public API (legacy compat) ─────────────────────────────────────────── + // Surfaces a fresh, auto-dismissing toast per call (name kept for pre-toast callers). + public void ShowBanner(string title, string message, RuntimeNotificationLevel level) + { + if (level == RuntimeNotificationLevel.Progress) return; + + var severity = level switch + { + RuntimeNotificationLevel.Error => InfoBarSeverity.Error, + RuntimeNotificationLevel.Success => InfoBarSeverity.Success, + _ => InfoBarSeverity.Informational, + }; + + var toast = new InfoBarViewModel + { + Title = title, + Message = message, + Severity = severity, + IsClosable = true, + IsOpen = true, + }; + toast.OnClosed = () => ViewModel.DismissToast(toast); + ViewModel.ShowToast(toast); + } + + // Pause/resume a toast's auto-dismiss countdown while the pointer is over it. + private void Toast_PointerEntered(object? sender, PointerEventArgs e) + { + if ((sender as Control)?.DataContext is InfoBarViewModel vm) + ViewModel.PauseToast(vm); + } + + private void Toast_PointerExited(object? sender, PointerEventArgs e) + { + if ((sender as Control)?.DataContext is InfoBarViewModel vm) + ViewModel.ResumeToast(vm); + } + + public void UpdateSystemTrayStatus() => _trayService?.UpdateStatus(); + + public void ShowRuntimeNotification(string title, string message, RuntimeNotificationLevel level) => + ShowBanner(title, message, level); + + // ─── BackgroundAPI integration ──────────────────────────────────────────── + public void ShowFromTray() + { + if (!IsVisible) + Show(); + if (WindowState == WindowState.Minimized) + WindowState = WindowState.Normal; + Activate(); + } + + public bool IsQuitting => Interlocked.CompareExchange(ref _isQuitting, 0, 0) == 1; + + public void QuitApplication() + { + if (Interlocked.Exchange(ref _isQuitting, 1) == 1) + return; + + _allowClose = true; + ReleaseWindowResources(); + + if (IsVisible) + Hide(); + + _ = QuitApplicationAsync(); + } + + private static async Task QuitApplicationAsync() + { + Logger.Warn("Quitting UniGetUI"); + try + { + await AvaloniaBootstrapper.StopIpcApiAsync().WaitAsync(TimeSpan.FromSeconds(5)); + } + catch (TimeoutException ex) + { + Logger.Warn("Timed out while stopping Avalonia IPC API during shutdown"); + Logger.Warn(ex); + } + catch (Exception ex) + { + Logger.Error(ex); + } + + Environment.Exit(0); + } + + public static void ApplyProxyVariableToProcess() + { + try + { + var proxyUri = Settings.GetProxyUrl(); + if (proxyUri is null || !Settings.Get(Settings.K.EnableProxy)) + { + Environment.SetEnvironmentVariable("HTTP_PROXY", "", EnvironmentVariableTarget.Process); + return; + } + + string content; + if (!Settings.Get(Settings.K.EnableProxyAuth)) + { + content = proxyUri.ToString(); + } + else + { + var creds = Settings.GetProxyCredentials(); + if (creds is null) + { + content = proxyUri.ToString(); + } + else + { + content = $"{proxyUri.Scheme}://{Uri.EscapeDataString(creds.UserName)}" + + $":{Uri.EscapeDataString(creds.Password)}" + + $"@{proxyUri.AbsoluteUri.Replace($"{proxyUri.Scheme}://", "")}"; + } + } + + Environment.SetEnvironmentVariable("HTTP_PROXY", content, EnvironmentVariableTarget.Process); + } + catch (Exception ex) + { + Logger.Error("Failed to apply proxy settings:"); + Logger.Error(ex); + } + } +} diff --git a/src/UniGetUI.Avalonia/Views/Pages/AboutPages/AboutPage.axaml b/src/UniGetUI.Avalonia/Views/Pages/AboutPages/AboutPage.axaml new file mode 100644 index 0000000..cc8da20 --- /dev/null +++ b/src/UniGetUI.Avalonia/Views/Pages/AboutPages/AboutPage.axaml @@ -0,0 +1,111 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/UniGetUI.Avalonia/Views/Pages/AboutPages/AboutPage.axaml.cs b/src/UniGetUI.Avalonia/Views/Pages/AboutPages/AboutPage.axaml.cs new file mode 100644 index 0000000..a844fae --- /dev/null +++ b/src/UniGetUI.Avalonia/Views/Pages/AboutPages/AboutPage.axaml.cs @@ -0,0 +1,13 @@ +using Avalonia.Controls; +using UniGetUI.Avalonia.ViewModels.Pages.AboutPages; + +namespace UniGetUI.Avalonia.Views.Pages.AboutPages; + +public partial class AboutPage : UserControl +{ + public AboutPage() + { + DataContext = new AboutPageViewModel(); + InitializeComponent(); + } +} diff --git a/src/UniGetUI.Avalonia/Views/Pages/AboutPages/Contributors.axaml b/src/UniGetUI.Avalonia/Views/Pages/AboutPages/Contributors.axaml new file mode 100644 index 0000000..c9e5a72 --- /dev/null +++ b/src/UniGetUI.Avalonia/Views/Pages/AboutPages/Contributors.axaml @@ -0,0 +1,70 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/UniGetUI.Avalonia/Views/Pages/AboutPages/Contributors.axaml.cs b/src/UniGetUI.Avalonia/Views/Pages/AboutPages/Contributors.axaml.cs new file mode 100644 index 0000000..2cdb6d1 --- /dev/null +++ b/src/UniGetUI.Avalonia/Views/Pages/AboutPages/Contributors.axaml.cs @@ -0,0 +1,21 @@ +using Avalonia.Controls; +using Avalonia.Interactivity; +using UniGetUI.Avalonia.ViewModels.Pages.AboutPages; +using UniGetUI.Core.Tools; + +namespace UniGetUI.Avalonia.Views.Pages.AboutPages; + +public partial class Contributors : UserControl +{ + public Contributors() + { + DataContext = new ContributorsViewModel(); + InitializeComponent(); + } + + private void GitHubButton_Click(object? sender, RoutedEventArgs e) + { + if (sender is Button { Tag: Uri url }) + CoreTools.Launch(url.ToString()); + } +} diff --git a/src/UniGetUI.Avalonia/Views/Pages/AboutPages/ThirdPartyLicenses.axaml b/src/UniGetUI.Avalonia/Views/Pages/AboutPages/ThirdPartyLicenses.axaml new file mode 100644 index 0000000..c522a6c --- /dev/null +++ b/src/UniGetUI.Avalonia/Views/Pages/AboutPages/ThirdPartyLicenses.axaml @@ -0,0 +1,78 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/UniGetUI.Avalonia/Views/Pages/AboutPages/ThirdPartyLicenses.axaml.cs b/src/UniGetUI.Avalonia/Views/Pages/AboutPages/ThirdPartyLicenses.axaml.cs new file mode 100644 index 0000000..96fd453 --- /dev/null +++ b/src/UniGetUI.Avalonia/Views/Pages/AboutPages/ThirdPartyLicenses.axaml.cs @@ -0,0 +1,27 @@ +using Avalonia.Controls; +using Avalonia.Interactivity; +using UniGetUI.Avalonia.ViewModels.Pages.AboutPages; +using UniGetUI.Core.Tools; + +namespace UniGetUI.Avalonia.Views.Pages.AboutPages; + +public partial class ThirdPartyLicenses : UserControl +{ + public ThirdPartyLicenses() + { + DataContext = new ThirdPartyLicensesViewModel(); + InitializeComponent(); + } + + private void LicenseButton_Click(object? sender, RoutedEventArgs e) + { + if (sender is Button { Tag: Uri url }) + CoreTools.Launch(url.ToString()); + } + + private void HomepageButton_Click(object? sender, RoutedEventArgs e) + { + if (sender is Button { Tag: Uri url }) + CoreTools.Launch(url.ToString()); + } +} diff --git a/src/UniGetUI.Avalonia/Views/Pages/AboutPages/Translators.axaml b/src/UniGetUI.Avalonia/Views/Pages/AboutPages/Translators.axaml new file mode 100644 index 0000000..76e05dc --- /dev/null +++ b/src/UniGetUI.Avalonia/Views/Pages/AboutPages/Translators.axaml @@ -0,0 +1,87 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/UniGetUI.Avalonia/Views/Pages/AboutPages/Translators.axaml.cs b/src/UniGetUI.Avalonia/Views/Pages/AboutPages/Translators.axaml.cs new file mode 100644 index 0000000..4ddd591 --- /dev/null +++ b/src/UniGetUI.Avalonia/Views/Pages/AboutPages/Translators.axaml.cs @@ -0,0 +1,24 @@ +using Avalonia.Controls; +using Avalonia.Interactivity; +using UniGetUI.Avalonia.ViewModels.Pages.AboutPages; +using UniGetUI.Core.Tools; + +namespace UniGetUI.Avalonia.Views.Pages.AboutPages; + +public partial class Translators : UserControl +{ + public Translators() + { + DataContext = new TranslatorsViewModel(); + InitializeComponent(); + } + + private void BecomeTranslatorButton_Click(object? sender, RoutedEventArgs e) => + CoreTools.Launch("https://github.com/Devolutions/UniGetUI/wiki#translating-wingetui"); + + private void GitHubButton_Click(object? sender, RoutedEventArgs e) + { + if (sender is Button { Tag: Uri url }) + CoreTools.Launch(url.ToString()); + } +} diff --git a/src/UniGetUI.Avalonia/Views/Pages/HelpPage.axaml b/src/UniGetUI.Avalonia/Views/Pages/HelpPage.axaml new file mode 100644 index 0000000..ed75c00 --- /dev/null +++ b/src/UniGetUI.Avalonia/Views/Pages/HelpPage.axaml @@ -0,0 +1,118 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/UniGetUI.Avalonia/Views/Pages/HelpPage.axaml.cs b/src/UniGetUI.Avalonia/Views/Pages/HelpPage.axaml.cs new file mode 100644 index 0000000..e684674 --- /dev/null +++ b/src/UniGetUI.Avalonia/Views/Pages/HelpPage.axaml.cs @@ -0,0 +1,80 @@ +using Avalonia.Controls; +using Avalonia.Interactivity; +using UniGetUI.Avalonia.ViewModels.Pages; + +namespace UniGetUI.Avalonia.Views.Pages; + +public partial class HelpPage : UserControl, IEnterLeaveListener +{ + private readonly HelpPageViewModel _viewModel; + private string _pendingNavigation = HelpPageViewModel.HelpBaseUrl; + private bool _adapterReady; + + public HelpPage() + { + _viewModel = new HelpPageViewModel(); + DataContext = _viewModel; + InitializeComponent(); + + if (OperatingSystem.IsLinux()) + { + WebViewBorder.IsVisible = false; + LinuxFallbackPanel.IsVisible = true; + return; + } + + WebViewControl.NavigationStarted += (_, _) => + NavProgressBar.IsVisible = true; + + WebViewControl.NavigationCompleted += (_, e) => + { + NavProgressBar.IsVisible = false; + _viewModel.CurrentUrl = WebViewControl.Source?.ToString() ?? HelpPageViewModel.HelpBaseUrl; + BackButton.IsEnabled = WebViewControl.CanGoBack; + ForwardButton.IsEnabled = WebViewControl.CanGoForward; + }; + + // WebView2 on Windows initializes asynchronously after the control is attached + // to the visual tree. Navigate() called before AdapterCreated is silently dropped. + // This mirrors WinUI's EnsureCoreWebView2Async() pattern. + WebViewControl.AdapterCreated += (_, _) => + { + _adapterReady = true; + WebViewControl.Navigate(new Uri(_pendingNavigation)); + }; + } + + public void NavigateTo(string uriAttachment) + { + string url = _viewModel.GetInitialUrl(uriAttachment); + _pendingNavigation = url; + if (_adapterReady) + WebViewControl.Navigate(new Uri(url)); + } + + public void OnEnter() + { + if (_adapterReady) + WebViewControl.Navigate(new Uri(_pendingNavigation)); + } + + public void OnLeave() { } + + private void BackButton_Click(object? sender, RoutedEventArgs e) + { + if (WebViewControl.CanGoBack) + WebViewControl.GoBack(); + } + + private void ForwardButton_Click(object? sender, RoutedEventArgs e) + { + if (WebViewControl.CanGoForward) + WebViewControl.GoForward(); + } + + private void HomeButton_Click(object? sender, RoutedEventArgs e) => + WebViewControl.Navigate(new Uri(HelpPageViewModel.HelpBaseUrl)); + + private void ReloadButton_Click(object? sender, RoutedEventArgs e) => + WebViewControl.Refresh(); +} diff --git a/src/UniGetUI.Avalonia/Views/Pages/LogPages/BaseLogPage.axaml b/src/UniGetUI.Avalonia/Views/Pages/LogPages/BaseLogPage.axaml new file mode 100644 index 0000000..332aaa7 --- /dev/null +++ b/src/UniGetUI.Avalonia/Views/Pages/LogPages/BaseLogPage.axaml @@ -0,0 +1,66 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/UniGetUI.Avalonia/Views/Pages/LogPages/BaseLogPage.axaml.cs b/src/UniGetUI.Avalonia/Views/Pages/LogPages/BaseLogPage.axaml.cs new file mode 100644 index 0000000..88147ac --- /dev/null +++ b/src/UniGetUI.Avalonia/Views/Pages/LogPages/BaseLogPage.axaml.cs @@ -0,0 +1,88 @@ +using System.Collections.Specialized; +using Avalonia.Controls; +using Avalonia.Input.Platform; +using Avalonia.Platform.Storage; +using Avalonia.Threading; +using UniGetUI.Avalonia.ViewModels.Pages.LogPages; +using UniGetUI.Core.Tools; + +namespace UniGetUI.Avalonia.Views.Pages.LogPages; + +public partial class BaseLogPage : UserControl, IEnterLeaveListener, IKeyboardShortcutListener +{ + protected readonly BaseLogPageViewModel ViewModel; + private bool _rebuildQueued; + + protected BaseLogPage(BaseLogPageViewModel viewModel) + { + ViewModel = viewModel; + DataContext = ViewModel; + InitializeComponent(); + + ViewModel.CopyTextRequested += OnCopyTextRequested; + ViewModel.ExportTextRequested += OnExportTextRequested; + ViewModel.ScrollToBottomRequested += OnScrollToBottomRequested; + ViewModel.LogLines.CollectionChanged += OnLogLinesChanged; + + // Line brushes are baked per theme at load time; reload so they follow a live theme switch. + ActualThemeVariantChanged += (_, _) => ViewModel.LoadLog(); + + LogEditor.SetLines(ViewModel.LogLines); + } + + // LoadLog clears and re-adds the lines one by one, firing many events; coalesce them into a + // single rebuild on the next dispatcher pass instead of rebuilding the document each time. + private void OnLogLinesChanged(object? sender, NotifyCollectionChangedEventArgs e) + { + if (_rebuildQueued) return; + _rebuildQueued = true; + Dispatcher.UIThread.Post(() => + { + _rebuildQueued = false; + LogEditor.SetLines(ViewModel.LogLines); + }, DispatcherPriority.Background); + } + + private async void OnCopyTextRequested(object? sender, string text) + { + var clipboard = TopLevel.GetTopLevel(this)?.Clipboard; + if (clipboard is not null) + await clipboard.SetTextAsync(text); + } + + private async void OnExportTextRequested(object? sender, string text) + { + var topLevel = TopLevel.GetTopLevel(this); + if (topLevel is null) return; + + var file = await topLevel.StorageProvider.SaveFilePickerAsync(new FilePickerSaveOptions + { + Title = CoreTools.Translate("Export log"), + SuggestedFileName = CoreTools.Translate("UniGetUI Log"), + FileTypeChoices = + [ + new FilePickerFileType(CoreTools.Translate("Text")) { Patterns = ["*.txt"] }, + ], + }); + + if (file is not null) + await File.WriteAllTextAsync(file.Path.LocalPath, text); + } + + private void OnScrollToBottomRequested(object? sender, EventArgs e) + { + Dispatcher.UIThread.Post(LogEditor.ScrollToBottom, DispatcherPriority.Background); + } + + public void OnEnter() => ViewModel.LoadLog(); + + public void OnLeave() => ViewModel.ClearLog(); + + public void ReloadTriggered() => ViewModel.LoadLog(isReload: true); + + public void SelectAllTriggered() => LogEditor.SelectAll(); + + public void SearchTriggered() { } + + public void DetailsTriggered() { } +} diff --git a/src/UniGetUI.Avalonia/Views/Pages/LogPages/ManagerLogsPage.cs b/src/UniGetUI.Avalonia/Views/Pages/LogPages/ManagerLogsPage.cs new file mode 100644 index 0000000..60a465f --- /dev/null +++ b/src/UniGetUI.Avalonia/Views/Pages/LogPages/ManagerLogsPage.cs @@ -0,0 +1,18 @@ +using UniGetUI.Avalonia.ViewModels.Pages.LogPages; +using UniGetUI.PackageEngine.Interfaces; + +namespace UniGetUI.Avalonia.Views.Pages; + +public class ManagerLogsPage : LogPages.BaseLogPage +{ + private readonly ManagerLogsPageViewModel _viewModel; + + public ManagerLogsPage() : this(new ManagerLogsPageViewModel()) { } + + private ManagerLogsPage(ManagerLogsPageViewModel vm) : base(vm) + { + _viewModel = vm; + } + + public void LoadForManager(IPackageManager manager) => _viewModel.LoadForManager(manager); +} diff --git a/src/UniGetUI.Avalonia/Views/Pages/LogPages/OperationHistoryPage.cs b/src/UniGetUI.Avalonia/Views/Pages/LogPages/OperationHistoryPage.cs new file mode 100644 index 0000000..2abfbd6 --- /dev/null +++ b/src/UniGetUI.Avalonia/Views/Pages/LogPages/OperationHistoryPage.cs @@ -0,0 +1,8 @@ +using UniGetUI.Avalonia.ViewModels.Pages.LogPages; + +namespace UniGetUI.Avalonia.Views.Pages; + +public class OperationHistoryPage : LogPages.BaseLogPage +{ + public OperationHistoryPage() : base(new OperationHistoryPageViewModel()) { } +} diff --git a/src/UniGetUI.Avalonia/Views/Pages/LogPages/UniGetUILogPage.cs b/src/UniGetUI.Avalonia/Views/Pages/LogPages/UniGetUILogPage.cs new file mode 100644 index 0000000..6492e78 --- /dev/null +++ b/src/UniGetUI.Avalonia/Views/Pages/LogPages/UniGetUILogPage.cs @@ -0,0 +1,8 @@ +using UniGetUI.Avalonia.ViewModels.Pages.LogPages; + +namespace UniGetUI.Avalonia.Views.Pages; + +public class UniGetUILogPage : LogPages.BaseLogPage +{ + public UniGetUILogPage() : base(new UniGetUILogPageViewModel()) { } +} diff --git a/src/UniGetUI.Avalonia/Views/Pages/ReleaseNotesPage.axaml b/src/UniGetUI.Avalonia/Views/Pages/ReleaseNotesPage.axaml new file mode 100644 index 0000000..55b8032 --- /dev/null +++ b/src/UniGetUI.Avalonia/Views/Pages/ReleaseNotesPage.axaml @@ -0,0 +1,63 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/UniGetUI.Avalonia/Views/Pages/ReleaseNotesPage.axaml.cs b/src/UniGetUI.Avalonia/Views/Pages/ReleaseNotesPage.axaml.cs new file mode 100644 index 0000000..a0b5e5e --- /dev/null +++ b/src/UniGetUI.Avalonia/Views/Pages/ReleaseNotesPage.axaml.cs @@ -0,0 +1,55 @@ +using Avalonia.Controls; +using UniGetUI.Avalonia.ViewModels.Pages; + +namespace UniGetUI.Avalonia.Views.Pages; + +public partial class ReleaseNotesPage : UserControl, IEnterLeaveListener +{ + private readonly ReleaseNotesPageViewModel _viewModel; + private bool _loaded; + private bool _adapterReady; + + public ReleaseNotesPage() + { + _viewModel = new ReleaseNotesPageViewModel(); + DataContext = _viewModel; + InitializeComponent(); + + if (OperatingSystem.IsLinux()) + { + WebViewBorder.IsVisible = false; + LinuxFallbackPanel.IsVisible = true; + return; + } + + WebViewControl.NavigationStarted += (_, _) => + NavProgressBar.IsVisible = true; + + WebViewControl.NavigationCompleted += (_, e) => + { + NavProgressBar.IsVisible = false; + _viewModel.CurrentUrl = WebViewControl.Source?.ToString() ?? _viewModel.ReleaseNotesUrl; + }; + + WebViewControl.AdapterCreated += (_, _) => + { + _adapterReady = true; + if (!_loaded) + { + WebViewControl.Navigate(new Uri(_viewModel.ReleaseNotesUrl)); + _loaded = true; + } + }; + } + + public void OnEnter() + { + if (!_loaded && _adapterReady) + { + WebViewControl.Navigate(new Uri(_viewModel.ReleaseNotesUrl)); + _loaded = true; + } + } + + public void OnLeave() { } +} diff --git a/src/UniGetUI.Avalonia/Views/Pages/SettingsPages/Administrator.axaml b/src/UniGetUI.Avalonia/Views/Pages/SettingsPages/Administrator.axaml new file mode 100644 index 0000000..949aa71 --- /dev/null +++ b/src/UniGetUI.Avalonia/Views/Pages/SettingsPages/Administrator.axaml @@ -0,0 +1,137 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/UniGetUI.Avalonia/Views/Pages/SettingsPages/Administrator.axaml.cs b/src/UniGetUI.Avalonia/Views/Pages/SettingsPages/Administrator.axaml.cs new file mode 100644 index 0000000..cf4a25f --- /dev/null +++ b/src/UniGetUI.Avalonia/Views/Pages/SettingsPages/Administrator.axaml.cs @@ -0,0 +1,23 @@ +using Avalonia.Controls; +using UniGetUI.Avalonia.ViewModels.Pages.SettingsPages; +using UniGetUI.Core.Tools; + +namespace UniGetUI.Avalonia.Views.Pages.SettingsPages; + +public sealed partial class Administrator : UserControl, ISettingsPage +{ + private AdministratorViewModel VM => (AdministratorViewModel)DataContext!; + + public bool CanGoBack => true; + public string ShortTitle => CoreTools.Translate("Administrator rights and other dangerous settings"); + + public event EventHandler? RestartRequired; + public event EventHandler? NavigationRequested { add { } remove { } } + + public Administrator() + { + DataContext = new AdministratorViewModel(); + InitializeComponent(); + VM.RestartRequired += (s, e) => RestartRequired?.Invoke(s, e); + } +} diff --git a/src/UniGetUI.Avalonia/Views/Pages/SettingsPages/Backup.axaml b/src/UniGetUI.Avalonia/Views/Pages/SettingsPages/Backup.axaml new file mode 100644 index 0000000..a55bd83 --- /dev/null +++ b/src/UniGetUI.Avalonia/Views/Pages/SettingsPages/Backup.axaml @@ -0,0 +1,191 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/UniGetUI.Avalonia/Views/Pages/SettingsPages/Backup.axaml.cs b/src/UniGetUI.Avalonia/Views/Pages/SettingsPages/Backup.axaml.cs new file mode 100644 index 0000000..e6e9a39 --- /dev/null +++ b/src/UniGetUI.Avalonia/Views/Pages/SettingsPages/Backup.axaml.cs @@ -0,0 +1,33 @@ +using Avalonia.Controls; +using UniGetUI.Avalonia.ViewModels.Pages.SettingsPages; +using UniGetUI.Core.Tools; + +namespace UniGetUI.Avalonia.Views.Pages.SettingsPages; + +public sealed partial class Backup : UserControl, ISettingsPage, IDisposable +{ + private readonly BackupViewModel _viewModel; + + public bool CanGoBack => true; + public string ShortTitle => CoreTools.Translate("Backup and Restore"); + + public event EventHandler? RestartRequired; + public event EventHandler? NavigationRequested { add { } remove { } } + + public Backup() + { + _viewModel = new BackupViewModel(); + DataContext = _viewModel; + InitializeComponent(); + + _viewModel.RestartRequired += OnRestartRequired; + } + + private void OnRestartRequired(object? sender, EventArgs e) => RestartRequired?.Invoke(sender, e); + + public void Dispose() + { + _viewModel.RestartRequired -= OnRestartRequired; + _viewModel.Dispose(); + } +} diff --git a/src/UniGetUI.Avalonia/Views/Pages/SettingsPages/Experimental.axaml b/src/UniGetUI.Avalonia/Views/Pages/SettingsPages/Experimental.axaml new file mode 100644 index 0000000..7726bfc --- /dev/null +++ b/src/UniGetUI.Avalonia/Views/Pages/SettingsPages/Experimental.axaml @@ -0,0 +1,79 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/UniGetUI.Avalonia/Views/Pages/SettingsPages/Experimental.axaml.cs b/src/UniGetUI.Avalonia/Views/Pages/SettingsPages/Experimental.axaml.cs new file mode 100644 index 0000000..78dfa76 --- /dev/null +++ b/src/UniGetUI.Avalonia/Views/Pages/SettingsPages/Experimental.axaml.cs @@ -0,0 +1,26 @@ +using Avalonia.Controls; +using UniGetUI.Avalonia.ViewModels.Pages.SettingsPages; +using UniGetUI.Core.Tools; + +namespace UniGetUI.Avalonia.Views.Pages.SettingsPages; + +public sealed partial class Experimental : UserControl, ISettingsPage +{ + public bool CanGoBack => true; + public string ShortTitle => CoreTools.Translate("Experimental settings and developer options"); + + public event EventHandler? RestartRequired; + public event EventHandler? NavigationRequested { add { } remove { } } + + public Experimental() + { + DataContext = new ExperimentalViewModel(); + InitializeComponent(); + + var vm = (ExperimentalViewModel)DataContext; + vm.RestartRequired += (s, e) => RestartRequired?.Invoke(s, e); + + ShowVersionNumberOnTitlebar.Text = CoreTools.Translate("Show UniGetUI's version and build number on the titlebar."); + IconDatabaseURLCard.HelpUrl = new Uri("https://github.com/Devolutions/UniGetUI"); + } +} diff --git a/src/UniGetUI.Avalonia/Views/Pages/SettingsPages/General.axaml b/src/UniGetUI.Avalonia/Views/Pages/SettingsPages/General.axaml new file mode 100644 index 0000000..403a2db --- /dev/null +++ b/src/UniGetUI.Avalonia/Views/Pages/SettingsPages/General.axaml @@ -0,0 +1,112 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/UniGetUI.Avalonia/Views/Pages/SettingsPages/General.axaml.cs b/src/UniGetUI.Avalonia/Views/Pages/SettingsPages/General.axaml.cs new file mode 100644 index 0000000..5fa669e --- /dev/null +++ b/src/UniGetUI.Avalonia/Views/Pages/SettingsPages/General.axaml.cs @@ -0,0 +1,78 @@ +using Avalonia; +using Avalonia.Controls; +using Avalonia.Input; +using Avalonia.Layout; +using Avalonia.Media; +using UniGetUI.Avalonia.ViewModels.Pages.SettingsPages; +using UniGetUI.Core.Language; +using UniGetUI.Core.Tools; +using CoreSettings = global::UniGetUI.Core.SettingsEngine.Settings; + +namespace UniGetUI.Avalonia.Views.Pages.SettingsPages; + +public sealed partial class General : UserControl, ISettingsPage +{ + public bool CanGoBack => true; + public string ShortTitle => CoreTools.Translate("General preferences"); + + public event EventHandler? RestartRequired; + public event EventHandler? NavigationRequested; + + public General() + { + DataContext = new GeneralViewModel(); + InitializeComponent(); + + var vm = (GeneralViewModel)DataContext; + vm.RestartRequired += (s, e) => RestartRequired?.Invoke(s, e); + vm.NavigationRequested += (s, t) => NavigationRequested?.Invoke(s, t); + + // Populate language selector (complex dynamic content) + var langDict = new Dictionary(LanguageData.LanguageReference.AsEnumerable()); + foreach (string key in langDict.Keys.ToList()) + { + if (key != "en" && LanguageData.TranslationPercentages.TryGetValue(key, out var pct)) + langDict[key] = langDict[key] + " (" + pct + ")"; + } + // The "System language" entry is shown in the OS language (the language it actually + // resolves to), not in the currently-selected app language. AutoTranslated keeps the + // string discoverable by the translation tooling. + string systemLanguageLabel = CoreTools.TranslateInSystemLanguage(CoreTools.AutoTranslated("System language")); + foreach (var entry in langDict) + LanguageSelector.AddItem( + entry.Key == "default" ? systemLanguageLabel : entry.Value, + entry.Key, false); + LanguageSelector.SettingName = CoreSettings.K.PreferredLanguage; + LanguageSelector.Text = CoreTools.Translate("UniGetUI display language:"); + LanguageSelector.ShowAddedItems(); + LanguageSelector.ValueChanged += (s, e) => RestartRequired?.Invoke(s, e); + LanguageSelector.Description = BuildTranslatorDescription(); + } + + private static StackPanel BuildTranslatorDescription() + { + var label = new TextBlock + { + Text = CoreTools.Translate("Is your language missing or incomplete?"), + VerticalAlignment = VerticalAlignment.Center, + Opacity = 0.8, + }; + + var link = new TextBlock + { + Text = CoreTools.Translate("Become a translator"), + TextDecorations = TextDecorations.Underline, + VerticalAlignment = VerticalAlignment.Center, + Cursor = new Cursor(StandardCursorType.Hand), + Margin = new Thickness(4, 0, 0, 0), + }; + link.Bind(TextBlock.ForegroundProperty, link.GetResourceObservable("SystemControlHighlightAccentBrush")); + link.PointerPressed += (_, _) => + CoreTools.Launch("https://github.com/Devolutions/UniGetUI/wiki#translating-wingetui"); + + var panel = new StackPanel { Orientation = Orientation.Horizontal }; + panel.Children.Add(label); + panel.Children.Add(link); + return panel; + } +} diff --git a/src/UniGetUI.Avalonia/Views/Pages/SettingsPages/ISettingsPage.cs b/src/UniGetUI.Avalonia/Views/Pages/SettingsPages/ISettingsPage.cs new file mode 100644 index 0000000..53c0b21 --- /dev/null +++ b/src/UniGetUI.Avalonia/Views/Pages/SettingsPages/ISettingsPage.cs @@ -0,0 +1,10 @@ +namespace UniGetUI.Avalonia.Views.Pages.SettingsPages; + +public interface ISettingsPage +{ + bool CanGoBack { get; } + string ShortTitle { get; } + + event EventHandler? RestartRequired; + event EventHandler? NavigationRequested; +} diff --git a/src/UniGetUI.Avalonia/Views/Pages/SettingsPages/InstallOptionsPanel.axaml b/src/UniGetUI.Avalonia/Views/Pages/SettingsPages/InstallOptionsPanel.axaml new file mode 100644 index 0000000..d6a25ad --- /dev/null +++ b/src/UniGetUI.Avalonia/Views/Pages/SettingsPages/InstallOptionsPanel.axaml @@ -0,0 +1,232 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/UniGetUI.Avalonia/Views/Pages/SettingsPages/InstallOptionsPanel.axaml.cs b/src/UniGetUI.Avalonia/Views/Pages/SettingsPages/InstallOptionsPanel.axaml.cs new file mode 100644 index 0000000..fa233cb --- /dev/null +++ b/src/UniGetUI.Avalonia/Views/Pages/SettingsPages/InstallOptionsPanel.axaml.cs @@ -0,0 +1,41 @@ +using Avalonia.Controls; +using UniGetUI.Avalonia.ViewModels.Pages.SettingsPages; +using UniGetUI.PackageEngine.Interfaces; + +namespace UniGetUI.Avalonia.Views.Pages.SettingsPages; + +public sealed partial class InstallOptionsPanel : UserControl +{ + private InstallOptionsPanelViewModel ViewModel => (InstallOptionsPanelViewModel)DataContext!; + + public event EventHandler? NavigateToAdministratorRequested; + + public InstallOptionsPanel(IPackageManager manager) + { + DataContext = new InstallOptionsPanelViewModel(manager); + InitializeComponent(); + + ViewModel.NavigateToAdministratorRequested += (s, e) => + NavigateToAdministratorRequested?.Invoke(s, e); + + ViewModel.PropertyChanged += (_, e) => + { + if (e.PropertyName == nameof(InstallOptionsPanelViewModel.HasChanges)) + { + if (ViewModel.HasChanges) + ApplyButton.Classes.Add("accent"); + else + ApplyButton.Classes.Remove("accent"); + } + }; + + // Wire location picker (needs Visual reference for StorageProvider) + SelectDirButton.Click += (_, _) => + _ = ViewModel.SelectLocationCommand.ExecuteAsync(this); + + // Mark changed whenever the user edits a CLI textbox + CustomInstallBox.TextChanged += (_, _) => ViewModel.MarkChanged(); + CustomUpdateBox.TextChanged += (_, _) => ViewModel.MarkChanged(); + CustomUninstallBox.TextChanged += (_, _) => ViewModel.MarkChanged(); + } +} diff --git a/src/UniGetUI.Avalonia/Views/Pages/SettingsPages/Interface_P.axaml b/src/UniGetUI.Avalonia/Views/Pages/SettingsPages/Interface_P.axaml new file mode 100644 index 0000000..f7a2463 --- /dev/null +++ b/src/UniGetUI.Avalonia/Views/Pages/SettingsPages/Interface_P.axaml @@ -0,0 +1,101 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/UniGetUI.Avalonia/Views/Pages/SettingsPages/Interface_P.axaml.cs b/src/UniGetUI.Avalonia/Views/Pages/SettingsPages/Interface_P.axaml.cs new file mode 100644 index 0000000..be730f1 --- /dev/null +++ b/src/UniGetUI.Avalonia/Views/Pages/SettingsPages/Interface_P.axaml.cs @@ -0,0 +1,55 @@ +using Avalonia.Controls; +using UniGetUI.Avalonia.ViewModels.Pages.SettingsPages; +using UniGetUI.Core.Tools; +using CoreSettings = global::UniGetUI.Core.SettingsEngine.Settings; + +namespace UniGetUI.Avalonia.Views.Pages.SettingsPages; + +public sealed partial class Interface_P : UserControl, ISettingsPage +{ + private Interface_PViewModel VM => (Interface_PViewModel)DataContext!; + + public bool CanGoBack => true; + public string ShortTitle => CoreTools.Translate("User interface preferences"); + + public event EventHandler? RestartRequired; + public event EventHandler? NavigationRequested { add { } remove { } } + + public Interface_P() + { + DataContext = new Interface_PViewModel(); + InitializeComponent(); + + VM.RestartRequired += (s, e) => RestartRequired?.Invoke(s, e); + _ = VM.LoadIconCacheSize(); + + if (CoreSettings.GetValue(CoreSettings.K.PreferredTheme) == "") + CoreSettings.SetValue(CoreSettings.K.PreferredTheme, "auto"); + + ThemeSelector.AddItem(CoreTools.Translate("Light"), "light"); + ThemeSelector.AddItem(CoreTools.Translate("Dark"), "dark"); + ThemeSelector.AddItem(CoreTools.Translate("Follow system color scheme"), "auto"); + ThemeSelector.SettingName = CoreSettings.K.PreferredTheme; + ThemeSelector.Text = CoreTools.Translate("Application theme:"); + ThemeSelector.ShowAddedItems(); + ThemeSelector.ValueChanged += (_, _) => App.ApplyTheme(CoreSettings.GetValue(CoreSettings.K.PreferredTheme)); + + StartupPageSelector.AddItem(CoreTools.Translate("Default"), "default"); + StartupPageSelector.AddItem(CoreTools.Translate("Discover Packages"), "discover"); + StartupPageSelector.AddItem(CoreTools.Translate("Software Updates"), "updates"); + StartupPageSelector.AddItem(CoreTools.Translate("Installed Packages"), "installed"); + StartupPageSelector.AddItem(CoreTools.Translate("Package Bundles"), "bundles"); + StartupPageSelector.AddItem(CoreTools.Translate("Settings"), "settings"); + StartupPageSelector.SettingName = CoreSettings.K.StartupPage; + StartupPageSelector.Text = CoreTools.Translate("UniGetUI startup page:"); + StartupPageSelector.ShowAddedItems(); + + NavMenuModeSelector.AddItem(CoreTools.Translate("Automatic"), "auto"); + NavMenuModeSelector.AddItem(CoreTools.Translate("Docked open"), "docked"); + NavMenuModeSelector.AddItem(CoreTools.Translate("Sliding overlay"), "overlay"); + NavMenuModeSelector.SettingName = CoreSettings.K.NavMenuMode; + NavMenuModeSelector.Text = CoreTools.Translate("Navigation menu:"); + NavMenuModeSelector.ShowAddedItems(); + NavMenuModeSelector.ValueChanged += (_, _) => MainWindow.Instance?.RefreshNavigationMode(); + } +} diff --git a/src/UniGetUI.Avalonia/Views/Pages/SettingsPages/Internet.axaml b/src/UniGetUI.Avalonia/Views/Pages/SettingsPages/Internet.axaml new file mode 100644 index 0000000..7cf8d54 --- /dev/null +++ b/src/UniGetUI.Avalonia/Views/Pages/SettingsPages/Internet.axaml @@ -0,0 +1,64 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/UniGetUI.Avalonia/Views/Pages/SettingsPages/Internet.axaml.cs b/src/UniGetUI.Avalonia/Views/Pages/SettingsPages/Internet.axaml.cs new file mode 100644 index 0000000..aa473fb --- /dev/null +++ b/src/UniGetUI.Avalonia/Views/Pages/SettingsPages/Internet.axaml.cs @@ -0,0 +1,33 @@ +using Avalonia; +using Avalonia.Controls; +using Avalonia.Layout; +using Avalonia.Media; +using UniGetUI.Avalonia.ViewModels.Pages.SettingsPages; +using UniGetUI.Avalonia.Views.Controls.Settings; +using UniGetUI.Core.Tools; +using UniGetUI.PackageEngine; +using UniGetUI.PackageEngine.ManagerClasses.Manager; +using CoreSettings = global::UniGetUI.Core.SettingsEngine.Settings; + +namespace UniGetUI.Avalonia.Views.Pages.SettingsPages; + +public sealed partial class Internet : UserControl, ISettingsPage +{ + public bool CanGoBack => true; + public string ShortTitle => CoreTools.Translate("Internet and proxy settings"); + + public event EventHandler? RestartRequired; + public event EventHandler? NavigationRequested { add { } remove { } } + + public Internet() + { + DataContext = new InternetViewModel(); + InitializeComponent(); + + var vm = (InternetViewModel)DataContext; + vm.RestartRequired += (s, e) => RestartRequired?.Invoke(s, e); + + CredentialsHolder.Content = vm.BuildCredentialsCard(); + ProxyCompatTableHolder.Content = vm.BuildProxyCompatTable(); + } +} diff --git a/src/UniGetUI.Avalonia/Views/Pages/SettingsPages/ManagersHomepage.axaml b/src/UniGetUI.Avalonia/Views/Pages/SettingsPages/ManagersHomepage.axaml new file mode 100644 index 0000000..328fca3 --- /dev/null +++ b/src/UniGetUI.Avalonia/Views/Pages/SettingsPages/ManagersHomepage.axaml @@ -0,0 +1,17 @@ + + + + + + + diff --git a/src/UniGetUI.Avalonia/Views/Pages/SettingsPages/ManagersHomepage.axaml.cs b/src/UniGetUI.Avalonia/Views/Pages/SettingsPages/ManagersHomepage.axaml.cs new file mode 100644 index 0000000..5e903b8 --- /dev/null +++ b/src/UniGetUI.Avalonia/Views/Pages/SettingsPages/ManagersHomepage.axaml.cs @@ -0,0 +1,162 @@ +using Avalonia; +using Avalonia.Automation; +using Avalonia.Controls; +using Avalonia.Layout; +using Avalonia.Media; +using UniGetUI.Avalonia.Infrastructure; +using UniGetUI.Avalonia.ViewModels.Pages.SettingsPages; +using UniGetUI.Avalonia.Views.Controls.Settings; +using UniGetUI.Core.Tools; +using UniGetUI.PackageEngine; +using UniGetUI.PackageEngine.Interfaces; +using CoreSettings = UniGetUI.Core.SettingsEngine.Settings; + +namespace UniGetUI.Avalonia.Views.Pages.SettingsPages; + +public sealed partial class ManagersHomepage : UserControl, ISettingsPage +{ + public bool CanGoBack => false; + public string ShortTitle => CoreTools.Translate("Package manager preferences"); + + public event EventHandler? RestartRequired { add { } remove { } } + public event EventHandler? NavigationRequested { add { } remove { } } + public event EventHandler? ManagerNavigationRequested; + + private readonly List<(ToggleSwitch Toggle, IPackageManager Manager, Border Badge, TextBlock BadgeText)> _rows = []; + private bool _isLoadingToggles; + + public ManagersHomepage() + { + DataContext = new ManagersHomepageViewModel(); + InitializeComponent(); + + int count = PEInterface.Managers.Length; + for (int i = 0; i < count; i++) + { + var manager = PEInterface.Managers[i]; + bool isFirst = i == 0; + bool isLast = i == count - 1; + + CornerRadius radius = isFirst && isLast ? new CornerRadius(8) + : isFirst ? new CornerRadius(8, 8, 0, 0) + : isLast ? new CornerRadius(0, 0, 8, 8) + : new CornerRadius(0); + var thickness = isFirst ? new Thickness(1) : new Thickness(1, 0, 1, 1); + + // ── Status badge (decorative — status surfaced via toggle HelpText) ─ + var badgeText = new TextBlock + { + FontSize = 12, + FontWeight = FontWeight.SemiBold, + VerticalAlignment = VerticalAlignment.Center, + }; + AutomationProperties.SetAccessibilityView(badgeText, AccessibilityView.Raw); + var badge = new Border + { + CornerRadius = new CornerRadius(4), + Padding = new Thickness(6, 3, 6, 3), + Child = badgeText, + }; + AutomationProperties.SetAccessibilityView(badge, AccessibilityView.Raw); + + // ── Enable/disable toggle ──────────────────────────────────────── + var toggle = new ToggleSwitch + { + OnContent = "", + OffContent = "", + VerticalAlignment = VerticalAlignment.Center, + }; + AutomationProperties.SetName(toggle, manager.DisplayName); + toggle.Loaded += (_, _) => + { + _isLoadingToggles = true; + toggle.IsChecked = manager.IsEnabled(); + _isLoadingToggles = false; + ApplyStatusBadge(manager, toggle, badge, badgeText); + }; + toggle.IsCheckedChanged += async (_, _) => + { + if (_isLoadingToggles) return; + CoreSettings.SetDictionaryItem(CoreSettings.K.DisabledManagers, manager.Name, toggle.IsChecked != true); + await Task.Run(manager.Initialize); + ApplyStatusBadge(manager, toggle, badge, badgeText); + AccessibilityAnnouncementService.AnnounceToggle(manager.DisplayName, toggle.IsChecked == true); + }; + + var toggleAndBadge = new StackPanel + { + Orientation = Orientation.Vertical, + Spacing = 4, + VerticalAlignment = VerticalAlignment.Center, + }; + toggleAndBadge.Children.Add(toggle); + toggleAndBadge.Children.Add(badge); + + var rightContent = toggleAndBadge; + + var btn = new SettingsPageButton + { + Text = manager.DisplayName, + UnderText = manager.Properties.Description.Split("
")[0], + Icon = manager.Properties.IconId, + CornerRadius = radius, + BorderThickness = thickness, + Content = rightContent, + }; + + var capturedManager = manager; + btn.Click += (_, _) => ManagerNavigationRequested?.Invoke(this, capturedManager); + + ManagersPanel.Children.Add(btn); + _rows.Add((toggle, manager, badge, badgeText)); + } + } + + /// Re-sync toggle states after returning from a sub-page. + public void RefreshToggles() + { + _isLoadingToggles = true; + foreach (var (toggle, manager, badge, badgeText) in _rows) + { + toggle.IsChecked = manager.IsEnabled(); + ApplyStatusBadge(manager, toggle, badge, badgeText); + } + _isLoadingToggles = false; + } + + private void ApplyStatusBadge(IPackageManager manager, ToggleSwitch toggle, Border badge, TextBlock text) + { + string bgKey, fgKey, label; + if (!manager.IsEnabled()) + { + bgKey = "WarningBannerBackground"; + fgKey = "StatusWarningForeground"; + label = CoreTools.Translate("Disabled"); + } + else if (manager.Status.Found) + { + bgKey = "StatusSuccessBackground"; + fgKey = "StatusSuccessForeground"; + label = CoreTools.Translate("Ready"); + } + else + { + bgKey = "StatusErrorBackground"; + fgKey = "StatusErrorForeground"; + label = CoreTools.Translate("Not found"); + } + badge.Background = LookupBrush(bgKey); + text.Foreground = LookupBrush(fgKey); + text.Text = label; + // Bake state into Name so VoiceOver always announces it on macOS + AutomationProperties.SetName(toggle, $"{manager.DisplayName}, {label}"); + AutomationProperties.SetItemStatus(toggle, label); + } + + private IBrush LookupBrush(string key) + { + if (this.TryFindResource(key, ActualThemeVariant, out var res) && res is IBrush brush) + return brush; + return Brushes.Transparent; + } +} diff --git a/src/UniGetUI.Avalonia/Views/Pages/SettingsPages/Notifications.axaml b/src/UniGetUI.Avalonia/Views/Pages/SettingsPages/Notifications.axaml new file mode 100644 index 0000000..86d7528 --- /dev/null +++ b/src/UniGetUI.Avalonia/Views/Pages/SettingsPages/Notifications.axaml @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/UniGetUI.Avalonia/Views/Pages/SettingsPages/Notifications.axaml.cs b/src/UniGetUI.Avalonia/Views/Pages/SettingsPages/Notifications.axaml.cs new file mode 100644 index 0000000..6ea544f --- /dev/null +++ b/src/UniGetUI.Avalonia/Views/Pages/SettingsPages/Notifications.axaml.cs @@ -0,0 +1,20 @@ +using Avalonia.Controls; +using UniGetUI.Avalonia.ViewModels.Pages.SettingsPages; +using UniGetUI.Core.Tools; + +namespace UniGetUI.Avalonia.Views.Pages.SettingsPages; + +public sealed partial class Notifications : UserControl, ISettingsPage +{ + public bool CanGoBack => true; + public string ShortTitle => CoreTools.Translate("Notification preferences"); + + public event EventHandler? RestartRequired { add { } remove { } } + public event EventHandler? NavigationRequested { add { } remove { } } + + public Notifications() + { + DataContext = new NotificationsViewModel(); + InitializeComponent(); + } +} diff --git a/src/UniGetUI.Avalonia/Views/Pages/SettingsPages/Operations.axaml b/src/UniGetUI.Avalonia/Views/Pages/SettingsPages/Operations.axaml new file mode 100644 index 0000000..fbf3376 --- /dev/null +++ b/src/UniGetUI.Avalonia/Views/Pages/SettingsPages/Operations.axaml @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/UniGetUI.Avalonia/Views/Pages/SettingsPages/Operations.axaml.cs b/src/UniGetUI.Avalonia/Views/Pages/SettingsPages/Operations.axaml.cs new file mode 100644 index 0000000..2a2fbe8 --- /dev/null +++ b/src/UniGetUI.Avalonia/Views/Pages/SettingsPages/Operations.axaml.cs @@ -0,0 +1,39 @@ +using Avalonia; +using Avalonia.Controls; +using Avalonia.Controls.ApplicationLifetimes; +using UniGetUI.Avalonia.ViewModels.Pages.SettingsPages; +using UniGetUI.Avalonia.Views; +using UniGetUI.Core.Tools; + +namespace UniGetUI.Avalonia.Views.Pages.SettingsPages; + +public sealed partial class Operations : UserControl, ISettingsPage +{ + private OperationsViewModel VM => (OperationsViewModel)DataContext!; + + public bool CanGoBack => true; + public string ShortTitle => CoreTools.Translate("Package operation preferences"); + + public event EventHandler? RestartRequired; + public event EventHandler? NavigationRequested; + + public Operations() + { + DataContext = new OperationsViewModel(); + InitializeComponent(); + + VM.RestartRequired += (s, e) => RestartRequired?.Invoke(s, e); + VM.NavigationRequested += (s, t) => NavigationRequested?.Invoke(s, t); + + foreach (var v in VM.ParallelOpCounts) + ParallelOperationCount.AddItem(v, v, false); + ParallelOperationCount.ShowAddedItems(); + + AskToDeleteNewDesktopShortcuts.Click += async (_, _) => + { + if (Application.Current?.ApplicationLifetime + is IClassicDesktopStyleApplicationLifetime { MainWindow: { } win }) + await new ManageDesktopShortcutsWindow().ShowDialog(win); + }; + } +} diff --git a/src/UniGetUI.Avalonia/Views/Pages/SettingsPages/PackageManagerPage.axaml b/src/UniGetUI.Avalonia/Views/Pages/SettingsPages/PackageManagerPage.axaml new file mode 100644 index 0000000..4a332bf --- /dev/null +++ b/src/UniGetUI.Avalonia/Views/Pages/SettingsPages/PackageManagerPage.axaml @@ -0,0 +1,130 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/UniGetUI.Avalonia/Views/Pages/SettingsPages/PackageManagerPage.axaml.cs b/src/UniGetUI.Avalonia/Views/Pages/SettingsPages/PackageManagerPage.axaml.cs new file mode 100644 index 0000000..901592e --- /dev/null +++ b/src/UniGetUI.Avalonia/Views/Pages/SettingsPages/PackageManagerPage.axaml.cs @@ -0,0 +1,667 @@ +using Avalonia.Automation; +using Avalonia.Controls; +using Avalonia.Input.Platform; +using Avalonia.Layout; +using Avalonia.Media; +using Avalonia.Platform.Storage; +using UniGetUI.Avalonia.Infrastructure; +using UniGetUI.Avalonia.ViewModels; +using UniGetUI.Avalonia.ViewModels.Pages.SettingsPages; +using UniGetUI.Avalonia.Views.Controls; +using UniGetUI.Avalonia.Views.Controls.Settings; +using UniGetUI.Core.SettingsEngine.SecureSettings; +using UniGetUI.Core.Tools; +using UniGetUI.Interface.Enums; +using UniGetUI.PackageEngine.Interfaces; +using UniGetUI.PackageEngine.ManagerClasses.Manager; +using UniGetUI.PackageEngine.Managers.VcpkgManager; +using CoreSettings = UniGetUI.Core.SettingsEngine.Settings; +using CornerRadius = global::Avalonia.CornerRadius; +using Thickness = global::Avalonia.Thickness; + +namespace UniGetUI.Avalonia.Views.Pages.SettingsPages; + +public sealed partial class PackageManagerPage : UserControl, ISettingsPage +{ + private PackageManagerViewModel ViewModel => (PackageManagerViewModel)DataContext!; + + public bool CanGoBack => true; + public string ShortTitle => ViewModel.PageTitle; + + public event EventHandler? RestartRequired; + public event EventHandler? NavigationRequested; + + public PackageManagerPage(IPackageManager manager) + { + DataContext = new PackageManagerViewModel(manager); + InitializeComponent(); + + ViewModel.PropertyChanged += (_, e) => + { + if (e.PropertyName is nameof(PackageManagerViewModel.Severity) + or nameof(PackageManagerViewModel.StatusTitle) + or nameof(PackageManagerViewModel.StatusMessage)) + ApplyStatusBrushes(); + }; + + ViewModel.RestartRequired += (s, e) => RestartRequired?.Invoke(s, e); + ViewModel.NavigateToAdministratorRequested += (_, _) => NavigationRequested?.Invoke(this, typeof(Administrator)); + + BuildPage(); + ApplyStatusBrushes(); + } + + // ── Dynamic UI construction ─────────────────────────────────────────────── + + private void BuildPage() + { + var manager = ViewModel.Manager; + + // ── Enable/Disable toggle + EnableManager.DictionaryName = CoreSettings.K.DisabledManagers; + EnableManager.KeyName = manager.Name; + EnableManager.Text = CoreTools.Translate("Enable {pm}").Replace("{pm}", manager.DisplayName); + ExtraControls.IsEnabled = manager.IsEnabled(); + EnableManager.StateChanged += (_, _) => + { + ExtraControls.IsEnabled = manager.IsEnabled(); + _ = ViewModel.ReloadManagerCommand.ExecuteAsync(null); + }; + + // ── Executable picker card + bool customPathsAllowed = SecureSettings.Get(SecureSettings.K.AllowCustomManagerPaths); + var execGrid = new Grid + { + ColumnDefinitions = new ColumnDefinitions("*,Auto"), + RowDefinitions = new RowDefinitions("Auto,Auto,Auto"), + HorizontalAlignment = HorizontalAlignment.Stretch, + }; + + var execHint = new TextBlock + { + Text = CoreTools.Translate("Not finding the file you are looking for? Browse to it or make sure it has been added to PATH."), + FontSize = 12, + FontWeight = FontWeight.SemiBold, + Opacity = 0.7, + TextWrapping = TextWrapping.Wrap, + }; + Grid.SetColumnSpan(execHint, 2); + execGrid.Children.Add(execHint); + + var execCombo = new ComboBox { HorizontalAlignment = HorizontalAlignment.Stretch }; + AutomationProperties.SetName(execCombo, CoreTools.Translate("Select the executable to be used. The following list shows the executables found by UniGetUI")); + foreach (var path in manager.FindCandidateExecutableFiles()) + AddExecutablePathItem(execCombo, path); + + string savedPath = CoreSettings.GetDictionaryItem(CoreSettings.K.ManagerPaths, manager.Name) ?? ""; + if (!string.IsNullOrEmpty(savedPath) && File.Exists(savedPath)) + AddExecutablePathItem(execCombo, savedPath); + if (string.IsNullOrEmpty(savedPath)) + { + var (found, path) = manager.GetExecutableFile(); + savedPath = found ? path : ""; + } + else if (!File.Exists(savedPath)) + { + var (found, path) = manager.GetExecutableFile(); + savedPath = found ? path : ""; + } + execCombo.SelectedItem = savedPath; + execCombo.IsEnabled = customPathsAllowed; + execCombo.SelectionChanged += (s, _) => + { + if (s is ComboBox combo && combo.SelectedItem?.ToString() is { Length: > 0 } selected) + ViewModel.OnExecutableSelected(selected); + }; + Grid.SetRow(execCombo, 1); + Grid.SetColumn(execCombo, 0); + execGrid.Children.Add(execCombo); + + var browseExecutableButton = new Button + { + Content = CoreTools.Translate("Browse..."), + IsEnabled = customPathsAllowed, + Margin = new Thickness(8, 0, 0, 0), + }; + browseExecutableButton.Click += async (_, _) => + { + if (TopLevel.GetTopLevel(this) is not { } topLevel) return; + var files = await topLevel.StorageProvider.OpenFilePickerAsync( + new FilePickerOpenOptions + { + AllowMultiple = false, + Title = CoreTools.Translate("Select executable"), + FileTypeFilter = GetExecutableFileTypeFilter(), + }); + if (files is not [{ } file]) return; + + string? path = file.TryGetLocalPath(); + if (string.IsNullOrWhiteSpace(path)) return; + + AddExecutablePathItem(execCombo, path); + execCombo.SelectedItem = path; + }; + Grid.SetRow(browseExecutableButton, 1); + Grid.SetColumn(browseExecutableButton, 1); + execGrid.Children.Add(browseExecutableButton); + + if (!customPathsAllowed) + { + var securityWarning = new TextBlock + { + Text = CoreTools.Translate("For security reasons, changing the executable file is disabled by default"), + FontSize = 12, + FontWeight = FontWeight.SemiBold, + Opacity = 0.7, + TextWrapping = TextWrapping.Wrap, + Classes = { "setting-warning-text" }, + }; + Grid.SetRow(securityWarning, 2); + execGrid.Children.Add(securityWarning); + + var goToSecureBtn = new Button + { + Content = new TextBlock { Text = CoreTools.Translate("Change this"), FontSize = 12, Classes = { "hyperlink" } }, + Background = Brushes.Transparent, + BorderThickness = new Thickness(0), + Padding = new Thickness(0), + }; + goToSecureBtn.Click += (_, _) => ViewModel.NavigateToAdministratorCommand.Execute(null); + Grid.SetRow(goToSecureBtn, 2); + Grid.SetColumn(goToSecureBtn, 1); + execGrid.Children.Add(goToSecureBtn); + } + + ExecutableHolder.Content = new SettingsCard + { + BorderThickness = new Thickness(1, 0, 1, 0), + CornerRadius = new CornerRadius(0), + Header = CoreTools.Translate("Select the executable to be used. The following list shows the executables found by UniGetUI"), + Description = execGrid, + Margin = new Thickness(0, 2, 0, 2), + }; + + // ── Current path card + var copyIcon = new SvgIcon + { + Path = "avares://UniGetUI/Assets/Symbols/copy.svg", + Width = 24, + Height = 24, + }; + var copyBtn = new Button + { + Content = copyIcon, + Padding = new Thickness(8), + VerticalAlignment = VerticalAlignment.Center, + Background = Brushes.Transparent, + BorderThickness = new Thickness(0), + }; + AutomationProperties.SetName(copyBtn, CoreTools.Translate("Copy path")); + var pathCard = new SettingsCard + { + BorderThickness = new Thickness(1, 0, 1, 1), + CornerRadius = new CornerRadius(0, 0, 8, 8), + Header = CoreTools.Translate("Current executable file:"), + Content = copyBtn, + }; + var pathLabel = new TextBlock + { + FontFamily = new FontFamily("Consolas,Cascadia Mono,Menlo,monospace"), + FontSize = 14, + TextWrapping = TextWrapping.Wrap, + }; + pathLabel.Text = ViewModel.PathLabelText; + ViewModel.PropertyChanged += (_, e) => + { + if (e.PropertyName == nameof(PackageManagerViewModel.PathLabelText)) + pathLabel.Text = ViewModel.PathLabelText; + }; + pathCard.Description = pathLabel; + copyBtn.Click += (_, _) => _ = CopyPathAndFlashIcon(pathLabel.Text, copyBtn, copyIcon); + PathHolder.Content = pathCard; + + // ── Install options panel + var installOptions = new InstallOptionsPanel(manager); + installOptions.NavigateToAdministratorRequested += (_, _) => + NavigationRequested?.Invoke(this, typeof(Administrator)); + InstallOptionsHolder.Content = installOptions; + + // ── Disable notifications card + var disableNotifsCard = new CheckboxCard_Dict + { + Text = CoreTools.Translate("Ignore packages from {pm} when showing a notification about updates") + .Replace("{pm}", manager.DisplayName), + DictionaryName = CoreSettings.K.DisabledPackageManagerNotifications, + ForceInversion = true, + KeyName = manager.Name, + }; + + BuildExtraControls(disableNotifsCard); + + // ── Per-manager minimum update age + ExtraControls.Children.Add(new TextBlock + { + Margin = new Thickness(44, 24, 4, 8), + FontWeight = FontWeight.SemiBold, + Text = CoreTools.Translate("Update security"), + }); + + (string Label, string Value)[] ageItems = + [ + (CoreTools.Translate("Use global setting"), ""), + (CoreTools.Translate("No minimum age"), "0"), + (CoreTools.Translate("1 day"), "1"), + (CoreTools.Translate("{0} days", 3), "3"), + (CoreTools.Translate("{0} days", 7), "7"), + (CoreTools.Translate("{0} days", 14), "14"), + (CoreTools.Translate("{0} days", 30), "30"), + (CoreTools.Translate("Custom..."), "custom"), + ]; + + var ageCombo = new ComboBox { MinWidth = 200 }; + AutomationProperties.SetName(ageCombo, CoreTools.Translate("Minimum age for updates")); + foreach (var (label, _) in ageItems) + ageCombo.Items.Add(label); + + string? savedAge = CoreSettings.GetDictionaryItem( + CoreSettings.K.PerManagerMinimumUpdateAge, manager.Name); + int savedAgeIdx = Array.FindIndex(ageItems, i => i.Value == (savedAge ?? "")); + ageCombo.SelectedIndex = savedAgeIdx >= 0 ? savedAgeIdx : 0; + + var customAgeInput = new TextBox + { + MinWidth = 200, + PlaceholderText = CoreTools.Translate("e.g. 10"), + [AutomationProperties.NameProperty] = CoreTools.Translate("Custom minimum age (days)"), + Text = CoreSettings.GetDictionaryItem( + CoreSettings.K.PerManagerMinimumUpdateAgeCustom, manager.Name) ?? "", + }; + customAgeInput.TextChanged += (_, _) => + { + string current = customAgeInput.Text ?? ""; + string filtered = string.Concat(current.Where(char.IsDigit)); + if (filtered != current) + { + customAgeInput.Text = filtered; + return; + } + if (filtered.Length > 0) + CoreSettings.SetDictionaryItem( + CoreSettings.K.PerManagerMinimumUpdateAgeCustom, manager.Name, filtered); + else + CoreSettings.RemoveDictionaryKey( + CoreSettings.K.PerManagerMinimumUpdateAgeCustom, manager.Name); + }; + + bool initiallyCustom = savedAge == "custom"; + var releaseDateSupport = manager.Capabilities.KnowsPackageReleaseDate; + bool ageSupported = releaseDateSupport != PackageReleaseDateSupport.No; + object ageDescription = releaseDateSupport switch + { + PackageReleaseDateSupport.No => new TextBlock + { + Text = CoreTools.Translate("{pm} does not provide release dates for its packages, so this setting will have no effect") + .Replace("{pm}", manager.DisplayName), + Foreground = new SolidColorBrush(Color.Parse("#e05252")), + TextWrapping = TextWrapping.Wrap, + FontSize = 12, + }, + PackageReleaseDateSupport.Partial => new TextBlock + { + Text = CoreTools.Translate("{pm} only provides release dates for some of its packages, so this setting will only apply to those packages") + .Replace("{pm}", manager.DisplayName), + Foreground = new SolidColorBrush(Color.FromRgb(224, 168, 0)), + TextWrapping = TextWrapping.Wrap, + FontSize = 12, + }, + _ => CoreTools.Translate("Override the global minimum update age for this package manager"), + }; + + ageCombo.IsEnabled = ageSupported; + customAgeInput.IsEnabled = ageSupported; + + var minimumAgeCard = new SettingsCard + { + Header = CoreTools.Translate("Minimum age for updates"), + Description = ageDescription, + Content = ageCombo, + CornerRadius = initiallyCustom ? new CornerRadius(8, 8, 0, 0) : new CornerRadius(8), + BorderThickness = new Thickness(1), + }; + var customAgeCard = new SettingsCard + { + Header = CoreTools.Translate("Custom minimum age (days)"), + Content = customAgeInput, + IsVisible = initiallyCustom, + CornerRadius = new CornerRadius(0, 0, 8, 8), + BorderThickness = new Thickness(1, 0, 1, 1), + }; + + ageCombo.SelectionChanged += (_, _) => + { + int idx = ageCombo.SelectedIndex; + if (idx < 0) return; + string val = ageItems[idx].Value; + + bool isCustom = val == "custom"; + customAgeCard.IsVisible = isCustom; + minimumAgeCard.CornerRadius = isCustom ? new CornerRadius(8, 8, 0, 0) : new CornerRadius(8); + + if (string.IsNullOrEmpty(val)) + CoreSettings.RemoveDictionaryKey( + CoreSettings.K.PerManagerMinimumUpdateAge, manager.Name); + else + CoreSettings.SetDictionaryItem( + CoreSettings.K.PerManagerMinimumUpdateAge, manager.Name, val); + }; + + ExtraControls.Children.Add(minimumAgeCard); + ExtraControls.Children.Add(customAgeCard); + + // ── Logs card + ManagerLogs.Text = CoreTools.Translate("View {0} logs", manager.DisplayName); + ManagerLogs.Icon = UniGetUI.Interface.Enums.IconType.Console; + ManagerLogs.Click += (_, _) => + { + if (TopLevel.GetTopLevel(this) is Window { DataContext: MainWindowViewModel vm }) + vm.OpenManagerLogs(manager); + }; + + // ── pip AppExecution Alias warning + if (manager.Name == "Pip") + { + ManagerLogs.CornerRadius = new CornerRadius(8, 8, 0, 0); + AppExecutionAliasWarning.IsVisible = true; + AppExecutionAliasLabel.Text = CoreTools.Translate( + "If Python cannot be found or is not listing packages but is installed on the system, " + + "you may need to disable the \"python.exe\" App Execution Alias in the settings."); + } + } + + private static IReadOnlyList GetExecutableFileTypeFilter() + { + if (!OperatingSystem.IsWindows()) + { + return [new FilePickerFileType(CoreTools.Translate("All files")) { Patterns = ["*"] }]; + } + + return + [ + new FilePickerFileType(CoreTools.Translate("Executable")) { Patterns = ["*.exe"] }, + new FilePickerFileType(CoreTools.Translate("All files")) { Patterns = ["*"] }, + ]; + } + + private static void AddExecutablePathItem(ComboBox comboBox, string path) + { + if (string.IsNullOrWhiteSpace(path)) + return; + + foreach (object? item in comboBox.Items) + { + if (string.Equals(item?.ToString(), path, StringComparison.OrdinalIgnoreCase)) + return; + } + + comboBox.Items.Add(path); + } + + private void BuildExtraControls(CheckboxCard_Dict disableNotifsCard) + { + ExtraControls.Children.Clear(); + var manager = ViewModel.Manager; + bool managerHasSources = manager.Capabilities.SupportsCustomSources && manager.Name != "vcpkg"; + + if (managerHasSources) + { + ExtraControls.Children.Add(new SourceManagerCard(manager) + { + Margin = new Thickness(0, 0, 0, 16), + }); + ExtraControls.Children.Add(new TextBlock + { + Margin = new Thickness(44, 24, 4, 8), + FontWeight = FontWeight.SemiBold, + Text = CoreTools.Translate("Advanced options"), + }); + } + + switch (manager.Name) + { + case "Winget": + disableNotifsCard.CornerRadius = new CornerRadius(8, 8, 0, 0); + disableNotifsCard.BorderThickness = new Thickness(1, 1, 1, 0); + ExtraControls.Children.Add(disableNotifsCard); + + var wingetCliToolPreference = new ComboboxCard + { + Text = CoreTools.Translate("WinGet command-line tool"), + Description = CoreTools.Translate( + "Choose which command-line tool UniGetUI uses for WinGet operations when the COM API is not used" + ), + SettingName = CoreSettings.K.WinGetCliToolPreference, + CornerRadius = new CornerRadius(0), + BorderThickness = new Thickness(1, 0, 1, 1), + }; + wingetCliToolPreference.AddItem("Default", "default"); + wingetCliToolPreference.AddItem("WinGet", "winget", false); + wingetCliToolPreference.AddItem("Pinget", "pinget", false); + wingetCliToolPreference.ShowAddedItems(); + wingetCliToolPreference.ValueChanged += (_, _) => + _ = ViewModel.ReloadManagerCommand.ExecuteAsync(null); + ExtraControls.Children.Add(wingetCliToolPreference); + + var wingetComApiPolicy = new ComboboxCard + { + Text = CoreTools.Translate("WinGet COM API"), + Description = CoreTools.Translate( + "Choose whether UniGetUI can use the WinGet COM API before falling back to the command-line tool" + ), + SettingName = CoreSettings.K.WinGetComApiPolicy, + CornerRadius = new CornerRadius(0), + BorderThickness = new Thickness(1, 0, 1, 1), + }; + wingetComApiPolicy.AddItem("Default", "default"); + wingetComApiPolicy.AddItem("Enabled", "enabled"); + wingetComApiPolicy.AddItem("Disabled", "disabled"); + wingetComApiPolicy.ShowAddedItems(); + wingetComApiPolicy.ValueChanged += (_, _) => + _ = ViewModel.ReloadManagerCommand.ExecuteAsync(null); + ExtraControls.Children.Add(wingetComApiPolicy); + + var wingetResetBtn = new ButtonCard + { + Text = CoreTools.Translate("Reset WinGet") + + $" ({CoreTools.Translate("This may help if no packages are listed")})", + ButtonText = CoreTools.AutoTranslated("Reset"), + CornerRadius = new CornerRadius(0), + BorderThickness = new Thickness(1, 0, 1, 1), + }; + wingetResetBtn.Click += (_, _) => _ = AvaloniaPackageOperationHelper.HandleBrokenWinGetAsync(); + ExtraControls.Children.Add(wingetResetBtn); + + ExtraControls.Children.Add(new CheckboxCard + { + Text = CoreTools.Translate("Force install location parameter when updating packages with custom locations"), + SettingName = CoreSettings.K.WinGetForceLocationOnUpdate, + CornerRadius = new CornerRadius(0), + BorderThickness = new Thickness(1, 0, 1, 1), + }); + + ExtraControls.Children.Add(new CheckboxCard + { + Text = CoreTools.Translate("Download full package manifest alongside the installer"), + SettingName = CoreSettings.K.WinGetDownloadFullManifest, + CornerRadius = new CornerRadius(0, 0, 8, 8), + BorderThickness = new Thickness(1, 0, 1, 1), + }); + + break; + + case "Scoop": + disableNotifsCard.CornerRadius = new CornerRadius(8, 8, 0, 0); + disableNotifsCard.BorderThickness = new Thickness(1, 1, 1, 0); + ExtraControls.Children.Add(disableNotifsCard); + + var scoopInstall = new ButtonCard + { + Text = CoreTools.AutoTranslated("Install Scoop"), + ButtonText = CoreTools.AutoTranslated("Install"), + CornerRadius = new CornerRadius(0), + }; + scoopInstall.Click += (_, _) => ViewModel.ScoopInstallCommand.Execute(null); + ExtraControls.Children.Add(scoopInstall); + + var scoopUninstall = new ButtonCard + { + Text = CoreTools.AutoTranslated("Uninstall Scoop (and its packages)"), + ButtonText = CoreTools.AutoTranslated("Uninstall"), + CornerRadius = new CornerRadius(0), + BorderThickness = new Thickness(1, 0, 1, 0), + }; + scoopUninstall.Click += (_, _) => ViewModel.ScoopUninstallCommand.Execute(null); + ExtraControls.Children.Add(scoopUninstall); + + var scoopCleanup = new ButtonCard + { + Text = CoreTools.AutoTranslated("Run cleanup and clear cache"), + ButtonText = CoreTools.AutoTranslated("Run"), + CornerRadius = new CornerRadius(0), + }; + scoopCleanup.Click += (_, _) => ViewModel.ScoopCleanupCommand.Execute(null); + ExtraControls.Children.Add(scoopCleanup); + + ExtraControls.Children.Add(new CheckboxCard + { + CornerRadius = new CornerRadius(0, 0, 8, 8), + BorderThickness = new Thickness(1, 0, 1, 1), + SettingName = CoreSettings.K.EnableScoopCleanup, + Text = CoreTools.AutoTranslated("Enable Scoop cleanup on launch"), + }); + break; + + case "Bun": + disableNotifsCard.CornerRadius = new CornerRadius(8, 8, 0, 0); + disableNotifsCard.BorderThickness = new Thickness(1, 1, 1, 0); + ExtraControls.Children.Add(disableNotifsCard); + + ExtraControls.Children.Add(new CheckboxCard + { + CornerRadius = new CornerRadius(0, 0, 8, 8), + BorderThickness = new Thickness(1, 0, 1, 1), + SettingName = CoreSettings.K.BunPreferLatestVersions, + Text = CoreTools.Translate("Prefer latest versions (may include breaking changes) instead of recommended safe updates"), + }); + break; + + case "vcpkg": + disableNotifsCard.CornerRadius = new CornerRadius(8, 8, 0, 0); + disableNotifsCard.BorderThickness = new Thickness(1, 1, 1, 0); + ExtraControls.Children.Add(disableNotifsCard); + + CoreSettings.SetValue(CoreSettings.K.DefaultVcpkgTriplet, Vcpkg.GetDefaultTriplet()); + var vcpkgTriplet = new ComboboxCard + { + Text = CoreTools.Translate("Default vcpkg triplet"), + SettingName = CoreSettings.K.DefaultVcpkgTriplet, + CornerRadius = new CornerRadius(0), + }; + foreach (string triplet in Vcpkg.GetSystemTriplets()) + vcpkgTriplet.AddItem(triplet, triplet, false); + vcpkgTriplet.ShowAddedItems(); + ExtraControls.Children.Add(vcpkgTriplet); + ExtraControls.Children.Add(BuildVcpkgRootCard()); + break; + + default: + disableNotifsCard.CornerRadius = new CornerRadius(8); + disableNotifsCard.BorderThickness = new Thickness(1); + ExtraControls.Children.Add(disableNotifsCard); + break; + } + } + + private ButtonCard BuildVcpkgRootCard() + { + var vcpkgRootCard = new ButtonCard + { + Text = CoreTools.AutoTranslated("Change vcpkg root location"), + ButtonText = CoreTools.AutoTranslated("Select"), + CornerRadius = new CornerRadius(0, 0, 8, 8), + BorderThickness = new Thickness(1, 0, 1, 1), + }; + + var rootLabel = new TextBlock + { + VerticalAlignment = VerticalAlignment.Center, + Text = ViewModel.VcpkgRootPath, + }; + var resetBtn = new Button + { + Content = CoreTools.Translate("Reset"), + IsEnabled = ViewModel.IsCustomVcpkgRootSet, + Margin = new Thickness(4, 0), + }; + AutomationProperties.SetName(resetBtn, CoreTools.Translate("Reset vcpkg root location")); + var openBtn = new Button + { + Content = CoreTools.Translate("Open"), + IsEnabled = ViewModel.IsCustomVcpkgRootSet, + Margin = new Thickness(4, 0), + }; + AutomationProperties.SetName(openBtn, CoreTools.Translate("Open vcpkg root location")); + + ViewModel.PropertyChanged += (_, e) => + { + if (e.PropertyName == nameof(PackageManagerViewModel.VcpkgRootPath)) + rootLabel.Text = ViewModel.VcpkgRootPath; + if (e.PropertyName == nameof(PackageManagerViewModel.IsCustomVcpkgRootSet)) + { + resetBtn.IsEnabled = ViewModel.IsCustomVcpkgRootSet; + openBtn.IsEnabled = ViewModel.IsCustomVcpkgRootSet; + } + }; + + resetBtn.Click += (_, _) => ViewModel.ResetVcpkgRootCommand.Execute(null); + openBtn.Click += (_, _) => ViewModel.OpenVcpkgRootCommand.Execute(null); + + var descPanel = new StackPanel { Orientation = Orientation.Horizontal, Spacing = 4 }; + descPanel.Children.Add(rootLabel); + descPanel.Children.Add(resetBtn); + descPanel.Children.Add(openBtn); + vcpkgRootCard.Description = descPanel; + + vcpkgRootCard.Command = ViewModel.PickVcpkgRootCommand; + vcpkgRootCard.CommandParameter = vcpkgRootCard; + return vcpkgRootCard; + } + + // ── View-only: brush lookup (needs ActualThemeVariant) ─────────────────── + + private void ApplyStatusBrushes() + { + StatusBar.Classes.Remove("status-success"); + StatusBar.Classes.Remove("status-warning"); + StatusBar.Classes.Remove("status-error"); + StatusBar.Classes.Remove("status-info"); + + string cls = ViewModel.Severity switch + { + ManagerStatusSeverity.Success => "status-success", + ManagerStatusSeverity.Warning => "status-warning", + ManagerStatusSeverity.Error => "status-error", + _ => "status-info", + }; + StatusBar.Classes.Add(cls); + } + + private async Task CopyPathAndFlashIcon(string? text, Button btn, SvgIcon icon) + { + if (string.IsNullOrEmpty(text)) return; + if (TopLevel.GetTopLevel(this)?.Clipboard is { } clipboard) + await clipboard.SetTextAsync(text); + btn.Content = new TextBlock { Text = "✓", FontSize = 20, VerticalAlignment = VerticalAlignment.Center }; + await Task.Delay(1000); + btn.Content = icon; + } +} diff --git a/src/UniGetUI.Avalonia/Views/Pages/SettingsPages/SettingsBasePage.axaml b/src/UniGetUI.Avalonia/Views/Pages/SettingsPages/SettingsBasePage.axaml new file mode 100644 index 0000000..846b021 --- /dev/null +++ b/src/UniGetUI.Avalonia/Views/Pages/SettingsPages/SettingsBasePage.axaml @@ -0,0 +1,71 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/UniGetUI.Avalonia/Views/SoftwarePages/AbstractPackagesPage.axaml.cs b/src/UniGetUI.Avalonia/Views/SoftwarePages/AbstractPackagesPage.axaml.cs new file mode 100644 index 0000000..538d0e7 --- /dev/null +++ b/src/UniGetUI.Avalonia/Views/SoftwarePages/AbstractPackagesPage.axaml.cs @@ -0,0 +1,542 @@ +using Avalonia; +using Avalonia.Animation; +using Avalonia.Animation.Easings; +using Avalonia.Automation; +using Avalonia.Controls; +using Avalonia.Controls.ApplicationLifetimes; +using Avalonia.Input; +using Avalonia.Input.Platform; +using Avalonia.Interactivity; +using Avalonia.Layout; +using Avalonia.Media; +using Avalonia.Media.Transformation; +using Avalonia.Threading; +using UniGetUI.Avalonia.Extensions; +using UniGetUI.Avalonia.ViewModels.Pages; +using UniGetUI.Avalonia.Views.Controls; +using UniGetUI.Core.SettingsEngine; +using UniGetUI.Core.Tools; +using UniGetUI.PackageEngine.Interfaces; +using UniGetUI.PackageEngine.PackageClasses; + +namespace UniGetUI.Avalonia.Views.Pages; + +public abstract partial class AbstractPackagesPage : UserControl, + IKeyboardShortcutListener, IEnterLeaveListener, ISearchBoxPage +{ + public PackagesPageViewModel ViewModel => (PackagesPageViewModel)DataContext!; + private readonly ContextMenu? _contextMenu; + private double _savedFilterPaneWidth = 220; + private bool _isOverlayMode; + private IDisposable? _sidePanelBgBinding; + private CancellationTokenSource? _filterPaneAnimCts; + + protected AbstractPackagesPage(PackagesPageData data) + { + // InitializeComponent BEFORE setting DataContext so that the svg:Svg + // Path binding has no context during XamlIlPopulate — Skia crashes if + // it tries to load an SVG synchronously mid-init on macOS. + InitializeComponent(); + DataContext = new PackagesPageViewModel(data); + + // Wire ViewModel events that need UI access + ViewModel.FocusListRequested += OnFocusListRequested; + ViewModel.HelpRequested += () => GetMainWindow()?.Navigate(PageType.Help); + ViewModel.ManageIgnoredRequested += async () => + { + if (GetMainWindow() is { } win) + await new ManageIgnoredUpdatesWindow().ShowDialog(win); + }; + + // "New version" sort option is only relevant on the updates page + OrderByNewVersion_Menu.IsVisible = ViewModel.RoleIsUpdateLike; + + // Stamp initial checkmarks, then keep them in sync with sort-property changes + UpdateSortMenuChecks(); + ViewModel.PropertyChanged += (_, args) => + { + if (args.PropertyName is nameof(PackagesPageViewModel.SortFieldIndex) + or nameof(PackagesPageViewModel.SortAscending)) + { + UpdateSortMenuChecks(); + SyncOrderByButtonName(); + } + if (args.PropertyName is nameof(PackagesPageViewModel.IsFilterPaneOpen)) + { + SyncFiltersButtonName(); + UpdateFilterPaneColumn(ViewModel.IsFilterPaneOpen, animate: true); + } + }; + SyncFiltersButtonName(); + SyncOrderByButtonName(); + + // Reload button added before subclass toolbar items (mirrors WinUI AbstractPackagesPage) + if (!ViewModel.DisableReload) + { + var reloadBtn = ViewModel.AddToolbarButton("reload", CoreTools.Translate("Reload"), + ViewModel.TriggerReload); + UpdateReloadButtonTooltip(reloadBtn); + } + + // Build the toolbar now that both AXAML controls and the ViewModel are ready + GenerateToolBar(ViewModel); + + // Double-click a list row → show details + PackageList.DoubleTapped += (_, _) => _ = ShowDetailsForPackage(SelectedItem); + + // Keyboard shortcuts on the package list. Handled on the tunnel route (and even when + // already handled) because the DataGrid swallows Enter on the bubble route otherwise. + PackageList.AddHandler(KeyDownEvent, PackageList_KeyDown, RoutingStrategies.Tunnel, handledEventsToo: true); + + // Type-to-search: printable characters typed while the list is focused + // redirect focus + the typed character to the global search box. + PackageList.TextInput += PackageList_TextInput; + + // Ease wheel scrolling to a stop instead of jumping per notch (WinUI-like feel). + DataGridWheelAnimator.Attach(PackageList); + + // Snap-close when splitter is dragged below the minimum (inline mode only). + // Using ColumnDefinition.WidthProperty fires every drag step, not just on release. + FilteringPanel.ColumnDefinitions[0] + .GetObservable(ColumnDefinition.WidthProperty) + .SubscribeValue(width => + { + if (_isOverlayMode || !ViewModel.IsFilterPaneOpen) return; + if (width.IsAbsolute && width.Value >= 100) + { + _savedFilterPaneWidth = width.Value; + ViewModel.TrackedFilterPaneWidth = width.Value; + Settings.SetDictionaryItem(Settings.K.SidepanelWidths, ViewModel.PageName, (int)width.Value); + } + else if (width.IsAbsolute && width.Value < 100) + { + _savedFilterPaneWidth = 220; + ViewModel.TrackedFilterPaneWidth = 220; + ViewModel.IsFilterPaneOpen = false; + } + }); + + // Responsive: switch between inline and overlay modes based on content width. + FilteringPanel.GetObservable(BoundsProperty) + .SubscribeValue(bounds => OnFilteringPanelWidthChanged(bounds.Width)); + + // Responsive: collapse the menu bar to icon-only on narrow windows so the + // toolbar buttons stay reachable instead of overflowing (mirrors WinUI). + this.GetObservable(BoundsProperty) + .SubscribeValue(bounds => ViewModel.SetToolbarLabelsCollapsed(bounds.Width < 900)); + + // Grid/icons views: stretch cards to fill each row then reflow (mirrors WinUI's + // UniformGridLayout) instead of leaving wasted space to the right. + GridViewItems.GetObservable(BoundsProperty) + .SubscribeValue(bounds => UpdateGridCardWidth(bounds.Width)); + IconsViewItems.GetObservable(BoundsProperty) + .SubscribeValue(bounds => UpdateIconCardWidth(bounds.Width)); + + // Overlay backdrop dismisses the filter pane when tapped. + FilterOverlayBackdrop.PointerPressed += (_, _) => ViewModel.IsFilterPaneOpen = false; + + // Wire context menu (built by subclass) + _contextMenu = GenerateContextMenu(); + if (_contextMenu is not null) + { + PackageList.ContextMenu = _contextMenu; + _contextMenu.Opening += (_, _) => + { + var pkg = SelectedItem; + if (pkg is not null) WhenShowingContextMenu(pkg); + }; + } + + // Restore per-page filter pane width from settings. + var savedWidth = Settings.GetDictionaryItem(Settings.K.SidepanelWidths, ViewModel.PageName); + if (savedWidth >= 100) _savedFilterPaneWidth = savedWidth; + ViewModel.TrackedFilterPaneWidth = _savedFilterPaneWidth; + + // Apply the initial filter-pane state (AXAML defaults to 220px open). + UpdateFilterPaneColumn(ViewModel.IsFilterPaneOpen); + + // Attach the pane slide AFTER the initial state so launch doesn't animate. The pane slides + // via a compositor RenderTransform (clipped by FilteringPanel) instead of width-tweening the + // column, which reflowed the package list every frame and felt laggy. + SidePanel.Transitions = new Transitions + { + new TransformOperationsTransition + { + Property = Visual.RenderTransformProperty, + Duration = TimeSpan.FromMilliseconds(200), + Easing = new SplineEasing(0.1, 0.9, 0.2, 1.0), + } + }; + } + + // Recompute the grid-view card slot width: fit as many >=275px columns as possible, + // then divide the row evenly among them so cards stretch to fill (WinUI parity). + private void UpdateGridCardWidth(double availableWidth) + { + if (availableWidth <= 0) return; + const double minSlotWidth = 275 + 8; // 275px card + 4px margin per side + int columns = Math.Max(1, (int)(availableWidth / minSlotWidth)); + ViewModel.GridCardWidth = Math.Floor(availableWidth / columns); + } + + // Same as UpdateGridCardWidth, for the smaller icon tiles (>=128px columns). + private void UpdateIconCardWidth(double availableWidth) + { + if (availableWidth <= 0) return; + const double minSlotWidth = 128 + 8; // 128px tile + 4px margin per side + int columns = Math.Max(1, (int)(availableWidth / minSlotWidth)); + ViewModel.IconCardWidth = Math.Floor(availableWidth / columns); + } + + // ─── UI-only: focus the package list ───────────────────────────────────── + private void OnFocusListRequested() => PackageList.Focus(); + + private void UpdateReloadButtonTooltip(Button reloadButton) + { + ToolTip.SetTip(reloadButton, ViewModel.ReloadButtonTooltip); + ViewModel.PropertyChanged += (_, args) => + { + if (args.PropertyName is nameof(PackagesPageViewModel.ReloadButtonTooltip)) + ToolTip.SetTip(reloadButton, ViewModel.ReloadButtonTooltip); + }; + } + + public void FocusPackageList() + { + if (ViewModel.MegaQueryBoxEnabled) + Dispatcher.UIThread.Post(() => + { + if (!ViewModel.MegaQueryVisible) return; + MegaQueryBlock.Focus(); + }, DispatcherPriority.ApplicationIdle); + else + ViewModel.RequestFocusList(); + } + public void FilterPackages() => ViewModel.FilterPackages(); + + // ─── Abstract: let concrete pages add toolbar items ─────────────────────── + protected abstract void GenerateToolBar(PackagesPageViewModel vm); + + // ─── Abstract: per-page actions invoked by base class keyboard/mouse handlers ─ + /// Performs the page's primary action (install / uninstall / update) on the package. + protected abstract void PerformMainPackageAction(IPackage? package); + /// Opens the details dialog for the package. + protected abstract Task ShowDetailsForPackage(IPackage? package); + /// Opens the installation-options dialog for the package. + protected abstract Task ShowInstallationOptionsForPackage(IPackage? package); + + // ─── Virtual: let concrete pages supply a context menu ──────────────────── + protected virtual ContextMenu? GenerateContextMenu() => null; + protected virtual void WhenShowingContextMenu(IPackage package) { } + + // ─── Helper: create a 16×16 SvgIcon for use as a menu item icon ─────────── + protected static SvgIcon LoadMenuIcon(string svgName) => new() + { + Path = $"avares://UniGetUI/Assets/Symbols/{svgName}.svg", + Width = 16, + Height = 16, + }; + + // ─── Protected access to main toolbar controls for subclasses ───────────── + /// Sets the icon and text of the primary action button. + protected void SetMainButton(string svgName, string label, Action onClick) + { + MainToolbarButtonIcon.Path = $"avares://UniGetUI/Assets/Symbols/{svgName}.svg"; + MainToolbarButtonText.Text = label; + AutomationProperties.SetName(MainToolbarButton, label); + MainToolbarButton.Click += (_, _) => onClick(); + } + + /// Sets the dropdown flyout of the primary action button. + protected void SetMainButtonDropdown(MenuFlyout flyout) + { + MainToolbarButtonDropdown.Flyout = flyout; + } + + // ─── Package selection ──────────────────────────────────────────────────── + /// + /// Returns the focused row's package, or the single checked package if + /// nothing is focused. Mirrors the WinUI SelectedItem pattern. + /// + protected IPackage? SelectedItem + { + get + { + if (PackageList.SelectedItem is PackageWrapper w) + return w.Package; + + var checked_ = ViewModel.FilteredPackages.GetCheckedPackages(); + if (checked_.Count == 1) + return checked_.First(); + + return null; + } + } + + // ─── Operation launchers (delegated to ViewModel) ───────────────────────── + protected static Task LaunchInstall( + IEnumerable packages, + bool? elevated = null, + bool? interactive = null, + bool? no_integrity = null) + => PackagesPageViewModel.LaunchInstall(packages, elevated, interactive, no_integrity); + + // ─── Sort menu checkmarks (UI reacts to ViewModel sort changes) ─────────── + private static TextBlock? Check(bool show) => + show ? new TextBlock { Text = "✓", FontSize = 12 } : null; + + private void SyncFiltersButtonName() + { + bool open = ViewModel.IsFilterPaneOpen; + string state = open ? CoreTools.Translate("Open") : CoreTools.Translate("Closed"); + string label = CoreTools.Translate("Filters"); + AutomationProperties.SetName(ToggleFiltersButton, $"{label}, {state}"); + } + + private void SyncOrderByButtonName() + { + string direction = ViewModel.SortAscending + ? CoreTools.Translate("Ascending") + : CoreTools.Translate("Descending"); + AutomationProperties.SetName( + OrderByButton, + CoreTools.Translate("{0}: {1}, {2}", CoreTools.Translate("Order by"), ViewModel.SortFieldName, direction)); + } + + private void UpdateSortMenuChecks() + { + OrderByName_Menu.Icon = Check(ViewModel.SortFieldIndex == 0); + OrderById_Menu.Icon = Check(ViewModel.SortFieldIndex == 1); + OrderByVersion_Menu.Icon = Check(ViewModel.SortFieldIndex == 2); + OrderByNewVersion_Menu.Icon = Check(ViewModel.SortFieldIndex == 3); + OrderBySource_Menu.Icon = Check(ViewModel.SortFieldIndex == 4); + OrderByAscending_Menu.Icon = Check(ViewModel.SortAscending); + OrderByDescending_Menu.Icon = Check(!ViewModel.SortAscending); + } + + // ─── IKeyboardShortcutListener ──────────────────────────────────────────── + public void SearchTriggered() => GetMainWindow()?.FocusGlobalSearch(); + + public void ReloadTriggered() => ViewModel.TriggerReload(); + public void SelectAllTriggered() => ViewModel.ToggleSelectAll(); + public void DetailsTriggered() { if (SelectedItem is { } pkg) _ = ShowDetailsForPackage(pkg); } + + // ─── IEnterLeaveListener ────────────────────────────────────────────────── + public virtual void OnEnter() { } + public virtual void OnLeave() { } + + // ─── ISearchBoxPage ─────────────────────────────────────────────────────── + public string QueryBackup + { + get => ViewModel.QueryBackup; + set => ViewModel.QueryBackup = value; + } + + public string SearchBoxPlaceholder => ViewModel.SearchBoxPlaceholder; + + public void SearchBox_QuerySubmitted(object? sender, EventArgs? e) => ViewModel.HandleSearchSubmitted(); + + private void MegaQueryBlock_KeyDown(object? sender, KeyEventArgs e) + { + if (e.Key == Key.Enter || e.Key == Key.Return) + ViewModel.SubmitSearch(); + } + + // Accelerator hints shown in package context menus; handling lives in PackageList_KeyDown below. + // Rendered manually (not via MenuItem.InputGesture) because Avalonia's Key enum aliases + // Enter→Return and would display "Return" instead of WinUI's "Enter". + protected const string MainActionShortcut = "Ctrl+Enter"; + protected const string OptionsShortcut = "Alt+Enter"; + protected const string DetailsShortcut = "Enter"; + + /// Builds a menu header with the label on the left and a dimmed, right-aligned shortcut hint. + protected static Control ShortcutHeader(string label, string shortcut) + { + var grid = new Grid + { + ColumnDefinitions = new ColumnDefinitions("*,Auto"), + HorizontalAlignment = HorizontalAlignment.Stretch, + }; + grid.Children.Add(new TextBlock { Text = label, VerticalAlignment = VerticalAlignment.Center }); + var hint = new TextBlock + { + Text = shortcut, + Opacity = 0.6, + Margin = new Thickness(24, 0, 0, 0), + VerticalAlignment = VerticalAlignment.Center, + }; + Grid.SetColumn(hint, 1); + grid.Children.Add(hint); + return grid; + } + + private void PackageList_KeyDown(object? sender, KeyEventArgs e) + { + var pkg = SelectedItem; + if (pkg is null) return; + + bool ctrl = e.KeyModifiers.HasFlag(KeyModifiers.Control); + bool alt = e.KeyModifiers.HasFlag(KeyModifiers.Alt); + + if (e.Key is Key.Enter or Key.Return) + { + if (alt) + _ = ShowInstallationOptionsForPackage(pkg); + else if (ctrl) + PerformMainPackageAction(pkg); + else + _ = ShowDetailsForPackage(pkg); + e.Handled = true; + } + } + + private void PackageList_TextInput(object? sender, TextInputEventArgs e) + { + if (string.IsNullOrEmpty(e.Text)) return; + + // Append the typed character to the current query and move focus to the search box + GetMainWindow()?.FocusGlobalSearch(ViewModel.GlobalQueryText + e.Text); + e.Handled = true; + } + + // ─── Filter pane column width management ───────────────────────────────── + + private void OnFilteringPanelWidthChanged(double width) + { + if (width <= 0) return; // layout not complete yet + bool shouldBeOverlay = width < 1000; + if (shouldBeOverlay == _isOverlayMode) return; + + _isOverlayMode = shouldBeOverlay; + + if (_isOverlayMode && ViewModel.IsFilterPaneOpen) + ViewModel.IsFilterPaneOpen = false; // collapse pane when entering overlay + else + UpdateFilterPaneColumn(ViewModel.IsFilterPaneOpen); + } + + private void UpdateFilterPaneColumn(bool open, bool animate = false) + { + if (FilteringPanel.ColumnDefinitions.Count < 2) return; + + if (_isOverlayMode) + { + _filterPaneAnimCts?.Cancel(); + + // Package list fills full width; filter pane and splitter take no space. + FilteringPanel.ColumnDefinitions[0].Width = new GridLength(0); + FilteringPanel.ColumnDefinitions[1].Width = new GridLength(0); + + // Float the filter pane on top of the content when open. + Grid.SetColumnSpan(SidePanel, 3); + SidePanel.ZIndex = 10; + SidePanel.Width = _savedFilterPaneWidth; + SidePanel.HorizontalAlignment = HorizontalAlignment.Left; + SidePanel.IsVisible = open; + SetSidePanelTransformInstant(0); + + // Floating over content needs an opaque surface (the page surface is transparent under Mica). + _sidePanelBgBinding ??= SidePanel.Bind(Border.BackgroundProperty, this.GetResourceObservable("AppWindowBackground")); + + // Semi-transparent backdrop covers the package list behind the pane. + FilterOverlayBackdrop.IsVisible = open; + } + else + { + // Inline mode: pane sits beside the package list and blends with the Mica page surface. + Grid.SetColumnSpan(SidePanel, 1); + SidePanel.ZIndex = 0; + SidePanel.Width = double.NaN; + SidePanel.HorizontalAlignment = HorizontalAlignment.Stretch; + _sidePanelBgBinding?.Dispose(); + _sidePanelBgBinding = null; + SidePanel.Background = null; + FilterOverlayBackdrop.IsVisible = false; + + if (animate) + { + AnimateInlineFilterPane(open); + } + else + { + _filterPaneAnimCts?.Cancel(); + SidePanel.IsVisible = open; + SetSidePanelTransformInstant(open ? 0 : -_savedFilterPaneWidth); + FilteringPanel.ColumnDefinitions[0].Width = open ? new GridLength(_savedFilterPaneWidth) : new GridLength(0); + FilteringPanel.ColumnDefinitions[1].Width = open ? new GridLength(4) : new GridLength(0); + } + } + } + + // Reserve/release the inline pane's column in one step (a single reflow, not a per-frame tween), + // and slide the pane itself in/out via a compositor RenderTransform (clipped by FilteringPanel) — + // tweening the column width reflowed the package list every frame and felt laggy. The toolbar + // buttons still slide via their MinWidth transition. + private async void AnimateInlineFilterPane(bool open) + { + _filterPaneAnimCts?.Cancel(); + var cts = new CancellationTokenSource(); + _filterPaneAnimCts = cts; + + var col0 = FilteringPanel.ColumnDefinitions[0]; + var col1 = FilteringPanel.ColumnDefinitions[1]; + + if (open) + { + // Reserve the column (one reflow), then slide the pane in from -width to 0. + col0.Width = new GridLength(_savedFilterPaneWidth); + col1.Width = new GridLength(4); + SidePanel.IsVisible = true; + SidePanel.RenderTransform = TranslateX(0); + } + else + { + // Reclaim the list width in one reflow NOW and float the pane over the list, then slide + // the floating pane out — otherwise the list sits beside an empty gap and only snaps to + // full width when the slide ends. Inline positioning is restored on the next open by + // UpdateFilterPaneColumn. + double w = _savedFilterPaneWidth; + Grid.SetColumnSpan(SidePanel, 3); + SidePanel.ZIndex = 10; + SidePanel.Width = w; + SidePanel.HorizontalAlignment = HorizontalAlignment.Left; + _sidePanelBgBinding ??= SidePanel.Bind(Border.BackgroundProperty, this.GetResourceObservable("AppWindowBackground")); + col0.Width = new GridLength(0); + col1.Width = new GridLength(0); + + SidePanel.RenderTransform = TranslateX(-w); + try { await Task.Delay(210, cts.Token); } + catch (TaskCanceledException) { return; } + SidePanel.IsVisible = false; + } + } + + private static ITransform TranslateX(double x) + => TransformOperations.Parse(string.Create(System.Globalization.CultureInfo.InvariantCulture, $"translateX({x}px)")); + + // Set the pane transform without triggering the slide transition (for initial/mode-change states). + private void SetSidePanelTransformInstant(double translateX) + { + var transitions = SidePanel.Transitions; + SidePanel.Transitions = null; + SidePanel.RenderTransform = TranslateX(translateX); + SidePanel.Transitions = transitions; + } + + // ─── Card overflow button (Grid / Icons view) ───────────────────────────── + private void CardOverflowButton_Click(object? sender, RoutedEventArgs e) + { + if (sender is not Button { DataContext: PackageWrapper wrapper } button) return; + PackageList.SelectedItem = wrapper; + if (_contextMenu is null) return; + WhenShowingContextMenu(wrapper.Package); + _contextMenu.PlacementTarget = button; + _contextMenu.Open(); + e.Handled = true; + } + + // ─── Shared cross-page helpers ──────────────────────────────────────────── + protected static MainWindow? GetMainWindow() + => Application.Current?.ApplicationLifetime + is IClassicDesktopStyleApplicationLifetime { MainWindow: MainWindow w } ? w : null; +} diff --git a/src/UniGetUI.Avalonia/Views/SoftwarePages/DiscoverSoftwarePage.cs b/src/UniGetUI.Avalonia/Views/SoftwarePages/DiscoverSoftwarePage.cs new file mode 100644 index 0000000..507e2b2 --- /dev/null +++ b/src/UniGetUI.Avalonia/Views/SoftwarePages/DiscoverSoftwarePage.cs @@ -0,0 +1,196 @@ +using Avalonia; +using Avalonia.Controls; +using Avalonia.Controls.ApplicationLifetimes; +using UniGetUI.Avalonia.Infrastructure; +using UniGetUI.Avalonia.ViewModels.Pages; +using UniGetUI.Avalonia.Views; +using UniGetUI.Core.Logging; +using UniGetUI.Core.Tools; +using UniGetUI.Interface.Enums; +using UniGetUI.Interface.Telemetry; +using UniGetUI.PackageEngine.Classes.Manager.Classes; +using UniGetUI.PackageEngine.Enums; +using UniGetUI.PackageEngine.Interfaces; +using UniGetUI.PackageEngine.PackageClasses; +using UniGetUI.PackageEngine.PackageLoader; + +namespace UniGetUI.Avalonia.Views.Pages; + +public class DiscoverSoftwarePage : AbstractPackagesPage +{ + // Context-menu items whose enabled state depends on the focused package's manager + private MenuItem? _menuAsAdmin; + private MenuItem? _menuInteractive; + private MenuItem? _menuSkipHash; + private MenuItem? _menuDownloadInstaller; + + public DiscoverSoftwarePage() : base(new PackagesPageData + { + PageName = "SoftwarePages.DiscoverSoftwarePage", + PageTitle = CoreTools.Translate("Discover Packages"), + IconName = "DiscoverPackage", + PageRole = OperationType.Install, + Loader = DiscoverablePackagesLoader.Instance ?? new DiscoverablePackagesLoader([]), + MegaQueryBlockEnabled = true, + DisableSuggestedResultsRadio = false, + PackagesAreCheckedByDefault = false, + ShowLastLoadTime = false, + DisableAutomaticPackageLoadOnStart = true, + DisableFilterOnQueryChange = true, + DisableReload = false, + NoPackages_BackgroundText = CoreTools.Translate("No results were found matching the input criteria"), + NoPackages_SourcesText = CoreTools.Translate("No packages were found"), + NoPackages_SubtitleText_Base = CoreTools.Translate("No packages were found"), + MainSubtitle_StillLoading = CoreTools.Translate("Loading packages"), + NoMatches_BackgroundText = CoreTools.Translate("No results were found matching the input criteria"), + }) + { } + + protected override void GenerateToolBar(PackagesPageViewModel vm) + { + // ── Main button dropdown: install variants ────────────────────────── + var installAsAdmin = new MenuItem { Header = CoreTools.Translate("Install as administrator"), IsVisible = OperatingSystem.IsWindows() }; + var installSkipHash = new MenuItem { Header = CoreTools.Translate("Skip integrity checks") }; + var installInteractive = new MenuItem { Header = CoreTools.Translate("Interactive installation") }; + var downloadInstallers = new MenuItem { Header = CoreTools.Translate("Download selected installers") }; + + SetMainButton("download", CoreTools.Translate("Install selection"), () => + _ = LaunchInstall(vm.FilteredPackages.GetCheckedPackages())); + + SetMainButtonDropdown(new MenuFlyout + { + Items = { installAsAdmin, installSkipHash, installInteractive, new Separator(), downloadInstallers }, + }); + + installAsAdmin.Click += (_, _) => _ = LaunchInstall(vm.FilteredPackages.GetCheckedPackages(), elevated: true); + installSkipHash.Click += (_, _) => _ = LaunchInstall(vm.FilteredPackages.GetCheckedPackages(), no_integrity: true); + installInteractive.Click += (_, _) => _ = LaunchInstall(vm.FilteredPackages.GetCheckedPackages(), interactive: true); + downloadInstallers.Click += (_, _) => _ = AvaloniaPackageOperationHelper.DownloadSelectedAsync( + vm.FilteredPackages.GetCheckedPackages(), TEL_InstallReferral.DIRECT_SEARCH); + + // ── Toolbar buttons ───────────────────────────────────────────────── + ViewModel.AddToolbarSeparator(); + ViewModel.AddToolbarButton("options", CoreTools.Translate("Install options"), + () => _ = ShowInstallationOptionsForPackage(SelectedItem)); + ViewModel.AddToolbarSeparator(); + ViewModel.AddToolbarButton("info_round", CoreTools.Translate("Package details"), + () => _ = ShowDetailsForPackage(SelectedItem), showLabel: false); + ViewModel.AddToolbarSeparator(); + ViewModel.AddToolbarButton("add_to", CoreTools.Translate("Add selection to bundle"), + () => _ = ExportSelectionToBundleAsync(vm)); + } + + // ─── Context menu ───────────────────────────────────────────────────────── + protected override ContextMenu? GenerateContextMenu() + { + _menuAsAdmin = new MenuItem + { + Header = CoreTools.Translate("Install as administrator"), + Icon = LoadMenuIcon("uac"), + IsVisible = OperatingSystem.IsWindows(), + }; + _menuAsAdmin.Click += (_, _) => _ = LaunchInstall([SelectedItem!], elevated: true); + + _menuInteractive = new MenuItem + { + Header = CoreTools.Translate("Interactive installation"), + Icon = LoadMenuIcon("interactive"), + }; + _menuInteractive.Click += (_, _) => _ = LaunchInstall([SelectedItem!], interactive: true); + + _menuSkipHash = new MenuItem + { + Header = CoreTools.Translate("Skip hash check"), + Icon = LoadMenuIcon("checksum"), + }; + _menuSkipHash.Click += (_, _) => _ = LaunchInstall([SelectedItem!], no_integrity: true); + + _menuDownloadInstaller = new MenuItem + { + Header = CoreTools.Translate("Download installer"), + Icon = LoadMenuIcon("download"), + }; + _menuDownloadInstaller.Click += (_, _) => _ = AvaloniaPackageOperationHelper.AskLocationAndDownloadAsync( + SelectedItem, TEL_InstallReferral.DIRECT_SEARCH); + + var menuInstall = new MenuItem { Header = ShortcutHeader(CoreTools.Translate("Install"), MainActionShortcut), Icon = LoadMenuIcon("download") }; + menuInstall.Click += (_, _) => _ = LaunchInstall([SelectedItem!]); + + var menuInstallOptions = new MenuItem { Header = ShortcutHeader(CoreTools.Translate("Install options"), OptionsShortcut), Icon = LoadMenuIcon("options") }; + menuInstallOptions.Click += (_, _) => _ = ShowInstallationOptionsForPackage(SelectedItem); + + var menuDetails = new MenuItem { Header = ShortcutHeader(CoreTools.Translate("Package details"), DetailsShortcut), Icon = LoadMenuIcon("info_round") }; + menuDetails.Click += (_, _) => _ = ShowDetailsForPackage(SelectedItem); + + var menu = new ContextMenu(); + menu.Items.Add(menuInstall); + menu.Items.Add(new Separator()); + menu.Items.Add(menuInstallOptions); + menu.Items.Add(new Separator()); + menu.Items.Add(_menuAsAdmin); + menu.Items.Add(_menuInteractive); + menu.Items.Add(_menuSkipHash); + menu.Items.Add(_menuDownloadInstaller); + menu.Items.Add(new Separator()); + menu.Items.Add(menuDetails); + + return menu; + } + + protected override void WhenShowingContextMenu(IPackage package) + { + if (_menuAsAdmin is null || _menuInteractive is null + || _menuSkipHash is null || _menuDownloadInstaller is null) + { + Logger.Warn("Context menu items are null on DiscoverSoftwarePage"); + return; + } + + _menuAsAdmin.IsEnabled = package.Manager.Capabilities.CanRunAsAdmin; + _menuInteractive.IsEnabled = package.Manager.Capabilities.CanRunInteractively; + _menuSkipHash.IsEnabled = package.Manager.Capabilities.CanSkipIntegrityChecks; + _menuDownloadInstaller.IsEnabled = package.Manager.Capabilities.CanDownloadInstaller; + } + + // ─── Abstract action overrides ──────────────────────────────────────────── + protected override void PerformMainPackageAction(IPackage? package) + { + if (package is null) return; + _ = LaunchInstall([package]); + } + + protected override async Task ShowDetailsForPackage(IPackage? package) + { + if (package is null) return; + if (GetMainWindow() is not { } win) return; + + var dialog = new PackageDetailsWindow(package, OperationType.Install); + await dialog.ShowDialog(win); + + if (dialog.ShouldProceedWithOperation) + await LaunchInstall([package]); + } + + protected override async Task ShowInstallationOptionsForPackage(IPackage? package) + { + if (package is null || package.Source.IsVirtualManager) return; + + var opts = await InstallOptionsFactory.LoadForPackageAsync(package); + if (GetMainWindow() is not { } win) return; + + var dialog = new InstallOptionsWindow(package, OperationType.Install, opts); + await dialog.ShowDialog(win); + await InstallOptionsFactory.SaveForPackageAsync(opts, package); + + if (dialog.ShouldProceedWithOperation) + await LaunchInstall([package]); + } + + private static async Task ExportSelectionToBundleAsync(PackagesPageViewModel vm) + { + var packages = vm.FilteredPackages.GetCheckedPackages(); + GetMainWindow()?.Navigate(PageType.Bundles); + if (PackageBundlesLoader.Instance is not null) + await PackageBundlesLoader.Instance.AddPackagesAsync(packages); + } +} diff --git a/src/UniGetUI.Avalonia/Views/SoftwarePages/InstalledPackagesPage.cs b/src/UniGetUI.Avalonia/Views/SoftwarePages/InstalledPackagesPage.cs new file mode 100644 index 0000000..c7db88f --- /dev/null +++ b/src/UniGetUI.Avalonia/Views/SoftwarePages/InstalledPackagesPage.cs @@ -0,0 +1,416 @@ +using System.Diagnostics; +using Avalonia.Controls; +using CommunityToolkit.Mvvm.Input; +using UniGetUI.Avalonia.Infrastructure; +using UniGetUI.Avalonia.ViewModels; +using UniGetUI.Avalonia.ViewModels.Pages; +using UniGetUI.Avalonia.ViewModels.Pages.SettingsPages; +using UniGetUI.Avalonia.Views; +using UniGetUI.Core.Logging; +using UniGetUI.Core.SettingsEngine; +using UniGetUI.Core.Tools; +using UniGetUI.Interface.Telemetry; +using UniGetUI.PackageEngine.Classes.Manager.Classes; +using UniGetUI.PackageEngine.Enums; +using UniGetUI.PackageEngine.Interfaces; +using UniGetUI.PackageEngine.Operations; +using UniGetUI.PackageEngine.PackageClasses; +using UniGetUI.PackageEngine.PackageLoader; + +namespace UniGetUI.Avalonia.Views.Pages; + +public class InstalledPackagesPage : AbstractPackagesPage +{ + // Context-menu items whose enabled state depends on the focused package + private MenuItem? _menuAsAdmin; + private MenuItem? _menuInteractive; + private MenuItem? _menuRemoveData; + private MenuItem? _menuInstallationOptions; + private MenuItem? _menuReinstall; + private MenuItem? _menuUninstallThenReinstall; + private MenuItem? _menuIgnoreUpdates; + private MenuItem? _menuDetails; + private MenuItem? _menuOpenInstallLocation; + private MenuItem? _menuDownloadInstaller; + + private static bool _hasBackedUp; + + public InstalledPackagesPage() : base(new PackagesPageData + { + PageName = "SoftwarePages.InstalledPackagesPage", + PageTitle = CoreTools.Translate("Installed Packages"), + IconName = "InstalledPackages", + PageRole = OperationType.Uninstall, + Loader = InstalledPackagesLoader.Instance ?? new InstalledPackagesLoader([]), + MegaQueryBlockEnabled = false, + DisableSuggestedResultsRadio = true, + PackagesAreCheckedByDefault = false, + ShowLastLoadTime = true, + DisableAutomaticPackageLoadOnStart = false, + DisableFilterOnQueryChange = false, + DisableReload = false, + NoPackages_BackgroundText = CoreTools.Translate("No packages were found"), + NoPackages_ImagePath = "avares://UniGetUI/Assets/Images/maurice_penseur.png", + NoPackages_SourcesText = CoreTools.Translate("No packages were found"), + NoPackages_SubtitleText_Base = CoreTools.Translate("No packages were found"), + MainSubtitle_StillLoading = CoreTools.Translate("Loading packages"), + NoMatches_BackgroundText = CoreTools.Translate("No results were found matching the input criteria"), + }) + { + ViewModel.PackagesLoaded += reason => + { + if (!_hasBackedUp) + { + _hasBackedUp = true; + if (Settings.Get(Settings.K.EnablePackageBackup_LOCAL)) + _ = BackupViewModel.DoLocalBackupStatic(); + if (Settings.Get(Settings.K.EnablePackageBackup_CLOUD)) + _ = BackupViewModel.DoCloudBackupStatic(); + } + + if (OperatingSystem.IsWindows() + && !Settings.Get(Settings.K.DisableWinGetMalfunctionDetector) + && AvaloniaPackageOperationHelper.IsWinGetMalfunctioning()) + { + UpdateWinGetMalfunctionBanner(malfunction: true); + } + else + { + UpdateWinGetMalfunctionBanner(malfunction: false); + } + }; + } + + protected override void GenerateToolBar(PackagesPageViewModel vm) + { + // ── Dropdown: uninstall variants ──────────────────────────────────── + var uninstallAsAdmin = new MenuItem { Header = CoreTools.Translate("Uninstall as administrator"), IsVisible = OperatingSystem.IsWindows() }; + var uninstallInteractive = new MenuItem { Header = CoreTools.Translate("Interactive uninstall") }; + var downloadInstallers = new MenuItem { Header = CoreTools.Translate("Download selected installers") }; + + SetMainButton("delete", CoreTools.Translate("Uninstall selection"), () => + _ = LaunchUninstall(vm.FilteredPackages.GetCheckedPackages())); + + SetMainButtonDropdown(new MenuFlyout + { + Items = { uninstallAsAdmin, uninstallInteractive, new Separator(), downloadInstallers }, + }); + + uninstallAsAdmin.Click += (_, _) => _ = LaunchUninstall(vm.FilteredPackages.GetCheckedPackages(), elevated: true); + uninstallInteractive.Click += (_, _) => _ = LaunchUninstall(vm.FilteredPackages.GetCheckedPackages(), interactive: true); + downloadInstallers.Click += (_, _) => _ = AvaloniaPackageOperationHelper.DownloadSelectedAsync( + vm.FilteredPackages.GetCheckedPackages(), TEL_InstallReferral.ALREADY_INSTALLED); + + // ── Toolbar buttons ───────────────────────────────────────────────── + ViewModel.AddToolbarSeparator(); + ViewModel.AddToolbarButton("options", CoreTools.Translate("Uninstall options"), + () => _ = ShowInstallationOptionsForPackage(SelectedItem), showLabel: false); + ViewModel.AddToolbarSeparator(); + ViewModel.AddToolbarButton("info_round", CoreTools.Translate("Package details"), + () => _ = ShowDetailsForPackage(SelectedItem), showLabel: false); + ViewModel.AddToolbarSeparator(); + ViewModel.AddToolbarButton("pin", CoreTools.Translate("Ignore selected packages"), async () => + { + foreach (var pkg in vm.FilteredPackages.GetCheckedPackages()) + { + if (!pkg.Source.IsVirtualManager) + { + UpgradablePackagesLoader.Instance.Remove(pkg); + await pkg.AddToIgnoredUpdatesAsync(); + } + } + }); + ViewModel.AddToolbarButton("clipboard_list", CoreTools.Translate("Manage ignored updates"), + () => vm.RequestManageIgnoredCommand.Execute(null)); + ViewModel.AddToolbarSeparator(); + ViewModel.AddToolbarButton("add_to", CoreTools.Translate("Add selection to bundle"), + () => _ = ExportSelectionToBundleAsync(vm)); + } + + // ─── Context menu ───────────────────────────────────────────────────────── + protected override ContextMenu? GenerateContextMenu() + { + var menuUninstall = new MenuItem + { + Header = ShortcutHeader(CoreTools.Translate("Uninstall"), MainActionShortcut), + Icon = LoadMenuIcon("delete"), + }; + menuUninstall.Click += (_, _) => _ = LaunchUninstall([SelectedItem!]); + + _menuInstallationOptions = new MenuItem + { + Header = ShortcutHeader(CoreTools.Translate("Uninstall options"), OptionsShortcut), + Icon = LoadMenuIcon("options"), + }; + _menuInstallationOptions.Click += (_, _) => _ = ShowInstallationOptionsForPackage(SelectedItem); + + _menuOpenInstallLocation = new MenuItem + { + Header = CoreTools.Translate("Open install location"), + Icon = LoadMenuIcon("launch"), + }; + _menuOpenInstallLocation.Click += (_, _) => OpenInstallLocation(SelectedItem); + + _menuAsAdmin = new MenuItem + { + Header = CoreTools.Translate("Uninstall as administrator"), + Icon = LoadMenuIcon("uac"), + IsVisible = OperatingSystem.IsWindows(), + }; + _menuAsAdmin.Click += (_, _) => _ = LaunchUninstall([SelectedItem!], elevated: true); + + _menuInteractive = new MenuItem + { + Header = CoreTools.Translate("Interactive uninstall"), + Icon = LoadMenuIcon("interactive"), + }; + _menuInteractive.Click += (_, _) => _ = LaunchUninstall([SelectedItem!], interactive: true); + + _menuRemoveData = new MenuItem + { + Header = CoreTools.Translate("Uninstall and remove data"), + Icon = LoadMenuIcon("close_round"), + }; + _menuRemoveData.Click += (_, _) => _ = LaunchUninstall([SelectedItem!], remove_data: true); + + _menuDownloadInstaller = new MenuItem + { + Header = CoreTools.Translate("Download installer"), + Icon = LoadMenuIcon("download"), + }; + _menuDownloadInstaller.Click += (_, _) => _ = AvaloniaPackageOperationHelper.AskLocationAndDownloadAsync( + SelectedItem, TEL_InstallReferral.ALREADY_INSTALLED); + + _menuReinstall = new MenuItem + { + Header = CoreTools.Translate("Reinstall package"), + Icon = LoadMenuIcon("download"), + }; + _menuReinstall.Click += (_, _) => _ = LaunchReinstall(SelectedItem); + + _menuUninstallThenReinstall = new MenuItem + { + Header = CoreTools.Translate("Uninstall package, then reinstall it"), + Icon = LoadMenuIcon("undelete"), + }; + _menuUninstallThenReinstall.Click += (_, _) => _ = LaunchUninstallThenReinstall(SelectedItem); + + _menuIgnoreUpdates = new MenuItem + { + Header = CoreTools.Translate("Ignore updates for this package"), + Icon = LoadMenuIcon("pin"), + }; + _menuIgnoreUpdates.Click += (_, _) => _ = ToggleIgnoreUpdatesAsync(SelectedItem); + + _menuDetails = new MenuItem + { + Header = ShortcutHeader(CoreTools.Translate("Package details"), DetailsShortcut), + Icon = LoadMenuIcon("info_round"), + }; + _menuDetails.Click += (_, _) => _ = ShowDetailsForPackage(SelectedItem); + + var menu = new ContextMenu(); + menu.Items.Add(menuUninstall); + menu.Items.Add(new Separator()); + menu.Items.Add(_menuInstallationOptions); + menu.Items.Add(_menuOpenInstallLocation); + menu.Items.Add(new Separator()); + menu.Items.Add(_menuAsAdmin); + menu.Items.Add(_menuInteractive); + menu.Items.Add(_menuRemoveData); + menu.Items.Add(new Separator()); + menu.Items.Add(_menuDownloadInstaller); + menu.Items.Add(new Separator()); + menu.Items.Add(_menuReinstall); + menu.Items.Add(_menuUninstallThenReinstall); + menu.Items.Add(new Separator()); + menu.Items.Add(_menuIgnoreUpdates); + menu.Items.Add(new Separator()); + menu.Items.Add(_menuDetails); + + return menu; + } + + protected override void WhenShowingContextMenu(IPackage package) + { + if (_menuAsAdmin is null || _menuInteractive is null || _menuRemoveData is null + || _menuInstallationOptions is null || _menuReinstall is null + || _menuUninstallThenReinstall is null || _menuIgnoreUpdates is null + || _menuDetails is null + || _menuOpenInstallLocation is null || _menuDownloadInstaller is null) + { + Logger.Warn("Context menu items are null on InstalledPackagesPage"); + return; + } + + bool isLocal = package.Source.IsVirtualManager; + var caps = package.Manager.Capabilities; + + _menuAsAdmin.IsEnabled = caps.CanRunAsAdmin; + _menuInteractive.IsEnabled = caps.CanRunInteractively; + _menuRemoveData.IsEnabled = caps.CanRemoveDataOnUninstall; + _menuDownloadInstaller.IsEnabled = !isLocal && caps.CanDownloadInstaller; + _menuInstallationOptions.IsEnabled = !isLocal; + _menuReinstall.IsEnabled = !isLocal; + _menuUninstallThenReinstall.IsEnabled = !isLocal; + _menuDetails.IsEnabled = !isLocal; + _menuOpenInstallLocation.IsEnabled = + package.Manager.DetailsHelper.GetInstallLocation(package) is not null; + + // Async ignore-state toggle label — fire and forget is fine here + _ = UpdateIgnoreMenuItemAsync(package); + } + + // ─── Abstract action overrides ──────────────────────────────────────────── + protected override void PerformMainPackageAction(IPackage? package) + { + if (package is null) return; + _ = LaunchUninstall([package]); + } + + protected override async Task ShowDetailsForPackage(IPackage? package) + { + if (package is null) return; + if (GetMainWindow() is not { } win) return; + + var dialog = new PackageDetailsWindow(package, OperationType.Uninstall); + await dialog.ShowDialog(win); + + if (dialog.ShouldProceedWithOperation) + await LaunchUninstall([package]); + } + + protected override async Task ShowInstallationOptionsForPackage(IPackage? package) + { + if (package is null || package.Source.IsVirtualManager) return; + var opts = await InstallOptionsFactory.LoadForPackageAsync(package); + if (GetMainWindow() is not { } win) return; + + var dialog = new InstallOptionsWindow(package, OperationType.Uninstall, opts); + await dialog.ShowDialog(win); + await InstallOptionsFactory.SaveForPackageAsync(opts, package); + + if (dialog.ShouldProceedWithOperation) + await LaunchUninstall([package]); + } + + // ─── WinGet malfunction banner ──────────────────────────────────────────── + + private static void UpdateWinGetMalfunctionBanner(bool malfunction) + { + if (MainWindow.Instance?.DataContext is not MainWindowViewModel vm) return; + var banner = vm.WinGetWarningBanner; + if (malfunction) + { + banner.Title = CoreTools.Translate("WinGet malfunction detected"); + banner.Message = CoreTools.Translate( + "It looks like WinGet is not working properly. Do you want to attempt to repair WinGet?"); + banner.ActionButtonText = CoreTools.Translate("Repair WinGet"); + banner.ActionButtonCommand = new AsyncRelayCommand(AvaloniaPackageOperationHelper.HandleBrokenWinGetAsync); + banner.IsClosable = true; + banner.IsOpen = true; + } + else + { + banner.IsOpen = false; + banner.ActionButtonText = ""; + banner.ActionButtonCommand = null; + } + } + + // ─── Page-specific actions ──────────────────────────────────────────────── + + private static void OpenInstallLocation(IPackage? package) + { + if (package is null) return; + var path = package.Manager.DetailsHelper.GetInstallLocation(package); + if (path is not null) + Process.Start(new ProcessStartInfo(path) { UseShellExecute = true }); + } + + private static async Task ExportSelectionToBundleAsync(PackagesPageViewModel vm) + { + var packages = vm.FilteredPackages.GetCheckedPackages(); + GetMainWindow()?.Navigate(PageType.Bundles); + if (PackageBundlesLoader.Instance is not null) + await PackageBundlesLoader.Instance.AddPackagesAsync(packages); + } + + private static async Task LaunchUninstall( + IEnumerable packages, + bool? elevated = null, + bool? interactive = null, + bool? remove_data = null) + { + var list = packages.ToList(); + if (list.Count == 0) return; + + foreach (var pkg in list) + { + var opts = await InstallOptionsFactory.LoadApplicableAsync( + pkg, elevated: elevated, interactive: interactive, remove_data: remove_data); + var op = new UninstallPackageOperation(pkg, opts); + op.OperationSucceeded += (_, _) => TelemetryHandler.UninstallPackage(pkg, TEL_OP_RESULT.SUCCESS); + op.OperationFailed += (_, _) => TelemetryHandler.UninstallPackage(pkg, TEL_OP_RESULT.FAILED); + AvaloniaOperationRegistry.Add(op); + _ = op.MainThread(); + } + } + + private static async Task LaunchReinstall(IPackage? package) + { + if (package is null || package.Source.IsVirtualManager) return; + var opts = await InstallOptionsFactory.LoadApplicableAsync(package); + var op = new InstallPackageOperation(package, opts); + op.OperationSucceeded += (_, _) => TelemetryHandler.InstallPackage(package, TEL_OP_RESULT.SUCCESS, TEL_InstallReferral.ALREADY_INSTALLED); + op.OperationFailed += (_, _) => TelemetryHandler.InstallPackage(package, TEL_OP_RESULT.FAILED, TEL_InstallReferral.ALREADY_INSTALLED); + AvaloniaOperationRegistry.Add(op); + _ = op.MainThread(); + } + + private static async Task LaunchUninstallThenReinstall(IPackage? package) + { + if (package is null || package.Source.IsVirtualManager) return; + var uninstallOpts = await InstallOptionsFactory.LoadApplicableAsync(package); + var reinstallOpts = await InstallOptionsFactory.LoadApplicableAsync(package); + var uninstallOp = new UninstallPackageOperation(package, uninstallOpts); + uninstallOp.OperationSucceeded += (_, _) => TelemetryHandler.UninstallPackage(package, TEL_OP_RESULT.SUCCESS); + uninstallOp.OperationFailed += (_, _) => TelemetryHandler.UninstallPackage(package, TEL_OP_RESULT.FAILED); + var reinstallOp = new InstallPackageOperation(package, reinstallOpts, req: uninstallOp); + reinstallOp.OperationSucceeded += (_, _) => TelemetryHandler.InstallPackage(package, TEL_OP_RESULT.SUCCESS, TEL_InstallReferral.ALREADY_INSTALLED); + reinstallOp.OperationFailed += (_, _) => TelemetryHandler.InstallPackage(package, TEL_OP_RESULT.FAILED, TEL_InstallReferral.ALREADY_INSTALLED); + AvaloniaOperationRegistry.Add(uninstallOp); + AvaloniaOperationRegistry.Add(reinstallOp); + _ = uninstallOp.MainThread(); + _ = reinstallOp.MainThread(); + } + + private static async Task ToggleIgnoreUpdatesAsync(IPackage? package) + { + if (package is null || package.Source.IsVirtualManager) return; + if (await package.HasUpdatesIgnoredAsync()) + { + await package.RemoveFromIgnoredUpdatesAsync(); + AccessibilityAnnouncementService.Announce( + CoreTools.Translate("Updates will no longer be ignored for {0}", package.Name)); + } + else + { + await package.AddToIgnoredUpdatesAsync(); + UpgradablePackagesLoader.Instance.Remove(package); + AccessibilityAnnouncementService.Announce( + CoreTools.Translate("Updates are now ignored for {0}", package.Name)); + } + } + + private async Task UpdateIgnoreMenuItemAsync(IPackage package) + { + if (_menuIgnoreUpdates is null || package.Source.IsVirtualManager) return; + _menuIgnoreUpdates.IsEnabled = false; + bool ignored = await package.HasUpdatesIgnoredAsync(); + _menuIgnoreUpdates.Header = ignored + ? CoreTools.Translate("Do not ignore updates for this package anymore") + : CoreTools.Translate("Ignore updates for this package"); + _menuIgnoreUpdates.IsEnabled = true; + } +} diff --git a/src/UniGetUI.Avalonia/Views/SoftwarePages/Interfaces/PageInterfaces.cs b/src/UniGetUI.Avalonia/Views/SoftwarePages/Interfaces/PageInterfaces.cs new file mode 100644 index 0000000..0a013ff --- /dev/null +++ b/src/UniGetUI.Avalonia/Views/SoftwarePages/Interfaces/PageInterfaces.cs @@ -0,0 +1,44 @@ +namespace UniGetUI.Avalonia.Views.Pages; + +/// +/// Implemented by pages that listen to keyboard shortcut triggers from MainWindow. +/// Mirrors UniGetUI.Pages.PageInterfaces.IKeyboardShortcutListener +/// +public interface IKeyboardShortcutListener +{ + void SearchTriggered(); + void ReloadTriggered(); + void SelectAllTriggered(); + void DetailsTriggered(); +} + +/// +/// Implemented by pages that have enter/leave lifecycle events. +/// Mirrors UniGetUI.Pages.PageInterfaces.IEnterLeaveListener +/// +public interface IEnterLeaveListener +{ + void OnEnter(); + void OnLeave(); +} + +/// +/// Implemented by pages that bind to the global search box. +/// Mirrors UniGetUI.Pages.PageInterfaces.ISearchBoxPage +/// +public interface ISearchBoxPage +{ + string QueryBackup { get; set; } + string SearchBoxPlaceholder { get; } + void SearchBox_QuerySubmitted(object? sender, EventArgs? e); +} + +/// +/// Implemented by pages that have their own internal navigation stack (e.g. Settings). +/// Mirrors UniGetUI.Pages.PageInterfaces.IInnerNavigationPage +/// +public interface IInnerNavigationPage +{ + bool CanGoBack(); + void GoBack(); +} diff --git a/src/UniGetUI.Avalonia/Views/SoftwarePages/PackageBundlesPage.cs b/src/UniGetUI.Avalonia/Views/SoftwarePages/PackageBundlesPage.cs new file mode 100644 index 0000000..8e73029 --- /dev/null +++ b/src/UniGetUI.Avalonia/Views/SoftwarePages/PackageBundlesPage.cs @@ -0,0 +1,676 @@ +using System.Text.Json; +using System.Text.Json.Nodes; +using Avalonia.Controls; +using Avalonia.Platform.Storage; +using UniGetUI.Avalonia.Infrastructure; +using UniGetUI.Avalonia.ViewModels.Pages; +using UniGetUI.Avalonia.Views.DialogPages; +using UniGetUI.Core.Data; +using UniGetUI.Core.Logging; +using UniGetUI.Core.SettingsEngine; +using UniGetUI.Core.SettingsEngine.SecureSettings; +using UniGetUI.Core.Tools; +using UniGetUI.Interface.Enums; +using UniGetUI.Interface.Telemetry; +using UniGetUI.PackageEngine; +using UniGetUI.PackageEngine.Classes.Serializable; +using UniGetUI.PackageEngine.Enums; +using UniGetUI.PackageEngine.Interfaces; +using UniGetUI.PackageEngine.Operations; +using UniGetUI.PackageEngine.PackageClasses; +using UniGetUI.PackageEngine.PackageLoader; + +namespace UniGetUI.Avalonia.Views.Pages; + +public class PackageBundlesPage : AbstractPackagesPage +{ + // Context-menu items whose enabled state depends on the focused package + private MenuItem? _menuInstall; + private MenuItem? _menuInstallOptions; + private MenuItem? _menuAsAdmin; + private MenuItem? _menuInteractive; + private MenuItem? _menuSkipHash; + private MenuItem? _menuDownloadInstaller; + private MenuItem? _menuDetails; + + private readonly PackageBundlesLoader _loader; + + private bool _hasUnsavedChanges; + public bool HasUnsavedChanges + { + get => _hasUnsavedChanges; + private set + { + _hasUnsavedChanges = value; + UnsavedChangesStateChanged?.Invoke(this, EventArgs.Empty); + } + } + public event EventHandler? UnsavedChangesStateChanged; + + public PackageBundlesPage() : base(new PackagesPageData + { + PageName = "SoftwarePages.PackageBundlesPage", + PageTitle = CoreTools.Translate("Package Bundles"), + IconName = "PackagesBundle", + PageRole = OperationType.Install, + Loader = PackageBundlesLoader.Instance!, + MegaQueryBlockEnabled = false, + DisableSuggestedResultsRadio = true, + PackagesAreCheckedByDefault = false, + ShowLastLoadTime = false, + DisableAutomaticPackageLoadOnStart = true, + DisableFilterOnQueryChange = false, + DisableReload = true, + NoPackages_BackgroundText = CoreTools.Translate("Add packages or open an existing package bundle"), + NoPackages_ImagePath = "avares://UniGetUI/Assets/Images/Empty_inbox.png", + NoPackages_SourcesText = CoreTools.Translate("Add packages to start"), + NoPackages_SubtitleText_Base = CoreTools.Translate("The current bundle has no packages. Add some packages to get started"), + MainSubtitle_StillLoading = CoreTools.Translate("Loading packages"), + NoMatches_BackgroundText = CoreTools.Translate("No results were found matching the input criteria"), + }) + { + _loader = PackageBundlesLoader.Instance!; + _loader.PackagesChanged += (_, _) => HasUnsavedChanges = true; + } + + // ─── Toolbar ────────────────────────────────────────────────────────────── + protected override void GenerateToolBar(PackagesPageViewModel vm) + { + var installAsAdmin = new MenuItem { Header = CoreTools.Translate("Install as administrator"), IsVisible = OperatingSystem.IsWindows() }; + var installInteractive = new MenuItem { Header = CoreTools.Translate("Interactive installation") }; + var installSkipHash = new MenuItem { Header = CoreTools.Translate("Skip integrity checks") }; + var downloadInstallers = new MenuItem { Header = CoreTools.Translate("Download selected installers") }; + + SetMainButton("download", CoreTools.Translate("Install selection"), () => + _ = ImportAndInstallPackage(GetCheckedNonInstalledPackages(vm))); + + SetMainButtonDropdown(new MenuFlyout + { + Items = { installAsAdmin, installInteractive, installSkipHash, new Separator(), downloadInstallers }, + }); + + installAsAdmin.Click += (_, _) => _ = ImportAndInstallPackage(GetCheckedNonInstalledPackages(vm), elevated: true); + installInteractive.Click += (_, _) => _ = ImportAndInstallPackage(GetCheckedNonInstalledPackages(vm), interactive: true); + installSkipHash.Click += (_, _) => _ = ImportAndInstallPackage(GetCheckedNonInstalledPackages(vm), skiphash: true); + downloadInstallers.Click += (_, _) => _ = AvaloniaPackageOperationHelper.DownloadSelectedAsync( + GetCheckedNonInstalledPackages(vm), TEL_InstallReferral.FROM_BUNDLE); + + ViewModel.AddToolbarSeparator(); + ViewModel.AddToolbarButton("add_to", CoreTools.Translate("New"), + () => _ = AskForNewBundle()); + ViewModel.AddToolbarButton("open_folder", CoreTools.Translate("Open"), + () => _ = AskOpenFromFile()); + ViewModel.AddToolbarButton("save_as", CoreTools.Translate("Save as"), + () => _ = SaveFile()); + ViewModel.AddToolbarButton("console", CoreTools.Translate("Create .ps1 script"), + () => _ = CreateBatchScriptAsync()); + ViewModel.AddToolbarSeparator(); + ViewModel.AddToolbarButton("delete", CoreTools.Translate("Remove selection from bundle"), () => + { + HasUnsavedChanges = true; + _loader.RemoveRange(vm.FilteredPackages.GetCheckedPackages()); + }); + ViewModel.AddToolbarSeparator(); + ViewModel.AddToolbarButton("info_round", CoreTools.Translate("Package details"), + () => _ = ShowDetailsForPackage(SelectedItem), showLabel: false); + } + + private static IReadOnlyList GetCheckedNonInstalledPackages(PackagesPageViewModel vm) + { + if (Settings.Get(Settings.K.InstallInstalledPackagesBundlesPage)) + return vm.FilteredPackages.GetCheckedPackages(); + + return vm.FilteredPackages.GetCheckedPackages() + .Where(p => p.Tag is not PackageTag.AlreadyInstalled) + .ToList(); + } + + // ─── Context menu ───────────────────────────────────────────────────────── + protected override ContextMenu? GenerateContextMenu() + { + _menuInstall = new MenuItem { Header = ShortcutHeader(CoreTools.Translate("Install"), MainActionShortcut), Icon = LoadMenuIcon("download") }; + _menuInstall.Click += (_, _) => _ = ImportAndInstallPackage(SelectedItem is { } p ? [p] : []); + + _menuInstallOptions = new MenuItem { Header = ShortcutHeader(CoreTools.Translate("Install options"), OptionsShortcut), Icon = LoadMenuIcon("options") }; + _menuInstallOptions.Click += (_, _) => + { + if (SelectedItem is ImportedPackage imported) + { + HasUnsavedChanges = true; + _ = ShowInstallationOptionsForPackage(imported); + } + }; + + _menuAsAdmin = new MenuItem { Header = CoreTools.Translate("Install as administrator"), Icon = LoadMenuIcon("uac"), IsVisible = OperatingSystem.IsWindows() }; + _menuAsAdmin.Click += (_, _) => _ = ImportAndInstallPackage(SelectedItem is { } p ? [p] : [], elevated: true); + + _menuInteractive = new MenuItem { Header = CoreTools.Translate("Interactive installation"), Icon = LoadMenuIcon("interactive") }; + _menuInteractive.Click += (_, _) => _ = ImportAndInstallPackage(SelectedItem is { } p ? [p] : [], interactive: true); + + _menuSkipHash = new MenuItem { Header = CoreTools.Translate("Skip hash checks"), Icon = LoadMenuIcon("checksum") }; + _menuSkipHash.Click += (_, _) => _ = ImportAndInstallPackage(SelectedItem is { } p ? [p] : [], skiphash: true); + + _menuDownloadInstaller = new MenuItem { Header = CoreTools.Translate("Download installer"), Icon = LoadMenuIcon("download") }; + _menuDownloadInstaller.Click += (_, _) => _ = AvaloniaPackageOperationHelper.AskLocationAndDownloadAsync( + SelectedItem, TEL_InstallReferral.FROM_BUNDLE); + + var menuRemoveFromList = new MenuItem { Header = CoreTools.Translate("Remove from list"), Icon = LoadMenuIcon("delete") }; + menuRemoveFromList.Click += (_, _) => + { + if (SelectedItem is { } pkg) + { + HasUnsavedChanges = true; + _loader.Remove(pkg); + } + }; + + _menuDetails = new MenuItem { Header = ShortcutHeader(CoreTools.Translate("Package details"), DetailsShortcut), Icon = LoadMenuIcon("info_round") }; + _menuDetails.Click += (_, _) => _ = ShowDetailsForPackage(SelectedItem); + + var menu = new ContextMenu(); + menu.Items.Add(_menuInstall); + menu.Items.Add(new Separator()); + menu.Items.Add(_menuInstallOptions); + menu.Items.Add(new Separator()); + menu.Items.Add(_menuAsAdmin); + menu.Items.Add(_menuInteractive); + menu.Items.Add(_menuSkipHash); + menu.Items.Add(_menuDownloadInstaller); + menu.Items.Add(new Separator()); + menu.Items.Add(menuRemoveFromList); + menu.Items.Add(new Separator()); + menu.Items.Add(_menuDetails); + return menu; + } + + protected override void WhenShowingContextMenu(IPackage package) + { + if (_menuInstall is null || _menuInstallOptions is null || _menuAsAdmin is null + || _menuInteractive is null || _menuSkipHash is null || _menuDownloadInstaller is null + || _menuDetails is null) + { + Logger.Warn("Context menu items are null on PackageBundlesPage"); + return; + } + + bool isValid = package is not InvalidImportedPackage; + var caps = package.Manager.Capabilities; + + _menuInstall.IsEnabled = isValid; + _menuInstallOptions.IsEnabled = isValid; + _menuAsAdmin.IsEnabled = isValid && caps.CanRunAsAdmin; + _menuInteractive.IsEnabled = isValid && caps.CanRunInteractively; + _menuSkipHash.IsEnabled = isValid && caps.CanSkipIntegrityChecks; + _menuDownloadInstaller.IsEnabled = isValid && caps.CanDownloadInstaller; + _menuDetails.IsEnabled = isValid; + } + + // ─── Abstract action overrides ──────────────────────────────────────────── + protected override void PerformMainPackageAction(IPackage? package) + { + if (package is null) return; + _ = ImportAndInstallPackage([package]); + } + + protected override async Task ShowDetailsForPackage(IPackage? package) + { + if (package is null || package is InvalidImportedPackage) return; + if (GetMainWindow() is not { } win) return; + + var dialog = new PackageDetailsWindow(package, OperationType.None); + await dialog.ShowDialog(win); + + if (dialog.ShouldProceedWithOperation) + _ = ImportAndInstallPackage([package]); + } + + protected override async Task ShowInstallationOptionsForPackage(IPackage? package) + { + if (package is not ImportedPackage imported) return; + if (GetMainWindow() is not { } win) return; + + var opts = imported.installation_options; + var dialog = new InstallOptionsWindow(imported, OperationType.Install, opts); + await dialog.ShowDialog(win); + + if (dialog.ShouldProceedWithOperation) + _ = ImportAndInstallPackage([imported]); + } + + // ─── Bundle operations ──────────────────────────────────────────────────── + public async Task AskForNewBundle() + { + if (_loader.Any() && HasUnsavedChanges && !await AskLoseChanges()) + return false; + + _loader.ClearPackages(); + HasUnsavedChanges = false; + return true; + } + + public async Task ImportAndInstallPackage( + IReadOnlyList packages, + bool? elevated = null, + bool? interactive = null, + bool? skiphash = null) + { + var toInstall = new List(); + foreach (var package in packages) + { + if (package is ImportedPackage imported) + { + Logger.ImportantInfo($"Registering package {imported.Id} from manager {imported.Source.AsString}"); + toInstall.Add(await imported.RegisterAndGetPackageAsync()); + } + else + { + Logger.Warn($"Attempted to install an invalid/incompatible package with Id={package.Id}"); + } + } + + foreach (var pkg in toInstall) + { + var opts = await InstallOptionsFactory.LoadApplicableAsync( + pkg, elevated: elevated, interactive: interactive, no_integrity: skiphash); + var op = new InstallPackageOperation(pkg, opts); + op.OperationSucceeded += (_, _) => TelemetryHandler.InstallPackage(pkg, TEL_OP_RESULT.SUCCESS, TEL_InstallReferral.FROM_BUNDLE); + op.OperationFailed += (_, _) => TelemetryHandler.InstallPackage(pkg, TEL_OP_RESULT.FAILED, TEL_InstallReferral.FROM_BUNDLE); + AvaloniaOperationRegistry.Add(op); + _ = op.MainThread(); + } + } + + public async Task OpenFromFile(string file) + { + try + { + var formatType = file.Split('.')[^1].ToLower() switch + { + "yaml" => BundleFormatType.YAML, + "xml" => BundleFormatType.XML, + "json" => BundleFormatType.JSON, + _ => BundleFormatType.UBUNDLE, + }; + + string fileContent = await File.ReadAllTextAsync(file); + await OpenFromString(fileContent, formatType, file, null); + } + catch (Exception ex) + { + Logger.Error("An error occurred while attempting to open a bundle"); + Logger.Error(ex); + if (GetMainWindow() is { } win) + await ShowErrorDialog(win, + CoreTools.Translate("The package bundle is not valid"), + CoreTools.Translate("The bundle you are trying to load appears to be invalid. Please check the file and try again.") + + "\n\n" + ex.Message); + } + } + + public async Task OpenFromString(string payload, BundleFormatType format, string source, int? _loadingId = null) + { + if (!await AskForNewBundle()) return; + + var (openVersion, report) = await AddFromBundle(payload, format); + TelemetryHandler.ImportBundle(format); + HasUnsavedChanges = false; + + if ((int)(openVersion * 10) != (int)(SerializableBundle.ExpectedVersion * 10)) + Logger.Warn($"Bundle \"{source}\" uses schema version {openVersion}, expected {SerializableBundle.ExpectedVersion}."); + + if (!report.IsEmpty && GetMainWindow() is { } win) + await ShowBundleSecurityReport(win, report); + } + + /// Compatibility overload matching the legacy stub signature. + public Task OpenFromString(string payload, object format, string source, int loadingId) + => OpenFromString(payload, + format is BundleFormatType f ? f : BundleFormatType.UBUNDLE, + source, (int?)loadingId); + + public async Task AskOpenFromFile() + { + if (!await AskForNewBundle()) return; + if (GetMainWindow() is not { } win) return; + + var files = await win.StorageProvider.OpenFilePickerAsync(new FilePickerOpenOptions + { + AllowMultiple = false, + FileTypeFilter = + [ + new FilePickerFileType("Package bundles") { Patterns = ["*.ubundle", "*.json", "*.yaml", "*.xml"] }, + new FilePickerFileType("All files") { Patterns = ["*"] }, + ], + }); + + if (files is not [{ } file]) return; + var path = file.TryGetLocalPath(); + if (path is null) return; + + await OpenFromFile(path); + } + + public async Task SaveFile() + { + if (GetMainWindow() is not { } win) return; + + var file = await win.StorageProvider.SaveFilePickerAsync(new FilePickerSaveOptions + { + SuggestedFileName = CoreTools.Translate("Package bundle") + ".ubundle", + FileTypeChoices = + [ + new FilePickerFileType("UniGetUI Bundle") { Patterns = ["*.ubundle"] }, + new FilePickerFileType("JSON") { Patterns = ["*.json"] }, + ], + }); + + if (file is null) return; + var path = file.TryGetLocalPath(); + if (path is null) return; + + try + { + var content = await CreateBundle(_loader.Packages); + await File.WriteAllTextAsync(path, content); + + var formatType = path.Split('.')[^1].ToLower() == "json" + ? BundleFormatType.JSON : BundleFormatType.UBUNDLE; + TelemetryHandler.ExportBundle(formatType); + + HasUnsavedChanges = false; + await CoreTools.ShowFileOnExplorer(path); + } + catch (Exception ex) + { + Logger.Error("An error occurred when saving packages to a file"); + Logger.Error(ex); + await ShowErrorDialog(win, + CoreTools.Translate("Could not create bundle"), + CoreTools.Translate("The package bundle could not be created due to an error.") + + "\n\n" + ex.Message); + } + } + + public static async Task CreateBundle(IReadOnlyList unsortedPackages) + { + var exportableData = new SerializableBundle(); + var packages = unsortedPackages.ToList(); + packages.Sort((x, y) => + { + if (x.Id != y.Id) return string.Compare(x.Id, y.Id, StringComparison.Ordinal); + if (x.Name != y.Name) return string.Compare(x.Name, y.Name, StringComparison.Ordinal); + return x.NormalizedVersion > y.NormalizedVersion ? -1 : 1; + }); + + foreach (var package in packages) + { + if (package is Package && !package.Source.IsVirtualManager) + exportableData.packages.Add(await package.AsSerializableAsync()); + else + exportableData.incompatible_packages.Add(package.AsSerializable_Incompatible()); + } + + return exportableData.AsJsonString(); + } + + public async Task<(double, BundleReport)> AddFromBundle(string content, BundleFormatType format) + { + if (format is BundleFormatType.YAML) + { + content = await SerializationHelpers.YAML_to_JSON(content); + Logger.ImportantInfo("YAML bundle was converted to JSON before deserialization"); + } + if (format is BundleFormatType.XML) + { + content = await SerializationHelpers.XML_to_JSON(content); + Logger.ImportantInfo("XML bundle was converted to JSON before deserialization"); + } + + var deserializedData = await Task.Run(() => + new SerializableBundle(JsonNode.Parse(content) + ?? throw new JsonException("Could not parse JSON object"))); + + var report = new BundleReport { IsEmpty = true }; + bool allowCLI = SecureSettings.Get(SecureSettings.K.AllowCLIArguments) + && SecureSettings.Get(SecureSettings.K.AllowImportingCLIArguments); + bool allowPrePost = SecureSettings.Get(SecureSettings.K.AllowPrePostOpCommand) + && SecureSettings.Get(SecureSettings.K.AllowImportPrePostOpCommands); + + var packages = new List(); + foreach (var pkg in deserializedData.packages) + { + var opts = pkg.InstallationOptions; + ReportList(ref report, pkg.Id, opts.CustomParameters_Install, "Custom install arguments", allowCLI); + ReportList(ref report, pkg.Id, opts.CustomParameters_Update, "Custom update arguments", allowCLI); + ReportList(ref report, pkg.Id, opts.CustomParameters_Uninstall, "Custom uninstall arguments", allowCLI); + opts.PreInstallCommand = ReportStr(ref report, pkg.Id, opts.PreInstallCommand, "Pre-install command", allowPrePost); + opts.PostInstallCommand = ReportStr(ref report, pkg.Id, opts.PostInstallCommand, "Post-install command", allowPrePost); + opts.PreUpdateCommand = ReportStr(ref report, pkg.Id, opts.PreUpdateCommand, "Pre-update command", allowPrePost); + opts.PostUpdateCommand = ReportStr(ref report, pkg.Id, opts.PostUpdateCommand, "Post-update command", allowPrePost); + opts.PreUninstallCommand = ReportStr(ref report, pkg.Id, opts.PreUninstallCommand, "Pre-uninstall command", allowPrePost); + opts.PostUninstallCommand = ReportStr(ref report, pkg.Id, opts.PostUninstallCommand, "Post-uninstall command", allowPrePost); + pkg.InstallationOptions = opts; + packages.Add(DeserializePackage(pkg)); + } + + foreach (var pkg in deserializedData.incompatible_packages) + packages.Add(DeserializeIncompatiblePackage(pkg, NullSource.Instance)); + + await PackageBundlesLoader.Instance.AddPackagesAsync(packages); + + return (deserializedData.export_version, report); + } + + // ─── Deserialization helpers ────────────────────────────────────────────── + public static IPackage DeserializePackage(SerializablePackage raw) + { + IPackageManager? manager = null; + foreach (var m in PEInterface.Managers) + { + if (m.Id == raw.ManagerName || m.Name == raw.ManagerName || m.DisplayName == raw.ManagerName) + { manager = m; break; } + } + + IManagerSource? source; + if (manager?.Capabilities.SupportsCustomSources == true) + { + if (raw.Source.Contains(": ")) + raw.Source = raw.Source.Split(": ")[^1]; + source = manager?.SourcesHelper?.Factory.GetSourceIfExists(raw.Source); + } + else + source = manager?.DefaultSource; + + if (manager is null || source is null) + return DeserializeIncompatiblePackage(raw.GetInvalidEquivalent(), NullSource.Instance); + + return new ImportedPackage(raw, manager, source); + } + + public static IPackage DeserializeIncompatiblePackage(SerializableIncompatiblePackage raw, IManagerSource source) + => new InvalidImportedPackage(raw, source); + + // ─── Security report helpers ────────────────────────────────────────────── + private static void ReportList(ref BundleReport report, string id, List values, string label, bool allowed) + { + if (!values.Any(x => x.Any())) return; + if (!report.Contents.ContainsKey(id)) report.Contents[id] = []; + report.Contents[id].Add(new BundleReportEntry($"{label}: [{string.Join(", ", values)}]", allowed)); + report.IsEmpty = false; + if (!allowed) values.Clear(); + } + + private static string ReportStr(ref BundleReport report, string id, string value, string label, bool allowed) + { + if (!value.Any()) return value; + if (!report.Contents.ContainsKey(id)) report.Contents[id] = []; + report.Contents[id].Add(new BundleReportEntry($"{label}: {value}", allowed)); + report.IsEmpty = false; + return allowed ? value : ""; + } + + // ─── Batch script export ────────────────────────────────────────────────── + private async Task CreateBatchScriptAsync() + { + try + { + if (GetMainWindow() is not { } win) return; + + string defaultName = CoreTools.Translate("Install script") + ".ps1"; + var file = await win.StorageProvider.SaveFilePickerAsync(new FilePickerSaveOptions + { + SuggestedFileName = defaultName, + FileTypeChoices = + [ + new FilePickerFileType(CoreTools.Translate("PowerShell script")) { Patterns = ["*.ps1"] }, + ], + }); + + var path = file?.TryGetLocalPath(); + if (path is null) return; + + var packages = new List(); + var commands = new List(); + + bool forceKill = Settings.Get(Settings.K.KillProcessesThatRefuseToDie); + foreach (var p in _loader.Packages) + { + if (p is not ImportedPackage pkg) continue; + + packages.Add(pkg.Name + " from " + pkg.Manager.DisplayName); + + foreach (var process in pkg.installation_options.KillBeforeOperation) + commands.Add($"taskkill /im \"{process}\"" + (forceKill ? " /f" : "")); + + if (pkg.installation_options.PreInstallCommand != "") + commands.Add(pkg.installation_options.PreInstallCommand); + + var param = pkg.Manager.OperationHelper.GetParameters( + pkg, pkg.installation_options, OperationType.Install); + commands.Add($"{pkg.Manager.Properties.ExecutableFriendlyName} {string.Join(' ', param)}"); + + if (pkg.installation_options.PostInstallCommand != "") + commands.Add(pkg.installation_options.PostInstallCommand); + } + + await File.WriteAllTextAsync(path, GenerateCommandString(packages, commands)); + + MainWindow.Instance?.ShowBanner( + CoreTools.Translate("Success!"), + CoreTools.Translate("The installation script saved to {0}", path), + MainWindow.RuntimeNotificationLevel.Success); + + TelemetryHandler.ExportBatch(); + await CoreTools.ShowFileOnExplorer(path); + } + catch (Exception ex) + { + Logger.Error("An error occurred while attempting to export an installation script"); + Logger.Error(ex); + MainWindow.Instance?.ShowBanner( + CoreTools.Translate("An error occurred"), + CoreTools.Translate("An error occurred while attempting to create an installation script:") + " " + ex.Message, + MainWindow.RuntimeNotificationLevel.Error); + } + } + + private static string GenerateCommandString(IReadOnlyList names, IReadOnlyList commands) + { + return $$""" + Clear-Host + Write-Host "" + Write-Host "========================================================" + Write-Host "" + Write-Host " __ __ _ ______ __ __ ______" -ForegroundColor Cyan + Write-Host " / / / /___ (_) ____/__ / _// / / / _/" -ForegroundColor Cyan + Write-Host " / / / / __ \/ / / __/ _ \/ __/ / / // /" -ForegroundColor Cyan + Write-Host " / /_/ / / / / / /_/ / __/ /_/ /_/ // /" -ForegroundColor Cyan + Write-Host " \____/_/ /_/_/\____/\___/\__/\____/___/" -ForegroundColor Cyan + Write-Host " UniGetUI Package Installer Script" + Write-Host " Created with UniGetUI Version {{CoreData.VersionName}}" + Write-Host "" + Write-Host "========================================================" + Write-Host "" + Write-Host "NOTES:" -ForegroundColor Yellow + Write-Host " - The install process will not be as reliable as importing a bundle with UniGetUI. Expect issues and errors." -ForegroundColor Yellow + Write-Host " - Packages will be installed with the install options specified at the time of creation of this script." -ForegroundColor Yellow + Write-Host " - Error/Success detection may not be 100% accurate." -ForegroundColor Yellow + Write-Host " - Some of the packages may require elevation. Some of them may ask for permission, but others may fail. Consider running this script elevated." -ForegroundColor Yellow + Write-Host " - You can skip confirmation prompts by running this script with the parameter `/DisablePausePrompts` " -ForegroundColor Yellow + Write-Host "" + Write-Host "" + if ($args[0] -ne "/DisablePausePrompts") { pause } + Write-Host "" + Write-Host "This script will attempt to install the following packages:" + {{string.Join('\n', names.Select(x => $"Write-Host \" - {x}\""))}} + Write-Host "" + if ($args[0] -ne "/DisablePausePrompts") { pause } + Clear-Host + + $success_count=0 + $failure_count=0 + $commands_run=0 + $results="" + + $commands= @( + {{string.Join( + ",\n ", + commands.Select(x => $"'{x.Replace("'", "''")}'") + )}} + ) + + foreach ($command in $commands) { + Write-Host "Running: $command" -ForegroundColor Yellow + cmd.exe /C $command + if ($LASTEXITCODE -eq 0) { + Write-Host "[ OK ] $command" -ForegroundColor Green + $success_count++ + $results += "$([char]0x1b)[32m[ OK ] $command`n" + } + else { + Write-Host "[ FAIL ] $command" -ForegroundColor Red + $failure_count++ + $results += "$([char]0x1b)[31m[ FAIL ] $command`n" + } + $commands_run++ + Write-Host "" + } + + Write-Host "========================================================" + Write-Host " OPERATION SUMMARY" + Write-Host "========================================================" + Write-Host "Total commands run: $commands_run" + Write-Host "Successful: $success_count" + Write-Host "Failed: $failure_count" + Write-Host "" + Write-Host "Details:" + Write-Host "$results$([char]0x1b)[37m" + Write-Host "========================================================" + + if ($failure_count -gt 0) { + Write-Host "Some commands failed. Please check the log above." -ForegroundColor Yellow + } + else { + Write-Host "All commands executed successfully!" -ForegroundColor Green + } + Write-Host "" + if ($args[0] -ne "/DisablePausePrompts") { pause } + exit $failure_count + """; + } + + // ─── Dialog helpers ─────────────────────────────────────────────────────── + private static async Task AskLoseChanges() + { + if (GetMainWindow() is not { } owner) return false; + var dialog = new DiscardBundleChangesDialog(); + await dialog.ShowDialog(owner); + return dialog.Confirmed; + } + + private static async Task ShowBundleSecurityReport(Window owner, BundleReport report) + => await new BundleSecurityReportDialog(report).ShowDialog(owner); + + private static async Task ShowErrorDialog(Window owner, string title, string message) + => await new SimpleErrorDialog(title, message).ShowDialog(owner); +} diff --git a/src/UniGetUI.Avalonia/Views/SoftwarePages/PageStubs.cs b/src/UniGetUI.Avalonia/Views/SoftwarePages/PageStubs.cs new file mode 100644 index 0000000..9bffc3e --- /dev/null +++ b/src/UniGetUI.Avalonia/Views/SoftwarePages/PageStubs.cs @@ -0,0 +1,4 @@ +namespace UniGetUI.Avalonia.Views.Pages; + +// All log pages and HelpPage have been ported to proper AXAML views. +// This file is intentionally left as a placeholder. diff --git a/src/UniGetUI.Avalonia/Views/SoftwarePages/SoftwareUpdatesPage.cs b/src/UniGetUI.Avalonia/Views/SoftwarePages/SoftwareUpdatesPage.cs new file mode 100644 index 0000000..594f750 --- /dev/null +++ b/src/UniGetUI.Avalonia/Views/SoftwarePages/SoftwareUpdatesPage.cs @@ -0,0 +1,493 @@ +using System.Diagnostics; +using System.Runtime.InteropServices; +using Avalonia.Controls; +using UniGetUI.Avalonia.Infrastructure; +using UniGetUI.Avalonia.ViewModels.Pages; +using UniGetUI.Avalonia.Views; +using UniGetUI.Core.Logging; +using UniGetUI.Core.SettingsEngine; +using UniGetUI.Core.Tools; +using UniGetUI.Interface.Enums; +using UniGetUI.Interface.Telemetry; +using UniGetUI.PackageEngine.Classes.Manager.Classes; +using UniGetUI.PackageEngine.Classes.Packages.Classes; +using UniGetUI.PackageEngine.Enums; +using UniGetUI.PackageEngine.Interfaces; +using UniGetUI.PackageEngine.Operations; +using UniGetUI.PackageEngine.PackageClasses; +using UniGetUI.PackageEngine.PackageLoader; + +namespace UniGetUI.Avalonia.Views.Pages; + +public class SoftwareUpdatesPage : AbstractPackagesPage +{ + // Context-menu items whose enabled state depends on the focused package + private MenuItem? _menuAsAdmin; + private MenuItem? _menuInteractive; + private MenuItem? _menuSkipHash; + private MenuItem? _menuDownloadInstaller; + private MenuItem? _menuOpenInstallLocation; + + public SoftwareUpdatesPage() : base(new PackagesPageData + { + PageName = "SoftwarePages.SoftwareUpdatesPage", + PageTitle = CoreTools.Translate("Software Updates"), + IconName = "update", + PageRole = OperationType.Update, + Loader = UpgradablePackagesLoader.Instance ?? new UpgradablePackagesLoader([]), + MegaQueryBlockEnabled = false, + DisableSuggestedResultsRadio = true, + PackagesAreCheckedByDefault = true, + ShowLastLoadTime = true, + DisableAutomaticPackageLoadOnStart = false, + DisableFilterOnQueryChange = false, + DisableReload = false, + NoPackages_BackgroundText = CoreTools.Translate("Hooray! No updates were found."), + NoPackages_ImagePath = "avares://UniGetUI/Assets/Images/Trophee.png", + NoPackages_SourcesText = CoreTools.Translate("Everything is up to date"), + NoPackages_SubtitleText_Base = CoreTools.Translate("Everything is up to date"), + MainSubtitle_StillLoading = CoreTools.Translate("Loading packages"), + NoMatches_BackgroundText = CoreTools.Translate("No results were found matching the input criteria"), + }) + { + ViewModel.PackagesLoaded += reason => { _ = WhenPackagesLoaded(); }; + } + + protected override void GenerateToolBar(PackagesPageViewModel vm) + { + // ── Dropdown: update variants ─────────────────────────────────────── + var updateAsAdmin = new MenuItem { Header = CoreTools.Translate("Update as administrator"), IsVisible = OperatingSystem.IsWindows() }; + var updateSkipHash = new MenuItem { Header = CoreTools.Translate("Skip integrity checks") }; + var updateInteractive = new MenuItem { Header = CoreTools.Translate("Interactive update") }; + var downloadInstallers = new MenuItem { Header = CoreTools.Translate("Download selected installers") }; + var uninstallSelected = new MenuItem { Header = CoreTools.Translate("Uninstall selected packages") }; + + SetMainButton("update", CoreTools.Translate("Update selection"), () => + _ = LaunchUpdate(vm.FilteredPackages.GetCheckedPackages())); + + SetMainButtonDropdown(new MenuFlyout + { + Items = + { + updateAsAdmin, updateSkipHash, updateInteractive, + new Separator(), + downloadInstallers, + new Separator(), + uninstallSelected, + }, + }); + + updateAsAdmin.Click += (_, _) => _ = LaunchUpdate(vm.FilteredPackages.GetCheckedPackages(), elevated: true); + updateSkipHash.Click += (_, _) => _ = LaunchUpdate(vm.FilteredPackages.GetCheckedPackages(), no_integrity: true); + updateInteractive.Click += (_, _) => _ = LaunchUpdate(vm.FilteredPackages.GetCheckedPackages(), interactive: true); + downloadInstallers.Click += (_, _) => _ = AvaloniaPackageOperationHelper.DownloadSelectedAsync( + vm.FilteredPackages.GetCheckedPackages(), TEL_InstallReferral.ALREADY_INSTALLED); + uninstallSelected.Click += (_, _) => _ = LaunchUninstallFromUpdates(vm.FilteredPackages.GetCheckedPackages()); + + // ── Toolbar buttons ───────────────────────────────────────────────── + ViewModel.AddToolbarSeparator(); + ViewModel.AddToolbarButton("options", CoreTools.Translate("Update options"), + () => _ = ShowInstallationOptionsForPackage(SelectedItem), showLabel: false); + ViewModel.AddToolbarSeparator(); + ViewModel.AddToolbarButton("info_round", CoreTools.Translate("Package details"), + () => _ = ShowDetailsForPackage(SelectedItem), showLabel: false); + ViewModel.AddToolbarSeparator(); + ViewModel.AddToolbarButton("pin", CoreTools.Translate("Ignore selected packages"), async () => + { + foreach (var pkg in vm.FilteredPackages.GetCheckedPackages()) + { + await pkg.AddToIgnoredUpdatesAsync(); + UpgradablePackagesLoader.Instance.Remove(pkg); + UpgradablePackagesLoader.Instance.IgnoredPackages[pkg.Id] = pkg; + } + }); + ViewModel.AddToolbarButton("clipboard_list", CoreTools.Translate("Manage ignored updates"), + () => vm.RequestManageIgnoredCommand.Execute(null)); + } + + // ─── Context menu ───────────────────────────────────────────────────────── + protected override ContextMenu? GenerateContextMenu() + { + var menuUpdate = new MenuItem + { + Header = ShortcutHeader(CoreTools.Translate("Update"), MainActionShortcut), + Icon = LoadMenuIcon("update"), + }; + menuUpdate.Click += (_, _) => _ = LaunchUpdate([SelectedItem!]); + + var menuUpdateOptions = new MenuItem + { + Header = ShortcutHeader(CoreTools.Translate("Update options"), OptionsShortcut), + Icon = LoadMenuIcon("options"), + }; + menuUpdateOptions.Click += (_, _) => _ = ShowInstallationOptionsForPackage(SelectedItem); + + _menuOpenInstallLocation = new MenuItem + { + Header = CoreTools.Translate("Open install location"), + Icon = LoadMenuIcon("launch"), + }; + _menuOpenInstallLocation.Click += (_, _) => OpenInstallLocation(SelectedItem); + + _menuAsAdmin = new MenuItem + { + Header = CoreTools.Translate("Update as administrator"), + Icon = LoadMenuIcon("uac"), + IsVisible = OperatingSystem.IsWindows(), + }; + _menuAsAdmin.Click += (_, _) => _ = LaunchUpdate([SelectedItem!], elevated: true); + + _menuInteractive = new MenuItem + { + Header = CoreTools.Translate("Interactive update"), + Icon = LoadMenuIcon("interactive"), + }; + _menuInteractive.Click += (_, _) => _ = LaunchUpdate([SelectedItem!], interactive: true); + + _menuSkipHash = new MenuItem + { + Header = CoreTools.Translate("Skip hash check"), + Icon = LoadMenuIcon("checksum"), + }; + _menuSkipHash.Click += (_, _) => _ = LaunchUpdate([SelectedItem!], no_integrity: true); + + _menuDownloadInstaller = new MenuItem + { + Header = CoreTools.Translate("Download installer"), + Icon = LoadMenuIcon("download"), + }; + _menuDownloadInstaller.Click += (_, _) => _ = AvaloniaPackageOperationHelper.AskLocationAndDownloadAsync( + SelectedItem, TEL_InstallReferral.ALREADY_INSTALLED); + + var menuUninstallThenUpdate = new MenuItem + { + Header = CoreTools.Translate("Uninstall package, then update it"), + Icon = LoadMenuIcon("undelete"), + }; + menuUninstallThenUpdate.Click += (_, _) => _ = LaunchUninstallThenUpdate(SelectedItem); + + var menuUninstall = new MenuItem + { + Header = CoreTools.Translate("Uninstall package"), + Icon = LoadMenuIcon("delete"), + }; + menuUninstall.Click += (_, _) => _ = LaunchUninstallFromUpdates([SelectedItem!]); + + var menuIgnore = new MenuItem + { + Header = CoreTools.Translate("Ignore updates for this package"), + Icon = LoadMenuIcon("pin"), + }; + menuIgnore.Click += (_, _) => + { + var pkg = SelectedItem; + if (pkg is null) return; + _ = pkg.AddToIgnoredUpdatesAsync(); + UpgradablePackagesLoader.Instance.Remove(pkg); + UpgradablePackagesLoader.Instance.IgnoredPackages[pkg.Id] = pkg; + }; + + var menuSkipVersion = new MenuItem + { + Header = CoreTools.Translate("Skip this version"), + Icon = LoadMenuIcon("skip"), + }; + menuSkipVersion.Click += (_, _) => + { + var pkg = SelectedItem; + if (pkg is null) return; + _ = pkg.AddToIgnoredUpdatesAsync(pkg.NewVersionString); + UpgradablePackagesLoader.Instance.Remove(pkg); + UpgradablePackagesLoader.Instance.IgnoredPackages[pkg.Id] = pkg; + }; + + // ── Pause updates submenu ────────────────────────────────────────── + var menuPause = new MenuItem + { + Header = CoreTools.Translate("Pause updates for"), + Icon = LoadMenuIcon("sandclock"), + }; + foreach (var pauseTime in new[] + { + new IgnoredUpdatesDatabase.PauseTime { Days = 1 }, + new IgnoredUpdatesDatabase.PauseTime { Days = 3 }, + new IgnoredUpdatesDatabase.PauseTime { Weeks = 1 }, + new IgnoredUpdatesDatabase.PauseTime { Weeks = 2 }, + new IgnoredUpdatesDatabase.PauseTime { Weeks = 4 }, + new IgnoredUpdatesDatabase.PauseTime { Months = 3 }, + new IgnoredUpdatesDatabase.PauseTime { Months = 6 }, + new IgnoredUpdatesDatabase.PauseTime { Months = 12}, + }) + { + var t = pauseTime; + var item = new MenuItem { Header = t.StringRepresentation() }; + item.Click += (_, _) => + { + var pkg = SelectedItem; + if (pkg is null) return; + _ = pkg.AddToIgnoredUpdatesAsync("<" + t.GetDateFromNow()); + UpgradablePackagesLoader.Instance.IgnoredPackages[pkg.Id] = pkg; + UpgradablePackagesLoader.Instance.Remove(pkg); + }; + menuPause.Items.Add(item); + } + + var menuDetails = new MenuItem + { + Header = ShortcutHeader(CoreTools.Translate("Package details"), DetailsShortcut), + Icon = LoadMenuIcon("info_round"), + }; + menuDetails.Click += (_, _) => _ = ShowDetailsForPackage(SelectedItem); + + var menu = new ContextMenu(); + menu.Items.Add(menuUpdate); + menu.Items.Add(new Separator()); + menu.Items.Add(menuUpdateOptions); + menu.Items.Add(_menuOpenInstallLocation); + menu.Items.Add(new Separator()); + menu.Items.Add(_menuAsAdmin); + menu.Items.Add(_menuInteractive); + menu.Items.Add(_menuSkipHash); + menu.Items.Add(_menuDownloadInstaller); + menu.Items.Add(new Separator()); + menu.Items.Add(menuUninstallThenUpdate); + menu.Items.Add(menuUninstall); + menu.Items.Add(new Separator()); + menu.Items.Add(menuIgnore); + menu.Items.Add(menuSkipVersion); + menu.Items.Add(menuPause); + menu.Items.Add(new Separator()); + menu.Items.Add(menuDetails); + + return menu; + } + + protected override void WhenShowingContextMenu(IPackage package) + { + if (_menuAsAdmin is null || _menuInteractive is null || _menuSkipHash is null + || _menuDownloadInstaller is null || _menuOpenInstallLocation is null) + { + Logger.Warn("Context menu items are null on SoftwareUpdatesPage"); + return; + } + + var caps = package.Manager.Capabilities; + _menuAsAdmin.IsEnabled = caps.CanRunAsAdmin; + _menuInteractive.IsEnabled = caps.CanRunInteractively; + _menuSkipHash.IsEnabled = caps.CanSkipIntegrityChecks; + _menuDownloadInstaller.IsEnabled = caps.CanDownloadInstaller; + _menuOpenInstallLocation.IsEnabled = + package.Manager.DetailsHelper.GetInstallLocation(package) is not null; + } + + // ─── Abstract action overrides ──────────────────────────────────────────── + protected override void PerformMainPackageAction(IPackage? package) + { + if (package is null) return; + _ = LaunchUpdate([package]); + } + + protected override async Task ShowDetailsForPackage(IPackage? package) + { + if (package is null) return; + if (GetMainWindow() is not { } win) return; + + var dialog = new PackageDetailsWindow(package, OperationType.Update); + await dialog.ShowDialog(win); + + if (dialog.ShouldProceedWithOperation) + await LaunchUpdate([package]); + } + + protected override async Task ShowInstallationOptionsForPackage(IPackage? package) + { + if (package is null || package.Source.IsVirtualManager) return; + var opts = await InstallOptionsFactory.LoadForPackageAsync(package); + if (GetMainWindow() is not { } win) return; + + var dialog = new InstallOptionsWindow(package, OperationType.Update, opts); + await dialog.ShowDialog(win); + await InstallOptionsFactory.SaveForPackageAsync(opts, package); + + if (dialog.ShouldProceedWithOperation) + await LaunchUpdate([package]); + } + + // ─── Page-specific actions ──────────────────────────────────────────────── + + private static void OpenInstallLocation(IPackage? package) + { + if (package is null) return; + var path = package.Manager.DetailsHelper.GetInstallLocation(package); + if (path is not null) + Process.Start(new ProcessStartInfo(path) { UseShellExecute = true }); + } + + // ─── Operation launchers ────────────────────────────────────────────────── + private static async Task LaunchUpdate( + IEnumerable packages, + bool? elevated = null, + bool? interactive = null, + bool? no_integrity = null) + { + foreach (var pkg in packages) + { + var opts = await InstallOptionsFactory.LoadApplicableAsync( + pkg, elevated: elevated, interactive: interactive, no_integrity: no_integrity); + var op = new UpdatePackageOperation(pkg, opts); + op.OperationSucceeded += (_, _) => TelemetryHandler.UpdatePackage(pkg, TEL_OP_RESULT.SUCCESS); + op.OperationFailed += (_, _) => TelemetryHandler.UpdatePackage(pkg, TEL_OP_RESULT.FAILED); + AvaloniaOperationRegistry.Add(op); + _ = op.MainThread(); + } + } + + private static async Task LaunchUninstallFromUpdates(IEnumerable packages) + { + foreach (var pkg in packages) + { + var opts = await InstallOptionsFactory.LoadApplicableAsync(pkg); + var op = new UninstallPackageOperation(pkg, opts); + op.OperationSucceeded += (_, _) => TelemetryHandler.UninstallPackage(pkg, TEL_OP_RESULT.SUCCESS); + op.OperationFailed += (_, _) => TelemetryHandler.UninstallPackage(pkg, TEL_OP_RESULT.FAILED); + AvaloniaOperationRegistry.Add(op); + _ = op.MainThread(); + } + } + + private static async Task LaunchUninstallThenUpdate(IPackage? package) + { + if (package is null || package.Source.IsVirtualManager) return; + var uninstallOpts = await InstallOptionsFactory.LoadApplicableAsync(package); + var updateOpts = await InstallOptionsFactory.LoadApplicableAsync(package); + var uninstallOp = new UninstallPackageOperation(package, uninstallOpts); + uninstallOp.OperationSucceeded += (_, _) => TelemetryHandler.UninstallPackage(package, TEL_OP_RESULT.SUCCESS); + uninstallOp.OperationFailed += (_, _) => TelemetryHandler.UninstallPackage(package, TEL_OP_RESULT.FAILED); + var updateOp = new UpdatePackageOperation(package, updateOpts, req: uninstallOp); + updateOp.OperationSucceeded += (_, _) => TelemetryHandler.UpdatePackage(package, TEL_OP_RESULT.SUCCESS); + updateOp.OperationFailed += (_, _) => TelemetryHandler.UpdatePackage(package, TEL_OP_RESULT.FAILED); + AvaloniaOperationRegistry.Add(uninstallOp); + AvaloniaOperationRegistry.Add(updateOp); + _ = uninstallOp.MainThread(); + _ = updateOp.MainThread(); + } + + // ─── Auto-update on load ────────────────────────────────────────────────── + + private static async Task WhenPackagesLoaded() + { + try + { + var upgradable = UpgradablePackagesLoader.Instance.Packages + .Where(p => p.Tag is not PackageTag.OnQueue and not PackageTag.BeingProcessed) + .ToList(); + + if (upgradable.Count == 0) return; + + if (Settings.Get(Settings.K.DisableAUPOnBattery) && IsOnBattery()) + { + Logger.Warn("Updates will not be installed automatically because the device is on battery."); + ShowAvailableUpdatesNotification(upgradable); + } + else if (Settings.Get(Settings.K.DisableAUPOnBatterySaver) && IsBatterySaverOn()) + { + Logger.Warn("Updates will not be installed automatically because battery saver is enabled."); + ShowAvailableUpdatesNotification(upgradable); + } + else if (Settings.Get(Settings.K.DisableAUPOnMeteredConnections) && IsOnMeteredConnection()) + { + Logger.Warn("Updates will not be installed automatically because the current internet connection is metered."); + ShowAvailableUpdatesNotification(upgradable); + } + else if (Settings.Get(Settings.K.AutomaticallyUpdatePackages)) + { + _ = AvaloniaPackageOperationHelper.UpdateAllAsync(); + ShowUpgradingPackagesNotification(upgradable); + } + else if (Environment.GetCommandLineArgs().Contains("--updateapps")) + { + _ = AvaloniaPackageOperationHelper.UpdateAllAsync(); + ShowUpgradingPackagesNotification(upgradable); + Logger.Warn("Automatic install of updates has been enabled via Command Line (user settings have been overriden)"); + } + else + { + foreach (var package in upgradable) + { + var opts = await InstallOptionsFactory.LoadApplicableAsync(package); + if (opts.AutoUpdatePackage) + await LaunchUpdate([package]); + } + ShowAvailableUpdatesNotification(upgradable); + } + } + catch (Exception ex) + { + Logger.Error(ex); + } + } + + private static void ShowAvailableUpdatesNotification(IReadOnlyList upgradable) + { + if (OperatingSystem.IsWindows()) + WindowsAppNotificationBridge.ShowUpdatesAvailableNotification(upgradable); + else if (OperatingSystem.IsMacOS()) + MacOsNotificationBridge.ShowUpdatesAvailableNotification(upgradable); + } + + private static void ShowUpgradingPackagesNotification(IReadOnlyList upgradable) + { + if (OperatingSystem.IsWindows()) + WindowsAppNotificationBridge.ShowUpgradingPackagesNotification(upgradable); + else if (OperatingSystem.IsMacOS()) + MacOsNotificationBridge.ShowUpgradingPackagesNotification(upgradable); + } + + // ─── Battery / power helpers (Windows P/Invoke) ─────────────────────────── + + [StructLayout(LayoutKind.Sequential)] + private struct SYSTEM_POWER_STATUS + { + public byte ACLineStatus; // 0 = battery, 1 = AC, 255 = unknown + public byte BatteryFlag; + public byte BatteryLifePercent; + public byte SystemStatusFlag; // bit 0: battery saver active + public uint BatteryLifeTime; + public uint BatteryFullLifeTime; + } + +#pragma warning disable CA1416 + [DllImport("kernel32.dll")] + private static extern bool GetSystemPowerStatus(out SYSTEM_POWER_STATUS status); +#pragma warning restore CA1416 + + private static bool IsOnBattery() + { + if (!OperatingSystem.IsWindows()) return false; +#pragma warning disable CA1416 + return GetSystemPowerStatus(out var s) && s.ACLineStatus == 0; +#pragma warning restore CA1416 + } + + private static bool IsBatterySaverOn() + { + if (!OperatingSystem.IsWindows()) return false; +#pragma warning disable CA1416 + return GetSystemPowerStatus(out var s) && (s.SystemStatusFlag & 0x01) != 0; +#pragma warning restore CA1416 + } + + private static bool IsOnMeteredConnection() + { +#if WINDOWS + var costType = Windows.Networking.Connectivity.NetworkInformation + .GetInternetConnectionProfile() + ?.GetConnectionCost() + .NetworkCostType; + return costType is Windows.Networking.Connectivity.NetworkCostType.Fixed + or Windows.Networking.Connectivity.NetworkCostType.Variable; +#else + return false; +#endif + } +} diff --git a/src/UniGetUI.Avalonia/Views/SplashWindow.axaml b/src/UniGetUI.Avalonia/Views/SplashWindow.axaml new file mode 100644 index 0000000..43b0502 --- /dev/null +++ b/src/UniGetUI.Avalonia/Views/SplashWindow.axaml @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + diff --git a/src/UniGetUI.Avalonia/Views/SplashWindow.axaml.cs b/src/UniGetUI.Avalonia/Views/SplashWindow.axaml.cs new file mode 100644 index 0000000..be6cc8b --- /dev/null +++ b/src/UniGetUI.Avalonia/Views/SplashWindow.axaml.cs @@ -0,0 +1,27 @@ +using System; +using Avalonia; +using Avalonia.Controls; +using Avalonia.Media; +using Avalonia.Media.Imaging; +using Avalonia.Platform; +using Avalonia.Styling; +using UniGetUI.Core.Tools; + +namespace UniGetUI.Avalonia.Views; + +public partial class SplashWindow : Window +{ + public SplashWindow() + { + InitializeComponent(); + + bool isDark = Application.Current?.ActualThemeVariant == ThemeVariant.Dark; + string uri = isDark + ? "avares://UniGetUI/Assets/SplashScreen.theme-dark.png" + : "avares://UniGetUI/Assets/SplashScreen.png"; + SplashImage.Source = new Bitmap(AssetLoader.Open(new Uri(uri))); + + TaglineText.Text = CoreTools.Translate("Package management made easy"); + TaglineText.Foreground = isDark ? Brushes.White : Brushes.Black; + } +} diff --git a/src/UniGetUI.Avalonia/app.manifest b/src/UniGetUI.Avalonia/app.manifest new file mode 100644 index 0000000..16f8395 --- /dev/null +++ b/src/UniGetUI.Avalonia/app.manifest @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + PerMonitorV2, PerMonitor + true + + + + diff --git a/src/UniGetUI.Core.Classes.Tests/ObservableQueueTests.cs b/src/UniGetUI.Core.Classes.Tests/ObservableQueueTests.cs new file mode 100644 index 0000000..9b673f2 --- /dev/null +++ b/src/UniGetUI.Core.Classes.Tests/ObservableQueueTests.cs @@ -0,0 +1,36 @@ +namespace UniGetUI.Core.Classes.Tests; + +public class ObservableQueueTests +{ + [Fact] + public void TestObservableQueue() + { + var queue = new ObservableQueue(); + + List enqueuedElements = []; + List dequeuedElements = []; + + queue.ItemEnqueued += (_, e) => enqueuedElements.Add(e.Item); + queue.ItemDequeued += (_, e) => dequeuedElements.Add(e.Item); + + queue.Enqueue(1); + queue.Enqueue(2); + Assert.Equal(1, queue.Dequeue()); + queue.Enqueue(4); + queue.Enqueue(3); + + Assert.Equal(2, queue.Dequeue()); + Assert.Equal(4, queue.Dequeue()); + + Assert.Equal(4, enqueuedElements.Count); + Assert.Equal(1, enqueuedElements[0]); + Assert.Equal(2, enqueuedElements[1]); + Assert.Equal(4, enqueuedElements[2]); + Assert.Equal(3, enqueuedElements[3]); + + Assert.Equal(3, dequeuedElements.Count); + Assert.Equal(1, dequeuedElements[0]); + Assert.Equal(2, dequeuedElements[1]); + Assert.Equal(4, dequeuedElements[2]); + } +} diff --git a/src/UniGetUI.Core.Classes.Tests/PersonTests.cs b/src/UniGetUI.Core.Classes.Tests/PersonTests.cs new file mode 100644 index 0000000..dd53854 --- /dev/null +++ b/src/UniGetUI.Core.Classes.Tests/PersonTests.cs @@ -0,0 +1,43 @@ +namespace UniGetUI.Core.Classes.Tests +{ + public class PersonTests + { + [Theory] + [InlineData( + "Bernat-Miquel Guimerà", + "https://github.com/BernatMiquelG.png", + "https://github.com/BernatMiquelG" + )] + [InlineData("Bernat-Miquel Guimerà", "https://github.com/BernatMiquelG.png", null)] + [InlineData("Bernat-Miquel Guimerà", null, "https://github.com/BernatMiquelG")] + [InlineData("Bernat-Miquel Guimerà", null, null)] + public void TestPerson(string name, string? profilePicture, string? gitHubUrl) + { + //arrange + Person actual = new( + Name: name, + ProfilePicture: profilePicture is null ? null : new Uri(profilePicture), + GitHubUrl: gitHubUrl is null ? null : new Uri(gitHubUrl) + ); + + //Assert + if (string.IsNullOrEmpty(profilePicture)) + { + Assert.False(actual.HasPicture); + } + else + { + Assert.True(actual.HasPicture); + } + + if (string.IsNullOrEmpty(gitHubUrl)) + { + Assert.False(actual.HasGitHubProfile); + } + else + { + Assert.True(actual.HasGitHubProfile); + } + } + } +} diff --git a/src/UniGetUI.Core.Classes.Tests/SortableObservableCollectionTests.cs b/src/UniGetUI.Core.Classes.Tests/SortableObservableCollectionTests.cs new file mode 100644 index 0000000..9073471 --- /dev/null +++ b/src/UniGetUI.Core.Classes.Tests/SortableObservableCollectionTests.cs @@ -0,0 +1,56 @@ +#pragma warning disable CA1852 +namespace UniGetUI.Core.Classes.Tests +{ + public class SortableObservableCollectionTests + { + private class SortableInt : IIndexableListItem + { + public int Value { get; set; } + public int Index { get; set; } + + public SortableInt(int value) + { + Value = value; + } + } + + [Fact] + public void TestSortableCollection() + { + int EventTriggeredCount = 0; + + SortableObservableCollection SortableCollection = []; + SortableCollection.CollectionChanged += (_, _) => + { + EventTriggeredCount++; + }; + SortableCollection.SortingSelector = (s) => + { + return s.Value; + }; + SortableCollection.Add(new(1)); + SortableCollection.Add(new(2)); + SortableCollection.Add(new(4)); + + SortableCollection.BlockSorting = true; + SortableCollection.Add(new(5)); + SortableCollection.Add(new(2)); + SortableCollection.BlockSorting = false; + + SortableCollection.Sort(); + + Assert.Equal(7, EventTriggeredCount); + Assert.Equal(5, SortableCollection.Count); + Assert.Equal(1, SortableCollection[0].Value); + Assert.Equal(2, SortableCollection[1].Value); + Assert.Equal(2, SortableCollection[2].Value); + Assert.Equal(4, SortableCollection[3].Value); + Assert.Equal(5, SortableCollection[4].Value); + + for (int i = 0; i < SortableCollection.Count; i++) + { + Assert.Equal(i, SortableCollection[i].Index); + } + } + } +} diff --git a/src/UniGetUI.Core.Classes.Tests/TaskRecyclerTests.cs b/src/UniGetUI.Core.Classes.Tests/TaskRecyclerTests.cs new file mode 100644 index 0000000..0fd14e7 --- /dev/null +++ b/src/UniGetUI.Core.Classes.Tests/TaskRecyclerTests.cs @@ -0,0 +1,196 @@ +using System.Diagnostics.CodeAnalysis; + +namespace UniGetUI.Core.Classes.Tests; + +public class TaskRecyclerTests +{ + private int MySlowMethod1() + { + Thread.Sleep(1000); + return new Random().Next(); + } + + private sealed class TestClass + { + public TestClass() { } + + [SuppressMessage( + "Performance", + "CA1822:Mark members as static", + Justification = "Instance methods are required to validate TaskRecycler instance-bound delegate behavior." + )] + public string SlowMethod2() + { + Thread.Sleep(1000); + return new Random().Next().ToString(); + } + + [SuppressMessage( + "Performance", + "CA1822:Mark members as static", + Justification = "Instance methods are required to validate TaskRecycler instance-bound delegate behavior." + )] + public string SlowMethod3() + { + Thread.Sleep(1000); + return new Random().Next().ToString(); + } + } + + private int MySlowMethod4(int argument) + { + Thread.Sleep(1000); + return new Random().Next() + (argument - argument); + } + + [Fact] + public async Task TestTaskRecycler_Static_Int() + { + // The same static method should be cached, and therefore the return value should be the same + var task1 = TaskRecycler.RunOrAttachAsync(MySlowMethod1); + var task2 = TaskRecycler.RunOrAttachAsync(MySlowMethod1); + int result1 = await task1; + int result2 = await task2; + Assert.Equal(result1, result2); + + // The same static method should be cached, and therefore the return value should be the same, but different from previous runs + var task3 = TaskRecycler.RunOrAttachAsync(MySlowMethod1); + var task4 = TaskRecycler.RunOrAttachAsync(MySlowMethod1); + int result4 = await task4; + int result3 = await task3; + Assert.Equal(result3, result4); + + // Ensure the last call was not permanently cached + Assert.NotEqual(result1, result3); + } + + [Fact] + public async Task TestTaskRecycler_Static_Int_WithCache() + { + // The same static method should be cached, and therefore the return value should be the same + var task1 = TaskRecycler.RunOrAttachAsync(MySlowMethod1, 2); + var task2 = TaskRecycler.RunOrAttachAsync(MySlowMethod1, 2); + int result1 = await task1; + int result2 = await task2; + Assert.Equal(result1, result2); + + // The same static method should be cached, and therefore the return value should be the same, + // and equal to previous runs due to 3 seconds cache + var task3 = TaskRecycler.RunOrAttachAsync(MySlowMethod1, 2); + var task4 = TaskRecycler.RunOrAttachAsync(MySlowMethod1, 2); + int result4 = await task4; + int result3 = await task3; + Assert.Equal(result3, result4); + Assert.Equal(result1, result3); + + // Wait for caches to clear + Thread.Sleep(3000); + + // The same static method should be cached, but cached runs should have been removed. This results should differ from previous ones + var task5 = TaskRecycler.RunOrAttachAsync(MySlowMethod1, 2); + var task6 = TaskRecycler.RunOrAttachAsync(MySlowMethod1, 2); + int result5 = await task6; + int result6 = await task5; + Assert.Equal(result5, result6); + Assert.NotEqual(result4, result5); + + // Clear cache + TaskRecycler.RemoveFromCache(MySlowMethod1); + + // The same static method should be cached, but cached runs should have been cleared manually. This results should differ from previous ones + var task7 = TaskRecycler.RunOrAttachAsync(MySlowMethod1, 2); + var task8 = TaskRecycler.RunOrAttachAsync(MySlowMethod1, 2); + int result7 = await task7; + int result8 = await task8; + Assert.Equal(result7, result8); + Assert.NotEqual(result6, result7); + } + + [Fact] + public async Task TestTaskRecycler_StaticWithArgument_Int() + { + // The same static method should be cached, and therefore the return value should be the same + var task1 = TaskRecycler.RunOrAttachAsync(MySlowMethod4, 2); + var task2 = TaskRecycler.RunOrAttachAsync(MySlowMethod4, 2); + var task3 = TaskRecycler.RunOrAttachAsync(MySlowMethod4, 3); + int result1 = await task1; + int result2 = await task2; + int result3 = await task3; + Assert.Equal(result1, result2); + Assert.NotEqual(result1, result3); + + // The same static method should be cached, and therefore the return value should be the same, but different from previous runs + var task4 = TaskRecycler.RunOrAttachAsync(MySlowMethod4, 2); + var task5 = TaskRecycler.RunOrAttachAsync(MySlowMethod4, 3); + int result4 = await task4; + int result5 = await task5; + Assert.NotEqual(result4, result5); + Assert.NotEqual(result1, result4); + Assert.NotEqual(result3, result5); + } + + [Fact] + public async Task FaultedTaskIsEvictedBeforeTheNextCall() + { + int calls = 0; + Func method = () => + { + if (Interlocked.Increment(ref calls) == 1) + throw new InvalidOperationException("Expected first attempt failure"); + return 42; + }; + + await Assert.ThrowsAsync( + async () => await TaskRecycler.RunOrAttachAsync(method) + ); + + int result = await TaskRecycler.RunOrAttachAsync(method); + + Assert.Equal(42, result); + Assert.Equal(2, calls); + } + + [Fact] + public async Task TestTaskRecycler_Class_String() + { + var class1 = new TestClass(); + var class2 = new TestClass(); + + // The SAME method from the SAME instance should be cached, + // and therefore the return value should be the same + var task1 = TaskRecycler.RunOrAttachAsync(class1.SlowMethod2); + var task2 = TaskRecycler.RunOrAttachAsync(class1.SlowMethod2); + string result1 = await task1; + string result2 = await task2; + Assert.Equal(result1, result2); + + var class1_copy = class1; + + // The SAME method from the SAME instance, even when called + // from different variable names should be cached, and therefore the return value should be the same + var task5 = TaskRecycler.RunOrAttachAsync(class1_copy.SlowMethod2); + var task6 = TaskRecycler.RunOrAttachAsync(class1.SlowMethod2); + string result5 = await task5; + string result6 = await task6; + Assert.Equal(result5, result6); + + // The SAME method from two DIFFERENT instances should NOT be + // cached, so the results should differ + var task3 = TaskRecycler.RunOrAttachAsync(class1.SlowMethod2); + var task4 = TaskRecycler.RunOrAttachAsync(class2.SlowMethod2); + string result4 = await task4; + string result3 = await task3; + Assert.NotEqual(result3, result4); + + // Ensure the last call was not permanently cached + Assert.NotEqual(result1, result3); + + // The SAME method from two DIFFERENT instances should NOT be + // cached, so the results should differ + var task7 = TaskRecycler.RunOrAttachAsync(class1.SlowMethod3); + var task8 = TaskRecycler.RunOrAttachAsync(class2.SlowMethod2); + string result7 = await task7; + string result8 = await task8; + Assert.NotEqual(result7, result8); + } +} diff --git a/src/UniGetUI.Core.Classes.Tests/UniGetUI.Core.Classes.Tests.csproj b/src/UniGetUI.Core.Classes.Tests/UniGetUI.Core.Classes.Tests.csproj new file mode 100644 index 0000000..2627cb8 --- /dev/null +++ b/src/UniGetUI.Core.Classes.Tests/UniGetUI.Core.Classes.Tests.csproj @@ -0,0 +1,38 @@ + + + $(PortableTargetFramework) + + false + true + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + + + + + + + + + + + diff --git a/src/UniGetUI.Core.Classes/IIndexableListItem.cs b/src/UniGetUI.Core.Classes/IIndexableListItem.cs new file mode 100644 index 0000000..5e7b20d --- /dev/null +++ b/src/UniGetUI.Core.Classes/IIndexableListItem.cs @@ -0,0 +1,7 @@ +namespace UniGetUI.Core.Classes +{ + public interface IIndexableListItem + { + public int Index { get; set; } + } +} diff --git a/src/UniGetUI.Core.Classes/ObservableQueue.cs b/src/UniGetUI.Core.Classes/ObservableQueue.cs new file mode 100644 index 0000000..54996e5 --- /dev/null +++ b/src/UniGetUI.Core.Classes/ObservableQueue.cs @@ -0,0 +1,25 @@ +namespace UniGetUI.Core.Classes; + +public class ObservableQueue : Queue +{ + public class EventArgs(T item) + { + public readonly T Item = item; + } + + public event EventHandler? ItemEnqueued; + public event EventHandler? ItemDequeued; + + public new void Enqueue(T item) + { + base.Enqueue(item); + ItemEnqueued?.Invoke(this, new EventArgs(item)); + } + + public new T Dequeue() + { + T item = base.Dequeue(); + ItemDequeued?.Invoke(this, new EventArgs(item)); + return item; + } +} diff --git a/src/UniGetUI.Core.Classes/Person.cs b/src/UniGetUI.Core.Classes/Person.cs new file mode 100644 index 0000000..be7aa29 --- /dev/null +++ b/src/UniGetUI.Core.Classes/Person.cs @@ -0,0 +1,27 @@ +namespace UniGetUI.Core.Classes +{ + public readonly struct Person + { + public readonly string Name; + public readonly Uri? ProfilePicture; + public readonly Uri? GitHubUrl; + public readonly bool HasPicture; + public readonly bool HasGitHubProfile; + public readonly string Language; + + public Person( + string Name, + Uri? ProfilePicture = null, + Uri? GitHubUrl = null, + string Language = "" + ) + { + this.Name = Name; + this.ProfilePicture = ProfilePicture; + this.GitHubUrl = GitHubUrl; + HasPicture = ProfilePicture is not null; + HasGitHubProfile = GitHubUrl is not null; + this.Language = Language; + } + } +} diff --git a/src/UniGetUI.Core.Classes/SortableObservableCollection.cs b/src/UniGetUI.Core.Classes/SortableObservableCollection.cs new file mode 100644 index 0000000..f651031 --- /dev/null +++ b/src/UniGetUI.Core.Classes/SortableObservableCollection.cs @@ -0,0 +1,66 @@ +using System.Collections.ObjectModel; +using System.Collections.Specialized; + +namespace UniGetUI.Core.Classes +{ + /* + * An observable sorted collection that keeps IIndexableListItem indexes up to date + */ + public class SortableObservableCollection : ObservableCollection + where T : IIndexableListItem + { + public Func? SortingSelector { get; set; } + public bool Descending { get; set; } + public bool BlockSorting { get; set; } + + protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e) + { + if (BlockSorting) + return; + + base.OnCollectionChanged(e); + if ( + SortingSelector is null + || e.Action + is NotifyCollectionChangedAction.Remove + or NotifyCollectionChangedAction.Reset + ) + return; + + Sort(); + } + + public void Sort() + { + if (BlockSorting) + return; + + BlockSorting = true; + + if (SortingSelector is null) + { + throw new InvalidOperationException( + "SortableObservableCollection.SortingSelector must not be null when sorting" + ); + } + + List sorted = Descending + ? this.OrderByDescending(SortingSelector).ToList() + : this.OrderBy(SortingSelector).ToList(); + foreach (T item in sorted) + { + Move(IndexOf(item), sorted.IndexOf(item)); + } + + for (int i = 0; i < Count; i++) + { + this.ElementAt(i).Index = i; + } + + BlockSorting = false; + base.OnCollectionChanged( + new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset) + ); + } + } +} diff --git a/src/UniGetUI.Core.Classes/TaskRecycler.cs b/src/UniGetUI.Core.Classes/TaskRecycler.cs new file mode 100644 index 0000000..9b87fea --- /dev/null +++ b/src/UniGetUI.Core.Classes/TaskRecycler.cs @@ -0,0 +1,180 @@ +using System.Collections.Concurrent; + +namespace UniGetUI.Core.Classes; + +/* + * This static class can help reduce the CPU + * impact of calling a CPU-intensive method + * that is expected to return the same result when + * called twice concurrently. + * + * This can apply to getting the locally installed + * packages, for example. + * + * + * WARNING: When using TaskRecycler with methods that return instances of classes + * the return instance WILL BE THE SAME when the call attaches to an existing call. + * Take this into account when handling received objects. + */ +public static class TaskRecycler +{ + private static readonly ConcurrentDictionary> _tasks = new(); + private static readonly ConcurrentDictionary _tasks_VOID = new(); + + public static Task RunOrAttachAsync_VOID(Action method, int cacheTimeSecs = 0) + { + int hash = method.GetHashCode(); + return _runTaskAndWait_VOID(new Task(method), hash, cacheTimeSecs); + } + + public static Task RunOrAttachAsync(Func method, int cacheTimeSecs = 0) + { + int hash = method.GetHashCode(); + return _runTaskAndWait(new Task(method), hash, cacheTimeSecs); + } + + public static Task RunOrAttachAsync( + Func method, + ParamT arg1, + int cacheTimeSecs = 0 + ) + { + int hash = method.GetHashCode() + (arg1?.GetHashCode() ?? 0); + return _runTaskAndWait(new Task(() => method(arg1)), hash, cacheTimeSecs); + } + + public static Task RunOrAttachAsync( + Func method, + Param1T arg1, + Param2T arg2, + int cacheTimeSecs = 0 + ) + { + int hash = method.GetHashCode() + (arg1?.GetHashCode() ?? 0) + (arg2?.GetHashCode() ?? 0); + return _runTaskAndWait(new Task(() => method(arg1, arg2)), hash, cacheTimeSecs); + } + + public static Task RunOrAttachAsync( + Func method, + Param1T arg1, + Param2T arg2, + Param3T arg3, + int cacheTimeSecs = 0 + ) + { + int hash = + method.GetHashCode() + + (arg1?.GetHashCode() ?? 0) + + (arg2?.GetHashCode() ?? 0) + + (arg3?.GetHashCode() ?? 0); + return _runTaskAndWait( + new Task(() => method(arg1, arg2, arg3)), + hash, + cacheTimeSecs + ); + } + + public static ReturnT RunOrAttach(Func method, int cacheTimeSecs = 0) => + RunOrAttachAsync(method, cacheTimeSecs).GetAwaiter().GetResult(); + + public static ReturnT RunOrAttach( + Func method, + ParamT arg1, + int cacheTimeSecs = 0 + ) => RunOrAttachAsync(method, arg1, cacheTimeSecs).GetAwaiter().GetResult(); + + public static ReturnT RunOrAttach( + Func method, + Param1T arg1, + Param2T arg2, + int cacheTimeSecs = 0 + ) => RunOrAttachAsync(method, arg1, arg2, cacheTimeSecs).GetAwaiter().GetResult(); + + public static ReturnT RunOrAttach( + Func method, + Param1T arg1, + Param2T arg2, + Param3T arg3, + int cacheTimeSecs = 0 + ) => RunOrAttachAsync(method, arg1, arg2, arg3, cacheTimeSecs).GetAwaiter().GetResult(); + + /// + /// Instantly removes a function call from the cache, even if the associated task has not + /// finished yet. Any previous call will finish as expected. New calls will not attach to any + /// preexisting Tasks, and a new Task will be created instead. + /// + public static void RemoveFromCache(Func method) => + _tasks.TryRemove(method.GetHashCode(), out _); + + private static Task _runTaskAndWait_VOID(Task task, int hash, int cacheTimeSecs) + { + Task cachedTask = _tasks_VOID.GetOrAdd(hash, task); + if (ReferenceEquals(cachedTask, task)) + { + task.Start(); + _ = _scheduleCacheRemoval_VOID(hash, task, cacheTimeSecs); + } + else + { + Interlocked.Increment(ref TaskRecyclerTelemetry.DeduplicatedCalls); + } + + return cachedTask; + } + + private static Task _runTaskAndWait(Task task, int hash, int cacheTimeSecs) + { + Task cachedTask = _tasks.GetOrAdd(hash, task); + if (ReferenceEquals(cachedTask, task)) + { + task.Start(); + _ = _scheduleCacheRemoval(hash, task, cacheTimeSecs); + } + else + { + Interlocked.Increment(ref TaskRecyclerTelemetry.DeduplicatedCalls); + } + + return cachedTask; + } + + private static Task _scheduleCacheRemoval(int hash, Task task, int cacheTimeSecs) => + task.ContinueWith( + completedTask => _removeFromCache(hash, completedTask, cacheTimeSecs), + CancellationToken.None, + TaskContinuationOptions.ExecuteSynchronously, + TaskScheduler.Default + ) + .Unwrap(); + + private static Task _scheduleCacheRemoval_VOID(int hash, Task task, int cacheTimeSecs) => + task.ContinueWith( + completedTask => _removeFromCache_VOID(hash, completedTask, cacheTimeSecs), + CancellationToken.None, + TaskContinuationOptions.ExecuteSynchronously, + TaskScheduler.Default + ) + .Unwrap(); + + private static async Task _removeFromCache(int hash, Task task, int cacheTimeSecs) + { + if (task.IsCompletedSuccessfully && cacheTimeSecs > 0) + await Task.Delay(TimeSpan.FromSeconds(cacheTimeSecs)).ConfigureAwait(false); + + ((ICollection>>)_tasks).Remove(new(hash, task)); + } + + private static async Task _removeFromCache_VOID(int hash, Task task, int cacheTimeSecs) + { + if (task.IsCompletedSuccessfully && cacheTimeSecs > 0) + await Task.Delay(TimeSpan.FromSeconds(cacheTimeSecs)).ConfigureAwait(false); + + ((ICollection>)_tasks_VOID).Remove(new(hash, task)); + } + +} + +public static class TaskRecyclerTelemetry +{ + public static int DeduplicatedCalls; +} diff --git a/src/UniGetUI.Core.Classes/UniGetUI.Core.Classes.csproj b/src/UniGetUI.Core.Classes/UniGetUI.Core.Classes.csproj new file mode 100644 index 0000000..b66c05a --- /dev/null +++ b/src/UniGetUI.Core.Classes/UniGetUI.Core.Classes.csproj @@ -0,0 +1,13 @@ + + + $(SharedTargetFrameworks) + + + + + + + + + + diff --git a/src/UniGetUI.Core.Data.Tests/ContributorsTests.cs b/src/UniGetUI.Core.Data.Tests/ContributorsTests.cs new file mode 100644 index 0000000..ab8ab45 --- /dev/null +++ b/src/UniGetUI.Core.Data.Tests/ContributorsTests.cs @@ -0,0 +1,11 @@ +namespace UniGetUI.Core.Data.Tests +{ + public class ContributorsTests + { + [Fact] + public void CheckIfContributorListIsEmpty() + { + Assert.NotEmpty(ContributorsData.Contributors); + } + } +} diff --git a/src/UniGetUI.Core.Data.Tests/CoreTests.cs b/src/UniGetUI.Core.Data.Tests/CoreTests.cs new file mode 100644 index 0000000..2eafee8 --- /dev/null +++ b/src/UniGetUI.Core.Data.Tests/CoreTests.cs @@ -0,0 +1,105 @@ +namespace UniGetUI.Core.Data.Tests +{ + public class CoreTests + { + public static object[][] Data => + [ + [CoreData.UniGetUIDataDirectory], + [CoreData.UniGetUIInstallationOptionsDirectory], + [CoreData.UniGetUICacheDirectory_Data], + [CoreData.UniGetUICacheDirectory_Icons], + [CoreData.UniGetUICacheDirectory_Lang], + [CoreData.UniGetUI_DefaultBackupDirectory], + ]; + + [Theory] + [MemberData(nameof(Data))] + public void CheckDirectoryAttributes(string directory) + { + Assert.True( + Directory.Exists(directory), + $"Directory ${directory} does not exist, but it should have been created automatically" + ); + } + + [Fact] + public void CheckOtherAttributes() + { + Assert.NotEmpty(CoreData.VersionName); + Assert.NotEqual(0, CoreData.BuildNumber); + Assert.NotEqual(0, CoreData.UpdatesAvailableNotificationTag); + + Assert.True( + Directory.Exists(CoreData.UniGetUIExecutableDirectory), + "Directory where the executable is located does not exist" + ); + Assert.True( + File.Exists(CoreData.UniGetUIExecutableFile), + "The executable file does not exist" + ); + } + + [Fact] + public void ResolveInstallationDirectoryReturnsParentForBundledAvaloniaDirectory() + { + string installDirectory = Path.GetFullPath(Path.Join("install-root")); + string avaloniaDirectory = Path.Join(installDirectory, "Avalonia"); + string classicExecutable = Path.Join(installDirectory, "UniGetUI.exe"); + + string resolvedDirectory = CoreData.ResolveInstallationDirectory( + avaloniaDirectory, + filePath => filePath == classicExecutable, + static _ => false + ); + + Assert.Equal(installDirectory, resolvedDirectory); + } + + [Fact] + public void ResolveInstallationDirectoryKeepsStandaloneAvaloniaDirectory() + { + string avaloniaDirectory = Path.GetFullPath(Path.Join("standalone", "Avalonia")); + + string resolvedDirectory = CoreData.ResolveInstallationDirectory( + avaloniaDirectory, + static _ => false, + static _ => false + ); + + Assert.Equal(avaloniaDirectory, resolvedDirectory); + } + + [Theory] + [InlineData("3.3.7", "3.3.7")] + [InlineData("2026.1.2", "v2026.1.2")] + [InlineData("v2026.1.2", "v2026.1.2")] + public void CheckGitHubReleaseTag(string versionName, string expectedTag) + { + Assert.Equal(expectedTag, CoreData.GetGitHubReleaseTag(versionName)); + } + + [Fact] + public void CheckGitHubReleaseTagCandidatesForCalendarVersion() + { + Assert.Equal( + ["v2026.1.2", "2026.1.2"], + CoreData.GetGitHubReleaseTagCandidates("2026.1.2") + ); + } + + [Fact] + public void CheckGitHubReleaseUrlsUseEscapedResolvedTag() + { + Assert.Equal( + "https://github.com/Devolutions/UniGetUI/releases/tag/v2026.1.2", + CoreData.GetGitHubReleasePageUrlFromTag(CoreData.GetGitHubReleaseTag("2026.1.2")) + ); + Assert.Equal( + "https://api.github.com/repos/Devolutions/UniGetUI/releases/tags/3.3.7-beta1", + CoreData.GetGitHubReleaseApiUrlFromTag("3.3.7-beta1") + ); + Assert.Equal("https://devolutions.net/unigetui/release-notes/", CoreData.ReleaseNotesUrl); + Assert.Equal(CoreData.ReleaseNotesUrl, CoreData.GetGitHubReleasePageUrl()); + } + } +} diff --git a/src/UniGetUI.Core.Data.Tests/LicensesTest.cs b/src/UniGetUI.Core.Data.Tests/LicensesTest.cs new file mode 100644 index 0000000..debdb89 --- /dev/null +++ b/src/UniGetUI.Core.Data.Tests/LicensesTest.cs @@ -0,0 +1,43 @@ +namespace UniGetUI.Core.Data.Tests +{ + public class LicensesTest + { + [Fact] + public void EnsureLicenseUrlsExist() + { + List MissingUrls = []; + + foreach (string library in LicenseData.LicenseNames.Keys) + { + if (!LicenseData.LicenseURLs.ContainsKey(library)) + { + MissingUrls.Add(library); + } + } + + Assert.True( + MissingUrls.Count == 0, + "The list of missing licenses is not empty: " + MissingUrls.ToArray().ToString() + ); + } + + [Fact] + public void EnsureHomepageUrlsExist() + { + List MissingUrls = []; + + foreach (string library in LicenseData.LicenseNames.Keys) + { + if (!LicenseData.HomepageUrls.ContainsKey(library)) + { + MissingUrls.Add(library); + } + } + + Assert.True( + MissingUrls.Count == 0, + "The list of missing licenses is not empty: " + MissingUrls.ToArray().ToString() + ); + } + } +} diff --git a/src/UniGetUI.Core.Data.Tests/UniGetUI.Core.Data.Tests.csproj b/src/UniGetUI.Core.Data.Tests/UniGetUI.Core.Data.Tests.csproj new file mode 100644 index 0000000..556d891 --- /dev/null +++ b/src/UniGetUI.Core.Data.Tests/UniGetUI.Core.Data.Tests.csproj @@ -0,0 +1,40 @@ + + + $(PortableTargetFramework) + + + + + false + true + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + + + + + + + + + + + diff --git a/src/UniGetUI.Core.Data.Tests/UpdateInProgressGuardTests.cs b/src/UniGetUI.Core.Data.Tests/UpdateInProgressGuardTests.cs new file mode 100644 index 0000000..966e9a6 --- /dev/null +++ b/src/UniGetUI.Core.Data.Tests/UpdateInProgressGuardTests.cs @@ -0,0 +1,89 @@ +namespace UniGetUI.Core.Data.Tests +{ + public class UpdateInProgressGuardTests : IDisposable + { + // {root}/app stands in for {app}; {root} is its always-empty parent. + private readonly string _root; + private readonly string _appDir; + + private static readonly Func ProcessAlive = _ => true; + private static readonly Func ProcessDead = _ => false; + + public UpdateInProgressGuardTests() + { + _root = Path.Combine(Path.GetTempPath(), "ugui-guard-" + Guid.NewGuid().ToString("N")); + _appDir = Path.Combine(_root, "app"); + Directory.CreateDirectory(_appDir); + } + + public void Dispose() + { + try { Directory.Delete(_root, recursive: true); } + catch { } + } + + private static string WriteMarker(string directory, string content = "1234") + { + Directory.CreateDirectory(directory); + string path = Path.Combine(directory, UpdateInProgressGuard.MarkerFileName); + File.WriteAllText(path, content); + return path; + } + + [Fact] + public void NoMarker_ReturnsFalse() + { + Assert.False(UpdateInProgressGuard.IsUpdateInProgress(_appDir, ProcessAlive)); + } + + [Fact] + public void MarkerWithRunningInstaller_ReturnsTrue() + { + WriteMarker(_appDir); + Assert.True(UpdateInProgressGuard.IsUpdateInProgress(_appDir, ProcessAlive)); + } + + [Fact] + public void MarkerInParentWithRunningInstaller_ReturnsTrue() + { + // Avalonia runs from {app}\Avalonia; marker is in {app}. + WriteMarker(_appDir); + string child = Path.Combine(_appDir, "Avalonia"); + Directory.CreateDirectory(child); + + Assert.True(UpdateInProgressGuard.IsUpdateInProgress(child, ProcessAlive)); + } + + [Fact] + public void MarkerWithDeadInstaller_ReturnsFalseAndIsDeleted() + { + string marker = WriteMarker(_appDir); + + Assert.False(UpdateInProgressGuard.IsUpdateInProgress(_appDir, ProcessDead)); + Assert.False(File.Exists(marker)); // stale marker is cleaned up + } + + [Fact] + public void MarkerWithUnreadableContent_ReturnsFalseAndIsKept() + { + string marker = WriteMarker(_appDir, "not-a-pid"); + + Assert.False(UpdateInProgressGuard.IsUpdateInProgress(_appDir, ProcessAlive)); + Assert.True(File.Exists(marker)); // not deleted: could be a partial write + } + + [Fact] + public void RealProcessCheck_TreatsCurrentProcessAsRunning() + { + // Exercises the real IsProcessRunning via the parameterless overload. + WriteMarker(_appDir, Environment.ProcessId.ToString()); + Assert.True(UpdateInProgressGuard.IsUpdateInProgress(_appDir)); + } + + [Fact] + public void MarkerFileName_MatchesInstallerContract() + { + Assert.Equal(".unigetui-update-in-progress", UpdateInProgressGuard.MarkerFileName); + } + } +} diff --git a/src/UniGetUI.Core.Data/Assets/Data/Contributors.list b/src/UniGetUI.Core.Data/Assets/Data/Contributors.list new file mode 100644 index 0000000..f8a0e74 --- /dev/null +++ b/src/UniGetUI.Core.Data/Assets/Data/Contributors.list @@ -0,0 +1,80 @@ +marticliment +excel-bot +mrixner +skanda890 +ppvnf +Saibamen +panther7 +RavenMacDaddy +Mikey1993 +flatron4eg +gnerkus +theguy000 +Malus-risus +tkohlmeier +raghavdhingra24 +snapsl +Taron-art +adripo +schembriaiden +CoolSpy3 +MisterEvans78 +mapi68 +SpaceTimee +sklart +uKER +turw41th +rumplin +Janek91 +Schtenk +KimCM +joguarino +sitiom +mvaneijken +elliot-100 +derula +candrapersada +BastianKamp +adfnekc +vedantmgoyal9 +wilt00 +Mertsch +jnsn +denismattos +dave-sc +szumsky +aaronliu0130 +igorskyflyer +harleylara +ercJuL +quantumfallout +Goooler +yrjarv +vsilvar +tomasz1986 +nowjon +pomodori92 +qianlongzt +redactedscribe +thepro-3418 +treysis +victorelec14 +Layfully +a-mnich +neoOpus +ArtyomZabroda +Simek +Carterpersall +FlyingError +hboyd2003 +HorridModz +eltociear +ImgBotApp +MSDNicrosoft +headquarter8302 +reima +Pandoriaantje +Satanarious +SierraKomodo +StefanSchoof +tiagozip diff --git a/src/UniGetUI.Core.Data/Contributors.cs b/src/UniGetUI.Core.Data/Contributors.cs new file mode 100644 index 0000000..46a913c --- /dev/null +++ b/src/UniGetUI.Core.Data/Contributors.cs @@ -0,0 +1,16 @@ +namespace UniGetUI.Core.Data +{ + public static class ContributorsData + { + public static string[] Contributors = File.ReadAllLines( + Path.Join( + CoreData.UniGetUIExecutableDirectory, + "Assets", + "Data", + "Contributors.list" + ) + ) + .Where(x => x != "") + .ToArray(); + } +} diff --git a/src/UniGetUI.Core.Data/CoreCredentialStore.cs b/src/UniGetUI.Core.Data/CoreCredentialStore.cs new file mode 100644 index 0000000..7cbed4a --- /dev/null +++ b/src/UniGetUI.Core.Data/CoreCredentialStore.cs @@ -0,0 +1,110 @@ +using System.Net; +using System.Security.Cryptography; +using System.Text; +using UniGetUI.Core.Logging; +#if WINDOWS +using Windows.Security.Credentials; +#endif + +namespace UniGetUI.Core.Data; + +public static class CoreCredentialStore +{ + public static NetworkCredential? GetCredential(string resourceName, string userName) + { + string? secret = GetSecret(resourceName, userName); + return secret is null + ? null + : new NetworkCredential { UserName = userName, Password = secret }; + } + + public static void SetCredential(string resourceName, string userName, string password) => + SetSecret(resourceName, userName, password); + + public static string? GetSecret(string resourceName, string userName) + { + try + { +#if WINDOWS + var vault = new PasswordVault(); + var credential = vault.Retrieve(resourceName, userName); + credential.RetrievePassword(); + return credential.Password; +#else + string secretPath = GetSecretPath(resourceName, userName); + return File.Exists(secretPath) ? File.ReadAllText(secretPath) : null; +#endif + } + catch (Exception ex) + { + Logger.Warn($"Unable to retrieve secret for resource '{resourceName}': {ex.Message}"); + return null; + } + } + + public static void SetSecret(string resourceName, string userName, string secret) + { + try + { +#if WINDOWS + DeleteSecret(resourceName, userName); + var vault = new PasswordVault(); + vault.Add(new PasswordCredential(resourceName, userName, secret)); +#else + string storageDirectory = GetStorageDirectory(); + Directory.CreateDirectory(storageDirectory); + File.WriteAllText(GetSecretPath(resourceName, userName), secret); +#endif + } + catch (Exception ex) + { + Logger.Error($"Unable to persist secret for resource '{resourceName}'"); + Logger.Error(ex); + } + } + + public static void DeleteSecret(string resourceName, string userName) + { + try + { +#if WINDOWS + var vault = new PasswordVault(); + IReadOnlyList credentials = + vault.FindAllByResource(resourceName) ?? []; + foreach ( + PasswordCredential credential in credentials.Where(credential => + credential.UserName == userName + ) + ) + { + vault.Remove(credential); + } +#else + string secretPath = GetSecretPath(resourceName, userName); + if (File.Exists(secretPath)) + { + File.Delete(secretPath); + } +#endif + } + catch (Exception ex) + { + Logger.Error($"Unable to delete secret for resource '{resourceName}'"); + Logger.Error(ex); + } + } + +#if !WINDOWS + private static string GetStorageDirectory() => + Path.Join(CoreData.UniGetUIDataDirectory, "SecureStorage"); + + private static string GetSecretPath(string resourceName, string userName) => + Path.Join(GetStorageDirectory(), GetStableFileName(resourceName, userName)); + + private static string GetStableFileName(string resourceName, string userName) + { + byte[] hash = SHA256.HashData(Encoding.UTF8.GetBytes($"{resourceName}\n{userName}")); + return Convert.ToHexString(hash) + ".secret"; + } +#endif +} diff --git a/src/UniGetUI.Core.Data/CoreData.cs b/src/UniGetUI.Core.Data/CoreData.cs new file mode 100644 index 0000000..e164d59 --- /dev/null +++ b/src/UniGetUI.Core.Data/CoreData.cs @@ -0,0 +1,687 @@ +using System.Diagnostics; +using System.Text; +using UniGetUI.Core.Logging; + +namespace UniGetUI.Core.Data +{ + public static class CoreData + { + private const string GitHubReleasePageBaseUrl = "https://github.com/Devolutions/UniGetUI/releases/tag/"; + private const string GitHubReleaseApiBaseUrl = "https://api.github.com/repos/Devolutions/UniGetUI/releases/tags/"; + private const string BundledModernAppDirectoryName = "Avalonia"; + private const string WindowsExecutableName = "UniGetUI.exe"; + private const string BundledPingetExecutableName = "pinget.exe"; + public const string ReleaseNotesUrl = "https://devolutions.net/unigetui/release-notes/"; + + private static int? __code_page; + public static int CODE_PAGE + { + get => __code_page ??= GetCodePage(); + } + + private static Encoding? __console_encoding; + // The encoding CLIs that don't force UTF-8 (e.g. Chocolatey) actually emit their console output in. + public static Encoding ConsoleEncoding + { + get + { + if (__console_encoding is not null) + return __console_encoding; + try + { + Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); + __console_encoding = Encoding.GetEncoding(CODE_PAGE); + } + catch (Exception e) + { + Logger.Warn($"Could not resolve console code page {CODE_PAGE}, falling back to UTF-8"); + Logger.Warn(e); + __console_encoding = Encoding.UTF8; + } + return __console_encoding; + } + } + public const string VersionName = "2026.1.0"; // Do not modify this line, use file scripts/set-version.ps1 + public const int BuildNumber = 106; // Do not modify this line, use file scripts/set-version.ps1 + + public const string UserAgentString = + $"UniGetUI/{VersionName} (https://devolutions.net/unigetui; unigetui@devolutions.net)"; + + public const string AppIdentifier = "MartiCliment.UniGetUI"; + public const string MainWindowIdentifier = "MartiCliment.UniGetUI.MainInterface"; + + public static string GetGitHubReleaseTag() + { + return GetGitHubReleaseTag(VersionName); + } + + public static string[] GetGitHubReleaseTagCandidates() + { + return GetGitHubReleaseTagCandidates(VersionName); + } + + public static string GetGitHubReleaseTag(string versionName) + { + return GetGitHubReleaseTagCandidates(versionName)[0]; + } + + public static string[] GetGitHubReleaseTagCandidates(string versionName) + { + string normalizedVersion = string.IsNullOrWhiteSpace(versionName) + ? VersionName + : versionName.Trim(); + + if (normalizedVersion.StartsWith("v", StringComparison.OrdinalIgnoreCase)) + { + return [normalizedVersion]; + } + + string prefixedTag = $"v{normalizedVersion}"; + return UsesPrefixedCalendarReleaseTags(normalizedVersion) + ? [prefixedTag, normalizedVersion] + : [normalizedVersion, prefixedTag]; + } + + public static string GetGitHubReleasePageUrl() + { + return ReleaseNotesUrl; + } + + public static string GetGitHubReleasePageUrlFromTag(string releaseTag) + { + return GitHubReleasePageBaseUrl + releaseTag; + } + + public static string GetGitHubReleaseApiUrlFromTag(string releaseTag) + { + return GitHubReleaseApiBaseUrl + Uri.EscapeDataString(releaseTag); + } + + private static bool UsesPrefixedCalendarReleaseTags(string versionName) + { + int dotIndex = versionName.IndexOf('.'); + if (dotIndex != 4 || dotIndex == versionName.Length - 1) + { + return false; + } + + ReadOnlySpan year = versionName.AsSpan(0, dotIndex); + return int.TryParse(year, out int parsedYear) && parsedYear >= 2000; + } + + private static bool? IS_PORTABLE; + private static string? PORTABLE_PATH; + public static bool IsPortable + { + get => IS_PORTABLE ?? false; + } + + public static string? TEST_DataDirectoryOverride { private get; set; } + + /// + /// The directory where all the user data is stored. The directory is automatically created if it does not exist. + /// + public static string UniGetUIDataDirectory + { + get + { + if (TEST_DataDirectoryOverride is not null) + { + return TEST_DataDirectoryOverride; + } + + if (IS_PORTABLE is null) + { + IS_PORTABLE = File.Exists( + Path.Join(UniGetUIExecutableDirectory, "ForceUniGetUIPortable") + ); + + if (IS_PORTABLE is true) + { + string path = Path.Join(UniGetUIExecutableDirectory, "Settings"); + try + { + if (!Directory.Exists(path)) + Directory.CreateDirectory(path); + var testfilepath = Path.Join(path, "PermissionTestFile"); + File.WriteAllText( + testfilepath, + "https://www.youtube.com/watch?v=dQw4w9WgXcQ" + ); + PORTABLE_PATH = path; + return path; + } + catch (Exception ex) + { + IS_PORTABLE = false; + Logger.Error( + $"Could not acces/write path {path}. UniGetUI will NOT be run in portable mode, and User settings will be used instead" + ); + Logger.Error(ex); + } + } + } + else if (IS_PORTABLE is true) + { + return PORTABLE_PATH + ?? throw new InvalidOperationException("This shouldn't be possible"); + } + + string old_path = Path.Join( + Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), + ".wingetui" + ); + string new_path = Path.Join(GetLocalDataRoot(), "UniGetUI"); + return GetNewDataDirectoryOrMoveOld(old_path, new_path); + } + } + + /// + /// The directory where the user configurations are stored. The directory is automatically created if it does not exist. + /// + public static string UniGetUIUserConfigurationDirectory + { + get + { + string oldConfigPath = UniGetUIDataDirectory; // Old config path was the data directory itself + string newConfigPath = Path.Join(UniGetUIDataDirectory, "Configuration"); + + if (Directory.Exists(oldConfigPath) && !Directory.Exists(newConfigPath)) + { + //Migration case + try + { + Logger.Info( + $"Moving configuration files from '{oldConfigPath}' to '{newConfigPath}'" + ); + Directory.CreateDirectory(newConfigPath); + + foreach ( + string file in Directory.GetFiles( + oldConfigPath, + "*.*", + SearchOption.TopDirectoryOnly + ) + ) + { + string fileName = Path.GetFileName(file); + string fileExtension = Path.GetExtension(file); + bool isConfigFile = + string.IsNullOrEmpty(fileExtension) + || fileExtension.ToLowerInvariant() == ".json"; + + if (isConfigFile) + { + string newFile = Path.Join(newConfigPath, fileName); + // Avoid overwriting if somehow file already exists + if (!File.Exists(newFile)) + { + File.Move(file, newFile); + Logger.Debug( + $"Moved configuration file '{file}' to '{newFile}'" + ); + } + // Clean up old file to avoid duplicates and confusion + else + { + Logger.Warn( + $"Configuration file '{newFile}' already exists, skipping move from '{file}'." + ); + File.Delete(file); + } + } + else + { + Logger.Debug( + $"Skipping non-configuration file '{file}' during migration." + ); + } + } + Logger.Info($"Configuration files moved successfully to '{newConfigPath}'"); + } + catch (Exception ex) + { + // Fallback to old path if migration fails to not break functionality + Logger.Error( + $"Error moving configuration files from '{oldConfigPath}' to '{newConfigPath}'. Using old path for now. Manual migration might be needed." + ); + Logger.Error(ex); + return oldConfigPath; + } + } + else if (!Directory.Exists(newConfigPath)) + { + //New install case, migration not needed + Directory.CreateDirectory(newConfigPath); + } + return newConfigPath; + } + } + + /// + /// The directory where the installation options are stored. The directory is automatically created if it does not exist. + /// + public static string UniGetUIInstallationOptionsDirectory + { + get + { + string path = Path.Join(UniGetUIDataDirectory, "InstallationOptions"); + if (!Directory.Exists(path)) + Directory.CreateDirectory(path); + return path; + } + } + + /// + /// The directory where the metadata cache is stored. The directory is automatically created if it does not exist. + /// + public static string UniGetUICacheDirectory_Data + { + get + { + string path = Path.Join(UniGetUIDataDirectory, "CachedMetadata"); + if (!Directory.Exists(path)) + Directory.CreateDirectory(path); + return path; + } + } + + /// + /// The directory where the cached icons and screenshots are saved. The directory is automatically created if it does not exist. + /// + public static string UniGetUICacheDirectory_Icons + { + get + { + string path = Path.Join(UniGetUIDataDirectory, "CachedMedia"); + if (!Directory.Exists(path)) + Directory.CreateDirectory(path); + return path; + } + } + + /// + /// The directory where the cached language files are stored. The directory is automatically created if it does not exist. + /// + public static string UniGetUICacheDirectory_Lang + { + get + { + string path = Path.Join(UniGetUIDataDirectory, "CachedLanguageFiles"); + if (!Directory.Exists(path)) + Directory.CreateDirectory(path); + return path; + } + } + + /// + /// The directory where package backups will be saved by default. + /// + public static string UniGetUI_DefaultBackupDirectory + { + get + { + string documentsDirectory = GetDocumentsRoot(); + string old_dir = Path.Join(documentsDirectory, "WingetUI"); + string new_dir = Path.Join(documentsDirectory, "UniGetUI"); + return GetNewDataDirectoryOrMoveOld(old_dir, new_dir); + } + } + + public static bool IsDaemon; + public static bool WasDaemon; + + /// + /// The ID of the notification that is used to inform the user that updates are available + /// + public const int UpdatesAvailableNotificationTag = 1234; + + /// + /// The ID of the notification that is used to inform the user that UniGetUI can be updated + /// + public const int UniGetUICanBeUpdated = 1235; + + /// + /// The ID of the notification that is used to inform the user that shortcuts are available for deletion + /// + public const int NewShortcutsNotificationTag = 1236; + + /// + /// A path pointing to the location where the app is installed + /// + public static string UniGetUIExecutableDirectory + { + get + { + string dir = NormalizeDirectoryPath(AppContext.BaseDirectory); + if (!string.IsNullOrEmpty(dir)) + { + return ResolveInstallationDirectory(dir); + } + + Logger.Error("AppContext.BaseDirectory returned an empty path"); + + return ResolveInstallationDirectory(NormalizeDirectoryPath(AppContext.BaseDirectory)); + } + } + + public static string ResolveInstallationDirectory( + string executableDirectory, + Func? fileExists = null, + Func? directoryExists = null + ) + { + fileExists ??= File.Exists; + directoryExists ??= Directory.Exists; + + string normalizedDirectory = NormalizeDirectoryPath(executableDirectory); + if (!string.Equals( + Path.GetFileName(normalizedDirectory), + BundledModernAppDirectoryName, + StringComparison.OrdinalIgnoreCase + )) + { + return normalizedDirectory; + } + + string? parentDirectory = Path.GetDirectoryName(normalizedDirectory); + if (string.IsNullOrEmpty(parentDirectory)) + { + return normalizedDirectory; + } + + parentDirectory = NormalizeDirectoryPath(parentDirectory); + return IsInstallRoot(parentDirectory, fileExists, directoryExists) + ? parentDirectory + : normalizedDirectory; + } + + /// + /// A path pointing to the executable file of the app + /// + public static string UniGetUIExecutableFile + { + get + { + string? filename = Process.GetCurrentProcess().MainModule?.FileName; + if (filename is not null) + { + return NormalizeExecutablePath(filename); + } + + Logger.Error( + "System.Reflection.Assembly.GetExecutingAssembly().Location returned an empty path" + ); + + return OperatingSystem.IsWindows() + ? Path.Join(UniGetUIExecutableDirectory, "UniGetUI.exe") + : NormalizeExecutablePath(Path.Join(UniGetUIExecutableDirectory, "UniGetUI")); + } + } + + public static string ElevatorPath = ""; + + /// + /// Extra arguments to insert between the elevator binary and the elevated command. + /// For example, "-A" when using sudo with an askpass helper on Linux. + /// + public static string ElevatorArgs = ""; + + /// + /// This method will return the most appropriate data directory. + /// If the new directory exists, it will be used. + /// If the new directory does not exist, but the old directory does, it will be moved to the new location, and the new location will be used. + /// If none exist, the new directory will be created. + /// + /// The old/legacy directory + /// The new directory + /// The path to an existing, valid directory + private static string GetNewDataDirectoryOrMoveOld(string old_path, string new_path) + { + if (Directory.Exists(new_path) && !Directory.Exists(old_path)) + { + return new_path; + } + + if (Directory.Exists(new_path) && Directory.Exists(old_path)) + { + try + { + foreach ( + string old_subdir in Directory.GetDirectories( + old_path, + "*", + SearchOption.AllDirectories + ) + ) + { + string new_subdir = old_subdir.Replace(old_path, new_path); + if (!Directory.Exists(new_subdir)) + { + Logger.Debug("New directory: " + new_subdir); + Directory.CreateDirectory(new_subdir); + } + else + { + Logger.Debug("Directory " + new_subdir + " already exists"); + } + } + + foreach ( + string old_file in Directory.GetFiles( + old_path, + "*", + SearchOption.AllDirectories + ) + ) + { + string new_file = old_file.Replace(old_path, new_path); + if (!File.Exists(new_file)) + { + Logger.Info("Copying " + old_file); + File.Move(old_file, new_file); + } + else + { + Logger.Debug("File " + new_file + " already exists."); + File.Delete(old_file); + } + } + + foreach ( + string old_subdir in Directory.GetDirectories( + old_path, + "*", + SearchOption.AllDirectories + ) + ) + { + if ( + !Directory.EnumerateFiles(old_subdir).Any() + && !Directory.EnumerateDirectories(old_subdir).Any() + ) + { + Logger.Debug("Deleting old empty subdirectory " + old_subdir); + Directory.Delete(old_subdir); + } + } + + if ( + !Directory.EnumerateFiles(old_path).Any() + && !Directory.EnumerateDirectories(old_path).Any() + ) + { + Logger.Info("Deleting old Chocolatey directory " + old_path); + Directory.Delete(old_path); + } + + return new_path; + } + catch (Exception e) + { + Logger.Error(e); + return new_path; + } + } + + if ( /*Directory.Exists(new_path)*/ + Directory.Exists(old_path) + ) + { + try + { + Directory.Move(old_path, new_path); + Task.Delay(100).Wait(); + return new_path; + } + catch (Exception e) + { + Logger.Error( + "Cannot move old data directory to new location. Directory to move: " + + old_path + + ". Destination: " + + new_path + ); + Logger.Error(e); + return old_path; + } + } + + try + { + Logger.Debug("Creating non-existing data directory at: " + new_path); + Directory.CreateDirectory(new_path); + return new_path; + } + catch (Exception e) + { + Logger.Error( + "Could not create new directory. You may perhaps need to disable Controlled Folder Access from Windows Settings or make an exception for UniGetUI." + ); + Logger.Error(e); + return new_path; + } + } + + private static int GetCodePage() + { + if (!OperatingSystem.IsWindows()) + { + return Encoding.UTF8.CodePage; + } + + try + { + using Process p = new Process + { + StartInfo = new ProcessStartInfo + { + FileName = "chcp.com", + RedirectStandardOutput = true, + UseShellExecute = false, + CreateNoWindow = true, + }, + }; + p.Start(); + string contents = p.StandardOutput.ReadToEnd(); + string purifiedString = ""; + + foreach (var c in contents.Split(':')[^1].Trim()) + { + if (c >= '0' && c <= '9') + { + purifiedString += c; + } + } + + return int.Parse(purifiedString); + } + catch (Exception e) + { + Logger.Error(e); + return 0; + } + } + + public static readonly string PowerShell5 = OperatingSystem.IsWindows() + ? Path.Join(Environment.SystemDirectory, "windowspowershell\\v1.0\\powershell.exe") + : "pwsh"; + + private static string GetLocalDataRoot() + { + string localApplicationData = Environment.GetFolderPath( + Environment.SpecialFolder.LocalApplicationData + ); + if (!string.IsNullOrWhiteSpace(localApplicationData)) + { + return localApplicationData; + } + + string? xdgDataHome = Environment.GetEnvironmentVariable("XDG_DATA_HOME"); + if (!string.IsNullOrWhiteSpace(xdgDataHome)) + { + return xdgDataHome; + } + + return Path.Join(GetUserHomeDirectory(), ".local", "share"); + } + + private static string GetDocumentsRoot() + { + string documentsDirectory = Environment.GetFolderPath( + Environment.SpecialFolder.MyDocuments + ); + if (!string.IsNullOrWhiteSpace(documentsDirectory)) + { + return documentsDirectory; + } + + return Path.Join(GetUserHomeDirectory(), "Documents"); + } + + private static string GetUserHomeDirectory() + { + string userProfile = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile); + if (!string.IsNullOrWhiteSpace(userProfile)) + { + return userProfile; + } + + return Environment.GetEnvironmentVariable("HOME") ?? AppContext.BaseDirectory; + } + + private static string NormalizeDirectoryPath(string path) + { + return Path.GetFullPath(path).TrimEnd( + Path.DirectorySeparatorChar, + Path.AltDirectorySeparatorChar + ); + } + + private static string NormalizeExecutablePath(string path) + { + if ( + OperatingSystem.IsWindows() + && path.EndsWith(".dll", StringComparison.OrdinalIgnoreCase) + ) + { + return Path.ChangeExtension(path, ".exe"); + } + + return path; + } + + private static bool IsInstallRoot( + string directory, + Func fileExists, + Func directoryExists + ) + { + return fileExists(Path.Join(directory, WindowsExecutableName)) + || fileExists(Path.Join(directory, BundledPingetExecutableName)) + || fileExists(Path.Join(directory, "IntegrityTree.json")) + || directoryExists(Path.Join(directory, "Assets", "Utilities")) + || directoryExists(Path.Join(directory, "Assets", "Data")); + } + } +} diff --git a/src/UniGetUI.Core.Data/InternalsVisibleTo.cs b/src/UniGetUI.Core.Data/InternalsVisibleTo.cs new file mode 100644 index 0000000..c9219af --- /dev/null +++ b/src/UniGetUI.Core.Data/InternalsVisibleTo.cs @@ -0,0 +1,3 @@ +using System.Runtime.CompilerServices; + +[assembly: InternalsVisibleTo("UniGetUI.Core.Data.Tests")] diff --git a/src/UniGetUI.Core.Data/Licenses.cs b/src/UniGetUI.Core.Data/Licenses.cs new file mode 100644 index 0000000..b2b8d45 --- /dev/null +++ b/src/UniGetUI.Core.Data/Licenses.cs @@ -0,0 +1,138 @@ +namespace UniGetUI.Core.Data +{ + public static class LicenseData + { + public static Dictionary LicenseNames = new() + { + { "UniGetUI", "MIT" }, + // C# Libraries + { "Pickers", "MIT" }, + { "Community Toolkit", "MIT" }, + { "H.NotifyIcon", "MIT" }, + { "Windows App Sdk", "MIT" }, + { "PhotoSauce.MagicScaler", "MIT" }, + { "YamlDotNet", "MIT" }, + { "InnoDependencyInstaller", "CPOL 1.02" }, + // Package managers and related + { "WinGet", "MIT" }, + { "Scoop", "MIT" }, + { "scoop-search", "MIT" }, + { "Chocolatey", "Apache v2" }, + { "npm", "Artistic License 2.0" }, + { "Pip", "MIT" }, + { "parse_pip_search", "MIT" }, + { "PowerShell Gallery", "Unknown" }, + { ".NET SDK", "MIT" }, + { "Cargo", "MIT" }, + { "cargo-binstall", "GPL-3.0-only" }, + { "cargo-update", "MIT" }, + { "vcpkg", "MIT" }, + // Other + { "GSudo", "MIT" }, + { "UniGetUI Elevator", "MIT" }, + { "Icons", "By Icons8" }, + }; + + public static Dictionary LicenseURLs = new() + { + { "UniGetUI", new Uri("https://github.com/Devolutions/UniGetUI/blob/main/LICENSE") }, + // C# Libraries + { "Pickers", new Uri("https://github.com/PavlikBender/Pickers/blob/master/LICENSE") }, + { + "Community Toolkit", + new Uri("https://github.com/CommunityToolkit/Windows/blob/main/License.md") + }, + { + "H.NotifyIcon", + new Uri("https://github.com/HavenDV/H.NotifyIcon/blob/master/LICENSE.md") + }, + { + "Windows App Sdk", + new Uri("https://github.com/microsoft/WindowsAppSDK/blob/main/LICENSE") + }, + { + "PhotoSauce.MagicScaler", + new Uri("https://github.com/saucecontrol/PhotoSauce/blob/master/license") + }, + { + "YamlDotNet", + new Uri("https://github.com/aaubry/YamlDotNet/blob/master/LICENSE.txt") + }, + { + "InnoDependencyInstaller", + new Uri( + "https://github.com/DomGries/InnoDependencyInstaller/blob/master/LICENSE.md" + ) + }, + // Package managers and related + { "WinGet", new Uri("https://github.com/microsoft/winget-cli/blob/master/LICENSE") }, + { "Scoop", new Uri("https://github.com/ScoopInstaller/Scoop/blob/master/LICENSE") }, + { + "scoop-search", + new Uri("https://github.com/shilangyu/scoop-search/blob/master/LICENSE") + }, + { "Chocolatey", new Uri("https://github.com/chocolatey/choco/blob/develop/LICENSE") }, + { "npm", new Uri("https://github.com/npm/cli/blob/latest/LICENSE") }, + { "Pip", new Uri("https://github.com/pypa/pip/blob/main/LICENSE.txt") }, + { + "parse_pip_search", + new Uri( + "https://github.com/marticliment/parseable_pip_search/blob/master/LICENSE.md" + ) + }, + { ".NET SDK", new Uri("https://github.com/dotnet/sdk/blob/main/LICENSE.TXT") }, + { "PowerShell Gallery", new Uri("https://www.powershellgallery.com/") }, + { "Cargo", new Uri("https://github.com/rust-lang/cargo/blob/master/LICENSE-MIT") }, + { "cargo-binstall", new Uri("https://spdx.org/licenses/GPL-3.0-only.html") }, + { + "cargo-update", + new Uri("https://github.com/nabijaczleweli/cargo-update/blob/master/LICENSE") + }, + { "vcpkg", new Uri("https://github.com/microsoft/vcpkg/blob/master/LICENSE.txt") }, + // Other + { "GSudo", new Uri("https://github.com/gerardog/gsudo/blob/master/LICENSE.txt") }, + { + "UniGetUI Elevator", + new Uri("https://github.com/Devolutions/gsudo-distro/blob/master/LICENSE") + }, + { "Icons", new Uri("https://icons8.com/license") }, + }; + + public static Dictionary HomepageUrls = new() + { + { "UniGetUI", new Uri("https://devolutions.net/unigetui") }, + // C# Libraries + { "Pickers", new Uri("https://github.com/PavlikBender/Pickers/") }, + { "Community Toolkit", new Uri("https://github.com/CommunityToolkit/Windows/") }, + { "H.NotifyIcon", new Uri("https://github.com/HavenDV/H.NotifyIcon/") }, + { "Windows App Sdk", new Uri("https://github.com/microsoft/WindowsAppSDK/") }, + { "PhotoSauce.MagicScaler", new Uri("https://github.com/saucecontrol/PhotoSauce/") }, + { "YamlDotNet", new Uri("https://github.com/aaubry/YamlDotNet/") }, + { + "InnoDependencyInstaller", + new Uri("https://github.com/DomGries/InnoDependencyInstaller") + }, + // Package managers and related + { "WinGet", new Uri("https://github.com/microsoft/winget-cli/") }, + { "Scoop", new Uri("https://github.com/ScoopInstaller/Scoop/") }, + { "scoop-search", new Uri("https://github.com/shilangyu/scoop-search/") }, + { "Chocolatey", new Uri("https://github.com/chocolatey/choco/") }, + { "npm", new Uri("https://github.com/npm/cli/") }, + { "Pip", new Uri("https://github.com/pypa/pip/") }, + { + "parse_pip_search", + new Uri("https://github.com/marticliment/parseable_pip_search/") + }, + { ".NET SDK", new Uri("https://dotnet.microsoft.com/") }, + { "PowerShell Gallery", new Uri("https://www.powershellgallery.com/") }, + { "Cargo", new Uri("https://github.com/rust-lang/cargo") }, + { "cargo-binstall", new Uri("https://github.com/cargo-bins/cargo-binstall") }, + { "cargo-update", new Uri("https://github.com/nabijaczleweli/cargo-update/") }, + { "vcpkg", new Uri("https://github.com/microsoft/vcpkg") }, + // Other + { "GSudo", new Uri("https://github.com/gerardog/gsudo/") }, + { "UniGetUI Elevator", new Uri("https://github.com/Devolutions/gsudo-distro") }, + { "Icons", new Uri("https://icons8.com") }, + }; + } +} diff --git a/src/UniGetUI.Core.Data/UniGetUI.Core.Data.csproj b/src/UniGetUI.Core.Data/UniGetUI.Core.Data.csproj new file mode 100644 index 0000000..9277739 --- /dev/null +++ b/src/UniGetUI.Core.Data/UniGetUI.Core.Data.csproj @@ -0,0 +1,24 @@ + + + $(SharedTargetFrameworks) + + + + + + + + + PreserveNewest + + + + + + + + + + + + diff --git a/src/UniGetUI.Core.Data/UpdateInProgressGuard.cs b/src/UniGetUI.Core.Data/UpdateInProgressGuard.cs new file mode 100644 index 0000000..af85fa4 --- /dev/null +++ b/src/UniGetUI.Core.Data/UpdateInProgressGuard.cs @@ -0,0 +1,76 @@ +using System.Diagnostics; + +namespace UniGetUI.Core.Data +{ + // Blocks UI startup while the Windows installer is replacing files in {app} (see UniGetUI.iss), + // so an instance launched mid-update doesn't load a half-written binary set and crash. + public static class UpdateInProgressGuard + { + // MUST match the marker name written by UniGetUI.iss. The file holds the installer's PID. + public const string MarkerFileName = ".unigetui-update-in-progress"; + + public static bool IsUpdateInProgress() + { + if (!OperatingSystem.IsWindows()) + return false; + + return IsUpdateInProgress(AppContext.BaseDirectory); + } + + // Checks the running dir and its parent (the Avalonia UI runs from {app}\Avalonia). + internal static bool IsUpdateInProgress(string baseDirectory) + => IsUpdateInProgress(baseDirectory, IsProcessRunning); + + internal static bool IsUpdateInProgress(string baseDirectory, Func isProcessRunning) + { + try + { + if (MarkerIsActive(baseDirectory, isProcessRunning)) + return true; + + string? parent = Directory + .GetParent(baseDirectory.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar)) + ?.FullName; + return parent is not null && MarkerIsActive(parent, isProcessRunning); + } + catch + { + return false; + } + } + + // Active only while the installer that wrote the PID is still running, so the guard tracks + // the real copy window (any duration) and self-heals if the installer dies without cleanup. + private static bool MarkerIsActive(string directory, Func isProcessRunning) + { + string marker = Path.Combine(directory, MarkerFileName); + if (!File.Exists(marker)) + return false; + + if (!int.TryParse(File.ReadAllText(marker).Trim(), out int pid)) + return false; // unreadable (e.g. racing the installer's write) — leave it alone + + if (isProcessRunning(pid)) + return true; + + try { File.Delete(marker); } catch { /* stale: installer is gone */ } + return false; + } + + private static bool IsProcessRunning(int pid) + { + if (pid <= 0) + return false; + + try + { + using var process = Process.GetProcessById(pid); + return !process.HasExited; + } + catch (ArgumentException) + { + return false; + } + } + } +} diff --git a/src/UniGetUI.Core.IconEngine.Tests/IconCacheEngineTests.cs b/src/UniGetUI.Core.IconEngine.Tests/IconCacheEngineTests.cs new file mode 100644 index 0000000..9b6391f --- /dev/null +++ b/src/UniGetUI.Core.IconEngine.Tests/IconCacheEngineTests.cs @@ -0,0 +1,305 @@ +using UniGetUI.Core.Data; + +namespace UniGetUI.Core.IconEngine.Tests +{ + public static class IconCacheEngineTests + { + private const string UniGetUiIconUrl = + "https://raw.githubusercontent.com/Devolutions/UniGetUI/main/src/UniGetUI.Core.IconEngine.Tests/TestData/unigetui.png"; + + private const string ElevenClockIconUrl = + "https://raw.githubusercontent.com/Devolutions/UniGetUI/main/src/UniGetUI.Core.IconEngine.Tests/TestData/elevenclock.png"; + + [Fact] + public static void TestCacheEngineForSha256() + { + Uri ICON_1 = new Uri(UniGetUiIconUrl); + byte[] HASH_1 = + [ + 0xB7, + 0x41, + 0xC3, + 0x18, + 0xBF, + 0x2B, + 0x07, + 0xAA, + 0x92, + 0xB2, + 0x7A, + 0x1B, + 0x4D, + 0xC5, + 0xEE, + 0xC4, + 0xD1, + 0x9B, + 0x22, + 0xD4, + 0x0A, + 0x13, + 0x26, + 0xA7, + 0x45, + 0xA4, + 0xA7, + 0xF5, + 0x81, + 0x8E, + 0xAF, + 0xFF, + ]; + Uri ICON_2 = new Uri(ElevenClockIconUrl); + byte[] HASH_2 = + [ + 0x9E, + 0xB8, + 0x7A, + 0x5A, + 0x64, + 0xCA, + 0x6D, + 0x8D, + 0x0A, + 0x7B, + 0x98, + 0xC5, + 0x4F, + 0x6A, + 0x58, + 0x72, + 0xFD, + 0x94, + 0xC9, + 0xA6, + 0x82, + 0xB3, + 0x2B, + 0x90, + 0x70, + 0x66, + 0x66, + 0x1C, + 0xBF, + 0x81, + 0x97, + 0x97, + ]; + + string managerName = "TestManager"; + string packageId = "Package55"; + + string extension = ICON_1.ToString().Split(".")[^1]; + string expectedFile = Path.Join( + CoreData.UniGetUICacheDirectory_Icons, + managerName, + packageId, + $"icon.{extension}" + ); + if (File.Exists(expectedFile)) + { + File.Delete(expectedFile); + } + + // Download a hashed icon + CacheableIcon icon = new(ICON_1, HASH_1); + string? path = IconCacheEngine.GetCacheOrDownloadIcon(icon, managerName, packageId, 0); + Assert.NotNull(path); + Assert.Equal(expectedFile, path); + Assert.True(File.Exists(path)); + + DateTime oldModificationDate = File.GetLastWriteTime(path); + + // Test the same icon, modification date shouldn't change + icon = new CacheableIcon(ICON_1, HASH_1); + path = IconCacheEngine.GetCacheOrDownloadIcon(icon, managerName, packageId, 0); + Assert.NotNull(path); + DateTime newModificationDate = File.GetLastWriteTime(path); + + Assert.Equal(oldModificationDate, newModificationDate); + Assert.Equal(expectedFile, path); + Assert.True(File.Exists(path)); + + // Attempt to retrieve a different icon. The modification date SHOULD have changed + icon = new CacheableIcon(ICON_2, HASH_2); + path = IconCacheEngine.GetCacheOrDownloadIcon(icon, managerName, packageId, 0); + Assert.NotNull(path); + DateTime newIconModificationDate = File.GetLastWriteTime(path); + + Assert.NotEqual(oldModificationDate, newIconModificationDate); + Assert.Equal(expectedFile, path); + Assert.True(File.Exists(path)); + + // Give an invalid hash: The icon should not be cached not returned + icon = new CacheableIcon(ICON_2, HASH_1); + path = IconCacheEngine.GetCacheOrDownloadIcon(icon, managerName, packageId, 0); + Assert.Null(path); + Assert.False(File.Exists(path)); + } + + [Fact] + public static void TestCacheEngineForPackageVersion() + { + Uri URI = new Uri(UniGetUiIconUrl); + string VERSION = "v3.01"; + string MANAGER_NAME = "TestManager"; + string PACKAGE_ID = "Package2"; + + string extension = URI.ToString().Split(".")[^1]; + string expectedFile = Path.Join( + CoreData.UniGetUICacheDirectory_Icons, + MANAGER_NAME, + PACKAGE_ID, + $"icon.{extension}" + ); + if (File.Exists(expectedFile)) + { + File.Delete(expectedFile); + } + + // Download an icon through version verification + CacheableIcon icon = new(URI, VERSION); + string? path = IconCacheEngine.GetCacheOrDownloadIcon( + icon, + MANAGER_NAME, + PACKAGE_ID, + 0 + ); + Assert.NotNull(path); + Assert.Equal(expectedFile, path); + Assert.True(File.Exists(path)); + + DateTime oldModificationDate = File.GetLastWriteTime(path); + + // Test the same version, the icon should not get touched + icon = new CacheableIcon(URI, VERSION); + path = IconCacheEngine.GetCacheOrDownloadIcon(icon, MANAGER_NAME, PACKAGE_ID, 0); + Assert.NotNull(path); + DateTime newModificationDate = File.GetLastWriteTime(path); + + Assert.Equal(oldModificationDate, newModificationDate); + Assert.Equal(expectedFile, path); + Assert.True(File.Exists(path)); + + // Test a new version, the icon should be downloaded again + icon = new CacheableIcon(URI, VERSION + "-beta0"); + path = IconCacheEngine.GetCacheOrDownloadIcon(icon, MANAGER_NAME, PACKAGE_ID, 0); + Assert.NotNull(path); + DateTime newNewModificationDate = File.GetLastWriteTime(path); + + Assert.Equal(oldModificationDate, newNewModificationDate); + Assert.Equal(expectedFile, path); + Assert.True(File.Exists(path)); + } + + [Fact] + public static void TestCacheEngineForIconUri() + { + Uri URI_1 = new Uri(UniGetUiIconUrl); + Uri URI_2 = new Uri(ElevenClockIconUrl); + string managerName = "TestManager"; + string packageId = "Package12"; + + string extension = URI_1.ToString().Split(".")[^1]; + string expectedFile = Path.Join( + CoreData.UniGetUICacheDirectory_Icons, + managerName, + packageId, + $"icon.{extension}" + ); + if (File.Exists(expectedFile)) + { + File.Delete(expectedFile); + } + + // Download an icon through URI verification + CacheableIcon icon = new(URI_1); + string? path = IconCacheEngine.GetCacheOrDownloadIcon(icon, managerName, packageId, 0); + Assert.NotNull(path); + Assert.Equal(expectedFile, path); + Assert.True(File.Exists(path)); + + DateTime oldModificationDate = File.GetLastWriteTime(path); + + // Test the same URI, the icon should not get touched + icon = new CacheableIcon(URI_1); + path = IconCacheEngine.GetCacheOrDownloadIcon(icon, managerName, packageId, 0); + Assert.NotNull(path); + DateTime newModificationDate = File.GetLastWriteTime(path); + + Assert.Equal(oldModificationDate, newModificationDate); + Assert.Equal(expectedFile, path); + Assert.True(File.Exists(path)); + + // Test a new URI, the icon should be downloaded again + icon = new CacheableIcon(URI_2); + path = IconCacheEngine.GetCacheOrDownloadIcon(icon, managerName, packageId, 0); + Assert.NotNull(path); + DateTime newNewModificationDate = File.GetLastWriteTime(path); + + Assert.NotEqual(oldModificationDate, newNewModificationDate); + Assert.Equal(expectedFile, path); + Assert.True(File.Exists(path)); + } + + [Fact] + public static void TestCacheEngineForPackageSize() + { + Uri ICON_1 = new Uri(UniGetUiIconUrl); + int ICON_1_SIZE = 19788; + Uri ICON_2 = new Uri(ElevenClockIconUrl); + int ICON_2_SIZE = 19747; + string managerName = "TestManager"; + string packageId = "Package3"; + + // Clear any cache for reproducible data + string extension = ICON_1.ToString().Split(".")[^1]; + string expectedFile = Path.Join( + CoreData.UniGetUICacheDirectory_Icons, + managerName, + packageId, + $"icon.{extension}" + ); + if (File.Exists(expectedFile)) + { + File.Delete(expectedFile); + } + + // Cache an icon + CacheableIcon icon = new(ICON_1, ICON_1_SIZE); + string? path = IconCacheEngine.GetCacheOrDownloadIcon(icon, managerName, packageId, 0); + Assert.NotNull(path); + Assert.Equal(expectedFile, path); + Assert.True(File.Exists(path)); + + DateTime oldModificationDate = File.GetLastWriteTime(path); + + // Attempt to retrieve the same icon again. + icon = new CacheableIcon(ICON_1, ICON_1_SIZE); + path = IconCacheEngine.GetCacheOrDownloadIcon(icon, managerName, packageId, 0); + Assert.NotNull(path); + DateTime newModificationDate = File.GetLastWriteTime(path); + + // The modification date shouldn't have changed + Assert.Equal(oldModificationDate, newModificationDate); + Assert.Equal(expectedFile, path); + Assert.True(File.Exists(path)); + + // Attempt to retrieve a different icon. The modification date SHOULD have changed + icon = new CacheableIcon(ICON_2, ICON_2_SIZE); + path = IconCacheEngine.GetCacheOrDownloadIcon(icon, managerName, packageId, 0); + Assert.NotNull(path); + DateTime newIconModificationDate = File.GetLastWriteTime(path); + + Assert.NotEqual(oldModificationDate, newIconModificationDate); + Assert.Equal(expectedFile, path); + Assert.True(File.Exists(path)); + + // Give an invalid size: The icon should not be cached not returned + icon = new CacheableIcon(ICON_1, ICON_1_SIZE + 1); + path = IconCacheEngine.GetCacheOrDownloadIcon(icon, managerName, packageId, 0); + Assert.Null(path); + Assert.False(File.Exists(path)); + } + } +} diff --git a/src/UniGetUI.Core.IconEngine.Tests/IconDatabaseTests.cs b/src/UniGetUI.Core.IconEngine.Tests/IconDatabaseTests.cs new file mode 100644 index 0000000..56df770 --- /dev/null +++ b/src/UniGetUI.Core.IconEngine.Tests/IconDatabaseTests.cs @@ -0,0 +1,78 @@ +namespace UniGetUI.Core.IconEngine.Tests +{ + public class IconDatabaseTests + { + private readonly IconDatabase iconStore = new(); + + [Fact] + public async Task LoadIconsAndScreenshotsDatabaseTest() + { + // Serializable is implicitly tested when calling the method + // LoadIconAndScreenshotsDatabase() + + await iconStore.LoadIconAndScreenshotsDatabaseAsync(); + + IconDatabase.IconCount iconCount = iconStore.GetIconCount(); + Assert.NotEqual(0, iconCount.PackagesWithIconCount); + Assert.NotEqual(0, iconCount.PackagesWithScreenshotCount); + Assert.NotEqual(0, iconCount.TotalScreenshotCount); + } + + [Fact] + public async Task TestGetExistingIconAndImagesAsync() + { + await iconStore.LoadIconAndScreenshotsDatabaseAsync(); + + string? icon = iconStore.GetIconUrlForId("__test_entry_DO_NOT_EDIT_PLEASE"); + Assert.Equal("https://this.is.a.test/url/used_for/automated_unit_testing.png", icon); + + string[] screenshots = iconStore.GetScreenshotsUrlForId( + "__test_entry_DO_NOT_EDIT_PLEASE" + ); + Assert.Equal(3, screenshots.Length); + Assert.Equal("https://image_number.com/1.png", screenshots[0]); + Assert.Equal("https://image_number.com/2.png", screenshots[1]); + Assert.Equal("https://image_number.com/3.png", screenshots[2]); + } + + [Fact] + public async Task TestGetNonExistingIconAndImagesAsync() + { + await iconStore.LoadIconAndScreenshotsDatabaseAsync(); + + string? nonexistent_icon = iconStore.GetIconUrlForId( + "__test_entry_THIS_ICON_DOES_NOT_EXTST" + ); + Assert.Null(nonexistent_icon); + + string[] nonexistent_screenshots = iconStore.GetScreenshotsUrlForId( + "__test_entry_THIS_ICON_DOES_NOT_EXTST" + ); + Assert.Empty(nonexistent_screenshots); + } + + [Fact] + public void TestCachedDatabaseFreshness() + { + string path = Path.Join(Path.GetTempPath(), Guid.NewGuid().ToString("N")); + try + { + File.WriteAllText(path, "{}"); + DateTime now = DateTime.UtcNow; + + File.SetLastWriteTimeUtc(path, now.AddHours(-23)); + Assert.True(IconDatabase.IsCachedDatabaseFresh(path, now)); + + File.SetLastWriteTimeUtc(path, now.AddHours(-25)); + Assert.False(IconDatabase.IsCachedDatabaseFresh(path, now)); + } + finally + { + if (File.Exists(path)) + { + File.Delete(path); + } + } + } + } +} diff --git a/src/UniGetUI.Core.IconEngine.Tests/TestData/elevenclock.png b/src/UniGetUI.Core.IconEngine.Tests/TestData/elevenclock.png new file mode 100644 index 0000000..0327d77 Binary files /dev/null and b/src/UniGetUI.Core.IconEngine.Tests/TestData/elevenclock.png differ diff --git a/src/UniGetUI.Core.IconEngine.Tests/TestData/unigetui.png b/src/UniGetUI.Core.IconEngine.Tests/TestData/unigetui.png new file mode 100644 index 0000000..d051352 Binary files /dev/null and b/src/UniGetUI.Core.IconEngine.Tests/TestData/unigetui.png differ diff --git a/src/UniGetUI.Core.IconEngine.Tests/UniGetUI.Core.IconEngine.Tests.csproj b/src/UniGetUI.Core.IconEngine.Tests/UniGetUI.Core.IconEngine.Tests.csproj new file mode 100644 index 0000000..57a4eff --- /dev/null +++ b/src/UniGetUI.Core.IconEngine.Tests/UniGetUI.Core.IconEngine.Tests.csproj @@ -0,0 +1,38 @@ + + + $(PortableTargetFramework) + + false + true + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + + + + + + + + + + + diff --git a/src/UniGetUI.Core.IconStore/IconCacheEngine.cs b/src/UniGetUI.Core.IconStore/IconCacheEngine.cs new file mode 100644 index 0000000..2de35b9 --- /dev/null +++ b/src/UniGetUI.Core.IconStore/IconCacheEngine.cs @@ -0,0 +1,479 @@ +using System.Collections.ObjectModel; +using System.Security.Cryptography; +using PhotoSauce.MagicScaler; +using UniGetUI.Core.Classes; +using UniGetUI.Core.Data; +using UniGetUI.Core.Logging; +using UniGetUI.Core.Tools; + +namespace UniGetUI.Core.IconEngine +{ + public enum IconValidationMethod + { + SHA256, + FileSize, + PackageVersion, + UriSource, + } + + public readonly struct CacheableIcon + { + public readonly Uri Url; + public readonly byte[] SHA256 = []; + public readonly string Version = ""; + public readonly long Size = -1; + private readonly int _hashCode = -1; + public readonly bool IsLocalPath = false; + public readonly string LocalPath = ""; + public readonly IconValidationMethod ValidationMethod; + + /// + /// Build a cacheable icon with SHA256 verification + /// + /// + /// + public CacheableIcon(Uri uri, byte[] Sha256) + { + Url = uri; + this.SHA256 = Sha256; + ValidationMethod = IconValidationMethod.SHA256; + _hashCode = + uri.ToString().GetHashCode() + Sha256[0] + Sha256[1] + Sha256[2] + Sha256[3]; + } + + /// + /// Build a cacheable icon with Version verification + /// + /// + /// + public CacheableIcon(Uri uri, string version) + { + Url = uri; + Version = version; + ValidationMethod = IconValidationMethod.PackageVersion; + _hashCode = uri.ToString().GetHashCode() + version.GetHashCode(); + } + + /// + /// Build a cacheable icon with Size verification + /// + /// + /// + public CacheableIcon(Uri uri, long size) + { + Url = uri; + Size = size; + ValidationMethod = IconValidationMethod.FileSize; + _hashCode = uri.ToString().GetHashCode() + (int)size; + } + + /// + /// Build a cacheable icon with Uri verification + /// + /// + public CacheableIcon(Uri uri) + { + Url = uri; + ValidationMethod = IconValidationMethod.UriSource; + _hashCode = uri.ToString().GetHashCode(); + } + + public CacheableIcon(string path) + { + IsLocalPath = true; + LocalPath = path; + Url = new Uri(path); + } + + public override int GetHashCode() + { + return _hashCode; + } + } + + public static class IconCacheEngine + { + /// + /// Returns the path to the icon file, downloading it if necessary + /// + /// a CacheableIcon object representing the object + /// The name of the PackageManager + /// the Id of the package + /// the Time to store the icons on the TaskRecycler cache + /// A path to a local icon file + public static string? GetCacheOrDownloadIcon( + CacheableIcon? icon, + string ManagerName, + string PackageId, + int cacheInterval = 30 + ) => + TaskRecycler.RunOrAttach( + _getCacheOrDownloadIcon, + icon, + ManagerName, + PackageId, + cacheInterval + ); + + private static string? _getCacheOrDownloadIcon( + CacheableIcon? _icon, + string ManagerName, + string PackageId + ) + { + if (_icon is null) + return null; + + var icon = _icon.Value; + + if (icon.IsLocalPath) + return icon.LocalPath; + + string iconLocation = Path.Join( + CoreData.UniGetUICacheDirectory_Icons, + ManagerName, + PackageId + ); + if (!Directory.Exists(iconLocation)) + Directory.CreateDirectory(iconLocation); + string iconVersionFile = Path.Join(iconLocation, $"icon.version"); + string iconUriFile = Path.Join(iconLocation, $"icon.uri"); + + // Get a local cache, if any + string? cachedIconFile = GetLocalCachedFile(icon, iconLocation); + + bool isLocalCacheValid = // Verify if the cached icon exists and is valid + cachedIconFile is not null + && icon.ValidationMethod switch + { + IconValidationMethod.FileSize => ValidateByImageSize(icon, cachedIconFile), + IconValidationMethod.SHA256 => ValidateBySHA256(icon, cachedIconFile), + IconValidationMethod.PackageVersion => ValidateByVersion(icon, iconVersionFile), + IconValidationMethod.UriSource => ValidateByUri(icon, iconUriFile), + _ => throw new InvalidDataException("Invalid icon validation method"), + }; + + // If a valid cache was found, return that cache + if (isLocalCacheValid) + { + Logger.Debug( + $"Cached icon for id={PackageId} is valid and won't be downloaded again ({icon.ValidationMethod})" + ); + return cachedIconFile; + } + + if (cachedIconFile is not null) + Logger.ImportantInfo( + $"Cached icon for id={PackageId} is INVALID ({icon.ValidationMethod})" + ); + + return SaveIconToCacheAndGetPath(icon, iconLocation); + } + + private static string? GetLocalCachedFile(CacheableIcon icon, string iconLocation) + { + if (!Directory.Exists(iconLocation)) + return null; // The directory does not exist + + string iconFileMime = Path.Join(iconLocation, $"icon.mime"); + if (!File.Exists(iconFileMime)) + return null; // If there is no mimetype for the saved icon + + if (!MimeToExtension.TryGetValue(File.ReadAllText(iconFileMime), out string? extension)) + return null; // If the saved mimetype is not valid + + string cachedIconFile = Path.Join(iconLocation, $"icon.{extension}"); + if (!File.Exists(cachedIconFile)) + return null; // If there is no saved file cache + + string iconVersionFile = Path.Join(iconLocation, $"icon.version"); + string iconUriFile = Path.Join(iconLocation, $"icon.uri"); + if ( + icon.ValidationMethod is IconValidationMethod.PackageVersion + && !File.Exists(iconVersionFile) + ) + return null; // If version file does not exist and icon is versioned + + if ( + icon.ValidationMethod is IconValidationMethod.UriSource + && !File.Exists(iconUriFile) + ) + return null; // If uri file does not exist and icon is versioned + + return cachedIconFile; + } + + private static string? SaveIconToCacheAndGetPath(CacheableIcon icon, string iconLocation) + { + try + { + string iconVersionFile = Path.Join(iconLocation, $"icon.version"); + string iconUriFile = Path.Join(iconLocation, $"icon.uri"); + + // If the cache is determined to NOT be valid, delete cache + DeteteCachedFiles(iconLocation); + + // After discarding the cache, regenerate it + using HttpClient client = new(CoreTools.GenericHttpClientParameters); + client.DefaultRequestHeaders.UserAgent.ParseAdd(CoreData.UserAgentString); + + using var request = new HttpRequestMessage(HttpMethod.Get, icon.Url); + using HttpResponseMessage response = client.Send(request); + if (!response.IsSuccessStatusCode) + { + Logger.Warn( + $"Icon download attempt at {icon.Url} failed with code {response.StatusCode}" + ); + return null; + } + + string mimeType = response.Content.Headers.GetValues("Content-Type").First(); + if (!MimeToExtension.TryGetValue(mimeType, out string? extension)) + { + Logger.Warn( + $"Unknown mimetype {mimeType} for icon {icon.Url}, aborting download" + ); + return null; + } + + string cachedIconFile = Path.Join(iconLocation, $"icon.{extension}"); + string iconFileMime = Path.Join(iconLocation, $"icon.mime"); + File.WriteAllText(iconFileMime, mimeType); + + using (Stream stream = response.Content.ReadAsStream()) + using (FileStream fileStream = File.Create(cachedIconFile)) + { + stream.CopyTo(fileStream); + } + + if (icon.ValidationMethod is IconValidationMethod.PackageVersion) + File.WriteAllText(iconVersionFile, icon.Version); + + if (icon.ValidationMethod is IconValidationMethod.UriSource) + File.WriteAllText(iconUriFile, icon.Url.ToString()); + + // Ensure the new icon has been properly downloaded + bool isNewCacheValid = icon.ValidationMethod switch + { + IconValidationMethod.FileSize => ValidateByImageSize(icon, cachedIconFile), + IconValidationMethod.SHA256 => ValidateBySHA256(icon, cachedIconFile), + IconValidationMethod.PackageVersion => true, // The validation result would be always true + IconValidationMethod.UriSource => true, // The validation result would be always true + _ => throw new InvalidDataException("Invalid icon validation method"), + }; + + if (isNewCacheValid) + { + if ( + icon.ValidationMethod + is IconValidationMethod.PackageVersion + or IconValidationMethod.UriSource + && new[] { "png", "webp", "tif", "avif" }.Contains(extension) + ) + { + DownsizeImage(cachedIconFile); + } + + Logger.Debug( + $"Icon for Location={iconLocation} has been downloaded and verified properly (if applicable) ({icon.ValidationMethod})" + ); + return cachedIconFile; + } + + Logger.Warn( + $"NEWLY DOWNLOADED Icon for Location={iconLocation} Uri={icon.Url} is NOT VALID and will be discarded (verification method is {icon.ValidationMethod})" + ); + DeteteCachedFiles(iconLocation); + return null; + } + catch (Exception ex) + { + Logger.Error(ex); + return null; + } + } + + /// + /// The given image will be downsized to the expected size of an icon, if required + /// + private static void DownsizeImage(string cachedIconFile) + { + try + { + const int MAX_SIDE = 192; + ImageFileInfo imageInfo = ImageFileInfo.Load(cachedIconFile); + ImageFileInfo.FrameInfo frameInfo = imageInfo.Frames[0]; + int width = frameInfo.Width; + int height = frameInfo.Height; + + // Calculate target size for the icon to be at max 192x192. + if (width > MAX_SIDE || height > MAX_SIDE) + { + File.Move(cachedIconFile, $"{cachedIconFile}.copy"); + using ( + var image = MagicImageProcessor.BuildPipeline( + $"{cachedIconFile}.copy", + new ProcessImageSettings + { + Width = MAX_SIDE, + Height = MAX_SIDE, + ResizeMode = CropScaleMode.Contain, + } + ) + ) + { + // Apply changes and save the image to disk + using (FileStream fileStream = File.Create(cachedIconFile)) + { + image.WriteOutput(fileStream); + } + Logger.Debug( + $"File {cachedIconFile} was downsized from {width}x{height} to {image.Settings.Width}x{image.Settings.Height}" + ); + } + File.Delete($"{cachedIconFile}.copy"); + } + else + { + Logger.Debug( + $"File {cachedIconFile} had an already appropiate size of {width}x{height}" + ); + } + } + catch (Exception ex) + { + Logger.Error($"An error occurred while downsizing the image file {cachedIconFile}"); + Logger.Error(ex); + } + } + + /// + /// Checks whether a cached image is valid or not depending on the size (in bytes) of the image + /// + private static bool ValidateByImageSize(CacheableIcon icon, string cachedIconPath) + { + try + { + FileInfo fileInfo = new FileInfo(cachedIconPath); + return icon.Size == fileInfo.Length; + } + catch (Exception e) + { + Logger.Warn( + $"Failed to verify icon file size for {icon.Url} via FileSize with error {e.Message}" + ); + return false; + } + } + + /// + /// Checks whether a cached image is valid or not depending on its SHA256 hash + /// + private static bool ValidateBySHA256(CacheableIcon icon, string cachedIconPath) + { + try + { + using FileStream stream = File.OpenRead(cachedIconPath); + using SHA256 sha256 = SHA256.Create(); + return (sha256.ComputeHash(stream)).SequenceEqual(icon.SHA256); + } + catch (Exception e) + { + Logger.Warn( + $"Failed to verify icon file size for {icon.Url} via Sha256 with error {e.Message}" + ); + return false; + } + } + + /// + /// Checks whether a cached image is valid or not depending on the package version it was pulled from + /// + private static bool ValidateByVersion(CacheableIcon icon, string versionPath) + { + try + { + return File.Exists(versionPath) + && CoreTools.VersionStringToStruct(File.ReadAllText(versionPath)) + >= CoreTools.VersionStringToStruct(icon.Version); + } + catch (Exception e) + { + Logger.Warn( + $"Failed to verify icon file size for {icon.Url} via PackageVersion with error {e.Message}" + ); + return false; + } + } + + /// + /// Checks whether a cached image is valid or not depending on the URI it was pulled from + /// + private static bool ValidateByUri(CacheableIcon icon, string uriPath) + { + try + { + return File.Exists(uriPath) && File.ReadAllText(uriPath) == icon.Url.ToString(); + } + catch (Exception e) + { + Logger.Warn( + $"Failed to verify icon file size for {icon.Url} via UriSource with error {e.Message}" + ); + return false; + } + } + + /// + /// Deletes all the cache files for a [icon] directory + /// + private static void DeteteCachedFiles(string iconLocation) + { + try + { + foreach (string file in Directory.GetFiles(iconLocation)) + { + File.Delete(file); + } + } + catch (Exception e) + { + Logger.Warn($"An error occurred while deleting old icon cache: {e.Message}"); + } + } + + public static readonly ReadOnlyDictionary MimeToExtension = + new ReadOnlyDictionary( + new Dictionary + { + { "image/avif", "avif" }, + { "image/gif", "gif" }, + // {"image/bmp", "bmp"}, Should non-transparent types be allowed? + // {"image/jpeg", "jpg"}, + { "image/png", "png" }, + { "image/webp", "webp" }, + { "image/svg+xml", "svg" }, + { "image/vnd.microsoft.icon", "ico" }, + { "application/octet-stream", "ico" }, + { "image/image/x-icon", "ico" }, + { "image/tiff", "tif" }, + } + ); + + public static readonly ReadOnlyDictionary ExtensionToMime = + new ReadOnlyDictionary( + new Dictionary + { + { "avif", "image/avif" }, + { "gif", "image/gif" }, + // {"bmp", "image/bmp"}, Should non-transparent types be allowed + // {"jpg", "image/jpeg"}, + { "png", "image/png" }, + { "webp", "image/webp" }, + { "svg", "image/svg+xml" }, + { "ico", "image/image/x-icon" }, + { "tif", "image/tiff" }, + } + ); + } +} diff --git a/src/UniGetUI.Core.IconStore/IconDatabase.cs b/src/UniGetUI.Core.IconStore/IconDatabase.cs new file mode 100644 index 0000000..32118b3 --- /dev/null +++ b/src/UniGetUI.Core.IconStore/IconDatabase.cs @@ -0,0 +1,171 @@ +using System.Text.Json; +using UniGetUI.Core.Data; +using UniGetUI.Core.Logging; +using UniGetUI.Core.SettingsEngine; +using UniGetUI.Core.Tools; + +namespace UniGetUI.Core.IconEngine +{ + /// + /// This class represents the structure of the icon and screenshot database. It is used to deserialize the JSON data. + /// + public class IconDatabase + { + private const string ICON_DATABASE_FILE_NAME = "Icon Database.json"; + private static readonly TimeSpan ICON_DATABASE_REFRESH_INTERVAL = TimeSpan.FromDays(1); + + public struct IconCount + { + public int PackagesWithIconCount = 0; + public int TotalScreenshotCount = 0; + public int PackagesWithScreenshotCount = 0; + + public IconCount() { } + } + + private static IconDatabase? __instance; + public static IconDatabase Instance + { + get => __instance ??= new(); + } + + /// + /// The icon and screenshot database + /// + private Dictionary< + string, + IconScreenshotDatabase_v2.PackageIconAndScreenshots + > IconDatabaseData = []; + private IconCount __icon_count = new(); + + /// + /// Download the icon and screenshots database to a local file, and load it into memory + /// + public async Task LoadIconAndScreenshotsDatabaseAsync() + { + string IconsAndScreenshotsFile = GetIconsAndScreenshotsFile(); + bool hasCustomDownloadUrl = Settings.Get(Settings.K.IconDataBaseURL); + if ( + !hasCustomDownloadUrl + && IsCachedDatabaseFresh(IconsAndScreenshotsFile, DateTime.UtcNow) + ) + { + Logger.Debug("Using cached icons and screenshots database; refresh is not due yet"); + await LoadFromCacheAsync(); + if (__icon_count.PackagesWithIconCount > 0) + { + return; + } + + Logger.Warn( + "Cached icons and screenshots database could not be loaded; refreshing it" + ); + } + + try + { + Uri DownloadUrl = new( + "https://github.com/Devolutions/UniGetUI/raw/refs/heads/main/WebBasedData/screenshot-database-v2.json" + ); + if (hasCustomDownloadUrl) + { + DownloadUrl = new Uri(Settings.GetValue(Settings.K.IconDataBaseURL)); + } + + using (HttpClient client = new(CoreTools.GenericHttpClientParameters)) + { + client.DefaultRequestHeaders.UserAgent.ParseAdd(CoreData.UserAgentString); + string fileContents = await client.GetStringAsync(DownloadUrl); + await WriteCacheFileAsync(IconsAndScreenshotsFile, fileContents); + } + + Logger.ImportantInfo("Downloaded new icons and screenshots successfully!"); + + if (!File.Exists(IconsAndScreenshotsFile)) + { + Logger.Error("Icon Database file not found"); + return; + } + } + catch (Exception e) + { + Logger.Warn("Failed to download icons and screenshots"); + Logger.Warn(e); + } + + // Update data with new cached file + await LoadFromCacheAsync(); + } + + internal static bool IsCachedDatabaseFresh(string path, DateTime utcNow) + { + if (!File.Exists(path)) + { + return false; + } + + DateTime lastWriteTimeUtc = File.GetLastWriteTimeUtc(path); + return utcNow - lastWriteTimeUtc < ICON_DATABASE_REFRESH_INTERVAL; + } + + private static string GetIconsAndScreenshotsFile() + { + return Path.Join(CoreData.UniGetUICacheDirectory_Data, ICON_DATABASE_FILE_NAME); + } + + private static async Task WriteCacheFileAsync(string path, string contents) + { + string temporaryPath = path + ".tmp"; + await File.WriteAllTextAsync(temporaryPath, contents); + File.Move(temporaryPath, path, overwrite: true); + } + + public async Task LoadFromCacheAsync() + { + try + { + string IconsAndScreenshotsFile = GetIconsAndScreenshotsFile(); + IconScreenshotDatabase_v2 JsonData = + IconStoreJson.DeserializeIconDatabase( + await File.ReadAllTextAsync(IconsAndScreenshotsFile) + ); + if (JsonData.icons_and_screenshots is not null) + { + IconDatabaseData = JsonData.icons_and_screenshots; + } + + __icon_count = new IconCount + { + PackagesWithIconCount = JsonData.package_count.packages_with_icon, + PackagesWithScreenshotCount = JsonData.package_count.packages_with_screenshot, + TotalScreenshotCount = JsonData.package_count.total_screenshots, + }; + } + catch (Exception ex) + { + Logger.Error("Failed to load icon and screenshot database"); + Logger.Error(ex); + } + } + + public string? GetIconUrlForId(string id) + { + if (IconDatabaseData.TryGetValue(id, out var value) && value.icon.Length != 0) + { + return value.icon; + } + + return null; + } + + public string[] GetScreenshotsUrlForId(string id) + { + return IconDatabaseData.TryGetValue(id, out var value) ? value.images.ToArray() : []; + } + + public IconCount GetIconCount() + { + return __icon_count; + } + } +} diff --git a/src/UniGetUI.Core.IconStore/IconStoreJson.cs b/src/UniGetUI.Core.IconStore/IconStoreJson.cs new file mode 100644 index 0000000..ed6c243 --- /dev/null +++ b/src/UniGetUI.Core.IconStore/IconStoreJson.cs @@ -0,0 +1,25 @@ +using System.Text.Json; +using System.Text.Json.Serialization; +using System.Text.Json.Serialization.Metadata; + +namespace UniGetUI.Core.IconEngine; + +internal static class IconStoreJson +{ + public static IconScreenshotDatabase_v2 DeserializeIconDatabase(string json) + { + return JsonSerializer.Deserialize(json, GetTypeInfo()); + } + + private static JsonTypeInfo GetTypeInfo() + { + return (JsonTypeInfo?)IconStoreJsonContext.Default.GetTypeInfo(typeof(T)) + ?? throw new InvalidOperationException( + $"Icon store JSON metadata for {typeof(T).FullName} was not generated." + ); + } +} + +[JsonSourceGenerationOptions(AllowTrailingCommas = true, WriteIndented = true)] +[JsonSerializable(typeof(IconScreenshotDatabase_v2))] +internal sealed partial class IconStoreJsonContext : JsonSerializerContext; diff --git a/src/UniGetUI.Core.IconStore/InternalsVisibleTo.cs b/src/UniGetUI.Core.IconStore/InternalsVisibleTo.cs new file mode 100644 index 0000000..15598c5 --- /dev/null +++ b/src/UniGetUI.Core.IconStore/InternalsVisibleTo.cs @@ -0,0 +1,3 @@ +using System.Runtime.CompilerServices; + +[assembly: InternalsVisibleTo("UniGetUI.Core.IconEngine.Tests")] diff --git a/src/UniGetUI.Core.IconStore/Serializable.cs b/src/UniGetUI.Core.IconStore/Serializable.cs new file mode 100644 index 0000000..a7acac1 --- /dev/null +++ b/src/UniGetUI.Core.IconStore/Serializable.cs @@ -0,0 +1,23 @@ +namespace UniGetUI.Core.IconEngine +{ + internal struct IconScreenshotDatabase_v2 + { + public struct PackageCount + { + public int total { get; set; } + public int done { get; set; } + public int packages_with_icon { get; set; } + public int packages_with_screenshot { get; set; } + public int total_screenshots { get; set; } + } + + public struct PackageIconAndScreenshots + { + public string icon { get; set; } + public List images { get; set; } + } + + public PackageCount package_count { get; set; } + public Dictionary icons_and_screenshots { get; set; } + } +} diff --git a/src/UniGetUI.Core.IconStore/UniGetUI.Core.IconEngine.csproj b/src/UniGetUI.Core.IconStore/UniGetUI.Core.IconEngine.csproj new file mode 100644 index 0000000..c360acd --- /dev/null +++ b/src/UniGetUI.Core.IconStore/UniGetUI.Core.IconEngine.csproj @@ -0,0 +1,20 @@ + + + $(SharedTargetFrameworks) + + + + + + + + + + + + + + + + + diff --git a/src/UniGetUI.Core.Language.Tests/LanguageDataTests.cs b/src/UniGetUI.Core.Language.Tests/LanguageDataTests.cs new file mode 100644 index 0000000..3fefaa3 --- /dev/null +++ b/src/UniGetUI.Core.Language.Tests/LanguageDataTests.cs @@ -0,0 +1,54 @@ +using UniGetUI.Core.Classes; + +namespace UniGetUI.Core.Language.Tests +{ + public class LanguageDataTests + { + public static object[][] Translators => + LanguageData.TranslatorsList.Select(x => new object[] { x }).ToArray(); + + public static object[][] LanguageReferences => + LanguageData.LanguageReference.Select(x => new object[] { x.Key, x.Value }).ToArray(); + + [Fact] + public void TranslatorsListNotEmptyTest() => Assert.NotEmpty(LanguageData.TranslatorsList); + + [Theory] + [MemberData(nameof(Translators))] + public void TranslatorsListTest(Person translator) => Assert.NotEmpty(translator.Name); + + [Fact] + public void LanguageReferenceNotEmptyTest() + { + Assert.NotEmpty(LanguageData.LanguageReference); + } + + [Theory] + [MemberData(nameof(LanguageReferences))] + public void LanguageReferenceTest(string key, string value) + { + Assert.False( + value.Contains("NoNameLang_"), + $"The language with key {key} has no assigned name" + ); + } + + [Fact] + public void TranslatedPercentageNotEmptyTests() + { + System.Collections.ObjectModel.ReadOnlyDictionary TranslatedPercent = + LanguageData.TranslationPercentages; + foreach (string key in TranslatedPercent.Keys) + { + Assert.True( + LanguageData.LanguageReference.ContainsKey(key), + $"The language key {key} was not found on LanguageReference" + ); + Assert.False( + LanguageData.TranslationPercentages[key].Contains("404%"), + $"Somehow the key {key} has no value" + ); + } + } + } +} diff --git a/src/UniGetUI.Core.Language.Tests/LanguageEngineTests.cs b/src/UniGetUI.Core.Language.Tests/LanguageEngineTests.cs new file mode 100644 index 0000000..0968fce --- /dev/null +++ b/src/UniGetUI.Core.Language.Tests/LanguageEngineTests.cs @@ -0,0 +1,129 @@ +using UniGetUI.Core.Data; +using UniGetUI.PackageEngine.Enums; + +namespace UniGetUI.Core.Language.Tests +{ + public class LanguageEngineTests + { + [Theory] + [InlineData("ca", "Subsistema Android")] + [InlineData("es", "Subsistema de Android")] + [InlineData("uk", "Підсистема Android")] + public void TestLoadingLanguage(string language, string translation) + { + LanguageEngine engine = new(); + + engine.LoadLanguage(language); + Assert.Equal(translation, engine.Translate("Android Subsystem")); + } + + [Fact] + public void TestLoadingLanguageForNonExistentKey() + { + //arrange + LanguageEngine engine = new(); + engine.LoadLanguage("es"); + //act + string NONEXISTENT_KEY = "This is a nonexistent key thay should be returned as-is"; + //assert + Assert.Equal(NONEXISTENT_KEY, engine.Translate(NONEXISTENT_KEY)); + } + + [Theory] + [InlineData("en", "UniGetUI Log", "UniGetUI")] + [InlineData("ca", "Registre de l'UniGetUI", "UniGetUI")] + public void TestUniGetUIRefactoring( + string language, + string uniGetUILogTranslation, + string uniGetUITranslation + ) + { + LanguageEngine engine = new(); + + engine.LoadLanguage(language); + Assert.Equal(uniGetUILogTranslation, engine.Translate("UniGetUI Log")); + Assert.Equal(uniGetUITranslation, engine.Translate("UniGetUI")); + } + + [Fact] + public void LocalFallbackTest() + { + LanguageEngine engine = new(); + engine.LoadLanguage("random-nonexistent-language"); + Assert.Equal("en", engine.Locale); + } + + [Fact] + public void TestLoadingUkrainianSpecificTranslation() + { + LanguageEngine engine = new(); + + engine.LoadLanguage("uk"); + Assert.Equal("Підсистема Android", engine.Translate("Android Subsystem")); + } + + [Fact] + public void TestLoadingLegacyUkrainianAlias() + { + LanguageEngine engine = new(); + + engine.LoadLanguage("ua"); + Assert.Equal("uk", engine.Locale); + } + + [Fact] + public void TestLoadingLanguageIgnoresCachedOverrides() + { + string cachedLangFile = Path.Join(CoreData.UniGetUICacheDirectory_Lang, "lang_en.json"); + string? previousContents = File.Exists(cachedLangFile) + ? File.ReadAllText(cachedLangFile) + : null; + + Directory.CreateDirectory(CoreData.UniGetUICacheDirectory_Lang); + File.WriteAllText( + cachedLangFile, + """ + { + "Starting operation...": "Cached override should be ignored" + } + """ + ); + + try + { + LanguageEngine engine = new(); + + Dictionary langFile = engine.LoadLanguageFile("en"); + Assert.Equal("Starting operation...", langFile["Starting operation..."]); + } + finally + { + if (previousContents is not null) + { + File.WriteAllText(cachedLangFile, previousContents); + } + else if (File.Exists(cachedLangFile)) + { + File.Delete(cachedLangFile); + } + } + } + + /* + [Fact] + public async Task TestDownloadUpdatedTranslationsAsync() + { + string expected_file = Path.Join(CoreData.UniGetUICacheDirectory_Lang, "lang_ca.json"); + if (File.Exists(expected_file)) + File.Delete(expected_file); + + LanguageEngine engine = new(); + engine.LoadLanguage("ca"); + await engine.DownloadUpdatedLanguageFile("ca"); + + Assert.True(File.Exists(expected_file), "The updated file was not created"); + File.Delete(expected_file); + } + */ + } +} diff --git a/src/UniGetUI.Core.Language.Tests/UniGetUI.Core.LanguageEngine.Tests.csproj b/src/UniGetUI.Core.Language.Tests/UniGetUI.Core.LanguageEngine.Tests.csproj new file mode 100644 index 0000000..8682af7 --- /dev/null +++ b/src/UniGetUI.Core.Language.Tests/UniGetUI.Core.LanguageEngine.Tests.csproj @@ -0,0 +1,37 @@ + + + $(PortableTargetFramework) + + false + true + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + + + + + + + + + + + diff --git a/src/UniGetUI.Core.LanguageEngine/LanguageData.cs b/src/UniGetUI.Core.LanguageEngine/LanguageData.cs new file mode 100644 index 0000000..90542c8 --- /dev/null +++ b/src/UniGetUI.Core.LanguageEngine/LanguageData.cs @@ -0,0 +1,207 @@ +using System.Collections.ObjectModel; +using System.Text.Json.Nodes; +using UniGetUI.Core.Classes; +using UniGetUI.Core.Data; +using UniGetUI.Core.Logging; +using UniGetUI.PackageEngine.Enums; + +namespace UniGetUI.Core.Language +{ + public static class LanguageData + { + private static Person[]? __translators_list; + + public static Person[] TranslatorsList + { + get + { + if (__translators_list is null) + { + __translators_list = LoadLanguageTranslatorList(); + } + + return __translators_list; + } + } + + private static ReadOnlyDictionary? __language_reference; + public static ReadOnlyDictionary LanguageReference + { + get + { + if (__language_reference is null) + { + __language_reference = LoadLanguageReference(); + } + + return __language_reference; + } + } + + private static ReadOnlyDictionary? __translation_percentages; + public static ReadOnlyDictionary TranslationPercentages + { + get + { + if (__translation_percentages is null) + { + __translation_percentages = LoadTranslationPercentages(); + } + + return __translation_percentages; + } + } + + private static ReadOnlyDictionary LoadTranslationPercentages() + { + try + { + if ( + JsonNode.Parse( + File.ReadAllText( + Path.Join( + CoreData.UniGetUIExecutableDirectory, + "Assets", + "Data", + "TranslatedPercentages.json" + ) + ) + ) + is JsonObject val + ) + { + return new( + val.ToDictionary(x => x.Key, x => (x.Value ?? ("404%" + x.Key)).ToString()) + ); + } + + return new(new Dictionary()); + } + catch (Exception ex) + { + Logger.Error("Could not load TranslatedPercentages.json from disk"); + Logger.Error(ex); + return new(new Dictionary()); + } + } + + private static ReadOnlyDictionary LoadLanguageReference() + { + try + { + if ( + JsonNode.Parse( + File.ReadAllText( + Path.Join( + CoreData.UniGetUIExecutableDirectory, + "Assets", + "Data", + "LanguagesReference.json" + ) + ) + ) + is JsonObject val + ) + { + return new( + val.ToDictionary( + x => x.Key, + x => (x.Value ?? ("NoNameLang_" + x.Key)).ToString() + ) + ); + } + + return new(new Dictionary()); + } + catch (Exception ex) + { + Logger.Error("Could not load LanguagesReference.json from disk"); + Logger.Error(ex); + return new(new Dictionary()); + } + } + + private static Person[] LoadLanguageTranslatorList() + { + try + { + string JsonContents = File.ReadAllText( + Path.Join( + CoreData.UniGetUIExecutableDirectory, + "Assets", + "Data", + "Translators.json" + ) + ); + + if (JsonNode.Parse(JsonContents) is not JsonObject TranslatorsInfo) + { + return []; + } + + List result = []; + foreach (KeyValuePair langKey in TranslatorsInfo) + { + if (!LanguageReference.ContainsKey(langKey.Key)) + { + Logger.Warn( + $"Language {langKey.Key} not in list, maybe has not been added yet?" + ); + continue; + } + + JsonArray TranslatorsForLang = (langKey.Value ?? new JsonArray()).AsArray(); + bool LangShown = false; + foreach (JsonNode? translator in TranslatorsForLang) + { + if (translator is null) + { + continue; + } + + Uri? url = null; + if (translator["link"] is not null && translator["link"]?.ToString() != "") + { + url = new Uri((translator["link"] ?? "").ToString()); + } + + Person person = new( + Name: (url is not null ? "@" : "") + + (translator["name"] ?? "").ToString(), + ProfilePicture: url is not null + ? new Uri(url.ToString() + ".png") + : null, + GitHubUrl: url, + Language: !LangShown ? LanguageReference[langKey.Key] : "" + ); + LangShown = true; + result.Add(person); + } + } + + return result.ToArray(); + } + catch (Exception ex) + { + Logger.Error("Could not load Translators.json from disk"); + Logger.Error(ex); + return []; + } + } + } + + public static class CommonTranslations + { + public static readonly Dictionary ScopeNames = new() + { + { PackageScope.Global, "Machine | Global" }, + { PackageScope.Local, "User | Local" }, + }; + + public static readonly Dictionary InvertedScopeNames = new() + { + { "Machine | Global", PackageScope.Global }, + { "User | Local", PackageScope.Local }, + }; + } +} diff --git a/src/UniGetUI.Core.LanguageEngine/LanguageEngine.cs b/src/UniGetUI.Core.LanguageEngine/LanguageEngine.cs new file mode 100644 index 0000000..7ba8bff --- /dev/null +++ b/src/UniGetUI.Core.LanguageEngine/LanguageEngine.cs @@ -0,0 +1,281 @@ +using System.Diagnostics.CodeAnalysis; +using System.Globalization; +using System.Text; +using System.Text.Json; +using Jeffijoe.MessageFormat; +using UniGetUI.Core.Data; +using UniGetUI.Core.Logging; +using UniGetUI.Core.SettingsEngine; + +namespace UniGetUI.Core.Language +{ + public class LanguageEngine + { + private static readonly Dictionary LocaleAliases = new(StringComparer.OrdinalIgnoreCase) + { + { "es_MX", "es-MX" }, + { "tg", "tl" }, + { "ua", "uk" }, + }; + + private Dictionary MainLangDict = []; + public static string SelectedLocale = "??"; + + [NotNull] + public string? Locale { get; private set; } + + private MessageFormatter? Formatter; + + public LanguageEngine(string ForceLanguage = "") + { + string LangName = Settings.GetValue(Settings.K.PreferredLanguage); + if (LangName is "default" or "") + { + LangName = CultureInfo.CurrentUICulture.ToString().Replace("-", "_"); + if (string.IsNullOrWhiteSpace(LangName)) + { + LangName = "en"; + } + } + LoadLanguage((ForceLanguage != "") ? ForceLanguage : LangName); + } + + /// + /// Loads the specified language into the current instance + /// + /// the language code + public void LoadLanguage(string lang) + { + try + { + lang = (lang ?? string.Empty).Trim(); + + Locale = "en"; + Locale = ResolveLocale(lang); + + MainLangDict = LoadLanguageFile(Locale); + Formatter = new() { Locale = Locale.Replace('_', '-') }; + + SelectedLocale = Locale; + Logger.Info("Loaded language locale: " + Locale); + } + catch (Exception ex) + { + Logger.Error($"Could not load language file \"{lang}\""); + Logger.Error(ex); + + // Keep the app functional even if locale resolution fails. + Locale = "en"; + MainLangDict = LoadLanguageFile(Locale); + Formatter = new() { Locale = "en" }; + SelectedLocale = Locale; + } + } + + private static string ResolveLocale(string lang) + { + foreach (string candidate in GetLocaleCandidates(lang)) + { + if (LanguageData.LanguageReference.ContainsKey(candidate)) + { + return candidate; + } + } + + return "en"; + } + + private static IEnumerable GetLocaleCandidates(string lang) + { + HashSet candidates = new(StringComparer.OrdinalIgnoreCase); + + void AddCandidate(string? candidate) + { + if (!string.IsNullOrWhiteSpace(candidate)) + { + candidates.Add(candidate.Trim()); + } + } + + string requested = (lang ?? string.Empty).Trim(); + string underscored = requested.Replace('-', '_'); + string hyphenated = requested.Replace('_', '-'); + + AddCandidate(requested); + AddCandidate(underscored); + AddCandidate(hyphenated); + + if (LocaleAliases.TryGetValue(requested, out string? requestedAlias)) + { + AddCandidate(requestedAlias); + } + + if (LocaleAliases.TryGetValue(underscored, out string? underscoredAlias)) + { + AddCandidate(underscoredAlias); + } + + string[] localeSegments = underscored.Split('_', StringSplitOptions.RemoveEmptyEntries); + if (localeSegments.Length > 0) + { + string baseLanguage = localeSegments[0]; + AddCandidate(baseLanguage); + + if (LocaleAliases.TryGetValue(baseLanguage, out string? baseLanguageAlias)) + { + AddCandidate(baseLanguageAlias); + } + } + + return candidates; + } + + public Dictionary LoadLanguageFile(string LangKey) + { + try + { + string BundledLangFileToLoad = Path.Join( + CoreData.UniGetUIExecutableDirectory, + "Assets", + "Languages", + "lang_" + LangKey + ".json" + ); + Dictionary LangDict = []; + + if (!File.Exists(BundledLangFileToLoad)) + { + Logger.Error( + $"Tried to access a non-existing bundled language file! file={BundledLangFileToLoad}" + ); + } + else + { + try + { + LangDict = ParseLanguageEntries( + File.ReadAllText(BundledLangFileToLoad), + BundledLangFileToLoad + ); + } + catch (Exception ex) + { + Logger.Warn( + $"Something went wrong when parsing language file {BundledLangFileToLoad}" + ); + Logger.Warn(ex); + } + } + + return LangDict; + } + catch (Exception e) + { + Logger.Error($"LoadLanguageFile Failed for LangKey={LangKey}"); + Logger.Error(e); + return []; + } + } + + private static Dictionary ParseLanguageEntries( + string fileContents, + string filePath + ) + { + Dictionary entries = []; + HashSet duplicateKeys = []; + Utf8JsonReader reader = new( + Encoding.UTF8.GetBytes(fileContents), + new JsonReaderOptions + { + AllowTrailingCommas = true, + CommentHandling = JsonCommentHandling.Skip, + } + ); + + if (!reader.Read() || reader.TokenType != JsonTokenType.StartObject) + { + throw new JsonException($"Language file {filePath} does not contain a JSON object"); + } + + while (reader.Read()) + { + if (reader.TokenType == JsonTokenType.EndObject) + { + break; + } + + if (reader.TokenType != JsonTokenType.PropertyName) + { + throw new JsonException( + $"Unexpected token {reader.TokenType} in language file {filePath}" + ); + } + + string key = reader.GetString() ?? throw new JsonException("Translation key is null"); + if (!reader.Read()) + { + throw new JsonException($"Missing translation value for key {key}"); + } + + using JsonDocument value = JsonDocument.ParseValue(ref reader); + string parsedValue = value.RootElement.ValueKind == JsonValueKind.Null + ? "" + : value.RootElement.ToString(); + + if (!entries.TryAdd(key, parsedValue)) + { + duplicateKeys.Add(key); + entries[key] = parsedValue; + } + } + + if (duplicateKeys.Count > 0) + { + Logger.Warn( + $"Language file {filePath} contains duplicate keys. Keeping the last value for: {string.Join(", ", duplicateKeys)}" + ); + } + + return entries; + } + + public string Translate(string key) + { + if (key == "WingetUI") + { + if ( + MainLangDict.TryGetValue("formerly WingetUI", out var formerly) + && formerly != "" + ) + { + return "UniGetUI (" + formerly + ")"; + } + + return "UniGetUI (formerly WingetUI)"; + } + + if (key == "Formerly known as WingetUI") + { + return MainLangDict.GetValueOrDefault(key, key); + } + + if (key is null or "") + { + return ""; + } + + if (MainLangDict.TryGetValue(key, out var value) && value != "") + { + return value.Replace("WingetUI", "UniGetUI"); + } + + return key.Replace("WingetUI", "UniGetUI"); + } + + public string Translate(string key, Dictionary dict) + { + Formatter ??= new() { Locale = (Locale ?? "en").Replace('_', '-') }; + return Formatter.FormatMessage(Translate(key), dict); + } + } +} diff --git a/src/UniGetUI.Core.LanguageEngine/UniGetUI.Core.LanguageEngine.csproj b/src/UniGetUI.Core.LanguageEngine/UniGetUI.Core.LanguageEngine.csproj new file mode 100644 index 0000000..c7bb671 --- /dev/null +++ b/src/UniGetUI.Core.LanguageEngine/UniGetUI.Core.LanguageEngine.csproj @@ -0,0 +1,40 @@ + + + $(SharedTargetFrameworks) + + + + + + + + + Assets\Data\LanguagesReference.json + PreserveNewest + + + Assets\Data\TranslatedPercentages.json + PreserveNewest + + + Assets\Data\Translators.json + PreserveNewest + + + Assets\Languages\%(Filename)%(Extension) + PreserveNewest + + + + + + + + + + + + + + + diff --git a/src/UniGetUI.Core.Logger/LogEntry.cs b/src/UniGetUI.Core.Logger/LogEntry.cs new file mode 100644 index 0000000..0686e6a --- /dev/null +++ b/src/UniGetUI.Core.Logger/LogEntry.cs @@ -0,0 +1,25 @@ +namespace UniGetUI.Core.Logging +{ + public readonly struct LogEntry + { + public enum SeverityLevel + { + Debug, + Info, + Success, + Warning, + Error, + } + + public readonly DateTime Time { get; } + public readonly string Content { get; } + public readonly SeverityLevel Severity { get; } + + public LogEntry(string content, SeverityLevel severity) + { + Time = DateTime.Now; + Content = content; + Severity = severity; + } + } +} diff --git a/src/UniGetUI.Core.Logger/Logger.cs b/src/UniGetUI.Core.Logger/Logger.cs new file mode 100644 index 0000000..3d2e744 --- /dev/null +++ b/src/UniGetUI.Core.Logger/Logger.cs @@ -0,0 +1,117 @@ +using Diagnostics = System.Diagnostics; + +namespace UniGetUI.Core.Logging +{ + public static class Logger + { + private static readonly List LogContents = []; + private static readonly Lock LogWriteLock = new(); + private static readonly string SessionLogPath = Path.Combine( + Path.GetTempPath(), + "UniGetUI", + "session.log" + ); + + private static readonly string UserName = Environment.UserName; + + // When enabled, the current user's name is replaced by **** in every logged line (privacy). + public static bool RedactUsername { get; set; } + + public static string GetSessionLogPath() => SessionLogPath; + + // Replaces the current user's name with **** when redaction is enabled (privacy). + // Public so other diagnostic surfaces (operation output, crash reports, update logs) + // can apply the same redaction before persisting or displaying their own content. + public static string Redact(string text) + { + if (!RedactUsername || UserName.Length == 0) + return text; + return text.Replace(UserName, "****", StringComparison.OrdinalIgnoreCase); + } + + private static void Add( + string content, + LogEntry.SeverityLevel severity, + string caller + ) + { + content = Redact(content); + Diagnostics.Debug.WriteLine($"[{caller}] " + content); + AppendToSessionLog(content); + LogContents.Add(new LogEntry(content, severity)); + } + + private static void AppendToSessionLog(string text) + { + try + { + Directory.CreateDirectory(Path.GetDirectoryName(SessionLogPath)!); + lock (LogWriteLock) + { + File.AppendAllText( + SessionLogPath, + $"[{DateTime.Now:yyyy-MM-dd h:mm:ss tt}] {text}{Environment.NewLine}" + ); + } + } + catch { } + } + + // String parameter log functions + public static void ImportantInfo( + string s, + [System.Runtime.CompilerServices.CallerMemberName] string caller = "" + ) => Add(s, LogEntry.SeverityLevel.Success, caller); + + public static void Debug( + string s, + [System.Runtime.CompilerServices.CallerMemberName] string caller = "" + ) => Add(s, LogEntry.SeverityLevel.Debug, caller); + + public static void Info( + string s, + [System.Runtime.CompilerServices.CallerMemberName] string caller = "" + ) => Add(s, LogEntry.SeverityLevel.Info, caller); + + public static void Warn( + string s, + [System.Runtime.CompilerServices.CallerMemberName] string caller = "" + ) => Add(s, LogEntry.SeverityLevel.Warning, caller); + + public static void Error( + string s, + [System.Runtime.CompilerServices.CallerMemberName] string caller = "" + ) => Add(s, LogEntry.SeverityLevel.Error, caller); + + // Exception parameter log functions + public static void ImportantInfo( + Exception e, + [System.Runtime.CompilerServices.CallerMemberName] string caller = "" + ) => Add(e.ToString(), LogEntry.SeverityLevel.Success, caller); + + public static void Debug( + Exception e, + [System.Runtime.CompilerServices.CallerMemberName] string caller = "" + ) => Add(e.ToString(), LogEntry.SeverityLevel.Debug, caller); + + public static void Info( + Exception e, + [System.Runtime.CompilerServices.CallerMemberName] string caller = "" + ) => Add(e.ToString(), LogEntry.SeverityLevel.Info, caller); + + public static void Warn( + Exception e, + [System.Runtime.CompilerServices.CallerMemberName] string caller = "" + ) => Add(e.ToString(), LogEntry.SeverityLevel.Warning, caller); + + public static void Error( + Exception e, + [System.Runtime.CompilerServices.CallerMemberName] string caller = "" + ) => Add(e.ToString(), LogEntry.SeverityLevel.Error, caller); + + public static LogEntry[] GetLogs() + { + return LogContents.ToArray(); + } + } +} diff --git a/src/UniGetUI.Core.Logger/UniGetUI.Core.Logging.csproj b/src/UniGetUI.Core.Logger/UniGetUI.Core.Logging.csproj new file mode 100644 index 0000000..3b1ea6e --- /dev/null +++ b/src/UniGetUI.Core.Logger/UniGetUI.Core.Logging.csproj @@ -0,0 +1,9 @@ + + + $(SharedTargetFrameworks) + + + + + + diff --git a/src/UniGetUI.Core.Logging.Tests/LogEntryTests.cs b/src/UniGetUI.Core.Logging.Tests/LogEntryTests.cs new file mode 100644 index 0000000..d04bc0f --- /dev/null +++ b/src/UniGetUI.Core.Logging.Tests/LogEntryTests.cs @@ -0,0 +1,37 @@ +namespace UniGetUI.Core.Logging.Tests +{ + public class LogEntryTests + { + [Fact] + public async Task TestLogEntry() + { + DateTime startTime = DateTime.Now; + + await Task.Delay(100); + + LogEntry logEntry1 = new("Hello World", LogEntry.SeverityLevel.Info); + await Task.Delay(50); + LogEntry logEntry2 = new("Hello World 2", LogEntry.SeverityLevel.Debug); + await Task.Delay(50); + LogEntry logEntry3 = new("Hello World 3", LogEntry.SeverityLevel.Error); + + await Task.Delay(100); + + DateTime endTime = DateTime.Now; + + Assert.Equal("Hello World", logEntry1.Content); + Assert.Equal("Hello World 2", logEntry2.Content); + Assert.Equal("Hello World 3", logEntry3.Content); + + Assert.Equal(LogEntry.SeverityLevel.Info, logEntry1.Severity); + Assert.Equal(LogEntry.SeverityLevel.Debug, logEntry2.Severity); + Assert.Equal(LogEntry.SeverityLevel.Error, logEntry3.Severity); + + Assert.True(logEntry1.Time > startTime && logEntry1.Time < endTime); + Assert.True(logEntry2.Time > startTime && logEntry2.Time < endTime); + Assert.True(logEntry3.Time > startTime && logEntry3.Time < endTime); + Assert.True(logEntry1.Time < logEntry2.Time); + Assert.True(logEntry2.Time < logEntry3.Time); + } + } +} diff --git a/src/UniGetUI.Core.Logging.Tests/LoggerTests.cs b/src/UniGetUI.Core.Logging.Tests/LoggerTests.cs new file mode 100644 index 0000000..250a559 --- /dev/null +++ b/src/UniGetUI.Core.Logging.Tests/LoggerTests.cs @@ -0,0 +1,35 @@ +#pragma warning disable CA2201 +namespace UniGetUI.Core.Logging.Tests +{ + public class LoggerTests + { + [Fact] + public void TestLogger() + { + DateTime startTime = DateTime.Now; + Logger.Info("Hello World"); + Logger.Debug("Hello World 2"); + Logger.Error("Hello World 3"); + Logger.Warn(new Exception("Test exception")); + + DateTime endTime = DateTime.Now; + + LogEntry[] logs = Logger.GetLogs(); + + Assert.Equal("Hello World", logs[0].Content); + Assert.Equal("Hello World 2", logs[1].Content); + Assert.Equal("Hello World 3", logs[2].Content); + Assert.Equal("System.Exception: Test exception", logs[3].Content); + + Assert.Equal(LogEntry.SeverityLevel.Info, logs[0].Severity); + Assert.Equal(LogEntry.SeverityLevel.Debug, logs[1].Severity); + Assert.Equal(LogEntry.SeverityLevel.Error, logs[2].Severity); + Assert.Equal(LogEntry.SeverityLevel.Warning, logs[3].Severity); + + Assert.True(logs[0].Time > startTime && logs[0].Time < endTime); + Assert.True(logs[1].Time > startTime && logs[1].Time < endTime); + Assert.True(logs[2].Time > startTime && logs[2].Time < endTime); + Assert.True(logs[3].Time > startTime && logs[3].Time < endTime); + } + } +} diff --git a/src/UniGetUI.Core.Logging.Tests/UniGetUI.Core.Logging.Tests.csproj b/src/UniGetUI.Core.Logging.Tests/UniGetUI.Core.Logging.Tests.csproj new file mode 100644 index 0000000..2a8ccce --- /dev/null +++ b/src/UniGetUI.Core.Logging.Tests/UniGetUI.Core.Logging.Tests.csproj @@ -0,0 +1,37 @@ + + + $(PortableTargetFramework) + + false + true + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + + + + + + + + + + + diff --git a/src/UniGetUI.Core.SecureSettings/SecureGHTokenManager.cs b/src/UniGetUI.Core.SecureSettings/SecureGHTokenManager.cs new file mode 100644 index 0000000..d5aa7b4 --- /dev/null +++ b/src/UniGetUI.Core.SecureSettings/SecureGHTokenManager.cs @@ -0,0 +1,84 @@ +using UniGetUI.Core.Data; +using UniGetUI.Core.Logging; + +namespace UniGetUI.Core.SecureSettings +{ + public static class SecureGHTokenManager + { + private const string GitHubResourceName = "UniGetUI/GitHubAccessToken"; + private const string CredentialNamespaceEnvironmentVariable = "UNIGETUI_GITHUB_TOKEN_NAMESPACE"; + private static readonly string UserName = Environment.UserName; + + public static void StoreToken(string token) + { + if (string.IsNullOrEmpty(token)) + { + Logger.Warn("Attempted to store a null or empty token. Operation cancelled."); + return; + } + + try + { + if (GetToken() is not null) + DeleteToken(); // Delete any old token(s) + + CoreCredentialStore.SetSecret(GetScopedResourceName(), UserName, token); + Logger.Info("GitHub access token stored/updated securely."); + } + catch (Exception ex) + { + Logger.Error( + "An error occurred while attempting to delete the currently stored GitHub Token" + ); + Logger.Error(ex); + } + } + + public static string? GetToken() + { + try + { + string? token = CoreCredentialStore.GetSecret(GetScopedResourceName(), UserName); + if (token is null) + { + return null; + } + + Logger.Debug("GitHub access token retrieved."); + return token; + } + catch (Exception ex) + { + Logger.Warn($"Could not retrieve token (it may not exist): {ex.Message}"); + return null; + } + } + + public static void DeleteToken() + { + try + { + CoreCredentialStore.DeleteSecret(GetScopedResourceName(), UserName); + Logger.Info("GitHub access token deleted."); + } + catch (Exception ex) + { + Logger.Error( + "An error occurred while attempting to delete the currently stored GitHub Token" + ); + Logger.Error(ex); + } + } + + private static string GetScopedResourceName() + { + string? credentialNamespace = Environment.GetEnvironmentVariable( + CredentialNamespaceEnvironmentVariable + ); + + return string.IsNullOrWhiteSpace(credentialNamespace) + ? GitHubResourceName + : $"{GitHubResourceName}/{credentialNamespace.Trim()}"; + } + } +} diff --git a/src/UniGetUI.Core.SecureSettings/SecureSettings.cs b/src/UniGetUI.Core.SecureSettings/SecureSettings.cs new file mode 100644 index 0000000..e5c8480 --- /dev/null +++ b/src/UniGetUI.Core.SecureSettings/SecureSettings.cs @@ -0,0 +1,171 @@ +using System.Collections.Concurrent; +using System.Diagnostics; +using UniGetUI.Core.Data; +using UniGetUI.Core.Tools; + +namespace UniGetUI.Core.SettingsEngine.SecureSettings; + +public static class SecureSettings +{ + public static string? TEST_SecureSettingsRootOverride { private get; set; } + + // Various predefined secure settings keys + public enum K + { + AllowCLIArguments, + AllowImportingCLIArguments, + AllowPrePostOpCommand, + AllowImportPrePostOpCommands, + ForceUserGSudo, + AllowCustomManagerPaths, + Unset, + }; + + public static string ResolveKey(K key) + { + return key switch + { + K.AllowCLIArguments => "AllowCLIArguments", + K.AllowImportingCLIArguments => "AllowImportingCLIArguments", + K.AllowPrePostOpCommand => "AllowPrePostInstallCommands", + K.AllowImportPrePostOpCommands => "AllowImportingPrePostInstallCommands", + K.ForceUserGSudo => "ForceUserGSudo", + K.AllowCustomManagerPaths => "AllowCustomManagerPaths", + + K.Unset => throw new InvalidDataException("SecureSettings key was unset!"), + _ => throw new KeyNotFoundException( + $"The SecureSettings key {key} was not found on the ResolveKey map" + ), + }; + } + + private static readonly ConcurrentDictionary _cache = new(); + + public static class Args + { + public const string ENABLE_FOR_USER = "--enable-secure-setting-for-user"; + public const string DISABLE_FOR_USER = "--disable-secure-setting-for-user"; + } + + public static bool Get(K key) + { + return GetForUser(Environment.UserName, key); + } + + public static bool GetForUser(string username, K key) + { + return GetForUser(username, ResolveKey(key)); + } + + public static bool GetForUser(string username, string setting) + { + string purifiedSetting = CoreTools.MakeValidFileName(setting); + string purifiedUser = CoreTools.MakeValidFileName(username); + string cacheKey = $"{purifiedUser}|{purifiedSetting}"; + if (_cache.TryGetValue(cacheKey, out var value)) + { + return value; + } + + var settingsLocation = Path.Join(GetSecureSettingsRoot(), purifiedUser); + var settingFile = Path.Join(settingsLocation, purifiedSetting); + + if (!Directory.Exists(settingsLocation)) + { + _cache[cacheKey] = false; + return false; + } + + bool exists = File.Exists(settingFile); + _cache[cacheKey] = exists; + return exists; + } + + public static async Task TrySet(K key, bool enabled) + { + string purifiedSetting = CoreTools.MakeValidFileName(ResolveKey(key)); + string purifiedUser = CoreTools.MakeValidFileName(Environment.UserName); + _cache.TryRemove($"{purifiedUser}|{purifiedSetting}", out _); + + if (!OperatingSystem.IsWindows()) + { + return ApplyForUser(purifiedUser, purifiedSetting, enabled) is 0; + } + + using Process p = new Process(); + p.StartInfo = new() + { + UseShellExecute = true, + CreateNoWindow = true, + FileName = CoreData.UniGetUIExecutableFile, + Verb = "runas", + ArgumentList = + { + enabled ? Args.ENABLE_FOR_USER : Args.DISABLE_FOR_USER, + purifiedUser, + purifiedSetting, + }, + }; + + p.Start(); + await p.WaitForExitAsync(); + return p.ExitCode is 0; + } + + public static int ApplyForUser(string username, string setting, bool enable) + { + try + { + string purifiedSetting = CoreTools.MakeValidFileName(setting); + string purifiedUser = CoreTools.MakeValidFileName(username); + _cache.TryRemove($"{purifiedUser}|{purifiedSetting}", out _); + + var settingsLocation = Path.Join(GetSecureSettingsRoot(), purifiedUser); + var settingFile = Path.Join(settingsLocation, purifiedSetting); + + if (!Directory.Exists(settingsLocation)) + { + Directory.CreateDirectory(settingsLocation); + } + + if (enable) + { + File.WriteAllText(settingFile, ""); + } + else + { + if (File.Exists(settingFile)) + { + File.Delete(settingFile); + } + } + + return 0; + } + catch (Exception ex) + { + Console.WriteLine(ex); + return -1; + } + } + + private static string GetSecureSettingsRoot() + { + if (TEST_SecureSettingsRootOverride is not null) + { + return TEST_SecureSettingsRootOverride; + } + + if (OperatingSystem.IsWindows()) + { + return Path.Join( + Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles), + "UniGetUI", + "SecureSettings" + ); + } + + return Path.Join(CoreData.UniGetUIDataDirectory, "SecureSettings"); + } + +} diff --git a/src/UniGetUI.Core.SecureSettings/UniGetUI.Core.SecureSettings.csproj b/src/UniGetUI.Core.SecureSettings/UniGetUI.Core.SecureSettings.csproj new file mode 100644 index 0000000..5d077fc --- /dev/null +++ b/src/UniGetUI.Core.SecureSettings/UniGetUI.Core.SecureSettings.csproj @@ -0,0 +1,14 @@ + + + $(SharedTargetFrameworks) + + + + + + + + + + + diff --git a/src/UniGetUI.Core.Settings.Tests/SecureSettingsTests.cs b/src/UniGetUI.Core.Settings.Tests/SecureSettingsTests.cs new file mode 100644 index 0000000..c8c67e8 --- /dev/null +++ b/src/UniGetUI.Core.Settings.Tests/SecureSettingsTests.cs @@ -0,0 +1,147 @@ +using System.Collections.Concurrent; +using System.Reflection; +using UniGetUI.Core.Tools; +using SecureSettingsStore = UniGetUI.Core.SettingsEngine.SecureSettings.SecureSettings; + +namespace UniGetUI.Core.SettingsEngine.Tests; + +public sealed class SecureSettingsTests : IDisposable +{ + private readonly string _testRoot; + + public SecureSettingsTests() + { + _testRoot = Path.Combine(Path.GetTempPath(), $"UniGetUI-SecureSettingsTests-{Guid.NewGuid():N}"); + Directory.CreateDirectory(_testRoot); + SecureSettingsStore.TEST_SecureSettingsRootOverride = _testRoot; + ClearSecureSettingsCache(); + } + + public void Dispose() + { + ClearSecureSettingsCache(); + SecureSettingsStore.TEST_SecureSettingsRootOverride = null; + + if (Directory.Exists(_testRoot)) + { + Directory.Delete(_testRoot, true); + } + } + + [Theory] + [InlineData(SecureSettingsStore.K.AllowCLIArguments, "AllowCLIArguments")] + [InlineData(SecureSettingsStore.K.AllowImportingCLIArguments, "AllowImportingCLIArguments")] + [InlineData(SecureSettingsStore.K.AllowPrePostOpCommand, "AllowPrePostInstallCommands")] + [InlineData(SecureSettingsStore.K.AllowImportPrePostOpCommands, "AllowImportingPrePostInstallCommands")] + [InlineData(SecureSettingsStore.K.ForceUserGSudo, "ForceUserGSudo")] + [InlineData(SecureSettingsStore.K.AllowCustomManagerPaths, "AllowCustomManagerPaths")] + public void ResolveKey_ReturnsExpectedMappings(SecureSettingsStore.K key, string expected) + { + Assert.Equal(expected, SecureSettingsStore.ResolveKey(key)); + } + + [Fact] + public void ResolveKey_ThrowsForUnsetAndUnknownKeys() + { + Assert.Throws(() => + SecureSettingsStore.ResolveKey(SecureSettingsStore.K.Unset) + ); + Assert.Throws(() => + SecureSettingsStore.ResolveKey((SecureSettingsStore.K)999) + ); + } + + [Fact] + public void Get_ReturnsFalseWhenSettingDoesNotExist() + { + Assert.False(SecureSettingsStore.Get(SecureSettingsStore.K.AllowCLIArguments)); + Assert.False(Directory.Exists(GetCurrentUserSettingsDirectory())); + } + + [Fact] + public void ApplyForUser_CreatesAndRemovesSanitizedFile() + { + const string username = "test:user?"; + const string setting = "settinginvalid|chars"; + + Assert.Equal(0, SecureSettingsStore.ApplyForUser(username, setting, true)); + Assert.True(File.Exists(GetSettingsFilePath(username, setting))); + + Assert.Equal(0, SecureSettingsStore.ApplyForUser(username, setting, false)); + Assert.False(File.Exists(GetSettingsFilePath(username, setting))); + } + + [Fact] + public void Get_RefreshesCachedValueAfterApplyForUserWrites() + { + string username = Environment.UserName; + string setting = SecureSettingsStore.ResolveKey(SecureSettingsStore.K.AllowCLIArguments); + + Assert.False(SecureSettingsStore.Get(SecureSettingsStore.K.AllowCLIArguments)); + + Assert.Equal(0, SecureSettingsStore.ApplyForUser(username, setting, true)); + Assert.True(File.Exists(GetSettingsFilePath(username, setting))); + Assert.True(SecureSettingsStore.Get(SecureSettingsStore.K.AllowCLIArguments)); + + Assert.Equal(0, SecureSettingsStore.ApplyForUser(username, setting, false)); + Assert.False(File.Exists(GetSettingsFilePath(username, setting))); + Assert.False(SecureSettingsStore.Get(SecureSettingsStore.K.AllowCLIArguments)); + } + + [Fact] + public async Task Get_AllowsConcurrentCacheMisses() + { + string username = Environment.UserName; + string setting = SecureSettingsStore.ResolveKey( + SecureSettingsStore.K.AllowCustomManagerPaths + ); + Assert.Equal(0, SecureSettingsStore.ApplyForUser(username, setting, true)); + + for (int iteration = 0; iteration < 25; iteration++) + { + ClearSecureSettingsCache(); + using ManualResetEventSlim startGate = new(false); + + Task[] tasks = Enumerable + .Range(0, 64) + .Select(_ => + Task.Run(() => + { + startGate.Wait(); + return SecureSettingsStore.Get( + SecureSettingsStore.K.AllowCustomManagerPaths + ); + }) + ) + .ToArray(); + + startGate.Set(); + bool[] results = await Task.WhenAll(tasks); + + Assert.All(results, Assert.True); + } + } + + private string GetCurrentUserSettingsDirectory() => + Path.Combine(_testRoot, CoreTools.MakeValidFileName(Environment.UserName)); + + private string GetSettingsFilePath(string username, string setting) => + Path.Combine( + _testRoot, + CoreTools.MakeValidFileName(username), + CoreTools.MakeValidFileName(setting) + ); + + private static ConcurrentDictionary GetCache() + { + FieldInfo? cacheField = typeof(SecureSettingsStore).GetField( + "_cache", + BindingFlags.NonPublic | BindingFlags.Static + ); + Assert.NotNull(cacheField); + + return Assert.IsType>(cacheField.GetValue(null)); + } + + private static void ClearSecureSettingsCache() => GetCache().Clear(); +} diff --git a/src/UniGetUI.Core.Settings.Tests/SettingsImportExportTests.cs b/src/UniGetUI.Core.Settings.Tests/SettingsImportExportTests.cs new file mode 100644 index 0000000..5dfa268 --- /dev/null +++ b/src/UniGetUI.Core.Settings.Tests/SettingsImportExportTests.cs @@ -0,0 +1,83 @@ +using System.Text.Json; +using UniGetUI.Core.Data; + +namespace UniGetUI.Core.SettingsEngine.Tests; + +public sealed class SettingsImportExportTests : IDisposable +{ + private readonly string _testRoot = Path.Combine( + Path.GetTempPath(), + nameof(SettingsImportExportTests), + Guid.NewGuid().ToString("N") + ); + + public SettingsImportExportTests() + { + Directory.CreateDirectory(_testRoot); + CoreData.TEST_DataDirectoryOverride = Path.Combine(_testRoot, "Data"); + Directory.CreateDirectory(CoreData.UniGetUIUserConfigurationDirectory); + Settings.ResetSettings(); + } + + public void Dispose() + { + Settings.ResetSettings(); + CoreData.TEST_DataDirectoryOverride = null; + if (Directory.Exists(_testRoot)) + { + Directory.Delete(_testRoot, recursive: true); + } + } + + [Fact] + public void ExportToStringJson_ExcludesSensitiveFiles() + { + Settings.Set(Settings.K.FreshBoolSetting, true); + Settings.SetValue(Settings.K.FreshValue, "configured"); + File.WriteAllText(Path.Combine(CoreData.UniGetUIUserConfigurationDirectory, "TelemetryClientToken"), "secret"); + File.WriteAllText(Path.Combine(CoreData.UniGetUIUserConfigurationDirectory, "CurrentSessionToken"), "secret"); + + var exported = JsonSerializer.Deserialize>(Settings.ExportToString_JSON()); + + Assert.NotNull(exported); + Assert.Contains(Settings.ResolveKey(Settings.K.FreshBoolSetting), exported.Keys); + Assert.Equal("configured", exported[Settings.ResolveKey(Settings.K.FreshValue)]); + Assert.DoesNotContain("TelemetryClientToken", exported.Keys); + Assert.DoesNotContain("CurrentSessionToken", exported.Keys); + } + + [Fact] + public void ImportFromStringJson_ResetsExistingFilesAndReloadsCache() + { + Settings.Set(Settings.K.Test1, true); + Settings.SetValue(Settings.K.FreshValue, "old-value"); + + string importedJson = JsonSerializer.Serialize( + new Dictionary + { + [Settings.ResolveKey(Settings.K.Test2)] = "", + [Settings.ResolveKey(Settings.K.FreshValue)] = "new-value", + } + ); + + Settings.ImportFromString_JSON(importedJson); + + Assert.False(File.Exists(Path.Combine(CoreData.UniGetUIUserConfigurationDirectory, Settings.ResolveKey(Settings.K.Test1)))); + Assert.True(Settings.Get(Settings.K.Test2)); + Assert.Equal("new-value", Settings.GetValue(Settings.K.FreshValue)); + } + + [Fact] + public void ImportFromFileJson_CopiesSourceWhenBackupLivesInSettingsDirectory() + { + Settings.SetValue(Settings.K.FreshValue, "before-import"); + string exportPath = Path.Combine(CoreData.UniGetUIUserConfigurationDirectory, "settings-backup.json"); + + Settings.ExportToFile_JSON(exportPath); + Settings.SetValue(Settings.K.FreshValue, "after-export"); + + Settings.ImportFromFile_JSON(exportPath); + + Assert.Equal("before-import", Settings.GetValue(Settings.K.FreshValue)); + } +} diff --git a/src/UniGetUI.Core.Settings.Tests/SettingsTest.cs b/src/UniGetUI.Core.Settings.Tests/SettingsTest.cs new file mode 100644 index 0000000..6ca45f8 --- /dev/null +++ b/src/UniGetUI.Core.Settings.Tests/SettingsTest.cs @@ -0,0 +1,563 @@ +using System.Text.Json; +using UniGetUI.Core.Data; + +namespace UniGetUI.Core.SettingsEngine.Tests +{ + public sealed class SerializableTestSub + { + public SerializableTestSub(string s, int c) + { + sub = s; + count = c; + } + + public string sub { get; set; } + public int count { get; set; } + } + + public sealed class SerializableTest + { + public SerializableTest(string t, int c, SerializableTestSub s) + { + title = t; + count = c; + sub = s; + } + + public string title { get; set; } + public int count { get; set; } + public SerializableTestSub sub { get; set; } + } + + public class SettingsTest : IDisposable + { + private readonly string _testRoot; + + private readonly string _oldConfigurationDirectory; + private readonly string _newConfigurationDirectory; + + public SettingsTest() + { + _testRoot = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString()); + Directory.CreateDirectory(_testRoot); + + // Configure the test environment. + CoreData.TEST_DataDirectoryOverride = Path.Combine(_testRoot, "Data"); + _oldConfigurationDirectory = CoreData.UniGetUIDataDirectory; + _newConfigurationDirectory = CoreData.UniGetUIUserConfigurationDirectory; + + // Ensure the new configuration directory is removed so that fresh installations are tested. + if (Directory.Exists(_newConfigurationDirectory)) + { + Directory.Delete(_newConfigurationDirectory, true); + } + } + + public void Dispose() + { + Directory.Delete(_testRoot, true); + } + + private string GetNewSettingPath(string fileName) => + Path.Combine(_newConfigurationDirectory, fileName); + + private string GetOldSettingsPath(string fileName) => + Path.Combine(_oldConfigurationDirectory, fileName); + + [Fact] + public void TestSettingsSaveToNewDirectory() + { + Settings.Set(Settings.K.FreshBoolSetting, true); + Settings.SetValue(Settings.K.FreshValue, "test"); + + Assert.True(File.Exists(GetNewSettingPath("FreshBoolSetting"))); + Assert.True(File.Exists(GetNewSettingPath("FreshValue"))); + } + + [Fact] + public void TestExistingSettingsMigrateToNewDirectory() + { + string settingName = Settings.ResolveKey(Settings.K.Test7_Legacy); + var oldPath = GetOldSettingsPath(settingName); + File.WriteAllText(oldPath, ""); + + var migratedValue = Settings.Get(Settings.K.Test7_Legacy); + var newPath = GetNewSettingPath(settingName); + var valueAfterMigration = Settings.Get(Settings.K.Test7_Legacy); + + Assert.True(migratedValue); + Assert.True(valueAfterMigration); + + Assert.True(File.Exists(newPath)); + Assert.False(File.Exists(oldPath)); + } + + [Theory] + [InlineData(Settings.K.Test1, true, false, false, true)] + [InlineData(Settings.K.Test2, true, false, false, false)] + [InlineData(Settings.K.Test3, true, false, true, true)] + [InlineData(Settings.K.Test4, false, true, false, false)] + [InlineData(Settings.K.Test5, false, false, false, false)] + [InlineData(Settings.K.Test6, true, false, true, true)] + public void TestBooleanSettings(Settings.K key, bool st1, bool st2, bool st3, bool st4) + { + string sName = Settings.ResolveKey(key); + Settings.Set(key, st1); + Assert.Equal(st1, Settings.Get(key)); + Assert.Equal( + st1, + File.Exists(Path.Join(CoreData.UniGetUIUserConfigurationDirectory, sName)) + ); + + Settings.Set(key, st2); + Assert.Equal(st2, Settings.Get(key)); + Assert.Equal( + st2, + File.Exists(Path.Join(CoreData.UniGetUIUserConfigurationDirectory, sName)) + ); + + Settings.Set(key, st3); + Assert.Equal(st3, Settings.Get(key)); + Assert.Equal( + st3, + File.Exists(Path.Join(CoreData.UniGetUIUserConfigurationDirectory, sName)) + ); + + Settings.Set(key, st4); + Assert.Equal(st4, Settings.Get(key)); + Assert.Equal( + st4, + File.Exists(Path.Join(CoreData.UniGetUIUserConfigurationDirectory, sName)) + ); + + Settings.Set(key, false); // Cleanup + Assert.False(Settings.Get(key)); + Assert.False( + File.Exists(Path.Join(CoreData.UniGetUIUserConfigurationDirectory, sName)) + ); + } + + [Theory] + [InlineData( + Settings.K.Test1, + "RandomFirstValue", + "RandomSecondValue", + "", + "RandomThirdValue" + )] + [InlineData(Settings.K.Test2, "", "", "", "RandomThirdValue")] + [InlineData(Settings.K.Test3, "RandomFirstValue", " ", "\t", "RandomThirdValue")] + [InlineData(Settings.K.Test4, "RandomFirstValue", "", "", "")] + [InlineData(Settings.K.Test5, "\x00\x01\x02\u0003", "", "", "RandomThirdValue")] + public void TestValueSettings( + Settings.K key, + string st1, + string st2, + string st3, + string st4 + ) + { + string sName = Settings.ResolveKey(key); + Settings.SetValue(key, st1); + Assert.Equal(st1, Settings.GetValue(key)); + Assert.Equal( + st1 != "", + File.Exists(Path.Join(CoreData.UniGetUIUserConfigurationDirectory, sName)) + ); + + Settings.SetValue(key, st2); + Assert.Equal(st2, Settings.GetValue(key)); + Assert.Equal( + st2 != "", + File.Exists(Path.Join(CoreData.UniGetUIUserConfigurationDirectory, sName)) + ); + + Settings.SetValue(key, st3); + Assert.Equal(st3, Settings.GetValue(key)); + Assert.Equal( + st3 != "", + File.Exists(Path.Join(CoreData.UniGetUIUserConfigurationDirectory, sName)) + ); + + Settings.SetValue(key, st4); + Assert.Equal(st4, Settings.GetValue(key)); + Assert.Equal( + st4 != "", + File.Exists(Path.Join(CoreData.UniGetUIUserConfigurationDirectory, sName)) + ); + + Settings.Set(key, false); // Cleanup + Assert.False(Settings.Get(key)); + Assert.Equal("", Settings.GetValue(key)); + Assert.False( + File.Exists(Path.Join(CoreData.UniGetUIUserConfigurationDirectory, sName)) + ); + } + + [Theory] + [InlineData( + "lsTestSetting1", + new[] { "UpdatedFirstValue", "RandomString1", "RandomTestValue", "AnotherRandomValue" }, + new[] { 9, 15, 21, 1001, 4567 }, + new[] { "itemA", "itemB", "itemC" } + )] + [InlineData( + "lsktjgshdfsd", + new[] { "newValue1", "updatedString", "emptyString", "randomSymbols@123" }, + new[] { 42, 23, 17, 98765, 3482 }, + new[] { "itemX", "itemY", "itemZ" } + )] + [InlineData( + "lsª", + new[] { "UniqueVal1", "NewVal2", "AnotherVal3", "TestVal4" }, + new[] { 123, 456, 789, 321, 654 }, + new[] { "item1", "item2", "item3" } + )] + [InlineData( + "lsTestSettingEntry With A Space", + new[] { "ChangedFirstValue", "AlteredSecondVal", "TestedValue", "FinalVal" }, + new[] { 23, 98, 456, 753, 951 }, + new[] { "testA", "testB", "testC" } + )] + [InlineData( + "lsVeryVeryLongTestSettingEntrySoTheClassCanReallyBeStressedOut", + new[] + { + "newCharacterSet\x99\x01\x02", + "UpdatedRandomValue", + "TestEmptyString", + "FinalTestValue", + }, + new[] { 0b11001100, 1234, 5678, 1000000 }, + new[] { "finalTest1", "finalTest2", "finalTest3" } + )] + public void TestListSettings( + string SettingName, + string[] ls1Array, + int[] ls2Array, + string[] ls3Array + ) + { + // Convert arrays to Lists manually + List ls1 = ls1Array.ToList(); + List ls2 = ls2Array.ToList(); + List ls3 = []; + foreach (var item in ls3Array.ToList()) + { + ls3.Add( + new SerializableTest( + item, + new Random().Next(), + new SerializableTestSub(item + new Random().Next(), new Random().Next()) + ) + ); + } + + Settings.ClearList(SettingName); + Assert.Empty( + Settings.GetList(SettingName) + ?? ["this shouldn't be null; something's wrong"] + ); + Settings.SetList(SettingName, ls1); + Assert.NotEmpty(Settings.GetList(SettingName) ?? []); + Assert.Equal(ls1[0], Settings.GetListItem(SettingName, 0)); + Assert.Equal(ls1[2], Settings.GetListItem(SettingName, 2)); + Assert.True(Settings.ListContains(SettingName, ls1[0])); + Assert.False(Settings.ListContains(SettingName, "this is not a test case")); + Assert.True(Settings.RemoveFromList(SettingName, ls1[0])); + Assert.False(Settings.ListContains(SettingName, ls1[0])); + Assert.False(Settings.RemoveFromList(SettingName, ls1[0])); + Assert.False(Settings.ListContains(SettingName, ls1[0])); + Assert.Equal(ls1[2], Settings.GetListItem(SettingName, 1)); + Settings.AddToList(SettingName, "this is now a test case"); + Assert.Equal("this is now a test case", Settings.GetListItem(SettingName, 3)); + Assert.Null(Settings.GetListItem(SettingName, 4)); + + List? persistedList = JsonSerializer.Deserialize>( + File.ReadAllText( + Path.Join(CoreData.UniGetUIUserConfigurationDirectory, $"{SettingName}.json") + ), + Settings.SerializationOptions + ); + Assert.NotNull(persistedList); + Assert.Equal(Settings.GetListItem(SettingName, 0), persistedList[0]); + Settings.ClearList(SettingName); + Assert.Empty( + Settings.GetList(SettingName) + ?? ["this shouldn't be null; something's wrong"] + ); + + Settings.SetList(SettingName, ls2); + Assert.NotEmpty(Settings.GetList(SettingName) ?? []); + Assert.Equal(ls2[0], Settings.GetListItem(SettingName, 0)); + Assert.False(Settings.ListContains(SettingName, -12000)); + Assert.True(Settings.ListContains(SettingName, ls2[3])); + Assert.True(Settings.RemoveFromList(SettingName, ls2[0])); + Assert.False(Settings.ListContains(SettingName, ls2[0])); + Assert.False(Settings.RemoveFromList(SettingName, ls2[0])); + Assert.False(Settings.ListContains(SettingName, ls2[0])); + + Settings.SetList(SettingName, ls3); + Assert.Equal(ls3.Count, Settings.GetList(SettingName)?.Count); + Assert.Equal( + ls3[1].sub.sub, + Settings.GetListItem(SettingName, 1)?.sub.sub + ); + Assert.True(Settings.RemoveFromList(SettingName, ls3[0])); + Assert.False(Settings.RemoveFromList(SettingName, ls3[0])); + Assert.Equal( + ls3[1].sub.sub, + Settings.GetListItem(SettingName, 0)?.sub.sub + ); + Settings.ClearList(SettingName); // Cleanup + Assert.Empty( + Settings.GetList(SettingName) + ?? ["this shouldn't be null; something's wrong"] + ); + Assert.False( + File.Exists( + Path.Join(CoreData.UniGetUIUserConfigurationDirectory, $"{SettingName}.json") + ) + ); + } + + [Theory] + [InlineData( + Settings.K.Test2, + new[] { "UpdatedFirstValue", "RandomString1", "RandomTestValue", "AnotherRandomValue" }, + new[] { 9, 15, 21, 1001, 4567 }, + new[] { "itemA", "itemB", "itemC" } + )] + [InlineData( + Settings.K.Test3, + new[] { "newValue1", "updatedString", "emptyString", "randomSymbols@123" }, + new[] { 42, 23, 17, 98765, 3482 }, + new[] { "itemX", "itemY", "itemZ" } + )] + [InlineData( + Settings.K.Test4, + new[] { "UniqueVal1", "NewVal2", "AnotherVal3", "TestVal4" }, + new[] { 123, 456, 789, 321, 654 }, + new[] { "item1", "item2", "item3" } + )] + [InlineData( + Settings.K.Test5, + new[] { "ChangedFirstValue", "AlteredSecondVal", "TestedValue", "FinalVal" }, + new[] { 23, 98, 456, 753, 951 }, + new[] { "testA", "testB", "testC" } + )] + [InlineData( + Settings.K.Test6, + new[] + { + "newCharacterSet\x99\x01\x02", + "UpdatedRandomValue", + "TestEmptyString", + "FinalTestValue", + }, + new[] { 0b11001100, 1234, 5678, 1000000 }, + new[] { "finalTest1", "finalTest2", "finalTest3" } + )] + public void TestDictionarySettings( + Settings.K SettingName, + string[] keyArray, + int[] intArray, + string[] strArray + ) + { + Dictionary test = []; + Dictionary nonEmptyDictionary = []; + nonEmptyDictionary["this should not be null; something's wrong"] = null; + + for (int idx = 0; idx < keyArray.Length; idx++) + { + test[keyArray[idx]] = new SerializableTest( + strArray[idx % strArray.Length], + intArray[idx % intArray.Length], + new SerializableTestSub( + strArray[(idx + 1) % strArray.Length], + intArray[(idx + 1) % intArray.Length] + ) + ); + } + + Settings.SetDictionaryItem(SettingName, "key", 12); + Assert.Equal(12, Settings.GetDictionaryItem(SettingName, "key")); + Settings.SetDictionary(SettingName, test); + Assert.Equal( + JsonSerializer.Serialize(test, Settings.SerializationOptions), + File.ReadAllText( + Path.Join( + CoreData.UniGetUIUserConfigurationDirectory, + $"{Settings.ResolveKey(SettingName)}.json" + ) + ) + ); + Assert.Equal( + test[keyArray[0]]?.sub.count, + Settings + .GetDictionary(SettingName) + ?[keyArray[0]]?.sub.count + ); + Assert.Equal( + test[keyArray[1]]?.sub.count, + Settings + .GetDictionaryItem(SettingName, keyArray[1]) + ?.sub.count + ); + Settings.SetDictionaryItem(SettingName, keyArray[0], test[keyArray[1]]); + Assert.Equal( + test[keyArray[1]]?.sub.count, + Settings + .GetDictionaryItem(SettingName, keyArray[0]) + ?.sub.count + ); + Assert.NotEqual( + test[keyArray[0]]?.sub.count, + Settings + .GetDictionaryItem(SettingName, keyArray[0]) + ?.sub.count + ); + Assert.Equal( + test[keyArray[1]]?.sub.count, + Settings + .GetDictionaryItem(SettingName, keyArray[1]) + ?.sub.count + ); + Assert.Equal( + test[keyArray[1]]?.count, + Settings + .SetDictionaryItem( + SettingName, + keyArray[0], + new SerializableTest( + "this is not test data", + -12000, + new SerializableTestSub("this sub is not test data", -13000) + ) + ) + ?.count + ); + Assert.Equal( + -12000, + Settings + .GetDictionaryItem(SettingName, keyArray[0]) + ?.count + ); + Assert.Equal( + "this is not test data", + Settings + .GetDictionaryItem(SettingName, keyArray[0]) + ?.title + ); + Assert.Equal( + -13000, + Settings + .GetDictionaryItem(SettingName, keyArray[0]) + ?.sub.count + ); + Settings.SetDictionaryItem( + SettingName, + "this is not a test data key", + test[keyArray[0]] + ); + Assert.Equal( + test[keyArray[0]]?.title, + Settings + .GetDictionaryItem( + SettingName, + "this is not a test data key" + ) + ?.title + ); + Assert.Equal( + test[keyArray[0]]?.sub.count, + Settings + .GetDictionaryItem( + SettingName, + "this is not a test data key" + ) + ?.sub.count + ); + Assert.True( + Settings.DictionaryContainsKey( + SettingName, + "this is not a test data key" + ) + ); + Assert.True( + Settings.DictionaryContainsValue( + SettingName, + test[keyArray[0]] + ) + ); + Assert.NotNull( + Settings.RemoveDictionaryKey( + SettingName, + "this is not a test data key" + ) + ); + Assert.Null( + Settings.RemoveDictionaryKey( + SettingName, + "this is not a test data key" + ) + ); + Assert.False( + Settings.DictionaryContainsKey( + SettingName, + "this is not a test data key" + ) + ); + Assert.False( + Settings.DictionaryContainsValue( + SettingName, + test[keyArray[0]] + ) + ); + Assert.True( + Settings.DictionaryContainsValue( + SettingName, + test[keyArray[2]] + ) + ); + + Assert.Equal( + JsonSerializer.Serialize( + Settings.GetDictionary(SettingName), + Settings.SerializationOptions + ), + File.ReadAllText( + Path.Join( + CoreData.UniGetUIUserConfigurationDirectory, + $"{Settings.ResolveKey(SettingName)}.json" + ) + ) + ); + + Settings.ClearDictionary(SettingName); // Cleanup + Assert.Empty( + Settings.GetDictionary(SettingName) ?? nonEmptyDictionary + ); + Assert.False( + File.Exists( + Path.Join( + CoreData.UniGetUIUserConfigurationDirectory, + $"{Settings.ResolveKey(SettingName)}.json" + ) + ) + ); + } + + [Fact] + public static void EnsureAllKeysResolve() + { + foreach (Settings.K key in Enum.GetValues(typeof(Settings.K))) + { + if (key is Settings.K.Unset) + continue; + Assert.NotEmpty(Settings.ResolveKey(key)); + } + } + } +} diff --git a/src/UniGetUI.Core.Settings.Tests/TestAssembly.cs b/src/UniGetUI.Core.Settings.Tests/TestAssembly.cs new file mode 100644 index 0000000..2171200 --- /dev/null +++ b/src/UniGetUI.Core.Settings.Tests/TestAssembly.cs @@ -0,0 +1,3 @@ +using Xunit; + +[assembly: CollectionBehavior(DisableTestParallelization = true)] diff --git a/src/UniGetUI.Core.Settings.Tests/UniGetUI.Core.Settings.Tests.csproj b/src/UniGetUI.Core.Settings.Tests/UniGetUI.Core.Settings.Tests.csproj new file mode 100644 index 0000000..7fdd8a3 --- /dev/null +++ b/src/UniGetUI.Core.Settings.Tests/UniGetUI.Core.Settings.Tests.csproj @@ -0,0 +1,37 @@ + + + $(PortableTargetFramework) + + + + + false + true + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + + + + + + + + diff --git a/src/UniGetUI.Core.Settings/SettingsEngine.cs b/src/UniGetUI.Core.Settings/SettingsEngine.cs new file mode 100644 index 0000000..85e29cc --- /dev/null +++ b/src/UniGetUI.Core.Settings/SettingsEngine.cs @@ -0,0 +1,115 @@ +using System.Collections.Concurrent; +using UniGetUI.Core.Data; +using UniGetUI.Core.Logging; + +namespace UniGetUI.Core.SettingsEngine +{ + public static partial class Settings + { + private static readonly ConcurrentDictionary booleanSettings = new(); + private static readonly ConcurrentDictionary valueSettings = new(); + + public static bool Get(K key, bool invert = false) + { + string setting = ResolveKey(key); + if (booleanSettings.TryGetValue(key, out bool result)) + { // If the setting was cached + return result ^ invert; + } + + // Otherwise, load the value from disk and cache that setting + result = File.Exists(Path.Join(CoreData.UniGetUIUserConfigurationDirectory, setting)); + booleanSettings[key] = result; + return result ^ invert; + } + + public static void Set(K key, bool value) + { + string setting = ResolveKey(key); + try + { + // Cache that setting's new value + booleanSettings[key] = value; + + // Update changes on disk if applicable + if ( + value + && !File.Exists(Path.Join(CoreData.UniGetUIUserConfigurationDirectory, setting)) + ) + { + File.WriteAllText( + Path.Join(CoreData.UniGetUIUserConfigurationDirectory, setting), + "" + ); + } + else if (!value) + { + valueSettings[key] = ""; + + if ( + File.Exists(Path.Join(CoreData.UniGetUIUserConfigurationDirectory, setting)) + ) + { + File.Delete( + Path.Join(CoreData.UniGetUIUserConfigurationDirectory, setting) + ); + } + } + } + catch (Exception e) + { + Logger.Error($"CANNOT SET SETTING FOR setting={setting} enabled={value}"); + Logger.Error(e); + } + } + + public static string GetValue(K key) + { + string setting = ResolveKey(key); + if (valueSettings.TryGetValue(key, out string? value)) + { // If the setting was cached + return value; + } + + // Otherwise, load the setting from disk and cache that setting + value = ""; + if (File.Exists(Path.Join(CoreData.UniGetUIUserConfigurationDirectory, setting))) + { + value = File.ReadAllText( + Path.Join(CoreData.UniGetUIUserConfigurationDirectory, setting) + ); + } + + valueSettings[key] = value; + return value; + } + + public static void SetValue(K key, string value) + { + string setting = ResolveKey(key); + try + { + if (value == String.Empty) + { + Set(key, false); + booleanSettings[key] = false; + valueSettings[key] = ""; + } + else + { + File.WriteAllText( + Path.Join(CoreData.UniGetUIUserConfigurationDirectory, setting), + value + ); + booleanSettings[key] = true; + valueSettings[key] = value; + } + } + catch (Exception e) + { + Logger.Error($"CANNOT SET SETTING VALUE FOR setting={setting} enabled={value}"); + Logger.Error(e); + } + } + } +} diff --git a/src/UniGetUI.Core.Settings/SettingsEngine_Dictionaries.cs b/src/UniGetUI.Core.Settings/SettingsEngine_Dictionaries.cs new file mode 100644 index 0000000..19701e1 --- /dev/null +++ b/src/UniGetUI.Core.Settings/SettingsEngine_Dictionaries.cs @@ -0,0 +1,202 @@ +using System.Collections.Concurrent; +using System.Text.Json; +using UniGetUI.Core.Data; +using UniGetUI.Core.Logging; + +namespace UniGetUI.Core.SettingsEngine +{ + public static partial class Settings + { + private static readonly ConcurrentDictionary< + K, + Dictionary + > _dictionarySettings = new(); + + // Returns an empty dictionary if the setting doesn't exist and null if the types are invalid + private static Dictionary? _getDictionary(K key) + where KeyT : notnull + { + string setting = ResolveKey(key); + try + { + try + { + if ( + _dictionarySettings.TryGetValue( + key, + out Dictionary? result + ) + ) + { + // If the setting was cached + return result.ToDictionary(kvp => (KeyT)kvp.Key, kvp => (ValueT?)kvp.Value); + } + } + catch (InvalidCastException) + { + Logger.Error( + $"Tried to get a dictionary setting with a key of type {typeof(KeyT)} and a value of type {typeof(ValueT)}, which is not the type of the dictionary" + ); + return null; + } + + // Otherwise, load the setting from disk and cache that setting + Dictionary value = []; + if ( + File.Exists( + Path.Join(CoreData.UniGetUIUserConfigurationDirectory, $"{setting}.json") + ) + ) + { + string result = File.ReadAllText( + Path.Join(CoreData.UniGetUIUserConfigurationDirectory, $"{setting}.json") + ); + try + { + if (result != "") + { + Dictionary? item = + SettingsJson.DeserializeDictionary(result); + if (item is not null) + { + value = item; + } + } + } + catch (InvalidCastException) + { + Logger.Error( + $"Tried to get a dictionary setting with a key of type {typeof(KeyT)} and a value of type {typeof(ValueT)}, but the setting on disk ({result}) cannot be deserialized to that" + ); + } + } + + _dictionarySettings[key] = value.ToDictionary( + kvp => (object)kvp.Key, + kvp => (object?)kvp.Value + ); + return value; + } + catch (Exception ex) + { + Logger.Error($"Could not load dictionary name {setting}"); + Logger.Error(ex); + return []; + } + } + + // Returns an empty dictionary if the setting doesn't exist and null if the types are invalid + public static IReadOnlyDictionary? GetDictionary(K settingsKey) + where KeyT : notnull + { + return _getDictionary(settingsKey); + } + + public static void SetDictionary( + K settingsKey, + Dictionary value + ) + where KeyT : notnull + { + string setting = ResolveKey(settingsKey); + _dictionarySettings[settingsKey] = value.ToDictionary( + kvp => (object)kvp.Key, + kvp => (object?)kvp.Value + ); + + var file = Path.Join(CoreData.UniGetUIUserConfigurationDirectory, $"{setting}.json"); + try + { + if (value.Count != 0) + File.WriteAllText(file, SettingsJson.SerializeDictionary(value)); + else if (File.Exists(file)) + File.Delete(file); + } + catch (Exception e) + { + Logger.Error( + $"CANNOT SET SETTING DICTIONARY FOR setting={setting} [{string.Join(", ", value)}]" + ); + Logger.Error(e); + } + } + + public static ValueT? GetDictionaryItem(K settingsKey, KeyT key) + where KeyT : notnull + { + Dictionary? dictionary = _getDictionary(settingsKey); + if (dictionary == null || !dictionary.TryGetValue(key, out ValueT? value)) + return default; + + return value; + } + + // Also works as `Add` + public static ValueT? SetDictionaryItem(K settingsKey, KeyT key, ValueT value) + where KeyT : notnull + { + Dictionary? dictionary = _getDictionary(settingsKey); + if (dictionary == null) + { + dictionary = new() { { key, value } }; + SetDictionary(settingsKey, dictionary); + return default; + } + + if (dictionary.TryGetValue(key, out ValueT? oldValue)) + { + dictionary[key] = value; + SetDictionary(settingsKey, dictionary); + return oldValue; + } + + dictionary.Add(key, value); + SetDictionary(settingsKey, dictionary); + return default; + } + + public static ValueT? RemoveDictionaryKey(K settingsKey, KeyT key) + where KeyT : notnull + { + Dictionary? dictionary = _getDictionary(settingsKey); + if (dictionary == null) + return default; + + bool success = false; + if (dictionary.TryGetValue(key, out ValueT? value)) + { + success = dictionary.Remove(key); + SetDictionary(settingsKey, dictionary); + } + + if (!success) + return default; + return value; + } + + public static bool DictionaryContainsKey(K settingsKey, KeyT key) + where KeyT : notnull + { + Dictionary? dictionary = _getDictionary(settingsKey); + if (dictionary == null) + return false; + + return dictionary.ContainsKey(key); + } + + public static bool DictionaryContainsValue(K settingsKey, ValueT value) + where KeyT : notnull + { + Dictionary? dictionary = _getDictionary(settingsKey); + if (dictionary == null) + return false; + + return dictionary.ContainsValue(value); + } + + public static void ClearDictionary(K settingsKey) + { + SetDictionary(settingsKey, new Dictionary()); + } + } +} diff --git a/src/UniGetUI.Core.Settings/SettingsEngine_Extras.cs b/src/UniGetUI.Core.Settings/SettingsEngine_Extras.cs new file mode 100644 index 0000000..adb3746 --- /dev/null +++ b/src/UniGetUI.Core.Settings/SettingsEngine_Extras.cs @@ -0,0 +1,80 @@ +using System.Net; +using System.Text.Json; +using UniGetUI.Core.Data; +using UniGetUI.Core.Logging; + +namespace UniGetUI.Core.SettingsEngine; + +public partial class Settings +{ + /* + * + * + */ + + public static bool AreNotificationsDisabled() => + Get(K.DisableSystemTray) || Get(K.DisableNotifications); + + public static bool AreUpdatesNotificationsDisabled() => + AreNotificationsDisabled() || Get(K.DisableUpdatesNotifications); + + public static bool AreErrorNotificationsDisabled() => + AreNotificationsDisabled() || Get(K.DisableErrorNotifications); + + public static bool AreSuccessNotificationsDisabled() => + AreNotificationsDisabled() || Get(K.DisableSuccessNotifications); + + public static bool AreProgressNotificationsDisabled() => + AreNotificationsDisabled() || Get(K.DisableProgressNotifications); + + public static Uri? GetProxyUrl() + { + if (!Get(K.EnableProxy)) + return null; + + string plainUrl = GetValue(K.ProxyURL); + Uri.TryCreate(plainUrl, UriKind.RelativeOrAbsolute, out Uri? var); + if (Get(K.EnableProxy) && var is null) + Logger.Warn($"Proxy setting {plainUrl} is not valid"); + return var; + } + + private const string PROXY_RES_ID = "UniGetUI_proxy"; + + public static NetworkCredential? GetProxyCredentials() + { + try + { + string username = GetValue(K.ProxyUsername); + return username.Length is 0 + ? null + : CoreCredentialStore.GetCredential(PROXY_RES_ID, username); + } + catch (Exception ex) + { + Logger.Error("Could not retrieve Proxy credentials"); + Logger.Error(ex); + return null; + } + } + + public static void SetProxyCredentials(string username, string password) + { + try + { + SetValue(K.ProxyUsername, username); + CoreCredentialStore.SetCredential(PROXY_RES_ID, username, password); + } + catch (Exception ex) + { + Logger.Error("Cannot save Proxy credentials"); + Logger.Error(ex); + } + } + + public static JsonSerializerOptions SerializationOptions = new() + { + AllowTrailingCommas = true, + WriteIndented = true, + }; +} diff --git a/src/UniGetUI.Core.Settings/SettingsEngine_ImportExport.cs b/src/UniGetUI.Core.Settings/SettingsEngine_ImportExport.cs new file mode 100644 index 0000000..afc50a0 --- /dev/null +++ b/src/UniGetUI.Core.Settings/SettingsEngine_ImportExport.cs @@ -0,0 +1,99 @@ +using System.Text.Json; +using UniGetUI.Core.Data; +using UniGetUI.Core.Logging; + +namespace UniGetUI.Core.SettingsEngine; + +public partial class Settings +{ + public static void ExportToFile_JSON(string path) + { + File.WriteAllText(path, ExportToString_JSON()); + } + + public static void ImportFromFile_JSON(string path) + { + if (Path.GetDirectoryName(path) == CoreData.UniGetUIUserConfigurationDirectory) + { + var tempLocation = Directory.CreateTempSubdirectory(); + var newPath = Path.Join(tempLocation.FullName, Path.GetFileName(path)); + File.Copy(path, newPath); + path = newPath; + } + ImportFromString_JSON(File.ReadAllText(path)); + } + + public static string ExportToString_JSON() + { + Dictionary settings = []; + foreach ( + string entry in Directory.EnumerateFiles(CoreData.UniGetUIUserConfigurationDirectory) + ) + { + if ( + new[] + { + "OperationHistory", + "WinGetAlreadyUpgradedPackages.json", + "TelemetryClientToken", + "CurrentSessionToken", + }.Contains(Path.GetFileName(entry)) + ) + continue; + + settings.Add(Path.GetFileName(entry), File.ReadAllText(entry)); + } + return SettingsJson.SerializeStringDictionary(settings); + } + + public static void ImportFromString_JSON(string jsonContent) + { + ResetSettings(); + Dictionary settings = + SettingsJson.DeserializeStringDictionary(jsonContent) ?? []; + foreach (KeyValuePair entry in settings) + { + if ( + new[] + { + "OperationHistory", + "WinGetAlreadyUpgradedPackages.json", + "TelemetryClientToken", + "CurrentSessionToken", + }.Contains(entry.Key) + ) + continue; + + File.WriteAllText( + Path.Join(CoreData.UniGetUIUserConfigurationDirectory, entry.Key), + entry.Value + ); + } + Logger.Info("Settings successfully imported from string content."); + } + + public static void ResetSettings() + { + booleanSettings.Clear(); + valueSettings.Clear(); + listSettings.Clear(); + _dictionarySettings.Clear(); + + foreach ( + string entry in Directory.EnumerateFiles(CoreData.UniGetUIUserConfigurationDirectory) + ) + { + try + { + if (new[] { "TelemetryClientToken" }.Contains(entry.Split("\\")[^1])) + continue; + + File.Delete(entry); + } + catch (Exception ex) + { + Logger.Warn(ex); + } + } + } +} diff --git a/src/UniGetUI.Core.Settings/SettingsEngine_Lists.cs b/src/UniGetUI.Core.Settings/SettingsEngine_Lists.cs new file mode 100644 index 0000000..398c320 --- /dev/null +++ b/src/UniGetUI.Core.Settings/SettingsEngine_Lists.cs @@ -0,0 +1,147 @@ +using System.Collections.Concurrent; +using System.Text.Json; +using UniGetUI.Core.Data; +using UniGetUI.Core.Logging; + +namespace UniGetUI.Core.SettingsEngine +{ + public static partial class Settings + { + private static readonly ConcurrentDictionary> listSettings = new(); + + // Returns an empty list if the setting doesn't exist and null if the type is invalid + private static List? _getList(string setting) + { + try + { + try + { + if (listSettings.TryGetValue(setting, out List? result)) + { + // If the setting was cached + return result.Cast().ToList(); + } + } + catch (InvalidCastException) + { + Logger.Error( + $"Tried to get a list setting as type {typeof(T)}, which is not the type of the list" + ); + return null; + } + + // Otherwise, load the setting from disk and cache that setting + List value = []; + + var file = Path.Join( + CoreData.UniGetUIUserConfigurationDirectory, + $"{setting}.json" + ); + if (File.Exists(file)) + { + string result = File.ReadAllText(file); + try + { + if (result != "") + { + List? item = SettingsJson.DeserializeList(result); + if (item is not null) + { + value = item; + } + } + } + catch (InvalidCastException) + { + Logger.Error( + $"Tried to get a list setting as type {typeof(T)}, but the setting on disk {result} cannot be deserialized to {typeof(T)}" + ); + } + } + + listSettings[setting] = value.Cast().ToList(); + return value; + } + catch (Exception ex) + { + Logger.Error($"Could not load list {setting} from settings"); + Logger.Error(ex); + return []; + } + } + + // Returns an empty list if the setting doesn't exist and null if the type is invalid + public static IReadOnlyList? GetList(string setting) + { + return _getList(setting); + } + + public static void SetList(string setting, List value) + { + listSettings[setting] = value.Cast().ToList(); + var file = Path.Join(CoreData.UniGetUIUserConfigurationDirectory, $"{setting}.json"); + try + { + if (value.Count != 0) + File.WriteAllText(file, SettingsJson.SerializeList(value)); + else if (File.Exists(file)) + File.Delete(file); + } + catch (Exception e) + { + Logger.Error( + $"CANNOT SET SETTING LIST FOR setting={setting} [{string.Join(", ", value)}]" + ); + Logger.Error(e); + } + } + + public static T? GetListItem(string setting, int index) + { + List? list = _getList(setting); + if (list == null) + return default; + if (list.Count <= index) + { + Logger.Error($"Index {index} out of range for list setting {setting}"); + return default; + } + + return list.ElementAt(index); + } + + public static void AddToList(string setting, T value) + { + List? list = _getList(setting); + if (list == null) + return; + + list.Add(value); + SetList(setting, list); + } + + public static bool RemoveFromList(string setting, T value) + { + List? list = _getList(setting); + if (list == null) + return false; + + bool result = list.Remove(value); + SetList(setting, list); + return result; + } + + public static bool ListContains(string setting, T value) + { + List? list = _getList(setting); + if (list == null) + return false; + return list.Contains(value); + } + + public static void ClearList(string setting) + { + SetList(setting, []); + } + } +} diff --git a/src/UniGetUI.Core.Settings/SettingsEngine_Names.cs b/src/UniGetUI.Core.Settings/SettingsEngine_Names.cs new file mode 100644 index 0000000..3e8e4c3 --- /dev/null +++ b/src/UniGetUI.Core.Settings/SettingsEngine_Names.cs @@ -0,0 +1,228 @@ +namespace UniGetUI.Core.SettingsEngine; + +public static partial class Settings +{ + public enum K + { + EnableProxy, + EnableProxyAuth, + DisableWaitForInternetConnection, + IconDataBaseURL, + DisableLangAutoUpdater, + DisableDMWThreadOptimizations, + DisableTelemetry, + DisableTimeoutOnPackageListingTasks, + RemoveAllDesktopShortcuts, + EnableScoopCleanup, + IgnoreUpdatesNotApplicable, + DisableNewWinGetTroubleshooter, + DisableUpdateVcpkgGitPorts, + DisableSelectingUpdatesByDefault, + DisableAutoCheckforUpdates, + AskToDeleteNewDesktopShortcuts, + DoCacheAdminRights, + DoCacheAdminRightsForBatches, + DisableAutoUpdateWingetUI, + EnableUniGetUIBeta, + ShowVersionNumberOnTitlebar, + TransferredOldSettings, + DisableApi, + DisableSystemTray, + MaintainSuccessfulInstalls, + AutomaticallyUpdatePackages, + DisableAUPOnMeteredConnections, + DisableAUPOnBatterySaver, + DisableAUPOnBattery, + CustomVcpkgRoot, + AlreadyWarnedAboutAdmin, + AlreadyWarnedAboutChocolateyMigration, + ShownTelemetryBanner, + CollapseNavMenuOnWideScreen, + NavMenuMode, + EnablePackageBackup_LOCAL, + EnablePackageBackup_CLOUD, + ChangeBackupOutputDirectory, + DisableWinGetMalfunctionDetector, + EnableBackupTimestamping, + DisableIconsOnPackageLists, + ProxyURL, + ProxyUsername, + PreferredLanguage, + DefaultVcpkgTriplet, + UpdatesCheckInterval, + ParallelOperationCount, + TelemetryClientToken, + PreferredTheme, + OperationHistory, + StartupPage, + WindowGeometry, + ChangeBackupFileName, + CurrentSessionToken, + IgnoredPackageUpdates, + DisabledManagers, + DeletableDesktopShortcuts, + WinGetAlreadyUpgradedPackages, + DependencyManagement, + DisabledPackageManagerNotifications, + PackageListViewMode, + DisableInstantSearch, + SidepanelWidths, + HideToggleFilters, + PackageListSortFieldIndex, + PackageListSortDescending, + FreshBoolSetting, + FreshValue, + DisableNotifications, + DisableUpdatesNotifications, + DisableErrorNotifications, + DisableSuccessNotifications, + DisableProgressNotifications, + ShowOperationSummaryNotifications, + KillProcessesThatRefuseToDie, + ManagerPaths, + GitHubUserLogin, + DisableNewProcessLineHandler, + InstallInstalledPackagesBundlesPage, + ProhibitElevation, + DisableIntegrityChecks, + UseLegacyElevator, + WinGetForceLocationOnUpdate, + MinimumUpdateAge, + MinimumUpdateAgeCustom, + PerManagerMinimumUpdateAge, + PerManagerMinimumUpdateAgeCustom, + WinGetCliToolPreference, + WinGetComApiPolicy, + WinGetDownloadFullManifest, + DisableInstallerHostChangeWarning, + BunPreferLatestVersions, + RedactUsernameInLog, + DisableReleaseNotesOnUpdate, + LastKnownBuildNumber, + DisableAutoSoftwareRenderingOnGpuLessHosts, + + Test1, + Test2, + Test3, + Test4, + Test5, + Test6, + Test7_Legacy, + Unset, + }; + + public static string ResolveKey(K key) + { + return key switch + { + K.EnableProxy => "EnableProxy", + K.EnableProxyAuth => "EnableProxyAuth", + K.DisableWaitForInternetConnection => "DisableWaitForInternetConnection", + K.IconDataBaseURL => "IconDataBaseURL", + K.DisableLangAutoUpdater => "DisableLangAutoUpdater", + K.DisableDMWThreadOptimizations => "DisableDMWThreadOptimizations", + K.DisableTelemetry => "DisableTelemetry", + K.DisableTimeoutOnPackageListingTasks => "DisableTimeoutOnPackageListingTasks", + K.RemoveAllDesktopShortcuts => "RemoveAllDesktopShortcuts", + K.EnableScoopCleanup => "EnableScoopCleanup", + K.IgnoreUpdatesNotApplicable => "IgnoreUpdatesNotApplicable", + K.DisableNewWinGetTroubleshooter => "DisableNewWinGetTroubleshooter", + K.DisableUpdateVcpkgGitPorts => "DisableUpdateVcpkgGitPorts", + K.DisableSelectingUpdatesByDefault => "DisableSelectingUpdatesByDefault", + K.DisableAutoCheckforUpdates => "DisableAutoCheckforUpdates", + K.AskToDeleteNewDesktopShortcuts => "AskToDeleteNewDesktopShortcuts", + K.DoCacheAdminRights => "DoCacheAdminRights", + K.DoCacheAdminRightsForBatches => "DoCacheAdminRightsForBatches", + K.DisableAutoUpdateWingetUI => "DisableAutoUpdateWingetUI", + K.EnableUniGetUIBeta => "EnableUniGetUIBeta", + K.ShowVersionNumberOnTitlebar => "ShowVersionNumberOnTitlebar", + K.TransferredOldSettings => "TransferredOldSettings", + K.DisableApi => "DisableApi", + K.DisableSystemTray => "DisableSystemTray", + K.MaintainSuccessfulInstalls => "MaintainSuccessfulInstalls", + K.AutomaticallyUpdatePackages => "AutomaticallyUpdatePackages", + K.DisableAUPOnMeteredConnections => "DisableAUPOnMeteredConnections", + K.DisableAUPOnBatterySaver => "DisableAUPOnBatterySaver", + K.DisableAUPOnBattery => "DisableAUPOnBattery", + K.CustomVcpkgRoot => "CustomVcpkgRoot", + K.AlreadyWarnedAboutAdmin => "AlreadyWarnedAboutAdmin", + K.AlreadyWarnedAboutChocolateyMigration => "AlreadyWarnedAboutChocolateyMigration", + K.ShownTelemetryBanner => "ShownTelemetryBanner", + K.CollapseNavMenuOnWideScreen => "CollapseNavMenuOnWideScreen", + K.NavMenuMode => "NavMenuMode", + K.EnablePackageBackup_LOCAL => "EnablePackageBackup", + K.EnablePackageBackup_CLOUD => "EnablePackageBackup_CLOUD", + K.ChangeBackupOutputDirectory => "ChangeBackupOutputDirectory", + K.DisableWinGetMalfunctionDetector => "DisableWinGetMalfunctionDetector", + K.EnableBackupTimestamping => "EnableBackupTimestamping", + K.DisableIconsOnPackageLists => "DisableIconsOnPackageLists", + K.ProxyURL => "ProxyURL", + K.ProxyUsername => "ProxyUsername", + K.PreferredLanguage => "PreferredLanguage", + K.DefaultVcpkgTriplet => "DefaultVcpkgTriplet", + K.UpdatesCheckInterval => "UpdatesCheckInterval", + K.ParallelOperationCount => "ParallelOperationCount", + K.TelemetryClientToken => "TelemetryClientToken", + K.PreferredTheme => "PreferredTheme", + K.OperationHistory => "OperationHistory", + K.StartupPage => "StartupPage", + K.WindowGeometry => "WindowGeometry", + K.ChangeBackupFileName => "ChangeBackupFileName", + K.CurrentSessionToken => "CurrentSessionToken", + K.IgnoredPackageUpdates => "IgnoredPackageUpdates", + K.DisabledManagers => "DisabledManagers", + K.DeletableDesktopShortcuts => "DeletableDesktopShortcuts", + K.WinGetAlreadyUpgradedPackages => "WinGetAlreadyUpgradedPackages", + K.DependencyManagement => "DependencyManagement", + K.DisabledPackageManagerNotifications => "DisabledPackageManagerNotifications", + K.PackageListViewMode => "PackageListViewMode", + K.DisableInstantSearch => "DisableInstantSearch", + K.SidepanelWidths => "SidepanelWidths", + K.HideToggleFilters => "HideToggleFilters", + K.PackageListSortFieldIndex => "PackageListSortFieldIndex", + K.PackageListSortDescending => "PackageListSortDescending", + K.FreshBoolSetting => "FreshBoolSetting", + K.FreshValue => "FreshValue", + K.DisableNotifications => "DisableNotifications", + K.DisableUpdatesNotifications => "DisableUpdatesNotifications", + K.DisableErrorNotifications => "DisableErrorNotifications", + K.DisableSuccessNotifications => "DisableSuccessNotifications", + K.DisableProgressNotifications => "DisableProgressNotifications", + K.ShowOperationSummaryNotifications => "ShowOperationSummaryNotifications", + K.KillProcessesThatRefuseToDie => "KillProcessesThatRefuseToDie", + K.ManagerPaths => "ManagerPaths", + K.GitHubUserLogin => "GitHubUserLogin", + K.DisableNewProcessLineHandler => "DisableNewProcessLineHandler", + K.InstallInstalledPackagesBundlesPage => "InstallInstalledPackagesBundlesPage", + K.ProhibitElevation => "ProhibitElevation", + K.DisableIntegrityChecks => "DisableIntegrityChecks", + K.UseLegacyElevator => "UseLegacyElevator", + K.WinGetForceLocationOnUpdate => "WinGetForceLocationOnUpdate", + K.MinimumUpdateAge => "MinimumUpdateAge", + K.MinimumUpdateAgeCustom => "MinimumUpdateAgeCustom", + K.PerManagerMinimumUpdateAge => "PerManagerMinimumUpdateAge", + K.PerManagerMinimumUpdateAgeCustom => "PerManagerMinimumUpdateAgeCustom", + K.WinGetCliToolPreference => "WinGetCliToolPreference", + K.WinGetComApiPolicy => "WinGetComApiPolicy", + K.WinGetDownloadFullManifest => "WinGetDownloadFullManifest", + K.DisableInstallerHostChangeWarning => "DisableInstallerHostChangeWarning", + K.BunPreferLatestVersions => "BunPreferLatestVersions", + K.RedactUsernameInLog => "RedactUsernameInLog", + K.DisableReleaseNotesOnUpdate => "DisableReleaseNotesOnUpdate", + K.LastKnownBuildNumber => "LastKnownBuildNumber", + K.DisableAutoSoftwareRenderingOnGpuLessHosts => "DisableAutoSoftwareRenderingOnGpuLessHosts", + + K.Test1 => "TestSetting1", + K.Test2 => "TestSetting2", + K.Test3 => "Test.Settings_with", + K.Test4 => "TestSettingEntry With A Space", + K.Test5 => "ª", + K.Test6 => "VeryVeryLongTestSettingEntrySoTheClassCanReallyBeStressedOut", + K.Test7_Legacy => "LegacyBoolSetting", + K.Unset => throw new InvalidDataException("Setting key was unset!"), + _ => throw new KeyNotFoundException( + $"The settings key {key} was not found on the ResolveKey map" + ), + }; + } +} diff --git a/src/UniGetUI.Core.Settings/SettingsJson.cs b/src/UniGetUI.Core.Settings/SettingsJson.cs new file mode 100644 index 0000000..42094f2 --- /dev/null +++ b/src/UniGetUI.Core.Settings/SettingsJson.cs @@ -0,0 +1,141 @@ +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using System.Text.Json.Serialization.Metadata; + +namespace UniGetUI.Core.SettingsEngine; + +internal static class SettingsJson +{ + public static string SerializeStringDictionary(Dictionary value) + { + return JsonSerializer.Serialize(value, GetRequiredTypeInfo>()); + } + + public static Dictionary? DeserializeStringDictionary(string json) + { + return JsonSerializer.Deserialize(json, GetRequiredTypeInfo>()); + } + + public static string SerializeList(List value) + { + JsonTypeInfo>? typeInfo = GetGeneratedTypeInfo>(); + return typeInfo is not null + ? JsonSerializer.Serialize(value, typeInfo) + : SerializeListWithReflection(value); + } + + public static List? DeserializeList(string json) + { + JsonTypeInfo>? typeInfo = GetGeneratedTypeInfo>(); + return typeInfo is not null + ? JsonSerializer.Deserialize(json, typeInfo) + : DeserializeListWithReflection(json); + } + + public static string SerializeDictionary(Dictionary value) + where KeyT : notnull + { + JsonTypeInfo>? typeInfo = + GetGeneratedTypeInfo>(); + return typeInfo is not null + ? JsonSerializer.Serialize(value, typeInfo) + : SerializeDictionaryWithReflection(value); + } + + public static Dictionary? DeserializeDictionary(string json) + where KeyT : notnull + { + JsonTypeInfo>? typeInfo = + GetGeneratedTypeInfo>(); + return typeInfo is not null + ? JsonSerializer.Deserialize(json, typeInfo) + : DeserializeDictionaryWithReflection(json); + } + + private static JsonTypeInfo? GetGeneratedTypeInfo() + { + return SettingsJsonContext.Default.GetTypeInfo(typeof(T)) as JsonTypeInfo; + } + + private static JsonTypeInfo GetRequiredTypeInfo() + { + return GetGeneratedTypeInfo() + ?? throw new InvalidOperationException( + $"Settings JSON metadata for {typeof(T).FullName} was not generated." + ); + } + + [UnconditionalSuppressMessage( + "Trimming", + "IL2026", + Justification = "Runtime settings use generated metadata for known app types; this fallback preserves generic settings tests and extension scenarios outside trimmed app paths.")] + [UnconditionalSuppressMessage( + "AotCompatibility", + "IL3050", + Justification = "This reflection fallback is only used when generated metadata is unavailable; NativeAOT app paths rely on source-generated metadata for the known settings types.")] + private static string SerializeListWithReflection(List value) + { + return JsonSerializer.Serialize(value, Settings.SerializationOptions); + } + + [UnconditionalSuppressMessage( + "Trimming", + "IL2026", + Justification = "Runtime settings use generated metadata for known app types; this fallback preserves generic settings tests and extension scenarios outside trimmed app paths.")] + [UnconditionalSuppressMessage( + "AotCompatibility", + "IL3050", + Justification = "This reflection fallback is only used when generated metadata is unavailable; NativeAOT app paths rely on source-generated metadata for the known settings types.")] + private static List? DeserializeListWithReflection(string json) + { + return JsonSerializer.Deserialize>(json, Settings.SerializationOptions); + } + + [UnconditionalSuppressMessage( + "Trimming", + "IL2026", + Justification = "Runtime settings use generated metadata for known app types; this fallback preserves generic settings tests and extension scenarios outside trimmed app paths.")] + [UnconditionalSuppressMessage( + "AotCompatibility", + "IL3050", + Justification = "This reflection fallback is only used when generated metadata is unavailable; NativeAOT app paths rely on source-generated metadata for the known settings types.")] + private static string SerializeDictionaryWithReflection( + Dictionary value + ) + where KeyT : notnull + { + return JsonSerializer.Serialize(value, Settings.SerializationOptions); + } + + [UnconditionalSuppressMessage( + "Trimming", + "IL2026", + Justification = "Runtime settings use generated metadata for known app types; this fallback preserves generic settings tests and extension scenarios outside trimmed app paths.")] + [UnconditionalSuppressMessage( + "AotCompatibility", + "IL3050", + Justification = "This reflection fallback is only used when generated metadata is unavailable; NativeAOT app paths rely on source-generated metadata for the known settings types.")] + private static Dictionary? DeserializeDictionaryWithReflection( + string json + ) + where KeyT : notnull + { + return JsonSerializer.Deserialize>( + json, + Settings.SerializationOptions + ); + } +} + +[JsonSourceGenerationOptions(AllowTrailingCommas = true, WriteIndented = true)] +[JsonSerializable(typeof(Dictionary))] +[JsonSerializable(typeof(Dictionary))] +[JsonSerializable(typeof(Dictionary))] +[JsonSerializable(typeof(Dictionary))] +[JsonSerializable(typeof(Dictionary))] +[JsonSerializable(typeof(List))] +[JsonSerializable(typeof(List))] +[JsonSerializable(typeof(List))] +[JsonSerializable(typeof(List))] +internal sealed partial class SettingsJsonContext : JsonSerializerContext; diff --git a/src/UniGetUI.Core.Settings/UniGetUI.Core.Settings.csproj b/src/UniGetUI.Core.Settings/UniGetUI.Core.Settings.csproj new file mode 100644 index 0000000..4ce0b1c --- /dev/null +++ b/src/UniGetUI.Core.Settings/UniGetUI.Core.Settings.csproj @@ -0,0 +1,14 @@ + + + $(SharedTargetFrameworks) + + + + + + + + + + + diff --git a/src/UniGetUI.Core.Tools.Tests/MetaTests.cs b/src/UniGetUI.Core.Tools.Tests/MetaTests.cs new file mode 100644 index 0000000..694169a --- /dev/null +++ b/src/UniGetUI.Core.Tools.Tests/MetaTests.cs @@ -0,0 +1,121 @@ +using System.Text.RegularExpressions; + +namespace UniGetUI.Core.Tools.Tests; + +public class MetaTests +{ + [Fact] + public void TestJsonSerializationOptions() + { + // This test ensures that any json operation has the proper serialization options set (required for TRIM support) + var solutionDirectory = FindRepositoryRoot(); + var csFiles = Directory + .GetFiles(solutionDirectory, "*.cs", SearchOption.AllDirectories) + .Where(file => + !file.Contains(@"bin\") + && !file.Contains(@"obj\") + && !file.EndsWith(".g.cs") + && !file.EndsWith("Tests.cs") + ); + + foreach (var file in csFiles) + { + var lines = File.ReadAllLines(file); + var jsonSerCount = lines.Count(x => x.Contains("JsonSerializer.Serialize")); + var jsonDeserCount = lines.Count(x => x.Contains("JsonSerializer.Deserialize")); + var trimSafeJsonMetadataCount = lines.Count(x => + x.Contains("SerializationHelpers.DefaultOptions") + || x.Contains("SerializationHelpers.ImportBundleOptions") + || x.Contains("SerializationOptions") + || x.Contains("JsonTypeInfo") + || x.Contains("JsonSerializerContext") + || x.Contains("JsonSourceGenerationOptions") + || x.Contains("GetTypeInfo") + || x.Contains("typeInfo") + ); + Assert.True( + (jsonSerCount + jsonDeserCount) <= trimSafeJsonMetadataCount, + $"Failing on {file}. The specified file does not serialize and/or deserialize JSON with" + + $" explicit trim-safe JSON metadata" + ); + } + } + + [Fact] + public void TestHttpClientInstantiation() + { + // This test ensures that any instantiation of HttpClient contains at least one empty line after it + var solutionDirectory = FindRepositoryRoot(); + var csFiles = Directory + .GetFiles(solutionDirectory, "*.cs", SearchOption.AllDirectories) + .Where(file => + !file.Contains(@"bin\") + && !file.Contains(@"obj\") + && !file.EndsWith(".g.cs") + && !file.EndsWith("Tests.cs") + && !file.EndsWith("LanguageEngine.cs") + ); + + foreach (var file in csFiles) + { + var fileContent = File.ReadAllText(file); + var match = Regex.Match(fileContent, "new HttpClient ?\\(\\)"); + var match2 = Regex.Match(fileContent, "HttpClient [a-zA-Z0-9_]+ ?= ?new ?\\(\\)"); + Assert.False( + match.Success || match2.Success, + $"File {file} has an incorrect instantiation of HttpClient, that does not pass the " + + $"compulsory CoreTools.GenericHttpClientParameters param" + ); + } + } + + [Fact] + public void TestJsonSerializerContextsDoNotReuseSharedOptions() + { + var solutionDirectory = FindRepositoryRoot(); + var csFiles = Directory + .GetFiles(solutionDirectory, "*.cs", SearchOption.AllDirectories) + .Where(file => + !file.Contains(@"bin\") + && !file.Contains(@"obj\") + && !file.EndsWith(".g.cs") + && !file.EndsWith("Tests.cs") + ); + + Regex forbiddenPattern = new( + @"JsonContext\s+\w+\s*=\s*new\(\s*SerializationHelpers\.DefaultOptions\s*\)", + RegexOptions.Multiline + ); + + foreach (var file in csFiles) + { + var fileContent = File.ReadAllText(file); + Assert.False( + forbiddenPattern.IsMatch(fileContent), + $"File {file} reuses SerializationHelpers.DefaultOptions when constructing a generated JsonSerializerContext. Clone the options first to avoid rebinding the shared resolver." + ); + } + } + + private static string FindRepositoryRoot() + { + DirectoryInfo? currentDirectory = new(AppDomain.CurrentDomain.BaseDirectory); + + while (currentDirectory is not null) + { + if ( + File.Exists(Path.Join(currentDirectory.FullName, "AGENTS.md")) + && Directory.Exists(Path.Join(currentDirectory.FullName, "src")) + ) + { + return currentDirectory.FullName; + } + + currentDirectory = currentDirectory.Parent; + } + + throw new DirectoryNotFoundException( + "Unable to locate the UniGetUI repository root from the test output directory." + ); + } +} diff --git a/src/UniGetUI.Core.Tools.Tests/ToolsTests.cs b/src/UniGetUI.Core.Tools.Tests/ToolsTests.cs new file mode 100644 index 0000000..031ffe3 --- /dev/null +++ b/src/UniGetUI.Core.Tools.Tests/ToolsTests.cs @@ -0,0 +1,456 @@ +using System.Diagnostics; +using UniGetUI.Core.Language; +using UniGetUI.PackageEngine.Enums; + +namespace UniGetUI.Core.Tools.Tests +{ + public class ToolsTests + { + [Theory] + [InlineData("NonExistentString", false)] + [InlineData(" ", false)] + [InlineData("", false)] + [InlineData("@@", false)] + [InlineData("No packages were found", true)] + [InlineData("Add packages or open an existing package bundle", true)] + public void TranslateFunctionTester(string textEntry, bool TranslationExists) + { + LanguageEngine langEngine = new("fr"); + CoreTools.ReloadLanguageEngineInstance("fr"); + + Assert.Equal(CoreTools.Translate(textEntry), langEngine.Translate(textEntry)); + + if (TranslationExists) + { + Assert.NotEqual(CoreTools.Translate(textEntry), textEntry); + } + else + { + Assert.Equal(CoreTools.Translate(textEntry), textEntry); + } + + Assert.Equal(CoreTools.AutoTranslated(textEntry), textEntry); + } + + [Fact] + public void TestStaticallyLoadedLanguages() + { + CoreTools.ReloadLanguageEngineInstance("ca"); + + Assert.Equal("Usuari | Local", CommonTranslations.ScopeNames[PackageScope.Local]); + Assert.Equal("Màquina | Global", CommonTranslations.ScopeNames[PackageScope.Global]); + + Assert.Equal( + PackageScope.Global, + CommonTranslations.InvertedScopeNames["Màquina | Global"] + ); + Assert.Equal( + PackageScope.Local, + CommonTranslations.InvertedScopeNames["Usuari | Local"] + ); + } + + [Fact] + public async Task TestWhichFunctionForExistingFile() + { + string existingCommand = OperatingSystem.IsWindows() ? "cmd.exe" : "sh"; + Tuple result = await CoreTools.WhichAsync(existingCommand); + Assert.True(result.Item1); + Assert.True(File.Exists(result.Item2)); + } + + [Fact] + public async Task TestWhichFunctionForNonExistingFile() + { + Tuple result = await CoreTools.WhichAsync( + "nonexistentfile-does-not-exist" + ); + Assert.False(result.Item1); + Assert.Equal("", result.Item2); + } + + [Fact] + public void TestWhichFunctionForDirectPath() + { + string tempDirectory = CreateTemporaryDirectory(); + string commandPath = Path.Combine( + tempDirectory, + OperatingSystem.IsWindows() ? "unigetui-direct-path-test.cmd" : "unigetui-direct-path-test" + ); + + try + { + CreateCommandFile(commandPath); + + Tuple result = CoreTools.Which(commandPath); + + Assert.True(result.Item1); + Assert.Equal(commandPath, result.Item2); + } + finally + { + Directory.Delete(tempDirectory, true); + } + } + + [Fact] + public void TestWhichMultipleRespectsProcessPathOrder() + { + string tempDirectory1 = CreateTemporaryDirectory(); + string tempDirectory2 = CreateTemporaryDirectory(); + string commandName = OperatingSystem.IsWindows() + ? "unigetui-path-order-test.exe" + : "unigetui-path-order-test"; + string commandPath1 = Path.Combine(tempDirectory1, commandName); + string commandPath2 = Path.Combine(tempDirectory2, commandName); + string? oldPath = Environment.GetEnvironmentVariable("PATH", EnvironmentVariableTarget.Process); + + try + { + CreateCommandFile(commandPath1); + CreateCommandFile(commandPath2); + Environment.SetEnvironmentVariable( + "PATH", + string.Join(Path.PathSeparator, tempDirectory1, tempDirectory2), + EnvironmentVariableTarget.Process + ); + + List result = CoreTools.WhichMultiple(commandName); + + Assert.Equal([commandPath1, commandPath2], result); + } + finally + { + Environment.SetEnvironmentVariable( + "PATH", + oldPath, + EnvironmentVariableTarget.Process + ); + Directory.Delete(tempDirectory1, true); + Directory.Delete(tempDirectory2, true); + } + } + + [Fact] + public void TestWhichFunctionResolvesPathextOnWindows() + { + if (!OperatingSystem.IsWindows()) + { + return; + } + + string tempDirectory = CreateTemporaryDirectory(); + string commandPath = Path.Combine(tempDirectory, "unigetui-pathext-test.exe"); + string? oldPath = Environment.GetEnvironmentVariable("PATH", EnvironmentVariableTarget.Process); + string? oldPathExt = Environment.GetEnvironmentVariable( + "PATHEXT", + EnvironmentVariableTarget.Process + ); + + try + { + CreateCommandFile(commandPath); + Environment.SetEnvironmentVariable( + "PATH", + tempDirectory, + EnvironmentVariableTarget.Process + ); + Environment.SetEnvironmentVariable( + "PATHEXT", + ".EXE;.CMD", + EnvironmentVariableTarget.Process + ); + + Tuple result = CoreTools.Which("unigetui-pathext-test"); + + Assert.True(result.Item1); + Assert.Equal(commandPath, result.Item2, StringComparer.OrdinalIgnoreCase); + } + finally + { + Environment.SetEnvironmentVariable( + "PATH", + oldPath, + EnvironmentVariableTarget.Process + ); + Environment.SetEnvironmentVariable( + "PATHEXT", + oldPathExt, + EnvironmentVariableTarget.Process + ); + Directory.Delete(tempDirectory, true); + } + } + + [Fact] + public void TestWhichFunctionRequiresExecutableBitOnUnix() + { + if (OperatingSystem.IsWindows()) + { + return; + } + + string tempDirectory = CreateTemporaryDirectory(); + string commandName = "unigetui-unix-executable-bit-test"; + string commandPath = Path.Combine(tempDirectory, commandName); + string? oldPath = Environment.GetEnvironmentVariable("PATH", EnvironmentVariableTarget.Process); + + try + { + File.WriteAllText(commandPath, string.Empty); + File.SetUnixFileMode( + commandPath, + UnixFileMode.UserRead + | UnixFileMode.UserWrite + | UnixFileMode.GroupRead + | UnixFileMode.OtherRead + ); + Environment.SetEnvironmentVariable( + "PATH", + tempDirectory, + EnvironmentVariableTarget.Process + ); + + Tuple result = CoreTools.Which(commandName); + + Assert.False(result.Item1); + Assert.Equal("", result.Item2); + } + finally + { + Environment.SetEnvironmentVariable( + "PATH", + oldPath, + EnvironmentVariableTarget.Process + ); + Directory.Delete(tempDirectory, true); + } + } + + [Theory] + [InlineData("7zip19.00-helpEr", "7zip19.00 HelpEr")] + [InlineData("packagename", "Packagename")] + [InlineData("Packagename", "Packagename")] + [InlineData("PackageName", "PackageName")] + [InlineData("pacKagENaMe", "PacKagENaMe")] + [InlineData("PACKAGENAME", "PACKAGENAME")] + [InlineData("package-Name", "Package Name")] + [InlineData("pub-name/pkg-version_2.00.portable", "Pkg Version 2.00")] + [InlineData("!helloWorld", "!helloWorld")] + [InlineData("@stylistic/eslint-plugin", "Eslint Plugin")] + [InlineData("Flask-RESTful", "Flask RESTful")] + [InlineData("vcpkg-item[option]", "Vcpkg Item [Option]")] + [InlineData("vcpkg-item[multi-option]", "Vcpkg Item [Multi Option]")] + [InlineData("vcpkg-item[multi-option]:triplet", "Vcpkg Item [Multi Option]")] + [InlineData("vcpkg-single-item:triplet", "Vcpkg Single Item")] + public void TestFormatAsName(string id, string name) + { + Assert.Equal(name, CoreTools.FormatAsName(id)); + } + + [Theory] + [InlineData(89)] + [InlineData(33)] + [InlineData(558)] + [InlineData(12)] + [InlineData(0)] + [InlineData(1)] + [InlineData(64)] + public void TestRandomStringGenerator(int length) + { + string string1 = CoreTools.RandomString(length); + string string2 = CoreTools.RandomString(length); + string string3 = CoreTools.RandomString(length); + Assert.Equal(string1.Length, length); + Assert.Equal(string2.Length, length); + Assert.Equal(string3.Length, length); + + // Zero-lenghted strings are always equal + // One-lenghted strings are likely to be equal + if (length > 1) + { + Assert.NotEqual(string1, string2); + Assert.NotEqual(string2, string3); + Assert.NotEqual(string1, string3); + } + + foreach (string s in new[] { string1, string2, string3 }) + { + foreach (char c in s) + { + Assert.True("abcdefghijklmnopqrstuvwxyz0123456789".Contains(c)); + } + } + } + + [Theory] + [InlineData("", 0)] + [InlineData( + "https://invalid.url.com/this/is/an/invalid.php?file=to_test&if=the&code_returns=zero", + 0 + )] + [InlineData("https://raw.githubusercontent.com/Devolutions/UniGetUI/main/src/UniGetUI.Core.IconEngine.Tests/TestData/unigetui.png", 19788)] + public async Task TestFileSizeLoader(string uri, long expectedSize) + { + long size = await CoreTools.GetFileSizeAsLongAsync(uri != "" ? new Uri(uri) : null); + Assert.Equal(expectedSize, size); + } + + [Theory] + [InlineData("1000.0", 1000, 0, 0, 0)] + [InlineData("2.4", 2, 4, 0, 0)] + [InlineData("33a.12-beta5", 33, 12, 5, 0)] + [InlineData("0", 0, 0, 0, 0)] + [InlineData("", 0, 0, 0, 0)] + [InlineData("dfgfdsgdfg", 0, 0, 0, 0)] + [InlineData("-12", 12, 0, 0, 0)] + [InlineData("4.0.0.1.0", 4, 0, 0, 10)] + [InlineData("4.0.0.1.05", 4, 0, 0, 105)] + [InlineData("2024.30.04.1223", 2024, 30, 4, 1223)] + [InlineData("0.0", 0, 0, 0, 0)] + public void TestGetVersionStringAsFloat(string version, int i1, int i2, int i3, int i4) + { + CoreTools.Version v = CoreTools.VersionStringToStruct(version); + Assert.Equal(i1, v.Major); + Assert.Equal(i2, v.Minor); + Assert.Equal(i3, v.Patch); + Assert.Equal(i4, v.Remainder); + } + + [Fact] + public void TestGetVersionStringAsFloat_WithNonNumericVersion_ReturnsNull() + { + CoreTools.Version v = CoreTools.VersionStringToStruct("10c8e557"); + Assert.Equal(CoreTools.Version.Null, v); + } + + [Theory] + [InlineData("2026.1.0", "2026.1.0")] + [InlineData("2026.1.0.0", "2026.1.0")] + [InlineData("2026.1.0.5", "2026.1.0")] + [InlineData("2026.1", "2026.1")] + public void TestNormalizeVersionForComparison(string rawVersion, string expected) + { + var version = System.Version.Parse(rawVersion); + var normalized = CoreTools.NormalizeVersionForComparison(version); + + Assert.Equal(System.Version.Parse(expected), normalized); + } + + [Theory] + [InlineData("Hello World", "Hello World")] + [InlineData("Hello; World", "Hello World")] + [InlineData("\"Hello; World\"", "Hello World")] + [InlineData("'Hello; World'", "Hello World")] + [InlineData("query\";start cmd.exe", "querystart cmd.exe")] + [InlineData("query;start /B program.exe", "querystart B program.exe")] + [InlineData(";&|<>%\"e'~?/\\`", "e")] + public void TestSafeQueryString(string query, string expected) + { + Assert.Equal(CoreTools.EnsureSafeQueryString(query), expected); + } + + [Fact] + public void TestEnvVariableCreation() + { + const string ENV1 = "NONEXISTENTENVVARIABLE"; + Environment.SetEnvironmentVariable(ENV1, null, EnvironmentVariableTarget.Process); + Environment.SetEnvironmentVariable(ENV1, null, EnvironmentVariableTarget.User); + + ProcessStartInfo oldInfo = CoreTools.UpdateEnvironmentVariables(); + oldInfo.Environment.TryGetValue(ENV1, out string? result); + Assert.Null(result); + + Environment.SetEnvironmentVariable(ENV1, "randomval", EnvironmentVariableTarget.User); + + ProcessStartInfo newInfo1 = CoreTools.UpdateEnvironmentVariables(); + newInfo1.Environment.TryGetValue(ENV1, out string? result2); + Assert.Equal("randomval", result2); + + Environment.SetEnvironmentVariable(ENV1, null, EnvironmentVariableTarget.User); + ProcessStartInfo newInfo2 = CoreTools.UpdateEnvironmentVariables(); + newInfo2.Environment.TryGetValue(ENV1, out string? result3); + Assert.Null(result3); + } + + [Fact] + public void TestEnvVariableReplacement() + { + const string ENV = "TMP"; + + var expected = Environment.GetEnvironmentVariable(ENV, EnvironmentVariableTarget.User); + + ProcessStartInfo info = CoreTools.UpdateEnvironmentVariables(); + info.Environment.TryGetValue(ENV, out string? result); + Assert.Equal(expected, result); + } + + [Fact] + public void TestEnvVariableJuxtaposition() + { + const string ENV = "PATH"; + + var oldpath = + Environment.GetEnvironmentVariable(ENV, EnvironmentVariableTarget.Machine) + + ";" + + Environment.GetEnvironmentVariable(ENV, EnvironmentVariableTarget.User); + + ProcessStartInfo info = CoreTools.UpdateEnvironmentVariables(); + info.Environment.TryGetValue(ENV, out string? result); + Assert.Equal(oldpath, result); + } + + [Theory] + [InlineData(10, 33, "hello", "[###.......] 33% (hello)")] + [InlineData(20, 37, null, "[#######.............] 37%")] + [InlineData(10, 0, "", "[..........] 0% ()")] + [InlineData(10, 100, "3/3", "[##########] 100% (3/3)")] + public void TestTextProgressbarGenerator( + int length, + int progress, + string? extra, + string? expected + ) + { + Assert.Equal(CoreTools.TextProgressGenerator(length, progress, extra), expected); + } + + [Theory] + [InlineData(0, 1, "0 Bytes")] + [InlineData(10, 1, "10 Bytes")] + [InlineData(1024 * 34, 0, "34 KB")] + [InlineData(65322450, 3, "62.296 MB")] + [InlineData(65322450000, 3, "60.836 GB")] + [InlineData(65322450000000, 3, "59.410 TB")] + public void TestFormatSize(long size, int decPlaces, string expected) + { + Assert.Equal(CoreTools.FormatAsSize(size, decPlaces).Replace(',', '.'), expected); + } + + private static string CreateTemporaryDirectory() + { + string path = Path.Combine(Path.GetTempPath(), $"UniGetUI-ToolsTests-{Guid.NewGuid():N}"); + Directory.CreateDirectory(path); + return path; + } + + private static void CreateCommandFile(string path) + { + File.WriteAllText(path, string.Empty); + + if (!OperatingSystem.IsWindows()) + { + File.SetUnixFileMode( + path, + UnixFileMode.UserRead + | UnixFileMode.UserWrite + | UnixFileMode.UserExecute + | UnixFileMode.GroupRead + | UnixFileMode.GroupExecute + | UnixFileMode.OtherRead + | UnixFileMode.OtherExecute + ); + } + } + } +} diff --git a/src/UniGetUI.Core.Tools.Tests/UniGetUI.Core.Tools.Tests.csproj b/src/UniGetUI.Core.Tools.Tests/UniGetUI.Core.Tools.Tests.csproj new file mode 100644 index 0000000..8b84341 --- /dev/null +++ b/src/UniGetUI.Core.Tools.Tests/UniGetUI.Core.Tools.Tests.csproj @@ -0,0 +1,36 @@ + + + $(PortableTargetFramework) + + + + + false + true + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + + + + + + + diff --git a/src/UniGetUI.Core.Tools.Tests/UpdaterDownloadEngineTests.cs b/src/UniGetUI.Core.Tools.Tests/UpdaterDownloadEngineTests.cs new file mode 100644 index 0000000..a73c265 --- /dev/null +++ b/src/UniGetUI.Core.Tools.Tests/UpdaterDownloadEngineTests.cs @@ -0,0 +1,420 @@ +using System.Net; +using System.Net.Http.Headers; +using UniGetUI.Core.Tools; + +namespace UniGetUI.Core.Tools.Tests; + +public sealed class UpdaterDownloadEngineTests +{ + [Fact] + public void DefaultAutomaticUpdateCheckInterval_IsOneHour() + { + Assert.Equal(TimeSpan.FromMinutes(60), UpdaterDownloadEngine.DefaultAutomaticUpdateCheckInterval); + } + + [Fact] + public async Task DownloadInstallerPartAsync_ResumesInterruptedDownloadWithRangeAndIfRange() + { + string destination = GetTempDestination(); + byte[] content = "abcdefghij"u8.ToArray(); + DateTimeOffset lastModified = new(2026, 6, 15, 17, 46, 1, TimeSpan.Zero); + int requestCount = 0; + using HttpClient client = new(new QueueHttpMessageHandler(request => + { + requestCount++; + if (requestCount == 1) + { + Assert.Null(request.Headers.Range); + var response = new HttpResponseMessage(HttpStatusCode.OK) + { + Content = new StreamContent(new FaultingReadStream(content, 5)), + }; + response.Content.Headers.ContentLength = content.Length; + response.Content.Headers.LastModified = lastModified; + return response; + } + + Assert.Equal(2, requestCount); + Assert.NotNull(request.Headers.Range); + RangeItemHeaderValue range = Assert.Single(request.Headers.Range!.Ranges); + Assert.Equal(5, range.From); + Assert.Null(range.To); + Assert.NotNull(request.Headers.IfRange?.Date); + Assert.Equal(lastModified, request.Headers.IfRange!.Date); + + var resumed = new HttpResponseMessage(HttpStatusCode.PartialContent) + { + Content = new ByteArrayContent(content[5..]), + }; + resumed.Content.Headers.ContentRange = new ContentRangeHeaderValue(5, 9, 10); + resumed.Content.Headers.ContentLength = 5; + resumed.Content.Headers.LastModified = lastModified; + return resumed; + })); + UpdaterDownloadIdentity identity = new("2026.2.1.0", "hash", "https://example.test/installer.exe"); + + try + { + await Assert.ThrowsAsync( + () => UpdaterDownloadEngine.DownloadInstallerPartAsync(client, identity, destination) + ); + Assert.Equal(5, new FileInfo(UpdaterDownloadEngine.GetPartialPath(destination)).Length); + + UpdaterDownloadResult result = await UpdaterDownloadEngine.DownloadInstallerPartAsync( + client, + identity, + destination + ); + + Assert.True(result.Resumed); + Assert.Equal(HttpStatusCode.PartialContent, result.StatusCode); + Assert.Equal(content.Length, result.BytesInPartialFile); + Assert.Equal(content, await File.ReadAllBytesAsync(result.PartialPath)); + Assert.Equal(2, requestCount); + } + finally + { + DeleteUpdaterTempFiles(destination); + } + } + + [Fact] + public async Task DownloadInstallerPartAsync_RestartsWhenServerIgnoresRange() + { + string destination = GetTempDestination(); + byte[] content = "abcdefghij"u8.ToArray(); + DateTimeOffset lastModified = new(2026, 6, 15, 17, 46, 1, TimeSpan.Zero); + int requestCount = 0; + using HttpClient client = new(new QueueHttpMessageHandler(request => + { + requestCount++; + if (requestCount == 1) + { + var response = new HttpResponseMessage(HttpStatusCode.OK) + { + Content = new StreamContent(new FaultingReadStream(content, 5)), + }; + response.Content.Headers.ContentLength = content.Length; + response.Content.Headers.LastModified = lastModified; + return response; + } + + Assert.NotNull(request.Headers.Range); + var restart = new HttpResponseMessage(HttpStatusCode.OK) + { + Content = new ByteArrayContent(content), + }; + restart.Content.Headers.ContentLength = content.Length; + restart.Content.Headers.LastModified = lastModified; + return restart; + })); + UpdaterDownloadIdentity identity = new("2026.2.1.0", "hash", "https://example.test/installer.exe"); + + try + { + await Assert.ThrowsAsync( + () => UpdaterDownloadEngine.DownloadInstallerPartAsync(client, identity, destination) + ); + + UpdaterDownloadResult result = await UpdaterDownloadEngine.DownloadInstallerPartAsync( + client, + identity, + destination + ); + + Assert.False(result.Resumed); + Assert.Equal(HttpStatusCode.OK, result.StatusCode); + Assert.Equal(content.Length, result.BytesInPartialFile); + Assert.Equal(content, await File.ReadAllBytesAsync(result.PartialPath)); + } + finally + { + DeleteUpdaterTempFiles(destination); + } + } + + [Fact] + public async Task DownloadInstallerPartAsync_RestartsWhenResumeValidatorChanges() + { + string destination = GetTempDestination(); + byte[] content = "abcdefghij"u8.ToArray(); + int requestCount = 0; + using HttpClient client = new(new QueueHttpMessageHandler(request => + { + requestCount++; + if (requestCount == 1) + { + var response = new HttpResponseMessage(HttpStatusCode.OK) + { + Content = new StreamContent(new FaultingReadStream(content, 5)), + }; + response.Headers.ETag = new EntityTagHeaderValue("\"old\""); + response.Content.Headers.ContentLength = content.Length; + return response; + } + + if (requestCount == 2) + { + Assert.NotNull(request.Headers.Range); + Assert.Equal("\"old\"", request.Headers.IfRange?.EntityTag?.ToString()); + var changedValidator = new HttpResponseMessage(HttpStatusCode.PartialContent) + { + Content = new ByteArrayContent(content[5..]), + }; + changedValidator.Headers.ETag = new EntityTagHeaderValue("\"new\""); + changedValidator.Content.Headers.ContentRange = new ContentRangeHeaderValue(5, 9, 10); + return changedValidator; + } + + Assert.Equal(3, requestCount); + Assert.Null(request.Headers.Range); + var restart = new HttpResponseMessage(HttpStatusCode.OK) + { + Content = new ByteArrayContent(content), + }; + restart.Headers.ETag = new EntityTagHeaderValue("\"new\""); + restart.Content.Headers.ContentLength = content.Length; + return restart; + })); + UpdaterDownloadIdentity identity = new("2026.2.1.0", "hash", "https://example.test/installer.exe"); + + try + { + await Assert.ThrowsAsync( + () => UpdaterDownloadEngine.DownloadInstallerPartAsync(client, identity, destination) + ); + + UpdaterDownloadResult result = await UpdaterDownloadEngine.DownloadInstallerPartAsync( + client, + identity, + destination + ); + + Assert.False(result.Resumed); + Assert.Equal(HttpStatusCode.OK, result.StatusCode); + Assert.Equal(content, await File.ReadAllBytesAsync(result.PartialPath)); + Assert.Equal(3, requestCount); + } + finally + { + DeleteUpdaterTempFiles(destination); + } + } + + [Fact] + public async Task DownloadInstallerPartAsync_ReusesCompletePartialWithoutNetwork() + { + string destination = GetTempDestination(); + byte[] content = "abc"u8.ToArray(); + int requestCount = 0; + using HttpClient firstClient = new(new QueueHttpMessageHandler(_ => + { + requestCount++; + var response = new HttpResponseMessage(HttpStatusCode.OK) + { + Content = new ByteArrayContent(content), + }; + response.Content.Headers.ContentLength = content.Length; + response.Content.Headers.LastModified = new DateTimeOffset(2026, 6, 15, 17, 46, 1, TimeSpan.Zero); + return response; + })); + UpdaterDownloadIdentity identity = new("2026.2.1.0", "hash", "https://example.test/installer.exe"); + + try + { + await UpdaterDownloadEngine.DownloadInstallerPartAsync(firstClient, identity, destination); + using HttpClient failingClient = new(new QueueHttpMessageHandler(_ => + throw new InvalidOperationException("Network should not be used for a complete partial") + )); + + UpdaterDownloadResult result = await UpdaterDownloadEngine.DownloadInstallerPartAsync( + failingClient, + identity, + destination + ); + + Assert.Equal(1, requestCount); + Assert.Equal(HttpStatusCode.NotModified, result.StatusCode); + Assert.Equal(content.Length, result.BytesInPartialFile); + } + finally + { + DeleteUpdaterTempFiles(destination); + } + } + + [Fact] + public void FailureBackoff_IsPersistentAndKeyedByInstallerIdentity() + { + string destination = GetTempDestination(); + string statePath = UpdaterDownloadEngine.GetFailureStatePath(destination); + DateTime now = DateTime.UtcNow; + UpdaterDownloadIdentity identity = new("2026.2.1.0", "ABC", "https://example.test/installer.exe"); + UpdaterDownloadIdentity differentHash = identity with { ExpectedHash = "DEF" }; + + try + { + UpdaterDownloadEngine.RecordFailure(statePath, identity, "download", now); + + Assert.True( + UpdaterDownloadEngine.IsFailureBackoffActive( + statePath, + identity, + now.AddMinutes(1), + out TimeSpan remaining, + out UpdaterDownloadFailureState? state + ) + ); + Assert.True(remaining > TimeSpan.FromMinutes(50)); + Assert.Equal(1, state?.AttemptCount); + Assert.Equal("download", state?.FailureClass); + + UpdaterDownloadEngine.RecordFailure(statePath, identity, "validation", now.AddMinutes(2)); + Assert.True( + UpdaterDownloadEngine.IsFailureBackoffActive( + statePath, + identity, + now.AddMinutes(3), + out _, + out state + ) + ); + Assert.Equal(1, state?.AttemptCount); + Assert.Equal("validation", state?.FailureClass); + + Assert.False( + UpdaterDownloadEngine.IsFailureBackoffActive( + statePath, + differentHash, + now.AddMinutes(1), + out _, + out _ + ) + ); + } + finally + { + DeleteUpdaterTempFiles(destination); + } + } + + [Fact] + public void CalculateFailureBackoff_UsesOneHourMinimumAndCapsAtOneDay() + { + UpdaterDownloadIdentity identity = new("2026.2.1.0", "ABC", "https://example.test/installer.exe"); + + TimeSpan first = UpdaterDownloadEngine.CalculateFailureBackoff(identity, "download", 1); + TimeSpan second = UpdaterDownloadEngine.CalculateFailureBackoff(identity, "download", 2); + TimeSpan capped = UpdaterDownloadEngine.CalculateFailureBackoff(identity, "download", 20); + + Assert.True(first >= TimeSpan.FromMinutes(60)); + Assert.True(first <= TimeSpan.FromMinutes(72)); + Assert.True(second > first); + Assert.Equal(TimeSpan.FromHours(24), capped); + } + + private static string GetTempDestination() + { + return Path.Join(Path.GetTempPath(), $"{Guid.NewGuid():N}.exe"); + } + + private static void DeleteUpdaterTempFiles(string destination) + { + foreach ( + string path in new[] + { + destination, + UpdaterDownloadEngine.GetPartialPath(destination), + UpdaterDownloadEngine.GetPartialMetadataPath(destination), + UpdaterDownloadEngine.GetFailureStatePath(destination), + } + ) + { + if (File.Exists(path)) + { + File.Delete(path); + } + } + } + + private sealed class QueueHttpMessageHandler : HttpMessageHandler + { + private readonly Func _handler; + + public QueueHttpMessageHandler(Func handler) + { + _handler = handler; + } + + protected override Task SendAsync( + HttpRequestMessage request, + CancellationToken cancellationToken + ) + { + return Task.FromResult(_handler(request)); + } + } + + private sealed class FaultingReadStream : Stream + { + private readonly byte[] _data; + private readonly int _failAfterBytes; + private int _position; + + public FaultingReadStream(byte[] data, int failAfterBytes) + { + _data = data; + _failAfterBytes = failAfterBytes; + } + + public override bool CanRead => true; + public override bool CanSeek => false; + public override bool CanWrite => false; + public override long Length => _data.Length; + public override long Position + { + get => _position; + set => throw new NotSupportedException(); + } + + public override void Flush() { } + + public override int Read(byte[] buffer, int offset, int count) + { + if (_position >= _failAfterBytes) + { + throw new IOException("Simulated interrupted download"); + } + + int remainingBeforeFailure = _failAfterBytes - _position; + int bytesToCopy = Math.Min(count, remainingBeforeFailure); + Array.Copy(_data, _position, buffer, offset, bytesToCopy); + _position += bytesToCopy; + return bytesToCopy; + } + + public override ValueTask ReadAsync( + Memory buffer, + CancellationToken cancellationToken = default + ) + { + if (_position >= _failAfterBytes) + { + throw new IOException("Simulated interrupted download"); + } + + int remainingBeforeFailure = _failAfterBytes - _position; + int bytesToCopy = Math.Min(buffer.Length, remainingBeforeFailure); + _data.AsMemory(_position, bytesToCopy).CopyTo(buffer); + _position += bytesToCopy; + return ValueTask.FromResult(bytesToCopy); + } + + public override long Seek(long offset, SeekOrigin origin) => throw new NotSupportedException(); + + public override void SetLength(long value) => throw new NotSupportedException(); + + public override void Write(byte[] buffer, int offset, int count) => + throw new NotSupportedException(); + } +} diff --git a/src/UniGetUI.Core.Tools/CoreToolsJson.cs b/src/UniGetUI.Core.Tools/CoreToolsJson.cs new file mode 100644 index 0000000..b4449eb --- /dev/null +++ b/src/UniGetUI.Core.Tools/CoreToolsJson.cs @@ -0,0 +1,25 @@ +using System.Text.Json; +using System.Text.Json.Serialization; +using System.Text.Json.Serialization.Metadata; + +namespace UniGetUI.Core.Data; + +internal static class CoreToolsJson +{ + public static Dictionary? DeserializeStringDictionary(string json) + { + return JsonSerializer.Deserialize(json, GetTypeInfo>()); + } + + private static JsonTypeInfo GetTypeInfo() + { + return (JsonTypeInfo?)CoreToolsJsonContext.Default.GetTypeInfo(typeof(T)) + ?? throw new InvalidOperationException( + $"Core tools JSON metadata for {typeof(T).FullName} was not generated." + ); + } +} + +[JsonSourceGenerationOptions(AllowTrailingCommas = true, WriteIndented = true)] +[JsonSerializable(typeof(Dictionary))] +internal sealed partial class CoreToolsJsonContext : JsonSerializerContext; diff --git a/src/UniGetUI.Core.Tools/DWMThreadHelper.cs b/src/UniGetUI.Core.Tools/DWMThreadHelper.cs new file mode 100644 index 0000000..a509226 --- /dev/null +++ b/src/UniGetUI.Core.Tools/DWMThreadHelper.cs @@ -0,0 +1,251 @@ +using System.Diagnostics; +using System.Runtime.InteropServices; +using UniGetUI.Core.Logging; +using UniGetUI.Core.SettingsEngine; + +namespace UniGetUI; + +public class DWMThreadHelper +{ + [DllImport("ntdll.dll")] + private static extern int NtQueryInformationThread( + IntPtr ThreadHandle, + int ThreadInformationClass, + ref IntPtr ThreadInformation, + int ThreadInformationLength, + out int ReturnLength + ); + + [DllImport("kernel32.dll")] + private static extern IntPtr OpenThread( + ThreadAccess dwDesiredAccess, + bool bInheritHandle, + uint dwThreadId + ); + + [DllImport("kernel32.dll")] + private static extern uint SuspendThread(IntPtr hThread); + + [DllImport("kernel32.dll")] + private static extern uint ResumeThread(IntPtr hThread); + + [DllImport("kernel32.dll")] + private static extern bool CloseHandle(IntPtr hObject); + + [Flags] + private enum ThreadAccess : uint + { + QUERY_INFORMATION = 0x0040, + SUSPEND_RESUME = 0x0002, + } + + private const int ThreadQuerySetWin32StartAddress = 9; + private static bool DWM_IsSuspended; + private static bool XAML_IsSuspended; + + private static int? DWMThreadId; + private static IntPtr? DWMThreadAdress; + private static int? XAMLThreadId; + private static IntPtr? XAMLThreadAdress; + + public static void ChangeState_DWM(bool suspend) + { + if (Settings.Get(Settings.K.DisableDMWThreadOptimizations)) + return; + + if (DWM_IsSuspended && suspend) + { + Logger.Debug("DWM Thread was already suspended"); + return; + } + else if (!DWM_IsSuspended && !suspend) + { + Logger.Debug("DWM Thread was already running"); + return; + } + + DWMThreadAdress ??= GetTargetFunctionAddress("dwmcorei.dll", 0x36240); // 0x36170); + if (DWMThreadAdress is null) + { + Logger.Error("Failed to resolve DWM thread start adress."); + return; + } + + ChangeState(suspend, (IntPtr)DWMThreadAdress, ref DWM_IsSuspended, ref DWMThreadId, "DWM"); + } + + public static void ChangeState_XAML(bool suspend) + { + if (Settings.Get(Settings.K.DisableDMWThreadOptimizations)) + return; + + if (XAML_IsSuspended && suspend) + { + Logger.Debug("XAML Thread was already suspended"); + return; + } + else if (!XAML_IsSuspended && !suspend) + { + Logger.Debug("XAML Thread was already running"); + return; + } + + // The reported offset on ProcessExplorer seems to be missing a part somehow. + // To find the real adress, set offset to 0, and then get the offset from the Debugger.Break at ChangeState() + XAMLThreadAdress ??= GetTargetFunctionAddress("Microsoft.UI.Xaml.dll", 0x27C0E0); //0x2771A0); + if (XAMLThreadAdress is null) + { + Logger.Error("Failed to resolve XAML thread start adress."); + return; + } + + ChangeState( + suspend, + (IntPtr)XAMLThreadAdress, + ref XAML_IsSuspended, + ref XAMLThreadId, + "XAML" + ); + } + + private static IntPtr GetThreadStartAdress(int threadId) + { + IntPtr hThread = OpenThread( + ThreadAccess.QUERY_INFORMATION | ThreadAccess.SUSPEND_RESUME, + false, + (uint)threadId + ); + if (hThread == IntPtr.Zero) + return IntPtr.Zero; + + IntPtr adress = 0x00; + int status = NtQueryInformationThread( + hThread, + ThreadQuerySetWin32StartAddress, + ref adress, + Marshal.SizeOf(), + out _ + ); + if (status != 0) + Logger.Warn( + $"NtQueryInformationThread returned non-zero status code 0x{(uint)status:X}" + ); + CloseHandle(hThread); + return adress; + } + + private static void ChangeState( + bool suspend, + IntPtr expectedAdress, + ref bool IsSuspended, + ref int? threadId, + string loggerName, + bool canRetry = true + ) + { + IntPtr minId = -1; + uint LastDiff = uint.MaxValue; + + if (threadId is null) + { + foreach (ProcessThread thread in Process.GetCurrentProcess().Threads) + { + var adress = GetThreadStartAdress(thread.Id); + if (adress == expectedAdress) + { + threadId = thread.Id; + Logger.Info($"Thread with Id {threadId} was assigned as {loggerName} thread"); + break; + } + else if (((uint)adress - (uint)expectedAdress) < LastDiff) + { + LastDiff = (uint)adress - (uint)expectedAdress; + minId = thread.Id; + } + } + } + + if (threadId is null) + { + Logger.Error( + $"No thread matching {loggerName} with start adress {expectedAdress:X} was found. " + + $"Best guess was {minId} with adress offset {LastDiff:X}" + ); + if (Debugger.IsAttached) + Debugger.Break(); + return; + } + + IntPtr hThread = OpenThread( + ThreadAccess.QUERY_INFORMATION | ThreadAccess.SUSPEND_RESUME, + false, + (uint)threadId + ); + if (hThread == IntPtr.Zero) + { // When the thread cannot be opened + if (canRetry) + { + threadId = null; // On first try, reset argument threadId so it does get loaded again. + ChangeState( + suspend, + expectedAdress, + ref IsSuspended, + ref threadId, + loggerName, + false + ); + return; + } + // The threadId was already reloaded + Logger.Warn( + $"Thread with id={threadId} and assigned as {loggerName} exists but could not be opened!" + ); + return; + } + + if (suspend) + { + uint res = SuspendThread(hThread); + if (res == 0) + { + IsSuspended = true; + Logger.Info($"{loggerName} Thread was suspended successfully"); + CloseHandle(hThread); + return; + } + else + { + Logger.Warn($"Could not suspend {loggerName} Thread with NTSTATUS = 0x{res:X}"); + } + } + else + { + int res = (int)ResumeThread(hThread); + if (res >= 0) + { + IsSuspended = false; + Logger.Info($"{loggerName} Thread was resumed successfully"); + CloseHandle(hThread); + return; + } + else + { + Logger.Error($"Could not resume {loggerName} Thread with NTSTATUS = 0x{res:X}"); + } + } + + CloseHandle(hThread); + } + + private static IntPtr? GetTargetFunctionAddress(string moduleName, int offset) + { + foreach (ProcessModule module in Process.GetCurrentProcess().Modules) + { + if (module.ModuleName.Equals(moduleName, StringComparison.OrdinalIgnoreCase)) + { + return module.BaseAddress + offset; + } + } + return null; + } +} diff --git a/src/UniGetUI.Core.Tools/IntegrityTester.cs b/src/UniGetUI.Core.Tools/IntegrityTester.cs new file mode 100644 index 0000000..f660800 --- /dev/null +++ b/src/UniGetUI.Core.Tools/IntegrityTester.cs @@ -0,0 +1,161 @@ +using System.Security.Cryptography; +using System.Text; +using System.Text.Json; +using UniGetUI.Core.Data; +using UniGetUI.Core.Logging; + +namespace UniGetUI.Core.Tools; + +public static class IntegrityTester +{ + public class MismatchedHash + { + public string Got = string.Empty; + public string Expected = string.Empty; + } + + public struct Result + { + public bool Passed; + public IReadOnlyList MissingFiles; + public Dictionary CorruptedFiles; + } + + private static string GetSHA256(string fullPath, bool canRetry) + { + try + { + using (var sha256 = SHA256.Create()) + { + using (var stream = File.OpenRead(fullPath)) + { + var hashBytes = sha256.ComputeHash(stream); + return BitConverter.ToString(hashBytes).Replace("-", ""); + } + } + } + catch (Exception ex) + { + if (canRetry) + { + Task.Delay(1000).GetAwaiter().GetResult(); + return GetSHA256(fullPath, false); + } + + return $"{ex.GetType()}: {ex.Message}"; + } + } + + public static Result CheckIntegrity(bool allowRetry = true) + { + string integrityTreePath = Path.Join( + CoreData.UniGetUIExecutableDirectory, + "IntegrityTree.json" + ); + if (!File.Exists(integrityTreePath)) + { + Logger.Error( + "/IntegrityTree.json does not exist, integrity check will not be performed!" + ); + return new() + { + Passed = false, + MissingFiles = ["/IntegrityTree.json"], + CorruptedFiles = new Dictionary(), + }; + } + + string rawData = File.ReadAllText(integrityTreePath); + Dictionary? data = null; + + try + { + data = CoreToolsJson.DeserializeStringDictionary(rawData); + } + catch (Exception ex) + { + Logger.Error("Failed to deserialize JSON object"); + Logger.Error(ex); + } + + if (data is null) + { + return new() + { + Passed = false, + MissingFiles = [], + CorruptedFiles = new() + { + { + "", + new MismatchedHash() { Got = rawData, Expected = "A valid JSON" } + }, + }, + }; + } + + Dictionary mismatches = new(); + List misses = new(); + + foreach (var (file, expectedHash) in data) + { + var fullPath = Path.Join(CoreData.UniGetUIExecutableDirectory, file); + if (!File.Exists(fullPath)) + { + misses.Add($"/{file}"); + Logger.Error($"File {file} expected but did not exist"); + continue; + } + + var currentHash = GetSHA256(fullPath, allowRetry).ToLower(); + if (currentHash != expectedHash.ToLower()) + { + mismatches.Add($"/{file}", new() { Expected = expectedHash, Got = currentHash }); + Logger.Error( + $"File {file} expected to have sha256 {expectedHash}, but had {currentHash} instead" + ); + } + } + + Result result = new() + { + Passed = !misses.Any() && !mismatches.Any(), + MissingFiles = misses, + CorruptedFiles = mismatches, + }; + + if (result.Passed) + { + Logger.ImportantInfo("Integrity check passed successfully!"); + } + + return result; + } + + public static string GetReadableReport(Result result) + { + var Builder = new StringBuilder(); + if (result.Passed) + { + Builder.Append("No integrity violations were found.\n"); + } + if (result.MissingFiles.Any()) + { + Builder.Append("Missing files: "); + foreach (var file in result.MissingFiles) + Builder.Append($"\n - {file}"); + Builder.Append('\n'); + } + if (result.CorruptedFiles.Any()) + { + Builder.Append("Corrupted files: "); + foreach (var (file, hashes) in result.CorruptedFiles) + Builder.Append( + $"\n - {file} (sha256 mismatch, got {hashes.Got} but expected {hashes.Expected} " + ); + Builder.Append('\n'); + } + + return Builder.ToString(); + } +} diff --git a/src/UniGetUI.Core.Tools/SerializationHelpers.cs b/src/UniGetUI.Core.Tools/SerializationHelpers.cs new file mode 100644 index 0000000..9880c09 --- /dev/null +++ b/src/UniGetUI.Core.Tools/SerializationHelpers.cs @@ -0,0 +1,191 @@ +using System.Globalization; +using System.Text.Json; +using System.Text.Json.Nodes; +using System.Xml; +using YamlDotNet.RepresentationModel; + +namespace UniGetUI.Core.Data; + +public static class SerializationHelpers +{ + private static readonly JsonSerializerOptions NodeJsonOptions = new() + { + AllowTrailingCommas = true, + WriteIndented = true, + }; + + public static Task YAML_to_JSON(string YAML) => Task.Run(() => yaml_to_json(YAML)); + + private static string yaml_to_json(string YAML) + { + using var reader = new StringReader(YAML); + var stream = new YamlStream(); + stream.Load(reader); + + if (stream.Documents.Count == 0 || stream.Documents[0].RootNode is null) + return "{\"message\":\"deserialized YAML object was null\"}"; + + return ConvertYamlNode(stream.Documents[0].RootNode)?.ToJsonString(NodeJsonOptions) + ?? "null"; + } + + public static Task XML_to_JSON(string XML) => Task.Run(() => xml_to_json(XML)); + + private static string xml_to_json(string XML) + { + var doc = new XmlDocument(); + doc.LoadXml(XML); + if (doc.DocumentElement is null) + return "{\"message\":\"XmlDocument.DocumentElement was null\"}"; + + return ConvertXmlNode(doc.DocumentElement)?.ToJsonString(NodeJsonOptions) + ?? "null"; + } + + private static JsonNode? ConvertXmlNode(XmlNode node) + { + if (node.ChildNodes.Count == 1 && node.FirstChild is XmlText singleText) + { + return JsonValue.Create(singleText.Value); + } + + var jsonObject = new JsonObject(); + if (node.Attributes?.Count > 0) + { + foreach (XmlAttribute attr in node.Attributes) + { + jsonObject[$"@{attr.Name}"] = attr.Value; + } + } + + var children = new Dictionary>(); + foreach (XmlNode child in node.ChildNodes) + { + if (child is XmlElement childElement) + { + var value = ConvertXmlNode(childElement); + if (!children.ContainsKey(childElement.Name)) + children[childElement.Name] = new List(); + children[childElement.Name].Add(value); + } + } + + if (children.Count == 1 && jsonObject.Count == 0) + { + var firstKey = children.Keys.First(); + return children[firstKey].Count == 1 + ? children[firstKey][0] + : new JsonArray(children[firstKey].ToArray()); + } + + foreach (var kv in children) + { + jsonObject[kv.Key] = kv.Value.Count == 1 ? kv.Value[0] : new JsonArray(kv.Value.ToArray()); + } + + return jsonObject; + } + + private static JsonNode? ConvertYamlNode(YamlNode node) + { + return node switch + { + YamlScalarNode scalar => ConvertYamlScalar(scalar), + YamlSequenceNode sequence => ConvertYamlSequence(sequence), + YamlMappingNode mapping => ConvertYamlMapping(mapping), + _ => JsonValue.Create(node.ToString()), + }; + } + + private static JsonNode? ConvertYamlScalar(YamlScalarNode scalar) + { + if (scalar.Value is null) + return null; + + if (bool.TryParse(scalar.Value, out bool boolValue)) + return JsonValue.Create(boolValue); + + if (long.TryParse(scalar.Value, NumberStyles.Integer, CultureInfo.InvariantCulture, out long longValue)) + return JsonValue.Create(longValue); + + if (double.TryParse(scalar.Value, NumberStyles.Float, CultureInfo.InvariantCulture, out double doubleValue)) + return JsonValue.Create(doubleValue); + + return JsonValue.Create(scalar.Value); + } + + private static JsonArray ConvertYamlSequence(YamlSequenceNode sequence) + { + var array = new JsonArray(); + foreach (YamlNode child in sequence.Children) + array.Add(ConvertYamlNode(child)); + return array; + } + + private static JsonObject ConvertYamlMapping(YamlMappingNode mapping) + { + var obj = new JsonObject(); + foreach (var (key, value) in mapping.Children) + obj[ConvertYamlKey(key)] = ConvertYamlNode(value); + return obj; + } + + private static string ConvertYamlKey(YamlNode key) + { + return key is YamlScalarNode scalar + ? scalar.Value ?? "" + : key.ToString(); + } + + public static JsonSerializerOptions DefaultOptions = new() + { + AllowTrailingCommas = true, + WriteIndented = true, + }; +} + +public static class JsonNodeExtensions +{ + /// + /// Safely gets a child node by key, returning null if the key does not exist. + /// + public static T GetVal(this JsonNode node) + { + if (typeof(T) == typeof(double) && node.GetValueKind() is JsonValueKind.String) + return (T)(object)double.Parse(node.GetValue(), CultureInfo.InvariantCulture); + + if (typeof(T) == typeof(int) && node.GetValueKind() is JsonValueKind.String) + return (T)(object)int.Parse(node.GetValue()); + + if (typeof(T) == typeof(bool) && node.GetValueKind() is JsonValueKind.String) + return (T)(object)bool.Parse(node.GetValue()); + + if (typeof(T) == typeof(string) && node.GetValueKind() is JsonValueKind.Object) + { + return (T)(object)""; + } + + return node.GetValue(); + } + + /// + /// The same as JsonNode.AsArray, but can convert objects whose keys are integers to arrays + /// + /// + /// + public static JsonArray AsArray2(this JsonNode node) + { + if (node is JsonValue val) + { + JsonArray result = new(); + result.Add(val.DeepClone()); + return result; + } + else if (node is JsonObject obj && !obj.Any()) + { + return new JsonArray(); + } + + return node.AsArray(); + } +} diff --git a/src/UniGetUI.Core.Tools/Tools.cs b/src/UniGetUI.Core.Tools/Tools.cs new file mode 100644 index 0000000..05ac720 --- /dev/null +++ b/src/UniGetUI.Core.Tools/Tools.cs @@ -0,0 +1,1237 @@ +using System.Collections; +using System.Diagnostics; +using System.Globalization; +using System.Net; +using System.Net.NetworkInformation; +using System.Runtime.InteropServices; +using System.Security.Cryptography; +using System.Security.Principal; +using System.Text; +using UniGetUI.Core.Classes; +using UniGetUI.Core.Data; +using UniGetUI.Core.Language; +using UniGetUI.Core.Logging; +using UniGetUI.Core.SettingsEngine; +using UniGetUI.PackageEngine.Enums; +#if WINDOWS +using Windows.Networking.Connectivity; +#endif + +namespace UniGetUI.Core.Tools +{ + public static class CoreTools + { + public static HttpClientHandler GenericHttpClientParameters + { + get + { + Uri? proxyUri = null; + IWebProxy? proxy = null; + ICredentials? creds = null; + + if (Settings.Get(Settings.K.EnableProxy)) + proxyUri = Settings.GetProxyUrl(); + if (Settings.Get(Settings.K.EnableProxyAuth)) + creds = Settings.GetProxyCredentials(); + if (proxyUri is not null) + proxy = new WebProxy() { Address = proxyUri, Credentials = creds }; + + return new() + { + AutomaticDecompression = DecompressionMethods.All, + AllowAutoRedirect = true, + UseProxy = (proxy is not null), + Proxy = proxy, + }; + } + } + + private static LanguageEngine LanguageEngine = new(); + + static CoreTools() + { + LoadStaticTranslation(); + } + + /// + /// Translate a string to the current language + /// + /// The string to translate + /// The translated string if available, the original string otherwise + public static string Translate(string text) + { + return LanguageEngine.Translate(text); + } + + public static string Translate(string text, Dictionary dict) + { + return LanguageEngine.Translate(text, dict); + } + + public static string Translate(string text, params object[] values) + { + Dictionary dict = []; + foreach ((object item, int index) in values.Select((item, index) => (item, index))) + { + dict.Add(index.ToString(), item); + } + + return Translate(text, dict); + } + + public static void ReloadLanguageEngineInstance(string ForceLanguage = "") + { + LanguageEngine = new LanguageEngine(ForceLanguage); + LoadStaticTranslation(); + } + + /// + /// Translates a string into the operating system's UI language, independently of the + /// language currently selected in UniGetUI. Used for the "System language" entry of the + /// language selector so it appears in the language it would actually resolve to. + /// Falls back to the current app language if the system language cannot be loaded. + /// + public static string TranslateInSystemLanguage(string text) + { + try + { + string systemLocale = CultureInfo.CurrentUICulture.ToString().Replace("-", "_"); + if (string.IsNullOrWhiteSpace(systemLocale)) + systemLocale = "en"; + + return new LanguageEngine(systemLocale).Translate(text); + } + catch (Exception ex) + { + Logger.Warn("Could not translate string into the system language; falling back to the app language"); + Logger.Warn(ex); + return Translate(text); + } + } + + private static void LoadStaticTranslation() + { + string localScopeName = CoreTools.Translate("User | Local"); + string globalScopeName = CoreTools.Translate("Machine | Global"); + + CommonTranslations.ScopeNames[PackageScope.Local] = localScopeName; + CommonTranslations.ScopeNames[PackageScope.Global] = globalScopeName; + + CommonTranslations.InvertedScopeNames.Clear(); + CommonTranslations.InvertedScopeNames.Add(globalScopeName, PackageScope.Global); + CommonTranslations.InvertedScopeNames.Add(localScopeName, PackageScope.Local); + } + + /// + /// Dummy function to capture the strings that need to be translated but the translation is handled by a custom widget + /// + public static string AutoTranslated(string text) + { + return text; + } + + /// + /// Launches the self executable on a new process and kills the current process + /// + public static void RelaunchProcess() + { + Logger.Debug("Launching process: " + CoreData.UniGetUIExecutableFile); + ScheduleRelaunchAfterExit(); + Logger.Warn("About to kill process"); + Environment.Exit(0); + } + + public static void ScheduleRelaunchAfterExit(string? executablePath = null) + { + executablePath ??= CoreData.UniGetUIExecutableFile; + int currentProcessId = Environment.ProcessId; + string escapedExecutablePath = executablePath.Replace("'", "''"); + string command = + $"Wait-Process -Id {currentProcessId}; Start-Process -FilePath '{escapedExecutablePath}'"; + + using var process = Process.Start( + new ProcessStartInfo + { + FileName = "powershell.exe", + Arguments = $"-NoProfile -WindowStyle Hidden -Command \"{command}\"", + UseShellExecute = false, + CreateNoWindow = true, + } + ); + } + + /// + /// Finds an executable in path and returns its location + /// + /// The executable alias to find + /// A tuple containing: a boolean that represents whether the path was found or not; the path to the file if found. + public static async Task> WhichAsync(string command) + { + return await Task.Run(() => Which(command)); + } + + public static List WhichMultiple(string command, bool updateEnv = true) + { + command = command.Replace(";", "").Replace("&", "").Trim(); + Logger.Debug($"Begin \"which\" search for command {command}"); + + _ = updateEnv; + + if (string.IsNullOrWhiteSpace(command)) + { + Logger.ImportantInfo($"Command {command} was not found on the system"); + return []; + } + + string pathValue = GetSearchPath(); + + List lines = FindExecutableMatches(command, pathValue); + if (lines.Count is 0) + { + Logger.ImportantInfo($"Command {command} was not found on the system"); + return []; + } + + Logger.Debug( + $"Command {command} was found on {lines[0]} (with {lines.Count - 1} more occurrences)" + ); + return lines; + } + + public static Tuple Which(string command, bool updateEnv = true) + { + var paths = WhichMultiple(command, updateEnv); + return new(paths.Any(), paths.Any() ? paths[0] : ""); + } + + /// + /// Formats a given package id as a name, capitalizing words and replacing separators with spaces + /// + /// A string containing the Id of a package + /// The formatted string + public static string FormatAsName(string name) + { + name = name.Replace(".install", "") + .Replace(".portable", "") + .Replace("-", " ") + .Replace("_", " ") + .Split("/")[^1] + .Split(":")[0]; + string newName = ""; + for (int i = 0; i < name.Length; i++) + { + if ( + i == 0 + || name[i - 1] == ' ' + || name[i - 1] == '[' /* for vcpkg options */ + ) + { + newName += name[i].ToString().ToUpper(); + } + else + { + newName += name[i]; + } + } + + newName = newName.Replace(" [", "[").Replace("[", " ["); + return newName; + } + + /// + /// Generates a random string composed of alphanumeric characters and numbers + /// + /// The length of the string + /// A string + public static string RandomString(int length) + { + Random random = new(); + const string pool = "abcdefghijklmnopqrstuvwxyz0123456789"; + IEnumerable chars = Enumerable + .Range(0, length) + .Select(_ => pool[random.Next(0, pool.Length)]); + return new string(chars.ToArray()); + } + + /// + /// Launches a .bat or .cmd file for the given filename + /// + /// The path of the batch file + /// The title of the window + /// Whether the batch file should be launched elevated or not + public static async Task LaunchBatchFile( + string path, + string WindowTitle = "", + bool RunAsAdmin = false + ) + { + try + { + using Process p = new(); + if (OperatingSystem.IsWindows()) + { + p.StartInfo.FileName = "cmd.exe"; + p.StartInfo.Arguments = "/C start \"" + WindowTitle + "\" \"" + path + "\""; + p.StartInfo.UseShellExecute = true; + p.StartInfo.Verb = RunAsAdmin ? "runas" : ""; + } + else + { + p.StartInfo.FileName = "/bin/sh"; + p.StartInfo.ArgumentList.Add(path); + p.StartInfo.UseShellExecute = false; + } + + p.StartInfo.CreateNoWindow = true; + p.Start(); + await p.WaitForExitAsync(); + } + catch (Exception ex) + { + Logger.Error(ex); + } + } + + /// + /// Checks whether the current process has administrator privileges + /// + /// True if the process has administrator privileges + public static bool IsAdministrator() + { + try + { + if (!OperatingSystem.IsWindows()) + { + return string.Equals(Environment.UserName, "root", StringComparison.Ordinal); + } + + return new WindowsPrincipal(WindowsIdentity.GetCurrent()).IsInRole( + WindowsBuiltInRole.Administrator + ); + } + catch (Exception e) + { + Logger.Warn("Could not check if user is administrator"); + Logger.Warn(e); + return false; + } + } + + /// + /// Checks whether the current process is running inside an MSIX package (Store / sideloaded). + /// + /// True when packaged, false when running unpackaged or on a non-Windows platform. + public static bool IsPackagedApp() + { + if (!OperatingSystem.IsWindows()) + { + return false; + } + + try + { + int len = 0; + int rc = GetCurrentPackageFullName(ref len, IntPtr.Zero); + return rc != APPMODEL_ERROR_NO_PACKAGE; + } + catch + { + return false; + } + } + + private const int APPMODEL_ERROR_NO_PACKAGE = 15700; + + [DllImport("kernel32.dll", SetLastError = false)] + private static extern int GetCurrentPackageFullName(ref int packageFullNameLength, IntPtr packageFullName); + + public static Task GetFileSizeAsLongAsync(Uri? url) => + Task.Run(() => GetFileSizeAsLong(url)); + + public static long GetFileSizeAsLong(Uri? url) + { + if (url is null) + return 0; + + try + { + using HttpClient client = new(CoreTools.GenericHttpClientParameters); + using var request = new HttpRequestMessage(HttpMethod.Head, url); + using HttpResponseMessage response = client.Send(request); + return response.Content.Headers.ContentLength ?? 0; + } + catch (Exception e) + { + Logger.Warn($"Could not load file size for url={url}"); + Logger.Warn(e); + } + + return 0; + } + + public static string GetFileName(Uri url) + { + try + { + var handler = CoreTools.GenericHttpClientParameters; + handler.AllowAutoRedirect = false; + using HttpClient client = new(handler); + using var request = new HttpRequestMessage(HttpMethod.Head, url); + using HttpResponseMessage response = client.Send(request); + + if ( + response.StatusCode + is HttpStatusCode.Moved + or HttpStatusCode.Redirect + or HttpStatusCode.RedirectMethod + or HttpStatusCode.TemporaryRedirect + or HttpStatusCode.PermanentRedirect + ) + { + return GetFileName( + response.Headers.Location + ?? throw new HttpRequestException( + "A redirect code was returned but no new location was given" + ) + ); + } + + return response.Content.Headers.ContentDisposition?.FileName + ?? Path.GetFileName(url.LocalPath); + } + catch (Exception e) + { + Logger.Warn($"Failed to retrieve file name for URL: {url}"); + Logger.Warn(e); + return string.Empty; + } + } + + public static Task GetFileNameAsync(Uri url) => Task.Run(() => GetFileName(url)); + + public struct Version : IComparable + { + public static readonly Version Null = new(-1, -1, -1, -1); + + public readonly int Major; + public readonly int Minor; + public readonly int Patch; + public readonly int Remainder; + + public Version(int major, int minor = 0, int patch = 0, int remainder = 0) + { + Major = major; + Minor = minor; + Patch = patch; + Remainder = remainder; + } + + public int CompareTo(object? other_) + { + if (other_ is not Version other) + return 0; + + int major = Major.CompareTo(other.Major); + if (major != 0) + return major; + + int minor = Minor.CompareTo(other.Minor); + if (minor != 0) + return minor; + + int patch = Patch.CompareTo(other.Patch); + if (patch != 0) + return patch; + + return Remainder.CompareTo(other.Remainder); + } + + public static bool operator ==(Version left, Version right) => + left.CompareTo(right) == 0; + + public static bool operator !=(Version left, Version right) => + left.CompareTo(right) != 0; + + public static bool operator >=(Version left, Version right) => + left.CompareTo(right) >= 0; + + public static bool operator <=(Version left, Version right) => + left.CompareTo(right) <= 0; + + public static bool operator >(Version left, Version right) => left.CompareTo(right) > 0; + + public static bool operator <(Version left, Version right) => left.CompareTo(right) < 0; + + public bool Equals(Version other) => + Major == other.Major + && Minor == other.Minor + && Patch == other.Patch + && Remainder == other.Remainder; + + public override bool Equals(object? obj) => obj is Version other && Equals(other); + + public override int GetHashCode() => HashCode.Combine(Major, Minor, Patch, Remainder); + } + + /// + /// Converts a string into a double floating-point number. + /// + /// Any string + /// The best approximation of the string as a Version + public static Version VersionStringToStruct(string version) + { + try + { + char[] separators = ['.', '-', '/', '#']; + string[] versionItems = ["", "", "", ""]; + + string[] segments = version.Split(separators, StringSplitOptions.RemoveEmptyEntries); + foreach (var segment in segments) + { + bool seenDigit = false; + bool seenLetterAfterDigit = false; + bool seenDigitAfterLetter = false; + foreach (char c in segment) + { + if (char.IsDigit(c)) + { + if (seenLetterAfterDigit) + seenDigitAfterLetter = true; + seenDigit = true; + } + else if (char.IsLetter(c) && seenDigit) + { + seenLetterAfterDigit = true; + } + } + + if (seenDigit && seenLetterAfterDigit && seenDigitAfterLetter) + { + Logger.Warn( + $"Version string {version} appears to contain non-numeric characters within a numeric segment and will be treated as unknown"); + return CoreTools.Version.Null; + } + } + + int dotCount = 0; + bool first = true; + + foreach (char c in version) + { + if (char.IsDigit(c)) + versionItems[dotCount] += c; + else if (!first && separators.Contains(c)) + if (dotCount < 3) + dotCount++; + first = false; + } + + int[] numbers = { 0, 0, 0, 0 }; + for (int i = 0; i < 4; i++) + { + if (int.TryParse(versionItems[i], out int val)) + numbers[i] = val; + } + + var ver = new Version(numbers[0], numbers[1], numbers[2], numbers[3]); + return ver; + } + catch + { + Logger.Warn($"Failed to parse version {version} to float"); + return CoreTools.Version.Null; + } + } + + public static System.Version NormalizeVersionForComparison(System.Version version) + { + return version.Revision >= 0 + ? new System.Version(version.Major, version.Minor, version.Build) + : version; + } + + /// + /// Returns the query that can be safely passed as a command-line parameter + /// + /// The query to make safe + /// The safe version of the query + public static string EnsureSafeQueryString(string query) + { + return query + .Replace(";", string.Empty) + .Replace("&", string.Empty) + .Replace("|", string.Empty) + .Replace(">", string.Empty) + .Replace("<", string.Empty) + .Replace("%", string.Empty) + .Replace("\"", string.Empty) + .Replace("~", string.Empty) + .Replace("?", string.Empty) + .Replace("/", string.Empty) + .Replace("'", string.Empty) + .Replace("\\", string.Empty) + .Replace("`", string.Empty); + } + + /// + /// Returns null if the string is empty + /// + /// The string to check + /// a string? instance + public static string? GetStringOrNull(string? value) + { + if (value == "") + { + return null; + } + + return value; + } + + /// + /// Returns a new Uri if the string is not empty. Returns null otherwise + /// + /// The null, empty or valid string + /// an Uri? instance + public static Uri? GetUriOrNull(string? url) + { + if (url is "" or null) + { + return null; + } + + return new Uri(url); + } + + /// + /// Enables GSudo cache for the current process + /// + private static bool _isCaching; + + public static async Task CacheUACForCurrentProcess() + { + if (Settings.Get(Settings.K.ProhibitElevation)) + { + Logger.Error( + "Elevation is prohibited, CacheUACForCurrentProcess() call will be ignored" + ); + return; + } + + while (_isCaching) + await Task.Delay(100); + + try + { + _isCaching = true; + Logger.Info("Caching admin rights for process id " + Environment.ProcessId); + + var elevatorName = Path.GetFileName(CoreData.ElevatorPath); + + // pkexec prompts on every invocation and has no caching protocol. + if (elevatorName == "pkexec") + { + _isCaching = false; + return; + } + + // sudo: -v validates/extends the cached timestamp. + // Prepend -A only when the SUDO_ASKPASS helper is configured. + // gsudo / UniGetUI Elevator.exe: use the gsudo cache protocol. + string cacheArgs = elevatorName == "sudo" + ? (CoreData.ElevatorArgs.Contains("-A") ? "-Av" : "-v") + : "cache on --pid " + Environment.ProcessId + " -d 1"; + + using Process p = new() + { + StartInfo = new ProcessStartInfo + { + FileName = CoreData.ElevatorPath, + Arguments = cacheArgs, + UseShellExecute = false, + RedirectStandardOutput = true, + RedirectStandardError = true, + RedirectStandardInput = true, + CreateNoWindow = true, + StandardOutputEncoding = Encoding.UTF8, + }, + }; + p.Start(); + await p.WaitForExitAsync(); + _isCaching = false; + } + catch (Exception ex) + { + Logger.Error(ex); + _isCaching = false; + } + } + + /// + /// Reset UAC cache for the current process + /// + public static async Task ResetUACForCurrentProcess() + { + if (Settings.Get(Settings.K.ProhibitElevation)) + { + Logger.Error( + "Elevation is prohibited, ResetUACForCurrentProcess() call will be ignored" + ); + return; + } + + Logger.Info( + "Resetting administrator rights cache for process id " + Environment.ProcessId + ); + + var elevatorName = Path.GetFileName(CoreData.ElevatorPath); + + // pkexec prompts on every invocation and has no caching protocol. + if (elevatorName == "pkexec") + { + return; + } + + // sudo: -K removes all cached timestamps. + // gsudo / UniGetUI Elevator.exe: use the gsudo cache protocol. + string resetArgs = elevatorName == "sudo" + ? "-K" + : "cache off --pid " + Environment.ProcessId; + + using Process p = new() + { + StartInfo = new ProcessStartInfo + { + FileName = CoreData.ElevatorPath, + Arguments = resetArgs, + UseShellExecute = false, + RedirectStandardOutput = true, + RedirectStandardError = true, + RedirectStandardInput = true, + CreateNoWindow = true, + StandardOutputEncoding = Encoding.UTF8, + }, + }; + p.Start(); + await p.WaitForExitAsync(); + } + + /// + /// Returns the hash of the given string in the form of a long integer. + /// The long integer is built with the first half of the MD5 sum of the given string + /// + /// A non-empty string + /// A long integer containing the first half of the bytes resulting from MD5 summing inputString + public static long HashStringAsLong(string inputString) + { + byte[] bytes = MD5.HashData(Encoding.UTF8.GetBytes(inputString)); + return BitConverter.ToInt64(bytes, 0); + } + + /// + /// Creates a symbolic link between directories + /// + /// The location of the link to be created + /// The location of the real folder where to point + public static void CreateSymbolicLinkDir(string linkPath, string targetPath) + { + Directory.CreateSymbolicLink(linkPath, targetPath); + + if (!Directory.Exists(linkPath)) + { + throw new InvalidOperationException( + $"The symbolic link '{linkPath}' was not created successfully." + ); + } + } + + /// + /// Will check whether the given folder is a symbolic link + /// + /// The folder to check + /// + public static bool IsSymbolicLinkDir(string path) + { + if (!Directory.Exists(path) && !File.Exists(path)) + { + throw new FileNotFoundException("The specified path does not exist.", path); + } + + var attributes = File.GetAttributes(path); + return (attributes & FileAttributes.ReparsePoint) == FileAttributes.ReparsePoint; + } + + /// + /// Returns the updated environment variables on a new ProcessStartInfo object + /// + /// + public static ProcessStartInfo UpdateEnvironmentVariables() + { + return UpdateEnvironmentVariables(new ProcessStartInfo()); + } + + /// + /// Returns the updated environment variables on the returned ProcessStartInfo object + /// + /// + public static ProcessStartInfo UpdateEnvironmentVariables(ProcessStartInfo info) + { + if (!OperatingSystem.IsWindows()) + { + foreach (DictionaryEntry env in Environment.GetEnvironmentVariables()) + { + info.Environment[env.Key?.ToString() ?? "UNKNOWN"] = env.Value?.ToString(); + } + + return info; + } + + foreach ( + DictionaryEntry env in Environment.GetEnvironmentVariables( + EnvironmentVariableTarget.Machine + ) + ) + { + info.Environment[env.Key?.ToString() ?? "UNKNOWN"] = env.Value?.ToString(); + } + + foreach ( + DictionaryEntry env in Environment.GetEnvironmentVariables( + EnvironmentVariableTarget.User + ) + ) + { + string key = env.Key.ToString() ?? ""; + string newValue = env.Value?.ToString() ?? ""; + if ( + info.Environment.TryGetValue(key, out string? oldValue) + && oldValue is not null + && oldValue.Contains(';') + && newValue != "" + ) + { + info.Environment[key] = oldValue + ";" + newValue; + } + else + { + info.Environment[key] = newValue; + } + } + + return info; + } + + /// + /// Pings the update server and 3 well-known sites to check for internet availability + /// + public static async Task WaitForInternetConnection() => + await TaskRecycler.RunOrAttachAsync_VOID(_waitForInternetConnection); + + public static void _waitForInternetConnection() + { + if (Settings.Get(Settings.K.DisableWaitForInternetConnection)) + return; + + Logger.Debug("Checking for internet connectivity..."); + bool internetLost = false; + +#if WINDOWS + var profile = NetworkInformation.GetInternetConnectionProfile(); + while ( + profile is null + || profile.GetNetworkConnectivityLevel() + is not NetworkConnectivityLevel.InternetAccess + ) + { + Thread.Sleep(1000); + profile = NetworkInformation.GetInternetConnectionProfile(); + if (!internetLost) + { + Logger.Warn( + "User is not connected to the internet, waiting for an internet connectio to be available..." + ); + internetLost = true; + } + } +#else + while (!NetworkInterface.GetIsNetworkAvailable()) + { + Thread.Sleep(1000); + if (!internetLost) + { + Logger.Warn( + "User is not connected to the internet, waiting for an internet connection to be available..." + ); + internetLost = true; + } + } +#endif + Logger.Debug("Internet connectivity was established."); + } + + public static string TextProgressGenerator(int length, int progressPercent, string? extra) + { + int done = (int)((progressPercent / 100.0) * (length)); + int rest = length - done; + + StringBuilder builder = new StringBuilder() + .Append('[') + .Append('#', done) + .Append('.', rest) + .Append("] ") + .Append(progressPercent) + .Append('%'); + + if (extra is not null) + { + builder.Append(" (").Append(extra).Append(')'); + } + + return builder.ToString(); + } + + public static string FormatAsSize(long number, int decimals = 1) + { + const double KiloByte = 1024d; + const double MegaByte = 1024d * 1024d; + const double GigaByte = 1024d * 1024d * 1024d; + const double TeraByte = 1024d * 1024d * 1024d * 1024d; + + if (number >= TeraByte) + { + return $"{(number / TeraByte).ToString($"F{decimals}")} TB"; + } + + if (number >= GigaByte) + { + return $"{(number / GigaByte).ToString($"F{decimals}")} GB"; + } + + if (number >= MegaByte) + { + return $"{(number / MegaByte).ToString($"F{decimals}")} MB"; + } + + if (number >= KiloByte) + { + return $"{(number / KiloByte).ToString($"F{decimals}")} KB"; + } + + return $"{number} Bytes"; + } + + public static async Task ShowFileOnExplorer(string path) + { + try + { + if (!File.Exists(path)) + throw new FileNotFoundException($"The file {path} was not found"); + + if (!OperatingSystem.IsWindows()) + { + Launch(Path.GetDirectoryName(path)); + return; + } + + using Process p = new() + { + StartInfo = new() + { + FileName = "explorer.exe", + Arguments = $"/select, \"{path}\"", + UseShellExecute = true, + CreateNoWindow = true, + }, + }; + p.Start(); + await p.WaitForExitAsync(); + } + catch (Exception ex) + { + Logger.Error(ex); + } + } + + public static void Launch(string? path) + { + try + { + if (path is null) + return; + + using var p = new Process() + { + StartInfo = new() { FileName = path, UseShellExecute = true, CreateNoWindow = true, }, + }; + p.Start(); + } + catch (Exception ex) + { + Logger.Error(ex); + } + } + + public static string GetCurrentLocale() + { + return LanguageEngine?.Locale ?? "Unset/Unknown"; + } + + private static readonly HashSet _illegalPathChars = Path.GetInvalidFileNameChars() + .ToHashSet(); + + public static string MakeValidFileName(string name) => + string.Concat(name.Where(x => !_illegalPathChars.Contains(x))); + + // Safely wait for a task that may throw an exception we don't care about + public static async void FinalizeDangerousTask(Task t) + { + try + { + await t.ConfigureAwait(false); + } + catch (Exception ex) + { + Logger.Error($"Task {t} crashed with exception:"); + Logger.Error(ex); + } + } + + private static List FindExecutableMatches(string command, string pathValue) + { + List matches = []; + HashSet seen = new( + OperatingSystem.IsWindows() + ? StringComparer.OrdinalIgnoreCase + : StringComparer.Ordinal + ); + + if (HasDirectoryComponent(command)) + { + AddExecutableMatches( + matches, + seen, + Path.GetDirectoryName(command) ?? string.Empty, + Path.GetFileName(command) + ); + return matches; + } + + foreach (string directory in EnumerateSearchDirectories(pathValue)) + { + AddExecutableMatches(matches, seen, directory, command); + } + + return matches; + } + + private static void AddExecutableMatches( + List matches, + HashSet seen, + string directory, + string command + ) + { + string searchDirectory = NormalizeSearchDirectory(directory); + if (searchDirectory.Length is 0) + { + return; + } + + foreach (string candidateName in EnumerateCandidateFileNames(command)) + { + TryAddExecutablePath(Path.Combine(searchDirectory, candidateName), matches, seen); + } + } + + private static IEnumerable EnumerateSearchDirectories(string pathValue) + { + if (OperatingSystem.IsWindows()) + { + yield return Environment.CurrentDirectory; + } + + foreach (string pathEntry in pathValue.Split(Path.PathSeparator)) + { + string normalizedEntry = NormalizeSearchDirectory(pathEntry); + if (normalizedEntry.Length is not 0) + { + yield return normalizedEntry; + } + } + } + + private static string NormalizeSearchDirectory(string? pathEntry) + { + if (string.IsNullOrWhiteSpace(pathEntry)) + { + return Environment.CurrentDirectory; + } + + return pathEntry.Trim().Trim('"'); + } + + private static IEnumerable EnumerateCandidateFileNames(string command) + { + if (!OperatingSystem.IsWindows() || Path.HasExtension(command)) + { + yield return command; + yield break; + } + + foreach (string extension in GetWindowsExecutableExtensions()) + { + yield return command + extension; + } + } + + private static IReadOnlyList GetWindowsExecutableExtensions() + { + List extensions = ( + Environment.GetEnvironmentVariable("PATHEXT") ?? ".COM;.EXE;.BAT;.CMD" + ) + .Split(';', StringSplitOptions.RemoveEmptyEntries) + .Select(extension => extension.Trim()) + .Where(extension => !string.IsNullOrWhiteSpace(extension)) + .Select(extension => extension.StartsWith('.') ? extension : "." + extension) + .Distinct(StringComparer.OrdinalIgnoreCase) + .ToList(); + + return extensions.Count > 0 ? extensions : [".COM", ".EXE", ".BAT", ".CMD"]; + } + + private static void TryAddExecutablePath( + string candidatePath, + List matches, + HashSet seen + ) + { + if (!File.Exists(candidatePath) || !IsExecutablePath(candidatePath)) + { + return; + } + + string fullPath = Path.GetFullPath(candidatePath); + if (seen.Add(fullPath)) + { + matches.Add(fullPath); + } + } + + private static bool IsExecutablePath(string candidatePath) + { + if (OperatingSystem.IsWindows()) + { + return true; + } + + try + { + const UnixFileMode ExecutableBits = + UnixFileMode.UserExecute + | UnixFileMode.GroupExecute + | UnixFileMode.OtherExecute; + + return (File.GetUnixFileMode(candidatePath) & ExecutableBits) is not 0; + } + catch (IOException) + { + return false; + } + catch (UnauthorizedAccessException) + { + return false; + } + catch (NotSupportedException) + { + return false; + } + } + + private static bool HasDirectoryComponent(string command) => + Path.IsPathRooted(command) + || command.Contains(Path.DirectorySeparatorChar) + || command.Contains(Path.AltDirectorySeparatorChar); + + private static string GetSearchPath() + { + if (!OperatingSystem.IsWindows()) + { + string currentPath = Environment.GetEnvironmentVariable("PATH") ?? string.Empty; + if (IsRunningInWsl()) + { + currentPath = RemoveWindowsHostPathEntries(currentPath); + } + + return currentPath; + } + + string separator = Path.PathSeparator.ToString(); + string pathValue = + ( + Environment.GetEnvironmentVariable("PATH", EnvironmentVariableTarget.User) + ?? string.Empty + ) + separator; + pathValue += + ( + Environment.GetEnvironmentVariable("PATH", EnvironmentVariableTarget.Machine) + ?? string.Empty + ) + separator; + pathValue += + Environment.GetEnvironmentVariable("PATH", EnvironmentVariableTarget.Process) + ?? string.Empty; + return pathValue.Replace(separator + separator, separator).Trim(Path.PathSeparator); + } + + private static bool IsRunningInWsl() + { + if (!OperatingSystem.IsLinux()) + { + return false; + } + + if (!string.IsNullOrWhiteSpace(Environment.GetEnvironmentVariable("WSL_DISTRO_NAME"))) + { + return true; + } + + return !string.IsNullOrWhiteSpace(Environment.GetEnvironmentVariable("WSL_INTEROP")); + } + + private static string RemoveWindowsHostPathEntries(string pathValue) + { + if (string.IsNullOrWhiteSpace(pathValue)) + { + return string.Empty; + } + + string separator = Path.PathSeparator.ToString(); + IEnumerable filteredEntries = pathValue + .Split(Path.PathSeparator, StringSplitOptions.RemoveEmptyEntries) + .Select(entry => entry.Trim()) + .Where(entry => !IsWindowsHostMountPath(entry)); + + return string.Join(separator, filteredEntries); + } + + private static bool IsWindowsHostMountPath(string pathEntry) + { + if (!pathEntry.StartsWith("/mnt/", StringComparison.OrdinalIgnoreCase)) + { + return false; + } + + if (pathEntry.Length < 6) + { + return false; + } + + char driveLetter = pathEntry[5]; + if (!char.IsAsciiLetter(driveLetter)) + { + return false; + } + + return pathEntry.Length == 6 || pathEntry[6] == '/'; + } + } +} diff --git a/src/UniGetUI.Core.Tools/UniGetUI.Core.Tools.csproj b/src/UniGetUI.Core.Tools/UniGetUI.Core.Tools.csproj new file mode 100644 index 0000000..8a5b817 --- /dev/null +++ b/src/UniGetUI.Core.Tools/UniGetUI.Core.Tools.csproj @@ -0,0 +1,17 @@ + + + $(SharedTargetFrameworks) + + + + + + + + + + + + + + diff --git a/src/UniGetUI.Core.Tools/UpdaterDownloadEngine.cs b/src/UniGetUI.Core.Tools/UpdaterDownloadEngine.cs new file mode 100644 index 0000000..f095918 --- /dev/null +++ b/src/UniGetUI.Core.Tools/UpdaterDownloadEngine.cs @@ -0,0 +1,657 @@ +using System.Buffers.Binary; +using System.Globalization; +using System.Net; +using System.Net.Http.Headers; +using System.Security.Cryptography; +using System.Text; +using System.Text.Json; +using System.Text.Json.Serialization; +using System.Text.Json.Serialization.Metadata; +using UniGetUI.Core.Logging; + +namespace UniGetUI.Core.Tools; + +public readonly record struct UpdaterDownloadIdentity( + string Version, + string ExpectedHash, + string Url +); + +public sealed class UpdaterInstallerDownloadMetadata +{ + public string Version { get; set; } = ""; + public string ExpectedHash { get; set; } = ""; + public string Url { get; set; } = ""; + public string ETag { get; set; } = ""; + public DateTimeOffset? LastModified { get; set; } + public long? TotalLength { get; set; } + public DateTime UpdatedUtc { get; set; } +} + +public sealed class UpdaterDownloadFailureState +{ + public string Version { get; set; } = ""; + public string ExpectedHash { get; set; } = ""; + public string Url { get; set; } = ""; + public string FailureClass { get; set; } = ""; + public int AttemptCount { get; set; } + public DateTime LastFailureUtc { get; set; } + public DateTime NextAttemptUtc { get; set; } +} + +public readonly record struct UpdaterDownloadResult( + string PartialPath, + long BytesInPartialFile, + long? TotalBytes, + HttpStatusCode StatusCode, + bool Resumed +); + +public static class UpdaterDownloadEngine +{ + public static readonly TimeSpan DefaultAutomaticUpdateCheckInterval = TimeSpan.FromMinutes(60); + + private const int CopyBufferSize = 81920; + private const string PartialMarker = ".part"; + private const string MetadataSuffix = ".json"; + private const string FailureStateSuffix = ".download-failed.json"; + private static readonly TimeSpan BaseFailureBackoff = TimeSpan.FromMinutes(60); + private static readonly TimeSpan MaxFailureBackoff = TimeSpan.FromHours(24); + private const double MaxJitterRatio = 0.20; + + public static string GetPartialPath(string destinationPath) + { + string? directory = Path.GetDirectoryName(destinationPath); + string fileName = Path.GetFileName(destinationPath); + string extension = Path.GetExtension(fileName); + string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(fileName); + string partialFileName = $"{fileNameWithoutExtension}{PartialMarker}{extension}"; + return string.IsNullOrEmpty(directory) + ? partialFileName + : Path.Join(directory, partialFileName); + } + + public static string GetPartialMetadataPath(string destinationPath) + { + return GetPartialPath(destinationPath) + MetadataSuffix; + } + + public static string GetFailureStatePath(string destinationPath) + { + return destinationPath + FailureStateSuffix; + } + + public static async Task DownloadInstallerPartAsync( + HttpClient client, + UpdaterDownloadIdentity identity, + string destinationPath, + Action? log = null, + CancellationToken cancellationToken = default + ) + { + return await DownloadInstallerPartAsync( + client, + identity, + destinationPath, + allowRestart: true, + log, + cancellationToken + ); + } + + private static async Task DownloadInstallerPartAsync( + HttpClient client, + UpdaterDownloadIdentity identity, + string destinationPath, + bool allowRestart, + Action? log, + CancellationToken cancellationToken + ) + { + string partialPath = GetPartialPath(destinationPath); + string metadataPath = GetPartialMetadataPath(destinationPath); + Directory.CreateDirectory(Path.GetDirectoryName(partialPath) ?? "."); + + UpdaterInstallerDownloadMetadata? metadata = TryReadMetadata(metadataPath, log); + bool canUsePartial = IsCompatible(metadata, identity); + if (!canUsePartial) + { + DeletePartialDownload(destinationPath, log); + metadata = null; + } + + long partialLength = File.Exists(partialPath) ? new FileInfo(partialPath).Length : 0; + if (metadata?.TotalLength is > 0 && partialLength > metadata.TotalLength.Value) + { + log?.Invoke( + $"Partial updater download is larger than expected ({partialLength}>{metadata.TotalLength}); restarting." + ); + DeletePartialDownload(destinationPath, log); + metadata = null; + partialLength = 0; + } + + if (metadata?.TotalLength is > 0 && partialLength == metadata.TotalLength.Value) + { + log?.Invoke( + $"Partial updater download is already complete ({partialLength} bytes); validating cached partial." + ); + return new UpdaterDownloadResult( + partialPath, + partialLength, + metadata.TotalLength, + HttpStatusCode.NotModified, + Resumed: false + ); + } + + RangeHeaderValue? range = null; + RangeConditionHeaderValue? ifRange = null; + bool requestResume = partialLength > 0 && TryConfigureResume(metadata, partialLength, out range, out ifRange); + if (partialLength > 0 && !requestResume) + { + log?.Invoke("Partial updater download cannot be resumed safely; restarting."); + DeletePartialDownload(destinationPath, log); + metadata = null; + partialLength = 0; + } + + using HttpRequestMessage request = new(HttpMethod.Get, identity.Url); + if (requestResume) + { + request.Headers.Range = range!; + request.Headers.IfRange = ifRange; + log?.Invoke($"Resuming updater download from byte {partialLength}."); + } + + using HttpResponseMessage response = await client.SendAsync( + request, + HttpCompletionOption.ResponseHeadersRead, + cancellationToken + ); + + if (response.StatusCode is HttpStatusCode.RequestedRangeNotSatisfiable && allowRestart) + { + log?.Invoke("Updater download range was not satisfiable; restarting from byte 0."); + DeletePartialDownload(destinationPath, log); + return await DownloadInstallerPartAsync( + client, + identity, + destinationPath, + allowRestart: false, + log, + cancellationToken + ); + } + + response.EnsureSuccessStatusCode(); + + bool appendToPartial = response.StatusCode is HttpStatusCode.PartialContent; + if (appendToPartial && !IsValidPartialResponse(response, partialLength)) + { + if (!allowRestart) + { + throw new InvalidDataException( + "The updater download server returned an invalid partial content range." + ); + } + + log?.Invoke("Updater download returned an invalid partial response; restarting."); + DeletePartialDownload(destinationPath, log); + return await DownloadInstallerPartAsync( + client, + identity, + destinationPath, + allowRestart: false, + log, + cancellationToken + ); + } + + if (appendToPartial && !IsResumeValidatorCompatible(metadata, response)) + { + if (!allowRestart) + { + throw new InvalidDataException( + "The updater download server returned partial content with a changed validator." + ); + } + + log?.Invoke("Updater download validator changed during resume; restarting."); + DeletePartialDownload(destinationPath, log); + return await DownloadInstallerPartAsync( + client, + identity, + destinationPath, + allowRestart: false, + log, + cancellationToken + ); + } + + if (!appendToPartial && partialLength > 0) + { + log?.Invoke("Updater download server ignored Range; restarting from byte 0."); + partialLength = 0; + } + + UpdaterInstallerDownloadMetadata newMetadata = CreateMetadata( + identity, + response, + appendToPartial + ); + WriteMetadata(metadataPath, newMetadata, log); + + FileMode fileMode = appendToPartial ? FileMode.Append : FileMode.Create; + await using (FileStream fileStream = new( + partialPath, + fileMode, + FileAccess.Write, + FileShare.Read, + CopyBufferSize, + useAsync: true + )) + await using (Stream downloadStream = await response.Content.ReadAsStreamAsync(cancellationToken)) + { + await downloadStream.CopyToAsync(fileStream, cancellationToken); + } + + long bytesInPartial = new FileInfo(partialPath).Length; + newMetadata.TotalLength ??= bytesInPartial; + newMetadata.UpdatedUtc = DateTime.UtcNow; + WriteMetadata(metadataPath, newMetadata, log); + + return new UpdaterDownloadResult( + partialPath, + bytesInPartial, + newMetadata.TotalLength, + response.StatusCode, + Resumed: appendToPartial + ); + } + + public static void PromotePartialDownload(string destinationPath, Action? log = null) + { + string partialPath = GetPartialPath(destinationPath); + if (!File.Exists(partialPath)) + { + throw new FileNotFoundException("The completed updater partial file was not found.", partialPath); + } + + File.Move(partialPath, destinationPath, overwrite: true); + DeleteFileIfExists(GetPartialMetadataPath(destinationPath), log); + } + + public static void DeletePartialDownload(string destinationPath, Action? log = null) + { + DeleteFileIfExists(GetPartialPath(destinationPath), log); + DeleteFileIfExists(GetPartialMetadataPath(destinationPath), log); + } + + public static bool IsFailureBackoffActive( + string statePath, + UpdaterDownloadIdentity identity, + DateTime utcNow, + out TimeSpan remaining, + out UpdaterDownloadFailureState? state, + Action? log = null + ) + { + remaining = TimeSpan.Zero; + state = TryReadFailureState(statePath, log); + if (state is null || !IsCompatible(state, identity)) + { + return false; + } + + remaining = state.NextAttemptUtc - utcNow; + if (remaining <= TimeSpan.Zero) + { + return false; + } + + if (remaining > MaxFailureBackoff + TimeSpan.FromHours(1)) + { + log?.Invoke( + $"Ignoring updater download backoff with unexpected future timestamp ({state.NextAttemptUtc:O})." + ); + return false; + } + + return true; + } + + public static void RecordFailure( + string statePath, + UpdaterDownloadIdentity identity, + string failureClass, + DateTime utcNow, + Action? log = null + ) + { + try + { + UpdaterDownloadFailureState? previous = TryReadFailureState(statePath, log); + int attemptCount = previous is not null + && IsCompatible(previous, identity) + && string.Equals( + previous.FailureClass, + failureClass, + StringComparison.OrdinalIgnoreCase + ) + ? previous.AttemptCount + 1 + : 1; + TimeSpan delay = CalculateFailureBackoff(identity, failureClass, attemptCount); + UpdaterDownloadFailureState state = new() + { + Version = identity.Version, + ExpectedHash = identity.ExpectedHash, + Url = identity.Url, + FailureClass = failureClass, + AttemptCount = attemptCount, + LastFailureUtc = utcNow, + NextAttemptUtc = utcNow + delay, + }; + + string? directory = Path.GetDirectoryName(statePath); + if (!string.IsNullOrEmpty(directory)) + { + Directory.CreateDirectory(directory); + } + + WriteFailureState(statePath, state); + log?.Invoke( + string.Format( + CultureInfo.InvariantCulture, + "Recorded updater download failure '{0}' attempt {1}; next automatic attempt after {2:O}.", + failureClass, + attemptCount, + state.NextAttemptUtc + ) + ); + } + catch (Exception ex) + { + Logger.Warn($"Could not record updater download failure state: {ex.Message}"); + } + } + + public static void ClearFailureState(string statePath, Action? log = null) + { + DeleteFileIfExists(statePath, log); + } + + public static TimeSpan CalculateFailureBackoff( + UpdaterDownloadIdentity identity, + string failureClass, + int attemptCount + ) + { + if (attemptCount < 1) + { + attemptCount = 1; + } + + int exponent = Math.Min(attemptCount - 1, 10); + double multiplier = Math.Pow(2, exponent); + TimeSpan delay = TimeSpan.FromTicks((long)(BaseFailureBackoff.Ticks * multiplier)); + if (delay > MaxFailureBackoff) + { + delay = MaxFailureBackoff; + } + + double jitterRatio = GetStableJitterRatio(identity, failureClass, attemptCount); + TimeSpan jitter = TimeSpan.FromTicks((long)(delay.Ticks * jitterRatio)); + TimeSpan jitteredDelay = delay + jitter; + return jitteredDelay > MaxFailureBackoff ? MaxFailureBackoff : jitteredDelay; + } + + private static bool TryConfigureResume( + UpdaterInstallerDownloadMetadata? metadata, + long partialLength, + out RangeHeaderValue range, + out RangeConditionHeaderValue? ifRange + ) + { + range = new RangeHeaderValue(partialLength, null); + ifRange = null; + if (metadata is null) + { + return false; + } + + if ( + !string.IsNullOrWhiteSpace(metadata.ETag) + && EntityTagHeaderValue.TryParse(metadata.ETag, out EntityTagHeaderValue? entityTag) + ) + { + ifRange = new RangeConditionHeaderValue(entityTag); + return true; + } + + if (metadata.LastModified is not null) + { + ifRange = new RangeConditionHeaderValue(metadata.LastModified.Value); + return true; + } + + return false; + } + + private static bool IsValidPartialResponse(HttpResponseMessage response, long expectedStart) + { + ContentRangeHeaderValue? contentRange = response.Content.Headers.ContentRange; + return contentRange?.From == expectedStart; + } + + private static bool IsResumeValidatorCompatible( + UpdaterInstallerDownloadMetadata? metadata, + HttpResponseMessage response + ) + { + if (metadata is null) + { + return true; + } + + if (!string.IsNullOrWhiteSpace(metadata.ETag) && response.Headers.ETag is not null) + { + return string.Equals( + metadata.ETag, + response.Headers.ETag.ToString(), + StringComparison.Ordinal + ); + } + + if (metadata.LastModified is not null && response.Content.Headers.LastModified is not null) + { + return metadata.LastModified.Value.Equals(response.Content.Headers.LastModified.Value); + } + + return true; + } + + private static UpdaterInstallerDownloadMetadata CreateMetadata( + UpdaterDownloadIdentity identity, + HttpResponseMessage response, + bool partialResponse + ) + { + long? totalLength = partialResponse + ? response.Content.Headers.ContentRange?.Length + : response.Content.Headers.ContentLength; + return new UpdaterInstallerDownloadMetadata + { + Version = identity.Version, + ExpectedHash = identity.ExpectedHash, + Url = identity.Url, + ETag = response.Headers.ETag?.ToString() ?? "", + LastModified = response.Content.Headers.LastModified, + TotalLength = totalLength, + UpdatedUtc = DateTime.UtcNow, + }; + } + + private static bool IsCompatible( + UpdaterInstallerDownloadMetadata? metadata, + UpdaterDownloadIdentity identity + ) + { + return metadata is not null + && string.Equals(metadata.Version, identity.Version, StringComparison.OrdinalIgnoreCase) + && string.Equals( + metadata.ExpectedHash, + identity.ExpectedHash, + StringComparison.OrdinalIgnoreCase + ) + && string.Equals(metadata.Url, identity.Url, StringComparison.Ordinal); + } + + private static bool IsCompatible( + UpdaterDownloadFailureState state, + UpdaterDownloadIdentity identity + ) + { + return string.Equals(state.Version, identity.Version, StringComparison.OrdinalIgnoreCase) + && string.Equals( + state.ExpectedHash, + identity.ExpectedHash, + StringComparison.OrdinalIgnoreCase + ) + && string.Equals(state.Url, identity.Url, StringComparison.Ordinal); + } + + private static UpdaterInstallerDownloadMetadata? TryReadMetadata( + string metadataPath, + Action? log + ) + { + if (!File.Exists(metadataPath)) + { + return null; + } + + try + { + return DeserializeJson( + File.ReadAllText(metadataPath), + UpdaterDownloadJsonContext.Default.UpdaterInstallerDownloadMetadata + ); + } + catch (Exception ex) + { + log?.Invoke($"Could not read updater partial metadata; restarting download: {ex.Message}"); + return null; + } + } + + private static UpdaterDownloadFailureState? TryReadFailureState( + string statePath, + Action? log + ) + { + if (!File.Exists(statePath)) + { + return null; + } + + try + { + return DeserializeJson( + File.ReadAllText(statePath), + UpdaterDownloadJsonContext.Default.UpdaterDownloadFailureState + ); + } + catch (Exception ex) + { + log?.Invoke($"Ignoring unreadable updater download failure state: {ex.Message}"); + return null; + } + } + + private static void WriteMetadata( + string metadataPath, + UpdaterInstallerDownloadMetadata metadata, + Action? log + ) + { + try + { + WriteJsonFile( + metadataPath, + SerializeJson( + metadata, + UpdaterDownloadJsonContext.Default.UpdaterInstallerDownloadMetadata + ) + ); + } + catch (Exception ex) + { + log?.Invoke($"Could not write updater partial metadata: {ex.Message}"); + throw; + } + } + + private static void WriteFailureState(string statePath, UpdaterDownloadFailureState state) + { + WriteJsonFile( + statePath, + SerializeJson( + state, + UpdaterDownloadJsonContext.Default.UpdaterDownloadFailureState + ) + ); + } + + private static T? DeserializeJson(string json, JsonTypeInfo typeInfo) + { + return JsonSerializer.Deserialize(json, typeInfo); + } + + private static string SerializeJson(T value, JsonTypeInfo typeInfo) + { + return JsonSerializer.Serialize(value, typeInfo); + } + + private static void WriteJsonFile(string path, string json) + { + string temporaryPath = path + ".tmp"; + File.WriteAllText(temporaryPath, json); + File.Move(temporaryPath, path, overwrite: true); + } + + private static void DeleteFileIfExists(string path, Action? log) + { + if (!File.Exists(path)) + { + return; + } + + try + { + File.Delete(path); + } + catch (Exception ex) + { + log?.Invoke($"Could not delete '{path}': {ex.Message}"); + } + } + + private static double GetStableJitterRatio( + UpdaterDownloadIdentity identity, + string failureClass, + int attemptCount + ) + { + string key = + $"{identity.Version}|{identity.ExpectedHash}|{identity.Url}|{failureClass}|{attemptCount}"; + byte[] hash = SHA256.HashData(Encoding.UTF8.GetBytes(key)); + ushort value = BinaryPrimitives.ReadUInt16LittleEndian(hash); + return value / (double)ushort.MaxValue * MaxJitterRatio; + } +} + +[JsonSourceGenerationOptions(AllowTrailingCommas = true, WriteIndented = true)] +[JsonSerializable(typeof(UpdaterInstallerDownloadMetadata))] +[JsonSerializable(typeof(UpdaterDownloadFailureState))] +internal sealed partial class UpdaterDownloadJsonContext : JsonSerializerContext; diff --git a/src/UniGetUI.Interface.Enums/Enums.cs b/src/UniGetUI.Interface.Enums/Enums.cs new file mode 100644 index 0000000..09e25a4 --- /dev/null +++ b/src/UniGetUI.Interface.Enums/Enums.cs @@ -0,0 +1,123 @@ +namespace UniGetUI.Interface.Enums +{ + /// + /// Represents the visual status of a package on a list + /// + public enum PackageTag + { + Default, + AlreadyInstalled, + IsUpgradable, + Pinned, + OnQueue, + BeingProcessed, + Failed, + Unavailable, + } + + public enum IconType + { + AddTo = '\uE900', + Android = '\uE901', + Backward = '\uE902', + Bucket = '\uE903', + Buggy = '\uE904', + Checksum = '\uE905', + Chocolatey = '\uE906', + ClipboardList = '\uE907', + Close_Round = '\uE908', + Collapse = '\uE909', + Console = '\uE90A', + Copy = '\uE90B', + Cross = '\uE90C', + Delete = '\uE90D', + Disk = '\uE90E', + DotNet = '\uE90F', + Download = '\uE910', + Empty = '\uE911', + Expand = '\uE912', + Experimental = '\uE913', + Forward = '\uE914', + GOG = '\uE915', + Help = '\uE916', + History = '\uE917', + Home = '\uE918', + Id = '\uE919', + Info_Round = '\uE91A', + Installed = '\uE91B', + Installed_Filled = '\uE91C', + Interactive = '\uE91D', + Launch = '\uE91E', + Loading = '\uE91F', + Loading_Filled = '\uE920', + LocalPc = '\uE921', + Megaphone = '\uE922', + MsStore = '\uE923', + Node = '\uE924', + OpenFolder = '\uE925', + Options = '\uE926', + Package = '\uE927', + Pin = '\uE928', + Pin_Filled = '\uE929', + PowerShell = '\uE92A', + Python = '\uE92B', + Reload = '\uE92C', + SandClock = '\uE92D', + SaveAs = '\uE92E', + Scoop = '\uE92F', + Search = '\uE930', + Settings = '\uE931', + Share = '\uE932', + Skip = '\uE933', + Steam = '\uE934', + SysTray = '\uE935', + UAC = '\uE936', + Undelete = '\uE937', + Update = '\uE938', + Upgradable = '\uE939', + Upgradable_Filled = '\uE93A', + UPlay = '\uE93B', + Version = '\uE93C', + Warning = '\uE93D', + Warning_Filled = '\uE93E', + Warning_Round = '\uE93F', + WinGet = '\uE940', + Rust = '\uE941', + Vcpkg = '\uE942', + Homebrew = '\uE943', + Apt = '\uE944', + Dnf = '\uE945', + Pacman = '\uE946', + Snap = '\uE947', + Flatpak = '\uE948', + Bun = '\uE949', + } + + public class NotificationArguments + { + public const string Show = "openUniGetUI"; + public const string ShowOnUpdatesTab = "openUniGetUIOnUpdatesTab"; + public const string UpdateAllPackages = "updateAll"; + public const string ReleaseSelfUpdateLock = "releaseSelfUpdateLock"; + } + + public struct BundleReportEntry + { + public readonly string Line; + public readonly bool Allowed; + + public BundleReportEntry(string line, bool allowed) + { + Line = line; + Allowed = allowed; + } + } + + public struct BundleReport + { + public bool IsEmpty = false; + public Dictionary> Contents = new(); + + public BundleReport() { } + } +} diff --git a/src/UniGetUI.Interface.Enums/UniGetUI.Interface.Enums.csproj b/src/UniGetUI.Interface.Enums/UniGetUI.Interface.Enums.csproj new file mode 100644 index 0000000..3b1ea6e --- /dev/null +++ b/src/UniGetUI.Interface.Enums/UniGetUI.Interface.Enums.csproj @@ -0,0 +1,9 @@ + + + $(SharedTargetFrameworks) + + + + + + diff --git a/src/UniGetUI.Interface.IpcApi/GitHubApiClient.cs b/src/UniGetUI.Interface.IpcApi/GitHubApiClient.cs new file mode 100644 index 0000000..8c64bd8 --- /dev/null +++ b/src/UniGetUI.Interface.IpcApi/GitHubApiClient.cs @@ -0,0 +1,393 @@ +using System.Net.Http.Headers; +using System.Text.Json; +using System.Text.Json.Serialization; +using System.Text.Json.Serialization.Metadata; +using UniGetUI.Core.Data; +using UniGetUI.Core.Tools; + +namespace UniGetUI.Interface; + +public sealed class GitHubApiClient : IDisposable +{ + private static readonly Uri GitHubBaseUri = new("https://github.com/"); + private static readonly Uri GitHubApiBaseUri = new("https://api.github.com/"); + private readonly HttpClient _httpClient; + + public GitHubApiClient(string? token = null) + { + _httpClient = new HttpClient(CoreTools.GenericHttpClientParameters) + { + BaseAddress = GitHubApiBaseUri, + }; + _httpClient.DefaultRequestHeaders.UserAgent.ParseAdd(CoreData.UserAgentString); + _httpClient.DefaultRequestHeaders.Accept.ParseAdd("application/vnd.github+json"); + _httpClient.DefaultRequestHeaders.Add("X-GitHub-Api-Version", "2022-11-28"); + + if (!string.IsNullOrWhiteSpace(token)) + { + _httpClient.DefaultRequestHeaders.Authorization = + new AuthenticationHeaderValue("Bearer", token); + } + } + + public static Uri GetOAuthLoginUrl( + string clientId, + Uri redirectUri, + IEnumerable scopes + ) + { + string query = BuildQueryString( + new Dictionary + { + ["client_id"] = clientId, + ["redirect_uri"] = redirectUri.ToString(), + ["scope"] = string.Join(' ', scopes), + } + ); + return new Uri(GitHubBaseUri, "login/oauth/authorize" + query); + } + + public Task CreateAccessTokenAsync( + string clientId, + string clientSecret, + string code, + Uri redirectUri + ) + { + return PostOAuthFormAsync( + "login/oauth/access_token", + new Dictionary + { + ["client_id"] = clientId, + ["client_secret"] = clientSecret, + ["code"] = code, + ["redirect_uri"] = redirectUri.ToString(), + }, + GitHubJsonContext.Default.GitHubOAuthToken + ); + } + + public Task InitiateDeviceFlowAsync( + string clientId, + IEnumerable scopes, + CancellationToken cancellationToken = default + ) + { + return PostOAuthFormAsync( + "login/device/code", + new Dictionary + { + ["client_id"] = clientId, + ["scope"] = string.Join(' ', scopes), + }, + GitHubJsonContext.Default.GitHubDeviceFlow, + cancellationToken + ); + } + + public Task CreateAccessTokenForDeviceFlowAsync( + string clientId, + GitHubDeviceFlow deviceFlow, + CancellationToken cancellationToken = default + ) + { + return PostOAuthFormAsync( + "login/oauth/access_token", + new Dictionary + { + ["client_id"] = clientId, + ["device_code"] = deviceFlow.DeviceCode, + ["grant_type"] = "urn:ietf:params:oauth:grant-type:device_code", + }, + GitHubJsonContext.Default.GitHubOAuthToken, + cancellationToken + ); + } + + public Task GetCurrentUserAsync(CancellationToken cancellationToken = default) + { + return GetJsonAsync("user", GitHubJsonContext.Default.GitHubUser, cancellationToken); + } + + public Task> GetCurrentUserGistsAsync( + CancellationToken cancellationToken = default + ) + { + return GetJsonAsync( + "gists", + GitHubJsonContext.Default.IReadOnlyListGitHubGist, + cancellationToken + ); + } + + public Task GetGistAsync(string gistId, CancellationToken cancellationToken = default) + { + return GetJsonAsync( + "gists/" + Uri.EscapeDataString(gistId), + GitHubJsonContext.Default.GitHubGist, + cancellationToken + ); + } + + public Task CreateGistAsync( + string description, + bool isPublic, + IReadOnlyDictionary files, + CancellationToken cancellationToken = default + ) + { + return SendGistAsync( + HttpMethod.Post, + "gists", + description, + isPublic, + files, + cancellationToken + ); + } + + public Task EditGistAsync( + string gistId, + string description, + IReadOnlyDictionary files, + CancellationToken cancellationToken = default + ) + { + return SendGistAsync( + HttpMethod.Patch, + "gists/" + Uri.EscapeDataString(gistId), + description, + isPublic: false, + files, + cancellationToken + ); + } + + private async Task SendGistAsync( + HttpMethod method, + string relativeUri, + string description, + bool isPublic, + IReadOnlyDictionary files, + CancellationToken cancellationToken + ) + { + var request = new GitHubGistRequest + { + Description = description, + IsPublic = method == HttpMethod.Post ? isPublic : null, + Files = files.ToDictionary( + file => file.Key, + file => new GitHubGistFileRequest { Content = file.Value }, + StringComparer.Ordinal + ), + }; + + using var message = new HttpRequestMessage(method, relativeUri) + { + Content = CreateJsonContent(request, GitHubJsonContext.Default.GitHubGistRequest), + }; + return await SendAsync(message, GitHubJsonContext.Default.GitHubGist, cancellationToken); + } + + private async Task GetJsonAsync( + string relativeUri, + JsonTypeInfo typeInfo, + CancellationToken cancellationToken + ) + { + using var message = new HttpRequestMessage(HttpMethod.Get, relativeUri); + return await SendAsync(message, typeInfo, cancellationToken); + } + + private async Task PostOAuthFormAsync( + string relativeUri, + IReadOnlyDictionary values, + JsonTypeInfo typeInfo, + CancellationToken cancellationToken = default + ) + { + using var message = new HttpRequestMessage(HttpMethod.Post, new Uri(GitHubBaseUri, relativeUri)) + { + Content = new FormUrlEncodedContent( + values + .Where(value => !string.IsNullOrWhiteSpace(value.Value)) + .Select(value => new KeyValuePair(value.Key, value.Value!)) + ), + }; + message.Headers.Accept.Clear(); + message.Headers.Accept.ParseAdd("application/json"); + return await SendAsync(message, typeInfo, cancellationToken); + } + + private async Task SendAsync( + HttpRequestMessage message, + JsonTypeInfo typeInfo, + CancellationToken cancellationToken + ) + { + using HttpResponseMessage response = await _httpClient.SendAsync(message, cancellationToken); + string content = await response.Content.ReadAsStringAsync(cancellationToken); + if (!response.IsSuccessStatusCode) + { + throw new HttpRequestException( + $"GitHub request failed with HTTP {(int)response.StatusCode} ({response.ReasonPhrase}): {GetErrorMessage(content)}" + ); + } + + return JsonSerializer.Deserialize(content, typeInfo) + ?? throw new InvalidOperationException("GitHub returned an empty response."); + } + + private static StringContent CreateJsonContent(T value, JsonTypeInfo typeInfo) + { + return new StringContent( + JsonSerializer.Serialize(value, typeInfo), + System.Text.Encoding.UTF8, + "application/json" + ); + } + + private static string GetErrorMessage(string content) + { + if (string.IsNullOrWhiteSpace(content)) + return "No response body."; + + try + { + GitHubError? error = JsonSerializer.Deserialize( + content, + GitHubJsonContext.Default.GitHubError + ); + if (!string.IsNullOrWhiteSpace(error?.ErrorDescription)) + return error.ErrorDescription; + if (!string.IsNullOrWhiteSpace(error?.Error)) + return error.Error; + if (!string.IsNullOrWhiteSpace(error?.Message)) + return error.Message; + } + catch (JsonException) + { + return content; + } + + return content; + } + + private static string BuildQueryString(IReadOnlyDictionary values) + { + string query = string.Join( + '&', + values + .Where(value => !string.IsNullOrWhiteSpace(value.Value)) + .Select(value => + Uri.EscapeDataString(value.Key) + "=" + Uri.EscapeDataString(value.Value!)) + ); + return string.IsNullOrEmpty(query) ? "" : "?" + query; + } + + public void Dispose() + { + _httpClient.Dispose(); + } +} + +public sealed class GitHubOAuthToken +{ + [JsonPropertyName("access_token")] + public string AccessToken { get; set; } = ""; +} + +public sealed class GitHubDeviceFlow +{ + [JsonPropertyName("device_code")] + public string DeviceCode { get; set; } = ""; + + [JsonPropertyName("user_code")] + public string UserCode { get; set; } = ""; + + [JsonPropertyName("verification_uri")] + public string VerificationUri { get; set; } = ""; + + [JsonPropertyName("expires_in")] + public int ExpiresIn { get; set; } + + [JsonPropertyName("interval")] + public int Interval { get; set; } +} + +public sealed class GitHubUser +{ + [JsonPropertyName("login")] + public string Login { get; set; } = ""; + + [JsonPropertyName("name")] + public string? Name { get; set; } + + [JsonPropertyName("avatar_url")] + public string? AvatarUrl { get; set; } +} + +public sealed class GitHubGist +{ + [JsonPropertyName("id")] + public string Id { get; set; } = ""; + + [JsonPropertyName("description")] + public string? Description { get; set; } + + [JsonPropertyName("files")] + public Dictionary Files { get; set; } = []; +} + +public sealed class GitHubGistFile +{ + [JsonPropertyName("size")] + public long Size { get; set; } + + [JsonPropertyName("content")] + public string? Content { get; set; } +} + +internal sealed class GitHubGistRequest +{ + [JsonPropertyName("description")] + public string Description { get; set; } = ""; + + [JsonPropertyName("public")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public bool? IsPublic { get; set; } + + [JsonPropertyName("files")] + public Dictionary Files { get; set; } = []; +} + +internal sealed class GitHubGistFileRequest +{ + [JsonPropertyName("content")] + public string Content { get; set; } = ""; +} + +internal sealed class GitHubError +{ + [JsonPropertyName("message")] + public string? Message { get; set; } + + [JsonPropertyName("error")] + public string? Error { get; set; } + + [JsonPropertyName("error_description")] + public string? ErrorDescription { get; set; } +} + +[JsonSourceGenerationOptions] +[JsonSerializable(typeof(GitHubOAuthToken))] +[JsonSerializable(typeof(GitHubDeviceFlow))] +[JsonSerializable(typeof(GitHubUser))] +[JsonSerializable(typeof(GitHubGist))] +[JsonSerializable(typeof(GitHubGistFile))] +[JsonSerializable(typeof(GitHubGistRequest))] +[JsonSerializable(typeof(GitHubGistFileRequest))] +[JsonSerializable(typeof(GitHubError))] +[JsonSerializable(typeof(IReadOnlyList))] +internal sealed partial class GitHubJsonContext : JsonSerializerContext; diff --git a/src/UniGetUI.Interface.IpcApi/HeadlessIpcHost.cs b/src/UniGetUI.Interface.IpcApi/HeadlessIpcHost.cs new file mode 100644 index 0000000..212169c --- /dev/null +++ b/src/UniGetUI.Interface.IpcApi/HeadlessIpcHost.cs @@ -0,0 +1,112 @@ +using UniGetUI.Core.Logging; + +namespace UniGetUI.Interface; + +public static class HeadlessIpcHost +{ + public static async Task RunAsync(Func initializeAsync, string hostName = "UniGetUI") + { + ArgumentNullException.ThrowIfNull(initializeAsync); + + IpcServer? backgroundApi = null; + using var shutdown = new CancellationTokenSource(); + + void RequestShutdown() + { + if (!shutdown.IsCancellationRequested) + { + shutdown.Cancel(); + } + } + + ConsoleCancelEventHandler cancelHandler = (_, eventArgs) => + { + eventArgs.Cancel = true; + RequestShutdown(); + }; + Console.CancelKeyPress += cancelHandler; + + EventHandler processExitHandler = (_, _) => RequestShutdown(); + AppDomain.CurrentDomain.ProcessExit += processExitHandler; + + try + { + Logger.Info($"Starting {hostName} headless daemon"); + + await initializeAsync(); + + backgroundApi = CreateIpcServer(RequestShutdown); + await backgroundApi.Start(); + + Logger.Info($"{hostName} headless daemon is ready"); + await WaitForShutdownAsync(shutdown.Token); + return 0; + } + catch (Exception ex) + { + Logger.Error($"{hostName} headless daemon failed to start"); + Logger.Error(ex); + return ex.HResult != 0 ? ex.HResult : 1; + } + finally + { + AppDomain.CurrentDomain.ProcessExit -= processExitHandler; + Console.CancelKeyPress -= cancelHandler; + + if (backgroundApi is not null) + { + await backgroundApi.Stop(); + } + } + } + + private static IpcServer CreateIpcServer(Action requestShutdown) + { + var backgroundApi = new IpcServer + { + SessionKind = IpcTransportOptions.HeadlessSessionKind, + }; + backgroundApi.AppInfoProvider = () => + new IpcAppInfo + { + Headless = true, + WindowAvailable = false, + WindowVisible = false, + CanShowWindow = false, + CanNavigate = false, + CanQuit = true, + SupportedPages = IpcAppPages.SupportedPages, + }; + backgroundApi.ShowAppHandler = () => + throw new InvalidOperationException( + "The current UniGetUI session is running headless and has no window to show." + ); + backgroundApi.NavigateAppHandler = _ => + throw new InvalidOperationException( + "The current UniGetUI session is running headless and cannot navigate UI pages." + ); + backgroundApi.QuitAppHandler = () => + { + _ = Task.Run(async () => + { + await Task.Delay(150); + requestShutdown(); + }); + return IpcCommandResult.Success("quit-app"); + }; + + return backgroundApi; + } + + private static Task WaitForShutdownAsync(CancellationToken cancellationToken) + { + if (cancellationToken.IsCancellationRequested) + { + return Task.CompletedTask; + } + + var completion = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + cancellationToken.Register(() => completion.TrySetResult()); + return completion.Task; + } +} diff --git a/src/UniGetUI.Interface.IpcApi/InternalsVisibleTo.cs b/src/UniGetUI.Interface.IpcApi/InternalsVisibleTo.cs new file mode 100644 index 0000000..f5236ec --- /dev/null +++ b/src/UniGetUI.Interface.IpcApi/InternalsVisibleTo.cs @@ -0,0 +1,3 @@ +using System.Runtime.CompilerServices; + +[assembly: InternalsVisibleTo("UniGetUI.Tests")] diff --git a/src/UniGetUI.Interface.IpcApi/IpcAppApi.cs b/src/UniGetUI.Interface.IpcApi/IpcAppApi.cs new file mode 100644 index 0000000..05ea7b5 --- /dev/null +++ b/src/UniGetUI.Interface.IpcApi/IpcAppApi.cs @@ -0,0 +1,89 @@ +namespace UniGetUI.Interface; + +public sealed class IpcAppInfo +{ + public bool Headless { get; set; } + public bool WindowAvailable { get; set; } + public bool WindowVisible { get; set; } + public bool CanShowWindow { get; set; } + public bool CanNavigate { get; set; } + public bool CanQuit { get; set; } + public string CurrentPage { get; set; } = ""; + public IReadOnlyList SupportedPages { get; set; } = IpcAppPages.SupportedPages; +} + +public sealed class IpcAppNavigateRequest +{ + public string Page { get; set; } = ""; + public string? ManagerName { get; set; } + public string? HelpAttachment { get; set; } +} + +public static class IpcAppPages +{ + public static readonly IReadOnlyList SupportedPages = + [ + "discover", + "updates", + "installed", + "bundles", + "settings", + "managers", + "own-log", + "manager-log", + "operation-history", + "help", + "release-notes", + "about", + ]; + + public static string NormalizePageName(string page) + { + ArgumentException.ThrowIfNullOrWhiteSpace(page); + + string normalized = page.Trim().ToLowerInvariant(); + return normalized switch + { + "discover" => normalized, + "updates" => normalized, + "installed" => normalized, + "bundles" => normalized, + "settings" => normalized, + "managers" => normalized, + "own-log" => normalized, + "manager-log" => normalized, + "operation-history" => normalized, + "help" => normalized, + "release-notes" => normalized, + "about" => normalized, + _ => throw new InvalidOperationException( + $"Unsupported page \"{page}\". Supported pages: {string.Join(", ", SupportedPages)}." + ), + }; + } + + public static string ToPageName(string? pageTypeName) + { + if (string.IsNullOrWhiteSpace(pageTypeName)) + { + return ""; + } + + return pageTypeName switch + { + "Discover" => "discover", + "Updates" => "updates", + "Installed" => "installed", + "Bundles" => "bundles", + "Settings" => "settings", + "Managers" => "managers", + "OwnLog" => "own-log", + "ManagerLog" => "manager-log", + "OperationHistory" => "operation-history", + "Help" => "help", + "ReleaseNotes" => "release-notes", + "About" => "about", + _ => pageTypeName.Trim(), + }; + } +} diff --git a/src/UniGetUI.Interface.IpcApi/IpcBackupApi.cs b/src/UniGetUI.Interface.IpcApi/IpcBackupApi.cs new file mode 100644 index 0000000..9a427ae --- /dev/null +++ b/src/UniGetUI.Interface.IpcApi/IpcBackupApi.cs @@ -0,0 +1,585 @@ +using UniGetUI.Core.Data; +using UniGetUI.Core.Logging; +using UniGetUI.Core.SecureSettings; +using UniGetUI.Core.SettingsEngine; +using UniGetUI.Core.Tools; +using UniGetUI.PackageEngine.Interfaces; +using UniGetUI.PackageEngine.PackageLoader; + +namespace UniGetUI.Interface; + +public sealed class IpcGitHubAuthInfo +{ + public bool ClientConfigured { get; set; } + public bool IsAuthenticated { get; set; } + public string? Login { get; set; } + public bool DeviceFlowPending { get; set; } + public string? UserCode { get; set; } + public string? VerificationUri { get; set; } + public DateTimeOffset? ExpiresAt { get; set; } + public int? PollIntervalSeconds { get; set; } +} + +public sealed class IpcBackupStatus +{ + public bool LocalBackupEnabled { get; set; } + public bool CloudBackupEnabled { get; set; } + public string BackupDirectory { get; set; } = ""; + public string? CustomBackupDirectory { get; set; } + public string BackupFileName { get; set; } = ""; + public bool TimestampingEnabled { get; set; } + public string CurrentMachineBackupKey { get; set; } = ""; + public IpcGitHubAuthInfo Auth { get; set; } = new(); +} + +public class IpcBackupCommandResult +{ + public string Status { get; set; } = "success"; + public string Command { get; set; } = ""; + public string? Message { get; set; } +} + +public sealed class IpcLocalBackupResult : IpcBackupCommandResult +{ + public string Path { get; set; } = ""; + public string FileName { get; set; } = ""; + public int PackageCount { get; set; } +} + +public sealed class IpcCloudBackupEntry +{ + public string Key { get; set; } = ""; + public string Display { get; set; } = ""; + public bool IsCurrentMachine { get; set; } +} + +public sealed class IpcCloudBackupUploadResult : IpcBackupCommandResult +{ + public string Key { get; set; } = ""; + public int PackageCount { get; set; } +} + +public sealed class IpcCloudBackupRequest +{ + public string Key { get; set; } = ""; + public bool Append { get; set; } +} + +public sealed class IpcCloudBackupContentResult : IpcBackupCommandResult +{ + public string Key { get; set; } = ""; + public string Content { get; set; } = ""; +} + +public sealed class IpcCloudBackupRestoreResult : IpcBackupCommandResult +{ + public string Key { get; set; } = ""; + public double SchemaVersion { get; set; } + public IpcBundleInfo Bundle { get; set; } = new(); + public IReadOnlyList SecurityReport { get; set; } = []; +} + +public sealed class IpcGitHubDeviceFlowRequest +{ + public bool LaunchBrowser { get; set; } +} + +public sealed class IpcGitHubAuthResult : IpcBackupCommandResult +{ + public IpcGitHubAuthInfo Auth { get; set; } = new(); +} + +public static class IpcBackupApi +{ + private const string MissingClientId = "CLIENT_ID_UNSET"; + private const string GistDescriptionEndingKey = "@[UNIGETUI_BACKUP_V1]"; + private const string PackageBackupStartingKey = "@[PACKAGES]"; + private const string GistDescription = + "UniGetUI package backups - DO NOT RENAME OR MODIFY " + GistDescriptionEndingKey; + private const string ReadMeContents = + "This special Gist is used by UniGetUI to store your package backups.\n" + + "Please DO NOT EDIT the contents or the description of this gist, or unexpected behaviours may occur.\n" + + "Learn more about UniGetUI at https://github.com/Devolutions/UniGetUI\n"; + + private static readonly object GitHubAuthLock = new(); + private static PendingGitHubDeviceFlow? _pendingGitHubDeviceFlow; + + private sealed class PendingGitHubDeviceFlow + { + public required GitHubDeviceFlow DeviceFlow { get; init; } + public required DateTimeOffset ExpiresAtUtc { get; init; } + } + + public static async Task GetStatusAsync() + { + string? customBackupDirectory = Settings.Get(Settings.K.ChangeBackupOutputDirectory) + ? Settings.GetValue(Settings.K.ChangeBackupOutputDirectory) + : null; + string backupFileName = Settings.GetValue(Settings.K.ChangeBackupFileName); + if (string.IsNullOrWhiteSpace(backupFileName)) + { + backupFileName = CoreTools.Translate( + "{pcName} installed packages", + new Dictionary { ["pcName"] = Environment.MachineName } + ); + } + + return new IpcBackupStatus + { + LocalBackupEnabled = Settings.Get(Settings.K.EnablePackageBackup_LOCAL), + CloudBackupEnabled = Settings.Get(Settings.K.EnablePackageBackup_CLOUD), + BackupDirectory = ResolveBackupDirectory(), + CustomBackupDirectory = string.IsNullOrWhiteSpace(customBackupDirectory) + ? null + : customBackupDirectory, + BackupFileName = backupFileName, + TimestampingEnabled = Settings.Get(Settings.K.EnableBackupTimestamping), + CurrentMachineBackupKey = BuildGistFileKey().Split(' ')[^1], + Auth = await GetGitHubAuthInfoAsync(), + }; + } + + public static async Task CreateLocalBackupAsync() + { + var packages = GetInstalledPackagesForBackup(); + string fileName = BuildBackupFileName(); + string outputDirectory = ResolveBackupDirectory(); + Directory.CreateDirectory(outputDirectory); + + string filePath = Path.Combine(outputDirectory, fileName); + string content = await IpcBundleApi.CreateBundleAsync(packages); + await File.WriteAllTextAsync(filePath, content); + + Logger.ImportantInfo("Local backup saved to " + filePath); + return new IpcLocalBackupResult + { + Status = "success", + Command = "create-local-backup", + Path = filePath, + FileName = fileName, + PackageCount = packages.Count, + }; + } + + public static async Task StartGitHubDeviceFlowAsync( + IpcGitHubDeviceFlowRequest? request = null + ) + { + request ??= new IpcGitHubDeviceFlowRequest(); + EnsureGitHubClientConfigured(); + + using var client = CreateAnonymousGitHubClient(); + var deviceFlow = await client.InitiateDeviceFlowAsync( + Secrets.GetGitHubClientId(), + ["read:user", "gist"], + CancellationToken.None + ); + + lock (GitHubAuthLock) + { + _pendingGitHubDeviceFlow = new PendingGitHubDeviceFlow + { + DeviceFlow = deviceFlow, + ExpiresAtUtc = DateTimeOffset.UtcNow.AddSeconds(deviceFlow.ExpiresIn), + }; + } + + if (request.LaunchBrowser) + { + CoreTools.Launch(deviceFlow.VerificationUri); + } + + return new IpcGitHubAuthResult + { + Status = "success", + Command = "start-github-sign-in", + Message = request.LaunchBrowser + ? "GitHub device flow started and the verification page was opened." + : "GitHub device flow started.", + Auth = await GetGitHubAuthInfoAsync(), + }; + } + + public static async Task CompleteGitHubDeviceFlowAsync() + { + EnsureGitHubClientConfigured(); + + PendingGitHubDeviceFlow pending = GetPendingGitHubDeviceFlow(); + if (DateTimeOffset.UtcNow >= pending.ExpiresAtUtc) + { + ClearPendingGitHubDeviceFlow(); + throw new InvalidOperationException( + "The pending GitHub device flow has expired. Start sign-in again." + ); + } + + try + { + using var client = CreateAnonymousGitHubClient(); + var token = await client.CreateAccessTokenForDeviceFlowAsync( + Secrets.GetGitHubClientId(), + pending.DeviceFlow, + CancellationToken.None + ); + + if (string.IsNullOrWhiteSpace(token.AccessToken)) + { + throw new InvalidOperationException("GitHub did not return an access token."); + } + + SecureGHTokenManager.StoreToken(token.AccessToken); + using var userClient = CreateAuthenticatedGitHubClient(token.AccessToken); + var user = await userClient.GetCurrentUserAsync(); + Settings.SetValue(Settings.K.GitHubUserLogin, user.Login ?? string.Empty); + ClearPendingGitHubDeviceFlow(); + + return new IpcGitHubAuthResult + { + Status = "success", + Command = "complete-github-sign-in", + Message = string.IsNullOrWhiteSpace(user.Login) + ? "GitHub sign-in completed." + : $"GitHub sign-in completed for {user.Login}.", + Auth = await GetGitHubAuthInfoAsync(), + }; + } + catch (Exception ex) + { + Logger.Error("An error occurred while completing GitHub device flow sign-in:"); + Logger.Error(ex); + throw new InvalidOperationException( + "GitHub sign-in did not complete successfully. Finish the device authorization and try again." + ); + } + } + + public static async Task SignOutGitHubAsync() + { + Settings.SetValue(Settings.K.GitHubUserLogin, ""); + SecureGHTokenManager.DeleteToken(); + ClearPendingGitHubDeviceFlow(); + + return new IpcGitHubAuthResult + { + Status = "success", + Command = "sign-out-github", + Message = "GitHub sign-out complete.", + Auth = await GetGitHubAuthInfoAsync(), + }; + } + + public static async Task> ListCloudBackupsAsync() + { + using var client = CreateAuthenticatedGitHubClient(); + await GetAuthenticatedGitHubUserAsync(client); + var backupGist = await GetBackupGistAsync(client, createIfMissing: false); + if (backupGist is null) + { + return []; + } + + string currentMachineKey = BuildGistFileKey().Split(' ')[^1]; + return backupGist.Files + .Where(file => file.Key.StartsWith(PackageBackupStartingKey, StringComparison.Ordinal)) + .Select(file => new IpcCloudBackupEntry + { + Key = file.Key.Split(' ')[^1], + Display = file.Key.Split(' ')[^1] + " (" + CoreTools.FormatAsSize(file.Value.Size) + ")", + IsCurrentMachine = file.Key.Split(' ')[^1].Equals( + currentMachineKey, + StringComparison.OrdinalIgnoreCase + ), + }) + .OrderBy(file => file.Key, StringComparer.OrdinalIgnoreCase) + .ToArray(); + } + + public static async Task CreateCloudBackupAsync() + { + var packages = GetInstalledPackagesForBackup(); + string bundleContents = await IpcBundleApi.CreateBundleAsync(packages); + using var client = CreateAuthenticatedGitHubClient(); + await GetAuthenticatedGitHubUserAsync(client); + var backupGist = await GetBackupGistAsync(client, createIfMissing: true) + ?? throw new InvalidOperationException("The GitHub backup gist could not be created."); + + string fileKey = BuildGistFileKey(); + await client.EditGistAsync( + backupGist.Id, + GistDescription, + new Dictionary { [fileKey] = bundleContents } + ); + return new IpcCloudBackupUploadResult + { + Status = "success", + Command = "create-cloud-backup", + Key = fileKey.Split(' ')[^1], + PackageCount = packages.Count, + }; + } + + public static async Task DownloadCloudBackupAsync( + IpcCloudBackupRequest request + ) + { + ArgumentNullException.ThrowIfNull(request); + string key = ValidateBackupKey(request.Key); + string content = await GetCloudBackupContentsAsync(key); + return new IpcCloudBackupContentResult + { + Status = "success", + Command = "download-cloud-backup", + Key = key, + Content = content, + }; + } + + public static async Task RestoreCloudBackupAsync( + IpcCloudBackupRequest request + ) + { + ArgumentNullException.ThrowIfNull(request); + string key = ValidateBackupKey(request.Key); + string content = await GetCloudBackupContentsAsync(key); + var importResult = await IpcBundleApi.ImportBundleAsync( + new IpcBundleImportRequest + { + Content = content, + Format = "ubundle", + Append = request.Append, + } + ); + + return new IpcCloudBackupRestoreResult + { + Status = importResult.Status, + Command = "restore-cloud-backup", + Message = importResult.Message, + Key = key, + SchemaVersion = importResult.SchemaVersion, + Bundle = importResult.Bundle, + SecurityReport = importResult.SecurityReport, + }; + } + + private static IReadOnlyList GetInstalledPackagesForBackup() + { + return InstalledPackagesLoader.Instance?.Packages.ToList() + ?? throw new InvalidOperationException("The installed packages loader is not available."); + } + + private static string ResolveBackupDirectory() + { + string directory = Settings.GetValue(Settings.K.ChangeBackupOutputDirectory); + return string.IsNullOrWhiteSpace(directory) + ? CoreData.UniGetUI_DefaultBackupDirectory + : directory; + } + + private static string BuildBackupFileName() + { + string fileName = Settings.GetValue(Settings.K.ChangeBackupFileName); + if (string.IsNullOrWhiteSpace(fileName)) + { + fileName = CoreTools.Translate( + "{pcName} installed packages", + new Dictionary { ["pcName"] = Environment.MachineName } + ); + } + + if (Settings.Get(Settings.K.EnableBackupTimestamping)) + { + fileName += " " + DateTime.Now.ToString("yyyy-MM-dd HH-mm-ss"); + } + + return fileName + ".ubundle"; + } + + private static async Task GetGitHubAuthInfoAsync() + { + PendingGitHubDeviceFlow? pending; + lock (GitHubAuthLock) + { + pending = _pendingGitHubDeviceFlow; + } + + bool isAuthenticated = !string.IsNullOrWhiteSpace(SecureGHTokenManager.GetToken()); + string login = Settings.GetValue(Settings.K.GitHubUserLogin); + var auth = new IpcGitHubAuthInfo + { + ClientConfigured = HasConfiguredGitHubClient(), + IsAuthenticated = isAuthenticated, + Login = string.IsNullOrWhiteSpace(login) ? null : login, + DeviceFlowPending = pending is not null && DateTimeOffset.UtcNow < pending.ExpiresAtUtc, + UserCode = pending?.DeviceFlow.UserCode, + VerificationUri = pending?.DeviceFlow.VerificationUri, + ExpiresAt = pending?.ExpiresAtUtc, + PollIntervalSeconds = pending?.DeviceFlow.Interval, + }; + + if (pending is not null && DateTimeOffset.UtcNow >= pending.ExpiresAtUtc) + { + ClearPendingGitHubDeviceFlow(); + auth.DeviceFlowPending = false; + auth.UserCode = null; + auth.VerificationUri = null; + auth.ExpiresAt = null; + auth.PollIntervalSeconds = null; + } + + if (!isAuthenticated) + { + return auth; + } + + if (!string.IsNullOrWhiteSpace(auth.Login)) + { + return auth; + } + + try + { + using var client = CreateAuthenticatedGitHubClient(); + var user = await client.GetCurrentUserAsync(); + if (!string.IsNullOrWhiteSpace(user.Login)) + { + Settings.SetValue(Settings.K.GitHubUserLogin, user.Login); + auth.Login = user.Login; + } + } + catch (Exception ex) + { + Logger.Warn(ex); + } + + return auth; + } + + private static bool HasConfiguredGitHubClient() + { + string clientId = Secrets.GetGitHubClientId(); + return !string.IsNullOrWhiteSpace(clientId) + && !string.Equals(clientId, MissingClientId, StringComparison.Ordinal); + } + + private static void EnsureGitHubClientConfigured() + { + if (!HasConfiguredGitHubClient()) + { + throw new InvalidOperationException( + "GitHub sign-in is not configured for this build. UNIGETUI_GITHUB_CLIENT_ID is missing." + ); + } + } + + private static GitHubApiClient CreateAnonymousGitHubClient() + { + return new GitHubApiClient(); + } + + private static GitHubApiClient CreateAuthenticatedGitHubClient(string? token = null) + { + token ??= SecureGHTokenManager.GetToken(); + if (string.IsNullOrWhiteSpace(token)) + { + throw new InvalidOperationException("GitHub authentication is required for cloud backups."); + } + + return new GitHubApiClient(token); + } + + private static async Task GetAuthenticatedGitHubUserAsync(GitHubApiClient client) + { + var user = await client.GetCurrentUserAsync(); + if (!string.IsNullOrWhiteSpace(user.Login)) + { + Settings.SetValue(Settings.K.GitHubUserLogin, user.Login); + } + + return user; + } + + private static async Task GetCloudBackupContentsAsync(string key) + { + using var client = CreateAuthenticatedGitHubClient(); + await GetAuthenticatedGitHubUserAsync(client); + var backupGist = await GetBackupGistAsync(client, createIfMissing: false); + if (backupGist is null) + { + throw new InvalidOperationException("No cloud backups are available for the current account."); + } + + var fullGist = await client.GetGistAsync(backupGist.Id); + var file = fullGist.Files.FirstOrDefault(candidate => + candidate.Key.StartsWith(PackageBackupStartingKey, StringComparison.Ordinal) + && candidate.Key.EndsWith(key, StringComparison.Ordinal)); + + if (file.Value?.Content is null) + { + throw new InvalidOperationException($"The cloud backup \"{key}\" was not found."); + } + + return file.Value.Content; + } + + private static async Task GetBackupGistAsync( + GitHubApiClient client, + bool createIfMissing + ) + { + var candidates = await client.GetCurrentUserGistsAsync(); + var backupGist = candidates.FirstOrDefault(candidate => + candidate.Description?.EndsWith(GistDescriptionEndingKey, StringComparison.Ordinal) + == true + ); + + if (backupGist is not null || !createIfMissing) + { + return backupGist; + } + + return await client.CreateGistAsync( + GistDescription, + isPublic: false, + new Dictionary { ["- UniGetUI Package Backups"] = ReadMeContents } + ); + } + + private static string BuildGistFileKey() + { + string deviceUser = (Environment.MachineName + "\\" + Environment.UserName).Replace( + " ", + string.Empty + ); + return PackageBackupStartingKey + " " + deviceUser; + } + + private static string ValidateBackupKey(string key) + { + if (string.IsNullOrWhiteSpace(key)) + { + throw new InvalidOperationException("The backup key is required."); + } + + return key; + } + + private static PendingGitHubDeviceFlow GetPendingGitHubDeviceFlow() + { + lock (GitHubAuthLock) + { + return _pendingGitHubDeviceFlow + ?? throw new InvalidOperationException( + "No GitHub device flow is pending. Start sign-in first." + ); + } + } + + private static void ClearPendingGitHubDeviceFlow() + { + lock (GitHubAuthLock) + { + _pendingGitHubDeviceFlow = null; + } + } +} diff --git a/src/UniGetUI.Interface.IpcApi/IpcBundleApi.cs b/src/UniGetUI.Interface.IpcApi/IpcBundleApi.cs new file mode 100644 index 0000000..1a4907d --- /dev/null +++ b/src/UniGetUI.Interface.IpcApi/IpcBundleApi.cs @@ -0,0 +1,800 @@ +using System.Text.Json.Nodes; +using UniGetUI.Core.Data; +using UniGetUI.Core.SettingsEngine; +using UniGetUI.Core.SettingsEngine.SecureSettings; +using UniGetUI.Core.Tools; +using UniGetUI.Interface.Enums; +using UniGetUI.PackageEngine; +using UniGetUI.PackageEngine.Classes.Serializable; +using UniGetUI.PackageEngine.Enums; +using UniGetUI.PackageEngine.Interfaces; +using UniGetUI.PackageEngine.Operations; +using UniGetUI.PackageEngine.PackageClasses; +using UniGetUI.PackageEngine.PackageLoader; +using UniGetUI.PackageEngine.Serializable; + +namespace UniGetUI.Interface; + +public sealed class IpcBundlePackageInfo +{ + public string Name { get; set; } = ""; + public string Id { get; set; } = ""; + public string Version { get; set; } = ""; + public string DisplayVersion { get; set; } = ""; + public string? SelectedVersion { get; set; } + public string? Scope { get; set; } + public bool PreRelease { get; set; } + public string Source { get; set; } = ""; + public string Manager { get; set; } = ""; + public bool IsCompatible { get; set; } + public bool IsInstalled { get; set; } + public bool IsUpgradable { get; set; } +} + +public sealed class IpcBundleInfo +{ + public int PackageCount { get; set; } + public IReadOnlyList Packages { get; set; } = []; +} + +public sealed class IpcBundleImportRequest +{ + public string? Content { get; set; } + public string? Path { get; set; } + public string? Format { get; set; } + public bool Append { get; set; } +} + +public sealed class IpcBundleExportRequest +{ + public string? Path { get; set; } +} + +public sealed class IpcBundlePackageRequest +{ + public string PackageId { get; set; } = ""; + public string? ManagerName { get; set; } + public string? PackageSource { get; set; } + public string? Version { get; set; } + public string? Scope { get; set; } + public bool? PreRelease { get; set; } + public string? Selection { get; set; } +} + +public sealed class IpcBundleInstallRequest +{ + public bool? IncludeInstalled { get; set; } + public bool? Elevated { get; set; } + public bool? Interactive { get; set; } + public bool? SkipHash { get; set; } +} + +public sealed class IpcBundleSecurityEntry +{ + public string PackageId { get; set; } = ""; + public string Line { get; set; } = ""; + public bool Allowed { get; set; } +} + +public class IpcBundleCommandResult +{ + public string Status { get; set; } = "success"; + public string Command { get; set; } = ""; + public string? Message { get; set; } +} + +public sealed class IpcBundleImportResult : IpcBundleCommandResult +{ + public double SchemaVersion { get; set; } + public string Format { get; set; } = ""; + public IpcBundleInfo Bundle { get; set; } = new(); + public IReadOnlyList SecurityReport { get; set; } = []; +} + +public sealed class IpcBundleExportResult : IpcBundleCommandResult +{ + public string Format { get; set; } = ""; + public string Content { get; set; } = ""; + public string? Path { get; set; } + public IpcBundleInfo Bundle { get; set; } = new(); +} + +public sealed class IpcBundlePackageOperationResult : IpcBundleCommandResult +{ + public IpcBundlePackageInfo? Package { get; set; } + public int RemovedCount { get; set; } + public IpcBundleInfo Bundle { get; set; } = new(); +} + +public sealed class IpcBundleInstallResult : IpcBundleCommandResult +{ + public int RequestedCount { get; set; } + public int SucceededCount { get; set; } + public int FailedCount { get; set; } + public int SkippedCount { get; set; } + public IpcBundleInfo Bundle { get; set; } = new(); + public IReadOnlyList Results { get; set; } = []; +} + +public static class IpcBundleApi +{ + public static async Task GetCurrentBundleAsync() + { + return await BuildBundleInfoAsync(GetLoader().Packages); + } + + public static IpcCommandResult ResetBundle() + { + GetLoader().ClearPackages(); + return IpcCommandResult.Success("reset-bundle"); + } + + public static async Task ImportBundleAsync( + IpcBundleImportRequest request + ) + { + ArgumentNullException.ThrowIfNull(request); + + var loader = GetLoader(); + var format = ResolveImportFormat(request); + var content = await ReadBundleContentAsync(request); + + if (!request.Append) + { + loader.ClearPackages(); + } + + var (schemaVersion, report) = await AddFromBundleAsync(content, format); + return new IpcBundleImportResult + { + Status = "success", + Command = "import-bundle", + SchemaVersion = schemaVersion, + Format = format.ToString().ToLowerInvariant(), + Bundle = await BuildBundleInfoAsync(loader.Packages), + SecurityReport = FlattenReport(report), + }; + } + + public static async Task ExportBundleAsync( + IpcBundleExportRequest? request = null + ) + { + request ??= new IpcBundleExportRequest(); + var packages = GetLoader().Packages; + var content = await CreateBundleAsync(packages); + var format = ResolveExportFormat(request.Path); + + if (!string.IsNullOrWhiteSpace(request.Path)) + { + await File.WriteAllTextAsync(request.Path, content); + } + + return new IpcBundleExportResult + { + Status = "success", + Command = "export-bundle", + Format = format.ToString().ToLowerInvariant(), + Path = request.Path, + Content = content, + Bundle = await BuildBundleInfoAsync(packages), + }; + } + + public static async Task AddPackageAsync( + IpcBundlePackageRequest request + ) + { + ArgumentNullException.ThrowIfNull(request); + + var loader = GetLoader(); + var package = await CreateBundlePackageAsync(request); + await loader.AddPackagesAsync([package]); + + return new IpcBundlePackageOperationResult + { + Status = "success", + Command = "add-bundle-package", + Package = await ToBundlePackageInfoAsync(package), + Bundle = await BuildBundleInfoAsync(loader.Packages), + }; + } + + public static async Task RemovePackageAsync( + IpcBundlePackageRequest request + ) + { + ArgumentNullException.ThrowIfNull(request); + + var loader = GetLoader(); + var packages = loader.Packages; + var toRemove = new List(); + foreach (var package in packages) + { + if (await MatchesBundleRequestAsync(package, request)) + { + toRemove.Add(package); + } + } + + loader.RemoveRange(toRemove); + + return new IpcBundlePackageOperationResult + { + Status = "success", + Command = "remove-bundle-package", + RemovedCount = toRemove.Count, + Bundle = await BuildBundleInfoAsync(loader.Packages), + }; + } + + public static async Task InstallBundleAsync( + IpcBundleInstallRequest? request = null + ) + { + request ??= new IpcBundleInstallRequest(); + + var packages = GetLoader().Packages; + bool includeInstalled = + request.IncludeInstalled ?? Settings.Get(Settings.K.InstallInstalledPackagesBundlesPage); + List results = []; + + foreach (var package in packages) + { + if (package is not ImportedPackage imported) + { + results.Add( + new IpcPackageOperationResult + { + Status = "error", + Command = "install-bundle", + OperationStatus = "invalid", + Message = "The bundle entry is incompatible and cannot be installed.", + Package = IpcPackageApi.CreateIpcPackageInfo(package), + } + ); + continue; + } + + if (!includeInstalled && package.Tag == PackageTag.AlreadyInstalled) + { + results.Add( + new IpcPackageOperationResult + { + Status = "success", + Command = "install-bundle", + OperationStatus = "skipped", + Message = "The package is already installed and include-installed is disabled.", + Package = IpcPackageApi.CreateIpcPackageInfo(package), + } + ); + continue; + } + + var registeredPackage = await imported.RegisterAndGetPackageAsync(); + var bundleOptions = await imported.GetInstallOptions(); + var options = await InstallOptionsFactory.LoadApplicableAsync( + registeredPackage, + elevated: request.Elevated, + interactive: request.Interactive, + no_integrity: request.SkipHash, + overridePackageOptions: bundleOptions + ); + + using var operation = new InstallPackageOperation(registeredPackage, options); + await operation.MainThread(); + if (operation.Status == OperationStatus.Succeeded) + { + imported.SetTag(PackageTag.AlreadyInstalled); + } + results.Add( + IpcPackageApi.CreateOperationResult( + "install-bundle", + imported, + operation + ) + ); + } + + return new IpcBundleInstallResult + { + Status = results.Any(result => result.Status == "error") ? "error" : "success", + Command = "install-bundle", + RequestedCount = packages.Count, + SucceededCount = results.Count(result => + result.Status == "success" && result.OperationStatus != "skipped" + ), + FailedCount = results.Count(result => result.Status == "error"), + SkippedCount = results.Count(result => result.OperationStatus == "skipped"), + Bundle = await BuildBundleInfoAsync(GetLoader().Packages), + Results = results, + }; + } + + private static PackageBundlesLoader GetLoader() + { + return PackageBundlesLoader.Instance + ?? throw new InvalidOperationException("The package bundle loader is not available."); + } + + private static async Task BuildBundleInfoAsync( + IReadOnlyList packages + ) + { + var bundlePackages = await Task.WhenAll(packages.Select(ToBundlePackageInfoAsync)); + var sortedPackages = bundlePackages + .OrderBy(package => package.Manager, StringComparer.OrdinalIgnoreCase) + .ThenBy(package => package.Id, StringComparer.OrdinalIgnoreCase) + .ThenBy(package => package.Version, StringComparer.OrdinalIgnoreCase) + .ToArray(); + + return new IpcBundleInfo + { + PackageCount = sortedPackages.Length, + Packages = sortedPackages, + }; + } + + private static async Task ToBundlePackageInfoAsync(IPackage package) + { + if (package is ImportedPackage imported) + { + var serialized = await imported.AsSerializableAsync(); + return new IpcBundlePackageInfo + { + Name = imported.Name, + Id = imported.Id, + Version = serialized.Version, + DisplayVersion = imported.VersionString, + SelectedVersion = string.IsNullOrWhiteSpace(serialized.InstallationOptions.Version) + ? null + : serialized.InstallationOptions.Version, + Scope = string.IsNullOrWhiteSpace(serialized.InstallationOptions.InstallationScope) + ? null + : serialized.InstallationOptions.InstallationScope, + PreRelease = serialized.InstallationOptions.PreRelease, + Source = imported.Source.AsString_DisplayName, + Manager = IpcManagerSettingsApi.GetPublicManagerId(imported.Manager), + IsCompatible = true, + IsInstalled = imported.Tag == PackageTag.AlreadyInstalled, + IsUpgradable = imported.Tag == PackageTag.IsUpgradable || imported.IsUpgradable, + }; + } + + if (package is InvalidImportedPackage invalid) + { + var serialized = invalid.AsSerializable_Incompatible(); + return new IpcBundlePackageInfo + { + Name = invalid.Name, + Id = invalid.Id, + Version = serialized.Version, + DisplayVersion = invalid.VersionString, + Source = invalid.SourceAsString, + Manager = IpcManagerSettingsApi.GetPublicManagerId(invalid.Manager), + IsCompatible = false, + IsInstalled = false, + IsUpgradable = false, + }; + } + + return new IpcBundlePackageInfo + { + Name = package.Name, + Id = package.Id, + Version = package.VersionString, + DisplayVersion = package.VersionString, + Source = package.Source.AsString_DisplayName, + Manager = IpcManagerSettingsApi.GetPublicManagerId(package.Manager), + IsCompatible = !package.Source.IsVirtualManager, + IsInstalled = package.Tag == PackageTag.AlreadyInstalled, + IsUpgradable = package.Tag == PackageTag.IsUpgradable || package.IsUpgradable, + }; + } + + private static async Task CreateBundlePackageAsync( + IpcBundlePackageRequest request + ) + { + var packageRequest = new IpcPackageActionRequest + { + PackageId = request.PackageId, + ManagerName = request.ManagerName, + PackageSource = request.PackageSource, + Version = request.Version, + Scope = request.Scope, + PreRelease = request.PreRelease, + }; + var package = IpcPackageApi.ResolvePackage( + packageRequest, + ParseLookupMode(request.Selection) + ); + + if (package.Source.IsVirtualManager) + { + return new InvalidImportedPackage(package.AsSerializable_Incompatible(), NullSource.Instance); + } + + var serialized = await package.AsSerializableAsync(); + IpcPackageApi.ApplyRequestedOptions(serialized.InstallationOptions, packageRequest); + return new ImportedPackage(serialized, package.Manager, package.Source); + } + + private static async Task MatchesBundleRequestAsync( + IPackage package, + IpcBundlePackageRequest request + ) + { + if (!package.Id.Equals(request.PackageId, StringComparison.OrdinalIgnoreCase)) + { + return false; + } + + if (!IpcManagerSettingsApi.MatchesManagerId(package.Manager, request.ManagerName)) + { + return false; + } + + if ( + !string.IsNullOrWhiteSpace(request.PackageSource) + && !package.Source.Name.Equals(request.PackageSource, StringComparison.OrdinalIgnoreCase) + && !package.Source.AsString_DisplayName.Equals( + request.PackageSource, + StringComparison.OrdinalIgnoreCase + ) + ) + { + return false; + } + + if (string.IsNullOrWhiteSpace(request.Version)) + { + return true; + } + + return request.Version.Equals( + await GetBundlePackageVersionAsync(package), + StringComparison.OrdinalIgnoreCase + ); + } + + private static async Task GetBundlePackageVersionAsync(IPackage package) + { + if (package is ImportedPackage imported) + { + return (await imported.AsSerializableAsync()).Version; + } + + if (package is InvalidImportedPackage invalid) + { + return invalid.AsSerializable_Incompatible().Version; + } + + return package.VersionString; + } + + private static async Task ReadBundleContentAsync(IpcBundleImportRequest request) + { + bool hasContent = !string.IsNullOrWhiteSpace(request.Content); + bool hasPath = !string.IsNullOrWhiteSpace(request.Path); + + if (hasContent == hasPath) + { + throw new InvalidOperationException( + "Exactly one of content or path must be supplied when importing a bundle." + ); + } + + if (hasContent) + { + return request.Content!; + } + + return await File.ReadAllTextAsync(request.Path!); + } + + private static BundleFormatType ResolveImportFormat(IpcBundleImportRequest request) + { + if (!string.IsNullOrWhiteSpace(request.Format)) + { + return ParseFormat(request.Format); + } + + if (string.IsNullOrWhiteSpace(request.Path)) + { + return BundleFormatType.UBUNDLE; + } + + return ParseFormat(Path.GetExtension(request.Path)); + } + + private static BundleFormatType ResolveExportFormat(string? path) + { + if (string.IsNullOrWhiteSpace(path)) + { + return BundleFormatType.UBUNDLE; + } + + var extension = Path.GetExtension(path); + return extension.ToLowerInvariant() switch + { + ".json" => BundleFormatType.JSON, + ".ubundle" or "" => BundleFormatType.UBUNDLE, + _ => throw new InvalidOperationException( + "Bundle export only supports .ubundle and .json output files." + ), + }; + } + + private static BundleFormatType ParseFormat(string? format) + { + return format?.Trim().TrimStart('.').ToLowerInvariant() switch + { + null or "" or "ubundle" => BundleFormatType.UBUNDLE, + "json" => BundleFormatType.JSON, + "yaml" or "yml" => BundleFormatType.YAML, + "xml" => BundleFormatType.XML, + _ => throw new InvalidOperationException( + $"The bundle format \"{format}\" is not supported." + ), + }; + } + + private static IpcPackageLookupMode ParseLookupMode(string? selection) + { + return selection?.Trim().ToLowerInvariant() switch + { + null or "" or "search" => IpcPackageLookupMode.Search, + "installed" => IpcPackageLookupMode.Installed, + "updates" or "upgradable" => IpcPackageLookupMode.Upgradable, + "auto" => IpcPackageLookupMode.Any, + _ => throw new InvalidOperationException( + $"The bundle selection mode \"{selection}\" is not supported." + ), + }; + } + + internal static async Task CreateBundleAsync(IReadOnlyList unsortedPackages) + { + var exportableData = new SerializableBundle(); + var packages = unsortedPackages.ToList(); + packages.Sort((x, y) => + { + if (x.Id != y.Id) + { + return string.Compare(x.Id, y.Id, StringComparison.Ordinal); + } + + if (x.Name != y.Name) + { + return string.Compare(x.Name, y.Name, StringComparison.Ordinal); + } + + return x.NormalizedVersion > y.NormalizedVersion ? -1 : 1; + }); + + foreach (var package in packages) + { + if (package is ImportedPackage imported) + { + exportableData.packages.Add(await imported.AsSerializableAsync()); + } + else + { + exportableData.incompatible_packages.Add(package.AsSerializable_Incompatible()); + } + } + + return exportableData.AsJsonString(); + } + + internal static async Task<(double SchemaVersion, BundleReport Report)> AddFromBundleAsync( + string content, + BundleFormatType format + ) + { + if (format == BundleFormatType.YAML) + { + content = await SerializationHelpers.YAML_to_JSON(content); + } + else if (format == BundleFormatType.XML) + { + content = await SerializationHelpers.XML_to_JSON(content); + } + + var deserializedData = await Task.Run(() => + new SerializableBundle( + JsonNode.Parse(content) + ?? throw new InvalidOperationException("The bundle content could not be parsed.") + ) + ); + + var report = new BundleReport { IsEmpty = true }; + bool allowCliArguments = + SecureSettings.Get(SecureSettings.K.AllowCLIArguments) + && SecureSettings.Get(SecureSettings.K.AllowImportingCLIArguments); + bool allowPrePostCommands = + SecureSettings.Get(SecureSettings.K.AllowPrePostOpCommand) + && SecureSettings.Get(SecureSettings.K.AllowImportPrePostOpCommands); + + List packages = []; + foreach (var package in deserializedData.packages) + { + var options = package.InstallationOptions; + ReportList( + ref report, + package.Id, + options.CustomParameters_Install, + "Custom install arguments", + allowCliArguments + ); + ReportList( + ref report, + package.Id, + options.CustomParameters_Update, + "Custom update arguments", + allowCliArguments + ); + ReportList( + ref report, + package.Id, + options.CustomParameters_Uninstall, + "Custom uninstall arguments", + allowCliArguments + ); + options.PreInstallCommand = ReportString( + ref report, + package.Id, + options.PreInstallCommand, + "Pre-install command", + allowPrePostCommands + ); + options.PostInstallCommand = ReportString( + ref report, + package.Id, + options.PostInstallCommand, + "Post-install command", + allowPrePostCommands + ); + options.PreUpdateCommand = ReportString( + ref report, + package.Id, + options.PreUpdateCommand, + "Pre-update command", + allowPrePostCommands + ); + options.PostUpdateCommand = ReportString( + ref report, + package.Id, + options.PostUpdateCommand, + "Post-update command", + allowPrePostCommands + ); + options.PreUninstallCommand = ReportString( + ref report, + package.Id, + options.PreUninstallCommand, + "Pre-uninstall command", + allowPrePostCommands + ); + options.PostUninstallCommand = ReportString( + ref report, + package.Id, + options.PostUninstallCommand, + "Post-uninstall command", + allowPrePostCommands + ); + package.InstallationOptions = options; + packages.Add(DeserializePackage(package)); + } + + foreach (var incompatiblePackage in deserializedData.incompatible_packages) + { + packages.Add(new InvalidImportedPackage(incompatiblePackage, NullSource.Instance)); + } + + await GetLoader().AddPackagesAsync(packages); + return (deserializedData.export_version, report); + } + + private static IPackage DeserializePackage(SerializablePackage raw) + { + IPackageManager? manager = IpcManagerSettingsApi.ResolveImportedManager(raw.ManagerName); + + IManagerSource? source; + if (manager?.Capabilities.SupportsCustomSources == true) + { + if (raw.Source.Contains(": ")) + { + raw.Source = raw.Source.Split(": ")[^1]; + } + + source = manager.SourcesHelper?.Factory.GetSourceIfExists(raw.Source); + } + else + { + source = manager?.DefaultSource; + } + + if (manager is null || source is null) + { + return new InvalidImportedPackage(raw.GetInvalidEquivalent(), NullSource.Instance); + } + + return new ImportedPackage(raw, manager, source); + } + + private static void ReportList( + ref BundleReport report, + string packageId, + List values, + string label, + bool allowed + ) + { + if (!values.Any(value => value.Any())) + { + return; + } + + if (!report.Contents.TryGetValue(packageId, out List? packageEntries)) + { + packageEntries = []; + report.Contents[packageId] = packageEntries; + } + + packageEntries.Add( + new BundleReportEntry($"{label}: [{string.Join(", ", values)}]", allowed) + ); + report.IsEmpty = false; + if (!allowed) + { + values.Clear(); + } + } + + private static string ReportString( + ref BundleReport report, + string packageId, + string value, + string label, + bool allowed + ) + { + if (!value.Any()) + { + return value; + } + + if (!report.Contents.TryGetValue(packageId, out List? packageEntries)) + { + packageEntries = []; + report.Contents[packageId] = packageEntries; + } + + packageEntries.Add(new BundleReportEntry($"{label}: {value}", allowed)); + report.IsEmpty = false; + return allowed ? value : ""; + } + + private static IReadOnlyList FlattenReport(BundleReport report) + { + if (report.IsEmpty) + { + return []; + } + + return report + .Contents.SelectMany(pair => + pair.Value.Select(entry => new IpcBundleSecurityEntry + { + PackageId = pair.Key, + Line = entry.Line, + Allowed = entry.Allowed, + }) + ) + .OrderBy(entry => entry.PackageId, StringComparer.OrdinalIgnoreCase) + .ThenBy(entry => entry.Line, StringComparer.OrdinalIgnoreCase) + .ToArray(); + } +} diff --git a/src/UniGetUI.Interface.IpcApi/IpcCliCommandRunner.cs b/src/UniGetUI.Interface.IpcApi/IpcCliCommandRunner.cs new file mode 100644 index 0000000..bc04bcf --- /dev/null +++ b/src/UniGetUI.Interface.IpcApi/IpcCliCommandRunner.cs @@ -0,0 +1,867 @@ +using System.Text.Json; +using System.Text.Json.Nodes; +using UniGetUI.Core.Data; +using UniGetUI.Core.Logging; + +namespace UniGetUI.Interface; + +public enum IpcCliExitCode +{ + Success = 0, + Failed = 1, + InvalidParameter = 2, + IpcUnavailable = 3, + UnknownCommand = 4, +} + +public static class IpcCliCommandRunner +{ + public static async Task RunAsync( + IReadOnlyList args, + TextWriter output, + TextWriter error + ) + { + IpcCliParseResult parseResult = IpcCliSyntax.Parse(args); + if (parseResult.Status == IpcCliParseStatus.Help) + { + await output.WriteLineAsync(IpcCliSyntax.GetHelpText()); + return (int)IpcCliExitCode.Success; + } + + if ( + parseResult.Status != IpcCliParseStatus.Success + || parseResult.Command is null + || parseResult.EffectiveArgs is null + ) + { + return await WriteErrorAsync( + output, + parseResult.Message ?? "A valid command was not provided.", + IpcCliExitCode.InvalidParameter + ); + } + + args = parseResult.EffectiveArgs; + string subcommand = parseResult.Command.Trim().ToLowerInvariant(); + + try + { + using var client = IpcClient.CreateForCli(args); + return subcommand switch + { + "status" => await WriteJsonAsync(output, await client.GetStatusAsync()), + "get-app-state" => await WriteWrappedJsonAsync( + output, + "app", + await client.GetAppInfoAsync() + ), + "show-app" => await WriteJsonAsync(output, await client.ShowAppAsync()), + "navigate-app" => await WriteJsonAsync( + output, + await client.NavigateAppAsync(BuildAppNavigateRequest(args)) + ), + "quit-app" => await WriteJsonAsync(output, await client.QuitAppAsync()), + "list-operations" => await WriteWrappedJsonAsync( + output, + "operations", + await client.ListOperationsAsync() + ), + "get-operation" => await WriteWrappedJsonAsync( + output, + "operation", + await client.GetOperationAsync( + GetRequiredArgument( + args, + "--operation-id", + "operation get requires --id." + ) + ) + ), + "get-operation-output" => await WriteWrappedJsonAsync( + output, + "output", + await client.GetOperationOutputAsync( + GetRequiredArgument( + args, + "--operation-id", + "operation output requires --id." + ), + GetOptionalIntArgument(args, "--tail") + ) + ), + "wait-operation" => await WriteWrappedJsonAsync( + output, + "operation", + await client.WaitForOperationAsync( + GetRequiredArgument( + args, + "--operation-id", + "operation wait requires --id." + ), + GetOptionalIntArgument(args, "--timeout") ?? 300, + ((GetOptionalIntArgument(args, "--delay") ?? 1) * 1000) + ) + ), + "cancel-operation" => await WriteJsonAsync( + output, + await client.CancelOperationAsync( + GetRequiredArgument( + args, + "--operation-id", + "operation cancel requires --id." + ) + ) + ), + "retry-operation" => await WriteJsonAsync( + output, + await client.RetryOperationAsync( + GetRequiredArgument( + args, + "--operation-id", + "operation retry requires --id." + ), + GetOptionalArgument(args, "--mode") + ) + ), + "reorder-operation" => await WriteJsonAsync( + output, + await client.ReorderOperationAsync( + GetRequiredArgument( + args, + "--operation-id", + "operation reorder requires --id." + ), + GetRequiredArgument( + args, + "--action", + "operation reorder requires --action." + ) + ) + ), + "forget-operation" => await WriteJsonAsync( + output, + await client.ForgetOperationAsync( + GetRequiredArgument( + args, + "--operation-id", + "operation forget requires --id." + ) + ) + ), + "list-managers" => await WriteWrappedJsonAsync( + output, + "managers", + await client.ListManagersAsync() + ), + "get-manager-maintenance" => await WriteWrappedJsonAsync( + output, + "maintenance", + await client.GetManagerMaintenanceAsync( + GetRequiredArgument( + args, + "--manager", + "manager maintenance requires --manager." + ) + ) + ), + "reload-manager" => await WriteJsonAsync( + output, + await client.ReloadManagerAsync(BuildManagerMaintenanceRequest(args)) + ), + "set-manager-executable" => await WriteJsonAsync( + output, + await client.SetManagerExecutablePathAsync( + BuildManagerMaintenanceRequest(args, requirePath: true) + ) + ), + "clear-manager-executable" => await WriteJsonAsync( + output, + await client.ClearManagerExecutablePathAsync(BuildManagerMaintenanceRequest(args)) + ), + "run-manager-action" => await WriteJsonAsync( + output, + await client.RunManagerActionAsync( + BuildManagerMaintenanceRequest(args, requireAction: true) + ) + ), + "list-sources" => await WriteWrappedJsonAsync( + output, + "sources", + await client.ListSourcesAsync(GetOptionalArgument(args, "--manager")) + ), + "add-source" => await WriteJsonAsync( + output, + await client.AddSourceAsync(BuildSourceRequest(args)) + ), + "remove-source" => await WriteJsonAsync( + output, + await client.RemoveSourceAsync(BuildSourceRequest(args)) + ), + "list-settings" => await WriteWrappedJsonAsync( + output, + "settings", + await client.ListSettingsAsync() + ), + "list-secure-settings" => await WriteWrappedJsonAsync( + output, + "settings", + await client.ListSecureSettingsAsync(GetOptionalArgument(args, "--user")) + ), + "get-secure-setting" => await WriteWrappedJsonAsync( + output, + "setting", + await client.GetSecureSettingAsync( + GetRequiredArgument( + args, + "--key", + "settings secure get requires --key." + ), + GetOptionalArgument(args, "--user") + ) + ), + "set-secure-setting" => await WriteWrappedJsonAsync( + output, + "setting", + await client.SetSecureSettingAsync(BuildSecureSettingRequest(args)) + ), + "get-setting" => await WriteWrappedJsonAsync( + output, + "setting", + await client.GetSettingAsync( + GetRequiredArgument( + args, + "--key", + "settings get requires --key." + ) + ) + ), + "set-setting" => await WriteWrappedJsonAsync( + output, + "setting", + await client.SetSettingAsync(BuildSettingRequest(args)) + ), + "clear-setting" => await WriteWrappedJsonAsync( + output, + "setting", + await client.ClearSettingAsync( + GetRequiredArgument( + args, + "--key", + "settings clear requires --key." + ) + ) + ), + "set-manager-enabled" => await WriteWrappedJsonAsync( + output, + "manager", + await client.SetManagerEnabledAsync(BuildManagerToggleRequest(args)) + ), + "set-manager-update-notifications" => await WriteWrappedJsonAsync( + output, + "manager", + await client.SetManagerUpdateNotificationsAsync( + BuildManagerToggleRequest(args) + ) + ), + "reset-settings" => await WriteJsonAsync( + output, + await client.ResetSettingsAsync() + ), + "list-desktop-shortcuts" => await WriteWrappedJsonAsync( + output, + "shortcuts", + await client.ListDesktopShortcutsAsync() + ), + "set-desktop-shortcut" => await WriteJsonAsync( + output, + await client.SetDesktopShortcutAsync(BuildDesktopShortcutRequest(args, requireStatus: true)) + ), + "reset-desktop-shortcut" => await WriteJsonAsync( + output, + await client.ResetDesktopShortcutAsync( + GetRequiredArgument( + args, + "--path", + "shortcut reset requires --path." + ) + ) + ), + "reset-desktop-shortcuts" => await WriteJsonAsync( + output, + await client.ResetDesktopShortcutsAsync() + ), + "get-app-log" => await WriteWrappedJsonAsync( + output, + "entries", + await client.GetAppLogAsync(GetOptionalIntArgument(args, "--level") ?? 4) + ), + "get-operation-history" => await WriteWrappedJsonAsync( + output, + "history", + await client.GetOperationHistoryAsync() + ), + "get-manager-log" => await WriteWrappedJsonAsync( + output, + "managers", + await client.GetManagerLogAsync( + GetOptionalArgument(args, "--manager"), + args.Contains("--verbose") + ) + ), + "get-backup-status" => await WriteWrappedJsonAsync( + output, + "backup", + await client.GetBackupStatusAsync() + ), + "create-local-backup" => await WriteJsonAsync( + output, + await client.CreateLocalBackupAsync() + ), + "start-github-sign-in" => await WriteJsonAsync( + output, + await client.StartGitHubDeviceFlowAsync(BuildGitHubDeviceFlowRequest(args)) + ), + "complete-github-sign-in" => await WriteJsonAsync( + output, + await client.CompleteGitHubDeviceFlowAsync() + ), + "sign-out-github" => await WriteJsonAsync( + output, + await client.SignOutGitHubAsync() + ), + "list-cloud-backups" => await WriteWrappedJsonAsync( + output, + "backups", + await client.ListCloudBackupsAsync() + ), + "create-cloud-backup" => await WriteJsonAsync( + output, + await client.CreateCloudBackupAsync() + ), + "download-cloud-backup" => await WriteJsonAsync( + output, + await client.DownloadCloudBackupAsync(BuildCloudBackupRequest(args)) + ), + "restore-cloud-backup" => await WriteJsonAsync( + output, + await client.RestoreCloudBackupAsync(BuildCloudBackupRequest(args)) + ), + "get-bundle" => await WriteWrappedJsonAsync( + output, + "bundle", + await client.GetBundleAsync() + ), + "reset-bundle" => await WriteJsonAsync( + output, + await client.ResetBundleAsync() + ), + "import-bundle" => await WriteJsonAsync( + output, + await client.ImportBundleAsync(BuildBundleImportRequest(args)) + ), + "export-bundle" => await WriteJsonAsync( + output, + await client.ExportBundleAsync(BuildBundleExportRequest(args)) + ), + "add-bundle-package" => await WriteJsonAsync( + output, + await client.AddBundlePackageAsync(BuildBundlePackageRequest(args)) + ), + "remove-bundle-package" => await WriteJsonAsync( + output, + await client.RemoveBundlePackageAsync(BuildBundlePackageRequest(args)) + ), + "install-bundle" => await WriteJsonAsync( + output, + await client.InstallBundleAsync(BuildBundleInstallRequest(args)) + ), + "get-version" => await WriteWrappedJsonAsync( + output, + "build", + await client.GetVersionAsync() + ), + "get-updates" => await WriteWrappedJsonAsync( + output, + "updates", + await client.ListUpgradablePackagesAsync( + GetOptionalArgument(args, "--manager") + ) + ), + "list-installed" => await WriteWrappedJsonAsync( + output, + "packages", + await client.ListInstalledPackagesAsync( + GetOptionalArgument(args, "--manager") + ) + ), + "search-packages" => await WriteWrappedJsonAsync( + output, + "packages", + await client.SearchPackagesAsync( + GetRequiredArgument( + args, + "--query", + "package search requires --query." + ), + GetOptionalArgument(args, "--manager"), + GetOptionalIntArgument(args, "--max-results") + ) + ), + "package-details" => await WriteWrappedJsonAsync( + output, + "package", + await client.GetPackageDetailsAsync(BuildPackageActionRequest(args)) + ), + "package-versions" => await WriteWrappedJsonAsync( + output, + "versions", + await client.GetPackageVersionsAsync(BuildPackageActionRequest(args)) + ), + "list-ignored-updates" => await WriteWrappedJsonAsync( + output, + "ignoredUpdates", + await client.ListIgnoredUpdatesAsync() + ), + "ignore-package" => await WriteJsonAsync( + output, + await client.IgnorePackageUpdateAsync(BuildPackageActionRequest(args)) + ), + "unignore-package" => await WriteJsonAsync( + output, + await client.RemoveIgnoredUpdateAsync(BuildPackageActionRequest(args)) + ), + "install-package" => await WriteJsonAsync( + output, + await client.InstallPackageAsync(BuildPackageActionRequest(args)) + ), + "download-package" => await WriteJsonAsync( + output, + await client.DownloadPackageAsync(BuildPackageActionRequest(args)) + ), + "reinstall-package" => await WriteJsonAsync( + output, + await client.ReinstallPackageAsync(BuildPackageActionRequest(args)) + ), + "update-package" => await WriteJsonAsync( + output, + await client.UpdatePackageAsync(BuildPackageActionRequest(args)) + ), + "uninstall-package" => await WriteJsonAsync( + output, + await client.UninstallPackageAsync(BuildPackageActionRequest(args)) + ), + "uninstall-then-reinstall-package" => await WriteJsonAsync( + output, + await client.UninstallThenReinstallPackageAsync(BuildPackageActionRequest(args)) + ), + "open-window" => await WriteJsonAsync(output, await client.OpenWindowAsync()), + "open-updates" => await WriteJsonAsync(output, await client.OpenUpdatesAsync()), + "show-package" => await WriteJsonAsync( + output, + await client.ShowPackageAsync( + GetRequiredArgument( + args, + "--package-id", + "package show requires --id." + ), + GetRequiredArgument( + args, + "--package-source", + "package show requires --source." + ) + ) + ), + "update-all" => await WriteJsonAsync(output, await client.UpdateAllAsync()), + "update-manager" => await WriteJsonAsync( + output, + await client.UpdateManagerAsync( + GetRequiredArgument( + args, + "--manager", + "package update-manager requires --manager." + ) + ) + ), + _ => await WriteErrorAsync( + output, + $"Unknown command \"{subcommand}\".", + IpcCliExitCode.UnknownCommand + ), + }; + } + catch (InvalidOperationException ex) + { + return await WriteErrorAsync(output, ex.Message, IpcCliExitCode.InvalidParameter); + } + catch (HttpRequestException ex) + { + return await WriteErrorAsync( + output, + ex.Message, + IpcCliExitCode.IpcUnavailable + ); + } + catch (IOException ex) + { + return await WriteErrorAsync( + output, + ex.Message, + IpcCliExitCode.IpcUnavailable + ); + } + catch (Exception ex) + { + Logger.Error(ex); + return await WriteErrorAsync(output, ex.Message, IpcCliExitCode.Failed); + } + } + + private static IpcPackageActionRequest BuildPackageActionRequest(IReadOnlyList args) + { + return new IpcPackageActionRequest + { + PackageId = GetRequiredArgument( + args, + "--package-id", + "This command requires --id." + ), + ManagerName = GetOptionalArgument(args, "--manager"), + PackageSource = GetOptionalArgument(args, "--package-source"), + Version = GetOptionalArgument(args, "--version"), + Scope = GetOptionalArgument(args, "--scope"), + PreRelease = args.Contains("--pre-release") ? true : null, + Elevated = GetOptionalBoolArgument(args, "--elevated"), + Interactive = GetOptionalBoolArgument(args, "--interactive"), + SkipHash = GetOptionalBoolArgument(args, "--skip-hash"), + RemoveData = GetOptionalBoolArgument(args, "--remove-data"), + WaitForCompletion = args.Contains("--detach") + ? false + : GetOptionalBoolArgument(args, "--wait"), + Architecture = GetOptionalArgument(args, "--architecture"), + InstallLocation = GetOptionalArgument(args, "--location"), + OutputPath = GetOptionalArgument(args, "--output"), + }; + } + + private static IpcAppNavigateRequest BuildAppNavigateRequest(IReadOnlyList args) + { + return new IpcAppNavigateRequest + { + Page = GetRequiredArgument( + args, + "--page", + "app navigate requires --page." + ), + ManagerName = GetOptionalArgument(args, "--manager"), + HelpAttachment = GetOptionalArgument(args, "--help-attachment"), + }; + } + + private static IpcSourceRequest BuildSourceRequest(IReadOnlyList args) + { + return new IpcSourceRequest + { + ManagerName = GetRequiredArgument( + args, + "--manager", + "This command requires --manager." + ), + SourceName = GetRequiredArgument( + args, + "--name", + "This command requires --name." + ), + SourceUrl = GetOptionalArgument(args, "--url"), + }; + } + + private static IpcManagerMaintenanceRequest BuildManagerMaintenanceRequest( + IReadOnlyList args, + bool requireAction = false, + bool requirePath = false + ) + { + return new IpcManagerMaintenanceRequest + { + ManagerName = GetRequiredArgument( + args, + "--manager", + "This command requires --manager." + ), + Action = requireAction + ? GetRequiredArgument(args, "--action", "This command requires --action.") + : GetOptionalArgument(args, "--action"), + Path = requirePath + ? GetRequiredArgument(args, "--path", "This command requires --path.") + : GetOptionalArgument(args, "--path"), + Confirm = args.Contains("--confirm"), + }; + } + + private static IpcSecureSettingRequest BuildSecureSettingRequest( + IReadOnlyList args + ) + { + return new IpcSecureSettingRequest + { + SettingKey = GetRequiredArgument(args, "--key", "This command requires --key."), + UserName = GetOptionalArgument(args, "--user"), + Enabled = GetRequiredBoolArgument(args, "--enabled"), + }; + } + + private static IpcManagerToggleRequest BuildManagerToggleRequest(IReadOnlyList args) + { + return new IpcManagerToggleRequest + { + ManagerName = GetRequiredArgument( + args, + "--manager", + "This command requires --manager." + ), + Enabled = GetRequiredBoolArgument(args, "--enabled"), + }; + } + + private static IpcDesktopShortcutRequest BuildDesktopShortcutRequest( + IReadOnlyList args, + bool requireStatus + ) + { + return new IpcDesktopShortcutRequest + { + Path = GetRequiredArgument(args, "--path", "This command requires --path."), + Status = requireStatus + ? GetRequiredArgument( + args, + "--status", + "This command requires --status." + ) + : GetOptionalArgument(args, "--status"), + }; + } + + private static IpcBundleImportRequest BuildBundleImportRequest( + IReadOnlyList args + ) + { + return new IpcBundleImportRequest + { + Path = GetOptionalArgument(args, "--path"), + Content = GetOptionalArgument(args, "--content"), + Format = GetOptionalArgument(args, "--format"), + Append = args.Contains("--append"), + }; + } + + private static IpcGitHubDeviceFlowRequest BuildGitHubDeviceFlowRequest( + IReadOnlyList args + ) + { + return new IpcGitHubDeviceFlowRequest + { + LaunchBrowser = args.Contains("--launch-browser"), + }; + } + + private static IpcCloudBackupRequest BuildCloudBackupRequest(IReadOnlyList args) + { + return new IpcCloudBackupRequest + { + Key = GetRequiredArgument( + args, + "--key", + "This command requires --key." + ), + Append = args.Contains("--append"), + }; + } + + private static IpcBundleExportRequest BuildBundleExportRequest( + IReadOnlyList args + ) + { + return new IpcBundleExportRequest { Path = GetOptionalArgument(args, "--path") }; + } + + private static IpcBundlePackageRequest BuildBundlePackageRequest( + IReadOnlyList args + ) + { + return new IpcBundlePackageRequest + { + PackageId = GetRequiredArgument( + args, + "--package-id", + "This command requires --id." + ), + ManagerName = GetOptionalArgument(args, "--manager"), + PackageSource = GetOptionalArgument(args, "--package-source"), + Version = GetOptionalArgument(args, "--version"), + Scope = GetOptionalArgument(args, "--scope"), + PreRelease = args.Contains("--pre-release") ? true : null, + Selection = GetOptionalArgument(args, "--selection"), + }; + } + + private static IpcBundleInstallRequest BuildBundleInstallRequest( + IReadOnlyList args + ) + { + return new IpcBundleInstallRequest + { + IncludeInstalled = GetOptionalBoolArgument(args, "--include-installed"), + Elevated = GetOptionalBoolArgument(args, "--elevated"), + Interactive = GetOptionalBoolArgument(args, "--interactive"), + SkipHash = GetOptionalBoolArgument(args, "--skip-hash"), + }; + } + + private static IpcSettingValueRequest BuildSettingRequest(IReadOnlyList args) + { + bool? enabled = null; + string? enabledValue = GetOptionalArgument(args, "--enabled"); + if (enabledValue is not null) + { + if (!bool.TryParse(enabledValue, out bool parsedEnabled)) + { + throw new InvalidOperationException( + "The value supplied to --enabled must be either true or false." + ); + } + + enabled = parsedEnabled; + } + + return new IpcSettingValueRequest + { + SettingKey = GetRequiredArgument( + args, + "--key", + "This command requires --key." + ), + Enabled = enabled, + Value = GetOptionalArgument(args, "--value"), + }; + } + + private static string GetRequiredArgument( + IReadOnlyList arguments, + string argumentName, + string errorMessage + ) + { + int index = arguments.ToList().IndexOf(argumentName); + if (index < 0 || index + 1 >= arguments.Count) + { + throw new InvalidOperationException(errorMessage); + } + + return arguments[index + 1].Trim('"').Trim('\''); + } + + private static string? GetOptionalArgument( + IReadOnlyList arguments, + string argumentName + ) + { + int index = arguments.ToList().IndexOf(argumentName); + if (index < 0 || index + 1 >= arguments.Count) + { + return null; + } + + return arguments[index + 1].Trim('"').Trim('\''); + } + + private static int? GetOptionalIntArgument( + IReadOnlyList arguments, + string argumentName + ) + { + string? value = GetOptionalArgument(arguments, argumentName); + if (value is null) + { + return null; + } + + if (int.TryParse(value, out int result)) + { + return result; + } + + throw new InvalidOperationException( + $"The value supplied to {argumentName} must be an integer." + ); + } + + private static bool? GetOptionalBoolArgument( + IReadOnlyList arguments, + string argumentName + ) + { + string? value = GetOptionalArgument(arguments, argumentName); + if (value is null) + { + return null; + } + + if (bool.TryParse(value, out bool result)) + { + return result; + } + + throw new InvalidOperationException( + $"The value supplied to {argumentName} must be either true or false." + ); + } + + private static bool GetRequiredBoolArgument(IReadOnlyList arguments, string argumentName) + { + bool? value = GetOptionalBoolArgument(arguments, argumentName); + if (!value.HasValue) + { + throw new InvalidOperationException( + $"This command requires {argumentName} with a value of true or false." + ); + } + + return value.Value; + } + + private static async Task WriteJsonAsync(TextWriter output, T value) + { + await output.WriteLineAsync( + IpcJson.Serialize(value) + ); + return (int)IpcCliExitCode.Success; + } + + private static async Task WriteWrappedJsonAsync( + TextWriter output, + string propertyName, + T value + ) + { + var response = new JsonObject + { + ["status"] = "success", + [propertyName] = JsonNode.Parse(IpcJson.Serialize(value)), + }; + await output.WriteLineAsync(response.ToJsonString(IpcJson.Options)); + return (int)IpcCliExitCode.Success; + } + + private static async Task WriteErrorAsync( + TextWriter output, + string message, + IpcCliExitCode exitCode + ) + { + await output.WriteLineAsync( + IpcJson.Serialize(new IpcCommandResult { Status = "error", Message = message }) + ); + return (int)exitCode; + } +} diff --git a/src/UniGetUI.Interface.IpcApi/IpcCliSyntax.cs b/src/UniGetUI.Interface.IpcApi/IpcCliSyntax.cs new file mode 100644 index 0000000..48f1998 --- /dev/null +++ b/src/UniGetUI.Interface.IpcApi/IpcCliSyntax.cs @@ -0,0 +1,385 @@ +namespace UniGetUI.Interface; + +internal enum IpcCliParseStatus +{ + NotIpcCommand, + Success, + Help, + Error, +} + +internal sealed record IpcCliParseResult( + IpcCliParseStatus Status, + string? Command = null, + string[]? EffectiveArgs = null, + string? Message = null +); + +public static class IpcCliSyntax +{ + private static readonly HashSet GlobalOptionsWithValue = new(StringComparer.OrdinalIgnoreCase) + { + IpcTransportOptions.CliTransportArgument, + IpcTransportOptions.CliTcpPortArgument, + IpcTransportOptions.CliNamedPipeArgument, + }; + + internal static IpcCliParseResult Parse(IReadOnlyList args) + { + if (args.Count == 0) + { + return new(IpcCliParseStatus.NotIpcCommand); + } + + if (args.Any(arg => string.Equals(arg, "--help", StringComparison.OrdinalIgnoreCase)) + || args.Any(arg => string.Equals(arg, "-h", StringComparison.OrdinalIgnoreCase))) + { + return new(IpcCliParseStatus.Help); + } + + List commandIndexes = []; + HashSet consumedIndexes = []; + List leadingGlobalArgs = []; + bool commandStarted = false; + + for (int i = 0; i < args.Count; i++) + { + string arg = args[i]; + if (!commandStarted) + { + if (GlobalOptionsWithValue.Contains(arg)) + { + leadingGlobalArgs.Add(arg); + consumedIndexes.Add(i); + if (i + 1 < args.Count) + { + leadingGlobalArgs.Add(args[i + 1]); + consumedIndexes.Add(i + 1); + i++; + } + + continue; + } + + if (arg.StartsWith("--", StringComparison.Ordinal)) + { + return new(IpcCliParseStatus.NotIpcCommand); + } + + commandStarted = true; + } + + if (arg.StartsWith("--", StringComparison.Ordinal)) + { + break; + } + + commandIndexes.Add(i); + consumedIndexes.Add(i); + } + + if (commandIndexes.Count == 0) + { + return new(IpcCliParseStatus.NotIpcCommand); + } + + string[] path = commandIndexes + .Select(index => NormalizeToken(args[index])) + .ToArray(); + + if (path is ["help"]) + { + return new(IpcCliParseStatus.Help); + } + + string? command = TryMapCommand(path, out List injectedArgs); + if (command is null) + { + return new( + IpcCliParseStatus.NotIpcCommand, + Message: $"Unknown command path \"{string.Join(" ", path)}\"." + ); + } + + List remainingArgs = []; + for (int i = 0; i < args.Count; i++) + { + if (!consumedIndexes.Contains(i)) + { + remainingArgs.Add(args[i]); + } + } + + RewriteArgumentAliases(command, remainingArgs); + + return new( + IpcCliParseStatus.Success, + Command: command, + EffectiveArgs: [.. leadingGlobalArgs, .. injectedArgs, .. remainingArgs] + ); + } + + public static bool IsIpcCommand(IReadOnlyList args) + { + return Parse(args).Status is IpcCliParseStatus.Success or IpcCliParseStatus.Help; + } + + public static bool HasVerbCommand(IReadOnlyList args) + { + int firstArgumentIndex = GetFirstNonGlobalArgumentIndex(args); + if (firstArgumentIndex < 0) + { + return false; + } + + string firstArgument = args[firstArgumentIndex]; + if (firstArgument.StartsWith("-", StringComparison.Ordinal)) + { + return false; + } + + return Parse(args).Status is IpcCliParseStatus.Success or IpcCliParseStatus.Help; + } + + public static string GetHelpText() + { + return """ +Usage: + unigetui [global-options] [subcommand] [options] + +Global options: + --transport {tcp|named-pipe} + --tcp-port + --pipe-name + +Core commands: + status + version + app status|show|navigate|quit + operation list|get|output|wait|cancel|retry|reorder|forget + manager list|maintenance|reload|set-executable|clear-executable|action|enable|disable + manager notifications enable|disable + source list|add|remove + settings list|get|set|clear|reset + settings secure list|get|set + shortcut list|set|reset|reset-all + log app|operations|manager + backup status + backup local create + backup cloud list|create|download|restore + backup github login start|complete + backup github logout + bundle get|reset|import|export|add|remove|install + package search|details|versions|installed|updates|install|download|reinstall|repair|update|uninstall|show + package ignored list|add|remove + package update-all + package update-manager + +Examples: + unigetui status + unigetui app status + unigetui package search --manager dotnet-tool --query dotnetsay + unigetui package install --manager dotnet-tool --id dotnetsay --version 2.1.4 --scope Global + unigetui operation wait --id 123 --timeout 300 + unigetui backup local create + unigetui backup github login start --launch-browser +"""; + } + + private static string NormalizeToken(string token) + { + return token.Trim().ToLowerInvariant() switch + { + "operations" => "operation", + "packages" => "package", + "managers" => "manager", + "sources" => "source", + "shortcuts" => "shortcut", + "logs" => "log", + "backups" => "backup", + "bundles" => "bundle", + _ => token.Trim().ToLowerInvariant(), + }; + } + + private static int GetFirstNonGlobalArgumentIndex(IReadOnlyList args) + { + for (int i = 0; i < args.Count; i++) + { + if (GlobalOptionsWithValue.Contains(args[i])) + { + if (i + 1 < args.Count) + { + i++; + } + + continue; + } + + return i; + } + + return -1; + } + + private static string? TryMapCommand(string[] path, out List injectedArgs) + { + injectedArgs = []; + + return path switch + { + ["status"] => "status", + ["version"] => "get-version", + + ["app", "status"] => "get-app-state", + ["app", "show"] => "show-app", + ["app", "navigate"] => "navigate-app", + ["app", "quit"] => "quit-app", + + ["operation", "list"] => "list-operations", + ["operation", "get"] => "get-operation", + ["operation", "output"] => "get-operation-output", + ["operation", "wait"] => "wait-operation", + ["operation", "cancel"] => "cancel-operation", + ["operation", "retry"] => "retry-operation", + ["operation", "reorder"] => "reorder-operation", + ["operation", "forget"] => "forget-operation", + + ["manager", "list"] => "list-managers", + ["manager", "maintenance"] => "get-manager-maintenance", + ["manager", "reload"] => "reload-manager", + ["manager", "set-executable"] => "set-manager-executable", + ["manager", "clear-executable"] => "clear-manager-executable", + ["manager", "action"] => "run-manager-action", + ["manager", "enable"] => Inject("set-manager-enabled", injectedArgs, "--enabled", "true"), + ["manager", "disable"] => Inject("set-manager-enabled", injectedArgs, "--enabled", "false"), + ["manager", "notifications", "enable"] => Inject( + "set-manager-update-notifications", + injectedArgs, + "--enabled", + "true" + ), + ["manager", "notifications", "disable"] => Inject( + "set-manager-update-notifications", + injectedArgs, + "--enabled", + "false" + ), + + ["source", "list"] => "list-sources", + ["source", "add"] => "add-source", + ["source", "remove"] => "remove-source", + + ["settings", "list"] => "list-settings", + ["settings", "get"] => "get-setting", + ["settings", "set"] => "set-setting", + ["settings", "clear"] => "clear-setting", + ["settings", "reset"] => "reset-settings", + ["settings", "secure", "list"] => "list-secure-settings", + ["settings", "secure", "get"] => "get-secure-setting", + ["settings", "secure", "set"] => "set-secure-setting", + + ["shortcut", "list"] => "list-desktop-shortcuts", + ["shortcut", "set"] => "set-desktop-shortcut", + ["shortcut", "reset"] => "reset-desktop-shortcut", + ["shortcut", "reset-all"] => "reset-desktop-shortcuts", + + ["log", "app"] => "get-app-log", + ["log", "operation"] => "get-operation-history", + ["log", "operations"] => "get-operation-history", + ["log", "manager"] => "get-manager-log", + + ["backup", "status"] => "get-backup-status", + ["backup", "local", "create"] => "create-local-backup", + ["backup", "cloud", "list"] => "list-cloud-backups", + ["backup", "cloud", "create"] => "create-cloud-backup", + ["backup", "cloud", "download"] => "download-cloud-backup", + ["backup", "cloud", "restore"] => "restore-cloud-backup", + ["backup", "github", "login", "start"] => "start-github-sign-in", + ["backup", "github", "login", "complete"] => "complete-github-sign-in", + ["backup", "github", "logout"] => "sign-out-github", + + ["bundle", "get"] => "get-bundle", + ["bundle", "reset"] => "reset-bundle", + ["bundle", "import"] => "import-bundle", + ["bundle", "export"] => "export-bundle", + ["bundle", "add"] => "add-bundle-package", + ["bundle", "remove"] => "remove-bundle-package", + ["bundle", "install"] => "install-bundle", + + ["package", "search"] => "search-packages", + ["package", "details"] => "package-details", + ["package", "versions"] => "package-versions", + ["package", "installed"] => "list-installed", + ["package", "updates"] => "get-updates", + ["package", "install"] => "install-package", + ["package", "download"] => "download-package", + ["package", "reinstall"] => "reinstall-package", + ["package", "repair"] => "uninstall-then-reinstall-package", + ["package", "update"] => "update-package", + ["package", "uninstall"] => "uninstall-package", + ["package", "show"] => "show-package", + ["package", "ignored", "list"] => "list-ignored-updates", + ["package", "ignored", "add"] => "ignore-package", + ["package", "ignored", "remove"] => "unignore-package", + ["package", "update-all"] => "update-all", + ["package", "update-manager"] => "update-manager", + + _ => null, + }; + } + + private static string Inject( + string command, + List injectedArgs, + params string[] args + ) + { + injectedArgs.AddRange(args); + return command; + } + + private static void RewriteArgumentAliases(string command, List args) + { + for (int i = 0; i < args.Count; i++) + { + args[i] = command switch + { + "get-operation" or "get-operation-output" or "wait-operation" or "cancel-operation" + or "retry-operation" or "reorder-operation" or "forget-operation" + when string.Equals(args[i], "--id", StringComparison.OrdinalIgnoreCase) + => "--operation-id", + + "package-details" or "package-versions" or "install-package" or "download-package" + or "reinstall-package" or "update-package" or "uninstall-package" + or "uninstall-then-reinstall-package" or "ignore-package" + or "unignore-package" or "show-package" or "add-bundle-package" + or "remove-bundle-package" + when string.Equals(args[i], "--id", StringComparison.OrdinalIgnoreCase) + => "--package-id", + + "package-details" or "package-versions" or "install-package" or "download-package" + or "reinstall-package" or "update-package" or "uninstall-package" + or "uninstall-then-reinstall-package" or "ignore-package" + or "unignore-package" or "show-package" or "add-bundle-package" + or "remove-bundle-package" + when string.Equals(args[i], "--source", StringComparison.OrdinalIgnoreCase) + => "--package-source", + + "add-source" or "remove-source" + when string.Equals(args[i], "--source-name", StringComparison.OrdinalIgnoreCase) + => "--name", + + "add-source" or "remove-source" + when string.Equals(args[i], "--source-url", StringComparison.OrdinalIgnoreCase) + => "--url", + + "download-cloud-backup" or "restore-cloud-backup" + when string.Equals(args[i], "--name", StringComparison.OrdinalIgnoreCase) + => "--key", + + _ => args[i], + }; + } + } +} diff --git a/src/UniGetUI.Interface.IpcApi/IpcClient.cs b/src/UniGetUI.Interface.IpcApi/IpcClient.cs new file mode 100644 index 0000000..9941b4c --- /dev/null +++ b/src/UniGetUI.Interface.IpcApi/IpcClient.cs @@ -0,0 +1,1530 @@ +using System.Diagnostics; +using System.IO.Pipes; +using System.Net.Http.Json; +using System.Net.Sockets; +using System.Text.Json; +using UniGetUI.Core.Data; +using UniGetUI.Core.Logging; + +namespace UniGetUI.Interface; + +public sealed class IpcClient : IDisposable +{ + private readonly HttpClient _httpClient; + private readonly string _token; + + public IpcTransportOptions TransportOptions { get; } + + private IpcClient(IpcTransportOptions transportOptions, string? token = null) + { + TransportOptions = transportOptions; + _token = token ?? string.Empty; + _httpClient = CreateHttpClient(transportOptions); + } + + public static IpcClient CreateForCli(IReadOnlyList? args = null) + { + args ??= Environment.GetCommandLineArgs(); + IpcTransportOptions requestedOptions = IpcTransportOptions.LoadForClient(args); + + if (IpcTransportOptions.HasExplicitClientOverride(args)) + { + return new IpcClient( + requestedOptions, + WaitForExplicitSessionToken(requestedOptions) + ); + } + + var preferredRegistration = SelectLiveRegistration( + IpcTransportOptions.OrderRegistrationsForCliSelection( + IpcTransportOptions.LoadPersistedRegistrations() + ) + ); + + return preferredRegistration is not null + ? new IpcClient( + preferredRegistration.ToTransportOptions(), + preferredRegistration.Token + ) + : new IpcClient(requestedOptions); + } + + private static string? WaitForExplicitSessionToken(IpcTransportOptions requestedOptions) + { + Stopwatch timeout = Stopwatch.StartNew(); + + while (timeout.Elapsed < TimeSpan.FromSeconds(5)) + { + var matchingRegistrations = IpcTransportOptions.LoadPersistedRegistrations() + .Where(candidate => candidate.Matches(requestedOptions)) + .ToArray(); + var registration = SelectLiveRegistration(matchingRegistrations); + string? token = registration?.Token + ?? matchingRegistrations.FirstOrDefault(candidate => + !string.IsNullOrWhiteSpace(candidate.Token) + )?.Token; + + if (!string.IsNullOrWhiteSpace(token)) + { + return token; + } + + Thread.Sleep(100); + } + + return null; + } + + public async Task GetStatusAsync() + { + try + { + string json = await SendAsync(HttpMethod.Get, IpcHttpRoutes.Path("/status")); + var status = IpcJson.Deserialize(json); + if (status is not null) + { + return status; + } + } + catch (Exception ex) when (IsConnectivityException(ex)) + { + Logger.Debug($"IPC API status probe failed: {ex.Message}"); + } + + return new IpcStatus + { + Running = false, + Transport = TransportOptions.TransportKind switch + { + IpcTransportKind.NamedPipe => "named-pipe", + _ => "tcp", + }, + TcpPort = TransportOptions.TcpPort, + NamedPipeName = TransportOptions.NamedPipeName, + NamedPipePath = TransportOptions.NamedPipePath ?? "", + BaseAddress = TransportOptions.BaseAddressString, + }; + } + + public async Task GetAppInfoAsync() + { + return await ReadAuthenticatedJsonAsync( + HttpMethod.Get, + IpcHttpRoutes.Path("/app") + ) + ?? new IpcAppInfo(); + } + + public async Task> ListOperationsAsync() + { + return await ReadAuthenticatedJsonAsync>( + HttpMethod.Get, + IpcHttpRoutes.Path("/operations") + ) + ?? []; + } + + public async Task GetOperationAsync(string operationId) + { + return await ReadAuthenticatedJsonAsync( + HttpMethod.Get, + IpcHttpRoutes.Path($"/operations/{Uri.EscapeDataString(operationId)}") + ); + } + + public async Task GetOperationOutputAsync( + string operationId, + int? tailLines = null + ) + { + Dictionary? parameters = null; + if (tailLines.HasValue) + { + parameters = new Dictionary + { + ["tailLines"] = tailLines.Value.ToString(), + }; + } + + return await ReadAuthenticatedJsonAsync( + HttpMethod.Get, + IpcHttpRoutes.Path($"/operations/{Uri.EscapeDataString(operationId)}/output"), + parameters + ) + ?? new IpcOperationOutputResult + { + OperationId = operationId, + }; + } + + public async Task WaitForOperationAsync( + string operationId, + int timeoutSeconds = 300, + int delayMilliseconds = 1000 + ) + { + timeoutSeconds = Math.Clamp(timeoutSeconds, 1, 3600); + delayMilliseconds = Math.Clamp(delayMilliseconds, 100, 10000); + + DateTime deadline = DateTime.UtcNow.AddSeconds(timeoutSeconds); + while (true) + { + var operation = await GetOperationAsync(operationId) + ?? throw new InvalidOperationException( + $"No tracked operation with id \"{operationId}\" was found." + ); + + if ( + operation.Status is "succeeded" or "failed" or "canceled" + ) + { + return operation; + } + + if (DateTime.UtcNow >= deadline) + { + throw new InvalidOperationException( + $"Timed out while waiting for operation {operationId}." + ); + } + + await Task.Delay(delayMilliseconds); + } + } + + public async Task CancelOperationAsync(string operationId) + { + return await ReadAuthenticatedJsonAsync( + HttpMethod.Post, + IpcHttpRoutes.Path($"/operations/{Uri.EscapeDataString(operationId)}/cancel") + ) + ?? new IpcCommandResult + { + Status = "error", + Command = "cancel-operation", + Message = "The IPC API returned an empty response.", + }; + } + + public async Task RetryOperationAsync( + string operationId, + string? mode = null + ) + { + Dictionary? parameters = null; + if (!string.IsNullOrWhiteSpace(mode)) + { + parameters = new Dictionary + { + ["mode"] = mode, + }; + } + + return await ReadAuthenticatedJsonAsync( + HttpMethod.Post, + IpcHttpRoutes.Path($"/operations/{Uri.EscapeDataString(operationId)}/retry"), + parameters + ) + ?? new IpcCommandResult + { + Status = "error", + Command = "retry-operation", + Message = "The IPC API returned an empty response.", + }; + } + + public async Task ReorderOperationAsync( + string operationId, + string action + ) + { + return await ReadAuthenticatedJsonAsync( + HttpMethod.Post, + IpcHttpRoutes.Path($"/operations/{Uri.EscapeDataString(operationId)}/reorder"), + new Dictionary { ["action"] = action } + ) + ?? new IpcCommandResult + { + Status = "error", + Command = "reorder-operation", + Message = "The IPC API returned an empty response.", + }; + } + + public async Task ForgetOperationAsync(string operationId) + { + return await ReadAuthenticatedJsonAsync( + HttpMethod.Post, + IpcHttpRoutes.Path($"/operations/{Uri.EscapeDataString(operationId)}/forget") + ) + ?? new IpcCommandResult + { + Status = "error", + Command = "forget-operation", + Message = "The IPC API returned an empty response.", + }; + } + + public async Task ShowAppAsync() + { + return await ReadAuthenticatedJsonAsync( + HttpMethod.Post, + IpcHttpRoutes.Path("/app/show") + ) + ?? new IpcCommandResult + { + Status = "error", + Command = "show-app", + Message = "The IPC API returned an empty response.", + }; + } + + public async Task NavigateAppAsync( + IpcAppNavigateRequest request + ) + { + return await ReadAuthenticatedJsonAsync( + HttpMethod.Post, + IpcHttpRoutes.Path("/app/navigate"), + BuildAppNavigateParameters(request) + ) + ?? new IpcCommandResult + { + Status = "error", + Command = "navigate-app", + Message = "The IPC API returned an empty response.", + }; + } + + public async Task QuitAppAsync() + { + return await ReadAuthenticatedJsonAsync( + HttpMethod.Post, + IpcHttpRoutes.Path("/app/quit") + ) + ?? new IpcCommandResult + { + Status = "error", + Command = "quit-app", + Message = "The IPC API returned an empty response.", + }; + } + + public async Task> ListManagersAsync() + { + return await ReadAuthenticatedJsonAsync>( + HttpMethod.Get, + IpcHttpRoutes.Path("/managers") + ) ?? []; + } + + public async Task GetManagerMaintenanceAsync( + string managerName + ) + { + return await ReadAuthenticatedJsonAsync( + HttpMethod.Get, + IpcHttpRoutes.Path("/managers/maintenance"), + new Dictionary { ["manager"] = managerName } + ); + } + + public async Task ReloadManagerAsync( + IpcManagerMaintenanceRequest request + ) + { + return await SendManagerMaintenanceActionAsync( + IpcHttpRoutes.Path("/managers/maintenance/reload"), + request + ); + } + + public async Task SetManagerExecutablePathAsync( + IpcManagerMaintenanceRequest request + ) + { + return await SendManagerMaintenanceActionAsync( + IpcHttpRoutes.Path("/managers/maintenance/executable/set"), + request + ); + } + + public async Task ClearManagerExecutablePathAsync( + IpcManagerMaintenanceRequest request + ) + { + return await SendManagerMaintenanceActionAsync( + IpcHttpRoutes.Path("/managers/maintenance/executable/clear"), + request + ); + } + + public async Task RunManagerActionAsync( + IpcManagerMaintenanceRequest request + ) + { + return await SendManagerMaintenanceActionAsync( + IpcHttpRoutes.Path("/managers/maintenance/action"), + request + ); + } + + public async Task> ListSourcesAsync(string? managerName = null) + { + Dictionary? parameters = null; + if (!string.IsNullOrWhiteSpace(managerName)) + { + parameters = new Dictionary { ["manager"] = managerName }; + } + + return await ReadAuthenticatedJsonAsync>( + HttpMethod.Get, + IpcHttpRoutes.Path("/sources"), + parameters + ) ?? []; + } + + public async Task AddSourceAsync(IpcSourceRequest request) + { + return await SendSourceOperationAsync(IpcHttpRoutes.Path("/sources/add"), request); + } + + public async Task RemoveSourceAsync(IpcSourceRequest request) + { + return await SendSourceOperationAsync(IpcHttpRoutes.Path("/sources/remove"), request); + } + + public async Task> ListSettingsAsync() + { + return await ReadAuthenticatedJsonAsync>( + HttpMethod.Get, + IpcHttpRoutes.Path("/settings") + ) ?? []; + } + + public async Task> ListSecureSettingsAsync( + string? userName = null + ) + { + Dictionary? parameters = null; + if (!string.IsNullOrWhiteSpace(userName)) + { + parameters = new Dictionary { ["user"] = userName }; + } + + return await ReadAuthenticatedJsonAsync>( + HttpMethod.Get, + IpcHttpRoutes.Path("/secure-settings"), + parameters + ) ?? []; + } + + public async Task GetSecureSettingAsync( + string key, + string? userName = null + ) + { + Dictionary parameters = new() { ["key"] = key }; + if (!string.IsNullOrWhiteSpace(userName)) + { + parameters["user"] = userName; + } + + return await ReadAuthenticatedJsonAsync( + HttpMethod.Get, + IpcHttpRoutes.Path("/secure-settings/item"), + parameters + ); + } + + public async Task SetSecureSettingAsync( + IpcSecureSettingRequest request + ) + { + Dictionary parameters = new() + { + ["key"] = request.SettingKey, + ["enabled"] = request.Enabled ? "true" : "false", + }; + if (!string.IsNullOrWhiteSpace(request.UserName)) + { + parameters["user"] = request.UserName; + } + + return await ReadAuthenticatedJsonAsync( + HttpMethod.Post, + IpcHttpRoutes.Path("/secure-settings/set"), + parameters + ); + } + + public async Task GetSettingAsync(string key) + { + return await ReadAuthenticatedJsonAsync( + HttpMethod.Get, + IpcHttpRoutes.Path("/settings/item"), + new Dictionary { ["key"] = key } + ); + } + + public async Task SetSettingAsync(IpcSettingValueRequest request) + { + Dictionary parameters = new() { ["key"] = request.SettingKey }; + if (request.Enabled.HasValue) + { + parameters["enabled"] = request.Enabled.Value ? "true" : "false"; + } + + if (request.Value is not null) + { + parameters["value"] = request.Value; + } + + return await ReadAuthenticatedJsonAsync( + HttpMethod.Post, + IpcHttpRoutes.Path("/settings/set"), + parameters + ); + } + + public async Task ClearSettingAsync(string key) + { + return await ReadAuthenticatedJsonAsync( + HttpMethod.Post, + IpcHttpRoutes.Path("/settings/clear"), + new Dictionary { ["key"] = key } + ); + } + + public async Task SetManagerEnabledAsync( + IpcManagerToggleRequest request + ) + { + return await ReadAuthenticatedJsonAsync( + HttpMethod.Post, + IpcHttpRoutes.Path("/managers/set-enabled"), + new Dictionary + { + ["manager"] = request.ManagerName, + ["enabled"] = request.Enabled ? "true" : "false", + } + ); + } + + public async Task SetManagerUpdateNotificationsAsync( + IpcManagerToggleRequest request + ) + { + return await ReadAuthenticatedJsonAsync( + HttpMethod.Post, + IpcHttpRoutes.Path("/managers/set-update-notifications"), + new Dictionary + { + ["manager"] = request.ManagerName, + ["enabled"] = request.Enabled ? "true" : "false", + } + ); + } + + public async Task ResetSettingsAsync() + { + return await ReadAuthenticatedJsonAsync( + HttpMethod.Post, + IpcHttpRoutes.Path("/settings/reset") + ) + ?? new IpcCommandResult + { + Status = "error", + Message = "The IPC API returned an empty response.", + }; + } + + public async Task> ListDesktopShortcutsAsync() + { + return await ReadAuthenticatedJsonAsync>( + HttpMethod.Get, + IpcHttpRoutes.Path("/desktop-shortcuts") + ) ?? []; + } + + public async Task SetDesktopShortcutAsync( + IpcDesktopShortcutRequest request + ) + { + return await SendDesktopShortcutOperationAsync( + IpcHttpRoutes.Path("/desktop-shortcuts/set"), + request + ); + } + + public async Task ResetDesktopShortcutAsync( + string shortcutPath + ) + { + return await SendDesktopShortcutOperationAsync( + IpcHttpRoutes.Path("/desktop-shortcuts/reset"), + new IpcDesktopShortcutRequest { Path = shortcutPath } + ); + } + + public async Task ResetDesktopShortcutsAsync() + { + return await ReadAuthenticatedJsonAsync( + HttpMethod.Post, + IpcHttpRoutes.Path("/desktop-shortcuts/reset-all") + ) + ?? new IpcCommandResult + { + Status = "error", + Message = "The IPC API returned an empty response.", + }; + } + + public async Task> GetAppLogAsync(int level = 4) + { + return await ReadAuthenticatedJsonAsync>( + HttpMethod.Get, + IpcHttpRoutes.Path("/logs/app"), + new Dictionary { ["level"] = level.ToString() } + ) ?? []; + } + + public async Task> GetOperationHistoryAsync() + { + return await ReadAuthenticatedJsonAsync>( + HttpMethod.Get, + IpcHttpRoutes.Path("/logs/history") + ) ?? []; + } + + public async Task> GetManagerLogAsync( + string? managerName = null, + bool verbose = false + ) + { + Dictionary? parameters = null; + if (!string.IsNullOrWhiteSpace(managerName) || verbose) + { + parameters = new Dictionary(); + if (!string.IsNullOrWhiteSpace(managerName)) + { + parameters["manager"] = managerName; + } + + if (verbose) + { + parameters["verbose"] = "true"; + } + } + + return await ReadAuthenticatedJsonAsync>( + HttpMethod.Get, + IpcHttpRoutes.Path("/logs/manager"), + parameters + ) ?? []; + } + + public async Task GetBackupStatusAsync() + { + return await ReadAuthenticatedJsonAsync( + HttpMethod.Get, + IpcHttpRoutes.Path("/backups/status") + ); + } + + public async Task CreateLocalBackupAsync() + { + return await ReadAuthenticatedJsonAsync( + HttpMethod.Post, + IpcHttpRoutes.Path("/backups/local/create") + ) + ?? new IpcLocalBackupResult + { + Status = "error", + Message = "The IPC API returned an empty response.", + }; + } + + public async Task StartGitHubDeviceFlowAsync( + IpcGitHubDeviceFlowRequest request + ) + { + return await ReadAuthenticatedJsonWithBodyAsync< + IpcGitHubAuthResult, + IpcGitHubDeviceFlowRequest + >(IpcHttpRoutes.Path("/backups/github/sign-in/start"), request) + ?? new IpcGitHubAuthResult + { + Status = "error", + Message = "The IPC API returned an empty response.", + }; + } + + public async Task CompleteGitHubDeviceFlowAsync() + { + return await ReadAuthenticatedJsonAsync( + HttpMethod.Post, + IpcHttpRoutes.Path("/backups/github/sign-in/complete") + ) + ?? new IpcGitHubAuthResult + { + Status = "error", + Message = "The IPC API returned an empty response.", + }; + } + + public async Task SignOutGitHubAsync() + { + return await ReadAuthenticatedJsonAsync( + HttpMethod.Post, + IpcHttpRoutes.Path("/backups/github/sign-out") + ) + ?? new IpcGitHubAuthResult + { + Status = "error", + Message = "The IPC API returned an empty response.", + }; + } + + public async Task> ListCloudBackupsAsync() + { + return await ReadAuthenticatedJsonAsync>( + HttpMethod.Get, + IpcHttpRoutes.Path("/backups/cloud") + ) ?? []; + } + + public async Task CreateCloudBackupAsync() + { + return await ReadAuthenticatedJsonAsync( + HttpMethod.Post, + IpcHttpRoutes.Path("/backups/cloud/create") + ) + ?? new IpcCloudBackupUploadResult + { + Status = "error", + Message = "The IPC API returned an empty response.", + }; + } + + public async Task DownloadCloudBackupAsync( + IpcCloudBackupRequest request + ) + { + return await ReadAuthenticatedJsonWithBodyAsync< + IpcCloudBackupContentResult, + IpcCloudBackupRequest + >(IpcHttpRoutes.Path("/backups/cloud/download"), request) + ?? new IpcCloudBackupContentResult + { + Status = "error", + Message = "The IPC API returned an empty response.", + }; + } + + public async Task RestoreCloudBackupAsync( + IpcCloudBackupRequest request + ) + { + return await ReadAuthenticatedJsonWithBodyAsync< + IpcCloudBackupRestoreResult, + IpcCloudBackupRequest + >(IpcHttpRoutes.Path("/backups/cloud/restore"), request) + ?? new IpcCloudBackupRestoreResult + { + Status = "error", + Message = "The IPC API returned an empty response.", + }; + } + + public async Task GetBundleAsync() + { + return await ReadAuthenticatedJsonAsync( + HttpMethod.Get, + IpcHttpRoutes.Path("/bundles") + ) + ?? new IpcBundleInfo(); + } + + public async Task ResetBundleAsync() + { + return await ReadAuthenticatedJsonAsync( + HttpMethod.Post, + IpcHttpRoutes.Path("/bundles/reset") + ) + ?? new IpcCommandResult + { + Status = "error", + Message = "The IPC API returned an empty response.", + }; + } + + public async Task ImportBundleAsync( + IpcBundleImportRequest request + ) + { + return await ReadAuthenticatedJsonWithBodyAsync< + IpcBundleImportResult, + IpcBundleImportRequest + >(IpcHttpRoutes.Path("/bundles/import"), request) + ?? new IpcBundleImportResult + { + Status = "error", + Message = "The IPC API returned an empty response.", + }; + } + + public async Task ExportBundleAsync( + IpcBundleExportRequest request + ) + { + return await ReadAuthenticatedJsonWithBodyAsync< + IpcBundleExportResult, + IpcBundleExportRequest + >(IpcHttpRoutes.Path("/bundles/export"), request) + ?? new IpcBundleExportResult + { + Status = "error", + Message = "The IPC API returned an empty response.", + }; + } + + public async Task AddBundlePackageAsync( + IpcBundlePackageRequest request + ) + { + return await ReadAuthenticatedJsonWithBodyAsync< + IpcBundlePackageOperationResult, + IpcBundlePackageRequest + >(IpcHttpRoutes.Path("/bundles/add"), request) + ?? new IpcBundlePackageOperationResult + { + Status = "error", + Message = "The IPC API returned an empty response.", + }; + } + + public async Task RemoveBundlePackageAsync( + IpcBundlePackageRequest request + ) + { + return await ReadAuthenticatedJsonWithBodyAsync< + IpcBundlePackageOperationResult, + IpcBundlePackageRequest + >(IpcHttpRoutes.Path("/bundles/remove"), request) + ?? new IpcBundlePackageOperationResult + { + Status = "error", + Message = "The IPC API returned an empty response.", + }; + } + + public async Task InstallBundleAsync( + IpcBundleInstallRequest request + ) + { + return await ReadAuthenticatedJsonWithBodyAsync< + IpcBundleInstallResult, + IpcBundleInstallRequest + >(IpcHttpRoutes.Path("/bundles/install"), request) + ?? new IpcBundleInstallResult + { + Status = "error", + Message = "The IPC API returned an empty response.", + }; + } + + public async Task OpenWindowAsync() + { + return await ShowAppAsync(); + } + + public async Task OpenUpdatesAsync() + { + return await NavigateAppAsync( + new IpcAppNavigateRequest + { + Page = "updates", + } + ); + } + + public async Task ShowPackageAsync( + string packageId, + string packageSource + ) + { + return await SendCommandAsync( + IpcHttpRoutes.Path("/packages/show"), + new Dictionary + { + ["packageId"] = packageId, + ["packageSource"] = packageSource, + } + ); + } + + public async Task GetVersionAsync() + { + return (await GetStatusAsync()).BuildNumber; + } + + public async Task> SearchPackagesAsync( + string query, + string? managerName = null, + int? maxResults = null + ) + { + Dictionary parameters = new() { ["query"] = query }; + if (!string.IsNullOrWhiteSpace(managerName)) + { + parameters["manager"] = managerName; + } + + if (maxResults.HasValue) + { + parameters["maxResults"] = maxResults.Value.ToString(); + } + + return await ReadAuthenticatedJsonAsync>( + HttpMethod.Get, + IpcHttpRoutes.Path("/packages/search"), + parameters + ) ?? []; + } + + public async Task> ListInstalledPackagesAsync( + string? managerName = null + ) + { + Dictionary? parameters = null; + if (!string.IsNullOrWhiteSpace(managerName)) + { + parameters = new Dictionary { ["manager"] = managerName }; + } + + return await ReadAuthenticatedJsonAsync>( + HttpMethod.Get, + IpcHttpRoutes.Path("/packages/installed"), + parameters + ) ?? []; + } + + public async Task> ListUpgradablePackagesAsync( + string? managerName = null + ) + { + Dictionary? parameters = null; + if (!string.IsNullOrWhiteSpace(managerName)) + { + parameters = new Dictionary { ["manager"] = managerName }; + } + + return await ReadAuthenticatedJsonAsync>( + HttpMethod.Get, + IpcHttpRoutes.Path("/packages/updates"), + parameters + ) ?? []; + } + + public async Task GetPackageDetailsAsync( + IpcPackageActionRequest request + ) + { + return await ReadAuthenticatedJsonAsync( + HttpMethod.Get, + IpcHttpRoutes.Path("/packages/details"), + BuildPackageQueryParameters(request) + ); + } + + public async Task> GetPackageVersionsAsync( + IpcPackageActionRequest request + ) + { + return await ReadAuthenticatedJsonAsync>( + HttpMethod.Get, + IpcHttpRoutes.Path("/packages/versions"), + BuildPackageQueryParameters(request) + ) ?? []; + } + + public async Task> ListIgnoredUpdatesAsync() + { + return await ReadAuthenticatedJsonAsync>( + HttpMethod.Get, + IpcHttpRoutes.Path("/packages/ignored") + ) ?? []; + } + + public async Task IgnorePackageUpdateAsync( + IpcPackageActionRequest request + ) + { + return await SendCommandAsync( + IpcHttpRoutes.Path("/packages/ignore"), + BuildPackageQueryParameters(request) + ); + } + + public async Task RemoveIgnoredUpdateAsync( + IpcPackageActionRequest request + ) + { + return await SendCommandAsync( + IpcHttpRoutes.Path("/packages/unignore"), + BuildPackageQueryParameters(request) + ); + } + + public async Task UpdateAllAsync() + { + return await SendCommandAsync(IpcHttpRoutes.Path("/packages/update-all")); + } + + public async Task UpdateManagerAsync(string managerName) + { + return await SendCommandAsync( + IpcHttpRoutes.Path("/packages/update-manager"), + new Dictionary { ["manager"] = managerName } + ); + } + + public async Task InstallPackageAsync( + IpcPackageActionRequest request + ) + { + return await SendPackageOperationAsync(IpcHttpRoutes.Path("/packages/install"), request); + } + + public async Task DownloadPackageAsync( + IpcPackageActionRequest request + ) + { + return await SendPackageOperationAsync( + IpcHttpRoutes.Path("/packages/download"), + request + ); + } + + public async Task ReinstallPackageAsync( + IpcPackageActionRequest request + ) + { + return await SendPackageOperationAsync( + IpcHttpRoutes.Path("/packages/reinstall"), + request + ); + } + + public async Task UpdatePackageAsync( + IpcPackageActionRequest request + ) + { + return await SendPackageOperationAsync(IpcHttpRoutes.Path("/packages/update"), request); + } + + public async Task UninstallPackageAsync( + IpcPackageActionRequest request + ) + { + return await SendPackageOperationAsync( + IpcHttpRoutes.Path("/packages/uninstall"), + request + ); + } + + public async Task UninstallThenReinstallPackageAsync( + IpcPackageActionRequest request + ) + { + return await SendPackageOperationAsync( + IpcHttpRoutes.Path("/packages/uninstall-then-reinstall"), + request + ); + } + + private async Task SendAuthenticatedAsync( + HttpMethod method, + string relativePath, + IReadOnlyDictionary? queryParameters = null, + HttpContent? requestContent = null + ) + { + EnsureTokenAvailable(); + + Dictionary parameters = new(queryParameters ?? new Dictionary()) + { + ["token"] = _token, + }; + + return await SendAsync(method, relativePath, parameters, requestContent); + } + + private async Task SendAsync( + HttpMethod method, + string relativePath, + IReadOnlyDictionary? queryParameters = null, + HttpContent? requestContent = null + ) + { + using var timeout = new CancellationTokenSource(GetRequestTimeout(method, relativePath)); + using var request = new HttpRequestMessage(method, BuildRelativeUri(relativePath, queryParameters)); + request.Content = requestContent; + using var response = await _httpClient.SendAsync(request, timeout.Token); + string content = await response.Content.ReadAsStringAsync(); + + if (!response.IsSuccessStatusCode) + { + throw new InvalidOperationException( + string.IsNullOrWhiteSpace(content) ? response.ReasonPhrase : content + ); + } + + return content; + } + + private async Task ReadAuthenticatedJsonAsync( + HttpMethod method, + string relativePath, + IReadOnlyDictionary? queryParameters = null + ) + { + string json = await SendAuthenticatedAsync(method, relativePath, queryParameters); + return IpcJson.Deserialize(json); + } + + private async Task ReadAuthenticatedJsonWithBodyAsync( + string relativePath, + TBody body, + IReadOnlyDictionary? queryParameters = null + ) + { + using var content = IpcJson.CreateContent(body); + string json = await SendAuthenticatedAsync(HttpMethod.Post, relativePath, queryParameters, content); + return IpcJson.Deserialize(json); + } + + private async Task SendPackageOperationAsync( + string relativePath, + IpcPackageActionRequest request + ) + { + return await ReadAuthenticatedJsonAsync( + HttpMethod.Post, + relativePath, + BuildPackageQueryParameters(request) + ) + ?? new IpcPackageOperationResult + { + Status = "error", + Message = "The IPC API returned an empty response.", + }; + } + + private async Task SendSourceOperationAsync( + string relativePath, + IpcSourceRequest request + ) + { + Dictionary parameters = new() + { + ["manager"] = request.ManagerName, + ["name"] = request.SourceName, + }; + + if (!string.IsNullOrWhiteSpace(request.SourceUrl)) + { + parameters["url"] = request.SourceUrl; + } + + return await ReadAuthenticatedJsonAsync( + HttpMethod.Post, + relativePath, + parameters + ) + ?? new IpcSourceOperationResult + { + Status = "error", + Message = "The IPC API returned an empty response.", + }; + } + + private async Task SendDesktopShortcutOperationAsync( + string relativePath, + IpcDesktopShortcutRequest request + ) + { + Dictionary parameters = new() { ["path"] = request.Path }; + if (!string.IsNullOrWhiteSpace(request.Status)) + { + parameters["status"] = request.Status; + } + + return await ReadAuthenticatedJsonAsync( + HttpMethod.Post, + relativePath, + parameters + ) + ?? new IpcDesktopShortcutOperationResult + { + Status = "error", + Message = "The IPC API returned an empty response.", + }; + } + + private async Task SendManagerMaintenanceActionAsync( + string relativePath, + IpcManagerMaintenanceRequest request + ) + { + return await ReadAuthenticatedJsonWithBodyAsync< + IpcManagerMaintenanceActionResult, + IpcManagerMaintenanceRequest + >(relativePath, request) + ?? new IpcManagerMaintenanceActionResult + { + Status = "error", + Message = "The IPC API returned an empty response.", + }; + } + + private async Task SendCommandAsync( + string relativePath, + IReadOnlyDictionary? queryParameters = null + ) + { + return await ReadAuthenticatedJsonAsync( + HttpMethod.Post, + relativePath, + queryParameters + ) + ?? new IpcCommandResult + { + Status = "error", + Message = "The IPC API returned an empty response.", + }; + } + + private static Dictionary BuildPackageQueryParameters( + IpcPackageActionRequest request + ) + { + Dictionary parameters = new() { ["packageId"] = request.PackageId }; + + if (!string.IsNullOrWhiteSpace(request.ManagerName)) + { + parameters["manager"] = request.ManagerName; + } + + if (!string.IsNullOrWhiteSpace(request.PackageSource)) + { + parameters["packageSource"] = request.PackageSource; + } + + if (!string.IsNullOrWhiteSpace(request.Version)) + { + parameters["version"] = request.Version; + } + + if (!string.IsNullOrWhiteSpace(request.Scope)) + { + parameters["scope"] = request.Scope; + } + + if (request.PreRelease.HasValue) + { + parameters["preRelease"] = request.PreRelease.Value ? "true" : "false"; + } + + if (request.Elevated.HasValue) + { + parameters["elevated"] = request.Elevated.Value ? "true" : "false"; + } + + if (request.Interactive.HasValue) + { + parameters["interactive"] = request.Interactive.Value ? "true" : "false"; + } + + if (request.SkipHash.HasValue) + { + parameters["skipHash"] = request.SkipHash.Value ? "true" : "false"; + } + + if (request.RemoveData.HasValue) + { + parameters["removeData"] = request.RemoveData.Value ? "true" : "false"; + } + + if (request.WaitForCompletion.HasValue) + { + parameters["wait"] = request.WaitForCompletion.Value ? "true" : "false"; + } + + if (!string.IsNullOrWhiteSpace(request.Architecture)) + { + parameters["architecture"] = request.Architecture; + } + + if (!string.IsNullOrWhiteSpace(request.InstallLocation)) + { + parameters["location"] = request.InstallLocation; + } + + if (!string.IsNullOrWhiteSpace(request.OutputPath)) + { + parameters["outputPath"] = request.OutputPath; + } + + return parameters; + } + + private static Dictionary BuildAppNavigateParameters( + IpcAppNavigateRequest request + ) + { + Dictionary parameters = new() + { + ["page"] = IpcAppPages.NormalizePageName(request.Page), + }; + + if (!string.IsNullOrWhiteSpace(request.ManagerName)) + { + parameters["manager"] = request.ManagerName; + } + + if (!string.IsNullOrWhiteSpace(request.HelpAttachment)) + { + parameters["helpAttachment"] = request.HelpAttachment; + } + + return parameters; + } + + private static HttpClient CreateHttpClient(IpcTransportOptions options) + { + if (options.TransportKind == IpcTransportKind.NamedPipe) + { + var handler = new SocketsHttpHandler + { + UseProxy = false, + ConnectCallback = async (_, cancellationToken) => + { + if (OperatingSystem.IsWindows()) + { + var pipeClient = new NamedPipeClientStream( + ".", + options.NamedPipeName, + PipeDirection.InOut, + PipeOptions.Asynchronous + ); + await pipeClient.ConnectAsync(cancellationToken); + return pipeClient; + } + + string socketPath = options.NamedPipePath + ?? throw new InvalidOperationException( + "The Unix socket path is not available for the named-pipe transport." + ); + var socket = new Socket(AddressFamily.Unix, SocketType.Stream, ProtocolType.Unspecified); + await socket.ConnectAsync( + new UnixDomainSocketEndPoint(socketPath), + cancellationToken + ); + return new NetworkStream(socket, ownsSocket: true); + }, + }; + + return new HttpClient(handler) + { + BaseAddress = options.BaseAddress, + Timeout = Timeout.InfiniteTimeSpan, + }; + } + + return new HttpClient + { + BaseAddress = options.BaseAddress, + Timeout = Timeout.InfiniteTimeSpan, + }; + } + + private static TimeSpan GetRequestTimeout(HttpMethod method, string relativePath) + { + if (IpcHttpRoutes.Matches(relativePath, "/status")) + { + return TimeSpan.FromSeconds(5); + } + + if (IpcHttpRoutes.StartsWith(relativePath, "/packages/")) + { + return method == HttpMethod.Post + ? TimeSpan.FromMinutes(5) + : TimeSpan.FromSeconds(30); + } + + if (IpcHttpRoutes.StartsWith(relativePath, "/bundles/install")) + { + return TimeSpan.FromMinutes(5); + } + + if (IpcHttpRoutes.StartsWith(relativePath, "/managers/maintenance/action")) + { + return TimeSpan.FromMinutes(10); + } + + if (IpcHttpRoutes.StartsWith(relativePath, "/backups/github/sign-in/complete")) + { + return TimeSpan.FromMinutes(5); + } + + if ( + IpcHttpRoutes.StartsWith(relativePath, "/backups/local/create") + || IpcHttpRoutes.StartsWith(relativePath, "/backups/cloud/create") + ) + { + return TimeSpan.FromMinutes(2); + } + + if (IpcHttpRoutes.StartsWith(relativePath, "/backups/")) + { + return method == HttpMethod.Post ? TimeSpan.FromMinutes(1) : TimeSpan.FromSeconds(30); + } + + if (IpcHttpRoutes.StartsWith(relativePath, "/bundles/")) + { + return method == HttpMethod.Post ? TimeSpan.FromMinutes(1) : TimeSpan.FromSeconds(15); + } + + if (IpcHttpRoutes.StartsWith(relativePath, "/sources/")) + { + return method == HttpMethod.Post + ? TimeSpan.FromMinutes(2) + : TimeSpan.FromSeconds(30); + } + + if ( + IpcHttpRoutes.StartsWith(relativePath, "/managers") + || IpcHttpRoutes.StartsWith(relativePath, "/settings") + || IpcHttpRoutes.StartsWith(relativePath, "/secure-settings") + || IpcHttpRoutes.StartsWith(relativePath, "/desktop-shortcuts") + || IpcHttpRoutes.StartsWith(relativePath, "/logs/") + ) + { + return TimeSpan.FromSeconds(15); + } + + return TimeSpan.FromSeconds(5); + } + + private static bool IsConnectivityException(Exception exception) + { + return exception is HttpRequestException + or IOException + or TaskCanceledException + or OperationCanceledException; + } + + private static IpcEndpointRegistration? SelectLiveRegistration( + IEnumerable candidates + ) + { + foreach (IpcEndpointRegistration candidate in candidates) + { + if (candidate.ProcessId > 0 && !IsProcessRunning(candidate.ProcessId)) + { + IpcTransportOptions.DeletePersistedMetadata(candidate.SessionId); + continue; + } + + if (IsEndpointAlive(candidate)) + { + return candidate; + } + + if (candidate.ProcessId <= 0) + { + IpcTransportOptions.DeletePersistedMetadata(candidate.SessionId); + } + } + + return null; + } + + private static bool IsEndpointAlive(IpcEndpointRegistration candidate) + { + try + { + using var client = new IpcClient(candidate.ToTransportOptions(), candidate.Token); + return client.GetStatusAsync().GetAwaiter().GetResult().Running; + } + catch (Exception ex) when (IsConnectivityException(ex) || ex is InvalidOperationException) + { + Logger.Debug( + $"IPC API registration {candidate.SessionId} probe failed: {ex.Message}" + ); + return false; + } + } + + private static bool IsProcessRunning(int processId) + { + try + { + using Process process = Process.GetProcessById(processId); + return !process.HasExited; + } + catch (Exception) + { + return false; + } + } + + private void EnsureTokenAvailable() + { + if (string.IsNullOrWhiteSpace(_token)) + { + throw new InvalidOperationException( + "The IPC API token is not available. Start UniGetUI and try again." + ); + } + } + + private static string BuildRelativeUri( + string relativePath, + IReadOnlyDictionary? queryParameters + ) + { + if (queryParameters is null || queryParameters.Count == 0) + { + return relativePath; + } + + string query = string.Join( + "&", + queryParameters.Select(pair => + $"{Uri.EscapeDataString(pair.Key)}={Uri.EscapeDataString(pair.Value)}" + ) + ); + + return $"{relativePath}?{query}"; + } + + public void Dispose() + { + _httpClient.Dispose(); + } +} + +public sealed class IpcCommandResult +{ + public string Status { get; set; } = "success"; + public string Command { get; set; } = ""; + public string? Message { get; set; } + + public static IpcCommandResult Success(string command) + { + return new IpcCommandResult { Command = command }; + } +} diff --git a/src/UniGetUI.Interface.IpcApi/IpcDesktopShortcutsApi.cs b/src/UniGetUI.Interface.IpcApi/IpcDesktopShortcutsApi.cs new file mode 100644 index 0000000..6573e11 --- /dev/null +++ b/src/UniGetUI.Interface.IpcApi/IpcDesktopShortcutsApi.cs @@ -0,0 +1,134 @@ +using UniGetUI.PackageEngine.Classes.Packages.Classes; + +namespace UniGetUI.Interface; + +public sealed class IpcDesktopShortcutInfo +{ + public string Path { get; set; } = ""; + public string Name { get; set; } = ""; + public string Status { get; set; } = ""; + public bool ExistsOnDisk { get; set; } + public bool IsTracked { get; set; } + public bool IsPendingReview { get; set; } +} + +public sealed class IpcDesktopShortcutRequest +{ + public string Path { get; set; } = ""; + public string? Status { get; set; } +} + +public sealed class IpcDesktopShortcutOperationResult +{ + public string Status { get; set; } = "success"; + public string Command { get; set; } = ""; + public string? Message { get; set; } + public IpcDesktopShortcutInfo? Shortcut { get; set; } +} + +public static class IpcDesktopShortcutsApi +{ + public static IReadOnlyList ListShortcuts() + { + var trackedShortcuts = DesktopShortcutsDatabase.GetDatabase(); + HashSet allShortcuts = + [ + .. DesktopShortcutsDatabase.GetAllShortcuts(), + .. DesktopShortcutsDatabase.GetUnknownShortcuts(), + ]; + + return allShortcuts + .OrderBy(path => System.IO.Path.GetFileName(path), StringComparer.OrdinalIgnoreCase) + .ThenBy(path => path, StringComparer.OrdinalIgnoreCase) + .Select(path => ToShortcutInfo(path, trackedShortcuts)) + .ToArray(); + } + + public static IpcDesktopShortcutOperationResult SetShortcut( + IpcDesktopShortcutRequest request + ) + { + string shortcutPath = NormalizeShortcutPath(request.Path); + string shortcutStatus = request.Status?.Trim().ToLowerInvariant() ?? ""; + + DesktopShortcutsDatabase.Status status = shortcutStatus switch + { + "delete" => DesktopShortcutsDatabase.Status.Delete, + "keep" => DesktopShortcutsDatabase.Status.Maintain, + _ => throw new InvalidOperationException( + "The status parameter must be either keep or delete." + ), + }; + + DesktopShortcutsDatabase.AddToDatabase(shortcutPath, status); + DesktopShortcutsDatabase.RemoveFromUnknownShortcuts(shortcutPath); + + if (status is DesktopShortcutsDatabase.Status.Delete && File.Exists(shortcutPath)) + { + DesktopShortcutsDatabase.DeleteFromDisk(shortcutPath); + } + + return new IpcDesktopShortcutOperationResult + { + Command = "set-desktop-shortcut", + Shortcut = ToShortcutInfo(shortcutPath), + }; + } + + public static IpcDesktopShortcutOperationResult ResetShortcut( + IpcDesktopShortcutRequest request + ) + { + string shortcutPath = NormalizeShortcutPath(request.Path); + DesktopShortcutsDatabase.AddToDatabase(shortcutPath, DesktopShortcutsDatabase.Status.Unknown); + + return new IpcDesktopShortcutOperationResult + { + Command = "reset-desktop-shortcut", + Shortcut = ToShortcutInfo(shortcutPath), + }; + } + + public static IpcCommandResult ResetAllShortcuts() + { + DesktopShortcutsDatabase.ResetDatabase(); + return IpcCommandResult.Success("reset-desktop-shortcuts"); + } + + private static IpcDesktopShortcutInfo ToShortcutInfo( + string shortcutPath, + IReadOnlyDictionary? trackedShortcuts = null + ) + { + trackedShortcuts ??= DesktopShortcutsDatabase.GetDatabase(); + string fileName = System.IO.Path.GetFileName(shortcutPath); + + return new IpcDesktopShortcutInfo + { + Path = shortcutPath, + Name = string.IsNullOrWhiteSpace(fileName) + ? shortcutPath + : System.IO.Path.GetFileNameWithoutExtension(fileName), + Status = DesktopShortcutsDatabase.GetStatus(shortcutPath) switch + { + DesktopShortcutsDatabase.Status.Delete => "delete", + DesktopShortcutsDatabase.Status.Maintain => "keep", + _ => "unknown", + }, + ExistsOnDisk = File.Exists(shortcutPath), + IsTracked = trackedShortcuts.ContainsKey(shortcutPath), + IsPendingReview = DesktopShortcutsDatabase.GetUnknownShortcuts().Contains(shortcutPath), + }; + } + + private static string NormalizeShortcutPath(string shortcutPath) + { + string normalizedPath = shortcutPath.Trim().Trim('"').Trim('\''); + if (string.IsNullOrWhiteSpace(normalizedPath)) + { + throw new InvalidOperationException("The path parameter is required."); + } + + return normalizedPath; + } +} diff --git a/src/UniGetUI.Interface.IpcApi/IpcHttpRoutes.cs b/src/UniGetUI.Interface.IpcApi/IpcHttpRoutes.cs new file mode 100644 index 0000000..cb1a6ba --- /dev/null +++ b/src/UniGetUI.Interface.IpcApi/IpcHttpRoutes.cs @@ -0,0 +1,30 @@ +namespace UniGetUI.Interface; + +internal static class IpcHttpRoutes +{ + public const string Prefix = "/uniget"; + public const string Version = "/v1"; + public const string ApiRoot = Prefix + Version; + + public static string Path(string relativePath) + { + ArgumentException.ThrowIfNullOrWhiteSpace(relativePath); + + return relativePath.StartsWith("/", StringComparison.Ordinal) + ? ApiRoot + relativePath + : throw new ArgumentException( + "IPC route fragments must start with '/'.", + nameof(relativePath) + ); + } + + public static bool Matches(string path, string relativePath) + { + return path.Equals(Path(relativePath), StringComparison.OrdinalIgnoreCase); + } + + public static bool StartsWith(string path, string relativePathPrefix) + { + return path.StartsWith(Path(relativePathPrefix), StringComparison.OrdinalIgnoreCase); + } +} diff --git a/src/UniGetUI.Interface.IpcApi/IpcJson.cs b/src/UniGetUI.Interface.IpcApi/IpcJson.cs new file mode 100644 index 0000000..1dbe68c --- /dev/null +++ b/src/UniGetUI.Interface.IpcApi/IpcJson.cs @@ -0,0 +1,166 @@ +using System.Text; +using System.Text.Json; +using System.Text.Json.Serialization; +using System.Text.Json.Serialization.Metadata; +using System.Threading; +using Microsoft.AspNetCore.Http; + +namespace UniGetUI.Interface; + +internal static class IpcJson +{ + public static JsonSerializerOptions Options { get; } = new(JsonSerializerDefaults.Web) + { + WriteIndented = true, + TypeInfoResolver = IpcJsonContext.Default, + }; + + public static string Serialize(T value) + { + return JsonSerializer.Serialize(value, GetTypeInfo()); + } + + public static T? Deserialize(string json) + { + return JsonSerializer.Deserialize(json, GetTypeInfo()); + } + + internal static JsonTypeInfo GetTypeInfo() + { + return (JsonTypeInfo?)IpcJsonContext.Default.GetTypeInfo(typeof(T)) + ?? throw new InvalidOperationException( + $"IPC JSON metadata for {typeof(T).FullName} was not generated." + ); + } + + public static HttpContent CreateContent(T value) + { + return new StringContent( + Serialize(value), + Encoding.UTF8, + "application/json" + ); + } + + public static Task WriteAsync(HttpResponse response, T value) + { + response.ContentType = "application/json; charset=utf-8"; + return response.WriteAsync(Serialize(value)); + } +} + +internal static class IpcHttpResponseJsonExtensions +{ + internal static Task WriteAsJsonAsync( + this HttpResponse response, + TValue value, + JsonSerializerOptions? options, + CancellationToken cancellationToken = default) + { + ArgumentNullException.ThrowIfNull(response); + JsonTypeInfo? typeInfo = options?.GetTypeInfo(typeof(TValue)) as JsonTypeInfo; + string json = JsonSerializer.Serialize(value, typeInfo ?? IpcJson.GetTypeInfo()); + response.ContentType = "application/json; charset=utf-8"; + return response.WriteAsync(json, cancellationToken); + } +} + +[JsonSourceGenerationOptions( + PropertyNamingPolicy = JsonKnownNamingPolicy.CamelCase, + WriteIndented = true +)] +[JsonSerializable(typeof(IpcAppInfo))] +[JsonSerializable(typeof(IpcAppNavigateRequest))] +[JsonSerializable(typeof(IpcBackupStatus))] +[JsonSerializable(typeof(IpcGitHubAuthInfo))] +[JsonSerializable(typeof(IpcBackupCommandResult))] +[JsonSerializable(typeof(IpcLocalBackupResult))] +[JsonSerializable(typeof(IpcCloudBackupEntry))] +[JsonSerializable(typeof(IpcCloudBackupUploadResult))] +[JsonSerializable(typeof(IpcCloudBackupRequest))] +[JsonSerializable(typeof(IpcCloudBackupContentResult))] +[JsonSerializable(typeof(IpcCloudBackupRestoreResult))] +[JsonSerializable(typeof(IpcGitHubDeviceFlowRequest))] +[JsonSerializable(typeof(IpcGitHubAuthResult))] +[JsonSerializable(typeof(IpcBundleInfo))] +[JsonSerializable(typeof(IpcBundlePackageInfo))] +[JsonSerializable(typeof(IpcBundleImportRequest))] +[JsonSerializable(typeof(IpcBundleExportRequest))] +[JsonSerializable(typeof(IpcBundlePackageRequest))] +[JsonSerializable(typeof(IpcBundleInstallRequest))] +[JsonSerializable(typeof(IpcBundleSecurityEntry))] +[JsonSerializable(typeof(IpcBundleCommandResult))] +[JsonSerializable(typeof(IpcBundleImportResult))] +[JsonSerializable(typeof(IpcBundleExportResult))] +[JsonSerializable(typeof(IpcBundlePackageOperationResult))] +[JsonSerializable(typeof(IpcBundleInstallResult))] +[JsonSerializable(typeof(IpcCommandResult))] +[JsonSerializable(typeof(IpcDesktopShortcutInfo))] +[JsonSerializable(typeof(IpcDesktopShortcutRequest))] +[JsonSerializable(typeof(IpcDesktopShortcutOperationResult))] +[JsonSerializable(typeof(IpcAppLogEntry))] +[JsonSerializable(typeof(IpcOperationHistoryEntry))] +[JsonSerializable(typeof(IpcManagerLogTask))] +[JsonSerializable(typeof(IpcManagerLogInfo))] +[JsonSerializable(typeof(IpcManagerMaintenanceInfo))] +[JsonSerializable(typeof(IpcManagerMaintenanceRequest))] +[JsonSerializable(typeof(IpcManagerMaintenanceActionResult))] +[JsonSerializable(typeof(IpcManagerCapabilitiesInfo))] +[JsonSerializable(typeof(IpcManagerInfo))] +[JsonSerializable(typeof(IpcSourceInfo))] +[JsonSerializable(typeof(IpcSourceRequest))] +[JsonSerializable(typeof(IpcSourceOperationResult))] +[JsonSerializable(typeof(IpcSettingInfo))] +[JsonSerializable(typeof(IpcSettingValueRequest))] +[JsonSerializable(typeof(IpcManagerToggleRequest))] +[JsonSerializable(typeof(IpcOperationOutputLine))] +[JsonSerializable(typeof(IpcOperationInfo))] +[JsonSerializable(typeof(IpcOperationDetails))] +[JsonSerializable(typeof(IpcOperationOutputResult))] +[JsonSerializable(typeof(IpcPackageInfo))] +[JsonSerializable(typeof(IpcPackageActionRequest))] +[JsonSerializable(typeof(IpcPackageOperationResult))] +[JsonSerializable(typeof(IpcPackageDependencyInfo))] +[JsonSerializable(typeof(IpcPackageDetailsInfo))] +[JsonSerializable(typeof(IpcIgnoredUpdateInfo))] +[JsonSerializable(typeof(IpcSecureSettingInfo))] +[JsonSerializable(typeof(IpcSecureSettingRequest))] +[JsonSerializable(typeof(IpcStatus))] +[JsonSerializable(typeof(IpcEndpointRegistration))] +[JsonSerializable(typeof(IReadOnlyList))] +[JsonSerializable(typeof(string[]))] +[JsonSerializable(typeof(IReadOnlyList))] +[JsonSerializable(typeof(IReadOnlyList))] +[JsonSerializable(typeof(IReadOnlyList))] +[JsonSerializable(typeof(IReadOnlyList))] +[JsonSerializable(typeof(IReadOnlyList))] +[JsonSerializable(typeof(IReadOnlyList))] +[JsonSerializable(typeof(IReadOnlyList))] +[JsonSerializable(typeof(IReadOnlyList))] +[JsonSerializable(typeof(IReadOnlyList))] +[JsonSerializable(typeof(IReadOnlyList))] +[JsonSerializable(typeof(IReadOnlyList))] +[JsonSerializable(typeof(IReadOnlyList))] +[JsonSerializable(typeof(IReadOnlyList))] +[JsonSerializable(typeof(IReadOnlyList))] +[JsonSerializable(typeof(IReadOnlyList))] +[JsonSerializable(typeof(IReadOnlyList))] +[JsonSerializable(typeof(IReadOnlyList))] +[JsonSerializable(typeof(IpcManagerInfo[]))] +[JsonSerializable(typeof(IpcSourceInfo[]))] +[JsonSerializable(typeof(IpcSettingInfo[]))] +[JsonSerializable(typeof(IpcSecureSettingInfo[]))] +[JsonSerializable(typeof(IpcDesktopShortcutInfo[]))] +[JsonSerializable(typeof(IpcAppLogEntry[]))] +[JsonSerializable(typeof(IpcOperationHistoryEntry[]))] +[JsonSerializable(typeof(IpcManagerLogInfo[]))] +[JsonSerializable(typeof(IpcOperationInfo[]))] +[JsonSerializable(typeof(IpcOperationOutputLine[]))] +[JsonSerializable(typeof(IpcPackageInfo[]))] +[JsonSerializable(typeof(IpcPackageDependencyInfo[]))] +[JsonSerializable(typeof(IpcIgnoredUpdateInfo[]))] +[JsonSerializable(typeof(IpcBundlePackageInfo[]))] +[JsonSerializable(typeof(IpcBundleSecurityEntry[]))] +[JsonSerializable(typeof(IpcPackageOperationResult[]))] +[JsonSerializable(typeof(IpcCloudBackupEntry[]))] +internal sealed partial class IpcJsonContext : JsonSerializerContext; diff --git a/src/UniGetUI.Interface.IpcApi/IpcLogsApi.cs b/src/UniGetUI.Interface.IpcApi/IpcLogsApi.cs new file mode 100644 index 0000000..7caa9b9 --- /dev/null +++ b/src/UniGetUI.Interface.IpcApi/IpcLogsApi.cs @@ -0,0 +1,112 @@ +using UniGetUI.Core.Logging; +using UniGetUI.Core.SettingsEngine; +using UniGetUI.PackageEngine; +using UniGetUI.PackageEngine.Interfaces; + +namespace UniGetUI.Interface; + +public sealed class IpcAppLogEntry +{ + public string Time { get; set; } = ""; + public string Severity { get; set; } = ""; + public string Content { get; set; } = ""; +} + +public sealed class IpcOperationHistoryEntry +{ + public string Content { get; set; } = ""; +} + +public sealed class IpcManagerLogTask +{ + public int Index { get; set; } + public string[] Lines { get; set; } = []; +} + +public sealed class IpcManagerLogInfo +{ + public string Name { get; set; } = ""; + public string DisplayName { get; set; } = ""; + public string Version { get; set; } = ""; + public IpcManagerLogTask[] Tasks { get; set; } = []; +} + +public static class IpcLogsApi +{ + public static IReadOnlyList ListAppLog(int level = 4) + { + return Logger.GetLogs() + .Where(entry => !string.IsNullOrWhiteSpace(entry.Content) && !ShouldSkip(entry.Severity, level)) + .Select(entry => new IpcAppLogEntry + { + Time = entry.Time.ToString("O"), + Severity = entry.Severity.ToString().ToLowerInvariant(), + Content = entry.Content, + }) + .ToArray(); + } + + public static IReadOnlyList ListOperationHistory() + { + return Settings.GetValue(Settings.K.OperationHistory) + .Split('\n') + .Select(line => line.Replace("\r", "").Replace("\n", "").Trim()) + .Where(line => !string.IsNullOrWhiteSpace(line)) + .Select(line => new IpcOperationHistoryEntry { Content = line }) + .ToArray(); + } + + public static IReadOnlyList ListManagerLogs( + string? managerName = null, + bool verbose = false + ) + { + return ResolveManagers(managerName) + .Select(manager => new IpcManagerLogInfo + { + Name = IpcManagerSettingsApi.GetPublicManagerId(manager), + DisplayName = manager.DisplayName, + Version = manager.Status.Version, + Tasks = manager.TaskLogger.Operations + .Select((operation, index) => new IpcManagerLogTask + { + Index = index, + Lines = operation + .AsColoredString(verbose) + .Where(line => !string.IsNullOrWhiteSpace(line)) + .Select(StripColorCode) + .Where(line => !string.IsNullOrWhiteSpace(line)) + .ToArray(), + }) + .Where(task => task.Lines.Length > 0) + .ToArray(), + }) + .ToArray(); + } + + private static IReadOnlyList ResolveManagers(string? managerName) + { + var managers = IpcManagerSettingsApi.ResolveManagers(managerName) + .OrderBy(manager => manager.DisplayName, StringComparer.OrdinalIgnoreCase) + .ToArray(); + + return managers; + } + + private static bool ShouldSkip(LogEntry.SeverityLevel severity, int level) => + level switch + { + <= 1 => severity != LogEntry.SeverityLevel.Error, + 2 => severity is LogEntry.SeverityLevel.Debug + or LogEntry.SeverityLevel.Info + or LogEntry.SeverityLevel.Success, + 3 => severity is LogEntry.SeverityLevel.Debug or LogEntry.SeverityLevel.Info, + 4 => severity == LogEntry.SeverityLevel.Debug, + _ => false, + }; + + private static string StripColorCode(string line) + { + return line.Length > 1 && char.IsDigit(line[0]) ? line[1..] : line; + } +} diff --git a/src/UniGetUI.Interface.IpcApi/IpcManagerMaintenanceApi.cs b/src/UniGetUI.Interface.IpcApi/IpcManagerMaintenanceApi.cs new file mode 100644 index 0000000..bef951b --- /dev/null +++ b/src/UniGetUI.Interface.IpcApi/IpcManagerMaintenanceApi.cs @@ -0,0 +1,382 @@ +using System.Diagnostics; +using UniGetUI.Core.Data; +using UniGetUI.Core.SettingsEngine; +using UniGetUI.Core.SettingsEngine.SecureSettings; +using UniGetUI.PackageEngine.Interfaces; +using UniGetUI.PackageEngine.Managers.VcpkgManager; + +namespace UniGetUI.Interface; + +public sealed class IpcManagerMaintenanceInfo +{ + public string Manager { get; set; } = ""; + public string DisplayName { get; set; } = ""; + public bool Enabled { get; set; } + public bool Ready { get; set; } + public bool CustomExecutablePathsAllowed { get; set; } + public string? ConfiguredExecutablePath { get; set; } + public string EffectiveExecutablePath { get; set; } = ""; + public IReadOnlyList CandidateExecutablePaths { get; set; } = []; + public IReadOnlyList SupportedActions { get; set; } = []; + public bool? UseBundledWinGet { get; set; } + public bool? UseSystemChocolatey { get; set; } + public bool? ScoopCleanupOnLaunch { get; set; } + public bool UpdateNotificationsSuppressed { get; set; } + public string? DefaultVcpkgTriplet { get; set; } + public IReadOnlyList AvailableVcpkgTriplets { get; set; } = []; + public string? CustomVcpkgRoot { get; set; } +} + +public sealed class IpcManagerMaintenanceRequest +{ + public string ManagerName { get; set; } = ""; + public string? Action { get; set; } + public string? Path { get; set; } + public bool Confirm { get; set; } +} + +public sealed class IpcManagerMaintenanceActionResult +{ + public string Status { get; set; } = "success"; + public string Command { get; set; } = ""; + public string Manager { get; set; } = ""; + public string Action { get; set; } = ""; + public string OperationStatus { get; set; } = ""; + public string? Message { get; set; } + public IpcManagerMaintenanceInfo Maintenance { get; set; } = new(); +} + +public static class IpcManagerMaintenanceApi +{ + public static IpcManagerMaintenanceInfo GetMaintenanceInfo(string managerName) + { + return ToMaintenanceInfo(IpcManagerSettingsApi.ResolveManager(managerName)); + } + + public static async Task ReloadManagerAsync( + IpcManagerMaintenanceRequest request + ) + { + ArgumentNullException.ThrowIfNull(request); + var manager = IpcManagerSettingsApi.ResolveManager(request.ManagerName); + await ReloadManagerAsync(manager); + return Success("reload-manager", manager, "reload", "completed"); + } + + public static async Task SetExecutablePathAsync( + IpcManagerMaintenanceRequest request + ) + { + ArgumentNullException.ThrowIfNull(request); + var manager = IpcManagerSettingsApi.ResolveManager(request.ManagerName); + if (!SecureSettings.Get(SecureSettings.K.AllowCustomManagerPaths)) + { + throw new InvalidOperationException( + "Custom manager paths are disabled by secure settings." + ); + } + + if (string.IsNullOrWhiteSpace(request.Path)) + { + throw new InvalidOperationException("The path field is required."); + } + + Settings.SetDictionaryItem(Settings.K.ManagerPaths, manager.Name, request.Path); + await ReloadManagerAsync(manager); + return Success( + "set-manager-executable", + manager, + "set-executable", + "completed", + $"Configured {manager.DisplayName} to use {request.Path}." + ); + } + + public static async Task ClearExecutablePathAsync( + IpcManagerMaintenanceRequest request + ) + { + ArgumentNullException.ThrowIfNull(request); + var manager = IpcManagerSettingsApi.ResolveManager(request.ManagerName); + Settings.RemoveDictionaryKey(Settings.K.ManagerPaths, manager.Name); + await ReloadManagerAsync(manager); + return Success( + "clear-manager-executable", + manager, + "clear-executable", + "completed", + $"Cleared the custom executable override for {manager.DisplayName}." + ); + } + + public static async Task RunActionAsync( + IpcManagerMaintenanceRequest request + ) + { + ArgumentNullException.ThrowIfNull(request); + var manager = IpcManagerSettingsApi.ResolveManager(request.ManagerName); + string action = request.Action?.Trim().ToLowerInvariant() + ?? throw new InvalidOperationException("The action field is required."); + + switch (action) + { + case "repair-winget": + EnsureConfirmed(request, action); + EnsureManager(manager, "WinGet"); + EnsureWindowsOnly(action); + await RunWindowsProcessAsync( + CoreData.PowerShell5, + "-ExecutionPolicy Bypass -NoLogo -NoProfile -Command \"& {" + + "cmd.exe /C \"\"rmdir /Q /S `\"%temp%\\WinGet`\"\"\"; " + + "cmd.exe /C \"\"`\"%localappdata%\\Microsoft\\WindowsApps\\winget.exe`\" source reset --force\"\"; " + + "taskkill /im winget.exe /f; " + + "taskkill /im WindowsPackageManagerServer.exe /f; " + + "Install-PackageProvider -Name NuGet -MinimumVersion 2.8.5.201 -Force; " + + "Install-Module Microsoft.WinGet.Client -Force -AllowClobber; " + + "Import-Module Microsoft.WinGet.Client; " + + "Repair-WinGetPackageManager -Force -Latest; " + + "Get-AppxPackage -Name 'Microsoft.DesktopAppInstaller' | Reset-AppxPackage; " + + "}\"", + runAsAdmin: true + ); + Settings.SetValue(Settings.K.WinGetCliToolPreference, "default"); + await ReloadManagerAsync(manager); + return Success( + "run-manager-action", + manager, + action, + "completed", + "WinGet repair completed." + ); + + case "install-scoop": + EnsureConfirmed(request, action); + EnsureManager(manager, "Scoop"); + EnsureWindowsOnly(action); + string installScriptPath = Path.Join( + CoreData.UniGetUIExecutableDirectory, + "Assets", + "Utilities", + "install_scoop.ps1" + ); + await RunWindowsProcessAsync( + CoreData.PowerShell5, + $"-ExecutionPolicy Bypass -File \"{installScriptPath}\"", + runAsAdmin: true + ); + await ReloadManagerAsync(manager); + return Success( + "run-manager-action", + manager, + action, + "completed", + "Scoop installation completed." + ); + + case "uninstall-scoop": + EnsureConfirmed(request, action); + EnsureManager(manager, "Scoop"); + EnsureWindowsOnly(action); + await RunWindowsProcessAsync( + CoreData.PowerShell5, + "-ExecutionPolicy Bypass -Command \"scoop uninstall -p scoop\"" + ); + await ReloadManagerAsync(manager); + return Success( + "run-manager-action", + manager, + action, + "completed", + "Scoop uninstall completed." + ); + + case "cleanup-scoop": + EnsureConfirmed(request, action); + EnsureManager(manager, "Scoop"); + EnsureWindowsOnly(action); + if (string.IsNullOrWhiteSpace(manager.Status.ExecutablePath)) + { + throw new InvalidOperationException("Scoop is not ready."); + } + + await RunWindowsProcessAsync( + manager.Status.ExecutablePath, + manager.Status.ExecutableCallArgs + " cache rm *" + ); + await RunWindowsProcessAsync( + manager.Status.ExecutablePath, + manager.Status.ExecutableCallArgs + " cleanup --all --cache" + ); + await RunWindowsProcessAsync( + manager.Status.ExecutablePath, + manager.Status.ExecutableCallArgs + " cleanup --all --global --cache", + runAsAdmin: true + ); + await ReloadManagerAsync(manager); + return Success( + "run-manager-action", + manager, + action, + "completed", + "Scoop cleanup completed." + ); + + default: + throw new InvalidOperationException( + $"The manager action \"{request.Action}\" is not supported." + ); + } + } + + private static IpcManagerMaintenanceInfo ToMaintenanceInfo(IPackageManager manager) + { + string? configuredExecutablePath = Settings.GetDictionaryItem( + Settings.K.ManagerPaths, + manager.Name + ); + + List supportedActions = + [ + "reload", + ]; + + if (manager.Name.Equals("WinGet", StringComparison.OrdinalIgnoreCase)) + { + supportedActions.Add("repair-winget"); + } + else if (manager.Name.Equals("Scoop", StringComparison.OrdinalIgnoreCase)) + { + supportedActions.Add("install-scoop"); + supportedActions.Add("uninstall-scoop"); + supportedActions.Add("cleanup-scoop"); + } + + IReadOnlyList triplets = manager.Name.Equals("vcpkg", StringComparison.OrdinalIgnoreCase) + ? Vcpkg.GetSystemTriplets().ToArray() + : []; + + string? customVcpkgRoot = manager.Name.Equals("vcpkg", StringComparison.OrdinalIgnoreCase) + && Settings.Get(Settings.K.CustomVcpkgRoot) + ? Settings.GetValue(Settings.K.CustomVcpkgRoot) + : null; + + return new IpcManagerMaintenanceInfo + { + Manager = IpcManagerSettingsApi.GetPublicManagerId(manager), + DisplayName = manager.DisplayName, + Enabled = manager.IsEnabled(), + Ready = manager.IsReady(), + CustomExecutablePathsAllowed = SecureSettings.Get(SecureSettings.K.AllowCustomManagerPaths), + ConfiguredExecutablePath = string.IsNullOrWhiteSpace(configuredExecutablePath) + ? null + : configuredExecutablePath, + EffectiveExecutablePath = manager.Status.ExecutablePath, + CandidateExecutablePaths = manager.FindCandidateExecutableFiles().ToArray(), + SupportedActions = supportedActions, + UseBundledWinGet = manager.Name.Equals("WinGet", StringComparison.OrdinalIgnoreCase) + ? string.Equals( + Settings.GetValue(Settings.K.WinGetCliToolPreference), + "pinget", + StringComparison.OrdinalIgnoreCase + ) + : null, + UseSystemChocolatey = manager.Name.Equals("Chocolatey", StringComparison.OrdinalIgnoreCase) + ? true + : null, + ScoopCleanupOnLaunch = manager.Name.Equals("Scoop", StringComparison.OrdinalIgnoreCase) + ? Settings.Get(Settings.K.EnableScoopCleanup) + : null, + UpdateNotificationsSuppressed = Settings.GetDictionaryItem( + Settings.K.DisabledPackageManagerNotifications, + manager.Name + ), + DefaultVcpkgTriplet = manager.Name.Equals("vcpkg", StringComparison.OrdinalIgnoreCase) + ? Settings.GetValue(Settings.K.DefaultVcpkgTriplet) + : null, + AvailableVcpkgTriplets = triplets, + CustomVcpkgRoot = string.IsNullOrWhiteSpace(customVcpkgRoot) ? null : customVcpkgRoot, + }; + } + + private static async Task ReloadManagerAsync(IPackageManager manager) + { + await Task.Run(manager.Initialize); + } + + private static async Task RunWindowsProcessAsync( + string fileName, + string arguments, + bool runAsAdmin = false + ) + { + using Process process = new() + { + StartInfo = new ProcessStartInfo + { + FileName = fileName, + Arguments = arguments, + UseShellExecute = runAsAdmin, + Verb = runAsAdmin ? "runas" : string.Empty, + CreateNoWindow = !runAsAdmin, + }, + }; + process.Start(); + await process.WaitForExitAsync(); + if (process.ExitCode != 0) + { + throw new InvalidOperationException( + $"The maintenance command exited with code {process.ExitCode}." + ); + } + } + + private static void EnsureConfirmed(IpcManagerMaintenanceRequest request, string action) + { + if (!request.Confirm) + { + throw new InvalidOperationException( + $"The manager action \"{action}\" requires confirm=true." + ); + } + } + + private static void EnsureManager(IPackageManager manager, string expectedName) + { + if (!manager.Name.Equals(expectedName, StringComparison.OrdinalIgnoreCase)) + { + throw new InvalidOperationException( + $"{expectedName} maintenance actions can only run against the {expectedName} manager." + ); + } + } + + private static void EnsureWindowsOnly(string action) + { + if (!OperatingSystem.IsWindows()) + { + throw new InvalidOperationException( + $"The manager action \"{action}\" is only supported on Windows." + ); + } + } + + private static IpcManagerMaintenanceActionResult Success( + string command, + IPackageManager manager, + string action, + string operationStatus, + string? message = null + ) + { + return new IpcManagerMaintenanceActionResult + { + Status = "success", + Command = command, + Manager = IpcManagerSettingsApi.GetPublicManagerId(manager), + Action = action, + OperationStatus = operationStatus, + Message = message, + Maintenance = ToMaintenanceInfo(manager), + }; + } +} diff --git a/src/UniGetUI.Interface.IpcApi/IpcManagerSettingsApi.cs b/src/UniGetUI.Interface.IpcApi/IpcManagerSettingsApi.cs new file mode 100644 index 0000000..11071a2 --- /dev/null +++ b/src/UniGetUI.Interface.IpcApi/IpcManagerSettingsApi.cs @@ -0,0 +1,539 @@ +using UniGetUI.Core.SettingsEngine; +using UniGetUI.PackageEngine; +using UniGetUI.PackageEngine.Classes.Manager; +using UniGetUI.PackageEngine.Enums; +using UniGetUI.PackageEngine.Interfaces; +using UniGetUI.PackageEngine.Operations; +using UniGetUI.PackageOperations; + +namespace UniGetUI.Interface; + +public sealed class IpcManagerCapabilitiesInfo +{ + public bool CanRunAsAdmin { get; set; } + public bool CanSkipIntegrityChecks { get; set; } + public bool CanRunInteractively { get; set; } + public bool CanRemoveDataOnUninstall { get; set; } + public bool CanDownloadInstaller { get; set; } + public bool SupportsCustomVersions { get; set; } + public bool SupportsCustomArchitectures { get; set; } + public bool SupportsCustomScopes { get; set; } + public bool SupportsPreRelease { get; set; } + public bool SupportsCustomLocations { get; set; } + public bool SupportsCustomSources { get; set; } + public bool MustInstallSourcesAsAdmin { get; set; } +} + +public sealed class IpcManagerInfo +{ + public string Name { get; set; } = ""; + public string DisplayName { get; set; } = ""; + public bool Enabled { get; set; } + public bool Ready { get; set; } + public bool NotificationsSuppressed { get; set; } + public string ExecutablePath { get; set; } = ""; + public string ExecutableArguments { get; set; } = ""; + public IpcManagerCapabilitiesInfo Capabilities { get; set; } = new(); +} + +public sealed class IpcSourceInfo +{ + public string Manager { get; set; } = ""; + public string Name { get; set; } = ""; + public string DisplayName { get; set; } = ""; + public string Url { get; set; } = ""; + public int? PackageCount { get; set; } + public string UpdateDate { get; set; } = ""; + public bool IsKnown { get; set; } + public bool IsConfigured { get; set; } +} + +public sealed class IpcSourceRequest +{ + public string ManagerName { get; set; } = ""; + public string SourceName { get; set; } = ""; + public string? SourceUrl { get; set; } +} + +public sealed class IpcSourceOperationResult +{ + public string Status { get; set; } = "success"; + public string Command { get; set; } = ""; + public string OperationStatus { get; set; } = ""; + public string? Message { get; set; } + public IpcSourceInfo? Source { get; set; } +} + +public sealed class IpcSettingInfo +{ + public string Name { get; set; } = ""; + public string Key { get; set; } = ""; + public bool IsSet { get; set; } + public bool BoolValue { get; set; } + public string StringValue { get; set; } = ""; + public bool HasStringValue { get; set; } +} + +public sealed class IpcSettingValueRequest +{ + public string SettingKey { get; set; } = ""; + public bool? Enabled { get; set; } + public string? Value { get; set; } +} + +public sealed class IpcManagerToggleRequest +{ + public string ManagerName { get; set; } = ""; + public bool Enabled { get; set; } +} + +public static class IpcManagerSettingsApi +{ + private static readonly HashSet HiddenSettings = + [ + Settings.K.CurrentSessionToken, + Settings.K.TelemetryClientToken, + ]; + + public static IReadOnlyList ListManagers() + { + return PEInterface.Managers + .OrderBy(manager => manager.DisplayName, StringComparer.OrdinalIgnoreCase) + .Select(ToManagerInfo) + .ToArray(); + } + + public static IReadOnlyList ListSources(string? managerName = null) + { + return ResolveManagers(managerName) + .SelectMany(GetMergedSources) + .OrderBy(source => source.Manager, StringComparer.OrdinalIgnoreCase) + .ThenBy(source => source.Name, StringComparer.OrdinalIgnoreCase) + .ToArray(); + } + + public static async Task AddSourceAsync( + IpcSourceRequest request + ) + { + var manager = ResolveManager(request.ManagerName); + var source = ResolveSourceForAdd(manager, request); + + using var operation = new AddSourceOperation(source); + await operation.MainThread(); + + return ToSourceOperationResult("add-source", operation, source); + } + + public static async Task RemoveSourceAsync( + IpcSourceRequest request + ) + { + var manager = ResolveManager(request.ManagerName); + var source = ResolveSourceForRemove(manager, request); + + using var operation = new RemoveSourceOperation(source); + await operation.MainThread(); + + return ToSourceOperationResult("remove-source", operation, source); + } + + public static IReadOnlyList ListSettings() + { + return Enum.GetValues() + .Where(IsVisibleSetting) + .OrderBy(setting => setting.ToString(), StringComparer.OrdinalIgnoreCase) + .Select(ToSettingInfo) + .ToArray(); + } + + public static IpcSettingInfo GetSetting(string settingKey) + { + return ToSettingInfo(ResolveSettingKey(settingKey)); + } + + public static IpcSettingInfo SetSetting(IpcSettingValueRequest request) + { + ArgumentNullException.ThrowIfNull(request); + + var key = ResolveSettingKey(request.SettingKey); + var hasEnabled = request.Enabled.HasValue; + var hasValue = request.Value is not null; + + if (hasEnabled == hasValue) + { + throw new InvalidOperationException( + "Provide exactly one of enabled or value when setting a setting." + ); + } + + if (hasValue) + { + Settings.SetValue(key, request.Value ?? ""); + } + else + { + Settings.Set(key, request.Enabled!.Value); + } + + return ToSettingInfo(key); + } + + public static IpcSettingInfo ClearSetting(string settingKey) + { + var key = ResolveSettingKey(settingKey); + Settings.SetValue(key, string.Empty); + return ToSettingInfo(key); + } + + public static void ResetSettingsPreservingSession() + { + Settings.ResetSettings(); + } + + public static async Task SetManagerEnabledAsync( + IpcManagerToggleRequest request + ) + { + ArgumentNullException.ThrowIfNull(request); + var manager = ResolveManager(request.ManagerName); + Settings.SetDictionaryItem(Settings.K.DisabledManagers, manager.Name, !request.Enabled); + await Task.Run(manager.Initialize); + return ToManagerInfo(manager); + } + + public static IpcManagerInfo SetManagerNotifications( + IpcManagerToggleRequest request + ) + { + ArgumentNullException.ThrowIfNull(request); + var manager = ResolveManager(request.ManagerName); + Settings.SetDictionaryItem( + Settings.K.DisabledPackageManagerNotifications, + manager.Name, + !request.Enabled + ); + return ToManagerInfo(manager); + } + + private static IpcManagerInfo ToManagerInfo(IPackageManager manager) + { + return new IpcManagerInfo + { + Name = GetPublicManagerId(manager), + DisplayName = manager.DisplayName, + Enabled = manager.IsEnabled(), + Ready = manager.IsReady(), + NotificationsSuppressed = Settings.GetDictionaryItem( + Settings.K.DisabledPackageManagerNotifications, + manager.Name + ), + ExecutablePath = manager.Status.ExecutablePath, + ExecutableArguments = manager.Status.ExecutableCallArgs, + Capabilities = new IpcManagerCapabilitiesInfo + { + CanRunAsAdmin = manager.Capabilities.CanRunAsAdmin, + CanSkipIntegrityChecks = manager.Capabilities.CanSkipIntegrityChecks, + CanRunInteractively = manager.Capabilities.CanRunInteractively, + CanRemoveDataOnUninstall = manager.Capabilities.CanRemoveDataOnUninstall, + CanDownloadInstaller = manager.Capabilities.CanDownloadInstaller, + SupportsCustomVersions = manager.Capabilities.SupportsCustomVersions, + SupportsCustomArchitectures = manager.Capabilities.SupportsCustomArchitectures, + SupportsCustomScopes = manager.Capabilities.SupportsCustomScopes, + SupportsPreRelease = manager.Capabilities.SupportsPreRelease, + SupportsCustomLocations = manager.Capabilities.SupportsCustomLocations, + SupportsCustomSources = manager.Capabilities.SupportsCustomSources, + MustInstallSourcesAsAdmin = manager.Capabilities.Sources.MustBeInstalledAsAdmin, + }, + }; + } + + private static IReadOnlyList GetMergedSources(IPackageManager manager) + { + Dictionary sources = new(StringComparer.OrdinalIgnoreCase); + + foreach (var knownSource in manager.Properties.KnownSources) + { + sources[GetSourceIdentity(knownSource)] = ToSourceInfo( + knownSource, + isKnown: true, + isConfigured: false + ); + } + + foreach (var configuredSource in GetConfiguredSources(manager)) + { + var sourceKey = GetSourceIdentity(configuredSource); + if (sources.TryGetValue(sourceKey, out var existing)) + { + existing.IsConfigured = true; + existing.PackageCount = configuredSource.PackageCount; + existing.UpdateDate = configuredSource.UpdateDate ?? ""; + existing.Url = configuredSource.Url.ToString(); + } + else + { + sources[sourceKey] = ToSourceInfo( + configuredSource, + isKnown: false, + isConfigured: true + ); + } + } + + return sources.Values.ToArray(); + } + + private static string GetSourceIdentity(IManagerSource source) + { + return $"{source.Manager.Name}|{source.Name}|{source.Url}"; + } + + private static IpcSourceInfo ToSourceInfo( + IManagerSource source, + bool isKnown, + bool isConfigured + ) + { + return new IpcSourceInfo + { + Manager = GetPublicManagerId(source.Manager), + Name = source.Name, + DisplayName = source.AsString_DisplayName, + Url = source.Url.ToString(), + PackageCount = source.PackageCount, + UpdateDate = source.UpdateDate ?? "", + IsKnown = isKnown, + IsConfigured = isConfigured, + }; + } + + private static IpcSourceOperationResult ToSourceOperationResult( + string command, + AbstractOperation operation, + IManagerSource source + ) + { + return new IpcSourceOperationResult + { + Status = operation.Status == OperationStatus.Succeeded ? "success" : "error", + Command = command, + OperationStatus = operation.Status.ToString().ToLowerInvariant(), + Message = operation.Status switch + { + OperationStatus.Succeeded => null, + OperationStatus.Canceled => "The operation was canceled.", + _ => operation.GetOutput().LastOrDefault().Item1, + }, + Source = ToSourceInfo(source, isKnown: true, isConfigured: true), + }; + } + + internal static IReadOnlyList ResolveManagers(string? managerName) + { + var managers = PEInterface.Managers + .Where(manager => MatchesManagerId(manager, managerName)) + .ToArray(); + + if (managers.Length == 0) + { + throw new InvalidOperationException( + string.IsNullOrWhiteSpace(managerName) + ? "No package managers are available." + : $"No package manager matching \"{managerName}\" was found." + ); + } + + return managers; + } + + internal static IPackageManager ResolveManager(string managerName) + { + if (string.IsNullOrWhiteSpace(managerName)) + { + throw new InvalidOperationException("The manager parameter is required."); + } + + return ResolveManagers(managerName).First(); + } + + internal static bool MatchesManagerId(IPackageManager manager, string? managerName) + { + return string.IsNullOrWhiteSpace(managerName) + || manager.Id.Equals(managerName, StringComparison.OrdinalIgnoreCase); + } + + internal static string GetPublicManagerId(IPackageManager manager) + { + return manager.Id; + } + + internal static string GetPublicManagerId(string? managerName) + { + if (string.IsNullOrWhiteSpace(managerName)) + { + return ""; + } + + return PEInterface.Managers.FirstOrDefault(manager => + manager.Id.Equals(managerName, StringComparison.OrdinalIgnoreCase) + || manager.Name.Equals(managerName, StringComparison.OrdinalIgnoreCase) + )?.Id + ?? managerName; + } + + internal static IPackageManager? ResolveImportedManager(string? managerName) + { + if (string.IsNullOrWhiteSpace(managerName)) + { + return null; + } + + return PEInterface.Managers.FirstOrDefault(manager => + manager.Id.Equals(managerName, StringComparison.OrdinalIgnoreCase) + || manager.Name.Equals(managerName, StringComparison.OrdinalIgnoreCase) + || manager.DisplayName.Equals(managerName, StringComparison.OrdinalIgnoreCase) + ); + } + + private static IManagerSource ResolveSourceForAdd( + IPackageManager manager, + IpcSourceRequest request + ) + { + if (string.IsNullOrWhiteSpace(request.SourceName)) + { + throw new InvalidOperationException("The source name is required."); + } + + if (!string.IsNullOrWhiteSpace(request.SourceUrl)) + { + return new ManagerSource( + manager, + request.SourceName, + new Uri(request.SourceUrl, UriKind.Absolute) + ); + } + + return manager.Properties.KnownSources.FirstOrDefault(source => + SourceMatches(source, request.SourceName, null) + ) + ?? throw new InvalidOperationException( + $"No known source matching \"{request.SourceName}\" was found for manager \"{manager.Name}\"." + ); + } + + private static IManagerSource ResolveSourceForRemove( + IPackageManager manager, + IpcSourceRequest request + ) + { + if (string.IsNullOrWhiteSpace(request.SourceName)) + { + throw new InvalidOperationException("The source name is required."); + } + + var configuredSource = GetConfiguredSources(manager).FirstOrDefault(source => + SourceMatches(source, request.SourceName, request.SourceUrl) + ); + if (configuredSource is not null) + { + return configuredSource; + } + + if (!string.IsNullOrWhiteSpace(request.SourceUrl)) + { + return new ManagerSource( + manager, + request.SourceName, + new Uri(request.SourceUrl, UriKind.Absolute) + ); + } + + var knownSource = manager.Properties.KnownSources.FirstOrDefault(source => + SourceMatches(source, request.SourceName, null) + ); + if (knownSource is not null) + { + return knownSource; + } + + return new ManagerSource(manager, request.SourceName, new Uri("https://localhost/")); + } + + private static bool SourceMatches( + IManagerSource source, + string sourceName, + string? sourceUrl + ) + { + return source.Name.Equals(sourceName, StringComparison.OrdinalIgnoreCase) + || source.AsString_DisplayName.Equals(sourceName, StringComparison.OrdinalIgnoreCase) + || ( + !string.IsNullOrWhiteSpace(sourceUrl) + && source.Url.ToString().Equals(sourceUrl, StringComparison.OrdinalIgnoreCase) + ); + } + + private static IReadOnlyList GetConfiguredSources(IPackageManager manager) + { + try + { + return manager.SourcesHelper.GetSources(); + } + catch (NotImplementedException) + { + return []; + } + } + + private static bool IsVisibleSetting(Settings.K setting) + { + return setting != Settings.K.Unset && !HiddenSettings.Contains(setting); + } + + private static Settings.K ResolveSettingKey(string settingKey) + { + if (string.IsNullOrWhiteSpace(settingKey)) + { + throw new InvalidOperationException("The setting key is required."); + } + + foreach (var candidate in Enum.GetValues()) + { + if (!IsVisibleSetting(candidate)) + { + continue; + } + + if ( + candidate.ToString().Equals(settingKey, StringComparison.OrdinalIgnoreCase) + || Settings.ResolveKey(candidate).Equals( + settingKey, + StringComparison.OrdinalIgnoreCase + ) + ) + { + return candidate; + } + } + + throw new InvalidOperationException($"No setting matching \"{settingKey}\" was found."); + } + + private static IpcSettingInfo ToSettingInfo(Settings.K setting) + { + string stringValue = Settings.GetValue(setting); + bool isSet = Settings.Get(setting); + + return new IpcSettingInfo + { + Name = setting.ToString(), + Key = Settings.ResolveKey(setting), + IsSet = isSet, + BoolValue = isSet, + StringValue = stringValue, + HasStringValue = !string.IsNullOrWhiteSpace(stringValue), + }; + } +} diff --git a/src/UniGetUI.Interface.IpcApi/IpcOperationApi.cs b/src/UniGetUI.Interface.IpcApi/IpcOperationApi.cs new file mode 100644 index 0000000..782d833 --- /dev/null +++ b/src/UniGetUI.Interface.IpcApi/IpcOperationApi.cs @@ -0,0 +1,504 @@ +using System.Collections.Concurrent; +using UniGetUI.Core.Tools; +using UniGetUI.PackageEngine.Enums; +using UniGetUI.PackageEngine.Operations; +using UniGetUI.PackageOperations; + +namespace UniGetUI.Interface; + +public sealed class IpcOperationOutputLine +{ + public string Text { get; set; } = ""; + public string Type { get; set; } = ""; +} + +public class IpcOperationInfo +{ + public string Id { get; set; } = ""; + public string Kind { get; set; } = ""; + public string Title { get; set; } = ""; + public string Status { get; set; } = ""; + public bool Started { get; set; } + public string LiveLine { get; set; } = ""; + public string LiveLineType { get; set; } = ""; + public int? QueuePosition { get; set; } + public int OutputLineCount { get; set; } + public bool CanCancel { get; set; } + public bool CanForget { get; set; } + public IReadOnlyList AvailableQueueActions { get; set; } = []; + public IReadOnlyList AvailableRetryModes { get; set; } = []; + public IpcPackageInfo? Package { get; set; } + public string ManagerName { get; set; } = ""; + public string SourceName { get; set; } = ""; +} + +public sealed class IpcOperationDetails : IpcOperationInfo +{ + public IReadOnlyList Output { get; set; } = []; +} + +public sealed class IpcOperationOutputResult +{ + public string OperationId { get; set; } = ""; + public int LineCount { get; set; } + public IReadOnlyList Output { get; set; } = []; +} + +public static class IpcOperationApi +{ + private sealed class TrackedOperation + { + private readonly List _output = []; + private readonly object _syncRoot = new(); + + public AbstractOperation Operation { get; } + public DateTime CreatedAtUtc { get; } = DateTime.UtcNow; + public DateTime UpdatedAtUtc { get; private set; } = DateTime.UtcNow; + public string LiveLine { get; private set; } = CoreTools.Translate("Please wait..."); + public string LiveLineType { get; private set; } = ToLineTypeName( + AbstractOperation.LineType.ProgressIndicator + ); + + public TrackedOperation(AbstractOperation operation) + { + Operation = operation; + + foreach (var (text, type) in operation.GetOutput()) + { + AddLine(text, type); + } + } + + public void AddLine(string text, AbstractOperation.LineType type) + { + lock (_syncRoot) + { + var line = new IpcOperationOutputLine + { + Text = text, + Type = ToLineTypeName(type), + }; + _output.Add(line); + LiveLine = text; + LiveLineType = line.Type; + UpdatedAtUtc = DateTime.UtcNow; + } + } + + public void Touch() + { + lock (_syncRoot) + { + UpdatedAtUtc = DateTime.UtcNow; + } + } + + public int GetOutputCount() + { + lock (_syncRoot) + { + return _output.Count; + } + } + + public IReadOnlyList GetOutputSnapshot(int? tailLines = null) + { + lock (_syncRoot) + { + if (!tailLines.HasValue || tailLines.Value <= 0 || tailLines.Value >= _output.Count) + { + return _output.ToArray(); + } + + return _output.Skip(_output.Count - tailLines.Value).ToArray(); + } + } + } + + private static readonly ConcurrentDictionary Operations = new(); + private const int MaxTrackedOperations = 200; + + public static string Track(AbstractOperation operation) + { + ArgumentNullException.ThrowIfNull(operation); + + string operationId = operation.Metadata.Identifier; + Operations.GetOrAdd( + operationId, + _ => + { + var tracked = new TrackedOperation(operation); + operation.LogLineAdded += (_, line) => tracked.AddLine(line.Item1, line.Item2); + operation.StatusChanged += (_, _) => tracked.Touch(); + operation.OperationFinished += (_, _) => tracked.Touch(); + return tracked; + } + ); + + PruneCompletedOperations(); + return operationId; + } + + public static IReadOnlyList ListOperations() + { + return Operations + .Values.OrderBy(entry => IsActive(entry.Operation.Status) ? 0 : 1) + .ThenBy(entry => entry.CreatedAtUtc) + .Select(CreateOperationInfo) + .ToArray(); + } + + public static IpcOperationDetails GetOperation(string operationId) + { + var tracked = GetTrackedOperation(operationId); + var info = CreateOperationInfo(tracked); + return new IpcOperationDetails + { + Id = info.Id, + Kind = info.Kind, + Title = info.Title, + Status = info.Status, + Started = info.Started, + LiveLine = info.LiveLine, + LiveLineType = info.LiveLineType, + QueuePosition = info.QueuePosition, + OutputLineCount = info.OutputLineCount, + CanCancel = info.CanCancel, + CanForget = info.CanForget, + AvailableQueueActions = info.AvailableQueueActions, + AvailableRetryModes = info.AvailableRetryModes, + Package = info.Package, + ManagerName = info.ManagerName, + SourceName = info.SourceName, + Output = tracked.GetOutputSnapshot(), + }; + } + + public static IpcOperationOutputResult GetOperationOutput( + string operationId, + int? tailLines = null + ) + { + if (tailLines.HasValue && tailLines.Value < 0) + { + throw new InvalidOperationException("tailLines must be greater than or equal to zero."); + } + + var tracked = GetTrackedOperation(operationId); + return new IpcOperationOutputResult + { + OperationId = tracked.Operation.Metadata.Identifier, + LineCount = tracked.GetOutputCount(), + Output = tracked.GetOutputSnapshot(tailLines), + }; + } + + public static IpcCommandResult CancelOperation(string operationId) + { + var tracked = GetTrackedOperation(operationId); + if (!IsActive(tracked.Operation.Status)) + { + throw new InvalidOperationException( + "Only queued or running operations can be canceled." + ); + } + + tracked.Operation.Cancel(); + return IpcCommandResult.Success("cancel-operation"); + } + + public static IpcCommandResult RetryOperation(string operationId, string? retryMode) + { + var tracked = GetTrackedOperation(operationId); + if (IsActive(tracked.Operation.Status)) + { + throw new InvalidOperationException( + "Running or queued operations cannot be retried." + ); + } + + string normalizedRetryMode = NormalizeRetryMode(retryMode); + var availableRetryModes = GetRetryModes(tracked.Operation); + if (!availableRetryModes.Contains(ToRetryModeName(normalizedRetryMode))) + { + throw new InvalidOperationException( + $"Retry mode \"{retryMode}\" is not supported for operation {operationId}." + ); + } + + tracked.Operation.Retry(normalizedRetryMode); + return IpcCommandResult.Success("retry-operation"); + } + + public static IpcCommandResult ReorderOperation(string operationId, string action) + { + var tracked = GetTrackedOperation(operationId); + if (tracked.Operation.Status != OperationStatus.InQueue) + { + throw new InvalidOperationException( + "Only queued operations can be reordered." + ); + } + + switch (NormalizeQueueAction(action)) + { + case "run-now": + tracked.Operation.SkipQueue(); + break; + case "run-next": + tracked.Operation.RunNext(); + break; + case "run-last": + tracked.Operation.BackOfTheQueue(); + break; + default: + throw new InvalidOperationException($"Unsupported queue action \"{action}\"."); + } + + return IpcCommandResult.Success("reorder-operation"); + } + + public static IpcCommandResult ForgetOperation(string operationId) + { + var tracked = GetTrackedOperation(operationId); + if (IsActive(tracked.Operation.Status)) + { + throw new InvalidOperationException( + "Running or queued operations cannot be forgotten." + ); + } + + ForgetTracking(operationId); + return IpcCommandResult.Success("forget-operation"); + } + + public static void ForgetTracking(string operationId) + { + Operations.TryRemove(operationId, out _); + } + + private static TrackedOperation GetTrackedOperation(string operationId) + { + ArgumentException.ThrowIfNullOrWhiteSpace(operationId); + + return Operations.TryGetValue(operationId.Trim(), out var tracked) + ? tracked + : throw new InvalidOperationException( + $"No tracked operation with id \"{operationId}\" was found." + ); + } + + private static IpcOperationInfo CreateOperationInfo(TrackedOperation tracked) + { + var operation = tracked.Operation; + return new IpcOperationInfo + { + Id = operation.Metadata.Identifier, + Kind = GetOperationKind(operation), + Title = operation.Metadata.Title, + Status = operation.Status.ToString().ToLowerInvariant(), + Started = operation.Started, + LiveLine = tracked.LiveLine, + LiveLineType = tracked.LiveLineType, + QueuePosition = GetQueuePosition(operation), + OutputLineCount = tracked.GetOutputCount(), + CanCancel = IsActive(operation.Status), + CanForget = !IsActive(operation.Status), + AvailableQueueActions = operation.Status == OperationStatus.InQueue + ? ["run-now", "run-next", "run-last"] + : [], + AvailableRetryModes = !IsActive(operation.Status) ? GetRetryModes(operation) : [], + Package = GetOperationPackage(operation), + ManagerName = GetManagerName(operation), + SourceName = GetSourceName(operation), + }; + } + + private static IpcPackageInfo? GetOperationPackage(AbstractOperation operation) + { + return operation switch + { + PackageOperation packageOperation => IpcPackageApi.CreateIpcPackageInfo( + packageOperation.Package + ), + DownloadOperation downloadOperation => IpcPackageApi.CreateIpcPackageInfo( + downloadOperation.Package + ), + _ => null, + }; + } + + private static string GetManagerName(AbstractOperation operation) + { + return operation switch + { + PackageOperation packageOperation => IpcManagerSettingsApi.GetPublicManagerId( + packageOperation.Package.Manager + ), + DownloadOperation downloadOperation => IpcManagerSettingsApi.GetPublicManagerId( + downloadOperation.Package.Manager + ), + SourceOperation sourceOperation => IpcManagerSettingsApi.GetPublicManagerId( + sourceOperation.ManagerSource.Manager + ), + _ => "", + }; + } + + private static string GetSourceName(AbstractOperation operation) + { + return operation is SourceOperation sourceOperation ? sourceOperation.ManagerSource.Name : ""; + } + + private static string GetOperationKind(AbstractOperation operation) + { + return operation switch + { + InstallPackageOperation => "install-package", + UpdatePackageOperation => "update-package", + UninstallPackageOperation => "uninstall-package", + DownloadOperation => "download-package", + AddSourceOperation => "add-source", + RemoveSourceOperation => "remove-source", + _ => operation.GetType().Name, + }; + } + + private static int? GetQueuePosition(AbstractOperation operation) + { + if (operation.Status != OperationStatus.InQueue) + { + return null; + } + + int index = AbstractOperation.OperationQueue.IndexOf(operation); + if (index < 0) + { + return null; + } + + return Math.Max(index - AbstractOperation.MAX_OPERATIONS + 1, 0); + } + + private static IReadOnlyList GetRetryModes(AbstractOperation operation) + { + List retryModes = ["retry"]; + + switch (operation) + { + case PackageOperation packageOperation: + if ( + !packageOperation.Options.RunAsAdministrator + && packageOperation.Package.Manager.Capabilities.CanRunAsAdmin + ) + { + retryModes.Add("retry-as-admin"); + } + + if ( + !packageOperation.Options.InteractiveInstallation + && packageOperation.Package.Manager.Capabilities.CanRunInteractively + ) + { + retryModes.Add("retry-interactive"); + } + + if ( + !packageOperation.Options.SkipHashCheck + && packageOperation.Package.Manager.Capabilities.CanSkipIntegrityChecks + ) + { + retryModes.Add("retry-no-hash-check"); + } + + break; + case SourceOperation sourceOperation when !sourceOperation.ForceAsAdministrator: + retryModes.Add("retry-as-admin"); + break; + } + + return retryModes; + } + + private static string NormalizeRetryMode(string? retryMode) + { + if (string.IsNullOrWhiteSpace(retryMode)) + { + return AbstractOperation.RetryMode.Retry; + } + + return retryMode.Trim().ToLowerInvariant() switch + { + "retry" => AbstractOperation.RetryMode.Retry, + "retry-as-admin" => AbstractOperation.RetryMode.Retry_AsAdmin, + "retry-interactive" => AbstractOperation.RetryMode.Retry_Interactive, + "retry-no-hash-check" => AbstractOperation.RetryMode.Retry_SkipIntegrity, + _ => throw new InvalidOperationException( + $"Unsupported retry mode \"{retryMode}\"." + ), + }; + } + + private static string ToRetryModeName(string retryMode) + { + return retryMode switch + { + var mode when mode == AbstractOperation.RetryMode.Retry => "retry", + var mode when mode == AbstractOperation.RetryMode.Retry_AsAdmin => "retry-as-admin", + var mode when mode == AbstractOperation.RetryMode.Retry_Interactive + => "retry-interactive", + var mode when mode == AbstractOperation.RetryMode.Retry_SkipIntegrity + => "retry-no-hash-check", + _ => retryMode, + }; + } + + private static string NormalizeQueueAction(string action) + { + ArgumentException.ThrowIfNullOrWhiteSpace(action); + + return action.Trim().ToLowerInvariant() switch + { + "run-now" => "run-now", + "run-next" => "run-next", + "run-last" => "run-last", + _ => throw new InvalidOperationException($"Unsupported queue action \"{action}\"."), + }; + } + + private static bool IsActive(OperationStatus status) + { + return status is OperationStatus.InQueue or OperationStatus.Running; + } + + private static string ToLineTypeName(AbstractOperation.LineType type) + { + return type switch + { + AbstractOperation.LineType.VerboseDetails => "verbose", + AbstractOperation.LineType.ProgressIndicator => "progress", + AbstractOperation.LineType.Information => "information", + AbstractOperation.LineType.Error => "error", + _ => type.ToString().ToLowerInvariant(), + }; + } + + private static void PruneCompletedOperations() + { + if (Operations.Count <= MaxTrackedOperations) + { + return; + } + + foreach ( + var completedOperation in Operations + .Values.Where(entry => !IsActive(entry.Operation.Status)) + .OrderBy(entry => entry.UpdatedAtUtc) + .Take(Operations.Count - MaxTrackedOperations) + .ToArray() + ) + { + ForgetTracking(completedOperation.Operation.Metadata.Identifier); + } + } +} diff --git a/src/UniGetUI.Interface.IpcApi/IpcPackageApi.cs b/src/UniGetUI.Interface.IpcApi/IpcPackageApi.cs new file mode 100644 index 0000000..0ec762f --- /dev/null +++ b/src/UniGetUI.Interface.IpcApi/IpcPackageApi.cs @@ -0,0 +1,804 @@ +using UniGetUI.Core.Logging; +using UniGetUI.PackageEngine; +using UniGetUI.PackageEngine.Classes.Packages.Classes; +using UniGetUI.PackageEngine.Enums; +using UniGetUI.PackageEngine.Interfaces; +using UniGetUI.PackageEngine.Operations; +using UniGetUI.PackageEngine.PackageClasses; +using UniGetUI.PackageEngine.PackageLoader; +using UniGetUI.PackageEngine.Serializable; +using UniGetUI.PackageOperations; + +namespace UniGetUI.Interface; + +public sealed class IpcPackageInfo +{ + public string Name { get; set; } = ""; + public string Id { get; set; } = ""; + public string Version { get; set; } = ""; + public string NewVersion { get; set; } = ""; + public string Source { get; set; } = ""; + public string Manager { get; set; } = ""; + public bool IsUpgradable { get; set; } +} + +public sealed class IpcPackageActionRequest +{ + public string PackageId { get; set; } = ""; + public string? ManagerName { get; set; } + public string? PackageSource { get; set; } + public string? Version { get; set; } + public string? Scope { get; set; } + public bool? PreRelease { get; set; } + public bool? Elevated { get; set; } + public bool? Interactive { get; set; } + public bool? SkipHash { get; set; } + public bool? RemoveData { get; set; } + public bool? WaitForCompletion { get; set; } + public string? Architecture { get; set; } + public string? InstallLocation { get; set; } + public string? OutputPath { get; set; } +} + +public sealed class IpcPackageOperationResult +{ + public string Status { get; set; } = "success"; + public string Command { get; set; } = ""; + public string OperationId { get; set; } = ""; + public string OperationStatus { get; set; } = ""; + public bool Completed { get; set; } = true; + public string? Message { get; set; } + public IpcPackageInfo? Package { get; set; } + public string? OutputPath { get; set; } + public IReadOnlyList Output { get; set; } = []; +} + +public sealed class IpcPackageDependencyInfo +{ + public string Name { get; set; } = ""; + public string Version { get; set; } = ""; + public bool Mandatory { get; set; } +} + +public sealed class IpcPackageDetailsInfo +{ + public string Name { get; set; } = ""; + public string Id { get; set; } = ""; + public string Version { get; set; } = ""; + public string NewVersion { get; set; } = ""; + public string Source { get; set; } = ""; + public string Manager { get; set; } = ""; + public string Description { get; set; } = ""; + public string Publisher { get; set; } = ""; + public string Author { get; set; } = ""; + public string HomepageUrl { get; set; } = ""; + public string License { get; set; } = ""; + public string LicenseUrl { get; set; } = ""; + public string InstallerUrl { get; set; } = ""; + public string InstallerHash { get; set; } = ""; + public string InstallerType { get; set; } = ""; + public long InstallerSize { get; set; } + public string ManifestUrl { get; set; } = ""; + public string UpdateDate { get; set; } = ""; + public string ReleaseNotes { get; set; } = ""; + public string ReleaseNotesUrl { get; set; } = ""; + public string IconUrl { get; set; } = ""; + public string InstallLocation { get; set; } = ""; + public string? IgnoredVersion { get; set; } + public IReadOnlyList Tags { get; set; } = []; + public IReadOnlyList Versions { get; set; } = []; + public IReadOnlyList Screenshots { get; set; } = []; + public IReadOnlyList Dependencies { get; set; } = []; +} + +public sealed class IpcIgnoredUpdateInfo +{ + public string IgnoredId { get; set; } = ""; + public string Manager { get; set; } = ""; + public string PackageId { get; set; } = ""; + public string Version { get; set; } = ""; + public bool IgnoreAllVersions { get; set; } + public bool IsPauseUntilDate { get; set; } + public string PauseUntil { get; set; } = ""; +} + +internal enum IpcPackageLookupMode +{ + Search, + Installed, + Upgradable, + InstalledOrUpgradable, + Any, +} + +public static class IpcPackageApi +{ + public static IReadOnlyList SearchPackages( + string query, + string? managerName = null, + int maxResults = 50 + ) + { + ArgumentException.ThrowIfNullOrWhiteSpace(query); + + maxResults = Math.Clamp(maxResults, 1, 500); + + return GetManagers(managerName) + .SelectMany(manager => manager.FindPackages(query)) + .DistinctBy(GetPackageIdentity) + .Select(ToIpcPackageInfo) + .OrderBy(package => package.Name, StringComparer.OrdinalIgnoreCase) + .ThenBy(package => package.Id, StringComparer.OrdinalIgnoreCase) + .Take(maxResults) + .ToArray(); + } + + public static IReadOnlyList ListInstalledPackages(string? managerName = null) + { + return GetInstalledPackagesSnapshot(managerName) + .DistinctBy(GetPackageIdentity) + .Select(ToIpcPackageInfo) + .OrderBy(package => package.Name, StringComparer.OrdinalIgnoreCase) + .ThenBy(package => package.Id, StringComparer.OrdinalIgnoreCase) + .ToArray(); + } + + public static IReadOnlyList ListUpgradablePackages(string? managerName = null) + { + return GetUpgradablePackagesSnapshot(managerName) + .DistinctBy(GetPackageIdentity) + .Select(ToIpcPackageInfo) + .OrderBy(package => package.Name, StringComparer.OrdinalIgnoreCase) + .ThenBy(package => package.Id, StringComparer.OrdinalIgnoreCase) + .ToArray(); + } + + public static Task InstallPackageAsync( + IpcPackageActionRequest request + ) + { + ArgumentNullException.ThrowIfNull(request); + + var package = FindSearchResult(request); + return ExecuteOperationAsync( + "install-package", + package, + request, + (pkg, options) => new InstallPackageOperation(pkg, options) + ); + } + + public static Task UpdatePackageAsync( + IpcPackageActionRequest request + ) + { + ArgumentNullException.ThrowIfNull(request); + + var package = FindUpgradablePackageOrInstalledPackage(request); + return ExecuteOperationAsync( + "update-package", + package, + request, + (pkg, options) => new UpdatePackageOperation(pkg, options) + ); + } + + public static Task UninstallPackageAsync( + IpcPackageActionRequest request + ) + { + ArgumentNullException.ThrowIfNull(request); + + var package = FindInstalledPackage(request); + return ExecuteOperationAsync( + "uninstall-package", + package, + request, + (pkg, options) => new UninstallPackageOperation(pkg, options) + ); + } + + public static async Task DownloadPackageAsync( + IpcPackageActionRequest request + ) + { + ArgumentNullException.ThrowIfNull(request); + + if (string.IsNullOrWhiteSpace(request.OutputPath)) + { + throw new InvalidOperationException( + "The outputPath parameter is required when downloading a package." + ); + } + + var package = FindAnyPackage(request); + if (!package.Manager.Capabilities.CanDownloadInstaller) + { + throw new InvalidOperationException( + $"The manager \"{IpcManagerSettingsApi.GetPublicManagerId(package.Manager)}\" does not support installer downloads." + ); + } + + var operation = new DownloadOperation(package, request.OutputPath); + string operationId = IpcOperationApi.Track(operation); + + if (request.WaitForCompletion == false) + { + _ = Task.Run(() => RunTrackedOperationAsync(operation)); + return CreateOperationResult( + "download-package", + package, + operation, + operation.DownloadLocation, + completed: false, + operationId: operationId + ); + } + + await RunTrackedOperationAsync(operation); + + return CreateOperationResult( + "download-package", + package, + operation, + operation.DownloadLocation, + operationId: operationId + ); + } + + public static Task ReinstallPackageAsync( + IpcPackageActionRequest request + ) + { + ArgumentNullException.ThrowIfNull(request); + + var package = FindInstalledPackage(request); + return ExecuteOperationAsync( + "reinstall-package", + package, + request, + (pkg, options) => new InstallPackageOperation(pkg, options) + ); + } + + public static async Task UninstallThenReinstallPackageAsync( + IpcPackageActionRequest request + ) + { + ArgumentNullException.ThrowIfNull(request); + + var package = FindInstalledPackage(request); + var options = await InstallOptionsFactory.LoadApplicableAsync(package); + ApplyRequestOptions(options, request); + + var uninstallOperation = new UninstallPackageOperation(package, options); + var installOperation = new InstallPackageOperation( + package, + options, + req: uninstallOperation + ); + string operationId = IpcOperationApi.Track(installOperation); + + if (request.WaitForCompletion == false) + { + _ = Task.Run(() => RunTrackedOperationAsync(installOperation)); + return CreateOperationResult( + "uninstall-then-reinstall-package", + package, + installOperation, + completed: false, + operationId: operationId + ); + } + + await RunTrackedOperationAsync(installOperation); + + return CreateOperationResult( + "uninstall-then-reinstall-package", + package, + installOperation, + operationId: operationId + ); + } + + public static async Task GetPackageDetailsAsync( + IpcPackageActionRequest request + ) + { + ArgumentNullException.ThrowIfNull(request); + + var package = FindAnyPackage(request); + await package.Details.Load(); + + return new IpcPackageDetailsInfo + { + Name = package.Name, + Id = package.Id, + Version = package.VersionString, + NewVersion = package.IsUpgradable ? package.NewVersionString : "", + Source = package.Source.AsString_DisplayName, + Manager = IpcManagerSettingsApi.GetPublicManagerId(package.Manager), + Description = package.Details.Description ?? "", + Publisher = package.Details.Publisher ?? "", + Author = package.Details.Author ?? "", + HomepageUrl = package.Details.HomepageUrl?.ToString() ?? "", + License = package.Details.License ?? "", + LicenseUrl = package.Details.LicenseUrl?.ToString() ?? "", + InstallerUrl = package.Details.InstallerUrl?.ToString() ?? "", + InstallerHash = package.Details.InstallerHash ?? "", + InstallerType = package.Details.InstallerType ?? "", + InstallerSize = package.Details.InstallerSize, + ManifestUrl = package.Details.ManifestUrl?.ToString() ?? "", + UpdateDate = package.Details.UpdateDate ?? "", + ReleaseNotes = package.Details.ReleaseNotes ?? "", + ReleaseNotesUrl = package.Details.ReleaseNotesUrl?.ToString() ?? "", + IconUrl = package.GetIconUrl().ToString(), + InstallLocation = package.Manager.DetailsHelper.GetInstallLocation(package) ?? "", + IgnoredVersion = await package.GetIgnoredUpdatesVersionAsync(), + Tags = package.Details.Tags.Where(tag => !string.IsNullOrWhiteSpace(tag)).ToArray(), + Versions = package.Manager.DetailsHelper.GetVersions(package), + Screenshots = package + .GetScreenshots() + .Select(screenshot => screenshot.ToString()) + .ToArray(), + Dependencies = package.Details.Dependencies + .Select(dependency => new IpcPackageDependencyInfo + { + Name = dependency.Name, + Version = dependency.Version, + Mandatory = dependency.Mandatory, + }) + .ToArray(), + }; + } + + public static IPackage ResolvePackage(IpcPackageActionRequest request) + { + ArgumentNullException.ThrowIfNull(request); + return FindAnyPackage(request); + } + + public static IReadOnlyList GetPackageVersions(IpcPackageActionRequest request) + { + ArgumentNullException.ThrowIfNull(request); + + var package = FindAnyPackage(request); + return package.Manager.DetailsHelper.GetVersions(package); + } + + public static IReadOnlyList ListIgnoredUpdates() + { + return IgnoredUpdatesDatabase.GetDatabase() + .Select(entry => + { + string[] parts = entry.Key.Split('\\', 2); + string version = entry.Value; + + return new IpcIgnoredUpdateInfo + { + IgnoredId = entry.Key, + Manager = parts.Length > 0 + ? IpcManagerSettingsApi.GetPublicManagerId(parts[0]) + : "", + PackageId = parts.Length > 1 ? parts[1] : "", + Version = version, + IgnoreAllVersions = version == "*", + IsPauseUntilDate = version.StartsWith("<", StringComparison.Ordinal), + PauseUntil = version.StartsWith("<", StringComparison.Ordinal) + ? version[1..] + : "", + }; + }) + .OrderBy(entry => entry.Manager, StringComparer.OrdinalIgnoreCase) + .ThenBy(entry => entry.PackageId, StringComparer.OrdinalIgnoreCase) + .ToArray(); + } + + public static async Task IgnorePackageUpdateAsync( + IpcPackageActionRequest request + ) + { + ArgumentNullException.ThrowIfNull(request); + + var package = FindPackageForStateMutation(request); + await package.AddToIgnoredUpdatesAsync( + string.IsNullOrWhiteSpace(request.Version) ? "*" : request.Version + ); + await RefreshUpgradablePackagesSnapshotAsync(); + + return new IpcCommandResult + { + Command = "ignore-package", + Message = $"Ignored updates for {package.Id}.", + }; + } + + public static async Task RemoveIgnoredUpdateAsync( + IpcPackageActionRequest request + ) + { + ArgumentNullException.ThrowIfNull(request); + + var package = TryFindPackageForStateMutation(request); + if (package is not null) + { + await package.RemoveFromIgnoredUpdatesAsync(); + } + else + { + var manager = GetManagers(request.ManagerName).FirstOrDefault() + ?? throw new InvalidOperationException( + "The manager parameter is required when removing an ignored update for a package that is not currently discoverable." + ); + IgnoredUpdatesDatabase.Remove($"{manager.Properties.Name.ToLowerInvariant()}\\{request.PackageId}"); + } + + await RefreshUpgradablePackagesSnapshotAsync(); + return IpcCommandResult.Success("unignore-package"); + } + + private static async Task ExecuteOperationAsync( + string command, + IPackage package, + IpcPackageActionRequest request, + Func operationFactory + ) + { + var options = await InstallOptionsFactory.LoadApplicableAsync(package); + ApplyRequestOptions(options, request); + + var operation = operationFactory(package, options); + string operationId = IpcOperationApi.Track(operation); + + if (request.WaitForCompletion == false) + { + _ = Task.Run(() => RunTrackedOperationAsync(operation)); + return CreateOperationResult( + command, + package, + operation, + completed: false, + operationId: operationId + ); + } + + await RunTrackedOperationAsync(operation); + + return CreateOperationResult(command, package, operation, operationId: operationId); + } + + private static async Task RunTrackedOperationAsync(AbstractOperation operation) + { + try + { + await operation.MainThread(); + } + finally + { + operation.Dispose(); + } + } + + private static void ApplyRequestOptions( + InstallOptions options, + IpcPackageActionRequest request + ) + { + if (!string.IsNullOrWhiteSpace(request.Version)) + { + options.Version = request.Version; + } + + if (!string.IsNullOrWhiteSpace(request.Scope)) + { + options.InstallationScope = request.Scope; + } + + if (request.PreRelease.HasValue) + { + options.PreRelease = request.PreRelease.Value; + } + + if (request.Elevated.HasValue) + { + options.RunAsAdministrator = request.Elevated.Value; + } + + if (request.Interactive.HasValue) + { + options.InteractiveInstallation = request.Interactive.Value; + } + + if (request.SkipHash.HasValue) + { + options.SkipHashCheck = request.SkipHash.Value; + } + + if (request.RemoveData.HasValue) + { + options.RemoveDataOnUninstall = request.RemoveData.Value; + } + + if (!string.IsNullOrWhiteSpace(request.Architecture)) + { + options.Architecture = request.Architecture; + } + + if (!string.IsNullOrWhiteSpace(request.InstallLocation)) + { + options.CustomInstallLocation = request.InstallLocation; + } + } + + internal static void ApplyRequestedOptions( + InstallOptions options, + IpcPackageActionRequest request + ) + { + ApplyRequestOptions(options, request); + } + + internal static IPackage ResolvePackage( + IpcPackageActionRequest request, + IpcPackageLookupMode lookupMode = IpcPackageLookupMode.Any + ) + { + return lookupMode switch + { + IpcPackageLookupMode.Search => FindSearchResult(request), + IpcPackageLookupMode.Installed => FindInstalledPackage(request), + IpcPackageLookupMode.Upgradable => FindUpgradablePackage(request), + IpcPackageLookupMode.InstalledOrUpgradable => FindUpgradablePackageOrInstalledPackage( + request + ), + _ => FindAnyPackage(request), + }; + } + + internal static IpcPackageInfo CreateIpcPackageInfo(IPackage package) + { + return ToIpcPackageInfo(package); + } + + internal static IpcPackageOperationResult CreateOperationResult( + string command, + IPackage package, + AbstractOperation operation, + string? outputPath = null, + bool completed = true, + string? operationId = null + ) + { + return new IpcPackageOperationResult + { + Status = completed && operation.Status != OperationStatus.Succeeded ? "error" : "success", + Command = command, + OperationId = operationId ?? operation.Metadata.Identifier, + OperationStatus = operation.Status.ToString().ToLowerInvariant(), + Completed = completed, + Message = operation.Status switch + { + _ when !completed => "The operation was queued for background execution.", + OperationStatus.Succeeded => null, + OperationStatus.Canceled => "The operation was canceled.", + _ => operation.GetOutput().LastOrDefault().Item1, + }, + Package = ToIpcPackageInfo(package), + OutputPath = outputPath, + Output = operation.GetOutput().Select(line => line.Item1).ToArray(), + }; + } + + private static IPackage FindSearchResult(IpcPackageActionRequest request) + { + foreach (var manager in GetManagers(request.ManagerName)) + { + var package = manager.FindPackages(request.PackageId).FirstOrDefault(candidate => + MatchesIdentity(candidate, request) + ); + if (package is not null) + { + return package; + } + } + + throw new InvalidOperationException( + $"No package matching id \"{request.PackageId}\" was found." + ); + } + + private static IPackage FindAnyPackage(IpcPackageActionRequest request) + { + return TryFindPackageForStateMutation(request) + ?? FindSearchResult(request); + } + + private static IPackage FindInstalledPackage(IpcPackageActionRequest request) + { + var package = GetInstalledPackagesSnapshot(request.ManagerName).FirstOrDefault(candidate => + MatchesIdentity(candidate, request) + ); + if (package is not null) + { + return package; + } + + throw new InvalidOperationException( + $"No installed package matching id \"{request.PackageId}\" was found." + ); + } + + private static IPackage FindUpgradablePackage(IpcPackageActionRequest request) + { + var package = GetUpgradablePackagesSnapshot(request.ManagerName).FirstOrDefault(candidate => + MatchesIdentity(candidate, request) + ); + if (package is not null) + { + return package; + } + + throw new InvalidOperationException( + $"No upgradable package matching id \"{request.PackageId}\" was found." + ); + } + + private static IPackage FindUpgradablePackageOrInstalledPackage( + IpcPackageActionRequest request + ) + { + try + { + return FindUpgradablePackage(request); + } + catch (InvalidOperationException) + { + return FindInstalledPackage(request); + } + } + + private static IPackage FindPackageForStateMutation(IpcPackageActionRequest request) + { + return TryFindPackageForStateMutation(request) + ?? throw new InvalidOperationException( + $"No package matching id \"{request.PackageId}\" was found." + ); + } + + private static IPackage? TryFindPackageForStateMutation(IpcPackageActionRequest request) + { + try + { + return FindUpgradablePackageOrInstalledPackage(request); + } + catch (InvalidOperationException) + { + return null; + } + } + + private static IReadOnlyList GetInstalledPackagesSnapshot(string? managerName) + { + var loaderPackages = GetLoaderPackages( + InstalledPackagesLoader.Instance, + managerName, + loader => loader.ReloadPackages() + ); + if (loaderPackages.Count > 0) + { + return loaderPackages; + } + + return GetManagers(managerName).SelectMany(manager => manager.GetInstalledPackages()).ToArray(); + } + + private static async Task RefreshUpgradablePackagesSnapshotAsync() + { + if (UpgradablePackagesLoader.Instance is null || UpgradablePackagesLoader.Instance.IsLoading) + { + return; + } + + await UpgradablePackagesLoader.Instance.ReloadPackages(); + } + + private static IReadOnlyList GetUpgradablePackagesSnapshot(string? managerName) + { + var loaderPackages = GetLoaderPackages( + UpgradablePackagesLoader.Instance, + managerName, + loader => loader.ReloadPackages() + ); + if (loaderPackages.Count > 0) + { + return loaderPackages; + } + + return GetManagers(managerName).SelectMany(manager => manager.GetAvailableUpdates()).ToArray(); + } + + private static IReadOnlyList GetLoaderPackages( + AbstractPackageLoader? loader, + string? managerName, + Func reload + ) + { + if (loader is null) + { + return []; + } + + if (loader.Packages.Count > 0) + { + return loader.Packages.Where(package => MatchesManager(package.Manager, managerName)).ToArray(); + } + + if (!loader.IsLoaded && !loader.IsLoading) + { + reload(loader).GetAwaiter().GetResult(); + } + + return loader.Packages.Where(package => MatchesManager(package.Manager, managerName)).ToArray(); + } + + private static IReadOnlyList GetManagers(string? managerName) + { + var managers = PEInterface.Managers + .Where(manager => manager.IsEnabled() && manager.IsReady()) + .Where(manager => MatchesManager(manager, managerName)) + .ToArray(); + + if (managers.Length == 0) + { + if (string.IsNullOrWhiteSpace(managerName)) + { + throw new InvalidOperationException("No ready package managers are available."); + } + + throw new InvalidOperationException( + $"No ready package manager matching \"{managerName}\" is available." + ); + } + + return managers; + } + + private static bool MatchesManager(IPackageManager manager, string? requestedManager) + { + return IpcManagerSettingsApi.MatchesManagerId(manager, requestedManager); + } + + private static bool MatchesIdentity(IPackage package, IpcPackageActionRequest request) + { + if (!package.Id.Equals(request.PackageId, StringComparison.OrdinalIgnoreCase)) + { + return false; + } + + return string.IsNullOrWhiteSpace(request.PackageSource) + || package.Source.Name.Equals(request.PackageSource, StringComparison.OrdinalIgnoreCase) + || package.Source.AsString_DisplayName.Equals( + request.PackageSource, + StringComparison.OrdinalIgnoreCase + ); + } + + private static string GetPackageIdentity(IPackage package) + { + return $"{package.Manager.Id}|{package.Source.Name}|{package.Id}|{package.VersionString}|{package.NewVersionString}"; + } + + private static IpcPackageInfo ToIpcPackageInfo(IPackage package) + { + return new IpcPackageInfo + { + Name = package.Name, + Id = package.Id, + Version = package.VersionString, + NewVersion = package.IsUpgradable ? package.NewVersionString : "", + Source = package.Source.AsString_DisplayName, + Manager = IpcManagerSettingsApi.GetPublicManagerId(package.Manager), + IsUpgradable = package.IsUpgradable, + }; + } +} diff --git a/src/UniGetUI.Interface.IpcApi/IpcSecureSettingsApi.cs b/src/UniGetUI.Interface.IpcApi/IpcSecureSettingsApi.cs new file mode 100644 index 0000000..6fe0ff1 --- /dev/null +++ b/src/UniGetUI.Interface.IpcApi/IpcSecureSettingsApi.cs @@ -0,0 +1,105 @@ +using UniGetUI.Core.SettingsEngine.SecureSettings; + +namespace UniGetUI.Interface; + +public sealed class IpcSecureSettingInfo +{ + public string Key { get; set; } = ""; + public string Name { get; set; } = ""; + public string UserName { get; set; } = ""; + public bool IsCurrentUser { get; set; } + public bool Enabled { get; set; } +} + +public sealed class IpcSecureSettingRequest +{ + public string SettingKey { get; set; } = ""; + public string? UserName { get; set; } + public bool Enabled { get; set; } +} + +public static class IpcSecureSettingsApi +{ + public static IReadOnlyList ListSettings(string? userName = null) + { + string resolvedUser = ResolveUserName(userName); + return Enum.GetValues() + .Where(key => key != SecureSettings.K.Unset) + .OrderBy(key => key.ToString(), StringComparer.OrdinalIgnoreCase) + .Select(key => ToSecureSettingInfo(key, resolvedUser)) + .ToArray(); + } + + public static IpcSecureSettingInfo GetSetting(string settingKey, string? userName = null) + { + return ToSecureSettingInfo(ResolveSettingKey(settingKey), ResolveUserName(userName)); + } + + public static async Task SetSettingAsync( + IpcSecureSettingRequest request + ) + { + ArgumentNullException.ThrowIfNull(request); + var key = ResolveSettingKey(request.SettingKey); + string userName = ResolveUserName(request.UserName); + + bool success = userName.Equals(Environment.UserName, StringComparison.OrdinalIgnoreCase) + ? await SecureSettings.TrySet(key, request.Enabled) + : SecureSettings.ApplyForUser(userName, SecureSettings.ResolveKey(key), request.Enabled) == 0; + + if (!success) + { + throw new InvalidOperationException( + $"Could not update secure setting \"{SecureSettings.ResolveKey(key)}\" for user \"{userName}\"." + ); + } + + return ToSecureSettingInfo(key, userName); + } + + private static IpcSecureSettingInfo ToSecureSettingInfo( + SecureSettings.K key, + string userName + ) + { + return new IpcSecureSettingInfo + { + Key = key.ToString(), + Name = SecureSettings.ResolveKey(key), + UserName = userName, + IsCurrentUser = userName.Equals(Environment.UserName, StringComparison.OrdinalIgnoreCase), + Enabled = SecureSettings.GetForUser(userName, key), + }; + } + + private static SecureSettings.K ResolveSettingKey(string settingKey) + { + if (string.IsNullOrWhiteSpace(settingKey)) + { + throw new InvalidOperationException("The secure setting key parameter is required."); + } + + if (Enum.TryParse(settingKey, true, out SecureSettings.K enumKey) && enumKey != SecureSettings.K.Unset) + { + return enumKey; + } + + foreach (var key in Enum.GetValues()) + { + if ( + key != SecureSettings.K.Unset + && SecureSettings.ResolveKey(key).Equals(settingKey, StringComparison.OrdinalIgnoreCase) + ) + { + return key; + } + } + + throw new InvalidOperationException($"No secure setting matching \"{settingKey}\" was found."); + } + + private static string ResolveUserName(string? userName) + { + return string.IsNullOrWhiteSpace(userName) ? Environment.UserName : userName.Trim(); + } +} diff --git a/src/UniGetUI.Interface.IpcApi/IpcServer.cs b/src/UniGetUI.Interface.IpcApi/IpcServer.cs new file mode 100644 index 0000000..b4b8aca --- /dev/null +++ b/src/UniGetUI.Interface.IpcApi/IpcServer.cs @@ -0,0 +1,1940 @@ +using System.Diagnostics.CodeAnalysis; +using System.Text; +using System.Text.Json; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Server.Kestrel.Core; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using UniGetUI.Core.Data; +using UniGetUI.Core.IconEngine; +using UniGetUI.Core.Logging; +using UniGetUI.Core.SettingsEngine; +using UniGetUI.Core.Tools; +using UniGetUI.Interface.Enums; +using UniGetUI.PackageEngine; +using UniGetUI.PackageEngine.Interfaces; +using UniGetUI.PackageEngine.PackageLoader; + +namespace UniGetUI.Interface +{ + internal static class ApiTokenHolder + { + public static string Token = ""; + } + + [UnconditionalSuppressMessage( + "Trimming", + "IL2026", + Justification = "IPC JSON metadata is supplied by IpcJsonContext; remaining ASP.NET Core JSON overload warnings are guarded by that generated resolver.")] + public class IpcServer + { + public string SessionId { get; } = Guid.NewGuid().ToString("N"); + public string SessionKind { get; init; } = IpcTransportOptions.GuiSessionKind; + public event EventHandler? OnUpgradeAll; + public event EventHandler? OnUpgradeAllForManager; + public Func? AppInfoProvider; + public Func? ShowAppHandler; + public Func? NavigateAppHandler; + public Func? QuitAppHandler; + public Func? ShowPackageHandler; + + private IHost? _host; + private IpcTransportOptions _transportOptions = + IpcTransportOptions.LoadForServer(); + private string? _namedPipePath; + private int _stopRequested; + + public IpcServer() { } + + public static bool AuthenticateToken(string? token) + { + return token == ApiTokenHolder.Token; + } + + public async Task Start() + { + _transportOptions = IpcTransportOptions.LoadForServer(); + _namedPipePath = _transportOptions.NamedPipePath; + PrepareTransportEndpoint(); + ApiTokenHolder.Token = CoreTools.RandomString(64); + Logger.Info("Generated a IPC API auth token for the current session"); + + var builder = WebApplication.CreateSlimBuilder(new WebApplicationOptions + { + Args = [], + ApplicationName = typeof(IpcServer).Assembly.FullName, + }); + builder.Services.AddCors(); + builder.WebHost.UseKestrel(ConfigureTransport); +#if !DEBUG + builder.WebHost.UseSetting(WebHostDefaults.SuppressStatusMessagesKey, "true"); +#endif + var app = builder.Build(); + app.UseCors(policy => + policy.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader() + ); + var endpoints = app; + endpoints.MapGet(IpcHttpRoutes.Path("/status"), V3_Status); + endpoints.MapGet(IpcHttpRoutes.Path("/app"), V3_GetAppInfo); + endpoints.MapPost(IpcHttpRoutes.Path("/app/show"), V3_ShowApp); + endpoints.MapPost(IpcHttpRoutes.Path("/app/navigate"), V3_NavigateApp); + endpoints.MapPost(IpcHttpRoutes.Path("/app/quit"), V3_QuitApp); + endpoints.MapGet(IpcHttpRoutes.Path("/operations"), V3_ListOperations); + endpoints.MapGet( + IpcHttpRoutes.Path("/operations/{operationId}"), + V3_GetOperation + ); + endpoints.MapGet( + IpcHttpRoutes.Path("/operations/{operationId}/output"), + V3_GetOperationOutput + ); + endpoints.MapPost( + IpcHttpRoutes.Path("/operations/{operationId}/cancel"), + V3_CancelOperation + ); + endpoints.MapPost( + IpcHttpRoutes.Path("/operations/{operationId}/retry"), + V3_RetryOperation + ); + endpoints.MapPost( + IpcHttpRoutes.Path("/operations/{operationId}/reorder"), + V3_ReorderOperation + ); + endpoints.MapPost( + IpcHttpRoutes.Path("/operations/{operationId}/forget"), + V3_ForgetOperation + ); + endpoints.MapGet(IpcHttpRoutes.Path("/managers"), V3_ListManagers); + endpoints.MapGet( + IpcHttpRoutes.Path("/managers/maintenance"), + V3_GetManagerMaintenance + ); + endpoints.MapPost( + IpcHttpRoutes.Path("/managers/maintenance/reload"), + V3_ReloadManager + ); + endpoints.MapPost( + IpcHttpRoutes.Path("/managers/maintenance/executable/set"), + V3_SetManagerExecutable + ); + endpoints.MapPost( + IpcHttpRoutes.Path("/managers/maintenance/executable/clear"), + V3_ClearManagerExecutable + ); + endpoints.MapPost( + IpcHttpRoutes.Path("/managers/maintenance/action"), + V3_RunManagerAction + ); + endpoints.MapGet(IpcHttpRoutes.Path("/sources"), V3_ListSources); + endpoints.MapPost(IpcHttpRoutes.Path("/sources/add"), V3_AddSource); + endpoints.MapPost(IpcHttpRoutes.Path("/sources/remove"), V3_RemoveSource); + endpoints.MapGet(IpcHttpRoutes.Path("/settings"), V3_ListSettings); + endpoints.MapGet(IpcHttpRoutes.Path("/settings/item"), V3_GetSetting); + endpoints.MapPost(IpcHttpRoutes.Path("/settings/set"), V3_SetSetting); + endpoints.MapPost(IpcHttpRoutes.Path("/settings/clear"), V3_ClearSetting); + endpoints.MapPost(IpcHttpRoutes.Path("/settings/reset"), V3_ResetSettings); + endpoints.MapGet( + IpcHttpRoutes.Path("/secure-settings"), + V3_ListSecureSettings + ); + endpoints.MapGet( + IpcHttpRoutes.Path("/secure-settings/item"), + V3_GetSecureSetting + ); + endpoints.MapPost( + IpcHttpRoutes.Path("/secure-settings/set"), + V3_SetSecureSetting + ); + endpoints.MapPost( + IpcHttpRoutes.Path("/managers/set-enabled"), + V3_SetManagerEnabled + ); + endpoints.MapPost( + IpcHttpRoutes.Path("/managers/set-update-notifications"), + V3_SetManagerUpdateNotifications + ); + endpoints.MapGet( + IpcHttpRoutes.Path("/desktop-shortcuts"), + V3_ListDesktopShortcuts + ); + endpoints.MapPost( + IpcHttpRoutes.Path("/desktop-shortcuts/set"), + V3_SetDesktopShortcut + ); + endpoints.MapPost( + IpcHttpRoutes.Path("/desktop-shortcuts/reset"), + V3_ResetDesktopShortcut + ); + endpoints.MapPost( + IpcHttpRoutes.Path("/desktop-shortcuts/reset-all"), + V3_ResetDesktopShortcuts + ); + endpoints.MapGet(IpcHttpRoutes.Path("/logs/app"), V3_GetAppLog); + endpoints.MapGet( + IpcHttpRoutes.Path("/logs/history"), + V3_GetOperationHistory + ); + endpoints.MapGet(IpcHttpRoutes.Path("/logs/manager"), V3_GetManagerLog); + endpoints.MapGet(IpcHttpRoutes.Path("/backups/status"), V3_GetBackupStatus); + endpoints.MapPost( + IpcHttpRoutes.Path("/backups/local/create"), + V3_CreateLocalBackup + ); + endpoints.MapPost( + IpcHttpRoutes.Path("/backups/github/sign-in/start"), + V3_StartGitHubDeviceFlow + ); + endpoints.MapPost( + IpcHttpRoutes.Path("/backups/github/sign-in/complete"), + V3_CompleteGitHubDeviceFlow + ); + endpoints.MapPost( + IpcHttpRoutes.Path("/backups/github/sign-out"), + V3_SignOutGitHub + ); + endpoints.MapGet( + IpcHttpRoutes.Path("/backups/cloud"), + V3_ListCloudBackups + ); + endpoints.MapPost( + IpcHttpRoutes.Path("/backups/cloud/create"), + V3_CreateCloudBackup + ); + endpoints.MapPost( + IpcHttpRoutes.Path("/backups/cloud/download"), + V3_DownloadCloudBackup + ); + endpoints.MapPost( + IpcHttpRoutes.Path("/backups/cloud/restore"), + V3_RestoreCloudBackup + ); + endpoints.MapGet(IpcHttpRoutes.Path("/bundles"), V3_GetBundle); + endpoints.MapPost(IpcHttpRoutes.Path("/bundles/reset"), V3_ResetBundle); + endpoints.MapPost(IpcHttpRoutes.Path("/bundles/import"), V3_ImportBundle); + endpoints.MapPost(IpcHttpRoutes.Path("/bundles/export"), V3_ExportBundle); + endpoints.MapPost(IpcHttpRoutes.Path("/bundles/add"), V3_AddBundlePackage); + endpoints.MapPost( + IpcHttpRoutes.Path("/bundles/remove"), + V3_RemoveBundlePackage + ); + endpoints.MapPost( + IpcHttpRoutes.Path("/bundles/install"), + V3_InstallBundle + ); + endpoints.MapGet( + IpcHttpRoutes.Path("/packages/search"), + V3_SearchPackages + ); + endpoints.MapGet( + IpcHttpRoutes.Path("/packages/installed"), + V3_ListInstalledPackages + ); + endpoints.MapGet( + IpcHttpRoutes.Path("/packages/updates"), + V3_ListUpgradablePackages + ); + endpoints.MapGet( + IpcHttpRoutes.Path("/packages/details"), + V3_GetPackageDetails + ); + endpoints.MapGet( + IpcHttpRoutes.Path("/packages/versions"), + V3_GetPackageVersions + ); + endpoints.MapGet( + IpcHttpRoutes.Path("/packages/ignored"), + V3_ListIgnoredUpdates + ); + endpoints.MapPost(IpcHttpRoutes.Path("/packages/ignore"), V3_IgnorePackage); + endpoints.MapPost( + IpcHttpRoutes.Path("/packages/unignore"), + V3_UnignorePackage + ); + endpoints.MapPost( + IpcHttpRoutes.Path("/packages/download"), + V3_DownloadPackage + ); + endpoints.MapPost( + IpcHttpRoutes.Path("/packages/install"), + V3_InstallPackage + ); + endpoints.MapPost( + IpcHttpRoutes.Path("/packages/reinstall"), + V3_ReinstallPackage + ); + endpoints.MapPost(IpcHttpRoutes.Path("/packages/update"), V3_UpdatePackage); + endpoints.MapPost( + IpcHttpRoutes.Path("/packages/uninstall"), + V3_UninstallPackage + ); + endpoints.MapPost( + IpcHttpRoutes.Path("/packages/uninstall-then-reinstall"), + V3_UninstallThenReinstallPackage + ); + endpoints.MapPost(IpcHttpRoutes.Path("/packages/show"), V3_ShowPackage); + endpoints.MapPost( + IpcHttpRoutes.Path("/packages/update-all"), + V3_UpdateAllPackages + ); + endpoints.MapPost( + IpcHttpRoutes.Path("/packages/update-manager"), + V3_UpdateAllPackagesForManager + ); + _host = app; + try + { + await _host.StartAsync(); + ApplyTransportSecurity(); + _transportOptions.Persist( + SessionId, + ApiTokenHolder.Token, + SessionKind, + Environment.ProcessId + ); + } + catch + { + IpcTransportOptions.DeletePersistedMetadata(SessionId); + CleanupTransportEndpoint(); + _host.Dispose(); + _host = null; + throw; + } + Logger.Info( + _transportOptions.TransportKind == IpcTransportKind.NamedPipe + ? OperatingSystem.IsWindows() + ? $"Api running on named pipe {_transportOptions.NamedPipeName}" + : $"Api running on unix socket {_transportOptions.NamedPipeDisplayName}" + : $"Api running on {_transportOptions.BaseAddressString}" + ); + } + + private void ConfigureTransport(KestrelServerOptions serverOptions) + { + if (_transportOptions.TransportKind == IpcTransportKind.NamedPipe) + { + if (OperatingSystem.IsWindows()) + { + serverOptions.ListenNamedPipe( + _transportOptions.NamedPipeName, + listenOptions => + { + listenOptions.Protocols = HttpProtocols.Http1; + } + ); + } + else + { + serverOptions.ListenUnixSocket( + _namedPipePath + ?? throw new InvalidOperationException( + "The Unix socket path is not available for the current transport." + ), + listenOptions => + { + listenOptions.Protocols = HttpProtocols.Http1; + } + ); + } + } + else + { + serverOptions.ListenLocalhost(_transportOptions.TcpPort); + } + } + + private void PrepareTransportEndpoint() + { + if (_transportOptions.TransportKind != IpcTransportKind.NamedPipe + || OperatingSystem.IsWindows()) + { + return; + } + + if (string.IsNullOrWhiteSpace(_namedPipePath)) + { + throw new InvalidOperationException( + "The Unix socket path is required for the named-pipe transport." + ); + } + + string? directory = Path.GetDirectoryName(_namedPipePath); + if (!string.IsNullOrWhiteSpace(directory)) + { + Directory.CreateDirectory(directory); + } + + if (File.Exists(_namedPipePath)) + { + if (HasExplicitUnixSocketPath()) + { + throw new InvalidOperationException( + $"Cannot bind the IPC API Unix socket because the explicit path \"{_namedPipePath}\" already exists." + ); + } + + DeleteUnixSocketFile(_namedPipePath); + } + } + + private void CleanupTransportEndpoint() + { + if (_transportOptions.TransportKind != IpcTransportKind.NamedPipe + || OperatingSystem.IsWindows() + || string.IsNullOrWhiteSpace(_namedPipePath)) + { + return; + } + + DeleteUnixSocketFile(_namedPipePath); + } + + private void ApplyTransportSecurity() + { + if (_transportOptions.TransportKind != IpcTransportKind.NamedPipe + || OperatingSystem.IsWindows() + || string.IsNullOrWhiteSpace(_namedPipePath)) + { + return; + } + + if (!File.Exists(_namedPipePath)) + { + throw new InvalidOperationException( + $"The IPC API Unix socket \"{_namedPipePath}\" was not created." + ); + } + + File.SetUnixFileMode( + _namedPipePath, + IpcTransportOptions.SameUserUnixSocketMode + ); + } + + private bool HasExplicitUnixSocketPath() + { + return _transportOptions.NamedPipeName.StartsWith("/", StringComparison.Ordinal); + } + + private static void DeleteUnixSocketFile(string path) + { + if (File.Exists(path)) + { + File.Delete(path); + } + } + + private async Task V3_Status(HttpContext context) + { + await context.Response.WriteAsJsonAsync( + new IpcStatus + { + Running = true, + Transport = _transportOptions.TransportKind switch + { + IpcTransportKind.NamedPipe => "named-pipe", + _ => "tcp", + }, + TcpPort = _transportOptions.TcpPort, + NamedPipeName = _transportOptions.NamedPipeName, + NamedPipePath = _transportOptions.NamedPipePath ?? "", + BaseAddress = _transportOptions.BaseAddressString, + Version = CoreData.VersionName, + BuildNumber = CoreData.BuildNumber, + }, + IpcJson.Options + ); + } + + private async Task V3_ListManagers(HttpContext context) + { + if (!AuthenticateToken(context.Request.Query["token"])) + { + context.Response.StatusCode = 401; + return; + } + + await context.Response.WriteAsJsonAsync( + IpcManagerSettingsApi.ListManagers(), + IpcJson.Options + ); + } + + private async Task V3_GetAppInfo(HttpContext context) + { + if (!AuthenticateToken(context.Request.Query["token"])) + { + context.Response.StatusCode = 401; + return; + } + + try + { + await context.Response.WriteAsJsonAsync( + AppInfoProvider?.Invoke() + ?? throw new InvalidOperationException( + "The application did not register an app-state provider." + ), + IpcJson.Options + ); + } + catch (InvalidOperationException ex) + { + context.Response.StatusCode = 400; + await context.Response.WriteAsync(ex.Message); + } + } + + private async Task V3_ShowApp(HttpContext context) + { + await HandleCommandAsync( + context, + () => + ShowAppHandler?.Invoke() + ?? throw new InvalidOperationException( + "The current UniGetUI session cannot show a window." + ) + ); + } + + private async Task V3_NavigateApp(HttpContext context) + { + await HandleCommandAsync( + context, + () => + NavigateAppHandler?.Invoke(BuildAppNavigateRequest(context.Request)) + ?? throw new InvalidOperationException( + "The current UniGetUI session cannot navigate application pages." + ) + ); + } + + private async Task V3_QuitApp(HttpContext context) + { + await HandleCommandAsync( + context, + () => + QuitAppHandler?.Invoke() + ?? throw new InvalidOperationException( + "The current UniGetUI session cannot be shut down through automation." + ) + ); + } + + private async Task V3_ListOperations(HttpContext context) + { + await HandleReadAsync(context, IpcOperationApi.ListOperations); + } + + private async Task V3_GetOperation(HttpContext context) + { + await HandleReadAsync( + context, + () => IpcOperationApi.GetOperation(GetRequiredRouteValue(context, "operationId")) + ); + } + + private async Task V3_GetOperationOutput(HttpContext context) + { + await HandleReadAsync( + context, + () => IpcOperationApi.GetOperationOutput( + GetRequiredRouteValue(context, "operationId"), + int.TryParse(context.Request.Query["tailLines"], out int tailLines) + ? tailLines + : null + ) + ); + } + + private async Task V3_CancelOperation(HttpContext context) + { + await HandleCommandAsync( + context, + () => IpcOperationApi.CancelOperation(GetRequiredRouteValue(context, "operationId")) + ); + } + + private async Task V3_RetryOperation(HttpContext context) + { + await HandleCommandAsync( + context, + () => IpcOperationApi.RetryOperation( + GetRequiredRouteValue(context, "operationId"), + context.Request.Query.TryGetValue("mode", out var mode) ? mode.ToString() : null + ) + ); + } + + private async Task V3_ReorderOperation(HttpContext context) + { + await HandleCommandAsync( + context, + () => IpcOperationApi.ReorderOperation( + GetRequiredRouteValue(context, "operationId"), + GetRequiredQueryValue(context, "action") + ) + ); + } + + private async Task V3_ForgetOperation(HttpContext context) + { + await HandleCommandAsync( + context, + () => IpcOperationApi.ForgetOperation(GetRequiredRouteValue(context, "operationId")) + ); + } + + private async Task V3_ListSources(HttpContext context) + { + if (!AuthenticateToken(context.Request.Query["token"])) + { + context.Response.StatusCode = 401; + return; + } + + try + { + await context.Response.WriteAsJsonAsync( + IpcManagerSettingsApi.ListSources(context.Request.Query["manager"]), + IpcJson.Options + ); + } + catch (InvalidOperationException ex) + { + context.Response.StatusCode = 400; + await context.Response.WriteAsync(ex.Message); + } + } + + private async Task V3_GetManagerMaintenance(HttpContext context) + { + if (!AuthenticateToken(context.Request.Query["token"])) + { + context.Response.StatusCode = 401; + return; + } + + string managerName = context.Request.Query["manager"].ToString(); + if (string.IsNullOrWhiteSpace(managerName)) + { + context.Response.StatusCode = 400; + await context.Response.WriteAsync("The manager parameter is required."); + return; + } + + try + { + await context.Response.WriteAsJsonAsync( + IpcManagerMaintenanceApi.GetMaintenanceInfo(managerName), + IpcJson.Options + ); + } + catch (InvalidOperationException ex) + { + context.Response.StatusCode = 400; + await context.Response.WriteAsync(ex.Message); + } + } + + private async Task V3_ReloadManager(HttpContext context) + { + await HandleManagerMaintenanceActionAsync< + IpcManagerMaintenanceRequest, + IpcManagerMaintenanceActionResult + >(context, IpcManagerMaintenanceApi.ReloadManagerAsync); + } + + private async Task V3_SetManagerExecutable(HttpContext context) + { + await HandleManagerMaintenanceActionAsync< + IpcManagerMaintenanceRequest, + IpcManagerMaintenanceActionResult + >(context, IpcManagerMaintenanceApi.SetExecutablePathAsync); + } + + private async Task V3_ClearManagerExecutable(HttpContext context) + { + await HandleManagerMaintenanceActionAsync< + IpcManagerMaintenanceRequest, + IpcManagerMaintenanceActionResult + >(context, IpcManagerMaintenanceApi.ClearExecutablePathAsync); + } + + private async Task V3_RunManagerAction(HttpContext context) + { + await HandleManagerMaintenanceActionAsync< + IpcManagerMaintenanceRequest, + IpcManagerMaintenanceActionResult + >(context, IpcManagerMaintenanceApi.RunActionAsync); + } + + private async Task V3_AddSource(HttpContext context) + { + await HandleSourceActionAsync(context, IpcManagerSettingsApi.AddSourceAsync); + } + + private async Task V3_RemoveSource(HttpContext context) + { + await HandleSourceActionAsync(context, IpcManagerSettingsApi.RemoveSourceAsync); + } + + private async Task V3_ListSettings(HttpContext context) + { + if (!AuthenticateToken(context.Request.Query["token"])) + { + context.Response.StatusCode = 401; + return; + } + + await context.Response.WriteAsJsonAsync( + IpcManagerSettingsApi.ListSettings(), + IpcJson.Options + ); + } + + private async Task V3_GetSetting(HttpContext context) + { + if (!AuthenticateToken(context.Request.Query["token"])) + { + context.Response.StatusCode = 401; + return; + } + + string key = context.Request.Query["key"].ToString(); + if (string.IsNullOrWhiteSpace(key)) + { + context.Response.StatusCode = 400; + await context.Response.WriteAsync("The key parameter is required."); + return; + } + + try + { + await context.Response.WriteAsJsonAsync( + IpcManagerSettingsApi.GetSetting(key), + IpcJson.Options + ); + } + catch (InvalidOperationException ex) + { + context.Response.StatusCode = 400; + await context.Response.WriteAsync(ex.Message); + } + } + + private async Task V3_SetSetting(HttpContext context) + { + if (!AuthenticateToken(context.Request.Query["token"])) + { + context.Response.StatusCode = 401; + return; + } + + try + { + await context.Response.WriteAsJsonAsync( + IpcManagerSettingsApi.SetSetting( + new IpcSettingValueRequest + { + SettingKey = GetRequiredQueryValue(context, "key"), + Enabled = bool.TryParse(context.Request.Query["enabled"], out bool enabled) + ? enabled + : null, + Value = GetOptionalQueryValue(context.Request, "value"), + } + ), + IpcJson.Options + ); + } + catch (InvalidOperationException ex) + { + context.Response.StatusCode = 400; + await context.Response.WriteAsync(ex.Message); + } + } + + private async Task V3_ClearSetting(HttpContext context) + { + if (!AuthenticateToken(context.Request.Query["token"])) + { + context.Response.StatusCode = 401; + return; + } + + string key = context.Request.Query["key"].ToString(); + if (string.IsNullOrWhiteSpace(key)) + { + context.Response.StatusCode = 400; + await context.Response.WriteAsync("The key parameter is required."); + return; + } + + try + { + await context.Response.WriteAsJsonAsync( + IpcManagerSettingsApi.ClearSetting(key), + IpcJson.Options + ); + } + catch (InvalidOperationException ex) + { + context.Response.StatusCode = 400; + await context.Response.WriteAsync(ex.Message); + } + } + + private async Task V3_ResetSettings(HttpContext context) + { + if (!AuthenticateToken(context.Request.Query["token"])) + { + context.Response.StatusCode = 401; + return; + } + + IpcManagerSettingsApi.ResetSettingsPreservingSession(); + await context.Response.WriteAsJsonAsync( + IpcCommandResult.Success("reset-settings"), + IpcJson.Options + ); + } + + private async Task V3_ListSecureSettings(HttpContext context) + { + if (!AuthenticateToken(context.Request.Query["token"])) + { + context.Response.StatusCode = 401; + return; + } + + await context.Response.WriteAsJsonAsync( + IpcSecureSettingsApi.ListSettings(context.Request.Query["user"]), + IpcJson.Options + ); + } + + private async Task V3_GetSecureSetting(HttpContext context) + { + if (!AuthenticateToken(context.Request.Query["token"])) + { + context.Response.StatusCode = 401; + return; + } + + try + { + await context.Response.WriteAsJsonAsync( + IpcSecureSettingsApi.GetSetting( + GetRequiredQueryValue(context, "key"), + GetOptionalQueryValue(context.Request, "user") + ), + IpcJson.Options + ); + } + catch (InvalidOperationException ex) + { + context.Response.StatusCode = 400; + await context.Response.WriteAsync(ex.Message); + } + } + + private async Task V3_SetSecureSetting(HttpContext context) + { + if (!AuthenticateToken(context.Request.Query["token"])) + { + context.Response.StatusCode = 401; + return; + } + + if (!bool.TryParse(context.Request.Query["enabled"], out bool enabled)) + { + context.Response.StatusCode = 400; + await context.Response.WriteAsync("The enabled parameter must be either true or false."); + return; + } + + try + { + await context.Response.WriteAsJsonAsync( + await IpcSecureSettingsApi.SetSettingAsync( + new IpcSecureSettingRequest + { + SettingKey = GetRequiredQueryValue(context, "key"), + UserName = GetOptionalQueryValue(context.Request, "user"), + Enabled = enabled, + } + ), + IpcJson.Options + ); + } + catch (InvalidOperationException ex) + { + context.Response.StatusCode = 400; + await context.Response.WriteAsync(ex.Message); + } + } + + private async Task V3_SetManagerEnabled(HttpContext context) + { + if (!AuthenticateToken(context.Request.Query["token"])) + { + context.Response.StatusCode = 401; + return; + } + + if (!bool.TryParse(context.Request.Query["enabled"], out bool enabled)) + { + context.Response.StatusCode = 400; + await context.Response.WriteAsync("The enabled parameter must be either true or false."); + return; + } + + try + { + await context.Response.WriteAsJsonAsync( + await IpcManagerSettingsApi.SetManagerEnabledAsync( + new IpcManagerToggleRequest + { + ManagerName = GetRequiredQueryValue(context, "manager"), + Enabled = enabled, + } + ), + IpcJson.Options + ); + } + catch (InvalidOperationException ex) + { + context.Response.StatusCode = 400; + await context.Response.WriteAsync(ex.Message); + } + } + + private async Task V3_SetManagerUpdateNotifications(HttpContext context) + { + if (!AuthenticateToken(context.Request.Query["token"])) + { + context.Response.StatusCode = 401; + return; + } + + if (!bool.TryParse(context.Request.Query["enabled"], out bool enabled)) + { + context.Response.StatusCode = 400; + await context.Response.WriteAsync("The enabled parameter must be either true or false."); + return; + } + + try + { + await context.Response.WriteAsJsonAsync( + IpcManagerSettingsApi.SetManagerNotifications( + new IpcManagerToggleRequest + { + ManagerName = GetRequiredQueryValue(context, "manager"), + Enabled = enabled, + } + ), + IpcJson.Options + ); + } + catch (InvalidOperationException ex) + { + context.Response.StatusCode = 400; + await context.Response.WriteAsync(ex.Message); + } + } + + private async Task V3_ListDesktopShortcuts(HttpContext context) + { + if (!AuthenticateToken(context.Request.Query["token"])) + { + context.Response.StatusCode = 401; + return; + } + + await context.Response.WriteAsJsonAsync( + IpcDesktopShortcutsApi.ListShortcuts(), + IpcJson.Options + ); + } + + private async Task V3_SetDesktopShortcut(HttpContext context) + { + if (!AuthenticateToken(context.Request.Query["token"])) + { + context.Response.StatusCode = 401; + return; + } + + try + { + await context.Response.WriteAsJsonAsync( + IpcDesktopShortcutsApi.SetShortcut( + new IpcDesktopShortcutRequest + { + Path = GetRequiredQueryValue(context, "path"), + Status = GetOptionalQueryValue(context.Request, "status"), + } + ), + IpcJson.Options + ); + } + catch (InvalidOperationException ex) + { + context.Response.StatusCode = 400; + await context.Response.WriteAsync(ex.Message); + } + } + + private async Task V3_ResetDesktopShortcut(HttpContext context) + { + if (!AuthenticateToken(context.Request.Query["token"])) + { + context.Response.StatusCode = 401; + return; + } + + try + { + await context.Response.WriteAsJsonAsync( + IpcDesktopShortcutsApi.ResetShortcut( + new IpcDesktopShortcutRequest + { + Path = GetRequiredQueryValue(context, "path"), + } + ), + IpcJson.Options + ); + } + catch (InvalidOperationException ex) + { + context.Response.StatusCode = 400; + await context.Response.WriteAsync(ex.Message); + } + } + + private async Task V3_ResetDesktopShortcuts(HttpContext context) + { + if (!AuthenticateToken(context.Request.Query["token"])) + { + context.Response.StatusCode = 401; + return; + } + + await context.Response.WriteAsJsonAsync( + IpcDesktopShortcutsApi.ResetAllShortcuts(), + IpcJson.Options + ); + } + + private async Task V3_GetAppLog(HttpContext context) + { + if (!AuthenticateToken(context.Request.Query["token"])) + { + context.Response.StatusCode = 401; + return; + } + + int level = int.TryParse(context.Request.Query["level"], out int parsedLevel) + ? parsedLevel + : 4; + await context.Response.WriteAsJsonAsync( + IpcLogsApi.ListAppLog(level), + IpcJson.Options + ); + } + + private async Task V3_GetOperationHistory(HttpContext context) + { + if (!AuthenticateToken(context.Request.Query["token"])) + { + context.Response.StatusCode = 401; + return; + } + + await context.Response.WriteAsJsonAsync( + IpcLogsApi.ListOperationHistory(), + IpcJson.Options + ); + } + + private async Task V3_GetManagerLog(HttpContext context) + { + if (!AuthenticateToken(context.Request.Query["token"])) + { + context.Response.StatusCode = 401; + return; + } + + try + { + await context.Response.WriteAsJsonAsync( + IpcLogsApi.ListManagerLogs( + context.Request.Query["manager"], + bool.TryParse(context.Request.Query["verbose"], out bool verbose) && verbose + ), + IpcJson.Options + ); + } + catch (InvalidOperationException ex) + { + context.Response.StatusCode = 400; + await context.Response.WriteAsync(ex.Message); + } + } + + private async Task V3_GetBackupStatus(HttpContext context) + { + if (!AuthenticateToken(context.Request.Query["token"])) + { + context.Response.StatusCode = 401; + return; + } + + await context.Response.WriteAsJsonAsync( + await IpcBackupApi.GetStatusAsync(), + IpcJson.Options + ); + } + + private async Task V3_CreateLocalBackup(HttpContext context) + { + if (!AuthenticateToken(context.Request.Query["token"])) + { + context.Response.StatusCode = 401; + return; + } + + try + { + await context.Response.WriteAsJsonAsync( + await IpcBackupApi.CreateLocalBackupAsync(), + IpcJson.Options + ); + } + catch (InvalidOperationException ex) + { + context.Response.StatusCode = 400; + await context.Response.WriteAsync(ex.Message); + } + } + + private async Task V3_StartGitHubDeviceFlow(HttpContext context) + { + await HandleBackupActionAsync< + IpcGitHubDeviceFlowRequest, + IpcGitHubAuthResult + >(context, IpcBackupApi.StartGitHubDeviceFlowAsync); + } + + private async Task V3_CompleteGitHubDeviceFlow(HttpContext context) + { + if (!AuthenticateToken(context.Request.Query["token"])) + { + context.Response.StatusCode = 401; + return; + } + + try + { + await context.Response.WriteAsJsonAsync( + await IpcBackupApi.CompleteGitHubDeviceFlowAsync(), + IpcJson.Options + ); + } + catch (InvalidOperationException ex) + { + context.Response.StatusCode = 400; + await context.Response.WriteAsync(ex.Message); + } + } + + private async Task V3_SignOutGitHub(HttpContext context) + { + if (!AuthenticateToken(context.Request.Query["token"])) + { + context.Response.StatusCode = 401; + return; + } + + await context.Response.WriteAsJsonAsync( + await IpcBackupApi.SignOutGitHubAsync(), + IpcJson.Options + ); + } + + private async Task V3_ListCloudBackups(HttpContext context) + { + if (!AuthenticateToken(context.Request.Query["token"])) + { + context.Response.StatusCode = 401; + return; + } + + try + { + await context.Response.WriteAsJsonAsync( + await IpcBackupApi.ListCloudBackupsAsync(), + IpcJson.Options + ); + } + catch (InvalidOperationException ex) + { + context.Response.StatusCode = 400; + await context.Response.WriteAsync(ex.Message); + } + } + + private async Task V3_CreateCloudBackup(HttpContext context) + { + if (!AuthenticateToken(context.Request.Query["token"])) + { + context.Response.StatusCode = 401; + return; + } + + try + { + await context.Response.WriteAsJsonAsync( + await IpcBackupApi.CreateCloudBackupAsync(), + IpcJson.Options + ); + } + catch (InvalidOperationException ex) + { + context.Response.StatusCode = 400; + await context.Response.WriteAsync(ex.Message); + } + } + + private async Task V3_DownloadCloudBackup(HttpContext context) + { + await HandleBackupActionAsync< + IpcCloudBackupRequest, + IpcCloudBackupContentResult + >(context, IpcBackupApi.DownloadCloudBackupAsync); + } + + private async Task V3_RestoreCloudBackup(HttpContext context) + { + await HandleBackupActionAsync< + IpcCloudBackupRequest, + IpcCloudBackupRestoreResult + >(context, IpcBackupApi.RestoreCloudBackupAsync); + } + + private async Task V3_GetBundle(HttpContext context) + { + if (!AuthenticateToken(context.Request.Query["token"])) + { + context.Response.StatusCode = 401; + return; + } + + try + { + await context.Response.WriteAsJsonAsync( + await IpcBundleApi.GetCurrentBundleAsync(), + IpcJson.Options + ); + } + catch (InvalidOperationException ex) + { + context.Response.StatusCode = 400; + await context.Response.WriteAsync(ex.Message); + } + } + + private async Task V3_ResetBundle(HttpContext context) + { + if (!AuthenticateToken(context.Request.Query["token"])) + { + context.Response.StatusCode = 401; + return; + } + + try + { + await context.Response.WriteAsJsonAsync( + IpcBundleApi.ResetBundle(), + IpcJson.Options + ); + } + catch (InvalidOperationException ex) + { + context.Response.StatusCode = 400; + await context.Response.WriteAsync(ex.Message); + } + } + + private async Task V3_ImportBundle(HttpContext context) + { + await HandleBundleActionAsync( + context, + IpcBundleApi.ImportBundleAsync + ); + } + + private async Task V3_ExportBundle(HttpContext context) + { + await HandleBundleActionAsync( + context, + IpcBundleApi.ExportBundleAsync + ); + } + + private async Task V3_AddBundlePackage(HttpContext context) + { + await HandleBundleActionAsync< + IpcBundlePackageRequest, + IpcBundlePackageOperationResult + >(context, IpcBundleApi.AddPackageAsync); + } + + private async Task V3_RemoveBundlePackage(HttpContext context) + { + await HandleBundleActionAsync< + IpcBundlePackageRequest, + IpcBundlePackageOperationResult + >(context, IpcBundleApi.RemovePackageAsync); + } + + private async Task V3_InstallBundle(HttpContext context) + { + await HandleBundleActionAsync< + IpcBundleInstallRequest, + IpcBundleInstallResult + >(context, IpcBundleApi.InstallBundleAsync); + } + + private async Task V3_SearchPackages(HttpContext context) + { + if (!AuthenticateToken(context.Request.Query["token"])) + { + context.Response.StatusCode = 401; + return; + } + + string query = context.Request.Query["query"].ToString(); + if (string.IsNullOrWhiteSpace(query)) + { + context.Response.StatusCode = 400; + await context.Response.WriteAsync("The query parameter is required."); + return; + } + + string? manager = context.Request.Query["manager"]; + int maxResults = 50; + if ( + int.TryParse(context.Request.Query["maxResults"], out int parsedMaxResults) + && parsedMaxResults > 0 + ) + { + maxResults = parsedMaxResults; + } + + try + { + await context.Response.WriteAsJsonAsync( + IpcPackageApi.SearchPackages(query, manager, maxResults), + IpcJson.Options + ); + } + catch (InvalidOperationException ex) + { + context.Response.StatusCode = 400; + await context.Response.WriteAsync(ex.Message); + } + } + + private async Task V3_ListInstalledPackages(HttpContext context) + { + if (!AuthenticateToken(context.Request.Query["token"])) + { + context.Response.StatusCode = 401; + return; + } + + try + { + await context.Response.WriteAsJsonAsync( + IpcPackageApi.ListInstalledPackages(context.Request.Query["manager"]), + IpcJson.Options + ); + } + catch (InvalidOperationException ex) + { + context.Response.StatusCode = 400; + await context.Response.WriteAsync(ex.Message); + } + } + + private async Task V3_ListUpgradablePackages(HttpContext context) + { + if (!AuthenticateToken(context.Request.Query["token"])) + { + context.Response.StatusCode = 401; + return; + } + + try + { + await context.Response.WriteAsJsonAsync( + IpcPackageApi.ListUpgradablePackages(context.Request.Query["manager"]), + IpcJson.Options + ); + } + catch (InvalidOperationException ex) + { + context.Response.StatusCode = 400; + await context.Response.WriteAsync(ex.Message); + } + } + + private async Task V3_GetPackageDetails(HttpContext context) + { + if (!AuthenticateToken(context.Request.Query["token"])) + { + context.Response.StatusCode = 401; + return; + } + + string packageId = context.Request.Query["packageId"].ToString(); + if (string.IsNullOrWhiteSpace(packageId)) + { + context.Response.StatusCode = 400; + await context.Response.WriteAsync("The packageId parameter is required."); + return; + } + + try + { + await context.Response.WriteAsJsonAsync( + await IpcPackageApi.GetPackageDetailsAsync( + BuildPackageActionRequest(context.Request) + ), + IpcJson.Options + ); + } + catch (InvalidOperationException ex) + { + context.Response.StatusCode = 400; + await context.Response.WriteAsync(ex.Message); + } + } + + private async Task V3_GetPackageVersions(HttpContext context) + { + if (!AuthenticateToken(context.Request.Query["token"])) + { + context.Response.StatusCode = 401; + return; + } + + string packageId = context.Request.Query["packageId"].ToString(); + if (string.IsNullOrWhiteSpace(packageId)) + { + context.Response.StatusCode = 400; + await context.Response.WriteAsync("The packageId parameter is required."); + return; + } + + try + { + await context.Response.WriteAsJsonAsync( + IpcPackageApi.GetPackageVersions(BuildPackageActionRequest(context.Request)), + IpcJson.Options + ); + } + catch (InvalidOperationException ex) + { + context.Response.StatusCode = 400; + await context.Response.WriteAsync(ex.Message); + } + } + + private async Task V3_ListIgnoredUpdates(HttpContext context) + { + if (!AuthenticateToken(context.Request.Query["token"])) + { + context.Response.StatusCode = 401; + return; + } + + await context.Response.WriteAsJsonAsync( + IpcPackageApi.ListIgnoredUpdates(), + IpcJson.Options + ); + } + + private async Task V3_IgnorePackage(HttpContext context) + { + await HandleCommandActionAsync(context, IpcPackageApi.IgnorePackageUpdateAsync); + } + + private async Task V3_UnignorePackage(HttpContext context) + { + await HandleCommandActionAsync(context, IpcPackageApi.RemoveIgnoredUpdateAsync); + } + + private async Task V3_InstallPackage(HttpContext context) + { + await HandlePackageActionAsync( + context, + IpcPackageApi.InstallPackageAsync + ); + } + + private async Task V3_DownloadPackage(HttpContext context) + { + await HandlePackageActionAsync( + context, + IpcPackageApi.DownloadPackageAsync + ); + } + + private async Task V3_ReinstallPackage(HttpContext context) + { + await HandlePackageActionAsync( + context, + IpcPackageApi.ReinstallPackageAsync + ); + } + + private async Task V3_UpdatePackage(HttpContext context) + { + await HandlePackageActionAsync( + context, + IpcPackageApi.UpdatePackageAsync + ); + } + + private async Task V3_UninstallPackage(HttpContext context) + { + await HandlePackageActionAsync( + context, + IpcPackageApi.UninstallPackageAsync + ); + } + + private async Task V3_UninstallThenReinstallPackage(HttpContext context) + { + await HandlePackageActionAsync( + context, + IpcPackageApi.UninstallThenReinstallPackageAsync + ); + } + + private async Task V3_ShowPackage(HttpContext context) + { + if (!AuthenticateToken(context.Request.Query["token"])) + { + context.Response.StatusCode = 401; + return; + } + + string packageId = context.Request.Query["packageId"].ToString(); + if (string.IsNullOrWhiteSpace(packageId)) + { + context.Response.StatusCode = 400; + await context.Response.WriteAsync("The packageId parameter is required."); + return; + } + + try + { + await context.Response.WriteAsJsonAsync( + ShowPackageHandler?.Invoke(BuildPackageActionRequest(context.Request)) + ?? throw new InvalidOperationException( + "The current UniGetUI session cannot open package details." + ), + IpcJson.Options + ); + } + catch (InvalidOperationException ex) + { + context.Response.StatusCode = 400; + await context.Response.WriteAsync(ex.Message); + } + } + + private async Task V3_UpdateAllPackages(HttpContext context) + { + await HandleCommandAsync( + context, + () => + { + if (OnUpgradeAll is null) + { + throw new InvalidOperationException( + "The current UniGetUI session cannot update all packages." + ); + } + + OnUpgradeAll.Invoke(null, EventArgs.Empty); + return IpcCommandResult.Success("update-all"); + } + ); + } + + private async Task V3_UpdateAllPackagesForManager(HttpContext context) + { + await HandleCommandAsync( + context, + () => + { + if (OnUpgradeAllForManager is null) + { + throw new InvalidOperationException( + "The current UniGetUI session cannot update manager packages." + ); + } + + string managerName = GetRequiredQueryValue(context, "manager"); + OnUpgradeAllForManager.Invoke(null, managerName); + return IpcCommandResult.Success("update-manager"); + } + ); + } + + private static async Task HandlePackageActionAsync( + HttpContext context, + Func> action + ) + { + if (!AuthenticateToken(context.Request.Query["token"])) + { + context.Response.StatusCode = 401; + return; + } + + string packageId = context.Request.Query["packageId"].ToString(); + if (string.IsNullOrWhiteSpace(packageId)) + { + context.Response.StatusCode = 400; + await context.Response.WriteAsync("The packageId parameter is required."); + return; + } + + try + { + var request = BuildPackageActionRequest(context.Request); + + await context.Response.WriteAsJsonAsync( + await action(request), + IpcJson.Options + ); + } + catch (InvalidOperationException ex) + { + context.Response.StatusCode = 400; + await context.Response.WriteAsync(ex.Message); + } + } + + private static async Task HandleReadAsync(HttpContext context, Func action) + { + if (!AuthenticateToken(context.Request.Query["token"])) + { + context.Response.StatusCode = 401; + return; + } + + try + { + await context.Response.WriteAsJsonAsync( + action(), + IpcJson.Options + ); + } + catch (InvalidOperationException ex) + { + context.Response.StatusCode = 400; + await context.Response.WriteAsync(ex.Message); + } + } + + private static async Task HandleCommandAsync( + HttpContext context, + Func action + ) + { + if (!AuthenticateToken(context.Request.Query["token"])) + { + context.Response.StatusCode = 401; + return; + } + + try + { + await context.Response.WriteAsJsonAsync( + action(), + IpcJson.Options + ); + } + catch (InvalidOperationException ex) + { + context.Response.StatusCode = 400; + await context.Response.WriteAsync(ex.Message); + } + } + + private static async Task HandleCommandActionAsync( + HttpContext context, + Func> action + ) + { + if (!AuthenticateToken(context.Request.Query["token"])) + { + context.Response.StatusCode = 401; + return; + } + + string packageId = context.Request.Query["packageId"].ToString(); + if (string.IsNullOrWhiteSpace(packageId)) + { + context.Response.StatusCode = 400; + await context.Response.WriteAsync("The packageId parameter is required."); + return; + } + + try + { + await context.Response.WriteAsJsonAsync( + await action(BuildPackageActionRequest(context.Request)), + IpcJson.Options + ); + } + catch (InvalidOperationException ex) + { + context.Response.StatusCode = 400; + await context.Response.WriteAsync(ex.Message); + } + } + + private static async Task HandleSourceActionAsync( + HttpContext context, + Func> action + ) + { + if (!AuthenticateToken(context.Request.Query["token"])) + { + context.Response.StatusCode = 401; + return; + } + + try + { + await context.Response.WriteAsJsonAsync( + await action( + new IpcSourceRequest + { + ManagerName = GetRequiredQueryValue(context, "manager"), + SourceName = GetRequiredQueryValue(context, "name"), + SourceUrl = GetOptionalQueryValue(context.Request, "url"), + } + ), + IpcJson.Options + ); + } + catch (InvalidOperationException ex) + { + context.Response.StatusCode = 400; + await context.Response.WriteAsync(ex.Message); + } + } + + private static async Task HandleBundleActionAsync( + HttpContext context, + Func> action + ) + { + if (!AuthenticateToken(context.Request.Query["token"])) + { + context.Response.StatusCode = 401; + return; + } + + try + { + await context.Response.WriteAsJsonAsync( + await action(await ReadJsonBodyAsync(context)), + IpcJson.Options + ); + } + catch (InvalidOperationException ex) + { + context.Response.StatusCode = 400; + await context.Response.WriteAsync(ex.Message); + } + } + + private static async Task HandleBackupActionAsync( + HttpContext context, + Func> action + ) + { + if (!AuthenticateToken(context.Request.Query["token"])) + { + context.Response.StatusCode = 401; + return; + } + + try + { + await context.Response.WriteAsJsonAsync( + await action(await ReadJsonBodyAsync(context)), + IpcJson.Options + ); + } + catch (InvalidOperationException ex) + { + context.Response.StatusCode = 400; + await context.Response.WriteAsync(ex.Message); + } + } + + private static async Task HandleManagerMaintenanceActionAsync( + HttpContext context, + Func> action + ) + { + if (!AuthenticateToken(context.Request.Query["token"])) + { + context.Response.StatusCode = 401; + return; + } + + try + { + await context.Response.WriteAsJsonAsync( + await action(await ReadJsonBodyAsync(context)), + IpcJson.Options + ); + } + catch (InvalidOperationException ex) + { + context.Response.StatusCode = 400; + await context.Response.WriteAsync(ex.Message); + } + } + + private static async Task ReadJsonBodyAsync(HttpContext context) + { + using var reader = new StreamReader(context.Request.Body, Encoding.UTF8); + var request = IpcJson.Deserialize(await reader.ReadToEndAsync()); + return request + ?? throw new InvalidOperationException("The request body is required."); + } + + private static IpcPackageActionRequest BuildPackageActionRequest(HttpRequest request) + { + return new IpcPackageActionRequest + { + PackageId = GetRequiredQueryValue(request, "packageId"), + ManagerName = GetOptionalQueryValue(request, "manager"), + PackageSource = GetOptionalQueryValue(request, "packageSource"), + Version = GetOptionalQueryValue(request, "version"), + Scope = GetOptionalQueryValue(request, "scope"), + PreRelease = bool.TryParse(request.Query["preRelease"], out bool preRelease) + ? preRelease + : null, + Elevated = bool.TryParse(request.Query["elevated"], out bool elevated) + ? elevated + : null, + Interactive = bool.TryParse(request.Query["interactive"], out bool interactive) + ? interactive + : null, + SkipHash = bool.TryParse(request.Query["skipHash"], out bool skipHash) + ? skipHash + : null, + RemoveData = bool.TryParse(request.Query["removeData"], out bool removeData) + ? removeData + : null, + WaitForCompletion = bool.TryParse(request.Query["wait"], out bool waitForCompletion) + ? waitForCompletion + : null, + Architecture = GetOptionalQueryValue(request, "architecture"), + InstallLocation = GetOptionalQueryValue(request, "location"), + OutputPath = GetOptionalQueryValue(request, "outputPath"), + }; + } + + private static IpcAppNavigateRequest BuildAppNavigateRequest(HttpRequest request) + { + return new IpcAppNavigateRequest + { + Page = GetRequiredQueryValue(request, "page"), + ManagerName = GetOptionalQueryValue(request, "manager"), + HelpAttachment = GetOptionalQueryValue(request, "helpAttachment"), + }; + } + + private static string GetRequiredRouteValue(HttpContext context, string key) + { + return context.Request.RouteValues.TryGetValue(key, out object? value) + && value is string stringValue + && !string.IsNullOrWhiteSpace(stringValue) + ? stringValue + : throw new InvalidOperationException($"The route value \"{key}\" is required."); + } + + private static string GetRequiredQueryValue(HttpContext context, string key) + { + string? value = context.Request.Query[key].ToString(); + return !string.IsNullOrWhiteSpace(value) + ? value + : throw new InvalidOperationException($"The query value \"{key}\" is required."); + } + + private static string GetRequiredQueryValue(HttpRequest request, string key) + { + string? value = request.Query[key].ToString(); + return !string.IsNullOrWhiteSpace(value) + ? value + : throw new InvalidOperationException($"The query value \"{key}\" is required."); + } + + private static string? GetOptionalQueryValue(HttpRequest request, string key) + { + if (!request.Query.TryGetValue(key, out var value)) + { + return null; + } + + string? stringValue = value.ToString(); + return string.IsNullOrWhiteSpace(stringValue) ? null : stringValue; + } + + public async Task Stop() + { + if (Interlocked.Exchange(ref _stopRequested, 1) == 1) + { + return; + } + + try + { + if (_host is not null) + { + await _host.StopAsync().ConfigureAwait(false); + _host.Dispose(); + _host = null; + } + + Logger.Info("Api was shut down"); + } + catch (Exception ex) + { + Logger.Error(ex); + } + finally + { + CleanupTransportEndpoint(); + IpcTransportOptions.DeletePersistedMetadata(SessionId); + } + } + } +} diff --git a/src/UniGetUI.Interface.IpcApi/IpcTransport.cs b/src/UniGetUI.Interface.IpcApi/IpcTransport.cs new file mode 100644 index 0000000..dbd92ea --- /dev/null +++ b/src/UniGetUI.Interface.IpcApi/IpcTransport.cs @@ -0,0 +1,411 @@ +using System.Text.Json; +using UniGetUI.Core.Data; +using UniGetUI.Core.Logging; + +namespace UniGetUI.Interface; + +public enum IpcTransportKind +{ + Tcp, + NamedPipe, +} + +public sealed record IpcTransportOptions( + IpcTransportKind TransportKind, + int TcpPort, + string NamedPipeName +) +{ + public const string GuiSessionKind = "gui"; + public const string HeadlessSessionKind = "headless"; + public const int DefaultTcpPort = 7058; + public const string DefaultNamedPipeName = "UniGetUI.IPC"; + public const string DefaultUnixSocketDirectory = "/tmp"; + internal const int MaxUnixSocketPathLength = 104; + internal const UnixFileMode SameUserUnixSocketMode = + UnixFileMode.UserRead | UnixFileMode.UserWrite; + + public const string TransportArgument = "--ipc-api-transport"; + public const string TcpPortArgument = "--ipc-api-port"; + public const string NamedPipeArgument = "--ipc-api-pipe-name"; + public const string CliTransportArgument = "--transport"; + public const string CliTcpPortArgument = "--tcp-port"; + public const string CliNamedPipeArgument = "--pipe-name"; + + public const string TransportEnvironmentVariable = "UNIGETUI_IPC_API_TRANSPORT"; + public const string TcpPortEnvironmentVariable = "UNIGETUI_IPC_API_PORT"; + public const string NamedPipeEnvironmentVariable = "UNIGETUI_IPC_API_PIPE_NAME"; + + private const string EndpointMetadataDirectoryName = "IpcApiEndpoints"; + + public Uri BaseAddress => + TransportKind == IpcTransportKind.NamedPipe + ? new Uri("http://localhost/") + : new Uri($"http://localhost:{TcpPort}/"); + + public string BaseAddressString => BaseAddress.ToString().TrimEnd('/'); + public string? NamedPipePath => + TransportKind == IpcTransportKind.NamedPipe && !OperatingSystem.IsWindows() + ? ResolveUnixSocketPath(NamedPipeName) + : null; + public string NamedPipeDisplayName => + TransportKind != IpcTransportKind.NamedPipe + ? BaseAddressString + : OperatingSystem.IsWindows() + ? NamedPipeName + : NamedPipePath ?? NamedPipeName; + + public static IpcTransportOptions Default { get; } = new( + IpcTransportKind.NamedPipe, + DefaultTcpPort, + DefaultNamedPipeName + ); + + public static string EndpointMetadataDirectoryPath => + Path.Join(CoreData.UniGetUIUserConfigurationDirectory, EndpointMetadataDirectoryName); + + public static IpcTransportOptions LoadForServer(IReadOnlyList? args = null) + { + args ??= Environment.GetCommandLineArgs(); + return Parse( + args, + includeCliAliases: false, + fallback: Default + ); + } + + public static IpcTransportOptions LoadForClient(IReadOnlyList? args = null) + { + args ??= Environment.GetCommandLineArgs(); + + if (HasExplicitClientOverride(args)) + { + return Parse( + args, + includeCliAliases: true, + fallback: TryLoadPersisted()?.ToTransportOptions() ?? Default + ); + } + + return TryLoadPersisted()?.ToTransportOptions() ?? Default; + } + + public void Persist(string sessionId, string token, string sessionKind, int processId) + { + Directory.CreateDirectory(EndpointMetadataDirectoryPath); + + var metadata = new IpcEndpointRegistration + { + SessionId = sessionId, + SessionKind = sessionKind, + Token = token, + ProcessId = processId, + PersistedAtUtc = DateTimeOffset.UtcNow, + Transport = TransportKind, + TcpPort = TcpPort, + NamedPipeName = NamedPipeName, + }; + + File.WriteAllText( + GetEndpointMetadataPath(sessionId), + IpcJson.Serialize(metadata) + ); + } + + public static void DeletePersistedMetadata(string? sessionId = null) + { + try + { + if (string.IsNullOrWhiteSpace(sessionId)) + { + if (Directory.Exists(EndpointMetadataDirectoryPath)) + { + Directory.Delete(EndpointMetadataDirectoryPath, recursive: true); + } + return; + } + + string metadataPath = GetEndpointMetadataPath(sessionId); + if (File.Exists(metadataPath)) + { + File.Delete(metadataPath); + } + } + catch (Exception ex) + { + Logger.Warn("Could not delete IPC API endpoint metadata"); + Logger.Warn(ex); + } + } + + internal static IReadOnlyList LoadPersistedRegistrations() + { + List registrations = []; + + try + { + if (Directory.Exists(EndpointMetadataDirectoryPath)) + { + foreach (string file in Directory.GetFiles(EndpointMetadataDirectoryPath, "*.json")) + { + var registration = IpcJson.Deserialize( + File.ReadAllText(file) + ); + + if (registration is not null) + { + registrations.Add(registration); + } + } + } + } + catch (Exception ex) + { + Logger.Warn("Could not load persisted IPC API endpoint metadata"); + Logger.Warn(ex); + } + + return registrations; + } + + internal static IReadOnlyList OrderRegistrationsForCliSelection( + IReadOnlyList registrations + ) + { + return registrations + .OrderByDescending(registration => registration.SessionKind == HeadlessSessionKind) + .ThenByDescending(registration => registration.PersistedAtUtc) + .ThenBy(registration => registration.SessionId, StringComparer.Ordinal) + .ToArray(); + } + + internal static IpcEndpointRegistration? FindRegistration( + IpcTransportOptions options + ) + { + return LoadPersistedRegistrations() + .Where(registration => registration.Matches(options)) + .OrderByDescending(registration => registration.PersistedAtUtc) + .FirstOrDefault(); + } + + private static IpcEndpointRegistration? TryLoadPersisted() + { + return OrderRegistrationsForCliSelection(LoadPersistedRegistrations()).FirstOrDefault(); + } + + internal static bool HasExplicitClientOverride(IReadOnlyList args) + { + return args.Contains(CliTransportArgument) + || args.Contains(CliTcpPortArgument) + || args.Contains(CliNamedPipeArgument) + || args.Contains(TransportArgument) + || args.Contains(TcpPortArgument) + || args.Contains(NamedPipeArgument) + || !string.IsNullOrWhiteSpace(Environment.GetEnvironmentVariable(TransportEnvironmentVariable)) + || !string.IsNullOrWhiteSpace(Environment.GetEnvironmentVariable(TcpPortEnvironmentVariable)) + || !string.IsNullOrWhiteSpace(Environment.GetEnvironmentVariable(NamedPipeEnvironmentVariable)); + } + + private static string GetEndpointMetadataPath(string sessionId) + { + string safeSessionId = string.Concat( + sessionId.Where(c => char.IsLetterOrDigit(c) || c is '-' or '_') + ); + if (string.IsNullOrWhiteSpace(safeSessionId)) + { + safeSessionId = "session"; + } + + return Path.Join(EndpointMetadataDirectoryPath, safeSessionId + ".json"); + } + + private static IpcTransportOptions Parse( + IReadOnlyList args, + bool includeCliAliases, + IpcTransportOptions fallback + ) + { + string? transportValue = GetArgumentValue( + args, + includeCliAliases + ? [CliTransportArgument, TransportArgument] + : [TransportArgument] + ); + transportValue ??= Environment.GetEnvironmentVariable(TransportEnvironmentVariable); + + string? portValue = GetArgumentValue( + args, + includeCliAliases + ? [CliTcpPortArgument, TcpPortArgument] + : [TcpPortArgument] + ); + portValue ??= Environment.GetEnvironmentVariable(TcpPortEnvironmentVariable); + + string? pipeValue = GetArgumentValue( + args, + includeCliAliases + ? [CliNamedPipeArgument, NamedPipeArgument] + : [NamedPipeArgument] + ); + pipeValue ??= Environment.GetEnvironmentVariable(NamedPipeEnvironmentVariable); + + var transport = ParseTransport(transportValue, fallback.TransportKind); + int tcpPort = ParseTcpPort(portValue, fallback.TcpPort); + string pipeName = ParseNamedPipeName(pipeValue, fallback.NamedPipeName); + + return new IpcTransportOptions(transport, tcpPort, pipeName); + } + + private static IpcTransportKind ParseTransport( + string? value, + IpcTransportKind fallback + ) + { + if (string.IsNullOrWhiteSpace(value)) + { + return fallback; + } + + return value.Trim().ToLowerInvariant() switch + { + "tcp" => IpcTransportKind.Tcp, + "named-pipe" or "namedpipe" or "pipe" => IpcTransportKind.NamedPipe, + _ => + LogInvalidTransport(value, fallback), + }; + } + + private static IpcTransportKind LogInvalidTransport( + string value, + IpcTransportKind fallback + ) + { + Logger.Warn( + $"Invalid IPC API transport \"{value}\". Falling back to {fallback}." + ); + return fallback; + } + + private static int ParseTcpPort(string? value, int fallback) + { + if (string.IsNullOrWhiteSpace(value)) + { + return fallback; + } + + if (int.TryParse(value, out int port) && port is > 0 and <= 65535) + { + return port; + } + + Logger.Warn($"Invalid IPC API TCP port \"{value}\". Falling back to {fallback}."); + return fallback; + } + + private static string ParseNamedPipeName(string? value, string fallback) + { + if (string.IsNullOrWhiteSpace(value)) + { + return fallback; + } + + string pipeName = value.Trim(); + if (pipeName.Length == 0) + { + Logger.Warn( + $"Invalid IPC API named pipe name \"{value}\". Falling back to {fallback}." + ); + return fallback; + } + + if (OperatingSystem.IsWindows() && Path.IsPathRooted(pipeName)) + { + Logger.Warn( + $"Absolute IPC API named pipe paths are not supported on Windows. Falling back to {fallback}." + ); + return fallback; + } + + if (!OperatingSystem.IsWindows()) + { + string resolvedPath = ResolveUnixSocketPath(pipeName); + if (resolvedPath.Length > MaxUnixSocketPathLength) + { + Logger.Warn( + $"IPC API Unix socket path \"{resolvedPath}\" exceeds the supported length limit. Falling back to {fallback}." + ); + return fallback; + } + } + + return pipeName; + } + + internal static string ResolveUnixSocketPath(string pipeName) + { + ArgumentException.ThrowIfNullOrWhiteSpace(pipeName); + + string trimmed = pipeName.Trim(); + if (trimmed.StartsWith("/", StringComparison.Ordinal)) + { + return trimmed; + } + + return $"{DefaultUnixSocketDirectory.TrimEnd('/')}/{trimmed.TrimStart('/')}"; + } + + private static string? GetArgumentValue( + IReadOnlyList args, + IReadOnlyList argumentNames + ) + { + for (int i = 0; i < args.Count; i++) + { + if (!argumentNames.Contains(args[i]) || i + 1 >= args.Count) + { + continue; + } + + return args[i + 1].Trim('"').Trim('\''); + } + + return null; + } +} + +public sealed class IpcStatus +{ + public bool Running { get; set; } + public string Transport { get; set; } = "tcp"; + public int TcpPort { get; set; } + public string NamedPipeName { get; set; } = IpcTransportOptions.DefaultNamedPipeName; + public string NamedPipePath { get; set; } = ""; + public string BaseAddress { get; set; } = "http://localhost:7058"; + public string Version { get; set; } = CoreData.VersionName; + public int BuildNumber { get; set; } = CoreData.BuildNumber; +} + +internal sealed class IpcEndpointRegistration +{ + public string SessionId { get; set; } = ""; + public string SessionKind { get; set; } = IpcTransportOptions.GuiSessionKind; + public string Token { get; set; } = ""; + public int ProcessId { get; set; } + public DateTimeOffset PersistedAtUtc { get; set; } + public IpcTransportKind Transport { get; set; } = IpcTransportKind.Tcp; + public int TcpPort { get; set; } = IpcTransportOptions.DefaultTcpPort; + public string NamedPipeName { get; set; } = IpcTransportOptions.DefaultNamedPipeName; + + public IpcTransportOptions ToTransportOptions() + { + return new IpcTransportOptions(Transport, TcpPort, NamedPipeName); + } + + public bool Matches(IpcTransportOptions options) + { + return Transport == options.TransportKind + && TcpPort == options.TcpPort + && string.Equals(NamedPipeName, options.NamedPipeName, StringComparison.Ordinal); + } +} diff --git a/src/UniGetUI.Interface.IpcApi/Secrets.cs b/src/UniGetUI.Interface.IpcApi/Secrets.cs new file mode 100644 index 0000000..61c9324 --- /dev/null +++ b/src/UniGetUI.Interface.IpcApi/Secrets.cs @@ -0,0 +1,12 @@ +namespace UniGetUI.Interface; + +internal static partial class Secrets +{ + /* ---------------------------------------------------------------- + * W A R N I N G !!! + * + * Seeing errors? Build the project (maybe twice) + */ + public static partial string GetGitHubClientId(); + /* ------------------------------------------------------------------------ */ +} diff --git a/src/UniGetUI.Interface.IpcApi/UniGetUI.Interface.IpcApi.csproj b/src/UniGetUI.Interface.IpcApi/UniGetUI.Interface.IpcApi.csproj new file mode 100644 index 0000000..64dbfb9 --- /dev/null +++ b/src/UniGetUI.Interface.IpcApi/UniGetUI.Interface.IpcApi.csproj @@ -0,0 +1,39 @@ + + + + + + + + + + + $(SharedTargetFrameworks) + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/UniGetUI.Interface.IpcApi/WindowsConsoleHost.cs b/src/UniGetUI.Interface.IpcApi/WindowsConsoleHost.cs new file mode 100644 index 0000000..d0a3b4d --- /dev/null +++ b/src/UniGetUI.Interface.IpcApi/WindowsConsoleHost.cs @@ -0,0 +1,94 @@ +using System.IO; +using System.Runtime.InteropServices; +using System.Text; + +namespace UniGetUI.Interface; + +public static class WindowsConsoleHost +{ + private const uint AttachParentProcess = 0xFFFFFFFF; + private const int StdInputHandle = -10; + private const int StdOutputHandle = -11; + private const int StdErrorHandle = -12; + private const uint FileTypeDisk = 0x0001; + private const uint FileTypePipe = 0x0003; + private static readonly IntPtr InvalidHandleValue = new(-1); + + public static bool PrepareCliIO(bool allowAllocateIfNoParent = false) + { + if (!OperatingSystem.IsWindows()) + { + return false; + } + + if (HasConsoleWindow() || HasRedirectedStandardHandles()) + { + RebindStandardStreams(); + return true; + } + + if (AttachConsole(AttachParentProcess) || (allowAllocateIfNoParent && AllocConsole())) + { + RebindStandardStreams(); + return true; + } + + return false; + } + + private static bool HasConsoleWindow() + { + return GetConsoleWindow() != IntPtr.Zero; + } + + private static bool HasRedirectedStandardHandles() + { + return HasRedirectedHandle(StdInputHandle) + || HasRedirectedHandle(StdOutputHandle) + || HasRedirectedHandle(StdErrorHandle); + } + + private static bool HasRedirectedHandle(int standardHandle) + { + IntPtr handle = GetStdHandle(standardHandle); + if (handle == IntPtr.Zero || handle == InvalidHandleValue) + { + return false; + } + + uint fileType = GetFileType(handle); + return fileType is FileTypeDisk or FileTypePipe; + } + + private static void RebindStandardStreams() + { + Encoding utf8 = new UTF8Encoding(encoderShouldEmitUTF8Identifier: false); + Console.InputEncoding = utf8; + Console.OutputEncoding = utf8; + + Console.SetIn( + new StreamReader( + Console.OpenStandardInput(), + utf8, + detectEncodingFromByteOrderMarks: false + ) + ); + Console.SetOut(new StreamWriter(Console.OpenStandardOutput(), utf8) { AutoFlush = true }); + Console.SetError(new StreamWriter(Console.OpenStandardError(), utf8) { AutoFlush = true }); + } + + [DllImport("kernel32.dll", SetLastError = true)] + private static extern bool AttachConsole(uint dwProcessId); + + [DllImport("kernel32.dll", SetLastError = true)] + private static extern bool AllocConsole(); + + [DllImport("kernel32.dll")] + private static extern IntPtr GetConsoleWindow(); + + [DllImport("kernel32.dll", SetLastError = true)] + private static extern IntPtr GetStdHandle(int nStdHandle); + + [DllImport("kernel32.dll", SetLastError = true)] + private static extern uint GetFileType(IntPtr hFile); +} diff --git a/src/UniGetUI.Interface.IpcApi/generate-secrets.ps1 b/src/UniGetUI.Interface.IpcApi/generate-secrets.ps1 new file mode 100644 index 0000000..13edc81 --- /dev/null +++ b/src/UniGetUI.Interface.IpcApi/generate-secrets.ps1 @@ -0,0 +1,22 @@ +param ( + [string]$OutputPath = "obj" +) + +$generatedDir = [System.IO.Path]::Combine($OutputPath, "Generated Files") +if (-not (Test-Path -Path $generatedDir)) { + New-Item -ItemType Directory -Path $generatedDir -Force | Out-Null +} + +$clientId = $env:UNIGETUI_GITHUB_CLIENT_ID +if (-not $clientId) { $clientId = "CLIENT_ID_UNSET" } + +@" +// Auto-generated file - do not modify +namespace UniGetUI.Interface +{ + internal static partial class Secrets + { + public static partial string GetGitHubClientId() => `"$clientId`"; + } +} +"@ | Set-Content -Encoding UTF8 ([System.IO.Path]::Combine($generatedDir, "Secrets.Generated.cs")) diff --git a/src/UniGetUI.Interface.IpcApi/generate-secrets.sh b/src/UniGetUI.Interface.IpcApi/generate-secrets.sh new file mode 100755 index 0000000..8e939cb --- /dev/null +++ b/src/UniGetUI.Interface.IpcApi/generate-secrets.sh @@ -0,0 +1,18 @@ +#!/bin/bash +OUTPUT_PATH="${1:-obj/}" + +if [ ! -d "${OUTPUT_PATH}Generated Files" ]; then mkdir -p "${OUTPUT_PATH}Generated Files"; fi + +CLIENT_ID="${UNIGETUI_GITHUB_CLIENT_ID}" +if [ -z "$CLIENT_ID" ]; then CLIENT_ID="CLIENT_ID_UNSET"; fi + +cat > "${OUTPUT_PATH}Generated Files/Secrets.Generated.cs" << CSEOF +// Auto-generated file - do not modify +namespace UniGetUI.Interface +{ + internal static partial class Secrets + { + public static partial string GetGitHubClientId() => "$CLIENT_ID"; + } +} +CSEOF diff --git a/src/UniGetUI.Interface.Telemetry.Tests/TelemetryHandlerTests.cs b/src/UniGetUI.Interface.Telemetry.Tests/TelemetryHandlerTests.cs new file mode 100644 index 0000000..0d041c2 --- /dev/null +++ b/src/UniGetUI.Interface.Telemetry.Tests/TelemetryHandlerTests.cs @@ -0,0 +1,408 @@ +using System.Net; +using System.Reflection; +using System.Text; +using System.Text.Json; +using UniGetUI.Core.Data; +using UniGetUI.Core.Logging; +using UniGetUI.Core.SettingsEngine; +using UniGetUI.PackageEngine.Classes.Manager; +using UniGetUI.PackageEngine.Enums; +using UniGetUI.PackageEngine.PackageClasses; + +[assembly: CollectionBehavior(DisableTestParallelization = true)] + +namespace UniGetUI.Interface.Telemetry.Tests; + +public sealed class TelemetryHandlerTests : IDisposable +{ + private const string KnownInstallId = + "1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef"; + + private readonly string _testRoot; + private readonly string _portableMarkerPath; + private readonly bool _originalWasDaemon; + + public TelemetryHandlerTests() + { + _testRoot = Path.Combine( + AppContext.BaseDirectory, + nameof(TelemetryHandlerTests), + Guid.NewGuid().ToString("N") + ); + _portableMarkerPath = Path.Combine(Environment.CurrentDirectory, "ForceUniGetUIPortable"); + _originalWasDaemon = CoreData.WasDaemon; + + CoreData.TEST_DataDirectoryOverride = Path.Combine(_testRoot, "Data"); + Directory.CreateDirectory(CoreData.UniGetUIUserConfigurationDirectory); + + ClearSettingsCaches(); + Settings.ResetSettings(); + Settings.Set(Settings.K.DisableTelemetry, false); + Settings.Set(Settings.K.DisableWaitForInternetConnection, true); + Settings.SetValue(Settings.K.TelemetryClientToken, KnownInstallId); + + TelemetryHandler.ResetTestState(); + File.Delete(_portableMarkerPath); + CoreData.WasDaemon = false; + } + + public void Dispose() + { + TelemetryHandler.ResetTestState(); + ClearSettingsCaches(); + CoreData.TEST_DataDirectoryOverride = null; + CoreData.WasDaemon = _originalWasDaemon; + + if (File.Exists(_portableMarkerPath)) + { + File.Delete(_portableMarkerPath); + } + + if (Directory.Exists(_testRoot)) + { + Directory.Delete(_testRoot, true); + } + } + + [Fact] + public async Task InitializeAsync_WithoutCredentials_DoesNotSendAndLogsOnce() + { + int sendCount = 0; + TelemetryHandler.TestSendAsyncOverride = _ => + { + sendCount++; + return Task.FromResult(new HttpResponseMessage(HttpStatusCode.OK)); + }; + + int warningCountBefore = Logger + .GetLogs() + .Count(log => log.Content.Contains("OpenSearch credentials are not configured")); + + await TelemetryHandler.InitializeAsync(); + await TelemetryHandler.InitializeAsync(); + + int warningCountAfter = Logger + .GetLogs() + .Count(log => log.Content.Contains("OpenSearch credentials are not configured")); + + Assert.Equal(0, sendCount); + Assert.Equal(warningCountBefore + 1, warningCountAfter); + } + + [Fact] + public async Task Posts_DisposeResponsesReturnedByInjectionSeam() + { + TelemetryHandler.Configure("telemetry-user", "telemetry-pass"); + var activityResponse = new TrackingHttpResponseMessage(HttpStatusCode.OK); + TelemetryHandler.TestSendAsyncOverride = _ => Task.FromResult(activityResponse); + + await TelemetryHandler.InitializeAsync(); + + Assert.True(activityResponse.IsDisposed); + + var packageResponse = new TrackingHttpResponseMessage(HttpStatusCode.BadRequest); + TelemetryHandler.TestSendAsyncOverride = _ => Task.FromResult(packageResponse); + var package = new Package( + "Telemetry Package", + "Telemetry.Package", + "1.0.0", + new NullSource("Telemetry Source"), + NullPackageManager.Instance + ); + TelemetryHandler.UpdatePackage(package, TEL_OP_RESULT.SUCCESS); + + await TelemetryHandler.FlushPackageEventsAsync(); + + Assert.True(packageResponse.IsDisposed); + } + + [Fact] + public void ComputeActiveSettingsBitmask_IncludesDeterministicSettingsAndSpecialPaths() + { + Settings.Set(Settings.K.DisableAutoUpdateWingetUI, false); + Settings.Set(Settings.K.EnableUniGetUIBeta, true); + Settings.Set(Settings.K.DisableSystemTray, true); + Settings.Set(Settings.K.DisableNotifications, true); + Settings.Set(Settings.K.DisableAutoCheckforUpdates, false); + Settings.Set(Settings.K.AutomaticallyUpdatePackages, true); + Settings.Set(Settings.K.AskToDeleteNewDesktopShortcuts, false); + Settings.Set(Settings.K.EnablePackageBackup_LOCAL, false); + Settings.Set(Settings.K.DoCacheAdminRights, false); + Settings.Set(Settings.K.DoCacheAdminRightsForBatches, false); + File.WriteAllText(_portableMarkerPath, string.Empty); + CoreData.WasDaemon = true; + + int activeSettings = TelemetryHandler.ComputeActiveSettingsBitmask(); + + Assert.Equal(3123, activeSettings); + } + + [Fact] + public async Task InitializeAsync_SendsActivityPayloadWithRequiredFields() + { + Settings.Set(Settings.K.DisableAutoUpdateWingetUI, false); + Settings.Set(Settings.K.EnableUniGetUIBeta, true); + Settings.Set(Settings.K.DisableSystemTray, true); + Settings.Set(Settings.K.DisableNotifications, true); + Settings.Set(Settings.K.DisableAutoCheckforUpdates, false); + Settings.Set(Settings.K.AutomaticallyUpdatePackages, true); + File.WriteAllText(_portableMarkerPath, string.Empty); + CoreData.WasDaemon = true; + + TelemetryHandler.Configure("telemetry-user", "telemetry-pass"); + var captured = await CaptureRequestAsync(TelemetryHandler.InitializeAsync); + + using var json = JsonDocument.Parse(captured.Body); + JsonElement root = json.RootElement; + + Assert.Contains("activity_events", captured.RequestUri.AbsoluteUri); + Assert.Equal("Basic", captured.Authorization?.Scheme); + Assert.Equal( + Convert.ToBase64String(Encoding.UTF8.GetBytes("telemetry-user:telemetry-pass")), + captured.Authorization?.Parameter + ); + Assert.False(string.IsNullOrEmpty(root.GetProperty("eventID").GetString())); + Assert.NotEqual(default, root.GetProperty("eventDate").GetDateTime()); + Assert.Equal(KnownInstallId, root.GetProperty("installID").GetString()); + Assert.True(root.TryGetProperty("enabledManagers", out _)); + Assert.True(root.TryGetProperty("foundManagers", out _)); + Assert.Equal(3123, root.GetProperty("activeSettings").GetInt32()); + Assert.Equal("UniGetUI", root.GetProperty("application").GetProperty("name").GetString()); + Assert.Equal("NotApplicable", root.GetProperty("application").GetProperty("dataSource").GetString()); + Assert.Equal("Free", root.GetProperty("application").GetProperty("pricing").GetString()); + Assert.False( + string.IsNullOrEmpty(root.GetProperty("platform").GetProperty("name").GetString()) + ); + } + + [Fact] + public async Task InstallPackage_SendsPackagePayloadWithResultAndReferral() + { + TelemetryHandler.Configure("telemetry-user", "telemetry-pass"); + var package = new Package( + "Telemetry Package", + "Telemetry.Package", + "1.0.0", + new NullSource("Telemetry Source"), + NullPackageManager.Instance + ); + + var captured = await CaptureRequestAsync(() => + { + TelemetryHandler.InstallPackage( + package, + TEL_OP_RESULT.SUCCESS, + TEL_InstallReferral.FROM_BUNDLE + ); + }); + + // Body is NDJSON: {"index":{}}\n{event}\n + string[] lines = captured.Body.Split('\n', StringSplitOptions.RemoveEmptyEntries); + Assert.Equal(2, lines.Length); + using var json = JsonDocument.Parse(lines[1]); + JsonElement root = json.RootElement; + + Assert.Contains("package_events/_bulk", captured.RequestUri.AbsoluteUri); + Assert.Equal("install", root.GetProperty("operation").GetString()); + Assert.Equal(package.Id, root.GetProperty("packageId").GetString()); + Assert.Equal(package.Manager.Name, root.GetProperty("managerName").GetString()); + Assert.Equal(package.Source.Name, root.GetProperty("sourceName").GetString()); + Assert.Equal(TEL_OP_RESULT.SUCCESS.ToString(), root.GetProperty("operationResult").GetString()); + Assert.Equal( + TEL_InstallReferral.FROM_BUNDLE.ToString(), + root.GetProperty("eventSource").GetString() + ); + Assert.Equal(KnownInstallId, root.GetProperty("installID").GetString()); + } + + [Fact] + public async Task PackageDetails_SendsEventSourceWithoutOperationResult() + { + TelemetryHandler.Configure("telemetry-user", "telemetry-pass"); + var package = new Package( + "Telemetry Package", + "Telemetry.Package", + "1.0.0", + new NullSource("Telemetry Source"), + NullPackageManager.Instance + ); + + var captured = await CaptureRequestAsync(() => + { + TelemetryHandler.PackageDetails(package, "DIRECT_LINK"); + }); + + // Body is NDJSON: {"index":{}}\n{event}\n + string[] lines = captured.Body.Split('\n', StringSplitOptions.RemoveEmptyEntries); + Assert.Equal(2, lines.Length); + using var json = JsonDocument.Parse(lines[1]); + JsonElement root = json.RootElement; + + Assert.Equal("details", root.GetProperty("operation").GetString()); + Assert.Equal("DIRECT_LINK", root.GetProperty("eventSource").GetString()); + Assert.False(root.TryGetProperty("operationResult", out _)); + } + + [Fact] + public async Task UpdatePackages_BatchesManyEventsIntoOneBulkRequest() + { + TelemetryHandler.Configure("telemetry-user", "telemetry-pass"); + + int requestCount = 0; + string lastBody = string.Empty; + TaskCompletionSource completionSource = new(TaskCreationOptions.RunContinuationsAsynchronously); + + TelemetryHandler.TestSendAsyncOverride = async request => + { + Interlocked.Increment(ref requestCount); + lastBody = request.Content is null ? string.Empty : await request.Content.ReadAsStringAsync(); + completionSource.TrySetResult(lastBody); + return new HttpResponseMessage(HttpStatusCode.OK); + }; + + var packages = Enumerable.Range(1, 5).Select(i => new Package( + $"Package {i}", $"pkg.{i}", "1.0", new NullSource("src"), NullPackageManager.Instance + )).ToArray(); + + foreach (var pkg in packages) + TelemetryHandler.UpdatePackage(pkg, TEL_OP_RESULT.SUCCESS); + + await TelemetryHandler.FlushPackageEventsAsync(); + string body = await completionSource.Task.WaitAsync(TimeSpan.FromSeconds(5)); + + Assert.Equal(1, requestCount); + + // NDJSON body must have 2 lines per event: action + document + string[] lines = body.Split('\n', StringSplitOptions.RemoveEmptyEntries); + Assert.Equal(10, lines.Length); // 5 events × 2 lines + for (int i = 0; i < lines.Length; i += 2) + Assert.Equal("{\"index\":{}}", lines[i]); + } + + [Fact] + public async Task BundleOperations_SendExpectedRoutingPayloads() + { + TelemetryHandler.Configure("telemetry-user", "telemetry-pass"); + var captured = await CaptureRequestsAsync( + expectedCount: 3, + trigger: () => + { + TelemetryHandler.ImportBundle(BundleFormatType.JSON); + TelemetryHandler.ExportBundle(BundleFormatType.UBUNDLE); + TelemetryHandler.ExportBatch(); + } + ); + + var actualRoutes = captured + .Select(request => + { + using JsonDocument json = JsonDocument.Parse(request.Body); + JsonElement root = json.RootElement; + return ( + Operation: root.GetProperty("operation").GetString(), + BundleType: root.GetProperty("bundleType").GetString() + ); + }) + .OrderBy(route => route.Operation, StringComparer.Ordinal) + .ThenBy(route => route.BundleType, StringComparer.Ordinal) + .ToArray(); + + Assert.Equal( + [ + ("export", "PS1_SCRIPT"), + ("export", BundleFormatType.UBUNDLE.ToString()), + ("import", BundleFormatType.JSON.ToString()), + ], + actualRoutes + ); + } + + private static async Task CaptureRequestAsync(Func trigger) + { + TaskCompletionSource completionSource = + new(TaskCreationOptions.RunContinuationsAsynchronously); + TelemetryHandler.TestSendAsyncOverride = async request => + { + completionSource.TrySetResult(await CapturedRequest.CreateAsync(request)); + return new HttpResponseMessage(HttpStatusCode.OK); + }; + + await trigger(); + return await completionSource.Task.WaitAsync(TimeSpan.FromSeconds(5)); + } + + private static Task CaptureRequestAsync(Action trigger) => + CaptureRequestAsync(() => + { + trigger(); + return TelemetryHandler.FlushPackageEventsAsync(); + }); + + private static async Task> CaptureRequestsAsync( + int expectedCount, + Action trigger + ) + { + List captured = []; + Lock sync = new(); + TaskCompletionSource> completionSource = + new(TaskCreationOptions.RunContinuationsAsynchronously); + + TelemetryHandler.TestSendAsyncOverride = async request => + { + CapturedRequest capturedRequest = await CapturedRequest.CreateAsync(request); + lock (sync) + { + captured.Add(capturedRequest); + if (captured.Count == expectedCount) + { + completionSource.TrySetResult(captured.ToArray()); + } + } + + return new HttpResponseMessage(HttpStatusCode.OK); + }; + + trigger(); + return await completionSource.Task.WaitAsync(TimeSpan.FromSeconds(5)); + } + + private static void ClearSettingsCaches() + { + ClearDictionaryField("booleanSettings"); + ClearDictionaryField("valueSettings"); + } + + private static void ClearDictionaryField(string fieldName) + { + FieldInfo field = typeof(Settings).GetField(fieldName, BindingFlags.NonPublic | BindingFlags.Static)!; + object dictionary = field.GetValue(null)!; + dictionary.GetType().GetMethod("Clear")!.Invoke(dictionary, null); + } + + private sealed class TrackingHttpResponseMessage(HttpStatusCode statusCode) + : HttpResponseMessage(statusCode) + { + public bool IsDisposed { get; private set; } + + protected override void Dispose(bool disposing) + { + IsDisposed = true; + base.Dispose(disposing); + } + } + + private sealed record CapturedRequest( + Uri RequestUri, + string Body, + System.Net.Http.Headers.AuthenticationHeaderValue? Authorization + ) + { + public static async Task CreateAsync(HttpRequestMessage request) => + new( + request.RequestUri!, + request.Content is null ? string.Empty : await request.Content.ReadAsStringAsync(), + request.Headers.Authorization + ); + } +} diff --git a/src/UniGetUI.Interface.Telemetry.Tests/UniGetUI.Interface.Telemetry.Tests.csproj b/src/UniGetUI.Interface.Telemetry.Tests/UniGetUI.Interface.Telemetry.Tests.csproj new file mode 100644 index 0000000..63026ec --- /dev/null +++ b/src/UniGetUI.Interface.Telemetry.Tests/UniGetUI.Interface.Telemetry.Tests.csproj @@ -0,0 +1,41 @@ + + + $(PortableTargetFramework) + + false + true + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + + + + + + + + + + + diff --git a/src/UniGetUI.Interface.Telemetry/Events/TelemetryEventBase.cs b/src/UniGetUI.Interface.Telemetry/Events/TelemetryEventBase.cs new file mode 100644 index 0000000..731fb28 --- /dev/null +++ b/src/UniGetUI.Interface.Telemetry/Events/TelemetryEventBase.cs @@ -0,0 +1,67 @@ +using System.Text.Json.Serialization; + +namespace UniGetUI.Interface.Telemetry; + +/// +/// Common fields shared by all UniGetUI telemetry events. +/// Mirrors the field names expected by the Devolutions OpenSearch schema. +/// +public abstract class TelemetryEventBase +{ + protected TelemetryEventBase() + { + EventID = Guid.NewGuid().ToString(); + EventDate = DateTime.UtcNow; + } + + [JsonPropertyName("eventID")] + public string EventID { get; set; } + + [JsonPropertyName("eventDate")] + public DateTime EventDate { get; set; } + + [JsonPropertyName("installID")] + public required string InstallID { get; set; } + + [JsonPropertyName("locale")] + public string? Locale { get; set; } + + [JsonPropertyName("application")] + public required TelemetryApplicationInfo Application { get; set; } + + [JsonPropertyName("platform")] + public TelemetryPlatformInfo? Platform { get; set; } +} + +public sealed class TelemetryApplicationInfo +{ + [JsonPropertyName("name")] + public required string Name { get; set; } + + [JsonPropertyName("version")] + public required string Version { get; set; } + + [JsonPropertyName("dataSource")] + public required string DataSource { get; set; } + + [JsonPropertyName("pricing")] + public required string Pricing { get; set; } + + [JsonPropertyName("language")] + public string? Language { get; set; } + + [JsonPropertyName("architectureType")] + public string? ArchitectureType { get; set; } +} + +public sealed class TelemetryPlatformInfo +{ + [JsonPropertyName("name")] + public required string Name { get; set; } + + [JsonPropertyName("version")] + public string? Version { get; set; } + + [JsonPropertyName("architecture")] + public string? Architecture { get; set; } +} diff --git a/src/UniGetUI.Interface.Telemetry/Events/UniGetUIActivityEvent.cs b/src/UniGetUI.Interface.Telemetry/Events/UniGetUIActivityEvent.cs new file mode 100644 index 0000000..7c51545 --- /dev/null +++ b/src/UniGetUI.Interface.Telemetry/Events/UniGetUIActivityEvent.cs @@ -0,0 +1,15 @@ +using System.Text.Json.Serialization; + +namespace UniGetUI.Interface.Telemetry; + +public sealed class UniGetUIActivityEvent : TelemetryEventBase +{ + [JsonPropertyName("enabledManagers")] + public string[] EnabledManagers { get; set; } = []; + + [JsonPropertyName("foundManagers")] + public string[] FoundManagers { get; set; } = []; + + [JsonPropertyName("activeSettings")] + public int ActiveSettings { get; set; } +} diff --git a/src/UniGetUI.Interface.Telemetry/Events/UniGetUIBundleEvent.cs b/src/UniGetUI.Interface.Telemetry/Events/UniGetUIBundleEvent.cs new file mode 100644 index 0000000..7d54bc2 --- /dev/null +++ b/src/UniGetUI.Interface.Telemetry/Events/UniGetUIBundleEvent.cs @@ -0,0 +1,12 @@ +using System.Text.Json.Serialization; + +namespace UniGetUI.Interface.Telemetry; + +public sealed class UniGetUIBundleEvent : TelemetryEventBase +{ + [JsonPropertyName("operation")] + public required string Operation { get; set; } + + [JsonPropertyName("bundleType")] + public required string BundleType { get; set; } +} diff --git a/src/UniGetUI.Interface.Telemetry/Events/UniGetUIPackageEvent.cs b/src/UniGetUI.Interface.Telemetry/Events/UniGetUIPackageEvent.cs new file mode 100644 index 0000000..7b5f35b --- /dev/null +++ b/src/UniGetUI.Interface.Telemetry/Events/UniGetUIPackageEvent.cs @@ -0,0 +1,24 @@ +using System.Text.Json.Serialization; + +namespace UniGetUI.Interface.Telemetry; + +public sealed class UniGetUIPackageEvent : TelemetryEventBase +{ + [JsonPropertyName("operation")] + public required string Operation { get; set; } + + [JsonPropertyName("packageId")] + public required string PackageId { get; set; } + + [JsonPropertyName("managerName")] + public required string ManagerName { get; set; } + + [JsonPropertyName("sourceName")] + public required string SourceName { get; set; } + + [JsonPropertyName("operationResult")] + public string? OperationResult { get; set; } + + [JsonPropertyName("eventSource")] + public string? EventSource { get; set; } +} diff --git a/src/UniGetUI.Interface.Telemetry/InternalsVisibleTo.cs b/src/UniGetUI.Interface.Telemetry/InternalsVisibleTo.cs new file mode 100644 index 0000000..569ff00 --- /dev/null +++ b/src/UniGetUI.Interface.Telemetry/InternalsVisibleTo.cs @@ -0,0 +1,3 @@ +using System.Runtime.CompilerServices; + +[assembly: InternalsVisibleTo("UniGetUI.Interface.Telemetry.Tests")] diff --git a/src/UniGetUI.Interface.Telemetry/TelemetryHandler.cs b/src/UniGetUI.Interface.Telemetry/TelemetryHandler.cs new file mode 100644 index 0000000..d2b87d7 --- /dev/null +++ b/src/UniGetUI.Interface.Telemetry/TelemetryHandler.cs @@ -0,0 +1,452 @@ +using System.Collections.Concurrent; +using System.Net.Http.Headers; +using System.Runtime.InteropServices; +using System.Text; +using System.Text.Json; +using System.Text.Json.Serialization; +using System.Text.Json.Serialization.Metadata; +using UniGetUI.Core.Data; +using UniGetUI.Core.Language; +using UniGetUI.Core.Logging; +using UniGetUI.Core.SettingsEngine; +using UniGetUI.Core.Tools; +using UniGetUI.PackageEngine; +using UniGetUI.PackageEngine.Enums; +using UniGetUI.PackageEngine.Interfaces; + +namespace UniGetUI.Interface.Telemetry; + +public enum TEL_InstallReferral +{ + DIRECT_SEARCH, + FROM_BUNDLE, + ALREADY_INSTALLED, +} + +public enum TEL_OP_RESULT +{ + SUCCESS, + FAILED, + CANCELED, +} + +public static class TelemetryHandler +{ + private const string OpenSearchUrl = "https://telemetry2.devolutions.net:9200"; + private static string _openSearchUsername = ""; + private static string _openSearchPassword = ""; + private static bool _credentialsWarningLogged; + internal static Func>? TestSendAsyncOverride; + + public static void Configure(string username, string password) + { + _openSearchUsername = username; + _openSearchPassword = password; + } + + private static bool CredentialsConfigured() + { + if (!string.IsNullOrEmpty(_openSearchUsername) + && !_openSearchUsername.EndsWith("_UNSET") + && !string.IsNullOrEmpty(_openSearchPassword) + && !_openSearchPassword.EndsWith("_UNSET")) + return true; + + if (!_credentialsWarningLogged) + { + Logger.Warn("[Telemetry] OpenSearch credentials are not configured — telemetry is disabled for this build."); + _credentialsWarningLogged = true; + } + + return false; + } + + // Index names — to be created on the OpenSearch server + private const string IndexActivity = "unigetui_activity_events"; + private const string IndexPackage = "unigetui_package_events"; + private const string IndexBundle = "unigetui_bundle_events"; + +#if DEBUG + private const string IndexPrefix = "dev-"; +#else + private const string IndexPrefix = ""; +#endif + + private static readonly HttpClient _httpClient = CreateHttpClient(); + private static readonly ConcurrentQueue _pendingPackageEvents = new(); + private static readonly Settings.K[] SettingsToSend = + [ + Settings.K.DisableAutoUpdateWingetUI, + Settings.K.EnableUniGetUIBeta, + Settings.K.DisableSystemTray, + Settings.K.DisableNotifications, + Settings.K.DisableAutoCheckforUpdates, + Settings.K.AutomaticallyUpdatePackages, + Settings.K.AskToDeleteNewDesktopShortcuts, + Settings.K.EnablePackageBackup_LOCAL, + Settings.K.DoCacheAdminRights, + Settings.K.DoCacheAdminRightsForBatches, + ]; + + // ------------------------------------------------------------------------- + + private static HttpClient CreateHttpClient() + { + var httpClient = new HttpClient(CoreTools.GenericHttpClientParameters) + { + Timeout = TimeSpan.FromSeconds(30), + }; + httpClient.DefaultRequestHeaders.UserAgent.ParseAdd(CoreData.UserAgentString); + return httpClient; + } + + public static async Task InitializeAsync() + { + try + { + // Bail out before waiting for internet or gathering any data when telemetry + // can't be sent — opted out, or this build has no OpenSearch credentials + // (every from-source/community build). Only the official build proceeds. + if (Settings.Get(Settings.K.DisableTelemetry) || !CredentialsConfigured()) + return; + + await CoreTools.WaitForInternetConnection(); + + string[] enabledManagers = PEInterface.Managers + .Where(m => m.IsEnabled()) + .Select(m => m.Name) + .ToArray(); + + string[] foundManagers = PEInterface.Managers + .Where(m => m.IsEnabled() && m.Status.Found) + .Select(m => m.Name) + .ToArray(); + + var ev = new UniGetUIActivityEvent + { + InstallID = GetRandomizedId(), + Locale = LanguageEngine.SelectedLocale, + EnabledManagers = enabledManagers, + FoundManagers = foundManagers, + ActiveSettings = ComputeActiveSettingsBitmask(), + Application = BuildApplicationInfo(), + Platform = BuildPlatformInfo(), + }; + + await PostToOpenSearchAsync(IndexActivity, ev, TelemetrySerializerContext.Trimming.UniGetUIActivityEvent); + } + catch (Exception ex) + { + Logger.Error("[Telemetry] Hard crash in InitializeAsync"); + Logger.Error(ex); + } + } + + internal static int ComputeActiveSettingsBitmask() + { + int settingsMagicValue = 0; + int mask = 0x1; + foreach (var setting in SettingsToSend) + { + bool enabled = Settings.Get( + key: setting, + invert: Settings.ResolveKey(setting).StartsWith("Disable")); + + if (enabled) + settingsMagicValue |= mask; + mask <<= 1; + + if (mask == 0x1) + throw new OverflowException(); + } + foreach (var sp in new[] { "SP1", "SP2" }) + { + bool enabled = sp switch + { + "SP1" => File.Exists("ForceUniGetUIPortable"), + "SP2" => CoreData.WasDaemon, + _ => throw new NotImplementedException(), + }; + + if (enabled) + settingsMagicValue |= mask; + mask <<= 1; + + if (mask == 0x1) + throw new OverflowException(); + } + + return settingsMagicValue; + } + + internal static void ResetTestState() + { + _openSearchUsername = ""; + _openSearchPassword = ""; + _credentialsWarningLogged = false; + TestSendAsyncOverride = null; + while (_pendingPackageEvents.TryDequeue(out _)) { } + } + + // ------------------------------------------------------------------------- + + public static void InstallPackage( + IPackage package, + TEL_OP_RESULT status, + TEL_InstallReferral source + ) => EnqueuePackageEvent(package, "install", status, source.ToString()); + + public static void UpdatePackage(IPackage package, TEL_OP_RESULT status) => + EnqueuePackageEvent(package, "update", status); + + public static void DownloadPackage( + IPackage package, + TEL_OP_RESULT status, + TEL_InstallReferral source + ) => EnqueuePackageEvent(package, "download", status, source.ToString()); + + public static void UninstallPackage(IPackage package, TEL_OP_RESULT status) => + EnqueuePackageEvent(package, "uninstall", status); + + public static void PackageDetails(IPackage package, string eventSource) => + EnqueuePackageEvent(package, "details", eventSource: eventSource); + + private static void EnqueuePackageEvent( + IPackage package, + string operation, + TEL_OP_RESULT? result = null, + string? eventSource = null) + { + if (result is null && eventSource is null) + throw new ArgumentException("result and eventSource cannot both be null"); + // Skip enqueuing entirely when telemetry can't be sent, so events don't + // accumulate only to be drained-and-discarded at flush time. + if (Settings.Get(Settings.K.DisableTelemetry) || !CredentialsConfigured()) + return; + + _pendingPackageEvents.Enqueue(new UniGetUIPackageEvent + { + InstallID = GetRandomizedId(), + Locale = LanguageEngine.SelectedLocale, + Application = BuildApplicationInfo(), + Platform = BuildPlatformInfo(), + Operation = operation, + PackageId = package.Id, + ManagerName = package.Manager.Name, + SourceName = package.Source.Name, + OperationResult = result?.ToString(), + EventSource = eventSource, + }); + } + + /// + /// Drains the pending package-event queue and sends everything in a single + /// bulk request. Called from QueueDrained event subscribers and on app shutdown. + /// + public static async Task FlushPackageEventsAsync() + { + if (Settings.Get(Settings.K.DisableTelemetry) || !CredentialsConfigured()) + return; + + if (_pendingPackageEvents.IsEmpty) + return; + + var batch = new List(); + while (_pendingPackageEvents.TryDequeue(out UniGetUIPackageEvent? ev)) + batch.Add(ev); + + if (batch.Count > 0) + await PostBulkPackageEventsAsync(batch); + } + + private static async Task PostBulkPackageEventsAsync(IReadOnlyList events) + { + if (!CredentialsConfigured()) + return; + + try + { + await CoreTools.WaitForInternetConnection(); + + string fullIndex = IndexPrefix + IndexPackage; + + var sb = new StringBuilder(); + foreach (UniGetUIPackageEvent ev in events) + { + sb.Append("{\"index\":{}}\n"); + sb.Append(JsonSerializer.Serialize(ev, TelemetrySerializerContext.BulkTrimming.UniGetUIPackageEvent)); + sb.Append('\n'); + } + + string credentials = Convert.ToBase64String( + Encoding.UTF8.GetBytes($"{_openSearchUsername}:{_openSearchPassword}")); + + using var content = new StringContent(sb.ToString(), Encoding.UTF8, "application/x-ndjson"); + using var request = new HttpRequestMessage(HttpMethod.Post, $"{OpenSearchUrl}/{fullIndex}/_bulk") + { + Content = content, + }; + request.Headers.Authorization = new AuthenticationHeaderValue("Basic", credentials); + + using HttpResponseMessage response = TestSendAsyncOverride is { } sendAsync + ? await sendAsync(request) + : await _httpClient.SendAsync(request); + + if (response.IsSuccessStatusCode) + Logger.Debug($"[Telemetry] Sent {events.Count} package event(s) to {fullIndex} (bulk)"); + else + Logger.Warn($"[Telemetry] Bulk {fullIndex} returned {(int)response.StatusCode}"); + } + catch (Exception ex) + { + Logger.Error("[Telemetry] Hard crash posting bulk package events"); + Logger.Error(ex); + } + } + + // ------------------------------------------------------------------------- + + public static void ImportBundle(BundleFormatType type) => + _ = TrackBundleEventAsync("import", type.ToString()); + + public static void ExportBundle(BundleFormatType type) => + _ = TrackBundleEventAsync("export", type.ToString()); + + public static void ExportBatch() => + _ = TrackBundleEventAsync("export", "PS1_SCRIPT"); + + private static async Task TrackBundleEventAsync(string operation, string bundleType) + { + try + { + if (Settings.Get(Settings.K.DisableTelemetry) || !CredentialsConfigured()) + return; + + await CoreTools.WaitForInternetConnection(); + + var ev = new UniGetUIBundleEvent + { + InstallID = GetRandomizedId(), + Locale = LanguageEngine.SelectedLocale, + Application = BuildApplicationInfo(), + Platform = BuildPlatformInfo(), + Operation = operation, + BundleType = bundleType, + }; + + await PostToOpenSearchAsync(IndexBundle, ev, TelemetrySerializerContext.Trimming.UniGetUIBundleEvent); + } + catch (Exception ex) + { + Logger.Error($"[Telemetry] Hard crash in TrackBundleEventAsync ({operation})"); + Logger.Error(ex); + } + } + + // ─── OpenSearch HTTP ────────────────────────────────────────────────────── + + private static async Task PostToOpenSearchAsync(string indexName, T eventData, JsonTypeInfo typeInfo) + { + if (!CredentialsConfigured()) + return; + + try + { + string fullIndex = IndexPrefix + indexName; + string json = JsonSerializer.Serialize(eventData, typeInfo); + + string credentials = Convert.ToBase64String( + Encoding.UTF8.GetBytes($"{_openSearchUsername}:{_openSearchPassword}")); + + using var content = new StringContent(json, Encoding.UTF8, "application/json"); + using var request = new HttpRequestMessage(HttpMethod.Post, $"{OpenSearchUrl}/{fullIndex}/_doc") + { + Content = content, + }; + request.Headers.Authorization = new AuthenticationHeaderValue("Basic", credentials); + + using HttpResponseMessage response = TestSendAsyncOverride is { } sendAsync + ? await sendAsync(request) + : await _httpClient.SendAsync(request); + + if (response.IsSuccessStatusCode) + Logger.Debug($"[Telemetry] Sent to {fullIndex}"); + else + Logger.Warn($"[Telemetry] {fullIndex} returned {(int)response.StatusCode}"); + } + catch (Exception ex) + { + Logger.Error($"[Telemetry] Hard crash posting to {indexName}"); + Logger.Error(ex); + } + } + + // ─── Helpers ───────────────────────────────────────────────────────────── + + private static string GetRandomizedId() + { + string id = Settings.GetValue(Settings.K.TelemetryClientToken); + if (id.Length != 64) + { + id = CoreTools.RandomString(64); + Settings.SetValue(Settings.K.TelemetryClientToken, id); + } + return id; + } + + private static TelemetryApplicationInfo BuildApplicationInfo() => + new() + { + Name = "UniGetUI", + Version = CoreData.VersionName, + DataSource = "NotApplicable", + Pricing = "Free", + Language = LanguageEngine.SelectedLocale, + ArchitectureType = RuntimeInformation.ProcessArchitecture.ToString(), + }; + + // Every field here is constant for the process lifetime, so build it once and + // reuse the instance across all events (including each doc in a bulk flush). + // The value is only ever read (serialized), never mutated, so sharing is safe; + // a benign race just builds it twice with identical results. + private static TelemetryPlatformInfo? _platformInfo; + + private static TelemetryPlatformInfo BuildPlatformInfo() => + _platformInfo ??= new() + { + Name = GetPlatformName(), + Version = Environment.OSVersion.VersionString, + Architecture = RuntimeInformation.OSArchitecture.ToString(), + }; + + private static string GetPlatformName() + { + if (OperatingSystem.IsWindows()) return "Windows"; + if (OperatingSystem.IsMacOS()) return "Mac"; + return "Linux"; + } +} + +// Source-generated JSON context — required for AOT/trimmed builds (WinUI). +// Reflection-based serialization is disabled in that configuration. +[JsonSourceGenerationOptions(DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull)] +[JsonSerializable(typeof(UniGetUIActivityEvent))] +[JsonSerializable(typeof(UniGetUIPackageEvent))] +[JsonSerializable(typeof(UniGetUIBundleEvent))] +internal partial class TelemetrySerializerContext : JsonSerializerContext +{ + internal static readonly TelemetrySerializerContext Trimming = + new(new JsonSerializerOptions(SerializationHelpers.DefaultOptions) + { + DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull, + }); + + // Compact (non-indented) variant required for NDJSON bulk payloads: + // OpenSearch _bulk API requires each document to be on a single line. + internal static readonly TelemetrySerializerContext BulkTrimming = + new(new JsonSerializerOptions(SerializationHelpers.DefaultOptions) + { + DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull, + WriteIndented = false, + }); +} diff --git a/src/UniGetUI.Interface.Telemetry/UniGetUI.Interface.Telemetry.csproj b/src/UniGetUI.Interface.Telemetry/UniGetUI.Interface.Telemetry.csproj new file mode 100644 index 0000000..d87ad3f --- /dev/null +++ b/src/UniGetUI.Interface.Telemetry/UniGetUI.Interface.Telemetry.csproj @@ -0,0 +1,21 @@ + + + $(SharedTargetFrameworks) + + + + false + UniGetUI.Interface.Telemetry + + + + + + + + + + + + + diff --git a/src/UniGetUI.PackageEngine.Enums/Enums.cs b/src/UniGetUI.PackageEngine.Enums/Enums.cs new file mode 100644 index 0000000..2061d7b --- /dev/null +++ b/src/UniGetUI.PackageEngine.Enums/Enums.cs @@ -0,0 +1,115 @@ +namespace UniGetUI.PackageEngine.Enums +{ + /// + /// Represents the installation scope of a package + /// + public static class PackageScope + { + public static HashSet ValidValues = [Machine, User]; + public const string Machine = "machine"; + public const string Global = Machine; + public const string User = "user"; + public const string Local = User; + } + + public static class Architecture + { + public static HashSet ValidValues = [x86, x64, arm32, arm64]; + public const string x86 = "x86"; + public const string x64 = "x64"; + public const string arm32 = "arm32"; + public const string arm64 = "arm64"; + } + + public enum DeserializedPackageStatus + { + ManagerNotFound, + ManagerNotEnabled, + ManagerNotReady, + SourceNotFound, + IsAvailable, + } + + public enum BundleFormatType + { + UBUNDLE, + JSON, + YAML, + XML, + } + + public enum OperationVeredict + { + Success, + Failure, + Canceled, + + // RestartRequired, + AutoRetry, + } + + public enum OperationStatus + { + InQueue, + Running, + Succeeded, + Failed, + Canceled, + } + + public enum OperationType + { + Install, + Update, + Uninstall, + None, + } + + public enum LoggableTaskType + { + /// + /// Installs a required dependency for a Package Manager + /// + InstallManagerDependency, + + /// + /// Searches for packages with a specific query + /// + FindPackages, + + /// + /// Lists all the available updates + /// + ListUpdates, + + /// + /// Lists the installed packages + /// + ListInstalledPackages, + + /// + /// Refreshes the package indexes + /// + RefreshIndexes, + + /// + /// Lists the available sources for the manager + /// + ListSources, + + /// + /// Loads the package details for a specific package + /// + LoadPackageDetails, + + /// + /// Loads the available versions for a specific package + /// + LoadPackageVersions, + + /// + /// Other, specific task + /// + OtherTask, + } +} diff --git a/src/UniGetUI.PackageEngine.Enums/ManagerCapabilities.cs b/src/UniGetUI.PackageEngine.Enums/ManagerCapabilities.cs new file mode 100644 index 0000000..27db407 --- /dev/null +++ b/src/UniGetUI.PackageEngine.Enums/ManagerCapabilities.cs @@ -0,0 +1,61 @@ +namespace UniGetUI.PackageEngine.ManagerClasses.Manager +{ + public enum ProxySupport + { + No, + Partially, + Yes, + } + + public enum PackageReleaseDateSupport + { + No, + Partial, + Yes, + } + + public struct SourceCapabilities + { + public bool KnowsUpdateDate { get; set; } = false; + public bool KnowsPackageCount { get; set; } = false; + public bool MustBeInstalledAsAdmin { get; set; } = false; + + public SourceCapabilities() { } + } + + public struct ManagerCapabilities + { + public bool IsDummy = false; + public bool CanRunAsAdmin = false; + public bool CanSkipIntegrityChecks = false; + public bool CanRunInteractively = false; + public bool CanRemoveDataOnUninstall = false; + public bool CanDownloadInstaller = false; + public bool CanUninstallPreviousVersionsAfterUpdate = false; + public bool CanListDependencies = false; + public bool SupportsCustomVersions = false; + public bool SupportsCustomArchitectures = false; + public string[] SupportedCustomArchitectures = []; + public bool SupportsCustomScopes = false; + public bool SupportsPreRelease = false; + public bool SupportsCustomLocations = false; + public bool SupportsCustomSources = false; + public bool SupportsCustomPackageIcons = false; + public bool SupportsCustomPackageScreenshots = false; + public ProxySupport SupportsProxy = ProxySupport.No; + public bool SupportsProxyAuth = false; + public PackageReleaseDateSupport KnowsPackageReleaseDate = PackageReleaseDateSupport.No; + public SourceCapabilities Sources { get; set; } + + public ManagerCapabilities() + { + Sources = new SourceCapabilities(); + } + + public ManagerCapabilities(bool IsDummy) + { + Sources = new SourceCapabilities(); + this.IsDummy = IsDummy; + } + } +} diff --git a/src/UniGetUI.PackageEngine.Enums/ManagerStatus.cs b/src/UniGetUI.PackageEngine.Enums/ManagerStatus.cs new file mode 100644 index 0000000..d645b7c --- /dev/null +++ b/src/UniGetUI.PackageEngine.Enums/ManagerStatus.cs @@ -0,0 +1,10 @@ +namespace UniGetUI.PackageEngine.Classes.Manager.ManagerHelpers +{ + public class ManagerStatus + { + public string Version = ""; + public bool Found; + public string ExecutablePath = ""; + public string ExecutableCallArgs = "Unset"; + } +} diff --git a/src/UniGetUI.PackageEngine.Enums/OverridenInstallationOptions.cs b/src/UniGetUI.PackageEngine.Enums/OverridenInstallationOptions.cs new file mode 100644 index 0000000..3346cd6 --- /dev/null +++ b/src/UniGetUI.PackageEngine.Enums/OverridenInstallationOptions.cs @@ -0,0 +1,22 @@ +namespace UniGetUI.PackageEngine.Structs; + +public struct OverridenInstallationOptions +{ + public string? Scope; + public bool? RunAsAdministrator; + public bool PowerShell_DoNotSetScopeParameter = false; + public bool? WinGet_SpecifyVersion = null; + public bool Pip_BreakSystemPackages = false; + public bool WinGet_DropArchAndScope = false; + + public OverridenInstallationOptions(string? scope = null, bool? runAsAdministrator = null) + { + Scope = scope; + RunAsAdministrator = runAsAdministrator; + } + + public override string ToString() + { + return $""; + } +} diff --git a/src/UniGetUI.PackageEngine.Enums/UniGetUI.PackageEngine.Structs.csproj b/src/UniGetUI.PackageEngine.Enums/UniGetUI.PackageEngine.Structs.csproj new file mode 100644 index 0000000..3b1ea6e --- /dev/null +++ b/src/UniGetUI.PackageEngine.Enums/UniGetUI.PackageEngine.Structs.csproj @@ -0,0 +1,9 @@ + + + $(SharedTargetFrameworks) + + + + + + diff --git a/src/UniGetUI.PackageEngine.Interfaces/IManagerLogger.cs b/src/UniGetUI.PackageEngine.Interfaces/IManagerLogger.cs new file mode 100644 index 0000000..1dc9f90 --- /dev/null +++ b/src/UniGetUI.PackageEngine.Interfaces/IManagerLogger.cs @@ -0,0 +1,36 @@ +using System.Diagnostics; +using UniGetUI.PackageEngine.Enums; + +namespace UniGetUI.PackageEngine.ManagerClasses.Classes; + +public interface IManagerLogger +{ + public IReadOnlyList Operations { get; } + INativeTaskLogger CreateNew(LoggableTaskType type); + IProcessTaskLogger CreateNew(LoggableTaskType type, Process process); +} + +public interface ITaskLogger +{ + IReadOnlyList AsColoredString(bool verbose = false); + void Close(int returnCode); +} + +public interface INativeTaskLogger : ITaskLogger +{ + void Error(Exception? e); + void Error(IReadOnlyList lines); + void Error(string? line); + void Log(IReadOnlyList lines); + void Log(string? line); +} + +public interface IProcessTaskLogger : ITaskLogger +{ + void AddToStdErr(IReadOnlyList lines); + void AddToStdErr(string? line); + void AddToStdIn(IReadOnlyList lines); + void AddToStdIn(string? line); + void AddToStdOut(IReadOnlyList lines); + void AddToStdOut(string? line); +} diff --git a/src/UniGetUI.PackageEngine.Interfaces/IManagerSource.cs b/src/UniGetUI.PackageEngine.Interfaces/IManagerSource.cs new file mode 100644 index 0000000..6226ef7 --- /dev/null +++ b/src/UniGetUI.PackageEngine.Interfaces/IManagerSource.cs @@ -0,0 +1,33 @@ +using UniGetUI.Interface.Enums; + +namespace UniGetUI.PackageEngine.Interfaces +{ + public interface IManagerSource + { + public IconType IconId { get; } + public bool IsVirtualManager { get; } + public IPackageManager Manager { get; } + public string Name { get; } + public Uri Url { get; protected set; } + public int? PackageCount { get; } + public string? UpdateDate { get; } + + public string AsString { get; } + public string AsString_DisplayName { get; } + + /// + /// Returns a human-readable string representing the source name + /// + public string ToString(); + + /// + /// Replaces the current URL with the new one. Must be used only when a placeholder URL is used. + /// + void ReplaceUrl(Uri newUrl) + { + Url = newUrl; + } + + void RefreshSourceNames(); + } +} diff --git a/src/UniGetUI.PackageEngine.Interfaces/IPackage.cs b/src/UniGetUI.PackageEngine.Interfaces/IPackage.cs new file mode 100644 index 0000000..d6ecd5e --- /dev/null +++ b/src/UniGetUI.PackageEngine.Interfaces/IPackage.cs @@ -0,0 +1,169 @@ +using System.ComponentModel; +using UniGetUI.Core.Tools; +using UniGetUI.Interface.Enums; +using UniGetUI.PackageEngine.Classes.Serializable; +using UniGetUI.PackageEngine.Serializable; +using UniGetUI.PackageEngine.Structs; + +namespace UniGetUI.PackageEngine.Interfaces +{ + public interface IPackage : INotifyPropertyChanged, IEquatable + { + public IPackageDetails Details { get; } + public PackageTag Tag { get; set; } + public bool IsChecked { get; set; } + public string Name { get; } + public string Id { get; } + public string VersionString { get; } + public CoreTools.Version NormalizedVersion { get; } + public CoreTools.Version NormalizedNewVersion { get; } + public IManagerSource Source { get; } + public IPackageManager Manager { get; } + public string NewVersionString { get; } + public bool IsUpgradable { get; } + public ref OverridenInstallationOptions OverridenOptions { get; } + public string AutomationName { get; } + + /// + /// Returns an identifier that can be used to compare different package instances that refer to the same package. + /// What is taken into account: + /// - Manager and Source + /// - Package Identifier + /// For more specific comparison use GetVersionedHash() + /// + public long GetHash(); + + /// + /// Returns an identifier that can be used to compare different package instances that refer to the same package. + /// What is taken into account: + /// - Manager and Source + /// - Package Identifier + /// - Package version + /// - Package new version (if any) + /// + public long GetVersionedHash(); + + /// + /// Check whether two packages are **REALLY** the same package. + /// What is taken into account: + /// - Manager and Source + /// - Package Identifier + /// - Package version + /// - Package new version (if any) + /// + public bool Equals(object? other); + + /// + /// Check whether two package instances represent the same package. + /// What is taken into account: + /// - Manager and Source + /// - Package Identifier + /// For more specific comparison use package.Equals(object? other) + /// + /// A package + /// Whether the two instances refer to the same instance + public bool IsEquivalentTo(IPackage? other); + + /// + /// Load the package's normalized icon id, + /// + /// a string with the package's normalized icon id + public string GetIconId(); + + /// + /// Get the package's icon url. If the package has no icon, a fallback image is returned. + /// After calling this method, the returned URL points to a location on the local machine + /// + /// An always-valid URI object, pointing to a file:// or to a ms-appx:// URL + public Uri GetIconUrl(); + + /// + /// Get the package's icon url. If the package has no icon, null is returned. + /// After calling this method, the returned URL (if any) points to a location on the local machine + /// + /// An always-valid URI object, pointing to a file:// or to a ms-appx:// URL + public Uri? GetIconUrlIfAny(); + + /// + /// Retrieves a list og URIs representing the available screenshots for this package. + /// + public IReadOnlyList GetScreenshots(); + + /// + /// Adds the package to the ignored updates list. If no version is provided, all updates are ignored. + /// Calling this method will override older ignored updates. + /// + public Task AddToIgnoredUpdatesAsync(string version = "*"); + + /// + /// Removes the package from the ignored updates list, either if it is ignored for all updates or for a specific version only. + /// + public Task RemoveFromIgnoredUpdatesAsync(); + + /// + /// Returns true if the package's updates are ignored. If the version parameter + /// is passed it will be checked if that version is ignored. Please note that if + /// all updates are ignored, calling this method with a specific version will + /// still return true, although the passed version is not explicitly ignored. + /// + public Task HasUpdatesIgnoredAsync(string version = "*"); + + /// + /// Returns (as a string) the version for which a package has been ignored. When no versions + /// are ignored, an empty string will be returned; and when all versions are ignored an asterisk + /// will be returned. + /// + public Task GetIgnoredUpdatesVersionAsync(); + + /// + /// Returns the corresponding installed Package object. Will return null if not applicable + /// + /// a Package object if found, null if not + public IReadOnlyList GetInstalledPackages(); + + /// + /// Returns the corresponding available Package object. Will return null if not applicable + /// + /// a Package object if found, null if not + public IPackage? GetAvailablePackage(); + + /// + /// Returns the corresponding upgradable Package object. Will return null if not applicable + /// + /// a Package object if found, null if not + public IPackage? GetUpgradablePackage(); + + /// + /// Sets the package tag. You may as well use the Tag property. + /// This function is used for compatibility with the ? operator + /// + public void SetTag(PackageTag tag); + + /// + /// Checks whether a new version of this package is installed + /// + public bool NewerVersionIsInstalled(); + + /// + /// Gets the installer file name for this package + /// + /// + public Task GetInstallerFileName(); + + /// + /// Checks whether a new update of this package is a minor update or not (0.0.x) + /// + /// False if the update is a major update or the update doesn't exist, true if it's a minor update + public bool IsUpdateMinor(); + + /// + /// Gets the applicable install options for this package + /// + /// The package install options, or, if not overriden, the manager install options + public Task GetInstallOptions(); + + public Task AsSerializableAsync(); + + public SerializableIncompatiblePackage AsSerializable_Incompatible(); + } +} diff --git a/src/UniGetUI.PackageEngine.Interfaces/IPackageDetails.cs b/src/UniGetUI.PackageEngine.Interfaces/IPackageDetails.cs new file mode 100644 index 0000000..607d4b3 --- /dev/null +++ b/src/UniGetUI.PackageEngine.Interfaces/IPackageDetails.cs @@ -0,0 +1,107 @@ +namespace UniGetUI.PackageEngine.Interfaces +{ + public interface IPackageDetails + { + /// + /// The package to which this details instance corresponds + /// + public IPackage Package { get; } + + /// + /// Whether this PackageDetails instance has valid data or not. + /// To load valid data, make use of the `Load()` method + /// + public bool IsPopulated { get; } + + /// + /// The description of the package + /// + public string? Description { get; set; } + + /// + /// The publisher of the package. The one(s) in charge of maintaining the package published on the package manager. + /// + public string? Publisher { get; set; } + + /// + /// The author of the package. Who has created the package. Usually the developer of the package. + /// + public string? Author { get; set; } + + /// + /// A link to the homepage of the package + /// + public Uri? HomepageUrl { get; set; } + + /// + /// The license name (not the URL) of the package + /// + public string? License { get; set; } + + /// + /// A URL pointing to the license of the package. + /// + public Uri? LicenseUrl { get; set; } + + /// + /// A URL pointing to the installer of the package + /// + public Uri? InstallerUrl { get; set; } + + /// + /// A string representing the hash of the installer. + /// + public string? InstallerHash { get; set; } + + /// + /// A string representing the type of the installer (.zip, .exe, .msi, .appx, tarball, etc.) + /// + public string? InstallerType { get; set; } + + /// + /// The size, in **BYTES**, of the installer + /// + public long InstallerSize { get; set; } + + /// + /// A URL pointing to the Manifest File of the package + /// + public Uri? ManifestUrl { get; set; } + + /// + /// The update date (aka the publication date for the latest version) of the package + /// + public string? UpdateDate { get; set; } + + /// + /// The release notes (not the URL) for the package. + /// + public string? ReleaseNotes { get; set; } + + /// + /// A URL to the package release notes. + /// + public Uri? ReleaseNotesUrl { get; set; } + + /// + /// A list of tags that (in theory) represent the package + /// + public string[] Tags { get; set; } + + /// + /// Loads the available package details. May override existing data. + /// If the load succeeds, `IsPopulated` will be set to True. + /// + /// An asynchronous task that can be awaited + public Task Load(); + + public List Dependencies { get; } + + public struct Dependency + { + public string Name; + public string Version; + public bool Mandatory; + } + } +} diff --git a/src/UniGetUI.PackageEngine.Interfaces/IPackageManager.cs b/src/UniGetUI.PackageEngine.Interfaces/IPackageManager.cs new file mode 100644 index 0000000..fb5d2f0 --- /dev/null +++ b/src/UniGetUI.PackageEngine.Interfaces/IPackageManager.cs @@ -0,0 +1,86 @@ +using System.Text; +using UniGetUI.PackageEngine.Classes.Manager.Classes; +using UniGetUI.PackageEngine.Classes.Manager.ManagerHelpers; +using UniGetUI.PackageEngine.Interfaces.ManagerProviders; +using UniGetUI.PackageEngine.ManagerClasses.Classes; +using UniGetUI.PackageEngine.ManagerClasses.Manager; + +namespace UniGetUI.PackageEngine.Interfaces +{ + public interface IPackageManager + { + public ManagerProperties Properties { get; } + public ManagerCapabilities Capabilities { get; } + public ManagerStatus Status { get; } + public string Id { get; } + public string Name { get; } + public string DisplayName { get; } + public IManagerSource DefaultSource { get; } + public IManagerLogger TaskLogger { get; } + public IMultiSourceHelper SourcesHelper { get; } + public IPackageDetailsHelper DetailsHelper { get; } + public IPackageOperationHelper OperationHelper { get; } + public IReadOnlyList Dependencies { get; } + + /// + /// The text encoding this manager's CLI emits its output in. Defaults to UTF-8; managers + /// whose CLI emits in the system console code page (e.g. Chocolatey) must override this. + /// + public Encoding OutputEncoding { get; } + + /// + /// Initializes the Package Manager (asynchronously). Must be run before using any other method of the manager. + /// + public void Initialize(); + + /// + /// Returns true if the manager is enabled, false otherwise + /// + public bool IsEnabled(); + + /// + /// Returns true if the manager is enabled and available (the required executable files were found). Returns false otherwise + /// + public bool IsReady(); + + /// + /// Returns an array of Package objects that the manager lists for the given query. Depending on the manager, the list may + /// also include similar results. This method is fail-safe and will return an empty array if an error occurs. + /// + public IReadOnlyList FindPackages(string query); + + /// + /// Returns an array of UpgradablePackage objects that represent the available updates reported by the manager. + /// This method is fail-safe and will return an empty array if an error occurs. + /// + public IReadOnlyList GetAvailableUpdates(); + + /// + /// Returns an array of Package objects that represent the installed reported by the manager. + /// This method is fail-safe and will return an empty array if an error occurs. + /// + public IReadOnlyList GetInstalledPackages(); + + /// + /// Refreshes the Package Manager sources/indexes + /// Each manager MUST implement this method. + /// + public void RefreshPackageIndexes(); + + /// + /// This method should attempt to resolve issues + /// such as COM API disconnect or similar issues that + /// can easily be resolved by reconnecting to a client and/or + /// clearing some internal caches. See the WinGet implementation for + /// an example + /// + public void AttemptFastRepair(); + + /// + /// Find all available executable files that apply to this package manager + /// + /// + public IReadOnlyList FindCandidateExecutableFiles(); + public Tuple GetExecutableFile(); + } +} diff --git a/src/UniGetUI.PackageEngine.Interfaces/ISourceFactory.cs b/src/UniGetUI.PackageEngine.Interfaces/ISourceFactory.cs new file mode 100644 index 0000000..3e40138 --- /dev/null +++ b/src/UniGetUI.PackageEngine.Interfaces/ISourceFactory.cs @@ -0,0 +1,32 @@ +namespace UniGetUI.PackageEngine.Interfaces +{ + public interface ISourceFactory + { + /// + /// Returns the existing source for the given name, or creates a new one if it does not exist. + /// + /// The name of the source + /// A valid ManagerSource + public IManagerSource GetSourceOrDefault(string name); + + /// + /// Returns the existing source for the given name, or null if it does not exist. + /// + public IManagerSource? GetSourceIfExists(string name); + + /// + /// Adds a source to the factory, if the given source does not exist + /// + public void AddSource(IManagerSource source); + + /// + /// Returns the available sources on the factory + /// + public IManagerSource[] GetAvailableSources(); + + /// + /// Resets the current state of the SourceFactory. All sources are lost + /// + public void Reset(); + } +} diff --git a/src/UniGetUI.PackageEngine.Interfaces/ManagerDependency.cs b/src/UniGetUI.PackageEngine.Interfaces/ManagerDependency.cs new file mode 100644 index 0000000..7eafaf2 --- /dev/null +++ b/src/UniGetUI.PackageEngine.Interfaces/ManagerDependency.cs @@ -0,0 +1,26 @@ +namespace UniGetUI.PackageEngine.Classes.Manager.Classes +{ + public readonly struct ManagerDependency + { + public readonly string Name; + public readonly string InstallFileName; + public readonly string InstallArguments; + public readonly Func> IsInstalled; + public readonly string FancyInstallCommand; + + public ManagerDependency( + string name, + string installFileName, + string installArguments, + string fancyInstallCommand, + Func> isInstalled + ) + { + Name = name; + InstallFileName = installFileName; + InstallArguments = installArguments; + IsInstalled = isInstalled; + FancyInstallCommand = fancyInstallCommand; + } + } +} diff --git a/src/UniGetUI.PackageEngine.Interfaces/ManagerHelpers/IMultiSourceHelper.cs b/src/UniGetUI.PackageEngine.Interfaces/ManagerHelpers/IMultiSourceHelper.cs new file mode 100644 index 0000000..37df868 --- /dev/null +++ b/src/UniGetUI.PackageEngine.Interfaces/ManagerHelpers/IMultiSourceHelper.cs @@ -0,0 +1,58 @@ +using UniGetUI.PackageEngine.Enums; + +namespace UniGetUI.PackageEngine.Interfaces.ManagerProviders +{ + /// + /// Has the required methods to handle a package manager that can handle multiple source + /// + public interface IMultiSourceHelper + { + public ISourceFactory Factory { get; } + + /// + /// Returns the command-line parameters required to add the given source to the manager. + /// + /// The source to add + /// An array containing the parameters to pass to the manager executable + public string[] GetAddSourceParameters(IManagerSource source); + + /// + /// Returns the command-line parameters required to remove the given source from the manager. + /// + /// The source to remove + /// An array containing the parameters to pass to the manager executable + public string[] GetRemoveSourceParameters(IManagerSource source); + + /// + /// Checks the result of attempting to add a source + /// + /// The added (or not) source + /// The return code of the operation + /// the command-line output of the operation + /// An OperationVeredict value + public OperationVeredict GetAddOperationVeredict( + IManagerSource source, + int ReturnCode, + string[] Output + ); + + /// + /// Checks the result of attempting to remove a source + /// + /// The removed (or not) source + /// The return code of the operation + /// the command-line output of the operation + /// An OperationVeredict value + public OperationVeredict GetRemoveOperationVeredict( + IManagerSource source, + int ReturnCode, + string[] Output + ); + + /// + /// Returns the available sources + /// + /// An array of ManagerSource objects + public IReadOnlyList GetSources(); + } +} diff --git a/src/UniGetUI.PackageEngine.Interfaces/ManagerHelpers/IPackageDetailsHelper.cs b/src/UniGetUI.PackageEngine.Interfaces/ManagerHelpers/IPackageDetailsHelper.cs new file mode 100644 index 0000000..5bfa086 --- /dev/null +++ b/src/UniGetUI.PackageEngine.Interfaces/ManagerHelpers/IPackageDetailsHelper.cs @@ -0,0 +1,50 @@ +using UniGetUI.Core.IconEngine; + +namespace UniGetUI.PackageEngine.Interfaces.ManagerProviders +{ + /// + /// Provides useful information about the packages + /// + public interface IPackageDetailsHelper + { + /// + /// Returns a PackageDetails object that represents the details for the given Package object. + /// This method is fail-safe and will return a valid but empty PackageDetails object with the package + /// id if an error occurs. + /// + /// The PackageDetails instance to load + /// A PackageDetails object + public void GetDetails(IPackageDetails details); + + /// + /// Returns the available versions to install for the given package. + /// If the manager does not support listing the versions, an empty array will be returned. + /// This method is fail-safe and will return an empty array if an error occurs. + /// + /// The package from which to load its versions + /// An array of stings containing the found versions, an empty array if none. + public IReadOnlyList GetVersions(IPackage package); + + /// + /// Returns an Uri pointing to the icon of this package. + /// The uri may be either a ms-appx:/// url or a http(s):// protocol url + /// + /// The package from which to load the icon + /// A full path to a valid icon file + public CacheableIcon? GetIcon(IPackage package); + + /// + /// Returns the URLs to the screenshots (if any) of this package. + /// + /// The package from which to load the screenshots + /// An array with valid URIs to the screenshots + public IReadOnlyList GetScreenshots(IPackage package); + + /// + /// Returns the location where the package is installed, or null if the location cannot be loaded. + /// + /// The package for which to get the location + /// A valid path in the form of a string or a null object + public string? GetInstallLocation(IPackage package); + } +} diff --git a/src/UniGetUI.PackageEngine.Interfaces/ManagerHelpers/IPackageOperationHelper.cs b/src/UniGetUI.PackageEngine.Interfaces/ManagerHelpers/IPackageOperationHelper.cs new file mode 100644 index 0000000..b070e05 --- /dev/null +++ b/src/UniGetUI.PackageEngine.Interfaces/ManagerHelpers/IPackageOperationHelper.cs @@ -0,0 +1,33 @@ +using UniGetUI.PackageEngine.Enums; +using UniGetUI.PackageEngine.Serializable; + +namespace UniGetUI.PackageEngine.Interfaces.ManagerProviders +{ + /// + /// Handled the process of installing and uninstalling packages + /// + public interface IPackageOperationHelper + { + /// + /// Returns the list of arguments that need to be passed to the Package Manager executable so + /// that the requested operation is performed over the given package, with its corresponding + /// installation options. + /// + public IReadOnlyList GetParameters( + IPackage package, + InstallOptions options, + OperationType operation + ); + + /// + /// Returns the veredict of the given package operation, given the package, the operation type, + /// the corresponding output and the return code. + /// + public OperationVeredict GetResult( + IPackage package, + OperationType operation, + IReadOnlyList processOutput, + int returnCode + ); + } +} diff --git a/src/UniGetUI.PackageEngine.Interfaces/ManagerProperties.cs b/src/UniGetUI.PackageEngine.Interfaces/ManagerProperties.cs new file mode 100644 index 0000000..188330c --- /dev/null +++ b/src/UniGetUI.PackageEngine.Interfaces/ManagerProperties.cs @@ -0,0 +1,33 @@ +using UniGetUI.Interface.Enums; +using UniGetUI.PackageEngine.Interfaces; + +namespace UniGetUI.PackageEngine.ManagerClasses.Manager +{ + public struct ManagerProperties + { + private const IconType DefaultIconId = (IconType)'\uE916'; + + public bool IsDummy = false; + public string Id { get; set; } = ""; + public string Name { get; set; } = "Unset"; + public string? DisplayName { get; set; } + public string Description { get; set; } = "Unset"; + public IconType IconId { get; set; } = DefaultIconId; + public string ColorIconId { get; set; } = "Unset"; + + // public string ExecutableCallArgs { get; set; } = "Unset"; + public string ExecutableFriendlyName { get; set; } = "Unset"; + public string InstallVerb { get; set; } = "Unset"; + public string UpdateVerb { get; set; } = "Unset"; + public string UninstallVerb { get; set; } = "Unset"; + public IManagerSource[] KnownSources { get; set; } = []; + public IManagerSource DefaultSource { get; set; } = null!; + + public ManagerProperties() { } + + public ManagerProperties(bool IsDummy) + { + this.IsDummy = IsDummy; + } + } +} diff --git a/src/UniGetUI.PackageEngine.Interfaces/UniGetUI.PackageEngine.Interfaces.csproj b/src/UniGetUI.PackageEngine.Interfaces/UniGetUI.PackageEngine.Interfaces.csproj new file mode 100644 index 0000000..6b9ab5f --- /dev/null +++ b/src/UniGetUI.PackageEngine.Interfaces/UniGetUI.PackageEngine.Interfaces.csproj @@ -0,0 +1,33 @@ + + + $(SharedTargetFrameworks) + + + + 10.0.19041.0 + 3.1.0.0 + 3.1.0-beta0 + UniGetUI + 3.1.0-beta0 + Copyright 2021-2026 Devolutions Inc. + + + + + + + + + + + + + + + + + + + diff --git a/src/UniGetUI.PackageEngine.Managers.Apt/Apt.cs b/src/UniGetUI.PackageEngine.Managers.Apt/Apt.cs new file mode 100644 index 0000000..59a1d46 --- /dev/null +++ b/src/UniGetUI.PackageEngine.Managers.Apt/Apt.cs @@ -0,0 +1,262 @@ +using System.Diagnostics; +using System.Text.RegularExpressions; +using UniGetUI.Core.Tools; +using UniGetUI.Interface.Enums; +using UniGetUI.PackageEngine.Classes.Manager; +using UniGetUI.PackageEngine.Classes.Manager.ManagerHelpers; +using UniGetUI.PackageEngine.Enums; +using UniGetUI.PackageEngine.Interfaces; +using UniGetUI.PackageEngine.ManagerClasses.Classes; +using UniGetUI.PackageEngine.ManagerClasses.Manager; +using UniGetUI.PackageEngine.PackageClasses; +using UniGetUI.PackageEngine.Structs; + +namespace UniGetUI.PackageEngine.Managers.AptManager; + +public class Apt : PackageManager +{ + public Apt() + { + Dependencies = []; + + Capabilities = new ManagerCapabilities + { + CanRunAsAdmin = true, + CanSkipIntegrityChecks = true, + SupportsCustomSources = false, + SupportsProxy = ProxySupport.No, + SupportsProxyAuth = false, + KnowsPackageReleaseDate = PackageReleaseDateSupport.No, + }; + + Properties = new ManagerProperties + { + Id = "apt", + Name = "Apt", + Description = CoreTools.Translate( + "The default package manager for Debian/Ubuntu-based Linux distributions.
Contains: Debian/Ubuntu packages" + ), + IconId = IconType.Apt, + ColorIconId = "debian", + ExecutableFriendlyName = "apt", + InstallVerb = "install", + UpdateVerb = "install", + UninstallVerb = "remove", + DefaultSource = new ManagerSource(this, "apt", new Uri("https://packages.debian.org")), + KnownSources = [new ManagerSource(this, "apt", new Uri("https://packages.debian.org"))], + }; + + DetailsHelper = new AptPkgDetailsHelper(this); + OperationHelper = new AptPkgOperationHelper(this); + } + + // ── Executable discovery ─────────────────────────────────────────────── + + public override IReadOnlyList FindCandidateExecutableFiles() + { + var candidates = new List(CoreTools.WhichMultiple("apt")); + foreach (var path in new[] { "/usr/bin/apt", "/usr/local/bin/apt" }) + { + if (File.Exists(path) && !candidates.Contains(path)) + candidates.Add(path); + } + return candidates; + } + + protected override void _loadManagerExecutableFile( + out bool found, + out string path, + out string callArguments) + { + (found, path) = GetExecutableFile(); + callArguments = ""; + } + + protected override void _loadManagerVersion(out string version) + { + using var p = new Process + { + StartInfo = new ProcessStartInfo + { + FileName = Status.ExecutablePath, + Arguments = "--version", + UseShellExecute = false, + RedirectStandardOutput = true, + RedirectStandardError = true, + CreateNoWindow = true, + }, + }; + p.Start(); + // First line: "apt X.Y.Z (arch)" + var line = p.StandardOutput.ReadLine()?.Trim() ?? ""; + var parts = line.Split(' '); + version = parts.Length >= 2 ? parts[1] : line; + p.WaitForExit(); + } + + // ── Index refresh ────────────────────────────────────────────────────── + + public override void RefreshPackageIndexes() + { + using var p = new Process + { + StartInfo = new ProcessStartInfo + { + FileName = Status.ExecutablePath, + Arguments = "update", + UseShellExecute = false, + RedirectStandardOutput = true, + RedirectStandardError = true, + CreateNoWindow = true, + }, + }; + IProcessTaskLogger logger = TaskLogger.CreateNew(LoggableTaskType.RefreshIndexes, p); + p.Start(); + logger.AddToStdOut(p.StandardOutput.ReadToEnd()); + logger.AddToStdErr(p.StandardError.ReadToEnd()); + p.WaitForExit(); + logger.Close(p.ExitCode); + } + + // ── Package listing ──────────────────────────────────────────────────── + + protected override IReadOnlyList FindPackages_UnSafe(string query) + { + var packages = new List(); + + using var p = new Process + { + StartInfo = new ProcessStartInfo + { + FileName = "apt-cache", + Arguments = $"search -- {query}", + UseShellExecute = false, + RedirectStandardOutput = true, + RedirectStandardError = true, + CreateNoWindow = true, + }, + }; + IProcessTaskLogger logger = TaskLogger.CreateNew(LoggableTaskType.FindPackages, p); + p.Start(); + + // Output format: " - " + string? line; + while ((line = p.StandardOutput.ReadLine()) is not null) + { + logger.AddToStdOut(line); + var dashIdx = line.IndexOf(" - ", StringComparison.Ordinal); + if (dashIdx <= 0) continue; + + var id = line[..dashIdx].Trim(); + if (id.Length == 0) continue; + + packages.Add(new Package( + CoreTools.FormatAsName(id), + id, + CoreTools.Translate("Latest"), + Properties.DefaultSource!, + this)); + } + + logger.AddToStdErr(p.StandardError.ReadToEnd()); + p.WaitForExit(); + logger.Close(p.ExitCode); + return packages; + } + + protected override IReadOnlyList GetInstalledPackages_UnSafe() + { + var packages = new List(); + + using var p = new Process + { + StartInfo = new ProcessStartInfo + { + FileName = Status.ExecutablePath, + Arguments = "list --installed", + UseShellExecute = false, + RedirectStandardOutput = true, + RedirectStandardError = true, + CreateNoWindow = true, + }, + }; + IProcessTaskLogger logger = TaskLogger.CreateNew(LoggableTaskType.ListInstalledPackages, p); + p.Start(); + + // Output format: "/,... [installed,...]" + // First line is "Listing..." header — skip it. + var idVersionPattern = new Regex(@"^([^/\s]+)/\S+\s+(\S+)"); + string? line; + while ((line = p.StandardOutput.ReadLine()) is not null) + { + logger.AddToStdOut(line); + var m = idVersionPattern.Match(line); + if (!m.Success) continue; + + var id = m.Groups[1].Value; + var version = m.Groups[2].Value; + packages.Add(new Package( + CoreTools.FormatAsName(id), + id, + version, + Properties.DefaultSource!, + this)); + } + + logger.AddToStdErr(p.StandardError.ReadToEnd()); + p.WaitForExit(); + logger.Close(p.ExitCode); + return packages; + } + + protected override IReadOnlyList GetAvailableUpdates_UnSafe() + { + var packages = new List(); + + using var p = new Process + { + StartInfo = new ProcessStartInfo + { + FileName = Status.ExecutablePath, + Arguments = "list --upgradable", + UseShellExecute = false, + RedirectStandardOutput = true, + RedirectStandardError = true, + CreateNoWindow = true, + }, + }; + p.StartInfo.Environment["LANG"] = "C"; + p.StartInfo.Environment["LC_ALL"] = "C"; + IProcessTaskLogger logger = TaskLogger.CreateNew(LoggableTaskType.ListUpdates, p); + p.Start(); + + // Output format: "/,... [ ]" + // The bracketed suffix is locale-dependent (e.g. "upgradable from:" in English, + // "pouvant être mis à jour depuis :" in French). Match it by capturing the last + // whitespace-delimited token inside the brackets as the old version. + var pattern = new Regex(@"^([^/\s]+)/\S+\s+(\S+)\s+\S+\s+\[.*\s(\S+)\]"); + string? line; + while ((line = p.StandardOutput.ReadLine()) is not null) + { + logger.AddToStdOut(line); + var m = pattern.Match(line); + if (!m.Success) continue; + + var id = m.Groups[1].Value; + var newVersion = m.Groups[2].Value; + var oldVersion = m.Groups[3].Value; + packages.Add(new Package( + CoreTools.FormatAsName(id), + id, + oldVersion, + newVersion, + Properties.DefaultSource!, + this)); + } + + logger.AddToStdErr(p.StandardError.ReadToEnd()); + p.WaitForExit(); + logger.Close(p.ExitCode); + return packages; + } +} diff --git a/src/UniGetUI.PackageEngine.Managers.Apt/Helpers/AptPkgDetailsHelper.cs b/src/UniGetUI.PackageEngine.Managers.Apt/Helpers/AptPkgDetailsHelper.cs new file mode 100644 index 0000000..fd82b5f --- /dev/null +++ b/src/UniGetUI.PackageEngine.Managers.Apt/Helpers/AptPkgDetailsHelper.cs @@ -0,0 +1,162 @@ +using System.Diagnostics; +using UniGetUI.Core.IconEngine; +using UniGetUI.PackageEngine.Classes.Manager.BaseProviders; +using UniGetUI.PackageEngine.Enums; +using UniGetUI.PackageEngine.Interfaces; +using UniGetUI.PackageEngine.ManagerClasses.Classes; + +namespace UniGetUI.PackageEngine.Managers.AptManager; + +internal sealed class AptPkgDetailsHelper : BasePkgDetailsHelper +{ + public AptPkgDetailsHelper(Apt manager) + : base(manager) { } + + protected override void GetDetails_UnSafe(IPackageDetails details) + { + using var p = new Process + { + StartInfo = new ProcessStartInfo + { + FileName = "apt-cache", + Arguments = $"show {details.Package.Id}", + UseShellExecute = false, + RedirectStandardOutput = true, + RedirectStandardError = true, + CreateNoWindow = true, + }, + }; + + IProcessTaskLogger logger = Manager.TaskLogger.CreateNew( + LoggableTaskType.LoadPackageDetails, p); + p.Start(); + + // apt-cache show outputs key: value pairs, one per line. + // Multi-line values are indented with a leading space. + var descLines = new List(); + bool inDescription = false; + + string? line; + while ((line = p.StandardOutput.ReadLine()) is not null) + { + logger.AddToStdOut(line); + + if (line.Length == 0) + { + // Blank line ends the current record — stop after the first record. + if (inDescription) break; + continue; + } + + if (line.StartsWith(' ') && inDescription) + { + var descLine = line.TrimStart(); + if (descLine != ".") descLines.Add(descLine); + continue; + } + + inDescription = false; + + var colonIdx = line.IndexOf(": ", StringComparison.Ordinal); + if (colonIdx <= 0) continue; + + var key = line[..colonIdx].Trim(); + var value = line[(colonIdx + 2)..].Trim(); + + switch (key) + { + case "Version": + // Already known; fill in so it's accessible if needed + break; + case "Homepage": + if (Uri.TryCreate(value, UriKind.Absolute, out var homepage)) + details.HomepageUrl = homepage; + break; + case "Description": + case "Description-en": + details.Description = value; + inDescription = true; + break; + case "Maintainer": + details.Publisher = value; + break; + case "Depends": + details.Dependencies.Clear(); + foreach (var dep in value.Split(',')) + { + var depName = dep.Trim().Split(' ')[0]; + if (depName.Length > 0) + details.Dependencies.Add(new() { Name = depName, Version = "", Mandatory = true }); + } + break; + case "Recommends": + foreach (var dep in value.Split(',')) + { + var depName = dep.Trim().Split(' ')[0]; + if (depName.Length > 0) + details.Dependencies.Add(new() { Name = depName, Version = "", Mandatory = false }); + } + break; + case "Installed-Size": + details.InstallerSize = long.TryParse(value.Replace(" kB", "").Trim(), out var kb) + ? kb * 1024 + : 0; + break; + case "Source": + details.ManifestUrl = new Uri($"https://packages.debian.org/source/stable/{value}"); + break; + } + } + + if (descLines.Count > 0) + details.Description = (details.Description ?? "") + "\n" + string.Join("\n", descLines); + + logger.AddToStdErr(p.StandardError.ReadToEnd()); + p.WaitForExit(); + logger.Close(p.ExitCode); + } + + protected override CacheableIcon? GetIcon_UnSafe(IPackage package) + => throw new NotImplementedException(); + + protected override IReadOnlyList GetScreenshots_UnSafe(IPackage package) + => throw new NotImplementedException(); + + protected override string? GetInstallLocation_UnSafe(IPackage package) + { + // Debian packages install to system paths; the most reliable way + // to find the install location is to query dpkg. + using var p = new Process + { + StartInfo = new ProcessStartInfo + { + FileName = "dpkg", + Arguments = $"-L {package.Id}", + UseShellExecute = false, + RedirectStandardOutput = true, + RedirectStandardError = true, + CreateNoWindow = true, + }, + }; + p.Start(); + + // Must drain all stdout before WaitForExit — packages with many files + // will fill the pipe buffer and deadlock if we stop reading early. + string? result = null; + string? line; + while ((line = p.StandardOutput.ReadLine()) is not null) + { + if (result is not null) continue; + var path = line.Trim(); + if (Directory.Exists(path)) + result = path; + } + + p.StandardError.ReadToEnd(); + p.WaitForExit(); + return result; + } + + protected override IReadOnlyList GetInstallableVersions_UnSafe(IPackage package) + => throw new InvalidOperationException("APT does not support installing arbitrary versions"); +} diff --git a/src/UniGetUI.PackageEngine.Managers.Apt/Helpers/AptPkgOperationHelper.cs b/src/UniGetUI.PackageEngine.Managers.Apt/Helpers/AptPkgOperationHelper.cs new file mode 100644 index 0000000..d247277 --- /dev/null +++ b/src/UniGetUI.PackageEngine.Managers.Apt/Helpers/AptPkgOperationHelper.cs @@ -0,0 +1,60 @@ +using UniGetUI.PackageEngine.Classes.Manager.BaseProviders; +using UniGetUI.PackageEngine.Enums; +using UniGetUI.PackageEngine.Interfaces; +using UniGetUI.PackageEngine.Serializable; + +namespace UniGetUI.PackageEngine.Managers.AptManager; + +internal sealed class AptPkgOperationHelper : BasePkgOperationHelper +{ + public AptPkgOperationHelper(Apt manager) + : base(manager) { } + + protected override IReadOnlyList _getOperationParameters( + IPackage package, + InstallOptions options, + OperationType operation) + { + // apt always requires root — force elevation via InstallOptions (reference type, persists) + options.RunAsAdministrator = true; + + List parameters = + [ + operation switch + { + OperationType.Install => Manager.Properties.InstallVerb, + OperationType.Uninstall => Manager.Properties.UninstallVerb, + OperationType.Update => Manager.Properties.UpdateVerb, + _ => throw new InvalidDataException("Invalid package operation"), + }, + ]; + + if (operation == OperationType.Update) + parameters.Add("--only-upgrade"); + + parameters.Add("-y"); + parameters.Add(package.Id); + + if (options.SkipHashCheck) + parameters.Add("--allow-unauthenticated"); + + parameters.AddRange( + operation switch + { + OperationType.Update => options.CustomParameters_Update, + OperationType.Uninstall => options.CustomParameters_Uninstall, + _ => options.CustomParameters_Install, + }); + + return parameters; + } + + protected override OperationVeredict _getOperationResult( + IPackage package, + OperationType operation, + IReadOnlyList processOutput, + int returnCode) + { + return returnCode == 0 ? OperationVeredict.Success : OperationVeredict.Failure; + } +} diff --git a/src/UniGetUI.PackageEngine.Managers.Apt/UniGetUI.PackageEngine.Managers.Apt.csproj b/src/UniGetUI.PackageEngine.Managers.Apt/UniGetUI.PackageEngine.Managers.Apt.csproj new file mode 100644 index 0000000..a0903da --- /dev/null +++ b/src/UniGetUI.PackageEngine.Managers.Apt/UniGetUI.PackageEngine.Managers.Apt.csproj @@ -0,0 +1,23 @@ + + + $(SharedTargetFrameworks) + + + + + + + + + + + + + + + + + + + + diff --git a/src/UniGetUI.PackageEngine.Managers.Bun/Bun.cs b/src/UniGetUI.PackageEngine.Managers.Bun/Bun.cs new file mode 100644 index 0000000..a75a521 --- /dev/null +++ b/src/UniGetUI.PackageEngine.Managers.Bun/Bun.cs @@ -0,0 +1,398 @@ +using System.Diagnostics; +using System.Text.Json.Nodes; +using UniGetUI.Core.Data; +using UniGetUI.Core.Logging; +using UniGetUI.Core.SettingsEngine; +using UniGetUI.Core.Tools; +using UniGetUI.Interface.Enums; +using UniGetUI.PackageEngine.Classes.Manager; +using UniGetUI.PackageEngine.Classes.Manager.ManagerHelpers; +using UniGetUI.PackageEngine.Enums; +using UniGetUI.PackageEngine.Interfaces; +using UniGetUI.PackageEngine.ManagerClasses.Classes; +using UniGetUI.PackageEngine.ManagerClasses.Manager; +using UniGetUI.PackageEngine.PackageClasses; +using UniGetUI.PackageEngine.Structs; + +namespace UniGetUI.PackageEngine.Managers.BunManager +{ + public class Bun : PackageManager + { + public Bun() + { + Capabilities = new ManagerCapabilities + { + CanRunAsAdmin = true, + SupportsCustomVersions = true, + CanDownloadInstaller = true, + SupportsCustomScopes = false, + CanListDependencies = true, + SupportsPreRelease = true, + SupportsProxy = ProxySupport.No, + SupportsProxyAuth = false, + KnowsPackageReleaseDate = PackageReleaseDateSupport.Yes, + }; + + Properties = new ManagerProperties + { + Id = "bun", + Name = "Bun", + Description = CoreTools.Translate("Fast JavaScript runtime, bundler, and package manager"), + IconId = IconType.Bun, + ColorIconId = "bun_color", + ExecutableFriendlyName = "bun", + InstallVerb = "add", + UninstallVerb = "remove", + UpdateVerb = "add", + DefaultSource = new ManagerSource(this, "Bun", new Uri("https://www.npmjs.com/")), + KnownSources = [new ManagerSource(this, "Bun", new Uri("https://www.npmjs.com/"))], + }; + + DetailsHelper = new BunPkgDetailsHelper(this); + OperationHelper = new BunPkgOperationHelper(this); + } + + protected override IReadOnlyList FindPackages_UnSafe(string query) + { + // Bun has no `search` subcommand; it resolves packages from the npm registry. + // Query the registry's search endpoint directly (the same data npm search uses). + INativeTaskLogger logger = TaskLogger.CreateNew(LoggableTaskType.FindPackages); + string url = "https://registry.npmjs.org/-/v1/search?size=100&text=" + Uri.EscapeDataString(query); + logger.Log($"Querying the npm registry: {url}"); + + try + { + using HttpClient client = new(CoreTools.GenericHttpClientParameters); + client.DefaultRequestHeaders.UserAgent.ParseAdd(CoreData.UserAgentString); + string strContents = client.GetStringAsync(url).GetAwaiter().GetResult(); + logger.Log(strContents); + + var packages = ParseSearchOutput(strContents, DefaultSource, this); + logger.Close(0); + return packages; + } + catch (Exception e) + { + logger.Error(e); + logger.Close(1); + return []; + } + } + + protected override IReadOnlyList GetAvailableUpdates_UnSafe() + { + // bun outdated checks the project in the current directory, not a --global flag. + // Until Bun supports per-project working directories in UniGetUI, expose Bun as + // a global-only manager and query the dedicated global package.json. + string globalDir = GetGlobalPackagesDirectory( + Environment.GetFolderPath(Environment.SpecialFolder.UserProfile)); + + if (!HasGlobalPackageManifest(globalDir)) + { + Logger.Info($"Bun: Skipping global update detection because {globalDir} is missing package.json"); + return []; + } + + using Process p = new() + { + StartInfo = new ProcessStartInfo + { + FileName = Status.ExecutablePath, + Arguments = Status.ExecutableCallArgs + " outdated", + RedirectStandardOutput = true, + RedirectStandardError = true, + RedirectStandardInput = true, + UseShellExecute = false, + CreateNoWindow = true, + WorkingDirectory = globalDir, + StandardOutputEncoding = System.Text.Encoding.UTF8 + } + }; + + IProcessTaskLogger logger = TaskLogger.CreateNew(LoggableTaskType.ListUpdates, p); + p.Start(); + + // Read both streams concurrently to avoid deadlock when the process writes + // to both. Bun may write the table to stderr when stdout is not a TTY. + var stdoutTask = p.StandardOutput.ReadToEndAsync(); + var stderrTask = p.StandardError.ReadToEndAsync(); + Task.WaitAll(stdoutTask, stderrTask); + + string strOut = stdoutTask.Result; + string strErr = stderrTask.Result; + logger.AddToStdOut(strOut); + logger.AddToStdErr(strErr); + + // Read the preference first + bool preferLatest = Settings.Get(Settings.K.BunPreferLatestVersions); + + // Parse stdout first; fall back to stderr if stdout has no table rows. + string tableSrc = ParseBunOutdatedTable(strOut, preferLatest).Any() ? strOut : strErr; + var result = ParseAvailableUpdates(tableSrc, DefaultSource, this, preferLatest); + + Logger.Info($"Bun: Found {result.Count} packages with available updates (preferLatest={preferLatest})"); + foreach (var pkg in result) + { + Logger.Info($" - {pkg.Id}: {pkg.VersionString} → {pkg.NewVersionString}"); + } + + p.WaitForExit(); + logger.Close(p.ExitCode); + return result; + } + + protected override IReadOnlyList GetInstalledPackages_UnSafe() + { + // `bun pm ls --global` is a no-op for the --global flag: Bun ignores it and walks + // up from the working directory to the nearest lockfile. List the dedicated global + // package.json by running from that directory instead, mirroring GetAvailableUpdates_UnSafe. + string globalDir = GetGlobalPackagesDirectory( + Environment.GetFolderPath(Environment.SpecialFolder.UserProfile)); + + if (!HasGlobalPackageManifest(globalDir)) + { + Logger.Info($"Bun: Skipping installed package detection because {globalDir} is missing package.json"); + return []; + } + + List Packages = []; + + using Process p = new() + { + StartInfo = new ProcessStartInfo + { + FileName = Status.ExecutablePath, + Arguments = Status.ExecutableCallArgs + " pm ls", + RedirectStandardOutput = true, + RedirectStandardError = true, + RedirectStandardInput = true, + UseShellExecute = false, + CreateNoWindow = true, + WorkingDirectory = globalDir, + StandardOutputEncoding = System.Text.Encoding.UTF8 + } + }; + + IProcessTaskLogger logger = TaskLogger.CreateNew(LoggableTaskType.ListInstalledPackages, p); + p.Start(); + + // Read both streams concurrently to avoid deadlock when the process writes + // to both. Bun may write to stderr when stdout is not a TTY. + var stdoutTask = p.StandardOutput.ReadToEndAsync(); + var stderrTask = p.StandardError.ReadToEndAsync(); + Task.WaitAll(stdoutTask, stderrTask); + + string strContents = stdoutTask.Result; + logger.AddToStdOut(strContents); + + Packages.AddRange(ParseInstalledPackages(strContents, DefaultSource, this, new OverridenInstallationOptions(PackageScope.Global))); + + logger.AddToStdErr(stderrTask.Result); + p.WaitForExit(); + logger.Close(p.ExitCode); + + return Packages; + } + + public override IReadOnlyList FindCandidateExecutableFiles() + { + if (!OperatingSystem.IsWindows()) + return CoreTools.WhichMultiple("bun"); + + // The official installer ships bun.exe, but `npm i -g bun` only puts a bun.cmd + // wrapper on the PATH (the real bun.exe stays inside node_modules). Search both. + List candidates = [.. CoreTools.WhichMultiple("bun.exe")]; + candidates.AddRange(CoreTools.WhichMultiple("bun.cmd")); + return candidates; + } + + internal static string GetGlobalPackagesDirectory(string userProfile) + => Path.Combine(userProfile, ".bun", "install", "global"); + + internal static bool HasGlobalPackageManifest(string globalDir) + => Directory.Exists(globalDir) && File.Exists(Path.Combine(globalDir, "package.json")); + + protected override void _loadManagerExecutableFile(out bool found, out string path, out string callArguments) + { + var (_found, _executablePath) = GetExecutableFile(); + found = _found; + path = _executablePath; + callArguments = ""; + } + + protected override void _loadManagerVersion(out string version) + { + using Process process = new() + { + StartInfo = new ProcessStartInfo + { + FileName = Status.ExecutablePath, + Arguments = Status.ExecutableCallArgs + " --version", + UseShellExecute = false, + RedirectStandardOutput = true, + RedirectStandardError = true, + RedirectStandardInput = true, + CreateNoWindow = true, + WorkingDirectory = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), + StandardOutputEncoding = System.Text.Encoding.UTF8 + } + }; + process.Start(); + version = process.StandardOutput.ReadToEnd().Trim(); + process.WaitForExit(); + } + + /// + /// Parses the npm registry search response (https://registry.npmjs.org/-/v1/search). + /// The payload is { "objects": [ { "package": { "name", "version" } } ] }. + /// + internal static IReadOnlyList ParseSearchOutput( + string output, + IManagerSource source, + IPackageManager manager) + { + List packages = []; + + if (!output.Any()) return packages; + + try + { + JsonArray? results = (JsonNode.Parse(output) as JsonObject)?["objects"] as JsonArray; + foreach (JsonNode? entry in results ?? []) + { + JsonNode? pkg = entry?["package"]; + string? id = pkg?["name"]?.ToString(); + string? version = pkg?["version"]?.ToString(); + if (id is not null && version is not null) + { + packages.Add(new Package(CoreTools.FormatAsName(id), id, version, source, manager)); + } + } + } + catch (Exception e) + { + Logger.Warn($"Failed to parse Bun search results: {e.Message}"); + } + + return packages; + } + + /// + /// Parses the outdated packages table from 'bun outdated'. + /// Creates packages with current and available versions and sets scope to Global. + /// + internal static IReadOnlyList ParseAvailableUpdates( + string output, + IManagerSource source, + IPackageManager manager, + bool preferLatest = false) + { + List packages = []; + + foreach (var (packageId, version, newVersion) in ParseBunOutdatedTable(output, preferLatest)) + { + packages.Add(new Package(CoreTools.FormatAsName(packageId), packageId, version, newVersion, + source, manager, new(PackageScope.Global))); + } + + return packages; + } + + /// + /// Parses the installed packages tree from 'bun pm ls --global'. + /// Each package entry is formatted as: [├/└]── [@scope/]name@version + /// + internal static IReadOnlyList ParseInstalledPackages( + string output, + IManagerSource source, + IPackageManager manager, + OverridenInstallationOptions options) + { + List packages = []; + + // bun pm ls --global outputs a tree: + // /home/user/.bun/install/global node_modules (3) + // ├── @devcontainers/cli@0.81.1 + // └── typescript@5.7.3 + foreach (string line in output.Split('\n')) + { + if (!line.Contains("──")) continue; + string entry = line[(line.IndexOf("──") + 2)..].Trim(); + + // Use LastIndexOf to handle scoped packages: @scope/name@version + int atIdx = entry.LastIndexOf('@'); + if (atIdx <= 0) continue; + + string packageName = entry[..atIdx]; + string version = entry[(atIdx + 1)..]; + + if (string.IsNullOrWhiteSpace(packageName) || string.IsNullOrWhiteSpace(version)) continue; + + packages.Add(new Package(CoreTools.FormatAsName(packageName), packageName, version, + source, manager, options)); + } + + return packages; + } + + /// + /// Parses the outdated packages table from 'bun outdated'. + /// Supports both ASCII pipe format (|) and Unicode box-drawing format (│). + /// Each yielded tuple contains (packageId, currentVersion, recommendedUpdateVersion). + /// Columns: [Package | Current | Update | Latest] + /// If preferLatest is true, uses "Latest" (parts[4], may have breaking changes). + /// If preferLatest is false (default), uses "Update" (parts[3], safe semantic version). + /// + // TODO: Replace table parsing with JSON deserialization when bun outdated adds --json flag. + // Track: https://github.com/oven-sh/bun/issues — once --json is available, this entire + // method should be swapped for a simple JsonNode.Parse() call. + internal static IEnumerable<(string Id, string Version, string NewVersion)> ParseBunOutdatedTable( + string output, + bool preferLatest = false) + { + int columnIndex = preferLatest ? 4 : 3; // 4 = Latest, 3 = Update + string columnName = preferLatest ? "Latest" : "Update"; + + foreach (string line in output.Split('\n')) + { + string trimmed = line.TrimStart(); + // Skip lines that don't contain package data (headers, separators, etc.) + if (!trimmed.StartsWith('│') && !trimmed.StartsWith('|')) + { + continue; + + } + // Split by either Unicode box-drawing or ASCII pipe characters + string[] parts = line.Split(new[] { '│', '|' }, StringSplitOptions.None); + if (parts.Length < columnIndex + 1) + { + continue; + } + + string id = parts[1].Trim(); + string version = parts[2].Trim(); + string recommendedUpdate = parts[columnIndex].Trim(); + + // Skip header row, empty rows, and border lines (which contain only dashes or box-drawing chars) + if (id is "Package" || string.IsNullOrWhiteSpace(id) + || string.IsNullOrWhiteSpace(version) || string.IsNullOrWhiteSpace(recommendedUpdate) + || id.All(c => c == '-' || c == '─' || c == '┬' || c == '┼' || c == '┴' || c == '├' || c == '┤' || c == '┌' || c == '└' || c == '┘' || c == '┐') + || version.All(c => c == '-' || c == '─' || c == '┬' || c == '┼' || c == '┴' || c == '├' || c == '┤' || c == '┌' || c == '└' || c == '┘' || c == '┐')) + { + continue; + } + + // Only include packages that have a different update version + if (version != recommendedUpdate) + { + Logger.Debug($"Bun: Found update for {id}: {version} → {recommendedUpdate} (using {columnName} column)"); + yield return (id, version, recommendedUpdate); + } + else + { + Logger.Debug($"Bun: Skipping {id} (no update available: {version} == {recommendedUpdate})"); + } + } + } + } +} diff --git a/src/UniGetUI.PackageEngine.Managers.Bun/Helpers/BunPkgDetailsHelper.cs b/src/UniGetUI.PackageEngine.Managers.Bun/Helpers/BunPkgDetailsHelper.cs new file mode 100644 index 0000000..59de3d4 --- /dev/null +++ b/src/UniGetUI.PackageEngine.Managers.Bun/Helpers/BunPkgDetailsHelper.cs @@ -0,0 +1,190 @@ +using System.Diagnostics; +using System.Globalization; +using System.Text.Json.Nodes; +using UniGetUI.Core.IconEngine; +using UniGetUI.Core.Logging; +using UniGetUI.PackageEngine.Classes.Manager.BaseProviders; +using UniGetUI.PackageEngine.Enums; +using UniGetUI.PackageEngine.Interfaces; +using UniGetUI.PackageEngine.ManagerClasses.Classes; + +namespace UniGetUI.PackageEngine.Managers.BunManager +{ + internal sealed class BunPkgDetailsHelper : BasePkgDetailsHelper + { + public BunPkgDetailsHelper(Bun manager) : base(manager) { } + + protected override void GetDetails_UnSafe(IPackageDetails details) + { + try + { + details.InstallerType = "Tarball"; + details.ManifestUrl = new Uri($"https://www.npmjs.com/package/{details.Package.Id}"); + details.ReleaseNotesUrl = new Uri($"https://www.npmjs.com/package/{details.Package.Id}?activeTab=versions"); + + using Process p = new(); + p.StartInfo = new ProcessStartInfo + { + FileName = Manager.Status.ExecutablePath, + Arguments = Manager.Status.ExecutableCallArgs + " info " + details.Package.Id + " --json --global", + UseShellExecute = false, + RedirectStandardOutput = true, + RedirectStandardError = true, + RedirectStandardInput = true, + CreateNoWindow = true, + WorkingDirectory = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), + StandardOutputEncoding = System.Text.Encoding.UTF8 + }; + + IProcessTaskLogger logger = Manager.TaskLogger.CreateNew(LoggableTaskType.LoadPackageDetails, p); + p.Start(); + + var stdoutTask = p.StandardOutput.ReadToEndAsync(); + var stderrTask = p.StandardError.ReadToEndAsync(); + Task.WaitAll(stdoutTask, stderrTask); + + string strContents = stdoutTask.Result; + logger.AddToStdOut(strContents); + JsonObject? contents = JsonNode.Parse(strContents) as JsonObject; + + details.License = contents?["license"]?.ToString(); + details.Description = contents?["description"]?.ToString(); + + if (Uri.TryCreate(contents?["homepage"]?.ToString() ?? "", UriKind.RelativeOrAbsolute, out var homepageUrl)) + details.HomepageUrl = homepageUrl; + + details.Publisher = (contents?["maintainers"] as JsonArray)?[0]?.ToString(); + // Handle author which can be string or object with "name" property + var authorNode = contents?["author"]; + details.Author = authorNode is JsonObject authorObj ? authorObj["name"]?.ToString() : authorNode?.ToString(); + details.UpdateDate = contents?["time"]?[contents?["dist-tags"]?["latest"]?.ToString() ?? details.Package.VersionString]?.ToString(); + + if (Uri.TryCreate(contents?["dist"]?["tarball"]?.ToString() ?? "", UriKind.RelativeOrAbsolute, out var installerUrl)) + details.InstallerUrl = installerUrl; + + if (int.TryParse(contents?["dist"]?["unpackedSize"]?.ToString() ?? "", NumberStyles.Any, CultureInfo.InvariantCulture, out int installerSize)) + details.InstallerSize = installerSize; + + details.InstallerHash = contents?["dist"]?["integrity"]?.ToString(); + + details.Dependencies.Clear(); + HashSet addedDeps = new(); + foreach (var rawDep in (contents?["dependencies"]?.AsObject() ?? [])) + { + if (addedDeps.Contains(rawDep.Key)) continue; + addedDeps.Add(rawDep.Key); + + details.Dependencies.Add(new() + { + Name = rawDep.Key, + Version = rawDep.Value?.GetValue() ?? "", + Mandatory = true, + }); + } + + foreach (var rawDep in (contents?["devDependencies"]?.AsObject() ?? [])) + { + if (addedDeps.Contains(rawDep.Key)) continue; + addedDeps.Add(rawDep.Key); + + details.Dependencies.Add(new() + { + Name = rawDep.Key, + Version = rawDep.Value?.GetValue() ?? "", + Mandatory = false, + }); + } + + foreach (var rawDep in (contents?["peerDependencies"]?.AsObject() ?? [])) + { + if (addedDeps.Contains(rawDep.Key)) continue; + addedDeps.Add(rawDep.Key); + + details.Dependencies.Add(new() + { + Name = rawDep.Key, + Version = rawDep.Value?.GetValue() ?? "", + Mandatory = false, + }); + } + + logger.AddToStdErr(stderrTask.Result); + p.WaitForExit(); + logger.Close(p.ExitCode); + } + catch (Exception e) + { + Logger.Error(e); + } + + return; + } + + protected override CacheableIcon? GetIcon_UnSafe(IPackage package) + { + return null; + } + + protected override IReadOnlyList GetScreenshots_UnSafe(IPackage package) + { + return []; + } + + protected override string? GetInstallLocation_UnSafe(IPackage package) + { + return GetInstallLocation( + Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), + package.OverridenOptions.Scope, + package.Id); + } + + internal static string GetInstallLocation(string userProfile, string? scope, string packageId) + { + if (scope is PackageScope.Local) + return Path.Join(userProfile, "node_modules", packageId); + + return Path.Join(Bun.GetGlobalPackagesDirectory(userProfile), "node_modules", packageId); + } + + protected override IReadOnlyList GetInstallableVersions_UnSafe(IPackage package) + { + using Process p = new() + { + StartInfo = new ProcessStartInfo + { + FileName = Manager.Status.ExecutablePath, + Arguments = + Manager.Status.ExecutableCallArgs + " info " + package.Id + " --json --global", + UseShellExecute = false, + RedirectStandardOutput = true, + RedirectStandardError = true, + RedirectStandardInput = true, + CreateNoWindow = true, + WorkingDirectory = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), + StandardOutputEncoding = System.Text.Encoding.UTF8 + } + }; + + IProcessTaskLogger logger = Manager.TaskLogger.CreateNew(LoggableTaskType.LoadPackageVersions, p); + p.Start(); + + string strContents = p.StandardOutput.ReadToEnd(); + logger.AddToStdOut(strContents); + JsonObject? contents = JsonNode.Parse(strContents) as JsonObject; + JsonArray? rawVersions = contents?["versions"] as JsonArray; + + List versions = []; + foreach (JsonNode? raw_ver in rawVersions ?? []) + { + if (raw_ver is not null) + versions.Add(raw_ver.ToString()); + } + + logger.AddToStdErr(p.StandardError.ReadToEnd()); + p.WaitForExit(); + logger.Close(p.ExitCode); + + return versions; + } + } +} diff --git a/src/UniGetUI.PackageEngine.Managers.Bun/Helpers/BunPkgOperationHelper.cs b/src/UniGetUI.PackageEngine.Managers.Bun/Helpers/BunPkgOperationHelper.cs new file mode 100644 index 0000000..82ec061 --- /dev/null +++ b/src/UniGetUI.PackageEngine.Managers.Bun/Helpers/BunPkgOperationHelper.cs @@ -0,0 +1,57 @@ +using UniGetUI.PackageEngine.Classes.Manager.BaseProviders; +using UniGetUI.PackageEngine.Enums; +using UniGetUI.PackageEngine.Interfaces; +using UniGetUI.PackageEngine.Serializable; + +namespace UniGetUI.PackageEngine.Managers.BunManager; + +internal sealed class BunPkgOperationHelper : BasePkgOperationHelper +{ + public BunPkgOperationHelper(Bun manager) : base(manager) { } + + protected override IReadOnlyList _getOperationParameters(IPackage package, + InstallOptions options, OperationType operation) + { + // Bun is called directly (not through PowerShell), so we do NOT use quotes. + // Quotes would be passed literally to bun.exe, which doesn't understand them. + // Unlike Npm which goes through PowerShell on Windows, Bun always executes directly. + + List parameters = operation switch + { + OperationType.Install => + [ + Manager.Properties.InstallVerb, + $"{package.Id}@{(options.Version == string.Empty ? package.VersionString : options.Version)}", + ], + OperationType.Update => + [ + Manager.Properties.UpdateVerb, + $"{package.Id}@{package.NewVersionString}", + ], + OperationType.Uninstall => [Manager.Properties.UninstallVerb, package.Id], + _ => throw new InvalidDataException("Invalid package operation") + }; + + string effectiveScope = package.OverridenOptions.Scope ?? options.InstallationScope; + if (effectiveScope is not PackageScope.Local) + parameters.Add("--global"); + + parameters.AddRange(operation switch + { + OperationType.Update => options.CustomParameters_Update, + OperationType.Uninstall => options.CustomParameters_Uninstall, + _ => options.CustomParameters_Install, + }); + + return parameters; + } + + protected override OperationVeredict _getOperationResult( + IPackage package, + OperationType operation, + IReadOnlyList processOutput, + int returnCode) + { + return returnCode == 0 ? OperationVeredict.Success : OperationVeredict.Failure; + } +} diff --git a/src/UniGetUI.PackageEngine.Managers.Bun/InternalsVisibleTo.cs b/src/UniGetUI.PackageEngine.Managers.Bun/InternalsVisibleTo.cs new file mode 100644 index 0000000..eeb63da --- /dev/null +++ b/src/UniGetUI.PackageEngine.Managers.Bun/InternalsVisibleTo.cs @@ -0,0 +1,3 @@ +using System.Runtime.CompilerServices; + +[assembly: InternalsVisibleTo("UniGetUI.PackageEngine.Tests")] diff --git a/src/UniGetUI.PackageEngine.Managers.Bun/UniGetUI.PackageEngine.Managers.Bun.csproj b/src/UniGetUI.PackageEngine.Managers.Bun/UniGetUI.PackageEngine.Managers.Bun.csproj new file mode 100644 index 0000000..74aff90 --- /dev/null +++ b/src/UniGetUI.PackageEngine.Managers.Bun/UniGetUI.PackageEngine.Managers.Bun.csproj @@ -0,0 +1,29 @@ + + + $(SharedTargetFrameworks) + UniGetUI.PackageEngine.Managers.Bun + UniGetUI.PackageEngine.Managers.BunManager + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/UniGetUI.PackageEngine.Managers.Cargo/Cargo.cs b/src/UniGetUI.PackageEngine.Managers.Cargo/Cargo.cs new file mode 100644 index 0000000..ce0f84b --- /dev/null +++ b/src/UniGetUI.PackageEngine.Managers.Cargo/Cargo.cs @@ -0,0 +1,278 @@ +using System.Diagnostics; +using System.Text; +using System.Text.RegularExpressions; +using UniGetUI.Core.Classes; +using UniGetUI.Core.Data; +using UniGetUI.Core.Logging; +using UniGetUI.Core.Tools; +using UniGetUI.Interface.Enums; +using UniGetUI.PackageEngine.Classes.Manager; +using UniGetUI.PackageEngine.Classes.Manager.Classes; +using UniGetUI.PackageEngine.Classes.Manager.ManagerHelpers; +using UniGetUI.PackageEngine.Enums; +using UniGetUI.PackageEngine.ManagerClasses.Classes; +using UniGetUI.PackageEngine.ManagerClasses.Manager; +using UniGetUI.PackageEngine.PackageClasses; + +namespace UniGetUI.PackageEngine.Managers.CargoManager; + +public partial class Cargo : PackageManager +{ + [GeneratedRegex(@"([\w-]+)\s=\s""(\d+\.\d+\.\d+)""\s*#\s(.*)")] + private static partial Regex SearchLineRegex(); + + [GeneratedRegex(@"(.+)v(\d+\.\d+\.\d+)\s*v(\d+\.\d+\.\d+)\s*(Yes|No)")] + private static partial Regex UpdateLineRegex(); + + // Matches "ripgrep v15.1.0:" lines from `cargo install --list` + [GeneratedRegex(@"^([\w-]+)\s+v(\d+\.\d+\.\d+):")] + private static partial Regex InstallListLineRegex(); + + public Cargo() + { + string cargoCommand = OperatingSystem.IsWindows() ? "cargo.exe" : "cargo"; + string cargoUpdateBinary = OperatingSystem.IsWindows() + ? "cargo-install-update.exe" + : "cargo-install-update"; + string cargoBinstallBinary = OperatingSystem.IsWindows() + ? "cargo-binstall.exe" + : "cargo-binstall"; + + Dependencies = + [ + // cargo-update is required to check for installed and upgradable packages + new ManagerDependency( + "cargo-update", + cargoCommand, + "install cargo-update", + "cargo install cargo-update", + async () => (await CoreTools.WhichAsync(cargoUpdateBinary)).Item1 + ), + // Cargo-binstall is required to install and update cargo binaries + new ManagerDependency( + "cargo-binstall", + cargoCommand, + "install cargo-binstall", + "cargo install cargo-binstall", + async () => (await CoreTools.WhichAsync(cargoBinstallBinary)).Item1 + ), + ]; + + Capabilities = new ManagerCapabilities + { + CanRunAsAdmin = true, + CanSkipIntegrityChecks = true, + SupportsCustomVersions = true, + SupportsCustomLocations = true, + CanDownloadInstaller = true, + SupportsProxy = ProxySupport.Partially, + SupportsProxyAuth = true, + KnowsPackageReleaseDate = PackageReleaseDateSupport.Yes, + }; + + var cratesIo = new ManagerSource(this, "crates.io", new Uri("https://index.crates.io/")); + + Properties = new ManagerProperties + { + Id = "cargo", + Name = "Cargo", + Description = CoreTools.Translate( + "The Rust package manager.
Contains: Rust libraries and programs written in Rust" + ), + IconId = IconType.Rust, + ColorIconId = "cargo_color", + ExecutableFriendlyName = "cargo.exe", + InstallVerb = "binstall", + UninstallVerb = "uninstall", + UpdateVerb = "binstall", + DefaultSource = cratesIo, + KnownSources = [cratesIo], + }; + + DetailsHelper = new CargoPkgDetailsHelper(this); + OperationHelper = new CargoPkgOperationHelper(this); + } + + protected override IReadOnlyList FindPackages_UnSafe(string query) + { + using Process p = GetProcess(Status.ExecutablePath, "search -q --color=never " + query); + IProcessTaskLogger logger = TaskLogger.CreateNew(LoggableTaskType.FindPackages, p); + p.Start(); + + string? line; + List Packages = []; + while ((line = p.StandardOutput.ReadLine()) is not null) + { + logger.AddToStdOut(line); + var match = SearchLineRegex().Match(line); + if (match.Success) + { + var id = match.Groups[1].Value; + var version = match.Groups[2].Value; + Packages.Add( + new Package(CoreTools.FormatAsName(id), id, version, DefaultSource, this) + ); + } + } + + logger.AddToStdErr(p.StandardError.ReadToEnd()); + p.WaitForExit(); + + List BinPackages = []; + + for (int i = 0; i < Packages.Count; i++) + { + DateTime startTime = DateTime.Now; + + var package = Packages[i]; + try + { + var versionInfo = CratesIOClient.GetManifestVersion( + package.Id, + package.VersionString + ); + if (versionInfo.bin_names?.Length > 0) + BinPackages.Add(package); + } + catch (Exception ex) + { + // On API failure, include the package rather than silently drop it + logger.AddToStdErr($"bin_names check failed for {package.Id}: {ex.Message}"); + BinPackages.Add(package); + } + + if (i + 1 == Packages.Count) + break; + // Crates.io requires no more than one request per second + Task.Delay(Math.Max(0, 1000 - (int)(DateTime.Now - startTime).TotalMilliseconds)) + .GetAwaiter() + .GetResult(); + } + + logger.Close(p.ExitCode); + + return [.. BinPackages]; + } + + protected override IReadOnlyList GetAvailableUpdates_UnSafe() + { + return GetPackages(LoggableTaskType.ListUpdates); + } + + protected override IReadOnlyList GetInstalledPackages_UnSafe() + { + return GetPackages(LoggableTaskType.ListInstalledPackages); + } + + public readonly bool HasBinstall = + CoreTools.Which(OperatingSystem.IsWindows() ? "cargo-binstall.exe" : "cargo-binstall").Item1; + + public override IReadOnlyList FindCandidateExecutableFiles() => + CoreTools.WhichMultiple(OperatingSystem.IsWindows() ? "cargo.exe" : "cargo"); + + protected override void _loadManagerExecutableFile( + out bool found, + out string path, + out string callArguments + ) + { + var (_found, _executablePath) = GetExecutableFile(); + found = _found; + path = _executablePath; + callArguments = ""; + } + + protected override void _loadManagerVersion(out string version) + { + using Process p = GetProcess(Status.ExecutablePath, "--version"); + p.Start(); + version = p.StandardOutput.ReadToEnd().Trim(); + string error = p.StandardError.ReadToEnd(); + if (!string.IsNullOrEmpty(error)) + Logger.Error("cargo version error: " + error); + } + + public void InvalidateInstalledCache() => + TaskRecycler>.RemoveFromCache(GetInstalledCommandOutput); + + private IReadOnlyList GetPackages(LoggableTaskType taskType) + { + List Packages = []; + foreach (var match in TaskRecycler>.RunOrAttach(GetInstalledCommandOutput, 15)) + { + var id = match.Groups[1]?.Value?.Trim() ?? ""; + var name = CoreTools.FormatAsName(id); + var oldVersion = match.Groups[2]?.Value?.Trim() ?? ""; + var newVersion = match.Groups[3]?.Value?.Trim() ?? ""; + if (taskType is LoggableTaskType.ListUpdates && oldVersion != newVersion) + Packages.Add(new Package(name, id, oldVersion, newVersion, DefaultSource, this)); + else if (taskType is LoggableTaskType.ListInstalledPackages) + Packages.Add(new Package(name, id, oldVersion, DefaultSource, this)); + } + return Packages; + } + + private List GetInstalledCommandOutput() + { + List output = []; + using Process p = GetProcess(Status.ExecutablePath, "install-update --list"); + IProcessTaskLogger logger = TaskLogger.CreateNew(LoggableTaskType.OtherTask, p); + logger.AddToStdOut("Other task: Call the install-update command"); + p.Start(); + + string? line; + while ((line = p.StandardOutput.ReadLine()) is not null) + { + logger.AddToStdOut(line); + var match = UpdateLineRegex().Match(line); + if (match.Success) + output.Add(match); + } + logger.AddToStdErr(p.StandardError.ReadToEnd()); + p.WaitForExit(); + logger.Close(p.ExitCode); + + if (output.Count > 0) + return output; + + // Fallback: cargo-update is not installed, use the built-in `cargo install --list`. + // No latest-version info is available, so updates won't be detected, but the installed + // packages list will be populated correctly. + using Process fallback = GetProcess(Status.ExecutablePath, "install --list"); + IProcessTaskLogger fallbackLogger = TaskLogger.CreateNew(LoggableTaskType.OtherTask, fallback); + fallbackLogger.AddToStdOut("Falling back to `cargo install --list` (cargo-update not available)"); + fallback.Start(); + while ((line = fallback.StandardOutput.ReadLine()) is not null) + { + fallbackLogger.AddToStdOut(line); + var m = InstallListLineRegex().Match(line); + if (!m.Success) continue; + // Synthesise a match compatible with UpdateLineRegex (same installed and latest version → no update) + var fake = UpdateLineRegex().Match($"{m.Groups[1].Value} v{m.Groups[2].Value} v{m.Groups[2].Value} No"); + if (fake.Success) + output.Add(fake); + } + fallbackLogger.AddToStdErr(fallback.StandardError.ReadToEnd()); + fallback.WaitForExit(); + fallbackLogger.Close(fallback.ExitCode); + return output; + } + + private Process GetProcess(string fileName, string extraArguments) + { + return new() + { + StartInfo = new ProcessStartInfo + { + FileName = fileName, + Arguments = Status.ExecutableCallArgs + " " + extraArguments, + RedirectStandardOutput = true, + RedirectStandardError = true, + UseShellExecute = false, + CreateNoWindow = true, + StandardOutputEncoding = Encoding.UTF8, + StandardErrorEncoding = Encoding.UTF8, + }, + }; + } +} diff --git a/src/UniGetUI.PackageEngine.Managers.Cargo/CargoJson.cs b/src/UniGetUI.PackageEngine.Managers.Cargo/CargoJson.cs new file mode 100644 index 0000000..a7fbd9b --- /dev/null +++ b/src/UniGetUI.PackageEngine.Managers.Cargo/CargoJson.cs @@ -0,0 +1,26 @@ +using System.Text.Json; +using System.Text.Json.Serialization; +using System.Text.Json.Serialization.Metadata; + +namespace UniGetUI.PackageEngine.Managers.CargoManager; + +internal static class CargoJson +{ + public static T? Deserialize(string json) + { + return JsonSerializer.Deserialize(json, GetTypeInfo()); + } + + private static JsonTypeInfo GetTypeInfo() + { + return (JsonTypeInfo?)CargoJsonContext.Default.GetTypeInfo(typeof(T)) + ?? throw new InvalidOperationException( + $"Cargo JSON metadata for {typeof(T).FullName} was not generated." + ); + } +} + +[JsonSourceGenerationOptions(AllowTrailingCommas = true, WriteIndented = true)] +[JsonSerializable(typeof(CargoManifest))] +[JsonSerializable(typeof(CargoManifestVersionWrapper))] +internal sealed partial class CargoJsonContext : JsonSerializerContext; diff --git a/src/UniGetUI.PackageEngine.Managers.Cargo/CratesIOClient.cs b/src/UniGetUI.PackageEngine.Managers.Cargo/CratesIOClient.cs new file mode 100644 index 0000000..3304ee4 --- /dev/null +++ b/src/UniGetUI.PackageEngine.Managers.Cargo/CratesIOClient.cs @@ -0,0 +1,109 @@ +using System.Text.Json; +using UniGetUI.Core.Data; +using UniGetUI.Core.Tools; + +namespace UniGetUI.PackageEngine.Managers.CargoManager; + +internal sealed record CargoManifest +{ + public CargoManifestCategory[]? categories { get; init; } + public required CargoManifestCrate crate { get; init; } + public required CargoManifestVersion[] versions { get; init; } +} + +internal sealed record CargoManifestCategory +{ + public required string category { get; init; } + public required string description { get; init; } + public required string id { get; init; } +} + +internal sealed record CargoManifestCrate +{ + public string[]? categories { get; init; } + public string? description { get; init; } + public string? documentation { get; init; } + public double? downloads { get; init; } + public string? homepage { get; init; } + public string[]? keywords { get; init; } + public required string max_stable_version { get; init; } + public required string max_version { get; init; } + public required string name { get; init; } + public required string newest_version { get; init; } + public string? repository { get; init; } + public string? updated_at { get; init; } +} + +internal sealed record CargoManifestVersion +{ + public string[]? bin_names { get; init; } + public required string checksum { get; init; } + public long? crate_size { get; init; } + public string? created_at { get; init; } + public required string dl_path { get; init; } + public string? license { get; init; } + public required string num { get; init; } + public CargoManifestPublisher? published_by { get; init; } + public string? updated_at { get; init; } + public bool yanked { get; init; } +} + +internal sealed record CargoManifestVersionWrapper +{ + public required CargoManifestVersion version { get; init; } +} + +internal sealed class CargoManifestPublisher +{ + public string? avatar { get; init; } + public required string name { get; init; } + public string? url { get; init; } +} + +internal sealed class CratesIOClient +{ + public const string ApiUrl = "https://crates.io/api/v1"; + internal static string? TEST_ApiUrlOverride { private get; set; } + + public static Tuple GetManifest(string packageId) + { + var manifestUrl = new Uri($"{GetApiUrl()}/crates/{packageId}"); + var manifest = Fetch(manifestUrl); + if (manifest.crate is null) + { + throw new NullResponseException($"Null response for package {packageId}"); + } + return Tuple.Create(manifestUrl, manifest); + } + + public static CargoManifestVersion GetManifestVersion(string packageId, string version) + { + var manifestUrl = new Uri($"{GetApiUrl()}/crates/{packageId}/{version}"); + var manifest = Fetch(manifestUrl); + if (manifest.version is null) + { + throw new NullResponseException($"Null response for package {packageId}"); + } + return manifest.version; + } + + private static string GetApiUrl() => TEST_ApiUrlOverride ?? ApiUrl; + + internal static T Fetch(Uri url) + { + using HttpClient client = new(CoreTools.GenericHttpClientParameters); + client.DefaultRequestHeaders.UserAgent.ParseAdd(CoreData.UserAgentString); + using var request = new HttpRequestMessage(HttpMethod.Get, url); + using HttpResponseMessage response = client.Send(request); + response.EnsureSuccessStatusCode(); + + string manifestStr = response.Content.ReadAsStringAsync().GetAwaiter().GetResult(); + + var manifest = + CargoJson.Deserialize(manifestStr) + ?? throw new NullResponseException($"Null response for request to {url}"); + return manifest; + } +} + +public class NullResponseException(string message) : Exception(message); diff --git a/src/UniGetUI.PackageEngine.Managers.Cargo/Helpers/CargoPkgDetailsHelper.cs b/src/UniGetUI.PackageEngine.Managers.Cargo/Helpers/CargoPkgDetailsHelper.cs new file mode 100644 index 0000000..6096e4d --- /dev/null +++ b/src/UniGetUI.PackageEngine.Managers.Cargo/Helpers/CargoPkgDetailsHelper.cs @@ -0,0 +1,109 @@ +using UniGetUI.Core.IconEngine; +using UniGetUI.PackageEngine.Classes.Manager.BaseProviders; +using UniGetUI.PackageEngine.Interfaces; +using UniGetUI.PackageEngine.ManagerClasses.Classes; + +namespace UniGetUI.PackageEngine.Managers.CargoManager; + +internal sealed class CargoPkgDetailsHelper(Cargo manager) : BasePkgDetailsHelper(manager) +{ + protected override void GetDetails_UnSafe(IPackageDetails details) + { + details.InstallerType = "Source"; + + INativeTaskLogger logger = Manager.TaskLogger.CreateNew( + Enums.LoggableTaskType.LoadPackageDetails + ); + + Uri manifestUrl; + CargoManifest manifest; + try + { + (manifestUrl, manifest) = CratesIOClient.GetManifest(details.Package.Id); + } + catch (Exception ex) + { + logger.Error(ex); + logger.Close(1); + return; + } + + details.Description = manifest.crate.description; + details.ManifestUrl = manifestUrl; + + var homepage = + manifest.crate.homepage ?? manifest.crate.repository ?? manifest.crate.documentation; + if (!string.IsNullOrEmpty(homepage)) + { + details.HomepageUrl = new Uri(homepage); + } + + var keywords = manifest.crate.keywords is null + ? [] + : (string[])manifest.crate.keywords.Clone(); + var categories = manifest.categories?.Select(c => c.category) ?? []; + details.Tags = [.. keywords, .. categories]; + + var versionData = manifest + .versions.Where((v) => v.num == details.Package.VersionString) + .First(); + + details.Author = versionData.published_by?.name; + details.License = versionData.license; + details.InstallerUrl = new Uri( + (CratesIOClient.ApiUrl + versionData.dl_path).Replace("/api/v1/api/v1", "/api/v1") + ); + details.InstallerSize = versionData.crate_size ?? 0; + details.InstallerHash = versionData.checksum; + details.Publisher = versionData.published_by?.name; + details.UpdateDate = versionData.updated_at; + + // TODO: most packages are hosted on Github; see if there's a way to use the repository + // info to extract release notes + + logger.Close(0); + return; + } + + protected override CacheableIcon? GetIcon_UnSafe(IPackage package) + { + throw new NotImplementedException(); + } + + protected override IReadOnlyList GetScreenshots_UnSafe(IPackage package) + { + throw new NotImplementedException(); + } + + protected override string? GetInstallLocation_UnSafe(IPackage package) + { + // Cargo installs binaries into $CARGO_HOME/bin (default ~/.cargo/bin). + var cargoHome = Environment.GetEnvironmentVariable("CARGO_HOME"); + if (string.IsNullOrEmpty(cargoHome)) + cargoHome = Path.Join( + Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), + ".cargo" + ); + return Path.Join(cargoHome, "bin"); + } + + protected override IReadOnlyList GetInstallableVersions_UnSafe(IPackage package) + { + INativeTaskLogger logger = Manager.TaskLogger.CreateNew( + Enums.LoggableTaskType.LoadPackageVersions + ); + try + { + var (_, manifest) = CratesIOClient.GetManifest(package.Id); + var versions = manifest.versions.Select((v) => v.num).ToArray(); + logger.Close(0); + return versions; + } + catch (Exception ex) + { + logger.Error(ex); + logger.Close(1); + throw; + } + } +} diff --git a/src/UniGetUI.PackageEngine.Managers.Cargo/Helpers/CargoPkgOperationHelper.cs b/src/UniGetUI.PackageEngine.Managers.Cargo/Helpers/CargoPkgOperationHelper.cs new file mode 100644 index 0000000..9ac2122 --- /dev/null +++ b/src/UniGetUI.PackageEngine.Managers.Cargo/Helpers/CargoPkgOperationHelper.cs @@ -0,0 +1,85 @@ +using UniGetUI.PackageEngine.Classes.Manager.BaseProviders; +using UniGetUI.PackageEngine.Enums; +using UniGetUI.PackageEngine.Interfaces; +using UniGetUI.PackageEngine.Serializable; + +namespace UniGetUI.PackageEngine.Managers.CargoManager; + +internal sealed class CargoPkgOperationHelper(Cargo cargo) : BasePkgOperationHelper(cargo) +{ + protected override IReadOnlyList _getOperationParameters( + IPackage package, + InstallOptions options, + OperationType operation + ) + { + var installVersion = options.Version == string.Empty ? package.VersionString : options.Version; + + bool hasBinstall = ((Cargo)Manager).HasBinstall; + + List parameters; + switch (operation) + { + case OperationType.Install: + if (hasBinstall) + parameters = [Manager.Properties.InstallVerb, "--version", installVersion, package.Id]; + else + parameters = ["install", package.Id, "--version", installVersion]; + break; + + case OperationType.Update: + if (hasBinstall) + parameters = [Manager.Properties.UpdateVerb, package.Id]; + else + parameters = ["install", package.Id, "--force"]; + break; + + case OperationType.Uninstall: + parameters = [Manager.Properties.UninstallVerb, package.Id]; + break; + + default: + throw new InvalidDataException("Invalid package operation"); + } + + if (operation is OperationType.Install or OperationType.Update) + { + if (hasBinstall) + { + parameters.Add("--no-confirm"); + + if (options.SkipHashCheck) + parameters.Add("--skip-signatures"); + + if (options.CustomInstallLocation != "") + parameters.AddRange(["--install-path", options.CustomInstallLocation]); + } + } + + parameters.AddRange( + operation switch + { + OperationType.Update => options.CustomParameters_Update, + OperationType.Uninstall => options.CustomParameters_Uninstall, + _ => options.CustomParameters_Install, + } + ); + + return parameters; + } + + protected override OperationVeredict _getOperationResult( + IPackage package, + OperationType operation, + IReadOnlyList processOutput, + int returnCode + ) + { + if (returnCode == 0) + { + ((Cargo)Manager).InvalidateInstalledCache(); + return OperationVeredict.Success; + } + return OperationVeredict.Failure; + } +} diff --git a/src/UniGetUI.PackageEngine.Managers.Cargo/InternalsVisibleTo.cs b/src/UniGetUI.PackageEngine.Managers.Cargo/InternalsVisibleTo.cs new file mode 100644 index 0000000..eeb63da --- /dev/null +++ b/src/UniGetUI.PackageEngine.Managers.Cargo/InternalsVisibleTo.cs @@ -0,0 +1,3 @@ +using System.Runtime.CompilerServices; + +[assembly: InternalsVisibleTo("UniGetUI.PackageEngine.Tests")] diff --git a/src/UniGetUI.PackageEngine.Managers.Cargo/UniGetUI.PackageEngine.Managers.Cargo.csproj b/src/UniGetUI.PackageEngine.Managers.Cargo/UniGetUI.PackageEngine.Managers.Cargo.csproj new file mode 100644 index 0000000..cfa6fbf --- /dev/null +++ b/src/UniGetUI.PackageEngine.Managers.Cargo/UniGetUI.PackageEngine.Managers.Cargo.csproj @@ -0,0 +1,27 @@ + + + $(SharedTargetFrameworks) + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/UniGetUI.PackageEngine.Managers.Chocolatey/Chocolatey.cs b/src/UniGetUI.PackageEngine.Managers.Chocolatey/Chocolatey.cs new file mode 100644 index 0000000..7c19d4e --- /dev/null +++ b/src/UniGetUI.PackageEngine.Managers.Chocolatey/Chocolatey.cs @@ -0,0 +1,406 @@ +using System.Diagnostics; +using System.Text; +using UniGetUI.Core.Data; +using UniGetUI.Core.Logging; +using UniGetUI.Core.SettingsEngine; +using UniGetUI.Core.Tools; +using UniGetUI.Interface.Enums; +using UniGetUI.PackageEngine.Classes.Manager; +using UniGetUI.PackageEngine.Classes.Manager.ManagerHelpers; +using UniGetUI.PackageEngine.Enums; +using UniGetUI.PackageEngine.ManagerClasses.Classes; +using UniGetUI.PackageEngine.ManagerClasses.Manager; +using UniGetUI.PackageEngine.Managers.Choco; +using UniGetUI.PackageEngine.Managers.PowerShellManager; +using UniGetUI.PackageEngine.PackageClasses; +using Architecture = UniGetUI.PackageEngine.Enums.Architecture; + +namespace UniGetUI.PackageEngine.Managers.ChocolateyManager +{ + public class Chocolatey : BaseNuGet + { + // Chocolatey emits its output in the system console code page, not UTF-8. + public override Encoding OutputEncoding => CoreData.ConsoleEncoding; + + public static readonly string[] FALSE_PACKAGE_IDS = + [ + "Directory", + "Output is Id", + "", + "Did", + "Features?", + "Validation", + "-", + "being", + "It", + "Error", + "L'accs", + "Maximum", + "This", + "Output is package name ", + "operable", + "Invalid", + ]; + public static readonly string[] FALSE_PACKAGE_VERSIONS = + [ + "", + "Version", + "of", + "Did", + "Features?", + "Validation", + "-", + "being", + "It", + "Error", + "L'accs", + "Maximum", + "This", + "packages", + "current version", + "installed version", + "is", + "program", + "validations", + "argument", + "no", + ]; + private const string DefaultSystemChocoPath = @"C:\ProgramData\chocolatey\bin\choco.exe"; + private static readonly string[] LegacyBundledChocolateyPaths = + [ + Path.Join( + Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), + "Programs\\WingetUI\\choco-cli" + ), + Path.Join(CoreData.UniGetUIDataDirectory, "Chocolatey"), + ]; + + // AttemptFastRepair is a no-op here, so retrying a timed-out choco listing just spawns another (#4974). + protected override bool RetryListingTasksOnTimeout => false; + + public Chocolatey() + { + Capabilities = new ManagerCapabilities + { + CanRunAsAdmin = true, + CanDownloadInstaller = true, + CanSkipIntegrityChecks = true, + CanRunInteractively = true, + SupportsCustomVersions = true, + CanListDependencies = true, + SupportsCustomArchitectures = true, + SupportedCustomArchitectures = [Architecture.x86], + SupportsPreRelease = true, + SupportsCustomSources = true, + SupportsCustomPackageIcons = true, + Sources = new SourceCapabilities + { + KnowsPackageCount = false, + KnowsUpdateDate = false, + }, + SupportsProxy = ProxySupport.Yes, + SupportsProxyAuth = true, + KnowsPackageReleaseDate = PackageReleaseDateSupport.Yes, + }; + + Properties = new ManagerProperties + { + Id = "chocolatey", + Name = "Chocolatey", + Description = CoreTools.Translate( + "The classical package manager for windows. You'll find everything there.
Contains: General Software" + ), + IconId = IconType.Chocolatey, + ColorIconId = "choco_color", + ExecutableFriendlyName = "choco.exe", + InstallVerb = "install", + UninstallVerb = "uninstall", + UpdateVerb = "upgrade", + KnownSources = + [ + new ManagerSource( + this, + "community", + new Uri("https://community.chocolatey.org/api/v2/") + ), + ], + DefaultSource = new ManagerSource( + this, + "community", + new Uri("https://community.chocolatey.org/api/v2/") + ), + }; + + SourcesHelper = new ChocolateySourceHelper(this); + DetailsHelper = new ChocolateyDetailsHelper(this); + OperationHelper = new ChocolateyPkgOperationHelper(this); + } + + public static string GetProxyArgument() + { + if (!Settings.Get(Settings.K.EnableProxy)) + return ""; + var proxyUri = Settings.GetProxyUrl(); + if (proxyUri is null) + return ""; + + if (Settings.Get(Settings.K.EnableProxyAuth) is false) + return $"--proxy {proxyUri.ToString()}"; + + var creds = Settings.GetProxyCredentials(); + if (creds is null) + return $"--proxy {proxyUri.ToString()}"; + + return $"--proxy={proxyUri.ToString()} --proxy-user={Uri.EscapeDataString(creds.UserName)}" + + $" --proxy-password={Uri.EscapeDataString(creds.Password)}"; + } + + public static bool HasLegacyBundledInstallation() + { + foreach (string path in LegacyBundledChocolateyPaths) + { + if ( + File.Exists(Path.Join(path, "choco.exe")) + || File.Exists(Path.Join(path, "bin", "choco.exe")) + ) + { + return true; + } + } + + return false; + } + + internal IReadOnlyList ParseAvailableUpdates(IEnumerable lines) + { + List packages = []; + foreach (string line in lines) + { + if (line.StartsWith("Chocolatey")) + { + continue; + } + + string[] elements = line.Split('|'); + for (int i = 0; i < elements.Length; i++) + { + elements[i] = elements[i].Trim(); + } + + if (elements.Length <= 2) + { + continue; + } + + if ( + FALSE_PACKAGE_IDS.Contains(elements[0]) + || FALSE_PACKAGE_VERSIONS.Contains(elements[1]) + || elements[1] == elements[2] + ) + { + continue; + } + + packages.Add( + new Package( + CoreTools.FormatAsName(elements[0]), + elements[0], + elements[1], + elements[2], + DefaultSource, + this + ) + ); + } + + return packages; + } + + internal IReadOnlyList ParseInstalledPackages(IEnumerable lines) + { + List packages = []; + foreach (string line in lines) + { + if (line.StartsWith("Chocolatey")) + { + continue; + } + + string[] elements = line.Split(' '); + for (int i = 0; i < elements.Length; i++) + { + elements[i] = elements[i].Trim(); + } + + if (elements.Length <= 1) + { + continue; + } + + if ( + FALSE_PACKAGE_IDS.Contains(elements[0]) + || FALSE_PACKAGE_VERSIONS.Contains(elements[1]) + ) + { + continue; + } + + packages.Add( + new Package( + CoreTools.FormatAsName(elements[0]), + elements[0], + elements[1], + DefaultSource, + this + ) + ); + } + + return packages; + } + + protected override IReadOnlyList GetAvailableUpdates_UnSafe() + { + using Process p = new() + { + StartInfo = new ProcessStartInfo + { + FileName = Status.ExecutablePath, + Arguments = Status.ExecutableCallArgs + " outdated " + GetProxyArgument(), + RedirectStandardOutput = true, + RedirectStandardError = true, + RedirectStandardInput = true, + UseShellExecute = false, + CreateNoWindow = true, + StandardOutputEncoding = OutputEncoding, + StandardErrorEncoding = OutputEncoding, + }, + }; + + IProcessTaskLogger logger = TaskLogger.CreateNew(LoggableTaskType.ListUpdates, p); + p.Start(); + RegisterListingProcess(p); + + string? line; + List lines = []; + while ((line = p.StandardOutput.ReadLine()) is not null) + { + logger.AddToStdOut(line); + lines.Add(line); + } + + logger.AddToStdErr(p.StandardError.ReadToEnd()); + p.WaitForExit(); + logger.Close(p.ExitCode); + + return ParseAvailableUpdates(lines); + } + + protected override IReadOnlyList _getInstalledPackages_UnSafe() + { + using Process p = new() + { + StartInfo = new ProcessStartInfo + { + FileName = Status.ExecutablePath, + Arguments = Status.ExecutableCallArgs + " list " + GetProxyArgument(), + RedirectStandardOutput = true, + RedirectStandardError = true, + RedirectStandardInput = true, + UseShellExecute = false, + CreateNoWindow = true, + StandardOutputEncoding = OutputEncoding, + StandardErrorEncoding = OutputEncoding, + }, + }; + + IProcessTaskLogger logger = TaskLogger.CreateNew( + LoggableTaskType.ListInstalledPackages, + p + ); + p.Start(); + RegisterListingProcess(p); + + string? line; + List lines = []; + while ((line = p.StandardOutput.ReadLine()) is not null) + { + logger.AddToStdOut(line); + lines.Add(line); + } + + logger.AddToStdErr(p.StandardError.ReadToEnd()); + p.WaitForExit(); + logger.Close(p.ExitCode); + + return ParseInstalledPackages(lines); + } + + public override IReadOnlyList FindCandidateExecutableFiles() + { + List candidates = []; + if (File.Exists(DefaultSystemChocoPath)) + { + candidates.Add(DefaultSystemChocoPath); + } + + foreach (string candidate in CoreTools.WhichMultiple("choco.exe")) + { + if (!candidates.Exists(existing => existing.Equals(candidate, StringComparison.OrdinalIgnoreCase))) + { + candidates.Add(candidate); + } + } + + return candidates; + } + + protected override void _loadManagerExecutableFile( + out bool found, + out string path, + out string callArguments + ) + { + var (_found, _path) = GetExecutableFile(); + found = _found; + path = _path; + callArguments = ""; + } + + protected override void _loadManagerVersion(out string version) + { + using Process process = new() + { + StartInfo = new ProcessStartInfo + { + FileName = Status.ExecutablePath, + Arguments = "--version " + GetProxyArgument(), + UseShellExecute = false, + RedirectStandardOutput = true, + RedirectStandardError = true, + CreateNoWindow = true, + StandardOutputEncoding = OutputEncoding, + StandardErrorEncoding = OutputEncoding, + }, + }; + process.Start(); + version = process.StandardOutput.ReadToEnd().Trim(); + } + + protected override void _performExtraLoadingSteps() + { + // Ensure the selected Chocolatey executable uses a matching installation root. + var choco_dir = + Path.GetDirectoryName(Status.ExecutablePath)?.Replace('/', '\\').Trim('\\') ?? ""; + if (choco_dir.EndsWith("bin")) + { + choco_dir = choco_dir[..^3].Trim('\\'); + } + Environment.SetEnvironmentVariable( + "chocolateyinstall", + choco_dir, + EnvironmentVariableTarget.Process + ); + } + } +} diff --git a/src/UniGetUI.PackageEngine.Managers.Chocolatey/Helpers/ChocolateyDetailsHelper.cs b/src/UniGetUI.PackageEngine.Managers.Chocolatey/Helpers/ChocolateyDetailsHelper.cs new file mode 100644 index 0000000..0a5a010 --- /dev/null +++ b/src/UniGetUI.PackageEngine.Managers.Chocolatey/Helpers/ChocolateyDetailsHelper.cs @@ -0,0 +1,115 @@ +using System.Diagnostics; +using UniGetUI.PackageEngine.Enums; +using UniGetUI.PackageEngine.Interfaces; +using UniGetUI.PackageEngine.ManagerClasses.Classes; +using UniGetUI.PackageEngine.Managers.ChocolateyManager; +using UniGetUI.PackageEngine.Managers.PowerShellManager; + +namespace UniGetUI.PackageEngine.Managers.Choco +{ + public class ChocolateyDetailsHelper : BaseNuGetDetailsHelper + { + public ChocolateyDetailsHelper(BaseNuGet manager) + : base(manager) { } + + internal static IReadOnlyList ParseInstallableVersions(IEnumerable lines) + { + List versions = []; + foreach (string line in lines) + { + if (line.Contains("[Approved]")) + { + versions.Add(line.Split(' ')[1].Trim()); + } + } + + return versions; + } + + protected override IReadOnlyList GetInstallableVersions_UnSafe(IPackage package) + { + using Process p = new() + { + StartInfo = new ProcessStartInfo + { + FileName = Manager.Status.ExecutablePath, + Arguments = + Manager.Status.ExecutableCallArgs + + $" search {package.Id} --exact --all-versions " + + Chocolatey.GetProxyArgument(), + UseShellExecute = false, + RedirectStandardOutput = true, + RedirectStandardError = true, + RedirectStandardInput = true, + CreateNoWindow = true, + StandardOutputEncoding = Manager.OutputEncoding, + StandardErrorEncoding = Manager.OutputEncoding, + }, + }; + + IProcessTaskLogger logger = Manager.TaskLogger.CreateNew( + LoggableTaskType.LoadPackageVersions, + p + ); + + p.Start(); + + string? line; + List lines = []; + while ((line = p.StandardOutput.ReadLine()) is not null) + { + logger.AddToStdOut(line); + lines.Add(line); + } + logger.AddToStdErr(p.StandardError.ReadToEnd()); + p.WaitForExit(); + logger.Close(p.ExitCode); + + return ParseInstallableVersions(lines); + } + + protected override string? GetInstallLocation_UnSafe(IPackage package) + { + string portable_path = Manager.Status.ExecutablePath.Replace( + "choco.exe", + $"bin\\{package.Id}.exe" + ); + if (File.Exists(portable_path)) + return Path.GetDirectoryName(portable_path); + + foreach ( + var base_path in new[] + { + Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles), + Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86), + Path.Join( + Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), + "Programs" + ), + Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), + } + ) + { + var path_with_id = Path.Join(base_path, package.Id); + if (Directory.Exists(path_with_id)) + return path_with_id; + } + + // Chocolatey keeps each package under \lib\. Resolve the root + // from the environment variable, falling back to the executable's folder (stepping out + // of the \bin shim folder when choco.exe is found there). + string? chocoRoot = Environment.GetEnvironmentVariable("ChocolateyInstall"); + if (string.IsNullOrEmpty(chocoRoot)) + { + var exeDir = Path.GetDirectoryName(Manager.Status.ExecutablePath); + chocoRoot = + exeDir is not null + && Path.GetFileName(exeDir).Equals("bin", StringComparison.OrdinalIgnoreCase) + ? Path.GetDirectoryName(exeDir) + : exeDir; + } + + return chocoRoot is null ? null : Path.Join(chocoRoot, "lib", package.Id); + } + } +} diff --git a/src/UniGetUI.PackageEngine.Managers.Chocolatey/Helpers/ChocolateyPkgOperationHelper.cs b/src/UniGetUI.PackageEngine.Managers.Chocolatey/Helpers/ChocolateyPkgOperationHelper.cs new file mode 100644 index 0000000..0774da6 --- /dev/null +++ b/src/UniGetUI.PackageEngine.Managers.Chocolatey/Helpers/ChocolateyPkgOperationHelper.cs @@ -0,0 +1,106 @@ +using UniGetUI.PackageEngine.Classes.Manager.BaseProviders; +using UniGetUI.PackageEngine.Enums; +using UniGetUI.PackageEngine.Interfaces; +using UniGetUI.PackageEngine.Serializable; +using Architecture = UniGetUI.PackageEngine.Enums.Architecture; + +namespace UniGetUI.PackageEngine.Managers.ChocolateyManager; + +internal sealed class ChocolateyPkgOperationHelper : BasePkgOperationHelper +{ + public ChocolateyPkgOperationHelper(Chocolatey manager) + : base(manager) { } + + protected override IReadOnlyList _getOperationParameters( + IPackage package, + InstallOptions options, + OperationType operation + ) + { + List parameters = + [ + operation switch + { + OperationType.Install => Manager.Properties.InstallVerb, + OperationType.Update => Manager.Properties.UpdateVerb, + OperationType.Uninstall => Manager.Properties.UninstallVerb, + _ => throw new InvalidDataException("Invalid package operation"), + }, + ]; + parameters.AddRange([package.Id, "-y"]); + + if (options.InteractiveInstallation) + parameters.Add("--notsilent"); + + if (operation is OperationType.Install or OperationType.Update) + { + parameters.Add("--no-progress"); + + if (options.Architecture == Architecture.x86) + parameters.Add("--forcex86"); + + if (options.PreRelease) + parameters.Add("--prerelease"); + + if (options.SkipHashCheck) + parameters.AddRange(["--ignore-checksums", "--force"]); + + if (options.Version != "") + parameters.AddRange([$"--version={options.Version}", "--allow-downgrade"]); + } + + parameters.Add(Chocolatey.GetProxyArgument()); + + parameters.AddRange( + operation switch + { + OperationType.Update => options.CustomParameters_Update, + OperationType.Uninstall => options.CustomParameters_Uninstall, + _ => options.CustomParameters_Install, + } + ); + + return parameters; + } + + protected override OperationVeredict _getOperationResult( + IPackage package, + OperationType operation, + IReadOnlyList processOutput, + int returnCode + ) + { + if (returnCode is 3010) + { + return OperationVeredict.Success; + // return OperationVeredict.RestartRequired; + } + + if (returnCode is 1641 or 1614 or 1605 or 0) + { + return OperationVeredict.Success; + } + + string output_string = string.Join("\n", processOutput); + if ( + package.OverridenOptions.RunAsAdministrator != true + && ( + output_string.Contains("Run as administrator") + || output_string.Contains("The requested operation requires elevation") + || output_string.Contains("Access to the path") + || output_string.Contains("Access denied") + || output_string.Contains("is denied") + || output_string.Contains( + "WARNING: Unable to create shortcut. Error captured was Unable to save shortcut" + ) + || output_string.Contains("access denied") + ) + ) + { + package.OverridenOptions.RunAsAdministrator = true; + return OperationVeredict.AutoRetry; + } + + return OperationVeredict.Failure; + } +} diff --git a/src/UniGetUI.PackageEngine.Managers.Chocolatey/Helpers/ChocolateySourceHelper.cs b/src/UniGetUI.PackageEngine.Managers.Chocolatey/Helpers/ChocolateySourceHelper.cs new file mode 100644 index 0000000..d12ea97 --- /dev/null +++ b/src/UniGetUI.PackageEngine.Managers.Chocolatey/Helpers/ChocolateySourceHelper.cs @@ -0,0 +1,144 @@ +using System.Diagnostics; +using UniGetUI.PackageEngine.Classes.Manager; +using UniGetUI.PackageEngine.Classes.Manager.Providers; +using UniGetUI.PackageEngine.Enums; +using UniGetUI.PackageEngine.Interfaces; +using UniGetUI.PackageEngine.ManagerClasses.Classes; + +namespace UniGetUI.PackageEngine.Managers.ChocolateyManager +{ + internal sealed class ChocolateySourceHelper : BaseSourceHelper + { + public ChocolateySourceHelper(Chocolatey manager) + : base(manager) { } + + public override string[] GetAddSourceParameters(IManagerSource source) + { + return + [ + "source", + "add", + "--name", + source.Name, + "--source", + source.Url.ToString(), + "-y", + ]; + } + + public override string[] GetRemoveSourceParameters(IManagerSource source) + { + return ["source", "remove", "--name", source.Name, "-y"]; + } + + protected override OperationVeredict _getAddSourceOperationVeredict( + IManagerSource source, + int ReturnCode, + string[] Output + ) + { + return ReturnCode == 0 ? OperationVeredict.Success : OperationVeredict.Failure; + } + + protected override OperationVeredict _getRemoveSourceOperationVeredict( + IManagerSource source, + int ReturnCode, + string[] Output + ) + { + return ReturnCode == 0 ? OperationVeredict.Success : OperationVeredict.Failure; + } + + protected override IReadOnlyList GetSources_UnSafe() + { + using Process p = new() + { + StartInfo = new() + { + FileName = Manager.Status.ExecutablePath, + Arguments = + Manager.Status.ExecutableCallArgs + + " source list " + + Chocolatey.GetProxyArgument(), + RedirectStandardOutput = true, + RedirectStandardError = true, + RedirectStandardInput = true, + UseShellExecute = false, + CreateNoWindow = true, + StandardOutputEncoding = Manager.OutputEncoding, + StandardErrorEncoding = Manager.OutputEncoding, + }, + }; + + IProcessTaskLogger logger = Manager.TaskLogger.CreateNew( + LoggableTaskType.ListSources, + p + ); + p.Start(); + + string? line; + List lines = []; + while ((line = p.StandardOutput.ReadLine()) is not null) + { + logger.AddToStdOut(line); + lines.Add(line); + } + + logger.AddToStdErr(p.StandardError.ReadToEnd()); + p.WaitForExit(); + logger.Close(p.ExitCode); + + return ParseSources(lines); + } + + internal IReadOnlyList ParseSources(IEnumerable lines) + { + List sources = []; + + foreach (string line in lines) + { + try + { + if (string.IsNullOrEmpty(line)) + { + continue; + } + + if (line.Contains(" - ") && line.Contains("| ")) + { + string[] parts = line.Trim().Split('|')[0].Trim().Split(" - "); + if ( + parts[1].Trim() == "https://community.chocolatey.org/api/v2/" + || parts[1].Trim() == "https://chocolatey.org/api/v2/" + ) + { + sources.Add( + new ManagerSource( + Manager, + "community", + new Uri("https://community.chocolatey.org/api/v2/") + ) + ); + } + else + { + sources.Add( + new ManagerSource( + Manager, + parts[0].Trim(), + new Uri(parts[1].Split(" ")[0].Trim()) + ) + ); + } + } + } + catch + { + continue; + } + } + + return sources; + } + } +} diff --git a/src/UniGetUI.PackageEngine.Managers.Chocolatey/InternalsVisibleTo.cs b/src/UniGetUI.PackageEngine.Managers.Chocolatey/InternalsVisibleTo.cs new file mode 100644 index 0000000..eeb63da --- /dev/null +++ b/src/UniGetUI.PackageEngine.Managers.Chocolatey/InternalsVisibleTo.cs @@ -0,0 +1,3 @@ +using System.Runtime.CompilerServices; + +[assembly: InternalsVisibleTo("UniGetUI.PackageEngine.Tests")] diff --git a/src/UniGetUI.PackageEngine.Managers.Chocolatey/UniGetUI.PackageEngine.Managers.Chocolatey.csproj b/src/UniGetUI.PackageEngine.Managers.Chocolatey/UniGetUI.PackageEngine.Managers.Chocolatey.csproj new file mode 100644 index 0000000..a6c0b04 --- /dev/null +++ b/src/UniGetUI.PackageEngine.Managers.Chocolatey/UniGetUI.PackageEngine.Managers.Chocolatey.csproj @@ -0,0 +1,29 @@ + + + $(WindowsTargetFramework) + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/UniGetUI.PackageEngine.Managers.Dnf/Dnf.cs b/src/UniGetUI.PackageEngine.Managers.Dnf/Dnf.cs new file mode 100644 index 0000000..4192ad6 --- /dev/null +++ b/src/UniGetUI.PackageEngine.Managers.Dnf/Dnf.cs @@ -0,0 +1,303 @@ +using System.Diagnostics; +using UniGetUI.Core.Tools; +using UniGetUI.Interface.Enums; +using UniGetUI.PackageEngine.Classes.Manager; +using UniGetUI.PackageEngine.Classes.Manager.ManagerHelpers; +using UniGetUI.PackageEngine.Enums; +using UniGetUI.PackageEngine.Interfaces; +using UniGetUI.PackageEngine.ManagerClasses.Classes; +using UniGetUI.PackageEngine.ManagerClasses.Manager; +using UniGetUI.PackageEngine.PackageClasses; +using UniGetUI.PackageEngine.Structs; + +namespace UniGetUI.PackageEngine.Managers.DnfManager; + +public class Dnf : PackageManager +{ + // Known RPM architectures — used to strip the trailing . from package names. + private static readonly HashSet _knownArches = + ["x86_64", "aarch64", "noarch", "i686", "i386", "ppc64le", "s390x", "src"]; + + public Dnf() + { + Dependencies = []; + + Capabilities = new ManagerCapabilities + { + CanRunAsAdmin = true, + CanSkipIntegrityChecks = true, + SupportsCustomSources = false, + SupportsProxy = ProxySupport.No, + SupportsProxyAuth = false, + KnowsPackageReleaseDate = PackageReleaseDateSupport.No, + }; + + Properties = new ManagerProperties + { + Id = "dnf", + Name = "Dnf", + Description = CoreTools.Translate( + "The default package manager for RHEL/Fedora-based Linux distributions.
Contains: RPM packages" + ), + IconId = IconType.Dnf, + ColorIconId = "dnf", + ExecutableFriendlyName = "dnf", + InstallVerb = "install", + UpdateVerb = "upgrade", + UninstallVerb = "remove", + DefaultSource = new ManagerSource(this, "dnf", new Uri("https://fedoraproject.org/wiki/DNF")), + KnownSources = [new ManagerSource(this, "dnf", new Uri("https://fedoraproject.org/wiki/DNF"))], + }; + + DetailsHelper = new DnfPkgDetailsHelper(this); + OperationHelper = new DnfPkgOperationHelper(this); + } + + // ── Executable discovery ─────────────────────────────────────────────── + + public override IReadOnlyList FindCandidateExecutableFiles() + { + var candidates = new List(CoreTools.WhichMultiple("dnf5")); + foreach (var path in CoreTools.WhichMultiple("dnf")) + { + if (!candidates.Contains(path)) + candidates.Add(path); + } + foreach (var path in new[] { "/usr/bin/dnf5", "/usr/bin/dnf", "/usr/local/bin/dnf" }) + { + if (File.Exists(path) && !candidates.Contains(path)) + candidates.Add(path); + } + return candidates; + } + + protected override void _loadManagerExecutableFile( + out bool found, + out string path, + out string callArguments) + { + (found, path) = GetExecutableFile(); + callArguments = ""; + } + + protected override void _loadManagerVersion(out string version) + { + using var p = new Process + { + StartInfo = new ProcessStartInfo + { + FileName = Status.ExecutablePath, + Arguments = "--version", + UseShellExecute = false, + RedirectStandardOutput = true, + RedirectStandardError = true, + CreateNoWindow = true, + }, + }; + p.Start(); + // First line is the version number: "X.Y.Z" + version = p.StandardOutput.ReadLine()?.Trim() ?? ""; + p.StandardOutput.ReadToEnd(); + p.StandardError.ReadToEnd(); + p.WaitForExit(); + } + + // ── Index refresh ────────────────────────────────────────────────────── + + public override void RefreshPackageIndexes() + { + using var p = new Process + { + StartInfo = new ProcessStartInfo + { + FileName = Status.ExecutablePath, + Arguments = "makecache", + UseShellExecute = false, + RedirectStandardOutput = true, + RedirectStandardError = true, + CreateNoWindow = true, + }, + }; + IProcessTaskLogger logger = TaskLogger.CreateNew(LoggableTaskType.RefreshIndexes, p); + p.Start(); + logger.AddToStdOut(p.StandardOutput.ReadToEnd()); + logger.AddToStdErr(p.StandardError.ReadToEnd()); + p.WaitForExit(); + logger.Close(p.ExitCode); + } + + // ── Package listing ──────────────────────────────────────────────────── + + protected override IReadOnlyList FindPackages_UnSafe(string query) + { + var packages = new List(); + + using var p = new Process + { + StartInfo = new ProcessStartInfo + { + FileName = Status.ExecutablePath, + Arguments = $"search --quiet {query}", + UseShellExecute = false, + RedirectStandardOutput = true, + RedirectStandardError = true, + CreateNoWindow = true, + }, + }; + IProcessTaskLogger logger = TaskLogger.CreateNew(LoggableTaskType.FindPackages, p); + p.Start(); + + // Output: ". : " + // Section headers look like "===== Name Matched: =====" — skip them. + var seen = new HashSet(StringComparer.Ordinal); + string? line; + while ((line = p.StandardOutput.ReadLine()) is not null) + { + logger.AddToStdOut(line); + if (line.StartsWith('=') || line.Length == 0) continue; + + var colonIdx = line.IndexOf(" : ", StringComparison.Ordinal); + if (colonIdx <= 0) continue; + + var nameArch = line[..colonIdx].Trim(); + var id = StripArch(nameArch); + if (id.Length == 0 || !seen.Add(id)) continue; + + packages.Add(new Package( + CoreTools.FormatAsName(id), + id, + CoreTools.Translate("Latest"), + Properties.DefaultSource!, + this)); + } + + logger.AddToStdErr(p.StandardError.ReadToEnd()); + p.WaitForExit(); + // dnf search exits 1 when no packages match the query — not an error + logger.Close(p.ExitCode == 1 && packages.Count == 0 ? 0 : p.ExitCode); + return packages; + } + + protected override IReadOnlyList GetInstalledPackages_UnSafe() + { + var packages = new List(); + + using var p = new Process + { + StartInfo = new ProcessStartInfo + { + FileName = Status.ExecutablePath, + Arguments = "list --installed", + UseShellExecute = false, + RedirectStandardOutput = true, + RedirectStandardError = true, + CreateNoWindow = true, + }, + }; + IProcessTaskLogger logger = TaskLogger.CreateNew(LoggableTaskType.ListInstalledPackages, p); + p.Start(); + + // Output: ". - <@repo>" + // Skip header/metadata lines (e.g. "Installed Packages", + // "Last metadata expiration check: ...") by requiring a known arch suffix. + string? line; + while ((line = p.StandardOutput.ReadLine()) is not null) + { + logger.AddToStdOut(line); + var parts = line.Split((char[]?)null, StringSplitOptions.RemoveEmptyEntries); + if (parts.Length < 2 || !IsPackageLine(parts[0])) continue; + + var id = StripArch(parts[0]); + var version = parts[1]; + packages.Add(new Package( + CoreTools.FormatAsName(id), + id, + version, + Properties.DefaultSource!, + this)); + } + + logger.AddToStdErr(p.StandardError.ReadToEnd()); + p.WaitForExit(); + logger.Close(p.ExitCode); + return packages; + } + + protected override IReadOnlyList GetAvailableUpdates_UnSafe() + { + var packages = new List(); + + using var p = new Process + { + StartInfo = new ProcessStartInfo + { + FileName = Status.ExecutablePath, + Arguments = "list --upgrades", + UseShellExecute = false, + RedirectStandardOutput = true, + RedirectStandardError = true, + CreateNoWindow = true, + }, + }; + // Build lookup before starting the process — reading from its pipe + // while a second process runs risks filling the pipe buffer and deadlocking. + Dictionary installed = []; + foreach (var pkg in GetInstalledPackages_UnSafe()) + installed.TryAdd(pkg.Id, pkg.VersionString); + + IProcessTaskLogger logger = TaskLogger.CreateNew(LoggableTaskType.ListUpdates, p); + p.Start(); + + // Output: ". - " + // Skip header/metadata lines (e.g. "Available Upgrades", + // "Last metadata expiration check: ...") by requiring a known arch suffix. + string? line; + while ((line = p.StandardOutput.ReadLine()) is not null) + { + logger.AddToStdOut(line); + var parts = line.Split((char[]?)null, StringSplitOptions.RemoveEmptyEntries); + if (parts.Length < 2 || !IsPackageLine(parts[0])) continue; + + var id = StripArch(parts[0]); + var newVersion = parts[1]; + installed.TryGetValue(id, out var oldVersion); + packages.Add(new Package( + CoreTools.FormatAsName(id), + id, + oldVersion ?? "", + newVersion, + Properties.DefaultSource!, + this)); + } + + logger.AddToStdErr(p.StandardError.ReadToEnd()); + p.WaitForExit(); + logger.Close(p.ExitCode); + return packages; + } + + // ── Helpers ──────────────────────────────────────────────────────────── + + /// + /// Strips the trailing . from a DNF package token (e.g. "vim.x86_64" → "vim"). + /// Package names that do not end in a known arch are returned unchanged. + /// + internal static string StripArch(string nameArch) + { + var dot = nameArch.LastIndexOf('.'); + if (dot > 0 && _knownArches.Contains(nameArch[(dot + 1)..])) + return nameArch[..dot]; + return nameArch; + } + + /// + /// Returns true when looks like a DNF package entry + /// (i.e. ends in a known architecture suffix such as ".x86_64" or ".noarch"). + /// Used to skip header/metadata lines in dnf list output. + /// + private static bool IsPackageLine(string token) + { + var dot = token.LastIndexOf('.'); + return dot > 0 && _knownArches.Contains(token[(dot + 1)..]); + } +} diff --git a/src/UniGetUI.PackageEngine.Managers.Dnf/Helpers/DnfPkgDetailsHelper.cs b/src/UniGetUI.PackageEngine.Managers.Dnf/Helpers/DnfPkgDetailsHelper.cs new file mode 100644 index 0000000..b862ff3 --- /dev/null +++ b/src/UniGetUI.PackageEngine.Managers.Dnf/Helpers/DnfPkgDetailsHelper.cs @@ -0,0 +1,161 @@ +using System.Diagnostics; +using UniGetUI.Core.IconEngine; +using UniGetUI.PackageEngine.Classes.Manager.BaseProviders; +using UniGetUI.PackageEngine.Enums; +using UniGetUI.PackageEngine.Interfaces; +using UniGetUI.PackageEngine.ManagerClasses.Classes; + +namespace UniGetUI.PackageEngine.Managers.DnfManager; + +internal sealed class DnfPkgDetailsHelper : BasePkgDetailsHelper +{ + public DnfPkgDetailsHelper(Dnf manager) + : base(manager) { } + + protected override void GetDetails_UnSafe(IPackageDetails details) + { + using var p = new Process + { + StartInfo = new ProcessStartInfo + { + FileName = Manager.Status.ExecutablePath, + Arguments = $"info {details.Package.Id}", + UseShellExecute = false, + RedirectStandardOutput = true, + RedirectStandardError = true, + CreateNoWindow = true, + }, + }; + + p.StartInfo.Environment["LANG"] = "C"; + p.StartInfo.Environment["LC_ALL"] = "C"; + IProcessTaskLogger logger = Manager.TaskLogger.CreateNew( + LoggableTaskType.LoadPackageDetails, p); + p.Start(); + + // dnf info outputs "Key : value" pairs. + // Multi-line Description values are indented. + var descLines = new List(); + bool inDescription = false; + + string? line; + while ((line = p.StandardOutput.ReadLine()) is not null) + { + logger.AddToStdOut(line); + + // Blank line marks the end of a package block. dnf info can output multiple + // blocks (e.g. "Installed Packages" then "Available Packages") — stop after + // the first so the second block doesn't silently overwrite parsed fields. + if (line.Length == 0) break; + + // Continuation lines for Description are indented with " : " prefix: + // " : second line of the description" + if (inDescription && line.StartsWith(' ')) + { + var contColon = line.IndexOf(" : ", StringComparison.Ordinal); + descLines.Add(contColon >= 0 ? line[(contColon + 3)..].Trim() : line.Trim()); + continue; + } + + inDescription = false; + + var colonIdx = line.IndexOf(" : ", StringComparison.Ordinal); + if (colonIdx <= 0) continue; + + var key = line[..colonIdx].Trim(); + var value = line[(colonIdx + 3)..].Trim(); + + switch (key) + { + case "URL": + if (Uri.TryCreate(value, UriKind.Absolute, out var url)) + details.HomepageUrl = url; + break; + case "Summary": + details.Description = value; + break; + case "Description": + descLines.Add(value); + inDescription = true; + break; + case "License": + details.License = value; + break; + case "Packager": + details.Publisher = value; + break; + case "Size": + // e.g. "1.5 M" or "234 k" + details.InstallerSize = ParseDnfSize(value); + break; + } + } + + if (descLines.Count > 0) + details.Description = string.Join("\n", descLines); + + logger.AddToStdErr(p.StandardError.ReadToEnd()); + p.WaitForExit(); + logger.Close(p.ExitCode); + } + + protected override CacheableIcon? GetIcon_UnSafe(IPackage package) + => throw new NotImplementedException(); + + protected override IReadOnlyList GetScreenshots_UnSafe(IPackage package) + => throw new NotImplementedException(); + + protected override string? GetInstallLocation_UnSafe(IPackage package) + { + using var p = new Process + { + StartInfo = new ProcessStartInfo + { + FileName = "rpm", + Arguments = $"-ql {package.Id}", + UseShellExecute = false, + RedirectStandardOutput = true, + RedirectStandardError = true, + CreateNoWindow = true, + }, + }; + p.Start(); + + // Must drain all stdout before WaitForExit — packages like glibc have thousands + // of file entries and will fill the pipe buffer, causing a deadlock. + string? result = null; + string? line; + while ((line = p.StandardOutput.ReadLine()) is not null) + { + if (result is not null) continue; + var path = line.Trim(); + if (Directory.Exists(path)) + result = path; + } + + p.StandardError.ReadToEnd(); + p.WaitForExit(); + return result; + } + + protected override IReadOnlyList GetInstallableVersions_UnSafe(IPackage package) + => throw new InvalidOperationException("DNF does not support installing arbitrary versions"); + + private static long ParseDnfSize(string value) + { + // Format: "1.5 M", "234 k", "56 G" + var parts = value.Split(' ', StringSplitOptions.RemoveEmptyEntries); + if (parts.Length < 2 || !double.TryParse(parts[0], + System.Globalization.NumberStyles.Any, + System.Globalization.CultureInfo.InvariantCulture, out var num)) + return 0; + + return parts[1].ToUpperInvariant() switch + { + "K" => (long)(num * 1024), + "M" => (long)(num * 1024 * 1024), + "G" => (long)(num * 1024 * 1024 * 1024), + _ => (long)num, + }; + } +} diff --git a/src/UniGetUI.PackageEngine.Managers.Dnf/Helpers/DnfPkgOperationHelper.cs b/src/UniGetUI.PackageEngine.Managers.Dnf/Helpers/DnfPkgOperationHelper.cs new file mode 100644 index 0000000..4df6cf8 --- /dev/null +++ b/src/UniGetUI.PackageEngine.Managers.Dnf/Helpers/DnfPkgOperationHelper.cs @@ -0,0 +1,56 @@ +using UniGetUI.PackageEngine.Classes.Manager.BaseProviders; +using UniGetUI.PackageEngine.Enums; +using UniGetUI.PackageEngine.Interfaces; +using UniGetUI.PackageEngine.Serializable; + +namespace UniGetUI.PackageEngine.Managers.DnfManager; + +internal sealed class DnfPkgOperationHelper : BasePkgOperationHelper +{ + public DnfPkgOperationHelper(Dnf manager) + : base(manager) { } + + protected override IReadOnlyList _getOperationParameters( + IPackage package, + InstallOptions options, + OperationType operation) + { + // dnf always requires root — force elevation via InstallOptions (reference type, persists) + options.RunAsAdministrator = true; + + List parameters = + [ + operation switch + { + OperationType.Install => Manager.Properties.InstallVerb, + OperationType.Update => Manager.Properties.UpdateVerb, + OperationType.Uninstall => Manager.Properties.UninstallVerb, + _ => throw new InvalidDataException("Invalid package operation"), + }, + "-y", + package.Id, + ]; + + if (options.SkipHashCheck) + parameters.Add("--nogpgcheck"); + + parameters.AddRange( + operation switch + { + OperationType.Update => options.CustomParameters_Update, + OperationType.Uninstall => options.CustomParameters_Uninstall, + _ => options.CustomParameters_Install, + }); + + return parameters; + } + + protected override OperationVeredict _getOperationResult( + IPackage package, + OperationType operation, + IReadOnlyList processOutput, + int returnCode) + { + return returnCode == 0 ? OperationVeredict.Success : OperationVeredict.Failure; + } +} diff --git a/src/UniGetUI.PackageEngine.Managers.Dnf/UniGetUI.PackageEngine.Managers.Dnf.csproj b/src/UniGetUI.PackageEngine.Managers.Dnf/UniGetUI.PackageEngine.Managers.Dnf.csproj new file mode 100644 index 0000000..a0903da --- /dev/null +++ b/src/UniGetUI.PackageEngine.Managers.Dnf/UniGetUI.PackageEngine.Managers.Dnf.csproj @@ -0,0 +1,23 @@ + + + $(SharedTargetFrameworks) + + + + + + + + + + + + + + + + + + + + diff --git a/src/UniGetUI.PackageEngine.Managers.Dotnet/DotNet.cs b/src/UniGetUI.PackageEngine.Managers.Dotnet/DotNet.cs new file mode 100644 index 0000000..51c8b9e --- /dev/null +++ b/src/UniGetUI.PackageEngine.Managers.Dotnet/DotNet.cs @@ -0,0 +1,238 @@ +using System.Diagnostics; +using System.Text.RegularExpressions; +using UniGetUI.Core.Tools; +using UniGetUI.Interface.Enums; +using UniGetUI.PackageEngine.Classes.Manager; +using UniGetUI.PackageEngine.Classes.Manager.ManagerHelpers; +using UniGetUI.PackageEngine.Enums; +using UniGetUI.PackageEngine.Interfaces; +using UniGetUI.PackageEngine.ManagerClasses.Classes; +using UniGetUI.PackageEngine.ManagerClasses.Manager; +using UniGetUI.PackageEngine.Managers.Chocolatey; +using UniGetUI.PackageEngine.Managers.PowerShellManager; +using UniGetUI.PackageEngine.PackageClasses; +using UniGetUI.PackageEngine.Structs; +using Architecture = UniGetUI.PackageEngine.Enums.Architecture; + +namespace UniGetUI.PackageEngine.Managers.DotNetManager +{ + public class DotNet : BaseNuGet + { + public static string[] FALSE_PACKAGE_IDS = [""]; + public static string[] FALSE_PACKAGE_VERSIONS = [""]; + + public DotNet() + { + Capabilities = new ManagerCapabilities + { + CanRunAsAdmin = true, + CanDownloadInstaller = true, + SupportsCustomScopes = true, + SupportsCustomArchitectures = true, + SupportedCustomArchitectures = + [ + Architecture.x86, + Architecture.x64, + Architecture.arm64, + Architecture.arm32, + ], + SupportsPreRelease = true, + CanListDependencies = true, + SupportsCustomLocations = true, + SupportsCustomPackageIcons = true, + SupportsCustomVersions = true, + SupportsProxy = ProxySupport.Partially, + SupportsProxyAuth = true, + KnowsPackageReleaseDate = PackageReleaseDateSupport.Yes, + }; + + Properties = new ManagerProperties + { + Id = "dotnet-tool", + Name = ".NET Tool", + Description = CoreTools.Translate( + "A repository full of tools and executables designed with Microsoft's .NET ecosystem in mind.
Contains: .NET related tools and scripts" + ), + IconId = IconType.DotNet, + ColorIconId = "dotnet_color", + ExecutableFriendlyName = "dotnet tool", + InstallVerb = "install", + UninstallVerb = "uninstall", + UpdateVerb = "update", + DefaultSource = new ManagerSource( + this, + "nuget.org", + new Uri("https://www.nuget.org/api/v2") + ), + KnownSources = + [ + new ManagerSource(this, "nuget.org", new Uri("https://www.nuget.org/api/v2")), + ], + }; + + DetailsHelper = new DotNetDetailsHelper(this); + OperationHelper = new DotNetPkgOperationHelper(this); + } + + protected override IReadOnlyList _getInstalledPackages_UnSafe() + { + List Packages = []; + foreach ( + var options in new OverridenInstallationOptions[] + { + new(PackageScope.Local), + new(PackageScope.Global), + } + ) + { + using Process p = new() + { + StartInfo = new ProcessStartInfo + { + FileName = Status.ExecutablePath, + Arguments = + Status.ExecutableCallArgs + + " list" + + (options.Scope == PackageScope.Global ? " --global" : ""), + RedirectStandardOutput = true, + RedirectStandardError = true, + UseShellExecute = false, + CreateNoWindow = true, + StandardOutputEncoding = System.Text.Encoding.UTF8, + }, + }; + + IProcessTaskLogger logger = TaskLogger.CreateNew( + LoggableTaskType.ListInstalledPackages, + p + ); + p.Start(); + + List outputLines = []; + string? line; + while ((line = p.StandardOutput.ReadLine()) is not null) + { + logger.AddToStdOut(line); + outputLines.Add(line); + } + logger.AddToStdErr(p.StandardError.ReadToEnd()); + p.WaitForExit(); + logger.Close(p.ExitCode); + + Packages.AddRange(ParseInstalledPackages(outputLines, DefaultSource, this, options)); + } + return Packages; + } + + public override IReadOnlyList FindCandidateExecutableFiles() => + CoreTools.WhichMultiple(OperatingSystem.IsWindows() ? "dotnet.exe" : "dotnet"); + + protected override void _loadManagerExecutableFile( + out bool found, + out string path, + out string callArguments + ) + { + var (_found, _path) = GetExecutableFile(); + found = _found; + path = _path; + callArguments = "tool "; + + // Ensure .NET SDK is installed + if (!found) + return; + var process = new Process() + { + StartInfo = new ProcessStartInfo + { + FileName = path, + Arguments = callArguments + "-h", + UseShellExecute = false, + RedirectStandardOutput = true, + RedirectStandardError = true, + CreateNoWindow = true, + StandardOutputEncoding = System.Text.Encoding.UTF8, + }, + }; + process.Start(); + process.WaitForExit(); + found = process.ExitCode is 0; + } + + protected override void _loadManagerVersion(out string version) + { + var process = new Process() + { + StartInfo = new ProcessStartInfo + { + FileName = Status.ExecutablePath, + Arguments = "--version", + UseShellExecute = false, + RedirectStandardOutput = true, + RedirectStandardError = true, + CreateNoWindow = true, + StandardOutputEncoding = System.Text.Encoding.UTF8, + }, + }; + + process.Start(); + version = process.StandardOutput.ReadToEnd().Trim(); + } + + internal static IReadOnlyList ParseInstalledPackages( + IEnumerable outputLines, + IManagerSource source, + IPackageManager manager, + OverridenInstallationOptions options + ) + { + List packages = []; + bool dashesPassed = false; + + foreach (string rawLine in outputLines) + { + if (!dashesPassed) + { + if (rawLine.Contains("----")) + { + dashesPassed = true; + } + + continue; + } + + string[] elements = Regex.Replace(rawLine, " {2,}", " ").Split(' '); + if (elements.Length < 2) + { + continue; + } + + for (int i = 0; i < elements.Length; i++) + { + elements[i] = elements[i].Trim(); + } + + if ( + FALSE_PACKAGE_IDS.Contains(elements[0]) + || FALSE_PACKAGE_VERSIONS.Contains(elements[1]) + ) + { + continue; + } + + packages.Add( + new Package( + CoreTools.FormatAsName(elements[0]), + elements[0], + elements[1], + source, + manager, + options + ) + ); + } + + return packages; + } + } +} diff --git a/src/UniGetUI.PackageEngine.Managers.Dotnet/Helpers/DotNetDetailsHelper.cs b/src/UniGetUI.PackageEngine.Managers.Dotnet/Helpers/DotNetDetailsHelper.cs new file mode 100644 index 0000000..779bf51 --- /dev/null +++ b/src/UniGetUI.PackageEngine.Managers.Dotnet/Helpers/DotNetDetailsHelper.cs @@ -0,0 +1,20 @@ +using UniGetUI.PackageEngine.Interfaces; +using UniGetUI.PackageEngine.Managers.PowerShellManager; + +namespace UniGetUI.PackageEngine.Managers.Chocolatey +{ + public class DotNetDetailsHelper : BaseNuGetDetailsHelper + { + public DotNetDetailsHelper(BaseNuGet manager) + : base(manager) { } + + protected override string? GetInstallLocation_UnSafe(IPackage package) + { + return Path.Join( + Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), + ".dotnet", + "tools" + ); + } + } +} diff --git a/src/UniGetUI.PackageEngine.Managers.Dotnet/Helpers/DotNetPkgOperationHelper.cs b/src/UniGetUI.PackageEngine.Managers.Dotnet/Helpers/DotNetPkgOperationHelper.cs new file mode 100644 index 0000000..0c9e7c8 --- /dev/null +++ b/src/UniGetUI.PackageEngine.Managers.Dotnet/Helpers/DotNetPkgOperationHelper.cs @@ -0,0 +1,93 @@ +using UniGetUI.PackageEngine.Classes.Manager.BaseProviders; +using UniGetUI.PackageEngine.Enums; +using UniGetUI.PackageEngine.Interfaces; +using UniGetUI.PackageEngine.Serializable; +using Architecture = UniGetUI.PackageEngine.Enums.Architecture; + +namespace UniGetUI.PackageEngine.Managers.DotNetManager; + +internal sealed class DotNetPkgOperationHelper : BasePkgOperationHelper +{ + public DotNetPkgOperationHelper(DotNet manager) + : base(manager) { } + + protected override IReadOnlyList _getOperationParameters( + IPackage package, + InstallOptions options, + OperationType operation + ) + { + List parameters = + [ + operation switch + { + OperationType.Install => Manager.Properties.InstallVerb, + OperationType.Update => Manager.Properties.UpdateVerb, + OperationType.Uninstall => Manager.Properties.UninstallVerb, + _ => throw new InvalidDataException("Invalid package operation"), + }, + package.Id, + ]; + + if (options.CustomInstallLocation != "") + parameters.AddRange(["--tool-path", "\"" + options.CustomInstallLocation + "\""]); + + if ( + package.OverridenOptions.Scope is PackageScope.Global + || ( + package.OverridenOptions.Scope is null + && options.InstallationScope is PackageScope.Global + ) + ) + parameters.Add("--global"); + + if (operation is OperationType.Install or OperationType.Update) + { + parameters.AddRange( + options.Architecture switch + { + Architecture.x86 => ["--arch", "x86"], + Architecture.x64 => ["--arch", "x64"], + Architecture.arm32 => ["--arch", "arm32"], + Architecture.arm64 => ["--arch", "arm64"], + _ => [], + } + ); + } + + if (operation is OperationType.Install or OperationType.Update) + { + if (options.Version != "") + { + parameters.AddRange(["--version", options.Version]); + } + } + + parameters.AddRange( + operation switch + { + OperationType.Update => options.CustomParameters_Update, + OperationType.Uninstall => options.CustomParameters_Uninstall, + _ => options.CustomParameters_Install, + } + ); + + return parameters; + } + + protected override OperationVeredict _getOperationResult( + IPackage package, + OperationType operation, + IReadOnlyList processOutput, + int returnCode + ) + { + if (returnCode is not 0 && package.OverridenOptions.Scope is not PackageScope.Global) + { + package.OverridenOptions.Scope = PackageScope.Global; + return OperationVeredict.AutoRetry; + } + + return returnCode is 0 ? OperationVeredict.Success : OperationVeredict.Failure; + } +} diff --git a/src/UniGetUI.PackageEngine.Managers.Dotnet/InternalsVisibleTo.cs b/src/UniGetUI.PackageEngine.Managers.Dotnet/InternalsVisibleTo.cs new file mode 100644 index 0000000..eeb63da --- /dev/null +++ b/src/UniGetUI.PackageEngine.Managers.Dotnet/InternalsVisibleTo.cs @@ -0,0 +1,3 @@ +using System.Runtime.CompilerServices; + +[assembly: InternalsVisibleTo("UniGetUI.PackageEngine.Tests")] diff --git a/src/UniGetUI.PackageEngine.Managers.Dotnet/UniGetUI.PackageEngine.Managers.Dotnet.csproj b/src/UniGetUI.PackageEngine.Managers.Dotnet/UniGetUI.PackageEngine.Managers.Dotnet.csproj new file mode 100644 index 0000000..d702841 --- /dev/null +++ b/src/UniGetUI.PackageEngine.Managers.Dotnet/UniGetUI.PackageEngine.Managers.Dotnet.csproj @@ -0,0 +1,28 @@ + + + $(SharedTargetFrameworks) + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/UniGetUI.PackageEngine.Managers.Flatpak/Flatpak.cs b/src/UniGetUI.PackageEngine.Managers.Flatpak/Flatpak.cs new file mode 100644 index 0000000..40a0e68 --- /dev/null +++ b/src/UniGetUI.PackageEngine.Managers.Flatpak/Flatpak.cs @@ -0,0 +1,226 @@ +using System.Diagnostics; +using UniGetUI.Core.Tools; +using UniGetUI.Interface.Enums; +using UniGetUI.PackageEngine.Classes.Manager; +using UniGetUI.PackageEngine.Enums; +using UniGetUI.PackageEngine.ManagerClasses.Classes; +using UniGetUI.PackageEngine.ManagerClasses.Manager; +using UniGetUI.PackageEngine.PackageClasses; + +namespace UniGetUI.PackageEngine.Managers.FlatpakManager; + +public partial class Flatpak : PackageManager +{ + private static readonly string[] FLATPAK_PATHS = + [ + "/usr/bin/flatpak", + "/usr/local/bin/flatpak", + ]; + + public Flatpak() + { + Dependencies = []; + + var flathubSource = new ManagerSource(this, "flathub", new Uri("https://dl.flathub.org/repo/")); + + Capabilities = new ManagerCapabilities + { + CanRunAsAdmin = true, + CanSkipIntegrityChecks = true, + SupportsCustomSources = true, + Sources = new SourceCapabilities + { + KnowsPackageCount = false, + KnowsUpdateDate = false, + }, + SupportsProxy = ProxySupport.No, + SupportsProxyAuth = false, + KnowsPackageReleaseDate = PackageReleaseDateSupport.No, + }; + + Properties = new ManagerProperties + { + Id = "flatpak", + Name = "Flatpak", + Description = CoreTools.Translate( + "The universal Linux package manager for desktop applications.
Contains: Flatpak applications from configured remotes" + ), + IconId = IconType.Flatpak, + ColorIconId = "flatpak", + ExecutableFriendlyName = "flatpak", + InstallVerb = "install", + UpdateVerb = "update", + UninstallVerb = "uninstall", + DefaultSource = flathubSource, + KnownSources = [flathubSource], + }; + + SourcesHelper = new FlatpakSourceHelper(this); + DetailsHelper = new FlatpakPkgDetailsHelper(this); + OperationHelper = new FlatpakPkgOperationHelper(this); + } + + public override IReadOnlyList FindCandidateExecutableFiles() + { + var candidates = new List(CoreTools.WhichMultiple("flatpak")); + foreach (var path in FLATPAK_PATHS) + { + if (File.Exists(path) && !candidates.Contains(path)) + candidates.Add(path); + } + return candidates; + } + + protected override void _loadManagerExecutableFile( + out bool found, + out string path, + out string callArguments) + { + (found, path) = GetExecutableFile(); + callArguments = ""; + } + + protected override void _loadManagerVersion(out string version) + { + using var p = new Process + { + StartInfo = new ProcessStartInfo + { + FileName = Status.ExecutablePath, + Arguments = "--version", + UseShellExecute = false, + RedirectStandardOutput = true, + RedirectStandardError = true, + CreateNoWindow = true, + }, + }; + p.Start(); + var line = p.StandardOutput.ReadLine()?.Trim() ?? ""; + version = line.Replace("Flatpak ", "").Trim(); + p.StandardError.ReadToEnd(); + p.WaitForExit(); + } + + public override void RefreshPackageIndexes() + { + using var p = new Process + { + StartInfo = new ProcessStartInfo + { + FileName = Status.ExecutablePath, + Arguments = "update --appstream", + UseShellExecute = false, + RedirectStandardOutput = true, + RedirectStandardError = true, + CreateNoWindow = true, + }, + }; + IProcessTaskLogger logger = TaskLogger.CreateNew(LoggableTaskType.RefreshIndexes, p); + p.Start(); + logger.AddToStdOut(p.StandardOutput.ReadToEnd()); + logger.AddToStdErr(p.StandardError.ReadToEnd()); + p.WaitForExit(); + logger.Close(p.ExitCode); + } + + protected override IReadOnlyList FindPackages_UnSafe(string query) + { + using var p = new Process + { + StartInfo = new ProcessStartInfo + { + FileName = Status.ExecutablePath, + Arguments = $"search {CoreTools.EnsureSafeQueryString(query)}", + UseShellExecute = false, + RedirectStandardOutput = true, + RedirectStandardError = true, + CreateNoWindow = true, + }, + }; + p.StartInfo.Environment["LANG"] = "C"; + p.StartInfo.Environment["LC_ALL"] = "C"; + IProcessTaskLogger logger = TaskLogger.CreateNew(LoggableTaskType.FindPackages, p); + p.Start(); + + List outputLines = []; + while (p.StandardOutput.ReadLine() is { } line) + { + logger.AddToStdOut(line); + outputLines.Add(line); + } + + logger.AddToStdErr(p.StandardError.ReadToEnd()); + p.WaitForExit(); + logger.Close(p.ExitCode); + + return ParseSearchResults(outputLines, DefaultSource, this); + } + + protected override IReadOnlyList GetInstalledPackages_UnSafe() + { + using var p = new Process + { + StartInfo = new ProcessStartInfo + { + FileName = Status.ExecutablePath, + Arguments = "list --app --columns=application,version,branch,origin,name", + UseShellExecute = false, + RedirectStandardOutput = true, + RedirectStandardError = true, + CreateNoWindow = true, + }, + }; + p.StartInfo.Environment["LANG"] = "C"; + p.StartInfo.Environment["LC_ALL"] = "C"; + IProcessTaskLogger logger = TaskLogger.CreateNew(LoggableTaskType.ListInstalledPackages, p); + p.Start(); + + List outputLines = []; + while (p.StandardOutput.ReadLine() is { } line) + { + logger.AddToStdOut(line); + outputLines.Add(line); + } + + logger.AddToStdErr(p.StandardError.ReadToEnd()); + p.WaitForExit(); + logger.Close(p.ExitCode); + + return ParseInstalledPackages(outputLines, DefaultSource, this); + } + + protected override IReadOnlyList GetAvailableUpdates_UnSafe() + { + using var p = new Process + { + StartInfo = new ProcessStartInfo + { + FileName = Status.ExecutablePath, + Arguments = "remote-ls --updates --columns=application,version,branch,origin,name", + UseShellExecute = false, + RedirectStandardOutput = true, + RedirectStandardError = true, + CreateNoWindow = true, + }, + }; + + p.StartInfo.Environment["LANG"] = "C"; + p.StartInfo.Environment["LC_ALL"] = "C"; + IProcessTaskLogger logger = TaskLogger.CreateNew(LoggableTaskType.ListUpdates, p); + + p.Start(); + + List outputLines = []; + while (p.StandardOutput.ReadLine() is { } line) + { + logger.AddToStdOut(line); + outputLines.Add(line); + } + + logger.AddToStdErr(p.StandardError.ReadToEnd()); + p.WaitForExit(); + logger.Close(p.ExitCode); + + return ParseAvailableUpdates(outputLines, DefaultSource, this, GetInstalledPackages_UnSafe()); + } +} diff --git a/src/UniGetUI.PackageEngine.Managers.Flatpak/FlatpakParsing.cs b/src/UniGetUI.PackageEngine.Managers.Flatpak/FlatpakParsing.cs new file mode 100644 index 0000000..dc2e6db --- /dev/null +++ b/src/UniGetUI.PackageEngine.Managers.Flatpak/FlatpakParsing.cs @@ -0,0 +1,173 @@ +using System.Text.RegularExpressions; +using UniGetUI.Core.Tools; +using UniGetUI.PackageEngine.Interfaces; +using UniGetUI.PackageEngine.PackageClasses; + +namespace UniGetUI.PackageEngine.Managers.FlatpakManager; + +public partial class Flatpak +{ + [GeneratedRegex(@"[a-zA-Z0-9][-a-zA-Z0-9]*(\.[a-zA-Z0-9][-a-zA-Z0-9]*)+")] + private static partial Regex _searchAppIdRegex(); + + [GeneratedRegex(@"\s{2,}")] + private static partial Regex _multiSpaceRegex(); + + private static void ParseColumns(IReadOnlyList parts, out string appId, out string version, out string name) + { + appId = parts[0]; + version = parts[1]; + if (string.IsNullOrEmpty(version) && parts.Count > 2) + version = parts[2]; + name = parts[4]; + } + + public static IReadOnlyList ParseInstalledPackages( + IEnumerable outputLines, + IManagerSource source, + IPackageManager manager) + { + var packages = new List(); + + foreach (var line in outputLines) + { + var trimmed = line.Trim(); + if (string.IsNullOrEmpty(trimmed)) + { + continue; + } + + var parts = trimmed.Split('\t'); + if (parts.Length < 5) + { + continue; + } + + var appId = parts[0]; + var version = parts[1]; + if (string.IsNullOrEmpty(version)) + { + version = parts[2]; + } + + var name = parts[4]; + + packages.Add(new Package( + CoreTools.FormatAsName(name), + appId, + version, + source, + manager)); + } + + return packages; + } + + public static IReadOnlyList ParseAvailableUpdates( + IEnumerable outputLines, + IManagerSource source, + IPackageManager manager, + IReadOnlyList installedPackages) + { + var installedPackageMap = new Dictionary(); + foreach (var installedPackage in installedPackages) + { + installedPackageMap.TryAdd(installedPackage.Id, installedPackage); + } + + var packages = new List(); + + foreach (var line in outputLines) + { + var trimmed = line.Trim(); + if (string.IsNullOrEmpty(trimmed)) + { + continue; + } + + var parts = trimmed.Split('\t'); + if (parts.Length < 5) + { + continue; + } + + ParseColumns(parts, out var appId, out var newVersion, out var name); + + if (installedPackageMap.TryGetValue(appId, out var installedPackage)) + { + packages.Add(new Package( + CoreTools.FormatAsName(name), + appId, + installedPackage.VersionString, + newVersion, + source, + manager)); + } + } + + return packages; + } + + public static IReadOnlyList ParseSearchResults( + IEnumerable outputLines, + IManagerSource source, + IPackageManager manager) + { + var lines = outputLines.ToArray(); + if (lines.Length == 0) + { + return []; + } + + var packages = new List(); + + // Detect format: tab-separated (no header) vs space-padded (with header) + int startIndex = lines[0].Contains('\t') ? 0 : 1; + + for (int i = startIndex; i < lines.Length; i++) + { + var trimmed = lines[i].Trim(); + if (string.IsNullOrEmpty(trimmed)) + { + continue; + } + + string name; + string appId; + string version; + + var tabParts = trimmed.Split('\t'); + if (tabParts.Length >= 4) + { + name = tabParts[0]; + appId = tabParts[2]; + version = tabParts[3]; + } + else + { + var appIdMatch = _searchAppIdRegex().Match(trimmed); + if (!appIdMatch.Success) + { + continue; + } + + appId = appIdMatch.Value; + var before = trimmed[..appIdMatch.Index].TrimEnd(); + var after = trimmed[(appIdMatch.Index + appIdMatch.Length)..].Trim(); + + name = _multiSpaceRegex().Split(before)[0]; + var parts = after.Split(' ', StringSplitOptions.RemoveEmptyEntries); + version = parts.Length > 0 ? parts[0] : ""; + } + + packages.Add(new Package( + CoreTools.FormatAsName(name), + appId, + version, + source, + manager)); + } + + return packages; + } +} diff --git a/src/UniGetUI.PackageEngine.Managers.Flatpak/Helpers/FlatpakPkgDetailsHelper.cs b/src/UniGetUI.PackageEngine.Managers.Flatpak/Helpers/FlatpakPkgDetailsHelper.cs new file mode 100644 index 0000000..88b998e --- /dev/null +++ b/src/UniGetUI.PackageEngine.Managers.Flatpak/Helpers/FlatpakPkgDetailsHelper.cs @@ -0,0 +1,102 @@ +using System.Diagnostics; +using UniGetUI.Core.IconEngine; +using UniGetUI.PackageEngine.Classes.Manager.BaseProviders; +using UniGetUI.PackageEngine.Enums; +using UniGetUI.PackageEngine.Interfaces; +using UniGetUI.PackageEngine.ManagerClasses.Classes; + +namespace UniGetUI.PackageEngine.Managers.FlatpakManager; + +internal sealed class FlatpakPkgDetailsHelper : BasePkgDetailsHelper +{ + public FlatpakPkgDetailsHelper(Flatpak manager) + : base(manager) { } + + protected override void GetDetails_UnSafe(IPackageDetails details) + { + using var p = new Process + { + StartInfo = new ProcessStartInfo + { + FileName = Manager.Status.ExecutablePath, + Arguments = $"info {details.Package.Id}", + UseShellExecute = false, + RedirectStandardOutput = true, + RedirectStandardError = true, + CreateNoWindow = true, + }, + }; + p.StartInfo.Environment["LANG"] = "C"; + p.StartInfo.Environment["LC_ALL"] = "C"; + + IProcessTaskLogger logger = Manager.TaskLogger.CreateNew( + LoggableTaskType.LoadPackageDetails, p); + p.Start(); + + while (p.StandardOutput.ReadLine() is { } line) + { + logger.AddToStdOut(line); + + var colonIdx = line.IndexOf(':', StringComparison.Ordinal); + if (colonIdx <= 0) continue; + + var key = line[..colonIdx].Trim().ToLowerInvariant(); + var value = line[(colonIdx + 1)..].Trim(); + + switch (key) + { + case "name": + break; + case "summary": + details.Description = value; + break; + case "license": + details.License = value; + break; + case "homepage": + if (Uri.TryCreate(value, UriKind.Absolute, out var homepage)) + details.HomepageUrl = homepage; + break; + case "origin": + details.Publisher = value; + break; + case "url": + if (Uri.TryCreate(value, UriKind.Absolute, out var url)) + details.ManifestUrl = url; + break; + } + } + + logger.AddToStdErr(p.StandardError.ReadToEnd()); + p.WaitForExit(); + logger.Close(p.ExitCode); + } + + protected override CacheableIcon? GetIcon_UnSafe(IPackage package) + => throw new NotImplementedException(); + + protected override IReadOnlyList GetScreenshots_UnSafe(IPackage package) + => Array.Empty(); + + protected override string? GetInstallLocation_UnSafe(IPackage package) + { + // System-wide installs live under /var/lib/flatpak, per-user installs under + // ~/.local/share/flatpak. Return whichever actually contains the app. + foreach (var baseDir in new[] + { + "/var/lib/flatpak", + Path.Join( + Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), + ".local", "share", "flatpak"), + }) + { + var path = Path.Join(baseDir, "app", package.Id); + if (Directory.Exists(path)) + return path; + } + return null; + } + + protected override IReadOnlyList GetInstallableVersions_UnSafe(IPackage package) + => throw new InvalidOperationException("Flatpak does not support installing arbitrary versions"); +} diff --git a/src/UniGetUI.PackageEngine.Managers.Flatpak/Helpers/FlatpakPkgOperationHelper.cs b/src/UniGetUI.PackageEngine.Managers.Flatpak/Helpers/FlatpakPkgOperationHelper.cs new file mode 100644 index 0000000..a60e7d7 --- /dev/null +++ b/src/UniGetUI.PackageEngine.Managers.Flatpak/Helpers/FlatpakPkgOperationHelper.cs @@ -0,0 +1,54 @@ +using UniGetUI.PackageEngine.Classes.Manager.BaseProviders; +using UniGetUI.PackageEngine.Enums; +using UniGetUI.PackageEngine.Interfaces; +using UniGetUI.PackageEngine.Serializable; + +namespace UniGetUI.PackageEngine.Managers.FlatpakManager; + +internal sealed class FlatpakPkgOperationHelper : BasePkgOperationHelper +{ + public FlatpakPkgOperationHelper(Flatpak manager) + : base(manager) { } + + protected override IReadOnlyList _getOperationParameters( + IPackage package, + InstallOptions options, + OperationType operation) + { + options.RunAsAdministrator = true; + + List parameters = + [ + operation switch + { + OperationType.Install => Manager.Properties.InstallVerb, + OperationType.Uninstall => Manager.Properties.UninstallVerb, + OperationType.Update => Manager.Properties.UpdateVerb, + _ => throw new InvalidDataException("Invalid package operation"), + }, + ]; + + parameters.Add("--noninteractive"); + parameters.Add("-y"); + parameters.Add(package.Id); + + parameters.AddRange( + operation switch + { + OperationType.Update => options.CustomParameters_Update, + OperationType.Uninstall => options.CustomParameters_Uninstall, + _ => options.CustomParameters_Install, + }); + + return parameters; + } + + protected override OperationVeredict _getOperationResult( + IPackage package, + OperationType operation, + IReadOnlyList processOutput, + int returnCode) + { + return returnCode == 0 ? OperationVeredict.Success : OperationVeredict.Failure; + } +} diff --git a/src/UniGetUI.PackageEngine.Managers.Flatpak/Helpers/FlatpakSourceHelper.cs b/src/UniGetUI.PackageEngine.Managers.Flatpak/Helpers/FlatpakSourceHelper.cs new file mode 100644 index 0000000..7336d4c --- /dev/null +++ b/src/UniGetUI.PackageEngine.Managers.Flatpak/Helpers/FlatpakSourceHelper.cs @@ -0,0 +1,84 @@ +using System.Diagnostics; +using System.Text.RegularExpressions; +using UniGetUI.Core.Logging; +using UniGetUI.PackageEngine.Classes.Manager; +using UniGetUI.PackageEngine.Classes.Manager.Providers; +using UniGetUI.PackageEngine.Enums; +using UniGetUI.PackageEngine.Interfaces; +using UniGetUI.PackageEngine.ManagerClasses.Classes; + +namespace UniGetUI.PackageEngine.Managers.FlatpakManager; + +public partial class Flatpak +{ + [GeneratedRegex(@"^(\S+)\s+(https?://\S+)$")] + internal static partial Regex RemoteListLineRegex(); +} + +internal sealed class FlatpakSourceHelper : BaseSourceHelper +{ + public FlatpakSourceHelper(Flatpak manager) + : base(manager) { } + + protected override IReadOnlyList GetSources_UnSafe() + { + var sources = new List(); + + using var p = new Process + { + StartInfo = new ProcessStartInfo + { + FileName = Manager.Status.ExecutablePath, + Arguments = "remote-list --columns=name,url", + UseShellExecute = false, + RedirectStandardOutput = true, + RedirectStandardError = true, + CreateNoWindow = true, + }, + }; + IProcessTaskLogger logger = Manager.TaskLogger.CreateNew(LoggableTaskType.ListSources, p); + p.Start(); + + string? line; + while ((line = p.StandardOutput.ReadLine()) is not null) + { + logger.AddToStdOut(line); + var match = Flatpak.RemoteListLineRegex().Match(line.Trim()); + if (!match.Success) + { + continue; + } + + var name = match.Groups[1].Value; + var url = match.Groups[2].Value; + + try + { + sources.Add(new ManagerSource(Manager, name, new Uri(url))); + } + catch (Exception ex) + { + Logger.Warn($"FlatpakSourceHelper: could not add remote '{name}': {ex.Message}"); + } + } + + logger.AddToStdErr(p.StandardError.ReadToEnd()); + p.WaitForExit(); + logger.Close(p.ExitCode); + return sources; + } + + public override string[] GetAddSourceParameters(IManagerSource source) + => ["remote-add", "--if-not-exists", source.Name, source.Url.ToString()]; + + public override string[] GetRemoveSourceParameters(IManagerSource source) + => ["remote-delete", source.Name]; + + protected override OperationVeredict _getAddSourceOperationVeredict( + IManagerSource source, int ReturnCode, string[] Output) + => ReturnCode == 0 ? OperationVeredict.Success : OperationVeredict.Failure; + + protected override OperationVeredict _getRemoveSourceOperationVeredict( + IManagerSource source, int ReturnCode, string[] Output) + => ReturnCode == 0 ? OperationVeredict.Success : OperationVeredict.Failure; +} diff --git a/src/UniGetUI.PackageEngine.Managers.Flatpak/UniGetUI.PackageEngine.Managers.Flatpak.csproj b/src/UniGetUI.PackageEngine.Managers.Flatpak/UniGetUI.PackageEngine.Managers.Flatpak.csproj new file mode 100644 index 0000000..a0903da --- /dev/null +++ b/src/UniGetUI.PackageEngine.Managers.Flatpak/UniGetUI.PackageEngine.Managers.Flatpak.csproj @@ -0,0 +1,23 @@ + + + $(SharedTargetFrameworks) + + + + + + + + + + + + + + + + + + + + diff --git a/src/UniGetUI.PackageEngine.Managers.Generic.NuGet/BaseNuGet.cs b/src/UniGetUI.PackageEngine.Managers.Generic.NuGet/BaseNuGet.cs new file mode 100644 index 0000000..f64233f --- /dev/null +++ b/src/UniGetUI.PackageEngine.Managers.Generic.NuGet/BaseNuGet.cs @@ -0,0 +1,330 @@ +using System.Text; +using System.Text.RegularExpressions; +using System.Web; +using UniGetUI.Core.Classes; +using UniGetUI.Core.Data; +using UniGetUI.Core.Tools; +using UniGetUI.PackageEngine.Enums; +using UniGetUI.PackageEngine.Interfaces; +using UniGetUI.PackageEngine.ManagerClasses.Classes; +using UniGetUI.PackageEngine.ManagerClasses.Manager; +using UniGetUI.PackageEngine.PackageClasses; + +namespace UniGetUI.PackageEngine.Managers.PowerShellManager +{ + public abstract class BaseNuGet : PackageManager + { + /// + /// When true, searches use Packages()?$filter=substringof(query,Id) which searches by + /// package name only but returns reliable results (e.g. PSGallery's Search() endpoint + /// silently omits some packages). When false, the standard Search() endpoint is used + /// which supports full-text search across name, description, and tags. + /// + protected virtual bool UseSubstringSearch => false; + public static Dictionary Manifests = new(); + + public sealed override void Initialize() + { + static void ThrowIC(string name) + { + throw new InvalidOperationException( + $"NuGet-based package managers must have Capabilities.{name} set to true" + ); + } + + if (DetailsHelper is not BaseNuGetDetailsHelper) + { + throw new InvalidOperationException( + "NuGet-based package managers must not reassign the PackageDetailsProvider property" + ); + } + + if (!Capabilities.SupportsCustomVersions) + ThrowIC(nameof(Capabilities.SupportsCustomVersions)); + if (!Capabilities.SupportsCustomPackageIcons) + ThrowIC(nameof(Capabilities.SupportsCustomPackageIcons)); + if (!Capabilities.CanListDependencies) + ThrowIC(nameof(Capabilities.CanListDependencies)); + + base.Initialize(); + } + + private struct SearchResult + { + public string version; + public CoreTools.Version version_float; + public string id; + public string manifest; + } + + protected sealed override IReadOnlyList FindPackages_UnSafe(string query) + { + List Packages = []; + INativeTaskLogger logger = TaskLogger.CreateNew(LoggableTaskType.FindPackages); + + IReadOnlyList sources; + if (Capabilities.SupportsCustomSources) + { + sources = SourcesHelper.GetSources(); + } + else + { + sources = [Properties.DefaultSource]; + } + + bool canPrerelease = InstallOptionsFactory.LoadForManager(this).PreRelease; + + foreach (IManagerSource source in sources) + { + try + { + string versionFilter = canPrerelease ? "IsAbsoluteLatestVersion eq true" : "IsLatestVersion eq true"; + string odataQuery = HttpUtility.UrlEncode(query.Replace("'", "''")); + Uri? SearchUrl = UseSubstringSearch + ? new Uri( + $"{source.Url}/Packages()" + + $"?$filter=substringof('{odataQuery}',Id) and {versionFilter}" + + $"&$orderby=DownloadCount desc" + + $"&$skip=0" + + $"&$top=50" + ) + : new Uri( + $"{source.Url}/Search()" + + $"?$filter=IsLatestVersion" + + $"&$orderby=Id&searchTerm='{odataQuery}'" + + $"&targetFramework=''" + + $"&includePrerelease={(canPrerelease ? "true" : "false")}" + + $"&$skip=0" + + $"&$top=50" + + $"&semVerLevel=2.0.0" + ); + logger.Log($"Begin package search with url={SearchUrl} on manager {Name}"); + Dictionary AlreadyProcessedPackages = []; + + using HttpClient client = new(CoreTools.GenericHttpClientParameters); + client.DefaultRequestHeaders.UserAgent.ParseAdd(CoreData.UserAgentString); + + while (SearchUrl is not null) + { + using var request = new HttpRequestMessage(HttpMethod.Get, SearchUrl); + using HttpResponseMessage response = client.Send(request); + + if (!response.IsSuccessStatusCode) + { + logger.Error( + $"Failed to fetch api at Url={SearchUrl} with status code {response.StatusCode}" + ); + SearchUrl = null; + continue; + } + + string SearchResults = response + .Content.ReadAsStringAsync() + .GetAwaiter() + .GetResult(); + MatchCollection matches = Regex.Matches( + SearchResults, + "([\\s\\S]*?)<\\/entry>" + ); + + foreach (Match match in matches) + { + if (!match.Success) + { + continue; + } + + string id = Regex.Match(match.Value, "Id='([^<>']+)'").Groups[1].Value; + string version = Regex + .Match(match.Value, "Version='([^<>']+)'") + .Groups[1] + .Value; + var float_version = CoreTools.VersionStringToStruct(version); + // Match title = Regex.Match(match.Value, "([^<>]+)<\\/title>"); + + if ( + AlreadyProcessedPackages.TryGetValue(id, out var value) + && value.version_float >= float_version + ) + { + continue; + } + + AlreadyProcessedPackages[id] = new SearchResult + { + id = id, + version = version, + version_float = float_version, + manifest = match.Value, + }; + } + + SearchUrl = null; + Match next = Regex.Match( + SearchResults, + "" + ); + if (next.Success) + { + SearchUrl = new Uri(next.Groups[1].Value.Replace("&", "&")); + logger.Log($"Adding extra info from URL={SearchUrl}"); + } + } + + foreach (SearchResult package in AlreadyProcessedPackages.Values) + { + logger.Log( + $"Found package {package.id} version {package.version} on source {source.Name}" + ); + var nativePackage = new Package( + CoreTools.FormatAsName(package.id), + package.id, + package.version, + source, + this + ); + Packages.Add(nativePackage); + Manifests[nativePackage.GetHash()] = package.manifest; + } + } + catch (Exception ex) + { + logger.Error( + $"Source {source.Name} on manager {source.Manager.Name} failed to find package data" + ); + logger.Error(ex); + } + } + + logger.Close(0); + return Packages; + } + + protected override IReadOnlyList GetAvailableUpdates_UnSafe() + { + int errors = 0; + var logger = TaskLogger.CreateNew(LoggableTaskType.ListUpdates); + + var installedPackages = TaskRecycler>.RunOrAttach( + GetInstalledPackages + ); + var Packages = new List(); + + Dictionary> sourceMapping = new(); + + foreach (var package in installedPackages) + { + var uri = package.Source; + if (!sourceMapping.ContainsKey(uri)) + sourceMapping[uri] = new(); + sourceMapping[uri].Add(package); + } + bool canPrerelease = InstallOptionsFactory.LoadForManager(this).PreRelease; + + foreach (var pair in sourceMapping) + { + try + { + var packageIds = new StringBuilder(); + var packageVers = new StringBuilder(); + var packageIdVersion = new Dictionary(); + foreach (var package in pair.Value) + { + packageIds.Append(package.Id + "|"); + packageVers.Append(package.VersionString + "|"); + packageIdVersion[package.Id.ToLower()] = package.VersionString; + } + + var SearchUrl = + $"{pair.Key.Url.ToString().Trim('/')}/GetUpdates()" + + $"?packageIds=%27{HttpUtility.UrlEncode(packageIds.ToString().Trim('|'))}%27" + + $"&versions=%27{HttpUtility.UrlEncode(packageVers.ToString().Trim('|'))}%27" + + $"&includePrerelease={(canPrerelease ? "true" : "false")}" + + $"&includeAllVersions=0"; + + using HttpClient client = new(CoreTools.GenericHttpClientParameters); + client.DefaultRequestHeaders.UserAgent.ParseAdd(CoreData.UserAgentString); + using var request = new HttpRequestMessage(HttpMethod.Get, SearchUrl); + using HttpResponseMessage response = client.Send(request); + + if (!response.IsSuccessStatusCode) + { + logger.Error( + $"Failed to fetch api at Url={SearchUrl} with status code {response.StatusCode}" + ); + errors++; + } + else + { + string SearchResults = response + .Content.ReadAsStringAsync() + .GetAwaiter() + .GetResult(); + MatchCollection matches = Regex.Matches( + SearchResults, + "([\\s\\S]*?)<\\/entry>" + ); + + foreach (Match match in matches) + { + if (!match.Success) + continue; + + string id = Regex + .Match(match.Value, "([^<]+)") + .Groups[1] + .Value; + string new_version = Regex + .Match(match.Value, "([^<]+)") + .Groups[1] + .Value; + // Match title = Regex.Match(match.Value, "([^<>]+)<\\/title>"); + + logger.Log( + $"Found package {id} version {new_version} on source {pair.Key.Name}" + ); + + var nativePackage = new Package( + CoreTools.FormatAsName(id), + id, + packageIdVersion[id.ToLower()], + new_version, + pair.Key, + this + ); + Packages.Add(nativePackage); + Manifests[nativePackage.GetHash()] = match.Value; + } + } + } + catch (Exception ex) + { + logger.Error( + $"Source {pair.Key.Name} on manager {pair.Key.Manager.Name} failed to load updates info with exception" + ); + logger.Error(ex); + } + } + + var maxVersions = new Dictionary(); + foreach (var pkg in installedPackages) + { + maxVersions.TryGetValue(pkg.Id, out var ver); + if (ver is null || ver < pkg.NormalizedVersion) + { + maxVersions[pkg.Id.ToLower()] = pkg.NormalizedVersion; + } + } + + logger.Close(errors); + return Packages + .Where(p => maxVersions[p.Id.ToLower()] < p.NormalizedNewVersion) + .ToArray(); + } + + protected sealed override IReadOnlyList GetInstalledPackages_UnSafe() => + TaskRecycler>.RunOrAttach(_getInstalledPackages_UnSafe); + + protected abstract IReadOnlyList _getInstalledPackages_UnSafe(); + } +} diff --git a/src/UniGetUI.PackageEngine.Managers.Generic.NuGet/BaseNuGetDetailsHelper.cs b/src/UniGetUI.PackageEngine.Managers.Generic.NuGet/BaseNuGetDetailsHelper.cs new file mode 100644 index 0000000..b478ba0 --- /dev/null +++ b/src/UniGetUI.PackageEngine.Managers.Generic.NuGet/BaseNuGetDetailsHelper.cs @@ -0,0 +1,298 @@ +using System.Text.RegularExpressions; +using UniGetUI.Core.Data; +using UniGetUI.Core.IconEngine; +using UniGetUI.Core.Logging; +using UniGetUI.Core.Tools; +using UniGetUI.PackageEngine.Classes.Manager.BaseProviders; +using UniGetUI.PackageEngine.Enums; +using UniGetUI.PackageEngine.Interfaces; +using UniGetUI.PackageEngine.Managers.Generic.NuGet.Internal; + +namespace UniGetUI.PackageEngine.Managers.PowerShellManager +{ + public abstract class BaseNuGetDetailsHelper : BasePkgDetailsHelper + { + public BaseNuGetDetailsHelper(BaseNuGet manager) + : base(manager) { } + + protected override void GetDetails_UnSafe(IPackageDetails details) + { + var logger = Manager.TaskLogger.CreateNew(LoggableTaskType.LoadPackageDetails); + try + { + details.ManifestUrl = NuGetManifestLoader.GetManifestUrl(details.Package); + string? PackageManifestContents = NuGetManifestLoader.GetManifestContent( + details.Package + ); + logger.Log(PackageManifestContents); + + if (PackageManifestContents is null) + { + logger.Error( + $"No manifest content could be loaded for package {details.Package.Id} on manager {details.Package.Manager.Name}, returning empty PackageDetails" + ); + logger.Close(1); + return; + } + + details.InstallerType = CoreTools.Translate("NuPkg (zipped manifest)"); + + foreach ( + Match match in Regex.Matches( + PackageManifestContents, + @"" + ) + ) + { + try + { + details.InstallerUrl = new Uri(match.Groups[1].Value); + break; + } + catch (Exception ex) + { + Logger.Warn( + $"Failed to parse NuGet Installer URL on package Id={details.Package.Id} for value={match.Groups[1].Value}: " + + ex.Message + ); + } + } + + foreach ( + Match match in Regex.Matches( + PackageManifestContents, + @"<(d\:)?PackageSize (m\:type=""[^""]+"")?>([0-9]+)<\/" + ) + ) + { + try + { + details.InstallerSize = long.Parse(match.Groups[3].Value); + break; + } + catch (Exception ex) + { + Logger.Warn( + $"Failed to parse NuGet Installer Size on package Id={details.Package.Id} for value={match.Groups[1].Value}: " + + ex.Message + ); + } + } + + foreach ( + Match match in Regex.Matches(PackageManifestContents, @"[^<>]+<\/name>") + ) + { + details.Author = match.Value.Replace("", "").Replace("", ""); + details.Publisher = match.Value.Replace("", "").Replace("", ""); + break; + } + + foreach ( + Match match in Regex.Matches( + PackageManifestContents, + @"[^<>]+<\/d:Description>" + ) + ) + { + details.Description = match + .Value.Replace("", "") + .Replace("", ""); + break; + } + + foreach ( + Match match in Regex.Matches( + PackageManifestContents, + @"[^<>]+<\/updated>" + ) + ) + { + details.UpdateDate = match + .Value.Replace("", "") + .Replace("", ""); + break; + } + + foreach ( + Match match in Regex.Matches( + PackageManifestContents, + @"[^<>]+<\/d:ProjectUrl>" + ) + ) + { + details.HomepageUrl = new Uri( + match.Value.Replace("", "").Replace("", "") + ); + break; + } + + foreach ( + Match match in Regex.Matches( + PackageManifestContents, + @"[^<>]+<\/d:LicenseUrl>" + ) + ) + { + details.LicenseUrl = new Uri( + match.Value.Replace("", "").Replace("", "") + ); + break; + } + + foreach ( + Match match in Regex.Matches( + PackageManifestContents, + @"[^<>]+<\/d:PackageHash>" + ) + ) + { + details.InstallerHash = match + .Value.Replace("", "") + .Replace("", ""); + break; + } + + foreach ( + Match match in Regex.Matches( + PackageManifestContents, + @"[^<>]+<\/d:ReleaseNotes>" + ) + ) + { + details.ReleaseNotes = match + .Value.Replace("", "") + .Replace("", ""); + break; + } + + foreach ( + Match match in Regex.Matches( + PackageManifestContents, + @"[^<>]+<\/d:LicenseNames>" + ) + ) + { + details.License = match + .Value.Replace("", "") + .Replace("", ""); + break; + } + + details.Dependencies.Clear(); + foreach ( + Match match in Regex.Matches( + PackageManifestContents, + @"([^<]+)" + ) + ) + { + foreach (var dep in match.Groups[1].ToString().Split('|')) + { + if (string.IsNullOrEmpty(dep)) + continue; + else if (dep.StartsWith("::")) + details.Dependencies.Add( + new() + { + Name = dep.TrimStart(':'), + Version = "", + Mandatory = true, + } + ); + else + details.Dependencies.Add( + new() + { + Name = dep.Split(':')[0], + Version = dep.Split(':')[1].TrimEnd(':'), + Mandatory = true, + } + ); + } + } + + logger.Close(0); + return; + } + catch (Exception e) + { + logger.Error(e); + logger.Close(1); + return; + } + } + + protected override CacheableIcon? GetIcon_UnSafe(IPackage package) + { + string? ManifestContent = NuGetManifestLoader.GetManifestContent(package); + if (ManifestContent is null) + { + Logger.Warn( + $"No manifest content could be loaded for package {package.Id} on manager {package.Manager.Name}" + ); + return null; + } + + Match possibleIconUrl = Regex.Match( + ManifestContent, + "<(?:d\\:)?IconUrl>(.*)<(?:\\/d:)?IconUrl>" + ); + + if (!possibleIconUrl.Success || possibleIconUrl.Groups[1].Value == "") + { + // Logger.Warn($"No Icon URL could be parsed on the manifest Url={NuGetManifestLoader.GetManifestUrl(package).ToString()}"); + return null; + } + + // Logger.Debug($"A native icon with Url={possibleIconUrl.Groups[1].Value} was found"); + return new CacheableIcon( + new Uri(possibleIconUrl.Groups[1].Value), + package.VersionString + ); + } + + protected override IReadOnlyList GetScreenshots_UnSafe(IPackage package) + { + throw new NotImplementedException(); + } + + protected override IReadOnlyList GetInstallableVersions_UnSafe(IPackage package) + { + Uri SearchUrl = new($"{package.Source.Url}/FindPackagesById()?id='{package.Id}'"); + Logger.Debug( + $"Begin package version search with url={SearchUrl} on manager {Manager.Name}" + ); + + List results = []; + + using HttpClient client = new(CoreTools.GenericHttpClientParameters); + client.DefaultRequestHeaders.UserAgent.ParseAdd(CoreData.UserAgentString); + using var request = new HttpRequestMessage(HttpMethod.Get, SearchUrl); + using HttpResponseMessage response = client.Send(request); + if (!response.IsSuccessStatusCode) + { + Logger.Warn( + $"Failed to fetch api at Url={SearchUrl} with status code {response.StatusCode} to load versions" + ); + return []; + } + + string SearchResults = response.Content.ReadAsStringAsync().GetAwaiter().GetResult(); + HashSet alreadyProcessed = []; + + MatchCollection matches = Regex.Matches(SearchResults, "Version='([^<>']+)'"); + foreach (Match match in matches) + { + if (!alreadyProcessed.Contains(match.Groups[1].Value) && match.Success) + { + results.Add(match.Groups[1].Value); + alreadyProcessed.Add(match.Groups[1].Value); + } + } + + results.Sort(StringComparer.OrdinalIgnoreCase); + return results; + } + } +} diff --git a/src/UniGetUI.PackageEngine.Managers.Generic.NuGet/Internal/NuGetManifestLoader.cs b/src/UniGetUI.PackageEngine.Managers.Generic.NuGet/Internal/NuGetManifestLoader.cs new file mode 100644 index 0000000..d811a3a --- /dev/null +++ b/src/UniGetUI.PackageEngine.Managers.Generic.NuGet/Internal/NuGetManifestLoader.cs @@ -0,0 +1,103 @@ +using UniGetUI.Core.Data; +using UniGetUI.Core.Logging; +using UniGetUI.Core.Tools; +using UniGetUI.PackageEngine.Interfaces; +using UniGetUI.PackageEngine.Managers.PowerShellManager; + +namespace UniGetUI.PackageEngine.Managers.Generic.NuGet.Internal +{ + internal static class NuGetManifestLoader + { + /// + /// Returns the URL to the manifest of a NuGet-based package + /// + /// A valid Package object + /// A Uri object + public static Uri GetManifestUrl(IPackage package) + { + return new Uri( + $"{package.Source.Url}/Packages(Id='{package.Id}',Version='{package.VersionString}')" + ); + } + + /// + /// Returns the URL to the NuPkg file + /// + /// A valid Package object + /// A Uri object + public static Uri GetNuPkgUrl(IPackage package) + { + return new Uri($"{package.Source.Url}/package/{package.Id}/{package.VersionString}"); + } + + /// + /// Returns the contents of the manifest of a NuGet-based package + /// + /// The package for which to obtain the manifest + /// A string containing the contents of the manifest + public static string? GetManifestContent(IPackage package) + { + if (BaseNuGet.Manifests.TryGetValue(package.GetHash(), out string? manifest)) + { + Logger.Debug( + $"Loading cached NuGet manifest for package {package.Id} on manager {package.Manager.Name}" + ); + return manifest; + } + + string PackageManifestUrl = GetManifestUrl(package).ToString(); + + try + { + using (HttpClient client = new(CoreTools.GenericHttpClientParameters)) + { + client.DefaultRequestHeaders.UserAgent.ParseAdd(CoreData.UserAgentString); + using var initialRequest = new HttpRequestMessage( + HttpMethod.Get, + PackageManifestUrl + ); + using HttpResponseMessage initialResponse = client.Send(initialRequest); + + if (!initialResponse.IsSuccessStatusCode && package.VersionString.EndsWith(".0")) + { + using var fallbackRequest = new HttpRequestMessage( + HttpMethod.Get, + new Uri(PackageManifestUrl.ToString().Replace(".0')", "')")) + ); + using HttpResponseMessage fallbackResponse = client.Send(fallbackRequest); + return CacheManifestContent(package, PackageManifestUrl, fallbackResponse); + } + + return CacheManifestContent(package, PackageManifestUrl, initialResponse); + } + } + catch (Exception e) + { + Logger.Warn( + $"Failed to download the {package.Manager.Name} manifest at Url={PackageManifestUrl.ToString()}" + ); + Logger.Warn(e); + return null; + } + } + + private static string? CacheManifestContent( + IPackage package, + string packageManifestUrl, + HttpResponseMessage response + ) + { + if (!response.IsSuccessStatusCode) + { + Logger.Warn( + $"Failed to download the {package.Manager.Name} manifest at Url={packageManifestUrl} with status code {response.StatusCode}" + ); + return null; + } + + string packageManifestContent = response.Content.ReadAsStringAsync().GetAwaiter().GetResult(); + BaseNuGet.Manifests[package.GetHash()] = packageManifestContent; + return packageManifestContent; + } + } +} diff --git a/src/UniGetUI.PackageEngine.Managers.Generic.NuGet/InternalsVisibleTo.cs b/src/UniGetUI.PackageEngine.Managers.Generic.NuGet/InternalsVisibleTo.cs new file mode 100644 index 0000000..eeb63da --- /dev/null +++ b/src/UniGetUI.PackageEngine.Managers.Generic.NuGet/InternalsVisibleTo.cs @@ -0,0 +1,3 @@ +using System.Runtime.CompilerServices; + +[assembly: InternalsVisibleTo("UniGetUI.PackageEngine.Tests")] diff --git a/src/UniGetUI.PackageEngine.Managers.Generic.NuGet/UniGetUI.PackageEngine.Managers.Generic.NuGet.csproj b/src/UniGetUI.PackageEngine.Managers.Generic.NuGet/UniGetUI.PackageEngine.Managers.Generic.NuGet.csproj new file mode 100644 index 0000000..6236cb7 --- /dev/null +++ b/src/UniGetUI.PackageEngine.Managers.Generic.NuGet/UniGetUI.PackageEngine.Managers.Generic.NuGet.csproj @@ -0,0 +1,18 @@ + + + $(SharedTargetFrameworks) + + + + + + + + + + + + + + + diff --git a/src/UniGetUI.PackageEngine.Managers.Homebrew/Helpers/HomebrewPkgDetailsHelper.cs b/src/UniGetUI.PackageEngine.Managers.Homebrew/Helpers/HomebrewPkgDetailsHelper.cs new file mode 100644 index 0000000..ba19a83 --- /dev/null +++ b/src/UniGetUI.PackageEngine.Managers.Homebrew/Helpers/HomebrewPkgDetailsHelper.cs @@ -0,0 +1,123 @@ +using System.Diagnostics; +using System.Text.Json.Nodes; +using UniGetUI.Core.IconEngine; +using UniGetUI.Core.Logging; +using UniGetUI.PackageEngine.Classes.Manager.BaseProviders; +using UniGetUI.PackageEngine.Interfaces; +using UniGetUI.PackageEngine.ManagerClasses.Classes; + +namespace UniGetUI.PackageEngine.Managers.HomebrewManager; + +internal sealed class HomebrewPkgDetailsHelper : BasePkgDetailsHelper +{ + private readonly Homebrew _brew; + + public HomebrewPkgDetailsHelper(Homebrew manager) + : base(manager) { _brew = manager; } + + protected override void GetDetails_UnSafe(IPackageDetails details) + { + using var p = new Process + { + StartInfo = _brew.MakeBrewStartInfo($"info --json=v2 {details.Package.Id}"), + }; + + IProcessTaskLogger logger = Manager.TaskLogger.CreateNew( + Enums.LoggableTaskType.LoadPackageDetails, p); + p.Start(); + string json = p.StandardOutput.ReadToEnd(); + logger.AddToStdOut(json); + logger.AddToStdErr(p.StandardError.ReadToEnd()); + p.WaitForExit(); + + if (JsonNode.Parse(json) is not JsonObject root) + { + logger.Close(1); + throw new InvalidOperationException("Failed to parse brew info JSON"); + } + + // Try formula first, then cask + var formula = root["formulae"]?.AsArray().FirstOrDefault(); + var cask = root["casks"]?.AsArray().FirstOrDefault(); + + if (formula is JsonObject f) + _populateFromFormula(details, f); + else if (cask is JsonObject c) + _populateFromCask(details, c); + + logger.Close(0); + } + + private static void _populateFromFormula(IPackageDetails details, JsonObject f) + { + details.Description = f["desc"]?.ToString(); + details.License = f["license"]?.ToString(); + details.InstallerType = "Homebrew Formula"; + + if (Uri.TryCreate(f["homepage"]?.ToString(), UriKind.Absolute, out var homepage)) + { + details.HomepageUrl = homepage; + details.Author = homepage.Host.Split('.')[^2]; + } + + if (Uri.TryCreate( + f["urls"]?["stable"]?["url"]?.ToString(), + UriKind.Absolute, out var url)) + details.InstallerUrl = url; + + // Dependencies + details.Dependencies.Clear(); + foreach (var dep in f["dependencies"]?.AsArray() ?? []) + { + var name = dep?.ToString(); + if (name is not null) + details.Dependencies.Add(new() { Name = name, Version = "", Mandatory = true }); + } + foreach (var dep in f["recommended_dependencies"]?.AsArray() ?? []) + { + var name = dep?.ToString(); + if (name is not null) + details.Dependencies.Add(new() { Name = name, Version = "", Mandatory = false }); + } + } + + private static void _populateFromCask(IPackageDetails details, JsonObject c) + { + details.Description = c["desc"]?.ToString(); + details.InstallerType = "Homebrew Cask"; + + if (Uri.TryCreate(c["homepage"]?.ToString(), UriKind.Absolute, out var homepage)) + { + details.HomepageUrl = homepage; + details.Author = homepage.Host.Split('.')[^2]; + } + + if (Uri.TryCreate(c["url"]?.ToString(), UriKind.Absolute, out var url)) + details.InstallerUrl = url; + } + + protected override CacheableIcon? GetIcon_UnSafe(IPackage package) + => throw new NotImplementedException(); + + protected override IReadOnlyList GetScreenshots_UnSafe(IPackage package) + => throw new NotImplementedException(); + + protected override string? GetInstallLocation_UnSafe(IPackage package) + { + // Apple Silicon prefix is /opt/homebrew, Intel/Linux is /usr/local (or /home/linuxbrew). + // Formulae live under Cellar/, casks under Caskroom/. + foreach (var prefix in new[] { "/opt/homebrew", "/usr/local", "/home/linuxbrew/.linuxbrew" }) + { + foreach (var kind in new[] { "Cellar", "Caskroom" }) + { + var path = Path.Join(prefix, kind, package.Id); + if (Directory.Exists(path)) + return path; + } + } + return null; + } + + protected override IReadOnlyList GetInstallableVersions_UnSafe(IPackage package) + => throw new InvalidOperationException("Homebrew does not support installing arbitrary versions"); +} diff --git a/src/UniGetUI.PackageEngine.Managers.Homebrew/Helpers/HomebrewPkgOperationHelper.cs b/src/UniGetUI.PackageEngine.Managers.Homebrew/Helpers/HomebrewPkgOperationHelper.cs new file mode 100644 index 0000000..29d3c80 --- /dev/null +++ b/src/UniGetUI.PackageEngine.Managers.Homebrew/Helpers/HomebrewPkgOperationHelper.cs @@ -0,0 +1,61 @@ +using UniGetUI.PackageEngine.Classes.Manager.BaseProviders; +using UniGetUI.PackageEngine.Enums; +using UniGetUI.PackageEngine.Interfaces; +using UniGetUI.PackageEngine.Serializable; + +namespace UniGetUI.PackageEngine.Managers.HomebrewManager; + +internal sealed class HomebrewPkgOperationHelper : BasePkgOperationHelper +{ + public HomebrewPkgOperationHelper(Homebrew manager) + : base(manager) { } + + protected override IReadOnlyList _getOperationParameters( + IPackage package, + InstallOptions options, + OperationType operation) + { + List parameters = + [ + operation switch + { + OperationType.Install => Manager.Properties.InstallVerb, + OperationType.Update => Manager.Properties.UpdateVerb, + OperationType.Uninstall => Manager.Properties.UninstallVerb, + _ => throw new InvalidDataException("Invalid package operation"), + }, + ]; + + // Casks need the --cask flag + if (package.Source.Name == "Homebrew Cask") + parameters.Add("--cask"); + + parameters.Add(package.Id); + + // Custom parameters + parameters.AddRange( + operation switch + { + OperationType.Update => options.CustomParameters_Update, + OperationType.Uninstall => options.CustomParameters_Uninstall, + _ => options.CustomParameters_Install, + }); + + return parameters; + } + + protected override OperationVeredict _getOperationResult( + IPackage package, + OperationType operation, + IReadOnlyList processOutput, + int returnCode) + { + string output = string.Join("\n", processOutput); + + // Homebrew prints "Error:" for failures + if (returnCode != 0 || output.Contains("Error:")) + return OperationVeredict.Failure; + + return OperationVeredict.Success; + } +} diff --git a/src/UniGetUI.PackageEngine.Managers.Homebrew/Helpers/HomebrewSourceHelper.cs b/src/UniGetUI.PackageEngine.Managers.Homebrew/Helpers/HomebrewSourceHelper.cs new file mode 100644 index 0000000..7919bff --- /dev/null +++ b/src/UniGetUI.PackageEngine.Managers.Homebrew/Helpers/HomebrewSourceHelper.cs @@ -0,0 +1,84 @@ +using System.Diagnostics; +using UniGetUI.Core.Logging; +using UniGetUI.PackageEngine.Classes.Manager; +using UniGetUI.PackageEngine.Classes.Manager.Providers; +using UniGetUI.PackageEngine.Enums; +using UniGetUI.PackageEngine.Interfaces; +using UniGetUI.PackageEngine.ManagerClasses.Classes; + +namespace UniGetUI.PackageEngine.Managers.HomebrewManager; + +internal sealed class HomebrewSourceHelper : BaseSourceHelper +{ + private readonly Homebrew _brew; + + public HomebrewSourceHelper(Homebrew manager) + : base(manager) { _brew = manager; } + + // ── Source listing ───────────────────────────────────────────────────── + + protected override IReadOnlyList GetSources_UnSafe() + { + var sources = new List(); + + using var p = new Process + { + StartInfo = _brew.MakeBrewStartInfo("tap"), + }; + IProcessTaskLogger logger = Manager.TaskLogger.CreateNew(LoggableTaskType.ListSources, p); + p.Start(); + + string? line; + while ((line = p.StandardOutput.ReadLine()) is not null) + { + logger.AddToStdOut(line); + var name = line.Trim(); + if (name.Length == 0) continue; + + // Build a best-effort URL: "org/repo" → "https://github.com/org/homebrew-repo" + Uri url; + try + { + var parts = name.Split('/'); + var org = parts[0]; + var repo = parts.Length > 1 ? parts[1] : name; + // Official taps follow the "homebrew-" convention on GitHub + url = new Uri($"https://github.com/{org}/homebrew-{repo}"); + } + catch + { + url = new Uri($"https://github.com/{name}"); + } + + try + { + sources.Add(new ManagerSource(Manager, name, url)); + } + catch (Exception ex) + { + Logger.Warn($"HomebrewSourceHelper: could not add tap '{name}': {ex.Message}"); + } + } + + logger.AddToStdErr(p.StandardError.ReadToEnd()); + p.WaitForExit(); + logger.Close(p.ExitCode); + return sources; + } + + // ── Add / remove ─────────────────────────────────────────────────────── + + public override string[] GetAddSourceParameters(IManagerSource source) + => ["tap", source.Name, source.Url.ToString()]; + + public override string[] GetRemoveSourceParameters(IManagerSource source) + => ["untap", source.Name]; + + protected override OperationVeredict _getAddSourceOperationVeredict( + IManagerSource source, int ReturnCode, string[] Output) + => ReturnCode == 0 ? OperationVeredict.Success : OperationVeredict.Failure; + + protected override OperationVeredict _getRemoveSourceOperationVeredict( + IManagerSource source, int ReturnCode, string[] Output) + => ReturnCode == 0 ? OperationVeredict.Success : OperationVeredict.Failure; +} diff --git a/src/UniGetUI.PackageEngine.Managers.Homebrew/Homebrew.cs b/src/UniGetUI.PackageEngine.Managers.Homebrew/Homebrew.cs new file mode 100644 index 0000000..d74978d --- /dev/null +++ b/src/UniGetUI.PackageEngine.Managers.Homebrew/Homebrew.cs @@ -0,0 +1,273 @@ +using System.Diagnostics; +using System.Runtime.InteropServices; +using System.Text.RegularExpressions; +using UniGetUI.Core.Logging; +using UniGetUI.Core.Tools; +using UniGetUI.Interface.Enums; +using UniGetUI.PackageEngine.Classes.Manager; +using UniGetUI.PackageEngine.Classes.Manager.ManagerHelpers; +using UniGetUI.PackageEngine.Enums; +using UniGetUI.PackageEngine.Interfaces; +using UniGetUI.PackageEngine.ManagerClasses.Classes; +using UniGetUI.PackageEngine.ManagerClasses.Manager; +using UniGetUI.PackageEngine.PackageClasses; +using UniGetUI.PackageEngine.Structs; + +namespace UniGetUI.PackageEngine.Managers.HomebrewManager; + +/// +/// A ManagerSource whose display name is just the source name, without the "Manager: " prefix. +/// +internal sealed class HomebrewSource : ManagerSource +{ + public HomebrewSource(IPackageManager manager, string name, Uri url) + : base(manager, name, url) + { + AsString_DisplayName = name; + } +} + +public class Homebrew : PackageManager +{ + // Standard Homebrew installation paths, in priority order + private static readonly string[] BREW_PATHS = + [ + "/opt/homebrew/bin/brew", // Apple Silicon + "/usr/local/bin/brew", // Intel Mac + "/home/linuxbrew/.linuxbrew/bin/brew", // Linux + ]; + + public Homebrew() + { + Dependencies = []; + + Capabilities = new ManagerCapabilities + { + CanRunAsAdmin = false, + CanDownloadInstaller = false, + SupportsCustomSources = true, + Sources = new SourceCapabilities + { + KnowsPackageCount = false, + KnowsUpdateDate = false, + }, + SupportsProxy = ProxySupport.No, + SupportsProxyAuth = false, + KnowsPackageReleaseDate = PackageReleaseDateSupport.No, + }; + + Properties = new ManagerProperties + { + Id = "homebrew", + Name = "Homebrew", + Description = CoreTools.Translate( + "The Missing Package Manager for macOS (or Linux).
Contains: Formulae, Casks" + ), + IconId = IconType.Homebrew, + ColorIconId = "homebrew_color", + ExecutableFriendlyName = "brew", + InstallVerb = "install", + UpdateVerb = "upgrade", + UninstallVerb = "uninstall", + KnownSources = + [ + new HomebrewSource(this, "Homebrew", new Uri("https://github.com/Homebrew/homebrew-core")), + new HomebrewSource(this, "Homebrew Cask", new Uri("https://github.com/Homebrew/homebrew-cask")), + ], + DefaultSource = new HomebrewSource(this, "Homebrew", new Uri("https://github.com/Homebrew/homebrew-core")), + }; + + SourcesHelper = new HomebrewSourceHelper(this); + DetailsHelper = new HomebrewPkgDetailsHelper(this); + OperationHelper = new HomebrewPkgOperationHelper(this); + } + + // ── Executable discovery ─────────────────────────────────────────────── + + public override IReadOnlyList FindCandidateExecutableFiles() + { + var candidates = new List(CoreTools.WhichMultiple("brew")); + foreach (var path in BREW_PATHS) + { + if (File.Exists(path) && !candidates.Contains(path)) + candidates.Add(path); + } + return candidates; + } + + protected override void _loadManagerExecutableFile( + out bool found, + out string path, + out string callArguments) + { + (found, path) = GetExecutableFile(); + // Force ARM64 when brew is at the Apple Silicon prefix. Without this, + // .NET's posix_spawn may select the x86_64 slice of universal binaries + // (bash, ruby) in the brew script chain, causing Homebrew to detect a + // Rosetta 2 context even when UniGetUI itself is ARM64-native. + if (path == BREW_PATHS[0] + && OperatingSystem.IsMacOS() + && RuntimeInformation.OSArchitecture == System.Runtime.InteropServices.Architecture.Arm64) + { + callArguments = $"-arm64 {path}"; + path = "/usr/bin/arch"; + } + else + { + callArguments = ""; + } + } + + internal ProcessStartInfo MakeBrewStartInfo(string arguments) => new() + { + FileName = Status.ExecutablePath, + Arguments = Status.ExecutableCallArgs.Length > 0 + ? $"{Status.ExecutableCallArgs} {arguments}" + : arguments, + UseShellExecute = false, + RedirectStandardOutput = true, + RedirectStandardError = true, + CreateNoWindow = true, + }; + + protected override void _loadManagerVersion(out string version) + { + using var p = new Process { StartInfo = MakeBrewStartInfo("--version") }; + p.Start(); + // First line: "Homebrew 4.x.x" + version = p.StandardOutput.ReadLine()?.Replace("Homebrew ", "").Trim() ?? ""; + p.WaitForExit(); + } + + // ── Index refresh ────────────────────────────────────────────────────── + + public override void RefreshPackageIndexes() + { + using var p = new Process { StartInfo = MakeBrewStartInfo("update") }; + IProcessTaskLogger logger = TaskLogger.CreateNew(LoggableTaskType.RefreshIndexes, p); + p.Start(); + logger.AddToStdOut(p.StandardOutput.ReadToEnd()); + logger.AddToStdErr(p.StandardError.ReadToEnd()); + p.WaitForExit(); + logger.Close(p.ExitCode); + } + + // ── Package listing ──────────────────────────────────────────────────── + + protected override IReadOnlyList FindPackages_UnSafe(string query) + { + var packages = new List(); + + IManagerSource formulaeSource = SourcesHelper.Factory.GetSourceOrDefault("Homebrew"); + IManagerSource caskSource = SourcesHelper.Factory.GetSourceOrDefault("Homebrew Cask"); + IManagerSource currentSection = formulaeSource; + + using var p = new Process { StartInfo = MakeBrewStartInfo($"search {query}") }; + IProcessTaskLogger logger = TaskLogger.CreateNew(LoggableTaskType.FindPackages, p); + p.Start(); + + string? line; + while ((line = p.StandardOutput.ReadLine()) is not null) + { + logger.AddToStdOut(line); + if (line.StartsWith("==> Formulae")) { currentSection = formulaeSource; continue; } + if (line.StartsWith("==> Casks")) { currentSection = caskSource; continue; } + + foreach (var token in line.Split(' ', StringSplitOptions.RemoveEmptyEntries)) + { + var id = token.Trim(); + if (id.Length == 0) continue; + packages.Add(new Package( + CoreTools.FormatAsName(id), + id, + CoreTools.Translate("Latest"), + currentSection, + this)); + } + } + + logger.AddToStdErr(p.StandardError.ReadToEnd()); + p.WaitForExit(); + logger.Close(p.ExitCode); + return packages; + } + + protected override IReadOnlyList GetInstalledPackages_UnSafe() + { + var packages = new List(); + packages.AddRange(ListInstalledByType("--formula", "Homebrew")); + packages.AddRange(ListInstalledByType("--cask", "Homebrew Cask")); + return packages; + } + + private IReadOnlyList ListInstalledByType(string typeFlag, string sourceName) + { + var packages = new List(); + IManagerSource source = SourcesHelper.Factory.GetSourceOrDefault(sourceName); + + using var p = new Process { StartInfo = MakeBrewStartInfo($"list {typeFlag} --versions") }; + IProcessTaskLogger logger = TaskLogger.CreateNew(LoggableTaskType.ListInstalledPackages, p); + p.Start(); + + string? line; + while ((line = p.StandardOutput.ReadLine()) is not null) + { + logger.AddToStdOut(line); + var parts = line.Split(' ', StringSplitOptions.RemoveEmptyEntries); + if (parts.Length < 2) continue; + var id = parts[0].Trim(); + var version = parts[1].Trim(); + packages.Add(new Package(CoreTools.FormatAsName(id), id, version, source, this)); + } + + logger.AddToStdErr(p.StandardError.ReadToEnd()); + p.WaitForExit(); + logger.Close(p.ExitCode); + return packages; + } + + protected override IReadOnlyList GetAvailableUpdates_UnSafe() + { + var packages = new List(); + + // Build a lookup of installed packages to retrieve their sources + Dictionary installed = []; + foreach (var pkg in GetInstalledPackages()) + installed.TryAdd(pkg.Id, pkg); + + using var p = new Process { StartInfo = MakeBrewStartInfo("outdated --verbose") }; + IProcessTaskLogger logger = TaskLogger.CreateNew(LoggableTaskType.ListUpdates, p); + p.Start(); + + // Format: "name (old_version) < new_version" + var pattern = new Regex(@"^(\S+)\s+\(([^)]+)\)\s+<\s+(.+)$"); + string? line; + while ((line = p.StandardOutput.ReadLine()) is not null) + { + logger.AddToStdOut(line); + var m = pattern.Match(line); + if (!m.Success) continue; + + var id = m.Groups[1].Value.Trim(); + var oldVersion = m.Groups[2].Value.Trim(); + var newVersion = m.Groups[3].Value.Trim(); + + installed.TryGetValue(id, out var installedPkg); + var source = installedPkg?.Source + ?? SourcesHelper.Factory.GetSourceOrDefault("Homebrew"); + + packages.Add(new Package( + CoreTools.FormatAsName(id), + id, + oldVersion, + newVersion, + source, + this)); + } + + logger.AddToStdErr(p.StandardError.ReadToEnd()); + p.WaitForExit(); + logger.Close(p.ExitCode); + return packages; + } +} diff --git a/src/UniGetUI.PackageEngine.Managers.Homebrew/UniGetUI.PackageEngine.Managers.Homebrew.csproj b/src/UniGetUI.PackageEngine.Managers.Homebrew/UniGetUI.PackageEngine.Managers.Homebrew.csproj new file mode 100644 index 0000000..a0903da --- /dev/null +++ b/src/UniGetUI.PackageEngine.Managers.Homebrew/UniGetUI.PackageEngine.Managers.Homebrew.csproj @@ -0,0 +1,23 @@ + + + $(SharedTargetFrameworks) + + + + + + + + + + + + + + + + + + + + diff --git a/src/UniGetUI.PackageEngine.Managers.Npm/Helpers/NpmPackageIdentifier.cs b/src/UniGetUI.PackageEngine.Managers.Npm/Helpers/NpmPackageIdentifier.cs new file mode 100644 index 0000000..16a4303 --- /dev/null +++ b/src/UniGetUI.PackageEngine.Managers.Npm/Helpers/NpmPackageIdentifier.cs @@ -0,0 +1,48 @@ +namespace UniGetUI.PackageEngine.Managers.NpmManager; + +/// +/// Normalizes npm package ids that may represent aliases. +/// npm-aliased dependencies are reported by `npm outdated --json` and `npm list --json` +/// with ids shaped like "localName:targetName@range". Real npm package names cannot contain +/// a colon, so the presence of one identifies an alias. +/// +internal readonly record struct NpmPackageIdentifier(string LocalName, string TargetName, bool IsAlias) +{ + /// + /// Parses an npm package id into local and registry-facing names. + /// For non-aliased packages, LocalName and TargetName are the same. + /// + public static NpmPackageIdentifier Parse(string id) + { + int colonIndex = id.IndexOf(':'); + if (colonIndex <= 0) + { + return new NpmPackageIdentifier(id, id, false); + } + + string aliasLocalName = id[..colonIndex]; + string aliasTargetSpec = id[(colonIndex + 1)..]; + int versionIndex = aliasTargetSpec.LastIndexOf('@'); + string aliasTargetName = + versionIndex > 0 ? aliasTargetSpec[..versionIndex] : aliasTargetSpec; + + return new NpmPackageIdentifier(aliasLocalName, aliasTargetName, true); + } + + /// + /// Builds the npm install or update specifier for the parsed package id. + /// Aliases must be reconstructed as "localName@npm:targetName@version". + /// + public string GetInstallSpec(string version) => + IsAlias ? $"{LocalName}@npm:{TargetName}@{version}" : $"{LocalName}@{version}"; + + /// + /// Returns the registry-facing package name used by npm show and package URLs. + /// + public string GetRegistryName() => TargetName; + + /// + /// Returns the local on-disk package name used under node_modules. + /// + public string GetInstallLocationName() => LocalName; +} diff --git a/src/UniGetUI.PackageEngine.Managers.Npm/Helpers/NpmPkgDetailsHelper.cs b/src/UniGetUI.PackageEngine.Managers.Npm/Helpers/NpmPkgDetailsHelper.cs new file mode 100644 index 0000000..fbae4d9 --- /dev/null +++ b/src/UniGetUI.PackageEngine.Managers.Npm/Helpers/NpmPkgDetailsHelper.cs @@ -0,0 +1,240 @@ +using System.Diagnostics; +using System.Globalization; +using System.Text.Json.Nodes; +using UniGetUI.Core.IconEngine; +using UniGetUI.Core.Logging; +using UniGetUI.PackageEngine.Classes.Manager.BaseProviders; +using UniGetUI.PackageEngine.Enums; +using UniGetUI.PackageEngine.Interfaces; +using UniGetUI.PackageEngine.ManagerClasses.Classes; + +namespace UniGetUI.PackageEngine.Managers.NpmManager +{ + internal sealed class NpmPkgDetailsHelper : BasePkgDetailsHelper + { + public NpmPkgDetailsHelper(Npm manager) + : base(manager) { } + + protected override void GetDetails_UnSafe(IPackageDetails details) + { + try + { + var identifier = NpmPackageIdentifier.Parse(details.Package.Id); + details.InstallerType = "Tarball"; + details.ManifestUrl = new Uri( + $"https://www.npmjs.com/package/{identifier.GetRegistryName()}" + ); + details.ReleaseNotesUrl = new Uri( + $"https://www.npmjs.com/package/{identifier.GetRegistryName()}?activeTab=versions" + ); + + using Process p = new(); + p.StartInfo = new ProcessStartInfo + { + FileName = Manager.Status.ExecutablePath, + Arguments = + Manager.Status.ExecutableCallArgs + + " show " + + identifier.GetRegistryName() + + " --json", + UseShellExecute = false, + RedirectStandardOutput = true, + RedirectStandardError = true, + RedirectStandardInput = true, + CreateNoWindow = true, + WorkingDirectory = Environment.GetFolderPath( + Environment.SpecialFolder.UserProfile + ), + StandardOutputEncoding = System.Text.Encoding.UTF8, + }; + + IProcessTaskLogger logger = Manager.TaskLogger.CreateNew( + LoggableTaskType.LoadPackageDetails, + p + ); + p.Start(); + + string strContents = p.StandardOutput.ReadToEnd(); + logger.AddToStdOut(strContents); + JsonObject? contents = JsonNode.Parse(strContents) as JsonObject; + + details.License = contents?["license"]?.ToString(); + details.Description = contents?["description"]?.ToString(); + + if ( + Uri.TryCreate( + contents?["homepage"]?.ToString() ?? "", + UriKind.RelativeOrAbsolute, + out var homepageUrl + ) + ) + details.HomepageUrl = homepageUrl; + + details.Publisher = (contents?["maintainers"] as JsonArray)?[0]?.ToString(); + details.Author = contents?["author"]?.ToString(); + details.UpdateDate = contents?["time"]?[ + contents?["dist-tags"]?["latest"]?.ToString() ?? details.Package.VersionString + ]?.ToString(); + + if ( + Uri.TryCreate( + contents?["dist"]?["tarball"]?.ToString() ?? "", + UriKind.RelativeOrAbsolute, + out var installerUrl + ) + ) + details.InstallerUrl = installerUrl; + + if ( + int.TryParse( + contents?["dist"]?["unpackedSize"]?.ToString() ?? "", + NumberStyles.Any, + CultureInfo.InvariantCulture, + out int installerSize + ) + ) + details.InstallerSize = installerSize; + + details.InstallerHash = contents?["dist"]?["integrity"]?.ToString(); + + details.Dependencies.Clear(); + HashSet addedDeps = new(); + foreach (var rawDep in (contents?["dependencies"]?.AsObject() ?? [])) + { + if (addedDeps.Contains(rawDep.Key)) + continue; + addedDeps.Add(rawDep.Key); + + details.Dependencies.Add( + new() + { + Name = rawDep.Key, + Version = rawDep.Value?.GetValue() ?? "", + Mandatory = true, + } + ); + } + + foreach (var rawDep in (contents?["devDependencies"]?.AsObject() ?? [])) + { + if (addedDeps.Contains(rawDep.Key)) + continue; + addedDeps.Add(rawDep.Key); + + details.Dependencies.Add( + new() + { + Name = rawDep.Key, + Version = rawDep.Value?.GetValue() ?? "", + Mandatory = false, + } + ); + } + + foreach (var rawDep in (contents?["peerDependencies"]?.AsObject() ?? [])) + { + if (addedDeps.Contains(rawDep.Key)) + continue; + addedDeps.Add(rawDep.Key); + + details.Dependencies.Add( + new() + { + Name = rawDep.Key, + Version = rawDep.Value?.GetValue() ?? "", + Mandatory = false, + } + ); + } + + logger.AddToStdErr(p.StandardError.ReadToEnd()); + p.WaitForExit(); + logger.Close(p.ExitCode); + } + catch (Exception e) + { + Logger.Error(e); + } + + return; + } + + protected override CacheableIcon? GetIcon_UnSafe(IPackage package) + { + throw new NotImplementedException(); + } + + protected override IReadOnlyList GetScreenshots_UnSafe(IPackage package) + { + throw new NotImplementedException(); + } + + protected override string? GetInstallLocation_UnSafe(IPackage package) + { + var identifier = NpmPackageIdentifier.Parse(package.Id); + if (package.OverridenOptions.Scope is PackageScope.Local) + return Path.Join( + Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), + "node_modules", + identifier.GetInstallLocationName() + ); + // ApplicationData already resolves to the Roaming folder; npm's default global prefix + // is %AppData%\npm, so global modules live under %AppData%\npm\node_modules. + return Path.Join( + Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), + "npm", + "node_modules", + identifier.GetInstallLocationName() + ); + } + + protected override IReadOnlyList GetInstallableVersions_UnSafe(IPackage package) + { + var identifier = NpmPackageIdentifier.Parse(package.Id); + using Process p = new() + { + StartInfo = new ProcessStartInfo + { + FileName = Manager.Status.ExecutablePath, + Arguments = + Manager.Status.ExecutableCallArgs + + " show " + + identifier.GetRegistryName() + + " versions --json", + UseShellExecute = false, + RedirectStandardOutput = true, + RedirectStandardError = true, + RedirectStandardInput = true, + CreateNoWindow = true, + WorkingDirectory = Environment.GetFolderPath( + Environment.SpecialFolder.UserProfile + ), + StandardOutputEncoding = System.Text.Encoding.UTF8, + }, + }; + + IProcessTaskLogger logger = Manager.TaskLogger.CreateNew( + LoggableTaskType.LoadPackageVersions, + p + ); + p.Start(); + + string strContents = p.StandardOutput.ReadToEnd(); + logger.AddToStdOut(strContents); + JsonArray? rawVersions = JsonNode.Parse(strContents) as JsonArray; + + List versions = []; + foreach (JsonNode? raw_ver in rawVersions ?? []) + { + if (raw_ver is not null) + versions.Add(raw_ver.ToString()); + } + + logger.AddToStdErr(p.StandardError.ReadToEnd()); + p.WaitForExit(); + logger.Close(p.ExitCode); + + return versions; + } + } +} diff --git a/src/UniGetUI.PackageEngine.Managers.Npm/Helpers/NpmPkgOperationHelper.cs b/src/UniGetUI.PackageEngine.Managers.Npm/Helpers/NpmPkgOperationHelper.cs new file mode 100644 index 0000000..8cbe06e --- /dev/null +++ b/src/UniGetUI.PackageEngine.Managers.Npm/Helpers/NpmPkgOperationHelper.cs @@ -0,0 +1,118 @@ +using UniGetUI.PackageEngine.Classes.Manager.BaseProviders; +using UniGetUI.PackageEngine.Enums; +using UniGetUI.PackageEngine.Interfaces; +using UniGetUI.PackageEngine.Serializable; + +namespace UniGetUI.PackageEngine.Managers.NpmManager; + +internal sealed class NpmPkgOperationHelper : BasePkgOperationHelper +{ + public NpmPkgOperationHelper(Npm manager) + : base(manager) { } + + protected override IReadOnlyList _getOperationParameters( + IPackage package, + InstallOptions options, + OperationType operation + ) + { + // On Windows, npm runs through PowerShell (-Command), so single quotes act as + // PowerShell string delimiters and are stripped before reaching npm. + // On macOS/Linux, npm is called directly (no shell), so single quotes are passed + // literally and must NOT be included. + bool useShellQuotes = OperatingSystem.IsWindows(); + + List parameters = operation switch + { + OperationType.Install => + [ + Manager.Properties.InstallVerb, + FormatSpec( + ResolveInstallSpec(package.Id, options.Version == string.Empty ? package.VersionString : options.Version), + useShellQuotes + ), + ], + OperationType.Update => + [ + Manager.Properties.UpdateVerb, + FormatSpec(ResolveInstallSpec(package.Id, package.NewVersionString), useShellQuotes), + ], + OperationType.Uninstall => [Manager.Properties.UninstallVerb, ResolveLocalName(package.Id)], + _ => throw new InvalidDataException("Invalid package operation"), + }; + + if ( + package.OverridenOptions.Scope == PackageScope.Global + || ( + package.OverridenOptions.Scope is null + && options.InstallationScope == PackageScope.Global + ) + ) + parameters.Add("--global"); + + if (options.PreRelease) + parameters.AddRange(["--include", "dev"]); + + parameters.AddRange( + operation switch + { + OperationType.Update => options.CustomParameters_Update, + OperationType.Uninstall => options.CustomParameters_Uninstall, + _ => options.CustomParameters_Install, + } + ); + + return parameters; + } + + private static string FormatSpec(string spec, bool useShellQuotes) => + useShellQuotes ? $"'{spec}'" : spec; + + /// + /// npm-aliased dependencies (package.json entries like "eslint-v9": "npm:eslint@^9.x") + /// are reported by `npm outdated --json` / `npm list --json` with a package id shaped + /// like "eslint-v9:eslint@^9.x" -- the local alias name, a literal colon, then the raw + /// alias target specifier (see Npm.ParseAvailableUpdatesOutput / ParseInstalledPackagesOutput, + /// which pass that id straight through as package.Id). Real npm package names can never + /// contain a colon, so its presence in package.Id unambiguously identifies an alias. + /// + private static bool TryParseAlias(string id, out string localName, out string targetName) + { + int colonIndex = id.IndexOf(':'); + if (colonIndex <= 0) + { + localName = id; + targetName = ""; + return false; + } + + localName = id[..colonIndex]; + string targetSpec = id[(colonIndex + 1)..]; + int atIndex = targetSpec.LastIndexOf('@'); + targetName = atIndex > 0 ? targetSpec[..atIndex] : targetSpec; + return true; + } + + private static string ResolveLocalName(string id) => + TryParseAlias(id, out string localName, out _) ? localName : id; + + /// + /// Builds the npm install/update specifier for a package, preserving alias syntax + /// ("localName@npm:targetName@version") for aliased dependencies instead of treating + /// package.Id as a literal, directly-installable package name. + /// + private static string ResolveInstallSpec(string id, string version) => + TryParseAlias(id, out string localName, out string targetName) + ? $"{localName}@npm:{targetName}@{version}" + : $"{id}@{version}"; + + protected override OperationVeredict _getOperationResult( + IPackage package, + OperationType operation, + IReadOnlyList processOutput, + int returnCode + ) + { + return returnCode == 0 ? OperationVeredict.Success : OperationVeredict.Failure; + } +} diff --git a/src/UniGetUI.PackageEngine.Managers.Npm/InternalsVisibleTo.cs b/src/UniGetUI.PackageEngine.Managers.Npm/InternalsVisibleTo.cs new file mode 100644 index 0000000..eeb63da --- /dev/null +++ b/src/UniGetUI.PackageEngine.Managers.Npm/InternalsVisibleTo.cs @@ -0,0 +1,3 @@ +using System.Runtime.CompilerServices; + +[assembly: InternalsVisibleTo("UniGetUI.PackageEngine.Tests")] diff --git a/src/UniGetUI.PackageEngine.Managers.Npm/Npm.cs b/src/UniGetUI.PackageEngine.Managers.Npm/Npm.cs new file mode 100644 index 0000000..11430c0 --- /dev/null +++ b/src/UniGetUI.PackageEngine.Managers.Npm/Npm.cs @@ -0,0 +1,356 @@ +using System.Diagnostics; +using System.Text.Json.Nodes; +using UniGetUI.Core.Data; +using UniGetUI.Core.Logging; +using UniGetUI.Core.Tools; +using UniGetUI.Interface.Enums; +using UniGetUI.PackageEngine.Classes.Manager; +using UniGetUI.PackageEngine.Classes.Manager.ManagerHelpers; +using UniGetUI.PackageEngine.Enums; +using UniGetUI.PackageEngine.Interfaces; +using UniGetUI.PackageEngine.ManagerClasses.Classes; +using UniGetUI.PackageEngine.ManagerClasses.Manager; +using UniGetUI.PackageEngine.PackageClasses; +using UniGetUI.PackageEngine.Structs; + +namespace UniGetUI.PackageEngine.Managers.NpmManager +{ + public class Npm : PackageManager + { + public Npm() + { + Capabilities = new ManagerCapabilities + { + CanRunAsAdmin = true, + SupportsCustomVersions = true, + CanDownloadInstaller = true, + SupportsCustomScopes = true, + CanListDependencies = true, + SupportsPreRelease = true, + SupportsProxy = ProxySupport.No, + SupportsProxyAuth = false, + KnowsPackageReleaseDate = PackageReleaseDateSupport.Yes, + }; + + Properties = new ManagerProperties + { + Id = "npm", + Name = "Npm", + Description = CoreTools.Translate( + "Node JS's package manager. Full of libraries and other utilities that orbit the javascript world
Contains: Node javascript libraries and other related utilities" + ), + IconId = IconType.Node, + ColorIconId = "node_color", + ExecutableFriendlyName = "npm", + InstallVerb = "install", + UninstallVerb = "uninstall", + UpdateVerb = "install", + DefaultSource = new ManagerSource(this, "npm", new Uri("https://www.npmjs.com/")), + KnownSources = [new ManagerSource(this, "npm", new Uri("https://www.npmjs.com/"))], + }; + + DetailsHelper = new NpmPkgDetailsHelper(this); + OperationHelper = new NpmPkgOperationHelper(this); + } + + protected override IReadOnlyList FindPackages_UnSafe(string query) + { + using Process p = new() + { + StartInfo = new ProcessStartInfo + { + FileName = Status.ExecutablePath, + Arguments = Status.ExecutableCallArgs + " search \"" + query + "\" --json", + RedirectStandardOutput = true, + RedirectStandardError = true, + RedirectStandardInput = true, + UseShellExecute = false, + CreateNoWindow = true, + WorkingDirectory = Environment.GetFolderPath( + Environment.SpecialFolder.UserProfile + ), + StandardOutputEncoding = System.Text.Encoding.UTF8, + }, + }; + + IProcessTaskLogger logger = TaskLogger.CreateNew(LoggableTaskType.FindPackages, p); + p.Start(); + + string strContents = p.StandardOutput.ReadToEnd(); + logger.AddToStdOut(strContents); + logger.AddToStdErr(p.StandardError.ReadToEnd()); + p.WaitForExit(); + logger.Close(p.ExitCode); + + return ParseSearchOutput(strContents, DefaultSource, this); + } + + protected override IReadOnlyList GetAvailableUpdates_UnSafe() + { + List Packages = []; + foreach ( + var options in new OverridenInstallationOptions[] + { + new(PackageScope.Local), + new(PackageScope.Global), + } + ) + { + using Process p = new() + { + StartInfo = new ProcessStartInfo + { + FileName = Status.ExecutablePath, + Arguments = + Status.ExecutableCallArgs + + " outdated --json" + + (options.Scope == PackageScope.Global ? " --global" : ""), + RedirectStandardOutput = true, + RedirectStandardError = true, + RedirectStandardInput = true, + UseShellExecute = false, + CreateNoWindow = true, + WorkingDirectory = Environment.GetFolderPath( + Environment.SpecialFolder.UserProfile + ), + StandardOutputEncoding = System.Text.Encoding.UTF8, + }, + }; + + IProcessTaskLogger logger = TaskLogger.CreateNew(LoggableTaskType.ListUpdates, p); + p.Start(); + + string strContents = p.StandardOutput.ReadToEnd(); + logger.AddToStdOut(strContents); + Packages.AddRange(ParseAvailableUpdatesOutput(strContents, DefaultSource, this, options)); + + logger.AddToStdErr(p.StandardError.ReadToEnd()); + p.WaitForExit(); + logger.Close(p.ExitCode); + } + return Packages; + } + + protected override IReadOnlyList GetInstalledPackages_UnSafe() + { + List Packages = []; + foreach ( + var options in new OverridenInstallationOptions[] + { + new(PackageScope.Local), + new(PackageScope.Global), + } + ) + { + using Process p = new() + { + StartInfo = new ProcessStartInfo + { + FileName = Status.ExecutablePath, + Arguments = + Status.ExecutableCallArgs + + " list --json" + + (options.Scope == PackageScope.Global ? " --global" : ""), + RedirectStandardOutput = true, + RedirectStandardError = true, + RedirectStandardInput = true, + UseShellExecute = false, + CreateNoWindow = true, + WorkingDirectory = Environment.GetFolderPath( + Environment.SpecialFolder.UserProfile + ), + StandardOutputEncoding = System.Text.Encoding.UTF8, + }, + }; + + IProcessTaskLogger logger = TaskLogger.CreateNew( + LoggableTaskType.ListInstalledPackages, + p + ); + p.Start(); + + string strContents = p.StandardOutput.ReadToEnd(); + logger.AddToStdOut(strContents); + Packages.AddRange(ParseInstalledPackagesOutput(strContents, DefaultSource, this, options)); + + logger.AddToStdErr(p.StandardError.ReadToEnd()); + p.WaitForExit(); + logger.Close(p.ExitCode); + } + + return Packages; + } + + public override IReadOnlyList FindCandidateExecutableFiles() => + CoreTools.WhichMultiple(OperatingSystem.IsWindows() ? "npm.cmd" : "npm"); + + protected override void _loadManagerExecutableFile( + out bool found, + out string path, + out string callArguments + ) + { + var (_found, _executable) = GetExecutableFile(); + + found = _found; + + if (OperatingSystem.IsWindows()) + { + path = CoreData.PowerShell5; + callArguments = + $"-NoProfile -ExecutionPolicy Bypass -Command \"{_executable.Replace(" ", "` ")}\" "; + return; + } + + path = _executable; + callArguments = ""; + } + + protected override void _loadManagerVersion(out string version) + { + using Process process = new() + { + StartInfo = new ProcessStartInfo + { + FileName = Status.ExecutablePath, + Arguments = Status.ExecutableCallArgs + "--version", + UseShellExecute = false, + RedirectStandardOutput = true, + RedirectStandardError = true, + RedirectStandardInput = true, + CreateNoWindow = true, + WorkingDirectory = Environment.GetFolderPath( + Environment.SpecialFolder.UserProfile + ), + StandardOutputEncoding = System.Text.Encoding.UTF8, + }, + }; + process.Start(); + version = process.StandardOutput.ReadToEnd().Trim(); + process.WaitForExit(); + } + + internal static IReadOnlyList ParseSearchOutput( + string output, + IManagerSource source, + IPackageManager manager + ) + { + List packages = []; + + void TryAdd(JsonNode? node) + { + string? id = node?["name"]?.ToString(); + string? version = node?["version"]?.ToString(); + if (id is not null && version is not null) + packages.Add(new Package(CoreTools.FormatAsName(id), id, version, source, manager)); + } + + bool parsedAsArray = false; + int arrayStart = output.IndexOf('['); + if (arrayStart >= 0) + { + try + { + JsonArray? results = JsonNode.Parse(output[arrayStart..]) as JsonArray; + foreach (JsonNode? entry in results ?? []) + TryAdd(entry); + parsedAsArray = true; + } + catch (Exception e) + { + Logger.Warn($"npm search JSON array parse failed, falling back to NDJSON: {e.Message}"); + } + } + + if (!parsedAsArray) + { + foreach (string line in output.Split('\n')) + { + string trimmed = line.Trim(); + if (!trimmed.StartsWith("{")) + continue; + + try + { + TryAdd(JsonNode.Parse(trimmed)); + } + catch (Exception e) + { + Logger.Warn($"npm search NDJSON line parse failed: {e.Message}"); + } + } + } + + return packages; + } + + internal static IReadOnlyList ParseAvailableUpdatesOutput( + string output, + IManagerSource source, + IPackageManager manager, + OverridenInstallationOptions options + ) + { + List packages = []; + if (!output.Any()) + return packages; + + JsonObject? contents = JsonNode.Parse(output) as JsonObject; + foreach (var (packageId, packageData) in contents?.ToDictionary() ?? []) + { + string? version = packageData?["current"]?.ToString(); + string? newVersion = packageData?["latest"]?.ToString(); + if (version is not null && newVersion is not null) + { + packages.Add( + new Package( + CoreTools.FormatAsName(packageId), + packageId, + version, + newVersion, + source, + manager, + options + ) + ); + } + } + + return packages; + } + + internal static IReadOnlyList ParseInstalledPackagesOutput( + string output, + IManagerSource source, + IPackageManager manager, + OverridenInstallationOptions options + ) + { + List packages = []; + if (!output.Any()) + return packages; + + JsonObject? contents = (JsonNode.Parse(output) as JsonObject)?["dependencies"] as JsonObject; + foreach (var (packageId, packageData) in contents?.ToDictionary() ?? []) + { + string? version = packageData?["version"]?.ToString(); + if (version is not null) + { + packages.Add( + new Package( + CoreTools.FormatAsName(packageId), + packageId, + version, + source, + manager, + options + ) + ); + } + } + + return packages; + } + } +} diff --git a/src/UniGetUI.PackageEngine.Managers.Npm/UniGetUI.PackageEngine.Managers.Npm.csproj b/src/UniGetUI.PackageEngine.Managers.Npm/UniGetUI.PackageEngine.Managers.Npm.csproj new file mode 100644 index 0000000..cfa6fbf --- /dev/null +++ b/src/UniGetUI.PackageEngine.Managers.Npm/UniGetUI.PackageEngine.Managers.Npm.csproj @@ -0,0 +1,27 @@ + + + $(SharedTargetFrameworks) + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/UniGetUI.PackageEngine.Managers.Pacman/Helpers/PacmanPkgDetailsHelper.cs b/src/UniGetUI.PackageEngine.Managers.Pacman/Helpers/PacmanPkgDetailsHelper.cs new file mode 100644 index 0000000..ffec565 --- /dev/null +++ b/src/UniGetUI.PackageEngine.Managers.Pacman/Helpers/PacmanPkgDetailsHelper.cs @@ -0,0 +1,185 @@ +using System.Diagnostics; +using UniGetUI.Core.IconEngine; +using UniGetUI.PackageEngine.Classes.Manager.BaseProviders; +using UniGetUI.PackageEngine.Enums; +using UniGetUI.PackageEngine.Interfaces; +using UniGetUI.PackageEngine.ManagerClasses.Classes; + +namespace UniGetUI.PackageEngine.Managers.PacmanManager; + +internal sealed class PacmanPkgDetailsHelper : BasePkgDetailsHelper +{ + public PacmanPkgDetailsHelper(Pacman manager) + : base(manager) { } + + protected override void GetDetails_UnSafe(IPackageDetails details) + { + using var p = new Process + { + StartInfo = new ProcessStartInfo + { + FileName = Manager.Status.ExecutablePath, + Arguments = $"-Si {details.Package.Id}", + UseShellExecute = false, + RedirectStandardOutput = true, + RedirectStandardError = true, + CreateNoWindow = true, + }, + }; + + p.StartInfo.Environment["LANG"] = "C"; + p.StartInfo.Environment["LC_ALL"] = "C"; + IProcessTaskLogger logger = Manager.TaskLogger.CreateNew( + LoggableTaskType.LoadPackageDetails, p); + p.Start(); + + // "pacman -Si" outputs "Key : value" pairs (key padded with spaces). + // Multi-dep fields (Depends On, Optional Deps) wrap onto continuation lines: + // " : next-dep another-dep" + // Continuation lines have an empty key (all spaces before " : "). + string? line; + string lastKey = ""; + while ((line = p.StandardOutput.ReadLine()) is not null) + { + logger.AddToStdOut(line); + if (line.Length == 0) break; // blank line separates package records + + var colonIdx = line.IndexOf(" : ", StringComparison.Ordinal); + if (colonIdx <= 0) continue; + + var key = line[..colonIdx].Trim(); + var value = line[(colonIdx + 3)..].Trim(); + if (value == "None" || value.Length == 0) continue; + + if (key.Length == 0) + { + // Continuation line — append to whatever field was active + switch (lastKey) + { + case "Depends On": + foreach (var dep in value.Split(" ", StringSplitOptions.RemoveEmptyEntries)) + { + var depName = dep.Split(new[] { '>', '<', '=', ':' })[0].Trim(); + if (depName.Length > 0) + details.Dependencies.Add(new() { Name = depName, Version = "", Mandatory = true }); + } + break; + case "Optional Deps": + foreach (var dep in value.Split(" ", StringSplitOptions.RemoveEmptyEntries)) + { + var depName = dep.Split(':')[0].Trim(); + if (depName.Length > 0) + details.Dependencies.Add(new() { Name = depName, Version = "", Mandatory = false }); + } + break; + } + continue; + } + + lastKey = key; + switch (key) + { + case "URL": + if (Uri.TryCreate(value, UriKind.Absolute, out var url)) + details.HomepageUrl = url; + break; + case "Description": + details.Description = value; + break; + case "Licenses": + details.License = value; + break; + case "Packager": + details.Publisher = value; + break; + case "Download Size": + details.InstallerSize = ParsePacmanSize(value); + break; + case "Depends On": + details.Dependencies.Clear(); + foreach (var dep in value.Split(" ", StringSplitOptions.RemoveEmptyEntries)) + { + var depName = dep.Split(new[] { '>', '<', '=', ':' })[0].Trim(); + if (depName.Length > 0) + details.Dependencies.Add(new() { Name = depName, Version = "", Mandatory = true }); + } + break; + case "Optional Deps": + foreach (var dep in value.Split(" ", StringSplitOptions.RemoveEmptyEntries)) + { + var depName = dep.Split(':')[0].Trim(); + if (depName.Length > 0) + details.Dependencies.Add(new() { Name = depName, Version = "", Mandatory = false }); + } + break; + } + } + + logger.AddToStdErr(p.StandardError.ReadToEnd()); + p.WaitForExit(); + logger.Close(p.ExitCode); + } + + protected override CacheableIcon? GetIcon_UnSafe(IPackage package) + => throw new NotImplementedException(); + + protected override IReadOnlyList GetScreenshots_UnSafe(IPackage package) + => throw new NotImplementedException(); + + protected override string? GetInstallLocation_UnSafe(IPackage package) + { + using var p = new Process + { + StartInfo = new ProcessStartInfo + { + FileName = Manager.Status.ExecutablePath, + Arguments = $"-Ql {package.Id}", + UseShellExecute = false, + RedirectStandardOutput = true, + RedirectStandardError = true, + CreateNoWindow = true, + }, + }; + p.Start(); + + // Output format: " " — find the first directory entry. + // Must drain stdout fully before WaitForExit to avoid a pipe-full deadlock + // on packages with thousands of file entries (e.g. linux-firmware). + string? result = null; + string? line; + while ((line = p.StandardOutput.ReadLine()) is not null) + { + if (result is not null) continue; + var spaceIdx = line.IndexOf(' '); + if (spaceIdx < 0) continue; + var path = line[(spaceIdx + 1)..].Trim(); + if (Directory.Exists(path)) + result = path; + } + + p.StandardError.ReadToEnd(); + p.WaitForExit(); + return result; + } + + protected override IReadOnlyList GetInstallableVersions_UnSafe(IPackage package) + => throw new InvalidOperationException("Pacman does not support installing arbitrary versions"); + + private static long ParsePacmanSize(string value) + { + // Format: "2.34 MiB", "234.56 KiB", "1.20 GiB" + var parts = value.Split(' '); + if (parts.Length < 2 || !double.TryParse(parts[0], + System.Globalization.NumberStyles.Any, + System.Globalization.CultureInfo.InvariantCulture, out var num)) + return 0; + + return parts[1] switch + { + "KiB" or "kB" => (long)(num * 1024), + "MiB" or "MB" => (long)(num * 1024 * 1024), + "GiB" or "GB" => (long)(num * 1024 * 1024 * 1024), + _ => (long)num, + }; + } +} diff --git a/src/UniGetUI.PackageEngine.Managers.Pacman/Helpers/PacmanPkgOperationHelper.cs b/src/UniGetUI.PackageEngine.Managers.Pacman/Helpers/PacmanPkgOperationHelper.cs new file mode 100644 index 0000000..912f2fb --- /dev/null +++ b/src/UniGetUI.PackageEngine.Managers.Pacman/Helpers/PacmanPkgOperationHelper.cs @@ -0,0 +1,53 @@ +using UniGetUI.PackageEngine.Classes.Manager.BaseProviders; +using UniGetUI.PackageEngine.Enums; +using UniGetUI.PackageEngine.Interfaces; +using UniGetUI.PackageEngine.Serializable; + +namespace UniGetUI.PackageEngine.Managers.PacmanManager; + +internal sealed class PacmanPkgOperationHelper : BasePkgOperationHelper +{ + public PacmanPkgOperationHelper(Pacman manager) + : base(manager) { } + + protected override IReadOnlyList _getOperationParameters( + IPackage package, + InstallOptions options, + OperationType operation) + { + // pacman always requires root — force elevation via InstallOptions (reference type, persists) + options.RunAsAdministrator = true; + + List parameters = + [ + operation switch + { + OperationType.Install => Manager.Properties.InstallVerb, + OperationType.Update => Manager.Properties.UpdateVerb, + OperationType.Uninstall => Manager.Properties.UninstallVerb, + _ => throw new InvalidDataException("Invalid package operation"), + }, + "--noconfirm", + package.Id, + ]; + + parameters.AddRange( + operation switch + { + OperationType.Update => options.CustomParameters_Update, + OperationType.Uninstall => options.CustomParameters_Uninstall, + _ => options.CustomParameters_Install, + }); + + return parameters; + } + + protected override OperationVeredict _getOperationResult( + IPackage package, + OperationType operation, + IReadOnlyList processOutput, + int returnCode) + { + return returnCode == 0 ? OperationVeredict.Success : OperationVeredict.Failure; + } +} diff --git a/src/UniGetUI.PackageEngine.Managers.Pacman/Pacman.cs b/src/UniGetUI.PackageEngine.Managers.Pacman/Pacman.cs new file mode 100644 index 0000000..944db2d --- /dev/null +++ b/src/UniGetUI.PackageEngine.Managers.Pacman/Pacman.cs @@ -0,0 +1,257 @@ +using System.Diagnostics; +using UniGetUI.Core.Tools; +using UniGetUI.Interface.Enums; +using UniGetUI.PackageEngine.Classes.Manager; +using UniGetUI.PackageEngine.Classes.Manager.ManagerHelpers; +using UniGetUI.PackageEngine.Enums; +using UniGetUI.PackageEngine.Interfaces; +using UniGetUI.PackageEngine.ManagerClasses.Classes; +using UniGetUI.PackageEngine.ManagerClasses.Manager; +using UniGetUI.PackageEngine.PackageClasses; +using UniGetUI.PackageEngine.Structs; + +namespace UniGetUI.PackageEngine.Managers.PacmanManager; + +public class Pacman : PackageManager +{ + public Pacman() + { + Dependencies = []; + + Capabilities = new ManagerCapabilities + { + CanRunAsAdmin = true, + CanSkipIntegrityChecks = false, + SupportsCustomSources = false, + SupportsProxy = ProxySupport.No, + SupportsProxyAuth = false, + KnowsPackageReleaseDate = PackageReleaseDateSupport.No, + }; + + Properties = new ManagerProperties + { + Id = "pacman", + Name = "Pacman", + Description = CoreTools.Translate( + "The default package manager for Arch Linux and its derivatives.
Contains: Arch Linux packages" + ), + IconId = IconType.Pacman, + ColorIconId = "pacman", + ExecutableFriendlyName = "pacman", + InstallVerb = "-S", + UpdateVerb = "-S", + UninstallVerb = "-Rs", + DefaultSource = new ManagerSource(this, "arch", new Uri("https://archlinux.org/packages/")), + KnownSources = [new ManagerSource(this, "arch", new Uri("https://archlinux.org/packages/"))], + }; + + DetailsHelper = new PacmanPkgDetailsHelper(this); + OperationHelper = new PacmanPkgOperationHelper(this); + } + + // ── Executable discovery ─────────────────────────────────────────────── + + public override IReadOnlyList FindCandidateExecutableFiles() + { + var candidates = new List(CoreTools.WhichMultiple("pacman")); + foreach (var path in new[] { "/usr/bin/pacman", "/usr/local/bin/pacman" }) + { + if (File.Exists(path) && !candidates.Contains(path)) + candidates.Add(path); + } + return candidates; + } + + protected override void _loadManagerExecutableFile( + out bool found, + out string path, + out string callArguments) + { + (found, path) = GetExecutableFile(); + callArguments = ""; + } + + protected override void _loadManagerVersion(out string version) + { + using var p = new Process + { + StartInfo = new ProcessStartInfo + { + FileName = Status.ExecutablePath, + Arguments = "-Q pacman", + UseShellExecute = false, + RedirectStandardOutput = true, + RedirectStandardError = true, + CreateNoWindow = true, + }, + }; + p.Start(); + // First line: "pacman X.Y.Z-N" + var line = p.StandardOutput.ReadLine()?.Trim() ?? ""; + var parts = line.Split(' '); + version = parts.Length >= 2 ? parts[1] : line; + p.StandardOutput.ReadToEnd(); + p.StandardError.ReadToEnd(); + p.WaitForExit(); + } + + // ── Index refresh ────────────────────────────────────────────────────── + + public override void RefreshPackageIndexes() + { + using var p = new Process + { + StartInfo = new ProcessStartInfo + { + FileName = Status.ExecutablePath, + Arguments = "-Sy", + UseShellExecute = false, + RedirectStandardOutput = true, + RedirectStandardError = true, + CreateNoWindow = true, + }, + }; + IProcessTaskLogger logger = TaskLogger.CreateNew(LoggableTaskType.RefreshIndexes, p); + p.Start(); + logger.AddToStdOut(p.StandardOutput.ReadToEnd()); + logger.AddToStdErr(p.StandardError.ReadToEnd()); + p.WaitForExit(); + logger.Close(p.ExitCode); + } + + // ── Package listing ──────────────────────────────────────────────────── + + protected override IReadOnlyList FindPackages_UnSafe(string query) + { + var packages = new List(); + + using var p = new Process + { + StartInfo = new ProcessStartInfo + { + FileName = Status.ExecutablePath, + Arguments = $"-Ss {query}", + UseShellExecute = false, + RedirectStandardOutput = true, + RedirectStandardError = true, + CreateNoWindow = true, + }, + }; + IProcessTaskLogger logger = TaskLogger.CreateNew(LoggableTaskType.FindPackages, p); + p.Start(); + + // Output format: "/ [groups]\n " + // Name lines start at column 0; description lines are indented. + string? line; + while ((line = p.StandardOutput.ReadLine()) is not null) + { + logger.AddToStdOut(line); + if (line.Length == 0 || line.StartsWith(' ')) continue; + + var slashIdx = line.IndexOf('/'); + if (slashIdx < 0) continue; + + var afterSlash = line[(slashIdx + 1)..]; + var spaceIdx = afterSlash.IndexOf(' '); + if (spaceIdx <= 0) continue; + + var id = afterSlash[..spaceIdx]; + packages.Add(new Package( + CoreTools.FormatAsName(id), + id, + CoreTools.Translate("Latest"), + Properties.DefaultSource!, + this)); + } + + logger.AddToStdErr(p.StandardError.ReadToEnd()); + p.WaitForExit(); + // pacman -Ss exits 1 when no packages match the query — not an error + logger.Close(p.ExitCode == 1 && packages.Count == 0 ? 0 : p.ExitCode); + return packages; + } + + protected override IReadOnlyList GetInstalledPackages_UnSafe() + { + var packages = new List(); + + using var p = new Process + { + StartInfo = new ProcessStartInfo + { + FileName = Status.ExecutablePath, + Arguments = "-Q", + UseShellExecute = false, + RedirectStandardOutput = true, + RedirectStandardError = true, + CreateNoWindow = true, + }, + }; + IProcessTaskLogger logger = TaskLogger.CreateNew(LoggableTaskType.ListInstalledPackages, p); + p.Start(); + + // Output format: " " + string? line; + while ((line = p.StandardOutput.ReadLine()) is not null) + { + logger.AddToStdOut(line); + var parts = line.Split(' ', StringSplitOptions.RemoveEmptyEntries); + if (parts.Length < 2) continue; + + packages.Add(new Package( + CoreTools.FormatAsName(parts[0]), + parts[0], + parts[1], + Properties.DefaultSource!, + this)); + } + + logger.AddToStdErr(p.StandardError.ReadToEnd()); + p.WaitForExit(); + logger.Close(p.ExitCode); + return packages; + } + + protected override IReadOnlyList GetAvailableUpdates_UnSafe() + { + var packages = new List(); + + using var p = new Process + { + StartInfo = new ProcessStartInfo + { + FileName = Status.ExecutablePath, + Arguments = "-Qu", + UseShellExecute = false, + RedirectStandardOutput = true, + RedirectStandardError = true, + CreateNoWindow = true, + }, + }; + IProcessTaskLogger logger = TaskLogger.CreateNew(LoggableTaskType.ListUpdates, p); + p.Start(); + + // Output format: " -> " + string? line; + while ((line = p.StandardOutput.ReadLine()) is not null) + { + logger.AddToStdOut(line); + var parts = line.Split(' ', StringSplitOptions.RemoveEmptyEntries); + if (parts.Length < 4 || parts[2] != "->") continue; + + packages.Add(new Package( + CoreTools.FormatAsName(parts[0]), + parts[0], + parts[1], + parts[3], + Properties.DefaultSource!, + this)); + } + + logger.AddToStdErr(p.StandardError.ReadToEnd()); + p.WaitForExit(); + // pacman -Qu exits 1 when there are no upgradable packages — not an error + logger.Close(p.ExitCode == 1 && packages.Count == 0 ? 0 : p.ExitCode); + return packages; + } +} diff --git a/src/UniGetUI.PackageEngine.Managers.Pacman/UniGetUI.PackageEngine.Managers.Pacman.csproj b/src/UniGetUI.PackageEngine.Managers.Pacman/UniGetUI.PackageEngine.Managers.Pacman.csproj new file mode 100644 index 0000000..a0903da --- /dev/null +++ b/src/UniGetUI.PackageEngine.Managers.Pacman/UniGetUI.PackageEngine.Managers.Pacman.csproj @@ -0,0 +1,23 @@ + + + $(SharedTargetFrameworks) + + + + + + + + + + + + + + + + + + + + diff --git a/src/UniGetUI.PackageEngine.Managers.Pip/Helpers/PipPkgDetailsHelper.cs b/src/UniGetUI.PackageEngine.Managers.Pip/Helpers/PipPkgDetailsHelper.cs new file mode 100644 index 0000000..70b753a --- /dev/null +++ b/src/UniGetUI.PackageEngine.Managers.Pip/Helpers/PipPkgDetailsHelper.cs @@ -0,0 +1,192 @@ +using System.Diagnostics; +using System.Text.Json.Nodes; +using UniGetUI.Core.Data; +using UniGetUI.Core.IconEngine; +using UniGetUI.Core.Tools; +using UniGetUI.PackageEngine.Classes.Manager.BaseProviders; +using UniGetUI.PackageEngine.Enums; +using UniGetUI.PackageEngine.Interfaces; +using UniGetUI.PackageEngine.ManagerClasses.Classes; + +namespace UniGetUI.PackageEngine.Managers.PipManager +{ + internal sealed class PipPkgDetailsHelper : BasePkgDetailsHelper + { + public PipPkgDetailsHelper(Pip manager) + : base(manager) { } + + protected override void GetDetails_UnSafe(IPackageDetails details) + { + INativeTaskLogger logger = Manager.TaskLogger.CreateNew( + LoggableTaskType.LoadPackageDetails + ); + + using HttpClient client = new(CoreTools.GenericHttpClientParameters); + client.DefaultRequestHeaders.UserAgent.ParseAdd(CoreData.UserAgentString); + using var request = new HttpRequestMessage( + HttpMethod.Get, + $"https://pypi.org/pypi/{details.Package.Id}/json" + ); + using HttpResponseMessage response = client.Send(request); + response.EnsureSuccessStatusCode(); + string JsonString = response.Content.ReadAsStringAsync().GetAwaiter().GetResult(); + + JsonObject? contents = JsonNode.Parse(JsonString) as JsonObject; + + if (contents?["info"] is JsonObject info) + { + details.Description = info["summary"]?.ToString(); + details.Author = info["author"]?.ToString(); + details.Publisher = info["maintainer"]?.ToString(); + details.License = info["license"]?.ToString(); + + if ( + Uri.TryCreate( + info["home_page"]?.ToString(), + UriKind.RelativeOrAbsolute, + out var homepageUrl + ) + ) + details.HomepageUrl = homepageUrl; + + if ( + Uri.TryCreate( + info["package_url"]?.ToString(), + UriKind.RelativeOrAbsolute, + out var packageUrl + ) + ) + details.ManifestUrl = packageUrl; + + if (info["classifiers"] is JsonArray classifiers) + { + List Tags = []; + foreach (string? line in classifiers) + { + if (line?.Contains("License ::") ?? false) + { + details.License = line.Split("::")[^1].Trim(); + } + else if (line?.Contains("Topic ::") ?? false) + { + if (!Tags.Contains(line.Split("::")[^1].Trim())) + Tags.Add(line.Split("::")[^1].Trim()); + } + } + details.Tags = Tags.ToArray(); + } + + details.Dependencies.Clear(); + foreach (var rawDep in (info?["requires_dist"]?.AsArray() ?? [])) + { + string line = rawDep?.GetValue().Split(';')[0] ?? ""; + string name = line.Split(['>', '<', '=', '!'])[0]; + details.Dependencies.Add( + new() + { + Name = name, + Version = line[name.Length..], + Mandatory = true, + } + ); + } + } + + JsonObject? url = contents?["url"] as JsonObject; + url ??= (contents?["urls"] as JsonArray)?[0] as JsonObject; + + if (url is not null) + { + if (url["digests"] is JsonObject digests) + details.InstallerHash = digests["sha256"]?.ToString(); + + if ( + Uri.TryCreate( + url["url"]?.ToString(), + UriKind.RelativeOrAbsolute, + out var installerUrl + ) + ) + { + details.InstallerType = url["url"] + ?.ToString() + .Split('.')[^1] + .Replace("whl", "Wheel"); + details.InstallerUrl = installerUrl; + details.InstallerSize = CoreTools.GetFileSizeAsLong(installerUrl); + } + + details.UpdateDate = url["upload_time"]?.ToString(); + } + + logger.Close(0); + } + + protected override CacheableIcon? GetIcon_UnSafe(IPackage package) + { + throw new NotImplementedException(); + } + + protected override IReadOnlyList GetScreenshots_UnSafe(IPackage package) + { + throw new NotImplementedException(); + } + + protected override string? GetInstallLocation_UnSafe(IPackage package) + { + var full_path = Path.Join( + Path.GetDirectoryName(Manager.Status.ExecutablePath), + "Lib", + "site-packages", + package.Id + ); + return Directory.Exists(full_path) ? full_path : Path.GetDirectoryName(full_path); + } + + protected override IReadOnlyList GetInstallableVersions_UnSafe(IPackage package) + { + using Process p = new() + { + StartInfo = new ProcessStartInfo + { + FileName = Manager.Status.ExecutablePath, + Arguments = + Manager.Status.ExecutableCallArgs + + " index versions " + + package.Id + + " " + + Pip.GetProxyArgument(), + RedirectStandardOutput = true, + RedirectStandardInput = true, + RedirectStandardError = true, + UseShellExecute = false, + CreateNoWindow = true, + StandardOutputEncoding = System.Text.Encoding.UTF8, + }, + }; + + IProcessTaskLogger logger = Manager.TaskLogger.CreateNew( + LoggableTaskType.LoadPackageVersions, + p + ); + p.Start(); + + string? line; + string[] result = []; + while ((line = p.StandardOutput.ReadLine()) is not null) + { + logger.AddToStdOut(line); + if (line.Contains("Available versions:")) + { + result = line.Replace("Available versions:", "").Trim().Split(", "); + } + } + + logger.AddToStdErr(p.StandardError.ReadToEnd()); + p.WaitForExit(); + logger.Close(p.ExitCode); + + return result; + } + } +} diff --git a/src/UniGetUI.PackageEngine.Managers.Pip/Helpers/PipPkgOperationHelper.cs b/src/UniGetUI.PackageEngine.Managers.Pip/Helpers/PipPkgOperationHelper.cs new file mode 100644 index 0000000..9375b3d --- /dev/null +++ b/src/UniGetUI.PackageEngine.Managers.Pip/Helpers/PipPkgOperationHelper.cs @@ -0,0 +1,109 @@ +using UniGetUI.PackageEngine.Classes.Manager.BaseProviders; +using UniGetUI.PackageEngine.Enums; +using UniGetUI.PackageEngine.Interfaces; +using UniGetUI.PackageEngine.Serializable; + +namespace UniGetUI.PackageEngine.Managers.PipManager; + +internal sealed class PipPkgOperationHelper : BasePkgOperationHelper +{ + public PipPkgOperationHelper(Pip manager) + : base(manager) { } + + protected override IReadOnlyList _getOperationParameters( + IPackage package, + InstallOptions options, + OperationType operation + ) + { + List parameters = + [ + operation switch + { + OperationType.Install => Manager.Properties.InstallVerb, + OperationType.Update => Manager.Properties.UpdateVerb, + OperationType.Uninstall => Manager.Properties.UninstallVerb, + _ => throw new InvalidDataException("Invalid package operation"), + }, + ]; + parameters.AddRange([ + options.Version.Any() ? $"{package.Id}=={options.Version}" : package.Id, + "--no-input", + "--no-color", + "--no-cache", + ]); + + if (operation is OperationType.Uninstall) + { + parameters.Add("--yes"); + } + else + { + if (options.PreRelease) + parameters.Add("--pre"); + + if ( + package.OverridenOptions.Scope == PackageScope.User + || ( + package.OverridenOptions.Scope is null + && options.InstallationScope == PackageScope.User + ) + ) + parameters.Add("--user"); + } + + if (package.OverridenOptions.Pip_BreakSystemPackages) + parameters.Add("--break-system-packages"); + + parameters.Add(Pip.GetProxyArgument()); + + parameters.AddRange( + operation switch + { + OperationType.Update => options.CustomParameters_Update, + OperationType.Uninstall => options.CustomParameters_Uninstall, + _ => options.CustomParameters_Install, + } + ); + + return parameters; + } + + protected override OperationVeredict _getOperationResult( + IPackage package, + OperationType operation, + IReadOnlyList processOutput, + int returnCode + ) + { + if (returnCode == 0) + { + return OperationVeredict.Success; + } + + string output_string = string.Join("\n", processOutput); + + if (output_string.Contains("externally-managed-environment")) + { + if (!package.OverridenOptions.Pip_BreakSystemPackages) + { + package.OverridenOptions.Pip_BreakSystemPackages = true; + return OperationVeredict.AutoRetry; + } + + if (package.OverridenOptions.Scope != PackageScope.User) + { + package.OverridenOptions.Scope = PackageScope.User; + return OperationVeredict.AutoRetry; + } + } + + if (output_string.Contains("--user") && package.OverridenOptions.Scope != PackageScope.User) + { + package.OverridenOptions.Scope = PackageScope.User; + return OperationVeredict.AutoRetry; + } + + return OperationVeredict.Failure; + } +} diff --git a/src/UniGetUI.PackageEngine.Managers.Pip/InternalsVisibleTo.cs b/src/UniGetUI.PackageEngine.Managers.Pip/InternalsVisibleTo.cs new file mode 100644 index 0000000..eeb63da --- /dev/null +++ b/src/UniGetUI.PackageEngine.Managers.Pip/InternalsVisibleTo.cs @@ -0,0 +1,3 @@ +using System.Runtime.CompilerServices; + +[assembly: InternalsVisibleTo("UniGetUI.PackageEngine.Tests")] diff --git a/src/UniGetUI.PackageEngine.Managers.Pip/Pip.cs b/src/UniGetUI.PackageEngine.Managers.Pip/Pip.cs new file mode 100644 index 0000000..a1aac9e --- /dev/null +++ b/src/UniGetUI.PackageEngine.Managers.Pip/Pip.cs @@ -0,0 +1,551 @@ +using System.Diagnostics; +using System.Text.Json.Nodes; +using System.Text.RegularExpressions; +using UniGetUI.Core.Data; +using UniGetUI.Core.Logging; +using UniGetUI.Core.SettingsEngine; +using UniGetUI.Core.Tools; +using UniGetUI.Interface.Enums; +using UniGetUI.PackageEngine.Classes.Manager; +using UniGetUI.PackageEngine.Enums; +using UniGetUI.PackageEngine.Interfaces; +using UniGetUI.PackageEngine.ManagerClasses.Classes; +using UniGetUI.PackageEngine.ManagerClasses.Manager; +using UniGetUI.PackageEngine.PackageClasses; + +namespace UniGetUI.PackageEngine.Managers.PipManager +{ + public class Pip : PackageManager + { + public static string[] FALSE_PACKAGE_IDS = + [ + "", + "WARNING:", + "[notice]", + "Package", + "DEPRECATION:", + ]; + public static string[] FALSE_PACKAGE_VERSIONS = ["", "Ignoring", "invalid"]; + + public Pip() + { + Dependencies = []; + /*Dependencies = [ + // parse_pip_search is required for pip package finding to work + new ManagerDependency( + "parse-pip-search", + CoreData.PowerShell5, + "-ExecutionPolicy Bypass -NoLogo -NoProfile -Command \"& {python.exe " + + "-m pip install parse_pip_search; if($error.count -ne 0){pause}}\"", + "python -m pip install parse_pip_search", + async () => + { + bool found = (await CoreTools.WhichAsync("parse_pip_search.exe")).Item1; + if (found) return true; + else if (Status.ExecutablePath.Contains("WindowsApps\\python.exe")) + { + Logger.Warn("parse_pip_search could was not found but the user will not be prompted to install it."); + Logger.Warn("NOTE: Microsoft Store python is not fully supported on UniGetUI"); + return true; + } + else return false; + } + ) + ];*/ + + Capabilities = new ManagerCapabilities + { + CanRunAsAdmin = true, + SupportsCustomVersions = true, + SupportsCustomScopes = true, + CanDownloadInstaller = true, + SupportsPreRelease = true, + CanListDependencies = true, + SupportsProxy = ProxySupport.Yes, + SupportsProxyAuth = true, + KnowsPackageReleaseDate = PackageReleaseDateSupport.Yes, + }; + + Properties = new ManagerProperties + { + Id = "pip", + Name = "Pip", + Description = CoreTools.Translate( + "Python's library manager. Full of python libraries and other python-related utilities
Contains: Python libraries and related utilities" + ), + IconId = IconType.Python, + ColorIconId = "pip_color", + ExecutableFriendlyName = "pip", + InstallVerb = "install", + UninstallVerb = "uninstall", + UpdateVerb = "install --upgrade", + DefaultSource = new ManagerSource(this, "pip", new Uri("https://pypi.org/")), + KnownSources = [new ManagerSource(this, "pip", new Uri("https://pypi.org/"))], + }; + + DetailsHelper = new PipPkgDetailsHelper(this); + OperationHelper = new PipPkgOperationHelper(this); + } + + public static string GetProxyArgument() + { + if (!Settings.Get(Settings.K.EnableProxy)) + return ""; + var proxyUri = Settings.GetProxyUrl(); + if (proxyUri is null) + return ""; + + if (Settings.Get(Settings.K.EnableProxyAuth) is false) + return $"--proxy {proxyUri.ToString()}"; + + var creds = Settings.GetProxyCredentials(); + if (creds is null) + return $"--proxy {proxyUri.ToString()}"; + + return $"--proxy {proxyUri.Scheme}://{Uri.EscapeDataString(creds.UserName)}:{Uri.EscapeDataString(creds.Password)}" + + $"@{proxyUri.AbsoluteUri.Replace($"{proxyUri.Scheme}://", "")}"; + } + + // In-memory cache of all PyPI package names, shared across searches + private static string[]? _cachedNames; + private static DateTime _cacheTimestamp = DateTime.MinValue; + private static readonly object _cacheLock = new(); + private const int CacheMaxAgeHours = 24; + private const int MaxSearchResults = 20; + + // Shared HTTP client and bounded concurrency for version fetches + private static readonly HttpClient _httpClient = CreateSharedHttpClient(); + private static readonly SemaphoreSlim _versionFetchSemaphore = new(6, 6); + + private static HttpClient CreateSharedHttpClient() + { + var client = new HttpClient(CoreTools.GenericHttpClientParameters); + client.DefaultRequestHeaders.UserAgent.ParseAdd(CoreData.UserAgentString); + return client; + } + + protected override IReadOnlyList FindPackages_UnSafe(string query) + { + INativeTaskLogger logger = TaskLogger.CreateNew(LoggableTaskType.FindPackages); + try + { + string[] allNames = GetOrRefreshIndex(logger); + + string[] matches = SelectSearchMatches(query, allNames); + + logger.Log($"Matched {matches.Length} packages for query '{query}'"); + + // Fetch latest version for each match in parallel, bounded to 6 concurrent requests + var versionTasks = matches + .Select(FetchLatestVersionAsync) + .ToArray(); + Task.WhenAll(versionTasks).GetAwaiter().GetResult(); + + List packages = []; + for (int i = 0; i < matches.Length; i++) + { + string version = versionTasks[i].Result ?? "latest"; + packages.Add(new Package( + CoreTools.FormatAsName(matches[i]), + matches[i], + version, + DefaultSource, + this, + new(PackageScope.Global) + )); + } + + logger.Close(0); + return packages; + } + catch (Exception e) + { + logger.Error(e); + logger.Close(1); + throw; + } + } + + private static string[] GetOrRefreshIndex(INativeTaskLogger logger) + { + lock (_cacheLock) + { + if (_cachedNames is not null && (DateTime.Now - _cacheTimestamp).TotalHours < CacheMaxAgeHours) + return _cachedNames; + } + + string cacheFile = Path.Join(CoreData.UniGetUICacheDirectory_Data, "pip_simple_index.cache"); + + // Use file cache if fresh enough + if (File.Exists(cacheFile) && (DateTime.Now - File.GetLastWriteTime(cacheFile)).TotalHours < CacheMaxAgeHours) + { + logger.Log($"Loading PyPI index from file cache ({File.GetLastWriteTime(cacheFile):g})"); + string[] cached = File.ReadAllLines(cacheFile); + if (cached.Length > 0) + { + lock (_cacheLock) { _cachedNames = cached; _cacheTimestamp = File.GetLastWriteTime(cacheFile); } + return cached; + } + logger.Error("PyPI index file cache was empty, re-downloading..."); + } + + // Download fresh index + logger.Log("Downloading PyPI simple index (one-time ~38 MB download, cached for 24 h)..."); + using HttpClient client = new(CoreTools.GenericHttpClientParameters); + client.DefaultRequestHeaders.UserAgent.ParseAdd(CoreData.UserAgentString); + client.DefaultRequestHeaders.Add("Accept", "application/vnd.pypi.simple.v1+json"); + + using var request = new HttpRequestMessage(HttpMethod.Get, "https://pypi.org/simple/"); + using HttpResponseMessage response = client.Send(request); + if (!response.IsSuccessStatusCode) + throw new HttpRequestException($"PyPI simple index returned {(int)response.StatusCode} {response.ReasonPhrase}"); + + string json = response.Content.ReadAsStringAsync().GetAwaiter().GetResult(); + string[] names = ParseSimpleIndexProjectNames(json); + + logger.Log($"Downloaded {names.Length} package names from PyPI"); + + // Update memory cache before attempting file write so searches work even if file write fails + lock (_cacheLock) { _cachedNames = names; _cacheTimestamp = DateTime.Now; } + + try + { + Directory.CreateDirectory(Path.GetDirectoryName(cacheFile)!); + File.WriteAllLines(cacheFile, names); + } + catch (Exception e) + { + logger.Error($"Could not write PyPI index file cache to {cacheFile}: {e.Message}"); + } + + return names; + } + + internal static string[] ParseSimpleIndexProjectNames(string json) + { + var projects = (JsonNode.Parse(json) as JsonObject)?["projects"] as JsonArray; + string[] names = projects? + .Select(p => p?["name"]?.GetValue()) + .Where(n => !string.IsNullOrEmpty(n)) + .Select(n => n!) + .ToArray() ?? []; + + if (names.Length == 0) + throw new InvalidDataException("PyPI simple index returned 0 packages — response may be malformed"); + + return names; + } + + internal static string[] SelectSearchMatches(string query, IEnumerable allNames) + { + string queryLower = query.ToLowerInvariant(); + return allNames + .Where(n => n.Contains(queryLower, StringComparison.OrdinalIgnoreCase)) + .OrderBy(n => n.StartsWith(queryLower, StringComparison.OrdinalIgnoreCase) ? 0 : 1) + .ThenBy(n => n.Length) + .Take(MaxSearchResults) + .ToArray(); + } + + private static async Task FetchLatestVersionAsync(string packageName) + { + await _versionFetchSemaphore.WaitAsync().ConfigureAwait(false); + try + { + using var request = new HttpRequestMessage( + HttpMethod.Get, + $"https://pypi.org/pypi/{Uri.EscapeDataString(packageName)}/json" + ); + using HttpResponseMessage response = await _httpClient + .SendAsync(request) + .ConfigureAwait(false); + response.EnsureSuccessStatusCode(); + string json = await response.Content.ReadAsStringAsync().ConfigureAwait(false); + return (JsonNode.Parse(json) as JsonObject)?["info"]?["version"]?.GetValue(); + } + catch + { + return null; + } + finally + { + _versionFetchSemaphore.Release(); + } + } + + protected override IReadOnlyList GetAvailableUpdates_UnSafe() + { + using Process p = new() + { + StartInfo = new ProcessStartInfo + { + FileName = Status.ExecutablePath, + Arguments = + Status.ExecutableCallArgs + " list --outdated " + GetProxyArgument(), + RedirectStandardOutput = true, + RedirectStandardError = true, + UseShellExecute = false, + CreateNoWindow = true, + StandardOutputEncoding = System.Text.Encoding.UTF8, + }, + }; + + IProcessTaskLogger logger = TaskLogger.CreateNew(LoggableTaskType.ListUpdates, p); + + p.Start(); + + string? line; + List outputLines = []; + while ((line = p.StandardOutput.ReadLine()) is not null) + { + logger.AddToStdOut(line); + outputLines.Add(line); + } + + logger.AddToStdErr(p.StandardError.ReadToEnd()); + p.WaitForExit(); + logger.Close(p.ExitCode); + + return ParseAvailableUpdates(outputLines, DefaultSource, this); + } + + protected override IReadOnlyList GetInstalledPackages_UnSafe() + { + using Process p = new() + { + StartInfo = new ProcessStartInfo + { + FileName = Status.ExecutablePath, + Arguments = Status.ExecutableCallArgs + " list " + GetProxyArgument(), + RedirectStandardOutput = true, + RedirectStandardError = true, + UseShellExecute = false, + CreateNoWindow = true, + StandardOutputEncoding = System.Text.Encoding.UTF8, + }, + }; + + IProcessTaskLogger logger = TaskLogger.CreateNew( + LoggableTaskType.ListInstalledPackages, + p + ); + + p.Start(); + + string? line; + List outputLines = []; + while ((line = p.StandardOutput.ReadLine()) is not null) + { + logger.AddToStdOut(line); + outputLines.Add(line); + } + + logger.AddToStdErr(p.StandardError.ReadToEnd()); + p.WaitForExit(); + logger.Close(p.ExitCode); + + return ParseInstalledPackages(outputLines, DefaultSource, this); + } + + internal static IReadOnlyList ParseAvailableUpdates( + IEnumerable outputLines, + IManagerSource source, + Pip manager + ) + { + return ParsePackages(outputLines, source, manager, expectAvailableVersion: true); + } + + internal static IReadOnlyList ParseInstalledPackages( + IEnumerable outputLines, + IManagerSource source, + Pip manager + ) + { + return ParsePackages(outputLines, source, manager, expectAvailableVersion: false); + } + + private static IReadOnlyList ParsePackages( + IEnumerable outputLines, + IManagerSource source, + Pip manager, + bool expectAvailableVersion + ) + { + bool dashesPassed = false; + List packages = []; + int requiredElements = expectAvailableVersion ? 3 : 2; + + foreach (string line in outputLines) + { + if (!dashesPassed) + { + if (line.Contains("----")) + { + dashesPassed = true; + } + continue; + } + + string[] elements = Regex + .Replace(line.Trim(), " {2,}", " ") + .Split(' ', StringSplitOptions.RemoveEmptyEntries); + if (elements.Length < requiredElements) + { + continue; + } + + if ( + FALSE_PACKAGE_IDS.Contains(elements[0]) + || FALSE_PACKAGE_VERSIONS.Contains(elements[1]) + ) + { + continue; + } + + packages.Add( + expectAvailableVersion + ? new Package( + CoreTools.FormatAsName(elements[0]), + elements[0], + elements[1], + elements[2], + source, + manager, + new(PackageScope.Global) + ) + : new Package( + CoreTools.FormatAsName(elements[0]), + elements[0], + elements[1], + source, + manager, + new(PackageScope.Global) + ) + ); + } + + return packages; + } + + public override IReadOnlyList FindCandidateExecutableFiles() + { + var FoundPaths = CoreTools.WhichMultiple("python"); + if (!OperatingSystem.IsWindows() && !FoundPaths.Any()) + FoundPaths = CoreTools.WhichMultiple("python3"); + List Paths = []; + + if (FoundPaths.Any()) + foreach (var Path in FoundPaths) + Paths.Add(Path); + + try + { + List DirsToSearch = []; + string ProgramFiles = @"C:\Program Files"; + string? UserPythonInstallDir = null; + string? AppData = Environment.GetEnvironmentVariable("APPDATA"); + + if (AppData != null) + UserPythonInstallDir = Path.Combine(AppData, "Programs", "Python"); + + if (Directory.Exists(ProgramFiles)) + DirsToSearch.Add(ProgramFiles); + if (Directory.Exists(UserPythonInstallDir)) + DirsToSearch.Add(UserPythonInstallDir); + + foreach (var Dir in DirsToSearch) + { + string DirName = Path.GetFileName(Dir); + string PythonPath = Path.Join(Dir, "python.exe"); + if (DirName.StartsWith("Python") && File.Exists(PythonPath)) + Paths.Add(PythonPath); + } + } + catch (Exception) { } + + return Paths; + } + + protected override void _loadManagerExecutableFile( + out bool found, + out string path, + out string callArguments + ) + { + // On non-Windows, prefer pip3/pip as standalone executables (avoids "No module named pip" + // errors on systems where pip is installed as a command but not as a Python module). + // Fall back to python/python3 + "-m pip" if no standalone pip is found. + if (!OperatingSystem.IsWindows()) + { + var pipPaths = CoreTools.WhichMultiple("pip3").Concat(CoreTools.WhichMultiple("pip")).ToList(); + if (pipPaths.Count > 0) + { + found = true; + path = pipPaths[0]; + callArguments = ""; + return; + } + } + + var (_found, _path) = GetExecutableFile(); + found = _found; + path = _path; + callArguments = "-m pip "; + } + + protected override void _loadManagerVersion(out string version) + { + using Process process = new() + { + StartInfo = new ProcessStartInfo + { + FileName = Status.ExecutablePath, + Arguments = Status.ExecutableCallArgs + "--version " + GetProxyArgument(), + UseShellExecute = false, + RedirectStandardOutput = true, + RedirectStandardError = true, + CreateNoWindow = true, + StandardOutputEncoding = System.Text.Encoding.UTF8, + }, + }; + process.Start(); + version = process.StandardOutput.ReadToEnd().Trim(); + process.WaitForExit(); + + if (process.ExitCode is 9009) + { + throw new InvalidOperationException( + "Microsoft Store python alias is not a valid python install" + ); + } + } + + protected override void _performExtraLoadingSteps() + { + Environment.SetEnvironmentVariable( + "PIP_REQUIRE_VIRTUALENV", + "false", + EnvironmentVariableTarget.Process + ); + + // Pre-warm the package name index in the background so the first search doesn't + // need to wait for the ~38 MB download inside the search timeout window. + Task.Run(() => + { + var logger = TaskLogger.CreateNew(LoggableTaskType.FindPackages); + try + { + GetOrRefreshIndex(logger); + logger.Close(0); + } + catch (Exception e) + { + logger.Error(e); + logger.Close(1); + Logger.Warn($"Pip: background index pre-warm failed: {e.Message}"); + } + }); + } + } +} diff --git a/src/UniGetUI.PackageEngine.Managers.Pip/UniGetUI.PackageEngine.Managers.Pip.csproj b/src/UniGetUI.PackageEngine.Managers.Pip/UniGetUI.PackageEngine.Managers.Pip.csproj new file mode 100644 index 0000000..cfa6fbf --- /dev/null +++ b/src/UniGetUI.PackageEngine.Managers.Pip/UniGetUI.PackageEngine.Managers.Pip.csproj @@ -0,0 +1,27 @@ + + + $(SharedTargetFrameworks) + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/UniGetUI.PackageEngine.Managers.PowerShell/Helpers/PowerShellDetailsHelper.cs b/src/UniGetUI.PackageEngine.Managers.PowerShell/Helpers/PowerShellDetailsHelper.cs new file mode 100644 index 0000000..1260435 --- /dev/null +++ b/src/UniGetUI.PackageEngine.Managers.PowerShell/Helpers/PowerShellDetailsHelper.cs @@ -0,0 +1,34 @@ +using UniGetUI.PackageEngine.Interfaces; +using UniGetUI.PackageEngine.Managers.PowerShellManager; + +namespace UniGetUI.PackageEngine.Managers.Chocolatey +{ + public class PowerShellDetailsHelper : BaseNuGetDetailsHelper + { + public PowerShellDetailsHelper(BaseNuGet manager) + : base(manager) { } + + protected override string? GetInstallLocation_UnSafe(IPackage package) + { + var user_path = Path.Join( + Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), + "WindowsPowerShell", + "Modules", + package.Id + ); + if (Directory.Exists(user_path)) + return user_path; + + var system_path = Path.Join( + Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles), + "WindowsPowerShell", + "Modules", + package.Id + ); + if (Directory.Exists(system_path)) + return system_path; + + return null; + } + } +} diff --git a/src/UniGetUI.PackageEngine.Managers.PowerShell/Helpers/PowerShellPkgOperationHelper.cs b/src/UniGetUI.PackageEngine.Managers.PowerShell/Helpers/PowerShellPkgOperationHelper.cs new file mode 100644 index 0000000..62b0efb --- /dev/null +++ b/src/UniGetUI.PackageEngine.Managers.PowerShell/Helpers/PowerShellPkgOperationHelper.cs @@ -0,0 +1,110 @@ +using UniGetUI.PackageEngine.Classes.Manager.BaseProviders; +using UniGetUI.PackageEngine.Enums; +using UniGetUI.PackageEngine.Interfaces; +using UniGetUI.PackageEngine.Serializable; + +namespace UniGetUI.PackageEngine.Managers.PowerShellManager; + +internal sealed class PowerShellPkgOperationHelper : BasePkgOperationHelper +{ + public PowerShellPkgOperationHelper(PowerShell manager) + : base(manager) { } + + protected override IReadOnlyList _getOperationParameters( + IPackage package, + InstallOptions options, + OperationType operation + ) + { + List parameters = + [ + operation switch + { + OperationType.Install => Manager.Properties.InstallVerb, + OperationType.Update => Manager.Properties.UpdateVerb, + OperationType.Uninstall => Manager.Properties.UninstallVerb, + _ => throw new InvalidDataException("Invalid package operation"), + }, + ]; + parameters.AddRange(["-Name", package.Id, "-Confirm:$false", "-Force"]); + + if (operation is not OperationType.Uninstall) + { + if (options.PreRelease) + parameters.Add("-AllowPrerelease"); + + // Update-Module (PowerShellGet) has no -Scope parameter; only Install-Module accepts it + if (operation is OperationType.Install && !package.OverridenOptions.PowerShell_DoNotSetScopeParameter) + { + if ( + package.OverridenOptions.Scope == PackageScope.Global + || ( + package.OverridenOptions.Scope is null + && options.InstallationScope == PackageScope.Global + ) + ) + parameters.AddRange(["-Scope", "AllUsers"]); + else + parameters.AddRange(["-Scope", "CurrentUser"]); + } + } + + if (operation is OperationType.Install) + { + if (options.SkipHashCheck) + parameters.Add("-SkipPublisherCheck"); + + if (options.Version != "") + parameters.AddRange(["-RequiredVersion", options.Version]); + } + + parameters.AddRange( + operation switch + { + OperationType.Update => options.CustomParameters_Update, + OperationType.Uninstall => options.CustomParameters_Uninstall, + _ => options.CustomParameters_Install, + } + ); + + // Windows PowerShell 5.x defaults to TLS 1.0/1.1, which the PowerShell Gallery rejects; force TLS 1.2 so gallery operations can connect under -NoProfile + if (operation is not OperationType.Uninstall) + parameters.Insert(0, "[Net.ServicePointManager]::SecurityProtocol=[Net.SecurityProtocolType]::Tls12;"); + + return parameters; + } + + protected override OperationVeredict _getOperationResult( + IPackage package, + OperationType operation, + IReadOnlyList processOutput, + int returnCode + ) + { + string output_string = string.Join("\n", processOutput); + + if ( + package.OverridenOptions.RunAsAdministrator is not true + && ( + output_string.Contains("AdminPrivilegesAreRequired") + || output_string.Contains("AdminPrivilegeRequired") + ) + ) + { + package.OverridenOptions.RunAsAdministrator = true; + return OperationVeredict.AutoRetry; + } + + if ( + output_string.Contains("-Scope") + && output_string.Contains("NamedParameterNotFound") + && !package.OverridenOptions.PowerShell_DoNotSetScopeParameter + ) + { + package.OverridenOptions.PowerShell_DoNotSetScopeParameter = true; + return OperationVeredict.AutoRetry; + } + + return returnCode == 0 ? OperationVeredict.Success : OperationVeredict.Failure; + } +} diff --git a/src/UniGetUI.PackageEngine.Managers.PowerShell/Helpers/PowerShellSourceHelper.cs b/src/UniGetUI.PackageEngine.Managers.PowerShell/Helpers/PowerShellSourceHelper.cs new file mode 100644 index 0000000..9a4af9d --- /dev/null +++ b/src/UniGetUI.PackageEngine.Managers.PowerShell/Helpers/PowerShellSourceHelper.cs @@ -0,0 +1,129 @@ +using System.Diagnostics; +using System.Text.RegularExpressions; +using UniGetUI.Core.Logging; +using UniGetUI.PackageEngine.Classes.Manager; +using UniGetUI.PackageEngine.Classes.Manager.Providers; +using UniGetUI.PackageEngine.Enums; +using UniGetUI.PackageEngine.Interfaces; +using UniGetUI.PackageEngine.ManagerClasses.Classes; + +namespace UniGetUI.PackageEngine.Managers.PowerShellManager +{ + internal sealed class PowerShellSourceHelper : BaseSourceHelper + { + public PowerShellSourceHelper(PowerShell manager) + : base(manager) { } + + public override string[] GetAddSourceParameters(IManagerSource source) + { + if (source.Url.ToString() == "https://www.powershellgallery.com/api/v2") + { + return ["Register-PSRepository", "-Default"]; + } + + return + [ + "Register-PSRepository", + "-Name", + source.Name, + "-SourceLocation", + source.Url.ToString(), + ]; + } + + public override string[] GetRemoveSourceParameters(IManagerSource source) + { + return ["Unregister-PSRepository", "-Name", source.Name]; + } + + protected override OperationVeredict _getAddSourceOperationVeredict( + IManagerSource source, + int ReturnCode, + string[] Output + ) + { + return ReturnCode == 0 ? OperationVeredict.Success : OperationVeredict.Failure; + } + + protected override OperationVeredict _getRemoveSourceOperationVeredict( + IManagerSource source, + int ReturnCode, + string[] Output + ) + { + return ReturnCode == 0 ? OperationVeredict.Success : OperationVeredict.Failure; + } + + protected override IReadOnlyList GetSources_UnSafe() + { + List sources = []; + + using Process p = new() + { + StartInfo = new() + { + FileName = Manager.Status.ExecutablePath, + Arguments = Manager.Status.ExecutableCallArgs + " Get-PSRepository", + RedirectStandardOutput = true, + RedirectStandardError = true, + RedirectStandardInput = true, + UseShellExecute = false, + CreateNoWindow = true, + StandardOutputEncoding = System.Text.Encoding.UTF8, + }, + }; + + IProcessTaskLogger logger = Manager.TaskLogger.CreateNew( + LoggableTaskType.ListSources, + p + ); + + p.Start(); + + bool dashesPassed = false; + string? line; + while ((line = p.StandardOutput.ReadLine()) is not null) + { + logger.AddToStdOut(line); + try + { + if (string.IsNullOrEmpty(line)) + { + continue; + } + + if (!dashesPassed) + { + if (line.Contains("---")) + { + dashesPassed = true; + } + } + else + { + string[] parts = Regex.Replace(line.Trim(), " {2,}", " ").Split(' '); + if (parts.Length >= 3) + { + sources.Add( + new ManagerSource( + Manager, + parts[0].Trim(), + new Uri(parts[2].Trim()) + ) + ); + } + } + } + catch (Exception e) + { + Logger.Warn(e); + } + } + logger.AddToStdErr(p.StandardError.ReadToEnd()); + p.WaitForExit(); + logger.Close(p.ExitCode); + + return sources; + } + } +} diff --git a/src/UniGetUI.PackageEngine.Managers.PowerShell/InternalsVisibleTo.cs b/src/UniGetUI.PackageEngine.Managers.PowerShell/InternalsVisibleTo.cs new file mode 100644 index 0000000..eeb63da --- /dev/null +++ b/src/UniGetUI.PackageEngine.Managers.PowerShell/InternalsVisibleTo.cs @@ -0,0 +1,3 @@ +using System.Runtime.CompilerServices; + +[assembly: InternalsVisibleTo("UniGetUI.PackageEngine.Tests")] diff --git a/src/UniGetUI.PackageEngine.Managers.PowerShell/PowerShell.cs b/src/UniGetUI.PackageEngine.Managers.PowerShell/PowerShell.cs new file mode 100644 index 0000000..e81a37f --- /dev/null +++ b/src/UniGetUI.PackageEngine.Managers.PowerShell/PowerShell.cs @@ -0,0 +1,203 @@ +using System.Diagnostics; +using System.Text; +using System.Text.RegularExpressions; +using UniGetUI.Core.Data; +using UniGetUI.Core.Tools; +using UniGetUI.Interface.Enums; +using UniGetUI.PackageEngine.Classes.Manager; +using UniGetUI.PackageEngine.Classes.Manager.ManagerHelpers; +using UniGetUI.PackageEngine.Enums; +using UniGetUI.PackageEngine.ManagerClasses.Classes; +using UniGetUI.PackageEngine.ManagerClasses.Manager; +using UniGetUI.PackageEngine.Managers.Chocolatey; +using UniGetUI.PackageEngine.PackageClasses; + +namespace UniGetUI.PackageEngine.Managers.PowerShellManager +{ + public class PowerShell : BaseNuGet + { + public PowerShell() + { + Capabilities = new ManagerCapabilities + { + CanRunAsAdmin = true, + CanSkipIntegrityChecks = true, + SupportsCustomVersions = true, + CanDownloadInstaller = true, + SupportsCustomScopes = true, + CanListDependencies = true, + SupportsCustomSources = true, + SupportsPreRelease = true, + SupportsCustomPackageIcons = true, + Sources = new SourceCapabilities + { + KnowsPackageCount = false, + KnowsUpdateDate = false, + }, + SupportsProxy = ProxySupport.Partially, + SupportsProxyAuth = true, + KnowsPackageReleaseDate = PackageReleaseDateSupport.Yes, + }; + + Properties = new ManagerProperties + { + Id = "winps", + Name = "PowerShell", + DisplayName = "PowerShell 5.x", + Description = CoreTools.Translate( + "PowerShell's package manager. Find libraries and scripts to expand PowerShell capabilities
Contains: Modules, Scripts, Cmdlets" + ), + IconId = IconType.PowerShell, + ColorIconId = "powershell_color", + ExecutableFriendlyName = "powershell.exe", + InstallVerb = "Install-Module", + UninstallVerb = "Uninstall-Module", + UpdateVerb = "Update-Module", + KnownSources = + [ + new ManagerSource( + this, + "PSGallery", + new Uri("https://www.powershellgallery.com/api/v2") + ), + new ManagerSource( + this, + "PoshTestGallery", + new Uri("https://www.poshtestgallery.com/api/v2") + ), + ], + DefaultSource = new ManagerSource( + this, + "PSGallery", + new Uri("https://www.powershellgallery.com/api/v2") + ), + }; + + DetailsHelper = new PowerShellDetailsHelper(this); + SourcesHelper = new PowerShellSourceHelper(this); + OperationHelper = new PowerShellPkgOperationHelper(this); + } + + protected override IReadOnlyList _getInstalledPackages_UnSafe() + { + using Process p = new() + { + StartInfo = new ProcessStartInfo + { + FileName = Status.ExecutablePath, + Arguments = Status.ExecutableCallArgs + " Get-InstalledModule", + RedirectStandardOutput = true, + RedirectStandardError = true, + RedirectStandardInput = true, + UseShellExecute = false, + CreateNoWindow = true, + StandardOutputEncoding = Encoding.UTF8, + }, + }; + + IProcessTaskLogger logger = TaskLogger.CreateNew( + LoggableTaskType.ListInstalledPackages, + p + ); + + p.Start(); + string? line; + List outputLines = []; + while ((line = p.StandardOutput.ReadLine()) is not null) + { + logger.AddToStdOut(line); + outputLines.Add(line); + } + + logger.AddToStdErr(p.StandardError.ReadToEnd()); + p.WaitForExit(); + logger.Close(p.ExitCode); + + return ParseInstalledPackages(outputLines, this); + } + + public override List FindCandidateExecutableFiles() + { + var candidates = CoreTools.WhichMultiple("powershell.exe"); + if (candidates.Count is 0) + candidates.Add(CoreData.PowerShell5); + return candidates; + } + + protected override void _loadManagerExecutableFile( + out bool found, + out string path, + out string callArguments + ) + { + var (_found, _path) = GetExecutableFile(); + found = _found; + path = _path; + callArguments = " -NoProfile -Command"; + } + + protected override void _loadManagerVersion(out string version) + { + using Process process = new() + { + StartInfo = new ProcessStartInfo + { + FileName = Status.ExecutablePath, + Arguments = Status.ExecutableCallArgs + " \"echo $PSVersionTable\"", + UseShellExecute = false, + RedirectStandardOutput = true, + RedirectStandardError = true, + CreateNoWindow = true, + StandardOutputEncoding = Encoding.UTF8, + }, + }; + process.Start(); + version = process.StandardOutput.ReadToEnd().Trim(); + } + + internal static IReadOnlyList ParseInstalledPackages( + IEnumerable outputLines, + PowerShell manager + ) + { + List packages = []; + bool dashesPassed = false; + + foreach (string rawLine in outputLines) + { + if (!dashesPassed) + { + if (rawLine.Contains("-----")) + { + dashesPassed = true; + } + + continue; + } + + string[] elements = Regex.Replace(rawLine, " {2,}", " ").Split(' '); + if (elements.Length < 3) + { + continue; + } + + for (int i = 0; i < elements.Length; i++) + { + elements[i] = elements[i].Trim(); + } + + packages.Add( + new Package( + CoreTools.FormatAsName(elements[1]), + elements[1], + elements[0], + manager.SourcesHelper.Factory.GetSourceOrDefault(elements[2]), + manager + ) + ); + } + + return packages; + } + } +} diff --git a/src/UniGetUI.PackageEngine.Managers.PowerShell/UniGetUI.PackageEngine.Managers.PowerShell.csproj b/src/UniGetUI.PackageEngine.Managers.PowerShell/UniGetUI.PackageEngine.Managers.PowerShell.csproj new file mode 100644 index 0000000..a6c0b04 --- /dev/null +++ b/src/UniGetUI.PackageEngine.Managers.PowerShell/UniGetUI.PackageEngine.Managers.PowerShell.csproj @@ -0,0 +1,29 @@ + + + $(WindowsTargetFramework) + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/UniGetUI.PackageEngine.Managers.PowerShell7/Helpers/PowerShell7DetailsHelper.cs b/src/UniGetUI.PackageEngine.Managers.PowerShell7/Helpers/PowerShell7DetailsHelper.cs new file mode 100644 index 0000000..5631b3b --- /dev/null +++ b/src/UniGetUI.PackageEngine.Managers.PowerShell7/Helpers/PowerShell7DetailsHelper.cs @@ -0,0 +1,34 @@ +using UniGetUI.PackageEngine.Interfaces; +using UniGetUI.PackageEngine.Managers.PowerShellManager; + +namespace UniGetUI.PackageEngine.Managers.Chocolatey +{ + public class PowerShell7DetailsHelper : BaseNuGetDetailsHelper + { + public PowerShell7DetailsHelper(BaseNuGet manager) + : base(manager) { } + + protected override string? GetInstallLocation_UnSafe(IPackage package) + { + var user_path = Path.Join( + Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), + "PowerShell", + "Modules", + package.Id + ); + if (Directory.Exists(user_path)) + return user_path; + + var system_path = Path.Join( + Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles), + "PowerShell", + "Modules", + package.Id + ); + if (Directory.Exists(system_path)) + return system_path; + + return null; + } + } +} diff --git a/src/UniGetUI.PackageEngine.Managers.PowerShell7/Helpers/PowerShell7PkgOperationHelper.cs b/src/UniGetUI.PackageEngine.Managers.PowerShell7/Helpers/PowerShell7PkgOperationHelper.cs new file mode 100644 index 0000000..3609fe7 --- /dev/null +++ b/src/UniGetUI.PackageEngine.Managers.PowerShell7/Helpers/PowerShell7PkgOperationHelper.cs @@ -0,0 +1,99 @@ +using UniGetUI.PackageEngine.Classes.Manager.BaseProviders; +using UniGetUI.PackageEngine.Enums; +using UniGetUI.PackageEngine.Interfaces; +using UniGetUI.PackageEngine.Serializable; + +namespace UniGetUI.PackageEngine.Managers.PowerShell7Manager; + +internal sealed class PowerShell7PkgOperationHelper : BasePkgOperationHelper +{ + public PowerShell7PkgOperationHelper(PowerShell7 manager) + : base(manager) { } + + protected override IReadOnlyList _getOperationParameters( + IPackage package, + InstallOptions options, + OperationType operation + ) + { + List parameters = + [ + operation switch + { + OperationType.Install => Manager.Properties.InstallVerb, + OperationType.Update => Manager.Properties.UpdateVerb, + OperationType.Uninstall => Manager.Properties.UninstallVerb, + _ => throw new InvalidDataException("Invalid package operation"), + }, + ]; + parameters.AddRange(["-Name", package.Id, "-Confirm:$false"]); + + if (operation is OperationType.Install) + { + if (options.Version != "") + parameters.AddRange(["-Version", options.Version]); + } + else if (operation is OperationType.Update) + { + parameters.Add("-Force"); + } + else if (operation is OperationType.Uninstall) + { + parameters.AddRange(["-Version", package.VersionString]); + } + + if (operation is not OperationType.Uninstall) + { + parameters.AddRange(["-TrustRepository", "-AcceptLicense"]); + + if (options.PreRelease) + parameters.Add("-Prerelease"); + + if ( + package.OverridenOptions.Scope is PackageScope.Global + || ( + package.OverridenOptions.Scope is null + && options.InstallationScope is PackageScope.Global + ) + ) + parameters.AddRange(["-Scope", "AllUsers"]); + else + parameters.AddRange(["-Scope", "CurrentUser"]); + } + + parameters.AddRange( + operation switch + { + OperationType.Update => options.CustomParameters_Update, + OperationType.Uninstall => options.CustomParameters_Uninstall, + _ => options.CustomParameters_Install, + } + ); + + return parameters; + } + + protected override OperationVeredict _getOperationResult( + IPackage package, + OperationType operation, + IReadOnlyList processOutput, + int returnCode + ) + { + string output_string = string.Join("\n", processOutput); + + if ( + package.OverridenOptions.RunAsAdministrator is not true + && ( + output_string.Contains("AdminPrivilegesAreRequired") + || output_string.Contains("AdminPrivilegeRequired") + ) + ) + { + package.OverridenOptions.RunAsAdministrator = true; + return OperationVeredict.AutoRetry; + } + + return returnCode == 0 ? OperationVeredict.Success : OperationVeredict.Failure; + } +} diff --git a/src/UniGetUI.PackageEngine.Managers.PowerShell7/Helpers/PowerShell7SourceHelper.cs b/src/UniGetUI.PackageEngine.Managers.PowerShell7/Helpers/PowerShell7SourceHelper.cs new file mode 100644 index 0000000..2777d28 --- /dev/null +++ b/src/UniGetUI.PackageEngine.Managers.PowerShell7/Helpers/PowerShell7SourceHelper.cs @@ -0,0 +1,136 @@ +using System.Diagnostics; +using System.Text.RegularExpressions; +using UniGetUI.Core.Logging; +using UniGetUI.PackageEngine.Classes.Manager; +using UniGetUI.PackageEngine.Classes.Manager.Providers; +using UniGetUI.PackageEngine.Enums; +using UniGetUI.PackageEngine.Interfaces; +using UniGetUI.PackageEngine.ManagerClasses.Classes; + +namespace UniGetUI.PackageEngine.Managers.PowerShell7Manager +{ + internal sealed class PowerShell7SourceHelper : BaseSourceHelper + { + public PowerShell7SourceHelper(PowerShell7 manager) + : base(manager) { } + + public override string[] GetAddSourceParameters(IManagerSource source) + { + if (source.Url.ToString() == "https://www.powershellgallery.com/api/v2") + { + return ["Register-PSRepository", "-Default"]; + } + + return + [ + "Register-PSRepository", + "-Name", + source.Name, + "-SourceLocation", + source.Url.ToString(), + ]; + } + + public override string[] GetRemoveSourceParameters(IManagerSource source) + { + return ["Unregister-PSRepository", "-Name", source.Name]; + } + + protected override OperationVeredict _getAddSourceOperationVeredict( + IManagerSource source, + int ReturnCode, + string[] Output + ) + { + return ReturnCode == 0 ? OperationVeredict.Success : OperationVeredict.Failure; + } + + protected override OperationVeredict _getRemoveSourceOperationVeredict( + IManagerSource source, + int ReturnCode, + string[] Output + ) + { + return ReturnCode == 0 ? OperationVeredict.Success : OperationVeredict.Failure; + } + + protected override IReadOnlyList GetSources_UnSafe() + { + List sources = []; + + using Process p = new() + { + StartInfo = new() + { + FileName = Manager.Status.ExecutablePath, + Arguments = + Manager.Status.ExecutableCallArgs + + " \"if (Get-Command Get-PSResourceRepository -ErrorAction SilentlyContinue)" + + " { Get-PSResourceRepository | Format-Table -Property Name,Uri }" + + " else { Get-PSRepository | Format-Table -Property" + + " Name,@{N='SourceLocation';E={If ($_.Uri) {$_.Uri.AbsoluteUri} Else {$_.SourceLocation}}} }\"", + RedirectStandardOutput = true, + RedirectStandardError = true, + RedirectStandardInput = true, + UseShellExecute = false, + CreateNoWindow = true, + StandardOutputEncoding = System.Text.Encoding.UTF8, + }, + }; + + IProcessTaskLogger logger = Manager.TaskLogger.CreateNew( + LoggableTaskType.ListSources, + p + ); + + p.Start(); + + bool dashesPassed = false; + string? line; + while ((line = p.StandardOutput.ReadLine()) is not null) + { + logger.AddToStdOut(line); + try + { + if (string.IsNullOrEmpty(line)) + { + continue; + } + + if (!dashesPassed) + { + if (line.Contains("---")) + { + dashesPassed = true; + } + } + else + { + string[] parts = Regex.Replace(line.Trim(), " {2,}", " ").Split(' '); + if (parts.Length >= 2) + { + string uri = Regex + .Match( + line, + "https?:\\/\\/([\\w%-]+\\.)+[\\w%-]+(\\/[\\w%-]+)+\\/?" + ) + .Value; + if (uri == "") + continue; + sources.Add(new ManagerSource(Manager, parts[0].Trim(), new Uri(uri))); + } + } + } + catch (Exception e) + { + Logger.Warn(e); + } + } + logger.AddToStdErr(p.StandardError.ReadToEnd()); + p.WaitForExit(); + logger.Close(p.ExitCode); + + return sources; + } + } +} diff --git a/src/UniGetUI.PackageEngine.Managers.PowerShell7/InternalsVisibleTo.cs b/src/UniGetUI.PackageEngine.Managers.PowerShell7/InternalsVisibleTo.cs new file mode 100644 index 0000000..eeb63da --- /dev/null +++ b/src/UniGetUI.PackageEngine.Managers.PowerShell7/InternalsVisibleTo.cs @@ -0,0 +1,3 @@ +using System.Runtime.CompilerServices; + +[assembly: InternalsVisibleTo("UniGetUI.PackageEngine.Tests")] diff --git a/src/UniGetUI.PackageEngine.Managers.PowerShell7/PowerShell7.cs b/src/UniGetUI.PackageEngine.Managers.PowerShell7/PowerShell7.cs new file mode 100644 index 0000000..85844ca --- /dev/null +++ b/src/UniGetUI.PackageEngine.Managers.PowerShell7/PowerShell7.cs @@ -0,0 +1,201 @@ +using System.Diagnostics; +using System.Formats.Asn1; +using System.Text; +using UniGetUI.Core.Tools; +using UniGetUI.Interface.Enums; +using UniGetUI.PackageEngine.Classes.Manager; +using UniGetUI.PackageEngine.Classes.Manager.ManagerHelpers; +using UniGetUI.PackageEngine.Enums; +using UniGetUI.PackageEngine.ManagerClasses.Classes; +using UniGetUI.PackageEngine.ManagerClasses.Manager; +using UniGetUI.PackageEngine.Managers.Chocolatey; +using UniGetUI.PackageEngine.Managers.PowerShellManager; +using UniGetUI.PackageEngine.PackageClasses; + +namespace UniGetUI.PackageEngine.Managers.PowerShell7Manager +{ + public class PowerShell7 : BaseNuGet + { + public PowerShell7() + { + Capabilities = new ManagerCapabilities + { + CanRunAsAdmin = true, + SupportsCustomVersions = true, + SupportsCustomScopes = true, + SupportsCustomSources = true, + SupportsPreRelease = true, + CanDownloadInstaller = true, + CanListDependencies = true, + SupportsCustomPackageIcons = true, + CanUninstallPreviousVersionsAfterUpdate = true, + Sources = new SourceCapabilities + { + KnowsPackageCount = false, + KnowsUpdateDate = false, + }, + SupportsProxy = ProxySupport.Partially, + SupportsProxyAuth = true, + KnowsPackageReleaseDate = PackageReleaseDateSupport.Yes, + }; + + Properties = new ManagerProperties + { + Id = "pwsh", + Name = "PowerShell7", + DisplayName = "PowerShell 7.x", + Description = CoreTools.Translate( + "PowerShell's package manager. Find libraries and scripts to expand PowerShell capabilities
Contains: Modules, Scripts, Cmdlets" + ), + IconId = IconType.PowerShell, + ColorIconId = "powershell_color", + ExecutableFriendlyName = OperatingSystem.IsWindows() ? "pwsh.exe" : "pwsh", + InstallVerb = "Install-PSResource", + UninstallVerb = "Uninstall-PSResource", + UpdateVerb = "Update-PSResource", + KnownSources = + [ + new ManagerSource( + this, + "PSGallery", + new Uri("https://www.powershellgallery.com/api/v2") + ), + new ManagerSource( + this, + "PoshTestGallery", + new Uri("https://www.poshtestgallery.com/api/v2") + ), + ], + DefaultSource = new ManagerSource( + this, + "PSGallery", + new Uri("https://www.powershellgallery.com/api/v2") + ), + }; + + DetailsHelper = new PowerShell7DetailsHelper(this); + SourcesHelper = new PowerShell7SourceHelper(this); + OperationHelper = new PowerShell7PkgOperationHelper(this); + } + + protected override IReadOnlyList _getInstalledPackages_UnSafe() + { + using Process p = new() + { + StartInfo = new ProcessStartInfo + { + FileName = Status.ExecutablePath, + Arguments = + Status.ExecutableCallArgs + + " \"Write-Output '##SCOPE:AllUsers##';" + + " Get-InstalledPSResource -Scope AllUsers | ForEach-Object { $_.Name + [char]9 + $_.Version + [char]9 + $_.Repository };" + + " Write-Output '##SCOPE:CurrentUser##';" + + " Get-InstalledPSResource -Scope CurrentUser | ForEach-Object { $_.Name + [char]9 + $_.Version + [char]9 + $_.Repository }\"", + RedirectStandardOutput = true, + RedirectStandardError = true, + RedirectStandardInput = true, + UseShellExecute = false, + CreateNoWindow = true, + StandardOutputEncoding = Encoding.UTF8, + }, + }; + + IProcessTaskLogger logger = TaskLogger.CreateNew( + LoggableTaskType.ListInstalledPackages, + p + ); + + p.Start(); + string? line; + List outputLines = []; + while ((line = p.StandardOutput.ReadLine()) is not null) + { + logger.AddToStdOut(line); + outputLines.Add(line); + } + + logger.AddToStdErr(p.StandardError.ReadToEnd()); + p.WaitForExit(); + logger.Close(p.ExitCode); + + return ParseInstalledPackages(outputLines, this); + } + + internal static IReadOnlyList ParseInstalledPackages( + IEnumerable outputLines, + PowerShell7 manager + ) + { + List packages = []; + string currentScope = "AllUsers"; + + foreach (string line in outputLines) + { + if (line.StartsWith("##SCOPE:")) + { + currentScope = line.Trim('#').Split(':')[1]; + continue; + } + + string[] elements = line.Split('\t'); + if (elements.Length < 3) + continue; + + for (int i = 0; i < elements.Length; i++) + elements[i] = elements[i].Trim(); + + if (elements[0].Length == 0) + continue; + + packages.Add( + new Package( + CoreTools.FormatAsName(elements[0]), + elements[0], + elements[1], + manager.SourcesHelper.Factory.GetSourceOrDefault(elements[2]), + manager, + new(currentScope == "CurrentUser" ? PackageScope.User : PackageScope.Machine) + ) + ); + } + + return packages; + } + + protected override bool UseSubstringSearch => true; + + public override IReadOnlyList FindCandidateExecutableFiles() => + CoreTools.WhichMultiple(OperatingSystem.IsWindows() ? "pwsh.exe" : "pwsh"); + + protected override void _loadManagerExecutableFile( + out bool found, + out string path, + out string callArguments + ) + { + var (_found, _path) = GetExecutableFile(); + found = _found; + path = _path; + callArguments = " -NoProfile -Command"; + } + + protected override void _loadManagerVersion(out string version) + { + using Process process = new() + { + StartInfo = new ProcessStartInfo + { + FileName = Status.ExecutablePath, + Arguments = "-NoProfile -Version", + UseShellExecute = false, + RedirectStandardOutput = true, + RedirectStandardError = true, + CreateNoWindow = true, + StandardOutputEncoding = Encoding.UTF8, + }, + }; + process.Start(); + version = process.StandardOutput.ReadToEnd().Trim(); + } + } +} diff --git a/src/UniGetUI.PackageEngine.Managers.PowerShell7/UniGetUI.PackageEngine.Managers.PowerShell7.csproj b/src/UniGetUI.PackageEngine.Managers.PowerShell7/UniGetUI.PackageEngine.Managers.PowerShell7.csproj new file mode 100644 index 0000000..fa307d2 --- /dev/null +++ b/src/UniGetUI.PackageEngine.Managers.PowerShell7/UniGetUI.PackageEngine.Managers.PowerShell7.csproj @@ -0,0 +1,27 @@ + + + $(SharedTargetFrameworks) + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/UniGetUI.PackageEngine.Managers.Scoop/Helpers/ScoopPkgDetailsHelper.cs b/src/UniGetUI.PackageEngine.Managers.Scoop/Helpers/ScoopPkgDetailsHelper.cs new file mode 100644 index 0000000..a960bed --- /dev/null +++ b/src/UniGetUI.PackageEngine.Managers.Scoop/Helpers/ScoopPkgDetailsHelper.cs @@ -0,0 +1,322 @@ +using System.Diagnostics; +using System.Text.Json.Nodes; +using UniGetUI.Core.IconEngine; +using UniGetUI.Core.Logging; +using UniGetUI.Core.Tools; +using UniGetUI.PackageEngine.Classes.Manager.BaseProviders; +using UniGetUI.PackageEngine.Interfaces; +using UniGetUI.PackageEngine.ManagerClasses.Classes; + +namespace UniGetUI.PackageEngine.Managers.ScoopManager +{ + internal sealed class ScoopPkgDetailsHelper : BasePkgDetailsHelper + { + public ScoopPkgDetailsHelper(Scoop manager) + : base(manager) { } + + protected override void GetDetails_UnSafe(IPackageDetails details) + { + if (details.Package.Source.Url is not null) + { + try + { + if (details.Package.Source.Name.StartsWith("http")) + details.ManifestUrl = new Uri(details.Package.Source.Name); + else if (details.Package.Source.Name.Contains(":\\")) + details.ManifestUrl = new Uri( + "file:///" + details.Package.Source.Name.Replace("\\", "/") + ); + else + details.ManifestUrl = new Uri( + details.Package.Source.Url + + "/blob/master/bucket/" + + details.Package.Id + + ".json" + ); + } + catch (Exception ex) + { + Logger.Error("Cannot load package manifest URL"); + Logger.Error(ex); + } + } + + string packageId; + // If source is ellipsed, a local path, or a URL manifest, omit source argument + if ( + details.Package.Source.Name.Contains("...") + || details.Package.Source.Name.Contains(":\\") + || details.Package.Source.Name.StartsWith("http") + ) + packageId = $"{details.Package.Id}"; + else + packageId = $"{details.Package.Source.Name}/{details.Package.Id}"; + + using Process p = new() + { + StartInfo = new ProcessStartInfo + { + FileName = Manager.Status.ExecutablePath, + Arguments = Manager.Status.ExecutableCallArgs + " cat " + packageId, + RedirectStandardOutput = true, + RedirectStandardError = true, + UseShellExecute = false, + CreateNoWindow = true, + StandardOutputEncoding = System.Text.Encoding.UTF8, + }, + }; + + IProcessTaskLogger logger = Manager.TaskLogger.CreateNew( + Enums.LoggableTaskType.LoadPackageDetails, + p + ); + + p.Start(); + string JsonString = p.StandardOutput.ReadToEnd(); + logger.AddToStdOut(JsonString); + logger.AddToStdErr(p.StandardError.ReadToEnd()); + + if (JsonNode.Parse(JsonString) is not JsonObject contents) + { + throw new InvalidOperationException("Deserialized RawInfo was null"); + } + + // Load description + if (contents["description"] is JsonArray descriptionList) + { + details.Description = ""; + foreach (var line in descriptionList) + { + details.Description += line + "\n"; + } + } + else + { + details.Description = contents["description"]?.ToString(); + } + + // Load installer type + if (contents["innsetup"]?.ToString() == "true") + details.InstallerType = "Inno Setup (" + CoreTools.Translate("extracted") + ")"; + else + details.InstallerType = CoreTools.Translate("Scoop package"); + + // Load homepage and author + if ( + Uri.TryCreate( + contents?["homepage"]?.ToString() ?? "", + UriKind.RelativeOrAbsolute, + out var homepageUrl + ) + ) + { + details.HomepageUrl = homepageUrl; + + if (homepageUrl.ToString().StartsWith("https://github.com/")) + details.Author = homepageUrl + .ToString() + .Replace("https://github.com/", "") + .Split("/")[0]; + else + details.Author = homepageUrl.Host.Split(".")[^2]; + } + + // Load notes + if (contents?["notes"] is JsonArray notesList) + { + details.ReleaseNotes = ""; + foreach (var line in notesList) + { + details.ReleaseNotes += line + "\n"; + } + } + else + { + details.ReleaseNotes = contents?["notes"]?.ToString(); + } + + if (contents?["license"] is JsonObject licenseDetails) + { + details.License = licenseDetails["identifier"]?.ToString(); + if ( + Uri.TryCreate( + licenseDetails["url"]?.ToString(), + UriKind.RelativeOrAbsolute, + out var licenseUrl + ) + ) + details.LicenseUrl = licenseUrl; + } + else + { + details.License = contents?["license"]?.ToString(); + } + + // Load installers + if (contents?["url"] is JsonArray urlList) + { + // Only one installer + if ( + Uri.TryCreate( + urlList[0]?.ToString(), + UriKind.RelativeOrAbsolute, + out var installerUrl + ) + ) + details.InstallerUrl = installerUrl; + + details.InstallerHash = (contents?["hash"] as JsonArray)?[0]?.ToString(); + } + else if (contents?["url"] is JsonValue value) + { + // Multiple installers + if ( + Uri.TryCreate( + value.ToString(), + UriKind.RelativeOrAbsolute, + out var installerUrl + ) + ) + details.InstallerUrl = installerUrl; + + details.InstallerHash = contents?["hash"]?.ToString(); + } + else if (contents?["architecture"] is JsonObject archNode) + { + // Architecture-based installer + string arch = archNode.ContainsKey("64bit") ? "64bit" : archNode.First().Key; + + if ( + Uri.TryCreate( + archNode[arch]?["url"]?.ToString(), + UriKind.RelativeOrAbsolute, + out var installerUrl + ) + ) + details.InstallerUrl = installerUrl; + + details.InstallerHash = archNode[arch]?["hash"]?.ToString(); + } + + if (details.InstallerUrl is not null) + details.InstallerSize = CoreTools.GetFileSizeAsLong(details.InstallerUrl); + + // Load release notes URL + if ( + contents?["checkver"] is JsonObject checkver + && Uri.TryCreate( + checkver["url"]?.ToString(), + UriKind.RelativeOrAbsolute, + out var releaseNotesUrl + ) + ) + details.ReleaseNotesUrl = releaseNotesUrl; + + details.Dependencies.Clear(); + _getDepends(details, contents); + _getSuggests(details, contents); + + logger.Close(0); + } + + private static void _getSuggests(IPackageDetails details, JsonObject? contents) + { + foreach (var rawDep in (contents?["suggest"]?.AsObject() ?? [])) + { + List innerDeps = []; + + if (rawDep.Value is JsonValue value) + innerDeps.Add(value.GetValue()); + else + { + foreach (var iDep in rawDep.Value?.AsArray() ?? []) + { + string? val = iDep?.GetValue(); + if (val is not null) + innerDeps.Add(val); + } + } + + foreach (var val in innerDeps) + details.Dependencies.Add( + new() + { + Name = val, + Version = "", + Mandatory = false, + } + ); + } + } + + private static void _getDepends(IPackageDetails details, JsonObject? contents) + { + var node = contents?["depends"]; + List innerDeps = []; + + if (node is JsonValue value) + innerDeps.Add(value.GetValue()); + else + { + foreach (var iDep in node?.AsArray() ?? []) + { + string? val = iDep?.GetValue(); + if (val is not null) + innerDeps.Add(val); + } + } + + foreach (var val in innerDeps) + details.Dependencies.Add( + new() + { + Name = val, + Version = "", + Mandatory = true, + } + ); + } + + protected override CacheableIcon? GetIcon_UnSafe(IPackage package) + { + throw new NotImplementedException(); + } + + protected override IReadOnlyList GetScreenshots_UnSafe(IPackage package) + { + throw new NotImplementedException(); + } + + protected override string? GetInstallLocation_UnSafe(IPackage package) + { + // Honor custom Scoop roots (SCOOP / SCOOP_GLOBAL) and both user and global installs, + // returning the first that actually exists. + string?[] roots = + [ + Environment.GetEnvironmentVariable("SCOOP"), + Path.Join(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), "scoop"), + Environment.GetEnvironmentVariable("SCOOP_GLOBAL"), + Path.Join( + Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), + "scoop" + ), + ]; + + foreach (var root in roots) + { + if (string.IsNullOrEmpty(root)) + continue; + var path = Path.Join(root, "apps", package.Id, "current"); + if (Directory.Exists(path)) + return path; + } + + return null; + } + + protected override IReadOnlyList GetInstallableVersions_UnSafe(IPackage package) + { + throw new InvalidOperationException("Scoop does not support custom package versions"); + } + } +} diff --git a/src/UniGetUI.PackageEngine.Managers.Scoop/Helpers/ScoopPkgOperationHelper.cs b/src/UniGetUI.PackageEngine.Managers.Scoop/Helpers/ScoopPkgOperationHelper.cs new file mode 100644 index 0000000..fb4f494 --- /dev/null +++ b/src/UniGetUI.PackageEngine.Managers.Scoop/Helpers/ScoopPkgOperationHelper.cs @@ -0,0 +1,135 @@ +using UniGetUI.Core.SettingsEngine; +using UniGetUI.PackageEngine.Classes.Manager.BaseProviders; +using UniGetUI.PackageEngine.Enums; +using UniGetUI.PackageEngine.Interfaces; +using UniGetUI.PackageEngine.Serializable; +using Architecture = UniGetUI.PackageEngine.Enums.Architecture; + +namespace UniGetUI.PackageEngine.Managers.ScoopManager; + +internal sealed class ScoopPkgOperationHelper : BasePkgOperationHelper +{ + public ScoopPkgOperationHelper(Scoop manager) + : base(manager) { } + + protected override IReadOnlyList _getOperationParameters( + IPackage package, + InstallOptions options, + OperationType operation + ) + { + List parameters = + [ + operation switch + { + OperationType.Install => Manager.Properties.InstallVerb, + OperationType.Update => Manager.Properties.UpdateVerb, + OperationType.Uninstall => Manager.Properties.UninstallVerb, + _ => throw new InvalidDataException("Invalid package operation"), + }, + ]; + + // If source is ellipsed, a local path, or a URL manifest, omit source argument + if (package.Source.Name.Contains("...") || package.Source.Name.Contains(":\\") || package.Source.Name.StartsWith("http")) + parameters.Add($"{package.Id}"); + else + parameters.Add($"{package.Source.Name}/{package.Id}"); + + if ( + package.OverridenOptions.Scope == PackageScope.Global + || ( + package.OverridenOptions.Scope is null + && options.InstallationScope == PackageScope.Global + ) + ) + { + // Scoop requires admin rights to install global packages + package.OverridenOptions.RunAsAdministrator = true; + parameters.Add("--global"); + } + + parameters.AddRange( + operation switch + { + OperationType.Update => options.CustomParameters_Update, + OperationType.Uninstall => options.CustomParameters_Uninstall, + _ => options.CustomParameters_Install, + } + ); + + if (operation is OperationType.Uninstall) + { + if (options.RemoveDataOnUninstall) + parameters.Add("--purge"); + } + else + { + if (options.SkipHashCheck) + parameters.Add("--skip-hash-check"); + } + + if (operation is OperationType.Install) + { + parameters.AddRange( + options.Architecture switch + { + Architecture.x64 => ["--arch", "64bit"], + Architecture.x86 => ["--arch", "32bit"], + Architecture.arm64 => ["--arch", "arm64"], + _ => [], + } + ); + } + + return parameters; + } + + protected override OperationVeredict _getOperationResult( + IPackage package, + OperationType operation, + IReadOnlyList processOutput, + int returnCode + ) + { + string output_string = string.Join("\n", processOutput); + if ( + package.OverridenOptions.Scope != PackageScope.Global + && output_string.Contains("Try again with the --global (or -g) flag instead") + ) + { + package.OverridenOptions.Scope = PackageScope.Global; + package.OverridenOptions.RunAsAdministrator = true; + return OperationVeredict.AutoRetry; + } + + if ( + package.OverridenOptions.RunAsAdministrator != true + && ( + output_string.Contains("requires admin rights") + || output_string.Contains("requires administrator rights") + || output_string.Contains("you need admin rights to install global apps") + ) + ) + { + package.OverridenOptions.RunAsAdministrator = true; + return OperationVeredict.AutoRetry; + } + + // Scoop can't resolve shims through the fresh 'current' junction in some contexts; an elevated (trusted) junction fixes it, so retry as admin unless elevation is disabled. See #4892 + if ( + package.OverridenOptions.RunAsAdministrator != true + && returnCode is not 0 + && !Settings.Get(Settings.K.ProhibitElevation) + && output_string.Contains("Can't shim") + ) + { + package.OverridenOptions.RunAsAdministrator = true; + return OperationVeredict.AutoRetry; + } + + if (output_string.Contains("ERROR") || returnCode is not 0) + return OperationVeredict.Failure; + + return OperationVeredict.Success; + } +} diff --git a/src/UniGetUI.PackageEngine.Managers.Scoop/Helpers/ScoopSourceHelper.cs b/src/UniGetUI.PackageEngine.Managers.Scoop/Helpers/ScoopSourceHelper.cs new file mode 100644 index 0000000..44b55e9 --- /dev/null +++ b/src/UniGetUI.PackageEngine.Managers.Scoop/Helpers/ScoopSourceHelper.cs @@ -0,0 +1,172 @@ +using System.Diagnostics; +using System.Text.RegularExpressions; +using UniGetUI.Core.Logging; +using UniGetUI.PackageEngine.Classes.Manager; +using UniGetUI.PackageEngine.Classes.Manager.Providers; +using UniGetUI.PackageEngine.Enums; +using UniGetUI.PackageEngine.Interfaces; +using UniGetUI.PackageEngine.ManagerClasses.Classes; + +namespace UniGetUI.PackageEngine.Managers.ScoopManager +{ + internal sealed class ScoopSourceHelper : BaseSourceHelper + { + public ScoopSourceHelper(Scoop manager) + : base(manager) { } + + protected override OperationVeredict _getAddSourceOperationVeredict( + IManagerSource source, + int ReturnCode, + string[] Output + ) + { + return ReturnCode == 0 ? OperationVeredict.Success : OperationVeredict.Failure; + } + + public override string[] GetAddSourceParameters(IManagerSource source) + { + return ["bucket", "add", source.Name, source.Url.ToString()]; + } + + protected override OperationVeredict _getRemoveSourceOperationVeredict( + IManagerSource source, + int ReturnCode, + string[] Output + ) + { + return ReturnCode == 0 ? OperationVeredict.Success : OperationVeredict.Failure; + } + + public override string[] GetRemoveSourceParameters(IManagerSource source) + { + return ["bucket", "rm", source.Name]; + } + + protected override IReadOnlyList GetSources_UnSafe() + { + using var p = new Process + { + StartInfo = new ProcessStartInfo + { + FileName = Manager.Status.ExecutablePath, + Arguments = Manager.Status.ExecutableCallArgs + " bucket list", + RedirectStandardOutput = true, + RedirectStandardError = true, + RedirectStandardInput = true, + UseShellExecute = false, + CreateNoWindow = true, + StandardInputEncoding = System.Text.Encoding.UTF8, + StandardOutputEncoding = System.Text.Encoding.UTF8, + }, + }; + + IProcessTaskLogger logger = Manager.TaskLogger.CreateNew( + LoggableTaskType.ListSources, + p + ); + + p.Start(); + + List lines = []; + string? line; + while ((line = p.StandardOutput.ReadLine()) is not null) + { + logger.AddToStdOut(line); + lines.Add(line); + } + logger.AddToStdErr(p.StandardError.ReadToEnd()); + p.WaitForExit(); + logger.Close(p.ExitCode); + + return ParseSources(lines); + } + + internal IReadOnlyList ParseSources(IEnumerable lines) + { + List sources = []; + bool dashesPassed = false; + + foreach (string line in lines) + { + try + { + if (!dashesPassed) + { + if (line.Contains("---")) + { + dashesPassed = true; + } + + continue; + } + + if (string.IsNullOrWhiteSpace(line)) + { + continue; + } + + string[] elements = Regex + .Replace( + Regex.Replace(line, "[1234567890 :.-][AaPp][Mm][\\W]", "").Trim(), + " {2,}", + " " + ) + .Split(' ', StringSplitOptions.RemoveEmptyEntries); + if (elements.Length < 5) + { + continue; + } + + if ( + !elements[1].Contains("https://") + && !elements[1].Contains("http://") + ) + { + elements[1] = Path.Join( + Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), + "scoop", + "buckets", + elements[0].Trim() + ); + } + else + { + elements[1] = Regex.Replace(elements[1], @"^(.*)\.git$", "$1"); + } + + try + { + sources.Add( + new ManagerSource( + Manager, + elements[0].Trim(), + new Uri(elements[1]), + int.Parse(elements[4].Trim()), + elements[2].Trim() + " " + elements[3].Trim() + ) + ); + } + catch (Exception ex) + { + Logger.Warn(ex); + sources.Add( + new ManagerSource( + Manager, + elements[0].Trim(), + new Uri(elements[1]), + -1, + "1/1/1970" + ) + ); + } + } + catch (Exception e) + { + Logger.Warn(e); + } + } + + return sources; + } + } +} diff --git a/src/UniGetUI.PackageEngine.Managers.Scoop/InternalsVisibleTo.cs b/src/UniGetUI.PackageEngine.Managers.Scoop/InternalsVisibleTo.cs new file mode 100644 index 0000000..eeb63da --- /dev/null +++ b/src/UniGetUI.PackageEngine.Managers.Scoop/InternalsVisibleTo.cs @@ -0,0 +1,3 @@ +using System.Runtime.CompilerServices; + +[assembly: InternalsVisibleTo("UniGetUI.PackageEngine.Tests")] diff --git a/src/UniGetUI.PackageEngine.Managers.Scoop/Scoop.cs b/src/UniGetUI.PackageEngine.Managers.Scoop/Scoop.cs new file mode 100644 index 0000000..b4bc191 --- /dev/null +++ b/src/UniGetUI.PackageEngine.Managers.Scoop/Scoop.cs @@ -0,0 +1,615 @@ +using System.Diagnostics; +using System.Text.RegularExpressions; +using UniGetUI.Core.Classes; +using UniGetUI.Core.Data; +using UniGetUI.Core.Logging; +using UniGetUI.Core.SettingsEngine; +using UniGetUI.Core.Tools; +using UniGetUI.Interface.Enums; +using UniGetUI.PackageEngine.Classes.Manager; +using UniGetUI.PackageEngine.Classes.Manager.Classes; +using UniGetUI.PackageEngine.Classes.Manager.ManagerHelpers; +using UniGetUI.PackageEngine.Enums; +using UniGetUI.PackageEngine.Interfaces; +using UniGetUI.PackageEngine.ManagerClasses.Classes; +using UniGetUI.PackageEngine.ManagerClasses.Manager; +using UniGetUI.PackageEngine.PackageClasses; +using UniGetUI.PackageEngine.Structs; +using Architecture = UniGetUI.PackageEngine.Enums.Architecture; + +namespace UniGetUI.PackageEngine.Managers.ScoopManager +{ + public class Scoop : PackageManager + { + public static string[] FALSE_PACKAGE_IDS = ["No", "WARN"]; + public static string[] FALSE_PACKAGE_VERSIONS = + [ + "Matches", + "Install", + "failed", + "failed,", + "Manifest", + "removed", + "removed,", + ]; + + private long LastScoopSourceUpdateTime; + + public Scoop() + { + Dependencies = + [ + // Scoop-Search is required for search to work + new ManagerDependency( + "Scoop-Search", + CoreData.PowerShell5, + "-ExecutionPolicy Bypass -NoLogo -NoProfile -Command \"& {scoop install main/scoop-search; if($error.count -ne 0){pause}}\"", + "scoop install main/scoop-search", + async () => (await CoreTools.WhichAsync("scoop-search.exe")).Item1 + ), + // GIT is required for scoop updates to work + new ManagerDependency( + "Git", + CoreData.PowerShell5, + "-ExecutionPolicy Bypass -NoLogo -NoProfile -Command \"& {scoop install main/git; if($error.count -ne 0){pause}}\"", + "scoop install main/git", + async () => (await CoreTools.WhichAsync("git.exe")).Item1 + ), + ]; + + Capabilities = new ManagerCapabilities + { + CanRunAsAdmin = true, + CanSkipIntegrityChecks = true, + CanDownloadInstaller = true, + CanListDependencies = true, + CanRemoveDataOnUninstall = true, + SupportsCustomArchitectures = true, + SupportedCustomArchitectures = + [ + Architecture.x86, + Architecture.x64, + Architecture.arm64, + ], + SupportsCustomScopes = true, + SupportsCustomSources = true, + Sources = new SourceCapabilities + { + KnowsPackageCount = true, + KnowsUpdateDate = true, + }, + SupportsProxy = ProxySupport.No, + SupportsProxyAuth = false, + KnowsPackageReleaseDate = PackageReleaseDateSupport.No, + }; + + Properties = new ManagerProperties + { + Id = "scoop", + Name = "Scoop", + Description = CoreTools.Translate( + "Great repository of unknown but useful utilities and other interesting packages.
Contains: Utilities, Command-line programs, General Software (extras bucket required)" + ), + IconId = IconType.Scoop, + ColorIconId = "scoop_color", + ExecutableFriendlyName = "scoop", + InstallVerb = "install", + UpdateVerb = "update", + UninstallVerb = "uninstall", + KnownSources = + [ + new ManagerSource( + this, + "main", + new Uri("https://github.com/ScoopInstaller/Main") + ), + new ManagerSource( + this, + "extras", + new Uri("https://github.com/ScoopInstaller/Extras") + ), + new ManagerSource( + this, + "versions", + new Uri("https://github.com/ScoopInstaller/Versions") + ), + new ManagerSource( + this, + "nirsoft", + new Uri("https://github.com/ScoopInstaller/Nirsoft") + ), + new ManagerSource( + this, + "sysinternals", + new Uri("https://github.com/niheaven/scoop-sysinternals") + ), + new ManagerSource( + this, + "php", + new Uri("https://github.com/ScoopInstaller/PHP") + ), + new ManagerSource( + this, + "nerd-fonts", + new Uri("https://github.com/matthewjberger/scoop-nerd-fonts") + ), + new ManagerSource( + this, + "nonportable", + new Uri("https://github.com/ScoopInstaller/Nonportable") + ), + new ManagerSource( + this, + "java", + new Uri("https://github.com/ScoopInstaller/Java") + ), + new ManagerSource( + this, + "games", + new Uri("https://github.com/Calinou/scoop-games") + ), + ], + DefaultSource = new ManagerSource( + this, + "main", + new Uri("https://github.com/ScoopInstaller/Main") + ), + }; + + SourcesHelper = new ScoopSourceHelper(this); + DetailsHelper = new ScoopPkgDetailsHelper(this); + OperationHelper = new ScoopPkgOperationHelper(this); + } + + internal IReadOnlyList ParseSearchOutput(IEnumerable lines) + { + List packages = []; + IManagerSource source = Properties.DefaultSource; + + foreach (string line in lines) + { + if (line.StartsWith("'")) + { + string sourceName = line.Split(" ")[0].Replace("'", ""); + source = SourcesHelper.Factory.GetSourceOrDefault(sourceName); + continue; + } + + if (string.IsNullOrWhiteSpace(line)) + { + continue; + } + + string[] elements = line.Trim().Split(' ', StringSplitOptions.RemoveEmptyEntries); + if (elements.Length < 2) + { + continue; + } + + for (int i = 0; i < elements.Length; i++) + { + elements[i] = elements[i].Trim(); + } + + if ( + FALSE_PACKAGE_IDS.Contains(elements[0]) + || FALSE_PACKAGE_VERSIONS.Contains(elements[1]) + ) + { + continue; + } + + packages.Add( + new Package( + CoreTools.FormatAsName(elements[0]), + elements[0], + elements[1].Replace("(", "").Replace(")", ""), + source, + this + ) + ); + } + + return packages; + } + + internal IReadOnlyList ParseAvailableUpdates( + IEnumerable lines, + IEnumerable installedPackages + ) + { + Dictionary installedPackageMap = []; + foreach (IPackage installedPackage in installedPackages) + { + string key = installedPackage.Id + "." + installedPackage.VersionString; + if (!installedPackageMap.ContainsKey(key)) + { + installedPackageMap.Add(key, installedPackage); + } + } + + List packages = []; + bool dashesPassed = false; + foreach (string line in lines) + { + if (!dashesPassed) + { + if (line.Contains("---")) + { + dashesPassed = true; + } + + continue; + } + + if (string.IsNullOrWhiteSpace(line)) + { + continue; + } + + string[] elements = Regex + .Replace(line, " {2,}", " ") + .Trim() + .Split(' ', StringSplitOptions.RemoveEmptyEntries); + if (elements.Length < 3) + { + continue; + } + + for (int i = 0; i < elements.Length; i++) + { + elements[i] = elements[i].Trim(); + } + + if ( + FALSE_PACKAGE_IDS.Contains(elements[0]) + || FALSE_PACKAGE_VERSIONS.Contains(elements[1]) + || FALSE_PACKAGE_VERSIONS.Contains(elements[2]) + ) + { + continue; + } + + if ( + installedPackageMap.TryGetValue( + elements[0] + "." + elements[1], + out IPackage? installedPackage + ) + ) + { + OverridenInstallationOptions options = new(installedPackage.OverridenOptions.Scope); + packages.Add( + new Package( + CoreTools.FormatAsName(elements[0]), + elements[0], + elements[1], + elements[2], + installedPackage.Source, + this, + options + ) + ); + } + } + + return packages; + } + + internal IReadOnlyList ParseInstalledPackages(IEnumerable lines) + { + List packages = []; + bool dashesPassed = false; + foreach (string line in lines) + { + if (!dashesPassed) + { + if (line.Contains("---")) + { + dashesPassed = true; + } + + continue; + } + + if (string.IsNullOrWhiteSpace(line)) + { + continue; + } + + string[] elements = Regex + .Replace(line, " {2,}", " ") + .Trim() + .Split(' ', StringSplitOptions.RemoveEmptyEntries); + if (elements.Length < 3) + { + continue; + } + + if (elements[2].Contains(":\\")) + { + var path = Regex.Match( + line, + "[A-Za-z]:(?:[\\\\\\/][^\\\\\\/\\n]+)+(?:.json|…)" + ); + if (!string.IsNullOrEmpty(path.Value)) + { + elements[2] = path.Value; + } + } + + for (int i = 0; i < elements.Length; i++) + { + elements[i] = elements[i].Trim(); + } + + if ( + FALSE_PACKAGE_IDS.Contains(elements[0]) + || FALSE_PACKAGE_VERSIONS.Contains(elements[1]) + ) + { + continue; + } + + OverridenInstallationOptions options = new( + line.Contains("Global install") ? PackageScope.Global : PackageScope.User + ); + + packages.Add( + new Package( + CoreTools.FormatAsName(elements[0]), + elements[0], + elements[1], + SourcesHelper.Factory.GetSourceOrDefault(elements[2]), + this, + options + ) + ); + } + + return packages; + } + + protected override IReadOnlyList FindPackages_UnSafe(string query) + { + var (found, path) = CoreTools.Which("scoop-search.exe"); + if (!found) + { + using Process proc = new() + { + StartInfo = new ProcessStartInfo + { + FileName = Status.ExecutablePath, + Arguments = Status.ExecutableCallArgs + " install main/scoop-search", + UseShellExecute = false, + RedirectStandardOutput = true, + RedirectStandardError = true, + CreateNoWindow = true, + }, + }; + IProcessTaskLogger aux_logger = TaskLogger.CreateNew( + LoggableTaskType.InstallManagerDependency, + proc + ); + proc.Start(); + aux_logger.AddToStdOut(proc.StandardOutput.ReadToEnd()); + aux_logger.AddToStdErr(proc.StandardError.ReadToEnd()); + proc.WaitForExit(); + aux_logger.Close(proc.ExitCode); + path = "scoop-search.exe"; + } + + using Process p = new() + { + StartInfo = new ProcessStartInfo + { + FileName = path, + Arguments = query, + RedirectStandardOutput = true, + RedirectStandardError = true, + UseShellExecute = false, + CreateNoWindow = true, + StandardOutputEncoding = System.Text.Encoding.UTF8, + }, + }; + p.StartInfo = CoreTools.UpdateEnvironmentVariables(p.StartInfo); + IProcessTaskLogger logger = TaskLogger.CreateNew(LoggableTaskType.FindPackages, p); + + p.Start(); + + List lines = []; + string? line; + while ((line = p.StandardOutput.ReadLine()) is not null) + { + logger.AddToStdOut(line); + lines.Add(line); + } + logger.AddToStdErr(p.StandardError.ReadToEnd()); + p.WaitForExit(); + logger.Close(p.ExitCode); + return ParseSearchOutput(lines); + } + + protected override IReadOnlyList GetAvailableUpdates_UnSafe() + { + IReadOnlyList installedPackages = GetInstalledPackages(); + + using Process p = new() + { + StartInfo = new ProcessStartInfo + { + FileName = Status.ExecutablePath, + Arguments = Status.ExecutableCallArgs + " status -l", + RedirectStandardOutput = true, + RedirectStandardError = true, + UseShellExecute = false, + CreateNoWindow = true, + StandardOutputEncoding = System.Text.Encoding.UTF8, + }, + }; + IProcessTaskLogger logger = TaskLogger.CreateNew(LoggableTaskType.ListUpdates, p); + + p.Start(); + + List lines = []; + string? line; + while ((line = p.StandardOutput.ReadLine()) is not null) + { + logger.AddToStdOut(line); + lines.Add(line); + } + logger.AddToStdErr(p.StandardError.ReadToEnd()); + p.WaitForExit(); + logger.Close(p.ExitCode); + return ParseAvailableUpdates(lines, installedPackages); + } + + protected override IReadOnlyList GetInstalledPackages_UnSafe() => + TaskRecycler>.RunOrAttach(_getInstalledPackages_UnSafe, 15); + + private IReadOnlyList _getInstalledPackages_UnSafe() + { + using Process p = new() + { + StartInfo = new ProcessStartInfo + { + FileName = Status.ExecutablePath, + Arguments = Status.ExecutableCallArgs + " list", + RedirectStandardOutput = true, + RedirectStandardError = true, + UseShellExecute = false, + CreateNoWindow = true, + StandardOutputEncoding = System.Text.Encoding.UTF8, + }, + }; + IProcessTaskLogger logger = TaskLogger.CreateNew( + LoggableTaskType.ListInstalledPackages, + p + ); + p.Start(); + + List lines = []; + string? line; + while ((line = p.StandardOutput.ReadLine()) is not null) + { + logger.AddToStdOut(line); + lines.Add(line); + } + logger.AddToStdErr(p.StandardError.ReadToEnd()); + p.WaitForExit(); + logger.Close(p.ExitCode); + return ParseInstalledPackages(lines); + } + + public override void RefreshPackageIndexes() + { + if (new TimeSpan(DateTime.Now.Ticks - LastScoopSourceUpdateTime).TotalMinutes < 10) + { + Logger.Info( + "Scoop buckets have been already refreshed in the last ten minutes, skipping." + ); + return; + } + LastScoopSourceUpdateTime = DateTime.Now.Ticks; + using Process p = new(); + ProcessStartInfo StartInfo = new() + { + FileName = Status.ExecutablePath, + Arguments = Status.ExecutableCallArgs + " update", + UseShellExecute = false, + RedirectStandardOutput = true, + RedirectStandardError = true, + RedirectStandardInput = true, + CreateNoWindow = true, + StandardOutputEncoding = System.Text.Encoding.UTF8, + }; + p.StartInfo = StartInfo; + IProcessTaskLogger logger = TaskLogger.CreateNew(LoggableTaskType.RefreshIndexes, p); + p.Start(); + logger.AddToStdOut(p.StandardOutput.ReadToEnd()); + logger.AddToStdErr(p.StandardError.ReadToEnd()); + p.WaitForExit(); + logger.Close(p.ExitCode); + } + + public override IReadOnlyList FindCandidateExecutableFiles() => + CoreTools.WhichMultiple("scoop.ps1"); + + protected override void _loadManagerExecutableFile( + out bool found, + out string path, + out string callArguments + ) + { + path = CoreData.PowerShell5; + var (pwshFound, pwshPath) = CoreTools.Which("pwsh.exe"); + if (pwshFound) + path = pwshPath; + + var (_found, executable) = GetExecutableFile(); + found = _found; + callArguments = + $"-NoProfile -ExecutionPolicy Bypass -Command \"{executable.Replace(" ", "` ")}\" "; + } + + protected override void _loadManagerVersion(out string version) + { + using Process process = new() + { + StartInfo = new ProcessStartInfo + { + FileName = Status.ExecutablePath, + Arguments = Status.ExecutableCallArgs + "--version", + UseShellExecute = false, + RedirectStandardOutput = true, + RedirectStandardError = true, + CreateNoWindow = true, + StandardOutputEncoding = System.Text.Encoding.UTF8, + }, + }; + process.Start(); + version = process.StandardOutput.ReadToEnd().Trim(); + } + + protected override void _performExtraLoadingSteps() + { + if (Settings.Get(Settings.K.EnableScoopCleanup)) + { + RunCleanup(); + } + } + + private void RunCleanup() => _ = _runCleanup(); + + private async Task _runCleanup() + { + Logger.Info("Starting scoop cleanup..."); + foreach ( + string command in new[] + { + " cache rm *", + " cleanup --all --cache", + " cleanup --all --global --cache", + } + ) + { + using Process p = new() + { + StartInfo = new ProcessStartInfo + { + FileName = Status.ExecutablePath, + Arguments = Status.ExecutableCallArgs + " " + command, + UseShellExecute = false, + RedirectStandardOutput = true, + RedirectStandardError = true, + CreateNoWindow = true, + StandardOutputEncoding = System.Text.Encoding.UTF8, + }, + }; + p.Start(); + await p.WaitForExitAsync(); + } + + Logger.Info("Scoop cleanup finished!"); + } + } +} diff --git a/src/UniGetUI.PackageEngine.Managers.Scoop/UniGetUI.PackageEngine.Managers.Scoop.csproj b/src/UniGetUI.PackageEngine.Managers.Scoop/UniGetUI.PackageEngine.Managers.Scoop.csproj new file mode 100644 index 0000000..da22e33 --- /dev/null +++ b/src/UniGetUI.PackageEngine.Managers.Scoop/UniGetUI.PackageEngine.Managers.Scoop.csproj @@ -0,0 +1,28 @@ + + + $(WindowsTargetFramework) + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/UniGetUI.PackageEngine.Managers.Snap/Helpers/SnapPkgDetailsHelper.cs b/src/UniGetUI.PackageEngine.Managers.Snap/Helpers/SnapPkgDetailsHelper.cs new file mode 100644 index 0000000..66bd30e --- /dev/null +++ b/src/UniGetUI.PackageEngine.Managers.Snap/Helpers/SnapPkgDetailsHelper.cs @@ -0,0 +1,129 @@ +using System.Diagnostics; +using UniGetUI.Core.IconEngine; +using UniGetUI.PackageEngine.Classes.Manager.BaseProviders; +using UniGetUI.PackageEngine.Enums; +using UniGetUI.PackageEngine.Interfaces; +using UniGetUI.PackageEngine.ManagerClasses.Classes; + +namespace UniGetUI.PackageEngine.Managers.SnapManager; + +internal sealed class SnapPkgDetailsHelper : BasePkgDetailsHelper +{ + public SnapPkgDetailsHelper(Snap manager) + : base(manager) { } + + protected override void GetDetails_UnSafe(IPackageDetails details) + { + using var p = new Process + { + StartInfo = new ProcessStartInfo + { + FileName = Manager.Status.ExecutablePath, + Arguments = $"info {details.Package.Id}", + UseShellExecute = false, + RedirectStandardOutput = true, + RedirectStandardError = true, + CreateNoWindow = true, + }, + }; + p.StartInfo.Environment["LANG"] = "C"; + p.StartInfo.Environment["LC_ALL"] = "C"; + + IProcessTaskLogger logger = Manager.TaskLogger.CreateNew( + LoggableTaskType.LoadPackageDetails, p); + p.Start(); + + var descLines = new List(); + bool inDescription = false; + bool inChannels = false; + + while (p.StandardOutput.ReadLine() is { } line) + { + logger.AddToStdOut(line); + + if (line.StartsWith("channels:", StringComparison.Ordinal)) + { + inChannels = true; + inDescription = false; + continue; + } + + if (inChannels && line.StartsWith(" ")) + continue; + + if (inChannels && !line.StartsWith(" ")) + inChannels = false; + + if (inDescription) + { + if (line.StartsWith(" ")) + { + var descLine = line.TrimStart(); + if (descLine != ".") descLines.Add(descLine); + continue; + } + else + { + inDescription = false; + } + } + + var colonIdx = line.IndexOf(':', StringComparison.Ordinal); + if (colonIdx <= 0) continue; + + var key = line[..colonIdx].Trim().ToLowerInvariant(); + var value = line[(colonIdx + 1)..].Trim(); + + switch (key) + { + case "summary": + details.Description = value; + break; + case "publisher": + details.Publisher = value.Replace("\u2713", "").Trim(); + break; + case "license": + details.License = value; + break; + case "homepage": + if (Uri.TryCreate(value, UriKind.Absolute, out var homepage)) + details.HomepageUrl = homepage; + break; + case "store-url": + if (Uri.TryCreate(value, UriKind.Absolute, out var storeUrl)) + details.ManifestUrl = storeUrl; + break; + case "description": + if (value == "|") + { + details.Description = ""; + inDescription = true; + } + else + { + details.Description = value; + } + break; + } + } + + if (descLines.Count > 0) + details.Description = (details.Description ?? "") + "\n" + string.Join("\n", descLines); + + logger.AddToStdErr(p.StandardError.ReadToEnd()); + p.WaitForExit(); + logger.Close(p.ExitCode); + } + + protected override CacheableIcon? GetIcon_UnSafe(IPackage package) + => throw new NotImplementedException(); + + protected override IReadOnlyList GetScreenshots_UnSafe(IPackage package) + => Array.Empty(); + + protected override string? GetInstallLocation_UnSafe(IPackage package) + => $"/snap/{package.Id}/current"; + + protected override IReadOnlyList GetInstallableVersions_UnSafe(IPackage package) + => throw new InvalidOperationException("Snap does not support installing arbitrary versions"); +} diff --git a/src/UniGetUI.PackageEngine.Managers.Snap/Helpers/SnapPkgOperationHelper.cs b/src/UniGetUI.PackageEngine.Managers.Snap/Helpers/SnapPkgOperationHelper.cs new file mode 100644 index 0000000..b4b3836 --- /dev/null +++ b/src/UniGetUI.PackageEngine.Managers.Snap/Helpers/SnapPkgOperationHelper.cs @@ -0,0 +1,55 @@ +using UniGetUI.PackageEngine.Classes.Manager.BaseProviders; +using UniGetUI.PackageEngine.Enums; +using UniGetUI.PackageEngine.Interfaces; +using UniGetUI.PackageEngine.Serializable; + +namespace UniGetUI.PackageEngine.Managers.SnapManager; + +internal sealed class SnapPkgOperationHelper : BasePkgOperationHelper +{ + public SnapPkgOperationHelper(Snap manager) + : base(manager) { } + + protected override IReadOnlyList _getOperationParameters( + IPackage package, + InstallOptions options, + OperationType operation) + { + options.RunAsAdministrator = true; + + List parameters = + [ + operation switch + { + OperationType.Install => Manager.Properties.InstallVerb, + OperationType.Uninstall => Manager.Properties.UninstallVerb, + OperationType.Update => Manager.Properties.UpdateVerb, + _ => throw new InvalidDataException("Invalid package operation"), + }, + ]; + + parameters.Add(package.Id); + + if (operation == OperationType.Uninstall) + parameters.Add("--purge"); + + parameters.AddRange( + operation switch + { + OperationType.Update => options.CustomParameters_Update, + OperationType.Uninstall => options.CustomParameters_Uninstall, + _ => options.CustomParameters_Install, + }); + + return parameters; + } + + protected override OperationVeredict _getOperationResult( + IPackage package, + OperationType operation, + IReadOnlyList processOutput, + int returnCode) + { + return returnCode == 0 ? OperationVeredict.Success : OperationVeredict.Failure; + } +} diff --git a/src/UniGetUI.PackageEngine.Managers.Snap/Snap.cs b/src/UniGetUI.PackageEngine.Managers.Snap/Snap.cs new file mode 100644 index 0000000..9c2cb7b --- /dev/null +++ b/src/UniGetUI.PackageEngine.Managers.Snap/Snap.cs @@ -0,0 +1,225 @@ +using System.Diagnostics; +using System.Text.RegularExpressions; +using UniGetUI.Core.Tools; +using UniGetUI.Interface.Enums; +using UniGetUI.PackageEngine.Classes.Manager; +using UniGetUI.PackageEngine.Enums; +using UniGetUI.PackageEngine.ManagerClasses.Classes; +using UniGetUI.PackageEngine.ManagerClasses.Manager; +using UniGetUI.PackageEngine.PackageClasses; + +namespace UniGetUI.PackageEngine.Managers.SnapManager; + +public partial class Snap : PackageManager +{ + [GeneratedRegex(@"^(\S+)\s+(\S+)")] + private static partial Regex InstalledLineRegex(); + + [GeneratedRegex(@"^(\S+)\s+(\S+)")] + private static partial Regex UpdateLineRegex(); + + [GeneratedRegex(@"^(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(.+)$")] + private static partial Regex FindLineRegex(); + + public Snap() + { + Dependencies = []; + + Capabilities = new ManagerCapabilities + { + CanRunAsAdmin = true, + CanSkipIntegrityChecks = true, + SupportsCustomSources = false, + SupportsProxy = ProxySupport.No, + SupportsProxyAuth = false, + KnowsPackageReleaseDate = PackageReleaseDateSupport.No, + }; + + var snapcraftSource = new ManagerSource(this, "snapcraft", new Uri("https://snapcraft.io")); + + Properties = new ManagerProperties + { + Id = "snap", + Name = "Snap", + Description = CoreTools.Translate( + "The universal Linux package manager by Canonical.
Contains: Snap packages from the Snapcraft store" + ), + IconId = IconType.Snap, + ColorIconId = "snap", + ExecutableFriendlyName = "snap", + InstallVerb = "install", + UpdateVerb = "refresh", + UninstallVerb = "remove", + DefaultSource = snapcraftSource, + KnownSources = [snapcraftSource], + }; + + DetailsHelper = new SnapPkgDetailsHelper(this); + OperationHelper = new SnapPkgOperationHelper(this); + } + + public override IReadOnlyList FindCandidateExecutableFiles() + { + var candidates = new List(CoreTools.WhichMultiple("snap")); + foreach (var path in new[] { "/usr/bin/snap", "/usr/local/bin/snap" }) + { + if (File.Exists(path) && !candidates.Contains(path)) + candidates.Add(path); + } + return candidates; + } + + protected override void _loadManagerExecutableFile( + out bool found, + out string path, + out string callArguments) + { + (found, path) = GetExecutableFile(); + callArguments = ""; + } + + protected override void _loadManagerVersion(out string version) + { + using var p = new Process + { + StartInfo = new ProcessStartInfo + { + FileName = Status.ExecutablePath, + Arguments = "--version", + UseShellExecute = false, + RedirectStandardOutput = true, + RedirectStandardError = true, + CreateNoWindow = true, + }, + }; + p.Start(); + var line = p.StandardOutput.ReadLine()?.Trim() ?? ""; + var parts = line.Split(' '); + version = parts.Length >= 2 ? parts[1] : line; + p.StandardError.ReadToEnd(); + p.WaitForExit(); + } + + public override void RefreshPackageIndexes() + { + using var p = new Process + { + StartInfo = new ProcessStartInfo + { + FileName = Status.ExecutablePath, + Arguments = "refresh --list", + UseShellExecute = false, + RedirectStandardOutput = true, + RedirectStandardError = true, + CreateNoWindow = true, + }, + }; + IProcessTaskLogger logger = TaskLogger.CreateNew(LoggableTaskType.RefreshIndexes, p); + p.Start(); + logger.AddToStdOut(p.StandardOutput.ReadToEnd()); + logger.AddToStdErr(p.StandardError.ReadToEnd()); + p.WaitForExit(); + logger.Close(p.ExitCode); + } + + protected override IReadOnlyList FindPackages_UnSafe(string query) + { + using var p = new Process + { + StartInfo = new ProcessStartInfo + { + FileName = Status.ExecutablePath, + Arguments = $"find {CoreTools.EnsureSafeQueryString(query)}", + UseShellExecute = false, + RedirectStandardOutput = true, + RedirectStandardError = true, + CreateNoWindow = true, + }, + }; + p.StartInfo.Environment["LANG"] = "C"; + p.StartInfo.Environment["LC_ALL"] = "C"; + IProcessTaskLogger logger = TaskLogger.CreateNew(LoggableTaskType.FindPackages, p); + p.Start(); + + List outputLines = []; + while (p.StandardOutput.ReadLine() is { } line) + { + logger.AddToStdOut(line); + outputLines.Add(line); + } + + logger.AddToStdErr(p.StandardError.ReadToEnd()); + p.WaitForExit(); + logger.Close(p.ExitCode); + + return ParseSearchResults(outputLines, DefaultSource, this); + } + + protected override IReadOnlyList GetInstalledPackages_UnSafe() + { + using var p = new Process + { + StartInfo = new ProcessStartInfo + { + FileName = Status.ExecutablePath, + Arguments = "list", + UseShellExecute = false, + RedirectStandardOutput = true, + RedirectStandardError = true, + CreateNoWindow = true, + }, + }; + p.StartInfo.Environment["LANG"] = "C"; + p.StartInfo.Environment["LC_ALL"] = "C"; + IProcessTaskLogger logger = TaskLogger.CreateNew(LoggableTaskType.ListInstalledPackages, p); + p.Start(); + + List outputLines = []; + while (p.StandardOutput.ReadLine() is { } line) + { + logger.AddToStdOut(line); + outputLines.Add(line); + } + + logger.AddToStdErr(p.StandardError.ReadToEnd()); + p.WaitForExit(); + logger.Close(p.ExitCode); + + return ParseInstalledPackages(outputLines, DefaultSource, this); + } + + protected override IReadOnlyList GetAvailableUpdates_UnSafe() + { + using var p = new Process + { + StartInfo = new ProcessStartInfo + { + FileName = Status.ExecutablePath, + Arguments = "refresh --list", + UseShellExecute = false, + RedirectStandardOutput = true, + RedirectStandardError = true, + CreateNoWindow = true, + }, + }; + + p.StartInfo.Environment["LANG"] = "C"; + p.StartInfo.Environment["LC_ALL"] = "C"; + IProcessTaskLogger logger = TaskLogger.CreateNew(LoggableTaskType.ListUpdates, p); + + p.Start(); + + List outputLines = []; + while (p.StandardOutput.ReadLine() is { } line) + { + logger.AddToStdOut(line); + outputLines.Add(line); + } + + logger.AddToStdErr(p.StandardError.ReadToEnd()); + p.WaitForExit(); + logger.Close(p.ExitCode); + + return ParseAvailableUpdates(outputLines, DefaultSource, this, GetInstalledPackages_UnSafe()); + } +} diff --git a/src/UniGetUI.PackageEngine.Managers.Snap/SnapParsing.cs b/src/UniGetUI.PackageEngine.Managers.Snap/SnapParsing.cs new file mode 100644 index 0000000..6166f2c --- /dev/null +++ b/src/UniGetUI.PackageEngine.Managers.Snap/SnapParsing.cs @@ -0,0 +1,126 @@ +using UniGetUI.Core.Tools; +using UniGetUI.PackageEngine.Interfaces; +using UniGetUI.PackageEngine.PackageClasses; + +namespace UniGetUI.PackageEngine.Managers.SnapManager; + +public partial class Snap +{ + public static IReadOnlyList ParseInstalledPackages( + IEnumerable outputLines, + IManagerSource source, + IPackageManager manager) + { + var packages = new List(); + bool headerSkipped = false; + + foreach (var line in outputLines) + { + if (!headerSkipped) + { + headerSkipped = true; + continue; + } + + var trimmed = line.Trim(); + if (string.IsNullOrEmpty(trimmed)) continue; + + var match = InstalledLineRegex().Match(trimmed); + if (!match.Success) continue; + + var id = match.Groups[1].Value; + var version = match.Groups[2].Value; + packages.Add(new Package( + CoreTools.FormatAsName(id), + id, + version, + source, + manager)); + } + + return packages; + } + + public static IReadOnlyList ParseAvailableUpdates( + IEnumerable outputLines, + IManagerSource source, + IPackageManager manager, + IReadOnlyList installedPackages + ) + { + var installedPackageMap = new Dictionary(); + foreach (var installedPackage in installedPackages) + { + installedPackageMap.TryAdd(installedPackage.Id, installedPackage); + } + + var packages = new List(); + bool headerSkipped = false; + + foreach (var line in outputLines) + { + if (!headerSkipped) + { + headerSkipped = true; + continue; + } + + var trimmed = line.Trim(); + if (string.IsNullOrEmpty(trimmed)) continue; + + var match = UpdateLineRegex().Match(trimmed); + if (!match.Success) continue; + + var id = match.Groups[1].Value; + var newVersion = match.Groups[2].Value; + + if (installedPackageMap.TryGetValue(id, out var installedPackage)) + { + packages.Add(new Package( + CoreTools.FormatAsName(id), + id, + installedPackage.VersionString, + newVersion, + source, + manager)); + } + } + + return packages; + } + + public static IReadOnlyList ParseSearchResults( + IEnumerable outputLines, + IManagerSource source, + IPackageManager manager) + { + var packages = new List(); + bool headerSkipped = false; + + foreach (var line in outputLines) + { + if (!headerSkipped) + { + headerSkipped = true; + continue; + } + + var trimmed = line.Trim(); + if (string.IsNullOrEmpty(trimmed)) continue; + + var match = FindLineRegex().Match(trimmed); + if (!match.Success) continue; + + var id = match.Groups[1].Value; + var version = match.Groups[2].Value; + packages.Add(new Package( + CoreTools.FormatAsName(id), + id, + version, + source, + manager)); + } + + return packages; + } +} diff --git a/src/UniGetUI.PackageEngine.Managers.Snap/UniGetUI.PackageEngine.Managers.Snap.csproj b/src/UniGetUI.PackageEngine.Managers.Snap/UniGetUI.PackageEngine.Managers.Snap.csproj new file mode 100644 index 0000000..a0903da --- /dev/null +++ b/src/UniGetUI.PackageEngine.Managers.Snap/UniGetUI.PackageEngine.Managers.Snap.csproj @@ -0,0 +1,23 @@ + + + $(SharedTargetFrameworks) + + + + + + + + + + + + + + + + + + + + diff --git a/src/UniGetUI.PackageEngine.Managers.Vcpkg/Helpers/VcpkgPkgDetailsHelper.cs b/src/UniGetUI.PackageEngine.Managers.Vcpkg/Helpers/VcpkgPkgDetailsHelper.cs new file mode 100644 index 0000000..566b1c0 --- /dev/null +++ b/src/UniGetUI.PackageEngine.Managers.Vcpkg/Helpers/VcpkgPkgDetailsHelper.cs @@ -0,0 +1,128 @@ +using System.Text.Json.Nodes; +using System.Text.RegularExpressions; +using UniGetUI.Core.Data; +using UniGetUI.Core.IconEngine; +using UniGetUI.Core.Tools; +using UniGetUI.PackageEngine.Classes.Manager.BaseProviders; +using UniGetUI.PackageEngine.Enums; +using UniGetUI.PackageEngine.Interfaces; +using UniGetUI.PackageEngine.ManagerClasses.Classes; + +namespace UniGetUI.PackageEngine.Managers.VcpkgManager +{ + internal sealed class VcpkgPkgDetailsHelper : BasePkgDetailsHelper + { + public VcpkgPkgDetailsHelper(Vcpkg manager) + : base(manager) { } + + protected override void GetDetails_UnSafe(IPackageDetails details) + { + INativeTaskLogger logger = Manager.TaskLogger.CreateNew( + LoggableTaskType.LoadPackageDetails + ); + + const string VCPKG_REPO = "microsoft/vcpkg"; + const string VCPKG_PORT_PATH = "master/ports"; + const string VCPKG_PORT_FILE = "vcpkg.json"; + string PackagePrefix = details.Package.Id.Split(":")[0]; + string PackageName = PackagePrefix.Split("[")[0]; + + using HttpClient client = new(CoreTools.GenericHttpClientParameters); + client.DefaultRequestHeaders.UserAgent.ParseAdd(CoreData.UserAgentString); + using var request = new HttpRequestMessage( + HttpMethod.Get, + $"https://raw.githubusercontent.com/{VCPKG_REPO}/refs/heads/{VCPKG_PORT_PATH}/{PackageName}/{VCPKG_PORT_FILE}" + ); + using HttpResponseMessage response = client.Send(request); + response.EnsureSuccessStatusCode(); + string JsonString = response.Content.ReadAsStringAsync().GetAwaiter().GetResult(); + + JsonObject? contents = JsonNode.Parse(JsonString) as JsonObject; + + details.Description = contents?["description"]?.ToString(); + details.Publisher = contents?["maintainers"]?.ToString(); + // vcpkg doesn't store the author, for some reason??? + if ( + Uri.TryCreate( + contents?["homepage"]?.ToString(), + UriKind.RelativeOrAbsolute, + out var homepageUrl + ) + ) + details.HomepageUrl = homepageUrl; + details.License = contents?["license"]?.ToString(); + details.ManifestUrl = new Uri( + $"https://github.com/{VCPKG_REPO}/blob/{VCPKG_PORT_PATH}/{PackageName}/{VCPKG_PORT_FILE}" + ); + // TODO: since each change results in a new commit to the file, you could determine the `UpdateDate` via figuring out the date of the last commit that changed the file was. + // Unfortunately, the GitHub API doesn't seem to allow getting the commit that changed a file, but you can get the date of a commit with + // https://api.github.com/repos/{VCPKG_REPO}/commits/{CommitHash} + + List Tags = []; + // TODO: the "features" and "dependencies" keys could also be good candidates for tags, however their type specifications are all over - + // strings, dictionaries, arrays - so one would first have to figure out how to handle that. + // See https://learn.microsoft.com/en-us/vcpkg/reference/vcpkg-json + if (PackagePrefix.Contains('[')) + { + Tags.Add($"{CoreTools.Translate("library")}: " + PackageName); + Tags.Add( + $"{CoreTools.Translate("feature")}: " + PackagePrefix.Split('[')[^1][..^1] + ); + } + + details.Tags = Tags.ToArray(); + + details.Dependencies.Clear(); + foreach (var iDep in contents?["dependencies"]?.AsArray() ?? []) + { + string? val = iDep?.GetValue(); + if (val is not null) + { + details.Dependencies.Add( + new() + { + Name = val, + Version = "", + Mandatory = true, + } + ); + } + } + + logger.Close(0); + } + + protected override CacheableIcon? GetIcon_UnSafe(IPackage package) + { + throw new NotImplementedException(); + } + + protected override IReadOnlyList GetScreenshots_UnSafe(IPackage package) + { + throw new NotImplementedException(); + } + + protected override string? GetInstallLocation_UnSafe(IPackage package) + { + var (rootFound, rootPath) = Vcpkg.GetVcpkgRoot(); + if (!rootFound) + { + return null; + } + + string PackageId = Regex.Replace(package.Id.Replace(":", "_"), @"\[.*\]", String.Empty); + var PackagePath = Path.Join(rootPath, "packages", PackageId); + var VcpkgInstalledPath = Path.Join(rootPath, "installed", package.Id.Split(":")[1]); + return Directory.Exists(PackagePath) + ? PackagePath + : Directory.Exists(VcpkgInstalledPath) + ? VcpkgInstalledPath + : null; + } + + protected override IReadOnlyList GetInstallableVersions_UnSafe(IPackage package) + { + throw new NotImplementedException(); + } + } +} diff --git a/src/UniGetUI.PackageEngine.Managers.Vcpkg/Helpers/VcpkgPkgOperationHelper.cs b/src/UniGetUI.PackageEngine.Managers.Vcpkg/Helpers/VcpkgPkgOperationHelper.cs new file mode 100644 index 0000000..1b6a7b9 --- /dev/null +++ b/src/UniGetUI.PackageEngine.Managers.Vcpkg/Helpers/VcpkgPkgOperationHelper.cs @@ -0,0 +1,48 @@ +using UniGetUI.PackageEngine.Classes.Manager.BaseProviders; +using UniGetUI.PackageEngine.Enums; +using UniGetUI.PackageEngine.Interfaces; +using UniGetUI.PackageEngine.Serializable; + +namespace UniGetUI.PackageEngine.Managers.VcpkgManager; + +internal sealed class VcpkgPkgOperationHelper : BasePkgOperationHelper +{ + public VcpkgPkgOperationHelper(Vcpkg manager) + : base(manager) { } + + protected override IReadOnlyList _getOperationParameters( + IPackage package, + InstallOptions options, + OperationType operation + ) + { + List parameters = operation switch + { + OperationType.Install => [Manager.Properties.InstallVerb, package.Id], + OperationType.Update => [Manager.Properties.UpdateVerb, package.Id, "--no-dry-run"], + OperationType.Uninstall => [Manager.Properties.UninstallVerb, package.Id, "--recurse"], + _ => throw new InvalidDataException("Invalid package operation"), + }; + + parameters.AddRange( + operation switch + { + OperationType.Update => options.CustomParameters_Update, + OperationType.Uninstall => options.CustomParameters_Uninstall, + _ => options.CustomParameters_Install, + } + ); + + return parameters; + } + + protected override OperationVeredict _getOperationResult( + IPackage package, + OperationType operation, + IReadOnlyList processOutput, + int returnCode + ) + { + return returnCode == 0 ? OperationVeredict.Success : OperationVeredict.Failure; + } +} diff --git a/src/UniGetUI.PackageEngine.Managers.Vcpkg/Helpers/VcpkgSourceHelper.cs b/src/UniGetUI.PackageEngine.Managers.Vcpkg/Helpers/VcpkgSourceHelper.cs new file mode 100644 index 0000000..3cf9aba --- /dev/null +++ b/src/UniGetUI.PackageEngine.Managers.Vcpkg/Helpers/VcpkgSourceHelper.cs @@ -0,0 +1,43 @@ +using UniGetUI.PackageEngine.Classes.Manager; +using UniGetUI.PackageEngine.Classes.Manager.Providers; +using UniGetUI.PackageEngine.Enums; +using UniGetUI.PackageEngine.Interfaces; + +namespace UniGetUI.PackageEngine.Managers.VcpkgManager +{ + internal sealed class VcpkgSourceHelper : BaseSourceHelper + { + public VcpkgSourceHelper(Vcpkg manager) + : base(manager) { } + + public override string[] GetAddSourceParameters(IManagerSource source) => + throw new NotImplementedException(); + + public override string[] GetRemoveSourceParameters(IManagerSource source) => + throw new NotImplementedException(); + + protected override OperationVeredict _getAddSourceOperationVeredict( + IManagerSource source, + int ReturnCode, + string[] Output + ) => throw new NotImplementedException(); + + protected override OperationVeredict _getRemoveSourceOperationVeredict( + IManagerSource source, + int ReturnCode, + string[] Output + ) => throw new NotImplementedException(); + + protected override IReadOnlyList GetSources_UnSafe() + { + List Sources = []; + + foreach (string Triplet in Vcpkg.GetSystemTriplets()) + { + Sources.Add(new ManagerSource(Manager, Triplet, Vcpkg.URI_VCPKG_IO)); + } + + return Sources; + } + } +} diff --git a/src/UniGetUI.PackageEngine.Managers.Vcpkg/UniGetUI.PackageEngine.Managers.Vcpkg.csproj b/src/UniGetUI.PackageEngine.Managers.Vcpkg/UniGetUI.PackageEngine.Managers.Vcpkg.csproj new file mode 100644 index 0000000..a0903da --- /dev/null +++ b/src/UniGetUI.PackageEngine.Managers.Vcpkg/UniGetUI.PackageEngine.Managers.Vcpkg.csproj @@ -0,0 +1,23 @@ + + + $(SharedTargetFrameworks) + + + + + + + + + + + + + + + + + + + + diff --git a/src/UniGetUI.PackageEngine.Managers.Vcpkg/Vcpkg.cs b/src/UniGetUI.PackageEngine.Managers.Vcpkg/Vcpkg.cs new file mode 100644 index 0000000..1ef3e63 --- /dev/null +++ b/src/UniGetUI.PackageEngine.Managers.Vcpkg/Vcpkg.cs @@ -0,0 +1,565 @@ +using System.Diagnostics; +using System.Runtime.InteropServices; +using System.Text; +using System.Text.RegularExpressions; +using UniGetUI.Core.Data; +using UniGetUI.Core.Logging; +using UniGetUI.Core.SettingsEngine; +using UniGetUI.Core.Tools; +using UniGetUI.Interface.Enums; +using UniGetUI.PackageEngine.Classes.Manager; +using UniGetUI.PackageEngine.Classes.Manager.Classes; +using UniGetUI.PackageEngine.Classes.Manager.ManagerHelpers; +using UniGetUI.PackageEngine.Enums; +using UniGetUI.PackageEngine.ManagerClasses.Classes; +using UniGetUI.PackageEngine.ManagerClasses.Manager; +using UniGetUI.PackageEngine.PackageClasses; +using Architecture = System.Runtime.InteropServices.Architecture; + +namespace UniGetUI.PackageEngine.Managers.VcpkgManager +{ + public class Vcpkg : PackageManager + { + public Dictionary TripletSourceMap; + public static Uri URI_VCPKG_IO = new Uri("https://vcpkg.io/"); + + public Vcpkg() + { + Dependencies = + [ + // GIT is required for vcpkg updates to work + new ManagerDependency( + "Git", + CoreData.PowerShell5, + "-ExecutionPolicy Bypass -NoLogo -NoProfile -Command \"& {winget install --id Git.Git --exact " + + "--source winget --accept-source-agreements --accept-package-agreements --force; if($error.count -ne 0){pause}}\"", + "winget install --id Git.Git --exact --source winget", + async () => (await CoreTools.WhichAsync("git.exe")).Item1 + ), + ]; + + Capabilities = new ManagerCapabilities + { + CanRunAsAdmin = true, + SupportsCustomSources = true, + CanListDependencies = true, + SupportsProxy = ProxySupport.No, + SupportsProxyAuth = false, + KnowsPackageReleaseDate = PackageReleaseDateSupport.No, + }; + + string DefaultTriplet = GetDefaultTriplet(); + + TripletSourceMap = new Dictionary + { + { "arm-neon-android", new ManagerSource(this, "arm-neon-android", URI_VCPKG_IO) }, + { "arm64-android", new ManagerSource(this, "arm64-android", URI_VCPKG_IO) }, + { "arm64-uwp", new ManagerSource(this, "arm64-uwp", URI_VCPKG_IO) }, + { "arm64-windows", new ManagerSource(this, "arm64-windows", URI_VCPKG_IO) }, + { "x64-android", new ManagerSource(this, "x64-android", URI_VCPKG_IO) }, + { "x64-linux", new ManagerSource(this, "x64-linux", URI_VCPKG_IO) }, + { "x64-osx", new ManagerSource(this, "x64-osx", URI_VCPKG_IO) }, + { "x64-uwp", new ManagerSource(this, "x64-uwp", URI_VCPKG_IO) }, + { + "x64-windows-static", + new ManagerSource(this, "x64-windows-static", URI_VCPKG_IO) + }, + { "x64-windows", new ManagerSource(this, "x64-windows", URI_VCPKG_IO) }, + { "x86-windows", new ManagerSource(this, "x86-windows", URI_VCPKG_IO) }, + }; + + Properties = new ManagerProperties + { + Id = "vcpkg", + Name = "vcpkg", + Description = CoreTools.Translate( + "A popular C/C++ library manager. Full of C/C++ libraries and other C/C++-related utilities
Contains: C/C++ libraries and related utilities" + ), + IconId = IconType.Vcpkg, + ColorIconId = "vcpkg_color", + ExecutableFriendlyName = "vcpkg", + InstallVerb = "install", + UninstallVerb = "remove", + UpdateVerb = "upgrade", + DefaultSource = new ManagerSource(this, DefaultTriplet, URI_VCPKG_IO), + KnownSources = [.. TripletSourceMap.Values], + }; + + SourcesHelper = new VcpkgSourceHelper(this); + DetailsHelper = new VcpkgPkgDetailsHelper(this); + OperationHelper = new VcpkgPkgOperationHelper(this); + } + + protected override IReadOnlyList FindPackages_UnSafe(string query) + { + string Triplet = GetDefaultTriplet(); + + using Process p = new() + { + StartInfo = new ProcessStartInfo + { + FileName = Status.ExecutablePath, + Arguments = + Status.ExecutableCallArgs + + $" search \"{CoreTools.EnsureSafeQueryString(query)}\"", + // vcpkg has an --x-json flag that would list installed packages in JSON, but it doesn't work for this call (as of 2024-09-30-ab8988503c7cffabfd440b243a383c0a352a023d) + // TODO: Perhaps use --x-json when it is fixed + RedirectStandardOutput = true, + RedirectStandardError = true, + UseShellExecute = false, + CreateNoWindow = true, + StandardOutputEncoding = Encoding.UTF8, + }, + }; + + IProcessTaskLogger logger = TaskLogger.CreateNew(LoggableTaskType.FindPackages, p); + string? line; + List Packages = []; + + p.Start(); + + Dictionary PackageVersions = []; + string optionString = CoreTools.Translate("option"); + string unknownVersion = CoreTools.Translate("Unknown"); + while ((line = p.StandardOutput.ReadLine()) is not null) + { + logger.AddToStdOut(line); + + // Sample line: + // name(source) version description + // ffmpeg[sdl2] Sdl2 support + // sdl1 - net 1.2.8#6 Networking library for SDL + // sdl2 2.30.8 Simple DirectMedia Layer is a cross - platform development library designed... + // (note that the suboptions, with the `name[build-option]` syntax have no version) + + // to get rid of many spaces of padding + string[] PackageData = Regex.Replace(line, @"\s+", " ").Split(' '); + string PackageId = PackageData[0]; // the id with the suboption + string PackageName = PackageId; // the actual name (id - suboption) + string PackageDetailedName = PackageName; // the name with a reformatted suboption reapplied (display name) + string PackageVersion = PackageData[1]; + + if ( + PackageName.Contains('[') /* meaning its a suboption, and thus has no version */ + ) + { + PackageName = PackageId.Split('[')[0]; //..PackageName.IndexOf("[", StringComparison.Ordinal)]; + PackageDetailedName = + PackageName + $" ({optionString}: {PackageId.Split('[')[1][..^1]})"; + + if (PackageVersions.TryGetValue(PackageName, out string? value)) + { + PackageVersion = value; + } + else + { + PackageVersion = unknownVersion; + } + } + else // If the package has a specified version (it is not a suboption) + { + PackageVersions[PackageName] = PackageVersion; + } + + if (!TripletSourceMap.TryGetValue(Triplet, out ManagerSource? source)) + { + source = new ManagerSource(this, Triplet, URI_VCPKG_IO); + TripletSourceMap.Add(Triplet, source); + } + + Packages.Add( + new Package( + CoreTools.FormatAsName(PackageDetailedName), + PackageId + ":" + Triplet, + PackageVersion, + source, + this + ) + ); + } + + logger.AddToStdErr(p.StandardError.ReadToEnd()); + p.WaitForExit(); + logger.Close(p.ExitCode); + return Packages; + } + + protected override IReadOnlyList GetAvailableUpdates_UnSafe() + { + List Packages = []; + + using Process p = new() + { + StartInfo = new ProcessStartInfo + { + FileName = Status.ExecutablePath, + Arguments = Status.ExecutableCallArgs + " update", + RedirectStandardOutput = true, + RedirectStandardError = true, + UseShellExecute = false, + CreateNoWindow = true, + StandardOutputEncoding = Encoding.UTF8, + }, + }; + IProcessTaskLogger logger = TaskLogger.CreateNew(LoggableTaskType.ListUpdates, p); + + p.Start(); + + string? line; + while ((line = p.StandardOutput.ReadLine()) is not null) + { + logger.AddToStdOut(line); + + // Sample line: + // (spaces) package name: package triplet current -> latest + // brotli:x64-mingw-dynamic 1.0.9#5 -> 1.1.0#1 + if (line.StartsWith('\t')) + { + line = line.Substring(1); + string[] PackageData = Regex.Replace(line, @"\s+", " ").Split(' '); + string PackageId = PackageData[0]; + string PackageName = PackageId.Split(':')[0], + PackageTriplet = PackageId.Split(':')[1], + PackageVersionCurrent = PackageData[1], + PackageVersionLatest = PackageData[3]; + + if (!TripletSourceMap.TryGetValue(PackageTriplet, out ManagerSource? value)) + { + value = new ManagerSource(this, PackageTriplet, URI_VCPKG_IO); + TripletSourceMap[PackageTriplet] = value; + } + + Packages.Add( + new Package( + CoreTools.FormatAsName(PackageName), + PackageId, + PackageVersionCurrent, + PackageVersionLatest, + value, + this + ) + ); + } + } + + logger.AddToStdErr(p.StandardError.ReadToEnd()); + p.WaitForExit(); + logger.Close(p.ExitCode); + return Packages; + } + + protected override IReadOnlyList GetInstalledPackages_UnSafe() + { + using Process p = new() + { + StartInfo = new ProcessStartInfo + { + FileName = Status.ExecutablePath, + Arguments = Status.ExecutableCallArgs + " list", + // vcpkg has an --x-json flag that would list installed packages in JSON, but it's experimental + // TODO: Once --x-json is stable migrate to --x-json + RedirectStandardOutput = true, + RedirectStandardError = true, + UseShellExecute = false, + CreateNoWindow = true, + StandardOutputEncoding = Encoding.UTF8, + }, + }; + + IProcessTaskLogger logger = TaskLogger.CreateNew( + LoggableTaskType.ListInstalledPackages, + p + ); + string? line; + List Packages = []; + + p.Start(); + + Dictionary PackageVersions = []; + while ((line = p.StandardOutput.ReadLine()) is not null) + { + logger.AddToStdOut(line); + + // Sample line: + // name:triplet (source) version description + // curl:x64-mingw-dynamic 8.1.2#2 A library for transferring data with URLs + // curl[non-http]:x64-mingw-dynamic Enables protocols beyond HTTP/HTTPS/HTTP2 + // (note that the suboptions, with the `name[build-option]` syntax have no version) + + // to get rid of many spaces of padding + string[] PackageData = Regex.Replace(line, @"\s+", " ").Split(' '); + string PackageId = PackageData[0]; + string PackageName = PackageId.Split(':')[0], + PackageTriplet = PackageId.Split(':')[1], + PackageVersion = PackageData[1]; + if ( + PackageId.Contains('[') /* meaning its a suboption, and thus has no version */ + ) + { + PackageVersion = PackageVersions[PackageName.Split("[")[0]]; + } + else + { + PackageVersions[PackageName] = PackageVersion; + } + + if (!TripletSourceMap.TryGetValue(PackageTriplet, out ManagerSource? value)) + { + value = new ManagerSource(this, PackageTriplet, URI_VCPKG_IO); + TripletSourceMap[PackageTriplet] = value; + } + + Packages.Add( + new Package( + CoreTools.FormatAsName(PackageName), + PackageId, + PackageVersion, + value, + this + ) + ); + } + + logger.AddToStdErr(p.StandardError.ReadToEnd()); + p.WaitForExit(); + logger.Close(p.ExitCode); + return Packages; + } + + public override IReadOnlyList FindCandidateExecutableFiles() + { + string vcpkgExe = OperatingSystem.IsWindows() ? "vcpkg.exe" : "vcpkg"; + var candidates = CoreTools.WhichMultiple(vcpkgExe); + + var (rootFound, rootPath) = GetVcpkgRoot(); + if (rootFound) + { + string VcpkgLocation = Path.Join(rootPath, vcpkgExe); + if (File.Exists(VcpkgLocation)) + candidates.Add(VcpkgLocation); + } + + return candidates; + } + + protected override void _loadManagerExecutableFile( + out bool found, + out string path, + out string callArguments + ) + { + var (exeFound, exePath) = GetExecutableFile(); + var (rootFound, _) = GetVcpkgRoot(); + + if (!rootFound) + Logger.Error( + "Vcpkg root was not found. Please define the %VCPKG_ROOT% environment variable or define it from UniGetUI Settings" + ); + found = exeFound && rootFound; + path = exePath; + + string vcpkgRoot = Settings.GetValue(Settings.K.CustomVcpkgRoot); + callArguments = vcpkgRoot == "" ? "" : $" --vcpkg-root=\"{vcpkgRoot}\""; + } + + protected override void _loadManagerVersion(out string version) + { + var (_, rootPath) = GetVcpkgRoot(); + + using Process process = new() + { + StartInfo = new ProcessStartInfo + { + FileName = Status.ExecutablePath, + Arguments = Status.ExecutableCallArgs + " version", + UseShellExecute = false, + RedirectStandardOutput = true, + RedirectStandardError = true, + CreateNoWindow = true, + StandardOutputEncoding = Encoding.UTF8, + StandardErrorEncoding = Encoding.UTF8, + }, + }; + process.Start(); + version = process.StandardOutput.ReadLine()?.Trim() ?? ""; + version += RuntimeInformation.IsOSPlatform(OSPlatform.Windows) + ? $"\n%VCPKG_ROOT% = {rootPath}" + : $"\n$VCPKG_ROOT = {rootPath}"; + } + + protected override void _performExtraLoadingSteps() + { + var (_, rootPath) = GetVcpkgRoot(); + bool isWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows); + using Process p2 = new() + { + StartInfo = new ProcessStartInfo + { + FileName = isWindows ? "cmd.exe" : "sh", + WorkingDirectory = rootPath, + Arguments = isWindows ? "/C .\\bootstrap-vcpkg.bat" : "./bootstrap-vcpkg.sh", + UseShellExecute = false, + CreateNoWindow = true, + }, + }; + IProcessTaskLogger processLogger2 = TaskLogger.CreateNew( + LoggableTaskType.RefreshIndexes, + p2 + ); + p2.Start(); + p2.WaitForExit(); + processLogger2.Close(p2.ExitCode); + } + + public override void RefreshPackageIndexes() + { + var (vcpkgRootFound, vcpkgRoot) = GetVcpkgRoot(); + var (gitFound, gitPath) = CoreTools.Which("git"); + + if (!Status.Found || !gitFound || !vcpkgRootFound) + { + INativeTaskLogger logger = TaskLogger.CreateNew(LoggableTaskType.RefreshIndexes); + if (Settings.Get(Settings.K.DisableUpdateVcpkgGitPorts)) + logger.Error("User has disabled updating sources"); + if (!Status.Found) + logger.Error("Vcpkg was not found???"); + if (!gitFound) + logger.Error("Vcpkg sources won't be updated since git was not found"); + if (!vcpkgRootFound) + logger.Error( + "Cannot update vcpkg port files as requested: the VCPKG_ROOT environment variable or custom vcpkg root setting was not set" + ); + logger.Close(Settings.Get(Settings.K.DisableUpdateVcpkgGitPorts) ? 0 : 1); + return; + } + + using Process p = new() + { + StartInfo = new ProcessStartInfo + { + FileName = gitPath, + WorkingDirectory = vcpkgRoot, + Arguments = "pull --all", + UseShellExecute = false, + RedirectStandardOutput = true, + RedirectStandardError = true, + CreateNoWindow = true, + }, + }; + IProcessTaskLogger processLogger = TaskLogger.CreateNew( + LoggableTaskType.RefreshIndexes, + p + ); + p.Start(); + p.WaitForExit(); + processLogger.AddToStdOut(p.StandardOutput.ReadToEnd()); + processLogger.AddToStdErr(p.StandardError.ReadToEnd()); + processLogger.Close(p.ExitCode); + } + + public static Tuple GetVcpkgRoot() + { + string? vcpkgRoot = Settings.GetValue(Settings.K.CustomVcpkgRoot); + if (vcpkgRoot == "") + { + vcpkgRoot = Environment.GetEnvironmentVariable("VCPKG_ROOT"); + } + + if (vcpkgRoot == null) + { + // Unfortunately, we can't use `GetVcpkgPath` or `GetExecutableFile` + // for this as it would become a bunch of functions calling each other + var paths = CoreTools.WhichMultiple("vcpkg"); + foreach (string path in paths) + { + string? dir = Path.GetDirectoryName(path); + if (string.IsNullOrEmpty(dir)) + { + continue; + } + + // Make sure the root is a valid root not just a random directory + if (Path.Exists(Path.Join(dir, "triplets"))) + { + vcpkgRoot = dir; + break; + } + } + } + + return Tuple.Create(vcpkgRoot != null, vcpkgRoot ?? ""); + } + + public static string GetDefaultTriplet() + { + string DefaultTriplet = Settings.GetValue(Settings.K.DefaultVcpkgTriplet); + if (DefaultTriplet == "") + { + DefaultTriplet = Environment.GetEnvironmentVariable("VCPKG_DEFAULT_TRIPLET") ?? ""; + } + + if (DefaultTriplet == "") + { + if (RuntimeInformation.OSArchitecture is Architecture.X64) + DefaultTriplet = "x64-"; + else if (RuntimeInformation.OSArchitecture is Architecture.X86) + DefaultTriplet = "x86-"; + else if (RuntimeInformation.OSArchitecture is Architecture.Arm64) + DefaultTriplet = "arm64-"; + + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + DefaultTriplet += "windows"; + if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) + DefaultTriplet += "osx"; + if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) + DefaultTriplet += "linux"; + } + + return DefaultTriplet; + } + + public static List GetSystemTriplets() + { + List Triplets = []; + // Retrieve all triplets on the system (in %VCPKG_ROOT%\triplets{\community}) + var (vcpkgRootFound, vcpkgRoot) = GetVcpkgRoot(); + if (vcpkgRootFound) + { + string tripletLocation = Path.Join(vcpkgRoot, "triplets"); + string communityTripletLocation = Path.Join(vcpkgRoot, "triplets", "community"); + + IEnumerable tripletFiles = []; + if (Path.Exists(tripletLocation)) + { + tripletFiles = tripletFiles.Concat(Directory.EnumerateFiles(tripletLocation)); + } + else + { + Logger.Warn( + $"The built-in triplet directory {tripletLocation} does not exist; triplets will not be loaded." + ); + } + + if (Path.Exists(communityTripletLocation)) + { + tripletFiles = tripletFiles.Concat( + Directory.EnumerateFiles(communityTripletLocation) + ); + } + else + { + Logger.Warn( + $"The community triplet directory {communityTripletLocation} does not exist; community triplets will not be loaded." + ); + } + + foreach (string tripletFile in tripletFiles) + { + Triplets.Add(Path.GetFileNameWithoutExtension(tripletFile)); + } + } + + return Triplets.Distinct().ToList(); + } + } +} diff --git a/src/UniGetUI.PackageEngine.Managers.WinGet/ClientHelpers/IWinGetManagerHelpers.cs b/src/UniGetUI.PackageEngine.Managers.WinGet/ClientHelpers/IWinGetManagerHelpers.cs new file mode 100644 index 0000000..5379b84 --- /dev/null +++ b/src/UniGetUI.PackageEngine.Managers.WinGet/ClientHelpers/IWinGetManagerHelpers.cs @@ -0,0 +1,20 @@ +using UniGetUI.PackageEngine.Interfaces; +using UniGetUI.PackageEngine.PackageClasses; + +namespace UniGetUI.PackageEngine.Managers.WingetManager +{ + internal static class WinGetHelper + { + public static IWinGetManagerHelper Instance = null!; + } + + internal interface IWinGetManagerHelper + { + public IReadOnlyList GetAvailableUpdates_UnSafe(); + public IReadOnlyList GetInstalledPackages_UnSafe(); + public IReadOnlyList FindPackages_UnSafe(string query); + public IReadOnlyList GetSources_UnSafe(); + public IReadOnlyList GetInstallableVersions_Unsafe(IPackage package); + public void GetPackageDetails_UnSafe(IPackageDetails details); + } +} diff --git a/src/UniGetUI.PackageEngine.Managers.WinGet/ClientHelpers/NativePackageHandler.cs b/src/UniGetUI.PackageEngine.Managers.WinGet/ClientHelpers/NativePackageHandler.cs new file mode 100644 index 0000000..cc04985 --- /dev/null +++ b/src/UniGetUI.PackageEngine.Managers.WinGet/ClientHelpers/NativePackageHandler.cs @@ -0,0 +1,229 @@ +using System.Collections.Concurrent; +using Microsoft.Management.Deployment; +using UniGetUI.Core.Logging; +using UniGetUI.PackageEngine.Enums; +using UniGetUI.PackageEngine.Interfaces; +using InstallOptions = UniGetUI.PackageEngine.Serializable.InstallOptions; + +namespace UniGetUI.PackageEngine.Managers.WingetManager; + +public static class NativePackageHandler +{ + private static readonly ConcurrentDictionary __nativePackages = new(); + private static readonly ConcurrentDictionary __nativeDetails = + new(); + private static ConcurrentDictionary __nativeInstallers_Install = + new(); + private static ConcurrentDictionary __nativeInstallers_Uninstall = + new(); + + /// + /// Get (cache or load) the native package for the given package, if any; + /// + /// + public static CatalogPackage? GetPackage(IPackage package) + { + if ( + NativeWinGetHelper.ExternalFactory is null + || NativeWinGetHelper.ExternalWinGetManager is null + ) + return null; + + __nativePackages.TryGetValue(package.GetHash(), out CatalogPackage? catalogPackage); + if (catalogPackage is not null) + return catalogPackage; + + // Rarely a package will not be available in cache (native WinGet helper should always call AddPackage) + // so it makes no sense to add TaskRecycler.RunOrAttach() here. (Only imported packages may arrive at this point) + catalogPackage = _findPackageOnCatalog(package); + if (catalogPackage is not null) + AddPackage(package, (CatalogPackage)catalogPackage); + + return catalogPackage; + } + + /// + /// Adds an external CatalogPackage to the internal database + /// + public static void AddPackage(IPackage package, CatalogPackage catalogPackage) + { + __nativePackages[package.GetHash()] = catalogPackage; + } + + /// + /// Get (cached or load) the native package details for the given package, if any; + /// + public static CatalogPackageMetadata? GetDetails(IPackage package) + // => TaskRecycler.RunOrAttach(_getDetails, package); + // + //private static CatalogPackageMetadata? _getDetails(IPackage package) + { + try + { + if ( + __nativeDetails.TryGetValue(package.GetHash(), out CatalogPackageMetadata? metadata) + ) + return metadata; + + CatalogPackage? catalogPackage = GetPackage(package); + if (catalogPackage is null) + return null; + + var availableVersions = catalogPackage.AvailableVersions?.ToArray() ?? []; + if (availableVersions.Length > 0) + { + metadata = catalogPackage + .GetPackageVersionInfo(availableVersions[0]) + .GetCatalogPackageMetadata(); + } + + if (metadata is not null) + __nativeDetails[package.GetHash()] = metadata; + + return metadata; + } + catch + { + throw; + } + } + + /// + /// Get (cached or load) the native installer for the given package, if any. The operation type determines wether + /// + public static PackageInstallerInfo? GetInstallationOptions( + IPackage package, + InstallOptions unigetuiOptions, + OperationType operation + ) + // => TaskRecycler.RunOrAttach(_getInstallationOptions, package, operation); + // + //private static PackageInstallerInfo? _getInstallationOptions(IPackage package, OperationType operation) + { + if (NativeWinGetHelper.ExternalFactory is null) + return null; + + PackageInstallerInfo? installerInfo; + if (operation is OperationType.Uninstall) + installerInfo = _getInstallationOptionsOnDict( + package, + ref __nativeInstallers_Uninstall, + true, + unigetuiOptions + ); + else + installerInfo = _getInstallationOptionsOnDict( + package, + ref __nativeInstallers_Install, + false, + unigetuiOptions + ); + + return installerInfo; + } + + public static void Clear() + { + __nativePackages.Clear(); + __nativeDetails.Clear(); + __nativeInstallers_Install.Clear(); + __nativeInstallers_Uninstall.Clear(); + } + + private static PackageInstallerInfo? _getInstallationOptionsOnDict( + IPackage package, + ref ConcurrentDictionary source, + bool installed, + InstallOptions unigetuiOptions + ) + { + if (source.TryGetValue(package.GetHash(), out PackageInstallerInfo? installerInfo)) + return installerInfo; + + PackageVersionInfo? catalogPackage; + if (installed) + catalogPackage = GetPackage(package)?.InstalledVersion; + else + catalogPackage = GetPackage(package)?.DefaultInstallVersion; + + Microsoft.Management.Deployment.InstallOptions? wingetOptions = + NativeWinGetHelper.ExternalFactory?.CreateInstallOptions(); + Microsoft.Management.Deployment.InstallOptions? wingetDefaultOptions = + NativeWinGetHelper.ExternalFactory?.CreateInstallOptions(); + + if (wingetOptions is null) + { + Logger.Error("WinGetFactory.CreateInstallOptions returned null!"); + return installerInfo; + } + + if (unigetuiOptions.InstallationScope is PackageScope.Machine) + { + wingetOptions.PackageInstallScope = PackageInstallScope.System; + } + else if (unigetuiOptions.InstallationScope is PackageScope.User) + { + wingetOptions.PackageInstallScope = PackageInstallScope.User; + } + + installerInfo = catalogPackage?.GetApplicableInstaller(wingetOptions); + installerInfo ??= catalogPackage?.GetApplicableInstaller(wingetDefaultOptions); + + if (installerInfo is not null) + source[package.GetHash()] = installerInfo; + + return installerInfo; + } + + private static CatalogPackage? _findPackageOnCatalog(IPackage package) + { + if ( + NativeWinGetHelper.ExternalWinGetManager is null + || NativeWinGetHelper.ExternalFactory is null + ) + return null; + + PackageCatalogReference Catalog = + NativeWinGetHelper.ExternalWinGetManager.GetPackageCatalogByName(package.Source.Name); + if (Catalog is null) + { + Logger.Error( + "Failed to get catalog " + package.Source.Name + ". Is the package local?" + ); + return null; + } + + // Connect to catalog + Catalog.AcceptSourceAgreements = true; + ConnectResult ConnectResult = Catalog.Connect(); + if (ConnectResult.Status != ConnectResultStatus.Ok) + { + Logger.Error("Failed to connect to catalog " + package.Source.Name); + return null; + } + + // Match only the exact same Id + FindPackagesOptions packageMatchFilter = + NativeWinGetHelper.ExternalFactory.CreateFindPackagesOptions(); + PackageMatchFilter filters = NativeWinGetHelper.ExternalFactory.CreatePackageMatchFilter(); + filters.Field = PackageMatchField.Id; + filters.Value = package.Id; + filters.Option = PackageFieldMatchOption.Equals; + packageMatchFilter.Filters.Add(filters); + packageMatchFilter.ResultLimit = 1; + var SearchResult = Task.Run(() => + ConnectResult.PackageCatalog.FindPackages(packageMatchFilter) + ); + + if (SearchResult?.Result?.Matches is null || SearchResult.Result.Matches.Count == 0) + { + Logger.Error( + "Failed to find package " + package.Id + " in catalog " + package.Source.Name + ); + return null; + } + + // Return the Native Package + return SearchResult.Result.Matches[0].CatalogPackage; + } +} diff --git a/src/UniGetUI.PackageEngine.Managers.WinGet/ClientHelpers/NativeWinGetHelper.cs b/src/UniGetUI.PackageEngine.Managers.WinGet/ClientHelpers/NativeWinGetHelper.cs new file mode 100644 index 0000000..c223e4e --- /dev/null +++ b/src/UniGetUI.PackageEngine.Managers.WinGet/ClientHelpers/NativeWinGetHelper.cs @@ -0,0 +1,809 @@ +using System.Runtime.ExceptionServices; +using System.Runtime.InteropServices; +using Microsoft.Management.Deployment; +using UniGetUI.Core.Classes; +using UniGetUI.Core.Logging; +using UniGetUI.Core.Tools; +using UniGetUI.PackageEngine.Classes.Manager; +using UniGetUI.PackageEngine.Enums; +using UniGetUI.PackageEngine.Interfaces; +using UniGetUI.PackageEngine.ManagerClasses.Classes; +using UniGetUI.PackageEngine.PackageClasses; +using UniGetUI.PackageEngine.Structs; +using WindowsPackageManager.Interop; + +namespace UniGetUI.PackageEngine.Managers.WingetManager; + +internal sealed class NativeWinGetHelper : IWinGetManagerHelper +{ + public WindowsPackageManagerFactory Factory = null!; + public static WindowsPackageManagerFactory? ExternalFactory; + public PackageManager WinGetManager = null!; + public static PackageManager? ExternalWinGetManager; + private readonly WinGet Manager; + private readonly Func _systemCliHelperFactory; + private readonly Func>? _localPackagesProvider; + private readonly IPingetPackageDetailsProvider _pingetPackageDetailsProvider; + private int _activeLocalPackageQueries; + private ExceptionDispatchInfo? _lastActivationException; + + public string ActivationMode { get; private set; } = string.Empty; + public string ActivationSource { get; private set; } = string.Empty; + + internal static IReadOnlyList PreferredActivationModes => + [ + "packaged COM registration", + "lower-trust COM registration", + ]; + + public NativeWinGetHelper(WinGet manager) + : this( + manager, + systemCliHelperFactory: null, + skipInitialization: false, + localPackagesProvider: null + ) + { } + + internal NativeWinGetHelper( + WinGet manager, + Func? systemCliHelperFactory, + bool skipInitialization, + Func>? localPackagesProvider, + IPingetPackageDetailsProvider? pingetPackageDetailsProvider = null + ) + { + Manager = manager; + _systemCliHelperFactory = + systemCliHelperFactory + ?? (static manager => manager.CreateCliHelperForSelectedCliTool()); + _localPackagesProvider = localPackagesProvider; + _pingetPackageDetailsProvider = + pingetPackageDetailsProvider ?? new PingetPackageDetailsProvider(); + if (CoreTools.IsAdministrator()) + { + Logger.Info( + "Running elevated, WinGet class registration is likely to fail unless using lower trust class registration is allowed in settings" + ); + } + + if (skipInitialization) + { + return; + } + + if (TryInitializeStandardFactory()) + { + return; + } + + if (TryInitializeLowerTrustFactory()) + { + return; + } + + _lastActivationException?.Throw(); + + throw new InvalidOperationException("WinGet: Failed to initialize system COM activation."); + } + + internal bool HasActiveLocalPackageQuery => Volatile.Read(ref _activeLocalPackageQueries) > 0; + + internal void SetLocalPackageQueryInProgressForTesting(bool value) + { + Interlocked.Exchange(ref _activeLocalPackageQueries, value ? 1 : 0); + } + + private bool TryInitializeLowerTrustFactory() + { + try + { + var factory = new WindowsPackageManagerStandardFactory(allowLowerTrustRegistration: true); + var winGetManager = factory.CreatePackageManager(); + ApplyFactory( + factory, + winGetManager, + "lower-trust COM registration", + "system COM registration (allow lower trust)", + "Connected to WinGet API using lower-trust COM activation." + ); + return true; + } + catch (WinGetComActivationException ex) + { + _lastActivationException = ExceptionDispatchInfo.Capture(ex); + Logger.Warn( + $"Lower-trust WinGet COM activation failed ({ex.HResultHex}: {ex.Reason})." + ); + return false; + } + catch (Exception ex) + { + _lastActivationException = ExceptionDispatchInfo.Capture(ex); + Logger.Warn( + $"Lower-trust WinGet COM activation failed ({ex.Message})." + ); + return false; + } + } + + private bool TryInitializeStandardFactory() + { + try + { + var factory = new WindowsPackageManagerStandardFactory(); + var winGetManager = factory.CreatePackageManager(); + ApplyFactory( + factory, + winGetManager, + "packaged COM registration", + "system COM registration", + "Connected to WinGet API using packaged COM activation." + ); + return true; + } + catch (WinGetComActivationException ex) + { + _lastActivationException = ExceptionDispatchInfo.Capture(ex); + Logger.Warn( + $"Packaged WinGet COM activation failed ({ex.HResultHex}: {ex.Reason}), attempting lower-trust activation..." + ); + return false; + } + catch (Exception ex) + { + _lastActivationException = ExceptionDispatchInfo.Capture(ex); + Logger.Warn( + $"Packaged WinGet COM activation failed ({ex.Message}), attempting lower-trust activation..." + ); + return false; + } + } + + private void ApplyFactory( + WindowsPackageManagerFactory factory, + PackageManager winGetManager, + string activationMode, + string activationSource, + string successMessage + ) + { + Factory = factory; + WinGetManager = winGetManager; + ActivationMode = activationMode; + ActivationSource = activationSource; + ExternalFactory = factory; + ExternalWinGetManager = winGetManager; + + Logger.Info(successMessage); + Logger.Info($"WinGet activation mode selected: {ActivationMode} | Source: {ActivationSource}"); + } + + public IReadOnlyList FindPackages_UnSafe(string query) + { + List packages = []; + INativeTaskLogger logger = Manager.TaskLogger.CreateNew(LoggableTaskType.FindPackages); + Dictionary< + (PackageCatalogReference, PackageMatchField), + Task + > FindPackageTasks = []; + + // Load catalogs + logger.Log("Loading available catalogs..."); + IReadOnlyList AvailableCatalogs = + WinGetManager.GetPackageCatalogs(); + + // Spawn Tasks to find packages on catalogs + logger.Log("Spawning catalog fetching tasks..."); + foreach (PackageCatalogReference CatalogReference in AvailableCatalogs.ToArray()) + { + logger.Log($"Begin search on catalog {CatalogReference.Info.Name}"); + // Connect to catalog + CatalogReference.AcceptSourceAgreements = true; + ConnectResult result = CatalogReference.Connect(); + if (result.Status == ConnectResultStatus.Ok) + { + foreach ( + var filter_type in new[] + { + PackageMatchField.Name, + PackageMatchField.Id, + PackageMatchField.Moniker, + } + ) + { + FindPackagesOptions PackageFilters = Factory.CreateFindPackagesOptions(); + + logger.Log("Generating filters..."); + // Name filter + PackageMatchFilter FilterName = Factory.CreatePackageMatchFilter(); + FilterName.Field = filter_type; + FilterName.Value = query; + FilterName.Option = PackageFieldMatchOption.ContainsCaseInsensitive; + PackageFilters.Filters.Add(FilterName); + + try + { + // Create task and spawn it + Task task = new(() => + result.PackageCatalog.FindPackages(PackageFilters) + ); + task.Start(); + + // Add task to list + FindPackageTasks.Add((CatalogReference, filter_type), task); + } + catch (Exception e) + { + logger.Error( + "WinGet: Catalog " + + CatalogReference.Info.Name + + " failed to spawn FindPackages task." + ); + logger.Error(e); + } + } + } + else + { + logger.Error( + "WinGet: Catalog " + CatalogReference.Info.Name + " failed to connect." + ); + } + } + + // Wait for tasks completion + Task.WhenAll(FindPackageTasks.Values.ToArray()).GetAwaiter().GetResult(); + logger.Log($"All catalogs fetched. Fetching results for query piece {query}"); + + foreach (var CatalogTaskPair in FindPackageTasks) + { + try + { + // Get the source for the catalog + IManagerSource source = Manager.SourcesHelper.Factory.GetSourceOrDefault( + CatalogTaskPair.Key.Item1.Info.Name + ); + + FindPackagesResult FoundPackages = CatalogTaskPair.Value.Result; + foreach (MatchResult matchResult in FoundPackages.Matches.ToArray()) + { + CatalogPackage nativePackage = matchResult.CatalogPackage; + // Create the Package item and add it to the list + logger.Log( + $"Found package: {nativePackage.Name}|{nativePackage.Id}|{nativePackage.DefaultInstallVersion.Version} on catalog {source.Name}" + ); + + var overriden_options = new OverridenInstallationOptions(); + + var UniGetUIPackage = new Package( + nativePackage.Name, + nativePackage.Id, + nativePackage.DefaultInstallVersion.Version, + source, + Manager, + overriden_options + ); + NativePackageHandler.AddPackage(UniGetUIPackage, nativePackage); + packages.Add(UniGetUIPackage); + } + } + catch (Exception e) + { + logger.Error( + "WinGet: Catalog " + + CatalogTaskPair.Key.Item1.Info.Name + + " failed to get available packages." + ); + logger.Error(e); + } + } + + logger.Close(0); + return packages; + } + + public IReadOnlyList GetAvailableUpdates_UnSafe() + { + var logger = Manager.TaskLogger.CreateNew(LoggableTaskType.ListUpdates); + IReadOnlyList nativePackages; + try + { + nativePackages = GetCachedLocalWinGetPackages(15); + } + catch (Exception ex) when (ShouldFallbackToCli(ex)) + { + return GetAvailableUpdatesFromSystemCli(ex); + } + + List packages = []; + foreach (var nativePackage in nativePackages) + { + try + { + if (!nativePackage.IsUpdateAvailable) + { + continue; + } + + if (nativePackage.DefaultInstallVersion is null) + { + Logger.Warn( + $"WinGet package {nativePackage.Id} has IsUpdateAvailable=true but DefaultInstallVersion is null, skipping" + ); + continue; + } + + if (nativePackage.DefaultInstallVersion.PackageCatalog?.Info is null) + { + Logger.Warn( + $"WinGet package {nativePackage.Id} has a DefaultInstallVersion with null PackageCatalog or Info, skipping" + ); + continue; + } + + IManagerSource source; + source = Manager.SourcesHelper.Factory.GetSourceOrDefault( + nativePackage.DefaultInstallVersion.PackageCatalog.Info.Name + ); + + string version = nativePackage.InstalledVersion.Version; + if (version == "Unknown") + version = WinGetPkgOperationHelper.GetLastInstalledVersion(nativePackage.Id); + + var UniGetUIPackage = new Package( + nativePackage.Name, + nativePackage.Id, + version, + nativePackage.DefaultInstallVersion.Version, + source, + Manager + ); + + // Trust COM IsUpdateAvailable, not the "already upgraded" cache (issue #5042). + NativePackageHandler.AddPackage(UniGetUIPackage, nativePackage); + packages.Add(UniGetUIPackage); + logger.Log( + $"Found package {nativePackage.Name} {nativePackage.Id} on source {source.Name}, from version {version} to version {nativePackage.DefaultInstallVersion.Version}" + ); + } + catch (Exception ex) + { + LogSkippedPackage(logger, nativePackage, "listing available updates", ex); + } + } + + logger.Close(0); + return packages; + } + + public IReadOnlyList GetInstalledPackages_UnSafe() + { + var logger = Manager.TaskLogger.CreateNew(LoggableTaskType.ListInstalledPackages); + IReadOnlyList nativePackages; + try + { + nativePackages = GetCachedLocalWinGetPackages(15); + } + catch (Exception ex) when (ShouldFallbackToCli(ex)) + { + return GetInstalledPackagesFromSystemCli(ex); + } + + List packages = []; + foreach (var nativePackage in nativePackages) + { + try + { + IManagerSource source; + var availableVersions = nativePackage.AvailableVersions?.ToArray() ?? []; + if (availableVersions.Length > 0) + { + var installPackage = nativePackage.GetPackageVersionInfo(availableVersions[0]); + source = Manager.SourcesHelper.Factory.GetSourceOrDefault( + installPackage.PackageCatalog.Info.Name + ); + } + else + { + source = Manager.GetLocalSource(nativePackage.Id); + } + + string version = nativePackage.InstalledVersion.Version; + if (version == "Unknown") + version = WinGetPkgOperationHelper.GetLastInstalledVersion(nativePackage.Id); + + logger.Log( + $"Found package {nativePackage.Name} {nativePackage.Id} on source {source.Name}" + ); + var UniGetUIPackage = new Package( + nativePackage.Name, + nativePackage.Id, + version, + source, + Manager + ); + NativePackageHandler.AddPackage(UniGetUIPackage, nativePackage); + packages.Add(UniGetUIPackage); + } + catch (Exception ex) + { + LogSkippedPackage(logger, nativePackage, "listing installed packages", ex); + } + } + logger.Close(0); + return packages; + } + + private IReadOnlyList GetCachedLocalWinGetPackages(int? cacheSeconds = null) + { + if (_localPackagesProvider is not null) + { + return _localPackagesProvider(); + } + + return cacheSeconds is null + ? TaskRecycler>.RunOrAttach(GetLocalWinGetPackages) + : TaskRecycler>.RunOrAttach( + GetLocalWinGetPackages, + cacheSeconds.Value + ); + } + + private IReadOnlyList GetAvailableUpdatesFromSystemCli(Exception ex) + { + var unwrappedException = UnwrapException(ex); + Logger.Warn( + $"Native WinGet update enumeration failed with {unwrappedException.GetType().Name}: {unwrappedException.Message}. Falling back to system WinGet CLI." + ); + return _systemCliHelperFactory(Manager).GetAvailableUpdates_UnSafe(); + } + + private IReadOnlyList GetInstalledPackagesFromSystemCli(Exception ex) + { + var unwrappedException = UnwrapException(ex); + Logger.Warn( + $"Native WinGet installed-package enumeration failed with {unwrappedException.GetType().Name}: {unwrappedException.Message}. Falling back to system WinGet CLI." + ); + return _systemCliHelperFactory(Manager).GetInstalledPackages_UnSafe(); + } + + private static bool ShouldFallbackToCli(Exception ex) + { + var unwrappedException = UnwrapException(ex); + + // Native COM/SEH exceptions from the WinGet COM server or its interop layer + if (unwrappedException is SEHException or COMException or AccessViolationException) + { + return true; + } + + return + unwrappedException is InvalidOperationException + && string.Equals( + unwrappedException.Message, + "WinGet: Failed to connect to composite catalog.", + StringComparison.Ordinal + ); + } + + private static Exception UnwrapException(Exception ex) + { + while (ex is AggregateException aggregateException && aggregateException.InnerException is not null) + { + ex = aggregateException.InnerException; + } + + return ex; + } + + private static void LogSkippedPackage( + INativeTaskLogger logger, + CatalogPackage nativePackage, + string operation, + Exception ex + ) + { + string packageDescription = DescribePackage(nativePackage); + logger.Error($"Skipping WinGet package while {operation}: {packageDescription}"); + logger.Error(ex); + Logger.Warn( + $"Skipping WinGet package while {operation}: {packageDescription}. {ex.GetType().Name}: {ex.Message}" + ); + } + + private static string DescribePackage(CatalogPackage nativePackage) + { + try + { + string id = nativePackage.Id; + if (!string.IsNullOrWhiteSpace(id)) + { + return id; + } + } + catch + { + } + + try + { + string name = nativePackage.Name; + if (!string.IsNullOrWhiteSpace(name)) + { + return name; + } + } + catch + { + } + + return ""; + } + + private IReadOnlyList GetLocalWinGetPackages() + { + Interlocked.Increment(ref _activeLocalPackageQueries); + var logger = Manager.TaskLogger.CreateNew(LoggableTaskType.OtherTask); + try + { + logger.Log("OtherTask: GetWinGetLocalPackages"); + var availableCatalogs = GetReachableLocalCatalogReferences(logger); + PackageCatalogReference installedSearchCatalogRef = CreateLocalCompositeCatalog( + availableCatalogs, + logger + ); + + var ConnectResult = installedSearchCatalogRef.Connect(); + if (ConnectResult.Status != ConnectResultStatus.Ok) + { + logger.Error("Failed to connect to installedSearchCatalogRef. Aborting."); + logger.Close(1); + throw new InvalidOperationException("WinGet: Failed to connect to composite catalog."); + } + + FindPackagesOptions findPackagesOptions = Factory.CreateFindPackagesOptions(); + PackageMatchFilter filter = Factory.CreatePackageMatchFilter(); + filter.Field = PackageMatchField.Id; + filter.Option = PackageFieldMatchOption.StartsWithCaseInsensitive; + filter.Value = ""; + findPackagesOptions.Filters.Add(filter); + + FindPackagesResult TaskResult; + try + { + TaskResult = ConnectResult.PackageCatalog.FindPackages(findPackagesOptions); + } + catch (Exception ex) + { + logger.Error($"FindPackages native call failed: {ex.GetType().Name}: {ex.Message}"); + logger.Close(1); + throw new InvalidOperationException("WinGet: Failed to connect to composite catalog.", ex); + } + + List foundPackages = []; + foreach (var match in TaskResult.Matches.ToArray()) + { + foundPackages.Add(match.CatalogPackage); + } + + logger.Close(0); + return foundPackages; + } + finally + { + Interlocked.Decrement(ref _activeLocalPackageQueries); + } + } + + private IReadOnlyList GetReachableLocalCatalogReferences( + INativeTaskLogger logger + ) + { + return SelectReachableCatalogs( + WinGetManager.GetPackageCatalogs().ToArray(), + static catalogRef => catalogRef.Info.Name, + catalogRef => TryConnectLocalCatalog(catalogRef, logger), + catalogName => + { + logger.Log($"Catalog {catalogName} is reachable for local package enumeration"); + }, + catalogName => + { + string message = + $"Skipping unavailable WinGet catalog {catalogName} while loading local packages"; + logger.Error(message); + Logger.Warn(message); + } + ); + } + + internal static IReadOnlyList SelectReachableCatalogs( + IEnumerable catalogs, + Func describeCatalog, + Func isReachable, + Action? onReachable = null, + Action? onSkipped = null + ) + { + List reachableCatalogs = []; + foreach (var catalog in catalogs) + { + string catalogName = describeCatalog(catalog); + if (isReachable(catalog)) + { + onReachable?.Invoke(catalogName); + reachableCatalogs.Add(catalog); + } + else + { + onSkipped?.Invoke(catalogName); + } + } + + if (reachableCatalogs.Count == 0) + { + throw new InvalidOperationException("WinGet: Failed to connect to composite catalog."); + } + + return reachableCatalogs; + } + + private bool TryConnectLocalCatalog(PackageCatalogReference catalogRef, INativeTaskLogger logger) + { + var localCatalogRef = CreateLocalCompositeCatalog([catalogRef], logger); + var connectResult = localCatalogRef.Connect(); + if (connectResult.Status == ConnectResultStatus.Ok) + { + return true; + } + + logger.Error( + $"WinGet: Catalog {catalogRef.Info.Name} failed local catalog connection with status {connectResult.Status}." + ); + return false; + } + + private PackageCatalogReference CreateLocalCompositeCatalog( + IEnumerable catalogs, + INativeTaskLogger logger + ) + { + CreateCompositePackageCatalogOptions createCompositePackageCatalogOptions = + Factory.CreateCreateCompositePackageCatalogOptions(); + foreach (var catalogRef in catalogs) + { + catalogRef.AcceptSourceAgreements = true; + logger.Log($"Adding catalog {catalogRef.Info.Name} to composite catalog"); + createCompositePackageCatalogOptions.Catalogs.Add(catalogRef); + } + + createCompositePackageCatalogOptions.CompositeSearchBehavior = + CompositeSearchBehavior.LocalCatalogs; + return WinGetManager.CreateCompositePackageCatalog(createCompositePackageCatalogOptions); + } + + public IReadOnlyList GetSources_UnSafe() + { + List sources = []; + INativeTaskLogger logger = Manager.TaskLogger.CreateNew(LoggableTaskType.ListSources); + + foreach (PackageCatalogReference catalog in WinGetManager.GetPackageCatalogs().ToList()) + { + try + { + logger.Log( + $"Found source {catalog.Info.Name} with argument {catalog.Info.Argument}" + ); + sources.Add( + new ManagerSource( + Manager, + catalog.Info.Name, + new Uri(catalog.Info.Argument), + updateDate: ( + catalog.Info.LastUpdateTime.Second != 0 + ? catalog.Info.LastUpdateTime + : DateTime.Now + ).ToString() + ) + ); + } + catch (Exception e) + { + logger.Error(e); + } + } + + logger.Close(0); + return sources; + } + + public IReadOnlyList GetInstallableVersions_Unsafe(IPackage package) + { + INativeTaskLogger logger = Manager.TaskLogger.CreateNew( + LoggableTaskType.LoadPackageVersions + ); + + var nativePackage = NativePackageHandler.GetPackage(package); + if (nativePackage is null) + return []; + + string[] versions = nativePackage.AvailableVersions.Select(x => x.Version).ToArray(); + foreach (string? version in versions) + { + logger.Log(version); + } + + logger.Close(0); + return versions ?? []; + } + + public void GetPackageDetails_UnSafe(IPackageDetails details) + { + INativeTaskLogger logger = Manager.TaskLogger.CreateNew( + LoggableTaskType.LoadPackageDetails + ); + + if (details.Package.Source.Name == "winget") + { + details.ManifestUrl = new Uri( + "https://github.com/microsoft/winget-pkgs/tree/master/manifests/" + + details.Package.Id[0].ToString().ToLower() + + "/" + + details.Package.Id.Split('.')[0] + + "/" + + string.Join( + "/", + details.Package.Id.Contains('.') + ? details.Package.Id.Split('.')[1..] + : details.Package.Id.Split('.') + ) + ); + } + else if (details.Package.Source.Name == "msstore") + { + details.ManifestUrl = new Uri( + "https://apps.microsoft.com/detail/" + details.Package.Id + ); + } + + CatalogPackageMetadata? NativeDetails = NativePackageHandler.GetDetails(details.Package); + if (NativeDetails is null) + { + logger.Close(1); + return; + } + + // Extract data from NativeDetails + if (NativeDetails.Author != "") + details.Author = NativeDetails.Author; + + if (NativeDetails.Description != "") + details.Description = NativeDetails.Description; + + if (NativeDetails.PackageUrl != "") + details.HomepageUrl = new Uri(NativeDetails.PackageUrl); + + if (NativeDetails.License != "") + details.License = NativeDetails.License; + + if (NativeDetails.LicenseUrl != "") + details.LicenseUrl = new Uri(NativeDetails.LicenseUrl); + + if (NativeDetails.Publisher != "") + details.Publisher = NativeDetails.Publisher; + + if (NativeDetails.ReleaseNotes != "") + details.ReleaseNotes = NativeDetails.ReleaseNotes; + + if (NativeDetails.ReleaseNotesUrl != "") + details.ReleaseNotesUrl = new Uri(NativeDetails.ReleaseNotesUrl); + + if (NativeDetails.Tags is not null) + details.Tags = NativeDetails.Tags.ToArray(); + + bool metadataLoaded = _pingetPackageDetailsProvider.LoadPackageDetails(details, logger); + + logger.Close(metadataLoaded ? 0 : 1); + } +} diff --git a/src/UniGetUI.PackageEngine.Managers.WinGet/ClientHelpers/PingetCliHelper.cs b/src/UniGetUI.PackageEngine.Managers.WinGet/ClientHelpers/PingetCliHelper.cs new file mode 100644 index 0000000..b43532a --- /dev/null +++ b/src/UniGetUI.PackageEngine.Managers.WinGet/ClientHelpers/PingetCliHelper.cs @@ -0,0 +1,284 @@ +using System.Diagnostics; +using System.Text; +using System.Text.Json; +using System.Text.Json.Serialization; +using Devolutions.Pinget.Core; +using UniGetUI.Core.Logging; +using UniGetUI.Core.Tools; +using UniGetUI.PackageEngine.Classes.Manager; +using UniGetUI.PackageEngine.Enums; +using UniGetUI.PackageEngine.Interfaces; +using UniGetUI.PackageEngine.ManagerClasses.Classes; +using UniGetUI.PackageEngine.PackageClasses; + +namespace UniGetUI.PackageEngine.Managers.WingetManager; + +internal sealed partial class PingetCliHelper : IWinGetManagerHelper +{ + private static readonly JsonSerializerOptions SerializationOptions = new() + { + PropertyNameCaseInsensitive = true, + }; + private static readonly PingetCliJsonContext SerializationContext = new(SerializationOptions); + + private readonly WinGet Manager; + private readonly string _cliExecutablePath; + private readonly IPingetPackageDetailsProvider _packageDetailsProvider; + + public PingetCliHelper(WinGet manager, string cliExecutablePath) + : this(manager, cliExecutablePath, new PingetPackageDetailsProvider()) { } + + internal PingetCliHelper( + WinGet manager, + string cliExecutablePath, + IPingetPackageDetailsProvider packageDetailsProvider + ) + { + Manager = manager; + _cliExecutablePath = cliExecutablePath; + _packageDetailsProvider = packageDetailsProvider; + } + + public IReadOnlyList GetAvailableUpdates_UnSafe() + { + ListResponse result = RunJson( + LoggableTaskType.ListUpdates, + "upgrade --include-unknown --output json" + ); + + List packages = []; + foreach (ListMatch match in result.Matches.Where(match => match.AvailableVersion is not null)) + { + var package = new Package( + match.Name, + match.Id, + match.InstalledVersion, + match.AvailableVersion!, + GetSource(match), + Manager + ); + + if (!WinGetPkgOperationHelper.ConsumeAlreadyUpgradedSuppression(package)) + { + packages.Add(package); + } + else + { + Logger.Warn( + $"WinGet package {package.Id} not being shown as an updated as this version has already been marked as installed" + ); + } + } + + return packages; + } + + public IReadOnlyList GetInstalledPackages_UnSafe() + { + ListResponse result = RunJson( + LoggableTaskType.ListInstalledPackages, + "list --output json" + ); + + return result + .Matches.Select(match => + new Package( + match.Name, + match.Id, + match.InstalledVersion, + GetSource(match), + Manager + ) + ) + .ToArray(); + } + + public IReadOnlyList FindPackages_UnSafe(string query) + { + SearchResponse result = RunJson( + LoggableTaskType.FindPackages, + $"search {Quote(query)} --output json" + ); + + return result + .Matches.Select(match => + new Package( + match.Name, + match.Id, + match.Version ?? "Unknown", + GetSource(match.SourceName, match.Id), + Manager + ) + ) + .ToArray(); + } + + public IReadOnlyList GetSources_UnSafe() + { + // pinget 0.4.1 dropped JSON support for `source list`; `source export` is the + // equivalent JSON-emitting command (PascalCase keys, but case-insensitive matching + // in SerializationOptions binds them to our records). + PingetSourcesResponse result = RunJson( + LoggableTaskType.ListSources, + "source export --output json" + ); + + return result + .Sources.Where(source => Uri.TryCreate(source.Arg, UriKind.Absolute, out _)) + .Select(source => + (IManagerSource) + new ManagerSource(Manager, source.Name, new Uri(source.Arg, UriKind.Absolute)) + ) + .ToArray(); + } + + public IReadOnlyList GetInstallableVersions_Unsafe(IPackage package) + { + VersionsResult result = RunJson( + LoggableTaskType.LoadPackageVersions, + $"show {WinGetPkgOperationHelper.GetIdNamePiece(package)} --versions --output json" + ); + + return result + .Versions.Select(version => + string.IsNullOrWhiteSpace(version.Channel) + ? version.Version + : $"{version.Version} [{version.Channel}]" + ) + .ToArray(); + } + + public void GetPackageDetails_UnSafe(IPackageDetails details) + { + if (details.Package.Source.Name == "winget") + { + details.ManifestUrl = new Uri( + "https://github.com/microsoft/winget-pkgs/tree/master/manifests/" + + details.Package.Id[0].ToString().ToLower() + + "/" + + details.Package.Id.Split('.')[0] + + "/" + + string.Join( + "/", + details.Package.Id.Contains('.') + ? details.Package.Id.Split('.')[1..] + : details.Package.Id.Split('.') + ) + ); + } + else if (details.Package.Source.Name == "msstore") + { + details.ManifestUrl = new Uri("https://apps.microsoft.com/detail/" + details.Package.Id); + } + + INativeTaskLogger logger = Manager.TaskLogger.CreateNew(LoggableTaskType.LoadPackageDetails); + bool metadataLoaded = _packageDetailsProvider.LoadPackageDetails(details, logger); + logger.Close(metadataLoaded ? 0 : 1); + } + + private T RunJson(LoggableTaskType taskType, string arguments) + { + using var _cliLock = WinGet.AcquireCliLock(); + using Process process = new() + { + StartInfo = new ProcessStartInfo + { + FileName = _cliExecutablePath, + Arguments = Manager.Status.ExecutableCallArgs + " " + arguments, + RedirectStandardOutput = true, + RedirectStandardError = true, + UseShellExecute = false, + CreateNoWindow = true, + StandardOutputEncoding = Encoding.UTF8, + StandardErrorEncoding = Encoding.UTF8, + }, + }; + + IProcessTaskLogger logger = Manager.TaskLogger.CreateNew(taskType, process); + + if (CoreTools.IsAdministrator()) + { + string winGetTemp = Path.Join(Path.GetTempPath(), "UniGetUI", "ElevatedWinGetTemp"); + logger.AddToStdErr( + $"[WARN] Redirecting %TEMP% folder to {winGetTemp}, since UniGetUI was run as admin" + ); + process.StartInfo.Environment["TEMP"] = winGetTemp; + process.StartInfo.Environment["TMP"] = winGetTemp; + } + + process.Start(); + var stdoutTask = process.StandardOutput.ReadToEndAsync(); + var stderrTask = process.StandardError.ReadToEndAsync(); + process.WaitForExit(); + string output = stdoutTask.GetAwaiter().GetResult(); + string error = stderrTask.GetAwaiter().GetResult(); + + logger.AddToStdOut(output.Split(Environment.NewLine)); + logger.AddToStdErr(error.Split(Environment.NewLine)); + logger.Close(process.ExitCode); + + if (process.ExitCode != 0) + { + throw new InvalidOperationException( + $"Pinget exited with code {process.ExitCode}: {error.Trim()}" + ); + } + + return DeserializeJson(output); + } + + internal static T DeserializeJson(string output) + { + return JsonSerializer.Deserialize(output, typeof(T), SerializationContext) is T result + ? result + : throw new InvalidOperationException("Pinget returned empty JSON output."); + } + + internal static string? InferSourceName(ListMatch match) + { + if (!string.IsNullOrWhiteSpace(match.SourceName)) + { + return match.SourceName; + } + + if (match.Id.Contains("_Microsoft.Winget.Source_8wekyb3d8bbwe", StringComparison.OrdinalIgnoreCase)) + { + return "winget"; + } + + if (!string.IsNullOrWhiteSpace(match.InstallLocation) + && match.InstallLocation.Contains("\\Microsoft\\WinGet\\Packages\\", StringComparison.OrdinalIgnoreCase)) + { + return "winget"; + } + + return null; + } + + private IManagerSource GetSource(ListMatch match) + { + return GetSource(InferSourceName(match), match.Id); + } + + private IManagerSource GetSource(string? sourceName, string packageId) + { + if (string.IsNullOrWhiteSpace(sourceName)) + { + return Manager.GetLocalSource(packageId); + } + + return Manager.SourcesHelper.Factory.GetSourceOrDefault(sourceName); + } + + private static string Quote(string value) => "\"" + value.Replace("\"", "\\\"") + "\""; + + private sealed record PingetSourcesResponse(List Sources); + + private sealed record PingetSourceRecord(string Name, string Arg); + + [JsonSerializable(typeof(ListResponse))] + [JsonSerializable(typeof(SearchResponse))] + [JsonSerializable(typeof(VersionsResult))] + [JsonSerializable(typeof(PingetSourcesResponse))] + private sealed partial class PingetCliJsonContext : JsonSerializerContext { } +} diff --git a/src/UniGetUI.PackageEngine.Managers.WinGet/ClientHelpers/PingetPackageDetailsProvider.cs b/src/UniGetUI.PackageEngine.Managers.WinGet/ClientHelpers/PingetPackageDetailsProvider.cs new file mode 100644 index 0000000..22f9685 --- /dev/null +++ b/src/UniGetUI.PackageEngine.Managers.WinGet/ClientHelpers/PingetPackageDetailsProvider.cs @@ -0,0 +1,615 @@ +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using Devolutions.Pinget.Core; +using UniGetUI.Core.Data; +using UniGetUI.Core.Logging; +using UniGetUI.Core.Tools; +using UniGetUI.PackageEngine.Interfaces; +using UniGetUI.PackageEngine.ManagerClasses.Classes; + +namespace UniGetUI.PackageEngine.Managers.WingetManager; + +internal interface IPingetPackageDetailsProvider +{ + bool LoadPackageDetails(IPackageDetails details, INativeTaskLogger logger); +} + +internal sealed class PingetCliPackageDetailsProvider(string cliExecutablePath) + : IPingetPackageDetailsProvider +{ + public bool LoadPackageDetails(IPackageDetails details, INativeTaskLogger logger) + { + try + { + PackageQuery query = PingetPackageDetailsProvider.CreateQuery(details.Package); + logger.Log("Loading WinGet installer metadata with bundled Pinget CLI"); + logger.Log($" Query: {PingetPackageDetailsProvider.FormatQueryForLog(query)}"); + + string output = RunShow(query, logger); + ApplyManifestJson(details, output); + return true; + } + catch (Exception ex) + { + Logger.Warn( + "Could not load WinGet installer metadata with bundled Pinget CLI for package " + + $"{details.Package.Id}: {ex.Message}" + ); + logger.Error(ex); + return false; + } + } + + private string RunShow(PackageQuery query, INativeTaskLogger logger) + { + List sources = [query.Source]; + if (string.IsNullOrWhiteSpace(query.Source)) + { + sources.AddRange(GetSourceNames(logger)); + } + + Exception? lastException = null; + foreach (string? source in sources.Distinct(StringComparer.OrdinalIgnoreCase)) + { + try + { + logger.Log( + string.IsNullOrWhiteSpace(source) + ? " Running source-less Pinget CLI show query" + : $" Running Pinget CLI show query with source {source}" + ); + return RunPinget(BuildShowArguments(query, source), logger); + } + catch (Exception ex) + { + lastException = ex; + logger.Log( + string.IsNullOrWhiteSpace(source) + ? " Source-less Pinget CLI show query failed: " + ex.Message + : $" Pinget CLI show query failed for source {source}: {ex.Message}" + ); + + if (!string.IsNullOrWhiteSpace(query.Source)) + { + break; + } + } + } + + throw lastException ?? new InvalidOperationException("Pinget CLI did not return package details."); + } + + private IReadOnlyList GetSourceNames(INativeTaskLogger logger) + { + try + { + string output = RunPinget(["source", "export", "--output", "json"], logger); + using JsonDocument document = JsonDocument.Parse(output); + if ( + !document.RootElement.TryGetProperty("Sources", out JsonElement sources) + || sources.ValueKind != JsonValueKind.Array + ) + { + return []; + } + + return sources + .EnumerateArray() + .Select(source => + source.TryGetProperty("Name", out JsonElement name) + ? name.GetString() + : null + ) + .Where(name => !string.IsNullOrWhiteSpace(name)) + .ToArray()!; + } + catch (Exception ex) + { + logger.Log(" Could not list bundled Pinget CLI sources for retry: " + ex.Message); + return []; + } + } + + private static IReadOnlyList BuildShowArguments(PackageQuery query, string? source) + { + List arguments = ["show"]; + if (!string.IsNullOrWhiteSpace(query.Id)) + { + arguments.Add("--id"); + arguments.Add(query.Id); + } + else if (!string.IsNullOrWhiteSpace(query.Name)) + { + arguments.Add("--name"); + arguments.Add(query.Name); + } + + if (query.Exact) + { + arguments.Add("--exact"); + } + + if (!string.IsNullOrWhiteSpace(source)) + { + arguments.Add("--source"); + arguments.Add(source); + } + + if (!string.IsNullOrWhiteSpace(query.Version)) + { + arguments.Add("--version"); + arguments.Add(query.Version); + } + + arguments.Add("--output"); + arguments.Add("json"); + return arguments; + } + + private string RunPinget(IReadOnlyList arguments, INativeTaskLogger logger) + { + using var _cliLock = WinGet.AcquireCliLock(); + using Process process = new() + { + StartInfo = new ProcessStartInfo + { + FileName = cliExecutablePath, + RedirectStandardOutput = true, + RedirectStandardError = true, + UseShellExecute = false, + CreateNoWindow = true, + }, + }; + + foreach (string argument in arguments) + { + process.StartInfo.ArgumentList.Add(argument); + } + + if (CoreTools.IsAdministrator()) + { + string winGetTemp = Path.Join(Path.GetTempPath(), "UniGetUI", "ElevatedWinGetTemp"); + logger.Log( + $"[WARN] Redirecting %TEMP% folder to {winGetTemp}, since UniGetUI was run as admin" + ); + process.StartInfo.Environment["TEMP"] = winGetTemp; + process.StartInfo.Environment["TMP"] = winGetTemp; + } + + process.Start(); + string output = process.StandardOutput.ReadToEnd(); + string error = process.StandardError.ReadToEnd(); + process.WaitForExit(); + + if (process.ExitCode != 0) + { + string detail = string.Join( + Environment.NewLine, + new[] { error, output }.Where(text => !string.IsNullOrWhiteSpace(text)) + ); + throw new InvalidOperationException( + string.IsNullOrWhiteSpace(detail) + ? $"Pinget exited with code {process.ExitCode}." + : detail.Trim() + ); + } + + return output; + } + + private static void ApplyManifestJson(IPackageDetails details, string output) + { + using JsonDocument document = JsonDocument.Parse(output); + JsonElement manifest = document.RootElement; + JsonElement installer = default; + bool hasInstaller = + manifest.TryGetProperty("Installers", out JsonElement installers) + && installers.ValueKind == JsonValueKind.Array + && installers.GetArrayLength() > 0 + && (installer = installers[0]).ValueKind == JsonValueKind.Object; + + SetIfMissing(value => details.Author = value, details.Author, GetString(manifest, "Author")); + SetIfMissing( + value => details.Description = value, + details.Description, + GetString(manifest, "Description") ?? GetString(manifest, "ShortDescription") + ); + SetIfMissing(value => details.License = value, details.License, GetString(manifest, "License")); + SetIfMissing( + value => details.Publisher = value, + details.Publisher, + GetString(manifest, "Publisher") + ); + SetIfMissing( + value => details.ReleaseNotes = value, + details.ReleaseNotes, + GetString(manifest, "ReleaseNotes") + ); + + SetUriIfMissing(uri => details.HomepageUrl = uri, details.HomepageUrl, GetString(manifest, "PackageUrl")); + SetUriIfMissing(uri => details.LicenseUrl = uri, details.LicenseUrl, GetString(manifest, "LicenseUrl")); + SetUriIfMissing( + uri => details.ReleaseNotesUrl = uri, + details.ReleaseNotesUrl, + GetString(manifest, "ReleaseNotesUrl") + ); + + if ( + details.Tags.Length == 0 + && manifest.TryGetProperty("Tags", out JsonElement tags) + && tags.ValueKind == JsonValueKind.Array + ) + { + details.Tags = tags + .EnumerateArray() + .Select(tag => tag.GetString()) + .Where(tag => !string.IsNullOrWhiteSpace(tag)) + .ToArray()!; + } + + // ReleaseDate is set at the manifest root by default, with an optional per-installer override + SetIfPresent(value => details.UpdateDate = value, + (hasInstaller ? GetString(installer, "ReleaseDate") : null) ?? GetString(manifest, "ReleaseDate")); + + if (hasInstaller) + { + SetIfPresent(value => details.InstallerHash = value, GetString(installer, "InstallerSha256")); + SetIfPresent(value => details.InstallerType = value, GetString(installer, "InstallerType")); + + if (TryCreateUri(GetString(installer, "InstallerUrl"), out Uri? installerUri)) + { + details.InstallerUrl = installerUri; + details.InstallerSize = CoreTools.GetFileSizeAsLong(installerUri); + } + } + } + + private static string? GetString(JsonElement element, string propertyName) => + element.TryGetProperty(propertyName, out JsonElement value) + && value.ValueKind == JsonValueKind.String + ? value.GetString() + : null; + + private static void SetIfMissing( + Action setValue, + string? currentValue, + string? newValue + ) + { + if (string.IsNullOrWhiteSpace(currentValue) && !string.IsNullOrWhiteSpace(newValue)) + { + setValue(newValue); + } + } + + private static void SetIfPresent(Action setValue, string? value) + { + if (!string.IsNullOrWhiteSpace(value)) + { + setValue(value); + } + } + + private static void SetUriIfMissing( + Action setValue, + Uri? currentValue, + string? newValue + ) + { + if (currentValue is null && TryCreateUri(newValue, out Uri? uri) && uri is not null) + { + setValue(uri); + } + } + + private static bool TryCreateUri([NotNullWhen(true)] string? value, out Uri? uri) + { + return Uri.TryCreate(value, UriKind.Absolute, out uri); + } +} + +internal sealed class PingetPackageDetailsProvider : IPingetPackageDetailsProvider +{ + private readonly Func _showPackage; + private readonly Func _installerSizeResolver; + + public PingetPackageDetailsProvider() + : this(ShowWithRepository) { } + + internal PingetPackageDetailsProvider( + Func showPackage, + Func? installerSizeResolver = null + ) + { + _showPackage = showPackage; + _installerSizeResolver = installerSizeResolver ?? CoreTools.GetFileSizeAsLong; + } + + public bool LoadPackageDetails(IPackageDetails details, INativeTaskLogger logger) + { + try + { + PackageQuery query = CreateQuery(details.Package); + logger.Log("Loading WinGet installer metadata with Pinget"); + logger.Log($" Query: {FormatQueryForLog(query)}"); + Logger.Info($"Loading WinGet installer metadata with Pinget. Query: {FormatQueryForLog(query)}"); + + ShowResult result = _showPackage(query); + + foreach (string warning in result.Warnings) + { + logger.Log(" Pinget warning: " + warning); + } + + ApplyShowResult(details, result, _installerSizeResolver); + return true; + } + catch (Exception ex) + { + Logger.Warn( + "Could not load WinGet installer metadata with Pinget for package " + + $"{details.Package.Id}: {ex.Message}" + ); + logger.Error(ex); + return false; + } + } + + internal static PackageQuery CreateQuery(IPackage package, string? version = null) + { + string id = package.Id.TrimEnd('…'); + string name = package.Name.TrimEnd('…'); + + PackageQuery query; + if (!string.IsNullOrWhiteSpace(id)) + { + query = new PackageQuery + { + Id = id, + Exact = !package.Id.EndsWith('…'), + }; + } + else + { + query = new PackageQuery + { + Name = name, + Exact = !package.Name.EndsWith('…'), + }; + } + + if ( + !package.Source.IsVirtualManager + && !string.IsNullOrWhiteSpace(package.Source.Name) + && !IsEllipsized(package.Source.Name) + ) + { + query = query with { Source = package.Source.Name }; + } + + if (!string.IsNullOrWhiteSpace(version)) + { + query = query with { Version = version }; + } + + return query; + } + + internal static void ApplyShowResult( + IPackageDetails details, + ShowResult result, + Func? installerSizeResolver = null + ) + { + installerSizeResolver ??= CoreTools.GetFileSizeAsLong; + Manifest manifest = result.Manifest; + Installer? installer = result.SelectedInstaller ?? manifest.Installers.FirstOrDefault(); + + SetIfMissing(value => details.Author = value, details.Author, manifest.Author); + SetIfMissing( + value => details.Description = value, + details.Description, + manifest.Description ?? manifest.ShortDescription + ); + SetIfMissing(value => details.License = value, details.License, manifest.License); + SetIfMissing(value => details.Publisher = value, details.Publisher, manifest.Publisher); + SetIfMissing(value => details.ReleaseNotes = value, details.ReleaseNotes, manifest.ReleaseNotes); + + SetUriIfMissing(uri => details.HomepageUrl = uri, details.HomepageUrl, manifest.PackageUrl); + SetUriIfMissing(uri => details.LicenseUrl = uri, details.LicenseUrl, manifest.LicenseUrl); + SetUriIfMissing( + uri => details.ReleaseNotesUrl = uri, + details.ReleaseNotesUrl, + manifest.ReleaseNotesUrl + ); + + if (details.Tags.Length == 0 && manifest.Tags.Count > 0) + { + details.Tags = manifest.Tags.ToArray(); + } + + if (installer is not null) + { + SetIfPresent(value => details.InstallerHash = value, installer.Sha256); + SetIfPresent(value => details.InstallerType = value, installer.InstallerType); + SetIfPresent(value => details.UpdateDate = value, installer.ReleaseDate); + + if (TryCreateUri(installer.Url, out Uri? installerUri)) + { + details.InstallerUrl = installerUri; + details.InstallerSize = installerSizeResolver(installerUri); + } + } + + details.Dependencies.Clear(); + foreach (string dependency in manifest.PackageDependencies.Concat( + installer?.PackageDependencies ?? [] + ).Distinct(StringComparer.OrdinalIgnoreCase)) + { + if (TryCreateDependency(dependency, out IPackageDetails.Dependency parsedDependency)) + { + details.Dependencies.Add(parsedDependency); + } + } + } + + private static ShowResult ShowWithRepository(PackageQuery query) + { + using Repository repository = OpenRepository(); + return repository.ShowFirstMatchAcrossSources(query); + } + + /// + /// Fetches the set of installer URL hosts for a specific version of a package. + /// Returns null if the manifest can't be loaded, OR a non-empty set otherwise. + /// Used to detect installer-host changes between installed and upgrade versions (issue #4617). + /// Returns the SET (not just one) because manifests typically have multiple installers + /// (per arch / locale / scope) — flagging on a single-installer comparison can produce + /// false positives when a publisher legitimately uses different CDNs per architecture + /// or adds/removes architectures across versions. + /// + internal static IReadOnlySet? TryGetInstallerHostsForVersion( + IPackage package, + string version + ) + { + try + { + PackageQuery query = CreateQuery(package, version); + ShowResult result; + using (Repository repository = OpenRepository()) + { + result = repository.ShowFirstMatchAcrossSources(query); + } + + // Pinget silently falls back to the latest manifest when the requested version + // isn't in the index (yanked / expired / never indexed). That fallback would + // make the host-change check return false-negatives, so reject any result whose + // manifest version doesn't match what we asked for. + string returnedVersion = result.Manifest.Version ?? ""; + if (!string.Equals(returnedVersion, version, StringComparison.OrdinalIgnoreCase)) + { + Logger.Info( + $"Pinget returned manifest version '{returnedVersion}' when '{version}' " + + $"was requested for {package.Id}; treating as not found" + ); + return null; + } + + HashSet hosts = new(StringComparer.OrdinalIgnoreCase); + foreach (Installer installer in result.Manifest.Installers) + { + if (TryCreateUri(installer.Url, out Uri? uri) && uri is not null) + hosts.Add(uri.Host); + } + + return hosts.Count > 0 ? hosts : null; + } + catch (Exception ex) + { + Logger.Warn( + $"Could not resolve installer hosts for {package.Id} version {version}: {ex.Message}" + ); + return null; + } + } + + private static Repository OpenRepository() + { + return Repository.Open(CreateRepositoryOptions()); + } + + internal static RepositoryOptions CreateRepositoryOptions() + { + return new RepositoryOptions + { + UserAgent = CoreData.UserAgentString, + }; + } + + internal static string FormatQueryForLog(PackageQuery query) + { + return string.Join( + ", ", + new[] + { + $"Id={query.Id}", + $"Name={query.Name}", + $"Source={query.Source}", + $"Exact={query.Exact}", + }.Where(part => !part.EndsWith("=")) + ); + } + + private static bool IsEllipsized(string value) => value.Contains('…'); + + private static void SetIfMissing( + Action setValue, + string? currentValue, + string? newValue + ) + { + if (string.IsNullOrWhiteSpace(currentValue) && !string.IsNullOrWhiteSpace(newValue)) + { + setValue(newValue); + } + } + + private static void SetIfPresent(Action setValue, string? value) + { + if (!string.IsNullOrWhiteSpace(value)) + { + setValue(value); + } + } + + private static void SetUriIfMissing(Action setValue, Uri? currentValue, string? value) + { + if (currentValue is null && TryCreateUri(value, out Uri? uri)) + { + setValue(uri); + } + } + + private static bool TryCreateUri(string? value, [NotNullWhen(true)] out Uri? uri) + { + return Uri.TryCreate(value, UriKind.Absolute, out uri); + } + + private static bool TryCreateDependency( + string value, + out IPackageDetails.Dependency dependency + ) + { + dependency = default; + string trimmedValue = value.Trim(); + if (trimmedValue == "") + return false; + + string name = trimmedValue; + string version = ""; + int versionStart = trimmedValue.IndexOf('[', StringComparison.Ordinal); + if (versionStart >= 0) + { + name = trimmedValue[..versionStart].Trim(); + version = trimmedValue[(versionStart + 1)..].TrimEnd(']').Trim(); + } + + if (name.Contains(' ')) + { + name = name.Split(' ', StringSplitOptions.RemoveEmptyEntries)[0]; + } + + if (name == "") + return false; + + dependency = new IPackageDetails.Dependency + { + Name = name, + Version = version, + Mandatory = true, + }; + return true; + } +} diff --git a/src/UniGetUI.PackageEngine.Managers.WinGet/ClientHelpers/WinGetCliHelper.cs b/src/UniGetUI.PackageEngine.Managers.WinGet/ClientHelpers/WinGetCliHelper.cs new file mode 100644 index 0000000..0e8c22d --- /dev/null +++ b/src/UniGetUI.PackageEngine.Managers.WinGet/ClientHelpers/WinGetCliHelper.cs @@ -0,0 +1,582 @@ +using System.Diagnostics; +using System.Text; +using System.Text.RegularExpressions; +using UniGetUI.Core.Logging; +using UniGetUI.Core.Tools; +using UniGetUI.PackageEngine.Classes.Manager; +using UniGetUI.PackageEngine.Enums; +using UniGetUI.PackageEngine.Interfaces; +using UniGetUI.PackageEngine.ManagerClasses.Classes; +using UniGetUI.PackageEngine.PackageClasses; + +namespace UniGetUI.PackageEngine.Managers.WingetManager; + +internal sealed class WinGetCliHelper : IWinGetManagerHelper +{ + // "winget search a" returns ~12k results; cap to the most relevant to avoid the freeze/RAM spike. + private const int MAX_SEARCH_RESULTS = 100; + + private readonly WinGet Manager; + private readonly string _cliExecutablePath; + private readonly IPingetPackageDetailsProvider _packageDetailsProvider; + + public WinGetCliHelper(WinGet manager, string cliExecutablePath) + : this( + manager, + cliExecutablePath, + File.Exists(WinGet.GetBundledPingetExecutablePath()) + ? new PingetCliPackageDetailsProvider(WinGet.GetBundledPingetExecutablePath()) + : new PingetPackageDetailsProvider() + ) + { } + + internal WinGetCliHelper( + WinGet manager, + string cliExecutablePath, + IPingetPackageDetailsProvider packageDetailsProvider + ) + { + Manager = manager; + _cliExecutablePath = cliExecutablePath; + _packageDetailsProvider = packageDetailsProvider; + } + + public IReadOnlyList GetAvailableUpdates_UnSafe() + { + using var _cliLock = WinGet.AcquireCliLock(); + List Packages = []; + using Process p = new() + { + StartInfo = new() + { + FileName = _cliExecutablePath, + Arguments = + Manager.Status.ExecutableCallArgs + + " update --include-unknown --accept-source-agreements " + + WinGet.GetProxyArgument(), + RedirectStandardOutput = true, + RedirectStandardError = true, + UseShellExecute = false, + CreateNoWindow = true, + StandardOutputEncoding = Encoding.UTF8, + }, + }; + + IProcessTaskLogger logger = Manager.TaskLogger.CreateNew(LoggableTaskType.ListUpdates, p); + + if (CoreTools.IsAdministrator()) + { + string WinGetTemp = Path.Join(Path.GetTempPath(), "UniGetUI", "ElevatedWinGetTemp"); + logger.AddToStdErr( + $"[WARN] Redirecting %TEMP% folder to {WinGetTemp}, since UniGetUI was run as admin" + ); + p.StartInfo.Environment["TEMP"] = WinGetTemp; + p.StartInfo.Environment["TMP"] = WinGetTemp; + } + + p.Start(); + + string OldLine = ""; + int IdIndex = -1; + int VersionIndex = -1; + int NewVersionIndex = -1; + int SourceIndex = -1; + bool DashesPassed = false; + string? line; + while ((line = p.StandardOutput.ReadLine()) is not null) + { + logger.AddToStdOut(line); + + if (line.Contains("have pins")) + { + continue; + } + + if (!DashesPassed && line.Contains("---")) + { + string HeaderPrefix = OldLine.Contains("SearchId") ? "Search" : ""; + string HeaderSuffix = OldLine.Contains("SearchId") ? "Header" : ""; + IdIndex = OldLine.IndexOf(HeaderPrefix + "Id", StringComparison.InvariantCulture); + VersionIndex = OldLine.IndexOf( + HeaderPrefix + "Version", + StringComparison.InvariantCulture + ); + NewVersionIndex = OldLine.IndexOf( + "Available" + HeaderSuffix, + StringComparison.InvariantCulture + ); + SourceIndex = OldLine.IndexOf( + HeaderPrefix + "Source", + StringComparison.InvariantCulture + ); + DashesPassed = true; + } + else if (line.Trim() == "") + { + DashesPassed = false; + } + else if ( + DashesPassed + && IdIndex > 0 + && VersionIndex > 0 + && NewVersionIndex > 0 + && IdIndex < VersionIndex + && VersionIndex < NewVersionIndex + && NewVersionIndex < line.Length + ) + { + int offset = 0; // Account for non-unicode character length + while (line[IdIndex - offset - 1] != ' ' || offset > (IdIndex - 5)) + { + offset++; + } + + string name = line[..(IdIndex - offset)].Trim(); + string id = line[(IdIndex - offset)..].Trim().Split(' ')[0]; + string version = line[(VersionIndex - offset)..(NewVersionIndex - offset)].Trim(); + string newVersion; + if (SourceIndex != -1) + { + newVersion = line[(NewVersionIndex - offset)..(SourceIndex - offset)].Trim(); + } + else + { + newVersion = line[(NewVersionIndex - offset)..].Trim().Split(' ')[0]; + } + + IManagerSource source; + if (SourceIndex == -1 || SourceIndex >= line.Length) + { + source = Manager.DefaultSource; + } + else + { + string sourceName = line[(SourceIndex - offset)..].Trim().Split(' ')[0]; + source = Manager.SourcesHelper.Factory.GetSourceOrDefault(sourceName); + } + + var package = new Package(name, id, version, newVersion, source, Manager); + if (!WinGetPkgOperationHelper.ConsumeAlreadyUpgradedSuppression(package)) + { + Packages.Add(package); + } + else + { + Logger.Warn( + $"WinGet package {package.Id} not being shown as an updated as this version has already been marked as installed" + ); + } + } + OldLine = line; + } + + logger.AddToStdErr(p.StandardError.ReadToEnd()); + p.WaitForExit(); + logger.Close(p.ExitCode); + + return Packages; + } + + public IReadOnlyList GetInstalledPackages_UnSafe() + { + using var _cliLock = WinGet.AcquireCliLock(); + List Packages = []; + using Process p = new() + { + StartInfo = new() + { + FileName = _cliExecutablePath, + Arguments = + Manager.Status.ExecutableCallArgs + + " list --accept-source-agreements " + + WinGet.GetProxyArgument(), + RedirectStandardOutput = true, + RedirectStandardError = true, + UseShellExecute = false, + CreateNoWindow = true, + StandardOutputEncoding = Encoding.UTF8, + }, + }; + + IProcessTaskLogger logger = Manager.TaskLogger.CreateNew( + LoggableTaskType.ListInstalledPackages, + p + ); + + if (CoreTools.IsAdministrator()) + { + string WinGetTemp = Path.Join(Path.GetTempPath(), "UniGetUI", "ElevatedWinGetTemp"); + logger.AddToStdErr( + $"[WARN] Redirecting %TEMP% folder to {WinGetTemp}, since UniGetUI was run as admin" + ); + p.StartInfo.Environment["TEMP"] = WinGetTemp; + p.StartInfo.Environment["TMP"] = WinGetTemp; + } + + p.Start(); + + string OldLine = ""; + int IdIndex = -1; + int VersionIndex = -1; + int SourceIndex = -1; + int NewVersionIndex = -1; + bool DashesPassed = false; + string? line; + while ((line = p.StandardOutput.ReadLine()) is not null) + { + try + { + logger.AddToStdOut(line); + if (!DashesPassed && line.Contains("---")) + { + string HeaderPrefix = OldLine.Contains("SearchId") ? "Search" : ""; + string HeaderSuffix = OldLine.Contains("SearchId") ? "Header" : ""; + IdIndex = OldLine.IndexOf( + HeaderPrefix + "Id", + StringComparison.InvariantCulture + ); + VersionIndex = OldLine.IndexOf( + HeaderPrefix + "Version", + StringComparison.InvariantCulture + ); + NewVersionIndex = OldLine.IndexOf( + "Available" + HeaderSuffix, + StringComparison.InvariantCulture + ); + SourceIndex = OldLine.IndexOf( + HeaderPrefix + "Source", + StringComparison.InvariantCulture + ); + DashesPassed = true; + } + else if ( + DashesPassed + && IdIndex > 0 + && VersionIndex > 0 + && IdIndex < VersionIndex + && VersionIndex < line.Length + ) + { + int offset = 0; // Account for non-unicode character length + while ( + ((IdIndex - offset) <= line.Length && line[IdIndex - offset - 1] != ' ') + || offset > (IdIndex - 5) + ) + { + offset++; + } + + string name = line[..(IdIndex - offset)].Trim(); + string id = line[(IdIndex - offset)..].Trim().Split(' ')[0]; + if (NewVersionIndex == -1 && SourceIndex != -1) + { + NewVersionIndex = SourceIndex; + } + else if (NewVersionIndex == -1 && SourceIndex == -1) + { + NewVersionIndex = line.Length - 1; + } + + string version = line[(VersionIndex - offset)..(NewVersionIndex - offset)] + .Trim(); + + IManagerSource source; + if (SourceIndex == -1 || (SourceIndex - offset) >= line.Length) + { + source = Manager.GetLocalSource(id); // Load Winget Local Sources + } + else + { + string sourceName = line[(SourceIndex - offset)..] + .Trim() + .Split(' ')[0] + .Trim(); + source = Manager.SourcesHelper.Factory.GetSourceOrDefault(sourceName); + } + Packages.Add(new Package(name, id, version, source, Manager)); + } + OldLine = line; + } + catch (Exception e) + { + Logger.Error(e); + } + } + + logger.AddToStdErr(p.StandardError.ReadToEnd()); + p.WaitForExit(); + logger.Close(p.ExitCode); + + return Packages; + } + + public IReadOnlyList FindPackages_UnSafe(string query) + { + using var _cliLock = WinGet.AcquireCliLock(); + List Packages = []; + using Process p = new() + { + StartInfo = new() + { + FileName = _cliExecutablePath, + Arguments = + Manager.Status.ExecutableCallArgs + + " search \"" + + query + + "\" --count " + + MAX_SEARCH_RESULTS + + " --accept-source-agreements " + + WinGet.GetProxyArgument(), + RedirectStandardOutput = true, + RedirectStandardError = true, + UseShellExecute = false, + CreateNoWindow = true, + StandardOutputEncoding = Encoding.UTF8, + }, + }; + + IProcessTaskLogger logger = Manager.TaskLogger.CreateNew(LoggableTaskType.FindPackages, p); + + if (CoreTools.IsAdministrator()) + { + string WinGetTemp = Path.Join(Path.GetTempPath(), "UniGetUI", "ElevatedWinGetTemp"); + logger.AddToStdErr( + $"[WARN] Redirecting %TEMP% folder to {WinGetTemp}, since UniGetUI was run as admin" + ); + p.StartInfo.Environment["TEMP"] = WinGetTemp; + p.StartInfo.Environment["TMP"] = WinGetTemp; + } + + p.Start(); + + string OldLine = ""; + int IdIndex = -1; + int VersionIndex = -1; + int SourceIndex = -1; + bool DashesPassed = false; + string? line; + while ((line = p.StandardOutput.ReadLine()) is not null) + { + logger.AddToStdOut(line); + if (!DashesPassed && line.Contains("---")) + { + string HeaderPrefix = OldLine.Contains("SearchId") ? "Search" : ""; + IdIndex = OldLine.IndexOf(HeaderPrefix + "Id", StringComparison.InvariantCulture); + VersionIndex = OldLine.IndexOf( + HeaderPrefix + "Version", + StringComparison.InvariantCulture + ); + SourceIndex = OldLine.IndexOf( + HeaderPrefix + "Source", + StringComparison.InvariantCulture + ); + DashesPassed = true; + } + else if ( + DashesPassed + && IdIndex > 0 + && VersionIndex > 0 + && IdIndex < VersionIndex + && VersionIndex < line.Length + ) + { + int offset = 0; // Account for non-unicode character length + while (line[IdIndex - offset - 1] != ' ' || offset > (IdIndex - 5)) + { + offset++; + } + + string name = line[..(IdIndex - offset)].Trim(); + string id = line[(IdIndex - offset)..].Trim().Split(' ')[0]; + string version = line[(VersionIndex - offset)..].Trim().Split(' ')[0]; + IManagerSource source; + if (SourceIndex == -1 || SourceIndex >= line.Length) + { + source = Manager.DefaultSource; + } + else + { + string sourceName = line[(SourceIndex - offset)..].Trim().Split(' ')[0]; + source = Manager.SourcesHelper.Factory.GetSourceOrDefault(sourceName); + } + Packages.Add(new Package(name, id, version, source, Manager)); + } + OldLine = line; + } + + logger.AddToStdErr(p.StandardError.ReadToEnd()); + p.WaitForExit(); + logger.Close(p.ExitCode); + + return Packages; + } + + public void GetPackageDetails_UnSafe(IPackageDetails details) + { + if (details.Package.Source.Name == "winget") + { + details.ManifestUrl = new Uri( + "https://github.com/microsoft/winget-pkgs/tree/master/manifests/" + + details.Package.Id[0].ToString().ToLower() + + "/" + + details.Package.Id.Split('.')[0] + + "/" + + string.Join( + "/", + details.Package.Id.Contains('.') + ? details.Package.Id.Split('.')[1..] + : details.Package.Id.Split('.') + ) + ); + } + else if (details.Package.Source.Name == "msstore") + { + details.ManifestUrl = new Uri( + "https://apps.microsoft.com/detail/" + details.Package.Id + ); + } + + INativeTaskLogger logger = Manager.TaskLogger.CreateNew(LoggableTaskType.LoadPackageDetails); + bool metadataLoaded = _packageDetailsProvider.LoadPackageDetails(details, logger); + logger.Close(metadataLoaded ? 0 : 1); + } + + public IReadOnlyList GetInstallableVersions_Unsafe(IPackage package) + { + using var _cliLock = WinGet.AcquireCliLock(); + using Process p = new() + { + StartInfo = new ProcessStartInfo + { + FileName = _cliExecutablePath, + Arguments = + Manager.Status.ExecutableCallArgs + + " show " + + WinGetPkgOperationHelper.GetIdNamePiece(package) + + $" --versions --accept-source-agreements " + + " " + + WinGet.GetProxyArgument(), + UseShellExecute = false, + RedirectStandardOutput = true, + RedirectStandardError = true, + RedirectStandardInput = true, + CreateNoWindow = true, + StandardOutputEncoding = Encoding.UTF8, + }, + }; + + IProcessTaskLogger logger = Manager.TaskLogger.CreateNew( + LoggableTaskType.LoadPackageVersions, + p + ); + if (CoreTools.IsAdministrator()) + { + string WinGetTemp = Path.Join(Path.GetTempPath(), "UniGetUI", "ElevatedWinGetTemp"); + Logger.Warn( + $"[WARN] Redirecting %TEMP% folder to {WinGetTemp}, since UniGetUI was run as admin" + ); + p.StartInfo.Environment["TEMP"] = WinGetTemp; + p.StartInfo.Environment["TMP"] = WinGetTemp; + } + p.Start(); + + string? line; + List versions = []; + bool DashesPassed = false; + while ((line = p.StandardOutput.ReadLine()) is not null) + { + logger.AddToStdOut(line); + if (!DashesPassed) + { + if (line.Contains("---")) + { + DashesPassed = true; + } + } + else + { + versions.Add(line.Trim()); + } + } + + logger.AddToStdErr(p.StandardError.ReadToEnd()); + p.WaitForExit(); + logger.Close(p.ExitCode); + return versions; + } + + public IReadOnlyList GetSources_UnSafe() + { + using var _cliLock = WinGet.AcquireCliLock(); + List sources = []; + + using Process p = new() + { + StartInfo = new() + { + FileName = Manager.Status.ExecutablePath, + Arguments = + Manager.Status.ExecutableCallArgs + " source list " + WinGet.GetProxyArgument(), + RedirectStandardOutput = true, + RedirectStandardError = true, + RedirectStandardInput = true, + UseShellExecute = false, + CreateNoWindow = true, + StandardOutputEncoding = Encoding.UTF8, + }, + }; + + IProcessTaskLogger logger = Manager.TaskLogger.CreateNew(LoggableTaskType.FindPackages, p); + if (CoreTools.IsAdministrator()) + { + string WinGetTemp = Path.Join(Path.GetTempPath(), "UniGetUI", "ElevatedWinGetTemp"); + Logger.Warn( + $"[WARN] Redirecting %TEMP% folder to {WinGetTemp}, since UniGetUI was run as admin" + ); + p.StartInfo.Environment["TEMP"] = WinGetTemp; + p.StartInfo.Environment["TMP"] = WinGetTemp; + } + p.Start(); + + bool dashesPassed = false; + string? line; + while ((line = p.StandardOutput.ReadLine()) is not null) + { + logger.AddToStdOut(line); + try + { + if (string.IsNullOrEmpty(line)) + { + continue; + } + + if (!dashesPassed) + { + if (line.Contains("---")) + { + dashesPassed = true; + } + } + else + { + string[] parts = Regex.Replace(line.Trim(), " {2,}", " ").Split(' '); + if (parts.Length > 1) + { + sources.Add( + new ManagerSource(Manager, parts[0].Trim(), new Uri(parts[1].Trim())) + ); + } + } + } + catch (Exception e) + { + Logger.Warn(e); + } + } + + logger.AddToStdErr(p.StandardError.ReadToEnd()); + p.WaitForExit(); + logger.Close(p.ExitCode); + return sources; + } +} diff --git a/src/UniGetUI.PackageEngine.Managers.WinGet/ClientHelpers/WinGetCliTool.cs b/src/UniGetUI.PackageEngine.Managers.WinGet/ClientHelpers/WinGetCliTool.cs new file mode 100644 index 0000000..d88630d --- /dev/null +++ b/src/UniGetUI.PackageEngine.Managers.WinGet/ClientHelpers/WinGetCliTool.cs @@ -0,0 +1,21 @@ +namespace UniGetUI.PackageEngine.Managers.WingetManager; + +internal enum WinGetCliToolKind +{ + SystemWinGet, + BundledPinget, +} + +internal enum WinGetCliToolPreference +{ + Default, + SystemWinGet, + BundledPinget, +} + +internal enum WinGetComApiPolicy +{ + Default, + Enabled, + Disabled, +} diff --git a/src/UniGetUI.PackageEngine.Managers.WinGet/ClientHelpers/WinGetIconsHelper.cs b/src/UniGetUI.PackageEngine.Managers.WinGet/ClientHelpers/WinGetIconsHelper.cs new file mode 100644 index 0000000..d6769b6 --- /dev/null +++ b/src/UniGetUI.PackageEngine.Managers.WinGet/ClientHelpers/WinGetIconsHelper.cs @@ -0,0 +1,365 @@ +using System.Globalization; +using System.Net; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading; +using Microsoft.Management.Deployment; +using Microsoft.Win32; +using UniGetUI.Core.IconEngine; +using UniGetUI.Core.Logging; +using UniGetUI.PackageEngine.Interfaces; +using UniGetUI.PackageEngine.Managers.WingetManager; + +namespace UniGetUI.PackageEngine.Managers.WinGet.ClientHelpers; + +internal static class WinGetIconsHelper +{ + private static readonly Dictionary __msstore_package_manifests = []; + + public static string? GetMicrosoftStoreManifest(IPackage package) + { + if (__msstore_package_manifests.TryGetValue(package.Id, out var manifest)) + return manifest; + + string CountryCode = CultureInfo.CurrentCulture.Name.Split("-")[^1]; + string Locale = CultureInfo.CurrentCulture.Name; + string url = + $"https://storeedgefd.dsx.mp.microsoft.com/v8.0/sdk/products?market={CountryCode}&locale={Locale}&deviceFamily=Windows.Desktop"; + +#pragma warning disable SYSLIB0014 + var httpRequest = (HttpWebRequest)WebRequest.Create(url); +#pragma warning restore SYSLIB0014 + + httpRequest.Method = "POST"; + httpRequest.ContentType = "application/json"; + + string data = "{\"productIds\": \"" + package.Id.ToLower() + "\"}"; + + using (StreamWriter streamWriter = new(httpRequest.GetRequestStream())) + streamWriter.Write(data); + + using var httpResponse = httpRequest.GetResponse() as HttpWebResponse; + if (httpResponse is null) + { + Logger.Warn($"Null MS Store response for uri={url} and data={data}"); + return null; + } + + string result; + using (StreamReader streamReader = new(httpResponse.GetResponseStream())) + result = streamReader.ReadToEnd(); + + Logger.Debug("Microsoft Store API call status code: " + httpResponse.StatusCode); + + if (result != "" && httpResponse.StatusCode == HttpStatusCode.OK) + __msstore_package_manifests[package.Id] = result; + + return result; + } + + public static CacheableIcon? GetMicrosoftStoreIcon(IPackage package) + { + string? ResponseContent = GetMicrosoftStoreManifest(package); + if (ResponseContent is null) + return null; + + Match IconArray = Regex.Match(ResponseContent, "(?:\"|')Images(?:\"|'): ?\\[([^\\]]+)\\]"); + if (!IconArray.Success) + { + Logger.Warn("Could not parse Images array from Microsoft Store response"); + return null; + } + + Dictionary FoundIcons = []; + + foreach (Match ImageEntry in Regex.Matches(IconArray.Groups[1].Value, "{([^}]+)}")) + { + string CurrentImage = ImageEntry.Groups[1].Value; + + if (!ImageEntry.Success) + continue; + + Match ImagePurpose = Regex.Match( + CurrentImage, + "(?:\"|')ImagePurpose(?:\"|'): ?(?:\"|')([^'\"]+)(?:\"|')" + ); + if (!ImagePurpose.Success || ImagePurpose.Groups[1].Value != "Tile") + continue; + + Match ImageUrl = Regex.Match( + CurrentImage, + "(?:\"|')Uri(?:\"|'): ?(?:\"|')([^'\"]+)(?:\"|')" + ); + Match ImageSize = Regex.Match(CurrentImage, "(?:\"|')Height(?:\"|'): ?([^,]+)"); + + if (!ImageUrl.Success || !ImageSize.Success) + continue; + + FoundIcons[int.Parse(ImageSize.Groups[1].Value)] = ImageUrl.Groups[1].Value; + } + + if (FoundIcons.Count == 0) + { + Logger.Warn( + $"No Logo image found for package {package.Id} in Microsoft Store response" + ); + return null; + } + + Logger.Debug( + "Choosing icon with size " + + FoundIcons.Keys.Max() + + " for package " + + package.Id + + " from Microsoft Store" + ); + + string uri = "https:" + FoundIcons[FoundIcons.Keys.Max()]; + + return new CacheableIcon(new Uri(uri)); + } + + public static CacheableIcon? GetWinGetPackageIcon(IPackage package) + { + CatalogPackageMetadata? NativeDetails = NativePackageHandler.GetDetails(package); + if (NativeDetails is null) + return null; + + // Get the actual icon and return it + foreach (Icon? icon in NativeDetails.Icons.ToArray()) + if (icon is not null && icon.Url is not null) + // Logger.Debug($"Found WinGet native icon for {package.Id} with URL={icon.Url}"); + return new CacheableIcon(new Uri(icon.Url), icon.Sha256); + + // Logger.Debug($"Native WinGet icon for Package={package.Id} on catalog={package.Source.Name} was not found :("); + return null; + } + + public static CacheableIcon? GetAppxPackageIcon(IPackage package) + { + string appxId = package.Id.Replace("MSIX\\", ""); + string globalPath = Path.Join( + Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles), + "WindowsApps", + appxId + ); + + if (!Directory.Exists(globalPath)) + globalPath = Path.Join( + Environment.GetFolderPath(Environment.SpecialFolder.Windows), + "SystemApps", + appxId + ); + + if (!Directory.Exists(globalPath)) + return null; + + string content = File.ReadAllText(Path.Join(globalPath, "AppxManifest.xml")); + Match? match = Regex.Match(content, "Square44x44Logo\\s*=\\s*[\"']([^\"']+)[\"']"); + if (!match.Success) + { + // There is no icon on the manifest + return null; + } + + string path = string.Join( + '.', + Path.Join(globalPath, match.Groups[1].ToString()).Split('.')[..^1] + ); + foreach ( + string ending in new[] + { + ".png", + ".scale-100.png", + ".scale-125.png", + ".scale-150.png", + ".scale-175.png", + ".scale-200.png", + } + ) + if (Path.Exists(path + ending)) + { + return new CacheableIcon(path + ending); + } + + return null; + } + + public static CacheableIcon? GetARPPackageIcon(IPackage package) + { + var bits = package.Id.Split("\\"); + if (bits.Length < 4) + return null; + + string regKey = ""; + regKey += bits[1] == "Machine" ? "HKEY_LOCAL_MACHINE" : "HKEY_CURRENT_USER"; + regKey += "\\SOFTWARE"; + if (bits[2] == "X86") + regKey += "\\WOW6432Node"; + + regKey += "\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\"; + regKey += bits[3]; + + string? displayIcon = (string?)Registry.GetValue(regKey, "DisplayIcon", null); + if ( + !string.IsNullOrEmpty(displayIcon) + && File.Exists(displayIcon) + && !displayIcon.EndsWith(".exe") + ) + return new CacheableIcon(displayIcon); + + return null; + } + + private const long MsixCacheTtlMs = 30_000; + private static readonly Lock _msixLock = new(); + private static Dictionary? _msixIndex; // normalized name -> install path + private static long _msixBuiltAt = long.MinValue; + + /// + /// Resolves an MSIX/Store package whose full name is encoded in the Id (Microsoft Store + /// source). Cheap — no package enumeration. + /// + public static string? GetMsixLocationFromId(IPackage package) + { + if (!package.Id.StartsWith("MSIX\\", StringComparison.OrdinalIgnoreCase)) + return null; + + var fullName = package.Id["MSIX\\".Length..]; + foreach ( + var root in new[] + { + Path.Join( + Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles), + "WindowsApps", + fullName + ), + Path.Join( + Environment.GetFolderPath(Environment.SpecialFolder.Windows), + "SystemApps", + fullName + ), + } + ) + if (Directory.Exists(root)) + return root; + + return null; + } + + /// + /// Resolves an MSIX/Store package by matching it against the installed AppX packages. These do + /// not appear in the "Add/Remove programs" registry, so this enumerates them via the platform + /// API (cached). Used as a last resort because the enumeration has a cost. + /// + public static string? GetMsixLocationByName(IPackage package) + { + var index = GetMsixIndex(); + if (index.Count == 0) + return null; + + string[] candidates = [NormalizeMsix(package.Id), NormalizeMsix(package.Name)]; + + // Exact match first (most reliable). + foreach (var candidate in candidates) + if (candidate.Length >= 3 && index.TryGetValue(candidate, out var location)) + return location; + + // Then a length-guarded fuzzy match (prefix or containment) to bridge identity/display-name + // differences, e.g. winget "Microsoft.AppInstaller" / "App Installer" vs the MSIX identity + // "Microsoft.DesktopAppInstaller". Only reached as a last resort, over the small MSIX set. + foreach (var candidate in candidates) + { + if (candidate.Length < 6) + continue; + foreach (var (key, location) in index) + if ( + key.StartsWith(candidate, StringComparison.Ordinal) + || candidate.StartsWith(key, StringComparison.Ordinal) + || key.Contains(candidate, StringComparison.Ordinal) + ) + return location; + } + + return null; + } + + private static Dictionary GetMsixIndex() + { + lock (_msixLock) + { + var now = Environment.TickCount64; + if (_msixIndex is null || now - _msixBuiltAt > MsixCacheTtlMs) + { + _msixIndex = BuildMsixIndex(); + _msixBuiltAt = now; + } + return _msixIndex; + } + } + + private const string AppxRepositoryKey = + @"Software\Classes\Local Settings\Software\Microsoft\Windows\CurrentVersion\AppModel\Repository\Packages"; + + private static Dictionary BuildMsixIndex() + { + // Read MSIX install locations straight from the AppModel repository registry rather than the + // WinRT PackageManager API: the latter fails to activate inside this process (the WinGet COM + // interop reconfigures process-wide COM security), whereas the registry is always readable. + var map = new Dictionary(StringComparer.Ordinal); + try + { + using var root = Registry.CurrentUser.OpenSubKey(AppxRepositoryKey); + if (root is null) + return map; + + foreach (var packageFullName in root.GetSubKeyNames()) + { + try + { + using var entry = root.OpenSubKey(packageFullName); + if (entry?.GetValue("PackageRootFolder") is not string path) + continue; + if (string.IsNullOrEmpty(path) || !Directory.Exists(path)) + continue; + + // Full name is "____". + AddMsixKey(map, packageFullName.Split('_')[0], path); + + if ( + entry.GetValue("DisplayName") is string displayName + && !displayName.StartsWith("ms-resource:", StringComparison.OrdinalIgnoreCase) + ) + AddMsixKey(map, displayName, path); + } + catch + { + // Skip unreadable entries. + } + } + } + catch (Exception ex) + { + Logger.Debug($"Could not read installed MSIX packages from the registry: {ex.Message}"); + } + return map; + } + + private static void AddMsixKey(Dictionary map, string? key, string path) + { + var normalized = NormalizeMsix(key); + if (normalized.Length >= 3 && !map.ContainsKey(normalized)) + map[normalized] = path; + } + + private static string NormalizeMsix(string? value) + { + if (string.IsNullOrWhiteSpace(value)) + return ""; + var sb = new StringBuilder(value.Length); + foreach (var c in value) + if (char.IsLetterOrDigit(c)) + sb.Append(char.ToLowerInvariant(c)); + return sb.ToString(); + } +} diff --git a/src/UniGetUI.PackageEngine.Managers.WinGet/Helpers/WinGetPkgDetailsHelper.cs b/src/UniGetUI.PackageEngine.Managers.WinGet/Helpers/WinGetPkgDetailsHelper.cs new file mode 100644 index 0000000..9d09e3b --- /dev/null +++ b/src/UniGetUI.PackageEngine.Managers.WinGet/Helpers/WinGetPkgDetailsHelper.cs @@ -0,0 +1,168 @@ +using System.Text.RegularExpressions; +using UniGetUI.Core.IconEngine; +using UniGetUI.Core.Logging; +using UniGetUI.PackageEngine.Classes.Manager.BaseProviders; +using UniGetUI.PackageEngine.Interfaces; +using UniGetUI.PackageEngine.Managers.WinGet.ClientHelpers; + +namespace UniGetUI.PackageEngine.Managers.WingetManager +{ + internal sealed class WinGetPkgDetailsHelper : BasePkgDetailsHelper + { + public WinGetPkgDetailsHelper(WinGet manager) + : base(manager) { } + + protected override IReadOnlyList GetInstallableVersions_UnSafe(IPackage package) + { + return WinGetHelper.Instance.GetInstallableVersions_Unsafe(package); + } + + protected override void GetDetails_UnSafe(IPackageDetails details) + { + WinGetHelper.Instance.GetPackageDetails_UnSafe(details); + } + + protected override CacheableIcon? GetIcon_UnSafe(IPackage package) + { + if (package.Source is LocalWinGetSource localSource) + { + if (localSource.Type is LocalWinGetSource.Type_t.MicrosftStore) + return WinGetIconsHelper.GetAppxPackageIcon(package); + else if (localSource.Type is LocalWinGetSource.Type_t.LocalPC) + return WinGetIconsHelper.GetARPPackageIcon(package); + + return null; + } + + if (package.Source.Name == "msstore") + return WinGetIconsHelper.GetMicrosoftStoreIcon(package); + + return WinGetIconsHelper.GetWinGetPackageIcon(package); + } + + protected override string? GetInstallLocation_UnSafe(IPackage package) + { + // Packages from the local "Add/Remove programs" source encode their exact registry key + // in the Id, so their install location can be read straight from that ARP entry. The + // generic name-based ARP lookup is handled by the base helper as a fallback. + if (package.Source is LocalWinGetSource { Type: LocalWinGetSource.Type_t.LocalPC }) + { + var encodedLocation = ArpRegistryHelper.GetLocationFromEncodedId(package.Id); + if (encodedLocation is not null) + return encodedLocation; + } + + // MSIX/Store packages from the Microsoft Store source encode their full name in the Id. + var msixFromId = WinGetIconsHelper.GetMsixLocationFromId(package); + if (msixFromId is not null) + return msixFromId; + + // Match against Add/Remove programs by name before the heavier lookups below. + var arpByName = ArpRegistryHelper.ResolveByName(package.Name, package.Id); + if (arpByName is not null) + return arpByName; + + foreach ( + var base_path in new[] + { + Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles), + Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86), + Path.Join( + Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), + "Programs" + ), + Path.Join( + Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), + "Microsoft", + "WinGet", + "Packages" + ), + Path.Join( + Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86), + "WinGet", + "Packages" + ), + Path.Join( + Environment.GetFolderPath(Environment.SpecialFolder.Programs), + "WinGet", + "Packages" + ), + Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), + } + ) + { + var path_with_name = Path.Join(base_path, package.Name); + if (Directory.Exists(path_with_name)) + return path_with_name; + + var path_with_id = Path.Join(base_path, package.Id); + if (Directory.Exists(path_with_id)) + return path_with_id; + + var path_with_source = Path.Join(base_path, $"{package.Id}_{package.Source.Name}"); + if (Directory.Exists(path_with_source)) + return path_with_source; + } + + // Last resort: enumerate installed MSIX packages (has a cost, so only reached when + // nothing cheaper matched — e.g. Store apps surfaced through the winget catalog). + return WinGetIconsHelper.GetMsixLocationByName(package); + } + + protected override IReadOnlyList GetScreenshots_UnSafe(IPackage package) + { + if (package.Source.Name != "msstore") + { + return []; + } + + string? ResponseContent = WinGetIconsHelper.GetMicrosoftStoreManifest(package); + if (ResponseContent is null) + { + return []; + } + + Match IconArray = Regex.Match( + ResponseContent, + "(?:\"|')Images(?:\"|'): ?\\[([^\\]]+)\\]" + ); + if (!IconArray.Success) + { + Logger.Warn("Could not parse Images array from Microsoft Store response"); + return []; + } + + List FoundIcons = []; + + foreach (Match ImageEntry in Regex.Matches(IconArray.Groups[1].Value, "{([^}]+)}")) + { + if (!ImageEntry.Success) + { + continue; + } + + Match ImagePurpose = Regex.Match( + ImageEntry.Groups[1].Value, + "(?:\"|')ImagePurpose(?:\"|'): ?(?:\"|')([^'\"]+)(?:\"|')" + ); + if (!ImagePurpose.Success || ImagePurpose.Groups[1].Value != "Screenshot") + { + continue; + } + + Match ImageUrl = Regex.Match( + ImageEntry.Groups[1].Value, + "(?:\"|')Uri(?:\"|'): ?(?:\"|')([^'\"]+)(?:\"|')" + ); + if (!ImageUrl.Success) + { + continue; + } + + FoundIcons.Add(new Uri("https:" + ImageUrl.Groups[1].Value)); + } + + return FoundIcons; + } + } +} diff --git a/src/UniGetUI.PackageEngine.Managers.WinGet/Helpers/WinGetPkgOperationHelper.cs b/src/UniGetUI.PackageEngine.Managers.WinGet/Helpers/WinGetPkgOperationHelper.cs new file mode 100644 index 0000000..71641d6 --- /dev/null +++ b/src/UniGetUI.PackageEngine.Managers.WinGet/Helpers/WinGetPkgOperationHelper.cs @@ -0,0 +1,485 @@ +using Microsoft.Management.Deployment; +using Microsoft.Win32; +using UniGetUI.Core.Logging; +using UniGetUI.Core.SettingsEngine; +using UniGetUI.Core.Tools; +using UniGetUI.PackageEngine.Classes.Manager.BaseProviders; +using UniGetUI.PackageEngine.Enums; +using UniGetUI.PackageEngine.Interfaces; +using UniGetUI.PackageEngine.PackageClasses; +using Architecture = UniGetUI.PackageEngine.Enums.Architecture; +using InstallOptions = UniGetUI.PackageEngine.Serializable.InstallOptions; + +namespace UniGetUI.PackageEngine.Managers.WingetManager; + +internal sealed class WinGetPkgOperationHelper : BasePkgOperationHelper +{ + public static string GetIdNamePiece(IPackage package) + { + if (!package.Id.EndsWith("…")) + return $"--id \"{package.Id.TrimEnd('…')}\" --exact"; + + if (!package.Name.EndsWith("…")) + return $"--name \"{package.Name}\" --exact"; + + return $"--id \"{package.Id.TrimEnd('…')}\""; + } + + public WinGetPkgOperationHelper(WinGet manager) + : base(manager) { } + + protected override IReadOnlyList _getOperationParameters( + IPackage package, + InstallOptions options, + OperationType operation + ) + { + // Pinget 0.4.x does not accept --accept-source-agreements, --disable-interactivity, + // or --proxy on any verb; --accept-package-agreements, --force, --location, and + // --interactive are accepted on install/uninstall but rejected on upgrade. + bool usePinget = + ((WinGet)Manager).SelectedCliToolKind == WinGetCliToolKind.BundledPinget; + + List parameters = + [ + operation switch + { + OperationType.Install => Manager.Properties.InstallVerb, + OperationType.Update => Manager.Properties.UpdateVerb, + OperationType.Uninstall => Manager.Properties.UninstallVerb, + _ => throw new InvalidDataException("Invalid package operation"), + }, + ]; + + parameters.AddRange(GetIdNamePiece(package).Split(" ")); + if (!package.Source.IsVirtualManager) + { + parameters.AddRange(["--source", package.Source.Name]); + } + if (!usePinget) + { + parameters.AddRange(["--accept-source-agreements", "--disable-interactivity"]); + } + + // package.OverridenInstallationOptions.Scope is meaningless in WinGet packages. Default is unspecified, hence the _ => []. + // WinGet_DropArchAndScope is set after an "update not applicable" failure to retry without the scope/architecture constraints. + if (!package.OverridenOptions.WinGet_DropArchAndScope) + { + parameters.AddRange( + (package.OverridenOptions.Scope ?? options.InstallationScope) switch + { + PackageScope.User => ["--scope", "user"], + PackageScope.Machine => ["--scope", "machine"], + _ => [], + } + ); + } + + if ( + operation is OperationType.Uninstall + && package.VersionString != "Unknown" + && package.OverridenOptions.WinGet_SpecifyVersion is not false + ) + { + parameters.AddRange(["--version", $"\"{package.VersionString}\""]); + } + else if (operation is OperationType.Install && options.Version != "") + { + parameters.AddRange(["--version", $"\"{options.Version}\""]); + } + + if (usePinget && operation is OperationType.Update) + { + // pinget upgrade only supports --silent (no --interactive). + parameters.Add("--silent"); + } + else + { + parameters.Add(options.InteractiveInstallation ? "--interactive" : "--silent"); + } + + if (operation is OperationType.Update) + { + if (package.Name.Contains("64-bit") || package.Id.ToLower().Contains("x64")) + { + options.Architecture = Architecture.x64; + } + else if (package.Name.Contains("32-bit") || package.Id.ToLower().Contains("x86")) + { + options.Architecture = Architecture.x86; + } + parameters.Add("--include-unknown"); + + if (!usePinget) + { + // For portable packages, always preserve the actual current install + // location read from the registry. A stale CustomInstallLocation in the + // saved InstallOptions would otherwise leave --location off and cause + // WinGet to uninstall the portable from its custom path and reinstall to + // the default portable root, silently deleting the original directory. + var detectedLocation = TryGetPortableInstallLocation(package); + if (detectedLocation is not null) + { + parameters.AddRange(["--location", $"\"{detectedLocation}\""]); + } + else if ( + options.CustomInstallLocation != "" + && Settings.Get(Settings.K.WinGetForceLocationOnUpdate) + ) + { + parameters.AddRange(["--location", $"\"{options.CustomInstallLocation}\""]); + } + } + } + else if (operation is OperationType.Install) + { + if (options.CustomInstallLocation != "") + parameters.AddRange(["--location", $"\"{options.CustomInstallLocation}\""]); + } + + if (operation is not OperationType.Uninstall) + { + // pinget upgrade does not accept --accept-package-agreements or --force. + if (!(usePinget && operation is OperationType.Update)) + { + parameters.AddRange(["--accept-package-agreements", "--force"]); + } + + if (options.SkipHashCheck) + parameters.Add("--ignore-security-hash"); + + if (!package.OverridenOptions.WinGet_DropArchAndScope) + { + parameters.AddRange( + options.Architecture switch + { + Architecture.x86 => ["--architecture", "x86"], + Architecture.x64 => ["--architecture", "x64"], + Architecture.arm64 => ["--architecture", "arm64"], + _ => [], + } + ); + } + } + + try + { + var installOptions = NativePackageHandler.GetInstallationOptions( + package, + options, + operation + ); + if ( + installOptions?.ElevationRequirement + is ElevationRequirement.ElevationRequired + or ElevationRequirement.ElevatesSelf + ) + { + Logger.Info( + $"WinGet package {package.Id} requires elevation, forcing administrator rights..." + ); + package.OverridenOptions.RunAsAdministrator = true; + } + else if ( + installOptions?.ElevationRequirement is ElevationRequirement.ElevationProhibited + ) + { + if (CoreTools.IsAdministrator()) + throw new UnauthorizedAccessException( + CoreTools.Translate( + "This package cannot be installed from an elevated context." + ) + + CoreTools.Translate( + "Please run UniGetUI as a regular user and try again." + ) + ); + + if (options.RunAsAdministrator) + throw new UnauthorizedAccessException( + CoreTools.Translate( + "This package cannot be installed from an elevated context." + ) + + CoreTools.Translate( + "Please check the installation options for this package and try again" + ) + ); + + package.OverridenOptions.RunAsAdministrator = false; + } + else if ( + installOptions?.Scope is PackageInstallerScope.System /* or PackageInstallerScope.Unknown*/ + ) + { + Logger.Info( + $"WinGet package {package.Id} is installed on a system-wide scope, forcing administrator rights..." + ); + package.OverridenOptions.RunAsAdministrator = true; + } + } + catch (Exception ex) + { + if (ex is UnauthorizedAccessException) + throw; + + Logger.Error("Recovered from fatal WinGet exception:"); + Logger.Error(ex); + } + + if (!usePinget) + { + parameters.Add(WinGet.GetProxyArgument()); + } + + parameters.AddRange( + operation switch + { + OperationType.Update => options.CustomParameters_Update, + OperationType.Uninstall => options.CustomParameters_Uninstall, + _ => options.CustomParameters_Install, + } + ); + return parameters; + } + + protected override OperationVeredict _getOperationResult( + IPackage package, + OperationType operation, + IReadOnlyList processOutput, + int returnCode + ) + { + // See https://github.com/microsoft/winget-cli/blob/master/doc/windows/package-manager/winget/returnCodes.md for reference + uint uintCode = (uint)returnCode; + + if (uintCode is 0x8A150109) + { // TODO: Restart required to finish installation + if (operation is OperationType.Update or OperationType.Install) + MarkUpgradeAsDone(package); + return OperationVeredict.Success; + } + + if (uintCode is 0x8A150077 or 0x8A15010C or 0x8A150005) + { // At some point, the user clicked cancel or Ctrl+C + return OperationVeredict.Canceled; + } + + if ( + operation is OperationType.Uninstall + && uintCode is 0x8A150017 + && package.OverridenOptions.WinGet_SpecifyVersion is not false + ) + { // No manifest found matching criteria + package.OverridenOptions.WinGet_SpecifyVersion = false; + return OperationVeredict.AutoRetry; + } + + if (uintCode is 0x8A150011) + { // TODO: Integrity failed + return OperationVeredict.Failure; + } + + // WinGet (CLI/COM) reports "not applicable" as 0x8A15002B; bundled pinget instead exits + // non-zero with "No applicable installer found" in its output. + bool pingetReportedNotApplicable = + ((WinGet)Manager).SelectedCliToolKind is WinGetCliToolKind.BundledPinget + && returnCode != 0 + && processOutput.Any(line => + line.Contains("No applicable installer found", StringComparison.OrdinalIgnoreCase) + ); + + if (uintCode is 0x8A15002B || pingetReportedNotApplicable) + { // The update is not applicable to the platform + // The scope/architecture we forced may exclude the only installer the package ships + // (e.g. forcing --architecture x64 on a package that only has an x86 installer). Retry + // once letting the package manager pick freely, matching what the CLI does by default. + if (operation is OperationType.Update && !package.OverridenOptions.WinGet_DropArchAndScope) + { + var options = InstallOptionsFactory.LoadApplicable(package); + bool hasScope = + (package.OverridenOptions.Scope ?? options.InstallationScope) + is PackageScope.User or PackageScope.Machine; + bool hasArch = + options.Architecture is Architecture.x86 or Architecture.x64 or Architecture.arm64; + + if (hasScope || hasArch) + { + Logger.Warn( + $"Update for {package.Id} reported as not applicable; retrying without the scope/architecture constraints" + ); + package.OverridenOptions.WinGet_DropArchAndScope = true; + return OperationVeredict.AutoRetry; + } + } + + Logger.Warn( + $"Update for {package.Id} is not applicable to this system, even without scope/architecture constraints" + ); + return OperationVeredict.Failure; + } + + if (uintCode is 0x8A15010D or 0x8A15004F or 0x8A15010E) + { // Application is already installed + if (operation is OperationType.Update or OperationType.Install) + MarkUpgradeAsDone(package); + return OperationVeredict.Success; + } + + if (returnCode is 0) + { // Operation succeeded + if (operation is OperationType.Update or OperationType.Install) + MarkUpgradeAsDone(package); + return OperationVeredict.Success; + } + + if ( + uintCode is 0x8A150056 + && package.OverridenOptions.RunAsAdministrator is not false + && !CoreTools.IsAdministrator() + ) + { // Installer can't run elevated, but this condition hasn't been forced on UniGetUI + package.OverridenOptions.RunAsAdministrator = false; + return OperationVeredict.AutoRetry; + } + + if ( + (uintCode is 0x8A150019 or 0x80073D28) + && package.OverridenOptions.RunAsAdministrator is not true + ) + { // Installer needs to run elevated, handle autoelevation + // Code 0x80073D28 was added after https://github.com/Devolutions/UniGetUI/issues/3093 + package.OverridenOptions.RunAsAdministrator = true; + return OperationVeredict.AutoRetry; + } + + if ( + operation is OperationType.Uninstall + && (uintCode is 0x8A150030) + && package.OverridenOptions.RunAsAdministrator is not true + ) + { // Sometimes, when uninstalling, error code 0x8A150030 can be caused by missing permissions. + package.OverridenOptions.RunAsAdministrator = true; + return OperationVeredict.AutoRetry; + } + + return OperationVeredict.Failure; + } + + private static void MarkUpgradeAsDone(IPackage package) + { + var options = InstallOptionsFactory.LoadApplicable(package); + string version; + if (package.IsUpgradable) + version = package.NewVersionString; + else if (options.Version != "") + version = options.Version; + else + version = package.VersionString; + Settings.SetDictionaryItem( + Settings.K.WinGetAlreadyUpgradedPackages, + package.Id, + version + ); + } + + public static bool UpdateAlreadyInstalled(IPackage package) + { + return Settings.GetDictionaryItem( + Settings.K.WinGetAlreadyUpgradedPackages, + package.Id + ) == package.NewVersionString; + } + + public static void ClearUpgradeMark(IPackage package) + { + Settings.RemoveDictionaryKey( + Settings.K.WinGetAlreadyUpgradedPackages, + package.Id + ); + } + + // One-shot suppression: hide a just-upgraded package once (bridges CLI index lag), then clear + // the mark so a still-outdated package reappears next scan instead of forever (issue #5042). + public static bool ConsumeAlreadyUpgradedSuppression(IPackage package) + { + if (!UpdateAlreadyInstalled(package)) + return false; + + ClearUpgradeMark(package); + return true; + } + + public static string GetLastInstalledVersion(string id) + { + var val = Settings.GetDictionaryItem( + Settings.K.WinGetAlreadyUpgradedPackages, + id + ); + if (val is null || val == "") + val = "Unknown"; + return val; + } + + /// + /// For portable WinGet packages, reads the current install location from the Windows registry + /// ARP entry (written by WinGet at install time). Returns null if the package is not portable + /// or the location cannot be determined. + /// + private static string? TryGetPortableInstallLocation(IPackage package) + { + try + { + foreach ( + var hive in new RegistryKey[] { Registry.CurrentUser, Registry.LocalMachine } + ) + { + using var uninstallKey = hive.OpenSubKey( + @"Software\Microsoft\Windows\CurrentVersion\Uninstall" + ); + if (uninstallKey is null) + continue; + + foreach (var name in uninstallKey.GetSubKeyNames()) + { + using var entry = uninstallKey.OpenSubKey(name); + if (entry is null) + continue; + + if ( + entry.GetValue("WinGetPackageIdentifier") is not string pkgId + || !string.Equals(pkgId, package.Id, StringComparison.OrdinalIgnoreCase) + ) + continue; + + if ( + entry.GetValue("WinGetInstallerType") is not string installerType + || !string.Equals( + installerType, + "portable", + StringComparison.OrdinalIgnoreCase + ) + ) + return null; + + if ( + entry.GetValue("InstallLocation") is string location + && location.Length > 0 + ) + { + Logger.Info( + $"Auto-detected portable install location for {package.Id}: {location}" + ); + return location; + } + } + } + } + catch (Exception ex) + { + Logger.Warn( + $"Failed to auto-detect portable install location for {package.Id}: {ex.Message}" + ); + } + + return null; + } +} diff --git a/src/UniGetUI.PackageEngine.Managers.WinGet/Helpers/WinGetSourceHelper.cs b/src/UniGetUI.PackageEngine.Managers.WinGet/Helpers/WinGetSourceHelper.cs new file mode 100644 index 0000000..04d25e4 --- /dev/null +++ b/src/UniGetUI.PackageEngine.Managers.WinGet/Helpers/WinGetSourceHelper.cs @@ -0,0 +1,85 @@ +using UniGetUI.PackageEngine.Classes.Manager.Providers; +using UniGetUI.PackageEngine.Enums; +using UniGetUI.PackageEngine.Interfaces; + +namespace UniGetUI.PackageEngine.Managers.WingetManager +{ + internal sealed class WinGetSourceHelper : BaseSourceHelper + { + private readonly string[][] _sourceTypes = + [ + ["--type", "Microsoft.PreIndexed.Package"], + ["--type", "Microsoft.Rest"], + ]; + private readonly Dictionary _attemptedSourceTypes = new(); + + public WinGetSourceHelper(WinGet manager) + : base(manager) { } + + public override string[] GetAddSourceParameters(IManagerSource source) + { + List args = + [ + "source", + "add", + "--name", + source.Name, + "--arg", + source.Url.ToString(), + "--accept-source-agreements", + "--disable-interactivity", + ]; + + if (source.Name != "winget") + { + int sourceIndex = _attemptedSourceTypes.GetValueOrDefault(source.Name); + args.AddRange(_sourceTypes[sourceIndex]); + } + + return args.ToArray(); + } + + public override string[] GetRemoveSourceParameters(IManagerSource source) + { + return ["source", "remove", "--name", source.Name, "--disable-interactivity"]; + } + + protected override OperationVeredict _getAddSourceOperationVeredict( + IManagerSource source, + int ReturnCode, + string[] Output + ) + { + // If operation succeeded, or the source already exists + if ((uint)ReturnCode is 0 or 0x8A15000C) + return OperationVeredict.Success; + + // Failed? Let's guess another source type and try again + int sourceIndex = _attemptedSourceTypes.GetValueOrDefault(source.Name); + if (sourceIndex + 1 >= _sourceTypes.Length) + { + // If we have tested all available sources? + _attemptedSourceTypes[source.Name] = 0; + return OperationVeredict.Failure; + } + + // Attempt another source type + _attemptedSourceTypes[source.Name] = sourceIndex + 1; + return OperationVeredict.AutoRetry; + } + + protected override OperationVeredict _getRemoveSourceOperationVeredict( + IManagerSource source, + int ReturnCode, + string[] Output + ) + { + return ReturnCode == 0 ? OperationVeredict.Success : OperationVeredict.Failure; + } + + protected override IReadOnlyList GetSources_UnSafe() + { + return WinGetHelper.Instance.GetSources_UnSafe(); + } + } +} diff --git a/src/UniGetUI.PackageEngine.Managers.WinGet/InternalsVisibleTo.cs b/src/UniGetUI.PackageEngine.Managers.WinGet/InternalsVisibleTo.cs new file mode 100644 index 0000000..f9f7a70 --- /dev/null +++ b/src/UniGetUI.PackageEngine.Managers.WinGet/InternalsVisibleTo.cs @@ -0,0 +1,4 @@ +using System.Runtime.CompilerServices; + +[assembly: InternalsVisibleTo("UniGetUI.PackageEngine.Tests")] +[assembly: InternalsVisibleTo("UniGetUI.PackageEngine.Operations")] diff --git a/src/UniGetUI.PackageEngine.Managers.WinGet/UniGetUI.PackageEngine.Managers.WinGet.csproj b/src/UniGetUI.PackageEngine.Managers.WinGet/UniGetUI.PackageEngine.Managers.WinGet.csproj new file mode 100644 index 0000000..f90f9be --- /dev/null +++ b/src/UniGetUI.PackageEngine.Managers.WinGet/UniGetUI.PackageEngine.Managers.WinGet.csproj @@ -0,0 +1,30 @@ + + + $(WindowsTargetFramework) + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/UniGetUI.PackageEngine.Managers.WinGet/WinGet.cs b/src/UniGetUI.PackageEngine.Managers.WinGet/WinGet.cs new file mode 100644 index 0000000..2ff8f11 --- /dev/null +++ b/src/UniGetUI.PackageEngine.Managers.WinGet/WinGet.cs @@ -0,0 +1,841 @@ +using System.Diagnostics; +using System.Security.AccessControl; +using System.Security.Principal; +using System.Text; +using UniGetUI.Core.Data; +using UniGetUI.Core.Logging; +using UniGetUI.Core.SettingsEngine; +using UniGetUI.Core.Tools; +using UniGetUI.Interface.Enums; +using UniGetUI.PackageEngine.Classes.Manager; +using UniGetUI.PackageEngine.Classes.Manager.ManagerHelpers; +using UniGetUI.PackageEngine.Enums; +using UniGetUI.PackageEngine.ManagerClasses.Classes; +using UniGetUI.PackageEngine.ManagerClasses.Manager; +using UniGetUI.PackageEngine.PackageClasses; +using WindowsPackageManager.Interop; +using Architecture = UniGetUI.PackageEngine.Enums.Architecture; + +namespace UniGetUI.PackageEngine.Managers.WingetManager +{ + public class WinGet : PackageManager + { + internal const string CliToolPreferenceEnvironmentVariable = "UNIGETUI_WINGET_CLI"; + internal const string ComApiPolicyEnvironmentVariable = "UNIGETUI_WINGET_COM"; + private const string SystemWinGetExecutableName = "winget.exe"; + private const string PingetExecutableName = "pinget.exe"; + + public static string[] FALSE_PACKAGE_NAMES = ["", "e(s)", "have", "the", "Id"]; + public static string[] FALSE_PACKAGE_IDS = + [ + "", + "e(s)", + "have", + "an", + "'winget", + "pin'", + "have", + "an", + "Version", + ]; + public static string[] FALSE_PACKAGE_VERSIONS = + [ + "", + "have", + "an", + "'winget", + "pin'", + "have", + "an", + "Version", + ]; + public LocalWinGetSource LocalPcSource { get; } + public LocalWinGetSource AndroidSubsystemSource { get; } + public LocalWinGetSource SteamSource { get; } + public LocalWinGetSource UbisoftConnectSource { get; } + public LocalWinGetSource GOGSource { get; } + public LocalWinGetSource MicrosoftStoreSource { get; } + public static bool NO_PACKAGES_HAVE_BEEN_LOADED { get; private set; } + internal WinGetCliToolKind SelectedCliToolKind { get; private set; } = + WinGetCliToolKind.SystemWinGet; + + // winget's local index isn't safe under concurrent process access: a `source update` (writer) + // running alongside list/upgrade/search (readers) yields partial or empty results. The COM + // backend serialized this implicitly; the CLI backends (winget.exe / pinget.exe) must do it + // explicitly. Reentrant (Monitor) so same-thread nested invocations don't self-deadlock. + private static readonly object _cliInvocationLock = new(); + + // Safety valve: never wait on the CLI lock longer than this, so a hung process can't freeze all WinGet queries. + private static readonly TimeSpan CliLockTimeout = TimeSpan.FromSeconds(120); + + internal static IDisposable AcquireCliLock() + { + bool taken = false; + Monitor.TryEnter(_cliInvocationLock, CliLockTimeout, ref taken); + if (!taken) + Logger.Warn("WinGet CLI lock not acquired within timeout; proceeding unserialized to avoid a hang."); + return new CliLockReleaser(taken); + } + + private sealed class CliLockReleaser(bool taken) : IDisposable + { + private bool _released; + public void Dispose() + { + if (_released || !taken) return; + _released = true; + Monitor.Exit(_cliInvocationLock); + } + } + + public WinGet() + { + Capabilities = new ManagerCapabilities + { + CanRunAsAdmin = true, + CanSkipIntegrityChecks = true, + CanRunInteractively = true, + SupportsCustomVersions = true, + CanDownloadInstaller = true, + CanListDependencies = true, + SupportsCustomArchitectures = true, + SupportedCustomArchitectures = + [ + Architecture.x86, + Architecture.x64, + Architecture.arm64, + ], + SupportsCustomScopes = true, + SupportsCustomLocations = true, + SupportsCustomSources = true, + SupportsCustomPackageIcons = true, + SupportsCustomPackageScreenshots = true, + Sources = new SourceCapabilities + { + KnowsPackageCount = false, + KnowsUpdateDate = true, + MustBeInstalledAsAdmin = true, + }, + SupportsProxy = ProxySupport.Partially, + SupportsProxyAuth = false, + KnowsPackageReleaseDate = PackageReleaseDateSupport.Partial, + }; + + Properties = new ManagerProperties + { + Id = "winget", + Name = "Winget", + DisplayName = "WinGet", + Description = CoreTools.Translate( + "Microsoft's official package manager. Full of well-known and verified packages
Contains: General Software, Microsoft Store apps" + ), + IconId = IconType.WinGet, + ColorIconId = "winget_color", + ExecutableFriendlyName = "winget.exe", + InstallVerb = "install", + UninstallVerb = "uninstall", + UpdateVerb = "update", + KnownSources = + [ + new ManagerSource( + this, + "winget", + new Uri("https://cdn.winget.microsoft.com/cache") + ), + new ManagerSource( + this, + "winget-fonts", + new Uri("https://cdn.winget.microsoft.com/fonts") + ), + new ManagerSource( + this, + "msstore", + new Uri("https://storeedgefd.dsx.mp.microsoft.com/v9.0") + ), + ], + DefaultSource = new ManagerSource( + this, + "winget", + new Uri("https://cdn.winget.microsoft.com/cache") + ), + }; + + SourcesHelper = new WinGetSourceHelper(this); + DetailsHelper = new WinGetPkgDetailsHelper(this); + OperationHelper = new WinGetPkgOperationHelper(this); + + LocalPcSource = new LocalWinGetSource( + this, + CoreTools.Translate("Local PC"), + IconType.LocalPc, + LocalWinGetSource.Type_t.LocalPC + ); + AndroidSubsystemSource = new( + this, + CoreTools.Translate("Android Subsystem"), + IconType.Android, + LocalWinGetSource.Type_t.Android + ); + SteamSource = new(this, "Steam", IconType.Steam, LocalWinGetSource.Type_t.Steam); + UbisoftConnectSource = new( + this, + "Ubisoft Connect", + IconType.UPlay, + LocalWinGetSource.Type_t.Ubisoft + ); + GOGSource = new(this, "GOG", IconType.GOG, LocalWinGetSource.Type_t.GOG); + MicrosoftStoreSource = new( + this, + "Microsoft Store", + IconType.MsStore, + LocalWinGetSource.Type_t.MicrosftStore + ); + } + + public static string GetProxyArgument() + { + if (!Settings.Get(Settings.K.EnableProxy)) + return ""; + var proxyUri = Settings.GetProxyUrl(); + if (proxyUri is null) + return ""; + + if (Settings.Get(Settings.K.EnableProxyAuth)) + { + Logger.Warn( + "Proxy is enabled, but WinGet does not support proxy authentication, so the proxy setting will be ignored" + ); + return ""; + } + return $"--proxy {proxyUri.ToString().TrimEnd('/')}"; + } + + /// + /// Returns the set of installer URL hosts from the WinGet manifest for a specific + /// version of the given package, or null if it can't be resolved. Used for the + /// installer-host-change warning on the Updates page (issue #4617). + /// Returns a set (not a single host) so callers can do set-overlap comparison — + /// see PingetPackageDetailsProvider.TryGetInstallerHostsForVersion for rationale. + /// + public static IReadOnlySet? TryGetInstallerHostsForVersion( + UniGetUI.PackageEngine.Interfaces.IPackage package, + string version + ) + { + return PingetPackageDetailsProvider.TryGetInstallerHostsForVersion(package, version); + } + + protected override IReadOnlyList FindPackages_UnSafe(string query) + { + return WinGetHelper.Instance.FindPackages_UnSafe(query); + } + + protected override IReadOnlyList GetAvailableUpdates_UnSafe() + { + return WinGetHelper + .Instance.GetAvailableUpdates_UnSafe() + .Where(p => p.Id != "Chocolatey.Chocolatey") + .ToArray(); + } + + protected override IReadOnlyList GetInstalledPackages_UnSafe() + { + try + { + var packages = WinGetHelper.Instance.GetInstalledPackages_UnSafe(); + NO_PACKAGES_HAVE_BEEN_LOADED = false; + return packages; + } + catch (Exception) + { + NO_PACKAGES_HAVE_BEEN_LOADED = true; + throw; + } + } + + public ManagerSource GetLocalSource(string id) + { + var IdPieces = id.Split('\\'); + if (IdPieces[0] == "MSIX") + { + return MicrosoftStoreSource; + } + + string MeaningfulId = IdPieces[^1]; + + // Fast Local PC Check + if (MeaningfulId[0] == '{') + { + return LocalPcSource; + } + + // Check if source is android + if ( + MeaningfulId.Count(x => x == '.') >= 2 + && MeaningfulId.All(c => + (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || c == '.' || c == '…' + ) + ) + { + return AndroidSubsystemSource; + } + + // Check if source is Steam + if (MeaningfulId == "Steam" || MeaningfulId.StartsWith("Steam App")) + { + return SteamSource; + } + + // Check if source is Ubisoft Connect + if (MeaningfulId == "Uplay" || MeaningfulId.StartsWith("Uplay Install")) + { + return UbisoftConnectSource; + } + + // Check if source is GOG + if ( + MeaningfulId.EndsWith("_is1") + && MeaningfulId.Replace("_is1", "").All(c => (c >= '0' && c <= '9')) + ) + { + return GOGSource; + } + + // Otherwise they are Local PC + return LocalPcSource; + } + + public override IReadOnlyList FindCandidateExecutableFiles() + { + return FindCandidateExecutableFiles( + executableName => CoreTools.WhichMultiple(executableName), + File.Exists, + GetBundledPingetExecutablePath(), + GetCliToolPreference() + ); + } + + internal static IReadOnlyList FindCandidateExecutableFiles( + Func> findExecutables, + Func fileExists, + string bundledPingetPath, + WinGetCliToolPreference cliToolPreference = WinGetCliToolPreference.Default + ) + { + List candidates = []; + + if (cliToolPreference is not WinGetCliToolPreference.BundledPinget) + { + candidates.AddRange(findExecutables(SystemWinGetExecutableName)); + } + + if (cliToolPreference is not WinGetCliToolPreference.SystemWinGet) + { + candidates.AddRange( + FindPingetExecutableFiles(findExecutables, fileExists, bundledPingetPath) + ); + } + + return candidates.Distinct(StringComparer.OrdinalIgnoreCase).ToArray(); + } + + private static IEnumerable FindPingetExecutableFiles( + Func> findExecutables, + Func fileExists, + string bundledPingetPath + ) + { + if (fileExists(bundledPingetPath)) + { + yield return bundledPingetPath; + } + + foreach (string pingetExecutablePath in findExecutables(PingetExecutableName)) + { + yield return pingetExecutablePath; + } + } + + internal static string GetBundledPingetExecutablePath() + { + return GetBundledPingetExecutablePath(CoreData.UniGetUIExecutableDirectory, File.Exists); + } + + internal static string GetBundledPingetExecutablePath( + string executableDirectory, + Func fileExists + ) + { + string installDirectory = CoreData.ResolveInstallationDirectory( + executableDirectory, + fileExists, + static _ => false + ); + string rootPingetPath = Path.Join(installDirectory, PingetExecutableName); + if (fileExists(rootPingetPath)) + { + return rootPingetPath; + } + + string avaloniaPingetPath = Path.Join( + installDirectory, + "Avalonia", + PingetExecutableName + ); + return fileExists(avaloniaPingetPath) ? avaloniaPingetPath : rootPingetPath; + } + + internal IWinGetManagerHelper CreateCliHelperForSelectedCliTool() + { + return CreateCliHelperForSelectedCliTool(Status.ExecutablePath); + } + + internal IWinGetManagerHelper CreateCliHelperForSelectedCliTool(string executablePath) + { + return SelectedCliToolKind == WinGetCliToolKind.BundledPinget + ? new PingetCliHelper(this, executablePath) + : new WinGetCliHelper(this, executablePath); + } + + protected override void _loadManagerExecutableFile( + out bool found, + out string path, + out string callArguments + ) + { + var (_found, _path) = GetExecutableFile(); + found = _found; + path = _path; + callArguments = ""; + + if (!found) + { + return; + } + + SelectedCliToolKind = GetCliToolKind(path); + + if (SelectedCliToolKind == WinGetCliToolKind.BundledPinget) + { + Logger.Warn("Using Pinget CLI tool."); + WinGetHelper.Instance = new PingetCliHelper(this, path); + return; + } + + WinGetComApiPolicy comApiPolicy = GetComApiPolicy(); + if (!ShouldUseWinGetComApi(SelectedCliToolKind, comApiPolicy)) + { + Logger.Warn("WinGet COM API usage is disabled; using WinGetCliHelper()."); + WinGetHelper.Instance = new WinGetCliHelper(this, path); + return; + } + + try + { + WinGetHelper.Instance = new NativeWinGetHelper(this); + } + catch (Exception ex) + { + if ( + ex is WinGetComActivationException activationEx + && activationEx.IsExpectedFallbackCondition + ) + { + Logger.Warn( + $"Native WinGet helper is unavailable on this machine ({activationEx.HResultHex}: {activationEx.Reason})" + ); + } + else + { + Logger.Warn( + $"Cannot instantiate Native WinGet Helper due to error: {ex.Message}" + ); + Logger.Warn(ex); + } + + Logger.Warn("WinGet will resort to using WinGetCliHelper()"); + WinGetHelper.Instance = CreateCliHelperForSelectedCliTool(path); + } + } + + internal static WinGetCliToolPreference GetCliToolPreference() + { + return GetCliToolPreference( + static name => Environment.GetEnvironmentVariable(name), + static key => Settings.GetValue(key) + ); + } + + internal static WinGetCliToolPreference GetCliToolPreference( + Func getEnvironmentVariable, + Func getSettingValue + ) + { + string? value = GetPolicyValue( + CliToolPreferenceEnvironmentVariable, + Settings.K.WinGetCliToolPreference, + getEnvironmentVariable, + getSettingValue + ); + + return ParseCliToolPreference(value) ?? WinGetCliToolPreference.Default; + } + + internal static WinGetComApiPolicy GetComApiPolicy() + { + return GetComApiPolicy( + static name => Environment.GetEnvironmentVariable(name), + static key => Settings.GetValue(key) + ); + } + + internal static WinGetComApiPolicy GetComApiPolicy( + Func getEnvironmentVariable, + Func getSettingValue + ) + { + string? value = GetPolicyValue( + ComApiPolicyEnvironmentVariable, + Settings.K.WinGetComApiPolicy, + getEnvironmentVariable, + getSettingValue + ); + + return ParseComApiPolicy(value) ?? WinGetComApiPolicy.Default; + } + + private static string? GetPolicyValue( + string environmentVariableName, + Settings.K settingKey, + Func getEnvironmentVariable, + Func getSettingValue + ) + { + string? environmentValue = getEnvironmentVariable(environmentVariableName); + if (!string.IsNullOrWhiteSpace(environmentValue)) + { + return environmentValue; + } + + string settingValue = getSettingValue(settingKey); + return string.IsNullOrWhiteSpace(settingValue) ? null : settingValue; + } + + private static WinGetCliToolPreference? ParseCliToolPreference(string? value) + { + return NormalizeCliToolPreferenceValue(value) switch + { + "default" => WinGetCliToolPreference.Default, + "winget" => WinGetCliToolPreference.SystemWinGet, + "pinget" => WinGetCliToolPreference.BundledPinget, + _ => null, + }; + } + + private static string NormalizeCliToolPreferenceValue(string? value) + { + return string.IsNullOrWhiteSpace(value) ? "" : value.Trim().ToLowerInvariant(); + } + + private static WinGetComApiPolicy? ParseComApiPolicy(string? value) + { + return NormalizePolicyValue(value) switch + { + "default" => WinGetComApiPolicy.Default, + "enabled" or "enable" or "on" or "true" or "1" => WinGetComApiPolicy.Enabled, + "disabled" or "disable" or "off" or "false" or "0" => WinGetComApiPolicy.Disabled, + _ => null, + }; + } + + internal static bool ShouldUseWinGetComApi( + WinGetCliToolKind cliToolKind, + WinGetComApiPolicy comApiPolicy + ) + { + return cliToolKind == WinGetCliToolKind.SystemWinGet + && comApiPolicy != WinGetComApiPolicy.Disabled; + } + + private static string NormalizePolicyValue(string? value) + { + return string.IsNullOrWhiteSpace(value) + ? "" + : value.Trim().Replace("-", "").Replace("_", "").ToLowerInvariant(); + } + + internal static WinGetCliToolKind GetCliToolKind(string executablePath) + { + return IsPingetExecutablePath(executablePath) + ? WinGetCliToolKind.BundledPinget + : WinGetCliToolKind.SystemWinGet; + } + + private static bool IsPingetExecutablePath(string executablePath) + { + if (string.IsNullOrWhiteSpace(executablePath)) + { + return false; + } + + return Path.GetFileName(executablePath).Equals( + PingetExecutableName, + StringComparison.OrdinalIgnoreCase + ) + || Path.GetFullPath(executablePath) + .Equals( + Path.GetFullPath(GetBundledPingetExecutablePath()), + StringComparison.OrdinalIgnoreCase + ); + } + + protected override void _loadManagerVersion(out string version) + { + bool usesCliHelper = WinGetHelper.Instance is WinGetCliHelper; + bool usesPingetHelper = WinGetHelper.Instance is PingetCliHelper; + + using Process process = new() + { + StartInfo = new ProcessStartInfo + { + FileName = Status.ExecutablePath, + Arguments = Status.ExecutableCallArgs + " --version", + UseShellExecute = false, + RedirectStandardOutput = true, + RedirectStandardError = true, + CreateNoWindow = true, + StandardOutputEncoding = Encoding.UTF8, + StandardErrorEncoding = Encoding.UTF8, + }, + }; + + if (CoreTools.IsAdministrator()) + { + string WinGetTemp = Path.Join(Path.GetTempPath(), "UniGetUI", "ElevatedWinGetTemp"); + process.StartInfo.Environment["TEMP"] = WinGetTemp; + process.StartInfo.Environment["TMP"] = WinGetTemp; + } + process.Start(); + + string rawVersion = process.StandardOutput.ReadToEnd().Trim(); + version = usesPingetHelper + ? $"Pinget CLI Version: {rawVersion}" + : $"System WinGet (CLI) Version: {rawVersion}"; + + if (usesPingetHelper) + version += "\nUsing Pinget CLI helper (JSON parsing)"; + else if (usesCliHelper) + version += "\nUsing WinGet CLI helper (CLI parsing)"; + else + { + version += "\nUsing Native WinGet helper (COM Api)"; + + if (WinGetHelper.Instance is NativeWinGetHelper nativeHelper) + { + version += $"\nActivation mode: {nativeHelper.ActivationMode}"; + version += $"\nActivation source: {nativeHelper.ActivationSource}"; + } + } + + string error = process.StandardError.ReadToEnd(); + if (error != "") + Logger.Error("WinGet STDERR not empty: " + error); + } + + protected override void _performExtraLoadingSteps() + { + TryRepairTempFolderPermissions(); + } + + private void ReRegisterCOMServer() + { + WinGetHelper.Instance = new NativeWinGetHelper(this); + NativePackageHandler.Clear(); + } + + public override void AttemptFastRepair() + { + try + { + TryRepairTempFolderPermissions(); + if (WinGetHelper.Instance is NativeWinGetHelper) + { + if ( + WinGetHelper.Instance is NativeWinGetHelper nativeHelper + && nativeHelper.HasActiveLocalPackageQuery + ) + { + Logger.Warn( + "WinGet local package enumeration is still running; skipping COM reconnection so the retry can attach to the in-flight task." + ); + return; + } + + Logger.ImportantInfo("Attempting to reconnect to WinGet COM Server..."); + ReRegisterCOMServer(); + NO_PACKAGES_HAVE_BEEN_LOADED = false; + } + else + { + Logger.Warn( + "Attempted to reconnect to COM Server but the active backend is not native WinGet." + ); + } + } + catch (Exception ex) + { + Logger.Error("An error ocurred while attempting to reconnect to COM Server"); + Logger.Error(ex); + } + } + + private static void TryRepairTempFolderPermissions() + { + // if (Settings.Get(Settings.K.DisableNewWinGetTroubleshooter)) return; + + try + { + string tempPath = Path.GetTempPath(); + string winGetTempPath = Path.Combine(tempPath, "WinGet"); + + if (!Directory.Exists(winGetTempPath)) + { + Logger.Warn("WinGet temp folder does not exist, creating it..."); + Directory.CreateDirectory(winGetTempPath); + } + + var directoryInfo = new DirectoryInfo(winGetTempPath); + var accessControl = directoryInfo.GetAccessControl(); + var rules = accessControl.GetAccessRules(true, true, typeof(NTAccount)); + + bool userHasAccess = false; + string currentUser = WindowsIdentity.GetCurrent().Name; + + foreach (FileSystemAccessRule rule in rules) + { + if ( + rule.IdentityReference.Value.Equals( + currentUser, + StringComparison.CurrentCultureIgnoreCase + ) + ) + { + userHasAccess = true; + break; + } + } + + if (!userHasAccess) + { + Logger.Warn( + "WinGet temp folder does not have correct permissions set, adding the current user..." + ); + var rule = new FileSystemAccessRule( + currentUser, + FileSystemRights.FullControl, + InheritanceFlags.ContainerInherit | InheritanceFlags.ObjectInherit, + PropagationFlags.None, + AccessControlType.Allow + ); + + accessControl.AddAccessRule(rule); + directoryInfo.SetAccessControl(accessControl); + } + } + catch (Exception ex) + { + Logger.Error( + "An error occurred while attempting to properly configure WinGet's temp folder permissions." + ); + Logger.Error(ex); + } + } + + public override void RefreshPackageIndexes() + { + using var _cliLock = AcquireCliLock(); + using Process p = new() + { + StartInfo = new ProcessStartInfo + { + FileName = Status.ExecutablePath, + Arguments = + Status.ExecutableCallArgs + + " source update" + + (SelectedCliToolKind == WinGetCliToolKind.SystemWinGet + ? " --disable-interactivity " + : " ") + + GetCliToolProxyArgument(), + UseShellExecute = false, + RedirectStandardOutput = true, + RedirectStandardError = true, + RedirectStandardInput = true, + CreateNoWindow = true, + StandardOutputEncoding = Encoding.UTF8, + }, + }; + + IProcessTaskLogger logger = TaskLogger.CreateNew(LoggableTaskType.RefreshIndexes, p); + + if (CoreTools.IsAdministrator()) + { + string WinGetTemp = Path.Join(Path.GetTempPath(), "UniGetUI", "ElevatedWinGetTemp"); + logger.AddToStdErr( + $"[WARN] Redirecting %TEMP% folder to {WinGetTemp}, since UniGetUI was run as admin" + ); + p.StartInfo.Environment["TEMP"] = WinGetTemp; + p.StartInfo.Environment["TMP"] = WinGetTemp; + } + + p.Start(); + logger.AddToStdOut(p.StandardOutput.ReadToEnd()); + logger.AddToStdErr(p.StandardError.ReadToEnd()); + logger.Close(p.ExitCode); + p.WaitForExit(); + p.Close(); + } + + private string GetCliToolProxyArgument() + { + return SelectedCliToolKind == WinGetCliToolKind.SystemWinGet + ? GetProxyArgument() + : ""; + } + } + + public class LocalWinGetSource : ManagerSource + { + public enum Type_t + { + LocalPC, + MicrosftStore, + Steam, + GOG, + Android, + Ubisoft, + } + + public readonly Type_t Type; + private readonly string name; + private readonly IconType __icon_id; + public override IconType IconId + { + get => __icon_id; + } + + public LocalWinGetSource(WinGet manager, string name, IconType iconId, Type_t type) + : base( + manager, + name, + new Uri("https://microsoft.com/local-pc-source"), + isVirtualManager: true + ) + { + Type = type; + this.name = name; + __icon_id = iconId; + AsString = Name; + AsString_DisplayName = Name; + } + } +} diff --git a/src/UniGetUI.PackageEngine.Operations/AbstractOperation.cs b/src/UniGetUI.PackageEngine.Operations/AbstractOperation.cs new file mode 100644 index 0000000..233d17a --- /dev/null +++ b/src/UniGetUI.PackageEngine.Operations/AbstractOperation.cs @@ -0,0 +1,748 @@ +using UniGetUI.Core.Logging; +using UniGetUI.Core.SettingsEngine; +using UniGetUI.Core.Tools; +using UniGetUI.PackageEngine.Enums; + +namespace UniGetUI.PackageOperations; + +public abstract partial class AbstractOperation : IDisposable +{ + public readonly OperationMetadata Metadata = new(); + + public event EventHandler? StatusChanged; + public event EventHandler? CancelRequested; + public event EventHandler<(string, LineType)>? LogLineAdded; + public event EventHandler? OperationStarting; + public event EventHandler? OperationFinished; + public event EventHandler? Enqueued; + public event EventHandler? OperationSucceeded; + public event EventHandler? OperationFailed; + public event EventHandler? BadgesChanged; + + public bool Started { get; private set; } + protected bool QUEUE_ENABLED; + protected bool FORCE_HOLD_QUEUE; + private bool IsInnerOperation; + private readonly object CancellationLock = new(); + private CancellationTokenSource? RunCancellationSource; + private AbstractOperation? ActiveInnerOperation; + private Task? ActiveRunTask; + private TaskCompletionSource? ScheduledRetryCompletionSource; + private bool ActiveRunIsStarting; + private volatile bool IsExecutingOperation; + private bool Disposed; + + private readonly List<(string, LineType)> LogList = []; + private OperationStatus _status = OperationStatus.InQueue; + public OperationStatus Status + { + get => _status; + set + { + _status = value; + StatusChanged?.Invoke(this, value); + } + } + + public void ApplyCapabilities(bool admin, bool interactive, bool skiphash, string? scope) + { + BadgesChanged?.Invoke(this, new BadgeCollection(admin, interactive, skiphash, scope)); + } + + private readonly IReadOnlyList PreOperations = []; + private readonly IReadOnlyList PostOperations = []; + + public AbstractOperation( + bool queue_enabled, + IReadOnlyList? preOps = null, + IReadOnlyList? postOps = null + ) + { + QUEUE_ENABLED = queue_enabled; + if (preOps is not null) + PreOperations = preOps; + if (postOps is not null) + PostOperations = postOps; + + Status = OperationStatus.InQueue; + Line("Please wait...", LineType.ProgressIndicator); + + if (int.TryParse(Settings.GetValue(Settings.K.ParallelOperationCount), out int _maxPps)) + { + MAX_OPERATIONS = _maxPps; + Logger.Debug($"Parallel operation limit set to {MAX_OPERATIONS}"); + } + else + { + MAX_OPERATIONS = 1; + Logger.Debug("Parallel operation limit not set, defaulting to 1"); + } + } + + public void Cancel() + { + AbstractOperation? activeInnerOperation; + bool wasRunning; + bool hasActiveWork; + lock (CancellationLock) + { + if ( + _status + is OperationStatus.Canceled + or OperationStatus.Failed + or OperationStatus.Succeeded + && !ActiveRunIsStarting + ) + return; + + wasRunning = _status is OperationStatus.Running; + hasActiveWork = IsExecutingOperation; + RunCancellationSource?.Cancel(); + activeInnerOperation = ActiveInnerOperation; + } + + Status = OperationStatus.Canceled; + activeInnerOperation?.Cancel(); + + if (wasRunning) + CancelRequested?.Invoke(this, EventArgs.Empty); + + // A queued operation has no active work to clean up. A running operation stays on the + // queue until MainThread has awaited its task and completed its cleanup. + if (!hasActiveWork) + { + while (OperationQueue.Remove(this)) + ; + } + } + + protected CancellationToken CancellationToken + { + get + { + lock (CancellationLock) + return RunCancellationSource?.Token ?? global::System.Threading.CancellationToken.None; + } + } + + private bool TrySetActiveInnerOperation(AbstractOperation operation) + { + bool cancellationRequested; + lock (CancellationLock) + { + cancellationRequested = + RunCancellationSource?.IsCancellationRequested is true + || Status is OperationStatus.Canceled; + if (!cancellationRequested) + ActiveInnerOperation = operation; + } + + if (cancellationRequested) + operation.Cancel(); + + return !cancellationRequested; + } + + private void ClearActiveInnerOperation(AbstractOperation operation) + { + lock (CancellationLock) + if (ReferenceEquals(ActiveInnerOperation, operation)) + ActiveInnerOperation = null; + } + + private void EndRunCancellation(CancellationTokenSource cancellationSource) + { + lock (CancellationLock) + { + if (!ReferenceEquals(RunCancellationSource, cancellationSource)) + return; + RunCancellationSource = null; + ActiveRunIsStarting = false; + } + cancellationSource.Dispose(); + } + + protected void Line(string line, LineType type) + { + // LogList stays raw: it is the source of truth for result parsing. Only display redacts. + if (type != LineType.ProgressIndicator) + LogList.Add((line, type)); + LogLineAdded?.Invoke(this, (Logger.Redact(line), type)); + } + + protected IReadOnlyList<(string, LineType)> GetRawOutput() => LogList; + + public IReadOnlyList<(string, LineType)> GetOutput() + { + if (!Logger.RedactUsername) + return LogList; + return LogList.Select(l => (Logger.Redact(l.Item1), l.Item2)).ToList(); + } + + public Task MainThread() + { + TaskCompletionSource completionSource; + CancellationTokenSource cancellationSource; + lock (CancellationLock) + { + ObjectDisposedException.ThrowIf(Disposed, this); + + if (ActiveRunTask is { IsCompleted: false }) + return ActiveRunTask; + + if (ScheduledRetryCompletionSource is not null) + return ScheduledRetryCompletionSource.Task; + + completionSource = new(TaskCreationOptions.RunContinuationsAsynchronously); + cancellationSource = new(); + ActiveRunTask = completionSource.Task; + RunCancellationSource = cancellationSource; + ActiveRunIsStarting = true; + } + + _ = ExecuteRunAsync(completionSource, cancellationSource); + return completionSource.Task; + } + + private async Task ExecuteRunAsync( + TaskCompletionSource completionSource, + CancellationTokenSource cancellationSource + ) + { + try + { + await MainThreadCore(cancellationSource).ConfigureAwait(false); + completionSource.SetResult(); + } + catch (Exception ex) + { + completionSource.SetException(ex); + } + } + + private async Task MainThreadCore(CancellationTokenSource runCancellation) + { + try + { + if (Metadata.Status == "") + throw new InvalidDataException("Metadata.Status was not set!"); + if (Metadata.Title == "") + throw new InvalidDataException("Metadata.Title was not set!"); + if (Metadata.OperationInformation == "") + throw new InvalidDataException("Metadata.OperationInformation was not set!"); + if (Metadata.SuccessTitle == "") + throw new InvalidDataException("Metadata.SuccessTitle was not set!"); + if (Metadata.SuccessMessage == "") + throw new InvalidDataException("Metadata.SuccessMessage was not set!"); + if (Metadata.FailureTitle == "") + throw new InvalidDataException("Metadata.FailureTitle was not set!"); + if (Metadata.FailureMessage == "") + throw new InvalidDataException("Metadata.FailureMessage was not set!"); + + Started = true; + + if (OperationQueue.Contains(this)) + throw new InvalidOperationException("This operation was already on the queue"); + + if (runCancellation.IsCancellationRequested) + { + MarkRunAsStarted(runCancellation); + CompleteCanceledRun(); + return; + } + + Status = OperationStatus.InQueue; + MarkRunAsStarted(runCancellation); + if (runCancellation.IsCancellationRequested) + { + CompleteCanceledRun(); + return; + } + + Line(Metadata.OperationInformation, LineType.VerboseDetails); + Line(Metadata.Status, LineType.ProgressIndicator); + + Enqueued?.Invoke(this, EventArgs.Empty); + if (runCancellation.IsCancellationRequested) + { + CompleteCanceledRun(); + return; + } + + if (QUEUE_ENABLED && !IsInnerOperation) + { + // QUEUE HANDLER + SKIP_QUEUE = false; + OperationQueue.Add(this); + if (runCancellation.IsCancellationRequested) + { + while (OperationQueue.Remove(this)) + ; + CompleteCanceledRun(); + return; + } + + int lastPos = -2; + + while ( + FORCE_HOLD_QUEUE + || (OperationQueue.IndexOf(this) >= MAX_OPERATIONS && !SKIP_QUEUE) + ) + { + int pos = OperationQueue.IndexOf(this) - MAX_OPERATIONS + 1; + + if (pos == -1) + return; + // In this case, operation was canceled; + + if (pos != lastPos) + { + lastPos = pos; + Line( + CoreTools.Translate("Operation on queue (position {0})...", pos), + LineType.ProgressIndicator + ); + } + + await Task.Delay(100); + } + } + // END QUEUE HANDLER + + IsExecutingOperation = true; + OperationVeredict result; + try + { + result = await _runOperation(); + } + finally + { + IsExecutingOperation = false; + } + while (OperationQueue.Remove(this)) + ; + + if (result == OperationVeredict.Success) + { + Status = OperationStatus.Succeeded; + OperationSucceeded?.Invoke(this, EventArgs.Empty); + OperationFinished?.Invoke(this, EventArgs.Empty); + Line(Metadata.SuccessMessage, LineType.Information); + } + else if (result == OperationVeredict.Failure) + { + Status = OperationStatus.Failed; + OperationFailed?.Invoke(this, EventArgs.Empty); + OperationFinished?.Invoke(this, EventArgs.Empty); + Line(Metadata.FailureMessage, LineType.Error); + Line( + Metadata.FailureMessage + + " - " + + CoreTools.Translate("Click here for more details"), + LineType.ProgressIndicator + ); + } + else if (result == OperationVeredict.Canceled) + { + Status = OperationStatus.Canceled; + OperationFinished?.Invoke(this, EventArgs.Empty); + Line(CoreTools.Translate("Operation canceled by user"), LineType.Error); + } + else + { + throw new InvalidCastException(); + } + } + catch (Exception ex) + { + Line("An internal error occurred:", LineType.Error); + foreach (var line in ex.ToString().Split("\n")) + { + Line(line, LineType.Error); + } + + while (OperationQueue.Remove(this)) + ; + + MarkRunAsStarted(runCancellation); + Status = OperationStatus.Failed; + try + { + OperationFinished?.Invoke(this, EventArgs.Empty); + OperationFailed?.Invoke(this, EventArgs.Empty); + } + catch (Exception e2) + { + Line( + "An internal error occurred while handling an internal error:", + LineType.Error + ); + foreach (var line in e2.ToString().Split("\n")) + { + Line(line, LineType.Error); + } + } + + Line(Metadata.FailureMessage, LineType.Error); + Line( + Metadata.FailureMessage + + " - " + + CoreTools.Translate("Click here for more details"), + LineType.ProgressIndicator + ); + } + finally + { + try + { + OnRunCompleted(); + } + finally + { + EndRunCancellation(runCancellation); + if (OperationQueue.Count == 0) + QueueDrained?.Invoke(null, EventArgs.Empty); + } + } + } + + private void CompleteCanceledRun() + { + Status = OperationStatus.Canceled; + OperationFinished?.Invoke(this, EventArgs.Empty); + Line(CoreTools.Translate("Operation canceled by user"), LineType.Error); + } + + private void MarkRunAsStarted(CancellationTokenSource cancellationSource) + { + lock (CancellationLock) + { + if (ReferenceEquals(RunCancellationSource, cancellationSource)) + ActiveRunIsStarting = false; + } + } + + private async Task _runOperation() + { + OperationVeredict result; + + // Process preoperations + int i = 0, + count = PreOperations.Count; + if (count > 0) + Line("", LineType.VerboseDetails); + foreach (var preReq in PreOperations) + { + if (Status is OperationStatus.Canceled || CancellationToken.IsCancellationRequested) + return OperationVeredict.Canceled; + + i++; + Line( + CoreTools.Translate("Running PreOperation ({0}/{1})...", i, count), + LineType.Information + ); + preReq.Operation.LogLineAdded += (_, line) => Line(line.Item1, line.Item2); + if (!TrySetActiveInnerOperation(preReq.Operation)) + return OperationVeredict.Canceled; + try + { + await preReq.Operation.MainThread(); + } + finally + { + ClearActiveInnerOperation(preReq.Operation); + } + if (Status is OperationStatus.Canceled || CancellationToken.IsCancellationRequested) + return OperationVeredict.Canceled; + if (preReq.Operation.Status is not OperationStatus.Succeeded && preReq.MustSucceed) + { + Line( + CoreTools.Translate( + "PreOperation {0} out of {1} failed, and was tagged as necessary. Aborting...", + i, + count + ), + LineType.Error + ); + return OperationVeredict.Failure; + } + Line( + CoreTools.Translate( + "PreOperation {0} out of {1} finished with result {2}", + i, + count, + preReq.Operation.Status + ), + LineType.Information + ); + Line("--------------------------------", LineType.Information); + Line("", LineType.VerboseDetails); + } + + // BEGIN ACTUAL OPERATION + Line(CoreTools.Translate("Starting operation..."), LineType.Information); + if (Status is OperationStatus.InQueue) + Status = OperationStatus.Running; + + do + { + if (Status is OperationStatus.Canceled || CancellationToken.IsCancellationRequested) + { + result = OperationVeredict.Canceled; + break; + } + + OperationStarting?.Invoke(this, EventArgs.Empty); + + try + { + Task op = PerformOperation(); + result = await op.ConfigureAwait(false); + if (Status is OperationStatus.Canceled || CancellationToken.IsCancellationRequested) + result = OperationVeredict.Canceled; + } + catch (Exception e) + { + result = CancellationToken.IsCancellationRequested + ? OperationVeredict.Canceled + : OperationVeredict.Failure; + Logger.Error(e); + foreach (string l in e.ToString().Split("\n")) + { + Line(l, LineType.Error); + } + } + } while (result is OperationVeredict.AutoRetry); + + if (result is not OperationVeredict.Success) + return result; + + // Process postoperations + i = 0; + count = PostOperations.Count; + foreach (var postReq in PostOperations) + { + i++; + Line("--------------------------------", LineType.Information); + Line("", LineType.VerboseDetails); + Line( + CoreTools.Translate("Running PostOperation ({0}/{1})...", i, count), + LineType.Information + ); + if (Status is OperationStatus.Canceled || CancellationToken.IsCancellationRequested) + return OperationVeredict.Canceled; + + postReq.Operation.LogLineAdded += (_, line) => Line(line.Item1, line.Item2); + if (!TrySetActiveInnerOperation(postReq.Operation)) + return OperationVeredict.Canceled; + try + { + await postReq.Operation.MainThread(); + } + finally + { + ClearActiveInnerOperation(postReq.Operation); + } + if (Status is OperationStatus.Canceled || CancellationToken.IsCancellationRequested) + return OperationVeredict.Canceled; + if (postReq.Operation.Status is not OperationStatus.Succeeded && postReq.MustSucceed) + { + Line( + CoreTools.Translate( + "PostOperation {0} out of {1} failed, and was tagged as necessary. Aborting...", + i, + count + ), + LineType.Error + ); + return OperationVeredict.Failure; + } + Line( + CoreTools.Translate( + "PostOperation {0} out of {1} finished with result {2}", + i, + count, + postReq.Operation.Status + ), + LineType.Information + ); + } + + return result; + } + + private bool SKIP_QUEUE; + + public void SkipQueue() + { + if (Status != OperationStatus.InQueue) + return; + while (OperationQueue.Remove(this)) + ; + SKIP_QUEUE = true; + } + + public void RunNext() + { + if (Status != OperationStatus.InQueue) + return; + if (!OperationQueue.Contains(this)) + return; + + FORCE_HOLD_QUEUE = true; + while (OperationQueue.Remove(this)) + ; + OperationQueue.Insert(Math.Min(MAX_OPERATIONS, OperationQueue.Count), this); + FORCE_HOLD_QUEUE = false; + } + + public void BackOfTheQueue() + { + if (Status != OperationStatus.InQueue) + return; + if (!OperationQueue.Contains(this)) + return; + + FORCE_HOLD_QUEUE = true; + while (OperationQueue.Remove(this)) + ; + OperationQueue.Add(this); + FORCE_HOLD_QUEUE = false; + } + + public void Retry(string retryMode) + { + if (retryMode is RetryMode.NoRetry) + throw new InvalidOperationException("We weren't supposed to reach this, weren't we?"); + + Task? previousRun = null; + TaskCompletionSource? scheduledRetry = null; + bool applyImmediately = false; + lock (CancellationLock) + { + if (Disposed) + return; + + if (Status is OperationStatus.Running) + return; + + if (Status is OperationStatus.InQueue) + { + applyImmediately = true; + } + else + { + if (ScheduledRetryCompletionSource is not null) + return; + + scheduledRetry = new(TaskCreationOptions.RunContinuationsAsynchronously); + ScheduledRetryCompletionSource = scheduledRetry; + previousRun = ActiveRunTask ?? Task.CompletedTask; + } + } + + if (applyImmediately) + { + ApplyRetryActionAndLog(retryMode); + return; + } + + _ = RetryAfterRunAsync(previousRun!, scheduledRetry!, retryMode); + } + + private async Task RetryAfterRunAsync( + Task previousRun, + TaskCompletionSource scheduledRetry, + string retryMode + ) + { + CancellationTokenSource? cancellationSource = null; + try + { + await previousRun.ConfigureAwait(false); + + lock (CancellationLock) + { + if (!ReferenceEquals(ScheduledRetryCompletionSource, scheduledRetry)) + return; + + if (Disposed) + { + ScheduledRetryCompletionSource = null; + scheduledRetry.TrySetCanceled(); + return; + } + + cancellationSource = new(); + RunCancellationSource = cancellationSource; + ActiveRunTask = scheduledRetry.Task; + ScheduledRetryCompletionSource = null; + ActiveRunIsStarting = true; + } + + ApplyRetryActionAndLog(retryMode); + await ExecuteRunAsync(scheduledRetry, cancellationSource).ConfigureAwait(false); + } + catch (Exception ex) + { + if (cancellationSource is not null) + EndRunCancellation(cancellationSource); + + lock (CancellationLock) + { + if (ReferenceEquals(ScheduledRetryCompletionSource, scheduledRetry)) + ScheduledRetryCompletionSource = null; + if (ReferenceEquals(ActiveRunTask, scheduledRetry.Task)) + ActiveRunTask = null; + } + scheduledRetry.TrySetException(ex); + Logger.Error(ex); + } + } + + private void ApplyRetryActionAndLog(string retryMode) + { + ApplyRetryAction(retryMode); + Line($"", LineType.VerboseDetails); + Line($"-----------------------", LineType.VerboseDetails); + Line($"Retrying operation with RetryMode={retryMode}", LineType.VerboseDetails); + Line($"", LineType.VerboseDetails); + } + + protected abstract void ApplyRetryAction(string retryMode); + protected abstract Task PerformOperation(); + public abstract Task GetOperationIcon(); + + protected virtual void OnRunCompleted() { } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + protected virtual void Dispose(bool disposing) + { + if (!disposing) + return; + + TaskCompletionSource? scheduledRetry; + lock (CancellationLock) + { + if (Disposed) + return; + + Disposed = true; + scheduledRetry = ScheduledRetryCompletionSource; + ScheduledRetryCompletionSource = null; + } + + scheduledRetry?.TrySetCanceled(); + Cancel(); + if (!IsExecutingOperation) + { + while (OperationQueue.Remove(this)) + ; + } + } +} diff --git a/src/UniGetUI.PackageEngine.Operations/AbstractOperation_Auxiliaries.cs b/src/UniGetUI.PackageEngine.Operations/AbstractOperation_Auxiliaries.cs new file mode 100644 index 0000000..4ac19cc --- /dev/null +++ b/src/UniGetUI.PackageEngine.Operations/AbstractOperation_Auxiliaries.cs @@ -0,0 +1,104 @@ +namespace UniGetUI.PackageOperations; + +public abstract partial class AbstractOperation +{ + public static readonly List OperationQueue = []; + public static int MAX_OPERATIONS; + + /// + /// Raised on the thread that completed the last operation in . + /// Subscribers should not do heavy work here — fire-and-forget async is fine. + /// + public static event EventHandler? QueueDrained; + + public static class RetryMode + { + public const string NoRetry = ""; + public const string Retry = "Retry"; + public const string Retry_AsAdmin = "RetryAsAdmin"; + public const string Retry_Interactive = "RetryInteractive"; + public const string Retry_SkipIntegrity = "RetryNoHashCheck"; + } + + public class OperationMetadata + { + /// + /// Installation of X + /// + public string Title = ""; + + /// + /// X is being installed/upated/removed + /// + public string Status = ""; + + /// + /// X was installed + /// + public string SuccessTitle = ""; + + /// + /// X has been installed successfully + /// + public string SuccessMessage = ""; + + /// + /// X could not be installed. + /// + public string FailureTitle = ""; + + /// + /// X Could not be installed + /// + public string FailureMessage = ""; + + /// + /// Starting operation X with options Y + /// + public string OperationInformation = ""; + + public readonly string Identifier; + + public OperationMetadata() + { + Identifier = new Random().NextInt64(1000000, 9999999).ToString(); + } + } + + public class BadgeCollection + { + public readonly bool AsAdministrator; + public readonly bool Interactive; + public readonly bool SkipHashCheck; + public readonly string? Scope; + + public BadgeCollection(bool admin, bool interactive, bool skiphash, string? scope) + { + AsAdministrator = admin; + Interactive = interactive; + SkipHashCheck = skiphash; + Scope = scope; + } + } + + public enum LineType + { + VerboseDetails, + ProgressIndicator, + Information, + Error, + } + + public struct InnerOperation + { + public readonly AbstractOperation Operation; + public readonly bool MustSucceed; + + public InnerOperation(AbstractOperation op, bool mustSucceed) + { + Operation = op; + MustSucceed = mustSucceed; + op.IsInnerOperation = true; + } + } +} diff --git a/src/UniGetUI.PackageEngine.Operations/AbstractProcessOperation.cs b/src/UniGetUI.PackageEngine.Operations/AbstractProcessOperation.cs new file mode 100644 index 0000000..a86613d --- /dev/null +++ b/src/UniGetUI.PackageEngine.Operations/AbstractProcessOperation.cs @@ -0,0 +1,254 @@ +using System.Diagnostics; +using System.Text; +using UniGetUI.Core.Logging; +using UniGetUI.Core.SettingsEngine; +using UniGetUI.Core.Tools; +using UniGetUI.PackageEngine.Enums; + +namespace UniGetUI.PackageOperations; + +public abstract class AbstractProcessOperation : AbstractOperation +{ + protected Process process { get; private set; } + private bool ProcessKilled; + + protected AbstractProcessOperation( + bool queue_enabled, + IReadOnlyList? preOps = null, + IReadOnlyList? postOps = null + ) + : base(queue_enabled, preOps, postOps) + { + process = new(); + CancelRequested += (_, _) => StopProcess(); + OperationStarting += (_, _) => + { + DisposeProcess(); + ProcessKilled = false; + process = new(); + process.StartInfo.UseShellExecute = false; + process.StartInfo.RedirectStandardOutput = true; + process.StartInfo.RedirectStandardInput = true; + process.StartInfo.RedirectStandardError = true; + process.StartInfo.CreateNoWindow = true; + process.StartInfo.StandardOutputEncoding = Encoding.UTF8; + process.StartInfo.StandardErrorEncoding = Encoding.UTF8; + process.StartInfo.StandardInputEncoding = Encoding.UTF8; + process.StartInfo.WorkingDirectory = Environment.GetFolderPath( + Environment.SpecialFolder.UserProfile + ); + process.StartInfo.FileName = "lol"; + process.StartInfo.Arguments = "lol"; + process.ErrorDataReceived += (_, e) => + { + if (e.Data is null) + return; + string line = e.Data.Trim(); + var lineType = LineType.Error; + if (line.Length < 6 || line.Contains("Waiting for another install...")) + lineType = LineType.ProgressIndicator; + + Line(line, lineType); + }; + PrepareProcessStartInfo(); + }; + } + + private bool _requiresUACCache; + + protected void RequestCachingOfUACPrompt() + { + _requiresUACCache = true; + } + + protected void RedirectWinGetTempFolder() + { + string WinGetTemp = Path.Join(Path.GetTempPath(), "UniGetUI", "ElevatedWinGetTemp"); + process.StartInfo.Environment["TEMP"] = WinGetTemp; + process.StartInfo.Environment["TMP"] = WinGetTemp; + } + + protected override async Task PerformOperation() + { + if (process.StartInfo.UseShellExecute) + throw new InvalidOperationException("UseShellExecute must be set to false"); + if (!process.StartInfo.RedirectStandardOutput) + throw new InvalidOperationException("RedirectStandardOutput must be set to true"); + if (!process.StartInfo.RedirectStandardInput) + throw new InvalidOperationException("RedirectStandardInput must be set to true"); + if (!process.StartInfo.RedirectStandardError) + throw new InvalidOperationException("RedirectStandardError must be set to true"); + if (process.StartInfo.FileName == "lol") + throw new InvalidOperationException("StartInfo.FileName has not been set"); + if (process.StartInfo.Arguments == "lol") + throw new InvalidOperationException("StartInfo.Arguments has not been set"); + + Line("Executing process with StartInfo:", LineType.VerboseDetails); + Line($" - FileName: \"{process.StartInfo.FileName.Trim()}\"", LineType.VerboseDetails); + Line($" - Arguments: \"{process.StartInfo.Arguments.Trim()}\"", LineType.VerboseDetails); + Line($"Start Time: \"{DateTime.Now}\"", LineType.VerboseDetails); + + if (string.IsNullOrWhiteSpace(process.StartInfo.FileName)) + { + Line( + CoreTools.Translate( + "This operation requires administrator privileges, but the elevation tool could not be found. The operation cannot continue." + ), + LineType.Error + ); + return OperationVeredict.Failure; + } + + if (_requiresUACCache) + { + _requiresUACCache = false; + await CoreTools.CacheUACForCurrentProcess(); + } + + CancellationToken.ThrowIfCancellationRequested(); + process.Start(); + if (CancellationToken.IsCancellationRequested) + { + StopProcess(); + await process.WaitForExitAsync().ConfigureAwait(false); + return OperationVeredict.Canceled; + } + + if (!Settings.Get(Settings.K.DisableNewProcessLineHandler)) + { + await process.StandardInput.WriteLineAsync("\r\n\r\n\r\n\r\n".AsMemory(), CancellationToken); + process.StandardInput.Close(); + } + try + { + process.BeginErrorReadLine(); + } + catch (InvalidOperationException ex) + { + Logger.Error(ex); + } + + StringBuilder currentLine = new(); + char[] buffer = new char[1]; + string? lastStringBeforeLF = null; + try + { + while ((await process.StandardOutput.ReadAsync(buffer.AsMemory(), CancellationToken)) > 0) + { + char c = buffer[0]; + if (c == 10) + { + if (currentLine.Length == 0) + { + if (lastStringBeforeLF is not null) + { + Line(lastStringBeforeLF, LineType.Information); + lastStringBeforeLF = null; + } + continue; + } + + string line = currentLine.ToString(); + Line(line, LineType.Information); + currentLine.Clear(); + } + else if (c == 13) + { + if (currentLine.Length == 0) + continue; + lastStringBeforeLF = currentLine.ToString(); + Line(lastStringBeforeLF, LineType.ProgressIndicator); + currentLine.Clear(); + } + else + { + currentLine.Append(c); + } + } + } + catch (OperationCanceledException) when (CancellationToken.IsCancellationRequested) + { + await process.WaitForExitAsync().ConfigureAwait(false); + return OperationVeredict.Canceled; + } + + try + { + await process.WaitForExitAsync(CancellationToken).ConfigureAwait(false); + } + catch (OperationCanceledException) when (CancellationToken.IsCancellationRequested) + { + await process.WaitForExitAsync().ConfigureAwait(false); + return OperationVeredict.Canceled; + } + + Line($"End Time: \"{DateTime.Now}\"", LineType.VerboseDetails); + Line( + $"Process return value: \"{process.ExitCode}\" (0x{process.ExitCode:X})", + LineType.VerboseDetails + ); + + if (ProcessKilled || CancellationToken.IsCancellationRequested) + return OperationVeredict.Canceled; + + List output = new(); + foreach (var line in GetRawOutput()) + { + if (line.Item2 is LineType.VerboseDetails && line.Item1 == "-----------------------") + output.Clear(); + if (line.Item2 is LineType.Error or LineType.Information) + output.Add(line.Item1); + } + + return await GetProcessVeredict(process.ExitCode, output); + } + + protected override void OnRunCompleted() + { + DisposeProcess(); + } + + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + if (disposing) + DisposeProcess(); + } + + private void StopProcess() + { + try + { + if (!process.HasExited) + { + process.Kill(entireProcessTree: true); + ProcessKilled = true; + } + } + catch (InvalidOperationException) { } + } + + private void DisposeProcess() + { + try + { + if (!process.HasExited) + { + process.Kill(entireProcessTree: true); + ProcessKilled = true; + process.WaitForExit(); + } + } + catch (InvalidOperationException) { } + finally + { + process.Dispose(); + } + } + + protected abstract Task GetProcessVeredict( + int ReturnCode, + List Output + ); + protected abstract void PrepareProcessStartInfo(); +} diff --git a/src/UniGetUI.PackageEngine.Operations/DownloadOperation.cs b/src/UniGetUI.PackageEngine.Operations/DownloadOperation.cs new file mode 100644 index 0000000..5d77344 --- /dev/null +++ b/src/UniGetUI.PackageEngine.Operations/DownloadOperation.cs @@ -0,0 +1,158 @@ +using UniGetUI.Core.Tools; +using UniGetUI.PackageEngine.Enums; +using UniGetUI.PackageEngine.Interfaces; +using UniGetUI.PackageOperations; + +namespace UniGetUI.PackageEngine.Operations; + +public class DownloadOperation : AbstractOperation +{ + private readonly IPackage _package; + public IPackage Package => _package; + private string downloadLocation; + public string DownloadLocation => downloadLocation; + + public DownloadOperation(IPackage package, string downloadPath) + : base(true, null) + { + downloadLocation = downloadPath; + _package = package; + + Metadata.OperationInformation = + "Downloading installer for Package=" + _package.Id + " with Manager=" + _package.Manager.Name; + Metadata.Title = CoreTools.Translate( + "{package} installer download", + new Dictionary { { "package", _package.Name } } + ); + Metadata.Status = CoreTools.Translate("{0} installer is being downloaded", _package.Name); + Metadata.SuccessTitle = CoreTools.Translate("Download succeeded"); + Metadata.SuccessMessage = CoreTools.Translate( + "{package} installer was downloaded successfully", + new Dictionary { { "package", _package.Name } } + ); + Metadata.FailureTitle = CoreTools.Translate( + "Download failed", + new Dictionary { { "package", _package.Name } } + ); + Metadata.FailureMessage = CoreTools.Translate( + "{package} installer could not be downloaded", + new Dictionary { { "package", _package.Name } } + ); + } + + public override Task GetOperationIcon() + { + return Task.Run(_package.GetIconUrl); + } + + protected override void ApplyRetryAction(string retryMode) { } + + protected override async Task PerformOperation() + { + bool downloadFileCreated = false; + try + { + CancellationToken.ThrowIfCancellationRequested(); + Line( + $"Fetching download url for package {_package.Name} from {_package.Manager.DisplayName}...", + LineType.Information + ); + await _package.Details.Load(); + CancellationToken.ThrowIfCancellationRequested(); + Uri? downloadUrl = _package.Details.InstallerUrl; + if (downloadUrl is null) + { + Line( + $"UniGetUI was not able to find any installer for this package. " + + "Please check that this package has an applicable installer and try again later", + LineType.Error + ); + return OperationVeredict.Failure; + } + + if (Directory.Exists(downloadLocation)) + { + string? fileName = await _package.GetInstallerFileName(); + CancellationToken.ThrowIfCancellationRequested(); + if (fileName is null) + { + Line( + "An error occurred while retrieving file name, default will be used!", + LineType.Error + ); + fileName = CoreTools.MakeValidFileName(_package.Name); + } + downloadLocation = Path.Join(downloadLocation, fileName); + } + + Line($"Download URL found at {downloadUrl} ", LineType.Information); + using var httpClient = new HttpClient(CoreTools.GenericHttpClientParameters); + using var response = await httpClient.GetAsync( + downloadUrl, + HttpCompletionOption.ResponseHeadersRead, + CancellationToken + ); + response.EnsureSuccessStatusCode(); + + var totalBytes = response.Content.Headers.ContentLength ?? -1L; + var canReportProgress = totalBytes > 0; + await using (var contentStream = await response.Content.ReadAsStreamAsync(CancellationToken)) + await using (var fileStream = new FileStream( + downloadLocation, + FileMode.Create, + FileAccess.Write, + FileShare.None, + 8192, + useAsync: true + )) + { + downloadFileCreated = true; + var buffer = new byte[4 * 1024 * 1024]; + long totalRead = 0; + int oldProgress = -1; + int bytesRead; + while ( + (bytesRead = await contentStream.ReadAsync(buffer.AsMemory(), CancellationToken)) > 0 + ) + { + await fileStream.WriteAsync(buffer.AsMemory(0, bytesRead), CancellationToken); + totalRead += bytesRead; + + if (canReportProgress) + { + var progress = (int)((totalRead * 100L) / totalBytes); + if (progress != oldProgress) + { + oldProgress = progress; + Line( + CoreTools.TextProgressGenerator( + 30, + progress, + $"{CoreTools.FormatAsSize(totalRead)}/{CoreTools.FormatAsSize(totalBytes)}" + ), + LineType.ProgressIndicator + ); + } + } + } + } + + CancellationToken.ThrowIfCancellationRequested(); + Line($"The file was saved to {downloadLocation}", LineType.Information); + return OperationVeredict.Success; + } + catch (OperationCanceledException) when (CancellationToken.IsCancellationRequested) + { + if (downloadFileCreated) + File.Delete(downloadLocation); + Line("User has canceled the operation", LineType.Error); + return OperationVeredict.Canceled; + } + catch (Exception ex) + { + Line($"{ex.GetType()}: {ex.Message}", LineType.Error); + Line($"{ex.StackTrace}", LineType.Error); + return OperationVeredict.Failure; + } + } +} diff --git a/src/UniGetUI.PackageEngine.Operations/KillProcessOperation.cs b/src/UniGetUI.PackageEngine.Operations/KillProcessOperation.cs new file mode 100644 index 0000000..92959f0 --- /dev/null +++ b/src/UniGetUI.PackageEngine.Operations/KillProcessOperation.cs @@ -0,0 +1,88 @@ +using System.Diagnostics; +using UniGetUI.Core.SettingsEngine; +using UniGetUI.Core.Tools; +using UniGetUI.PackageEngine.Enums; + +namespace UniGetUI.PackageOperations; + +public class KillProcessOperation : AbstractOperation +{ + private readonly string ProcessName; + + public KillProcessOperation(string procName) + : base(false) + { + ProcessName = CoreTools.MakeValidFileName(procName); + Metadata.Status = $"Closing process(es) {procName}"; + Metadata.Title = $"Closing process(es) {procName}"; + Metadata.OperationInformation = " "; + Metadata.SuccessTitle = "Done!"; + Metadata.SuccessMessage = "Done!"; + Metadata.FailureTitle = "Failed to close process"; + Metadata.FailureMessage = $"The process(es) {procName} could not be closed"; + } + + protected override void ApplyRetryAction(string retryMode) { } + + protected override async Task PerformOperation() + { + try + { + Line( + $"Attempting to close all processes with name {ProcessName}...", + LineType.Information + ); + foreach (var proc in Process.GetProcessesByName(ProcessName.Replace(".exe", ""))) + { + using (proc) + { + CancellationToken.ThrowIfCancellationRequested(); + if (proc.HasExited) + continue; + Line( + $"Attempting to close process {ProcessName} with pid={proc.Id}...", + LineType.VerboseDetails + ); + proc.CloseMainWindow(); + await Task.WhenAny( + proc.WaitForExitAsync(CancellationToken), + Task.Delay(1000, CancellationToken) + ); + CancellationToken.ThrowIfCancellationRequested(); + if (!proc.HasExited) + { + if (Settings.Get(Settings.K.KillProcessesThatRefuseToDie)) + { + Line( + $"Timeout for process {ProcessName}, attempting to kill...", + LineType.Information + ); + proc.Kill(entireProcessTree: true); + await proc.WaitForExitAsync(CancellationToken); + } + else + { + Line( + $"{ProcessName} with pid={proc.Id} did not exit and will not be killed. You can change this from UniGetUI settings.", + LineType.Error + ); + } + } + } + } + + return OperationVeredict.Success; + } + catch (OperationCanceledException) when (CancellationToken.IsCancellationRequested) + { + return OperationVeredict.Canceled; + } + catch (Exception ex) + { + Line(ex.ToString(), LineType.Error); + return OperationVeredict.Failure; + } + } + + public override Task GetOperationIcon() => Task.FromResult(new Uri("about:blank")); +} diff --git a/src/UniGetUI.PackageEngine.Operations/PackageOperations.cs b/src/UniGetUI.PackageEngine.Operations/PackageOperations.cs new file mode 100644 index 0000000..ae369b1 --- /dev/null +++ b/src/UniGetUI.PackageEngine.Operations/PackageOperations.cs @@ -0,0 +1,536 @@ +using UniGetUI.Core.Classes; +using UniGetUI.Core.Data; +using UniGetUI.Core.Logging; +using UniGetUI.Core.SettingsEngine; +using UniGetUI.Core.Tools; +using UniGetUI.Interface.Enums; +using UniGetUI.PackageEngine.Classes.Packages.Classes; +using UniGetUI.PackageEngine.Enums; +using UniGetUI.PackageEngine.Interfaces; +using UniGetUI.PackageEngine.PackageClasses; +using UniGetUI.PackageEngine.PackageLoader; +using UniGetUI.PackageEngine.Serializable; +using UniGetUI.PackageOperations; +#if WINDOWS +using UniGetUI.PackageEngine.Managers.WingetManager; +#endif + +namespace UniGetUI.PackageEngine.Operations +{ + public abstract class PackageOperation : AbstractProcessOperation + { + protected List DesktopShortcutsBeforeStart = []; + + public readonly IPackage Package; + public readonly InstallOptions Options; + public readonly OperationType Role; + + protected abstract Task HandleSuccess(); + protected abstract Task HandleFailure(); + protected abstract void Initialize(); + + public PackageOperation( + IPackage package, + InstallOptions options, + OperationType role, + bool IgnoreParallelInstalls = false, + AbstractOperation? req = null + ) + : base( + !IgnoreParallelInstalls, + _getPreInstallOps(options, role, req), + _getPostInstallOps(options, role, package) + ) + { + Package = package; + Options = options; + Role = role; + + Initialize(); + + Enqueued += (_, _) => + { + ApplyCapabilities( + RequiresAdminRights(), + Options.InteractiveInstallation, + (Options.SkipHashCheck && Role is not OperationType.Uninstall), + Package.OverridenOptions.Scope ?? Options.InstallationScope + ); + + Package.SetTag(PackageTag.OnQueue); + }; + CancelRequested += (_, _) => Package.SetTag(PackageTag.Default); + OperationSucceeded += (_, _) => HandleSuccess(); + OperationFailed += (_, _) => HandleFailure(); + } + + private bool RequiresAdminRights() => + !Settings.Get(Settings.K.ProhibitElevation) + && (Package.OverridenOptions.RunAsAdministrator is true || Options.RunAsAdministrator); + + protected override void ApplyRetryAction(string retryMode) + { + switch (retryMode) + { + case RetryMode.Retry_AsAdmin: + Options.RunAsAdministrator = true; + break; + case RetryMode.Retry_Interactive: + Options.InteractiveInstallation = true; + break; + case RetryMode.Retry_SkipIntegrity: + Options.SkipHashCheck = true; + break; + case RetryMode.Retry: + break; + default: + throw new InvalidOperationException( + $"Retry mode {retryMode} is not supported in this context" + ); + } + Metadata.OperationInformation = + "Retried package operation for Package=" + + Package.Id + + " with Manager=" + + Package.Manager.Name + + "\nUpdated installation options: " + + Options.ToString() + + "\nOverriden options: " + + Package.OverridenOptions.ToString(); + } + + protected sealed override void PrepareProcessStartInfo() + { + bool IsAdmin = CoreTools.IsAdministrator(); + Package.SetTag(PackageTag.OnQueue); + string operation_args = string.Join( + " ", + Package.Manager.OperationHelper.GetParameters(Package, Options, Role) + ); + string FileName, + Arguments; + + if (RequiresAdminRights() && IsAdmin is false) + { + IsAdmin = true; + if ( + OperatingSystem.IsLinux() + || Settings.Get(Settings.K.DoCacheAdminRights) + || Settings.Get(Settings.K.DoCacheAdminRightsForBatches) + ) + { + RequestCachingOfUACPrompt(); + } + + FileName = CoreData.ElevatorPath; + Arguments = + $"{CoreData.ElevatorArgs} \"{Package.Manager.Status.ExecutablePath}\" {Package.Manager.Status.ExecutableCallArgs} {operation_args}".TrimStart(); + } + else + { + FileName = Package.Manager.Status.ExecutablePath; + Arguments = $"{Package.Manager.Status.ExecutableCallArgs} {operation_args}"; + } + + if (IsAdmin && IsWinGetManager(Package.Manager)) + { + RedirectWinGetTempFolder(); + } + + process.StartInfo.FileName = FileName; + process.StartInfo.Arguments = Arguments; + process.StartInfo.StandardOutputEncoding = Package.Manager.OutputEncoding; + process.StartInfo.StandardErrorEncoding = Package.Manager.OutputEncoding; + + ApplyCapabilities( + IsAdmin, + Options.InteractiveInstallation, + (Options.SkipHashCheck && Role is not OperationType.Uninstall), + Package.OverridenOptions.Scope ?? Options.InstallationScope + ); + } + + protected sealed override Task GetProcessVeredict( + int ReturnCode, + List Output + ) + { + return Task.FromResult( + Package.Manager.OperationHelper.GetResult(Package, Role, Output, ReturnCode) + ); + } + + private static bool IsWinGetManager(IPackageManager manager) + { +#if WINDOWS + return manager is WinGet; +#else + return false; +#endif + } + + protected async Task ResolveInstalledPackageSnapshotAsync( + string fallbackVersion, + bool preferFallbackVersionWhenMissing = false + ) + { + try + { + var installedMatches = await Task.Run(() => + Package + .Manager.GetInstalledPackages() + .Where(candidate => candidate.IsEquivalentTo(Package)) + .ToArray() + ); + + if (installedMatches.Length > 0) + { + if (!string.IsNullOrWhiteSpace(fallbackVersion)) + { + var exactMatch = installedMatches.FirstOrDefault(candidate => + candidate.VersionString.Equals( + fallbackVersion, + StringComparison.OrdinalIgnoreCase + ) + ); + if (exactMatch is not null) + { + return exactMatch; + } + + if (preferFallbackVersionWhenMissing) + { + return CreateSyntheticInstalledPackage(fallbackVersion); + } + } + + return installedMatches + .OrderByDescending(candidate => candidate.NormalizedVersion) + .First(); + } + } + catch (Exception ex) + { + Logger.Warn( + $"Could not resolve the installed snapshot for package {Package.Id}; falling back to synthetic state" + ); + Logger.Warn(ex); + } + + return CreateSyntheticInstalledPackage(fallbackVersion); + } + + private IPackage CreateSyntheticInstalledPackage(string version) + { + return new Package( + Package.Name, + Package.Id, + version, + Package.Source, + Package.Manager, + Package.OverridenOptions + ); + } + + public override Task GetOperationIcon() + { + return TaskRecycler.RunOrAttachAsync(Package.GetIconUrl); + } + + private static IReadOnlyList _getPreInstallOps( + InstallOptions opts, + OperationType role, + AbstractOperation? preReq = null + ) + { + List l = new(); + if (preReq is not null) + l.Add(new(preReq, true)); + + foreach (var process in opts.KillBeforeOperation) + l.Add(new InnerOperation(new KillProcessOperation(process), mustSucceed: false)); + + if (role is OperationType.Install && opts.PreInstallCommand.Any()) + l.Add( + new(new PrePostOperation(opts.PreInstallCommand), opts.AbortOnPreInstallFail) + ); + else if (role is OperationType.Update && opts.PreUpdateCommand.Any()) + l.Add(new(new PrePostOperation(opts.PreUpdateCommand), opts.AbortOnPreUpdateFail)); + else if (role is OperationType.Uninstall && opts.PreUninstallCommand.Any()) + l.Add( + new( + new PrePostOperation(opts.PreUninstallCommand), + opts.AbortOnPreUninstallFail + ) + ); + + return l; + } + + private static IReadOnlyList _getPostInstallOps( + InstallOptions opts, + OperationType role, + IPackage package + ) + { + List l = new(); + + if (role is OperationType.Install && opts.PostInstallCommand.Any()) + l.Add(new(new PrePostOperation(opts.PostInstallCommand), false)); + else if (role is OperationType.Update && opts.PostUpdateCommand.Any()) + l.Add(new(new PrePostOperation(opts.PostUpdateCommand), false)); + else if (role is OperationType.Uninstall && opts.PostUninstallCommand.Any()) + l.Add(new(new PrePostOperation(opts.PostUninstallCommand), false)); + + if (role is OperationType.Update && opts.UninstallPreviousVersionsOnUpdate) + { + var matches = InstalledPackagesLoader.Instance.Packages.Where(p => + p.IsEquivalentTo(package) && p.NormalizedVersion < package.NormalizedNewVersion + ); + foreach (var match in matches) + { + Logger.Info( + $"Queuing {match} version {match.VersionString} for automatic uninstall after update..." + ); + l.Add(new(new UninstallPackageOperation(match, opts.Copy()), false)); + } + } + + return l; + } + } + + /* + * + * + * + * PER-OPERATION PACKAGE OPERATIONS + * + * + * + */ + public class InstallPackageOperation : PackageOperation + { + public InstallPackageOperation( + IPackage package, + InstallOptions options, + bool IgnoreParallelInstalls = false, + AbstractOperation? req = null + ) + : base(package, options, OperationType.Install, IgnoreParallelInstalls, req) { } + + protected override Task HandleFailure() + { + Package.SetTag(PackageTag.Failed); + return Task.CompletedTask; + } + + protected override async Task HandleSuccess() + { + Package.SetTag(PackageTag.AlreadyInstalled); + bool explicitVersionRequested = !string.IsNullOrWhiteSpace(Options.Version); + var installedPackage = await ResolveInstalledPackageSnapshotAsync( + explicitVersionRequested ? Options.Version : Package.VersionString, + preferFallbackVersionWhenMissing: explicitVersionRequested + ); + await InstalledPackagesLoader.Instance.AddForeign(installedPackage); + + if (Settings.Get(Settings.K.AskToDeleteNewDesktopShortcuts)) + { + DesktopShortcutsDatabase.HandleNewShortcuts(DesktopShortcutsBeforeStart); + } + } + + protected override void Initialize() + { + Metadata.OperationInformation = + "Package install operation for Package=" + + Package.Id + + " with Manager=" + + Package.Manager.Name + + "\nInstallation options: " + + Options.ToString() + + "\nOverriden options: " + + Package.OverridenOptions.ToString(); + + Metadata.Title = CoreTools.Translate( + "{package} Installation", + new Dictionary { { "package", Package.Name } } + ); + Metadata.Status = CoreTools.Translate("{0} is being installed", Package.Name); + Metadata.SuccessTitle = CoreTools.Translate("Installation succeeded"); + Metadata.SuccessMessage = CoreTools.Translate( + "{package} was installed successfully", + new Dictionary { { "package", Package.Name } } + ); + Metadata.FailureTitle = CoreTools.Translate( + "Installation failed", + new Dictionary { { "package", Package.Name } } + ); + Metadata.FailureMessage = CoreTools.Translate( + "{package} could not be installed", + new Dictionary { { "package", Package.Name } } + ); + + if (Settings.Get(Settings.K.AskToDeleteNewDesktopShortcuts)) + { + DesktopShortcutsBeforeStart = DesktopShortcutsDatabase.GetShortcutsOnDisk(); + } + } + } + + public class UpdatePackageOperation : PackageOperation + { + public UpdatePackageOperation( + IPackage package, + InstallOptions options, + bool IgnoreParallelInstalls = false, + AbstractOperation? req = null + ) + : base(package, options, OperationType.Update, IgnoreParallelInstalls, req) { } + + protected override Task HandleFailure() + { + Package.SetTag(PackageTag.Failed); + return Task.CompletedTask; + } + + protected override async Task HandleSuccess() + { + Package.SetTag(PackageTag.Default); + Package.GetAvailablePackage()?.SetTag(PackageTag.AlreadyInstalled); + + foreach (var p in Package.GetInstalledPackages()) + p.SetTag(PackageTag.Default); + + UpgradablePackagesLoader.Instance.Remove(Package); + InstalledPackagesLoader.Instance.Remove(Package); + + bool explicitVersionRequested = !string.IsNullOrWhiteSpace(Options.Version); + var installedPackage = await ResolveInstalledPackageSnapshotAsync( + explicitVersionRequested + ? Options.Version + : string.IsNullOrWhiteSpace(Package.NewVersionString) + ? Package.VersionString + : Package.NewVersionString, + preferFallbackVersionWhenMissing: explicitVersionRequested + ); + await InstalledPackagesLoader.Instance.AddForeign(installedPackage); + + if (Settings.Get(Settings.K.AskToDeleteNewDesktopShortcuts)) + { + DesktopShortcutsDatabase.HandleNewShortcuts(DesktopShortcutsBeforeStart); + } + + if ( + await Package.HasUpdatesIgnoredAsync() + && await Package.GetIgnoredUpdatesVersionAsync() != "*" + ) + await Package.RemoveFromIgnoredUpdatesAsync(); + } + + protected override void Initialize() + { + Metadata.OperationInformation = + "Package update operation for Package=" + + Package.Id + + " with Manager=" + + Package.Manager.Name + + "\nUpdate options: " + + Options.ToString() + + "\nOverriden options: " + + Package.OverridenOptions.ToString() + + "\nVersion: " + + Package.VersionString + + " -> " + + Package.NewVersionString; + + Metadata.Title = CoreTools.Translate( + "{package} Update", + new Dictionary { { "package", Package.Name } } + ); + Metadata.Status = CoreTools.Translate( + "{0} is being updated to version {1}", + Package.Name, + Package.NewVersionString + ); + Metadata.SuccessTitle = CoreTools.Translate("Update succeeded"); + Metadata.SuccessMessage = CoreTools.Translate( + "{package} was updated successfully", + new Dictionary { { "package", Package.Name } } + ); + Metadata.FailureTitle = CoreTools.Translate( + "Update failed", + new Dictionary { { "package", Package.Name } } + ); + Metadata.FailureMessage = CoreTools.Translate( + "{package} could not be updated", + new Dictionary { { "package", Package.Name } } + ); + + if (Settings.Get(Settings.K.AskToDeleteNewDesktopShortcuts)) + { + DesktopShortcutsBeforeStart = DesktopShortcutsDatabase.GetShortcutsOnDisk(); + } + } + } + + public class UninstallPackageOperation : PackageOperation + { + public UninstallPackageOperation( + IPackage package, + InstallOptions options, + bool IgnoreParallelInstalls = false, + AbstractOperation? req = null + ) + : base(package, options, OperationType.Uninstall, IgnoreParallelInstalls, req) { } + + protected override Task HandleFailure() + { + Package.SetTag(PackageTag.Failed); + return Task.CompletedTask; + } + + protected override Task HandleSuccess() + { + Package.SetTag(PackageTag.Default); + Package.GetAvailablePackage()?.SetTag(PackageTag.Default); + UpgradablePackagesLoader.Instance.Remove(Package); + InstalledPackagesLoader.Instance.Remove(Package); + + return Task.CompletedTask; + } + + protected override void Initialize() + { + Metadata.OperationInformation = + "Package uninstall operation for Package=" + + Package.Id + + " with Manager=" + + Package.Manager.Name + + "\nUninstall options: " + + Options.ToString() + + "\nOverriden options: " + + Package.OverridenOptions.ToString(); + + Metadata.Title = CoreTools.Translate( + "{package} Uninstall", + new Dictionary { { "package", Package.Name } } + ); + Metadata.Status = CoreTools.Translate("{0} is being uninstalled", Package.Name); + Metadata.SuccessTitle = CoreTools.Translate("Uninstall succeeded"); + Metadata.SuccessMessage = CoreTools.Translate( + "{package} was uninstalled successfully", + new Dictionary { { "package", Package.Name } } + ); + Metadata.FailureTitle = CoreTools.Translate( + "Uninstall failed", + new Dictionary { { "package", Package.Name } } + ); + Metadata.FailureMessage = CoreTools.Translate( + "{package} could not be uninstalled", + new Dictionary { { "package", Package.Name } } + ); + } + } +} diff --git a/src/UniGetUI.PackageEngine.Operations/PrePostOperation.cs b/src/UniGetUI.PackageEngine.Operations/PrePostOperation.cs new file mode 100644 index 0000000..b9a7f38 --- /dev/null +++ b/src/UniGetUI.PackageEngine.Operations/PrePostOperation.cs @@ -0,0 +1,128 @@ +using System.Diagnostics; +using UniGetUI.PackageEngine.Enums; +using UniGetUI.PackageOperations; + +namespace UniGetUI.PackageEngine.Operations; + +public class PrePostOperation : AbstractOperation +{ + private readonly string Payload; + private readonly object ProcessLock = new(); + private Process? ActiveProcess; + + public PrePostOperation(string payload) + : base(true) + { + Payload = payload.Replace("\r", "\n").Replace("\n\n", "\n").Replace("\n", "&"); + Metadata.Status = $"Running custom operation {Payload}"; + Metadata.Title = "Custom operation"; + Metadata.OperationInformation = " "; + Metadata.SuccessTitle = "Done!"; + Metadata.SuccessMessage = "Done!"; + Metadata.FailureTitle = "Custom operation failed"; + Metadata.FailureMessage = $"The custom operation {Payload} failed to run"; + CancelRequested += (_, _) => StopActiveProcess(); + } + + protected override void ApplyRetryAction(string retryMode) { } + + protected override async Task PerformOperation() + { + Line($"Running command {Payload}", LineType.Information); + using var process = new Process + { + StartInfo = new ProcessStartInfo + { + FileName = "cmd.exe", + Arguments = $"/C {Payload}", + RedirectStandardOutput = true, + RedirectStandardError = true, + UseShellExecute = false, + CreateNoWindow = true, + }, + }; + DataReceivedEventHandler outputHandler = (_, e) => + { + if (e.Data is not null) + Line(e.Data, LineType.Information); + }; + DataReceivedEventHandler errorHandler = (_, e) => + { + if (e.Data is not null) + Line(e.Data, LineType.Error); + }; + process.OutputDataReceived += outputHandler; + process.ErrorDataReceived += errorHandler; + lock (ProcessLock) + ActiveProcess = process; + bool processStarted = false; + + try + { + CancellationToken.ThrowIfCancellationRequested(); + process.Start(); + processStarted = true; + if (CancellationToken.IsCancellationRequested) + StopActiveProcess(); + process.BeginErrorReadLine(); + process.BeginOutputReadLine(); + + try + { + await process.WaitForExitAsync(CancellationToken).ConfigureAwait(false); + } + catch (OperationCanceledException) when (CancellationToken.IsCancellationRequested) + { + await process.WaitForExitAsync().ConfigureAwait(false); + return OperationVeredict.Canceled; + } + + if (CancellationToken.IsCancellationRequested) + return OperationVeredict.Canceled; + + int exitCode = process.ExitCode; + Line($"Exit code is {exitCode}", LineType.Information); + return exitCode == 0 ? OperationVeredict.Success : OperationVeredict.Failure; + } + finally + { + if (processStarted && !process.HasExited) + { + StopActiveProcess(); + await process.WaitForExitAsync().ConfigureAwait(false); + } + process.OutputDataReceived -= outputHandler; + process.ErrorDataReceived -= errorHandler; + lock (ProcessLock) + { + if (ReferenceEquals(ActiveProcess, process)) + ActiveProcess = null; + } + } + } + + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + if (disposing) + StopActiveProcess(); + } + + private void StopActiveProcess() + { + Process? process; + lock (ProcessLock) + process = ActiveProcess; + if (process is null) + return; + + try + { + if (!process.HasExited) + process.Kill(entireProcessTree: true); + } + catch (InvalidOperationException) { } + } + + public override Task GetOperationIcon() => Task.FromResult(new Uri("about:blank")); +} diff --git a/src/UniGetUI.PackageEngine.Operations/ProgressLineCollapser.cs b/src/UniGetUI.PackageEngine.Operations/ProgressLineCollapser.cs new file mode 100644 index 0000000..11c23f3 --- /dev/null +++ b/src/UniGetUI.PackageEngine.Operations/ProgressLineCollapser.cs @@ -0,0 +1,20 @@ +namespace UniGetUI.PackageOperations; + +// Folds a live log stream for in-place display: progress indicators (carriage-return redraws such +// as installer spinners or download bars) repaint the previous line instead of stacking up, +// mirroring how a terminal repaints in place. The first non-progress line that follows settles +// into that same line. Because a progress line is always the most recent one, "replace" always +// targets the last rendered line. +public sealed class ProgressLineCollapser +{ + public enum Fold { Append, ReplaceLast } + + private bool _lastWasProgress; + + public Fold Next(AbstractOperation.LineType type) + { + bool wasProgress = _lastWasProgress; + _lastWasProgress = type == AbstractOperation.LineType.ProgressIndicator; + return wasProgress ? Fold.ReplaceLast : Fold.Append; + } +} diff --git a/src/UniGetUI.PackageEngine.Operations/SourceOperations.cs b/src/UniGetUI.PackageEngine.Operations/SourceOperations.cs new file mode 100644 index 0000000..9be166a --- /dev/null +++ b/src/UniGetUI.PackageEngine.Operations/SourceOperations.cs @@ -0,0 +1,260 @@ +using UniGetUI.Core.Data; +using UniGetUI.Core.SettingsEngine; +using UniGetUI.Core.Tools; +using UniGetUI.PackageEngine.Enums; +using UniGetUI.PackageEngine.Interfaces; +using UniGetUI.PackageOperations; + +namespace UniGetUI.PackageEngine.Operations +{ + public abstract class SourceOperation : AbstractProcessOperation + { + protected abstract void Initialize(); + + protected IManagerSource Source; + public IManagerSource ManagerSource => Source; + public bool ForceAsAdministrator { get; private set; } + + public SourceOperation(IManagerSource source, IReadOnlyList? preOps) + : base(false, preOps) + { + Source = source; + Initialize(); + } + + public override Task GetOperationIcon() + { + return Task.FromResult( + new Uri($"ms-appx:///Assets/Images/{Source.Manager.Properties.ColorIconId}.png") + ); + } + + protected bool RequiresAdminRights() => + !Settings.Get(Settings.K.ProhibitElevation) + && (ForceAsAdministrator || Source.Manager.Capabilities.Sources.MustBeInstalledAsAdmin); + + protected override void ApplyRetryAction(string retryMode) + { + switch (retryMode) + { + case RetryMode.Retry: + break; + case RetryMode.Retry_AsAdmin: + ForceAsAdministrator = true; + break; + default: + throw new InvalidOperationException( + $"Retry mode {retryMode} is not supported in this context" + ); + } + } + + protected static bool IsWinGetManager(IPackageManager manager) + { +#if WINDOWS + return manager.Name == "Winget"; +#else + return false; +#endif + } + } + + public class AddSourceOperation : SourceOperation + { + public AddSourceOperation(IManagerSource source) + : base(source, []) { } + + protected override void PrepareProcessStartInfo() + { + var exePath = Source.Manager.Status.ExecutablePath; + bool admin = false; + if (RequiresAdminRights()) + { + if ( + OperatingSystem.IsLinux() + || Settings.Get(Settings.K.DoCacheAdminRights) + || Settings.Get(Settings.K.DoCacheAdminRightsForBatches) + ) + RequestCachingOfUACPrompt(); + + if (IsWinGetManager(Source.Manager)) + RedirectWinGetTempFolder(); + + admin = true; + process.StartInfo.FileName = CoreData.ElevatorPath; + process.StartInfo.Arguments = + ($"{CoreData.ElevatorArgs} \"{exePath}\" " + + Source.Manager.Status.ExecutableCallArgs + + " " + + string.Join(" ", Source.Manager.SourcesHelper.GetAddSourceParameters(Source))).TrimStart(); + } + else + { + process.StartInfo.FileName = exePath; + process.StartInfo.Arguments = + Source.Manager.Status.ExecutableCallArgs + + " " + + string.Join(" ", Source.Manager.SourcesHelper.GetAddSourceParameters(Source)); + } + + ApplyCapabilities(admin, false, false, null); + } + + protected override Task GetProcessVeredict( + int ReturnCode, + List Output + ) + { + return Task.Run(() => + Source.Manager.SourcesHelper.GetAddOperationVeredict( + Source, + ReturnCode, + Output.ToArray() + ) + ); + } + + protected override void Initialize() + { + Metadata.OperationInformation = + "Starting adding source operation for source=" + + Source.Name + + "with Manager=" + + Source.Manager.Name; + + Metadata.Title = CoreTools.Translate( + "Adding source {source}", + new Dictionary { { "source", Source.Name } } + ); + Metadata.Status = CoreTools.Translate( + "Adding source {source} to {manager}", + new Dictionary + { + { "source", Source.Name }, + { "manager", Source.Manager.Name }, + } + ); + ; + Metadata.SuccessTitle = CoreTools.Translate("Source added successfully"); + Metadata.SuccessMessage = CoreTools.Translate( + "The source {source} was added to {manager} successfully", + new Dictionary + { + { "source", Source.Name }, + { "manager", Source.Manager.Name }, + } + ); + Metadata.FailureTitle = CoreTools.Translate("Could not add source"); + Metadata.FailureMessage = CoreTools.Translate( + "Could not add source {source} to {manager}", + new Dictionary + { + { "source", Source.Name }, + { "manager", Source.Manager.Name }, + } + ); + } + } + + public class RemoveSourceOperation : SourceOperation + { + public RemoveSourceOperation(IManagerSource source) + : base(source, []) { } + + protected override void PrepareProcessStartInfo() + { + var exePath = Source.Manager.Status.ExecutablePath; + bool admin = false; + if (RequiresAdminRights()) + { + if ( + OperatingSystem.IsLinux() + || Settings.Get(Settings.K.DoCacheAdminRights) + || Settings.Get(Settings.K.DoCacheAdminRightsForBatches) + ) + RequestCachingOfUACPrompt(); + + if (IsWinGetManager(Source.Manager)) + RedirectWinGetTempFolder(); + + admin = true; + process.StartInfo.FileName = CoreData.ElevatorPath; + process.StartInfo.Arguments = + ($"{CoreData.ElevatorArgs} \"{exePath}\" " + + Source.Manager.Status.ExecutableCallArgs + + " " + + string.Join( + " ", + Source.Manager.SourcesHelper.GetRemoveSourceParameters(Source) + )).TrimStart(); + } + else + { + process.StartInfo.FileName = exePath; + process.StartInfo.Arguments = + Source.Manager.Status.ExecutableCallArgs + + " " + + string.Join( + " ", + Source.Manager.SourcesHelper.GetRemoveSourceParameters(Source) + ); + } + ApplyCapabilities(admin, false, false, null); + } + + protected override Task GetProcessVeredict( + int ReturnCode, + List Output + ) + { + return Task.Run(() => + Source.Manager.SourcesHelper.GetRemoveOperationVeredict( + Source, + ReturnCode, + Output.ToArray() + ) + ); + } + + protected override void Initialize() + { + Metadata.OperationInformation = + "Starting remove source operation for source=" + + Source.Name + + "with Manager=" + + Source.Manager.Name; + + Metadata.Title = CoreTools.Translate( + "Removing source {source}", + new Dictionary { { "source", Source.Name } } + ); + Metadata.Status = CoreTools.Translate( + "Removing source {source} from {manager}", + new Dictionary + { + { "source", Source.Name }, + { "manager", Source.Manager.Name }, + } + ); + ; + Metadata.SuccessTitle = CoreTools.Translate("Source removed successfully"); + Metadata.SuccessMessage = CoreTools.Translate( + "The source {source} was removed from {manager} successfully", + new Dictionary + { + { "source", Source.Name }, + { "manager", Source.Manager.Name }, + } + ); + Metadata.FailureTitle = CoreTools.Translate("Could not remove source"); + Metadata.FailureMessage = CoreTools.Translate( + "Could not remove source {source} from {manager}", + new Dictionary + { + { "source", Source.Name }, + { "manager", Source.Manager.Name }, + } + ); + } + } +} diff --git a/src/UniGetUI.PackageEngine.Operations/UniGetUI.PackageEngine.Operations.csproj b/src/UniGetUI.PackageEngine.Operations/UniGetUI.PackageEngine.Operations.csproj new file mode 100644 index 0000000..6b664b6 --- /dev/null +++ b/src/UniGetUI.PackageEngine.Operations/UniGetUI.PackageEngine.Operations.csproj @@ -0,0 +1,24 @@ + + + $(SharedTargetFrameworks) + + + + + + + + + + + + + + + + + + + + + diff --git a/src/UniGetUI.PackageEngine.Operations/WinGetManifestDownloadOperation.cs b/src/UniGetUI.PackageEngine.Operations/WinGetManifestDownloadOperation.cs new file mode 100644 index 0000000..db52ad7 --- /dev/null +++ b/src/UniGetUI.PackageEngine.Operations/WinGetManifestDownloadOperation.cs @@ -0,0 +1,115 @@ +#if WINDOWS +using UniGetUI.Core.Tools; +using UniGetUI.PackageEngine.Enums; +using UniGetUI.PackageEngine.Interfaces; +using UniGetUI.PackageEngine.Managers.WingetManager; +using UniGetUI.PackageOperations; + +namespace UniGetUI.PackageEngine.Operations; + +public class WinGetManifestDownloadOperation : AbstractProcessOperation +{ + private readonly IPackage _package; + private readonly string _downloadDirectory; + public IPackage Package => _package; + public string DownloadLocation => _downloadDirectory; + + public WinGetManifestDownloadOperation(IPackage package, string downloadDirectory) + : base(true, null) + { + _package = package; + _downloadDirectory = downloadDirectory; + + Metadata.OperationInformation = + "Downloading installer and manifest for WinGet Package=" + + _package.Id + + " into " + + _downloadDirectory; + Metadata.Title = CoreTools.Translate( + "{package} installer and manifest download", + new Dictionary { { "package", _package.Name } } + ); + Metadata.Status = CoreTools.Translate( + "{0} installer and manifest are being downloaded", + _package.Name + ); + Metadata.SuccessTitle = CoreTools.Translate("Download succeeded"); + Metadata.SuccessMessage = CoreTools.Translate( + "{package} installer and manifest were downloaded successfully", + new Dictionary { { "package", _package.Name } } + ); + Metadata.FailureTitle = CoreTools.Translate( + "Download failed", + new Dictionary { { "package", _package.Name } } + ); + Metadata.FailureMessage = CoreTools.Translate( + "{package} installer and manifest could not be downloaded", + new Dictionary { { "package", _package.Name } } + ); + } + + public override Task GetOperationIcon() + { + return Task.Run(_package.GetIconUrl); + } + + protected override void ApplyRetryAction(string retryMode) + { + // Do nothing + } + + protected override void PrepareProcessStartInfo() + { + var winget = (WinGet)_package.Manager; + bool usePinget = winget.SelectedCliToolKind == WinGetCliToolKind.BundledPinget; + + List args = ["download"]; + + args.AddRange(WinGetPkgOperationHelper.GetIdNamePiece(_package).Split(" ")); + + if (!_package.Source.IsVirtualManager) + { + args.AddRange(["--source", _package.Source.Name]); + } + + args.AddRange(["--download-directory", $"\"{_downloadDirectory}\""]); + + if (!usePinget) + { + args.AddRange( + [ + "--accept-package-agreements", + "--accept-source-agreements", + "--disable-interactivity", + ] + ); + + string proxyArg = WinGet.GetProxyArgument(); + if (proxyArg.Length > 0) + { + args.AddRange(proxyArg.Split(' ')); + } + } + + process.StartInfo.FileName = winget.Status.ExecutablePath; + process.StartInfo.Arguments = + winget.Status.ExecutableCallArgs + " " + string.Join(" ", args); + } + + protected override Task GetProcessVeredict( + int ReturnCode, + List Output + ) + { + // winget download return codes follow the standard winget code space. + uint uintCode = (uint)ReturnCode; + + if (uintCode is 0x8A150077 or 0x8A15010C or 0x8A150005) + return Task.FromResult(OperationVeredict.Canceled); + + return Task.FromResult( + ReturnCode == 0 ? OperationVeredict.Success : OperationVeredict.Failure + ); + } +} +#endif diff --git a/src/UniGetUI.PackageEngine.PackageEngine/PEInterface.cs b/src/UniGetUI.PackageEngine.PackageEngine/PEInterface.cs new file mode 100644 index 0000000..1d1ebd4 --- /dev/null +++ b/src/UniGetUI.PackageEngine.PackageEngine/PEInterface.cs @@ -0,0 +1,247 @@ +using System.Diagnostics.CodeAnalysis; +using UniGetUI.Core.Logging; +using UniGetUI.PackageEngine.Interfaces; +using UniGetUI.PackageEngine.Managers.BunManager; +using UniGetUI.PackageEngine.Managers.CargoManager; +using UniGetUI.PackageEngine.Managers.DotNetManager; +using UniGetUI.PackageEngine.Managers.NpmManager; +using UniGetUI.PackageEngine.Managers.PipManager; +using UniGetUI.PackageEngine.Managers.PowerShell7Manager; +using UniGetUI.PackageEngine.Managers.VcpkgManager; +using UniGetUI.PackageEngine.PackageClasses; +using UniGetUI.PackageEngine.PackageLoader; +#if WINDOWS +using UniGetUI.PackageEngine.Managers.ChocolateyManager; +using UniGetUI.PackageEngine.Managers.PowerShellManager; +using UniGetUI.PackageEngine.Managers.ScoopManager; +using UniGetUI.PackageEngine.Managers.WingetManager; +#else +using UniGetUI.PackageEngine.Managers.AptManager; +using UniGetUI.PackageEngine.Managers.DnfManager; +using UniGetUI.PackageEngine.Managers.HomebrewManager; +using UniGetUI.PackageEngine.Managers.PacmanManager; +using UniGetUI.PackageEngine.Managers.SnapManager; +using UniGetUI.PackageEngine.Managers.FlatpakManager; +#endif + +namespace UniGetUI.PackageEngine +{ + /// + /// The interface/entry point for the UniGetUI Package Engine + /// + public static class PEInterface + { + private const int ManagerLoadTimeout = 60; // 60 seconds timeout for Package Manager initialization (in seconds) +#if WINDOWS + public static readonly WinGet? WinGet = Create(() => new WinGet()); + public static readonly Scoop? Scoop = Create(() => new Scoop()); + public static readonly Chocolatey? Chocolatey = Create(() => new Chocolatey()); +#endif + public static readonly Npm? Npm = Create(() => new Npm()); + public static readonly Bun? Bun = Create(() => new Bun()); + public static readonly Pip? Pip = Create(() => new Pip()); + public static readonly DotNet? DotNet = Create(() => new DotNet()); + public static readonly PowerShell7? PowerShell7 = Create(() => new PowerShell7()); +#if WINDOWS + public static readonly PowerShell? PowerShell = Create(() => new PowerShell()); +#endif + public static readonly Cargo? Cargo = Create(() => new Cargo()); + public static readonly Vcpkg? Vcpkg = Create(() => new Vcpkg()); +#if !WINDOWS + public static readonly Apt? Apt = Create(() => new Apt()); + public static readonly Dnf? Dnf = Create(() => new Dnf()); + public static readonly Pacman? Pacman = Create(() => new Pacman()); + public static readonly Homebrew? Homebrew = Create(() => new Homebrew()); + public static readonly Snap? Snap = Create(() => new Snap()); + public static readonly Flatpak? Flatpak = Create(() => new Flatpak()); +#endif + + public static readonly IPackageManager[] Managers = CreateManagers(); + + // A single manager that fails to construct must not take down the whole engine (and with it + // the app, via TypeInitializationException). Log it and leave the field null; CreateManagers + // drops nulls so the rest of the managers stay usable. + private static T? Create(Func factory) where T : class, IPackageManager + { + try + { + return factory(); + } + catch (Exception ex) + { + // Logging runs inside its own guard: this method must never throw, or it would + // re-trigger the TypeInitializationException it exists to prevent (it runs from + // a static field initializer). + try + { + Logger.Error($"Failed to construct package manager {typeof(T).Name}; it will be unavailable this session."); + Logger.Error(ex); + } + catch { /* swallow: never let static initialization fail */ } + return null; + } + } + + private static IPackageManager[] CreateManagers() + { + List candidates = [Npm, Bun, Pip, Cargo, Vcpkg, DotNet, PowerShell7]; +#if WINDOWS + candidates.InsertRange(0, [WinGet, Scoop, Chocolatey]); + candidates.Add(PowerShell); +#else + candidates.Insert(0, Homebrew); + if (OperatingSystem.IsLinux()) + { + var families = ReadLinuxDistroFamilies(); + // If /etc/os-release is unreadable, include both as a safe fallback. + bool unknown = families.Count == 0; + if (unknown || families.Contains("debian") || families.Contains("ubuntu")) + candidates.Add(Apt); + if (unknown || families.Contains("fedora") || families.Contains("rhel") || families.Contains("centos")) + candidates.Add(Dnf); + if (unknown || families.Contains("arch")) + candidates.Add(Pacman); + if (unknown || families.Contains("ubuntu") || families.Contains("debian") || families.Contains("fedora") || families.Contains("arch")) + { + candidates.Add(Snap); + candidates.Add(Flatpak); + } + } +#endif + List managers = []; + foreach (IPackageManager? manager in candidates) + if (manager is not null) + managers.Add(manager); + return [.. managers]; + } + + public static void LoadLoaders() + { + DiscoverablePackagesLoader.Instance = new DiscoverablePackagesLoader(Managers); + InstalledPackagesLoader.Instance = new InstalledPackagesLoader(Managers); + UpgradablePackagesLoader.Instance = new UpgradablePackagesLoader(Managers); + PackageBundlesLoader.Instance = new PackageBundlesLoader_I(Managers); + } + + public static void LoadManagers() + { + try + { + List initializeTasks = []; + + foreach (IPackageManager manager in Managers) + { + initializeTasks.Add(Task.Run(manager.Initialize)); + } + + Task ManagersMegaTask = Task.WhenAll(initializeTasks); + + if (!ManagersMegaTask.Wait(TimeSpan.FromSeconds(ManagerLoadTimeout))) + { + Logger.Warn("Timeout: Not all package managers have finished initializing."); + } + + _ = InstalledPackagesLoader.Instance.ReloadPackages(); + _ = UpgradablePackagesLoader.Instance.ReloadPackages(); +#if !WINDOWS + // Re-run any search that was triggered before all managers were ready, + // so results from managers that finished initializing late are included. + _ = DiscoverablePackagesLoader.Instance.ReloadPackages(); +#endif + } + catch (Exception ex) + { + Logger.Error(ex); + } + } + +#if !WINDOWS + [System.Runtime.Versioning.SupportedOSPlatform("linux")] + private static HashSet ReadLinuxDistroFamilies() + { + var families = new HashSet(StringComparer.OrdinalIgnoreCase); + try + { + foreach (var line in File.ReadLines("/etc/os-release")) + { + if (!line.StartsWith("ID=", StringComparison.Ordinal) && + !line.StartsWith("ID_LIKE=", StringComparison.Ordinal)) + continue; + var value = line[(line.IndexOf('=') + 1)..].Trim('"'); + foreach (var token in value.Split(' ', StringSplitOptions.RemoveEmptyEntries)) + families.Add(token); + } + } + catch { /* /etc/os-release not readable — caller will use fallback */ } + return families; + } +#endif + } + + public class PackageBundlesLoader_I : PackageBundlesLoader + { + public PackageBundlesLoader_I(IReadOnlyList managers) + : base(managers) { } + + public override async Task AddPackagesAsync(IReadOnlyList foreign_packages) + { + List added = new(); + foreach (IPackage foreign in foreign_packages) + { + IPackage? package = null; + + if (foreign is not ImportedPackage && foreign is Package native) + { + if (native.Source.IsVirtualManager) + { + Logger.Debug( + $"Adding native package with id={native.Id} to bundle as an INVALID package..." + ); + package = new InvalidImportedPackage( + native.AsSerializable_Incompatible(), + NullSource.Instance + ); + } + else + { + Logger.Debug( + $"Adding native package with id={native.Id} to bundle as a VALID package..." + ); + package = new ImportedPackage( + await native.AsSerializableAsync(), + native.Manager, + native.Source + ); + } + } + else if (foreign is ImportedPackage imported) + { + Logger.Debug( + $"Adding loaded imported package with id={imported.Id} to bundle..." + ); + package = imported; + } + else if (foreign is InvalidImportedPackage invalid) + { + Logger.Debug( + $"Adding loaded incompatible package with id={invalid.Id} to bundle..." + ); + package = invalid; + } + else + { + Logger.Error( + $"An IPackage instance id={foreign.Id} did not match the types Package, ImportedPackage or InvalidImportedPackage. This should never be the case" + ); + } + + if (package is not null) + { // Here, AddForeign is not used so a single PackagesChangedEvent can be invoked. + await AddPackage(package); + added.Add(package); + } + } + InvokePackagesChangedEvent(true, added, []); + } + } +} diff --git a/src/UniGetUI.PackageEngine.PackageEngine/UniGetUI.PackageEngine.PEInterface.csproj b/src/UniGetUI.PackageEngine.PackageEngine/UniGetUI.PackageEngine.PEInterface.csproj new file mode 100644 index 0000000..c614e9d --- /dev/null +++ b/src/UniGetUI.PackageEngine.PackageEngine/UniGetUI.PackageEngine.PEInterface.csproj @@ -0,0 +1,79 @@ + + + $(SharedTargetFrameworks) + + + + + + + + + + + + + + + + + + + + + + + + + + + false + + + false + + + false + + + false + + + + + + + false + + + false + + + false + + + false + + + false + + + false + + + + + + + + + + + \ No newline at end of file diff --git a/src/UniGetUI.PackageEngine.PackageLoader/AbstractPackageLoader.cs b/src/UniGetUI.PackageEngine.PackageLoader/AbstractPackageLoader.cs new file mode 100644 index 0000000..be51392 --- /dev/null +++ b/src/UniGetUI.PackageEngine.PackageLoader/AbstractPackageLoader.cs @@ -0,0 +1,372 @@ +using System.Collections.Concurrent; +using UniGetUI.Core.Logging; +using UniGetUI.Core.Tools; +using UniGetUI.PackageEngine.Interfaces; + +namespace UniGetUI.PackageEngine.PackageLoader +{ + public class PackagesChangedEvent + { + public PackagesChangedEvent( + bool proceduralChange, + IReadOnlyList addedPackages, + IReadOnlyList removedPackages + ) + { + ProceduralChange = proceduralChange; + AddedPackages = addedPackages; + RemovedPackages = removedPackages; + } + + public readonly bool ProceduralChange; + public readonly IReadOnlyList AddedPackages; + public readonly IReadOnlyList RemovedPackages; + } + + public abstract class AbstractPackageLoader + { + /// + /// Checks if the loader has loaded packages + /// + public bool IsLoaded { get; private set; } + + /// + /// Checks if the loader is fetching new packages right now + /// + public bool IsLoading { get; protected set; } + + public bool Any() + { + return !PackageReference.IsEmpty; + } + + /// + /// The collection of currently available packages + /// + public List Packages + { + get => PackageReference.Values.ToList(); + } + + protected readonly ConcurrentDictionary PackageReference; + + /// + /// Fires when a block of packages (one package or more) is added or removed to the loader + /// + public event EventHandler? PackagesChanged; + + /// + /// Fires when the loader finishes fetching packages + /// + public event EventHandler? FinishedLoading; + + /// + /// Fires when the manager starts fetching packages + /// + public event EventHandler? StartedLoading; + + private readonly bool ALLOW_MULTIPLE_PACKAGE_VERSIONS; + private readonly bool DISABLE_RELOAD; + private readonly bool PACKAGES_CHECKED_BY_DEFAULT; + private readonly bool REQUIRES_INTERNET; + protected string LOADER_IDENTIFIER; + private int LoadOperationIdentifier; + protected IReadOnlyList Managers { get; private set; } + + public AbstractPackageLoader( + IReadOnlyList managers, + string identifier, + bool AllowMultiplePackageVersions, + bool DisableReload, + bool CheckedBydefault, + bool RequiresInternet + ) + { + Managers = managers; + PackageReference = new ConcurrentDictionary(); + IsLoaded = false; + IsLoading = false; + PACKAGES_CHECKED_BY_DEFAULT = CheckedBydefault; + DISABLE_RELOAD = DisableReload; + ALLOW_MULTIPLE_PACKAGE_VERSIONS = AllowMultiplePackageVersions; + LOADER_IDENTIFIER = identifier; + ALLOW_MULTIPLE_PACKAGE_VERSIONS = AllowMultiplePackageVersions; + REQUIRES_INTERNET = RequiresInternet; + } + + /// + /// Stops the current loading process + /// + public void StopLoading(bool emitFinishSignal = true) + { + LoadOperationIdentifier = -1; + IsLoaded = false; + IsLoading = false; + if (emitFinishSignal) + InvokeFinishedLoadingEvent(); + } + + protected void InvokePackagesChangedEvent( + bool proceduralChange, + IReadOnlyList toAdd, + IReadOnlyList toRemove + ) + { + PackagesChanged?.Invoke(this, new(proceduralChange, toAdd, toRemove)); + } + + protected void InvokeStartedLoadingEvent() + { + StartedLoading?.Invoke(this, EventArgs.Empty); + } + + protected void InvokeFinishedLoadingEvent() + { + FinishedLoading?.Invoke(this, EventArgs.Empty); + } + + /// + /// Will trigger a forceful reload of the packages + /// + public virtual async Task ReloadPackages() + { + try + { + if (DISABLE_RELOAD) + { + InvokePackagesChangedEvent(false, [], []); + return; + } + + if (IsLoading) + { + Logger.Debug($"[{this.GetType()}] Packages are already being loaded!!!"); + return; + } + + LoadOperationIdentifier = new Random().Next(); + int current_identifier = LoadOperationIdentifier; + IsLoading = true; + StartedLoading?.Invoke(this, EventArgs.Empty); + + // Clear packages only after signaling the load started, so the UI shows the + // loading state instead of briefly flashing the "no packages found" message. + PackageReference.Clear(); + IsLoaded = false; + InvokePackagesChangedEvent(false, [], []); + + if (REQUIRES_INTERNET) + { + await CoreTools.WaitForInternetConnection(); + } + + List>> tasks = []; + + foreach (IPackageManager manager in Managers) + { + if (manager.IsReady()) + { + Task> task = Task.Run(() => + LoadPackagesFromManager(manager) + ); + tasks.Add(task); + } + } + + while (tasks.Count > 0) + { + foreach (Task> task in tasks.ToArray()) + { + if (!task.IsCompleted) + { + await Task.Delay(100).ConfigureAwait(false); + } + + if (task.IsCompleted) + { + if ( + LoadOperationIdentifier == current_identifier + && task.IsCompletedSuccessfully + ) + { + var toAdd = new List(); + foreach (IPackage package in task.Result) + { + if (Contains(package) || !await IsPackageValid(package)) + { + continue; + } + + toAdd.Add(package); + await AddPackage(package); + } + + InvokePackagesChangedEvent(true, toAdd, []); + } + + tasks.Remove(task); + } + } + } + + if (LoadOperationIdentifier == current_identifier) + { + InvokeFinishedLoadingEvent(); + IsLoaded = true; + } + + IsLoading = false; + } + catch (Exception ex) + { + Logger.Error(ex); + IsLoading = false; + } + } + + /// + /// Resets the packages available on the loader + /// + public void ClearPackages(bool emitFinishSignal = true) + { + StopLoading(emitFinishSignal); + PackageReference.Clear(); + IsLoaded = false; + IsLoading = false; + InvokePackagesChangedEvent(false, [], []); + } + + /// + /// Loads the packages from the given manager + /// + /// The manager from which to load packages + /// A task that will load the packages + protected abstract IReadOnlyList LoadPackagesFromManager(IPackageManager manager); + + /// + /// Checks whether the package is valid or must be skipped + /// + /// The package to check + /// True if the package can be added, false otherwise + protected abstract Task IsPackageValid(IPackage package); + + /// + /// A method to post-process packages after they have been added. + /// + /// The package to process + protected abstract Task WhenAddingPackage(IPackage package); + + /// + /// Checks whether a package is contained on the current Loader + /// + /// The package to check against + public bool Contains(IPackage package) + { + return PackageReference.ContainsKey(HashPackage(package)); + } + + /// + /// Returns the appropriate hash of the package, according to the current loader configuration + /// + /// The package to hash + /// A long int containing the hash + protected long HashPackage(IPackage package) + { + return ALLOW_MULTIPLE_PACKAGE_VERSIONS ? package.GetVersionedHash() : package.GetHash(); + } + + protected async Task AddPackage(IPackage package) + { + if (Contains(package)) + return; + + package.IsChecked = PACKAGES_CHECKED_BY_DEFAULT; + await WhenAddingPackage(package); + PackageReference.TryAdd(HashPackage(package), package); + } + + /// + /// Adds a foreign package to the current loader. Perhaps a package has been recently installed and it needs to be added to the installed packages loader + /// + /// The package to add + public async Task AddForeign(IPackage? package) + { + if (package is null) + { + return; + } + + await AddPackage(package); + InvokePackagesChangedEvent(true, [package], []); + } + + /// + /// Removes the given package from the list. + /// + public void Remove(IPackage? package) + { + if (package is null) + { + return; + } + + if (!Contains(package)) + { + return; + } + + PackageReference.Remove(HashPackage(package), out _); + InvokePackagesChangedEvent(true, [], [package]); + } + + /// + /// Gets the corresponding package on the current loader. + /// This method follows the equivalence settings for this loader + /// + /// A Package? object + public IPackage? GetEquivalentPackage(IPackage? package) + { + if (package is null) + { + return null; + } + + PackageReference.TryGetValue(HashPackage(package), out IPackage? eq); + return eq; + } + + /// + /// Gets ALL of the equivalent packages on this loader. + /// This method does NOT follow the equivalence settings for this loader + /// + /// The package for which to find the equivalent packages + /// A IReadOnlyList object + public IReadOnlyList GetEquivalentPackages(IPackage? package) + { + if (package is null) + { + return []; + } + + return Packages.Where(p => p.IsEquivalentTo(package)).ToArray(); + } + + public IPackage? GetPackageForId(string id, string? sourceName = null) + { + foreach (IPackage package in Packages) + { + if (package.Id == id && (sourceName is null || package.Source.Name == sourceName)) + { + return package; + } + } + + return null; + } + + public int Count() + { + return PackageReference.Count; + } + } +} diff --git a/src/UniGetUI.PackageEngine.PackageLoader/DiscoverablePackagesLoader.cs b/src/UniGetUI.PackageEngine.PackageLoader/DiscoverablePackagesLoader.cs new file mode 100644 index 0000000..4ad94f6 --- /dev/null +++ b/src/UniGetUI.PackageEngine.PackageLoader/DiscoverablePackagesLoader.cs @@ -0,0 +1,163 @@ +using UniGetUI.Core.Tools; +using UniGetUI.Interface.Enums; +using UniGetUI.PackageEngine.Interfaces; + +namespace UniGetUI.PackageEngine.PackageLoader +{ + public class DiscoverablePackagesLoader : AbstractPackageLoader + { + public static DiscoverablePackagesLoader Instance = null!; + + // Cap results per manager; a broad query across every enabled manager otherwise wraps, + // tags and renders thousands of packages, freezing the UI and spiking RAM. + private const int MAX_RESULTS_PER_MANAGER = 100; + + private string QUERY_TEXT = string.Empty; + private volatile bool _pendingReload; + + public DiscoverablePackagesLoader(IReadOnlyList managers) + : base( + managers, + identifier: "DISCOVERABLE_PACKAGES", + AllowMultiplePackageVersions: false, + DisableReload: false, + CheckedBydefault: false, + RequiresInternet: true + ) + { + Instance = this; + FinishedLoading += OnFinishedLoading; + } + + private void OnFinishedLoading(object? sender, EventArgs e) + { + if (_pendingReload) + { + _pendingReload = false; + _ = ReloadPackages(); + } + } + + public async Task ReloadPackages(string query) + { + QUERY_TEXT = query; + await ReloadPackages(); + } + + public override async Task ReloadPackages() + { + if (QUERY_TEXT == "") + { + return; + } + + if (IsLoading) + { + _pendingReload = true; + return; + } + + await base.ReloadPackages(); + } + + protected override async Task IsPackageValid(IPackage package) + { + return await Task.FromResult(true); + } + + protected override IReadOnlyList LoadPackagesFromManager(IPackageManager manager) + { + string text = QUERY_TEXT; + text = CoreTools.EnsureSafeQueryString(text); + if (text == string.Empty) + { + return []; + } + + IReadOnlyList found = manager.FindPackages(text); + return found.Count > MAX_RESULTS_PER_MANAGER + ? found.Take(MAX_RESULTS_PER_MANAGER).ToArray() + : found; + } + + protected override Task WhenAddingPackage(IPackage package) + { + if (package.GetUpgradablePackage() is not null) + { + package.SetTag(PackageTag.IsUpgradable); + } + else if (package.GetInstalledPackages().Any()) + { + package.SetTag(PackageTag.AlreadyInstalled); + } + return Task.CompletedTask; + } + + public (IPackage?, string?) GetPackageFromIdAndManager( + string id, + string managerName, + string sourceName + ) + { + IPackageManager? manager = null; + + foreach (var candidate in Managers) + { + if (candidate.Name == managerName || candidate.DisplayName == managerName) + { + manager = candidate; + break; + } + } + + if (manager is null) + return ( + null, + CoreTools.Translate("The package manager \"{0}\" was not found", managerName) + ); + + if (!manager.IsEnabled()) + return ( + null, + CoreTools.Translate( + "The package manager \"{0}\" is disabled", + manager.DisplayName + ) + ); + + if (!manager.Status.Found) + return ( + null, + CoreTools.Translate( + "There is an error with the configuration of the package manager \"{0}\"", + manager.DisplayName + ) + ); + + var results = manager.FindPackages(id); + var candidates = results.Where(p => p.Id == id).ToArray(); + + if (candidates.Length == 0) + return ( + null, + CoreTools.Translate( + "The package \"{0}\" was not found on the package manager \"{1}\"", + id, + manager.DisplayName + ) + ); + + IPackage package = candidates[0]; + + // Get package from best source + if (candidates.Length >= 1 && manager.Capabilities.SupportsCustomSources) + foreach (var candidate in candidates) + { + if (candidate.Source.Name == sourceName) + package = candidate; + } + + return (package, null); + } + } +} diff --git a/src/UniGetUI.PackageEngine.PackageLoader/InstalledPackagesLoader.cs b/src/UniGetUI.PackageEngine.PackageLoader/InstalledPackagesLoader.cs new file mode 100644 index 0000000..abba4cb --- /dev/null +++ b/src/UniGetUI.PackageEngine.PackageLoader/InstalledPackagesLoader.cs @@ -0,0 +1,120 @@ +using UniGetUI.Core.Logging; +using UniGetUI.Interface.Enums; +using UniGetUI.PackageEngine.Interfaces; + +namespace UniGetUI.PackageEngine.PackageLoader +{ + public class InstalledPackagesLoader : AbstractPackageLoader + { + public static InstalledPackagesLoader Instance = null!; + + public InstalledPackagesLoader(IReadOnlyList managers) + : base( + managers, + identifier: "INSTALLED_PACKAGES", + AllowMultiplePackageVersions: true, + DisableReload: false, + CheckedBydefault: false, + RequiresInternet: true + ) + { + Instance = this; + } + + protected override Task IsPackageValid(IPackage package) + { + return Task.FromResult(true); + } + + protected override IReadOnlyList LoadPackagesFromManager(IPackageManager manager) + { + return manager.GetInstalledPackages(); + } + + protected override async Task WhenAddingPackage(IPackage package) + { + if (await package.HasUpdatesIgnoredAsync(version: "*")) + { + package.Tag = PackageTag.Pinned; + } + else if (package.GetUpgradablePackage() is not null) + { + package.Tag = PackageTag.IsUpgradable; + } + + package.GetAvailablePackage()?.SetTag(PackageTag.AlreadyInstalled); + } + + public async Task ReloadPackagesSilently() + { + if (IsLoading) + { + Logger.Debug($"[{this.GetType()}] Packages are already being loaded!!!"); + return; + } + + try + { + IsLoading = true; + InvokeStartedLoadingEvent(); + + List>> tasks = []; + + foreach (IPackageManager manager in Managers) + { + if (manager.IsEnabled() && manager.Status.Found) + { + Task> task = Task.Run(() => + LoadPackagesFromManager(manager) + ); + tasks.Add(task); + } + } + + while (tasks.Count > 0) + { + foreach (Task> task in tasks.ToArray()) + { + if (!task.IsCompleted) + { + await Task.Delay(100); + } + + if (task.IsCompleted) + { + if (task.IsCompletedSuccessfully) + { + var toAdd = new List(); + foreach (IPackage package in task.Result) + { + if (Contains(package) || !await IsPackageValid(package)) + { + continue; + } + + Logger.ImportantInfo( + $"Adding missing package {package.Id} to installed packages list" + ); + toAdd.Add(package); + await AddPackage(package); + } + + InvokePackagesChangedEvent(true, toAdd, []); + } + + tasks.Remove(task); + } + } + } + + InvokeFinishedLoadingEvent(); + IsLoading = false; + } + catch (Exception ex) + { + Logger.Error(ex); + IsLoading = false; + } + } + } +} diff --git a/src/UniGetUI.PackageEngine.PackageLoader/PackageBundlesLoader.cs b/src/UniGetUI.PackageEngine.PackageLoader/PackageBundlesLoader.cs new file mode 100644 index 0000000..01ffdd1 --- /dev/null +++ b/src/UniGetUI.PackageEngine.PackageLoader/PackageBundlesLoader.cs @@ -0,0 +1,64 @@ +using UniGetUI.Interface.Enums; +using UniGetUI.PackageEngine.Interfaces; + +namespace UniGetUI.PackageEngine.PackageLoader +{ + public abstract class PackageBundlesLoader : AbstractPackageLoader + { + public static PackageBundlesLoader Instance = null!; + + public PackageBundlesLoader(IReadOnlyList managers) + : base( + managers, + identifier: "PACKAGE_BUNDLES", + AllowMultiplePackageVersions: true, + DisableReload: true, + CheckedBydefault: false, + RequiresInternet: false + ) + { + Instance = this; + } + + protected override Task IsPackageValid(IPackage package) + { + return Task.FromResult(true); + } + + protected override IReadOnlyList LoadPackagesFromManager(IPackageManager manager) + { + return []; + } + + protected override Task WhenAddingPackage(IPackage package) + { + if (package.NewerVersionIsInstalled()) + { + package.SetTag(PackageTag.AlreadyInstalled); + } + else if (package.GetUpgradablePackage() is not null) + { + package.SetTag(PackageTag.IsUpgradable); + } + + return Task.CompletedTask; + } + + /* + * This method required access to the Package, ImportedPackage and InvalidPackage classes, + * but they are not defined here yet. This class will be inherited on PEInterface, with the missing member + */ + public abstract Task AddPackagesAsync(IReadOnlyList foreign_packages); + + public void RemoveRange(IReadOnlyList packages) + { + foreach (IPackage package in packages) + { + if (!Contains(package)) + continue; + PackageReference.Remove(HashPackage(package), out IPackage? _); + } + InvokePackagesChangedEvent(true, [], packages); + } + } +} diff --git a/src/UniGetUI.PackageEngine.PackageLoader/UniGetUI.PackageEngine.PackageLoaders.csproj b/src/UniGetUI.PackageEngine.PackageLoader/UniGetUI.PackageEngine.PackageLoaders.csproj new file mode 100644 index 0000000..4efc5b1 --- /dev/null +++ b/src/UniGetUI.PackageEngine.PackageLoader/UniGetUI.PackageEngine.PackageLoaders.csproj @@ -0,0 +1,19 @@ + + + $(SharedTargetFrameworks) + + + + + + + + + + + + + + + + diff --git a/src/UniGetUI.PackageEngine.PackageLoader/UpgradablePackagesLoader.cs b/src/UniGetUI.PackageEngine.PackageLoader/UpgradablePackagesLoader.cs new file mode 100644 index 0000000..70ef99b --- /dev/null +++ b/src/UniGetUI.PackageEngine.PackageLoader/UpgradablePackagesLoader.cs @@ -0,0 +1,149 @@ +using System.Collections.Concurrent; +using System.Globalization; +using UniGetUI.Core.Logging; +using UniGetUI.Core.SettingsEngine; +using UniGetUI.Interface.Enums; +using UniGetUI.PackageEngine.Interfaces; + +namespace UniGetUI.PackageEngine.PackageLoader +{ + public class UpgradablePackagesLoader : AbstractPackageLoader + { + private System.Timers.Timer? UpdatesTimer; + public static UpgradablePackagesLoader Instance = null!; + + /// + /// The collection of packages with updates ignored + /// + public ConcurrentDictionary IgnoredPackages = new(); + + public UpgradablePackagesLoader(IReadOnlyList managers) + : base( + managers, + identifier: "UPGRADABLE_PACKAGES", + AllowMultiplePackageVersions: false, + DisableReload: false, + CheckedBydefault: !Settings.Get(Settings.K.DisableSelectingUpdatesByDefault), + RequiresInternet: true + ) + { + Instance = this; + FinishedLoading += (_, _) => StartAutoCheckTimeout(); + } + + protected override async Task IsPackageValid(IPackage package) + { + if (package.VersionString == package.NewVersionString) + return false; + + if (package.NewerVersionIsInstalled()) + return false; + + if (package.IsUpdateMinor() && (await package.GetInstallOptions()).SkipMinorUpdates) + { + Logger.Info( + $"Ignoring package {package.Id} because it is a minor update ({package.VersionString} -> {package.NewVersionString}) and SkipMinorUpdates is set to true." + ); + return false; + } + + if (await package.HasUpdatesIgnoredAsync(package.NewVersionString)) + { + IgnoredPackages[package.Id] = package; + return false; + } + + string? perManagerVal = Settings.GetDictionaryItem( + Settings.K.PerManagerMinimumUpdateAge, package.Manager.Name); + + int minimumAge; + if (perManagerVal is { Length: > 0 }) + { + if (perManagerVal == "custom") + int.TryParse( + Settings.GetDictionaryItem( + Settings.K.PerManagerMinimumUpdateAgeCustom, package.Manager.Name), + out minimumAge); + else + int.TryParse(perManagerVal, out minimumAge); + } + else + { + string globalVal = Settings.GetValue(Settings.K.MinimumUpdateAge); + if (globalVal == "custom") + int.TryParse( + Settings.GetValue(Settings.K.MinimumUpdateAgeCustom), + out minimumAge); + else + int.TryParse(globalVal, out minimumAge); + } + + if (minimumAge > 0) + { + await package.Details.Load(); + string? dateStr = package.Details.UpdateDate; + if (dateStr is { Length: > 0 } && + DateTime.TryParse(dateStr, CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTime releaseDate) && + (DateTime.UtcNow - releaseDate.ToUniversalTime()).TotalDays < minimumAge) + { + Logger.Info( + $"Suppressing update for {package.Id}: released {releaseDate:yyyy-MM-dd}, minimum age is {minimumAge} days" + ); + return false; + } + } + + return true; + } + + protected override IReadOnlyList LoadPackagesFromManager(IPackageManager manager) + { + return manager.GetAvailableUpdates(); + } + + protected override Task WhenAddingPackage(IPackage package) + { + package.GetAvailablePackage()?.SetTag(PackageTag.IsUpgradable); + + foreach (var p in package.GetInstalledPackages()) + p.SetTag(PackageTag.IsUpgradable); + + return Task.CompletedTask; + } + + protected void StartAutoCheckTimeout() + { + if (!Settings.Get(Settings.K.DisableAutoCheckforUpdates)) + { + long waitTime = 3600; + try + { + waitTime = long.Parse(Settings.GetValue(Settings.K.UpdatesCheckInterval)); + Logger.Debug( + $"Starting check for updates wait interval with waitTime={waitTime}" + ); + } + catch + { + Logger.Debug( + "Invalid value for UpdatesCheckInterval, using default value of 3600 seconds" + ); + } + + if (UpdatesTimer is not null) + { + UpdatesTimer.Stop(); + UpdatesTimer.Dispose(); + } + + UpdatesTimer = new System.Timers.Timer(waitTime * 1000) + { + Enabled = false, + AutoReset = false, + }; + UpdatesTimer.Elapsed += (s, e) => _ = ReloadPackages(); + UpdatesTimer.Start(); + } + } + } +} diff --git a/src/UniGetUI.PackageEngine.PackageManagerClasses/Manager/Classes/ManagerLogger.cs b/src/UniGetUI.PackageEngine.PackageManagerClasses/Manager/Classes/ManagerLogger.cs new file mode 100644 index 0000000..31ec77f --- /dev/null +++ b/src/UniGetUI.PackageEngine.PackageManagerClasses/Manager/Classes/ManagerLogger.cs @@ -0,0 +1,479 @@ +using System.Diagnostics; +using UniGetUI.Core.Logging; +using UniGetUI.PackageEngine.Enums; +using UniGetUI.PackageEngine.Interfaces; + +namespace UniGetUI.PackageEngine.ManagerClasses.Classes +{ + public class ManagerLogger : IManagerLogger + { + private readonly IPackageManager Manager; + + // Keep only recent operations; retained unbounded, each holds its full output and grows forever. + private const int MAX_RETAINED_OPERATIONS = 100; + private readonly List operations = []; + public IReadOnlyList Operations + { + get { lock (operations) return operations.ToArray(); } + } + + public ManagerLogger(IPackageManager manager) + { + Manager = manager; + } + + private void Register(TaskLogger operation) + { + lock (operations) + { + operations.Add(operation); + if (operations.Count > MAX_RETAINED_OPERATIONS) + operations.RemoveRange(0, operations.Count - MAX_RETAINED_OPERATIONS); + } + } + + public IProcessTaskLogger CreateNew(LoggableTaskType type, Process process) + { + if (process.StartInfo is null) + { + throw new InvalidOperationException( + "Given process instance did not have a valid StartInfo value" + ); + } + + ProcessTaskLogger operation = new( + Manager, + type, + process.StartInfo.FileName, + process.StartInfo.Arguments + ); + Register(operation); + return operation; + } + + public INativeTaskLogger CreateNew(LoggableTaskType type) + { + NativeTaskLogger operation = new(Manager, type); + Register(operation); + return operation; + } + } + + public abstract class TaskLogger : ITaskLogger + { + // Cap retained output per stream (chunk-trimmed to keep appending O(1)); a search can emit thousands of lines. + protected const int MaxRetainedLines = 1000; + private const int TrimSlack = 256; + + protected static void AppendCapped(List target, string line) + { + target.Add(line); + if (target.Count > MaxRetainedLines + TrimSlack) + target.RemoveRange(0, target.Count - MaxRetainedLines); + } + + protected DateTime StartTime; + protected DateTime? EndTime; + protected bool isComplete; + protected bool isOpen; + protected IReadOnlyList? CachedMessage; + protected IReadOnlyList? CachedVerboseMessage; + + private const int RETURNCODE_UNSET = -200; + protected int ReturnCode = -200; + + public TaskLogger() + { + StartTime = DateTime.Now; + isComplete = false; + isOpen = true; + } + + ~TaskLogger() + { + if (isOpen) + { + Close(RETURNCODE_UNSET); + } + } + + public void Close(int returnCode) + { + ReturnCode = returnCode; + EndTime = DateTime.Now; + isOpen = false; + isComplete = true; + CachedMessage = null; + CachedVerboseMessage = null; + } + + /// + /// Returns the output with a preceding digit representing the color of the line: + /// 0. White + /// 1. Grey + /// 2. Red + /// 3. Blue + /// 4. Green + /// 5. Yellow + /// + public abstract IReadOnlyList AsColoredString(bool verbose = false); + } + + public class ProcessTaskLogger : TaskLogger, IProcessTaskLogger + { + private readonly IPackageManager Manager; + private readonly LoggableTaskType Type; + + private readonly string Executable; + private readonly string Arguments; + private readonly List StdIn = []; + private readonly List StdOut = []; + private readonly List StdErr = []; + + public ProcessTaskLogger( + IPackageManager manager, + LoggableTaskType type, + string executable, + string arguments + ) + { + Type = type; + Manager = manager; + Executable = executable; + Arguments = arguments; + } + + public void AddToStdIn(string? line) + { + if (line is not null) + { + AddToStdIn(line.Split('\n')); + } + } + + public void AddToStdIn(IReadOnlyList lines) + { + if (!isOpen) + { + throw new InvalidOperationException( + "Attempted to write log into an already-closed ProcessTaskLogger" + ); + } + + foreach (string line in lines) + { + if (line != "") + { + StdIn.Add(line); + } + } + } + + public void AddToStdOut(string? line) + { + if (line is not null) + { + AddToStdOut(line.Split('\n')); + } + } + + public void AddToStdOut(IReadOnlyList lines) + { + if (!isOpen) + { + throw new InvalidOperationException( + "Attempted to write log into an already-closed ProcessTaskLogger" + ); + } + + foreach (string line in lines) + { + if (line != "") + { + AppendCapped(StdOut, line); + } + } + } + + public void AddToStdErr(string? line) + { + if (line is not null) + { + AddToStdErr(line.Split('\n')); + } + } + + public void AddToStdErr(IReadOnlyList lines) + { + if (!isOpen) + { + throw new InvalidOperationException( + "Attempted to write log into an already-closed ProcessTaskLogger" + ); + } + + foreach (string line in lines) + { + if (line != "") + { + AppendCapped(StdErr, line); + } + } + } + + public override IReadOnlyList AsColoredString(bool verbose = false) + { + if (!verbose && CachedMessage is not null && isComplete) + { + return CachedMessage; + } + + if (verbose && CachedVerboseMessage is not null && isComplete) + { + return CachedVerboseMessage; + } + + List result = + [ + $"0Logged subprocess-based task on manager {Manager.Name}. Task type is {Type}", + $"0Subprocess executable: \"{Executable}\"", + $"0Command-line arguments: \"{Arguments}\"", + $"0Process start time: {StartTime}", + EndTime is null + ? "2Process end time: UNFINISHED" + : $"0Process end time: {EndTime}", + ]; + + if (StdIn.Count > 0) + { + result.Add("0"); + result.Add("0-- Process STDIN"); + if (verbose) + { + foreach (string line in StdIn) + { + result.Add("3 " + line); + } + } + else + { + result.Add("1 ..."); + } + } + if (StdOut.Count > 0) + { + result.Add("0"); + result.Add("0-- Process STDOUT"); + if (verbose) + { + foreach (string line in StdOut) + { + result.Add("1 " + line); + } + } + else + { + result.Add("1 ..."); + } + } + if (StdErr.Count > 0) + { + result.Add("0"); + result.Add("0-- Process STDERR"); + foreach (string line in StdErr) + { + result.Add("2 " + line); + } + } + result.Add("0"); + if (!isComplete) + { + result.Add("5Return code: Process has not finished yet"); + } + else if (ReturnCode == -200) + { + result.Add("5Return code: UNSPECIFIED"); + } + else if (ReturnCode == 0) + { + result.Add("4Return code: SUCCESS (0)"); + } + else + { + result.Add( + $"2Return code: FAILED (0x{(uint)ReturnCode:X}, {(uint)ReturnCode}, {ReturnCode})" + ); + } + + result.Add("0"); + result.Add("0——————————————————————————————————————————"); + result.Add("0"); + + for (int i = 0; i < result.Count; i++) + result[i] = Logger.Redact(result[i]); + + if (verbose) + { + return CachedVerboseMessage = result; + } + + return CachedMessage = result; + } + } + + public class NativeTaskLogger : TaskLogger, INativeTaskLogger + { + private readonly IPackageManager Manager; + private readonly LoggableTaskType Type; + + private readonly List Info = []; + private readonly List Errors = []; + + public NativeTaskLogger(IPackageManager manager, LoggableTaskType type) + { + Type = type; + Manager = manager; + } + + public void Log(IReadOnlyList lines) + { + if (!isOpen) + { + throw new InvalidOperationException( + "Attempted to write log into an already-closed NativeTaskLogger" + ); + } + + foreach (string line in lines) + { + if (line != "") + { + AppendCapped(Info, line); + } + } + } + + public void Log(string? line) + { + if (line is not null) + { + Log(line.Split('\n')); + } + } + + public void Error(IReadOnlyList lines) + { + if (!isOpen) + { + throw new InvalidOperationException( + "Attempted to write log into an already-closed NativeTaskLogger" + ); + } + + foreach (string line in lines) + { + if (line != "") + { + AppendCapped(Errors, line); + } + } + } + + public void Error(string? line) + { + if (line is not null) + { + Error(line.Split('\n')); + } + } + + public void Error(Exception? e) + { + if (e is not null) + { + Error(e.ToString().Split('\n')); + } + } + + public override IReadOnlyList AsColoredString(bool verbose = false) + { + if (!verbose && CachedMessage is not null && isComplete) + { + return CachedMessage; + } + + if (verbose && CachedVerboseMessage is not null && isComplete) + { + return CachedVerboseMessage; + } + + List result = + [ + $"0Logged native task on manager {Manager.Name}. Task type is {Type}", + $"0Process start time: {StartTime}", + EndTime is null + ? "2Process end time: UNFINISHED" + : $"0Process end time: {EndTime}", + ]; + + if (Info.Count > 0) + { + result.Add("0"); + result.Add("0-- Task information"); + if (verbose) + { + foreach (string line in Info) + { + result.Add("1 " + line); + } + } + else + { + result.Add("1 ..."); + } + } + if (Errors.Count > 0) + { + result.Add("0"); + result.Add("0-- Task errors"); + foreach (string line in Errors) + { + result.Add("2 " + line); + } + } + result.Add("0"); + if (!isComplete) + { + result.Add("5The task has not finished yet"); + } + else if (ReturnCode == -200) + { + result.Add("5The task did not report a finish status"); + } + else if (ReturnCode == 0) + { + result.Add("4The task reported success"); + } + else + { + result.Add( + $"2The task reported a failure (0x{(uint)ReturnCode:X}, {(uint)ReturnCode}, {ReturnCode})" + ); + } + + result.Add("0"); + result.Add("0——————————————————————————————————————————"); + result.Add("0"); + + for (int i = 0; i < result.Count; i++) + result[i] = Logger.Redact(result[i]); + + if (verbose) + { + return CachedVerboseMessage = result; + } + + return CachedMessage = result; + } + } +} diff --git a/src/UniGetUI.PackageEngine.PackageManagerClasses/Manager/Classes/ManagerSource.cs b/src/UniGetUI.PackageEngine.PackageManagerClasses/Manager/Classes/ManagerSource.cs new file mode 100644 index 0000000..a1ee649 --- /dev/null +++ b/src/UniGetUI.PackageEngine.PackageManagerClasses/Manager/Classes/ManagerSource.cs @@ -0,0 +1,73 @@ +using UniGetUI.Interface.Enums; +using UniGetUI.PackageEngine.Interfaces; + +namespace UniGetUI.PackageEngine.Classes.Manager +{ + public class ManagerSource : IManagerSource + { + public virtual IconType IconId + { + get { return Manager.Properties.IconId; } + } + + public IPackageManager Manager { get; } + public string Name { get; } + public Uri Url { get; set; } + public int? PackageCount { get; } + public string UpdateDate { get; } + public string AsString { get; protected set; } + public string AsString_DisplayName { get; protected set; } + + public bool IsVirtualManager { get; } + + public ManagerSource( + IPackageManager manager, + string name, + Uri url, + int? packageCount = 0, + string updateDate = "", + bool isVirtualManager = false + ) + { + IsVirtualManager = isVirtualManager; + Manager = manager; + Name = name; + Url = url; + if (manager.Capabilities.Sources.KnowsPackageCount) + { + PackageCount = packageCount; + } + + UpdateDate = updateDate; + AsString = ""; + AsString_DisplayName = ""; + RefreshSourceNames(); + } + + public override string ToString() => AsString; + + /// + /// Replaces the current URL with the new one. Must be used only when a placeholder URL is used. + /// + public void ReplaceUrl(Uri newUrl) + { + Url = newUrl; + } + + /// + /// Will refresh the source names based on the current manager's properties. + /// + public void RefreshSourceNames() + { + AsString = Manager.Capabilities.SupportsCustomSources + ? $"{Manager.Properties.Name}: {Name}" + : Manager.Properties.Name; + if (Manager.Properties.DisplayName is string display_name) + AsString_DisplayName = Manager.Capabilities.SupportsCustomSources + ? $"{display_name}: {Name}" + : display_name; + else + AsString_DisplayName = AsString; + } + } +} diff --git a/src/UniGetUI.PackageEngine.PackageManagerClasses/Manager/Classes/NullPackageManager.cs b/src/UniGetUI.PackageEngine.PackageManagerClasses/Manager/Classes/NullPackageManager.cs new file mode 100644 index 0000000..daa176f --- /dev/null +++ b/src/UniGetUI.PackageEngine.PackageManagerClasses/Manager/Classes/NullPackageManager.cs @@ -0,0 +1,162 @@ +using System.Text; +using UniGetUI.Core.IconEngine; +using UniGetUI.Core.Tools; +using UniGetUI.Interface.Enums; +using UniGetUI.PackageEngine.Classes.Manager.Classes; +using UniGetUI.PackageEngine.Classes.Manager.ManagerHelpers; +using UniGetUI.PackageEngine.Enums; +using UniGetUI.PackageEngine.Interfaces; +using UniGetUI.PackageEngine.Interfaces.ManagerProviders; +using UniGetUI.PackageEngine.ManagerClasses.Classes; +using UniGetUI.PackageEngine.ManagerClasses.Manager; +using UniGetUI.PackageEngine.PackageClasses; +using UniGetUI.PackageEngine.Serializable; + +namespace UniGetUI.PackageEngine.Classes.Manager +{ + public class NullPackageManager : IPackageManager + { + public static NullPackageManager Instance = new(); + public ManagerProperties Properties { get; } + public ManagerCapabilities Capabilities { get; } + public ManagerStatus Status { get; } + public Encoding OutputEncoding => Encoding.UTF8; + public string Id + { + get => string.IsNullOrWhiteSpace(Properties.Id) ? Properties.Name : Properties.Id; + } + public string Name + { + get => Properties.Name; + } + public string DisplayName + { + get => Properties.DisplayName ?? Properties.Name; + } + public IManagerSource DefaultSource + { + get => Properties.DefaultSource; + } + public bool ManagerReady + { + get => true; + } + public IManagerLogger TaskLogger { get; } + public IMultiSourceHelper SourcesHelper { get; } + public IPackageDetailsHelper DetailsHelper { get; } + public IPackageOperationHelper OperationHelper { get; } + public IReadOnlyList Dependencies { get; } + + public NullPackageManager() + { + TaskLogger = new ManagerLogger(this); + var nullsource = NullSource.Instance; + SourcesHelper = new NullSourceHelper(); + DetailsHelper = new NullPkgDetailsHelper(); + OperationHelper = new NullPkgOperationHelper(); + Properties = new ManagerProperties + { + IsDummy = true, + Id = "unknown", + Name = CoreTools.Translate("Unknown"), + Description = "Unset", + IconId = IconType.Help, + ColorIconId = "Unset", + ExecutableFriendlyName = "Unset", + InstallVerb = "Unset", + UpdateVerb = "Unset", + UninstallVerb = "Unset", + KnownSources = [nullsource], + DefaultSource = nullsource, + }; + Capabilities = new ManagerCapabilities(); + Status = new ManagerStatus + { + ExecutablePath = "C:/file.exe", + ExecutableCallArgs = "Unset", + Found = false, + Version = "0", + }; + Dependencies = []; + } + + public IReadOnlyList FindPackages(string query) => + throw new NotImplementedException(); + + public IReadOnlyList GetAvailableUpdates() => throw new NotImplementedException(); + + public IReadOnlyList GetInstalledPackages() => + throw new NotImplementedException(); + + public void Initialize() => throw new NotImplementedException(); + + public bool IsEnabled() => throw new NotImplementedException(); + + public bool IsReady() => throw new NotImplementedException(); + + public void RefreshPackageIndexes() => throw new NotImplementedException(); + + public void AttemptFastRepair() => throw new NotImplementedException(); + + public IReadOnlyList FindCandidateExecutableFiles() => + throw new NotImplementedException(); + + public Tuple GetExecutableFile() => throw new NotImplementedException(); + } + + internal sealed class NullSourceHelper : IMultiSourceHelper + { + public ISourceFactory Factory => throw new NotImplementedException(); + + public string[] GetAddSourceParameters(IManagerSource source) => + throw new NotImplementedException(); + + public string[] GetRemoveSourceParameters(IManagerSource source) => + throw new NotImplementedException(); + + public OperationVeredict GetAddOperationVeredict( + IManagerSource source, + int ReturnCode, + string[] Output + ) => throw new NotImplementedException(); + + public OperationVeredict GetRemoveOperationVeredict( + IManagerSource source, + int ReturnCode, + string[] Output + ) => throw new NotImplementedException(); + + public IReadOnlyList GetSources() => throw new NotImplementedException(); + } + + internal sealed class NullPkgDetailsHelper : IPackageDetailsHelper + { + public void GetDetails(IPackageDetails details) => throw new NotImplementedException(); + + public IReadOnlyList GetVersions(IPackage package) => + throw new NotImplementedException(); + + public CacheableIcon? GetIcon(IPackage package) => throw new NotImplementedException(); + + public IReadOnlyList GetScreenshots(IPackage package) => + throw new NotImplementedException(); + + public string? GetInstallLocation(IPackage package) => throw new NotImplementedException(); + } + + internal sealed class NullPkgOperationHelper : IPackageOperationHelper + { + public IReadOnlyList GetParameters( + IPackage package, + InstallOptions options, + OperationType operation + ) => throw new NotImplementedException(); + + public OperationVeredict GetResult( + IPackage package, + OperationType operation, + IReadOnlyList processOutput, + int returnCode + ) => throw new NotImplementedException(); + } +} diff --git a/src/UniGetUI.PackageEngine.PackageManagerClasses/Manager/Classes/SourceFactory.cs b/src/UniGetUI.PackageEngine.PackageManagerClasses/Manager/Classes/SourceFactory.cs new file mode 100644 index 0000000..49dda43 --- /dev/null +++ b/src/UniGetUI.PackageEngine.PackageManagerClasses/Manager/Classes/SourceFactory.cs @@ -0,0 +1,70 @@ +using System.Collections.Concurrent; +using UniGetUI.PackageEngine.Interfaces; + +namespace UniGetUI.PackageEngine.Classes.Manager +{ + public class SourceFactory : ISourceFactory + { + private readonly IPackageManager __manager; + private readonly ConcurrentDictionary __reference; + private readonly Uri __default_uri = new("https://devolutions.net/unigetui"); + + public SourceFactory(IPackageManager manager) + { + __reference = []; + __manager = manager; + } + + public void Reset() + { + __reference.Clear(); + } + + /// + /// Returns the existing source for the given name, or creates a new one if it does not exist. + /// + /// The name of the source + /// A valid ManagerSource + public IManagerSource GetSourceOrDefault(string name) + { + if (__reference.TryGetValue(name, out IManagerSource? source)) + { + return source; + } + + ManagerSource new_source = new(__manager, name, __default_uri); + __reference.TryAdd(name, new_source); + return new_source; + } + + /// + /// Returns the existing source for the given name, or null if it does not exist. + /// + public IManagerSource? GetSourceIfExists(string name) + { + if (__reference.TryGetValue(name, out IManagerSource? source)) + { + return source; + } + + return null; + } + + public void AddSource(IManagerSource source) + { + if (!__reference.TryAdd(source.Name, source)) + { + IManagerSource existing_source = __reference[source.Name]; + if (existing_source.Url == __default_uri) + { + existing_source.ReplaceUrl(source.Url); + } + } + } + + public IManagerSource[] GetAvailableSources() + { + return __reference.Values.ToArray(); + } + } +} diff --git a/src/UniGetUI.PackageEngine.PackageManagerClasses/Manager/Helpers/ArpRegistryHelper.cs b/src/UniGetUI.PackageEngine.PackageManagerClasses/Manager/Helpers/ArpRegistryHelper.cs new file mode 100644 index 0000000..19433c4 --- /dev/null +++ b/src/UniGetUI.PackageEngine.PackageManagerClasses/Manager/Helpers/ArpRegistryHelper.cs @@ -0,0 +1,258 @@ +#if WINDOWS +using System.Text.RegularExpressions; +using Microsoft.Win32; +#endif + +namespace UniGetUI.PackageEngine.Classes.Manager.BaseProviders +{ + /// + /// Resolves the install location of a package from the Windows "Add/Remove programs" (ARP) + /// registry. This is a manager-agnostic fallback: any package that registered an uninstall + /// entry (which most Windows installers do, regardless of the manager that ran them) can be + /// located here when the manager's own logic cannot find the folder. On non-Windows platforms + /// every method is a no-op. + /// + public static partial class ArpRegistryHelper + { +#if WINDOWS + private const long CacheTtlMs = 30_000; + private static readonly Lock _lock = new(); + private static Dictionary? _index; // normalized DisplayName -> install folder + private static long _indexBuiltAt = long.MinValue; + + private const string UninstallSubKey = + @"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall"; + + // Open both registry views explicitly (instead of relying on process bitness + a hard-coded + // WOW6432Node path) so 64-bit and 32-bit entries are indexed regardless of the process arch, + // including per-user 32-bit apps under HKCU. + private static readonly (RegistryHive Hive, RegistryView View)[] UninstallRoots = + [ + (RegistryHive.LocalMachine, RegistryView.Registry64), + (RegistryHive.LocalMachine, RegistryView.Registry32), + (RegistryHive.CurrentUser, RegistryView.Registry64), + (RegistryHive.CurrentUser, RegistryView.Registry32), + ]; + + /// + /// Resolves the install folder by matching the given candidate names against the system's + /// ARP display names. Returns null when no confident match has a resolvable folder. + /// + public static string? ResolveByName(params string?[] candidateNames) + { + var index = GetIndex(); + if (index.Count == 0) + return null; + + foreach (var name in candidateNames) + { + var target = Normalize(name); + if (target.Length < 3) + continue; + + // Exact normalized match is the most reliable. + if (index.TryGetValue(target, out var exact)) + return exact; + + // Otherwise accept only the ARP name being the package name plus a version/edition + // suffix (e.g. "Mozilla Firefox" vs "Mozilla Firefox (x64 en-US)" once normalized, + // or "7-Zip" vs "7-Zip 23.01"). The reverse direction — the package name merely + // starting with a shorter ARP name — is intentionally excluded, as it can resolve an + // unrelated app (e.g. a package "javascript-x" matching an ARP entry "Java"). + if (target.Length < 4) + continue; + foreach (var (key, location) in index) + if (key.StartsWith(target, StringComparison.Ordinal)) + return location; + } + + return null; + } + + /// + /// Resolves the install folder for a package whose Id encodes its registry location (as + /// produced by the WinGet LocalPC source), e.g. "ARP\Machine\X64\{key}". + /// + public static string? GetLocationFromEncodedId(string packageId) + { + var bits = packageId.Split('\\'); + if (bits.Length < 4) + return null; + + var hive = bits[1] == "Machine" ? RegistryHive.LocalMachine : RegistryHive.CurrentUser; + var view = bits[2] == "X86" ? RegistryView.Registry32 : RegistryView.Registry64; + + try + { + using var baseKey = RegistryKey.OpenBaseKey(hive, view); + using var entry = baseKey.OpenSubKey(UninstallSubKey + "\\" + bits[3]); + return entry is null ? null : ReadLocation(entry); + } + catch + { + return null; + } + } + + private static Dictionary GetIndex() + { + lock (_lock) + { + var now = Environment.TickCount64; + if (_index is null || now - _indexBuiltAt > CacheTtlMs) + { + _index = BuildIndex(); + _indexBuiltAt = now; + } + return _index; + } + } + + private static Dictionary BuildIndex() + { + var map = new Dictionary(StringComparer.Ordinal); + + foreach (var (hive, view) in UninstallRoots) + { + try + { + using var baseKey = RegistryKey.OpenBaseKey(hive, view); + using var root = baseKey.OpenSubKey(UninstallSubKey); + if (root is null) + continue; + + foreach (var name in root.GetSubKeyNames()) + { + try + { + using var entry = root.OpenSubKey(name); + if (entry?.GetValue("DisplayName") is not string displayName) + continue; + if ((entry.GetValue("SystemComponent") as int?) == 1) + continue; + + var normalized = Normalize(displayName); + if (normalized.Length < 3 || map.ContainsKey(normalized)) + continue; + + var location = ReadLocation(entry); + if (location is not null) + map[normalized] = location; + } + catch + { + // Skip unreadable entries. + } + } + } + catch + { + // Skip unreadable hives. + } + } + + return map; + } + + /// + /// Resolves the install folder from a single ARP entry, trying the most-to-least reliable + /// signals: the recorded InstallLocation, the folder of the DisplayIcon, then the folder of + /// the uninstaller (which for EXE/NSIS/Inno installers lives in the install directory). + /// + private static string? ReadLocation(RegistryKey entry) + { + // Registry values can contain unexpanded environment variables (e.g. %ProgramFiles%), + // so expand before testing/returning any path. + if (entry.GetValue("InstallLocation") is string rawLocation && rawLocation.Length > 0) + { + var location = Environment + .ExpandEnvironmentVariables(rawLocation) + .Trim() + .Trim('"') + .TrimEnd('\\'); + if (location.Length > 0 && Directory.Exists(location)) + return location; + } + + if (entry.GetValue("DisplayIcon") is string displayIcon && displayIcon.Length > 0) + { + var iconPath = Environment + .ExpandEnvironmentVariables(displayIcon) + .Split(',')[0] + .Trim() + .Trim('"'); + var dir = DirectoryOf(iconPath); + // MSI cached icons live under C:\Windows\Installer; never treat a system folder as + // an install location. + if (dir is not null && !IsSystemDirectory(dir)) + return dir; + } + + if (entry.GetValue("UninstallString") is string uninstall && uninstall.Length > 0) + { + var exe = ExtractExecutable(Environment.ExpandEnvironmentVariables(uninstall)); + if (exe is not null + && !Path.GetFileName(exe).Equals("msiexec.exe", StringComparison.OrdinalIgnoreCase)) + { + var dir = DirectoryOf(exe); + if (dir is not null && !IsSystemDirectory(dir)) + return dir; + } + } + + return null; + } + + private static string? DirectoryOf(string filePath) + { + try + { + var dir = Path.GetDirectoryName(filePath); + return !string.IsNullOrEmpty(dir) && Directory.Exists(dir) ? dir : null; + } + catch + { + return null; + } + } + + private static string? ExtractExecutable(string command) + { + command = command.Trim(); + if (command.StartsWith('"')) + { + var end = command.IndexOf('"', 1); + return end > 1 ? command[1..end] : null; + } + + var idx = command.IndexOf(".exe", StringComparison.OrdinalIgnoreCase); + return idx >= 0 ? command[..(idx + 4)] : command.Split(' ')[0]; + } + + private static bool IsSystemDirectory(string dir) + { + var windows = Environment.GetFolderPath(Environment.SpecialFolder.Windows); + return !string.IsNullOrEmpty(windows) + && dir.StartsWith(windows, StringComparison.OrdinalIgnoreCase); + } + + private static string Normalize(string? value) + { + if (string.IsNullOrWhiteSpace(value)) + return ""; + value = ParentheticalRegex().Replace(value, " "); + return NonAlphanumericRegex().Replace(value, "").ToLowerInvariant(); + } + + [GeneratedRegex(@"\([^)]*\)")] + private static partial Regex ParentheticalRegex(); + + [GeneratedRegex("[^a-zA-Z0-9]")] + private static partial Regex NonAlphanumericRegex(); +#else + public static string? ResolveByName(params string?[] candidateNames) => null; + + public static string? GetLocationFromEncodedId(string packageId) => null; +#endif + } +} diff --git a/src/UniGetUI.PackageEngine.PackageManagerClasses/Manager/Helpers/BasePkgDetailsHelper.cs b/src/UniGetUI.PackageEngine.PackageManagerClasses/Manager/Helpers/BasePkgDetailsHelper.cs new file mode 100644 index 0000000..b3d7669 --- /dev/null +++ b/src/UniGetUI.PackageEngine.PackageManagerClasses/Manager/Helpers/BasePkgDetailsHelper.cs @@ -0,0 +1,211 @@ +using UniGetUI.Core.IconEngine; +using UniGetUI.Core.Logging; +using UniGetUI.PackageEngine.Interfaces; +using UniGetUI.PackageEngine.Interfaces.ManagerProviders; + +namespace UniGetUI.PackageEngine.Classes.Manager.BaseProviders +{ + public abstract class BasePkgDetailsHelper : IPackageDetailsHelper + { + protected IPackageManager Manager; + + public BasePkgDetailsHelper(IPackageManager manager) + { + Manager = manager; + } + + public void GetDetails(IPackageDetails details) + { + if (!Manager.IsReady()) + { + Logger.Warn( + $"Manager {Manager.Name} is disabled but yet GetPackageDetails was called" + ); + return; + } + try + { + GetDetails_UnSafe(details); + Logger.Info( + $"Loaded details for package {details.Package.Id} on manager {Manager.Name}" + ); + } + catch (Exception e) + { + Logger.Error("Error finding installed packages on manager " + Manager.Name); + Logger.Error(e); + } + } + + public IReadOnlyList GetVersions(IPackage package) + { + if (!Manager.IsReady()) + { + Logger.Warn( + $"Manager {Manager.Name} is disabled but yet GetPackageVersions was called" + ); + return []; + } + try + { + if (Manager.Capabilities.SupportsCustomVersions) + { + var result = GetInstallableVersions_UnSafe(package); + Logger.Debug( + $"Found {result.Count} versions for package Id={package.Id} on manager {Manager.Name}" + ); + return result; + } + + Logger.Warn( + $"Manager {Manager.Name} does not support version retrieving, this method should have not been called" + ); + return []; + } + catch (Exception e) + { + Logger.Error( + $"Error finding available package versions for package {package.Id} on manager " + + Manager.Name + ); + Logger.Error(e); + return []; + } + } + + public CacheableIcon? GetIcon(IPackage package) + { + try + { + // Load native icon + if (Manager.Capabilities.SupportsCustomPackageIcons) + { + var nativeIcon = GetIcon_UnSafe(package); + if (nativeIcon is not null) + { + return nativeIcon; + } + } + + foreach (string lookupId in GetIconDatabaseLookupIds(package)) + { + string? iconUrl = IconDatabase.Instance.GetIconUrlForId(lookupId); + if (iconUrl is not null) + return new CacheableIcon(new Uri(iconUrl)); + } + + return null; + } + catch (Exception e) + { + Logger.Error( + $"Error when loading the package icon for the package {package.Id} on manager " + + Manager.Name + ); + Logger.Error(e); + return null; + } + } + + public IReadOnlyList GetScreenshots(IPackage package) + { + try + { + IReadOnlyList URIs = []; + + // Load native screenshots + if (Manager.Capabilities.SupportsCustomPackageScreenshots) + { + URIs = GetScreenshots_UnSafe(package); + } + else + { + Logger.Debug($"Manager {Manager.Name} does not support native screenshots"); + } + + // Try to get exact screenshots for this package + if (!URIs.Any()) + { + foreach (string lookupId in GetIconDatabaseLookupIds(package)) + { + string[] UrlArray = IconDatabase.Instance.GetScreenshotsUrlForId( + lookupId + ); + List UriList = []; + foreach (string url in UrlArray) + { + if (url != "") + UriList.Add(new Uri(url)); + } + + if (UriList.Count > 0) + { + URIs = UriList; + break; + } + } + } + + Logger.Info($"Found {URIs.Count} screenshots for package Id={package.Id}"); + return URIs; + } + catch (Exception e) + { + Logger.Error( + $"Error when loading the package icon for the package {package.Id} on manager " + + Manager.Name + ); + Logger.Error(e); + return []; + } + } + + private IEnumerable GetIconDatabaseLookupIds(IPackage package) + { + yield return Manager.Name + "." + package.Id; + + if (Manager.Name == "Winget") + { + yield return package.Id; + } + + yield return package.GetIconId(); + } + + protected abstract void GetDetails_UnSafe(IPackageDetails details); + protected abstract IReadOnlyList GetInstallableVersions_UnSafe(IPackage package); + protected abstract CacheableIcon? GetIcon_UnSafe(IPackage package); + protected abstract IReadOnlyList GetScreenshots_UnSafe(IPackage package); + protected abstract string? GetInstallLocation_UnSafe(IPackage package); + + public string? GetInstallLocation(IPackage package) + { + try + { + string? path = GetInstallLocation_UnSafe(package); + if (path is not null && !Directory.Exists(path)) + { + Logger.Warn( + $"Path returned by the package manager \"{path}\" did not exist while loading package install location for package Id={package.Id} with Manager={package.Manager.Name}" + ); + path = null; + } + + // Manager-agnostic fallback: most Windows installers register an "Add/Remove + // programs" entry regardless of which manager ran them, so try to locate the + // package there when the manager's own logic came up empty. No-op on non-Windows. + path ??= ArpRegistryHelper.ResolveByName(package.Name, package.Id); + + return path; + } + catch (Exception ex) + { + Logger.Error( + $"An error occurred while loading package install location for package Id={package.Id} with Manager={package.Manager.Name}" + ); + Logger.Error(ex); + return null; + } + } + } +} diff --git a/src/UniGetUI.PackageEngine.PackageManagerClasses/Manager/Helpers/BasePkgOperationHelper.cs b/src/UniGetUI.PackageEngine.PackageManagerClasses/Manager/Helpers/BasePkgOperationHelper.cs new file mode 100644 index 0000000..497bb9f --- /dev/null +++ b/src/UniGetUI.PackageEngine.PackageManagerClasses/Manager/Helpers/BasePkgOperationHelper.cs @@ -0,0 +1,69 @@ +using UniGetUI.Core.Logging; +using UniGetUI.PackageEngine.Enums; +using UniGetUI.PackageEngine.Interfaces; +using UniGetUI.PackageEngine.Interfaces.ManagerProviders; +using UniGetUI.PackageEngine.Serializable; + +namespace UniGetUI.PackageEngine.Classes.Manager.BaseProviders; + +public abstract class BasePkgOperationHelper : IPackageOperationHelper +{ + protected IPackageManager Manager; + + public BasePkgOperationHelper(IPackageManager manager) + { + Manager = manager; + } + + protected abstract IReadOnlyList _getOperationParameters( + IPackage package, + InstallOptions options, + OperationType operation + ); + + protected abstract OperationVeredict _getOperationResult( + IPackage package, + OperationType operation, + IReadOnlyList processOutput, + int returnCode + ); + + public IReadOnlyList GetParameters( + IPackage package, + InstallOptions options, + OperationType operation + ) + { + var parameters = _getOperationParameters(package, options, operation); + Logger.Info( + $"Loaded operation parameters for package id={package.Id} on manager {Manager.Name} and operation {operation}: " + + string.Join(' ', parameters) + ); + return parameters.Where(x => x.Any()).ToArray(); + } + + public OperationVeredict GetResult( + IPackage package, + OperationType operation, + IReadOnlyList processOutput, + int returnCode + ) + { + if ( + returnCode is 999 + && ( + !processOutput.Any() + || processOutput[processOutput.Count - 1] + == "Error: The operation was canceled by the user." + ) + ) + { + Logger.Warn( + "Elevator [or GSudo] UAC prompt was canceled, not showing error message..." + ); + return OperationVeredict.Canceled; + } + + return _getOperationResult(package, operation, processOutput, returnCode); + } +} diff --git a/src/UniGetUI.PackageEngine.PackageManagerClasses/Manager/Helpers/BaseSourceHelper.cs b/src/UniGetUI.PackageEngine.PackageManagerClasses/Manager/Helpers/BaseSourceHelper.cs new file mode 100644 index 0000000..d44166e --- /dev/null +++ b/src/UniGetUI.PackageEngine.PackageManagerClasses/Manager/Helpers/BaseSourceHelper.cs @@ -0,0 +1,124 @@ +using UniGetUI.Core.Classes; +using UniGetUI.Core.Logging; +using UniGetUI.Core.SettingsEngine; +using UniGetUI.Core.Tools; +using UniGetUI.PackageEngine.Enums; +using UniGetUI.PackageEngine.Interfaces; +using UniGetUI.PackageEngine.Interfaces.ManagerProviders; + +namespace UniGetUI.PackageEngine.Classes.Manager.Providers +{ + public abstract class BaseSourceHelper : IMultiSourceHelper + { + private const int PackageListingTaskTimeout = 60; + + public ISourceFactory Factory { get; } + protected IPackageManager Manager; + + public BaseSourceHelper(IPackageManager manager) + { + Manager = manager; + Factory = new SourceFactory(manager); + } + + public abstract string[] GetAddSourceParameters(IManagerSource source); + public abstract string[] GetRemoveSourceParameters(IManagerSource source); + protected abstract OperationVeredict _getAddSourceOperationVeredict( + IManagerSource source, + int ReturnCode, + string[] Output + ); + protected abstract OperationVeredict _getRemoveSourceOperationVeredict( + IManagerSource source, + int ReturnCode, + string[] Output + ); + + public OperationVeredict GetAddOperationVeredict( + IManagerSource source, + int ReturnCode, + string[] Output + ) + { + TaskRecycler>.RemoveFromCache(_getSources); + if ( + ReturnCode is 999 + && Output.Last() == "Error: The operation was canceled by the user." + ) + { + Logger.Warn( + "Elevator [or GSudo] UAC prompt was canceled, not showing error message..." + ); + return OperationVeredict.Canceled; + } + return _getAddSourceOperationVeredict(source, ReturnCode, Output); + } + + public OperationVeredict GetRemoveOperationVeredict( + IManagerSource source, + int ReturnCode, + string[] Output + ) + { + TaskRecycler>.RemoveFromCache(_getSources); + if ( + ReturnCode is 999 + && Output.Last() == "Error: The operation was canceled by the user." + ) + { + Logger.Warn( + "Elevator [or GSudo] UAC prompt was canceled, not showing error message..." + ); + return OperationVeredict.Canceled; + } + return _getRemoveSourceOperationVeredict(source, ReturnCode, Output); + } + + /// + /// Loads the sources for the manager. This method SHOULD NOT handle exceptions + /// + protected abstract IReadOnlyList GetSources_UnSafe(); + + public virtual IReadOnlyList GetSources() => + TaskRecycler>.RunOrAttach(_getSources, 15); + + public virtual IReadOnlyList _getSources() + { + try + { + var task = Task.Run(GetSources_UnSafe); + if (!task.Wait(TimeSpan.FromSeconds(PackageListingTaskTimeout))) + { + if (!Settings.Get(Settings.K.DisableTimeoutOnPackageListingTasks)) + { + CoreTools.FinalizeDangerousTask(task); + throw new TimeoutException( + $"Task _getInstalledPackages for manager {Manager.Name} did not finish after " + + $"{PackageListingTaskTimeout} seconds, aborting. You may disable " + + $"timeouts from UniGetUI Advanced Settings" + ); + } + + task.Wait(); + } + + var sources = task.Result; + Factory.Reset(); + + foreach (IManagerSource source in sources) + { + Factory.AddSource(source); + } + + Logger.Debug($"Loaded {sources.Count} sources for manager {Manager.Name}"); + return sources; + } + catch (Exception e) + { + Logger.Error("Error finding sources for manager " + Manager.Name); + Logger.Error(e); + return []; + } + } + } +} diff --git a/src/UniGetUI.PackageEngine.PackageManagerClasses/Manager/PackageManager.cs b/src/UniGetUI.PackageEngine.PackageManagerClasses/Manager/PackageManager.cs new file mode 100644 index 0000000..9070b56 --- /dev/null +++ b/src/UniGetUI.PackageEngine.PackageManagerClasses/Manager/PackageManager.cs @@ -0,0 +1,507 @@ +using System.Diagnostics; +using System.Text; +using UniGetUI.Core.Logging; +using UniGetUI.Core.SettingsEngine; +using UniGetUI.Core.SettingsEngine.SecureSettings; +using UniGetUI.Core.Tools; +using UniGetUI.PackageEngine.Classes.Manager; +using UniGetUI.PackageEngine.Classes.Manager.Classes; +using UniGetUI.PackageEngine.Classes.Manager.ManagerHelpers; +using UniGetUI.PackageEngine.Classes.Packages; +using UniGetUI.PackageEngine.Interfaces; +using UniGetUI.PackageEngine.Interfaces.ManagerProviders; +using UniGetUI.PackageEngine.ManagerClasses.Classes; +using UniGetUI.PackageEngine.PackageClasses; + +namespace UniGetUI.PackageEngine.ManagerClasses.Manager +{ + public abstract class PackageManager : IPackageManager + { + private const int PackageListingTaskTimeout = 60; + + public ManagerProperties Properties { get; set; } = new(IsDummy: true); + public ManagerCapabilities Capabilities { get; set; } = new(IsDummy: true); + public ManagerStatus Status { get; set; } = new() { Found = false }; + public string Id + { + get => string.IsNullOrWhiteSpace(Properties.Id) ? Name : Properties.Id; + } + public string Name + { + get => Properties.Name; + } + public string DisplayName + { + get => Properties.DisplayName ?? Name; + } + public IManagerSource DefaultSource + { + get => Properties.DefaultSource; + } + public IManagerLogger TaskLogger { get; } + public IReadOnlyList Dependencies { get; protected set; } = []; + public IMultiSourceHelper SourcesHelper { get; protected set; } = new NullSourceHelper(); + public IPackageDetailsHelper DetailsHelper { get; protected set; } = null!; + public IPackageOperationHelper OperationHelper { get; protected set; } = null!; + public virtual Encoding OutputEncoding => Encoding.UTF8; + + private readonly bool _baseConstructorCalled; + private bool _ready; + + public PackageManager() + { + _baseConstructorCalled = true; + TaskLogger = new ManagerLogger(this); + } + + private static void Throw(string message) + { + throw new InvalidDataException(message); + } + + protected abstract void _loadManagerExecutableFile( + out bool found, + out string path, + out string callArguments + ); + protected abstract void _loadManagerVersion(out string version); + + protected virtual void _performExtraLoadingSteps() { } + + public virtual void Initialize() + { + try + { + _ready = false; + _ensurePropertlyConstructed(); + + if (!IsEnabled()) + { // Do NOT initialise disabled package managers + Status = new() { Version = CoreTools.Translate("{0} is disabled", DisplayName) }; + Logger.ImportantInfo($"{Name} is not enabled"); + return; + } + + // Find package manager executable + _loadManagerExecutableFile( + out bool found, + out string path, + out string callArguments + ); + Status = new ManagerStatus(); + Status.Found = found; + Status.ExecutablePath = path; + Status.ExecutableCallArgs = callArguments; + + if (!Status.Found) + { // Do not load version of managers that were not found + Status.Version = CoreTools + .Translate("{pm} was not found!") + .Replace("{pm}", DisplayName) + .Trim('!'); + Logger.Error($"{Name} is enabled but was not found on the system!"); + return; + } + + Logger.ImportantInfo($"{Name} is enabled and was found on {path}"); + + // Load manager version + _loadManagerVersion(out string version); + Status.Version = version; + _logManagerInfo(); + + // Finish initialization + _performExtraLoadingSteps(); + _ready = true; + _initializeSources(); + } + catch (Exception ex) + { + Logger.Error($"An error occurred while initialising package manager {Name}"); + Logger.Error(ex); + } + } + + /// + /// This serves to ensure that the implemented hasn't messed up any crucial + /// details on the implementation + /// + private void _ensurePropertlyConstructed() + { + if (!_baseConstructorCalled) + Throw($"The Manager {Properties.Name} has not called the base constructor."); + if (Capabilities.IsDummy) + Throw( + $"The current instance of PackageManager with name ${Properties.Name} does not have a valid Capabilities object" + ); + if (Properties.IsDummy) + Throw( + $"The current instance of PackageManager with name ${Properties.Name} does not have a valid Properties object" + ); + + if (OperationHelper is NullPkgOperationHelper) + Throw($"Manager {Name} does not have an OperationProvider"); + if (DetailsHelper is NullPkgDetailsHelper) + Throw($"Manager {Name} does not have a valid DetailsHelper"); + + if (Capabilities.SupportsCustomSources && SourcesHelper is NullSourceHelper) + Throw( + $"Manager {Name} has been declared as SupportsCustomSources but has no helper associated with it" + ); + } + + /// + /// Load and prepare manager sources sources + /// + private void _initializeSources() + { + // Sources that are instantiated before Manager's DisplayName property will have invalid DisplayName + // To prevent loading it on runtime, the string is cached internally and will only be reloaded when needed to + Properties.DefaultSource.RefreshSourceNames(); + foreach (var source in Properties.KnownSources) + { + source.RefreshSourceNames(); + } + + if (Capabilities.SupportsCustomSources) + { + // SourcesHelper.GetSources() will handle saving the found sources to the internal registry + SourcesHelper.GetSources(); + } + } + + private void _logManagerInfo() + { + string LogData = $""" + ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ + █▀▀▀▀▀▀▀▀▀▀▀▀▀ MANAGER LOADED ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀ + █ Name: {DisplayName} (aka {Name}) + █ Executable name: "{Properties.ExecutableFriendlyName}" + █ Executable path: "{Status.ExecutablePath}" + █ Call arguments: "{Status.ExecutableCallArgs}" + █ Version: {Status.Version.Trim().Replace("\n", "\n█ ")} + █ + █ {DisplayName} is enabled and ready to go. + ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀ + """; + Logger.Info(LogData); + } + + /// + /// Returns a list of paths that could be used for this package manager. + /// For example, if you have three Pythons installed on your system, this would return those three Pythons. + /// + /// A tuple containing: a boolean that represents whether the path was found or not; the path to the file if found. + public abstract IReadOnlyList FindCandidateExecutableFiles(); + + public Tuple GetExecutableFile() + { + var candidates = FindCandidateExecutableFiles(); + + // If custom package manager paths are DISABLED, get the first one (as old UniGetUI did) and return it. + if (!SecureSettings.Get(SecureSettings.K.AllowCustomManagerPaths)) + { + if (candidates.Count == 0) + { + // No paths were found + return new(false, ""); + } + + return new(true, candidates[0]); + } + else + { + string? exeSelection = Settings.GetDictionaryItem( + Settings.K.ManagerPaths, + Name + ); + // If there is no executable selection for this package manager + if (string.IsNullOrEmpty(exeSelection)) + { + if (candidates.Count == 0) + { + // No paths were found + return new(false, ""); + } + + return new(true, candidates[0]); + } + else if (!File.Exists(exeSelection)) + { + Logger.Error( + $"The selected executable path {exeSelection} for manager {Name} does not exist, the default one will be used if available..." + ); + } + + else + { + return new(true, exeSelection); + } + + if (candidates.Count == 0) + { + // No paths were found + return new(false, ""); + } + + return new(true, candidates[0]); + } + } + + /// + /// Returns true if the manager is enabled, false otherwise + /// + public bool IsEnabled() + { + return !Settings.GetDictionaryItem(Settings.K.DisabledManagers, Name); + } + + /// + /// Returns true if the manager is enabled and available (the required executable files were found). Returns false otherwise + /// + public bool IsReady() + { + return _ready && IsEnabled() && Status.Found; + } + + // Opt out (override => false) when AttemptFastRepair can't recover a timed-out query (issue #4974). + protected virtual bool RetryListingTasksOnTimeout => true; + + // Processes started by the current listing task, so a timeout can kill them instead of orphaning them. + private readonly AsyncLocal?> _listingProcesses = new(); + + // Lets a listing task register a process for kill-on-timeout. No-op when outside a listing task. + protected void RegisterListingProcess(Process process) + { + List? processes = _listingProcesses.Value; + if (processes is null) + return; + lock (processes) + processes.Add(process); + } + + private static void KillListingProcesses(List processes) + { + lock (processes) + foreach (Process p in processes) + { + try + { + if (!p.HasExited) + p.Kill(entireProcessTree: true); + } + catch (Exception ex) + { + Logger.Warn($"Could not kill a timed-out process tree: {ex.Message}"); + } + } + } + + private T RunListingTaskWithTimeout(Func method, string taskName) + { + List processes = []; + var task = Task.Run(() => + { + _listingProcesses.Value = processes; + return method(); + }); + + if (!task.Wait(TimeSpan.FromSeconds(PackageListingTaskTimeout))) + { + if (!Settings.Get(Settings.K.DisableTimeoutOnPackageListingTasks)) + { + KillListingProcesses(processes); + CoreTools.FinalizeDangerousTask(task); + throw new TimeoutException( + $"Task {taskName} for manager {Name} did not finish after " + + $"{PackageListingTaskTimeout} seconds, aborting. You may disable " + + $"timeouts from UniGetUI Advanced Settings" + ); + } + + task.Wait(); + } + + return task.GetAwaiter().GetResult(); + } + + /// + /// Returns an array of Package objects that the manager lists for the given query. Depending on the manager, the list may + /// also include similar results. This method is fail-safe and will return an empty array if an error occurs. + /// + public IReadOnlyList FindPackages(string query) => _findPackages(query, false); + + private IReadOnlyList _findPackages(string query, bool SecondAttempt) + { + if (!IsReady()) + { + Logger.Warn($"Manager {Name} is disabled but yet FindPackages was called"); + return []; + } + try + { + var packages = RunListingTaskWithTimeout( + () => FindPackages_UnSafe(query), + "_findPackages" + ); + Logger.Info( + $"Found {packages.Count} available packages from {Name} with the query {query}" + ); + return packages; + } + catch (Exception e) + { + while (e is AggregateException) + e = e.InnerException ?? new InvalidOperationException("How did we get here?"); + + if (!SecondAttempt && (RetryListingTasksOnTimeout || e is not TimeoutException)) + { + Logger.Warn( + $"Manager {DisplayName} failed to find packages with exception {e.GetType().Name}: {e.Message}" + ); + Logger.Warn( + $"Since this was the first attempt, {Name}.AttemptFastRepair() will be called and the procedure will be restarted" + ); + AttemptFastRepair(); + return _findPackages(query, true); + } + + Logger.Error("Error finding packages on manager " + Name + " with query " + query); + Logger.Error(e); + return []; + } + } + + /// + /// Returns an array of UpgradablePackage objects that represent the available updates reported by the manager. + /// This method is fail-safe and will return an empty array if an error occurs. + /// + public IReadOnlyList GetAvailableUpdates() => _getAvailableUpdates(false); + + private IReadOnlyList _getAvailableUpdates(bool SecondAttempt) + { + if (!IsReady()) + { + Logger.Warn($"Manager {Name} is disabled but yet GetAvailableUpdates was called"); + return []; + } + try + { + Task.Run(RefreshPackageIndexes) + .Wait(TimeSpan.FromSeconds(PackageListingTaskTimeout)); + + var packages = RunListingTaskWithTimeout( + GetAvailableUpdates_UnSafe, + "_getAvailableUpdates" + ); + Logger.Info($"Found {packages.Count} available updates from {Name}"); + return packages; + } + catch (Exception e) + { + while (e is AggregateException) + e = e.InnerException ?? new InvalidOperationException("How did we get here?"); + + if (!SecondAttempt && (RetryListingTasksOnTimeout || e is not TimeoutException)) + { + Logger.Warn( + $"Manager {DisplayName} failed to list available updates with exception {e.GetType().Name}: {e.Message}" + ); + Logger.Warn( + $"Since this was the first attempt, {Name}.AttemptFastRepair() will be called and the procedure will be restarted" + ); + AttemptFastRepair(); + return _getAvailableUpdates(true); + } + + Logger.Error("Error finding updates on manager " + Name); + Logger.Error(e); + return []; + } + } + + /// + /// Returns an array of Package objects that represent the installed reported by the manager. + /// This method is fail-safe and will return an empty array if an error occurs. + /// + public IReadOnlyList GetInstalledPackages() => _getInstalledPackages(false); + + private IReadOnlyList _getInstalledPackages(bool SecondAttempt) + { + if (!IsReady()) + { + Logger.Warn($"Manager {Name} is disabled but yet GetInstalledPackages was called"); + return []; + } + try + { + var packages = RunListingTaskWithTimeout( + GetInstalledPackages_UnSafe, + "_getInstalledPackages" + ); + Logger.Info($"Found {packages.Count} installed packages from {Name}"); + return packages; + } + catch (Exception e) + { + while (e is AggregateException) + e = e.InnerException ?? new InvalidOperationException("How did we get here?"); + + if (!SecondAttempt && (RetryListingTasksOnTimeout || e is not TimeoutException)) + { + Logger.Warn( + $"Manager {DisplayName} failed to list installed packages with exception {e.GetType().Name}: {e.Message}" + ); + Logger.Warn( + $"Since this was the first attempt, {Name}.AttemptFastRepair() will be called and the procedure will be restarted" + ); + AttemptFastRepair(); + return _getInstalledPackages(true); + } + + Logger.Error("Error finding installed packages on manager " + Name); + Logger.Error(e); + return []; + } + } + + /// + /// Returns the available packages to install for the given query. + /// Each manager MUST implement this method. + /// + /// The query string to search for + /// An array of Package objects + protected abstract IReadOnlyList FindPackages_UnSafe(string query); + + /// + /// Returns the available updates reported by the manager. + /// Each manager MUST implement this method. + /// + /// An array of UpgradablePackage objects + protected abstract IReadOnlyList GetAvailableUpdates_UnSafe(); + + /// + /// Returns an array of Package objects containing the installed packages reported by the manager. + /// Each manager MUST implement this method. + /// + /// An array of Package objects + protected abstract IReadOnlyList GetInstalledPackages_UnSafe(); + + /// + /// Refreshes the Package Manager sources/indexes + /// Each manager MUST implement this method. + /// + public virtual void RefreshPackageIndexes() + { + Logger.Debug($"Manager {Name} has not implemented RefreshPackageIndexes"); + } + + /// + /// Attempt a live, fast, repair method when an exception occurs (for example, reconnect to COM Server) + /// + public virtual void AttemptFastRepair() + { + Logger.Debug($"Manager {Name} has not implemented AttemptFastRepair"); + } + } +} diff --git a/src/UniGetUI.PackageEngine.PackageManagerClasses/Packages/Classes/DesktopShortcutsDatabase.cs b/src/UniGetUI.PackageEngine.PackageManagerClasses/Packages/Classes/DesktopShortcutsDatabase.cs new file mode 100644 index 0000000..bdad20e --- /dev/null +++ b/src/UniGetUI.PackageEngine.PackageManagerClasses/Packages/Classes/DesktopShortcutsDatabase.cs @@ -0,0 +1,240 @@ +using UniGetUI.Core.Logging; +using UniGetUI.Core.SettingsEngine; + +namespace UniGetUI.PackageEngine.Classes.Packages.Classes; + +public static class DesktopShortcutsDatabase +{ + public enum Status + { + Maintain, // The user has explicitly requested this shortcut not be deleted + Unknown, // The user has not said whether they want this shortcut to be deleted + Delete, // The user has allowed the shortcut to be deleted + } + + private static readonly List UnknownShortcuts = []; + + public static IReadOnlyDictionary GetDatabase() + { + return Settings.GetDictionary(Settings.K.DeletableDesktopShortcuts) + ?? new Dictionary(); + } + + public static void ResetDatabase() + { + Settings.ClearDictionary(Settings.K.DeletableDesktopShortcuts); + } + + /// + /// Adds a desktop shortcut to the deletable desktop shortcuts database + /// + /// The path of the shortcut to delete + /// The status to set + public static void AddToDatabase(string shortcutPath, Status shortcutStatus) + { + if (shortcutStatus is Status.Unknown) + Settings.RemoveDictionaryKey( + Settings.K.DeletableDesktopShortcuts, + shortcutPath + ); + else + Settings.SetDictionaryItem( + Settings.K.DeletableDesktopShortcuts, + shortcutPath, + shortcutStatus is Status.Delete + ); + } + + /// + /// Attempts to remove the given shortcut path from the database + /// + /// The path of the shortcut to delete + /// True if the shortcut was removed, false if it was not there from the beginning + public static bool Remove(string shortcutPath) + { + // Remove the entry if present + if ( + Settings.DictionaryContainsKey( + Settings.K.DeletableDesktopShortcuts, + shortcutPath + ) + ) + { + // Remove the entry and propagate changes to disk + Settings.SetDictionaryItem(Settings.K.DeletableDesktopShortcuts, shortcutPath, false); + return true; + } + + // Do nothing if the entry was not there + Logger.Warn( + $"Attempted to remove from deletable desktop shortcuts a shortcut {{shortcutPath={shortcutPath}}} that was not found there" + ); + return false; + } + + /// + /// Attempts to delete the given shortcut path off the disk + /// + /// The path of the shortcut to delete + /// True if the shortcut was deleted, false if it was not (or didn't exist) + public static bool DeleteFromDisk(string shortcutPath) + { + Logger.Info("Deleting shortcut " + shortcutPath); + try + { + File.Delete(shortcutPath); + return true; + } + catch (Exception e) + { + Logger.Error($"Failed to delete shortcut {{shortcutPath={shortcutPath}}}: {e.Message}"); + return false; + } + } + + /// + /// Checks whether a given shortcut can be deleted. + /// If a user has provided on opinion on whether or not the shortcut can be deleted, it will be returned. + /// Otherwise, `ShortcutDeletableStatus.Unknown` will be returned and the shortcut should not be deleted + /// until a choice is given to the user and they explicitly request that it be deleted. + /// + /// The path of the shortcut to be deleted + /// The status of a shortcut + public static Status GetStatus(string shortcutPath) + { + // Check if the package is ignored + if ( + Settings.DictionaryContainsKey( + Settings.K.DeletableDesktopShortcuts, + shortcutPath + ) + ) + { + bool canDelete = Settings.GetDictionaryItem( + Settings.K.DeletableDesktopShortcuts, + shortcutPath + ); + return canDelete ? Status.Delete : Status.Maintain; + } + + return Status.Unknown; + } + + /// + /// Get a list of shortcuts (.lnk files only) currently on the user's desktop + /// + /// A list of desktop shortcut paths + public static List GetShortcutsOnDisk() + { + try + { + List shortcuts = []; + string UserDesktop = Environment.GetFolderPath( + Environment.SpecialFolder.DesktopDirectory + ); + string CommonDesktop = Environment.GetFolderPath( + Environment.SpecialFolder.CommonDesktopDirectory + ); + if (UserDesktop != "") + shortcuts.AddRange(Directory.EnumerateFiles(UserDesktop, "*.lnk")); + if (CommonDesktop != "") + shortcuts.AddRange(Directory.EnumerateFiles(CommonDesktop, "*.lnk")); + return shortcuts; + } + catch (Exception ex) + { + Logger.Error("Failed to load desktop shortcuts on disk"); + Logger.Error(ex); + return []; + } + } + + /// + /// Gets all the shortcuts exist on disk or/and on the database + /// + /// + public static List GetAllShortcuts() + { + var shortcuts = GetShortcutsOnDisk(); + + foreach (var item in GetDatabase()) + { + if (!shortcuts.Contains(item.Key)) + shortcuts.Add(item.Key); + } + + return shortcuts; + } + + /// + /// Remove a shortcut from the list of shortcuts whose deletion verdicts are unknown (as in, the user needs to be asked about deleting them when their operations finish) + /// + /// The path of the shortcut to be asked about deletion + /// True if it was found, false otherwise + public static bool RemoveFromUnknownShortcuts(string shortcutPath) + { + return UnknownShortcuts.Remove(shortcutPath); + } + + /// + /// Get the list of shortcuts whose deletion verdicts are unknown (as in, the user needs to be asked about deleting them when their operations finish) + /// + /// The list of shortcuts awaiting verdicts + public static List GetUnknownShortcuts() + { + return UnknownShortcuts; + } + + /// + /// Will handle the removal, if applicable, of any shortcut that is not present on the given PreviousShortCutList. + /// + /// The shortcuts that already existed + public static void HandleNewShortcuts(IReadOnlyList PreviousShortCutList) + { + bool DeleteUnknownShortcuts = Settings.Get(Settings.K.RemoveAllDesktopShortcuts); + HashSet PreviousShortcuts = [.. PreviousShortCutList]; + List CurrentShortcuts = GetShortcutsOnDisk(); + + foreach (string shortcut in CurrentShortcuts) + { + var status = GetStatus(shortcut); + if (status is Status.Maintain) + { + // Don't delete this shortcut, it has been set to be kept + } + else if (status is Status.Delete) + { + // If a shortcut is set to be deleted, delete it, + // even when it was not created during an UniGetUI operation + DeleteFromDisk(shortcut); + } + else if (status is Status.Unknown) + { + // If a shortcut has not been detected yet, and it + // existed before an operation started, then do nothing. + if (PreviousShortcuts.Contains(shortcut)) + continue; + + if (DeleteUnknownShortcuts) + { + // If the shortcut was created during an operation + // and autodelete is enabled, delete that icon + Logger.Warn( + $"New shortcut {shortcut} will be set for deletion (this shortcut was never seen before)" + ); + AddToDatabase(shortcut, Status.Delete); + DeleteFromDisk(shortcut); + } + else + { + // Mark the shortcut as unknown and prompt the user. + if (!UnknownShortcuts.Contains(shortcut)) + { + Logger.Info($"Marking the shortcut {shortcut} to be asked to be deleted"); + UnknownShortcuts.Add(shortcut); + } + } + } + } + } +} diff --git a/src/UniGetUI.PackageEngine.PackageManagerClasses/Packages/Classes/IgnoredUpdatesDatabase.cs b/src/UniGetUI.PackageEngine.PackageManagerClasses/Packages/Classes/IgnoredUpdatesDatabase.cs new file mode 100644 index 0000000..577ccea --- /dev/null +++ b/src/UniGetUI.PackageEngine.PackageManagerClasses/Packages/Classes/IgnoredUpdatesDatabase.cs @@ -0,0 +1,201 @@ +using UniGetUI.Core.Logging; +using UniGetUI.Core.SettingsEngine; +using UniGetUI.Core.Tools; +using UniGetUI.PackageEngine.Interfaces; + +namespace UniGetUI.PackageEngine.Classes.Packages.Classes; + +public static class IgnoredUpdatesDatabase +{ + public class PauseTime + { + private int _daysTill; + public int Months + { + get { return Weeks / 4; } + set { Weeks = value * 4; } + } + public int Weeks + { + get { return Days / 7; } + set { Days = value * 7; } + } + public int Days + { + get { return _daysTill; } + set { _daysTill = value; } + } + + public string GetDateFromNow() + { + DateTime NewTime = DateTime.Now.AddDays(_daysTill); + return NewTime.ToString("yyyy-MM-dd"); + } + + public void Parse(string Date) + { + try + { + DateTime ParsedDate = DateTime.ParseExact( + Date, + "yyyy-MM-dd", + System.Globalization.CultureInfo.InvariantCulture + ); + DateTime Now = DateTime.Now; + if (ParsedDate > Now) + { + _daysTill = (int)(ParsedDate - Now).TotalDays; + } + else + { + _daysTill = (int)(Now - ParsedDate).TotalDays; + } + } + catch (FormatException ex) + { + Logger.Error($"Couldn't parse date {Date}:"); + Logger.Error(ex); + } + } + + public string StringRepresentation() + { + if (Months >= 12 && Months % 12 == 0) + { + int Years = Months / 12; + if (Years > 1) + return CoreTools.Translate("{0} years", Years); + return CoreTools.Translate("1 year"); + } + + if (Months >= 1) + { + if (Months > 1) + return CoreTools.Translate("{0} months", Months); + return CoreTools.Translate("1 month"); + } + + if (Weeks >= 1) + { + if (Weeks > 1) + return CoreTools.Translate("{0} weeks", Weeks); + return CoreTools.Translate("1 week"); + } + + if (Days != 1) + return CoreTools.Translate("{0} days", Days); + return CoreTools.Translate("1 day"); + } + } + + public static IReadOnlyDictionary GetDatabase() + { + return Settings + .GetDictionary(Settings.K.IgnoredPackageUpdates) + ?.Where(kvp => kvp.Value is not null) + .ToDictionary(kvp => kvp.Key, kvp => kvp.Value!) + ?? new Dictionary(); + } + + public static string GetIgnoredIdForPackage(IPackage package) + { + return $"{package.Manager.Properties.Name.ToLower()}\\{package.Id}"; + } + + /// + /// Adds a package to the ignored packages database + /// + /// The Ignored Identifier to check + /// The version to ignore. Use wildcard (`*`) to ignore all versions + public static void Add(string ignoredId, string version = "*") + { + Settings.SetDictionaryItem(Settings.K.IgnoredPackageUpdates, ignoredId, version); + } + + /// + /// Attempts to remove the given package from the database + /// + /// The Ignored Identifier to check + /// True if the package was removed, false if it was not there from the beginning + public static bool Remove(string ignoredId) + { + // Remove the entry if present + if ( + Settings.DictionaryContainsKey( + Settings.K.IgnoredPackageUpdates, + ignoredId + ) + ) + { + // Remove the entry and propagate changes to disk + return Settings.RemoveDictionaryKey( + Settings.K.IgnoredPackageUpdates, + ignoredId + ) != null; + } + + // Do nothing if the entry was not there + Logger.Warn( + $"Attempted to remove from ignored updates a package {{ignoredId={ignoredId}}} that was not found there" + ); + return false; + } + + /// + /// Checks whether a package version is ignored. + /// A package version is considered ignored when: + /// a) All versions for that package are ignored. + /// b) That specific version is ignored + /// + /// You may use the wildcard (`*`) as the version to check if + /// all versions are ignored. + /// + /// The Ignored Identifier to check + /// The version to check + /// True if the package is ignored, false otherwise + public static bool HasUpdatesIgnored(string ignoredId, string version = "*") + { + string? ignoredVersion = Settings.GetDictionaryItem( + Settings.K.IgnoredPackageUpdates, + ignoredId + ); + + if (ignoredVersion != null && ignoredVersion.StartsWith("<")) + { + try + { + var ignoreDate = DateTime.ParseExact( + ignoredVersion[1..], + "yyyy-MM-dd", + System.Globalization.CultureInfo.InvariantCulture + ); + if (ignoreDate > DateTime.Now) + return true; + Remove(ignoredId); + } + catch (FormatException ex) + { + Logger.Error($"Couldn't parse update ignoration {ignoredVersion}:"); + Logger.Error(ex); + } + } + + // Check if the package is ignored + return ignoredVersion == "*" || ignoredVersion == version; + } + + /// + /// Retrieves the ignored version for a package + /// + /// The Ignored Identifier to check + /// The ignored version, as a string + /// If **all** versions are ignored, the wildcard (`*`) will be returned. + /// If **no** versions are ignored, null will be returned. + public static string? GetIgnoredVersion(string ignoredId) + { + return Settings.GetDictionaryItem( + Settings.K.IgnoredPackageUpdates, + ignoredId + ); + } +} diff --git a/src/UniGetUI.PackageEngine.PackageManagerClasses/Packages/Classes/InstallOptionsFactory.cs b/src/UniGetUI.PackageEngine.PackageManagerClasses/Packages/Classes/InstallOptionsFactory.cs new file mode 100644 index 0000000..2bc13c9 --- /dev/null +++ b/src/UniGetUI.PackageEngine.PackageManagerClasses/Packages/Classes/InstallOptionsFactory.cs @@ -0,0 +1,309 @@ +using System.Collections.Concurrent; +using System.Text.Json; +using System.Text.Json.Nodes; +using UniGetUI.Core.Data; +using UniGetUI.Core.Logging; +using UniGetUI.Core.SettingsEngine.SecureSettings; +using UniGetUI.Core.Tools; +using UniGetUI.PackageEngine.Interfaces; +using UniGetUI.PackageEngine.Serializable; + +namespace UniGetUI.PackageEngine.PackageClasses +{ + /// + /// This class represents the options in which a package must be installed, updated or uninstalled. + /// + public static class InstallOptionsFactory + { + private static class StoragePath + { + public static string Get(IPackageManager manager) => + "GlobalValues." + manager.Name.Replace(" ", "").Replace(".", "") + ".json"; + + public static string Get(IPackage package) => + package.Manager.Name.Replace(" ", "").Replace(".", "") + "." + package.Id + ".json"; + } + + // Loading from disk (package and manager) + public static InstallOptions LoadForPackage(IPackage package) => + _loadFromDisk(StoragePath.Get(package)); + + public static Task LoadForPackageAsync(IPackage package) => + Task.Run(() => LoadForPackage(package)); + + public static InstallOptions LoadForManager(IPackageManager manager) => + _loadFromDisk(StoragePath.Get(manager)); + + public static Task LoadForManagerAsync(IPackageManager manager) => + Task.Run(() => LoadForManager(manager)); + + // Saving to disk (package and manager) + public static void SaveForPackage(InstallOptions options, IPackage package) => + _saveToDisk(options, StoragePath.Get(package)); + + public static Task SaveForPackageAsync(InstallOptions options, IPackage package) => + Task.Run(() => _saveToDisk(options, StoragePath.Get(package))); + + public static void SaveForManager(InstallOptions options, IPackageManager manager) => + _saveToDisk(options, StoragePath.Get(manager)); + + public static Task SaveForManagerAsync(InstallOptions options, IPackageManager manager) => + Task.Run(() => _saveToDisk(options, StoragePath.Get(manager))); + + /// + /// Loads the applicable InstallationOptions, and applies + /// any required transformations in case that generic options are being used + /// + /// The package whose options to load + /// Overrides the RunAsAdmin property + /// Overrides the Interactive property + /// Overrides the SkipHashCheck property + /// Overrides the RemoveDataOnUninstall property + /// In case of on-the-fly command generation, the PACKAGE + /// options can be overriden with this object + /// The applicable InstallOptions + public static InstallOptions LoadApplicable( + IPackage package, + bool? elevated = null, + bool? interactive = null, + bool? no_integrity = null, + bool? remove_data = null, + InstallOptions? overridePackageOptions = null + ) + { + var instance = overridePackageOptions ?? LoadForPackage(package); + if (!instance.OverridesNextLevelOpts) + { + Logger.Debug( + $"Package {package.Id} does not override options, will use package manager's default..." + ); + instance = LoadForManager(package.Manager); + + var legalizedId = CoreTools.MakeValidFileName(package.Id); + instance.CustomInstallLocation = instance.CustomInstallLocation.Replace( + "%PACKAGE%", + legalizedId + ); + } + + if (elevated is not null) + instance.RunAsAdministrator = (bool)elevated; + if (interactive is not null) + instance.InteractiveInstallation = (bool)interactive; + if (no_integrity is not null) + instance.SkipHashCheck = (bool)no_integrity; + if (remove_data is not null) + instance.RemoveDataOnUninstall = (bool)remove_data; + + return EnsureSecureOptions(instance); + } + + /// + /// Loads the applicable InstallationOptions, and applies + /// any required transformations in case that generic options are being used + /// + /// The package whose options to load + /// Overrides the RunAsAdmin property + /// Overrides the Interactive property + /// Overrides the SkipHashCheck property + /// Overrides the RemoveDataOnUninstall property + /// In case of on-the-fly command generation, the PACKAGE + /// options can be overriden with this object + /// The applicable InstallOptions + public static Task LoadApplicableAsync( + IPackage package, + bool? elevated = null, + bool? interactive = null, + bool? no_integrity = null, + bool? remove_data = null, + InstallOptions? overridePackageOptions = null + ) => + Task.Run(() => + LoadApplicable( + package, + elevated, + interactive, + no_integrity, + remove_data, + overridePackageOptions + ) + ); + + /* + * + * SAVE TO DISK MECHANISMS + * + */ + + private static readonly ConcurrentDictionary _optionsCache = new(); + + private static void _saveToDisk(InstallOptions options, string key) + { + try + { + var filePath = Path.Join(CoreData.UniGetUIInstallationOptionsDirectory, key); + _optionsCache[key] = options.Copy(); + + string fileContents = options.AsJsonString(); + File.WriteAllText(filePath, fileContents); + } + catch (Exception ex) + { + Logger.Error($"Could not save {key} options to disk"); + Logger.Error(ex); + } + } + + private static InstallOptions _loadFromDisk(string key) + { + var filePath = Path.Join(CoreData.UniGetUIInstallationOptionsDirectory, key); + try + { + InstallOptions serializedOptions; + if (_optionsCache.TryGetValue(key, out var cached)) + { + // If the wanted instance is already cached + return cached.Copy(); + } + else + { + if (!File.Exists(filePath)) + { + // If the file where it should be stored does not exist + _optionsCache[key] = new InstallOptions(); + return new InstallOptions(); + } + else + { + // If the options are not cached, and the save file exists + var rawData = File.ReadAllText(filePath); + JsonNode? jsonData = JsonNode.Parse(rawData); + ArgumentNullException.ThrowIfNull(jsonData); + serializedOptions = new InstallOptions(jsonData); + _optionsCache[key] = serializedOptions; + return serializedOptions.Copy(); + } + } + } + catch (JsonException) + { + Logger.Warn( + "An error occurred while parsing package " + + key + + ". The file will be overwritten" + ); + try + { + File.WriteAllText(filePath, "{}"); + } + catch (Exception ex) + { + Logger.Warn(ex); + } + return new(); + } + catch (Exception e) + { + Logger.Error("Loading installation options for file " + key + " have failed: "); + Logger.Error(e); + return new(); + } + } + + private static InstallOptions EnsureSecureOptions(InstallOptions options) + { + if (SecureSettings.Get(SecureSettings.K.AllowCLIArguments)) + { + // If CLI arguments are allowed, sanitize them + for (int i = 0; i < options.CustomParameters_Install.Count; i++) + { + options.CustomParameters_Install[i] = options + .CustomParameters_Install[i] + .Replace("&", "") + .Replace("|", "") + .Replace(";", "") + .Replace("<", "") + .Replace(">", "") + .Replace("\n", ""); + } + for (int i = 0; i < options.CustomParameters_Update.Count; i++) + { + options.CustomParameters_Update[i] = options + .CustomParameters_Update[i] + .Replace("&", "") + .Replace("|", "") + .Replace(";", "") + .Replace("<", "") + .Replace(">", "") + .Replace("\n", ""); + } + for (int i = 0; i < options.CustomParameters_Uninstall.Count; i++) + { + options.CustomParameters_Uninstall[i] = options + .CustomParameters_Uninstall[i] + .Replace("&", "") + .Replace("|", "") + .Replace(";", "") + .Replace("<", "") + .Replace(">", "") + .Replace("\n", ""); + } + } + else + { + // Otherwhise, clear them + if (options.CustomParameters_Install.Count > 0) + Logger.Warn( + $"Custom install parameters [{string.Join(' ', options.CustomParameters_Install)}] will be discarded" + ); + if (options.CustomParameters_Update.Count > 0) + Logger.Warn( + $"Custom update parameters [{string.Join(' ', options.CustomParameters_Update)}] will be discarded" + ); + if (options.CustomParameters_Uninstall.Count > 0) + Logger.Warn( + $"Custom uninstall parameters [{string.Join(' ', options.CustomParameters_Uninstall)}] will be discarded" + ); + + options.CustomParameters_Install = []; + options.CustomParameters_Update = []; + options.CustomParameters_Uninstall = []; + } + + if (!SecureSettings.Get(SecureSettings.K.AllowPrePostOpCommand)) + { + if (options.PreInstallCommand.Any()) + Logger.Warn( + $"Pre-install command {options.PreInstallCommand} will be discarded" + ); + if (options.PostInstallCommand.Any()) + Logger.Warn( + $"Post-install command {options.PostInstallCommand} will be discarded" + ); + if (options.PreUpdateCommand.Any()) + Logger.Warn($"Pre-update command {options.PreUpdateCommand} will be discarded"); + if (options.PostUpdateCommand.Any()) + Logger.Warn( + $"Post-update command {options.PostUpdateCommand} will be discarded" + ); + if (options.PreUninstallCommand.Any()) + Logger.Warn( + $"Pre-uninstall command {options.PreUninstallCommand} will be discarded" + ); + if (options.PostUninstallCommand.Any()) + Logger.Warn( + $"Post-uninstall command {options.PostUninstallCommand} will be discarded" + ); + + options.PreInstallCommand = ""; + options.PostInstallCommand = ""; + options.PreUpdateCommand = ""; + options.PostUpdateCommand = ""; + options.PreUninstallCommand = ""; + options.PostUninstallCommand = ""; + } + + return options; + } + } +} diff --git a/src/UniGetUI.PackageEngine.PackageManagerClasses/Packages/Classes/PackageDetails.cs b/src/UniGetUI.PackageEngine.PackageManagerClasses/Packages/Classes/PackageDetails.cs new file mode 100644 index 0000000..fcb956d --- /dev/null +++ b/src/UniGetUI.PackageEngine.PackageManagerClasses/Packages/Classes/PackageDetails.cs @@ -0,0 +1,118 @@ +using UniGetUI.Core.Logging; +using UniGetUI.PackageEngine.Interfaces; + +namespace UniGetUI.PackageEngine.PackageClasses +{ + /// + /// Holds the details of a Package. + /// + public class PackageDetails : IPackageDetails + { + /// + /// The package to which this details instance corresponds + /// + public IPackage Package { get; } + + /// + /// Whether this PackageDetails instance has valid data or not. + /// To load valid data, make use of the `Load()` method + /// + public bool IsPopulated { get; private set; } + + /// + /// The description of the package + /// + public string? Description { get; set; } + + /// + /// The publisher of the package. The one(s) in charge of maintaining the package published on the package manager. + /// + public string? Publisher { get; set; } + + /// + /// The author of the package. Who has created the package. Usually the developer of the package. + /// + public string? Author { get; set; } + + /// + /// A link to the homepage of the package + /// + public Uri? HomepageUrl { get; set; } + + /// + /// The license name (not the URL) of the package + /// + public string? License { get; set; } + + /// + /// A URL pointing to the license of the package. + /// + public Uri? LicenseUrl { get; set; } + + /// + /// A URL pointing to the installer of the package + /// + public Uri? InstallerUrl { get; set; } + + /// + /// A string representing the hash of the installer. + /// + public string? InstallerHash { get; set; } + + /// + /// A string representing the type of the installer (.zip, .exe, .msi, .appx, tarball, etc.) + /// + public string? InstallerType { get; set; } + + /// + /// The size, in **BYTES**, of the installer + /// + public long InstallerSize { get; set; } + + /// + /// A URL pointing to the Manifest File of the package + /// + public Uri? ManifestUrl { get; set; } + + /// + /// The update date (aka the publication date for the latest version) of the package + /// + public string? UpdateDate { get; set; } + + /// + /// The release notes (not the URL) for the package. + /// + public string? ReleaseNotes { get; set; } + + /// + /// A URL to the package release notes. + /// + public Uri? ReleaseNotesUrl { get; set; } + + /// + /// A list of tags that (in theory) represent the package + /// + public string[] Tags { get; set; } = []; + + public List Dependencies { get; set; } = []; + + public PackageDetails(IPackage package) + { + Package = package; + } + + public async Task Load() + { + try + { + await Task.Run(() => Package.Manager.DetailsHelper.GetDetails(this)); + IsPopulated = true; + } + catch (Exception ex) + { + Logger.Error($"PackageDetails.Load failed for package {Package.Name}"); + Logger.Error(ex); + } + } + } +} diff --git a/src/UniGetUI.PackageEngine.PackageManagerClasses/Packages/ImportedPackage.cs b/src/UniGetUI.PackageEngine.PackageManagerClasses/Packages/ImportedPackage.cs new file mode 100644 index 0000000..4c92f3a --- /dev/null +++ b/src/UniGetUI.PackageEngine.PackageManagerClasses/Packages/ImportedPackage.cs @@ -0,0 +1,76 @@ +using UniGetUI.Core.Tools; +using UniGetUI.PackageEngine.Classes.Serializable; +using UniGetUI.PackageEngine.Interfaces; +using UniGetUI.PackageEngine.Serializable; + +namespace UniGetUI.PackageEngine.PackageClasses +{ + public partial class ImportedPackage : Package + { + /// + /// Construct an invalid package with a given name, id, version, source and manager, and an optional scope. + /// + public SerializableUpdatesOptions updates_options; + public InstallOptions installation_options; + + private readonly string _version; + private static readonly string _latestString = CoreTools.Translate("Latest"); + + public override string VersionString + { + get + { + if (installation_options.Version != "") + return installation_options.Version; + return _latestString; + } + } + + public ImportedPackage( + SerializablePackage raw_data, + IPackageManager manager, + IManagerSource source + ) + : base(raw_data.Name, raw_data.Id, raw_data.Version, source, manager) + { + _version = raw_data.Version; + installation_options = raw_data.InstallationOptions; + updates_options = raw_data.Updates; + } + + public async Task RegisterAndGetPackageAsync() + { + var package = new Package(Name, Id, _version, Source, Manager); + await InstallOptionsFactory.SaveForPackageAsync(installation_options, package); + + if (updates_options.UpdatesIgnored) + await AddToIgnoredUpdatesAsync(updates_options.IgnoredVersion); + + return package; + } + + public override Task GetInstallOptions() => + Task.FromResult(installation_options.Copy()); + + public override Task AsSerializableAsync() + { + return Task.FromResult( + new SerializablePackage + { + Id = Id, + Name = Name, + Version = _version, + Source = Source.Name, + ManagerName = Manager.Id, + InstallationOptions = installation_options.Copy(), + Updates = updates_options.Copy(), + } + ); + } + + public void FirePackageVersionChangedEvent() + { + OnPropertyChanged(nameof(VersionString)); + } + } +} diff --git a/src/UniGetUI.PackageEngine.PackageManagerClasses/Packages/InvalidImportedPackage.cs b/src/UniGetUI.PackageEngine.PackageManagerClasses/Packages/InvalidImportedPackage.cs new file mode 100644 index 0000000..77f773a --- /dev/null +++ b/src/UniGetUI.PackageEngine.PackageManagerClasses/Packages/InvalidImportedPackage.cs @@ -0,0 +1,259 @@ +using System.ComponentModel; +using System.Runtime.CompilerServices; +using UniGetUI.Core.Tools; +using UniGetUI.Interface.Enums; +using UniGetUI.PackageEngine.Classes.Manager; +using UniGetUI.PackageEngine.Classes.Serializable; +using UniGetUI.PackageEngine.Enums; +using UniGetUI.PackageEngine.Interfaces; +using UniGetUI.PackageEngine.Serializable; +using UniGetUI.PackageEngine.Structs; + +namespace UniGetUI.PackageEngine.PackageClasses +{ + public partial class InvalidImportedPackage : IPackage, INotifyPropertyChanged + { + public IPackageDetails Details { get; } + + public PackageTag Tag + { + get => PackageTag.Unavailable; + set { } + } + + private bool __is_checked; + public bool IsChecked + { + get { return __is_checked; } + set + { + __is_checked = value; + OnPropertyChanged(nameof(IsChecked)); + } + } + + private readonly long __hash; + private readonly long __extended_hash; + + private static OverridenInstallationOptions __overriden_options; + public ref OverridenInstallationOptions OverridenOptions + { + get => ref __overriden_options; + } + + public string Name { get; } + + public string Id { get; } + + public string VersionString { get; } + + public CoreTools.Version NormalizedVersion { get; } + + public CoreTools.Version NormalizedNewVersion + { + get => CoreTools.Version.Null; + } + + public IManagerSource Source { get; } + + public IPackageManager Manager { get; } + + public string NewVersionString + { + get => ""; + } + + public bool IsUpgradable + { + get => false; + } + + public string Scope + { + get => PackageScope.Local; + set { } + } + + public string SourceAsString { get; } + + public string AutomationName { get; } + + public event PropertyChangedEventHandler? PropertyChanged; + + public InvalidImportedPackage(SerializableIncompatiblePackage data, IManagerSource source) + { + Name = data.Name; + Id = data.Id.Split('\\')[^1]; + VersionString = data.Version; + NormalizedVersion = CoreTools.VersionStringToStruct(data.Version); + SourceAsString = data.Source; + AutomationName = data.Name; + Manager = source.Manager; + Source = source; + Details = new PackageDetails(this); + + __hash = CoreTools.HashStringAsLong(data.Name + data.Id); + __extended_hash = CoreTools.HashStringAsLong(data.Name + data.Id + data.Version); + } + + public Task AddToIgnoredUpdatesAsync(string version = "*") + { + return Task.CompletedTask; + } + + public Task GetInstallOptions() => Task.FromResult(new InstallOptions()); + + public Task AsSerializableAsync() + { + throw new NotImplementedException(); + } + + public SerializableIncompatiblePackage AsSerializable_Incompatible() + { + return new SerializableIncompatiblePackage + { + Name = Name, + Id = Id, + Version = VersionString, + Source = SourceAsString, + }; + } + + protected void OnPropertyChanged([CallerMemberName] string? name = null) + { + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name)); + } + + public IPackage? GetAvailablePackage() + { + return null; + } + + public long GetHash() + { + return __hash; + } + + public string GetIconId() + { + throw new NotImplementedException(); + } + + public Uri GetIconUrl() + { + return new Uri("ms-appx:///Assets/Images/package_color.png"); + } + + public Uri? GetIconUrlIfAny() + { + return null; + } + + public Task GetIgnoredUpdatesVersionAsync() + { + return Task.FromResult(String.Empty); + } + + public IReadOnlyList GetInstalledPackages() + { + return []; + } + + public IReadOnlyList GetScreenshots() + { + return []; + } + + public IPackage? GetUpgradablePackage() + { + return null; + } + + public long GetVersionedHash() + { + return __extended_hash; + } + + public async Task HasUpdatesIgnoredAsync(string version = "*") + { + return false; + } + + public bool Equals(IPackage? other) + { + return __hash == other?.GetVersionedHash(); + } + + public bool IsEquivalentTo(IPackage? other) + { + return __hash == other?.GetHash(); + } + + public bool NewerVersionIsInstalled() + { + return false; + } + + public Task GetInstallerFileName() + { + return Task.FromResult(""); + } + + public bool IsUpdateMinor() + { + return false; + } + + public async Task RemoveFromIgnoredUpdatesAsync() + { + return; + } + + public void SetTag(PackageTag tag) + { + return; + } + +#pragma warning restore CS1998 + } + + public class NullSource : IManagerSource + { + public static NullSource Instance = new(CoreTools.Translate("Unknown")); + public IconType IconId { get; } + public bool IsVirtualManager { get; } + public IPackageManager Manager { get; } + public string Name { get; } + public Uri Url { get; set; } + public int? PackageCount { get; } + public string? UpdateDate { get; } + + public string AsString + { + get => Name; + } + public string AsString_DisplayName + { + get => Name; + } + + public NullSource(string name) + { + Name = name; + Url = new Uri("about:blank"); + IsVirtualManager = true; + IconId = IconType.Help; + Manager = (IPackageManager)NullPackageManager.Instance; + } + + /// + /// Returns a human-readable string representing the source name + /// + public override string ToString() + { + return Name; + } + + public void RefreshSourceNames() { } + } +} diff --git a/src/UniGetUI.PackageEngine.PackageManagerClasses/Packages/Package.cs b/src/UniGetUI.PackageEngine.PackageManagerClasses/Packages/Package.cs new file mode 100644 index 0000000..b3dffe9 --- /dev/null +++ b/src/UniGetUI.PackageEngine.PackageManagerClasses/Packages/Package.cs @@ -0,0 +1,425 @@ +using System.Collections.Concurrent; +using System.ComponentModel; +using System.Runtime.CompilerServices; +using UniGetUI.Core.Classes; +using UniGetUI.Core.IconEngine; +using UniGetUI.Core.Logging; +using UniGetUI.Core.Tools; +using UniGetUI.Interface.Enums; +using UniGetUI.PackageEngine.Classes.Packages; +using UniGetUI.PackageEngine.Classes.Packages.Classes; +using UniGetUI.PackageEngine.Classes.Serializable; +using UniGetUI.PackageEngine.Interfaces; +using UniGetUI.PackageEngine.PackageLoader; +using UniGetUI.PackageEngine.Serializable; +using UniGetUI.PackageEngine.Structs; + +namespace UniGetUI.PackageEngine.PackageClasses +{ + public partial class Package : IPackage + { + // Internal properties + private bool __is_checked; + public event PropertyChangedEventHandler? PropertyChanged; + private PackageTag __tag; + + private readonly long _hash; + private readonly long _versionedHash; + private readonly string _ignoredId; + private readonly string _iconId; + + private static readonly ConcurrentDictionary _cachedIconPaths = new(); + + private IPackageDetails? __details; + public IPackageDetails Details + { + get => __details ??= new PackageDetails(this); + } + + public PackageTag Tag + { + get => __tag; + set + { + __tag = value; + OnPropertyChanged(); + } + } + + public bool IsChecked + { + get => __is_checked; + set + { + __is_checked = value; + OnPropertyChanged(); + } + } + + private OverridenInstallationOptions _overridenOptions; + public ref OverridenInstallationOptions OverridenOptions + { + get => ref _overridenOptions; + } + public string Name { get; } + public string AutomationName { get; } + public string Id { get; } + public virtual string VersionString { get; } + public CoreTools.Version NormalizedVersion { get; } + public CoreTools.Version NormalizedNewVersion { get; } + public bool IsPopulated { get; set; } + public IManagerSource Source { get; } + + /// + /// IPackageManager is guaranteed to be PackageManager, but C# doesn't allow covariant attributes + /// + public IPackageManager Manager { get; } + public string NewVersionString { get; } + public virtual bool IsUpgradable { get; } + + /// + /// Construct a package with a given name, id, version, source and manager, and an optional scope. + /// + public Package( + string name, + string id, + string version, + IManagerSource source, + IPackageManager manager, + OverridenInstallationOptions? options = null + ) + : this(name, id, version, version, source, manager, options) + { + IsUpgradable = false; + } + + /// + /// Creates an UpgradablePackage object representing a package that can be upgraded; given its name, id, installed version, new version, source and manager, and an optional scope. + /// + public Package( + string name, + string id, + string installed_version, + string new_version, + IManagerSource source, + IPackageManager manager, + OverridenInstallationOptions? options = null + ) + { + Name = name; + Id = id; + VersionString = installed_version; + NormalizedVersion = CoreTools.VersionStringToStruct(installed_version); + NewVersionString = new_version; + NormalizedNewVersion = CoreTools.VersionStringToStruct(new_version); + Source = source; + Manager = manager; + + IsUpgradable = true; + Tag = PackageTag.Default; + + AutomationName = CoreTools + .Translate("Package {name} from {manager}") + .Replace("{name}", name) + .Replace("{manager}", Source.AsString_DisplayName); + + _overridenOptions = options ?? _overridenOptions; + _hash = CoreTools.HashStringAsLong( + $"{Manager.Name}\\{Source.AsString_DisplayName}\\{Id}" + ); + _versionedHash = CoreTools.HashStringAsLong( + $"{Manager.Name}\\{Source.AsString_DisplayName}\\{Id}\\{installed_version}" + ); + _ignoredId = IgnoredUpdatesDatabase.GetIgnoredIdForPackage(this); + _iconId = GenerateIconId(this); + } + + public long GetHash() => _hash; + + public long GetVersionedHash() => _versionedHash; + + public bool Equals(IPackage? other) => _versionedHash == other?.GetHash(); + + public override int GetHashCode() => (int)_versionedHash; + + /// + /// Check whether two package instances represent the same package. + /// What is taken into account: + /// - Manager and Source + /// - Package Identifier + /// For more specific comparison use package.Equals(object? other) + /// + /// A package + /// Whether the two instances refer to the same instance + public bool IsEquivalentTo(IPackage? other) => _hash == other?.GetHash(); + + public string GetIconId() => _iconId; + + public virtual Uri GetIconUrl() + { + return GetIconUrlIfAny() ?? new Uri("ms-appx:///Assets/Images/package_color.png"); + } + + public virtual Uri? GetIconUrlIfAny() + { + if (_cachedIconPaths.TryGetValue(this.GetHashCode(), out Uri? path)) + { + return path; + } + var CachedIcon = LoadIconUrlIfAny(); + _cachedIconPaths.TryAdd(this.GetHashCode(), CachedIcon); + return CachedIcon; + } + + private Uri? LoadIconUrlIfAny() + { + try + { + CacheableIcon? icon = TaskRecycler.RunOrAttach( + Manager.DetailsHelper.GetIcon, + this + ); + string? path = IconCacheEngine.GetCacheOrDownloadIcon( + icon, + Manager.Name, + CoreTools.MakeValidFileName(Id) + ); + return path is null ? null : new Uri((path.StartsWith('/') ? "file://" : "file:///") + path); + } + catch (Exception ex) + { + Logger.Error($"An error occurred while retrieving the icon for package {Id}"); + Logger.Error(ex); + return null; + } + } + + public virtual IReadOnlyList GetScreenshots() + { + return Manager.DetailsHelper.GetScreenshots(this); + } + + public virtual async Task AddToIgnoredUpdatesAsync(string version = "*") + { + try + { + await Task.Run(() => IgnoredUpdatesDatabase.Add(_ignoredId, version)); + foreach (var p in GetInstalledPackages()) + p.SetTag(PackageTag.Pinned); + } + catch (Exception ex) + { + Logger.Error($"Could not add package {Id} to ignored updates"); + Logger.Error(ex); + } + } + + public virtual async Task RemoveFromIgnoredUpdatesAsync() + { + try + { + await Task.Run(() => IgnoredUpdatesDatabase.Remove(_ignoredId)); + foreach (var p in GetInstalledPackages()) + p.SetTag(PackageTag.Default); + } + catch (Exception ex) + { + Logger.Error($"Could not remove package {Id} from ignored updates"); + Logger.Error(ex); + } + } + + /// + /// Returns true if the package's updates are ignored. If the version parameter + /// is passed it will be checked if that version is ignored. Please note that if + /// all updates are ignored, calling this method with a specific version will + /// still return true, although the passed version is not explicitly ignored. + /// + public virtual async Task HasUpdatesIgnoredAsync(string version = "*") + { + try + { + return await Task.Run(() => + IgnoredUpdatesDatabase.HasUpdatesIgnored(_ignoredId, version) + ); + } + catch (Exception ex) + { + Logger.Error($"Could not check whether package {Id} has updates ignored"); + Logger.Error(ex); + return false; + } + } + + /// + /// Returns (as a string) the version for which a package has been ignored. When no versions + /// are ignored, an empty string will be returned; and when all versions are ignored an asterisk + /// will be returned. + /// + public virtual async Task GetIgnoredUpdatesVersionAsync() + { + try + { + return await Task.Run(() => IgnoredUpdatesDatabase.GetIgnoredVersion(_ignoredId)) + ?? ""; + } + catch (Exception ex) + { + Logger.Error($"Could not retrieve the ignored updates version for package {Id}"); + Logger.Error(ex); + return ""; + } + } + + protected void OnPropertyChanged([CallerMemberName] string? name = null) + { + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name)); + } + + public IPackage? GetAvailablePackage() => + DiscoverablePackagesLoader.Instance.GetEquivalentPackage(this); + + public IPackage? GetUpgradablePackage() => + UpgradablePackagesLoader.Instance.GetEquivalentPackage(this); + + public IReadOnlyList GetInstalledPackages() => + InstalledPackagesLoader.Instance.GetEquivalentPackages(this); + + public virtual void SetTag(PackageTag tag) + { + Tag = tag; + } + + public virtual bool NewerVersionIsInstalled() + { + foreach (var p in GetInstalledPackages()) + { + if (p.NormalizedVersion == CoreTools.Version.Null || this.NormalizedNewVersion == CoreTools.Version.Null) + { + continue; + } + + if (p.NormalizedVersion >= this.NormalizedNewVersion) + { + return true; + } + } + + return false; + } + + public async Task GetInstallerFileName() + { + if (Manager.Name.StartsWith("PowerShell") || Manager.Name.StartsWith(".NET")) + { + return CoreTools.MakeValidFileName($"{Id}.nupkg"); + } + else + { + if (!Details.IsPopulated) + await Details.Load(); + if (Details.InstallerUrl is null) + return null; + return await CoreTools.GetFileNameAsync(Details.InstallerUrl); + } + } + + public virtual bool IsUpdateMinor() + { + if (!IsUpgradable) + return false; + + return NormalizedVersion.Major == NormalizedNewVersion.Major + && NormalizedVersion.Minor == NormalizedNewVersion.Minor + && ( + NormalizedVersion.Patch != NormalizedNewVersion.Patch + || NormalizedVersion.Remainder != NormalizedNewVersion.Remainder + ); + } + + public virtual Task GetInstallOptions() => + InstallOptionsFactory.LoadApplicableAsync(this); + + public virtual async Task AsSerializableAsync() + { + return new SerializablePackage + { + Id = Id, + Name = Name, + Version = VersionString, + Source = Source.Name, + ManagerName = Manager.Id, + InstallationOptions = await InstallOptionsFactory.LoadForPackageAsync(this), + Updates = new SerializableUpdatesOptions + { + IgnoredVersion = await GetIgnoredUpdatesVersionAsync(), + UpdatesIgnored = await HasUpdatesIgnoredAsync(), + }, + }; + } + + public SerializableIncompatiblePackage AsSerializable_Incompatible() + { + return new SerializableIncompatiblePackage + { + Id = Id, + Name = Name, + Version = VersionString, + Source = Source.Name, + }; + } + + public static void ResetIconCache() + { + _cachedIconPaths.Clear(); + } + + private static string GenerateIconId(Package p) + { + string iconId; + try + { + iconId = p.Manager.Name switch + { + "Winget" => p.Source.Name switch + { + "Steam" => p + .Id.ToLower() + .Split("\\")[^1] + .Replace("steam app ", "steam-") + .Trim(), + "Local PC" => p.Id.Split("\\")[^1], + // If the first underscore is before the period, this ID has no publisher + "Microsoft Store" => p.Id.IndexOf('_') < p.Id.IndexOf('.') + ? + // no publisher: remove `MSIX\`, then the standard ending _version_arch__{random p.Id} + string.Join('_', p.Id.Split("\\")[1].Split("_")[0..^4]) + : + // remove the publisher (before the first .), then the standard _version_arch__{random p.Id} + string.Join( + '_', + string.Join('.', p.Id.Split(".")[1..]).Split("_")[0..^4] + ), + _ => string.Join('.', p.Id.Split(".")[1..]), + }, + "Scoop" => p.Id.Replace(".app", ""), + "Chocolatey" => p.Id.Replace(".install", "").Replace(".portable", ""), + "vcpkg" => p.Id.Split(":")[0].Split("[")[0], + _ => p.Id, + }; + } + catch + { + iconId = p.Id; + } + + return iconId + .ToLower() + .Replace('_', '-') + .Replace('.', '-') + .Replace(' ', '-') + .Replace('/', '-') + .Replace(',', '-'); + } + } +} diff --git a/src/UniGetUI.PackageEngine.PackageManagerClasses/UniGetUI.PackageEngine.Classes.csproj b/src/UniGetUI.PackageEngine.PackageManagerClasses/UniGetUI.PackageEngine.Classes.csproj new file mode 100644 index 0000000..e924cc1 --- /dev/null +++ b/src/UniGetUI.PackageEngine.PackageManagerClasses/UniGetUI.PackageEngine.Classes.csproj @@ -0,0 +1,28 @@ + + + $(SharedTargetFrameworks) + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/UniGetUI.PackageEngine.Serializable.Tests/TestDuplicateUpdateDetection.cs b/src/UniGetUI.PackageEngine.Serializable.Tests/TestDuplicateUpdateDetection.cs new file mode 100644 index 0000000..719c85d --- /dev/null +++ b/src/UniGetUI.PackageEngine.Serializable.Tests/TestDuplicateUpdateDetection.cs @@ -0,0 +1,192 @@ +using NSubstitute; +using UniGetUI.Interface.Enums; +using UniGetUI.PackageEngine.Interfaces; +using UniGetUI.PackageEngine.PackageClasses; + +namespace UniGetUI.PackageEngine.Tests; + +/// +/// Tests for duplicate detection in update operations (Issue #4131). +/// These tests verify the logic used in AppOperationHelper.UpdateAll() and UpdateAllForManager() +/// to prevent multiple update operations for the same package from being queued simultaneously. +/// +public class TestDuplicateUpdateDetection +{ + /// + /// Test that verifies Package.GetHash() returns the same value for identical packages. + /// This is the core mechanism used to detect duplicate operations in the queue. + /// + /// Background: Issue #4131 - When unattended updates trigger repeatedly while UAC prompts + /// are pending, UpdateAll() was creating dozens of duplicate operations for the same package. + /// The fix uses GetHash() to check if an operation for a package already exists in the queue. + /// + [Fact] + public void GetHash_ShouldReturnSameValue_ForIdenticalPackages() + { + // Arrange - Create mock manager and source + // Note: We use the same instances to ensure consistent hashing + var mockManager = Substitute.For(); + mockManager.Name.Returns("TestManager"); + + var mockSource = Substitute.For(); + mockSource.Name.Returns("TestSource"); + + // Create two package instances with identical identity (same manager, source, and ID) + var package1 = new Package( + name: "TestPackage", + id: "test.package.id", + version: "1.0.0", + source: mockSource, + manager: mockManager + ); + + var package2 = new Package( + name: "TestPackage", + id: "test.package.id", + version: "1.0.0", + source: mockSource, + manager: mockManager + ); + + // Act - Get hash for both packages + long hash1 = package1.GetHash(); + long hash2 = package2.GetHash(); + + // Assert - Hashes must be equal for the duplicate detection to work + Assert.Equal(hash1, hash2); + } + + /// + /// Test that verifies Package.GetHash() returns different values for different packages. + /// This ensures the duplicate detection doesn't falsely match unrelated packages. + /// + [Fact] + public void GetHash_ShouldReturnDifferentValues_ForDifferentPackages() + { + // Arrange + var mockManager = Substitute.For(); + mockManager.Name.Returns("TestManager"); + + var mockSource = Substitute.For(); + mockSource.Name.Returns("TestSource"); + + // Create packages with different IDs + var package1 = new Package( + name: "TestPackage1", + id: "test.package.one", + version: "1.0.0", + source: mockSource, + manager: mockManager + ); + + var package2 = new Package( + name: "TestPackage2", + id: "test.package.two", + version: "1.0.0", + source: mockSource, + manager: mockManager + ); + + // Act + long hash1 = package1.GetHash(); + long hash2 = package2.GetHash(); + + // Assert - Hashes must be different so we don't skip legitimate different packages + Assert.NotEqual(hash1, hash2); + } + + /// + /// Test that verifies packages from different managers have different hashes. + /// The duplicate detection must consider the package manager as part of identity. + /// + [Fact] + public void GetHash_ShouldDiffer_ForSamePackageFromDifferentManagers() + { + // Arrange - Create two different managers + var mockManager1 = Substitute.For(); + mockManager1.Name.Returns("WinGet"); + + var mockManager2 = Substitute.For(); + mockManager2.Name.Returns("Chocolatey"); + + var mockSource = Substitute.For(); + mockSource.Name.Returns("TestSource"); + + // Same package ID from different managers + var packageFromWinGet = new Package( + name: "TestPackage", + id: "test.package", + version: "1.0.0", + source: mockSource, + manager: mockManager1 + ); + + var packageFromChoco = new Package( + name: "TestPackage", + id: "test.package", + version: "1.0.0", + source: mockSource, + manager: mockManager2 + ); + + // Act + long hashWinGet = packageFromWinGet.GetHash(); + long hashChoco = packageFromChoco.GetHash(); + + // Assert - Must be different because they're from different managers + Assert.NotEqual(hashWinGet, hashChoco); + } + + /// + /// Test simulating the scenario where multiple UpdateAll() calls should detect duplicates. + /// This represents what happens when auto-updates trigger while operations are queued. + /// + [Fact] + public void SimulateDuplicateDetection_MultipleIdenticalPackages_ShouldHaveSameHash() + { + // Arrange - Simulate receiving same package multiple times from UpgradablePackagesLoader + var mockManager = Substitute.For(); + mockManager.Name.Returns("WinGet"); + + var mockSource = Substitute.For(); + mockSource.Name.Returns("winget"); + + // Simulate UpdateAll() being called 3 times, each time getting "same" package + var packagesFromFirstCall = new Package( + name: "Git", + id: "Git.Git", + version: "2.40.0", + source: mockSource, + manager: mockManager + ); + + var packagesFromSecondCall = new Package( + name: "Git", + id: "Git.Git", + version: "2.40.0", + source: mockSource, + manager: mockManager + ); + + var packagesFromThirdCall = new Package( + name: "Git", + id: "Git.Git", + version: "2.40.0", + source: mockSource, + manager: mockManager + ); + + // Act - Get hashes that would be used for duplicate detection + var hash1 = packagesFromFirstCall.GetHash(); + var hash2 = packagesFromSecondCall.GetHash(); + var hash3 = packagesFromThirdCall.GetHash(); + + // Assert - All three should have the same hash, allowing duplicate detection + Assert.Equal(hash1, hash2); + Assert.Equal(hash2, hash3); + Assert.Equal(hash1, hash3); + + // In the actual implementation, the second and third calls would find + // an existing operation with matching hash and skip creating duplicates + } +} diff --git a/src/UniGetUI.PackageEngine.Serializable.Tests/TestInstallOptions.cs b/src/UniGetUI.PackageEngine.Serializable.Tests/TestInstallOptions.cs new file mode 100644 index 0000000..fd60f2c --- /dev/null +++ b/src/UniGetUI.PackageEngine.Serializable.Tests/TestInstallOptions.cs @@ -0,0 +1,265 @@ +using System.Text.Json.Nodes; +using Xunit.Sdk; + +namespace UniGetUI.PackageEngine.Serializable.Tests; + +public class TestInstallOptions +{ + [Theory] + [InlineData(false, false, "", "", "", "", "", "", false, false, false, "")] + [InlineData( + true, + true, + "testval", + "testval", + "testval", + "testval", + "testval", + "testval", + true, + true, + true, + "testval" + )] + [InlineData( + true, + false, + "true", + "helloWorld", + "testval", + "heheheheeheh", + "--parse\n-int", + "12", + false, + true, + false, + "4.4.0-beta2" + )] + public void ToAndFromJsonNode( + bool a, + bool b, + string c, + string d, + string e, + string f, + string g, + string h, + bool i, + bool j, + bool k, + string l + ) + { + var originalObject1 = new InstallOptions() + { + SkipHashCheck = a, + Architecture = h, + CustomInstallLocation = c, + CustomParameters_Install = [d, e, f], + CustomParameters_Update = [d, e, f, f, f, d], + CustomParameters_Uninstall = [e, f, f], + InstallationScope = g, + InteractiveInstallation = b, + PreRelease = i, + RunAsAdministrator = j, + SkipMinorUpdates = k, + Version = l, + }; + + Assert.Equal(a, originalObject1.DiffersFromDefault()); + + var object2 = new InstallOptions(); + string contents = originalObject1.AsJsonString(); + Assert.NotEmpty(contents); + var jsonContent = JsonNode.Parse(contents); + Assert.NotNull(jsonContent); + object2.LoadFromJson(jsonContent); + AssertAreEqual(originalObject1, object2); + + var object3 = new InstallOptions(originalObject1.AsJsonNode()); + AssertAreEqual(originalObject1, object3); + + var object4 = originalObject1.Copy(); + AssertAreEqual(originalObject1, object4); + } + + [Theory] + [InlineData("{}", false, false, "", "", "", "", "", "", false, false, false, "", false)] + [InlineData( + """ + { + "SkipHashCheck": true, + "InteractiveInstallation": true, + "RunAsAdministrator": false, + "Architecture": "lol", + "InstallationScope": "", + "CustomParameters": [ + "a" + ] + } + """, + true, + true, + "", + "a", + "", + "", + "", + "lol", + false, + false, + false, + "", + true + )] + [InlineData( + """ + { + "PreRelease": false, + "CustomInstallLocation": "", + "Version": "heyheyhey", + "SkipMinorUpdates": true, + "UNKNOWN_VAL1": true, + "UNKNOWN_VAL2": null, + "UNKNOWN_VAL3": 22, + "UNKNOWN_VAL4": "hehe" + } + """, + false, + false, + "", + "", + "", + "", + "", + "", + false, + false, + true, + "heyheyhey", + true + )] + public void FromJson( + string JSON, + bool hash, + bool inter, + string installLoc, + string arg1, + string arg2, + string arg3, + string scope, + string arch, + bool pre, + bool admin, + bool skipMin, + string ver, + bool mod + ) + { + Assert.NotEmpty(JSON); + var jsonContent = JsonNode.Parse(JSON); + Assert.NotNull(jsonContent); + var o2 = new InstallOptions(jsonContent); + + var list = new List() { arg1, arg2, arg3 }.Where(x => x.Any()); + + Assert.Equal(mod, o2.OverridesNextLevelOpts); + Assert.Equal(mod, o2.DiffersFromDefault()); + Assert.Equal(hash, o2.SkipHashCheck); + Assert.Equal(arch, o2.Architecture); + Assert.Equal(installLoc, o2.CustomInstallLocation); + Assert.Equal( + list.Where(x => x.Any()).ToList(), + o2.CustomParameters_Install.Where(x => x.Any()).ToList() + ); + Assert.Equal( + list.Where(x => x.Any()).ToList(), + o2.CustomParameters_Update.Where(x => x.Any()).ToList() + ); + Assert.Equal( + list.Where(x => x.Any()).ToList(), + o2.CustomParameters_Uninstall.Where(x => x.Any()).ToList() + ); + Assert.Equal(scope, o2.InstallationScope); + Assert.Equal(inter, o2.InteractiveInstallation); + Assert.Equal(pre, o2.PreRelease); + Assert.Equal(admin, o2.RunAsAdministrator); + Assert.Equal(skipMin, o2.SkipMinorUpdates); + Assert.Equal(ver, o2.Version); + } + + [Theory] + [InlineData(13345)] + [InlineData(219574)] + [InlineData(-3453)] + [InlineData(15820753)] + [InlineData(9026)] + [InlineData(12783)] + [InlineData(87432574)] + [InlineData(34)] + [InlineData(86578312)] + public void RandomPropertyAssignTester(int seed) + { + InstallOptions o1 = GenerateRandom(seed); + InstallOptions o2 = o1.Copy(); + Assert.True(o2.DiffersFromDefault()); + AssertAreEqual(o1, o2); + var c1 = o1.AsJsonString(); + var c2 = o2.AsJsonString(); + Assert.Equal(c1, c2); + InstallOptions o3 = new(); + o3.LoadFromJson(JsonNode.Parse(c1) ?? throw new ArgumentException("null")); + AssertAreEqual(o1, o2); + AssertAreEqual(o2, o3); + AssertAreEqual(o1, o3); // Yeah, it is redundant + Assert.Equal(c1, o3.AsJsonString()); + } + + private static InstallOptions GenerateRandom(int seed) + { + Random r = new(seed); + + InstallOptions o1 = new(); + foreach (var (key, _) in o1._defaultBoolValues) + o1._boolVal[key] = r.Next(2) is 0; + + o1.OverridesNextLevelOpts = r.Next(2) is 0; + + foreach (var key in o1._stringKeys) + o1._strVal[key] = r.Next().ToString(); + + foreach (var key in o1._listKeys) + { + var randomList = Enumerable + .Range(0, r.Next(0, 11)) + .Select(_ => r.Next().ToString()) + .ToList(); + o1._listVal[key] = randomList; + } + + return o1; + } + + internal static void AssertAreEqual(InstallOptions o1, InstallOptions o2) + { + Assert.Equal(o1.OverridesNextLevelOpts, o2.OverridesNextLevelOpts); + + foreach (var (key, _) in o1._defaultBoolValues) + { + Assert.Equal(o1._boolVal[key], o2._boolVal[key]); + } + + foreach (var key in o1._stringKeys) + { + Assert.Equal(o1._strVal[key], o2._strVal[key]); + } + + foreach (var key in o1._listKeys) + { + Assert.Equal( + o1._listVal[key].Where(x => x.Any()), + o2._listVal[key].Where(x => x.Any()) + ); + } + } +} diff --git a/src/UniGetUI.PackageEngine.Serializable.Tests/TestSerializableBundle.cs b/src/UniGetUI.PackageEngine.Serializable.Tests/TestSerializableBundle.cs new file mode 100644 index 0000000..cad1f3d --- /dev/null +++ b/src/UniGetUI.PackageEngine.Serializable.Tests/TestSerializableBundle.cs @@ -0,0 +1,136 @@ +using System.Text.Json.Nodes; +using UniGetUI.PackageEngine.Classes.Serializable; + +namespace UniGetUI.PackageEngine.Serializable.Tests; + +public class TestSerializableBundle +{ + public static SerializablePackage TestPackage1 = new() + { + Name = "Package", + Id = "Identifier1", + ManagerName = "Scoop", + Source = "", + Version = "3.0", + InstallationOptions = new() + { + SkipHashCheck = true, + Architecture = "4+1€", + CustomParameters_Install = ["--hello-world", "--another-param", "-help"], + CustomParameters_Update = ["--update", "--another-param", "-help"], + CustomParameters_Uninstall = ["--uninstall", "--another-param", "-help"], + }, + Updates = new() { IgnoredVersion = "12", UpdatesIgnored = false }, + }; + + public static SerializablePackage TestPackage2 = new() + { + Name = "AnotherPackage", + Id = "Identifier2", + ManagerName = "WinGet", + Source = "msstore", + Version = "5.0", + }; + + public static SerializableIncompatiblePackage TestIncompatiblePackage = new() + { + Name = "AnotherPackage3", + Id = "Identifier4", + Source = "msstore", + Version = "5.0", + }; + + [Fact] + public void ToAndFromJsonNode() + { + var originalObject1 = new SerializableBundle() + { + export_version = 5, + packages = [TestPackage1, TestPackage2], + incompatible_packages_info = + "I'm trying to reach you regarding your car's extended warranty", + incompatible_packages = [TestIncompatiblePackage], + }; + + var object2 = new SerializableBundle(); + string contents = originalObject1.AsJsonString(); + Assert.NotEmpty(contents); + var jsonContent = JsonNode.Parse(contents); + Assert.NotNull(jsonContent); + object2.LoadFromJson(jsonContent); + AreEqual(originalObject1, object2); + + var object3 = new SerializableBundle(originalObject1.AsJsonNode()); + AreEqual(originalObject1, object3); + + var object4 = originalObject1.Copy(); + AreEqual(originalObject1, object4); + } + + [Theory] + [InlineData("{}", "", "", "")] + [InlineData( + """ + { + "export_version": 2.1, + "packages": [ + { + "Id": "Hello" + }, + { + "Id": "World" + } + ], + "incompatible_packages_info": "hey", + "incompatible_packages": [ + { + "Id": "3" + } + ] + } + """, + "Hello", + "World", + "3" + )] + public void FromJson(string JSON, string id1, string id2, string id3) + { + Assert.NotEmpty(JSON); + var jsonContent = JsonNode.Parse(JSON); + Assert.NotNull(jsonContent); + var o2 = new SerializableBundle(jsonContent); + + if (id1 == "") + { + Assert.Equal(0, o2.export_version); + Assert.Equal(SerializableBundle.IncompatMessage, o2.incompatible_packages_info); + Assert.Empty(o2.packages); + Assert.Empty(o2.incompatible_packages); + } + else + { + Assert.Equal(2.1, o2.export_version); + Assert.Equal("hey", o2.incompatible_packages_info); + Assert.Equal(id1, o2.packages[0].Id); + Assert.Equal(id2, o2.packages[1].Id); + Assert.Equal(id3, o2.incompatible_packages[0].Id); + } + } + + internal static void AreEqual(SerializableBundle o1, SerializableBundle o2) + { + Assert.Equal(o1.export_version, o2.export_version); + Assert.Equal(o1.incompatible_packages_info, o2.incompatible_packages_info); + + Assert.Equal(o1.packages.Count, o2.packages.Count); + for (int i = 0; i < o1.packages.Count; i++) + TestSerializablePackage.AreEqual(o1.packages[i], o2.packages[i]); + + Assert.Equal(o1.incompatible_packages.Count, o2.incompatible_packages.Count); + for (int i = 0; i < o1.incompatible_packages.Count; i++) + TestSerializableIncompatiblePackage.AreEqual( + o1.incompatible_packages[i], + o2.incompatible_packages[i] + ); + } +} diff --git a/src/UniGetUI.PackageEngine.Serializable.Tests/TestSerializableIncompatiblePackage.cs b/src/UniGetUI.PackageEngine.Serializable.Tests/TestSerializableIncompatiblePackage.cs new file mode 100644 index 0000000..067a1ef --- /dev/null +++ b/src/UniGetUI.PackageEngine.Serializable.Tests/TestSerializableIncompatiblePackage.cs @@ -0,0 +1,90 @@ +using System.Text.Json.Nodes; +using UniGetUI.PackageEngine.Classes.Serializable; + +namespace UniGetUI.PackageEngine.Serializable.Tests; + +public class TestSerializableIncompatiblePackage +{ + [Theory] + [InlineData("", "", "", "")] + [InlineData("UniGetUI", "MartiCliment.UniGetUI.Pre-Release", "3.2.1-beta1", "WinGet")] + [InlineData("Mr. Trololo", "\n\n\n", "\x12", "\r")] + public void ToAndFromJsonNode(string id, string name, string version, string manager) + { + var originalObject1 = new SerializableIncompatiblePackage() + { + Id = id, + Name = name, + Source = manager, + Version = version, + }; + + var object2 = new SerializableIncompatiblePackage(); + string contents = originalObject1.AsJsonString(); + Assert.NotEmpty(contents); + var jsonContent = JsonNode.Parse(contents); + Assert.NotNull(jsonContent); + object2.LoadFromJson(jsonContent); + AreEqual(originalObject1, object2); + + var object3 = new SerializableIncompatiblePackage(originalObject1.AsJsonNode()); + AreEqual(originalObject1, object3); + + var object4 = originalObject1.Copy(); + AreEqual(originalObject1, object4); + } + + [Theory] + [InlineData("{}", "", "", "", "")] + [InlineData( + """ + { + "Name": "name", + "Id": "true" + } + """, + "true", + "name", + "", + "" + )] + [InlineData( + """ + { + "Version": "false", + "Source": "lol", + "UNKNOWN_VAL1": true, + "UNKNOWN_VAL2": null, + "UNKNOWN_VAL3": 22, + "UNKNOWN_VAL4": "hehe" + } + """, + "", + "", + "false", + "lol" + )] + public void FromJson(string JSON, string id, string name, string version, string manager) + { + Assert.NotEmpty(JSON); + var jsonContent = JsonNode.Parse(JSON); + Assert.NotNull(jsonContent); + var o2 = new SerializableIncompatiblePackage(jsonContent); + + Assert.Equal(name, o2.Name); + Assert.Equal(id, o2.Id); + Assert.Equal(manager, o2.Source); + Assert.Equal(version, o2.Version); + } + + internal static void AreEqual( + SerializableIncompatiblePackage o1, + SerializableIncompatiblePackage o2 + ) + { + Assert.Equal(o1.Name, o2.Name); + Assert.Equal(o1.Id, o2.Id); + Assert.Equal(o1.Source, o2.Source); + Assert.Equal(o1.Version, o2.Version); + } +} diff --git a/src/UniGetUI.PackageEngine.Serializable.Tests/TestSerializablePackage.cs b/src/UniGetUI.PackageEngine.Serializable.Tests/TestSerializablePackage.cs new file mode 100644 index 0000000..19f4fe1 --- /dev/null +++ b/src/UniGetUI.PackageEngine.Serializable.Tests/TestSerializablePackage.cs @@ -0,0 +1,136 @@ +using System.Text.Json.Nodes; +using UniGetUI.PackageEngine.Classes.Serializable; + +namespace UniGetUI.PackageEngine.Serializable.Tests; + +public class TestSerializablePackage +{ + public static InstallOptions TestOptions = new() + { + SkipHashCheck = true, + CustomParameters_Install = ["a", "b", "c"], + CustomParameters_Update = ["b", "b", "b"], + CustomParameters_Uninstall = ["c", "b", "a"], + Architecture = "ia64", + Version = "-1", + RunAsAdministrator = true, + }; + + public static SerializableUpdatesOptions TestUpdatesOpts = new() + { + UpdatesIgnored = true, + IgnoredVersion = "Espresso Macchiato", + }; + + [Theory] + [InlineData("", "", "", "")] + [InlineData("UniGetUI", "MartiCliment.UniGetUI.Pre-Release", "3.2.1-beta1", "WinGet")] + [InlineData("Mr. Trololo", "\n\n\n", "\x12", "\r")] + public void ToAndFromJsonNode(string id, string name, string version, string manager) + { + var originalObject1 = new SerializablePackage() + { + Id = id, + Name = name, + Source = manager, + Version = version, + }; + + var object2 = new SerializablePackage(); + string contents = originalObject1.AsJsonString(); + Assert.NotEmpty(contents); + var jsonContent = JsonNode.Parse(contents); + Assert.NotNull(jsonContent); + object2.LoadFromJson(jsonContent); + AreEqual(originalObject1, object2); + + var object3 = new SerializablePackage(originalObject1.AsJsonNode()); + AreEqual(originalObject1, object3); + + var object4 = originalObject1.Copy(); + AreEqual(originalObject1, object4); + } + + [Theory] + [InlineData("{}", "", "", "", "", "", false, "")] + [InlineData( + """ + { + "Name": "name", + "Id": "true", + "Updates" : { + "IgnoredVersion": "Hey" + } + } + """, + "true", + "name", + "", + "", + "", + false, + "Hey" + )] + [InlineData( + """ + { + "Version": "false", + "Source": "lol", + "ManagerName": "Rodolfo Chikilicuatre", + "UNKNOWN_VAL1": true, + "UNKNOWN_VAL2": null, + "UNKNOWN_VAL3": 22, + "UNKNOWN_VAL4": "hehe", + "InstallationOptions" : { + "SkipHashCheck": true, + "OverridesNextLevelOpts": false + } + } + """, + "", + "", + "false", + "Rodolfo Chikilicuatre", + "lol", + true, + "" + )] + public void FromJson( + string JSON, + string id, + string name, + string version, + string manager, + string source, + bool skipHash, + string ignoredVer + ) + { + Assert.NotEmpty(JSON); + var jsonContent = JsonNode.Parse(JSON); + Assert.NotNull(jsonContent); + var o2 = new SerializablePackage(jsonContent); + + Assert.Equal(name, o2.Name); + Assert.Equal(id, o2.Id); + Assert.Equal(manager, o2.ManagerName); + Assert.Equal(source, o2.Source); + Assert.Equal(version, o2.Version); + TestInstallOptions.AssertAreEqual( + new() { SkipHashCheck = skipHash }, + o2.InstallationOptions + ); + TestSerializableUpdatesOptions.AreEqual(new() { IgnoredVersion = ignoredVer }, o2.Updates); + } + + internal static void AreEqual(SerializablePackage o1, SerializablePackage o2) + { + Assert.Equal(o1.Name, o2.Name); + Assert.Equal(o1.Id, o2.Id); + Assert.Equal(o1.Source, o2.Source); + Assert.Equal(o1.Version, o2.Version); + Assert.Equal(o1.ManagerName, o2.ManagerName); + TestInstallOptions.AssertAreEqual(o1.InstallationOptions, o2.InstallationOptions); + TestSerializableUpdatesOptions.AreEqual(o1.Updates, o2.Updates); + } +} diff --git a/src/UniGetUI.PackageEngine.Serializable.Tests/TestSerializableUpdatesOptions.cs b/src/UniGetUI.PackageEngine.Serializable.Tests/TestSerializableUpdatesOptions.cs new file mode 100644 index 0000000..2fc5e17 --- /dev/null +++ b/src/UniGetUI.PackageEngine.Serializable.Tests/TestSerializableUpdatesOptions.cs @@ -0,0 +1,76 @@ +using System.Text.Json.Nodes; +using UniGetUI.PackageEngine.Classes.Serializable; + +namespace UniGetUI.PackageEngine.Serializable.Tests; + +public class TestSerializableUpdatesOptions +{ + [Theory] + [InlineData(false, "")] + [InlineData(true, "MartiCliment.UniGetUI.Pre-Release")] + [InlineData(false, "hey")] + [InlineData(true, "")] + public void ToAndFromJsonNode(bool ign, string ver) + { + var originalObject1 = new SerializableUpdatesOptions() + { + UpdatesIgnored = ign, + IgnoredVersion = ver, + }; + + var object2 = new SerializableUpdatesOptions(); + string contents = originalObject1.AsJsonString(); + Assert.NotEmpty(contents); + var jsonContent = JsonNode.Parse(contents); + Assert.NotNull(jsonContent); + object2.LoadFromJson(jsonContent); + AreEqual(originalObject1, object2); + + var object3 = new SerializableUpdatesOptions(originalObject1.AsJsonNode()); + AreEqual(originalObject1, object3); + + var object4 = originalObject1.Copy(); + AreEqual(originalObject1, object4); + } + + [Theory] + [InlineData("{}", false, "")] + [InlineData( + """ + { + "UpdatesIgnored": true + } + """, + true, + "" + )] + [InlineData( + """ + { + "IgnoredVersion": "lol", + "UNKNOWN_VAL1": true, + "UNKNOWN_VAL2": null, + "UNKNOWN_VAL3": 22, + "UNKNOWN_VAL4": "hehe" + } + """, + false, + "lol" + )] + public void FromJson(string JSON, bool ign, string ver) + { + Assert.NotEmpty(JSON); + var jsonContent = JsonNode.Parse(JSON); + Assert.NotNull(jsonContent); + var o2 = new SerializableUpdatesOptions(jsonContent); + + Assert.Equal(ign, o2.UpdatesIgnored); + Assert.Equal(ver, o2.IgnoredVersion); + } + + internal static void AreEqual(SerializableUpdatesOptions o1, SerializableUpdatesOptions o2) + { + Assert.Equal(o1.IgnoredVersion, o2.IgnoredVersion); + Assert.Equal(o1.UpdatesIgnored, o2.UpdatesIgnored); + } +} diff --git a/src/UniGetUI.PackageEngine.Serializable.Tests/UniGetUI.PackageEngine.Serializable.Tests.csproj b/src/UniGetUI.PackageEngine.Serializable.Tests/UniGetUI.PackageEngine.Serializable.Tests.csproj new file mode 100644 index 0000000..6813dd3 --- /dev/null +++ b/src/UniGetUI.PackageEngine.Serializable.Tests/UniGetUI.PackageEngine.Serializable.Tests.csproj @@ -0,0 +1,30 @@ + + + $(PortableTargetFramework) + + false + true + + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + + + + + + diff --git a/src/UniGetUI.PackageEngine.Serializable/InstallOptions.cs b/src/UniGetUI.PackageEngine.Serializable/InstallOptions.cs new file mode 100644 index 0000000..a39b275 --- /dev/null +++ b/src/UniGetUI.PackageEngine.Serializable/InstallOptions.cs @@ -0,0 +1,378 @@ +using System.Collections.Concurrent; +using System.Text; +using System.Text.Json.Nodes; +using UniGetUI.Core.Data; + +namespace UniGetUI.PackageEngine.Serializable +{ + public class InstallOptions : SerializableComponent + { + private const string SKIP_HASH = "SkipHashCheck"; + private const string INTERACTIVE = "InteractiveInstallation"; + private const string AS_ADMIN = "RunAsAdministrator"; + private const string PRERELEASE = "PreRelease"; + private const string SKIP_MINOR = "SkipMinorUpdates"; + private const string REMOVE_DATA_UNINST = "RemoveDataOnUninstall"; + private const string CLEAR_PREV_VER = "UninstallPreviousVersionsOnUpdate"; + private const string ABORT_PRE_INST_FAIL = "AbortOnPreInstallFail"; + private const string ABORT_PRE_UPD_FAIL = "AbortOnPreUpdateFail"; + private const string ABORT_PRE_UNINST_FAIL = "AbortOnPreUninstallFail"; + private const string AUTO_UPDATE_PACKAGE = "AutoUpdatePackage"; + + private const string ARCH = "Architecture"; + private const string SCOPE = "InstallationScope"; + private const string LOCATION = "CustomInstallLocation"; + private const string VERSION = "Version"; + private const string PRE_INST_CMD = "PreInstallCommand"; + private const string POST_INST_CMD = "PostInstallCommand"; + private const string PRE_UPD_CMD = "PreUpdateCommand"; + private const string POST_UPD_CMD = "PostUpdateCommand"; + private const string PRE_UNINST_CMD = "PreUninstallCommand"; + private const string POST_UNINST_CMD = "PostUninstallCommand"; + + private const string INST_PARAMS = "CustomParameters_Install"; + private const string UPD_PARAMS = "CustomParameters_Update"; + private const string UNINST_PARAMS = "CustomParameters_Uninstall"; + private const string KILL_BEFORE_OP = "KillBeforeOperation"; + + public readonly IReadOnlyDictionary _defaultBoolValues = new Dictionary< + string, + bool + >() + { // OverridesNextLevelOpts is deliberately skipped here + { SKIP_HASH, false }, + { INTERACTIVE, false }, + { AS_ADMIN, false }, + { PRERELEASE, false }, + { SKIP_MINOR, false }, + { REMOVE_DATA_UNINST, false }, + { CLEAR_PREV_VER, false }, + { ABORT_PRE_INST_FAIL, true }, + { ABORT_PRE_UPD_FAIL, true }, + { ABORT_PRE_UNINST_FAIL, true }, + { AUTO_UPDATE_PACKAGE, false }, + }; + + public readonly IReadOnlyList _stringKeys = + [ + ARCH, + SCOPE, + LOCATION, + VERSION, + PRE_INST_CMD, + POST_INST_CMD, + PRE_UPD_CMD, + POST_UPD_CMD, + PRE_UNINST_CMD, + POST_UNINST_CMD, + ]; + + public readonly IReadOnlyList _listKeys = + [ + INST_PARAMS, + UPD_PARAMS, + UNINST_PARAMS, + KILL_BEFORE_OP, + ]; + + public readonly ConcurrentDictionary _boolVal = new(); + public readonly ConcurrentDictionary _strVal = new(); + public readonly ConcurrentDictionary> _listVal = new(); + + public bool SkipHashCheck + { + get => _boolVal[SKIP_HASH]; + set => _boolVal[SKIP_HASH] = value; + } + public bool InteractiveInstallation + { + get => _boolVal[INTERACTIVE]; + set => _boolVal[INTERACTIVE] = value; + } + public bool RunAsAdministrator + { + get => _boolVal[AS_ADMIN]; + set => _boolVal[AS_ADMIN] = value; + } + public bool PreRelease + { + get => _boolVal[PRERELEASE]; + set => _boolVal[PRERELEASE] = value; + } + public bool SkipMinorUpdates + { + get => _boolVal[SKIP_MINOR]; + set => _boolVal[SKIP_MINOR] = value; + } + public bool RemoveDataOnUninstall + { + get => _boolVal[REMOVE_DATA_UNINST]; + set => _boolVal[REMOVE_DATA_UNINST] = value; + } + public bool UninstallPreviousVersionsOnUpdate + { + get => _boolVal[CLEAR_PREV_VER]; + set => _boolVal[CLEAR_PREV_VER] = value; + } + public bool AbortOnPreInstallFail + { + get => _boolVal[ABORT_PRE_INST_FAIL]; + set => _boolVal[ABORT_PRE_INST_FAIL] = value; + } + public bool AbortOnPreUpdateFail + { + get => _boolVal[ABORT_PRE_UPD_FAIL]; + set => _boolVal[ABORT_PRE_UPD_FAIL] = value; + } + public bool AbortOnPreUninstallFail + { + get => _boolVal[ABORT_PRE_UNINST_FAIL]; + set => _boolVal[ABORT_PRE_UNINST_FAIL] = value; + } + public bool AutoUpdatePackage + { + get => _boolVal[AUTO_UPDATE_PACKAGE]; + set => _boolVal[AUTO_UPDATE_PACKAGE] = value; + } + + public string Architecture + { + get => _strVal[ARCH]; + set => _strVal[ARCH] = value; + } + public string InstallationScope + { + get => _strVal[SCOPE]; + set => _strVal[SCOPE] = value; + } + public string CustomInstallLocation + { + get => _strVal[LOCATION]; + set => _strVal[LOCATION] = value; + } + public string Version + { + get => _strVal[VERSION]; + set => _strVal[VERSION] = value; + } + public string PreInstallCommand + { + get => _strVal[PRE_INST_CMD]; + set => _strVal[PRE_INST_CMD] = value; + } + public string PostInstallCommand + { + get => _strVal[POST_INST_CMD]; + set => _strVal[POST_INST_CMD] = value; + } + public string PreUpdateCommand + { + get => _strVal[PRE_UPD_CMD]; + set => _strVal[PRE_UPD_CMD] = value; + } + public string PostUpdateCommand + { + get => _strVal[POST_UPD_CMD]; + set => _strVal[POST_UPD_CMD] = value; + } + public string PreUninstallCommand + { + get => _strVal[PRE_UNINST_CMD]; + set => _strVal[PRE_UNINST_CMD] = value; + } + public string PostUninstallCommand + { + get => _strVal[POST_UNINST_CMD]; + set => _strVal[POST_UNINST_CMD] = value; + } + + public List CustomParameters_Install + { + get => _listVal[INST_PARAMS]; + set => _listVal[INST_PARAMS] = value; + } + public List CustomParameters_Update + { + get => _listVal[UPD_PARAMS]; + set => _listVal[UPD_PARAMS] = value; + } + public List CustomParameters_Uninstall + { + get => _listVal[UNINST_PARAMS]; + set => _listVal[UNINST_PARAMS] = value; + } + public List KillBeforeOperation + { + get => _listVal[KILL_BEFORE_OP]; + set => _listVal[KILL_BEFORE_OP] = value; + } + + public bool OverridesNextLevelOpts { get; set; } + + public override InstallOptions Copy() + { + var copy = new InstallOptions(); + + foreach (var (boolKey, _) in _defaultBoolValues) + copy._boolVal[boolKey] = this._boolVal[boolKey]; + + foreach (var stringKey in _stringKeys) + copy._strVal[stringKey] = this._strVal[stringKey]; + + foreach (var listKey in _listKeys) + copy._listVal[listKey] = this._listVal[listKey].ToList(); + + // Handle non-automated OverridesNextLevelOpts + copy.OverridesNextLevelOpts = OverridesNextLevelOpts; + return copy; + } + + public override void LoadFromJson(JsonNode data) + { + foreach (var (boolKey, defValue) in _defaultBoolValues) + _boolVal[boolKey] = data[boolKey]?.GetVal() ?? defValue; + + foreach (var stringKey in _stringKeys) + _strVal[stringKey] = data[stringKey]?.GetVal() ?? ""; + + foreach (var listKey in _listKeys) + _listVal[listKey] = _readArrayFromJson(data, listKey); + + // Handle case where setting has not been migrated yet to have three different entries for CustomParameters + if ( + this.CustomParameters_Install.Count is 0 + && this.CustomParameters_Update.Count is 0 + && this.CustomParameters_Uninstall.Count is 0 + && ((data as JsonObject)?.ContainsKey("CustomParameters") ?? false) + ) + { + this.CustomParameters_Install = _readArrayFromJson(data, "CustomParameters"); + this.CustomParameters_Update = _readArrayFromJson(data, "CustomParameters"); + this.CustomParameters_Uninstall = _readArrayFromJson(data, "CustomParameters"); + } + + // if OverridesNextLevelOpts is not found on the JSON, set it to true or false depending + // on whether the current settings instances are different from the default values. + // This entry shall be checked the last one, to ensure all other properties are set + this.OverridesNextLevelOpts = + data[nameof(OverridesNextLevelOpts)]?.GetValue() ?? DiffersFromDefault(); + } + + public override JsonObject AsJsonNode() + { + JsonObject obj = new(); + + // OverridesNextLevelOpts is not among the automated properties, must be dealt manually + if (OverridesNextLevelOpts is true || this.DiffersFromDefault()) + obj.Add(nameof(OverridesNextLevelOpts), OverridesNextLevelOpts); + + foreach (var (boolKey, defValue) in _defaultBoolValues) + { + bool currentValue = _boolVal[boolKey]; + if (currentValue != defValue) + obj.Add(boolKey, currentValue); + } + + foreach (var stringKey in _stringKeys) + { + string currentValue = _strVal[stringKey]; + if (currentValue.Any()) + obj.Add(stringKey, currentValue); + } + + foreach (var listKey in _listKeys) + { + var currentValue = _listVal[listKey]; + if (currentValue.Where(x => x.Any()).Any()) + { + obj.Add( + listKey, + new JsonArray( + currentValue.Select(x => JsonValue.Create(x) as JsonNode).ToArray() + ) + ); + } + } + + return obj; + } + + private static List _readArrayFromJson(JsonNode data, string name) + { + List result = new List(); + foreach (var element in data[name]?.AsArray2() ?? []) + if (element is not null) + result.Add(element.GetVal()); + return result.Where(x => x.Any()).ToList(); + } + + public bool DiffersFromDefault() + { + foreach (var (boolKey, defValue) in _defaultBoolValues) + if (_boolVal[boolKey] != defValue) + return true; + + foreach (var stringKey in _stringKeys) + if (_strVal[stringKey].Any()) + return true; + + foreach (var listKey in _listKeys) + if (_listVal[listKey].Where(x => x.Any()).Any()) + return true; + + return false; + // OverridesNextLevelOpts does not need to be checked here, since + // this method is invoked before this property has been set + } + + public InstallOptions() + : base() + { + // Initialize default values, ensure keys exist + foreach (var (boolKey, defValue) in _defaultBoolValues) + _boolVal[boolKey] = defValue; + + foreach (var stringKey in _stringKeys) + _strVal[stringKey] = ""; + + foreach (var listKey in _listKeys) + _listVal[listKey] = new(); + } + + public InstallOptions(JsonNode data) + { + // No need to ensure keys exist, LoadFromJson will do that + LoadFromJson(data); + } + + public override string ToString() + { + StringBuilder b = new(" x.Any()).Any()) + { + b.Append($"\n\t{listKey}: [{string.Join(", ", currentValue)}]"); + } + } + + b.Append($"\n\tOverridesNextLevelOpts: {OverridesNextLevelOpts}>"); + return b.ToString(); + } + } +} diff --git a/src/UniGetUI.PackageEngine.Serializable/SerializableBundle.cs b/src/UniGetUI.PackageEngine.Serializable/SerializableBundle.cs new file mode 100644 index 0000000..7c4bbaf --- /dev/null +++ b/src/UniGetUI.PackageEngine.Serializable/SerializableBundle.cs @@ -0,0 +1,86 @@ +using System.Text.Json.Nodes; +using UniGetUI.Core.Data; +using UniGetUI.PackageEngine.Serializable; + +namespace UniGetUI.PackageEngine.Classes.Serializable +{ + public class SerializableBundle : SerializableComponent + { + public const double ExpectedVersion = 3; + public const string IncompatMessage = + "Incompatible packages cannot be installed from UniGetUI, " + + "either because they came from a local source (for example Local PC) " + + "or because the package manager was unavailable. " + + "Nevertheless, they have been listed here for logging purposes."; + + public double export_version { get; set; } = 3; + public List packages { get; set; } = []; + public string incompatible_packages_info { get; set; } = IncompatMessage; + public List incompatible_packages { get; set; } = []; + + public override SerializableBundle Copy() + { + var _packages = new List(); + var _incompatPackages = new List(); + + foreach (var package in this.packages) + _packages.Add(package.Copy()); + + foreach (var incompatPackage in this.incompatible_packages) + _incompatPackages.Add(incompatPackage.Copy()); + + return new() + { + export_version = this.export_version, + packages = _packages, + incompatible_packages_info = this.incompatible_packages_info, + incompatible_packages = _incompatPackages, + }; + } + + public override void LoadFromJson(JsonNode data) + { + this.export_version = data[nameof(export_version)]?.GetVal() ?? 0; + this.incompatible_packages_info = + data[nameof(incompatible_packages_info)]?.GetVal() ?? IncompatMessage; + this.packages = new List(); + this.incompatible_packages = new List(); + + foreach (JsonNode? pkg in data[nameof(packages)]?.AsArray2() ?? new()) + { + if (pkg is null) + throw new InvalidDataException("JsonNode? pkg was null, when it shouldn't"); + packages.Add(new SerializablePackage(pkg)); + } + + foreach (JsonNode? inc_pkg in data[nameof(incompatible_packages)]?.AsArray2() ?? new()) + { + if (inc_pkg is null) + throw new InvalidDataException("JsonNode? inc_pkg was null, when it shouldn't"); + incompatible_packages.Add(new SerializableIncompatiblePackage(inc_pkg)); + } + } + + public override JsonObject AsJsonNode() + { + JsonObject obj = new(); + obj.Add(nameof(export_version), export_version); + obj.Add( + nameof(packages), + new JsonArray(packages.Select(p => p.AsJsonNode()).ToArray()) + ); + obj.Add(nameof(incompatible_packages_info), incompatible_packages_info); + obj.Add( + nameof(incompatible_packages), + new JsonArray(incompatible_packages.Select(p => p.AsJsonNode()).ToArray()) + ); + return obj; + } + + public SerializableBundle() + : base() { } + + public SerializableBundle(JsonNode data) + : base(data) { } + } +} diff --git a/src/UniGetUI.PackageEngine.Serializable/SerializableComponent.cs b/src/UniGetUI.PackageEngine.Serializable/SerializableComponent.cs new file mode 100644 index 0000000..974cf5f --- /dev/null +++ b/src/UniGetUI.PackageEngine.Serializable/SerializableComponent.cs @@ -0,0 +1,50 @@ +using System.Text.Json; +using System.Text.Json.Nodes; +using UniGetUI.Core.Data; + +namespace UniGetUI.PackageEngine.Serializable; + +public abstract class SerializableComponent + where T : class +{ + /// + /// Creates a deep copy of the object + /// + /// A memory-independend copy of this + public abstract T Copy(); + + /// + /// Loads data for this object from a JsonNode object + /// + /// The JSON from which to load the data + public abstract void LoadFromJson(JsonNode data); + + /// + /// Serializes this object into a JsonNode object + /// + /// A pretty-formatted JSON string representing the current data + public string AsJsonString() + { + return AsJsonNode().ToJsonString(SerializationHelpers.DefaultOptions); + } + + /// + /// Serializes this object into a JsonNode object + /// + /// A pretty-formatted JSON string representing the current data + public abstract JsonObject AsJsonNode(); + + /// + /// Creates an instance of this object with the default data + /// + public SerializableComponent() { } + + /// + /// Creates an instance of this object, and loads the data from the given JsonNode object + /// + /// The JSON from which to load the data + public SerializableComponent(JsonNode data) + { + LoadFromJson(data); + } +} diff --git a/src/UniGetUI.PackageEngine.Serializable/SerializableIncompatiblePackage.cs b/src/UniGetUI.PackageEngine.Serializable/SerializableIncompatiblePackage.cs new file mode 100644 index 0000000..dcbaf40 --- /dev/null +++ b/src/UniGetUI.PackageEngine.Serializable/SerializableIncompatiblePackage.cs @@ -0,0 +1,50 @@ +using System.Text.Json.Nodes; +using UniGetUI.Core.Data; +using UniGetUI.PackageEngine.Serializable; + +namespace UniGetUI.PackageEngine.Classes.Serializable +{ + public class SerializableIncompatiblePackage + : SerializableComponent + { + public string Id { get; set; } = ""; + public string Name { get; set; } = ""; + public string Version { get; set; } = ""; + public string Source { get; set; } = ""; + + public override SerializableIncompatiblePackage Copy() + { + return new() + { + Id = this.Id, + Name = this.Name, + Version = this.Version, + Source = this.Source, + }; + } + + public override void LoadFromJson(JsonNode data) + { + this.Id = data[nameof(Id)]?.GetVal() ?? ""; + this.Name = data[nameof(Name)]?.GetVal() ?? ""; + this.Version = data[nameof(Version)]?.GetVal() ?? ""; + this.Source = data[nameof(Source)]?.GetVal() ?? ""; + } + + public override JsonObject AsJsonNode() + { + JsonObject obj = new(); + obj.Add(nameof(Id), Id); + obj.Add(nameof(Name), Name); + obj.Add(nameof(Version), Version); + obj.Add(nameof(Source), Source); + return obj; + } + + public SerializableIncompatiblePackage(JsonNode data) + : base(data) { } + + public SerializableIncompatiblePackage() + : base() { } + } +} diff --git a/src/UniGetUI.PackageEngine.Serializable/SerializablePackage.cs b/src/UniGetUI.PackageEngine.Serializable/SerializablePackage.cs new file mode 100644 index 0000000..88de99c --- /dev/null +++ b/src/UniGetUI.PackageEngine.Serializable/SerializablePackage.cs @@ -0,0 +1,89 @@ +using System.Text.Json.Nodes; +using UniGetUI.Core.Data; +using UniGetUI.PackageEngine.Serializable; + +namespace UniGetUI.PackageEngine.Classes.Serializable +{ + public class SerializablePackage : SerializableComponent + { + public string Id { get; set; } = ""; + public string Name { get; set; } = ""; + public string Version { get; set; } = ""; + public string Source { get; set; } = ""; + public string ManagerName { get; set; } = ""; + + public InstallOptions InstallationOptions { get; set; } = new(); + public SerializableUpdatesOptions Updates { get; set; } = new(); + + public override SerializablePackage Copy() + { + return new SerializablePackage() + { + Name = this.Name, + Id = this.Id, + Version = this.Version, + Source = this.Source, + ManagerName = this.ManagerName, + InstallationOptions = this.InstallationOptions.Copy(), + Updates = this.Updates.Copy(), + }; + } + + public override void LoadFromJson(JsonNode data) + { + this.Name = data[nameof(Name)]?.GetVal() ?? ""; + this.Id = data[nameof(Id)]?.GetVal() ?? ""; + this.Version = data[nameof(Version)]?.GetVal() ?? ""; + this.Source = data[nameof(Source)]?.GetVal() ?? ""; + this.ManagerName = data[nameof(ManagerName)]?.GetVal() ?? ""; + + this.InstallationOptions = new(data[nameof(InstallationOptions)] ?? new JsonObject()); + this.Updates = new(data[nameof(Updates)] ?? new JsonObject()); + } + + public override JsonObject AsJsonNode() + { + JsonObject obj = new(); + obj.Add(nameof(Id), Id); + obj.Add(nameof(Name), Name); + obj.Add(nameof(Version), Version); + obj.Add(nameof(Source), Source); + obj.Add(nameof(ManagerName), ManagerName); + + var ioNode = InstallationOptions.AsJsonNode(); + if (ioNode.Count > 0) + { + obj.Add(nameof(InstallationOptions), InstallationOptions.AsJsonNode()); + } + + var updNode = Updates.AsJsonNode(); + if (updNode.Count > 0) + { + obj.Add(nameof(Updates), updNode); + } + + return obj; + } + + public SerializablePackage() + : base() { } + + public SerializablePackage(JsonNode data) + : base(data) { } + + /// + /// Returns an equivalent copy of the current package as an Invalid Serializable Package. + /// The reverse operation is not possible, since data is lost. + /// + public SerializableIncompatiblePackage GetInvalidEquivalent() + { + return new SerializableIncompatiblePackage + { + Id = Id, + Name = Name, + Version = Version, + Source = Source, + }; + } + } +} diff --git a/src/UniGetUI.PackageEngine.Serializable/SerializableUpdatesOptions.cs b/src/UniGetUI.PackageEngine.Serializable/SerializableUpdatesOptions.cs new file mode 100644 index 0000000..205ce1e --- /dev/null +++ b/src/UniGetUI.PackageEngine.Serializable/SerializableUpdatesOptions.cs @@ -0,0 +1,43 @@ +using System.Text.Json.Nodes; +using UniGetUI.Core.Data; +using UniGetUI.PackageEngine.Serializable; + +namespace UniGetUI.PackageEngine.Classes.Serializable +{ + public class SerializableUpdatesOptions : SerializableComponent + { + public bool UpdatesIgnored { get; set; } + public string IgnoredVersion { get; set; } = ""; + + public override SerializableUpdatesOptions Copy() + { + return new() + { + UpdatesIgnored = this.UpdatesIgnored, + IgnoredVersion = this.IgnoredVersion, + }; + } + + public override void LoadFromJson(JsonNode data) + { + this.UpdatesIgnored = data[nameof(UpdatesIgnored)]?.GetVal() ?? false; + this.IgnoredVersion = data[nameof(IgnoredVersion)]?.GetVal() ?? ""; + } + + public override JsonObject AsJsonNode() + { + JsonObject obj = new(); + if (UpdatesIgnored is not false) + obj.Add(nameof(UpdatesIgnored), UpdatesIgnored); + if (IgnoredVersion.Any()) + obj.Add(nameof(IgnoredVersion), IgnoredVersion); + return obj; + } + + public SerializableUpdatesOptions() + : base() { } + + public SerializableUpdatesOptions(JsonNode data) + : base(data) { } + } +} diff --git a/src/UniGetUI.PackageEngine.Serializable/UniGetUI.PackageEngine.Serializable.csproj b/src/UniGetUI.PackageEngine.Serializable/UniGetUI.PackageEngine.Serializable.csproj new file mode 100644 index 0000000..139499f --- /dev/null +++ b/src/UniGetUI.PackageEngine.Serializable/UniGetUI.PackageEngine.Serializable.csproj @@ -0,0 +1,13 @@ + + + $(SharedTargetFrameworks) + + + + + + + + + + diff --git a/src/UniGetUI.PackageEngine.Tests/BunManagerTests.cs b/src/UniGetUI.PackageEngine.Tests/BunManagerTests.cs new file mode 100644 index 0000000..913b231 --- /dev/null +++ b/src/UniGetUI.PackageEngine.Tests/BunManagerTests.cs @@ -0,0 +1,809 @@ +using UniGetUI.Interface.Enums; +using UniGetUI.PackageEngine.Enums; +using UniGetUI.PackageEngine.ManagerClasses.Manager; +using UniGetUI.PackageEngine.Managers.BunManager; +using UniGetUI.PackageEngine.PackageClasses; +using UniGetUI.PackageEngine.Serializable; +using UniGetUI.PackageEngine.Structs; +using UniGetUI.PackageEngine.Tests.Infrastructure.Assertions; +using UniGetUI.PackageEngine.Tests.Infrastructure.Builders; +using UniGetUI.PackageEngine.Tests.Infrastructure.Helpers; + +namespace UniGetUI.PackageEngine.Tests; + +/// +/// Unit and integration tests for the Bun package manager. +/// Tests cover search, package listing, updates detection, and package operations. +/// +public sealed class BunManagerTests +{ + private sealed class TestableBun : Bun + { + public IReadOnlyList GetAvailableUpdatesUnsafe() => base.GetAvailableUpdates_UnSafe(); + } + + /// + /// Tests parsing of the npm registry search response (registry.npmjs.org/-/v1/search). + /// Verifies that multiple packages with different names and versions are correctly parsed. + /// + [Fact] + public void ParseSearchOutputParsesRegistryResponse() + { + var manager = new Bun(); + + var searchOutput = PackageEngineFixtureFiles.ReadAllText(Path.Combine("Bun", "search-results.json")); + var packages = Bun.ParseSearchOutput(searchOutput, manager.DefaultSource, manager); + + var packageList = packages.ToArray(); + Assert.Equal(3, packageList.Length); + + // Verify first package + PackageAssert.BelongsTo(packageList[0], manager, manager.DefaultSource); + Assert.Equal("typescript", packageList[0].Id); + Assert.Equal("5.3.3", packageList[0].VersionString); + + // Verify second package + PackageAssert.BelongsTo(packageList[1], manager, manager.DefaultSource); + Assert.Equal("lodash", packageList[1].Id); + Assert.Equal("4.17.21", packageList[1].VersionString); + + // Verify scoped package + PackageAssert.BelongsTo(packageList[2], manager, manager.DefaultSource); + Assert.Equal("@types/node", packageList[2].Id); + Assert.Equal("20.10.6", packageList[2].VersionString); + } + + /// + /// Tests parsing of the outdated packages table output from 'bun outdated'. + /// Verifies that the Unicode box-drawing table format is correctly parsed. + /// + [Fact] + public void ParseBunOutdatedTableParsesUnicodeTable() + { + var outdatedOutput = PackageEngineFixtureFiles.ReadAllText(Path.Combine("Bun", "outdated-table.txt")); + + var results = Bun.ParseBunOutdatedTable(outdatedOutput).ToList(); + + Assert.Equal(3, results.Count); + + // Verify first package (typescript) + Assert.Equal("typescript", results[0].Id); + Assert.Equal("5.2.0", results[0].Version); + Assert.Equal("5.3.0", results[0].NewVersion); + + // Verify scoped package (@types/node) + Assert.Equal("@types/node", results[1].Id); + Assert.Equal("20.8.0", results[1].Version); + Assert.Equal("20.9.0", results[1].NewVersion); + + // Verify third package (vite) + Assert.Equal("vite", results[2].Id); + Assert.Equal("4.5.0", results[2].Version); + Assert.Equal("4.5.1", results[2].NewVersion); + } + + /// + /// Tests that ParseBunOutdatedTable skips the header row and empty lines. + /// + [Fact] + public void ParseBunOutdatedTableSkipsHeaderAndEmptyLines() + { + var output = """ + |-------------------------------------------------| + | Package | Current | Update | Latest | + |--------------------------------------------------| + | typescript | 5.2.0 | 5.3.0 | 5.4.0 | + |-------------------------------------------------| + """; + + var results = Bun.ParseBunOutdatedTable(output).ToList(); + + Assert.Single(results); + Assert.Equal("typescript", results[0].Id); + } + + /// + /// Tests that ParseBunOutdatedTable returns empty list for invalid input. + /// + [Fact] + public void ParseBunOutdatedTableReturnsEmptyForInvalidInput() + { + var output = "Invalid output format\nNo table here"; + + var results = Bun.ParseBunOutdatedTable(output).ToList(); + + Assert.Empty(results); + } + + /// + /// Tests that ParseBunOutdatedTable skips border lines (all dashes or box-drawing chars). + /// Verifies that lines like |---| or ├─┤ are not parsed as packages. + /// + [Fact] + public void ParseBunOutdatedTableSkipsBorderLines() + { + var output = """ + bun outdated v1.3.9 + |-------------------------------------------------| + | Package | Current | Update | Latest | + |--------------------------------------------------| + | typescript | 5.2.0 | 5.3.0 | 5.4.0 | + |-------------------------------------------------| + | lodash | 4.17.0 | 4.17.21 | 4.17.21 | + |-------------------------------------------------| + """; + + var results = Bun.ParseBunOutdatedTable(output).ToList(); + + // Should find both typescript and lodash with updates, and skip all border lines + Assert.Equal(2, results.Count); + Assert.Equal("typescript", results[0].Id); + Assert.Equal("lodash", results[1].Id); + } + + /// + /// Tests that ParseBunOutdatedTable skips Unicode box-drawing borders. + /// + [Fact] + public void ParseBunOutdatedTableSkipsUnicodeBorders() + { + var output = """ + bun outdated v1.3.10 + ┌────────────────┬─────────┬────────┬────────┐ + │ Package │ Current │ Update │ Latest │ + ├────────────────┼─────────┼────────┼────────┤ + │ typescript │ 5.2.0 │ 5.3.0 │ 5.4.0 │ + ├────────────────┼─────────┼────────┼────────┤ + │ lodash │ 4.17.0 │ 4.17.21│ 4.17.21│ + └────────────────┴─────────┴────────┴────────┘ + """; + + var results = Bun.ParseBunOutdatedTable(output).ToList(); + + // Should find both packages with updates, and skip Unicode border lines + Assert.Equal(2, results.Count); + Assert.Equal("typescript", results[0].Id); + Assert.Equal("lodash", results[1].Id); + } + + /// + /// Tests that ParseBunOutdatedTable uses "Update" column by default (preferLatest=false). + /// This provides safe, semantic-versioning compatible updates. + /// + [Fact] + public void ParseBunOutdatedTableUsesUpdateColumnByDefault() + { + var output = """ + |-------------------------------------------------| + | Package | Current | Update | Latest | + |--------------------------------------------------| + | typescript | 5.2.0 | 5.3.0 | 6.0.0 | + | lodash | 4.17.0 | 4.17.21 | 4.17.21 | + |-------------------------------------------------| + """; + + var results = Bun.ParseBunOutdatedTable(output, preferLatest: false).ToList(); + + Assert.Equal(2, results.Count); + // typescript: uses Update column (5.3.0), not Latest (6.0.0) + Assert.Equal("typescript", results[0].Id); + Assert.Equal("5.3.0", results[0].NewVersion); + // lodash: Update == Latest, so only one entry + Assert.Equal("lodash", results[1].Id); + Assert.Equal("4.17.21", results[1].NewVersion); + } + + /// + /// Tests that ParseBunOutdatedTable uses "Latest" column when preferLatest=true. + /// This allows users to upgrade to the absolute latest, even with breaking changes. + /// + [Fact] + public void ParseBunOutdatedTableUsesLatestColumnWhenPreferLatest() + { + var output = """ + |-------------------------------------------------| + | Package | Current | Update | Latest | + |--------------------------------------------------| + | typescript | 5.2.0 | 5.3.0 | 6.0.0 | + | lodash | 4.17.0 | 4.17.21 | 4.17.21 | + |-------------------------------------------------| + """; + + var results = Bun.ParseBunOutdatedTable(output, preferLatest: true).ToList(); + + Assert.Equal(2, results.Count); + // typescript: uses Latest column (6.0.0), not Update (5.3.0) + Assert.Equal("typescript", results[0].Id); + Assert.Equal("6.0.0", results[0].NewVersion); + // lodash: Update == Latest, so included + Assert.Equal("lodash", results[1].Id); + Assert.Equal("4.17.21", results[1].NewVersion); + } + + /// + /// Tests parsing of the tree output from 'bun pm ls --global'. + /// Verifies that globally installed packages are correctly extracted from the tree structure. + /// + [Fact] + public void ParseInstalledPackagesOutputParsesTreeFormat() + { + var manager = new Bun(); + var installedOutput = PackageEngineFixtureFiles.ReadAllText(Path.Combine("Bun", "installed.txt")); + + var packages = Bun.ParseInstalledPackages(installedOutput, manager.DefaultSource, manager, + new OverridenInstallationOptions(PackageScope.Global)); + + var packageList = packages.ToArray(); + Assert.Equal(5, packageList.Length); + + // Verify first package + Assert.Equal("typescript", packageList[0].Id); + Assert.Equal("5.7.3", packageList[0].VersionString); + Assert.Equal(PackageScope.Global, packageList[0].OverridenOptions.Scope); + + // Verify scoped package + Assert.Equal("@devcontainers/cli", packageList[1].Id); + Assert.Equal("0.81.1", packageList[1].VersionString); + + // Verify last package + Assert.Equal("bunx", packageList[4].Id); + Assert.Equal("1.0.24", packageList[4].VersionString); + } + + /// + /// Tests that scoped packages (with @ prefix) are correctly handled. + /// + [Fact] + public void ParseInstalledPackagesHandlesScopedPackagesCorrectly() + { + var manager = new Bun(); + var output = """ + /home/user/.bun/install/global node_modules (2) + ├── @scope/package@1.0.0 + └── @another-scope/tool@2.5.3 + """; + + var packages = Bun.ParseInstalledPackages(output, manager.DefaultSource, manager, + new OverridenInstallationOptions(PackageScope.Global)); + + var packageList = packages.ToArray(); + Assert.Equal(2, packageList.Length); + Assert.Equal("@scope/package", packageList[0].Id); + Assert.Equal("1.0.0", packageList[0].VersionString); + Assert.Equal("@another-scope/tool", packageList[1].Id); + Assert.Equal("2.5.3", packageList[1].VersionString); + } + + /// + /// Tests that invalid or malformed tree lines are skipped during parsing. + /// + [Fact] + public void ParseInstalledPackagesSkipsInvalidLines() + { + var manager = new Bun(); + var output = """ + /home/user/.bun/install/global node_modules + Invalid line without marker + ├── valid-package@1.0.0 + └── another@2.0.0 + └── @invalid-version + """; + + var packages = Bun.ParseInstalledPackages(output, manager.DefaultSource, manager, + new OverridenInstallationOptions(PackageScope.Global)); + + // Should only parse the two valid packages + Assert.Equal(2, packages.Count); + } + + /// + /// Tests that search returns empty list for an empty registry response. + /// + [Fact] + public void ParseSearchOutputReturnsEmptyForEmptyResults() + { + var manager = new Bun(); + var packages = Bun.ParseSearchOutput("""{"objects":[],"total":0}""", manager.DefaultSource, manager); + + Assert.Empty(packages); + } + + /// + /// Tests OperationHelper builds correct install parameters for basic install. + /// + [Fact] + public void OperationHelperBuildsInstallParameters() + { + var manager = new Bun(); + var package = new PackageBuilder() + .WithManager(manager) + .WithId("typescript") + .WithVersion("5.3.3") + .Build(); + + var parameters = manager.OperationHelper.GetParameters(package, new InstallOptions(), OperationType.Install); + + Assert.Contains("add", parameters); + Assert.Contains("typescript@5.3.3", parameters); + Assert.Contains("--global", parameters); + } + + /// + /// Tests OperationHelper correctly adds --global flag for global scope. + /// + [Fact] + public void OperationHelperAddsGlobalFlagForGlobalScope() + { + var manager = new Bun(); + var package = new PackageBuilder() + .WithManager(manager) + .WithId("typescript") + .WithVersion("5.3.3") + .Build(); + + var options = new InstallOptions { InstallationScope = PackageScope.Global }; + var parameters = manager.OperationHelper.GetParameters(package, options, OperationType.Install); + + Assert.Contains("--global", parameters); + } + + /// + /// Tests OperationHelper uses custom version when specified in options. + /// + [Fact] + public void OperationHelperUsesCustomVersionFromOptions() + { + var manager = new Bun(); + var package = new PackageBuilder() + .WithManager(manager) + .WithId("lodash") + .WithVersion("4.17.20") + .Build(); + + var options = new InstallOptions { Version = "4.17.21" }; + var parameters = manager.OperationHelper.GetParameters(package, options, OperationType.Install); + + Assert.Contains("lodash@4.17.21", parameters); + } + + /// + /// Tests OperationHelper builds correct uninstall parameters. + /// + [Fact] + public void OperationHelperBuildsUninstallParameters() + { + var manager = new Bun(); + var package = new PackageBuilder() + .WithManager(manager) + .WithId("typescript") + .WithVersion("5.3.3") + .Build(); + + var parameters = manager.OperationHelper.GetParameters(package, new InstallOptions(), OperationType.Uninstall); + + Assert.Contains("remove", parameters); + Assert.Contains("typescript", parameters); + } + + /// + /// Tests OperationHelper builds correct update parameters. + /// + [Fact] + public void OperationHelperBuildsUpdateParameters() + { + var manager = new Bun(); + var package = new PackageBuilder() + .WithManager(manager) + .WithId("typescript") + .WithVersion("5.2.0") + .WithNewVersion("5.4.0") + .Build(); + + var parameters = manager.OperationHelper.GetParameters(package, new InstallOptions(), OperationType.Update); + + Assert.Contains("add", parameters); + Assert.Contains("typescript@5.4.0", parameters); + } + + /// + /// Tests OperationHelper respects package's overridden scope over options scope. + /// + [Fact] + public void OperationHelperRespectsPackageScopeOverOption() + { + var manager = new Bun(); + var package = new PackageBuilder() + .WithManager(manager) + .WithId("typescript") + .WithVersion("5.3.3") + .WithOptions(new OverridenInstallationOptions(PackageScope.Global)) + .Build(); + + var options = new InstallOptions { InstallationScope = PackageScope.Local }; + var parameters = manager.OperationHelper.GetParameters(package, options, OperationType.Install); + + Assert.Contains("--global", parameters); + } + + /// + /// Tests OperationHelper allows explicit local installs when scope is overridden. + /// + [Fact] + public void OperationHelperDoesNotAddGlobalFlagForExplicitLocalScope() + { + var manager = new Bun(); + var package = new PackageBuilder() + .WithManager(manager) + .WithId("typescript") + .WithVersion("5.3.3") + .WithOptions(new OverridenInstallationOptions(PackageScope.Local)) + .Build(); + + var parameters = manager.OperationHelper.GetParameters(package, new InstallOptions(), OperationType.Install); + + Assert.DoesNotContain("--global", parameters); + } + + /// + /// Tests OperationHelper includes custom install parameters. + /// + [Fact] + public void OperationHelperIncludesCustomParameters() + { + var manager = new Bun(); + var package = new PackageBuilder() + .WithManager(manager) + .WithId("typescript") + .WithVersion("5.3.3") + .Build(); + + var options = new InstallOptions(); + options.CustomParameters_Install.Add("--save-dev"); + options.CustomParameters_Install.Add("--no-save"); + + var parameters = manager.OperationHelper.GetParameters(package, options, OperationType.Install); + + Assert.Contains("--save-dev", parameters); + Assert.Contains("--no-save", parameters); + } + + /// + /// Tests OperationHelper returns Success for zero exit code. + /// + [Fact] + public void OperationHelperReturnsSuccessForZeroExitCode() + { + var manager = new Bun(); + var package = new PackageBuilder().WithManager(manager).Build(); + + var result = manager.OperationHelper.GetResult(package, OperationType.Install, [], 0); + + Assert.Equal(OperationVeredict.Success, result); + } + + /// + /// Tests OperationHelper returns Failure for non-zero exit code. + /// + [Fact] + public void OperationHelperReturnsFailureForNonZeroExitCode() + { + var manager = new Bun(); + var package = new PackageBuilder().WithManager(manager).Build(); + + var result = manager.OperationHelper.GetResult(package, OperationType.Install, [], 1); + + Assert.Equal(OperationVeredict.Failure, result); + } + + /// + /// Tests that manager has correct capabilities configured. + /// + [Fact] + public void BunManagerHasCorrectCapabilities() + { + var manager = new Bun(); + + Assert.True(manager.Capabilities.CanRunAsAdmin); + Assert.True(manager.Capabilities.SupportsCustomVersions); + Assert.True(manager.Capabilities.CanDownloadInstaller); + Assert.False(manager.Capabilities.SupportsCustomScopes); + Assert.True(manager.Capabilities.CanListDependencies); + Assert.True(manager.Capabilities.SupportsPreRelease); + Assert.Equal(ProxySupport.No, manager.Capabilities.SupportsProxy); + Assert.False(manager.Capabilities.SupportsProxyAuth); + } + + /// + /// Tests that manager properties are correctly configured. + /// + [Fact] + public void BunManagerHasCorrectProperties() + { + var manager = new Bun(); + + Assert.Equal("bun", manager.Properties.Id); + Assert.Equal("Bun", manager.Properties.Name); + Assert.Equal("add", manager.Properties.InstallVerb); + Assert.Equal("remove", manager.Properties.UninstallVerb); + Assert.Equal("add", manager.Properties.UpdateVerb); + Assert.NotNull(manager.Properties.DefaultSource); + Assert.Equal("https://www.npmjs.com/", manager.Properties.DefaultSource.Url.ToString()); + } + + /// + /// Tests that scoped packages with multiple @ symbols are handled correctly. + /// This is a regression test for packages like @scope/name@version. + /// + [Fact] + public void ParseInstalledPackagesHandlesMultipleAtSymbols() + { + var manager = new Bun(); + var output = """ + /home/user/.bun/install/global node_modules (1) + └── @babel/core@7.23.5 + """; + + var packages = Bun.ParseInstalledPackages(output, manager.DefaultSource, manager, + new OverridenInstallationOptions(PackageScope.Global)); + + Assert.Single(packages); + Assert.Equal("@babel/core", packages[0].Id); + Assert.Equal("7.23.5", packages[0].VersionString); + } + + /// + /// Tests that ParseBunOutdatedTable correctly identifies and skips the Package header. + /// + [Fact] + public void ParseBunOutdatedTableSkipsPackageHeader() + { + var output = """ + bun outdated v1.3.9 + |-------------------------------------------------| + | Package | Current | Update | Latest | + |--------------------------------------------------| + | typescript | 5.2.0 | 5.3.0 | 5.4.0 | + |-------------------------------------------------| + """; + + var results = Bun.ParseBunOutdatedTable(output).ToList(); + + Assert.Single(results); + Assert.Equal("typescript", results[0].Id); + Assert.Equal("5.2.0", results[0].Version); + Assert.Equal("5.3.0", results[0].NewVersion); + } + + /// + /// Tests parsing of Unicode box-drawing table format from 'bun outdated' (v1.3.10+). + /// Real-world output uses Unicode box-drawing characters instead of ASCII pipes. + /// Verifies that the parser correctly handles both formats. + /// + [Fact] + public void ParseBunOutdatedTableHandlesUnicodeBoxDrawingFormat() + { + var output = """ + bun outdated v1.3.10 (30e609e0) + ┌───────────────────────────┬─────────┬────────┬────────┐ + │ Package │ Current │ Update │ Latest │ + ├───────────────────────────┼─────────┼────────┼────────┤ + │ @types/jest │ 29.6.0 │ 29.6.0 │ 30.0.0 │ + ├───────────────────────────┼─────────┼────────┼────────┤ + │ @org/shared-lib │ 3.2.0 │ 3.2.0 │ 4.0.0 │ + └───────────────────────────┴─────────┴────────┴────────┘ + """; + + var results = Bun.ParseBunOutdatedTable(output).ToList(); + + // Both packages have Current == Update, so they should NOT be included (no updates available) + Assert.Empty(results); + } + + /// + /// Tests that ParseBunOutdatedTable correctly handles Unicode format with actual updates available. + /// + [Fact] + public void ParseBunOutdatedTableHandlesUnicodeBoxDrawingWithUpdates() + { + var output = """ + bun outdated v1.3.10 + ┌────────────────┬─────────┬────────┬────────┐ + │ Package │ Current │ Update │ Latest │ + ├────────────────┼─────────┼────────┼────────┤ + │ typescript │ 5.2.0 │ 5.3.0 │ 5.4.0 │ + ├────────────────┼─────────┼────────┼────────┤ + │ @types/node │ 20.8.0 │ 20.9.0 │ 20.10.0│ + └────────────────┴─────────┴────────┴────────┘ + """; + + var results = Bun.ParseBunOutdatedTable(output).ToList(); + + Assert.Equal(2, results.Count); + Assert.Equal("typescript", results[0].Id); + Assert.Equal("5.2.0", results[0].Version); + Assert.Equal("5.3.0", results[0].NewVersion); + Assert.Equal("@types/node", results[1].Id); + Assert.Equal("20.8.0", results[1].Version); + Assert.Equal("20.9.0", results[1].NewVersion); + } + + /// + /// Tests that Unicode box-drawing format works with preferLatest=true. + /// This scenario matches when a user enables BunPreferLatestVersions setting + /// and runs bun outdated with the new Unicode table format. + /// + [Fact] + public void ParseBunOutdatedTableHandlesUnicodeWithPreferLatest() + { + var output = """ + bun outdated v1.3.10 (30e609e0) + ┌───────────────────────────┬─────────┬────────┬────────┐ + │ Package │ Current │ Update │ Latest │ + ├───────────────────────────┼─────────┼────────┼────────┤ + │ @types/jest │ 29.6.0 │ 29.6.0 │ 30.0.0 │ + ├───────────────────────────┼─────────┼────────┼────────┤ + │ @org/shared-lib │ 3.2.0 │ 3.2.0 │ 4.0.0 │ + └───────────────────────────┴─────────┴────────┴────────┘ + """; + + // With preferLatest=false (default), no updates because Update column = Current + var resultsDefault = Bun.ParseBunOutdatedTable(output, preferLatest: false).ToList(); + Assert.Empty(resultsDefault); + + // With preferLatest=true, both packages should show as having updates from Latest column + var resultsPreferLatest = Bun.ParseBunOutdatedTable(output, preferLatest: true).ToList(); + Assert.Equal(2, resultsPreferLatest.Count); + Assert.Equal("@types/jest", resultsPreferLatest[0].Id); + Assert.Equal("29.6.0", resultsPreferLatest[0].Version); + Assert.Equal("30.0.0", resultsPreferLatest[0].NewVersion); + Assert.Equal("@org/shared-lib", resultsPreferLatest[1].Id); + Assert.Equal("3.2.0", resultsPreferLatest[1].Version); + Assert.Equal("4.0.0", resultsPreferLatest[1].NewVersion); + } + + /// + /// Tests that manager returns public interface correctly (IPackageManager compliance). + /// + [Fact] + public void ParseAvailableUpdatesRespectsPreferlatesParameter() + { + var manager = new Bun(); + var output = """ + |-------------------------------------------------| + | Package | Current | Update | Latest | + |--------------------------------------------------| + | typescript | 5.2.0 | 5.3.0 | 6.0.0 | + |-------------------------------------------------| + """; + + // Test with preferLatest=false (default): should use Update column (5.3.0) + var resultsUpdate = Bun.ParseAvailableUpdates(output, manager.DefaultSource, manager, preferLatest: false); + Assert.Single(resultsUpdate); + Assert.Equal("typescript", resultsUpdate[0].Id); + Assert.Equal("5.3.0", resultsUpdate[0].NewVersionString); + + // Test with preferLatest=true: should use Latest column (6.0.0) + var resultsLatest = Bun.ParseAvailableUpdates(output, manager.DefaultSource, manager, preferLatest: true); + Assert.Single(resultsLatest); + Assert.Equal("typescript", resultsLatest[0].Id); + Assert.Equal("6.0.0", resultsLatest[0].NewVersionString); + } + + /// + /// Tests Bun global updates are skipped when there is no global package manifest. + /// + [Fact] + public void HasGlobalPackageManifestRequiresPackageJson() + { + string globalDir = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString("N")); + + try + { + Directory.CreateDirectory(globalDir); + + Assert.False(Bun.HasGlobalPackageManifest(globalDir)); + + File.WriteAllText(Path.Combine(globalDir, "package.json"), "{}"); + + Assert.True(Bun.HasGlobalPackageManifest(globalDir)); + } + finally + { + if (Directory.Exists(globalDir)) + Directory.Delete(globalDir, recursive: true); + } + } + + /// + /// Tests Bun update detection returns no results when the global manifest is missing. + /// + [Fact] + public void GetAvailableUpdatesReturnsEmptyWhenGlobalManifestIsMissing() + { + string userProfile = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile); + string globalDir = Bun.GetGlobalPackagesDirectory(userProfile); + string manifestPath = Path.Combine(globalDir, "package.json"); + string backupManifestPath = manifestPath + ".bun-test-backup"; + + if (!Directory.Exists(globalDir)) + { + Assert.Empty(new TestableBun().GetAvailableUpdatesUnsafe()); + return; + } + + bool restoreManifest = false; + + try + { + if (File.Exists(backupManifestPath)) + File.Delete(backupManifestPath); + + if (File.Exists(manifestPath)) + { + File.Move(manifestPath, backupManifestPath); + restoreManifest = true; + } + + Assert.Empty(new TestableBun().GetAvailableUpdatesUnsafe()); + } + finally + { + if (restoreManifest) + { + if (File.Exists(manifestPath)) + File.Delete(manifestPath); + File.Move(backupManifestPath, manifestPath); + } + } + } + + /// + /// Tests Bun install location defaults to the global Bun node_modules directory. + /// + [Fact] + public void GetInstallLocationDefaultsToBunGlobalNodeModules() + { + string userProfile = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile); + string location = BunPkgDetailsHelper.GetInstallLocation(userProfile, null, "typescript"); + + Assert.Equal( + Path.Join(userProfile, ".bun", "install", "global", "node_modules", "typescript"), + location); + } + + /// + /// Tests Bun install location honors explicit local scope. + /// + [Fact] + public void GetInstallLocationUsesLocalNodeModulesForLocalScope() + { + string userProfile = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile); + string location = BunPkgDetailsHelper.GetInstallLocation(userProfile, PackageScope.Local, "typescript"); + + Assert.Equal(Path.Join(userProfile, "node_modules", "typescript"), location); + } + + /// + /// Tests that manager returns public interface correctly (IPackageManager compliance). + /// + [Fact] + public void BunImplementsIPackageManager() + { + var manager = new Bun(); + + // Verify that the manager implements IPackageManager interface + Assert.NotNull(manager); + Assert.NotNull(manager.DefaultSource); + Assert.NotNull(manager.OperationHelper); + } + + /// + /// Tests that package info fixture exists for details helper testing. + /// + [Fact] + public void PackageInfoFixtureExists() + { + string fixturePath = Path.Combine(AppContext.BaseDirectory, "Fixtures", "Bun", "package-info.json"); + Assert.True(File.Exists(fixturePath), $"Fixture file not found at {fixturePath}"); + } +} diff --git a/src/UniGetUI.PackageEngine.Tests/CargoClientTests.cs b/src/UniGetUI.PackageEngine.Tests/CargoClientTests.cs new file mode 100644 index 0000000..57b6e88 --- /dev/null +++ b/src/UniGetUI.PackageEngine.Tests/CargoClientTests.cs @@ -0,0 +1,100 @@ +using UniGetUI.PackageEngine.Managers.CargoManager; +using UniGetUI.PackageEngine.Tests.Infrastructure.Helpers; + +namespace UniGetUI.PackageEngine.Tests; + +public sealed class CargoClientTests : IDisposable +{ + public void Dispose() + { + CratesIOClient.TEST_ApiUrlOverride = null; + } + + [Fact] + public void GetManifest_ReturnsManifestAndResolvedUri() + { + using var server = new TestHttpServer(request => + { + return request.Url?.AbsolutePath switch + { + "/api/v1/crates/ripgrep" => ( + 200, + """ + { + "crate": { + "max_stable_version": "14.1.0", + "max_version": "14.1.0", + "name": "ripgrep", + "newest_version": "14.1.0" + }, + "versions": [ + { + "checksum": "abc", + "dl_path": "/api/v1/crates/ripgrep/14.1.0/download", + "num": "14.1.0", + "yanked": false + } + ] + } + """, + "application/json" + ), + _ => (404, string.Empty, "application/json"), + }; + }); + CratesIOClient.TEST_ApiUrlOverride = $"{server.BaseUri.AbsoluteUri.TrimEnd('/')}/api/v1"; + + var (uri, manifest) = CratesIOClient.GetManifest("ripgrep"); + + Assert.Equal($"{server.BaseUri.AbsoluteUri.TrimEnd('/')}/api/v1/crates/ripgrep", uri.ToString()); + Assert.Equal("ripgrep", manifest.crate.name); + Assert.Equal("14.1.0", Assert.Single(manifest.versions).num); + } + + [Fact] + public void GetManifestVersion_ReturnsWrappedVersion() + { + using var server = new TestHttpServer(request => + { + return request.Url?.AbsolutePath switch + { + "/api/v1/crates/ripgrep/14.1.0" => ( + 200, + """ + { + "version": { + "checksum": "abc", + "dl_path": "/api/v1/crates/ripgrep/14.1.0/download", + "num": "14.1.0", + "yanked": false + } + } + """, + "application/json" + ), + _ => (404, string.Empty, "application/json"), + }; + }); + CratesIOClient.TEST_ApiUrlOverride = $"{server.BaseUri.AbsoluteUri.TrimEnd('/')}/api/v1"; + + var version = CratesIOClient.GetManifestVersion("ripgrep", "14.1.0"); + + Assert.Equal("14.1.0", version.num); + } + + [Fact] + public void GetManifest_ThrowsWhenResponseContainsNullCrate() + { + using var server = new TestHttpServer(request => + { + return request.Url?.AbsolutePath switch + { + "/api/v1/crates/ripgrep" => (200, """{"crate":null,"versions":[]}""", "application/json"), + _ => (404, string.Empty, "application/json"), + }; + }); + CratesIOClient.TEST_ApiUrlOverride = $"{server.BaseUri.AbsoluteUri.TrimEnd('/')}/api/v1"; + + Assert.Throws(() => CratesIOClient.GetManifest("ripgrep")); + } +} diff --git a/src/UniGetUI.PackageEngine.Tests/ChocolateyManagerTests.cs b/src/UniGetUI.PackageEngine.Tests/ChocolateyManagerTests.cs new file mode 100644 index 0000000..8228936 --- /dev/null +++ b/src/UniGetUI.PackageEngine.Tests/ChocolateyManagerTests.cs @@ -0,0 +1,276 @@ +#if WINDOWS +using UniGetUI.Core.Data; +using UniGetUI.Core.SettingsEngine; +using UniGetUI.PackageEngine.Enums; +using UniGetUI.PackageEngine.Managers.Choco; +using UniGetUI.PackageEngine.Managers.ChocolateyManager; +using UniGetUI.PackageEngine.Serializable; +using UniGetUI.PackageEngine.Structs; +using UniGetUI.PackageEngine.Tests.Infrastructure.Assertions; +using UniGetUI.PackageEngine.Tests.Infrastructure.Builders; +using UniGetUI.PackageEngine.Tests.Infrastructure.Helpers; +using Architecture = UniGetUI.PackageEngine.Enums.Architecture; + +namespace UniGetUI.PackageEngine.Tests; + +[CollectionDefinition("Chocolatey manager tests", DisableParallelization = true)] +public sealed class ChocolateyManagerTestCollection +{ + public const string Name = "Chocolatey manager tests"; +} + +[Collection(ChocolateyManagerTestCollection.Name)] +public sealed class ChocolateyManagerTests : IDisposable +{ + private readonly string _testRoot = Path.Combine( + AppContext.BaseDirectory, + nameof(ChocolateyManagerTests), + Guid.NewGuid().ToString("N") + ); + + public ChocolateyManagerTests() + { + Directory.CreateDirectory(_testRoot); + CoreData.TEST_DataDirectoryOverride = Path.Combine(_testRoot, "Data"); + Directory.CreateDirectory(CoreData.UniGetUIUserConfigurationDirectory); + Settings.ResetSettings(); + Settings.Set(Settings.K.EnableProxy, false); + Settings.Set(Settings.K.EnableProxyAuth, false); + Settings.SetValue(Settings.K.ProxyURL, ""); + } + + public void Dispose() + { + Settings.ResetSettings(); + CoreData.TEST_DataDirectoryOverride = null; + if (Directory.Exists(_testRoot)) + { + Directory.Delete(_testRoot, recursive: true); + } + } + + [Fact] + public void GetProxyArgumentReturnsConfiguredProxyWhenAuthenticationIsDisabled() + { + Settings.Set(Settings.K.EnableProxy, true); + Settings.Set(Settings.K.EnableProxyAuth, false); + Settings.SetValue(Settings.K.ProxyURL, "http://proxy.example.test:3128/"); + + Assert.Equal("--proxy http://proxy.example.test:3128/", Chocolatey.GetProxyArgument()); + } + + [Fact] + public void ParseAvailableUpdatesFiltersNoiseAndBuildsPackagesFromFixture() + { + var manager = new Chocolatey(); + + var packages = manager.ParseAvailableUpdates( + ReadFixtureLines("Chocolatey\\outdated-output.txt") + ); + + Assert.Collection( + packages, + package => + { + Assert.Equal("git", package.Id); + Assert.Equal("2.47.0", package.VersionString); + Assert.Equal("2.48.1", package.NewVersionString); + PackageAssert.BelongsTo(package, manager, manager.DefaultSource); + }, + package => + { + Assert.Equal("7zip", package.Id); + Assert.Equal("24.9.0", package.VersionString); + Assert.Equal("25.0.0", package.NewVersionString); + PackageAssert.BelongsTo(package, manager, manager.DefaultSource); + } + ); + } + + [Fact] + public void ParseInstalledPackagesFiltersNoiseAndBuildsPackagesFromFixture() + { + var manager = new Chocolatey(); + + var packages = manager.ParseInstalledPackages(ReadFixtureLines("Chocolatey\\list-output.txt")); + + Assert.Collection( + packages, + package => + { + Assert.Equal("git", package.Id); + Assert.Equal("2.47.0", package.VersionString); + PackageAssert.BelongsTo(package, manager, manager.DefaultSource); + }, + package => + { + Assert.Equal("7zip", package.Id); + Assert.Equal("24.9.0", package.VersionString); + PackageAssert.BelongsTo(package, manager, manager.DefaultSource); + } + ); + } + + [Fact] + public void ParseSourcesNormalizesCommunityFeedsAndPreservesCustomFeeds() + { + var manager = new Chocolatey(); + var helper = Assert.IsType(manager.SourcesHelper); + + var sources = helper.ParseSources(ReadFixtureLines("Chocolatey\\source-list-output.txt")); + + Assert.Collection( + sources, + source => + { + Assert.Equal("community", source.Name); + Assert.Equal(new Uri("https://community.chocolatey.org/api/v2/"), source.Url); + }, + source => + { + Assert.Equal("community", source.Name); + Assert.Equal(new Uri("https://community.chocolatey.org/api/v2/"), source.Url); + }, + source => + { + Assert.Equal("internal repo", source.Name); + Assert.Equal(new Uri("https://packages.example.test/api/v2/"), source.Url); + } + ); + } + + [Fact] + public void ParseInstallableVersionsReadsApprovedVersionsFromFixture() + { + var versions = ChocolateyDetailsHelper.ParseInstallableVersions( + ReadFixtureLines("Chocolatey\\search-versions-output.txt") + ); + + Assert.Equal(["2.46.0", "2.47.0", "2.48.1"], versions); + } + + [Fact] + public void InstallParametersIncludeChocolateySpecificFlagsAndCustomParameters() + { + var manager = new Chocolatey(); + var package = new PackageBuilder().WithManager(manager).WithId("git").Build(); + var options = new InstallOptions + { + InteractiveInstallation = true, + Architecture = Architecture.x86, + PreRelease = true, + SkipHashCheck = true, + Version = "2.48.1", + CustomParameters_Install = ["--install-arg"], + }; + + var parameters = manager.OperationHelper.GetParameters(package, options, OperationType.Install); + + OperationAssert.HasParameters( + parameters, + "install", + "git", + "-y", + "--notsilent", + "--no-progress", + "--forcex86", + "--prerelease", + "--ignore-checksums", + "--force", + "--version=2.48.1", + "--allow-downgrade", + "--install-arg" + ); + } + + [Fact] + public void UninstallParametersUseUninstallVerbAndOnlyUninstallCustomParameters() + { + var manager = new Chocolatey(); + var package = new PackageBuilder().WithManager(manager).WithId("git").Build(); + var options = new InstallOptions + { + InteractiveInstallation = true, + SkipHashCheck = true, + CustomParameters_Install = ["--install-arg"], + CustomParameters_Uninstall = ["--remove-arg"], + }; + + var parameters = manager.OperationHelper.GetParameters(package, options, OperationType.Uninstall); + + OperationAssert.HasParameters( + parameters, + "uninstall", + "git", + "-y", + "--notsilent", + "--remove-arg" + ); + } + + [Theory] + [InlineData(0)] + [InlineData(3010)] + [InlineData(1641)] + [InlineData(1614)] + [InlineData(1605)] + public void OperationResultTreatsChocolateySuccessCodesAsSuccess(int returnCode) + { + var manager = new Chocolatey(); + var package = new PackageBuilder().WithManager(manager).Build(); + + var veredict = manager.OperationHelper.GetResult( + package, + OperationType.Install, + ["completed"], + returnCode + ); + + OperationAssert.HasVeredict(veredict, OperationVeredict.Success); + } + + [Fact] + public void OperationResultPromotesElevationFailuresToAutoRetry() + { + var manager = new Chocolatey(); + var package = new PackageBuilder() + .WithManager(manager) + .WithOptions(new OverridenInstallationOptions(runAsAdministrator: false)) + .Build(); + + var veredict = manager.OperationHelper.GetResult( + package, + OperationType.Install, + ["Access denied while installing package"], + 1 + ); + + OperationAssert.HasVeredict(veredict, OperationVeredict.AutoRetry); + Assert.True(package.OverridenOptions.RunAsAdministrator); + } + + [Fact] + public void OperationResultReturnsFailureWhenElevationWasAlreadyRequested() + { + var manager = new Chocolatey(); + var package = new PackageBuilder() + .WithManager(manager) + .WithOptions(new OverridenInstallationOptions(runAsAdministrator: true)) + .Build(); + + var veredict = manager.OperationHelper.GetResult( + package, + OperationType.Install, + ["Access denied while installing package"], + 1 + ); + + OperationAssert.HasVeredict(veredict, OperationVeredict.Failure); + } + + private static string[] ReadFixtureLines(string relativePath) + { + return PackageEngineFixtureFiles.ReadAllText(relativePath).Replace("\r\n", "\n").Split('\n'); + } +} +#endif diff --git a/src/UniGetUI.PackageEngine.Tests/DesktopShortcutsDatabaseTests.cs b/src/UniGetUI.PackageEngine.Tests/DesktopShortcutsDatabaseTests.cs new file mode 100644 index 0000000..c668d8d --- /dev/null +++ b/src/UniGetUI.PackageEngine.Tests/DesktopShortcutsDatabaseTests.cs @@ -0,0 +1,69 @@ +using UniGetUI.Core.Data; +using UniGetUI.Core.SettingsEngine; +using UniGetUI.PackageEngine.Classes.Packages.Classes; + +namespace UniGetUI.PackageEngine.Tests; + +public sealed class DesktopShortcutsDatabaseTests : IDisposable +{ + private readonly string _testRoot = Path.Combine( + Path.GetTempPath(), + nameof(DesktopShortcutsDatabaseTests), + Guid.NewGuid().ToString("N") + ); + + public DesktopShortcutsDatabaseTests() + { + Directory.CreateDirectory(_testRoot); + CoreData.TEST_DataDirectoryOverride = Path.Combine(_testRoot, "Data"); + Directory.CreateDirectory(CoreData.UniGetUIUserConfigurationDirectory); + Settings.ResetSettings(); + DesktopShortcutsDatabase.ResetDatabase(); + DesktopShortcutsDatabase.GetUnknownShortcuts().Clear(); + } + + public void Dispose() + { + DesktopShortcutsDatabase.ResetDatabase(); + DesktopShortcutsDatabase.GetUnknownShortcuts().Clear(); + Settings.ResetSettings(); + CoreData.TEST_DataDirectoryOverride = null; + if (Directory.Exists(_testRoot)) + { + Directory.Delete(_testRoot, recursive: true); + } + } + + [Fact] + public void AddStatusRoundTripAndResetDatabaseWorkForTrackedShortcuts() + { + string shortcutPath = Path.Combine(_testRoot, "SyntheticShortcut.lnk"); + + DesktopShortcutsDatabase.AddToDatabase(shortcutPath, DesktopShortcutsDatabase.Status.Maintain); + Assert.Equal(DesktopShortcutsDatabase.Status.Maintain, DesktopShortcutsDatabase.GetStatus(shortcutPath)); + Assert.Contains(shortcutPath, DesktopShortcutsDatabase.GetAllShortcuts()); + + DesktopShortcutsDatabase.AddToDatabase(shortcutPath, DesktopShortcutsDatabase.Status.Delete); + Assert.Equal(DesktopShortcutsDatabase.Status.Delete, DesktopShortcutsDatabase.GetStatus(shortcutPath)); + + DesktopShortcutsDatabase.AddToDatabase(shortcutPath, DesktopShortcutsDatabase.Status.Unknown); + Assert.Equal(DesktopShortcutsDatabase.Status.Unknown, DesktopShortcutsDatabase.GetStatus(shortcutPath)); + Assert.DoesNotContain(shortcutPath, DesktopShortcutsDatabase.GetDatabase().Keys); + + DesktopShortcutsDatabase.AddToDatabase(shortcutPath, DesktopShortcutsDatabase.Status.Delete); + DesktopShortcutsDatabase.ResetDatabase(); + Assert.Equal(DesktopShortcutsDatabase.Status.Unknown, DesktopShortcutsDatabase.GetStatus(shortcutPath)); + } + + [Fact] + public void DeleteFromDiskRemovesExistingShortcutFile() + { + string shortcutPath = Path.Combine(_testRoot, "DeleteMe.lnk"); + File.WriteAllText(shortcutPath, "synthetic shortcut"); + + bool deleted = DesktopShortcutsDatabase.DeleteFromDisk(shortcutPath); + + Assert.True(deleted); + Assert.False(File.Exists(shortcutPath)); + } +} diff --git a/src/UniGetUI.PackageEngine.Tests/DotNetManagerTests.cs b/src/UniGetUI.PackageEngine.Tests/DotNetManagerTests.cs new file mode 100644 index 0000000..d4972fe --- /dev/null +++ b/src/UniGetUI.PackageEngine.Tests/DotNetManagerTests.cs @@ -0,0 +1,61 @@ +using UniGetUI.PackageEngine.Enums; +using UniGetUI.PackageEngine.Managers.DotNetManager; +using UniGetUI.PackageEngine.Structs; + +namespace UniGetUI.PackageEngine.Tests; + +public sealed class DotNetManagerTests +{ + [Fact] + public void ParseInstalledPackages_SkipsHeadersAndFalseRows() + { + var manager = new DotNet(); + var packages = DotNet.ParseInstalledPackages( + [ + "Package Id Version Commands", + "--------------------------------------", + "dotnetsay 2.1.7 dotnetsay", + " 1.0.0", + "try-convert 0.9.232202", + ], + manager.DefaultSource, + manager, + new OverridenInstallationOptions(PackageScope.Local) + ); + + Assert.Collection( + packages, + package => + { + Assert.Equal("dotnetsay", package.Id); + Assert.Equal("2.1.7", package.VersionString); + Assert.Equal(PackageScope.Local, package.OverridenOptions.Scope); + }, + package => + { + Assert.Equal("try-convert", package.Id); + Assert.Equal("0.9.232202", package.VersionString); + } + ); + } + + [Fact] + public void ParseInstalledPackages_PreservesRequestedScope() + { + var manager = new DotNet(); + var package = Assert.Single( + DotNet.ParseInstalledPackages( + [ + "Package Id Version Commands", + "--------------------------------------", + "dotnetsay 2.1.7 dotnetsay", + ], + manager.DefaultSource, + manager, + new OverridenInstallationOptions(PackageScope.Global) + ) + ); + + Assert.Equal(PackageScope.Global, package.OverridenOptions.Scope); + } +} diff --git a/src/UniGetUI.PackageEngine.Tests/Fixtures/Bun/installed.txt b/src/UniGetUI.PackageEngine.Tests/Fixtures/Bun/installed.txt new file mode 100644 index 0000000..c785bb5 --- /dev/null +++ b/src/UniGetUI.PackageEngine.Tests/Fixtures/Bun/installed.txt @@ -0,0 +1,6 @@ +/home/user/.bun/install/global node_modules (5) +├── typescript@5.7.3 +├── @devcontainers/cli@0.81.1 +├── esbuild@0.19.11 +├── @swc/cli@0.1.62 +└── bunx@1.0.24 diff --git a/src/UniGetUI.PackageEngine.Tests/Fixtures/Bun/outdated-table.txt b/src/UniGetUI.PackageEngine.Tests/Fixtures/Bun/outdated-table.txt new file mode 100644 index 0000000..bdb50ea --- /dev/null +++ b/src/UniGetUI.PackageEngine.Tests/Fixtures/Bun/outdated-table.txt @@ -0,0 +1,10 @@ +bun outdated v1.3.9 (cf6cdbbb) +|-------------------------------------------------| +| Package | Current | Update | Latest | +|--------------------------------------------------| +| typescript | 5.2.0 | 5.3.0 | 5.4.0 | +|--------------------------------------------------| +| @types/node | 20.8.0 | 20.9.0 | 20.10.6 | +|--------------------------------------------------| +| vite | 4.5.0 | 4.5.1 | 5.0.0 | +|-------------------------------------------------| diff --git a/src/UniGetUI.PackageEngine.Tests/Fixtures/Bun/package-info.json b/src/UniGetUI.PackageEngine.Tests/Fixtures/Bun/package-info.json new file mode 100644 index 0000000..5f5e464 --- /dev/null +++ b/src/UniGetUI.PackageEngine.Tests/Fixtures/Bun/package-info.json @@ -0,0 +1,28 @@ +{ + "name": "example-lib", + "version": "2.0.0", + "description": "An example library for testing", + "license": "MIT", + "homepage": "https://example.com/lib", + "author": "Example Author", + "maintainers": ["maintainer1"], + "time": { + "2.0.0": "2025-01-15T00:00:00.000Z" + }, + "dist-tags": { + "latest": "2.0.0" + }, + "dist": { + "tarball": "https://registry.example.com/example-lib/-/example-lib-2.0.0.tgz", + "unpackedSize": 12345, + "integrity": "sha512-exampleIntegrityHash==" + }, + "dependencies": { + "helper-lib": "^1.0.0" + }, + "versions": [ + "1.0.0", + "1.1.0", + "2.0.0" + ] +} diff --git a/src/UniGetUI.PackageEngine.Tests/Fixtures/Bun/search-results.json b/src/UniGetUI.PackageEngine.Tests/Fixtures/Bun/search-results.json new file mode 100644 index 0000000..fee6deb --- /dev/null +++ b/src/UniGetUI.PackageEngine.Tests/Fixtures/Bun/search-results.json @@ -0,0 +1,27 @@ +{ + "objects": [ + { + "package": { + "name": "typescript", + "version": "5.3.3", + "description": "TypeScript is a language for application scale JavaScript development" + } + }, + { + "package": { + "name": "lodash", + "version": "4.17.21", + "description": "Lodash modular utilities." + } + }, + { + "package": { + "name": "@types/node", + "version": "20.10.6", + "description": "TypeScript definitions for Node.js" + } + } + ], + "total": 3, + "time": "Mon Jun 04 2026 00:00:00 GMT+0000" +} diff --git a/src/UniGetUI.PackageEngine.Tests/Fixtures/Chocolatey/list-output.txt b/src/UniGetUI.PackageEngine.Tests/Fixtures/Chocolatey/list-output.txt new file mode 100644 index 0000000..40c5661 --- /dev/null +++ b/src/UniGetUI.PackageEngine.Tests/Fixtures/Chocolatey/list-output.txt @@ -0,0 +1,6 @@ +Chocolatey v2.4.3 +git 2.47.0 +Validation Failures: +7zip 24.9.0 +Output is Id Version +foo diff --git a/src/UniGetUI.PackageEngine.Tests/Fixtures/Chocolatey/outdated-output.txt b/src/UniGetUI.PackageEngine.Tests/Fixtures/Chocolatey/outdated-output.txt new file mode 100644 index 0000000..6a5d552 --- /dev/null +++ b/src/UniGetUI.PackageEngine.Tests/Fixtures/Chocolatey/outdated-output.txt @@ -0,0 +1,6 @@ +Chocolatey v2.4.3 +git|2.47.0|2.48.1 +Validation|current version|available version +7zip|24.9.0|25.0.0 +git|2.48.1|2.48.1 +foo|1.0 diff --git a/src/UniGetUI.PackageEngine.Tests/Fixtures/Chocolatey/search-versions-output.txt b/src/UniGetUI.PackageEngine.Tests/Fixtures/Chocolatey/search-versions-output.txt new file mode 100644 index 0000000..faeea04 --- /dev/null +++ b/src/UniGetUI.PackageEngine.Tests/Fixtures/Chocolatey/search-versions-output.txt @@ -0,0 +1,5 @@ +Chocolatey v2.4.3 +git 2.46.0 [Approved] +git 2.47.0 [Approved] +not-a-version line +git 2.48.1 [Approved] diff --git a/src/UniGetUI.PackageEngine.Tests/Fixtures/Chocolatey/source-list-output.txt b/src/UniGetUI.PackageEngine.Tests/Fixtures/Chocolatey/source-list-output.txt new file mode 100644 index 0000000..b28ad32 --- /dev/null +++ b/src/UniGetUI.PackageEngine.Tests/Fixtures/Chocolatey/source-list-output.txt @@ -0,0 +1,5 @@ +Chocolatey v2.4.3 +community - https://community.chocolatey.org/api/v2/ | Priority 0|Bypass Proxy - false|Self-Service - false|Admin Only - false +legacy community - https://chocolatey.org/api/v2/ | Priority 0|Bypass Proxy - false|Self-Service - false|Admin Only - false +internal repo - https://packages.example.test/api/v2/ | Priority 10|Bypass Proxy - false|Self-Service - false|Admin Only - false +invalid source line diff --git a/src/UniGetUI.PackageEngine.Tests/Fixtures/Flatpak/installed-list.txt b/src/UniGetUI.PackageEngine.Tests/Fixtures/Flatpak/installed-list.txt new file mode 100644 index 0000000..31db72b --- /dev/null +++ b/src/UniGetUI.PackageEngine.Tests/Fixtures/Flatpak/installed-list.txt @@ -0,0 +1,3 @@ +com.github.tchx84.Flatseal 2.4.0 stable flathub Flatseal +com.heroicgameslauncher.hgl v2.21.0 stable flathub Heroic +io.github.nokse22.high-tide 1.3.1 stable flathub High Tide diff --git a/src/UniGetUI.PackageEngine.Tests/Fixtures/Flatpak/search-sqlitebrowser-tab.txt b/src/UniGetUI.PackageEngine.Tests/Fixtures/Flatpak/search-sqlitebrowser-tab.txt new file mode 100644 index 0000000..c4f1bf2 --- /dev/null +++ b/src/UniGetUI.PackageEngine.Tests/Fixtures/Flatpak/search-sqlitebrowser-tab.txt @@ -0,0 +1 @@ +DB Browser for SQLite light GUI editor for SQLite databases org.sqlitebrowser.sqlitebrowser 3.13.1 stable flathub diff --git a/src/UniGetUI.PackageEngine.Tests/Fixtures/Flatpak/search-sqlitebrowser.txt b/src/UniGetUI.PackageEngine.Tests/Fixtures/Flatpak/search-sqlitebrowser.txt new file mode 100644 index 0000000..68239b3 --- /dev/null +++ b/src/UniGetUI.PackageEngine.Tests/Fixtures/Flatpak/search-sqlitebrowser.txt @@ -0,0 +1,2 @@ +Name Description Application ID Version Branch Remotes +DB Browser for SQLite light GUI editor for SQLite databases org.sqlitebrowser.sqlitebrowser 3.13.1 stable flathub diff --git a/src/UniGetUI.PackageEngine.Tests/Fixtures/Flatpak/updates-list.txt b/src/UniGetUI.PackageEngine.Tests/Fixtures/Flatpak/updates-list.txt new file mode 100644 index 0000000..130275f --- /dev/null +++ b/src/UniGetUI.PackageEngine.Tests/Fixtures/Flatpak/updates-list.txt @@ -0,0 +1,3 @@ +io.podman_desktop.PodmanDesktop 1.27.1 stable flathub Podman Desktop +org.freedesktop.Platform.Compat.i386 25.08 flathub i386 +org.freedesktop.Platform.GL.default 26.0.4 24.08 flathub Mesa diff --git a/src/UniGetUI.PackageEngine.Tests/Fixtures/Npm/installed.json b/src/UniGetUI.PackageEngine.Tests/Fixtures/Npm/installed.json new file mode 100644 index 0000000..e94d287 --- /dev/null +++ b/src/UniGetUI.PackageEngine.Tests/Fixtures/Npm/installed.json @@ -0,0 +1,11 @@ +{ + "name": "workspace", + "dependencies": { + "rimraf": { + "version": "6.0.1" + }, + "missing-version": { + "resolved": "https://registry.npmjs.org/missing-version" + } + } +} diff --git a/src/UniGetUI.PackageEngine.Tests/Fixtures/Npm/outdated.json b/src/UniGetUI.PackageEngine.Tests/Fixtures/Npm/outdated.json new file mode 100644 index 0000000..8153358 --- /dev/null +++ b/src/UniGetUI.PackageEngine.Tests/Fixtures/Npm/outdated.json @@ -0,0 +1,11 @@ +{ + "npm": { + "current": "10.9.0", + "wanted": "10.9.0", + "latest": "11.0.0", + "location": "C:\\Users\\tester\\AppData\\Roaming\\npm\\node_modules\\npm" + }, + "missing-current": { + "latest": "1.0.0" + } +} diff --git a/src/UniGetUI.PackageEngine.Tests/Fixtures/Npm/search-array-with-warning.txt b/src/UniGetUI.PackageEngine.Tests/Fixtures/Npm/search-array-with-warning.txt new file mode 100644 index 0000000..92d6745 --- /dev/null +++ b/src/UniGetUI.PackageEngine.Tests/Fixtures/Npm/search-array-with-warning.txt @@ -0,0 +1,13 @@ +npm warn config global `--global`, `--local` are deprecated. Use `--location=global` instead. +[ + { + "name": "left-pad", + "version": "1.3.0", + "description": "String left pad" + }, + { + "name": "@types/node", + "version": "24.0.0", + "description": "TypeScript definitions for Node.js" + } +] diff --git a/src/UniGetUI.PackageEngine.Tests/Fixtures/Npm/search-ndjson.txt b/src/UniGetUI.PackageEngine.Tests/Fixtures/Npm/search-ndjson.txt new file mode 100644 index 0000000..cea052c --- /dev/null +++ b/src/UniGetUI.PackageEngine.Tests/Fixtures/Npm/search-ndjson.txt @@ -0,0 +1,5 @@ +npm warn old lockfile +{"name":"chalk","version":"5.4.1","description":"Terminal string styling done right"} +not-json +{"name":"missing-version"} +{"name":"npm-check-updates","version":"17.1.1","description":"Find newer package dependencies"} diff --git a/src/UniGetUI.PackageEngine.Tests/Fixtures/Pip/installed-list.txt b/src/UniGetUI.PackageEngine.Tests/Fixtures/Pip/installed-list.txt new file mode 100644 index 0000000..febd633 --- /dev/null +++ b/src/UniGetUI.PackageEngine.Tests/Fixtures/Pip/installed-list.txt @@ -0,0 +1,6 @@ +Package Version +------------------ ---------- +requests 2.31.0 +[notice] invalid +django-reqtools 1.0.0 +DEPRECATION: ignored diff --git a/src/UniGetUI.PackageEngine.Tests/Fixtures/Pip/outdated-list.txt b/src/UniGetUI.PackageEngine.Tests/Fixtures/Pip/outdated-list.txt new file mode 100644 index 0000000..2b6088c --- /dev/null +++ b/src/UniGetUI.PackageEngine.Tests/Fixtures/Pip/outdated-list.txt @@ -0,0 +1,6 @@ +Package Version Latest Type +------------------ ---------- ---------- ----- +requests 2.31.0 2.32.3 wheel +[notice] invalid invalid wheel +django-reqtools 1.0.0 1.1.0 wheel +WARNING: ignored ignored wheel diff --git a/src/UniGetUI.PackageEngine.Tests/Fixtures/Pip/simple-index.json b/src/UniGetUI.PackageEngine.Tests/Fixtures/Pip/simple-index.json new file mode 100644 index 0000000..884cd9a --- /dev/null +++ b/src/UniGetUI.PackageEngine.Tests/Fixtures/Pip/simple-index.json @@ -0,0 +1,12 @@ +{ + "projects": [ + { "name": "requests" }, + { "name": "req" }, + { "name": "requests-cache" }, + { "name": "requestium" }, + { "name": "django-reqtools" }, + { "name": "pytest" }, + { "name": null }, + {} + ] +} diff --git a/src/UniGetUI.PackageEngine.Tests/Fixtures/Scoop/bucket-list-output.txt b/src/UniGetUI.PackageEngine.Tests/Fixtures/Scoop/bucket-list-output.txt new file mode 100644 index 0000000..537cc44 --- /dev/null +++ b/src/UniGetUI.PackageEngine.Tests/Fixtures/Scoop/bucket-list-output.txt @@ -0,0 +1,5 @@ +Name Source Updated Manifests +---- ------ ------- --------- +main https://github.com/ScoopInstaller/Main.git 2024-02-01 12:34:56 1234 +extras C:\Users\fixture\scoop\buckets\extras 2024-02-02 09:08:07 321 +invalid line diff --git a/src/UniGetUI.PackageEngine.Tests/Fixtures/Scoop/list-output.txt b/src/UniGetUI.PackageEngine.Tests/Fixtures/Scoop/list-output.txt new file mode 100644 index 0000000..90cec9e --- /dev/null +++ b/src/UniGetUI.PackageEngine.Tests/Fixtures/Scoop/list-output.txt @@ -0,0 +1,5 @@ +Name Version Source +---- ------- ------ +git 2.47.1 main +pwsh 7.4.6 versions Global install +No packages installed diff --git a/src/UniGetUI.PackageEngine.Tests/Fixtures/Scoop/search-output.txt b/src/UniGetUI.PackageEngine.Tests/Fixtures/Scoop/search-output.txt new file mode 100644 index 0000000..c373032 --- /dev/null +++ b/src/UniGetUI.PackageEngine.Tests/Fixtures/Scoop/search-output.txt @@ -0,0 +1,6 @@ +'main' bucket: +7zip 24.09 +WARN ignored +'versions' bucket: +python310 3.10.11 +No Matches Found diff --git a/src/UniGetUI.PackageEngine.Tests/Fixtures/Scoop/status-output.txt b/src/UniGetUI.PackageEngine.Tests/Fixtures/Scoop/status-output.txt new file mode 100644 index 0000000..9ec066f --- /dev/null +++ b/src/UniGetUI.PackageEngine.Tests/Fixtures/Scoop/status-output.txt @@ -0,0 +1,6 @@ +Name Installed Latest +---- --------- ------ +git 2.47.1 2.48.1 +pwsh 7.4.6 7.5.0 +orphan 0.1.0 0.2.0 +WARN failed removed diff --git a/src/UniGetUI.PackageEngine.Tests/Fixtures/Snap/find-signal.txt b/src/UniGetUI.PackageEngine.Tests/Fixtures/Snap/find-signal.txt new file mode 100644 index 0000000..8fadbef --- /dev/null +++ b/src/UniGetUI.PackageEngine.Tests/Fixtures/Snap/find-signal.txt @@ -0,0 +1,2 @@ +Name Version Publisher Notes Summary +signal-desktop 8.5.0 snapcrafters✪ - Speak Freely - Private Messenger diff --git a/src/UniGetUI.PackageEngine.Tests/Fixtures/Snap/info-signal.txt b/src/UniGetUI.PackageEngine.Tests/Fixtures/Snap/info-signal.txt new file mode 100644 index 0000000..3f8f4c3 --- /dev/null +++ b/src/UniGetUI.PackageEngine.Tests/Fixtures/Snap/info-signal.txt @@ -0,0 +1,57 @@ +name: signal-desktop +summary: Speak Freely - Private Messenger +publisher: Snapcrafters✪ +store-url: https://snapcraft.io/signal-desktop +contact: https://github.com//snapcrafters/signal-desktop/issues +license: AGPL-3.0-only +description: | + **Note: To use the Signal desktop app, you must first install Signal on your phone.** + + Millions of people use Signal every day for free and instantaneous communication anywhere in the + world. Send and receive high-fidelity messages, participate in HD voice/video calls, and explore a + growing set of new features that help you stay connected. Signal's advanced privacy-preserving + technology is always enabled, so you can focus on sharing the moments that matter with the people + who matter to you. + + - Say anything - State-of-the-art end-to-end encryption (powered by the open source Signal + Protocol™) keeps your conversations secure. Privacy isn't an optional mode; it's just the way that + Signal works. Every message, every call, every time. + - Go fast - Messages are delivered quickly and reliably, even on slow networks. Signal is + optimized to operate in the most constrained environment possible. + - Feel free - Signal is a completely independent 501c3 nonprofit. Development is supported by + users like you. No advertisements. No trackers. No kidding. + - Be yourself - You can use your existing phone number and address book to securely communicate + with your friends. + - Speak up - Whether they live across town or across the ocean, Signal's enhanced audio and video + quality will make your friends and family feel closer. + - Whisper in the shadows - Switch to the dark theme if you refuse to see the light. + + **Minimize to tray** + + Per the request of the Signal developers, this snap does not use the system tray by default. This + is disabled by default per the request of the Signal developers, because system tray support is + not stable. Set to `false`, Signal will stop when you close it and will not have a system tray + icon. You can enable it by running the following command. + + snap set signal-desktop tray-icon=true + + + **Are you having issues?** + + Let us know by creating a new issue here: https://github.com/snapcrafters/signal-desktop/issues + + **Authors** + + This snap is maintained by the Snapcrafters community, and is not necessarily endorsed or + officially maintained by the upstream developers. +commands: + - signal-desktop +snap-id: r4LxMVp7zWramXsJQAKdamxy6TAWlaDD +tracking: latest/stable +refresh-date: 22 days ago, at 16:32 EDT +channels: + latest/stable: 8.5.0 2026-04-02 (894) 189MB - + latest/candidate: 8.5.0 2026-04-02 (894) 189MB - + latest/beta: ↑ + latest/edge: ↑ +installed: 8.5.0 (894) 189MB - diff --git a/src/UniGetUI.PackageEngine.Tests/Fixtures/Snap/installed-list.txt b/src/UniGetUI.PackageEngine.Tests/Fixtures/Snap/installed-list.txt new file mode 100644 index 0000000..9cbe27b --- /dev/null +++ b/src/UniGetUI.PackageEngine.Tests/Fixtures/Snap/installed-list.txt @@ -0,0 +1,7 @@ +Name Version Rev Tracking Publisher Notes +aspnetcore-runtime-100 10.0.7 27 latest/stable canonical✓ - +bare 1.0 5 latest/stable canonical✓ base +code 10c8e557 235 latest/stable vscode✓ classic +core18 20260204 2999 latest/stable canonical✓ base +core20 20260211 2769 latest/stable canonical✓ base +core22 20260225 2411 latest/stable canonical✓ base diff --git a/src/UniGetUI.PackageEngine.Tests/Fixtures/Snap/updates-list.txt b/src/UniGetUI.PackageEngine.Tests/Fixtures/Snap/updates-list.txt new file mode 100644 index 0000000..f302e21 --- /dev/null +++ b/src/UniGetUI.PackageEngine.Tests/Fixtures/Snap/updates-list.txt @@ -0,0 +1,3 @@ +Name Version Rev Size Publisher Notes +discord 0.0.134 277 122MB snapcrafters✪ - +firefox 150.0-1 8191 288MB mozilla✓ - diff --git a/src/UniGetUI.PackageEngine.Tests/Fixtures/sample-manager-output.txt b/src/UniGetUI.PackageEngine.Tests/Fixtures/sample-manager-output.txt new file mode 100644 index 0000000..38d3959 --- /dev/null +++ b/src/UniGetUI.PackageEngine.Tests/Fixtures/sample-manager-output.txt @@ -0,0 +1,3 @@ +Name Id Version +---------------------------------------- +Contoso Tool Contoso.Tool 1.2.3 diff --git a/src/UniGetUI.PackageEngine.Tests/FlatpakManagerTests.cs b/src/UniGetUI.PackageEngine.Tests/FlatpakManagerTests.cs new file mode 100644 index 0000000..e0feee0 --- /dev/null +++ b/src/UniGetUI.PackageEngine.Tests/FlatpakManagerTests.cs @@ -0,0 +1,385 @@ +using UniGetUI.Core.Data; +using UniGetUI.Core.SettingsEngine; +using UniGetUI.PackageEngine.Enums; +using UniGetUI.PackageEngine.Managers.FlatpakManager; +using UniGetUI.PackageEngine.PackageClasses; +using UniGetUI.PackageEngine.Serializable; +using UniGetUI.PackageEngine.Tests.Infrastructure.Assertions; +using UniGetUI.PackageEngine.Tests.Infrastructure.Builders; +using UniGetUI.PackageEngine.Tests.Infrastructure.Helpers; + +namespace UniGetUI.PackageEngine.Tests; + +[CollectionDefinition("Flatpak manager tests", DisableParallelization = true)] +public sealed class FlatpakManagerTestCollection +{ + public const string Name = "Flatpak manager tests"; +} + +[Collection(FlatpakManagerTestCollection.Name)] +public sealed class FlatpakManagerTests : IDisposable +{ + private readonly string _testRoot = Path.Combine( + AppContext.BaseDirectory, + nameof(FlatpakManagerTests), + Guid.NewGuid().ToString("N") + ); + + public FlatpakManagerTests() + { + Directory.CreateDirectory(_testRoot); + CoreData.TEST_DataDirectoryOverride = Path.Combine(_testRoot, "Data"); + Directory.CreateDirectory(CoreData.UniGetUIUserConfigurationDirectory); + Settings.ResetSettings(); + } + + public void Dispose() + { + Settings.ResetSettings(); + CoreData.TEST_DataDirectoryOverride = null; + if (Directory.Exists(_testRoot)) + { + Directory.Delete(_testRoot, recursive: true); + } + } + + [Fact] + public void ParseInstalledPackagesBuildsPackagesFromFixture() + { + var manager = new Flatpak(); + + var packages = Flatpak.ParseInstalledPackages( + File.ReadLines(PackageEngineFixtureFiles.GetPath(Path.Combine("Flatpak", "installed-list.txt"))), + manager.DefaultSource, + manager + ); + + Assert.Collection( + packages, + package => + { + PackageAssert.Matches(package, "Flatseal", "com.github.tchx84.Flatseal", "2.4.0"); + PackageAssert.BelongsTo(package, manager, manager.DefaultSource); + }, + package => + { + PackageAssert.Matches(package, "Heroic", "com.heroicgameslauncher.hgl", "v2.21.0"); + PackageAssert.BelongsTo(package, manager, manager.DefaultSource); + }, + package => + { + PackageAssert.Matches(package, "High Tide", "io.github.nokse22.high-tide", "1.3.1"); + PackageAssert.BelongsTo(package, manager, manager.DefaultSource); + } + ); + } + + [Fact] + public void ParseAvailableUpdatesBuildsPackagesFromFixture() + { + var manager = new Flatpak(); + + var installedPackages = new List + { + new("Podman Desktop", "io.podman_desktop.PodmanDesktop", "1.26.0", manager.DefaultSource, manager), + new("Mesa", "org.freedesktop.Platform.GL.default", "26.0.3", manager.DefaultSource, manager), + }; + + var packages = Flatpak.ParseAvailableUpdates( + File.ReadLines(PackageEngineFixtureFiles.GetPath(Path.Combine("Flatpak", "updates-list.txt"))), + manager.DefaultSource, + manager, + installedPackages + ); + + Assert.Collection( + packages, + package => + { + PackageAssert.Matches(package, "Podman Desktop", "io.podman_desktop.PodmanDesktop", "1.26.0", "1.27.1"); + Assert.True(package.IsUpgradable); + PackageAssert.BelongsTo(package, manager, manager.DefaultSource); + }, + package => + { + PackageAssert.Matches(package, "Mesa", "org.freedesktop.Platform.GL.default", "26.0.3", "26.0.4"); + Assert.True(package.IsUpgradable); + PackageAssert.BelongsTo(package, manager, manager.DefaultSource); + } + ); + } + + [Fact] + public void ParseSearchResultsBuildsPackagesFromFixture() + { + var manager = new Flatpak(); + + var packages = Flatpak.ParseSearchResults( + File.ReadLines(PackageEngineFixtureFiles.GetPath(Path.Combine("Flatpak", "search-sqlitebrowser.txt"))), + manager.DefaultSource, + manager + ); + + Assert.Collection( + packages, + package => + { + PackageAssert.Matches(package, "DB Browser For SQLite", "org.sqlitebrowser.sqlitebrowser", "3.13.1"); + PackageAssert.BelongsTo(package, manager, manager.DefaultSource); + } + ); + } + + [Fact] + public void ParseInstalledPackagesFiltersEmptyLines() + { + var manager = new Flatpak(); + var lines = new[] + { + "", + " ", + "com.github.tchx84.Flatseal\t2.4.0\tstable\tflathub\tFlatseal", + }; + + var packages = Flatpak.ParseInstalledPackages(lines, manager.DefaultSource, manager); + + Assert.Single(packages); + Assert.Equal("com.github.tchx84.Flatseal", packages[0].Id); + } + + [Fact] + public void ParseAvailableUpdatesFiltersEmptyLines() + { + var manager = new Flatpak(); + var lines = new[] + { + "", + "io.podman_desktop.PodmanDesktop\t1.27.1\tstable\tflathub\tPodman Desktop", + }; + + var installedPackages = new List + { + new Package("Podman Desktop", "io.podman_desktop.PodmanDesktop", "1.26.0", manager.DefaultSource, manager), + }; + + var packages = Flatpak.ParseAvailableUpdates(lines, manager.DefaultSource, manager, installedPackages); + + Assert.Single(packages); + Assert.Equal("io.podman_desktop.PodmanDesktop", packages[0].Id); + Assert.Equal("1.26.0", packages[0].VersionString); + Assert.Equal("1.27.1", packages[0].NewVersionString); + } + + [Fact] + public void ParseSearchResultsHandlesTabSeparatedOutputWithoutHeader() + { + var manager = new Flatpak(); + + var packages = Flatpak.ParseSearchResults( + File.ReadLines(PackageEngineFixtureFiles.GetPath(Path.Combine("Flatpak", "search-sqlitebrowser-tab.txt"))), + manager.DefaultSource, + manager + ); + + Assert.Collection( + packages, + package => + { + PackageAssert.Matches(package, "DB Browser For SQLite", "org.sqlitebrowser.sqlitebrowser", "3.13.1"); + PackageAssert.BelongsTo(package, manager, manager.DefaultSource); + } + ); + } + + [Fact] + public void ParseSearchResultsSkipsHeaderAndEmptyLines() + { + var manager = new Flatpak(); + var lines = new[] + { + "Name Description Application ID Version Branch Remotes", + "", + "DB Browser for SQLite light GUI editor for SQLite databases org.sqlitebrowser.sqlitebrowser 3.13.1 stable flathub", + }; + + var packages = Flatpak.ParseSearchResults(lines, manager.DefaultSource, manager); + + Assert.Single(packages); + Assert.Equal("org.sqlitebrowser.sqlitebrowser", packages[0].Id); + } + + [Fact] + public void ParseInstalledPackagesReturnsEmptyForNoResults() + { + var manager = new Flatpak(); + + var packages = Flatpak.ParseInstalledPackages([], manager.DefaultSource, manager); + + Assert.Empty(packages); + } + + [Fact] + public void ParseAvailableUpdatesReturnsEmptyForNoResults() + { + var manager = new Flatpak(); + + var packages = Flatpak.ParseAvailableUpdates([], manager.DefaultSource, manager, []); + Assert.Empty(packages); + } + + [Fact] + public void ParseSearchResultsReturnsEmptyForNoResults() + { + var manager = new Flatpak(); + var lines = new[] + { + "Name Description Application ID Version Branch Remotes", + }; + + var packages = Flatpak.ParseSearchResults(lines, manager.DefaultSource, manager); + + Assert.Empty(packages); + } + + [Fact] + public void OperationHelperBuildsInstallAndUninstallParameters() + { + var manager = new Flatpak(); + var package = new PackageBuilder() + .WithManager(manager) + .WithId("org.sqlitebrowser.sqlitebrowser") + .Build(); + var installOptions = new InstallOptions + { + CustomParameters_Install = [], + }; + var uninstallOptions = new InstallOptions(); + + var installParameters = manager.OperationHelper.GetParameters( + package, + installOptions, + OperationType.Install + ); + var uninstallParameters = manager.OperationHelper.GetParameters( + package, + uninstallOptions, + OperationType.Uninstall + ); + + Assert.Equal( + [ + "install", + "--noninteractive", + "-y", + "org.sqlitebrowser.sqlitebrowser", + ], + installParameters + ); + Assert.Equal( + [ + "uninstall", + "--noninteractive", + "-y", + "org.sqlitebrowser.sqlitebrowser", + ], + uninstallParameters + ); + } + + [Fact] + public void OperationHelperForcesAdministratorForAllOperations() + { + var manager = new Flatpak(); + var package = new PackageBuilder() + .WithManager(manager) + .WithId("com.github.tchx84.Flatseal") + .Build(); + var options = new InstallOptions(); + + _ = manager.OperationHelper.GetParameters(package, options, OperationType.Install); + Assert.True(options.RunAsAdministrator); + + options = new InstallOptions(); + _ = manager.OperationHelper.GetParameters(package, options, OperationType.Update); + Assert.True(options.RunAsAdministrator); + + options = new InstallOptions(); + _ = manager.OperationHelper.GetParameters(package, options, OperationType.Uninstall); + Assert.True(options.RunAsAdministrator); + } + + [Fact] + public void OperationHelperReturnsSuccessOnZeroExitCode() + { + var manager = new Flatpak(); + var package = new PackageBuilder() + .WithManager(manager) + .WithId("com.github.tchx84.Flatseal") + .Build(); + + var result = manager.OperationHelper.GetResult( + package, + OperationType.Install, + ["Installing..."], + 0 + ); + + Assert.Equal(OperationVeredict.Success, result); + } + + [Fact] + public void OperationHelperReturnsFailureOnNonZeroExitCode() + { + var manager = new Flatpak(); + var package = new PackageBuilder() + .WithManager(manager) + .WithId("com.github.tchx84.Flatseal") + .Build(); + + var result = manager.OperationHelper.GetResult( + package, + OperationType.Install, + ["error: something went wrong"], + 1 + ); + + Assert.Equal(OperationVeredict.Failure, result); + } + + [Fact] + public void ManagerHasCorrectCapabilities() + { + var manager = new Flatpak(); + + Assert.True(manager.Capabilities.CanRunAsAdmin); + Assert.True(manager.Capabilities.CanSkipIntegrityChecks); + Assert.True(manager.Capabilities.SupportsCustomSources); + } + + [Fact] + public void ManagerHasCorrectProperties() + { + var manager = new Flatpak(); + + Assert.Equal("Flatpak", manager.Name); + Assert.Equal("flatpak", manager.Properties.ExecutableFriendlyName); + Assert.Equal("install", manager.Properties.InstallVerb); + Assert.Equal("update", manager.Properties.UpdateVerb); + Assert.Equal("uninstall", manager.Properties.UninstallVerb); + Assert.Equal("flathub", manager.DefaultSource.Name); + Assert.Equal("https://dl.flathub.org/repo/", manager.DefaultSource.Url.ToString()); + } + + [Fact] + public void GetInstallableVersionsReturnsEmptyList() + { + var manager = new Flatpak(); + var package = new PackageBuilder() + .WithManager(manager) + .WithId("org.sqlitebrowser.sqlitebrowser") + .Build(); + + var versions = manager.DetailsHelper.GetVersions(package); + Assert.Empty(versions); + } +} diff --git a/src/UniGetUI.PackageEngine.Tests/HarnessSmokeTests.cs b/src/UniGetUI.PackageEngine.Tests/HarnessSmokeTests.cs new file mode 100644 index 0000000..84ee4dd --- /dev/null +++ b/src/UniGetUI.PackageEngine.Tests/HarnessSmokeTests.cs @@ -0,0 +1,147 @@ +using UniGetUI.PackageEngine.Enums; +using UniGetUI.PackageEngine.PackageLoader; +using UniGetUI.PackageEngine.Serializable; +using UniGetUI.PackageEngine.Tests.Infrastructure.Assertions; +using UniGetUI.PackageEngine.Tests.Infrastructure.Builders; +using UniGetUI.PackageEngine.Tests.Infrastructure.Helpers; + +namespace UniGetUI.PackageEngine.Tests; + +public sealed class HarnessSmokeTests +{ + [Fact] + public void PackageManagerBuilderCreatesReadyManagerWithDeterministicSources() + { + var manager = new PackageManagerBuilder() + .WithName("Harness") + .WithDisplayName("Harness Manager") + .WithSources(manager => + [ + new SourceBuilder() + .WithManager(manager) + .WithName("community") + .WithUrl("https://example.test/community") + .WithPackageCount(42) + .Build(), + ]) + .Build(); + + Assert.True(manager.IsReady()); + Assert.Equal("Harness", manager.Name); + Assert.Equal("Harness Manager", manager.DisplayName); + var source = Assert.Single(manager.SourcesHelper.GetSources()); + Assert.Equal("community", source.Name); + Assert.Same(source, manager.SourcesHelper.Factory.GetSourceIfExists("community")); + } + + [Fact] + public async Task PackageDetailsBuilderPopulatesPackageThroughFakeHelper() + { + var manager = new PackageManagerBuilder() + .ConfigureDetails(helper => + helper.DetailsFactory = package => + new PackageDetailsBuilder() + .WithDescription("Deterministic package description") + .WithPublisher("Contoso") + .WithAuthor("UniGetUI Tests") + .WithHomepage("https://example.test/package") + .WithLicense("MIT", "https://example.test/license") + .WithInstaller( + "https://example.test/installer.exe", + "abc123", + "exe", + 2048 + ) + .WithManifest("https://example.test/manifest.json") + .WithReleaseNotes( + "Smoke-test release notes", + "https://example.test/release-notes" + ) + .WithUpdateDate("2026-01-01") + .WithTag("smoke") + .WithDependency("dep.one", "1.0.0") + .Build(package)) + .Build(); + var package = new PackageBuilder().WithManager(manager).WithId("Contoso.Test").Build(); + + await package.Details.Load(); + + Assert.True(package.Details.IsPopulated); + Assert.Equal("Deterministic package description", package.Details.Description); + Assert.Equal("Contoso", package.Details.Publisher); + Assert.Single(package.Details.Dependencies); + } + + [Fact] + public async Task InstalledPackagesLoaderLoadsConfiguredPackagesWithoutLiveProcesses() + { + var manager = new PackageManagerBuilder() + .WithInstalledPackages(manager => + [ + new PackageBuilder() + .WithManager(manager) + .WithName("Contoso Tool") + .WithId("Contoso.Tool") + .WithVersion("1.2.3") + .Build(), + ]) + .Build(); + _ = new DiscoverablePackagesLoader([manager]); + _ = new UpgradablePackagesLoader([manager]); + var loader = new InstalledPackagesLoader([manager]); + var recorder = new LoaderEventRecorder(loader); + + await loader.ReloadPackagesSilently(); + + Assert.True(recorder.StartedLoading); + Assert.True(recorder.FinishedLoading); + var package = Assert.Single(loader.Packages); + PackageAssert.Matches(package, "Contoso Tool", "Contoso.Tool", "1.2.3"); + Assert.Contains(recorder.AddedPackages, candidate => candidate.Id == "Contoso.Tool"); + } + + [Fact] + public void OperationHelperReturnsConfiguredParametersAndVeredict() + { + var manager = new PackageManagerBuilder() + .ConfigureOperation(helper => + { + helper.ParametersFactory = (package, options, operation) => + [ + operation.ToString().ToLowerInvariant(), + package.Id, + "--scope", + options.InstallationScope, + ]; + helper.ResultFactory = (_, _, _, returnCode) => + returnCode == 0 ? OperationVeredict.Success : OperationVeredict.Failure; + }) + .Build(); + var package = new PackageBuilder() + .WithManager(manager) + .WithName("Contoso Tool") + .WithId("Contoso.Tool") + .Build(); + var options = new InstallOptions { InstallationScope = PackageScope.User }; + + var parameters = manager.OperationHelper.GetParameters(package, options, OperationType.Install); + var veredict = manager.OperationHelper.GetResult( + package, + OperationType.Install, + ["completed"], + 0 + ); + + OperationAssert.HasParameters(parameters, "install", "Contoso.Tool", "--scope", PackageScope.User); + OperationAssert.HasVeredict(veredict, OperationVeredict.Success); + } + + [Fact] + public void FixtureHelperReadsSampleFixture() + { + var contents = PackageEngineFixtureFiles.ReadAllText("sample-manager-output.txt"); + + Assert.Contains("Contoso.Tool", contents); + Assert.Contains("1.2.3", contents); + } +} diff --git a/src/UniGetUI.PackageEngine.Tests/IgnoredUpdatesDatabaseTests.cs b/src/UniGetUI.PackageEngine.Tests/IgnoredUpdatesDatabaseTests.cs new file mode 100644 index 0000000..f334da0 --- /dev/null +++ b/src/UniGetUI.PackageEngine.Tests/IgnoredUpdatesDatabaseTests.cs @@ -0,0 +1,87 @@ +using UniGetUI.Core.Data; +using UniGetUI.Core.SettingsEngine; +using UniGetUI.Core.Tools; +using UniGetUI.PackageEngine.Classes.Packages.Classes; +using UniGetUI.PackageEngine.Tests.Infrastructure.Builders; + +namespace UniGetUI.PackageEngine.Tests; + +public sealed class IgnoredUpdatesDatabaseTests : IDisposable +{ + private readonly string _testRoot = Path.Combine( + Path.GetTempPath(), + nameof(IgnoredUpdatesDatabaseTests), + Guid.NewGuid().ToString("N") + ); + + public IgnoredUpdatesDatabaseTests() + { + Directory.CreateDirectory(_testRoot); + CoreData.TEST_DataDirectoryOverride = Path.Combine(_testRoot, "Data"); + Directory.CreateDirectory(CoreData.UniGetUIUserConfigurationDirectory); + Settings.ResetSettings(); + } + + public void Dispose() + { + Settings.ResetSettings(); + CoreData.TEST_DataDirectoryOverride = null; + if (Directory.Exists(_testRoot)) + { + Directory.Delete(_testRoot, recursive: true); + } + } + + [Fact] + public void AddGetAndRemoveRoundTripForSpecificVersions() + { + var manager = new PackageManagerBuilder().Build(); + var package = new PackageBuilder().WithManager(manager).WithId("Contoso.Tool").Build(); + string ignoredId = IgnoredUpdatesDatabase.GetIgnoredIdForPackage(package); + + IgnoredUpdatesDatabase.Add(ignoredId, "2.0.0"); + + Assert.Equal("2.0.0", IgnoredUpdatesDatabase.GetIgnoredVersion(ignoredId)); + Assert.True(IgnoredUpdatesDatabase.HasUpdatesIgnored(ignoredId, "2.0.0")); + Assert.False(IgnoredUpdatesDatabase.HasUpdatesIgnored(ignoredId, "3.0.0")); + Assert.True(IgnoredUpdatesDatabase.Remove(ignoredId)); + Assert.Null(IgnoredUpdatesDatabase.GetIgnoredVersion(ignoredId)); + } + + [Fact] + public void HasUpdatesIgnored_HonorsWildcardAndExpiresPastDateEntries() + { + const string ignoredId = "manager\\contoso.tool"; + string futureDate = $"<{DateTime.Today.AddDays(5):yyyy-MM-dd}"; + string pastDate = $"<{DateTime.Today.AddDays(-5):yyyy-MM-dd}"; + + IgnoredUpdatesDatabase.Add(ignoredId, "*"); + Assert.True(IgnoredUpdatesDatabase.HasUpdatesIgnored(ignoredId, "9.9.9")); + + Settings.SetDictionary(Settings.K.IgnoredPackageUpdates, new Dictionary { [ignoredId] = futureDate }); + Assert.True(IgnoredUpdatesDatabase.HasUpdatesIgnored(ignoredId, "1.0.0")); + + Settings.SetDictionary(Settings.K.IgnoredPackageUpdates, new Dictionary { [ignoredId] = pastDate }); + Assert.False(IgnoredUpdatesDatabase.HasUpdatesIgnored(ignoredId, "1.0.0")); + Assert.Null(IgnoredUpdatesDatabase.GetIgnoredVersion(ignoredId)); + } + + [Theory] + [InlineData(14)] + [InlineData(30)] + [InlineData(365)] + public void PauseTime_StringRepresentationUsesLargestFriendlyUnit(int days) + { + var pauseTime = new IgnoredUpdatesDatabase.PauseTime { Days = days }; + + string expected = days switch + { + 14 => CoreTools.Translate("{0} weeks", 2), + 30 => CoreTools.Translate("1 month"), + 365 => CoreTools.Translate("{0} months", 13), + _ => throw new InvalidOperationException("Unexpected test input"), + }; + + Assert.Equal(expected, pauseTime.StringRepresentation()); + } +} diff --git a/src/UniGetUI.PackageEngine.Tests/Infrastructure/Assertions/OperationAssert.cs b/src/UniGetUI.PackageEngine.Tests/Infrastructure/Assertions/OperationAssert.cs new file mode 100644 index 0000000..f031ee9 --- /dev/null +++ b/src/UniGetUI.PackageEngine.Tests/Infrastructure/Assertions/OperationAssert.cs @@ -0,0 +1,16 @@ +using UniGetUI.PackageEngine.Enums; + +namespace UniGetUI.PackageEngine.Tests.Infrastructure.Assertions; + +public static class OperationAssert +{ + public static void HasVeredict(OperationVeredict actual, OperationVeredict expected) + { + Assert.Equal(expected, actual); + } + + public static void HasParameters(IReadOnlyList actual, params string[] expected) + { + Assert.Equal(expected, actual); + } +} diff --git a/src/UniGetUI.PackageEngine.Tests/Infrastructure/Assertions/PackageAssert.cs b/src/UniGetUI.PackageEngine.Tests/Infrastructure/Assertions/PackageAssert.cs new file mode 100644 index 0000000..5ea81ab --- /dev/null +++ b/src/UniGetUI.PackageEngine.Tests/Infrastructure/Assertions/PackageAssert.cs @@ -0,0 +1,25 @@ +using UniGetUI.PackageEngine.Interfaces; + +namespace UniGetUI.PackageEngine.Tests.Infrastructure.Assertions; + +public static class PackageAssert +{ + public static void Matches(IPackage package, string name, string id, string version, string? newVersion = null) + { + Assert.Equal(name, package.Name); + Assert.Equal(id, package.Id); + Assert.Equal(version, package.VersionString); + Assert.Equal(newVersion ?? version, package.NewVersionString); + } + + public static void BelongsTo(IPackage package, IPackageManager manager, IManagerSource source) + { + Assert.Same(manager, package.Manager); + Assert.Same(source, package.Source); + } + + public static void ContainsIds(IEnumerable packages, params string[] expectedIds) + { + Assert.Equal(expectedIds.OrderBy(id => id), packages.Select(package => package.Id).OrderBy(id => id)); + } +} diff --git a/src/UniGetUI.PackageEngine.Tests/Infrastructure/Builders/PackageBuilder.cs b/src/UniGetUI.PackageEngine.Tests/Infrastructure/Builders/PackageBuilder.cs new file mode 100644 index 0000000..96ace5f --- /dev/null +++ b/src/UniGetUI.PackageEngine.Tests/Infrastructure/Builders/PackageBuilder.cs @@ -0,0 +1,68 @@ +using UniGetUI.PackageEngine.Interfaces; +using UniGetUI.PackageEngine.PackageClasses; +using UniGetUI.PackageEngine.Structs; + +namespace UniGetUI.PackageEngine.Tests.Infrastructure.Builders; + +public sealed class PackageBuilder +{ + private string _name = "Test Package"; + private string _id = "Contoso.Test"; + private string _installedVersion = "1.0.0"; + private string? _availableVersion; + private IManagerSource? _source; + private IPackageManager? _manager; + private OverridenInstallationOptions? _options; + + public PackageBuilder WithName(string name) + { + _name = name; + return this; + } + + public PackageBuilder WithId(string id) + { + _id = id; + return this; + } + + public PackageBuilder WithVersion(string version) + { + _installedVersion = version; + return this; + } + + public PackageBuilder WithNewVersion(string version) + { + _availableVersion = version; + return this; + } + + public PackageBuilder WithManager(IPackageManager manager) + { + _manager = manager; + return this; + } + + public PackageBuilder WithSource(IManagerSource source) + { + _source = source; + return this; + } + + public PackageBuilder WithOptions(OverridenInstallationOptions options) + { + _options = options; + return this; + } + + public Package Build() + { + var manager = _manager ?? new PackageManagerBuilder().Build(); + var source = _source ?? manager.DefaultSource; + + return _availableVersion is null + ? new Package(_name, _id, _installedVersion, source, manager, _options) + : new Package(_name, _id, _installedVersion, _availableVersion, source, manager, _options); + } +} diff --git a/src/UniGetUI.PackageEngine.Tests/Infrastructure/Builders/PackageDetailsBuilder.cs b/src/UniGetUI.PackageEngine.Tests/Infrastructure/Builders/PackageDetailsBuilder.cs new file mode 100644 index 0000000..37f92c7 --- /dev/null +++ b/src/UniGetUI.PackageEngine.Tests/Infrastructure/Builders/PackageDetailsBuilder.cs @@ -0,0 +1,125 @@ +using UniGetUI.PackageEngine.Interfaces; +using UniGetUI.PackageEngine.PackageClasses; + +namespace UniGetUI.PackageEngine.Tests.Infrastructure.Builders; + +public sealed class PackageDetailsBuilder +{ + private string? _description; + private string? _publisher; + private string? _author; + private Uri? _homepageUrl; + private string? _license; + private Uri? _licenseUrl; + private Uri? _installerUrl; + private string? _installerHash; + private string? _installerType; + private long _installerSize; + private Uri? _manifestUrl; + private string? _updateDate; + private string? _releaseNotes; + private Uri? _releaseNotesUrl; + private readonly List _tags = []; + private readonly List _dependencies = []; + + public PackageDetailsBuilder WithDescription(string description) + { + _description = description; + return this; + } + + public PackageDetailsBuilder WithPublisher(string publisher) + { + _publisher = publisher; + return this; + } + + public PackageDetailsBuilder WithAuthor(string author) + { + _author = author; + return this; + } + + public PackageDetailsBuilder WithHomepage(string homepageUrl) + { + _homepageUrl = new Uri(homepageUrl); + return this; + } + + public PackageDetailsBuilder WithLicense(string license, string? licenseUrl = null) + { + _license = license; + _licenseUrl = licenseUrl is null ? null : new Uri(licenseUrl); + return this; + } + + public PackageDetailsBuilder WithInstaller(string installerUrl, string hash, string installerType, long installerSize) + { + _installerUrl = new Uri(installerUrl); + _installerHash = hash; + _installerType = installerType; + _installerSize = installerSize; + return this; + } + + public PackageDetailsBuilder WithManifest(string manifestUrl) + { + _manifestUrl = new Uri(manifestUrl); + return this; + } + + public PackageDetailsBuilder WithReleaseNotes(string releaseNotes, string? releaseNotesUrl = null) + { + _releaseNotes = releaseNotes; + _releaseNotesUrl = releaseNotesUrl is null ? null : new Uri(releaseNotesUrl); + return this; + } + + public PackageDetailsBuilder WithUpdateDate(string updateDate) + { + _updateDate = updateDate; + return this; + } + + public PackageDetailsBuilder WithTag(string tag) + { + _tags.Add(tag); + return this; + } + + public PackageDetailsBuilder WithDependency(string name, string version, bool mandatory = true) + { + _dependencies.Add( + new IPackageDetails.Dependency + { + Name = name, + Version = version, + Mandatory = mandatory, + } + ); + return this; + } + + public PackageDetails Build(IPackage package) + { + return new PackageDetails(package) + { + Description = _description, + Publisher = _publisher, + Author = _author, + HomepageUrl = _homepageUrl, + License = _license, + LicenseUrl = _licenseUrl, + InstallerUrl = _installerUrl, + InstallerHash = _installerHash, + InstallerType = _installerType, + InstallerSize = _installerSize, + ManifestUrl = _manifestUrl, + UpdateDate = _updateDate, + ReleaseNotes = _releaseNotes, + ReleaseNotesUrl = _releaseNotesUrl, + Tags = _tags.ToArray(), + Dependencies = _dependencies.ToList(), + }; + } +} diff --git a/src/UniGetUI.PackageEngine.Tests/Infrastructure/Builders/PackageManagerBuilder.cs b/src/UniGetUI.PackageEngine.Tests/Infrastructure/Builders/PackageManagerBuilder.cs new file mode 100644 index 0000000..36a611b --- /dev/null +++ b/src/UniGetUI.PackageEngine.Tests/Infrastructure/Builders/PackageManagerBuilder.cs @@ -0,0 +1,120 @@ +using UniGetUI.PackageEngine.Interfaces; +using UniGetUI.PackageEngine.ManagerClasses.Manager; +using UniGetUI.PackageEngine.PackageClasses; +using UniGetUI.PackageEngine.Tests.Infrastructure.Fakes; + +namespace UniGetUI.PackageEngine.Tests.Infrastructure.Builders; + +public sealed class PackageManagerBuilder +{ + private string _name = "TestManager"; + private string _displayName = "Test Manager"; + private Func _capabilitiesFactory = static capabilities => capabilities; + private Func> _sourcesFactory = manager => [manager.DefaultSource]; + private Func> _availableUpdatesFactory = static _ => []; + private Func> _installedPackagesFactory = static _ => []; + private Action? _detailsConfiguration; + private Action? _operationConfiguration; + private Action? _sourceConfiguration; + private Action? _managerConfiguration; + + public PackageManagerBuilder WithName(string name) + { + _name = name; + return this; + } + + public PackageManagerBuilder WithDisplayName(string displayName) + { + _displayName = displayName; + return this; + } + + public PackageManagerBuilder ConfigureCapabilities( + Func capabilitiesFactory + ) + { + _capabilitiesFactory = capabilitiesFactory; + return this; + } + + public PackageManagerBuilder WithSources( + Func> sourcesFactory + ) + { + _sourcesFactory = sourcesFactory; + return this; + } + + public PackageManagerBuilder WithFindPackages( + Func> findPackagesFactory + ) + { + _managerConfiguration += manager => manager.SetFindPackages(query => findPackagesFactory(manager, query)); + return this; + } + + public PackageManagerBuilder WithInstalledPackages( + Func> installedPackagesFactory + ) + { + _installedPackagesFactory = installedPackagesFactory; + return this; + } + + public PackageManagerBuilder WithAvailableUpdates( + Func> availableUpdatesFactory + ) + { + _availableUpdatesFactory = availableUpdatesFactory; + return this; + } + + public PackageManagerBuilder ConfigureDetails(Action configure) + { + _detailsConfiguration = configure; + return this; + } + + public PackageManagerBuilder ConfigureOperation(Action configure) + { + _operationConfiguration = configure; + return this; + } + + public PackageManagerBuilder ConfigureSources(Action configure) + { + _sourceConfiguration = configure; + return this; + } + + public PackageManagerBuilder ConfigureManager(Action configure) + { + _managerConfiguration += configure; + return this; + } + + public TestPackageManager Build(bool initialize = true) + { + var manager = new TestPackageManager(_name, _displayName); + manager.Capabilities = _capabilitiesFactory(manager.Capabilities); + + _detailsConfiguration?.Invoke(manager.TestDetailsHelper); + _operationConfiguration?.Invoke(manager.TestOperationHelper); + _sourceConfiguration?.Invoke(manager.TestSourcesHelper); + + manager.SetKnownSources(_sourcesFactory(manager)); + manager.SetFindPackages(_ => []); + manager.SetAvailableUpdates(() => _availableUpdatesFactory(manager)); + manager.SetInstalledPackages(() => _installedPackagesFactory(manager)); + + _managerConfiguration?.Invoke(manager); + + if (initialize) + { + manager.Initialize(); + } + + return manager; + } +} diff --git a/src/UniGetUI.PackageEngine.Tests/Infrastructure/Builders/SourceBuilder.cs b/src/UniGetUI.PackageEngine.Tests/Infrastructure/Builders/SourceBuilder.cs new file mode 100644 index 0000000..231ac96 --- /dev/null +++ b/src/UniGetUI.PackageEngine.Tests/Infrastructure/Builders/SourceBuilder.cs @@ -0,0 +1,63 @@ +using UniGetUI.PackageEngine.Classes.Manager; +using UniGetUI.PackageEngine.Interfaces; + +namespace UniGetUI.PackageEngine.Tests.Infrastructure.Builders; + +public sealed class SourceBuilder +{ + private IPackageManager? _manager; + private string _name = "default"; + private Uri _url = new("https://example.test/default"); + private int? _packageCount = 0; + private string _updateDate = string.Empty; + private bool _isVirtualManager; + + public SourceBuilder WithManager(IPackageManager manager) + { + _manager = manager; + return this; + } + + public SourceBuilder WithName(string name) + { + _name = name; + return this; + } + + public SourceBuilder WithUrl(string url) + { + _url = new Uri(url); + return this; + } + + public SourceBuilder WithPackageCount(int? packageCount) + { + _packageCount = packageCount; + return this; + } + + public SourceBuilder WithUpdateDate(string updateDate) + { + _updateDate = updateDate; + return this; + } + + public SourceBuilder AsVirtualManager(bool isVirtualManager = true) + { + _isVirtualManager = isVirtualManager; + return this; + } + + public ManagerSource Build() + { + var manager = _manager ?? new PackageManagerBuilder().Build(); + return new ManagerSource( + manager, + _name, + _url, + _packageCount, + _updateDate, + _isVirtualManager + ); + } +} diff --git a/src/UniGetUI.PackageEngine.Tests/Infrastructure/Fakes/TestPackageDetailsHelper.cs b/src/UniGetUI.PackageEngine.Tests/Infrastructure/Fakes/TestPackageDetailsHelper.cs new file mode 100644 index 0000000..b2b951b --- /dev/null +++ b/src/UniGetUI.PackageEngine.Tests/Infrastructure/Fakes/TestPackageDetailsHelper.cs @@ -0,0 +1,71 @@ +using UniGetUI.Core.IconEngine; +using UniGetUI.PackageEngine.Classes.Manager.BaseProviders; +using UniGetUI.PackageEngine.Interfaces; + +namespace UniGetUI.PackageEngine.Tests.Infrastructure.Fakes; + +public sealed class TestPackageDetailsHelper(TestPackageManager manager) : BasePkgDetailsHelper(manager) +{ + public Func? DetailsFactory { get; set; } + + public Action? PopulateDetails { get; set; } + + public Func> VersionsFactory { get; set; } = static _ => []; + + public Func IconFactory { get; set; } = static _ => null; + + public Func> ScreenshotsFactory { get; set; } = static _ => []; + + public Func InstallLocationFactory { get; set; } = static _ => null; + + protected override void GetDetails_UnSafe(IPackageDetails details) + { + if (DetailsFactory?.Invoke(details.Package) is { } source) + { + Copy(source, details); + } + + PopulateDetails?.Invoke(details); + } + + protected override IReadOnlyList GetInstallableVersions_UnSafe(IPackage package) + { + return VersionsFactory(package); + } + + protected override CacheableIcon? GetIcon_UnSafe(IPackage package) + { + return IconFactory(package); + } + + protected override IReadOnlyList GetScreenshots_UnSafe(IPackage package) + { + return ScreenshotsFactory(package); + } + + protected override string? GetInstallLocation_UnSafe(IPackage package) + { + return InstallLocationFactory(package); + } + + private static void Copy(IPackageDetails source, IPackageDetails target) + { + target.Description = source.Description; + target.Publisher = source.Publisher; + target.Author = source.Author; + target.HomepageUrl = source.HomepageUrl; + target.License = source.License; + target.LicenseUrl = source.LicenseUrl; + target.InstallerUrl = source.InstallerUrl; + target.InstallerHash = source.InstallerHash; + target.InstallerType = source.InstallerType; + target.InstallerSize = source.InstallerSize; + target.ManifestUrl = source.ManifestUrl; + target.UpdateDate = source.UpdateDate; + target.ReleaseNotes = source.ReleaseNotes; + target.ReleaseNotesUrl = source.ReleaseNotesUrl; + target.Tags = source.Tags.ToArray(); + target.Dependencies.Clear(); + target.Dependencies.AddRange(source.Dependencies); + } +} diff --git a/src/UniGetUI.PackageEngine.Tests/Infrastructure/Fakes/TestPackageLoader.cs b/src/UniGetUI.PackageEngine.Tests/Infrastructure/Fakes/TestPackageLoader.cs new file mode 100644 index 0000000..e64af17 --- /dev/null +++ b/src/UniGetUI.PackageEngine.Tests/Infrastructure/Fakes/TestPackageLoader.cs @@ -0,0 +1,49 @@ +using UniGetUI.PackageEngine.Interfaces; +using UniGetUI.PackageEngine.PackageLoader; + +namespace UniGetUI.PackageEngine.Tests.Infrastructure.Fakes; + +internal sealed class TestPackageLoader : AbstractPackageLoader +{ + private readonly Func> _loadPackages; + private readonly Func> _isPackageValid; + private readonly Func _whenAddingPackage; + + public TestPackageLoader( + IReadOnlyList managers, + bool allowMultiplePackageVersions = false, + bool disableReload = false, + bool checkedByDefault = false, + Func>? loadPackages = null, + Func>? isPackageValid = null, + Func? whenAddingPackage = null + ) + : base( + managers, + identifier: "TEST_LOADER", + AllowMultiplePackageVersions: allowMultiplePackageVersions, + DisableReload: disableReload, + CheckedBydefault: checkedByDefault, + RequiresInternet: false + ) + { + _loadPackages = loadPackages ?? (manager => manager.GetInstalledPackages()); + _isPackageValid = isPackageValid ?? (_ => Task.FromResult(true)); + _whenAddingPackage = whenAddingPackage ?? (_ => Task.CompletedTask); + } + + protected override IReadOnlyList LoadPackagesFromManager(IPackageManager manager) + { + return _loadPackages(manager); + } + + protected override Task IsPackageValid(IPackage package) + { + return _isPackageValid(package); + } + + protected override Task WhenAddingPackage(IPackage package) + { + return _whenAddingPackage(package); + } +} diff --git a/src/UniGetUI.PackageEngine.Tests/Infrastructure/Fakes/TestPackageManager.cs b/src/UniGetUI.PackageEngine.Tests/Infrastructure/Fakes/TestPackageManager.cs new file mode 100644 index 0000000..a8ee96d --- /dev/null +++ b/src/UniGetUI.PackageEngine.Tests/Infrastructure/Fakes/TestPackageManager.cs @@ -0,0 +1,175 @@ +using UniGetUI.Interface.Enums; +using UniGetUI.PackageEngine.Classes.Manager; +using UniGetUI.PackageEngine.Interfaces; +using UniGetUI.PackageEngine.ManagerClasses.Manager; +using UniGetUI.PackageEngine.PackageClasses; + +namespace UniGetUI.PackageEngine.Tests.Infrastructure.Fakes; + +public sealed class TestPackageManager : PackageManager +{ + private Func> _findPackages = _ => []; + private Func> _getAvailableUpdates = static () => []; + private Func> _getInstalledPackages = static () => []; + private IReadOnlyList _candidateExecutableFiles; + + public TestPackageManager(string name = "TestManager", string? displayName = null) + { + Capabilities = new ManagerCapabilities + { + CanRunAsAdmin = true, + CanSkipIntegrityChecks = true, + CanRunInteractively = true, + CanRemoveDataOnUninstall = true, + CanDownloadInstaller = true, + CanUninstallPreviousVersionsAfterUpdate = true, + CanListDependencies = true, + SupportsCustomVersions = true, + SupportsCustomArchitectures = true, + SupportsCustomScopes = true, + SupportsPreRelease = true, + SupportsCustomLocations = true, + SupportsCustomSources = true, + SupportsCustomPackageIcons = true, + SupportsCustomPackageScreenshots = true, + SupportsProxy = ProxySupport.Yes, + SupportsProxyAuth = true, + Sources = new SourceCapabilities + { + KnowsPackageCount = true, + KnowsUpdateDate = true, + }, + }; + + Properties = new ManagerProperties + { + Name = name, + DisplayName = displayName ?? name, + Description = "Package-engine test harness manager", + ExecutableFriendlyName = $"{name}.exe", + InstallVerb = "install", + UpdateVerb = "update", + UninstallVerb = "uninstall", + ColorIconId = "package_mask", + IconId = (IconType)'\uE8FD', + }; + + var defaultSource = new ManagerSource(this, "default", new Uri("https://example.test/default")); + var properties = Properties; + properties.DefaultSource = defaultSource; + properties.KnownSources = [defaultSource]; + Properties = properties; + + TestDetailsHelper = new TestPackageDetailsHelper(this); + TestOperationHelper = new TestPackageOperationHelper(this); + TestSourcesHelper = new TestSourceHelper(this); + + DetailsHelper = TestDetailsHelper; + OperationHelper = TestOperationHelper; + SourcesHelper = TestSourcesHelper; + + _candidateExecutableFiles = [$"C:\\test-tools\\{name}.exe"]; + } + + public TestPackageDetailsHelper TestDetailsHelper { get; } + + public TestPackageOperationHelper TestOperationHelper { get; } + + public TestSourceHelper TestSourcesHelper { get; } + + public bool ExecutableFound { get; set; } = true; + + public string ExecutablePath { get; set; } = "C:\\test-tools\\manager.exe"; + + public string ExecutableArguments { get; set; } = ""; + + public string LoadedVersion { get; set; } = "1.0.0-test"; + + public int AttemptFastRepairCalls { get; private set; } + + public int RefreshPackageIndexesCalls { get; private set; } + + public string? LastQuery { get; private set; } + + public void SetFindPackages(Func> findPackages) + { + _findPackages = findPackages; + } + + public void SetAvailableUpdates(Func> getAvailableUpdates) + { + _getAvailableUpdates = getAvailableUpdates; + } + + public void SetInstalledPackages(Func> getInstalledPackages) + { + _getInstalledPackages = getInstalledPackages; + } + + public void SetCandidateExecutableFiles(params string[] candidateExecutableFiles) + { + _candidateExecutableFiles = candidateExecutableFiles; + } + + public void SetKnownSources(IEnumerable sources) + { + var sourceArray = sources.ToArray(); + if (sourceArray.Length == 0) + { + sourceArray = [DefaultSource]; + } + + TestSourcesHelper.SetSources(sourceArray); + + var properties = Properties; + properties.KnownSources = sourceArray; + Properties = properties; + } + + protected override void _loadManagerExecutableFile( + out bool found, + out string path, + out string callArguments + ) + { + found = ExecutableFound; + path = ExecutablePath; + callArguments = ExecutableArguments; + } + + protected override void _loadManagerVersion(out string version) + { + version = LoadedVersion; + } + + protected override IReadOnlyList FindPackages_UnSafe(string query) + { + LastQuery = query; + return _findPackages(query); + } + + protected override IReadOnlyList GetAvailableUpdates_UnSafe() + { + return _getAvailableUpdates(); + } + + protected override IReadOnlyList GetInstalledPackages_UnSafe() + { + return _getInstalledPackages(); + } + + public override IReadOnlyList FindCandidateExecutableFiles() + { + return _candidateExecutableFiles; + } + + public override void AttemptFastRepair() + { + AttemptFastRepairCalls++; + } + + public override void RefreshPackageIndexes() + { + RefreshPackageIndexesCalls++; + } +} diff --git a/src/UniGetUI.PackageEngine.Tests/Infrastructure/Fakes/TestPackageOperationHelper.cs b/src/UniGetUI.PackageEngine.Tests/Infrastructure/Fakes/TestPackageOperationHelper.cs new file mode 100644 index 0000000..74a9c33 --- /dev/null +++ b/src/UniGetUI.PackageEngine.Tests/Infrastructure/Fakes/TestPackageOperationHelper.cs @@ -0,0 +1,35 @@ +using UniGetUI.PackageEngine.Classes.Manager.BaseProviders; +using UniGetUI.PackageEngine.Enums; +using UniGetUI.PackageEngine.Interfaces; +using UniGetUI.PackageEngine.Serializable; + +namespace UniGetUI.PackageEngine.Tests.Infrastructure.Fakes; + +public sealed class TestPackageOperationHelper(TestPackageManager manager) + : BasePkgOperationHelper(manager) +{ + public Func> ParametersFactory { get; set; } = + static (_, _, _) => []; + + public Func, int, OperationVeredict> ResultFactory { get; set; } = + static (_, _, _, returnCode) => returnCode == 0 ? OperationVeredict.Success : OperationVeredict.Failure; + + protected override IReadOnlyList _getOperationParameters( + IPackage package, + InstallOptions options, + OperationType operation + ) + { + return ParametersFactory(package, options, operation); + } + + protected override OperationVeredict _getOperationResult( + IPackage package, + OperationType operation, + IReadOnlyList processOutput, + int returnCode + ) + { + return ResultFactory(package, operation, processOutput, returnCode); + } +} diff --git a/src/UniGetUI.PackageEngine.Tests/Infrastructure/Fakes/TestSourceHelper.cs b/src/UniGetUI.PackageEngine.Tests/Infrastructure/Fakes/TestSourceHelper.cs new file mode 100644 index 0000000..8f39f1b --- /dev/null +++ b/src/UniGetUI.PackageEngine.Tests/Infrastructure/Fakes/TestSourceHelper.cs @@ -0,0 +1,60 @@ +using UniGetUI.PackageEngine.Classes.Manager.Providers; +using UniGetUI.PackageEngine.Enums; +using UniGetUI.PackageEngine.Interfaces; + +namespace UniGetUI.PackageEngine.Tests.Infrastructure.Fakes; + +public sealed class TestSourceHelper(TestPackageManager manager) : BaseSourceHelper(manager) +{ + private IReadOnlyList _sources = [manager.DefaultSource]; + + public Func AddParametersFactory { get; set; } = + static source => ["source", "add", source.Name]; + + public Func RemoveParametersFactory { get; set; } = + static source => ["source", "remove", source.Name]; + + public Func AddVeredictFactory { get; set; } = + static (_, returnCode, _) => returnCode == 0 ? OperationVeredict.Success : OperationVeredict.Failure; + + public Func RemoveVeredictFactory { get; set; } = + static (_, returnCode, _) => returnCode == 0 ? OperationVeredict.Success : OperationVeredict.Failure; + + public void SetSources(IEnumerable sources) + { + _sources = sources.ToArray(); + } + + public override string[] GetAddSourceParameters(IManagerSource source) + { + return AddParametersFactory(source); + } + + public override string[] GetRemoveSourceParameters(IManagerSource source) + { + return RemoveParametersFactory(source); + } + + protected override OperationVeredict _getAddSourceOperationVeredict( + IManagerSource source, + int ReturnCode, + string[] Output + ) + { + return AddVeredictFactory(source, ReturnCode, Output); + } + + protected override OperationVeredict _getRemoveSourceOperationVeredict( + IManagerSource source, + int ReturnCode, + string[] Output + ) + { + return RemoveVeredictFactory(source, ReturnCode, Output); + } + + protected override IReadOnlyList GetSources_UnSafe() + { + return _sources; + } +} diff --git a/src/UniGetUI.PackageEngine.Tests/Infrastructure/Fakes/TestUpgradablePackagesLoader.cs b/src/UniGetUI.PackageEngine.Tests/Infrastructure/Fakes/TestUpgradablePackagesLoader.cs new file mode 100644 index 0000000..b68e915 --- /dev/null +++ b/src/UniGetUI.PackageEngine.Tests/Infrastructure/Fakes/TestUpgradablePackagesLoader.cs @@ -0,0 +1,25 @@ +using System.Reflection; +using UniGetUI.PackageEngine.Interfaces; +using UniGetUI.PackageEngine.PackageLoader; + +namespace UniGetUI.PackageEngine.Tests.Infrastructure.Fakes; + +internal sealed class TestUpgradablePackagesLoader : UpgradablePackagesLoader +{ + private static readonly FieldInfo UpdatesTimerField = typeof(UpgradablePackagesLoader).GetField( + "UpdatesTimer", + BindingFlags.Instance | BindingFlags.NonPublic + )!; + + public TestUpgradablePackagesLoader(IReadOnlyList managers) + : base(managers) { } + + public Task EvaluatePackageAsync(IPackage package) => IsPackageValid(package); + + public Task ApplyWhenAddingPackageAsync(IPackage package) => WhenAddingPackage(package); + + public void StartTimer() => StartAutoCheckTimeout(); + + public double? GetTimerIntervalMilliseconds() => + (UpdatesTimerField.GetValue(this) as System.Timers.Timer)?.Interval; +} diff --git a/src/UniGetUI.PackageEngine.Tests/Infrastructure/Helpers/LoaderEventRecorder.cs b/src/UniGetUI.PackageEngine.Tests/Infrastructure/Helpers/LoaderEventRecorder.cs new file mode 100644 index 0000000..1d4fbc5 --- /dev/null +++ b/src/UniGetUI.PackageEngine.Tests/Infrastructure/Helpers/LoaderEventRecorder.cs @@ -0,0 +1,37 @@ +using UniGetUI.PackageEngine.PackageLoader; + +namespace UniGetUI.PackageEngine.Tests.Infrastructure.Helpers; + +public sealed class LoaderEventRecorder +{ + public LoaderEventRecorder(AbstractPackageLoader loader) + { + loader.StartedLoading += (_, _) => + { + StartedLoading = true; + StartedLoadingCount++; + }; + loader.FinishedLoading += (_, _) => + { + FinishedLoading = true; + FinishedLoadingCount++; + }; + loader.PackagesChanged += (_, args) => Changes.Add(args); + } + + public bool StartedLoading { get; private set; } + + public int StartedLoadingCount { get; private set; } + + public bool FinishedLoading { get; private set; } + + public int FinishedLoadingCount { get; private set; } + + public List Changes { get; } = []; + + public IReadOnlyList AddedPackages => + Changes.SelectMany(change => change.AddedPackages).ToArray(); + + public IReadOnlyList RemovedPackages => + Changes.SelectMany(change => change.RemovedPackages).ToArray(); +} diff --git a/src/UniGetUI.PackageEngine.Tests/Infrastructure/Helpers/PackageEngineFixtureFiles.cs b/src/UniGetUI.PackageEngine.Tests/Infrastructure/Helpers/PackageEngineFixtureFiles.cs new file mode 100644 index 0000000..e897104 --- /dev/null +++ b/src/UniGetUI.PackageEngine.Tests/Infrastructure/Helpers/PackageEngineFixtureFiles.cs @@ -0,0 +1,23 @@ +namespace UniGetUI.PackageEngine.Tests.Infrastructure.Helpers; + +public static class PackageEngineFixtureFiles +{ + public static string RootPath => Path.Combine(AppContext.BaseDirectory, "Fixtures"); + + public static string GetPath(string relativePath) + { + var fullPath = Path.Combine(RootPath, relativePath); + Assert.True(File.Exists(fullPath), $"Expected fixture file to exist: {fullPath}"); + return fullPath; + } + + public static string ReadAllText(string relativePath) + { + return File.ReadAllText(GetPath(relativePath)); + } + + public static byte[] ReadAllBytes(string relativePath) + { + return File.ReadAllBytes(GetPath(relativePath)); + } +} diff --git a/src/UniGetUI.PackageEngine.Tests/Infrastructure/Helpers/TestHttpServer.cs b/src/UniGetUI.PackageEngine.Tests/Infrastructure/Helpers/TestHttpServer.cs new file mode 100644 index 0000000..e3e731f --- /dev/null +++ b/src/UniGetUI.PackageEngine.Tests/Infrastructure/Helpers/TestHttpServer.cs @@ -0,0 +1,87 @@ +using System.Net; +using System.Net.Sockets; + +namespace UniGetUI.PackageEngine.Tests.Infrastructure.Helpers; + +internal sealed class TestHttpServer : IDisposable +{ + private readonly HttpListener _listener = new(); + private readonly Func _handler; + private readonly List _requestPaths = []; + private readonly Task _backgroundTask; + + public TestHttpServer( + Func handler + ) + { + _handler = handler; + int port = GetAvailablePort(); + BaseUri = new Uri($"http://127.0.0.1:{port}/"); + _listener.Prefixes.Add(BaseUri.AbsoluteUri); + _listener.Start(); + _backgroundTask = Task.Run(ListenAsync); + } + + public Uri BaseUri { get; } + + public IReadOnlyList RequestPaths + { + get + { + lock (_requestPaths) + { + return _requestPaths.ToArray(); + } + } + } + + public void Dispose() + { + if (_listener.IsListening) + { + _listener.Stop(); + } + + _listener.Close(); + _backgroundTask.GetAwaiter().GetResult(); + } + + private async Task ListenAsync() + { + while (true) + { + try + { + HttpListenerContext context = await _listener.GetContextAsync(); + + lock (_requestPaths) + { + _requestPaths.Add(context.Request.RawUrl ?? context.Request.Url?.AbsolutePath ?? string.Empty); + } + + var (statusCode, content, contentType) = _handler(context.Request); + context.Response.StatusCode = statusCode; + context.Response.ContentType = contentType; + using StreamWriter writer = new(context.Response.OutputStream); + await writer.WriteAsync(content); + await writer.FlushAsync(); + context.Response.Close(); + } + catch (HttpListenerException) + { + break; + } + catch (ObjectDisposedException) + { + break; + } + } + } + + private static int GetAvailablePort() + { + using TcpListener listener = new(IPAddress.Loopback, 0); + listener.Start(); + return ((IPEndPoint)listener.LocalEndpoint).Port; + } +} diff --git a/src/UniGetUI.PackageEngine.Tests/InstallOptionsFactoryTests.cs b/src/UniGetUI.PackageEngine.Tests/InstallOptionsFactoryTests.cs new file mode 100644 index 0000000..ef63fad --- /dev/null +++ b/src/UniGetUI.PackageEngine.Tests/InstallOptionsFactoryTests.cs @@ -0,0 +1,164 @@ +using UniGetUI.Core.Data; +using UniGetUI.Core.SettingsEngine; +using UniGetUI.Core.SettingsEngine.SecureSettings; +using UniGetUI.Core.Tools; +using UniGetUI.PackageEngine.Classes.Packages; +using UniGetUI.PackageEngine.Classes.Packages.Classes; +using UniGetUI.PackageEngine.PackageClasses; +using UniGetUI.PackageEngine.Serializable; +using UniGetUI.PackageEngine.Tests.Infrastructure.Builders; + +namespace UniGetUI.PackageEngine.Tests; + +public sealed class InstallOptionsFactoryTests : IDisposable +{ + private readonly string _testRoot = Path.Combine( + Path.GetTempPath(), + nameof(InstallOptionsFactoryTests), + Guid.NewGuid().ToString("N") + ); + + public InstallOptionsFactoryTests() + { + Directory.CreateDirectory(_testRoot); + CoreData.TEST_DataDirectoryOverride = Path.Combine(_testRoot, "Data"); + SecureSettings.TEST_SecureSettingsRootOverride = Path.Combine(_testRoot, "SecureSettings"); + Directory.CreateDirectory(CoreData.UniGetUIInstallationOptionsDirectory); + Directory.CreateDirectory(CoreData.UniGetUIUserConfigurationDirectory); + Settings.ResetSettings(); + SecureSettings.ApplyForUser( + Environment.UserName, + SecureSettings.ResolveKey(SecureSettings.K.AllowCLIArguments), + false + ); + SecureSettings.ApplyForUser( + Environment.UserName, + SecureSettings.ResolveKey(SecureSettings.K.AllowPrePostOpCommand), + false + ); + } + + public void Dispose() + { + Settings.ResetSettings(); + CoreData.TEST_DataDirectoryOverride = null; + SecureSettings.TEST_SecureSettingsRootOverride = null; + if (Directory.Exists(_testRoot)) + { + Directory.Delete(_testRoot, recursive: true); + } + } + + [Fact] + public void LoadApplicable_UsesManagerDefaultsAndExpandsPackageToken() + { + var manager = new PackageManagerBuilder().WithName($"Manager{Guid.NewGuid():N}").Build(); + var package = new PackageBuilder().WithManager(manager).WithId("Contoso:Tool").Build(); + var managerOptions = new InstallOptions + { + CustomInstallLocation = @"C:\Apps\%PACKAGE%", + InteractiveInstallation = true, + }; + + InstallOptionsFactory.SaveForManager(managerOptions, manager); + InstallOptionsFactory.SaveForPackage(new InstallOptions(), package); + + var resolved = InstallOptionsFactory.LoadApplicable(package); + + Assert.Equal( + $@"C:\Apps\{CoreTools.MakeValidFileName(package.Id)}", + resolved.CustomInstallLocation + ); + Assert.True(resolved.InteractiveInstallation); + } + + [Fact] + public void LoadApplicable_AppliesExplicitOverridesAndRemovesDisallowedSecureOptions() + { + var manager = new PackageManagerBuilder().WithName($"Manager{Guid.NewGuid():N}").Build(); + var package = new PackageBuilder().WithManager(manager).WithId($"Pkg{Guid.NewGuid():N}").Build(); + var packageOptions = new InstallOptions + { + OverridesNextLevelOpts = true, + CustomParameters_Install = ["--keep&drop|;<>\n"], + CustomParameters_Update = ["--update"], + CustomParameters_Uninstall = ["--remove"], + PreInstallCommand = "echo pre", + PostInstallCommand = "echo post", + PreUpdateCommand = "echo pre-update", + PostUpdateCommand = "echo post-update", + PreUninstallCommand = "echo pre-uninstall", + PostUninstallCommand = "echo post-uninstall", + }; + + InstallOptionsFactory.SaveForPackage(packageOptions, package); + + var resolved = InstallOptionsFactory.LoadApplicable( + package, + elevated: true, + interactive: true, + no_integrity: true, + remove_data: true + ); + + Assert.True(resolved.RunAsAdministrator); + Assert.True(resolved.InteractiveInstallation); + Assert.True(resolved.SkipHashCheck); + Assert.True(resolved.RemoveDataOnUninstall); + Assert.Empty(resolved.CustomParameters_Install); + Assert.Empty(resolved.CustomParameters_Update); + Assert.Empty(resolved.CustomParameters_Uninstall); + Assert.Equal("", resolved.PreInstallCommand); + Assert.Equal("", resolved.PostInstallCommand); + Assert.Equal("", resolved.PreUpdateCommand); + Assert.Equal("", resolved.PostUpdateCommand); + Assert.Equal("", resolved.PreUninstallCommand); + Assert.Equal("", resolved.PostUninstallCommand); + } + + [Fact] + public void LoadApplicable_SanitizesCustomParametersWhenCliArgumentsAreAllowed() + { + var manager = new PackageManagerBuilder().WithName($"Manager{Guid.NewGuid():N}").Build(); + var package = new PackageBuilder().WithManager(manager).WithId($"Pkg{Guid.NewGuid():N}").Build(); + var packageOptions = new InstallOptions + { + OverridesNextLevelOpts = true, + CustomParameters_Install = ["--keep&drop|;<>\n"], + }; + + SecureSettings.ApplyForUser(Environment.UserName, SecureSettings.ResolveKey(SecureSettings.K.AllowCLIArguments), true); + InstallOptionsFactory.SaveForPackage(packageOptions, package); + + var resolved = InstallOptionsFactory.LoadApplicable(package); + + Assert.Equal(["--keepdrop"], resolved.CustomParameters_Install); + } + + [Fact] + public void SaveAndLoadForPackage_RoundTripsPersistedOptions() + { + var manager = new PackageManagerBuilder().WithName($"Manager{Guid.NewGuid():N}").Build(); + var package = new PackageBuilder().WithManager(manager).WithId($"Pkg{Guid.NewGuid():N}").Build(); + var expected = new InstallOptions + { + OverridesNextLevelOpts = true, + Architecture = "x64", + CustomInstallLocation = @"D:\Tools", + InteractiveInstallation = true, + SkipMinorUpdates = true, + }; + expected.CustomParameters_Install.Add("--quiet"); + + InstallOptionsFactory.SaveForPackage(expected, package); + + var actual = InstallOptionsFactory.LoadForPackage(package); + + Assert.True(actual.OverridesNextLevelOpts); + Assert.Equal("x64", actual.Architecture); + Assert.Equal(@"D:\Tools", actual.CustomInstallLocation); + Assert.True(actual.InteractiveInstallation); + Assert.True(actual.SkipMinorUpdates); + Assert.Equal(["--quiet"], actual.CustomParameters_Install); + } +} diff --git a/src/UniGetUI.PackageEngine.Tests/NpmManagerTests.cs b/src/UniGetUI.PackageEngine.Tests/NpmManagerTests.cs new file mode 100644 index 0000000..f47e37d --- /dev/null +++ b/src/UniGetUI.PackageEngine.Tests/NpmManagerTests.cs @@ -0,0 +1,293 @@ +using UniGetUI.PackageEngine.Enums; +using UniGetUI.PackageEngine.Managers.NpmManager; +using UniGetUI.PackageEngine.Serializable; +using UniGetUI.PackageEngine.Structs; +using UniGetUI.PackageEngine.Tests.Infrastructure.Assertions; +using UniGetUI.PackageEngine.Tests.Infrastructure.Builders; +using UniGetUI.PackageEngine.Tests.Infrastructure.Helpers; + +namespace UniGetUI.PackageEngine.Tests; + +public sealed class NpmManagerTests +{ + [Fact] + public void ParseSearchOutputParsesJsonArrayAfterWarningPrefix() + { + var manager = new Npm(); + + var packages = Npm.ParseSearchOutput( + File.ReadAllText(PackageEngineFixtureFiles.GetPath(Path.Combine("Npm", "search-array-with-warning.txt"))), + manager.DefaultSource, + manager + ); + + var packageList = packages.ToArray(); + Assert.Equal(2, packageList.Length); + PackageAssert.BelongsTo(packageList[0], manager, manager.DefaultSource); + Assert.Equal("left-pad", packageList[0].Id); + Assert.Equal("1.3.0", packageList[0].VersionString); + PackageAssert.BelongsTo(packageList[1], manager, manager.DefaultSource); + Assert.Equal("@types/node", packageList[1].Id); + Assert.Equal("24.0.0", packageList[1].VersionString); + } + + [Fact] + public void ParseSearchOutputFallsBackToNdjsonAndSkipsInvalidEntries() + { + var manager = new Npm(); + + var packages = Npm.ParseSearchOutput( + File.ReadAllText(PackageEngineFixtureFiles.GetPath(Path.Combine("Npm", "search-ndjson.txt"))), + manager.DefaultSource, + manager + ); + + var packageList = packages.ToArray(); + Assert.Equal(2, packageList.Length); + Assert.Equal("chalk", packageList[0].Id); + Assert.Equal("5.4.1", packageList[0].VersionString); + Assert.Equal("npm-check-updates", packageList[1].Id); + Assert.Equal("17.1.1", packageList[1].VersionString); + } + + [Fact] + public void ParseAvailableUpdatesOutputCreatesPackagesWithRequestedScope() + { + var manager = new Npm(); + + var packages = Npm.ParseAvailableUpdatesOutput( + File.ReadAllText(PackageEngineFixtureFiles.GetPath(Path.Combine("Npm", "outdated.json"))), + manager.DefaultSource, + manager, + new OverridenInstallationOptions(PackageScope.Global) + ); + + var package = Assert.Single(packages); + PackageAssert.BelongsTo(package, manager, manager.DefaultSource); + Assert.Equal("npm", package.Id); + Assert.Equal("10.9.0", package.VersionString); + Assert.Equal("11.0.0", package.NewVersionString); + Assert.Equal(PackageScope.Global, package.OverridenOptions.Scope); + } + + [Fact] + public void ParseInstalledPackagesOutputCreatesPackagesWithRequestedScope() + { + var manager = new Npm(); + + var packages = Npm.ParseInstalledPackagesOutput( + File.ReadAllText(PackageEngineFixtureFiles.GetPath(Path.Combine("Npm", "installed.json"))), + manager.DefaultSource, + manager, + new OverridenInstallationOptions(PackageScope.Local) + ); + + var package = Assert.Single(packages); + PackageAssert.BelongsTo(package, manager, manager.DefaultSource); + Assert.Equal("rimraf", package.Id); + Assert.Equal("6.0.1", package.VersionString); + Assert.Equal(PackageScope.Local, package.OverridenOptions.Scope); + } + + [Fact] + public void OperationHelperBuildsInstallParametersFromOptions() + { + var manager = new Npm(); + var package = new PackageBuilder() + .WithManager(manager) + .WithId("contoso-tool") + .WithVersion("1.0.0") + .Build(); + var options = new InstallOptions + { + Version = "2.0.0", + InstallationScope = PackageScope.Global, + PreRelease = true, + }; + options.CustomParameters_Install.Add("--foreground-scripts"); + + var parameters = manager.OperationHelper.GetParameters(package, options, OperationType.Install); + + Assert.Equal( + [ + "install", + OperatingSystem.IsWindows() ? "'contoso-tool@2.0.0'" : "contoso-tool@2.0.0", + "--global", + "--include", + "dev", + "--foreground-scripts", + ], + parameters + ); + } + + [Fact] + public void OperationHelperLetsPackageScopeOverrideUpdateScope() + { + var manager = new Npm(); + var package = new PackageBuilder() + .WithManager(manager) + .WithId("contoso-tool") + .WithVersion("1.0.0") + .WithNewVersion("3.0.0") + .WithOptions(new OverridenInstallationOptions(PackageScope.Global)) + .Build(); + var options = new InstallOptions + { + InstallationScope = PackageScope.Local, + }; + options.CustomParameters_Update.Add("--audit"); + + var parameters = manager.OperationHelper.GetParameters(package, options, OperationType.Update); + + Assert.Equal( + [ + "install", + OperatingSystem.IsWindows() ? "'contoso-tool@3.0.0'" : "contoso-tool@3.0.0", + "--global", + "--audit", + ], + parameters + ); + } + + [Fact] + public void OperationHelperReconstructsAliasSyntaxForUpdate() + { + // `npm outdated --json` reports npm-aliased dependencies (package.json entries like + // "eslint-v9": "npm:eslint@^9.39.4") with this exact "localName:targetName@targetRange" + // shape as the package id -- see Npm.ParseAvailableUpdatesOutput. + var manager = new Npm(); + var package = new PackageBuilder() + .WithManager(manager) + .WithId("eslint-v9:eslint@^9.39.4") + .WithVersion("9.39.4") + .WithNewVersion("10.6.0") + .Build(); + var options = new InstallOptions(); + + var parameters = manager.OperationHelper.GetParameters(package, options, OperationType.Update); + + Assert.Equal( + [ + "install", + OperatingSystem.IsWindows() + ? "'eslint-v9@npm:eslint@10.6.0'" + : "eslint-v9@npm:eslint@10.6.0", + ], + parameters + ); + } + + [Fact] + public void OperationHelperReconstructsAliasSyntaxForScopedTarget() + { + // The alias target itself can be scoped (e.g. "npm:@babel/core@^7.20.0"), which contains + // its own '@'. Splitting on the *last* '@' must still separate the scoped target name + // from the version, not the scope prefix from the rest of the name. + var manager = new Npm(); + var package = new PackageBuilder() + .WithManager(manager) + .WithId("babel-core-legacy:@babel/core@^7.20.0") + .WithVersion("7.20.0") + .WithNewVersion("7.28.0") + .Build(); + var options = new InstallOptions(); + + var parameters = manager.OperationHelper.GetParameters(package, options, OperationType.Update); + + Assert.Equal( + [ + "install", + OperatingSystem.IsWindows() + ? "'babel-core-legacy@npm:@babel/core@7.28.0'" + : "babel-core-legacy@npm:@babel/core@7.28.0", + ], + parameters + ); + } + + [Fact] + public void OperationHelperUsesLocalNameForAliasUninstall() + { + var manager = new Npm(); + var package = new PackageBuilder() + .WithManager(manager) + .WithId("eslint-v9:eslint@^9.39.4") + .WithVersion("9.39.4") + .Build(); + var options = new InstallOptions(); + + var parameters = manager.OperationHelper.GetParameters(package, options, OperationType.Uninstall); + + Assert.Equal(["uninstall", "eslint-v9"], parameters); + } + + [Fact] + public void OperationHelperLeavesOrdinaryPackageIdsUntouched() + { + // Sanity check: ordinary (non-aliased) package ids never contain a colon, so the alias + // path must not be reachable for them. + var manager = new Npm(); + var package = new PackageBuilder() + .WithManager(manager) + .WithId("contoso-tool") + .WithVersion("1.0.0") + .WithNewVersion("2.0.0") + .Build(); + var options = new InstallOptions(); + + var parameters = manager.OperationHelper.GetParameters(package, options, OperationType.Update); + + Assert.Equal( + ["install", OperatingSystem.IsWindows() ? "'contoso-tool@2.0.0'" : "contoso-tool@2.0.0"], + parameters + ); + } + + [Fact] + public void DetailsHelperUsesAliasLocalNameForInstallLocation() + { + var manager = new Npm(); + var package = new PackageBuilder() + .WithManager(manager) + .WithId("eslint-v9:eslint@^9.39.4") + .WithVersion("9.39.4") + .WithOptions(new OverridenInstallationOptions(PackageScope.Local)) + .Build(); + string expectedLocation = Path.Combine( + Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), + "node_modules", + "eslint-v9" + ); + bool existed = Directory.Exists(expectedLocation); + Directory.CreateDirectory(expectedLocation); + + try + { + var location = manager.DetailsHelper.GetInstallLocation(package); + + Assert.Equal(expectedLocation, location); + } + finally + { + if (!existed) + { + Directory.Delete(expectedLocation, recursive: true); + } + } + } + + [Fact] + public void OperationHelperReturnsSuccessOnlyForZeroExitCode() + { + var manager = new Npm(); + var package = new PackageBuilder().WithManager(manager).Build(); + + var success = manager.OperationHelper.GetResult(package, OperationType.Install, [], 0); + var failure = manager.OperationHelper.GetResult(package, OperationType.Install, [], 1); + + Assert.Equal(OperationVeredict.Success, success); + Assert.Equal(OperationVeredict.Failure, failure); + } +} diff --git a/src/UniGetUI.PackageEngine.Tests/NpmPackageIdentifierTests.cs b/src/UniGetUI.PackageEngine.Tests/NpmPackageIdentifierTests.cs new file mode 100644 index 0000000..c9db8ab --- /dev/null +++ b/src/UniGetUI.PackageEngine.Tests/NpmPackageIdentifierTests.cs @@ -0,0 +1,45 @@ +using UniGetUI.PackageEngine.Managers.NpmManager; + +namespace UniGetUI.PackageEngine.Tests; + +public sealed class NpmPackageIdentifierTests +{ + [Fact] + public void ParseSeparatesAliasComponents() + { + var identifier = NpmPackageIdentifier.Parse("eslint-v9:eslint@^9.39.4"); + + Assert.True(identifier.IsAlias); + Assert.Equal("eslint-v9", identifier.LocalName); + Assert.Equal("eslint", identifier.TargetName); + Assert.Equal("eslint-v9@npm:eslint@10.6.0", identifier.GetInstallSpec("10.6.0")); + Assert.Equal("eslint", identifier.GetRegistryName()); + Assert.Equal("eslint-v9", identifier.GetInstallLocationName()); + } + + [Fact] + public void ParseHandlesScopedAliasTargets() + { + var identifier = NpmPackageIdentifier.Parse("babel-core-legacy:@babel/core@^7.20.0"); + + Assert.True(identifier.IsAlias); + Assert.Equal("babel-core-legacy", identifier.LocalName); + Assert.Equal("@babel/core", identifier.TargetName); + Assert.Equal("babel-core-legacy@npm:@babel/core@7.28.0", identifier.GetInstallSpec("7.28.0")); + Assert.Equal("@babel/core", identifier.GetRegistryName()); + Assert.Equal("babel-core-legacy", identifier.GetInstallLocationName()); + } + + [Fact] + public void ParseLeavesOrdinaryNamesUntouched() + { + var identifier = NpmPackageIdentifier.Parse("contoso-tool"); + + Assert.False(identifier.IsAlias); + Assert.Equal("contoso-tool", identifier.LocalName); + Assert.Equal("contoso-tool", identifier.TargetName); + Assert.Equal("contoso-tool@2.0.0", identifier.GetInstallSpec("2.0.0")); + Assert.Equal("contoso-tool", identifier.GetRegistryName()); + Assert.Equal("contoso-tool", identifier.GetInstallLocationName()); + } +} diff --git a/src/UniGetUI.PackageEngine.Tests/NuGetManifestLoaderTests.cs b/src/UniGetUI.PackageEngine.Tests/NuGetManifestLoaderTests.cs new file mode 100644 index 0000000..383baf2 --- /dev/null +++ b/src/UniGetUI.PackageEngine.Tests/NuGetManifestLoaderTests.cs @@ -0,0 +1,84 @@ +using UniGetUI.PackageEngine.Managers.Generic.NuGet; +using UniGetUI.PackageEngine.Managers.Generic.NuGet.Internal; +using UniGetUI.PackageEngine.Managers.PowerShellManager; +using UniGetUI.PackageEngine.Tests.Infrastructure.Builders; +using UniGetUI.PackageEngine.Tests.Infrastructure.Helpers; + +namespace UniGetUI.PackageEngine.Tests; + +public sealed class NuGetManifestLoaderTests +{ + [Fact] + public void GetManifestUrlAndNuPkgUrl_UsePackageSourceAndVersion() + { + var manager = new PackageManagerBuilder().Build(); + var source = new SourceBuilder() + .WithManager(manager) + .WithUrl("https://packages.example.test/feed") + .Build(); + var package = new PackageBuilder() + .WithManager(manager) + .WithSource(source) + .WithId("Contoso.Tool") + .WithVersion("1.2.3") + .Build(); + + Assert.Equal( + "https://packages.example.test/feed/Packages(Id='Contoso.Tool',Version='1.2.3')", + NuGetManifestLoader.GetManifestUrl(package).ToString() + ); + Assert.Equal( + "https://packages.example.test/feed/package/Contoso.Tool/1.2.3", + NuGetManifestLoader.GetNuPkgUrl(package).ToString() + ); + } + + [Fact] + public void GetManifestContent_UsesCachedManifestWhenAvailable() + { + BaseNuGet.Manifests.Clear(); + var manager = new PackageManagerBuilder().Build(); + var package = new PackageBuilder().WithManager(manager).WithId("Contoso.Tool").Build(); + BaseNuGet.Manifests[package.GetHash()] = ""; + + Assert.Equal("", NuGetManifestLoader.GetManifestContent(package)); + } + + [Fact] + public void GetManifestContent_FallsBackWhenTrailingZeroVersionReturnsNotFound() + { + BaseNuGet.Manifests.Clear(); + using var server = new TestHttpServer(request => + { + string rawUrl = request.RawUrl ?? string.Empty; + return rawUrl switch + { + string value when value.Contains("Version='1.0.0'") || value.Contains("Version=%271.0.0%27") + => (404, string.Empty, "application/xml"), + string value when value.Contains("Version='1.0'") || value.Contains("Version=%271.0%27") + => (200, "manifest", "application/xml"), + _ => (500, string.Empty, "text/plain"), + }; + }); + var manager = new PackageManagerBuilder().Build(); + var source = new SourceBuilder() + .WithManager(manager) + .WithUrl(server.BaseUri.AbsoluteUri.TrimEnd('/')) + .Build(); + var package = new PackageBuilder() + .WithManager(manager) + .WithSource(source) + .WithId("Contoso.Tool") + .WithVersion("1.0.0") + .Build(); + + var manifest = NuGetManifestLoader.GetManifestContent(package); + + Assert.Equal("manifest", manifest); + Assert.Equal(2, server.RequestPaths.Count); + Assert.Contains("1.0.0", server.RequestPaths[0]); + Assert.True( + server.RequestPaths[1].Contains("Version='1.0'") || server.RequestPaths[1].Contains("Version=%271.0%27") + ); + } +} diff --git a/src/UniGetUI.PackageEngine.Tests/PackageLoaderPipelineTests.cs b/src/UniGetUI.PackageEngine.Tests/PackageLoaderPipelineTests.cs new file mode 100644 index 0000000..658ad8a --- /dev/null +++ b/src/UniGetUI.PackageEngine.Tests/PackageLoaderPipelineTests.cs @@ -0,0 +1,191 @@ +using UniGetUI.PackageEngine.Interfaces; +using UniGetUI.PackageEngine.Tests.Infrastructure.Builders; +using UniGetUI.PackageEngine.Tests.Infrastructure.Fakes; +using UniGetUI.PackageEngine.Tests.Infrastructure.Helpers; + +namespace UniGetUI.PackageEngine.Tests; + +public sealed class PackageLoaderPipelineTests +{ + [Fact] + public async Task AddForeign_DeduplicatesByPackageHash_WhenVersionAwareIdentityIsDisabled() + { + var manager = new PackageManagerBuilder().Build(); + var loader = new TestPackageLoader([manager], allowMultiplePackageVersions: false); + var packageV1 = new PackageBuilder() + .WithManager(manager) + .WithId("Contoso.Tool") + .WithVersion("1.0.0") + .Build(); + var packageV2 = new PackageBuilder() + .WithManager(manager) + .WithId("Contoso.Tool") + .WithVersion("2.0.0") + .Build(); + + await loader.AddForeign(packageV1); + await loader.AddForeign(packageV2); + + Assert.Equal(1, loader.Count()); + Assert.True(loader.Contains(packageV1)); + Assert.True(loader.Contains(packageV2)); + Assert.Same(packageV1, loader.GetEquivalentPackage(packageV2)); + Assert.Single(loader.GetEquivalentPackages(packageV1)); + } + + [Fact] + public async Task AddForeign_KeepsDistinctVersions_WhenVersionAwareIdentityIsEnabled() + { + var manager = new PackageManagerBuilder().Build(); + var loader = new TestPackageLoader([manager], allowMultiplePackageVersions: true); + var packageV1 = new PackageBuilder() + .WithManager(manager) + .WithId("Contoso.Tool") + .WithVersion("1.0.0") + .Build(); + var packageV2 = new PackageBuilder() + .WithManager(manager) + .WithId("Contoso.Tool") + .WithVersion("2.0.0") + .Build(); + + await loader.AddForeign(packageV1); + await loader.AddForeign(packageV2); + + Assert.Equal(2, loader.Count()); + Assert.Same(packageV1, loader.GetEquivalentPackage(packageV1)); + Assert.Same(packageV2, loader.GetEquivalentPackage(packageV2)); + Assert.Equal( + ["1.0.0", "2.0.0"], + loader.GetEquivalentPackages(packageV1).Select(package => package.VersionString).Order() + ); + } + + [Fact] + public async Task LookupAndRemovalApisUseLoaderIdentityAndSourceFiltering() + { + var manager = new PackageManagerBuilder() + .WithSources(testManager => + [ + new SourceBuilder() + .WithManager(testManager) + .WithName("stable") + .WithUrl("https://example.test/stable") + .Build(), + new SourceBuilder() + .WithManager(testManager) + .WithName("beta") + .WithUrl("https://example.test/beta") + .Build(), + ]) + .Build(); + var stableSource = manager.SourcesHelper.GetSources().Single(source => source.Name == "stable"); + var betaSource = manager.SourcesHelper.GetSources().Single(source => source.Name == "beta"); + var loader = new TestPackageLoader([manager]); + var uniquePackage = new PackageBuilder() + .WithManager(manager) + .WithSource(stableSource) + .WithId("Contoso.Unique") + .Build(); + var stablePackage = new PackageBuilder() + .WithManager(manager) + .WithSource(stableSource) + .WithId("Contoso.Shared") + .Build(); + var betaPackage = new PackageBuilder() + .WithManager(manager) + .WithSource(betaSource) + .WithId("Contoso.Shared") + .Build(); + var recorder = new LoaderEventRecorder(loader); + + await loader.AddForeign(uniquePackage); + await loader.AddForeign(stablePackage); + await loader.AddForeign(betaPackage); + loader.Remove(betaPackage); + + Assert.True(loader.Contains(stablePackage)); + Assert.False(loader.Contains(betaPackage)); + Assert.Same(uniquePackage, loader.GetPackageForId("Contoso.Unique")); + Assert.Same(stablePackage, loader.GetPackageForId("Contoso.Shared", "stable")); + Assert.Null(loader.GetPackageForId("Contoso.Shared", "beta")); + Assert.Single(loader.GetEquivalentPackages(stablePackage)); + Assert.Null(loader.GetEquivalentPackage(betaPackage)); + Assert.Contains(recorder.RemovedPackages, package => package.Id == "Contoso.Shared"); + } + + [Fact] + public async Task ClearPackagesAndStopLoading_EmitExpectedEvents() + { + var manager = new PackageManagerBuilder().Build(); + var loader = new TestPackageLoader([manager]); + var recorder = new LoaderEventRecorder(loader); + var package = new PackageBuilder().WithManager(manager).WithId("Contoso.Tool").Build(); + + await loader.AddForeign(package); + loader.StopLoading(emitFinishSignal: false); + loader.ClearPackages(); + + Assert.Equal(0, loader.Count()); + Assert.Equal(1, recorder.FinishedLoadingCount); + Assert.Equal(2, recorder.Changes.Count); + Assert.False(recorder.Changes[1].ProceduralChange); + Assert.Empty(recorder.Changes[1].AddedPackages); + Assert.Empty(recorder.Changes[1].RemovedPackages); + } + + [Fact] + public async Task ReloadPackages_ClearsExistingPackages_FiltersInvalidOnes_AndRaisesLifecycleEvents() + { + var manager = new PackageManagerBuilder() + .WithInstalledPackages(testManager => + [ + new PackageBuilder() + .WithManager(testManager) + .WithId("Contoso.Accepted") + .WithVersion("1.0.0") + .Build(), + new PackageBuilder() + .WithManager(testManager) + .WithId("Contoso.Accepted") + .WithVersion("1.0.0") + .Build(), + new PackageBuilder() + .WithManager(testManager) + .WithId("Contoso.Rejected") + .WithVersion("1.0.0") + .Build(), + ]) + .Build(); + var loader = new TestPackageLoader( + [manager], + loadPackages: testManager => testManager.GetInstalledPackages(), + isPackageValid: package => Task.FromResult(package.Id != "Contoso.Rejected") + ); + var stalePackage = new PackageBuilder() + .WithManager(manager) + .WithId("Contoso.Stale") + .WithVersion("0.9.0") + .Build(); + var recorder = new LoaderEventRecorder(loader); + + await loader.AddForeign(stalePackage); + await loader.ReloadPackages(); + + var changeEvents = recorder.Changes.Skip(1).ToArray(); + + Assert.True(recorder.StartedLoading); + Assert.True(recorder.FinishedLoading); + Assert.Equal(1, recorder.StartedLoadingCount); + Assert.Equal(1, recorder.FinishedLoadingCount); + Assert.True(loader.IsLoaded); + Assert.False(loader.IsLoading); + Assert.Equal(["Contoso.Accepted"], loader.Packages.Select(package => package.Id).Distinct()); + Assert.Single(loader.Packages); + Assert.Equal(2, changeEvents.Length); + Assert.False(changeEvents[0].ProceduralChange); + Assert.Empty(changeEvents[0].AddedPackages); + Assert.True(changeEvents[1].ProceduralChange); + Assert.Equal(["Contoso.Accepted"], changeEvents[1].AddedPackages.Select(package => package.Id).Distinct()); + } +} diff --git a/src/UniGetUI.PackageEngine.Tests/PackageManagerTests.cs b/src/UniGetUI.PackageEngine.Tests/PackageManagerTests.cs new file mode 100644 index 0000000..0aab8e4 --- /dev/null +++ b/src/UniGetUI.PackageEngine.Tests/PackageManagerTests.cs @@ -0,0 +1,349 @@ +using UniGetUI.Core.Data; +using UniGetUI.Core.SettingsEngine; +using UniGetUI.Core.SettingsEngine.SecureSettings; +using UniGetUI.Core.Tools; +using UniGetUI.PackageEngine.PackageClasses; +using UniGetUI.PackageEngine.Tests.Infrastructure.Builders; +using UniGetUI.PackageEngine.Tests.Infrastructure.Fakes; + +namespace UniGetUI.PackageEngine.Tests; + +public sealed class PackageManagerTests : IDisposable +{ + private readonly string _testRoot; + + public PackageManagerTests() + { + _testRoot = Path.Combine( + AppContext.BaseDirectory, + nameof(PackageManagerTests), + Guid.NewGuid().ToString("N") + ); + var secureSettingsRoot = Path.Combine(_testRoot, "SecureSettings"); + + CoreData.TEST_DataDirectoryOverride = Path.Combine(_testRoot, "Data"); + SecureSettings.TEST_SecureSettingsRootOverride = secureSettingsRoot; + + Directory.CreateDirectory(CoreData.UniGetUIUserConfigurationDirectory); + Directory.CreateDirectory(secureSettingsRoot); + + Settings.ResetSettings(); + Settings.SetDictionary(Settings.K.DisabledManagers, new Dictionary()); + Settings.SetDictionary(Settings.K.ManagerPaths, new Dictionary()); + SecureSettings.ApplyForUser( + Environment.UserName, + SecureSettings.ResolveKey(SecureSettings.K.AllowCustomManagerPaths), + false + ); + } + + public void Dispose() + { + Settings.SetDictionary(Settings.K.DisabledManagers, new Dictionary()); + Settings.SetDictionary(Settings.K.ManagerPaths, new Dictionary()); + SecureSettings.ApplyForUser( + Environment.UserName, + SecureSettings.ResolveKey(SecureSettings.K.AllowCustomManagerPaths), + false + ); + + CoreData.TEST_DataDirectoryOverride = null; + SecureSettings.TEST_SecureSettingsRootOverride = null; + + if (Directory.Exists(_testRoot)) + { + Directory.Delete(_testRoot, true); + } + } + + [Fact] + public void InitializeDisabledManagerSkipsLoadingAndStaysNotReady() + { + var manager = CreateManager(); + Settings.SetDictionaryItem(Settings.K.DisabledManagers, manager.Name, true); + + manager.Initialize(); + + Assert.False(manager.IsEnabled()); + Assert.False(manager.IsReady()); + Assert.False(manager.Status.Found); + Assert.Equal(string.Empty, manager.Status.ExecutablePath); + Assert.Equal( + CoreTools.Translate("{0} is disabled", manager.DisplayName), + manager.Status.Version + ); + } + + [Fact] + public void InitializeEnabledManagerWithoutExecutableStaysNotReady() + { + var manager = CreateManager(); + manager.ExecutableFound = false; + manager.ExecutablePath = CreateExecutable("missing-manager.exe"); + + manager.Initialize(); + + Assert.True(manager.IsEnabled()); + Assert.False(manager.IsReady()); + Assert.False(manager.Status.Found); + Assert.Equal(manager.ExecutablePath, manager.Status.ExecutablePath); + Assert.Equal( + CoreTools.Translate("{pm} was not found!").Replace("{pm}", manager.DisplayName).Trim('!'), + manager.Status.Version + ); + } + + [Fact] + public void InitializeEnabledManagerWithExecutableBecomesReady() + { + var manager = CreateManager(); + manager.ExecutablePath = CreateExecutable("ready-manager.exe"); + manager.LoadedVersion = "9.9.9-test"; + + manager.Initialize(); + + Assert.True(manager.IsEnabled()); + Assert.True(manager.IsReady()); + Assert.True(manager.Status.Found); + Assert.Equal(manager.ExecutablePath, manager.Status.ExecutablePath); + Assert.Equal("9.9.9-test", manager.Status.Version); + } + + [Fact] + public void IsReadyTracksEnablementChangesAfterInitialization() + { + var manager = CreateManager(); + manager.ExecutablePath = CreateExecutable("toggle-manager.exe"); + + Assert.True(manager.IsEnabled()); + Assert.False(manager.IsReady()); + + manager.Initialize(); + + Assert.True(manager.IsReady()); + + Settings.SetDictionaryItem(Settings.K.DisabledManagers, manager.Name, true); + + Assert.False(manager.IsEnabled()); + Assert.False(manager.IsReady()); + + Settings.SetDictionaryItem(Settings.K.DisabledManagers, manager.Name, false); + + Assert.True(manager.IsEnabled()); + Assert.True(manager.IsReady()); + } + + [Fact] + public void GetExecutableFileReturnsFalseWhenNoCandidatesExist() + { + var manager = CreateManager(); + manager.SetCandidateExecutableFiles(); + + var executable = manager.GetExecutableFile(); + + Assert.False(executable.Item1); + Assert.Equal(string.Empty, executable.Item2); + } + + [Fact] + public void GetExecutableFileUsesSavedPathWhenNoCandidatesExistAndCustomPathsAreEnabled() + { + var manager = CreateManager(); + var customPath = CreateExecutable("custom-only.exe"); + manager.SetCandidateExecutableFiles(); + EnableCustomManagerPaths(); + Settings.SetDictionaryItem(Settings.K.ManagerPaths, manager.Name, customPath); + + var executable = manager.GetExecutableFile(); + + Assert.True(executable.Item1); + Assert.Equal(customPath, executable.Item2); + } + + [Fact] + public void GetExecutableFileIgnoresSavedPathWhenCustomPathsAreDisabled() + { + var manager = CreateManager(); + var first = CreateExecutable("candidate-a.exe"); + var second = CreateExecutable("candidate-b.exe"); + manager.SetCandidateExecutableFiles(first, second); + Settings.SetDictionaryItem(Settings.K.ManagerPaths, manager.Name, second); + + var executable = manager.GetExecutableFile(); + + Assert.True(executable.Item1); + Assert.Equal(first, executable.Item2); + } + + [Fact] + public void GetExecutableFileUsesSavedCandidateWhenCustomPathsAreEnabled() + { + var manager = CreateManager(); + var first = CreateExecutable("enabled-a.exe"); + var second = CreateExecutable("enabled-b.exe"); + manager.SetCandidateExecutableFiles(first, second); + EnableCustomManagerPaths(); + Settings.SetDictionaryItem(Settings.K.ManagerPaths, manager.Name, second); + + var executable = manager.GetExecutableFile(); + + Assert.True(executable.Item1); + Assert.Equal(second, executable.Item2); + } + + [Fact] + public void GetExecutableFileFallsBackWhenSavedPathDoesNotExist() + { + var manager = CreateManager(); + var first = CreateExecutable("fallback-a.exe"); + var second = CreateExecutable("fallback-b.exe"); + manager.SetCandidateExecutableFiles(first, second); + EnableCustomManagerPaths(); + Settings.SetDictionaryItem( + Settings.K.ManagerPaths, + manager.Name, + Path.Combine(_testRoot, "missing.exe") + ); + + var executable = manager.GetExecutableFile(); + + Assert.True(executable.Item1); + Assert.Equal(first, executable.Item2); + } + + [Fact] + public void GetExecutableFileUsesSavedPathWhenSavedPathIsNotACandidate() + { + var manager = CreateManager(); + var first = CreateExecutable("outside-a.exe"); + var second = CreateExecutable("outside-b.exe"); + var outsideCandidateList = CreateExecutable("outside-c.exe"); + manager.SetCandidateExecutableFiles(first, second); + EnableCustomManagerPaths(); + Settings.SetDictionaryItem( + Settings.K.ManagerPaths, + manager.Name, + outsideCandidateList + ); + + var executable = manager.GetExecutableFile(); + + Assert.True(executable.Item1); + Assert.Equal(outsideCandidateList, executable.Item2); + } + + [Fact] + public void FindPackagesReturnsEmptyWhenManagerIsNotReady() + { + var manager = CreateManager(); + + var packages = manager.FindPackages("tool"); + + Assert.Empty(packages); + Assert.Null(manager.LastQuery); + Assert.Equal(0, manager.AttemptFastRepairCalls); + } + + [Fact] + public void FindPackagesRetriesOnceAfterFailure() + { + var manager = CreateReadyManager(); + var attempts = 0; + manager.SetFindPackages(query => + { + attempts++; + return attempts == 1 + ? throw new InvalidOperationException("search failed") + : [CreatePackage(manager, "Contoso.Search", "Contoso Search")]; + }); + + var packages = manager.FindPackages("Contoso"); + + var package = Assert.Single(packages); + Assert.Equal("Contoso.Search", package.Id); + Assert.Equal("Contoso", manager.LastQuery); + Assert.Equal(1, manager.AttemptFastRepairCalls); + } + + [Fact] + public void GetAvailableUpdatesRetriesOnceAndRefreshesIndexesPerAttempt() + { + var manager = CreateReadyManager(); + var attempts = 0; + manager.SetAvailableUpdates(() => + { + attempts++; + return attempts == 1 + ? throw new InvalidOperationException("updates failed") + : [CreatePackage(manager, "Contoso.Update", "Contoso Update", "1.0.0", "2.0.0")]; + }); + + var packages = manager.GetAvailableUpdates(); + + var package = Assert.Single(packages); + Assert.Equal("Contoso.Update", package.Id); + Assert.Equal(1, manager.AttemptFastRepairCalls); + Assert.Equal(2, manager.RefreshPackageIndexesCalls); + } + + [Fact] + public void GetInstalledPackagesReturnsEmptyAfterSecondFailure() + { + var manager = CreateReadyManager(); + manager.SetInstalledPackages(() => throw new InvalidOperationException("installed failed")); + + var packages = manager.GetInstalledPackages(); + + Assert.Empty(packages); + Assert.Equal(1, manager.AttemptFastRepairCalls); + } + + private static TestPackageManager CreateManager() + { + return new PackageManagerBuilder() + .WithName($"TestManager-{Guid.NewGuid():N}") + .WithDisplayName("Test Manager") + .Build(initialize: false); + } + + private TestPackageManager CreateReadyManager() + { + var manager = CreateManager(); + manager.ExecutablePath = CreateExecutable($"{manager.Name}.exe"); + manager.Initialize(); + Assert.True(manager.IsReady()); + return manager; + } + + private static void EnableCustomManagerPaths() + { + Assert.Equal( + 0, + SecureSettings.ApplyForUser( + Environment.UserName, + SecureSettings.ResolveKey(SecureSettings.K.AllowCustomManagerPaths), + true + ) + ); + } + + private string CreateExecutable(string fileName) + { + var path = Path.Combine(_testRoot, "Executables", fileName); + Directory.CreateDirectory(Path.GetDirectoryName(path)!); + File.WriteAllText(path, string.Empty); + return path; + } + + private static Package CreatePackage( + TestPackageManager manager, + string id, + string name, + string version = "1.0.0", + string? newVersion = null + ) + { + var builder = new PackageBuilder().WithManager(manager).WithId(id).WithName(name).WithVersion(version); + return newVersion is null ? builder.Build() : builder.WithNewVersion(newVersion).Build(); + } +} diff --git a/src/UniGetUI.PackageEngine.Tests/PackageOperationsTests.cs b/src/UniGetUI.PackageEngine.Tests/PackageOperationsTests.cs new file mode 100644 index 0000000..bb68cac --- /dev/null +++ b/src/UniGetUI.PackageEngine.Tests/PackageOperationsTests.cs @@ -0,0 +1,904 @@ +using System.Diagnostics; +using System.Reflection; +using UniGetUI.Core.Logging; +using UniGetUI.Core.Tools; +using UniGetUI.Interface.Enums; +using UniGetUI.PackageEngine.Enums; +using UniGetUI.PackageEngine.Interfaces; +using UniGetUI.PackageEngine.Operations; +using UniGetUI.PackageEngine.PackageClasses; +using UniGetUI.PackageEngine.PackageLoader; +using UniGetUI.PackageEngine.Serializable; +using UniGetUI.PackageEngine.Structs; +using UniGetUI.PackageEngine.Tests.Infrastructure.Builders; +using UniGetUI.PackageEngine.Tests.Infrastructure.Fakes; +using UniGetUI.PackageOperations; + +namespace UniGetUI.PackageEngine.Tests; + +[CollectionDefinition(nameof(OperationOrchestrationTestCollection), DisableParallelization = true)] +public sealed class OperationOrchestrationTestCollection; + +[Collection(nameof(OperationOrchestrationTestCollection))] +public sealed class PackageOperationsTests +{ + [Fact] + public void RetryModesMutateInstallOptionsAndMetadata() + { + var package = CreatePackage(); + var options = new InstallOptions(); + var operation = new InspectableInstallPackageOperation(package, options); + + operation.Retry(AbstractOperation.RetryMode.Retry_AsAdmin); + operation.Retry(AbstractOperation.RetryMode.Retry_Interactive); + operation.Retry(AbstractOperation.RetryMode.Retry_SkipIntegrity); + + Assert.True(options.RunAsAdministrator); + Assert.True(options.InteractiveInstallation); + Assert.True(options.SkipHashCheck); + Assert.Contains("Retried package operation", operation.Metadata.OperationInformation); + Assert.Contains(package.Id, operation.Metadata.OperationInformation); + Assert.Throws(() => operation.Retry("InvalidRetryMode")); + } + + [Fact] + public void InstallOperationBuildsPrerequisitesKillListAndPreCommand() + { + var package = CreatePackage(); + var options = new InstallOptions + { + PreInstallCommand = "echo before install", + AbortOnPreInstallFail = false, + }; + options.KillBeforeOperation.Add("proc-one"); + options.KillBeforeOperation.Add("proc-two"); + using var prerequisite = new StubOperation(); + using var operation = new InspectableInstallPackageOperation(package, options, req: prerequisite); + + var preOperations = GetInnerOperations(operation, "PreOperations"); + + Assert.Collection( + preOperations, + inner => + { + Assert.Same(prerequisite, inner.Operation); + Assert.True(inner.MustSucceed); + }, + inner => + { + Assert.IsType(inner.Operation); + Assert.False(inner.MustSucceed); + }, + inner => + { + Assert.IsType(inner.Operation); + Assert.False(inner.MustSucceed); + }, + inner => + { + var preCommand = Assert.IsType(inner.Operation); + Assert.False(inner.MustSucceed); + Assert.Contains("echo before install", preCommand.Metadata.Status); + } + ); + } + + [Fact] + public async Task UpdateOperationBuildsPostOperationsForCommandAndPreviousVersions() + { + var manager = CreateManager(); + var package = new PackageBuilder() + .WithManager(manager) + .WithId("Contoso.Tool") + .WithVersion("1.0.0") + .WithNewVersion("3.0.0") + .Build(); + var olderInstalledVersion = new PackageBuilder() + .WithManager(manager) + .WithId("Contoso.Tool") + .WithVersion("2.0.0") + .Build(); + var newerInstalledVersion = new PackageBuilder() + .WithManager(manager) + .WithId("Contoso.Tool") + .WithVersion("3.1.0") + .Build(); + InitializeLoaders(); + await InstalledPackagesLoader.Instance.AddForeign(olderInstalledVersion); + await InstalledPackagesLoader.Instance.AddForeign(newerInstalledVersion); + var options = new InstallOptions + { + PostUpdateCommand = "echo after update", + UninstallPreviousVersionsOnUpdate = true, + }; + + using var operation = new UpdatePackageOperation(package, options); + var postOperations = GetInnerOperations(operation, "PostOperations"); + + Assert.Collection( + postOperations, + inner => + { + var postCommand = Assert.IsType(inner.Operation); + Assert.False(inner.MustSucceed); + Assert.Contains("echo after update", postCommand.Metadata.Status); + }, + inner => + { + var uninstall = Assert.IsType(inner.Operation); + Assert.False(inner.MustSucceed); + Assert.Equal("2.0.0", uninstall.Package.VersionString); + } + ); + Assert.Contains("1.0.0 -> 3.0.0", operation.Metadata.OperationInformation); + } + + [Fact] + public void UninstallOperationBuildsPreAndPostCommandsForUninstallPath() + { + var package = CreatePackage(); + var options = new InstallOptions + { + PreUninstallCommand = "echo before uninstall", + AbortOnPreUninstallFail = false, + PostUninstallCommand = "echo after uninstall", + }; + using var operation = new UninstallPackageOperation(package, options); + + var preOperations = GetInnerOperations(operation, "PreOperations"); + var postOperations = GetInnerOperations(operation, "PostOperations"); + + var preOperation = Assert.Single(preOperations); + var preCommand = Assert.IsType(preOperation.Operation); + Assert.False(preOperation.MustSucceed); + Assert.Contains("echo before uninstall", preCommand.Metadata.Status); + + var postOperation = Assert.Single(postOperations); + var postCommand = Assert.IsType(postOperation.Operation); + Assert.False(postOperation.MustSucceed); + Assert.Contains("echo after uninstall", postCommand.Metadata.Status); + } + + [Fact] + public void InstallOperationPrepareProcessStartInfoUsesManagerCommandLineAndSetsBadges() + { + var manager = new PackageManagerBuilder() + .ConfigureManager(manager => + { + manager.ExecutablePath = "C:\\tools\\pkgmgr.exe"; + manager.ExecutableArguments = "--cli"; + }) + .ConfigureOperation(helper => + helper.ParametersFactory = (package, _, operation) => + [ + operation.ToString().ToLowerInvariant(), + package.Id, + ]) + .Build(); + var package = new PackageBuilder() + .WithManager(manager) + .WithOptions(new OverridenInstallationOptions(scope: PackageScope.Machine)) + .Build(); + var options = new InstallOptions + { + InstallationScope = PackageScope.User, + InteractiveInstallation = true, + SkipHashCheck = true, + }; + using var operation = new InspectableInstallPackageOperation(package, options); + AbstractOperation.BadgeCollection? badges = null; + operation.BadgesChanged += (_, updatedBadges) => badges = updatedBadges; + + var startInfo = operation.PrepareProcessStartInfoForTests(); + + Assert.Equal("C:\\tools\\pkgmgr.exe", startInfo.FileName); + Assert.Equal("--cli install Contoso.Test", startInfo.Arguments.Trim()); + Assert.Equal(PackageTag.OnQueue, package.Tag); + Assert.NotNull(badges); + Assert.Equal(CoreTools.IsAdministrator(), badges!.AsAdministrator); + Assert.True(badges.Interactive); + Assert.True(badges.SkipHashCheck); + Assert.Equal(PackageScope.Machine, badges.Scope); + } + + [Fact] + public async Task InstallOperationSuccessfulRunSetsPackageTagAndAddsInstalledCopy() + { + var package = CreatePackage(); + InitializeLoaders(); + using var operation = new SimulatedInstallPackageOperation( + package, + new InstallOptions(), + OperationVeredict.Success + ); + + await operation.MainThread(); + await WaitForAsync(() => InstalledPackagesLoader.Instance.GetEquivalentPackage(package) is not null); + + Assert.Equal(PackageTag.AlreadyInstalled, package.Tag); + Assert.NotNull(InstalledPackagesLoader.Instance.GetEquivalentPackage(package)); + } + + [Fact] + public async Task InstallOperationSuccessfulRunPrefersAuthoritativeInstalledVersion() + { + TestPackageManager? manager = null; + Package? installedPackage = null; + manager = new PackageManagerBuilder() + .WithInstalledPackages(_ => [Assert.IsType(installedPackage)]) + .Build(); + var searchResult = new PackageBuilder() + .WithManager(manager) + .WithId("dotnetsay") + .WithVersion("3.0.3") + .Build(); + installedPackage = new PackageBuilder() + .WithManager(manager) + .WithId("dotnetsay") + .WithVersion("2.1.4") + .Build(); + InitializeLoaders(); + using var operation = new SimulatedInstallPackageOperation( + searchResult, + new InstallOptions { Version = "2.1.4" }, + OperationVeredict.Success + ); + + await operation.MainThread(); + await WaitForAsync(() => + InstalledPackagesLoader.Instance.GetEquivalentPackages(searchResult) + .Any(package => package.VersionString == "2.1.4") + ); + + Assert.DoesNotContain( + InstalledPackagesLoader.Instance.GetEquivalentPackages(searchResult), + package => package.VersionString == "3.0.3" + ); + } + + [Fact] + public async Task UpdateOperationSuccessfulRunPrefersAuthoritativeInstalledVersion() + { + TestPackageManager? manager = null; + Package? installedPackage = null; + manager = new PackageManagerBuilder() + .WithInstalledPackages(_ => [Assert.IsType(installedPackage)]) + .Build(); + var upgradablePackage = new PackageBuilder() + .WithManager(manager) + .WithId("dotnetsay") + .WithVersion("2.1.4") + .WithNewVersion("3.0.0") + .Build(); + installedPackage = new PackageBuilder() + .WithManager(manager) + .WithId("dotnetsay") + .WithVersion("3.0.3") + .Build(); + InitializeLoaders(); + await InstalledPackagesLoader.Instance.AddForeign(upgradablePackage); + using var operation = new SimulatedUpdatePackageOperation( + upgradablePackage, + new InstallOptions(), + OperationVeredict.Success + ); + + await operation.MainThread(); + await WaitForAsync(() => + InstalledPackagesLoader.Instance.GetEquivalentPackages(upgradablePackage) + .Any(package => package.VersionString == "3.0.3") + ); + + Assert.DoesNotContain( + InstalledPackagesLoader.Instance.GetEquivalentPackages(upgradablePackage), + package => package.VersionString == "3.0.0" + ); + } + + [Fact] + public async Task UpdateOperationSuccessfulRunPrefersRequestedVersionWhenSnapshotLags() + { + TestPackageManager? manager = null; + Package? installedPackage = null; + manager = new PackageManagerBuilder() + .WithInstalledPackages(_ => [Assert.IsType(installedPackage)]) + .Build(); + var installedBeforeUpdate = new PackageBuilder() + .WithManager(manager) + .WithId("dotnetsay") + .WithVersion("2.1.4") + .Build(); + installedPackage = new PackageBuilder() + .WithManager(manager) + .WithId("dotnetsay") + .WithVersion("2.1.4") + .Build(); + InitializeLoaders(); + await InstalledPackagesLoader.Instance.AddForeign(installedBeforeUpdate); + using var operation = new SimulatedUpdatePackageOperation( + installedBeforeUpdate, + new InstallOptions { Version = "3.0.3" }, + OperationVeredict.Success + ); + + await operation.MainThread(); + await WaitForAsync(() => + InstalledPackagesLoader.Instance.GetEquivalentPackages(installedBeforeUpdate) + .Any(package => package.VersionString == "3.0.3") + ); + + Assert.DoesNotContain( + InstalledPackagesLoader.Instance.GetEquivalentPackages(installedBeforeUpdate), + package => package.VersionString == "2.1.4" + ); + } + + [Fact] + public void UsernameRedactionAppliesToDisplayOutputButNeverToResultParsingOutput() + { + // Regression: result parsing must see raw output; only display (GetOutput) may redact. + var username = Environment.UserName; + if (string.IsNullOrEmpty(username)) + return; + + using var operation = new LoggingStubOperation(); + var rawLine = $"Error: the operation was canceled by C:\\Users\\{username}\\app"; + operation.EmitLine(rawLine, AbstractOperation.LineType.Information); + + bool previous = Logger.RedactUsername; + Logger.RedactUsername = true; + try + { + var parsingOutput = operation.RawOutputForTests(); + var displayOutput = operation.GetOutput(); + + Assert.Contains(parsingOutput, l => l.Item1 == rawLine); + Assert.DoesNotContain(displayOutput, l => l.Item1.Contains(username)); + Assert.Contains(displayOutput, l => l.Item1.Contains("****")); + } + finally + { + Logger.RedactUsername = previous; + } + } + + [Fact] + public async Task CancelWaitsForTheActiveOperationToCompleteCleanup() + { + using var operation = new CancellationAwareStubOperation(); + Task mainThread = operation.MainThread(); + await operation.PerformStarted.Task.WaitAsync(TimeSpan.FromSeconds(1)); + + operation.Cancel(); + await operation.CancellationObserved.Task.WaitAsync(TimeSpan.FromSeconds(1)); + + Assert.False(mainThread.IsCompleted); + operation.AllowCleanupToComplete.TrySetResult(true); + await mainThread; + + Assert.Equal(OperationStatus.Canceled, operation.Status); + } + + [Fact] + public async Task RetryWaitsForCanceledRunCleanupBeforeStartingAgain() + { + using var operation = new RetryAwareStubOperation(); + Task firstRun = operation.MainThread(); + await operation.FirstRunStarted.Task.WaitAsync(TimeSpan.FromSeconds(1)); + + operation.Cancel(); + await operation.CancellationObserved.Task.WaitAsync(TimeSpan.FromSeconds(1)); + operation.Retry(AbstractOperation.RetryMode.Retry); + + await Task.Delay(50); + Assert.Equal(1, operation.RunCount); + Assert.False(firstRun.IsCompleted); + + operation.AllowCleanupToComplete.TrySetResult(true); + await firstRun; + await operation.SecondRunStarted.Task.WaitAsync(TimeSpan.FromSeconds(1)); + await WaitForAsync(() => operation.Status is OperationStatus.Succeeded); + + Assert.Equal(2, operation.RunCount); + Assert.Equal(1, operation.MaxConcurrentRuns); + } + + [Fact] + public async Task ConcurrentMainThreadCallsShareTheActiveRun() + { + using var operation = new CancellationAwareStubOperation(); + + Task firstCall = operation.MainThread(); + Task secondCall = operation.MainThread(); + + Assert.Same(firstCall, secondCall); + await operation.PerformStarted.Task.WaitAsync(TimeSpan.FromSeconds(1)); + operation.Cancel(); + await operation.CancellationObserved.Task.WaitAsync(TimeSpan.FromSeconds(1)); + operation.AllowCleanupToComplete.TrySetResult(true); + await firstCall; + } + + [Fact] + public async Task RetryRequestedFromRetriedRunCompletionSchedulesAnotherRun() + { + using var operation = new RepeatedRetryStubOperation(); + await operation.MainThread(); + operation.OperationFailed += (_, _) => + { + if (operation.RunCount == 2) + operation.Retry(AbstractOperation.RetryMode.Retry); + }; + + operation.Retry(AbstractOperation.RetryMode.Retry); + + await operation.ThirdRunStarted.Task.WaitAsync(TimeSpan.FromSeconds(1)); + await WaitForAsync(() => operation.Status is OperationStatus.Failed); + Assert.Equal(3, operation.RunCount); + } + + [Fact] + public async Task DisposePreventsADeferredRetryFromStarting() + { + var operation = new RetryAwareStubOperation(); + Task firstRun = operation.MainThread(); + await operation.FirstRunStarted.Task.WaitAsync(TimeSpan.FromSeconds(1)); + operation.Cancel(); + await operation.CancellationObserved.Task.WaitAsync(TimeSpan.FromSeconds(1)); + operation.Retry(AbstractOperation.RetryMode.Retry); + + operation.Dispose(); + operation.AllowCleanupToComplete.TrySetResult(true); + await firstRun; + await Task.Delay(50); + + Assert.Equal(1, operation.RunCount); + Assert.Throws(() => + { + _ = operation.MainThread(); + }); + } + + [Fact] + public async Task DisposeFromTerminalEventPreservesCompletedStatus() + { + var operation = new RepeatedRetryStubOperation(); + operation.OperationFailed += (_, _) => operation.Dispose(); + + await operation.MainThread(); + + Assert.Equal(OperationStatus.Failed, operation.Status); + } + + [Fact] + public async Task DisposeFromStartupFailurePreservesFailedStatus() + { + var operation = new InvalidMetadataStubOperation(); + operation.OperationFailed += (_, _) => operation.Dispose(); + + await operation.MainThread(); + + Assert.Equal(OperationStatus.Failed, operation.Status); + } + + [Fact] + public async Task RetryOptionFailureDoesNotPreventALaterRetry() + { + using var operation = new ThrowingRetryStubOperation(); + await operation.MainThread(); + + operation.Retry("InvalidRetryMode"); + operation.Retry(AbstractOperation.RetryMode.Retry); + + await operation.SecondRunStarted.Task.WaitAsync(TimeSpan.FromSeconds(1)); + Assert.Equal(2, operation.RunCount); + } + + [Fact] + public async Task CancellationFromEnqueuedDoesNotRemainOnAFullQueue() + { + using var firstOperation = new CancellationAwareStubOperation(queueEnabled: true); + using var canceledOperation = new CancellationAwareStubOperation(queueEnabled: true); + AbstractOperation.OperationQueue.Clear(); + AbstractOperation.MAX_OPERATIONS = 1; + + Task firstRun = firstOperation.MainThread(); + await firstOperation.PerformStarted.Task.WaitAsync(TimeSpan.FromSeconds(1)); + canceledOperation.Enqueued += (_, _) => canceledOperation.Cancel(); + + await canceledOperation.MainThread().WaitAsync(TimeSpan.FromSeconds(1)); + + Assert.Equal(OperationStatus.Canceled, canceledOperation.Status); + Assert.DoesNotContain(canceledOperation, AbstractOperation.OperationQueue); + + firstOperation.Cancel(); + await firstOperation.CancellationObserved.Task.WaitAsync(TimeSpan.FromSeconds(1)); + firstOperation.AllowCleanupToComplete.TrySetResult(true); + await firstRun; + } + + private static IReadOnlyList GetInnerOperations( + AbstractOperation operation, + string fieldName + ) + { + var field = typeof(AbstractOperation).GetField( + fieldName, + BindingFlags.Instance | BindingFlags.NonPublic + ); + + return Assert.IsAssignableFrom>( + field?.GetValue(operation) + ); + } + + private static IPackage CreatePackage() + { + var manager = CreateManager(); + return new PackageBuilder().WithManager(manager).Build(); + } + + private static IPackageManager CreateManager() + { + return new PackageManagerBuilder() + .ConfigureManager(manager => + { + manager.ExecutablePath = "C:\\test-tools\\manager.exe"; + manager.ExecutableArguments = "--test"; + }) + .ConfigureOperation(helper => + helper.ParametersFactory = (package, _, operation) => + [ + operation.ToString().ToLowerInvariant(), + package.Id, + ]) + .Build(); + } + + private static void InitializeLoaders() + { + _ = new DiscoverablePackagesLoader([]); + _ = new UpgradablePackagesLoader([]); + _ = new InstalledPackagesLoader([]); + } + + private static async Task WaitForAsync(Func condition) + { + for (var attempt = 0; attempt < 20; attempt++) + { + if (condition()) + return; + + await Task.Delay(25); + } + } + + private class InspectableInstallPackageOperation : InstallPackageOperation + { + public InspectableInstallPackageOperation( + IPackage package, + InstallOptions options, + bool ignoreParallelInstalls = true, + AbstractOperation? req = null + ) + : base(package, options, ignoreParallelInstalls, req) { } + + public ProcessStartInfo PrepareProcessStartInfoForTests() + { + InitializeProcessStartInfoDefaults(); + PrepareProcessStartInfo(); + return process.StartInfo; + } + + private void InitializeProcessStartInfoDefaults() + { + process.StartInfo.UseShellExecute = false; + process.StartInfo.RedirectStandardOutput = true; + process.StartInfo.RedirectStandardInput = true; + process.StartInfo.RedirectStandardError = true; + process.StartInfo.CreateNoWindow = true; + process.StartInfo.StandardOutputEncoding = System.Text.Encoding.UTF8; + process.StartInfo.StandardErrorEncoding = System.Text.Encoding.UTF8; + process.StartInfo.StandardInputEncoding = System.Text.Encoding.UTF8; + process.StartInfo.WorkingDirectory = Environment.GetFolderPath( + Environment.SpecialFolder.UserProfile + ); + process.StartInfo.FileName = "lol"; + process.StartInfo.Arguments = "lol"; + } + } + + private sealed class SimulatedInstallPackageOperation : InspectableInstallPackageOperation + { + private readonly OperationVeredict _veredict; + + public SimulatedInstallPackageOperation( + IPackage package, + InstallOptions options, + OperationVeredict veredict + ) + : base(package, options) + { + _veredict = veredict; + } + + protected override Task PerformOperation() + { + return Task.FromResult(_veredict); + } + } + + private sealed class SimulatedUpdatePackageOperation : UpdatePackageOperation + { + private readonly OperationVeredict _veredict; + + public SimulatedUpdatePackageOperation( + IPackage package, + InstallOptions options, + OperationVeredict veredict + ) + : base(package, options) + { + _veredict = veredict; + } + + protected override Task PerformOperation() + { + return Task.FromResult(_veredict); + } + } + + private sealed class CancellationAwareStubOperation : AbstractOperation + { + public TaskCompletionSource PerformStarted { get; } = new( + TaskCreationOptions.RunContinuationsAsynchronously + ); + public TaskCompletionSource CancellationObserved { get; } = new( + TaskCreationOptions.RunContinuationsAsynchronously + ); + public TaskCompletionSource AllowCleanupToComplete { get; } = new( + TaskCreationOptions.RunContinuationsAsynchronously + ); + + public CancellationAwareStubOperation(bool queueEnabled = false) + : base(queue_enabled: queueEnabled) + { + Metadata.Status = "Cancelable stub status"; + Metadata.Title = "Cancelable stub title"; + Metadata.OperationInformation = "Cancelable stub info"; + Metadata.SuccessTitle = "Cancelable stub success"; + Metadata.SuccessMessage = "Cancelable stub success"; + Metadata.FailureTitle = "Cancelable stub failure"; + Metadata.FailureMessage = "Cancelable stub failure"; + } + + protected override void ApplyRetryAction(string retryMode) { } + + protected override async Task PerformOperation() + { + PerformStarted.TrySetResult(true); + try + { + await Task.Delay(Timeout.InfiniteTimeSpan, CancellationToken); + } + catch (OperationCanceledException) when (CancellationToken.IsCancellationRequested) + { + CancellationObserved.TrySetResult(true); + await AllowCleanupToComplete.Task; + return OperationVeredict.Canceled; + } + + return OperationVeredict.Success; + } + + public override Task GetOperationIcon() => Task.FromResult(new Uri("about:blank")); + } + + private sealed class RetryAwareStubOperation : AbstractOperation + { + private int _concurrentRuns; + private int _maxConcurrentRuns; + private int _runCount; + + public TaskCompletionSource FirstRunStarted { get; } = new( + TaskCreationOptions.RunContinuationsAsynchronously + ); + public TaskCompletionSource CancellationObserved { get; } = new( + TaskCreationOptions.RunContinuationsAsynchronously + ); + public TaskCompletionSource AllowCleanupToComplete { get; } = new( + TaskCreationOptions.RunContinuationsAsynchronously + ); + public TaskCompletionSource SecondRunStarted { get; } = new( + TaskCreationOptions.RunContinuationsAsynchronously + ); + + public int RunCount => Volatile.Read(ref _runCount); + public int MaxConcurrentRuns => Volatile.Read(ref _maxConcurrentRuns); + + public RetryAwareStubOperation() + : base(queue_enabled: false) + { + Metadata.Status = "Retryable stub status"; + Metadata.Title = "Retryable stub title"; + Metadata.OperationInformation = "Retryable stub info"; + Metadata.SuccessTitle = "Retryable stub success"; + Metadata.SuccessMessage = "Retryable stub success"; + Metadata.FailureTitle = "Retryable stub failure"; + Metadata.FailureMessage = "Retryable stub failure"; + } + + protected override void ApplyRetryAction(string retryMode) { } + + protected override async Task PerformOperation() + { + int concurrentRuns = Interlocked.Increment(ref _concurrentRuns); + UpdateMaximum(ref _maxConcurrentRuns, concurrentRuns); + int run = Interlocked.Increment(ref _runCount); + try + { + if (run == 1) + { + FirstRunStarted.TrySetResult(true); + try + { + await Task.Delay(Timeout.InfiniteTimeSpan, CancellationToken); + } + catch (OperationCanceledException) when (CancellationToken.IsCancellationRequested) + { + CancellationObserved.TrySetResult(true); + await AllowCleanupToComplete.Task; + return OperationVeredict.Canceled; + } + } + + SecondRunStarted.TrySetResult(true); + return OperationVeredict.Success; + } + finally + { + Interlocked.Decrement(ref _concurrentRuns); + } + } + + private static void UpdateMaximum(ref int target, int value) + { + int current; + do + { + current = Volatile.Read(ref target); + if (current >= value) + return; + } while (Interlocked.CompareExchange(ref target, value, current) != current); + } + + public override Task GetOperationIcon() => Task.FromResult(new Uri("about:blank")); + } + + private sealed class RepeatedRetryStubOperation : AbstractOperation + { + private int _runCount; + + public int RunCount => Volatile.Read(ref _runCount); + public TaskCompletionSource ThirdRunStarted { get; } = new( + TaskCreationOptions.RunContinuationsAsynchronously + ); + + public RepeatedRetryStubOperation() + : base(queue_enabled: false) + { + Metadata.Status = "Repeated retry stub status"; + Metadata.Title = "Repeated retry stub title"; + Metadata.OperationInformation = "Repeated retry stub info"; + Metadata.SuccessTitle = "Repeated retry stub success"; + Metadata.SuccessMessage = "Repeated retry stub success"; + Metadata.FailureTitle = "Repeated retry stub failure"; + Metadata.FailureMessage = "Repeated retry stub failure"; + } + + protected override void ApplyRetryAction(string retryMode) { } + + protected override Task PerformOperation() + { + if (Interlocked.Increment(ref _runCount) == 3) + ThirdRunStarted.TrySetResult(true); + return Task.FromResult(OperationVeredict.Failure); + } + + public override Task GetOperationIcon() => Task.FromResult(new Uri("about:blank")); + } + + private sealed class InvalidMetadataStubOperation : AbstractOperation + { + public InvalidMetadataStubOperation() + : base(queue_enabled: false) { } + + protected override void ApplyRetryAction(string retryMode) { } + + protected override Task PerformOperation() + => Task.FromResult(OperationVeredict.Success); + + public override Task GetOperationIcon() => Task.FromResult(new Uri("about:blank")); + } + + private sealed class ThrowingRetryStubOperation : AbstractOperation + { + private int _runCount; + + public int RunCount => Volatile.Read(ref _runCount); + public TaskCompletionSource SecondRunStarted { get; } = new( + TaskCreationOptions.RunContinuationsAsynchronously + ); + + public ThrowingRetryStubOperation() + : base(queue_enabled: false) + { + Metadata.Status = "Throwing retry stub status"; + Metadata.Title = "Throwing retry stub title"; + Metadata.OperationInformation = "Throwing retry stub info"; + Metadata.SuccessTitle = "Throwing retry stub success"; + Metadata.SuccessMessage = "Throwing retry stub success"; + Metadata.FailureTitle = "Throwing retry stub failure"; + Metadata.FailureMessage = "Throwing retry stub failure"; + } + + protected override void ApplyRetryAction(string retryMode) + { + if (retryMode == "InvalidRetryMode") + throw new InvalidOperationException("Invalid retry mode"); + } + + protected override Task PerformOperation() + { + if (Interlocked.Increment(ref _runCount) == 2) + SecondRunStarted.TrySetResult(true); + return Task.FromResult(OperationVeredict.Failure); + } + + public override Task GetOperationIcon() => Task.FromResult(new Uri("about:blank")); + } + + private sealed class LoggingStubOperation : AbstractOperation + { + public LoggingStubOperation() + : base(queue_enabled: false) { } + + public void EmitLine(string line, LineType type) => Line(line, type); + + public IReadOnlyList<(string, LineType)> RawOutputForTests() => GetRawOutput(); + + protected override void ApplyRetryAction(string retryMode) { } + + protected override Task PerformOperation() + => Task.FromResult(OperationVeredict.Success); + + public override Task GetOperationIcon() => Task.FromResult(new Uri("about:blank")); + } + + private sealed class StubOperation : AbstractOperation + { + public StubOperation() + : base(queue_enabled: false) + { + Metadata.Status = "Stub status"; + Metadata.Title = "Stub title"; + Metadata.OperationInformation = "Stub info"; + Metadata.SuccessTitle = "Stub success"; + Metadata.SuccessMessage = "Stub success"; + Metadata.FailureTitle = "Stub failure"; + Metadata.FailureMessage = "Stub failure"; + } + + protected override void ApplyRetryAction(string retryMode) { } + + protected override Task PerformOperation() + { + return Task.FromResult(OperationVeredict.Success); + } + + public override Task GetOperationIcon() + { + return Task.FromResult(new Uri("about:blank")); + } + } +} diff --git a/src/UniGetUI.PackageEngine.Tests/PackageTests.cs b/src/UniGetUI.PackageEngine.Tests/PackageTests.cs new file mode 100644 index 0000000..a9b6e7b --- /dev/null +++ b/src/UniGetUI.PackageEngine.Tests/PackageTests.cs @@ -0,0 +1,68 @@ +using UniGetUI.Core.Data; +using UniGetUI.Core.SettingsEngine; +using UniGetUI.Core.SettingsEngine.SecureSettings; +using UniGetUI.PackageEngine.PackageLoader; +using UniGetUI.PackageEngine.Tests.Infrastructure.Builders; + +namespace UniGetUI.PackageEngine.Tests; + +public sealed class NewerVersionIsInstalledTests : IDisposable +{ + private readonly string _testRoot; + + public NewerVersionIsInstalledTests() + { + _testRoot = Path.Combine( + Path.GetTempPath(), + nameof(NewerVersionIsInstalledTests), + Guid.NewGuid().ToString("N") + ); + CoreData.TEST_DataDirectoryOverride = Path.Combine(_testRoot, "Data"); + SecureSettings.TEST_SecureSettingsRootOverride = Path.Combine(_testRoot, "SecureSettings"); + Directory.CreateDirectory(CoreData.UniGetUIUserConfigurationDirectory); + Settings.ResetSettings(); + } + + public void Dispose() + { + Settings.ResetSettings(); + CoreData.TEST_DataDirectoryOverride = null; + SecureSettings.TEST_SecureSettingsRootOverride = null; + if (Directory.Exists(_testRoot)) + Directory.Delete(_testRoot, recursive: true); + } + + [Theory] + [InlineData("1.0.0", "2.0.0", false)] + [InlineData("2.0.0", "2.0.0", true)] + [InlineData("3.0.0", "2.0.0", true)] + [InlineData("10c8e557", "8b640eef", false)] + [InlineData("10c8e557", "2.0.0", false)] + [InlineData("2.0.0", "8b640eef", false)] + [InlineData("", "2.0.0", false)] + [InlineData("1.0.0;3.0.0", "2.0.0", true)] + public async Task NewerVersionIsInstalled_ReturnsExpectedResult(string installedVersions, string newVersion, bool expected) + { + var manager = new PackageManagerBuilder().Build(); + InitializeLoaders(); + + foreach (var v in installedVersions.Split(';', StringSplitOptions.RemoveEmptyEntries)) + { + await InstalledPackagesLoader.Instance.AddForeign( + new PackageBuilder().WithManager(manager).WithId("Contoso.Tool").WithVersion(v.Trim()).Build() + ); + } + + var update = new PackageBuilder() + .WithManager(manager).WithId("Contoso.Tool").WithVersion("1.0.0").WithNewVersion(newVersion).Build(); + + Assert.Equal(expected, update.NewerVersionIsInstalled()); + } + + private static void InitializeLoaders() + { + _ = new DiscoverablePackagesLoader([]); + _ = new UpgradablePackagesLoader([]); + _ = new InstalledPackagesLoader([]); + } +} diff --git a/src/UniGetUI.PackageEngine.Tests/PipManagerTests.cs b/src/UniGetUI.PackageEngine.Tests/PipManagerTests.cs new file mode 100644 index 0000000..94ded14 --- /dev/null +++ b/src/UniGetUI.PackageEngine.Tests/PipManagerTests.cs @@ -0,0 +1,223 @@ +using UniGetUI.Core.Data; +using UniGetUI.Core.SettingsEngine; +using UniGetUI.PackageEngine.Enums; +using UniGetUI.PackageEngine.Managers.PipManager; +using UniGetUI.PackageEngine.Serializable; +using UniGetUI.PackageEngine.Structs; +using UniGetUI.PackageEngine.Tests.Infrastructure.Assertions; +using UniGetUI.PackageEngine.Tests.Infrastructure.Builders; +using UniGetUI.PackageEngine.Tests.Infrastructure.Helpers; + +namespace UniGetUI.PackageEngine.Tests; + +[CollectionDefinition("Pip manager tests", DisableParallelization = true)] +public sealed class PipManagerTestCollection +{ + public const string Name = "Pip manager tests"; +} + +[Collection(PipManagerTestCollection.Name)] +public sealed class PipManagerTests : IDisposable +{ + private readonly string _testRoot = Path.Combine( + AppContext.BaseDirectory, + nameof(PipManagerTests), + Guid.NewGuid().ToString("N") + ); + + public PipManagerTests() + { + Directory.CreateDirectory(_testRoot); + CoreData.TEST_DataDirectoryOverride = Path.Combine(_testRoot, "Data"); + Directory.CreateDirectory(CoreData.UniGetUIUserConfigurationDirectory); + Settings.ResetSettings(); + Settings.Set(Settings.K.EnableProxy, false); + Settings.Set(Settings.K.EnableProxyAuth, false); + Settings.SetValue(Settings.K.ProxyURL, ""); + } + + public void Dispose() + { + Settings.ResetSettings(); + CoreData.TEST_DataDirectoryOverride = null; + if (Directory.Exists(_testRoot)) + { + Directory.Delete(_testRoot, recursive: true); + } + } + + [Fact] + public void SearchHelpersParseSimpleIndexAndRankPrefixMatchesFirst() + { + var names = Pip.ParseSimpleIndexProjectNames( + + PackageEngineFixtureFiles.ReadAllText(Path.Combine("Pip", "simple-index.json")) + ); + + var matches = Pip.SelectSearchMatches("req", names); + + Assert.Equal( + ["req", "requests", "requestium", "requests-cache", "django-reqtools"], + matches + ); + } + + [Fact] + public void ParseAvailableUpdatesBuildsPackagesFromFixture() + { + var manager = new Pip(); + + var packages = Pip.ParseAvailableUpdates( + File.ReadLines(PackageEngineFixtureFiles.GetPath(Path.Combine("Pip", "outdated-list.txt"))), + manager.DefaultSource, + manager + ); + + Assert.Collection( + packages, + package => + { + PackageAssert.Matches(package, "Requests", "requests", "2.31.0", "2.32.3"); + PackageAssert.BelongsTo(package, manager, manager.DefaultSource); + }, + package => + { + PackageAssert.Matches( + package, + "Django Reqtools", + "django-reqtools", + "1.0.0", + "1.1.0" + ); + PackageAssert.BelongsTo(package, manager, manager.DefaultSource); + } + ); + } + + [Fact] + public void ParseInstalledPackagesBuildsPackagesFromFixture() + { + var manager = new Pip(); + + var packages = Pip.ParseInstalledPackages( + File.ReadLines(PackageEngineFixtureFiles.GetPath(Path.Combine("Pip", "installed-list.txt"))), + manager.DefaultSource, + manager + ); + + Assert.Collection( + packages, + package => + { + PackageAssert.Matches(package, "Requests", "requests", "2.31.0"); + PackageAssert.BelongsTo(package, manager, manager.DefaultSource); + }, + package => + { + PackageAssert.Matches(package, "Django Reqtools", "django-reqtools", "1.0.0"); + PackageAssert.BelongsTo(package, manager, manager.DefaultSource); + } + ); + } + + [Fact] + public void OperationHelperBuildsInstallAndUninstallParameters() + { + Settings.Set(Settings.K.EnableProxy, true); + Settings.Set(Settings.K.EnableProxyAuth, false); + Settings.SetValue(Settings.K.ProxyURL, "http://proxy.example.test:3128/"); + var manager = new Pip(); + var overridenOptions = new OverridenInstallationOptions(); + overridenOptions.Pip_BreakSystemPackages = true; + var package = new PackageBuilder() + .WithManager(manager) + .WithId("requests") + .WithOptions(overridenOptions) + .Build(); + var installOptions = new InstallOptions + { + Version = "2.31.0", + InstallationScope = PackageScope.User, + PreRelease = true, + CustomParameters_Install = ["--quiet"], + }; + var uninstallOptions = new InstallOptions + { + CustomParameters_Uninstall = ["--verbose"], + }; + + var installParameters = manager.OperationHelper.GetParameters( + package, + installOptions, + OperationType.Install + ); + var uninstallParameters = manager.OperationHelper.GetParameters( + package, + uninstallOptions, + OperationType.Uninstall + ); + + Assert.Equal( + [ + "install", + "requests==2.31.0", + "--no-input", + "--no-color", + "--no-cache", + "--pre", + "--user", + "--break-system-packages", + "--proxy http://proxy.example.test:3128/", + "--quiet", + ], + installParameters + ); + Assert.Equal( + [ + "uninstall", + "requests", + "--no-input", + "--no-color", + "--no-cache", + "--yes", + "--break-system-packages", + "--proxy http://proxy.example.test:3128/", + "--verbose", + ], + uninstallParameters + ); + } + + [Fact] + public void OperationHelperUsesAutoRetryMutationsForKnownPipFailures() + { + var manager = new Pip(); + var breakSystemPackage = new PackageBuilder().WithManager(manager).WithId("requests").Build(); + var userScopedPackage = new PackageBuilder().WithManager(manager).WithId("requests").Build(); + + var externallyManagedResult = manager.OperationHelper.GetResult( + breakSystemPackage, + OperationType.Install, + ["error: externally-managed-environment"], + 1 + ); + var userScopeResult = manager.OperationHelper.GetResult( + userScopedPackage, + OperationType.Install, + ["hint: try again with --user"], + 1 + ); + var failureResult = manager.OperationHelper.GetResult( + new PackageBuilder().WithManager(manager).WithId("requests").Build(), + OperationType.Install, + ["boom"], + 1 + ); + + Assert.Equal(OperationVeredict.AutoRetry, externallyManagedResult); + Assert.True(breakSystemPackage.OverridenOptions.Pip_BreakSystemPackages); + Assert.Equal(OperationVeredict.AutoRetry, userScopeResult); + Assert.Equal(PackageScope.User, userScopedPackage.OverridenOptions.Scope); + Assert.Equal(OperationVeredict.Failure, failureResult); + } +} diff --git a/src/UniGetUI.PackageEngine.Tests/PowerShell7ManagerTests.cs b/src/UniGetUI.PackageEngine.Tests/PowerShell7ManagerTests.cs new file mode 100644 index 0000000..63872d7 --- /dev/null +++ b/src/UniGetUI.PackageEngine.Tests/PowerShell7ManagerTests.cs @@ -0,0 +1,105 @@ +#if WINDOWS +using UniGetUI.PackageEngine.Enums; +using UniGetUI.PackageEngine.Managers.PowerShell7Manager; + +namespace UniGetUI.PackageEngine.Tests; + +public sealed class PowerShell7ManagerTests +{ + [Fact] + public void ParseInstalledPackages_BuildsPackagesFromTabDelimitedOutput() + { + var manager = new PowerShell7(); + + var packages = PowerShell7.ParseInstalledPackages( + [ + "##SCOPE:AllUsers##", + "Pester\t5.7.1\tPSGallery", + "##SCOPE:CurrentUser##", + "PSReadLine\t2.2.5\tPSGallery", + ], + manager + ); + + Assert.Collection( + packages, + package => + { + Assert.Equal("Pester", package.Id); + Assert.Equal("5.7.1", package.VersionString); + Assert.Equal("PSGallery", package.Source.Name); + Assert.Equal(PackageScope.Machine, package.OverridenOptions.Scope); + }, + package => + { + Assert.Equal("PSReadLine", package.Id); + Assert.Equal("2.2.5", package.VersionString); + Assert.Equal("PSGallery", package.Source.Name); + Assert.Equal(PackageScope.User, package.OverridenOptions.Scope); + } + ); + } + + [Fact] + public void ParseInstalledPackages_SkipsBlankAndMalformedLines() + { + var manager = new PowerShell7(); + + var package = Assert.Single( + PowerShell7.ParseInstalledPackages( + [ + "##SCOPE:AllUsers##", + "", + "not-enough-columns", + "only\ttwo", + "\t\t", + "Pester\t5.7.1\tPSGallery", + ], + manager + ) + ); + + Assert.Equal("Pester", package.Id); + } + + // Regression for https://github.com/Devolutions/UniGetUI/issues/4781: + // the previous Format-Table-based pipeline truncated long names (e.g. + // "Microsoft.Graph.Beta.DeviceManagement.Administration" → "Microsoft.Graph.Beta..") + // which then poisoned the GetUpdates() URL sent to PSGallery, returning + // NotFound and silently dropping every PS7 update from the list. + [Fact] + public void ParseInstalledPackages_PreservesLongNamesAndVersionsVerbatim() + { + var manager = new PowerShell7(); + + var packages = PowerShell7.ParseInstalledPackages( + [ + "##SCOPE:CurrentUser##", + "Microsoft.Graph.Beta.DeviceManagement.Administration\t2.34.0\tPSGallery", + "Az.RedisEnterpriseCache\t1.6.0\tPSGallery", + "Microsoft.PowerShell.SecretManagement\t1.1.2\tPSGallery", + ], + manager + ); + + Assert.Collection( + packages, + package => + { + Assert.Equal("Microsoft.Graph.Beta.DeviceManagement.Administration", package.Id); + Assert.Equal("2.34.0", package.VersionString); + }, + package => + { + Assert.Equal("Az.RedisEnterpriseCache", package.Id); + Assert.Equal("1.6.0", package.VersionString); + }, + package => + { + Assert.Equal("Microsoft.PowerShell.SecretManagement", package.Id); + Assert.Equal("1.1.2", package.VersionString); + } + ); + } +} +#endif diff --git a/src/UniGetUI.PackageEngine.Tests/PowerShellManagerTests.cs b/src/UniGetUI.PackageEngine.Tests/PowerShellManagerTests.cs new file mode 100644 index 0000000..351e014 --- /dev/null +++ b/src/UniGetUI.PackageEngine.Tests/PowerShellManagerTests.cs @@ -0,0 +1,59 @@ +#if WINDOWS +using UniGetUI.PackageEngine.Managers.PowerShellManager; + +namespace UniGetUI.PackageEngine.Tests; + +public sealed class PowerShellManagerTests +{ + [Fact] + public void ParseInstalledPackages_BuildsPackagesFromModuleTable() + { + var manager = new PowerShell(); + var packages = PowerShell.ParseInstalledPackages( + [ + "Version Name Repository Description", + "------- ---- ---------- -----------", + "5.5.0 Pester PSGallery Test framework", + "2.2.5 PSReadLine PSGallery Command line editing", + ], + manager + ); + + Assert.Collection( + packages, + package => + { + Assert.Equal("Pester", package.Id); + Assert.Equal("5.5.0", package.VersionString); + Assert.Equal("PSGallery", package.Source.Name); + }, + package => + { + Assert.Equal("PSReadLine", package.Id); + Assert.Equal("2.2.5", package.VersionString); + Assert.Equal("PSGallery", package.Source.Name); + } + ); + } + + [Fact] + public void ParseInstalledPackages_SkipsMalformedLines() + { + var manager = new PowerShell(); + + var package = Assert.Single( + PowerShell.ParseInstalledPackages( + [ + "Version Name Repository Description", + "------- ---- ---------- -----------", + "not-enough-columns", + "5.5.0 Pester PSGallery Test framework", + ], + manager + ) + ); + + Assert.Equal("Pester", package.Id); + } +} +#endif diff --git a/src/UniGetUI.PackageEngine.Tests/ProgressLineCollapserTests.cs b/src/UniGetUI.PackageEngine.Tests/ProgressLineCollapserTests.cs new file mode 100644 index 0000000..2543922 --- /dev/null +++ b/src/UniGetUI.PackageEngine.Tests/ProgressLineCollapserTests.cs @@ -0,0 +1,95 @@ +using UniGetUI.PackageOperations; +using LineType = UniGetUI.PackageOperations.AbstractOperation.LineType; + +namespace UniGetUI.PackageEngine.Tests; + +public class ProgressLineCollapserTests +{ + // Applies the collapser to a stream of (text, type) lines exactly like the live log view does, + // returning the lines that would actually be rendered. + private static List Render(IEnumerable<(string Text, LineType Type)> stream) + { + var collapser = new ProgressLineCollapser(); + var rendered = new List(); + foreach (var (text, type) in stream) + { + if (collapser.Next(type) is ProgressLineCollapser.Fold.ReplaceLast && rendered.Count > 0) + rendered[^1] = text; + else + rendered.Add(text); + } + return rendered; + } + + [Fact] + public void SpinnerFramesCollapseToASingleLine() + { + var spinner = new[] { "|", "/", "-", "\\", "|", "/", "-", "\\" } + .Select(f => ($"Installing {f}", LineType.ProgressIndicator)); + + var rendered = Render(spinner); + + Assert.Single(rendered); + Assert.Equal("Installing \\", rendered[0]); // last frame wins + } + + [Fact] + public void DownloadProgressCollapsesAndSettlesIntoFinalLine() + { + var stream = new List<(string, LineType)> + { + ("Fetching download url...", LineType.Information), + ("[= ] 10 MB/100 MB", LineType.ProgressIndicator), + ("[===== ] 50 MB/100 MB", LineType.ProgressIndicator), + ("[==========] 100 MB/100 MB", LineType.ProgressIndicator), + ("The file was saved to C:\\out.exe", LineType.Information), + }; + + var rendered = Render(stream); + + Assert.Equal( + [ + "Fetching download url...", + "The file was saved to C:\\out.exe", // progress bar settled into this line + ], rendered); + } + + [Fact] + public void NonProgressLinesAlwaysAppend() + { + var stream = new[] + { + ("line 1", LineType.Information), + ("line 2", LineType.VerboseDetails), + ("line 3", LineType.Error), + }; + + var rendered = Render(stream); + + Assert.Equal(["line 1", "line 2", "line 3"], rendered); + } + + [Fact] + public void ProgressBetweenNormalLinesDoesNotEatThem() + { + var stream = new[] + { + ("before", LineType.Information), + ("spin 1", LineType.ProgressIndicator), + ("spin 2", LineType.ProgressIndicator), + ("after", LineType.Information), + ("end", LineType.Information), + }; + + var rendered = Render(stream); + + // "before" kept, two spins collapse and settle into "after", then "end" appends. + Assert.Equal(["before", "after", "end"], rendered); + } + + [Fact] + public void FirstLineNeverReplaces() + { + Assert.Equal(ProgressLineCollapser.Fold.Append, new ProgressLineCollapser().Next(LineType.ProgressIndicator)); + } +} diff --git a/src/UniGetUI.PackageEngine.Tests/ScoopManagerTests.cs b/src/UniGetUI.PackageEngine.Tests/ScoopManagerTests.cs new file mode 100644 index 0000000..028dd28 --- /dev/null +++ b/src/UniGetUI.PackageEngine.Tests/ScoopManagerTests.cs @@ -0,0 +1,394 @@ +#if WINDOWS +using UniGetUI.Core.Data; +using UniGetUI.Core.SettingsEngine; +using UniGetUI.PackageEngine.Enums; +using UniGetUI.PackageEngine.Interfaces; +using UniGetUI.PackageEngine.Managers.ScoopManager; +using UniGetUI.PackageEngine.Serializable; +using UniGetUI.PackageEngine.Structs; +using UniGetUI.PackageEngine.Tests.Infrastructure.Assertions; +using UniGetUI.PackageEngine.Tests.Infrastructure.Builders; +using UniGetUI.PackageEngine.Tests.Infrastructure.Helpers; +using Architecture = UniGetUI.PackageEngine.Enums.Architecture; + +namespace UniGetUI.PackageEngine.Tests; + +[CollectionDefinition("Scoop manager tests", DisableParallelization = true)] +public sealed class ScoopManagerTestCollection +{ + public const string Name = "Scoop manager tests"; +} + +[Collection(ScoopManagerTestCollection.Name)] +public sealed class ScoopManagerTests : IDisposable +{ + private readonly string _testRoot = Path.Combine( + AppContext.BaseDirectory, + nameof(ScoopManagerTests), + Guid.NewGuid().ToString("N") + ); + + public ScoopManagerTests() + { + Directory.CreateDirectory(_testRoot); + CoreData.TEST_DataDirectoryOverride = Path.Combine(_testRoot, "Data"); + Directory.CreateDirectory(CoreData.UniGetUIUserConfigurationDirectory); + Settings.ResetSettings(); + } + + public void Dispose() + { + Settings.ResetSettings(); + CoreData.TEST_DataDirectoryOverride = null; + if (Directory.Exists(_testRoot)) + { + Directory.Delete(_testRoot, recursive: true); + } + } + + [Fact] + public void ParseSearchOutputBuildsPackagesFromBucketSections() + { + var manager = CreateManagerWithKnownSources("main", "versions"); + + var packages = manager.ParseSearchOutput(ReadFixtureLines(@"Scoop\search-output.txt")); + + Assert.Collection( + packages, + package => + { + PackageAssert.Matches(package, "7zip", "7zip", "24.09"); + PackageAssert.BelongsTo(package, manager, manager.SourcesHelper.Factory.GetSourceOrDefault("main")); + }, + package => + { + PackageAssert.Matches(package, "Python310", "python310", "3.10.11"); + PackageAssert.BelongsTo( + package, + manager, + manager.SourcesHelper.Factory.GetSourceOrDefault("versions") + ); + } + ); + } + + [Fact] + public void ParseInstalledPackagesBuildsPackagesAndScopesFromFixture() + { + var manager = CreateManagerWithKnownSources("main", "versions"); + + var packages = manager.ParseInstalledPackages(ReadFixtureLines(@"Scoop\list-output.txt")); + + Assert.Collection( + packages, + package => + { + PackageAssert.Matches(package, "Git", "git", "2.47.1"); + PackageAssert.BelongsTo(package, manager, manager.SourcesHelper.Factory.GetSourceOrDefault("main")); + Assert.Equal(PackageScope.User, package.OverridenOptions.Scope); + }, + package => + { + PackageAssert.Matches(package, "Pwsh", "pwsh", "7.4.6"); + PackageAssert.BelongsTo( + package, + manager, + manager.SourcesHelper.Factory.GetSourceOrDefault("versions") + ); + Assert.Equal(PackageScope.Global, package.OverridenOptions.Scope); + } + ); + } + + [Fact] + public void ParseAvailableUpdatesPreservesInstalledSourceAndScope() + { + var manager = CreateManagerWithKnownSources("main", "versions"); + var installedPackages = manager.ParseInstalledPackages(ReadFixtureLines(@"Scoop\list-output.txt")); + + var packages = manager.ParseAvailableUpdates( + ReadFixtureLines(@"Scoop\status-output.txt"), + installedPackages + ); + + Assert.Collection( + packages, + package => + { + PackageAssert.Matches(package, "Git", "git", "2.47.1", "2.48.1"); + PackageAssert.BelongsTo(package, manager, manager.SourcesHelper.Factory.GetSourceOrDefault("main")); + Assert.Equal(PackageScope.User, package.OverridenOptions.Scope); + }, + package => + { + PackageAssert.Matches(package, "Pwsh", "pwsh", "7.4.6", "7.5.0"); + PackageAssert.BelongsTo( + package, + manager, + manager.SourcesHelper.Factory.GetSourceOrDefault("versions") + ); + Assert.Equal(PackageScope.Global, package.OverridenOptions.Scope); + } + ); + } + + [Fact] + public void ParseSourcesNormalizesGitUrlsAndLocalBuckets() + { + var manager = new Scoop(); + var helper = Assert.IsType(manager.SourcesHelper); + + var sources = helper.ParseSources(ReadFixtureLines(@"Scoop\bucket-list-output.txt")); + + Assert.Collection( + sources, + source => + { + Assert.Equal("main", source.Name); + Assert.Equal(new Uri("https://github.com/ScoopInstaller/Main"), source.Url); + Assert.Equal(1234, source.PackageCount); + Assert.Equal("2024-02-01 12:34:56", source.UpdateDate); + }, + source => + { + Assert.Equal("extras", source.Name); + Assert.Equal( + new Uri( + Path.Join( + Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), + "scoop", + "buckets", + "extras" + ) + ), + source.Url + ); + Assert.Equal(321, source.PackageCount); + Assert.Equal("2024-02-02 09:08:07", source.UpdateDate); + } + ); + } + + [Fact] + public void SourceHelperBuildsBucketCommandsAndMapsExitCodes() + { + var manager = new Scoop(); + var source = new SourceBuilder() + .WithManager(manager) + .WithName("extras") + .WithUrl("https://github.com/ScoopInstaller/Extras") + .Build(); + + Assert.Equal( + ["bucket", "add", "extras", "https://github.com/ScoopInstaller/Extras"], + manager.SourcesHelper.GetAddSourceParameters(source) + ); + Assert.Equal(["bucket", "rm", "extras"], manager.SourcesHelper.GetRemoveSourceParameters(source)); + Assert.Equal( + OperationVeredict.Success, + manager.SourcesHelper.GetAddOperationVeredict(source, 0, []) + ); + Assert.Equal( + OperationVeredict.Failure, + manager.SourcesHelper.GetRemoveOperationVeredict(source, 1, []) + ); + } + + [Fact] + public void InstallParametersIncludeSourceScopeArchitectureAndHashFlags() + { + var manager = new Scoop(); + var source = new SourceBuilder() + .WithManager(manager) + .WithName("extras") + .WithUrl("https://github.com/ScoopInstaller/Extras") + .Build(); + manager.SourcesHelper.Factory.AddSource(source); + var package = new PackageBuilder().WithManager(manager).WithSource(source).WithId("git").Build(); + var options = new InstallOptions + { + InstallationScope = PackageScope.Global, + Architecture = Architecture.x64, + SkipHashCheck = true, + CustomParameters_Install = ["--no-cache"], + }; + + var parameters = manager.OperationHelper.GetParameters(package, options, OperationType.Install); + + OperationAssert.HasParameters( + parameters, + "install", + "extras/git", + "--global", + "--no-cache", + "--skip-hash-check", + "--arch", + "64bit" + ); + Assert.True(package.OverridenOptions.RunAsAdministrator); + } + + [Fact] + public void UninstallParametersOmitLocalSourcePrefixAndAppendPurge() + { + var manager = new Scoop(); + var source = new SourceBuilder() + .WithManager(manager) + .WithName(@"C:\Buckets\custom") + .WithUrl("https://example.test/custom") + .Build(); + var package = new PackageBuilder() + .WithManager(manager) + .WithSource(source) + .WithId("custom-tool") + .Build(); + var options = new InstallOptions + { + RemoveDataOnUninstall = true, + CustomParameters_Uninstall = ["--verbose"], + }; + + var parameters = manager.OperationHelper.GetParameters(package, options, OperationType.Uninstall); + + OperationAssert.HasParameters( + parameters, + "uninstall", + "custom-tool", + "--verbose", + "--purge" + ); + } + + [Fact] + public void OperationResultPromotesGlobalRetryWhenScoopRequestsGlobalFlag() + { + var manager = new Scoop(); + var package = new PackageBuilder().WithManager(manager).Build(); + + var veredict = manager.OperationHelper.GetResult( + package, + OperationType.Install, + ["Try again with the --global (or -g) flag instead"], + 1 + ); + + OperationAssert.HasVeredict(veredict, OperationVeredict.AutoRetry); + Assert.Equal(PackageScope.Global, package.OverridenOptions.Scope); + Assert.True(package.OverridenOptions.RunAsAdministrator); + } + + [Fact] + public void OperationResultPromotesElevationRetryBeforeReturningFailure() + { + var manager = new Scoop(); + var package = new PackageBuilder() + .WithManager(manager) + .WithOptions(new OverridenInstallationOptions(runAsAdministrator: false)) + .Build(); + + var retry = manager.OperationHelper.GetResult( + package, + OperationType.Install, + ["package requires administrator rights"], + 1 + ); + var failure = manager.OperationHelper.GetResult(package, OperationType.Install, ["ERROR: failed"], 1); + var success = manager.OperationHelper.GetResult(package, OperationType.Install, ["done"], 0); + + OperationAssert.HasVeredict(retry, OperationVeredict.AutoRetry); + Assert.True(package.OverridenOptions.RunAsAdministrator); + OperationAssert.HasVeredict(failure, OperationVeredict.Failure); + OperationAssert.HasVeredict(success, OperationVeredict.Success); + } + + [Fact] + public void OperationResultRetriesElevatedOnShimResolutionFailure() + { + var manager = new Scoop(); + var package = new PackageBuilder() + .WithManager(manager) + .WithOptions(new OverridenInstallationOptions(runAsAdministrator: false)) + .Build(); + + var retry = manager.OperationHelper.GetResult( + package, + OperationType.Update, + ["Creating shim for 'notepad++'.", "Can't shim 'notepad++.exe': File doesn't exist."], + 1 + ); + + OperationAssert.HasVeredict(retry, OperationVeredict.AutoRetry); + Assert.True(package.OverridenOptions.RunAsAdministrator); + + // Already elevated: the same failure must not loop, it should surface as a plain failure + var failure = manager.OperationHelper.GetResult( + package, + OperationType.Update, + ["Can't shim 'notepad++.exe': File doesn't exist."], + 1 + ); + OperationAssert.HasVeredict(failure, OperationVeredict.Failure); + } + + [Fact] + public void OperationResultDoesNotRetryShimMessageOnSuccess() + { + var manager = new Scoop(); + var package = new PackageBuilder().WithManager(manager).Build(); + + var veredict = manager.OperationHelper.GetResult( + package, + OperationType.Update, + ["Creating shim for 'tool'.", "Can't shim is mentioned but the operation succeeded"], + 0 + ); + + OperationAssert.HasVeredict(veredict, OperationVeredict.Success); + } + + [Fact] + public void OperationResultDoesNotElevateShimFailureWhenElevationProhibited() + { + Settings.Set(Settings.K.ProhibitElevation, true); + var manager = new Scoop(); + var package = new PackageBuilder() + .WithManager(manager) + .WithOptions(new OverridenInstallationOptions(runAsAdministrator: false)) + .Build(); + + var veredict = manager.OperationHelper.GetResult( + package, + OperationType.Update, + ["Can't shim 'notepad++.exe': File doesn't exist."], + 1 + ); + + OperationAssert.HasVeredict(veredict, OperationVeredict.Failure); + Assert.False(package.OverridenOptions.RunAsAdministrator); + } + + private static Scoop CreateManagerWithKnownSources(params string[] sourceNames) + { + var manager = new Scoop(); + manager.SourcesHelper.Factory.AddSource(manager.DefaultSource); + foreach (string sourceName in sourceNames) + { + IManagerSource source = + manager.Properties.KnownSources.FirstOrDefault(source => source.Name == sourceName) + ?? new SourceBuilder() + .WithManager(manager) + .WithName(sourceName) + .WithUrl($"https://example.test/{sourceName}") + .Build(); + manager.SourcesHelper.Factory.AddSource(source); + } + + return manager; + } + + private static string[] ReadFixtureLines(string relativePath) + { + return PackageEngineFixtureFiles.ReadAllText(relativePath).Replace("\r\n", "\n").Split('\n'); + } +} +#endif diff --git a/src/UniGetUI.PackageEngine.Tests/SnapManagerTests.cs b/src/UniGetUI.PackageEngine.Tests/SnapManagerTests.cs new file mode 100644 index 0000000..66877b2 --- /dev/null +++ b/src/UniGetUI.PackageEngine.Tests/SnapManagerTests.cs @@ -0,0 +1,388 @@ +using UniGetUI.Core.Data; +using UniGetUI.Core.SettingsEngine; +using UniGetUI.PackageEngine.Enums; +using UniGetUI.PackageEngine.Managers.SnapManager; +using UniGetUI.PackageEngine.PackageClasses; +using UniGetUI.PackageEngine.Serializable; +using UniGetUI.PackageEngine.Tests.Infrastructure.Assertions; +using UniGetUI.PackageEngine.Tests.Infrastructure.Builders; +using UniGetUI.PackageEngine.Tests.Infrastructure.Helpers; + +namespace UniGetUI.PackageEngine.Tests; + +[CollectionDefinition("Snap manager tests", DisableParallelization = true)] +public sealed class SnapManagerTestCollection +{ + public const string Name = "Snap manager tests"; +} + +[Collection(SnapManagerTestCollection.Name)] +public sealed class SnapManagerTests : IDisposable +{ + private readonly string _testRoot = Path.Combine( + AppContext.BaseDirectory, + nameof(SnapManagerTests), + Guid.NewGuid().ToString("N") + ); + + public SnapManagerTests() + { + Directory.CreateDirectory(_testRoot); + CoreData.TEST_DataDirectoryOverride = Path.Combine(_testRoot, "Data"); + Directory.CreateDirectory(CoreData.UniGetUIUserConfigurationDirectory); + Settings.ResetSettings(); + } + + public void Dispose() + { + Settings.ResetSettings(); + CoreData.TEST_DataDirectoryOverride = null; + if (Directory.Exists(_testRoot)) + { + Directory.Delete(_testRoot, recursive: true); + } + } + + [Fact] + public void ParseInstalledPackagesBuildsPackagesFromFixture() + { + var manager = new Snap(); + + var packages = Snap.ParseInstalledPackages( + File.ReadLines(PackageEngineFixtureFiles.GetPath(Path.Combine("Snap", "installed-list.txt"))), + manager.DefaultSource, + manager + ); + + Assert.Collection( + packages, + package => + { + PackageAssert.Matches(package, "Aspnetcore Runtime 100", "aspnetcore-runtime-100", "10.0.7"); + PackageAssert.BelongsTo(package, manager, manager.DefaultSource); + }, + package => + { + PackageAssert.Matches(package, "Bare", "bare", "1.0"); + PackageAssert.BelongsTo(package, manager, manager.DefaultSource); + }, + package => + { + PackageAssert.Matches(package, "Code", "code", "10c8e557"); + PackageAssert.BelongsTo(package, manager, manager.DefaultSource); + }, + package => + { + PackageAssert.Matches(package, "Core18", "core18", "20260204"); + PackageAssert.BelongsTo(package, manager, manager.DefaultSource); + }, + package => + { + PackageAssert.Matches(package, "Core20", "core20", "20260211"); + PackageAssert.BelongsTo(package, manager, manager.DefaultSource); + }, + package => + { + PackageAssert.Matches(package, "Core22", "core22", "20260225"); + PackageAssert.BelongsTo(package, manager, manager.DefaultSource); + } + ); + } + + [Fact] + public void ParseAvailableUpdatesBuildsPackagesFromFixture() + { + var manager = new Snap(); + + var installedPackages = new List + { + new("Discord", "discord", "0.0.130", manager.DefaultSource, manager), + new("Firefox", "firefox", "149.0", manager.DefaultSource, manager), + }; + + var packages = Snap.ParseAvailableUpdates( + File.ReadLines(PackageEngineFixtureFiles.GetPath(Path.Combine("Snap", "updates-list.txt"))), + manager.DefaultSource, + manager, + installedPackages + ); + + Assert.Collection( + packages, + package => + { + PackageAssert.Matches(package, "Discord", "discord", "0.0.130", "0.0.134"); + Assert.True(package.IsUpgradable); + PackageAssert.BelongsTo(package, manager, manager.DefaultSource); + }, + package => + { + PackageAssert.Matches(package, "Firefox", "firefox", "149.0", "150.0-1"); + Assert.True(package.IsUpgradable); + PackageAssert.BelongsTo(package, manager, manager.DefaultSource); + } + ); + } + + [Fact] + public void ParseSearchResultsBuildsPackagesFromFixture() + { + var manager = new Snap(); + + var packages = Snap.ParseSearchResults( + File.ReadLines(PackageEngineFixtureFiles.GetPath(Path.Combine("Snap", "find-signal.txt"))), + manager.DefaultSource, + manager + ); + + Assert.Collection( + packages, + package => + { + PackageAssert.Matches(package, "Signal Desktop", "signal-desktop", "8.5.0"); + PackageAssert.BelongsTo(package, manager, manager.DefaultSource); + } + ); + } + + [Fact] + public void ParseInstalledPackagesSkipsHeaderAndEmptyLines() + { + var manager = new Snap(); + var lines = new[] + { + "Name Version Rev Tracking Publisher Notes", + "", + " ", + "code 10c8e557 235 latest/stable vscode✓ classic", + }; + + var packages = Snap.ParseInstalledPackages(lines, manager.DefaultSource, manager); + + Assert.Single(packages); + Assert.Equal("code", packages[0].Id); + } + + [Fact] + public void ParseAvailableUpdatesSkipsHeaderAndEmptyLines() + { + var manager = new Snap(); + var lines = new[] + { + "Name Version Rev Size Publisher Notes", + "", + "firefox 150.0-1 8191 288MB mozilla✓ -", + }; + + var installedPackages = new List + { + new Package("Firefox", "firefox", "149.0", manager.DefaultSource, manager), + }; + + var packages = Snap.ParseAvailableUpdates(lines, manager.DefaultSource, manager, installedPackages); + + Assert.Single(packages); + Assert.Equal("firefox", packages[0].Id); + Assert.Equal("149.0", packages[0].VersionString); + Assert.Equal("150.0-1", packages[0].NewVersionString); + } + + [Fact] + public void ParseSearchResultsSkipsHeaderAndEmptyLines() + { + var manager = new Snap(); + var lines = new[] + { + "Name Version Publisher Notes Summary", + "", + "signal-desktop 8.5.0 snapcrafters✪ - Speak Freely - Private Messenger", + }; + + var packages = Snap.ParseSearchResults(lines, manager.DefaultSource, manager); + + Assert.Single(packages); + Assert.Equal("signal-desktop", packages[0].Id); + } + + [Fact] + public void ParseInstalledPackagesReturnsEmptyForNoResults() + { + var manager = new Snap(); + var lines = new[] + { + "Name Version Rev Tracking Publisher Notes", + }; + + var packages = Snap.ParseInstalledPackages(lines, manager.DefaultSource, manager); + + Assert.Empty(packages); + } + + [Fact] + public void ParseAvailableUpdatesReturnsEmptyForNoResults() + { + var manager = new Snap(); + var lines = new[] + { + "Name Version Rev Size Publisher Notes", + }; + + var packages = Snap.ParseAvailableUpdates(lines, manager.DefaultSource, manager, []); + Assert.Empty(packages); + } + + [Fact] + public void ParseSearchResultsReturnsEmptyForNoResults() + { + var manager = new Snap(); + var lines = new[] + { + "Name Version Publisher Notes Summary", + }; + + var packages = Snap.ParseSearchResults(lines, manager.DefaultSource, manager); + + Assert.Empty(packages); + } + + [Fact] + public void OperationHelperBuildsInstallAndUninstallParameters() + { + var manager = new Snap(); + var package = new PackageBuilder() + .WithManager(manager) + .WithId("signal-desktop") + .Build(); + var installOptions = new InstallOptions + { + CustomParameters_Install = ["--classic"], + }; + var uninstallOptions = new InstallOptions(); + + var installParameters = manager.OperationHelper.GetParameters( + package, + installOptions, + OperationType.Install + ); + var uninstallParameters = manager.OperationHelper.GetParameters( + package, + uninstallOptions, + OperationType.Uninstall + ); + + Assert.Equal( + [ + "install", + "signal-desktop", + "--classic", + ], + installParameters + ); + Assert.Equal( + [ + "remove", + "signal-desktop", + "--purge", + ], + uninstallParameters + ); + } + + [Fact] + public void OperationHelperForcesAdministratorForAllOperations() + { + var manager = new Snap(); + var package = new PackageBuilder() + .WithManager(manager) + .WithId("firefox") + .Build(); + var options = new InstallOptions(); + + _ = manager.OperationHelper.GetParameters(package, options, OperationType.Install); + Assert.True(options.RunAsAdministrator); + + options = new InstallOptions(); + _ = manager.OperationHelper.GetParameters(package, options, OperationType.Update); + Assert.True(options.RunAsAdministrator); + + options = new InstallOptions(); + _ = manager.OperationHelper.GetParameters(package, options, OperationType.Uninstall); + Assert.True(options.RunAsAdministrator); + } + + [Fact] + public void OperationHelperReturnsSuccessOnZeroExitCode() + { + var manager = new Snap(); + var package = new PackageBuilder() + .WithManager(manager) + .WithId("firefox") + .Build(); + + var result = manager.OperationHelper.GetResult( + package, + OperationType.Install, + ["Setting up firefox..."], + 0 + ); + + Assert.Equal(OperationVeredict.Success, result); + } + + [Fact] + public void OperationHelperReturnsFailureOnNonZeroExitCode() + { + var manager = new Snap(); + var package = new PackageBuilder() + .WithManager(manager) + .WithId("firefox") + .Build(); + + var result = manager.OperationHelper.GetResult( + package, + OperationType.Install, + ["error: something went wrong"], + 1 + ); + + Assert.Equal(OperationVeredict.Failure, result); + } + + [Fact] + public void ManagerHasCorrectCapabilities() + { + var manager = new Snap(); + + Assert.True(manager.Capabilities.CanRunAsAdmin); + Assert.True(manager.Capabilities.CanSkipIntegrityChecks); + Assert.False(manager.Capabilities.SupportsCustomSources); + } + + [Fact] + public void ManagerHasCorrectProperties() + { + var manager = new Snap(); + + Assert.Equal("Snap", manager.Name); + Assert.Equal("snap", manager.Properties.ExecutableFriendlyName); + Assert.Equal("install", manager.Properties.InstallVerb); + Assert.Equal("refresh", manager.Properties.UpdateVerb); + Assert.Equal("remove", manager.Properties.UninstallVerb); + Assert.Equal("snapcraft", manager.DefaultSource.Name); + Assert.Equal("https://snapcraft.io/", manager.DefaultSource.Url.ToString()); + } + + [Fact] + public void GetInstallableVersionsReturnsEmptyList() + { + var manager = new Snap(); + var package = new PackageBuilder() + .WithManager(manager) + .WithId("signal-desktop") + .Build(); + + var versions = manager.DetailsHelper.GetVersions(package); + + Assert.Empty(versions); + } +} diff --git a/src/UniGetUI.PackageEngine.Tests/SourceOperationsTests.cs b/src/UniGetUI.PackageEngine.Tests/SourceOperationsTests.cs new file mode 100644 index 0000000..aac5e09 --- /dev/null +++ b/src/UniGetUI.PackageEngine.Tests/SourceOperationsTests.cs @@ -0,0 +1,169 @@ +using System.Diagnostics; +using UniGetUI.Core.Data; +using UniGetUI.Core.SettingsEngine; +using UniGetUI.PackageEngine.Enums; +using UniGetUI.PackageEngine.Interfaces; +using UniGetUI.PackageEngine.Operations; +using UniGetUI.PackageEngine.Tests.Infrastructure.Builders; +using UniGetUI.PackageOperations; + +namespace UniGetUI.PackageEngine.Tests; + +[Collection(nameof(OperationOrchestrationTestCollection))] +public sealed class SourceOperationsTests +{ + [Fact] + public void RetryAsAdminSetsForceAsAdministrator() + { + var source = CreateSource(); + using var operation = new InspectableAddSourceOperation(source); + + operation.Retry(AbstractOperation.RetryMode.Retry_AsAdmin); + + Assert.True(operation.ForceAsAdministrator); + Assert.Throws( + () => operation.Retry(AbstractOperation.RetryMode.Retry_Interactive) + ); + } + + [Fact] + public void AddSourcePrepareProcessStartInfoUsesManagerExecutableWithoutAdmin() + { + var manager = new PackageManagerBuilder() + .ConfigureManager(manager => + { + manager.ExecutablePath = "C:\\tools\\sources.exe"; + manager.ExecutableArguments = "--cli"; + }) + .ConfigureSources(helper => helper.AddParametersFactory = source => ["source", "add", source.Name]) + .Build(); + var source = new SourceBuilder().WithManager(manager).WithName("community").Build(); + using var operation = new InspectableAddSourceOperation(source); + AbstractOperation.BadgeCollection? badges = null; + operation.BadgesChanged += (_, updatedBadges) => badges = updatedBadges; + + var startInfo = operation.PrepareProcessStartInfoForTests(); + + Assert.Equal("C:\\tools\\sources.exe", startInfo.FileName); + Assert.Equal("--cli source add community", startInfo.Arguments.Trim()); + Assert.NotNull(badges); + Assert.False(badges!.AsAdministrator); + } + + [Fact] + public void RemoveSourcePrepareProcessStartInfoUsesElevatorWhenAdminRequired() + { + using var prohibitElevation = new BooleanSettingScope(Settings.K.ProhibitElevation, false); + var manager = new PackageManagerBuilder() + .ConfigureCapabilities(capabilities => + { + var sourceCapabilities = capabilities.Sources; + sourceCapabilities.MustBeInstalledAsAdmin = true; + capabilities.Sources = sourceCapabilities; + return capabilities; + }) + .ConfigureManager(manager => + { + manager.ExecutablePath = "C:\\tools\\sources.exe"; + manager.ExecutableArguments = "--cli"; + }) + .ConfigureSources(helper => + helper.RemoveParametersFactory = source => ["source", "remove", source.Name] + ) + .Build(); + var source = new SourceBuilder().WithManager(manager).WithName("community").Build(); + using var operation = new InspectableRemoveSourceOperation(source); + AbstractOperation.BadgeCollection? badges = null; + operation.BadgesChanged += (_, updatedBadges) => badges = updatedBadges; + + var startInfo = operation.PrepareProcessStartInfoForTests(); + + Assert.Equal(CoreData.ElevatorPath, startInfo.FileName); + Assert.Equal("\"C:\\tools\\sources.exe\" --cli source remove community", startInfo.Arguments); + Assert.NotNull(badges); + Assert.True(badges!.AsAdministrator); + } + + private static IManagerSource CreateSource() + { + return new SourceBuilder().WithManager(new PackageManagerBuilder().Build()).Build(); + } + + private sealed class InspectableAddSourceOperation : AddSourceOperation + { + public InspectableAddSourceOperation(IManagerSource source) + : base(source) { } + + public ProcessStartInfo PrepareProcessStartInfoForTests() + { + InitializeProcessStartInfoDefaults(); + PrepareProcessStartInfo(); + return process.StartInfo; + } + + private void InitializeProcessStartInfoDefaults() + { + process.StartInfo.UseShellExecute = false; + process.StartInfo.RedirectStandardOutput = true; + process.StartInfo.RedirectStandardInput = true; + process.StartInfo.RedirectStandardError = true; + process.StartInfo.CreateNoWindow = true; + process.StartInfo.StandardOutputEncoding = System.Text.Encoding.UTF8; + process.StartInfo.StandardErrorEncoding = System.Text.Encoding.UTF8; + process.StartInfo.StandardInputEncoding = System.Text.Encoding.UTF8; + process.StartInfo.WorkingDirectory = Environment.GetFolderPath( + Environment.SpecialFolder.UserProfile + ); + process.StartInfo.FileName = "lol"; + process.StartInfo.Arguments = "lol"; + } + } + + private sealed class InspectableRemoveSourceOperation : RemoveSourceOperation + { + public InspectableRemoveSourceOperation(IManagerSource source) + : base(source) { } + + public ProcessStartInfo PrepareProcessStartInfoForTests() + { + InitializeProcessStartInfoDefaults(); + PrepareProcessStartInfo(); + return process.StartInfo; + } + + private void InitializeProcessStartInfoDefaults() + { + process.StartInfo.UseShellExecute = false; + process.StartInfo.RedirectStandardOutput = true; + process.StartInfo.RedirectStandardInput = true; + process.StartInfo.RedirectStandardError = true; + process.StartInfo.CreateNoWindow = true; + process.StartInfo.StandardOutputEncoding = System.Text.Encoding.UTF8; + process.StartInfo.StandardErrorEncoding = System.Text.Encoding.UTF8; + process.StartInfo.StandardInputEncoding = System.Text.Encoding.UTF8; + process.StartInfo.WorkingDirectory = Environment.GetFolderPath( + Environment.SpecialFolder.UserProfile + ); + process.StartInfo.FileName = "lol"; + process.StartInfo.Arguments = "lol"; + } + } + + private sealed class BooleanSettingScope : IDisposable + { + private readonly Settings.K _key; + private readonly bool _originalValue; + + public BooleanSettingScope(Settings.K key, bool value) + { + _key = key; + _originalValue = Settings.Get(key); + Settings.Set(key, value); + } + + public void Dispose() + { + Settings.Set(_key, _originalValue); + } + } +} diff --git a/src/UniGetUI.PackageEngine.Tests/TestAssembly.cs b/src/UniGetUI.PackageEngine.Tests/TestAssembly.cs new file mode 100644 index 0000000..2171200 --- /dev/null +++ b/src/UniGetUI.PackageEngine.Tests/TestAssembly.cs @@ -0,0 +1,3 @@ +using Xunit; + +[assembly: CollectionBehavior(DisableTestParallelization = true)] diff --git a/src/UniGetUI.PackageEngine.Tests/UniGetUI.PackageEngine.Tests.csproj b/src/UniGetUI.PackageEngine.Tests/UniGetUI.PackageEngine.Tests.csproj new file mode 100644 index 0000000..a978364 --- /dev/null +++ b/src/UniGetUI.PackageEngine.Tests/UniGetUI.PackageEngine.Tests.csproj @@ -0,0 +1,59 @@ + + + + $(SharedTargetFrameworks) + false + true + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/UniGetUI.PackageEngine.Tests/UpgradablePackagesLoaderTests.cs b/src/UniGetUI.PackageEngine.Tests/UpgradablePackagesLoaderTests.cs new file mode 100644 index 0000000..f1aa681 --- /dev/null +++ b/src/UniGetUI.PackageEngine.Tests/UpgradablePackagesLoaderTests.cs @@ -0,0 +1,144 @@ +using UniGetUI.Core.Data; +using UniGetUI.Core.SettingsEngine; +using UniGetUI.Core.SettingsEngine.SecureSettings; +using UniGetUI.Interface.Enums; +using UniGetUI.PackageEngine.PackageClasses; +using UniGetUI.PackageEngine.PackageLoader; +using UniGetUI.PackageEngine.Serializable; +using UniGetUI.PackageEngine.Structs; +using UniGetUI.PackageEngine.Tests.Infrastructure.Builders; +using UniGetUI.PackageEngine.Tests.Infrastructure.Fakes; + +namespace UniGetUI.PackageEngine.Tests; + +public sealed class UpgradablePackagesLoaderTests : IDisposable +{ + private readonly string _testRoot = Path.Combine( + Path.GetTempPath(), + nameof(UpgradablePackagesLoaderTests), + Guid.NewGuid().ToString("N") + ); + + public UpgradablePackagesLoaderTests() + { + Directory.CreateDirectory(_testRoot); + CoreData.TEST_DataDirectoryOverride = Path.Combine(_testRoot, "Data"); + SecureSettings.TEST_SecureSettingsRootOverride = Path.Combine(_testRoot, "SecureSettings"); + Directory.CreateDirectory(CoreData.UniGetUIUserConfigurationDirectory); + Directory.CreateDirectory(CoreData.UniGetUIInstallationOptionsDirectory); + Settings.ResetSettings(); + } + + public void Dispose() + { + Settings.ResetSettings(); + CoreData.TEST_DataDirectoryOverride = null; + SecureSettings.TEST_SecureSettingsRootOverride = null; + if (Directory.Exists(_testRoot)) + { + Directory.Delete(_testRoot, recursive: true); + } + } + + [Fact] + public async Task EvaluatePackageAsync_SkipsMinorUpdatesWhenConfigured() + { + var manager = new PackageManagerBuilder().Build(); + _ = new InstalledPackagesLoader([manager]); + _ = new DiscoverablePackagesLoader([manager]); + var loader = new TestUpgradablePackagesLoader([manager]); + var package = new PackageBuilder() + .WithManager(manager) + .WithId("Contoso.Tool") + .WithVersion("1.0.0") + .WithNewVersion("1.0.1") + .Build(); + + InstallOptionsFactory.SaveForPackage( + new InstallOptions + { + OverridesNextLevelOpts = true, + SkipMinorUpdates = true, + }, + package + ); + + Assert.False(await loader.EvaluatePackageAsync(package)); + } + + [Fact] + public async Task EvaluatePackageAsync_SkipsIgnoredAndSupersededPackages() + { + var manager = new PackageManagerBuilder().Build(); + var installedLoader = new InstalledPackagesLoader([manager]); + _ = new DiscoverablePackagesLoader([manager]); + var loader = new TestUpgradablePackagesLoader([manager]); + var ignoredPackage = new PackageBuilder() + .WithManager(manager) + .WithId("Contoso.Ignored") + .WithVersion("1.0.0") + .WithNewVersion("2.0.0") + .Build(); + var supersededPackage = new PackageBuilder() + .WithManager(manager) + .WithId("Contoso.Superseded") + .WithVersion("1.0.0") + .WithNewVersion("2.0.0") + .Build(); + + await ignoredPackage.AddToIgnoredUpdatesAsync("2.0.0"); + await installedLoader.AddForeign( + new PackageBuilder() + .WithManager(manager) + .WithId("Contoso.Superseded") + .WithVersion("3.0.0") + .Build() + ); + + Assert.False(await loader.EvaluatePackageAsync(ignoredPackage)); + Assert.Contains("Contoso.Ignored", loader.IgnoredPackages.Keys); + Assert.False(await loader.EvaluatePackageAsync(supersededPackage)); + } + + [Fact] + public async Task ApplyWhenAddingPackageAsync_UpdatesDiscoverableAndInstalledTags() + { + var manager = new PackageManagerBuilder().Build(); + var installedLoader = new InstalledPackagesLoader([manager]); + var discoverableLoader = new DiscoverablePackagesLoader([manager]); + var loader = new TestUpgradablePackagesLoader([manager]); + var availablePackage = new PackageBuilder().WithManager(manager).WithId("Contoso.Tagged").Build(); + var installedPackage = new PackageBuilder().WithManager(manager).WithId("Contoso.Tagged").Build(); + var upgradablePackage = new PackageBuilder() + .WithManager(manager) + .WithId("Contoso.Tagged") + .WithVersion("1.0.0") + .WithNewVersion("2.0.0") + .Build(); + + await discoverableLoader.AddForeign(availablePackage); + await installedLoader.AddForeign(installedPackage); + + await loader.ApplyWhenAddingPackageAsync(upgradablePackage); + + Assert.Equal(PackageTag.IsUpgradable, availablePackage.Tag); + Assert.Equal(PackageTag.IsUpgradable, installedPackage.Tag); + } + + [Theory] + [InlineData("120", 120000)] + [InlineData("not-a-number", 3600000)] + public void StartTimer_UsesConfiguredIntervalOrDefault(string configuredValue, double expectedInterval) + { + var manager = new PackageManagerBuilder().Build(); + _ = new InstalledPackagesLoader([manager]); + _ = new DiscoverablePackagesLoader([manager]); + var loader = new TestUpgradablePackagesLoader([manager]); + Settings.Set(Settings.K.DisableAutoCheckforUpdates, false); + Settings.SetValue(Settings.K.UpdatesCheckInterval, configuredValue); + + loader.StartTimer(); + + Assert.Equal(expectedInterval, loader.GetTimerIntervalMilliseconds()); + } +} diff --git a/src/UniGetUI.PackageEngine.Tests/WinGetManagerTests.cs b/src/UniGetUI.PackageEngine.Tests/WinGetManagerTests.cs new file mode 100644 index 0000000..4862a21 --- /dev/null +++ b/src/UniGetUI.PackageEngine.Tests/WinGetManagerTests.cs @@ -0,0 +1,1250 @@ +#if WINDOWS +using Devolutions.Pinget.Core; +using UniGetUI.Core.Data; +using UniGetUI.Core.SettingsEngine; +using UniGetUI.PackageEngine.Classes.Manager; +using UniGetUI.PackageEngine.Enums; +using UniGetUI.PackageEngine.Interfaces; +using UniGetUI.PackageEngine.Managers.WingetManager; +using UniGetUI.PackageEngine.ManagerClasses.Classes; +using UniGetUI.PackageEngine.PackageClasses; +using UniGetUI.PackageEngine.Serializable; +using UniGetUI.PackageEngine.Tests.Infrastructure.Assertions; +using UniGetUI.PackageEngine.Tests.Infrastructure.Builders; + +namespace UniGetUI.PackageEngine.Tests; + +[CollectionDefinition("WinGet manager tests", DisableParallelization = true)] +public sealed class WinGetManagerTestCollection +{ + public const string Name = "WinGet manager tests"; +} + +[Collection(WinGetManagerTestCollection.Name)] +public sealed class WinGetManagerTests : IDisposable +{ + private readonly string _testRoot = Path.Combine( + AppContext.BaseDirectory, + "WinGetManagerTests", + Guid.NewGuid().ToString("N") + ); + + public WinGetManagerTests() + { + Directory.CreateDirectory(_testRoot); + CoreData.TEST_DataDirectoryOverride = Path.Combine(_testRoot, "Data"); + SetNoPackagesHaveBeenLoaded(false); + Settings.Set(Settings.K.EnableProxy, false); + Settings.Set(Settings.K.EnableProxyAuth, false); + Settings.SetValue(Settings.K.ProxyURL, ""); + Settings.SetValue(Settings.K.WinGetCliToolPreference, ""); + Settings.SetValue(Settings.K.WinGetComApiPolicy, ""); + } + + public void Dispose() + { + SetNoPackagesHaveBeenLoaded(false); + WinGetHelper.Instance = null!; + CoreData.TEST_DataDirectoryOverride = null; + if (Directory.Exists(_testRoot)) + { + Directory.Delete(_testRoot, recursive: true); + } + } + + [Fact] + public void GetProxyArgumentReturnsEmptyStringWhenProxyIsDisabled() + { + Settings.Set(Settings.K.EnableProxy, false); + Settings.SetValue(Settings.K.ProxyURL, "http://proxy.example.test:3128/"); + + Assert.Equal("", WinGet.GetProxyArgument()); + } + + [Fact] + public void GetProxyArgumentReturnsTrimmedProxyArgumentWhenProxyIsEnabled() + { + Settings.Set(Settings.K.EnableProxy, true); + Settings.Set(Settings.K.EnableProxyAuth, false); + Settings.SetValue(Settings.K.ProxyURL, "http://proxy.example.test:3128/"); + + Assert.Equal("--proxy http://proxy.example.test:3128", WinGet.GetProxyArgument()); + } + + [Fact] + public void GetProxyArgumentReturnsEmptyStringWhenProxyAuthIsEnabled() + { + Settings.Set(Settings.K.EnableProxy, true); + Settings.Set(Settings.K.EnableProxyAuth, true); + Settings.SetValue(Settings.K.ProxyURL, "http://proxy.example.test:3128/"); + + Assert.Equal("", WinGet.GetProxyArgument()); + } + + [Theory] + [MemberData(nameof(LocalSourceCases))] + public void GetLocalSourceClassifiesKnownSourceFamilies( + string id, + LocalSourceKind expectedSourceKind + ) + { + var manager = new WinGet(); + + var source = manager.GetLocalSource(id); + + Assert.Same(GetExpectedSource(manager, expectedSourceKind), source); + } + + public static TheoryData LocalSourceCases => + new() + { + { "MSIX\\Microsoft.WindowsStore_8wekyb3d8bbwe", LocalSourceKind.MicrosoftStore }, + { "Programs\\{12345678-1234-1234-1234-123456789ABC}", LocalSourceKind.LocalPc }, + { "Apps\\com.example.android.app", LocalSourceKind.Android }, + { "Games\\Steam", LocalSourceKind.Steam }, + { "Games\\Steam App 12345", LocalSourceKind.Steam }, + { "Games\\Uplay", LocalSourceKind.Ubisoft }, + { "Games\\Uplay Install 12345", LocalSourceKind.Ubisoft }, + { "Games\\123456789_is1", LocalSourceKind.Gog }, + { "Programs\\Contoso.App", LocalSourceKind.LocalPc }, + }; + + [Fact] + public void GetInstalledPackagesUpdatesNoPackagesFlagForFailureAndRecovery() + { + var manager = new TestableWinGet(); + var expectedPackage = new PackageBuilder() + .WithManager(manager) + .WithName("Contoso Tool") + .WithId("Contoso.Tool") + .WithVersion("1.2.3") + .Build(); + var helper = new TestWinGetManagerHelper + { + GetInstalledPackagesHandler = () => throw new InvalidOperationException("boom"), + }; + WinGetHelper.Instance = helper; + + Assert.Throws(manager.InvokeGetInstalledPackages); + Assert.True(WinGet.NO_PACKAGES_HAVE_BEEN_LOADED); + + helper.GetInstalledPackagesHandler = () => [expectedPackage]; + + var packages = manager.InvokeGetInstalledPackages(); + + Assert.False(WinGet.NO_PACKAGES_HAVE_BEEN_LOADED); + PackageAssert.Matches(Assert.Single(packages), "Contoso Tool", "Contoso.Tool", "1.2.3"); + } + + [Fact] + public void NativeWinGetHelperPrefersSystemComBeforeBundledActivation() + { + Assert.Equal( + ["packaged COM registration", "lower-trust COM registration"], + NativeWinGetHelper.PreferredActivationModes + ); + } + + [Fact] + public void GetBundledPingetExecutablePathPrefersRootExecutable() + { + const string installDir = @"C:\Program Files\UniGetUI"; + string rootPinget = Path.Join(installDir, "pinget.exe"); + string avaloniaPinget = Path.Join(installDir, "Avalonia", "pinget.exe"); + + string path = WinGet.GetBundledPingetExecutablePath( + installDir, + filePath => filePath == rootPinget || filePath == avaloniaPinget + ); + + Assert.Equal(rootPinget, path); + } + + [Fact] + public void GetBundledPingetExecutablePathFindsRootExecutableFromAvaloniaDirectory() + { + const string installDir = @"C:\Program Files\UniGetUI"; + string avaloniaDir = Path.Join(installDir, "Avalonia"); + string rootPinget = Path.Join(installDir, "pinget.exe"); + + string path = WinGet.GetBundledPingetExecutablePath( + avaloniaDir, + filePath => filePath == rootPinget + ); + + Assert.Equal(rootPinget, path); + } + + [Fact] + public void GetBundledPingetExecutablePathFallsBackToAvaloniaExecutable() + { + const string installDir = @"C:\Program Files\UniGetUI"; + string avaloniaPinget = Path.Join(installDir, "Avalonia", "pinget.exe"); + + string path = WinGet.GetBundledPingetExecutablePath( + installDir, + filePath => filePath == avaloniaPinget + ); + + Assert.Equal(avaloniaPinget, path); + } + + [Fact] + public void GetBundledPingetExecutablePathReturnsRootPathWhenNoExecutableExists() + { + const string installDir = @"C:\Program Files\UniGetUI"; + string rootPinget = Path.Join(installDir, "pinget.exe"); + + string path = WinGet.GetBundledPingetExecutablePath(installDir, static _ => false); + + Assert.Equal(rootPinget, path); + } + + [Fact] + public void FindCandidateExecutableFilesPrefersSystemWinGetBeforeBundledPinget() + { + const string systemWinGet = @"C:\WindowsApps\winget.exe"; + const string bundledPinget = @"C:\Program Files\UniGetUI\pinget.exe"; + + var candidates = WinGet.FindCandidateExecutableFiles( + static executableName => executableName == "winget.exe" ? [systemWinGet] : [], + path => path == bundledPinget, + bundledPinget + ); + + Assert.Equal([systemWinGet, bundledPinget], candidates); + } + + [Fact] + public void FindCandidateExecutableFilesUsesBundledPingetWhenSystemWinGetIsMissing() + { + const string bundledPinget = @"C:\Program Files\UniGetUI\pinget.exe"; + + var candidates = WinGet.FindCandidateExecutableFiles( + static _ => [], + path => path == bundledPinget, + bundledPinget + ); + + Assert.Equal([bundledPinget], candidates); + } + + [Fact] + public void FindCandidateExecutableFilesCanUseSystemWinGetWithoutBundledPingetFallback() + { + const string systemWinGet = @"C:\WindowsApps\winget.exe"; + const string bundledPinget = @"C:\Program Files\UniGetUI\pinget.exe"; + + var candidates = WinGet.FindCandidateExecutableFiles( + static executableName => executableName == "winget.exe" ? [systemWinGet] : [], + path => path == bundledPinget, + bundledPinget, + WinGetCliToolPreference.SystemWinGet + ); + + Assert.Equal([systemWinGet], candidates); + } + + [Fact] + public void FindCandidateExecutableFilesCanUseBundledPingetWithoutSystemWinGetFallback() + { + const string systemWinGet = @"C:\WindowsApps\winget.exe"; + const string bundledPinget = @"C:\Program Files\UniGetUI\pinget.exe"; + + var candidates = WinGet.FindCandidateExecutableFiles( + static executableName => executableName == "winget.exe" ? [systemWinGet] : [], + path => path == bundledPinget, + bundledPinget, + WinGetCliToolPreference.BundledPinget + ); + + Assert.Equal([bundledPinget], candidates); + } + + [Fact] + public void FindCandidateExecutableFilesCanUsePathPingetWithoutSystemWinGetFallback() + { + const string bundledPinget = @"C:\Program Files\UniGetUI\pinget.exe"; + const string pathPinget = @"C:\Tools\pinget.exe"; + + var candidates = WinGet.FindCandidateExecutableFiles( + static executableName => + executableName switch + { + "winget.exe" => throw new InvalidOperationException( + "System WinGet should not be queried in Pinget mode." + ), + "pinget.exe" => [pathPinget], + _ => [], + }, + static _ => false, + bundledPinget, + WinGetCliToolPreference.BundledPinget + ); + + Assert.Equal([pathPinget], candidates); + } + + [Fact] + public void FindCandidateExecutableFilesReturnsEmptyWhenNoCliToolExists() + { + var candidates = WinGet.FindCandidateExecutableFiles( + static _ => [], + static _ => false, + @"C:\Program Files\UniGetUI\pinget.exe" + ); + + Assert.Empty(candidates); + } + + [Fact] + public void PingetCliHelperDeserializesListResponsesWithGeneratedContext() + { + // Pinget emits PascalCase keys. + const string json = """ + { + "Matches": [ + { + "Name": "Contoso Tool", + "Id": "Contoso.Tool", + "LocalId": null, + "InstalledVersion": "1.2.3", + "AvailableVersion": "2.0.0", + "SourceName": "winget", + "Publisher": null, + "Scope": null, + "InstallerCategory": null, + "InstallLocation": null, + "PackageFamilyNames": [], + "ProductCodes": [], + "UpgradeCodes": [] + } + ], + "Warnings": [], + "Truncated": false + } + """; + + ListResponse response = PingetCliHelper.DeserializeJson(json); + + ListMatch match = Assert.Single(response.Matches); + Assert.Equal("Contoso Tool", match.Name); + Assert.Equal("Contoso.Tool", match.Id); + Assert.Equal("1.2.3", match.InstalledVersion); + Assert.Equal("2.0.0", match.AvailableVersion); + Assert.Equal("winget", match.SourceName); + } + + [Fact] + public void PingetCliHelperInfersWingetSourceWhenInstalledSourceNameIsMissing() + { + const string json = """ + { + "Matches": [ + { + "Name": "Contoso Tool", + "Id": "ARP\\User\\X64\\Contoso.Tool_Microsoft.Winget.Source_8wekyb3d8bbwe", + "LocalId": null, + "InstalledVersion": "1.2.3", + "AvailableVersion": null, + "SourceName": null, + "Publisher": "Contoso", + "Scope": "User", + "InstallerCategory": "exe", + "InstallLocation": "C:\\Users\\example\\AppData\\Local\\Microsoft\\WinGet\\Packages\\Contoso.Tool_Microsoft.Winget.Source_8wekyb3d8bbwe", + "PackageFamilyNames": [], + "ProductCodes": [], + "UpgradeCodes": [] + } + ], + "Warnings": [], + "Truncated": false + } + """; + + ListMatch match = Assert.Single(PingetCliHelper.DeserializeJson(json).Matches); + + Assert.Equal("winget", PingetCliHelper.InferSourceName(match)); + } + + [Fact] + public void GetCliToolPreferenceUsesEnvironmentBeforeSettings() + { + var preference = WinGet.GetCliToolPreference( + name => name == WinGet.CliToolPreferenceEnvironmentVariable ? "pinget" : null, + key => key == Settings.K.WinGetCliToolPreference ? "winget" : "" + ); + + Assert.Equal(WinGetCliToolPreference.BundledPinget, preference); + } + + [Fact] + public void GetCliToolPreferenceFallsBackToSettings() + { + var preference = WinGet.GetCliToolPreference( + static _ => null, + key => key == Settings.K.WinGetCliToolPreference ? "pinget" : "" + ); + + Assert.Equal(WinGetCliToolPreference.BundledPinget, preference); + } + + [Theory] + [InlineData("default", 0)] + [InlineData("winget", 1)] + [InlineData("pinget", 2)] + public void GetCliToolPreferenceAcceptsSupportedValues( + string value, + int expectedPreference + ) + { + var preference = WinGet.GetCliToolPreference( + static _ => null, + key => key == Settings.K.WinGetCliToolPreference ? value : "" + ); + + Assert.Equal((WinGetCliToolPreference)expectedPreference, preference); + } + + [Theory] + [InlineData(@"C:\Program Files\UniGetUI\pinget.exe", 1)] + [InlineData(@"C:\Tools\pinget.exe", 1)] + [InlineData(@"C:\WindowsApps\winget.exe", 0)] + public void GetCliToolKindRecognizesPingetExecutableName( + string executablePath, + int expectedKind + ) + { + Assert.Equal((WinGetCliToolKind)expectedKind, WinGet.GetCliToolKind(executablePath)); + } + + [Theory] + [InlineData("auto")] + [InlineData("system")] + [InlineData("bundled-pinget")] + [InlineData("pinget-only")] + public void GetCliToolPreferenceIgnoresUnsupportedValues(string value) + { + var preference = WinGet.GetCliToolPreference( + static _ => null, + key => key == Settings.K.WinGetCliToolPreference ? value : "" + ); + + Assert.Equal(WinGetCliToolPreference.Default, preference); + } + + [Fact] + public void GetComApiPolicyUsesEnvironmentBeforeSettings() + { + var policy = WinGet.GetComApiPolicy( + name => name == WinGet.ComApiPolicyEnvironmentVariable ? "disabled" : null, + key => key == Settings.K.WinGetComApiPolicy ? "enabled" : "" + ); + + Assert.Equal(WinGetComApiPolicy.Disabled, policy); + } + + [Fact] + public void GetComApiPolicyAcceptsDefaultValue() + { + var policy = WinGet.GetComApiPolicy( + static _ => null, + key => key == Settings.K.WinGetComApiPolicy ? "default" : "" + ); + + Assert.Equal(WinGetComApiPolicy.Default, policy); + } + + [Fact] + public void ShouldUseWinGetComApiAllowsSystemCliToolWhenPolicyAllowsComApi() + { + Assert.True( + WinGet.ShouldUseWinGetComApi( + WinGetCliToolKind.SystemWinGet, + WinGetComApiPolicy.Default + ) + ); + Assert.True( + WinGet.ShouldUseWinGetComApi( + WinGetCliToolKind.SystemWinGet, + WinGetComApiPolicy.Enabled + ) + ); + } + + [Fact] + public void ShouldUseWinGetComApiCanDisableComForSystemCliTool() + { + Assert.False( + WinGet.ShouldUseWinGetComApi( + WinGetCliToolKind.SystemWinGet, + WinGetComApiPolicy.Disabled + ) + ); + } + + [Fact] + public void ShouldUseWinGetComApiNeverUsesComForBundledPingetCliTool() + { + Assert.False( + WinGet.ShouldUseWinGetComApi( + WinGetCliToolKind.BundledPinget, + WinGetComApiPolicy.Default + ) + ); + Assert.False( + WinGet.ShouldUseWinGetComApi( + WinGetCliToolKind.BundledPinget, + WinGetComApiPolicy.Enabled + ) + ); + } + + [Fact] + public void CreateCliHelperForSelectedCliToolUsesExplicitExecutablePath() + { + var manager = new WinGet(); + SetCliToolKind(manager, WinGetCliToolKind.SystemWinGet); + + IWinGetManagerHelper helper = manager.CreateCliHelperForSelectedCliTool( + @"C:\WindowsApps\winget.exe" + ); + + var pathField = typeof(WinGetCliHelper).GetField( + "_cliExecutablePath", + System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic + ); + + Assert.NotNull(pathField); + Assert.Equal(@"C:\WindowsApps\winget.exe", pathField.GetValue(helper)); + } + + [Fact] + public void NativeWinGetHelperUsesSystemCliFallbackForInstalledPackagesWhenCompositeCatalogFails() + { + var manager = new TestableWinGet(); + var expectedPackage = new PackageBuilder() + .WithManager(manager) + .WithName("Contoso Tool") + .WithId("Contoso.Tool") + .WithVersion("1.2.3") + .Build(); + var systemCliFallbackHelper = new TestWinGetManagerHelper + { + GetInstalledPackagesHandler = () => [expectedPackage], + }; + var helper = new NativeWinGetHelper( + manager, + systemCliHelperFactory: _ => systemCliFallbackHelper, + skipInitialization: true, + localPackagesProvider: () => + throw new InvalidOperationException("WinGet: Failed to connect to composite catalog.") + ); + + var packages = helper.GetInstalledPackages_UnSafe(); + + PackageAssert.Matches(Assert.Single(packages), "Contoso Tool", "Contoso.Tool", "1.2.3"); + } + + [Fact] + public void NativeWinGetHelperUsesSystemCliFallbackForUpdatesWhenCompositeCatalogFails() + { + var manager = new TestableWinGet(); + var expectedPackage = new PackageBuilder() + .WithManager(manager) + .WithName("Contoso Tool") + .WithId("Contoso.Tool") + .WithVersion("1.2.3") + .WithNewVersion("2.0.0") + .Build(); + var systemCliFallbackHelper = new TestWinGetManagerHelper + { + GetAvailableUpdatesHandler = () => [expectedPackage], + }; + var helper = new NativeWinGetHelper( + manager, + systemCliHelperFactory: _ => systemCliFallbackHelper, + skipInitialization: true, + localPackagesProvider: () => + throw new InvalidOperationException("WinGet: Failed to connect to composite catalog.") + ); + + var packages = helper.GetAvailableUpdates_UnSafe(); + + var package = Assert.Single(packages); + Assert.Equal("Contoso.Tool", package.Id); + Assert.Equal("2.0.0", package.NewVersionString); + } + + [Fact] + public void NativeWinGetHelperSelectReachableCatalogsSkipsUnavailableSources() + { + var reachableCatalogs = NativeWinGetHelper.SelectReachableCatalogs( + ["winget", "offline", "msstore"], + static catalog => catalog, + static catalog => catalog != "offline" + ); + + Assert.Equal(["winget", "msstore"], reachableCatalogs); + } + + [Fact] + public void NativeWinGetHelperSelectReachableCatalogsThrowsWhenAllSourcesAreUnavailable() + { + var exception = Assert.Throws(() => + NativeWinGetHelper.SelectReachableCatalogs( + ["offline-a", "offline-b"], + static catalog => catalog, + static _ => false + ) + ); + + Assert.Equal("WinGet: Failed to connect to composite catalog.", exception.Message); + } + + [Fact] + public void AttemptFastRepairKeepsNativeHelperWhileLocalPackageEnumerationIsStillRunning() + { + var manager = new TestableWinGet(); + var helper = new NativeWinGetHelper( + manager, + systemCliHelperFactory: null, + skipInitialization: true, + localPackagesProvider: null + ); + helper.SetLocalPackageQueryInProgressForTesting(true); + WinGetHelper.Instance = helper; + + manager.AttemptFastRepair(); + + Assert.Same(helper, WinGetHelper.Instance); + } + + [Fact] + public void PingetPackageDetailsProviderMapsShowResultToPackageDetails() + { + var manager = new WinGet(); + var package = new PackageBuilder() + .WithManager(manager) + .WithName("Contoso Tool") + .WithId("Contoso.Tool") + .WithVersion("1.0.0") + .Build(); + var details = new PackageDetails(package); + PackageQuery? capturedQuery = null; + var provider = new PingetPackageDetailsProvider( + query => + { + capturedQuery = query; + return CreatePingetShowResult(); + }, + installerSizeResolver: _ => 1234 + ); + + provider.LoadPackageDetails(details, new TestNativeTaskLogger()); + + Assert.NotNull(capturedQuery); + Assert.Equal("Contoso.Tool", capturedQuery.Id); + Assert.Equal("winget", capturedQuery.Source); + Assert.True(capturedQuery.Exact); + Assert.Equal("https://example.test/installer.exe", details.InstallerUrl?.ToString()); + Assert.Equal("ABC123", details.InstallerHash); + Assert.Equal("exe", details.InstallerType); + Assert.Equal("2026-04-27", details.UpdateDate); + Assert.Equal(1234, details.InstallerSize); + Assert.Contains(details.Dependencies, dependency => + dependency.Name == "Contoso.Dependency" && dependency.Version == "2.0" + ); + Assert.Contains("utility", details.Tags); + } + + [Fact] + public void PingetPackageDetailsProviderKeepsExistingDetailsWhenShowFails() + { + var manager = new WinGet(); + var package = new PackageBuilder() + .WithManager(manager) + .WithName("Contoso Tool") + .WithId("Contoso.Tool") + .WithVersion("1.0.0") + .Build(); + var details = new PackageDetailsBuilder() + .WithDescription("Native description") + .WithPublisher("Native publisher") + .Build(package); + var provider = new PingetPackageDetailsProvider( + _ => throw new InvalidOperationException("source cache missing") + ); + + provider.LoadPackageDetails(details, new TestNativeTaskLogger()); + + Assert.Equal("Native description", details.Description); + Assert.Equal("Native publisher", details.Publisher); + Assert.Null(details.InstallerUrl); + Assert.Empty(details.Dependencies); + } + + [Fact] + public void PingetPackageDetailsProviderUsesShortDescriptionWhenDescriptionIsMissing() + { + var manager = new WinGet(); + var package = new PackageBuilder() + .WithManager(manager) + .WithName("tessl") + .WithId("tessl.tessl") + .WithVersion("0.77.0") + .Build(); + var details = new PackageDetails(package); + var provider = new PingetPackageDetailsProvider( + _ => CreatePingetShowResult(description: null, shortDescription: "The package manager for agent skills and context"), + installerSizeResolver: _ => 1234 + ); + + provider.LoadPackageDetails(details, new TestNativeTaskLogger()); + + Assert.Equal("The package manager for agent skills and context", details.Description); + } + + [Fact] + public void PingetPackageDetailsProviderOmitsEllipsizedSourceFromQuery() + { + var manager = new WinGet(); + var package = new PackageBuilder() + .WithManager(manager) + .WithName("Contoso Tool") + .WithId("Contoso.Tool") + .WithVersion("1.0.0") + .WithSource(new ManagerSource(manager, "winge…", new Uri("https://example.test"))) + .Build(); + + PackageQuery query = PingetPackageDetailsProvider.CreateQuery(package); + + Assert.Null(query.Source); + } + + [Fact] + public void PingetPackageDetailsProviderUsesSystemWingetRepositorySources() + { + RepositoryOptions options = PingetPackageDetailsProvider.CreateRepositoryOptions(); + + Assert.Null(options.AppRoot); + Assert.False(string.IsNullOrWhiteSpace(options.UserAgent)); + } + + [Fact] + public void WinGetCliHelperUsesPingetProviderForPackageDetails() + { + var manager = new WinGet(); + var package = new PackageBuilder() + .WithManager(manager) + .WithName("Contoso Tool") + .WithId("Contoso.Tool") + .WithVersion("1.0.0") + .Build(); + var details = new PackageDetails(package); + int providerCallCount = 0; + var provider = new TestPingetPackageDetailsProvider(packageDetails => + { + providerCallCount++; + packageDetails.Publisher = "Pinget publisher"; + packageDetails.InstallerHash = "PINGET-HASH"; + }); + var helper = new WinGetCliHelper(manager, @"C:\missing\winget.exe", provider); + + helper.GetPackageDetails_UnSafe(details); + + Assert.Equal(1, providerCallCount); + Assert.Equal("Pinget publisher", details.Publisher); + Assert.Equal("PINGET-HASH", details.InstallerHash); + Assert.Equal( + "https://github.com/microsoft/winget-pkgs/tree/master/manifests/c/Contoso/Tool", + details.ManifestUrl?.ToString() + ); + } + + [Theory] + [InlineData(0)] // OperationType.Install + [InlineData(1)] // OperationType.Update + [InlineData(2)] // OperationType.Uninstall + public void WinGetOperationHelperEmitsWinGetCompatibleFlagsForSystemCli(int operationType) + { + var manager = new WinGet(); + SetCliToolKind(manager, WinGetCliToolKind.SystemWinGet); + var package = new PackageBuilder() + .WithManager(manager) + .WithId("Contoso.Tool") + .WithVersion("1.0.0") + .WithNewVersion("2.0.0") + .Build(); + + var parameters = manager.OperationHelper.GetParameters( + package, + new InstallOptions(), + (OperationType)operationType + ); + + Assert.Contains("--accept-source-agreements", parameters); + Assert.Contains("--disable-interactivity", parameters); + } + + [Fact] + public void WinGetOperationHelperSkipsUnsupportedFlagsForPingetInstall() + { + var manager = new WinGet(); + SetCliToolKind(manager, WinGetCliToolKind.BundledPinget); + var package = new PackageBuilder() + .WithManager(manager) + .WithId("Spotify.Spotify") + .Build(); + + var parameters = manager.OperationHelper.GetParameters( + package, + new InstallOptions(), + OperationType.Install + ); + + Assert.DoesNotContain("--accept-source-agreements", parameters); + Assert.DoesNotContain("--disable-interactivity", parameters); + // pinget install does accept these. + Assert.Contains("--accept-package-agreements", parameters); + Assert.Contains("--force", parameters); + Assert.Contains("--silent", parameters); + } + + [Fact] + public void WinGetOperationHelperSkipsUnsupportedFlagsForPingetUpgrade() + { + var manager = new WinGet(); + SetCliToolKind(manager, WinGetCliToolKind.BundledPinget); + var package = new PackageBuilder() + .WithManager(manager) + .WithId("Contoso.Tool") + .WithVersion("1.0.0") + .WithNewVersion("2.0.0") + .Build(); + var options = new InstallOptions + { + InteractiveInstallation = true, + CustomInstallLocation = @"C:\Apps\Contoso", + }; + + var parameters = manager.OperationHelper.GetParameters( + package, + options, + OperationType.Update + ); + + Assert.DoesNotContain("--accept-source-agreements", parameters); + Assert.DoesNotContain("--disable-interactivity", parameters); + // pinget upgrade does NOT accept these even though winget upgrade does. + Assert.DoesNotContain("--accept-package-agreements", parameters); + Assert.DoesNotContain("--force", parameters); + Assert.DoesNotContain("--interactive", parameters); + Assert.DoesNotContain("--location", parameters); + // pinget upgrade still supports --include-unknown and --silent. + Assert.Contains("--include-unknown", parameters); + Assert.Contains("--silent", parameters); + } + + [Fact] + public void WinGetOperationHelperSkipsUnsupportedFlagsForPingetUninstall() + { + var manager = new WinGet(); + SetCliToolKind(manager, WinGetCliToolKind.BundledPinget); + var package = new PackageBuilder() + .WithManager(manager) + .WithId("Contoso.Tool") + .WithVersion("1.0.0") + .Build(); + + var parameters = manager.OperationHelper.GetParameters( + package, + new InstallOptions(), + OperationType.Uninstall + ); + + Assert.DoesNotContain("--accept-source-agreements", parameters); + Assert.DoesNotContain("--disable-interactivity", parameters); + } + + [Fact] + public void WinGetOperationHelperOmitsProxyArgumentForPinget() + { + Settings.Set(Settings.K.EnableProxy, true); + Settings.Set(Settings.K.EnableProxyAuth, false); + Settings.SetValue(Settings.K.ProxyURL, "http://proxy.example.test:3128/"); + try + { + var manager = new WinGet(); + SetCliToolKind(manager, WinGetCliToolKind.BundledPinget); + var package = new PackageBuilder() + .WithManager(manager) + .WithId("Contoso.Tool") + .Build(); + + var parameters = manager.OperationHelper.GetParameters( + package, + new InstallOptions(), + OperationType.Install + ); + + Assert.DoesNotContain(parameters, p => p.StartsWith("--proxy", StringComparison.Ordinal)); + } + finally + { + Settings.Set(Settings.K.EnableProxy, false); + Settings.SetValue(Settings.K.ProxyURL, ""); + } + } + + [Fact] + public void WinGetUpdateNotApplicableRetriesOnceWithoutScopeAndArchitecture() + { + // Regression test for #4954: a package whose only installer is x86 (e.g. Bulk Crap + // Uninstaller) reports "update not applicable" when we force --architecture/--scope. + var manager = new WinGet(); + SetCliToolKind(manager, WinGetCliToolKind.SystemWinGet); + var package = new PackageBuilder() + .WithManager(manager) + .WithId("Klocman.BulkCrapUninstaller") + .WithVersion("6.1") + .WithNewVersion("6.2") + .Build(); + package.OverridenOptions.Scope = PackageScope.Machine; + var options = new InstallOptions { Architecture = "x64" }; + + // The forced constraints are present on the first attempt. + var firstAttempt = manager.OperationHelper.GetParameters(package, options, OperationType.Update); + Assert.Contains("--scope", firstAttempt); + Assert.Contains("--architecture", firstAttempt); + + // An "update not applicable" result triggers a single relaxed retry. + var veredict = manager.OperationHelper.GetResult( + package, + OperationType.Update, + [], + unchecked((int)0x8A15002B) + ); + + OperationAssert.HasVeredict(veredict, OperationVeredict.AutoRetry); + Assert.True(package.OverridenOptions.WinGet_DropArchAndScope); + + // The relaxed retry drops both constraints, matching the WinGet CLI default. + var retryAttempt = manager.OperationHelper.GetParameters(package, options, OperationType.Update); + Assert.DoesNotContain("--scope", retryAttempt); + Assert.DoesNotContain("--architecture", retryAttempt); + } + + [Fact] + public void WinGetUpdateNotApplicableDoesNotRetryASecondTime() + { + var manager = new WinGet(); + var package = new PackageBuilder() + .WithManager(manager) + .WithId("Klocman.BulkCrapUninstaller") + .WithVersion("6.1") + .WithNewVersion("6.2") + .Build(); + package.OverridenOptions.Scope = PackageScope.Machine; + package.OverridenOptions.WinGet_DropArchAndScope = true; // the relaxed retry already happened + + var veredict = manager.OperationHelper.GetResult( + package, + OperationType.Update, + [], + unchecked((int)0x8A15002B) + ); + + OperationAssert.HasVeredict(veredict, OperationVeredict.Failure); + } + + [Fact] + public void WinGetUpdateNotApplicableFailsWhenThereIsNothingToRelax() + { + var manager = new WinGet(); + var package = new PackageBuilder() + .WithManager(manager) + .WithId("Contoso.Tool") + .WithVersion("1.0.0") + .WithNewVersion("2.0.0") + .Build(); + + var veredict = manager.OperationHelper.GetResult( + package, + OperationType.Update, + [], + unchecked((int)0x8A15002B) + ); + + OperationAssert.HasVeredict(veredict, OperationVeredict.Failure); + Assert.False(package.OverridenOptions.WinGet_DropArchAndScope); + } + + [Fact] + public void WinGetUpdateNotApplicableViaPingetRetriesWithoutScopeAndArchitecture() + { + // Bundled pinget signals "not applicable" with a non-zero exit code and a + // "No applicable installer found" message instead of WinGet's 0x8A15002B. + var manager = new WinGet(); + SetCliToolKind(manager, WinGetCliToolKind.BundledPinget); + var package = new PackageBuilder() + .WithManager(manager) + .WithId("JRSoftware.InnoSetup") + .WithVersion("6.7.1") + .WithNewVersion("6.7.3") + .Build(); + package.OverridenOptions.Scope = PackageScope.Machine; + + var veredict = manager.OperationHelper.GetResult( + package, + OperationType.Update, + [ + "Selecting applicable installer for this system...", + " Error upgrading JRSoftware.InnoSetup: No applicable installer found", + ], + 1 + ); + + OperationAssert.HasVeredict(veredict, OperationVeredict.AutoRetry); + Assert.True(package.OverridenOptions.WinGet_DropArchAndScope); + } + + [Fact] + public void WinGetGenericPingetFailureDoesNotRetry() + { + // A non-zero pinget exit without the "No applicable installer found" message + // is a real failure and must not be mistaken for the not-applicable case. + var manager = new WinGet(); + SetCliToolKind(manager, WinGetCliToolKind.BundledPinget); + var package = new PackageBuilder() + .WithManager(manager) + .WithId("JRSoftware.InnoSetup") + .WithVersion("6.7.1") + .WithNewVersion("6.7.3") + .Build(); + package.OverridenOptions.Scope = PackageScope.Machine; + + var veredict = manager.OperationHelper.GetResult( + package, + OperationType.Update, + ["error: download failed"], + 1 + ); + + OperationAssert.HasVeredict(veredict, OperationVeredict.Failure); + Assert.False(package.OverridenOptions.WinGet_DropArchAndScope); + } + + [Fact] + public void ConsumeAlreadyUpgradedSuppression_HidesOnceThenRevealsOnNextScan() + { + var manager = new WinGet(); + var package = new PackageBuilder() + .WithManager(manager) + .WithId("Contoso.OneShot") + .WithVersion("1.0.0") + .WithNewVersion("2.0.0") + .Build(); + + // Simulate a completed upgrade to 2.0.0 (as MarkUpgradeAsDone records it). + Settings.SetDictionaryItem( + Settings.K.WinGetAlreadyUpgradedPackages, + package.Id, + "2.0.0" + ); + + // First scan hides the still-listed update once, then consumes the mark... + Assert.True(WinGetPkgOperationHelper.ConsumeAlreadyUpgradedSuppression(package)); + Assert.False(WinGetPkgOperationHelper.UpdateAlreadyInstalled(package)); + + // ...so a genuinely-outdated package (no-op upgrade) reappears next scan (issue #5042). + Assert.False(WinGetPkgOperationHelper.ConsumeAlreadyUpgradedSuppression(package)); + } + + [Fact] + public void ConsumeAlreadyUpgradedSuppression_DoesNotHideDifferentAvailableVersion() + { + var manager = new WinGet(); + var package = new PackageBuilder() + .WithManager(manager) + .WithId("Contoso.NewerUpdate") + .WithVersion("1.0.0") + .WithNewVersion("3.0.0") + .Build(); + + // A mark from a previous upgrade to a different version must never hide a new update. + Settings.SetDictionaryItem( + Settings.K.WinGetAlreadyUpgradedPackages, + package.Id, + "2.0.0" + ); + + Assert.False(WinGetPkgOperationHelper.ConsumeAlreadyUpgradedSuppression(package)); + Assert.Equal( + "2.0.0", + Settings.GetDictionaryItem( + Settings.K.WinGetAlreadyUpgradedPackages, + package.Id + ) + ); + } + + [Fact] + public void ConsumeAlreadyUpgradedSuppression_NoMarkNeverHides() + { + var manager = new WinGet(); + var package = new PackageBuilder() + .WithManager(manager) + .WithId("Contoso.NoMark") + .WithVersion("1.0.0") + .WithNewVersion("2.0.0") + .Build(); + + Assert.False(WinGetPkgOperationHelper.ConsumeAlreadyUpgradedSuppression(package)); + } + + private static void SetCliToolKind(WinGet manager, WinGetCliToolKind kind) + { + typeof(WinGet) + .GetProperty(nameof(WinGet.SelectedCliToolKind), System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic)! + .GetSetMethod(nonPublic: true)! + .Invoke(manager, [kind]); + } + + private sealed class TestableWinGet : WinGet + { + public IReadOnlyList InvokeGetInstalledPackages() => base.GetInstalledPackages_UnSafe(); + } + + private static IManagerSource GetExpectedSource(WinGet manager, LocalSourceKind expectedSourceKind) => + expectedSourceKind switch + { + LocalSourceKind.MicrosoftStore => manager.MicrosoftStoreSource, + LocalSourceKind.LocalPc => manager.LocalPcSource, + LocalSourceKind.Android => manager.AndroidSubsystemSource, + LocalSourceKind.Steam => manager.SteamSource, + LocalSourceKind.Ubisoft => manager.UbisoftConnectSource, + LocalSourceKind.Gog => manager.GOGSource, + _ => throw new ArgumentOutOfRangeException(nameof(expectedSourceKind)), + }; + + private static void SetNoPackagesHaveBeenLoaded(bool value) + { + typeof(WinGet) + .GetProperty(nameof(WinGet.NO_PACKAGES_HAVE_BEEN_LOADED))! + .GetSetMethod(nonPublic: true)! + .Invoke(null, [value]); + } + + private static ShowResult CreatePingetShowResult( + string? description = "Contoso description", + string? shortDescription = null + ) + { + var package = new SearchMatch + { + SourceName = "winget", + SourceKind = SourceKind.PreIndexed, + Id = "Contoso.Tool", + Name = "Contoso Tool", + Version = "1.2.3", + }; + var installer = new Installer + { + Architecture = "x64", + InstallerType = "exe", + Url = "https://example.test/installer.exe", + Sha256 = "ABC123", + ReleaseDate = "2026-04-27", + PackageDependencies = ["Contoso.Dependency [2.0]"], + }; + + return new ShowResult + { + Package = package, + Manifest = new Manifest + { + Id = "Contoso.Tool", + Name = "Contoso Tool", + Version = "1.2.3", + Author = "Contoso", + Description = description, + ShortDescription = shortDescription, + License = "MIT", + PackageUrl = "https://example.test/tool", + Publisher = "Contoso Ltd.", + ReleaseNotes = "Release notes", + Tags = ["utility"], + PackageDependencies = ["Contoso.Runtime"], + Installers = [installer], + }, + SelectedInstaller = installer, + StructuredDocument = new Dictionary(), + }; + } + + public enum LocalSourceKind + { + MicrosoftStore, + LocalPc, + Android, + Steam, + Ubisoft, + Gog, + } + + private sealed class TestWinGetManagerHelper : IWinGetManagerHelper + { + public Func> GetAvailableUpdatesHandler { get; set; } = static () => []; + public Func> GetInstalledPackagesHandler { get; set; } = static () => []; + public Func> FindPackagesHandler { get; set; } = static _ => []; + public Func> GetSourcesHandler { get; set; } = static () => []; + public Func> GetInstallableVersionsHandler { get; set; } = + static _ => []; + public Action GetPackageDetailsHandler { get; set; } = static _ => { }; + + public IReadOnlyList GetAvailableUpdates_UnSafe() => GetAvailableUpdatesHandler(); + + public IReadOnlyList GetInstalledPackages_UnSafe() => GetInstalledPackagesHandler(); + + public IReadOnlyList FindPackages_UnSafe(string query) => FindPackagesHandler(query); + + public IReadOnlyList GetSources_UnSafe() => GetSourcesHandler(); + + public IReadOnlyList GetInstallableVersions_Unsafe(IPackage package) => + GetInstallableVersionsHandler(package); + + public void GetPackageDetails_UnSafe(IPackageDetails details) => GetPackageDetailsHandler(details); + } + + private sealed class TestPingetPackageDetailsProvider(Action handler) + : IPingetPackageDetailsProvider + { + public bool LoadPackageDetails(IPackageDetails details, INativeTaskLogger logger) + { + handler(details); + return true; + } + } + + private sealed class TestNativeTaskLogger : INativeTaskLogger + { + public List Lines { get; } = []; + public int? ReturnCode { get; private set; } + + public IReadOnlyList AsColoredString(bool verbose = false) => Lines; + + public void Close(int returnCode) => ReturnCode = returnCode; + + public void Error(Exception? e) => Lines.Add(e?.Message ?? ""); + + public void Error(IReadOnlyList lines) => Lines.AddRange(lines); + + public void Error(string? line) => Lines.Add(line ?? ""); + + public void Log(IReadOnlyList lines) => Lines.AddRange(lines); + + public void Log(string? line) => Lines.Add(line ?? ""); + } +} +#endif diff --git a/src/UniGetUI.Tests/AutoUpdaterTests.cs b/src/UniGetUI.Tests/AutoUpdaterTests.cs new file mode 100644 index 0000000..c6e75c1 --- /dev/null +++ b/src/UniGetUI.Tests/AutoUpdaterTests.cs @@ -0,0 +1,102 @@ +using System.Runtime.InteropServices; +using Microsoft.Win32; +using UniGetUI.Shared; + +namespace UniGetUI.Tests; + +public sealed class AutoUpdaterTests +{ + [Theory] + [InlineData("https://devolutions.net/productinfo.json", false, true)] + [InlineData("https://updates.devolutions.net/productinfo.json", false, true)] + [InlineData("https://notdevolutions.net/productinfo.json", false, false)] + [InlineData("https://github.com/Devolutions/UniGetUI/releases", false, true)] + [InlineData("http://devolutions.net/productinfo.json", false, false)] + [InlineData("http://contoso.invalid/file.exe", true, true)] + public void IsSourceUrlAllowed_RestrictsUnsafeOrUnexpectedHosts( + string url, + bool allowUnsafeUrls, + bool expected + ) + { + Assert.Equal(expected, AutoUpdaterHelpers.IsSourceUrlAllowed(url, allowUnsafeUrls)); + } + + [Fact] + public void SelectInstallerFile_PrefersExecutableForCurrentArchitecture() + { + string targetArch = RuntimeInformation.ProcessArchitecture switch + { + Architecture.Arm64 => "arm64", + Architecture.X64 => "x64", + _ => "x64", + }; + var preferred = new AutoUpdaterHelpers.ProductInfoFile + { + Arch = targetArch, + Type = "exe", + Url = "https://example.test/app.exe", + Hash = "hash-exe", + }; + + var selected = AutoUpdaterHelpers.SelectInstallerFile( + [ + new AutoUpdaterHelpers.ProductInfoFile + { + Arch = "Any", + Type = "exe", + Url = "https://example.test/any.exe", + Hash = "hash-any", + }, + new AutoUpdaterHelpers.ProductInfoFile + { + Arch = targetArch, + Type = "msi", + Url = "https://example.test/app.msi", + Hash = "hash-msi", + }, + preferred, + ] + ); + + Assert.Same(preferred, selected); + } + + [Fact] + public void ParseVersionOrFallback_ParsesTrimmedVersionsAndFallsBackForInvalidInput() + { + Version fallback = new(9, 9, 9, 9); + + Assert.Equal(new Version(1, 2, 3), AutoUpdaterHelpers.ParseVersionOrFallback("v1.2.3", fallback)); + Assert.Equal(fallback, AutoUpdaterHelpers.ParseVersionOrFallback("not-a-version", fallback)); + } + + [Fact] + public void NormalizeThumbprint_RemovesNonHexCharactersAndLowercases() + { + Assert.Equal("abcdef1234", AutoUpdaterHelpers.NormalizeThumbprint("AB:CD ef-12_34")); + } + +#if DEBUG + [Fact] + public void RegistryHelpers_ParseTrimmedStringsAndTruthyValues() + { + string keyPath = $@"Software\Devolutions\UniGetUI.Tests\{Guid.NewGuid():N}"; + using RegistryKey key = Registry.CurrentUser.CreateSubKey(keyPath)!; + key.SetValue("ProductInfoUrl", " https://devolutions.net/custom.json "); + key.SetValue("AllowUnsafe", "yes"); + + try + { + Assert.Equal("https://devolutions.net/custom.json", AutoUpdaterHelpers.GetRegistryString(key, "ProductInfoUrl")); + Assert.True(AutoUpdaterHelpers.GetRegistryBool(key, "AllowUnsafe")); + Assert.Null(AutoUpdaterHelpers.GetRegistryString(key, "Missing")); + Assert.False(AutoUpdaterHelpers.GetRegistryBool(key, "Missing")); + } + finally + { + Registry.CurrentUser.DeleteSubKeyTree(keyPath, throwOnMissingSubKey: false); + } + } +#endif +} diff --git a/src/UniGetUI.Tests/CLIHandlerTests.cs b/src/UniGetUI.Tests/CLIHandlerTests.cs new file mode 100644 index 0000000..350ad2b --- /dev/null +++ b/src/UniGetUI.Tests/CLIHandlerTests.cs @@ -0,0 +1,159 @@ +using System.Text.Json; +using UniGetUI.Core.Data; +using UniGetUI.Core.SettingsEngine; +using UniGetUI.Core.SettingsEngine.SecureSettings; +using UniGetUI.Shared; + +namespace UniGetUI.Tests; + +public sealed class CLIHandlerTests : IDisposable +{ + private readonly string _testRoot = Path.Combine( + Path.GetTempPath(), + nameof(CLIHandlerTests), + Guid.NewGuid().ToString("N") + ); + private readonly string _secureSettingsRoot; + + public CLIHandlerTests() + { + Directory.CreateDirectory(_testRoot); + CoreData.TEST_DataDirectoryOverride = Path.Combine(_testRoot, "Data"); + _secureSettingsRoot = Path.Combine(_testRoot, "SecureSettings"); + SecureSettings.TEST_SecureSettingsRootOverride = _secureSettingsRoot; + Directory.CreateDirectory(CoreData.UniGetUIUserConfigurationDirectory); + Settings.ResetSettings(); + } + + public void Dispose() + { + Settings.ResetSettings(); + CoreData.TEST_DataDirectoryOverride = null; + SecureSettings.TEST_SecureSettingsRootOverride = null; + if (Directory.Exists(_testRoot)) + { + Directory.Delete(_testRoot, recursive: true); + } + } + + [Fact] + public void ImportSettings_ReturnsNoSuchFileWhenInputIsMissing() + { + int result = SharedPreUiCommandDispatcher.ImportSettings( + ["unigetui", SharedPreUiCommandDispatcher.ImportSettingsArgument, Path.Combine(_testRoot, "missing.json")], + SharedPreUiCommandDispatcher.WindowsCliExitCodes + ); + + Assert.Equal(-1073741809, result); + } + + [Fact] + public void ExportAndImportSettings_RoundTripConfiguration() + { + string exportPath = Path.Combine(_testRoot, "settings.json"); + Settings.Set(Settings.K.FreshBoolSetting, true); + Settings.SetValue(Settings.K.FreshValue, "before-export"); + + Assert.Equal( + 0, + SharedPreUiCommandDispatcher.ExportSettings( + ["unigetui", SharedPreUiCommandDispatcher.ExportSettingsArgument, exportPath], + SharedPreUiCommandDispatcher.WindowsCliExitCodes + ) + ); + + Settings.Set(Settings.K.FreshBoolSetting, false); + Settings.SetValue(Settings.K.FreshValue, "after-export"); + + Assert.Equal( + 0, + SharedPreUiCommandDispatcher.ImportSettings( + ["unigetui", SharedPreUiCommandDispatcher.ImportSettingsArgument, exportPath], + SharedPreUiCommandDispatcher.WindowsCliExitCodes + ) + ); + Assert.True(Settings.Get(Settings.K.FreshBoolSetting)); + Assert.Equal("before-export", Settings.GetValue(Settings.K.FreshValue)); + + var exported = JsonSerializer.Deserialize>(File.ReadAllText(exportPath)); + Assert.NotNull(exported); + Assert.Equal("before-export", exported[Settings.ResolveKey(Settings.K.FreshValue)]); + } + + [Fact] + public void EnableDisableAndSetValue_MutateSettings() + { + Assert.Equal( + 0, + SharedPreUiCommandDispatcher.EnableSetting( + ["unigetui", SharedPreUiCommandDispatcher.EnableSettingArgument, nameof(Settings.K.Test1)], + SharedPreUiCommandDispatcher.WindowsCliExitCodes + ) + ); + Assert.True(Settings.Get(Settings.K.Test1)); + + Assert.Equal( + 0, + SharedPreUiCommandDispatcher.SetSettingValue( + [ + "unigetui", + SharedPreUiCommandDispatcher.SetSettingValueArgument, + nameof(Settings.K.FreshValue), + "cli-value", + ], + SharedPreUiCommandDispatcher.WindowsCliExitCodes + ) + ); + Assert.Equal("cli-value", Settings.GetValue(Settings.K.FreshValue)); + + Assert.Equal( + 0, + SharedPreUiCommandDispatcher.DisableSetting( + ["unigetui", SharedPreUiCommandDispatcher.DisableSettingArgument, nameof(Settings.K.Test1)], + SharedPreUiCommandDispatcher.WindowsCliExitCodes + ) + ); + Assert.False(Settings.Get(Settings.K.Test1)); + } + + [Fact] + public void EnableAndDisableSecureSettingForUser_MutateSecureSettings() + { + string user = "cli-user"; + string setting = "AllowCLIArguments"; + + Assert.Equal( + 0, + SharedPreUiCommandDispatcher.EnableSecureSettingForUser( + ["unigetui", SecureSettings.Args.ENABLE_FOR_USER, user, setting], + SharedPreUiCommandDispatcher.WindowsCliExitCodes + ) + ); + Assert.True( + File.Exists( + Path.Combine( + _secureSettingsRoot, + user, + setting + ) + ) + ); + + Assert.Equal( + 0, + SharedPreUiCommandDispatcher.DisableSecureSettingForUser( + ["unigetui", SecureSettings.Args.DISABLE_FOR_USER, user, setting], + SharedPreUiCommandDispatcher.WindowsCliExitCodes + ) + ); + Assert.False( + File.Exists( + Path.Combine( + _secureSettingsRoot, + user, + setting + ) + ) + ); + } +} diff --git a/src/UniGetUI.Tests/IpcCliSyntaxTests.cs b/src/UniGetUI.Tests/IpcCliSyntaxTests.cs new file mode 100644 index 0000000..8128122 --- /dev/null +++ b/src/UniGetUI.Tests/IpcCliSyntaxTests.cs @@ -0,0 +1,172 @@ +using UniGetUI.Interface; + +namespace UniGetUI.Tests; + +public sealed class IpcCliSyntaxTests +{ + private static string GetCommand(IpcCliParseResult result) + { + return Assert.IsType(result.Command); + } + + private static string[] GetEffectiveArgs(IpcCliParseResult result) + { + return Assert.IsType(result.EffectiveArgs); + } + + [Fact] + public void ParseMapsTopLevelStatusCommand() + { + IpcCliParseResult result = IpcCliSyntax.Parse(["status"]); + + Assert.Equal(IpcCliParseStatus.Success, result.Status); + Assert.Equal("status", GetCommand(result)); + Assert.Equal([], GetEffectiveArgs(result)); + } + + [Fact] + public void ParsePreservesLeadingTransportOverrides() + { + IpcCliParseResult result = IpcCliSyntax.Parse( + ["--transport", "named-pipe", "--pipe-name", "probe-1", "status"] + ); + + Assert.Equal(IpcCliParseStatus.Success, result.Status); + Assert.Equal("status", GetCommand(result)); + Assert.Equal(["--transport", "named-pipe", "--pipe-name", "probe-1"], GetEffectiveArgs(result)); + } + + [Fact] + public void ParseMapsOperationIdAlias() + { + IpcCliParseResult result = IpcCliSyntax.Parse( + ["operation", "wait", "--id", "op-123", "--timeout", "30"] + ); + + Assert.Equal(IpcCliParseStatus.Success, result.Status); + Assert.Equal("wait-operation", GetCommand(result)); + Assert.Equal(["--operation-id", "op-123", "--timeout", "30"], GetEffectiveArgs(result)); + } + + [Fact] + public void ParseMapsPackageAliases() + { + IpcCliParseResult result = IpcCliSyntax.Parse( + ["package", "details", "--manager", "dotnet-tool", "--id", "dotnetsay", "--source", "nuget.org"] + ); + + Assert.Equal(IpcCliParseStatus.Success, result.Status); + Assert.Equal("package-details", GetCommand(result)); + Assert.Equal( + ["--manager", "dotnet-tool", "--package-id", "dotnetsay", "--package-source", "nuget.org"], + GetEffectiveArgs(result) + ); + } + + [Fact] + public void ParseMapsNestedBackupCommands() + { + IpcCliParseResult result = IpcCliSyntax.Parse( + ["backup", "github", "login", "start", "--launch-browser"] + ); + + Assert.Equal(IpcCliParseStatus.Success, result.Status); + Assert.Equal("start-github-sign-in", GetCommand(result)); + Assert.Equal(["--launch-browser"], GetEffectiveArgs(result)); + } + + [Fact] + public void ParseMapsManagerNotificationSubcommands() + { + IpcCliParseResult result = IpcCliSyntax.Parse( + ["manager", "notifications", "disable", "--manager", "dotnet-tool"] + ); + + Assert.Equal(IpcCliParseStatus.Success, result.Status); + Assert.Equal("set-manager-update-notifications", GetCommand(result)); + Assert.Equal(["--enabled", "false", "--manager", "dotnet-tool"], GetEffectiveArgs(result)); + } + + [Fact] + public void ParseMapsSecureSettingsDomain() + { + IpcCliParseResult result = IpcCliSyntax.Parse( + ["settings", "secure", "list", "--user", "alice"] + ); + + Assert.Equal(IpcCliParseStatus.Success, result.Status); + Assert.Equal("list-secure-settings", GetCommand(result)); + Assert.Equal(["--user", "alice"], GetEffectiveArgs(result)); + } + + [Fact] + public void ParseMapsSourceDocumentationAliases() + { + IpcCliParseResult result = IpcCliSyntax.Parse( + ["source", "add", "--manager", "dotnet-tool", "--source-name", "nuget.org", "--source-url", "https://api.nuget.org/v3/index.json"] + ); + + Assert.Equal(IpcCliParseStatus.Success, result.Status); + Assert.Equal("add-source", GetCommand(result)); + Assert.Equal( + ["--manager", "dotnet-tool", "--name", "nuget.org", "--url", "https://api.nuget.org/v3/index.json"], + GetEffectiveArgs(result) + ); + } + + [Fact] + public void ParseTreatsHelpAsCliHelp() + { + IpcCliParseResult result = IpcCliSyntax.Parse(["help"]); + + Assert.Equal(IpcCliParseStatus.Help, result.Status); + } + + [Fact] + public void HasVerbCommandReturnsTrueForVerbInvocation() + { + Assert.True(IpcCliSyntax.HasVerbCommand(["package", "search", "--manager", "npm"])); + } + + [Fact] + public void HasVerbCommandReturnsTrueForHelpVerb() + { + Assert.True(IpcCliSyntax.HasVerbCommand(["help"])); + } + + [Fact] + public void HasVerbCommandReturnsTrueAfterLeadingTransportOverride() + { + Assert.True(IpcCliSyntax.HasVerbCommand(["--transport", "named-pipe", "status"])); + } + + [Fact] + public void HasVerbCommandReturnsFalseForStartupParameter() + { + Assert.False(IpcCliSyntax.HasVerbCommand(["--daemon"])); + } + + [Fact] + public void HasVerbCommandReturnsFalseForGlobalHelpFlag() + { + Assert.False(IpcCliSyntax.HasVerbCommand(["--help"])); + } + + [Fact] + public void HasVerbCommandReturnsFalseForShortHelpFlag() + { + Assert.False(IpcCliSyntax.HasVerbCommand(["-h"])); + } + + [Fact] + public void HasVerbCommandReturnsFalseForHeadlessStartup() + { + Assert.False(IpcCliSyntax.HasVerbCommand(["--headless"])); + } + + [Fact] + public void HasVerbCommandReturnsFalseForUnknownBareToken() + { + Assert.False(IpcCliSyntax.HasVerbCommand(["foo"])); + } +} diff --git a/src/UniGetUI.Tests/IpcTransportTests.cs b/src/UniGetUI.Tests/IpcTransportTests.cs new file mode 100644 index 0000000..de1f0c0 --- /dev/null +++ b/src/UniGetUI.Tests/IpcTransportTests.cs @@ -0,0 +1,186 @@ +using UniGetUI.Core.Data; +using UniGetUI.Interface; + +namespace UniGetUI.Tests; + +public sealed class IpcTransportTests : IDisposable +{ + private readonly string _dataDirectory = Path.Join( + Path.GetTempPath(), + "UniGetUI.Tests", + Guid.NewGuid().ToString("N") + ); + + public IpcTransportTests() + { + CoreData.TEST_DataDirectoryOverride = _dataDirectory; + Directory.CreateDirectory(_dataDirectory); + } + + [Fact] + public void DefaultTransportUsesNamedPipeOnAllPlatforms() + { + Assert.Equal(IpcTransportKind.NamedPipe, IpcTransportOptions.Default.TransportKind); + Assert.Equal(IpcTransportOptions.DefaultTcpPort, IpcTransportOptions.Default.TcpPort); + Assert.Equal( + IpcTransportOptions.DefaultNamedPipeName, + IpcTransportOptions.Default.NamedPipeName + ); + } + + [Fact] + public void LoadForServerParsesNamedPipeOverrides() + { + var options = IpcTransportOptions.LoadForServer( + [ + "UniGetUI.exe", + IpcTransportOptions.TransportArgument, + "named-pipe", + IpcTransportOptions.NamedPipeArgument, + "Contoso.Pipe", + IpcTransportOptions.TcpPortArgument, + "7258", + ] + ); + + Assert.Equal(IpcTransportKind.NamedPipe, options.TransportKind); + Assert.Equal("Contoso.Pipe", options.NamedPipeName); + Assert.Equal(7258, options.TcpPort); + } + + [Fact] + public void ResolveUnixSocketPathUsesTmpForRelativePipeNames() + { + string socketPath = IpcTransportOptions.ResolveUnixSocketPath( + IpcTransportOptions.DefaultNamedPipeName + ); + + Assert.Equal("/tmp/UniGetUI.IPC", socketPath); + } + + [Fact] + public void ResolveUnixSocketPathPreservesAbsolutePaths() + { + const string socketPath = "/tmp/custom-unigetui.sock"; + + Assert.Equal(socketPath, IpcTransportOptions.ResolveUnixSocketPath(socketPath)); + } + + [Fact] + public void SameUserUnixSocketModeUsesOwnerOnlyPermissions() + { + Assert.Equal( + UnixFileMode.UserRead | UnixFileMode.UserWrite, + IpcTransportOptions.SameUserUnixSocketMode + ); + } + + [Fact] + public void LoadForServerRejectsAbsolutePipePathOnWindows() + { + if (!OperatingSystem.IsWindows()) + { + return; + } + + var options = IpcTransportOptions.LoadForServer( + [ + "UniGetUI.exe", + IpcTransportOptions.TransportArgument, + "named-pipe", + IpcTransportOptions.NamedPipeArgument, + "/tmp/custom-unigetui.sock", + ] + ); + + Assert.Equal(IpcTransportOptions.DefaultNamedPipeName, options.NamedPipeName); + } + + [Fact] + public void LoadForServerAcceptsAbsolutePipePathOnUnix() + { + if (OperatingSystem.IsWindows()) + { + return; + } + + const string socketPath = "/tmp/custom-unigetui.sock"; + var options = IpcTransportOptions.LoadForServer( + [ + "UniGetUI.exe", + IpcTransportOptions.TransportArgument, + "named-pipe", + IpcTransportOptions.NamedPipeArgument, + socketPath, + ] + ); + + Assert.Equal(socketPath, options.NamedPipeName); + Assert.Equal(socketPath, options.NamedPipePath); + } + + [Fact] + public void LoadForClientUsesPersistedEndpointMetadataWhenNoOverridesExist() + { + var persisted = new IpcTransportOptions( + IpcTransportKind.NamedPipe, + 7058, + "Persisted.Pipe" + ); + persisted.Persist( + sessionId: "gui-session", + token: "gui-token", + sessionKind: IpcTransportOptions.GuiSessionKind, + processId: Environment.ProcessId + ); + + var options = IpcTransportOptions.LoadForClient(["UniGetUI.exe"]); + + Assert.Equal(IpcTransportKind.NamedPipe, options.TransportKind); + Assert.Equal("Persisted.Pipe", options.NamedPipeName); + } + + [Fact] + public void LoadForClientPrefersHeadlessPersistedSessionWhenMultipleSessionsExist() + { + var guiOptions = new IpcTransportOptions( + IpcTransportKind.Tcp, + 7058, + IpcTransportOptions.DefaultNamedPipeName + ); + guiOptions.Persist( + sessionId: "gui-session", + token: "gui-token", + sessionKind: IpcTransportOptions.GuiSessionKind, + processId: Environment.ProcessId + ); + + var headlessOptions = new IpcTransportOptions( + IpcTransportKind.NamedPipe, + 7058, + "Headless.Pipe" + ); + headlessOptions.Persist( + sessionId: "headless-session", + token: "headless-token", + sessionKind: IpcTransportOptions.HeadlessSessionKind, + processId: Environment.ProcessId + ); + + var options = IpcTransportOptions.LoadForClient(["UniGetUI.exe"]); + + Assert.Equal(IpcTransportKind.NamedPipe, options.TransportKind); + Assert.Equal("Headless.Pipe", options.NamedPipeName); + } + + public void Dispose() + { + IpcTransportOptions.DeletePersistedMetadata(); + CoreData.TEST_DataDirectoryOverride = null; + + if (Directory.Exists(_dataDirectory)) + { + Directory.Delete(_dataDirectory, recursive: true); + } + } +} diff --git a/src/UniGetUI.Tests/TestAssembly.cs b/src/UniGetUI.Tests/TestAssembly.cs new file mode 100644 index 0000000..2171200 --- /dev/null +++ b/src/UniGetUI.Tests/TestAssembly.cs @@ -0,0 +1,3 @@ +using Xunit; + +[assembly: CollectionBehavior(DisableTestParallelization = true)] diff --git a/src/UniGetUI.Tests/UniGetUI.Tests.csproj b/src/UniGetUI.Tests/UniGetUI.Tests.csproj new file mode 100644 index 0000000..c7ca3d7 --- /dev/null +++ b/src/UniGetUI.Tests/UniGetUI.Tests.csproj @@ -0,0 +1,50 @@ + + + $(WindowsTargetFramework) + + false + true + x64 + win-x64 + false + false + false + false + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/UniGetUI.Windows.slnx b/src/UniGetUI.Windows.slnx new file mode 100644 index 0000000..0547916 --- /dev/null +++ b/src/UniGetUI.Windows.slnx @@ -0,0 +1,232 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/WindowsPackageManager.Interop/Exceptions/WinGetComActivationException.cs b/src/WindowsPackageManager.Interop/Exceptions/WinGetComActivationException.cs new file mode 100644 index 0000000..49cf069 --- /dev/null +++ b/src/WindowsPackageManager.Interop/Exceptions/WinGetComActivationException.cs @@ -0,0 +1,55 @@ +using System.Runtime.InteropServices; + +namespace WindowsPackageManager.Interop; + +public sealed class WinGetComActivationException : COMException +{ + public Guid Clsid { get; } + public Guid Iid { get; } + public bool AllowLowerTrustRegistration { get; } + public string HResultHex => $"0x{HResult:X8}"; + + public string Reason => DescribeHResult(HResult); + + public bool IsExpectedFallbackCondition => + HResult is + unchecked((int)0x80040154) or + unchecked((int)0x80070490) or + unchecked((int)0x80070002) or + unchecked((int)0x8000000F) + || Message.Contains("Element not found", StringComparison.OrdinalIgnoreCase) + || Message.Contains( + "Typename or Namespace was not found in metadata file", + StringComparison.OrdinalIgnoreCase + ); + + public WinGetComActivationException( + Guid clsid, + Guid iid, + int hresult, + bool allowLowerTrustRegistration + ) + : base(CreateMessage(clsid, iid, hresult, allowLowerTrustRegistration), hresult) + { + Clsid = clsid; + Iid = iid; + AllowLowerTrustRegistration = allowLowerTrustRegistration; + } + + private static string CreateMessage( + Guid clsid, + Guid iid, + int hresult, + bool allowLowerTrustRegistration + ) => + $"WinGet COM activation failed for CLSID {clsid} (IID {iid}, AllowLowerTrustRegistration={allowLowerTrustRegistration}): {DescribeHResult(hresult)}"; + + private static string DescribeHResult(int hresult) => hresult switch + { + unchecked((int)0x80040154) => "Class not registered", + unchecked((int)0x80070490) => "Element not found", + unchecked((int)0x80070002) => "File not found", + unchecked((int)0x8000000F) => "Typename or Namespace was not found in metadata file", + _ => Marshal.GetExceptionForHR(hresult)?.Message ?? $"HRESULT 0x{hresult:X8}", + }; +} diff --git a/src/WindowsPackageManager.Interop/Exceptions/WinGetConfigurationException.cs b/src/WindowsPackageManager.Interop/Exceptions/WinGetConfigurationException.cs new file mode 100644 index 0000000..f70c091 --- /dev/null +++ b/src/WindowsPackageManager.Interop/Exceptions/WinGetConfigurationException.cs @@ -0,0 +1,37 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +namespace WindowsPackageManager.Interop; + +public class WinGetConfigurationException : Exception +{ + // WinGet Configuration error codes: + // https://github.com/microsoft/winget-cli/blob/master/src/PowerShell/Microsoft.WinGet.Configuration.Engine/Exceptions/ErrorCodes.cs + public const int WingetConfigErrorInvalidConfigurationFile = unchecked((int)0x8A15C001); + public const int WingetConfigErrorInvalidYaml = unchecked((int)0x8A15C002); + public const int WingetConfigErrorInvalidFieldType = unchecked((int)0x8A15C003); + public const int WingetConfigErrorUnknownConfigurationFileVersion = unchecked((int)0x8A15C004); + public const int WingetConfigErrorSetApplyFailed = unchecked((int)0x8A15C005); + public const int WingetConfigErrorDuplicateIdentifier = unchecked((int)0x8A15C006); + public const int WingetConfigErrorMissingDependency = unchecked((int)0x8A15C007); + public const int WingetConfigErrorDependencyUnsatisfied = unchecked((int)0x8A15C008); + public const int WingetConfigErrorAssertionFailed = unchecked((int)0x8A15C009); + public const int WingetConfigErrorManuallySkipped = unchecked((int)0x8A15C00A); + public const int WingetConfigErrorWarningNotAccepted = unchecked((int)0x8A15C00B); + public const int WingetConfigErrorSetDependencyCycle = unchecked((int)0x8A15C00C); + public const int WingetConfigErrorInvalidFieldValue = unchecked((int)0x8A15C00D); + public const int WingetConfigErrorMissingField = unchecked((int)0x8A15C00E); + + // WinGet Configuration unit error codes: + public const int WinGetConfigUnitNotFound = unchecked((int)0x8A15C101); + public const int WinGetConfigUnitNotFoundRepository = unchecked((int)0x8A15C102); + public const int WinGetConfigUnitMultipleMatches = unchecked((int)0x8A15C103); + public const int WinGetConfigUnitInvokeGet = unchecked((int)0x8A15C104); + public const int WinGetConfigUnitInvokeTest = unchecked((int)0x8A15C105); + public const int WinGetConfigUnitInvokeSet = unchecked((int)0x8A15C106); + public const int WinGetConfigUnitModuleConflict = unchecked((int)0x8A15C107); + public const int WinGetConfigUnitImportModule = unchecked((int)0x8A15C108); + public const int WinGetConfigUnitInvokeInvalidResult = unchecked((int)0x8A15C109); + public const int WinGetConfigUnitSettingConfigRoot = unchecked((int)0x8A15C110); + public const int WinGetConfigUnitImportModuleAdmin = unchecked((int)0x8A15C111); +} diff --git a/src/WindowsPackageManager.Interop/ExternalLibraries.WindowsPackageManager.Interop.csproj b/src/WindowsPackageManager.Interop/ExternalLibraries.WindowsPackageManager.Interop.csproj new file mode 100644 index 0000000..8f2f83b --- /dev/null +++ b/src/WindowsPackageManager.Interop/ExternalLibraries.WindowsPackageManager.Interop.csproj @@ -0,0 +1,74 @@ + + + $(WindowsTargetFramework) + + + true + WindowsPackageManager.Interop + + $(NoWarn);IL2050 + + + + + + $(PkgMicrosoft_Windows_SDK_Contracts)\ref\netstandard2.0 + 10.0.26100.0 + Microsoft.Management.Deployment + $(PkgMicrosoft_WindowsPackageManager_InProcCom)\lib\Microsoft.Management.Deployment.winmd + + + + + + + + + + + + true + none + + + all + runtime; build; native; contentfiles; analyzers + + + + + NU1701 + true + none + false + + + + NU1701 + true + none + + + diff --git a/src/WindowsPackageManager.Interop/NativeMethods.txt b/src/WindowsPackageManager.Interop/NativeMethods.txt new file mode 100644 index 0000000..a7650f2 --- /dev/null +++ b/src/WindowsPackageManager.Interop/NativeMethods.txt @@ -0,0 +1,7 @@ +CoCreateInstance +CoMarshalInterface +CoUnmarshalInterface +CreateStreamOnHGlobal +HRESULT_FROM_WIN32 +MSHCTX +MSHLFLAGS diff --git a/src/WindowsPackageManager.Interop/WindowsPackageManager/ClassModel.cs b/src/WindowsPackageManager.Interop/WindowsPackageManager/ClassModel.cs new file mode 100644 index 0000000..a37bc10 --- /dev/null +++ b/src/WindowsPackageManager.Interop/WindowsPackageManager/ClassModel.cs @@ -0,0 +1,49 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +namespace WindowsPackageManager.Interop; + +internal sealed class ClassModel +{ + /// + /// Gets the interface for the projected class type generated by CsWinRT + /// + public Type InterfaceType { get; init; } = null!; + + /// + /// Gets the projected class type generated by CsWinRT + /// + public Type ProjectedClassType { get; init; } = null!; + + /// + /// Gets the clsids for each context (e.g. OutOfProcProd, OutOfProcDev) + /// + public IReadOnlyDictionary Clsids { get; init; } = null!; + + /// + /// Get CLSID based on the provided context + /// + /// Context + /// CLSID for the provided context. + /// Throw an exception if the clsid context is not available for the current instance. + public Guid GetClsid(ClsidContext context) + { + if (!Clsids.TryGetValue(context, out Guid clsid)) + { + throw new InvalidOperationException( + $"{ProjectedClassType.FullName} is not implemented in context {context}" + ); + } + + return clsid; + } + + /// + /// Get IID corresponding to the COM object + /// + /// IID. + public Guid GetIid() + { + return InterfaceType.GUID; + } +} diff --git a/src/WindowsPackageManager.Interop/WindowsPackageManager/ClassesDefinition.cs b/src/WindowsPackageManager.Interop/WindowsPackageManager/ClassesDefinition.cs new file mode 100644 index 0000000..7ba76c5 --- /dev/null +++ b/src/WindowsPackageManager.Interop/WindowsPackageManager/ClassesDefinition.cs @@ -0,0 +1,118 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using Microsoft.Management.Deployment; + +namespace WindowsPackageManager.Interop; + +internal static class ClassesDefinition +{ + private static Dictionary Classes { get; } = + new() + { + [typeof(PackageManager)] = new() + { + ProjectedClassType = typeof(PackageManager), + InterfaceType = typeof(IPackageManager), + Clsids = new Dictionary + { + [ClsidContext.Prod] = new Guid("C53A4F16-787E-42A4-B304-29EFFB4BF597"), + [ClsidContext.Dev] = new Guid("74CB3139-B7C5-4B9E-9388-E6616DEA288C"), + }, + }, + + [typeof(FindPackagesOptions)] = new() + { + ProjectedClassType = typeof(FindPackagesOptions), + InterfaceType = typeof(IFindPackagesOptions), + Clsids = new Dictionary + { + [ClsidContext.Prod] = new Guid("572DED96-9C60-4526-8F92-EE7D91D38C1A"), + [ClsidContext.Dev] = new Guid("1BD8FF3A-EC50-4F69-AEEE-DF4C9D3BAA96"), + }, + }, + + [typeof(CreateCompositePackageCatalogOptions)] = new() + { + ProjectedClassType = typeof(CreateCompositePackageCatalogOptions), + InterfaceType = typeof(ICreateCompositePackageCatalogOptions), + Clsids = new Dictionary + { + [ClsidContext.Prod] = new Guid("526534B8-7E46-47C8-8416-B1685C327D37"), + [ClsidContext.Dev] = new Guid("EE160901-B317-4EA7-9CC6-5355C6D7D8A7"), + }, + }, + + [typeof(InstallOptions)] = new() + { + ProjectedClassType = typeof(InstallOptions), + InterfaceType = typeof(IInstallOptions), + Clsids = new Dictionary + { + [ClsidContext.Prod] = new Guid("1095F097-EB96-453B-B4E6-1613637F3B14"), + [ClsidContext.Dev] = new Guid("44FE0580-62F7-44D4-9E91-AA9614AB3E86"), + }, + }, + + [typeof(UninstallOptions)] = new() + { + ProjectedClassType = typeof(UninstallOptions), + InterfaceType = typeof(IUninstallOptions), + Clsids = new Dictionary + { + [ClsidContext.Prod] = new Guid("E1D9A11E-9F85-4D87-9C17-2B93143ADB8D"), + [ClsidContext.Dev] = new Guid("AA2A5C04-1AD9-46C4-B74F-6B334AD7EB8C"), + }, + }, + + [typeof(PackageMatchFilter)] = new() + { + ProjectedClassType = typeof(PackageMatchFilter), + InterfaceType = typeof(IPackageMatchFilter), + Clsids = new Dictionary + { + [ClsidContext.Prod] = new Guid("D02C9DAF-99DC-429C-B503-4E504E4AB000"), + [ClsidContext.Dev] = new Guid("3F85B9F4-487A-4C48-9035-2903F8A6D9E8"), + }, + }, + }; + + /// + /// Get CLSID based on the provided context for the specified type + /// + /// Projected class type + /// Context + /// CLSID for the provided context and type, or throw an exception if not found. + /// Throws an exception if type is not a project class. + public static Guid GetClsid(ClsidContext context) + { + ValidateType(); + return Classes[typeof(T)].GetClsid(context); + } + + /// + /// Get IID corresponding to the COM object + /// + /// Projected class type + /// IID or throw an exception if not found. + /// Throws an exception if type is not a project class. + public static Guid GetIid() + { + ValidateType(); + return Classes[typeof(T)].GetIid(); + } + + /// + /// Validate that the provided type is defined. + /// + /// Throws an exception if type is not a project class. + private static void ValidateType() + { + if (!Classes.ContainsKey(typeof(TType))) + { + throw new InvalidOperationException( + $"{typeof(TType).Name} is not a projected class type." + ); + } + } +} diff --git a/src/WindowsPackageManager.Interop/WindowsPackageManager/ClsidContext.cs b/src/WindowsPackageManager.Interop/WindowsPackageManager/ClsidContext.cs new file mode 100644 index 0000000..fab2005 --- /dev/null +++ b/src/WindowsPackageManager.Interop/WindowsPackageManager/ClsidContext.cs @@ -0,0 +1,13 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +namespace WindowsPackageManager.Interop; + +public enum ClsidContext +{ + // Production CLSID Guids + Prod, + + // Development CLSID Guids + Dev, +} diff --git a/src/WindowsPackageManager.Interop/WindowsPackageManager/WindowsPackageManagerElevatedFactory.cs b/src/WindowsPackageManager.Interop/WindowsPackageManager/WindowsPackageManagerElevatedFactory.cs new file mode 100644 index 0000000..e4a93ab --- /dev/null +++ b/src/WindowsPackageManager.Interop/WindowsPackageManager/WindowsPackageManagerElevatedFactory.cs @@ -0,0 +1,56 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +namespace WindowsPackageManager.Interop; + +/// +/// Factory for creating winget COM objects using manual activation +/// to have them in an elevated context. +/// +/// +/// This needs to be called from an elevated context, or the winget +/// server will reject the connection. +/// +/// The WinGetServerManualActivation_CreateInstance function used here is defined in +/// https://github.com/microsoft/winget-cli/blob/master/src/WinGetServer/WinGetServerManualActivation_Client.cpp +/// +/// This class is based on what the winget cmdlets do. See +/// https://github.com/microsoft/winget-cli/blob/master/src/PowerShell/Microsoft.WinGet.Client/Helpers/ComObjectFactory.cs +/// +/*public class WindowsPackageManagerElevatedFactory : WindowsPackageManagerFactory +{ + // The only CLSID context supported by the DLL we call is Prod. + // If we want to use Dev classes we have to use a Dev version of the DLL. + public WindowsPackageManagerElevatedFactory() + : base(ClsidContext.Prod) + { + } + + protected override unsafe T CreateInstance(Guid clsid, Guid iid) + { + void* pUnknown = null; + + try + { + int hr = WinGetServerManualActivation_CreateInstance(in clsid, in iid, 0, out pUnknown); + Marshal.ThrowExceptionForHR(hr); + return MarshalInterface.FromAbi((IntPtr)pUnknown); + } + finally + { + // CoCreateInstance and FromAbi both AddRef on the native object. + // Release once to prevent memory leak. + if (pUnknown is not null) + { + Marshal.Release((IntPtr)pUnknown); + } + } + } + + [DllImport("winrtact.dll")] + private static extern unsafe int WinGetServerManualActivation_CreateInstance( + in Guid clsid, + in Guid iid, + uint flags, + out void* instance); +}*/ diff --git a/src/WindowsPackageManager.Interop/WindowsPackageManager/WindowsPackageManagerFactory.cs b/src/WindowsPackageManager.Interop/WindowsPackageManager/WindowsPackageManagerFactory.cs new file mode 100644 index 0000000..16c5480 --- /dev/null +++ b/src/WindowsPackageManager.Interop/WindowsPackageManager/WindowsPackageManagerFactory.cs @@ -0,0 +1,63 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using Microsoft.Management.Deployment; + +namespace WindowsPackageManager.Interop; + +/// +/// Factory class for creating WinGet COM objects. +/// Details about each method can be found in the source IDL: +/// https://github.com/microsoft/winget-cli/blob/master/src/Microsoft.Management.Deployment/PackageManager.idl +/// +public abstract class WindowsPackageManagerFactory +{ + private readonly ClsidContext _clsidContext; + protected readonly bool _allowLowerTrustRegistration; + + public WindowsPackageManagerFactory( + ClsidContext clsidContext, + bool allowLowerTrustRegistration = false + ) + { + _clsidContext = clsidContext; + _allowLowerTrustRegistration = allowLowerTrustRegistration; + } + + /// + /// Creates an instance of the class . + /// + /// + /// Type must be one of the types defined in the winget COM API. + /// Implementations of this method can assume that and + /// are the right GUIDs for the class in the given context. + /// + protected abstract T CreateInstance(Guid clsid, Guid iid); + + public PackageManager CreatePackageManager() => CreateInstance(); + + public FindPackagesOptions CreateFindPackagesOptions() => CreateInstance(); + + public CreateCompositePackageCatalogOptions CreateCreateCompositePackageCatalogOptions() => + CreateInstance(); + + public InstallOptions CreateInstallOptions() => CreateInstance(); + + public UninstallOptions CreateUninstallOptions() => CreateInstance(); + + public PackageMatchFilter CreatePackageMatchFilter() => CreateInstance(); + + /// + /// Creates an instance of the class . + /// + /// + /// This is a helper for calling the derived class's + /// method with the appropriate GUIDs. + /// + private T CreateInstance() + { + Guid clsid = ClassesDefinition.GetClsid(_clsidContext); + Guid iid = ClassesDefinition.GetIid(); + return CreateInstance(clsid, iid); + } +} diff --git a/src/WindowsPackageManager.Interop/WindowsPackageManager/WindowsPackageManagerStandardFactory.cs b/src/WindowsPackageManager.Interop/WindowsPackageManager/WindowsPackageManagerStandardFactory.cs new file mode 100644 index 0000000..20ac87a --- /dev/null +++ b/src/WindowsPackageManager.Interop/WindowsPackageManager/WindowsPackageManagerStandardFactory.cs @@ -0,0 +1,95 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using System.Diagnostics.CodeAnalysis; +using System.Runtime.InteropServices; +using System.Runtime.Versioning; +using Windows.Win32.System.Com; +using WinRT; + +namespace WindowsPackageManager.Interop; + +[SupportedOSPlatform("windows5.0")] +public class WindowsPackageManagerStandardFactory : WindowsPackageManagerFactory +{ + public WindowsPackageManagerStandardFactory( + ClsidContext clsidContext = ClsidContext.Prod, + bool allowLowerTrustRegistration = false + ) + : base(clsidContext, allowLowerTrustRegistration) { } + + [UnconditionalSuppressMessage( + "Trimming", + "IL2072", + Justification = "WinGet COM projected activation types come from the Windows Package Manager WinMD and registered COM server; this path does not depend on app-owned trimmed constructors.")] + protected override T CreateInstance(Guid clsid, Guid iid) + { + if (!_allowLowerTrustRegistration) + { + Type? projectedType = Type.GetTypeFromCLSID(clsid); + if (projectedType is null) + { + throw new WinGetComActivationException( + clsid, + iid, + unchecked((int)0x80040154), + _allowLowerTrustRegistration + ); + } + + object? activatedInstance = Activator.CreateInstance(projectedType); + if (activatedInstance is null) + { + throw new WinGetComActivationException( + clsid, + iid, + unchecked((int)0x80004003), + _allowLowerTrustRegistration + ); + } + + IntPtr pointer = Marshal.GetIUnknownForObject(activatedInstance); + return MarshalGeneric.FromAbi(pointer); + } + + CLSCTX clsctx = CLSCTX.CLSCTX_LOCAL_SERVER; + if (_allowLowerTrustRegistration) + { + clsctx |= CLSCTX.CLSCTX_ALLOW_LOWER_TRUST_REGISTRATION; + } + + int errorCode = CoCreateInstanceRaw( + in clsid, + IntPtr.Zero, + (uint)clsctx, + in iid, + out IntPtr instance + ); + + if (errorCode < 0) + { + throw new WinGetComActivationException( + clsid, + iid, + errorCode, + _allowLowerTrustRegistration + ); + } + + return MarshalGeneric.FromAbi(instance); + } + + [DllImport( + "api-ms-win-core-com-l1-1-0.dll", + EntryPoint = "CoCreateInstance", + ExactSpelling = true, + PreserveSig = true + )] + private static extern int CoCreateInstanceRaw( + in Guid clsid, + IntPtr pUnkOuter, + uint dwClsContext, + in Guid iid, + out IntPtr instance + ); +} diff --git a/testing/UPDATE-TESTING.md b/testing/UPDATE-TESTING.md new file mode 100644 index 0000000..51d753e --- /dev/null +++ b/testing/UPDATE-TESTING.md @@ -0,0 +1,176 @@ +# UniGetUI Auto-Update Testing Guide (ProductInfo-only path) + +This guide validates the ProductInfo-only auto-update flow that reads from `productinfo.json`. + +UniGetUI no longer falls back to the legacy updater logic. If the ProductInfo lookup fails, the update check fails. + +## Files used + +- `testing/productinfo.unigetui.test.json` +- Test artifacts expected by that file: + - `UniGetUI.Installer.x64.exe` + - `UniGetUI.Installer.arm64.exe` + - `UniGetUI.x64.zip` + - `UniGetUI.arm64.zip` + +## What is being tested + +- Default updater source is ProductInfo-based. +- Product key lookup for `Devolutions.UniGetUI`. +- Architecture-aware installer selection (`x64`/`arm64`, `exe` preferred). +- Hash validation (enabled by default). +- Debug-only override behavior via registry keys under `HKLM\Software\Devolutions\UniGetUI`. + +## Release vs Debug behavior + +- Release builds honor only `UpdaterProductInfoUrl` from `HKLM\Software\Devolutions\UniGetUI`. +- Release builds ignore `UpdaterProductKey` and all validation-bypass flags. +- Debug builds can read updater overrides from `HKLM\Software\Devolutions\UniGetUI` for local testing. +- Dangerous validation bypasses are for Debug/dev testing only: + - `UpdaterAllowUnsafeUrls` + - `UpdaterSkipHashValidation` + - `UpdaterSkipSignerThumbprintCheck` + - `UpdaterDisableTlsValidation` + +## 1) Host the test files locally + +From repository root: + +```powershell +Push-Location testing +python -m http.server 8080 +Pop-Location +``` + +Make sure these URLs are reachable: + +- `http://127.0.0.1:8080/productinfo.unigetui.test.json` +- `http://127.0.0.1:8080/UniGetUI.Installer.x64.exe` +- `http://127.0.0.1:8080/UniGetUI.Installer.arm64.exe` + +## 2) Configure updater overrides (test mode) + +These steps apply to a Debug build only. + +Run in PowerShell: + +```powershell +$regPath = 'HKLM:\Software\Devolutions\UniGetUI' +New-Item -Path $regPath -Force | Out-Null + +# Point updater to local productinfo +Set-ItemProperty -Path $regPath -Name 'UpdaterProductInfoUrl' -Value 'http://127.0.0.1:8080/productinfo.unigetui.test.json' + +# Product key inside productinfo JSON +Set-ItemProperty -Path $regPath -Name 'UpdaterProductKey' -Value 'Devolutions.UniGetUI' + +# Allow local http URL and local domain for package downloads +Set-ItemProperty -Path $regPath -Name 'UpdaterAllowUnsafeUrls' -Type DWord -Value 1 + +# Keep hash validation enabled for normal test pass +Set-ItemProperty -Path $regPath -Name 'UpdaterSkipHashValidation' -Type DWord -Value 0 + +# Keep signer thumbprint validation enabled for normal test pass +Set-ItemProperty -Path $regPath -Name 'UpdaterSkipSignerThumbprintCheck' -Type DWord -Value 0 + +# Optional only for HTTPS cert troubleshooting in test environments +Set-ItemProperty -Path $regPath -Name 'UpdaterDisableTlsValidation' -Type DWord -Value 0 +``` + +## 3) Trigger update check in UniGetUI + +1. Launch UniGetUI. +2. Go to **Settings → General**. +3. Click **Check for updates**. + +Expected result: + +- Updater reads the local `productinfo.unigetui.test.json`. +- It picks the correct architecture `exe` installer. +- Download starts and hash is validated. +- Update banner/toast appears when update is ready. + +## 4) Negative test: hash mismatch protection + +Use one of these methods: + +- Replace installer file content but keep original hash in JSON, or +- Edit hash in JSON to an incorrect value. + +Expected result: + +- Hash validation fails. +- Update is aborted with installer authenticity error. + +## 5) Negative test: block unsafe URLs + +Set: + +```powershell +Set-ItemProperty -Path 'HKLM:\Software\Devolutions\UniGetUI' -Name 'UpdaterAllowUnsafeUrls' -Type DWord -Value 0 +``` + +Expected result with local `http://127.0.0.1` URLs: + +- Updater rejects source/download URL as unsafe. +- No installer launch. + +## 6) Negative test: broken ProductInfo source + +Use one of these methods: + +- Point `UpdaterProductInfoUrl` to a missing URL, or +- Point `UpdaterProductInfoUrl` to a malformed JSON file, or +- In a Debug build only, point `UpdaterProductKey` to a non-existent product. + +Example: + +```powershell +Set-ItemProperty -Path 'HKLM:\Software\Devolutions\UniGetUI' -Name 'UpdaterProductInfoUrl' -Value 'http://127.0.0.1:8080/does-not-exist.json' +``` + +Expected result: + +- Productinfo check fails. +- UniGetUI reports the update-check failure. +- No fallback source is used. + +## 7) Optional: disable signer thumbprint check (test-only) + +Use this only if your local installer is unsigned or signed with a non-Devolutions certificate. + +```powershell +Set-ItemProperty -Path 'HKLM:\Software\Devolutions\UniGetUI' -Name 'UpdaterSkipSignerThumbprintCheck' -Type DWord -Value 1 +``` + +## 8) Release-build hardening check + +Run the same registry override setup against a Release build. + +Expected result: + +- Release build honors `UpdaterProductInfoUrl` only if it still passes normal source validation. +- Release build ignores `UpdaterProductKey`. +- Release build ignores validation bypass flags. +- Updater uses the configured ProductInfo URL and the built-in `Devolutions.UniGetUI` product key. + +## 9) Cleanup after testing + +Reset to default production behavior: + +```powershell +$regPath = 'HKLM:\Software\Devolutions\UniGetUI' +Remove-ItemProperty -Path $regPath -Name 'UpdaterProductInfoUrl' -ErrorAction SilentlyContinue +Remove-ItemProperty -Path $regPath -Name 'UpdaterProductKey' -ErrorAction SilentlyContinue +Remove-ItemProperty -Path $regPath -Name 'UpdaterAllowUnsafeUrls' -ErrorAction SilentlyContinue +Remove-ItemProperty -Path $regPath -Name 'UpdaterSkipHashValidation' -ErrorAction SilentlyContinue +Remove-ItemProperty -Path $regPath -Name 'UpdaterSkipSignerThumbprintCheck' -ErrorAction SilentlyContinue +Remove-ItemProperty -Path $regPath -Name 'UpdaterDisableTlsValidation' -ErrorAction SilentlyContinue +``` + +With all override values removed, UniGetUI uses: + +- `https://devolutions.net/productinfo.json` +- product key `Devolutions.UniGetUI` +- safety checks enabled +- hash validation enabled diff --git a/testing/automation/cli-e2e.manifest.linux-nativeaot.json b/testing/automation/cli-e2e.manifest.linux-nativeaot.json new file mode 100644 index 0000000..16d1ca1 --- /dev/null +++ b/testing/automation/cli-e2e.manifest.linux-nativeaot.json @@ -0,0 +1,99 @@ +{ + "name": "linux-headless-ipc", + "daemon": { + "kind": "avalonia-native", + "project": "UniGetUI.Avalonia\\UniGetUI.Avalonia.csproj", + "assemblyName": "UniGetUI" + }, + "transport": { + "kind": "named-pipe", + "verifyNoTcpListener": false + }, + "secureSettings": { + "allowSet": true, + "toggleKey": "AllowCustomManagerPaths", + "managerForExecutableOverride": "npm" + }, + "uninstallValidationManagers": [ + "pip" + ], + "packageManagers": [ + { + "manager": "pip", + "sourceName": "pip", + "query": "cowsay", + "packageId": "cowsay", + "installVersion": "5.0", + "scope": "User", + "roles": [ + "specific-update" + ] + }, + { + "manager": "npm", + "sourceName": "npm", + "query": "cowsay", + "packageId": "cowsay", + "installVersion": "1.5.0", + "scope": "Global", + "roles": [ + "bundle", + "update-manager", + "reinstall", + "repair", + "toggle-manager", + "update-all" + ] + } + ], + "queueOperations": [ + { + "manager": "pip", + "sourceName": "pip", + "packageId": "awscli", + "target": "download", + "query": "awscli" + }, + { + "manager": "npm", + "sourceName": "npm", + "packageId": "typescript", + "target": "download", + "query": "typescript" + } + ], + "excludedCommands": [ + { + "command": "manager action", + "reason": "Current manager actions are Windows-specific and system-changing, so they are intentionally excluded from Linux CI." + }, + { + "command": "source add", + "reason": "The deterministic Linux manager matrix does not include a manager with reliable CI-safe custom source mutation." + }, + { + "command": "source remove", + "reason": "The deterministic Linux manager matrix does not include a manager with reliable CI-safe custom source mutation." + }, + { + "command": "operation cancel", + "reason": "Queued package downloads complete too quickly on current Linux CI runners to guarantee a stable cancellable operation window." + }, + { + "command": "operation retry", + "reason": "A deterministic retry scenario depends on first forcing a stable failed or canceled operation, which is not yet reliable in CI." + }, + { + "command": "operation reorder", + "reason": "Queued package downloads complete too quickly on current Linux CI runners to guarantee a stable reorderable operation window." + }, + { + "command": "backup github *", + "reason": "GitHub device-flow authentication is intentionally excluded from deterministic CI." + }, + { + "command": "backup cloud *", + "reason": "Cloud backup flows depend on external authenticated GitHub state and are intentionally excluded from deterministic CI." + } + ] +} diff --git a/testing/automation/cli-e2e.manifest.linux.json b/testing/automation/cli-e2e.manifest.linux.json new file mode 100644 index 0000000..5d20967 --- /dev/null +++ b/testing/automation/cli-e2e.manifest.linux.json @@ -0,0 +1,99 @@ +{ + "name": "linux-headless-ipc", + "daemon": { + "kind": "avalonia-dll", + "project": "UniGetUI.Avalonia\\UniGetUI.Avalonia.csproj", + "assemblyName": "UniGetUI" + }, + "transport": { + "kind": "named-pipe", + "verifyNoTcpListener": false + }, + "secureSettings": { + "allowSet": true, + "toggleKey": "AllowCustomManagerPaths", + "managerForExecutableOverride": "npm" + }, + "uninstallValidationManagers": [ + "pip" + ], + "packageManagers": [ + { + "manager": "pip", + "sourceName": "pip", + "query": "cowsay", + "packageId": "cowsay", + "installVersion": "5.0", + "scope": "User", + "roles": [ + "specific-update" + ] + }, + { + "manager": "npm", + "sourceName": "npm", + "query": "cowsay", + "packageId": "cowsay", + "installVersion": "1.5.0", + "scope": "Global", + "roles": [ + "bundle", + "update-manager", + "reinstall", + "repair", + "toggle-manager", + "update-all" + ] + } + ], + "queueOperations": [ + { + "manager": "pip", + "sourceName": "pip", + "packageId": "awscli", + "target": "download", + "query": "awscli" + }, + { + "manager": "npm", + "sourceName": "npm", + "packageId": "typescript", + "target": "download", + "query": "typescript" + } + ], + "excludedCommands": [ + { + "command": "manager action", + "reason": "Current manager actions are Windows-specific and system-changing, so they are intentionally excluded from Linux CI." + }, + { + "command": "source add", + "reason": "The deterministic Linux manager matrix does not include a manager with reliable CI-safe custom source mutation." + }, + { + "command": "source remove", + "reason": "The deterministic Linux manager matrix does not include a manager with reliable CI-safe custom source mutation." + }, + { + "command": "operation cancel", + "reason": "Queued package downloads complete too quickly on current Linux CI runners to guarantee a stable cancellable operation window." + }, + { + "command": "operation retry", + "reason": "A deterministic retry scenario depends on first forcing a stable failed or canceled operation, which is not yet reliable in CI." + }, + { + "command": "operation reorder", + "reason": "Queued package downloads complete too quickly on current Linux CI runners to guarantee a stable reorderable operation window." + }, + { + "command": "backup github *", + "reason": "GitHub device-flow authentication is intentionally excluded from deterministic CI." + }, + { + "command": "backup cloud *", + "reason": "Cloud backup flows depend on external authenticated GitHub state and are intentionally excluded from deterministic CI." + } + ] +} diff --git a/testing/automation/cli-e2e.manifest.windows.json b/testing/automation/cli-e2e.manifest.windows.json new file mode 100644 index 0000000..28329ba --- /dev/null +++ b/testing/automation/cli-e2e.manifest.windows.json @@ -0,0 +1,105 @@ +{ + "name": "windows-headless-ipc", + "daemon": { + "kind": "avalonia-dll", + "project": "UniGetUI.Avalonia\\UniGetUI.Avalonia.csproj", + "assemblyName": "UniGetUI" + }, + "transport": { + "kind": "named-pipe", + "verifyNoTcpListener": true + }, + "secureSettings": { + "allowSet": false, + "toggleKey": "AllowCustomManagerPaths", + "managerForExecutableOverride": "npm" + }, + "packageManagers": [ + { + "manager": "dotnet-tool", + "sourceName": "nuget.org", + "query": "dotnetsay", + "packageId": "dotnetsay", + "installVersion": "2.1.4", + "scope": "Global", + "roles": [ + "bundle", + "update-manager", + "reinstall", + "repair" + ] + }, + { + "manager": "npm", + "sourceName": "npm", + "query": "cowsay", + "packageId": "cowsay", + "installVersion": "1.5.0", + "scope": "Global", + "roles": [ + "specific-update", + "toggle-manager", + "update-all", + "update-discovery" + ] + } + ], + "queueOperations": [ + { + "manager": "npm", + "sourceName": "npm", + "packageId": "typescript", + "target": "download", + "query": "typescript" + } + ], + "uninstallValidationManagers": [ + "dotnet-tool" + ], + "excludedCommands": [ + { + "command": "manager action", + "reason": "Windows manager actions require elevated system changes that are not deterministic on hosted runners." + }, + { + "command": "settings secure set", + "reason": "Secure setting writes on Windows elevate via runas, which is not deterministic in GitHub-hosted CI." + }, + { + "command": "source add", + "reason": "The deterministic Windows manager matrix does not include a manager with reliable CI-safe custom source mutation." + }, + { + "command": "source remove", + "reason": "The deterministic Windows manager matrix does not include a manager with reliable CI-safe custom source mutation." + }, + { + "command": "operation cancel", + "reason": "Queued package downloads complete too quickly on current Windows CI runners to guarantee a stable cancellable operation window." + }, + { + "command": "operation retry", + "reason": "A deterministic retry scenario depends on first forcing a stable failed or canceled operation, which is not yet reliable in CI." + }, + { + "command": "operation reorder", + "reason": "Queued package downloads complete too quickly on current Windows CI runners to guarantee a stable reorderable operation window." + }, + { + "command": "manager set-executable", + "reason": "Custom manager path coverage depends on secure setting writes, which are skipped on Windows CI." + }, + { + "command": "manager clear-executable", + "reason": "Custom manager path coverage depends on secure setting writes, which are skipped on Windows CI." + }, + { + "command": "backup github *", + "reason": "GitHub device-flow authentication is intentionally excluded from deterministic CI." + }, + { + "command": "backup cloud *", + "reason": "Cloud backup flows depend on external authenticated GitHub state and are intentionally excluded from deterministic CI." + } + ] +} diff --git a/testing/automation/run-cli-e2e.ps1 b/testing/automation/run-cli-e2e.ps1 new file mode 100644 index 0000000..b87c3b9 --- /dev/null +++ b/testing/automation/run-cli-e2e.ps1 @@ -0,0 +1,1155 @@ +$ErrorActionPreference = 'Stop' +Set-StrictMode -Version Latest + +$runningOnWindows = [System.Runtime.InteropServices.RuntimeInformation]::IsOSPlatform( + [System.Runtime.InteropServices.OSPlatform]::Windows +) + +$repoRoot = Split-Path -Parent (Split-Path -Parent $PSScriptRoot) +$srcRoot = Join-Path $repoRoot 'src' +$configuration = if ($env:CONFIGURATION) { $env:CONFIGURATION } else { 'Release' } +$defaultManifest = if ($runningOnWindows) { + Join-Path $PSScriptRoot 'cli-e2e.manifest.windows.json' +} +else { + Join-Path $PSScriptRoot 'cli-e2e.manifest.linux.json' +} +$manifestPath = if ($env:UNIGETUI_CLI_E2E_MANIFEST) { + $env:UNIGETUI_CLI_E2E_MANIFEST +} +else { + $defaultManifest +} + +if (-not (Test-Path $manifestPath)) { + throw "CLI E2E manifest not found at $manifestPath" +} + +$manifest = Get-Content $manifestPath -Raw | ConvertFrom-Json -AsHashtable +if ($null -eq $manifest) { + throw "Could not parse CLI E2E manifest at $manifestPath" +} + +$artifactRoot = if ($env:UNIGETUI_CLI_E2E_ARTIFACTS) { + $env:UNIGETUI_CLI_E2E_ARTIFACTS +} +else { + Join-Path ([System.IO.Path]::GetTempPath()) ("unigetui-cli-e2e-" + [Guid]::NewGuid().ToString('N')) +} +if (Test-Path $artifactRoot) { + Remove-Item -Recurse -Force $artifactRoot +} +New-Item -ItemType Directory -Path $artifactRoot -Force | Out-Null +$artifactRoot = (Resolve-Path $artifactRoot).Path + +$daemonRoot = $artifactRoot +$downloadRoot = Join-Path $daemonRoot 'downloads' +$coveragePath = Join-Path $daemonRoot 'coverage.json' +$inventoryPath = Join-Path $daemonRoot 'environment.json' +$daemonStdOutLog = Join-Path $daemonRoot 'headless-daemon.stdout.log' +$daemonStdErrLog = Join-Path $daemonRoot 'headless-daemon.stderr.log' +$preserveArtifacts = $true + +$localDataRoot = if ($runningOnWindows) { + Join-Path $daemonRoot 'AppData\Local' +} +else { + Join-Path $daemonRoot '.local\share' +} +$roamingDataRoot = if ($runningOnWindows) { + Join-Path $daemonRoot 'AppData\Roaming' +} +else { + $null +} +$dotnetHomeRoot = Join-Path $daemonRoot '.dotnet-home' +$npmGlobalRoot = Join-Path $daemonRoot 'npm-global' + +New-Item -ItemType Directory -Path $downloadRoot -Force | Out-Null +New-Item -ItemType Directory -Path $localDataRoot -Force | Out-Null +New-Item -ItemType Directory -Path $dotnetHomeRoot -Force | Out-Null +New-Item -ItemType Directory -Path $npmGlobalRoot -Force | Out-Null +if (-not [string]::IsNullOrWhiteSpace($roamingDataRoot)) { + New-Item -ItemType Directory -Path $roamingDataRoot -Force | Out-Null +} + +$env:DOTNET_CLI_HOME = $dotnetHomeRoot +$env:DOTNET_SKIP_FIRST_TIME_EXPERIENCE = '1' +$env:DOTNET_CLI_TELEMETRY_OPTOUT = '1' +$env:UNIGETUI_GITHUB_TOKEN_NAMESPACE = "cli-e2e-$([Guid]::NewGuid().ToString('N'))" +$env:UNIGETUI_AVALONIA_DEVTOOLS = 'disabled' +$env:npm_config_prefix = $npmGlobalRoot + +if (-not $runningOnWindows) { + $env:HOME = $daemonRoot + $env:USERPROFILE = $daemonRoot + $env:XDG_DATA_HOME = $localDataRoot +} + +$coverage = [ordered]@{ + manifest = $manifest.name + tested = @() + excluded = @($manifest.excludedCommands) +} + +function Add-Tested { + param( + [Parameter(Mandatory = $true)] + [string] $Command, + [string] $Mode = 'success' + ) + + $script:coverage.tested += [ordered]@{ + command = $Command + mode = $Mode + } +} + +function Write-Stage { + param( + [Parameter(Mandatory = $true)] + [string] $Name + ) + + Write-Host "== $Name ==" +} + +function Find-BuiltArtifact { + param( + [Parameter(Mandatory = $true)] + [string] $ProjectDirectory, + [Parameter(Mandatory = $true)] + [string] $FileName + ) + + $outputRoot = Join-Path $ProjectDirectory 'bin' + if (-not (Test-Path $outputRoot)) { + return $null + } + + return Get-ChildItem -Path $outputRoot -Recurse -File -Filter $FileName | + Sort-Object @{ + Expression = { if ($_.FullName -like "*\bin\*\$configuration\*") { 0 } else { 1 } } + }, @{ + Expression = { $_.FullName } + } | + Select-Object -First 1 -ExpandProperty FullName +} + +function Get-ManifestManagerByRole { + param( + [Parameter(Mandatory = $true)] + [string] $Role + ) + + $matches = @($manifest.packageManagers | Where-Object { @($_.roles) -contains $Role }) + if ($matches.Count -eq 0) { + return $null + } + + return $matches[0] +} + +function Get-PackageArguments { + param( + [Parameter(Mandatory = $true)] + [hashtable] $Fixture, + [switch] $IncludeVersion, + [switch] $IncludeSource + ) + + $arguments = @( + '--manager', [string]$Fixture.manager, + '--id', [string]$Fixture.packageId + ) + if ($IncludeVersion -and $Fixture.ContainsKey('installVersion')) { + $arguments += @('--version', [string]$Fixture.installVersion) + } + if ($IncludeSource -and $Fixture.ContainsKey('sourceName')) { + $arguments += @('--source', [string]$Fixture.sourceName) + } + if ($Fixture.ContainsKey('scope')) { + $arguments += @('--scope', [string]$Fixture.scope) + } + return $arguments +} + +function Find-PackageMatch { + param( + [Parameter(Mandatory = $true)] + [object[]] $Packages, + [Parameter(Mandatory = $true)] + [hashtable] $Fixture, + [string] $Version + ) + + return @($Packages | Where-Object { + $_.id -eq $Fixture.packageId -and ( + -not $PSBoundParameters.ContainsKey('Version') -or $_.version -eq $Version + ) + })[0] +} + +function Resolve-QueueOutputPath { + param( + [Parameter(Mandatory = $true)] + [hashtable] $QueueFixture + ) + + $safeManager = ([string]$QueueFixture.manager) -replace '[^A-Za-z0-9._-]', '_' + $safePackage = ([string]$QueueFixture.packageId) -replace '[^A-Za-z0-9._-]', '_' + $targetDirectory = Join-Path $downloadRoot "$safeManager-$safePackage" + New-Item -ItemType Directory -Path $targetDirectory -Force | Out-Null + return $targetDirectory +} + +function Get-DaemonCommand { + $daemonProject = Join-Path $srcRoot ([string]$manifest.daemon.project) + if (-not (Test-Path $daemonProject)) { + throw "Daemon project not found at $daemonProject" + } + + switch ([string]$manifest.daemon.kind) { + 'windows-exe' { + $daemonExe = if ($env:UNIGETUI_DAEMON_EXE) { + $env:UNIGETUI_DAEMON_EXE + } + else { + Find-BuiltArtifact -ProjectDirectory (Split-Path $daemonProject -Parent) -FileName "$($manifest.daemon.assemblyName).exe" + } + if ([string]::IsNullOrWhiteSpace($daemonExe) -or -not (Test-Path $daemonExe)) { + throw "Windows headless executable was not found. Expected $($manifest.daemon.assemblyName).exe under $(Split-Path $daemonProject -Parent)\bin\$configuration" + } + + return @{ + FilePath = (Resolve-Path $daemonExe).Path + WorkingDirectory = Split-Path (Resolve-Path $daemonExe).Path -Parent + } + } + 'avalonia-dll' { + $daemonDll = if ($env:UNIGETUI_DAEMON_DLL) { + $env:UNIGETUI_DAEMON_DLL + } + else { + Find-BuiltArtifact -ProjectDirectory (Split-Path $daemonProject -Parent) -FileName "$($manifest.daemon.assemblyName).dll" + } + if ([string]::IsNullOrWhiteSpace($daemonDll) -or -not (Test-Path $daemonDll)) { + throw "Avalonia headless daemon DLL was not found. Expected $($manifest.daemon.assemblyName).dll under $(Split-Path $daemonProject -Parent)\bin\$configuration" + } + + $resolvedDll = (Resolve-Path $daemonDll).Path + return @{ + FilePath = 'dotnet' + WorkingDirectory = Split-Path $resolvedDll -Parent + PrefixArguments = @($resolvedDll) + } + } + 'avalonia-native' { + $fileName = if ($runningOnWindows) { "$($manifest.daemon.assemblyName).exe" } else { $manifest.daemon.assemblyName } + $daemonNative = if ($env:UNIGETUI_DAEMON_EXE) { + $env:UNIGETUI_DAEMON_EXE + } + else { + Find-BuiltArtifact -ProjectDirectory (Split-Path $daemonProject -Parent) -FileName $fileName + } + if ([string]::IsNullOrWhiteSpace($daemonNative) -or -not (Test-Path $daemonNative)) { + throw "NativeAOT headless executable was not found. Expected $fileName under $(Split-Path $daemonProject -Parent)\bin\$configuration" + } + + return @{ + FilePath = (Resolve-Path $daemonNative).Path + WorkingDirectory = Split-Path (Resolve-Path $daemonNative).Path -Parent + } + } + default { + throw "Unsupported daemon kind $($manifest.daemon.kind)" + } + } +} + +$pipeName = "UniGetUI.CI.$([Guid]::NewGuid().ToString('N'))" +$transportArgs = @('--transport', 'named-pipe', '--pipe-name', $pipeName) +$daemonExtraArgs = @('--headless', '--ipc-api-transport', 'named-pipe', '--ipc-api-pipe-name', $pipeName) +$daemonStartupTimeoutSeconds = if ($runningOnWindows) { 300 } else { 120 } +$daemonCommand = Get-DaemonCommand +$cliCommand = $daemonCommand +$process = $null +$gracefulShutdown = $false + +function Get-DaemonLog { + $stdout = if (Test-Path $daemonStdOutLog) { Get-Content $daemonStdOutLog -Raw } else { '' } + $stderr = if (Test-Path $daemonStdErrLog) { Get-Content $daemonStdErrLog -Raw } else { '' } + return ($stdout, $stderr -join [Environment]::NewLine).Trim() +} + +function Stop-Daemon { + if ($null -ne $script:process -and -not $script:process.HasExited) { + Stop-Process -Id $script:process.Id + } +} + +function Invoke-CliRaw { + param( + [Parameter(Mandatory = $true)] + [string[]] $Arguments + ) + + $commandArguments = @() + if ($cliCommand.ContainsKey('PrefixArguments')) { + $commandArguments += $cliCommand.PrefixArguments + } + $commandArguments += $transportArgs + $Arguments + $startInfo = [System.Diagnostics.ProcessStartInfo]::new() + $startInfo.FileName = $cliCommand.FilePath + $startInfo.WorkingDirectory = $cliCommand.WorkingDirectory + $startInfo.UseShellExecute = $false + $startInfo.RedirectStandardOutput = $true + $startInfo.RedirectStandardError = $true + foreach ($argument in $commandArguments) { + [void]$startInfo.ArgumentList.Add([string]$argument) + } + + $commandProcess = [System.Diagnostics.Process]::Start($startInfo) + if ($null -eq $commandProcess) { + throw "Failed to start CLI command: $($cliCommand.FilePath) $($commandArguments -join ' ')" + } + + $stdout = $commandProcess.StandardOutput.ReadToEnd() + $stderr = $commandProcess.StandardError.ReadToEnd() + $commandProcess.WaitForExit() + $text = (@($stdout, $stderr) | Where-Object { -not [string]::IsNullOrWhiteSpace($_) } | ForEach-Object { + $_.TrimEnd() + }) -join [Environment]::NewLine + return @{ + ExitCode = $commandProcess.ExitCode + Text = $text + } +} + +function Invoke-CliJson { + param( + [Parameter(Mandatory = $true)] + [string[]] $Arguments + ) + + $result = Invoke-CliRaw -Arguments $Arguments + if ($result.ExitCode -ne 0) { + throw "CLI command failed ($($result.ExitCode)): $($Arguments -join ' ')`n$($result.Text)" + } + if ([string]::IsNullOrWhiteSpace($result.Text)) { + throw "CLI command returned empty output: $($Arguments -join ' ')" + } + return $result.Text | ConvertFrom-Json +} + +function Invoke-CliFailure { + param( + [Parameter(Mandatory = $true)] + [string[]] $Arguments + ) + + $result = Invoke-CliRaw -Arguments $Arguments + if ($result.ExitCode -eq 0) { + throw "CLI command unexpectedly succeeded: $($Arguments -join ' ')`n$($result.Text)" + } + return $result +} + +function Wait-ForCliCondition { + param( + [Parameter(Mandatory = $true)] + [string[]] $Arguments, + [Parameter(Mandatory = $true)] + [scriptblock] $Condition, + [Parameter(Mandatory = $true)] + [string] $FailureMessage, + [int] $TimeoutSeconds = 120, + [int] $DelaySeconds = 2 + ) + + $deadline = (Get-Date).AddSeconds($TimeoutSeconds) + $lastResponse = $null + $lastError = $null + + do { + try { + $lastResponse = Invoke-CliJson -Arguments $Arguments + $lastError = $null + if (& $Condition $lastResponse) { + return $lastResponse + } + } + catch { + $lastError = $_.Exception.Message + } + + Start-Sleep -Seconds $DelaySeconds + } while ((Get-Date) -lt $deadline) + + if ($null -ne $lastResponse) { + throw "$FailureMessage`nLast payload: $($lastResponse | ConvertTo-Json -Depth 10)" + } + + throw "$FailureMessage`nLast error: $lastError" +} + +function Wait-ForInstalledPackage { + param( + [Parameter(Mandatory = $true)] + [hashtable] $Fixture, + [string] $ExpectedVersion, + [int] $TimeoutSeconds = 180 + ) + + return Wait-ForCliCondition ` + -Arguments @('package', 'installed', '--manager', [string]$Fixture.manager) ` + -Condition { + param($response) + @($response.packages | Where-Object { + $_.id -eq $Fixture.packageId -and ( + [string]::IsNullOrWhiteSpace($ExpectedVersion) -or $_.version -eq $ExpectedVersion + ) + }).Count -gt 0 + } ` + -FailureMessage "package installed did not report $($Fixture.packageId) for manager $($Fixture.manager)" ` + -TimeoutSeconds $TimeoutSeconds ` + -DelaySeconds 3 +} + +function Wait-ForPackageRemoval { + param( + [Parameter(Mandatory = $true)] + [hashtable] $Fixture, + [int] $TimeoutSeconds = 180 + ) + + return Wait-ForCliCondition ` + -Arguments @('package', 'installed', '--manager', [string]$Fixture.manager) ` + -Condition { + param($response) + @($response.packages | Where-Object { $_.id -eq $Fixture.packageId }).Count -eq 0 + } ` + -FailureMessage "$($Fixture.packageId) still appears in package installed for manager $($Fixture.manager)" ` + -TimeoutSeconds $TimeoutSeconds ` + -DelaySeconds 3 +} + +function Wait-ForPackageUpdateVisibility { + param( + [Parameter(Mandatory = $true)] + [hashtable] $Fixture, + [int] $TimeoutSeconds = 120 + ) + + return Wait-ForCliCondition ` + -Arguments @('package', 'updates', '--manager', [string]$Fixture.manager) ` + -Condition { + param($response) + @($response.updates | Where-Object { $_.id -eq $Fixture.packageId }).Count -gt 0 + } ` + -FailureMessage "package updates did not report $($Fixture.packageId) for manager $($Fixture.manager)" ` + -TimeoutSeconds $TimeoutSeconds ` + -DelaySeconds 3 +} + +function Get-LatestFixtureVersion { + param( + [Parameter(Mandatory = $true)] + [hashtable] $Fixture, + [Parameter(Mandatory = $true)] + [object] $SearchResponse, + [Parameter(Mandatory = $true)] + [object] $VersionResponse + ) + + $searchMatch = @($SearchResponse.packages | Where-Object { $_.id -eq $Fixture.packageId })[0] + if ($null -eq $searchMatch) { + throw "package search did not return $($Fixture.packageId) for manager $($Fixture.manager)" + } + + $candidateVersions = @() + if (-not [string]::IsNullOrWhiteSpace($searchMatch.version)) { + $candidateVersions += [string]$searchMatch.version + } + $candidateVersions += @($VersionResponse.versions) + + $latestVersion = @($candidateVersions | Where-Object { + -not [string]::IsNullOrWhiteSpace($_) -and $_ -ne $Fixture.installVersion + })[0] + + if ([string]::IsNullOrWhiteSpace($latestVersion)) { + throw "Could not resolve a newer version for $($Fixture.packageId) on manager $($Fixture.manager)" + } + + return [string]$latestVersion +} + +function Assert-JsonCommandSucceeded { + param( + [Parameter(Mandatory = $true)] + [object] $Response, + [Parameter(Mandatory = $true)] + [string] $Label + ) + + if ($Response.status -ne 'success') { + throw "$Label failed: $($Response | ConvertTo-Json -Depth 10)" + } +} + +function Write-EnvironmentInventory { + $inventory = [ordered]@{ + manifest = $manifest.name + os = if ($runningOnWindows) { 'windows' } else { 'linux' } + dotnet = (& dotnet --version) + python = '' + pip = '' + npm = '' + } + + try { + $inventory.python = (& python --version 2>&1 | Out-String).Trim() + } + catch { + $inventory.python = $_.Exception.Message + } + + try { + $inventory.pip = (& python -m pip --version 2>&1 | Out-String).Trim() + } + catch { + $inventory.pip = $_.Exception.Message + } + + try { + $inventory.npm = (& npm --version 2>&1 | Out-String).Trim() + } + catch { + $inventory.npm = $_.Exception.Message + } + + Set-Content -Path $inventoryPath -Value ($inventory | ConvertTo-Json -Depth 8) -Encoding UTF8 +} + +Write-EnvironmentInventory + +try { + $daemonArguments = @() + if ($daemonCommand.ContainsKey('PrefixArguments')) { + $daemonArguments += $daemonCommand.PrefixArguments + } + $daemonArguments += $daemonExtraArgs + + $process = Start-Process ` + -FilePath $daemonCommand.FilePath ` + -ArgumentList $daemonArguments ` + -WorkingDirectory $daemonCommand.WorkingDirectory ` + -RedirectStandardOutput $daemonStdOutLog ` + -RedirectStandardError $daemonStdErrLog ` + -PassThru + + $status = Wait-ForCliCondition ` + -Arguments @('status') ` + -Condition { param($response) $response.running -and $response.transport -eq 'named-pipe' } ` + -FailureMessage 'Headless daemon never became ready over named-pipe IPC.' ` + -TimeoutSeconds $daemonStartupTimeoutSeconds ` + -DelaySeconds 2 + + Write-Stage 'Status and headless transport' + if ($status.namedPipeName -ne $pipeName) { + throw "status did not report the expected named pipe name. Expected $pipeName, got $($status.namedPipeName)" + } + if (-not $runningOnWindows) { + $expectedSocketPath = "/tmp/$pipeName" + if ($status.namedPipePath -ne $expectedSocketPath) { + throw "status did not report the expected Unix socket path. Expected $expectedSocketPath, got $($status.namedPipePath)" + } + } + Add-Tested 'status' + + $version = Invoke-CliJson -Arguments @('version') + if ($version.build -le 0) { + throw "version did not return a positive build number" + } + Add-Tested 'version' + + $appState = Invoke-CliJson -Arguments @('app', 'status') + if (-not $appState.app.headless -or $appState.app.windowAvailable -or $appState.app.canNavigate -or -not $appState.app.canQuit) { + throw "app status did not report the expected headless state: $($appState | ConvertTo-Json -Depth 8)" + } + Add-Tested 'app status' + + Invoke-CliFailure -Arguments @('app', 'show') | Out-Null + Add-Tested 'app show' 'expected-failure' + + Invoke-CliFailure -Arguments @('app', 'navigate', '--page', 'settings') | Out-Null + Add-Tested 'app navigate' 'expected-failure' + + $bundleFixture = Get-ManifestManagerByRole -Role 'bundle' + Invoke-CliFailure -Arguments @('package', 'show', '--id', [string]$bundleFixture.packageId, '--source', [string]$bundleFixture.sourceName) | Out-Null + Add-Tested 'package show' 'expected-failure' + + if ($runningOnWindows -and $manifest.transport.verifyNoTcpListener) { + $connections = Get-NetTCPConnection -State Listen -ErrorAction SilentlyContinue | Where-Object { $_.OwningProcess -eq $process.Id } + if (@($connections).Count -ne 0) { + throw "Headless named-pipe session opened a TCP listener unexpectedly: $(@($connections | Select-Object -ExpandProperty LocalPort) -join ', ')" + } + } + + Write-Stage 'Manager inspection' + $managers = Invoke-CliJson -Arguments @('manager', 'list') + foreach ($fixture in @($manifest.packageManagers)) { + if (@($managers.managers | Where-Object { $_.name -eq $fixture.manager }).Count -eq 0) { + throw "manager list did not report $($fixture.manager)" + } + } + Add-Tested 'manager list' + + foreach ($fixture in @($manifest.packageManagers)) { + $maintenance = Invoke-CliJson -Arguments @('manager', 'maintenance', '--manager', [string]$fixture.manager) + if ($maintenance.maintenance.manager -ne $fixture.manager) { + throw "manager maintenance did not return the expected manager payload for $($fixture.manager)" + } + if (@($maintenance.maintenance.supportedActions | Where-Object { $_ -eq 'reload' }).Count -eq 0) { + throw "manager maintenance did not expose reload for $($fixture.manager)" + } + + $reloadManager = Invoke-CliJson -Arguments @('manager', 'reload', '--manager', [string]$fixture.manager) + if ($reloadManager.operationStatus -ne 'completed') { + throw "manager reload did not complete successfully for $($fixture.manager): $($reloadManager | ConvertTo-Json -Depth 8)" + } + } + Add-Tested 'manager maintenance' + Add-Tested 'manager reload' + + $toggleManagerFixture = Get-ManifestManagerByRole -Role 'toggle-manager' + $disableManager = Invoke-CliJson -Arguments @('manager', 'disable', '--manager', [string]$toggleManagerFixture.manager) + if ($disableManager.manager.enabled) { + throw "manager disable did not disable $($toggleManagerFixture.manager)" + } + $enableManager = Invoke-CliJson -Arguments @('manager', 'enable', '--manager', [string]$toggleManagerFixture.manager) + if (-not $enableManager.manager.enabled) { + throw "manager enable did not re-enable $($toggleManagerFixture.manager)" + } + Add-Tested 'manager enable' + Add-Tested 'manager disable' + + $disableNotifications = Invoke-CliJson -Arguments @('manager', 'notifications', 'disable', '--manager', [string]$bundleFixture.manager) + if (-not $disableNotifications.manager.notificationsSuppressed) { + throw "manager notifications disable did not suppress notifications for $($bundleFixture.manager)" + } + $enableNotifications = Invoke-CliJson -Arguments @('manager', 'notifications', 'enable', '--manager', [string]$bundleFixture.manager) + if ($enableNotifications.manager.notificationsSuppressed) { + throw "manager notifications enable did not re-enable notifications for $($bundleFixture.manager)" + } + Add-Tested 'manager notifications disable' + Add-Tested 'manager notifications enable' + + foreach ($fixture in @($manifest.packageManagers)) { + $sources = Invoke-CliJson -Arguments @('source', 'list', '--manager', [string]$fixture.manager) + if (@($sources.sources | Where-Object { $_.name -eq $fixture.sourceName }).Count -eq 0) { + throw "source list did not report $($fixture.sourceName) for $($fixture.manager)" + } + } + Add-Tested 'source list' + + $sourceFixture = Get-ManifestManagerByRole -Role 'source' + if ($null -ne $sourceFixture) { + Write-Stage 'Source add/remove' + $sourceDirectory = Join-Path $daemonRoot 'LocalFeed' + New-Item -ItemType Directory -Path $sourceDirectory -Force | Out-Null + $sourceUri = ([System.Uri](Resolve-Path $sourceDirectory).Path).AbsoluteUri + $customSourceName = 'ci-local-feed' + $addedSource = Invoke-CliJson -Arguments @( + 'source', 'add', + '--manager', [string]$sourceFixture.manager, + '--name', $customSourceName, + '--url', $sourceUri + ) + Assert-JsonCommandSucceeded -Response $addedSource -Label 'source add' + $sourcesAfterAdd = Invoke-CliJson -Arguments @('source', 'list', '--manager', [string]$sourceFixture.manager) + if (@($sourcesAfterAdd.sources | Where-Object { $_.name -eq $customSourceName -and $_.url -eq $sourceUri }).Count -eq 0) { + throw "source add did not expose the configured custom source" + } + $removedSource = Invoke-CliJson -Arguments @( + 'source', 'remove', + '--manager', [string]$sourceFixture.manager, + '--name', $customSourceName, + '--url', $sourceUri + ) + Assert-JsonCommandSucceeded -Response $removedSource -Label 'source remove' + $sourcesAfterRemove = Invoke-CliJson -Arguments @('source', 'list', '--manager', [string]$sourceFixture.manager) + if (@($sourcesAfterRemove.sources | Where-Object { $_.name -eq $customSourceName }).Count -ne 0) { + throw "source remove did not remove the configured custom source" + } + Add-Tested 'source add' + Add-Tested 'source remove' + } + + Write-Stage 'Settings and secure settings' + $settings = Invoke-CliJson -Arguments @('settings', 'list') + if (@($settings.settings | Where-Object { $_.name -eq 'FreshValue' }).Count -eq 0) { + throw "settings list did not report FreshValue" + } + Add-Tested 'settings list' + + $setFreshValue = Invoke-CliJson -Arguments @('settings', 'set', '--key', 'FreshValue', '--value', 'cli-smoke') + if ($setFreshValue.setting.stringValue -ne 'cli-smoke') { + throw "settings set did not persist FreshValue" + } + $getFreshValue = Invoke-CliJson -Arguments @('settings', 'get', '--key', 'FreshValue') + if ($getFreshValue.setting.stringValue -ne 'cli-smoke') { + throw "settings get did not return FreshValue" + } + Add-Tested 'settings set' + Add-Tested 'settings get' + + $setFreshBool = Invoke-CliJson -Arguments @('settings', 'set', '--key', 'FreshBoolSetting', '--enabled', 'true') + if (-not $setFreshBool.setting.boolValue) { + throw "settings set did not enable FreshBoolSetting" + } + + $secureList = Invoke-CliJson -Arguments @('settings', 'secure', 'list') + if (@($secureList.settings | Where-Object { $_.key -eq $manifest.secureSettings.toggleKey }).Count -eq 0) { + throw "settings secure list did not report $($manifest.secureSettings.toggleKey)" + } + $secureGet = Invoke-CliJson -Arguments @('settings', 'secure', 'get', '--key', [string]$manifest.secureSettings.toggleKey) + if ($secureGet.setting.key -ne $manifest.secureSettings.toggleKey) { + throw "settings secure get did not return the requested key" + } + Add-Tested 'settings secure list' + Add-Tested 'settings secure get' + + if ($manifest.secureSettings.allowSet) { + $secureSetOn = Invoke-CliJson -Arguments @( + 'settings', 'secure', 'set', + '--key', [string]$manifest.secureSettings.toggleKey, + '--enabled', 'true' + ) + if (-not $secureSetOn.setting.enabled) { + throw "settings secure set did not enable $($manifest.secureSettings.toggleKey)" + } + Add-Tested 'settings secure set' + + $maintenanceWithCustomPaths = Invoke-CliJson -Arguments @('manager', 'maintenance', '--manager', [string]$manifest.secureSettings.managerForExecutableOverride) + if (-not $maintenanceWithCustomPaths.maintenance.customExecutablePathsAllowed) { + throw "manager maintenance did not reflect enabled custom executable paths" + } + + $setExecutable = Invoke-CliJson -Arguments @( + 'manager', 'set-executable', + '--manager', [string]$manifest.secureSettings.managerForExecutableOverride, + '--path', [string]$maintenanceWithCustomPaths.maintenance.effectiveExecutablePath + ) + if ($setExecutable.maintenance.configuredExecutablePath -ne $maintenanceWithCustomPaths.maintenance.effectiveExecutablePath) { + throw "manager set-executable did not persist the configured executable path" + } + $clearExecutable = Invoke-CliJson -Arguments @( + 'manager', 'clear-executable', + '--manager', [string]$manifest.secureSettings.managerForExecutableOverride + ) + if (-not [string]::IsNullOrWhiteSpace($clearExecutable.maintenance.configuredExecutablePath)) { + throw "manager clear-executable did not clear the custom executable path" + } + Add-Tested 'manager set-executable' + Add-Tested 'manager clear-executable' + + $secureSetOff = Invoke-CliJson -Arguments @( + 'settings', 'secure', 'set', + '--key', [string]$manifest.secureSettings.toggleKey, + '--enabled', 'false' + ) + if ($secureSetOff.setting.enabled) { + throw "settings secure set did not disable $($manifest.secureSettings.toggleKey)" + } + } + + Write-Stage 'Shortcut and backup' + $syntheticShortcut = Join-Path $daemonRoot 'SyntheticShortcut.lnk' + New-Item -ItemType File -Path $syntheticShortcut | Out-Null + + $keepShortcut = Invoke-CliJson -Arguments @('shortcut', 'set', '--path', $syntheticShortcut, '--status', 'keep') + if ($keepShortcut.shortcut.status -ne 'keep') { + throw "shortcut set did not persist keep" + } + $shortcuts = Invoke-CliJson -Arguments @('shortcut', 'list') + if (@($shortcuts.shortcuts | Where-Object { $_.path -eq $syntheticShortcut -and $_.status -eq 'keep' -and $_.existsOnDisk }).Count -eq 0) { + throw "shortcut list did not report the kept shortcut" + } + $deleteShortcut = Invoke-CliJson -Arguments @('shortcut', 'set', '--path', $syntheticShortcut, '--status', 'delete') + if ($deleteShortcut.shortcut.status -ne 'delete' -or (Test-Path $syntheticShortcut)) { + throw "shortcut set --status delete did not delete the shortcut" + } + $resetShortcut = Invoke-CliJson -Arguments @('shortcut', 'reset', '--path', $syntheticShortcut) + if ($resetShortcut.shortcut.status -ne 'unknown') { + throw "shortcut reset did not clear the shortcut verdict" + } + $resetAllShortcuts = Invoke-CliJson -Arguments @('shortcut', 'reset-all') + Assert-JsonCommandSucceeded -Response $resetAllShortcuts -Label 'shortcut reset-all' + Add-Tested 'shortcut list' + Add-Tested 'shortcut set' + Add-Tested 'shortcut reset' + Add-Tested 'shortcut reset-all' + + $appLog = Invoke-CliJson -Arguments @('log', 'app', '--level', '5') + if (@($appLog.entries).Count -eq 0) { + throw "log app returned no entries" + } + Add-Tested 'log app' + + $backupStatus = Invoke-CliJson -Arguments @('backup', 'status') + if ([string]::IsNullOrWhiteSpace($backupStatus.backup.backupDirectory)) { + throw "backup status did not report the backup directory" + } + Add-Tested 'backup status' + + $backupDirectory = Join-Path $daemonRoot 'backups' + $setBackupDirectory = Invoke-CliJson -Arguments @('settings', 'set', '--key', 'ChangeBackupOutputDirectory', '--value', $backupDirectory) + $setBackupFileName = Invoke-CliJson -Arguments @('settings', 'set', '--key', 'ChangeBackupFileName', '--value', 'cli-e2e-backup') + $disableBackupTimestamping = Invoke-CliJson -Arguments @('settings', 'set', '--key', 'EnableBackupTimestamping', '--enabled', 'false') + if ($setBackupDirectory.setting.stringValue -ne $backupDirectory -or $setBackupFileName.setting.stringValue -ne 'cli-e2e-backup' -or $disableBackupTimestamping.setting.boolValue) { + throw "backup settings did not persist correctly" + } + + $localBackup = Invoke-CliJson -Arguments @('backup', 'local', 'create') + Assert-JsonCommandSucceeded -Response $localBackup -Label 'backup local create' + if (-not (Test-Path $localBackup.path)) { + throw "backup local create did not write the reported backup path" + } + Add-Tested 'backup local create' + + Write-Stage 'Package discovery' + $fixtureState = @{} + foreach ($fixture in @($manifest.packageManagers)) { + $search = Invoke-CliJson -Arguments @('package', 'search', '--manager', [string]$fixture.manager, '--query', [string]$fixture.query, '--max-results', '20') + $details = Invoke-CliJson -Arguments (@('package', 'details') + (Get-PackageArguments -Fixture $fixture -IncludeSource)) + $versions = Invoke-CliJson -Arguments (@('package', 'versions') + (Get-PackageArguments -Fixture $fixture -IncludeSource)) + if (@($versions.versions | Where-Object { $_ -eq $fixture.installVersion }).Count -eq 0) { + throw "package versions did not include $($fixture.installVersion) for $($fixture.packageId) on $($fixture.manager)" + } + if ($details.package.id -ne $fixture.packageId) { + throw "package details did not return $($fixture.packageId) for $($fixture.manager)" + } + $latestVersion = Get-LatestFixtureVersion -Fixture $fixture -SearchResponse $search -VersionResponse $versions + $downloadDirectory = Join-Path $downloadRoot (([string]$fixture.manager -replace '[^A-Za-z0-9._-]', '_') + '-sync') + New-Item -ItemType Directory -Path $downloadDirectory -Force | Out-Null + $download = Invoke-CliJson -Arguments (@('package', 'download') + (Get-PackageArguments -Fixture $fixture -IncludeSource) + @('--output', $downloadDirectory)) + Assert-JsonCommandSucceeded -Response $download -Label "package download $($fixture.packageId)" + if ([string]::IsNullOrWhiteSpace($download.outputPath) -or -not (Test-Path $download.outputPath)) { + throw "package download did not create an artifact for $($fixture.packageId) on $($fixture.manager)" + } + + $fixtureState[[string]$fixture.manager] = [ordered]@{ + fixture = $fixture + latestVersion = $latestVersion + } + } + Add-Tested 'package search' + Add-Tested 'package details' + Add-Tested 'package versions' + Add-Tested 'package download' + + Write-Stage 'Bundle roundtrip and bundle install' + $resetBundle = Invoke-CliJson -Arguments @('bundle', 'reset') + Assert-JsonCommandSucceeded -Response $resetBundle -Label 'bundle reset' + $bundleAfterReset = Invoke-CliJson -Arguments @('bundle', 'get') + if ($bundleAfterReset.bundle.packageCount -ne 0) { + throw "bundle get did not return an empty bundle after reset" + } + $addBundlePackage = Invoke-CliJson -Arguments (@('bundle', 'add') + (Get-PackageArguments -Fixture $bundleFixture -IncludeVersion -IncludeSource) + @('--selection', 'search')) + if ($addBundlePackage.package.id -ne $bundleFixture.packageId) { + throw "bundle add did not add $($bundleFixture.packageId)" + } + $bundle = Invoke-CliJson -Arguments @('bundle', 'get') + if (@($bundle.bundle.packages | Where-Object { $_.id -eq $bundleFixture.packageId -and $_.selectedVersion -eq $bundleFixture.installVersion }).Count -eq 0) { + throw "bundle get did not report the selected bundle package" + } + $exportedBundle = Invoke-CliJson -Arguments @('bundle', 'export') + if ([string]::IsNullOrWhiteSpace($exportedBundle.content)) { + throw "bundle export returned no content" + } + $bundleRoundtripPath = Join-Path $daemonRoot 'BundleRoundtrip.json' + Set-Content -Path $bundleRoundtripPath -Value $exportedBundle.content -Encoding UTF8 + $removeBundlePackage = Invoke-CliJson -Arguments (@('bundle', 'remove') + (Get-PackageArguments -Fixture $bundleFixture -IncludeSource)) + if ($removeBundlePackage.removedCount -lt 1) { + throw "bundle remove did not remove $($bundleFixture.packageId)" + } + $importBundle = Invoke-CliJson -Arguments @('bundle', 'import', '--path', $bundleRoundtripPath) + Assert-JsonCommandSucceeded -Response $importBundle -Label 'bundle import' + $bundleInstall = Invoke-CliJson -Arguments @('bundle', 'install') + if ($bundleInstall.status -ne 'success' -or @($bundleInstall.results | Where-Object { $_.package.id -eq $bundleFixture.packageId }).Count -eq 0) { + throw "bundle install did not report a successful package result: $($bundleInstall | ConvertTo-Json -Depth 10)" + } + Wait-ForInstalledPackage -Fixture $bundleFixture | Out-Null + Add-Tested 'bundle get' + Add-Tested 'bundle reset' + Add-Tested 'bundle add' + Add-Tested 'bundle remove' + Add-Tested 'bundle export' + Add-Tested 'bundle import' + Add-Tested 'bundle install' + + Write-Stage 'Operation queue control' + $queuedOperationIds = @() + foreach ($queueFixture in @($manifest.queueOperations)) { + $queueDownload = Invoke-CliJson -Arguments @( + 'package', 'download', + '--manager', [string]$queueFixture.manager, + '--id', [string]$queueFixture.packageId, + '--source', [string]$queueFixture.sourceName, + '--output', (Resolve-QueueOutputPath -QueueFixture $queueFixture), + '--wait', 'false' + ) + if ($queueDownload.status -ne 'success' -or $queueDownload.completed -or [string]::IsNullOrWhiteSpace($queueDownload.operationId)) { + throw "package download --wait false did not return an in-progress operation payload for $($queueFixture.packageId): $($queueDownload | ConvertTo-Json -Depth 10)" + } + $queuedOperationIds += [string]$queueDownload.operationId + } + + $queuedOperations = Wait-ForCliCondition ` + -Arguments @('operation', 'list') ` + -Condition { + param($response) + $targeted = @($response.operations | Where-Object { $queuedOperationIds -contains $_.id }) + $targeted.Count -eq $queuedOperationIds.Count + } ` + -FailureMessage 'operation list never reported the queued download operations.' ` + -TimeoutSeconds 180 ` + -DelaySeconds 2 + + $queuedOperation = @($queuedOperations.operations | Where-Object { + $queuedOperationIds -contains $_.id + })[0] + + $operationDetails = Invoke-CliJson -Arguments @('operation', 'get', '--id', $queuedOperation.id) + if ($operationDetails.operation.id -ne $queuedOperation.id) { + throw "operation get did not return the requested queued operation id" + } + $operationOutput = Invoke-CliJson -Arguments @('operation', 'output', '--id', $queuedOperation.id, '--tail', '10') + if ($operationOutput.output.operationId -ne $queuedOperation.id) { + throw "operation output did not return the requested queued operation id" + } + + foreach ($operationId in $queuedOperationIds) { + $waitedOperation = Invoke-CliJson -Arguments @('operation', 'wait', '--id', $operationId, '--timeout', '300', '--delay', '1') + if ($waitedOperation.operation.status -ne 'succeeded') { + throw "operation wait did not report success for operation ${operationId}: $($waitedOperation | ConvertTo-Json -Depth 10)" + } + } + + foreach ($operationId in $queuedOperationIds) { + $completedOutput = Invoke-CliJson -Arguments @('operation', 'output', '--id', $operationId) + if ($completedOutput.output.lineCount -lt 0) { + throw "operation output reported an invalid line count for operation $operationId" + } + $forget = Invoke-CliJson -Arguments @('operation', 'forget', '--id', $operationId) + Assert-JsonCommandSucceeded -Response $forget -Label "operation forget $operationId" + } + $operationsAfterForget = Invoke-CliJson -Arguments @('operation', 'list') + if (@($operationsAfterForget.operations | Where-Object { $queuedOperationIds -contains $_.id }).Count -ne 0) { + throw "operation forget did not remove all queued download operations" + } + Add-Tested 'operation list' + Add-Tested 'operation get' + Add-Tested 'operation output' + Add-Tested 'operation wait' + Add-Tested 'operation forget' + + Write-Stage 'Package lifecycle and updates' + $specificUpdateFixture = @($manifest.packageManagers | Where-Object { @($_.roles) -contains 'specific-update' })[0] + if ($null -eq $specificUpdateFixture) { + throw 'The CLI E2E manifest must define a package manager fixture with the specific-update role.' + } + $directInstallFixtures = @($manifest.packageManagers | Where-Object { + $null -ne $specificUpdateFixture -and [string]$_.manager -eq [string]$specificUpdateFixture.manager + }) + $otherInstallFixtures = @($manifest.packageManagers | Where-Object { + [string]$_.manager -ne [string]$bundleFixture.manager -and + [string]$_.manager -ne [string]$specificUpdateFixture.manager + }) + $directInstallFixtures += $otherInstallFixtures + $bundleLatestVersion = [string]$fixtureState[$bundleFixture.manager].latestVersion + + foreach ($installFixture in $directInstallFixtures) { + $installResult = Invoke-CliJson -Arguments (@('package', 'install') + (Get-PackageArguments -Fixture $installFixture -IncludeVersion -IncludeSource)) + Assert-JsonCommandSucceeded -Response $installResult -Label "package install $($installFixture.manager)" + Wait-ForInstalledPackage -Fixture $installFixture -ExpectedVersion $installFixture.installVersion | Out-Null + } + Add-Tested 'package install' + Add-Tested 'package installed' + + $updateDiscoveryFixtures = @($manifest.packageManagers | Where-Object { @($_.roles) -contains 'update-discovery' }) + foreach ($updateDiscoveryFixture in $updateDiscoveryFixtures) { + $reloadManager = Invoke-CliJson -Arguments @('manager', 'reload', '--manager', [string]$updateDiscoveryFixture.manager) + if ($reloadManager.operationStatus -ne 'completed') { + throw "manager reload before package updates did not complete successfully for $($updateDiscoveryFixture.manager): $($reloadManager | ConvertTo-Json -Depth 8)" + } + } + foreach ($updateDiscoveryFixture in $updateDiscoveryFixtures) { + Wait-ForPackageUpdateVisibility -Fixture $updateDiscoveryFixture | Out-Null + } + $allUpdates = Invoke-CliJson -Arguments @('package', 'updates') + if ($null -eq $allUpdates.updates) { + throw "package updates did not return an updates payload" + } + Add-Tested 'package updates' + + $ignoredAdd = Invoke-CliJson -Arguments @('package', 'ignored', 'add', '--manager', [string]$bundleFixture.manager, '--id', [string]$bundleFixture.packageId) + Assert-JsonCommandSucceeded -Response $ignoredAdd -Label 'package ignored add' + $ignoredList = Invoke-CliJson -Arguments @('package', 'ignored', 'list') + if (@($ignoredList.ignoredUpdates | Where-Object { $_.packageId -eq $bundleFixture.packageId }).Count -eq 0) { + throw "package ignored list did not report the ignored dotnet-tool fixture" + } + $ignoredRemove = Invoke-CliJson -Arguments @('package', 'ignored', 'remove', '--manager', [string]$bundleFixture.manager, '--id', [string]$bundleFixture.packageId) + Assert-JsonCommandSucceeded -Response $ignoredRemove -Label 'package ignored remove' + Add-Tested 'package ignored list' + Add-Tested 'package ignored add' + Add-Tested 'package ignored remove' + + $specificUpdate = Invoke-CliJson -Arguments (@( + 'package', 'update' + ) + (Get-PackageArguments -Fixture $specificUpdateFixture -IncludeSource) + @( + '--version', [string]$fixtureState[$specificUpdateFixture.manager].latestVersion + )) + Assert-JsonCommandSucceeded -Response $specificUpdate -Label "package update $($specificUpdateFixture.manager)" + Wait-ForInstalledPackage -Fixture $specificUpdateFixture -ExpectedVersion ([string]$fixtureState[$specificUpdateFixture.manager].latestVersion) | Out-Null + Add-Tested 'package update' + + $updateManager = Invoke-CliFailure -Arguments @('package', 'update-manager', '--manager', [string]$bundleFixture.manager) + if ($updateManager.Text -notmatch 'cannot update manager packages') { + throw "package update-manager did not report the expected headless limitation: $($updateManager.Text)" + } + Add-Tested 'package update-manager' 'expected-failure' + + $updateAll = Invoke-CliFailure -Arguments @('package', 'update-all') + if ($updateAll.Text -notmatch 'cannot update all packages') { + throw "package update-all did not report the expected headless limitation: $($updateAll.Text)" + } + Add-Tested 'package update-all' 'expected-failure' + + $reinstall = Invoke-CliJson -Arguments (@('package', 'reinstall') + (Get-PackageArguments -Fixture $bundleFixture -IncludeSource)) + Assert-JsonCommandSucceeded -Response $reinstall -Label 'package reinstall' + Wait-ForInstalledPackage -Fixture $bundleFixture -ExpectedVersion $bundleLatestVersion | Out-Null + Add-Tested 'package reinstall' + + $repair = Invoke-CliJson -Arguments (@('package', 'repair') + (Get-PackageArguments -Fixture $bundleFixture -IncludeSource)) + Assert-JsonCommandSucceeded -Response $repair -Label 'package repair' + Wait-ForInstalledPackage -Fixture $bundleFixture -ExpectedVersion $bundleLatestVersion | Out-Null + Add-Tested 'package repair' + + $installedAll = Invoke-CliJson -Arguments @('package', 'installed') + foreach ($fixture in @($manifest.packageManagers)) { + if (@($installedAll.packages | Where-Object { $_.id -eq $fixture.packageId }).Count -eq 0) { + throw "package installed did not report $($fixture.packageId) after lifecycle operations" + } + } + + Write-Stage 'Logs' + $operationHistory = Invoke-CliJson -Arguments @('log', 'operations') + if ($null -eq $operationHistory.history) { + throw "log operations did not return a history payload" + } + $managerLog = Wait-ForCliCondition ` + -Arguments @('log', 'manager', '--manager', [string]$bundleFixture.manager, '--verbose') ` + -Condition { + param($response) + @( + $response.managers | + Where-Object { + $_.name -eq $bundleFixture.manager -and + @($_.tasks | Where-Object { @($_.lines | Where-Object { $_ -match $bundleFixture.packageId }).Count -gt 0 }).Count -gt 0 + } + ).Count -gt 0 + } ` + -FailureMessage "log manager did not capture package activity for $($bundleFixture.packageId)" ` + -TimeoutSeconds 180 ` + -DelaySeconds 3 + Add-Tested 'log operations' + Add-Tested 'log manager' + + Write-Stage 'Package uninstall' + $uninstallValidationFixtures = @($manifest.packageManagers) + if ($null -ne $manifest.PSObject.Properties['uninstallValidationManagers']) { + $uninstallValidationManagerNames = [System.Collections.Generic.HashSet[string]]::new([System.StringComparer]::OrdinalIgnoreCase) + foreach ($managerName in @($manifest.uninstallValidationManagers)) { + if (-not [string]::IsNullOrWhiteSpace([string]$managerName)) { + [void]$uninstallValidationManagerNames.Add([string]$managerName) + } + } + + $uninstallValidationFixtures = @($manifest.packageManagers | Where-Object { + $uninstallValidationManagerNames.Contains([string]$_.manager) + }) + } + foreach ($fixture in $uninstallValidationFixtures) { + $uninstall = Invoke-CliJson -Arguments (@('package', 'uninstall') + (Get-PackageArguments -Fixture $fixture -IncludeSource)) + Assert-JsonCommandSucceeded -Response $uninstall -Label "package uninstall $($fixture.packageId)" + if (-not [string]::IsNullOrWhiteSpace($uninstall.operationId)) { + $waitedUninstall = Invoke-CliJson -Arguments @('operation', 'wait', '--id', [string]$uninstall.operationId, '--timeout', '300', '--delay', '1') + if ($waitedUninstall.operation.status -ne 'succeeded') { + throw "package uninstall did not complete successfully for $($fixture.packageId): $($waitedUninstall | ConvertTo-Json -Depth 10)" + } + } + $reloadManager = Invoke-CliJson -Arguments @('manager', 'reload', '--manager', [string]$fixture.manager) + if ($reloadManager.operationStatus -ne 'completed') { + throw "manager reload after uninstall did not complete successfully for $($fixture.manager): $($reloadManager | ConvertTo-Json -Depth 8)" + } + Wait-ForPackageRemoval -Fixture $fixture | Out-Null + } + if ($uninstallValidationFixtures.Count -gt 0) { + Add-Tested 'package uninstall' + } + + Write-Stage 'Settings reset and shutdown' + $clearFreshValue = Invoke-CliJson -Arguments @('settings', 'clear', '--key', 'FreshValue') + if ($clearFreshValue.setting.isSet) { + throw "settings clear did not clear FreshValue" + } + $disableFreshBool = Invoke-CliJson -Arguments @('settings', 'set', '--key', 'FreshBoolSetting', '--enabled', 'false') + if ($disableFreshBool.setting.boolValue) { + throw "settings set did not disable FreshBoolSetting" + } + Add-Tested 'settings clear' + + $resetSettings = Invoke-CliJson -Arguments @('settings', 'reset') + Assert-JsonCommandSucceeded -Response $resetSettings -Label 'settings reset' + Add-Tested 'settings reset' + + $postResetStatus = Invoke-CliJson -Arguments @('status') + if (-not $postResetStatus.running) { + throw "settings reset broke the active IPC session" + } + + $quitApp = Invoke-CliJson -Arguments @('app', 'quit') + Assert-JsonCommandSucceeded -Response $quitApp -Label 'app quit' + Add-Tested 'app quit' + + $quitDeadline = (Get-Date).AddSeconds(30) + while (-not $process.HasExited -and (Get-Date) -lt $quitDeadline) { + Start-Sleep -Seconds 1 + } + + if (-not $process.HasExited) { + throw "app quit did not stop the headless daemon" + } + + $gracefulShutdown = $true +} +finally { + $coverage.status = if ($gracefulShutdown) { 'success' } else { 'failed' } + Set-Content -Path $coveragePath -Value ($coverage | ConvertTo-Json -Depth 12) -Encoding UTF8 + + if (-not $gracefulShutdown) { + Stop-Daemon + } + + $daemonLog = Get-DaemonLog + if (-not [string]::IsNullOrWhiteSpace($daemonLog)) { + Write-Host '--- Headless daemon log ---' + Write-Host $daemonLog + } + + if (-not $preserveArtifacts) { + Remove-Item -Recurse -Force $daemonRoot -ErrorAction SilentlyContinue + } +} diff --git a/testing/productinfo.unigetui.test.json b/testing/productinfo.unigetui.test.json new file mode 100644 index 0000000..5a63686 --- /dev/null +++ b/testing/productinfo.unigetui.test.json @@ -0,0 +1,806 @@ +{ + "RDMWindows": { + "Current": { + "Version": "2025.3.32.0", + "Date": "2026-02-26", + "Files": [ + { + "Arch": "Any", + "Type": "exe", + "Url": "https://cdn.devolutions.net/download/Setup.RemoteDesktopManager.2025.3.32.0.exe", + "Hash": "EFA2B96FF59DFEEAE6BBA3DBC425220E447C7069F408CB48B4AA9F1AC8B1E850" + }, + { + "Arch": "Any", + "Type": "msi", + "Url": "https://cdn.devolutions.net/download/Setup.RemoteDesktopManager.2025.3.32.0.msi", + "Hash": "62AFE25ED724CCA3EA83AAB9FD84B7D065C643722CDDCFCFF3FD5E7A27389ED4" + }, + { + "Arch": "arm64", + "Type": "exe", + "Url": "https://cdn.devolutions.net/download/Setup.RemoteDesktopManager.win-arm64.2025.3.32.0.exe", + "Hash": "5392753F8F960C426906C2DCC883491ADF2D4CB5ADF1D8B799FA543BCE939861" + }, + { + "Arch": "x64", + "Type": "exe", + "Url": "https://cdn.devolutions.net/download/Setup.RemoteDesktopManager.win-x64.2025.3.32.0.exe", + "Hash": "F036DFFA06971DA7A374ECA72650BABBC19EDE83C611F3270964949A79361311" + }, + { + "Arch": "arm64", + "Type": "msi", + "Url": "https://cdn.devolutions.net/download/Setup.RemoteDesktopManager.win-arm64.2025.3.32.0.msi", + "Hash": "24514E83B47233E48E6CCD522D1B03C67E421645E7760E4618E58FD306550441" + }, + { + "Arch": "x64", + "Type": "msi", + "Url": "https://cdn.devolutions.net/download/Setup.RemoteDesktopManager.win-x64.2025.3.32.0.msi", + "Hash": "9AACE90721C9CC7A3C6DB073EA85B836FBC57DF7A081FBE52FC7D970DC6BB8D7" + }, + { + "Arch": "Any", + "Type": "zip", + "Url": "https://cdn.devolutions.net/download/Devolutions.RemoteDesktopManager.Bin.2025.3.32.0.zip", + "Hash": "4A68FA1065F37599CC67C8F7EA0C2F8ABF3BD9A935D11CAF16A3D5BD1693507C" + }, + { + "Arch": "arm64", + "Type": "7z", + "Url": "https://cdn.devolutions.net/download/Devolutions.RemoteDesktopManager.win-arm64.2025.3.32.0.7z", + "Hash": "FCC97E4D34CA8F54E1DDF6001E2E34597BAD65122B0B714B9A49249BF2CAEFBC" + }, + { + "Arch": "x64", + "Type": "7z", + "Url": "https://cdn.devolutions.net/download/Devolutions.RemoteDesktopManager.win-x64.2025.3.32.0.7z", + "Hash": "857C91113F12FE629692716ABE87F7204A9CF7BC677A583ED6C4C9D8D1A42CFB" + } + ] + }, + "Beta": { + "Version": "2026.1.8.0", + "Date": "2026-02-19", + "Files": [ + { + "Arch": "Any", + "Type": "exe", + "Url": "https://cdn.devolutions.net/download/Setup.RemoteDesktopManager.2026.1.8.0.exe", + "Hash": "8A850F23D0F2D494D8601B2D8861A9764AF63EE36D620FB5F41C81EDE67E641F" + }, + { + "Arch": "Any", + "Type": "msi", + "Url": "https://cdn.devolutions.net/download/Setup.RemoteDesktopManager.2026.1.8.0.msi", + "Hash": "4CE4F38C047D766F888F3E8128ADA4B51322D2E1A1FCB5CE9ACC0E0961522A5E" + }, + { + "Arch": "arm64", + "Type": "exe", + "Url": "https://cdn.devolutions.net/download/Setup.RemoteDesktopManager.win-arm64.2026.1.8.0.exe", + "Hash": "D4FF7DDA881F12ECCB2CCC443B22FE3385151AC488BE1BBC97027D18952481AA" + }, + { + "Arch": "x64", + "Type": "exe", + "Url": "https://cdn.devolutions.net/download/Setup.RemoteDesktopManager.win-x64.2026.1.8.0.exe", + "Hash": "B0E0AA4325647595AE83829794C7937D926A138C4743A2D881EC0BAEC5D98347" + }, + { + "Arch": "arm64", + "Type": "msi", + "Url": "https://cdn.devolutions.net/download/Setup.RemoteDesktopManager.win-arm64.2026.1.8.0.msi", + "Hash": "4C8EF2BDD7F0DD6B2811804D6B6FF566252452C3EF6354F89598C8E3FE2AD03D" + }, + { + "Arch": "x64", + "Type": "msi", + "Url": "https://cdn.devolutions.net/download/Setup.RemoteDesktopManager.win-x64.2026.1.8.0.msi", + "Hash": "DF1AD55915A54DDE0F685782843E0BABB83B5807F56488947572DD98421B1946" + }, + { + "Arch": "Any", + "Type": "zip", + "Url": "https://cdn.devolutions.net/download/Devolutions.RemoteDesktopManager.Bin.2026.1.8.0.zip", + "Hash": "0598B5EAB915E42348101331DF1A57D8B6874F0C437821328AF6EA818CBE6FC6" + }, + { + "Arch": "arm64", + "Type": "7z", + "Url": "https://cdn.devolutions.net/download/Devolutions.RemoteDesktopManager.win-arm64.2026.1.8.0.7z", + "Hash": "9953C9061C90E8AB6078B7FB9647C6D033C4A34FC476515A494ACA3A3DF4DED0" + }, + { + "Arch": "x64", + "Type": "7z", + "Url": "https://cdn.devolutions.net/download/Devolutions.RemoteDesktopManager.win-x64.2026.1.8.0.7z", + "Hash": "FD3592CC14D6ED487023490560AD9847555B93935CB3AD9126BD7DEB93E41DCC" + } + ] + }, + "Update": { + "Version": "2025.3.32.0", + "Date": "2026-02-26", + "Files": [ + { + "Arch": "Any", + "Type": "exe", + "Url": "https://cdn.devolutions.net/download/Setup.RemoteDesktopManager.2025.3.32.0.exe", + "Hash": "EFA2B96FF59DFEEAE6BBA3DBC425220E447C7069F408CB48B4AA9F1AC8B1E850" + }, + { + "Arch": "Any", + "Type": "msi", + "Url": "https://cdn.devolutions.net/download/Setup.RemoteDesktopManager.2025.3.32.0.msi", + "Hash": "62AFE25ED724CCA3EA83AAB9FD84B7D065C643722CDDCFCFF3FD5E7A27389ED4" + }, + { + "Arch": "arm64", + "Type": "exe", + "Url": "https://cdn.devolutions.net/download/Setup.RemoteDesktopManager.win-arm64.2025.3.32.0.exe", + "Hash": "5392753F8F960C426906C2DCC883491ADF2D4CB5ADF1D8B799FA543BCE939861" + }, + { + "Arch": "x64", + "Type": "exe", + "Url": "https://cdn.devolutions.net/download/Setup.RemoteDesktopManager.win-x64.2025.3.32.0.exe", + "Hash": "F036DFFA06971DA7A374ECA72650BABBC19EDE83C611F3270964949A79361311" + }, + { + "Arch": "arm64", + "Type": "msi", + "Url": "https://cdn.devolutions.net/download/Setup.RemoteDesktopManager.win-arm64.2025.3.32.0.msi", + "Hash": "24514E83B47233E48E6CCD522D1B03C67E421645E7760E4618E58FD306550441" + }, + { + "Arch": "x64", + "Type": "msi", + "Url": "https://cdn.devolutions.net/download/Setup.RemoteDesktopManager.win-x64.2025.3.32.0.msi", + "Hash": "9AACE90721C9CC7A3C6DB073EA85B836FBC57DF7A081FBE52FC7D970DC6BB8D7" + }, + { + "Arch": "arm64", + "Type": "7z", + "Url": "https://cdn.devolutions.net/download/Devolutions.RemoteDesktopManager.win-arm64.2025.3.32.0.7z", + "Hash": "FCC97E4D34CA8F54E1DDF6001E2E34597BAD65122B0B714B9A49249BF2CAEFBC" + }, + { + "Arch": "x64", + "Type": "7z", + "Url": "https://cdn.devolutions.net/download/Devolutions.RemoteDesktopManager.win-x64.2025.3.32.0.7z", + "Hash": "857C91113F12FE629692716ABE87F7204A9CF7BC677A583ED6C4C9D8D1A42CFB" + } + ] + } + }, + "RDMMac": { + "Current": { + "Version": "2025.3.10.2", + "Date": "2026-02-19", + "Files": [ + { + "Arch": "universal", + "Type": "dmg", + "Url": "https://cdn.devolutions.net/download/Mac/Devolutions.RemoteDesktopManager.Mac.2025.3.10.2.dmg", + "Hash": "93460DAB1FFEB28DF4DB7F2226A2858035251EB2C0104C41D9EEBFCA29731451" + } + ] + }, + "Beta": { + "Version": "2025.3.10.2", + "Date": "2026-02-19", + "Files": [ + { + "Arch": "universal", + "Type": "dmg", + "Url": "https://cdn.devolutions.net/download/Mac/Devolutions.RemoteDesktopManager.Mac.2025.3.10.2.dmg", + "Hash": "93460DAB1FFEB28DF4DB7F2226A2858035251EB2C0104C41D9EEBFCA29731451" + } + ] + } + }, + "RDMLinux": { + "Current": { + "Version": "2025.3.2.3", + "Date": "2026-02-13", + "Files": [ + { + "Arch": "x64", + "Type": "deb", + "Url": "https://cdn.devolutions.net/download/Linux/RDM/2025.3.2.3/RemoteDesktopManager_2025.3.2.3_amd64.deb", + "Hash": "545822CD95D7EAE3E1423963B1934EFBC6EFB2E8B0E9ED2ECA0393B2D447B3EB" + }, + { + "Arch": "x64", + "Type": "rpm", + "Url": "https://cdn.devolutions.net/download/Linux/RDM/2025.3.2.3/RemoteDesktopManager_2025.3.2.3_x86_64.rpm", + "Hash": "3DEED02B1DB6DBC3B0721CF211B39AD4BE436A8FA06715A7D3C51FF055110DB4" + }, + { + "Arch": "arm64", + "Type": "deb", + "Url": "https://cdn.devolutions.net/download/Linux/RDM/2025.3.2.3/RemoteDesktopManager_2025.3.2.3_arm64.deb", + "Hash": "611B37B4A47719E9CBC917E16E3456FCA5198EB47549BBED3487713F9D28703B" + }, + { + "Arch": "arm64", + "Type": "rpm", + "Url": "https://cdn.devolutions.net/download/Linux/RDM/2025.3.2.3/RemoteDesktopManager_2025.3.2.3_aarch64.rpm", + "Hash": "BA3317B7EF80231014AB919EB54A3B2CB55B4E99E36E9A7AD34544A9C9D9DE13" + } + ] + } + }, + "RDMAgent": { + "Current": { + "Version": "2025.3.32.0", + "Date": "2026-02-26", + "Files": [ + { + "Arch": "x64", + "Type": "exe", + "Url": "https://cdn.devolutions.net/download/Setup.RemoteDesktopManagerJump.2025.3.32.0.exe", + "Hash": "95399330EBEE12F6526BE7879D832B112182E3E6EB2321236C7D71A51225A471" + }, + { + "Arch": "x64", + "Type": "msi", + "Url": "https://cdn.devolutions.net/download/Setup.RemoteDesktopManagerJump.2025.3.32.0.msi", + "Hash": "C59B020D9F10A9A21C11F5EF6CCF167FEAA29B8B55312AA090DD192A1BDC07E4" + }, + { + "Arch": "x64", + "Type": "zip", + "Url": "https://cdn.devolutions.net/download/Devolutions.RemoteDesktopManagerJump.Bin.2025.3.32.0.zip", + "Hash": "52DB422FA1ED07E028C212D7C4D26801EBF6C6EFEA480AF6B893BE816ABF2EE2" + } + ] + }, + "Beta": { + "Version": "2026.1.8.0", + "Date": "2026-02-19", + "Files": [ + { + "Arch": "x64", + "Type": "exe", + "Url": "https://cdn.devolutions.net/download/Setup.RemoteDesktopManagerJump.2026.1.8.0.exe", + "Hash": "4FCBB551474835226DA895B55AC1641288432F28B81E67CFEBD20F37CDEAA224" + }, + { + "Arch": "x64", + "Type": "msi", + "Url": "https://cdn.devolutions.net/download/Setup.RemoteDesktopManagerJump.2026.1.8.0.msi", + "Hash": "AD90374D7230B60DC1EAABF75E9ADF16DA7B947248557C8BFE0065212151C432" + }, + { + "Arch": "x64", + "Type": "zip", + "Url": "https://cdn.devolutions.net/download/Devolutions.RemoteDesktopManagerJump.Bin.2026.1.8.0.zip", + "Hash": "5A197493B43AF8434D38F3CEA9F2ACDBF4C7CC2A922D145F6656887FFD6D54B2" + } + ] + } + }, + "Agent": { + "Current": { + "Version": "2026.1.0.0", + "Date": "2026-02-27", + "Files": [ + { + "Arch": "x64", + "Type": "msi", + "Url": "https://cdn.devolutions.net/download/DevolutionsAgent-x86_64-2026.1.0.0.msi", + "Hash": "794DB95AA3A846D0135E7233D89AE9A61400A80CAAA046BA4EBD52F341A28CD6" + }, + { + "Arch": "arm64", + "Type": "msi", + "Url": "https://cdn.devolutions.net/download/DevolutionsAgent-arm64-2026.1.0.0.msi", + "Hash": "4396B8862DF5EC49E58E4E099ADB707202E0DAA730AFAAC10EACCAD428B062FA" + }, + { + "Arch": "x64", + "Type": "deb", + "Url": "https://cdn.devolutions.net/download/devolutions-agent_2026.1.0.0_amd64.deb", + "Hash": "B05A1CD591238CF2050E540F7000584AAAD1CBE3A8D5CDBAC812CBF53D6D6564" + } + ] + }, + "Beta": { + "Version": "2026.1.0.0", + "Date": "2026-02-27", + "Files": [ + { + "Arch": "x64", + "Type": "msi", + "Url": "https://cdn.devolutions.net/download/DevolutionsAgent-x86_64-2026.1.0.0.msi", + "Hash": "794DB95AA3A846D0135E7233D89AE9A61400A80CAAA046BA4EBD52F341A28CD6" + }, + { + "Arch": "arm64", + "Type": "msi", + "Url": "https://cdn.devolutions.net/download/DevolutionsAgent-arm64-2026.1.0.0.msi", + "Hash": "4396B8862DF5EC49E58E4E099ADB707202E0DAA730AFAAC10EACCAD428B062FA" + }, + { + "Arch": "x64", + "Type": "deb", + "Url": "https://cdn.devolutions.net/download/devolutions-agent_2026.1.0.0_amd64.deb", + "Hash": "B05A1CD591238CF2050E540F7000584AAAD1CBE3A8D5CDBAC812CBF53D6D6564" + } + ] + } + }, + "PowerShell": { + "Current": { + "Version": "2025.3.4.0", + "Date": "2026-02-02", + "Files": [ + { + "Arch": "Any", + "Type": "nupkg", + "Url": "https://cdn.devolutions.net/download/Devolutions.PowerShell.2025.3.4.0.nupkg", + "Hash": "63FB9ADECD0AB10F1FEE187F06030225AF9FF4D526AF8469AC8BC9279483BA9C" + } + ] + } + }, + "PowerShellUniversal": { + "Current": { + "Version": "2026.1.3.0", + "Date": "2026-02-27", + "Files": [ + { + "Arch": "x64", + "Type": "msi", + "Url": "https://cdn.devolutions.net/download/Devolutions.PowerShellUniversal.2026.1.3.0.msi", + "Hash": "E555093C06E64EA096D1162EEA08BF5FAD020D1617668DD4C8433C589D3373E9" + }, + { + "Arch": "x64", + "Type": "msi", + "Url": "https://cdn.devolutions.net/download/Devolutions.PowerShellUniversal.Agent.2026.1.3.0.msi", + "Hash": "9CBE8D03EA2D41356BEC4A95DD257E5CAEEF539A8056A3BEED73F8C5ED12E17A" + }, + { + "Arch": "x64", + "Type": "zip", + "Url": "https://cdn.devolutions.net/download/Devolutions.PowerShellUniversal.win-x64.2026.1.3.0.zip", + "Hash": "B5B0DC1ABE87F11FF6F7B245E50BC9538FFCF7B3328521D309F36EEB7DDA0172" + }, + { + "Arch": "arm64", + "Type": "zip", + "Url": "https://cdn.devolutions.net/download/Devolutions.PowerShellUniversal.win-arm64.2026.1.3.0.zip", + "Hash": "E57F71BF173C96B8EB41317953AA8E4239EF31C5A7C1E8C870922030EA78EB47" + }, + { + "Arch": "x64", + "Type": "zip", + "Url": "https://cdn.devolutions.net/download/Devolutions.PowerShellUniversal.linux-x64.2026.1.3.0.zip", + "Hash": "4ECD52E4E80BFA73F010842EC228DEB6825A1D322C3C4105D0000AE9275A1F09" + }, + { + "Arch": "arm", + "Type": "zip", + "Url": "https://cdn.devolutions.net/download/Devolutions.PowerShellUniversal.linux-arm.2026.1.3.0.zip", + "Hash": "4E9267E04B036FD93AD156333138B37365ACC2FD533B6D9E727696902D0C1E7F" + }, + { + "Arch": "arm64", + "Type": "zip", + "Url": "https://cdn.devolutions.net/download/Devolutions.PowerShellUniversal.linux-arm64.2026.1.3.0.zip", + "Hash": "70D47AC41B41B4A71262BAAFFDAD01E275D8EC5FE8B11FD32A0128884C433779" + }, + { + "Arch": "x64", + "Type": "zip", + "Url": "https://cdn.devolutions.net/download/Devolutions.PowerShellUniversal.osx-x64.2026.1.3.0.zip", + "Hash": "9168B4EC85AE5980D50CAC0CBA2F798CB4075F7E75367919E7E0938FB1F906E7" + }, + { + "Arch": "arm64", + "Type": "zip", + "Url": "https://cdn.devolutions.net/download/Devolutions.PowerShellUniversal.osx-arm64.2026.1.3.0.zip", + "Hash": "79865486934ADA2BA527E53401CCAF61C17319346E31FA869C7F5EFBF1DC9CC0" + } + ] + } + }, + "DVLS": { + "Current": { + "Version": "2025.3.15.0", + "Date": "2026-02-09", + "Files": [ + { + "Arch": "Any", + "Type": "zip", + "Url": "https://cdn.devolutions.net/download/RDMS/DVLS.2025.3.15.0.zip", + "Hash": "1B47D61293FB601C26B7F0F38E939B9FB8EDA87CB0AE8A3BA0EDD6B783F001DD" + }, + { + "Arch": "x64", + "Type": "tar.gz", + "Url": "https://cdn.devolutions.net/download/RDMS/DVLS.2025.3.15.0.linux-x64.tar.gz", + "Hash": "4B5F44C0FFBBF297A3E61145D09AE9426ECB81B2EC87260A2282DFAF9C689523" + } + ] + }, + "Stable": { + "Version": "2025.2.22.0", + "Date": "2026-01-14", + "Files": [ + { + "Arch": "Any", + "Type": "zip", + "Url": "https://cdn.devolutions.net/download/RDMS/DVLS.2025.2.22.0.zip", + "Hash": "E1806A33CA37FB8BB332D58037AFDCD2BD60B536ED56D568920F738C43B2307F" + }, + { + "Arch": "x64", + "Type": "tar.gz", + "Url": "https://cdn.devolutions.net/download/RDMS/DVLS.2025.2.22.0.linux-x64.tar.gz", + "Hash": "5EA811FF3C1F715E53186D4AF09DE6380DF341B8F13B82753116737055EFDC89" + } + ] + }, + "Beta": { + "Version": "2026.1.3.0", + "Date": "2026-02-23", + "Files": [ + { + "Arch": "Any", + "Type": "zip", + "Url": "https://cdn.devolutions.net/download/RDMS/DVLS.2026.1.3.0.zip", + "Hash": "8C085283FFB6492F9411502B8EFD7AB7B56C766C130FEE01CAA2BCCF3CF9964D" + }, + { + "Arch": "x64", + "Type": "tar.gz", + "Url": "https://cdn.devolutions.net/download/RDMS/DVLS.2026.1.3.0.linux-x64.tar.gz", + "Hash": "0C49BE5EF9ED6C5ABB3A66BFBED917C60834943110DBFC98CEAEF1E8133CDBC6" + } + ] + } + }, + "Console": { + "Current": { + "Version": "2025.3.15.0", + "Date": "2026-02-09", + "Files": [ + { + "Arch": "x64", + "Type": "exe", + "Url": "https://cdn.devolutions.net/download/Setup.DVLS.Console.2025.3.15.0.exe", + "Hash": "5B107771BF9B6A1BFEA86C7712C25332A9FA0A314D66446C3B6A4612A3BAA6BF" + } + ] + }, + "Beta": { + "Version": "2026.1.3.0", + "Date": "2026-02-23", + "Files": [ + { + "Arch": "x64", + "Type": "exe", + "Url": "https://cdn.devolutions.net/download/Setup.DVLS.Console.2026.1.3.0.exe", + "Hash": "02C78B0B23A6A471C9F6CA8795F38C30C8B55FC10FFE97C2A248FBEBE2C376FB" + } + ] + } + }, + "Gateway": { + "Current": { + "Version": "2026.1.0.0", + "Date": "2026-02-27", + "Files": [ + { + "Arch": "x64", + "Type": "msi", + "Url": "https://cdn.devolutions.net/download/DevolutionsGateway-x86_64-2026.1.0.0.msi", + "Hash": "0253C4267FB1B1699BBBC1C783C37514D1059051C5678FFEFDE7B390724A4756" + }, + { + "Arch": "x64", + "Type": "deb", + "Url": "https://cdn.devolutions.net/download/devolutions-gateway_2026.1.0.0_amd64.deb", + "Hash": "2612A9F18D9227D014CA096EDC76BA0BF34E6CBAAE773849B631FAFEA8D0DE31" + } + ] + }, + "Beta": { + "Version": "2026.1.0.0", + "Date": "2026-02-27", + "Files": [ + { + "Arch": "x64", + "Type": "msi", + "Url": "https://cdn.devolutions.net/download/DevolutionsGateway-x86_64-2026.1.0.0.msi", + "Hash": "0253C4267FB1B1699BBBC1C783C37514D1059051C5678FFEFDE7B390724A4756" + }, + { + "Arch": "x64", + "Type": "deb", + "Url": "https://cdn.devolutions.net/download/devolutions-gateway_2026.1.0.0_amd64.deb", + "Hash": "2612A9F18D9227D014CA096EDC76BA0BF34E6CBAAE773849B631FAFEA8D0DE31" + } + ] + } + }, + "Launcher": { + "Current": { + "Version": "2025.3.32.0", + "Date": "2026-02-26", + "Files": [ + { + "Arch": "x64", + "Type": "exe", + "Url": "https://cdn.devolutions.net/download/Setup.Devolutions.Launcher.2025.3.32.0.exe", + "Hash": "CBC70FAFA11A0B677BE01158F9E39F407DC17A1EAB413B0F428CFC913288031D" + }, + { + "Arch": "x64", + "Type": "msi", + "Url": "https://cdn.devolutions.net/download/Setup.Devolutions.Launcher.2025.3.32.0.msi", + "Hash": "968C24593650FF5C1B9D3B8888D331769199B71C0667283921DA634F176BFDD5" + } + ] + }, + "Beta": { + "Version": "2026.1.8.0", + "Date": "2026-02-19", + "Files": [ + { + "Arch": "x64", + "Type": "exe", + "Url": "https://cdn.devolutions.net/download/Setup.Devolutions.Launcher.2026.1.8.0.exe", + "Hash": "241AA246DC15845A505F0794F5DADB19DFC37D7F4A83A6633796C18036013021" + }, + { + "Arch": "x64", + "Type": "msi", + "Url": "https://cdn.devolutions.net/download/Setup.Devolutions.Launcher.2026.1.8.0.msi", + "Hash": "FE8E895FFF609010AF2C8574DA7F22EDCE4758E5F9B76782CE8FA7076D6380D0" + } + ] + } + }, + "HubServices": { + "Current": { + "Version": "2025.3.1.1", + "Date": "2025-10-07", + "Files": [ + { + "Arch": "x64", + "Type": "msi", + "Url": "https://cdn.devolutions.net/download/Hub/Services/Setup.Devolutions.Hub.Services.2025.3.1.1.msi", + "Hash": "2802128648097C2C5BBD061ADCFCA0A509E9FDF29662619F9721C2494F7521F3" + } + ] + } + }, + "WorkspaceWindows": { + "Current": { + "Version": "2025.3.4.0", + "Date": "2025-12-03", + "Files": [ + { + "Arch": "x64", + "Type": "msix", + "Url": "https://cdn.devolutions.net/download/Devolutions.Workspace-2025.3.4.0-x64.msix", + "Hash": "445968BFDC0CC208D95BD55ED59C6E124C3E0FF0EEE2F8F101662663173A3FB6" + }, + { + "Arch": "x64", + "Type": "msi", + "Url": "https://cdn.devolutions.net/download/Devolutions.Workspace-2025.3.4.0-x64.msi", + "Hash": "9D6CABD84990E69BD774EA6E7BDDF7CCD759C133CA564098F6816AC1E8266524" + } + ] + }, + "Beta": { + "Version": "2025.3.4.0", + "Date": "2025-12-03", + "Files": [ + { + "Arch": "x64", + "Type": "msix", + "Url": "https://cdn.devolutions.net/download/Devolutions.Workspace-2025.3.4.0-x64.msix", + "Hash": "445968BFDC0CC208D95BD55ED59C6E124C3E0FF0EEE2F8F101662663173A3FB6" + }, + { + "Arch": "x64", + "Type": "msi", + "Url": "https://cdn.devolutions.net/download/Devolutions.Workspace-2025.3.4.0-x64.msi", + "Hash": "9D6CABD84990E69BD774EA6E7BDDF7CCD759C133CA564098F6816AC1E8266524" + } + ] + } + }, + "WorkspaceMac": { + "Current": { + "Version": "2025.3.4.0", + "Date": "2025-12-03", + "Files": [ + { + "Arch": "universal", + "Type": "dmg", + "Url": "https://cdn.devolutions.net/download/Mac/Workspace/2025.3.4.0/Devolutions.Workspace.2025.3.4.0.dmg", + "Hash": "B83F7DC1C47A0384B63DEE9154C76609A27A4B4C11A7AB95893C2125F78FB44F" + }, + { + "Arch": "universal", + "Type": "pkg", + "Url": "https://cdn.devolutions.net/download/Mac/Workspace/2025.3.4.0/Devolutions.Workspace.2025.3.4.0.pkg", + "Hash": "1C7D173E919D420D34208AEE9C8D389911CF4917F08E9B34659022B9028D1A3F" + } + ] + }, + "Beta": { + "Version": "2025.3.4.0", + "Date": "2025-12-03", + "Files": [ + { + "Arch": "universal", + "Type": "dmg", + "Url": "https://cdn.devolutions.net/download/Mac/Workspace/2025.3.4.0/Devolutions.Workspace.2025.3.4.0.dmg", + "Hash": "B83F7DC1C47A0384B63DEE9154C76609A27A4B4C11A7AB95893C2125F78FB44F" + }, + { + "Arch": "universal", + "Type": "pkg", + "Url": "https://cdn.devolutions.net/download/Mac/Workspace/2025.3.4.0/Devolutions.Workspace.2025.3.4.0.pkg", + "Hash": "1C7D173E919D420D34208AEE9C8D389911CF4917F08E9B34659022B9028D1A3F" + } + ] + } + }, + "WorkspaceLinux": { + "Current": { + "Version": "2025.3.4.0", + "Date": "2025-12-03", + "Files": [ + { + "Arch": "x64", + "Type": "deb", + "Url": "https://cdn.devolutions.net/download/Linux/Workspace/2025.3.4.0/workspace_2025.3.4.0_amd64.deb", + "Hash": "AACED08BDE0800A6D998683A8651DA1608D140C1C9C526C85833564C0DD980CC" + } + ] + }, + "Beta": { + "Version": "2025.3.4.0", + "Date": "2025-12-03", + "Files": [ + { + "Arch": "x64", + "Type": "deb", + "Url": "https://cdn.devolutions.net/download/Linux/Workspace/2025.3.4.0/workspace_2025.3.4.0_amd64.deb", + "Hash": "AACED08BDE0800A6D998683A8651DA1608D140C1C9C526C85833564C0DD980CC" + } + ] + } + }, + "WorkspaceFirefox": { + "Current": { + "Version": "2025.3.3.5", + "Date": "2026-01-14", + "Files": [ + { + "Arch": "Any", + "Type": "xpi", + "Url": "https://cdn.devolutions.net/download/BrowserExtension/DevolutionsWebLoginFirefox.2025.3.3.5.xpi", + "Hash": "" + } + ] + } + }, + "WorkspaceChrome": { + "Current": { + "Version": "2025.3.3.4", + "Date": "2026-01-14", + "Files": [ + { + "Arch": "Any", + "Type": "web", + "Url": "https://chrome.google.com/webstore/detail/devolutions-web-login/neimonjjffhehnojilepgfejkneaidmo?hl=en-US&gl=CA", + "Hash": "" + } + ] + } + }, + "WorkspaceEdge": { + "Current": { + "Version": "2025.3.3.4", + "Date": "2026-01-14", + "Files": [ + { + "Arch": "Any", + "Type": "web", + "Url": "https://microsoftedge.microsoft.com/addons/detail/ddloeodolhdfbohkokiflfbacbfpjahp", + "Hash": "" + } + ] + } + }, + "WorkspaceOpera": { + "Current": { + "Version": "2025.3.3.5", + "Date": "2026-01-14", + "Files": [ + { + "Arch": "Any", + "Type": "crx", + "Url": "https://cdn.devolutions.net/download/BrowserExtension/DevolutionsWebLoginOpera.2025.3.3.5.crx", + "Hash": "" + } + ] + } + }, + "WorkspaceSafari": { + "Current": { + "Version": "2025.3.0.3", + "Date": "2025-10-07", + "Files": [ + { + "Arch": "Any", + "Type": "web", + "Url": "https://apps.apple.com/us/app/devolutions-workspace/id1462282993", + "Hash": "" + } + ] + } + }, + "Devolutions.UniGetUI": { + "Current": { + "Version": "3.3.99.0", + "Date": "2026-02-27", + "Files": [ + { + "Arch": "x64", + "Type": "exe", + "Url": "http://127.0.0.1:8080/UniGetUI.Installer.x64.exe", + "Hash": "E870E68BAF732DFAD6275BC0F851D2BB8FCD2CB00DEB514459A997FCDDBFFC35" + }, + { + "Arch": "arm64", + "Type": "exe", + "Url": "http://127.0.0.1:8080/UniGetUI.Installer.arm64.exe", + "Hash": "67F89B83907851552925F16262DE6F2DB3E551A4DF6C37265C625AAC0E79AB14" + }, + { + "Arch": "x64", + "Type": "zip", + "Url": "http://127.0.0.1:8080/UniGetUI.x64.zip", + "Hash": "7CB3F3D725AC1FE4DF0835FB291E8F9611826ACF57FB3842AE374BD5B121542C" + }, + { + "Arch": "arm64", + "Type": "zip", + "Url": "http://127.0.0.1:8080/UniGetUI.arm64.zip", + "Hash": "5D4B3606BC772BCFF375226249DAF63524551BBAE7F18B1AE6110BD326680FCD" + } + ] + }, + "Beta": { + "Version": "3.4.0.0", + "Date": "2026-02-27", + "Files": [ + { + "Arch": "x64", + "Type": "exe", + "Url": "http://127.0.0.1:8080/UniGetUI.Installer.x64.exe", + "Hash": "E870E68BAF732DFAD6275BC0F851D2BB8FCD2CB00DEB514459A997FCDDBFFC35" + }, + { + "Arch": "arm64", + "Type": "exe", + "Url": "http://127.0.0.1:8080/UniGetUI.Installer.arm64.exe", + "Hash": "67F89B83907851552925F16262DE6F2DB3E551A4DF6C37265C625AAC0E79AB14" + } + ] + } + } +}